From 57d2b552c74dbd03b9909e6b8cd7b3de1f8b40e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 27 Feb 2024 13:53:30 +0200 Subject: [PATCH 001/571] params: begin v1.13.15 cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 09368cd9faac..671037a82b7e 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 13 // Minor version component of the current release - VersionPatch = 14 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 13 // Minor version component of the current release + VersionPatch = 15 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 02d77c98f9e1efaf3fede313b0e9183dc54562b6 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Wed, 28 Feb 2024 15:25:12 +0800 Subject: [PATCH 002/571] core: using math.MaxUint64 instead of 0xffffffffffffffff (#29094) --- core/vm/instructions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index b8055de6bce7..ac3ea4bcd62b 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -305,7 +305,7 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext ) dataOffset64, overflow := dataOffset.Uint64WithOverflow() if overflow { - dataOffset64 = 0xffffffffffffffff + dataOffset64 = math.MaxUint64 } // These values are checked for overflow during gas cost calculation memOffset64 := memOffset.Uint64() From 170fcd80c6f5d07d7d839e895765de193c34a8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 28 Feb 2024 10:01:52 +0200 Subject: [PATCH 003/571] params: being major version bump cycle --- params/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/params/version.go b/params/version.go index 671037a82b7e..a49385da7d56 100644 --- a/params/version.go +++ b/params/version.go @@ -22,8 +22,8 @@ import ( const ( VersionMajor = 1 // Major version component of the current release - VersionMinor = 13 // Minor version component of the current release - VersionPatch = 15 // Patch version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release VersionMeta = "unstable" // Version metadata to append to the version string ) From 49623bd4697f5b333ae977968186d0717f918927 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 28 Feb 2024 20:23:52 +0800 Subject: [PATCH 004/571] core, triedb/pathdb: calculate the size for batch pre-allocation (#29106) * core, triedb/pathdb: calculate the size for batch pre-allocation * triedb/pathdb: address comment --- core/rawdb/schema.go | 30 +++++++++++++++--------------- triedb/pathdb/nodebuffer.go | 15 ++++++++++++++- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 11cf5b40fef6..dbf010be0ca8 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -113,8 +113,8 @@ var ( skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header // Path-based storage scheme of merkle patricia trie. - trieNodeAccountPrefix = []byte("A") // trieNodeAccountPrefix + hexPath -> trie node - trieNodeStoragePrefix = []byte("O") // trieNodeStoragePrefix + accountHash + hexPath -> trie node + TrieNodeAccountPrefix = []byte("A") // TrieNodeAccountPrefix + hexPath -> trie node + TrieNodeStoragePrefix = []byte("O") // TrieNodeStoragePrefix + accountHash + hexPath -> trie node stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage @@ -265,15 +265,15 @@ func stateIDKey(root common.Hash) []byte { return append(stateIDPrefix, root.Bytes()...) } -// accountTrieNodeKey = trieNodeAccountPrefix + nodePath. +// accountTrieNodeKey = TrieNodeAccountPrefix + nodePath. func accountTrieNodeKey(path []byte) []byte { - return append(trieNodeAccountPrefix, path...) + return append(TrieNodeAccountPrefix, path...) } -// storageTrieNodeKey = trieNodeStoragePrefix + accountHash + nodePath. +// storageTrieNodeKey = TrieNodeStoragePrefix + accountHash + nodePath. func storageTrieNodeKey(accountHash common.Hash, path []byte) []byte { - buf := make([]byte, len(trieNodeStoragePrefix)+common.HashLength+len(path)) - n := copy(buf, trieNodeStoragePrefix) + buf := make([]byte, len(TrieNodeStoragePrefix)+common.HashLength+len(path)) + n := copy(buf, TrieNodeStoragePrefix) n += copy(buf[n:], accountHash.Bytes()) copy(buf[n:], path) return buf @@ -294,16 +294,16 @@ func IsLegacyTrieNode(key []byte, val []byte) bool { // account trie node in path-based state scheme, and returns the resolved // node path if so. func ResolveAccountTrieNodeKey(key []byte) (bool, []byte) { - if !bytes.HasPrefix(key, trieNodeAccountPrefix) { + if !bytes.HasPrefix(key, TrieNodeAccountPrefix) { return false, nil } // The remaining key should only consist a hex node path // whose length is in the range 0 to 64 (64 is excluded // since leaves are always wrapped with shortNode). - if len(key) >= len(trieNodeAccountPrefix)+common.HashLength*2 { + if len(key) >= len(TrieNodeAccountPrefix)+common.HashLength*2 { return false, nil } - return true, key[len(trieNodeAccountPrefix):] + return true, key[len(TrieNodeAccountPrefix):] } // IsAccountTrieNode reports whether a provided database entry is an account @@ -317,20 +317,20 @@ func IsAccountTrieNode(key []byte) bool { // trie node in path-based state scheme, and returns the resolved account hash // and node path if so. func ResolveStorageTrieNode(key []byte) (bool, common.Hash, []byte) { - if !bytes.HasPrefix(key, trieNodeStoragePrefix) { + if !bytes.HasPrefix(key, TrieNodeStoragePrefix) { return false, common.Hash{}, nil } // The remaining key consists of 2 parts: // - 32 bytes account hash // - hex node path whose length is in the range 0 to 64 - if len(key) < len(trieNodeStoragePrefix)+common.HashLength { + if len(key) < len(TrieNodeStoragePrefix)+common.HashLength { return false, common.Hash{}, nil } - if len(key) >= len(trieNodeStoragePrefix)+common.HashLength+common.HashLength*2 { + if len(key) >= len(TrieNodeStoragePrefix)+common.HashLength+common.HashLength*2 { return false, common.Hash{}, nil } - accountHash := common.BytesToHash(key[len(trieNodeStoragePrefix) : len(trieNodeStoragePrefix)+common.HashLength]) - return true, accountHash, key[len(trieNodeStoragePrefix)+common.HashLength:] + accountHash := common.BytesToHash(key[len(TrieNodeStoragePrefix) : len(TrieNodeStoragePrefix)+common.HashLength]) + return true, accountHash, key[len(TrieNodeStoragePrefix)+common.HashLength:] } // IsStorageTrieNode reports whether a provided database entry is a storage diff --git a/triedb/pathdb/nodebuffer.go b/triedb/pathdb/nodebuffer.go index 4a7d328b9afb..8f84c2b44207 100644 --- a/triedb/pathdb/nodebuffer.go +++ b/triedb/pathdb/nodebuffer.go @@ -204,6 +204,19 @@ func (b *nodebuffer) setSize(size int, db ethdb.KeyValueStore, clean *fastcache. return b.flush(db, clean, id, false) } +// allocBatch returns a database batch with pre-allocated buffer. +func (b *nodebuffer) allocBatch(db ethdb.KeyValueStore) ethdb.Batch { + var metasize int + for owner, nodes := range b.nodes { + if owner == (common.Hash{}) { + metasize += len(nodes) * len(rawdb.TrieNodeAccountPrefix) // database key prefix + } else { + metasize += len(nodes) * (len(rawdb.TrieNodeStoragePrefix) + common.HashLength) // database key prefix + owner + } + } + return db.NewBatchWithSize((metasize + int(b.size)) * 11 / 10) // extra 10% for potential pebble internal stuff +} + // flush persists the in-memory dirty trie node into the disk if the configured // memory threshold is reached. Note, all data must be written atomically. func (b *nodebuffer) flush(db ethdb.KeyValueStore, clean *fastcache.Cache, id uint64, force bool) error { @@ -217,7 +230,7 @@ func (b *nodebuffer) flush(db ethdb.KeyValueStore, clean *fastcache.Cache, id ui } var ( start = time.Now() - batch = db.NewBatchWithSize(int(b.size)) + batch = b.allocBatch(db) ) nodes := writeNodes(batch, b.nodes, clean) rawdb.WritePersistentStateID(batch, id) From 5bae14f9df498243091078fc8d3ea6ab99669087 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 28 Feb 2024 20:40:28 +0800 Subject: [PATCH 005/571] triedb/pathdb: fix panic in recoverable (#29107) * triedb/pathdb: fix panic in recoverable * triedb/pathdb: add todo * triedb/pathdb: rename * triedb/pathdb: rename --- triedb/pathdb/database.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index f2d6cea635a9..307f307df53d 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -391,17 +391,23 @@ func (db *Database) Recoverable(root common.Hash) bool { if *id >= dl.stateID() { return false } + // This is a temporary workaround for the unavailability of the freezer in + // dev mode. As a consequence, the Pathdb loses the ability for deep reorg + // in certain cases. + // TODO(rjl493456442): Implement the in-memory ancient store. + if db.freezer == nil { + return false + } // Ensure the requested state is a canonical state and all state // histories in range [id+1, disklayer.ID] are present and complete. - parent := root return checkHistories(db.freezer, *id+1, dl.stateID()-*id, func(m *meta) error { - if m.parent != parent { + if m.parent != root { return errors.New("unexpected state history") } if len(m.incomplete) > 0 { return errors.New("incomplete state history") } - parent = m.root + root = m.root return nil }) == nil } From 9986a69c25452ff0e7ce323446b215e2d0075185 Mon Sep 17 00:00:00 2001 From: buddho Date: Thu, 29 Feb 2024 01:38:21 +0800 Subject: [PATCH 006/571] internal/ethapi: pass in accesslist in test (#29089) Co-authored-by: Sina Mahmoodi --- internal/ethapi/api_test.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index a6f7405eb363..8ffa638a6b5c 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -1272,10 +1272,14 @@ func TestFillBlobTransaction(t *testing.T) { func argsFromTransaction(tx *types.Transaction, from common.Address) TransactionArgs { var ( - gas = tx.Gas() - nonce = tx.Nonce() - input = tx.Data() + gas = tx.Gas() + nonce = tx.Nonce() + input = tx.Data() + accessList *types.AccessList ) + if acl := tx.AccessList(); acl != nil { + accessList = &acl + } return TransactionArgs{ From: &from, To: tx.To(), @@ -1286,10 +1290,9 @@ func argsFromTransaction(tx *types.Transaction, from common.Address) Transaction Nonce: (*hexutil.Uint64)(&nonce), Input: (*hexutil.Bytes)(&input), ChainID: (*hexutil.Big)(tx.ChainId()), - // TODO: impl accessList conversion - //AccessList: tx.AccessList(), - BlobFeeCap: (*hexutil.Big)(tx.BlobGasFeeCap()), - BlobHashes: tx.BlobHashes(), + AccessList: accessList, + BlobFeeCap: (*hexutil.Big)(tx.BlobGasFeeCap()), + BlobHashes: tx.BlobHashes(), } } From 1883438964a7a4c68cee1de619526e8bc1e68b30 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:59:16 -0700 Subject: [PATCH 007/571] eth/catalyst: return invalid payload attributes instead of invalid parms for bad fcu payload (#29115) --- eth/catalyst/api.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 58566a47fc6c..fea9d34cb83e 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -190,21 +190,21 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa // attributes. It supports both PayloadAttributesV1 and PayloadAttributesV2. func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { if params != nil { + if params.BeaconRoot != nil { + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("unexpected beacon root")) + } switch api.eth.BlockChain().Config().LatestFork(params.Timestamp) { case forks.Paris: if params.Withdrawals != nil { - return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("withdrawals before shanghai")) + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai")) } case forks.Shanghai: if params.Withdrawals == nil { - return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("missing withdrawals")) + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing withdrawals")) } default: return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV2 must only be called with paris and shanghai payloads")) } - if params.BeaconRoot != nil { - return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("unexpected beacon root")) - } } return api.forkchoiceUpdated(update, params, engine.PayloadV2, false) } @@ -213,15 +213,11 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa // in the payload attributes. It supports only PayloadAttributesV3. func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { if params != nil { - // TODO(matt): according to https://github.com/ethereum/execution-apis/pull/498, - // payload attributes that are invalid should return error - // engine.InvalidPayloadAttributes. Once hive updates this, we should update - // on our end. if params.Withdrawals == nil { - return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("missing withdrawals")) + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing withdrawals")) } if params.BeaconRoot == nil { - return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("missing beacon root")) + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root")) } if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads")) From dbc27a199f411fc620eeb8589fd75a144f83ee8c Mon Sep 17 00:00:00 2001 From: cui fliter Date: Thu, 29 Feb 2024 17:29:06 +0800 Subject: [PATCH 008/571] all: fix function names in docs (#29128) Signed-off-by: cui fliter --- eth/peerset.go | 2 +- eth/protocols/eth/dispatcher.go | 2 +- internal/era/iterator.go | 2 +- metrics/sample.go | 2 +- p2p/enode/nodedb.go | 4 ++-- rpc/handler.go | 2 +- signer/core/signed_data.go | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/eth/peerset.go b/eth/peerset.go index c0c11e3e85ee..c56a7223e964 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -100,7 +100,7 @@ func (ps *peerSet) registerSnapExtension(peer *snap.Peer) error { return nil } -// waitExtensions blocks until all satellite protocols are connected and tracked +// waitSnapExtension blocks until all satellite protocols are connected and tracked // by the peerset. func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { // If the peer does not support a compatible `snap`, don't wait diff --git a/eth/protocols/eth/dispatcher.go b/eth/protocols/eth/dispatcher.go index ae98820cd6ac..146eec3f6085 100644 --- a/eth/protocols/eth/dispatcher.go +++ b/eth/protocols/eth/dispatcher.go @@ -136,7 +136,7 @@ func (p *Peer) dispatchRequest(req *Request) error { } } -// dispatchRequest fulfils a pending request and delivers it to the requested +// dispatchResponse fulfils a pending request and delivers it to the requested // sink. func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) error { resOp := &response{ diff --git a/internal/era/iterator.go b/internal/era/iterator.go index e74a8154b1a6..5dfc12445f79 100644 --- a/internal/era/iterator.go +++ b/internal/era/iterator.go @@ -30,7 +30,7 @@ type Iterator struct { inner *RawIterator } -// NewRawIterator returns a new Iterator instance. Next must be immediately +// NewIterator returns a new Iterator instance. Next must be immediately // called on new iterators to load the first item. func NewIterator(e *Era) (*Iterator, error) { inner, err := NewRawIterator(e) diff --git a/metrics/sample.go b/metrics/sample.go index 5398dd42d5de..bb81e105cf9e 100644 --- a/metrics/sample.go +++ b/metrics/sample.go @@ -148,7 +148,7 @@ func (NilSample) Clear() {} func (NilSample) Snapshot() SampleSnapshot { return (*emptySnapshot)(nil) } func (NilSample) Update(v int64) {} -// SamplePercentiles returns an arbitrary percentile of the slice of int64. +// SamplePercentile returns an arbitrary percentile of the slice of int64. func SamplePercentile(values []int64, p float64) float64 { return CalculatePercentiles(values, []float64{p})[0] } diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go index 7e7fb69b293a..6d55ce17f130 100644 --- a/p2p/enode/nodedb.go +++ b/p2p/enode/nodedb.go @@ -84,7 +84,7 @@ func OpenDB(path string) (*DB, error) { return newPersistentDB(path) } -// newMemoryNodeDB creates a new in-memory node database without a persistent backend. +// newMemoryDB creates a new in-memory node database without a persistent backend. func newMemoryDB() (*DB, error) { db, err := leveldb.Open(storage.NewMemStorage(), nil) if err != nil { @@ -93,7 +93,7 @@ func newMemoryDB() (*DB, error) { return &DB{lvl: db, quit: make(chan struct{})}, nil } -// newPersistentNodeDB creates/opens a leveldb backed persistent node database, +// newPersistentDB creates/opens a leveldb backed persistent node database, // also flushing its contents in case of a version mismatch. func newPersistentDB(path string) (*DB, error) { opts := &opt.Options{OpenFilesCacheCapacity: 5} diff --git a/rpc/handler.go b/rpc/handler.go index f44e4d7b01d8..792581cbc0ad 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -324,7 +324,7 @@ func (h *handler) addRequestOp(op *requestOp) { } } -// removeRequestOps stops waiting for the given request IDs. +// removeRequestOp stops waiting for the given request IDs. func (h *handler) removeRequestOp(op *requestOp) { for _, id := range op.ids { delete(h.respWait, string(id)) diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index c6ae7b12743f..f8b3c9d86d1d 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -260,7 +260,7 @@ func fromHex(data any) ([]byte, error) { return nil, fmt.Errorf("wrong type %T", data) } -// typeDataRequest tries to convert the data into a SignDataRequest. +// typedDataRequest tries to convert the data into a SignDataRequest. func typedDataRequest(data any) (*SignDataRequest, error) { var typedData apitypes.TypedData if td, ok := data.(apitypes.TypedData); ok { From 28d55218f7d793c184f4220a16a60e309caa70af Mon Sep 17 00:00:00 2001 From: Ng Wei Han <47109095+weiihann@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:56:17 +0800 Subject: [PATCH 009/571] cmd/geth: parseDumpConfig should not return closed db (#29100) * cmd: parseDumpConfig should not return closed db * fix lint --- cmd/geth/chaincmd.go | 24 ++++++++++++------------ cmd/geth/snapshot.go | 5 ++++- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index d333c175599d..c8041d563a1a 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -514,13 +514,10 @@ func importPreimages(ctx *cli.Context) error { return nil } -func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, ethdb.Database, common.Hash, error) { - db := utils.MakeChainDatabase(ctx, stack, true) - defer db.Close() - +func parseDumpConfig(ctx *cli.Context, stack *node.Node, db ethdb.Database) (*state.DumpConfig, common.Hash, error) { var header *types.Header if ctx.NArg() > 1 { - return nil, nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg()) + return nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg()) } if ctx.NArg() == 1 { arg := ctx.Args().First() @@ -529,17 +526,17 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth if number := rawdb.ReadHeaderNumber(db, hash); number != nil { header = rawdb.ReadHeader(db, hash, *number) } else { - return nil, nil, common.Hash{}, fmt.Errorf("block %x not found", hash) + return nil, common.Hash{}, fmt.Errorf("block %x not found", hash) } } else { number, err := strconv.ParseUint(arg, 10, 64) if err != nil { - return nil, nil, common.Hash{}, err + return nil, common.Hash{}, err } if hash := rawdb.ReadCanonicalHash(db, number); hash != (common.Hash{}) { header = rawdb.ReadHeader(db, hash, number) } else { - return nil, nil, common.Hash{}, fmt.Errorf("header for block %d not found", number) + return nil, common.Hash{}, fmt.Errorf("header for block %d not found", number) } } } else { @@ -547,7 +544,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth header = rawdb.ReadHeadHeader(db) } if header == nil { - return nil, nil, common.Hash{}, errors.New("no head block found") + return nil, common.Hash{}, errors.New("no head block found") } startArg := common.FromHex(ctx.String(utils.StartKeyFlag.Name)) var start common.Hash @@ -559,7 +556,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth start = crypto.Keccak256Hash(startArg) log.Info("Converting start-address to hash", "address", common.BytesToAddress(startArg), "hash", start.Hex()) default: - return nil, nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg) + return nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg) } var conf = &state.DumpConfig{ SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name), @@ -571,14 +568,17 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth log.Info("State dump configured", "block", header.Number, "hash", header.Hash().Hex(), "skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage, "start", hexutil.Encode(conf.Start), "limit", conf.Max) - return conf, db, header.Root, nil + return conf, header.Root, nil } func dump(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - conf, db, root, err := parseDumpConfig(ctx, stack) + db := utils.MakeChainDatabase(ctx, stack, true) + defer db.Close() + + conf, root, err := parseDumpConfig(ctx, stack, db) if err != nil { return err } diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 4284005a0221..1e0933e46f59 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -541,7 +541,10 @@ func dumpState(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - conf, db, root, err := parseDumpConfig(ctx, stack) + db := utils.MakeChainDatabase(ctx, stack, true) + defer db.Close() + + conf, root, err := parseDumpConfig(ctx, stack, db) if err != nil { return err } From db4cf6916606e07d908af44e405257925dd9265e Mon Sep 17 00:00:00 2001 From: yzb <335357057@qq.com> Date: Thu, 29 Feb 2024 17:56:46 +0800 Subject: [PATCH 010/571] all: replace fmt.Errorf() with errors.New() if no param required (#29126) replace-fmt-errorf Co-authored-by: yzb@example.cn --- cmd/era/main.go | 7 ++++--- cmd/geth/chaincmd.go | 2 +- cmd/utils/cmd.go | 2 +- core/txpool/validation.go | 5 +++-- internal/era/accumulator.go | 3 ++- internal/era/builder.go | 3 ++- internal/era/e2store/e2store.go | 3 ++- internal/era/e2store/e2store_test.go | 4 ++-- internal/era/era.go | 3 ++- internal/era/iterator.go | 3 ++- miner/worker.go | 2 +- node/rpcstack.go | 5 +++-- p2p/discover/v4_udp.go | 2 +- p2p/discover/v5_udp.go | 2 +- p2p/discover/v5wire/encoding.go | 6 +++--- p2p/dnsdisc/client.go | 2 +- p2p/dnsdisc/tree.go | 3 ++- p2p/enode/idscheme.go | 4 ++-- p2p/nat/natpmp.go | 3 ++- p2p/simulations/adapters/exec.go | 2 +- signer/core/apitypes/types.go | 2 +- trie/trie_test.go | 10 +++++----- triedb/pathdb/history.go | 2 +- 23 files changed, 45 insertions(+), 35 deletions(-) diff --git a/cmd/era/main.go b/cmd/era/main.go index e27d8ccec605..c7f5de12bc1a 100644 --- a/cmd/era/main.go +++ b/cmd/era/main.go @@ -18,6 +18,7 @@ package main import ( "encoding/json" + "errors" "fmt" "math/big" "os" @@ -182,7 +183,7 @@ func open(ctx *cli.Context, epoch uint64) (*era.Era, error) { // that the accumulator matches the expected value. func verify(ctx *cli.Context) error { if ctx.Args().Len() != 1 { - return fmt.Errorf("missing accumulators file") + return errors.New("missing accumulators file") } roots, err := readHashes(ctx.Args().First()) @@ -203,7 +204,7 @@ func verify(ctx *cli.Context) error { } if len(entries) != len(roots) { - return fmt.Errorf("number of era1 files should match the number of accumulator hashes") + return errors.New("number of era1 files should match the number of accumulator hashes") } // Verify each epoch matches the expected root. @@ -308,7 +309,7 @@ func checkAccumulator(e *era.Era) error { func readHashes(f string) ([]common.Hash, error) { b, err := os.ReadFile(f) if err != nil { - return nil, fmt.Errorf("unable to open accumulators file") + return nil, errors.New("unable to open accumulators file") } s := strings.Split(string(b), "\n") // Remove empty last element, if present. diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index c8041d563a1a..17aab678768d 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -444,7 +444,7 @@ func importHistory(ctx *cli.Context) error { return fmt.Errorf("no era1 files found in %s", dir) } if len(networks) > 1 { - return fmt.Errorf("multiple networks found, use a network flag to specify desired network") + return errors.New("multiple networks found, use a network flag to specify desired network") } network = networks[0] } diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 4b5716466556..37736dda8509 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -245,7 +245,7 @@ func readList(filename string) ([]string, error) { // starting from genesis. func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, network string) error { if chain.CurrentSnapBlock().Number.BitLen() != 0 { - return fmt.Errorf("history import only supported when starting from genesis") + return errors.New("history import only supported when starting from genesis") } entries, err := era.ReadDir(dir, network) if err != nil { diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 8913859e846e..63f127f55ca2 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -18,6 +18,7 @@ package txpool import ( "crypto/sha256" + "errors" "fmt" "math/big" @@ -120,13 +121,13 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } sidecar := tx.BlobTxSidecar() if sidecar == nil { - return fmt.Errorf("missing sidecar in blob transaction") + return errors.New("missing sidecar in blob transaction") } // Ensure the number of items in the blob transaction and various side // data match up before doing any expensive validations hashes := tx.BlobHashes() if len(hashes) == 0 { - return fmt.Errorf("blobless blob transaction") + return errors.New("blobless blob transaction") } if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob { return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) diff --git a/internal/era/accumulator.go b/internal/era/accumulator.go index 19e03973f1f5..2ece2755e12d 100644 --- a/internal/era/accumulator.go +++ b/internal/era/accumulator.go @@ -17,6 +17,7 @@ package era import ( + "errors" "fmt" "math/big" @@ -28,7 +29,7 @@ import ( // accumulator of header records. func ComputeAccumulator(hashes []common.Hash, tds []*big.Int) (common.Hash, error) { if len(hashes) != len(tds) { - return common.Hash{}, fmt.Errorf("must have equal number hashes as td values") + return common.Hash{}, errors.New("must have equal number hashes as td values") } if len(hashes) > MaxEra1Size { return common.Hash{}, fmt.Errorf("too many records: have %d, max %d", len(hashes), MaxEra1Size) diff --git a/internal/era/builder.go b/internal/era/builder.go index 9217c049f33b..75782a08c251 100644 --- a/internal/era/builder.go +++ b/internal/era/builder.go @@ -18,6 +18,7 @@ package era import ( "bytes" "encoding/binary" + "errors" "fmt" "io" "math/big" @@ -158,7 +159,7 @@ func (b *Builder) AddRLP(header, body, receipts []byte, number uint64, hash comm // corresponding e2store entries. func (b *Builder) Finalize() (common.Hash, error) { if b.startNum == nil { - return common.Hash{}, fmt.Errorf("finalize called on empty builder") + return common.Hash{}, errors.New("finalize called on empty builder") } // Compute accumulator root and write entry. root, err := ComputeAccumulator(b.hashes, b.tds) diff --git a/internal/era/e2store/e2store.go b/internal/era/e2store/e2store.go index d85b3e44e97d..8e4d5dd24a55 100644 --- a/internal/era/e2store/e2store.go +++ b/internal/era/e2store/e2store.go @@ -18,6 +18,7 @@ package e2store import ( "encoding/binary" + "errors" "fmt" "io" ) @@ -160,7 +161,7 @@ func (r *Reader) ReadMetadataAt(off int64) (typ uint16, length uint32, err error // Check reserved bytes of header. if b[6] != 0 || b[7] != 0 { - return 0, 0, fmt.Errorf("reserved bytes are non-zero") + return 0, 0, errors.New("reserved bytes are non-zero") } return typ, length, nil diff --git a/internal/era/e2store/e2store_test.go b/internal/era/e2store/e2store_test.go index febcffe4cf2c..b0803493c7cd 100644 --- a/internal/era/e2store/e2store_test.go +++ b/internal/era/e2store/e2store_test.go @@ -18,7 +18,7 @@ package e2store import ( "bytes" - "fmt" + "errors" "io" "testing" @@ -92,7 +92,7 @@ func TestDecode(t *testing.T) { }, { // basic invalid decoding have: "ffff000000000001", - err: fmt.Errorf("reserved bytes are non-zero"), + err: errors.New("reserved bytes are non-zero"), }, { // no more entries to read, returns EOF have: "", diff --git a/internal/era/era.go b/internal/era/era.go index a0e701b7e0f9..2099c2d575c7 100644 --- a/internal/era/era.go +++ b/internal/era/era.go @@ -18,6 +18,7 @@ package era import ( "encoding/binary" + "errors" "fmt" "io" "math/big" @@ -127,7 +128,7 @@ func (e *Era) Close() error { func (e *Era) GetBlockByNumber(num uint64) (*types.Block, error) { if e.m.start > num || e.m.start+e.m.count <= num { - return nil, fmt.Errorf("out-of-bounds") + return nil, errors.New("out-of-bounds") } off, err := e.readOffset(num) if err != nil { diff --git a/internal/era/iterator.go b/internal/era/iterator.go index 5dfc12445f79..d90e9586a4e6 100644 --- a/internal/era/iterator.go +++ b/internal/era/iterator.go @@ -17,6 +17,7 @@ package era import ( + "errors" "fmt" "io" "math/big" @@ -61,7 +62,7 @@ func (it *Iterator) Error() error { // Block returns the block for the iterator's current position. func (it *Iterator) Block() (*types.Block, error) { if it.inner.Header == nil || it.inner.Body == nil { - return nil, fmt.Errorf("header and body must be non-nil") + return nil, errors.New("header and body must be non-nil") } var ( header types.Header diff --git a/miner/worker.go b/miner/worker.go index 9a36106231e9..134f91cafc4b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -947,7 +947,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { if genParams.parentHash != (common.Hash{}) { block := w.chain.GetBlockByHash(genParams.parentHash) if block == nil { - return nil, fmt.Errorf("missing parent") + return nil, errors.New("missing parent") } parent = block.Header() } diff --git a/node/rpcstack.go b/node/rpcstack.go index d80d5271a7fa..253db0d564a6 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -19,6 +19,7 @@ package node import ( "compress/gzip" "context" + "errors" "fmt" "io" "net" @@ -299,7 +300,7 @@ func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error { defer h.mu.Unlock() if h.rpcAllowed() { - return fmt.Errorf("JSON-RPC over HTTP is already enabled") + return errors.New("JSON-RPC over HTTP is already enabled") } // Create RPC server and handler. @@ -335,7 +336,7 @@ func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error { defer h.mu.Unlock() if h.wsAllowed() { - return fmt.Errorf("JSON-RPC over WebSocket is already enabled") + return errors.New("JSON-RPC over WebSocket is already enabled") } // Create RPC server and handler. srv := rpc.NewServer() diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 988f16b01df2..44b1f5305c45 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -364,7 +364,7 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { return nil, err } if respN.ID() != n.ID() { - return nil, fmt.Errorf("invalid ID in response record") + return nil, errors.New("invalid ID in response record") } if respN.Seq() < n.Seq() { return n, nil // response record is older diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 8b3e33d37cf7..71f8d8dd0899 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -442,7 +442,7 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s } } if _, ok := seen[node.ID()]; ok { - return nil, fmt.Errorf("duplicate record") + return nil, errors.New("duplicate record") } seen[node.ID()] = struct{}{} return node, nil diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index 5108910620e0..904a3ddec6f2 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -367,11 +367,11 @@ func (c *Codec) makeHandshakeAuth(toID enode.ID, addr string, challenge *Whoarey // key is part of the ID nonce signature. var remotePubkey = new(ecdsa.PublicKey) if err := challenge.Node.Load((*enode.Secp256k1)(remotePubkey)); err != nil { - return nil, nil, fmt.Errorf("can't find secp256k1 key for recipient") + return nil, nil, errors.New("can't find secp256k1 key for recipient") } ephkey, err := c.sc.ephemeralKeyGen() if err != nil { - return nil, nil, fmt.Errorf("can't generate ephemeral key") + return nil, nil, errors.New("can't generate ephemeral key") } ephpubkey := EncodePubkey(&ephkey.PublicKey) auth.pubkey = ephpubkey[:] @@ -395,7 +395,7 @@ func (c *Codec) makeHandshakeAuth(toID enode.ID, addr string, challenge *Whoarey // Create session keys. sec := deriveKeys(sha256.New, ephkey, remotePubkey, c.localnode.ID(), challenge.Node.ID(), cdata) if sec == nil { - return nil, nil, fmt.Errorf("key derivation failed") + return nil, nil, errors.New("key derivation failed") } return auth, sec, err } diff --git a/p2p/dnsdisc/client.go b/p2p/dnsdisc/client.go index 8f1c221b8038..4f14d860e1ec 100644 --- a/p2p/dnsdisc/client.go +++ b/p2p/dnsdisc/client.go @@ -191,7 +191,7 @@ func (c *Client) resolveEntry(ctx context.Context, domain, hash string) (entry, func (c *Client) doResolveEntry(ctx context.Context, domain, hash string) (entry, error) { wantHash, err := b32format.DecodeString(hash) if err != nil { - return nil, fmt.Errorf("invalid base32 hash") + return nil, errors.New("invalid base32 hash") } name := hash + "." + domain txts, err := c.cfg.Resolver.LookupTXT(ctx, hash+"."+domain) diff --git a/p2p/dnsdisc/tree.go b/p2p/dnsdisc/tree.go index 7d9703a34558..dfac4fb37208 100644 --- a/p2p/dnsdisc/tree.go +++ b/p2p/dnsdisc/tree.go @@ -21,6 +21,7 @@ import ( "crypto/ecdsa" "encoding/base32" "encoding/base64" + "errors" "fmt" "io" "strings" @@ -341,7 +342,7 @@ func parseLinkEntry(e string) (entry, error) { func parseLink(e string) (*linkEntry, error) { if !strings.HasPrefix(e, linkPrefix) { - return nil, fmt.Errorf("wrong/missing scheme 'enrtree' in URL") + return nil, errors.New("wrong/missing scheme 'enrtree' in URL") } e = e[len(linkPrefix):] diff --git a/p2p/enode/idscheme.go b/p2p/enode/idscheme.go index fd5d868b761d..6ad7f809a71d 100644 --- a/p2p/enode/idscheme.go +++ b/p2p/enode/idscheme.go @@ -18,7 +18,7 @@ package enode import ( "crypto/ecdsa" - "fmt" + "errors" "io" "github.com/ethereum/go-ethereum/common/math" @@ -67,7 +67,7 @@ func (V4ID) Verify(r *enr.Record, sig []byte) error { if err := r.Load(&entry); err != nil { return err } else if len(entry) != 33 { - return fmt.Errorf("invalid public key") + return errors.New("invalid public key") } h := sha3.NewLegacyKeccak256() diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index 97601c99dcbb..ea2d8978293f 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -17,6 +17,7 @@ package nat import ( + "errors" "fmt" "net" "strings" @@ -46,7 +47,7 @@ func (n *pmp) ExternalIP() (net.IP, error) { func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) { if lifetime <= 0 { - return 0, fmt.Errorf("lifetime must not be <= 0") + return 0, errors.New("lifetime must not be <= 0") } // Note order of port arguments is switched between our // AddMapping and the client's AddPortMapping. diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go index 63cc4936c1bd..17e0f75d5ab9 100644 --- a/p2p/simulations/adapters/exec.go +++ b/p2p/simulations/adapters/exec.go @@ -460,7 +460,7 @@ func startExecNodeStack() (*node.Node, error) { // decode the config confEnv := os.Getenv(envNodeConfig) if confEnv == "" { - return nil, fmt.Errorf("missing " + envNodeConfig) + return nil, errors.New("missing " + envNodeConfig) } var conf execNodeConfig if err := json.Unmarshal([]byte(confEnv), &conf); err != nil { diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 6bfcd2a727b4..e28f059106f3 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -708,7 +708,7 @@ func formatPrimitiveValue(encType string, encValue interface{}) (string, error) func (t Types) validate() error { for typeKey, typeArr := range t { if len(typeKey) == 0 { - return fmt.Errorf("empty type key") + return errors.New("empty type key") } for i, typeObj := range typeArr { if len(typeObj.Type) == 0 { diff --git a/trie/trie_test.go b/trie/trie_test.go index 379a866f7ea0..920594fdd24f 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -556,7 +556,7 @@ func runRandTest(rt randTest) error { checktr.MustUpdate(it.Key, it.Value) } if tr.Hash() != checktr.Hash() { - rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") + rt[i].err = errors.New("hash mismatch in opItercheckhash") } case opNodeDiff: var ( @@ -594,19 +594,19 @@ func runRandTest(rt randTest) error { } } if len(insertExp) != len(tr.tracer.inserts) { - rt[i].err = fmt.Errorf("insert set mismatch") + rt[i].err = errors.New("insert set mismatch") } if len(deleteExp) != len(tr.tracer.deletes) { - rt[i].err = fmt.Errorf("delete set mismatch") + rt[i].err = errors.New("delete set mismatch") } for insert := range tr.tracer.inserts { if _, present := insertExp[insert]; !present { - rt[i].err = fmt.Errorf("missing inserted node") + rt[i].err = errors.New("missing inserted node") } } for del := range tr.tracer.deletes { if _, present := deleteExp[del]; !present { - rt[i].err = fmt.Errorf("missing deleted node") + rt[i].err = errors.New("missing deleted node") } } } diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 6e3f3faaedce..051e122bec64 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -215,7 +215,7 @@ func (m *meta) encode() []byte { // decode unpacks the meta object from byte stream. func (m *meta) decode(blob []byte) error { if len(blob) < 1 { - return fmt.Errorf("no version tag") + return errors.New("no version tag") } switch blob[0] { case stateHistoryVersion: From 865e1e9f577f4fa804d0246f82cbcedc27db9bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 29 Feb 2024 12:40:59 +0200 Subject: [PATCH 011/571] cmd/utils, core/rawdb, triedb/pathdb: flip hash to path scheme (#29108) * cmd/utils, core/rawdb, triedb/pathdb: flip hash to path scheme * graphql: run tests in hash mode as the chain maker needs it --- cmd/utils/flags.go | 3 +++ core/rawdb/accessors_trie.go | 8 +++----- graphql/graphql_test.go | 2 ++ triedb/pathdb/database.go | 1 - 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b813e52970d8..82af26ff9659 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1668,6 +1668,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.String(GCModeFlag.Name) == "archive" && cfg.TransactionHistory != 0 { cfg.TransactionHistory = 0 log.Warn("Disabled transaction unindexing for archive node") + + cfg.StateScheme = rawdb.HashScheme + log.Warn("Forcing hash state-scheme for archive mode") } if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index ea3367db3606..e34b24fd7661 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -315,7 +315,7 @@ func ReadStateScheme(db ethdb.Reader) string { // the stored state. // // - If the provided scheme is none, use the scheme consistent with persistent -// state, or fallback to hash-based scheme if state is empty. +// state, or fallback to path-based scheme if state is empty. // // - If the provided scheme is hash, use hash-based scheme or error out if not // compatible with persistent state scheme. @@ -329,10 +329,8 @@ func ParseStateScheme(provided string, disk ethdb.Database) (string, error) { stored := ReadStateScheme(disk) if provided == "" { if stored == "" { - // use default scheme for empty database, flip it when - // path mode is chosen as default - log.Info("State schema set to default", "scheme", "hash") - return HashScheme, nil + log.Info("State schema set to default", "scheme", "path") + return PathScheme, nil // use default scheme for empty database } log.Info("State scheme set to already existing", "scheme", stored) return stored, nil // reuse scheme of persistent scheme diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 1dda10205822..f3f9d1778ab0 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -452,6 +453,7 @@ func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Ge TrieDirtyCache: 5, TrieTimeout: 60 * time.Minute, SnapshotCache: 5, + StateScheme: rawdb.HashScheme, } var engine consensus.Engine = ethash.NewFaker() if shanghai { diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 307f307df53d..3e8e83a00c2c 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -203,7 +203,6 @@ func New(diskdb ethdb.Database, config *Config) *Database { log.Crit("Failed to disable database", "err", err) // impossible to happen } } - log.Warn("Path-based state scheme is an experimental feature") return db } From 0a2f33946b95989e8ce36e72a88138adceab6a23 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Thu, 29 Feb 2024 13:17:32 +0100 Subject: [PATCH 012/571] eth/catalyst: update simulated beacon for cancun (#28829) * eth/catalyst: update simulated beacon for cancun * validate blob hashes * compute hashes from commitment * fix beacon root and payload version * check commitment conversion * fix random attr * flip dev to cancun --- eth/catalyst/simulated_beacon.go | 21 ++++++++++++++++++--- params/config.go | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index f1c5689e1d28..4ae60ed4907c 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -18,6 +18,7 @@ package catalyst import ( "crypto/rand" + "crypto/sha256" "errors" "math/big" "sync" @@ -27,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -161,14 +163,14 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u SuggestedFeeRecipient: feeRecipient, Withdrawals: withdrawals, Random: random, - }, engine.PayloadV2, true) + BeaconRoot: &common.Hash{}, + }, engine.PayloadV3, true) if err != nil { return err } if fcResponse == engine.STATUS_SYNCING { return errors.New("chain rewind prevented invocation of payload creation") } - envelope, err := c.engineAPI.getPayload(*fcResponse.PayloadID, true) if err != nil { return err @@ -186,8 +188,21 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u } } + // Independently calculate the blob hashes from sidecars. + blobHashes := make([]common.Hash, 0) + if envelope.BlobsBundle != nil { + hasher := sha256.New() + for _, commit := range envelope.BlobsBundle.Commitments { + var c kzg4844.Commitment + if len(commit) != len(c) { + return errors.New("invalid commitment length") + } + copy(c[:], commit) + blobHashes = append(blobHashes, kzg4844.CalcBlobHashV1(hasher, &c)) + } + } // Mark the payload as canon - if _, err = c.engineAPI.NewPayloadV2(*payload); err != nil { + if _, err = c.engineAPI.NewPayloadV3(*payload, blobHashes, &common.Hash{}); err != nil { return err } c.setCurrentState(payload.BlockHash, finalizedHash) diff --git a/params/config.go b/params/config.go index 21ede457fd68..b24e782b8d96 100644 --- a/params/config.go +++ b/params/config.go @@ -183,6 +183,7 @@ var ( ArrowGlacierBlock: big.NewInt(0), GrayGlacierBlock: big.NewInt(0), ShanghaiTime: newUint64(0), + CancunTime: newUint64(0), TerminalTotalDifficulty: big.NewInt(0), TerminalTotalDifficultyPassed: true, } From 0b1438c3df5da5551e89dddc683d65f4d48ad3d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Sat, 2 Mar 2024 22:39:22 +0200 Subject: [PATCH 013/571] eth: make transaction propagation paths in the network deterministic (#29034) * eth: make transaction propagation paths in the network deterministic * eth: avoid potential division by 0 * eth: make tx propagation dependent on local node id too * eth: fix review comments --- eth/backend.go | 1 + eth/handler.go | 57 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 0a0813aafac6..09e1dbd258cd 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -236,6 +236,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // Permit the downloader to use the trie cache allowance during fast sync cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit if eth.handler, err = newHandler(&handlerConfig{ + NodeID: eth.p2pServer.Self().ID(), Database: chainDb, Chain: eth.blockchain, TxPool: eth.txPool, diff --git a/eth/handler.go b/eth/handler.go index 0343a5787012..bc27eb4b88c5 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/fetcher" "github.com/ethereum/go-ethereum/eth/protocols/eth" @@ -41,7 +42,9 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/triedb/pathdb" + "golang.org/x/crypto/sha3" ) const ( @@ -84,6 +87,7 @@ type txPool interface { // handlerConfig is the collection of initialization parameters to create a full // node network handler. type handlerConfig struct { + NodeID enode.ID // P2P node ID used for tx propagation topology Database ethdb.Database // Database for direct sync insertions Chain *core.BlockChain // Blockchain to serve data from TxPool txPool // Transaction pool to propagate from @@ -96,6 +100,7 @@ type handlerConfig struct { } type handler struct { + nodeID enode.ID networkID uint64 forkFilter forkid.Filter // Fork ID filter, constant across the lifetime of the node @@ -137,6 +142,7 @@ func newHandler(config *handlerConfig) (*handler, error) { config.EventMux = new(event.TypeMux) // Nicety initialization for tests } h := &handler{ + nodeID: config.NodeID, networkID: config.Network, forkFilter: forkid.NewFilter(config.Chain), eventMux: config.EventMux, @@ -614,25 +620,54 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { annos = make(map[*ethPeer][]common.Hash) // Set peer->hash to announce ) // Broadcast transactions to a batch of peers not knowing about it - for _, tx := range txs { - peers := h.peers.peersWithoutTransaction(tx.Hash()) + direct := big.NewInt(int64(math.Sqrt(float64(h.peers.len())))) // Approximate number of peers to broadcast to + if direct.BitLen() == 0 { + direct = big.NewInt(1) + } + total := new(big.Int).Exp(direct, big.NewInt(2), nil) // Stabilise total peer count a bit based on sqrt peers - var numDirect int + var ( + signer = types.LatestSignerForChainID(h.chain.Config().ChainID) // Don't care about chain status, we just need *a* sender + hasher = sha3.NewLegacyKeccak256().(crypto.KeccakState) + hash = make([]byte, 32) + ) + for _, tx := range txs { + var maybeDirect bool switch { case tx.Type() == types.BlobTxType: blobTxs++ case tx.Size() > txMaxBroadcastSize: largeTxs++ default: - numDirect = int(math.Sqrt(float64(len(peers)))) + maybeDirect = true } - // Send the tx unconditionally to a subset of our peers - for _, peer := range peers[:numDirect] { - txset[peer] = append(txset[peer], tx.Hash()) - } - // For the remaining peers, send announcement only - for _, peer := range peers[numDirect:] { - annos[peer] = append(annos[peer], tx.Hash()) + // Send the transaction (if it's small enough) directly to a subset of + // the peers that have not received it yet, ensuring that the flow of + // transactions is groupped by account to (try and) avoid nonce gaps. + // + // To do this, we hash the local enode IW with together with a peer's + // enode ID together with the transaction sender and broadcast if + // `sha(self, peer, sender) mod peers < sqrt(peers)`. + for _, peer := range h.peers.peersWithoutTransaction(tx.Hash()) { + var broadcast bool + if maybeDirect { + hasher.Reset() + hasher.Write(h.nodeID.Bytes()) + hasher.Write(peer.Node().ID().Bytes()) + + from, _ := types.Sender(signer, tx) // Ignore error, we only use the addr as a propagation target splitter + hasher.Write(from.Bytes()) + + hasher.Read(hash) + if new(big.Int).Mod(new(big.Int).SetBytes(hash), total).Cmp(direct) < 0 { + broadcast = true + } + } + if broadcast { + txset[peer] = append(txset[peer], tx.Hash()) + } else { + annos[peer] = append(annos[peer], tx.Hash()) + } } } for peer, hashes := range txset { From 00905f7dc406cfb67f64cd74113777044fb886d8 Mon Sep 17 00:00:00 2001 From: Undefinedor Date: Sun, 3 Mar 2024 04:42:50 +0800 Subject: [PATCH 014/571] all: remove redundant import aliases (#29144) --- cmd/geth/snapshot.go | 2 +- cmd/geth/verkle.go | 2 +- consensus/clique/clique.go | 2 +- eth/protocols/snap/metrics.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 1e0933e46f59..192c850868c8 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -36,7 +36,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - cli "github.com/urfave/cli/v2" + "github.com/urfave/cli/v2" ) var ( diff --git a/cmd/geth/verkle.go b/cmd/geth/verkle.go index 420b063d8ba1..ff3931356e8f 100644 --- a/cmd/geth/verkle.go +++ b/cmd/geth/verkle.go @@ -29,7 +29,7 @@ import ( "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/gballet/go-verkle" - cli "github.com/urfave/cli/v2" + "github.com/urfave/cli/v2" ) var ( diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index c693189ea5ef..59f0e96ebe3e 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -30,7 +30,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - lru "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" diff --git a/eth/protocols/snap/metrics.go b/eth/protocols/snap/metrics.go index a7d071953f67..a8dc2b582432 100644 --- a/eth/protocols/snap/metrics.go +++ b/eth/protocols/snap/metrics.go @@ -17,7 +17,7 @@ package snap import ( - metrics "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/metrics" ) var ( From a732ad036488e3d5db33928f0155ffd66e08c08d Mon Sep 17 00:00:00 2001 From: yzb Date: Mon, 4 Mar 2024 17:16:05 +0800 Subject: [PATCH 015/571] p2p: remove unused argument 'flags' (#29132) --- p2p/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/server.go b/p2p/server.go index 975a3bb91662..5b7afb4565b9 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -937,7 +937,7 @@ func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *enode.Node) c.transport = srv.newTransport(fd, dialDest.Pubkey()) } - err := srv.setupConn(c, flags, dialDest) + err := srv.setupConn(c, dialDest) if err != nil { if !c.is(inboundConn) { markDialError(err) @@ -947,7 +947,7 @@ func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *enode.Node) return err } -func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) error { +func (srv *Server) setupConn(c *conn, dialDest *enode.Node) error { // Prevent leftover pending conns from entering the handshake. srv.lock.Lock() running := srv.running From b408b3e5fece3524bf7721ac8dd8d9a898f571a8 Mon Sep 17 00:00:00 2001 From: yzb Date: Mon, 4 Mar 2024 17:24:24 +0800 Subject: [PATCH 016/571] accounts/abi: delete duplicate error check (#29136) --- accounts/abi/type.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 2eee11787fda..383982663331 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -179,9 +179,6 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty return Type{}, errors.New("abi: purely anonymous or underscored field is not supported") } fieldName := ResolveNameConflict(name, func(s string) bool { return used[s] }) - if err != nil { - return Type{}, err - } used[fieldName] = true if !isValidFieldName(fieldName) { return Type{}, fmt.Errorf("field %d has invalid name", idx) From 5a1e8a6547d6606c7ff1e3f3841fbb1c9f205282 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Mon, 4 Mar 2024 17:30:15 +0800 Subject: [PATCH 017/571] core: delete unused ErrMaxInitCodeSizeExceeded (#29062) --- core/vm/errors.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/vm/errors.go b/core/vm/errors.go index fbbf19e178bf..004f8ef1c83c 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -29,7 +29,6 @@ var ( ErrInsufficientBalance = errors.New("insufficient balance for transfer") ErrContractAddressCollision = errors.New("contract address collision") ErrExecutionReverted = errors.New("execution reverted") - ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded") ErrMaxCodeSizeExceeded = errors.New("max code size exceeded") ErrInvalidJump = errors.New("invalid jump destination") ErrWriteProtection = errors.New("write protection") From 679a27a2b36d4f86e6b49c49c0d51c47a7ef6145 Mon Sep 17 00:00:00 2001 From: buddho Date: Mon, 4 Mar 2024 17:31:18 +0800 Subject: [PATCH 018/571] all: use EmptyUncleHash, EmptyCodeHash instead of raw value (#29134) --- cmd/devp2p/internal/ethtest/snap.go | 2 +- core/types/block_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index 64e063358545..8ff3f1f71a6e 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -648,7 +648,7 @@ The server should reject the request.`, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8}}, }, nBytes: 5000, - expHashes: []common.Hash{common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")}, + expHashes: []common.Hash{types.EmptyCodeHash}, }, { diff --git a/core/types/block_test.go b/core/types/block_test.go index cf0b1dd85c1e..982d002242f6 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -196,7 +196,7 @@ func TestEIP2718BlockEncoding(t *testing.T) { func TestUncleHash(t *testing.T) { uncles := make([]*Header, 0) h := CalcUncleHash(uncles) - exp := common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") + exp := EmptyUncleHash if h != exp { t.Fatalf("empty uncle hash is wrong, got %x != %x", h, exp) } From 35cebc16877c4cfbf48b883ab3bfa02b9100a87a Mon Sep 17 00:00:00 2001 From: psogv0308 Date: Mon, 4 Mar 2024 19:03:53 +0900 Subject: [PATCH 019/571] triedb/pathdb: changed the test code to check for verifying state (#29150) Co-authored-by: this-is-iron --- triedb/pathdb/database_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index e7bd4699938d..df69942e9aa2 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -397,7 +397,11 @@ func TestDatabaseRollback(t *testing.T) { if err := tester.db.Recover(parent, loader); err != nil { t.Fatalf("Failed to revert db, err: %v", err) } - tester.verifyState(parent) + if i > 0 { + if err := tester.verifyState(parent); err != nil { + t.Fatalf("Failed to verify state, err: %v", err) + } + } } if tester.db.tree.len() != 1 { t.Fatal("Only disk layer is expected") From a97d622588c2b71557c6222b95d487f51b46bd78 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 4 Mar 2024 14:07:41 +0100 Subject: [PATCH 020/571] cmd/devp2p: fix commandHasFlag (#29091) It got broken in some update of the cli library, and thus bootnodes weren't being configured automatically for some of the discovery commands. --- cmd/devp2p/main.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cmd/devp2p/main.go b/cmd/devp2p/main.go index 8461a8b9b5e2..66974bba5890 100644 --- a/cmd/devp2p/main.go +++ b/cmd/devp2p/main.go @@ -66,9 +66,15 @@ func commandHasFlag(ctx *cli.Context, flag cli.Flag) bool { for _, name := range names { set[name] = struct{}{} } - for _, fn := range ctx.FlagNames() { - if _, ok := set[fn]; ok { - return true + for _, ctx := range ctx.Lineage() { + if ctx.Command != nil { + for _, f := range ctx.Command.Flags { + for _, name := range f.Names() { + if _, ok := set[name]; ok { + return true + } + } + } } } return false From ca473b81cbe4a96cde4e8424c49b15ab304787bb Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 4 Mar 2024 22:25:53 +0800 Subject: [PATCH 021/571] core: use finalized block as the chain freeze indicator (#28683) * core: use finalized block as the chain freeze indicator * core/rawdb: use max(finality, head-90k) as chain freezing threshold * core/rawdb: fix tests * core/rawdb: fix lint * core/rawdb: address comments from peter * core/rawdb: fix typo --- core/blockchain_repair_test.go | 10 ++- core/blockchain_sethead_test.go | 8 ++- core/rawdb/chain_freezer.go | 113 ++++++++++++++++++++------------ core/rawdb/database.go | 8 +-- 4 files changed, 84 insertions(+), 55 deletions(-) diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index b2df39d17bb8..b6a299f8ba89 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1757,7 +1757,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) { // It's hard to follow the test case, visualize the input - //log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // fmt.Println(tt.dump(true)) // Create a temporary persistent database @@ -1830,10 +1830,14 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s } // Force run a freeze cycle type freezer interface { - Freeze(threshold uint64) error + Freeze() error Ancients() (uint64, error) } - db.(freezer).Freeze(tt.freezeThreshold) + if tt.freezeThreshold < uint64(tt.canonicalBlocks) { + final := uint64(tt.canonicalBlocks) - tt.freezeThreshold + chain.SetFinalized(canonblocks[int(final)-1].Header()) + } + db.(freezer).Freeze() // Set the simulated pivot block if tt.pivotBlock != nil { diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 1504c74e0ef3..b96ee12c9952 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -2044,10 +2044,14 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme // Force run a freeze cycle type freezer interface { - Freeze(threshold uint64) error + Freeze() error Ancients() (uint64, error) } - db.(freezer).Freeze(tt.freezeThreshold) + if tt.freezeThreshold < uint64(tt.canonicalBlocks) { + final := uint64(tt.canonicalBlocks) - tt.freezeThreshold + chain.SetFinalized(canonblocks[int(final)-1].Header()) + } + db.(freezer).Freeze() // Set the simulated pivot block if tt.pivotBlock != nil { diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index bb2c409dbbd5..d8214874bdb8 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -17,9 +17,9 @@ package rawdb import ( + "errors" "fmt" "sync" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -43,8 +43,6 @@ const ( // The background thread will keep moving ancient chain segments from key-value // database to flat files for saving space on live database. type chainFreezer struct { - threshold atomic.Uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests) - *Freezer quit chan struct{} wg sync.WaitGroup @@ -57,13 +55,11 @@ func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFre if err != nil { return nil, err } - cf := chainFreezer{ + return &chainFreezer{ Freezer: freezer, quit: make(chan struct{}), trigger: make(chan chan struct{}), - } - cf.threshold.Store(params.FullImmutabilityThreshold) - return &cf, nil + }, nil } // Close closes the chain freezer instance and terminates the background thread. @@ -77,6 +73,57 @@ func (f *chainFreezer) Close() error { return f.Freezer.Close() } +// readHeadNumber returns the number of chain head block. 0 is returned if the +// block is unknown or not available yet. +func (f *chainFreezer) readHeadNumber(db ethdb.KeyValueReader) uint64 { + hash := ReadHeadBlockHash(db) + if hash == (common.Hash{}) { + log.Error("Head block is not reachable") + return 0 + } + number := ReadHeaderNumber(db, hash) + if number == nil { + log.Error("Number of head block is missing") + return 0 + } + return *number +} + +// readFinalizedNumber returns the number of finalized block. 0 is returned +// if the block is unknown or not available yet. +func (f *chainFreezer) readFinalizedNumber(db ethdb.KeyValueReader) uint64 { + hash := ReadFinalizedBlockHash(db) + if hash == (common.Hash{}) { + return 0 + } + number := ReadHeaderNumber(db, hash) + if number == nil { + log.Error("Number of finalized block is missing") + return 0 + } + return *number +} + +// freezeThreshold returns the threshold for chain freezing. It's determined +// by formula: max(finality, HEAD-params.FullImmutabilityThreshold). +func (f *chainFreezer) freezeThreshold(db ethdb.KeyValueReader) (uint64, error) { + var ( + head = f.readHeadNumber(db) + final = f.readFinalizedNumber(db) + headLimit uint64 + ) + if head > params.FullImmutabilityThreshold { + headLimit = head - params.FullImmutabilityThreshold + } + if final == 0 && headLimit == 0 { + return 0, errors.New("freezing threshold is not available") + } + if final > headLimit { + return final, nil + } + return headLimit, nil +} + // freeze is a background thread that periodically checks the blockchain for any // import progress and moves ancient data from the fast database into the freezer. // @@ -114,60 +161,39 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { return } } - // Retrieve the freezing threshold. - hash := ReadHeadBlockHash(nfdb) - if hash == (common.Hash{}) { - log.Debug("Current full block hash unavailable") // new chain, empty database + threshold, err := f.freezeThreshold(nfdb) + if err != nil { backoff = true + log.Debug("Current full block not old enough to freeze", "err", err) continue } - number := ReadHeaderNumber(nfdb, hash) - threshold := f.threshold.Load() frozen := f.frozen.Load() - switch { - case number == nil: - log.Error("Current full block number unavailable", "hash", hash) - backoff = true - continue - case *number < threshold: - log.Debug("Current full block not old enough to freeze", "number", *number, "hash", hash, "delay", threshold) - backoff = true - continue - - case *number-threshold <= frozen: - log.Debug("Ancient blocks frozen already", "number", *number, "hash", hash, "frozen", frozen) + // Short circuit if the blocks below threshold are already frozen. + if frozen != 0 && frozen-1 >= threshold { backoff = true + log.Debug("Ancient blocks frozen already", "threshold", threshold, "frozen", frozen) continue } - head := ReadHeader(nfdb, hash, *number) - if head == nil { - log.Error("Current full block unavailable", "number", *number, "hash", hash) - backoff = true - continue - } - // Seems we have data ready to be frozen, process in usable batches var ( - start = time.Now() - first, _ = f.Ancients() - limit = *number - threshold + start = time.Now() + first = frozen // the first block to freeze + last = threshold // the last block to freeze ) - if limit-first > freezerBatchLimit { - limit = first + freezerBatchLimit + if last-first+1 > freezerBatchLimit { + last = freezerBatchLimit + first - 1 } - ancients, err := f.freezeRange(nfdb, first, limit) + ancients, err := f.freezeRange(nfdb, first, last) if err != nil { log.Error("Error in block freeze operation", "err", err) backoff = true continue } - // Batch of blocks have been frozen, flush them before wiping from leveldb if err := f.Sync(); err != nil { log.Crit("Failed to flush frozen tables", "err", err) } - // Wipe out all data from the active database batch := db.NewBatch() for i := 0; i < len(ancients); i++ { @@ -250,8 +276,11 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { } } +// freezeRange moves a batch of chain segments from the fast database to the freezer. +// The parameters (number, limit) specify the relevant block range, both of which +// are included. func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hashes []common.Hash, err error) { - hashes = make([]common.Hash, 0, limit-number) + hashes = make([]common.Hash, 0, limit-number+1) _, err = f.ModifyAncients(func(op ethdb.AncientWriteOp) error { for ; number <= limit; number++ { @@ -293,11 +322,9 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash if err := op.AppendRaw(ChainFreezerDifficultyTable, number, td); err != nil { return fmt.Errorf("can't write td to Freezer: %v", err) } - hashes = append(hashes, hash) } return nil }) - return hashes, err } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 27a9ec7412ca..9cab30bfcd1f 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -66,16 +66,10 @@ func (frdb *freezerdb) Close() error { // Freeze is a helper method used for external testing to trigger and block until // a freeze cycle completes, without having to sleep for a minute to trigger the // automatic background run. -func (frdb *freezerdb) Freeze(threshold uint64) error { +func (frdb *freezerdb) Freeze() error { if frdb.AncientStore.(*chainFreezer).readonly { return errReadOnly } - // Set the freezer threshold to a temporary value - defer func(old uint64) { - frdb.AncientStore.(*chainFreezer).threshold.Store(old) - }(frdb.AncientStore.(*chainFreezer).threshold.Load()) - frdb.AncientStore.(*chainFreezer).threshold.Store(threshold) - // Trigger a freeze cycle and block until it's done trigger := make(chan struct{}, 1) frdb.AncientStore.(*chainFreezer).trigger <- trigger From 19607d1a10d37542ba13ab9db48cf4e501715cce Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Mon, 4 Mar 2024 20:21:43 +0100 Subject: [PATCH 022/571] eth/tracers: Fix prestateTracer pre nonce on contract creation (#29099) The prestateTracer was reporting an inaccurate nonce for the contract being created in post EIP-158 transactions. Correct nonce is 0, due to the issue nonce was being reported as 1. --- .../prestate_tracer/create_post_eip158.json | 64 +++++++++++++++ .../create_post_eip158.json | 82 +++++++++++++++++++ eth/tracers/native/prestate.go | 3 + 3 files changed, 149 insertions(+) create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json new file mode 100644 index 000000000000..205b472dabe4 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json @@ -0,0 +1,64 @@ +{ + "genesis": { + "baseFeePerGas": "7", + "difficulty": "2", + "extraData": "0xd983010d0e846765746888676f312e32312e318664617277696e0000000000001713699f05f79a59abec177c7a87b90ceda79b72ff5edc9197dd7627a447cde45b079bbc3765a236cdf680e2d4d2247135d0e6bb6fd92b50638b92504ddb274f00", + "gasLimit": "30000000", + "hash": "0x6ad5258175c66f4e883d238a92a08428d8ebcbeac631ab7b972634cc05effab3", + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "number": "39137", + "stateRoot": "0x715f00df764dbadd4863247a215ac44b5420beafde3ec458b15db7aafa89be0c", + "timestamp": "1709022192", + "totalDifficulty": "78275", + "alloc": { + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f06447a8d44dba190", + "nonce": "2" + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6abd7a808913ed2", + "nonce": "64" + } + }, + "config": { + "chainId": 12345, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "clique": { + "period": 5, + "epoch": 30000 + } + } + }, + "context": { + "number": "39138", + "difficulty": "2", + "timestamp": "1709022197", + "gasLimit": "30000000", + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0" + }, + "input": "0x02f902af823039408459682f008459682f088302b3538080b90254608060405234801561001057600080fd5b50610234806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033c001a0a8cf4729b7e4664687abb3e2559853d7d489eb441519be2a17493061fb4c3a03a04b5a904ba8a6e59c6c40049c4d14a73233aeb8a45b38403199f304630dc0d453", + "result": { + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f06447a8d44dba190", + "nonce": 2 + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6abd7a808913ed2", + "nonce": 64 + } + } +} diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json new file mode 100644 index 000000000000..83266f6669cf --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json @@ -0,0 +1,82 @@ +{ + "genesis": { + "baseFeePerGas": "7", + "difficulty": "2", + "extraData": "0xd983010d0e846765746888676f312e32312e318664617277696e0000000000001713699f05f79a59abec177c7a87b90ceda79b72ff5edc9197dd7627a447cde45b079bbc3765a236cdf680e2d4d2247135d0e6bb6fd92b50638b92504ddb274f00", + "gasLimit": "30000000", + "hash": "0x6ad5258175c66f4e883d238a92a08428d8ebcbeac631ab7b972634cc05effab3", + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "number": "39137", + "stateRoot": "0x715f00df764dbadd4863247a215ac44b5420beafde3ec458b15db7aafa89be0c", + "timestamp": "1709022192", + "totalDifficulty": "78275", + "alloc": { + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f06447a8d44dba190", + "nonce": "2" + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6abd7a808913ed2", + "nonce": "64" + } + }, + "config": { + "chainId": 12345, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "clique": { + "period": 5, + "epoch": 30000 + } + } + }, + "context": { + "number": "39138", + "difficulty": "2", + "timestamp": "1709022197", + "gasLimit": "30000000", + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0" + }, + "input": "0x02f902af823039408459682f008459682f088302b3538080b90254608060405234801561001057600080fd5b50610234806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033c001a0a8cf4729b7e4664687abb3e2559853d7d489eb441519be2a17493061fb4c3a03a04b5a904ba8a6e59c6c40049c4d14a73233aeb8a45b38403199f304630dc0d453", + "tracerConfig": { + "diffMode": true + }, + "result": { + "post": { + "0x1bda2f8e4735507930bd6cfe873bf0bf0f4ab1de": { + "code": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033", + "nonce": 1 + }, + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f0645688331eb5690" + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6aae9b21b6ee855", + "nonce": 65 + } + }, + "pre": { + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f06447a8d44dba190", + "nonce": 2 + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6abd7a808913ed2", + "nonce": 64 + } + } + } +} diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index d7e10173cf27..0d57f62caf20 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -102,6 +102,9 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo // The recipient balance includes the value transferred. toBal := new(big.Int).Sub(t.pre[to].Balance, value) t.pre[to].Balance = toBal + if env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time).IsEIP158 && create { + t.pre[to].Nonce-- + } // The sender balance is after reducing: value and gasLimit. // We need to re-add them to get the pre-tx balance. From 5d5b384efd0acabe4d808c46fce9700114d2046f Mon Sep 17 00:00:00 2001 From: Domino Valdano Date: Mon, 4 Mar 2024 12:58:25 -0800 Subject: [PATCH 023/571] .mailmap: remove invalid email address (#29163) --- .mailmap | 1 - 1 file changed, 1 deletion(-) diff --git a/.mailmap b/.mailmap index aa074b76d6b5..312e51d8544f 100644 --- a/.mailmap +++ b/.mailmap @@ -56,7 +56,6 @@ Diederik Loerakker Dimitry Khokhlov Domino Valdano -Domino Valdano Edgar Aroutiounian From 9b3ceb2137df125dd0f6957a362e9f08d6c41b66 Mon Sep 17 00:00:00 2001 From: Vie Date: Tue, 5 Mar 2024 15:33:52 +0800 Subject: [PATCH 024/571] core/types: reuse signtx (#29152) * core/types: reuse signtx * core/types: inline signtx --- core/types/transaction_signing.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 9e26642f753d..70dee0776e7b 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -107,13 +107,7 @@ func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, err // SignNewTx creates a transaction and signs it. func SignNewTx(prv *ecdsa.PrivateKey, s Signer, txdata TxData) (*Transaction, error) { - tx := NewTx(txdata) - h := s.Hash(tx) - sig, err := crypto.Sign(h[:], prv) - if err != nil { - return nil, err - } - return tx.WithSignature(s, sig) + return SignTx(NewTx(txdata), s, prv) } // MustSignNewTx creates a transaction and signs it. From d89d7ebdec27d8c8fed217767e2f17b09b5460a0 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 5 Mar 2024 16:47:58 +0800 Subject: [PATCH 025/571] core: initialize `gasRemaining` with `=` instead of `+=` (#29149) initialize gasRemaining with = instead of += --- core/state_transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state_transition.go b/core/state_transition.go index 9c4f76d1c585..bda2a995bf31 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -263,7 +263,7 @@ func (st *StateTransition) buyGas() error { if err := st.gp.SubGas(st.msg.GasLimit); err != nil { return err } - st.gasRemaining += st.msg.GasLimit + st.gasRemaining = st.msg.GasLimit st.initialGas = st.msg.GasLimit mgvalU256, _ := uint256.FromBig(mgval) From e199319fd680aa4b135147f0480549a1c7d95350 Mon Sep 17 00:00:00 2001 From: buddho Date: Tue, 5 Mar 2024 17:47:56 +0800 Subject: [PATCH 026/571] rlp: remove a moot todo (#29154) --- rlp/iterator.go | 1 - 1 file changed, 1 deletion(-) diff --git a/rlp/iterator.go b/rlp/iterator.go index 6be574572e61..95bd3f258208 100644 --- a/rlp/iterator.go +++ b/rlp/iterator.go @@ -23,7 +23,6 @@ type listIterator struct { } // NewListIterator creates an iterator for the (list) represented by data -// TODO: Consider removing this implementation, as it is no longer used. func NewListIterator(data RawValue) (*listIterator, error) { k, t, c, err := readKind(data) if err != nil { From 7b81cf6362b3bb52762b823edf2a31bbbed4aa84 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 5 Mar 2024 21:31:55 +0800 Subject: [PATCH 027/571] core/state, trie/triedb/pathdb: remove storage incomplete flag (#28940) As SELF-DESTRUCT opcode is disabled in the cancun fork(unless the account is created within the same transaction, nothing to delete in this case). The account will only be deleted in the following cases: - The account is created within the same transaction. In this case the original storage was empty. - The account is empty(zero nonce, zero balance, zero code) and is touched within the transaction. Fortunately this kind of accounts are not-existent on ethereum-mainnet. All in all, after cancun, we are pretty sure there is no large contract deletion and we don't need this mechanism for oom protection. --- core/state/metrics.go | 1 - core/state/statedb.go | 87 ++++++++++++---------------------- core/state/statedb_test.go | 4 +- trie/triestate/state.go | 15 +++--- triedb/pathdb/database.go | 3 -- triedb/pathdb/database_test.go | 4 +- triedb/pathdb/disklayer.go | 7 --- triedb/pathdb/history.go | 40 +++++----------- triedb/pathdb/history_test.go | 2 +- triedb/pathdb/journal.go | 32 ++++++------- 10 files changed, 67 insertions(+), 128 deletions(-) diff --git a/core/state/metrics.go b/core/state/metrics.go index 64c651461e73..7447e44dfd1e 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -33,5 +33,4 @@ var ( slotDeletionTimer = metrics.NewRegisteredResettingTimer("state/delete/storage/timer", nil) slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil) slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil) - slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil) ) diff --git a/core/state/statedb.go b/core/state/statedb.go index a4b8cf93e2d2..4d1163d3c6af 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -36,12 +36,6 @@ import ( "github.com/holiman/uint256" ) -const ( - // storageDeleteLimit denotes the highest permissible memory allocation - // employed for contract storage deletion. - storageDeleteLimit = 512 * 1024 * 1024 -) - type revision struct { id int journalIndex int @@ -949,10 +943,10 @@ func (s *StateDB) clearJournalAndRefund() { // of a specific account. It leverages the associated state snapshot for fast // storage iteration and constructs trie node deletion markers by creating // stack trie with iterated slots. -func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (bool, common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { +func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { iter, err := s.snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{}) if err != nil { - return false, 0, nil, nil, err + return 0, nil, nil, err } defer iter.Release() @@ -968,40 +962,37 @@ func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (boo }) stack := trie.NewStackTrie(options) for iter.Next() { - if size > storageDeleteLimit { - return true, size, nil, nil, nil - } slot := common.CopyBytes(iter.Slot()) if err := iter.Error(); err != nil { // error might occur after Slot function - return false, 0, nil, nil, err + return 0, nil, nil, err } size += common.StorageSize(common.HashLength + len(slot)) slots[iter.Hash()] = slot if err := stack.Update(iter.Hash().Bytes(), slot); err != nil { - return false, 0, nil, nil, err + return 0, nil, nil, err } } if err := iter.Error(); err != nil { // error might occur during iteration - return false, 0, nil, nil, err + return 0, nil, nil, err } if stack.Hash() != root { - return false, 0, nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash()) + return 0, nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash()) } - return false, size, slots, nodes, nil + return size, slots, nodes, nil } // slowDeleteStorage serves as a less-efficient alternative to "fastDeleteStorage," // employed when the associated state snapshot is not available. It iterates the // storage slots along with all internal trie nodes via trie directly. -func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (bool, common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { +func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root, s.trie) if err != nil { - return false, 0, nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err) + return 0, nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err) } it, err := tr.NodeIterator(nil) if err != nil { - return false, 0, nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err) + return 0, nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err) } var ( size common.StorageSize @@ -1009,9 +1000,6 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r slots = make(map[common.Hash][]byte) ) for it.Next(true) { - if size > storageDeleteLimit { - return true, size, nil, nil, nil - } if it.Leaf() { slots[common.BytesToHash(it.LeafKey())] = common.CopyBytes(it.LeafBlob()) size += common.StorageSize(common.HashLength + len(it.LeafBlob())) @@ -1024,9 +1012,9 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r nodes.AddNode(it.Path(), trienode.NewDeleted()) } if err := it.Error(); err != nil { - return false, 0, nil, nil, err + return 0, nil, nil, err } - return false, size, slots, nodes, nil + return size, slots, nodes, nil } // deleteStorage is designed to delete the storage trie of a designated account. @@ -1034,31 +1022,27 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r // potentially leading to an out-of-memory panic. The function will make an attempt // to utilize an efficient strategy if the associated state snapshot is reachable; // otherwise, it will resort to a less-efficient approach. -func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (bool, map[common.Hash][]byte, *trienode.NodeSet, error) { +func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { var ( - start = time.Now() - err error - aborted bool - size common.StorageSize - slots map[common.Hash][]byte - nodes *trienode.NodeSet + start = time.Now() + err error + size common.StorageSize + slots map[common.Hash][]byte + nodes *trienode.NodeSet ) // The fast approach can be failed if the snapshot is not fully // generated, or it's internally corrupted. Fallback to the slow // one just in case. if s.snap != nil { - aborted, size, slots, nodes, err = s.fastDeleteStorage(addrHash, root) + size, slots, nodes, err = s.fastDeleteStorage(addrHash, root) } if s.snap == nil || err != nil { - aborted, size, slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) + size, slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) } if err != nil { - return false, nil, nil, err + return nil, nil, err } if metrics.EnabledExpensive { - if aborted { - slotDeletionSkip.Inc(1) - } n := int64(len(slots)) slotDeletionMaxCount.UpdateIfGt(int64(len(slots))) @@ -1068,7 +1052,7 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root slotDeletionCount.Mark(n) slotDeletionSize.Mark(int64(size)) } - return aborted, slots, nodes, nil + return slots, nodes, nil } // handleDestruction processes all destruction markers and deletes the account @@ -1095,13 +1079,12 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root // // In case (d), **original** account along with its storages should be deleted, // with their values be tracked as original value. -func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.Address]struct{}, error) { +func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) error { // Short circuit if geth is running with hash mode. This procedure can consume // considerable time and storage deletion isn't supported in hash mode, thus // preemptively avoiding unnecessary expenses. - incomplete := make(map[common.Address]struct{}) if s.db.TrieDB().Scheme() == rawdb.HashScheme { - return incomplete, nil + return nil } for addr, prev := range s.stateObjectsDestruct { // The original account was non-existing, and it's marked as destructed @@ -1124,18 +1107,9 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.A continue } // Remove storage slots belong to the account. - aborted, slots, set, err := s.deleteStorage(addr, addrHash, prev.Root) + slots, set, err := s.deleteStorage(addr, addrHash, prev.Root) if err != nil { - return nil, fmt.Errorf("failed to delete storage, err: %w", err) - } - // The storage is too huge to handle, skip it but mark as incomplete. - // For case (d), the account is resurrected might with a few slots - // created. In this case, wipe the entire storage state diff because - // of aborted deletion. - if aborted { - incomplete[addr] = struct{}{} - delete(s.storagesOrigin, addr) - continue + return fmt.Errorf("failed to delete storage, err: %w", err) } if s.storagesOrigin[addr] == nil { s.storagesOrigin[addr] = slots @@ -1147,10 +1121,10 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.A } } if err := nodes.Merge(set); err != nil { - return nil, err + return err } } - return incomplete, nil + return nil } // Commit writes the state to the underlying in-memory trie database. @@ -1179,8 +1153,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er codeWriter = s.db.DiskDB().NewBatch() ) // Handle all state deletions first - incomplete, err := s.handleDestruction(nodes) - if err != nil { + if err := s.handleDestruction(nodes); err != nil { return common.Hash{}, err } // Handle all state updates afterwards @@ -1276,7 +1249,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er } if root != origin { start := time.Now() - set := triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete) + set := triestate.New(s.accountsOrigin, s.storagesOrigin) if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil { return common.Hash{}, err } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index cd86a7f4b67f..3649b0ac589b 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -1161,12 +1161,12 @@ func TestDeleteStorage(t *testing.T) { obj := fastState.getOrNewStateObject(addr) storageRoot := obj.data.Root - _, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) + _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) if err != nil { t.Fatal(err) } - _, _, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) + _, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) if err != nil { t.Fatal(err) } diff --git a/trie/triestate/state.go b/trie/triestate/state.go index 4c47e9c39734..aa4d32f852f9 100644 --- a/trie/triestate/state.go +++ b/trie/triestate/state.go @@ -59,18 +59,16 @@ type TrieLoader interface { // The value refers to the original content of state before the transition // is made. Nil means that the state was not present previously. type Set struct { - Accounts map[common.Address][]byte // Mutated account set, nil means the account was not present - Storages map[common.Address]map[common.Hash][]byte // Mutated storage set, nil means the slot was not present - Incomplete map[common.Address]struct{} // Indicator whether the storage is incomplete due to large deletion - size common.StorageSize // Approximate size of set + Accounts map[common.Address][]byte // Mutated account set, nil means the account was not present + Storages map[common.Address]map[common.Hash][]byte // Mutated storage set, nil means the slot was not present + size common.StorageSize // Approximate size of set } // New constructs the state set with provided data. -func New(accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, incomplete map[common.Address]struct{}) *Set { +func New(accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) *Set { return &Set{ - Accounts: accounts, - Storages: storages, - Incomplete: incomplete, + Accounts: accounts, + Storages: storages, } } @@ -88,7 +86,6 @@ func (s *Set) Size() common.StorageSize { } s.size += common.StorageSize(common.AddressLength) } - s.size += common.StorageSize(common.AddressLength * len(s.Incomplete)) return s.size } diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 3e8e83a00c2c..b1e01abac4d6 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -403,9 +403,6 @@ func (db *Database) Recoverable(root common.Hash) bool { if m.parent != root { return errors.New("unexpected state history") } - if len(m.incomplete) > 0 { - return errors.New("incomplete state history") - } root = m.root return nil }) == nil diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index df69942e9aa2..2e7e1bef05ff 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -299,7 +299,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode } } } - return root, ctx.nodes, triestate.New(ctx.accountOrigin, ctx.storageOrigin, nil) + return root, ctx.nodes, triestate.New(ctx.accountOrigin, ctx.storageOrigin) } // lastRoot returns the latest root hash, or empty if nothing is cached. @@ -543,7 +543,7 @@ func TestCorruptedJournal(t *testing.T) { // Mutate the journal in disk, it should be regarded as invalid blob := rawdb.ReadTrieJournal(tester.db.diskdb) - blob[0] = 1 + blob[0] = 0xa rawdb.WriteTrieJournal(tester.db.diskdb, blob) // Verify states, all not-yet-written states should be discarded diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index ef697cbce8ce..777e4ec8a750 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -17,7 +17,6 @@ package pathdb import ( - "errors" "fmt" "sync" @@ -239,12 +238,6 @@ func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) (*diskLayer if h.meta.root != dl.rootHash() { return nil, errUnexpectedHistory } - // Reject if the provided state history is incomplete. It's due to - // a large construct SELF-DESTRUCT which can't be handled because - // of memory limitation. - if len(h.meta.incomplete) > 0 { - return nil, errors.New("incomplete state history") - } if dl.id == 0 { return nil, fmt.Errorf("%w: zero state id", errStateUnrecoverable) } diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 051e122bec64..68fb4809f01d 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -66,7 +66,7 @@ import ( const ( accountIndexSize = common.AddressLength + 13 // The length of encoded account index slotIndexSize = common.HashLength + 5 // The length of encoded slot index - historyMetaSize = 9 + 2*common.HashLength // The length of fixed size part of meta object + historyMetaSize = 9 + 2*common.HashLength // The length of encoded history meta stateHistoryVersion = uint8(0) // initial version of state history structure. ) @@ -192,23 +192,19 @@ func (i *slotIndex) decode(blob []byte) { // meta describes the meta data of state history object. type meta struct { - version uint8 // version tag of history object - parent common.Hash // prev-state root before the state transition - root common.Hash // post-state root after the state transition - block uint64 // associated block number - incomplete []common.Address // list of address whose storage set is incomplete + version uint8 // version tag of history object + parent common.Hash // prev-state root before the state transition + root common.Hash // post-state root after the state transition + block uint64 // associated block number } // encode packs the meta object into byte stream. func (m *meta) encode() []byte { - buf := make([]byte, historyMetaSize+len(m.incomplete)*common.AddressLength) + buf := make([]byte, historyMetaSize) buf[0] = m.version copy(buf[1:1+common.HashLength], m.parent.Bytes()) copy(buf[1+common.HashLength:1+2*common.HashLength], m.root.Bytes()) binary.BigEndian.PutUint64(buf[1+2*common.HashLength:historyMetaSize], m.block) - for i, h := range m.incomplete { - copy(buf[i*common.AddressLength+historyMetaSize:], h.Bytes()) - } return buf[:] } @@ -219,20 +215,13 @@ func (m *meta) decode(blob []byte) error { } switch blob[0] { case stateHistoryVersion: - if len(blob) < historyMetaSize { + if len(blob) != historyMetaSize { return fmt.Errorf("invalid state history meta, len: %d", len(blob)) } - if (len(blob)-historyMetaSize)%common.AddressLength != 0 { - return fmt.Errorf("corrupted state history meta, len: %d", len(blob)) - } m.version = blob[0] m.parent = common.BytesToHash(blob[1 : 1+common.HashLength]) m.root = common.BytesToHash(blob[1+common.HashLength : 1+2*common.HashLength]) m.block = binary.BigEndian.Uint64(blob[1+2*common.HashLength : historyMetaSize]) - for pos := historyMetaSize; pos < len(blob); { - m.incomplete = append(m.incomplete, common.BytesToAddress(blob[pos:pos+common.AddressLength])) - pos += common.AddressLength - } return nil default: return fmt.Errorf("unknown version %d", blob[0]) @@ -257,7 +246,6 @@ func newHistory(root common.Hash, parent common.Hash, block uint64, states *trie var ( accountList []common.Address storageList = make(map[common.Address][]common.Hash) - incomplete []common.Address ) for addr := range states.Accounts { accountList = append(accountList, addr) @@ -272,18 +260,12 @@ func newHistory(root common.Hash, parent common.Hash, block uint64, states *trie slices.SortFunc(slist, common.Hash.Cmp) storageList[addr] = slist } - for addr := range states.Incomplete { - incomplete = append(incomplete, addr) - } - slices.SortFunc(incomplete, common.Address.Cmp) - return &history{ meta: &meta{ - version: stateHistoryVersion, - parent: parent, - root: root, - block: block, - incomplete: incomplete, + version: stateHistoryVersion, + parent: parent, + root: root, + block: block, }, accounts: states.Accounts, accountList: accountList, diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_test.go index a3257441de80..ab0d44777d7b 100644 --- a/triedb/pathdb/history_test.go +++ b/triedb/pathdb/history_test.go @@ -47,7 +47,7 @@ func randomStateSet(n int) *triestate.Set { account := generateAccount(types.EmptyRootHash) accounts[addr] = types.SlimAccountRLP(account) } - return triestate.New(accounts, storages, nil) + return triestate.New(accounts, storages) } func makeHistory() *history { diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index ac770763e38d..3a0b7ebae273 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -41,7 +41,13 @@ var ( errUnmatchedJournal = errors.New("unmatched journal") ) -const journalVersion uint64 = 0 +// journalVersion ensures that an incompatible journal is detected and discarded. +// +// Changelog: +// +// - Version 0: initial version +// - Version 1: storage.Incomplete field is removed +const journalVersion uint64 = 1 // journalNode represents a trie node persisted in the journal. type journalNode struct { @@ -64,10 +70,9 @@ type journalAccounts struct { // journalStorage represents a list of storage slots belong to an account. type journalStorage struct { - Incomplete bool - Account common.Address - Hashes []common.Hash - Slots [][]byte + Account common.Address + Hashes []common.Hash + Slots [][]byte } // loadJournal tries to parse the layer journal from the disk. @@ -209,11 +214,10 @@ func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) { } // Read state changes from journal var ( - jaccounts journalAccounts - jstorages []journalStorage - accounts = make(map[common.Address][]byte) - storages = make(map[common.Address]map[common.Hash][]byte) - incomplete = make(map[common.Address]struct{}) + jaccounts journalAccounts + jstorages []journalStorage + accounts = make(map[common.Address][]byte) + storages = make(map[common.Address]map[common.Hash][]byte) ) if err := r.Decode(&jaccounts); err != nil { return nil, fmt.Errorf("load diff accounts: %v", err) @@ -233,12 +237,9 @@ func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) { set[h] = nil } } - if entry.Incomplete { - incomplete[entry.Account] = struct{}{} - } storages[entry.Account] = set } - return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, nodes, triestate.New(accounts, storages, incomplete)), r) + return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, nodes, triestate.New(accounts, storages)), r) } // journal implements the layer interface, marshaling the un-flushed trie nodes @@ -316,9 +317,6 @@ func (dl *diffLayer) journal(w io.Writer) error { storage := make([]journalStorage, 0, len(dl.states.Storages)) for addr, slots := range dl.states.Storages { entry := journalStorage{Account: addr} - if _, ok := dl.states.Incomplete[addr]; ok { - entry.Incomplete = true - } for slotHash, slot := range slots { entry.Hashes = append(entry.Hashes, slotHash) entry.Slots = append(entry.Slots, slot) From 96bf23f1ea95d29a32abe8fe2992b86e892b6c4c Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 5 Mar 2024 14:32:47 +0100 Subject: [PATCH 028/571] accounts/usbwallet: use updated hid (only) library (#28945) * accounts/usbwallet: use updated hid (only) library * deps: update karalabe/hid --- accounts/usbwallet/hub.go | 8 ++++---- accounts/usbwallet/wallet.go | 6 +++--- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index e67942dbc107..e22dffe9718e 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -26,7 +26,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/karalabe/usb" + "github.com/karalabe/hid" ) // LedgerScheme is the protocol scheme prefixing account and wallet URLs. @@ -109,7 +109,7 @@ func NewTrezorHubWithWebUSB() (*Hub, error) { // 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 !usb.Supported() { + if !hid.Supported() { return nil, errors.New("unsupported platform") } hub := &Hub{ @@ -155,7 +155,7 @@ func (hub *Hub) refreshWallets() { return } // Retrieve the current list of USB wallet devices - var devices []usb.DeviceInfo + var devices []hid.DeviceInfo if runtime.GOOS == "linux" { // hidapi on Linux opens the device during enumeration to retrieve some infos, @@ -170,7 +170,7 @@ func (hub *Hub) refreshWallets() { return } } - infos, err := usb.Enumerate(hub.vendorID, 0) + infos, err := hid.Enumerate(hub.vendorID, 0) if err != nil { failcount := hub.enumFails.Add(1) if runtime.GOOS == "linux" { diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 69083dc8939d..0fd0415a9ef8 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/usb" + "github.com/karalabe/hid" ) // Maximum time between wallet health checks to detect USB unplugs. @@ -79,8 +79,8 @@ type wallet struct { driver driver // Hardware implementation of the low level device operations url *accounts.URL // Textual URL uniquely identifying this wallet - info usb.DeviceInfo // Known USB device infos about the wallet - device usb.Device // USB device advertising itself as a hardware wallet + info hid.DeviceInfo // Known USB device infos about the 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/go.mod b/go.mod index 7a54b1ff7ca9..48faa0a321d3 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 github.com/julienschmidt/httprouter v1.3.0 - github.com/karalabe/usb v0.0.2 + github.com/karalabe/hid v1.0.1-0.20240209121748-d3b59fe37df8 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.17 diff --git a/go.sum b/go.sum index bb4ded5c2ff7..20a95d36877c 100644 --- a/go.sum +++ b/go.sum @@ -385,8 +385,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= -github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/karalabe/hid v1.0.1-0.20240209121748-d3b59fe37df8 h1:IMoiklsIksD2ii43zKCybVU6jLNzpSl3bT31+5mUjgg= +github.com/karalabe/hid v1.0.1-0.20240209121748-d3b59fe37df8/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8= github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= From dfa6c5e9c80e0965d0476909afc26e87aa199e6a Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 5 Mar 2024 21:37:26 +0800 Subject: [PATCH 029/571] internal/jsre: format blob fields from hexdecimal to int (#29166) * internal/jsre: format receipt.{blobGasPrice,blobGasUsed} to int Signed-off-by: jsvisa * internal/jsre: format tx.maxFeePerBlobGas to int Signed-off-by: jsvisa * internal/jsre: format blob* in block Signed-off-by: jsvisa --------- Signed-off-by: jsvisa --- internal/jsre/deps/web3.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index 0b360e74150a..4196cb8db0ee 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -3734,7 +3734,7 @@ var inputCallFormatter = function (options){ options.to = inputAddressFormatter(options.to); } - ['maxFeePerGas', 'maxPriorityFeePerGas', 'gasPrice', 'gas', 'value', 'nonce'].filter(function (key) { + ['maxFeePerBlobGas', 'maxFeePerGas', 'maxPriorityFeePerGas', 'gasPrice', 'gas', 'value', 'nonce'].filter(function (key) { return options[key] !== undefined; }).forEach(function(key){ options[key] = utils.fromDecimal(options[key]); @@ -3759,7 +3759,7 @@ var inputTransactionFormatter = function (options){ options.to = inputAddressFormatter(options.to); } - ['maxFeePerGas', 'maxPriorityFeePerGas', 'gasPrice', 'gas', 'value', 'nonce'].filter(function (key) { + ['maxFeePerBlobGas', 'maxFeePerGas', 'maxPriorityFeePerGas', 'gasPrice', 'gas', 'value', 'nonce'].filter(function (key) { return options[key] !== undefined; }).forEach(function(key){ options[key] = utils.fromDecimal(options[key]); @@ -3789,6 +3789,9 @@ var outputTransactionFormatter = function (tx){ if(tx.maxPriorityFeePerGas !== undefined) { tx.maxPriorityFeePerGas = utils.toBigNumber(tx.maxPriorityFeePerGas); } + if(tx.maxFeePerBlobGas !== undefined) { + tx.maxFeePerBlobGas = utils.toBigNumber(tx.maxFeePerBlobGas); + } tx.value = utils.toBigNumber(tx.value); return tx; }; @@ -3810,6 +3813,12 @@ var outputTransactionReceiptFormatter = function (receipt){ if(receipt.effectiveGasPrice !== undefined) { receipt.effectiveGasPrice = utils.toBigNumber(receipt.effectiveGasPrice); } + if(receipt.blobGasPrice !== undefined) { + receipt.blobGasPrice = utils.toBigNumber(receipt.blobGasPrice); + } + if(receipt.blobGasUsed !== undefined) { + receipt.blobGasUsed = utils.toBigNumber(receipt.blobGasUsed); + } if(utils.isArray(receipt.logs)) { receipt.logs = receipt.logs.map(function(log){ return outputLogFormatter(log); @@ -3831,11 +3840,17 @@ var outputBlockFormatter = function(block) { if (block.baseFeePerGas !== undefined) { block.baseFeePerGas = utils.toBigNumber(block.baseFeePerGas); } + if (block.blobGasUsed !== undefined) { + block.blobGasUsed = utils.toBigNumber(block.blobGasUsed); + } + if (block.excessBlobGas !== undefined) { + block.excessBlobGas = utils.toBigNumber(block.excessBlobGas); + } block.gasLimit = utils.toDecimal(block.gasLimit); block.gasUsed = utils.toDecimal(block.gasUsed); block.size = utils.toDecimal(block.size); block.timestamp = utils.toDecimal(block.timestamp); - if(block.number !== null) + if (block.number !== null) block.number = utils.toDecimal(block.number); block.difficulty = utils.toBigNumber(block.difficulty); From a6d6e8ac410170eb1085b9e7b0388b1c67f95548 Mon Sep 17 00:00:00 2001 From: Undefinedor Date: Tue, 5 Mar 2024 21:44:23 +0800 Subject: [PATCH 030/571] rpc: remove deprecated method "Notifier.Closed" (#29162) --- eth/downloader/api.go | 2 -- eth/filters/api.go | 6 ------ eth/tracers/api.go | 4 ++-- node/api.go | 2 -- p2p/simulations/http_test.go | 2 -- rpc/subscription.go | 6 ------ rpc/testservice_test.go | 5 +---- 7 files changed, 3 insertions(+), 24 deletions(-) diff --git a/eth/downloader/api.go b/eth/downloader/api.go index 6b8cb98e23bd..90c36afbb5ba 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -149,8 +149,6 @@ func (api *DownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error notifier.Notify(rpcSub.ID, status) case <-rpcSub.Err(): return - case <-notifier.Closed(): - return } } }() diff --git a/eth/filters/api.go b/eth/filters/api.go index 8cf701ec5713..59103ac03ca6 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -179,8 +179,6 @@ func (api *FilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool) } case <-rpcSub.Err(): return - case <-notifier.Closed(): - return } } }() @@ -241,8 +239,6 @@ func (api *FilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) { notifier.Notify(rpcSub.ID, h) case <-rpcSub.Err(): return - case <-notifier.Closed(): - return } } }() @@ -278,8 +274,6 @@ func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subsc } case <-rpcSub.Err(): // client send an unsubscribe request return - case <-notifier.Closed(): // connection dropped - return } } }() diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 683310820526..fa8c881d1a71 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -226,7 +226,7 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf } sub := notifier.CreateSubscription() - resCh := api.traceChain(from, to, config, notifier.Closed()) + resCh := api.traceChain(from, to, config, sub.Err()) go func() { for result := range resCh { notifier.Notify(sub.ID, result) @@ -240,7 +240,7 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf // the end block but excludes the start one. The return value will be one item per // transaction, dependent on the requested tracer. // The tracing procedure should be aborted in case the closed signal is received. -func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan interface{}) chan *blockTraceResult { +func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan error) chan *blockTraceResult { reexec := defaultTraceReexec if config != nil && config.Reexec != nil { reexec = *config.Reexec diff --git a/node/api.go b/node/api.go index f81f394beb24..a71ae6aa2954 100644 --- a/node/api.go +++ b/node/api.go @@ -145,8 +145,6 @@ func (api *adminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) return case <-rpcSub.Err(): return - case <-notifier.Closed(): - return } } }() diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go index c53a49797bd3..c04308fe0bf8 100644 --- a/p2p/simulations/http_test.go +++ b/p2p/simulations/http_test.go @@ -282,8 +282,6 @@ func (t *TestAPI) Events(ctx context.Context) (*rpc.Subscription, error) { return case <-rpcSub.Err(): return - case <-notifier.Closed(): - return } } }() diff --git a/rpc/subscription.go b/rpc/subscription.go index 9cb07275479e..d3dff32a272e 100644 --- a/rpc/subscription.go +++ b/rpc/subscription.go @@ -145,12 +145,6 @@ func (n *Notifier) Notify(id ID, data any) error { return nil } -// Closed returns a channel that is closed when the RPC connection is closed. -// Deprecated: use subscription error channel -func (n *Notifier) Closed() <-chan interface{} { - return n.h.conn.closed() -} - // takeSubscription returns the subscription (if one has been created). No subscription can // be created after this call. func (n *Notifier) takeSubscription() *Subscription { diff --git a/rpc/testservice_test.go b/rpc/testservice_test.go index 7d873af6670e..69199e21b711 100644 --- a/rpc/testservice_test.go +++ b/rpc/testservice_test.go @@ -195,10 +195,7 @@ func (s *notificationTestService) SomeSubscription(ctx context.Context, n, val i return } } - select { - case <-notifier.Closed(): - case <-subscription.Err(): - } + <-subscription.Err() if s.unsubscribed != nil { s.unsubscribed <- string(subscription.ID) } From a970295956d602c348dccce034712c14aedce5e0 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Tue, 5 Mar 2024 21:45:17 +0800 Subject: [PATCH 031/571] rlp: using unsafe.Slice instead of SliceHeader (#29067) Co-authored-by: Felix Lange --- rlp/unsafe.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/rlp/unsafe.go b/rlp/unsafe.go index 2152ba35fc4a..10868caaf287 100644 --- a/rlp/unsafe.go +++ b/rlp/unsafe.go @@ -26,10 +26,5 @@ import ( // byteArrayBytes returns a slice of the byte array v. func byteArrayBytes(v reflect.Value, length int) []byte { - var s []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s)) - hdr.Data = v.UnsafeAddr() - hdr.Cap = length - hdr.Len = length - return s + return unsafe.Slice((*byte)(unsafe.Pointer(v.UnsafeAddr())), length) } From 9e129efd7b43242fb5e605065713c27d615e753d Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 5 Mar 2024 21:48:27 +0800 Subject: [PATCH 032/571] core: remove useless assignments (#29065) --- core/state_transition.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index bda2a995bf31..8fcf4c093dbc 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -234,7 +234,7 @@ func (st *StateTransition) to() common.Address { func (st *StateTransition) buyGas() error { mgval := new(big.Int).SetUint64(st.msg.GasLimit) - mgval = mgval.Mul(mgval, st.msg.GasPrice) + mgval.Mul(mgval, st.msg.GasPrice) balanceCheck := new(big.Int).Set(mgval) if st.msg.GasFeeCap != nil { balanceCheck.SetUint64(st.msg.GasLimit) @@ -477,7 +477,7 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { // Return ETH for remaining gas, exchanged at the original rate. remaining := uint256.NewInt(st.gasRemaining) - remaining = remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) + remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) st.state.AddBalance(st.msg.From, remaining) // Also return remaining gas to the block gas counter so it is From 9a0fa8093ca5f7b896c3f7e849f7ca532d24e2a6 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 5 Mar 2024 14:52:44 +0100 Subject: [PATCH 033/571] node: remove test which doesn't do a lot (#29159) * node: fix test if directory already exists * node: remove test --- node/node_test.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/node/node_test.go b/node/node_test.go index 04810a815bf6..d1d1e5dfe8fa 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -415,21 +415,6 @@ func TestRegisterHandler_Successful(t *testing.T) { assert.Equal(t, "success", string(buf)) } -// Tests that the given handler will not be successfully mounted since no HTTP server -// is enabled for RPC -func TestRegisterHandler_Unsuccessful(t *testing.T) { - node, err := New(&DefaultConfig) - if err != nil { - t.Fatalf("could not create new node: %v", err) - } - - // create and mount handler - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("success")) - }) - node.RegisterHandler("test", "/test", handler) -} - // Tests whether websocket requests can be handled on the same port as a regular http server. func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) { node := startHTTP(t, 0, 0) From f4d53133f6e4b13f0dbcfef3bc45e9650d863b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 5 Mar 2024 16:13:28 +0200 Subject: [PATCH 034/571] consensus, cmd, core, eth: remove support for non-merge mode of operation (#29169) * eth: drop support for forward sync triggers and head block packets * consensus, eth: enforce always merged network * eth: fix tx looper startup and shutdown * cmd, core: fix some tests * core: remove notion of future blocks * core, eth: drop unused methods and types --- cmd/geth/testdata/clique.json | 1 + consensus/merger.go | 110 ---- core/block_validator_test.go | 6 - core/blockchain.go | 108 +--- core/blockchain_insert.go | 5 - core/blockchain_test.go | 5 - eth/backend.go | 34 +- eth/catalyst/api.go | 45 +- eth/catalyst/api_test.go | 4 - eth/ethconfig/config.go | 13 +- eth/fetcher/block_fetcher.go | 939 ----------------------------- eth/fetcher/block_fetcher_test.go | 949 ------------------------------ eth/fetcher/tx_fetcher.go | 10 +- eth/handler.go | 180 +----- eth/handler_eth.go | 62 -- eth/handler_eth_test.go | 159 ----- eth/handler_test.go | 2 - eth/peerset.go | 34 -- eth/protocols/eth/broadcast.go | 33 -- eth/protocols/eth/handlers.go | 37 +- eth/protocols/eth/peer.go | 107 +--- eth/protocols/eth/protocol.go | 13 - eth/sync.go | 215 ------- eth/sync_test.go | 5 +- params/config.go | 2 + 25 files changed, 88 insertions(+), 2990 deletions(-) delete mode 100644 consensus/merger.go delete mode 100644 eth/fetcher/block_fetcher.go delete mode 100644 eth/fetcher/block_fetcher_test.go diff --git a/cmd/geth/testdata/clique.json b/cmd/geth/testdata/clique.json index b54b4a7d3b72..36f5c3105703 100644 --- a/cmd/geth/testdata/clique.json +++ b/cmd/geth/testdata/clique.json @@ -8,6 +8,7 @@ "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, + "terminalTotalDifficultyPassed": true, "clique": { "period": 5, "epoch": 30000 diff --git a/consensus/merger.go b/consensus/merger.go deleted file mode 100644 index ffbcbf2b8569..000000000000 --- a/consensus/merger.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2021 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 consensus - -import ( - "fmt" - "sync" - - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" -) - -// transitionStatus describes the status of eth1/2 transition. This switch -// between modes is a one-way action which is triggered by corresponding -// consensus-layer message. -type transitionStatus struct { - LeftPoW bool // The flag is set when the first NewHead message received - EnteredPoS bool // The flag is set when the first FinalisedBlock message received -} - -// Merger is an internal help structure used to track the eth1/2 transition status. -// It's a common structure can be used in both full node and light client. -type Merger struct { - db ethdb.KeyValueStore - status transitionStatus - mu sync.RWMutex -} - -// NewMerger creates a new Merger which stores its transition status in the provided db. -func NewMerger(db ethdb.KeyValueStore) *Merger { - var status transitionStatus - blob := rawdb.ReadTransitionStatus(db) - if len(blob) != 0 { - if err := rlp.DecodeBytes(blob, &status); err != nil { - log.Crit("Failed to decode the transition status", "err", err) - } - } - return &Merger{ - db: db, - status: status, - } -} - -// ReachTTD is called whenever the first NewHead message received -// from the consensus-layer. -func (m *Merger) ReachTTD() { - m.mu.Lock() - defer m.mu.Unlock() - - if m.status.LeftPoW { - return - } - m.status = transitionStatus{LeftPoW: true} - blob, err := rlp.EncodeToBytes(m.status) - if err != nil { - panic(fmt.Sprintf("Failed to encode the transition status: %v", err)) - } - rawdb.WriteTransitionStatus(m.db, blob) - log.Info("Left PoW stage") -} - -// FinalizePoS is called whenever the first FinalisedBlock message received -// from the consensus-layer. -func (m *Merger) FinalizePoS() { - m.mu.Lock() - defer m.mu.Unlock() - - if m.status.EnteredPoS { - return - } - m.status = transitionStatus{LeftPoW: true, EnteredPoS: true} - blob, err := rlp.EncodeToBytes(m.status) - if err != nil { - panic(fmt.Sprintf("Failed to encode the transition status: %v", err)) - } - rawdb.WriteTransitionStatus(m.db, blob) - log.Info("Entered PoS stage") -} - -// TDDReached reports whether the chain has left the PoW stage. -func (m *Merger) TDDReached() bool { - m.mu.RLock() - defer m.mu.RUnlock() - - return m.status.LeftPoW -} - -// PoSFinalized reports whether the chain has entered the PoS stage. -func (m *Merger) PoSFinalized() bool { - m.mu.RLock() - defer m.mu.RUnlock() - - return m.status.EnteredPoS -} diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 385c0afd9d40..2f86b2d751b8 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -94,7 +94,6 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { preBlocks []*types.Block postBlocks []*types.Block engine consensus.Engine - merger = consensus.NewMerger(rawdb.NewMemoryDatabase()) ) if isClique { var ( @@ -186,11 +185,6 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { } chain.InsertChain(preBlocks[i : i+1]) } - - // Make the transition - merger.ReachTTD() - merger.FinalizePoS() - // Verify the blocks after the merging for i := 0; i < len(postBlocks); i++ { _, results := engine.VerifyHeaders(chain, []*types.Header{postHeaders[i]}) diff --git a/core/blockchain.go b/core/blockchain.go index b1bbc3d5982d..67b49cfe0262 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -50,7 +50,6 @@ import ( "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/hashdb" "github.com/ethereum/go-ethereum/triedb/pathdb" - "golang.org/x/exp/slices" ) var ( @@ -97,13 +96,11 @@ var ( ) const ( - bodyCacheLimit = 256 - blockCacheLimit = 256 - receiptsCacheLimit = 32 - txLookupCacheLimit = 1024 - maxFutureBlocks = 256 - maxTimeFutureBlocks = 30 - TriesInMemory = 128 + bodyCacheLimit = 256 + blockCacheLimit = 256 + receiptsCacheLimit = 32 + txLookupCacheLimit = 1024 + TriesInMemory = 128 // BlockChainVersion ensures that an incompatible database forces a resync from scratch. // @@ -245,9 +242,6 @@ type BlockChain struct { blockCache *lru.Cache[common.Hash, *types.Block] txLookupCache *lru.Cache[common.Hash, txLookup] - // future blocks are blocks added for later processing - futureBlocks *lru.Cache[common.Hash, *types.Block] - wg sync.WaitGroup quit chan struct{} // shutdown signal, closed in Stop. stopping atomic.Bool // false if chain is running, true when stopped @@ -299,7 +293,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis receiptsCache: lru.NewCache[common.Hash, []*types.Receipt](receiptsCacheLimit), blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit), txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit), - futureBlocks: lru.NewCache[common.Hash, *types.Block](maxFutureBlocks), engine: engine, vmConfig: vmConfig, } @@ -449,11 +442,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root) } - - // Start future block processor. - bc.wg.Add(1) - go bc.updateFutureBlocks() - // Rewind the chain in case of an incompatible config upgrade. if compat, ok := genesisErr.(*params.ConfigCompatError); ok { log.Warn("Rewinding chain to upgrade configuration", "err", compat) @@ -794,7 +782,6 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha bc.receiptsCache.Purge() bc.blockCache.Purge() bc.txLookupCache.Purge() - bc.futureBlocks.Purge() // Clear safe block, finalized block if needed if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.Number.Uint64() { @@ -1048,24 +1035,6 @@ func (bc *BlockChain) insertStopped() bool { return bc.procInterrupt.Load() } -func (bc *BlockChain) procFutureBlocks() { - blocks := make([]*types.Block, 0, bc.futureBlocks.Len()) - for _, hash := range bc.futureBlocks.Keys() { - if block, exist := bc.futureBlocks.Peek(hash); exist { - blocks = append(blocks, block) - } - } - if len(blocks) > 0 { - slices.SortFunc(blocks, func(a, b *types.Block) int { - return a.Number().Cmp(b.Number()) - }) - // Insert one by one as chain insertion needs contiguous ancestry between blocks - for i := range blocks { - bc.InsertChain(blocks[i : i+1]) - } - } -} - // WriteStatus status of write type WriteStatus byte @@ -1466,8 +1435,6 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types if status == CanonStatTy { bc.writeHeadBlock(block) } - bc.futureBlocks.Remove(block.Hash()) - if status == CanonStatTy { bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) if len(logs) > 0 { @@ -1487,25 +1454,6 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types return status, nil } -// addFutureBlock checks if the block is within the max allowed window to get -// accepted for future processing, and returns an error if the block is too far -// ahead and was not added. -// -// TODO after the transition, the future block shouldn't be kept. Because -// it's not checked in the Geth side anymore. -func (bc *BlockChain) addFutureBlock(block *types.Block) error { - max := uint64(time.Now().Unix() + maxTimeFutureBlocks) - if block.Time() > max { - return fmt.Errorf("future block timestamp %v > allowed %v", block.Time(), max) - } - if block.Difficulty().Cmp(common.Big0) == 0 { - // Never add PoS blocks into the future queue - return nil - } - bc.futureBlocks.Add(block.Hash(), block) - return nil -} - // InsertChain attempts to insert the given batch of blocks in to the canonical // chain or, otherwise, create a fork. If an error is returned it will return // the index number of the failing block as well an error describing what went @@ -1643,26 +1591,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) _, err := bc.recoverAncestors(block) return it.index, err } - // First block is future, shove it (and all children) to the future queue (unknown ancestor) - case errors.Is(err, consensus.ErrFutureBlock) || (errors.Is(err, consensus.ErrUnknownAncestor) && bc.futureBlocks.Contains(it.first().ParentHash())): - for block != nil && (it.index == 0 || errors.Is(err, consensus.ErrUnknownAncestor)) { - log.Debug("Future block, postponing import", "number", block.Number(), "hash", block.Hash()) - if err := bc.addFutureBlock(block); err != nil { - return it.index, err - } - block, err = it.next() - } - stats.queued += it.processed() - stats.ignored += it.remaining() - - // If there are any still remaining, mark as ignored - return it.index, err - // Some other error(except ErrKnownBlock) occurred, abort. // ErrKnownBlock is allowed here since some known blocks // still need re-execution to generate snapshots that are missing case err != nil && !errors.Is(err, ErrKnownBlock): - bc.futureBlocks.Remove(block.Hash()) stats.ignored += len(it.chain) bc.reportBlock(block, nil, err) return it.index, err @@ -1867,23 +1799,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) "root", block.Root()) } } - - // Any blocks remaining here? The only ones we care about are the future ones - if block != nil && errors.Is(err, consensus.ErrFutureBlock) { - if err := bc.addFutureBlock(block); err != nil { - return it.index, err - } - block, err = it.next() - - for ; block != nil && errors.Is(err, consensus.ErrUnknownAncestor); block, err = it.next() { - if err := bc.addFutureBlock(block); err != nil { - return it.index, err - } - stats.queued++ - } - } stats.ignored += it.remaining() - return it.index, err } @@ -2334,20 +2250,6 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) { return head.Hash(), nil } -func (bc *BlockChain) updateFutureBlocks() { - futureTimer := time.NewTicker(5 * time.Second) - defer futureTimer.Stop() - defer bc.wg.Done() - for { - select { - case <-futureTimer.C: - bc.procFutureBlocks() - case <-bc.quit: - return - } - } -} - // skipBlock returns 'true', if the block being imported can be skipped over, meaning // that the block does not need to be processed but can be considered already fully 'done'. func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool { diff --git a/core/blockchain_insert.go b/core/blockchain_insert.go index 9bf662b6b710..c7c4c4bfea8b 100644 --- a/core/blockchain_insert.go +++ b/core/blockchain_insert.go @@ -179,8 +179,3 @@ func (it *insertIterator) first() *types.Block { func (it *insertIterator) remaining() int { return len(it.chain) - it.index } - -// processed returns the number of processed blocks. -func (it *insertIterator) processed() int { - return it.index + 1 -} diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 876d662f74d8..4fa759129c9a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2129,7 +2129,6 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Generate a canonical chain to act as the main dataset chainConfig := *params.TestChainConfig var ( - merger = consensus.NewMerger(rawdb.NewMemoryDatabase()) engine = beacon.New(ethash.NewFaker()) key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key.PublicKey) @@ -2153,8 +2152,6 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Activate the transition since genesis if required if mergePoint == 0 { mergeBlock = 0 - merger.ReachTTD() - merger.FinalizePoS() // Set the terminal total difficulty in the config gspec.Config.TerminalTotalDifficulty = big.NewInt(0) @@ -2189,8 +2186,6 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Activate the transition in the middle of the chain if mergePoint == 1 { - merger.ReachTTD() - merger.FinalizePoS() // Set the terminal total difficulty in the config ttd := big.NewInt(int64(len(blocks))) ttd.Mul(ttd, params.GenesisDifficulty) diff --git a/eth/backend.go b/eth/backend.go index 09e1dbd258cd..f6c1637acadf 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -74,7 +74,6 @@ type Ethereum struct { handler *handler ethDialCandidates enode.Iterator snapDialCandidates enode.Iterator - merger *consensus.Merger // DB interfaces chainDb ethdb.Database // Block chain database @@ -158,7 +157,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } eth := &Ethereum{ config: config, - merger: consensus.NewMerger(chainDb), chainDb: chainDb, eventMux: stack.EventMux(), accountManager: stack.AccountManager(), @@ -240,7 +238,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { Database: chainDb, Chain: eth.blockchain, TxPool: eth.txPool, - Merger: eth.merger, Network: networkID, Sync: config.SyncMode, BloomCache: uint64(cacheLimit), @@ -487,11 +484,6 @@ func (s *Ethereum) Synced() bool { return s.handler.synced func (s *Ethereum) SetSynced() { s.handler.enableSyncedFeatures() } func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } -func (s *Ethereum) Merger() *consensus.Merger { return s.merger } -func (s *Ethereum) SyncMode() downloader.SyncMode { - mode, _ := s.handler.chainSync.modeAndLocalHead() - return mode -} // Protocols returns all the currently configured // network protocols to start. @@ -551,3 +543,29 @@ func (s *Ethereum) Stop() error { return nil } + +// SyncMode retrieves the current sync mode, either explicitly set, or derived +// from the chain status. +func (s *Ethereum) SyncMode() downloader.SyncMode { + // If we're in snap sync mode, return that directly + if s.handler.snapSync.Load() { + return downloader.SnapSync + } + // We are probably in full sync, but we might have rewound to before the + // snap sync pivot, check if we should re-enable snap sync. + head := s.blockchain.CurrentBlock() + if pivot := rawdb.ReadLastPivotNumber(s.chainDb); pivot != nil { + if head.Number.Uint64() < *pivot { + return downloader.SnapSync + } + } + // We are in a full sync, but the associated head state is missing. To complete + // the head state, forcefully rerun the snap sync. Note it doesn't mean the + // persistent state is corrupted, just mismatch with the head block. + if !s.blockchain.HasState(head.Root) { + log.Info("Reenabled snap sync as chain is stateless") + return downloader.SnapSync + } + // Nope, we're really full syncing + return downloader.FullSync +} diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index fea9d34cb83e..e5781b2c8f3e 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -267,12 +267,6 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl finalized := api.remoteBlocks.get(update.FinalizedBlockHash) // Header advertised via a past newPayload request. Start syncing to it. - // Before we do however, make sure any legacy sync in switched off so we - // don't accidentally have 2 cycles running. - if merger := api.eth.Merger(); !merger.TDDReached() { - merger.ReachTTD() - api.eth.Downloader().Cancel() - } context := []interface{}{"number", header.Number, "hash", header.Hash()} if update.FinalizedBlockHash != (common.Hash{}) { if finalized == nil { @@ -334,9 +328,6 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl // If the beacon client also advertised a finalized block, mark the local // chain final and completely in PoS mode. if update.FinalizedBlockHash != (common.Hash{}) { - if merger := api.eth.Merger(); !merger.PoSFinalized() { - merger.FinalizePoS() - } // If the finalized block is not in our canonical tree, something is wrong finalBlock := api.eth.BlockChain().GetBlockByHash(update.FinalizedBlockHash) if finalBlock == nil { @@ -620,13 +611,6 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe return api.invalid(err, parent.Header()), nil } - // We've accepted a valid payload from the beacon client. Mark the local - // chain transitions to notify other subsystems (e.g. downloader) of the - // behavioral change. - if merger := api.eth.Merger(); !merger.TDDReached() { - merger.ReachTTD() - api.eth.Downloader().Cancel() - } hash := block.Hash() return engine.PayloadStatusV1{Status: engine.VALID, LatestValidHash: &hash}, nil } @@ -784,26 +768,23 @@ func (api *ConsensusAPI) heartbeat() { // If there have been no updates for the past while, warn the user // that the beacon client is probably offline - if api.eth.BlockChain().Config().TerminalTotalDifficultyPassed || api.eth.Merger().TDDReached() { - if time.Since(lastForkchoiceUpdate) <= beaconUpdateConsensusTimeout || time.Since(lastNewPayloadUpdate) <= beaconUpdateConsensusTimeout { - offlineLogged = time.Time{} - continue - } - - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { - if lastTransitionUpdate.IsZero() { - log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") - } else { - log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") - } + if time.Since(lastForkchoiceUpdate) <= beaconUpdateConsensusTimeout || time.Since(lastNewPayloadUpdate) <= beaconUpdateConsensusTimeout { + offlineLogged = time.Time{} + continue + } + if time.Since(offlineLogged) > beaconUpdateWarnFrequency { + if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { + if lastTransitionUpdate.IsZero() { + log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") } else { - log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!") + log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") } - offlineLogged = time.Now() + } else { + log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!") } - continue + offlineLogged = time.Now() } + continue } } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index cc1258ca55bf..a82e2d6cf6f2 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -862,7 +862,6 @@ func TestTrickRemoteBlockCache(t *testing.T) { func TestInvalidBloom(t *testing.T) { genesis, preMergeBlocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) - ethservice.Merger().ReachTTD() defer n.Close() commonAncestor := ethservice.BlockChain().CurrentBlock() @@ -1044,7 +1043,6 @@ func TestWithdrawals(t *testing.T) { genesis.Config.ShanghaiTime = &time n, ethservice := startEthService(t, genesis, blocks) - ethservice.Merger().ReachTTD() defer n.Close() api := NewConsensusAPI(ethservice) @@ -1162,7 +1160,6 @@ func TestNilWithdrawals(t *testing.T) { genesis.Config.ShanghaiTime = &time n, ethservice := startEthService(t, genesis, blocks) - ethservice.Merger().ReachTTD() defer n.Close() api := NewConsensusAPI(ethservice) @@ -1589,7 +1586,6 @@ func TestParentBeaconBlockRoot(t *testing.T) { genesis.Config.CancunTime = &time n, ethservice := startEthService(t, genesis, blocks) - ethservice.Merger().ReachTTD() defer n.Close() api := NewConsensusAPI(ethservice) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index ad664afb5bd1..420a8b147a7f 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -165,15 +165,14 @@ type Config struct { // Clique is allowed for now to live standalone, but ethash is forbidden and can // only exist on already merged networks. func CreateConsensusEngine(config *params.ChainConfig, db ethdb.Database) (consensus.Engine, error) { - // If proof-of-authority is requested, set it up + // Geth v1.14.0 dropped support for non-merged networks in any consensus + // mode. If such a network is requested, reject startup. + if !config.TerminalTotalDifficultyPassed { + return nil, errors.New("only PoS networks are supported, please transition old ones with Geth v1.13.x") + } + // Wrap previously supported consensus engines into their post-merge counterpart if config.Clique != nil { return beacon.New(clique.New(config.Clique, db)), nil } - // If defaulting to proof-of-work, enforce an already merged network since - // we cannot run PoW algorithms anymore, so we cannot even follow a chain - // not coordinated by a beacon node. - if !config.TerminalTotalDifficultyPassed { - return nil, errors.New("ethash is only supported as a historical component of already merged networks") - } return beacon.New(ethash.NewFaker()), nil } diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go deleted file mode 100644 index 126eaaea7fad..000000000000 --- a/eth/fetcher/block_fetcher.go +++ /dev/null @@ -1,939 +0,0 @@ -// Copyright 2015 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 fetcher contains the announcement based header, blocks or transaction synchronisation. -package fetcher - -import ( - "errors" - "math/rand" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/prque" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/protocols/eth" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/trie" -) - -const ( - lightTimeout = time.Millisecond // Time allowance before an announced header is explicitly requested - arriveTimeout = 500 * time.Millisecond // Time allowance before an announced block/transaction is explicitly requested - gatherSlack = 100 * time.Millisecond // Interval used to collate almost-expired announces with fetches - fetchTimeout = 5 * time.Second // Maximum allotted time to return an explicitly requested block/transaction -) - -const ( - maxUncleDist = 7 // Maximum allowed backward distance from the chain head - maxQueueDist = 32 // Maximum allowed distance from the chain head to queue - hashLimit = 256 // Maximum number of unique blocks or headers a peer may have announced - blockLimit = 64 // Maximum number of unique blocks a peer may have delivered -) - -var ( - blockAnnounceInMeter = metrics.NewRegisteredMeter("eth/fetcher/block/announces/in", nil) - blockAnnounceOutTimer = metrics.NewRegisteredTimer("eth/fetcher/block/announces/out", nil) - blockAnnounceDropMeter = metrics.NewRegisteredMeter("eth/fetcher/block/announces/drop", nil) - blockAnnounceDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/block/announces/dos", nil) - - blockBroadcastInMeter = metrics.NewRegisteredMeter("eth/fetcher/block/broadcasts/in", nil) - blockBroadcastOutTimer = metrics.NewRegisteredTimer("eth/fetcher/block/broadcasts/out", nil) - blockBroadcastDropMeter = metrics.NewRegisteredMeter("eth/fetcher/block/broadcasts/drop", nil) - blockBroadcastDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/block/broadcasts/dos", nil) - - headerFetchMeter = metrics.NewRegisteredMeter("eth/fetcher/block/headers", nil) - bodyFetchMeter = metrics.NewRegisteredMeter("eth/fetcher/block/bodies", nil) - - headerFilterInMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/headers/in", nil) - headerFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/headers/out", nil) - bodyFilterInMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/bodies/in", nil) - bodyFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/bodies/out", nil) -) - -var errTerminated = errors.New("terminated") - -// HeaderRetrievalFn is a callback type for retrieving a header from the local chain. -type HeaderRetrievalFn func(common.Hash) *types.Header - -// blockRetrievalFn is a callback type for retrieving a block from the local chain. -type blockRetrievalFn func(common.Hash) *types.Block - -// headerRequesterFn is a callback type for sending a header retrieval request. -type headerRequesterFn func(common.Hash, chan *eth.Response) (*eth.Request, error) - -// bodyRequesterFn is a callback type for sending a body retrieval request. -type bodyRequesterFn func([]common.Hash, chan *eth.Response) (*eth.Request, error) - -// headerVerifierFn is a callback type to verify a block's header for fast propagation. -type headerVerifierFn func(header *types.Header) error - -// blockBroadcasterFn is a callback type for broadcasting a block to connected peers. -type blockBroadcasterFn func(block *types.Block, propagate bool) - -// chainHeightFn is a callback type to retrieve the current chain height. -type chainHeightFn func() uint64 - -// headersInsertFn is a callback type to insert a batch of headers into the local chain. -type headersInsertFn func(headers []*types.Header) (int, error) - -// chainInsertFn is a callback type to insert a batch of blocks into the local chain. -type chainInsertFn func(types.Blocks) (int, error) - -// peerDropFn is a callback type for dropping a peer detected as malicious. -type peerDropFn func(id string) - -// blockAnnounce is the hash notification of the availability of a new block in the -// network. -type blockAnnounce struct { - hash common.Hash // Hash of the block being announced - number uint64 // Number of the block being announced (0 = unknown | old protocol) - header *types.Header // Header of the block partially reassembled (new protocol) - time time.Time // Timestamp of the announcement - - origin string // Identifier of the peer originating the notification - - fetchHeader headerRequesterFn // Fetcher function to retrieve the header of an announced block - fetchBodies bodyRequesterFn // Fetcher function to retrieve the body of an announced block -} - -// headerFilterTask represents a batch of headers needing fetcher filtering. -type headerFilterTask struct { - peer string // The source peer of block headers - headers []*types.Header // Collection of headers to filter - time time.Time // Arrival time of the headers -} - -// bodyFilterTask represents a batch of block bodies (transactions and uncles) -// needing fetcher filtering. -type bodyFilterTask struct { - peer string // The source peer of block bodies - transactions [][]*types.Transaction // Collection of transactions per block bodies - uncles [][]*types.Header // Collection of uncles per block bodies - time time.Time // Arrival time of the blocks' contents -} - -// blockOrHeaderInject represents a schedules import operation. -type blockOrHeaderInject struct { - origin string - - header *types.Header // Used for light mode fetcher which only cares about header. - block *types.Block // Used for normal mode fetcher which imports full block. -} - -// number returns the block number of the injected object. -func (inject *blockOrHeaderInject) number() uint64 { - if inject.header != nil { - return inject.header.Number.Uint64() - } - return inject.block.NumberU64() -} - -// number returns the block hash of the injected object. -func (inject *blockOrHeaderInject) hash() common.Hash { - if inject.header != nil { - return inject.header.Hash() - } - return inject.block.Hash() -} - -// BlockFetcher is responsible for accumulating block announcements from various peers -// and scheduling them for retrieval. -type BlockFetcher struct { - light bool // The indicator whether it's a light fetcher or normal one. - - // Various event channels - notify chan *blockAnnounce - inject chan *blockOrHeaderInject - - headerFilter chan chan *headerFilterTask - bodyFilter chan chan *bodyFilterTask - - done chan common.Hash - quit chan struct{} - - // Announce states - announces map[string]int // Per peer blockAnnounce counts to prevent memory exhaustion - announced map[common.Hash][]*blockAnnounce // Announced blocks, scheduled for fetching - fetching map[common.Hash]*blockAnnounce // Announced blocks, currently fetching - fetched map[common.Hash][]*blockAnnounce // Blocks with headers fetched, scheduled for body retrieval - completing map[common.Hash]*blockAnnounce // Blocks with headers, currently body-completing - - // Block cache - queue *prque.Prque[int64, *blockOrHeaderInject] // Queue containing the import operations (block number sorted) - queues map[string]int // Per peer block counts to prevent memory exhaustion - queued map[common.Hash]*blockOrHeaderInject // Set of already queued blocks (to dedup imports) - - // Callbacks - getHeader HeaderRetrievalFn // Retrieves a header from the local chain - getBlock blockRetrievalFn // Retrieves a block from the local chain - verifyHeader headerVerifierFn // Checks if a block's headers have a valid proof of work - broadcastBlock blockBroadcasterFn // Broadcasts a block to connected peers - chainHeight chainHeightFn // Retrieves the current chain's height - insertHeaders headersInsertFn // Injects a batch of headers into the chain - insertChain chainInsertFn // Injects a batch of blocks into the chain - dropPeer peerDropFn // Drops a peer for misbehaving - - // Testing hooks - announceChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a hash from the blockAnnounce list - queueChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a block from the import queue - fetchingHook func([]common.Hash) // Method to call upon starting a block (eth/61) or header (eth/62) fetch - completingHook func([]common.Hash) // Method to call upon starting a block body fetch (eth/62) - importedHook func(*types.Header, *types.Block) // Method to call upon successful header or block import (both eth/61 and eth/62) -} - -// NewBlockFetcher creates a block fetcher to retrieve blocks based on hash announcements. -func NewBlockFetcher(light bool, getHeader HeaderRetrievalFn, getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, insertHeaders headersInsertFn, insertChain chainInsertFn, dropPeer peerDropFn) *BlockFetcher { - return &BlockFetcher{ - light: light, - notify: make(chan *blockAnnounce), - inject: make(chan *blockOrHeaderInject), - headerFilter: make(chan chan *headerFilterTask), - bodyFilter: make(chan chan *bodyFilterTask), - done: make(chan common.Hash), - quit: make(chan struct{}), - announces: make(map[string]int), - announced: make(map[common.Hash][]*blockAnnounce), - fetching: make(map[common.Hash]*blockAnnounce), - fetched: make(map[common.Hash][]*blockAnnounce), - completing: make(map[common.Hash]*blockAnnounce), - queue: prque.New[int64, *blockOrHeaderInject](nil), - queues: make(map[string]int), - queued: make(map[common.Hash]*blockOrHeaderInject), - getHeader: getHeader, - getBlock: getBlock, - verifyHeader: verifyHeader, - broadcastBlock: broadcastBlock, - chainHeight: chainHeight, - insertHeaders: insertHeaders, - insertChain: insertChain, - dropPeer: dropPeer, - } -} - -// Start boots up the announcement based synchroniser, accepting and processing -// hash notifications and block fetches until termination requested. -func (f *BlockFetcher) Start() { - go f.loop() -} - -// Stop terminates the announcement based synchroniser, canceling all pending -// operations. -func (f *BlockFetcher) Stop() { - close(f.quit) -} - -// Notify announces the fetcher of the potential availability of a new block in -// the network. -func (f *BlockFetcher) Notify(peer string, hash common.Hash, number uint64, time time.Time, - headerFetcher headerRequesterFn, bodyFetcher bodyRequesterFn) error { - block := &blockAnnounce{ - hash: hash, - number: number, - time: time, - origin: peer, - fetchHeader: headerFetcher, - fetchBodies: bodyFetcher, - } - select { - case f.notify <- block: - return nil - case <-f.quit: - return errTerminated - } -} - -// Enqueue tries to fill gaps the fetcher's future import queue. -func (f *BlockFetcher) Enqueue(peer string, block *types.Block) error { - op := &blockOrHeaderInject{ - origin: peer, - block: block, - } - select { - case f.inject <- op: - return nil - case <-f.quit: - return errTerminated - } -} - -// FilterHeaders extracts all the headers that were explicitly requested by the fetcher, -// returning those that should be handled differently. -func (f *BlockFetcher) FilterHeaders(peer string, headers []*types.Header, time time.Time) []*types.Header { - log.Trace("Filtering headers", "peer", peer, "headers", len(headers)) - - // Send the filter channel to the fetcher - filter := make(chan *headerFilterTask) - - select { - case f.headerFilter <- filter: - case <-f.quit: - return nil - } - // Request the filtering of the header list - select { - case filter <- &headerFilterTask{peer: peer, headers: headers, time: time}: - case <-f.quit: - return nil - } - // Retrieve the headers remaining after filtering - select { - case task := <-filter: - return task.headers - case <-f.quit: - return nil - } -} - -// FilterBodies extracts all the block bodies that were explicitly requested by -// the fetcher, returning those that should be handled differently. -func (f *BlockFetcher) FilterBodies(peer string, transactions [][]*types.Transaction, uncles [][]*types.Header, time time.Time) ([][]*types.Transaction, [][]*types.Header) { - log.Trace("Filtering bodies", "peer", peer, "txs", len(transactions), "uncles", len(uncles)) - - // Send the filter channel to the fetcher - filter := make(chan *bodyFilterTask) - - select { - case f.bodyFilter <- filter: - case <-f.quit: - return nil, nil - } - // Request the filtering of the body list - select { - case filter <- &bodyFilterTask{peer: peer, transactions: transactions, uncles: uncles, time: time}: - case <-f.quit: - return nil, nil - } - // Retrieve the bodies remaining after filtering - select { - case task := <-filter: - return task.transactions, task.uncles - case <-f.quit: - return nil, nil - } -} - -// Loop is the main fetcher loop, checking and processing various notification -// events. -func (f *BlockFetcher) loop() { - // Iterate the block fetching until a quit is requested - var ( - fetchTimer = time.NewTimer(0) - completeTimer = time.NewTimer(0) - ) - <-fetchTimer.C // clear out the channel - <-completeTimer.C - defer fetchTimer.Stop() - defer completeTimer.Stop() - - for { - // Clean up any expired block fetches - for hash, announce := range f.fetching { - if time.Since(announce.time) > fetchTimeout { - f.forgetHash(hash) - } - } - // Import any queued blocks that could potentially fit - height := f.chainHeight() - for !f.queue.Empty() { - op := f.queue.PopItem() - hash := op.hash() - if f.queueChangeHook != nil { - f.queueChangeHook(hash, false) - } - // If too high up the chain or phase, continue later - number := op.number() - if number > height+1 { - f.queue.Push(op, -int64(number)) - if f.queueChangeHook != nil { - f.queueChangeHook(hash, true) - } - break - } - // Otherwise if fresh and still unknown, try and import - if (number+maxUncleDist < height) || (f.light && f.getHeader(hash) != nil) || (!f.light && f.getBlock(hash) != nil) { - f.forgetBlock(hash) - continue - } - if f.light { - f.importHeaders(op.origin, op.header) - } else { - f.importBlocks(op.origin, op.block) - } - } - // Wait for an outside event to occur - select { - case <-f.quit: - // BlockFetcher terminating, abort all operations - return - - case notification := <-f.notify: - // A block was announced, make sure the peer isn't DOSing us - blockAnnounceInMeter.Mark(1) - - count := f.announces[notification.origin] + 1 - if count > hashLimit { - log.Debug("Peer exceeded outstanding announces", "peer", notification.origin, "limit", hashLimit) - blockAnnounceDOSMeter.Mark(1) - break - } - if notification.number == 0 { - break - } - // If we have a valid block number, check that it's potentially useful - if dist := int64(notification.number) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { - log.Debug("Peer discarded announcement", "peer", notification.origin, "number", notification.number, "hash", notification.hash, "distance", dist) - blockAnnounceDropMeter.Mark(1) - break - } - // All is well, schedule the announce if block's not yet downloading - if _, ok := f.fetching[notification.hash]; ok { - break - } - if _, ok := f.completing[notification.hash]; ok { - break - } - f.announces[notification.origin] = count - f.announced[notification.hash] = append(f.announced[notification.hash], notification) - if f.announceChangeHook != nil && len(f.announced[notification.hash]) == 1 { - f.announceChangeHook(notification.hash, true) - } - if len(f.announced) == 1 { - f.rescheduleFetch(fetchTimer) - } - - case op := <-f.inject: - // A direct block insertion was requested, try and fill any pending gaps - blockBroadcastInMeter.Mark(1) - - // Now only direct block injection is allowed, drop the header injection - // here silently if we receive. - if f.light { - continue - } - f.enqueue(op.origin, nil, op.block) - - case hash := <-f.done: - // A pending import finished, remove all traces of the notification - f.forgetHash(hash) - f.forgetBlock(hash) - - case <-fetchTimer.C: - // At least one block's timer ran out, check for needing retrieval - request := make(map[string][]common.Hash) - - for hash, announces := range f.announced { - // In current LES protocol(les2/les3), only header announce is - // available, no need to wait too much time for header broadcast. - timeout := arriveTimeout - gatherSlack - if f.light { - timeout = 0 - } - if time.Since(announces[0].time) > timeout { - // Pick a random peer to retrieve from, reset all others - announce := announces[rand.Intn(len(announces))] - f.forgetHash(hash) - - // If the block still didn't arrive, queue for fetching - if (f.light && f.getHeader(hash) == nil) || (!f.light && f.getBlock(hash) == nil) { - request[announce.origin] = append(request[announce.origin], hash) - f.fetching[hash] = announce - } - } - } - // Send out all block header requests - for peer, hashes := range request { - log.Trace("Fetching scheduled headers", "peer", peer, "list", hashes) - - // Create a closure of the fetch and schedule in on a new thread - fetchHeader, hashes := f.fetching[hashes[0]].fetchHeader, hashes - go func(peer string) { - if f.fetchingHook != nil { - f.fetchingHook(hashes) - } - for _, hash := range hashes { - headerFetchMeter.Mark(1) - go func(hash common.Hash) { - resCh := make(chan *eth.Response) - - req, err := fetchHeader(hash, resCh) - if err != nil { - return // Legacy code, yolo - } - defer req.Close() - - timeout := time.NewTimer(2 * fetchTimeout) // 2x leeway before dropping the peer - defer timeout.Stop() - - select { - case res := <-resCh: - res.Done <- nil - f.FilterHeaders(peer, *res.Res.(*eth.BlockHeadersRequest), time.Now()) - - case <-timeout.C: - // The peer didn't respond in time. The request - // was already rescheduled at this point, we were - // waiting for a catchup. With an unresponsive - // peer however, it's a protocol violation. - f.dropPeer(peer) - } - }(hash) - } - }(peer) - } - // Schedule the next fetch if blocks are still pending - f.rescheduleFetch(fetchTimer) - - case <-completeTimer.C: - // At least one header's timer ran out, retrieve everything - request := make(map[string][]common.Hash) - - for hash, announces := range f.fetched { - // Pick a random peer to retrieve from, reset all others - announce := announces[rand.Intn(len(announces))] - f.forgetHash(hash) - - // If the block still didn't arrive, queue for completion - if f.getBlock(hash) == nil { - request[announce.origin] = append(request[announce.origin], hash) - f.completing[hash] = announce - } - } - // Send out all block body requests - for peer, hashes := range request { - log.Trace("Fetching scheduled bodies", "peer", peer, "list", hashes) - - // Create a closure of the fetch and schedule in on a new thread - if f.completingHook != nil { - f.completingHook(hashes) - } - fetchBodies := f.completing[hashes[0]].fetchBodies - bodyFetchMeter.Mark(int64(len(hashes))) - - go func(peer string, hashes []common.Hash) { - resCh := make(chan *eth.Response) - - req, err := fetchBodies(hashes, resCh) - if err != nil { - return // Legacy code, yolo - } - defer req.Close() - - timeout := time.NewTimer(2 * fetchTimeout) // 2x leeway before dropping the peer - defer timeout.Stop() - - select { - case res := <-resCh: - res.Done <- nil - // Ignoring withdrawals here, since the block fetcher is not used post-merge. - txs, uncles, _ := res.Res.(*eth.BlockBodiesResponse).Unpack() - f.FilterBodies(peer, txs, uncles, time.Now()) - - case <-timeout.C: - // The peer didn't respond in time. The request - // was already rescheduled at this point, we were - // waiting for a catchup. With an unresponsive - // peer however, it's a protocol violation. - f.dropPeer(peer) - } - }(peer, hashes) - } - // Schedule the next fetch if blocks are still pending - f.rescheduleComplete(completeTimer) - - case filter := <-f.headerFilter: - // Headers arrived from a remote peer. Extract those that were explicitly - // requested by the fetcher, and return everything else so it's delivered - // to other parts of the system. - var task *headerFilterTask - select { - case task = <-filter: - case <-f.quit: - return - } - headerFilterInMeter.Mark(int64(len(task.headers))) - - // Split the batch of headers into unknown ones (to return to the caller), - // known incomplete ones (requiring body retrievals) and completed blocks. - unknown, incomplete, complete, lightHeaders := []*types.Header{}, []*blockAnnounce{}, []*types.Block{}, []*blockAnnounce{} - for _, header := range task.headers { - hash := header.Hash() - - // Filter fetcher-requested headers from other synchronisation algorithms - if announce := f.fetching[hash]; announce != nil && announce.origin == task.peer && f.fetched[hash] == nil && f.completing[hash] == nil && f.queued[hash] == nil { - // If the delivered header does not match the promised number, drop the announcer - if header.Number.Uint64() != announce.number { - log.Trace("Invalid block number fetched", "peer", announce.origin, "hash", header.Hash(), "announced", announce.number, "provided", header.Number) - f.dropPeer(announce.origin) - f.forgetHash(hash) - continue - } - // Collect all headers only if we are running in light - // mode and the headers are not imported by other means. - if f.light { - if f.getHeader(hash) == nil { - announce.header = header - lightHeaders = append(lightHeaders, announce) - } - f.forgetHash(hash) - continue - } - // Only keep if not imported by other means - if f.getBlock(hash) == nil { - announce.header = header - announce.time = task.time - - // If the block is empty (header only), short circuit into the final import queue - if header.TxHash == types.EmptyTxsHash && header.UncleHash == types.EmptyUncleHash { - log.Trace("Block empty, skipping body retrieval", "peer", announce.origin, "number", header.Number, "hash", header.Hash()) - - block := types.NewBlockWithHeader(header) - block.ReceivedAt = task.time - - complete = append(complete, block) - f.completing[hash] = announce - continue - } - // Otherwise add to the list of blocks needing completion - incomplete = append(incomplete, announce) - } else { - log.Trace("Block already imported, discarding header", "peer", announce.origin, "number", header.Number, "hash", header.Hash()) - f.forgetHash(hash) - } - } else { - // BlockFetcher doesn't know about it, add to the return list - unknown = append(unknown, header) - } - } - headerFilterOutMeter.Mark(int64(len(unknown))) - select { - case filter <- &headerFilterTask{headers: unknown, time: task.time}: - case <-f.quit: - return - } - // Schedule the retrieved headers for body completion - for _, announce := range incomplete { - hash := announce.header.Hash() - if _, ok := f.completing[hash]; ok { - continue - } - f.fetched[hash] = append(f.fetched[hash], announce) - if len(f.fetched) == 1 { - f.rescheduleComplete(completeTimer) - } - } - // Schedule the header for light fetcher import - for _, announce := range lightHeaders { - f.enqueue(announce.origin, announce.header, nil) - } - // Schedule the header-only blocks for import - for _, block := range complete { - if announce := f.completing[block.Hash()]; announce != nil { - f.enqueue(announce.origin, nil, block) - } - } - - case filter := <-f.bodyFilter: - // Block bodies arrived, extract any explicitly requested blocks, return the rest - var task *bodyFilterTask - select { - case task = <-filter: - case <-f.quit: - return - } - bodyFilterInMeter.Mark(int64(len(task.transactions))) - blocks := []*types.Block{} - // abort early if there's nothing explicitly requested - if len(f.completing) > 0 { - for i := 0; i < len(task.transactions) && i < len(task.uncles); i++ { - // Match up a body to any possible completion request - var ( - matched = false - uncleHash common.Hash // calculated lazily and reused - txnHash common.Hash // calculated lazily and reused - ) - for hash, announce := range f.completing { - if f.queued[hash] != nil || announce.origin != task.peer { - continue - } - if uncleHash == (common.Hash{}) { - uncleHash = types.CalcUncleHash(task.uncles[i]) - } - if uncleHash != announce.header.UncleHash { - continue - } - if txnHash == (common.Hash{}) { - txnHash = types.DeriveSha(types.Transactions(task.transactions[i]), trie.NewStackTrie(nil)) - } - if txnHash != announce.header.TxHash { - continue - } - // Mark the body matched, reassemble if still unknown - matched = true - if f.getBlock(hash) == nil { - block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i]) - block.ReceivedAt = task.time - blocks = append(blocks, block) - } else { - f.forgetHash(hash) - } - } - if matched { - task.transactions = append(task.transactions[:i], task.transactions[i+1:]...) - task.uncles = append(task.uncles[:i], task.uncles[i+1:]...) - i-- - continue - } - } - } - bodyFilterOutMeter.Mark(int64(len(task.transactions))) - select { - case filter <- task: - case <-f.quit: - return - } - // Schedule the retrieved blocks for ordered import - for _, block := range blocks { - if announce := f.completing[block.Hash()]; announce != nil { - f.enqueue(announce.origin, nil, block) - } - } - } - } -} - -// rescheduleFetch resets the specified fetch timer to the next blockAnnounce timeout. -func (f *BlockFetcher) rescheduleFetch(fetch *time.Timer) { - // Short circuit if no blocks are announced - if len(f.announced) == 0 { - return - } - // Schedule announcement retrieval quickly for light mode - // since server won't send any headers to client. - if f.light { - fetch.Reset(lightTimeout) - return - } - // Otherwise find the earliest expiring announcement - earliest := time.Now() - for _, announces := range f.announced { - if earliest.After(announces[0].time) { - earliest = announces[0].time - } - } - fetch.Reset(arriveTimeout - time.Since(earliest)) -} - -// rescheduleComplete resets the specified completion timer to the next fetch timeout. -func (f *BlockFetcher) rescheduleComplete(complete *time.Timer) { - // Short circuit if no headers are fetched - if len(f.fetched) == 0 { - return - } - // Otherwise find the earliest expiring announcement - earliest := time.Now() - for _, announces := range f.fetched { - if earliest.After(announces[0].time) { - earliest = announces[0].time - } - } - complete.Reset(gatherSlack - time.Since(earliest)) -} - -// enqueue schedules a new header or block import operation, if the component -// to be imported has not yet been seen. -func (f *BlockFetcher) enqueue(peer string, header *types.Header, block *types.Block) { - var ( - hash common.Hash - number uint64 - ) - if header != nil { - hash, number = header.Hash(), header.Number.Uint64() - } else { - hash, number = block.Hash(), block.NumberU64() - } - // Ensure the peer isn't DOSing us - count := f.queues[peer] + 1 - if count > blockLimit { - log.Debug("Discarded delivered header or block, exceeded allowance", "peer", peer, "number", number, "hash", hash, "limit", blockLimit) - blockBroadcastDOSMeter.Mark(1) - f.forgetHash(hash) - return - } - // Discard any past or too distant blocks - if dist := int64(number) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { - log.Debug("Discarded delivered header or block, too far away", "peer", peer, "number", number, "hash", hash, "distance", dist) - blockBroadcastDropMeter.Mark(1) - f.forgetHash(hash) - return - } - // Schedule the block for future importing - if _, ok := f.queued[hash]; !ok { - op := &blockOrHeaderInject{origin: peer} - if header != nil { - op.header = header - } else { - op.block = block - } - f.queues[peer] = count - f.queued[hash] = op - f.queue.Push(op, -int64(number)) - if f.queueChangeHook != nil { - f.queueChangeHook(hash, true) - } - log.Debug("Queued delivered header or block", "peer", peer, "number", number, "hash", hash, "queued", f.queue.Size()) - } -} - -// importHeaders spawns a new goroutine to run a header insertion into the chain. -// If the header's number is at the same height as the current import phase, it -// updates the phase states accordingly. -func (f *BlockFetcher) importHeaders(peer string, header *types.Header) { - hash := header.Hash() - log.Debug("Importing propagated header", "peer", peer, "number", header.Number, "hash", hash) - - go func() { - defer func() { f.done <- hash }() - // If the parent's unknown, abort insertion - parent := f.getHeader(header.ParentHash) - if parent == nil { - log.Debug("Unknown parent of propagated header", "peer", peer, "number", header.Number, "hash", hash, "parent", header.ParentHash) - return - } - // Validate the header and if something went wrong, drop the peer - if err := f.verifyHeader(header); err != nil && err != consensus.ErrFutureBlock { - log.Debug("Propagated header verification failed", "peer", peer, "number", header.Number, "hash", hash, "err", err) - f.dropPeer(peer) - return - } - // Run the actual import and log any issues - if _, err := f.insertHeaders([]*types.Header{header}); err != nil { - log.Debug("Propagated header import failed", "peer", peer, "number", header.Number, "hash", hash, "err", err) - return - } - // Invoke the testing hook if needed - if f.importedHook != nil { - f.importedHook(header, nil) - } - }() -} - -// importBlocks spawns a new goroutine to run a block insertion into the chain. If the -// block's number is at the same height as the current import phase, it updates -// the phase states accordingly. -func (f *BlockFetcher) importBlocks(peer string, block *types.Block) { - hash := block.Hash() - - // Run the import on a new thread - log.Debug("Importing propagated block", "peer", peer, "number", block.Number(), "hash", hash) - go func() { - defer func() { f.done <- hash }() - - // If the parent's unknown, abort insertion - parent := f.getBlock(block.ParentHash()) - if parent == nil { - log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash()) - return - } - // Quickly validate the header and propagate the block if it passes - switch err := f.verifyHeader(block.Header()); err { - case nil: - // All ok, quickly propagate to our peers - blockBroadcastOutTimer.UpdateSince(block.ReceivedAt) - go f.broadcastBlock(block, true) - - case consensus.ErrFutureBlock: - // Weird future block, don't fail, but neither propagate - - default: - // Something went very wrong, drop the peer - log.Debug("Propagated block verification failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err) - f.dropPeer(peer) - return - } - // Run the actual import and log any issues - if _, err := f.insertChain(types.Blocks{block}); err != nil { - log.Debug("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err) - return - } - // If import succeeded, broadcast the block - blockAnnounceOutTimer.UpdateSince(block.ReceivedAt) - go f.broadcastBlock(block, false) - - // Invoke the testing hook if needed - if f.importedHook != nil { - f.importedHook(nil, block) - } - }() -} - -// forgetHash removes all traces of a block announcement from the fetcher's -// internal state. -func (f *BlockFetcher) forgetHash(hash common.Hash) { - // Remove all pending announces and decrement DOS counters - if announceMap, ok := f.announced[hash]; ok { - for _, announce := range announceMap { - f.announces[announce.origin]-- - if f.announces[announce.origin] <= 0 { - delete(f.announces, announce.origin) - } - } - delete(f.announced, hash) - if f.announceChangeHook != nil { - f.announceChangeHook(hash, false) - } - } - // Remove any pending fetches and decrement the DOS counters - if announce := f.fetching[hash]; announce != nil { - f.announces[announce.origin]-- - if f.announces[announce.origin] <= 0 { - delete(f.announces, announce.origin) - } - delete(f.fetching, hash) - } - - // Remove any pending completion requests and decrement the DOS counters - for _, announce := range f.fetched[hash] { - f.announces[announce.origin]-- - if f.announces[announce.origin] <= 0 { - delete(f.announces, announce.origin) - } - } - delete(f.fetched, hash) - - // Remove any pending completions and decrement the DOS counters - if announce := f.completing[hash]; announce != nil { - f.announces[announce.origin]-- - if f.announces[announce.origin] <= 0 { - delete(f.announces, announce.origin) - } - delete(f.completing, hash) - } -} - -// forgetBlock removes all traces of a queued block from the fetcher's internal -// state. -func (f *BlockFetcher) forgetBlock(hash common.Hash) { - if insert := f.queued[hash]; insert != nil { - f.queues[insert.origin]-- - if f.queues[insert.origin] == 0 { - delete(f.queues, insert.origin) - } - delete(f.queued, hash) - } -} diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go deleted file mode 100644 index cb7cbaf79edc..000000000000 --- a/eth/fetcher/block_fetcher_test.go +++ /dev/null @@ -1,949 +0,0 @@ -// Copyright 2015 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 fetcher - -import ( - "errors" - "math/big" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/protocols/eth" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/triedb" -) - -var ( - testdb = rawdb.NewMemoryDatabase() - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - testAddress = crypto.PubkeyToAddress(testKey.PublicKey) - gspec = &core.Genesis{ - Config: params.TestChainConfig, - Alloc: types.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, - BaseFee: big.NewInt(params.InitialBaseFee), - } - genesis = gspec.MustCommit(testdb, triedb.NewDatabase(testdb, triedb.HashDefaults)) - unknownBlock = types.NewBlock(&types.Header{Root: types.EmptyRootHash, GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil)) -) - -// makeChain creates a chain of n blocks starting at and including parent. -// the returned hash chain is ordered head->parent. In addition, every 3rd block -// contains a transaction and every 5th an uncle to allow testing correct block -// reassembly. -func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { - blocks, _ := core.GenerateChain(gspec.Config, parent, ethash.NewFaker(), testdb, n, func(i int, block *core.BlockGen) { - block.SetCoinbase(common.Address{seed}) - - // If the block number is multiple of 3, send a bonus transaction to the miner - if parent == genesis && i%3 == 0 { - signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp()) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) - if err != nil { - panic(err) - } - block.AddTx(tx) - } - // If the block number is a multiple of 5, add a bonus uncle to the block - if i > 0 && i%5 == 0 { - block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 2).Hash(), Number: big.NewInt(int64(i - 1))}) - } - }) - hashes := make([]common.Hash, n+1) - hashes[len(hashes)-1] = parent.Hash() - blockm := make(map[common.Hash]*types.Block, n+1) - blockm[parent.Hash()] = parent - for i, b := range blocks { - hashes[len(hashes)-i-2] = b.Hash() - blockm[b.Hash()] = b - } - return hashes, blockm -} - -// fetcherTester is a test simulator for mocking out local block chain. -type fetcherTester struct { - fetcher *BlockFetcher - - hashes []common.Hash // Hash chain belonging to the tester - headers map[common.Hash]*types.Header // Headers belonging to the tester - blocks map[common.Hash]*types.Block // Blocks belonging to the tester - drops map[string]bool // Map of peers dropped by the fetcher - - lock sync.RWMutex -} - -// newTester creates a new fetcher test mocker. -func newTester(light bool) *fetcherTester { - tester := &fetcherTester{ - hashes: []common.Hash{genesis.Hash()}, - headers: map[common.Hash]*types.Header{genesis.Hash(): genesis.Header()}, - blocks: map[common.Hash]*types.Block{genesis.Hash(): genesis}, - drops: make(map[string]bool), - } - tester.fetcher = NewBlockFetcher(light, tester.getHeader, tester.getBlock, tester.verifyHeader, tester.broadcastBlock, tester.chainHeight, tester.insertHeaders, tester.insertChain, tester.dropPeer) - tester.fetcher.Start() - - return tester -} - -// getHeader retrieves a header from the tester's block chain. -func (f *fetcherTester) getHeader(hash common.Hash) *types.Header { - f.lock.RLock() - defer f.lock.RUnlock() - - return f.headers[hash] -} - -// getBlock retrieves a block from the tester's block chain. -func (f *fetcherTester) getBlock(hash common.Hash) *types.Block { - f.lock.RLock() - defer f.lock.RUnlock() - - return f.blocks[hash] -} - -// verifyHeader is a nop placeholder for the block header verification. -func (f *fetcherTester) verifyHeader(header *types.Header) error { - return nil -} - -// broadcastBlock is a nop placeholder for the block broadcasting. -func (f *fetcherTester) broadcastBlock(block *types.Block, propagate bool) { -} - -// chainHeight retrieves the current height (block number) of the chain. -func (f *fetcherTester) chainHeight() uint64 { - f.lock.RLock() - defer f.lock.RUnlock() - - if f.fetcher.light { - return f.headers[f.hashes[len(f.hashes)-1]].Number.Uint64() - } - return f.blocks[f.hashes[len(f.hashes)-1]].NumberU64() -} - -// insertChain injects a new headers into the simulated chain. -func (f *fetcherTester) insertHeaders(headers []*types.Header) (int, error) { - f.lock.Lock() - defer f.lock.Unlock() - - for i, header := range headers { - // Make sure the parent in known - if _, ok := f.headers[header.ParentHash]; !ok { - return i, errors.New("unknown parent") - } - // Discard any new blocks if the same height already exists - if header.Number.Uint64() <= f.headers[f.hashes[len(f.hashes)-1]].Number.Uint64() { - return i, nil - } - // Otherwise build our current chain - f.hashes = append(f.hashes, header.Hash()) - f.headers[header.Hash()] = header - } - return 0, nil -} - -// insertChain injects a new blocks into the simulated chain. -func (f *fetcherTester) insertChain(blocks types.Blocks) (int, error) { - f.lock.Lock() - defer f.lock.Unlock() - - for i, block := range blocks { - // Make sure the parent in known - if _, ok := f.blocks[block.ParentHash()]; !ok { - return i, errors.New("unknown parent") - } - // Discard any new blocks if the same height already exists - if block.NumberU64() <= f.blocks[f.hashes[len(f.hashes)-1]].NumberU64() { - return i, nil - } - // Otherwise build our current chain - f.hashes = append(f.hashes, block.Hash()) - f.blocks[block.Hash()] = block - } - return 0, nil -} - -// dropPeer is an emulator for the peer removal, simply accumulating the various -// peers dropped by the fetcher. -func (f *fetcherTester) dropPeer(peer string) { - f.lock.Lock() - defer f.lock.Unlock() - - f.drops[peer] = true -} - -// makeHeaderFetcher retrieves a block header fetcher associated with a simulated peer. -func (f *fetcherTester) makeHeaderFetcher(peer string, blocks map[common.Hash]*types.Block, drift time.Duration) headerRequesterFn { - closure := make(map[common.Hash]*types.Block) - for hash, block := range blocks { - closure[hash] = block - } - // Create a function that return a header from the closure - return func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) { - // Gather the blocks to return - headers := make([]*types.Header, 0, 1) - if block, ok := closure[hash]; ok { - headers = append(headers, block.Header()) - } - // Return on a new thread - req := ð.Request{ - Peer: peer, - } - res := ð.Response{ - Req: req, - Res: (*eth.BlockHeadersRequest)(&headers), - Time: drift, - Done: make(chan error, 1), // Ignore the returned status - } - go func() { - sink <- res - }() - return req, nil - } -} - -// makeBodyFetcher retrieves a block body fetcher associated with a simulated peer. -func (f *fetcherTester) makeBodyFetcher(peer string, blocks map[common.Hash]*types.Block, drift time.Duration) bodyRequesterFn { - closure := make(map[common.Hash]*types.Block) - for hash, block := range blocks { - closure[hash] = block - } - // Create a function that returns blocks from the closure - return func(hashes []common.Hash, sink chan *eth.Response) (*eth.Request, error) { - // Gather the block bodies to return - transactions := make([][]*types.Transaction, 0, len(hashes)) - uncles := make([][]*types.Header, 0, len(hashes)) - - for _, hash := range hashes { - if block, ok := closure[hash]; ok { - transactions = append(transactions, block.Transactions()) - uncles = append(uncles, block.Uncles()) - } - } - // Return on a new thread - bodies := make([]*eth.BlockBody, len(transactions)) - for i, txs := range transactions { - bodies[i] = ð.BlockBody{ - Transactions: txs, - Uncles: uncles[i], - } - } - req := ð.Request{ - Peer: peer, - } - res := ð.Response{ - Req: req, - Res: (*eth.BlockBodiesResponse)(&bodies), - Time: drift, - Done: make(chan error, 1), // Ignore the returned status - } - go func() { - sink <- res - }() - return req, nil - } -} - -// verifyFetchingEvent verifies that one single event arrive on a fetching channel. -func verifyFetchingEvent(t *testing.T, fetching chan []common.Hash, arrive bool) { - t.Helper() - - if arrive { - select { - case <-fetching: - case <-time.After(time.Second): - t.Fatalf("fetching timeout") - } - } else { - select { - case <-fetching: - t.Fatalf("fetching invoked") - case <-time.After(10 * time.Millisecond): - } - } -} - -// verifyCompletingEvent verifies that one single event arrive on an completing channel. -func verifyCompletingEvent(t *testing.T, completing chan []common.Hash, arrive bool) { - t.Helper() - - if arrive { - select { - case <-completing: - case <-time.After(time.Second): - t.Fatalf("completing timeout") - } - } else { - select { - case <-completing: - t.Fatalf("completing invoked") - case <-time.After(10 * time.Millisecond): - } - } -} - -// verifyImportEvent verifies that one single event arrive on an import channel. -func verifyImportEvent(t *testing.T, imported chan interface{}, arrive bool) { - t.Helper() - - if arrive { - select { - case <-imported: - case <-time.After(time.Second): - t.Fatalf("import timeout") - } - } else { - select { - case <-imported: - t.Fatalf("import invoked") - case <-time.After(20 * time.Millisecond): - } - } -} - -// verifyImportCount verifies that exactly count number of events arrive on an -// import hook channel. -func verifyImportCount(t *testing.T, imported chan interface{}, count int) { - t.Helper() - - for i := 0; i < count; i++ { - select { - case <-imported: - case <-time.After(time.Second): - t.Fatalf("block %d: import timeout", i+1) - } - } - verifyImportDone(t, imported) -} - -// verifyImportDone verifies that no more events are arriving on an import channel. -func verifyImportDone(t *testing.T, imported chan interface{}) { - t.Helper() - - select { - case <-imported: - t.Fatalf("extra block imported") - case <-time.After(50 * time.Millisecond): - } -} - -// verifyChainHeight verifies the chain height is as expected. -func verifyChainHeight(t *testing.T, fetcher *fetcherTester, height uint64) { - t.Helper() - - if fetcher.chainHeight() != height { - t.Fatalf("chain height mismatch, got %d, want %d", fetcher.chainHeight(), height) - } -} - -// Tests that a fetcher accepts block/header announcements and initiates retrievals -// for them, successfully importing into the local chain. -func TestFullSequentialAnnouncements(t *testing.T) { testSequentialAnnouncements(t, false) } -func TestLightSequentialAnnouncements(t *testing.T) { testSequentialAnnouncements(t, true) } - -func testSequentialAnnouncements(t *testing.T, light bool) { - // Create a chain of blocks to import - targetBlocks := 4 * hashLimit - hashes, blocks := makeChain(targetBlocks, 0, genesis) - - tester := newTester(light) - defer tester.fetcher.Stop() - headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) - bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) - - // Iteratively announce blocks until all are imported - imported := make(chan interface{}) - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { - if light { - if header == nil { - t.Fatalf("Fetcher try to import empty header") - } - imported <- header - } else { - if block == nil { - t.Fatalf("Fetcher try to import empty block") - } - imported <- block - } - } - for i := len(hashes) - 2; i >= 0; i-- { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) - verifyImportEvent(t, imported, true) - } - verifyImportDone(t, imported) - verifyChainHeight(t, tester, uint64(len(hashes)-1)) -} - -// Tests that if blocks are announced by multiple peers (or even the same buggy -// peer), they will only get downloaded at most once. -func TestFullConcurrentAnnouncements(t *testing.T) { testConcurrentAnnouncements(t, false) } -func TestLightConcurrentAnnouncements(t *testing.T) { testConcurrentAnnouncements(t, true) } - -func testConcurrentAnnouncements(t *testing.T, light bool) { - // Create a chain of blocks to import - targetBlocks := 4 * hashLimit - hashes, blocks := makeChain(targetBlocks, 0, genesis) - - // Assemble a tester with a built in counter for the requests - tester := newTester(light) - firstHeaderFetcher := tester.makeHeaderFetcher("first", blocks, -gatherSlack) - firstBodyFetcher := tester.makeBodyFetcher("first", blocks, 0) - secondHeaderFetcher := tester.makeHeaderFetcher("second", blocks, -gatherSlack) - secondBodyFetcher := tester.makeBodyFetcher("second", blocks, 0) - - var counter atomic.Uint32 - firstHeaderWrapper := func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) { - counter.Add(1) - return firstHeaderFetcher(hash, sink) - } - secondHeaderWrapper := func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) { - counter.Add(1) - return secondHeaderFetcher(hash, sink) - } - // Iteratively announce blocks until all are imported - imported := make(chan interface{}) - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { - if light { - if header == nil { - t.Fatalf("Fetcher try to import empty header") - } - imported <- header - } else { - if block == nil { - t.Fatalf("Fetcher try to import empty block") - } - imported <- block - } - } - for i := len(hashes) - 2; i >= 0; i-- { - tester.fetcher.Notify("first", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), firstHeaderWrapper, firstBodyFetcher) - tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout+time.Millisecond), secondHeaderWrapper, secondBodyFetcher) - tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout-time.Millisecond), secondHeaderWrapper, secondBodyFetcher) - verifyImportEvent(t, imported, true) - } - verifyImportDone(t, imported) - - // Make sure no blocks were retrieved twice - if c := int(counter.Load()); c != targetBlocks { - t.Fatalf("retrieval count mismatch: have %v, want %v", c, targetBlocks) - } - verifyChainHeight(t, tester, uint64(len(hashes)-1)) -} - -// Tests that announcements arriving while a previous is being fetched still -// results in a valid import. -func TestFullOverlappingAnnouncements(t *testing.T) { testOverlappingAnnouncements(t, false) } -func TestLightOverlappingAnnouncements(t *testing.T) { testOverlappingAnnouncements(t, true) } - -func testOverlappingAnnouncements(t *testing.T, light bool) { - // Create a chain of blocks to import - targetBlocks := 4 * hashLimit - hashes, blocks := makeChain(targetBlocks, 0, genesis) - - tester := newTester(light) - headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) - bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) - - // Iteratively announce blocks, but overlap them continuously - overlap := 16 - imported := make(chan interface{}, len(hashes)-1) - for i := 0; i < overlap; i++ { - imported <- nil - } - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { - if light { - if header == nil { - t.Fatalf("Fetcher try to import empty header") - } - imported <- header - } else { - if block == nil { - t.Fatalf("Fetcher try to import empty block") - } - imported <- block - } - } - - for i := len(hashes) - 2; i >= 0; i-- { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) - select { - case <-imported: - case <-time.After(time.Second): - t.Fatalf("block %d: import timeout", len(hashes)-i) - } - } - // Wait for all the imports to complete and check count - verifyImportCount(t, imported, overlap) - verifyChainHeight(t, tester, uint64(len(hashes)-1)) -} - -// Tests that announces already being retrieved will not be duplicated. -func TestFullPendingDeduplication(t *testing.T) { testPendingDeduplication(t, false) } -func TestLightPendingDeduplication(t *testing.T) { testPendingDeduplication(t, true) } - -func testPendingDeduplication(t *testing.T, light bool) { - // Create a hash and corresponding block - hashes, blocks := makeChain(1, 0, genesis) - - // Assemble a tester with a built in counter and delayed fetcher - tester := newTester(light) - headerFetcher := tester.makeHeaderFetcher("repeater", blocks, -gatherSlack) - bodyFetcher := tester.makeBodyFetcher("repeater", blocks, 0) - - delay := 50 * time.Millisecond - var counter atomic.Uint32 - headerWrapper := func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) { - counter.Add(1) - - // Simulate a long running fetch - resink := make(chan *eth.Response) - req, err := headerFetcher(hash, resink) - if err == nil { - go func() { - res := <-resink - time.Sleep(delay) - sink <- res - }() - } - return req, err - } - checkNonExist := func() bool { - return tester.getBlock(hashes[0]) == nil - } - if light { - checkNonExist = func() bool { - return tester.getHeader(hashes[0]) == nil - } - } - // Announce the same block many times until it's fetched (wait for any pending ops) - for checkNonExist() { - tester.fetcher.Notify("repeater", hashes[0], 1, time.Now().Add(-arriveTimeout), headerWrapper, bodyFetcher) - time.Sleep(time.Millisecond) - } - time.Sleep(delay) - - // Check that all blocks were imported and none fetched twice - if c := counter.Load(); c != 1 { - t.Fatalf("retrieval count mismatch: have %v, want %v", c, 1) - } - verifyChainHeight(t, tester, 1) -} - -// Tests that announcements retrieved in a random order are cached and eventually -// imported when all the gaps are filled in. -func TestFullRandomArrivalImport(t *testing.T) { testRandomArrivalImport(t, false) } -func TestLightRandomArrivalImport(t *testing.T) { testRandomArrivalImport(t, true) } - -func testRandomArrivalImport(t *testing.T, light bool) { - // Create a chain of blocks to import, and choose one to delay - targetBlocks := maxQueueDist - hashes, blocks := makeChain(targetBlocks, 0, genesis) - skip := targetBlocks / 2 - - tester := newTester(light) - headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) - bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) - - // Iteratively announce blocks, skipping one entry - imported := make(chan interface{}, len(hashes)-1) - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { - if light { - if header == nil { - t.Fatalf("Fetcher try to import empty header") - } - imported <- header - } else { - if block == nil { - t.Fatalf("Fetcher try to import empty block") - } - imported <- block - } - } - for i := len(hashes) - 1; i >= 0; i-- { - if i != skip { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) - time.Sleep(time.Millisecond) - } - } - // Finally announce the skipped entry and check full import - tester.fetcher.Notify("valid", hashes[skip], uint64(len(hashes)-skip-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) - verifyImportCount(t, imported, len(hashes)-1) - verifyChainHeight(t, tester, uint64(len(hashes)-1)) -} - -// Tests that direct block enqueues (due to block propagation vs. hash announce) -// are correctly schedule, filling and import queue gaps. -func TestQueueGapFill(t *testing.T) { - // Create a chain of blocks to import, and choose one to not announce at all - targetBlocks := maxQueueDist - hashes, blocks := makeChain(targetBlocks, 0, genesis) - skip := targetBlocks / 2 - - tester := newTester(false) - headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) - bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) - - // Iteratively announce blocks, skipping one entry - imported := make(chan interface{}, len(hashes)-1) - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { imported <- block } - - for i := len(hashes) - 1; i >= 0; i-- { - if i != skip { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) - time.Sleep(time.Millisecond) - } - } - // Fill the missing block directly as if propagated - tester.fetcher.Enqueue("valid", blocks[hashes[skip]]) - verifyImportCount(t, imported, len(hashes)-1) - verifyChainHeight(t, tester, uint64(len(hashes)-1)) -} - -// Tests that blocks arriving from various sources (multiple propagations, hash -// announces, etc) do not get scheduled for import multiple times. -func TestImportDeduplication(t *testing.T) { - // Create two blocks to import (one for duplication, the other for stalling) - hashes, blocks := makeChain(2, 0, genesis) - - // Create the tester and wrap the importer with a counter - tester := newTester(false) - headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) - bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) - - var counter atomic.Uint32 - tester.fetcher.insertChain = func(blocks types.Blocks) (int, error) { - counter.Add(uint32(len(blocks))) - return tester.insertChain(blocks) - } - // Instrument the fetching and imported events - fetching := make(chan []common.Hash) - imported := make(chan interface{}, len(hashes)-1) - tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- hashes } - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { imported <- block } - - // Announce the duplicating block, wait for retrieval, and also propagate directly - tester.fetcher.Notify("valid", hashes[0], 1, time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) - <-fetching - - tester.fetcher.Enqueue("valid", blocks[hashes[0]]) - tester.fetcher.Enqueue("valid", blocks[hashes[0]]) - tester.fetcher.Enqueue("valid", blocks[hashes[0]]) - - // Fill the missing block directly as if propagated, and check import uniqueness - tester.fetcher.Enqueue("valid", blocks[hashes[1]]) - verifyImportCount(t, imported, 2) - - if c := counter.Load(); c != 2 { - t.Fatalf("import invocation count mismatch: have %v, want %v", c, 2) - } -} - -// Tests that blocks with numbers much lower or higher than out current head get -// discarded to prevent wasting resources on useless blocks from faulty peers. -func TestDistantPropagationDiscarding(t *testing.T) { - // Create a long chain to import and define the discard boundaries - hashes, blocks := makeChain(3*maxQueueDist, 0, genesis) - head := hashes[len(hashes)/2] - - low, high := len(hashes)/2+maxUncleDist+1, len(hashes)/2-maxQueueDist-1 - - // Create a tester and simulate a head block being the middle of the above chain - tester := newTester(false) - - tester.lock.Lock() - tester.hashes = []common.Hash{head} - tester.blocks = map[common.Hash]*types.Block{head: blocks[head]} - tester.lock.Unlock() - - // Ensure that a block with a lower number than the threshold is discarded - tester.fetcher.Enqueue("lower", blocks[hashes[low]]) - time.Sleep(10 * time.Millisecond) - if !tester.fetcher.queue.Empty() { - t.Fatalf("fetcher queued stale block") - } - // Ensure that a block with a higher number than the threshold is discarded - tester.fetcher.Enqueue("higher", blocks[hashes[high]]) - time.Sleep(10 * time.Millisecond) - if !tester.fetcher.queue.Empty() { - t.Fatalf("fetcher queued future block") - } -} - -// Tests that announcements with numbers much lower or higher than out current -// head get discarded to prevent wasting resources on useless blocks from faulty -// peers. -func TestFullDistantAnnouncementDiscarding(t *testing.T) { testDistantAnnouncementDiscarding(t, false) } -func TestLightDistantAnnouncementDiscarding(t *testing.T) { testDistantAnnouncementDiscarding(t, true) } - -func testDistantAnnouncementDiscarding(t *testing.T, light bool) { - // Create a long chain to import and define the discard boundaries - hashes, blocks := makeChain(3*maxQueueDist, 0, genesis) - head := hashes[len(hashes)/2] - - low, high := len(hashes)/2+maxUncleDist+1, len(hashes)/2-maxQueueDist-1 - - // Create a tester and simulate a head block being the middle of the above chain - tester := newTester(light) - - tester.lock.Lock() - tester.hashes = []common.Hash{head} - tester.headers = map[common.Hash]*types.Header{head: blocks[head].Header()} - tester.blocks = map[common.Hash]*types.Block{head: blocks[head]} - tester.lock.Unlock() - - headerFetcher := tester.makeHeaderFetcher("lower", blocks, -gatherSlack) - bodyFetcher := tester.makeBodyFetcher("lower", blocks, 0) - - fetching := make(chan struct{}, 2) - tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- struct{}{} } - - // Ensure that a block with a lower number than the threshold is discarded - tester.fetcher.Notify("lower", hashes[low], blocks[hashes[low]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) - select { - case <-time.After(50 * time.Millisecond): - case <-fetching: - t.Fatalf("fetcher requested stale header") - } - // Ensure that a block with a higher number than the threshold is discarded - tester.fetcher.Notify("higher", hashes[high], blocks[hashes[high]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) - select { - case <-time.After(50 * time.Millisecond): - case <-fetching: - t.Fatalf("fetcher requested future header") - } -} - -// Tests that peers announcing blocks with invalid numbers (i.e. not matching -// the headers provided afterwards) get dropped as malicious. -func TestFullInvalidNumberAnnouncement(t *testing.T) { testInvalidNumberAnnouncement(t, false) } -func TestLightInvalidNumberAnnouncement(t *testing.T) { testInvalidNumberAnnouncement(t, true) } - -func testInvalidNumberAnnouncement(t *testing.T, light bool) { - // Create a single block to import and check numbers against - hashes, blocks := makeChain(1, 0, genesis) - - tester := newTester(light) - badHeaderFetcher := tester.makeHeaderFetcher("bad", blocks, -gatherSlack) - badBodyFetcher := tester.makeBodyFetcher("bad", blocks, 0) - - imported := make(chan interface{}) - announced := make(chan interface{}, 2) - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { - if light { - if header == nil { - t.Fatalf("Fetcher try to import empty header") - } - imported <- header - } else { - if block == nil { - t.Fatalf("Fetcher try to import empty block") - } - imported <- block - } - } - // Announce a block with a bad number, check for immediate drop - tester.fetcher.announceChangeHook = func(hash common.Hash, b bool) { - announced <- nil - } - tester.fetcher.Notify("bad", hashes[0], 2, time.Now().Add(-arriveTimeout), badHeaderFetcher, badBodyFetcher) - verifyAnnounce := func() { - for i := 0; i < 2; i++ { - select { - case <-announced: - continue - case <-time.After(1 * time.Second): - t.Fatal("announce timeout") - return - } - } - } - verifyAnnounce() - verifyImportEvent(t, imported, false) - tester.lock.RLock() - dropped := tester.drops["bad"] - tester.lock.RUnlock() - - if !dropped { - t.Fatalf("peer with invalid numbered announcement not dropped") - } - goodHeaderFetcher := tester.makeHeaderFetcher("good", blocks, -gatherSlack) - goodBodyFetcher := tester.makeBodyFetcher("good", blocks, 0) - // Make sure a good announcement passes without a drop - tester.fetcher.Notify("good", hashes[0], 1, time.Now().Add(-arriveTimeout), goodHeaderFetcher, goodBodyFetcher) - verifyAnnounce() - verifyImportEvent(t, imported, true) - - tester.lock.RLock() - dropped = tester.drops["good"] - tester.lock.RUnlock() - - if dropped { - t.Fatalf("peer with valid numbered announcement dropped") - } - verifyImportDone(t, imported) -} - -// Tests that if a block is empty (i.e. header only), no body request should be -// made, and instead the header should be assembled into a whole block in itself. -func TestEmptyBlockShortCircuit(t *testing.T) { - // Create a chain of blocks to import - hashes, blocks := makeChain(32, 0, genesis) - - tester := newTester(false) - defer tester.fetcher.Stop() - headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) - bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) - - // Add a monitoring hook for all internal events - fetching := make(chan []common.Hash) - tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- hashes } - - completing := make(chan []common.Hash) - tester.fetcher.completingHook = func(hashes []common.Hash) { completing <- hashes } - - imported := make(chan interface{}) - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { - if block == nil { - t.Fatalf("Fetcher try to import empty block") - } - imported <- block - } - // Iteratively announce blocks until all are imported - for i := len(hashes) - 2; i >= 0; i-- { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) - - // All announces should fetch the header - verifyFetchingEvent(t, fetching, true) - - // Only blocks with data contents should request bodies - verifyCompletingEvent(t, completing, len(blocks[hashes[i]].Transactions()) > 0 || len(blocks[hashes[i]].Uncles()) > 0) - - // Irrelevant of the construct, import should succeed - verifyImportEvent(t, imported, true) - } - verifyImportDone(t, imported) -} - -// Tests that a peer is unable to use unbounded memory with sending infinite -// block announcements to a node, but that even in the face of such an attack, -// the fetcher remains operational. -func TestHashMemoryExhaustionAttack(t *testing.T) { - // Create a tester with instrumented import hooks - tester := newTester(false) - - imported, announces := make(chan interface{}), atomic.Int32{} - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { imported <- block } - tester.fetcher.announceChangeHook = func(hash common.Hash, added bool) { - if added { - announces.Add(1) - } else { - announces.Add(-1) - } - } - // Create a valid chain and an infinite junk chain - targetBlocks := hashLimit + 2*maxQueueDist - hashes, blocks := makeChain(targetBlocks, 0, genesis) - validHeaderFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) - validBodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) - - attack, _ := makeChain(targetBlocks, 0, unknownBlock) - attackerHeaderFetcher := tester.makeHeaderFetcher("attacker", nil, -gatherSlack) - attackerBodyFetcher := tester.makeBodyFetcher("attacker", nil, 0) - - // Feed the tester a huge hashset from the attacker, and a limited from the valid peer - for i := 0; i < len(attack); i++ { - if i < maxQueueDist { - tester.fetcher.Notify("valid", hashes[len(hashes)-2-i], uint64(i+1), time.Now(), validHeaderFetcher, validBodyFetcher) - } - tester.fetcher.Notify("attacker", attack[i], 1 /* don't distance drop */, time.Now(), attackerHeaderFetcher, attackerBodyFetcher) - } - if count := announces.Load(); count != hashLimit+maxQueueDist { - t.Fatalf("queued announce count mismatch: have %d, want %d", count, hashLimit+maxQueueDist) - } - // Wait for fetches to complete - verifyImportCount(t, imported, maxQueueDist) - - // Feed the remaining valid hashes to ensure DOS protection state remains clean - for i := len(hashes) - maxQueueDist - 2; i >= 0; i-- { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), validHeaderFetcher, validBodyFetcher) - verifyImportEvent(t, imported, true) - } - verifyImportDone(t, imported) -} - -// Tests that blocks sent to the fetcher (either through propagation or via hash -// announces and retrievals) don't pile up indefinitely, exhausting available -// system memory. -func TestBlockMemoryExhaustionAttack(t *testing.T) { - // Create a tester with instrumented import hooks - tester := newTester(false) - - imported, enqueued := make(chan interface{}), atomic.Int32{} - tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { imported <- block } - tester.fetcher.queueChangeHook = func(hash common.Hash, added bool) { - if added { - enqueued.Add(1) - } else { - enqueued.Add(-1) - } - } - // Create a valid chain and a batch of dangling (but in range) blocks - targetBlocks := hashLimit + 2*maxQueueDist - hashes, blocks := makeChain(targetBlocks, 0, genesis) - attack := make(map[common.Hash]*types.Block) - for i := byte(0); len(attack) < blockLimit+2*maxQueueDist; i++ { - hashes, blocks := makeChain(maxQueueDist-1, i, unknownBlock) - for _, hash := range hashes[:maxQueueDist-2] { - attack[hash] = blocks[hash] - } - } - // Try to feed all the attacker blocks make sure only a limited batch is accepted - for _, block := range attack { - tester.fetcher.Enqueue("attacker", block) - } - time.Sleep(200 * time.Millisecond) - if queued := enqueued.Load(); queued != blockLimit { - t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit) - } - // Queue up a batch of valid blocks, and check that a new peer is allowed to do so - for i := 0; i < maxQueueDist-1; i++ { - tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-3-i]]) - } - time.Sleep(100 * time.Millisecond) - if queued := enqueued.Load(); queued != blockLimit+maxQueueDist-1 { - t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit+maxQueueDist-1) - } - // Insert the missing piece (and sanity check the import) - tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-2]]) - verifyImportCount(t, imported, maxQueueDist) - - // Insert the remaining blocks in chunks to ensure clean DOS protection - for i := maxQueueDist; i < len(hashes)-1; i++ { - tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-2-i]]) - verifyImportEvent(t, imported, true) - } - verifyImportDone(t, imported) -} diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index ea7892d8d84e..18c5ff007a9f 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -107,6 +107,8 @@ var ( txFetcherFetchingHashes = metrics.NewRegisteredGauge("eth/fetcher/transaction/fetching/hashes", nil) ) +var errTerminated = errors.New("terminated") + // txAnnounce is the notification of the availability of a batch // of new transactions in the network. type txAnnounce struct { @@ -783,7 +785,7 @@ func (f *TxFetcher) loop() { // rescheduleWait iterates over all the transactions currently in the waitlist // and schedules the movement into the fetcher for the earliest. // -// The method has a granularity of 'gatherSlack', since there's not much point in +// The method has a granularity of 'txGatherSlack', since there's not much point in // spinning over all the transactions just to maybe find one that should trigger // a few ms earlier. func (f *TxFetcher) rescheduleWait(timer *mclock.Timer, trigger chan struct{}) { @@ -796,7 +798,7 @@ func (f *TxFetcher) rescheduleWait(timer *mclock.Timer, trigger chan struct{}) { for _, instance := range f.waittime { if earliest > instance { earliest = instance - if txArriveTimeout-time.Duration(now-earliest) < gatherSlack { + if txArriveTimeout-time.Duration(now-earliest) < txGatherSlack { break } } @@ -809,7 +811,7 @@ func (f *TxFetcher) rescheduleWait(timer *mclock.Timer, trigger chan struct{}) { // rescheduleTimeout iterates over all the transactions currently in flight and // schedules a cleanup run when the first would trigger. // -// The method has a granularity of 'gatherSlack', since there's not much point in +// The method has a granularity of 'txGatherSlack', since there's not much point in // spinning over all the transactions just to maybe find one that should trigger // a few ms earlier. // @@ -834,7 +836,7 @@ func (f *TxFetcher) rescheduleTimeout(timer *mclock.Timer, trigger chan struct{} } if earliest > req.time { earliest = req.time - if txFetchTimeout-time.Duration(now-earliest) < gatherSlack { + if txFetchTimeout-time.Duration(now-earliest) < txGatherSlack { break } } diff --git a/eth/handler.go b/eth/handler.go index bc27eb4b88c5..a32a04e00b72 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -25,8 +25,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/core/rawdb" @@ -91,7 +89,6 @@ type handlerConfig struct { Database ethdb.Database // Database for direct sync insertions Chain *core.BlockChain // Blockchain to serve data from TxPool txPool // Transaction pool to propagate from - Merger *consensus.Merger // The manager for eth1/2 transition Network uint64 // Network identifier to advertise Sync downloader.SyncMode // Whether to snap or full sync BloomCache uint64 // Megabytes to alloc for snap sync bloom @@ -112,24 +109,20 @@ type handler struct { chain *core.BlockChain maxPeers int - downloader *downloader.Downloader - blockFetcher *fetcher.BlockFetcher - txFetcher *fetcher.TxFetcher - peers *peerSet - merger *consensus.Merger + downloader *downloader.Downloader + txFetcher *fetcher.TxFetcher + peers *peerSet - eventMux *event.TypeMux - txsCh chan core.NewTxsEvent - txsSub event.Subscription - minedBlockSub *event.TypeMuxSubscription + eventMux *event.TypeMux + txsCh chan core.NewTxsEvent + txsSub event.Subscription requiredBlocks map[uint64]common.Hash // channels for fetcher, syncer, txsyncLoop quitSync chan struct{} - chainSync *chainSyncer - wg sync.WaitGroup + wg sync.WaitGroup handlerStartCh chan struct{} handlerDoneCh chan struct{} @@ -150,7 +143,6 @@ func newHandler(config *handlerConfig) (*handler, error) { txpool: config.TxPool, chain: config.Chain, peers: newPeerSet(), - merger: config.Merger, requiredBlocks: config.RequiredBlocks, quitSync: make(chan struct{}), handlerDoneCh: make(chan struct{}), @@ -190,92 +182,6 @@ func newHandler(config *handlerConfig) (*handler, error) { } // Construct the downloader (long sync) h.downloader = downloader.New(config.Database, h.eventMux, h.chain, nil, h.removePeer, h.enableSyncedFeatures) - if ttd := h.chain.Config().TerminalTotalDifficulty; ttd != nil { - if h.chain.Config().TerminalTotalDifficultyPassed { - log.Info("Chain post-merge, sync via beacon client") - } else { - head := h.chain.CurrentBlock() - if td := h.chain.GetTd(head.Hash(), head.Number.Uint64()); td.Cmp(ttd) >= 0 { - log.Info("Chain post-TTD, sync via beacon client") - } else { - log.Warn("Chain pre-merge, sync via PoW (ensure beacon client is ready)") - } - } - } else if h.chain.Config().TerminalTotalDifficultyPassed { - log.Error("Chain configured post-merge, but without TTD. Are you debugging sync?") - } - // Construct the fetcher (short sync) - validator := func(header *types.Header) error { - // All the block fetcher activities should be disabled - // after the transition. Print the warning log. - if h.merger.PoSFinalized() { - log.Warn("Unexpected validation activity", "hash", header.Hash(), "number", header.Number) - return errors.New("unexpected behavior after transition") - } - // Reject all the PoS style headers in the first place. No matter - // the chain has finished the transition or not, the PoS headers - // should only come from the trusted consensus layer instead of - // p2p network. - if beacon, ok := h.chain.Engine().(*beacon.Beacon); ok { - if beacon.IsPoSHeader(header) { - return errors.New("unexpected post-merge header") - } - } - return h.chain.Engine().VerifyHeader(h.chain, header) - } - heighter := func() uint64 { - return h.chain.CurrentBlock().Number.Uint64() - } - inserter := func(blocks types.Blocks) (int, error) { - // All the block fetcher activities should be disabled - // after the transition. Print the warning log. - if h.merger.PoSFinalized() { - var ctx []interface{} - ctx = append(ctx, "blocks", len(blocks)) - if len(blocks) > 0 { - ctx = append(ctx, "firsthash", blocks[0].Hash()) - ctx = append(ctx, "firstnumber", blocks[0].Number()) - ctx = append(ctx, "lasthash", blocks[len(blocks)-1].Hash()) - ctx = append(ctx, "lastnumber", blocks[len(blocks)-1].Number()) - } - log.Warn("Unexpected insertion activity", ctx...) - return 0, errors.New("unexpected behavior after transition") - } - // If snap sync is running, deny importing weird blocks. This is a problematic - // clause when starting up a new network, because snap-syncing miners might not - // accept each others' blocks until a restart. Unfortunately we haven't figured - // out a way yet where nodes can decide unilaterally whether the network is new - // or not. This should be fixed if we figure out a solution. - if !h.synced.Load() { - log.Warn("Syncing, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) - return 0, nil - } - if h.merger.TDDReached() { - // The blocks from the p2p network is regarded as untrusted - // after the transition. In theory block gossip should be disabled - // entirely whenever the transition is started. But in order to - // handle the transition boundary reorg in the consensus-layer, - // the legacy blocks are still accepted, but only for the terminal - // pow blocks. Spec: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3675.md#halt-the-importing-of-pow-blocks - for i, block := range blocks { - ptd := h.chain.GetTd(block.ParentHash(), block.NumberU64()-1) - if ptd == nil { - return 0, nil - } - td := new(big.Int).Add(ptd, block.Difficulty()) - if !h.chain.Config().IsTerminalPoWBlock(ptd, td) { - log.Info("Filtered out non-terminal pow block", "number", block.NumberU64(), "hash", block.Hash()) - return 0, nil - } - if err := h.chain.InsertBlockWithoutSetHead(block); err != nil { - return i, err - } - } - return 0, nil - } - return h.chain.InsertChain(blocks) - } - h.blockFetcher = fetcher.NewBlockFetcher(false, nil, h.chain.GetBlockByHash, validator, h.BroadcastBlock, heighter, nil, inserter, h.removePeer) fetchTx := func(peer string, hashes []common.Hash) error { p := h.peers.peer(peer) @@ -288,7 +194,6 @@ func newHandler(config *handlerConfig) (*handler, error) { return h.txpool.Add(txs, false, false) } h.txFetcher = fetcher.NewTxFetcher(h.txpool.Has, addTxs, fetchTx, h.removePeer) - h.chainSync = newChainSyncer(h) return h, nil } @@ -398,8 +303,6 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { return err } } - h.chainSync.handlePeerEvent() - // Propagate existing transactions. new transactions appearing // after this will be sent via broadcasts. h.syncTransactions(peer) @@ -526,14 +429,8 @@ func (h *handler) Start(maxPeers int) { h.txsSub = h.txpool.SubscribeTransactions(h.txsCh, false) go h.txBroadcastLoop() - // broadcast mined blocks - h.wg.Add(1) - h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{}) - go h.minedBroadcastLoop() - // start sync handlers - h.wg.Add(1) - go h.chainSync.loop() + h.txFetcher.Start() // start peer handler tracker h.wg.Add(1) @@ -541,8 +438,9 @@ func (h *handler) Start(maxPeers int) { } func (h *handler) Stop() { - h.txsSub.Unsubscribe() // quits txBroadcastLoop - h.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop + h.txsSub.Unsubscribe() // quits txBroadcastLoop + h.txFetcher.Stop() + h.downloader.Terminate() // Quit chainSync and txsync64. // After this is done, no new peers will be accepted. @@ -558,50 +456,6 @@ func (h *handler) Stop() { log.Info("Ethereum protocol stopped") } -// BroadcastBlock will either propagate a block to a subset of its peers, or -// will only announce its availability (depending what's requested). -func (h *handler) BroadcastBlock(block *types.Block, propagate bool) { - // Disable the block propagation if the chain has already entered the PoS - // stage. The block propagation is delegated to the consensus layer. - if h.merger.PoSFinalized() { - return - } - // Disable the block propagation if it's the post-merge block. - if beacon, ok := h.chain.Engine().(*beacon.Beacon); ok { - if beacon.IsPoSHeader(block.Header()) { - return - } - } - hash := block.Hash() - peers := h.peers.peersWithoutBlock(hash) - - // If propagation is requested, send to a subset of the peer - if propagate { - // Calculate the TD of the block (it's not imported yet, so block.Td is not valid) - var td *big.Int - if parent := h.chain.GetBlock(block.ParentHash(), block.NumberU64()-1); parent != nil { - td = new(big.Int).Add(block.Difficulty(), h.chain.GetTd(block.ParentHash(), block.NumberU64()-1)) - } else { - log.Error("Propagating dangling block", "number", block.Number(), "hash", hash) - return - } - // Send the block to a subset of our peers - transfer := peers[:int(math.Sqrt(float64(len(peers))))] - for _, peer := range transfer { - peer.AsyncSendNewBlock(block, td) - } - log.Trace("Propagated block", "hash", hash, "recipients", len(transfer), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) - return - } - // Otherwise if the block is indeed in out own chain, announce it - if h.chain.HasBlock(hash, block.NumberU64()) { - for _, peer := range peers { - peer.AsyncSendNewBlockHash(block) - } - log.Trace("Announced block", "hash", hash, "recipients", len(peers), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) - } -} - // BroadcastTransactions will propagate a batch of transactions // - To a square root of all peers for non-blob transactions // - And, separately, as announcements to all peers which are not known to @@ -684,18 +538,6 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { "bcastpeers", directPeers, "bcastcount", directCount, "annpeers", annPeers, "anncount", annCount) } -// minedBroadcastLoop sends mined blocks to connected peers. -func (h *handler) minedBroadcastLoop() { - defer h.wg.Done() - - for obj := range h.minedBlockSub.Chan() { - if ev, ok := obj.Data.(core.NewMinedBlockEvent); ok { - h.BroadcastBlock(ev.Block, true) // First propagate block to peers - h.BroadcastBlock(ev.Block, false) // Only then announce to the rest - } - } -} - // txBroadcastLoop announces new transactions to connected peers. func (h *handler) txBroadcastLoop() { defer h.wg.Done() diff --git a/eth/handler_eth.go b/eth/handler_eth.go index f1284c10e637..b2cd52a22105 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -19,10 +19,7 @@ package eth import ( "errors" "fmt" - "math/big" - "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/protocols/eth" @@ -60,13 +57,6 @@ func (h *ethHandler) AcceptTxs() bool { func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error { // Consume any broadcasts and announces, forwarding the rest to the downloader switch packet := packet.(type) { - case *eth.NewBlockHashesPacket: - hashes, numbers := packet.Unpack() - return h.handleBlockAnnounces(peer, hashes, numbers) - - case *eth.NewBlockPacket: - return h.handleBlockBroadcast(peer, packet.Block, packet.TD) - case *eth.NewPooledTransactionHashesPacket: return h.txFetcher.Notify(peer.ID(), packet.Types, packet.Sizes, packet.Hashes) @@ -85,55 +75,3 @@ func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error { return fmt.Errorf("unexpected eth packet type: %T", packet) } } - -// handleBlockAnnounces is invoked from a peer's message handler when it transmits a -// batch of block announcements for the local node to process. -func (h *ethHandler) handleBlockAnnounces(peer *eth.Peer, hashes []common.Hash, numbers []uint64) error { - // Drop all incoming block announces from the p2p network if - // the chain already entered the pos stage and disconnect the - // remote peer. - if h.merger.PoSFinalized() { - return errors.New("disallowed block announcement") - } - // Schedule all the unknown hashes for retrieval - var ( - unknownHashes = make([]common.Hash, 0, len(hashes)) - unknownNumbers = make([]uint64, 0, len(numbers)) - ) - for i := 0; i < len(hashes); i++ { - if !h.chain.HasBlock(hashes[i], numbers[i]) { - unknownHashes = append(unknownHashes, hashes[i]) - unknownNumbers = append(unknownNumbers, numbers[i]) - } - } - for i := 0; i < len(unknownHashes); i++ { - h.blockFetcher.Notify(peer.ID(), unknownHashes[i], unknownNumbers[i], time.Now(), peer.RequestOneHeader, peer.RequestBodies) - } - return nil -} - -// handleBlockBroadcast is invoked from a peer's message handler when it transmits a -// block broadcast for the local node to process. -func (h *ethHandler) handleBlockBroadcast(peer *eth.Peer, block *types.Block, td *big.Int) error { - // Drop all incoming block announces from the p2p network if - // the chain already entered the pos stage and disconnect the - // remote peer. - if h.merger.PoSFinalized() { - return errors.New("disallowed block broadcast") - } - // Schedule the block for import - h.blockFetcher.Enqueue(peer.ID(), block) - - // Assuming the block is importable by the peer, but possibly not yet done so, - // calculate the head hash and TD that the peer truly must have. - var ( - trueHead = block.ParentHash() - trueTD = new(big.Int).Sub(td, block.Difficulty()) - ) - // Update the peer's total difficulty if better than the previous - if _, td := peer.Head(); trueTD.Cmp(td) > 0 { - peer.SetHead(trueHead, trueTD) - h.chainSync.handlePeerEvent() - } - return nil -} diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 579ca3c09735..297a6bf154ed 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -23,7 +23,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" @@ -109,7 +108,6 @@ func testForkIDSplit(t *testing.T, protocol uint) { Database: dbNoFork, Chain: chainNoFork, TxPool: newTestTxPool(), - Merger: consensus.NewMerger(rawdb.NewMemoryDatabase()), Network: 1, Sync: downloader.FullSync, BloomCache: 1, @@ -118,7 +116,6 @@ func testForkIDSplit(t *testing.T, protocol uint) { Database: dbProFork, Chain: chainProFork, TxPool: newTestTxPool(), - Merger: consensus.NewMerger(rawdb.NewMemoryDatabase()), Network: 1, Sync: downloader.FullSync, BloomCache: 1, @@ -441,159 +438,3 @@ func testTransactionPropagation(t *testing.T, protocol uint) { } } } - -// Tests that blocks are broadcast to a sqrt number of peers only. -func TestBroadcastBlock1Peer(t *testing.T) { testBroadcastBlock(t, 1, 1) } -func TestBroadcastBlock2Peers(t *testing.T) { testBroadcastBlock(t, 2, 1) } -func TestBroadcastBlock3Peers(t *testing.T) { testBroadcastBlock(t, 3, 1) } -func TestBroadcastBlock4Peers(t *testing.T) { testBroadcastBlock(t, 4, 2) } -func TestBroadcastBlock5Peers(t *testing.T) { testBroadcastBlock(t, 5, 2) } -func TestBroadcastBlock8Peers(t *testing.T) { testBroadcastBlock(t, 9, 3) } -func TestBroadcastBlock12Peers(t *testing.T) { testBroadcastBlock(t, 12, 3) } -func TestBroadcastBlock16Peers(t *testing.T) { testBroadcastBlock(t, 16, 4) } -func TestBroadcastBloc26Peers(t *testing.T) { testBroadcastBlock(t, 26, 5) } -func TestBroadcastBlock100Peers(t *testing.T) { testBroadcastBlock(t, 100, 10) } - -func testBroadcastBlock(t *testing.T, peers, bcasts int) { - t.Parallel() - - // Create a source handler to broadcast blocks from and a number of sinks - // to receive them. - source := newTestHandlerWithBlocks(1) - defer source.close() - - sinks := make([]*testEthHandler, peers) - for i := 0; i < len(sinks); i++ { - sinks[i] = new(testEthHandler) - } - // Interconnect all the sink handlers with the source handler - var ( - genesis = source.chain.Genesis() - td = source.chain.GetTd(genesis.Hash(), genesis.NumberU64()) - ) - for i, sink := range sinks { - sink := sink // Closure for gorotuine below - - sourcePipe, sinkPipe := p2p.MsgPipe() - defer sourcePipe.Close() - defer sinkPipe.Close() - - sourcePeer := eth.NewPeer(eth.ETH68, p2p.NewPeerPipe(enode.ID{byte(i)}, "", nil, sourcePipe), sourcePipe, nil) - sinkPeer := eth.NewPeer(eth.ETH68, p2p.NewPeerPipe(enode.ID{0}, "", nil, sinkPipe), sinkPipe, nil) - defer sourcePeer.Close() - defer sinkPeer.Close() - - go source.handler.runEthPeer(sourcePeer, func(peer *eth.Peer) error { - return eth.Handle((*ethHandler)(source.handler), peer) - }) - if err := sinkPeer.Handshake(1, td, genesis.Hash(), genesis.Hash(), forkid.NewIDWithChain(source.chain), forkid.NewFilter(source.chain)); err != nil { - t.Fatalf("failed to run protocol handshake") - } - go eth.Handle(sink, sinkPeer) - } - // Subscribe to all the transaction pools - blockChs := make([]chan *types.Block, len(sinks)) - for i := 0; i < len(sinks); i++ { - blockChs[i] = make(chan *types.Block, 1) - defer close(blockChs[i]) - - sub := sinks[i].blockBroadcasts.Subscribe(blockChs[i]) - defer sub.Unsubscribe() - } - // Initiate a block propagation across the peers - time.Sleep(100 * time.Millisecond) - header := source.chain.CurrentBlock() - source.handler.BroadcastBlock(source.chain.GetBlock(header.Hash(), header.Number.Uint64()), true) - - // Iterate through all the sinks and ensure the correct number got the block - done := make(chan struct{}, peers) - for _, ch := range blockChs { - ch := ch - go func() { - <-ch - done <- struct{}{} - }() - } - var received int - for { - select { - case <-done: - received++ - - case <-time.After(100 * time.Millisecond): - if received != bcasts { - t.Errorf("broadcast count mismatch: have %d, want %d", received, bcasts) - } - return - } - } -} - -// Tests that a propagated malformed block (uncles or transactions don't match -// with the hashes in the header) gets discarded and not broadcast forward. -func TestBroadcastMalformedBlock68(t *testing.T) { testBroadcastMalformedBlock(t, eth.ETH68) } - -func testBroadcastMalformedBlock(t *testing.T, protocol uint) { - t.Parallel() - - // Create a source handler to broadcast blocks from and a number of sinks - // to receive them. - source := newTestHandlerWithBlocks(1) - defer source.close() - - // Create a source handler to send messages through and a sink peer to receive them - p2pSrc, p2pSink := p2p.MsgPipe() - defer p2pSrc.Close() - defer p2pSink.Close() - - src := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pSrc), p2pSrc, source.txpool) - sink := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pSink), p2pSink, source.txpool) - defer src.Close() - defer sink.Close() - - go source.handler.runEthPeer(src, func(peer *eth.Peer) error { - return eth.Handle((*ethHandler)(source.handler), peer) - }) - // Run the handshake locally to avoid spinning up a sink handler - var ( - genesis = source.chain.Genesis() - td = source.chain.GetTd(genesis.Hash(), genesis.NumberU64()) - ) - if err := sink.Handshake(1, td, genesis.Hash(), genesis.Hash(), forkid.NewIDWithChain(source.chain), forkid.NewFilter(source.chain)); err != nil { - t.Fatalf("failed to run protocol handshake") - } - // After the handshake completes, the source handler should stream the sink - // the blocks, subscribe to inbound network events - backend := new(testEthHandler) - - blocks := make(chan *types.Block, 1) - sub := backend.blockBroadcasts.Subscribe(blocks) - defer sub.Unsubscribe() - - go eth.Handle(backend, sink) - - // Create various combinations of malformed blocks - head := source.chain.CurrentBlock() - block := source.chain.GetBlock(head.Hash(), head.Number.Uint64()) - - malformedUncles := head - malformedUncles.UncleHash[0]++ - malformedTransactions := head - malformedTransactions.TxHash[0]++ - malformedEverything := head - malformedEverything.UncleHash[0]++ - malformedEverything.TxHash[0]++ - - // Try to broadcast all malformations and ensure they all get discarded - for _, header := range []*types.Header{malformedUncles, malformedTransactions, malformedEverything} { - block := types.NewBlockWithHeader(header).WithBody(block.Transactions(), block.Uncles()) - if err := src.SendNewBlock(block, big.NewInt(131136)); err != nil { - t.Fatalf("failed to broadcast block: %v", err) - } - select { - case <-blocks: - t.Fatalf("malformed block forwarded") - case <-time.After(100 * time.Millisecond): - } - } -} diff --git a/eth/handler_test.go b/eth/handler_test.go index 58353f6b6452..bcc8ea30e415 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -22,7 +22,6 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -164,7 +163,6 @@ func newTestHandlerWithBlocks(blocks int) *testHandler { Database: db, Chain: chain, TxPool: txpool, - Merger: consensus.NewMerger(rawdb.NewMemoryDatabase()), Network: 1, Sync: downloader.SnapSync, BloomCache: 1, diff --git a/eth/peerset.go b/eth/peerset.go index c56a7223e964..6b0aff226c1c 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -19,7 +19,6 @@ package eth import ( "errors" "fmt" - "math/big" "sync" "github.com/ethereum/go-ethereum/common" @@ -192,21 +191,6 @@ func (ps *peerSet) peer(id string) *ethPeer { return ps.peers[id] } -// peersWithoutBlock retrieves a list of peers that do not have a given block in -// their set of known hashes so it might be propagated to them. -func (ps *peerSet) peersWithoutBlock(hash common.Hash) []*ethPeer { - ps.lock.RLock() - defer ps.lock.RUnlock() - - list := make([]*ethPeer, 0, len(ps.peers)) - for _, p := range ps.peers { - if !p.KnownBlock(hash) { - list = append(list, p) - } - } - return list -} - // peersWithoutTransaction retrieves a list of peers that do not have a given // transaction in their set of known hashes. func (ps *peerSet) peersWithoutTransaction(hash common.Hash) []*ethPeer { @@ -240,24 +224,6 @@ func (ps *peerSet) snapLen() int { return ps.snapPeers } -// peerWithHighestTD retrieves the known peer with the currently highest total -// difficulty, but below the given PoS switchover threshold. -func (ps *peerSet) peerWithHighestTD() *eth.Peer { - ps.lock.RLock() - defer ps.lock.RUnlock() - - var ( - bestPeer *eth.Peer - bestTd *big.Int - ) - for _, p := range ps.peers { - if _, td := p.Head(); bestPeer == nil || td.Cmp(bestTd) > 0 { - bestPeer, bestTd = p.Peer, td - } - } - return bestPeer -} - // close disconnects all peers. func (ps *peerSet) close() { ps.lock.Lock() diff --git a/eth/protocols/eth/broadcast.go b/eth/protocols/eth/broadcast.go index ad5395cb8dd9..f0ed1d6bc9a0 100644 --- a/eth/protocols/eth/broadcast.go +++ b/eth/protocols/eth/broadcast.go @@ -17,8 +17,6 @@ package eth import ( - "math/big" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -29,37 +27,6 @@ const ( maxTxPacketSize = 100 * 1024 ) -// blockPropagation is a block propagation event, waiting for its turn in the -// broadcast queue. -type blockPropagation struct { - block *types.Block - td *big.Int -} - -// broadcastBlocks is a write loop that multiplexes blocks and block announcements -// to the remote peer. The goal is to have an async writer that does not lock up -// node internals and at the same time rate limits queued data. -func (p *Peer) broadcastBlocks() { - for { - select { - case prop := <-p.queuedBlocks: - if err := p.SendNewBlock(prop.block, prop.td); err != nil { - return - } - p.Log().Trace("Propagated block", "number", prop.block.Number(), "hash", prop.block.Hash(), "td", prop.td) - - case block := <-p.queuedBlockAnns: - if err := p.SendNewBlockHashes([]common.Hash{block.Hash()}, []uint64{block.NumberU64()}); err != nil { - return - } - p.Log().Trace("Announced block", "number", block.Number(), "hash", block.Hash()) - - case <-p.term: - return - } - } -} - // broadcastTransactions is a write loop that schedules transaction broadcasts // to the remote peer. The goal is to have an async writer that does not lock up // node internals and at the same time rate limits queued data. diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 0275708a6cd5..96656afb1b20 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -18,6 +18,7 @@ package eth import ( "encoding/json" + "errors" "fmt" "github.com/ethereum/go-ethereum/common" @@ -274,43 +275,11 @@ func ServiceGetReceiptsQuery(chain *core.BlockChain, query GetReceiptsRequest) [ } func handleNewBlockhashes(backend Backend, msg Decoder, peer *Peer) error { - // A batch of new block announcements just arrived - ann := new(NewBlockHashesPacket) - if err := msg.Decode(ann); err != nil { - return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) - } - // Mark the hashes as present at the remote node - for _, block := range *ann { - peer.markBlock(block.Hash) - } - // Deliver them all to the backend for queuing - return backend.Handle(peer, ann) + return errors.New("block announcements disallowed") // We dropped support for non-merge networks } func handleNewBlock(backend Backend, msg Decoder, peer *Peer) error { - // Retrieve and decode the propagated block - ann := new(NewBlockPacket) - if err := msg.Decode(ann); err != nil { - return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) - } - if err := ann.sanityCheck(); err != nil { - return err - } - if hash := types.CalcUncleHash(ann.Block.Uncles()); hash != ann.Block.UncleHash() { - log.Warn("Propagated block has invalid uncles", "have", hash, "exp", ann.Block.UncleHash()) - return nil // TODO(karalabe): return error eventually, but wait a few releases - } - if hash := types.DeriveSha(ann.Block.Transactions(), trie.NewStackTrie(nil)); hash != ann.Block.TxHash() { - log.Warn("Propagated block has invalid body", "have", hash, "exp", ann.Block.TxHash()) - return nil // TODO(karalabe): return error eventually, but wait a few releases - } - ann.Block.ReceivedAt = msg.Time() - ann.Block.ReceivedFrom = peer - - // Mark the peer as owning the block - peer.markBlock(ann.Block.Hash()) - - return backend.Handle(peer, ann) + return errors.New("block broadcasts disallowed") // We dropped support for non-merge networks } func handleBlockHeaders(backend Backend, msg Decoder, peer *Peer) error { diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index ffd78b05946a..94f28f240f86 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -33,10 +33,6 @@ const ( // before starting to randomly evict them. maxKnownTxs = 32768 - // maxKnownBlocks is the maximum block hashes to keep in the known list - // before starting to randomly evict them. - maxKnownBlocks = 1024 - // maxQueuedTxs is the maximum number of transactions to queue up before dropping // older broadcasts. maxQueuedTxs = 4096 @@ -44,16 +40,6 @@ const ( // maxQueuedTxAnns is the maximum number of transaction announcements to queue up // before dropping older announcements. maxQueuedTxAnns = 4096 - - // maxQueuedBlocks is the maximum number of block propagations to queue up before - // dropping broadcasts. There's not much point in queueing stale blocks, so a few - // that might cover uncles should be enough. - maxQueuedBlocks = 4 - - // maxQueuedBlockAnns is the maximum number of block announcements to queue up before - // dropping broadcasts. Similarly to block propagations, there's no point to queue - // above some healthy uncle limit, so use that. - maxQueuedBlockAnns = 4 ) // max is a helper function which returns the larger of the two given integers. @@ -75,10 +61,6 @@ type Peer struct { head common.Hash // Latest advertised head block hash td *big.Int // Latest advertised head block total difficulty - knownBlocks *knownCache // Set of block hashes known to be known by this peer - queuedBlocks chan *blockPropagation // Queue of blocks to broadcast to the peer - queuedBlockAnns chan *types.Block // Queue of blocks to announce to the peer - txpool TxPool // Transaction pool used by the broadcasters for liveness checks knownTxs *knownCache // Set of transaction hashes known to be known by this peer txBroadcast chan []common.Hash // Channel used to queue transaction propagation requests @@ -96,24 +78,20 @@ type Peer struct { // version. func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter, txpool TxPool) *Peer { peer := &Peer{ - id: p.ID().String(), - Peer: p, - rw: rw, - version: version, - knownTxs: newKnownCache(maxKnownTxs), - knownBlocks: newKnownCache(maxKnownBlocks), - queuedBlocks: make(chan *blockPropagation, maxQueuedBlocks), - queuedBlockAnns: make(chan *types.Block, maxQueuedBlockAnns), - txBroadcast: make(chan []common.Hash), - txAnnounce: make(chan []common.Hash), - reqDispatch: make(chan *request), - reqCancel: make(chan *cancel), - resDispatch: make(chan *response), - txpool: txpool, - term: make(chan struct{}), + id: p.ID().String(), + Peer: p, + rw: rw, + version: version, + knownTxs: newKnownCache(maxKnownTxs), + txBroadcast: make(chan []common.Hash), + txAnnounce: make(chan []common.Hash), + reqDispatch: make(chan *request), + reqCancel: make(chan *cancel), + resDispatch: make(chan *response), + txpool: txpool, + term: make(chan struct{}), } // Start up all the broadcasters - go peer.broadcastBlocks() go peer.broadcastTransactions() go peer.announceTransactions() go peer.dispatcher() @@ -156,23 +134,11 @@ func (p *Peer) SetHead(hash common.Hash, td *big.Int) { p.td.Set(td) } -// KnownBlock returns whether peer is known to already have a block. -func (p *Peer) KnownBlock(hash common.Hash) bool { - return p.knownBlocks.Contains(hash) -} - // KnownTransaction returns whether peer is known to already have a transaction. func (p *Peer) KnownTransaction(hash common.Hash) bool { return p.knownTxs.Contains(hash) } -// markBlock marks a block as known for the peer, ensuring that the block will -// never be propagated to this particular peer. -func (p *Peer) markBlock(hash common.Hash) { - // If we reached the memory allowance, drop a previously known block hash - p.knownBlocks.Add(hash) -} - // markTransaction marks a transaction as known for the peer, ensuring that it // will never be propagated to this particular peer. func (p *Peer) markTransaction(hash common.Hash) { @@ -248,55 +214,6 @@ func (p *Peer) ReplyPooledTransactionsRLP(id uint64, hashes []common.Hash, txs [ }) } -// SendNewBlockHashes announces the availability of a number of blocks through -// a hash notification. -func (p *Peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error { - // Mark all the block hashes as known, but ensure we don't overflow our limits - p.knownBlocks.Add(hashes...) - - request := make(NewBlockHashesPacket, len(hashes)) - for i := 0; i < len(hashes); i++ { - request[i].Hash = hashes[i] - request[i].Number = numbers[i] - } - return p2p.Send(p.rw, NewBlockHashesMsg, request) -} - -// AsyncSendNewBlockHash queues the availability of a block for propagation to a -// remote peer. If the peer's broadcast queue is full, the event is silently -// dropped. -func (p *Peer) AsyncSendNewBlockHash(block *types.Block) { - select { - case p.queuedBlockAnns <- block: - // Mark all the block hash as known, but ensure we don't overflow our limits - p.knownBlocks.Add(block.Hash()) - default: - p.Log().Debug("Dropping block announcement", "number", block.NumberU64(), "hash", block.Hash()) - } -} - -// SendNewBlock propagates an entire block to a remote peer. -func (p *Peer) SendNewBlock(block *types.Block, td *big.Int) error { - // Mark all the block hash as known, but ensure we don't overflow our limits - p.knownBlocks.Add(block.Hash()) - return p2p.Send(p.rw, NewBlockMsg, &NewBlockPacket{ - Block: block, - TD: td, - }) -} - -// AsyncSendNewBlock queues an entire block for propagation to a remote peer. If -// the peer's broadcast queue is full, the event is silently dropped. -func (p *Peer) AsyncSendNewBlock(block *types.Block, td *big.Int) { - select { - case p.queuedBlocks <- &blockPropagation{block: block, td: td}: - // Mark all the block hash as known, but ensure we don't overflow our limits - p.knownBlocks.Add(block.Hash()) - default: - p.Log().Debug("Dropping block propagation", "number", block.NumberU64(), "hash", block.Hash()) - } -} - // ReplyBlockHeadersRLP is the response to GetBlockHeaders. func (p *Peer) ReplyBlockHeadersRLP(id uint64, headers []rlp.RawValue) error { return p2p.Send(p.rw, BlockHeadersMsg, &BlockHeadersRLPPacket{ diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index 47e8d97244cb..c5cb2dd1dca4 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -189,19 +189,6 @@ type NewBlockPacket struct { TD *big.Int } -// sanityCheck verifies that the values are reasonable, as a DoS protection -func (request *NewBlockPacket) sanityCheck() error { - if err := request.Block.SanityCheck(); err != nil { - return err - } - //TD at mainnet block #7753254 is 76 bits. If it becomes 100 million times - // larger, it will still fit within 100 bits - if tdlen := request.TD.BitLen(); tdlen > 100 { - return fmt.Errorf("too large block TD: bitlen %d", tdlen) - } - return nil -} - // GetBlockBodiesRequest represents a block body query. type GetBlockBodiesRequest []common.Hash diff --git a/eth/sync.go b/eth/sync.go index cdcfbdb3db49..61f2b2b376cd 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -17,21 +17,9 @@ package eth import ( - "errors" - "math/big" - "time" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool" - "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/protocols/eth" - "github.com/ethereum/go-ethereum/log" -) - -const ( - forceSyncCycle = 10 * time.Second // Time interval to force syncs, even if few peers are available - defaultMinSyncPeers = 5 // Amount of peers desired to start syncing ) // syncTransactions starts sending all currently pending transactions to the given peer. @@ -47,206 +35,3 @@ func (h *handler) syncTransactions(p *eth.Peer) { } p.AsyncSendPooledTransactionHashes(hashes) } - -// chainSyncer coordinates blockchain sync components. -type chainSyncer struct { - handler *handler - force *time.Timer - forced bool // true when force timer fired - warned time.Time - peerEventCh chan struct{} - doneCh chan error // non-nil when sync is running -} - -// chainSyncOp is a scheduled sync operation. -type chainSyncOp struct { - mode downloader.SyncMode - peer *eth.Peer - td *big.Int - head common.Hash -} - -// newChainSyncer creates a chainSyncer. -func newChainSyncer(handler *handler) *chainSyncer { - return &chainSyncer{ - handler: handler, - peerEventCh: make(chan struct{}), - } -} - -// handlePeerEvent notifies the syncer about a change in the peer set. -// This is called for new peers and every time a peer announces a new -// chain head. -func (cs *chainSyncer) handlePeerEvent() bool { - select { - case cs.peerEventCh <- struct{}{}: - return true - case <-cs.handler.quitSync: - return false - } -} - -// loop runs in its own goroutine and launches the sync when necessary. -func (cs *chainSyncer) loop() { - defer cs.handler.wg.Done() - - cs.handler.blockFetcher.Start() - cs.handler.txFetcher.Start() - defer cs.handler.blockFetcher.Stop() - defer cs.handler.txFetcher.Stop() - defer cs.handler.downloader.Terminate() - - // The force timer lowers the peer count threshold down to one when it fires. - // This ensures we'll always start sync even if there aren't enough peers. - cs.force = time.NewTimer(forceSyncCycle) - defer cs.force.Stop() - - for { - if op := cs.nextSyncOp(); op != nil { - cs.startSync(op) - } - select { - case <-cs.peerEventCh: - // Peer information changed, recheck. - case err := <-cs.doneCh: - cs.doneCh = nil - cs.force.Reset(forceSyncCycle) - cs.forced = false - - // If we've reached the merge transition but no beacon client is available, or - // it has not yet switched us over, keep warning the user that their infra is - // potentially flaky. - if errors.Is(err, downloader.ErrMergeTransition) && time.Since(cs.warned) > 10*time.Second { - log.Warn("Local chain is post-merge, waiting for beacon client sync switch-over...") - cs.warned = time.Now() - } - case <-cs.force.C: - cs.forced = true - - case <-cs.handler.quitSync: - // Disable all insertion on the blockchain. This needs to happen before - // terminating the downloader because the downloader waits for blockchain - // inserts, and these can take a long time to finish. - cs.handler.chain.StopInsert() - cs.handler.downloader.Terminate() - if cs.doneCh != nil { - <-cs.doneCh - } - return - } - } -} - -// nextSyncOp determines whether sync is required at this time. -func (cs *chainSyncer) nextSyncOp() *chainSyncOp { - if cs.doneCh != nil { - return nil // Sync already running - } - // If a beacon client once took over control, disable the entire legacy sync - // path from here on end. Note, there is a slight "race" between reaching TTD - // and the beacon client taking over. The downloader will enforce that nothing - // above the first TTD will be delivered to the chain for import. - // - // An alternative would be to check the local chain for exceeding the TTD and - // avoid triggering a sync in that case, but that could also miss sibling or - // other family TTD block being accepted. - if cs.handler.chain.Config().TerminalTotalDifficultyPassed || cs.handler.merger.TDDReached() { - return nil - } - // Ensure we're at minimum peer count. - minPeers := defaultMinSyncPeers - if cs.forced { - minPeers = 1 - } else if minPeers > cs.handler.maxPeers { - minPeers = cs.handler.maxPeers - } - if cs.handler.peers.len() < minPeers { - return nil - } - // We have enough peers, pick the one with the highest TD, but avoid going - // over the terminal total difficulty. Above that we expect the consensus - // clients to direct the chain head to sync to. - peer := cs.handler.peers.peerWithHighestTD() - if peer == nil { - return nil - } - mode, ourTD := cs.modeAndLocalHead() - op := peerToSyncOp(mode, peer) - if op.td.Cmp(ourTD) <= 0 { - // We seem to be in sync according to the legacy rules. In the merge - // world, it can also mean we're stuck on the merge block, waiting for - // a beacon client. In the latter case, notify the user. - if ttd := cs.handler.chain.Config().TerminalTotalDifficulty; ttd != nil && ourTD.Cmp(ttd) >= 0 && time.Since(cs.warned) > 10*time.Second { - log.Warn("Local chain is post-merge, waiting for beacon client sync switch-over...") - cs.warned = time.Now() - } - return nil // We're in sync - } - return op -} - -func peerToSyncOp(mode downloader.SyncMode, p *eth.Peer) *chainSyncOp { - peerHead, peerTD := p.Head() - return &chainSyncOp{mode: mode, peer: p, td: peerTD, head: peerHead} -} - -func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) { - // If we're in snap sync mode, return that directly - if cs.handler.snapSync.Load() { - block := cs.handler.chain.CurrentSnapBlock() - td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64()) - return downloader.SnapSync, td - } - // We are probably in full sync, but we might have rewound to before the - // snap sync pivot, check if we should re-enable snap sync. - head := cs.handler.chain.CurrentBlock() - if pivot := rawdb.ReadLastPivotNumber(cs.handler.database); pivot != nil { - if head.Number.Uint64() < *pivot { - block := cs.handler.chain.CurrentSnapBlock() - td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64()) - return downloader.SnapSync, td - } - } - // We are in a full sync, but the associated head state is missing. To complete - // the head state, forcefully rerun the snap sync. Note it doesn't mean the - // persistent state is corrupted, just mismatch with the head block. - if !cs.handler.chain.HasState(head.Root) { - block := cs.handler.chain.CurrentSnapBlock() - td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64()) - log.Info("Reenabled snap sync as chain is stateless") - return downloader.SnapSync, td - } - // Nope, we're really full syncing - td := cs.handler.chain.GetTd(head.Hash(), head.Number.Uint64()) - return downloader.FullSync, td -} - -// startSync launches doSync in a new goroutine. -func (cs *chainSyncer) startSync(op *chainSyncOp) { - cs.doneCh = make(chan error, 1) - go func() { cs.doneCh <- cs.handler.doSync(op) }() -} - -// doSync synchronizes the local blockchain with a remote peer. -func (h *handler) doSync(op *chainSyncOp) error { - // Run the sync cycle, and disable snap sync if we're past the pivot block - err := h.downloader.LegacySync(op.peer.ID(), op.head, op.td, h.chain.Config().TerminalTotalDifficulty, op.mode) - if err != nil { - return err - } - h.enableSyncedFeatures() - - head := h.chain.CurrentBlock() - if head.Number.Uint64() > 0 { - // We've completed a sync cycle, notify all peers of new state. This path is - // essential in star-topology networks where a gateway node needs to notify - // all its out-of-date peers of the availability of a new block. This failure - // scenario will most often crop up in private and hackathon networks with - // degenerate connectivity, but it should be healthy for the mainnet too to - // more reliably update peers or the local TD state. - if block := h.chain.GetBlock(head.Hash(), head.Number.Uint64()); block != nil { - h.BroadcastBlock(block, false) - } - } - return nil -} diff --git a/eth/sync_test.go b/eth/sync_test.go index a31986730f06..7ede0a82c5d5 100644 --- a/eth/sync_test.go +++ b/eth/sync_test.go @@ -85,10 +85,11 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) { time.Sleep(250 * time.Millisecond) // Check that snap sync was disabled - op := peerToSyncOp(downloader.SnapSync, empty.handler.peers.peerWithHighestTD()) - if err := empty.handler.doSync(op); err != nil { + if err := empty.handler.downloader.BeaconSync(downloader.SnapSync, full.chain.CurrentBlock(), nil); err != nil { t.Fatal("sync failed:", err) } + empty.handler.enableSyncedFeatures() + if empty.handler.snapSync.Load() { t.Fatalf("snap sync not disabled after successful synchronisation") } diff --git a/params/config.go b/params/config.go index b24e782b8d96..439e88218924 100644 --- a/params/config.go +++ b/params/config.go @@ -361,6 +361,8 @@ type ChainConfig struct { // TerminalTotalDifficultyPassed is a flag specifying that the network already // passed the terminal total difficulty. Its purpose is to disable legacy sync // even without having seen the TTD locally (safer long term). + // + // TODO(karalabe): Drop this field eventually (always assuming PoS mode) TerminalTotalDifficultyPassed bool `json:"terminalTotalDifficultyPassed,omitempty"` // Various consensus engines From 66e1a6ef496e001abc7ae7433282251a557deb2c Mon Sep 17 00:00:00 2001 From: Devon Bear Date: Tue, 5 Mar 2024 09:15:02 -0500 Subject: [PATCH 035/571] go.mod: bump pebble db to official release (#29038) bump pebble --- ethdb/pebble/pebble.go | 4 +- go.mod | 13 ++-- go.sum | 148 ++++------------------------------------- 3 files changed, 21 insertions(+), 144 deletions(-) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index af4686cf5b72..57689ab04b9b 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -589,8 +589,8 @@ func (b *batch) Reset() { func (b *batch) Replay(w ethdb.KeyValueWriter) error { reader := b.b.Reader() for { - kind, k, v, ok := reader.Next() - if !ok { + kind, k, v, ok, err := reader.Next() + if !ok || err != nil { break } // The (k,v) slices might be overwritten if the batch is reset/reused, diff --git a/go.mod b/go.mod index 48faa0a321d3..870ce76cb6e9 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.79.0 - github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 + github.com/cockroachdb/pebble v1.1.0 github.com/consensys/gnark-crypto v0.12.1 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/crate-crypto/go-kzg-4844 v0.7.0 @@ -91,10 +91,9 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cockroachdb/errors v1.8.1 // indirect - github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect - github.com/cockroachdb/redact v1.0.8 // indirect - github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect + github.com/cockroachdb/errors v1.11.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect @@ -102,11 +101,11 @@ require ( github.com/deepmap/oapi-codegen v1.6.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect + github.com/getsentry/sentry-go v0.18.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -140,7 +139,7 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.18.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index 20a95d36877c..58006701c69b 100644 --- a/go.sum +++ b/go.sum @@ -31,7 +31,6 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= @@ -44,20 +43,14 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkM github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= -github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -65,7 +58,6 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= github.com/aws/aws-sdk-go-v2/config v1.18.45 h1:Aka9bI7n8ysuwPeFdm77nfbyHCAKQ3z9ghB3S/38zes= @@ -92,7 +84,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwF github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -119,30 +110,21 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cloudflare/cloudflare-go v0.79.0 h1:ErwCYDjFCYppDJlDJ/5WhsSmzegAUe2+K9qgFyQDg3M= github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= -github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= -github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= -github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= -github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= -github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= +github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4= +github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= @@ -162,9 +144,7 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/deepmap/oapi-codegen v1.6.0 h1:w/d1ntwh91XI0b/8ja7+u5SvA4IFfM0UNNLmiDR1gg0= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= @@ -174,45 +154,36 @@ github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 h1:qwcF+vdFrvPSEUDSX5R github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -222,7 +193,6 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -231,20 +201,13 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -280,7 +243,6 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -295,8 +257,6 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -319,9 +279,7 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= @@ -334,10 +292,8 @@ github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrj github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= @@ -347,21 +303,14 @@ github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXei github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= -github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= -github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= @@ -377,30 +326,17 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/hid v1.0.1-0.20240209121748-d3b59fe37df8 h1:IMoiklsIksD2ii43zKCybVU6jLNzpSl3bT31+5mUjgg= github.com/karalabe/hid v1.0.1-0.20240209121748-d3b59fe37df8/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8= -github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= -github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= -github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= -github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -418,11 +354,9 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= @@ -432,7 +366,6 @@ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -444,17 +377,11 @@ github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= -github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= @@ -467,23 +394,18 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= -github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -491,11 +413,9 @@ github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -539,26 +459,13 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -580,26 +487,13 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -613,11 +507,9 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME= go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -664,11 +556,9 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -677,7 +567,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -725,7 +614,6 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -735,7 +623,6 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -808,15 +695,11 @@ golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -883,7 +766,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -913,7 +795,6 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -938,8 +819,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -948,9 +829,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= From 588c5480fd1f355a39d3f52a5507ab9d0da334c9 Mon Sep 17 00:00:00 2001 From: Tom <45168162+tomdever@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:23:35 +0800 Subject: [PATCH 036/571] internal/ethapi: delete needless error check (#29127) --- internal/ethapi/api_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 8ffa638a6b5c..1d0383daad03 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -1244,7 +1244,7 @@ func TestFillBlobTransaction(t *testing.T) { if len(tc.err) > 0 { if err == nil { t.Fatalf("missing error. want: %s", tc.err) - } else if err != nil && err.Error() != tc.err { + } else if err.Error() != tc.err { t.Fatalf("error mismatch. want: %s, have: %s", tc.err, err.Error()) } return From 899bb88a4ba19af2d8fe4874561a9d55355acf48 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 6 Mar 2024 10:32:17 +0100 Subject: [PATCH 037/571] accounts/usbwallet: revert #28945 (#29175) --- accounts/usbwallet/hub.go | 8 ++++---- accounts/usbwallet/wallet.go | 6 +++--- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index e22dffe9718e..e67942dbc107 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -26,7 +26,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. @@ -109,7 +109,7 @@ func NewTrezorHubWithWebUSB() (*Hub, error) { // 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{ @@ -155,7 +155,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, @@ -170,7 +170,7 @@ func (hub *Hub) refreshWallets() { return } } - infos, err := hid.Enumerate(hub.vendorID, 0) + infos, err := usb.Enumerate(hub.vendorID, 0) if err != nil { failcount := hub.enumFails.Add(1) if runtime.GOOS == "linux" { diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 0fd0415a9ef8..69083dc8939d 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. @@ -79,8 +79,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/go.mod b/go.mod index 870ce76cb6e9..42114e115a55 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 github.com/julienschmidt/httprouter v1.3.0 - github.com/karalabe/hid v1.0.1-0.20240209121748-d3b59fe37df8 + github.com/karalabe/usb v0.0.2 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.17 diff --git a/go.sum b/go.sum index 58006701c69b..e9f62bbfd75d 100644 --- a/go.sum +++ b/go.sum @@ -329,8 +329,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/karalabe/hid v1.0.1-0.20240209121748-d3b59fe37df8 h1:IMoiklsIksD2ii43zKCybVU6jLNzpSl3bT31+5mUjgg= -github.com/karalabe/hid v1.0.1-0.20240209121748-d3b59fe37df8/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8= +github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= +github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= From a000acb61114c2a3a74c065f2e61b4d6bca3ae46 Mon Sep 17 00:00:00 2001 From: Andrei Kostakov Date: Wed, 6 Mar 2024 11:53:12 +0200 Subject: [PATCH 038/571] rpc: add more test cases for arg types (#29006) --- rpc/types_test.go | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/rpc/types_test.go b/rpc/types_test.go index 617f441d9166..2fa74f9899bb 100644 --- a/rpc/types_test.go +++ b/rpc/types_test.go @@ -45,9 +45,11 @@ func TestBlockNumberJSONUnmarshal(t *testing.T) { 11: {`"pending"`, false, PendingBlockNumber}, 12: {`"latest"`, false, LatestBlockNumber}, 13: {`"earliest"`, false, EarliestBlockNumber}, - 14: {`someString`, true, BlockNumber(0)}, - 15: {`""`, true, BlockNumber(0)}, - 16: {``, true, BlockNumber(0)}, + 14: {`"safe"`, false, SafeBlockNumber}, + 15: {`"finalized"`, false, FinalizedBlockNumber}, + 16: {`someString`, true, BlockNumber(0)}, + 17: {`""`, true, BlockNumber(0)}, + 18: {``, true, BlockNumber(0)}, } for i, test := range tests { @@ -87,18 +89,22 @@ func TestBlockNumberOrHash_UnmarshalJSON(t *testing.T) { 11: {`"pending"`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)}, 12: {`"latest"`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, 13: {`"earliest"`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)}, - 14: {`someString`, true, BlockNumberOrHash{}}, - 15: {`""`, true, BlockNumberOrHash{}}, - 16: {``, true, BlockNumberOrHash{}}, - 17: {`"0x0000000000000000000000000000000000000000000000000000000000000000"`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, - 18: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, - 19: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":false}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, - 20: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":true}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), true)}, - 21: {`{"blockNumber":"0x1"}`, false, BlockNumberOrHashWithNumber(1)}, - 22: {`{"blockNumber":"pending"}`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)}, - 23: {`{"blockNumber":"latest"}`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, - 24: {`{"blockNumber":"earliest"}`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)}, - 25: {`{"blockNumber":"0x1", "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, true, BlockNumberOrHash{}}, + 14: {`"safe"`, false, BlockNumberOrHashWithNumber(SafeBlockNumber)}, + 15: {`"finalized"`, false, BlockNumberOrHashWithNumber(FinalizedBlockNumber)}, + 16: {`someString`, true, BlockNumberOrHash{}}, + 17: {`""`, true, BlockNumberOrHash{}}, + 18: {``, true, BlockNumberOrHash{}}, + 19: {`"0x0000000000000000000000000000000000000000000000000000000000000000"`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, + 20: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, + 21: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":false}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, + 22: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":true}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), true)}, + 23: {`{"blockNumber":"0x1"}`, false, BlockNumberOrHashWithNumber(1)}, + 24: {`{"blockNumber":"pending"}`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)}, + 25: {`{"blockNumber":"latest"}`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, + 26: {`{"blockNumber":"earliest"}`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)}, + 27: {`{"blockNumber":"safe"}`, false, BlockNumberOrHashWithNumber(SafeBlockNumber)}, + 28: {`{"blockNumber":"finalized"}`, false, BlockNumberOrHashWithNumber(FinalizedBlockNumber)}, + 29: {`{"blockNumber":"0x1", "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, true, BlockNumberOrHash{}}, } for i, test := range tests { @@ -133,6 +139,8 @@ func TestBlockNumberOrHash_WithNumber_MarshalAndUnmarshal(t *testing.T) { {"pending", int64(PendingBlockNumber)}, {"latest", int64(LatestBlockNumber)}, {"earliest", int64(EarliestBlockNumber)}, + {"safe", int64(SafeBlockNumber)}, + {"finalized", int64(FinalizedBlockNumber)}, } for _, test := range tests { test := test @@ -160,6 +168,8 @@ func TestBlockNumberOrHash_StringAndUnmarshal(t *testing.T) { BlockNumberOrHashWithNumber(PendingBlockNumber), BlockNumberOrHashWithNumber(LatestBlockNumber), BlockNumberOrHashWithNumber(EarliestBlockNumber), + BlockNumberOrHashWithNumber(SafeBlockNumber), + BlockNumberOrHashWithNumber(FinalizedBlockNumber), BlockNumberOrHashWithNumber(32), BlockNumberOrHashWithHash(common.Hash{0xaa}, false), } From e73f55365c458c5185a493935b65dd96bacf6933 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 6 Mar 2024 11:31:50 +0100 Subject: [PATCH 039/571] accounts/usbwallet: update hid library (#29176) --- accounts/usbwallet/hub.go | 8 ++++---- accounts/usbwallet/wallet.go | 6 +++--- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index e67942dbc107..e22dffe9718e 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -26,7 +26,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/karalabe/usb" + "github.com/karalabe/hid" ) // LedgerScheme is the protocol scheme prefixing account and wallet URLs. @@ -109,7 +109,7 @@ func NewTrezorHubWithWebUSB() (*Hub, error) { // 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 !usb.Supported() { + if !hid.Supported() { return nil, errors.New("unsupported platform") } hub := &Hub{ @@ -155,7 +155,7 @@ func (hub *Hub) refreshWallets() { return } // Retrieve the current list of USB wallet devices - var devices []usb.DeviceInfo + var devices []hid.DeviceInfo if runtime.GOOS == "linux" { // hidapi on Linux opens the device during enumeration to retrieve some infos, @@ -170,7 +170,7 @@ func (hub *Hub) refreshWallets() { return } } - infos, err := usb.Enumerate(hub.vendorID, 0) + infos, err := hid.Enumerate(hub.vendorID, 0) if err != nil { failcount := hub.enumFails.Add(1) if runtime.GOOS == "linux" { diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 69083dc8939d..0fd0415a9ef8 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/usb" + "github.com/karalabe/hid" ) // Maximum time between wallet health checks to detect USB unplugs. @@ -79,8 +79,8 @@ type wallet struct { driver driver // Hardware implementation of the low level device operations url *accounts.URL // Textual URL uniquely identifying this wallet - info usb.DeviceInfo // Known USB device infos about the wallet - device usb.Device // USB device advertising itself as a hardware wallet + info hid.DeviceInfo // Known USB device infos about the 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/go.mod b/go.mod index 42114e115a55..6591bee62ff1 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 github.com/julienschmidt/httprouter v1.3.0 - github.com/karalabe/usb v0.0.2 + github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.17 diff --git a/go.sum b/go.sum index e9f62bbfd75d..cc74e15cb4b9 100644 --- a/go.sum +++ b/go.sum @@ -329,8 +329,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= -github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 h1:msKODTL1m0wigztaqILOtla9HeW1ciscYG4xjLtvk5I= +github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= From a90fe84971183aa0b6c40d71c6586ae3f2eda4c8 Mon Sep 17 00:00:00 2001 From: Undefinedor Date: Wed, 6 Mar 2024 18:55:44 +0800 Subject: [PATCH 040/571] accounts: remove deprecated function NewPlaintextKeyStore (#29171) --- accounts/keystore/account_cache_test.go | 2 +- accounts/keystore/keystore.go | 9 ------- accounts/keystore/keystore_test.go | 34 +++++++++++-------------- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index 48a238048fec..bb92cc2adca5 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -86,7 +86,7 @@ func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error { func TestWatchNewFile(t *testing.T) { t.Parallel() - dir, ks := tmpKeyStore(t, false) + dir, ks := tmpKeyStore(t) // Ensure the watcher is started before adding any files. ks.Accounts() diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 0ffcf376a5fd..e62a8eb25738 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -87,15 +87,6 @@ func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore { return ks } -// NewPlaintextKeyStore creates a keystore for the given directory. -// Deprecated: Use NewKeyStore. -func NewPlaintextKeyStore(keydir string) *KeyStore { - keydir, _ = filepath.Abs(keydir) - ks := &KeyStore{storage: &keyStorePlain{keydir}} - ks.init(keydir) - return ks -} - func (ks *KeyStore) init(keydir string) { // Lock the mutex since the account cache might call back with events ks.mu.Lock() diff --git a/accounts/keystore/keystore_test.go b/accounts/keystore/keystore_test.go index c9a23eddd6ca..c871392b82ec 100644 --- a/accounts/keystore/keystore_test.go +++ b/accounts/keystore/keystore_test.go @@ -37,7 +37,7 @@ var testSigData = make([]byte, 32) func TestKeyStore(t *testing.T) { t.Parallel() - dir, ks := tmpKeyStore(t, true) + dir, ks := tmpKeyStore(t) a, err := ks.NewAccount("foo") if err != nil { @@ -72,7 +72,7 @@ func TestKeyStore(t *testing.T) { func TestSign(t *testing.T) { t.Parallel() - _, ks := tmpKeyStore(t, true) + _, ks := tmpKeyStore(t) pass := "" // not used but required by API a1, err := ks.NewAccount(pass) @@ -89,7 +89,7 @@ func TestSign(t *testing.T) { func TestSignWithPassphrase(t *testing.T) { t.Parallel() - _, ks := tmpKeyStore(t, true) + _, ks := tmpKeyStore(t) pass := "passwd" acc, err := ks.NewAccount(pass) @@ -117,7 +117,7 @@ func TestSignWithPassphrase(t *testing.T) { func TestTimedUnlock(t *testing.T) { t.Parallel() - _, ks := tmpKeyStore(t, true) + _, ks := tmpKeyStore(t) pass := "foo" a1, err := ks.NewAccount(pass) @@ -152,7 +152,7 @@ func TestTimedUnlock(t *testing.T) { func TestOverrideUnlock(t *testing.T) { t.Parallel() - _, ks := tmpKeyStore(t, false) + _, ks := tmpKeyStore(t) pass := "foo" a1, err := ks.NewAccount(pass) @@ -193,7 +193,7 @@ func TestOverrideUnlock(t *testing.T) { // This test should fail under -race if signing races the expiration goroutine. func TestSignRace(t *testing.T) { t.Parallel() - _, ks := tmpKeyStore(t, false) + _, ks := tmpKeyStore(t) // Create a test account. a1, err := ks.NewAccount("") @@ -238,7 +238,7 @@ func waitForKsUpdating(t *testing.T, ks *KeyStore, wantStatus bool, maxTime time func TestWalletNotifierLifecycle(t *testing.T) { t.Parallel() // Create a temporary keystore to test with - _, ks := tmpKeyStore(t, false) + _, ks := tmpKeyStore(t) // Ensure that the notification updater is not running yet time.Sleep(250 * time.Millisecond) @@ -284,7 +284,7 @@ type walletEvent struct { // or deleted from the keystore. func TestWalletNotifications(t *testing.T) { t.Parallel() - _, ks := tmpKeyStore(t, false) + _, ks := tmpKeyStore(t) // Subscribe to the wallet feed and collect events. var ( @@ -346,7 +346,7 @@ func TestWalletNotifications(t *testing.T) { // TestImportExport tests the import functionality of a keystore. func TestImportECDSA(t *testing.T) { t.Parallel() - _, ks := tmpKeyStore(t, true) + _, ks := tmpKeyStore(t) key, err := crypto.GenerateKey() if err != nil { t.Fatalf("failed to generate key: %v", key) @@ -365,7 +365,7 @@ func TestImportECDSA(t *testing.T) { // TestImportECDSA tests the import and export functionality of a keystore. func TestImportExport(t *testing.T) { t.Parallel() - _, ks := tmpKeyStore(t, true) + _, ks := tmpKeyStore(t) acc, err := ks.NewAccount("old") if err != nil { t.Fatalf("failed to create account: %v", acc) @@ -374,7 +374,7 @@ func TestImportExport(t *testing.T) { if err != nil { t.Fatalf("failed to export account: %v", acc) } - _, ks2 := tmpKeyStore(t, true) + _, ks2 := tmpKeyStore(t) if _, err = ks2.Import(json, "old", "old"); err == nil { t.Errorf("importing with invalid password succeeded") } @@ -394,7 +394,7 @@ func TestImportExport(t *testing.T) { // This test should fail under -race if importing races. func TestImportRace(t *testing.T) { t.Parallel() - _, ks := tmpKeyStore(t, true) + _, ks := tmpKeyStore(t) acc, err := ks.NewAccount("old") if err != nil { t.Fatalf("failed to create account: %v", acc) @@ -403,7 +403,7 @@ func TestImportRace(t *testing.T) { if err != nil { t.Fatalf("failed to export account: %v", acc) } - _, ks2 := tmpKeyStore(t, true) + _, ks2 := tmpKeyStore(t) var atom atomic.Uint32 var wg sync.WaitGroup wg.Add(2) @@ -457,11 +457,7 @@ func checkEvents(t *testing.T, want []walletEvent, have []walletEvent) { } } -func tmpKeyStore(t *testing.T, encrypted bool) (string, *KeyStore) { +func tmpKeyStore(t *testing.T) (string, *KeyStore) { d := t.TempDir() - newKs := NewPlaintextKeyStore - if encrypted { - newKs = func(kd string) *KeyStore { return NewKeyStore(kd, veryLightScryptN, veryLightScryptP) } - } - return d, newKs(d) + return d, NewKeyStore(d, veryLightScryptN, veryLightScryptP) } From 6e379b6fc776668c9a7db6d5b014d0dd89d7118d Mon Sep 17 00:00:00 2001 From: Delweng Date: Wed, 6 Mar 2024 20:36:12 +0800 Subject: [PATCH 041/571] eth/tracers: prestate tracer add blob fee (#29168) * eth/tracers: prestate balance add blob fee Signed-off-by: jsvisa * eth/tracers: prestate test support blob tx Signed-off-by: jsvisa * eth/tracers: add prestate blob tx test Signed-off-by: jsvisa --------- Signed-off-by: jsvisa --- .../internal/tracetest/prestate_test.go | 6 ++ .../testdata/prestate_tracer/blob_tx.json | 63 +++++++++++++++++++ eth/tracers/native/prestate.go | 7 +++ 3 files changed, 76 insertions(+) create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 8a60123dc2c6..38097ff334b2 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -25,6 +25,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -107,6 +108,11 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { ) defer state.Close() + if test.Genesis.ExcessBlobGas != nil && test.Genesis.BlobGasUsed != nil { + excessBlobGas := eip4844.CalcExcessBlobGas(*test.Genesis.ExcessBlobGas, *test.Genesis.BlobGasUsed) + context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) + } + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json new file mode 100644 index 000000000000..315481aff536 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json @@ -0,0 +1,63 @@ +{ + "genesis": { + "baseFeePerGas": "7", + "blobGasUsed": "0", + "difficulty": "0", + "excessBlobGas": "36306944", + "extraData": "0xd983010e00846765746888676f312e32312e308664617277696e", + "gasLimit": "15639172", + "hash": "0xc682259fda061bb9ce8ccb491d5b2d436cb73daf04e1025dd116d045ce4ad28c", + "miner": "0x0000000000000000000000000000000000000000", + "mixHash": "0xae1a5ba939a4c9ac38aabeff361169fb55a6fc2c9511457e0be6eff9514faec0", + "nonce": "0x0000000000000000", + "number": "315", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x577f42ab21ccfd946511c57869ace0bdf7c217c36f02b7cd3459df0ed1cffc1a", + "timestamp": "1709626771", + "totalDifficulty": "1", + "withdrawals": [], + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x272e0528" + }, + "0x0c2c51a0990aee1d73c1228de158688341557508": { + "balance": "0xde0b6b3a7640000" + } + }, + "config": { + "chainId": 1337, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "shanghaiTime": 0, + "cancunTime": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true + } + }, + "context": { + "number": "316", + "difficulty": "0", + "timestamp": "1709626785", + "gasLimit": "15654443", + "miner": "0x0000000000000000000000000000000000000000" + }, + "input": "0x03f8b1820539806485174876e800825208940c2c51a0990aee1d73c1228de1586883415575088080c083020000f842a00100c9fbdf97f747e85847b4f3fff408f89c26842f77c882858bf2c89923849aa00138e3896f3c27f2389147507f8bcec52028b0efca6ee842ed83c9158873943880a0dbac3f97a532c9b00e6239b29036245a5bfbb96940b9d848634661abee98b945a03eec8525f261c2e79798f7b45a5d6ccaefa24576d53ba5023e919b86841c0675", + "result": { + "0x0000000000000000000000000000000000000000": { "balance": "0x272e0528" }, + "0x0c2c51a0990aee1d73c1228de158688341557508": { + "balance": "0xde0b6b3a7640000" + } + } +} diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 0d57f62caf20..b86c5c461c7d 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" ) //go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go @@ -112,6 +113,12 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo gasPrice := env.TxContext.GasPrice consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit)) fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) + + // Add blob fee to the sender's balance. + if env.Context.BlobBaseFee != nil && len(env.TxContext.BlobHashes) > 0 { + blobGas := uint64(params.BlobTxBlobGasPerBlob * len(env.TxContext.BlobHashes)) + fromBal.Add(fromBal, new(big.Int).Mul(env.Context.BlobBaseFee, new(big.Int).SetUint64(blobGas))) + } t.pre[from].Balance = fromBal t.pre[from].Nonce-- From d8e0807da22eb922539d15b0d5d01ccdd58b1267 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 6 Mar 2024 13:45:03 +0100 Subject: [PATCH 042/571] miner: refactor the miner, make the pending block on demand (#28623) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * miner: untangle miner * miner: use common.hash instead of *types.header * cmd/geth: deprecate --mine * eth: get rid of most miner api * console: get rid of coinbase in welcome message * miner/stress: get rid of the miner stress test * eth: get rid of miner.setEtherbase * ethstats: remove miner and hashrate flags * ethstats: remove miner and hashrate flags * cmd: rename pendingBlockProducer to miner.pending.feeRecipient flag * miner: use pendingFeeRecipient instead of etherbase * miner: add mutex to protect the pending block * miner: add mutex to protect the pending block * eth: get rid of etherbase mentions * miner: no need to lock the coinbase * eth, miner: fix linter --------- Co-authored-by: Martin Holst Swende Co-authored-by: Péter Szilágyi --- cmd/geth/consolecmd_test.go | 3 - cmd/geth/main.go | 26 +- cmd/utils/flags.go | 43 +- cmd/utils/flags_legacy.go | 20 + consensus/consensus.go | 8 - console/console.go | 3 - console/console_test.go | 5 +- eth/api.go | 52 - eth/api_backend.go | 23 +- eth/api_debug.go | 4 +- eth/api_miner.go | 28 - eth/backend.go | 152 +-- eth/catalyst/api_test.go | 5 +- eth/catalyst/simulated_beacon_test.go | 3 +- eth/filters/filter.go | 2 +- eth/filters/filter_system.go | 78 +- eth/filters/filter_system_test.go | 42 +- eth/filters/filter_test.go | 7 +- eth/gasprice/feehistory.go | 2 +- eth/gasprice/gasprice.go | 3 +- eth/gasprice/gasprice_test.go | 8 +- ethclient/ethclient_test.go | 23 +- ethstats/ethstats.go | 25 +- internal/ethapi/api_test.go | 5 +- internal/ethapi/backend.go | 3 +- internal/ethapi/transaction_args_test.go | 5 +- internal/web3ext/web3ext.go | 23 - miner/miner.go | 256 ++--- miner/miner_test.go | 204 +--- miner/payload_building.go | 9 +- miner/payload_building_test.go | 119 ++- miner/pending.go | 67 ++ miner/stress/clique/main.go | 223 ----- miner/worker.go | 1097 +++------------------- miner/worker_test.go | 510 ---------- 35 files changed, 598 insertions(+), 2488 deletions(-) delete mode 100644 eth/api.go create mode 100644 miner/pending.go delete mode 100644 miner/stress/clique/main.go delete mode 100644 miner/worker_test.go diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index ef6ef5f28836..4d6220641703 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -71,7 +71,6 @@ func TestConsoleWelcome(t *testing.T) { Welcome to the Geth JavaScript console! instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}} -coinbase: {{.Etherbase}} at block: 0 ({{niltime}}) datadir: {{.Datadir}} modules: {{apis}} @@ -131,7 +130,6 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) attach.SetTemplateFunc("gover", runtime.Version) attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") }) - attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase }) attach.SetTemplateFunc("niltime", func() string { return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") }) @@ -144,7 +142,6 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { Welcome to the Geth JavaScript console! instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}} -coinbase: {{etherbase}} at block: 0 ({{niltime}}){{if ipc}} datadir: {{datadir}}{{end}} modules: {{apis}} diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 2f7d37fdd7e7..9a88e9f2e8b4 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/console/prompt" - "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/internal/debug" @@ -116,13 +115,14 @@ var ( utils.DiscoveryPortFlag, utils.MaxPeersFlag, utils.MaxPendingPeersFlag, - utils.MiningEnabledFlag, + utils.MiningEnabledFlag, // deprecated utils.MinerGasLimitFlag, utils.MinerGasPriceFlag, - utils.MinerEtherbaseFlag, + utils.MinerEtherbaseFlag, // deprecated utils.MinerExtraDataFlag, utils.MinerRecommitIntervalFlag, - utils.MinerNewPayloadTimeout, + utils.MinerPendingFeeRecipientFlag, + utils.MinerNewPayloadTimeoutFlag, // deprecated utils.NATFlag, utils.NoDiscoverFlag, utils.DiscoveryV4Flag, @@ -421,24 +421,6 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon } }() } - - // Start auxiliary services if enabled - if ctx.Bool(utils.MiningEnabledFlag.Name) { - // Mining only makes sense if a full Ethereum node is running - if ctx.String(utils.SyncModeFlag.Name) == "light" { - utils.Fatalf("Light clients do not support mining") - } - ethBackend, ok := backend.(*eth.EthAPIBackend) - if !ok { - utils.Fatalf("Ethereum service not running") - } - // Set the gas price to the limits from the CLI and start mining - gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) - ethBackend.TxPool().SetGasTip(gasprice) - if err := ethBackend.StartMining(); err != nil { - utils.Fatalf("Failed to start mining: %v", err) - } - } } // unlockAccounts unlocks any account specifically requested. diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 82af26ff9659..fad567cd55d2 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -425,11 +425,6 @@ var ( } // Miner settings - MiningEnabledFlag = &cli.BoolFlag{ - Name: "mine", - Usage: "Enable mining", - Category: flags.MinerCategory, - } MinerGasLimitFlag = &cli.Uint64Flag{ Name: "miner.gaslimit", Usage: "Target gas ceiling for mined blocks", @@ -442,11 +437,6 @@ var ( Value: ethconfig.Defaults.Miner.GasPrice, Category: flags.MinerCategory, } - MinerEtherbaseFlag = &cli.StringFlag{ - Name: "miner.etherbase", - Usage: "0x prefixed public address for block mining rewards", - Category: flags.MinerCategory, - } MinerExtraDataFlag = &cli.StringFlag{ Name: "miner.extradata", Usage: "Block extra data set by the miner (default = client version)", @@ -458,10 +448,9 @@ var ( Value: ethconfig.Defaults.Miner.Recommit, Category: flags.MinerCategory, } - MinerNewPayloadTimeout = &cli.DurationFlag{ - Name: "miner.newpayload-timeout", - Usage: "Specify the maximum time allowance for creating a new payload", - Value: ethconfig.Defaults.Miner.NewPayloadTimeout, + MinerPendingFeeRecipientFlag = &cli.StringFlag{ + Name: "miner.pending.feeRecipient", + Usage: "0x prefixed public address for the pending block producer (not used for actual block production)", Category: flags.MinerCategory, } @@ -1268,19 +1257,23 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error // setEtherbase retrieves the etherbase from the directly specified command line flags. func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) { - if !ctx.IsSet(MinerEtherbaseFlag.Name) { + if ctx.IsSet(MinerEtherbaseFlag.Name) { + log.Warn("Option --miner.etherbase is deprecated as the etherbase is set by the consensus client post-merge") return } - addr := ctx.String(MinerEtherbaseFlag.Name) + if !ctx.IsSet(MinerPendingFeeRecipientFlag.Name) { + return + } + addr := ctx.String(MinerPendingFeeRecipientFlag.Name) if strings.HasPrefix(addr, "0x") || strings.HasPrefix(addr, "0X") { addr = addr[2:] } b, err := hex.DecodeString(addr) if err != nil || len(b) != common.AddressLength { - Fatalf("-%s: invalid etherbase address %q", MinerEtherbaseFlag.Name, addr) + Fatalf("-%s: invalid pending block producer address %q", MinerPendingFeeRecipientFlag.Name, addr) return } - cfg.Miner.Etherbase = common.BytesToAddress(b) + cfg.Miner.PendingFeeRecipient = common.BytesToAddress(b) } // MakePasswordList reads password lines from the file specified by the global --password flag. @@ -1496,6 +1489,9 @@ func setTxPool(ctx *cli.Context, cfg *legacypool.Config) { } func setMiner(ctx *cli.Context, cfg *miner.Config) { + if ctx.Bool(MiningEnabledFlag.Name) { + log.Warn("The flag --mine is deprecated and will be removed") + } if ctx.IsSet(MinerExtraDataFlag.Name) { cfg.ExtraData = []byte(ctx.String(MinerExtraDataFlag.Name)) } @@ -1508,8 +1504,9 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) { if ctx.IsSet(MinerRecommitIntervalFlag.Name) { cfg.Recommit = ctx.Duration(MinerRecommitIntervalFlag.Name) } - if ctx.IsSet(MinerNewPayloadTimeout.Name) { - cfg.NewPayloadTimeout = ctx.Duration(MinerNewPayloadTimeout.Name) + if ctx.IsSet(MinerNewPayloadTimeoutFlag.Name) { + log.Warn("The flag --miner.newpayload-timeout is deprecated and will be removed, please use --miner.recommit") + cfg.Recommit = ctx.Duration(MinerNewPayloadTimeoutFlag.Name) } } @@ -1786,8 +1783,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // Figure out the dev account address. // setEtherbase has been called above, configuring the miner address from command line flags. - if cfg.Miner.Etherbase != (common.Address{}) { - developer = accounts.Account{Address: cfg.Miner.Etherbase} + if cfg.Miner.PendingFeeRecipient != (common.Address{}) { + developer = accounts.Account{Address: cfg.Miner.PendingFeeRecipient} } else if accs := ks.Accounts(); len(accs) > 0 { developer = ks.Accounts()[0] } else { @@ -1798,7 +1795,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { } // Make sure the address is configured as fee recipient, otherwise // the miner will fail to start. - cfg.Miner.Etherbase = developer.Address + cfg.Miner.PendingFeeRecipient = developer.Address if err := ks.Unlock(developer, passphrase); err != nil { Fatalf("Failed to unlock developer account: %v", err) diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go index 243abd831105..49321053c672 100644 --- a/cmd/utils/flags_legacy.go +++ b/cmd/utils/flags_legacy.go @@ -47,6 +47,9 @@ var DeprecatedFlags = []cli.Flag{ LightNoSyncServeFlag, LogBacktraceAtFlag, LogDebugFlag, + MinerNewPayloadTimeoutFlag, + MinerEtherbaseFlag, + MiningEnabledFlag, } var ( @@ -132,6 +135,23 @@ var ( Usage: "Prepends log messages with call-site location (deprecated)", Category: flags.DeprecatedCategory, } + // Deprecated February 2024 + MinerNewPayloadTimeoutFlag = &cli.DurationFlag{ + Name: "miner.newpayload-timeout", + Usage: "Specify the maximum time allowance for creating a new payload", + Value: ethconfig.Defaults.Miner.Recommit, + Category: flags.MinerCategory, + } + MinerEtherbaseFlag = &cli.StringFlag{ + Name: "miner.etherbase", + Usage: "0x prefixed public address for block mining rewards", + Category: flags.MinerCategory, + } + MiningEnabledFlag = &cli.BoolFlag{ + Name: "mine", + Usage: "Enable mining", + Category: flags.MinerCategory, + } ) // showDeprecated displays deprecated flags that will be soon removed from the codebase. diff --git a/consensus/consensus.go b/consensus/consensus.go index 3a2c2d222916..5cc052cb0fea 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -119,11 +119,3 @@ type Engine interface { // Close terminates any background threads maintained by the consensus engine. Close() error } - -// PoW is a consensus engine based on proof-of-work. -type PoW interface { - Engine - - // Hashrate returns the current mining hashrate of a PoW consensus engine. - Hashrate() float64 -} diff --git a/console/console.go b/console/console.go index cdee53684ecf..5acb4cdccb5b 100644 --- a/console/console.go +++ b/console/console.go @@ -325,9 +325,6 @@ func (c *Console) Welcome() { // Print some generic Geth metadata if res, err := c.jsre.Run(` var message = "instance: " + web3.version.node + "\n"; - try { - message += "coinbase: " + eth.coinbase + "\n"; - } catch (err) {} message += "at block: " + eth.blockNumber + " (" + new Date(1000 * eth.getBlock(eth.blockNumber).timestamp) + ")\n"; try { message += " datadir: " + admin.datadir + "\n"; diff --git a/console/console_test.go b/console/console_test.go index a13be6a99ded..4c30c1b49cc6 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -96,7 +96,7 @@ func newTester(t *testing.T, confOverride func(*ethconfig.Config)) *tester { ethConf := ðconfig.Config{ Genesis: core.DeveloperGenesisBlock(11_500_000, nil), Miner: miner.Config{ - Etherbase: common.HexToAddress(testAddress), + PendingFeeRecipient: common.HexToAddress(testAddress), }, } if confOverride != nil { @@ -167,9 +167,6 @@ func TestWelcome(t *testing.T) { if want := fmt.Sprintf("instance: %s", testInstance); !strings.Contains(output, want) { t.Fatalf("console output missing instance: have\n%s\nwant also %s", output, want) } - if want := fmt.Sprintf("coinbase: %s", testAddress); !strings.Contains(output, want) { - t.Fatalf("console output missing coinbase: have\n%s\nwant also %s", output, want) - } if want := "at block: 0"; !strings.Contains(output, want) { t.Fatalf("console output missing sync status: have\n%s\nwant also %s", output, want) } diff --git a/eth/api.go b/eth/api.go deleted file mode 100644 index 44e934fd040b..000000000000 --- a/eth/api.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2015 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 eth - -import ( - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" -) - -// EthereumAPI provides an API to access Ethereum full node-related information. -type EthereumAPI struct { - e *Ethereum -} - -// NewEthereumAPI creates a new Ethereum protocol API for full nodes. -func NewEthereumAPI(e *Ethereum) *EthereumAPI { - return &EthereumAPI{e} -} - -// Etherbase is the address that mining rewards will be sent to. -func (api *EthereumAPI) Etherbase() (common.Address, error) { - return api.e.Etherbase() -} - -// Coinbase is the address that mining rewards will be sent to (alias for Etherbase). -func (api *EthereumAPI) Coinbase() (common.Address, error) { - return api.Etherbase() -} - -// Hashrate returns the POW hashrate. -func (api *EthereumAPI) Hashrate() hexutil.Uint64 { - return hexutil.Uint64(api.e.Miner().Hashrate()) -} - -// Mining returns an indication if this node is currently mining. -func (api *EthereumAPI) Mining() bool { - return api.e.IsMining() -} diff --git a/eth/api_backend.go b/eth/api_backend.go index 65adccd8518c..48c46447c5a0 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -37,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -67,7 +66,7 @@ func (b *EthAPIBackend) SetHead(number uint64) { func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { // Pending block is only known by the miner if number == rpc.PendingBlockNumber { - block := b.eth.miner.PendingBlock() + block, _, _ := b.eth.miner.Pending() if block == nil { return nil, errors.New("pending block is not available") } @@ -118,7 +117,7 @@ func (b *EthAPIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*ty func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { // Pending block is only known by the miner if number == rpc.PendingBlockNumber { - block := b.eth.miner.PendingBlock() + block, _, _ := b.eth.miner.Pending() if block == nil { return nil, errors.New("pending block is not available") } @@ -182,14 +181,14 @@ func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash r return nil, errors.New("invalid arguments; neither block nor hash specified") } -func (b *EthAPIBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { - return b.eth.miner.PendingBlockAndReceipts() +func (b *EthAPIBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { + return b.eth.miner.Pending() } func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { // Pending state is only known by the miner if number == rpc.PendingBlockNumber { - block, state := b.eth.miner.Pending() + block, _, state := b.eth.miner.Pending() if block == nil || state == nil { return nil, nil, errors.New("pending state is not available") } @@ -267,10 +266,6 @@ func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEven return b.eth.BlockChain().SubscribeRemovedLogsEvent(ch) } -func (b *EthAPIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { - return b.eth.miner.SubscribePendingLogs(ch) -} - func (b *EthAPIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return b.eth.BlockChain().SubscribeChainEvent(ch) } @@ -421,14 +416,6 @@ func (b *EthAPIBackend) CurrentHeader() *types.Header { return b.eth.blockchain.CurrentHeader() } -func (b *EthAPIBackend) Miner() *miner.Miner { - return b.eth.Miner() -} - -func (b *EthAPIBackend) StartMining() error { - return b.eth.StartMining() -} - func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtBlock(ctx, block, reexec, base, readOnly, preferDisk) } diff --git a/eth/api_debug.go b/eth/api_debug.go index 05010a3969c6..d5e4dda1401c 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -56,7 +56,7 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) { // If we're dumping the pending state, we need to request // both the pending block as well as the pending state from // the miner and operate on those - _, stateDb := api.eth.miner.Pending() + _, _, stateDb := api.eth.miner.Pending() if stateDb == nil { return state.Dump{}, errors.New("pending state is not available") } @@ -142,7 +142,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex // If we're dumping the pending state, we need to request // both the pending block as well as the pending state from // the miner and operate on those - _, stateDb = api.eth.miner.Pending() + _, _, stateDb = api.eth.miner.Pending() if stateDb == nil { return state.Dump{}, errors.New("pending state is not available") } diff --git a/eth/api_miner.go b/eth/api_miner.go index 764d0ae5e2f5..8c96f4c54aff 100644 --- a/eth/api_miner.go +++ b/eth/api_miner.go @@ -18,9 +18,7 @@ package eth import ( "math/big" - "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -34,21 +32,6 @@ func NewMinerAPI(e *Ethereum) *MinerAPI { return &MinerAPI{e} } -// Start starts the miner with the given number of threads. If threads is nil, -// the number of workers started is equal to the number of logical CPUs that are -// usable by this process. If mining is already running, this method adjust the -// number of threads allowed to use and updates the minimum price required by the -// transaction pool. -func (api *MinerAPI) Start() error { - return api.e.StartMining() -} - -// Stop terminates the miner, both at the consensus engine level as well as at -// the block creation level. -func (api *MinerAPI) Stop() { - api.e.StopMining() -} - // SetExtra sets the extra data string that is included when this miner mines a block. func (api *MinerAPI) SetExtra(extra string) (bool, error) { if err := api.e.Miner().SetExtra([]byte(extra)); err != nil { @@ -73,14 +56,3 @@ func (api *MinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool { api.e.Miner().SetGasCeil(uint64(gasLimit)) return true } - -// SetEtherbase sets the etherbase of the miner. -func (api *MinerAPI) SetEtherbase(etherbase common.Address) bool { - api.e.SetEtherbase(etherbase) - return true -} - -// SetRecommitInterval updates the interval for miner sealing work recommitting. -func (api *MinerAPI) SetRecommitInterval(interval int) { - api.e.Miner().SetRecommitInterval(time.Duration(interval) * time.Millisecond) -} diff --git a/eth/backend.go b/eth/backend.go index f6c1637acadf..81d84028a5f8 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -28,8 +28,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/beacon" - "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" @@ -88,9 +86,8 @@ type Ethereum struct { APIBackend *EthAPIBackend - miner *miner.Miner - gasPrice *big.Int - etherbase common.Address + miner *miner.Miner + gasPrice *big.Int networkID uint64 netRPCService *ethapi.NetAPI @@ -164,7 +161,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { closeBloomHandler: make(chan struct{}), networkID: networkID, gasPrice: config.Miner.GasPrice, - etherbase: config.Miner.Etherbase, bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), p2pServer: stack.Server(), @@ -211,7 +207,11 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.OverrideVerkle != nil { overrides.OverrideVerkle = config.OverrideVerkle } - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TransactionHistory) + // TODO (MariusVanDerWijden) get rid of shouldPreserve in a follow-up PR + shouldPreserve := func(header *types.Header) bool { + return false + } + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, shouldPreserve, &config.TransactionHistory) if err != nil { return nil, err } @@ -247,7 +247,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { return nil, err } - eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine, eth.isLocalBlock) + eth.miner = miner.New(eth, config.Miner, eth.engine) eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil} @@ -313,9 +313,6 @@ func (s *Ethereum) APIs() []rpc.API { // Append all the local APIs and return return append(apis, []rpc.API{ { - Namespace: "eth", - Service: NewEthereumAPI(s), - }, { Namespace: "miner", Service: NewMinerAPI(s), }, { @@ -338,138 +335,6 @@ func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { s.blockchain.ResetWithGenesisBlock(gb) } -func (s *Ethereum) Etherbase() (eb common.Address, err error) { - s.lock.RLock() - etherbase := s.etherbase - s.lock.RUnlock() - - if etherbase != (common.Address{}) { - return etherbase, nil - } - return common.Address{}, errors.New("etherbase must be explicitly specified") -} - -// isLocalBlock checks whether the specified block is mined -// by local miner accounts. -// -// We regard two types of accounts as local miner account: etherbase -// and accounts specified via `txpool.locals` flag. -func (s *Ethereum) isLocalBlock(header *types.Header) bool { - author, err := s.engine.Author(header) - if err != nil { - log.Warn("Failed to retrieve block author", "number", header.Number.Uint64(), "hash", header.Hash(), "err", err) - return false - } - // Check whether the given address is etherbase. - s.lock.RLock() - etherbase := s.etherbase - s.lock.RUnlock() - if author == etherbase { - return true - } - // Check whether the given address is specified by `txpool.local` - // CLI flag. - for _, account := range s.config.TxPool.Locals { - if account == author { - return true - } - } - return false -} - -// shouldPreserve checks whether we should preserve the given block -// during the chain reorg depending on whether the author of block -// is a local account. -func (s *Ethereum) shouldPreserve(header *types.Header) bool { - // The reason we need to disable the self-reorg preserving for clique - // is it can be probable to introduce a deadlock. - // - // e.g. If there are 7 available signers - // - // r1 A - // r2 B - // r3 C - // r4 D - // r5 A [X] F G - // r6 [X] - // - // In the round5, the in-turn signer E is offline, so the worst case - // is A, F and G sign the block of round5 and reject the block of opponents - // and in the round6, the last available signer B is offline, the whole - // network is stuck. - if _, ok := s.engine.(*clique.Clique); ok { - return false - } - return s.isLocalBlock(header) -} - -// SetEtherbase sets the mining reward address. -func (s *Ethereum) SetEtherbase(etherbase common.Address) { - s.lock.Lock() - s.etherbase = etherbase - s.lock.Unlock() - - s.miner.SetEtherbase(etherbase) -} - -// StartMining starts the miner with the given number of CPU threads. If mining -// is already running, this method adjust the number of threads allowed to use -// and updates the minimum price required by the transaction pool. -func (s *Ethereum) StartMining() error { - // If the miner was not running, initialize it - if !s.IsMining() { - // Propagate the initial price point to the transaction pool - s.lock.RLock() - price := s.gasPrice - s.lock.RUnlock() - s.txPool.SetGasTip(price) - - // Configure the local mining address - eb, err := s.Etherbase() - if err != nil { - log.Error("Cannot start mining without etherbase", "err", err) - return fmt.Errorf("etherbase missing: %v", err) - } - var cli *clique.Clique - if c, ok := s.engine.(*clique.Clique); ok { - cli = c - } else if cl, ok := s.engine.(*beacon.Beacon); ok { - if c, ok := cl.InnerEngine().(*clique.Clique); ok { - cli = c - } - } - if cli != nil { - wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) - if wallet == nil || err != nil { - log.Error("Etherbase account unavailable locally", "err", err) - return fmt.Errorf("signer missing: %v", err) - } - cli.Authorize(eb, wallet.SignData) - } - // If mining is started, we can disable the transaction rejection mechanism - // introduced to speed sync times. - s.handler.enableSyncedFeatures() - - go s.miner.Start() - } - return nil -} - -// StopMining terminates the miner, both at the consensus engine level as well as -// at the block creation level. -func (s *Ethereum) StopMining() { - // Update the thread count within the consensus engine - type threaded interface { - SetThreads(threads int) - } - if th, ok := s.engine.(threaded); ok { - th.SetThreads(-1) - } - // Stop the block creating itself - s.miner.Stop() -} - -func (s *Ethereum) IsMining() bool { return s.miner.Mining() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } @@ -531,7 +396,6 @@ func (s *Ethereum) Stop() error { s.bloomIndexer.Close() close(s.closeBloomHandler) s.txPool.Close() - s.miner.Close() s.blockchain.Stop() s.engine.Close() diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index a82e2d6cf6f2..a88996744c04 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -447,7 +447,9 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) t.Fatal("can't create node:", err) } - ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256} + mcfg := miner.DefaultConfig + mcfg.PendingFeeRecipient = testAddr + ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256, Miner: mcfg} ethservice, err := eth.New(n, ethcfg) if err != nil { t.Fatal("can't create eth service:", err) @@ -460,7 +462,6 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) t.Fatal("can't import test blocks:", err) } - ethservice.SetEtherbase(testAddr) ethservice.SetSynced() return n, ethservice } diff --git a/eth/catalyst/simulated_beacon_test.go b/eth/catalyst/simulated_beacon_test.go index 6fa97ad87a2a..df682b49d96e 100644 --- a/eth/catalyst/simulated_beacon_test.go +++ b/eth/catalyst/simulated_beacon_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" @@ -48,7 +49,7 @@ func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis) (*node. t.Fatal("can't create node:", err) } - ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256} + ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256, Miner: miner.DefaultConfig} ethservice, err := eth.New(n, ethcfg) if err != nil { t.Fatal("can't create eth service:", err) diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 83e3284a2b5b..f2b92d5a99da 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -333,7 +333,7 @@ func (f *Filter) checkMatches(ctx context.Context, header *types.Header) ([]*typ // pendingLogs returns the logs matching the filter criteria within the pending block. func (f *Filter) pendingLogs() []*types.Log { - block, receipts := f.sys.backend.PendingBlockAndReceipts() + block, receipts, _ := f.sys.backend.Pending() if block == nil || receipts == nil { return nil } diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index f98a1f84ce14..c32b837eb477 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "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/ethdb" "github.com/ethereum/go-ethereum/event" @@ -62,7 +63,7 @@ type Backend interface { GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) - PendingBlockAndReceipts() (*types.Block, types.Receipts) + Pending() (*types.Block, types.Receipts, *state.StateDB) CurrentHeader() *types.Header ChainConfig() *params.ChainConfig @@ -70,7 +71,6 @@ type Backend interface { SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription - SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription BloomStatus() (uint64, uint64) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) @@ -198,20 +198,18 @@ type EventSystem struct { lastHead *types.Header // Subscriptions - txsSub event.Subscription // Subscription for new transaction event - logsSub event.Subscription // Subscription for new log event - rmLogsSub event.Subscription // Subscription for removed log event - pendingLogsSub event.Subscription // Subscription for pending log event - chainSub event.Subscription // Subscription for new chain event + txsSub event.Subscription // Subscription for new transaction event + logsSub event.Subscription // Subscription for new log event + rmLogsSub event.Subscription // Subscription for removed log event + chainSub event.Subscription // Subscription for new chain event // Channels - install chan *subscription // install filter for event notification - uninstall chan *subscription // remove filter for event notification - txsCh chan core.NewTxsEvent // Channel to receive new transactions event - logsCh chan []*types.Log // Channel to receive new log event - pendingLogsCh chan []*types.Log // Channel to receive new log event - rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event - chainCh chan core.ChainEvent // Channel to receive new chain event + install chan *subscription // install filter for event notification + uninstall chan *subscription // remove filter for event notification + txsCh chan core.NewTxsEvent // Channel to receive new transactions event + logsCh chan []*types.Log // Channel to receive new log event + rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event + chainCh chan core.ChainEvent // Channel to receive new chain event } // NewEventSystem creates a new manager that listens for event on the given mux, @@ -222,16 +220,15 @@ type EventSystem struct { // or by stopping the given mux. func NewEventSystem(sys *FilterSystem, lightMode bool) *EventSystem { m := &EventSystem{ - sys: sys, - backend: sys.backend, - lightMode: lightMode, - install: make(chan *subscription), - uninstall: make(chan *subscription), - txsCh: make(chan core.NewTxsEvent, txChanSize), - logsCh: make(chan []*types.Log, logsChanSize), - rmLogsCh: make(chan core.RemovedLogsEvent, rmLogsChanSize), - pendingLogsCh: make(chan []*types.Log, logsChanSize), - chainCh: make(chan core.ChainEvent, chainEvChanSize), + sys: sys, + backend: sys.backend, + lightMode: lightMode, + install: make(chan *subscription), + uninstall: make(chan *subscription), + txsCh: make(chan core.NewTxsEvent, txChanSize), + logsCh: make(chan []*types.Log, logsChanSize), + rmLogsCh: make(chan core.RemovedLogsEvent, rmLogsChanSize), + chainCh: make(chan core.ChainEvent, chainEvChanSize), } // Subscribe events @@ -239,10 +236,9 @@ func NewEventSystem(sys *FilterSystem, lightMode bool) *EventSystem { m.logsSub = m.backend.SubscribeLogsEvent(m.logsCh) m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh) m.chainSub = m.backend.SubscribeChainEvent(m.chainCh) - m.pendingLogsSub = m.backend.SubscribePendingLogsEvent(m.pendingLogsCh) // Make sure none of the subscriptions are empty - if m.txsSub == nil || m.logsSub == nil || m.rmLogsSub == nil || m.chainSub == nil || m.pendingLogsSub == nil { + if m.txsSub == nil || m.logsSub == nil || m.rmLogsSub == nil || m.chainSub == nil { log.Crit("Subscribe for event system failed") } @@ -434,12 +430,12 @@ func (es *EventSystem) handleLogs(filters filterIndex, ev []*types.Log) { } } -func (es *EventSystem) handlePendingLogs(filters filterIndex, ev []*types.Log) { - if len(ev) == 0 { +func (es *EventSystem) handlePendingLogs(filters filterIndex, logs []*types.Log) { + if len(logs) == 0 { return } for _, f := range filters[PendingLogsSubscription] { - matchedLogs := filterLogs(ev, nil, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics) + matchedLogs := filterLogs(logs, nil, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics) if len(matchedLogs) > 0 { f.logs <- matchedLogs } @@ -550,7 +546,6 @@ func (es *EventSystem) eventLoop() { es.txsSub.Unsubscribe() es.logsSub.Unsubscribe() es.rmLogsSub.Unsubscribe() - es.pendingLogsSub.Unsubscribe() es.chainSub.Unsubscribe() }() @@ -567,10 +562,29 @@ func (es *EventSystem) eventLoop() { es.handleLogs(index, ev) case ev := <-es.rmLogsCh: es.handleLogs(index, ev.Logs) - case ev := <-es.pendingLogsCh: - es.handlePendingLogs(index, ev) case ev := <-es.chainCh: es.handleChainEvent(index, ev) + // If we have no pending log subscription, + // we don't need to collect any pending logs. + if len(index[PendingLogsSubscription]) == 0 { + continue + } + + // Pull the pending logs if there is a new chain head. + pendingBlock, pendingReceipts, _ := es.backend.Pending() + if pendingBlock == nil || pendingReceipts == nil { + continue + } + if pendingBlock.ParentHash() != ev.Block.Hash() { + continue + } + var logs []*types.Log + for _, receipt := range pendingReceipts { + if len(receipt.Logs) > 0 { + logs = append(logs, receipt.Logs...) + } + } + es.handlePendingLogs(index, logs) case f := <-es.install: if f.typ == MinedAndPendingLogsSubscription { diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 99c012cc84f4..6238c9773522 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "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/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -48,7 +49,6 @@ type testBackend struct { txFeed event.Feed logsFeed event.Feed rmLogsFeed event.Feed - pendingLogsFeed event.Feed chainFeed event.Feed pendingBlock *types.Block pendingReceipts types.Receipts @@ -125,8 +125,8 @@ func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash, number uint return logs, nil } -func (b *testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { - return b.pendingBlock, b.pendingReceipts +func (b *testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { + return b.pendingBlock, b.pendingReceipts, nil } func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { @@ -141,10 +141,6 @@ func (b *testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript return b.logsFeed.Subscribe(ch) } -func (b *testBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { - return b.pendingLogsFeed.Subscribe(ch) -} - func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return b.chainFeed.Subscribe(ch) } @@ -180,6 +176,20 @@ func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.Matc }() } +func (b *testBackend) setPending(block *types.Block, receipts types.Receipts) { + b.pendingBlock = block + b.pendingReceipts = receipts +} + +func (b *testBackend) notifyPending(logs []*types.Log) { + genesis := &core.Genesis{ + Config: params.TestChainConfig, + } + _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 2, func(i int, b *core.BlockGen) {}) + b.setPending(blocks[1], []*types.Receipt{{Logs: logs}}) + b.chainFeed.Send(core.ChainEvent{Block: blocks[0]}) +} + func newTestFilterSystem(t testing.TB, db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) { backend := &testBackend{db: db} sys := NewFilterSystem(backend, cfg) @@ -203,7 +213,7 @@ func TestBlockSubscription(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), } _, chain, _ = core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 10, func(i int, gen *core.BlockGen) {}) - chainEvents = []core.ChainEvent{} + chainEvents []core.ChainEvent ) for _, blk := range chain { @@ -386,7 +396,7 @@ func TestLogFilterCreation(t *testing.T) { {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, // from block "higher" than to block {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false}, - // topics more then 4 + // topics more than 4 {FilterCriteria{Topics: [][]common.Hash{{}, {}, {}, {}, {}}}, false}, } ) @@ -546,9 +556,9 @@ func TestLogFilter(t *testing.T) { if nsend := backend.logsFeed.Send(allLogs); nsend == 0 { t.Fatal("Logs event not delivered") } - if nsend := backend.pendingLogsFeed.Send(allLogs); nsend == 0 { - t.Fatal("Pending logs event not delivered") - } + + // set pending logs + backend.notifyPending(allLogs) for i, tt := range testCases { var fetched []*types.Log @@ -754,10 +764,12 @@ func TestPendingLogsSubscription(t *testing.T) { }() } - // raise events - for _, ev := range allLogs { - backend.pendingLogsFeed.Send(ev) + // set pending logs + var flattenLogs []*types.Log + for _, logs := range allLogs { + flattenLogs = append(flattenLogs, logs...) } + backend.notifyPending(flattenLogs) for i := range testCases { err := <-testCases[i].err diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 659ca5ce197d..48aaa584dbb1 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -109,8 +109,8 @@ func BenchmarkFilters(b *testing.B) { func TestFilters(t *testing.T) { var ( - db = rawdb.NewMemoryDatabase() - _, sys = newTestFilterSystem(t, db, Config{}) + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(t, db, Config{}) // Sender account key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key1.PublicKey) @@ -277,8 +277,7 @@ func TestFilters(t *testing.T) { }), signer, key1) gen.AddTx(tx) }) - sys.backend.(*testBackend).pendingBlock = pchain[0] - sys.backend.(*testBackend).pendingReceipts = preceipts[0] + backend.setPending(pchain[0], preceipts[0]) for i, tc := range []struct { f *Filter diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index d657eb6d996b..8ab57294b7e8 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -160,7 +160,7 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNum ) switch reqEnd { case rpc.PendingBlockNumber: - if pendingBlock, pendingReceipts = oracle.backend.PendingBlockAndReceipts(); pendingBlock != nil { + if pendingBlock, pendingReceipts, _ = oracle.backend.Pending(); pendingBlock != nil { resolved = pendingBlock.Header() } else { // Pending block not supported by backend, process only until latest block. diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index b71964981145..3fa70e41a094 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" @@ -54,7 +55,7 @@ type OracleBackend interface { HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) - PendingBlockAndReceipts() (*types.Block, types.Receipts) + Pending() (*types.Block, types.Receipts, *state.StateDB) ChainConfig() *params.ChainConfig SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription } diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 79217502f799..1d2e02cde6e1 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "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" @@ -97,12 +98,13 @@ func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types. return b.chain.GetReceiptsByHash(hash), nil } -func (b *testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { +func (b *testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { if b.pending { block := b.chain.GetBlockByNumber(testHead + 1) - return block, b.chain.GetReceiptsByHash(block.Hash()) + state, _ := b.chain.StateAt(block.Root()) + return block, b.chain.GetReceiptsByHash(block.Hash()), state } - return nil, nil + return nil, nil, nil } func (b *testBackend) ChainConfig() *params.ChainConfig { diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 0d2675f8d10d..2f3229cedcb5 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -602,17 +602,22 @@ func testAtFunctions(t *testing.T, client *rpc.Client) { } // send a transaction for some interesting pending status + // and wait for the transaction to be included in the pending block sendTransaction(ec) - time.Sleep(100 * time.Millisecond) - // Check pending transaction count - pending, err := ec.PendingTransactionCount(context.Background()) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if pending != 1 { - t.Fatalf("unexpected pending, wanted 1 got: %v", pending) + // wait for the transaction to be included in the pending block + for { + // Check pending transaction count + pending, err := ec.PendingTransactionCount(context.Background()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if pending == 1 { + break + } + time.Sleep(100 * time.Millisecond) } + // Query balance balance, err := ec.BalanceAt(context.Background(), testAddr, nil) if err != nil { @@ -737,7 +742,7 @@ func sendTransaction(ec *Client) error { if err != nil { return err } - nonce, err := ec.PendingNonceAt(context.Background(), testAddr) + nonce, err := ec.NonceAt(context.Background(), testAddr, nil) if err != nil { return err } diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index 61ceec443ebc..6e71666ec121 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -39,7 +39,6 @@ import ( ethproto "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" @@ -80,13 +79,6 @@ type fullNodeBackend interface { SuggestGasTipCap(ctx context.Context) (*big.Int, error) } -// miningNodeBackend encompasses the functionality necessary for a mining node -// reporting to ethstats -type miningNodeBackend interface { - fullNodeBackend - Miner() *miner.Miner -} - // Service implements an Ethereum netstats reporting daemon that pushes local // chain statistics up to a monitoring server. type Service struct { @@ -777,30 +769,21 @@ func (s *Service) reportPending(conn *connWrapper) error { type nodeStats struct { Active bool `json:"active"` Syncing bool `json:"syncing"` - Mining bool `json:"mining"` - Hashrate int `json:"hashrate"` Peers int `json:"peers"` GasPrice int `json:"gasPrice"` Uptime int `json:"uptime"` } -// reportStats retrieves various stats about the node at the networking and -// mining layer and reports it to the stats server. +// reportStats retrieves various stats about the node at the networking layer +// and reports it to the stats server. func (s *Service) reportStats(conn *connWrapper) error { - // Gather the syncing and mining infos from the local miner instance + // Gather the syncing infos from the local miner instance var ( - mining bool - hashrate int syncing bool gasprice int ) // check if backend is a full node if fullBackend, ok := s.backend.(fullNodeBackend); ok { - if miningBackend, ok := s.backend.(miningNodeBackend); ok { - mining = miningBackend.Miner().Mining() - hashrate = int(miningBackend.Miner().Hashrate()) - } - sync := fullBackend.SyncProgress() syncing = !sync.Done() @@ -820,8 +803,6 @@ func (s *Service) reportStats(conn *connWrapper) error { "id": s.node, "stats": &nodeStats{ Active: true, - Mining: mining, - Hashrate: hashrate, Peers: s.server.PeerCount(), GasPrice: gasprice, Syncing: syncing, diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 1d0383daad03..3f69f861444c 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -547,7 +547,7 @@ func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOr } panic("only implemented for number") } -func (b testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { panic("implement me") } +func (b testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { panic("implement me") } func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { header, err := b.HeaderByHash(ctx, hash) if header == nil || err != nil { @@ -615,9 +615,6 @@ func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { panic("implement me") } -func (b testBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { - panic("implement me") -} func (b testBackend) BloomStatus() (uint64, uint64) { panic("implement me") } func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { panic("implement me") diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 5f408ba20ba5..fd2f5699eabf 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -65,7 +65,7 @@ type Backend interface { BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) - PendingBlockAndReceipts() (*types.Block, types.Receipts) + Pending() (*types.Block, types.Receipts, *state.StateDB) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetTd(ctx context.Context, hash common.Hash) *big.Int GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM @@ -94,7 +94,6 @@ type Backend interface { GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription - SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription BloomStatus() (uint64, uint64) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) } diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 1b1634b25031..24ecb1dee4e7 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -358,7 +358,7 @@ func (b *backendMock) StateAndHeaderByNumber(ctx context.Context, number rpc.Blo func (b *backendMock) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { return nil, nil, nil } -func (b *backendMock) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return nil, nil } +func (b *backendMock) Pending() (*types.Block, types.Receipts, *state.StateDB) { return nil, nil, nil } func (b *backendMock) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { return nil, nil } @@ -396,9 +396,6 @@ func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscr func (b *backendMock) BloomStatus() (uint64, uint64) { return 0, 0 } func (b *backendMock) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {} func (b *backendMock) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return nil } -func (b *backendMock) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { - return nil -} func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { return nil } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index b86b5909d2cb..1da7d737dd94 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -649,20 +649,6 @@ const MinerJs = ` web3._extend({ property: 'miner', methods: [ - new web3._extend.Method({ - name: 'start', - call: 'miner_start', - }), - new web3._extend.Method({ - name: 'stop', - call: 'miner_stop' - }), - new web3._extend.Method({ - name: 'setEtherbase', - call: 'miner_setEtherbase', - params: 1, - inputFormatter: [web3._extend.formatters.inputAddressFormatter] - }), new web3._extend.Method({ name: 'setExtra', call: 'miner_setExtra', @@ -680,15 +666,6 @@ web3._extend({ params: 1, inputFormatter: [web3._extend.utils.fromDecimal] }), - new web3._extend.Method({ - name: 'setRecommitInterval', - call: 'miner_setRecommitInterval', - params: 1, - }), - new web3._extend.Method({ - name: 'getHashrate', - call: 'miner_getHashrate' - }), ], properties: [] }); diff --git a/miner/miner.go b/miner/miner.go index 58bb71b557b8..430efcb2fcf1 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -30,9 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -45,207 +42,124 @@ type Backend interface { // Config is the configuration parameters of mining. type Config struct { - Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards - ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner - GasFloor uint64 // Target gas floor for mined blocks. - GasCeil uint64 // Target gas ceiling for mined blocks. - GasPrice *big.Int // Minimum gas price for mining a transaction - Recommit time.Duration // The time interval for miner to re-create mining work. - - NewPayloadTimeout time.Duration // The maximum time allowance for creating a new payload + Etherbase common.Address `toml:"-"` // Deprecated + PendingFeeRecipient common.Address `toml:"-"` // Address for pending block rewards. + ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner + GasCeil uint64 // Target gas ceiling for mined blocks. + GasPrice *big.Int // Minimum gas price for mining a transaction + Recommit time.Duration // The time interval for miner to re-create mining work. } // DefaultConfig contains default settings for miner. var DefaultConfig = Config{ - GasCeil: 30000000, + GasCeil: 30_000_000, GasPrice: big.NewInt(params.GWei), // The default recommit time is chosen as two seconds since // consensus-layer usually will wait a half slot of time(6s) // for payload generation. It should be enough for Geth to // run 3 rounds. - Recommit: 2 * time.Second, - NewPayloadTimeout: 2 * time.Second, + Recommit: 2 * time.Second, } -// Miner creates blocks and searches for proof-of-work values. +// Miner is the main object which takes care of submitting new work to consensus +// engine and gathering the sealing result. type Miner struct { - mux *event.TypeMux - eth Backend - engine consensus.Engine - exitCh chan struct{} - startCh chan struct{} - stopCh chan struct{} - worker *worker - - wg sync.WaitGroup -} - -func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(header *types.Header) bool) *Miner { - miner := &Miner{ - mux: mux, - eth: eth, - engine: engine, - exitCh: make(chan struct{}), - startCh: make(chan struct{}), - stopCh: make(chan struct{}), - worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true), - } - miner.wg.Add(1) - go miner.update() - return miner -} - -// update keeps track of the downloader events. Please be aware that this is a one shot type of update loop. -// It's entered once and as soon as `Done` or `Failed` has been broadcasted the events are unregistered and -// the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks -// and halt your mining operation for as long as the DOS continues. -func (miner *Miner) update() { - defer miner.wg.Done() - - events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{}) - defer func() { - if !events.Closed() { - events.Unsubscribe() - } - }() - - shouldStart := false - canStart := true - dlEventCh := events.Chan() - for { - select { - case ev := <-dlEventCh: - if ev == nil { - // Unsubscription done, stop listening - dlEventCh = nil - continue - } - switch ev.Data.(type) { - case downloader.StartEvent: - wasMining := miner.Mining() - miner.worker.stop() - canStart = false - if wasMining { - // Resume mining after sync was finished - shouldStart = true - log.Info("Mining aborted due to sync") - } - miner.worker.syncing.Store(true) - - case downloader.FailedEvent: - canStart = true - if shouldStart { - miner.worker.start() - } - miner.worker.syncing.Store(false) - - case downloader.DoneEvent: - canStart = true - if shouldStart { - miner.worker.start() - } - miner.worker.syncing.Store(false) - - // Stop reacting to downloader events - events.Unsubscribe() - } - case <-miner.startCh: - if canStart { - miner.worker.start() - } - shouldStart = true - case <-miner.stopCh: - shouldStart = false - miner.worker.stop() - case <-miner.exitCh: - miner.worker.close() - return - } + confMu sync.RWMutex // The lock used to protect the config fields: GasCeil, GasTip and Extradata + config *Config + chainConfig *params.ChainConfig + engine consensus.Engine + txpool *txpool.TxPool + chain *core.BlockChain + pending *pending + pendingMu sync.Mutex // Lock protects the pending block +} + +// New creates a new miner with provided config. +func New(eth Backend, config Config, engine consensus.Engine) *Miner { + return &Miner{ + config: &config, + chainConfig: eth.BlockChain().Config(), + engine: engine, + txpool: eth.TxPool(), + chain: eth.BlockChain(), + pending: &pending{}, } } -func (miner *Miner) Start() { - miner.startCh <- struct{}{} -} - -func (miner *Miner) Stop() { - miner.stopCh <- struct{}{} -} - -func (miner *Miner) Close() { - close(miner.exitCh) - miner.wg.Wait() -} - -func (miner *Miner) Mining() bool { - return miner.worker.isRunning() -} - -func (miner *Miner) Hashrate() uint64 { - if pow, ok := miner.engine.(consensus.PoW); ok { - return uint64(pow.Hashrate()) +// Pending returns the currently pending block and associated receipts, logs +// and statedb. The returned values can be nil in case the pending block is +// not initialized. +func (miner *Miner) Pending() (*types.Block, types.Receipts, *state.StateDB) { + pending := miner.getPending() + if pending == nil { + return nil, nil, nil } - return 0 + return pending.block, pending.receipts, pending.stateDB.Copy() } +// SetExtra sets the content used to initialize the block extra field. func (miner *Miner) SetExtra(extra []byte) error { if uint64(len(extra)) > params.MaximumExtraDataSize { return fmt.Errorf("extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize) } - miner.worker.setExtra(extra) + miner.confMu.Lock() + miner.config.ExtraData = extra + miner.confMu.Unlock() return nil } -func (miner *Miner) SetGasTip(tip *big.Int) error { - miner.worker.setGasTip(tip) - return nil -} - -// SetRecommitInterval sets the interval for sealing work resubmitting. -func (miner *Miner) SetRecommitInterval(interval time.Duration) { - miner.worker.setRecommitInterval(interval) -} - -// Pending returns the currently pending block and associated state. The returned -// values can be nil in case the pending block is not initialized -func (miner *Miner) Pending() (*types.Block, *state.StateDB) { - return miner.worker.pending() -} - -// PendingBlock returns the currently pending block. The returned block can be -// nil in case the pending block is not initialized. -// -// Note, to access both the pending block and the pending state -// simultaneously, please use Pending(), as the pending state can -// change between multiple method calls -func (miner *Miner) PendingBlock() *types.Block { - return miner.worker.pendingBlock() -} - -// PendingBlockAndReceipts returns the currently pending block and corresponding receipts. -// The returned values can be nil in case the pending block is not initialized. -func (miner *Miner) PendingBlockAndReceipts() (*types.Block, types.Receipts) { - return miner.worker.pendingBlockAndReceipts() -} - -func (miner *Miner) SetEtherbase(addr common.Address) { - miner.worker.setEtherbase(addr) -} - // SetGasCeil sets the gaslimit to strive for when mining blocks post 1559. // For pre-1559 blocks, it sets the ceiling. func (miner *Miner) SetGasCeil(ceil uint64) { - miner.worker.setGasCeil(ceil) + miner.confMu.Lock() + miner.config.GasCeil = ceil + miner.confMu.Unlock() } -// SubscribePendingLogs starts delivering logs from pending transactions -// to the given channel. -func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription { - return miner.worker.pendingLogsFeed.Subscribe(ch) +// SetGasTip sets the minimum gas tip for inclusion. +func (miner *Miner) SetGasTip(tip *big.Int) error { + miner.confMu.Lock() + miner.config.GasPrice = tip + miner.confMu.Unlock() + return nil } // BuildPayload builds the payload according to the provided parameters. func (miner *Miner) BuildPayload(args *BuildPayloadArgs) (*Payload, error) { - return miner.worker.buildPayload(args) + return miner.buildPayload(args) +} + +// getPending retrieves the pending block based on the current head block. +// The result might be nil if pending generation is failed. +func (miner *Miner) getPending() *newPayloadResult { + header := miner.chain.CurrentHeader() + miner.pendingMu.Lock() + defer miner.pendingMu.Unlock() + if cached := miner.pending.resolve(header.Hash()); cached != nil { + return cached + } + + var ( + timestamp = uint64(time.Now().Unix()) + withdrawal types.Withdrawals + ) + if miner.chainConfig.IsShanghai(new(big.Int).Add(header.Number, big.NewInt(1)), timestamp) { + withdrawal = []*types.Withdrawal{} + } + ret := miner.generateWork(&generateParams{ + timestamp: timestamp, + forceTime: false, + parentHash: header.Hash(), + coinbase: miner.config.PendingFeeRecipient, + random: common.Hash{}, + withdrawals: withdrawal, + beaconRoot: nil, + noTxs: false, + }) + if ret.err != nil { + return nil + } + miner.pending.update(header.Hash(), ret) + return ret } diff --git a/miner/miner_test.go b/miner/miner_test.go index 5907fb446466..7c39564240c1 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -18,10 +18,9 @@ package miner import ( - "errors" "math/big" + "sync" "testing" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/clique" @@ -33,7 +32,6 @@ import ( "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/eth/downloader" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" @@ -60,10 +58,6 @@ func (m *mockBackend) TxPool() *txpool.TxPool { return m.txPool } -func (m *mockBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { - return nil, errors.New("not supported") -} - type testBlockChain struct { root common.Hash config *params.ChainConfig @@ -99,171 +93,18 @@ func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) return bc.chainHeadFeed.Subscribe(ch) } -func TestMiner(t *testing.T) { - t.Parallel() - miner, mux, cleanup := createMiner(t) - defer cleanup(false) - - miner.Start() - waitForMiningState(t, miner, true) - // Start the downloader - mux.Post(downloader.StartEvent{}) - waitForMiningState(t, miner, false) - // Stop the downloader and wait for the update loop to run - mux.Post(downloader.DoneEvent{}) - waitForMiningState(t, miner, true) - - // Subsequent downloader events after a successful DoneEvent should not cause the - // miner to start or stop. This prevents a security vulnerability - // that would allow entities to present fake high blocks that would - // stop mining operations by causing a downloader sync - // until it was discovered they were invalid, whereon mining would resume. - mux.Post(downloader.StartEvent{}) - waitForMiningState(t, miner, true) - - mux.Post(downloader.FailedEvent{}) - waitForMiningState(t, miner, true) -} - -// TestMinerDownloaderFirstFails tests that mining is only -// permitted to run indefinitely once the downloader sees a DoneEvent (success). -// An initial FailedEvent should allow mining to stop on a subsequent -// downloader StartEvent. -func TestMinerDownloaderFirstFails(t *testing.T) { - t.Parallel() - miner, mux, cleanup := createMiner(t) - defer cleanup(false) - - miner.Start() - waitForMiningState(t, miner, true) - // Start the downloader - mux.Post(downloader.StartEvent{}) - waitForMiningState(t, miner, false) - - // Stop the downloader and wait for the update loop to run - mux.Post(downloader.FailedEvent{}) - waitForMiningState(t, miner, true) - - // Since the downloader hasn't yet emitted a successful DoneEvent, - // we expect the miner to stop on next StartEvent. - mux.Post(downloader.StartEvent{}) - waitForMiningState(t, miner, false) - - // Downloader finally succeeds. - mux.Post(downloader.DoneEvent{}) - waitForMiningState(t, miner, true) - - // Downloader starts again. - // Since it has achieved a DoneEvent once, we expect miner - // state to be unchanged. - mux.Post(downloader.StartEvent{}) - waitForMiningState(t, miner, true) - - mux.Post(downloader.FailedEvent{}) - waitForMiningState(t, miner, true) -} - -func TestMinerStartStopAfterDownloaderEvents(t *testing.T) { - t.Parallel() - miner, mux, cleanup := createMiner(t) - defer cleanup(false) - - miner.Start() - waitForMiningState(t, miner, true) - // Start the downloader - mux.Post(downloader.StartEvent{}) - waitForMiningState(t, miner, false) - - // Downloader finally succeeds. - mux.Post(downloader.DoneEvent{}) - waitForMiningState(t, miner, true) - - miner.Stop() - waitForMiningState(t, miner, false) - - miner.Start() - waitForMiningState(t, miner, true) - - miner.Stop() - waitForMiningState(t, miner, false) -} - -func TestStartWhileDownload(t *testing.T) { - t.Parallel() - miner, mux, cleanup := createMiner(t) - defer cleanup(false) - waitForMiningState(t, miner, false) - miner.Start() - waitForMiningState(t, miner, true) - // Stop the downloader and wait for the update loop to run - mux.Post(downloader.StartEvent{}) - waitForMiningState(t, miner, false) - // Starting the miner after the downloader should not work - miner.Start() - waitForMiningState(t, miner, false) -} - -func TestStartStopMiner(t *testing.T) { - t.Parallel() - miner, _, cleanup := createMiner(t) - defer cleanup(false) - waitForMiningState(t, miner, false) - miner.Start() - waitForMiningState(t, miner, true) - miner.Stop() - waitForMiningState(t, miner, false) -} - -func TestCloseMiner(t *testing.T) { - t.Parallel() - miner, _, cleanup := createMiner(t) - defer cleanup(true) - waitForMiningState(t, miner, false) - miner.Start() - waitForMiningState(t, miner, true) - // Terminate the miner and wait for the update loop to run - miner.Close() - waitForMiningState(t, miner, false) -} - -// TestMinerSetEtherbase checks that etherbase becomes set even if mining isn't -// possible at the moment -func TestMinerSetEtherbase(t *testing.T) { - t.Parallel() - miner, mux, cleanup := createMiner(t) - defer cleanup(false) - miner.Start() - waitForMiningState(t, miner, true) - // Start the downloader - mux.Post(downloader.StartEvent{}) - waitForMiningState(t, miner, false) - // Now user tries to configure proper mining address - miner.Start() - // Stop the downloader and wait for the update loop to run - mux.Post(downloader.DoneEvent{}) - waitForMiningState(t, miner, true) - - coinbase := common.HexToAddress("0xdeedbeef") - miner.SetEtherbase(coinbase) - if addr := miner.worker.etherbase(); addr != coinbase { - t.Fatalf("Unexpected etherbase want %x got %x", coinbase, addr) - } -} - -// waitForMiningState waits until either -// * the desired mining state was reached -// * a timeout was reached which fails the test -func waitForMiningState(t *testing.T, m *Miner, mining bool) { - t.Helper() - - var state bool - for i := 0; i < 100; i++ { - time.Sleep(10 * time.Millisecond) - if state = m.Mining(); state == mining { - return +func TestBuildPendingBlocks(t *testing.T) { + miner := createMiner(t) + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + block, _, _ := miner.Pending() + if block == nil { + t.Error("Pending failed") } - } - t.Fatalf("Mining() == %t, want %t", state, mining) + }() + wg.Wait() } func minerTestGenesisBlock(period uint64, gasLimit uint64, faucet common.Address) *core.Genesis { @@ -294,10 +135,11 @@ func minerTestGenesisBlock(period uint64, gasLimit uint64, faucet common.Address }, } } -func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { + +func createMiner(t *testing.T) *Miner { // Create Ethash config config := Config{ - Etherbase: common.HexToAddress("123456789"), + PendingFeeRecipient: common.HexToAddress("123456789"), } // Create chainConfig chainDB := rawdb.NewMemoryDatabase() @@ -320,18 +162,8 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { pool := legacypool.New(testTxPoolConfig, blockchain) txpool, _ := txpool.New(testTxPoolConfig.PriceLimit, blockchain, []txpool.SubPool{pool}) - backend := NewMockBackend(bc, txpool) - // Create event Mux - mux := new(event.TypeMux) // Create Miner - miner := New(backend, &config, chainConfig, mux, engine, nil) - cleanup := func(skipMiner bool) { - bc.Stop() - engine.Close() - txpool.Close() - if !skipMiner { - miner.Close() - } - } - return miner, mux, cleanup + backend := NewMockBackend(bc, txpool) + miner := New(backend, config, engine) + return miner } diff --git a/miner/payload_building.go b/miner/payload_building.go index 719736c4795c..cbdb82a642cf 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -46,7 +46,6 @@ type BuildPayloadArgs struct { // Id computes an 8-byte identifier by hashing the components of the payload arguments. func (args *BuildPayloadArgs) Id() engine.PayloadID { - // Hash hasher := sha256.New() hasher.Write(args.Parent[:]) binary.Write(hasher, binary.BigEndian, args.Timestamp) @@ -177,7 +176,7 @@ func (payload *Payload) ResolveFull() *engine.ExecutionPayloadEnvelope { } // buildPayload builds the payload according to the provided parameters. -func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { +func (miner *Miner) buildPayload(args *BuildPayloadArgs) (*Payload, error) { // Build the initial version with no transaction included. It should be fast // enough to run. The empty payload can at least make sure there is something // to deliver for not missing slot. @@ -191,7 +190,7 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { beaconRoot: args.BeaconRoot, noTxs: true, } - empty := w.getSealingBlock(emptyParams) + empty := miner.generateWork(emptyParams) if empty.err != nil { return nil, empty.err } @@ -227,11 +226,11 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { select { case <-timer.C: start := time.Now() - r := w.getSealingBlock(fullParams) + r := miner.generateWork(fullParams) if r.err == nil { payload.update(r, time.Since(start)) } - timer.Reset(w.recommit) + timer.Reset(miner.config.Recommit) case <-payload.stop: log.Info("Stopping work on payload", "id", payload.id, "reason", "delivery") return diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index 708072b5ecf2..1728b9e5bd59 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -17,26 +17,141 @@ package miner import ( + "math/big" "reflect" "testing" "time" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/legacypool" "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/params" ) +var ( + // Test chain configurations + testTxPoolConfig legacypool.Config + ethashChainConfig *params.ChainConfig + cliqueChainConfig *params.ChainConfig + + // Test accounts + testBankKey, _ = crypto.GenerateKey() + testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) + testBankFunds = big.NewInt(1000000000000000000) + + testUserKey, _ = crypto.GenerateKey() + testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey) + + // Test transactions + pendingTxs []*types.Transaction + newTxs []*types.Transaction + + testConfig = Config{ + PendingFeeRecipient: testBankAddress, + Recommit: time.Second, + GasCeil: params.GenesisGasLimit, + } +) + +func init() { + testTxPoolConfig = legacypool.DefaultConfig + testTxPoolConfig.Journal = "" + ethashChainConfig = new(params.ChainConfig) + *ethashChainConfig = *params.TestChainConfig + cliqueChainConfig = new(params.ChainConfig) + *cliqueChainConfig = *params.TestChainConfig + cliqueChainConfig.Clique = ¶ms.CliqueConfig{ + Period: 10, + Epoch: 30000, + } + + signer := types.LatestSigner(params.TestChainConfig) + tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{ + ChainID: params.TestChainConfig.ChainID, + Nonce: 0, + To: &testUserAddress, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: big.NewInt(params.InitialBaseFee), + }) + pendingTxs = append(pendingTxs, tx1) + + tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{ + Nonce: 1, + To: &testUserAddress, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: big.NewInt(params.InitialBaseFee), + }) + newTxs = append(newTxs, tx2) +} + +// testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. +type testWorkerBackend struct { + db ethdb.Database + txPool *txpool.TxPool + chain *core.BlockChain + genesis *core.Genesis +} + +func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { + var gspec = &core.Genesis{ + Config: chainConfig, + Alloc: types.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, + } + switch e := engine.(type) { + case *clique.Clique: + gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) + copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) + e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { + return crypto.Sign(crypto.Keccak256(data), testBankKey) + }) + case *ethash.Ethash: + default: + t.Fatalf("unexpected consensus engine type: %T", engine) + } + chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("core.NewBlockChain failed: %v", err) + } + pool := legacypool.New(testTxPoolConfig, chain) + txpool, _ := txpool.New(testTxPoolConfig.PriceLimit, chain, []txpool.SubPool{pool}) + + return &testWorkerBackend{ + db: db, + chain: chain, + txPool: txpool, + genesis: gspec, + } +} + +func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } +func (b *testWorkerBackend) TxPool() *txpool.TxPool { return b.txPool } + +func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*Miner, *testWorkerBackend) { + backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) + backend.txPool.Add(pendingTxs, true, false) + w := New(backend, testConfig, engine) + return w, backend +} + func TestBuildPayload(t *testing.T) { - t.Parallel() var ( db = rawdb.NewMemoryDatabase() recipient = common.HexToAddress("0xdeadbeef") ) w, b := newTestWorker(t, params.TestChainConfig, ethash.NewFaker(), db, 0) - defer w.close() timestamp := uint64(time.Now().Unix()) args := &BuildPayloadArgs{ diff --git a/miner/pending.go b/miner/pending.go new file mode 100644 index 000000000000..bb91fe89690a --- /dev/null +++ b/miner/pending.go @@ -0,0 +1,67 @@ +// Copyright 2024 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 miner + +import ( + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" +) + +// pendingTTL indicates the period of time a generated pending block should +// exist to serve RPC requests before being discarded if the parent block +// has not changed yet. The value is chosen to align with the recommit interval. +const pendingTTL = 2 * time.Second + +// pending wraps a pending block with additional metadata. +type pending struct { + created time.Time + parentHash common.Hash + result *newPayloadResult + lock sync.Mutex +} + +// resolve retrieves the cached pending result if it's available. Nothing will be +// returned if the parentHash is not matched or the result is already too old. +// +// Note, don't modify the returned payload result. +func (p *pending) resolve(parentHash common.Hash) *newPayloadResult { + p.lock.Lock() + defer p.lock.Unlock() + + if p.result == nil { + return nil + } + if parentHash != p.parentHash { + return nil + } + if time.Since(p.created) > pendingTTL { + return nil + } + return p.result +} + +// update refreshes the cached pending block with newly created one. +func (p *pending) update(parent common.Hash, result *newPayloadResult) { + p.lock.Lock() + defer p.lock.Unlock() + + p.parentHash = parent + p.result = result + p.created = time.Now() +} diff --git a/miner/stress/clique/main.go b/miner/stress/clique/main.go deleted file mode 100644 index 60593938458b..000000000000 --- a/miner/stress/clique/main.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 . - -// This file contains a miner stress test based on the Clique consensus engine. -package main - -import ( - "bytes" - "crypto/ecdsa" - "math/big" - "math/rand" - "os" - "os/signal" - "time" - - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/fdlimit" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/txpool/legacypool" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/miner" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/params" -) - -func main() { - log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) - fdlimit.Raise(2048) - - // Generate a batch of accounts to seal and fund with - faucets := make([]*ecdsa.PrivateKey, 128) - for i := 0; i < len(faucets); i++ { - faucets[i], _ = crypto.GenerateKey() - } - sealers := make([]*ecdsa.PrivateKey, 4) - for i := 0; i < len(sealers); i++ { - sealers[i], _ = crypto.GenerateKey() - } - // Create a Clique network based off of the Sepolia config - genesis := makeGenesis(faucets, sealers) - - // Handle interrupts. - interruptCh := make(chan os.Signal, 5) - signal.Notify(interruptCh, os.Interrupt) - - var ( - stacks []*node.Node - nodes []*eth.Ethereum - enodes []*enode.Node - ) - for _, sealer := range sealers { - // Start the node and wait until it's up - stack, ethBackend, err := makeSealer(genesis) - if err != nil { - panic(err) - } - defer stack.Close() - - for stack.Server().NodeInfo().Ports.Listener == 0 { - time.Sleep(250 * time.Millisecond) - } - // Connect the node to all the previous ones - for _, n := range enodes { - stack.Server().AddPeer(n) - } - // Start tracking the node and its enode - stacks = append(stacks, stack) - nodes = append(nodes, ethBackend) - enodes = append(enodes, stack.Server().Self()) - - // Inject the signer key and start sealing with it - ks := keystore.NewKeyStore(stack.KeyStoreDir(), keystore.LightScryptN, keystore.LightScryptP) - signer, err := ks.ImportECDSA(sealer, "") - if err != nil { - panic(err) - } - if err := ks.Unlock(signer, ""); err != nil { - panic(err) - } - stack.AccountManager().AddBackend(ks) - } - - // Iterate over all the nodes and start signing on them - time.Sleep(3 * time.Second) - for _, node := range nodes { - if err := node.StartMining(); err != nil { - panic(err) - } - } - time.Sleep(3 * time.Second) - - // Start injecting transactions from the faucet like crazy - nonces := make([]uint64, len(faucets)) - for { - // Stop when interrupted. - select { - case <-interruptCh: - for _, node := range stacks { - node.Close() - } - return - default: - } - - // Pick a random signer node - index := rand.Intn(len(faucets)) - backend := nodes[index%len(nodes)] - - // Create a self transaction and inject into the pool - tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000), nil), types.HomesteadSigner{}, faucets[index]) - if err != nil { - panic(err) - } - if err := backend.TxPool().Add([]*types.Transaction{tx}, true, false); err != nil { - panic(err) - } - nonces[index]++ - - // Wait if we're too saturated - if pend, _ := backend.TxPool().Stats(); pend > 2048 { - time.Sleep(100 * time.Millisecond) - } - } -} - -// makeGenesis creates a custom Clique genesis block based on some pre-defined -// signer and faucet accounts. -func makeGenesis(faucets []*ecdsa.PrivateKey, sealers []*ecdsa.PrivateKey) *core.Genesis { - // Create a Clique network based off of the Sepolia config - genesis := core.DefaultSepoliaGenesisBlock() - genesis.GasLimit = 25000000 - - genesis.Config.ChainID = big.NewInt(18) - genesis.Config.Clique.Period = 1 - - genesis.Alloc = types.GenesisAlloc{} - for _, faucet := range faucets { - genesis.Alloc[crypto.PubkeyToAddress(faucet.PublicKey)] = types.Account{ - Balance: new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil), - } - } - // Sort the signers and embed into the extra-data section - signers := make([]common.Address, len(sealers)) - for i, sealer := range sealers { - signers[i] = crypto.PubkeyToAddress(sealer.PublicKey) - } - for i := 0; i < len(signers); i++ { - for j := i + 1; j < len(signers); j++ { - if bytes.Compare(signers[i][:], signers[j][:]) > 0 { - signers[i], signers[j] = signers[j], signers[i] - } - } - } - genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+65) - for i, signer := range signers { - copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:]) - } - // Return the genesis block for initialization - return genesis -} - -func makeSealer(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { - // Define the basic configurations for the Ethereum node - datadir, _ := os.MkdirTemp("", "") - - config := &node.Config{ - Name: "geth", - Version: params.Version, - DataDir: datadir, - P2P: p2p.Config{ - ListenAddr: "0.0.0.0:0", - NoDiscovery: true, - MaxPeers: 25, - }, - } - // Start the node and configure a full Ethereum node on it - stack, err := node.New(config) - if err != nil { - return nil, nil, err - } - // Create and register the backend - ethBackend, err := eth.New(stack, ðconfig.Config{ - Genesis: genesis, - NetworkId: genesis.Config.ChainID.Uint64(), - SyncMode: downloader.FullSync, - DatabaseCache: 256, - DatabaseHandles: 256, - TxPool: legacypool.DefaultConfig, - GPO: ethconfig.Defaults.GPO, - Miner: miner.Config{ - GasCeil: genesis.GasLimit * 11 / 10, - GasPrice: big.NewInt(1), - Recommit: time.Second, - }, - }) - if err != nil { - return nil, nil, err - } - - err = stack.Start() - return stack, ethBackend, err -} diff --git a/miner/worker.go b/miner/worker.go index 134f91cafc4b..7e038b0f301b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -20,12 +20,10 @@ import ( "errors" "fmt" "math/big" - "sync" "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" @@ -33,47 +31,11 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/trie" "github.com/holiman/uint256" ) -const ( - // resultQueueSize is the size of channel listening to sealing result. - resultQueueSize = 10 - - // txChanSize is the size of channel listening to NewTxsEvent. - // The number is referenced from the size of tx pool. - txChanSize = 4096 - - // chainHeadChanSize is the size of channel listening to ChainHeadEvent. - chainHeadChanSize = 10 - - // resubmitAdjustChanSize is the size of resubmitting interval adjustment channel. - resubmitAdjustChanSize = 10 - - // minRecommitInterval is the minimal time interval to recreate the sealing block with - // any newly arrived transactions. - minRecommitInterval = 1 * time.Second - - // maxRecommitInterval is the maximum time interval to recreate the sealing block with - // any newly arrived transactions. - maxRecommitInterval = 15 * time.Second - - // intervalAdjustRatio is the impact a single interval adjustment has on sealing work - // resubmitting interval. - intervalAdjustRatio = 0.1 - - // intervalAdjustBias is applied during the new resubmit interval calculation in favor of - // increasing upper limit or decreasing lower limit so that the limit can be reachable. - intervalAdjustBias = 200 * 1000.0 * 1000.0 - - // staleThreshold is the maximum depth of the acceptable stale block. - staleThreshold = 7 -) - var ( errBlockInterruptedByNewHead = errors.New("new head arrived while building block") errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block") @@ -96,47 +58,6 @@ type environment struct { blobs int } -// copy creates a deep copy of environment. -func (env *environment) copy() *environment { - cpy := &environment{ - signer: env.signer, - state: env.state.Copy(), - tcount: env.tcount, - coinbase: env.coinbase, - header: types.CopyHeader(env.header), - receipts: copyReceipts(env.receipts), - } - if env.gasPool != nil { - gasPool := *env.gasPool - cpy.gasPool = &gasPool - } - cpy.txs = make([]*types.Transaction, len(env.txs)) - copy(cpy.txs, env.txs) - - cpy.sidecars = make([]*types.BlobTxSidecar, len(env.sidecars)) - copy(cpy.sidecars, env.sidecars) - - return cpy -} - -// discard terminates the background prefetcher go-routine. It should -// always be called for all created environment instances otherwise -// the go-routine leak can happen. -func (env *environment) discard() { - if env.state == nil { - return - } - env.state.StopPrefetcher() -} - -// task contains all information for consensus engine sealing and result submitting. -type task struct { - receipts []*types.Receipt - state *state.StateDB - block *types.Block - createdAt time.Time -} - const ( commitInterruptNone int32 = iota commitInterruptNewHead @@ -144,629 +65,174 @@ const ( commitInterruptTimeout ) -// newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. -type newWorkReq struct { - interrupt *atomic.Int32 - timestamp int64 -} - // newPayloadResult is the result of payload generation. type newPayloadResult struct { err error block *types.Block fees *big.Int // total block fees sidecars []*types.BlobTxSidecar // collected blobs of blob transactions + stateDB *state.StateDB // StateDB after executing the transactions + receipts []*types.Receipt // Receipts collected during construction } -// getWorkReq represents a request for getting a new sealing work with provided parameters. -type getWorkReq struct { - params *generateParams - result chan *newPayloadResult // non-blocking channel -} - -// intervalAdjust represents a resubmitting interval adjustment. -type intervalAdjust struct { - ratio float64 - inc bool -} - -// worker is the main object which takes care of submitting new work to consensus engine -// and gathering the sealing result. -type worker struct { - config *Config - chainConfig *params.ChainConfig - engine consensus.Engine - eth Backend - chain *core.BlockChain - - // Feeds - pendingLogsFeed event.Feed - - // Subscriptions - mux *event.TypeMux - txsCh chan core.NewTxsEvent - txsSub event.Subscription - chainHeadCh chan core.ChainHeadEvent - chainHeadSub event.Subscription - - // Channels - newWorkCh chan *newWorkReq - getWorkCh chan *getWorkReq - taskCh chan *task - resultCh chan *types.Block - startCh chan struct{} - exitCh chan struct{} - resubmitIntervalCh chan time.Duration - resubmitAdjustCh chan *intervalAdjust - - wg sync.WaitGroup - - current *environment // An environment for current running cycle. - - mu sync.RWMutex // The lock used to protect the coinbase and extra fields - coinbase common.Address - extra []byte - tip *uint256.Int // Minimum tip needed for non-local transaction to include them - - pendingMu sync.RWMutex - pendingTasks map[common.Hash]*task - - snapshotMu sync.RWMutex // The lock used to protect the snapshots below - snapshotBlock *types.Block - snapshotReceipts types.Receipts - snapshotState *state.StateDB - - // atomic status counters - running atomic.Bool // The indicator whether the consensus engine is running or not. - newTxs atomic.Int32 // New arrival transaction count since last sealing work submitting. - syncing atomic.Bool // The indicator whether the node is still syncing. - - // newpayloadTimeout is the maximum timeout allowance for creating payload. - // The default value is 2 seconds but node operator can set it to arbitrary - // large value. A large timeout allowance may cause Geth to fail creating - // a non-empty payload within the specified time and eventually miss the slot - // in case there are some computation expensive transactions in txpool. - newpayloadTimeout time.Duration - - // recommit is the time interval to re-create sealing work or to re-build - // payload in proof-of-stake stage. - recommit time.Duration - - // External functions - isLocalBlock func(header *types.Header) bool // Function used to determine whether the specified block is mined by local miner. - - // Test hooks - newTaskHook func(*task) // Method to call upon receiving a new sealing task. - skipSealHook func(*task) bool // Method to decide whether skipping the sealing. - fullTaskHook func() // Method to call before pushing the full sealing task. - resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. +// generateParams wraps various of settings for generating sealing task. +type generateParams struct { + timestamp uint64 // The timestamp for sealing task + forceTime bool // Flag whether the given timestamp is immutable or not + parentHash common.Hash // Parent block hash, empty means the latest chain head + coinbase common.Address // The fee recipient address for including transaction + random common.Hash // The randomness generated by beacon chain, empty before the merge + withdrawals types.Withdrawals // List of withdrawals to include in block (shanghai field) + beaconRoot *common.Hash // The beacon root (cancun field). + noTxs bool // Flag whether an empty block without any transaction is expected } -func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(header *types.Header) bool, init bool) *worker { - worker := &worker{ - config: config, - chainConfig: chainConfig, - engine: engine, - eth: eth, - chain: eth.BlockChain(), - mux: mux, - isLocalBlock: isLocalBlock, - coinbase: config.Etherbase, - extra: config.ExtraData, - tip: uint256.MustFromBig(config.GasPrice), - pendingTasks: make(map[common.Hash]*task), - txsCh: make(chan core.NewTxsEvent, txChanSize), - chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), - newWorkCh: make(chan *newWorkReq), - getWorkCh: make(chan *getWorkReq), - taskCh: make(chan *task), - resultCh: make(chan *types.Block, resultQueueSize), - startCh: make(chan struct{}, 1), - exitCh: make(chan struct{}), - resubmitIntervalCh: make(chan time.Duration), - resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize), - } - // Subscribe for transaction insertion events (whether from network or resurrects) - worker.txsSub = eth.TxPool().SubscribeTransactions(worker.txsCh, true) - // Subscribe events for blockchain - worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) - - // Sanitize recommit interval if the user-specified one is too short. - recommit := worker.config.Recommit - if recommit < minRecommitInterval { - log.Warn("Sanitizing miner recommit interval", "provided", recommit, "updated", minRecommitInterval) - recommit = minRecommitInterval - } - worker.recommit = recommit - - // Sanitize the timeout config for creating payload. - newpayloadTimeout := worker.config.NewPayloadTimeout - if newpayloadTimeout == 0 { - log.Warn("Sanitizing new payload timeout to default", "provided", newpayloadTimeout, "updated", DefaultConfig.NewPayloadTimeout) - newpayloadTimeout = DefaultConfig.NewPayloadTimeout - } - if newpayloadTimeout < time.Millisecond*100 { - log.Warn("Low payload timeout may cause high amount of non-full blocks", "provided", newpayloadTimeout, "default", DefaultConfig.NewPayloadTimeout) +// generateWork generates a sealing block based on the given parameters. +func (miner *Miner) generateWork(params *generateParams) *newPayloadResult { + work, err := miner.prepareWork(params) + if err != nil { + return &newPayloadResult{err: err} } - worker.newpayloadTimeout = newpayloadTimeout - - worker.wg.Add(4) - go worker.mainLoop() - go worker.newWorkLoop(recommit) - go worker.resultLoop() - go worker.taskLoop() + if !params.noTxs { + interrupt := new(atomic.Int32) + timer := time.AfterFunc(miner.config.Recommit, func() { + interrupt.Store(commitInterruptTimeout) + }) + defer timer.Stop() - // Submit first work to initialize pending state. - if init { - worker.startCh <- struct{}{} + err := miner.fillTransactions(interrupt, work) + if errors.Is(err, errBlockInterruptedByTimeout) { + log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit)) + } } - return worker -} - -// setEtherbase sets the etherbase used to initialize the block coinbase field. -func (w *worker) setEtherbase(addr common.Address) { - w.mu.Lock() - defer w.mu.Unlock() - w.coinbase = addr -} - -// etherbase retrieves the configured etherbase address. -func (w *worker) etherbase() common.Address { - w.mu.RLock() - defer w.mu.RUnlock() - return w.coinbase -} - -func (w *worker) setGasCeil(ceil uint64) { - w.mu.Lock() - defer w.mu.Unlock() - w.config.GasCeil = ceil -} - -// setExtra sets the content used to initialize the block extra field. -func (w *worker) setExtra(extra []byte) { - w.mu.Lock() - defer w.mu.Unlock() - w.extra = extra -} - -// setGasTip sets the minimum miner tip needed to include a non-local transaction. -func (w *worker) setGasTip(tip *big.Int) { - w.mu.Lock() - defer w.mu.Unlock() - w.tip = uint256.MustFromBig(tip) -} - -// setRecommitInterval updates the interval for miner sealing work recommitting. -func (w *worker) setRecommitInterval(interval time.Duration) { - select { - case w.resubmitIntervalCh <- interval: - case <-w.exitCh: + block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, work.txs, nil, work.receipts, params.withdrawals) + if err != nil { + return &newPayloadResult{err: err} } -} - -// pending returns the pending state and corresponding block. The returned -// values can be nil in case the pending block is not initialized. -func (w *worker) pending() (*types.Block, *state.StateDB) { - w.snapshotMu.RLock() - defer w.snapshotMu.RUnlock() - if w.snapshotState == nil { - return nil, nil + return &newPayloadResult{ + block: block, + fees: totalFees(block, work.receipts), + sidecars: work.sidecars, + stateDB: work.state, + receipts: work.receipts, } - return w.snapshotBlock, w.snapshotState.Copy() } -// pendingBlock returns pending block. The returned block can be nil in case the -// pending block is not initialized. -func (w *worker) pendingBlock() *types.Block { - w.snapshotMu.RLock() - defer w.snapshotMu.RUnlock() - return w.snapshotBlock -} - -// pendingBlockAndReceipts returns pending block and corresponding receipts. -// The returned values can be nil in case the pending block is not initialized. -func (w *worker) pendingBlockAndReceipts() (*types.Block, types.Receipts) { - w.snapshotMu.RLock() - defer w.snapshotMu.RUnlock() - return w.snapshotBlock, w.snapshotReceipts -} - -// start sets the running status as 1 and triggers new work submitting. -func (w *worker) start() { - w.running.Store(true) - w.startCh <- struct{}{} -} - -// stop sets the running status as 0. -func (w *worker) stop() { - w.running.Store(false) -} - -// isRunning returns an indicator whether worker is running or not. -func (w *worker) isRunning() bool { - return w.running.Load() -} - -// close terminates all background threads maintained by the worker. -// Note the worker does not support being closed multiple times. -func (w *worker) close() { - w.running.Store(false) - close(w.exitCh) - w.wg.Wait() -} +// prepareWork constructs the sealing task according to the given parameters, +// either based on the last chain head or specified parent. In this function +// the pending transactions are not filled yet, only the empty task returned. +func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) { + miner.confMu.RLock() + defer miner.confMu.RUnlock() -// recalcRecommit recalculates the resubmitting interval upon feedback. -func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) time.Duration { - var ( - prevF = float64(prev.Nanoseconds()) - next float64 - ) - if inc { - next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) - max := float64(maxRecommitInterval.Nanoseconds()) - if next > max { - next = max - } - } else { - next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) - min := float64(minRecommit.Nanoseconds()) - if next < min { - next = min + // Find the parent block for sealing task + parent := miner.chain.CurrentBlock() + if genParams.parentHash != (common.Hash{}) { + block := miner.chain.GetBlockByHash(genParams.parentHash) + if block == nil { + return nil, fmt.Errorf("missing parent") } + parent = block.Header() } - return time.Duration(int64(next)) -} - -// newWorkLoop is a standalone goroutine to submit new sealing work upon received events. -func (w *worker) newWorkLoop(recommit time.Duration) { - defer w.wg.Done() - var ( - interrupt *atomic.Int32 - minRecommit = recommit // minimal resubmit interval specified by user. - timestamp int64 // timestamp for each round of sealing. - ) - - timer := time.NewTimer(0) - defer timer.Stop() - <-timer.C // discard the initial tick - - // commit aborts in-flight transaction execution with given signal and resubmits a new one. - commit := func(s int32) { - if interrupt != nil { - interrupt.Store(s) - } - interrupt = new(atomic.Int32) - select { - case w.newWorkCh <- &newWorkReq{interrupt: interrupt, timestamp: timestamp}: - case <-w.exitCh: - return + // Sanity check the timestamp correctness, recap the timestamp + // to parent+1 if the mutation is allowed. + timestamp := genParams.timestamp + if parent.Time >= timestamp { + if genParams.forceTime { + return nil, fmt.Errorf("invalid timestamp, parent %d given %d", parent.Time, timestamp) } - timer.Reset(recommit) - w.newTxs.Store(0) + timestamp = parent.Time + 1 } - // clearPending cleans the stale pending tasks. - clearPending := func(number uint64) { - w.pendingMu.Lock() - for h, t := range w.pendingTasks { - if t.block.NumberU64()+staleThreshold <= number { - delete(w.pendingTasks, h) - } - } - w.pendingMu.Unlock() + // Construct the sealing block header. + header := &types.Header{ + ParentHash: parent.Hash(), + Number: new(big.Int).Add(parent.Number, common.Big1), + GasLimit: core.CalcGasLimit(parent.GasLimit, miner.config.GasCeil), + Time: timestamp, + Coinbase: genParams.coinbase, } - - for { - select { - case <-w.startCh: - clearPending(w.chain.CurrentBlock().Number.Uint64()) - timestamp = time.Now().Unix() - commit(commitInterruptNewHead) - - case head := <-w.chainHeadCh: - clearPending(head.Block.NumberU64()) - timestamp = time.Now().Unix() - commit(commitInterruptNewHead) - - case <-timer.C: - // If sealing is running resubmit a new work cycle periodically to pull in - // higher priced transactions. Disable this overhead for pending blocks. - if w.isRunning() && (w.chainConfig.Clique == nil || w.chainConfig.Clique.Period > 0) { - // Short circuit if no new transaction arrives. - if w.newTxs.Load() == 0 { - timer.Reset(recommit) - continue - } - commit(commitInterruptResubmit) - } - - case interval := <-w.resubmitIntervalCh: - // Adjust resubmit interval explicitly by user. - if interval < minRecommitInterval { - log.Warn("Sanitizing miner recommit interval", "provided", interval, "updated", minRecommitInterval) - interval = minRecommitInterval - } - log.Info("Miner recommit interval update", "from", minRecommit, "to", interval) - minRecommit, recommit = interval, interval - - if w.resubmitHook != nil { - w.resubmitHook(minRecommit, recommit) - } - - case adjust := <-w.resubmitAdjustCh: - // Adjust resubmit interval by feedback. - if adjust.inc { - before := recommit - target := float64(recommit.Nanoseconds()) / adjust.ratio - recommit = recalcRecommit(minRecommit, recommit, target, true) - log.Trace("Increase miner recommit interval", "from", before, "to", recommit) - } else { - before := recommit - recommit = recalcRecommit(minRecommit, recommit, float64(minRecommit.Nanoseconds()), false) - log.Trace("Decrease miner recommit interval", "from", before, "to", recommit) - } - - if w.resubmitHook != nil { - w.resubmitHook(minRecommit, recommit) - } - - case <-w.exitCh: - return - } + // Set the extra field. + if len(miner.config.ExtraData) != 0 { + header.Extra = miner.config.ExtraData } -} - -// mainLoop is responsible for generating and submitting sealing work based on -// the received event. It can support two modes: automatically generate task and -// submit it or return task according to given parameters for various proposes. -func (w *worker) mainLoop() { - defer w.wg.Done() - defer w.txsSub.Unsubscribe() - defer w.chainHeadSub.Unsubscribe() - defer func() { - if w.current != nil { - w.current.discard() - } - }() - - for { - select { - case req := <-w.newWorkCh: - w.commitWork(req.interrupt, req.timestamp) - - case req := <-w.getWorkCh: - req.result <- w.generateWork(req.params) - - case ev := <-w.txsCh: - // Apply transactions to the pending state if we're not sealing - // - // Note all transactions received may not be continuous with transactions - // already included in the current sealing block. These transactions will - // be automatically eliminated. - if !w.isRunning() && w.current != nil { - // If block is already full, abort - if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas { - continue - } - txs := make(map[common.Address][]*txpool.LazyTransaction, len(ev.Txs)) - for _, tx := range ev.Txs { - acc, _ := types.Sender(w.current.signer, tx) - txs[acc] = append(txs[acc], &txpool.LazyTransaction{ - Pool: w.eth.TxPool(), // We don't know where this came from, yolo resolve from everywhere - Hash: tx.Hash(), - Tx: nil, // Do *not* set this! We need to resolve it later to pull blobs in - Time: tx.Time(), - GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()), - GasTipCap: uint256.MustFromBig(tx.GasTipCap()), - Gas: tx.Gas(), - BlobGas: tx.BlobGas(), - }) - } - plainTxs := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) // Mixed bag of everrything, yolo - blobTxs := newTransactionsByPriceAndNonce(w.current.signer, nil, w.current.header.BaseFee) // Empty bag, don't bother optimising - - tcount := w.current.tcount - w.commitTransactions(w.current, plainTxs, blobTxs, nil) - - // Only update the snapshot if any new transactions were added - // to the pending block - if tcount != w.current.tcount { - w.updateSnapshot(w.current) - } - } else { - // Special case, if the consensus engine is 0 period clique(dev mode), - // submit sealing work here since all empty submission will be rejected - // by clique. Of course the advance sealing(empty submission) is disabled. - if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 { - w.commitWork(nil, time.Now().Unix()) - } - } - w.newTxs.Add(int32(len(ev.Txs))) - - // System stopped - case <-w.exitCh: - return - case <-w.txsSub.Err(): - return - case <-w.chainHeadSub.Err(): - return - } + // Set the randomness field from the beacon chain if it's available. + if genParams.random != (common.Hash{}) { + header.MixDigest = genParams.random } -} - -// taskLoop is a standalone goroutine to fetch sealing task from the generator and -// push them to consensus engine. -func (w *worker) taskLoop() { - defer w.wg.Done() - var ( - stopCh chan struct{} - prev common.Hash - ) - - // interrupt aborts the in-flight sealing task. - interrupt := func() { - if stopCh != nil { - close(stopCh) - stopCh = nil + // Set baseFee and GasLimit if we are on an EIP-1559 chain + if miner.chainConfig.IsLondon(header.Number) { + header.BaseFee = eip1559.CalcBaseFee(miner.chainConfig, parent) + if !miner.chainConfig.IsLondon(parent.Number) { + parentGasLimit := parent.GasLimit * miner.chainConfig.ElasticityMultiplier() + header.GasLimit = core.CalcGasLimit(parentGasLimit, miner.config.GasCeil) } } - for { - select { - case task := <-w.taskCh: - if w.newTaskHook != nil { - w.newTaskHook(task) - } - // Reject duplicate sealing work due to resubmitting. - sealHash := w.engine.SealHash(task.block.Header()) - if sealHash == prev { - continue - } - // Interrupt previous sealing operation - interrupt() - stopCh, prev = make(chan struct{}), sealHash - - if w.skipSealHook != nil && w.skipSealHook(task) { - continue - } - w.pendingMu.Lock() - w.pendingTasks[sealHash] = task - w.pendingMu.Unlock() - - if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { - log.Warn("Block sealing failed", "err", err) - w.pendingMu.Lock() - delete(w.pendingTasks, sealHash) - w.pendingMu.Unlock() - } - case <-w.exitCh: - interrupt() - return + // Apply EIP-4844, EIP-4788. + if miner.chainConfig.IsCancun(header.Number, header.Time) { + var excessBlobGas uint64 + if miner.chainConfig.IsCancun(parent.Number, parent.Time) { + excessBlobGas = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed) + } else { + // For the first post-fork block, both parent.data_gas_used and parent.excess_data_gas are evaluated as 0 + excessBlobGas = eip4844.CalcExcessBlobGas(0, 0) } + header.BlobGasUsed = new(uint64) + header.ExcessBlobGas = &excessBlobGas + header.ParentBeaconRoot = genParams.beaconRoot } -} - -// resultLoop is a standalone goroutine to handle sealing result submitting -// and flush relative data to the database. -func (w *worker) resultLoop() { - defer w.wg.Done() - for { - select { - case block := <-w.resultCh: - // Short circuit when receiving empty result. - if block == nil { - continue - } - // Short circuit when receiving duplicate result caused by resubmitting. - if w.chain.HasBlock(block.Hash(), block.NumberU64()) { - continue - } - var ( - sealhash = w.engine.SealHash(block.Header()) - hash = block.Hash() - ) - w.pendingMu.RLock() - task, exist := w.pendingTasks[sealhash] - w.pendingMu.RUnlock() - if !exist { - log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", sealhash, "hash", hash) - continue - } - // Different block could share same sealhash, deep copy here to prevent write-write conflict. - var ( - receipts = make([]*types.Receipt, len(task.receipts)) - logs []*types.Log - ) - for i, taskReceipt := range task.receipts { - receipt := new(types.Receipt) - receipts[i] = receipt - *receipt = *taskReceipt - - // add block location fields - receipt.BlockHash = hash - receipt.BlockNumber = block.Number() - receipt.TransactionIndex = uint(i) - - // Update the block hash in all logs since it is now available and not when the - // receipt/log of individual transactions were created. - receipt.Logs = make([]*types.Log, len(taskReceipt.Logs)) - for i, taskLog := range taskReceipt.Logs { - log := new(types.Log) - receipt.Logs[i] = log - *log = *taskLog - log.BlockHash = hash - } - logs = append(logs, receipt.Logs...) - } - // Commit block and state to database. - _, err := w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true) - if err != nil { - log.Error("Failed writing block to chain", "err", err) - continue - } - log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, - "elapsed", common.PrettyDuration(time.Since(task.createdAt))) - - // Broadcast the block and announce chain insertion event - w.mux.Post(core.NewMinedBlockEvent{Block: block}) - - case <-w.exitCh: - return - } + // Run the consensus preparation with the default or customized consensus engine. + if err := miner.engine.Prepare(miner.chain, header); err != nil { + log.Error("Failed to prepare header for sealing", "err", err) + return nil, err + } + // Could potentially happen if starting to mine in an odd state. + // Note genParams.coinbase can be different with header.Coinbase + // since clique algorithm can modify the coinbase field in header. + env, err := miner.makeEnv(parent, header, genParams.coinbase) + if err != nil { + log.Error("Failed to create sealing context", "err", err) + return nil, err + } + if header.ParentBeaconRoot != nil { + context := core.NewEVMBlockContext(header, miner.chain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) + core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) } + return env, nil } // makeEnv creates a new environment for the sealing block. -func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address) (*environment, error) { +func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address) (*environment, error) { // Retrieve the parent state to execute on top and start a prefetcher for // the miner to speed block sealing up a bit. - state, err := w.chain.StateAt(parent.Root) + state, err := miner.chain.StateAt(parent.Root) if err != nil { return nil, err } - state.StartPrefetcher("miner") - // Note the passed coinbase may be different with header.Coinbase. - env := &environment{ - signer: types.MakeSigner(w.chainConfig, header.Number, header.Time), + return &environment{ + signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time), state: state, coinbase: coinbase, header: header, - } - // Keep track of transactions which return errors so they can be removed - env.tcount = 0 - return env, nil + }, nil } -// updateSnapshot updates pending snapshot block, receipts and state. -func (w *worker) updateSnapshot(env *environment) { - w.snapshotMu.Lock() - defer w.snapshotMu.Unlock() - - w.snapshotBlock = types.NewBlock( - env.header, - env.txs, - nil, - env.receipts, - trie.NewStackTrie(nil), - ) - w.snapshotReceipts = copyReceipts(env.receipts) - w.snapshotState = env.state.Copy() -} - -func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]*types.Log, error) { +func (miner *Miner) commitTransaction(env *environment, tx *types.Transaction) error { if tx.Type() == types.BlobTxType { - return w.commitBlobTransaction(env, tx) + return miner.commitBlobTransaction(env, tx) } - receipt, err := w.applyTransaction(env, tx) + receipt, err := miner.applyTransaction(env, tx) if err != nil { - return nil, err + return err } env.txs = append(env.txs, tx) env.receipts = append(env.receipts, receipt) - return receipt.Logs, nil + env.tcount++ + return nil } -func (w *worker) commitBlobTransaction(env *environment, tx *types.Transaction) ([]*types.Log, error) { +func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transaction) error { sc := tx.BlobTxSidecar() if sc == nil { panic("blob transaction without blobs in miner") @@ -776,27 +242,28 @@ func (w *worker) commitBlobTransaction(env *environment, tx *types.Transaction) // and not during execution. This means core.ApplyTransaction will not return an error if the // tx has too many blobs. So we have to explicitly check it here. if (env.blobs+len(sc.Blobs))*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock { - return nil, errors.New("max data blobs reached") + return errors.New("max data blobs reached") } - receipt, err := w.applyTransaction(env, tx) + receipt, err := miner.applyTransaction(env, tx) if err != nil { - return nil, err + return err } env.txs = append(env.txs, tx.WithoutBlobTxSidecar()) env.receipts = append(env.receipts, receipt) env.sidecars = append(env.sidecars, sc) env.blobs += len(sc.Blobs) *env.header.BlobGasUsed += receipt.BlobGasUsed - return receipt.Logs, nil + env.tcount++ + return nil } // applyTransaction runs the transaction. If execution fails, state and gas pool are reverted. -func (w *worker) applyTransaction(env *environment, tx *types.Transaction) (*types.Receipt, error) { +func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*types.Receipt, error) { var ( snap = env.state.Snapshot() gp = env.gasPool.Gas() ) - receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *w.chain.GetVMConfig()) + receipt, err := core.ApplyTransaction(miner.chainConfig, miner.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *miner.chain.GetVMConfig()) if err != nil { env.state.RevertToSnapshot(snap) env.gasPool.SetGas(gp) @@ -804,13 +271,11 @@ func (w *worker) applyTransaction(env *environment, tx *types.Transaction) (*typ return receipt, err } -func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error { +func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error { gasLimit := env.header.GasLimit if env.gasPool == nil { env.gasPool = new(core.GasPool).AddGas(gasLimit) } - var coalescedLogs []*types.Log - for { // Check interruption signal and abort building if it's fired. if interrupt != nil { @@ -877,15 +342,15 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac // Check whether the tx is replay protected. If we're not in the EIP155 hf // phase, start ignoring the sender until we do. - if tx.Protected() && !w.chainConfig.IsEIP155(env.header.Number) { - log.Trace("Ignoring replay protected transaction", "hash", ltx.Hash, "eip155", w.chainConfig.EIP155Block) + if tx.Protected() && !miner.chainConfig.IsEIP155(env.header.Number) { + log.Trace("Ignoring replay protected transaction", "hash", ltx.Hash, "eip155", miner.chainConfig.EIP155Block) txs.Pop() continue } // Start executing the transaction env.state.SetTxContext(tx.Hash(), env.tcount) - logs, err := w.commitTransaction(env, tx) + err := miner.commitTransaction(env, tx) switch { case errors.Is(err, core.ErrNonceTooLow): // New head notification data race between the transaction pool and miner, shift @@ -894,8 +359,6 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac case errors.Is(err, nil): // Everything ok, collect the logs and shift in the next transaction from the same account - coalescedLogs = append(coalescedLogs, logs...) - env.tcount++ txs.Shift() default: @@ -905,130 +368,20 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac txs.Pop() } } - if !w.isRunning() && len(coalescedLogs) > 0 { - // We don't push the pendingLogsEvent while we are sealing. The reason is that - // when we are sealing, the worker will regenerate a sealing block every 3 seconds. - // In order to avoid pushing the repeated pendingLog, we disable the pending log pushing. - - // make a copy, the state caches the logs and these logs get "upgraded" from pending to mined - // logs by filling in the block hash when the block was mined by the local miner. This can - // cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed. - cpy := make([]*types.Log, len(coalescedLogs)) - for i, l := range coalescedLogs { - cpy[i] = new(types.Log) - *cpy[i] = *l - } - w.pendingLogsFeed.Send(cpy) - } return nil } -// generateParams wraps various of settings for generating sealing task. -type generateParams struct { - timestamp uint64 // The timestamp for sealing task - forceTime bool // Flag whether the given timestamp is immutable or not - parentHash common.Hash // Parent block hash, empty means the latest chain head - coinbase common.Address // The fee recipient address for including transaction - random common.Hash // The randomness generated by beacon chain, empty before the merge - withdrawals types.Withdrawals // List of withdrawals to include in block. - beaconRoot *common.Hash // The beacon root (cancun field). - noTxs bool // Flag whether an empty block without any transaction is expected -} - -// prepareWork constructs the sealing task according to the given parameters, -// either based on the last chain head or specified parent. In this function -// the pending transactions are not filled yet, only the empty task returned. -func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { - w.mu.RLock() - defer w.mu.RUnlock() - - // Find the parent block for sealing task - parent := w.chain.CurrentBlock() - if genParams.parentHash != (common.Hash{}) { - block := w.chain.GetBlockByHash(genParams.parentHash) - if block == nil { - return nil, errors.New("missing parent") - } - parent = block.Header() - } - // Sanity check the timestamp correctness, recap the timestamp - // to parent+1 if the mutation is allowed. - timestamp := genParams.timestamp - if parent.Time >= timestamp { - if genParams.forceTime { - return nil, fmt.Errorf("invalid timestamp, parent %d given %d", parent.Time, timestamp) - } - timestamp = parent.Time + 1 - } - // Construct the sealing block header. - header := &types.Header{ - ParentHash: parent.Hash(), - Number: new(big.Int).Add(parent.Number, common.Big1), - GasLimit: core.CalcGasLimit(parent.GasLimit, w.config.GasCeil), - Time: timestamp, - Coinbase: genParams.coinbase, - } - // Set the extra field. - if len(w.extra) != 0 { - header.Extra = w.extra - } - // Set the randomness field from the beacon chain if it's available. - if genParams.random != (common.Hash{}) { - header.MixDigest = genParams.random - } - // Set baseFee and GasLimit if we are on an EIP-1559 chain - if w.chainConfig.IsLondon(header.Number) { - header.BaseFee = eip1559.CalcBaseFee(w.chainConfig, parent) - if !w.chainConfig.IsLondon(parent.Number) { - parentGasLimit := parent.GasLimit * w.chainConfig.ElasticityMultiplier() - header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) - } - } - // Apply EIP-4844, EIP-4788. - if w.chainConfig.IsCancun(header.Number, header.Time) { - var excessBlobGas uint64 - if w.chainConfig.IsCancun(parent.Number, parent.Time) { - excessBlobGas = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed) - } else { - // For the first post-fork block, both parent.data_gas_used and parent.excess_data_gas are evaluated as 0 - excessBlobGas = eip4844.CalcExcessBlobGas(0, 0) - } - header.BlobGasUsed = new(uint64) - header.ExcessBlobGas = &excessBlobGas - header.ParentBeaconRoot = genParams.beaconRoot - } - // Run the consensus preparation with the default or customized consensus engine. - if err := w.engine.Prepare(w.chain, header); err != nil { - log.Error("Failed to prepare header for sealing", "err", err) - return nil, err - } - // Could potentially happen if starting to mine in an odd state. - // Note genParams.coinbase can be different with header.Coinbase - // since clique algorithm can modify the coinbase field in header. - env, err := w.makeEnv(parent, header, genParams.coinbase) - if err != nil { - log.Error("Failed to create sealing context", "err", err) - return nil, err - } - if header.ParentBeaconRoot != nil { - context := core.NewEVMBlockContext(header, w.chain, nil) - vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{}) - core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) - } - return env, nil -} - // fillTransactions retrieves the pending transactions from the txpool and fills them // into the given sealing block. The transaction selection and ordering strategy can // be customized with the plugin in the future. -func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) error { - w.mu.RLock() - tip := w.tip - w.mu.RUnlock() +func (miner *Miner) fillTransactions(interrupt *atomic.Int32, env *environment) error { + miner.confMu.RLock() + tip := miner.config.GasPrice + miner.confMu.RUnlock() // Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees filter := txpool.PendingFilter{ - MinTip: tip, + MinTip: uint256.MustFromBig(tip), } if env.header.BaseFee != nil { filter.BaseFee = uint256.MustFromBig(env.header.BaseFee) @@ -1037,16 +390,16 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas)) } filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false - pendingPlainTxs := w.eth.TxPool().Pending(filter) + pendingPlainTxs := miner.txpool.Pending(filter) filter.OnlyPlainTxs, filter.OnlyBlobTxs = false, true - pendingBlobTxs := w.eth.TxPool().Pending(filter) + pendingBlobTxs := miner.txpool.Pending(filter) // Split the pending transactions into locals and remotes. localPlainTxs, remotePlainTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs localBlobTxs, remoteBlobTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs - for _, account := range w.eth.TxPool().Locals() { + for _, account := range miner.txpool.Locals() { if txs := remotePlainTxs[account]; len(txs) > 0 { delete(remotePlainTxs, account) localPlainTxs[account] = txs @@ -1061,7 +414,7 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err plainTxs := newTransactionsByPriceAndNonce(env.signer, localPlainTxs, env.header.BaseFee) blobTxs := newTransactionsByPriceAndNonce(env.signer, localBlobTxs, env.header.BaseFee) - if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil { + if err := miner.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil { return err } } @@ -1069,189 +422,13 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err plainTxs := newTransactionsByPriceAndNonce(env.signer, remotePlainTxs, env.header.BaseFee) blobTxs := newTransactionsByPriceAndNonce(env.signer, remoteBlobTxs, env.header.BaseFee) - if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil { + if err := miner.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil { return err } } return nil } -// generateWork generates a sealing block based on the given parameters. -func (w *worker) generateWork(params *generateParams) *newPayloadResult { - work, err := w.prepareWork(params) - if err != nil { - return &newPayloadResult{err: err} - } - defer work.discard() - - if !params.noTxs { - interrupt := new(atomic.Int32) - timer := time.AfterFunc(w.newpayloadTimeout, func() { - interrupt.Store(commitInterruptTimeout) - }) - defer timer.Stop() - - err := w.fillTransactions(interrupt, work) - if errors.Is(err, errBlockInterruptedByTimeout) { - log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.newpayloadTimeout)) - } - } - block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, nil, work.receipts, params.withdrawals) - if err != nil { - return &newPayloadResult{err: err} - } - return &newPayloadResult{ - block: block, - fees: totalFees(block, work.receipts), - sidecars: work.sidecars, - } -} - -// commitWork generates several new sealing tasks based on the parent block -// and submit them to the sealer. -func (w *worker) commitWork(interrupt *atomic.Int32, timestamp int64) { - // Abort committing if node is still syncing - if w.syncing.Load() { - return - } - start := time.Now() - - // Set the coinbase if the worker is running or it's required - var coinbase common.Address - if w.isRunning() { - coinbase = w.etherbase() - if coinbase == (common.Address{}) { - log.Error("Refusing to mine without etherbase") - return - } - } - work, err := w.prepareWork(&generateParams{ - timestamp: uint64(timestamp), - coinbase: coinbase, - }) - if err != nil { - return - } - // Fill pending transactions from the txpool into the block. - err = w.fillTransactions(interrupt, work) - switch { - case err == nil: - // The entire block is filled, decrease resubmit interval in case - // of current interval is larger than the user-specified one. - w.adjustResubmitInterval(&intervalAdjust{inc: false}) - - case errors.Is(err, errBlockInterruptedByRecommit): - // Notify resubmit loop to increase resubmitting interval if the - // interruption is due to frequent commits. - gaslimit := work.header.GasLimit - ratio := float64(gaslimit-work.gasPool.Gas()) / float64(gaslimit) - if ratio < 0.1 { - ratio = 0.1 - } - w.adjustResubmitInterval(&intervalAdjust{ - ratio: ratio, - inc: true, - }) - - case errors.Is(err, errBlockInterruptedByNewHead): - // If the block building is interrupted by newhead event, discard it - // totally. Committing the interrupted block introduces unnecessary - // delay, and possibly causes miner to mine on the previous head, - // which could result in higher uncle rate. - work.discard() - return - } - // Submit the generated block for consensus sealing. - w.commit(work.copy(), w.fullTaskHook, true, start) - - // Swap out the old work with the new one, terminating any leftover - // prefetcher processes in the mean time and starting a new one. - if w.current != nil { - w.current.discard() - } - w.current = work -} - -// commit runs any post-transaction state modifications, assembles the final block -// and commits new work if consensus engine is running. -// Note the assumption is held that the mutation is allowed to the passed env, do -// the deep copy first. -func (w *worker) commit(env *environment, interval func(), update bool, start time.Time) error { - if w.isRunning() { - if interval != nil { - interval() - } - // Create a local environment copy, avoid the data race with snapshot state. - // https://github.com/ethereum/go-ethereum/issues/24299 - env := env.copy() - // Withdrawals are set to nil here, because this is only called in PoW. - block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, env.txs, nil, env.receipts, nil) - if err != nil { - return err - } - // If we're post merge, just ignore - if !w.isTTDReached(block.Header()) { - select { - case w.taskCh <- &task{receipts: env.receipts, state: env.state, block: block, createdAt: time.Now()}: - fees := totalFees(block, env.receipts) - feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), big.NewFloat(params.Ether)) - log.Info("Commit new sealing work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), - "txs", env.tcount, "gas", block.GasUsed(), "fees", feesInEther, - "elapsed", common.PrettyDuration(time.Since(start))) - - case <-w.exitCh: - log.Info("Worker has exited") - } - } - } - if update { - w.updateSnapshot(env) - } - return nil -} - -// getSealingBlock generates the sealing block based on the given parameters. -// The generation result will be passed back via the given channel no matter -// the generation itself succeeds or not. -func (w *worker) getSealingBlock(params *generateParams) *newPayloadResult { - req := &getWorkReq{ - params: params, - result: make(chan *newPayloadResult, 1), - } - select { - case w.getWorkCh <- req: - return <-req.result - case <-w.exitCh: - return &newPayloadResult{err: errors.New("miner closed")} - } -} - -// isTTDReached returns the indicator if the given block has reached the total -// terminal difficulty for The Merge transition. -func (w *worker) isTTDReached(header *types.Header) bool { - td, ttd := w.chain.GetTd(header.ParentHash, header.Number.Uint64()-1), w.chain.Config().TerminalTotalDifficulty - return td != nil && ttd != nil && td.Cmp(ttd) >= 0 -} - -// adjustResubmitInterval adjusts the resubmit interval. -func (w *worker) adjustResubmitInterval(message *intervalAdjust) { - select { - case w.resubmitAdjustCh <- message: - default: - log.Warn("the resubmitAdjustCh is full, discard the message") - } -} - -// copyReceipts makes a deep copy of the given receipts. -func copyReceipts(receipts []*types.Receipt) []*types.Receipt { - result := make([]*types.Receipt, len(receipts)) - for i, l := range receipts { - cpy := *l - result[i] = &cpy - } - return result -} - // totalFees computes total consumed miner fees in Wei. Block transactions and receipts have to have the same order. func totalFees(block *types.Block, receipts []*types.Receipt) *big.Int { feesWei := new(big.Int) diff --git a/miner/worker_test.go b/miner/worker_test.go deleted file mode 100644 index 9dba12ae51a2..000000000000 --- a/miner/worker_test.go +++ /dev/null @@ -1,510 +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 miner - -import ( - "math/big" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/clique" - "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/txpool" - "github.com/ethereum/go-ethereum/core/txpool/legacypool" - "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/event" - "github.com/ethereum/go-ethereum/params" - "github.com/holiman/uint256" -) - -const ( - // testCode is the testing contract binary code which will initialises some - // variables in constructor - testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032" - - // testGas is the gas required for contract deployment. - testGas = 144109 -) - -var ( - // Test chain configurations - testTxPoolConfig legacypool.Config - ethashChainConfig *params.ChainConfig - cliqueChainConfig *params.ChainConfig - - // Test accounts - testBankKey, _ = crypto.GenerateKey() - testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) - testBankFunds = big.NewInt(1000000000000000000) - - testUserKey, _ = crypto.GenerateKey() - testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey) - - // Test transactions - pendingTxs []*types.Transaction - newTxs []*types.Transaction - - testConfig = &Config{ - Recommit: time.Second, - GasCeil: params.GenesisGasLimit, - } -) - -func init() { - testTxPoolConfig = legacypool.DefaultConfig - testTxPoolConfig.Journal = "" - ethashChainConfig = new(params.ChainConfig) - *ethashChainConfig = *params.TestChainConfig - cliqueChainConfig = new(params.ChainConfig) - *cliqueChainConfig = *params.TestChainConfig - cliqueChainConfig.Clique = ¶ms.CliqueConfig{ - Period: 10, - Epoch: 30000, - } - - signer := types.LatestSigner(params.TestChainConfig) - tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{ - ChainID: params.TestChainConfig.ChainID, - Nonce: 0, - To: &testUserAddress, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: big.NewInt(params.InitialBaseFee), - }) - pendingTxs = append(pendingTxs, tx1) - - tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{ - Nonce: 1, - To: &testUserAddress, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: big.NewInt(params.InitialBaseFee), - }) - newTxs = append(newTxs, tx2) -} - -// testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. -type testWorkerBackend struct { - db ethdb.Database - txPool *txpool.TxPool - chain *core.BlockChain - genesis *core.Genesis -} - -func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { - var gspec = &core.Genesis{ - Config: chainConfig, - Alloc: types.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, - } - switch e := engine.(type) { - case *clique.Clique: - gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) - copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) - e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { - return crypto.Sign(crypto.Keccak256(data), testBankKey) - }) - case *ethash.Ethash: - default: - t.Fatalf("unexpected consensus engine type: %T", engine) - } - chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil) - if err != nil { - t.Fatalf("core.NewBlockChain failed: %v", err) - } - pool := legacypool.New(testTxPoolConfig, chain) - txpool, _ := txpool.New(testTxPoolConfig.PriceLimit, chain, []txpool.SubPool{pool}) - - return &testWorkerBackend{ - db: db, - chain: chain, - txPool: txpool, - genesis: gspec, - } -} - -func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } -func (b *testWorkerBackend) TxPool() *txpool.TxPool { return b.txPool } - -func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { - var tx *types.Transaction - gasPrice := big.NewInt(10 * params.InitialBaseFee) - if creation { - tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey) - } else { - tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey) - } - return tx -} - -func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend) { - backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) - backend.txPool.Add(pendingTxs, true, false) - w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false) - w.setEtherbase(testBankAddress) - return w, backend -} - -func TestGenerateAndImportBlock(t *testing.T) { - t.Parallel() - var ( - db = rawdb.NewMemoryDatabase() - config = *params.AllCliqueProtocolChanges - ) - config.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} - engine := clique.New(config.Clique, db) - - w, b := newTestWorker(t, &config, engine, db, 0) - defer w.close() - - // This test chain imports the mined blocks. - chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, b.genesis, nil, engine, vm.Config{}, nil, nil) - defer chain.Stop() - - // Ignore empty commit here for less noise. - w.skipSealHook = func(task *task) bool { - return len(task.receipts) == 0 - } - - // Wait for mined blocks. - sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) - defer sub.Unsubscribe() - - // Start mining! - w.start() - - for i := 0; i < 5; i++ { - b.txPool.Add([]*types.Transaction{b.newRandomTx(true)}, true, false) - b.txPool.Add([]*types.Transaction{b.newRandomTx(false)}, true, false) - - select { - case ev := <-sub.Chan(): - block := ev.Data.(core.NewMinedBlockEvent).Block - if _, err := chain.InsertChain([]*types.Block{block}); err != nil { - t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) - } - case <-time.After(3 * time.Second): // Worker needs 1s to include new changes. - t.Fatalf("timeout") - } - } -} - -func TestEmptyWorkEthash(t *testing.T) { - t.Parallel() - testEmptyWork(t, ethashChainConfig, ethash.NewFaker()) -} -func TestEmptyWorkClique(t *testing.T) { - t.Parallel() - testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) -} - -func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { - defer engine.Close() - - w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) - defer w.close() - - taskCh := make(chan struct{}, 2) - checkEqual := func(t *testing.T, task *task) { - // The work should contain 1 tx - receiptLen, balance := 1, uint256.NewInt(1000) - if len(task.receipts) != receiptLen { - t.Fatalf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) - } - if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { - t.Fatalf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) - } - } - w.newTaskHook = func(task *task) { - if task.block.NumberU64() == 1 { - checkEqual(t, task) - taskCh <- struct{}{} - } - } - w.skipSealHook = func(task *task) bool { return true } - w.fullTaskHook = func() { - time.Sleep(100 * time.Millisecond) - } - w.start() // Start mining! - select { - case <-taskCh: - case <-time.NewTimer(3 * time.Second).C: - t.Error("new task timeout") - } -} - -func TestAdjustIntervalEthash(t *testing.T) { - t.Parallel() - testAdjustInterval(t, ethashChainConfig, ethash.NewFaker()) -} - -func TestAdjustIntervalClique(t *testing.T) { - t.Parallel() - testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) -} - -func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { - defer engine.Close() - - w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) - defer w.close() - - w.skipSealHook = func(task *task) bool { - return true - } - w.fullTaskHook = func() { - time.Sleep(100 * time.Millisecond) - } - var ( - progress = make(chan struct{}, 10) - result = make([]float64, 0, 10) - index = 0 - start atomic.Bool - ) - w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { - // Short circuit if interval checking hasn't started. - if !start.Load() { - return - } - var wantMinInterval, wantRecommitInterval time.Duration - - switch index { - case 0: - wantMinInterval, wantRecommitInterval = 3*time.Second, 3*time.Second - case 1: - origin := float64(3 * time.Second.Nanoseconds()) - estimate := origin*(1-intervalAdjustRatio) + intervalAdjustRatio*(origin/0.8+intervalAdjustBias) - wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond - case 2: - estimate := result[index-1] - min := float64(3 * time.Second.Nanoseconds()) - estimate = estimate*(1-intervalAdjustRatio) + intervalAdjustRatio*(min-intervalAdjustBias) - wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond - case 3: - wantMinInterval, wantRecommitInterval = time.Second, time.Second - } - - // Check interval - if minInterval != wantMinInterval { - t.Errorf("resubmit min interval mismatch: have %v, want %v ", minInterval, wantMinInterval) - } - if recommitInterval != wantRecommitInterval { - t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval) - } - result = append(result, float64(recommitInterval.Nanoseconds())) - index += 1 - progress <- struct{}{} - } - w.start() - - time.Sleep(time.Second) // Ensure two tasks have been submitted due to start opt - start.Store(true) - - w.setRecommitInterval(3 * time.Second) - select { - case <-progress: - case <-time.NewTimer(time.Second).C: - t.Error("interval reset timeout") - } - - w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8} - select { - case <-progress: - case <-time.NewTimer(time.Second).C: - t.Error("interval reset timeout") - } - - w.resubmitAdjustCh <- &intervalAdjust{inc: false} - select { - case <-progress: - case <-time.NewTimer(time.Second).C: - t.Error("interval reset timeout") - } - - w.setRecommitInterval(500 * time.Millisecond) - select { - case <-progress: - case <-time.NewTimer(time.Second).C: - t.Error("interval reset timeout") - } -} - -func TestGetSealingWorkEthash(t *testing.T) { - t.Parallel() - testGetSealingWork(t, ethashChainConfig, ethash.NewFaker()) -} - -func TestGetSealingWorkClique(t *testing.T) { - t.Parallel() - testGetSealingWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) -} - -func TestGetSealingWorkPostMerge(t *testing.T) { - t.Parallel() - local := new(params.ChainConfig) - *local = *ethashChainConfig - local.TerminalTotalDifficulty = big.NewInt(0) - testGetSealingWork(t, local, ethash.NewFaker()) -} - -func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { - defer engine.Close() - - w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) - defer w.close() - - w.setExtra([]byte{0x01, 0x02}) - - w.skipSealHook = func(task *task) bool { - return true - } - w.fullTaskHook = func() { - time.Sleep(100 * time.Millisecond) - } - timestamp := uint64(time.Now().Unix()) - assertBlock := func(block *types.Block, number uint64, coinbase common.Address, random common.Hash) { - if block.Time() != timestamp { - // Sometime the timestamp will be mutated if the timestamp - // is even smaller than parent block's. It's OK. - t.Logf("Invalid timestamp, want %d, get %d", timestamp, block.Time()) - } - _, isClique := engine.(*clique.Clique) - if !isClique { - if len(block.Extra()) != 2 { - t.Error("Unexpected extra field") - } - if block.Coinbase() != coinbase { - t.Errorf("Unexpected coinbase got %x want %x", block.Coinbase(), coinbase) - } - } else { - if block.Coinbase() != (common.Address{}) { - t.Error("Unexpected coinbase") - } - } - if !isClique { - if block.MixDigest() != random { - t.Error("Unexpected mix digest") - } - } - if block.Nonce() != 0 { - t.Error("Unexpected block nonce") - } - if block.NumberU64() != number { - t.Errorf("Mismatched block number, want %d got %d", number, block.NumberU64()) - } - } - var cases = []struct { - parent common.Hash - coinbase common.Address - random common.Hash - expectNumber uint64 - expectErr bool - }{ - { - b.chain.Genesis().Hash(), - common.HexToAddress("0xdeadbeef"), - common.HexToHash("0xcafebabe"), - uint64(1), - false, - }, - { - b.chain.CurrentBlock().Hash(), - common.HexToAddress("0xdeadbeef"), - common.HexToHash("0xcafebabe"), - b.chain.CurrentBlock().Number.Uint64() + 1, - false, - }, - { - b.chain.CurrentBlock().Hash(), - common.Address{}, - common.HexToHash("0xcafebabe"), - b.chain.CurrentBlock().Number.Uint64() + 1, - false, - }, - { - b.chain.CurrentBlock().Hash(), - common.Address{}, - common.Hash{}, - b.chain.CurrentBlock().Number.Uint64() + 1, - false, - }, - { - common.HexToHash("0xdeadbeef"), - common.HexToAddress("0xdeadbeef"), - common.HexToHash("0xcafebabe"), - 0, - true, - }, - } - - // This API should work even when the automatic sealing is not enabled - for _, c := range cases { - r := w.getSealingBlock(&generateParams{ - parentHash: c.parent, - timestamp: timestamp, - coinbase: c.coinbase, - random: c.random, - withdrawals: nil, - beaconRoot: nil, - noTxs: false, - forceTime: true, - }) - if c.expectErr { - if r.err == nil { - t.Error("Expect error but get nil") - } - } else { - if r.err != nil { - t.Errorf("Unexpected error %v", r.err) - } - assertBlock(r.block, c.expectNumber, c.coinbase, c.random) - } - } - - // This API should work even when the automatic sealing is enabled - w.start() - for _, c := range cases { - r := w.getSealingBlock(&generateParams{ - parentHash: c.parent, - timestamp: timestamp, - coinbase: c.coinbase, - random: c.random, - withdrawals: nil, - beaconRoot: nil, - noTxs: false, - forceTime: true, - }) - if c.expectErr { - if r.err == nil { - t.Error("Expect error but get nil") - } - } else { - if r.err != nil { - t.Errorf("Unexpected error %v", r.err) - } - assertBlock(r.block, c.expectNumber, c.coinbase, c.random) - } - } -} From aadcb886753079d419f966a3bc990f708f8d1c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Wed, 6 Mar 2024 17:50:22 +0100 Subject: [PATCH 043/571] cmd/blsync, beacon/light: beacon chain light client (#28822) Here we add a beacon chain light client for use by geth. Geth can now be configured to run against a beacon chain API endpoint, without pointing a CL to it. To set this up, use the `--beacon.api` flag. Information provided by the beacon chain is verified, i.e. geth does not blindly trust the beacon API endpoint in this mode. The root of trust are the beacon chain 'sync committees'. The configured beacon API endpoint must provide light client data. At this time, only Lodestar and Nimbus provide the necessary APIs. There is also a standalone tool, cmd/blsync, which uses the beacon chain light client to drive any EL implementation via its engine API. --------- Co-authored-by: Felix Lange --- beacon/blsync/block_sync.go | 203 ++++++++++ beacon/blsync/block_sync_test.go | 160 ++++++++ beacon/blsync/client.go | 103 +++++ beacon/blsync/config.go | 113 ++++++ beacon/light/api/api_server.go | 103 +++++ beacon/light/api/light_api.go | 496 +++++++++++++++++++++++++ beacon/light/committee_chain.go | 25 +- beacon/light/committee_chain_test.go | 4 +- beacon/light/head_tracker.go | 150 ++++++++ beacon/light/request/scheduler.go | 401 ++++++++++++++++++++ beacon/light/request/scheduler_test.go | 122 ++++++ beacon/light/request/server.go | 439 ++++++++++++++++++++++ beacon/light/request/server_test.go | 158 ++++++++ beacon/light/sync/head_sync.go | 176 +++++++++ beacon/light/sync/head_sync_test.go | 151 ++++++++ beacon/light/sync/test_helpers.go | 254 +++++++++++++ beacon/light/sync/types.go | 42 +++ beacon/light/sync/update_sync.go | 299 +++++++++++++++ beacon/light/sync/update_sync_test.go | 219 +++++++++++ beacon/params/params.go | 2 + beacon/types/light_sync.go | 56 +++ cmd/blsync/engine_api.go | 69 ++++ cmd/blsync/main.go | 125 +++++++ cmd/geth/config.go | 3 + cmd/geth/main.go | 8 + cmd/utils/flags.go | 53 +++ eth/catalyst/blsync.go | 88 +++++ go.mod | 5 +- go.sum | 16 +- internal/flags/categories.go | 1 + node/node.go | 24 +- 31 files changed, 4049 insertions(+), 19 deletions(-) create mode 100755 beacon/blsync/block_sync.go create mode 100644 beacon/blsync/block_sync_test.go create mode 100644 beacon/blsync/client.go create mode 100644 beacon/blsync/config.go create mode 100755 beacon/light/api/api_server.go create mode 100755 beacon/light/api/light_api.go create mode 100644 beacon/light/head_tracker.go create mode 100644 beacon/light/request/scheduler.go create mode 100644 beacon/light/request/scheduler_test.go create mode 100644 beacon/light/request/server.go create mode 100644 beacon/light/request/server_test.go create mode 100644 beacon/light/sync/head_sync.go create mode 100644 beacon/light/sync/head_sync_test.go create mode 100644 beacon/light/sync/test_helpers.go create mode 100644 beacon/light/sync/types.go create mode 100644 beacon/light/sync/update_sync.go create mode 100644 beacon/light/sync/update_sync_test.go create mode 100644 cmd/blsync/engine_api.go create mode 100644 cmd/blsync/main.go create mode 100644 eth/catalyst/blsync.go diff --git a/beacon/blsync/block_sync.go b/beacon/blsync/block_sync.go new file mode 100755 index 000000000000..91b21163e655 --- /dev/null +++ b/beacon/blsync/block_sync.go @@ -0,0 +1,203 @@ +// Copyright 2023 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 blsync + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/beacon/engine" + "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/light/sync" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + ctypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/trie" + "github.com/holiman/uint256" + "github.com/protolambda/zrnt/eth2/beacon/capella" + "github.com/protolambda/zrnt/eth2/configs" + "github.com/protolambda/ztyp/tree" +) + +// beaconBlockSync implements request.Module; it fetches the beacon blocks belonging +// to the validated and prefetch heads. +type beaconBlockSync struct { + recentBlocks *lru.Cache[common.Hash, *capella.BeaconBlock] + locked map[common.Hash]request.ServerAndID + serverHeads map[request.Server]common.Hash + headTracker headTracker + + lastHeadInfo types.HeadInfo + chainHeadFeed *event.Feed +} + +type headTracker interface { + PrefetchHead() types.HeadInfo + ValidatedHead() (types.SignedHeader, bool) + ValidatedFinality() (types.FinalityUpdate, bool) +} + +// newBeaconBlockSync returns a new beaconBlockSync. +func newBeaconBlockSync(headTracker headTracker, chainHeadFeed *event.Feed) *beaconBlockSync { + return &beaconBlockSync{ + headTracker: headTracker, + chainHeadFeed: chainHeadFeed, + recentBlocks: lru.NewCache[common.Hash, *capella.BeaconBlock](10), + locked: make(map[common.Hash]request.ServerAndID), + serverHeads: make(map[request.Server]common.Hash), + } +} + +// Process implements request.Module. +func (s *beaconBlockSync) Process(requester request.Requester, events []request.Event) { + for _, event := range events { + switch event.Type { + case request.EvResponse, request.EvFail, request.EvTimeout: + sid, req, resp := event.RequestInfo() + blockRoot := common.Hash(req.(sync.ReqBeaconBlock)) + if resp != nil { + s.recentBlocks.Add(blockRoot, resp.(*capella.BeaconBlock)) + } + if s.locked[blockRoot] == sid { + delete(s.locked, blockRoot) + } + case sync.EvNewHead: + s.serverHeads[event.Server] = event.Data.(types.HeadInfo).BlockRoot + case request.EvUnregistered: + delete(s.serverHeads, event.Server) + } + } + s.updateEventFeed() + // request validated head block if unavailable and not yet requested + if vh, ok := s.headTracker.ValidatedHead(); ok { + s.tryRequestBlock(requester, vh.Header.Hash(), false) + } + // request prefetch head if the given server has announced it + if prefetchHead := s.headTracker.PrefetchHead().BlockRoot; prefetchHead != (common.Hash{}) { + s.tryRequestBlock(requester, prefetchHead, true) + } +} + +func (s *beaconBlockSync) tryRequestBlock(requester request.Requester, blockRoot common.Hash, needSameHead bool) { + if _, ok := s.recentBlocks.Get(blockRoot); ok { + return + } + if _, ok := s.locked[blockRoot]; ok { + return + } + for _, server := range requester.CanSendTo() { + if needSameHead && (s.serverHeads[server] != blockRoot) { + continue + } + id := requester.Send(server, sync.ReqBeaconBlock(blockRoot)) + s.locked[blockRoot] = request.ServerAndID{Server: server, ID: id} + return + } +} + +func blockHeadInfo(block *capella.BeaconBlock) types.HeadInfo { + if block == nil { + return types.HeadInfo{} + } + return types.HeadInfo{Slot: uint64(block.Slot), BlockRoot: beaconBlockHash(block)} +} + +// beaconBlockHash calculates the hash of a beacon block. +func beaconBlockHash(beaconBlock *capella.BeaconBlock) common.Hash { + return common.Hash(beaconBlock.HashTreeRoot(configs.Mainnet, tree.GetHashFn())) +} + +// getExecBlock extracts the execution block from the beacon block's payload. +func getExecBlock(beaconBlock *capella.BeaconBlock) (*ctypes.Block, error) { + payload := &beaconBlock.Body.ExecutionPayload + txs := make([]*ctypes.Transaction, len(payload.Transactions)) + for i, opaqueTx := range payload.Transactions { + var tx ctypes.Transaction + if err := tx.UnmarshalBinary(opaqueTx); err != nil { + return nil, fmt.Errorf("failed to parse tx %d: %v", i, err) + } + txs[i] = &tx + } + withdrawals := make([]*ctypes.Withdrawal, len(payload.Withdrawals)) + for i, w := range payload.Withdrawals { + withdrawals[i] = &ctypes.Withdrawal{ + Index: uint64(w.Index), + Validator: uint64(w.ValidatorIndex), + Address: common.Address(w.Address), + Amount: uint64(w.Amount), + } + } + wroot := ctypes.DeriveSha(ctypes.Withdrawals(withdrawals), trie.NewStackTrie(nil)) + execHeader := &ctypes.Header{ + ParentHash: common.Hash(payload.ParentHash), + UncleHash: ctypes.EmptyUncleHash, + Coinbase: common.Address(payload.FeeRecipient), + Root: common.Hash(payload.StateRoot), + TxHash: ctypes.DeriveSha(ctypes.Transactions(txs), trie.NewStackTrie(nil)), + ReceiptHash: common.Hash(payload.ReceiptsRoot), + Bloom: ctypes.Bloom(payload.LogsBloom), + Difficulty: common.Big0, + Number: new(big.Int).SetUint64(uint64(payload.BlockNumber)), + GasLimit: uint64(payload.GasLimit), + GasUsed: uint64(payload.GasUsed), + Time: uint64(payload.Timestamp), + Extra: []byte(payload.ExtraData), + MixDigest: common.Hash(payload.PrevRandao), // reused in merge + Nonce: ctypes.BlockNonce{}, // zero + BaseFee: (*uint256.Int)(&payload.BaseFeePerGas).ToBig(), + WithdrawalsHash: &wroot, + } + execBlock := ctypes.NewBlockWithHeader(execHeader).WithBody(txs, nil).WithWithdrawals(withdrawals) + if execBlockHash := execBlock.Hash(); execBlockHash != common.Hash(payload.BlockHash) { + return execBlock, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", common.Hash(payload.BlockHash), execBlockHash) + } + return execBlock, nil +} + +func (s *beaconBlockSync) updateEventFeed() { + head, ok := s.headTracker.ValidatedHead() + if !ok { + return + } + finality, ok := s.headTracker.ValidatedFinality() //TODO fetch directly if subscription does not deliver + if !ok || head.Header.Epoch() != finality.Attested.Header.Epoch() { + return + } + validatedHead := head.Header.Hash() + headBlock, ok := s.recentBlocks.Get(validatedHead) + if !ok { + return + } + headInfo := blockHeadInfo(headBlock) + if headInfo == s.lastHeadInfo { + return + } + s.lastHeadInfo = headInfo + // new head block and finality info available; extract executable data and send event to feed + execBlock, err := getExecBlock(headBlock) + if err != nil { + log.Error("Error extracting execution block from validated beacon block", "error", err) + return + } + s.chainHeadFeed.Send(types.ChainHeadEvent{ + HeadBlock: engine.BlockToExecutableData(execBlock, nil, nil).ExecutionPayload, + Finalized: common.Hash(finality.Finalized.PayloadHeader.BlockHash), + }) +} diff --git a/beacon/blsync/block_sync_test.go b/beacon/blsync/block_sync_test.go new file mode 100644 index 000000000000..9ce434d86273 --- /dev/null +++ b/beacon/blsync/block_sync_test.go @@ -0,0 +1,160 @@ +// Copyright 2023 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 blsync + +import ( + "testing" + + "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/light/sync" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/event" + "github.com/protolambda/zrnt/eth2/beacon/capella" + "github.com/protolambda/zrnt/eth2/configs" + "github.com/protolambda/ztyp/tree" +) + +var ( + testServer1 = "testServer1" + testServer2 = "testServer2" + + testBlock1 = &capella.BeaconBlock{ + Slot: 123, + Body: capella.BeaconBlockBody{ + ExecutionPayload: capella.ExecutionPayload{BlockNumber: 456}, + }, + } + testBlock2 = &capella.BeaconBlock{ + Slot: 124, + Body: capella.BeaconBlockBody{ + ExecutionPayload: capella.ExecutionPayload{BlockNumber: 457}, + }, + } +) + +func init() { + eb1, _ := getExecBlock(testBlock1) + testBlock1.Body.ExecutionPayload.BlockHash = tree.Root(eb1.Hash()) + eb2, _ := getExecBlock(testBlock2) + testBlock2.Body.ExecutionPayload.BlockHash = tree.Root(eb2.Hash()) +} + +func TestBlockSync(t *testing.T) { + ht := &testHeadTracker{} + eventFeed := new(event.Feed) + blockSync := newBeaconBlockSync(ht, eventFeed) + headCh := make(chan types.ChainHeadEvent, 16) + eventFeed.Subscribe(headCh) + ts := sync.NewTestScheduler(t, blockSync) + ts.AddServer(testServer1, 1) + ts.AddServer(testServer2, 1) + + expHeadBlock := func(tci int, expHead *capella.BeaconBlock) { + var expNumber, headNumber uint64 + if expHead != nil { + expNumber = uint64(expHead.Body.ExecutionPayload.BlockNumber) + } + select { + case event := <-headCh: + headNumber = event.HeadBlock.Number + default: + } + if headNumber != expNumber { + t.Errorf("Wrong head block in test case #%d (expected block number %d, got %d)", tci, expNumber, headNumber) + } + } + + // no block requests expected until head tracker knows about a head + ts.Run(1) + expHeadBlock(1, nil) + + // set block 1 as prefetch head, announced by server 2 + head1 := blockHeadInfo(testBlock1) + ht.prefetch = head1 + ts.ServerEvent(sync.EvNewHead, testServer2, head1) + // expect request to server 2 which has announced the head + ts.Run(2, testServer2, sync.ReqBeaconBlock(head1.BlockRoot)) + + // valid response + ts.RequestEvent(request.EvResponse, ts.Request(2, 1), testBlock1) + ts.AddAllowance(testServer2, 1) + ts.Run(3) + // head block still not expected as the fetched block is not the validated head yet + expHeadBlock(3, nil) + + // set as validated head, expect no further requests but block 1 set as head block + ht.validated.Header = blockHeader(testBlock1) + ts.Run(4) + expHeadBlock(4, testBlock1) + + // set block 2 as prefetch head, announced by server 1 + head2 := blockHeadInfo(testBlock2) + ht.prefetch = head2 + ts.ServerEvent(sync.EvNewHead, testServer1, head2) + // expect request to server 1 + ts.Run(5, testServer1, sync.ReqBeaconBlock(head2.BlockRoot)) + + // req2 fails, no further requests expected because server 2 has not announced it + ts.RequestEvent(request.EvFail, ts.Request(5, 1), nil) + ts.Run(6) + + // set as validated head before retrieving block; now it's assumed to be available from server 2 too + ht.validated.Header = blockHeader(testBlock2) + // expect req2 retry to server 2 + ts.Run(7, testServer2, sync.ReqBeaconBlock(head2.BlockRoot)) + // now head block should be unavailable again + expHeadBlock(4, nil) + + // valid response, now head block should be block 2 immediately as it is already validated + ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testBlock2) + ts.Run(8) + expHeadBlock(5, testBlock2) +} + +func blockHeader(block *capella.BeaconBlock) types.Header { + return types.Header{ + Slot: uint64(block.Slot), + ProposerIndex: uint64(block.ProposerIndex), + ParentRoot: common.Hash(block.ParentRoot), + StateRoot: common.Hash(block.StateRoot), + BodyRoot: common.Hash(block.Body.HashTreeRoot(configs.Mainnet, tree.GetHashFn())), + } +} + +type testHeadTracker struct { + prefetch types.HeadInfo + validated types.SignedHeader +} + +func (h *testHeadTracker) PrefetchHead() types.HeadInfo { + return h.prefetch +} + +func (h *testHeadTracker) ValidatedHead() (types.SignedHeader, bool) { + return h.validated, h.validated.Header != (types.Header{}) +} + +// TODO add test case for finality +func (h *testHeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { + return types.FinalityUpdate{ + Attested: types.HeaderWithExecProof{Header: h.validated.Header}, + Finalized: types.HeaderWithExecProof{PayloadHeader: &capella.ExecutionPayloadHeader{}}, + Signature: h.validated.Signature, + SignatureSlot: h.validated.SignatureSlot, + }, h.validated.Header != (types.Header{}) +} diff --git a/beacon/blsync/client.go b/beacon/blsync/client.go new file mode 100644 index 000000000000..1bfbb1316069 --- /dev/null +++ b/beacon/blsync/client.go @@ -0,0 +1,103 @@ +// Copyright 2024 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 blsync + +import ( + "strings" + + "github.com/ethereum/go-ethereum/beacon/light" + "github.com/ethereum/go-ethereum/beacon/light/api" + "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/light/sync" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/event" + "github.com/urfave/cli/v2" +) + +type Client struct { + scheduler *request.Scheduler + chainHeadFeed *event.Feed + urls []string + customHeader map[string]string +} + +func NewClient(ctx *cli.Context) *Client { + if !ctx.IsSet(utils.BeaconApiFlag.Name) { + utils.Fatalf("Beacon node light client API URL not specified") + } + var ( + chainConfig = makeChainConfig(ctx) + customHeader = make(map[string]string) + ) + for _, s := range ctx.StringSlice(utils.BeaconApiHeaderFlag.Name) { + kv := strings.Split(s, ":") + if len(kv) != 2 { + utils.Fatalf("Invalid custom API header entry: %s", s) + } + customHeader[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1]) + } + // create data structures + var ( + db = memorydb.New() + threshold = ctx.Int(utils.BeaconThresholdFlag.Name) + committeeChain = light.NewCommitteeChain(db, chainConfig.ChainConfig, threshold, !ctx.Bool(utils.BeaconNoFilterFlag.Name)) + headTracker = light.NewHeadTracker(committeeChain, threshold) + ) + headSync := sync.NewHeadSync(headTracker, committeeChain) + + // set up scheduler and sync modules + chainHeadFeed := new(event.Feed) + scheduler := request.NewScheduler() + checkpointInit := sync.NewCheckpointInit(committeeChain, chainConfig.Checkpoint) + forwardSync := sync.NewForwardUpdateSync(committeeChain) + beaconBlockSync := newBeaconBlockSync(headTracker, chainHeadFeed) + scheduler.RegisterTarget(headTracker) + scheduler.RegisterTarget(committeeChain) + scheduler.RegisterModule(checkpointInit, "checkpointInit") + scheduler.RegisterModule(forwardSync, "forwardSync") + scheduler.RegisterModule(headSync, "headSync") + scheduler.RegisterModule(beaconBlockSync, "beaconBlockSync") + + return &Client{ + scheduler: scheduler, + urls: ctx.StringSlice(utils.BeaconApiFlag.Name), + customHeader: customHeader, + chainHeadFeed: chainHeadFeed, + } +} + +// SubscribeChainHeadEvent allows callers to subscribe a provided channel to new +// head updates. +func (c *Client) SubscribeChainHeadEvent(ch chan<- types.ChainHeadEvent) event.Subscription { + return c.chainHeadFeed.Subscribe(ch) +} + +func (c *Client) Start() { + c.scheduler.Start() + // register server(s) + for _, url := range c.urls { + beaconApi := api.NewBeaconLightApi(url, c.customHeader) + c.scheduler.RegisterServer(request.NewServer(api.NewApiServer(beaconApi), &mclock.System{})) + } +} + +func (c *Client) Stop() { + c.scheduler.Stop() +} diff --git a/beacon/blsync/config.go b/beacon/blsync/config.go new file mode 100644 index 000000000000..b51d3e2b0566 --- /dev/null +++ b/beacon/blsync/config.go @@ -0,0 +1,113 @@ +// Copyright 2022 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 blsync + +import ( + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/urfave/cli/v2" +) + +// lightClientConfig contains beacon light client configuration +type lightClientConfig struct { + *types.ChainConfig + Checkpoint common.Hash +} + +var ( + MainnetConfig = lightClientConfig{ + ChainConfig: (&types.ChainConfig{ + GenesisValidatorsRoot: common.HexToHash("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"), + GenesisTime: 1606824023, + }). + AddFork("GENESIS", 0, []byte{0, 0, 0, 0}). + AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}). + AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}). + AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}), + Checkpoint: common.HexToHash("0x388be41594ec7d6a6894f18c73f3469f07e2c19a803de4755d335817ed8e2e5a"), + } + + SepoliaConfig = lightClientConfig{ + ChainConfig: (&types.ChainConfig{ + GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"), + GenesisTime: 1655733600, + }). + AddFork("GENESIS", 0, []byte{144, 0, 0, 105}). + AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}). + AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}). + AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}), + Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"), + } + + GoerliConfig = lightClientConfig{ + ChainConfig: (&types.ChainConfig{ + GenesisValidatorsRoot: common.HexToHash("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb"), + GenesisTime: 1614588812, + }). + AddFork("GENESIS", 0, []byte{0, 0, 16, 32}). + AddFork("ALTAIR", 36660, []byte{1, 0, 16, 32}). + AddFork("BELLATRIX", 112260, []byte{2, 0, 16, 32}). + AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}), + Checkpoint: common.HexToHash("0x53a0f4f0a378e2c4ae0a9ee97407eb69d0d737d8d8cd0a5fb1093f42f7b81c49"), + } +) + +func makeChainConfig(ctx *cli.Context) lightClientConfig { + utils.CheckExclusive(ctx, utils.MainnetFlag, utils.GoerliFlag, utils.SepoliaFlag) + customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name) || ctx.IsSet(utils.BeaconGenesisRootFlag.Name) || ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) + var config lightClientConfig + switch { + case ctx.Bool(utils.MainnetFlag.Name): + config = MainnetConfig + case ctx.Bool(utils.SepoliaFlag.Name): + config = SepoliaConfig + case ctx.Bool(utils.GoerliFlag.Name): + config = GoerliConfig + default: + if !customConfig { + config = MainnetConfig + } + } + if customConfig && config.Forks != nil { + utils.Fatalf("Cannot use custom beacon chain config flags in combination with pre-defined network config") + } + if ctx.IsSet(utils.BeaconGenesisRootFlag.Name) { + if c, err := hexutil.Decode(ctx.String(utils.BeaconGenesisRootFlag.Name)); err == nil && len(c) <= 32 { + copy(config.GenesisValidatorsRoot[:len(c)], c) + } else { + utils.Fatalf("Invalid hex string", "beacon.genesis.gvroot", ctx.String(utils.BeaconGenesisRootFlag.Name), "error", err) + } + } + if ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) { + config.GenesisTime = ctx.Uint64(utils.BeaconGenesisTimeFlag.Name) + } + if ctx.IsSet(utils.BeaconConfigFlag.Name) { + if err := config.ChainConfig.LoadForks(ctx.String(utils.BeaconConfigFlag.Name)); err != nil { + utils.Fatalf("Could not load beacon chain config file", "file name", ctx.String(utils.BeaconConfigFlag.Name), "error", err) + } + } + if ctx.IsSet(utils.BeaconCheckpointFlag.Name) { + if c, err := hexutil.Decode(ctx.String(utils.BeaconCheckpointFlag.Name)); err == nil && len(c) <= 32 { + copy(config.Checkpoint[:len(c)], c) + } else { + utils.Fatalf("Invalid hex string", "beacon.checkpoint", ctx.String(utils.BeaconCheckpointFlag.Name), "error", err) + } + } + return config +} diff --git a/beacon/light/api/api_server.go b/beacon/light/api/api_server.go new file mode 100755 index 000000000000..da044f4b2d6e --- /dev/null +++ b/beacon/light/api/api_server.go @@ -0,0 +1,103 @@ +// Copyright 2023 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" + + "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/light/sync" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" +) + +// ApiServer is a wrapper around BeaconLightApi that implements request.requestServer. +type ApiServer struct { + api *BeaconLightApi + eventCallback func(event request.Event) + unsubscribe func() +} + +// NewApiServer creates a new ApiServer. +func NewApiServer(api *BeaconLightApi) *ApiServer { + return &ApiServer{api: api} +} + +// Subscribe implements request.requestServer. +func (s *ApiServer) Subscribe(eventCallback func(event request.Event)) { + s.eventCallback = eventCallback + listener := HeadEventListener{ + OnNewHead: func(slot uint64, blockRoot common.Hash) { + log.Debug("New head received", "slot", slot, "blockRoot", blockRoot) + eventCallback(request.Event{Type: sync.EvNewHead, Data: types.HeadInfo{Slot: slot, BlockRoot: blockRoot}}) + }, + OnSignedHead: func(head types.SignedHeader) { + log.Debug("New signed head received", "slot", head.Header.Slot, "blockRoot", head.Header.Hash(), "signerCount", head.Signature.SignerCount()) + eventCallback(request.Event{Type: sync.EvNewSignedHead, Data: head}) + }, + OnFinality: func(head types.FinalityUpdate) { + log.Debug("New finality update received", "slot", head.Attested.Slot, "blockRoot", head.Attested.Hash(), "signerCount", head.Signature.SignerCount()) + eventCallback(request.Event{Type: sync.EvNewFinalityUpdate, Data: head}) + }, + OnError: func(err error) { + log.Warn("Head event stream error", "err", err) + }, + } + s.unsubscribe = s.api.StartHeadListener(listener) +} + +// SendRequest implements request.requestServer. +func (s *ApiServer) SendRequest(id request.ID, req request.Request) { + go func() { + var resp request.Response + var err error + switch data := req.(type) { + case sync.ReqUpdates: + log.Debug("Beacon API: requesting light client update", "reqid", id, "period", data.FirstPeriod, "count", data.Count) + var r sync.RespUpdates + r.Updates, r.Committees, err = s.api.GetBestUpdatesAndCommittees(data.FirstPeriod, data.Count) + resp = r + case sync.ReqHeader: + log.Debug("Beacon API: requesting header", "reqid", id, "hash", common.Hash(data)) + resp, err = s.api.GetHeader(common.Hash(data)) + case sync.ReqCheckpointData: + log.Debug("Beacon API: requesting checkpoint data", "reqid", id, "hash", common.Hash(data)) + resp, err = s.api.GetCheckpointData(common.Hash(data)) + case sync.ReqBeaconBlock: + log.Debug("Beacon API: requesting block", "reqid", id, "hash", common.Hash(data)) + resp, err = s.api.GetBeaconBlock(common.Hash(data)) + default: + } + + if err != nil { + log.Warn("Beacon API request failed", "type", reflect.TypeOf(req), "reqid", id, "err", err) + s.eventCallback(request.Event{Type: request.EvFail, Data: request.RequestResponse{ID: id, Request: req}}) + } else { + s.eventCallback(request.Event{Type: request.EvResponse, Data: request.RequestResponse{ID: id, Request: req, Response: resp}}) + } + }() +} + +// Unsubscribe implements request.requestServer. +// Note: Unsubscribe should not be called concurrently with Subscribe. +func (s *ApiServer) Unsubscribe() { + if s.unsubscribe != nil { + s.unsubscribe() + s.unsubscribe = nil + } +} diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go new file mode 100755 index 000000000000..fd701dc0a871 --- /dev/null +++ b/beacon/light/api/light_api.go @@ -0,0 +1,496 @@ +// Copyright 2022 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 detaiapi. +// +// 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/json" + "errors" + "fmt" + "io" + "net/http" + "time" + + "github.com/donovanhide/eventsource" + "github.com/ethereum/go-ethereum/beacon/merkle" + "github.com/ethereum/go-ethereum/beacon/params" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/protolambda/zrnt/eth2/beacon/capella" + "github.com/protolambda/zrnt/eth2/configs" + "github.com/protolambda/ztyp/tree" +) + +var ( + ErrNotFound = errors.New("404 Not Found") + ErrInternal = errors.New("500 Internal Server Error") +) + +type CommitteeUpdate struct { + Version string + Update types.LightClientUpdate + NextSyncCommittee types.SerializedSyncCommittee +} + +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate +type committeeUpdateJson struct { + Version string `json:"version"` + Data committeeUpdateData `json:"data"` +} + +type committeeUpdateData struct { + Header jsonBeaconHeader `json:"attested_header"` + NextSyncCommittee types.SerializedSyncCommittee `json:"next_sync_committee"` + NextSyncCommitteeBranch merkle.Values `json:"next_sync_committee_branch"` + FinalizedHeader *jsonBeaconHeader `json:"finalized_header,omitempty"` + FinalityBranch merkle.Values `json:"finality_branch,omitempty"` + SyncAggregate types.SyncAggregate `json:"sync_aggregate"` + SignatureSlot common.Decimal `json:"signature_slot"` +} + +type jsonBeaconHeader struct { + Beacon types.Header `json:"beacon"` +} + +type jsonHeaderWithExecProof struct { + Beacon types.Header `json:"beacon"` + Execution *capella.ExecutionPayloadHeader `json:"execution"` + ExecutionBranch merkle.Values `json:"execution_branch"` +} + +// UnmarshalJSON unmarshals from JSON. +func (u *CommitteeUpdate) UnmarshalJSON(input []byte) error { + var dec committeeUpdateJson + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + u.Version = dec.Version + u.NextSyncCommittee = dec.Data.NextSyncCommittee + u.Update = types.LightClientUpdate{ + AttestedHeader: types.SignedHeader{ + Header: dec.Data.Header.Beacon, + Signature: dec.Data.SyncAggregate, + SignatureSlot: uint64(dec.Data.SignatureSlot), + }, + NextSyncCommitteeRoot: u.NextSyncCommittee.Root(), + NextSyncCommitteeBranch: dec.Data.NextSyncCommitteeBranch, + FinalityBranch: dec.Data.FinalityBranch, + } + if dec.Data.FinalizedHeader != nil { + u.Update.FinalizedHeader = &dec.Data.FinalizedHeader.Beacon + } + return nil +} + +// fetcher is an interface useful for debug-harnessing the http api. +type fetcher interface { + Do(req *http.Request) (*http.Response, error) +} + +// BeaconLightApi requests light client information from a beacon node REST API. +// Note: all required API endpoints are currently only implemented by Lodestar. +type BeaconLightApi struct { + url string + client fetcher + customHeaders map[string]string +} + +func NewBeaconLightApi(url string, customHeaders map[string]string) *BeaconLightApi { + return &BeaconLightApi{ + url: url, + client: &http.Client{ + Timeout: time.Second * 10, + }, + customHeaders: customHeaders, + } +} + +func (api *BeaconLightApi) httpGet(path string) ([]byte, error) { + req, err := http.NewRequest("GET", api.url+path, nil) + if err != nil { + return nil, err + } + for k, v := range api.customHeaders { + req.Header.Set(k, v) + } + resp, err := api.client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + return io.ReadAll(resp.Body) + case 404: + return nil, ErrNotFound + case 500: + return nil, ErrInternal + default: + return nil, fmt.Errorf("unexpected error from API endpoint \"%s\": status code %d", path, resp.StatusCode) + } +} + +func (api *BeaconLightApi) httpGetf(format string, params ...any) ([]byte, error) { + return api.httpGet(fmt.Sprintf(format, params...)) +} + +// GetBestUpdateAndCommittee fetches and validates LightClientUpdate for given +// period and full serialized committee for the next period (committee root hash +// equals update.NextSyncCommitteeRoot). +// Note that the results are validated but the update signature should be verified +// by the caller as its validity depends on the update chain. +func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64) ([]*types.LightClientUpdate, []*types.SerializedSyncCommittee, error) { + resp, err := api.httpGetf("/eth/v1/beacon/light_client/updates?start_period=%d&count=%d", firstPeriod, count) + if err != nil { + return nil, nil, err + } + + var data []CommitteeUpdate + if err := json.Unmarshal(resp, &data); err != nil { + return nil, nil, err + } + if len(data) != int(count) { + return nil, nil, errors.New("invalid number of committee updates") + } + updates := make([]*types.LightClientUpdate, int(count)) + committees := make([]*types.SerializedSyncCommittee, int(count)) + for i, d := range data { + if d.Update.AttestedHeader.Header.SyncPeriod() != firstPeriod+uint64(i) { + return nil, nil, errors.New("wrong committee update header period") + } + if err := d.Update.Validate(); err != nil { + return nil, nil, err + } + if d.NextSyncCommittee.Root() != d.Update.NextSyncCommitteeRoot { + return nil, nil, errors.New("wrong sync committee root") + } + updates[i], committees[i] = new(types.LightClientUpdate), new(types.SerializedSyncCommittee) + *updates[i], *committees[i] = d.Update, d.NextSyncCommittee + } + return updates, committees, nil +} + +// GetOptimisticHeadUpdate fetches a signed header based on the latest available +// optimistic update. Note that the signature should be verified by the caller +// as its validity depends on the update chain. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate +func (api *BeaconLightApi) GetOptimisticHeadUpdate() (types.SignedHeader, error) { + resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update") + if err != nil { + return types.SignedHeader{}, err + } + return decodeOptimisticHeadUpdate(resp) +} + +func decodeOptimisticHeadUpdate(enc []byte) (types.SignedHeader, error) { + var data struct { + Data struct { + Header jsonBeaconHeader `json:"attested_header"` + Aggregate types.SyncAggregate `json:"sync_aggregate"` + SignatureSlot common.Decimal `json:"signature_slot"` + } `json:"data"` + } + if err := json.Unmarshal(enc, &data); err != nil { + return types.SignedHeader{}, err + } + if data.Data.Header.Beacon.StateRoot == (common.Hash{}) { + // workaround for different event encoding format in Lodestar + if err := json.Unmarshal(enc, &data.Data); err != nil { + return types.SignedHeader{}, err + } + } + + if len(data.Data.Aggregate.Signers) != params.SyncCommitteeBitmaskSize { + return types.SignedHeader{}, errors.New("invalid sync_committee_bits length") + } + if len(data.Data.Aggregate.Signature) != params.BLSSignatureSize { + return types.SignedHeader{}, errors.New("invalid sync_committee_signature length") + } + return types.SignedHeader{ + Header: data.Data.Header.Beacon, + Signature: data.Data.Aggregate, + SignatureSlot: uint64(data.Data.SignatureSlot), + }, nil +} + +// GetFinalityUpdate fetches the latest available finality update. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate +func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) { + resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update") + if err != nil { + return types.FinalityUpdate{}, err + } + return decodeFinalityUpdate(resp) +} + +func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) { + var data struct { + Data struct { + Attested jsonHeaderWithExecProof `json:"attested_header"` + Finalized jsonHeaderWithExecProof `json:"finalized_header"` + FinalityBranch merkle.Values `json:"finality_branch"` + Aggregate types.SyncAggregate `json:"sync_aggregate"` + SignatureSlot common.Decimal `json:"signature_slot"` + } `json:"data"` + } + if err := json.Unmarshal(enc, &data); err != nil { + return types.FinalityUpdate{}, err + } + + if len(data.Data.Aggregate.Signers) != params.SyncCommitteeBitmaskSize { + return types.FinalityUpdate{}, errors.New("invalid sync_committee_bits length") + } + if len(data.Data.Aggregate.Signature) != params.BLSSignatureSize { + return types.FinalityUpdate{}, errors.New("invalid sync_committee_signature length") + } + return types.FinalityUpdate{ + Attested: types.HeaderWithExecProof{ + Header: data.Data.Attested.Beacon, + PayloadHeader: data.Data.Attested.Execution, + PayloadBranch: data.Data.Attested.ExecutionBranch, + }, + Finalized: types.HeaderWithExecProof{ + Header: data.Data.Finalized.Beacon, + PayloadHeader: data.Data.Finalized.Execution, + PayloadBranch: data.Data.Finalized.ExecutionBranch, + }, + FinalityBranch: data.Data.FinalityBranch, + Signature: data.Data.Aggregate, + SignatureSlot: uint64(data.Data.SignatureSlot), + }, nil +} + +// GetHead fetches and validates the beacon header with the given blockRoot. +// If blockRoot is null hash then the latest head header is fetched. +func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, error) { + var blockId string + if blockRoot == (common.Hash{}) { + blockId = "head" + } else { + blockId = blockRoot.Hex() + } + resp, err := api.httpGetf("/eth/v1/beacon/headers/%s", blockId) + if err != nil { + return types.Header{}, err + } + + var data struct { + Data struct { + Root common.Hash `json:"root"` + Canonical bool `json:"canonical"` + Header struct { + Message types.Header `json:"message"` + Signature hexutil.Bytes `json:"signature"` + } `json:"header"` + } `json:"data"` + } + if err := json.Unmarshal(resp, &data); err != nil { + return types.Header{}, err + } + header := data.Data.Header.Message + if blockRoot == (common.Hash{}) { + blockRoot = data.Data.Root + } + if header.Hash() != blockRoot { + return types.Header{}, errors.New("retrieved beacon header root does not match") + } + return header, nil +} + +// GetCheckpointData fetches and validates bootstrap data belonging to the given checkpoint. +func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types.BootstrapData, error) { + resp, err := api.httpGetf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:]) + if err != nil { + return nil, err + } + + // See data structure definition here: + // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientbootstrap + type bootstrapData struct { + Data struct { + Header jsonBeaconHeader `json:"header"` + Committee *types.SerializedSyncCommittee `json:"current_sync_committee"` + CommitteeBranch merkle.Values `json:"current_sync_committee_branch"` + } `json:"data"` + } + + var data bootstrapData + if err := json.Unmarshal(resp, &data); err != nil { + return nil, err + } + if data.Data.Committee == nil { + return nil, errors.New("sync committee is missing") + } + header := data.Data.Header.Beacon + if header.Hash() != checkpointHash { + return nil, fmt.Errorf("invalid checkpoint block header, have %v want %v", header.Hash(), checkpointHash) + } + checkpoint := &types.BootstrapData{ + Header: header, + CommitteeBranch: data.Data.CommitteeBranch, + CommitteeRoot: data.Data.Committee.Root(), + Committee: data.Data.Committee, + } + if err := checkpoint.Validate(); err != nil { + return nil, fmt.Errorf("invalid checkpoint: %w", err) + } + if checkpoint.Header.Hash() != checkpointHash { + return nil, errors.New("wrong checkpoint hash") + } + return checkpoint, nil +} + +func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*capella.BeaconBlock, error) { + resp, err := api.httpGetf("/eth/v2/beacon/blocks/0x%x", blockRoot) + if err != nil { + return nil, err + } + + var beaconBlockMessage struct { + Data struct { + Message capella.BeaconBlock `json:"message"` + } `json:"data"` + } + if err := json.Unmarshal(resp, &beaconBlockMessage); err != nil { + return nil, fmt.Errorf("invalid block json data: %v", err) + } + beaconBlock := new(capella.BeaconBlock) + *beaconBlock = beaconBlockMessage.Data.Message + root := common.Hash(beaconBlock.HashTreeRoot(configs.Mainnet, tree.GetHashFn())) + if root != blockRoot { + return nil, fmt.Errorf("Beacon block root hash mismatch (expected: %x, got: %x)", blockRoot, root) + } + return beaconBlock, nil +} + +func decodeHeadEvent(enc []byte) (uint64, common.Hash, error) { + var data struct { + Slot common.Decimal `json:"slot"` + Block common.Hash `json:"block"` + } + if err := json.Unmarshal(enc, &data); err != nil { + return 0, common.Hash{}, err + } + return uint64(data.Slot), data.Block, nil +} + +type HeadEventListener struct { + OnNewHead func(slot uint64, blockRoot common.Hash) + OnSignedHead func(head types.SignedHeader) + OnFinality func(head types.FinalityUpdate) + OnError func(err error) +} + +// StartHeadListener creates an event subscription for heads and signed (optimistic) +// head updates and calls the specified callback functions when they are received. +// The callbacks are also called for the current head and optimistic head at startup. +// They are never called concurrently. +func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() { + closeCh := make(chan struct{}) // initiate closing the stream + closedCh := make(chan struct{}) // stream closed (or failed to create) + stoppedCh := make(chan struct{}) // sync loop stopped + streamCh := make(chan *eventsource.Stream, 1) + go func() { + defer close(closedCh) + // when connected to a Lodestar node the subscription blocks until the + // first actual event arrives; therefore we create the subscription in + // a separate goroutine while letting the main goroutine sync up to the + // current head + req, err := http.NewRequest("GET", api.url+ + "/eth/v1/events?topics=head&topics=light_client_optimistic_update&topics=light_client_finality_update", nil) + if err != nil { + listener.OnError(fmt.Errorf("error creating event subscription request: %v", err)) + return + } + for k, v := range api.customHeaders { + req.Header.Set(k, v) + } + stream, err := eventsource.SubscribeWithRequest("", req) + if err != nil { + listener.OnError(fmt.Errorf("error creating event subscription: %v", err)) + close(streamCh) + return + } + streamCh <- stream + <-closeCh + stream.Close() + }() + + go func() { + defer close(stoppedCh) + + if head, err := api.GetHeader(common.Hash{}); err == nil { + listener.OnNewHead(head.Slot, head.Hash()) + } + if signedHead, err := api.GetOptimisticHeadUpdate(); err == nil { + listener.OnSignedHead(signedHead) + } + if finalityUpdate, err := api.GetFinalityUpdate(); err == nil { + listener.OnFinality(finalityUpdate) + } + stream := <-streamCh + if stream == nil { + return + } + + for { + select { + case event, ok := <-stream.Events: + if !ok { + break + } + switch event.Event() { + case "head": + if slot, blockRoot, err := decodeHeadEvent([]byte(event.Data())); err == nil { + listener.OnNewHead(slot, blockRoot) + } else { + listener.OnError(fmt.Errorf("error decoding head event: %v", err)) + } + case "light_client_optimistic_update": + if signedHead, err := decodeOptimisticHeadUpdate([]byte(event.Data())); err == nil { + listener.OnSignedHead(signedHead) + } else { + listener.OnError(fmt.Errorf("error decoding optimistic update event: %v", err)) + } + case "light_client_finality_update": + if finalityUpdate, err := decodeFinalityUpdate([]byte(event.Data())); err == nil { + listener.OnFinality(finalityUpdate) + } else { + listener.OnError(fmt.Errorf("error decoding finality update event: %v", err)) + } + default: + listener.OnError(fmt.Errorf("unexpected event: %s", event.Event())) + } + case err, ok := <-stream.Errors: + if !ok { + break + } + listener.OnError(err) + } + } + }() + return func() { + close(closeCh) + <-closedCh + <-stoppedCh + } +} diff --git a/beacon/light/committee_chain.go b/beacon/light/committee_chain.go index d707f8cc34da..a8d032bb65c5 100644 --- a/beacon/light/committee_chain.go +++ b/beacon/light/committee_chain.go @@ -70,6 +70,7 @@ type CommitteeChain struct { committees *canonicalStore[*types.SerializedSyncCommittee] fixedCommitteeRoots *canonicalStore[common.Hash] committeeCache *lru.Cache[uint64, syncCommittee] // cache deserialized committees + changeCounter uint64 clock mclock.Clock // monotonic clock (simulated clock in tests) unixNano func() int64 // system clock (simulated clock in tests) @@ -86,6 +87,11 @@ func NewCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signer return newCommitteeChain(db, config, signerThreshold, enforceTime, blsVerifier{}, &mclock.System{}, func() int64 { return time.Now().UnixNano() }) } +// NewTestCommitteeChain creates a new CommitteeChain for testing. +func NewTestCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, clock *mclock.Simulated) *CommitteeChain { + return newCommitteeChain(db, config, signerThreshold, enforceTime, dummyVerifier{}, clock, func() int64 { return int64(clock.Now()) }) +} + // newCommitteeChain creates a new CommitteeChain with the option of replacing the // clock source and signature verification for testing purposes. func newCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain { @@ -181,20 +187,20 @@ func (s *CommitteeChain) Reset() { if err := s.rollback(0); err != nil { log.Error("Error writing batch into chain database", "error", err) } + s.changeCounter++ } -// CheckpointInit initializes a CommitteeChain based on the checkpoint. +// CheckpointInit initializes a CommitteeChain based on a checkpoint. // Note: if the chain is already initialized and the committees proven by the // checkpoint do match the existing chain then the chain is retained and the // new checkpoint becomes fixed. -func (s *CommitteeChain) CheckpointInit(bootstrap *types.BootstrapData) error { +func (s *CommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error { s.chainmu.Lock() defer s.chainmu.Unlock() if err := bootstrap.Validate(); err != nil { return err } - period := bootstrap.Header.SyncPeriod() if err := s.deleteFixedCommitteeRootsFrom(period + 2); err != nil { s.Reset() @@ -215,6 +221,7 @@ func (s *CommitteeChain) CheckpointInit(bootstrap *types.BootstrapData) error { s.Reset() return err } + s.changeCounter++ return nil } @@ -367,6 +374,7 @@ func (s *CommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommi return ErrWrongCommitteeRoot } } + s.changeCounter++ if reorg { if err := s.rollback(period + 1); err != nil { return err @@ -405,6 +413,13 @@ func (s *CommitteeChain) NextSyncPeriod() (uint64, bool) { return s.committees.periods.End - 1, true } +func (s *CommitteeChain) ChangeCounter() uint64 { + s.chainmu.RLock() + defer s.chainmu.RUnlock() + + return s.changeCounter +} + // rollback removes all committees and fixed roots from the given period and updates // starting from the previous period. func (s *CommitteeChain) rollback(period uint64) error { @@ -452,12 +467,12 @@ func (s *CommitteeChain) getSyncCommittee(period uint64) (syncCommittee, error) if sc, ok := s.committees.get(s.db, period); ok { c, err := s.sigVerifier.deserializeSyncCommittee(sc) if err != nil { - return nil, fmt.Errorf("Sync committee #%d deserialization error: %v", period, err) + return nil, fmt.Errorf("sync committee #%d deserialization error: %v", period, err) } s.committeeCache.Add(period, c) return c, nil } - return nil, fmt.Errorf("Missing serialized sync committee #%d", period) + return nil, fmt.Errorf("missing serialized sync committee #%d", period) } // VerifySignedHeader returns true if the given signed header has a valid signature diff --git a/beacon/light/committee_chain_test.go b/beacon/light/committee_chain_test.go index 60ea2a0efdbf..57b6d7175cce 100644 --- a/beacon/light/committee_chain_test.go +++ b/beacon/light/committee_chain_test.go @@ -241,12 +241,12 @@ func newCommitteeChainTest(t *testing.T, config types.ChainConfig, signerThresho signerThreshold: signerThreshold, enforceTime: enforceTime, } - c.chain = newCommitteeChain(c.db, &config, signerThreshold, enforceTime, dummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) }) + c.chain = NewTestCommitteeChain(c.db, &config, signerThreshold, enforceTime, c.clock) return c } func (c *committeeChainTest) reloadChain() { - c.chain = newCommitteeChain(c.db, &c.config, c.signerThreshold, c.enforceTime, dummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) }) + c.chain = NewTestCommitteeChain(c.db, &c.config, c.signerThreshold, c.enforceTime, c.clock) } func (c *committeeChainTest) setClockPeriod(period float64) { diff --git a/beacon/light/head_tracker.go b/beacon/light/head_tracker.go new file mode 100644 index 000000000000..579e1b53daa9 --- /dev/null +++ b/beacon/light/head_tracker.go @@ -0,0 +1,150 @@ +// Copyright 2023 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 light + +import ( + "errors" + "sync" + "time" + + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/log" +) + +// HeadTracker keeps track of the latest validated head and the "prefetch" head +// which is the (not necessarily validated) head announced by the majority of +// servers. +type HeadTracker struct { + lock sync.RWMutex + committeeChain *CommitteeChain + minSignerCount int + signedHead types.SignedHeader + hasSignedHead bool + finalityUpdate types.FinalityUpdate + hasFinalityUpdate bool + prefetchHead types.HeadInfo + changeCounter uint64 +} + +// NewHeadTracker creates a new HeadTracker. +func NewHeadTracker(committeeChain *CommitteeChain, minSignerCount int) *HeadTracker { + return &HeadTracker{ + committeeChain: committeeChain, + minSignerCount: minSignerCount, + } +} + +// ValidatedHead returns the latest validated head. +func (h *HeadTracker) ValidatedHead() (types.SignedHeader, bool) { + h.lock.RLock() + defer h.lock.RUnlock() + + return h.signedHead, h.hasSignedHead +} + +// ValidatedHead returns the latest validated head. +func (h *HeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { + h.lock.RLock() + defer h.lock.RUnlock() + + return h.finalityUpdate, h.hasFinalityUpdate +} + +// Validate validates the given signed head. If the head is successfully validated +// and it is better than the old validated head (higher slot or same slot and more +// signers) then ValidatedHead is updated. The boolean return flag signals if +// ValidatedHead has been changed. +func (h *HeadTracker) ValidateHead(head types.SignedHeader) (bool, error) { + h.lock.Lock() + defer h.lock.Unlock() + + replace, err := h.validate(head, h.signedHead) + if replace { + h.signedHead, h.hasSignedHead = head, true + h.changeCounter++ + } + return replace, err +} + +func (h *HeadTracker) ValidateFinality(update types.FinalityUpdate) (bool, error) { + h.lock.Lock() + defer h.lock.Unlock() + + replace, err := h.validate(update.SignedHeader(), h.finalityUpdate.SignedHeader()) + if replace { + h.finalityUpdate, h.hasFinalityUpdate = update, true + h.changeCounter++ + } + return replace, err +} + +func (h *HeadTracker) validate(head, oldHead types.SignedHeader) (bool, error) { + signerCount := head.Signature.SignerCount() + if signerCount < h.minSignerCount { + return false, errors.New("low signer count") + } + if head.Header.Slot < oldHead.Header.Slot || (head.Header.Slot == oldHead.Header.Slot && signerCount <= oldHead.Signature.SignerCount()) { + return false, nil + } + sigOk, age, err := h.committeeChain.VerifySignedHeader(head) + if err != nil { + return false, err + } + if age < 0 { + log.Warn("Future signed head received", "age", age) + } + if age > time.Minute*2 { + log.Warn("Old signed head received", "age", age) + } + if !sigOk { + return false, errors.New("invalid header signature") + } + return true, nil +} + +// PrefetchHead returns the latest known prefetch head's head info. +// This head can be used to start fetching related data hoping that it will be +// validated soon. +// Note that the prefetch head cannot be validated cryptographically so it should +// only be used as a performance optimization hint. +func (h *HeadTracker) PrefetchHead() types.HeadInfo { + h.lock.RLock() + defer h.lock.RUnlock() + + return h.prefetchHead +} + +// SetPrefetchHead sets the prefetch head info. +// Note that HeadTracker does not verify the prefetch head, just acts as a thread +// safe bulletin board. +func (h *HeadTracker) SetPrefetchHead(head types.HeadInfo) { + h.lock.Lock() + defer h.lock.Unlock() + + if head == h.prefetchHead { + return + } + h.prefetchHead = head + h.changeCounter++ +} + +func (h *HeadTracker) ChangeCounter() uint64 { + h.lock.RLock() + defer h.lock.RUnlock() + + return h.changeCounter +} diff --git a/beacon/light/request/scheduler.go b/beacon/light/request/scheduler.go new file mode 100644 index 000000000000..20f811900ecf --- /dev/null +++ b/beacon/light/request/scheduler.go @@ -0,0 +1,401 @@ +// Copyright 2023 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 request + +import ( + "sync" + + "github.com/ethereum/go-ethereum/log" +) + +// Module represents a mechanism which is typically responsible for downloading +// and updating a passive data structure. It does not directly interact with the +// servers. It can start requests using the Requester interface, maintain its +// internal state by receiving and processing Events and update its target data +// structure based on the obtained data. +// It is the Scheduler's responsibility to feed events to the modules, call +// Process as long as there might be something to process and then generate request +// candidates using MakeRequest and start the best possible requests. +// Modules are called by Scheduler whenever a global trigger is fired. All events +// fire the trigger. Changing a target data structure also triggers a next +// processing round as it could make further actions possible either by the same +// or another Module. +type Module interface { + // Process is a non-blocking function responsible for starting requests, + // processing events and updating the target data structures(s) and the + // internal state of the module. Module state typically consists of information + // about pending requests and registered servers. + // Process is always called after an event is received or after a target data + // structure has been changed. + // + // Note: Process functions of different modules are never called concurrently; + // they are called by Scheduler in the same order of priority as they were + // registered in. + Process(Requester, []Event) +} + +// Requester allows Modules to obtain the list of momentarily available servers, +// start new requests and report server failure when a response has been proven +// to be invalid in the processing phase. +// Note that all Requester functions should be safe to call from Module.Process. +type Requester interface { + CanSendTo() []Server + Send(Server, Request) ID + Fail(Server, string) +} + +// Scheduler is a modular network data retrieval framework that coordinates multiple +// servers and retrieval mechanisms (modules). It implements a trigger mechanism +// that calls the Process function of registered modules whenever either the state +// of existing data structures or events coming from registered servers could +// allow new operations. +type Scheduler struct { + lock sync.Mutex + modules []Module // first has highest priority + names map[Module]string + servers map[server]struct{} + targets map[targetData]uint64 + + requesterLock sync.RWMutex + serverOrder []server + pending map[ServerAndID]pendingRequest + + // eventLock guards access to the events list. Note that eventLock can be + // locked either while lock is locked or unlocked but lock cannot be locked + // while eventLock is locked. + eventLock sync.Mutex + events []Event + stopCh chan chan struct{} + + triggerCh chan struct{} // restarts waiting sync loop + // if trigger has already been fired then send to testWaitCh blocks until + // the triggered processing round is finished + testWaitCh chan struct{} +} + +type ( + // Server identifies a server without allowing any direct interaction. + // Note: server interface is used by Scheduler and Tracker but not used by + // the modules that do not interact with them directly. + // In order to make module testing easier, Server interface is used in + // events and modules. + Server any + Request any + Response any + ID uint64 + ServerAndID struct { + Server Server + ID ID + } +) + +// targetData represents a registered target data structure that increases its +// ChangeCounter whenever it has been changed. +type targetData interface { + ChangeCounter() uint64 +} + +// pendingRequest keeps track of sent and not yet finalized requests and their +// sender modules. +type pendingRequest struct { + request Request + module Module +} + +// NewScheduler creates a new Scheduler. +func NewScheduler() *Scheduler { + s := &Scheduler{ + servers: make(map[server]struct{}), + names: make(map[Module]string), + pending: make(map[ServerAndID]pendingRequest), + targets: make(map[targetData]uint64), + stopCh: make(chan chan struct{}), + // Note: testWaitCh should not have capacity in order to ensure + // that after a trigger happens testWaitCh will block until the resulting + // processing round has been finished + triggerCh: make(chan struct{}, 1), + testWaitCh: make(chan struct{}), + } + return s +} + +// RegisterTarget registers a target data structure, ensuring that any changes +// made to it trigger a new round of Module.Process calls, giving a chance to +// modules to react to the changes. +func (s *Scheduler) RegisterTarget(t targetData) { + s.lock.Lock() + defer s.lock.Unlock() + + s.targets[t] = 0 +} + +// RegisterModule registers a module. Should be called before starting the scheduler. +// In each processing round the order of module processing depends on the order of +// registration. +func (s *Scheduler) RegisterModule(m Module, name string) { + s.lock.Lock() + defer s.lock.Unlock() + + s.modules = append(s.modules, m) + s.names[m] = name +} + +// RegisterServer registers a new server. +func (s *Scheduler) RegisterServer(server server) { + s.lock.Lock() + defer s.lock.Unlock() + + s.addEvent(Event{Type: EvRegistered, Server: server}) + server.subscribe(func(event Event) { + event.Server = server + s.addEvent(event) + }) +} + +// UnregisterServer removes a registered server. +func (s *Scheduler) UnregisterServer(server server) { + s.lock.Lock() + defer s.lock.Unlock() + + server.unsubscribe() + s.addEvent(Event{Type: EvUnregistered, Server: server}) +} + +// Start starts the scheduler. It should be called after registering all modules +// and before registering any servers. +func (s *Scheduler) Start() { + go s.syncLoop() +} + +// Stop stops the scheduler. +func (s *Scheduler) Stop() { + stop := make(chan struct{}) + s.stopCh <- stop + <-stop + s.lock.Lock() + for server := range s.servers { + server.unsubscribe() + } + s.servers = nil + s.lock.Unlock() +} + +// syncLoop is the main event loop responsible for event/data processing and +// sending new requests. +// A round of processing starts whenever the global trigger is fired. Triggers +// fired during a processing round ensure that there is going to be a next round. +func (s *Scheduler) syncLoop() { + for { + s.lock.Lock() + s.processRound() + s.lock.Unlock() + loop: + for { + select { + case stop := <-s.stopCh: + close(stop) + return + case <-s.triggerCh: + break loop + case <-s.testWaitCh: + } + } + } +} + +// targetChanged returns true if a registered target data structure has been +// changed since the last call to this function. +func (s *Scheduler) targetChanged() (changed bool) { + for target, counter := range s.targets { + if newCounter := target.ChangeCounter(); newCounter != counter { + s.targets[target] = newCounter + changed = true + } + } + return +} + +// processRound runs an entire processing round. It calls the Process functions +// of all modules, passing all relevant events and repeating Process calls as +// long as any changes have been made to the registered target data structures. +// Once all events have been processed and a stable state has been achieved, +// requests are generated and sent if necessary and possible. +func (s *Scheduler) processRound() { + for { + log.Trace("Processing modules") + filteredEvents := s.filterEvents() + for _, module := range s.modules { + log.Trace("Processing module", "name", s.names[module], "events", len(filteredEvents[module])) + module.Process(requester{s, module}, filteredEvents[module]) + } + if !s.targetChanged() { + break + } + } +} + +// Trigger starts a new processing round. If fired during processing, it ensures +// another full round of processing all modules. +func (s *Scheduler) Trigger() { + select { + case s.triggerCh <- struct{}{}: + default: + } +} + +// addEvent adds an event to be processed in the next round. Note that it can be +// called regardless of the state of the lock mutex, making it safe for use in +// the server event callback. +func (s *Scheduler) addEvent(event Event) { + s.eventLock.Lock() + s.events = append(s.events, event) + s.eventLock.Unlock() + s.Trigger() +} + +// filterEvent sorts each Event either as a request event or a server event, +// depending on its type. Request events are also sorted in a map based on the +// module that originally initiated the request. It also ensures that no events +// related to a server are returned before EvRegistered or after EvUnregistered. +// In case of an EvUnregistered server event it also closes all pending requests +// to the given server by adding a failed request event (EvFail), ensuring that +// all requests get finalized and thereby allowing the module logic to be safe +// and simple. +func (s *Scheduler) filterEvents() map[Module][]Event { + s.eventLock.Lock() + events := s.events + s.events = nil + s.eventLock.Unlock() + + s.requesterLock.Lock() + defer s.requesterLock.Unlock() + + filteredEvents := make(map[Module][]Event) + for _, event := range events { + server := event.Server.(server) + if _, ok := s.servers[server]; !ok && event.Type != EvRegistered { + continue // before EvRegister or after EvUnregister, discard + } + + if event.IsRequestEvent() { + sid, _, _ := event.RequestInfo() + pending, ok := s.pending[sid] + if !ok { + continue // request already closed, ignore further events + } + if event.Type == EvResponse || event.Type == EvFail { + delete(s.pending, sid) // final event, close pending request + } + filteredEvents[pending.module] = append(filteredEvents[pending.module], event) + } else { + switch event.Type { + case EvRegistered: + s.servers[server] = struct{}{} + s.serverOrder = append(s.serverOrder, nil) + copy(s.serverOrder[1:], s.serverOrder[:len(s.serverOrder)-1]) + s.serverOrder[0] = server + case EvUnregistered: + s.closePending(event.Server, filteredEvents) + delete(s.servers, server) + for i, srv := range s.serverOrder { + if srv == server { + copy(s.serverOrder[i:len(s.serverOrder)-1], s.serverOrder[i+1:]) + s.serverOrder = s.serverOrder[:len(s.serverOrder)-1] + break + } + } + } + for _, module := range s.modules { + filteredEvents[module] = append(filteredEvents[module], event) + } + } + } + return filteredEvents +} + +// closePending closes all pending requests to the given server and adds an EvFail +// event to properly finalize them +func (s *Scheduler) closePending(server Server, filteredEvents map[Module][]Event) { + for sid, pending := range s.pending { + if sid.Server == server { + filteredEvents[pending.module] = append(filteredEvents[pending.module], Event{ + Type: EvFail, + Server: server, + Data: RequestResponse{ + ID: sid.ID, + Request: pending.request, + }, + }) + delete(s.pending, sid) + } + } +} + +// requester implements Requester. Note that while requester basically wraps +// Scheduler (with the added information of the currently processed Module), all +// functions are safe to call from Module.Process which is running while +// the Scheduler.lock mutex is held. +type requester struct { + *Scheduler + module Module +} + +// CanSendTo returns the list of currently available servers. It also returns +// them in an order of least to most recently used, ensuring a round-robin usage +// of suitable servers if the module always chooses the first suitable one. +func (s requester) CanSendTo() []Server { + s.requesterLock.RLock() + defer s.requesterLock.RUnlock() + + list := make([]Server, 0, len(s.serverOrder)) + for _, server := range s.serverOrder { + if server.canRequestNow() { + list = append(list, server) + } + } + return list +} + +// Send sends a request and adds an entry to Scheduler.pending map, ensuring that +// related request events will be delivered to the sender Module. +func (s requester) Send(srv Server, req Request) ID { + s.requesterLock.Lock() + defer s.requesterLock.Unlock() + + server := srv.(server) + id := server.sendRequest(req) + sid := ServerAndID{Server: srv, ID: id} + s.pending[sid] = pendingRequest{request: req, module: s.module} + for i, ss := range s.serverOrder { + if ss == server { + copy(s.serverOrder[i:len(s.serverOrder)-1], s.serverOrder[i+1:]) + s.serverOrder[len(s.serverOrder)-1] = server + return id + } + } + log.Error("Target server not found in ordered list of registered servers") + return id +} + +// Fail should be called when a server delivers invalid or useless information. +// Calling Fail disables the given server for a period that is initially short +// but is exponentially growing if it happens frequently. This results in a +// somewhat fault tolerant operation that avoids hammering servers with requests +// that they cannot serve but still gives them a chance periodically. +func (s requester) Fail(srv Server, desc string) { + srv.(server).fail(desc) +} diff --git a/beacon/light/request/scheduler_test.go b/beacon/light/request/scheduler_test.go new file mode 100644 index 000000000000..7d5a56707864 --- /dev/null +++ b/beacon/light/request/scheduler_test.go @@ -0,0 +1,122 @@ +package request + +import ( + "reflect" + "testing" +) + +func TestEventFilter(t *testing.T) { + s := NewScheduler() + module1 := &testModule{name: "module1"} + module2 := &testModule{name: "module2"} + s.RegisterModule(module1, "module1") + s.RegisterModule(module2, "module2") + s.Start() + // startup process round without events + s.testWaitCh <- struct{}{} + module1.expProcess(t, nil) + module2.expProcess(t, nil) + srv := &testServer{} + // register server; both modules should receive server event + s.RegisterServer(srv) + s.testWaitCh <- struct{}{} + module1.expProcess(t, []Event{ + {Type: EvRegistered, Server: srv}, + }) + module2.expProcess(t, []Event{ + {Type: EvRegistered, Server: srv}, + }) + // let module1 send a request + srv.canRequest = 1 + module1.sendReq = testRequest + s.Trigger() + // in first triggered round module1 sends the request, no events yet + s.testWaitCh <- struct{}{} + module1.expProcess(t, nil) + module2.expProcess(t, nil) + // server emits EvTimeout; only module1 should receive it + srv.eventCb(Event{Type: EvTimeout, Data: RequestResponse{ID: 1, Request: testRequest}}) + s.testWaitCh <- struct{}{} + module1.expProcess(t, []Event{ + {Type: EvTimeout, Server: srv, Data: RequestResponse{ID: 1, Request: testRequest}}, + }) + module2.expProcess(t, nil) + // unregister server; both modules should receive server event + s.UnregisterServer(srv) + s.testWaitCh <- struct{}{} + module1.expProcess(t, []Event{ + // module1 should also receive EvFail on its pending request + {Type: EvFail, Server: srv, Data: RequestResponse{ID: 1, Request: testRequest}}, + {Type: EvUnregistered, Server: srv}, + }) + module2.expProcess(t, []Event{ + {Type: EvUnregistered, Server: srv}, + }) + // response after server unregistered; should be discarded + srv.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}}) + s.testWaitCh <- struct{}{} + module1.expProcess(t, nil) + module2.expProcess(t, nil) + // no more process rounds expected; shut down + s.testWaitCh <- struct{}{} + module1.expNoMoreProcess(t) + module2.expNoMoreProcess(t) + s.Stop() +} + +type testServer struct { + eventCb func(Event) + lastID ID + canRequest int +} + +func (s *testServer) subscribe(eventCb func(Event)) { + s.eventCb = eventCb +} + +func (s *testServer) canRequestNow() bool { + return s.canRequest > 0 +} + +func (s *testServer) sendRequest(req Request) ID { + s.canRequest-- + s.lastID++ + return s.lastID +} + +func (s *testServer) fail(string) {} +func (s *testServer) unsubscribe() {} + +type testModule struct { + name string + processed [][]Event + sendReq Request +} + +func (m *testModule) Process(requester Requester, events []Event) { + m.processed = append(m.processed, events) + if m.sendReq != nil { + if cs := requester.CanSendTo(); len(cs) > 0 { + requester.Send(cs[0], m.sendReq) + } + } +} + +func (m *testModule) expProcess(t *testing.T, expEvents []Event) { + if len(m.processed) == 0 { + t.Errorf("Missing call to %s.Process", m.name) + return + } + events := m.processed[0] + m.processed = m.processed[1:] + if !reflect.DeepEqual(events, expEvents) { + t.Errorf("Call to %s.Process with wrong events (expected %v, got %v)", m.name, expEvents, events) + } +} + +func (m *testModule) expNoMoreProcess(t *testing.T) { + for len(m.processed) > 0 { + t.Errorf("Unexpected call to %s.Process with events %v", m.name, m.processed[0]) + m.processed = m.processed[1:] + } +} diff --git a/beacon/light/request/server.go b/beacon/light/request/server.go new file mode 100644 index 000000000000..999f64178af4 --- /dev/null +++ b/beacon/light/request/server.go @@ -0,0 +1,439 @@ +// Copyright 2023 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 request + +import ( + "math" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/log" +) + +var ( + // request events + EvResponse = &EventType{Name: "response", requestEvent: true} // data: RequestResponse; sent by requestServer + EvFail = &EventType{Name: "fail", requestEvent: true} // data: RequestResponse; sent by requestServer + EvTimeout = &EventType{Name: "timeout", requestEvent: true} // data: RequestResponse; sent by serverWithTimeout + // server events + EvRegistered = &EventType{Name: "registered"} // data: nil; sent by Scheduler + EvUnregistered = &EventType{Name: "unregistered"} // data: nil; sent by Scheduler + EvCanRequestAgain = &EventType{Name: "canRequestAgain"} // data: nil; sent by serverWithLimits +) + +const ( + softRequestTimeout = time.Second // allow resending request to a different server but do not cancel yet + hardRequestTimeout = time.Second * 10 // cancel request +) + +const ( + // serverWithLimits parameters + parallelAdjustUp = 0.1 // adjust parallelLimit up in case of success under full load + parallelAdjustDown = 1 // adjust parallelLimit down in case of timeout/failure + minParallelLimit = 1 // parallelLimit lower bound + defaultParallelLimit = 3 // parallelLimit initial value + minFailureDelay = time.Millisecond * 100 // minimum disable time in case of request failure + maxFailureDelay = time.Minute // maximum disable time in case of request failure + maxServerEventBuffer = 5 // server event allowance buffer limit + maxServerEventRate = time.Second // server event allowance buffer recharge rate +) + +// requestServer can send requests in a non-blocking way and feed back events +// through the event callback. After each request it should send back either +// EvResponse or EvFail. Additionally, it may also send application-defined +// events that the Modules can interpret. +type requestServer interface { + Subscribe(eventCallback func(Event)) + SendRequest(ID, Request) + Unsubscribe() +} + +// server is implemented by a requestServer wrapped into serverWithTimeout and +// serverWithLimits and is used by Scheduler. +// In addition to requestServer functionality, server can also handle timeouts, +// limit the number of parallel in-flight requests and temporarily disable +// new requests based on timeouts and response failures. +type server interface { + subscribe(eventCallback func(Event)) + canRequestNow() bool + sendRequest(Request) ID + fail(string) + unsubscribe() +} + +// NewServer wraps a requestServer and returns a server +func NewServer(rs requestServer, clock mclock.Clock) server { + s := &serverWithLimits{} + s.parent = rs + s.serverWithTimeout.init(clock) + s.init() + return s +} + +// EventType identifies an event type, either related to a request or the server +// in general. Server events can also be externally defined. +type EventType struct { + Name string + requestEvent bool // all request events are pre-defined in request package +} + +// Event describes an event where the type of Data depends on Type. +// Server field is not required when sent through the event callback; it is filled +// out when processed by the Scheduler. Note that the Scheduler can also create +// and send events (EvRegistered, EvUnregistered) directly. +type Event struct { + Type *EventType + Server Server // filled by Scheduler + Data any +} + +// IsRequestEvent returns true if the event is a request event +func (e *Event) IsRequestEvent() bool { + return e.Type.requestEvent +} + +// RequestInfo assumes that the event is a request event and returns its contents +// in a convenient form. +func (e *Event) RequestInfo() (ServerAndID, Request, Response) { + data := e.Data.(RequestResponse) + return ServerAndID{Server: e.Server, ID: data.ID}, data.Request, data.Response +} + +// RequestResponse is the Data type of request events. +type RequestResponse struct { + ID ID + Request Request + Response Response +} + +// serverWithTimeout wraps a requestServer and introduces timeouts. +// The request's lifecycle is concluded if EvResponse or EvFail emitted by the +// parent requestServer. If this does not happen until softRequestTimeout then +// EvTimeout is emitted, after which the final EvResponse or EvFail is still +// guaranteed to follow. +// If the parent fails to send this final event for hardRequestTimeout then +// serverWithTimeout emits EvFail and discards any further events from the +// parent related to the given request. +type serverWithTimeout struct { + parent requestServer + lock sync.Mutex + clock mclock.Clock + childEventCb func(event Event) + timeouts map[ID]mclock.Timer + lastID ID +} + +// init initializes serverWithTimeout +func (s *serverWithTimeout) init(clock mclock.Clock) { + s.clock = clock + s.timeouts = make(map[ID]mclock.Timer) +} + +// subscribe subscribes to events which include parent (requestServer) events +// plus EvTimeout. +func (s *serverWithTimeout) subscribe(eventCallback func(event Event)) { + s.lock.Lock() + defer s.lock.Unlock() + + s.childEventCb = eventCallback + s.parent.Subscribe(s.eventCallback) +} + +// sendRequest generated a new request ID, emits EvRequest, sets up the timeout +// timer, then sends the request through the parent (requestServer). +func (s *serverWithTimeout) sendRequest(request Request) (reqId ID) { + s.lock.Lock() + s.lastID++ + id := s.lastID + s.startTimeout(RequestResponse{ID: id, Request: request}) + s.lock.Unlock() + s.parent.SendRequest(id, request) + return id +} + +// eventCallback is called by parent (requestServer) event subscription. +func (s *serverWithTimeout) eventCallback(event Event) { + s.lock.Lock() + defer s.lock.Unlock() + + switch event.Type { + case EvResponse, EvFail: + id := event.Data.(RequestResponse).ID + if timer, ok := s.timeouts[id]; ok { + // Note: if stopping the timer is unsuccessful then the resulting AfterFunc + // call will just do nothing + timer.Stop() + delete(s.timeouts, id) + s.childEventCb(event) + } + default: + s.childEventCb(event) + } +} + +// startTimeout starts a timeout timer for the given request. +func (s *serverWithTimeout) startTimeout(reqData RequestResponse) { + id := reqData.ID + s.timeouts[id] = s.clock.AfterFunc(softRequestTimeout, func() { + s.lock.Lock() + if _, ok := s.timeouts[id]; !ok { + s.lock.Unlock() + return + } + s.timeouts[id] = s.clock.AfterFunc(hardRequestTimeout-softRequestTimeout, func() { + s.lock.Lock() + if _, ok := s.timeouts[id]; !ok { + s.lock.Unlock() + return + } + delete(s.timeouts, id) + childEventCb := s.childEventCb + s.lock.Unlock() + childEventCb(Event{Type: EvFail, Data: reqData}) + }) + childEventCb := s.childEventCb + s.lock.Unlock() + childEventCb(Event{Type: EvTimeout, Data: reqData}) + }) +} + +// stop stops all goroutines associated with the server. +func (s *serverWithTimeout) unsubscribe() { + s.lock.Lock() + defer s.lock.Unlock() + + for _, timer := range s.timeouts { + if timer != nil { + timer.Stop() + } + } + s.childEventCb = nil + s.parent.Unsubscribe() +} + +// serverWithLimits wraps serverWithTimeout and implements server. It limits the +// number of parallel in-flight requests and prevents sending new requests when a +// pending one has already timed out. Server events are also rate limited. +// It also implements a failure delay mechanism that adds an exponentially growing +// delay each time a request fails (wrong answer or hard timeout). This makes the +// syncing mechanism less brittle as temporary failures of the server might happen +// sometimes, but still avoids hammering a non-functional server with requests. +type serverWithLimits struct { + serverWithTimeout + lock sync.Mutex + childEventCb func(event Event) + softTimeouts map[ID]struct{} + pendingCount, timeoutCount int + parallelLimit float32 + sendEvent bool + delayTimer mclock.Timer + delayCounter int + failureDelayEnd mclock.AbsTime + failureDelay float64 + serverEventBuffer int + eventBufferUpdated mclock.AbsTime +} + +// init initializes serverWithLimits +func (s *serverWithLimits) init() { + s.softTimeouts = make(map[ID]struct{}) + s.parallelLimit = defaultParallelLimit + s.serverEventBuffer = maxServerEventBuffer +} + +// subscribe subscribes to events which include parent (serverWithTimeout) events +// plus EvCanRequstAgain. +func (s *serverWithLimits) subscribe(eventCallback func(event Event)) { + s.lock.Lock() + defer s.lock.Unlock() + + s.childEventCb = eventCallback + s.serverWithTimeout.subscribe(s.eventCallback) +} + +// eventCallback is called by parent (serverWithTimeout) event subscription. +func (s *serverWithLimits) eventCallback(event Event) { + s.lock.Lock() + var sendCanRequestAgain bool + passEvent := true + switch event.Type { + case EvTimeout: + id := event.Data.(RequestResponse).ID + s.softTimeouts[id] = struct{}{} + s.timeoutCount++ + s.parallelLimit -= parallelAdjustDown + if s.parallelLimit < minParallelLimit { + s.parallelLimit = minParallelLimit + } + log.Debug("Server timeout", "count", s.timeoutCount, "parallelLimit", s.parallelLimit) + case EvResponse, EvFail: + id := event.Data.(RequestResponse).ID + if _, ok := s.softTimeouts[id]; ok { + delete(s.softTimeouts, id) + s.timeoutCount-- + log.Debug("Server timeout finalized", "count", s.timeoutCount, "parallelLimit", s.parallelLimit) + } + if event.Type == EvResponse && s.pendingCount >= int(s.parallelLimit) { + s.parallelLimit += parallelAdjustUp + } + s.pendingCount-- + if s.canRequest() { + sendCanRequestAgain = s.sendEvent + s.sendEvent = false + } + if event.Type == EvFail { + s.failLocked("failed request") + } + default: + // server event; check rate limit + if s.serverEventBuffer < maxServerEventBuffer { + now := s.clock.Now() + sinceUpdate := time.Duration(now - s.eventBufferUpdated) + if sinceUpdate >= maxServerEventRate*time.Duration(maxServerEventBuffer-s.serverEventBuffer) { + s.serverEventBuffer = maxServerEventBuffer + s.eventBufferUpdated = now + } else { + addBuffer := int(sinceUpdate / maxServerEventRate) + s.serverEventBuffer += addBuffer + s.eventBufferUpdated += mclock.AbsTime(maxServerEventRate * time.Duration(addBuffer)) + } + } + if s.serverEventBuffer > 0 { + s.serverEventBuffer-- + } else { + passEvent = false + } + } + childEventCb := s.childEventCb + s.lock.Unlock() + if passEvent { + childEventCb(event) + } + if sendCanRequestAgain { + childEventCb(Event{Type: EvCanRequestAgain}) + } +} + +// sendRequest sends a request through the parent (serverWithTimeout). +func (s *serverWithLimits) sendRequest(request Request) (reqId ID) { + s.lock.Lock() + s.pendingCount++ + s.lock.Unlock() + return s.serverWithTimeout.sendRequest(request) +} + +// stop stops all goroutines associated with the server. +func (s *serverWithLimits) unsubscribe() { + s.lock.Lock() + defer s.lock.Unlock() + + if s.delayTimer != nil { + s.delayTimer.Stop() + s.delayTimer = nil + } + s.childEventCb = nil + s.serverWithTimeout.unsubscribe() +} + +// canRequest checks whether a new request can be started. +func (s *serverWithLimits) canRequest() bool { + if s.delayTimer != nil || s.pendingCount >= int(s.parallelLimit) || s.timeoutCount > 0 { + return false + } + if s.parallelLimit < minParallelLimit { + s.parallelLimit = minParallelLimit + } + return true +} + +// canRequestNow checks whether a new request can be started, according to the +// current in-flight request count and parallelLimit, and also the failure delay +// timer. +// If it returns false then it is guaranteed that an EvCanRequestAgain will be +// sent whenever the server becomes available for requesting again. +func (s *serverWithLimits) canRequestNow() bool { + var sendCanRequestAgain bool + s.lock.Lock() + canRequest := s.canRequest() + if canRequest { + sendCanRequestAgain = s.sendEvent + s.sendEvent = false + } + childEventCb := s.childEventCb + s.lock.Unlock() + if sendCanRequestAgain { + childEventCb(Event{Type: EvCanRequestAgain}) + } + return canRequest +} + +// delay sets the delay timer to the given duration, disabling new requests for +// the given period. +func (s *serverWithLimits) delay(delay time.Duration) { + if s.delayTimer != nil { + // Note: if stopping the timer is unsuccessful then the resulting AfterFunc + // call will just do nothing + s.delayTimer.Stop() + s.delayTimer = nil + } + + s.delayCounter++ + delayCounter := s.delayCounter + log.Debug("Server delay started", "length", delay) + s.delayTimer = s.clock.AfterFunc(delay, func() { + log.Debug("Server delay ended", "length", delay) + var sendCanRequestAgain bool + s.lock.Lock() + if s.delayTimer != nil && s.delayCounter == delayCounter { // do nothing if there is a new timer now + s.delayTimer = nil + if s.canRequest() { + sendCanRequestAgain = s.sendEvent + s.sendEvent = false + } + } + childEventCb := s.childEventCb + s.lock.Unlock() + if sendCanRequestAgain { + childEventCb(Event{Type: EvCanRequestAgain}) + } + }) +} + +// fail reports that a response from the server was found invalid by the processing +// Module, disabling new requests for a dynamically adjused time period. +func (s *serverWithLimits) fail(desc string) { + s.lock.Lock() + defer s.lock.Unlock() + + s.failLocked(desc) +} + +// failLocked calculates the dynamic failure delay and applies it. +func (s *serverWithLimits) failLocked(desc string) { + log.Debug("Server error", "description", desc) + s.failureDelay *= 2 + now := s.clock.Now() + if now > s.failureDelayEnd { + s.failureDelay *= math.Pow(2, -float64(now-s.failureDelayEnd)/float64(maxFailureDelay)) + } + if s.failureDelay < float64(minFailureDelay) { + s.failureDelay = float64(minFailureDelay) + } + s.failureDelayEnd = now + mclock.AbsTime(s.failureDelay) + s.delay(time.Duration(s.failureDelay)) +} diff --git a/beacon/light/request/server_test.go b/beacon/light/request/server_test.go new file mode 100644 index 000000000000..b6b9edf9a056 --- /dev/null +++ b/beacon/light/request/server_test.go @@ -0,0 +1,158 @@ +package request + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common/mclock" +) + +const ( + testRequest = "Life, the Universe, and Everything" + testResponse = 42 +) + +var testEventType = &EventType{Name: "testEvent"} + +func TestServerEvents(t *testing.T) { + rs := &testRequestServer{} + clock := &mclock.Simulated{} + srv := NewServer(rs, clock) + var lastEventType *EventType + srv.subscribe(func(event Event) { lastEventType = event.Type }) + evTypeName := func(evType *EventType) string { + if evType == nil { + return "none" + } + return evType.Name + } + expEvent := func(expType *EventType) { + if lastEventType != expType { + t.Errorf("Wrong event type (expected %s, got %s)", evTypeName(expType), evTypeName(lastEventType)) + } + lastEventType = nil + } + // user events should simply be passed through + rs.eventCb(Event{Type: testEventType}) + expEvent(testEventType) + // send request, soft timeout, then valid response + srv.sendRequest(testRequest) + clock.WaitForTimers(1) + clock.Run(softRequestTimeout) + expEvent(EvTimeout) + rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}}) + expEvent(EvResponse) + // send request, hard timeout (response after hard timeout should be ignored) + srv.sendRequest(testRequest) + clock.WaitForTimers(1) + clock.Run(softRequestTimeout) + expEvent(EvTimeout) + clock.WaitForTimers(1) + clock.Run(hardRequestTimeout) + expEvent(EvFail) + rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}}) + expEvent(nil) +} + +func TestServerParallel(t *testing.T) { + rs := &testRequestServer{} + srv := NewServer(rs, &mclock.Simulated{}) + srv.subscribe(func(event Event) {}) + + expSend := func(expSent int) { + var sent int + for sent <= expSent { + if !srv.canRequestNow() { + break + } + sent++ + srv.sendRequest(testRequest) + } + if sent != expSent { + t.Errorf("Wrong number of parallel requests accepted (expected %d, got %d)", expSent, sent) + } + } + // max out parallel allowance + expSend(defaultParallelLimit) + // 1 answered, should accept 1 more + rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}}) + expSend(1) + // 2 answered, should accept 2 more + rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 2, Request: testRequest, Response: testResponse}}) + rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 3, Request: testRequest, Response: testResponse}}) + expSend(2) + // failed request, should decrease allowance and not accept more + rs.eventCb(Event{Type: EvFail, Data: RequestResponse{ID: 4, Request: testRequest}}) + expSend(0) + srv.unsubscribe() +} + +func TestServerFail(t *testing.T) { + rs := &testRequestServer{} + clock := &mclock.Simulated{} + srv := NewServer(rs, clock) + srv.subscribe(func(event Event) {}) + expCanRequest := func(expCanRequest bool) { + if canRequest := srv.canRequestNow(); canRequest != expCanRequest { + t.Errorf("Wrong result for canRequestNow (expected %v, got %v)", expCanRequest, canRequest) + } + } + // timed out request + expCanRequest(true) + srv.sendRequest(testRequest) + clock.WaitForTimers(1) + expCanRequest(true) + clock.Run(softRequestTimeout) + expCanRequest(false) // cannot request when there is a timed out request + rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}}) + expCanRequest(true) + // explicit server.Fail + srv.fail("") + clock.WaitForTimers(1) + expCanRequest(false) // cannot request for a while after a failure + clock.Run(minFailureDelay) + expCanRequest(true) + // request returned with EvFail + srv.sendRequest(testRequest) + rs.eventCb(Event{Type: EvFail, Data: RequestResponse{ID: 2, Request: testRequest}}) + clock.WaitForTimers(1) + expCanRequest(false) // EvFail should also start failure delay + clock.Run(minFailureDelay) + expCanRequest(false) // second failure delay is longer, should still be disabled + clock.Run(minFailureDelay) + expCanRequest(true) + srv.unsubscribe() +} + +func TestServerEventRateLimit(t *testing.T) { + rs := &testRequestServer{} + clock := &mclock.Simulated{} + srv := NewServer(rs, clock) + var eventCount int + srv.subscribe(func(event Event) { + if !event.IsRequestEvent() { + eventCount++ + } + }) + expEvents := func(send, expAllowed int) { + eventCount = 0 + for sent := 0; sent < send; sent++ { + rs.eventCb(Event{Type: testEventType}) + } + if eventCount != expAllowed { + t.Errorf("Wrong number of server events passing rate limitation (sent %d, expected %d, got %d)", send, expAllowed, eventCount) + } + } + expEvents(maxServerEventBuffer+5, maxServerEventBuffer) + clock.Run(maxServerEventRate) + expEvents(5, 1) + clock.Run(maxServerEventRate * maxServerEventBuffer * 2) + expEvents(maxServerEventBuffer+5, maxServerEventBuffer) +} + +type testRequestServer struct { + eventCb func(Event) +} + +func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb } +func (rs *testRequestServer) SendRequest(ID, Request) {} +func (rs *testRequestServer) Unsubscribe() {} diff --git a/beacon/light/sync/head_sync.go b/beacon/light/sync/head_sync.go new file mode 100644 index 000000000000..9fef95b0df79 --- /dev/null +++ b/beacon/light/sync/head_sync.go @@ -0,0 +1,176 @@ +// Copyright 2023 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 sync + +import ( + "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/types" +) + +type headTracker interface { + ValidateHead(head types.SignedHeader) (bool, error) + ValidateFinality(head types.FinalityUpdate) (bool, error) + SetPrefetchHead(head types.HeadInfo) +} + +// HeadSync implements request.Module; it updates the validated and prefetch +// heads of HeadTracker based on the EvHead and EvSignedHead events coming from +// registered servers. +// It can also postpone the validation of the latest announced signed head +// until the committee chain is synced up to at least the required period. +type HeadSync struct { + headTracker headTracker + chain committeeChain + nextSyncPeriod uint64 + chainInit bool + unvalidatedHeads map[request.Server]types.SignedHeader + unvalidatedFinality map[request.Server]types.FinalityUpdate + serverHeads map[request.Server]types.HeadInfo + headServerCount map[types.HeadInfo]headServerCount + headCounter uint64 + prefetchHead types.HeadInfo +} + +// headServerCount is associated with most recently seen head infos; it counts +// the number of servers currently having the given head info as their announced +// head and a counter signaling how recent that head is. +// This data is used for selecting the prefetch head. +type headServerCount struct { + serverCount int + headCounter uint64 +} + +// NewHeadSync creates a new HeadSync. +func NewHeadSync(headTracker headTracker, chain committeeChain) *HeadSync { + s := &HeadSync{ + headTracker: headTracker, + chain: chain, + unvalidatedHeads: make(map[request.Server]types.SignedHeader), + unvalidatedFinality: make(map[request.Server]types.FinalityUpdate), + serverHeads: make(map[request.Server]types.HeadInfo), + headServerCount: make(map[types.HeadInfo]headServerCount), + } + return s +} + +// Process implements request.Module. +func (s *HeadSync) Process(requester request.Requester, events []request.Event) { + for _, event := range events { + switch event.Type { + case EvNewHead: + s.setServerHead(event.Server, event.Data.(types.HeadInfo)) + case EvNewSignedHead: + s.newSignedHead(event.Server, event.Data.(types.SignedHeader)) + case EvNewFinalityUpdate: + s.newFinalityUpdate(event.Server, event.Data.(types.FinalityUpdate)) + case request.EvUnregistered: + s.setServerHead(event.Server, types.HeadInfo{}) + delete(s.serverHeads, event.Server) + delete(s.unvalidatedHeads, event.Server) + } + } + + nextPeriod, chainInit := s.chain.NextSyncPeriod() + if nextPeriod != s.nextSyncPeriod || chainInit != s.chainInit { + s.nextSyncPeriod, s.chainInit = nextPeriod, chainInit + s.processUnvalidated() + } +} + +// newSignedHead handles received signed head; either validates it if the chain +// is properly synced or stores it for further validation. +func (s *HeadSync) newSignedHead(server request.Server, signedHead types.SignedHeader) { + if !s.chainInit || types.SyncPeriod(signedHead.SignatureSlot) > s.nextSyncPeriod { + s.unvalidatedHeads[server] = signedHead + return + } + s.headTracker.ValidateHead(signedHead) +} + +// newSignedHead handles received signed head; either validates it if the chain +// is properly synced or stores it for further validation. +func (s *HeadSync) newFinalityUpdate(server request.Server, finalityUpdate types.FinalityUpdate) { + if !s.chainInit || types.SyncPeriod(finalityUpdate.SignatureSlot) > s.nextSyncPeriod { + s.unvalidatedFinality[server] = finalityUpdate + return + } + s.headTracker.ValidateFinality(finalityUpdate) +} + +// processUnvalidatedHeads iterates the list of unvalidated heads and validates +// those which can be validated. +func (s *HeadSync) processUnvalidated() { + if !s.chainInit { + return + } + for server, signedHead := range s.unvalidatedHeads { + if types.SyncPeriod(signedHead.SignatureSlot) <= s.nextSyncPeriod { + s.headTracker.ValidateHead(signedHead) + delete(s.unvalidatedHeads, server) + } + } + for server, finalityUpdate := range s.unvalidatedFinality { + if types.SyncPeriod(finalityUpdate.SignatureSlot) <= s.nextSyncPeriod { + s.headTracker.ValidateFinality(finalityUpdate) + delete(s.unvalidatedFinality, server) + } + } +} + +// setServerHead processes non-validated server head announcements and updates +// the prefetch head if necessary. +func (s *HeadSync) setServerHead(server request.Server, head types.HeadInfo) bool { + if oldHead, ok := s.serverHeads[server]; ok { + if head == oldHead { + return false + } + h := s.headServerCount[oldHead] + if h.serverCount--; h.serverCount > 0 { + s.headServerCount[oldHead] = h + } else { + delete(s.headServerCount, oldHead) + } + } + if head != (types.HeadInfo{}) { + h, ok := s.headServerCount[head] + if !ok { + s.headCounter++ + h.headCounter = s.headCounter + } + h.serverCount++ + s.headServerCount[head] = h + s.serverHeads[server] = head + } else { + delete(s.serverHeads, server) + } + var ( + bestHead types.HeadInfo + bestHeadInfo headServerCount + ) + for head, headServerCount := range s.headServerCount { + if headServerCount.serverCount > bestHeadInfo.serverCount || + (headServerCount.serverCount == bestHeadInfo.serverCount && headServerCount.headCounter > bestHeadInfo.headCounter) { + bestHead, bestHeadInfo = head, headServerCount + } + } + if bestHead == s.prefetchHead { + return false + } + s.prefetchHead = bestHead + s.headTracker.SetPrefetchHead(bestHead) + return true +} diff --git a/beacon/light/sync/head_sync_test.go b/beacon/light/sync/head_sync_test.go new file mode 100644 index 000000000000..12faad62920e --- /dev/null +++ b/beacon/light/sync/head_sync_test.go @@ -0,0 +1,151 @@ +// Copyright 2023 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 sync + +import ( + "testing" + + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" +) + +var ( + testServer1 = "testServer1" + testServer2 = "testServer2" + testServer3 = "testServer3" + testServer4 = "testServer4" + + testHead0 = types.HeadInfo{} + testHead1 = types.HeadInfo{Slot: 123, BlockRoot: common.Hash{1}} + testHead2 = types.HeadInfo{Slot: 124, BlockRoot: common.Hash{2}} + testHead3 = types.HeadInfo{Slot: 124, BlockRoot: common.Hash{3}} + testHead4 = types.HeadInfo{Slot: 125, BlockRoot: common.Hash{4}} + + testSHead1 = types.SignedHeader{SignatureSlot: 0x0124, Header: types.Header{Slot: 0x0123, StateRoot: common.Hash{1}}} + testSHead2 = types.SignedHeader{SignatureSlot: 0x2010, Header: types.Header{Slot: 0x200e, StateRoot: common.Hash{2}}} + // testSHead3 is at the end of period 1 but signed in period 2 + testSHead3 = types.SignedHeader{SignatureSlot: 0x4000, Header: types.Header{Slot: 0x3fff, StateRoot: common.Hash{3}}} + testSHead4 = types.SignedHeader{SignatureSlot: 0x6444, Header: types.Header{Slot: 0x6443, StateRoot: common.Hash{4}}} +) + +func TestValidatedHead(t *testing.T) { + chain := &TestCommitteeChain{} + ht := &TestHeadTracker{} + headSync := NewHeadSync(ht, chain) + ts := NewTestScheduler(t, headSync) + + ht.ExpValidated(t, 0, nil) + + ts.AddServer(testServer1, 1) + ts.ServerEvent(EvNewSignedHead, testServer1, testSHead1) + ts.Run(1) + // announced head should be queued because of uninitialized chain + ht.ExpValidated(t, 1, nil) + + chain.SetNextSyncPeriod(0) // initialize chain + ts.Run(2) + // expect previously queued head to be validated + ht.ExpValidated(t, 2, []types.SignedHeader{testSHead1}) + + chain.SetNextSyncPeriod(1) + ts.ServerEvent(EvNewSignedHead, testServer1, testSHead2) + ts.AddServer(testServer2, 1) + ts.ServerEvent(EvNewSignedHead, testServer2, testSHead2) + ts.Run(3) + // expect both head announcements to be validated instantly + ht.ExpValidated(t, 3, []types.SignedHeader{testSHead2, testSHead2}) + + ts.ServerEvent(EvNewSignedHead, testServer1, testSHead3) + ts.AddServer(testServer3, 1) + ts.ServerEvent(EvNewSignedHead, testServer3, testSHead4) + ts.Run(4) + // future period annonced heads should be queued + ht.ExpValidated(t, 4, nil) + + chain.SetNextSyncPeriod(2) + ts.Run(5) + // testSHead3 can be validated now but not testSHead4 + ht.ExpValidated(t, 5, []types.SignedHeader{testSHead3}) + + // server 3 disconnected without proving period 3, its announced head should be dropped + ts.RemoveServer(testServer3) + ts.Run(6) + ht.ExpValidated(t, 6, nil) + + chain.SetNextSyncPeriod(3) + ts.Run(7) + // testSHead4 could be validated now but it's not queued by any registered server + ht.ExpValidated(t, 7, nil) + + ts.ServerEvent(EvNewSignedHead, testServer2, testSHead4) + ts.Run(8) + // now testSHead4 should be validated + ht.ExpValidated(t, 8, []types.SignedHeader{testSHead4}) +} + +func TestPrefetchHead(t *testing.T) { + chain := &TestCommitteeChain{} + ht := &TestHeadTracker{} + headSync := NewHeadSync(ht, chain) + ts := NewTestScheduler(t, headSync) + + ht.ExpPrefetch(t, 0, testHead0) // no servers registered + + ts.AddServer(testServer1, 1) + ts.ServerEvent(EvNewHead, testServer1, testHead1) + ts.Run(1) + ht.ExpPrefetch(t, 1, testHead1) // s1: h1 + + ts.AddServer(testServer2, 1) + ts.ServerEvent(EvNewHead, testServer2, testHead2) + ts.Run(2) + ht.ExpPrefetch(t, 2, testHead2) // s1: h1, s2: h2 + + ts.ServerEvent(EvNewHead, testServer1, testHead2) + ts.Run(3) + ht.ExpPrefetch(t, 3, testHead2) // s1: h2, s2: h2 + + ts.AddServer(testServer3, 1) + ts.ServerEvent(EvNewHead, testServer3, testHead3) + ts.Run(4) + ht.ExpPrefetch(t, 4, testHead2) // s1: h2, s2: h2, s3: h3 + + ts.AddServer(testServer4, 1) + ts.ServerEvent(EvNewHead, testServer4, testHead4) + ts.Run(5) + ht.ExpPrefetch(t, 5, testHead2) // s1: h2, s2: h2, s3: h3, s4: h4 + + ts.ServerEvent(EvNewHead, testServer2, testHead3) + ts.Run(6) + ht.ExpPrefetch(t, 6, testHead3) // s1: h2, s2: h3, s3: h3, s4: h4 + + ts.RemoveServer(testServer3) + ts.Run(7) + ht.ExpPrefetch(t, 7, testHead4) // s1: h2, s2: h3, s4: h4 + + ts.RemoveServer(testServer1) + ts.Run(8) + ht.ExpPrefetch(t, 8, testHead4) // s2: h3, s4: h4 + + ts.RemoveServer(testServer4) + ts.Run(9) + ht.ExpPrefetch(t, 9, testHead3) // s2: h3 + + ts.RemoveServer(testServer2) + ts.Run(10) + ht.ExpPrefetch(t, 10, testHead0) // no servers registered +} diff --git a/beacon/light/sync/test_helpers.go b/beacon/light/sync/test_helpers.go new file mode 100644 index 000000000000..a1ca2b590993 --- /dev/null +++ b/beacon/light/sync/test_helpers.go @@ -0,0 +1,254 @@ +// Copyright 2023 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 sync + +import ( + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/beacon/light" + "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/types" +) + +type requestWithID struct { + sid request.ServerAndID + request request.Request +} + +type TestScheduler struct { + t *testing.T + module request.Module + events []request.Event + servers []request.Server + allowance map[request.Server]int + sent map[int][]requestWithID + testIndex int + expFail map[request.Server]int // expected Server.Fail calls during next Run + lastId request.ID +} + +func NewTestScheduler(t *testing.T, module request.Module) *TestScheduler { + return &TestScheduler{ + t: t, + module: module, + allowance: make(map[request.Server]int), + expFail: make(map[request.Server]int), + sent: make(map[int][]requestWithID), + } +} + +func (ts *TestScheduler) Run(testIndex int, exp ...any) { + expReqs := make([]requestWithID, len(exp)/2) + id := ts.lastId + for i := range expReqs { + id++ + expReqs[i] = requestWithID{ + sid: request.ServerAndID{Server: exp[i*2].(request.Server), ID: id}, + request: exp[i*2+1].(request.Request), + } + } + if len(expReqs) == 0 { + expReqs = nil + } + + ts.testIndex = testIndex + ts.module.Process(ts, ts.events) + ts.events = nil + + for server, count := range ts.expFail { + delete(ts.expFail, server) + if count == 0 { + continue + } + ts.t.Errorf("Missing %d Server.Fail(s) from server %s in test case #%d", count, server.(string), testIndex) + } + + if !reflect.DeepEqual(ts.sent[testIndex], expReqs) { + ts.t.Errorf("Wrong sent requests in test case #%d (expected %v, got %v)", testIndex, expReqs, ts.sent[testIndex]) + } +} + +func (ts *TestScheduler) CanSendTo() (cs []request.Server) { + for _, server := range ts.servers { + if ts.allowance[server] > 0 { + cs = append(cs, server) + } + } + return +} + +func (ts *TestScheduler) Send(server request.Server, req request.Request) request.ID { + ts.lastId++ + ts.sent[ts.testIndex] = append(ts.sent[ts.testIndex], requestWithID{ + sid: request.ServerAndID{Server: server, ID: ts.lastId}, + request: req, + }) + ts.allowance[server]-- + return ts.lastId +} + +func (ts *TestScheduler) Fail(server request.Server, desc string) { + if ts.expFail[server] == 0 { + ts.t.Errorf("Unexpected Fail from server %s in test case #%d: %s", server.(string), ts.testIndex, desc) + return + } + ts.expFail[server]-- +} + +func (ts *TestScheduler) Request(testIndex, reqIndex int) requestWithID { + if len(ts.sent[testIndex]) < reqIndex { + ts.t.Errorf("Missing request from test case %d index %d", testIndex, reqIndex) + return requestWithID{} + } + return ts.sent[testIndex][reqIndex-1] +} + +func (ts *TestScheduler) ServerEvent(evType *request.EventType, server request.Server, data any) { + ts.events = append(ts.events, request.Event{ + Type: evType, + Server: server, + Data: data, + }) +} + +func (ts *TestScheduler) RequestEvent(evType *request.EventType, req requestWithID, resp request.Response) { + if req.request == nil { + return + } + ts.events = append(ts.events, request.Event{ + Type: evType, + Server: req.sid.Server, + Data: request.RequestResponse{ + ID: req.sid.ID, + Request: req.request, + Response: resp, + }, + }) +} + +func (ts *TestScheduler) AddServer(server request.Server, allowance int) { + ts.servers = append(ts.servers, server) + ts.allowance[server] = allowance + ts.ServerEvent(request.EvRegistered, server, nil) +} + +func (ts *TestScheduler) RemoveServer(server request.Server) { + ts.servers = append(ts.servers, server) + for i, s := range ts.servers { + if s == server { + copy(ts.servers[i:len(ts.servers)-1], ts.servers[i+1:]) + ts.servers = ts.servers[:len(ts.servers)-1] + break + } + } + delete(ts.allowance, server) + ts.ServerEvent(request.EvUnregistered, server, nil) +} + +func (ts *TestScheduler) AddAllowance(server request.Server, allowance int) { + ts.allowance[server] += allowance +} + +func (ts *TestScheduler) ExpFail(server request.Server) { + ts.expFail[server]++ +} + +type TestCommitteeChain struct { + fsp, nsp uint64 + init bool +} + +func (t *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error { + t.fsp, t.nsp, t.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true + return nil +} + +func (t *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error { + period := update.AttestedHeader.Header.SyncPeriod() + if period < t.fsp || period > t.nsp || !t.init { + return light.ErrInvalidPeriod + } + if period == t.nsp { + t.nsp++ + } + return nil +} + +func (t *TestCommitteeChain) NextSyncPeriod() (uint64, bool) { + return t.nsp, t.init +} + +func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) { + if tc.init != ExpInit { + t.Errorf("Incorrect init flag (expected %v, got %v)", ExpInit, tc.init) + } +} + +func (t *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) { + t.init, t.nsp = true, nsp +} + +func (tc *TestCommitteeChain) ExpNextSyncPeriod(t *testing.T, expNsp uint64) { + tc.ExpInit(t, true) + if tc.nsp != expNsp { + t.Errorf("Incorrect NextSyncPeriod (expected %d, got %d)", expNsp, tc.nsp) + } +} + +type TestHeadTracker struct { + phead types.HeadInfo + validated []types.SignedHeader +} + +func (ht *TestHeadTracker) ValidateHead(head types.SignedHeader) (bool, error) { + ht.validated = append(ht.validated, head) + return true, nil +} + +// TODO add test case for finality +func (ht *TestHeadTracker) ValidateFinality(head types.FinalityUpdate) (bool, error) { + return true, nil +} + +func (ht *TestHeadTracker) ExpValidated(t *testing.T, tci int, expHeads []types.SignedHeader) { + for i, expHead := range expHeads { + if i >= len(ht.validated) { + t.Errorf("Missing validated head in test case #%d index #%d (expected {slot %d blockRoot %x}, got none)", tci, i, expHead.Header.Slot, expHead.Header.Hash()) + continue + } + if ht.validated[i] != expHead { + vhead := ht.validated[i].Header + t.Errorf("Wrong validated head in test case #%d index #%d (expected {slot %d blockRoot %x}, got {slot %d blockRoot %x})", tci, i, expHead.Header.Slot, expHead.Header.Hash(), vhead.Slot, vhead.Hash()) + } + } + for i := len(expHeads); i < len(ht.validated); i++ { + vhead := ht.validated[i].Header + t.Errorf("Unexpected validated head in test case #%d index #%d (expected none, got {slot %d blockRoot %x})", tci, i, vhead.Slot, vhead.Hash()) + } + ht.validated = nil +} + +func (ht *TestHeadTracker) SetPrefetchHead(head types.HeadInfo) { + ht.phead = head +} + +func (ht *TestHeadTracker) ExpPrefetch(t *testing.T, tci int, exp types.HeadInfo) { + if ht.phead != exp { + t.Errorf("Wrong prefetch head in test case #%d (expected {slot %d blockRoot %x}, got {slot %d blockRoot %x})", tci, exp.Slot, exp.BlockRoot, ht.phead.Slot, ht.phead.BlockRoot) + } +} diff --git a/beacon/light/sync/types.go b/beacon/light/sync/types.go new file mode 100644 index 000000000000..6449ae842d00 --- /dev/null +++ b/beacon/light/sync/types.go @@ -0,0 +1,42 @@ +// Copyright 2023 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 sync + +import ( + "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" +) + +var ( + EvNewHead = &request.EventType{Name: "newHead"} // data: types.HeadInfo + EvNewSignedHead = &request.EventType{Name: "newSignedHead"} // data: types.SignedHeader + EvNewFinalityUpdate = &request.EventType{Name: "newFinalityUpdate"} // data: types.FinalityUpdate +) + +type ( + ReqUpdates struct { + FirstPeriod, Count uint64 + } + RespUpdates struct { + Updates []*types.LightClientUpdate + Committees []*types.SerializedSyncCommittee + } + ReqHeader common.Hash + ReqCheckpointData common.Hash + ReqBeaconBlock common.Hash +) diff --git a/beacon/light/sync/update_sync.go b/beacon/light/sync/update_sync.go new file mode 100644 index 000000000000..533e470fb022 --- /dev/null +++ b/beacon/light/sync/update_sync.go @@ -0,0 +1,299 @@ +// Copyright 2023 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 sync + +import ( + "sort" + + "github.com/ethereum/go-ethereum/beacon/light" + "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" +) + +const maxUpdateRequest = 8 // maximum number of updates requested in a single request + +type committeeChain interface { + CheckpointInit(bootstrap types.BootstrapData) error + InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error + NextSyncPeriod() (uint64, bool) +} + +// CheckpointInit implements request.Module; it fetches the light client bootstrap +// data belonging to the given checkpoint hash and initializes the committee chain +// if successful. +type CheckpointInit struct { + chain committeeChain + checkpointHash common.Hash + locked request.ServerAndID + initialized bool +} + +// NewCheckpointInit creates a new CheckpointInit. +func NewCheckpointInit(chain committeeChain, checkpointHash common.Hash) *CheckpointInit { + return &CheckpointInit{ + chain: chain, + checkpointHash: checkpointHash, + } +} + +// Process implements request.Module. +func (s *CheckpointInit) Process(requester request.Requester, events []request.Event) { + for _, event := range events { + if !event.IsRequestEvent() { + continue + } + sid, req, resp := event.RequestInfo() + if s.locked == sid { + s.locked = request.ServerAndID{} + } + if resp != nil { + if checkpoint := resp.(*types.BootstrapData); checkpoint.Header.Hash() == common.Hash(req.(ReqCheckpointData)) { + s.chain.CheckpointInit(*checkpoint) + s.initialized = true + return + } + + requester.Fail(event.Server, "invalid checkpoint data") + } + } + // start a request if possible + if s.initialized || s.locked != (request.ServerAndID{}) { + return + } + cs := requester.CanSendTo() + if len(cs) == 0 { + return + } + server := cs[0] + id := requester.Send(server, ReqCheckpointData(s.checkpointHash)) + s.locked = request.ServerAndID{Server: server, ID: id} +} + +// ForwardUpdateSync implements request.Module; it fetches updates between the +// committee chain head and each server's announced head. Updates are fetched +// in batches and multiple batches can also be requested in parallel. +// Out of order responses are also handled; if a batch of updates cannot be added +// to the chain immediately because of a gap then the future updates are +// remembered until they can be processed. +type ForwardUpdateSync struct { + chain committeeChain + rangeLock rangeLock + lockedIDs map[request.ServerAndID]struct{} + processQueue []updateResponse + nextSyncPeriod map[request.Server]uint64 +} + +// NewForwardUpdateSync creates a new ForwardUpdateSync. +func NewForwardUpdateSync(chain committeeChain) *ForwardUpdateSync { + return &ForwardUpdateSync{ + chain: chain, + rangeLock: make(rangeLock), + lockedIDs: make(map[request.ServerAndID]struct{}), + nextSyncPeriod: make(map[request.Server]uint64), + } +} + +// rangeLock allows locking sections of an integer space, preventing the syncing +// mechanism from making requests again for sections where a not timed out request +// is already pending or where already fetched and unprocessed data is available. +type rangeLock map[uint64]int + +// lock locks or unlocks the given section, depending on the sign of the add parameter. +func (r rangeLock) lock(first, count uint64, add int) { + for i := first; i < first+count; i++ { + if v := r[i] + add; v > 0 { + r[i] = v + } else { + delete(r, i) + } + } +} + +// firstUnlocked returns the first unlocked section starting at or after start +// and not longer than maxCount. +func (r rangeLock) firstUnlocked(start, maxCount uint64) (first, count uint64) { + first = start + for { + if _, ok := r[first]; !ok { + break + } + first++ + } + for { + count++ + if count == maxCount { + break + } + if _, ok := r[first+count]; ok { + break + } + } + return +} + +// lockRange locks the range belonging to the given update request, unless the +// same request has already been locked +func (s *ForwardUpdateSync) lockRange(sid request.ServerAndID, req ReqUpdates) { + if _, ok := s.lockedIDs[sid]; ok { + return + } + s.lockedIDs[sid] = struct{}{} + s.rangeLock.lock(req.FirstPeriod, req.Count, 1) +} + +// unlockRange unlocks the range belonging to the given update request, unless +// same request has already been unlocked +func (s *ForwardUpdateSync) unlockRange(sid request.ServerAndID, req ReqUpdates) { + if _, ok := s.lockedIDs[sid]; !ok { + return + } + delete(s.lockedIDs, sid) + s.rangeLock.lock(req.FirstPeriod, req.Count, -1) +} + +// verifyRange returns true if the number of updates and the individual update +// periods in the response match the requested section. +func (s *ForwardUpdateSync) verifyRange(request ReqUpdates, response RespUpdates) bool { + if uint64(len(response.Updates)) != request.Count || uint64(len(response.Committees)) != request.Count { + return false + } + for i, update := range response.Updates { + if update.AttestedHeader.Header.SyncPeriod() != request.FirstPeriod+uint64(i) { + return false + } + } + return true +} + +// updateResponse is a response that has passed initial verification and has been +// queued for processing. Note that an update response cannot be processed until +// the previous updates have also been added to the chain. +type updateResponse struct { + sid request.ServerAndID + request ReqUpdates + response RespUpdates +} + +// updateResponseList implements sort.Sort and sorts update request/response events by FirstPeriod. +type updateResponseList []updateResponse + +func (u updateResponseList) Len() int { return len(u) } +func (u updateResponseList) Swap(i, j int) { u[i], u[j] = u[j], u[i] } +func (u updateResponseList) Less(i, j int) bool { + return u[i].request.FirstPeriod < u[j].request.FirstPeriod +} + +// Process implements request.Module. +func (s *ForwardUpdateSync) Process(requester request.Requester, events []request.Event) { + for _, event := range events { + switch event.Type { + case request.EvResponse, request.EvFail, request.EvTimeout: + sid, rq, rs := event.RequestInfo() + req := rq.(ReqUpdates) + var queued bool + if event.Type == request.EvResponse { + resp := rs.(RespUpdates) + if s.verifyRange(req, resp) { + // there is a response with a valid format; put it in the process queue + s.processQueue = append(s.processQueue, updateResponse{sid: sid, request: req, response: resp}) + s.lockRange(sid, req) + queued = true + } else { + requester.Fail(event.Server, "invalid update range") + } + } + if !queued { + s.unlockRange(sid, req) + } + case EvNewSignedHead: + signedHead := event.Data.(types.SignedHeader) + s.nextSyncPeriod[event.Server] = types.SyncPeriod(signedHead.SignatureSlot + 256) + case request.EvUnregistered: + delete(s.nextSyncPeriod, event.Server) + } + } + + // try processing ordered list of available responses + sort.Sort(updateResponseList(s.processQueue)) + for s.processQueue != nil { + u := s.processQueue[0] + if !s.processResponse(requester, u) { + break + } + s.unlockRange(u.sid, u.request) + s.processQueue = s.processQueue[1:] + if len(s.processQueue) == 0 { + s.processQueue = nil + } + } + + // start new requests if possible + startPeriod, chainInit := s.chain.NextSyncPeriod() + if !chainInit { + return + } + for { + firstPeriod, maxCount := s.rangeLock.firstUnlocked(startPeriod, maxUpdateRequest) + var ( + sendTo request.Server + bestCount uint64 + ) + for _, server := range requester.CanSendTo() { + nextPeriod := s.nextSyncPeriod[server] + if nextPeriod <= firstPeriod { + continue + } + count := maxCount + if nextPeriod < firstPeriod+maxCount { + count = nextPeriod - firstPeriod + } + if count > bestCount { + sendTo, bestCount = server, count + } + } + if sendTo == nil { + return + } + req := ReqUpdates{FirstPeriod: firstPeriod, Count: bestCount} + id := requester.Send(sendTo, req) + s.lockRange(request.ServerAndID{Server: sendTo, ID: id}, req) + } +} + +// processResponse adds the fetched updates and committees to the committee chain. +// Returns true in case of full or partial success. +func (s *ForwardUpdateSync) processResponse(requester request.Requester, u updateResponse) (success bool) { + for i, update := range u.response.Updates { + if err := s.chain.InsertUpdate(update, u.response.Committees[i]); err != nil { + if err == light.ErrInvalidPeriod { + // there is a gap in the update periods; stop processing without + // failing and try again next time + return + } + if err == light.ErrInvalidUpdate || err == light.ErrWrongCommitteeRoot || err == light.ErrCannotReorg { + requester.Fail(u.sid.Server, "invalid update received") + } else { + log.Error("Unexpected InsertUpdate error", "error", err) + } + return + } + success = true + } + return +} diff --git a/beacon/light/sync/update_sync_test.go b/beacon/light/sync/update_sync_test.go new file mode 100644 index 000000000000..1c4b3d6d76fa --- /dev/null +++ b/beacon/light/sync/update_sync_test.go @@ -0,0 +1,219 @@ +// Copyright 2024 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 sync + +import ( + "testing" + + "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/types" +) + +func TestCheckpointInit(t *testing.T) { + chain := &TestCommitteeChain{} + checkpoint := &types.BootstrapData{Header: types.Header{Slot: 0x2000*4 + 0x1000}} // period 4 + checkpointHash := checkpoint.Header.Hash() + chkInit := NewCheckpointInit(chain, checkpointHash) + ts := NewTestScheduler(t, chkInit) + // add 2 servers + ts.AddServer(testServer1, 1) + ts.AddServer(testServer2, 1) + + // expect bootstrap request to server 1 + ts.Run(1, testServer1, ReqCheckpointData(checkpointHash)) + + // server 1 times out; expect request to server 2 + ts.RequestEvent(request.EvTimeout, ts.Request(1, 1), nil) + ts.Run(2, testServer2, ReqCheckpointData(checkpointHash)) + + // invalid response from server 2; expect init state to still be false + ts.RequestEvent(request.EvResponse, ts.Request(2, 1), &types.BootstrapData{Header: types.Header{Slot: 123456}}) + ts.ExpFail(testServer2) + ts.Run(3) + chain.ExpInit(t, false) + + // server 1 fails (hard timeout) + ts.RequestEvent(request.EvFail, ts.Request(1, 1), nil) + ts.Run(4) + chain.ExpInit(t, false) + + // server 3 is registered; expect bootstrap request to server 3 + ts.AddServer(testServer3, 1) + ts.Run(5, testServer3, ReqCheckpointData(checkpointHash)) + + // valid response from server 3; expect chain to be initialized + ts.RequestEvent(request.EvResponse, ts.Request(5, 1), checkpoint) + ts.Run(6) + chain.ExpInit(t, true) +} + +func TestUpdateSyncParallel(t *testing.T) { + chain := &TestCommitteeChain{} + chain.SetNextSyncPeriod(0) + updateSync := NewForwardUpdateSync(chain) + ts := NewTestScheduler(t, updateSync) + // add 2 servers, head at period 100; allow 3-3 parallel requests for each + ts.AddServer(testServer1, 3) + ts.ServerEvent(EvNewSignedHead, testServer1, types.SignedHeader{SignatureSlot: 0x2000*100 + 0x1000}) + ts.AddServer(testServer2, 3) + ts.ServerEvent(EvNewSignedHead, testServer2, types.SignedHeader{SignatureSlot: 0x2000*100 + 0x1000}) + + // expect 6 requests to be sent + ts.Run(1, + testServer1, ReqUpdates{FirstPeriod: 0, Count: 8}, + testServer1, ReqUpdates{FirstPeriod: 8, Count: 8}, + testServer1, ReqUpdates{FirstPeriod: 16, Count: 8}, + testServer2, ReqUpdates{FirstPeriod: 24, Count: 8}, + testServer2, ReqUpdates{FirstPeriod: 32, Count: 8}, + testServer2, ReqUpdates{FirstPeriod: 40, Count: 8}) + + // valid response to request 1; expect 8 periods synced and a new request started + ts.RequestEvent(request.EvResponse, ts.Request(1, 1), testRespUpdate(ts.Request(1, 1))) + ts.AddAllowance(testServer1, 1) + ts.Run(2, testServer1, ReqUpdates{FirstPeriod: 48, Count: 8}) + chain.ExpNextSyncPeriod(t, 8) + + // valid response to requests 4 and 5 + ts.RequestEvent(request.EvResponse, ts.Request(1, 4), testRespUpdate(ts.Request(1, 4))) + ts.RequestEvent(request.EvResponse, ts.Request(1, 5), testRespUpdate(ts.Request(1, 5))) + ts.AddAllowance(testServer2, 2) + // expect 2 more requests but no sync progress (responses 4 and 5 cannot be added before 2 and 3) + ts.Run(3, + testServer2, ReqUpdates{FirstPeriod: 56, Count: 8}, + testServer2, ReqUpdates{FirstPeriod: 64, Count: 8}) + chain.ExpNextSyncPeriod(t, 8) + + // soft timeout for requests 2 and 3 (server 1 is overloaded) + ts.RequestEvent(request.EvTimeout, ts.Request(1, 2), nil) + ts.RequestEvent(request.EvTimeout, ts.Request(1, 3), nil) + // no allowance, no more requests + ts.Run(4) + + // valid response to requests 6 and 8 and 9 + ts.RequestEvent(request.EvResponse, ts.Request(1, 6), testRespUpdate(ts.Request(1, 6))) + ts.RequestEvent(request.EvResponse, ts.Request(3, 1), testRespUpdate(ts.Request(3, 1))) + ts.RequestEvent(request.EvResponse, ts.Request(3, 2), testRespUpdate(ts.Request(3, 2))) + ts.AddAllowance(testServer2, 3) + // server 2 can now resend requests 2 and 3 (timed out by server 1) and also send a new one + ts.Run(5, + testServer2, ReqUpdates{FirstPeriod: 8, Count: 8}, + testServer2, ReqUpdates{FirstPeriod: 16, Count: 8}, + testServer2, ReqUpdates{FirstPeriod: 72, Count: 8}) + + // server 1 finally answers timed out request 2 + ts.RequestEvent(request.EvResponse, ts.Request(1, 2), testRespUpdate(ts.Request(1, 2))) + ts.AddAllowance(testServer1, 1) + // expect sync progress and one new request + ts.Run(6, testServer1, ReqUpdates{FirstPeriod: 80, Count: 8}) + chain.ExpNextSyncPeriod(t, 16) + + // server 2 answers requests 11 and 12 (resends of requests 2 and 3) + ts.RequestEvent(request.EvResponse, ts.Request(5, 1), testRespUpdate(ts.Request(5, 1))) + ts.RequestEvent(request.EvResponse, ts.Request(5, 2), testRespUpdate(ts.Request(5, 2))) + ts.AddAllowance(testServer2, 2) + ts.Run(7, + testServer2, ReqUpdates{FirstPeriod: 88, Count: 8}, + testServer2, ReqUpdates{FirstPeriod: 96, Count: 4}) + // finally the gap is filled, update can process responses up to req6 + chain.ExpNextSyncPeriod(t, 48) + + // all remaining requests are answered + ts.RequestEvent(request.EvResponse, ts.Request(1, 3), testRespUpdate(ts.Request(1, 3))) + ts.RequestEvent(request.EvResponse, ts.Request(2, 1), testRespUpdate(ts.Request(2, 1))) + ts.RequestEvent(request.EvResponse, ts.Request(5, 3), testRespUpdate(ts.Request(5, 3))) + ts.RequestEvent(request.EvResponse, ts.Request(6, 1), testRespUpdate(ts.Request(6, 1))) + ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testRespUpdate(ts.Request(7, 1))) + ts.RequestEvent(request.EvResponse, ts.Request(7, 2), testRespUpdate(ts.Request(7, 2))) + ts.Run(8) + // expect chain to be fully synced + chain.ExpNextSyncPeriod(t, 100) +} + +func TestUpdateSyncDifferentHeads(t *testing.T) { + chain := &TestCommitteeChain{} + chain.SetNextSyncPeriod(10) + updateSync := NewForwardUpdateSync(chain) + ts := NewTestScheduler(t, updateSync) + // add 3 servers with different announced head periods + ts.AddServer(testServer1, 1) + ts.ServerEvent(EvNewSignedHead, testServer1, types.SignedHeader{SignatureSlot: 0x2000*15 + 0x1000}) + ts.AddServer(testServer2, 1) + ts.ServerEvent(EvNewSignedHead, testServer2, types.SignedHeader{SignatureSlot: 0x2000*16 + 0x1000}) + ts.AddServer(testServer3, 1) + ts.ServerEvent(EvNewSignedHead, testServer3, types.SignedHeader{SignatureSlot: 0x2000*17 + 0x1000}) + + // expect request to the best announced head + ts.Run(1, testServer3, ReqUpdates{FirstPeriod: 10, Count: 7}) + + // request times out, expect request to the next best head + ts.RequestEvent(request.EvTimeout, ts.Request(1, 1), nil) + ts.Run(2, testServer2, ReqUpdates{FirstPeriod: 10, Count: 6}) + + // request times out, expect request to the last available server + ts.RequestEvent(request.EvTimeout, ts.Request(2, 1), nil) + ts.Run(3, testServer1, ReqUpdates{FirstPeriod: 10, Count: 5}) + + // valid response to request 3, expect chain synced to period 15 + ts.RequestEvent(request.EvResponse, ts.Request(3, 1), testRespUpdate(ts.Request(3, 1))) + ts.AddAllowance(testServer1, 1) + ts.Run(4) + chain.ExpNextSyncPeriod(t, 15) + + // invalid response to request 1, server can only deliver updates up to period 15 despite announced head + truncated := ts.Request(1, 1) + truncated.request = ReqUpdates{FirstPeriod: 10, Count: 5} + ts.RequestEvent(request.EvResponse, ts.Request(1, 1), testRespUpdate(truncated)) + ts.ExpFail(testServer3) + ts.Run(5) + // expect no progress of chain head + chain.ExpNextSyncPeriod(t, 15) + + // valid response to request 2, expect chain synced to period 16 + ts.RequestEvent(request.EvResponse, ts.Request(2, 1), testRespUpdate(ts.Request(2, 1))) + ts.AddAllowance(testServer2, 1) + ts.Run(6) + chain.ExpNextSyncPeriod(t, 16) + + // a new server is registered with announced head period 17 + ts.AddServer(testServer4, 1) + ts.ServerEvent(EvNewSignedHead, testServer4, types.SignedHeader{SignatureSlot: 0x2000*17 + 0x1000}) + // expect request to sync one more period + ts.Run(7, testServer4, ReqUpdates{FirstPeriod: 16, Count: 1}) + + // valid response, expect chain synced to period 17 + ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testRespUpdate(ts.Request(7, 1))) + ts.AddAllowance(testServer4, 1) + ts.Run(8) + chain.ExpNextSyncPeriod(t, 17) +} + +func testRespUpdate(request requestWithID) request.Response { + var resp RespUpdates + if request.request == nil { + return resp + } + req := request.request.(ReqUpdates) + resp.Updates = make([]*types.LightClientUpdate, int(req.Count)) + resp.Committees = make([]*types.SerializedSyncCommittee, int(req.Count)) + period := req.FirstPeriod + for i := range resp.Updates { + resp.Updates[i] = &types.LightClientUpdate{AttestedHeader: types.SignedHeader{Header: types.Header{Slot: 0x2000*period + 0x1000}}} + resp.Committees[i] = new(types.SerializedSyncCommittee) + period++ + } + return resp +} diff --git a/beacon/params/params.go b/beacon/params/params.go index ee9feb1acbea..e4e0d009340e 100644 --- a/beacon/params/params.go +++ b/beacon/params/params.go @@ -41,4 +41,6 @@ const ( StateIndexNextSyncCommittee = 55 StateIndexExecPayload = 56 StateIndexExecHead = 908 + + BodyIndexExecPayload = 25 ) diff --git a/beacon/types/light_sync.go b/beacon/types/light_sync.go index 3284081e4d49..ed62d237f126 100644 --- a/beacon/types/light_sync.go +++ b/beacon/types/light_sync.go @@ -20,11 +20,20 @@ import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/beacon/merkle" "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/common" + "github.com/protolambda/zrnt/eth2/beacon/capella" + "github.com/protolambda/ztyp/tree" ) +// HeadInfo represents an unvalidated new head announcement. +type HeadInfo struct { + Slot uint64 + BlockRoot common.Hash +} + // BootstrapData contains a sync committee where light sync can be started, // together with a proof through a beacon header and corresponding state. // Note: BootstrapData is fetched from a server based on a known checkpoint hash. @@ -134,3 +143,50 @@ func (u UpdateScore) BetterThan(w UpdateScore) bool { } return u.SignerCount > w.SignerCount } + +type HeaderWithExecProof struct { + Header + PayloadHeader *capella.ExecutionPayloadHeader + PayloadBranch merkle.Values +} + +func (h *HeaderWithExecProof) Validate() error { + payloadRoot := merkle.Value(h.PayloadHeader.HashTreeRoot(tree.GetHashFn())) + return merkle.VerifyProof(h.BodyRoot, params.BodyIndexExecPayload, h.PayloadBranch, payloadRoot) +} + +type FinalityUpdate struct { + Attested, Finalized HeaderWithExecProof + FinalityBranch merkle.Values + // Sync committee BLS signature aggregate + Signature SyncAggregate + // Slot in which the signature has been created (newer than Header.Slot, + // determines the signing sync committee) + SignatureSlot uint64 +} + +func (u *FinalityUpdate) SignedHeader() SignedHeader { + return SignedHeader{ + Header: u.Attested.Header, + Signature: u.Signature, + SignatureSlot: u.SignatureSlot, + } +} + +func (u *FinalityUpdate) Validate() error { + if err := u.Attested.Validate(); err != nil { + return err + } + if err := u.Finalized.Validate(); err != nil { + return err + } + return merkle.VerifyProof(u.Attested.StateRoot, params.StateIndexFinalBlock, u.FinalityBranch, merkle.Value(u.Finalized.Hash())) +} + +// ChainHeadEvent returns an authenticated execution payload associated with the +// latest accepted head of the beacon chain, along with the hash of the latest +// finalized execution block. +type ChainHeadEvent struct { + HeadBlock *engine.ExecutableData + Finalized common.Hash +} diff --git a/cmd/blsync/engine_api.go b/cmd/blsync/engine_api.go new file mode 100644 index 000000000000..d10750e295fe --- /dev/null +++ b/cmd/blsync/engine_api.go @@ -0,0 +1,69 @@ +// Copyright 2024 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" + "time" + + "github.com/ethereum/go-ethereum/beacon/engine" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" +) + +func updateEngineApi(client *rpc.Client, headCh chan types.ChainHeadEvent) { + for event := range headCh { + if client == nil { // dry run, no engine API specified + log.Info("New execution block retrieved", "block number", event.HeadBlock.Number, "block hash", event.HeadBlock.BlockHash, "finalized block hash", event.Finalized) + } else { + if status, err := callNewPayloadV2(client, event.HeadBlock); err == nil { + log.Info("Successful NewPayload", "block number", event.HeadBlock.Number, "block hash", event.HeadBlock.BlockHash, "status", status) + } else { + log.Error("Failed NewPayload", "block number", event.HeadBlock.Number, "block hash", event.HeadBlock.BlockHash, "error", err) + } + if status, err := callForkchoiceUpdatedV1(client, event.HeadBlock.BlockHash, event.Finalized); err == nil { + log.Info("Successful ForkchoiceUpdated", "head", event.HeadBlock.BlockHash, "status", status) + } else { + log.Error("Failed ForkchoiceUpdated", "head", event.HeadBlock.BlockHash, "error", err) + } + } + } +} + +func callNewPayloadV2(client *rpc.Client, execData *engine.ExecutableData) (string, error) { + var resp engine.PayloadStatusV1 + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + err := client.CallContext(ctx, &resp, "engine_newPayloadV2", execData) + cancel() + return resp.Status, err +} + +func callForkchoiceUpdatedV1(client *rpc.Client, headHash, finalizedHash common.Hash) (string, error) { + var resp engine.ForkChoiceResponse + update := engine.ForkchoiceStateV1{ + HeadBlockHash: headHash, + SafeBlockHash: finalizedHash, + FinalizedBlockHash: finalizedHash, + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + err := client.CallContext(ctx, &resp, "engine_forkchoiceUpdatedV1", update, nil) + cancel() + return resp.PayloadStatus.Status, err +} diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go new file mode 100644 index 000000000000..fd22761d3c45 --- /dev/null +++ b/cmd/blsync/main.go @@ -0,0 +1,125 @@ +// Copyright 2022 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" + "fmt" + "io" + "os" + + "github.com/ethereum/go-ethereum/beacon/blsync" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/rpc" + "github.com/mattn/go-colorable" + "github.com/mattn/go-isatty" + "github.com/urfave/cli/v2" +) + +var ( + verbosityFlag = &cli.IntFlag{ + Name: "verbosity", + Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", + Value: 3, + Category: flags.LoggingCategory, + } + vmoduleFlag = &cli.StringFlag{ + Name: "vmodule", + Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", + Value: "", + Hidden: true, + Category: flags.LoggingCategory, + } +) + +func main() { + app := flags.NewApp("beacon light syncer tool") + app.Flags = []cli.Flag{ + utils.BeaconApiFlag, + utils.BeaconApiHeaderFlag, + utils.BeaconThresholdFlag, + utils.BeaconNoFilterFlag, + utils.BeaconConfigFlag, + utils.BeaconGenesisRootFlag, + utils.BeaconGenesisTimeFlag, + utils.BeaconCheckpointFlag, + //TODO datadir for optional permanent database + utils.MainnetFlag, + utils.SepoliaFlag, + utils.GoerliFlag, + utils.BlsyncApiFlag, + utils.BlsyncJWTSecretFlag, + verbosityFlag, + vmoduleFlag, + } + app.Action = sync + + if err := app.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func sync(ctx *cli.Context) error { + usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" + output := io.Writer(os.Stderr) + if usecolor { + output = colorable.NewColorable(os.Stderr) + } + verbosity := log.FromLegacyLevel(ctx.Int(verbosityFlag.Name)) + log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor))) + + headCh := make(chan types.ChainHeadEvent, 16) + client := blsync.NewClient(ctx) + sub := client.SubscribeChainHeadEvent(headCh) + go updateEngineApi(makeRPCClient(ctx), headCh) + client.Start() + // run until stopped + <-ctx.Done() + client.Stop() + sub.Unsubscribe() + close(headCh) + return nil +} + +func makeRPCClient(ctx *cli.Context) *rpc.Client { + if !ctx.IsSet(utils.BlsyncApiFlag.Name) { + log.Warn("No engine API target specified, performing a dry run") + return nil + } + if !ctx.IsSet(utils.BlsyncJWTSecretFlag.Name) { + utils.Fatalf("JWT secret parameter missing") //TODO use default if datadir is specified + } + + engineApiUrl, jwtFileName := ctx.String(utils.BlsyncApiFlag.Name), ctx.String(utils.BlsyncJWTSecretFlag.Name) + var jwtSecret [32]byte + if jwt, err := node.ObtainJWTSecret(jwtFileName); err == nil { + copy(jwtSecret[:], jwt) + } else { + utils.Fatalf("Error loading or generating JWT secret: %v", err) + } + auth := node.NewJWTAuth(jwtSecret) + cl, err := rpc.DialOptions(context.Background(), engineApiUrl, rpc.WithHTTPAuth(auth)) + if err != nil { + utils.Fatalf("Could not create RPC client: %v", err) + } + return cl +} diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 5f52f1df5442..37d17fb1e77d 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -31,6 +31,7 @@ import ( "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/beacon/blsync" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -221,6 +222,8 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { } catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon) stack.RegisterLifecycle(simBeacon) + } else if ctx.IsSet(utils.BeaconApiFlag.Name) { + stack.RegisterLifecycle(catalyst.NewBlsync(blsync.NewClient(ctx), eth)) } else { err := catalyst.Register(stack, eth) if err != nil { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 9a88e9f2e8b4..d79d23e22687 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -146,6 +146,14 @@ var ( configFileFlag, utils.LogDebugFlag, utils.LogBacktraceAtFlag, + utils.BeaconApiFlag, + utils.BeaconApiHeaderFlag, + utils.BeaconThresholdFlag, + utils.BeaconNoFilterFlag, + utils.BeaconConfigFlag, + utils.BeaconGenesisRootFlag, + utils.BeaconGenesisTimeFlag, + utils.BeaconCheckpointFlag, }, utils.NetworkFlags, utils.DatabaseFlags) rpcFlags = []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index fad567cd55d2..e002975d53cf 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" + bparams "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/core" @@ -281,6 +282,58 @@ var ( Value: ethconfig.Defaults.TransactionHistory, Category: flags.StateCategory, } + // Beacon client light sync settings + BeaconApiFlag = &cli.StringSliceFlag{ + Name: "beacon.api", + Usage: "Beacon node (CL) light client API URL. This flag can be given multiple times.", + Category: flags.BeaconCategory, + } + BeaconApiHeaderFlag = &cli.StringSliceFlag{ + Name: "beacon.api.header", + Usage: "Pass custom HTTP header fields to the emote beacon node API in \"key:value\" format. This flag can be given multiple times.", + Category: flags.BeaconCategory, + } + BeaconThresholdFlag = &cli.IntFlag{ + Name: "beacon.threshold", + Usage: "Beacon sync committee participation threshold", + Value: bparams.SyncCommitteeSupermajority, + Category: flags.BeaconCategory, + } + BeaconNoFilterFlag = &cli.BoolFlag{ + Name: "beacon.nofilter", + Usage: "Disable future slot signature filter", + Category: flags.BeaconCategory, + } + BeaconConfigFlag = &cli.StringFlag{ + Name: "beacon.config", + Usage: "Beacon chain config YAML file", + Category: flags.BeaconCategory, + } + BeaconGenesisRootFlag = &cli.StringFlag{ + Name: "beacon.genesis.gvroot", + Usage: "Beacon chain genesis validators root", + Category: flags.BeaconCategory, + } + BeaconGenesisTimeFlag = &cli.Uint64Flag{ + Name: "beacon.genesis.time", + Usage: "Beacon chain genesis time", + Category: flags.BeaconCategory, + } + BeaconCheckpointFlag = &cli.StringFlag{ + Name: "beacon.checkpoint", + Usage: "Beacon chain weak subjectivity checkpoint block hash", + Category: flags.BeaconCategory, + } + BlsyncApiFlag = &cli.StringFlag{ + Name: "blsync.engine.api", + Usage: "Target EL engine API URL", + Category: flags.BeaconCategory, + } + BlsyncJWTSecretFlag = &cli.StringFlag{ + Name: "blsync.jwtsecret", + Usage: "Path to a JWT secret to use for target engine API endpoint", + Category: flags.BeaconCategory, + } // Transaction pool settings TxPoolLocalsFlag = &cli.StringFlag{ Name: "txpool.locals", diff --git a/eth/catalyst/blsync.go b/eth/catalyst/blsync.go new file mode 100644 index 000000000000..4877cf4c6361 --- /dev/null +++ b/eth/catalyst/blsync.go @@ -0,0 +1,88 @@ +// Copyright 2024 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 catalyst + +import ( + "github.com/ethereum/go-ethereum/beacon/engine" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" +) + +// Blsync tracks the head of the beacon chain through the beacon light client +// and drives the local node via ConsensusAPI. +type Blsync struct { + engine *ConsensusAPI + client Client + headCh chan types.ChainHeadEvent + headSub event.Subscription + + quitCh chan struct{} +} + +type Client interface { + SubscribeChainHeadEvent(ch chan<- types.ChainHeadEvent) event.Subscription + Start() + Stop() +} + +// NewBlsync creates a new beacon light syncer. +func NewBlsync(client Client, eth *eth.Ethereum) *Blsync { + return &Blsync{ + engine: newConsensusAPIWithoutHeartbeat(eth), + client: client, + headCh: make(chan types.ChainHeadEvent, 16), + quitCh: make(chan struct{}), + } +} + +// Start starts underlying beacon light client and the sync logic for driving +// the local node. +func (b *Blsync) Start() error { + log.Info("Beacon light sync started") + b.headSub = b.client.SubscribeChainHeadEvent(b.headCh) + go b.client.Start() + + for { + select { + case <-b.quitCh: + return nil + case head := <-b.headCh: + if _, err := b.engine.NewPayloadV2(*head.HeadBlock); err != nil { + log.Error("failed to send new payload", "err", err) + continue + } + update := engine.ForkchoiceStateV1{ + HeadBlockHash: head.HeadBlock.BlockHash, + SafeBlockHash: head.Finalized, //TODO pass finalized or empty hash here? + FinalizedBlockHash: head.Finalized, + } + if _, err := b.engine.ForkchoiceUpdatedV1(update, nil); err != nil { + log.Error("failed to send forkchoice updated", "err", err) + continue + } + } + } +} + +// Stop signals to the light client and syncer to exit. +func (b *Blsync) Stop() error { + b.client.Stop() + close(b.quitCh) + return nil +} diff --git a/go.mod b/go.mod index 6591bee62ff1..ca45364b8bf2 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,8 @@ require ( github.com/crate-crypto/go-kzg-4844 v0.7.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 - github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 + github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 + github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 github.com/ethereum/c-kzg-4844 v0.4.0 github.com/fatih/color v1.13.0 github.com/ferranbt/fastssz v0.1.2 @@ -54,6 +55,8 @@ require ( github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 + github.com/protolambda/zrnt v0.30.0 + github.com/protolambda/ztyp v0.2.2 github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 diff --git a/go.sum b/go.sum index cc74e15cb4b9..18236bf8e74d 100644 --- a/go.sum +++ b/go.sum @@ -149,9 +149,11 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 h1:C7t6eeMaEQVy6e8CarIhscYQlNmw5e3G36y7l7Y21Ao= +github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0/go.mod h1:56wL82FO0bfMU5RvfXoIwSOP2ggqqxT+tAfNEIyxuHw= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 h1:qwcF+vdFrvPSEUDSX5RVoRccG8a5DhOdWdQ4zN62zzo= -github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= +github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 h1:+3HCtB74++ClLy8GgjUQYeC8R4ILzVcIe8+5edAJJnE= +github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -239,6 +241,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -298,6 +301,7 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6w github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -380,6 +384,7 @@ github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= @@ -448,8 +453,14 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e/go.mod h1:MPZvj2Pr0N8/dXyTPS5REeg2sdLG7t8DRzC1rLv925w= github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 h1:cZC+usqsYgHtlBaGulVnZ1hfKAi8iWtujBnRLQE698c= github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY= +github.com/protolambda/messagediff v1.4.0/go.mod h1:LboJp0EwIbJsePYpzh5Op/9G1/4mIztMRYzzwR0dR2M= +github.com/protolambda/zrnt v0.30.0 h1:pHEn69ZgaDFGpLGGYG1oD7DvYI7RDirbMBPfbC+8p4g= +github.com/protolambda/zrnt v0.30.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax/2lMsJ4Jw= +github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY= +github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU= github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -842,6 +853,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/flags/categories.go b/internal/flags/categories.go index 3ff0767921b9..c044e28f384c 100644 --- a/internal/flags/categories.go +++ b/internal/flags/categories.go @@ -20,6 +20,7 @@ import "github.com/urfave/cli/v2" const ( EthCategory = "ETHEREUM" + BeaconCategory = "BEACON CHAIN" LightCategory = "LIGHT CLIENT" DevCategory = "DEVELOPER CHAIN" StateCategory = "STATE HISTORY MANAGEMENT" diff --git a/node/node.go b/node/node.go index dfa83d58c726..c5cb552d2737 100644 --- a/node/node.go +++ b/node/node.go @@ -339,15 +339,9 @@ func (n *Node) closeDataDir() { } } -// obtainJWTSecret loads the jwt-secret, either from the provided config, -// or from the default location. If neither of those are present, it generates -// a new secret and stores to the default location. -func (n *Node) obtainJWTSecret(cliParam string) ([]byte, error) { - fileName := cliParam - if len(fileName) == 0 { - // no path provided, use default - fileName = n.ResolvePath(datadirJWTKey) - } +// ObtainJWTSecret loads the jwt-secret from the provided config. If the file is not +// present, it generates a new secret and stores to the given location. +func ObtainJWTSecret(fileName string) ([]byte, error) { // try reading from file if data, err := os.ReadFile(fileName); err == nil { jwtSecret := common.FromHex(strings.TrimSpace(string(data))) @@ -373,6 +367,18 @@ func (n *Node) obtainJWTSecret(cliParam string) ([]byte, error) { return jwtSecret, nil } +// obtainJWTSecret loads the jwt-secret, either from the provided config, +// or from the default location. If neither of those are present, it generates +// a new secret and stores to the default location. +func (n *Node) obtainJWTSecret(cliParam string) ([]byte, error) { + fileName := cliParam + if len(fileName) == 0 { + // no path provided, use default + fileName = n.ResolvePath(datadirJWTKey) + } + return ObtainJWTSecret(fileName) +} + // startRPC is a helper method to configure all the various RPC endpoints during node // startup. It's not meant to be called at any time afterwards as it makes certain // assumptions about the state of the node. From 3bebabbd036d4f550e32bb20a92bf7da6e6a2797 Mon Sep 17 00:00:00 2001 From: cuinix <65650185+cuinix@users.noreply.github.com> Date: Fri, 8 Mar 2024 05:25:08 +0800 Subject: [PATCH 044/571] accounts: remove redundant string conversion (#29184) --- accounts/accounts.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/accounts.go b/accounts/accounts.go index 6c351a9649ea..b995498a6db9 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -195,7 +195,7 @@ func TextHash(data []byte) []byte { // // This gives context to the signed message and prevents signing of transactions. func TextAndHash(data []byte) ([]byte, string) { - msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), string(data)) + msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) hasher := sha3.NewLegacyKeccak256() hasher.Write([]byte(msg)) return hasher.Sum(nil), msg From cd490608e344e388edd7ef3dd323968d706ccf8c Mon Sep 17 00:00:00 2001 From: hyhnet Date: Fri, 8 Mar 2024 05:56:19 +0800 Subject: [PATCH 045/571] all: fix typos in comments (#29186) --- cmd/evm/internal/t8ntool/block.go | 2 +- cmd/evm/internal/t8ntool/transaction.go | 2 +- cmd/evm/internal/t8ntool/transition.go | 2 +- cmd/evm/internal/t8ntool/tx_iterator.go | 2 +- cmd/evm/internal/t8ntool/utils.go | 2 +- core/types/account.go | 2 +- core/types/receipt_test.go | 4 ++-- crypto/kzg4844/kzg4844.go | 2 +- crypto/secp256k1/libsecp256k1/include/secp256k1.h | 2 +- crypto/secp256k1/libsecp256k1/sage/group_prover.sage | 2 +- eth/handler.go | 2 +- eth/protocols/snap/sync_test.go | 4 ++-- ethclient/gethclient/gethclient_test.go | 2 +- rpc/client.go | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go index a2dc4734372b..62c8593a1d47 100644 --- a/cmd/evm/internal/t8ntool/block.go +++ b/cmd/evm/internal/t8ntool/block.go @@ -242,7 +242,7 @@ func readInput(ctx *cli.Context) (*bbInput, error) { if headerStr == stdinSelector || ommersStr == stdinSelector || txsStr == stdinSelector || cliqueStr == stdinSelector { decoder := json.NewDecoder(os.Stdin) if err := decoder.Decode(inputData); err != nil { - return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err)) + return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshalling stdin: %v", err)) } } if cliqueStr != stdinSelector && cliqueStr != "" { diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 8533b7863769..7f66ba4d85d6 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -86,7 +86,7 @@ func Transaction(ctx *cli.Context) error { if txStr == stdinSelector { decoder := json.NewDecoder(os.Stdin) if err := decoder.Decode(inputData); err != nil { - return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err)) + return NewError(ErrorJson, fmt.Errorf("failed unmarshalling stdin: %v", err)) } // Decode the body of already signed transactions body = common.FromHex(inputData.TxRlp) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 7802d4965199..aa0483a8ba67 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -135,7 +135,7 @@ func Transition(ctx *cli.Context) error { if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector { decoder := json.NewDecoder(os.Stdin) if err := decoder.Decode(inputData); err != nil { - return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err)) + return NewError(ErrorJson, fmt.Errorf("failed unmarshalling stdin: %v", err)) } } if allocStr != stdinSelector { diff --git a/cmd/evm/internal/t8ntool/tx_iterator.go b/cmd/evm/internal/t8ntool/tx_iterator.go index 8f28dc70223b..046f62314dae 100644 --- a/cmd/evm/internal/t8ntool/tx_iterator.go +++ b/cmd/evm/internal/t8ntool/tx_iterator.go @@ -127,7 +127,7 @@ func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *pa return newRlpTxIterator(body), nil } if err := json.Unmarshal(data, &txsWithKeys); err != nil { - return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshaling txs-file: %v", err)) + return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshalling txs-file: %v", err)) } } else { if len(inputData.TxRlp) > 0 { diff --git a/cmd/evm/internal/t8ntool/utils.go b/cmd/evm/internal/t8ntool/utils.go index 8ec38c7618de..42f5471e7b24 100644 --- a/cmd/evm/internal/t8ntool/utils.go +++ b/cmd/evm/internal/t8ntool/utils.go @@ -33,7 +33,7 @@ func readFile(path, desc string, dest interface{}) error { defer inFile.Close() decoder := json.NewDecoder(inFile) if err := decoder.Decode(dest); err != nil { - return NewError(ErrorJson, fmt.Errorf("failed unmarshaling %s file: %v", desc, err)) + return NewError(ErrorJson, fmt.Errorf("failed unmarshalling %s file: %v", desc, err)) } return nil } diff --git a/core/types/account.go b/core/types/account.go index bb0f4ca02e10..52ce184cda5d 100644 --- a/core/types/account.go +++ b/core/types/account.go @@ -52,7 +52,7 @@ type accountMarshaling struct { } // storageJSON represents a 256 bit byte array, but allows less than 256 bits when -// unmarshaling from hex. +// unmarshalling from hex. type storageJSON common.Hash func (h *storageJSON) UnmarshalText(text []byte) error { diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index a7b26444712f..fc51eb11a528 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -343,7 +343,7 @@ func TestReceiptJSON(t *testing.T) { r := Receipt{} err = r.UnmarshalJSON(b) if err != nil { - t.Fatal("error unmarshaling receipt from json:", err) + t.Fatal("error unmarshalling receipt from json:", err) } } } @@ -360,7 +360,7 @@ func TestEffectiveGasPriceNotRequired(t *testing.T) { r2 := Receipt{} err = r2.UnmarshalJSON(b) if err != nil { - t.Fatal("error unmarshaling receipt from json:", err) + t.Fatal("error unmarshalling receipt from json:", err) } } diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index 52124df67461..168ff8347095 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -85,7 +85,7 @@ type Claim [32]byte var useCKZG atomic.Bool // UseCKZG can be called to switch the default Go implementation of KZG to the C -// library if fo some reason the user wishes to do so (e.g. consensus bug in one +// library if for some reason the user wishes to do so (e.g. consensus bug in one // or the other). func UseCKZG(use bool) error { if use && !ckzgAvailable { diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1.h b/crypto/secp256k1/libsecp256k1/include/secp256k1.h index f268e309d0bf..76af8396918e 100644 --- a/crypto/secp256k1/libsecp256k1/include/secp256k1.h +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1.h @@ -357,7 +357,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( /** Verify an ECDSA signature. * * Returns: 1: correct signature - * 0: incorrect or unparseable signature + * 0: incorrect or unparsable signature * Args: ctx: a secp256k1 context object, initialized for verification. * In: sig: the signature being verified (cannot be NULL) * msg32: the 32-byte message hash being verified (cannot be NULL) diff --git a/crypto/secp256k1/libsecp256k1/sage/group_prover.sage b/crypto/secp256k1/libsecp256k1/sage/group_prover.sage index ab580c5b23bb..68882e93659a 100644 --- a/crypto/secp256k1/libsecp256k1/sage/group_prover.sage +++ b/crypto/secp256k1/libsecp256k1/sage/group_prover.sage @@ -17,7 +17,7 @@ # - A constraint describing the requirements of the law, called "require" # * Implementations are transliterated into functions that operate as well on # algebraic input points, and are called once per combination of branches -# exectured. Each execution returns: +# executed. Each execution returns: # - A constraint describing the assumptions this implementation requires # (such as Z1=1), called "assumeFormula" # - A constraint describing the assumptions this specific branch requires, diff --git a/eth/handler.go b/eth/handler.go index a32a04e00b72..0d27e061c49b 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -497,7 +497,7 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { } // Send the transaction (if it's small enough) directly to a subset of // the peers that have not received it yet, ensuring that the flow of - // transactions is groupped by account to (try and) avoid nonce gaps. + // transactions is grouped by account to (try and) avoid nonce gaps. // // To do this, we hash the local enode IW with together with a peer's // enode ID together with the transaction sender and broadcast if diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index b780868b4e06..cea83aa2bc8e 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1502,7 +1502,7 @@ func getCodeByHash(hash common.Hash) []byte { return nil } -// makeAccountTrieNoStorage spits out a trie, along with the leafs +// makeAccountTrieNoStorage spits out a trie, along with the leaves func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv) { var ( db = triedb.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) @@ -1650,7 +1650,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots return db.Scheme(), accTrie, entries, storageTries, storageEntries } -// makeAccountTrieWithStorage spits out a trie, along with the leafs +// makeAccountTrieWithStorage spits out a trie, along with the leaves func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, boundary bool, uneven bool) (*trie.Trie, []*kv, map[common.Hash]*trie.Trie, map[common.Hash][]*kv) { var ( db = triedb.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 158886475eda..d562bcda1f01 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -146,7 +146,7 @@ func TestGethClient(t *testing.T) { func(t *testing.T) { testCallContractWithBlockOverrides(t, client) }, }, // The testaccesslist is a bit time-sensitive: the newTestBackend imports - // one block. The `testAcessList` fails if the miner has not yet created a + // one block. The `testAccessList` fails if the miner has not yet created a // new pending-block after the import event. // Hence: this test should be last, execute the tests serially. { diff --git a/rpc/client.go b/rpc/client.go index 2b0016db8f4e..eef6ee21cf05 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -70,7 +70,7 @@ type BatchElem struct { // discarded. Result interface{} // Error is set if the server returns an error for this request, or if - // unmarshaling into Result fails. It is not set for I/O errors. + // unmarshalling into Result fails. It is not set for I/O errors. Error error } From c41105ce80f12f60ec4bf6c65c4c59c6bf4a86e7 Mon Sep 17 00:00:00 2001 From: Sebastian Stammler Date: Fri, 8 Mar 2024 00:01:31 +0100 Subject: [PATCH 046/571] log: add Handler getter to Logger interface (#28793) log: Add Handler getter to Logger interface --- internal/testlog/testlog.go | 4 ++++ log/logger.go | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/internal/testlog/testlog.go b/internal/testlog/testlog.go index 037b7ee9c120..3cdbea6e0537 100644 --- a/internal/testlog/testlog.go +++ b/internal/testlog/testlog.go @@ -98,6 +98,10 @@ func LoggerWithHandler(t *testing.T, handler slog.Handler) log.Logger { } } +func (l *logger) Handler() slog.Handler { + return l.l.Handler() +} + func (l *logger) Write(level slog.Level, msg string, ctx ...interface{}) {} func (l *logger) Enabled(ctx context.Context, level slog.Level) bool { diff --git a/log/logger.go b/log/logger.go index 75e364304488..c28bbde56840 100644 --- a/log/logger.go +++ b/log/logger.go @@ -137,6 +137,9 @@ type Logger interface { // Enabled reports whether l emits log records at the given context and level. Enabled(ctx context.Context, level slog.Level) bool + + // Handler returns the underlying handler of the inner logger. + Handler() slog.Handler } type logger struct { @@ -150,6 +153,10 @@ func NewLogger(h slog.Handler) Logger { } } +func (l *logger) Handler() slog.Handler { + return l.inner.Handler() +} + // write logs a message at the specified level: func (l *logger) Write(level slog.Level, msg string, attrs ...any) { if !l.inner.Enabled(context.Background(), level) { From d35c8f0c25d3b5781e016252625b582c9553601a Mon Sep 17 00:00:00 2001 From: colin <102356659+colinlyguo@users.noreply.github.com> Date: Fri, 8 Mar 2024 19:13:46 +0800 Subject: [PATCH 047/571] ethclient/gethclient: add blob transaction fields in toCallArg (#29198) --- ethclient/gethclient/gethclient.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index 73d05d499efe..b1678b67664e 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -245,6 +245,12 @@ func toCallArg(msg ethereum.CallMsg) interface{} { if msg.AccessList != nil { arg["accessList"] = msg.AccessList } + if msg.BlobGasFeeCap != nil { + arg["maxFeePerBlobGas"] = (*hexutil.Big)(msg.BlobGasFeeCap) + } + if msg.BlobHashes != nil { + arg["blobVersionedHashes"] = msg.BlobHashes + } return arg } From e31709db6570e302557a9bccd681034ea0dcc246 Mon Sep 17 00:00:00 2001 From: Haotian <51777534+tmelhao@users.noreply.github.com> Date: Fri, 8 Mar 2024 19:15:52 +0800 Subject: [PATCH 048/571] console: fix the wrong error msg of datadir testcase (#29183) --- console/console_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/console/console_test.go b/console/console_test.go index 4c30c1b49cc6..d210a993c2d7 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -152,8 +152,7 @@ func (env *tester) Close(t *testing.T) { } // Tests that the node lists the correct welcome message, notably that it contains -// the instance name, coinbase account, block number, data directory and supported -// console modules. +// the instance name, block number, data directory and supported console modules. func TestWelcome(t *testing.T) { tester := newTester(t, nil) defer tester.Close(t) @@ -171,7 +170,10 @@ func TestWelcome(t *testing.T) { t.Fatalf("console output missing sync status: have\n%s\nwant also %s", output, want) } if want := fmt.Sprintf("datadir: %s", tester.workspace); !strings.Contains(output, want) { - t.Fatalf("console output missing coinbase: have\n%s\nwant also %s", output, want) + t.Fatalf("console output missing datadir: have\n%s\nwant also %s", output, want) + } + if want := "modules: "; !strings.Contains(output, want) { + t.Fatalf("console output missing modules: have\n%s\nwant also %s", output, want) } } From 3dc549b3d75af790e78ef2d7f63a947efb9b0e95 Mon Sep 17 00:00:00 2001 From: Kero Date: Mon, 11 Mar 2024 03:01:26 +0800 Subject: [PATCH 049/571] p2p/simulations/adapters: fix error messages in TestTCPPipeBidirections (#29207) --- p2p/simulations/adapters/inproc_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/simulations/adapters/inproc_test.go b/p2p/simulations/adapters/inproc_test.go index 2a61508fe18b..d0539ca86752 100644 --- a/p2p/simulations/adapters/inproc_test.go +++ b/p2p/simulations/adapters/inproc_test.go @@ -78,7 +78,7 @@ func TestTCPPipeBidirections(t *testing.T) { } if !bytes.Equal(expected, out) { - t.Fatalf("expected %#v, got %#v", out, expected) + t.Fatalf("expected %#v, got %#v", expected, out) } else { msg := []byte(fmt.Sprintf("pong %02d", i)) if _, err := c2.Write(msg); err != nil { @@ -94,7 +94,7 @@ func TestTCPPipeBidirections(t *testing.T) { t.Fatal(err) } if !bytes.Equal(expected, out) { - t.Fatalf("expected %#v, got %#v", out, expected) + t.Fatalf("expected %#v, got %#v", expected, out) } } } From b393ad8d29fe002fe6c0329a09d7715b00030c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 11 Mar 2024 10:06:57 +0200 Subject: [PATCH 050/571] cmd, core, metrics: always report expensive metrics (#29191) * cmd, core, metrics: always report expensive metrics * core, metrics: report block processing metrics as resetting timer * metrics: update reporter tests --- cmd/geth/config.go | 2 +- cmd/utils/flags.go | 6 -- cmd/utils/flags_legacy.go | 29 ++++--- core/blockchain.go | 40 +++++----- core/state/state_object.go | 26 +++--- core/state/statedb.go | 87 +++++++++------------ internal/flags/categories.go | 1 - metrics/config.go | 2 +- metrics/influxdb/influxdb.go | 25 +++--- metrics/influxdb/testdata/influxdbv1.want | 2 +- metrics/influxdb/testdata/influxdbv2.want | 2 +- metrics/metrics.go | 25 ------ metrics/prometheus/collector.go | 9 ++- metrics/prometheus/testdata/prometheus.want | 5 +- 14 files changed, 112 insertions(+), 149 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 37d17fb1e77d..cf4cdef76ce1 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -267,7 +267,7 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) { cfg.Metrics.Enabled = ctx.Bool(utils.MetricsEnabledFlag.Name) } if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) { - cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name) + log.Warn("Expensive metrics are collected by default, please remove this flag", "flag", utils.MetricsEnabledExpensiveFlag.Name) } if ctx.IsSet(utils.MetricsHTTPFlag.Name) { cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index e002975d53cf..b38f33b8dd7f 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -862,12 +862,6 @@ var ( Usage: "Enable metrics collection and reporting", Category: flags.MetricsCategory, } - MetricsEnabledExpensiveFlag = &cli.BoolFlag{ - Name: "metrics.expensive", - Usage: "Enable expensive metrics collection and reporting", - Category: flags.MetricsCategory, - } - // MetricsHTTPFlag defines the endpoint for a stand-alone metrics HTTP endpoint. // Since the pprof service enables sensitive/vulnerable behavior, this allows a user // to enable a public-OK metrics endpoint without having to worry about ALSO exposing diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go index 49321053c672..1dfd1a5f8934 100644 --- a/cmd/utils/flags_legacy.go +++ b/cmd/utils/flags_legacy.go @@ -93,35 +93,35 @@ var ( Name: "light.serve", Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)", Value: ethconfig.Defaults.LightServ, - Category: flags.LightCategory, + Category: flags.DeprecatedCategory, } LightIngressFlag = &cli.IntFlag{ Name: "light.ingress", Usage: "Incoming bandwidth limit for serving light clients (deprecated)", Value: ethconfig.Defaults.LightIngress, - Category: flags.LightCategory, + Category: flags.DeprecatedCategory, } LightEgressFlag = &cli.IntFlag{ Name: "light.egress", Usage: "Outgoing bandwidth limit for serving light clients (deprecated)", Value: ethconfig.Defaults.LightEgress, - Category: flags.LightCategory, + Category: flags.DeprecatedCategory, } LightMaxPeersFlag = &cli.IntFlag{ Name: "light.maxpeers", Usage: "Maximum number of light clients to serve, or light servers to attach to (deprecated)", Value: ethconfig.Defaults.LightPeers, - Category: flags.LightCategory, + Category: flags.DeprecatedCategory, } LightNoPruneFlag = &cli.BoolFlag{ Name: "light.nopruning", Usage: "Disable ancient light chain data pruning (deprecated)", - Category: flags.LightCategory, + Category: flags.DeprecatedCategory, } LightNoSyncServeFlag = &cli.BoolFlag{ Name: "light.nosyncserve", Usage: "Enables serving light clients before syncing (deprecated)", - Category: flags.LightCategory, + Category: flags.DeprecatedCategory, } // Deprecated November 2023 LogBacktraceAtFlag = &cli.StringFlag{ @@ -138,19 +138,24 @@ var ( // Deprecated February 2024 MinerNewPayloadTimeoutFlag = &cli.DurationFlag{ Name: "miner.newpayload-timeout", - Usage: "Specify the maximum time allowance for creating a new payload", + Usage: "Specify the maximum time allowance for creating a new payload (deprecated)", Value: ethconfig.Defaults.Miner.Recommit, - Category: flags.MinerCategory, + Category: flags.DeprecatedCategory, } MinerEtherbaseFlag = &cli.StringFlag{ Name: "miner.etherbase", - Usage: "0x prefixed public address for block mining rewards", - Category: flags.MinerCategory, + Usage: "0x prefixed public address for block mining rewards (deprecated)", + Category: flags.DeprecatedCategory, } MiningEnabledFlag = &cli.BoolFlag{ Name: "mine", - Usage: "Enable mining", - Category: flags.MinerCategory, + Usage: "Enable mining (deprecated)", + Category: flags.DeprecatedCategory, + } + MetricsEnabledExpensiveFlag = &cli.BoolFlag{ + Name: "metrics.expensive", + Usage: "Enable expensive metrics collection and reporting (deprecated)", + Category: flags.DeprecatedCategory, } ) diff --git a/core/blockchain.go b/core/blockchain.go index 67b49cfe0262..9bd7fdcd9544 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -61,26 +61,26 @@ var ( chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil) - accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil) - accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil) - accountUpdateTimer = metrics.NewRegisteredTimer("chain/account/updates", nil) - accountCommitTimer = metrics.NewRegisteredTimer("chain/account/commits", nil) - - storageReadTimer = metrics.NewRegisteredTimer("chain/storage/reads", nil) - storageHashTimer = metrics.NewRegisteredTimer("chain/storage/hashes", nil) - storageUpdateTimer = metrics.NewRegisteredTimer("chain/storage/updates", nil) - storageCommitTimer = metrics.NewRegisteredTimer("chain/storage/commits", nil) - - snapshotAccountReadTimer = metrics.NewRegisteredTimer("chain/snapshot/account/reads", nil) - snapshotStorageReadTimer = metrics.NewRegisteredTimer("chain/snapshot/storage/reads", nil) - snapshotCommitTimer = metrics.NewRegisteredTimer("chain/snapshot/commits", nil) - - triedbCommitTimer = metrics.NewRegisteredTimer("chain/triedb/commits", nil) - - blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil) - blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil) - blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil) - blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil) + accountReadTimer = metrics.NewRegisteredResettingTimer("chain/account/reads", nil) + accountHashTimer = metrics.NewRegisteredResettingTimer("chain/account/hashes", nil) + accountUpdateTimer = metrics.NewRegisteredResettingTimer("chain/account/updates", nil) + accountCommitTimer = metrics.NewRegisteredResettingTimer("chain/account/commits", nil) + + storageReadTimer = metrics.NewRegisteredResettingTimer("chain/storage/reads", nil) + storageHashTimer = metrics.NewRegisteredResettingTimer("chain/storage/hashes", nil) + storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil) + storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil) + + snapshotAccountReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/account/reads", nil) + snapshotStorageReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/storage/reads", nil) + snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil) + + triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil) + + blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil) + blockValidationTimer = metrics.NewRegisteredResettingTimer("chain/validation", nil) + blockExecutionTimer = metrics.NewRegisteredResettingTimer("chain/execution", nil) + blockWriteTimer = metrics.NewRegisteredResettingTimer("chain/write", nil) blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil) blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil) diff --git a/core/state/state_object.go b/core/state/state_object.go index fc26af68dbe7..6dea68465baa 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -25,7 +25,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/metrics" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/holiman/uint256" @@ -197,9 +196,8 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { if s.db.snap != nil { start := time.Now() enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes())) - if metrics.EnabledExpensive { - s.db.SnapshotStorageReads += time.Since(start) - } + s.db.SnapshotStorageReads += time.Since(start) + if len(enc) > 0 { _, content, _, err := rlp.Split(enc) if err != nil { @@ -217,9 +215,8 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { return common.Hash{} } val, err := tr.GetStorage(s.address, key.Bytes()) - if metrics.EnabledExpensive { - s.db.StorageReads += time.Since(start) - } + s.db.StorageReads += time.Since(start) + if err != nil { s.db.setError(err) return common.Hash{} @@ -283,9 +280,8 @@ func (s *stateObject) updateTrie() (Trie, error) { return s.trie, nil } // Track the amount of time wasted on updating the storage trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) - } + defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) + // The snapshot storage map for the object var ( storage map[common.Hash][]byte @@ -370,9 +366,8 @@ func (s *stateObject) updateRoot() { return } // Track the amount of time wasted on hashing the storage trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) - } + defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) + s.data.Root = tr.Hash() } @@ -386,9 +381,8 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) { return nil, nil } // Track the amount of time wasted on committing the storage trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) - } + defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) + // The trie is currently in an open state and could potentially contain // cached mutations. Call commit to acquire a set of nodes that have been // modified, the set can be nil if nothing to commit. diff --git a/core/state/statedb.go b/core/state/statedb.go index 4d1163d3c6af..f90b30f3994e 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" @@ -495,9 +494,8 @@ func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common // updateStateObject writes the given object to the trie. func (s *StateDB) updateStateObject(obj *stateObject) { // Track the amount of time wasted on updating the account from the trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) - } + defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) + // Encode the account and update the account trie addr := obj.Address() if err := s.trie.UpdateAccount(addr, &obj.data); err != nil { @@ -527,9 +525,8 @@ func (s *StateDB) updateStateObject(obj *stateObject) { // deleteStateObject removes the given object from the state trie. func (s *StateDB) deleteStateObject(obj *stateObject) { // Track the amount of time wasted on deleting the account from the trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) - } + defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) + // Delete the account from the trie addr := obj.Address() if err := s.trie.DeleteAccount(addr); err != nil { @@ -561,9 +558,8 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { if s.snap != nil { start := time.Now() acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes())) - if metrics.EnabledExpensive { - s.SnapshotAccountReads += time.Since(start) - } + s.SnapshotAccountReads += time.Since(start) + if err == nil { if acc == nil { return nil @@ -587,9 +583,8 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { start := time.Now() var err error data, err = s.trie.GetAccount(addr) - if metrics.EnabledExpensive { - s.AccountReads += time.Since(start) - } + s.AccountReads += time.Since(start) + if err != nil { s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %w", addr.Bytes(), err)) return nil @@ -917,9 +912,8 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.stateObjectsPending = make(map[common.Address]struct{}) } // Track the amount of time wasted on hashing the account trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) - } + defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) + return s.trie.Hash() } @@ -1042,16 +1036,16 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root if err != nil { return nil, nil, err } - if metrics.EnabledExpensive { - n := int64(len(slots)) + // Report the metrics + n := int64(len(slots)) - slotDeletionMaxCount.UpdateIfGt(int64(len(slots))) - slotDeletionMaxSize.UpdateIfGt(int64(size)) + slotDeletionMaxCount.UpdateIfGt(int64(len(slots))) + slotDeletionMaxSize.UpdateIfGt(int64(size)) + + slotDeletionTimer.UpdateSince(start) + slotDeletionCount.Mark(n) + slotDeletionSize.Mark(int64(size)) - slotDeletionTimer.UpdateSince(start) - slotDeletionCount.Mark(n) - slotDeletionSize.Mark(int64(size)) - } return slots, nodes, nil } @@ -1190,10 +1184,8 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er } } // Write the account trie changes, measuring the amount of wasted time - var start time.Time - if metrics.EnabledExpensive { - start = time.Now() - } + start := time.Now() + root, set, err := s.trie.Commit(true) if err != nil { return common.Hash{}, err @@ -1205,23 +1197,23 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er } accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() } - if metrics.EnabledExpensive { - s.AccountCommits += time.Since(start) + // Report the commit metrics + s.AccountCommits += time.Since(start) + + accountUpdatedMeter.Mark(int64(s.AccountUpdated)) + storageUpdatedMeter.Mark(int64(s.StorageUpdated)) + accountDeletedMeter.Mark(int64(s.AccountDeleted)) + storageDeletedMeter.Mark(int64(s.StorageDeleted)) + accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated)) + accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) + storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated)) + storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted)) + s.AccountUpdated, s.AccountDeleted = 0, 0 + s.StorageUpdated, s.StorageDeleted = 0, 0 - accountUpdatedMeter.Mark(int64(s.AccountUpdated)) - storageUpdatedMeter.Mark(int64(s.StorageUpdated)) - accountDeletedMeter.Mark(int64(s.AccountDeleted)) - storageDeletedMeter.Mark(int64(s.StorageDeleted)) - accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated)) - accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) - storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated)) - storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted)) - s.AccountUpdated, s.AccountDeleted = 0, 0 - s.StorageUpdated, s.StorageDeleted = 0, 0 - } // If snapshotting is enabled, update the snapshot tree with this new version if s.snap != nil { - start := time.Now() + start = time.Now() // Only update if there's a state transition (skip empty Clique blocks) if parent := s.snap.Root(); parent != root { if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil { @@ -1235,9 +1227,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er log.Warn("Failed to cap snapshot tree", "root", root, "layers", 128, "err", err) } } - if metrics.EnabledExpensive { - s.SnapshotCommits += time.Since(start) - } + s.SnapshotCommits += time.Since(start) s.snap = nil } if root == (common.Hash{}) { @@ -1248,15 +1238,14 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er origin = types.EmptyRootHash } if root != origin { - start := time.Now() + start = time.Now() set := triestate.New(s.accountsOrigin, s.storagesOrigin) if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil { return common.Hash{}, err } s.originalRoot = root - if metrics.EnabledExpensive { - s.TrieDBCommits += time.Since(start) - } + s.TrieDBCommits += time.Since(start) + if s.onCommit != nil { s.onCommit(set) } diff --git a/internal/flags/categories.go b/internal/flags/categories.go index c044e28f384c..d426add55b10 100644 --- a/internal/flags/categories.go +++ b/internal/flags/categories.go @@ -21,7 +21,6 @@ import "github.com/urfave/cli/v2" const ( EthCategory = "ETHEREUM" BeaconCategory = "BEACON CHAIN" - LightCategory = "LIGHT CLIENT" DevCategory = "DEVELOPER CHAIN" StateCategory = "STATE HISTORY MANAGEMENT" TxPoolCategory = "TRANSACTION POOL (EVM)" diff --git a/metrics/config.go b/metrics/config.go index 2eb09fb48a33..72f94dd194c9 100644 --- a/metrics/config.go +++ b/metrics/config.go @@ -19,7 +19,7 @@ package metrics // Config contains the configuration for the metric collection. type Config struct { Enabled bool `toml:",omitempty"` - EnabledExpensive bool `toml:",omitempty"` + EnabledExpensive bool `toml:"-"` HTTP string `toml:",omitempty"` Port int `toml:",omitempty"` EnableInfluxDB bool `toml:",omitempty"` diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index bbc4fc024b34..5c8501fd9db5 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -98,20 +98,23 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf } return measurement, fields case metrics.ResettingTimer: - t := metric.Snapshot() - if t.Count() == 0 { + ms := metric.Snapshot() + if ms.Count() == 0 { break } - ps := t.Percentiles([]float64{0.50, 0.95, 0.99}) - measurement := fmt.Sprintf("%s%s.span", namespace, name) + ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) + measurement := fmt.Sprintf("%s%s.timer", namespace, name) fields := map[string]interface{}{ - "count": t.Count(), - "max": t.Max(), - "mean": t.Mean(), - "min": t.Min(), - "p50": int(ps[0]), - "p95": int(ps[1]), - "p99": int(ps[2]), + "count": ms.Count(), + "max": ms.Max(), + "mean": ms.Mean(), + "min": ms.Min(), + "p50": ps[0], + "p75": ps[1], + "p95": ps[2], + "p99": ps[3], + "p999": ps[4], + "p9999": ps[5], } return measurement, fields } diff --git a/metrics/influxdb/testdata/influxdbv1.want b/metrics/influxdb/testdata/influxdbv1.want index 9443faedc5a2..ded9434c7314 100644 --- a/metrics/influxdb/testdata/influxdbv1.want +++ b/metrics/influxdb/testdata/influxdbv1.want @@ -7,5 +7,5 @@ goth.test/gauge_float64.gauge value=34567.89 978307200000000000 goth.test/gauge_info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000 goth.test/histogram.histogram count=3i,max=3i,mean=2,min=1i,p25=1,p50=2,p75=3,p95=3,p99=3,p999=3,p9999=3,stddev=0.816496580927726,variance=0.6666666666666666 978307200000000000 goth.test/meter.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000 -goth.test/resetting_timer.span count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12500000i,p95=120000000i,p99=120000000i 978307200000000000 +goth.test/resetting_timer.timer count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12500000,p75=40500000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000 978307200000000000 goth.test/timer.timer count=6i,m1=0,m15=0,m5=0,max=120000000i,mean=38333333.333333336,meanrate=0,min=20000000i,p50=22500000,p75=48000000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000,stddev=36545253.529775314,variance=1335555555555555.2 978307200000000000 diff --git a/metrics/influxdb/testdata/influxdbv2.want b/metrics/influxdb/testdata/influxdbv2.want index 9443faedc5a2..ded9434c7314 100644 --- a/metrics/influxdb/testdata/influxdbv2.want +++ b/metrics/influxdb/testdata/influxdbv2.want @@ -7,5 +7,5 @@ goth.test/gauge_float64.gauge value=34567.89 978307200000000000 goth.test/gauge_info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000 goth.test/histogram.histogram count=3i,max=3i,mean=2,min=1i,p25=1,p50=2,p75=3,p95=3,p99=3,p999=3,p9999=3,stddev=0.816496580927726,variance=0.6666666666666666 978307200000000000 goth.test/meter.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000 -goth.test/resetting_timer.span count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12500000i,p95=120000000i,p99=120000000i 978307200000000000 +goth.test/resetting_timer.timer count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12500000,p75=40500000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000 978307200000000000 goth.test/timer.timer count=6i,m1=0,m15=0,m5=0,max=120000000i,mean=38333333.333333336,meanrate=0,min=20000000i,p50=22500000,p75=48000000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000,stddev=36545253.529775314,variance=1335555555555555.2 978307200000000000 diff --git a/metrics/metrics.go b/metrics/metrics.go index 9ca8f115c0f7..9e0ac23dd511 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -24,23 +24,12 @@ import ( // for less cluttered pprof profiles. var Enabled = false -// EnabledExpensive is a soft-flag meant for external packages to check if costly -// metrics gathering is allowed or not. The goal is to separate standard metrics -// for health monitoring and debug metrics that might impact runtime performance. -var EnabledExpensive = false - // enablerFlags is the CLI flag names to use to enable metrics collections. var enablerFlags = []string{"metrics"} // enablerEnvVars is the env var names to use to enable metrics collections. var enablerEnvVars = []string{"GETH_METRICS"} -// expensiveEnablerFlags is the CLI flag names to use to enable metrics collections. -var expensiveEnablerFlags = []string{"metrics.expensive"} - -// expensiveEnablerEnvVars is the env var names to use to enable metrics collections. -var expensiveEnablerEnvVars = []string{"GETH_METRICS_EXPENSIVE"} - // Init enables or disables the metrics system. Since we need this to run before // any other code gets to create meters and timers, we'll actually do an ugly hack // and peek into the command line args for the metrics flag. @@ -53,14 +42,6 @@ func init() { } } } - for _, enabler := range expensiveEnablerEnvVars { - if val, found := syscall.Getenv(enabler); found && !EnabledExpensive { - if enable, _ := strconv.ParseBool(val); enable { // ignore error, flag parser will choke on it later - log.Info("Enabling expensive metrics collection") - EnabledExpensive = true - } - } - } for _, arg := range os.Args { flag := strings.TrimLeft(arg, "-") @@ -70,12 +51,6 @@ func init() { Enabled = true } } - for _, enabler := range expensiveEnablerFlags { - if !EnabledExpensive && flag == enabler { - log.Info("Enabling expensive metrics collection") - EnabledExpensive = true - } - } } } diff --git a/metrics/prometheus/collector.go b/metrics/prometheus/collector.go index 25b258d56ab1..353336763b0b 100644 --- a/metrics/prometheus/collector.go +++ b/metrics/prometheus/collector.go @@ -125,12 +125,13 @@ func (c *collector) addResettingTimer(name string, m metrics.ResettingTimerSnaps if m.Count() <= 0 { return } - ps := m.Percentiles([]float64{0.50, 0.95, 0.99}) + pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999} + ps := m.Percentiles(pv) c.writeSummaryCounter(name, m.Count()) c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name))) - c.writeSummaryPercentile(name, "0.50", ps[0]) - c.writeSummaryPercentile(name, "0.95", ps[1]) - c.writeSummaryPercentile(name, "0.99", ps[2]) + for i := range pv { + c.writeSummaryPercentile(name, strconv.FormatFloat(pv[i], 'f', -1, 64), ps[i]) + } c.buff.WriteRune('\n') } diff --git a/metrics/prometheus/testdata/prometheus.want b/metrics/prometheus/testdata/prometheus.want index 861c5f5cf087..a999d83801c6 100644 --- a/metrics/prometheus/testdata/prometheus.want +++ b/metrics/prometheus/testdata/prometheus.want @@ -53,9 +53,12 @@ test_meter 0 test_resetting_timer_count 6 # TYPE test_resetting_timer summary -test_resetting_timer {quantile="0.50"} 1.25e+07 +test_resetting_timer {quantile="0.5"} 1.25e+07 +test_resetting_timer {quantile="0.75"} 4.05e+07 test_resetting_timer {quantile="0.95"} 1.2e+08 test_resetting_timer {quantile="0.99"} 1.2e+08 +test_resetting_timer {quantile="0.999"} 1.2e+08 +test_resetting_timer {quantile="0.9999"} 1.2e+08 # TYPE test_timer_count counter test_timer_count 6 From 00c21128ef62be54bef798f3220f79ae2297be66 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Mon, 11 Mar 2024 05:05:17 -0500 Subject: [PATCH 051/571] core/txpool/blobpool: return ErrAlreadyKnown for duplicate txs (#29210) Signed-off-by: Lee Bousfield --- core/txpool/blobpool/blobpool.go | 6 +++++- core/txpool/blobpool/blobpool_test.go | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 3ed698c1b18f..6dbcc9dadc05 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1131,8 +1131,12 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error { next = p.state.GetNonce(from) ) if uint64(len(p.index[from])) > tx.Nonce()-next { - // Account can support the replacement, but the price bump must also be met prev := p.index[from][int(tx.Nonce()-next)] + // Ensure the transaction is different than the one tracked locally + if prev.hash == tx.Hash() { + return txpool.ErrAlreadyKnown + } + // Account can support the replacement, but the price bump must also be met switch { case tx.GasFeeCapIntCmp(prev.execFeeCap.ToBig()) <= 0: return fmt.Errorf("%w: new tx gas fee cap %v <= %v queued", txpool.ErrReplaceUnderpriced, tx.GasFeeCap(), prev.execFeeCap) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index f7644c1d0ab6..bac239db4769 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -984,9 +984,14 @@ func TestAdd(t *testing.T) { }, }, adds: []addtx{ - { // New account, 1 tx pending: reject replacement nonce 0 (ignore price for now) + { // New account, 1 tx pending: reject duplicate nonce 0 from: "alice", tx: makeUnsignedTx(0, 1, 1, 1), + err: txpool.ErrAlreadyKnown, + }, + { // New account, 1 tx pending: reject replacement nonce 0 (ignore price for now) + from: "alice", + tx: makeUnsignedTx(0, 1, 1, 2), err: txpool.ErrReplaceUnderpriced, }, { // New account, 1 tx pending: accept nonce 1 @@ -1009,10 +1014,10 @@ func TestAdd(t *testing.T) { tx: makeUnsignedTx(3, 1, 1, 1), err: nil, }, - { // Old account, 1 tx in chain, 1 tx pending: reject replacement nonce 1 (ignore price for now) + { // Old account, 1 tx in chain, 1 tx pending: reject duplicate nonce 1 from: "bob", tx: makeUnsignedTx(1, 1, 1, 1), - err: txpool.ErrReplaceUnderpriced, + err: txpool.ErrAlreadyKnown, }, { // Old account, 1 tx in chain, 1 tx pending: accept nonce 2 (ignore price for now) from: "bob", From fa4ade8ecb4e37687b464fdab6986c01cc1e50c2 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:05:48 +0100 Subject: [PATCH 052/571] core: fix deprecation comment for GenesisAccount (#29218) core: fix deprecation comment --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index 54570ac61e4c..3f1fde8dfca4 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -45,7 +45,7 @@ import ( var errGenesisNoConfig = errors.New("genesis has no chain configuration") -// Deprecated: use types.GenesisAccount instead. +// Deprecated: use types.Account instead. type GenesisAccount = types.Account // Deprecated: use types.GenesisAlloc instead. From ebf9e11af2ff701d0961623e817d37b421b96802 Mon Sep 17 00:00:00 2001 From: guangwu Date: Mon, 11 Mar 2024 18:17:16 +0800 Subject: [PATCH 053/571] beacon/light/request: fix typos (#29216) --- beacon/light/request/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon/light/request/server.go b/beacon/light/request/server.go index 999f64178af4..407eb69f497e 100644 --- a/beacon/light/request/server.go +++ b/beacon/light/request/server.go @@ -257,7 +257,7 @@ func (s *serverWithLimits) init() { } // subscribe subscribes to events which include parent (serverWithTimeout) events -// plus EvCanRequstAgain. +// plus EvCanRequestAgain. func (s *serverWithLimits) subscribe(eventCallback func(event Event)) { s.lock.Lock() defer s.lock.Unlock() @@ -415,7 +415,7 @@ func (s *serverWithLimits) delay(delay time.Duration) { } // fail reports that a response from the server was found invalid by the processing -// Module, disabling new requests for a dynamically adjused time period. +// Module, disabling new requests for a dynamically adjusted time period. func (s *serverWithLimits) fail(desc string) { s.lock.Lock() defer s.lock.Unlock() From 4e1116f9c513961b62dff146a7cce069fe7a36b0 Mon Sep 17 00:00:00 2001 From: San Ye Date: Tue, 12 Mar 2024 16:49:53 +0800 Subject: [PATCH 054/571] crypto/bn256/cloudflare: fix noescape-directive (#29222) --- crypto/bn256/cloudflare/gfp_decl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/bn256/cloudflare/gfp_decl.go b/crypto/bn256/cloudflare/gfp_decl.go index cf7f5654239f..1954d14a4a5a 100644 --- a/crypto/bn256/cloudflare/gfp_decl.go +++ b/crypto/bn256/cloudflare/gfp_decl.go @@ -13,7 +13,7 @@ import ( //nolint:varcheck,unused,deadcode var hasBMI2 = cpu.X86.HasBMI2 -// go:noescape +//go:noescape func gfpNeg(c, a *gfP) //go:noescape From 89cefe240fd22b01e413786e18ad35263c93a61f Mon Sep 17 00:00:00 2001 From: Bin <49082129+songzhibin97@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:00:34 +0800 Subject: [PATCH 055/571] cmd: use package filepath over path for file system operations (#29227) Package filepath implements utility routines for manipulating filename paths in a way compatible with the target operating system-defined file paths. Package path implements utility routines for manipulating slash-separated paths. The path package should only be used for paths separated by forward slashes, such as the paths in URLs --- cmd/devp2p/internal/ethtest/chain.go | 10 +++++----- cmd/devp2p/internal/ethtest/engine.go | 4 ++-- cmd/devp2p/internal/ethtest/suite_test.go | 4 ++-- cmd/era/main.go | 6 +++--- cmd/evm/internal/t8ntool/transition.go | 8 ++++---- cmd/utils/cmd.go | 12 ++++++------ cmd/utils/history_test.go | 6 +++--- core/blockchain_repair_test.go | 6 +++--- core/blockchain_snapshot_test.go | 4 ++-- core/rawdb/freezer_test.go | 3 ++- 10 files changed, 32 insertions(+), 31 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index e8b3725b17a5..a34a41dacdaa 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -26,7 +26,7 @@ import ( "io" "math/big" "os" - "path" + "path/filepath" "sort" "strings" @@ -56,21 +56,21 @@ type Chain struct { // NewChain takes the given chain.rlp file, and decodes and returns // the blocks from the file. func NewChain(dir string) (*Chain, error) { - gen, err := loadGenesis(path.Join(dir, "genesis.json")) + gen, err := loadGenesis(filepath.Join(dir, "genesis.json")) if err != nil { return nil, err } gblock := gen.ToBlock() - blocks, err := blocksFromFile(path.Join(dir, "chain.rlp"), gblock) + blocks, err := blocksFromFile(filepath.Join(dir, "chain.rlp"), gblock) if err != nil { return nil, err } - state, err := readState(path.Join(dir, "headstate.json")) + state, err := readState(filepath.Join(dir, "headstate.json")) if err != nil { return nil, err } - accounts, err := readAccounts(path.Join(dir, "accounts.json")) + accounts, err := readAccounts(filepath.Join(dir, "accounts.json")) if err != nil { return nil, err } diff --git a/cmd/devp2p/internal/ethtest/engine.go b/cmd/devp2p/internal/ethtest/engine.go index ea4fc76e6ff7..0e94efa5bdac 100644 --- a/cmd/devp2p/internal/ethtest/engine.go +++ b/cmd/devp2p/internal/ethtest/engine.go @@ -22,7 +22,7 @@ import ( "io" "net/http" "os" - "path" + "path/filepath" "time" "github.com/ethereum/go-ethereum/common" @@ -38,7 +38,7 @@ type EngineClient struct { // NewEngineClient creates a new engine client. func NewEngineClient(dir, url, jwt string) (*EngineClient, error) { - headfcu, err := os.ReadFile(path.Join(dir, "headfcu.json")) + headfcu, err := os.ReadFile(filepath.Join(dir, "headfcu.json")) if err != nil { return nil, fmt.Errorf("failed to read headfcu: %w", err) } diff --git a/cmd/devp2p/internal/ethtest/suite_test.go b/cmd/devp2p/internal/ethtest/suite_test.go index ad73bc9f90e7..d70adda51f92 100644 --- a/cmd/devp2p/internal/ethtest/suite_test.go +++ b/cmd/devp2p/internal/ethtest/suite_test.go @@ -20,7 +20,7 @@ import ( crand "crypto/rand" "fmt" "os" - "path" + "path/filepath" "testing" "time" @@ -39,7 +39,7 @@ func makeJWTSecret() (string, [32]byte, error) { if _, err := crand.Read(secret[:]); err != nil { return "", secret, fmt.Errorf("failed to create jwt secret: %v", err) } - jwtPath := path.Join(os.TempDir(), "jwt_secret") + jwtPath := filepath.Join(os.TempDir(), "jwt_secret") if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil { return "", secret, fmt.Errorf("failed to prepare jwt secret file: %v", err) } diff --git a/cmd/era/main.go b/cmd/era/main.go index c7f5de12bc1a..8b57fd695c53 100644 --- a/cmd/era/main.go +++ b/cmd/era/main.go @@ -22,7 +22,7 @@ import ( "fmt" "math/big" "os" - "path" + "path/filepath" "strconv" "strings" "time" @@ -176,7 +176,7 @@ func open(ctx *cli.Context, epoch uint64) (*era.Era, error) { if epoch >= uint64(len(entries)) { return nil, fmt.Errorf("epoch out-of-bounds: last %d, want %d", len(entries)-1, epoch) } - return era.Open(path.Join(dir, entries[epoch])) + return era.Open(filepath.Join(dir, entries[epoch])) } // verify checks each era1 file in a directory to ensure it is well-formed and @@ -212,7 +212,7 @@ func verify(ctx *cli.Context) error { // Wrap in function so defers don't stack. err := func() error { name := entries[i] - e, err := era.Open(path.Join(dir, name)) + e, err := era.Open(filepath.Join(dir, name)) if err != nil { return fmt.Errorf("error opening era1 file %s: %w", name, err) } diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index aa0483a8ba67..a9489d069a70 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -22,7 +22,7 @@ import ( "fmt" "math/big" "os" - "path" + "path/filepath" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -96,7 +96,7 @@ func Transition(ctx *cli.Context) error { Debug: true, } getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { - traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) + traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) if err != nil { return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } @@ -108,7 +108,7 @@ func Transition(ctx *cli.Context) error { config = []byte(ctx.String(TraceTracerConfigFlag.Name)) } getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { - traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String()))) + traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String()))) if err != nil { return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } @@ -302,7 +302,7 @@ func saveFile(baseDir, filename string, data interface{}) error { if err != nil { return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) } - location := path.Join(baseDir, filename) + location := filepath.Join(baseDir, filename) if err = os.WriteFile(location, b, 0644); err != nil { return NewError(ErrorIO, fmt.Errorf("failed writing output: %v", err)) } diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 37736dda8509..fc66e11dca96 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -27,7 +27,7 @@ import ( "io" "os" "os/signal" - "path" + "path/filepath" "runtime" "strings" "syscall" @@ -251,7 +251,7 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ if err != nil { return fmt.Errorf("error reading %s: %w", dir, err) } - checksums, err := readList(path.Join(dir, "checksums.txt")) + checksums, err := readList(filepath.Join(dir, "checksums.txt")) if err != nil { return fmt.Errorf("unable to read checksums.txt: %w", err) } @@ -268,7 +268,7 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ ) for i, filename := range entries { err := func() error { - f, err := os.Open(path.Join(dir, filename)) + f, err := os.Open(filepath.Join(dir, filename)) if err != nil { return fmt.Errorf("unable to open era: %w", err) } @@ -425,7 +425,7 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) er ) for i := first; i <= last; i += step { err := func() error { - filename := path.Join(dir, era.Filename(network, int(i/step), common.Hash{})) + filename := filepath.Join(dir, era.Filename(network, int(i/step), common.Hash{})) f, err := os.Create(filename) if err != nil { return fmt.Errorf("could not create era file: %w", err) @@ -458,7 +458,7 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) er return fmt.Errorf("export failed to finalize %d: %w", step/i, err) } // Set correct filename with root. - os.Rename(filename, path.Join(dir, era.Filename(network, int(i/step), root))) + os.Rename(filename, filepath.Join(dir, era.Filename(network, int(i/step), root))) // Compute checksum of entire Era1. if _, err := f.Seek(0, io.SeekStart); err != nil { @@ -481,7 +481,7 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) er } } - os.WriteFile(path.Join(dir, "checksums.txt"), []byte(strings.Join(checksums, "\n")), os.ModePerm) + os.WriteFile(filepath.Join(dir, "checksums.txt"), []byte(strings.Join(checksums, "\n")), os.ModePerm) log.Info("Exported blockchain to", "dir", dir) diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go index 9b7f1797d8dd..1d8e48344a2e 100644 --- a/cmd/utils/history_test.go +++ b/cmd/utils/history_test.go @@ -22,7 +22,7 @@ import ( "io" "math/big" "os" - "path" + "path/filepath" "strings" "testing" @@ -99,7 +99,7 @@ func TestHistoryImportAndExport(t *testing.T) { } // Read checksums. - b, err := os.ReadFile(path.Join(dir, "checksums.txt")) + b, err := os.ReadFile(filepath.Join(dir, "checksums.txt")) if err != nil { t.Fatalf("failed to read checksums: %v", err) } @@ -109,7 +109,7 @@ func TestHistoryImportAndExport(t *testing.T) { entries, _ := era.ReadDir(dir, "mainnet") for i, filename := range entries { func() { - f, err := os.Open(path.Join(dir, filename)) + f, err := os.Open(filepath.Join(dir, filename)) if err != nil { t.Fatalf("error opening era file: %v", err) } diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index b6a299f8ba89..a4761f337b85 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -22,7 +22,7 @@ package core import ( "math/big" - "path" + "path/filepath" "testing" "time" @@ -1762,7 +1762,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s // Create a temporary persistent database datadir := t.TempDir() - ancient := path.Join(datadir, "ancient") + ancient := filepath.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, @@ -1912,7 +1912,7 @@ func testIssue23496(t *testing.T, scheme string) { // Create a temporary persistent database datadir := t.TempDir() - ancient := path.Join(datadir, "ancient") + ancient := filepath.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index dd012c430c4d..80f8035df151 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -24,7 +24,7 @@ import ( "fmt" "math/big" "os" - "path" + "path/filepath" "strings" "testing" "time" @@ -63,7 +63,7 @@ type snapshotTestBasic struct { func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) { // Create a temporary persistent database datadir := t.TempDir() - ancient := path.Join(datadir, "ancient") + ancient := filepath.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index b4bd6a382a86..2a156638903d 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -24,6 +24,7 @@ import ( "math/rand" "os" "path" + "path/filepath" "sync" "testing" @@ -393,7 +394,7 @@ func TestRenameWindows(t *testing.T) { dir2 := t.TempDir() // Create file in dir1 and fill with data - f, err := os.Create(path.Join(dir1, fname)) + f, err := os.Create(filepath.Join(dir1, fname)) if err != nil { t.Fatal(err) } From 99bbbc0277e34fc3a31512a345ba20874ae98e18 Mon Sep 17 00:00:00 2001 From: Shiming Zhang Date: Tue, 12 Mar 2024 19:12:37 +0800 Subject: [PATCH 056/571] internal/build, rpc: add missing HTTP response body Close() calls (#29223) Co-authored-by: Felix Lange --- internal/build/download.go | 6 ++++-- rpc/http.go | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/build/download.go b/internal/build/download.go index fda573df8331..206c51dce1e3 100644 --- a/internal/build/download.go +++ b/internal/build/download.go @@ -84,10 +84,12 @@ func (db *ChecksumDB) DownloadFile(url, dstPath string) error { resp, err := http.Get(url) if err != nil { return fmt.Errorf("download error: %v", err) - } else if resp.StatusCode != http.StatusOK { - return fmt.Errorf("download error: status %d", resp.StatusCode) } defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("download error: status %d", resp.StatusCode) + } if err := os.MkdirAll(filepath.Dir(dstPath), 0755); err != nil { return err } diff --git a/rpc/http.go b/rpc/http.go index dd376b1ecd59..f4b99429ef4f 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -236,7 +236,7 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos if _, err := buf.ReadFrom(resp.Body); err == nil { body = buf.Bytes() } - + resp.Body.Close() return nil, HTTPError{ Status: resp.Status, StatusCode: resp.StatusCode, From 4bd55a064ccc804127de09397273d16966fe8a37 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Tue, 12 Mar 2024 20:05:31 +0800 Subject: [PATCH 057/571] common/math: copy result in Exp (#29233) common/math: does not change base parameter --- common/math/big.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/common/math/big.go b/common/math/big.go index 013c0ba4b66f..721b297c9c4d 100644 --- a/common/math/big.go +++ b/common/math/big.go @@ -224,7 +224,7 @@ func ReadBits(bigint *big.Int, buf []byte) { } } -// U256 encodes as a 256 bit two's complement number. This operation is destructive. +// U256 encodes x as a 256 bit two's complement number. This operation is destructive. func U256(x *big.Int) *big.Int { return x.And(x, tt256m1) } @@ -255,14 +255,15 @@ func S256(x *big.Int) *big.Int { // // Courtesy @karalabe and @chfast func Exp(base, exponent *big.Int) *big.Int { + copyBase := new(big.Int).Set(base) result := big.NewInt(1) for _, word := range exponent.Bits() { for i := 0; i < wordBits; i++ { if word&1 == 1 { - U256(result.Mul(result, base)) + U256(result.Mul(result, copyBase)) } - U256(base.Mul(base, base)) + U256(copyBase.Mul(copyBase, copyBase)) word >>= 1 } } From 6c76b813df6d53b86fac17471e9a31afd20c481e Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 12 Mar 2024 14:29:35 +0100 Subject: [PATCH 058/571] miner: add additional log (#29193) Adds a debug level log if the payload building failed for whatever reason --- miner/payload_building.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miner/payload_building.go b/miner/payload_building.go index cbdb82a642cf..d027cd1e1f3a 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -229,6 +229,8 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs) (*Payload, error) { r := miner.generateWork(fullParams) if r.err == nil { payload.update(r, time.Since(start)) + } else { + log.Info("Error while generating work", "id", payload.id, "err", r.err) } timer.Reset(miner.config.Recommit) case <-payload.stop: From 758fce71fab5289e3af711b1fa21a541c77cc435 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 12 Mar 2024 19:23:24 +0100 Subject: [PATCH 059/571] p2p: fix race in dialScheduler (#29235) Co-authored-by: Stefan --- p2p/dial.go | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/p2p/dial.go b/p2p/dial.go index 5e4ab1d50dcc..08e1db28771e 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -25,6 +25,7 @@ import ( mrand "math/rand" "net" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common/mclock" @@ -248,7 +249,7 @@ loop: } case task := <-d.doneCh: - id := task.dest.ID() + id := task.dest().ID() delete(d.dialing, id) d.updateStaticPool(id) d.doneSinceLastLog++ @@ -410,7 +411,7 @@ func (d *dialScheduler) startStaticDials(n int) (started int) { // updateStaticPool attempts to move the given static dial back into staticPool. func (d *dialScheduler) updateStaticPool(id enode.ID) { task, ok := d.static[id] - if ok && task.staticPoolIndex < 0 && d.checkDial(task.dest) == nil { + if ok && task.staticPoolIndex < 0 && d.checkDial(task.dest()) == nil { d.addToStaticPool(task) } } @@ -437,10 +438,11 @@ func (d *dialScheduler) removeFromStaticPool(idx int) { // startDial runs the given dial task in a separate goroutine. func (d *dialScheduler) startDial(task *dialTask) { - d.log.Trace("Starting p2p dial", "id", task.dest.ID(), "ip", task.dest.IP(), "flag", task.flags) - hkey := string(task.dest.ID().Bytes()) + node := task.dest() + d.log.Trace("Starting p2p dial", "id", node.ID(), "ip", node.IP(), "flag", task.flags) + hkey := string(node.ID().Bytes()) d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration)) - d.dialing[task.dest.ID()] = task + d.dialing[node.ID()] = task go func() { task.run(d) d.doneCh <- task @@ -451,39 +453,46 @@ func (d *dialScheduler) startDial(task *dialTask) { type dialTask struct { staticPoolIndex int flags connFlag + // These fields are private to the task and should not be // accessed by dialScheduler while the task is running. - dest *enode.Node + destPtr atomic.Pointer[enode.Node] lastResolved mclock.AbsTime resolveDelay time.Duration } func newDialTask(dest *enode.Node, flags connFlag) *dialTask { - return &dialTask{dest: dest, flags: flags, staticPoolIndex: -1} + t := &dialTask{flags: flags, staticPoolIndex: -1} + t.destPtr.Store(dest) + return t } type dialError struct { error } +func (t *dialTask) dest() *enode.Node { + return t.destPtr.Load() +} + func (t *dialTask) run(d *dialScheduler) { if t.needResolve() && !t.resolve(d) { return } - err := t.dial(d, t.dest) + err := t.dial(d, t.dest()) if err != nil { // For static nodes, resolve one more time if dialing fails. if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 { if t.resolve(d) { - t.dial(d, t.dest) + t.dial(d, t.dest()) } } } } func (t *dialTask) needResolve() bool { - return t.flags&staticDialedConn != 0 && t.dest.IP() == nil + return t.flags&staticDialedConn != 0 && t.dest().IP() == nil } // resolve attempts to find the current endpoint for the destination @@ -502,29 +511,31 @@ func (t *dialTask) resolve(d *dialScheduler) bool { if t.lastResolved > 0 && time.Duration(d.clock.Now()-t.lastResolved) < t.resolveDelay { return false } - resolved := d.resolver.Resolve(t.dest) + + node := t.dest() + resolved := d.resolver.Resolve(node) t.lastResolved = d.clock.Now() if resolved == nil { t.resolveDelay *= 2 if t.resolveDelay > maxResolveDelay { t.resolveDelay = maxResolveDelay } - d.log.Debug("Resolving node failed", "id", t.dest.ID(), "newdelay", t.resolveDelay) + d.log.Debug("Resolving node failed", "id", node.ID(), "newdelay", t.resolveDelay) return false } // The node was found. t.resolveDelay = initialResolveDelay - t.dest = resolved - d.log.Debug("Resolved node", "id", t.dest.ID(), "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()}) + t.destPtr.Store(resolved) + d.log.Debug("Resolved node", "id", resolved.ID(), "addr", &net.TCPAddr{IP: resolved.IP(), Port: resolved.TCP()}) return true } // dial performs the actual connection attempt. func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error { dialMeter.Mark(1) - fd, err := d.dialer.Dial(d.ctx, t.dest) + fd, err := d.dialer.Dial(d.ctx, dest) if err != nil { - d.log.Trace("Dial error", "id", t.dest.ID(), "addr", nodeAddr(t.dest), "conn", t.flags, "err", cleanupDialErr(err)) + d.log.Trace("Dial error", "id", dest.ID(), "addr", nodeAddr(dest), "conn", t.flags, "err", cleanupDialErr(err)) dialConnectionError.Mark(1) return &dialError{err} } @@ -532,8 +543,9 @@ func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error { } func (t *dialTask) String() string { - id := t.dest.ID() - return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], t.dest.IP(), t.dest.TCP()) + node := t.dest() + id := node.ID() + return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], node.IP(), node.TCP()) } func cleanupDialErr(err error) error { From eff424cc302152f3914e3f9c8b49efe92e33353f Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Wed, 13 Mar 2024 07:40:02 +0100 Subject: [PATCH 060/571] eth/tracers: fix concurrency issue for JS-tracing a block (#29238) This change fixes a concurrency-issue where JS-tracers were accessing the block-ctx GetHash function in a in parallel, which is not safe. --- eth/tracers/api.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index fa8c881d1a71..0add06c8f69b 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -632,7 +632,6 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat var ( txs = block.Transactions() blockHash = block.Hash() - blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) results = make([]*txTraceResult, len(txs)) pend sync.WaitGroup @@ -655,6 +654,11 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat TxIndex: task.index, TxHash: txs[task.index].Hash(), } + // Reconstruct the block context for each transaction + // as the GetHash function of BlockContext is not safe for + // concurrent use. + // See: https://github.com/ethereum/go-ethereum/issues/29114 + blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) if err != nil { results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()} @@ -667,6 +671,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat // Feed the transactions into the tracers and return var failed error + blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) txloop: for i, tx := range txs { // Send the trace task over for execution From d5bacfa4def558a4c7b261c1a9fbfdbfc295e491 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 13 Mar 2024 07:51:46 +0100 Subject: [PATCH 061/571] crypto/kz4844: pass blobs by ref (#29050) This change makes use of the following underlying changes to the kzg-libraries in order to avoid passing large things on the stack: - c-kzg: https://github.com/ethereum/c-kzg-4844/pull/393 and - go-kzg: https://github.com/crate-crypto/go-kzg-4844/pull/63 --- cmd/devp2p/internal/ethtest/suite.go | 4 ++-- core/txpool/blobpool/blobpool_test.go | 4 ++-- core/txpool/validation.go | 2 +- core/types/tx_blob_test.go | 4 ++-- crypto/kzg4844/kzg4844.go | 8 ++++---- crypto/kzg4844/kzg4844_ckzg_cgo.go | 16 ++++++++-------- crypto/kzg4844/kzg4844_ckzg_nocgo.go | 8 ++++---- crypto/kzg4844/kzg4844_gokzg.go | 16 ++++++++-------- crypto/kzg4844/kzg4844_test.go | 4 ++-- go.mod | 4 ++-- go.sum | 8 ++++---- internal/ethapi/api_test.go | 17 +++++++++-------- internal/ethapi/transaction_args.go | 6 +++--- 13 files changed, 51 insertions(+), 50 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index d9efe2624432..b5cc27a2b590 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -754,8 +754,8 @@ func makeSidecar(data ...byte) *types.BlobTxSidecar { ) for i := range blobs { blobs[i][0] = data[i] - c, _ := kzg4844.BlobToCommitment(blobs[i]) - p, _ := kzg4844.ComputeBlobProof(blobs[i], c) + c, _ := kzg4844.BlobToCommitment(&blobs[i]) + p, _ := kzg4844.ComputeBlobProof(&blobs[i], c) commitments = append(commitments, c) proofs = append(proofs, p) } diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index bac239db4769..279750c73f2a 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -48,7 +48,7 @@ import ( ) var ( - emptyBlob = kzg4844.Blob{} + emptyBlob = new(kzg4844.Blob) emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) emptyBlobVHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) @@ -198,7 +198,7 @@ func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap BlobHashes: []common.Hash{emptyBlobVHash}, Value: uint256.NewInt(100), Sidecar: &types.BlobTxSidecar{ - Blobs: []kzg4844.Blob{emptyBlob}, + Blobs: []kzg4844.Blob{*emptyBlob}, Commitments: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}, }, diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 63f127f55ca2..d9a85a435da4 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -162,7 +162,7 @@ func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) err // Blob commitments match with the hashes in the transaction, verify the // blobs themselves via KZG for i := range sidecar.Blobs { - if err := kzg4844.VerifyBlobProof(sidecar.Blobs[i], sidecar.Commitments[i], sidecar.Proofs[i]); err != nil { + if err := kzg4844.VerifyBlobProof(&sidecar.Blobs[i], sidecar.Commitments[i], sidecar.Proofs[i]); err != nil { return fmt.Errorf("invalid blob %d: %v", i, err) } } diff --git a/core/types/tx_blob_test.go b/core/types/tx_blob_test.go index 25d09e31ce4a..6bd0f183b730 100644 --- a/core/types/tx_blob_test.go +++ b/core/types/tx_blob_test.go @@ -59,7 +59,7 @@ func TestBlobTxSize(t *testing.T) { } var ( - emptyBlob = kzg4844.Blob{} + emptyBlob = new(kzg4844.Blob) emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) ) @@ -72,7 +72,7 @@ func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction { func createEmptyBlobTxInner(withSidecar bool) *BlobTx { sidecar := &BlobTxSidecar{ - Blobs: []kzg4844.Blob{emptyBlob}, + Blobs: []kzg4844.Blob{*emptyBlob}, Commitments: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}, } diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index 168ff8347095..39fdfbe740ee 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -105,7 +105,7 @@ func UseCKZG(use bool) error { } // BlobToCommitment creates a small commitment out of a data blob. -func BlobToCommitment(blob Blob) (Commitment, error) { +func BlobToCommitment(blob *Blob) (Commitment, error) { if useCKZG.Load() { return ckzgBlobToCommitment(blob) } @@ -114,7 +114,7 @@ func BlobToCommitment(blob Blob) (Commitment, error) { // ComputeProof computes the KZG proof at the given point for the polynomial // represented by the blob. -func ComputeProof(blob Blob, point Point) (Proof, Claim, error) { +func ComputeProof(blob *Blob, point Point) (Proof, Claim, error) { if useCKZG.Load() { return ckzgComputeProof(blob, point) } @@ -134,7 +134,7 @@ func VerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) e // the commitment. // // This method does not verify that the commitment is correct with respect to blob. -func ComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { +func ComputeBlobProof(blob *Blob, commitment Commitment) (Proof, error) { if useCKZG.Load() { return ckzgComputeBlobProof(blob, commitment) } @@ -142,7 +142,7 @@ func ComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { } // VerifyBlobProof verifies that the blob data corresponds to the provided commitment. -func VerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { +func VerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { if useCKZG.Load() { return ckzgVerifyBlobProof(blob, commitment, proof) } diff --git a/crypto/kzg4844/kzg4844_ckzg_cgo.go b/crypto/kzg4844/kzg4844_ckzg_cgo.go index 54002856987c..11bc451b58a9 100644 --- a/crypto/kzg4844/kzg4844_ckzg_cgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_cgo.go @@ -61,10 +61,10 @@ func ckzgInit() { } // ckzgBlobToCommitment creates a small commitment out of a data blob. -func ckzgBlobToCommitment(blob Blob) (Commitment, error) { +func ckzgBlobToCommitment(blob *Blob) (Commitment, error) { ckzgIniter.Do(ckzgInit) - commitment, err := ckzg4844.BlobToKZGCommitment((ckzg4844.Blob)(blob)) + commitment, err := ckzg4844.BlobToKZGCommitment((*ckzg4844.Blob)(blob)) if err != nil { return Commitment{}, err } @@ -73,10 +73,10 @@ func ckzgBlobToCommitment(blob Blob) (Commitment, error) { // ckzgComputeProof computes the KZG proof at the given point for the polynomial // represented by the blob. -func ckzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { +func ckzgComputeProof(blob *Blob, point Point) (Proof, Claim, error) { ckzgIniter.Do(ckzgInit) - proof, claim, err := ckzg4844.ComputeKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes32)(point)) + proof, claim, err := ckzg4844.ComputeKZGProof((*ckzg4844.Blob)(blob), (ckzg4844.Bytes32)(point)) if err != nil { return Proof{}, Claim{}, err } @@ -102,10 +102,10 @@ func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proo // the commitment. // // This method does not verify that the commitment is correct with respect to blob. -func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { +func ckzgComputeBlobProof(blob *Blob, commitment Commitment) (Proof, error) { ckzgIniter.Do(ckzgInit) - proof, err := ckzg4844.ComputeBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment)) + proof, err := ckzg4844.ComputeBlobKZGProof((*ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment)) if err != nil { return Proof{}, err } @@ -113,10 +113,10 @@ func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { } // ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment. -func ckzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { +func ckzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { ckzgIniter.Do(ckzgInit) - valid, err := ckzg4844.VerifyBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes48)(proof)) + valid, err := ckzg4844.VerifyBlobKZGProof((*ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes48)(proof)) if err != nil { return err } diff --git a/crypto/kzg4844/kzg4844_ckzg_nocgo.go b/crypto/kzg4844/kzg4844_ckzg_nocgo.go index ed840c75bb68..70a78e80d16a 100644 --- a/crypto/kzg4844/kzg4844_ckzg_nocgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_nocgo.go @@ -32,13 +32,13 @@ func ckzgInit() { } // ckzgBlobToCommitment creates a small commitment out of a data blob. -func ckzgBlobToCommitment(blob Blob) (Commitment, error) { +func ckzgBlobToCommitment(blob *Blob) (Commitment, error) { panic("unsupported platform") } // ckzgComputeProof computes the KZG proof at the given point for the polynomial // represented by the blob. -func ckzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { +func ckzgComputeProof(blob *Blob, point Point) (Proof, Claim, error) { panic("unsupported platform") } @@ -52,11 +52,11 @@ func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proo // the commitment. // // This method does not verify that the commitment is correct with respect to blob. -func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { +func ckzgComputeBlobProof(blob *Blob, commitment Commitment) (Proof, error) { panic("unsupported platform") } // ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment. -func ckzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { +func ckzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { panic("unsupported platform") } diff --git a/crypto/kzg4844/kzg4844_gokzg.go b/crypto/kzg4844/kzg4844_gokzg.go index 3f03bb52738e..b4af9b1671e9 100644 --- a/crypto/kzg4844/kzg4844_gokzg.go +++ b/crypto/kzg4844/kzg4844_gokzg.go @@ -46,10 +46,10 @@ func gokzgInit() { } // gokzgBlobToCommitment creates a small commitment out of a data blob. -func gokzgBlobToCommitment(blob Blob) (Commitment, error) { +func gokzgBlobToCommitment(blob *Blob) (Commitment, error) { gokzgIniter.Do(gokzgInit) - commitment, err := context.BlobToKZGCommitment((gokzg4844.Blob)(blob), 0) + commitment, err := context.BlobToKZGCommitment((*gokzg4844.Blob)(blob), 0) if err != nil { return Commitment{}, err } @@ -58,10 +58,10 @@ func gokzgBlobToCommitment(blob Blob) (Commitment, error) { // gokzgComputeProof computes the KZG proof at the given point for the polynomial // represented by the blob. -func gokzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { +func gokzgComputeProof(blob *Blob, point Point) (Proof, Claim, error) { gokzgIniter.Do(gokzgInit) - proof, claim, err := context.ComputeKZGProof((gokzg4844.Blob)(blob), (gokzg4844.Scalar)(point), 0) + proof, claim, err := context.ComputeKZGProof((*gokzg4844.Blob)(blob), (gokzg4844.Scalar)(point), 0) if err != nil { return Proof{}, Claim{}, err } @@ -80,10 +80,10 @@ func gokzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Pro // the commitment. // // This method does not verify that the commitment is correct with respect to blob. -func gokzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { +func gokzgComputeBlobProof(blob *Blob, commitment Commitment) (Proof, error) { gokzgIniter.Do(gokzgInit) - proof, err := context.ComputeBlobKZGProof((gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), 0) + proof, err := context.ComputeBlobKZGProof((*gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), 0) if err != nil { return Proof{}, err } @@ -91,8 +91,8 @@ func gokzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { } // gokzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment. -func gokzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { +func gokzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { gokzgIniter.Do(gokzgInit) - return context.VerifyBlobKZGProof((gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), (gokzg4844.KZGProof)(proof)) + return context.VerifyBlobKZGProof((*gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), (gokzg4844.KZGProof)(proof)) } diff --git a/crypto/kzg4844/kzg4844_test.go b/crypto/kzg4844/kzg4844_test.go index fae8a7a76eaf..a6782d4768ad 100644 --- a/crypto/kzg4844/kzg4844_test.go +++ b/crypto/kzg4844/kzg4844_test.go @@ -36,13 +36,13 @@ func randFieldElement() [32]byte { return gokzg4844.SerializeScalar(r) } -func randBlob() Blob { +func randBlob() *Blob { var blob Blob for i := 0; i < len(blob); i += gokzg4844.SerializedScalarSize { fieldElementBytes := randFieldElement() copy(blob[i:i+gokzg4844.SerializedScalarSize], fieldElementBytes[:]) } - return blob + return &blob } func TestCKZGWithPoint(t *testing.T) { testKZGWithPoint(t, true) } diff --git a/go.mod b/go.mod index ca45364b8bf2..1e0344594ac3 100644 --- a/go.mod +++ b/go.mod @@ -16,12 +16,12 @@ require ( github.com/cockroachdb/pebble v1.1.0 github.com/consensys/gnark-crypto v0.12.1 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 - github.com/crate-crypto/go-kzg-4844 v0.7.0 + github.com/crate-crypto/go-kzg-4844 v1.0.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 - github.com/ethereum/c-kzg-4844 v0.4.0 + github.com/ethereum/c-kzg-4844 v1.0.0 github.com/fatih/color v1.13.0 github.com/ferranbt/fastssz v0.1.2 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e diff --git a/go.sum b/go.sum index 18236bf8e74d..98137d3e442e 100644 --- a/go.sum +++ b/go.sum @@ -129,8 +129,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= -github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= -github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= +github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= +github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -160,8 +160,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= -github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= +github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 3f69f861444c..5636309589df 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -1088,7 +1088,8 @@ func TestFillBlobTransaction(t *testing.T) { Config: params.MergedTestChainConfig, Alloc: types.GenesisAlloc{}, } - emptyBlob = kzg4844.Blob{} + emptyBlob = new(kzg4844.Blob) + emptyBlobs = []kzg4844.Blob{*emptyBlob} emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) emptyBlobHash common.Hash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) @@ -1171,14 +1172,14 @@ func TestFillBlobTransaction(t *testing.T) { From: &b.acc.Address, To: &to, Value: (*hexutil.Big)(big.NewInt(1)), - Blobs: []kzg4844.Blob{emptyBlob}, + Blobs: emptyBlobs, Commitments: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}, }, want: &result{ Hashes: []common.Hash{emptyBlobHash}, Sidecar: &types.BlobTxSidecar{ - Blobs: []kzg4844.Blob{emptyBlob}, + Blobs: emptyBlobs, Commitments: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}, }, @@ -1191,14 +1192,14 @@ func TestFillBlobTransaction(t *testing.T) { To: &to, Value: (*hexutil.Big)(big.NewInt(1)), BlobHashes: []common.Hash{emptyBlobHash}, - Blobs: []kzg4844.Blob{emptyBlob}, + Blobs: emptyBlobs, Commitments: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}, }, want: &result{ Hashes: []common.Hash{emptyBlobHash}, Sidecar: &types.BlobTxSidecar{ - Blobs: []kzg4844.Blob{emptyBlob}, + Blobs: emptyBlobs, Commitments: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}, }, @@ -1211,7 +1212,7 @@ func TestFillBlobTransaction(t *testing.T) { To: &to, Value: (*hexutil.Big)(big.NewInt(1)), BlobHashes: []common.Hash{{0x01, 0x22}}, - Blobs: []kzg4844.Blob{emptyBlob}, + Blobs: emptyBlobs, Commitments: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}, }, @@ -1223,12 +1224,12 @@ func TestFillBlobTransaction(t *testing.T) { From: &b.acc.Address, To: &to, Value: (*hexutil.Big)(big.NewInt(1)), - Blobs: []kzg4844.Blob{emptyBlob}, + Blobs: emptyBlobs, }, want: &result{ Hashes: []common.Hash{emptyBlobHash}, Sidecar: &types.BlobTxSidecar{ - Blobs: []kzg4844.Blob{emptyBlob}, + Blobs: emptyBlobs, Commitments: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}, }, diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index bae1c6864159..2751d5b5aae6 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -326,12 +326,12 @@ func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context, b Backend) er commitments := make([]kzg4844.Commitment, n) proofs := make([]kzg4844.Proof, n) for i, b := range args.Blobs { - c, err := kzg4844.BlobToCommitment(b) + c, err := kzg4844.BlobToCommitment(&b) if err != nil { return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err) } commitments[i] = c - p, err := kzg4844.ComputeBlobProof(b, c) + p, err := kzg4844.ComputeBlobProof(&b, c) if err != nil { return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err) } @@ -341,7 +341,7 @@ func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context, b Backend) er args.Proofs = proofs } else { for i, b := range args.Blobs { - if err := kzg4844.VerifyBlobProof(b, args.Commitments[i], args.Proofs[i]); err != nil { + if err := kzg4844.VerifyBlobProof(&b, args.Commitments[i], args.Proofs[i]); err != nil { return fmt.Errorf("failed to verify blob proof: %v", err) } } From b80643b7370075262fd6dfad7ae8aa77710e2ef1 Mon Sep 17 00:00:00 2001 From: Justin Dhillon Date: Tue, 12 Mar 2024 23:54:40 -0700 Subject: [PATCH 062/571] accounts/usbwallet, common/bitutil: fix broken links in docs (#29078) fixes some links in documentation --- accounts/usbwallet/ledger.go | 2 +- common/bitutil/bitutil.go | 2 +- common/bitutil/bitutil_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/accounts/usbwallet/ledger.go b/accounts/usbwallet/ledger.go index d0cb93e74e00..81836b3717ac 100644 --- a/accounts/usbwallet/ledger.go +++ b/accounts/usbwallet/ledger.go @@ -16,7 +16,7 @@ // This file contains the implementation for interacting with the Ledger hardware // wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo: -// https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc +// https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc package usbwallet diff --git a/common/bitutil/bitutil.go b/common/bitutil/bitutil.go index cd3e72169fc5..a18a6d18eed8 100644 --- a/common/bitutil/bitutil.go +++ b/common/bitutil/bitutil.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Adapted from: https://golang.org/src/crypto/cipher/xor.go +// Adapted from: https://go.dev/src/crypto/subtle/xor_generic.go // Package bitutil implements fast bitwise operations. package bitutil diff --git a/common/bitutil/bitutil_test.go b/common/bitutil/bitutil_test.go index 307bf731f765..12f3fe24a6c9 100644 --- a/common/bitutil/bitutil_test.go +++ b/common/bitutil/bitutil_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Adapted from: https://golang.org/src/crypto/cipher/xor_test.go +// Adapted from: https://go.dev/src/crypto/subtle/xor_test.go package bitutil From c170fa277cbf2a9faf9f35665f1ba8f34f94062a Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 13 Mar 2024 19:39:30 +0800 Subject: [PATCH 063/571] core: improve chain rewinding mechanism (#29196) * core: improve chain rewinding mechanism * core: address comment * core: periodically print progress log * core: address comments * core: fix comment * core: fix rewinding in path * core: fix beyondRoot condition * core: polish code * core: polish code * core: extend code comment * core: stop rewinding if chain is gapped or genesis is reached * core: fix broken tests --- core/blockchain.go | 238 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 183 insertions(+), 55 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 9bd7fdcd9544..ba346b010d47 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -616,6 +616,172 @@ func (bc *BlockChain) SetSafe(header *types.Header) { } } +// rewindPathHead implements the logic of rewindHead in the context of hash scheme. +func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash) (*types.Header, uint64) { + var ( + limit uint64 // The oldest block that will be searched for this rewinding + beyondRoot = root == common.Hash{} // Flag whether we're beyond the requested root (no root, always true) + pivot = rawdb.ReadLastPivotNumber(bc.db) // Associated block number of pivot point state + rootNumber uint64 // Associated block number of requested root + + start = time.Now() // Timestamp the rewinding is restarted + logged = time.Now() // Timestamp last progress log was printed + ) + // The oldest block to be searched is determined by the pivot block or a constant + // searching threshold. The rationale behind this is as follows: + // + // - Snap sync is selected if the pivot block is available. The earliest available + // state is the pivot block itself, so there is no sense in going further back. + // + // - Full sync is selected if the pivot block does not exist. The hash database + // periodically flushes the state to disk, and the used searching threshold is + // considered sufficient to find a persistent state, even for the testnet. It + // might be not enough for a chain that is nearly empty. In the worst case, + // the entire chain is reset to genesis, and snap sync is re-enabled on top, + // which is still acceptable. + if pivot != nil { + limit = *pivot + } else if head.Number.Uint64() > params.FullImmutabilityThreshold { + limit = head.Number.Uint64() - params.FullImmutabilityThreshold + } + for { + logger := log.Trace + if time.Since(logged) > time.Second*8 { + logged = time.Now() + logger = log.Info + } + logger("Block state missing, rewinding further", "number", head.Number, "hash", head.Hash(), "elapsed", common.PrettyDuration(time.Since(start))) + + // If a root threshold was requested but not yet crossed, check + if !beyondRoot && head.Root == root { + beyondRoot, rootNumber = true, head.Number.Uint64() + } + // If search limit is reached, return the genesis block as the + // new chain head. + if head.Number.Uint64() < limit { + log.Info("Rewinding limit reached, resetting to genesis", "number", head.Number, "hash", head.Hash(), "limit", limit) + return bc.genesisBlock.Header(), rootNumber + } + // If the associated state is not reachable, continue searching + // backwards until an available state is found. + if !bc.HasState(head.Root) { + // If the chain is gapped in the middle, return the genesis + // block as the new chain head. + parent := bc.GetHeader(head.ParentHash, head.Number.Uint64()-1) + if parent == nil { + log.Error("Missing block in the middle, resetting to genesis", "number", head.Number.Uint64()-1, "hash", head.ParentHash) + return bc.genesisBlock.Header(), rootNumber + } + head = parent + + // If the genesis block is reached, stop searching. + if head.Number.Uint64() == 0 { + log.Info("Genesis block reached", "number", head.Number, "hash", head.Hash()) + return head, rootNumber + } + continue // keep rewinding + } + // Once the available state is found, ensure that the requested root + // has already been crossed. If not, continue rewinding. + if beyondRoot || head.Number.Uint64() == 0 { + log.Info("Rewound to block with state", "number", head.Number, "hash", head.Hash()) + return head, rootNumber + } + log.Debug("Skipping block with threshold state", "number", head.Number, "hash", head.Hash(), "root", head.Root) + head = bc.GetHeader(head.ParentHash, head.Number.Uint64()-1) // Keep rewinding + } +} + +// rewindPathHead implements the logic of rewindHead in the context of path scheme. +func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*types.Header, uint64) { + var ( + pivot = rawdb.ReadLastPivotNumber(bc.db) // Associated block number of pivot block + rootNumber uint64 // Associated block number of requested root + + // BeyondRoot represents whether the requested root is already + // crossed. The flag value is set to true if the root is empty. + beyondRoot = root == common.Hash{} + + // noState represents if the target state requested for search + // is unavailable and impossible to be recovered. + noState = !bc.HasState(root) && !bc.stateRecoverable(root) + + start = time.Now() // Timestamp the rewinding is restarted + logged = time.Now() // Timestamp last progress log was printed + ) + // Rewind the head block tag until an available state is found. + for { + logger := log.Trace + if time.Since(logged) > time.Second*8 { + logged = time.Now() + logger = log.Info + } + logger("Block state missing, rewinding further", "number", head.Number, "hash", head.Hash(), "elapsed", common.PrettyDuration(time.Since(start))) + + // If a root threshold was requested but not yet crossed, check + if !beyondRoot && head.Root == root { + beyondRoot, rootNumber = true, head.Number.Uint64() + } + // If the root threshold hasn't been crossed but the available + // state is reached, quickly determine if the target state is + // possible to be reached or not. + if !beyondRoot && noState && bc.HasState(head.Root) { + beyondRoot = true + log.Info("Disable the search for unattainable state", "root", root) + } + // Check if the associated state is available or recoverable if + // the requested root has already been crossed. + if beyondRoot && (bc.HasState(head.Root) || bc.stateRecoverable(head.Root)) { + break + } + // If pivot block is reached, return the genesis block as the + // new chain head. Theoretically there must be a persistent + // state before or at the pivot block, prevent endless rewinding + // towards the genesis just in case. + if pivot != nil && *pivot >= head.Number.Uint64() { + log.Info("Pivot block reached, resetting to genesis", "number", head.Number, "hash", head.Hash()) + return bc.genesisBlock.Header(), rootNumber + } + // If the chain is gapped in the middle, return the genesis + // block as the new chain head + parent := bc.GetHeader(head.ParentHash, head.Number.Uint64()-1) // Keep rewinding + if parent == nil { + log.Error("Missing block in the middle, resetting to genesis", "number", head.Number.Uint64()-1, "hash", head.ParentHash) + return bc.genesisBlock.Header(), rootNumber + } + head = parent + + // If the genesis block is reached, stop searching. + if head.Number.Uint64() == 0 { + log.Info("Genesis block reached", "number", head.Number, "hash", head.Hash()) + return head, rootNumber + } + } + // Recover if the target state if it's not available yet. + if !bc.HasState(head.Root) { + if err := bc.triedb.Recover(head.Root); err != nil { + log.Crit("Failed to rollback state", "err", err) + } + } + log.Info("Rewound to block with state", "number", head.Number, "hash", head.Hash()) + return head, rootNumber +} + +// rewindHead searches the available states in the database and returns the associated +// block as the new head block. +// +// If the given root is not empty, then the rewind should attempt to pass the specified +// state root and return the associated block number as well. If the root, typically +// representing the state corresponding to snapshot disk layer, is deemed impassable, +// then block number zero is returned, indicating that snapshot recovery is disabled +// and the whole snapshot should be auto-generated in case of head mismatch. +func (bc *BlockChain) rewindHead(head *types.Header, root common.Hash) (*types.Header, uint64) { + if bc.triedb.Scheme() == rawdb.PathScheme { + return bc.rewindPathHead(head, root) + } + return bc.rewindHashHead(head, root) +} + // setHeadBeyondRoot rewinds the local chain to a new head with the extra condition // that the rewind must pass the specified state root. This method is meant to be // used when rewinding with snapshots enabled to ensure that we go back further than @@ -634,79 +800,40 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha } defer bc.chainmu.Unlock() - // Track the block number of the requested root hash - var rootNumber uint64 // (no root == always 0) - - // Retrieve the last pivot block to short circuit rollbacks beyond it and the - // current freezer limit to start nuking id underflown - pivot := rawdb.ReadLastPivotNumber(bc.db) - frozen, _ := bc.db.Ancients() + var ( + // Track the block number of the requested root hash + rootNumber uint64 // (no root == always 0) + // Retrieve the last pivot block to short circuit rollbacks beyond it + // and the current freezer limit to start nuking it's underflown. + pivot = rawdb.ReadLastPivotNumber(bc.db) + ) updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) { // Rewind the blockchain, ensuring we don't end up with a stateless head // block. Note, depth equality is permitted to allow using SetHead as a // chain reparation mechanism without deleting any data! if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.Number.Uint64() { - newHeadBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) - if newHeadBlock == nil { - log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash()) - newHeadBlock = bc.genesisBlock - } else { - // Block exists. Keep rewinding until either we find one with state - // or until we exceed the optional threshold root hash - beyondRoot := (root == common.Hash{}) // Flag whether we're beyond the requested root (no root, always true) - - for { - // If a root threshold was requested but not yet crossed, check - if root != (common.Hash{}) && !beyondRoot && newHeadBlock.Root() == root { - beyondRoot, rootNumber = true, newHeadBlock.NumberU64() - } - if !bc.HasState(newHeadBlock.Root()) && !bc.stateRecoverable(newHeadBlock.Root()) { - log.Trace("Block state missing, rewinding further", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash()) - if pivot == nil || newHeadBlock.NumberU64() > *pivot { - parent := bc.GetBlock(newHeadBlock.ParentHash(), newHeadBlock.NumberU64()-1) - if parent != nil { - newHeadBlock = parent - continue - } - log.Error("Missing block in the middle, aiming genesis", "number", newHeadBlock.NumberU64()-1, "hash", newHeadBlock.ParentHash()) - newHeadBlock = bc.genesisBlock - } else { - log.Trace("Rewind passed pivot, aiming genesis", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash(), "pivot", *pivot) - newHeadBlock = bc.genesisBlock - } - } - if beyondRoot || newHeadBlock.NumberU64() == 0 { - if !bc.HasState(newHeadBlock.Root()) && bc.stateRecoverable(newHeadBlock.Root()) { - // Rewind to a block with recoverable state. If the state is - // missing, run the state recovery here. - if err := bc.triedb.Recover(newHeadBlock.Root()); err != nil { - log.Crit("Failed to rollback state", "err", err) // Shouldn't happen - } - log.Debug("Rewound to block with state", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash()) - } - break - } - log.Debug("Skipping block with threshold state", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash(), "root", newHeadBlock.Root()) - newHeadBlock = bc.GetBlock(newHeadBlock.ParentHash(), newHeadBlock.NumberU64()-1) // Keep rewinding - } - } + var newHeadBlock *types.Header + newHeadBlock, rootNumber = bc.rewindHead(header, root) rawdb.WriteHeadBlockHash(db, newHeadBlock.Hash()) // Degrade the chain markers if they are explicitly reverted. // In theory we should update all in-memory markers in the // last step, however the direction of SetHead is from high // to low, so it's safe to update in-memory markers directly. - bc.currentBlock.Store(newHeadBlock.Header()) - headBlockGauge.Update(int64(newHeadBlock.NumberU64())) + bc.currentBlock.Store(newHeadBlock) + headBlockGauge.Update(int64(newHeadBlock.Number.Uint64())) // The head state is missing, which is only possible in the path-based // scheme. This situation occurs when the chain head is rewound below // the pivot point. In this scenario, there is no possible recovery // approach except for rerunning a snap sync. Do nothing here until the // state syncer picks it up. - if !bc.HasState(newHeadBlock.Root()) { - log.Info("Chain is stateless, wait state sync", "number", newHeadBlock.Number(), "hash", newHeadBlock.Hash()) + if !bc.HasState(newHeadBlock.Root) { + if newHeadBlock.Number.Uint64() != 0 { + log.Crit("Chain is stateless at a non-genesis block") + } + log.Info("Chain is stateless, wait state sync", "number", newHeadBlock.Number, "hash", newHeadBlock.Hash()) } } // Rewind the snap block in a simpleton way to the target head @@ -733,6 +860,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha // intent afterwards is full block importing, delete the chain segment // between the stateful-block and the sethead target. var wipe bool + frozen, _ := bc.db.Ancients() if headNumber+1 < frozen { wipe = pivot == nil || headNumber >= *pivot } From f3d18d64bf4c026740ee6c8ae8949a8c19391b49 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 13 Mar 2024 18:12:23 +0100 Subject: [PATCH 064/571] tests, appveyor: only execute one in four permutations on CI (#29220) tests, appveyor: only execute one in four permutations when flag -short is used Also enable -short flag on all appveyor builds (also ubuntu) --- appveyor.yml | 2 +- tests/block_test.go | 41 +++++++++++++++++++++++++---------------- tests/state_test.go | 23 ++++++++++++++++++----- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 4a8c4b737a2f..41c70491b4eb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,7 +26,7 @@ for: - go run build/ci.go lint - go run build/ci.go install -dlgo test_script: - - go run build/ci.go test -dlgo + - go run build/ci.go test -dlgo -short # linux/386 is disabled. - matrix: diff --git a/tests/block_test.go b/tests/block_test.go index fb355085fd8c..1ba84f5f24b6 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -18,7 +18,6 @@ package tests import ( "math/rand" - "runtime" "testing" "github.com/ethereum/go-ethereum/common" @@ -51,9 +50,6 @@ func TestBlockchain(t *testing.T) { bt.skipLoad(`.*randomStatetest94.json.*`) bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { - if runtime.GOARCH == "386" && runtime.GOOS == "windows" && rand.Int63()%2 == 0 { - t.Skip("test (randomly) skipped on 32-bit windows") - } execBlockTest(t, bt, test) }) // There is also a LegacyTests folder, containing blockchain tests generated @@ -74,20 +70,33 @@ func TestExecutionSpecBlocktests(t *testing.T) { } func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) { - if err := bt.checkFailure(t, test.Run(false, rawdb.HashScheme, nil, nil)); err != nil { - t.Errorf("test in hash mode without snapshotter failed: %v", err) - return + // If -short flag is used, we don't execute all four permutations, only one. + executionMask := 0xf + if testing.Short() { + executionMask = (1 << (rand.Int63() & 4)) + } + if executionMask&0x1 != 0 { + if err := bt.checkFailure(t, test.Run(false, rawdb.HashScheme, nil, nil)); err != nil { + t.Errorf("test in hash mode without snapshotter failed: %v", err) + return + } } - if err := bt.checkFailure(t, test.Run(true, rawdb.HashScheme, nil, nil)); err != nil { - t.Errorf("test in hash mode with snapshotter failed: %v", err) - return + if executionMask&0x2 != 0 { + if err := bt.checkFailure(t, test.Run(true, rawdb.HashScheme, nil, nil)); err != nil { + t.Errorf("test in hash mode with snapshotter failed: %v", err) + return + } } - if err := bt.checkFailure(t, test.Run(false, rawdb.PathScheme, nil, nil)); err != nil { - t.Errorf("test in path mode without snapshotter failed: %v", err) - return + if executionMask&0x4 != 0 { + if err := bt.checkFailure(t, test.Run(false, rawdb.PathScheme, nil, nil)); err != nil { + t.Errorf("test in path mode without snapshotter failed: %v", err) + return + } } - if err := bt.checkFailure(t, test.Run(true, rawdb.PathScheme, nil, nil)); err != nil { - t.Errorf("test in path mode with snapshotter failed: %v", err) - return + if executionMask&0x8 != 0 { + if err := bt.checkFailure(t, test.Run(true, rawdb.PathScheme, nil, nil)); err != nil { + t.Errorf("test in path mode with snapshotter failed: %v", err) + return + } } } diff --git a/tests/state_test.go b/tests/state_test.go index 1d749d8bcf52..6ec5c9d857bc 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -25,7 +25,6 @@ import ( "os" "path/filepath" "reflect" - "runtime" "strings" "testing" "time" @@ -99,15 +98,20 @@ func TestExecutionSpecState(t *testing.T) { } func execStateTest(t *testing.T, st *testMatcher, test *StateTest) { - if runtime.GOARCH == "386" && runtime.GOOS == "windows" && rand.Int63()%2 == 0 { - t.Skip("test (randomly) skipped on 32-bit windows") - return - } for _, subtest := range test.Subtests() { subtest := subtest key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index) + // If -short flag is used, we don't execute all four permutations, only + // one. + executionMask := 0xf + if testing.Short() { + executionMask = (1 << (rand.Int63() & 4)) + } t.Run(key+"/hash/trie", func(t *testing.T) { + if executionMask&0x1 == 0 { + t.Skip("test (randomly) skipped due to short-tag") + } withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { var result error test.Run(subtest, vmconfig, false, rawdb.HashScheme, func(err error, state *StateTestState) { @@ -117,6 +121,9 @@ func execStateTest(t *testing.T, st *testMatcher, test *StateTest) { }) }) t.Run(key+"/hash/snap", func(t *testing.T) { + if executionMask&0x2 == 0 { + t.Skip("test (randomly) skipped due to short-tag") + } withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { var result error test.Run(subtest, vmconfig, true, rawdb.HashScheme, func(err error, state *StateTestState) { @@ -132,6 +139,9 @@ func execStateTest(t *testing.T, st *testMatcher, test *StateTest) { }) }) t.Run(key+"/path/trie", func(t *testing.T) { + if executionMask&0x4 == 0 { + t.Skip("test (randomly) skipped due to short-tag") + } withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { var result error test.Run(subtest, vmconfig, false, rawdb.PathScheme, func(err error, state *StateTestState) { @@ -141,6 +151,9 @@ func execStateTest(t *testing.T, st *testMatcher, test *StateTest) { }) }) t.Run(key+"/path/snap", func(t *testing.T) { + if executionMask&0x8 == 0 { + t.Skip("test (randomly) skipped due to short-tag") + } withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { var result error test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, state *StateTestState) { From 57308beecf7040391aee6c3102587063501f6825 Mon Sep 17 00:00:00 2001 From: Bin <49082129+songzhibin97@users.noreply.github.com> Date: Thu, 14 Mar 2024 07:25:42 +0800 Subject: [PATCH 065/571] go.mod: update golang.org/x/crypto from v0.17.0 to v0.21.0 (#29228) --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 1e0344594ac3..4e481065469f 100644 --- a/go.mod +++ b/go.mod @@ -66,10 +66,10 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.25.7 go.uber.org/automaxprocs v1.5.2 - golang.org/x/crypto v0.17.0 + golang.org/x/crypto v0.21.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.5.0 - golang.org/x/sys v0.16.0 + golang.org/x/sys v0.18.0 golang.org/x/text v0.14.0 golang.org/x/time v0.3.0 golang.org/x/tools v0.15.0 @@ -141,7 +141,7 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.18.0 // indirect + golang.org/x/net v0.21.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index 98137d3e442e..b5cb268a0bda 100644 --- a/go.sum +++ b/go.sum @@ -526,8 +526,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -599,8 +599,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -682,8 +682,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= From 3c26ffeb2968907f68d41faab757dacdcb280941 Mon Sep 17 00:00:00 2001 From: Haotian <51777534+tmelhao@users.noreply.github.com> Date: Thu, 14 Mar 2024 07:26:46 +0800 Subject: [PATCH 066/571] eth/catalyst: remove error return in delayPayloadImport (#29043) Co-authored-by: tmelhao --- eth/catalyst/api.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index e5781b2c8f3e..f549f29dc62b 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -567,7 +567,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe // update after legit payload executions. parent := api.eth.BlockChain().GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { - return api.delayPayloadImport(block) + return api.delayPayloadImport(block), nil } // We have an existing parent, do some sanity checks to avoid the beacon client // triggering too early @@ -593,7 +593,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe // into the database directly will conflict with the assumptions of snap sync // that it has an empty db that it can fill itself. if api.eth.SyncMode() != downloader.FullSync { - return api.delayPayloadImport(block) + return api.delayPayloadImport(block), nil } if !api.eth.BlockChain().HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { api.remoteBlocks.put(block.Hash(), block.Header()) @@ -619,11 +619,11 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe // either via a forkchoice update or a sync extension. This method is meant to // be called by the newpayload command when the block seems to be ok, but some // prerequisite prevents it from being processed (e.g. no parent, or snap sync). -func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (engine.PayloadStatusV1, error) { +func (api *ConsensusAPI) delayPayloadImport(block *types.Block) engine.PayloadStatusV1 { // Sanity check that this block's parent is not on a previously invalidated // chain. If it is, mark the block as invalid too. if res := api.checkInvalidAncestor(block.ParentHash(), block.Hash()); res != nil { - return *res, nil + return *res } // Stash the block away for a potential forced forkchoice update to it // at a later time. @@ -635,7 +635,7 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (engine.PayloadS err := api.eth.Downloader().BeaconExtend(api.eth.SyncMode(), block.Header()) if err == nil { log.Debug("Payload accepted for sync extension", "number", block.NumberU64(), "hash", block.Hash()) - return engine.PayloadStatusV1{Status: engine.SYNCING}, nil + return engine.PayloadStatusV1{Status: engine.SYNCING} } // Either no beacon sync was started yet, or it rejected the delivered // payload as non-integratable on top of the existing sync. We'll just @@ -652,7 +652,7 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (engine.PayloadS // and cannot afford concurrent out-if-band modifications via imports. log.Warn("Ignoring payload while snap syncing", "number", block.NumberU64(), "hash", block.Hash(), "reason", err) } - return engine.PayloadStatusV1{Status: engine.SYNCING}, nil + return engine.PayloadStatusV1{Status: engine.SYNCING} } // setInvalidAncestor is a callback for the downloader to notify us if a bad block From 20d3e0ac06ef2ad2f5f6500402edc5b6f0bf5b7c Mon Sep 17 00:00:00 2001 From: Ng Wei Han <47109095+weiihann@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:32:49 +0800 Subject: [PATCH 067/571] cmd/devp2p: fix decoding of raw RLP ENR attributes (#29257) --- cmd/devp2p/enrcmd.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/devp2p/enrcmd.go b/cmd/devp2p/enrcmd.go index c5a97c8411fd..c9b692612f57 100644 --- a/cmd/devp2p/enrcmd.go +++ b/cmd/devp2p/enrcmd.go @@ -183,8 +183,8 @@ var attrFormatters = map[string]func(rlp.RawValue) (string, bool){ } func formatAttrRaw(v rlp.RawValue) (string, bool) { - s := hex.EncodeToString(v) - return s, true + content, _, err := rlp.SplitString(v) + return hex.EncodeToString(content), err == nil } func formatAttrString(v rlp.RawValue) (string, bool) { From d28adb61bf8445f9de58612155c308e5ac3b197a Mon Sep 17 00:00:00 2001 From: John Xu Date: Thu, 14 Mar 2024 21:38:11 +0800 Subject: [PATCH 068/571] cmd/emv/internal/t8ntool: fix shadowing of `excessBlobGas` (#29263) fix(t8n): unexpected `excessBlobGas` shadowed --- cmd/evm/internal/t8ntool/execution.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index cb975054c1b2..0735a05d6ac2 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -169,7 +169,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, // Calculate the BlobBaseFee var excessBlobGas uint64 if pre.Env.ExcessBlobGas != nil { - excessBlobGas := *pre.Env.ExcessBlobGas + excessBlobGas = *pre.Env.ExcessBlobGas vmContext.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) } else { // If it is not explicitly defined, but we have the parent values, we try From cffb7c8604d299ac21e0a9714205cc7b52faa501 Mon Sep 17 00:00:00 2001 From: Haotian <51777534+tmelhao@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:14:31 +0800 Subject: [PATCH 069/571] params: use the same variable name as EIP-4788 (#29195) In https://eips.ethereum.org/EIPS/eip-4788 the name `BEACON_ROOTS_ADDRESS` is used. This change makes geth use the same variable name to avoid confusion. --- core/chain_makers_test.go | 6 +++--- core/state_processor.go | 4 ++-- eth/catalyst/api_test.go | 8 ++++---- params/protocol_params.go | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index b46b898afb92..a2ec9e6507d4 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -47,8 +47,8 @@ func TestGeneratePOSChain(t *testing.T) { gspec = &Genesis{ Config: &config, Alloc: types.GenesisAlloc{ - address: {Balance: funds}, - params.BeaconRootsStorageAddress: {Balance: common.Big0, Code: asm4788}, + address: {Balance: funds}, + params.BeaconRootsAddress: {Balance: common.Big0, Code: asm4788}, }, BaseFee: big.NewInt(params.InitialBaseFee), Difficulty: common.Big1, @@ -180,7 +180,7 @@ func TestGeneratePOSChain(t *testing.T) { } state, _ := blockchain.State() idx := block.Time()%8191 + 8191 - got := state.GetState(params.BeaconRootsStorageAddress, common.BigToHash(new(big.Int).SetUint64(idx))) + got := state.GetState(params.BeaconRootsAddress, common.BigToHash(new(big.Int).SetUint64(idx))) if got != want { t.Fatalf("block %d, wrong parent beacon root in state: got %s, want %s", i, got, want) } diff --git a/core/state_processor.go b/core/state_processor.go index 9e32ab4e5696..2f18d257b91e 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -181,11 +181,11 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat GasPrice: common.Big0, GasFeeCap: common.Big0, GasTipCap: common.Big0, - To: ¶ms.BeaconRootsStorageAddress, + To: ¶ms.BeaconRootsAddress, Data: beaconRoot[:], } vmenv.Reset(NewEVMTxContext(msg), statedb) - statedb.AddAddressToAccessList(params.BeaconRootsStorageAddress) + statedb.AddAddressToAccessList(params.BeaconRootsAddress) _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) statedb.Finalise(true) } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index a88996744c04..ab1d78f90e1b 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -72,8 +72,8 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { genesis := &core.Genesis{ Config: &config, Alloc: types.GenesisAlloc{ - testAddr: {Balance: testBalance}, - params.BeaconRootsStorageAddress: {Balance: common.Big0, Code: common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500")}, + testAddr: {Balance: testBalance}, + params.BeaconRootsAddress: {Balance: common.Big0, Code: common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500")}, }, ExtraData: []byte("test genesis"), Timestamp: 9000, @@ -1650,10 +1650,10 @@ func TestParentBeaconBlockRoot(t *testing.T) { rootIdx = common.BigToHash(big.NewInt(int64((execData.ExecutionPayload.Timestamp % 98304) + 98304))) ) - if num := db.GetState(params.BeaconRootsStorageAddress, timeIdx); num != timeIdx { + if num := db.GetState(params.BeaconRootsAddress, timeIdx); num != timeIdx { t.Fatalf("incorrect number stored: want %s, got %s", timeIdx, num) } - if root := db.GetState(params.BeaconRootsStorageAddress, rootIdx); root != *blockParams.BeaconRoot { + if root := db.GetState(params.BeaconRootsAddress, rootIdx); root != *blockParams.BeaconRoot { t.Fatalf("incorrect root stored: want %s, got %s", *blockParams.BeaconRoot, root) } } diff --git a/params/protocol_params.go b/params/protocol_params.go index 7eb63e89ac61..4e01b80970f1 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -184,8 +184,8 @@ var ( MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be. DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not. - // BeaconRootsStorageAddress is the address where historical beacon roots are stored as per EIP-4788 - BeaconRootsStorageAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02") + // BeaconRootsAddress is the address where historical beacon roots are stored as per EIP-4788 + BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02") // SystemAddress is where the system-transaction is sent from as per EIP-4788 - SystemAddress common.Address = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe") + SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe") ) From 95715fdb0317dc7d6ebbec702fe78257380c95a1 Mon Sep 17 00:00:00 2001 From: shivhg Date: Fri, 15 Mar 2024 14:37:47 +0530 Subject: [PATCH 070/571] eth/downloader, graphql: fix typos (#29243) --- eth/downloader/downloader.go | 8 ++++---- graphql/graphql.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 6e7c5dcf02c8..6b26822e22b7 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -39,10 +39,10 @@ import ( ) var ( - MaxBlockFetch = 128 // Amount of blocks to be fetched per retrieval request - MaxHeaderFetch = 192 // Amount of block headers to be fetched per retrieval request - MaxSkeletonSize = 128 // Number of header fetches to need for a skeleton assembly - MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request + MaxBlockFetch = 128 // Number of blocks to be fetched per retrieval request + MaxHeaderFetch = 192 // Number of block headers to be fetched per retrieval request + MaxSkeletonSize = 128 // Number of header fetches needed for a skeleton assembly + MaxReceiptFetch = 256 // Number of transaction receipts to allow fetching per request maxQueuedHeaders = 32 * 1024 // [eth/62] Maximum number of headers to queue for import (DOS protection) maxHeadersProcess = 2048 // Number of header download results to import at once into the chain diff --git a/graphql/graphql.go b/graphql/graphql.go index bac86476b105..f7cf164d3144 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1517,7 +1517,7 @@ func (s *SyncState) TxIndexRemainingBlocks() hexutil.Uint64 { } // Syncing returns false in case the node is currently not syncing with the network. It can be up-to-date or has not -// yet received the latest block headers from its pears. In case it is synchronizing: +// yet received the latest block headers from its peers. In case it is synchronizing: // - startingBlock: block number this node started to synchronize from // - currentBlock: block number this node is currently importing // - highestBlock: block number of the highest block header this node has received from peers From 40cac1d0e2cb37e769c3928cc477efb41124bb60 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 15 Mar 2024 10:44:41 +0100 Subject: [PATCH 071/571] eth/catalyst: prettier output on bad new payloads (#29259) When we receive a bad NewPayload, we currently emit a lot of data to the logging facilities. This PR makes it so we print less data. --- common/types.go | 11 +++++++++++ eth/catalyst/api.go | 29 ++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/common/types.go b/common/types.go index aadca87f82af..b914787d1347 100644 --- a/common/types.go +++ b/common/types.go @@ -475,3 +475,14 @@ func (d *Decimal) UnmarshalJSON(input []byte) error { return err } } + +type PrettyBytes []byte + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (b PrettyBytes) TerminalString() string { + if len(b) < 7 { + return fmt.Sprintf("%x", b) + } + return fmt.Sprintf("%#x...%x (%dB)", b[:3], b[len(b)-3:], len(b)) +} diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index f549f29dc62b..d154d794be1d 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -20,6 +20,7 @@ package catalyst import ( "errors" "fmt" + "strconv" "sync" "time" @@ -540,7 +541,33 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash) block, err := engine.ExecutableDataToBlock(params, versionedHashes, beaconRoot) if err != nil { - log.Warn("Invalid NewPayload params", "params", params, "error", err) + bgu := "nil" + if params.BlobGasUsed != nil { + bgu = strconv.Itoa(int(*params.BlobGasUsed)) + } + ebg := "nil" + if params.BlobGasUsed != nil { + ebg = strconv.Itoa(int(*params.ExcessBlobGas)) + } + log.Warn("Invalid NewPayload params", + "params.Number", params.Number, + "params.ParentHash", params.ParentHash, + "params.BlockHash", params.BlockHash, + "params.StateRoot", params.StateRoot, + "params.FeeRecipient", params.FeeRecipient, + "params.LogsBloom", common.PrettyBytes(params.LogsBloom), + "params.Random", params.Random, + "params.GasLimit", params.GasLimit, + "params.GasUsed", params.GasUsed, + "params.Timestamp", params.Timestamp, + "params.ExtraData", common.PrettyBytes(params.ExtraData), + "params.BaseFeePerGas", params.BaseFeePerGas, + "params.BlobGasUsed", bgu, + "params.ExcessBlobGas", ebg, + "len(params.Transactions)", len(params.Transactions), + "len(params.Withdrawals)", len(params.Withdrawals), + "beaconRoot", beaconRoot, + "error", err) return api.invalid(err, nil), nil } // Stash away the last update to warn the user if the beacon client goes offline From ba2dd9385c2a51134e520083dc732787a813b107 Mon Sep 17 00:00:00 2001 From: SanYe Date: Fri, 15 Mar 2024 17:46:22 +0800 Subject: [PATCH 072/571] accounts/abi/bind: remove unused err set and check (#29269) accounts/abi: remove unused err set and check --- accounts/abi/bind/base.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 96d284cdcc0c..c8972a9dff2a 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -461,7 +461,7 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int if err != nil { return nil, nil, err } - sub, err := event.NewSubscription(func(quit <-chan struct{}) error { + sub := event.NewSubscription(func(quit <-chan struct{}) error { for _, log := range buff { select { case logs <- log: @@ -470,11 +470,8 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int } } return nil - }), nil + }) - if err != nil { - return nil, nil, err - } return logs, sub, nil } From c6119247271220ce89e76e1b1b2eaeaaa8fbd9d1 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 18 Mar 2024 08:13:55 +0100 Subject: [PATCH 073/571] go.mod: update protobuf (#29270) --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 4e481065469f..cf5cd37abfe9 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.5.0 - github.com/golang/protobuf v1.5.3 + github.com/golang/protobuf v1.5.4 github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/google/gofuzz v1.2.0 github.com/google/uuid v1.3.0 @@ -142,7 +142,7 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.21.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index b5cb268a0bda..7685b64a552c 100644 --- a/go.sum +++ b/go.sum @@ -239,8 +239,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= @@ -830,8 +830,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From ab49f228ad6f37ba78be66b34aa5fee740245f57 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 18 Mar 2024 17:36:50 +0100 Subject: [PATCH 074/571] all: update to go version 1.22.1 (#28946) Since Go 1.22 has deprecated certain elliptic curve operations, this PR removes references to the affected functions and replaces them with a custom implementation in package crypto. This causes backwards-incompatible changes in some places. --------- Co-authored-by: Marius van der Wijden Co-authored-by: Felix Lange --- .travis.yml | 20 +++++------ Dockerfile | 2 +- Dockerfile.alltools | 2 +- README.md | 2 +- accounts/scwallet/securechannel.go | 5 ++- build/checksums.txt | 30 ++++++++-------- crypto/crypto.go | 15 ++++++-- crypto/ecies/ecies.go | 56 +++++++++++++++++------------- crypto/secp256k1/secp256_test.go | 3 +- crypto/signature_cgo.go | 7 ++-- crypto/signature_nocgo.go | 56 ++++++++++++++++++++++++++---- go.mod | 2 +- go.sum | 15 ++++++++ p2p/rlpx/rlpx.go | 6 ++-- 14 files changed, 147 insertions(+), 74 deletions(-) diff --git a/.travis.yml b/.travis.yml index a55583a703fe..8c0af291a3df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ jobs: os: linux arch: amd64 dist: bionic - go: 1.21.x + go: 1.22.x env: - docker services: @@ -33,7 +33,7 @@ jobs: os: linux arch: arm64 dist: bionic - go: 1.21.x + go: 1.22.x env: - docker services: @@ -51,7 +51,7 @@ jobs: os: linux dist: bionic sudo: required - go: 1.21.x + go: 1.22.x env: - azure-linux git: @@ -85,7 +85,7 @@ jobs: if: type = push os: osx osx_image: xcode14.2 - go: 1.21.x + go: 1.22.x env: - azure-osx git: @@ -101,7 +101,7 @@ jobs: os: linux arch: amd64 dist: bionic - go: 1.21.x + go: 1.22.x script: - travis_wait 30 go run build/ci.go test $TEST_PACKAGES @@ -110,14 +110,14 @@ jobs: os: linux arch: arm64 dist: bionic - go: 1.20.x + go: 1.21.x script: - travis_wait 30 go run build/ci.go test $TEST_PACKAGES - stage: build os: linux dist: bionic - go: 1.20.x + go: 1.21.x script: - travis_wait 30 go run build/ci.go test $TEST_PACKAGES @@ -126,7 +126,7 @@ jobs: if: type = cron || (type = push && tag ~= /^v[0-9]/) os: linux dist: bionic - go: 1.21.x + go: 1.22.x env: - ubuntu-ppa git: @@ -149,7 +149,7 @@ jobs: if: type = cron os: linux dist: bionic - go: 1.21.x + go: 1.22.x env: - azure-purge git: @@ -162,7 +162,7 @@ jobs: if: type = cron os: linux dist: bionic - go: 1.21.x + go: 1.22.x script: - travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES diff --git a/Dockerfile b/Dockerfile index ed69a0478967..ffd89905a704 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.21-alpine as builder +FROM golang:1.22-alpine as builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/Dockerfile.alltools b/Dockerfile.alltools index c317da25fa48..db256f531620 100644 --- a/Dockerfile.alltools +++ b/Dockerfile.alltools @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.21-alpine as builder +FROM golang:1.22-alpine as builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/README.md b/README.md index 1e8dba809094..0d5b7872124a 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ archives are published at https://geth.ethereum.org/downloads/. For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth). -Building `geth` requires both a Go (version 1.19 or later) and a C compiler. You can install +Building `geth` requires both a Go (version 1.21 or later) and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run ```shell diff --git a/accounts/scwallet/securechannel.go b/accounts/scwallet/securechannel.go index bbd8b2264796..b3a7be8df0bd 100644 --- a/accounts/scwallet/securechannel.go +++ b/accounts/scwallet/securechannel.go @@ -20,7 +20,6 @@ import ( "bytes" "crypto/aes" "crypto/cipher" - "crypto/elliptic" "crypto/rand" "crypto/sha256" "crypto/sha512" @@ -72,11 +71,11 @@ func NewSecureChannelSession(card *pcsc.Card, keyData []byte) (*SecureChannelSes if err != nil { return nil, fmt.Errorf("could not unmarshal public key from card: %v", err) } - secret, _ := key.Curve.ScalarMult(cardPublic.X, cardPublic.Y, key.D.Bytes()) + secret, _ := crypto.S256().ScalarMult(cardPublic.X, cardPublic.Y, key.D.Bytes()) return &SecureChannelSession{ card: card, secret: secret.Bytes(), - publicKey: elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y), + publicKey: crypto.FromECDSAPub(&key.PublicKey), }, nil } diff --git a/build/checksums.txt b/build/checksums.txt index 03a53946dfe0..f92f739a2fa4 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,22 +5,22 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.21.6 +# version:golang 1.22.1 # https://go.dev/dl/ -124926a62e45f78daabbaedb9c011d97633186a33c238ffc1e25320c02046248 go1.21.6.src.tar.gz -31d6ecca09010ab351e51343a5af81d678902061fee871f912bdd5ef4d778850 go1.21.6.darwin-amd64.tar.gz -0ff541fb37c38e5e5c5bcecc8f4f43c5ffd5e3a6c33a5d3e4003ded66fcfb331 go1.21.6.darwin-arm64.tar.gz -a1d1a149b34bf0f53965a237682c6da1140acabb131bf0e597240e4a140b0e5e go1.21.6.freebsd-386.tar.gz -de59e1217e4398b1522eed8dddabab2fa1b97aecbdca3af08e34832b4f0e3f81 go1.21.6.freebsd-amd64.tar.gz -05d09041b5a1193c14e4b2db3f7fcc649b236c567f5eb93305c537851b72dd95 go1.21.6.linux-386.tar.gz -3f934f40ac360b9c01f616a9aa1796d227d8b0328bf64cb045c7b8c4ee9caea4 go1.21.6.linux-amd64.tar.gz -e2e8aa88e1b5170a0d495d7d9c766af2b2b6c6925a8f8956d834ad6b4cacbd9a go1.21.6.linux-arm64.tar.gz -6a8eda6cc6a799ff25e74ce0c13fdc1a76c0983a0bb07c789a2a3454bf6ec9b2 go1.21.6.linux-armv6l.tar.gz -e872b1e9a3f2f08fd4554615a32ca9123a4ba877ab6d19d36abc3424f86bc07f go1.21.6.linux-ppc64le.tar.gz -92894d0f732d3379bc414ffdd617eaadad47e1d72610e10d69a1156db03fc052 go1.21.6.linux-s390x.tar.gz -65b38857135cf45c80e1d267e0ce4f80fe149326c68835217da4f2da9b7943fe go1.21.6.windows-386.zip -27ac9dd6e66fb3fd0acfa6792ff053c86e7d2c055b022f4b5d53bfddec9e3301 go1.21.6.windows-amd64.zip -b93aff8f3c882c764c66a39b7a1483b0460e051e9992bf3435479129e5051bcd go1.21.6.windows-arm64.zip +79c9b91d7f109515a25fc3ecdaad125d67e6bdb54f6d4d98580f46799caea321 go1.22.1.src.tar.gz +3bc971772f4712fec0364f4bc3de06af22a00a12daab10b6f717fdcd13156cc0 go1.22.1.darwin-amd64.tar.gz +f6a9cec6b8a002fcc9c0ee24ec04d67f430a52abc3cfd613836986bcc00d8383 go1.22.1.darwin-arm64.tar.gz +99f81c10d5a3f8a886faf8fa86aaa2aaf929fbed54a972ae5eec3c5e0bdb961a go1.22.1.freebsd-386.tar.gz +51c614ddd92ee4a9913a14c39bf80508d9cfba08561f24d2f075fd00f3cfb067 go1.22.1.freebsd-amd64.tar.gz +8484df36d3d40139eaf0fe5e647b006435d826cc12f9ae72973bf7ec265e0ae4 go1.22.1.linux-386.tar.gz +aab8e15785c997ae20f9c88422ee35d962c4562212bb0f879d052a35c8307c7f go1.22.1.linux-amd64.tar.gz +e56685a245b6a0c592fc4a55f0b7803af5b3f827aaa29feab1f40e491acf35b8 go1.22.1.linux-arm64.tar.gz +8cb7a90e48c20daed39a6ac8b8a40760030ba5e93c12274c42191d868687c281 go1.22.1.linux-armv6l.tar.gz +ac775e19d93cc1668999b77cfe8c8964abfbc658718feccfe6e0eb87663cd668 go1.22.1.linux-ppc64le.tar.gz +7bb7dd8e10f95c9a4cc4f6bef44c816a6e7c9e03f56ac6af6efbb082b19b379f go1.22.1.linux-s390x.tar.gz +0c5ebb7eb39b7884ec99f92b425d4c03a96a72443562aafbf6e7d15c42a3108a go1.22.1.windows-386.zip +cf9c66a208a106402a527f5b956269ca506cfe535fc388e828d249ea88ed28ba go1.22.1.windows-amd64.zip +85b8511b298c9f4199ecae26afafcc3d46155bac934d43f2357b9224bcaa310f go1.22.1.windows-arm64.zip # version:golangci 1.55.2 # https://github.com/golangci/golangci-lint/releases/ diff --git a/crypto/crypto.go b/crypto/crypto.go index 2492165d388c..734feed5cac3 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -51,6 +51,15 @@ var ( var errInvalidPubkey = errors.New("invalid secp256k1 public key") +// EllipticCurve contains curve operations. +type EllipticCurve interface { + elliptic.Curve + + // Point marshaling/unmarshaing. + Marshal(x, y *big.Int) []byte + Unmarshal(data []byte) (x, y *big.Int) +} + // KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports // Read to get a variable amount of data from the hash state. Read is faster than Sum // because it doesn't copy the internal state, but also modifies the internal state. @@ -148,7 +157,7 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) { return nil, errors.New("invalid private key, zero or negative") } - priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d) + priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(d) if priv.PublicKey.X == nil { return nil, errors.New("invalid private key") } @@ -165,7 +174,7 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte { // UnmarshalPubkey converts bytes to a secp256k1 public key. func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) { - x, y := elliptic.Unmarshal(S256(), pub) + x, y := S256().Unmarshal(pub) if x == nil { return nil, errInvalidPubkey } @@ -176,7 +185,7 @@ func FromECDSAPub(pub *ecdsa.PublicKey) []byte { if pub == nil || pub.X == nil || pub.Y == nil { return nil } - return elliptic.Marshal(S256(), pub.X, pub.Y) + return S256().Marshal(pub.X, pub.Y) } // HexToECDSA parses a secp256k1 private key. diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 738bb8f584aa..1b6c9e97c121 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -40,6 +40,8 @@ import ( "hash" "io" "math/big" + + "github.com/ethereum/go-ethereum/crypto" ) var ( @@ -95,15 +97,15 @@ func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { // Generate an elliptic curve public / private keypair. If params is nil, // the recommended default parameters for the key will be chosen. func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { - pb, x, y, err := elliptic.GenerateKey(curve, rand) + sk, err := ecdsa.GenerateKey(curve, rand) if err != nil { return } prv = new(PrivateKey) - prv.PublicKey.X = x - prv.PublicKey.Y = y + prv.PublicKey.X = sk.X + prv.PublicKey.Y = sk.Y prv.PublicKey.Curve = curve - prv.D = new(big.Int).SetBytes(pb) + prv.D = new(big.Int).Set(sk.D) if params == nil { params = ParamsFromCurve(curve) } @@ -255,12 +257,15 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e d := messageTag(params.Hash, Km, em, s2) - Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y) - ct = make([]byte, len(Rb)+len(em)+len(d)) - copy(ct, Rb) - copy(ct[len(Rb):], em) - copy(ct[len(Rb)+len(em):], d) - return ct, nil + if curve, ok := pub.Curve.(crypto.EllipticCurve); ok { + Rb := curve.Marshal(R.PublicKey.X, R.PublicKey.Y) + ct = make([]byte, len(Rb)+len(em)+len(d)) + copy(ct, Rb) + copy(ct[len(Rb):], em) + copy(ct[len(Rb)+len(em):], d) + return ct, nil + } + return nil, ErrInvalidCurve } // Decrypt decrypts an ECIES ciphertext. @@ -297,21 +302,24 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { R := new(PublicKey) R.Curve = prv.PublicKey.Curve - R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen]) - if R.X == nil { - return nil, ErrInvalidPublicKey - } - z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen) - if err != nil { - return nil, err - } - Ke, Km := deriveKeys(hash, z, s1, params.KeyLen) + if curve, ok := R.Curve.(crypto.EllipticCurve); ok { + R.X, R.Y = curve.Unmarshal(c[:rLen]) + if R.X == nil { + return nil, ErrInvalidPublicKey + } - d := messageTag(params.Hash, Km, c[mStart:mEnd], s2) - if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 { - return nil, ErrInvalidMessage - } + z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen) + if err != nil { + return nil, err + } + Ke, Km := deriveKeys(hash, z, s1, params.KeyLen) - return symDecrypt(params, Ke, c[mStart:mEnd]) + d := messageTag(params.Hash, Km, c[mStart:mEnd], s2) + if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 { + return nil, ErrInvalidMessage + } + return symDecrypt(params, Ke, c[mStart:mEnd]) + } + return nil, ErrInvalidCurve } diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index 74408d06d2bf..8bb870fa18bc 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -10,7 +10,6 @@ package secp256k1 import ( "bytes" "crypto/ecdsa" - "crypto/elliptic" "crypto/rand" "encoding/hex" "io" @@ -24,7 +23,7 @@ func generateKeyPair() (pubkey, privkey []byte) { if err != nil { panic(err) } - pubkey = elliptic.Marshal(S256(), key.X, key.Y) + pubkey = S256().Marshal(key.X, key.Y) privkey = make([]byte, 32) blob := key.D.Bytes() diff --git a/crypto/signature_cgo.go b/crypto/signature_cgo.go index 2339e5201547..87289253c0ff 100644 --- a/crypto/signature_cgo.go +++ b/crypto/signature_cgo.go @@ -21,7 +21,6 @@ package crypto import ( "crypto/ecdsa" - "crypto/elliptic" "errors" "fmt" @@ -40,9 +39,7 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { if err != nil { return nil, err } - - x, y := elliptic.Unmarshal(S256(), s) - return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil + return UnmarshalPubkey(s) } // Sign calculates an ECDSA signature. @@ -84,6 +81,6 @@ func CompressPubkey(pubkey *ecdsa.PublicKey) []byte { } // S256 returns an instance of the secp256k1 curve. -func S256() elliptic.Curve { +func S256() EllipticCurve { return secp256k1.S256() } diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index 6d628d758d93..f70617019eb7 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -21,9 +21,9 @@ package crypto import ( "crypto/ecdsa" - "crypto/elliptic" "errors" "fmt" + "math/big" "github.com/btcsuite/btcd/btcec/v2" btc_ecdsa "github.com/btcsuite/btcd/btcec/v2/ecdsa" @@ -58,7 +58,13 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { if err != nil { return nil, err } - return pub.ToECDSA(), nil + // We need to explicitly set the curve here, because we're wrapping + // the original curve to add (un-)marshalling + return &ecdsa.PublicKey{ + Curve: S256(), + X: pub.X(), + Y: pub.Y(), + }, nil } // Sign calculates an ECDSA signature. @@ -73,7 +79,7 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { if len(hash) != 32 { return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash)) } - if prv.Curve != btcec.S256() { + if prv.Curve != S256() { return nil, errors.New("private key curve is not secp256k1") } // ecdsa.PrivateKey -> btcec.PrivateKey @@ -128,7 +134,13 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) { if err != nil { return nil, err } - return key.ToECDSA(), nil + // We need to explicitly set the curve here, because we're wrapping + // the original curve to add (un-)marshalling + return &ecdsa.PublicKey{ + Curve: S256(), + X: key.X(), + Y: key.Y(), + }, nil } // CompressPubkey encodes a public key to the 33-byte compressed format. The @@ -147,6 +159,38 @@ func CompressPubkey(pubkey *ecdsa.PublicKey) []byte { } // S256 returns an instance of the secp256k1 curve. -func S256() elliptic.Curve { - return btcec.S256() +func S256() EllipticCurve { + return btCurve{btcec.S256()} +} + +type btCurve struct { + *btcec.KoblitzCurve +} + +// Marshall converts a point given as (x, y) into a byte slice. +func (curve btCurve) Marshal(x, y *big.Int) []byte { + byteLen := (curve.Params().BitSize + 7) / 8 + + ret := make([]byte, 1+2*byteLen) + ret[0] = 4 // uncompressed point + + x.FillBytes(ret[1 : 1+byteLen]) + y.FillBytes(ret[1+byteLen : 1+2*byteLen]) + + return ret +} + +// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On +// error, x = nil. +func (curve btCurve) Unmarshal(data []byte) (x, y *big.Int) { + byteLen := (curve.Params().BitSize + 7) / 8 + if len(data) != 1+2*byteLen { + return nil, nil + } + if data[0] != 4 { // uncompressed form + return nil, nil + } + x = new(big.Int).SetBytes(data[1 : 1+byteLen]) + y = new(big.Int).SetBytes(data[1+byteLen:]) + return } diff --git a/go.mod b/go.mod index cf5cd37abfe9..49bce7c1ae85 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ethereum/go-ethereum -go 1.20 +go 1.21 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 diff --git a/go.sum b/go.sum index 7685b64a552c..70aa4cdb607b 100644 --- a/go.sum +++ b/go.sum @@ -34,14 +34,18 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 h1:Ma67P/GGprNwsslzEH6+Kb8nybI8jpDTm4Wmzu2ReK8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 h1:gggzg0SUMs6SQbEw+3LoSsYf9YMjkupeAnHMX8O9mmY= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgxoBDMqMO/Nvy7bZ9a0nbU3I1DtFQK3YvB4= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= @@ -93,6 +97,7 @@ github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6 github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= @@ -111,6 +116,7 @@ github.com/cloudflare/cloudflare-go v0.79.0 h1:ErwCYDjFCYppDJlDJ/5WhsSmzegAUe2+K github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= @@ -149,6 +155,7 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 h1:C7t6eeMaEQVy6e8CarIhscYQlNmw5e3G36y7l7Y21Ao= github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0/go.mod h1:56wL82FO0bfMU5RvfXoIwSOP2ggqqxT+tAfNEIyxuHw= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= @@ -186,6 +193,7 @@ github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnR github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -260,6 +268,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -293,6 +302,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -361,6 +371,7 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= @@ -421,7 +432,9 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -430,6 +443,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -462,6 +476,7 @@ github.com/protolambda/zrnt v0.30.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY= github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU= github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw= +github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/p2p/rlpx/rlpx.go b/p2p/rlpx/rlpx.go index 8bd6f64b9bd3..a338490e62b3 100644 --- a/p2p/rlpx/rlpx.go +++ b/p2p/rlpx/rlpx.go @@ -22,7 +22,6 @@ import ( "crypto/aes" "crypto/cipher" "crypto/ecdsa" - "crypto/elliptic" "crypto/hmac" "crypto/rand" "encoding/binary" @@ -664,7 +663,10 @@ func exportPubkey(pub *ecies.PublicKey) []byte { if pub == nil { panic("nil pubkey") } - return elliptic.Marshal(pub.Curve, pub.X, pub.Y)[1:] + if curve, ok := pub.Curve.(crypto.EllipticCurve); ok { + return curve.Marshal(pub.X, pub.Y)[1:] + } + return []byte{} } func xor(one, other []byte) (xor []byte) { From 15eb9773f9b99c29f3cd17be4e4bbd1bf1b48bb7 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 19 Mar 2024 10:50:08 +0800 Subject: [PATCH 075/571] triedb/pathdb: improve tests (#29278) --- eth/protocols/snap/sync_test.go | 6 +- .../utils.go => internal/testrand/rand.go | 28 +++---- trie/stacktrie_test.go | 8 +- triedb/pathdb/database.go | 8 +- triedb/pathdb/database_test.go | 73 +++++++++++++++---- triedb/pathdb/difflayer_test.go | 18 +++-- triedb/pathdb/history_test.go | 12 +-- triedb/pathdb/testutils.go | 7 +- 8 files changed, 104 insertions(+), 56 deletions(-) rename trie/testutil/utils.go => internal/testrand/rand.go (61%) diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index cea83aa2bc8e..87e186633b58 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -32,10 +32,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/testutil" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/pathdb" @@ -1816,8 +1816,8 @@ func makeUnevenStorageTrie(owner common.Hash, slots int, db *triedb.Database) (c break } for j := 0; j < slots/3; j++ { - key := append([]byte{byte(n)}, testutil.RandBytes(31)...) - val, _ := rlp.EncodeToBytes(testutil.RandBytes(32)) + key := append([]byte{byte(n)}, testrand.Bytes(31)...) + val, _ := rlp.EncodeToBytes(testrand.Bytes(32)) elem := &kv{key, val} tr.MustUpdate(elem.k, elem.v) diff --git a/trie/testutil/utils.go b/internal/testrand/rand.go similarity index 61% rename from trie/testutil/utils.go rename to internal/testrand/rand.go index a75d0431b0f4..690993de05b9 100644 --- a/trie/testutil/utils.go +++ b/internal/testrand/rand.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 . -package testutil +package testrand import ( crand "crypto/rand" @@ -22,11 +22,9 @@ import ( mrand "math/rand" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/trie/trienode" ) -// Prng is a pseudo random number generator seeded by strong randomness. +// prng is a pseudo random number generator seeded by strong randomness. // The randomness is printed on startup in order to make failures reproducible. var prng = initRand() @@ -37,25 +35,19 @@ func initRand() *mrand.Rand { return rnd } -// RandBytes generates a random byte slice with specified length. -func RandBytes(n int) []byte { +// Bytes generates a random byte slice with specified length. +func Bytes(n int) []byte { r := make([]byte, n) prng.Read(r) return r } -// RandomHash generates a random blob of data and returns it as a hash. -func RandomHash() common.Hash { - return common.BytesToHash(RandBytes(common.HashLength)) +// Hash generates a random hash. +func Hash() common.Hash { + return common.BytesToHash(Bytes(common.HashLength)) } -// RandomAddress generates a random blob of data and returns it as an address. -func RandomAddress() common.Address { - return common.BytesToAddress(RandBytes(common.AddressLength)) -} - -// RandomNode generates a random node. -func RandomNode() *trienode.Node { - val := RandBytes(100) - return trienode.New(crypto.Keccak256Hash(val), val) +// Address generates a random address. +func Address() common.Address { + return common.BytesToAddress(Bytes(common.AddressLength)) } diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index 3a0e1cb26072..203ebd99a9ea 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -25,7 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/trie/testutil" + "github.com/ethereum/go-ethereum/internal/testrand" "github.com/stretchr/testify/assert" "golang.org/x/exp/slices" ) @@ -431,12 +431,12 @@ func TestPartialStackTrie(t *testing.T) { for i := 0; i < n; i++ { var val []byte if rand.Intn(3) == 0 { - val = testutil.RandBytes(3) + val = testrand.Bytes(3) } else { - val = testutil.RandBytes(32) + val = testrand.Bytes(32) } entries = append(entries, &kv{ - k: testutil.RandBytes(32), + k: testrand.Bytes(32), v: val, }) } diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index b1e01abac4d6..7bdb6132bb57 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -34,9 +34,6 @@ import ( ) const ( - // maxDiffLayers is the maximum diff layers allowed in the layer tree. - maxDiffLayers = 128 - // defaultCleanSize is the default memory allowance of clean cache. defaultCleanSize = 16 * 1024 * 1024 @@ -54,6 +51,11 @@ const ( DefaultBufferSize = 64 * 1024 * 1024 ) +var ( + // maxDiffLayers is the maximum diff layers allowed in the layer tree. + maxDiffLayers = 128 +) + // layer is the interface implemented by all state layers which includes some // public methods and some additional methods for internal usage. type layer interface { diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 2e7e1bef05ff..a41cf4268aac 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -27,8 +27,8 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie/testutil" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" "github.com/holiman/uint256" @@ -46,7 +46,10 @@ func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[comm h.Update(key.Bytes(), val) } } - root, nodes, _ := h.Commit(false) + root, nodes, err := h.Commit(false) + if err != nil { + panic(fmt.Errorf("failed to commit hasher, err: %w", err)) + } return root, nodes } @@ -54,7 +57,7 @@ func generateAccount(storageRoot common.Hash) types.StateAccount { return types.StateAccount{ Nonce: uint64(rand.Intn(100)), Balance: uint256.NewInt(rand.Uint64()), - CodeHash: testutil.RandBytes(32), + CodeHash: testrand.Bytes(32), Root: storageRoot, } } @@ -101,8 +104,8 @@ func newTester(t *testing.T, historyLimit uint64) *tester { disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) db = New(disk, &Config{ StateHistory: historyLimit, - CleanCacheSize: 256 * 1024, - DirtyCacheSize: 256 * 1024, + CleanCacheSize: 16 * 1024, + DirtyCacheSize: 16 * 1024, }) obj = &tester{ db: db, @@ -113,7 +116,7 @@ func newTester(t *testing.T, historyLimit uint64) *tester { snapStorages: make(map[common.Hash]map[common.Hash]map[common.Hash][]byte), } ) - for i := 0; i < 2*128; i++ { + for i := 0; i < 8; i++ { var parent = types.EmptyRootHash if len(obj.roots) != 0 { parent = obj.roots[len(obj.roots)-1] @@ -146,8 +149,8 @@ func (t *tester) generateStorage(ctx *genctx, addr common.Address) common.Hash { origin = make(map[common.Hash][]byte) ) for i := 0; i < 10; i++ { - v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testutil.RandBytes(32))) - hash := testutil.RandomHash() + v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testrand.Bytes(32))) + hash := testrand.Hash() storage[hash] = v origin[hash] = nil @@ -175,8 +178,8 @@ func (t *tester) mutateStorage(ctx *genctx, addr common.Address, root common.Has } } for i := 0; i < 3; i++ { - v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testutil.RandBytes(32))) - hash := testutil.RandomHash() + v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testrand.Bytes(32))) + hash := testrand.Hash() storage[hash] = v origin[hash] = nil @@ -218,7 +221,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode switch rand.Intn(opLen) { case createAccountOp: // account creation - addr := testutil.RandomAddress() + addr := testrand.Address() addrHash := crypto.Keccak256Hash(addr.Bytes()) if _, ok := t.accounts[addrHash]; ok { continue @@ -320,14 +323,16 @@ func (t *tester) verifyState(root common.Hash) error { return errors.New("root node is not available") } for addrHash, account := range t.snapAccounts[root] { - blob, err := reader.Node(common.Hash{}, addrHash.Bytes(), crypto.Keccak256Hash(account)) + path := crypto.Keccak256(addrHash.Bytes()) + blob, err := reader.Node(common.Hash{}, path, crypto.Keccak256Hash(account)) if err != nil || !bytes.Equal(blob, account) { return fmt.Errorf("account is mismatched: %w", err) } } for addrHash, slots := range t.snapStorages[root] { for hash, slot := range slots { - blob, err := reader.Node(addrHash, hash.Bytes(), crypto.Keccak256Hash(slot)) + path := crypto.Keccak256(hash.Bytes()) + blob, err := reader.Node(addrHash, path, crypto.Keccak256Hash(slot)) if err != nil || !bytes.Equal(blob, slot) { return fmt.Errorf("slot is mismatched: %w", err) } @@ -379,6 +384,12 @@ func (t *tester) bottomIndex() int { } func TestDatabaseRollback(t *testing.T) { + // Redefine the diff layer depth allowance for faster testing. + maxDiffLayers = 4 + defer func() { + maxDiffLayers = 128 + }() + // Verify state histories tester := newTester(t, 0) defer tester.release() @@ -409,6 +420,12 @@ func TestDatabaseRollback(t *testing.T) { } func TestDatabaseRecoverable(t *testing.T) { + // Redefine the diff layer depth allowance for faster testing. + maxDiffLayers = 4 + defer func() { + maxDiffLayers = 128 + }() + var ( tester = newTester(t, 0) index = tester.bottomIndex() @@ -448,6 +465,12 @@ func TestDatabaseRecoverable(t *testing.T) { } func TestDisable(t *testing.T) { + // Redefine the diff layer depth allowance for faster testing. + maxDiffLayers = 4 + defer func() { + maxDiffLayers = 128 + }() + tester := newTester(t, 0) defer tester.release() @@ -484,6 +507,12 @@ func TestDisable(t *testing.T) { } func TestCommit(t *testing.T) { + // Redefine the diff layer depth allowance for faster testing. + maxDiffLayers = 4 + defer func() { + maxDiffLayers = 128 + }() + tester := newTester(t, 0) defer tester.release() @@ -508,6 +537,12 @@ func TestCommit(t *testing.T) { } func TestJournal(t *testing.T) { + // Redefine the diff layer depth allowance for faster testing. + maxDiffLayers = 4 + defer func() { + maxDiffLayers = 128 + }() + tester := newTester(t, 0) defer tester.release() @@ -532,6 +567,12 @@ func TestJournal(t *testing.T) { } func TestCorruptedJournal(t *testing.T) { + // Redefine the diff layer depth allowance for faster testing. + maxDiffLayers = 4 + defer func() { + maxDiffLayers = 128 + }() + tester := newTester(t, 0) defer tester.release() @@ -574,6 +615,12 @@ func TestCorruptedJournal(t *testing.T) { // truncating the tail histories. This ensures that the ID of the persistent state // always falls within the range of [oldest-history-id, latest-history-id]. func TestTailTruncateHistory(t *testing.T) { + // Redefine the diff layer depth allowance for faster testing. + maxDiffLayers = 4 + defer func() { + maxDiffLayers = 128 + }() + tester := newTester(t, 10) defer tester.release() diff --git a/triedb/pathdb/difflayer_test.go b/triedb/pathdb/difflayer_test.go index 9b5907c3c5b3..75890b8a8371 100644 --- a/triedb/pathdb/difflayer_test.go +++ b/triedb/pathdb/difflayer_test.go @@ -22,7 +22,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/trie/testutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/trie/trienode" ) @@ -66,8 +67,9 @@ func benchmarkSearch(b *testing.B, depth int, total int) { nodes[common.Hash{}] = make(map[string]*trienode.Node) for i := 0; i < 3000; i++ { var ( - path = testutil.RandBytes(32) - node = testutil.RandomNode() + path = testrand.Bytes(32) + blob = testrand.Bytes(100) + node = trienode.New(crypto.Keccak256Hash(blob), blob) ) nodes[common.Hash{}][string(path)] = trienode.New(node.Hash, node.Blob) if npath == nil && depth == index { @@ -112,8 +114,9 @@ func BenchmarkPersist(b *testing.B) { nodes[common.Hash{}] = make(map[string]*trienode.Node) for i := 0; i < 3000; i++ { var ( - path = testutil.RandBytes(32) - node = testutil.RandomNode() + path = testrand.Bytes(32) + blob = testrand.Bytes(100) + node = trienode.New(crypto.Keccak256Hash(blob), blob) ) nodes[common.Hash{}][string(path)] = trienode.New(node.Hash, node.Blob) } @@ -149,8 +152,9 @@ func BenchmarkJournal(b *testing.B) { nodes[common.Hash{}] = make(map[string]*trienode.Node) for i := 0; i < 3000; i++ { var ( - path = testutil.RandBytes(32) - node = testutil.RandomNode() + path = testrand.Bytes(32) + blob = testrand.Bytes(100) + node = trienode.New(crypto.Keccak256Hash(blob), blob) ) nodes[common.Hash{}][string(path)] = trienode.New(node.Hash, node.Blob) } diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_test.go index ab0d44777d7b..81ac768acdc6 100644 --- a/triedb/pathdb/history_test.go +++ b/triedb/pathdb/history_test.go @@ -26,8 +26,8 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie/testutil" "github.com/ethereum/go-ethereum/trie/triestate" ) @@ -38,11 +38,11 @@ func randomStateSet(n int) *triestate.Set { storages = make(map[common.Address]map[common.Hash][]byte) ) for i := 0; i < n; i++ { - addr := testutil.RandomAddress() + addr := testrand.Address() storages[addr] = make(map[common.Hash][]byte) for j := 0; j < 3; j++ { - v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testutil.RandBytes(32))) - storages[addr][testutil.RandomHash()] = v + v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testrand.Bytes(32))) + storages[addr][testrand.Hash()] = v } account := generateAccount(types.EmptyRootHash) accounts[addr] = types.SlimAccountRLP(account) @@ -51,7 +51,7 @@ func randomStateSet(n int) *triestate.Set { } func makeHistory() *history { - return newHistory(testutil.RandomHash(), types.EmptyRootHash, 0, randomStateSet(3)) + return newHistory(testrand.Hash(), types.EmptyRootHash, 0, randomStateSet(3)) } func makeHistories(n int) []*history { @@ -60,7 +60,7 @@ func makeHistories(n int) []*history { result []*history ) for i := 0; i < n; i++ { - root := testutil.RandomHash() + root := testrand.Hash() h := newHistory(root, parent, uint64(i), randomStateSet(3)) parent = root result = append(result, h) diff --git a/triedb/pathdb/testutils.go b/triedb/pathdb/testutils.go index d6fdacb4213e..546cb819b83a 100644 --- a/triedb/pathdb/testutils.go +++ b/triedb/pathdb/testutils.go @@ -93,10 +93,13 @@ func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, e if bytes.Equal(val, h.cleans[hash]) { continue } + // Utilize the hash of the state key as the node path to mitigate + // potential collisions within the path. + path := crypto.Keccak256(hash.Bytes()) if len(val) == 0 { - set.AddNode(hash.Bytes(), trienode.NewDeleted()) + set.AddNode(path, trienode.NewDeleted()) } else { - set.AddNode(hash.Bytes(), trienode.New(crypto.Keccak256Hash(val), val)) + set.AddNode(path, trienode.New(crypto.Keccak256Hash(val), val)) } } root, blob := hash(nodes) From ac6060a4c61b99743173c8c88ea1f8f68f6cdbfc Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Tue, 19 Mar 2024 18:25:30 +0800 Subject: [PATCH 076/571] log: replace tmp with bytes.Buffer.AvailableBuffer (#29287) --- log/format.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/log/format.go b/log/format.go index 6447f3c1f1e9..391e9a8dbbba 100644 --- a/log/format.go +++ b/log/format.go @@ -79,24 +79,18 @@ func (h *TerminalHandler) format(buf []byte, r slog.Record, usecolor bool) []byt } func (h *TerminalHandler) formatAttributes(buf *bytes.Buffer, r slog.Record, color string) { - // tmp is a temporary buffer we use, until bytes.Buffer.AvailableBuffer() (1.21) - // can be used. - var tmp = make([]byte, 40) writeAttr := func(attr slog.Attr, first, last bool) { buf.WriteByte(' ') if color != "" { buf.WriteString(color) - //buf.Write(appendEscapeString(buf.AvailableBuffer(), attr.Key)) - buf.Write(appendEscapeString(tmp[:0], attr.Key)) + buf.Write(appendEscapeString(buf.AvailableBuffer(), attr.Key)) buf.WriteString("\x1b[0m=") } else { - //buf.Write(appendEscapeString(buf.AvailableBuffer(), attr.Key)) - buf.Write(appendEscapeString(tmp[:0], attr.Key)) + buf.Write(appendEscapeString(buf.AvailableBuffer(), attr.Key)) buf.WriteByte('=') } - //val := FormatSlogValue(attr.Value, true, buf.AvailableBuffer()) - val := FormatSlogValue(attr.Value, tmp[:0]) + val := FormatSlogValue(attr.Value, buf.AvailableBuffer()) padding := h.fieldPadding[attr.Key] From 6b3d4d068ac720de1c2edab7d1e1a1311811d747 Mon Sep 17 00:00:00 2001 From: bitcoin-lightning <153181187+AtomicInnovation321@users.noreply.github.com> Date: Tue, 19 Mar 2024 21:05:06 +0800 Subject: [PATCH 077/571] beacon/light/sync: fix typo in comment (#29256) --- beacon/light/sync/head_sync_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon/light/sync/head_sync_test.go b/beacon/light/sync/head_sync_test.go index 12faad62920e..2f75487f161c 100644 --- a/beacon/light/sync/head_sync_test.go +++ b/beacon/light/sync/head_sync_test.go @@ -73,7 +73,7 @@ func TestValidatedHead(t *testing.T) { ts.AddServer(testServer3, 1) ts.ServerEvent(EvNewSignedHead, testServer3, testSHead4) ts.Run(4) - // future period annonced heads should be queued + // future period announced heads should be queued ht.ExpValidated(t, 4, nil) chain.SetNextSyncPeriod(2) From eda9c7e36f120a3e4feb3dfa9472084e88e35054 Mon Sep 17 00:00:00 2001 From: Tien Nguyen <116023870+htiennv@users.noreply.github.com> Date: Tue, 19 Mar 2024 20:05:31 +0700 Subject: [PATCH 078/571] accounts/abi/bind: check invalid chainID first (#29275) --- accounts/abi/bind/auth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go index 0740c6951025..b5e6e349c443 100644 --- a/accounts/abi/bind/auth.go +++ b/accounts/abi/bind/auth.go @@ -142,10 +142,10 @@ func NewKeyStoreTransactorWithChainID(keystore *keystore.KeyStore, account accou // NewKeyedTransactorWithChainID is a utility method to easily create a transaction signer // from a single private key. func NewKeyedTransactorWithChainID(key *ecdsa.PrivateKey, chainID *big.Int) (*TransactOpts, error) { - keyAddr := crypto.PubkeyToAddress(key.PublicKey) if chainID == nil { return nil, ErrNoChainID } + keyAddr := crypto.PubkeyToAddress(key.PublicKey) signer := types.LatestSignerForChainID(chainID) return &TransactOpts{ From: keyAddr, From 4c1b57856f0f5ebccb6edb83ab755ab114500078 Mon Sep 17 00:00:00 2001 From: buddho Date: Tue, 19 Mar 2024 22:23:55 +0800 Subject: [PATCH 079/571] miner: modify header before checking time-based fields (#29242) The Prepare-method of consensus engine might modify the time-field in a header, so it should be called prior to checks that rely on it --- miner/worker.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 7e038b0f301b..a72af3a3a454 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -167,6 +167,12 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) header.GasLimit = core.CalcGasLimit(parentGasLimit, miner.config.GasCeil) } } + // Run the consensus preparation with the default or customized consensus engine. + // Note that the `header.Time` may be changed. + if err := miner.engine.Prepare(miner.chain, header); err != nil { + log.Error("Failed to prepare header for sealing", "err", err) + return nil, err + } // Apply EIP-4844, EIP-4788. if miner.chainConfig.IsCancun(header.Number, header.Time) { var excessBlobGas uint64 @@ -180,11 +186,6 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) header.ExcessBlobGas = &excessBlobGas header.ParentBeaconRoot = genParams.beaconRoot } - // Run the consensus preparation with the default or customized consensus engine. - if err := miner.engine.Prepare(miner.chain, header); err != nil { - log.Error("Failed to prepare header for sealing", "err", err) - return nil, err - } // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase // since clique algorithm can modify the coinbase field in header. From 6f929a0762be92130588779a8535ed0e3fc58d87 Mon Sep 17 00:00:00 2001 From: zgfzgf <48779939+zgfzgf@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:46:50 +0800 Subject: [PATCH 080/571] core/asm: minor code-clarification (#29293) --- core/asm/asm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/asm/asm.go b/core/asm/asm.go index 294eb6ffaad7..ff41ff531524 100644 --- a/core/asm/asm.go +++ b/core/asm/asm.go @@ -66,7 +66,7 @@ func (it *instructionIterator) Next() bool { it.op = vm.OpCode(it.code[it.pc]) if it.op.IsPush() { - a := uint64(it.op) - uint64(vm.PUSH1) + 1 + a := uint64(it.op) - uint64(vm.PUSH0) u := it.pc + 1 + a if uint64(len(it.code)) <= it.pc || uint64(len(it.code)) < u { it.error = fmt.Errorf("incomplete push instruction at %v", it.pc) From 45b88abbde92eab99bab6ac1e55aa88bccccfe80 Mon Sep 17 00:00:00 2001 From: miles <66052478+miles-six@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:49:38 +0800 Subject: [PATCH 081/571] all: fix typos (#29288) --- Dockerfile | 2 +- Dockerfile.alltools | 2 +- core/rawdb/freezer_test.go | 2 +- core/txpool/validation.go | 2 +- signer/fourbyte/abi.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index ffd89905a704..63b92e082529 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/ EXPOSE 8545 8546 30303 30303/udp ENTRYPOINT ["geth"] -# Add some metadata labels to help programatic image consumption +# Add some metadata labels to help programmatic image consumption ARG COMMIT="" ARG VERSION="" ARG BUILDNUM="" diff --git a/Dockerfile.alltools b/Dockerfile.alltools index db256f531620..bdefd9540c7d 100644 --- a/Dockerfile.alltools +++ b/Dockerfile.alltools @@ -24,7 +24,7 @@ COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/ EXPOSE 8545 8546 30303 30303/udp -# Add some metadata labels to help programatic image consumption +# Add some metadata labels to help programmatic image consumption ARG COMMIT="" ARG VERSION="" ARG BUILDNUM="" diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index 2a156638903d..b92cd7b734f9 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -276,7 +276,7 @@ func TestFreezerReadonlyValidate(t *testing.T) { } require.NoError(t, f.Close()) - // Re-openening as readonly should fail when validating + // Re-opening as readonly should fail when validating // table lengths. _, err = NewFreezer(dir, "", true, 2049, tables) if err == nil { diff --git a/core/txpool/validation.go b/core/txpool/validation.go index d9a85a435da4..555b777505cf 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -33,7 +33,7 @@ import ( var ( // blobTxMinBlobGasPrice is the big.Int version of the configured protocol - // parameter to avoid constucting a new big integer for every transaction. + // parameter to avoid constructing a new big integer for every transaction. blobTxMinBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice) ) diff --git a/signer/fourbyte/abi.go b/signer/fourbyte/abi.go index 352abc59e182..bdfbd05a1e77 100644 --- a/signer/fourbyte/abi.go +++ b/signer/fourbyte/abi.go @@ -98,7 +98,7 @@ func parseCallData(calldata []byte, unescapedAbidata string) (*decodedCallData, if len(argdata)%32 != 0 { return nil, fmt.Errorf("invalid call data; length should be a multiple of 32 bytes (was %d)", len(argdata)) } - // Validate the called method and upack the call data accordingly + // Validate the called method and unpack the call data accordingly abispec, err := abi.JSON(strings.NewReader(unescapedAbidata)) if err != nil { return nil, fmt.Errorf("invalid method signature (%q): %v", unescapedAbidata, err) From 0ceac8d00e3067b6bb7ddc79670383295ddf7d6d Mon Sep 17 00:00:00 2001 From: georgehao Date: Wed, 20 Mar 2024 15:51:45 +0800 Subject: [PATCH 082/571] metrics: fix docstrings (#29279) --- metrics/json.go | 4 ++-- metrics/registry.go | 38 +++++++++++++++++++------------------- metrics/timer.go | 8 ++++---- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/metrics/json.go b/metrics/json.go index 2087d8211eb1..6b134d477b60 100644 --- a/metrics/json.go +++ b/metrics/json.go @@ -26,6 +26,6 @@ func WriteJSONOnce(r Registry, w io.Writer) { json.NewEncoder(w).Encode(r) } -func (p *PrefixedRegistry) MarshalJSON() ([]byte, error) { - return json.Marshal(p.GetAll()) +func (r *PrefixedRegistry) MarshalJSON() ([]byte, error) { + return json.Marshal(r.GetAll()) } diff --git a/metrics/registry.go b/metrics/registry.go index 8bfbc080420f..ca4741feef02 100644 --- a/metrics/registry.go +++ b/metrics/registry.go @@ -8,8 +8,8 @@ import ( "sync" ) -// DuplicateMetric is the error returned by Registry.Register when a metric -// already exists. If you mean to Register that metric you must first +// DuplicateMetric is the error returned by Registry. Register when a metric +// already exists. If you mean to Register that metric you must first // Unregister the existing metric. type DuplicateMetric string @@ -20,11 +20,11 @@ func (err DuplicateMetric) Error() string { // A Registry holds references to a set of metrics by name and can iterate // over them, calling callback functions provided by the user. // -// This is an interface so as to encourage other structs to implement +// This is an interface to encourage other structs to implement // the Registry API as appropriate. type Registry interface { - // Call the given function for each registered metric. + // Each call the given function for each registered metric. Each(func(string, interface{})) // Get the metric by the given name or nil if none is registered. @@ -33,7 +33,7 @@ type Registry interface { // GetAll metrics in the Registry. GetAll() map[string]map[string]interface{} - // Gets an existing metric or registers the given one. + // GetOrRegister gets an existing metric or registers the given one. // The interface can be the metric to register if not found in registry, // or a function returning the metric for lazy instantiation. GetOrRegister(string, interface{}) interface{} @@ -41,7 +41,7 @@ type Registry interface { // Register the given metric under the given name. Register(string, interface{}) error - // Run all registered healthchecks. + // RunHealthchecks run all registered healthchecks. RunHealthchecks() // Unregister the metric with the given name. @@ -52,7 +52,7 @@ type orderedRegistry struct { StandardRegistry } -// Call the given function for each registered metric. +// Each call the given function for each registered metric. func (r *orderedRegistry) Each(f func(string, interface{})) { var names []string reg := r.registered() @@ -75,13 +75,13 @@ func NewOrderedRegistry() Registry { return new(orderedRegistry) } -// The standard implementation of a Registry uses sync.map +// StandardRegistry the standard implementation of a Registry uses sync.map // of names to metrics. type StandardRegistry struct { metrics sync.Map } -// Call the given function for each registered metric. +// Each call the given function for each registered metric. func (r *StandardRegistry) Each(f func(string, interface{})) { for name, i := range r.registered() { f(name, i) @@ -94,7 +94,7 @@ func (r *StandardRegistry) Get(name string) interface{} { return item } -// Gets an existing metric or creates and registers a new one. Threadsafe +// GetOrRegister gets an existing metric or creates and registers a new one. Threadsafe // alternative to calling Get and Register on failure. // The interface can be the metric to register if not found in registry, // or a function returning the metric for lazy instantiation. @@ -114,7 +114,7 @@ func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} return item } -// Register the given metric under the given name. Returns a DuplicateMetric +// Register the given metric under the given name. Returns a DuplicateMetric // if a metric by the given name is already registered. func (r *StandardRegistry) Register(name string, i interface{}) error { // fast path @@ -133,7 +133,7 @@ func (r *StandardRegistry) Register(name string, i interface{}) error { return nil } -// Run all registered healthchecks. +// RunHealthchecks run all registered healthchecks. func (r *StandardRegistry) RunHealthchecks() { r.metrics.Range(func(key, value any) bool { if h, ok := value.(Healthcheck); ok { @@ -263,7 +263,7 @@ func NewPrefixedChildRegistry(parent Registry, prefix string) Registry { } } -// Call the given function for each registered metric. +// Each call the given function for each registered metric. func (r *PrefixedRegistry) Each(fn func(string, interface{})) { wrappedFn := func(prefix string) func(string, interface{}) { return func(name string, iface interface{}) { @@ -295,7 +295,7 @@ func (r *PrefixedRegistry) Get(name string) interface{} { return r.underlying.Get(realName) } -// Gets an existing metric or registers the given one. +// GetOrRegister gets an existing metric or registers the given one. // The interface can be the metric to register if not found in registry, // or a function returning the metric for lazy instantiation. func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} { @@ -309,7 +309,7 @@ func (r *PrefixedRegistry) Register(name string, metric interface{}) error { return r.underlying.Register(realName, metric) } -// Run all registered healthchecks. +// RunHealthchecks run all registered healthchecks. func (r *PrefixedRegistry) RunHealthchecks() { r.underlying.RunHealthchecks() } @@ -331,7 +331,7 @@ var ( AccountingRegistry = NewRegistry() // registry used in swarm ) -// Call the given function for each registered metric. +// Each call the given function for each registered metric. func Each(f func(string, interface{})) { DefaultRegistry.Each(f) } @@ -341,7 +341,7 @@ func Get(name string) interface{} { return DefaultRegistry.Get(name) } -// Gets an existing metric or creates and registers a new one. Threadsafe +// GetOrRegister gets an existing metric or creates and registers a new one. Threadsafe // alternative to calling Get and Register on failure. func GetOrRegister(name string, i interface{}) interface{} { return DefaultRegistry.GetOrRegister(name, i) @@ -353,7 +353,7 @@ func Register(name string, i interface{}) error { return DefaultRegistry.Register(name, i) } -// Register the given metric under the given name. Panics if a metric by the +// MustRegister register the given metric under the given name. Panics if a metric by the // given name is already registered. func MustRegister(name string, i interface{}) { if err := Register(name, i); err != nil { @@ -361,7 +361,7 @@ func MustRegister(name string, i interface{}) { } } -// Run all registered healthchecks. +// RunHealthchecks run all registered healthchecks. func RunHealthchecks() { DefaultRegistry.RunHealthchecks() } diff --git a/metrics/timer.go b/metrics/timer.go index bb8def82fb29..fc2a88f508bc 100644 --- a/metrics/timer.go +++ b/metrics/timer.go @@ -10,7 +10,7 @@ type TimerSnapshot interface { MeterSnapshot } -// Timers capture the duration and rate of events. +// Timer capture the duration and rate of events. type Timer interface { Snapshot() TimerSnapshot Stop() @@ -99,14 +99,14 @@ func (t *StandardTimer) Stop() { t.meter.Stop() } -// Record the duration of the execution of the given function. +// Time record the duration of the execution of the given function. func (t *StandardTimer) Time(f func()) { ts := time.Now() f() t.Update(time.Since(ts)) } -// Record the duration of an event, in nanoseconds. +// Update the duration of an event, in nanoseconds. func (t *StandardTimer) Update(d time.Duration) { t.mutex.Lock() defer t.mutex.Unlock() @@ -114,7 +114,7 @@ func (t *StandardTimer) Update(d time.Duration) { t.meter.Mark(1) } -// Record the duration of an event that started at a time and ends now. +// UpdateSince update the duration of an event that started at a time and ends now. // The record uses nanoseconds. func (t *StandardTimer) UpdateSince(ts time.Time) { t.Update(time.Since(ts)) From de08f3d62552531f3fb2fc3a64a4bfdb962900eb Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 20 Mar 2024 09:12:58 +0100 Subject: [PATCH 083/571] cmd/evm: make staterunner always output stateroot to stderr (#29290) This changes makes it so that when `evm statetest` executes, regardless of whether `--json` is specified or not, the stateroot is printed on `stderr` as a `jsonl` line. This enables speedier execution of testcases in goevmlab, in cases where full execution op-by-op is not required. --- cmd/evm/staterunner.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 458d809ad82e..79ca44a4a428 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -67,7 +67,7 @@ func stateTestCmd(ctx *cli.Context) error { } // Load the test content from the input file if len(ctx.Args().First()) != 0 { - return runStateTest(ctx.Args().First(), cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name)) + return runStateTest(ctx.Args().First(), cfg, ctx.Bool(MachineFlag.Name)) } // Read filenames from stdin and execute back-to-back scanner := bufio.NewScanner(os.Stdin) @@ -76,7 +76,7 @@ func stateTestCmd(ctx *cli.Context) error { if len(fname) == 0 { return nil } - if err := runStateTest(fname, cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name)); err != nil { + if err := runStateTest(fname, cfg, ctx.Bool(MachineFlag.Name)); err != nil { return err } } @@ -84,7 +84,7 @@ func stateTestCmd(ctx *cli.Context) error { } // runStateTest loads the state-test given by fname, and executes the test. -func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error { +func runStateTest(fname string, cfg vm.Config, dump bool) error { src, err := os.ReadFile(fname) if err != nil { return err @@ -105,9 +105,7 @@ func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error { if tstate.StateDB != nil { root = tstate.StateDB.IntermediateRoot(false) result.Root = &root - if jsonOut { - fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) - } + fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) if dump { // Dump any state to aid debugging cpy, _ := state.New(root, tstate.StateDB.Database(), nil) dump := cpy.RawDump(nil) From 9a7e6ce6f593d1284512032d5757a85a15e6d636 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 20 Mar 2024 10:38:30 +0100 Subject: [PATCH 084/571] cmd/evm: fix flag-mismatch from #29290 (#29298) --- cmd/evm/staterunner.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 79ca44a4a428..aaf2b00f879d 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -67,7 +67,7 @@ func stateTestCmd(ctx *cli.Context) error { } // Load the test content from the input file if len(ctx.Args().First()) != 0 { - return runStateTest(ctx.Args().First(), cfg, ctx.Bool(MachineFlag.Name)) + return runStateTest(ctx.Args().First(), cfg, ctx.Bool(DumpFlag.Name)) } // Read filenames from stdin and execute back-to-back scanner := bufio.NewScanner(os.Stdin) @@ -76,7 +76,7 @@ func stateTestCmd(ctx *cli.Context) error { if len(fname) == 0 { return nil } - if err := runStateTest(fname, cfg, ctx.Bool(MachineFlag.Name)); err != nil { + if err := runStateTest(fname, cfg, ctx.Bool(DumpFlag.Name)); err != nil { return err } } From 22ac46cbdbd0601d2c59a74bb29fb0ceb34dddaa Mon Sep 17 00:00:00 2001 From: imalasong <55082705+imalasong@users.noreply.github.com> Date: Wed, 20 Mar 2024 20:09:46 +0800 Subject: [PATCH 085/571] Makefile: update PHONY directive (#29296) --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 99b8ba54b492..278ae63120f6 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 evm all test clean +.PHONY: geth all test lint clean devtools help GOBIN = ./build/bin GO ?= latest @@ -47,4 +47,3 @@ devtools: help: Makefile @echo " Choose a command run in go-ethereum:" @sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /' -.PHONY: help From 78c102dec5f1c7b5256c466df4421b4818bfe0e6 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 20 Mar 2024 20:11:30 +0800 Subject: [PATCH 086/571] core: skip the check the statefulness of head block in repair (#29245) --- core/blockchain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index ba346b010d47..1b41d777329e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -891,7 +891,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha // touching the header chain altogether, unless the freezer is broken if repair { if target, force := updateFn(bc.db, bc.CurrentBlock()); force { - bc.hc.SetHead(target.Number.Uint64(), updateFn, delFn) + bc.hc.SetHead(target.Number.Uint64(), nil, delFn) } } else { // Rewind the chain to the requested head and keep going backwards until a From 0444388c746f99186e086f8ea733ea45e91918ac Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Wed, 20 Mar 2024 21:51:05 +0800 Subject: [PATCH 087/571] core/txpool/blobpool: calculate log1.125 faster (#29300) --- core/txpool/blobpool/priority.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/txpool/blobpool/priority.go b/core/txpool/blobpool/priority.go index a8332bd9b0e6..7ae7f92def12 100644 --- a/core/txpool/blobpool/priority.go +++ b/core/txpool/blobpool/priority.go @@ -23,8 +23,8 @@ import ( "github.com/holiman/uint256" ) -// log2_1_125 is used in the eviction priority calculation. -var log2_1_125 = math.Log2(1.125) +// log1_125 is used in the eviction priority calculation. +var log1_125 = math.Log(1.125) // evictionPriority calculates the eviction priority based on the algorithm // described in the BlobPool docs for both fee components. @@ -57,8 +57,8 @@ func evictionPriority1D(basefeeJumps float64, txfeeJumps float64) int { // dynamicFeeJumps calculates the log1.125(fee), namely the number of fee jumps // needed to reach the requested one. We only use it when calculating the jumps -// between 2 fees, so it doesn't matter from what exact number with returns. -// it returns the result from (0, 1, 1.125). +// between 2 fees, so it doesn't matter from what exact number it returns. +// It returns the result from (0, 1, 1.125). // // This method is very expensive, taking about 75ns on a very recent laptop CPU, // but the result does not change with the lifetime of a transaction, so it can @@ -67,7 +67,7 @@ func dynamicFeeJumps(fee *uint256.Int) float64 { if fee.IsZero() { return 0 // can't log2 zero, should never happen outside tests, but don't choke } - return math.Log2(fee.Float64()) / log2_1_125 + return math.Log(fee.Float64()) / log1_125 } // intLog2 is a helper to calculate the integral part of a log2 of an unsigned From 8f7fbdfedcbaca2a2bffb00badc75c03d58052ec Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 20 Mar 2024 14:58:47 +0100 Subject: [PATCH 088/571] core: refactor consensus interface (#29283) This PR modifies the consensus interface to wrap the body fields. --- consensus/beacon/consensus.go | 20 ++++++++++---------- consensus/clique/clique.go | 10 +++++----- consensus/consensus.go | 6 ++---- consensus/ethash/consensus.go | 12 ++++++------ core/chain_makers.go | 3 ++- core/state_processor.go | 2 +- miner/worker.go | 3 ++- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index a350e383a293..9ffed438a877 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -348,13 +348,13 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H } // Finalize implements consensus.Engine and processes withdrawals on top. -func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { +func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) { if !beacon.IsPoSHeader(header) { - beacon.ethone.Finalize(chain, header, state, txs, uncles, nil) + beacon.ethone.Finalize(chain, header, state, body) return } // Withdrawals processing. - for _, w := range withdrawals { + for _, w := range body.Withdrawals { // Convert amount from gwei to wei. amount := new(uint256.Int).SetUint64(w.Amount) amount = amount.Mul(amount, uint256.NewInt(params.GWei)) @@ -365,29 +365,29 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. // FinalizeAndAssemble implements consensus.Engine, setting the final state and // assembling the block. -func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { +func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) { if !beacon.IsPoSHeader(header) { - return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts, nil) + return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts) } shanghai := chain.Config().IsShanghai(header.Number, header.Time) if shanghai { // All blocks after Shanghai must include a withdrawals root. - if withdrawals == nil { - withdrawals = make([]*types.Withdrawal, 0) + if body.Withdrawals == nil { + body.Withdrawals = make([]*types.Withdrawal, 0) } } else { - if len(withdrawals) > 0 { + if len(body.Withdrawals) > 0 { return nil, errors.New("withdrawals set before Shanghai activation") } } // Finalize and assemble the block. - beacon.Finalize(chain, header, state, txs, uncles, withdrawals) + beacon.Finalize(chain, header, state, body) // Assign the final state root to header. header.Root = state.IntermediateRoot(true) // Assemble and return the final block. - return types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)), nil + return types.NewBlockWithWithdrawals(header, body.Transactions, body.Uncles, receipts, body.Withdrawals, trie.NewStackTrie(nil)), nil } // Seal generates a new sealing request for the given input block and pushes diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 59f0e96ebe3e..b5727fc666d5 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -580,24 +580,24 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header // Finalize implements consensus.Engine. There is no post-transaction // consensus rules in clique, do nothing here. -func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { +func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) { // No block rewards in PoA, so the state remains as is } // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, // nor block rewards given, and returns the final block. -func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { - if len(withdrawals) > 0 { +func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) { + if len(body.Withdrawals) > 0 { return nil, errors.New("clique does not support withdrawals") } // Finalize block - c.Finalize(chain, header, state, txs, uncles, nil) + c.Finalize(chain, header, state, body) // Assign the final state root to header. header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) // Assemble and return the final block for sealing. - return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil + return types.NewBlock(header, body.Transactions, nil, receipts, trie.NewStackTrie(nil)), nil } // Authorize injects a private key into the consensus engine to mint new blocks diff --git a/consensus/consensus.go b/consensus/consensus.go index 5cc052cb0fea..9232f7a2c8bf 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -88,16 +88,14 @@ type Engine interface { // // Note: The state database might be updated to reflect any consensus rules // that happen at finalization (e.g. block rewards). - Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, - uncles []*types.Header, withdrawals []*types.Withdrawal) + Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) // FinalizeAndAssemble runs any post-transaction state modifications (e.g. block // rewards or process withdrawals) and assembles the final block. // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). - FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, - uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) + FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) // Seal generates a new sealing request for the given input block and pushes // the result into the given channel. diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index c2936fd4b341..5299afa610d0 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -501,25 +501,25 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H } // Finalize implements consensus.Engine, accumulating the block and uncle rewards. -func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { +func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) { // Accumulate any block and uncle rewards - accumulateRewards(chain.Config(), state, header, uncles) + accumulateRewards(chain.Config(), state, header, body.Uncles) } // FinalizeAndAssemble implements consensus.Engine, accumulating the block and // uncle rewards, setting the final state and assembling the block. -func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { - if len(withdrawals) > 0 { +func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) { + if len(body.Withdrawals) > 0 { return nil, errors.New("ethash does not support withdrawals") } // Finalize block - ethash.Finalize(chain, header, state, txs, uncles, nil) + ethash.Finalize(chain, header, state, body) // Assign the final state root to header. header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) // Header seems complete, assemble into a block and return - return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil + return types.NewBlock(header, body.Transactions, body.Uncles, receipts, trie.NewStackTrie(nil)), nil } // SealHash returns the hash of a block prior to it being sealed. diff --git a/core/chain_makers.go b/core/chain_makers.go index 733030fd1c9e..1c42ab0c9af2 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -345,7 +345,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse gen(i, b) } - block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, b.txs, b.uncles, b.receipts, b.withdrawals) + body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals} + block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts) if err != nil { panic(err) } diff --git a/core/state_processor.go b/core/state_processor.go index 2f18d257b91e..9c8beaa7f5cc 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -99,7 +99,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, nil, 0, errors.New("withdrawals before shanghai") } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), withdrawals) + p.engine.Finalize(p.bc, header, statedb, block.Body()) return receipts, allLogs, *usedGas, nil } diff --git a/miner/worker.go b/miner/worker.go index a72af3a3a454..f22242841f77 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -105,7 +105,8 @@ func (miner *Miner) generateWork(params *generateParams) *newPayloadResult { log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit)) } } - block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, work.txs, nil, work.receipts, params.withdrawals) + body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals} + block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts) if err != nil { return &newPayloadResult{err: err} } From 04bf1c802ffe9dfc34c34b3e666ee15e96b4a203 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 20 Mar 2024 15:22:52 +0100 Subject: [PATCH 089/571] eth/protocols/snap, internal/testlog: fix dataraces (#29301) --- eth/protocols/snap/sync_test.go | 5 +++-- internal/testlog/testlog.go | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 87e186633b58..9bfc9bcb5c57 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1873,8 +1873,9 @@ func verifyTrie(scheme string, db ethdb.KeyValueStore, root common.Hash, t *test // TestSyncAccountPerformance tests how efficient the snap algo is at minimizing // state healing func TestSyncAccountPerformance(t *testing.T) { - t.Parallel() - + // These tests must not run in parallel: they modify the + // global var accountConcurrency + // t.Parallel() testSyncAccountPerformance(t, rawdb.HashScheme) testSyncAccountPerformance(t, rawdb.PathScheme) } diff --git a/internal/testlog/testlog.go b/internal/testlog/testlog.go index 3cdbea6e0537..e5ddf9cfeb0b 100644 --- a/internal/testlog/testlog.go +++ b/internal/testlog/testlog.go @@ -47,9 +47,12 @@ type bufHandler struct { buf []slog.Record attrs []slog.Attr level slog.Level + mu sync.Mutex } func (h *bufHandler) Handle(_ context.Context, r slog.Record) error { + h.mu.Lock() + defer h.mu.Unlock() h.buf = append(h.buf, r) return nil } @@ -59,12 +62,14 @@ func (h *bufHandler) Enabled(_ context.Context, lvl slog.Level) bool { } func (h *bufHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + h.mu.Lock() + defer h.mu.Unlock() records := make([]slog.Record, len(h.buf)) copy(records[:], h.buf[:]) return &bufHandler{ - records, - append(h.attrs, attrs...), - h.level, + buf: records, + attrs: append(h.attrs, attrs...), + level: h.level, } } @@ -75,9 +80,9 @@ func (h *bufHandler) WithGroup(_ string) slog.Handler { // Logger returns a logger which logs to the unit test log of t. func Logger(t *testing.T, level slog.Level) log.Logger { handler := bufHandler{ - []slog.Record{}, - []slog.Attr{}, - level, + buf: []slog.Record{}, + attrs: []slog.Attr{}, + level: level, } return &logger{ t: t, @@ -200,6 +205,8 @@ func (h *bufHandler) terminalFormat(r slog.Record) string { // flush writes all buffered messages and clears the buffer. func (l *logger) flush() { l.t.Helper() + l.h.mu.Lock() + defer l.h.mu.Unlock() for _, r := range l.h.buf { l.t.Logf("%s", l.h.terminalFormat(r)) } From bca6c407098fefc757c263ae2da6aeff719e17ca Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 20 Mar 2024 19:22:44 +0100 Subject: [PATCH 090/571] beacon/blsync: support for deneb fork (#29180) This adds support for the Deneb beacon chain fork, and fork handling in general, to the beacon chain light client implementation. Co-authored-by: Zsolt Felfoldi --- beacon/blsync/block_sync.go | 95 +- beacon/blsync/block_sync_test.go | 78 +- beacon/blsync/client.go | 46 +- beacon/blsync/config.go | 9 +- beacon/blsync/engineclient.go | 147 ++ beacon/light/api/light_api.go | 57 +- beacon/types/beacon_block.go | 110 + beacon/types/beacon_block_test.go | 77 + beacon/types/config.go | 12 +- beacon/types/exec_header.go | 80 + beacon/types/exec_payload.go | 144 ++ beacon/types/header.go | 11 + beacon/types/light_sync.go | 13 +- beacon/types/testdata/block_capella.json | 1703 ++++++++++++++ beacon/types/testdata/block_deneb.json | 2644 ++++++++++++++++++++++ cmd/blsync/engine_api.go | 69 - cmd/blsync/main.go | 9 +- cmd/geth/config.go | 13 +- eth/catalyst/blsync.go | 88 - go.mod | 4 +- go.sum | 13 +- 21 files changed, 5074 insertions(+), 348 deletions(-) create mode 100644 beacon/blsync/engineclient.go create mode 100644 beacon/types/beacon_block.go create mode 100644 beacon/types/beacon_block_test.go create mode 100644 beacon/types/exec_header.go create mode 100644 beacon/types/exec_payload.go create mode 100644 beacon/types/testdata/block_capella.json create mode 100644 beacon/types/testdata/block_deneb.json delete mode 100644 cmd/blsync/engine_api.go delete mode 100644 eth/catalyst/blsync.go diff --git a/beacon/blsync/block_sync.go b/beacon/blsync/block_sync.go index 91b21163e655..ef852dfe996f 100755 --- a/beacon/blsync/block_sync.go +++ b/beacon/blsync/block_sync.go @@ -17,35 +17,25 @@ package blsync import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/beacon/light/request" "github.com/ethereum/go-ethereum/beacon/light/sync" "github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" - ctypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/trie" - "github.com/holiman/uint256" - "github.com/protolambda/zrnt/eth2/beacon/capella" - "github.com/protolambda/zrnt/eth2/configs" - "github.com/protolambda/ztyp/tree" ) // beaconBlockSync implements request.Module; it fetches the beacon blocks belonging // to the validated and prefetch heads. type beaconBlockSync struct { - recentBlocks *lru.Cache[common.Hash, *capella.BeaconBlock] + recentBlocks *lru.Cache[common.Hash, *types.BeaconBlock] locked map[common.Hash]request.ServerAndID serverHeads map[request.Server]common.Hash headTracker headTracker lastHeadInfo types.HeadInfo - chainHeadFeed *event.Feed + chainHeadFeed event.FeedOf[types.ChainHeadEvent] } type headTracker interface { @@ -55,16 +45,19 @@ type headTracker interface { } // newBeaconBlockSync returns a new beaconBlockSync. -func newBeaconBlockSync(headTracker headTracker, chainHeadFeed *event.Feed) *beaconBlockSync { +func newBeaconBlockSync(headTracker headTracker) *beaconBlockSync { return &beaconBlockSync{ - headTracker: headTracker, - chainHeadFeed: chainHeadFeed, - recentBlocks: lru.NewCache[common.Hash, *capella.BeaconBlock](10), - locked: make(map[common.Hash]request.ServerAndID), - serverHeads: make(map[request.Server]common.Hash), + headTracker: headTracker, + recentBlocks: lru.NewCache[common.Hash, *types.BeaconBlock](10), + locked: make(map[common.Hash]request.ServerAndID), + serverHeads: make(map[request.Server]common.Hash), } } +func (s *beaconBlockSync) SubscribeChainHead(ch chan<- types.ChainHeadEvent) event.Subscription { + return s.chainHeadFeed.Subscribe(ch) +} + // Process implements request.Module. func (s *beaconBlockSync) Process(requester request.Requester, events []request.Event) { for _, event := range events { @@ -73,7 +66,7 @@ func (s *beaconBlockSync) Process(requester request.Requester, events []request. sid, req, resp := event.RequestInfo() blockRoot := common.Hash(req.(sync.ReqBeaconBlock)) if resp != nil { - s.recentBlocks.Add(blockRoot, resp.(*capella.BeaconBlock)) + s.recentBlocks.Add(blockRoot, resp.(*types.BeaconBlock)) } if s.locked[blockRoot] == sid { delete(s.locked, blockRoot) @@ -112,63 +105,11 @@ func (s *beaconBlockSync) tryRequestBlock(requester request.Requester, blockRoot } } -func blockHeadInfo(block *capella.BeaconBlock) types.HeadInfo { +func blockHeadInfo(block *types.BeaconBlock) types.HeadInfo { if block == nil { return types.HeadInfo{} } - return types.HeadInfo{Slot: uint64(block.Slot), BlockRoot: beaconBlockHash(block)} -} - -// beaconBlockHash calculates the hash of a beacon block. -func beaconBlockHash(beaconBlock *capella.BeaconBlock) common.Hash { - return common.Hash(beaconBlock.HashTreeRoot(configs.Mainnet, tree.GetHashFn())) -} - -// getExecBlock extracts the execution block from the beacon block's payload. -func getExecBlock(beaconBlock *capella.BeaconBlock) (*ctypes.Block, error) { - payload := &beaconBlock.Body.ExecutionPayload - txs := make([]*ctypes.Transaction, len(payload.Transactions)) - for i, opaqueTx := range payload.Transactions { - var tx ctypes.Transaction - if err := tx.UnmarshalBinary(opaqueTx); err != nil { - return nil, fmt.Errorf("failed to parse tx %d: %v", i, err) - } - txs[i] = &tx - } - withdrawals := make([]*ctypes.Withdrawal, len(payload.Withdrawals)) - for i, w := range payload.Withdrawals { - withdrawals[i] = &ctypes.Withdrawal{ - Index: uint64(w.Index), - Validator: uint64(w.ValidatorIndex), - Address: common.Address(w.Address), - Amount: uint64(w.Amount), - } - } - wroot := ctypes.DeriveSha(ctypes.Withdrawals(withdrawals), trie.NewStackTrie(nil)) - execHeader := &ctypes.Header{ - ParentHash: common.Hash(payload.ParentHash), - UncleHash: ctypes.EmptyUncleHash, - Coinbase: common.Address(payload.FeeRecipient), - Root: common.Hash(payload.StateRoot), - TxHash: ctypes.DeriveSha(ctypes.Transactions(txs), trie.NewStackTrie(nil)), - ReceiptHash: common.Hash(payload.ReceiptsRoot), - Bloom: ctypes.Bloom(payload.LogsBloom), - Difficulty: common.Big0, - Number: new(big.Int).SetUint64(uint64(payload.BlockNumber)), - GasLimit: uint64(payload.GasLimit), - GasUsed: uint64(payload.GasUsed), - Time: uint64(payload.Timestamp), - Extra: []byte(payload.ExtraData), - MixDigest: common.Hash(payload.PrevRandao), // reused in merge - Nonce: ctypes.BlockNonce{}, // zero - BaseFee: (*uint256.Int)(&payload.BaseFeePerGas).ToBig(), - WithdrawalsHash: &wroot, - } - execBlock := ctypes.NewBlockWithHeader(execHeader).WithBody(txs, nil).WithWithdrawals(withdrawals) - if execBlockHash := execBlock.Hash(); execBlockHash != common.Hash(payload.BlockHash) { - return execBlock, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", common.Hash(payload.BlockHash), execBlockHash) - } - return execBlock, nil + return types.HeadInfo{Slot: block.Slot(), BlockRoot: block.Root()} } func (s *beaconBlockSync) updateEventFeed() { @@ -190,14 +131,16 @@ func (s *beaconBlockSync) updateEventFeed() { return } s.lastHeadInfo = headInfo + // new head block and finality info available; extract executable data and send event to feed - execBlock, err := getExecBlock(headBlock) + execBlock, err := headBlock.ExecutionPayload() if err != nil { log.Error("Error extracting execution block from validated beacon block", "error", err) return } s.chainHeadFeed.Send(types.ChainHeadEvent{ - HeadBlock: engine.BlockToExecutableData(execBlock, nil, nil).ExecutionPayload, - Finalized: common.Hash(finality.Finalized.PayloadHeader.BlockHash), + BeaconHead: head.Header, + Block: execBlock, + Finalized: finality.Finalized.PayloadHeader.BlockHash(), }) } diff --git a/beacon/blsync/block_sync_test.go b/beacon/blsync/block_sync_test.go index 9ce434d86273..73ae89ae734f 100644 --- a/beacon/blsync/block_sync_test.go +++ b/beacon/blsync/block_sync_test.go @@ -23,70 +23,69 @@ import ( "github.com/ethereum/go-ethereum/beacon/light/sync" "github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/event" - "github.com/protolambda/zrnt/eth2/beacon/capella" - "github.com/protolambda/zrnt/eth2/configs" - "github.com/protolambda/ztyp/tree" + zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/protolambda/zrnt/eth2/beacon/deneb" ) var ( testServer1 = "testServer1" testServer2 = "testServer2" - testBlock1 = &capella.BeaconBlock{ + testBlock1 = types.NewBeaconBlock(&deneb.BeaconBlock{ Slot: 123, - Body: capella.BeaconBlockBody{ - ExecutionPayload: capella.ExecutionPayload{BlockNumber: 456}, + Body: deneb.BeaconBlockBody{ + ExecutionPayload: deneb.ExecutionPayload{ + BlockNumber: 456, + BlockHash: zrntcommon.Hash32(common.HexToHash("905ac721c4058d9ed40b27b6b9c1bdd10d4333e4f3d9769100bf9dfb80e5d1f6")), + }, }, - } - testBlock2 = &capella.BeaconBlock{ + }) + testBlock2 = types.NewBeaconBlock(&deneb.BeaconBlock{ Slot: 124, - Body: capella.BeaconBlockBody{ - ExecutionPayload: capella.ExecutionPayload{BlockNumber: 457}, + Body: deneb.BeaconBlockBody{ + ExecutionPayload: deneb.ExecutionPayload{ + BlockNumber: 457, + BlockHash: zrntcommon.Hash32(common.HexToHash("011703f39c664efc1c6cf5f49ca09b595581eec572d4dfddd3d6179a9e63e655")), + }, }, - } + }) ) -func init() { - eb1, _ := getExecBlock(testBlock1) - testBlock1.Body.ExecutionPayload.BlockHash = tree.Root(eb1.Hash()) - eb2, _ := getExecBlock(testBlock2) - testBlock2.Body.ExecutionPayload.BlockHash = tree.Root(eb2.Hash()) -} - func TestBlockSync(t *testing.T) { ht := &testHeadTracker{} - eventFeed := new(event.Feed) - blockSync := newBeaconBlockSync(ht, eventFeed) + blockSync := newBeaconBlockSync(ht) headCh := make(chan types.ChainHeadEvent, 16) - eventFeed.Subscribe(headCh) + blockSync.SubscribeChainHead(headCh) ts := sync.NewTestScheduler(t, blockSync) ts.AddServer(testServer1, 1) ts.AddServer(testServer2, 1) - expHeadBlock := func(tci int, expHead *capella.BeaconBlock) { + expHeadBlock := func(expHead *types.BeaconBlock) { + t.Helper() var expNumber, headNumber uint64 if expHead != nil { - expNumber = uint64(expHead.Body.ExecutionPayload.BlockNumber) + p, _ := expHead.ExecutionPayload() + expNumber = p.NumberU64() } select { case event := <-headCh: - headNumber = event.HeadBlock.Number + headNumber = event.Block.NumberU64() default: } if headNumber != expNumber { - t.Errorf("Wrong head block in test case #%d (expected block number %d, got %d)", tci, expNumber, headNumber) + t.Errorf("Wrong head block, expected block number %d, got %d)", expNumber, headNumber) } } // no block requests expected until head tracker knows about a head ts.Run(1) - expHeadBlock(1, nil) + expHeadBlock(nil) // set block 1 as prefetch head, announced by server 2 head1 := blockHeadInfo(testBlock1) ht.prefetch = head1 ts.ServerEvent(sync.EvNewHead, testServer2, head1) + // expect request to server 2 which has announced the head ts.Run(2, testServer2, sync.ReqBeaconBlock(head1.BlockRoot)) @@ -95,12 +94,12 @@ func TestBlockSync(t *testing.T) { ts.AddAllowance(testServer2, 1) ts.Run(3) // head block still not expected as the fetched block is not the validated head yet - expHeadBlock(3, nil) + expHeadBlock(nil) // set as validated head, expect no further requests but block 1 set as head block - ht.validated.Header = blockHeader(testBlock1) + ht.validated.Header = testBlock1.Header() ts.Run(4) - expHeadBlock(4, testBlock1) + expHeadBlock(testBlock1) // set block 2 as prefetch head, announced by server 1 head2 := blockHeadInfo(testBlock2) @@ -114,26 +113,16 @@ func TestBlockSync(t *testing.T) { ts.Run(6) // set as validated head before retrieving block; now it's assumed to be available from server 2 too - ht.validated.Header = blockHeader(testBlock2) + ht.validated.Header = testBlock2.Header() // expect req2 retry to server 2 ts.Run(7, testServer2, sync.ReqBeaconBlock(head2.BlockRoot)) // now head block should be unavailable again - expHeadBlock(4, nil) + expHeadBlock(nil) // valid response, now head block should be block 2 immediately as it is already validated ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testBlock2) ts.Run(8) - expHeadBlock(5, testBlock2) -} - -func blockHeader(block *capella.BeaconBlock) types.Header { - return types.Header{ - Slot: uint64(block.Slot), - ProposerIndex: uint64(block.ProposerIndex), - ParentRoot: common.Hash(block.ParentRoot), - StateRoot: common.Hash(block.StateRoot), - BodyRoot: common.Hash(block.Body.HashTreeRoot(configs.Mainnet, tree.GetHashFn())), - } + expHeadBlock(testBlock2) } type testHeadTracker struct { @@ -151,9 +140,10 @@ func (h *testHeadTracker) ValidatedHead() (types.SignedHeader, bool) { // TODO add test case for finality func (h *testHeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { + finalized := types.NewExecutionHeader(new(deneb.ExecutionPayloadHeader)) return types.FinalityUpdate{ Attested: types.HeaderWithExecProof{Header: h.validated.Header}, - Finalized: types.HeaderWithExecProof{PayloadHeader: &capella.ExecutionPayloadHeader{}}, + Finalized: types.HeaderWithExecProof{PayloadHeader: finalized}, Signature: h.validated.Signature, SignatureSlot: h.validated.SignatureSlot, }, h.validated.Header != (types.Header{}) diff --git a/beacon/blsync/client.go b/beacon/blsync/client.go index 1bfbb1316069..39a1c6ea76c1 100644 --- a/beacon/blsync/client.go +++ b/beacon/blsync/client.go @@ -28,14 +28,20 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/rpc" "github.com/urfave/cli/v2" ) type Client struct { - scheduler *request.Scheduler - chainHeadFeed *event.Feed - urls []string - customHeader map[string]string + urls []string + customHeader map[string]string + chainConfig *lightClientConfig + scheduler *request.Scheduler + blockSync *beaconBlockSync + engineRPC *rpc.Client + + chainHeadSub event.Subscription + engineClient *engineClient } func NewClient(ctx *cli.Context) *Client { @@ -53,6 +59,7 @@ func NewClient(ctx *cli.Context) *Client { } customHeader[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1]) } + // create data structures var ( db = memorydb.New() @@ -63,11 +70,10 @@ func NewClient(ctx *cli.Context) *Client { headSync := sync.NewHeadSync(headTracker, committeeChain) // set up scheduler and sync modules - chainHeadFeed := new(event.Feed) scheduler := request.NewScheduler() checkpointInit := sync.NewCheckpointInit(committeeChain, chainConfig.Checkpoint) forwardSync := sync.NewForwardUpdateSync(committeeChain) - beaconBlockSync := newBeaconBlockSync(headTracker, chainHeadFeed) + beaconBlockSync := newBeaconBlockSync(headTracker) scheduler.RegisterTarget(headTracker) scheduler.RegisterTarget(committeeChain) scheduler.RegisterModule(checkpointInit, "checkpointInit") @@ -76,28 +82,34 @@ func NewClient(ctx *cli.Context) *Client { scheduler.RegisterModule(beaconBlockSync, "beaconBlockSync") return &Client{ - scheduler: scheduler, - urls: ctx.StringSlice(utils.BeaconApiFlag.Name), - customHeader: customHeader, - chainHeadFeed: chainHeadFeed, + scheduler: scheduler, + urls: ctx.StringSlice(utils.BeaconApiFlag.Name), + customHeader: customHeader, + chainConfig: &chainConfig, + blockSync: beaconBlockSync, } } -// SubscribeChainHeadEvent allows callers to subscribe a provided channel to new -// head updates. -func (c *Client) SubscribeChainHeadEvent(ch chan<- types.ChainHeadEvent) event.Subscription { - return c.chainHeadFeed.Subscribe(ch) +func (c *Client) SetEngineRPC(engine *rpc.Client) { + c.engineRPC = engine } -func (c *Client) Start() { +func (c *Client) Start() error { + headCh := make(chan types.ChainHeadEvent, 16) + c.chainHeadSub = c.blockSync.SubscribeChainHead(headCh) + c.engineClient = startEngineClient(c.chainConfig, c.engineRPC, headCh) + c.scheduler.Start() - // register server(s) for _, url := range c.urls { beaconApi := api.NewBeaconLightApi(url, c.customHeader) c.scheduler.RegisterServer(request.NewServer(api.NewApiServer(beaconApi), &mclock.System{})) } + return nil } -func (c *Client) Stop() { +func (c *Client) Stop() error { + c.engineClient.stop() + c.chainHeadSub.Unsubscribe() c.scheduler.Stop() + return nil } diff --git a/beacon/blsync/config.go b/beacon/blsync/config.go index b51d3e2b0566..1b0b0dbff935 100644 --- a/beacon/blsync/config.go +++ b/beacon/blsync/config.go @@ -39,7 +39,8 @@ var ( AddFork("GENESIS", 0, []byte{0, 0, 0, 0}). AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}). AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}). - AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}), + AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}). + AddFork("DENEB", 269568, []byte{4, 0, 0, 0}), Checkpoint: common.HexToHash("0x388be41594ec7d6a6894f18c73f3469f07e2c19a803de4755d335817ed8e2e5a"), } @@ -51,7 +52,8 @@ var ( AddFork("GENESIS", 0, []byte{144, 0, 0, 105}). AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}). AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}). - AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}), + AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}). + AddFork("DENEB", 132608, []byte{144, 0, 0, 115}), Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"), } @@ -63,7 +65,8 @@ var ( AddFork("GENESIS", 0, []byte{0, 0, 16, 32}). AddFork("ALTAIR", 36660, []byte{1, 0, 16, 32}). AddFork("BELLATRIX", 112260, []byte{2, 0, 16, 32}). - AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}), + AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}). + AddFork("DENEB", 231680, []byte{4, 0, 16, 32}), Checkpoint: common.HexToHash("0x53a0f4f0a378e2c4ae0a9ee97407eb69d0d737d8d8cd0a5fb1093f42f7b81c49"), } ) diff --git a/beacon/blsync/engineclient.go b/beacon/blsync/engineclient.go new file mode 100644 index 000000000000..5a2d292a7d22 --- /dev/null +++ b/beacon/blsync/engineclient.go @@ -0,0 +1,147 @@ +// Copyright 2024 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 blsync + +import ( + "context" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum/beacon/engine" + "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" + ctypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" +) + +type engineClient struct { + config *lightClientConfig + rpc *rpc.Client + rootCtx context.Context + cancelRoot context.CancelFunc + wg sync.WaitGroup +} + +func startEngineClient(config *lightClientConfig, rpc *rpc.Client, headCh <-chan types.ChainHeadEvent) *engineClient { + ctx, cancel := context.WithCancel(context.Background()) + ec := &engineClient{ + config: config, + rpc: rpc, + rootCtx: ctx, + cancelRoot: cancel, + } + ec.wg.Add(1) + go ec.updateLoop(headCh) + return ec +} + +func (ec *engineClient) stop() { + ec.cancelRoot() + ec.wg.Wait() +} + +func (ec *engineClient) updateLoop(headCh <-chan types.ChainHeadEvent) { + defer ec.wg.Done() + + for { + select { + case <-ec.rootCtx.Done(): + return + + case event := <-headCh: + if ec.rpc == nil { // dry run, no engine API specified + log.Info("New execution block retrieved", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "finalized", event.Finalized) + continue + } + + fork := ec.config.ForkAtEpoch(event.BeaconHead.Epoch()) + forkName := strings.ToLower(fork.Name) + + if status, err := ec.callNewPayload(forkName, event); err == nil { + log.Info("Successful NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "status", status) + } else { + log.Error("Failed NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "error", err) + } + + if status, err := ec.callForkchoiceUpdated(forkName, event); err == nil { + log.Info("Successful ForkchoiceUpdated", "head", event.Block.Hash(), "status", status) + } else { + log.Error("Failed ForkchoiceUpdated", "head", event.Block.Hash(), "error", err) + } + } + } +} + +func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent) (string, error) { + execData := engine.BlockToExecutableData(event.Block, nil, nil).ExecutionPayload + + var ( + method string + params = []any{execData} + ) + switch fork { + case "deneb": + method = "engine_newPayloadV3" + parentBeaconRoot := event.BeaconHead.ParentRoot + blobHashes := collectBlobHashes(event.Block) + params = append(params, blobHashes, parentBeaconRoot) + case "capella": + method = "engine_newPayloadV2" + default: + method = "engine_newPayloadV1" + } + + ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5) + defer cancel() + var resp engine.PayloadStatusV1 + err := ec.rpc.CallContext(ctx, &resp, method, params...) + return resp.Status, err +} + +func collectBlobHashes(b *ctypes.Block) []common.Hash { + list := make([]common.Hash, 0) + for _, tx := range b.Transactions() { + list = append(list, tx.BlobHashes()...) + } + return list +} + +func (ec *engineClient) callForkchoiceUpdated(fork string, event types.ChainHeadEvent) (string, error) { + update := engine.ForkchoiceStateV1{ + HeadBlockHash: event.Block.Hash(), + SafeBlockHash: event.Finalized, + FinalizedBlockHash: event.Finalized, + } + + var method string + switch fork { + case "deneb": + method = "engine_forkchoiceUpdatedV3" + case "capella": + method = "engine_forkchoiceUpdatedV2" + default: + method = "engine_forkchoiceUpdatedV1" + } + + ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5) + defer cancel() + var resp engine.ForkChoiceResponse + err := ec.rpc.CallContext(ctx, &resp, method, update, nil) + return resp.PayloadStatus.Status, err +} diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index fd701dc0a871..7e5ac38420b2 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -30,9 +30,6 @@ import ( "github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/protolambda/zrnt/eth2/beacon/capella" - "github.com/protolambda/zrnt/eth2/configs" - "github.com/protolambda/ztyp/tree" ) var ( @@ -68,9 +65,9 @@ type jsonBeaconHeader struct { } type jsonHeaderWithExecProof struct { - Beacon types.Header `json:"beacon"` - Execution *capella.ExecutionPayloadHeader `json:"execution"` - ExecutionBranch merkle.Values `json:"execution_branch"` + Beacon types.Header `json:"beacon"` + Execution json.RawMessage `json:"execution"` + ExecutionBranch merkle.Values `json:"execution_branch"` } // UnmarshalJSON unmarshals from JSON. @@ -244,33 +241,44 @@ func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) { func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) { var data struct { - Data struct { + Version string + Data struct { Attested jsonHeaderWithExecProof `json:"attested_header"` Finalized jsonHeaderWithExecProof `json:"finalized_header"` FinalityBranch merkle.Values `json:"finality_branch"` Aggregate types.SyncAggregate `json:"sync_aggregate"` SignatureSlot common.Decimal `json:"signature_slot"` - } `json:"data"` + } } if err := json.Unmarshal(enc, &data); err != nil { return types.FinalityUpdate{}, err } - + // Decode the execution payload headers. + attestedExecHeader, err := types.ExecutionHeaderFromJSON(data.Version, data.Data.Attested.Execution) + if err != nil { + return types.FinalityUpdate{}, fmt.Errorf("invalid attested header: %v", err) + } + finalizedExecHeader, err := types.ExecutionHeaderFromJSON(data.Version, data.Data.Finalized.Execution) + if err != nil { + return types.FinalityUpdate{}, fmt.Errorf("invalid finalized header: %v", err) + } + // Perform sanity checks. if len(data.Data.Aggregate.Signers) != params.SyncCommitteeBitmaskSize { return types.FinalityUpdate{}, errors.New("invalid sync_committee_bits length") } if len(data.Data.Aggregate.Signature) != params.BLSSignatureSize { return types.FinalityUpdate{}, errors.New("invalid sync_committee_signature length") } + return types.FinalityUpdate{ Attested: types.HeaderWithExecProof{ Header: data.Data.Attested.Beacon, - PayloadHeader: data.Data.Attested.Execution, + PayloadHeader: attestedExecHeader, PayloadBranch: data.Data.Attested.ExecutionBranch, }, Finalized: types.HeaderWithExecProof{ Header: data.Data.Finalized.Beacon, - PayloadHeader: data.Data.Finalized.Execution, + PayloadHeader: finalizedExecHeader, PayloadBranch: data.Data.Finalized.ExecutionBranch, }, FinalityBranch: data.Data.FinalityBranch, @@ -359,27 +367,30 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types return checkpoint, nil } -func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*capella.BeaconBlock, error) { +func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconBlock, error) { resp, err := api.httpGetf("/eth/v2/beacon/blocks/0x%x", blockRoot) if err != nil { return nil, err } var beaconBlockMessage struct { - Data struct { - Message capella.BeaconBlock `json:"message"` - } `json:"data"` + Version string + Data struct { + Message json.RawMessage `json:"message"` + } } if err := json.Unmarshal(resp, &beaconBlockMessage); err != nil { return nil, fmt.Errorf("invalid block json data: %v", err) } - beaconBlock := new(capella.BeaconBlock) - *beaconBlock = beaconBlockMessage.Data.Message - root := common.Hash(beaconBlock.HashTreeRoot(configs.Mainnet, tree.GetHashFn())) - if root != blockRoot { - return nil, fmt.Errorf("Beacon block root hash mismatch (expected: %x, got: %x)", blockRoot, root) + block, err := types.BlockFromJSON(beaconBlockMessage.Version, beaconBlockMessage.Data.Message) + if err != nil { + return nil, err + } + computedRoot := block.Root() + if computedRoot != blockRoot { + return nil, fmt.Errorf("Beacon block root hash mismatch (expected: %x, got: %x)", blockRoot, computedRoot) } - return beaconBlock, nil + return block, nil } func decodeHeadEvent(enc []byte) (uint64, common.Hash, error) { @@ -456,7 +467,7 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() select { case event, ok := <-stream.Events: if !ok { - break + return } switch event.Event() { case "head": @@ -482,7 +493,7 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() } case err, ok := <-stream.Errors: if !ok { - break + return } listener.OnError(err) } diff --git a/beacon/types/beacon_block.go b/beacon/types/beacon_block.go new file mode 100644 index 000000000000..370152114a45 --- /dev/null +++ b/beacon/types/beacon_block.go @@ -0,0 +1,110 @@ +// Copyright 2024 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 types + +import ( + "encoding/json" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/protolambda/zrnt/eth2/beacon/capella" + zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/protolambda/zrnt/eth2/beacon/deneb" + "github.com/protolambda/zrnt/eth2/configs" + "github.com/protolambda/ztyp/tree" +) + +type blockObject interface { + HashTreeRoot(spec *zrntcommon.Spec, hFn tree.HashFn) zrntcommon.Root + Header(spec *zrntcommon.Spec) *zrntcommon.BeaconBlockHeader +} + +// BeaconBlock represents a full block in the beacon chain. +type BeaconBlock struct { + blockObj blockObject +} + +// BlockFromJSON decodes a beacon block from JSON. +func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) { + var obj blockObject + switch forkName { + case "deneb": + obj = new(deneb.BeaconBlock) + case "capella": + obj = new(capella.BeaconBlock) + default: + return nil, fmt.Errorf("unsupported fork: " + forkName) + } + if err := json.Unmarshal(data, obj); err != nil { + return nil, err + } + return &BeaconBlock{obj}, nil +} + +// NewBeaconBlock wraps a ZRNT block. +func NewBeaconBlock(obj blockObject) *BeaconBlock { + switch obj := obj.(type) { + case *capella.BeaconBlock: + return &BeaconBlock{obj} + case *deneb.BeaconBlock: + return &BeaconBlock{obj} + default: + panic(fmt.Errorf("unsupported block type %T", obj)) + } +} + +// Slot returns the slot number of the block. +func (b *BeaconBlock) Slot() uint64 { + switch obj := b.blockObj.(type) { + case *capella.BeaconBlock: + return uint64(obj.Slot) + case *deneb.BeaconBlock: + return uint64(obj.Slot) + default: + panic(fmt.Errorf("unsupported block type %T", b.blockObj)) + } +} + +// ExecutionPayload parses and returns the execution payload of the block. +func (b *BeaconBlock) ExecutionPayload() (*types.Block, error) { + switch obj := b.blockObj.(type) { + case *capella.BeaconBlock: + return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot) + case *deneb.BeaconBlock: + return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot) + default: + panic(fmt.Errorf("unsupported block type %T", b.blockObj)) + } +} + +// Header returns the block's header data. +func (b *BeaconBlock) Header() Header { + switch obj := b.blockObj.(type) { + case *capella.BeaconBlock: + return headerFromZRNT(obj.Header(configs.Mainnet)) + case *deneb.BeaconBlock: + return headerFromZRNT(obj.Header(configs.Mainnet)) + default: + panic(fmt.Errorf("unsupported block type %T", b.blockObj)) + } +} + +// Root computes the SSZ root hash of the block. +func (b *BeaconBlock) Root() common.Hash { + return common.Hash(b.blockObj.HashTreeRoot(configs.Mainnet, tree.GetHashFn())) +} diff --git a/beacon/types/beacon_block_test.go b/beacon/types/beacon_block_test.go new file mode 100644 index 000000000000..d5920e805ada --- /dev/null +++ b/beacon/types/beacon_block_test.go @@ -0,0 +1,77 @@ +// Copyright 2024 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 types + +import ( + "os" + "path/filepath" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func TestBlockFromJSON(t *testing.T) { + type blocktest struct { + file string + version string + wantSlot uint64 + wantBlockNumber uint64 + wantBlockHash common.Hash + } + tests := []blocktest{ + { + file: "block_deneb.json", + version: "deneb", + wantSlot: 8631513, + wantBlockNumber: 19431837, + wantBlockHash: common.HexToHash("0x4cf7d9108fc01b50023ab7cab9b372a96068fddcadec551630393b65acb1f34c"), + }, + { + file: "block_capella.json", + version: "capella", + wantSlot: 7378495, + wantBlockNumber: 18189758, + wantBlockHash: common.HexToHash("0x802acf5c350f4252e31d83c431fcb259470250fa0edf49e8391cfee014239820"), + }, + } + + for _, test := range tests { + t.Run(test.file, func(t *testing.T) { + data, err := os.ReadFile(filepath.Join("testdata", test.file)) + if err != nil { + t.Fatal(err) + } + beaconBlock, err := BlockFromJSON(test.version, data) + if err != nil { + t.Fatal(err) + } + if beaconBlock.Slot() != test.wantSlot { + t.Errorf("wrong slot number %d", beaconBlock.Slot()) + } + execBlock, err := beaconBlock.ExecutionPayload() + if err != nil { + t.Fatalf("payload extraction failed: %v", err) + } + if execBlock.NumberU64() != test.wantBlockNumber { + t.Errorf("wrong block number: %v", execBlock.NumberU64()) + } + if execBlock.Hash() != test.wantBlockHash { + t.Errorf("wrong block hash: %v", execBlock.Hash()) + } + }) + } +} diff --git a/beacon/types/config.go b/beacon/types/config.go index 8cb8808b6f02..a52da5212eee 100644 --- a/beacon/types/config.go +++ b/beacon/types/config.go @@ -37,7 +37,7 @@ const syncCommitteeDomain = 7 // Fork describes a single beacon chain fork and also stores the calculated // signature domain used after this fork. type Fork struct { - // Name of the fork in the chain config (config.yaml) file{ + // Name of the fork in the chain config (config.yaml) file Name string // Epoch when given fork version is activated @@ -110,6 +110,16 @@ type ChainConfig struct { Forks Forks } +// ForkAtEpoch returns the latest active fork at the given epoch. +func (c *ChainConfig) ForkAtEpoch(epoch uint64) Fork { + for i := len(c.Forks) - 1; i >= 0; i-- { + if c.Forks[i].Epoch <= epoch { + return *c.Forks[i] + } + } + return Fork{} +} + // AddFork adds a new item to the list of forks. func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig { fork := &Fork{ diff --git a/beacon/types/exec_header.go b/beacon/types/exec_header.go new file mode 100644 index 000000000000..3085c3de6978 --- /dev/null +++ b/beacon/types/exec_header.go @@ -0,0 +1,80 @@ +// Copyright 2024 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 types + +import ( + "encoding/json" + "fmt" + + "github.com/ethereum/go-ethereum/beacon/merkle" + "github.com/ethereum/go-ethereum/common" + "github.com/protolambda/zrnt/eth2/beacon/capella" + zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/protolambda/zrnt/eth2/beacon/deneb" + "github.com/protolambda/ztyp/tree" +) + +type headerObject interface { + HashTreeRoot(hFn tree.HashFn) zrntcommon.Root +} + +type ExecutionHeader struct { + obj headerObject +} + +// HeaderFromJSON decodes an execution header from JSON data provided by +// the beacon chain API. +func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, error) { + var obj headerObject + switch forkName { + case "capella": + obj = new(capella.ExecutionPayloadHeader) + case "deneb": + obj = new(deneb.ExecutionPayloadHeader) + default: + return nil, fmt.Errorf("unsupported fork: " + forkName) + } + if err := json.Unmarshal(data, obj); err != nil { + return nil, err + } + return &ExecutionHeader{obj: obj}, nil +} + +func NewExecutionHeader(obj headerObject) *ExecutionHeader { + switch obj.(type) { + case *capella.ExecutionPayloadHeader: + case *deneb.ExecutionPayloadHeader: + default: + panic(fmt.Errorf("unsupported ExecutionPayloadHeader type %T", obj)) + } + return &ExecutionHeader{obj: obj} +} + +func (eh *ExecutionHeader) PayloadRoot() merkle.Value { + return merkle.Value(eh.obj.HashTreeRoot(tree.GetHashFn())) +} + +func (eh *ExecutionHeader) BlockHash() common.Hash { + switch obj := eh.obj.(type) { + case *capella.ExecutionPayloadHeader: + return common.Hash(obj.BlockHash) + case *deneb.ExecutionPayloadHeader: + return common.Hash(obj.BlockHash) + default: + panic(fmt.Errorf("unsupported ExecutionPayloadHeader type %T", obj)) + } +} diff --git a/beacon/types/exec_payload.go b/beacon/types/exec_payload.go new file mode 100644 index 000000000000..604de288d269 --- /dev/null +++ b/beacon/types/exec_payload.go @@ -0,0 +1,144 @@ +// Copyright 2024 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 types + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/trie" + "github.com/holiman/uint256" + "github.com/protolambda/zrnt/eth2/beacon/capella" + zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" + "github.com/protolambda/zrnt/eth2/beacon/deneb" +) + +type payloadType interface { + *capella.ExecutionPayload | *deneb.ExecutionPayload +} + +// convertPayload converts a beacon chain execution payload to types.Block. +func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*types.Block, error) { + var ( + header types.Header + transactions []*types.Transaction + withdrawals []*types.Withdrawal + expectedHash [32]byte + err error + ) + switch p := any(payload).(type) { + case *capella.ExecutionPayload: + convertCapellaHeader(p, &header) + transactions, err = convertTransactions(p.Transactions, &header) + if err != nil { + return nil, err + } + withdrawals = convertWithdrawals(p.Withdrawals, &header) + expectedHash = p.BlockHash + case *deneb.ExecutionPayload: + convertDenebHeader(p, common.Hash(*parentRoot), &header) + transactions, err = convertTransactions(p.Transactions, &header) + if err != nil { + return nil, err + } + withdrawals = convertWithdrawals(p.Withdrawals, &header) + expectedHash = p.BlockHash + default: + panic("unsupported block type") + } + + block := types.NewBlockWithHeader(&header) + block = block.WithBody(transactions, nil) + block = block.WithWithdrawals(withdrawals) + hash := block.Hash() + if hash != expectedHash { + return block, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash) + } + return block, nil +} + +func convertCapellaHeader(payload *capella.ExecutionPayload, h *types.Header) { + // note: h.TxHash is set in convertTransactions + h.ParentHash = common.Hash(payload.ParentHash) + h.UncleHash = types.EmptyUncleHash + h.Coinbase = common.Address(payload.FeeRecipient) + h.Root = common.Hash(payload.StateRoot) + h.ReceiptHash = common.Hash(payload.ReceiptsRoot) + h.Bloom = types.Bloom(payload.LogsBloom) + h.Difficulty = common.Big0 + h.Number = new(big.Int).SetUint64(uint64(payload.BlockNumber)) + h.GasLimit = uint64(payload.GasLimit) + h.GasUsed = uint64(payload.GasUsed) + h.Time = uint64(payload.Timestamp) + h.Extra = []byte(payload.ExtraData) + h.MixDigest = common.Hash(payload.PrevRandao) + h.Nonce = types.BlockNonce{} + h.BaseFee = (*uint256.Int)(&payload.BaseFeePerGas).ToBig() +} + +func convertDenebHeader(payload *deneb.ExecutionPayload, parentRoot common.Hash, h *types.Header) { + // note: h.TxHash is set in convertTransactions + h.ParentHash = common.Hash(payload.ParentHash) + h.UncleHash = types.EmptyUncleHash + h.Coinbase = common.Address(payload.FeeRecipient) + h.Root = common.Hash(payload.StateRoot) + h.ReceiptHash = common.Hash(payload.ReceiptsRoot) + h.Bloom = types.Bloom(payload.LogsBloom) + h.Difficulty = common.Big0 + h.Number = new(big.Int).SetUint64(uint64(payload.BlockNumber)) + h.GasLimit = uint64(payload.GasLimit) + h.GasUsed = uint64(payload.GasUsed) + h.Time = uint64(payload.Timestamp) + h.Extra = []byte(payload.ExtraData) + h.MixDigest = common.Hash(payload.PrevRandao) + h.Nonce = types.BlockNonce{} + h.BaseFee = (*uint256.Int)(&payload.BaseFeePerGas).ToBig() + // new in deneb + h.BlobGasUsed = (*uint64)(&payload.BlobGasUsed) + h.ExcessBlobGas = (*uint64)(&payload.ExcessBlobGas) + h.ParentBeaconRoot = &parentRoot +} + +func convertTransactions(list zrntcommon.PayloadTransactions, execHeader *types.Header) ([]*types.Transaction, error) { + txs := make([]*types.Transaction, len(list)) + for i, opaqueTx := range list { + var tx types.Transaction + if err := tx.UnmarshalBinary(opaqueTx); err != nil { + return nil, fmt.Errorf("failed to parse tx %d: %v", i, err) + } + txs[i] = &tx + } + execHeader.TxHash = types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)) + return txs, nil +} + +func convertWithdrawals(list zrntcommon.Withdrawals, execHeader *types.Header) []*types.Withdrawal { + withdrawals := make([]*types.Withdrawal, len(list)) + for i, w := range list { + withdrawals[i] = &types.Withdrawal{ + Index: uint64(w.Index), + Validator: uint64(w.ValidatorIndex), + Address: common.Address(w.Address), + Amount: uint64(w.Amount), + } + } + wroot := types.DeriveSha(types.Withdrawals(withdrawals), trie.NewStackTrie(nil)) + execHeader.WithdrawalsHash = &wroot + return withdrawals +} diff --git a/beacon/types/header.go b/beacon/types/header.go index 2ddc4575f175..c8388df1e7bf 100644 --- a/beacon/types/header.go +++ b/beacon/types/header.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/beacon/merkle" "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/common" + zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" ) //go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go @@ -57,6 +58,16 @@ type Header struct { BodyRoot common.Hash `gencodec:"required" json:"body_root"` } +func headerFromZRNT(zh *zrntcommon.BeaconBlockHeader) Header { + return Header{ + Slot: uint64(zh.Slot), + ProposerIndex: uint64(zh.ProposerIndex), + ParentRoot: common.Hash(zh.ParentRoot), + StateRoot: common.Hash(zh.StateRoot), + BodyRoot: common.Hash(zh.BodyRoot), + } +} + // headerMarshaling is a field type overrides for gencodec. type headerMarshaling struct { Slot common.Decimal diff --git a/beacon/types/light_sync.go b/beacon/types/light_sync.go index ed62d237f126..62becdb21cfd 100644 --- a/beacon/types/light_sync.go +++ b/beacon/types/light_sync.go @@ -20,12 +20,10 @@ import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/beacon/merkle" "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/common" - "github.com/protolambda/zrnt/eth2/beacon/capella" - "github.com/protolambda/ztyp/tree" + "github.com/ethereum/go-ethereum/core/types" ) // HeadInfo represents an unvalidated new head announcement. @@ -146,12 +144,12 @@ func (u UpdateScore) BetterThan(w UpdateScore) bool { type HeaderWithExecProof struct { Header - PayloadHeader *capella.ExecutionPayloadHeader + PayloadHeader *ExecutionHeader PayloadBranch merkle.Values } func (h *HeaderWithExecProof) Validate() error { - payloadRoot := merkle.Value(h.PayloadHeader.HashTreeRoot(tree.GetHashFn())) + payloadRoot := h.PayloadHeader.PayloadRoot() return merkle.VerifyProof(h.BodyRoot, params.BodyIndexExecPayload, h.PayloadBranch, payloadRoot) } @@ -187,6 +185,7 @@ func (u *FinalityUpdate) Validate() error { // latest accepted head of the beacon chain, along with the hash of the latest // finalized execution block. type ChainHeadEvent struct { - HeadBlock *engine.ExecutableData - Finalized common.Hash + BeaconHead Header + Block *types.Block + Finalized common.Hash } diff --git a/beacon/types/testdata/block_capella.json b/beacon/types/testdata/block_capella.json new file mode 100644 index 000000000000..fa6149ada289 --- /dev/null +++ b/beacon/types/testdata/block_capella.json @@ -0,0 +1,1703 @@ +{ + "slot": "7378495", + "proposer_index": "806393", + "parent_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "state_root": "0xb699414b8cae77b7cc01cb3ea5d218062dc534fee640759ef504f1f1f43cf693", + "body": { + "randao_reveal": "0xb9b9101090eabc8d0060ddb91f88bcf579c236883e8b3da0e0192466f5b5739af17b8b7a942036edb28637d1ede61e6c1388e62999b34ea9d54c3b9f1c3683cb58c6dae377b49bc3f604ba7698137c69f7c94108ad29b8de48cd74fc6f173ac1", + "eth1_data": { + "deposit_root": "0x79a2ad4067ee252dc60760a40c00ca5536906668eba5a9e7f7a30fa3b078fddc", + "deposit_count": "970997", + "block_hash": "0xf4fe68e4dab126c3c8fded4c7c825c6cda8b460c81b1a8c3c0b6e10b33e3a4c4" + }, + "graffiti": "0x0000000000000000000000000000000000000000000000000000000000000000", + "proposer_slashings": [], + "attester_slashings": [], + "attestations": [ + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "20", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x89a2fdc5d13638100251a3a447bfbebb205b23e87671f2d0744a1685eed149e5377f9b893ce2cbba559df9ca48cfa075160dbe5d531ed7e32f8ae0a371c38d46c15eedfc1f73dd824fd81607dc84660b97552137af6e7b28ddfe58f457c70091" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "5", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb1c2789fa06b3c2e0019597c54df891c24ef30c8a0c3a2aa2d0ab95b332af97525d4f42518705eebeff6176c87d401e8135711345620a17364f8ad9b7c96ec9973f749d2d05208012e3d25699565f8046752c33c4508ee6d3d3955ca01942a83" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "37", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x825e16bb91abafd316b9d1be810435bb07635a8cd28204e5a1b60f4b2604b085fc6b51850e32d86c137720c1b9e515ae0fc882551f037ba4549d74f686efe48517261eced01174ca699e32e1a42b98d1e2eb523db1e03d7d40be5543c8338645" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "35", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xaff3a1152b91ee89a5557bc852374ce81497663e9a4a18df47cebe59bc926d5845c7f550bb6e55e172c14b12afd7ae3e13c78dc7f256637daa1f0ad66d1d859ff025a379d7c021ff1b4825d6a044a9775254ac0674665d4b361d605fbc6fce18" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "60", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xac7a6651bc4a755414570d441298a7840755bda19fa8b77393e544ece6c917dcb0d0cd092a2b7ec347745c504a626fb70ab0951f48743d872fe21af088668dc29c96f7550d70c34f8f11844c091ed8536696180f5ccc3a9c55b287ce6c709853" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "24", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x92d538e3c9fffd7beb7e408b590c4cf084bc9d9e55fb49d1f84c3da36453c6754b434f47c84139c962c8b0fef8ead19901338417ee0c157e946b987c65babdf767f508981174986a89a5505061406e63f2630dbb5553542dfb7b23993aa27aa5" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "13", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8511a4bb585749da9b9d309172d33358092a07574f213459b618259e38daf493dcad876be2370006c132b384d6997cfe190fa9005f151eb489a5bb1d3cca9491ead28bf3b1874a00612f6a5616757b99109abf42e08fbc7d5a9d4808a72b161f" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "14", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xab5c1637d860eaf8700e1da67df1ffc763cdc0bea2c31261329c6d7d619c9566b0bcdcba1d6a0d2a546dd730d233469d0eeb21dbdba538eae77c9dce5e6953b89a0b47c5a25378b89aefb8a3cb387f10b8ad5b3d4e22b4c7ed6bc99e418ad393" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "54", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb1528f2cb78dda3644816272ec4c24bcc5c554075d3499f48f66f8a3056b5b644acc68733427309567876955199520e50ce72c462d9b4641fd0bd9ff6310a1456b2160d3a12055d37a2d44b8a8739ac04a3f3d498e2b67695f6bd514a9988567" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "16", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb5c2376070b13b792d91ddd3afcb98a15a59f6582a5654264e850064984b2c8f0ae5df8b45b7fe469caa55dedc9ab8950b7bbd375ab1a5de3f20e1aea85be31c3d8c27f3aea8fbd85769ac39e2718ee3aaa4060f7b6290abd3d8a7969a129a8b" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "3", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8e587c9dee7f54e2d9c1058a4afbc28b32f4e45d51303078fa7405cb1a50b8dba1a70dcd4babea8ba37bf9c9e2a1504e007eefc13e2040ee7d11e741e6fa58474347dc490af39868caf2c7c6ffbab90fa4429b068b0673fa7b811ccd847ff9a1" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "31", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x95eb7f201e93f10df263956eb26f3f0e9f0d8db2588d845f0f50314f76ab5b33c87849d7546d56ee99ce6a1b0fe6e67b11e6a813aad3f04f61763772091471f65a1f976a0d2180e58f5db3e54dc16ef7f2b3f20445be68ea1a6701f7d6c6b4a4" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "28", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x97e8426a39404686826704f6f7ab5eb31c532f64352b0e756aa95f4a6742e733053d8bc7e8b44076eed03802dd6a154a177933582503fdfce82b0472e9a7b8c250f0cb7a2c153ad43736c0613004f5b4e915109ed64eeb445453c59a7f51cbb6" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffff3f", + "data": { + "slot": "7378494", + "index": "62", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x861eda1e26cb7866100650538319a266f2c946986db3c90349ac88de7e8ba30d5970454d19b91543d29c1616197e98c2020c3fd54b726cb06249075a0969f16a492282ff60e7d7e656e206eef371ea6cd51cbeb4aed25809077a3c389d505e33" + }, + { + "aggregation_bits": "0xfffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "11", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xadf1e3e7a66cff8cd606f8142fa2341583870f0ee406bf9ce9dc1b85ce004ce42b1425f27c18986afac16b80df70264d0f3ae1b22f5d7d3b34ae88f5f18a37a74ee67c7c1eb0d593d98dcf30b8b18dfe8db9359dbf9737c018ad78da4a07fe55" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "61", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x85dabe8ab392970b7ab10a6415ce2d2c928dee022a148c096c6626c1431a305912a96d267c173d3a388e167fad9586fc0367703c97f6e3d80de3576ce2acc136c69d86f14e611860a29f425593ac0cf1639e8adb49a580051823603bc4fa1871" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff3f", + "data": { + "slot": "7378494", + "index": "9", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x91370c8bfd2b5a47aeeac66693bc824ccc4ddbfe4bb90520efdd60ea0c93083638b21d1574fbf6cc3bbf88094ad9e2e5019c3d1dc316c68ed81129cfae87860a45c7801ad180b2c69df9375b6a8b48ba3e33faf72d48745d2dffcce3199da875" + }, + { + "aggregation_bits": "0xffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "22", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x974181ffb8c8820580b1bb35a58c8cb2fbc5704a2b1f9c14101314eb3bcfddf558aad925785b0ce13dd4d3fd58adaf10168d9f06ac198161bd73e351b7fc37a5a9b6b62a4aa3b028a54779d9f16cbf6872a8339cb58c564808fade87ad7cf3cc" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffff3f", + "data": { + "slot": "7378494", + "index": "7", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x81ca3a2e57e8ce743313c8e83d42b9847d18f48835e1fe445e689fdaf7d72568984de9444a88ba9e7a01b4716581723a0cab39f739f6580ad7f0348c7c5a32d069b1c86efee80161142af6dcd84469f4dd5f19b53318dada988ce2304f7195c5" + }, + { + "aggregation_bits": "0xfffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "1", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x86757289ea9294712661b0c4da2afd17894bd43b1ac2e11a1627a50b0ebdeced615b11058919058356158005ff8d2363157d9be67f4a4600100f4547e7d2bc4b9ef14f81cd21dc42bdc207e3e22375b9737147b5a1cfdbef8959cf1d16d64beb" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "4", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8b8c158686252d39fe3c6edbefdcdedb99ebb7df7f66f6c18f2ab45baaf076c1ad889eca5d3621210f81dafa8055284b01da2e1c0e0309fdacee0dede2f4d33a707d539841488e40e45bd14bd38dc5df1758ec73a0a3dfb34d7be2b361bd5ee1" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "33", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x86ebe26268beda78609de2009ab037c042a8b96acecab1c001ec587fb9dbdb5693595d13b7c61e05cfee9eab79c400090a0c7222d08932956580e5ff0a76028da6375045c7e52ea4a8e0a547aa0464d6ebbcc2a72901e606232a2ff349f59cec" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "6", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x91caf7efebe5c9e719e69d69fb7985348f488391f8885368355fc6bfccd5923d9bbfeaacf6e88d060e6876cf388a3da808e63950e76a9f25b25b548b4e1fab691c7f4bad81021154eeb8066383b2519fb594e15f37938b8c821dd2742193c963" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "46", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x880458dab1b2c5f63576cc5d6de51cc53842c3f8cd491a045317e5cac9010aee197cd578bbc276c487c735b98cf2aa6303651e54475ac7dbd4dcdb5552300d369cd9ee5cab8d9741722d8452957844de93edb8d357f503717d179dca6faa7e78" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "19", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xae536d3961e78c85bf1756622f09ca64d0aca31d39042f32a28f8e7c72ce7778edf53cc997407735c97ecbb06ef49f8c08c33246ea80e9cccf86aa0644298b9ed2398336f88ed054521b94f0ed7d61af4e28c516889e2177ebef4f180bbf2ab1" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "26", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x9822678731a8db092b5e007e53c7e5e7f396a102bec255d3773613a93773bac1608b2530a83d467825872bebf6403d9d0696ab837309b82fbd0fb09365d7d1ce20c19f1abe44bc17550483c5e2e8ec5b630443ab338c522626b9dc692100177a" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "45", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8cf67eaa40f2095c91c19f4a8eea844266d0a9b91211c38d8fa0552cbe41578db864463b292184239eb8a4c64139510c0cb4b7f419d5447f812e4f6b2f3665fb8f717cf07f7e76ea196de7f16711d32d3a9cc357cb9d95b5599e31cf698b88eb" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "17", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x94ebbd88f4aa545d7a7fe44b4aadb74a31a84c38a7ac519ebbc26730a4046ba85a5f64585891b8a67b0822b454892ee816b92dd53fc81799b5f77e3771ac6db169ae99415c6d86cbdb973c826ee5c6869f5840ca86273254c4211981da262001" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "30", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x85b54e1443aeb87d78cfe00681c9d30a619b850a454c3b7e126c23c9bf2df0188f59c715dbac64adf1d93453eeeec7d605f5297b178107bae8ef2293bcbd0c3d8a73f924558b4331661951f5706472fd355a45589e3fea173db238355d0b8d60" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "18", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xafc699d33be631418d821a44f64648697e0921cf1dad336c04d3a4424b293ea70a680683f414e67565d837b55b027f1d04f3d0a0e9a42a4cf61ff977cfd23695e5f91890da6eea51bd46eb22085e1241e970788c17ae8f13288c04724caff17c" + }, + { + "aggregation_bits": "0xfeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "59", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb5d6da99f07a3afe87593ab930848c99fa7ddb352298c210faa0d131ccaea3727cf3389a8dc07d64c6312ffe93660293088e4332aeb60d0df51fa25bd7c922d15cd084db19ea8d69a42661738ae02a0370e99573c2db8b4ba7b6748a0fe15b74" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffeffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "58", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xafaa8a5ad8082a05db922f78205ae39fe45c364176f732f4697a35659d9cb803ac10b90729d11a3f35141095b478a939086b0a195430fc4efcbfc61ef4b79ff770c2b50e3949cb51f977541253877ed319b60d27027e29363b5fa4d8bf37f24a" + }, + { + "aggregation_bits": "0xfffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "42", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb3f70d94e80376f986498cf8c41eeb3376730c19fa0c14ca03dbff1d85180aa475865f4bd85485d0ba5c97f9918f38320ed3e0a2edd1ab159493c5956f1dd111ef85e0921105c7b77dc940401a94db4b62929e839035559072260aaa78f21bf1" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "32", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x886736358ded1b56826412fd3e604cd71832d88a597656a65ca1eae5121fa037148a2e2678f3c2369868e30937cfe7b011763f6bc9bb78107d9158b4048ad7eaf31348a2622541be4942e4f522fbffba520ee58002e8a4d71a3c5f7f040cdafe" + }, + { + "aggregation_bits": "0xfffffffffffffffbfffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "39", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8a8a8641c5c757b6a46dbf2500adb236cb100781588c9b156cf928f237f338620b1856fbc200c95c197b7f08ba89a8a606880a64b2b47ebbde066bb4694ea38795b54cc55f907e09f43eaa0cd4d868b57f0805d3aefd1538102acf295078cefc" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "53", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xa26e6c52b9e82f286ea699339e7156ad6e62590855063365c8beb4923e7b5f9bafcbbd40d476a70da97d452989b7b6c307ae8265e31d8ab35cd9d680b5ef4f277ee18c9167a81ec68a58c13447a23cc995807d6a2866d44e2afaa39333cfec71" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffffff1f", + "data": { + "slot": "7378494", + "index": "36", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x888547c6d5d294f66ce31b96a2357f7e27e72c8f76865310f83125f158bce9a1ad1506835086cc0bfe88bc2f94ff42de1823bbf61973372da2133f93d1a8d202f3a2d5ea75c446fbda5a834b2f143a7f24d30b1934e511ec8b218668705d2f0f" + }, + { + "aggregation_bits": "0xffffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "47", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xa35f8f9fd4848615e331c08e9088c434d27f885c1794e138cb6f2dacfbed501df2b07de14c9d0e7704fbb597e6bc8668058e0e838d7a2cd64301068db3e8f0b74991b1a81d2d4591a55ea6489a3b80f5ba2ba818f7907273bfa3aec702cab0f1" + }, + { + "aggregation_bits": "0xffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "29", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xa480ba3e3af31e33277863c46165f18ebd710838949b051496eaf1bd79ea361586d37959e398368905bb9fc55bcb48c80a8aff7420234640a34149905726653cb283a4d0f348f572ad0afaa8e42c74cae152ad20bad5615b2a65bc1657260e7a" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "21", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb0be1593527fe7e9bae75a9686dc8027610ffc969dab11c6f4a5b94e6c46e2e4f57022630da357da98c61fc877c8697010e2e15456fc2c4e74932f07ddbccd3fb3ba756f52365df96f9e7aea690554be43d03cb720d2c03d79af35d3b2a1f456" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffdffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "52", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8019f790aeb9e5d5de1c179a02b648b9936a5bced2e3f64eaeb0baa8ed794dcd55ef5a861e7401deb78af96cb83470340c8ff39e320db4e445359519a477740aa5f836aad885759d3759ecf4c56dcdea31b9299a5d476334778ad203656bcf4a" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffefffffffffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "56", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xabc0dfdbb7ea5255f92fae93243569d1362d47d4f67d44c25b38185d4ae2e3b02f812223531e901388f003dbdd4ec1841181e5bafe8f873c06b4e9f01b4701362bd89917c563ae077745e81a922371aed4e17669e3bf5e529743dccb8a5036b3" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "55", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x828866f494c35c712f5ac17f1dd259d9e527509cae8947089fbb1bbc10e6ba9f13cc237caa217c280d060b200cbb122807486307a42ff96c940ae27fd175c5337fa093ff3a64153fe7723e6a54981372875a5a82ff41bc675d4eadccc9e5884d" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "34", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8c77a3007d6fa118fd801dec53dbb8c58b133b319b03befddd022f001dd0b0480841161d38e8f833d128cbb959fab7e90bb1ab60aab531f6af4b77b102d713b2aee48536129b7a309dae9bb0371af7ce683748646087dae41fa528ecb579506c" + }, + { + "aggregation_bits": "0xffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "23", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xa790ea43694fce44a777b9071e1a9c7ff6b20783f9c6ed59dd90ceefa71ef770a1b4cbb8c23a295e019055e7fb004b99025dd54fd95b050dd13162ed1d861090db80fda95307ee0196d0faeaf8f83caabc33b332d603061d8de8b44ac9956e8b" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffdfffffffffffffffffffffffffffffffffffffffffffdfffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "25", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb4aa421f9d93f03a62f004c9b24e66253957f237fc548b9d60d5d51dbf6e99656c16aabfec33ab6c0765ed16745e33440650c42ce90e0ec4021524610d6ec7211b1bbff23ba913fbdd2505970213a9b890c0347f35f671b01d9bf0387e97631c" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffdffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "0", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x89726e95f463d159279178dd7abb677c507575ad4b0e59f52303af95983e1c5bba45e49df86f5ba88ea8c433b9b5beeb02ddbe75bbc3404d85355a0af642ce615051414897b6bb3fdf14787cac832f3a93ee3a83e00d412af3f5d513ee12152b" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffbfffffffff1f", + "data": { + "slot": "7378494", + "index": "57", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x818dab21ea1a34d31179a3db511b93f538399b1f898744b01b5c569a3c27107641d5c16c3d3a3367df8dfd28e8686143035b5334d595e30b0eab3739f248462bf2bfaa69a067cb2ce9c279630196f554d73912e38702fb1e5991b7003d1c3546" + }, + { + "aggregation_bits": "0xfffffffdfffffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "12", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb8cfc57942d455cd6a93d9a0cddd662c99d3f317a6e2585bc36399192d17111f9aa2fc5f7a5c80ba532c3a8a1bc3c46b08a2bb3b2db007eb7f78056332d8a9d903d11488022927f1a7c9d60c8c509089ca8ab30cf913a9aa7c45c91275287774" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffffffffffffbfffffffffffffffeffffffffff3f", + "data": { + "slot": "7378494", + "index": "48", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb5ec81bc92ea85c105acb162bd95daaa7daff124f5effa1b399ff6d92beddbc10d9c8a217b8a03e047f8c9644200e27605a7ee60068fbb01a1517bbfe383759ec24a553d621a5e5290a41e9b121fa13e82769ac40a450b30cac877871f90841e" + }, + { + "aggregation_bits": "0xffffffff7ffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdf3f", + "data": { + "slot": "7378494", + "index": "43", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xa40d82c6c4e71c5ee93e31d4987c016fb3933bc348ee33a7a9b6e9cd592377af9461138d40c1f1188541acc9b6a10bf4035820563a467a4c345125660188ad9f5ba433b4a6168757c37ba8f895faae87dca56b4e1940834ddd5765ebc7cd7dae" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffd7ffffff1f", + "data": { + "slot": "7378494", + "index": "27", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x9439508713ae98aa4a8614b4fe4de5738bf4935d00f769e3a8afadbc1880e87854918cc6f1cc1e4beb61672fa9ef944e147c469aca29bd2d0a924730cf618729269a11b3c65edc1b8dcb836bd670ab2fc0af20ee139ab2bc57de07412771d26d" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffbffffffffffffffffffffffff7fffffffff1f", + "data": { + "slot": "7378494", + "index": "49", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb67ecdb8a80153ee5f63d2f1afb1a5e9fbcadd280f015b3eaddd420126b5f550e0d2f1115781e29da657662c6e821a2d0014076059eadb67468e269d6fa277555f553e54d4810525ed31277644967c8f2a8ac98f95a406f055172ebc78f81650" + }, + { + "aggregation_bits": "0xffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffdffffffffffffffffffffffbffffffff1f", + "data": { + "slot": "7378494", + "index": "10", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x99ab8d38886fc33b205acd97c0c069c0fb3f55e5dccd70611c1f159b73e0d3d20a91997f4b3e93f80bac42c99ea92b5d1460a78b53f335c0de7f9d04f77ac59bbbc141fdfeabadb1125a5ecff7d9d421c6d553837d34eece99ac2a59f3938af1" + }, + { + "aggregation_bits": "0xffeffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffdfffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "15", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x922c40a03459860e7b32df69fb2f1153e0c52601a08e7716d8a637a0ad2eb717ddd8f90d95d71c77f1baff1d9c386c2d1627c9ae755698ba3a1d5bd62dd4343c708da623db4c8aead3c52d309aaf3fff7b90a8ea739ab076f2e623227efe57a1" + }, + { + "aggregation_bits": "0xfffffffffffffffffffdfffffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffffdfffffffff1f", + "data": { + "slot": "7378494", + "index": "40", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb6b43e392a1ee37d435a900be9fdcc1e4802c87fdfe441570f6869a61c8e2de9efcf80e266d3dc4bab4aa70f0fc99dff1424d5eddbe179b4abe8c356f948a7309290ce791de8af16410727ddede4b8a8fdf20fcc3496495825a15a9cca07f04e" + }, + { + "aggregation_bits": "0xfffdfffffffffffffffffffeffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "2", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x979301b9636dc5decc492df123920c28464ea97c2630e300d44c4b6d700a2f21d46f1b922763517b0e8234c7724f146505c18b0397b613aa2e1bd2fbca5266f03fc113af517726c7fc70aa930ee95365f32cc552d779447622b1b27dbd9394f2" + }, + { + "aggregation_bits": "0xfeffffffffffffffffffffffffffffffffffefffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffef3f", + "data": { + "slot": "7378494", + "index": "50", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb06352fe674ca8af724db3c28eece93c8ffd29b12d1db38f04dc7a4d74c454899aa0a17e821d7b768ed3c5c849b559270126a0f2572cc7076b9278289d79415817691d7c3519666603f2b0ca8f80dfdfdbbed87ed8fe328bced445aa9764b684" + }, + { + "aggregation_bits": "0xfffffffff7fffffdfffffffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fff1f", + "data": { + "slot": "7378494", + "index": "44", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xad45143668483fc7aaae6cd3f46caf4461bd543a062679ee3c8c786947d580fcc20b358858606edf65d21c512965aeec11fbfb0f9dd3212e9b04b4fc683fd69a2dc2991a9297963fa683c0806948310b645cadc76f7208ce44c05c5f127ea110" + }, + { + "aggregation_bits": "0xfdbffffffffffffffffffffffffffffeffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffff1f", + "data": { + "slot": "7378494", + "index": "38", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xa34e85836b67b56d722c02c0cbbfd44492f0f8ffeacc9deed8e1ec8efb2180d1818e102451eb9571f4e265a20e73ac4702fcb55ef2012aea7bc2a73efdaf24e6e81d01aed51d937a17df21b4bb9cc5945dd5a5fb2d7a14d727283ec2d5cd3ee6" + }, + { + "aggregation_bits": "0xfffffffffffffffffffeffffffffffffffffbffffffffffdfffffffffffffffffffffffffeffffffffffdfffffffffffff3f", + "data": { + "slot": "7378494", + "index": "63", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x95697e4ab24617346af013bdb607a4cd9ba68647ecf77adff969fb25cd2849a0f0947a71dac14cc75bac28f13b88490701cc5c1e3d8578a147c9fb2ea5ea0641464d4702bf2ce4ff733331d6946787f142fc2dbc2a31c5d4bdb859d5464c6c41" + }, + { + "aggregation_bits": "0xfffeefffffffffffffffffffbfffffffffffffffffffffffffffffffffdfffffffff7fffffffffffffffffffffffffffff3f", + "data": { + "slot": "7378494", + "index": "41", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xabc2f9ce23e03325784b4fa68950f36f93c9b51df97040402e72b4edd7fbed17f624632e666ca725a8044906b2643ce10cf1eaf55cf661e0ef9d6024a013ae4eecf14d2952cdde2169d8f2dba7b28dc7d48465f0a87f2b3c6b3a287c4ea5e63d" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffdfffdffffffffffff7fffdffffffffffffffffffffffffff7fffffffffef1f", + "data": { + "slot": "7378494", + "index": "51", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xaf2d02761082aff8842a44321c687d8722aebea6611d1d65873f50515b751cf67eb5929fb99c3a8818929d2d7e8bda97189c3589a5b99f8b027464017208e7ec79e3fd0a4b88c5df1ce277d6da7ae9d9b675cbe00ec0085e85f36e15d9eea1c9" + }, + { + "aggregation_bits": "0xffffefffffffffffffffefffeffffffffffffffffffffffffffffdffffffffeffffffffffffffffffffbffbffffffffffe1f", + "data": { + "slot": "7378494", + "index": "8", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x93669ada664de0740ee57235fc4aeff39daedca3d99190c4bf0f1603636ed4fb8d2289aa63362f2d0ef109c2e01c54bc0c01fc17f71c5ebcefabdf5237803a4608e621ea0f576d0209a96186ab548b5f8a35ed44dd8ae034abc7290424aef1d8" + }, + { + "aggregation_bits": "0x0000100000000000000010001000000000000000000400000000020000000010000000000000080000040040000000000010", + "data": { + "slot": "7378494", + "index": "8", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8136d4d491ac7d49fc966091ff31631e7da9dbc33ca7d5ccdcc8836c3c797ace914c8cc512a371440e0352ccdfe104231059453e21f915d16d9ba64463f6943963f7515f7bb6e823218852d583109ff99d99a58928820020f36cb0ea7987acce" + }, + { + "aggregation_bits": "0x0000020000000000000100000000000000004000000004000000000002000020000004000000000000082000000000000020", + "data": { + "slot": "7378494", + "index": "63", + "beacon_block_root": "0x8d93e82f4ccae01a237d9c1bbfe4deb546aea2c02f3a5d8fa6f8befe96c9a537", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x80996d8bfad4ce23481fdfb8824b8e60ef828847174dc64e824a12542680572fd38eaad95f2d99c8bb9cbbcdaae094f9066d3ed62875bdf402f678808e6b545d843ad872b3a14e3d69e5b04a910877b92299fe6586f1a0768a83639c76814872" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000001020", + "data": { + "slot": "7378494", + "index": "50", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb649f1829fbf1ab8c2737fa4bb5a2db3a9f4d9ae8dbf378b9f9e5a0f927a0314bbcfea4cdbdb71d78d43922cf0d489860b7570e02489defe2276c88c574388dbc32e926ca124f25c20cc6e8ad0951ecb8f2f1ef70291bceaf5bee6ace949b235" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000020", + "data": { + "slot": "7378494", + "index": "9", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xa71226b5430c675b00c95baadd0d051d83745f995e449e00a2d29b5d3e45210841b8023bf1a6f32d5756751d8f51623e162ebd1e2faf773552e5900152bee0cf9e59c7e955707e99a2fadda7859d304c5f12d328990df642006aba9d777db1d8" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000020", + "data": { + "slot": "7378494", + "index": "33", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xad1f93841542a300585d51d034d2b4c906054eb89b5193efabc7ac8cd0461ce31af127d973361cb1f9c98d3ee1fbd9480d8b3786df4c631619510ea75c8b1065e2077dda4f51053e9a36096b10b5e0b781bb0be24e0cc8ba7d2dfc564fc96618" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010", + "data": { + "slot": "7378494", + "index": "38", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x88b2b792e1f1ed648e645fae6e0bc6c7021a99f11e05e9a994120887c65280a2e5e49011e06f263a666c1186cf73252507b6efe0b049b876ef686deee017fac76d363b687dd53c6dae6926b6a831304cd15b83b7d46b33fa9ad798fea3f7204e" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000010", + "data": { + "slot": "7378494", + "index": "27", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x886c27c1f86d771936ed595e7f145b0d9fee329f6beab5e7e04be10ae3043cc964612e8e9e60e0a1eb65acbe58a3e93300df489d2a782708db1de1918e7ffbaf276594df1a73746805a4e321c52a61b4af6422058cf85cbc322b6be791287b27" + }, + { + "aggregation_bits": "0x0000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000020", + "data": { + "slot": "7378494", + "index": "1", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x93ed986d6948d557e631c70abc77a8b18b82900b5d95fe91fdc9c6d53e239b0095a28133ba21a05779758299545d64ec145e3e7c805ba4c26c3a71647597fc5923098f196c1d514b45db59f109b77238b0bf98c8dc5749c6426be4b2aad9d827" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000010", + "data": { + "slot": "7378494", + "index": "21", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb41891824051794a18ab11a12a524c7857b327567304109dc83abddb49475ee6e639525ebb505488a631b84354a97a6b130bb559cbe773578969c2608da8854b76283a48f1b1af6090f13af65436c444ac4fa3e023a55716990386f61be6e30b" + }, + { + "aggregation_bits": "0x0000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000020", + "data": { + "slot": "7378494", + "index": "41", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8145a8db62dab4c43d075f212357edf2395a50da11173b0455a88e0aef96acbbb403258265da20ed30b2bd8cf741f9320a659f3bb58f22bd51b011c1f15ec1bf9c23d5471dd40b12c939abfdf97ebd6a81305451dbb970cb3d8064621f3eb14d" + }, + { + "aggregation_bits": "0x0000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000010", + "data": { + "slot": "7378494", + "index": "25", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb29d54c853e60e0e29f59ebbf00a729f04d7e948a4a063bfc66b273b0cc3de66dbf9df090afc48e472a0ab8242ead35306ecf170f5dbcfe299927201c395ac18f42afdc0ce3974c88a06ed7849cd8cfcfe56db4853c9490fef930a8f8dccdc55" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000010", + "data": { + "slot": "7378494", + "index": "15", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x99ab43ce9475ea56c6cec9f284782a7b2234745ce68e3d25c2a2b9044ad7fb2a1f574fa329e849b64c8eb0224acd428510131378b3c3d7d9a8bb50a147939bcb439dc808e153217e3a0ae2ad31e3c570fab4ca851d6d9d9397a60cb8c769aeec" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110", + "data": { + "slot": "7378494", + "index": "8", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x953635b952cd3c924d91b80cc8fe725bf256eea9d28a7325c713bba8cb6f0ac2a4b8161dd865a2dd460531046be9bc4a0e4f461002d9d51d43d20c3d3cd61c18738a0254769502e915d5235dcc0f59f65d962e660b24a11896cdd133c68c001e" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000010", + "data": { + "slot": "7378494", + "index": "32", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8d442fe70c41b582ad3bb0c8ae2044dd6f8990cf2030288e9e8d2816f3ecaac2c74db82c6ebf730ccfaf40b8a61b18d619729f0bd439b0b638168c15d167a8e12f5f3ca9e609582b0e70525d9aedaed4f4cad6fc186e509af58e99d8d847b53c" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000010", + "data": { + "slot": "7378494", + "index": "36", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb250f21b8113d831e77df1a84ace39a7b44befdad1090f6d653ea687ee96a8f3ab061389c7d7d67f8488a2cb79259c29070b7f4ba7dba087fa1051ddb6278bc377db21e7bdc42cab6f7c1bab75a9ce7bd7a8d5645294e16d253f01a73df6f50e" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000010", + "data": { + "slot": "7378494", + "index": "51", + "beacon_block_root": "0x27c3f56f32193ea28595e76681ea327d4a165cec76e7416b8ea63f8706ec9391", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb01b9b75b99e2e22b0a6f29c6d89c3c0aaf5e917d322fc487ff0fa4a32a74b498c6c6bc823f2247e84fb0849dd79f8511293d78ea24e671fd803e5894466d70cbe6b997d59a5fc530435551e41e5a3ab713eb42586375db8ee3349221f23516a" + }, + { + "aggregation_bits": "0x0000000000000010000000000000000000000000000000000000000000000000000000000000000000000000008000000020", + "data": { + "slot": "7378492", + "index": "9", + "beacon_block_root": "0xeab9fe966f136db09c1a42dcaac1b8bf6e58a9e722612a5ac73ab4b2f48b001d", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xafbd61d25ab5fdcb3c8a263b08a20e3d315b209eadf2db068300075baea8f39a7afdcf7e7453733ae9ba9eae8422aa0508ad01fd943fe694a474282d66dfb32c9f2c6669f17bfa4ee01a11281060e310a7d8e834fb9d6e43676501e013a1c204" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000020", + "data": { + "slot": "7378492", + "index": "43", + "beacon_block_root": "0xeab9fe966f136db09c1a42dcaac1b8bf6e58a9e722612a5ac73ab4b2f48b001d", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x8a55078263eea258c83d53073dc9bfd783741914eeda57dcfe1dfe4e935daab5320b46f0ee60488a1eef6bb427a4fe490c4c347dd99f986e246478071923488b37c7e63fde9fe0c1b6d259423cc9afc0e22f38abf172e335e5a426229a54155c" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000020", + "data": { + "slot": "7378491", + "index": "11", + "beacon_block_root": "0x7da3491e9e1ca60297512f8c2304b13f570f395665236a24a968fae6dd44e402", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0x86a7aeadf1031d01003400c5912323b659ed472ea4b913239a12fc494388884ff898b8f9c0fd400e935917021aa42fe517e6594d304e57930f501938adbb5f759890bbb2d2eff9a4a46b1e6dcdfe64a01d6106037b735fc4d721ebdece7cfd11" + }, + { + "aggregation_bits": "0xffffffffffffefffffffffffffffffffffffff7ffff6fffffffffffffffffffffffdfefffffffffffffffffff7ffffffff1f", + "data": { + "slot": "7378486", + "index": "41", + "beacon_block_root": "0xa1946350486b0ca91a93fae2de443411901a9ac824a8cc93dd046ba15f7c8ea6", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb7d6275bda2982202a8c75ce31190bf726a43ec197bab381e4ea61997b8fcbaebc1fe8a94b6f865b297fbd723709222b0621da909edc0fdbdbf5eb085961c142afd07e73dc7075f23221d934eef0e835dd5b042f1c74bae569e6446c5238e1a0" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000020", + "data": { + "slot": "7378478", + "index": "55", + "beacon_block_root": "0x96a3675a608ca14556c06d35ac4783492cf033cdd328973788909444256a8c9a", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb98e95ffcfe118d1d5b5a4f310d1871dcaff5e65cde31355828787bedb27146c96689ca9ed3f32fa204ec81b99523f4e0848161ce7b9b3fa5fa38d0a9d96ba50b1ecdccad3e2a17d3598b9c64017d7589617f3a8009366664a884bf91e2049eb" + }, + { + "aggregation_bits": "0xfffffffffffffdfffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef1f", + "data": { + "slot": "7378469", + "index": "33", + "beacon_block_root": "0xe91d6c3eaf1b381dff1bbd0558d9e6dcae714efffc72890391b3ac8fcd56f51d", + "source": { + "epoch": "230576", + "root": "0x8457e7b625df2b40a671fb135acc0fef14d29c39a2f8ffb80fbe0d274bcbcf8c" + }, + "target": { + "epoch": "230577", + "root": "0x4d12215357069641e9aca3d7b03851bde21faa001110c6204dd88d317696f3b4" + } + }, + "signature": "0xb7cb86960dc0dd66f3bf556de8f71a09ec8d2e0d0d0a483006e19671b3fa74470492b30e9bb7e3458e080577b031b1560aeaccd0861092f05a0116144d838931b78ecaf1ed4b8a5dda64bdd18758956b1f01f8c4d579c614d68880f9c49b0834" + } + ], + "deposits": [], + "voluntary_exits": [], + "sync_aggregate": { + "sync_committee_bits": "0xffffffffdfffffffbffffffffffffffffffffffffffffffffffff7ffffffffffffffbffffffffffffffffffffffffffffffffffffffffdff7fffffffffff7fff", + "sync_committee_signature": "0xa3e0ea489cfc3f2370aa2587f486e99a3ae405bc1d46466c2cd373cd9669bec5818914ade2a465096eb4528a1d1f368817ed65262a195206ef87503ecbb22e17dd90f6155fa61f4288bf44baa088e50ed3776fd9e005b45b15a016ec8fb050bb" + }, + "execution_payload": { + "parent_hash": "0xf08c1d3dd9cc49d708e89dfe8543dead59bda12ebc714c9df0a5902259dd4fb4", + "fee_recipient": "0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97", + "state_root": "0x7a4d9731f6fbcb9135225b82edb9418b8bf9407957a524cd3d3f0e60dd520974", + "receipts_root": "0x4e30ab0d1b712b4b4b93864f956287dfcd688f3c077dd356d1b78b6d316d1622", + "logs_bloom": "0xdaa17125c458582c508070b48993d338a9aaab4f0f902129981d200a8110108262b67dd54282243420d2138b013505390a9333083f917cc0d660958ab12ea300e013a1dc040bdc18890f7a19d95a80e43e8326e289c79c880ddaecc69e62a0c019087924d209c18730c210b24c265c0f02974088880844b29754921a52793855874822d02a468aa0114dc4c84a230c96600e6485ed1d8c8eee6900ce14d8166d82a0f0c14aac2042e10600e851d68c31260a0ea844b32833244d056711105941c7c1129239c51d395142886aac98f20748382938044ea6534a04513a42303063a83eb1960b326db1c3a7609a8881c801aaa09a9b5b0038f3806bbd475f971c43", + "prev_randao": "0xf25f7763261cdf5ba7a89b400998a1403f12dde232c5d9ed85caeac1f30974b2", + "block_number": "18189758", + "gas_limit": "29970705", + "gas_used": "10355584", + "timestamp": "1695365963", + "extra_data": "0x546974616e2028746974616e6275696c6465722e78797a29", + "base_fee_per_gas": "8339352708", + "block_hash": "0x802acf5c350f4252e31d83c431fcb259470250fa0edf49e8391cfee014239820", + "transactions": [ + "0x02f9081b018314470d808501f1106c848305bc1a946b75d8af000000e20b7a7ddf000ba900b4009a80840efa8910b884be341de2523740544851b599aafe5870c5997e5c8addecc2649caa3918b54ce26f2e30f64c5b684b141311ce138ab5e00e71d6ffdc00059448e5de5cd0ad98ba6288ed7819246a1ebc0386c32c314bc4189840ffa4c5e25dbfc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2d0d56273290d339aaf1417d9bfa1bb8cfe8a093301f42df90725f901e6947e52eb9fadb02f95de1eb8634dc0b4bbd4628f38f901cea0ab2e97a75db32eb3b19136ac5fcb6d7a64d182e81eb81decf514e3d877434a50a00000000000000000000000000000000000000000000000000000000000000007a0404e955b4f11522f99577dfc88d0dda82da90992492b18491843775f5a1cdc61a0000000000000000000000000000000000000000000000000000000000000000ca04729effceb34e32ea7539c2827046bdcb467a191dfa169688430ec34d1dd2963a029cb8bd4e192d16f51155329ce8b0f5eb88a1d9e4d3b93ce07efbac9e1c4d175a00000000000000000000000000000000000000000000000000000000000000011a02dee8fee0050f9b50254bb2dce2adbf1d1176c39619cfda08a9fcd208972e273a0000000000000000000000000000000000000000000000000000000000000001aa0000000000000000000000000000000000000000000000000000000000000000ba04cf2bd51af1a8ac56b4fb0e23da1717ba813b99917e5e36de6e3ae319a316b3ba00000000000000000000000000000000000000000000000000000000000000009a04c39b3fdaf585b5ee5622d9ec0cb4cf2bc86694673ab95e5a63f084e37d4e9b8a00000000000000000000000000000000000000000000000000000000000000018f8dd94b54ce26f2e30f64c5b684b141311ce138ab5e00ef8c6a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000af901c59475c97384ca209f915381755c582ec0e2ce88c1baf901ada0404e955b4f11522f99577dfc88d0dda82da90992492b18491843775f5a1cdc61a04c29a58e6ae8e8d5675a8f982d2b7b5003c687633919a622b92973af39bb0548a0000000000000000000000000000000000000000000000000000000000000000aa05a0dc5d4d49c845a7e5c8f30d3eb17f36afd4610ee030b6b45acdef0e06b51fda0a1d95ad0e500f5e4b1bd149186814df18eb98e8780bf676e8f3db3a0f3face33a0d6cd76e208ea80eb6f706515ebcfc15fc94f57f3e18452883d9478107143d407a0000000000000000000000000000000000000000000000000000000000000000ca0154bb98efc83b034ad81fbf23cc88c9737739df170c146ea18e8113dac893665a00000000000000000000000000000000000000000000000000000000000000010a0f2c891cab2af1155379e2cb5a591b3e1f3859d3ef1c231d4987204c1fe7ea115a09bb3e24e1534bce24e9896f3377327d742d6c1d430477b7ebc070c2eb64e3147a0000000000000000000000000000000000000000000000000000000000000000fa0000000000000000000000000000000000000000000000000000000000000000bf8bc945cd0ad98ba6288ed7819246a1ebc0386c32c314bf8a5a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000001a0f09b457c15826396efb730bf67656e5debac76c904fafa6861ed5765cea4df44a00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000000f85994d0d56273290d339aaf1417d9bfa1bb8cfe8a0933f842a0b17349740b669941baf55dc09d27353d5066f7515a585f533b40596bae334695a0577b913a3c8810dd10161c9ae11e2ee31042564c62114c83b0bc5d3a3e71b362f89b94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f884a012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8a0b1aa816c3c240e8935aa44133611887ed238c7d51f01f8b123b6f452e8272eb4a009d0a653d028a303e3445ad078cd9784c32b672ecd784e05dfa863f177744f2ea027902350b23dab8e343168a9c4efe515d63cf66808c513bd6a00ee1036192055f8dd94e2523740544851b599aafe5870c5997e5c8addecf8c6a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000aa0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a0000000000000000000000000000000000000000000000000000000000000000680a0b4686af228e16c5e21f2b62f7896e62b8e47e9a81c89cdfc8c804880880030c8a0606201c4f426d1864e52a0833c31f7b6e74f828a1b5e425ba2c01acef3635bf0", + "0x02f9015a015f85037e11d600850667aa78c683035925947a250d5630b4cf539739df2c5dacb4c659f2488d8802c68af0bb140000b8e4b6f9de950000000000000000000000000000000000000000000000000021d6a5778fff4e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000002e0ab608813dc3a413481d8a600ccb4f5704545200000000000000000000000000000000000000000000000000000000650d3bc00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000007e52eb9fadb02f95de1eb8634dc0b4bbd4628f38c080a0c616f500f8735ac3ca85feacca898cb12b655633124e6781d4594259db78255fa02bbea542ddda2bbccbc45c9729b006ad7929a768adc8d3de97eba872dc9b8f64", + "0x02f902fb018201c78405f5e1008502ceb580f5830326ef943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad876a94d74f430000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000650d423b00000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000006a94d74f43000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000006a94d74f4300000000000000000000000000000000000000000000000000000004dde6c0c64ea600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000007e52eb9fadb02f95de1eb8634dc0b4bbd4628f38c001a027bb6379a22d41fe5cf6aad6c448e7fe2980e1844b246d3a338fc8904b9ba882a05a438e766d3cc916550c63157b7ec6f654ecc94b30009ad54039393bea47e7ea", + "0x02f901da01818a8411e1a30085036d589cd58303455e94b517850510997a34b4ddc8c3797b4f83fad510c48801f161421c8e0000b9016466b210ac000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000001f161421c8e00000000000000000000000000000000000000000000000000000015e5073bf5771200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000b619d517c47fa807bb19e6a4e66bf4552fd2e6210000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000007e52eb9fadb02f95de1eb8634dc0b4bbd4628f380000000000000000000000000000000000000000000000000000000000000001000000000000000000000000d2a52f45c74b358abe1428bc43f0ce9ddf130780c080a03d2813afeabbb404e687b0749061af0f17ca73f95c8b2813fca9bbbaedc929aa9f3b3da0c7b741f3badb07c45c805c5a186507d2842612688b02ecef3848fdb3", + "0x02f905d8018204b784070c4719850239295ca88304ebeb941111111254eeb25477b68fb85ed929f73a96058280b9056812aa3caf00000000000000000000000074f33228ced53754d0e3fe7ba92e46abd5b15763000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000075c97384ca209f915381755c582ec0e2ce88c1ba00000000000000000000000074f33228ced53754d0e3fe7ba92e46abd5b1576300000000000000000000000019f4d695952cef25328686ac7db05bddaba81e1e000000000000000000000000000000000000000000000000000000009502f9000000000000000000000000000000000000000001b74e3d0196b6e1d324e40efc000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c472501348bab121842e674cbb95ce7116199c57adc865b22220a8326716986d3f7026efe4e32c5b5788b54ef177118af7b39a2aa632ec79bd480a6a462a2e423500000000000000000000000000000000000000000000000000000000036600a007e5c0d20000000000000000000000000000000000000000000003420002b300029900a0860a32ec000000000000000000000000000000000000000000000000000000009502f9000002705120f6a94dfd0e6ea9ddfdffe4762ad4236576136613dac17f958d2ee523a2206206994597c13d831ec700e4f02109290000000000000000000000000000000000000000000000000000000000000020000000000000000000000000bfa899c1ad97229d9c604e9ea927c7acb988c05c00000000000000000000000051c72848c68a965f66fa7a88855f9f7784502a7f00000000000000000000000074f33228ced53754d0e3fe7ba92e46abd5b1576300000000000000000000000019f4d695952cef25328686ac7db05bddaba81e1e000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009502f90000000000000000000000000000000000000000000000000015cb4e8892f0860000000000000000000000000000000000000000000000000000000000650d3b680000000000000000000000000000000000000000000000000000018abbaf4c47002000000000000000000000000000ffffffffffffff001b5d4864463ec6000100000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000041d2aaac950ed27cd9eafc88901ba8fecb9a9e787076ed7ccaad7a5b2ac743e3f76774db49ca7e585494c45ef5361da23f9b2ac2abe1f04b97c3a67575af4160a21b000000000000000000000000000000000000000000000000000000000012340020d6bdbf78c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20c20c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b54ce26f2e30f64c5b684b141311ce138ab5e00e6ae4071138002dc6c0b54ce26f2e30f64c5b684b141311ce138ab5e00e1111111254eeb25477b68fb85ed929f73a9605820000000000000000000000000000000000000001b51926d602a7b1bb5bc8f7c7c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000e26b9977c080a01b70f49b8caa36113ad532d50e5bfe8106213089870f11918531e888fe8ca111a0087c38a323105c67801b3a260ce1015ff467cac1695397bd371b3f16e928e0ab", + "0x02f9021a0160841a483f6e850242357375830372d09468b3465833fb72a70ecdf485e0e4c7bd8665fc458828a97379e7e50000b901a45ae401dc00000000000000000000000000000000000000000000000000000000650d3ff500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e404e45aaf000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000d0d56273290d339aaf1417d9bfa1bb8cfe8a093300000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000741f485b010da3f2c9d4131f867155f1b3a99d6c00000000000000000000000000000000000000000000000028a97379e7e50000000000000000000000000000000000000000000144eba8f77fc518b23de7e0e4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c001a0ad879c7b36b6756e998558fb6f4af076035b4d8aea7558a50bad0146254cf541a0143d22a8ae3c317bc879511c43db0c8bd93006b9b0935696477c3e49ce74b4ee", + "0x02f907e7018314470e8521fda6fa928521fda6fa9283055234946b75d8af000000e20b7a7ddf000ba900b4009a80840f6920dcb8aebe753de2523740544851b599aafe5870c5997e5c8addec7e52eb9fadb02f95de1eb8634dc0b4bbd4628f38c2649ca9607a38b54ce26f2e30f64c5b684b141311ce138ab5e00e75c97384ca209f915381755c582ec0e2ce88c1ba71d6ffdb0005a7869f60e85cd0ad98ba6288ed7819246a1ebc0386c32c314ba4c5e25dffc418e5a880c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2d0d56273290d339aaf1417d9bfa1bb8cfe8a093301f42df906c2f901a49475c97384ca209f915381755c582ec0e2ce88c1baf9018ca0000000000000000000000000000000000000000000000000000000000000000aa0a1d95ad0e500f5e4b1bd149186814df18eb98e8780bf676e8f3db3a0f3face33a0404e955b4f11522f99577dfc88d0dda82da90992492b18491843775f5a1cdc61a09bb3e24e1534bce24e9896f3377327d742d6c1d430477b7ebc070c2eb64e3147a0000000000000000000000000000000000000000000000000000000000000000ca04c29a58e6ae8e8d5675a8f982d2b7b5003c687633919a622b92973af39bb0548a05a0dc5d4d49c845a7e5c8f30d3eb17f36afd4610ee030b6b45acdef0e06b51fda00000000000000000000000000000000000000000000000000000000000000010a0f2c891cab2af1155379e2cb5a591b3e1f3859d3ef1c231d4987204c1fe7ea115a0d6cd76e208ea80eb6f706515ebcfc15fc94f57f3e18452883d9478107143d407a0000000000000000000000000000000000000000000000000000000000000000fa0afa9712ae32b996e680ddfb579f88c5714eff15e4f29153eadd3decaad54ebcaf89b94b54ce26f2e30f64c5b684b141311ce138ab5e00ef884a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007f8bc945cd0ad98ba6288ed7819246a1ebc0386c32c314bf8a5a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000002a0f09b457c15826396efb730bf67656e5debac76c904fafa6861ed5765cea4df44a00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000000f85994d0d56273290d339aaf1417d9bfa1bb8cfe8a0933f842a0b17349740b669941baf55dc09d27353d5066f7515a585f533b40596bae334695a0577b913a3c8810dd10161c9ae11e2ee31042564c62114c83b0bc5d3a3e71b362f90228947e52eb9fadb02f95de1eb8634dc0b4bbd4628f38f90210a0000000000000000000000000000000000000000000000000000000000000000ba04cf2bd51af1a8ac56b4fb0e23da1717ba813b99917e5e36de6e3ae319a316b3ba00000000000000000000000000000000000000000000000000000000000000012a00000000000000000000000000000000000000000000000000000000000000018a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000aa02dee8fee0050f9b50254bb2dce2adbf1d1176c39619cfda08a9fcd208972e273a029cb8bd4e192d16f51155329ce8b0f5eb88a1d9e4d3b93ce07efbac9e1c4d175a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000008a04729effceb34e32ea7539c2827046bdcb467a191dfa169688430ec34d1dd2963a0ab2e97a75db32eb3b19136ac5fcb6d7a64d182e81eb81decf514e3d877434a50a04c39b3fdaf585b5ee5622d9ec0cb4cf2bc86694673ab95e5a63f084e37d4e9b8a00000000000000000000000000000000000000000000000000000000000000019a0404e955b4f11522f99577dfc88d0dda82da90992492b18491843775f5a1cdc61f89b94e2523740544851b599aafe5870c5997e5c8addecf884a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007f89b94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f884a0b1aa816c3c240e8935aa44133611887ed238c7d51f01f8b123b6f452e8272eb4a012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8a009d0a653d028a303e3445ad078cd9784c32b672ecd784e05dfa863f177744f2ea027902350b23dab8e343168a9c4efe515d63cf66808c513bd6a00ee103619205501a01099ee4dda8320e58fa87e38ad5c4766544c04e9254ece6d1a3c4ccc274ee2dca07090040021e1b7f9ccbc624e5da07f116d614fc01f09a9fff9486206f9ee979e", + "0x02f9015c018202678506fc23ac008509e5bc4ec683043206947a250d5630b4cf539739df2c5dacb4c659f2488d88058d15e176280000b8e4b6f9de95000000000000000000000000000000000000000014bdac5c38b84104abdb58400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000f6ab629ecafe852cb118ecfcb769d07be76ff84f00000000000000000000000000000000000000000000000000000000650d3bc00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000c6980fa29a42e44852e29492268d9285d89c9dacc001a07c0b8eb74b0376c57aba5629769a2d859b374448e4a4af1e712a306abe80da3fa0288f7c9958856d9756d758412924b5c3be08b307bdac7e431e77aaad5d771060", + "0x02f9015a014f850342770c0085062c0faec683042bbe947a250d5630b4cf539739df2c5dacb4c659f2488d8802c68af0bb140000b8e4b6f9de95000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000005ad7881a995c530d519ca843bb1e5c61441c0f4200000000000000000000000000000000000000000000000000000000650d3bbc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000bcd657377d4086cc582b215294c3611b997ef1bec001a0e4c47bef5e5ea64705bdab7477c89e220a29c3402d17edaebef86894b36c8c1ca05ae62df6e69158e03ae480d2415bd511af7dd9612b64d87f4ec735a5cf294fc5", + "0x02f90175018203bc850271d949008504685640288303d0909468b3465833fb72a70ecdf485e0e4c7bd8665fc4580b90104b858183f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000bbb34ffb832146d599ae08091b096d982c76a2e2000000000000000000000000000000000000000000000005b12aefafa80400000000000000000000000000000000000000000000000000000b7eeb4a764743c6000000000000000000000000000000000000000000000000000000000000002b9e32b13ce7f2e80a01932b42553652e053d6ed8e000bb8c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000c080a03c983e7673809a7272afe748c4242806f7830a2e2de3f3601c8f07b3240b21d6a02240632441b63caee132602f48cdf69795f449116ef6677dac7a8a05b598ef3b", + "0x02f901750182013f8501dcd650008504e808dcde8303ac91947a250d5630b4cf539739df2c5dacb4c659f2488d80b90104791ac9470000000000000000000000000000000000000000000000249e29cb37a9ce051f000000000000000000000000000000000000000000000000000432db12e2353000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000001630d8aff69591bc1e7e0226b55867e4587e495800000000000000000000000000000000000000000000000000000000650d3bb60000000000000000000000000000000000000000000000000000000000000002000000000000000000000000089453742936dd35134383aee9d78bee63a69b01000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2c001a0b373e83ac5f99059fc700e20e7f2acfe059bfb57731d7d5478b2342101e93619a07cbd8831561f65d1629fbab4836bdf4216871925c7356ec364f34f1fbd00f49c", + "0x02f9015c01820151850165a0bc0085044f395ec68303beef947a250d5630b4cf539739df2c5dacb4c659f2488d8802c68af0bb140000b8e4b6f9de950000000000000000000000000000000000000000000000000009664a6852aa790000000000000000000000000000000000000000000000000000000000000080000000000000000000000000481104920a3170954144d97f0a38757ca92c928200000000000000000000000000000000000000000000000000000000650d3bbf0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000007e52eb9fadb02f95de1eb8634dc0b4bbd4628f38c001a04c7b5d7e2454abc29c2a93aa65d4264e7d678d7a0ca79343024803ef2523fdf6a0239df32468a6e2a8fe914ed76ba2d959d10aa6daf4d5b678abd99607ead4986d", + "0x02f8b10139849502f9008504b6f005708306cdd8947a1957ea071eddd490d3a5eda903eaa0dc76a1b880b844c83ec04d00000000000000000000000000000000000000000000001b1ae4d6e2ef50000000000000000000000000000000000000000000000000001b1ae4d6e2ef500000c080a0ee6bd76834fe37d3248dd7bdb36476036f459be43264d0a162dd2deff8e49e16a0096ad979fac82231507a3370f7cba185910575d39448656974545041dfb7df8e", + "0xf9015269850306dc4200830497d1947a250d5630b4cf539739df2c5dacb4c659f2488d88016345785d8a0000b8e47ff36ab5000000000000000000000000000000000000000000000000000a8e0c17312bfc00000000000000000000000000000000000000000000000000000000000000800000000000000000000000008b8eafa96fddf5ecc8e13f5c9668eb6d1b69e6720000000000000000000000000000000000000000000000000000018ac0d5e26c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000404d4a815ea854bc0666cee8041af8fd1add1a0125a01c14cccee71797a25705f50d74232fcaac27cce9dd776abaac6b4bc16603da20a073f8671fbc40d82219e604413e38e3aff8f72f7cd565d9fb6b3863d6012f51a9", + "0x02f908b3016184b2d05e00852e90edd00084011a49a094260552861d45681d7a2789ea29981f184aac43da80b9084412514bba0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000002696459e63520de63d10f8bffa89c1fbd0ab67b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000002696459e63520de63d10f8bffa89c1fbd0ab67b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000002696459e63520de63d10f8bffa89c1fbd0ab67b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000002696459e63520de63d10f8bffa89c1fbd0ab67b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000002696459e63520de63d10f8bffa89c1fbd0ab67b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000002696459e63520de63d10f8bffa89c1fbd0ab67b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000002696459e63520de63d10f8bffa89c1fbd0ab67b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000002696459e63520de63d10f8bffa89c1fbd0ab67b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000130f7fa60923711db8a5b57b1da930c83cccf494000000000000000000000000130f7fa60923711db8a5b57b1da930c83cccf4940000000000000000000000005b5a6fd70a7e7df8580331f0389e95bafa6c16f40000000000000000000000005b5a6fd70a7e7df8580331f0389e95bafa6c16f4000000000000000000000000130fc0d30181fd072d2d47f57e9f99f9db97f494000000000000000000000000130fc0d30181fd072d2d47f57e9f99f9db97f494000000000000000000000000a5b5408340fb28dbc20833af0a2fd28cbd39dbbf000000000000000000000000a5b5408340fb28dbc20833af0a2fd28cbd39dbbf0000000000000000000000006836f0fccb1473833c4e6a174c626afcdae441320000000000000000000000006836f0fccb1473833c4e6a174c626afcdae441320000000000000000000000005b5a6fdafa5ecf6bfef4ce654957abf4fa6c16f40000000000000000000000005b5a6fdafa5ecf6bfef4ce654957abf4fa6c16f40000000000000000000000009e2c3c4d1c69c1124a68ed427f1f8336e6001bea0000000000000000000000009e2c3c4d1c69c1124a68ed427f1f8336e6001bea000000000000000000000000a5b5408efc081bf3e475b4661993bccdbd39dbbf000000000000000000000000a5b5408efc081bf3e475b4661993bccdbd39dbbf000000000000000000000000dcac4d02bf15d84d87de85e7c3ef45632335d924000000000000000000000000dcac4d02bf15d84d87de85e7c3ef45632335d924000000000000000000000000ea2402baa40d3cb80ea47000f238ac24f72cc452000000000000000000000000ea2402baa40d3cb80ea47000f238ac24f72cc452000000000000000000000000dcac4d020a47ec66da0e2c23632d35df2835d924000000000000000000000000dcac4d020a47ec66da0e2c23632d35df2835d924000000000000000000000000e4bc15674dd27cdfb960eb1d9439ec796d2a5fa2000000000000000000000000e4bc15674dd27cdfb960eb1d9439ec796d2a5fa200000000000000000000000068d985eec63bd7826f70fb3add66a5c098b5368000000000000000000000000068d985eec63bd7826f70fb3add66a5c098b53680000000000000000000000000ea2402ba035899397f09fc91e61e854df72cc452000000000000000000000000ea2402ba035899397f09fc91e61e854df72cc452000000000000000000000000de06285d8a040612d0dbd05d4399f0a3dcbc1bb5000000000000000000000000de06285d8a040612d0dbd05d4399f0a3dcbc1bb5000000000000000000000000e4bc156b3576af8b257599923d810ee6632a5fa2000000000000000000000000e4bc156b3576af8b257599923d810ee6632a5fa20000000000000000000000000000000000000000000000020f5b1eaad8d80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014d1120d7b16000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f5b1eaad8d80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000554a4fe826a7c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c629bcf4aaf2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014d1120d7b1600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000554a4fe826a7c80000000000000000000000000000000000000000000000000000000000000000000c001a0ab7d5cedaf8addf1751c2f6d2b580de1c01206cbd9ec9db3ff88b45abb4361d1a03102bf37fa598ccd40bd2462ef7afaa86fcb8e0005468d11730f8826bfe456ac", + "0x02f902fa0181ab849b4a5b248504840300dc8304028e943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad874a9b6384488000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000650d422f00000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004a9b638448800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000004a9b63844880000000000000000000000000000000000000000000000004586c5c7355b6aa875700000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000055559d9b47fff7b7f891de11e9ef56654b42ffbdc080a08d3ceb25f1579ea7be864c88a06d5b3248d9c8b531250b401ecd5775ba75a0d3a0084a0f03552dfe5a19cea0219bbcdbd001d2e7018c9dccc6c14a73debe72106c", + "0xf8a955850424bec27a82ea609457b9d10157f66d8c00a815b5e289a152dedbe7ed80b844a9059cbb00000000000000000000000005a479d8b3c72821d41a9c802a492a832582d2c800000000000000000000000000000000000000000000000000000000000186a01ca01d03b929585ed25b52fcda511ddba993d5c33089a6979a91322979c84d719227a07eaf12e88497e5e0605ab09e79c5071d31b2cd4e722d8d9e4bbd361b9a458dc3", + "0x02f9015a0182024184b2d05e0085039c6900c68303e88f947a250d5630b4cf539739df2c5dacb4c659f2488d87b1a2bc2ec50000b8e4b6f9de95000000000000000000000000000000000000000000000000000001347e08055c00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000e0a01fdf17141ca25fcdf03e0549899da1f7c4700000000000000000000000000000000000000000000000000000000650d3bbc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000005041f018b4c130e32ae985edea8e76d2195001a6c080a010bf2f3323e4ab64986f19c242cfefa8f3337cdf51aefa6bd14c2162e0841d85a039b874de823db572e680d2cd2977947cd53e97cae3de37f28e2e2ec82be58d7b", + "0x02f904320149846b49d2008502540be40083057e99943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b903c43593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000650d422f00000000000000000000000000000000000000000000000000000000000000020a080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000014fee680690900ba0cccfc76ad70fd1b95d10e16000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000006534c83200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad00000000000000000000000000000000000000000000000000000000650d423a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000041c51a446e5b38de3265e4aac64cf330db3b161068817c2528156883bf6d37974a4cccf0ba1de588cb06198574a5e078996a302c3fc44e485658a820a1e1ee34711b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000003828eda98d800000000000000000000000000000000000000000000000000000000033c38fb00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000014fee680690900ba0cccfc76ad70fd1b95d10e16000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c080a05c0b5c4fec450d7bdbad29101e73841a790a5ca301c216cf2b1e2fe4364a176aa05bfb1a25a5696803ba38712379c43348b0335781e677bcaa372387a63f0b27fb", + "0x02f8b2016285016a53e9ae8503cd844cd28307e76f9441c2ad4add42a83eb74701cc8b132501a991a93380b844095ea7b30000000000000000000000003999d2c5207c06bbc5cf8a6bea52966cabb76d41ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a07d54a4d6c40115cd4b473c549c4e3e777c07409ab76240af7a02c583c776ed8ba067a3dc9cb4d5de0388b4f10ab6ff4d16738fc7d8cadbea1dbdcd0be56c2fc1fd", + "0x02f901d3016385016a53e9ae8503cd844cd28307e76f943999d2c5207c06bbc5cf8a6bea52966cabb76d4180b901648ee938a90000000000000000000000000000000000000005535f8d310d4b800000000000000000000000000000000000000000000000000000000000001d81dec19f649700000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000650d3b5e0000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000041c2ad4add42a83eb74701cc8b132501a991a933000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000067863757276650000000000000000000000000000000000000000000000000000c001a0deb6157d8706b9e2b6c0f563880118a8d1af08b0ae0fc5c5143d08074fb91751a07d4d3ef21f4e10facabcbbf35ff1d6058333ba0309818f15febe38f02f5d4906", + "0x02f8b40183020a3c8501c4a33e8085043c98d81482ad0b947d1afa7b718fb893db30a3abc0cfc608aacfebb080b844a9059cbb000000000000000000000000de77e98e58dbb7e77e253c090843508eecb3d74d00000000000000000000000000000000000000000000000274a9edfd85320000c001a0393071e73830abb485f7c44cf466fa0623cd75dbf55aea004c4f1f8b459b82cea02e5b3fd2945a43df2e863267cb7ad0923f1606ec85019e566f6c9a281aadc2f2", + "0x02f9019201028432a9f88085033ff5448183046ba094889edc2edab5f40e902b864ad4d7ade8e412f9b180b90124acf41e4d00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000ed12c3837fa789b8bc37ffec8b2d19f05262396b000000000000000000000000000000000000000000000000048e7fb600addc0bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001ce6fc6b5b56cd00e9ba034105888c40e78af8d31afb2146c9b06da5c504162b451c4c7f47a49bcb9f8065f95b39d88513111b3ae650f2bee3b831eeda243ba0320000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000048e7fb600addc0bc001a0a733075c6d25de1b3e400a40e908e7a3bee8027f1a0e055145cb0060a179da6aa01f5af45659a9f2c7972d590f3b7aaf9f8783d2847fbecefcc2d633d582dc748a", + "0x02f8d90102849502f9008504b4ef743283012bbf94f5c9f957705bea56a7e806943f98f7777b9958268802315429b2830000b8646ce5d95704a2e178341aa53fd0c0852851ce5338d293401da5e2101d4316304bfe656e3900b333e3142fe16b78628f19bb15afddaef437e72d6d7f5c6c20c6801a27fba600000000000000000000000000000000000000000000000000000000002688e5c080a096545335507fdbe249d1a93a4c7d8bf85ca933b4b22d137919d911fab7107590a00300ebb0895223b288c4dcc4486bd92f9503c947ce10128535c6cc7168c2623f", + "0xf8ac827b0b8502a4a6930483013880941a3496c18d558bd9c6c8f609e1b129f67ab0816380b844a9059cbb000000000000000000000000b02ed88986b74574650de87e8f6a578b1e2427ad0000000000000000000000000000000000000000000009b588922c49ec28000025a0c07fcabdae75efa779e9237bae6a42cecd95f20eda89cb106c6183934d38da6ea036dc93263ff67eeee085dc92497390199bc7b5e734d65931009992860b30fac9", + "0x02f8ba0182ed82843de47d0d85029346fa1e83028c5694fb071837728455c581f370704b225ac9eabdfa4a872c934b294cd400b8445173ffaa0000000000000000000000005c5d5202d8cd871614c86ee7586cf27f7ded92750000000000000000000000000000000000000000000000000000000000000245c001a0649da1987303cd516dbfe574df1107223df0ab5b828b9cfdb8dbbb3fe40c880ba02284a3e8563423761dc74f078a5cfec479936dd84aefd28ea91b1dc9897c5b51", + "0x02f8b1012484773594008502b96b6cdb8301117094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000cf3aa1a77fa8c221f80bd15f4d7a36186eeb7df10000000000000000000000000000000000000000000000000000000007270e00c080a0d5701426adcbf17f20353389eeedff7c30420dc3b95b1a105b42f67f45994f8fa0040e87ced08417fa84ca69d6886c06d34cc35655eecd745f70633553cc17884e", + "0xf9018b08850218711a008303717a94be6fee3756f7be3a0cd492059341cb5b77dd81f980b90124f01e063a0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000069df738dfc2d1e2ea3e1314f00000000000000000000000000000000000000000000000000801277b814c28a00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000020000000000000000000000008a9e6d160d7c0087121e40e398fa3f67a4598b75000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc225a0915fd2529c30cde9428210ce48f96ccc6ba1f46b2ea0a17bd50e2a0471b6a969a07bb3f7e47bb7f1832586634194c777af4c7b09390eb8ba8c0849d3716f6a2f22", + "0x02f8b30182014c84773594008502baa6aeb78301117094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb0000000000000000000000001207fc953ca19e470063a9d3c944fcd5509fdfd600000000000000000000000000000000000000000000000000000000b8c63f00c080a0ed29e0284c913d8c1fa3d249a7325ba87efd8e74df2e60922fbb8b21022c5c3ea06ff2aac75a35a5bcc92d437b8856d4123d8b53b02f7e597e046b495f341452c1", + "0x02f8b4018376feeb84773594008517bfac7c008303291894430ef9263e76dae63c84292c3409d61c598e968280b844a9059cbb00000000000000000000000019267f3000ad73223dd7a8fa9b9b5ce58c28712100000000000000000000000000000000000000000000011578c3544a26250000c080a0553dbd4c1d4227a24041d09bbb6b782b0b61502d4a5a6161694b2b59c3f237b2a07c155a16a056e8079870843155b5a9ce3d28bd8c2371ab18c35f8cf57bde7e93", + "0x02f8b201820d9c8459682f0085046856402882c992942960d71855a521c8414d29a27218efdb67c3418080b844a9059cbb000000000000000000000000781c876ce98abca880f304c5a3934f65e64302730000000000000000000000000000000000000000000002e2b4737ca62f6e0000c001a0b4c3620cb8b4fce3aff26c6016de8b9633530915ba752e1de440d69fb7d1b5b1a005bb710b536b214b076d430e03e9e360cbfa53da7ce7df02aad3a25b7f8e1d78", + "0x02f8b001598459682f0085046856402882b5f394b92e40c0bd1a135c5cb19ea98d2d729909ceab6180b844095ea7b3000000000000000000000000e1ce310e3cb20073ff25b1a76faa7e032f41cf7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a06a91c0e1442a2be601ac13be71946b026c0e9b60c7c36b8c3b595bcca611947ca05fce31d09568abc84ef55ac29b90c078b9518fb033d62ac5289a5e45174d5336", + "0x02f8d301821db8843b9aca00850430e2340083010323943506424f91fd33084466f402d5d97f05f8e3b4af80b86423b872dd00000000000000000000000072b83a114e3254849679673e97b2ea3bd9a3920a000000000000000000000000dcff7bdd67eb501f214faf41c9d596b53dbffc5f00000000000000000000000000000000000000000000000bcee26cd2632f8657c080a04a69ef73e530864823505230de965a2b356f98a73d925486f4f67d2b86f0c358a0533047aa4de7d29814677b06933138b74cdcd994b3d12199cbbd655e31724c9f", + "0x02f902db018205a68405f5e1008502d00f7c9983095d7f94c36442b4a4522e871399cd717abdd847ab11fe8887470de4df820000b90264ac9650d800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001648831645600000000000000000000000020561172f791f915323241e885b4f7d5187c36e1000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000002710fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe10b0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe2a7800000000000000000000000000000000000000000000002a1f12d4e0aeba9d7700000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000002811653334d531c09600000000000000000000000000000000000000000000000000465205e1b4d892000000000000000000000000560805d557eba6a00e5618e019a216efa47775d900000000000000000000000000000000000000000000000000000000650d3b6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412210e8a00000000000000000000000000000000000000000000000000000000c080a0afc9c3292b7fdbbcd16941d4fc65d344e0d302943e2a59490593b838ef1b1293a05902fe30e723dce269bb1f0860c70185af61a46c8f90577ded2d63ad1e9c61d4", + "0x02f8b20182019f843b9aca008502b4998a8982f35294fa1a856cfa3409cfa145fa4e20eb270df3eb21ab80b844a9059cbb0000000000000000000000008cce8709a5fbd78a27aec1e7174cc5276fcc68fa000000000000000000000000000000000000000000000cb8e39d1bd0d55c0000c001a0eb27acf651a0ac3afdcfbbd8a8dab0c857f93c993dee146e1dbb0691a2aef6aaa00d8fea3ea755e14ccb60a96ca51758820e7eecea035423a14d6e910154bdda7e", + "0x02f8760183021d35847735940085048623a528830329189445e7d523dcf83269f8b8586655a966a733fe1b38870e4c533842e3c080c001a02572c1abf8481b58339d759464a03efbc5d1cb131bf6a307fcb9d8f6634977baa0488ae4caa36e4458e9691db0cc546761a6fd6012fd34a26f87203b0cc7b6959a", + "0x02f8720101847735940085026846008482520894dce92f40cadde2c4e3ea78b8892c540e6bfe2f81878e4be056c093e080c080a0cab09875ed6df6893ac90891df5252bb0063bdd5b179b3fdce5e403b34d46d2ea0239c71539b9a304b712197b1472c248dcb0e52841fc4aa5887e288fe567b66c9", + "0x02f8730168847735940085026846008482520894dce92f40cadde2c4e3ea78b8892c540e6bfe2f818802a6c88a9741b23880c001a0c683b1ed551072e7db8937ad58dd78b4ed01a17e0b2bdd1efc2bd67a792f3828a0261297f9861d626d3ab4b1bc70b55252a708a308af1d2a557215f086c7149de6", + "0x02f876018301a9658477359400850459566d0882520894b2943be603e11b493b20411692a2e2efbfa82aad88010fc90b84e4d40080c001a0592edcd0217bc3c65ef4d35d9c9da691e50489a409e7c1b51cbd6a309477a78aa02aff224db05486243416bab5f1a876e789ec7ac6d443c55ab201572b4e49db16", + "0x02f877018372bf4e84773594008517bfac7c0083032918948745d208d684a61a5023b9a96c1f28890d20a064880558f9e74f19580080c001a07f9b8ba8a93d671036ddc7f70c72e7f78d90fb3b512f16d57e48b26ec8d4c0d6a04987db6930bdca36415a3e3394d975d0d62631d0433cc7ac4f38ae3163254180", + "0x02f874018201ab8459682f0085039c6900c682cf0894cac0f1a06d3f02397cfb6d7077321d73b504916e872386f26fc1000080c080a053d7a48f67ef1d604f88d930ce6e7f9b3aa5259292a66b23dbf2b331fc789967a040dfc3dcd1a9009e93987ec6cf0cf5e7632dab5a09138211aae44f324a5c8efa", + "0x02f901b201058405f5e1008502ceb580f58305f0e2947a250d5630b4cf539739df2c5dacb4c659f2488d80b901445b0d5984000000000000000000000000df98398d12eecd6275ff3c906686ff7aabb4513500000000000000000000000000000000000000000000001ac42dc434e9683659000000000000000000000000000000000000000000003c49e9764603dc9f33960000000000000000000000000000000000000000000000000ab9aeb24e319a9c000000000000000000000000484219de75a791cd83d613e14408a433848576f600000000000000000000000000000000000000000000000000000000650d46070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b9a9af484bcba44a3085ac4180e942823d5060a722e9b7b5802ff83ae116cc656397a4bc869fb7ce4ac178414ec2fb454c588ff36e25363adda87c8e8a6301bb7c001a032255120bf16f7ec8ad6cc0d1a54f90f32a3c45e54c05504e97c9b46594e6ac2a0361d40030b950ec6b9e571ef065b46f678e6a03732c3469f1c6fc215d8f2cf77", + "0x02f9089e01068405f5e10085025048a8558304f81b94def1c0ded9bec7f1a1670819833240f027b25eff8852d9b35e9d150000b90828415565b0000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000052d9b35e9d150000000000000000000000000000000000000000000000000000000000022483477300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000004e000000000000000000000000000000000000000000000000000000000000005e0000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000000000000000000000000000052d9b35e9d15000000000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000052d9b35e9d15000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000002360b0cea00000000000000000000000000000000000000000000000052d9b35e9d150000000000000000000000000000bb289bc97591f70d8216462df40ed713011b968a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000533f6f812421b9271db6edf0e46fac24ff9d6aad00000000650d3b760000000000000000000000000000000000000000650d3b380000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001bfba32863e0e5c402ddb4184ea18bf566eca381c20c49835abf88888deb33f4636aa077425d4e30877a69365a4e27f5f5c57c254c4348123a9509d9e09f0f520000000000000000000000000000000000000000000000000052d9b35e9d150000000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000008c8f51000000000000000000000000ad01c20d5886137e056775af56915de824c8fce5000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000000000000000000000000000000000000000000000869584cd000000000000000000000000382ffce2287252f930e1c8dc9328dac5bf282ba10000000000000000000000000000000006937218260a6fe77fb37f7d4df81cc9c001a03bb4473cc91acdff066f03c76fcf96aef9bd697c23df960da88042d620e0f0b6a002ca2df45f6862adfaaac674ae1043d54dac16fc46c18ecc5d6d6868fc425e1e", + "0x02f902d4018201ee8405f5e1008502ceb580f58303f8e294ba12222222228d8ba445958a75a0704d566bf2c880b902648bdb3913e7e2c68d3b13d905bbb636709cf4dfd21076b9d20000000000000000000005ca00000000000000000000000001717b7ee44c3723b4803a11ee843b697ce6c10300000000000000000000000001717b7ee44c3723b4803a11ee843b697ce6c103000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000e7e2c68d3b13d905bbb636709cf4dfd21076b9d2000000000000000000000000f951e335afb289353dc249e82926178eac7ded780000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000006e7491a814db77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c6ae2cbe30784f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000778b18beaa1367ec080a0050b4419f0b5d0f3b5f401b140005dd239e3942ca214489de4dd3a6f9e813bfca00d2d58a2513c3e3a313271e323c582501fa6551b239aa653f074f1d054f3ba19", + "0x02f874018209ff843b9aca008502c6aedeab825208943f4833b244c7dccf034da7d733c3a485f0c121cb870254dd702e280080c001a0682d91b2afdb8fdb79e9e557824eafafc13cbc3938b59f9e2069271e0c63b46ba038b4ea5e7fe315e2fe7d7ab753ea7e71426bad774e63ea74cfe05ba1c228ebf5", + "0x02f877018309113a843b9aca00855d21dba00083033450946fddb91b1e3cacec85b8b8c568e950744a0c9037880de0b6b3a764000080c080a0a159e0e7479d0ce98decae732245a2cf4ba9895fd6599c05739bfb2d0c0b1777a002f81af2bce29a0eaa3bd5b2a2110681aeeaf116956a0bebaaa1c4da430e5250", + "0x02f876018317771c843b9aca00855d21dba0008303345094605f78cd9fd82433dc1fd9c3b331aaea445708e08723b8084e6eb40080c001a064278ac9b8eaf6ec3a6491403dd3360ab49396d33520c8487200ec41095cf979a00cbc0c2ab4910246ac613f1e80e8bd946fdd377fdd7089c3348a46e415109129", + "0x02f876018317771d843b9aca00855d21dba000830334509469e28c8d85d25ba1cd0544e76bcd6d24fd4313a8872386f26fc1000080c001a06803dec8fec9bd1a9a833bde86397f3fc9209fe6786a45cd122601abad8e7a8ca0690337d320e450419489bc6e5bc1547e84e69607707d22a6e774e3f43739f555", + "0x02f877018317771e843b9aca00855d21dba0008303345094ab477e5d4cc2d975ae082be6252813d8146eb77f8801305350ef75c00080c001a0fb61c6e7d898b87df03cb61b2a95b1ecdef0501fa5b28edb9a933ef52181a167a03d66b75f2bd8855fc0a9419b1bea646e946d715ef49199e8690c415d6644284b", + "0x02f876018317771f843b9aca00855d21dba0008303345094fba5a6c47c5477a48e151f6e0d7bd00b025ad096872386f26fc1000080c001a01617cbe439398443fa1ddf8db7423cf96b210fa744a9d557fdfd127ba28dd793a02f34a3b89a0265ec8b26f3318ae2c781be64081f57a4207308cefd1f52ad1615", + "0x02f8760183177720843b9aca00855d21dba0008303345094601092bd5dca1d80f7ab81e858a001b699f3360f87b5303ad38b800080c080a05a8be1066f4ad8bb8d013f5d8671cd0cdeebc3b58ece98d1b294be1a8d062a44a0136be11303edf7cdebbe64fb287a09bcd8fd27a84ed2ac4759cb3753f8115734", + "0x02f877018303de21843b9aca00853c89352800830186a0945af99d79d74a2f14e7f71af444dac47ab0f8edc188025b5b7c3634602380c001a0f2b74ae6aaa3aa430b91b952def69c7f86a7be3d7426ddcee2d7128c47b4c60ba029a970d3b242f15c5f4041f77add145458f65dd53ad226d5f6388977cd385e31", + "0x02f8730102843b9aca008502540be400830186a094c902fc03248c7024456cd2ae6f21eb804495bcd787d8b72d434c800080c080a0e2e167824f28238ea5e48bd18d94c3872c1b2f891df1f968c08c34efa6c461d4a061e2793b77dcd67d6370ebef6baacb8600b08574ebd25342df115603ab775fca", + "0xf90193808501fafa22af830247759432400084c286cf3e17e7b677ea9583e60a0003248804e0bf754f744f00b90124eb6724190000000000000000000000000e8abd54de0a63797f59a9bd150ca91088fc242200000000000000000000000000000000000000000000000004df6dc79989000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000b54a3000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000e8abd54de0a63797f59a9bd150ca91088fc24220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026a071f36d2a326722e5b7fdc463f812f58ba4d65eda867e1cadc41df67bcb13a73ba00830771d975236296a0ed54c3b062cf8305f43b814f54b7f9ad2756a1c621a04", + "0xf86a81ec8501fafa22af83020fc99437476750a31266557609212e9707895e06e36ca480841f83bf4425a0bae5b977cecf7b90264dec4307e611d4305ae02ac714179968f9357ae421b5afa05985a78500bbc35b18c6914b47a682a24f5c4e4c0ad7afef7a32155f7c199676", + "0x02f90574018202b38405f5e1008502ceb580f58303978c9417b5a77d6e7cde0e8d1f59bd1edb26d9badf6e9e80b9050487151b880000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000117f385a0d4aec94000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003b06bc7b205f1a827f6504244db7a8f5b0bf7dfa00000000000000000000000000000000000000000000000003c57c4c7d3bcb5e0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000cb83e1143173140c8a2314ff90df5b68574a6c9bf5b6bd23f1ca6a0c04faf71e675fa4a7d9eea857686f38887307c74f310dd9d5d7ad0f03f766b4143974dfa099632d0c373e0c1de94476e5ef74b6bfb7890f153d65fed04e17ce6f7a071e9a271efa2ab9f7d8427716e425df8119373c5e55910575b9c5a3b232dd75a647b185704492b0bfc912392ab9748398d6590290c9289d49cbe4f9234d2da2d483f7aef656ccb10b9f033832ec9c9985711c1edeed643b652143ed632b91fbf5a26a99bfa4f414bf756586214ae1629b9472d84611e9261a117cc7550c12269bc8e7bc87d19f9d86a184ba374c1b266062d4482c39f1865f634c74309d3afb0734cf3f291e8709c6caee62ee9e873506d7c640761259dae43539a776213b8642f7bb0a226e0fb9373a97a95565aaf5f2982abe18d9a20a2a00c6ee435dc4d0c9acc21f89de707b46bc7636728f0d0c1e1dc032091d72eadae6455bddeaf8ceb6f39ef2a0d596396598f6876744405716f180ae880c5f158098efa1360f85568da00b1000000000000000000000000c55126051b22ebb829d00368f4b12bde432de5da0000000000000000000000003b06bc7b205f1a827f6504244db7a8f5b0bf7dfa0000000000000000000000000000000000000000000000026d8e645dfd3559940000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d847b709d8cf1ce1bfcfbd95b61af94558dd54972ec8aa7b4fdcb0092a8a3e8523118a915a1557371cf10f5c8dc24a60fea45f7d1d1b3350162e952dba5bbc259b4e1a3edb86654bc8f8292a95ac01b8b581f9ddc5e632d4c57f4c345380686d7e11ae992e09634ea7998437703fdc39d512ed56b41c43d1b672d9ddbff2cb9132724ddfcd6fd2c1a1db26f45de6f271d02d7a48d92a4b0c50ddddaee7f6d6cfaa1635f5e826379d2afda090ec54c462f5cb22a66cccd3252132f2771c0f2e38b6326cafe5ed2c21e287f1cf5adaf409e62b4b9b2d3459d9b70a0708f919b55cd1d93cf68330451403808e0bca32236fb54c5c33f274b6c4b151b9ad77c970a7cc8c1a3f5db80adde3acc78401a26e94eae5d51e672083ca6ab126a34ba2955f03164bcfb9afbbb86f2fad7153fae146b396b7a402e49c5b954cdf3c56c4969337b970128cd940cdef8bb9ad944bddb6077db30908b48bd26054273916895bd008abe7f481a8aedddab03befb792704804cbe6a51588fbbb0cc38127a904166338c90b1fc0319ba61d5ba86eb9737921c05509afff5f27c9233780e9881b117bdc080a0e76e6674393dcb18e1448fecf3d10fcb44fe68a3eda7d30fe9b91956bce9e015a01801e00a6d848a81c471a563b9acdaa664f4c6a638f7c2be37186915a9739ca5", + "0x02f9011301820fc98402faf080850212f12e1983069bcc9487870bca3f3fd6335c3f4ce8392d69350b4fa4e280b8a4a415bcad000000000000000000000000ae78736cd615f374d3085123a210448e74fc63930000000000000000000000000000000000000000000000005a0d8f1eab8280000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014b30b46ec4fa1a993806bd5dda4195c5a82353ec080a0f7c36d6285912b8f627c437b18d009a67183870d8ecf0fc73480f4758613008ea06ac686e66613a7dabc54502ab69fc335406d0d6fd2cab9a74b47097c55174d0c", + "0x02f9043c01820c568405f5e1008502ceb580f58303cde6943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad88012dfb0cb5e88000b903c43593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000650d422300000000000000000000000000000000000000000000000000000000000000040b080604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000012dfb0cb5e8800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000012dfb0cb5e88000000000000000000000000000000000000000000000b3cc654d78fe95e73ba70600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006982508145454ce325ddbe47a25d4ec3d231193300000000000000000000000000000000000000000000000000000000000000600000000000000000000000006982508145454ce325ddbe47a25d4ec3d231193300000000000000000000000017cc6042605381c158d2adab487434bde79aa61c000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000600000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000b3cc654d78fe95e73ba706c080a03d105d8ca3dffbe1f993d1962e60df96904976af7666274e6b72536ed06eabbfa060efdaf5966babcbfcf7355af6356f4563e15e172cfb8e6a27db596c292ecd9b", + "0x02f902fc018203cb8405f5e1008502ceb580f58302c93c943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad880140c7a6f6948c9fb902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000650d423b00000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000140c7a6f6948c9f000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000140c7a6f6948c9f0000000000000000000000000000000000000000000002f1024c33a47334524b00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc200271020561172f791f915323241e885b4f7d5187c36e1000000000000000000000000000000000000000000c080a0d46cd893e8374cfd37b258f92d666499174bc4206d6490d7db55517f9954e0aba0256038e0d6f705a1a6f8c155eaf1051fc4736cf90a4e3b128bdd7c55bac9a63f", + "0xf86b028502125f613d825208943e180d55386f7fe1441c0e0d7b1b79b768eef31f871550f7dca700008025a094572925a303a4831e4fef20210cafe26266fb97688ac02e5a9c8a70b4966fd9a01cb943314ccb59045804c15500f57e04e3875228a63cbd548cde6369d66a0793", + "0x02f8b901028405f5e1008502ceb580f58301c9ee94ae0ee0a63a2ce6baeeffe56e7714fb4efe48d419881bc213e3cf2118a8b844e2bbb1580000000000000000000000000000000000000000000000001bc16d674ec8000001ff494ffcedaf5691d5d737fbfd8a8b1fcf6f04dd096799dd59e016537b4a3dc001a0f7039fa4032a12cb3d5a2599e38315f8217b2f8e1cc3ef15ad34881a01f1097ca06244f87e4541f839a97ddd86f285855254969bb0731eb4109476a3c2f8831bf5", + "0x02f8b801018405f5e1008502ceb580f58301c9e294ae0ee0a63a2ce6baeeffe56e7714fb4efe48d41987104843555c18a8b844e2bbb158000000000000000000000000000000000000000000000000000fa1c6d503000004bf4d8c999b4c2df6432edd5d615f6d0929ed7bfc6d082144e74e8d6c917bb2c001a0f282c15d1cd33b9e9e3270d9505545dfffa02362d32c1630337d3916db387affa0605452016445e413a0c534c17cd43808a356d4276a6e5cdd0dec8b1ffc4b3d21", + "0x02f8b801808405f5e1008502ceb580f58301c9e294ae0ee0a63a2ce6baeeffe56e7714fb4efe48d41987242d6ef01a18a8b844e2bbb158000000000000000000000000000000000000000000000000002386f26fc1000001d31527f66aa942b93e2276f98db82099fbe704edca8df182800d771db456f7c080a07b4ee84124626997bc8a9bd2e253a546c69812f2ffd0a8c049b2f56a06c907b6a039fd8216ab2f6ad53dcfb02fcd0031472e3bf17ae3ca23b04205f4dc1e3bd59e", + "0x02f88f01298411e1a3008503936aa551829ab394c02aaa39b223fe8d0a0e5c4f27ead9083c756cc280a42e1a7d4d00000000000000000000000000000000000000000000000000b1a2bc2ec50000c001a0b157dc7a49f31bc8ec7622051e0484c5cb71d2ab262946e816931850d333e86ca055f477aa21b1890fd28451945c843613f5830281079f8d3e1b02afd957b77b59", + "0x02f9013101028405f5e1008502ceb580f58301d7d5940000000000664ceffed39244a8312bd89547080380b8c4b510391f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000416c900627e982831c8a4026c3af1a44415170c2ae9241abf0ecfea9a4c9d62c9a1e3b7ca03456ecab60a53beec75011810bab14580efe9397e52851f138eb1e8a1c00000000000000000000000000000000000000000000000000000000000000c001a049d132b84645a86e88c15f29d92637f8e6b934ed5a0cdacdee6bd734769f3ac5a0079c35ded64a74cbb12a638505dcfe6c4e1b0de90e7b5a975f5b1f19cde64f17", + "0x02f8b101348405f5e1008502ceb580f583021b3a9406450dee7fd2fb8e39061434babcfc05599a6fb880b8441c5603050000000000000000000000006a79acf27a5a7eb7a94ffd34be7540e34b216a7d0000000000000000000000000000000000000000000000000000000000000064c080a0747ff3e0ca333bf7fb2b045888aaa619135e9a7a18f771c2ac62ffc2d793635da048cde2afe81eb019f520cb86a8469a6168bfb9ecdd52c77d4032739e8549a563", + "0x02f8f801018405f5e1008502ceb580f5830183e594d19d4b5d358258f05d7b411e21a1460d11b0876f87adf0b4bc3365c0b8849f3ce55a000000000000000000000000be68ef12a001181f9ac477efec411029cffe1add00000000000000000000000000000000000000000000000000007f2cb64425c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000c080a01882dcc7b988693da16b43e59079f93d4da54eb9b2be5cd71cc6c47e24589d29a018528b1840bea8aa7e24912adee3d7de376eb84df7ec501e1263d64e9a5f929b", + "0x02f9013801108402faf0808501f3cc49d28302acc0941eb73fee2090fb1c20105d5ba887e3c3ba14a17e8701c6bf52634000b8c4fa2b068f000000000000000000000000d2bdd497db05622576b6cb8082fb08de042987ca000000000000000000000000000000000000000000000000000000000485a0f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000037ce8f01b71942e0dd12e81ebea73dcd4e1afb70000000000000000000000000000000000000000000000000000000000000000c001a04b9a337c9bcb9ef9a9271817abc644b033613af4d8fb902f01e30e59b2a69aa2a01b0a0fc78a641c27dd48a80401a9c9db6062a28bf2ce417150ce351e1fbae103", + "0x02f90138010e8402faf0808501f3cc49d28302acc0941eb73fee2090fb1c20105d5ba887e3c3ba14a17e8701c6bf52634000b8c4fa2b068f000000000000000000000000d2bdd497db05622576b6cb8082fb08de042987ca000000000000000000000000000000000000000000000000000000000485a0f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000bae146ad179cde9b8d6a512687503ef8746b79ce0000000000000000000000000000000000000000000000000000000000000000c080a03abfcfa49081cd0db4e6daf97c9b456eee4ac7fbd3f3dea5dfd991faebef3dbea05a29a607d7b3941e960f011f03e17e1f19a01b2fd06a8c2b1116eec8663765a1", + "0x02f9019a01018402faf0808501f4add4008301f7789432400084c286cf3e17e7b677ea9583e60a000324880ac3347f23902f00b90124eb672419000000000000000000000000d4254e71937d2fc36c8679a911f62b1aeeb320430000000000000000000000000000000000000000000000000ac1e2d16da4e00000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000b54a300000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000d4254e71937d2fc36c8679a911f62b1aeeb3204300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c001a03a6a7e95d52947ed00f9c23543a5a6d782208802b6c9e955aacdf877d2773bc0a00ef75c8398317269241f31e9d4cb6893bedd47052e3a461cc34dc27d9051b02e", + "0x02f8b801018402faf0808501f757435c8301c9ee94ae0ee0a63a2ce6baeeffe56e7714fb4efe48d419871aeee3cbde6088b844e2bbb158000000000000000000000000000000000000000000000000001a4a42c3568000034c3acea1ced1cc9fd27ea3ad5a9388b8061e5eaf70d855baca46f127cc93a3c001a0ceae79abf8494af8bc6c155fd2a462fb617604e5f5cf5bdc8bc9891f6940520fa05832e9d7053f35ee54d76fde5982e2d919c2b7ab4e0e064e3bc389614e6746e5", + "0x02f9013501468405f5e1008502ceb580f5830120b19487df0306f147e752805261156d5a00d912786b1880b8c8f242432a00000000000000000000000046365df48693de2bf9da6e7e13f84b96689a05dd000000000000000000000000098c19790299f2704c4306ae58aa0f4bdf7e8ad00000000000000000000000000000000000000000000000000000000000000056000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000360c6ebec001a06ba992260842c6b6fb79dcf8f09d978276d08f8c1387384eb1524e07544a4ba3a014fff713157d371432127c390119a51383294c4eb4d66f69bd28ebf72a070e73", + "0x02f9049901078405f5e1008502ceb580f5830120329400000000000000adc04c56bf30ac9d3c0aaf14dc80b9042cfd9f1e100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000009e17d5748636fb9440eae5ee5504d4e902013457000000000000000000000000004c00500000ad104d7dbd00e3ae0a5c00560c0000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000650d381c000000000000000000000000000000000000000000000000000000006534c51c0000000000000000000000000000000000000000000000000000000000000000360c6ebe0000000000000000000000000000000000000000c7d1bceb8ab790d90000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000071d1e9741da1e25ffd377be56d133359492b9c3b00000000000000000000000000000000000000000000000000000000000013dc00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0bda27d97a80000000000000000000000000000000000000000000000000000f0bda27d97a8000000000000000000000000009e17d5748636fb9440eae5ee5504d4e90201345700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000062c3f3e4c180000000000000000000000000000000000000000000000000000062c3f3e4c18000000000000000000000000000000a26b00c1f0df003000390027140000faa71900000000360c6ebec0809f7c8666d4d7a13d2030362ff414d41c09f15d3d042bb2d1563b1f36765967d7a012cc4e0716be4dbff5ec448f72dfe824c4fab0e87a0aba3407546ff55ac77ee6", + "0x02f8b101118405f5e1008502b07a01c083013e6f94fa11f91aa636ef5b0cb62597a0fc49e859beff2380b844a9059cbb0000000000000000000000001866ae7c471022c5551e999c8dc207a56ce323c6000000000000000000000000000000000000001a8c9d0f39bb51ae0ada000000c001a0115e50b731e69007fddc53aea34099d045788bffbe288eb01168eae9600ab0a2a05e0b7cf1571a9722136576a25420dae3e12e0af46adf1e69ed72db1cba89e44e", + "0x02f8b801808402faf0808501f3cc49d28301c9e294ae0ee0a63a2ce6baeeffe56e7714fb4efe48d419877a25590bd96088b844e2bbb158000000000000000000000000000000000000000000000000007980b80351800005e14eeec8882ecd790083b12c4c2ea86b632e79747b63a6689dcf2d787f3bc9c001a059672fb40dc32347bf98f5bc888af7017211bf329affb2f6dfd8c752ff4d05c1a00f8875985194ac2680a987c64a349821bfe56d71efec0ab97bfa2cefd2614ed3", + "0x02f8b3018201eb8405f5e1008502ceb580f5830132fc94876a76c80b32e5cfbb27fd840a1a530ef828ebec80b844a9059cbb00000000000000000000000093628ac572b92d5561ad19446761394fdad22fc100000000000000000000000000000000000000000000010f0cf064dd59200000c001a0fad9b6f6e14d2cd3d10518ebfddb216209586add598416dd053388826fb7962ba03bbba27f988ef668cbb4dcbbf49b1fa6e140e4bb9c18f851a38b1c8083ee2c03", + "0x02f87301048405f5e1008502ceb580f58301348894ca1de18ab658d8fe3439b538cf361b30c500d02387208d9273d85a4e80c080a0eb96e050cf314770227a4f33a669d2aca841ea3c890c989650720405c7d22469a0342aecc7158b4e077b0ca44530f5dfb0ed66056938617f1dfe39506ead93539e", + "0x02f903d201078402faf0808501f757435c8301bec694d4b80c3d7240325d18e645b49e6535a3bf95cc5880b9036408635a950000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000b58500000000000000000000000077f801db98b34b03d4da3dbb2ed3b61258e62f7800000000000000000000000077f801db98b34b03d4da3dbb2ed3b61258e62f7800000000000000000000000000000000000000000000000000000000013c9a110000000000000000000000000000000000000000000000000000000001144a070000000000000000000000000000000000000000000000000000000064fde17a000000000000000000000000000000000000000000000000008e1bc9bf04000000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000010e549f3fd0cdeeff94c4a7d5348cb0146fb3cfab2062a0ab9ce95f8b69b14d1aa8e858cad3c5b8de18ddddc3cd7ee5e445c871dd9c2b680daf181172b6d30fe5cd9ead1f5c897a2811eb5a75d91fa0fde64e250ee86399f092c2f28432b169912890589a222e30125f94fe0ecc62ce6a64a55173ce05961f0082ea3cfe540d267f70a5729dbb70cd0e90a619912cf09fb37dc7f05c82e49738dd947c42038ad236ae9f5506526e51bc67795a8622635072ff71d508823ea78de1c905838d633f7649c270d85cf1fa6e686975513d1f7b4c2ead0d07524b39062971e29ccfd059c0fef6a8d93dc135030919d239ebba31bcade5c84a675ae01f8c11eabc66c377ae604865d1b9e763776b41044a8e922f8a20d24dc67169a6c4d24b4c8d2565329dc405b0ea72b2fa26146cfb479acd302fc8e2f49cd2dc7d239eb55f77b5add227604ae62fa7ae8bde0b15be58c0296febfd0bb5a88d8cba7d5b66029eaffabea0000000000000000000000000000000000000000000000000000000000000000f47f4f4df7da36596545f2152e25f53ab42298f7f0654416b1aeeabc340bdc8b0330e9dc43a98d1a70a990f7a3754ede2b7a64de2df85ab95577ecb4fb6d4d990000000000000000000000000000000000000000000000000000000000000000381c1afe39558ac38a213df9c4b61f4bd79ce80fff5dc5ac773715cb19e3b9be0000000000000000000000000000000000000000000000000000000000000000c001a0466af3380fef0d5741fe8484f3940642533fb69968afd47987c1785138550473a023b2a9f07bbdc45b093b362c2f80fab216f086be63a4183768ea12b82a6f1da1", + "0x02f894011a8402faf0808501f3cc49d283028d1794de9d2181451620bac2dbd80f98d8412a6da60fe580a8efef39a1000000000000000000000000000000000000000000000000000000000000000372db8c0bc001a092617c3ccbb9ace9d815cbd079272ac41bd466c696d3aa375d1f3174de56858ea07cc7cc6ddca2b470d4dfa2ac5a58b71fa49d20b60bd39b46f048c041def789fd", + "0x02f8b2018201e48405f5e1008502ceb580f582b4969496610186f3ab8d73ebee1cf950c750f3b1fb79c280b844095ea7b300000000000000000000000021dd761cac8461a68344f40d2f12e172a18a297f00000000000000000000000000000000000000000001041cccd61fd4fc220000c001a0314ab6d563bd638aee7fa43d1bc4d4ee2417fa5bcd8e2b181eb0b2a386bc3b7ba03112a43fec744b462831c7409f9b5610faf083ba5a418cd843177eda3e6b7736", + "0x02f8b30182065f8405e69ec08502b82ea800830110b9947e52eb9fadb02f95de1eb8634dc0b4bbd4628f3880b844095ea7b300000000000000000000000000000047bb99ea4d791bb749d970de71ee0b1a34ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a0edbffb0a196cd02dacc675918736f76d8f4b78d3e2b5b82f57b21852324779e5a01f3166b6dbfca7a56c40e5558f102b42a61be892045b997f218f30c440ff2b22", + "0x02f901160182029b8405f5e1008502ceb580f582ec4e94f4b84cbeeda78c960eda07da4ae8828594ea515380b8a8b88d4fde0000000000000000000000002725bc53a2f792d4fff5397092ad631f51700aaa0000000000000000000000005a98db5d98a9716ec48012c364d42768d7b1e243000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000360c6ebec001a061e295684da6c6c058934d827e9cff65d34356ccb63a4015076680b404c871d0a0169facd30968f911a233caff684db10bdf371264a0b51eaf93d590f91705c3ce", + "0x02f9035b010484010fabe385023c3b4746830479a294881d40237659c251811cec9c364ef91dc08d300c872386f26fc10000b902e65f57552900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000136f6e65496e6368563546656544796e616d69630000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000023375dc15608000000000000000000000000000000000000000000000000000000000000eb7d1f000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000004f94ae6af800000000000000000000000000f326e4de8f66a0bdc0970b79e0924e33c79f1915000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c80502b1c500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023375dc15608000000000000000000000000000000000000000000000000000000000000eb7d1f0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000003b6d034006da0fd433c1a5d7a4faa01111c044910a184553ab4991fe00000000000000000000000000000000000000000000000000e0c080a03e307cbdd556823f6c1e62e32b4968deb6fdd1d572cbee7eac07411ede411e3da05fa59938d2dc7ae668f83e6f16ba330661687d6113efaf0f81b5472f7b5cf17d", + "0x02f88f01088405f5e1008502ceb580f5828caf94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc280a42e1a7d4d000000000000000000000000000000000000000000000000000c6f3b40b6c000c080a0e34071b9b7a00001e33dc9ece3c868e1eefb21c2b0d210cc7b0f4670dc622acda05e3e16c226c7fc252dcd4d1d6112211d930e99aa04beb82413912069249f8dea", + "0x02f8b701058405f5e1008502ceb580f582701694b584d4be1a5470ca1a8778e9b86c81e1652045998727147114878000b844e56461ad000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000db4af0457279effffa5a4be6e3b941ea240d8f9dc080a0d752b19bfbb31c0cadc48022d4a9d1426fd17e849c1ca4b3a87c4e6188185fc7a07b5a012d8fb7b37e79bc7c0633a87110eef72166c9f7dca71b358f111b9c3c54", + "0x02f902fd0182026e83bebc2285020835c4b68305221094881d40237659c251811cec9c364ef91dc08d300c8810a741a462780000b902865f5755290000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010a741a46278000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000001c616972737761704c696768743446656544796e616d696346697865640000000000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000018ab2786a7200000000000000000000000000000000000000000000000000000000650d3bc700000000000000000000000051c72848c68a965f66fa7a88855f9f7784502a7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000070e75c990000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000108794965da6c000000000000000000000000000000000000000000000000000000000000000001cf085811d0d1a14f1b4da598717dfe9f697e8d756b8f2386172102f3b32cf95fb13679fb740c53e2110ae831a5c9668246d7fe3d7483afd30c671d24f30fc0e94000000000000000000000000000000000000000000000000001fad0e04d14000000000000000000000000000f326e4de8f66a0bdc0970b79e0924e33c79f1915000000000000000000000000000000000000000000000000000000000000000000afc080a0af47adc6df9c8da3b40abfd6a9fd576f52f30c320f92f4717327adef91df066ca02276054e598f1998d4d8836c93f5956b6147fca6a3d437a04e88d2210c54c6b3", + "0x02f872013c8405f5e1008502ceb580f58252089437adf7b1a95a3309fbc58f80320d32a5b72caca287a327cb389b310080c080a0562adda6d257d3c47a4d34f4f94eae088e0e0ba833507f7741d4d45c0fdacc19a0389bcf9af90f8620c3f55fec3ef29ce5b08e576f842db64a390c1fc58e434e94", + "0x02f87201128405f5e1008502ceb580f58252089423392d66721cf9e8c23e346139e81ccad62b92e2878e1bc9bf04000080c001a002312d85c66cf17b6294db8c74b55534c187740323c440dafb5c744d7cdb3f76a048018cf5276bc2caaa3bc1d60d14a9ee998959a7581063e41685599e81ec8d74", + "0x02f8b701038402faf0808501fc8c382a82701694b584d4be1a5470ca1a8778e9b86c81e165204599870221b262dd8000b844e56461ad0000000000000000000000000000000000000000000000000000000000000089000000000000000000000000445fbcdfef289f7912d28825edc7bfb74f419e5dc001a089b4cf16fab2259337030947f546ac39c34242638c6226ead7037fb8ba943eeea03e0682ba6675e121fcf5760f3458a65cf57b44f1bb12a11520f2f1e29b7d3cd8", + "0x02f872010c8402faf0808501f3cc49d2825208943780f6ca38dec5a83edfb8826486fb1ec9b182918708e1bc9bf0400080c080a019ebd7842667fa13d5443dd4fc0eb5a550d295b2f016640c48069720c4cca5b7a06613cbf7bac311b61db3237875b8d09e8b3a779d9544ab6895c90e71e0d0d3ab", + "0xf8ee048501f19233e28301c9b69400005ea00ac477b1030ce78506496e8c2de24bf580b888161ac21f000000000000000000000000a460051def6ec25bded4164722fbe6230fbdcaa90000000000000000000000000000a26b00c1f0df003000390027140000faa719000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050021fb3f25a036f34b67e18b41aa1fb43ab94867a892a0a9fd400fd7f1aa52b227cd47065d02a053b3f27507e7a9523e54bb4070fd8ec31908812d0e475990a1823b93761b8e19", + "0x02f8790182013184010fabe385023c3b474682afee94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2881d012bed3c91000084d0e30db0c001a0298573a2670e93f4cab424e66e4d8be46a5fcc160dcb7f472952b441307b9468a07414351600bf1f3c367431c79caa7b3d69f8623b572ba8afb0c5d648e4ad9671", + "0x02f86f01020185028954caba82c18594c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28428e3878084d0e30db0c080a02583325121bc262f83f83839c5faa0b1172605d971746e342705572400b449aca0589fcbba5567bcadc1050bb24e0ee22bfef7ad803f66e6bcce646ce72dca46b0", + "0x02f8b1012284851ca9a08502d044dd02830131249472bab498fa50a33a03362d0024bb27efbc50a7b780b844a9059cbb000000000000000000000000ef811bbb9b8a2ce8f598ba04329b6db8b36d95be000000000000000000000000000000000000000000084595161401484a000000c080a0898e328e73116724d0d0e3ad2f0dc95401cb5c7c3abad90e770f634c0b28ae71a00e563a05814bca0570ca44e1cf26a06d08ab6695a28ee0c75b1f566aba4627fc", + "0x02f8910181838405f5e1008502ceb580f583011cf594fc8f838d593bce8da977c83bdae3a6df00db9ca280a4074306c2000000000000000000000000a848a1d33d8ef1633397a6acf617620fab8e5da8c080a0bb7d0b5d028076fc5b0ce6accc9cc24486cb31afb30a444b590f0b9de9e4a419a01a473551dd6f6d3c93fa9da2214dbef2b343bf09198446fe637173b2ac6aa40e", + "0x02f9015a01648506fc23ac008509e5bc4ec683043206947a250d5630b4cf539739df2c5dacb4c659f2488d8803782dace9d90000b8e4b6f9de9500000000000000000000000000000000000000000bad97982994a61d7d504b94000000000000000000000000000000000000000000000000000000000000008000000000000000000000000014c0c7031e0fcbdd0db81c32a90b29ee5c41d1d200000000000000000000000000000000000000000000000000000000650d3bc10000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000c6980fa29a42e44852e29492268d9285d89c9dacc001a0abefec6763bba15dcf373f8ef4d68be877afeda8afafdf93d9665659fe34cc91a03556acdf4c8c6fd7cd4c54308aa7d59b55f33e9d6b63f88b537b4b57238d6cf7", + "0xf86c0a8502710caab782ea6094897b425dab19eb886dc6ae2010fe2a0de85308fa8802ee03111e5f95608025a03997154468e725f5c74e3482479eaab55706fadbd77c11a52d952b538ead2fdca03cb969906b9a7bbad27798e074eb5d9b9a1143de8a327fb8925bd2c8ee0f0116", + "0x02f901980101839896808503b9aca000830202059432400084c286cf3e17e7b677ea9583e60a000324879fcbb8fc976611b90124eb67241900000000000000000000000000037fae997dc49e357f6d717f397b14241472b9000000000000000000000000000000000000000000000000009e04f9aa34261100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000b71b00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000037fae997dc49e357f6d717f397b14241472b900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a0040420abee74512bb5355caad3f177779c5556dd3d276b92c88191f65fbe1178a04fe64531b6e0216ba29edc217489bbce8298ea71ee4eb8b4b0a64245a0e100fb", + "0xf901538204fe850251cc0894830f4240947a250d5630b4cf539739df2c5dacb4c659f2488d879fdf42f6e48000b8e4b6f9de95000000000000000000000000000000000000000000000000005340a142a486a800000000000000000000000000000000000000000000000000000000000000800000000000000000000000009e1b2e13d5adadd4f18a84396ba3825e9f8665770000000000000000000000000000000000000000000000000000018abbaf99d70000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000011a15d6ba4c27c89e468e959ba2230337317184c25a08e6c0aac59fc29108246cf7b05b3a133fc6f87d2a84e757f4cb257d2037ed369a05afd77fe4804d67098e13d1abb9bc0585d54dbfbaf2c4c4c9846e55fb65ff6ff", + "0x02f8700182ecb8808501f1106c848252089413f2241aa64bb6da2b74553fa9e12b713b74f33487d17a925100884f80c001a0f60e642a491338ca56b7975712bb0ef2c3fdaf3631f53bd16f17704002b92688a0593d2ec21ecd01a46982ffa35732a7ac04a1eeabfb0b8366f23274160d68f020" + ], + "withdrawals": [ + { + "index": "18476769", + "validator_index": "711858", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "16008754" + }, + { + "index": "18476770", + "validator_index": "711859", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "15964023" + }, + { + "index": "18476771", + "validator_index": "711860", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "55978346" + }, + { + "index": "18476772", + "validator_index": "711861", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "16018825" + }, + { + "index": "18476773", + "validator_index": "711862", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "55701351" + }, + { + "index": "18476774", + "validator_index": "711863", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "16048658" + }, + { + "index": "18476775", + "validator_index": "711864", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "16109594" + }, + { + "index": "18476776", + "validator_index": "711865", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "55192849" + }, + { + "index": "18476777", + "validator_index": "711866", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "16034174" + }, + { + "index": "18476778", + "validator_index": "711867", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "15996922" + }, + { + "index": "18476779", + "validator_index": "711868", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "15988508" + }, + { + "index": "18476780", + "validator_index": "711869", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "15991175" + }, + { + "index": "18476781", + "validator_index": "711870", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "16040454" + }, + { + "index": "18476782", + "validator_index": "711871", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "54619862" + }, + { + "index": "18476783", + "validator_index": "711872", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "16119355" + }, + { + "index": "18476784", + "validator_index": "711873", + "address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f", + "amount": "16122912" + } + ] + }, + "bls_to_execution_changes": [] + } +} diff --git a/beacon/types/testdata/block_deneb.json b/beacon/types/testdata/block_deneb.json new file mode 100644 index 000000000000..6dedcfc343c4 --- /dev/null +++ b/beacon/types/testdata/block_deneb.json @@ -0,0 +1,2644 @@ +{ + "slot": "8631513", + "proposer_index": "1124880", + "parent_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "state_root": "0x855b6335a3b955443fb14111738881680817a2de050a1e2534904ce2ddd8e5e0", + "body": { + "randao_reveal": "0x8c290463d6e68154d171deeca3a4d8d8fa276c72e9c34094f8b6bf89e551e99d63162e362a936b628af4840d69b10c24191e892d0a282bb5358a5669f44e42b627ebeb63fd6467c7aad62636a348b5f4edfb8ce01650e4d079339d9dc5700f05", + "eth1_data": { + "deposit_root": "0x636ab1747c976fe08cf337b437ccbb5f543e0d0c6b5d70097c3ab7737c1748d5", + "deposit_count": "1342638", + "block_hash": "0x429813f0390a9e104740e8a24ebb83ac03929dff4a9702385f2bf24391ba754b" + }, + "graffiti": "0x526f636b617761795820496e6672610000000000000000000000000000000000", + "proposer_slashings": [], + "attester_slashings": [], + "attestations": [ + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "19", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x903146f136e4df8200be0229eb96bc9a2409d04763df61ebba51f54cfbd9eca2c88274cb94828c2705bff1454c50322e03372883c2dd47ee329cd17a3653f44314fa8693c73fa2097f622e7f2e163f7b7cb688aebad93e14c273d406743ec7ad" + }, + { + "aggregation_bits": "0xffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "27", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x99d3c97b5036025d1b30ac32efd469a815269e2575a7525b1cc8323db85556aef7af7464d965ab9b6ee1804005436a0b05faf870cb213dff04552ddffcfe355987d35201e58dce3897c0de27a19016321fba9ac346452755ae9340f60cea895d" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "44", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb2f0775dd77d2969cc57c0d03ccdf0c79e9f4d34150a539f79d9f090cdf918a4092f1170008aca3c5c7d6ddc743f79d317f8300dd58ce040ac7a9e50940b3bae964426a7883d143012e504091bb669510d5901f11d008b8b630d8c42ade6863a" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "22", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8fa4c08ee7406d44034e6925dc65e1ed9b08d9fa32260f0e49d7477b5ba9762c413d7385692c498a57217eefc4f11b4b0c6a470df5f1c1e98f890975424af15a6925e657628e518fbfd80db38553790e8ae5dc6704de1cb727011ee084bc1af5" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "35", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x81ec8b97197bc59634b30a2356035f664a648f6aec4d30c7f357ad33d39f28205596683defcddf1ba6fcf1f3fced1a470b8a78ea360d7f1f1db4e2e5d6f98045071e5fe04338865d986c6b8f4aeff0d01ce19952d9a7084ee21da0d557b17f38" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f", + "data": { + "slot": "8631512", + "index": "63", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x950881fcc3a1d4d88feef09eb6cf4e72bdc68b76754ce5d496b2f1232b9ea9851e453e45eeb8e23524acbc756cc7b9f614ecd1e34aef281487d72e73078e0116ac30a846f2b085aacae17a5066aa6eb383579e35ed70508127f19e8caff78ce1" + }, + { + "aggregation_bits": "0xffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "58", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x940c731c48b8ff0d522fb38f301228f47272b89b5bd1f1ecf44d79bf762616baf05be5ad0f389a9524de812646ea5a50096ed04747bf642f8d8a75b60015d5c690414ee4d87b19d8fcc111b1cbd594aa78d939205fc5ed28e78b82afdec0f92c" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77", + "data": { + "slot": "8631512", + "index": "53", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8c528252b23858ec845a50f6fd0d001639c8dcc8c665cf10bc52c2076ef0b97711ca1348bdfceebefc45ea9065376da90217d1ec09ae4409683b6d461c80458f3f9bc0308e5337ebd856bd8217a8b530aa56f0b8804cc181b636b990e88853c7" + }, + { + "aggregation_bits": "0xfffffffffffffffbfffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "3", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x95b64b1648464197415f13f02601e0100318af579c8774fc4192124dc2ed181496c09304a7f3a342541b3da1a82affe9199d3f4ef40285dee2dc082d6783cd84e5df15ee29c0a4436eabdeebe236a2973b9eae91ef9c929406e14de1ad78a7e4" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "2", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb40357603fb9b486e6c37d0152e52a76dd5e385f63bac25816bc210bad5501071474745ba808e1767b95c5a7202eabc512010e470d351ed49089de3e0f602ef3d6a4cab8603ac27217cb26d523517d340bc784270191573b18c5c7f4f68e70b2" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffeffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "9", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x866b139ee2b3d7771212031592f284836624427883ea7d9f9e247eb507c18a1044bdd71a27121fdde10a0898ba536d4400a9af47a470f61fb7367f038db35e1dcc4f9567a6251e9c01f1cc43624829811485eff6e64f5052f2f1632d6beb3728" + }, + { + "aggregation_bits": "0xffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "16", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb0742e0f82acb1366a6a1887388a80461c077e705fd1a5776491e80b34bb2c60f1626e2f4fafe3f0361da79731d465f40667b2abbd2abfda557a845eae6bd414593a4bcc9a82f3cc1a4a0fbc86bf5255caa794cfbcee4c87619b44ee5be8e713" + }, + { + "aggregation_bits": "0xffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "24", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa606e4d20408f30f4552e3e1d62f6964140d2dc4a297f2c300ecaa35594e658a55801d427c8166a1033bb8d46daeeb371779c4c1c89cbadd019411177ad63b22d42f083e0882c73df093523bb2184f5bcfec544366c3180a3c6d5d4e4715bf01" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "20", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x886d4565a820a4cf546207ea013939830add03e5147ae9bd6257ef886dae1119edc6e3677edee1937c433f33646264440d7c06c91642cff4f8f875fbc706d590bf51105ab8e7c3ee7779ec9fa40058935ae30227c338608f05650df94157422c" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "32", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb2ec56e1cafb774c4f3e86447b9e69c997699d4a611846f582ba6d60886aff12cfb87442cc650996cbe30f35e0c7c15f034037762103bae2a8b8461ed21a6e6000a3f1afec40eeee45ed82243400086d3e6527d9cd00954d661392d492ca93be" + }, + { + "aggregation_bits": "0xfffffffffffffffffefffffffffffdfffffffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "13", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x872a82d58281f34caf12e34046ffd1a137415090ac37b84e797e1f9800b2ca339d5d6fbfab056662bfdbe201634b2c5c0f3001a22e181ff38ec6841b804a3aa214ee0ae863de8db9ded627280e05784f0c715dc6256df492aacc5185dd602369" + }, + { + "aggregation_bits": "0xff7ffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "34", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa491e4ee4f0dff0b0282b4fa3dd6e6a5efad861a33f1ecddd2eb9cbbdf663a88a19de6643276ba341739b9a0d6fed65a09b33d499e947d2836bac1c098a012d9096d4bc95eb86953dd6ea425b973418de05fbe3e439835bae81d61db3c85e098" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffffe3f", + "data": { + "slot": "8631512", + "index": "15", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8663ea9804a9a07f32291db4018a20024b06b5e45fa55de6a9a9d6db7f75f2af1e71af643eb6bc56f15da20ba74af1d80e6d0d459c69e2971d71a72d83a3807f269898669e850fdf49dbae277dfe3e48dfb5b34436c9476e137a34f2f56a97b4" + }, + { + "aggregation_bits": "0xffffffffffffffffbffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "8", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa9d69c457435763e8afd1e2c26b2b39e063e951ecdeefc1a3dcca848d75c617aaf25c5f79f2185f64a54c13d7883ee1315b18d1510b35e194b0502cd1e56ea470cb9eebb5592601cee169e4b65c79ad34efa1080e55523cf08060550f092db62" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffbffffffffffffffffffffffffdffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "21", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa42469725f212b6319a9113eb681dbbef08297b4fc458e16c8b157a77c426136c1215d3e885753ee5270f0e6dd53e58717800baa56e74a50d59c975a6e6838ec3d4e7e7df71a3ea02d490dcf496b96a16ced37467e746308b39f7ba11c3d417e" + }, + { + "aggregation_bits": "0xfffffffffffffffffffbfffffffffffffffffffffffffffffffdffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "40", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x918ae9885a56fe78cdb92a710af61738bad108f08f63ced0e12419930dfee4191c91bf7b32c8189a206f73fa497ef88308320d4fa1e1437e45946ab8f372e292e0edd897696a6a93b7ea2f6b6f97e9d2e2c10b400a70591b1cb482f7f15e383c" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff3f", + "data": { + "slot": "8631512", + "index": "51", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb0ce301a6e464261782af4300275f915fd1e9bc33dd3c1d8d79476e9d3fd2098fc1b4d967c9773864afcf7de12e579260b0cf8a7048a03c4b8b2715e5b8dd7587fbf5e570e4b77e31fe92fcec7db52ef909106122a9ee1ac56c856a9022fd54e" + }, + { + "aggregation_bits": "0xfffffffffffffffffffeffffffffffffffdffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "11", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x99767e9d12d961d8c2845c230a6a56b753e8c9eb9d228a178d8aefb93a96c320d87ba648199db301af51ce55628cf1a70f5df1a5c150130ba81113544bb3cf361a8be881590a7fc123cc82023ea5e4ea115e59a1c765ef8f926f199a27ee4d6e" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffefffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefff7f", + "data": { + "slot": "8631512", + "index": "52", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8452d2819e0e02ed4bf803a31d9a0f2b2b2b249d4944f4729e3d8538a1dd16231061706bc82d56b0f3365b867dd3d2840bf813e116efaef44a8dc81ed37c4662503931f479e1ee33095195726ddd06f843ce4f1be58009a9209528650a8ec40f" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffdfffffffffffffffffffffffffdfffffffffffffffffffffffffffffffffffffbffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "1", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xaef55f46a3fe443eca0644769a0e1ee3805c60feff89335493789c8814223fccc863cd42250a64ef7e6e026ab8171ec315eff1f2a6d080ffc288e266aac71c41622c714578c10942bff43c11e283c41bff28fa29e691f71f19e1f994d7d35045" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffbffffffff3f", + "data": { + "slot": "8631512", + "index": "59", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa3503124a73c7e04e7a4912364f445b6dac529c9058d7633fafddcc837bd23464d26cf2f65d5f368b9707d3b4bfe13501028d3543f1f0b50fb5069ca377b7ba0e0cf54734f581e5fc19ffd6eb67481f0895781dcf677977986b79f106d2eeaac" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffff7fffffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "18", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa47b9fa745d4120436e297fefcd31c16169be9d4f20f55589c0d4e5cd4d84c8d3b88bb0a94778ce44dad47dd9f79e2b90ae0956a1530105f450ae10ac229c2de887fbcad2b7ae339f3bc1a8ae505bda878bf5b9e021229d797345a483dd04239" + }, + { + "aggregation_bits": "0xfffffffffffffffdffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffbffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "55", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x979245abb880bccc2c3f67a31e913def8e090cc821aa3be3744f1c503316421cdf1711d6287a6789b5c48d92bf424e1b0c7dc776ad5f9c559f59d4ef98d495d25321ac2c8f33ff943c442662c691bf348494480757e3867a1d20f07e21eafc4b" + }, + { + "aggregation_bits": "0xffffffffffffffffffbfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "54", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa3cec14a422ae48d91b03da27937ac6acd1e258dbc6e33133307fa1077da8bee97608a0a806400b819fb46d06f23417f0c8e5541ecc438e783ce27cd202bd0d69ab92092df7b8bd372b2a18f4ea30ef39883c769a9eb2c2bca520dc44c0e6eb7" + }, + { + "aggregation_bits": "0xffffffffffbfffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffffffff7ffbffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "49", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb356179743682d9df75eed9cb2398b3a7d91df8bcdc1abba65aff74b61c31bd91935893ed6223d5d61b1b7f5f3e5f819068ca705c824fa9860faf19022208b24fa3d9cc38e304da3722308dfab3535cc4460ed416513e52e87ac56c3d217b3fc" + }, + { + "aggregation_bits": "0xfffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffeff7fffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "50", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa20edf17e5b0f1fa35a3e4327432db00c1957e5ea6eaea5798c442b3de5b01686f8b82901ebda7860428e554afda95760e729d9d917f36f74ce1094fde666665b7f5b4b11e71e80566da43e0e597a0b3e23bd5a8d57e380885622822aa0a14df" + }, + { + "aggregation_bits": "0xfbfffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffdffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "4", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xad119153e2744c66c9b8066d694e49db4ec0ffb8a2bb984db630bc00c7a6e6ebb343b7a6f7e1ac1f40762bfbccdcbbca09ed57f768a2baa18073e3c144d79bb19c7f1ada89cd44297d51aa9a399963ca99bf5c91c653bcc2502d575df557c732" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffffdfffffffffefffffffffff7f", + "data": { + "slot": "8631512", + "index": "26", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb9a04ea00e249207cfafe9693d77e87cdfa34512db9781dd32a7fb80dcf5f4334f848574966d56a6447e54031e0eab2a08b75f915698d2cdf5266ee292a57bf265135887303998fd99fa2b654117667649e0ae74db015ec954c9ad18988c92d0" + }, + { + "aggregation_bits": "0xfefffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "28", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x88133f0ab0d7cdff20b844feb4275ae15b832c91e46afae8704e18539da6596fdd8a37f95559172b1afdfd40b340a23a180900e7fc2679e1b257206e879db706e0c9d393ccbcbbd1793c24834862f6d9fa3d9614118b27def456148fb2cc6217" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffbfffffffffffffffffffffffffffffffffffffbfffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "7", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8c379743152b7330835e9a740a0b102a762225c2e5108faf02df7ff9e6438018f5331c3ab5e8b1424388f226250e622c145580ff9f972a66767bce5d9d74e34fd809c12cf404940f3eff0596cf4a2187cbc0b614a9f25a9f5111fe54685e5ea2" + }, + { + "aggregation_bits": "0xfeffffffffffffffffffffffffffffdfffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffdfffffffffffff7f", + "data": { + "slot": "8631512", + "index": "29", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xadd685e2acc665e03c10eec1777b1470650b41c931fd3856cfffd2413709db3e77a163da695f2e79a06e447f8331ca5f12c8f8737e26fe56c2ff203e884e0cc7fb36c53e1e7e517a9c2628805d583c1e14963077abf03a5dce22145b50ac1b37" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffdfffffefffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "25", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x994f6497b6671372784ee8ad0876f147dc724d0074b8799925f4f21d318d1e2b8c78ff571a234d32da916dc94dae967b194073192ffca59c5bcc767b5455472edfaf46e7bd4afaf143f9ee562e4fda8ea187d809e2e68b803918d266223cb938" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffdffffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "23", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8efd6e9c8c41beebbab07a4952739123a554b16d527ae4e15982d339fe50388b6169d617c83e11a29230e7ef464e31880bd21ce4f9154faf101bc6233ed09d4ca8f51ec143c437428f47f64cc0b104754f3c19292a2bea3bc4d292bcd5a9da1c" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffdfffffffff7ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6f", + "data": { + "slot": "8631512", + "index": "37", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa8b0c046f9cff0a03e328c384b96df4ef7408276ebb2731f3ca95d12239db218f4feb4669a053b307d991d77ba4692530d6b4f27292e79d51b458cc13b109e15d63504a4cc16ecaa15f4e396a3860bb5f5977a8c8da37a786beb88a48187363e" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffbfffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "10", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x87651e4014f8c00148f196776463092f1574eb24816cae2b681ebf944f74957757b5e90550a73b2d1cbc3aa9f9a9b0ca05966502ba0a1d23182fe2a99c86e35e1116069ce4c61aa5e8548a7a42ca1465c30f9c3b3e0689d2ef87dfebfa78f2fc" + }, + { + "aggregation_bits": "0xfffffffffffffdffffffffffffffffbfffffffffffffffffffffffffff7ffffdffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "17", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x801a1d09004c0fc95ed510b9deb1a98c4abd88e91c46179ff5a7f17bfa1f2db48a0b42c3110cddc71ec0097185d6cd7407e36483cdb36745a6a0a23d3fad3123c0ffa5008f26c9a75b8bdabd2753fe9dbbf08d292d79a73a2736d533aa9fcad2" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffbfffffeffffffeffffffffffffdffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "46", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb564bc7299fa09ae6d355ad187719ee147965f3cedfacc0a0f2b2b627c06e0535067b4548d810d9f609e5d55369e9b870dce515bb482202f324c93d8ba100f1893073ac010399918d642294f08b3dca311f56be91395a6bd4b5c43666aff123a" + }, + { + "aggregation_bits": "0xffffffffffefffffffffff7ffffffffffffffffffffffffffdffffffffdffffffffffffffffffffffffffffffeffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "6", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x910fb8a623531872777c69cd9098b4599840000067fe94eebb61a5aad67520718e3c5d1b0e674ba334e501d5414443e3132ffc00a8bc087d1c7c24c1110d2ab3eae5eb52fdc1542d2e85973eb94193735ce397bd55db2adaba1c1c5d80dd9ef1" + }, + { + "aggregation_bits": "0xffffffffffffffffffff7dfffffffffffffff7fffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffff7f", + "data": { + "slot": "8631512", + "index": "39", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa74a52e52313fa31a6d69f139de567134459d9eeec28eefbe5d0f05bbba2c755a3d854d058ccf2ebfc45e45209d381681964e6a419bfdfc8921f366bad44759fbe7c768cb55bc5353600b8b51f08b6f5f7448f42bde2de52466255a1a255145f" + }, + { + "aggregation_bits": "0xffffff7ffffffffffffffffffffffffffffffffffffffbffffffffefffffffd7ffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "62", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xab1adcc9c42316e0dd3d02d056c6dba3baff880f217cb256f88262fb265d813c0704fbf08e2e60e1af25618bfd637d3918161bf3750803103fb91df250c281126fa3119ea020ff56ccee61cf4b210ec8227cb90390be77258037f46c15d5e6d2" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffeffffffffffffffbfffffffffffffffffffffffbffffffffff7ffffffffffffffffffffffffffffffffffffffbffff7f", + "data": { + "slot": "8631512", + "index": "47", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x84180e4ced9a7260462715bfa0a474693bc6e56ae4d4595d72abd6b2fc16afc775bdafbc4690e30f5495be40dbd5442609848e264ca48e7bcd6895ce3340b57521a266c3481f01792f1e7cb7215105345f6d05d192969b07520f02f1f61d04bc" + }, + { + "aggregation_bits": "0xffffffffffffffffff7fffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffdfffffffffffff3f", + "data": { + "slot": "8631512", + "index": "12", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x901c3f60fbc25644d817e3964f29cb3c5a090cb7c9c843a23b39a1211635ebf4d0a7599ec511b5a637e60a05d6b809600bf096a151434ef9e35645ebbf943b442cecb3745d2a91dcaea4cd71e93e334827c558a78f7ea9101db95deb5773fe13" + }, + { + "aggregation_bits": "0xfffffeffffffffffffffff7fffffdffffffffffffbfffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "45", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8303e3e0aa2ffe77dd162a3660c8916a964aefee66152f27be11da6ae97e3704573b5a7c9282a5e5a9f7fe340621629e03ff9a4988b286a895e2568314f151ad250518d356b2ed33d6017b9405c2b341213d7654fdc4924b9d789f3568f860f7" + }, + { + "aggregation_bits": "0xbfffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffbffefffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "38", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb9697d52d9483c8770a73a7b28cc6f4fe2fbd9e269181483445582a18b0e580f8ef1680ed68506ac52e4bcf5285a1ae108f97d2baa542d39b1efca6f509c1344cca433af5ccefebe31d1765b5e697db7fc40a917f995982e6d71c17c074f265a" + }, + { + "aggregation_bits": "0xffffffffffffbfffffffdfffffffffffffbffffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "14", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x873a15e74e683d9a128b822ed8c73a592a6abdf5b6b67d0391614cb2772f4b6ccff445895ea34f754e7436986fa3539d0875cb6db0210480f118bffde9cf04504990a57e040384ba5fbfb921525a1fab7b2eda325df5d49a99208578f175433b" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffb7fffffffffffffffffffffffffdfffffffffffdfffffffffffffffbfffffffffffffffffffffffffffffffffffffff7f7f", + "data": { + "slot": "8631512", + "index": "60", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x98e3833f9dd9f4a50342789ed1cd462072d0e3e04e734d352c8366bfeea49a0e94def4c54461a5c603ce53ba1efa07c60ec81de0625f0b770f858b90b5d8762b3111c26357b026384b2f1d66676500d5090f7f9b781882bc949a722f8a2bdd0f" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffefffffffffffffffffeffffff7fffeffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "48", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8af584ee4533db14726f67b0045ce97a185fed5c60cf3a1a5092a7335fb7fd804399362373613d9032fdff3d6993f0b8024d46db51119fcfa9d631657075c1c7a2d86551df69034d821a8b2a587374b4c827c9031ba2274d772ab3cb35360cc5" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffdffffffffffffffffffffffbfffffffffffffffffffffffbfffb7ffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "43", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x909dbbd5a35c63d3584bdc244753df1afad73d36e322f4781d8f729bf859b3c059aeaaa496b1eac32aadb21a0718de5114517884dc2333373b20fbd38f6a44c5a1e4783c4cbcde6f47fb2bf88ad1e5cafcf83ed6a21da26c25b67cc7db90fb96" + }, + { + "aggregation_bits": "0xfffff7ffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffff6ffffffffffff7ffffffffffffffffffffffffffbfffffffff7f", + "data": { + "slot": "8631512", + "index": "31", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8addf5882ae131192defac2c0fd0fb2823b175ef9c3935eac43fa6ac2ce0799320cc7ddf5198cac4fca3194bb6c350c50d5bd7961585da8aee3947fd70bcf35850afa2422335a9dabe1ea355ef8656621151a64c454a2f151b218f865d3208d9" + }, + { + "aggregation_bits": "0xfffffffefffffffffffffffffffffffffbffffffffffffffffff7dffffffffffffffffffffbfffffffffffffffdfffffffffffffffffffffffffff7f", + "data": { + "slot": "8631512", + "index": "57", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x934c856940d84c4f14a733bee6274d9cc2169f204ea0b6ffe56ac508a6415bf35205fd375345e77d8a5f2300efe4ded2132d832b056ea87652113e53a5b9b0f4e9c2d5fe12d71c7c469dc249a58d5d0ff6b3ec1a38f7b2357193dcbf77e08667" + }, + { + "aggregation_bits": "0xfffffffffffffffeffffffffdfffffffffff7ffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffdffff3f", + "data": { + "slot": "8631512", + "index": "33", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xadbd39160d68eade93f8c1c347d5f279f5da8ed5dcd1707f6c4baae397c522351a13a3fdd88dea0669767d87937d771b055be2e0788d1b71bd94e37d453418c5f14fd633ce1cab4948b4f0a7ee8389d44af96023550add95e53166387e8a5651" + }, + { + "aggregation_bits": "0xfff7fffffffffffffffefffffffffffffffffffffffffddffffffffffffffffffffffffffffffffffffffffffffffffffffffbffff7fffffffffff3f", + "data": { + "slot": "8631512", + "index": "36", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xaaa9a9ad6e62fb6d72fff1f8adbfbff847c7daed439f2d61f427eafdf9e635bfd737b8c50b22f5254e7aeeaffe0aca4207e0cc9789ff8673222c94fcb00d565dacd1b4d7174d1d8d46a94afee1823a9e253ba34512416f5b4b9e6ab0ec7a4603" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffefffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffd7fffeefffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "5", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8796bf82191746e96ed7a4815b529d58b89637a73a257f91a37e5efb24f45928d73874e070baeede5dc307192a66adb61622a9e1cee830a42f9dba769b5f2faacb1ee48b45c4b3ef36b250d507b1e1d98da615f2e449f4e31f2399ea967e597d" + }, + { + "aggregation_bits": "0xefffbefffffffffffffffffffffffffffffffffeffffffffffffffff7fffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "56", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa8e03e06c2cb4c547a999470566efb71762b3a1c6799dcaa88a87fbcac801ebc6b8e6c6a3356240751a002050d96c7e805d8ee44b371694bf134b14a73f66c98a3d4635d7de9c87d66d8129d2b2baf6555f3dc89587e9ed8170a67430d967dc7" + }, + { + "aggregation_bits": "0xffffffffdffffffffffffffffffffffffffffffffffffffffe7fbffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffb3f", + "data": { + "slot": "8631512", + "index": "30", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb123ca42495b24ba8dde57f7de4076a3f16862e9bf6e4553d4362a6f7a79734ed4e42e11e61645436751c96ea4232395061a0f14a6b581f07f690256d87c266f73f6b1184ad38beeb32fe07839b2ea7d3d4a0fcc90642896d92ff4004c1b5dce" + }, + { + "aggregation_bits": "0xffffffffffffffffffffffffffeffffffffffffffffffffffffdfffdff7fffffffffffffffffffbfffffffffffffff7fffffffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "61", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8de31ecbc01fd8fb43d4aacfcc2a03b6e936931dae2c5e183d76ec80d2529344167fc2b2c9418ecb55c6aa28bed977660be65b96f3af37a5da57f8555cc6c4eda2048c86f49035ec627d52b4bf8df4661a750528eedfd68e50917d70bdd2d32a" + }, + { + "aggregation_bits": "0xfffffdffeffffffffffffffffff7fffff7fffffffffffffffffffffffffffffffffffffffffffffeffffffefffffffffffbfffffffffffffffffff3f", + "data": { + "slot": "8631512", + "index": "0", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb74ed75a3bfe483a2481cc43e8cb7b3cc8d5f24d8d9e94857a507a1dabe821551012ebde3164a8d6696cf5e27e424626036eb52dcc1c306e656c776994805865c14b9e8b68e387095d76da3ba18522a5616fbe3434874b5bf2aa655996191799" + }, + { + "aggregation_bits": "0xfffffffffffffffffdffffffffffffffffffffffffffbfffffffffffffffffffffffffbfffff7fffffffffefffffffdfffffffbffffffdefffffff7f", + "data": { + "slot": "8631512", + "index": "42", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8f17caa5bef643c0ad87233155725f33f74561eadafcd08be133e3294d5f203258d6b0ba931885dc4a539baa2731971801c7ae96585a57798074ea0fb66a75413fca184466b88f30a12a18d44243c5342e7422b1487162dfaed5d27d8a88a8be" + }, + { + "aggregation_bits": "0xeffff7fdffffffffffffffbfffffffffffffffffeffffffbffffffffffffffdfffffffefffffffffffffffffffffffffffffffffefffffffffffff3f", + "data": { + "slot": "8631512", + "index": "41", + "beacon_block_root": "0x5a585679198d1bae7f337f987496d22c9f0db95fb1bcd4d8069a74be0e76a5ae", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x83d26a533885e91d048c8afb165513641e3290db26884d4bd9f8c250af11174a40272e38fbb676e7bcf9adcf35b6571808623f517ad35935dd3c7d44faf12769bdeb37e692e2176c6af442c170b8a787e154e7aeb219fa3da054377a59785036" + }, + { + "aggregation_bits": "0x000000000000020400040040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000040", + "data": { + "slot": "8631511", + "index": "19", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa8fa520c646b127498e1148bc60cfb946ac50527b5a370533c4b7f1386cbb537872f35e684d4778708aab0c505a7079f06d318b0871899ebd802c3e0fd7ac75cd8a9e1ce68a434aa5056b83606125bc6b0511f87104ad56e487b44b0cc9f2d18" + }, + { + "aggregation_bits": "0x000000000000000010000000000000000000001000000000080000000000000000200000000000000000000000000000000000000000000000010040", + "data": { + "slot": "8631511", + "index": "60", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x941256861b17a7842620bd000ccc6b3927d80a9b8057895133404d78f4a2e3f89f031cfcdcda558990758b394789b8e6013d85b889b1e843710885a8bdb6f2a0f8fa1ae6ef87e8e80b9c33208538f4d93e2317b863f2eb1a54fafea716bb969f" + }, + { + "aggregation_bits": "0x000000000000010000001000000000000000000000000000000000000000000100000000100010000000000000000000000000000000000000000040", + "data": { + "slot": "8631511", + "index": "5", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x929bf36ba7957d5c34c8d7f07d722be4e5802cdb112e4453e450df0210e1744d8aa936a5c003aa0ad08c3f469819915b05c0966b5bf989530205d9452588fff8a17cb6265fc29343d585249d2dc8e8147dec0039b61a5aa2552a72d213bccce1" + }, + { + "aggregation_bits": "0x000000000000001000000004000000000000000020000000000000000000000001000000000000000000000000000000000000010000000000000020", + "data": { + "slot": "8631511", + "index": "22", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa76f0c0d444a02d38967477fb80cdf171597303fe26287f0976e3289e502d9dfdb69f9909f96b4e3585f53563ff1f0a5067c0563c61f0a96497dd263eac1269e2b0b225c06dd26347230933e627e0f5bf5ac885f0952323f54de3e874a7393db" + }, + { + "aggregation_bits": "0x000000000001000000000000001200000000000000000000000000000000000000000002000000000000000020000000000000000000000000000020", + "data": { + "slot": "8631511", + "index": "4", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xac3da2d3a7bbdf5649e13fbae50c7a70dd215754b731e9d644947948384e050926231850273047cb711c3680cff91aef07aad7233a6a5184c940f798204753ba0a09c6774a1fec7fbf200331a7252b1f54315219d3c12c030fe8d814078835dd" + }, + { + "aggregation_bits": "0x000200000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000040000000000020000020", + "data": { + "slot": "8631511", + "index": "35", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xad0193b75611d846c91a8ee3709158c93e716ed635437668b5a6518d5deadd43ea76d669d341de52042d54b5e4f932b107e042f5187db2bf08cbd38cfc10cc6d5759652dbaeb801860bae78f734d6d56600cd514b18be9e7b487b17fae791590" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000010000000000200000020000000000000000000040000000000000000000000000020", + "data": { + "slot": "8631511", + "index": "25", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8a2f2208e25bba65d32e402d293eb4cd533b08750ff4184791b1b4846e08ab8ba0fc405429040418abc14fa880c8af7300978d3146a85a1fbda1467749c6c6aaa62c752183bf66391760b2fddcc84c1646530541aa592bf95f10ff05ea0f63a9" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000800000000000000000000000000000000000000000000030000000000000000000001000000000000040", + "data": { + "slot": "8631511", + "index": "18", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb97f6842a1472ac1f96646de52f131d6aa0a68cf440e0caffb0bb7d073c07a6fe416dc3664601a5dcefd4ae1916778a30799dcad6b283713c4ad79d8a2086ccd3fe5bcb4a3f95ad363bc0ff309f75e2004c8811469bb4c82d1601c05ed23255c" + }, + { + "aggregation_bits": "0x800000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000002000000000000000000000020", + "data": { + "slot": "8631511", + "index": "20", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xab3a064a02d7e06fbf1332fda21aa144afb7f56f51054fd9df07df17433a66b7e68536d6866a8e92c542cd7d4c2e4e410ee8efe1ce8e3e5fe30fadfc4097d0eece0b2e6854403e8410470b3b7fdd632e20ca17b917f8dd8d920d4d04d4438cbf" + }, + { + "aggregation_bits": "0x000008000080000000000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000040", + "data": { + "slot": "8631510", + "index": "26", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb582bdb2e6fc782ac3398a41249b751714ee06c5ccb9c1d4fb8fd1d2eeda4e7e024a0070ca7100e4dd9a167553d1f14414bada9ca70d29844742f3a03e35283b167d3e02f1ba091a30ff95ca48b141061f1580d7ae4ace2b561ea29769a601c4" + }, + { + "aggregation_bits": "0x000000000000000000000000002000000000000000000000000000000000000000000000000000000000100000000000000000000200000000020040", + "data": { + "slot": "8631511", + "index": "13", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x903a63dc8287b453fbe6e7a5346042ab3953ea9aeb4f97e6938963632386a7138e2ea57186e4bc448127524833bd5b0607f2032e835fb603b3c4c8461b62776dfe91ac8d361ae4ac799d30550b238d1cabbc03d17792d7e1ce21bb4773793559" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000002000080400000000000000002000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631511", + "index": "49", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xac50ce515c5097b44b5abf3ba8eadab663acac8342956b4a9c81d43139726d2db3508ba086d91643017453a194b9223f0ed6165375ae8d1e8b838bcc67e1e12c1d7748c2c7add7c10171cc32c8f1008c086ad0d510cf2a52dfa112bda6fb263b" + }, + { + "aggregation_bits": "0x000400000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000004000000000020", + "data": { + "slot": "8631510", + "index": "32", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xaa923c5ab1e1d9bd56fd533d2079936f0de80465cc981588ea5d7bfc17216b165e7399ad57dc36177066fe8c25c1b10401edb3f5afc471586cc00fbaa6bef2c9c5e73f1526aa9a0110f31d05a663931db95dcf1d2be0a8db6708b44679bbdd9a" + }, + { + "aggregation_bits": "0x000000000400000000000000000000000000200000000000000000000000000000000000000000000000002000000000000000000000000000400040", + "data": { + "slot": "8631511", + "index": "10", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa71aab6347798a06e86bbb73ad7048816218deffbd49d3317c5eb4785530cde15aa10b1d0ea76b4484461b10bb19ed2c18f618bb293a8c02b35fec12615eabf84a6a385e152fad263e5dafee8754cd7e4a031d0ddf4a3c8ae923bd69e324ff79" + }, + { + "aggregation_bits": "0x080000000000000000000000000000000000002000000000020000000000000000000000000000000000000000000000000000000000008000000040", + "data": { + "slot": "8631511", + "index": "46", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa993c440d798f29489b9b2149ba58a40b54e00590f403485221b257c2daeefb287f137911284ffc5a0f54b09f961641f0b1fdd7ada9bf01f41f03862c1253d92086134b14d7fa5915d3d5f2ccff25f44283f6624fabba31bec6df2c74787cb9a" + }, + { + "aggregation_bits": "0x000000000000000800000000040000000000000000000000000000000000000001000000000000000000000000000000000002000000000000000020", + "data": { + "slot": "8631511", + "index": "15", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8554ae2377e193ba5fd1d377c2f878d8f482acc20ed4a252effb4f1a493ecfc25f50fd458ccd5967b89110f6b944384410267966b24e05a30f3cc8c5fe03520bc0b85768f58413f8400ffbc6680f0227651d234cc700d5ee3f4e82383bf58cd3" + }, + { + "aggregation_bits": "0x000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000020", + "data": { + "slot": "8631510", + "index": "25", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8fb874900df428621171d56646474315b1f86c13f9ec4a63cd5e993d08089adbc1c7343e0928c5a10cd69510ce4cc1b210c40515c0142099f373840c6941f84fc9dc82f069ec23d9b1f53b33ec0dfc65c2bfaeb0781fcb084824b9f79835f845" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000100000000000080000000000000000000004000000000000000000000000000000000000020", + "data": { + "slot": "8631511", + "index": "56", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8c8b5f32af81b739ff6ed6b3853013641902dbdc7479fb58f64469d1d414cab4ec029fa6e5f24d856f87c4602aa9f2d819b805f63f151e529178d3ccd108d38c71e87ce24a8e5d29023fcfbb8b05319c15c3a09c833875825efaee52e832f328" + }, + { + "aggregation_bits": "0x010000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000040", + "data": { + "slot": "8631511", + "index": "59", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb2545fd500913cb22353af3d7e69c4470a049d4f43ff7b20f9fdbbf75790d6f8acaa5911398414ba52fcb8539ddcc8450e23eca65a1bd336a6eb0fe94a403de50b5e6da9f892fecd00eaf8b61d690c6ca8ad40f9964e4f195d9f7d83a0f800a2" + }, + { + "aggregation_bits": "0x000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000042", + "data": { + "slot": "8631511", + "index": "36", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb7b798c12586933f6454b240658743062db77e6b2a05d99c4abfe5189f07e7dc94558e57d037625e28c18d61d0976eb1125e05fca38e563fdd092f02963077ebf545aec0246006c8024172eb5813f24c7d66f845b75cb5324755f1bcab76791d" + }, + { + "aggregation_bits": "0x000000000000000000000000080000000000000000000000000000000000000000400000002000000000000000000000000000000000000000000020", + "data": { + "slot": "8631510", + "index": "9", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8a15db0376937efdbf6c0583dfe593547f039b8bbdd4985551dc0f4b3cd7f1a045622deb071f61e54d3a0a31b4716b500b9fb9a3bdfe549a11264c2ffeed2cdd63fcd84dcbe33ae28b207b768bbd24ba2c43f843edd45813ebddcbad59bcca99" + }, + { + "aggregation_bits": "0x000001000000000000002000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "18", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x982cc06550a70787a073eea5d83815400ef4e83545bcb05f827df53558d9476eed3413644698748e6b4732fdd3641a50036a09d93a7084e0cba0122923a49bf628467026795a5159732a87450651c3e64fbd1b3076b417f0013e805f1bf288c5" + }, + { + "aggregation_bits": "0x000008000000000000000000000000000000000000000000000000000000000000040000000000000000000000000004000000000000000000000020", + "data": { + "slot": "8631511", + "index": "12", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb554a32185eb69e174694065a11af9ce5d4db924c997fd369ab83674d6d437362308ea9728d3f024df9bc414ba235e6817bf351c60a30d2d7b7d4e532b47840f08e1aef0287391afd840e1ba3522f82d6c70a6cf0fc36d3ea8d080971cba0050" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000010002000000000000000000000000000000000000000000000000000000000000040000000000000000040", + "data": { + "slot": "8631510", + "index": "51", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb643396eb85db6eefc67d810f21ff0dd54bb5e102460029dc2eb90c6561a2831b9217ea8ffb97e8f290a25db820492ef0cb87e8f281a4c4517bf5f973af4078c8d394e9dc37b398055ad1cacad65391cacd26bf01610db40acb695e84e6ef134" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000080000000000002000000000000000000000000000000000000000000000000000000000000000000021", + "data": { + "slot": "8631511", + "index": "27", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8cd635309ce8be6abdb592c6ac2430c702841031d47418acbe4edd62aa0e5bfa13f6014d5520943b131f88887c950dcd18dc1befd85a268220121f8b30677a4a4a31bb36ccc2c4b3c008822076bc4d2c308ffca97758849ef14ce4a0906c5a0c" + }, + { + "aggregation_bits": "0x000000000000008000000000000000000000000000000000000000000000000000000000000000200000008000000000000000000000000000000020", + "data": { + "slot": "8631511", + "index": "58", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb20259156b98e6cf14baf3e168cd21551746da97cf6a28094e08c7caf20e88487ee661468f2476012f593c0e5f373294099f692ad463ada9d3f1d746974bec9cb00b2a4852f8df2044c18f759f13f4e63f1e32ea2520de4950718b9455b83438" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000800000000000000000020000000000000000000000000000041", + "data": { + "slot": "8631511", + "index": "6", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x92cd0e974f0be31e3c7baabf6788678496807cd4592894dfdf63d044c91a74b7a5d85b6126fb02daf6f129ecf2fa69950ae228662b512fe5f3de4a0e8578ba2ce73114d90c0d9c58eef33314b5d3916ee465c055430297103241d4c7490eb033" + }, + { + "aggregation_bits": "0x000000000000000000000000800000000000200000000000000000000000000010000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "47", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb6b000777f0e5022994fd0dc8f4264b0ddbafc128daaa27f2cf8ccdcf45134c24b57bb0c719c427c52c80dfe0f73552f059139af95a1f9ae152073624d5b26c90e66cbc582db51328f37d9fa94de17932e3956a5946000d31e62ce39cd1f3cb5" + }, + { + "aggregation_bits": "0x000000000000000002000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000000040", + "data": { + "slot": "8631512", + "index": "42", + "beacon_block_root": "0xeb0c08d706859c73e7172f788977b3cff4ad0e2936c4dd95582dd27dbbbdd69d", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x97a6cfc872eb64f6fe701fda43c418a4bf24b57a00bf0c06e37dd3825643949c8435c7124d22f61e003544ff7bfbc206080cf9abfb0589fd53fdffd866ad0dd2d67797ac1f70df6ca868ddb411abba17114c6018de2c6e7ddd5ac9f8bcd786e9" + }, + { + "aggregation_bits": "0x000000000000000000000000000000a00000000000000000000000000000000000000000800000000000000000000000000000000000000000000040", + "data": { + "slot": "8631511", + "index": "26", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb7101682aa16481f440b65471da4841f50806df7e0fb42f8377e6673d94127c27fa891045af4c4be5872798328e546ec035ec2d0ff8d6045afc7d3d882957a2c07584790e00cd584b74755fe59fa011606497f41efa8c1cda7b24f9f5b85bc0d" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000008020", + "data": { + "slot": "8631511", + "index": "51", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xab57f287032eaa8faba41f725604de4558e7a8b16535d1c6de0a0938742e1a236812dd92c4922b38bceaa6f2e8a32dcf195413f9532c2c325e052d77e24076237d33ec60246235b2fa9f43edccf1f1f59ec75e1e80cdf1852ea60b9acc1b634d" + }, + { + "aggregation_bits": "0x010000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000040", + "data": { + "slot": "8631511", + "index": "14", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb345079aa0fcf1fec97e0311d14ab06d82922c9687794a1cdad8ff8b862e10984e4f39bac677f1f28f9d93eaf0fc0e4013250514952d1249cf8b0b4e3936eac5cef46bf4a1316990a3e3b42f5594ed06268b90a6da5b7e957b495277ea522494" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000020", + "data": { + "slot": "8631511", + "index": "9", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x90d714486d6af4450b192cb61a3d0f27b5f8d3224482ae5f4cdd094cc93f1656a59445cb7cb49e1d637fee67ebc57d240f4c6ae04af5a81df81c522c367b296110c8235506f51e8e7600ebd3ffea73ec0dcbd6995787344d3ec1b5ab61db9ecb" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000040000000000000000000000000040", + "data": { + "slot": "8631511", + "index": "16", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb1cc73e3063be66b25c580a794c228904af071144d3419ce67f4a553ff174e9980ac4b21d7ecefd9e4eb88a5049e55310083b7bd220b2cd5c3e3ef994113dd9843076377bfc66c862d4e120c138d8d004cbbe929a89e01a42c60d504a4fbb0d4" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000004000000000000000000000000000004000000000000000000000000000000000000000020", + "data": { + "slot": "8631511", + "index": "38", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa327b99a8052aa4bcb8b6b430d69ff5a9a38e70e6d72500cf56b05bc11ba2b5c67084aed2cfdecbef4428302279f3d2e10ebfc89434f98a961f7d1010fac135224b801a19bf86f0e266a24f17b2574bbe92d9f045434fb2f341076014ae74a52" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000400000000000000000000040", + "data": { + "slot": "8631511", + "index": "11", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x93c7c98fb3fe5849dee7e7b2496c8223279265f90ffe6667c9dbf12c945ad05761a194354f51ab4c6ac10f127fe893b202455a178cf05f88e4c25858705534f59c7e4e12710450e6de73cfa64d3a9baff5e142c4b1e6c7511617e1061ad0cd2f" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000800000000000000000000040", + "data": { + "slot": "8631510", + "index": "36", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb3c48536b6f029d4aa9af5b0d3925900712457674aaa3bea97690ea15cfc38b0bd591161ff24b024096bec8860424e650069a6ae1265c97fcff48b622a46c9ef9c7e042e000185f8fe758141eec8a72ced2abaad0e21136c1a0595634878efae" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000100100000000000000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "3", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa9167a98dd2e7a1fd3e806abcb0a0ca6d7a2387d09082ef31148ce2b10f9d268e48962a76e43e417842a48bbe1b58fc6035a22dc5b217475dffd5b12eba3122fbdd5619aa739a236491e2c5f65e8f646606fbb6621819ffa9a531032f5bf74a4" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000001000000000000000000020", + "data": { + "slot": "8631510", + "index": "7", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x893819c979ca70b9bcfb02a022cb0ab9a30500194c993ffe3e28c83f15459d20be0c6fb0888862e18a91db6d1ad49df40fb59769675c7c00e6bd5de13d613d5fec2587a07e4c00986ed2cc5744661c72197fd02c635899f62abdf0601b8f5398" + }, + { + "aggregation_bits": "0x000000000000000000000002000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "62", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa450e8ccebd05fc7cb957b80d2b095cf6bd6a87ea47604ebe44bbe1b9611c6c701a47a39bc63b34246b72384c8ee3b5a1088bba7e62df199d0817c34795cb335b05fc195381362fe1578ecf482159c06f6c36bf074b174e56788474d299ed73f" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000200000000000000000000000000000000000000000100000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "34", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8f3e898455473c2a0ffe6f1e06eee8719cb27f104c03b480315959ca2ecf5003790c34c67c9564c48e0eb100109cec60127d3048e360634cf6baa7b6fe5dc52dc191266491170bec046f6528d03d26976fbba33ca5e5919489ac91c4887b17df" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000800000000000000000000000000000000000000000000000000000800000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "28", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8c6a20eb7479a966dad4a0355aad6cc6222ab3c4a3ed0633e83ac41987f28c330cf140a91c47166f4da91213f5d2f8dc18ad0766424066e86ca6e9ac1fe72fb0351ab5a5be2faa31295b4ccc080511d81acd15bc49c13ec922b566fe93b8c95e" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffff7fefffffffffffffff7ffffffeffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffdff7f", + "data": { + "slot": "8631511", + "index": "41", + "beacon_block_root": "0xeb0c08d706859c73e7172f788977b3cff4ad0e2936c4dd95582dd27dbbbdd69d", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa0249d3c4552e9339862d138967e41f7c78bf5ad19981ee1ed573c2c2ced58899539086efb5a014b2fe1bc8a4b40a4d8157cc9e78330e418e3016f5467fe5c7ee9e0b13f10375720eee24936b4bf777008cfd1f08070db501e3aefb6c93673f6" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000000000080001000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "39", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8ae1e3db8e3017986bea4d9fad3ec206d3ad28826588becc8623cf7108e11e66b3c27351d1cedae1bbfd9ada038de094116476826204dcde067968a673669dbd55ed9c029e03ef035746798322433b6a23dafa29a69eaf38d16387e7803a6798" + }, + { + "aggregation_bits": "0x000000000000080000000000000000000000000001010000000000000800000000002000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631511", + "index": "42", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb8bb8402eef655b5e5dd2b19757d3fbcdddd6872b40e18c9af1d3b8fda7d7123a79f0ecb116fd1f51c2a5dcfd463df1502803dd4d5f3a4e77defe4b7c0b979380282b6b9ac91bff0dc77a575aebff4a213ab88f02044756a11e22f4a3e8432eb" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000080000000000020", + "data": { + "slot": "8631512", + "index": "36", + "beacon_block_root": "0xeb0c08d706859c73e7172f788977b3cff4ad0e2936c4dd95582dd27dbbbdd69d", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xaa4b0c2e07e6b988eca22d355675cdceb52273b8adaa90c8a830541713eefe358bde676571bb8048c39e4c1dc61230e413daba8d34dbdc0c98eadd812ecfefd6f484c96db50ad82632aa13699f6510cc2493cac8143d0905aa1c0e5eaea47018" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000140", + "data": { + "slot": "8631510", + "index": "13", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa448bb31a03d8d4991c4d0bff68fedfcfaa56b2b715bd0df636ce97311139d22b7220520f8206060a6f2f14bfcfd94710ef60cc8ce79bf3407a92ac9562bb8f87b29cae92b192e4acdef407cf7af5b0a6b2c143d184a74b9457ea1547f73207b" + }, + { + "aggregation_bits": "0x000000002000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000004000000040", + "data": { + "slot": "8631511", + "index": "28", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8d5db320e083f09d225104d450de1af9faca98f133271f863f11cd85a6c34314298e45c95b66ad9e4812bbd10983cc4c035ce9542f91eae44669cbccb19033c874c4be3c50646bec9fce48013813ee764d8f0d0e11be9d7f77de6dc571f96164" + }, + { + "aggregation_bits": "0x000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000040", + "data": { + "slot": "8631510", + "index": "8", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x9918318a0d0e53213039d99b67bb3d4c8c8c6e760d2a318daf531cb503e77bb97ebb77bb52bb2eeda73cd83b17dc8a740fc8a8d8733131908af8bedb4721eff9782144291c40088a5a34dcf3f00b6ce8fc889912f7fd01cef80b407641795b6f" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffbffffffffffffffffffffffeff6fffffffffffffffffffff7f", + "data": { + "slot": "8631511", + "index": "32", + "beacon_block_root": "0xeb0c08d706859c73e7172f788977b3cff4ad0e2936c4dd95582dd27dbbbdd69d", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xaae3ec3d7f3f2b3fe4091a3c355f5e335ebf3a8d8cc1e3d159ce8922c49c1680bdbe416a2a6a845749ae109252a531eb071865d709e6b79467e15e501ed01ed7c2da20101443e3af6b3a38f91e7188187f6b505534b6eb8d6c0b434fdd5c5a0d" + }, + { + "aggregation_bits": "0x000000000000000000001000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000020", + "data": { + "slot": "8631511", + "index": "17", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8dac2f31202247c4794d9d97c081b5f0f187f4a6bcb6cae372d05f9143468951dcd9488ca31fbd4727f60e2dc9bc4b1d18a8d1f79ef19c64a0d035ef127dea40486ec2549e08218af66709be9a61ba41e8f07a5e20db93f18bfc0825e93eef7e" + }, + { + "aggregation_bits": "0x000200000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "33", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8600af9f38e1f010ef20400ce2255c5fd7716fe99541cd2fb83a0cc8865ff9b3baac450ad032d09580eb3b72e721faca16066a0d97fc152749cb60628ecd37118d2f61d1d5526374ab06edc61cd4b6b62d927c87254b26d29f22cb553ba63ee0" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000800000000020", + "data": { + "slot": "8631511", + "index": "33", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8254b51bf9a36d557afefd737fba80b97bf9d3e230518be396beaca728a32fabaf3a61041b670b254c3d2f31d110a73e197c6ba2ee93ea4f1492f8dc6944f92dfe1a18172b1ef78cf0ee221039b13886af835134225c850641bf9b8a036464a4" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000400000000000000000000000040", + "data": { + "slot": "8631511", + "index": "62", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb926adcc0d2d36128b2c9957171cac55ac3c9ee397c4e8f4651b8941210c381e938e0a7de217722c8669063e9c87ac40114813a5ba587fbe6b9ae74b13ac920d5bc1dc283196e1c6f8516ff4c5f60e10d5401a4ceedd4ae3a0831ec97db1795f" + }, + { + "aggregation_bits": "0x000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "21", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x914facfd0403c914108f1fa001ccc2b9bf3a54aa6e189f9d23c22254b785363a2ae1bbb158444ccc22a17c781b373f6e199dd12f27032653edf2b1a7ecba0b0fbebb7e261bb44d33fb40bf95acb3d41b47997b69f948797b548cf9b851b65409" + }, + { + "aggregation_bits": "0xfffffffffffffffffffffffffffffffffffdfbff7fbffffffffffffffffdffffffffefffffffffffffffffffffffffffffffffffffffffffffffff7f", + "data": { + "slot": "8631511", + "index": "49", + "beacon_block_root": "0xeb0c08d706859c73e7172f788977b3cff4ad0e2936c4dd95582dd27dbbbdd69d", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x856a03f298ba41988bc8aa2839c6bf1d387b24a086e73857939dcaf7902b37f022de604d00c11695b4de360932a86407016e6e91609abd7964f80f4169cb25b253b33ba0d47f555fa69228f3f11efc859098c470f18d046dd5701d01f0115c7e" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000020", + "data": { + "slot": "8631512", + "index": "38", + "beacon_block_root": "0xeb0c08d706859c73e7172f788977b3cff4ad0e2936c4dd95582dd27dbbbdd69d", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xab26e1fff20f4898e615bc5791e95a5753ecd292a05af731136dbb2835dc5a6e9a863d1e8df66a5202be497a32d429550b74271a06aa5b7432191b14ea8fd13aed719c9ff839ed9383d0bf86eaa4c83e933888443f591135e50d33ba35a7c0c3" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631512", + "index": "34", + "beacon_block_root": "0xeb0c08d706859c73e7172f788977b3cff4ad0e2936c4dd95582dd27dbbbdd69d", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x834b554ba91baa6ea4cf3d4e852a2885d6f04abb002a139e5dab1dbff60f48272af14027b76e3a4a391d406a56ec1ce701977951a43d5a09fac3d22aec58fb50d7274c2fdde568dece8b87a67418b41c68a24c89927942ad16762de0ef4b450d" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "10", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xa4d7dd332d16fefa5988346d73848e61bb40ace8da64f9a05163cf558644ef57974700e9fdffa56edfb8ecd8a37673e908b10eeb32b065391453e395bede891c5a939be445fff7627ef6bdf9bc3a90300dda43a6c2fa69ffa81d98b516062dfd" + }, + { + "aggregation_bits": "0x000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631510", + "index": "11", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x83c37557550d1178642e165c617c56d372ee8193197887e823bc466e3508d269d20ea16c144c94b1e95665e472622bb906fac5c0bb0b2ea70b144b683f46ff0b8de44f8c0f513c0ca7b962336fdc23f26d9c70af2d08c393a76257aec0bf9211" + }, + { + "aggregation_bits": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000040", + "data": { + "slot": "8631511", + "index": "52", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xb6b02a9c1c729948089dfb5f7d9fe974fae6cd229abca0b5ff9a52e587500941551f6f700fc2ae3510b7dc905a22cd2218f8825fc08b7b35f3484ac19341c4b222533a0f872a4a26b65d36b532408980fdf6fe056ac130c241be3c9e7d57c8c9" + }, + { + "aggregation_bits": "0x000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020", + "data": { + "slot": "8631510", + "index": "50", + "beacon_block_root": "0x5509ec83ef9b0cedaf406785234c03bdacbb0d7398e361cacceff28e9dcba9c9", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0xaf15aa9471b6951bff42fc87186422f5be3a9220b001d0a060ea2ef0ce79215d89e455edc8b26b7c180b9dede41a418e11fcdd5b7f46b7180f2dd447217151e666e221ee061df533059cf69e7fe3752fca19aea5b18899f008e711b39129c4de" + }, + { + "aggregation_bits": "0x000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631511", + "index": "62", + "beacon_block_root": "0x450216d36649e2c08db47a5bea94a17fd299d52b57981172e25792be1616eaad", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x92316b53d5ad6d7d8575e06777caf46af60b2f743fa29df4b60e9f6faa91f97dd82bade290ac6c767b69f05142d1e94a0fd205350b52afcc518546fb954629c937aba5ec16c59932b0140668a9a5058be802986fbd6168fc9606b71d7e995a2e" + }, + { + "aggregation_bits": "0x000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040", + "data": { + "slot": "8631511", + "index": "41", + "beacon_block_root": "0xe3e518a58e2685b72179c7fb86f63dca7a5717006a7ae0ffc9945495f4664573", + "source": { + "epoch": "269733", + "root": "0x508880ef7fe7cac1a601bcb00868cc41a523497b34d85fb71dc338f891eb049b" + }, + "target": { + "epoch": "269734", + "root": "0x89926ca6add36803c7239a78f78af0fb91df932f8af2ac34d4cf89998ea3ec68" + } + }, + "signature": "0x8eaf69445a5b52667d0af90420b2bcbf38920da1f5fe37be19a76975dfd59a932f5da17760751a699949f3b1157db8b50ff59a2ee8b76dd469e5a10ae2a05eeccfd44a940071abe53def172ae6df613a797010987887743e6ac97a6878d069ca" + } + ], + "deposits": [], + "voluntary_exits": [], + "sync_aggregate": { + "sync_committee_bits": "0xfffffffffffffffeffffffffffffffffffbffffffffffffffffffdfffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sync_committee_signature": "0xae953c135ac95f1cd669a8caf9e89770483bdf3dbf138b2dfdd76198e9baac00ab4d807b518ebfa9e665a8a78dab9c210ff7a073b85fef1e75ccd49f0747c73fe850f9e87c63985f9bf5d795c28474c4ea67716e194a320382c6d9e560aebc9e" + }, + "execution_payload": { + "parent_hash": "0x5cb0f2822e542e2c6fbc0099aa8f996509c178bfaa634e04b728add8da42c65d", + "fee_recipient": "0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5", + "state_root": "0xca4e0ab986d29ee5bddd8b4b9d9481e90d7bbd1ce7ee9e0d077c89ba03cdcf32", + "receipts_root": "0x09fdee17a2dafb2328798f9e47b44e50a5a8e5d9951929afa51f70fc222846c2", + "logs_bloom": "0xbffdca4be5945bfbba8a8ed5eadb7ff2dcefce7f6cb67b94cf81ad38dc9a943b76e541efe10b2768ded9de385ffdd9596b79a4ecffbafd407ffca3453cff2d9ebf7f57ffe3069abb7eebf66eddc460ecd9ef7ded9c67de1b1ccb7ce9e9f9cf7e3fdcdc2fbe974ae2be4cd35271d47b5bda4459fde93d3f0bead5c558997b18386ef38ff77e234f6eb7cda7d47bee4ab6b273b8f9ffb37d5be6ffb7dac9ffbd36ffc6eb33ffaa7f832f264dc5f9966fed1fc7c0fdf6fb719e7fb39b6e38dddfe3defbde6a7668fb7f2166e79fb8df91adbd73545fbf3ae59caeedf7df6937fc5039fafaff21fd720fd9f5d6a3e85798e0d7abde86f3a6afff6383fb0beefcdc0f", + "prev_randao": "0xb48f684132ba484557c07ea6964d6b3841607a44a540a24dd31cbbccb14f06a5", + "block_number": "19431837", + "gas_limit": "30000000", + "gas_used": "28138718", + "timestamp": "1710402179", + "extra_data": "0x6265617665726275696c642e6f7267", + "base_fee_per_gas": "44330915133", + "block_hash": "0x4cf7d9108fc01b50023ab7cab9b372a96068fddcadec551630393b65acb1f34c", + "transactions": [ + "0x02f904b40183222e6b80850a5254153d8303adab946b75d8af000000e20b7a7ddf000ba900b4009a808509bafeda9db83a7f381ce270557c1f68cfb577b856766310bf8b47fd9ce8d11a5b113a7a922aea89288d8c91777beecc68df4a17151df102bbfc4140e8c3d5e806f90407f8bc94e485e2f1bab389c08721b291f6b59780fec83fd7f8a5a0ddf68a16e33fcf794c93d34148c2e2c4391f4f3f27ff7a52703ddbcdb5c569f0a0b39e9ba92c3c47c76d4f70e3bc9c3270ab78d2592718d377c8f5433a34d3470aa09edbdabec2e16ca41f1efb3c19f5f3d18c604847272628636ea866af352b901ca09bb3e24e1534bce24e9896f3377327d742d6c1d430477b7ebc070c2eb64e3147a0000000000000000000000000000000000000000000000000000000000000000bf859941ce270557c1f68cfb577b856766310bf8b47fd9cf842a0b39e9ba92c3c47c76d4f70e3bc9c3270ab78d2592718d377c8f5433a34d3470aa094fe3377ad59f5716da176e7699b06460ce5b4208f8313f3d26113b1cf3d3170f8dd947054b0f980a7eb5b3a6b3446f3c947d80162775cf8c6a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000aa0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006f85994c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f842a0051234925bf172ac8e2ccbd292c65330169d67445a0966551f13a5df19bb9321a012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8f8bc94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f8a5a0d2764b6d304d6875dc1632274f53a7d27047ae66fe20f57cce9fb878c86ccdeaa010d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390ba07050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3a00000000000000000000000000000000000000000000000000000000000000001a0154bb98efc83b034ad81fbf23cc88c9737739df170c146ea18e8113dac893665d69443506849d7c04f9138d1a2050bbf3a0c054402ddc0f8dd947a922aea89288d8c91777beecc68df4a17151df1f8c6a00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000aa0000000000000000000000000000000000000000000000000000000000000000c80a0bc7a0020d84346ad4ffdce908fbf7291f7f7f251a6381bd43583f02606a05471a04acbaeb9886f864bc654123665b91e527623fd2a9225e1371e061ecf5fa4dbf8", + "0x02f9017501829a308502540be400850f8839d18083061a80947a250d5630b4cf539739df2c5dacb4c659f2488d80b9010438ed17390000000000000000000000000000000000000003221ceed0394f7b8ef2b12118000000000000000000000000000000000000000000000000213a0fe9640f2a2d00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000001d283807630ffb876a5d78b8e0788e491449f2410000000000000000000000000000000000000000000000000000018e3bee84e100000000000000000000000000000000000000000000000000000000000000020000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2c001a036e76fbcbc86dd2d6fe3d37e65ca3e83aec7259a850b28686fece7105c1d2a24a06c4b4d44d359c9360b8ebf2554eacae621824441f00d99275be3bfd01f554239", + "0x02f906b4018201e28402321261850fae8bdf9a8307159c943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b906443593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acc300000000000000000000000000000000000000000000000000000000000000040a00000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000004600000000000000000000000000000000000000000000000000000000000000160000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000661a375e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad0000000000000000000000000000000000000000000000000000000065f2b16600000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000004106882e8110f296c60d47cdf7cdc88434fe9b82d97c4dd92b797f7e8d8a54321968be5ba5e9f6ba051f28d593966a89493c697b93af24a2532df7d3083a60d3ae1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000858b793d000000000000000000000000000000000000000000000184dba000c3fc6b755100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000042dac17f958d2ee523a2206206994597c13d831ec70001f4a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48002710e485e2f1bab389c08721b291f6b59780fec83fd700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000007a922aea89288d8c91777beecc68df4a17151df100000000000000000000000000000000000000000000000000000004b1e74327000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002bdac17f958d2ee523a2206206994597c13d831ec7000064a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dd04cee96c94d5a7ad100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000e485e2f1bab389c08721b291f6b59780fec83fd7c080a0d70b4c189764065925757d8bd2e3969810dd6e3b440b8080f1b6feb7c5562baba042a71e23d5021929ae4371a3b2a7c55373d58cbc5b4b4a228463ec1e1802f6c3", + "0x02f904440183222e6c80850a5254153d83033bf2946b75d8af000000e20b7a7ddf000ba900b4009a808532577c909db84e09177054b0f980a7eb5b3a6b3446f3c947d80162775c04b3cd89213a7a922aea89288d8c91777beecc68df4a17151df1e485e2f1bab389c08721b291f6b59780fec83fd702bbfc4020f036d3f606f90383f85994c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f842a012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8a0051234925bf172ac8e2ccbd292c65330169d67445a0966551f13a5df19bb9321f89b947054b0f980a7eb5b3a6b3446f3c947d80162775cf884a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007f859941ce270557c1f68cfb577b856766310bf8b47fd9cf842a094fe3377ad59f5716da176e7699b06460ce5b4208f8313f3d26113b1cf3d3170a0b39e9ba92c3c47c76d4f70e3bc9c3270ab78d2592718d377c8f5433a34d3470af8bc94e485e2f1bab389c08721b291f6b59780fec83fd7f8a5a0b39e9ba92c3c47c76d4f70e3bc9c3270ab78d2592718d377c8f5433a34d3470aa0ddf68a16e33fcf794c93d34148c2e2c4391f4f3f27ff7a52703ddbcdb5c569f0a09bb3e24e1534bce24e9896f3377327d742d6c1d430477b7ebc070c2eb64e3147a09edbdabec2e16ca41f1efb3c19f5f3d18c604847272628636ea866af352b901ca0000000000000000000000000000000000000000000000000000000000000000bf89b947a922aea89288d8c91777beecc68df4a17151df1f884a00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a0000000000000000000000000000000000000000000000000000000000000000cf8bc94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f8a5a0154bb98efc83b034ad81fbf23cc88c9737739df170c146ea18e8113dac893665a010d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390ba07050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3a00000000000000000000000000000000000000000000000000000000000000001a0d2764b6d304d6875dc1632274f53a7d27047ae66fe20f57cce9fb878c86ccdead69443506849d7c04f9138d1a2050bbf3a0c054402ddc001a0d54fb22d1cbfa827b9fdd559512572d4524b1085d8f933823d76cd5c678415d8a0509fa03693e2371027c87ba95f77c2f916d6ba1ccb0bf94b9d715e053ae922b8", + "0x02f9015b01824c5d8501dcd650008513b4c10d008307a120947a250d5630b4cf539739df2c5dacb4c659f2488d8837f0fd2491998000b8e47ff36ab500000000000000000000000000000000000000051cd15f4c8240f4719d8880000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000479cd4c24c567cd18520f0d087acfa5f89fe6c890000000000000000000000000000000000000000000000000000000065f2aaf10000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9cc0809f82bf8141d135009cc6b3327b566a18577812eadc58774dc0e20b8891c604c4a069fd890b9318af6a641380d6da52ef1632c8bc275ab891129718b66a4f76a66c", + "0x02f901e50183222e6d85db5c95740f85db5c95740f8301a3b5946b75d8af000000e20b7a7ddf000ba900b4009a80852960773c9d9b7f371ce270557c1f68cfb577b856766310bf8b47fd9c03cafc6d06f90153f859941ce270557c1f68cfb577b856766310bf8b47fd9cf842a0b39e9ba92c3c47c76d4f70e3bc9c3270ab78d2592718d377c8f5433a34d3470aa094fe3377ad59f5716da176e7699b06460ce5b4208f8313f3d26113b1cf3d3170f89b947054b0f980a7eb5b3a6b3446f3c947d80162775cf884a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007f85994c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f842a012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8a0051234925bf172ac8e2ccbd292c65330169d67445a0966551f13a5df19bb932101a0e432951488a733bc6f10ac87caeff25ebfa3693ee0362134588b580d99d358d3a0036bbca9bf15f825e87ed5d98bcc4d56039f1e72a6647b87a44be152bf7445a8", + "0x02f9015c01823437850f30220c2b851ac688be008305c7ea947a250d5630b4cf539739df2c5dacb4c659f2488d8829a2241af62c0000b8e4b6f9de9500000000000000000000000000000000000000030fd894eb7a45600000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000067bb6879b16ef6bc9035e92dd6c24facacb931b60000000000000000000000000000000000000000000000000000000065f2b1840000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9cc080a0a5110daab9292819ba68d08f3e8d1ff79b371f70c4c9bc83fe4d49bf9a917834a0665ac7171f7393d00c68657189fe84d8a09db79502524a5e5f92091acd997523", + "0x02f904930101850110e5e5f6850d422605738305357b943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b9042424856bc30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030a000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000001600000000000000000000000008881562783028f5c1bcb985d2283d5e170d88888000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000661b88f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad0000000000000000000000000000000000000000000000000000000065f2b17f00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000041ec33c6271e090e54429664d1291e04b4de51f1d1599563f11efc1ee3cef82a237ffe73ae66690769bccf49e0a4ce604881b75d31e53c8606b07177c88832940e1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000006fd727d954471cc8000000000000000000000000000000000000000000000000000371c7a0a17166eb00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000428881562783028f5c1bcb985d2283d5e170d88888000bb8a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000004402ba72aea4abd839a0d1db7d7273b1bc9493cd0000000000000000000000000000000000000000000000000371c7a0a17166ebc080a07ac12b4ea5fef6892b2c4f45d16d4fc4062d4f5ef59c17ca4e656776a91f779aa0767f63688afe873454cbcc9edfca54469a2c62c97b42c61653ada04adb84e9a7", + "0x02f9015401822b6b850aabbc443d850aabbc443d8307a12094360e051a25ca6decd2f0e91ea4c179a96c0e565e80b8e4ccf22927000000000000000000000000b62132e35a6c13ee1ee0f84dc5d40bad8d815206000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000001a590a1dcc7d1aa3388000000000000000000000000000000000000000000000000293cfb12b6a0d0860000000000000000000000004c54ff7f1c424ff5487a32aad0b48b19cbaf087f0000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000000000000000001c080a0a13a208f888da29bb1a436d468bffd0d96c6c8db1c1ef9d862906a112568354fa03a6bf177eaab40161405f299639309d96606ea537f2caa9094dafd28d4ce1dd4", + "0x02f9013b018204d68439d10680850cc9aa78c083031e1d94f3de3c0d654fda23dad170f0f320a921725091278802c68af0bb140000b8c49871efa4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000c0466456cecb64500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001b0000000000000003b6d0340f4041d29ad20219188cb6f4a3ea0fd1b8192a856c080a05a961ebd36a8bc3c8811d9f7c26085d96d91967b069844a9e6240c443aa776c7a0720e8ee65b702c4101f1f0359d0c74a4f64653a23c6bb559f0019742fec01829", + "0x02f9037a01658405f5e100850bdfd63e008307568e9468b3465833fb72a70ecdf485e0e4c7bd8665fc45881d24b2dfac520000b903045ae401dc0000000000000000000000000000000000000000000000000000000065f2aa9000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000124b858183f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000637a7db1da1c54b628fa5d597632b8d3d9c266660000000000000000000000000000000000000000000000001d24b2dfac520000000000000000000000000000000000000000000000000361401f699b7406e8e40000000000000000000000000000000000000000000000000000000000000042c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f4a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb88881562783028f5c1bcb985d2283d5e170d88888000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064df2ab5bb000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000637a7db1da1c54b628fa5d597632b8d3d9c2666600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412210e8a00000000000000000000000000000000000000000000000000000000c001a0a4e5008b47b5e17669d14856dc4e6c622c8acdc12decf8f34dd2c76daafda05ca079ce55de2d7276772335d97833960b6ce6cbd973753367e1d9a1305f316b9599", + "0xf8ab8203a08522c334157f83030d4094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb00000000000000000000000095362c2df7b2afaff345a6adbb19ed68e9b1e5fa0000000000000000000000000000000000000000000000000000000000f8b7e0269fadb6373e31560e5957c588df5755e0ace18e74e558871d6549123ebb68fbaca020ef57772468b4a9b2629a69308b65823f16883a0539ad5b824ca913ea3cb86a", + "0xf8ad8303a84885151165cc3e83015f9094d26114cd6ee289accf82350c8d8487fedb8a0c0780b844a9059cbb000000000000000000000000710513b93c5290fe7d1cecc31d3e15a9628ee77500000000000000000000000000000000000000000000050a33598e3218e0000026a08c153454d4ab15fc9d650d5893b1b49fba29bc079f2ef8bca6526b4239fbb848a017e3640a6d6f2d2bea62f1fe1af39d1262e7e77a8c0d09ef1d74a23afb67ceb0", + "0xf86e8312edbd8510babc5f0082d6d894aca60a27d73947a6b70d9573dd854ef009bf094b8785e382247de0008026a0015d8946bcf580c4755617989d7ab1c65c2990b00d38cb3c4931ed3ea53268f0a06bf359f294159f30d8aa887426a852b12814bf8a8099e6271ad597d37ce94106", + "0x02f9015b01820188850f574a5a40850f574a5a4083034cc794f3de3c0d654fda23dad170f0f320a92172509127875029ef9204b429b8e49871efa40000000000000000000187cf0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004fec5eb942a44300000000000000000000000000000000000000000000005172739a75a59691fb00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001b0000000000000003b6d0340f0f93a837cce0054b7c0128fd5ae507f54aca0e73ca20afc2aaa00000000001e96c195f6643a3d797cb90cb6ba0ae2776d51b5f3c001a0d2167b629edb7e6a9d5386996814ebf56a7dad6beb0c90747ead2ba86e36ed29a0548b78d63706aa78207e50965eff54c999b7598f91531d2ca6f338892061403a", + "0x02f8b1010b850f0ecdfb42850f0ecdfb4282a30f94e41d2489571d322189246dafa5ebde1f4699f49880b844a9059cbb00000000000000000000000048c04ed5691981c42154c6167398f95e8f38a7ff00000000000000000000000000000000000000000000006b10a18400647c0000c080a0520b5000347377c4d1a5f29f76101a8b105551c0396a20f61518f9701841eb0fa040fb134c25d38c449f8d6c3c650fba9cd817e3b8c2bbb6fb50238b8c612d0ff8", + "0x02f8730101850e5fa55382850e5fa5538282520894ff7a1084b50dbf07fc970ec42f2fb4cf1de8d635870d63202bff8ece80c080a0d7583160a9eaffa2f48665f8f50161b29985364ef68b86bd9c2b853664e716dea066446e0957f5a7ca5f8fe756202318c923b303e1db4abf6c53d30050a9fb412d", + "0xf86c81a0850def3fd16b82520894c8700fa8338e990b4dc920568c9d43df748306bd870d23cf3baff7ea8026a0816e5b8e474a2f2286b1cf2b838e63915d0c6026e4d620ee90a453e907e3c528a0322756d81a9524bb20bf38bbd51238bb2d317db9eddf42cbf0fa3f06e92b272f", + "0xf8a980850da7cffa7f82d87a94f411903cbc70a74d22900a5de66a2dda6650725580b844a9059cbb000000000000000000000000af91f2d992f37450695bfdd15f26362c40d710880000000000000000000000000000000000000000000045640b8bfa7b44f9380026a00e124e09655f0e197aacdf3ed5979a8308449577c86192caa9dca6dd8e7d5c5fa01d7d9e637fa831426e9da71596108c98f8d1ec2f6d73ed493f212b90e61a65bf", + "0xf86f835d07d3850d4576fa0082c3509413d142b7cc2c5b02ba8053a7eb5a68d16f44b52f88016345785d8a00008025a0832f200ae1811363271ffa92ed822a1755cb0d741c49008197fcec4f5e367828a03d2e8ca2dd1818ff4edb43b7c9c492a6d3c64e2a747e5aa3e358b1966c94d003", + "0x02f8740180850d0920753f850d0920753f82520894c88f7666330b4b511358b7742dc2a3234710e7b18809b0389825dd240880c080a007b71ffcfa989a5b57707b32949ffda068f0598a425ef42770dcedb8f6b59412a010bf8db768ee58088f74e824806066af8631f48fad75a7c5dc0a4be46cc72aba", + "0x02f903b301808502f4fa9f00850cce4166008302e96594c059a531b4234d05e9ef4ac51028f7e6156e2cce80b90344e1c8455d00000000000000000000000000000000000000000000008a22af5c529b9f0000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000008a22b7e5f992b9062a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000125b25c828c914d3d336fe1db9bed49886729be2d88b0f21e8967f3e23ae8548315c8c08b6354ba860f6d1b680d4f6eed04e394bfde3ab96bf6d1c6203be68c17b99871806e775e36a9d27ed783034164f7cb2c2a7227f4218de0b86b33020daceaab8a9a40c5b986471067add1cd9b392ba37d0e195147c529b66d3e07f1f748acaa383752b3f2742cb99b986462899cd082947dbfe7c9430540b374ec23fcc435c212e72e8fc80fe0ddf1261af59ef66849c3497f4997af2932cb06feef87194ac6f37ca3b577a3cbe764030048784f2dc9bbd21ecd0121a7f6413b2fb77d47c51a3f065731a3122899c4f967475bae44e87792598aa0d1ce0cae2af3f8de75502593b78f42bd3f22887a4fda93d01e75bcdbee061cd4ae41fd92d17efc43ac2c6b091b1c5af4ec138bacecf17fe968408a5f6dd91eb09b6b649f5d579f2be42753be136a7c76aa63dfd5594a78eed1ff1bfc19681837c9d003a2ea9217941436754398af6fafcdec394c601386614891260b3ba9b0fc62571380a77d3e1c374a1777966baf36dc8cc5f4d0c7fe31876428aa616efe94616aeaf74627b3f00bfc003099ab80200205567d103920229171d9211ec23859d159fff215550e91f0267eb720753f9423aa17accea01ce7ac4767da5678c91eeb94e7ab9ef342146c266220d0d69d2ea75f1abaa361fa2325dcb8d95131a12081acc0dbca9d16b8856ecef3f38904031cbedf8f8d77f7533385b9176d0ebe964055755bea7fdd7a73b3bdd1e5318b1af41fa68346461d94bc4793ebd12fd81ce5d0b74b62d096838eac080a0a3899e36bfa7ae0aef62ce893a261a263b14d52e90cfa06692e329c4e0aaa9dba01dba59634e4cbc0c3eb9e7740ae5b4aec63c1210c6dd0896a2fafebaffee9b3c", + "0xf86e8308b61b850cc5fa7ff8825208943851451f023494a7852d95356c19bef700f11de9877a4e6c9a8d068f8026a04d69f82c3764f637bd77ea5ac1f8a1552193acff987f408d683dfd2b75b20183a065c65e4ba60c875164017511411ccf836ff53ce31b70849188564884cd6b267d", + "0xf8ad8303333e850cc06ca3d5830186a094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb0000000000000000000000004d1ce86f72f03fdd683bc802c7f5c5fe948a027c0000000000000000000000000000000000000000000000000000000004a62f8025a0f24eaa90a2c97e748c719a71648293e24e01b74b11724b3d91006a57a18530f5a054c1a660581f6db579c889031eb9ecb06d530384110f6747907497e44e91b6cc", + "0x02f8740180850c96e98dff850c96e98dff825208943f6b569d627896c41711c1925d8070527c34e38988161f9c2a4b66220880c001a0b1e740a79b0567aad3bca673a6ced9ae7f2eb939f82063da4c529c2b003b725ea0111a29b43768cd3cfba84e9171eb23e630e08cbc254456410e61e50cc0392162", + "0xf8aa80850c92a69c008301117094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000a6fecf2344f5bc04ac6a67fcd1938d6eb5195c55000000000000000000000000000000000000000000000000000000006fe318f825a06b64fa4d2896c6aefafc7f0f944cd11440c13028455dfbdbcbe45e6090bedc94a00567579905de4c573dc9d5c3bf08368240dd8671f603f8c9a080c5b8688e6dc5", + "0x02f901f50182214f8502031b2cab8516e070d5ff8306387794767af52d988d1241a346851a1b39ccd11357376e80b901846ac56d4e951ceec2ea1b3b1b2ac1b07b819ea391c6fb5b75a470425499dd77dd956d78ad000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001208e349991b942ad58964ada2a7de1036823b30cbfbd3122ea8984fc38fdc544b589c2891c6485ab014452bd8a12c396d802409f49295f22ea8984fc2be2d00c827d3a161dac8be4ff2d79ba957fd847b367b2347b295f22ea8984fc38fdc545f38ede111dac8be4ff2d79ba947d3dd5f11db8d89204bccf04969c1c2d81c0c3e6eadf3ac76df47172039c99375fba412a2225f546aa41e5ea88703c1257fcf7d070531b13f0c4c315f47186e0131a3d966ae404cfe60cb5d356a8a19449031c01c65313356ca14ec69f5a441875d61bfc4058ed73152a4e2895668c6d81da2d3c3ba9a94bdae8f440a63e47097fd847b367b2347b295f22ea8984fc38fdc545f393648c27f6be0eb81c917b672b69270134d2579ec9b5d115dd220dd501f04d3cc080a05c211382dd4b2791049e1c2eb4bcd70a7ebac8653591aa7f470e425f0b59eed1a03154927a96ca6bce1c92ed5b99b128cdb5a740c2dab8731035ca30271a8183b3", + "0x02f9015d01830154918501dcd65000850eab17b600830aae60947a250d5630b4cf539739df2c5dacb4c659f2488d88106033bf82f60000b8e47ff36ab5000000000000000000000000000000000000000182cdc4f62c8ca30c7b140000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000021375e8ff94a9acad555e0d8a4f17c69c5e33bd50000000000000000000000000000000000000000000000000000000065f2adfc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9cc001a04f64cce6e85bc3440041b3bd9f659d8e512414b78fac0c4a234f7068474d5979a0797bfc1c30fbecd372a2a4d11d8cc08c449f822428edb48e280d24bb28320138", + "0xf8ab82e083850c2ab8a11f82fcab94dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000ac26b31b4ead466dff55b967903b3caf9577df9b0000000000000000000000000000000000000000000000000000000014dc938026a080210bd7705207df754ed6e6d5c4ffd81c8a7198887e0ac13f15c2a6f7416266a04ce56a6684754c995f3662b2c12a16a122737c6faf76ba5a34d233b87cf93972", + "0x02f8b50183010e00850bba6f5042850bba6f5042831e848094bd100d061e120b2c67a24453cf6368e63f1be05680b844a9059cbb000000000000000000000000f5aae5276b1ed63544edb779dcd7e449a7d8017b000000000000000000000000000000000000000000002b39036ce57ccf130000c001a0d13bd010a8370eaba6c2b85cebc78758f216f8b80a7d5b2028d477f251b478c6a0442e6fa4310adb03d9958a3c7fac3fd9acad9f832f648e0cbe87e63eb885f054", + "0x02f8b1010a85015fe197c8850dd0a712a282fc8d9425b4f5d4c314bcd5d7962734936c957b947cb7cf80b844a9059cbb000000000000000000000000e7250ad3e16c6e951dbae9e7d178bc0ebaf9bce800000000000000000000000000000000000000000000003635c9adc5dea00000c080a083342b5b702f801b07c8c37ba9b358c8879fcdd995c40e350fa83e771b7a3f95a0671509edf7e32e1d9162d4b11f403838cb4d60d37ef2bb6451724333dc2f548a", + "0x02f8b1010a85015fe197c8850dd0a712a282dbed941ce270557c1f68cfb577b856766310bf8b47fd9c80b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a01741a609fbab5fc00b91ca5a7f0e90f5fa2da99c83b4f86339b97a066fec720fa01a76ad61adcd119512439e26ba65e859dc5e93b70d93a7ea085d49252f5442a2", + "0x02f8b1010585015fe197c8850dd0a712a282dbed941ce270557c1f68cfb577b856766310bf8b47fd9c80b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a077d3134cefefbdb13c6379aaa352eeb67f927b87494b84a4957b7f9b313568e3a05ef84f4583d7a6cce1aac7a54d33b8ef58dbcd17b7fe69d27e1e49a16f82325d", + "0x02f90473010b85015fe197c8850dd0a712a283035de9943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b9040424856bc30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030a080c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001600000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9c000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000661b88da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad0000000000000000000000000000000000000000000000000000000065f2b16200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000041eb0bebb9b24b4109bb4b5774799e230aaed199d6417881aada2590f90ebc03b87282a6db4529e45f57040f94c0e6020b800212d1cc98b80a9a9f71d9ca168c511c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000cb6ca86f57525e1052017fa5000000000000000000000000000000000000000000000000091384da0a48737300000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000c916f41c82aaa584ce0912e4c1e731c8259ca306000000000000000000000000000000000000000000000000091384da0a487373c001a09f22832ca93e3b46f6f4f6c8d8df7c351e6a17b892255a4fc0ef43c4ddad12d8a01c4ced5357eaaee98b52c1da26a7f828e10200ebd9de94b9dd109ab66092e7a0", + "0x02f90473010685015fe197c8850dd0a712a283035dd9943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b9040424856bc30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030a080c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001600000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9c000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000661b7ac800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad0000000000000000000000000000000000000000000000000000000065f2b16000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000410125606f39d2916aaad8ce811674725e537a40131f8fbbc28b5380330c6368740fbed970b6c46a9f3622b9b1cf3086344be41be48001ee67c29132913fd1ea581b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000001d50debba86cf9c4a071f5c20000000000000000000000000000000000000000000000000140dfa843c70af500000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000ed564d4a96cf7aaf9770006147a597eae55f3c580000000000000000000000000000000000000000000000000140dfa843c70af5c001a0bf2a2178f25e1b82536c4e7b186d8be7414c844138fdea6a5ba1b9b0ebfec056a066f45ee787c89524e5c4225dd3facbf0910e5ea2e35ec16565f0b6dcafb6fab1", + "0x02f873010185015fe197c8850dd0a712a282627094e57d40f34f40b67c7b7b1dee0765018479849b8c871a4a42c356800080c001a08420ceef61483108d9d205f481faa4dcf638c7f2c385efc80de9afc999e8b202a03f4e3a47e527e127ad1b6fc00733475e2a987e58e07230e589c394eee8cb90b6", + "0x02f902da018085015fe197c8850dd0a712a283035fdf943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad873a248477002800b9026424856bc30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000003a24847700280000000000000000000000000000000000000000000000000000000000000001000000000000000000000000009fe3e7148415e10a8812be17e405650d31f91a3a000000000000000000000000000000000000000000000000003a248477002800000000000000000000000000000000000000000000000002d86a4d20ee7faf9600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001258d60b224c0c5cd888d37bbf31aa5fcfb7e870c001a0c57cf927cdc7c543566f58b447be7e0d61a1fd5b23b1ff5873f387031b4c70a7a042faf8d347a265ffbd36ad35ee962020ddb48e629bb99c96e0f8cc063f8ac4a7", + "0xf903ab02850b9cb52e848301f0d594c059a531b4234d05e9ef4ac51028f7e6156e2cce80b90344e1c8455d00000000000000000000000000000000000000000000008b80d253a5feba0000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000008b80d8228c84f7b00c0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001225a94f1f723fc33d5167fc43903dc9353f4f19f428ac36b0a3fd477343cdfc4e9f8c406f1b977f765bc096344fd3d2980085057c671cabc763803db36b9d96804615f13139c222f054d34d67e42dd1fa049cfdff64f827de1cbc6d549e3eef89832a18674b2a0b983e8873f7f8ac67897b71776f2d2bc1ee8057e16b1fc9d280971ce2259366ae4df90c802d9d4e0f00ae7f7a0d34f6ad0348358fed204020ff1b920c3877bb5f57fe795d129914d48730b67edad54c0345f80989c36736680fb646c4d68523b00bfa5ad9b04fc5fe6a0af064af8355ab8af186ab4e944d00d6ef1c35da7929ed3924661dfd31e155dc17cb5fc940e62a91ab01481d7f7f6e527945bd2200c654b4a5d706b5f051425abd5f1a2cd28904d9505adfc4ed3edb0bb6b38a1585c891b98a146fe173dc9a113927d40b4a99dac98fe5d61b456fb938e9214ebcec741a12ebc24cadf7a2eec6aa832dcb37f8a2ea980f3776e0e04e061d8871a61d7eed512be66b0c5cb544e1def1aa1db20ee6f680e5a2d4f5c3a5663abe1c71045451b3f33a32d42af448881022424dcc910536e38de38666fd8612c99568fe3f7a990d0f00b2714b7105fecfa26db4a56489b71f088208342c09247751e549c0b5d29e5f473b4ce26846c3973dc05e90bae1daa1156eb69fb68c9d08a7d0a6af883df133f4dda40a2bf9d18ea6e9b3b90b30974c74803005be777e854f5656ba40bc7ae01e2b8cb95cffecd7cc1fa7a3a3e69fa5faf5d26f1771383bdd1e5318b1af41fa68346461d94bc4793ebd12fd81ce5d0b74b62d096838ea26a085e6009449a5343549691699bb5d772ec8efbdec71bd506b08377cd6fa6aa692a02c95599cff9cb2d8752868f37d43141233c8d2a521e2669fdf4471747d80b164", + "0xf8ad83a549fc850b965e63898305573094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000eb132715c8560fd3832baceb36699e4c275480ea000000000000000000000000000000000000000000000000000000001cd9410025a08ac4221d205e2615a3955ba50661f0eac5a099d2dbaf13898367f86511365966a06c39ae260706750e747e74aef8f42b36c7360ccdca60b4a1b27a35528e05655b", + "0x02f8730108850b964f2148850b964f2148825208946cc8dcbca746a6e4fdefb98e1d0df903b107fd21874c9adcb727bda680c001a00c2ee154ee471824c18edea9309f2f9480d905924ab956387cfb0a6252cb6d7ba058f4b65bd333222be823b34186061bf634622f53b9ff5146befa50445aef1fee", + "0x02f8b1010a8501330d149e850ee2688b4e82dbf694be9f61555f50dd6167f2772e9cf7519790d9662480b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a065730e98a96c93448e582150b3cdefd1d2472f54d08f997adf31e171828764faa01369bac5247c404c93795ae163f8611c4277b7215bc7c698f20b38a1e44bb80c", + "0x02f90493010b8501330d149e850ee2688b4e83061945943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b9042424856bc30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030a000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000be9f61555f50dd6167f2772e9cf7519790d96624000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000661b88ef00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad0000000000000000000000000000000000000000000000000000000065f2b17700000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000004134866262fbf32e9c6a99477564fcdb5b81308e3c6ca7fa2afc6d22f76278c5db60a39206de9436fc96f5072e07cf09bad8a9e6f852b0219ab419e2dec1bf03061c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000bca24a51b82889d831c0000000000000000000000000000000000000000000000002018643b999fdd1800000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000042be9f61555f50dd6167f2772e9cf7519790d96624000bb8a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000006997d59f49ec919caa7c8b1c5bf1eaa03842dfd20000000000000000000000000000000000000000000000002018643b999fdd18c001a0e8f24ff09f347e6c0b15f6bd0a98e881fa543e351ba0c652827f5824ee555b67a04da8b7a7432c9c3ec967c81e1817e30d04e896c636b0a9634a4929e81cd6ae8d", + "0x02f9035a01058501330d149e850ee2688b4e8303a1df943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad87976c11aabce199b902e424856bc30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000976c11aabce19900000000000000000000000000000000000000000000000000000000000001000000000000000000000000004732dbebdf7e45faf5cbb0b5923de36392e551b500000000000000000000000000000000000000000000000000005af3107a400000000000000000000000000000000000000000000000000000976c11aabce19900000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000c3f8143212871014b472ea83285af7f25928dee400000000000000000000000000000000000000000000000000000000000000400000000000000000000000004732dbebdf7e45faf5cbb0b5923de36392e551b50000000000000000000000000000000000000000000000000000000000000000c001a0f251bcc144ee6c6728961ff9b607a34f0685f98e03ec75da8e419a7513c5173ba01b63fb36405c5fb3b3c1da8fcdd5d2e35fd34a6260c8d341347d890530fe4874", + "0xf86e832905b2850b7fb7760282520894c027ed26517deb1c5ab035575f2572f8d8162be487072293978f32e08025a06fcfa4b5b68cc408c008cb6d3c4bf25ce9de5ec57f4964403c7b145d7372e225a07db25c643e7ef418fb104f979d6a174c5165ec2002c8f707757f436e59224071", + "0x02f8b501830d046885012a05f200850d69a4441d83030d40949e976f211daea0d652912ab99b0dc21a7fd728e480b844a9059cbb000000000000000000000000082547bbf74f4eb48138e83fb1d8845e7c239a70000000000000000000000000000000000000000000001eaf49fa6a83627d8400c080a00eb64f6b37eebbe016ff20ceda921d786dbffd8d3d33c1f403ae74916b7e557ca01df31dc95ac330361ecf3fef85dc4d3cd273fc0343248516ca2d652ad8c2fc33", + "0xf86b01850b68a0aa00825208944e5b2e1dc63f6b91cb6cd759936495434c7e972f872aec0a10f272008026a0af770d803d6ff43bbf46c58195cb438a87bb497d4bba6656584655d67ffaeb54a06ca124c1bdb4b4a283f437629e73e9d0486dd81a589fddbecc33642a0d84dc88", + "0xf86d8208cd850b68a0aa0082520894890026952ed29515d96098db1250492669692f67871340c2cf1b2c008025a09a4cc2310ee789f86ec041761741a601063c43077451f2506ade19faad0fdb1ba048e9ce05a675712c238db18f738796b7e9e3799dc5c3f9767173f7e6ae6e80e0", + "0x02f902d40181a6850110e5e5f6850d4226057383036231943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b9026424856bc3000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002080c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000009580cf5d9870000000000000000000000000000000000000000000000000061d4e22009bf0600000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000006a6aa13393b7d1100c00a57c76c39e8b6c835041000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000400000000000000000000000005a03ce41153697783d7ea8e0fb322f8bc61f82170000000000000000000000000000000000000000000000000061d4e22009bf06c080a0a7d3d023f9a2080ad2810049d7a2720c70789d61c934b545ed3e7166c9b2a25da05e748f58b1bce7b0c9ff172a98b187aeff4143d427ee90a495193635cff28475", + "0x02f87601830ecd7b84fa47a7c0850fbbdd93428252089405922b84abd2b3451f17913cd38ef2352177583d8803a38582c41b800080c080a0b66f717de0184280be5ff97dbee3305fdb12b2a079787a0a1e9601f727e4bda1a03d6dabcb515ec812463f311e002b81aa27a6151bef3f4900ed9a260ba922e743", + "0x02f8b40183032be684fa47a7c0850fbbdd93428301482094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000dc2f340ee359ac809b991160204ab92f6da62e18000000000000000000000000000000000000000000000000000000001df8e1d0c001a0090ed221942618d7d9d7cb8bda17028dcd1f45b6f1f7a0a1b1d158a504af867ea047519808a8384bcc0af521a1c84de12dddb70d5f732e0eba459a98488b728148", + "0x02f87501830a29b784e41b62c0850f529d556a8252089426544ae074f3f4a51f344c38825ddd32424c94bf877a369e2446000080c080a0a5956b53be8203030d87a786e099a62c26de8a11d4b5657d88b3dc45699c5cb0a01f32f207b9b2852cb5bb42dc5904c5ebe6b818ad9f4cbe5beb7f1a24e647e4f3", + "0xf86e830aa3ec850b2d05e00082520894e9e954671db1ad060398951b2be1841d293dd44987306e3b559400008026a0225af81b392d9f053749b318e51bb3d7b60da0be7bc67e4b00d9423bdd6f047fa015a94668988c165e91ab67cb9af4b574a4a67f24d70e7cf7674fa12dc1a3e371", + "0x02f90292011e84be740e988512289ef29e83036b76943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b902243593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acb700000000000000000000000000000000000000000000000000000000000000010800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000006acb2ccb83332e66c2d9670c000000000000000000000000000000000000000000000000000000005002231c00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c001a060ff4ed8117f97aefc70b422b635d594e607b4780abb274428426b41faffd915a06dfffd7e0a9554270e5b38671c985ccf0590d4c7e44edb53f40d3b682b9ecacb", + "0x02f90492012184be740e988512289ef29e830417f8943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b904243593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acb700000000000000000000000000000000000000000000000000000000000000030a080c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001600000000000000000000000009760aa5124b8255fff140a76994f91ca22d2647d000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000661a376400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad0000000000000000000000000000000000000000000000000000000065f2b16c00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000041612fef4fb4ba56322a8d1e4cfc1635ee5f34deb6ab07db91f80015ecf50c717376450e9ff133713cd2d0f456ff507129b465d98185e4a129374646eb5fb9ccd21c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000a80715fbb4f80000000000000000000000000000000000000000000000000097fcac4a90ad9500000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000009760aa5124b8255fff140a76994f91ca22d2647d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000097fcac4a90ad95c080a0893245f2cbba47ca744104efcfbbe50f15706340b93e2ebacfee83024f26a7b6a054ca7ae631f571bdd654f16f06e6a02a83bd20b9a4c1f6108ba5135a698aaa7a", + "0x02f872010a84be740e9885108a9b860682520894b201d5c0e79fb09ba79a5d11950ab78f57bf3b70872386f26fc1000080c080a0d9b225d61474a24cb41f5c782eaa926c4926f7007d81e892ba579c390a139583a053035b248ea719fc3ae8a76d424e83fb9979a927eec03d4227f450f891ce2eda", + "0x02f8b1014284be740e9885108a9b86068301b9b194d9812f24f34e0d727bbf6ea7caaee05b7f7a260380b844a9059cbb000000000000000000000000a2d12ad88c21830f438620467241213e8e8616fc0000000000000000000000000000000000000000000005d723aaf284072c45d5c080a08428cf84fd778c498ee2362997f9e3671572e5ae3a7b4253f641e451e35666dfa0512bf68e37da709821827252354eb35a8b4e6dc75736f363c3fcdf043bd4c4c2", + "0x02f8b1010f84be740e9885108a9b86068301158194cae6ebacef456e5a942afb40fc99f2f38639ef0180b844095ea7b3000000000000000000000000b9b213d92253a405977ffe38fe8e2bd9c14457a10000000000000000000000000000000000000000000058f03ee118a13e800000c080a03aa2432066cbf8f82753a0f81019fe406f9a34a1e9c98648260e3de2386fd79ba0061ca71e72ae5ee0094364d735de68fd9fded576f027c0d77de7d52ab8955041", + "0x02f872010984be740e9885108a9b860682520894a40d8cbb65b546a1c1740fe35feddc1eec6983b2876a94d74f43000080c001a04bfc01b60f0d5ca4b4b8d9c9206e36271fec9f3854869182a6ea82374f194223a0595dc7d9eca0b94d88a5936f2ad7c065eed10bb85fa886ca15e33e1567cd7380", + "0x02f8b1012b84be740e9885108a9b86068301324694ddb3422497e61e13543bea06989c0789117555c580b844a9059cbb00000000000000000000000042a289b725980361669356e0fd6fd52ab386e1f200000000000000000000000000000000000000000000004b56763adf67a40000c080a07d853e7042e5454ed9920381453b775dc0331993baafba96bbafd50b002e2f29a020a24aa1988abce355a84e698a066f7378649607b57829808894ff7ab76daab4", + "0x02f902f9010584be740e9885121f2937978303b8e6943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad870aa87bee538000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2accf00000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000aa87bee53800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000aa87bee5380000000000000000000000000000000000000000000000000000d3e77830498ac2900000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000cd24ba0e3364233ee9301c1d608a14753c8739c5c001a02a28422be21a9442f6e1283f86a52248e3b1a3b7599dcecb839c19a95e310597a038a4b35f2fe9cd57117e0edda565c3057507473c3f3e79fb9332e4aa9f69248c", + "0x02f875018302928d84b2d05e018513a7cc86ec826aa494816342193a94ae0bf0a4807976f78d5ab03d12ef872fce292419000080c080a05ec69593c99e139227d5015b70e0b5bbf68f955137b75edde3753efc703c6359a048e542994553c9a7535fa1dcaafd4b857dd9ef6c86b2049d4e64f14973fd91a9", + "0x02f8b401830adc9a84b2d05e00850d4576fa0083014c0894bbbbca6a901c926f240b89eacb641d8aec7aeafd80b844a9059cbb0000000000000000000000006767526a362ec6c6b1df185478e4f01506b73ff30000000000000000000000000000000000000000000006cccb85a7550fc00000c001a01ad1b4dfd6dc28ce7ac910abbacdeec4dcbf32d15208b85758d1d48d7498c072a037377aaec06ef2d5a626d6874eb040e2a3cd07c341dd65f53b3f30779fe7a4dd", + "0x02f9023a018084b2d05e0085104c533c0083021ed59444acfa1395e583b9fdc88137b7a03a8e173788b388034d8bbd308b0000b901c4b77a147b0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c45a4e4df40fe2bf63d9de141376f050f15916b17e3c729d28a0ab49ed8627800d27062894fa8fb51238dc11061d677f413e6b772ef39e06b1c22e0021eb8f880486f0f3fbce03139aec098665754ebfbe38380883968524693d94ac35f958ed9eda1fcd7a2e4b8db4c41fb63992acf6a950070d33546b08330ade10e7fd68a5cb0cb062db4acd87fdde77d5b891f58c57dd462de6991b7a6f340bc1f73c1ddb53ec90c20c54f6f0be2115cf8fc290dae6089852c57d6454706604c8544918ed392fcc8e2d922cd23f5f4bb61e6f661c4b93bb9404fea2179db3bb46ca1088d3687ca7ee737db680b4c814f5de84a0430f54e4bac146d94709abf0da7cf1878a29dae9a8fdcc2e3cdef8edcca1a1bb3d4c6bce50adb9005396a73a4e3e76e047676d7155dfa18871344ba028334f76f25081a871a310975ef8d4d333a21cc947390d4db92d61c9563f6649309b5ff90ecb576cc35e86f5320327060f36d22181d08cc612709bad88760231f5e7fb70d334443865091f8085cf14e0e97f120d247c001a0524fb2543274c82f343e5f55e944e2df33814f3823ece8d6ddd44c875ae3eeb9a0066b35ad284d1994e76ae4e8128768137d7c23d41fc06b1527d0a4e92b0e4cb1", + "0xf86c80850af16b1600825208947f58200b81d2885807da57589b1f255be825ff0e8806f05b59d3b200008026a029c4e6ebed80d23439a5641591335fb27b39a42ec4e737a2b8d6887fa4875a70a06810b74b2629f4ed9ac3d802fb48ce57623c93874de9a2f6cc723a7f074e9a2a", + "0xf86e830fae65850af16b16008255f094a62225f6008c092299637020fd97c25999f319d687183665bb1ea4008025a09ed1ce836f07fa12b2ecbce2ced394406d679940fa1a91456383d6f3b4757aada044d77a96e5e679d64d8d3f2f5e4deab4234f1a225157e7c28534855f9757a08e", + "0x02f8b00180849402f900850e81818c0582cac39495ad61b0a150d79219dcf64e1e6cc01f0b64c4ce80b844a9059cbb00000000000000000000000040e129cb3a203ae007a6411191fc0d57c350b3c000000000000000000000000000000000000000000006a1c870d47e5e274df800c001a0b1c0b14b8db85e946216205bc50a9a1fbe2d2187f5d0f2cb3104288c829bf8f0a0140a2b165388bf9908aacf6a793e19430ba918f22467b5d5852ac73ddb8a7c38", + "0x02f8b301830321aa847744d640850f20621b8882a4d89495ad61b0a150d79219dcf64e1e6cc01f0b64c4ce80b844a9059cbb00000000000000000000000077095982aac409f3fb448aad9e209c7c07815e7e000000000000000000000000000000000000000000526ddddf71b28034a31000c001a052383a32119afa16a15e8cfd2aaa180561e44d7ccbd0b58c016ed46b45a39a09a06bd599340379746b89c39e29a6a4cb3c94a49fc3039c5c0ec926be545b6985c8", + "0x02f87501830211b1847744d640850f20621b8882520894650993dc97634ccf05d362bead78b4add5d506c587246139ca80000080c080a004b465d6891f9fb80bbafa255b204a4e7572072f2b92031e3660b965dfb9125ca0665a80460becb67e705a29e07c71230813649210e63cd11f58b1321ae02c3051", + "0x02f8b1010d8477359400850ddf42a8cc83012e1a94467719ad09025fcc6cf6f8311755809d45a5e5f380b844a9059cbb0000000000000000000000000fb28aca9355a6aa973f6b2774c811c5d0320c850000000000000000000000000000000000000000000000000000000038ec24c0c080a0416d591a0f4f0264b62afabef8a7137dd5f81744300e5e2ae57cbb5249619257a068ac9dca55e16482aa4f959195819f4215138adaf216b2cc63c63b54ecce46c2", + "0x02f8b001808477359400850df847580082c35094b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb0000000000000000000000006cc5f688a315f3dc28a7781717a9a798a59fda7b00000000000000000000000000000000000000000000000cbd47b6eaa8cc0000c080a04890ebf991b2338963de4b50d01f768becdf51a5a98c6e1abe4a62c682fc7400a058396cf140403ec2fb171dcb82052bc00db3309b7bb2435ce205d9864d469654", + "0x02f8b001028477359400850df847580082c35094b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb0000000000000000000000006cc5f688a315f3dc28a7781717a9a798a59fda7b000000000000000000000000000000000000000000000007ea28327577080000c080a0106082d34ac82abed0039a1a6425b59eb1fec8da396517b47b8e2ac2e6fbf8b2a030f9381d899c51c1f7b82b653dfc1f82b8cf7fe1b08ea15a54f7f79871e6cb0f", + "0x02f87201808477359400850c0d03af5582520894808d0aee8db7e7c74faf4b264333afe8c9ccdba4873636e8f996a35880c001a029bf001cb0b6aa3a71024a3d60a92e3bbfb2feedd4f44c1c33d47c76080234d3a053395cb47773ebf4a876053f4a9397f697e8707457f08029b9a4875fe5129bb6", + "0x02f8750183029f2a84773594008517a2d1caaa82d6d8941bab31b520c8c312ff722477b7a1cc890473c883870a1d0c0facfdb880c080a07b8ac6701ca8162448221202bf26e8d16a20b84447c1cbfb144ceebdf2fe3db1a02ddcb2ea4c943aab10c370a423020f3b551d3a11fe18597e825ec0a2fbf4f93a", + "0x02f8b4018388941c84773594008517bfac7c0083035d1494dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000a5c0ae1c0d7838ebd6b0b9c9a50be5511e0aa11e000000000000000000000000000000000000000000000000000000001dcd9188c080a0b55571f4132d1baa4904720f50f2af59133fc98d7d81e7b58eedc43c2eedf316a076c80841a293cb799727689ef35c6350b42d5b2abadeb34c8671310ba45a324e", + "0x02f876018381e9ec84773594008517bfac7c008303291894c1e4f895e81c6fb82e4a9b043f4e0da61a29f7b4871b3bee858c300080c001a08fd3f48b41dc515b033bf466bf42b4fd835366adf5dcea4c67807b737a92db38a078f866574e2b97ac1453c2c1f6820d596a4ae215d121fc092d8200d85e80d9dd", + "0x02f8b4018381e9ed84773594008517bfac7c0083032918949be89d2a4cd102d8fecc6bf9da793be995c2254180b844a9059cbb000000000000000000000000cc4013a3afe4630eb4671d924b0084c01a3e5a64000000000000000000000000000000000000000000000000000000000000a8afc001a0c19152c83d612d923e27a7940a944fe0069915bae2d1a1fac44b9873bdd06cc3a0409cc2b5b59c3362a797f8a2737a5d01b0e58b5edeb705f9cefda28fe5db0a5b", + "0x02f874018204cb8477359400850df8475800827b0c94ab83a311ebcc5be7466edbcd5b798f18121f5196872bf55d2dab36bb80c001a0debfe435ce07e8a7f572adb752d41f385658a28b2459448b4ee53a91869652aaa06abab0000360f08ec7668a0e164edfcd9e89612e4aa7efd303f44eb141eae265", + "0x02f8b001808477359400850c2521caa982dc2494e28b3b32b6c345a34ff64674606124dd5aceca3080b844095ea7b3000000000000000000000000f955c57f9ea9dc8781965feae0b6a2ace2bad6f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a0e4224fd2900fd472113cc8db34a88bfefeb78c754b17f93fa3ec22e51e9a6d2da0522311d1bcdef7c15d66b358c00c2d9eb9976dbbd8cfea040c727e856984d05d", + "0x02f876018328af298477359400853a3529440083015f909488022e41f7c108e7fc786b6f15bc705d10d34dca873d7642229d400080c001a082c73d2c2492a2cf4613535516b3ed769cc3f08d4449b302506acc68234adcada0245cb18060599f93d0575a430a980dc44c3e662605fbf7fef843768fee04f86b", + "0x02f8b20181988477359400850e5fa553828301117094a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4880b844a9059cbb0000000000000000000000009bf81cc31d0f1fa7ade83058509a4db154a182a2000000000000000000000000000000000000000000000000000000000dc4c7c0c001a050d9b55158f4a76ad549c5ac6e5ffa8767426e81298bb9a10ea35cc51ac4ebe8a0579dcefb0e6bfc3a067dce6000131aa3b1fe09bf290a09bcb3eb92b06b8234dd", + "0x02f8b001028477359400850e65be4a6b829ed194f411903cbc70a74d22900a5de66a2dda6650725580b844095ea7b3000000000000000000000000a7ca2c8673bcfa5a26d8ceec2887f2cc2b0db22affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a05022e8b159eb3ebf3b8aa40863855a0fff534d9045de0327c7d50d5dfc4e3ca0a039c05e5cd887106d135ffc64b37cda928743950acf837ab298af7d3ece712119", + "0x02f8b001688477359400850df847580082ea609464bc2ca1be492be7185faa2c8835d9b824c8a19480b844a9059cbb0000000000000000000000006cc5f688a315f3dc28a7781717a9a798a59fda7b000000000000000000000000000000000000000000000266acc439ba50730000c080a0d8c067895655081946eac52305e0b11e2d310b38e1de9765da5bc9917b704d2ba007256e53ac4e6c32d25277011a7f110b6b91a3fc9ff81227c90d88d0f15a8f2b", + "0x02f872018084773594008517bfac7c008252089477696bb39917c91a0c3908d577d5e322095425ca871bb4d4b62cd6b080c001a05938f654a7077b081ed152d911e9505f659d23fb3b82569067413883bb653a70a032dda885f92738ba8c75661ccbc056bb4e7fb466d98c4960b48aadb34761b9d0", + "0x02f872018084773594008517bfac7c008252089477696bb39917c91a0c3908d577d5e322095425ca8738e708d3ee119080c080a03b8bc43d25584671f81e962959a228cabea7d4916b2b5da327f31d068290e910a0403dea2d3dc8b582cc4bcbcabbb18c3af3a951979dbd7b243ba521b44c4dbd7a", + "0x02f872018084773594008517bfac7c008252089477696bb39917c91a0c3908d577d5e322095425ca874dce0dcd5f92d080c001a02d50f46b5700a8f99273831ba1652ff79ac78e4b55fab216795fcbfdb79d499aa010be44e79c4444c73bb29d9c5e2c1e57bac925f6990ee177a3d51ad316cfc356", + "0x02f873010984773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e43880564febb0d6e6cf280c001a062f0679cdd027ae0293e2b460c80f3675b7c0d0ffa02b395a63eeeaa4367f78ba07252d94b81f0d35f314b3d1f6ef1915d8ce9a01e0090245b50aedb68d2d68621", + "0x02f873013b84773594008517bfac7c008252089477696bb39917c91a0c3908d577d5e322095425ca8802a5c9f4b52a525880c001a038a46b8582f9f92f65c7985150e5160ae27d9c04f8eb2e6bd084fc56b0897a33a0739cbdc2a82a452cf911a86bce6f363775d233f240e7dfb2144c42ff2e2f6f9e", + "0x02f874018084773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e43890207d4a0b06100358d80c080a0ac2bf9bcf27997ebbe1ee31bb91de46e9a97ae599b0b66e35bebee95caf9a9e2a049d3cbd468e87b6aa6e02486c29087e29e3df17428ff696c9453bf4023550754", + "0x02f872010384773594008517bfac7c008252089477696bb39917c91a0c3908d577d5e322095425ca87ac81d977bfb82b80c080a0775e385b916c681963114c5aa627e7e20eb087519f89600b643fe57bcc97ad47a062fb00c672cb2f6365866be21aaacb3a44d8d0b167e43e398b93e14cf96d11c6", + "0x02f873018084773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e438801077067cd1bdc0080c001a08ac07c8cf253fe07cfdf5651ed1156ed40c617e57dc8d4152afd7ecac3a9aae5a006ee7881bfd943ebc6f2c078c75bb1b9324e7992e8a1777ce9d17420b34ccd51", + "0x02f873018084773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e438802c409f4ad946c0080c080a0c87db5ed2e5f45ba65a98e3b8e4d37e0dedc97a5d0580ee2afb1ab8893c44e78a028d0da83975b13050467cdd7461fe926b53cd1dba09d9bf30b6db413b4704af6", + "0x02f873018084773594008517bfac7c008252089477696bb39917c91a0c3908d577d5e322095425ca8802aa4c08e8072f0180c001a0ef55f969d0c720f9fe95a6c1c7c551bbf066a006a256bcc6ee758c1ce27694c3a0685100f72084c8923f98ee90a9da40c0d768db33c88b9c6a8e1332be83e4769d", + "0x02f872010184773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e4387de86aa0b18a36080c001a0a217f7527ca9b1bdeed84be67aba1dec65a24b84d02a66de9d36f0e190d35d80a065225df53f59b593a71f6b10e37160aeea7193e4527fd0c36588b43d93853554", + "0x02f873011f84773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e43885b1d3e80723e434880c080a09774f1ad0a37a05948146ca07e6a6b069383c3707695b4975ee1fedbccc1ee7ca02a6e21ebbb427e870dcc9ceaa7978381ecec9efe5ee5a8a482e43b4550e5393e", + "0x02f873010684773594008517bfac7c008252089477696bb39917c91a0c3908d577d5e322095425ca880a7578444257064c80c001a02b0b4425133adc0c98f986bd8881e237f4cb91e177868862a39483ec443e37eca0039cf8dcc580114a394875fc26a7870e4fc30397f29c654387e2be0283b0ae88", + "0x02f875018301bcb684773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e43880523effeeb452f3180c001a0409fede92e8ed5f980492516402d600372db0b35cea0663ad7a8de262ba880719fa9de714f459f81513d413a83952d4cc093f93aefc04bc052177fe4fb0d2b62", + "0x02f872014a84773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e438782ab24ab6b5c8a80c001a05e31b9ac844d84f68bcd6aa2f5248d42846c06618df161ec49ca52472636628fa00c12d0e716b76f27f8c3d62e7ae87caeb683b7aaf8eb2b30d4f996e442f6fa97", + "0x02f872018084773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e4387198b6b551f687780c080a0a40bd0778d94c6c64c3b0b01682a73ee495f888a9750c01cb17d360eba6d240ca0701cb6c2be9e56ca8374393579b875040d093b6caf6d96f629df09f6229adaa0", + "0x02f872017684773594008517bfac7c00825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e43872709ce03efd1e580c001a04bfeb49efd34d0f8260ae341e5c8ff0ae23182b92c2235bde25f5772dbe1cf88a01848d5b95f3ccd5e5332e16c8843ea922a39855bc7b80885f4fa3c0fee3754de", + "0x02f8760183106eec8477359400855d21dba0008303345094215b4ab21d2296222c76cdb16588d585b169af6d874325732a41400080c080a0bfbfc3e114c3ca68887d8d77b1ae791c275852cba4b0120af30146120e680c12a02ecbbcbec039dfa0f9ab710daac89b8760b2b9fc451d0003d09d7fdb7487b867", + "0x02f8b001028477359400850df847580082c35094b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb0000000000000000000000006cc5f688a315f3dc28a7781717a9a798a59fda7b000000000000000000000000000000000000000000000004c53ecdc18a600000c080a0695e0c278594b3610d8e6b8606c0b8fca37a9a5df0473365bfb258163fb1abb9a0544fef1342e53370273231a1378b33774e81405fc78c69d23532cad8ceae3971", + "0x02f8b001018477359400850df847580082c35094b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb0000000000000000000000006cc5f688a315f3dc28a7781717a9a798a59fda7b00000000000000000000000000000000000000000000001fd242edf0d24c0000c080a0560e3dcfc62acecc0ab1316577003453775de1f38b17b672fa2e866903c65c34a06e9de5009852cd0108e4d50aa2983474be773a1e54ce2ca764dc9f4659b76dca", + "0x02f8b001808477359400850df847580082c35094b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb0000000000000000000000006cc5f688a315f3dc28a7781717a9a798a59fda7b00000000000000000000000000000000000000000000000fe2311b9e95740000c001a0d762e1840c43133ec0873c9463bf1d9edcbe2ed0701779ffb3467e50e8d5662da0090085f359fbcc7d2724cf1c676c3be582bd3205a22585c0a41d38ab70b3c9e1", + "0x02f8740182035e8477359400850e5fa5538282520894ee31993ab5310f1f85f01e3fe12f4dc8ed017542880de0b6b3a764000080c0809fc4ff9124a70b6c21181f55121f34253caea75beb53b51700d7e6b040999331a0647007cb4c06237905a35d2bd8d08251b01e908de31e688a0c9e13d22c868fed", + "0x02f874018202f28477359400850e5fa5538282520894cc6166d957115d4b2a93192c5060d763de913bd78756d2f298653dd980c001a002ab297ddb7ace9ec230f208522331dbc4f9d97b1ac90dd117de5043e3b41e07a02e744a9539e239f49cfa463fec1bf43b9aa4a86e914bc501e216aef43749925a", + "0x02f87701838ceae084773594008517bfac7c008303291894398132ae4b3f8a9409a5d9af816079c3b8ddee53880bdec7ed01e6000080c001a04bd782765419be32b76491b3a1aab2197d19f6a6a51649402295600713a19dd8a03fdcf5d50fae76476f7190d1b01ec1f33b75970b74d9ea8dae20e509f7a8f9fb", + "0x02f87701835c488484773594008517bfac7c0083032918943a4245a215a7af26438e42d97d21119b769842b388d0ea8d3d90bb000080c001a02fca9dcb60c8603084679d442df49d2a07d2a37036281292ecae8a7ecaca07fba014ef6f7e6c140d0733e0cf3a950a04b1cec57789dd660884dd4a0cec4407f266", + "0x02f87601833ab70384773594008517bfac7c0083032918946894e745915afae9dbb1b84c8bf11cb285a16e698722c5681358800080c001a0420441d003f0dca8f0fccd858211e34c9fc16ed1b1498e0e6a9b37b00b6719dea04e70b511251868b46a471ca1664ba52b453ccfcd8960d89affaad83397681742", + "0x02f8b4018381e9ee84773594008517bfac7c008303291894fa1a856cfa3409cfa145fa4e20eb270df3eb21ab80b844a9059cbb000000000000000000000000082f4d0b3e90aecb5b38143a50278bea1308ee5b000000000000000000000000000000000000000000000bf5559e13dbfa508000c001a066b3e6f72e613d95ed1fde25bd0991973ffe958447aa359ab0c13a0821a1b713a049ffa84a401cc799804a51bccdedce4eebc64c725b05c990d0c48f14df7ed5a8", + "0x02f8b4018381e9ef84773594008517bfac7c0083035d1494dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb0000000000000000000000002b88cec110af5376af0bb6ef8598c65bb87460290000000000000000000000000000000000000000000000000000000005c35f50c080a075d1a20346bf6d8c638300f788f69970ae166561290697d6ccdbbedbdddfd3ada00362acd337471e8f5619a4a134e20aceb11d988c94671b5cad7659f20c2feff4", + "0x02f8740182093384773594008515a73b6200825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e4387059a4ae4a761d080c001a025c5f09b3ebea185133df5a68124f8fe524d07cce849ee74fb31e0ef27999685a03abbf03958bad0a1ddabc778268af404bd735f93772561b3273a205bae0d2519", + "0x02f872010e84773594008515a73b6200825b0494a9d1e08c7793af67e9d92fe308d5697fb81d3e43870599cead3a4b8380c001a0137ee0d80cf0d1c764fba84c2ee695c8e133108ac1d7c182d1936c355af6e699a05a0ee602e18285c685812e12053e9cf06f76da18c2d337f840c33d740164498b", + "0x02f876018328af2a8477359400853a3529440083015f9094a93eb99caf4570eff900d1178c1d7d6a80b1c5d68710aa62945cd80080c080a04cf98bd8f135ba9e1f9a9dd1d7e5a50c65950d47937313836117736f38b0dc94a031785f37f35d8e76135191b5c28d1bf25191a266d4e6bc37690fb06d1b6d122c", + "0x02f87501831c5b2784773594008545d964b80082520894135f0b874d2a810ab545f18457574860a1d41817870cca2e5131000080c001a057fa557a78037aafa623a1bb1d917e9bac86e69228c40b9749f26ea8186d8ba1a0102ef4109e8ff9bd67e234919c4ed229d293eb0444efd68db54258368e2ee73e", + "0x02f87501831c5b2884773594008545d964b80082520894de0932875d9eeb403f327125f86614b70d57a903870cca2e5131000080c080a02064189b7fc268be45dc602bac349a611506b81be7d55448005b9eaa67d8679ba07f8cf3feec39cae186cf38afa3d53c1e120ef2e49f7e3187d26934db422016e9", + "0x02f87501831c5b2984773594008545d964b8008252089467006f2c487cd503539491b383c63032a8414397870cca2e5131000080c001a02bbc892b61976edb8b03229619ab408bb3f310513e36d2fa8184c5fc97e17b48a05ce6b50aa0d6e7f0837790923574e5590076680e35a6d040f69436a105d0de5e", + "0x02f87501831c5b2a84773594008545d964b80082520894b880725c8191ced33e344ee794d01d7df39d7fd1870cca2e5131000080c080a051d8d2705d2e2460bb187aeabb4986db6de4abb8daa965a10ce4c9163a2149bda069f970b13513455ddc34f76c4a0820adca2970811b9fb3fa4d8f36ecd44ce209", + "0x02f87501831c5b2b84773594008545d964b80082520894188469409bed858db50465c9e3b1a2d51e62afd0870cca2e5131000080c001a0bf669fc5a6f5782fb321065b96e7419acc29d0959cbd6975330f06df2c075ef7a05542db702f0ba5f8d38c47322af0f412dd8fba2c717f7ab1ff2473715cafc00a", + "0x02f8b3018221f884773594008517a2d1caaa830186a094cf0c122c6b73ff809c693db761e7baebe62b6a2e80b844a9059cbb00000000000000000000000086d2929645aa65b01931857d816b9fe3c7df1c3100000000000000000000000000000000000000000000000000f78176af9da400c001a04ee2ce0578a7fd506d7c0aa61b1fe468e28d77d8e4dfd8af21dee6c01754357ca062722f6ab2bda05bf3443774af3933e7f552ccdbd174c2da56a1eebff4666c1a", + "0x02f872018084773594008515a73b62008252089477696bb39917c91a0c3908d577d5e322095425ca872f470281e2500080c001a0179114a619096f5e3c451784184ed2e11897cd108e9c6e2c0d3446a2111446faa00f2f8428217ac1a36aef0952c8f18038df31a8830937d9d4cc8d34ad37a20353", + "0x02f8b4018388941d84773594008517bfac7c008303291894a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4880b844a9059cbb00000000000000000000000004b888c81c747fd2fb04c96e2c314e59598f326000000000000000000000000000000000000000000000000000000087fe000880c080a00b27d31bc9ddfe8ff443f8b81fa502562109e37c6dbe0f4e61f3078fd0d82f41a03263f94c0b815003b9c0522b0318ab651e3f56fa691dd340ba9b7d5ed8765bd0", + "0x02f87601838ceae184773594008517bfac7c0083032918940b5b51be20f30d22024ee7595513fc7b11b31e2b871b0028e44b000080c001a059d21c8d2aecfa0b2ade92909ab54d61f93d64dd0c1a0c3be26caf0d8c95166ba042eaae0da63176afa7661d9156302a67c6feba7d576a59e56bb4ddca4c403cf4", + "0x02f8b401835c488584773594008517bfac7c0083035d1494dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000f6a78eafd03f38d1a7ddd3bc3db91a8e1b90072c0000000000000000000000000000000000000000000000000000000023957f40c080a09f58532c3d3c85a6ccb155e9a454b2df9cd64e92b8d557817e6d24e50b02a8aba0374bd38629cc102ce51151f0eb2a52bb017b3435904b157ab50c2cff8d810d4b", + "0x02f876018328af2b8477359400853a3529440083015f9094bcb6d31e3363ff68e213169b50a5b2650646f79b87b2c2fb32d6940080c001a009d20a97f8e39e9dc9b364686548505d073dc00d8e4dfada8ef727bbda392372a06ed4dcf9c2d5f9f32bb3179ea3e4de9c525c19b8fef7d700ae1df759a735b4a2", + "0x02f8b40183064e6c8477359400851087ee06008301d4c0944b9278b94a1112cad404048903b8d343a810b07e80b844a9059cbb00000000000000000000000065da6725d8be6090b07af197969ca64720a79853000000000000000000000000000000000000000000000439387a52dc6e040000c001a0f832350a8a3fb47e51d14c28480bdb6b2b2bd3338e57e6853a38dd4739118022a0446198ed466d78e9ef3a23efd697e1c7ba8ecaaa8abef2e8fd47d2cecb1eaa2e", + "0x02f8b1011e8459682f00851791a15f08830124f894514910771af9ca656af840dff83e8264ecf986ca80b844a9059cbb000000000000000000000000a2f90b06b1d36a0b075f5fbdd7ee2c091ef7610f00000000000000000000000000000000000000000000000244fc7dc57cab0420c080a06a79dd00aa022286b27ecf31c88fceaaa679dd217eedfec091175054cc939d35a02cd5f884ad8ccefca82afe2be8569942755ebebadd77b96d3f447e5b0076d428", + "0x02f8d3018302d8bf8459682f00851791a15f0882f2089446950ba8946d7be4594399bcf203fb53e1fd7d3780b8648f975a6400000000000000000000000064bc2ca1be492be7185faa2c8835d9b824c8a1940000000000000000000000007b68226938b4db2d74404caca4e8d9ce9ac6dfec00000000000000000000000000000000000000000000000ea5c73c6b468c0000c080a09fc0f6f254d609ff633b7a861d1b9ee2af583a97a905178f32cffe0265c10701a007b522edd88729c7451963d6da110c1eb1a932cf97d986bfed89ee1979a2be46", + "0x02f8b20182068b8459682f00851791a15f0882b770947dafe897a6ff1d7b0b64f908e60e8665b61d53af80b844095ea7b3000000000000000000000000ed12310d5a37326e6506209c4838146950166760ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a0356435050fcffeb158c1080d94b9ebaa18e351b38015de9d047785c857007415a025eff1463b90980c67bc18f7fa1d6f02b025e5c14b567ccfbe7d38e41e518f6e", + "0x02f8b001118459682f00850e47f0e56b82b5a694cc8fa225d80b9c7d42f96e9570156c65d6caaa2580b844095ea7b300000000000000000000000064192819ac13ef72bf6b5ae239ac672b43a9af08000000000000000000000000000000000000000000000000000000000000afc8c080a098818c0328568bff1b14d823a5dc4bba9341e17ce6f4f7226f02222903764800a031662073f64f3f46457c1e2592bdd682b1dcebf753b1c9acd349249f4460eef4", + "0x02f90374018252388459682f008515699cce3e830f424094787a0acab02437c60aafb1a29167a3609801e32080b903048c3152e9000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000028e6000000000000000000000000420000000000000000000000000000000000000700000000000000000000000011dd2d9b5ec142dbafbefea82a75985eae4e12b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031b8000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e4d764ad0b00010000000000000000000000000000000000000000000000000000000028e600000000000000000000000042000000000000000000000000000000000000100000000000000000000000004082c9647c098a6493fb499eae63b5ce3259c5740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e40166a07a000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b9d571c1ec576300f01ddfa5a082d9c571e45e360000000000000000000000004d44b9abb13c80d2e376b7c5c982aa972239d845000000000000000000000000dbab11a841ef6b2761acd76c3b9eaee847d7381b0000000000000000000000000000000000000000000000000019ef4fb2dc400000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a0a1dfb511b6859fd0ddfd7576a19469b12907866f287d624ea8f3c9039a52a80aa0052f682611c33e9d39e1fb9ce815ffbe30463142e366f8b1bbdc8d00c77dec48", + "0x02f8b201826a44843b9aca00850efd30b58282f88c948881562783028f5c1bcb985d2283d5e170d8888880b844a9059cbb000000000000000000000000e12670fd59c315cc97ef77cfb3d06065b78f85b80000000000000000000000000000000000000000000000c3a88f6c9983bbc800c001a09a61be61ade365fd0557a61c0dc454287ec70f13074f116831980f010f79c511a024c94f6dc0b710695d878c9040f2204792e1ffc61d2436e6f8391963e0a2c017", + "0x02f8b301823566843b9aca00850efd30b5828301482094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb0000000000000000000000005edcfa1187d1e0216a0dfc7c7898a9f0f556039100000000000000000000000000000000000000000000000000000000014acf80c001a01d5ad3c53e8ffe2cf267d68366ab3072e97d0ffe5ce22fc729b6e4cdde67afd6a04608dff99f61af02858d52cde53a559a6884cdd232b9e05fa9e20b0e5b38becd", + "0x02f8730104843b9aca00850efd30b582825208942df9b935c44057ac240634c7536511d8aa03028d8804f741fce15f881f80c001a0092f5e983fa9a4c057919ce3dbe03f77ecc26fa4c9f32e0247a1c3d5897565c2a0785370e61ee455422a2347c3730cb357eb5e123672c66373e2b936ed6f48e3fd", + "0x02f874018272d1843b9aca00850efd30b5828252089447b6897359d31b648a10cf9a3e886400288bea3987279e861cce1ff480c001a08f303dc0353ed26eef5574ec2cbff01e379c32cd79f26f0645b9e152748435b5a03ce267967e335b7ce2df87bab4892385f9a1c9932927e71e9cd95111a73cb50c", + "0x02f87501830f5966843b9aca00850b6cbf811082520894c406a13e82c5a57fee7a68b4508ee07ae0de74af875535d1cfbb478080c001a0dca00e515144ef862d5a790ed8dc27bd36d7b93cd14765c4537862d8bad3d9c6a058e8ff7ab4aad2c8682a910f666e643d432782d71cb9f4a49536f6d646fa3cf9", + "0x02f8b201826a45843b9aca00850eaa1cbcaa82f88c948881562783028f5c1bcb985d2283d5e170d8888880b844a9059cbb0000000000000000000000001417177c3ba9187d90ab76de062cff18b4b530b60000000000000000000000000000000000000000000000c146e25f2f4756d400c080a04be2fd58f9764c65133f67a069b1078b0545e21c523b4851f1e5ef5b869fc3c1a0665f85c3edaabbcd27428c2f2f30a8f9788905d43e17445962c305897620e123", + "0x02f8760183087e39843b9aca00850eaa1cbcaa82520894dc5a0c7470b5671567771901b080ce608749ce2b88014b62071e11c00080c001a0c842ad8893dc8b1fa3833f429dc21fbe59857ea78cbef9ab93811ac8caa92830a02f33ccf399e6f1aff96affdc3c760ebc3bec06bd2e553d57f187e5cb38038b77", + "0x02f87401824169843b9aca00850cdcbeca1f82c35094672feaaeff55ed395e43f93a875d5dedbe3692498709a6dd2c01f9f080c001a0db911b0abd3e61460d33631f8cbb3ebc3f05130409a6cae91edad110fd39c2f5a05459d7ff083a838812ab756655e617f91132e8a3ae38d83a71275c95935a4db9", + "0x02f8b201826a46843b9aca00850eaa1cbcaa82a660948881562783028f5c1bcb985d2283d5e170d8888880b844a9059cbb0000000000000000000000001e7127c81c8a58661a0811f026b6be66533934be000000000000000000000000000000000000000000000069bfd250c6a77b1000c080a01de08434bcb35698ce9f348edcea70b4b9d32874771d599affa459e79b87665fa052504ebdb3da3d075b1b12c3b5fa1ab146467c2f7005af524d7d621a3906d272", + "0x02f87501830f5967843b9aca00850b6e4de1cf8252089439d7e80ef17afe7261b947c9529b869ba7c88045872853aca2d8700080c001a00466eb79832050fae55fb33067b7df7d45853f6d6bf52602bd1a90dc5137452ea04914e94face76b18820ce5db22c4c8be10b0d44b5b416b9ab6e8352272120234", + "0x02f876018302b841843b9aca00850eaa1cbcaa82520894944311875ecc192445654b1794fe48ab54ae6a8f88054b7b77377136b080c080a03e7396b978a14081cd3e90f0fb592687d11c2559805d4444d5403e5420766d4aa078a7006e9899befd664a084f94de1c69a1da9977f694b94153476cb2a4fa9766", + "0x02f876018306c414843b9aca00852098a67800830186a09464f961eec2ba222dcba8fa354f03e27529b96f5b87153ec73fc1c01b80c001a0583dc990d273492b5c74d3c94524e058f7de47042e4f92cb35b11c3b4dcb0e1aa0180e393a76b3d6065d0c55e625cc82da05c7896801d95c64e99a91b7fa170a5f", + "0x02f8750183087e3a843b9aca00850ee4b80f4882520894136e2d4c689617daf7110c53a32b512a9acb20b8877ca8599fe1000080c001a053f72254417682846121f46cb0d828d3536b027ef6a4894a9339fae216e62291a05df50338a3afd9db52bee8fef6ba4563e7148259660d385bece9d58e99f31ebd", + "0x02f8b3018189850a88b2e61f850a88b2e61f830493e0943071be11f9e92a9eb28f305e1fa033cd102714e780b844441a3e700000000000000000000000005c17b7bd70a80ce3fa7221aa1bcbf62de3985d2e0079ee7d871797a521c7a0cd953e51a1f079ff3d3a0b02a4d63f995258fcf0efc080a05d6371050d017e140b78c4f1e77b4deef02960c04ab29c9a3540315adcd12f44a05b1a7e67963f6838afc484c2b742e70b9c6a019712c1d2f66ed712ca956b43b5", + "0xf86b01850a88b2e61f825208944d24eececb86041f47bca41265319e9f06ae2fcb8757edb39a8dad978026a03d319923d281a9a0e87f33c43f419f75ffff2d2ab346fd0034528a2fb1ead3aca0046b56de8266ab78e57c448e451c51f372ece5f9600228d09b01bf4e7387218e", + "0xf902eb44850a8590080183037460943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2ac630000000000000000000000000000000000000000000000000000000000000002080c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000152d04202d703370c47900000000000000000000000000000000000000000000000001d45d9126f3dc9300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000d1f17b7a6bff962659ed608bcd6d318bb5fbb249000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000001d45d9126f3dc9326a0fcce90823efc87c96d390627c0e1b553b98739665be61e32dbb619f62e0627f0a015432090f7de23806fa2f6bd067c92643043b198507ccd29744366661ca09816", + "0x02f8750109842a51bd80850fbc9e4b40827c4b94f70da97812cb96acdf810712aa562db8dfa3dbef8703c619ef1625608319b786c080a0e32c688e8524736de4a3dcd1b687fcd7275239d6c6b9a05db426f73656a073d7a07c50950254c39fb0aaf410e0af41c12c0a7ece32c93fe76a783dcfabc20d3a7f", + "0x02f8b00113842a51bd80850fbc9e4b4082b15894aa6a914c605f9134a8480745729c6d0e00be038480b844a9059cbb000000000000000000000000dc1a50161a07c451629356ad5dc2c488b4bd05f800000000000000000000000000000000000000000629404873eba963786b37dfc080a08b66989e3401856b05bde57c6822409b5697b06de8e49ee068105b2af9441c87a00bb782a16dcdc72223335211fb34b703c5f0a636530839f150ff88df372e041b", + "0x02f91874018234728429b92700850f28c4de2083114e6c94b2ecfe4e4d61f8790bbb9de2d1259b9e2410cea580b918047034d1200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000178000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000008a0000000000000000000000000b4d24dacbdffa1bbf9a624044484b3feeb7fdf740000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000154000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000006f43b26ba724ae3ddb0c55536d64e5f985000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f9493c46d9b905e227ecfc266752eb7c7aef4cf5a8fb4e84018df3536ce8a172f9e700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d3d71500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e8849281b1971b7d614adce8504681ed0000000000000000000000000b0a206794611892587e3b0df04a64239e2a3490000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f949a0c92bad50dc3bc9b7103be708607112c3cb42d094333215bc030df903c51e7c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000065f2aab4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003bceac2eac4cc05b5332bc268aa69a140000000000000000000000000e71c843ce2c374e3b7bec768fd3abc8b7465b56000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f949c3fdd6f428a207dfcae4fd4e947ae2782b9af579b42ff22eff9c133e250a8b1900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d355cd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000afef5ebe12de0c5895cb43a34c417d600000000000000000000000006d02ce0cd50bff383035e1de5c8b2235fb22e4e8000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f9493c46d9b905e227ecfc266752eb7c7aef4cf5a8fb4e84018df3536ce8a172f9e700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d3d6db00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f9badcb58f445cf9a7ccc096fba6cdac000000000000000000000000da714bfafbc2b139bf6e91d9809fac5a104a9798000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f949c3fdd6f428a207dfcae4fd4e947ae2782b9af579b42ff22eff9c133e250a8b1900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d3d1a800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c44722ce8a6747a4096e0c79ccceaa9e000000000000000000000000f13532cc8f5c700dd30f9faf8b833b38cf78c7d6000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f949c9799823cd012e2adc57aa64008c7af4b388f9a6b0fb7387b1c94fe217238bef00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d311e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008583bb513a7f4bce368f190cb1e0d2df000000000000000000000000f4ce3f01788a6066d38145ca5995f68ed9128e61000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f94935952892cf0503d50413209caa900477ad2cd683d3d31d61b83e779afc67082700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d311e700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bc3bf7e6e1de2444e4eeed5863070e90000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000006e0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000b600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000002ea11e32ad500000000000000000000000000000000000000000000000000000000000000004c38000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006300000000000000000000000000000000000000000000000002ea11e32ad500000000000000000000000000000000000000000000000000000000000000002f51000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000002ea11e32ad5000000000000000000000000000000000000000000000000000000000000000002c8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000002ea11e32ad500000000000000000000000000000000000000000000000000000000000000002eaf000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000002ea11e32ad500000000000000000000000000000000000000000000000000000000000000002d08000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000002ea11e32ad5000000000000000000000000000000000000000000000000000000000000000021f4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000002ea11e32ad5000000000000000000000000000000000000000000000000000000000000000031c2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000002ea11e32ad500000000000000000000000000000000000000000000000000000000000000003807000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000002ea11e32ad5000000000000000000000000000000000000000000000000000000000000000023cc000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000002ea11e32ad5000000000000000000000000000000000000000000000000000000000000000043280000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c73f69c4c2d9de81380ffa825e2723744a750ea770c2e3ef35a190cc0a7e651bb75ee9a54a45770d7a514920819c9705553754efae5ebfe25d4dca57bcff8fea051bd4f747cb65d2d2aeb491359c61ea62974182170bea195dbaa357bf5673d34a115bc8026d7fe931bf2f2de05956701057b186a862dbbc5e0f7f9bc5aec7edabcf1b4f8d7e9f4813bd2a40f2dc56fc307e44f13b15400b20363b9773e3cb55519221325bf18920f7ea9470aa9571b1dc14d88507846f8fa2f567972aef341535fa971bb4276ca35a2e0efcf6a9a439a2dae85ce62e0af254c3f32fc8c1e52f6b267cf642f87e72034d240cc0c72e797d6a0a66016150d84df2bda0afb639a03c1284541c3372aa12fdb1c96c09df3bcd793d31fb92bdafaec82bac791c22090ba6ba0ccd021ef04e8fee62420bbb46448bf6892fd7ab623b7c9c3aad3f2a1734351053331baf3f6f03d04af9b9693ef440db14efe5fbddf364d311386a8149aa6035f1c89e08cad3ea9669e663b95636a07406f0c1acdb6458099cf3d3cd1f86fdb51b8e531bab64a8552da0eb41c74617033a5ef07296ed49bdcfc38ada79a45193544beba46affea94c132d9f59d7209003fcb4b7555c114486168fa265a8814959afefa691c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000592d73154611fa1946c16daa7834137449258c80fa499f4ba58070ba1e9c0cfcd5709885a5e3404a4e9c79df8b1b0d87983bc23ecb90643c8cd07eb93c0ffc81ad1c0128819a6af68e5d010513ff70a3aaed9afeb8661116e6ce00000000000000c080a0f63d057c9061b69c3001a666186f91fbcddbce1afaf6ee053201f1f913cac64da018b61e9fd0dee1a2a31b0647540392dc5b139f4909a64857f2e7f51f341f2fb4", + "0x02f911f401823473842a51bd80850fbc9e4b40830c5d0a94b2ecfe4e4d61f8790bbb9de2d1259b9e2410cea580b911847034d1200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000b4d24dacbdffa1bbf9a624044484b3feeb7fdf7400000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000f4000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000006f43b26ba724ae3ddb0c55536d64e5f985000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f9493c46d9b905e227ecfc266752eb7c7aef4cf5a8fb4e84018df3536ce8a172f9e700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d3d71500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e8849281b1971b7d614adce8504681ed0000000000000000000000000b0a206794611892587e3b0df04a64239e2a3490000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f949a0c92bad50dc3bc9b7103be708607112c3cb42d094333215bc030df903c51e7c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000065f2aab4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003bceac2eac4cc05b5332bc268aa69a14000000000000000000000000927192c4158bbfd98874ef9e781abfff43bbbb5b000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f949ed0e627242314a2d7fd604ff2614c48994ba23e090f4bbf517ce43210f2cc8d000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d31d8d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d0e19226ecede1101d9f454860067a4000000000000000000000000a3b3acf61034ccd05f204e24e5935cea4d291065000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f94913bb5cbedf2f3d8a64e1efa7a0ce0e1e21c62daca139a8ed77f521f00c7c5c5c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d3cf8e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ebc11bce224cc654fb2acc8f5588dc0000000000000000000000000ba3269e784c087c2c427c62499b5badca6775dcd000000000000000000000000306b1ea3ecdf94ab739f1910bbda052ed4a9f949a433df76e7d352a93c61a503f86ce9192b1857b4f25470be2d300b1fcc0aee6f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000067d3d6da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e82a9ff9a7afd0165c2f7a4f4c797d4e000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000002ea11e32ad5000000000000000000000000000000000000000000000000000000000000000031c2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006300000000000000000000000000000000000000000000000002ea11e32ad500000000000000000000000000000000000000000000000000000000000000002e03000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000002ea11e32ad500000000000000000000000000000000000000000000000000000000000000002d08000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f00000000000000000000000000000000000000000000000002ea11e32ad5000000000000000000000000000000000000000000000000000000000000000023cc000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f00000000000000000000000000000000000000000000000002ea11e32ad500000000000000000000000000000000000000000000000000000000000000002644000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f00000000000000000000000000000000000000000000000002ea11e32ad500000000000000000000000000000000000000000000000000000000000000004328000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f00000000000000000000000000000000000000000000000002ea11e32ad5000000000000000000000000000000000000000000000000000000000000000021f40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001453f69c4c2d9de81380ffa825e2723744a750ea770c2e3ef35a190cc0a7e651bb75ee9a54a45770d7a514920819c9705553754efae5ebfe25d4dca57bcff8fea051bd4f747cb65d2d2aeb491359c61ea62974182170bea195dbaa357bf5673d34a115bc8026d7fe931bf2f2de05956701057b186a862dbbc5e0f7f9bc5aec7edabcf1b37ededdda37a8706ecf2f1690cd77abdd471c03dd6ab290d02ba01b823c05c0a52811707d9bc26a609560435d87c4f65fcc62c2ee12cf47b091b2182ca5528e81ba7200a3acc4243d870eca358f2633b96d3a148c8b02cd9ddcdb38eed07c83e7e15fab344e41c7797e7c911aa6b9b22dd8545e1f7137e372fe1e6d9ee8fc17a451cf2bca54a737139fba92b3a95e37c503bf5421cfcd2c67b5119635233fb1263b6292d2390eeb32a5faf40d931b26705a5c4e08ff24fbda17cfb716cea782eec101c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000595568309a8db19f87180b74a21c4a665f80195e9107b8f7388d4e294c174d1fc00ccdc2d240c9a974c3626a307222dc9a05a8ea4551e90390f2f3b6cae42bde6d1b0128819b6af68e5d010513ff70a3aaed9afeb8661116e6ce00000000000000c001a09c538b5a2e4536a0b245e793dc7040a24d1e61893a9faba926263466dd3e3935a03134ee529876102b69b839f33061aee638fb0620c0b596aa3257668c80d89a23", + "0x02f90232014a8429b92700850f28c4de208307a73f94ba12222222228d8ba445958a75a0704d566bf2c880b901c452bbbe2900000000000000000000000000000000000000000000000000000000000000e000000000000000000000000086b1fc73244a6df1a3cf0accdd1bde525932d630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086b1fc73244a6df1a3cf0accdd1bde525932d6300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a333e9b15e9800000000000000000000000000000000000000000000000000000000000065f2c1db596192bb6e41802428ac943d2f1476c1af25cc0e0000000000000000000006590000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bf5495efe5db9ce00f80364c8b423567e58d21100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a3065f8bf46c54a500000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000c080a01bd842010f6fab9cb92eee450a25cf5e359cfeabaf30314711241afe67ea3b40a028f8b7474cc42e1e2dd6d3f1c8e09baf2208cc2f49671a7378d439cbca280384", + "0x02f90259018205588429b92700850fbc9e4b408270189400000000000000000000000000000000000face780b901ea1f8b080000000000000355525d6fd43010fc2f79e554fcbdf6211e4a4b25242424a8c4f37a777d04ae4994f8505175ff1d27e52a9ac7d99d9df14c182bee719a8e3d61edc7e1edef81af0a92d4abfaf8e6e7320eefe6d351decbd24f61f7d48d53b7ef088fc76ed771e376fba7ae8e0d538fe4130b81f33a52a01872525a01d9e01c526224d42e09a8c62ca78156b5c6432299ea975264feded71fdffac380f5344bdbc2f9b0acf7c77578ff6792b6feb95f6a3f1cda74433ff1262dacb22d4a078739836072458b06efbd0b5e025fd665ded6db34dbe8b56129042441454b6255114a9a2805106fa3b8469b85faa997a13e3fd144e500cadd87ebe074bc16367297b48b51e0f6d6d80846df02c4d5fcb248bd19873a233d939d684162029d2403281320816305585a5258ac269f635017f2f6360dce5c807f117cfc7ad3642ee0f5c3785adde95d47e3b0f42cf356e4fdf84b864d5707b0de29e3ac40b2590900291bd9618cce4529c51bc7b426feeac2cbe5a85e7fbb6ea938d7fbfe4136875ad9149f8dcbc0ffc1abe8062f2fad6e41500066d6262150292d6fefb34d5685e27db081452144e6dc82454e31a7e4028362d78a31e25a62a684e6dea269bd91297a6d5c38a0581f122b5b0058a5ec20e8f62b72146daccf2914a6023a77e7f3f92f4b751e4efa020000c080a0e1cfd7ed04ba71a4b1b784a44fba06f4e708cb2613fa89197dcabe0e1ce1fe7da02aac895e125f07125572d4e28db67de2f441e762137f696a8cca3207f48e65b0", + "0x02f8b101028429b92700850f28c4de2083010ed994dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb00000000000000000000000092e929d8b2c8430bcaf4cd87654789578bb2b786000000000000000000000000000000000000000000000000000000001d77caf0c001a0ffe55b891ddeefdbc515ec2d5e98d303ee7deb39ed0954f7129310565dbdc3c5a073952d6a0c70886478da9d6d639f86c5721a6b255074ad4515489b2fa0e678c4", + "0x02f87201018429432e978510eb53889682520894d455f7c9898cacd7b1f820bb45dcaffd33d030d0873596be64fc0dda80c001a0ac5c94daa1e787f2919b8fbe5c959d3c2e4ac493d338e416d26b6175f9f5ce80a058052f807831749e38bae86b0927ba765e7c30307062866a16f3b60b5175b72b", + "0x02f873015f8429432e978510eb53889682520894fb228b655d106c81756b11ff07baf93ac8b9a8058842c1bab096b53fc180c001a0d8c479149bd51784e376abcd3ebbfb7700af5180f6103c77747c621fa7b0ff6da07040b9a753018bfa5f0d3709cad09be329c069bb11778292e9f5779268fdf6e9", + "0x02f87301088429432e978510eb538896825208949031943751e319da09ca948ae56b0a67118dc41988015dd990412daf5080c080a064d860d4f407c5d941d2f583795e75fcb74539dff0e21676903ce0d89e5afe1ba04434ef0234fe4871b82fe539e4bfea525bb4c4c536c2a64449abce36d05bdcee", + "0x02f8b001208427f3f16285108164a99382ca25944e3fbd56cd56c3e72c1403e103b45db9da5b9d2b80b844a9059cbb00000000000000000000000030f6759b7db6596897116ba606d7eb580cb1c1670000000000000000000000000000000000000000000001c2c84c5a9fa6a57aaac080a02ca94a07d61c94c0943da11b479bdcc6940601339aff80c090fca9f7b8c3836fa00c3aa253bac32d13159fce078080e9701e8d4b31b946c714deb80c36da1416de", + "0xf903ed82013b850a7a3582008309873294c36442b4a4522e871399cd717abdd847ab11fe8880b90384ac9650d80000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000a40c49ccbe000000000000000000000000000000000000000000000000000000000004b51500000000000000000000000000000000000000000000000a51e89a8d0bbd9b69000000000000000000000000000000000000000000000027fccd3250516a761400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065f2a51f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084fc6f7865000000000000000000000000000000000000000000000000000000000004b515000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004449404b7c00000000000000000000000000000000000000000000000000869046150d3310000000000000000000000000fa2da36193c5d80829529fc71bd0f2cf63594776000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064df2ab5bb0000000000000000000000005a98fcbea516cf06857215779fd812ca3bef1b32000000000000000000000000000000000000000000000029dd40184d25d9c21f000000000000000000000000fa2da36193c5d80829529fc71bd0f2cf635947760000000000000000000000000000000000000000000000000000000025a03dee2b757a75890d31b4e1679cb51c85d9809b2372989e5b313fca97f0686c22a0482b6532923cc89fe72d58c20a5334384edcb9b3bc7eea7c4192a25dcadc366c", + "0xf88e03850a7a35820082b2679400000000000e1a99dddd5610111884278bdbda1d872386f26fc10000a4497ecfc56d31396470707265773637000000000000000000000000000000000000000000259f04b55ff9c08d6a62858854e9441b9c3e477ac8f7b41b4e3a3fb1bfd5380ba0a0787f4bea2be6e65860a3cc6fe9282a6cdde15abe7206957b11ec1132ae0edc1e", + "0x02f8930182011d85010c388d00850a7a3582008302107d94feefe92e2192cf49cc0bb75f4c0f044d3313370780a40e5c011e00000000000000000000000044d585fc510c5d30d909d83563fec8a47d8d264dc080a0cd3f4c901dadc10dee9816c19f24f8b7b6a97e985ce54f441d15cc633167049ba036d90a8e25e7d2400b57f84cde0358535c4c06619649d36630e3d52692ac6f57", + "0x02f90332018084258d0980850f574a5a408301351b94d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef000000000000000000000000000000000000000000000000000000000000ac510000000000000000000000006be13e25bcfa44b43ed359c9a6e436eba0b083100000000000000000000000000000000000000000000000019274b259f654000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000011b72dc4e4d0b42a6839af67ca600078e35248b55f38301a4cb184cc526fc904aa3441c8b9dd1d18f328cdeb1811105930295f25af268937acd71ebab1d5dcd079abcb76e5db2538ae47c4e3538c86ba3d88df9f1f709a32eb611492f3388656feacd2140d70724bf1f7297d4cf7a027d6e643e43d939f9c522ec165bdfbad171e653f63ffa60a3204bd246211f0f2f99b37d6b1944f6f33d001a512502aa1a376829d388ec86b231c68730723bef51c856adf24670469cd9063d2fa37db902198b64ae6788fa19e5787a2c9281d6f98ea6cad20553c2fab031e9dd531cbb726f1aa35b2c66d55ecbefa599d6de6c8efd717848ebe6abbaf40cb6f9e07882a2b7ee9069f62d1461a0ba3fc962021e63a9d0a98898489d6bbd7220a7aaf4974f226a3c43ec7e0b18cc01a74c3f8e7603e3465925484e6c5834c0508cf43f278ea3607ad21985c0a7b220c77ec1c4d2ba832cd5e2b80964ba4b60ced2b5967de3919578d7be013075f6f887937e87075ad37f49a82d0be743328564015ddc49e3faa3a2daa97f744d166ab5c9b170efc3e9fcf70d2dc968e4cba43ba29ed414753c8439869e225fee3df7bead8c9c011e7e36996bef45fc334cec3a7b3dd000cc2801845c13f25cbba3d726231691cc1678de0936fe89df8d408c9bc344d58d0ae0a46e70d0e09debcd1ba9ca8ff28fa3dcc7b1318cdac64c0b387c56304d964a2f86643f31da169680b58a8548f4d3144a13fdb0eb53a2844abdea2d4a0c76a82ddc001a07cd7e54a4d194ef506043559379c2dd6550d67dfa1c8752cf9b9b5125d283c62a04b1e25140455769f5a453696600f4a764ed8879c36809ae69d57ca4798cc9223", + "0x02f8b10101841dcd6500850b398a3880830111e894c02aaa39b223fe8d0a0e5c4f27ead9083c756cc280b844095ea7b300000000000000000000000040aa958dd87fc8305b97f2ba922cddca374bcd7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a055c69b24a62cad13ca6d1a23f10aa931c025176fb61df1c5d4ffc06d5aa6b11da07592433cf4b012de8f5676c7a0fb9d88fa632b29d8e7c176236fb72c8cad1b48", + "0x02f8730181a7841dcd6500850bd22a8aa6825208943a9b6fe84c1d10549d234100e301c43db576ebbd870be1fb16c5e74580c080a02fd8afb784c727d3b0fcdbf9059b1f8b1da148073dac76d3dc1a97418fe64252a07bc8a7681d9aa2e4c8f4cc81e96decf5e1bad3e72f4dfad8e53961ac6f5a7cff", + "0x02f9063501820257850a6d3076f2850a6d3076f28307a12094fd9f795b4c15183bdba83da08da02d5f9536748f80b905c49ff802a7000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000e3c2881d0c899a44e610b0f6ad13e5a240eb28910000000000000000000000000000000000000000000000a030dcebbd2f4c000022fdde52ca166b82dbda5ed31925283641de12ef678c571eb359dd14941475a300000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000420f63c799bfedd6fc5dfd04b51c99001c0edc8171c4ccf30e4ed26e29dc468e9020000000000000000000000004f42cd614516409e9bedf91a6e94dfe8dedb3570000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000412dc0c42432bdb572655756bbfdf0199ea3bf178aef3fd7d3357872d2abfaf00b44d0f0f6bb07afdb697cd5e39eac02d44b9e703b8a39d714cf09c396c38c37491b00000000000000000000000000000000000000000000000000000000000000f63c799bfedd6fc5dfd04b51c99001c0edc8171c4ccf30e4ed26e29dc468e90200000000000000000000000079182fb1ebbc09f2b8aecfe2dfbf7dea40b4fc6a00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000041e35381ed52125d436e4e3b649054197faaae99cf696f8257f4be2e59b832431e01b9e2c73b65f6e7f497902fe7b134e684e206c01fa89993b86c2d86a041908c1c00000000000000000000000000000000000000000000000000000000000000f63c799bfedd6fc5dfd04b51c99001c0edc8171c4ccf30e4ed26e29dc468e9020000000000000000000000007cdcf0e56aa0f34d844a03d388c1874b6edaf400000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000417b28ea1fb229ea7359f15dc0c4e42c803bd8823d59ea3375ed0ff55846aabe0a7531141aacd9e2d71f09ab7bbc37aa63c2b0c9bb4f7c44508eb44e42c1dd169c1c00000000000000000000000000000000000000000000000000000000000000f63c799bfedd6fc5dfd04b51c99001c0edc8171c4ccf30e4ed26e29dc468e902000000000000000000000000aac269d7d513b09bf721de748c4969fb01d3af06000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000411c4bec7856f808655ecc0fbdca9388e4b7b05b38e38be145520a0948753005e51812b1c1d14007deba833e8ad51f41f4879270d8d1b706fda5e2af875d77a9341b00000000000000000000000000000000000000000000000000000000000000f63c799bfedd6fc5dfd04b51c99001c0edc8171c4ccf30e4ed26e29dc468e902000000000000000000000000d8d8f676d5479c4cdfc27ee7ba370a3959308ff60000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004184b80bf38da6bb99aefaa2770c0394c4b7d4ecb948972aadfa8aa5f5ccf106ec7593e8bbd30f8729e7d45ddca1a3608da27bb3b4e54c860e91b052ff29c71a3a1b00000000000000000000000000000000000000000000000000000000000000c001a0f89dfb9dd5727a66d815d1f37ab709f8e925199dcfa1ff28c4e5ce9d384af582a0728d78422b1bddf958ce2462a61a7ed831ee7ec872095394ffb153aee4775cb5", + "0x01f87101830a6d8e850a6d3076f28307a12094b05178ed26b624875de845e07a8eb612d14097e1872ec391d29f000080c080a0ca6269197e71623f391827c2020871d611e341f74c12ee1d13e274348cf8c996a0189ff08439030629c395d59fbaaa626b4fdc37744b94a30f6773ed3e4a31420f", + "0xf86b02850a6d3076f282520894a32de314c33429f9b83d2f7b516b597b19d5d520872386f26fc100008026a05a7bfbdb0d54db91077ce176d6469fe54a69dbcbec926dd3f7dd028db500b6b7a0473734fb8fec5db3778b1338aa30803aba5528bfb9dd33d2284674974e475a29", + "0xf86b05850a6d3076f2825208940297567c6d98ac887a6e2abf7ca5beb65bf82663872386f26fc100008026a0f8e2555b04b2b4bb471d827f27c50777a72ccdd250ada84d485c71d14184a851a055b80cc36821435c8699fc33274a98446e575457ee6792fe6edceab500a9d080", + "0x02f86f0177843b9aca00850a6c97e07282b54b944679b663b018b6c944da502031634ec1ea96a6fb80841b55ba3ac080a06beb45f3e17dd7b13c6953de2a8da57e977b2d10ee93ba5f9c5b230ae5bca80da066a0b33596cc99ff61fb60721c115e01dfdd6fc8f603eb575bd93f0e2e6cedbc", + "0x02f8b001178414ddd4e78510d6ee2ee682b42994dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb0000000000000000000000003522965bf958bb753ef12de9629a8e453e0d71f700000000000000000000000000000000000000000000000000000026b545ae80c001a05fd964572f3d2b7857c84467e656f3cea3d9c99d25b76dbf97634e6509d66901a05c5ad6323f5c0114d0ab0a7e3be84032e8475444d3984b29bb2b2cd6da5445d1", + "0x02f877018226318414936b2c850cd2f622d6826270945a3fbda16754664800a638ae25c689c358ccb1a4874a9b63844880008319b77cc080a0c3ef28405b34c3d54c32e56987899212fe8106536d9742acd0aadef4b631e140a01e85eb7237502a2bd4b4b655892ea7a0f8f511cf4efa7fc167a46618d930ac07", + "0x02f877018226328414936b2c850cd2f622d682627094a7a50fea91fba3860fb86ed3610a5150f84ab7fc8740a8cdb6e980008319b781c080a056364c8dfea21baac1cd2643de6596d091e5ad91bad0c956e75fd3395e817825a00f347b03af3be43c67a543f0449d885345d6148df5e7499f577ff334e7a65814", + "0x02f9013e0180850a662dad61850a662dad6183023463941111111254eeb25477b68fb85ed929f73a96058288016345785d8a0000b8c80502b1c50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000d97e29537a876cad750000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000180000000000000003b6d0340106b3f201f7b152b3239d2d443b1b1743b108b743c748c39c080a07c17d816c90cc71a19c56c4818d7c97112fde84d0b10b6e0e092e54b7da5d18aa051cef64e0fecba40c2ad98875987d1a2f557896fc7f0e59401301a305cd7e173", + "0xf8a949850a662dad6182f2ec94db82c0d91e057e05600c8f8dc836beb41da6df1480b844a9059cbb0000000000000000000000005c549e582566fc28f88aa54b0421d5f9093c90c1000000000000000000000000000000000000000000000001a055690d9db8000026a08ad6d0f6fd5b12e0c7d89dd6715569de7179d6a6e24cffc568bb56adc2401363a013dd090887c2197d89cb811a1f6aa6f78fbd1afeef710a6923b55876539b536b", + "0x02f8b10171840a21fe80850a773f59d98301132f94dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb00000000000000000000000063e3506625e417776e3f83d1121daefbe81ea6340000000000000000000000000000000000000000000000000000000625900800c080a0790f6ef76840fe24032a2591212b926b3925eaf3374a878360fa9fd3c3aee796a06a1fec622e81eb6967c75f7848b711b2a934f7ba09b6a02c57a23797638cbec5", + "0x02f875018202aa8407bfa480850f66404f008252089466c578190fc157e230a7810b1a6db67e13925cfa880214e8348c4f000080c080a009318f77023c606cf6e2ed00d1990ae450047c3f40018629f2f1a1a72feeb8daa076380b6f8553a6f71e66b8d321c5a055fe4869372a9a1ec6eacc3e0ae5e5e46f", + "0x02f902d40182ecf58405f5e1008522ecb25c0083b71b009440864568f679c10ac9e72211500096a5130770fa80b902645578ceae000000000000000000000000000000000000000000000000000000000021015000000000000000000000000000000000000000000000000000000000000000a007295d94422783d4fe7fc43c5e20a5776f9e46e12735c9aa8d47979e40954c74022c2bb7ba287e18bbb1bcad42710f34f0505d45cc102632660dc3580b81dd7b0800000000000011000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000d030d8763f5ee5e9f912a63c2e44a9a4b0719c27d9226863d5e0c8ba4e687471007f8b374db3a04403df6611d21e1bc998a0e3e36767edd75507a14923bb7784e0000000000000000000000000000000000000000000000000000000000095de801dd2216b6b224cefba3913dc83de22a9d3b642daa52abff17d46b561c25951405ba2078240f1585f96424c2d1ee48211da3b3f9177bf2b9880b4fc91d59e9a200000000000000000000000000000000000000000000000000000000000000010000000000000000c131ca811505599ca4957903c258741b31aabc4f79ece9f90000000000000000876c27b18bcddf530b38fd396edcfdb15c140c435359d33e0334c5d4f6189e872ad078beac2e8cd9375bf73b5583f722ae89dddfe99d52e6000000000000000000000000000000008c5109350c693c3a2e974a6ea38a07d200000000000000000000000000000000019464e94991fce56f27e855f2c1e5fa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c001a05880cc75fe51c36c156414a3cb71c8bb0e73a0cf62b692dc057b0f15df6f1807a02b3e069c603a9beff43f4be59c0afd2002ee0f27c8d81775eec52a0c43afafe4", + "0x02f902d40182ecf68405f5e1008522ecb25c0083b71b009440864568f679c10ac9e72211500096a5130770fa80b902645578ceae000000000000000000000000000000000000000000000000000000000021015f00000000000000000000000000000000000000000000000000000000000000a007295d94422783d4fe7fc43c5e20a5776f9e46e12735c9aa8d47979e40954c74022c2bb7ba287e18bbb1bcad42710f34f0505d45cc102632660dc3580b81dd7b0800000000000011000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000d039cbb700c264ffede35259f488b494a2139ac52f72081eafc46383768e6f54e036455b87817766982a35fe43819b54990ed473b33d1e06da6243dd0f1e5b8000000000000000000000000000000000000000000000000000000000000095df2041d22eb19105f41e51e88f421ff7a4f55af77c78408af37641a15b5db4f889c05ba2078240f1585f96424c2d1ee48211da3b3f9177bf2b9880b4fc91d59e9a2000000000000000000000000000000000000000000000000000000000000000100000000000000003f9a24475b02b33e946ade4cfc4fa7d4deeb303cbb437b6200000000000000008666b93ba6dd4f173c6b5325f26e15f46bbc58160f1e8117001abff59eb9692eb2fe7a6c3f4c46a3bdf97c22689d103b43031a60efcf1592000000000000000000000000000000002a32a2aff1b150e918c96156d91faf280000000000000000000000000000000015b983311b9371ced1cccbe7953e047200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a04bf9ba9a85c626beb6d447ad26e53f70185d9de883f678484d77e8609c189cbea0073cb98e3f4999049403deb809ec6c9c0068aedee833df6e614d0cd1445c26e3", + "0x02f8b3018203778405f5e100850b68a0aa00830111c8941bbe973bef3a977fc51cbed703e8ffdefe001fed80b844095ea7b30000000000000000000000001111111254eeb25477b68fb85ed929f73a96058200000000000000000000000000000000000000000000000e706091ac5abd5591c001a08ecd4015a2c7ac2d89419ff0d895b8fcda713ed3f247929505d803d68eae20e9a00cb7a59bfc73663891daf7a216d9b5b5641ceb68e6c18dd22cf110e1208915cd", + "0x02f9033201098405f5e100850b68a0aa008301cfa094d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef0000000000000000000000000000000000000000000000000000000000013e4a000000000000000000000000f5d7e9c98b50f79f95cf1ffe4958152001f678040000000000000000000000000000000000000000000000019274b259f654000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000011a00fd0174c1ce8ab4546d6b0eaef4cf67a009c8a94c19d12ca849eb71fd192282608c7bbdc2544905d5ae9e9930bd059aa42d46a0f959dad4ac9faca4f798f0abc411d8912717a1eb90b30a4d317818bdc883d9cd8a7190127fe47567fb82acec3eae723a4148abc7691b2dce46761e28cf2f87f5232fed73e590dc52ff30b53b47ab1b175b5b5e551b0ed445fbe36420411d97b9e2a93107106d03b9dd6acc3ccbce6478c3784fd9b4a3621f42f370cef10b05d547896b14ec35c45c7d482805648abc7a4e6d0b16c1a1507e1994556e4e2acce89374a35ae0c061b645091425fe80ef85bc3e331bbaeb3161c2fb1dda6fc18f857831e23c927451f437d1e7d5937f65a1900a8336a53cda2bec24004a9d1456f78ae70d1f73465fd4cf919a4380350982e0479c032ce002d60c2a6ef7ae43f20642b726bd71cca1c3a49f4508013f45562d05e53b3a266edb09d6c36fe1dd603f311d68fe6f3f0e0b955dd735361874dbb87e350500fe9bc850acd8dfd03d626be0e60ec97ed189d09a0056c5f22909cc52b3cf1e69c3f1fa49062129331fc72283a842f3555e1bb19543955591b25fbbf6e15798754c79aa53f46bb2c72ba25bd77457c639d37bf351fb0973817ee8a14f49b7efe1f8351d9e474eca711776c9d4b2f80a01e0889a1e8a3497dbbba44476a13c02cfed0b524896278c0bfc2ede44fcc65c1b9efe49e33a5ae340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec001a022ae5e44a99bb95e8a1722a50fdfe3cf64956bcd4c15fe2a708bfb1aee4831eea04c1b962f1ac20f8d77f59fc96c0816790812a325d65f998b4ef9b776bd6f5f78", + "0x02f876018307c4838405f5e100850e75d6a3118252089496b48748b24b91498d44fc8cd84ec389b54e798a88116d89737007300080c080a01906902fc22e12725dba875cb92b9c189ea61f180fb7de62ac29346360616ca8a03df0354777b23d762a4521459378e2b74a2ba89eb9388b976a0933061b157aa2", + "0x02f8b001038405f5e100850ba43b740082cb0794b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb00000000000000000000000067006f2c487cd503539491b383c63032a841439700000000000000000000000000000000000000000000000657b3801b80b40000c001a0ffbb920cfdce35101bbf5c7f009fab0ee43e9366686ad698be97fedd490e4289a0764c9c151084f7b5530ba85f581ccf9de86810002dc3210902a9d659fd255d1a", + "0x02f8b3018201418405f5e100850d09dc300083012d7a94b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb000000000000000000000000498d3b772abf0d83be724a95518e7201126fa4dd00000000000000000000000000000000000000000000003487938e0499840000c001a0f09582e0fc733b9d6952c2aa9ef94274c94d3bcb8362f0d57d13ca89a21dc232a020e44fbe4dc03bec5eb08a1821a5549c2b23368a3f7963b33ea9f923ca3c8416", + "0x02f875018207478405f5e100850f5de814008252089443a61be362f1c4faafc7f1573e5bda4619bbb0f48845a805a27464780080c001a0fd17102e6557f82743863977af9fedf62f214db05bab0a458128d555876449d2a00a471be82cca8be9570c13738f31e0b33ec2b7298b8bd3626f9d5ee60b14b555", + "0x02f904a0018202918405f5e100850b68a0aa00830480c094b2ecfe4e4d61f8790bbb9de2d1259b9e2410cea58803782dace9d90000b9042870bce2d6000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000a00f2a39633e4106ad37cc4c4e10c7f30d77c2300000000000000000000000028a11da34a93712b1fde4ad15da217a3b14d94652719600d335e65eb5bf5c0d037479e9086f9efe57069d205f886cbe3ebe32b2200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000065f3c6a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c57a69b180a4367e796e4811d19b7b4400000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000005d22babfdc8047c4a91070aa04759bda4ea77f84000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000028f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000003782dace9d90000000000000000000000000000000000000000000000000000000000010000028f0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417b9d43d62383e3bd5dad9411e62388543e7fb56de53ba9e91776c7e0b002e0770d735e2e0b9b7be59ce8bbd4db583acc243e0d45ed61cc14bda0ce68381816e61b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059e1c5e24c8ccc22d545feb2ee523984f41249b0dfc0a3aad6210f4e33c44656554911616f2beb995495963488a1009ed1bbf275e3dda76a691c891a9919b19abe1c0128819a6af68e5d010513ff70a3aaed9afeb8661116e6ce00000000000000332d1229c001a05780991d65d7cbf54a7f7b2933e56d1d3ef409d1970dfc5459f7f0c87deb4ae0a07536a692c253276ee377987675e9db6d6819d52ee6be0cc1af644de67ef3b83e", + "0x03f902fd018309544e8405f5e1008522ecb25c008353ec6094c662c410c0ecf747543f5ba90660f6abebd9c8c480b90264b72d42a100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000d02a4e2a181575ab70a9d8404b79a32169d68df616485ca2461fc75012eb719fa033bbbe635ce2226f0b6eb17ef629cbbc493f591df3382262d9b51a9f08ee426000000000000000000000000000000000000000000000000000000000009544d0095d2cc27eec6a3d3f322887081372fcacaa45e0bf613bcbd1eee0f9cb2be9505ba2078240f1585f96424c2d1ee48211da3b3f9177bf2b9880b4fc91d59e9a20000000000000000000000000000000000000000000000000000000000000001000000000000000046d28d2e52040577a77957256c530ca25974f6a814511b1a000000000000000097d62d4572935295f909f243714201d9221215bfcc91af650500bc56e61cc10fda276c872277f0eb212b54000c8ef146f5d7f1b2a6d176a100000000000000000000000000000000f1095b16b9bc2e06de338ad6bbf6ee810000000000000000000000000000000017e5d40332f9657814a4deb4d81127b4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030b220fe303275c35177980f7a03cfea1b71092701195fb3cbde91fe2389d0c0797f4cb6976711cf4bb184b0372d48930a00000000000000000000000000000000c08522ecb25c00e1a0017f8d5e53298d8d6c73bac47ffcf2ec1eaef1d9874c402a4f4a7c187b2fd57401a0cf8f0152da9400b324b56b5c14b52fbd5ffeb7f46e4a15736aa0888ff9e47037a07f40ae77195347f761f2131338a78c624de434f7414713f236b08fcd5ac0ed8e", + "0x02f9039601178408583b00850a583bff808303d4e9941111111254eeb25477b68fb85ed929f73a96058280b9032812aa3caf000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09000000000000000000000000a5f2211b9b8170f694421f2046281775e8468044000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09000000000000000000000000446c8de76c4d32b607acd88c56380bc9bb732d710000000000000000000000000000000000000000000000fec99a4a552ff000000000000000000000000000000000000000000000000000000000000076b71256000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000018200006800004e802026678dcda5f2211b9b8170f694421f2046281775e8468044b4f34d09124b8c9712957b76707b42510041ecbb0000000000000000000000000000000000000000000000008273823258ac00000020d6bdbf78a5f2211b9b8170f694421f2046281775e846804400a007e5c0d20000000000000000000000000000000000000000000000000000f600008f0c20a5f2211b9b8170f694421f2046281775e84680443d3f13f2529ec3c84b2940155effbf9b39a8f3ec6ae40711b8002dc6c03d3f13f2529ec3c84b2940155effbf9b39a8f3ec06da0fd433c1a5d7a4faa01111c044910a18455300000000000000000000000000000000000000000000000006fd1772e66b5cc7a5f2211b9b8170f694421f2046281775e846804400206ae40711b8002dc6c006da0fd433c1a5d7a4faa01111c044910a1845531111111254eeb25477b68fb85ed929f73a9605820000000000000000000000000000000000000000000000000000000076b71256c02aaa39b223fe8d0a0e5c4f27ead9083c756cc213dbfa98c001a001697eb858418a3989ee6ff94d2a7a22e16c615dec996a0d47898cb0bd55603ea00dd83d692700edcca09da2d4ba150852507df921bd372fb6dcb17bb555767337", + "0x02f902fc018201a38405e69ec0850e20cf5200830356a4943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad8802c68af0bb140000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acb700000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000000044e46be818a9e00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000088490ce333e3f3aa384e5183836142490600da8cc080a008207e2bd0ea1ebf384169461e7775ff60099963e09cb519547c76225a3da239a01756fec9550faf2b48f0180db30e2e019915c2d9c0881d405f16ab2e036d4719", + "0x02f8b10181e98405e69ec0850f896afe8082b77794c668695dcbcf682de106da94bde65c9bc79362d380b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a0906def09dceb8606d66f1f346b528e31291c036742049b45dc5c52914f262288a03436327bda153fda3c63c0939256a239e0297e75609a944f748e240ebf08d622", + "0x02f8b20182011284055d4a80850d14fd758482c3ae94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4880b844a9059cbb000000000000000000000000d3b5e8704ca157ca747890162cec428cf71c1b0e00000000000000000000000000000000000000000000000000000000089c5e32c080a09c8ef1cfa82438957d36aacf2d46583fb083b4c921b13f13b8584e2582561d55a004f1e185bb4ace351de31d541ba40fc80cd932a56034185734292e836b36b49e", + "0x02f902b40182014984055d4a80850e2036bb80830460e094def171fe48cf0115b1d80b88dc8eab59176fee5780b902443865bde60000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e0000000000000000000000004591dbff62656e7859afe5e45f6f47d3669fbb280000000000000000000000003de254a0f838a844f727fee81040e0fa7884b9350000000000000000000000000000000000000000000005c38daab6873ea764d90000000000000000000000000000000000000000000005c924c7af1d52c03c030000000000000000000000000000000000000000000005d0962bbe25306ede6801000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020096bef91365f7415d82b2e1499e8e5d2e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a0a3f62e50c347fff9f263d8eaa39573a51450b6f844c939c45052c9ef0f70db05a056b79404a999551f31cc78502b6d77b7492175addfb307d9941e5576e2d47817", + "0x02f87201558404c4b400850e1f9e2500825a3c94f2566618d6d4f63bec3091602a678d59e1624bfb877c27fd1ff8ce6880c001a055ee943aaa726c9c2dadf8a4120ba3f20e3ac1ea7b400b49e23d4742b2a90654a074e9a6c93b9fddbe6a3e8263b49e2a96865745efbf100fdfd5bf975a33b5684c", + "0x02f8b101168404c4b400850c963a23008303486194b9f599ce614feb2e1bbe58f180f370d05b39344e80b844095ea7b3000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a00219612083352645f4ced91c957c510fc470e3425fe0b485a11e5aa835dabd92a001991f629910c577cfdfeb5c1f9b455347e766b9cf7db2efe359a54b687796a3", + "0x02f8b101248402faf080850d09dc300083012fa894db82c0d91e057e05600c8f8dc836beb41da6df1480b844a9059cbb000000000000000000000000d74d21ae35ff1337a0d6d79989228a8ea0a83904000000000000000000000000000000000000000000000001c9f78d2893e40000c080a080aabe18ee85ac238ac6c33ce3df02e99518d12a2edcfe57b7b126af9b4526c2a0141c9b35a2b5f9725d85bcf86540e0850ad4a2af63e3156d8b578474c573039a", + "0x02fa0186b80183080e6e8402faf080850e8a27214b831d252e941c479675ad559dc151f6ec7ed3fbf8cee79582b680ba0183848f111f3c000000000000000000000000000000000000000000000000000000000008d67c00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000161257000000000000000000000000e64a54e2533fd126c2e452c5fab544d80e2e4eb5000000000000000000000000000000000000000000000000000000000a039428000000000000000000000000000000000000000000000000000000000a0395360000000000000000000000000000000000000000000000000000000000018291005b1713353b50bb4d0480b19daf979a3df50937c6d9ed2cef7023ef935148af28ab7733feab041b0ed516bc1f5112591a87ba60ca4623e0060d456880a53150ea20da8610ca03f797c76bad37f5aeffbe33c01d566e71fe3cadadf7feff33dbc492924ba552a1ce1246e48260a1b4d1236515468fdd608e7127177a8795ab9c62a3bd18c7005df3fefb482c115bf9c3e2f257cb1f96b0e0c5e5c52d6c416bc14b18a06b7ec60288452e680997c805adbc006c6a53be7f4a9fe566680b2ccf851e0890509a2ba5cf09fb8572df46364b555f1b838541cabc8875a7efb66c2e56c4de220cd38bfdfdbfaaf6cb071194e83155b62bb529adfc120c1f21c67896bc0359c35d6a6794ce19c265161a8b009f6051022543628a4a12956d2e6952aab805beb83c9429f0b981549620351b52e116d1da428a5b446b6b2168d12b13d4b64200f60c05113b29954ea942f01e9f1b2d3745e4a3194a604ae30c40a5c0e416a6cbded2beb62bd9a6ecfffeef6ffbfb48fef6d3e547d9fee98cfef6e3afb4665fcb6ffa072570a2afbe24a43443dc4f7e647b52dd9b7a663f6497840969e62e1b07c6613cc270382cee840f7108c985b44b9c5db2bae00d4223141ef84f2f02a097a10381f3036d3e350346e77e6d73c9efac6c977fbebfefdf774e33d24f0b6a944eaddae94e5d3af5308201e1162c1a81b6a3807afb4d3f4c1126a4db45c5e79f39fbee7d6f5a79bfee76b69bce262661ff30094e30121b3a8aa006b18315937e16fe5f979ff75cb3a02f9e82fb80976ef0c04831d86260305276374e9f94ca4af3ff1fddbedfe7a2f34acbfcd235d399f52d191f2acf878a0db151fa4369d24a422024900e38ba521534c6e1aa5a2116120362898cea4253010aea31b498812dde51e5cd60680c0a7ac3403426513dac4154b23f77a634afb7da688daa5ac8ed180de1441c168782fab70f02d001281cfd67ea4ed16e2d6e83305ffd5629b4e1c12d8264af947bfcf068c22676d62a16ce9b8ebca121a11cdf0997c78eff078c1f56b259ec78e48d842072cd10d3fc2b05f04593c10cdc08362e296f8e027d3a900d06160943d8a6f34a20a57d6fa63afa1eaa76e151122dc1734d1c086795d77300a8c6bd09d2881380140c906998113fe9ef835afab03246d3f8da653bf9b5606a845d8c0a207d4438a42082022ebd7359340064ee0ab1473b77406e6e15105beb1401b84b657fac71029c4206014bd6a6033b45fd5fdb9d0769a4954273659071f90b6c1f8c99ed5a1f5156699ee082fb81d97313c8354b1414b09ebbbf5fe73013abb92a98219dd8f121019a1bd9dbadefbf28852524b851a11b5ad28c72bead226f04186ce36e6067a36ffcaed01a96349a4de496faabd1ff58bd07d460911607d281aca6654346efa41e59f1a7299e53c3cfa2f15ae853ba49a4405764c17a7824eed03051324ea2859a0b38edc2040920050a3068ca2d46315dc830a3044d2c5380189a96a41c70de31297339d227af28695491088881d9ed4bebc3347c50135513ee6ab4349a46615620cfa5ec2403a680d4252b017932237a9eee36b6ea5ea62e84b75532a284c42b5dc19b9f1ae6322ee2b50b3d3be2c262a5b33ca16d298089a5510084550cda484a6086dc15a39229601c1dad16a7222be6c7f13b4c5b5157effa52b7ff49fcd34ec251045cc725250c04039e346945437ce8f0102ba198ca0909ee043b382c00ce0816437df9244699b33be0c8554a03e42f4c42a9ad2a8aa317c09dfd13d17512f5fe418e08b796f5e9d1a313dafa9bab237935bbf46915cb0d145adbfc54bdfe30314307c5cde844972186e8c907ad122cccc8938ca56417d14e7086e27e9ccf4fd21c2e4158d98e2277c1f656e391f572e0c86c3d809f21fd2919059f3f792dac991ba276f90335868624067a32011405136094bdf1b132c2207ec5d0feb299b3d7b02c9e0c3fe6b2fb12a8372193f0617a0d77971671aeff9ac7dc3a0400faf346b64c37424bdecb9e5e197dd33c7875085a72c75b9a38caad2a19940243d8e84aaed91bb92d2582ce8f4166c602959e3d3cc3569c94aac9a7431e599ddf1e75d12ec0fdb2c767823bc131cdf2906a0d0e482991cb299dfd6adbd987ff72fdb2ba5ab86dc20c072b093c801192bb4ee1abc4283c4b8a52e62d8e75acddf8e461f8e80931bcb7831d5ab4c725443edabaeef7903c5fe16bd3a930b4295ed3c54872f640ea2f029464e7e07f65ac066aabce59853c9c59978eceb13dd6a06a83993206b53f86378b5837bf60cb96e4ba1f15f9a92ca6980a3e64a4cf48122608211f810793049939f039556c8ca0b26ac44e2d7e05fdcdc45fa5db65941922ef48ce69dab8d316ee24b366c3ca909518d6eb5f36a8612f3ed7b761dd0d29cb238a208ce5017ef8691b10ecadb39482542200a357b6ef602dab497e25158426f0b8d1f9e2fad17f4365df493aa40dd445d0960199cdddf3b3c5bda4e1c00ed5dc55fae3538fa2433fe47be7287106183b6b9e07100fac82802d47ebde67edce90f0a6392350d9b75e1a5029de8e5b2a3741e0d83a44c1dd6f3ebaa2844ee6ffdb37ccc8c19d0a9550053d005965c8677b71a1febb34286853048dc81c51eb9bb4b7f39a53037c07edd97bc08ed716b15ec22bea39eedbed2fc2287d3ba57f1168f865352658597f7b5f91df0c12a140508c6a8e301eb6ec66e35cc3e55350f64cff13e30205d20621f5a420e3e5e58f50085035f26e91330058b78eb5feb7aea786371ceae6497fe2b5f0336dd71440e573d653cc2fff921ea17fc88c2a089dcb3459d705c15d1005a1eb642dbb6c901d889fb33cf18f1b22ff4d3d7ad55cc24795a0c37af566e5fe65c3d305699e6e9aad9148c9eedc38031c56868c3dcc778f18160f16c2f5c7f88022e134d0a2a3c11b34a96cad0d31425a0a1e9be9f5b6deb2e5e66cca3263a0c8a240684a082e957b5a2a1b13c6188a51eac11c549dd167850894babc29c9034246bbc3f8064e09b5f57af641a5de2634eb5093dd1bd9885b954b26b17e3eff56226d02d492b02c1dce0acc07d03037bb61656cfd98b029eacda37c42876fe046c767a6e178e14294ae018f6ae96ea554611c4952c7b6603baa3392a21635f69483a1ff1d9ffbddb8a0f16c57bf96b1d08d4524a05cc3395c078201294e4e46523a4f2e3db5a51ac65eba331c6c18f6b34502ed0f641e1c758d1565807b9cc548f4e61e472fed1aa7caac4d4681f08791f87e9c5f6dfda6629aefa636ec4189216f14832f1cd6981f54aa2d1e9f4a329be2b2b55de1288df894b4dda84541fcbf7a2772911951c104540d2e2f5f6611c5b9242377b80f9b70ca30a88dab5bd98d2d877590704ac4d0ea5a96dcac063c5313505a58e1a141e6552ff651fb93226943409d93c7a026240cf39c9abbebcb07a1a434cb144f663084061366fe4335d7aa81e457c879fcb140823264eb15397e88cb522ccee7cf5c263a952f0629615a3127ca0c6d0ed8f7253463dbd763c644de71f4f0109346d87c0c288e61946ca3e941ace4f7ddfc810c9629144c263a7347467f4d5e4e6e3590f62f2f708d509f3e8434dfa9d749537e1efbb1fc4eea63f22b6223e577e04418067b3f2bd95947e4d7cb61c96fbb354cc16a517edd0791a95acaf04acbdf80782dc44917d85b15e1810d8e43d3571112baad279bf316321350f883d2f83c9301a780b542be890a6719b072f368e386b6c854a3d3ec9c233f24c76f980b3293de0e3f10bbcf038f11cf9e02958178394195f7797eb9915a3a39fd7a15a450a8efc99a8daa44a244092a60ee2780c468904a24c0baee0c759511f06f8c27b13bb08b86a4a1d9dcdc89e040e1beaab75b7e01560b3044584f2f949da0f6d58fe2ed07cf2061199dbf91b3cc2f7cdcd84bdf227ff8dbd100b0fbbd3031c8fde5d068c6f9d5d42f58fbf1590319c299dc88e323efc281b682a9cee04e0538cbf266c1e64fcecb17405b9c2f9de61faa87bef68af576047b4067f5cfc4d13d652e115c1ec18389616a0ef9e0c45cb061b47abaa868c8fdd3ea0fb839630e4b113b24a0a4d6e0bc2ffcb8651aa65b8986c2553c6dfe6521179b653f9b2119778171b4d30923e62d2b5221e43e0fecf8dd088b075a8a52b2e3bb73244984cb53ee6aaa5edcb4739fd71b5fddadc3bb7346d6a11007852cc29900f8750b8d5108f45b22a763e3d83f02f7facf5281e029e7cf26911c846bc6d22b6b6a0a046c99105ad21c8de5e517eec5990a2a538a8c034ac918f552f935a9a5f91395f7343df682180f06de90a0cbc6a3682fe1324d8241d7921cdfb23e4f34665592492bd0870f0e9827af8d4b9fcc9676817126d860605dd8cc00caaaae6c8d46b639d21b08c2c3b494ab4a95d95e24aa4fd080c01f43b59298ec5089e68d86b5883148291f82c3f88cb652c96c7b2e8495e0bf48328ff0e3fb1b186234e29606772128889e53e4044e292074030007227aeb17d77471cb073457293e9af334ca4f7923b6425e6dffce06ab0847a098c86ca434a442ce364ec165d95ee2a212be7b4effb1673b396dd7bd9e5a601d42e9ada053e09ef042388c9b8d15a4c65947638c893bb17bba834a11afa7222aae733046a9b3bda5ac89966a27627f933423e6086fbbd85df637f1dd1b9ab9e7f2c361af552f3c964fafe4460c4d38b8b8a6af12957831287cfcf140d6746c4a2d6cdad3b1c0f1ab836f69668fe1011b3a12ec35243cef3f8ac33c5cd786d9fe0eea773907357eb405ef1f9c0b3ca403187257a01ce9bff10dd77d9c92dcb88ca1f8f83f22f8bfe4a16120df0954114fa23462fde150c01965941a5b42c929c51ae56a4a50c6fba8ecc3d287b562d1d0861e075ec19a8fc16d7dff8cc993cf397b3ea6e8cbfcb8949b8c122eae74d4da78f2ade8d2ab0120b2b258b9a02c3886985e35c71932324d0e12ebffcda413fa1f61676c05cb18ec59e80ba6ef03d53acbb1226d680e22897c9930d952eb34a8161276956c3704b8bf696f0949ec1a85792435dd3405c840ca698c31d77c03c1c07c7ce0a150ad80486c10871f34ab697b81c2237a6ccac2d3812633274eeb973fc0fd1b964fb998d969ec5f6166be63006369d012ba7098694a78a74b66659db6829c1b8d211f5023b859b1c1c0541a05eba7bbbd8be9993aa78a7f882a29be214f5e12128946c317ac2117e5b9e93842c39ca50389c14f00bc24b369d9ddaca45c3a5be697829600046c6e6dd58f16c862b425b9f3fe909125688b80fc33ee4360194b3f7595cbfea40547b86b9623cc059c4464064e162c961e9d85e3bb90e6ffac0a36e37f0cae02543a653e4c368df87b907fa9d609cee2f6c36fdad910718a3fbe3a4da9a6c1e82ba6a4c0521189e4d89496c3a07be01d9e540ba4db1bbe9d1088068a2176448c30b0efbcdba4b5f5a7c7c53783b3f100cea045ddb633e919b0c2241ca7a1872465928ae9ae47f9aeeb7c6c88b69dba99e6ae0b04025ad9fac038a8de9d10af4865cae763267a7ae762199ccff8dbbef43e0571426d7bc41bde784320c0a76d5b9177464d71fb23f628d498755ea076a3a49748fb5ef05337aadcb67404b84a227accb760c1824bc391ca68eaa23914bd5eb82331c7c3649f35b01e9ccce0a142e149abe4e0614fbbcad82d098ebddc6fab556bc20dff7112476da215ff7d5f548f97087cce9d8d9de46dc9adb52e8afc96fc3a5ee2604ab62f5635e2d98bcfca9a231f0d97fd41c14ae1b6bf961a61fc01ed459b7afae965577710d1a21be3967795bcef5017e4dad51d045d76c47273c3da500e175ee3901e7db47899b5f594c3276d04d8339b6a65ea2bac27bebf38de894e1470b96462bdfeb306c5b9818c7a55fe53288e99590c10b98820b786b7bdcad6a938df4bfd19f28070110dce60bdc8d61bd6ec7e859de1dab074d5d4f7cedf0dc6a27cc7d53251bf59827621c444871affb84402b8a2bc72c6435b893438aa7f3631d6ba20fb4e70b1d80af1f5269c4e831780218ea1b9bbdeaaac5e58324a740edbb032ba1708a4b59d215c277824c2642ce9d6d44b084e7af82593423c47444b8784dbda9ee9993a39825c2f235fd624c3fef2161e538f82da4adffebf00409b9a9e819a1de0221f88031ff89314781d0900d440013a0da66d01ac3a379def00aaed6f4fb9803216d0cf03dc2200800477e0b03f70fb06382f0b7c8f056a1480b7536f17f720343760dc5d009a3e80a63e2da0d9016812402a1381ce6e40b701c0dbfab79864c0be0800b07d0b0c78011c5903843400c1a781dd3780dc59c0fa5460c57760c84a009adeed80e19bde94d0de427481111b81c812c0c7e9edb1db157f44d832e547cd1fea80a7de5f174fd3ff877a2ff4ffb3c303681ac2a4695ca0695b4264a427f45c55e163e07949becb5b08414594f8b60eb0f65e2e378eb3e42f31ccb6d42326a1db10b8d65ed324aad71f91e2dd7891378eb1355f171c99027257904a52d5d395da0eef0bc0f028d540f1af6db2f5cfe8103afa52abbd12d71763bfb41027a8ea5659d2bcad799643c990e513912558a0a443ccbdd08006e3e7c63271d0e4a75e1eb9f467613638c2946abdd27b52d05cf396b1d9de177bf7bcd7dffcda4e895f3c22bf60a4e88d5452fa22966b3a2dbb7fc508f472343e27c4cd5b6ddf9da9534b96d423e7debd733dc39a295f31fcafe1021cd08753f82a98506784cfbf007a2b39a8b84223de944342e8ef83f5dad1b742eff50bbebb49acde0616867ea375249e3f2fcf1179157c8c6b2fd7642751a28ecc8963c2ea289b56a99c7af94566c73b0249a0a3c0e2b97a4929e186e8c68ae78d8af255b1834541405ccdecd073ad65f6a79614f19f594c90a76b47a1c74515c779343302dc9486d3e5836a64ea48d6007cd83ffc2f1654fbb154bcb9d21463ef8a282bc1eb7add24435ba16e46a6f515391f14f0ee5b75514b29dd417cdb953d4f79f6ed11fb57003be27ec0aebed721256e7f1874a4a8a128ca9a0aca8776f79d772ee5f27c4d6de1358a12ec7973fe829f4d2991b6c98ba3f9608987aed6f0786401a01accd06475ee8f4759811a7743638c13741441e0c6a5fc4990d494fc5eb885be93e87447164ba1218b14302877d85101c2a875bf1a5fd6cc341a4185f4da6275486d2e078281457836fd5d459c3adaa0e171c98a30fb562a3a3e2aca84591344fca199f1d26b00b67f21e67b124075e3edfac32a690c87237bfa37343da13b6f23e5cbcbd72ea81322aab24a0a6210b8c3d0742f5c678804885695660b65c87ff5e1cd8b3d5d545f27fe4da6bea4144d8a5dcf40ee1a8b1a05a4495f200a33f9d2553323ef2bb0aef99d8aeb8e2a66a995fa1a1b1c124b975ea023af39a6d79bd6b0ccaa2ae7356e2a7926f1b092edf5ee416f365af1140cee2bdcd67334d868bf9ab9088b162371c8ff3f4740a8313b04fcca3f37069dbbad95ada885a98b87a59b16db3ecd072727e5dee391ec1fb10dfdda46c27342083ced7eabe2d4f4cb7e90a50987461ad0f0407587b8e8e366352a10704a9f496b032ef619ac5e1bd98316d6e5d31d23f27e9efa6944f8c762963356893ea50bb5fc2241a9135b716fa815dc5a564679d6eb3f581e8d71e3ee590a661c6e9a6582a55d8daed32bfe019db58c7e723e02055fb57353716f21248df3c8ddfd690f2e1096cc80960373abcb851dc0d19df4c211306033418e730c0a9b4faadd3951b82527bc1841b676f09a8fcee902f5010cdc88ed51e5cd94b6f02223aaabc254f29a211275747571cf89c56002eaa530174b87fff148dbeff86c714360ba400a53e4dd0aa1ad39cc9102577289964d123f58db789830f470dddb7ee775fe4e78f030fedc40dcbaadf6e64a7b103f4c827bec6d49950d61fc5aa32f26a4b04d1ebfaf02290a12605466819a9b001c10314f069629bd61dd3403edc62f38d84e844fc9310b61f01d63777706c9ca172bf3810c6503a180dab55936a887874a0f4284e508d1c17093a618b2f9a3a7b280fe1685caf9cb45276448adb7fb0720e02b7ae8355aa6fda98fae840726882968ac426968b2a3e4086b2f4b9a60e409c827d9c86f67c0ca088c1ddff89f0fffac368be56c2ce224906a84f9d597292446038b407db029fc09f0eeb89119966087ae7da17f933330ffbf43e8de78321adc443b868c889c98175cffc025cfb11ce61a2b5640dcb5186ae9f82dedf6aa9bae260015b220d575a37db3c0b42235b5b6e89c421fd1778535cfdcffb746fb37d83009b39e813c2a9fe07eb5e41f082f8579170f7842730a86651fe6b96b2763c50df1761bb5753322d1588cb87c3e0de0714549baded81c811741d2df3dc2c03b4e26e0790de52f4f64b4453180f4e9ec8d5e182c04e916b198b4000a3615e7865761905d05eec1ad55f23c51da37afecb3e0be24ef37eff6a0ecd9b168f76c368214d7b66c11fc0cb0ae5f446bd3446b4ec7d380026c3ffac8139499f24d227e6a33bf5450c5a9bc183df97f410d500f4f4f02f6a16e913d860743a440cbe119b1aab11e7a7d1f766eec003edebd04a9b9fd4f1e741402b61c7449c4441e4710d70de3a6a3146fb713b5d228f0ad66f2ecbbadfbd447f1a4b372638eacfb85bcd26229d727e12aeb912318f7c7350c04e8356d7b2fe4d125aef6b4abfca286e8a9ec8d0461f42fddfba94cdab35b0dd5f19d404d40f2840cc14cc3aeda920ad6ed57add498672c58d6c98be77057febdec61def25b8780ce00e44e11ca5a85570fc840ea9ada8547b66aa0c5c796bf4b8b09005c14b5ecef27823b417bbadd7dac031038a944605be9dfdcada9b94d2bcd7ecb9506ced415ac00cf082d4b4235841772e0087319e20d036d161ae8585dffbf4f124a05bb5d3f26a9c308a1d2008c4ae7674d19f036803c41a10c4789b0e191ba50ef96c104482cca1d2b03954c63b1d7b9f3e8cf3f2ebe214dd8bb852dfd44d31dc008f8355e5121971f397792c749dfefc50a10779cfd673182ded3c535ca780d8ee83224770ddfc5ea2a9a50ce5a11fc4127d3b10862f757428e9bb0abcbf0d9981a2467ca196f23a9ab9cba4dd8404749af2f83591bdc699fdafa7e477cb6c0cde1be9d1efcbf5a0380539edc4b5eb41c7cd7d23c41d5d82c54829bf76ce5911fa18839f9b0ab0b491415769f926cbbd41423e884881c60ed7e606bdb2c85e0b54e9a82f13db861bb812bb49ca655c9c92bcc88a7e91bdb526ba55bb8a8f50776ca72ef3e6852fda3acdab0f805808473c5a0b6883ceca31d799f9c398d83901d3fbc06b22c4bf28b9d73d2c53d74b881d87d2edce1a93c63ab637696eed00fb31c2a0df7f4ec60d754653502c5208ae95823080ef8ceb366b10bfb78df72bcd48db522a44312d5a7a25e63e17e4ed3ebfdc32b3f7b94c48a03deadb654c412c88965c1217e613cc723ffdea49b894fadff3c9f30d3790db11c77c2ae03ec41b91e9dba66e222ac4e19780f9f30153b806beb801a4f718b6e9d4531d42ca193762d29aa095242d528f65028951db61279ac1ec319ea5975b83724a25860f33cb717defaad651db9f276ce0c4f870c5f97307382ad0946304ec8b90a8ebda04eb9f9c6f739c1eeba345da1efaa9c1e4347d44079de78692ebee0697549692d3ef9097f9b50b960c3805ce3f8afaf7e115955002a7e29ffd99f6c49d01d8f5a82daa0ad97640230a1c595ae3dd9657b3451c3c8fe64301f3b804213affcca7eec5bcb69cacd61a2121ecac627514f438d2befb6a05567652ae18232b65e4c0dffd4b020eab286701f1a0da5c9b20356a2b203039762ec3466d8d1cb11a2b89d411287c96793a22caab04f9f828325245e698b8b86ae71dda4e1d596d869b941fbc2970d15358478a478bc2a817a4eac9bee93a7e265c30c14292c3b69c9be601af5c25d51f18d81bf2b56eea4faba354a6183cb52e4c78cf7d43301cde4d52e160335db6b8c4d25308b49d62dcaa475b065c1b7ff62710e0312f2df81a5b7052d06a06bd7e9e9d6ce2d4b0209a3ffb5f9e031a80759855cf3e7c88041750dc33657287b665433d3ffae87ab924cb87f4fffd1782a7502d5db74225f1b289b24e25b424b01ab13f9dd05a8b2b252638641bd96a891aa10a5598e60e5941bea1b14ac1288f6e96a999e99224c15441c5a146af68348c4285a883c81e61243c4313213f17bc5d53c67eb79e308fcf0ccf81fc5d68caa3da04e51e633399c7ea5bae2c69d72cd6a0c9095f286c17f66f492f8b40aa611ee0ff1bff4b672d3a3fd890f2fe13bc04c88ff7d64178c8050adb318bddcd74447a9200080813dc837cb5d8fc371de4a38fd6c00e2c080f4978b9e71cb1dfbd4870d2eaddae9a9d13aad7ff40357a401ce6095279e19914df63c92f6906a42a4ae6434b553c0225644b28b34e9947df852e5a762449953f78d0c6fc0fc05dcc1bc6e8909408529419ef4baf90e6e9ee2f5e25a9a57ec13bcf0cf9b21d75980db67595e3c7433bd6768614798292bd100392583b7f57d3fbfe461c3e27c40244102b6dd8ebb9552149731defe8078e12c50c54b6dd75772d9c70524dcf945c92b9c4ae7b49f4f357c9180c39ea8309a01540860a141e04ad90b72484eb0e5bd3839ff383b5f4c2cfaa917dbf6e24b22ac5f1769eb68ea9140ea7f58a939bec62539440138f728ee91eb991ba746c72aadd86718311fc5bd500ecc1daf4d2e8bd506a91106698a3c2ef0ee9be5255bc3006eca3b9f113dfb20e61679c66574ad90df503d3171c65b34ee003e1f2cbcb8a3aa8639eb4fc5c6dccbedf375349241600fc8fd861c76066909d109803e81685576a4953ac203b76973d659c0d138122886b435e330abfe2b67e3ed14b2dba6bc7f3e32f81ce443d6ed4efeb75af3d547bd07d7161ea812ed7d64c8cc79f290524030fdebf736f7ede57d14311bcd24168fd79710f5bc92f75ce26e9670a69a2b71ff75f4883ca9eecfe6c072a9b73b1db3abfdfdff47cb55ffe258fe30edb82eef76f2bf38e26f75f62ed91a305aca0fd8f7a11d71ce5cda03ef6c292dbc874674e7710b45a578542fcb10292e54f2f4b7225cea0ef9f1c66761087c96e33d43f8540dedcdcdac3bcdb602edc66481263e69d31921f55a0e2f37aea429401626c507331a4ce2abc5860634e65db0074f8ce3ce82778a9b3aefbe877ab69550809347ccdf723e78032972bd8f7fc7f6ab10fc95dd262a6baa4bd4b9cf70d8c1e6a39b00cf5b4990f5e9cda3d2fb3bbc0f56c3443720f0d72f9ab8a72967fcf9ae0fe67d3716cc5339caa190cdbfd2a22d56651c6b62b8adad359180df1eeda5bdc2260372c4b9e62131e454a97574ebad6fd1476fe2d19474c5b76d24e174943827b4e74c9f1eb10916df4d60080a92050480d4f3c23f8e1c0c5f4637b60ecc46088b9382c0a0d49a4789427df93a1013a67af77967fc94ad37280a6bd2e1b871dd6170551feaad59f9bdcc2deb017931da8dc2aac8d86ed13e4be32dd2164b31fb7f990148661a2d67dcf231b925fa831017d666f2d77b88a148528dcc8c2e38f1c82f8d7a9805a589a6644acf382205d4f67b58774d34958527bc413b15343021c5494ff821ba99702d491199cd8359d12011a9e24b031a69432e086e7c2f5030e67e8f8c1859ac0fcba0e5a2ada3f495871127134c32d65a363869ef857055538e75b236cf11909f541f5dba7bf6f6fd75256c3a430aa92107a9ba228b80b4926f6840cd86cdf47a137fdf690a845668c4adbf175f5b9cc2d3bfaf2b6f1f009d87c8510807f32ce68a392a69c17faae647927bf2d1f82002da71df216a1a4e2758fed7626e4c873c60bc7e2befa9aef9dd973adb6f6f342dbf372701b17089e925f60125518e19dc096270f6fce1691a360a2165f08a25e4d851d07c66876ca399780f2db44e960059b937d369de97106b6614fcbb081a43f74e9064d2d609d8ded5e9bf301245d83bcbb12a5a13fa168ef21782911953cf9666001af32d79e3a32731dd99124c7b81268b4194077052d5825aea1f763600e7a89e551dacdc0095ed79772af3e405ac791f4bda2ee0dbe782bb2c81dbc907794b8b1ec5063cb0de63636e4340147fe47d54a3e8b2ac9706a21eb644109f43af4dcfcee644a250164444cee0dfd10e30b0e57068793374aa8bfeb8fbc57942325d313885953345b87957e3175e2550053b761bf4027756baff61a097f525c825c2aa0f315a9cb717cbc45299b16ab072f0bf592a6f6a086d20c3be733946f066004cc255b4f09df1d134093e5f9b79ca576c1d88ef572c882ad75087f4a52c88169d60328e467bfc683e9768a6bd60b08fa0b5251572ee20078db3459195c9d23e341e719481b4f088f746a38e9bdab7f30efa2bd5a1eb0002dd64a7fa66953f550e2255b9438a6d14326f168c125516ab3fea54d0392b8ce400c394efbb762d23c1998bcde438b64db74238a936af298e2b968abd49e7a19cdd1d381102b6141fcafb89cc9758fb391b0a7b0c2f88f14db7446e588ba82380b06efa815e611cc560538fd02cd31fb8e6dd945c2b2a0457edd687d01520152c1e0bd69ee0110660387f3b5d65a918c8a20214d7ca4532967778acadd868bf821ced87ffa388e331b99e4b61131883cb4e5da32f282208a6805bde77b3a640842222cb4d1a550f236547425d9d8952254da8d7398d36848a95db8b718963bcfea828c9c5d1db510fbc96e039ed35bbceb2e72b83fba0c104abc4338670f2625bdad36e6d00034e9a9c3dd83e013d4116964fd88de11dc3aeb99d34c57919eb4af8862f1b28d092d4e051f990685efae6eb21d2c7b8f593481d34a14cefff7ee30bd97adadaa34779f02408d832ce1c12a5561508db448b7cb722b0a427c76e452d193bdc65cf46634fea5ef04281c6c1b40b8b5ad2ee60424f5e9572d9f1e778d03b47337c6caefe7235c53956cebf8ce61b0392f395923a8c8ae929bf23d4548b18048edb4a95885c651b257f2eccfc526c40e8c2eeb6688990b4b82859791bb2e50fcdaa3b3ee582206dcfa0cc86adffc5bc18684b2e39e0f820436594f689f809477643fa8c73e61452af9810a239537f3942f1acf9d8112fc06ef7afd6a67e655da00aab77c1df64495c1baf3d3df4c82a5d83107906e44e211e5c00b9cfc51c295d6dcc6f42a94f88b317c76d83eb947b921af0368174010ba4a85150d601617b3ae11d78f66f33f774c8e1eabf2bea4a39e4f905ae933af7ec9494f918422e5f3c39ff6f7c1df8d96ac842cda75a7376d4baec93ccf971391b9ccf6351f7ec6ee6c7eadb31b1c72f84fe82bcd1c5e8d435d34ebc0f1e445d305b52c15d08f694cc7e9769e64e74dfe58af189f4d2c6d204acc24623fe2b15bfe18aaeec2be10bb61424594ab47df65f56affa0f2ef66b29004ebcbbabd45314e6e152133608b316f0095254a4e2ef9e6352270d7954e5471daa3e461f1c9536bfb8533f9334f336427f06dc617fd73dd07ad411258eb702b48cdf293c5458acb19c8ff9563224bd9df667f9542d009f03c8ebaef51b0111ff303ecfb14446a59b884572a9b905ffb5e3e7213ad4b1cefafabf74c4d65d5535b9db7a3161913308bbe37cb8593c607f55021c562127ce63117c9c0f4fee5e95fce16ecf7be04e6c65b7315728b1f05af83d1d66d29f084c62757634a8bed25d519753a71a2bef622a6a200ecd8fd17d8b3d63448e6bef9a23e5659b8ae02e903d61e4b23c38256eda5a321432df28cdf5e0ff7a5ac9ea6fcde72e19c842234f027865bf0b7b527bd12a2dc6b1333e4dd52b710805bcbe28ff17031a670c69167bf073da7311b17bd88987cb9ae4de13f55f2ff8ead583cb90fcaf9aa21fa4cde4145882a17f530cc1cb70b70b132f8853e8ae190a244dea4d59b2b9246824d89f1bf4b4c21cc3c2a4dcce6c5a40fb3f985e0cedb78e96f309070c0ddfbd8b4804c0c3133547e46e75dbb9b9f98e235ae4c3133d02cd13bb807bec273ce8989f38cb07527641c08dcaa4712991b1959055926f214fe5237f13c7c1843d1fa140b37b69f741844d659442bb5094a300fc24a512ac9365981106c12dd734acdf129dc45bc1e6c97827a43aa687855c14412f7134233fc7249eac9948e24a092918ce121162db72c1a6cc2a1cddf3235f7df1033129bc721c74ffcc4e61ea5a478418240408d62c8e78a8b5d4544a121a4293b46529ed74a2c15b6fe064eb3e78418b5d6de9ed82434042e694674bc57ce14f0e190fafae8971f67ef843c5125a804993a11620c4fa3227ebbc7bb5419c71a459fc8ecf33328c605b534fffb512e955dca7eeba1cce00e212cd4ee8515d42af83455eb60e62d3b6e1ccf0792f5ee342873fd9ddea8c363e26015df8183e864c2940bce00a88499d59b382365dc2f54b81463aacffe70d8ba4ad1304aecb13134445d341db452e4d95a9c2836190120315b9e7d9f5474492c6e39d27eac79482bf5110c9e12563c1902d3a2d4f9354f29f13d3d478193323eedb7fedb5a2aa486e7e034c43fa6359ca8c31f12f809f92cfebd8b25fcb85ea00245e87929a7156d9698b00f2579b8d8bf61fbbebe9ad1912655681a7ae7c66c20d4e536483370761b43ff8a8fa9ca2c1ded3c9a9e3adfb94bee3371a1b96a85902a9a5a79f59b77d63a894208bcdeff6114b27799fd09c591f970119d9f0d72fc7282dc1ff23642b15d53334d1075b2173262c3c957c8289f290aaa3de529a48fd30041a8b31eb285359c5c80fdeb9ad32987e24811ffb569a831d1691b1b81278422e936ea1d9aed0b942fe5c9a66171b0003fed024f02612c995b5e1fc937baf612a9953f992f3c02d3640850a0ec48c8686c2c54a28aaf03563b1b69b8f4cdd57da7efae69b7104f6266e68fd62b4e9a569e10ec8499457c3edb47b47309f4694ed82e2c9f2338bd70e12615c54b2a6a6ba0a6c9f615b6e42fb2c5dab49dd94e375332f26b9593e89d7d338ca6122ee7cc1c6d90610be3f050e00909678f175e1e9ef315cfcb95036b04ecc032412cfb755e49031e86d9eea1a7bfd270cec2f8a5fe5fc1631423cac81cb92bbd0cde256d4635b9d7baf871cd2e0c238b8c37e0c766b73e0c6be96425556209329d1b460e7c83e15ed8f29c845801fc401149141902c5e521a791e468c9aac630ef946119a66ae665dcbb3a657252e83a86a648094f2983e39f48c1ced9e8cf316d1149f1408a7751bb40ee0ea504eedaf334de28afe520863f509ca6e4f746582ea841e249418ea0da7ba9e6c890a6bf27a2cbd42fab943e24c74a6fc28c57add616505a36092c3abd45f3d6e2ef1c84f46dd850c5a3ef1731bffa3454c5088e6d8125acd8afe03092ea066c4d01a6051685a51cbf68c54ba624c7d3bb8459115b5de5134604da27b8fb3352518afed44a40271843890125977b67a1cfaa44b6a3656ee14af3cda057639b9285e57add5f2acdbe8948cac3cb825d324950ee4379acdcd2dba839c024399c7c614c0e8b3c5f1fd0fe10ba9ddc359444916d1dd0ff3d07fe9abd57742e82cb71f7e447bf5905702e8c10fda4df57b8663105d7db9553e326a4c8a41b6398abc2129c927b48c903e823836fe506113ae384d7c85acee468526db72021e31a42773d3bc538bc679ef038e01dbc590f6272d69ad0ce48109abbd8ff9630443c6f053c2e38849fa97d00da8ddda6b1a462bc0fd151d9de4a6670c8df9699422461f5a0123a64482c943de8b5a8444a1928539be384a0e016fa4585125cd526389779b22fa81a27ea8bc6c97bf205f0e427a87fe2c240638a96ee548b4d044fef2671e6522e8f7392eb1d459939a18ec915e88d83b81032d8fc82ccfde149af7e7ac4e583fc694b711be723393d10127bbba96670d79f0f51645ed40eaa7b248406d75ecbf2c639c6cc8e440cb0056b7e57db9f77f7586f22fe6f7db9ddabef35f6c17e45d1bbd5b06af984c2fa13ea5020efcae358a962777bcc1ccc14cdc8b35ffccc5bf95c693f7256e6295f58718858e7c27b3abf40cc033d5c7db0421790abd875cea216332c549836c2a945897e25345f2ad94283c599e4b545af5eb6c0572973155e44066199e86be13d687a536291e319970ff270d082ed1e6c7d3c76bed9fcffe77d737abc12b6171eae833ccb9ee01f472650662cef23f805affbbf1b05bb1a827d17376fd97c7157c652bfaf05fae3a8fb62b086af120cd4e0861a43a0cb93f1086d0c35f1695db2c3e188623eac501b2b53dc7c88f85687cd3fce9684a9ce3132aa8eb73f6166035fb8ba6fcb3cac980c4d73b9ce38cbbc489b7c169ce6562de591af569a8a3f0fd703b237e7eb88dcd2f5393752ce36c4a17c2de4bdd96bbc9a30efacc08d7bb07582c578f7b3515c8fe20d6498764fa97b69340bc8d53b9ccd83a2b95b8193d644a66363d0abc5c50e68bb970911ae2eb84f1209e540f2a24bc94f0b943a48681600079e12c39ff11347a0b8a48f316a77800597db83e98d45b25db88dd279748e802606e163233596692eaaee4f0f453ec316d3d76a5845a8e52e6b98610b8d53ea7800efd7d9784b316b43fe6f06f6646dbc601827cabf33ce5a51fd7887112e3ca1c7ec50b31b1f00dacd07f6525cf0385e713035446613407ae4b2e7c75f19b0b43547b0cbea41954a457bd58f6277836ff57200598d44ff436b6079000b26648dbd374b87e75d5e5bed791a88e407314671dffe844854131c00fc53437a95278b42a5906677fac21a1cb22bd5a841735f7d06f3e340b8f22af796e9bd9c3476dc08de3dd9a21d3deeb84a85d50b0d1dc4015bcedf5f8a54bb393bc5f715a861f0a7867e6bd81b4749495edef6b250444cee946847ca063eae546e61318f8d68c203a57dbd3891b5ac4dffe797312739ed4156b8eb5b78cbc55e53a41ebf1331a7225d75985c84f7e3b1d1950957d48cb41cbe8ef23fabbbd65f51503791918ff30ed354a24b9feb0b0620b7f9ae54317367a8d6f6d9193f875cbed0d5d3f54cae46daf768a935ad605a932851d6c79f8dd54aea8ff13204f3b3fb9b127efde44e32f33f17a141ab4e6954ddafe5da972a48a4d728665170a01aa0a001de3f048558a94c082c272da593162e870366f9b0921fde5d6180542def5516750b1e6561b6aac17fb5cf873840cfe90f536f0c8fcda855faab8fe1d815ac2f08fb1592cfc1240855b156c444384993f444c6550f0fa1698276f9f40f165576d93739b5464e0d4e1cd71451775b2f45e4ce41cb61a933d6973d3333eff03e827fc93bce8dcf4d48678f08aa6edfd63822c97c001fb2b649aedae37fb3ad729cc923c71d060184ab27fd0afdfb5b216b2d47109f867f92c992937418a9537a0c92bb0121e50e6f215f18c139e3a2ad1dfe72fc97742fc7a9344367877dc8f3dea50b008077f7c0f0dc7daff1a1ccdcd4d9dea3ef573a341cad444f94de523bea798e4ae43fd2eb81354ae3ff7cbb411e6e8c9d5fd5539c0e03a49581d9e06d59ebdedc41e4a2b866ead24371297882f776c86b4c0806ceff1408cc6a186c13769c46075ce92db9041d03c49b2f21fb31545bfbdeb9dc6cab99083e823323fca81ed29dbe59f47537185f93311cef72a6d574c507f797595aa188e687c5c0938d7b11fdee74ae53ca53e2a242c6ad43d6b726baf9bd58274ded79c93baecb976880e8001ab46d04e2b7fcc4b8ac29d59f8a49c9cd0b8a6534dbf645544698acf8c80223d4012ff60a32757c191a47a5019cab71ec65e91807c89662f1da98e5411713e890f1ffd2304dcf22eb4a419d55acd21f26b198bbbb4626cfc006ebfe9488cc7dd3e9f535d323999d27eeccc41590a2815f91b36bba2454847769df8ac7dd66a90a9fa94390995cb9c31f59235f00a6a827af78d7ef6f6c42cc2982180b92887edfb58a3fd9de13b2cd169bafc0c013712fe691f9d1b22e27bb3afcfaf23990eb9dfebf8f284225aa7d70d2bdf1d21c8f3165513c1998589deb2d42f74e47b5f8169b02a3be166bb1012e68b7fed3a81627bbb36ce4268b350971289f69c933d6f7bfa13e9c77f312c0049869c6ed3bff070edb4ade0324b3677fc11503f306072ab916c3f402e4c2ceb022bc43d8d48aa52e8ba91cb4e3355d5178e4adfb92b2b4eae379c442d372290e3b7bb840c3c0c0cd15e9a5a086359e32b9e99e54c611b12c20eaf89dfc6c779e30066a799a7f6053d3523344ef062debeb36b5702fb75883564bf2743988f3ff004f0a08720f7fb43c1b3c7d3d3e27ec12aa83d283c344b1040070d0a9ea91544dfdfe9caeaa3dcb2dde504586e3e7a97a9673cb55f9e75a5ea53c2f8afd48df996279b300c2dfef0133abcac6a679bc2586f018db24ddee96d03b868346d678ae304cc97e76353e5131a77d8c09baea78bf73d4d45cf6aec20ec71b1a168338f7bdb13f247e46f8de063cf70dced137f2d22eb27d189cf0f83c533b328781a6ccd5c92cfc25fbdfe5b065e7c07577da5af4c208e32d237d69068ef0799534134f4f3868baf0de0b7fad6adcb8df79b757b4699b33bf7de545f901034233d0caee4a412267e7a7930b72bc6c32d5506d642c3dc7f44255be8cb9171d8d5396d2400d4bc1dbd09fa8c3d49c10be12b79b8229c7aeda444387d5c76b55ef1c0d34af9a60fa043930f4473bd8e3e87d1c9864d314a537808e0dd9d57b1232e2e3931da3921f96dfae23dcdc92f41c01bf9c5d814e2867c13ca9160a37adef809ee1a793380140c3e36daca1530bd3735d3603cd937c2fe9d57a4503c43d7bd07c7cdd9f5231c3ddefb2f07d1507a901429435dc0eb364fe434dc4d0fcd2137a89f24c1e73b9aa648d7186cd8cdf365432f4f6f2c68438ad11ce17bf01b3f2964835dcdad8cd6230fe706e0c38609ed5b6eb20ab01fe2eac7599997c12d42786be6c4ea51148ccd7971b7918ac77dec874e886df655ed25ba0e7e957fc8efe33f5404b1eba5a280af1ff2603bcd9137c8d3680897634038f6cad3d159c576de3e46d41d4378eaf8879aacfa33c3dfcf02c44a5ed4e9751efadbcf059e332565d53672b831e8bffe503e4b8a4c5f2d1150424594d1af2978755799d31d554621129683a35b88236dfcd950e3ef7ecf2c328c4a9e09e1dd9dc83d77b2f904d6d50bfa67f5a3357c675efd3225a5d2cf2a6bb423ddcfcd8d69d32777a8418e986852ca318af4a1fb328aef62538d803a663279be59c3c1f529721d71b7b582227a94424e0b7300c2e5ec064d4d24ee521c6a1885a5039966f3f4f5ca2ad93cc123a77e2a782cbaa48073987e46032f47a4d0cb8734bb5d66654d498fa312c570b1df8ff989bcad91eee6f620f30d33568bbe33216ed83725139e9f74c57e936a6021e0c88f86c5150975597e2c2590beadea2a315bb53f0c58aa0dc2cb58223d7708b696de037b112a3b3cf9f5b235458957e20ad0e7cad097aab6d7fcebf0fffeaff6e50aa40064d750a2bd0281e630dc678b74d65d99714a0f248651b574c0cfd5b5d7a06d898e83279c7f8318553249610ae50111f6a95775f359a02f54e2f48524c72012867efa273599e338590297001df2df3bddef5075e028df52c65de1f4934e4fd012afaf5bca823aa3521e1262fade05bf61ff26e7a562c623720187a22c577bf68cdb1b8339705138bf57273d14cb03cb121340345f0c0aadb6df4a9d4bbd380a2a9e83db1b6d21e1ab2f990e3df1fddc31190b3af2d480239eb5d0d2d90c2ea807aff3f5a9b699ccae04076e0ce81d6e9127acdc3b41b737a32de8357b7b3881ca36b47c9a6864d16021aed66c7f6f3fa3e6f2d881cc285d8f9044e7a789d3d3a5c48d39cde7198dad3691510251e9a25598ca368e3f0ecdecff39227d8e6cfeb898302099037feb394ce66de2c4a1732e90983d3b048eefa46a43cebab4a36efc2a6dec822ae584a5dc7334e02406872bdd012fdf8bad77ddc49eaccdd62ac1ae786369e7c82cd8b7a634e0bb896dd8007b9bbe721d49e6d11710a510796fce0d19231718c334297082ccbc1823fb6375c9c5d217ea7798f14e0f55327e70fd47ef984cb942ad149a790b8354884042ce462a6435f36842325ed4fd328bf26862b695e36370fc47abe20f31da6c11b97c9b8c0bf95fe2ada2668dc2e93afc401780de6ee0348c6ffbdc726e98040020cd11c18ba1aa3f6209f0a02808e004c6089eda0a4c32c9128970db57913ecaefabd81c34d9ef02d009508f57aca2ac1c443a1c2bbcac278d8c6bf6fe2cbf5c253186855d55fe4feaf7577340ef74c01821a75f0e0926216012d4906d8f9bb2ac5f525c1207f58e74e32cb9ded85840f4779cbff04d25ffb2fbbe9ac034838dfed334a7c91f2b85e172e87b885dc567f4abe55c52840537ccb0d84c501952808c08b7ecf4521cee222400a8b657a3e655efdf2cbb02aaf535bc8174088a08fc39d93aa3b9bdc149e0fed44fd9298768801fdeb8defef4e3fbd35d219798c953b19ff13a81a0efb313699323fdd51bc3aaa5e18fcd702ea49b710362e2d71438ad78929ccf73ac33b09dd2e509783d0677f96164704310c01ad8aeba2db2e978592862ec95159910c96500938a2b297acea0d789a3d7e8088580ab1640ecfe6a28d8790de35466cb224cbd5cee65257dfbb2567e1f63ed7714bd44bf7b7f8276d807ab207d01480f799a25c03e4eab186c83fcd1a7ba3673b4c3494c7e13c8ec54da7a896bc3930de888c0f974d7fb1f692c7727a3c55fd8bd1bbc76d8e84e7a019231483687803a9a4033116c9eeb82c8f2cb912be7b2010eadd488fa1f8266114fefd6702bf18ee66e27627f327e748da76d85a61afeafa4e5c8824f6c409318bb812ce6f28ba01e8747f778fdada02d213cba64393236c915e9c93d7ada8154540bd68b9fbd2dbcbee6120f5b4b98c1d3433b47c395d7de96bac448174aa2ea11fd82bf14f6b1855de95d00b2e7781ffbb00dc3d7a0b039895bef468d2ff0c4b6f52f81bfd6bbce0381bec79d50f0966d6209b140ebf6dd27675498b4eeef25849673e1050c71f0a6f252c838ef83413202081df8aedbd5325f86b3c33724606d4d7d118c98fc1e9908d5fc4cb5379e2195703a545d4c480b5f28b1f0e8f298a39d020323d85c6628e58c070c03d25ab9df48e13faa8987c3235a6e4df22b95872cef715be7c18b2c433cf15555138f0652503ed8d87f39cbba5b941aa7ff05db6f0dd19772d0eb9ba2064f3691ef16de4f3434b141f0059b39f11ca56753dafc0bdbe973c245c65f4e6820fc850b56c9a1ca12886e429316818ce443497bc2fd2bad2578c86c3d6661f4d1b56ff89c319e49260e2c6960804438e1a09aea14d92b696c08aff3ee71feff67d1c79a22aa67b4012560c663be8947dd87ac11fd774535b4f82048a268f86be1d7af13d17503ca363d7427ddad9f1eb71d9625ed8d56dc3f3aaf88de6ea2b57e7d8237ffeb4fcc11b18eef95024b20f59f97cedb482920cd846a0e10f3b03ea4d3f8aaf4461053d961a013d9e4d44ea4149a7ca28ccd32ff6d9c7167fe1103a9f904ad9c8cf3f9fb98e8652994a69fde244b0aca3bc1a451da7e88bdbbe2c362c7a2195ac50b18f4ad77a607b16677b70b4ba7f844965523a0fd5f7764d4ae20ea8fd298170daaf9900ddcafbf92fd7de9d64d8958920205e27ac3f353384f8d28b35d69b5f17d173cd835f53b2cde51470c178a22a913914f7b36a00d76c0e1f7791762b8eee49f4ecf5c11d27c1cad42e40a92a9fd90e1b373f4946d2be74ee371f829675ac5762e78194dc954a5691ef7a3a9dddc3bc99dc67411a6b99a2324158d378312324fd7972a7284f08962638366b73d07d7a4d48512c609930c86e7b3e9aad4eb667dd592502d5ed021683c1d5aad4a3dbe8732f877ba9dfe1abd0158d46d92166c0d435de1a7b8fbf76588fa6e75f5f7e2151e1cb164e48ca14f6f6bd72b1b6b1a23754dc9f2f5653b6daea7820c3e4b232fb1c3438269c430a32d1e868a5b318832a3979661d4865e05dbbfd804ffb11cdd15dc0f07828163922a781fe32ec8cb47c1304128bd17522497bc8f82e2d438f8ceed4bd9637180e9d7c628021f1fc4b8cb9176a978cfe361998d1fc241b527f637a24153fd7c0c75f8bbe708b132352a907a71e8d93179f79bfd7f2a74b3d1f3f061d6443c6577f063328c7419856f70619c5bc10487545d070815830a43fb0566b07c5a483eea8a684bfe57d3d265c68fa750f90b3cfa1e7fed32f8f5034edd4023853f343219fccc4c4e9de7ea2e06535166d83fc5f6c47b3f07aa397499c711695b90a9fd355e479b7df266b2aa1d1103f380ba8a470095e896083dce49b210bbb5b6541fcf684a9a2032fd3d2a7762fc0c6c45b471684a11138afa1588247bf1686bf3ed8d354ceb55a9c316622d25ba4c511859b3aebebdebd2d568dfd15104f611aeb3507b5d602375e9daeb5549f8b14a545066c92f79151862bf964fcff1411fb54154dad084e9a4faf229c9e2d24fc5ba417932fcd53219a22e6ec53b040db7922869691685e1d122c7b4c13b9e691bd3dd906649c8c79b5a24bca6237b60406319bb9b66d7ffacf0096951b304e061f2d070235641c2ab0a275b7023ebf6d06d54ad7661c589fe30a2d2d43858c681f719b8e57614b3b8716309f6214a6a49f1af6a87f8f9773a5663efd26ed551f1aaa7c3681cf7fd2a22411054d9cb3dec61a74244ff9b98fd59d70628a0b0d24b45343b075aeebcc79b967e9586859719aebccd3a3fa8afda4750d5aa0cd0be2594fbf259e9c205c167331ac251af4117285a85512f204c07d6dd9dfe8bc65c8b20f7f3435e2b656730f40119a9e5c2fc30b9573649a92333fb325590b058c762d3e092f6362b4a3ea88dbc165e342dcb120ac26718ace76fa3c1c6bab9c9f876a8b698c9eb0d3989162a96e47b6be847bd1a710878b7d25de8bdd78db7e85c6d05a468ac458a5e63ff1bf8749ce52850f372de448a37100066906a1ed6ec18589ac0027f0af0ae511d430ce08e1600af737a8d4033c83abce74688406e5ac9b27537436924afaa6ade15302b1cc68f9fe58aeae67ac46b31f68a858b4400fe10bf13d6aef68a5d3fea2eb69c529e7c30a5951b151430ffdafc86168d84eb8413662de4a4e2fd7afbda7b55461ddaf8c5968e2e8f5042af2e88b0c5e968b58fdd09971ca74a35637c2f9c34e95710a9d730f3299636d8cca4ba23aa48de82c59f62f3b670df31170375ff343d35236e8b74ef371ec5f7b80039a153fbed0df285b670b0653d9e93a3e1b269c69f8d628e4aed17a3c4adf28a06828103519bed56f1bb631e6a5ffc9842c49fdb302deb8bfa3ba3f85be658c2eb7f5280b0f130457446bda28a4f901f987df808eaced2cc3e901831be23d6c645881b3c8200bff7456d70954c2188ff4e8732b684620fb0af7bdcd6364d9da045818558f5ad758a84f738bef5cb00e3df87f490cf5d227f2ddc74c5b6885f1f1d49271399c98bd2b0465c830085f698fde7948c2ecae3b7f298ce354dd3b1e2afcfc8b9c41459641a120d8a823341b4356eab521e110df2043c03912492889615215d207b5ba3e77e72d116dc9729a1a68f4c74bee0a09c04b5eeadeda6e190995f95d1c985242d3d8392cd4d02e1708551d2aeb0342187fb1ae3fd3a7714538860143eebbe3c627fdfe2752e654850b5d2b0a3669c9b0640a50d872209f6b87bbcbcc36dbcc6d198735895ff0b9d9df435ddb51b718fb1392db59a1b87d8b29b875d4f5b5b7af99ecd55da4d354297874a10c64b8518d3f618920466a5f5a360c85e64e34100fb33d589400444a84e439d21862f531eb0ca4e1de4a09859689fd6f550fc3b8f900702e26705a2c80588a7b42f4ac277602567d57cdc1bc3f5eb2e0ecbeeec1caafe3394a3dd8523d0217d3bcb66c760c4188fb5d820dab873fd969907fbd1bc8e10bd96506d82ed7cad1d0dc93a678b930f826a4879b5a6f74d8300a40fd1981da2595f30200cca79a4506465a54373df0e7a4c9b0a4f0dd48778e90636cbcaba1203fb72d1b66183156361dfdaeea684fbcca107c804669d6f5e8c5a5db6c97e5f1b39a89c542a95c125ec3d95e4f147e7ab900c1893aebc28368f792b19499e191e269ecc48905a9b21ca1a633940781130d820e695472937c2dd911aa36e46307f1de08de719f19bf664958c44064849f8576df8c4461cdb79cff39dffafa23ea7eb15eec375cd3fe2422da73799e0499de08885e061cafb0ca0d38c2bc6ed26e0563eaec456f69720cc8b9c2882fc637f025859d7a78590e1f1f5dc6374e6e3260502a3c8576e86f3c97a162bc62dde8bda1d3ea0e1c21f40559204edef00f458ed3a3f906aa434233bf07d589e97f2aed981935a7c467bdc3a0aec5f87d3d048dc0786d46f12843df04c0b52ed68f7c3c8b122f3b6f26549b03d07297c3b962078ea031637876b7ffe1184b53134244f18f137414bac450db982efab218cac48367b0347af85a50b1402d5416987c60b9d185677b8fa4e34468c26edb6b86b08b321d05f51f39c1181aa35b3923e51785518ee9e44b45b83d1f4292d21bdb51b81d5d8138a6b70fdc4c2ff8e15d655bcb857b967f68f8e517b3a95eb1e51b76a14cf6811d3fe2d78cefaa259a4c0e1ce192d56b5d0e3f00a4861e4c7f3a67f46b5b8a98e428520cbe5cd622ce30564d761284a24fd6fbb894c26d79db2ce97816264df0e50aa2872e7904180ca3d5bd2845d735f4010dff58717f5e8f2fef6dc89a0540cda1bc75ee43d511eb815e63d436cff6766f4fb9a38bc0a31d70c13157ebaae83b881d88f4616863bae00e72e67f75151fb922174a757ced101d8d92133f5354dd4fc734208cb82669112864af510b410c284c5f3766c9d0581190770950e904a453a8a3edf2b978d6fbd6ed6fff2a2c4668d1656aa342f3cbf6c19b68a291642e3400b7439e6ef1c19fcea87a01c4bd292ad25460149d35116ada194b100c4817b18d85299b3be893049408865b269b54069a1f72e0c80837f02004e37e5c781b32946b6590a4f3ad04e3180a7dfa04373603080db4f0d4712bee5177dc401bf1746fd86fb6c821c01000c050a09e718000121832802345a37d606db5f2aaa90aaf6c81d953f4a51d3aa26c82db3e9c664d6c1492745bf9f941c1f63551d2834fb8285ee51837f681a505df8def47e510a47b6021ef83f046c79bc18a7e8be81ad6015a2a23fb7fe81c905f2844332560ec5fe46a9ddf59ca1ff8d2403f3194c0100b690138adc63e479fe39c4168ac796137040478edcc53db1c979bece0fba78d62ea78e73f791dab69607035078c568c20737231c721fcffde8cb3a06e082281eb2f5535376579efd333aba823cb8749ab5439b39439ea99861e6476ed990c643659ace569c5f557ab224bfce28f0c51ab68cdda74523664fc448f05b43a3d5d56460d69316e7415c012cf76f32ed0d1518547402ac6ad00a7d21a9305a1450f6fff423af9264842fe860a8c1161380001b3c3c220c64fa0200aac76b36db5fbb85da81f5e41eee0e917910d757e4eee2cc6575a8dbbbf14f663f3b7cd06a4736005ace30cf8154463d34c64427628fbe47616b9a1ae9cd9079bfb13bb6176f997b918aef843cf02d91b0943536127e4645aac44d9bb77ce517d3b6791849ff03e8ad8a3258b4472a7029e83780aa911410d69d3d8ba9c0e2aa09e739b76fb06c0a9e492f54232a9d730ca019abf60d137739268415732c674d69172a612759bffb3d178cb06f95fc1884bddb8ac423d6232fbd9639f7c3308aa5353549ec2f9ae8ccb9f33c5e78800547938c35096834b685ecef8b95161a8e3fc4a7d54cb5705a5af0ec9df6f47cfb3333a69e8a4d1c6f6c38ec7dd93a5cd201fee9d3bb16cf78c52f8f4042f6bb64a926592b9992492be5806af107fed65e83a54946fe0648a12bcd323a63b39c014e6c2ac8ec21d01ec309d1e649385c3fa3eb0c12ae2d0625d0903981b5644210439e24f91f3eb556391cfd5f50d87804784354356733b260482f06a9e938ce31ba070593e66496906c591774395b88070c1d99e12996134c0b8180fb4f0072c0888efe18a9f6626063c70e67ef21c9becfcf7c168f863458eb3f55a4691aa514323a087528b6c1f493646b43f55915bbef678a0ddcb40a0987b4debcbcbfa773b4551a7c409bd256018bc00ffa363d8f41ee2522aa55002a5e6c5347189348e2644ca6d39cd76cc3e14df996cac9a5530ea7ce4cbdbd4049d5f066277a1d0b63b11d3a6145f3f7932621981d8e4fb46f29ebf3934c358bb4a7156dc250de3df7f5a3bc1b0e9ea8dff526db12f9ed1df40656b57451be39ff9eab0ed17e29635e7927485734be86993bb618d354315d42aecb45f04926317c92886746ccfeb8eafec4099988cb3ad3eea7cd3675462d2e5c5f5dd0be76f2e7eac7e9fc4646cc7f97d59529c883fdd1e5d3e74358c6b06c6517a84024df893940b3dca4c28f3044b69617fec9cdc2623a5f7d46ceb2876c79ea00af268b75caaebc581096b9181f095894abd794d4db827f0004300ca994df7147f8fb4acae257cbe1385e3beaa4062d1d269cbb75350aeb26fac36545b90f30b118fe469c8b07b9d86889bc142a0fc4998f4138f5d5b3a5c869adea00c998319ab2a41c67a56cc815a01acc199dfd4872ab4e102bc2225d29d8ad2ca29ba423c86d959f6ccd417274e89c0e45a40ebea02c7c0ac184eb0d36127c4ff744975f105b8daa2d137bac522e0cccdd45b6ae8a398d1230b875827ff8901a5b200f581f4576c7468379403f35dff3e5c5743d5e694b218b7252fe67ae3e926d48701748e1c64137fd3774042933b272854949949d6da7e48f0a1399efa0accd2efbec808f8f32e77fea27bbe295879d35c0905c6b2d61fdbb67751572a9b0fed38538cf17031bd979c16e3eeb1e1a67346c32f7bfa7723cd84cca3681e7aa8a1337a2716776394032a850c4d12bb8d30db89fc5839dcc6e0fb48c2c2d8b45103ab7fd6709caf924886e14be607404e5d3c47f1f6abb74a07d47dcdaff85cd179d038fb107e8046eddc4fc6d0087d83fc9d91f283fb41139d2eb95ba08d7ae7bd5f0e40413e13e1aa1e3cf627b9f856290aa09971683db59b98e9d6162c5fb10b5ca9f0091431d82ecc479d6984118596f637bc9ed8adc6aa92dfc3a35b6dd098c1fab3d55d411a121aaee6cffbacaa58e3fac01c62f8fe15f6b7e43a932eca6ca1bbf2dc10450d5ffb161b09d213b45f906dc33ce2f9f7203eb5ae8fe1522d01bd0f8e4237cefae5199c13c60f4d64173511f6d0fafebe9409fc5093d90431b1055998704135c46f8ecf89e70bd26d74fd2342a3d247da9bc736d5d23b6bac2686dac8ccc708d997b354fb1a443071eb023a4eb4bf9f353fb53569c9ac36bec37d0c22eedf21d650da69e08ce0633da9f65a9e6b644c924eb04aa147fba4e7925cc588275993421c56657e9aa91b2585e627f22b4d0882f62498752da62ca6c39ce61833de6077c20357e7f42d32b9fcf6f4b99c902ed45e76c0f3883f3fbfcee4a77de44a6c27bcd0cb9334d9906b83c485ba4754a9783f68f48109397abde4b9eb5b5b311376e207f1e0a5997455ed5c5f239a3df3826c343151bac3cd3cb8d82a225f792da7cc2b1321cbbcfd4d4fa0c03f9aa751597c08ae392326078ed9a29ac16f2d1cacbbbf255cbcc759798cc156923e6d48a0a835b2a4afb7c6a5e6b9f16dc506dcfec5be4832972ffab3f44be86e799c5337a7d75c27d411269c051843989ee6d532f742283fd77d3a8f4635766a5f33937af9092496bd1ac04a873fcfb19dc512e27ece8008a0e015dcfb3e1db92fbedc9aace90c925cb816060ba9d679d82a72e880a2533214f0ed78343eb5113096f9e385f7a82d29786871cf8b9b4dda5a6e6c2c443da95cfbe5b09dad2acf4c2daeffa28c1957dbe1363b4dbd32415e4037109d3ff2b55c0f59996b6089866ffeb2c83bbec4e66a6ed43f74d8e353c1ac4d2848c91cca62960c888641aa52dd3788c619d2d7c271df91bf4595731fa0c6e469c082b2024e7068e39786e440d3c26d6082621242330fe0550e7b66ea258a3d5748fb81f33a570be44e1b23e91b57fc57d701f0f3e9ad07eb4898136e3ce20999a51a666fe280464c2f5bb847c59bb9f3d088cfd0acd6354102878d9bf457f89624da5f89efd29565f8e35ef9e3cf2b8e8a33a949c6f9656578e711195d6efa817cc740b7a11e2c32e009223702b48dc82bddf3b6de66bc276daf16b05c217c2fd1e8db6ea31926d3d35261b412ca3563ee1bbd1d8f474ebd8752a6c7b82010455bccf7e2d1d0af56c64887d9d4ac415c943b135e242ca5404a35a66123eca404cb4a71044dbb17241a3fbedb8dfb8b912cf6ea3d69b27b87e28b73254134b25687f0ae8c952ebc3458a1a77b4fb821945ce13ae497b9a50f72a65e0cf56f5041c3d9c8a9dbff8d0fcfce0d3d38e81a5d98da14832c6100eb1db9fe7fadf7b8cca83b33294c88412fec4d1db89fee80d37a5439554761e364b5a48d231c8b1a602b57bff638f6d31887804bf9eb99cbd3d50356884ad46a006a4f03b9af135d9655c3e807ff69dd31ff605c1a9a2cf60aac9fb4e048831078c2500477b668b1762477a49519fe85297f4e760a7440daf5e6de175ed8e61bc54715e5371207fa4fe6be88928ad0cc7734a871d27dc8adfbbffb08b3c508c44f6e2867a18db2a0cebbc377388638a6f01686dfeaca251308c03e9df9f30a4c474568bff63371f6119f3a4e6670c0b366cb728d173fa17d7b8ca2cc3e8a9466c469bc1162d5a8fdea82e03eef1e10551723ad160b45667fc111e63e94744f0b796028326578f4295d38517087a40ae4782541cd3a71cf47c610277b57d8e35b23b7e2ae15ed9ea0ccf38a42d92a5349d6831a72f282c7caaaae604276518308bd7abb8c5f6503b862f2e6eae1958df4e108a4ef2f31b29fea7c6e68ea4f0069857c70b0ba6d2bf019ebf065d36f85789d7f7b0d1a09c38eb2941f35a66268160c229cf37e09e5fab13ca0414b143a8cf8e06910fa4bda86ede9fba950fab8a1a7f980e7ae7aafa2b30d4c513c824a817823b217bf5aef1748e848bd65f52a3cffc53f56835fd810dd6afdf99cb3061c4177b9cb366757049367c8b62e4650cb49dd5f3d03bcf56b835ffa646fff665975333edd9da177b79ed06b7fa4d213880e9bfdcb0388b073add75775f1891abf25ec1a3387affe71b96bd9cc3e0b4c185dbd6fbcd4445f92163eab8f8d4c0f5575d30074b25830c3b3c596ae831295db3d02727747dd4b589f07508153b2adb59120dd1fc23147a82c8d3028f7171729405cff03573167bc8f6b7e1e4c95eff5a66e7c4d1ac1fefa24b70d42ecb7a223f6a024953102e252259f991876e6c882d8c9fa464748785bda1d2259bb6106253f9e49f5052b36ce691cb5420cbdb68aa9f95923a5d92c74863b90617f3e498f21b66b8a02f94011fb0be587a65d75a6395c0b7317a3bcd0696dda1fae2c9d348c0bbcd33ea997d0e3a2f2812ba17f508f943e70323212a7e7e5ed0425b3b0f4bfe43fc2f4fb72f5f9e8c034fdd72e59f9260525f6f6bd36ede7fa72dad99f06fff8fde344644d702e3c9cabf07583636f39336dc1aa5edff3bfe1bcd4895c72b877488bc908bd0e2566c4874a17b22adc6380f813145787cb6ad7338c1f36dc68c096fb7aaf393d25f7c00dd2e47cd23611e14bdc27ee0449d54166d972dbe8c20561e1e3e869d442a0a0ca6e882ea851b1f70f4455273a3ef18b7a34350992b3a7f467c8a20936c99399a0ba62fd34e06af4221847331d468b06f5e511ee536d5f44865962cf757a1b8d070ca0f9230a6724092f2f987a54210ca27823d791914f3a04f81028020024ce5bea36ffe7b117b049705f22afd2e23bd625418103b79858240c6a94001e695117e9156173c157cebab293f3a3c547eace7d1c38f72b361f8d1a861c94faba9320c0c948071afa9a474f8595070479863bff80404a772430febb5685d09f52c3a40ba7bd6d3f9203e7daf49a54e0b9be1b9e1634ac5de55760a78026b38addd10ff60bb8aeed125cb1c080b520a0bd2ce62647875f62f658bb4916f8e09c2c3c889766aa39de62b2f15c0156e87d67a012b5570370842fc5b401271cf40f0fb756904e44be9043e6ee1e43f14ed313dcdd7e327e05eabac5f644090d225ef564a5a290fab16194c3b10f22cba5b6f59c39d6aa9b230614a05e17dc53082c5a3982abdca1e75d3c488962043ba2ae94eb67332edcfb11aa5baefee8ad655aa87297ebdf01af6bd41e184beedf7194bef3534fc0f338d8b6b7010fe80c3c43156d240b875f346bdd48c6a22875cbc3eb8e712bce105fbfba17aa78464c3ec7febea9511103bf49c9c37fcefba8efd6350e5de02bcdf1ccdedd1387c8085ae67c0e27392cd5747dde939745775037d1319b52b5be8841e5e7dbd4852c4930ceab4cb99477afdfbc83beb51ca25ebb76e8b109d08232fc87804b121c543c830322293e6b092c084fa13e92f0ca2ac86dfd58f3e4efe75b83ed323f07ade320913d61638e5c65562fc4891c1cc30eb32b7bc6cbf093d44681919b5d6058746a1a9bca2013040c7b4866946205537179d5d8aa565fc4ccbcc6f7f3df96a09057b963fe47dab0390991bec0a0c2ccff95e18f9ce4b0a694df879ee953da0e92ae5ba63d81479bddb9f7cc19746c037a1d17ab5003914bcc67c66384a39405d3ed3b57b2cc86914fa949c2874f572c447ce05564660ecf8166875d7fe62f0687f4b94bc12f89890a8ca7b81b6307a6c564d2a5a7746bb2eb3f080ad3fe1114c112e3066e9272d12c14cf1b771564c36bc343c270ea4b373c6b79a4a966eb0b5de52d1fc3d186c46ddfe539bfd5fe83b13ee88696a40f1c3903f8b4b03d14e15c4092c92e203b987a8a5ebe85c3a82bd1c994108d11ae99c1c0cae701977ffa11545a67cd9809fa7cd0f5b7792c385873f8c55081ab252fa752b8500b840d7f410d287b9098f8659e34e4ddfcf470999e24ec97fe29a1cc4d3ed55897464866e9c775e08b99fc7108e703c042a251dba4dd56d2fc49ee6b1fd954d4ca66cbaaa6591c738c81f5c52017be6fb7266811d2b90cada3ae135ac4332f4731af6040d6ede06c31f2c2db07a9dd3a1a2fed9219dd52b920a1dc076fda4839cf6b0d5778fb2907a06edc35bcacd22a6c0ab90c7f9f96f8b64c94b278c344239f2500e6b324ef09ae4ab2a77db90ea2205e53d299c777c70d5c3a2d68f8a6e8c58ca1985657766106d3218e9836c0e43f67ceef5383afb8733a61871b2679599a637131648b1d3ff9565f016452efad7987cd568517bafd200073a10e2d3d156313f791ff4769932bfefd6170426b1a12f8117cb9cf537c58ac2a6b1d52b16920954bb30e5e5f99dd51046761fe069faa5a22d05b0aad4e3b1bc4b04c69c747671342125a57a25a43924801f96abf29aea0cee027812d0144a04236e888ac29f207f85e3fb5dff6e172eceb7d94d53ab0659bba376ca245ba4b02e92871b23535ae1346a039c898f637272a87a9459117457bdc5aeff87a4d57e16139655073cebfbd4fb71182cc9acb39ed04a264ffbf3685c5ca43d3ecad9019238856cc73d893c5ed2bef0f73c55666238ebfd9f4911c7046d9a7e7961c463141c47cec2437151197baf9687c158fa6d126511c0161f977e12bd442dd4da8a6ae79617d16c415b825bdc56a0c21928916b107005a47b73af3416a407be74a06983ff8ea9fc1415aaff4cb2922af012e7e8b390de4e323d1e794881c5144c73a949e2098469fbd75ab4437f62ddaeb0cd231ad72b8d51c4d06289bc8b0dac1ca02e4e6b3e77aab896c8191ed7f33e20f558ed49ce45f27b58a1aa4df6114ea5440d85880ad0325d5d836dcdd509e35a36b3e8f0d3092082e8173142896bc7c8a69678f4dff1641d3942e76642bf7ba4a81756e3953773517b7c65b2e1c7001a055e39f962b78bba3e1fb3707d95da73cc8b09851822564660ecf87caf5cac0d9dd968384d8be396f0637525957b47bba587367f15e1f92283a3e8b61bc1984565d760886f440e918587b06b395f42031afc20fdf52d381caa058f105fc710536d2c9b3d7ab73ff5b6e06df6b87d943323b6df7370dd5de6ec027541d8275c6e5bdfd145e494b67afd5945df6d51beee5e3c082f632e7cec1f8720a91dbca148c0049f93806c035a2c24b82619253942ffadf38054ea82a65d779b328f67524206803be1f7c3ea0a9aac08b4cce8a3d8f6fba87cfc056a4950abbc97127b2fb6cd1c2da1254b9c982f3e58356c966854241672730706b316b91763960d80011d5f697e47085da11e50fbe5da3faefeda203fe1dc7b8a79199a11992041c2c703308b82f3bcb61bf8deed4073dedca6ed124bf7d674a7c50e72ad72a0d534910f7604f41f23268e8356d013abe9396358db2c72783d51a82de512b30796fdb157939a016813b8b3252c163f55302c00bd57d4b2f4c2f6ac9639101baa3af0498974b396a30a08c036c7d8101d20627e7a10dece6f94ca0d4532581e064dd0e47bbb26cfde84eb08bf19c243ee0b42e1af4fe2ea8e94a6ca10835b053caf21df6f584595b540116430d0ec88e64909f298dc01ad38be5c6a3703903527afd01502459fadd4bc13f379a1cc3997f9bd2d42a2b6722058580ef781a2ec577c9e13fab0c3723ffc4e6d6d5d4066da01dd7025aa253643674756eb04939809692a4910f63ebd2c2d472f17f7009562e7f5c1fcfd095167ea4decb5aa75ae273ab2cee0121dea23753687600a778207c000fec2db5c2dbf873f791084095ecd3068bbbfa011106b70818afa71d9e48e582700285ca3c735a102f925e93ce8ff03d1f1675e247015cb716fa8aa7e19febaf170290782c172665cd498b81265459c9e3fd5e17afa803231436e929f8f5515624fc6acb3c440cdff13e69175b671ebd8a8c09caaa06f143a4b663ff8c4fcf4306d83f507c11c331fc0198c52a94d1377720d656c1dbb9a3fa4d819247dce64da40b368e34425337f97fd504a93c4c22508ce85a3603a312ecb5d70d0912a87b14ca767ff27e1add0aad167f1c1e4bfde585edec68046944b77377ae272527dbb95f4a115973eaf674fc3242d2f29d9e18f594db8961e9356654fe91ec871b352be18d068b4608261f296328a794b76f3eb2d6e19836dcc8cf67c70860245f632df128359b0f8128646a3f2630adf9827f087f338cbb58b604a892034833a3eddd8f9324050d374fc5420c20f24ec32a9d4ff4657ce09dce9bff2549b03fa351db1efdd525e9a1ba3e1847f42aceb77cf353cde6bb23ec6b307e226c6d7b188d70e2f309f19e822b22b41944fa4cf8a46c04aae4e24ba14e5a6ac134bfd8fc560ab54a54d6ca3c262918949c354a27d678b42400cf61ecd59816c5a16940c32773ea3e1a74c74751685abe90018208f960011e0548aaa7d1ba08a075a53f90a98c0210afcc7a165e980f7f4ab0140448a3ad2fdcfa690f117dfcf5601993eaecb83627d7788d1d9d4423cbca4fa4331891174590e056d38768984d48ed51d84786b4edd70c05bf3b3ffc2cc206931b47822a0592555c77b7094c7e1c7272567c1a08527dd2092370201ae50f28008d72dfd8b85a8956759d0a4c07b28bbf6de3028fcd0e8c1460da060b26c92db043bbc3231826ba33d032b466f4c39fe31cdeda3a62f54419c2fc72d48a3a45a34ef8ec8bb37b0de6b0d6be9a4726422784e0a7dfba6eab04e134cdd683c686dfd33c88b0c32ef2b2b7bf6ba5af0c3efbefce5571b411d526e0f6fddc0a3b871cf3d759dcec234de25148fc490f296309dcda5847980a7fcd7b02730f620e520370f9f188ff1882d5ab8ba8b0a75a091a61af7d8e5c1a66fa1926fc40cbcd13c01b9f68c51bd6ec8b36533f2098318932c06b599d82157daad3508bbb382d537ad0e21c74b66ee0e4358d3f15c47157ebab7a015b9f1bcefc9730dd5ed1f655b688adab070b6787948962bb20f8702889d0f7bf2638655344d259816c94bd3035c92a9cdbd602a05277e52df5daa925643e41f52c7a66f142761cecd63af75ebbb7a197a702d028859422010075c9af6ef9e81f58deeaf1a9a275793b19ed7de65442e53873e330cd0d5c5a1281f0302b62c0b2d6f969d927343d42e3a756bfdeaa8e1efaf16d4ff11c7f03769dd07e1989e91b7f71755347e253737bc85f1345d42200d83b3fd40eec348da9326aadcb821b3e792d1a149c6cdbc4e105fb027f10950f86f5ecbfad9691d566c1995c5034933d047481be4766079e613569f32972adb096e596149ad0ff94054c252d7cc8b19735a725c12575205ed49e473d2f6e5857f2a5522ffcb19c3f53815d0877ae09bad26fbc21a0183a50928a9c3e7f243ac0e285ff390ff91cc0541c48069a8386f550c520226774a5a641fde799649289e1ebac82dbf1ad9dd5e01efa92722392e2d16b19e26c397f899744d166114cea6205fcd78f18e72fd471951b4fcf8cfcf1484657ae2fa206ae4caf66fea6b7678e580d5ade484f9d960a525cadddb0051cba5aa4d01b382a1c29384be3844c2c290982ec8bda3108dc4172d6b8e7801197ea16e2ad5a60ecdafa7fcaac34d6268fe2d4cc40d293be528f0127e680285858ef084d2c8f6ee664ed4bd36e3475b1add44fc2b5ff9daa83fadcb4db75c5dd8ed71d9cea4ae0ab9560f06c922b0524bba525a69ec670d8dbd58cc01e225cfedb715c9a828a307c5a111cd313d3a409510a3326ab9411e887f6f3a0191a3dec9c60a2d2b0837649c933537b8c4f80e1db96d1088ee5250d68d51613ed02018e8f227581afe93f4d296bd5edd670be647c5d91f83f100e33ac3df722b091a525884b267676fcbb714e6471a2ae3cb8d123ba18007b5b4f9cd080872fd04f3d92c599a4b0f679388cb0a6bde9872262c3f12b3a3d37f7369d428af7cd7d75b4f4e4b6e870f80d423c9daa46bdd98381b4528bea86297c791e921f544aabe5118ab17b46005d3ff2322cae1073dd1b5aec80808094b4064f7df518ebaf17a93e4c3d2356032bc50f027e54c8ab3753967fe6506ec525dc627d6bd818fb5def80a6f6608c367d2089ad47525fd2341e8d4f99db38e5660b32761483a16e37bfba5a6fc8decf8d9affb08728490e4d152918e63a967139bc9bdfbc0b260c6b00280436e28fe6a7ac7f12fc16c73675fb3900cf3d59d97ebdaba6ca2f2822cc22d343252f75598b44f17e5371700996caf4a85f66dc30bdd1dcea14cc4a30921b8335b487275284561be2651836628e2fc7b3e19da97f58d82255c925a637ce2c6737b546ac9c1f7ab3c5ff5ef9ac4aa6ce4539214d61ea80c4f7634d6a048bb0798488a292579f4bc068ab0a865ad476c2440d31f853febf8326225fb48d0025483d595e05301712e9902a86c0daad147ed0da3267fe87d3d5f6afffdd7bf8f52470b96c81065bc0f82ecaf55b44e14049581aed7a3a7ae1915221da571e21e944fd917da6cdeb669c655f45289c09021903dbe240e563836ccba8a6862bd93e090eb77c79c960c7fd21afcd60ce4f82e1c11492e5ef9dadae2f198220cf24a2541acf0cb1c4d5770ee6643b4e622b9cd38cd0add5a13c8aa82b40a6467a0fdeba33018f22973eabb607f853c5d4d6603f492fcb6203543d561cee94b08bb42e11f66d7ab7ebf7523670858a3413b4812d02becc6e3d6c44f97b649834197a116a10f9c9c6439de1f51ec66032cf866d84875ed6ea18ac5dba1aeadf8581604b37223bb5ae4a171252b00aa5260aa7f0d07d115b27cb3842787955b2600cf01175f7ed9e0c35c294a6c609cff85cfadb5a63b7a000cf8daa926fabc2fdbc138d7f199e5f84707e740e7009d28555fd11d142a69cec30428a5c609b8ad92e4fae33f41d558b70af18b986952e1cf75c8837f499441c55fed04ef6f1d44a6a5ae59d405e4fa57b741b65c620cf2e6270c67ae1c774d06aa6269420aeb77ebd70ab2d47bb52165e6ed6afd33713c2bd9b4d61106efb45dfa737f1422a39484734b467e061a73457f7ac00d04a2e36b6de0c912b5f76c2e3e25f950551e87f1bc5900f8d8efa05c43641a285da60a05422f2c44983b233cfba798e95ab037351b1cad51e0192b9c781d39ae4051bd3b27ce69e230fdd4ffc5f9adb9509602ecfb0f0afb5fe3f86d4341871fdd00df888564da1ba50f9ef446eb1f8b7fedb154ff6cf736074634ea44f734f768b03be20aeb834a2060cbf4abd197eb5317068a85c7c8a6b00261b4457d30bec24c151e90e9e0d32bd70595429b9cee97c189980ef795eaa041eec1279720321433100ce06576fdfcca7111fa218235515a5765b1ace8c10fd333d476ef27c718fdfc6b0cf03b4e8c2ee725bf9c88ac348b1489e7764ff27381a1e27b256a7dd79a4e928aee44998bfd980c1e7f7b3404a5da971064d52e8c8dcfc60fd19e5023ab6c8fc9604799e6ce99b83a320838e3dbff0186ae1416f334e678cbff1efb9f5fe527a25f1399ff1492ee73f843b72eea4700b5279e9008d35f649ae644e4813d1e70a7a7b762d9e3c8c65ab734be57801c3e4219a18ea1cecf216ece593064346a59e535f4f5feca64ac53081afd71e23212039987fd4d919d3f38cbfe459912d2a438b7e743468b8cf9c500c68b2699c317ca94fd092922fb90a2d603e3ec1e5d5bc6e8b240884fd393ec3eb8d45e9bb3eb09ee6e9f5b43913710f8663973901e9127d999b45ffbba58c1e16de4801d506af8270ac5768b32bf7285a4d000ebc99c2cd74f759f550ebf634718df6304bba83ded3aa1d4675520421d67e89e6a08e066ff48db1c6403f0b9ffcfeddb4313120c7bdcea3e3a0c5ce20ea93d659ed433ee9fa36c691c141e7a52b6b740941c06d235872574eaf62f560fcc90b4c58bc1b66bb6cd77c5b04a26fa1b8a63df721b074b4714440044a37d9c36286dba0a454c97025d53cde49b00f3df907b40b7268662522403e63ecf0097225ed9226a865c2ba14c86cc80c2da52b0133943bb0a98303b12a41e71459cd7036d3fc25661c47650c5f9fe887634d86b85915e26ea627c729195523c8a0d040341efd28f28ce3174175143c8de70ccbf6bcc2dbbab918e048cd3d72d56e8e9d5003b629df8e9678194ba5df1dd8e524fb569e145fadb345a51b54b9f151a8d5a927b353e3ce6699b76cef8f2414bfed30224ee291d175425848f06ca44d0f3c7abc732befc71dd2d87f7f6c1e81586df66b2d965b45862d3cb3210b43501d615d6cd264ceec123fbd84096c0f68930c810683d2136faebf9d36d7a01cc64ca4dcb7285794eaaebec57ecf2538db311e217190a2b014aa2dcdb47d2726cba359fda39298469fab2e93077616a115cfc8ede33f8f64686ec6ba7cdcde39ec14a0108ccc89723bf2c417be27e0253061da7821839c790a92f97954308537671af9ef3371c056efeec325ab2bc4095d0f7847c5616a8a9462ef7f7f67168304e314dc94277bf8bc44725bb99478eb9fb799e67de28a03d588af94599681c6c3db96558f185c4264e2b915b10b0f2d48295b1a3d5765476b58eaf666891769a80ca58739d4ef873583ea017466cae6b4e4833b1366f6c63dcdc89d5bc82bd1fd25b07324fbab2c023b422d0721006bcf08cd19a987e96ffe2fe68f7c829d115d6207b9f2cde387572df30e22f39e34deca569848a3c41de09184620c4494abc074040ca6b789eece7074eed140aca5a548c484d868b6da64b07c15ff657c882f916027014ceade441ea77886ea365c454514ddf897e093fb34f3ebbd251efb4810f7e5a47925534aa086ba128badd35902e49190af98abcdc1b61ee3d7e2e93865f3f370ec39482bf4e9cbb929a13d58b74cad9ecb101f2c9ca493d2c3932912f4a417ff5d4f779b0b1e6b2aecd53efd5f445bf3423f0b2c629a378c2d67ad2cdd729ee84853ee372cf2b6f1eb04645389acbf179363affe6b7ee3369e5e62e4e5b5f465d55e61e19c91b77715413a50cfb4ae66e525f026f39855f8044120ef55f7b0c206ab25a81dfd091cae91e0aeef531be93527fa45a2cbf422053b3765684379a23c031c48eeb473972149b2a53cf1f4202f4c6d49e78bfa9de52cf5578de04d0f72762a71de1b74270ce168833d56e17fefa16428955324011b4d7de2f9bb12339b8998ec48c1d74364326c3fb8a2324a7ae7d9f2b3599e2b75c5d4f5aec1c4140e2666065b599760f1efc6a3ce6e8406e0ac128b3a1b12c19874681a5e3085252abebd5bb92dfed0564973e68a6616f66dd7651789d36fff0f1b47f38541c6f86cc721832fce67bc6a734664e4154b6c7b9a68d89aefb6be858d19f5c495e2e4131dc8e4edd50973f5eafc8fe5f71dd0bcb28732d3bc3db297388712c56b65f9b8e9ef47fe292e9d9ca87ae8abab7cc69be293b2c5a248e87424a72dce92c8c6510064763a9c10ed7090a907ac47214a0dcf999c931b794b9f56c0e2de59d1e67e4ab2ddc471366d9e78b0519e50194e4a91f8714b3efe48ed8bf35b19613cf89762bb7b4cf91469b1277754e144a39d59ff76e92e33d7f77be846e44cbaa4a3d69150dac7b595dcaf5fc14801f7a36c77efc6d2819f1ac492b4b252e778ed4624d9d22977fd277addb25261aa65ade1f4a5ca7b64dcfe8475116334aee619d51c9d60d173ddaa32cb53a12063cd5fa36cec9f3fd617e5aee8f6296c9766e95a034c45b29d936f36d64a1504b02b8a3603ab656d8e1255631fdbbccca11224fdeee2452117bcd5bf7b2188dd4d3d0fdef8f0d899ac24ab9d43ea6440c1916846318f9224b34734cbd49fc8159b31a20964e7af96960d79fc3d0010313aeb17ae28574bdcb448bc3ccfa2f8b16fb0edf9a5e76776ecdabd1142cb55bf38836cf23636ecf7671073a65505cb87cb568fb29f8657e37213a0c65d69256717ebe20be7257da47267e7da74a28d68c4f01e7d07f82aa7f2a1998e68739ca80f5cc6374995a607525466dc4d100537788cc342c439e0973ddeee9d7c4c403749c821d5f081968b0cb777b83e3bbd1834e4d89e9f3680b8b19a8493434890f85683bc403c6565ec04e9a27936e64e89f9d1dd2c7550de4c23817cc22a1a6b1e95566965371e02708b8a5e13a86f6973f2567ea5eded9e94d0ceeec05b4073d1158a54645c6ef92f442f17183ffc14e278abbd19141e98061be7c2ccdb5478602496cb0bfeb43155aac31e06eb3ed7fd5f1bb79e26a6ef4611cf9c62abc9aaad200c696231c07a92ec98daeeeaf2338d68f6077b338d2313920d41a137f63e16a587622520294731741eef343f515539ecc978912489dccf541a32017b0942666ee39ccf128e92138867c375343f136507e37b0fc2fe84aa5e2121ca4087b2a9834d7920d00591827717c56485a89ba7e640dbb98c76f149bdd1503d8389b909a18b5ff3ccfe7f35c9f210f9a549491f8f91696bd4fbdd5f7e7197128cdf957f805739d080c69331e3520b5423edc2e3a7f24f73f2a9424f2327be03113ddb2cbcc6635b4fb33cdf6ba58b712425798cae9bf6eb072a9e0afcfd5abb6bd44057fb6e5177cfd5e80150385da3f28a47fad4e30a120f48dd5e3b553f9b1a2600626f9bb42c5aac7423ece130adc1615853553d4d4f077950249460d59f1634350411a3ad00a72ef63b43dfaaa02d213de9064a045dab9270bce65284867dadb84bbc7179f9f155b2db5ca1be868e4be18e0828dc4e0ddb97ea664b8980029b423f6674ba7bbca201ede016d2a6009bfa229ff7714178f1ef1f5d44c04bfe80e39d4cd899b87557b212ece0c52812cacf82a50319bf0a6288c1c723d2263f83fd5c35dea44136eed8c27d70f7d5296851f27e80f9561c95d911b1a511e3f07c830a6954fe10182e457580d9f4309b48b118070869f21abbf430d9756ef01229f78077a7103af13820df4e610d44b434710804b98399c69a67d462727e4b3b35b6adb36a0188921a4ae176c607b000127d127e90c14b83b65ab62f4d3e0ba9bda16e382a532fca486192c95c83997042048194f386a90041d5276ac46e0287edce674b9618751e76386f9795dcf02b6f4800624a4b30441651e10561d5ceb58f1e43cf638ede2cdc63c61edc1433b0383abd3facdab57e1e57e51cc8e0a127032de1c2c34d64ffaebc00e09a5e99a7933c3513997838c5c0f57ee834d295dc70d76612dfb321c1cef78dcf5ce56a751fde1c560e79df508aa5c87fc43816728c1c291fd7467554683d8830d865a50b2cc7fbaaf72456118d7b45c296755f6c7f97130cb903680e812ba15f1bc526be46095bc76794a19f97b355545916cac5b9e028ce5737aa2965380d02c574b55065ac83fcf1ba217f361054f0737ce1c6c254ba86fbfcc8a8ae3673ac1a9c61e1204046a1760197d8c35b12196a63f08a99ee3f77a3a4e470b3c712e6006801535329e5a557f1734af974351508e87066cec60cd9308ff71faa40d618d836ac58712ac55b2336b0cf4be0e47bbce3d80596146098107c4fd993a1f7b830c7a9d8df5628640e06d12c679d11b050cbde0b992966a507bc7f4c3194d45067943ac28f0f996a7891c8b0b646ab3a3e3ddd645f709bf81b40030d05dc40114652f72c8a9401710181340986fb45de9b665186d35c6a22937dbfbadd364990b0240af142135dfec81cf92a342a57d18ef8fdb1530010000119050d08000c1487800c0f388959b5b464db23217659f1a60e74b5a51ae25fda0cd1da8823e692d0f017a2532746c20b4efccd62cce528863d2e64326680a260757574d2b83a4a903fe6e44beb6ed142ff062fccc8c189f2e27f5d3b7154c08b8cdcfc18f519481d4cc3d4024527ec04218551c3bae9fd12665692340038aa77e84029af6151d5973aecc562fb75b7168810f89c5b763687b3cc0250c835e199a231ff947b5337b22bbaa0e1e8dd5ceef31925a8dd8226bf9c73560643c9ae988fcefe26d0b2e0471a141306ab3bab62fa5c06be4b7f2c3281201765cdf2bb8b4999d428fce7da88efc50dad88238cdd61ad076fcc431ef7bffe43be486c5cec74dcacdf4d5cf7d426e65b3dadd002d7274df44c69a3f40ff2429b80ff0e79915a28a9daaa26fd8b16671a06abf64f7601054fb3a62ce4d1b42fb673061b9a6a91380d43396a583b2f5532d4c3140b6eeab1b95b3979b1f870f2a965a994613641a8f5fe0f9acfa80841b27b98e3f4133288caee018c57a34c790aa2e248fd63a810e23ad238cf0b98981009dbaa12ef78cb7e07bff18aaf9a8e9762540cd7638b0f57e22ca3f1ae8eff2cb308cf7f14ccf9ac55b1ca878872e14f753f0f3cea7338174c8b1aeeaad0a954ac7c53eb71800a97b2c4701ca9d9f493218f67985b992af033612722e38ceebf70e5bc03e0ccafae2ee919769eff719ed6d43e9c2b13e86218f0adee48cd2efa20cbc76a27c27eaf693c11d4558aac2c7cec77838f9dce80c47e54dc560c21fb060048cffa743f820f241840bf88196567c8d8162bc5b54269988ded69496ff7f44b2fdc22f300d27605ebc6d8793555e6168c397dd9a67b43d76ec0c926c6a9b6a5393473159f6f1ffffe66fd0533e753fae8cea728011f1d5c5838c461e85904e609dc13f3037133bfa0b3ba737cd4b3f76a46c2e2b62b9449e005da60e58b90612667af0285339fbdb7e2ea5ac3e9537ef394255ddf665766beed1ea6e4b5bfe8ec4d5c98a180df9bfbe98fe155aa87a1130b5adfdac1f4abc8d106c24a3ce3d9fb3e15ae7a957a2d54d60127292eeb51d9e883534ac482ca34b6249804a2163bfda24836591e42024642cab92e5358e9d134797a90a561e703cabb232659b1edca25d0e9b3cf13cfe56b8827603495aec1c0003fcee170228fd2166537a0a5331d03f7713b8404a4f148bae88bba6701eed298c8753a02df578581738a2262a9186c6f4d42bdf4a4967f2928c5dce8e069dc90ab2b57c49c8640921e2202056ba775e3babe567b19b7b5ebb6db12fb3fe9c57001eae2f52626909fa7cb4abdc4813aae4edb7696b99b4ac960ebb9a21974f80af41e19ffc12013e81a0bad3e6ea1a324818b3266bb46c6b0d6ea226108a39dcbcd27453c829010662f1e78e8120c6110562b0ea1e114e1099e2ef8b7387c6755bf6b2b7331542d932b42a936824a978c3201b29d61630c0b6d7a842821985ed1b5fb3a19f3ae11f9cbbfd8dbec523c52fbda1f0c942f55e801de6b885552df34c866411e9b740b9e79281bae18a6dec0f7820c1c58b5c01a90b6109d80c5e576005acc98db134fd415c5034c0808eb05456ce0efcf9ed7e835983126dc8521b3e6d7983b6999e0d2c197620141b31b9ca11d8e1b6db86125941a76580bc6e79107e9602e5e8cf93ef39f9b960a064a57b2b049ce3c557eecca276dcae16e38d746590d7ff53514232eb45f2bd260899c3a3281a17c0dbefe1caf655fd1120817f305f7abe05e904e7c08d38fc451137574378631fa113d40aa47111fc7c6165c9fec2eea669c74b1d1eeaa27a839dccaae2960ef4b6e9360d5c4804d1eaa51bff27ba5b6232effb9e2cd05837c241e849cfc3c9b4bc66977eafc23bdc98c6ae025d1fd5179a48f26f798a3cd73bc7b8fe66f2a10f73dde70b1b267d806e82da1201c8b563b854107091b4d6345a6e683590eb054feb40ac614bbc2a29e451ffa9d202b447a49d890a60f38e50023afe9b9d18ec297a9f0a70739c1e731657b0712e3074c23cc15397239e168e42c4b8494079ea55495fcf916386cb3146c2a6e0537bc1a9b5eeb87ea90cf5561cc1bc02d3bd4ce4d765388b7d7da7b180f08b9b8bfe125b729358010b0abec731a5001334fe1d8ab16167339da5bfaabd4fc43f420c85221a0a45ed8eff1aebc86ca222ea412f0ab55c1e6e02060684b71db85efb1748904f0cf6610504448d18873b64275a071d48bd60990a94ad1fe9273eed59a9862948a47e49980fb389f4edac1d534b7aff7bac543a8a9b2d56458aeb40ccd75891e5d1a086e0025500e37709ca0126b1e3d6b91ef6dc5ba701013a75435dfe3991322fba9ddd7d68ef5daff52a28a8a6957d70fd64f0553d7e29eaea0854be226167fd181f644089038a33c31b464eca1c0e180b29090b1b20e238da52204b22b0755f6ed6766b5ed0e6d962fcc5e0eed2842924eac09a2819e7b3ff579c6e66ca65ecbf8663d126da018c51ee09ae4a6d77afe32f1275b8666c9c769fc05c957bc351efd1645d8b72ac8aa04b97a90b56eef2747d23f171641a266577d9de5e27dc8462e7809994dbb7e089d039dcf2f7df7dbfa65039c147b35b2383c2491d58b673567dcd7a2efa5983eb2002c062799b86faf09721392cbc575b85afa487ab965e8de0993b23c9f3c9cf021aa2db671bb3605308ba0ca5bf9771c6399176aee1c753c44bb274fbe54c3f3baa52331d2dac59fafa1fb87722108f61538fe1c8938a0b4bd7dc74fe1ec0d22fa1d6085a70091328bf164ad2d247ef6cfc1f124b8d05973458470c217ca3cbe1e66812801ad6b38ea797204a8661a8ed2cac56b9687a082b23f4c372ae78d14c83c5aa8f4e308b534d684f8f42506876afb2006f6e2a45795b569b04c6650b8045bfd9f2dbd91ecdd43d0a7ca8dee62b09348d91d71da3c12bdde6071f3ada835a91bef26ade4f5328cf00f6a4c571da5dce1b64dfb00b3b1504cc102b7ff2e5613ff69e3624f1ce5c4e2cfa5f7cf0422ad7a5bfc5b6f20036d4330ba12970a0bee313a21ce7c99ae774b495c4708766024513e250df4e34fb30d1469f931f33cce701b35ae2a1e4f0a00dc39e365e65beeeebbf6d662b772111da210b81883b313a0bf49210718561feaa348dc04aaa9a5996e90b0105a5c5681519374363e7637e97d4eada4a65d548d191e4effcf0e5f578cff11f2dbf377aea28a7ec7e3cb1f4c0b71e0b7031e4644c443f7ebc1726ca89db9973416b43c90db5361def6b58c7c1f5be3ff5325bf9c136323c8fea96c523d682e9b0c7764cff379ee9b14715d21287a4e0f8ddfc9d592d1a42b1ef4e07ba0ef014c42b5c46ce9477ea08b61dac5347af01858124ce55db7f7c75dbe5ab92fa19d38382511084271a28b99fb45e6ad1c2f39f4630873cba1c8e9d25d1003ff74049f15b4842bbea908a3afbbfb298cbee64ab610e956fdf1f951ff4fa30ce75ba0ff19d190c1c86b76354daba40107201f136623e468ba4444b4eb24e96fa4596ae4b64cae930a038063affb7b5e0f07b8c446254da556adc4dec574fecc7c7c9d96074ea7a0932a450298094666991d11de7c4e637fa728a10b8741266541544c177cb47d77e63841cb72bee2c19327b757178fae4df4fa884f3ae112735c033969e5cceacf4174add0809b784a4fa01948d0cb8c76df02b711af6009a1aedf54b0dc30525e221fc0925acfade43349f4b8483ceb1f1b7b80f7e5d4b9dc8e6a0b095e890cb3759202f62c7f5d361e060b8f2b232d6e841494a3dc797eb1fd9d3166d2f91605c8748024f55f512b439be3ad489b55625b6bef1dce2edce9500e72213224fb5dc586b022326017097abe0ac83e6b72aea7f1ec50fd50a8c496fff2472b7ebc59174125f129ed5e42fc847f91980f05baf85efb10a44064f95e976fc33d5308fcf5a49bcab77db6af924a6ab9ddb5dee7c9c9472686c703972d84e89eb8642aab44243537f84acfb53641463c4ed70a303bcff11d2341940cd90f1ee2cda80721e07d6f1078b3b1686e5b8acf360a6dccf121fa49eb02c1d94ad2e8f04b19721028d4beab307d2c06a5cf086ff5793732eb88a3eefb8f83aaf4d2374afff61765ebb879eb33e5a870bc32131a130d94b1ef1a0a7fb653b0b1cfc11d0a91beaf2bfddafaf99f88942fbdd394d5f3f18f985340e6f2c8d48c93c7883bdee44abe031131f14d95591faac83c9defd93dc287d6c89ae6a5954d2a068120edbc665c717850f2a0c009ea300e5cecf48a83db9c3cadd6d1267da34a7d9968aa444350fb74d9697c3534de659cd3a55b0db8a0c4790c5caf2e2de2548b5d60a2f7b732f1c08f89004b5e9f1817a6bc61260e76374064d5550291f73fa2ee55faaf62717ca122dba99cff5840749cf255ac0904e3815f994fa009d209a6c01ec4cfcc824d2debb3b24b0f1d33e84d98aa523462904b25bf38436cf1dd1ff196a0174a1e2eb6355fb68372c3d987542adbc6d3b754469c58c4cabd64a83c77393530296bf7537a3d30536072df8b8b12e724c34ffd7de1f6a40d54aa2cbd406ab7f1282d99289879b7be6f318c14c462e643319bf612beeeaddc61b350c005abfb9fed02641e81546d535b825aea0e1ffd2eb4f5850b4a31eec8412fabeb1bc437888e594fd4fcaed6db88001cb3c60d74b8333f2d0c2e826f2bae39ff170b5742140a5ecd67f2b104f146837fab6ee2bb6d2370468fba3a05b62809b2143b7fb05b46d786bc42fafabc2fa43a9a0418fb18b1367b7f650e610e6d6f5390f1e02c43f88257ba180def07ec78695ab066b89dc9f5f1f2665086fb0992c379924555ea35b7a9dd4ba9d6022f57c82ed90688407676833f3d40af316491d1bb8ff64fde99fadc1dd32c2b8f4d135812ec51cdc314222b5e0f98257aca08766ff508b4fada1906e30eb2ef6721e183dee46af2828df3ee5bfffaff568ec1a7a30686df639f45c838ee61fbb5bf3e02eceb35facc1371e0806a010879141c3bc546e523db3a61ec7d5e3653c3904b9014e43c8f4e95369a16fc05f371ea2ed0e9d7d6cc6791f6153f06b6a290cebf021d0d2e5ffb7601b85e6cb4e307260c0cd78c457f932c4cca58e6b2f93d881059c461150d500f3c4bf6310f7a3ba158b3a05391caaf003c779679fbdb3db7968dcd4084a518eb355b4723407dcadbe326522162719e1e8873b6dc61553c977af708364491efad0bb21f9cccd2b4edaeaa204f69a0005c30c08ccd6d7d098b8afdb19ad7fa4d9b44a30efc7ab15563d03efc494c79c3b711b41940fecd80e096e746cf666a4504efb91ca1d17da93ea17588f094dbc9f08f9a6b093446f5e3d42f3738252492481762d70e7a418d435d38e029539876d710faf6b500c049575d000410b0f5632c17a2bd842831d4db01f38d331915ffb38d207e29a0828e7f63e78e71e0ffe0b2c3834f78ba9f459edc962244616268225dc794a3e09c9043a77b2259076745081a52b49d262c90fab8e8e7cf2785e5391ac484c1acc768276270fe04124a0f49995e560c4430dbac1f865857331c1822737894be71e886c4708687f68a63af48c2c7226b64a00743e74aa85d08bcc4e4c42ea554fa1d8f901a920666eab60dcc9650b22124147ad725e55d681a23b970788ca89a3fb8eac0130400a2978bc1eecdde6ffa70b5f23ce8a458c1e9b296a65d2c3eaea1725ca88de4d8084995cf1e96065eadfc4cf795579299ea256ef152b89cb044ed2ab7d11e333757c7e80bcbe0b25736ef19f68ce9270a055e1974870474cb41ff55cca540c1b704f217b5672cacbc4d82ffbef91abde0e8d5fff5b369a2dc1405f2b9aea67a462970fd6ad0a60dbd717776606f4bd70395c506923aa566277df859ff7ee52755bdd2b7e52fb11925331c2fe64a50e85da8944acfdd104a6d4cb175afc391b0a13961db9e50033885ed6bf77e1506a2eabc4d54c4f6208a257e8b1da9fa15d748b42cdb4498de2bf168b3a7b70f8212d705ead3b067761f3f8eae96483940234d3cfce32bea06c5ff1eaedc1a27f59cec35415faeca9c2c188e7883f1436ab81952029eeae6e5e61290d5db7da3ac3ea4e5ecae6579fdda4fe314eac9f9d3a7a6d2a141e1bf014ca55f42453353fbeffb558d0500e3797c2a94921ccf0e64f8e06473017206c4baad3a654259d7d1fc973f8f5e3523ee68369389bd8a930e5093dc5ebe86f56b9a0d7a26895a90d5f708c48684f14fb9fa315c388eb9d2e54971c25dd9e787fc736cff4f72885a4db545f3fb07781e4cd4bba25eaea58c4eb0af774be847c282c06500b6aac578c99122d89fb4696901c235ad5ab73490ccb6a19a367d97cd548d5367010229f9af6401e687b1492f5dbb38d1a97686aa02f320df59f78becd4a35c1b24138c00767d22e1a02c7db89c80604d5080a433421d282d50f9adfa2f3ce33bfa566393359fcf146329a40f98b458352bc6b85a60fc867460f22b3ae47566a55dd506bf0a0dc181da579103d57f7693e9f948032a0d8bdb8ffd4092a852853a9ce0e1829493f1f959cac224d27247ed6cf8ebd1b7ac629800dcbb752e01912c6d4c54ff87562605ca185179aa7c321f0d2d5c53f3046e5a9f6e81c66718c5d3511c41445078a39f545ed789eee7f2f17dbde4291e2d6bb80153cf1bf2a58d9ee7c05fe3f1ff54b95797aac80c22c0b5f441cdfe19b89ec32fefa211d253164323d3e9fef7b9b74610a0597bd38703c046c295c8024fdee433ea88a353b6d1b8d8499a0b32eeb28a555af6e55843d5f3434e36f6af2203809181034d40bfa92e010d0bcf82f9bf2dcd699b6125e812385c3e8338380ad8293e10ec0d1675797a73a1f78765ac3bcbb1ba08d906438fbbd8e1d3b0597fdd5895afba1c317f4a825f41f7a92d5f8ab24a97022a3ac70c15447147c32be1d8aff4bbbcb8df3a37992090656ad013dbee38dd1bed7c17e67671ac7fccabafe3c9ba161e0649d29924fbea48acf77883f3604e8b5ad6ffa024d428a65f8e975f3ff3c4306ba22b932fbf6eefabdc1f94493642743b9e73d94d9a1cf2d8995ab4ef37b442add6d3231456b05d4ff4fa09f71266106acab5f51f82bbf9c4886958fb192ff6e4fba56ee6ded08f9619b816e5d1b76ab81d7f0ffd10e504dc6b07115b6e043af93666cecf6e098fc210b7bf6a78209b3ca562f475e84f4a9da9a1a487bf39a2a1ac87a4cc1afe7fede0bd99014b030b3adc85228cd34324452e18ec855efff5d0354fc1495ded26688b90b181798403ef601c025ac334f950633278d6c91d261ff702b47fe711db17734de1be9f029a90be063173c00af6b1349654fdbf2a64f88201c8ec7e288ff0141c1e5c7e6814950e61b3c94651b77670d5061f6177bbf0427d8e80ec890a83b188e0aac6063e528757fbd3ae507f4edd876421503f4a9238d47a80d541bc74027955aca50507b066ff23627e6fa069d3bb0249987260ab57c515c5f949b27ba318ad49818048d1a5478fff9ff1ed798f14f5a6b2fb45eda1dcf60c4dc75801a3001d730d395e56780229d762b8c0d45b243e0e02f933bb4668722ba7d06baafa453444160df2d72e9a50c01aff184b3f333c431f8b79d497521b86e250a8f119a1f83a77199298857e79f6713153a3f75527deafc4e83cb249bfcb4307dca8bcb2c1ec2966de40eff05c1984d02b4a574aa449b1324bbb4a67f4a5a17bfa6ed1ddcd63a8e903591d1eace5eaecc2a580229460bff18faf32dfb203e1c9637730330e8795d64f82fe2a8af3c9df8d7fde442beaf3e36098f73bf5d704ec71ed59b637f676852ed89ea3056be581812e8fe2fa45afaad7ca3ea473d0338ecf02e0c6ca34591d2f2e0d5545d2d8f7482ee3a6cdee77716e2dde3c86a22987abff9e71db5e165ce7402f25728c318e93411ee8c37dc5850b7efd88684ee9d639cf76b51da9d5924c3e89fcb8944557516c86964baa65f8b8d8e7b05941066af7fd45e934683afc4f070f63e1a5fe1776bf3d160a1b7fdb34161a0fdab5c7fe1942ae61f6166f31f639bc64a5c9dd13a0035938efcb44e0d96c1cd30167df26fb91b576734fa96cafd4341640dabfd53cd5cf641c6ea09f62d26bae14f85be3c00a0a65514c0a54397078bcb54251f8da78d01c5f9f8bd4e3d0f38ec5dd3e6c51b18a7534cef73febdc3a426c332ccfd38912a288720f3d54982f876daf82f93a1fc392dcf572219adab7522ec5c25f229b7ec0fd2a76f0ba72ead86fb7d38797f8554852a40e5a61821b29cbf9d37f879b2f12495952419ad4eab49be2b769cbe54161e980ec9f13759ccf262c7f52bc3af15544623314a8bb2c4062de1256d6df75030f0e57c68b940a4c12206a51ab4790696239939c74772bc55fe7280471a0d976380dd2676efb127da82989abc056d235fd62a8b5391959f978e6e5daa8b3f629074dd6b1f71be5714cf82965e83838c1dd76f951bf221fbd9f017fd533cbf8fb97372980b73985d2dd898eb95b5e97bdf0902b1f371c47e2a4e5bf4a957cfb15429a9a9f523f53a0a9b0f3eabd4c55a228e13a26522b0b30f30f4f77fe9b4e1546d74e67e626e7eb40eb124bd360f8c607b1853dc761080d42b96a583b2d565a6630eb4a6cca0cc083afd2a106c729bb2a2efcff5c82cd2538829acd609ea0d18c4fca68b2121fca91b2d8c451c08de1c35817d5ab0afd3f68fb8c74014421e9dbaa12ef78ccbedb5abf8796074e14b5a28ba03dd86f47b284a0b3be49a85aa11d6d2a54e98a43ddb3e871b69ecdc23b6c874562c666e487ef3371e9a1ec6689bab7ffba12f48bd61390a50ee744db5e0d210bea51b62db26e555f5a766e0d9de1f3265ebf12a32a11bcaa9c481623e4121ec32e9a6b4d837baad45e6a1ccbc1baef52e3c86dc9738b1b0ef155a7dec7cccd98864804206398d9cd2ff58050c4a435c82fce6265add25675616e84727ce6ee9f0f950a7eea960474ebe0fa23f5433abb83aebe32e7329ab358e29f2a4ae63f8b25bf38ab647e9553f8b7d7bcdb410a18b9b91570e0c2b2689aeb71287c79325a27a3a8f2154a17dcb573641647c28dc453333d127478f8e5d66b066d4f01f6cf7ecb9af62d90409a3bb2d7af891ac48582064b7e60d6d8fdd41705ed4c221443d1d5675a8dd5b1873bcf849a8b17a1929c2fb42b0370ab108970c23b8b24fb361f4c5272cd0f911d2e08b9de8cdc00f921a5d762846e69c005da63e58796bb2e6cf584e5c3a8be78b5f884345b173c5c499a85354a5db7e000c6851e41efbfb1c9ce7c47aa6288ed959f37402733278c350f45f20ebedc7d6890cc08bbc83bc885bb6449ebffe6bff736b126faac0e6d3153a3d7090cd44a64ae0aa133c1ff87f8008c19201be41e1938c7c76b6f254607494114edac7ab802b217b90c0c6059aceb667f757b8c864e9eef40ce68f6b3b0de90e02c3f8b8dc448840d933f31037ad0025131dd335c4587f20070b9a1ea5a3d16f7ec39fbf191f6ab401a6075096b0078783583027c8f170f1df83340b49a845043ffb1cf46afdb0f877473be0038bea7056ce451ab891e76c6368f72d1e23766cc767695a90c7c0a5636e4b2e81e0e359846861e56c78d8f7e35652099b6cbfd3a72a9eb4a1a074bd588fae4e0a308d079df79f65905f4ba59a8893cba56750c772bd6751d6697d56a553c424b6e884e9bf5b001119f163e12810c34aa154beb033655677dc3f1bbe6665b78b11439f02b563c03da87f057741caa96b533f5d4a2e96f1e32946ddc3aa5930b0fffde66d78399cf7ea67168ce7a45ea9e302ac618e1cbefa97c46261122867e4f1838534e45396893c34178a121a6982caad94f962b7c2999d9e14ab89ffd8d8285138d6f58218ed94d4cfacf676fb75b3d7e24078cdc8edc77ab85b13f50d7c18e19d4d1c08c9d74a8b65956bd0912d48a9c366ae5ea7f9511ef7d49b40a819656755061c0a8ef506c186260d57d9e9135b24afaaaf88b9190b273b8b25238f29170f230717b739a32987b905a3153bbba919ebb39f60e69ce66c20d130b3dfe641b8b71e252ca134d2ec51dd20da7c07e0d1aa62adcffd5559c3d9f9901afeaa26419c585570662d44cf735b18fb880fa6eae55b6b18d2629b8fcb36c1c52b72549ddf6545509f9ec1b1ea68ba77f27f65fc9da9d54ff88e5ef8b0bf2584feda1f7b1f11ce1980517993f90a98c4c94785541afce1545dc8ae450e20276e0d33b926dab566d2da9559982ae6d0f77976b107f9ebd865f9509eeb2ca5033c4fd4f4443834a28fcccf56350c9dfa28f5a1ce43aa036054a945ada0ada566746edffa5b1d5c2e3889c66e88f29a2448a148e441fde89e8d57bcd8ba634e7c51cc7e5a370b33cbfd8e7b54ce4193b0be935f8236ff30189f1f7038e0debf47011c5dbfcb9907306cb1c903b73ae0b7ded9d6922aa530a779b24a3b308e06ae52b4bfab2226891b2dfb24a339d302dc0f0da1910cee04c528454259c1df69874f451cbd9715cc7ca1174c90ccb8dfc9c050a9e1152ba16b3f56094a5bf3367afdb1bb5823186fa86550b566381997c24030507c0fcfe0afcdbdbd0a75ffad5d45798934147cbd3f9933e45f8a8c01a82b8d0a205437f91d744abd1aa76439f637e96049a582007aa0841cd40b2b5743836627b92bae6f4148eaca6bc8b7cadb503ef06e98f2836b1d6852193eeb1f68d2c54e92dd3bb468054de3384b7b1fe228d77a086131664436f48dac80a6030a8941671697e02f858ea28cde93cf305e0ecb4c472a81e744fc27e38a27e1746830e9c01dec864958448ef6f0b0e526686e71470483dbb3e21322a11226cd254222255e1225495a496b11c42829922ae9d246da4b07e9289da4b374956ed2537a4b1fe92f0364a00c92c13244868a4932245386499664cb70190123835febe0ffb604784a3084048828bc410431892892c8602e0a1083086212512491c15c94200611c424a2482283b9a8400c22884944914406735183184410938822890ce6a2013188202611451219cc450b3ff13300eabd16014053631448bf9ca65120f7720aa340e26534ecd072b84a9b9573458995588b8dd8ecb115410fa20f7682d8057b511c82831c1c4de2149ca4e02c0467736826061743709183ab49dc829b14dc85e06e0e1e62f034044f39184ce215bca4e02d046f73f0118baf4198b4910ed243c28549baf41677091326ada58f647ec8b18694f61ff2245cce36d2e372464a90f416fc982321433ee470487b51d5e51c819d3b2032dd5967cb287d645347063bf3242dfd7acbf11d8d9e99e9741e8ccad24dbd694b473d7e4d30b2736546439214d2c1d4837a92ee45776e2a8d2f2e4aa4d00bd47d5174d59b1aa957ce1249efca38474d065fb9045b29ad8f98794dbab2e965ddaeea9aaa3ed3d42397ca705194b16aa59da9f3cfc195895464abadf54369d1aad6bf92c26920cd5ee90c52501a66532831883471504bb3a9944860285a090c45274d0856d21e6bced25a9a5a890486622b0d3c9c628941a48983bd349b6a893429471c25c0509ca44909ced29e668466d26cea2512188aab34f0700a26069126fe1f643f00003da386588490e9ed5ea4b44e6c802b4f904d3b6d6d839736cdc3f405f6a32ef8e7768568f8f9bf133cd5343190e5ffb639b494e868bb8329fb35501b8b77a56dfba2ed293dfc88e695cca293c8ce57cf621e7505959bbbd5e97caeec5b0aa445ba17b9238247522cd2690e75a5b2ccecfa63406168dccaf9ff75f52cddf141910bebc759df9956a36324c1a76a8f8eb88fca98dfd4bc3c13731cc2275bfcca383e7cbf44d13cd716664381ffa0f5d79cf3481e0424658cf1e2411b8e95515d93aee7071f847eea97f6b1309fe1f5ad99adc785b5adea49fe9757a48689d079c8fa45b7fd525f7354d5d207fae55de4e52feb577d7dd92e73e64db8ed97ba69e79ea7b87db8f108b879cf1fc01165f7a9018487b0d4409c0b2e04a700dd8f30d76b8a3b8841991fb4e1c1551ff4d1c1e15e607f05ce23388605cdb4c25e4040e1532136287303c606fdce40bb05eb81411f1fd4aae0d62fa8ae056d7d30c405d5ff41bd3cc0d440b203db1ea02878360bdaf810d02e0407078798e03120b824062ee9f5664a2b20a20088456dde6302e457dbd45644813d264e294f71412c3666108aad7c4a61aa2b20a2808802220a80581ccd602a4e3208c5590661aee9d4a7bc2f050af43e982ce9360176d979ccedddf17c411b8cba62824940873fd468caf2add3f7d2fd2e86d48e4687a8c7259abff6fba38ce34664b5c06b7916979639c828cf1dd569644afbbbae10ad44d24afd7152efc4ab125c8f57e2d0994e3d48a3443bcadc24e956a8e5e6157c159df922ad4fb26cc53dce6135f4a1c3f4db264b904ec1622aaf67ba5f4d3c48024d41ed8bf30f2c72ab2776ef333607afc172ee7826cb4315fb6e2f9dfc09d8e329badf8752ba55bffa662aeedbecb076d99d88cda8a939295d82cd72105897506462770f325219cb7281a5c9952d884bb9d14b0fc472f955349ffe497c1d5889a7749efb043ec3ad32f5831839da315f303352afc65d153cb6d49b183ef4d55a3785e5ce3ce5ae8daed2abb1aa84f5abf5167975c6d0836d4a7fabd2ef9bc4ff3745fe5ff5ab733771a0eecc3619463060bf0b4120d3454818e89544c777fcd5af3ece33843d13a40ef0cff4a3c663834162a9f849153797d0cdbaa271b16c009d1b812df664f8e0fd9629ec27a7ec2480327b70fdcc7c83483e444246633e4c0ff215f2fa29f25ae318391ac3c35400ffaaf548f0bdd980939c8e183ec64d47d4821f42cbb829a76ea3b55d123849d2fe387eff969365f5a9f121655950eb92987f8f14c1b10c7112a6d300d40d141f5e6ab3d55a902bb52553c687f7cbdf99ab3585df72580705addd39b130482d7267eaec747f68785162b9a07cf64a65aa7ac8349588a7724fd83ebd19bf3befed9780aa3a5919ccfcc641e327ab64e7c5487467eca91ff74166049c88f9b7fbe51e417edf8852cbf55de3d656a2a66678b206f2eb9defd95129134ad0332e1c8cb8e768818d230dee6e08299d4ce8c64500250323802db73a543c90a50a36ef3a4617a15c316cfc2981223a3eae8743ea92aa3a0ef99a0af6dbd376166cc2c95623c19b49f504af8bc73cc865d162904115de37f1b176f06569e8daa0489d08f65f69628d4c30d1153761f4a84a7b5fd4fedadc4718e930eabaca2642bbe9a6960fb8719b5a9685bd31f5374a838dab1fe32039ca077523e79e70cf66702546c59678746c437574c4c68657947a48700c92d703a8548ce922f5849378cda5d82db493f287d0bfa436419fd5bf41d1902c571e8ce164a99d10fb611d8da65823258df98d8d06f55939e9975251f854721f17b1c225708afbc25604e1767be360465e9b9ae64cd1980c2b36780c72fdc66b758b85897e895a849b9c3764bd83023045fcc033df3894431e64a50c98788af9016ab316a3b0b5d92422e3d7184481409924aaf66192ce082b150a65497b4eb6073cc448f084a729c9d82df774ecd183561388c37fd0ee375eb1ba07fc7981ae10a48e25464cc678bc0e63d923f308f0fd029efc9fdb24c8087833b542c6b7ba7fa72624a3357af7b8f9cbc23c3caa5f47223d741ef8aa256f0750aafe360a49bb50cce13099d194c0973a60fd23769f24befa2af2cb262cfd8e1a557ff0f5f062ae4a8b26d1c909cac221f157aa8957f49e34990e5fff420219a450649996c786786998b1777c4f16c9688a53a6c6de2d432b7bdd2c885afd7ae0259ebe5a0b74b5ce432b3f03065e13ae2e3dae51a6b0b6371c1ebc5c03c9ed0ed6f170456f57253da258a531dcfac52b2b86b5c69748ed4b69ef3805c28be015e70980299866621e0e15d410ec222da249fe104f78feb18dec64962a3dda26dd0690577b2904eb74b23b353b9271b5c7adbcf904c0a025d5d85356f59c7908b4f0778209a96530d065f42c30a55e2259c5e44d1eb5a2be2089ff4d5f1895a6b380ce62861cdc1c3fe88db032d8dfe4c876e216701c747f6ebaec94ab7774bc7be4c262271ef4df3793fb961253823ceb21f5b3b4938674d093c3b05afdd577bfed2c9bc932a90f0a38fe9498213875f4c7834f8b4de77382c94b5280e347d13835f30dcd735a9f2cbe9ffb7dfce8bb205b984c522e9b4d389ba00ea8a0405259cfdea90beb693b14354adb277b545a1ea4edac7b38f0b603c92de33a91d44174821abee9d04065c8493c6361c811e4a9b20854ceb945e2a716c7fa52fd1029c014dd50d878f00ac3bc68e7403484a770153f9050ac6db652b79aa657e2cf40a2cc9ff1b86eb84af1bed2bb0c8cea1ca07b25a7f9dab6f928951efe03870f6c98879b8017026a0ef919519e7121381ef9b4dde559ca87602336b0dad73373039abf957a1e5d999f9101ed3720228c1ab4e6fad5475fcd1f19bc71182ce9eed806387c6ca768b72ce6445b4454a30bd2e671832ef96ebe010877d7a6cdeb9bd505b84a39202a06cbe203ffaa6a6249474fa41a8369bf54de9346dbae4381e11c5fa2a1b375ecfbcdced98ebb8819682ac9ead0338ad7891e0142ec685e0e78e67085532d6c706c430b1c3dfa83401d0a8da0e240894c188f40af69c2e6f22b0abbfd14fe255139e027a145e1e8a0271fd3c02867d6e1f521de27c03044a575b12e535e6db13e77fca7144349bece102bfb554694616ca36af90be2835f45e31f7eb160adcecc0e01c9e31417a6b2e242161f827d313197aca8736fb642d31e78d06c6b5a9c434d46af6d073001b7e64c64d33735be67d590b4acd649b495b963277127db485d68c409f403d78f996e1a1fd5caadb3b0b8788c4798e8c45a57893e7c0946777329b8884f26c8f3c810e47de7a7892bc876a8c64bce5680932a34bf62d40699185e22ecaa984df70743238b294dcbf4039efdaba7b9e8aa3442161c31aad000aa31c3fe77813ec1b4d10d2ac65fed56be9fdc9adeaa91067f98c433c76308eeccc5ec678f835a664a8aac7e81ed3c9579c63a439484138e7ff729afddf4730bc7f35030654290b0dc6a403f3079a19bf86c9a4f07accbf209809ab02eef1f33fbb8a1445ff6baae8e63963f9268d96f58eb73ef5d3b82e948a0541f21af0d61b0665f83e0378375584d94cde2ee88316ec84900b89c55aac6a43feb68682a2b8ae62be8a072150cf24a7d63b13d290fdea3c56f68e3e65caa8d6da122e17663cf9113a30d650ce96f709cacc54320c8aacc21cceceffc7699f5a81b9b31156928b742c5577db5d4ef1009f4c77ed751ef0487ea891b3a44c752afedf002d6e5dff46d75b98eedba02fe5e528e4c1194af35d786c0e96c7acf8531879d52dbee0a9f00a8fc2a46260260698c3357d0fa22976fd13c83aa91151d5fc3fc97167294ac8946e3f1cd163ac41cce5c0f0b9412679ba4c646d458d028eed141fe2172810a5c5a683e00af857e04769694d943f85c4762e35097664a06b360ff55e9c38c8565d3d24f2519df57cc5a5b8fb9ac0803ec3e822c5a21bf9e7bac32e415bdd702a42e8accc620c7e502937a1008a29c04c71293ab28f08ec1476f1071ad26719b04c6fe0f03c814c32c2df498ffdb6709d96885f18aee14c91a500f14c4f1fd842352ed0135fac41df3ef412c742beeb332f677e9213a122e35fa28ad9a68b2ca2305256f66623a6214433949625bc240de392bd3e95b7bd09717e7137be5350840358e7bdbc17e0143d94940e341891d19ec49456f931e35ac42738eb23da337ef6d8af45f220b2b994f75c0db0057a907a7de6d3fa928b822ebdc37f1d55ca723bc5a44c6dd126139cdc3a46a7aa5f0ba5184f5500182a5bf4f34793f7090a7ea39f6c96acdb91ca689bffa6a6bd07f4911fbfadd9e5c24f4830115f4ec7748dd5ace2d68d7da726f9b01cd794399fe2f4c83033f5f2ab70c5591ee6e044f8aa80745b9b4cc50cced09c3258d911aa058dc72cabb04746b57c332c101287cce793cca8dec98dd9a7e66515d8727ffaf89e20ff94c8ca82f89420dc8987f0ac189b5bf98067aafce71af9810b2b4d37dbb4ae99925d93af05c0c9656c792ccca31f6cd14b02535488521d09e41e23c89c2123f67e468ef7be7dd393cbc1fedfb63f6b63fe00e2dbf94c3a9088f9c6880cbf98077710004302575f714717df6dfc2707c27f38d880026fe8854edb167814ed3841db4357d142ef079ba7d923136595c17a73d8686f9a95cf0052d46e71c2c881f6f96fd87b3d1545dc68322d479d2494d669671597df2f131a1eecbdf438e35ad22312bacfed5f5d3b3987a5dc5807905a978c2020889cff61397e996ef7652f05496e5c693b0ebd693cca688ff7671f6c05dd01b22ba667381344bf1c44ec5a97dc2281f45f69f9bb0679f3fc47e2b9d245da075cd9e4d16f5ba7ea8a69068b5ba7bc3ff88b90a6b2a47ac88a14e39fe5d95b3558bdbc1dfca140220522bb80ebf0c6dbb77f5974d0b3282f660c62f074d8307efa78c94f622a89c3ed48dc2e5480cc4263b49f8fe4fb9a6ec6fe4feb40d2466735fbcfbe18d60a65f152c4d08b7a37f4725ff3608d07eb5c403371ad9d273451e5edaf250d68a8e7ba279f9e70a236d5266cfb07ce762b53bdd684abda6e521ce2f7471801394858cf6010d0c618b146fe21f75fd281739bf80cecbc63926358864d9ff43b57f22a19225e822a90656be46d2067b0e1a53d828e0e9eb1233cd5cec227dc40c3cd9bf678d075cd639bf135142933be8dbee23bee9d26ddd0e5fa6967fd36f3fcce7398dce818bd5b1394fa26bd8067e6e85d539e645ee22ef51f1c6f69c5a06026b57aa5abd380726d068715a35fd9f129ed6ea47a6a2c87e8ce7ca1fb430aaafb6e0645d49356cdef5448330eb1782e45f579b1e6b6cc35083dea4344f0bba905c7dde6b17bdc233d63b2113fc9870f04483673710c42e7a2a10ef1c88bf5518ce3474b545153d306d2176da1903f29d1d65ac2a4fe3d0ee6b0ae4f555771ebb9bd6012f6dadff54d890cac2a45de3fd841760b9fe70c1d58756fff48ccb47451a6e79e2c51066a1fd39b7c7c99b5d851314ad07ea5b33a684b9b5eb208b2c8d2dfc4cc93f1429d43ad4c08385038cb65dc6c1c0b562afc7bc37739cf4b73a12815e1d262bc8250cb746211bde4ea1ec1c057b6460f81dadb93bc59bb2806b8140ce729971521486e53f86b9017c8bd27a0b469afeef5cfa8d2953aa1ade5927180ada70fc12859b1ee7b84ca426c777a442158e54953e93e37d2ed0044fef661ba0cf41c803bc7cb40e46ecd07729688218f31f08285ea1229401a2e02c0d69897718d2a96f28288028380a5088b31982b9300a95b51486324ddacfa30e2fe4ff7f267724c60a4c5dc99247fc49f6b5a1b2625f5d5a1c2e94c0a9d694d72c77de5acdebc27cd9d069d69f80f2875779af49dcd2645d24d8e9cf89596770fcb57e7e3a3e45d4f21be56528fd3a30e9d15a3a4238f12726c040773b53c0ebe128eef77bdff5caf947ef6f41bf3af03814a44dc9a3755856d1864bf5ecb472f54c788c378ba37f0f53cfa7718d1b984c10152ecb10898c24781d91873484e79974e6b2b35ef30eeef838f62b8d9c66b051959e8c4e4011e58dad0c1b0c3aa6b547885d4778e9418b6298a9ff3391e109278c26cc7fb4bff62aeb71ad21f5d30dacaf19a7e2cf0985d0c240a3217b008ee1e58550f6247dc5cd66f6eb6059e9fd62ec9c3d4ee1344b92d9d5d1757f4ae673bd94bf2d949794a4728be491e76f8b343a3d428a7f380396a2d73a09e4c5836d1eaa2cb9de4da7f94d0b37a911ef4f8c3fe772b9e1a9063a1201763f0f6ca644f2c5ca2e86e9aeb398a0e5855b1821f7171f84ec68f5e046e5a2e50a3973c24ebb7e8e511f7bd9a358e66dc5367d251d89b4e675dc0722b17a8c941f004d73c0f45283e3051f798003cf6bd7485b8b407a0a5665fefed8d30e649ada9f4e183d188492fc5092ae451c6a941c2a96bbb4aec296d96a30c3942f827d183d6f69b27f113429a2089e2e1ffdd3d872fb13c415ab82c8874cbd8196987487ddb0081973be5a8e841528ada9d5a1a5512d95b60c63619712f2c7ef96d200f8c6d82d754332c53ecfa7d2b511fc44c21e4b1352438de9884d9fbb0efa78249453745ec9a7212bb5284cfd1c7da080a36fe5f866c7cba47efeaa2afd24e33053cc4d1c19582b6411c8e4290c5b6941a59b229d9f57f844639e9f1f6b3bd0aa3eb141425d4430ce4b0f38e8f92c0b2fed142b51536ad1112d1c26b2243a7df2d566793794901fe4feb73e502addbc8ba8966a90e1950fa80986e1b1eeb43d79e43fcfd98a177916fe39917156aa8b9aaaca0d956a047b291660fd8da104afb61d4b5cbb924c2ac1d41eaefe53bee54e5fa200f2dc3f1e34ad6e359669f20a2bebb2528257da0ff53c75ddc3ad179ae8b98c313db118b8fd9ac6a8a07592b5bd56ddcdd2cd26aa3313c47d4804f378b390004196d4c152851d94aaec0054bd8667ec4c783586d372d1430843072750d65bc60063d81694298705fd41aee3cd607cb4747b64763d68be2e371fbc6dcdc54fabe136022f7fad1aa93acff29a02c2b2ca571ba4936833cf31fbf44c6abfad3fe3a79cbc30497322523bb5eccb5d3d993669cc7cd78f29c958816769f3a2a060e03a684c9a14b986ffd88005399a093e42c7e12305ea8fb9b1e782135f37fcb535a09a58728cb0f2210dd69fe0c80a344405fc79b76745d8994c5804fbc8e8a863bb3166b2a4e85333bcacbc253e578f6e0e97b73acdf71c3ee77b2dd3e6b330cdbc9c20612cef9fcd5566cbc881402c6942da88bfc27133db785e9c6314db75848fa096ff9d64ad7b06dc518e72c939d5218d8b212fbade700c07a8170fdc74db22eeb21f23c49c384fd04c48065d76359082b2e11b8be9af1f61487d74f36e5e1d99d037c1e56214d076ae7598b8b155ffa58b4e8fa2016302a001e9004c2be1c5ed473377e09dbeda5feab80e7039c397535ecb949299bab631e4f966dbb29f03d75f108ae7a0cff2fbea65e01bd68e0d0a404a44d46db86a41b39ee3a3f8c3e4d4d0de21555972803dad4bc8118d1a462a1d0ddfb34372c076015a26b071d0a657ffc7bc4246f7aa3c4793d880e1f68f958ea30b7f160d1d90e3e1deaa3f0d0794d31a9a950c17ca8dd74f0b1b714c225b5045eb394c627e7c9511ee028918f47c61842fa48aa3578de6c2726d6f214776cc37820397b8c1a75bee80aff5477a50ae601818064fd3ff6d5cc411dc0ce85fcbae5e28e483307026efc99806f78eb5890c26a52c8a5500fb26d488d31226acc89c3ef91d467917cbe487da786539ba9a8e37f5150c2add0f75b5e0990e963a51a43eb0bd27b0e6d76d227edeada82dd7f01e64bc81d34c309ba0f88992c252327d52c16582e7f4fdb2aa630ef389da8591078fce567fe8a60bafc76e4e98c013b150b8afbccee860e36adc8b47af382d40955085c266c0ea0c753fbde7e9d13cf10f344447d50584504f1a68c7598e1f289d202a2dd34788b35229d7d83f08a105b5fe22179439d464c4763788453a4356926a38227c460bbf22e94fa44554515acbf053dad6891e2810bfcc87b4ecf6df450737f5fe809b3e82d039f84ddff7b982ba0454a264d8137b8c138e3fd84ba74e0e7589bfa32aa2d586eb11addcb4a58aa92ae052c3d722856ecbeec8e02d1c2c7d3d504f17478042de4bde7be6580782816896415275b4a13568a16736c24ea4c74e2e961439889bbd885bed2f66f497810033df6127fed182cc9441a1b9b5f0f2baa054a54c7b50df5e1bbdc33bf5aa536727f8a9c8407ad02828cb75a6827b5f93a0c888a371dffc65932d92c6a923cb0d4ef376cce3dfbddb5f7c8dd6230de6174c5352533775c58754572c397e4e65239afa7db7c5f49de715b0aad4d76d0c909679cc2c0383ea9a2361928f9382033f22ff27147f0bc5ba86258d712c2ef83208f43e341eab97b5493bbd3c07a3f623c077722692965d6ab38d2cae337fad23fb0d1340049ac22470f00a8c3abed54f23a7948ea73c8a40fdb260e48d2a7e5b7a1bc6ee89228ccb343cda95847dd5524ced51fe4b2e94382da8fcaec7dbfa0efcc7f87dbc7265e3c38f12d33ffc4e5027dc746ba829af005e20103774fcaf8e420f29c6d3c66bcfe3924f90641b1b8fb21576f7f376ef3ada05954d94787db6c9a9c77433d4fdaacd77e935792c0ebe995baaf946c2101f6eee071fd5dc237c0e63ba850bd833feb10a16f31daaaa544b09472bc0042b4aaa84add7b12e9091dfe7ce4f9ca22bd2e862c58f3f2d7f35f9b09621e32ad90fc1ec2b3802b93f1806ca0889604aba5a00155db1086d950666f3001db8d3461797427848a57ce4ef2027ec30c3cded13e77f32e83a0b4acef686b492c33ade26551a31dbeb153d420ba81308c8a31b858b1c783a8b6f12a9ca7bcfd6ae249464695761bf0024c8f18431acd6a91d191f15a95527a89887e3a897fa0688c7c6a4c094aa9323a0afdae11041d91f26d74998b65b57238116b7d46670b00b4be5a16f85ba04a2b1014e1a1cf5ae4cfb41567d956fb13f396ce37eadf8bb8b778b81dcf2b043b333eb2fe27b3d5b74e29971b60da1ce9f7fc10bdee46fb7149e97d82732660ca34e8ef8207c79ab403d0a9d5ed01dd2e128b625c6769090b1798e199f9e631e4e796b934ceed3e40ede2b36d0b36dc642fbc40cac8b40424c3cfd88d630b9425d8e8f836c7dd1530cab2000a44dd8af05a91e823385705be25b3ee169b346e7f4b049094eed0ba3ef9789e67622acdf68b498a9f4ea6284f1a6328f619fb197526350f81f68b33cdbea9234f7bd4643725a9cf45ae8b7dafeca04e7ceaee8ff4ceee07cd270d7dd61001b5f21969f246b788253f924910a5100867962f7d1da43466964e07b65b4c8a5a31d99221aa5fdb6caba7cc261967f1c74d43093609ceab7f4e2b3468b0eb53d7510bb9f15a217d58039db8d1821762653bc6aff3db813bc47d036321647858de30272812c0822c173e20a1b4e247a39daf27a47fbfe97b7521b5ceb98655e38d52733612c23e3f7b37309ef81aca060ac7d0e5cbb00291527473c0c68856c2c25ad5b649f8cfd01dfc32ad01a8c5cb09d57fa5d4b09e013f94e7bf0236efed765fb92687bd89055a66fa72df2612d34ae33eeec9890eb841a9a69ffbb81ff25933d4d212ff5372a685d9f05cc3ac6e5a8a9e9e7efb54990ae04acd29d0ab72aa149f49787a81d921fb4b0ec7d8b050fe6542fa7f4988e91fc31f64f549b836ca5594991dcfc610d5b298a1cc97dcd7c295fb6dafda8124a65bc320248d31c29870dd9563554ec61378ac7f901f88187cfa7e95f1a4c6ce819d0dfb35912d33193888999730e5cd04b471cedf3c0b5959f99378a6e9d9031d1ff71896112a1790ce20c0f69ce28b96afb924400436ddd5b65bba62ede60fe3ae5319b6ce161327c1854c9e0679a58c3f04f68560a7e6c69de464cbe8126e797b6b891dc8e636bdf8082700d474ef8841a9301e48a9bb771347573b627f84c56f80b3627f6203cfb22139f84836dddd7140bc68f63913a32e4850f6888801c92604e62d3610fc5183107d551005013aa0babe1964d10b92185008c75f0b035162ee8ed82df3b73bb5fccc72e439c73d67d2545eb8d2587c42dfe5e83bc053b525055951f00db5681de060194a3865dc57736ea22b14b53fe1ab2af3ac999c475417f1b03ef4e483f848146cc41bfcfb5661ad809349d0111af2fda5f40107b9037276f30df9b8ce9f7dcd9dd8141c729aad48a263d0fdcec3c77a11a40b62d550af1e1f3385af647159397e0b68b82147bcef51a42029652f14f1ba154d2e840a4fb578c80ef43a3a5de34150efb614dde25d8fb402d2b1077876c7deec893824b3e4bfa725771e804585e8151c73763a1af56b2f83b36d2c1b9bd910ab3abb3816324714fddfabfcd79af3dcf6a7a5a4fe5debacee7cebf891f35d2c756dbfe5b39390f2a59fccc12563f67e059e7f0595abb0a58cda17884bdfe075411bdce61657f6fdca555e776ae79994262f4cff669f34f6fe8f92fb61bbbb6f68db147b850a4469cea496b557ffce647df67dc693344cdcf900391144f8f2433ddb290a7701bc66fbca745216ded261dd192a48dedb70e32dca0b0e7fb146dfae56ceb7f6f0fb6f1ee081df6d8e51ada44d89167f78b0ff31ffa7b9faca97f1a64cdde7e951b56ee2bb2c7aad1ab011b43dfe6fdb092f8de6632578559bcfeaa37ab79c551c1d7a616c7b2b0ff28c2ec622993d6d55b2cb254b6d538025167bab3fc428023d7e624001ffdf71a952d2adfe70f021ee0e0d6754333a7d6111cca31a9c550904ef49e28d0220f295795fd5835e391160fe49e18756e40dc80122133dc399614251a0c8f335efb10014178c0f257a672626cd65e24a547a0b5fffd68a55f6e6011fdb23f1570adc0fcdd6c009eadcc85c16aafdea27a1c32456836fc1fa3bd12c2ede8d31edfcc609a446e7bdd5a4a357079623c66fd1142763a558bcedb6166478f6f56be294254eb50310cfe89133548489dd83e5fc0f1dd522d74994d30a78373b0b9e7709fbf5006e31821d38dca5087fd0a470cec8fbf82355c36faccebace80f418c0868d3ac7b72df7e2530a2066fcf0eef04fbfd5a87465f09a1a6254f233083aeeac8c92a749d07f566c7f027bae4b7c8d3a8a0a1c804ba2f5a700942e2ba014699d9421c98918117c11d9ac40462465dc9bb32bce2f9301c7bb6240d9e9483a69fe5a649c13446915b491436217cb76757b977fe3015f8dcce9de03774c334a0017871b43633ad9d39c0717af4489bb80f19ff54186cb6c0bca22d8dabedc06a18ae12311eac1a5ebea8d02c58edba545190520623b8a5c1a58f5da2400fc85a95b6738889ea9070715ec24cef32c215a6de2a8de534862e22c2da019020bd3ea07f05a17da61b0b8db9c1e8d29b6cb022af38fc3d2076741241f1e7e80467fca24556845e7a8832e4cce022ba9910b1510e4647aa95f01c1f2391c74b6e8c784cfb872b4cf9e59dc46cb2b27b207d77d00225211db6e3ce840bf628429a02aa8bfe41771ce1543138e1e5d99d2d3b9294ab26701c02d8914d5f139cbaaec363e86a59ab9b5121a9f15170cf15896a0c51b2c745b8bc4f6548bbc89a6b2174f0e6e7b40eba062904455083d1b7be606c4fdbe54c75ec27d56c307768fe52d7fd9cfb8861006f9b5205abe4805f7f7173413f7910b7af743461067cd962f561cda24ceaac15717353e20360c0bba8f01ecf2a2965d6e67e9800f3d98bbd06f3f10c9e82dd765729e593927b1d404cb07aa621909c330e5c3314b452860c89a4f1e79cfc993be3b508d09c5da1bc3f9d44508ef960945290166c705ddf223bee493d703deb459c36d1337336c2d21ec29a93f43f170fee280fccdc1b4a751721e248b4fceb424aa5d2a41eab94d44465159835d525ea8c71090678717b7fa3db30c54178944fd77283faebcfd45b9d2e277ca5bbc36d1af0860025f42796fac31afd88648cf0bf5b16ee07a4704e4caf658bbf87e1e285cca3c0ba10f3679e4ab4245a0ca3605c6f7425a44a45600063aa355b95b12dca87dd4b2ced1de0ffc90dee82d88f4545904650073012d0ff3b25c5441627a46699ca619964a7269375ef3b8b3d0957a1daf0cb4c70f7395ab6b0be96f298ec407b405f3b1631334a278a2d421d3c94ed06773852f152eefd77c50b2f087cb4e82c0a36d10af6670cabe8020aa71b09772a68bc75c7adf23de60351cad05fd8bde9cbc3e9289cc3dfb02801dc3ff222f630246107e8e0bfdb090d2875e3d78341faad6c6332eceed26d1ead7583578e7b776fd10b69fd394dc87a61173ea2d752312dc3453cad22381c21557d34cc583a3085d3df9c8d6650dc4ab542a00f362902433289b06e1f07a7c5e5ca66c86ace5ef7fd24bdfea255ae6c5fab839fb685ac3a725d5afa70bfe86698cace6a5ebe6c6e0aad3962a8776980881b525bd976451b072976d3fd2ae330a9d548c84b0c29f9adaf46451b993a9635619f9ec970a4975ac18787a242be19c5c35628d639637f397f44de67bcaed7533511bc83c79c12be1680a1544fae906eebb118269aaf923190f1e2ea971780376dc1b277026ee9d0c06666cbecbfc5f620e819f6f669b63ff7525118635ae6626bcaa4d48ca40fdad7361a83a19694ab700e5abd6d257005a74a7e29aa2c2efb7de4d945a79c0772dd468a2be59af40224218cef37f992d5e324f104e928cff52ea11368fef8450e07d1af083720a4b7628c7fb318e73a9f94d3a738a67cab35081509d6fa4d544fb6ff916a0a5755217bd9fa67fe307c9cfa717642f6b55321f3d6e59625ef617bbceb9faa90a52605b26afb1b39dd4b7df933410f6bccd766297715548abc01bd2842c99d6c69af6e3047b86b143a2e289463c3c1b0a570b357432a38b29d1ff86e9ecf67824e0ee08b00c3763709738ac69f7106bbb95de457aa816f711ec44f7469e39866bfee53cbb87f00a10725757b6a681d76aecfa7938798d36996ea5b1758df025e8ee6bf47afe606a402369bf4ff992b23bee5fd7d718d49e1888b6e6ee7c193e867c223e81995052daf11f33ca29819490457a9792a4bdd21078b5a0675a69a2685dd9f1af7665518ec3c00db02f40b7f73f97ce71f615c2a5ad52f1b8af85ab444588b1fd9b8ded96441e2993ddf2f571c25b562a9ae839993fc12f465f85dd4a85a903dd9e212144eccd92d0be83bb3cb70edbd5f1a9e78ea8f685370274119c68dff3b672d30214bdce00df8ccd07cbb08c1a30946248f18c6e538fabff7fea446c85b1c83a042a833ffa9ac7205c8fe588d0fe0940000dff8f9e65a988ffbd1e73ca12d9a8368b78eaa3199ee59be084cb6c9a7b794df000000da212e34a0bb8b38123e1d4011abdc64b763e38f8f4b49c8213b9644283d61ab97926f0be0440dac69d310335cb6ff3037e50f28621a7e718d49cc64069c9ae5687e9cf42fea44c596c8bcfc2b16e4fdd912dec11ec37fa49fca7ac4356b6dfffac1e02018a83f3b6c387c4dfdf2364b718cf41fde004a5f4300f9e7fb72bbb37fb3d6f75ea722cca95f093c370634310c8575352ad90e882e49f1201413e36dd67e00db2b67b9dba3426bc33c86554039ad18a49cf56beb6258963592853fbe6045a1e4901239b1880634ca7c80b904eb6efc0c2e37a0d8bc9f3f1581ed8ce7afdbf184675138fd367eed88ce97960057fbf97b26fbfdafe45ea3fc5f0407ac244fcce9c629a41351b35fb37243ba7aab9dd0341f8869c4a4f496857272c66c6e9cc19d8f150df9fa9db88302b42afc372cf6d1271fbe428a661998e955bce7ffd5dacd9dd51a4f093e60c5e27fb40d02c61b436365c4ff128895fbb6a67cb6982c6bf1430d7d1079fe5b8e88ff227f51bb59f4d5b9eff104cff80d8ba5ab58872fca9bc93e696709d2d022d12422450afc2a5badd0b547f06629758bba11eef0240350690e257ed99e0eeae02cc282133c3ae29a014c0a5ee5c4e2b760e0453651b2549fc6338aa2b1585289d7c3cfac4dafbfc87ef98b53287ca73fa3993bd2204916e5b7066c1e70cef87e39c6c94ac8cca64bf9e649b400c0a29d1a4880b9acda5fa6856c2828a1f665deef17ec5868cb5f73abae86d6a7968bc91921ec12796aaf3029b9e2b5e2d63cee27fa0cc8fbf653aabb24764aed3a6796e536b500fc4b9ff397635bbe377bc396e6e4f88903a4b28e36d88f0df09723e3dac57ab91c18d3de81d9ebff640604e7485cf5c75308b5ab4a687fce91b09dff185dc8705207435eb58d14861224ea74b205eeb0181cbee4f4b0090ebb664734738aa48aae4d5b4e2cc42244afc108ca405227a17e725f51f6230c53e633d3939c2d203e4ed3c718a4049e363423c762b6bf4f7beee0b3c5814e34bbb4edd4192fc794dc6006bb58ca74d4fe593e0bf5b830ac8a778a1faa0977a964f1eb5a5a73bc83c25c6d698ee700a43a1ab85d71bfae3f1b4bd7e3c10f4715dc2b0c794830a5d0e1e6a456814d1c16911b0efc6b301d00ade49cdf4504958537bdaaca526d32f4977fee84301327251ad0e9462f49e74d45b761f98f02266f352bb051212da30dec5bc413a68c863aaa16cc024d2babea26cefa5637a26a64337c9629fd9384de4fd9de23cbf6f98bfc7920ab56c2deb2e0b9d66ca8b303e4ff0a85c38a8edb5685f811dd6644067cab4a7c59c91c4b5cee32f4b5314716d6f347a2be8081f449b84561fc4b81b0a1dea93a5f30ec4da94f220e3205f4615d81781b88e542020e5a2677a6b97f59d8494e884c6c200cdb3bb9d5de1aaf9b8ffac6b625c2111310df92220c5df5faa493d5fe53e7c700365ba2fb227f1b47edbde687a39412773aa06386390b1d362cb82ddb5a310d40ddf42cfe408912ec31e139c855a4e6d1522ea26f4b61c0dc8d4c51e725928ac65f07d9d6e348ff4ddd33f61b59b1fcc1ae9eb6fb9fa87427dd4339a2624d7d3bc12a3bc9858e96f70fc5bf7ea54cbd94971de44c421cd96e68f9fc29ded48f4163515800f1543e130485d2e23306ab4f840fce8f11c8c784b23a973a2caaddda2c060fce2f9905e66f1337da32e27d13cd6742fc9eb8825dcce2cfafe7f3b7dd3c0d20fdd01124b8fb60ec882cc15e51056eec1598dfdda0caaebaf5dba8d04dc0d777808fbff6caeb417eef096f500486d8654aeb65ddba4bfe3ce4e71af2374cba919f4c46f64ef33acc337d9875c2c0b9b96ecbcf1222299694138c66638e8fa735bca3f3747d4d75a22338476e851e4b6e1a5dddfc0f3cd9dea549449a467624c22eb8973695e8b11df462dd05dce1fe7a311fdda29c82872ce0a56335114c4507c351d3e2c8b985956abd731f01e92682a19e5bc023479fa23a139a2281d9cc511038b34a648e560ba279ce291c349243a6f28d21093496f9c38169e23ad2f1aad2d890e576a4093025fa255dd9e13cebd731506bb4002dbd3360ec86a903491c727e93867ba98d7156916460bb308286a47b28e84835be6451c2c6448e66df8c2b783a794b8a8f07ec00705df9763c800218fb4f76baa0c8c1cdc1c581e7794c56acd5db6c9aace866b10f1911b4af8a4ed07f1d64a8ef323c166fa6237507c21812a2b633572c7ab39bf220151ff5f7799b7e523640b955c4110a5ff339497809731699a97b3062616e9b8b7968c59594f357f83072a0a18a3f52c046708b8d52dc31c049bb0d207d19a50f3d24d183b38cf3ebe0a0ae2ff4555d66fb17d9b0f3b19e9dfc82d51168cf8fbae9068efb9f44b2be24772219e76d969ce4586a01a7c48e1d908ea776bd6f7ea0b70efef93f714aacfca64488eaee54f8c6c4070797e07de14b8163888504e998e7f539d36fcdd34f75cec63c3802f43400aec87ed4c18b1ef2f50c6eb04c3d3c1d6831d19adc73714c5ed40c5ae36229cbe24ae9190bc3564d1592c5af711453e17706837f462461e04dc7ec4a341821453a871f085027d252858d06fa6497b0ae20b80818be487e26d4fed28dc86afecf2929329c709008a0cc7db7e2d2ecf83afdbf45f2134d756b40a9a2b0e26749dcb30bd2c130618e4e472730f30d9349581f27ef1f4dab9527c1e820628557f53c48cb33cf1ff398cab2478bffd2c5744a1e318f4a5279bb61e1b4e6e0bbc48fe3421260d6f7b7b194e8fcf2720062108fa40cc6a081ebb6d1f3dcf14a3f3d8040e24f2c33ca2ce86c1d872695f073c9c41a65b8a140ac1685c02298a7d95eaf133ceff0258ae6cb331b30eb804fb0067be95b4bf7fe35224e22dc7fa735eec971b6e8913ff93f96485684af1b32cd6bb481dc7aab2aea05ddc6b4c9fe13eb503b9587084c8b9bb53abfca09600fc427d84324de5df97808247fa81cc2897cf4672c36ca87d974c0446aec4c32a07478656bc6e7ec5188cfc9360623fc5c56ccc00fd3dd2143a274168db0cd82617f8858c7e79c1a7a6e708a7abba41aa488fb135c869562ba9452c00dc452abcb27f093f91f61336f0c34436ed8da436598ed4f4523c4d468a4e1cb08f6f5d8ccaa2a857408c5d5bb8060934194f11a75b65685d9927ec1402f4782222a93ac77815f1dc527272949c94fb11ab92d68c04ce33ea5ad6e1359f9801b2b554fa48f0cc3f079d46c196cac70bb32010577cd415be0cd85b1b834d78c426d93210e729265b878d6335c6070116d8d71fb0a4e2090c8e7f7ede4db9ac3feec8df31b35975cf0f9e2ebb7e4e23be7f918faad61aa697e5d4c6fff40acd6b0dd9833473dc41baedd5e3dd5aaae2203537d212b97431e72d2a391ccd2f41b7ac64f64eccf613d67c8cd077878cc8db3db3b9dccbe0cb64c7829d0ae1c069cff7e0aaf87a5ee2218f60b97d8c470f7f37ba2ffcbe1f2da492a71b3277ed182664202c5b61e31c60bf52dfd06f6594ea355bea545ddbcd9d9ecc1571527cd627507e69060d48b3ebf333dfe2611a0c3686c1e41239fa59530f68c953d9f8aa3388babb88b410cc107829f180221048a2108f684500887102e86e6109a8b211242b418e240124222846431b4866014431a8436e291f6c02b02c8a19310bac8a1bb107acaa18f10fac961a01006cbc124844c390c33876c08c30d61a41446c961b4398c35855c3114402812cb7800314c8230452cd301c43203400c2284123194422817c36c0873c5b200400c8b202c1143253c4862e4e977f53d0c303d87a010434989b518e1acdf3fec56aa5ea39b1d9f8bedf93af7421d59000b2bf43f833e807a725bd3f91805fd0a80a643fc5d178d1a0b7001e384ae2f53d56a5938d77de35db406fa015464a052037d3788a7dd5b93aad922d2156e157e114fadcffc4f2f45004ea86114a32623a1726a01912cefa747718db11294867910f0c4914fb1a29d3a552d31ef874a979daeaa86391dc4dfae02e99fdc6eaa6a27281ded4e40903a80faade577a52148f63b442557aaf2bb3990cb35b548510b6527a82ec290dd58f6026c5abac25250f1c7d53479125594137afaee15ea421b09cddca7daf3348fb8be1630efb535a0522fdd840a55a5c98a1ef5b59d38d505fab6a07f42e47368027c44a14c94aaee7948bcc699ae5a72d56540b2bc94012a53b6aafce71753c164d5e79777c7a151017423447ee401204114ca5c5567b769cc79dabd8665d27c730b01bf49bd4c3b925b0b9a39db4ad6715fd35b0d325da35855902a9817e02cac05cdf41f44134cd1dd366e35ff8b9a31a8549ee75bb900c2c53b3441e559c16a68441326981c00b599ac8777b29386119169fe32076c5245c33be53d31376f6e09e61b430468260f8b3ee3488930234895d6a85930ae85aa1e1428298b00c3518a0bc577799a56aa72080d28f30ed0ab72c8fac527084630ef5f0365d63e2f5dfbb2ee1760cbcb0b4895d64700e72205aac3215813e12ab0735e475570f7e52d99fb340052943f125bd27ad30bf7530fe9aabd961a2b7c4f4b0c8c2d47224dbc118445a12ceb9bbafff03dfebe37ca9be5dcb5006e928f6e29da5c15a578f235afd3e7a971611f3ae982b0fc429df70640a26b907956fff65f1cbab954be23f07672c7658078ce0a1859d38dca5aef81a102facc9e55f03151ed04eacdcdfed63134a9b8cbac742ff7971b005509520d6b0e9cd8c4aad49b87cb5f5cacf515be39781be2a041df65b9804b1ab05d950c94d961d33434f5312934fad023a5fc41be8b1a84f2d0673be5aaff678c07ed7cb14b4f5b6b58074a224577868a3a411c5deb2684553f5cc4c0110630ec0250e888fc5ad1071264f0e759046a332a8fd93180ea77a42d71157dd4ca9ecaefd7a877d57253ba7bad7d8d9e093e1b82a87688ea833860fb2ebe2794559cfdcbd61a3bb366f434cb85dab401c723414549a77891beb87bf8a4f18ac8ca9419a578d602361c71aa76b5ae90b111b10e835ecff90d4b0fb4484c11d50d45a433c659440d87327fa0d78bb7a331700dea34ab49037a0d41c863445e72e7b3f9b14df5ed2250ab1119f6afdc08389c6a17643f2a9f90452db4c5084b9ac0c7e423913a083f57fb5bc846e5bfecd715fe2191b288ea05a9d1e10d340d610a65a1cfb9615c756eac29b66659a85fa1a0c53e5a8a5fb0f63fc67f327a2ee7c01ea65096dd05baa7516bade318fd31f315f6b4fb5e67a2ad9aee9bcb9b4f4f6997efef4f49fc26f42a44e16b1960a8285468d34f46f5b35c630f804ff2906c02dbd5baa22456581557c2bfeca16fccaccfa1880c0d0a65b9e9bdbd8806602bbc4931cb44596f6fe4bb38143fcaa5d4db54c92ef3c4ac42cfdf84ffb6bf10f397550164122a0afaf3c5ae98cf232f7bc90e58c41cf0fcb7aaeab0fbec2f1e92576934a026416a11a421700c210ae55035654a445710c39135aa1b9a70ad0cc24ff5fe5dd4a245dd3f01e22d3b53f69416782540ef431455a201fc4570a790cb5767c53933829ae472cd171e60668a3f612b1c8eba005725d116077010b9fb129c16dd1c42997aff298ea5adb2256bc270d4df5966ea200e86ee10350b50eb030ee8fe4cc49e501611aa6c96a2a1358960ba6aefe9e64dc080142faa6a375b8dcc140cb508521b22430028946587c7fd2c6e6e00c38f297dc50344bd92d07cc8232dc6cbf0ae24b506d946836a97b068ae52d2d36d78a47576a3ed4260fb1ff43544b1766d20437b425976a63e907d5c8869d42acbb5b3064049f2916d92ecde36a69ed72de97ca56970eef0caad27e453a45026da54cbac8ca91161ebf7a6fa0b3099e40ba1d0c044d166bf5c619a1f4d2b9369ad4255ef72d31c02b26ac25016f406adb287de3c451f7b2812c07f3b2c38c2ac237cd9dea7167aa73150573191bf017cbbc9a4500e5523ed2792f7304e0ea006b94e44330de08b890f03d2b4df7e167ec74afdf754667f165efa4b55ecfd8ff9eae5327af78ec95929719a7a7217340815dad541866dd2fc790ed42e1ffd1511c4dee2b5300886ea3b52d98953f51b806d12f9ea0d78a748a5fb92e62fde08f6f232b9099b46f89944e6c518604a298f3c26a1a2a06b2f7665a70bf9e82b75e8a6f7e6c724a0efc9570113d38e077d0b519c680048e982649eddb1053d575727734635f2b9909735e84a13ee3480c71738fc3e7339972d39ed70a05091ae6bee7075306940289a99f004b12e421dc493006c0ad9af78714f4f7ca0aeebff42e2630a971aa5c53db93e99b924b3c55e1eab9445290cb8a76b253024cc29f8fbecdbf45e5ac99aad3f519ef9ff26fca5371cd00931e2e39662f5a8c06485ea5170ab5b00f60613ecb67bc781a5864339b6bbf5efa02cbb61a8d57a532c3c6605bee53a71741eaa1775d76b1606dcaf263f5085409f1d9bcccb50a97a1d994c346303accf4f546f236b4c2b3d712851280f7d5cb442b4e577686c9b92226a38a048f5fe5da3d0abd0aa907c4f7796c003250c9d4945edb248270307c199f5b1e794299cee9bb4341781232ee0a3738a1139fd6da24980110afade960cfffc455d861d92f8c083308e4da7bf437f21f9b7bc3cfd9d54e58e14692e2503b2295e0a6a1a5aab5f6899e35b536879e453340965a12ffffcb45f13061475c83209366bc0f195c8101f81db921e3d2104be963ece2e648b1a142b1b3051132bdc680ced10c7290ba86388ba6c70b0b529946967dafeaf947f931afd3b9355eba1fd72295652643d748dd2294c1d79b637cdc9cb015dc096aee56dff86d8967fe5b32a02f93cebd2903853bd27948375f738d729cea0b2c313ae869066d217c06001e40fd97af69ec517e5b6de748645e2f5e2e7fcad963643b5e61068c088ac6bfdc19a9e36424750f23859f8b19bced59e4dee236113726dd46ab54fd9c5755004750f52afc21b41a38badb7ee78591c4324e8c934abeb5ef4fc268a95c6a81c34f6c3c6adc7f7d555f051903dd05a67385cb55d723774e4013ed52c14d43389fa0a4de04dd09e50d6aabb4b6dc5ff49eb3fd46c67b994791ad08e61c776419f96ac9cbcd5dd560a4c6d9096a1ff4d849951cf10a513a5a8fba65454a4768118923bf5c968c0b62992e5582fe34a7ecf14a6bdca52e898500f3d13738e70b3fbe357b4f54c53163c3146bd42d3d7db0299607ea6c9d96286f6b5e600a84b7092dc696090e477e1af7fe3ce9f9968591ba7078de4f6cab0883132f5566dbbf62cbd76d27b18a959dc9ac6f64c7e2c4a557aa6304527044301d9bf0d4497c75dffcba76c5ebaf73f0dc794558870230f58df0c325028242d1548da95dfd123515fcd5377fb7c7246f25a9befd22c816db783d409f37fdb556be0a1e48aa3b9a3848f84bdf22e744bd5cfd55c7d5034b6f813acbc2a24b6771325b0790beca83da12cf4ede9e92391c48ea31e592ea53500f8968a1281aedcaed615e6745fc6a695ed28557414eb810e51d82779b317c0d64df09e50d18f8239e16acc521f3d50fa50c8ef926aa2ba193d3eec69bb284fb81adb4944dc024244a1b2c03eefee9d0c182afa1acb37febfa71b481577bfa177c5b29b4cef11450e3634193f381de85e65288a3fdd7ad352e1c2cc5b65690edb76415344fb32be56f52a54ebc07175be0212e3a2f8498a00a4f673077b984945ae3e72b63f67a72edafe6ac777131991e18962d6b8eb566d4defd91f28e752bb748be7033df67e28ff31bcf0dba785ab4235764b6fbbfec71ff068507dac4b6b60869075862b31fe0a2b88d480f8ff57ad2acd4f9c93253a21ea03b32c22dcd3a80e246aa174b3546a7847bec57abcb67f00ff34d8930e2f42c213bbca19bf27f23a23a85f21a6e885946f021eacb3756daaa8b0fd17b2fd1597b753bbff9d61f23829408cb1030ea4c9d88c2900652d8871c0de6569028918089ae06e0d4bb74c02d90e24298bc1fa3446973796b6ef910068c9c2ffa4a3458cdf144571c9445d30327ed7f47f3e34c517c8b11776933df7be97c60cc1412996ea28b6e059b4623321684d1b1b26df9c2e1bece034896596d8bfd0ab9a12b24b393452288be3ffe7ca0412dfa01d6ed204f584892b21994e75007095acba15dd5a3533b5689c63ae1788befef5b4f132af024bbb8cfdb73c980e151abb92d522bcb7986ce12cb571d5d405ff2080aae8e81d630a51b97c2460f587310eae2a77594dc97fc266b63d82bd9e18716a44d4f562038b6d445c1327170f0c41c0a9e56ffa8b497197a6eb141f728dc443ea7af53187617b5f4ead6b263343f23898f289a776cd842592122a0b37383659083cd2e308c226c09d89b86bedd6d060b649d466e1ff157bfdaa84a23ca935bd03666fabeda372d260950fc5d520c6838ff24f350ec5aae9ef46903a0d1ec65be84cb864d1d91e2640dc35444376d82ea3a0780e306788007e1b112ca50a894c14abcfbf6d35a98dfa38a1340a4a8679b2d33140977fb9bf83e3751b2c9866a2cf080d3319673f48ffa44e9fcb1c6f67574cb3aac09f2032e18266d6a2d2f30da8da620ab3ed54615170ba4e6384f5d266a925e40bb60bf4adcd006364ea223fb0f2ecf2203cd0362d110239f700871213dda25bf8160c040810ab134dc9bc6e21e921199aa02b3dcc74bc7d99893aafaae8b66da84699f80be98f87012db54526e48851459e3bf94d6fc321753f9311e8dfae36513ed1ff47e5a2f1903bd1a3766592728c5e22258b44e93c8413ce5a82ca416c88f750eab7466e9bb03781621f73cbfe04601bad0c8ad7b368bc0c7a00a53441cc421856841a72769408c490ee14cdeab3fd933680e12bf0601d07e20a31839d0e3334bce8c62d80b295c207f40859e10ec786184da943f709191909c269ce5a0d19a4764af4a7bbcbf21c04ed8bfca2e781bc691e1dad078494ce60aedf21b037e1bb7aaedfe11497e85af0a8fc06f4cc896351e87c840589f687db027e7dc801602cfc6e9110cba2b5684e39d8337b8792c0bafd83075196b5384b68639431eb5a74651b3fb195a9a4da2bc7cc0d175e3c3ad0f17b1dac70099f83f7c9c5eaba507911b00497576ced85428be1b0ec0f9c421f409f6b83f38e770a32dc07eea7bfb04dd943b748d9cf43f98c2c338ea41ce618a60e60fe916c62b35e8f8a18819d2c28aae480f570f7df1dc054eda3be9f195a4a70e12eeb10f2d06919869ee84c5337bb816b3dfeab7b1a5c083fbd97f0ce722f42f2e7fdd88d97055c0d4b652142849710b7b5c967a1bfdca347195f49b0e945d1480e3cc444c36311bbbc5ddcf60855ed76b8a9ed962b921b15cefb44edeb75ea44146686b0e9363f97b7d1ae276fbdb2c885a7bafefc88a2580f96a34f89f2163935024f8c0fb969899aeae360bce21b8e4739691888a7b56fe0ba1b26529b5b61349b65064169d1c944f0871874f8f07d9d5236318e7a7514bf0e29fee5dbc51b73c40377f8cddf172fbdc0cf42c68026d662d35ed06c37968e1ab83210a7c476e694c25f54643e14579793303075d3ffcd73d5d6e41471534600e7c5f2c17991988bae38a95681b4c8d75fe0edc854a83f0425ee8f2bf2babb3820ecceaf3f29f597fc2bdacae1f5cc2445f4f32fcb1e0339fd4fa6dcdac8bfb902d091ace138114929914b2b39332feb982f888afcdd8e3ec9d0dc095b315466fa6423028b1fc590677087cf4c6954e04cc42ffc3a313f9258675f5585e030ffb720119c384d9d8063c8fee7b11058c5df190d1220a737d9c61d53626350cd550fbdba30c4d27800544f6fed4dafb0cb1d49222e8d12dfeff2f868a21d742e739b37f3f9b02feeb1bac01f192d6fd9fba4ae591f8d5e39135c52112e49ace6a4a0b9f4599c814d4f5090152c67253bd61a24840bb06419c3e20564d19060a5865712cedd67a33cdd3f1c2b31296eeda53358f544b9fb4e835697d32610f36ecad5d6e4e05849c6b77a26e14fef90a6be4f539bd760e52b11551d78638866539d2c12e237c1f7bceede2b2834be691fc383ceee15beafdff3621a6a92477af41dfe8e041208f905b577f0973cb7fdb571b7cc2d567106e0bf9c55c5ea7ed0d2d9c13f5c0a1ea3c7924a62d635c449dc12882dc0d3fc293c58dff02cab041df560b374d4c554b879333b7d7fcdb0cceab98f8238f0691539e4614d080604adafc8f254cb82ae4f444d85195eb61c8be87fe8642cf858c5c8dde7dc77b203819e7c66e37d0bc49aaae93d2ed989d2bf36e8c08fd591452cf84945ab8f566613f3196d0dae9976e0c82c39c597039015b252972b011aa4612c96e075647494894004e17bcce3c0093ebe2df71ccc1caf092526d1a94c57dda0742bcbb8b464fbda91eab0177d3a1e62a3fcd276b71e0ebc6ffef526bad9f137a2a8fc7adaeeafc1a9a75f1d7bc29355a6cfac89945f658a20a68d9f24c79e246e95e76252d7fed193563456b7142eee2cf947398a3a4ce20b45432dee11b0445539be72bc8add6fa23646aeb6515ff261b4928c4b4477cd7a9da6b281abc024af68dba44cb8c1bf5f9b7c7f0f433ff9e555e97351d35fb0df0da351946a770a2a4107acc1be402353f2e141f4e912e5c6f9d39aea4139867cbb3513bd1c2b33fee27f40cb0d67d34f8b80767c3cb434016e6c8eb5831957cc787cbda99cc7d190575b15cd3467171f922e2afa63599f4cff00344e0597e42dc36db2451a3efc265e2416c074001bc11610b7487256d2e2a6d27988b4ea42200486fa45606bf9be334ba05271146cebbebccbbc8e65ec514c9059de88e662a77c50385a904fe3e7430b24fa73927b8f2efcac6c27d4c2e8ed61d47a12fc918d9745de2d06728b779c48a59288a45771545856b6a6464ae298fe0c7841ff49cb6d8abb29b25ae19fe974d4f6e4cba188aca86700f183a0dffdc6ec163c8af1ccc06ffe7d9d2b4d3952a6edb4a2f9d0cc379765b84f5536c8ecf012aae8cf951fa5b6f7176ef872ebdbcb84071247eab45ce5a76ebc731bb6c6e18e1f30f977b3e31f67479cbc865735bb43f845d9df5473f90b3af5567bd23cf096ef064ef6e5cd811b1504e974ad81b5a9028ef80b4df3b9eb584ac84cd307711adc6dcd8c0229eff7ceec24f5d73c9c9eabd57086ad3ab1e8f7ec4c5e73f6052c349e46a7479443bf85d47e4f101af74dd62bd475217f06582372a6a62ff21d18b607b383fffa171bb71621498cda85ccf062a2daeae0bea8af8856bb5aa5cbbae5aa034e8ce47182b6f98f3646fb34d38c2cc1aa6e209d611f22c34ed92147270bee71535bf31687bea05c61bdc7e2cec21fab042ce92db9da50b4398d2fc3c8adac56c8ab124fd6032b1e59b3ed6222fa6102e2b2d35ace428afa715b3ee83600a4ab40830334a183d3286afe8e9a57fc09824e8c6427d891beec833f0ae00a426d2bff47061a1c8d2a8044a7e93d66c336ac830f496407f08f5ec3e434fb140d4bbdfd816b19ba38036e1000e82eb1b867860c13698c57d8767ef6cd6072093ca1ce8f109788ff668cb31bd7ad007c38ac280550c3811ffa1e9ed27b27178763e0e12d056bb3349c7b33ac3ccb29ecb3f1bec34a3c8c96134e452c69af71aae397ea9bb4f0bddbc2e2a52039737107bb72d2db62fad4f774226f2ba21a3c68f86798849b0b92eccd07ff6447a4325f45305c4713626ab312fb4bd964b18662896ef45a7364fdb0508194c8a6d57c49a780542be27ea828303ff54f082cefc420941bfc89b44d6e8c3dc1544de414dfafedddeabb0de0a9b5f32ac8cb8a5ec1c5594bb84b2fba5ce8fb1f415525ec7fbe973eaf546d7f3b52abd7ecfc610f12ce11d2785b0cad75085def26bf1a1d6c021b88ff1acd4dd956d7c8c86f26a0ab1afa025ea5594ca5b456a7d44c2c9e8e29b18dbd8e14010627d6d62955e5995d762c6e9da85f20cae6b64e873c58c7cbbf33a7dcaf67aaab86243683bf5b51950994865e0d0a60a6285fb00e1a9aa553757015709fac1c45fd6d5300ee88a69b577aa457fae0db5aee945c9eacc89c72abcc1cd0bcdc8af2fe9a2546d08f942b72312f737bd1346f3a1599758ba3992212e78a6edcf66a212d3cd7c8198e82e753f045fd91596458213400e5d70168e5847ead48269f57c45737ec8f22a4fc5f10bf57e4127ebeb4fd0f1557c1a126e5ca7dd8191aa9d90756a26877a77dda9c08e3f60c4d600cd7970202b42763e5a46e2f3de8d676ac932115b2f13bb87edd0f5bd3d80f5f58b25d774187a6e921224d718df994b998764b7aa71c4d0228a1243c012d7dcc044ddaf04762adec15678aa123331ea9cbcdff902d186d8c6a619d82f7f88ce1a0b61fc4980c80017cdcb94f2ee6d6fa5d10deeb75431b15564b7398bc4daaff3aebf7f4f56f6f9800af27b309ea06e62aaa0e2732a8301708d902eda6e13f9a2be38fafbd1a748a3b9d50bd5fbcc63e81bb021b600d3b158bd71f5897af699b22fb11ec3b07e73a34545122e2d3df58f6d09d6c4309e5bba5720d2ac6400ea6227b3941b7d19a3c9bac8211c4eb38153b1ded251b5dcc886ab9f6a079dce294ab4068fa75e4b63421aa744ad4dec4440b89bcf4ded043d3ed8a11629eb5d15cf18d74fb808a0fadf91f8c0338091f7cffeed5dbd769c49ee9666fbe67999ec3d537e244d15a3164826f09c9cdc7c476361854f3e4fc607e18e88168372a0d84fd23ff62f7bad81c85af5846dedf3eb2e7e68b080102e716e8cfa2c3b7016c18eaf531cb6998fb0f8ebe1455bea0ceabe4b3a6f987f435e839c1a0185b0e6656e3659b490a89cc9da3d3c4327849e278245f1173cfbb6e42bf898750e4f27dbb043fe2cf3fa9eb9f023f5471feea894226b7341ce154d4f40a970890e4085a6ae1c7d5e00dc35a6187dfb5b85003afb93c82c53072239a5bb85c89dc162a62d75623c4afccfa5e5a5a662282fbafcce3a19a33adc3fc270286764c1a04fa0034da5768961c8a1797e296f5f73cffaf924ef4c67ffc65889a5b660fe13dd87fe312b4bd87cc596a5f1e93ee8ea9961881bc418f95f2405b69335ee199d3d92830f32e1ac0acebf1a899b869e510ea23b2f706be0e9fc7ea244975d2f82336145c9f533596c731bf801e8ed3e1cff9836ac5c60ecf900b2b268f9932d04f0e168e5f11f538c721ecb43bbcd36985ed87476bbf9ab719dae7690be513125b84563ef78d085adbadbf0e5188578238a35b2c012226dfc4f3f4e2c0c54e2dd6e7a204b576d6b183d8228621bc99d61007754633d063f14d01f53eaae5692cf9a99259300f5b6c6ae175fa4c5e36f933e653e1a256fc9093bcdce4e52b1f4e70dd6c22ffc8617b8453c77ed6417d7a79c5d16339da223f70329fa595dca00c52e699963bb2655a09d3fd6d7af80417a8fc00ea87e1293598e5027ba40e0dafc52c599481824944e8346af799ac19cf18ead14e3042b916494bdf24b809534d112cdef10ca68ca9d5ff7426bd20f0bd2c2e751e5e5819f3a23fd27011034448a35bae140025898911ee3dcf9685a3e45e1cc196ddcfac3c7f2ca55377820e8dafcf4884466aca1590fbd23090224938f4efa18130b40193543fd8d121b28c81fa4d8573c11d34645c21d72a8de02c102e0919e185e297a803c80e67e5913db1fcf703b35a4189206490811f3c360f2a693d0b4e14433573eac92efea9fbe75a42fa4218025e9292cf7c032487af13bb27d0f17c0424ef67cae95b61146f8ca345d11f3ec3a73aa13fbc0ee55db5e09322dfcfec3f538ff6320aee44421aaaad499b970516115ca40b5f5606ce3bd3cecbc972be251ea2c5296569b94856d32c3d1dd416940ca7582de88b6f58c1944ce5d4ce2ded1889f51828a388ceef5e1d455cb7edecd088d72883eb7fb7e9f4bf049a14e04ca607c55530fd13bfc8103ee3956a16fd8fde1ca96767ec65b7f093d7ac4eeddf2c81d195a1d36d53b929c20e104200a782be5f65e2c440e668ea90372b28c798036e30223bccbb05f2dbb12cc6f881cf2335756395ae812ee748a575c8c6bf7ae37e4ea0651c0b474314cce545701d856cc161db832e05cdf6d45c65d23f5123f06e2efc3ca5383fdcdde4a7eee74c784ab7aa28ea03ba0088c33a340d2ca802e7e3a7660637f9bd4e9074f5ee66a5cfe6db50eaf04eb1cb35681ebb58d04af1f9decc8069c99482ed5149fe26e7081b08068c4fe71255da45ab86611faa005fc7e109874c1cf297580d972ebd0a9ecd4e1680fe7c9bed12373b29d1ea89a8a8b1e71e61982b0ca510b91eb7cc61675f6685b5f82619e84111f6ecb67629fdd68408a0dd99cc35f64732699478452152e09804b9bdab1c3a4ad3b7f8d5d2ba7d681e67c0f154334188897340e75f00dc696ab6878a1e56fc5f52ffb98b9df5920e0e4d16d925df20ca826c35f532f53bcee85c214e4de0188623ce4297eac5beb467bdd1f4105d66a35a2fd1449cfac35db89dc89617ffc17d2d9ca8b4f66e643031bc4c7a07307c35603c8d7a716d7d1dbf32cdc69b7b048f4e5ea7e851e44748cbed20405576791f1e5a0d3d3bb2c05fca077a8add0b617d7aec07962f3d71710834a62fd656c26fff37af6bacc6f646d47e556c3ad38c6c27022f2604975d3dc494b5238ac7e3d0c37085d98316bab580e2e2d63e559d0ac676ac19ac9f4a23f74b5fa55ab1606608a9da410a0ece97b84721d5c92650c42abae55970d8df3e8ea64dca763d510fcf661663b5e016510127e17ffbe3e9756d607289a8392b43d699c986cf612c1741e6df364163cf123379538f3e96fb20ab00643a3a972a12fce6bd448bc701e3653c8b68c50087e1bb7c28015d180127e8c2ce0fbb6d7ce19209080faf54b54fdd762c94a257330b16370a7678165a70bbeef015459036ef83fc3ace36c171950fba0ad764ba3b3b18c5edef30a0e3583f51487963fb785e50bef936fcf6ef3c18572e3a94d6d515e9e055bfcd6ea86417822849f98fdeaed6334236351a55218d70fde033a0baae77cd1b0203c6104d45c550f8a2d660fdf950f2ea6a733364ed02a82eb75fa9c188c59bfe83809dc9cde6b40465675d349e1c11e44fd2782e87b84e9dff0adb1e70860d74e5bf36873c7490628692a3f03de173cf8152a85aaf154a590f1270a954ddf61427e8bef55936fc588c16df22b3e406e8eac3898db24906657f05c84cdd8fab3ea983a4097b2c6d7c5fb888bfb592f7208d362812e32e7988b98bed49dd7f8638292418764419d61a12a7441f55b52cb6fdec194f70d21276cfb5f603349b3d8d3e23a5999d9054112d641373f7c8fcde8635094da4d2ced38388e13ca1af8feca88e6065df3cb90ffb0571537c8985f58e0d828206e29e10380d7d70741f00039634737791325bf486822e7cc2f286f727413b4166e99b1dffc99a948aed6c650089ae4505a7247d9d5cc6c29810e73134bd21563ab4e8167e51c9cfb599787167e810962d43246a2135abf246d3874ab1776cb6e6cb80cd38c780451772996ed976f20418373b1491c8c322f9e74ff0b0245b1b93e19026d6bc9b2489ea09fe5f7fb3361909446472466ee6409ad9c3fa9224ebb45a169cf9d8dea2978f86236d467daba46c27f8834f8d7215c68be602d3ff0dc593fea75a3dbb25086e0e9dddacf863ace017ff0c807a2d2fc622477c31483ea0964ee2d8f4c2d4717102e611f2448f31375b8561dbb89ea8c63eb59e1b4e3ecdefd0d60361221dbfa72b3a41148dd79001bb51a8dba7b5681ddd8e9f19468dc83d278b5091f23780e728da9126b9d1df7a83b920d5d29e981f984c0628427d5f2f8c27b8eef03a6edec974c60926d282ac9e774fb8a1739861a20e6d41ac222a7b50e4b2331ad6097f709b98767f13349cbbdf67fdcfc5cce263267f263deb593412ee7f7f993019005a36ddf40e77a96dff17fea4cb3e5f8ed385b1aaaf32f8436d183a47b6d83a097782bd426fe11f48545bc388ef0552f8c9aa35ff3c2a6a9130a4dbf878d78e42e021553acd45cb934dd29caa87a5d11775d5e7ea2b2b59caf7d66cefbdcb0957fc0919a7c6413008306e8522ff202a929333baf93f32c30807f9a1dc1e7b04468b8196bbbe37a95298d10f09323b76616db072911df193eb5fda36b496b306a23b18f92abb9813061a17d702c2177b8659634df53b5c4cf9c9bfb2173d079b9f8e9bf1d5acf2a8fa4dfdfd2c120fce91e6c49c1a03e32c0ba1cc5500e1ddbebca8bdc4a1725f05e0b206b9bd0955ec487ad45a8116dbaf7d8005dbc57884523393fcd04fbed7f3772f3d20b759b030a6be8325e393739f392dbb2590c433ecd7265ff5ae4ea6c074d236a04399c60adbb91e8b285064ad7cfa2a9976d2baad4c0dcefd24463b876caa803c684cb4266caa1d5d4d53b8345f21c4edc7d3455a46973a57348a799900b253f2a8aebf191c85a71219f196b6b73213898c455e74c87ff9697a07126b920fd3ca30df5ebeff107311832f9beb01e77dd4d6a151cd70bc2a3ceeb73c4c4b82ff90dbeb1e8d9117bb64f5b94c2bcf80fe548f4bd45955aaf96f2f7723b84589caec4d3ccf62a82b34fc433c2469c7adaed81db6af42648deb915815bfd018afc4c59ef70f7160c2c79c3634d51104898e065283e1dc1a836930fc1ff218139ed7983cc3e4e162dca1871c4fa845b107d7cf76415c19abbd730f5ccac09694ea9f931628e677d1ecb294c1950b8b15ae526ae1f48eb8283527de4cee8a29ee4e795b74d0625cae5f2b6cd385d61ea9bc00583f2bc708b9633d0e42c014ed8cc400146e8e44b174b6d65458123d671a1c4caaa1f1a01e6f4c66335b27fd84837c1e800c7752df3f45d0f8a19eab29751d4c6a7bb89accc755f9b5d20b3b773255b17d426edb43ee7da311e66c254cb575ab25a98802deedf640334ec328ec94b32b50d5ee6b194f304555c14ca4fdaee561db465fe0c56d62809d56b61e708e5c95aacc9b57170f007f1938dfded4b327c3bdeb6b423659e494e3bdb2fdc68cace7211472b530d0e4b6976f26cdb0d220462822516fcdfbe0a2008a1122e98af5131348df770c3243dfda38fc449144f98188ef2641ff7f68022eea90a933f92af5c143974e38687a70b1b3bd70a43383b1396ae71eae186a53812ee4698db19aac6ff35d79dc658ce033bc29a2b44f7d0b7622e394d4190c1c27120d56d18f39a038be8a24de373f549328b4dc4453fa94198fd4a0d8ff7b132a44f34fcfb7f888869b541787707c2a4160defc55d75020f6c444d1a65cddb2759dd60c6e7b26c2879f7c3776e22a8b57499ae48aa957bcbafea6abd19caf3ce14e16f215128d56d9b59c084e5d08179cbb6355cfad0b4b318d431be245664fa36455fd8fd193defe4585e4860f056e0c25152488688277b9540e6b6269680c5d0943511dff73800b095f8f77444bba6424c81c6004bfef8b233b32181d4af5ec8b5c8ec65e529db1c268159368b2a6bf4eaba91c2756ad8f8b6eee79597e4ec71a1365964fe3cfcf7300d97efc727c897f7d49eacb9b3001fb4558c46f64a280fe165d7b065d3e4a9ade56eae91de04b50b93767609d716fa99c93960ab27d7084886aada110d2c862b2e01b02294e8f8c1eb41da25d89c6e709de498cb358b2ca1cd4063a01d6076df33114e823c62fe95c510f17ec6601edcf6c29837563ed4ffa777df15fc1a1e27668c93fc8bd2abac7c282ac5c947f9cd308228cbff9aaa801cbbde757a566ac313084baa7f312a6092c2ee484e2eccb960db438abd88e425b84227f283225732c0d81f29264a6ae7f35ca4da0fa81bab6143ee99a6853b097e8cd73971a8909568d4c82fc041c0e52f7d2f872cb7b039679bf6f5f6847d45b7a5531173bbd6f017e028acf3af38471011ee55123523d4006f84163023b6480180285b929a02c5acb3d73ff6f0f1be99ccbd253d0ddc450278c8ef7d3fd78c8542d72e4a02ea2fa9a7b345dacdabf2cb08e7ecbbaffe3a08dfea3476666c2feef235c780c5f5a22b75d82898bf285c4d625861a133c13f1e02b4a333cb28bd600ded284d9612bf9c1d06efbf9f15e402844f6b9882f650c6fb1622b8ec2a3be1e490aeaa5d04e1c821b890ca7cc53ad04070d05f0c684ef98de55db7c17df56840da94619a3630c9697ab7442976b849854a72ba981316914fbd4b2d9bb8095bc9843fb4d8dc1e3884cbb25aa7777ef6fff6e1ce64f76faf8dc82e3362329080fa735746d925b4836c3a624d614804abfbf1a63b9b0aa0f1790bbab35a7832f2b40c8af0f243068ff606cea94c356f15221143b199eb0a5c220d53cdced82d01327918d5517cdd999a0bf62986a68040dae60f74062ef3dd6b39eab222f87e622b1ce17c88a2e2468b293c89c6f4c1a3cebbf86c8fa38b72e292ce269b423fb4e428801962447d159dc9d45b0a05a2d88ab95a65e75e25c1f2368b471b7af0c84126e011fb13ba7c7c960afd7f6cfb42898080a97a3717552a0de6a081dc667de14d917dfc342fa1ef84f69f1b511906d7d015d092ae2e6edfee1690f43d0fad9f0cac4057de273065b4b9fe8e9fa273338184a1e82c3327cada5e017c2d8246096e6646029881f75e668f96348d4f9e66113b4bdb94339ae6b28fb2d04e83a00a61b13f3ceb2bf2f1e682896783f8ab60f4c5ea27ec577fde9dcd08f32d1295d09850095ba996036e12a242a304a8f184c0391107df03b5ee872c7cde7cdedc397ab7af2f159e0b3f6c814f1a3a419ebff91926df5ef262d002a80de56d6a6c3da3d486c29f544fe418c7bf1e9260bce95ad934028725027661631dd238dc6f97dd33851d5c68a4eba0596ba07b09967daf43371a2b5bfe075a2c1a63fe4741a02a270fc2f0b3f22e8690f79799fae207cafe30228b618c78b8b2b87c9f5aabe27751c4e0041dea874396f702e6f7599b2a95341da543a8e095d8b970fba9209330b69db16c4b25e8bb48243a6ffd50147ba3a352568c2c497e69b6858cd2779a280309f6bb16b23b8e4cc93a28416cf9579f604e5cc3bc2fb8e061602cf970f425eb5f1442d1c8cd285f7a43c1d0003feaba7a6b396e2f442116b19d57ad48231d1fc7d8f478b9878f45e0f20aab0170104b175e41a69e7efac606373329abeddb8792c7022c78fae4220afe27d5f6114ea84a3d9651a8bed1c2c3ff352b5fd142bd39e0509b49331e2d66d968f82d681d111a6a55bcede7ddca5b9e84259c98ac468ced96983203634030136fd008e57292f6040054752783aef30904104296056502050a140214081218602b3d510e4783449b28d3abcdc38b0a25395fd32cb613e27ef9b4b72f08c743e226c26493e8c88974eaa18bb8db892d3edd37207152cdba873c97daed88ccaf604552a12ef8f4f6396a1473f0cddbcbd74843c5c1c6e77e2c6f1449c03fe9eaeaf281a06dc7b798a6d4f1322bf0ce219f535309eefaf841af560896a75ecd64e35db90b55a7f57163e5c4b39e1319ecf1cd3485f367413d2d3a8d854788d0374f343924bb6fe6074d23dc7a61b5315f6d5903bfa4c0d460264898ebb8f33f991f948c861d1410eab4dc3182e7beda78f805a39aac2057186c02632584e4a6f6896b4bbd2e5b5f88ba08b5ef6553a18cf06a22aeff21158aa126e53388fadb3ab4ce1a8eb30e17c6b17e6911993cb3c84cfbb38d95ba5e326365696871f718f0ba1426562f16a87b4e0a191fd2777abb60f40beea2915c28308ffe1d3ea1e6bac9ef91fd6c77037f7e623a7f93bba795bdba9bae992f1d426e4698ad4a9bf279122a2235e598d673157f5b172b7c8f87149c1eabf0bcb0b50c5bc28479d3a499ba8a92fdad17be18dfd388b6091c4001820d2e0709c2778430c7efaad2483008dab60d4c118e69f48f4b386f62cfcd3eb3c003590e542fd09d3d41be325ad91e8f7bdf7a5e1a45e6afe52de5c095cf6df491b1c80124e42ee4bb016fce16c42636892fae1befb1ffe5f4daa410e3eb618c12313696c3c5d140a9d0e895c2558e7082ff54d0c63b5a8cc1afd085d06f44d5759082ab7d75eeae1cb6214c94af0f1375e8302d18e7190162f039af3e014b2086863e24b672bc9c4070731b9af7d7cd8f859704c65b6f3ad8af0f33872c86ee1009815c6b125fd52524248eaebcb581650c9108313cff1735d8a2aaa01eed4f92c465b34b25e7e49ceacbf83dfbd0388aa97e4d3c253ac63ddb23868619f8312c086dec5e336eb53845a0598838d88a502703870a3f415f9a78284ff166df94adbf97cb1b67ea3bd80c1cfd6e92c4112e59060445670f949b7ca4bb45615ee27a8b4cc8aea86a1d408b01212bbc8e144a6682d3d7dcd69d5ddcad847d8c95e126e363c34fffec62fb4130a09aa0685cf7f91905d937bcdadb755c33da77aff7487c0b6f5d8397b6ee11b8f2d3ea36d7f8889d524534702fd877d526bf90645d6462cbdcc6be91d93f76f3d82f3fc8f7840b9292f8dc24507635e7d5ba43935993b25cd79b4ad28c83c2be41dd41a8f7f13f4273131bc5c9e30a6852b7181158a88bb60f6a8deff6d564438e87820acb86f4cb8e0e6e1cca4f6befa2667709d4881f422ad5331b8f40e22e2db8627f6aad6271b755c2e6bea2690c1fda4ade5041006f71fecd402e52aabbc905bad559e55f3f9fd2b6176ddf4b8274ac42482953ac150a1e74215110558334577fc1f0ac74560875224dd9785d10f76f8b8398af3753bca62008e5f9f04ae4b06699f3cf50bb75fdbf0795d789e78f5c10df14ac1384494b9d94e004646d558b168cd6019496dcc7480ac2eed6d5b92b3c2329cb0572b48026f931ac4d4e08987e5a54d45abd290b4259211bb55d49ffff5e87a51077324704346236b248834f5a2c0f6965b8b1131caf897a8a904f859f0dd23070224244513074b2e074fa2de959307001451d656138427976316a88974b9c2eda9188149885fee6910ffd97bf1f0c8a8385c8663e6d4da15e982937a8fbbfd233a69f8e0a417276c74a8d6f4e5cbf9cfebcb14d0a568f5e259bee62df596dfc69f589fa2b9a8e2d842f233a5c08c801360f3ce1359be03eed8a02f9ef758bf67b55f38443ba2cf14dc7928c3c69a78f23ff0950bd17e3ae8e2ddf6dc93970e386cd18daa568af8bfaf70fe9fed1933709effbcb160a7eddbc2714303c0a68919ffe9d1fd493c92d9c859f5dcefe593f6998025fd266e29ff35be44d60efdf99c1191bc359afa7971cad921b0ffb6e54692f3873b2435328e514d010cbf7c650eedcde2bd00d7b8e356003568254a491814b0eb27d8675d50014f42f2cd96b70c3e7c263c822129edf47eba8c89c168d9f4f86117daa4472d03bfce0fdc442f2b7ef774a9133263d1a64c09f5e83ba4699371b688f36e9408ae6e36b7a6a3f7f314b698671096e04b0a75b4f7612a285b7dfde47a9d27a6315af417263b47f3fc05f352ee99304a06b89f6b145ff141893d226d7f21e4b7a122c7a3843cc281840936752d03c8dd8e450fd80cf75493622a7eff1c005a38c7f58deec43eb4a19dc7f7e6dff7413dfa34f7fa257965738e242273c3c7d04cfa52f7af04813e81c667f44af121d53fd528c7f40f52f17784e522f8033b1426b1d665b902b71afc6d536330a1f50a9f3a3e473dc6fa1ff14ef06795f74a27cd442525d18276437e73d48caeb6c4621aaf87fbdf13fea84d2e42bef444402d6c813d666cad790efca3ab9c2e42da6ad407a3245fe0260dc47e8950428a5320f8cc552f0ec8a9ad62c988dad1750a1b3fda05bba493f2f4feed8c5e8b62b013c582b9af0ff57be9b7f0dabe95e2544373cf41fc26bca148c04f10953169d9a02190440c6575713e193c51a79841cf39a1d8af152e796e9f1cd03dedf218bd61d2d46952a49d8392e05bdb38eeb44a65aaf68f6f1180ff7a5b97880cd1cb125af9f243acac686c301ca5c6ea66ad337742e37e841802633743157e24a45d98617b0a7b81e1c422b23dce7b70f8b22ce1eb6c30d72752f6abb1cd60373ce733dc29e9c1eb49db8c2cd650dcf65474ac6a513b50ae726747355daa1499c0a046b6137c6242eea2082f48cd1b0603e862b1324dd3faf21fdb5bcb6350fdfa15f0b6c7250ac1fe7c25181b97ca825405d4e6a804e184c2b552d69f9bee5cd3ff9522f2afc54c21e080f857f7a29c9eab221eb7cb2bb05a3f21fc50fff833ddf79ce874bc04931131c81c6f44c32de2aebf6286165f6e718e37c5f838ceeed2d2bdba1fc9ac8158d26b8d7baddf65506b2fef7b02760e80a593a21d47bb61b8d9ee322a17b726dc6864622d580103c73593be8de100ef34f21391b755b4a97db804bfa105b94d257f6d74fc4b013ddf5817cfd32a6d33c5bd278cfd51df0f7a52db8add2a15385575c1ccca48e6c2eb5ba0b6a6c1d8daed1dfba21900e6ee08d871124779403884fca6f246289d876cbcb6f4f280af58e09081faa0001e0405206fc83241b939331a3799e68fb9d0ce7145142a8bfdd25d7cf885430fec27ffff13e2cde999493c3881aed36f51b3da32fd43842c0dac1edd422c5f8b681519eba2bb579af57bdbb1e27ae4150734fc9a5ffdaad5431ac65ee829cbfed3e5ee438dbd7521f39c40306a91bfcb05f8685f3b6c709238ba5b2fc6a4375b796dbf14ccfeab8ac8d26d16622097fecfd2095e559e9a34744e107ed7812824fc60b63c4b42016a1ec9f07737439f77c56a2527dbbcc2a44677bcd4a1d4de31358d2db9011cc40ce2c8b85f65ebff8782014e9c03f510d3c7546bf492f824ae6e4f7ceacabc37d21191ba35577bfa75f9134cb6cf794ce935b0f34f2c0359dd715c748f47e112b0ff717b962dda87b772c0aa127ed26e09cf5d2f7d3be13184cd41c5081e5419b911ae1962e2a1a064ca9730108804ff589316a87f87d20f7c230d59127a098a9288271daec91a1a97a554a988222ca2f6a5e28aba75f29ad184079b18cfa2c6f31791b0b41806d4924d6eaed04a9392a5ee62793b3fd914d7593a2cbca211e9df7d0edf33938387beeaf792fc50c9bd55f2ab76dcbb8e2d10388b8b1b142d574d94898be87395fcb5ab279b957c4cc15c040b6394f7ff6b826d93f29eb2a6ef485a09c34db1735eeb3039ab977243f2e43756b34929a87ff1294d26f056391195b35857442180ab3281f27ce4f113633e15372c62eb529434e600bea8a45fc64baf66c880408a90b310edf480261f6b272deea46f2dbd58b835c74043d9d6abd4c046e9690387ee07eaf52ca4c2b969a00e7f167f8875ae148ed54fa1a6145d2e33a6b148ef99fb0c84543b6af799ec6a185a6bce7813a96a6343a50120db79302803fc619043df0415e76c39c625cc1f33bcdab9739e597ee9f33b8a60449d24ab5651c9d0d037ad2978f51cbcbec0edac8ac91bf33f0c56f29ed9111ddb889cfd9250d96bd1c170758b7d4ec00ffcda05316bea4465f52b22042dcae3c2f2d8a2b653068f82752af9a35815465445d983669fd004e3d3d2537e352a187bcc8d1485d1492cfb9c31e0933909e3dbd25af1737bafe5709cc24bc8bac00d7fdc917016def88fba9e17e30343d3ffeabfaa37f16c0cb5c596eeb294387a285bc566dd6465c011ec3eb2fc5f8d7874780aad952383fe2e58512979a77a16cc2e2caf8befa2d8dcadcc11861f95132b3bf7782f32a7eda4f919817304baded27d984d0a26cee3909a1f92c5257a26c5442cc9fdf5f6774ba17369414d3de5ee739f84bad0bf5fcb6353c27d21a5c4b36f6df733fc454bb19032dad9d17d57a5bb932c785dd5ebf43b12adb788e0c9b35f52992a85105a297fc49c53f8bfec1dc6c530460b8234863753a880c683a8a29046b538b0d966b181d2f233b4ed35c17a949f2810053ffa8abbba3e659fbb103dd545e7920d870f4ea7207fd0770a4fd81dcb71f165831a33063f3b0ef2259eaf76ed49fea652e8eb42ba2b76383b1a045ef30db795c1957330031b866953b3940597c3fac181fa40e707a69032684cc5558318d9dfbfa5c70127352c79030563e89929564a57046e42fcebaf4a35271b1a895721025ce2fb2f8a3b4c2ee1d954ff8138273a8668e256fc80b10d409b606e894fff7f0ea1ec7e286469a1a840b65c30f52dc4d72717e9d731d2f842e78bdef7dd22d911f44aeb15781d03e48935e940c638cd7c0abac9e749446a1b250479bb1e6cc81e5784e95ae129e49ae584a34bb1bdaa8a92051de5485f10a46da73132cf492fedd593e788267dafaf68e33976814fd61fa7e5eba3be0795cfda2c507f52aa8808272a4ffe5bf845d533a929986c6eaae4cced4bd4fbffadf438cc1b108ff8c61662408eb0b18d6a97c19683df93168a09c97d940154e96057de9f008e43c4b05cf3ea53978c83a80d88993d497d1bc8dcb23cb28486a1c62ad565440f83c138a14ac25936b77896cd9ca8458cff49157d154efa89b6f3a976e677afa9ced5823597051185e149688bdcea4efb75915972f1f9349a162ea965b8aecc11fe63060cd687fd8276baaf662f5cfeb94623f5d3bb2e67e50df39f4034ae7755c5ec10ed24dd4b4abeb7c66bfe7ce63dbffb2ad7caef13e7b1cd50ba51c5db9b235043e12018dcfc41d10c98bafbc6adc1f0506df50e7dbea85aec6c26cce568dbc3062acfd42f9ab0f3157763d4fe770d0f66a3e01f0a02047ebb9c7ea6bd0b2f317cab2ae7cf2075132525a3b6c1ba1a7e189328bebea8c85759f2ddc4db4961e7f4fcb22336dbbcd0af09e2e6da8c4c4ce202e2fc3087316eeb18fe5c2168f8e384b8316ba69774202d93924676acd9654278df298f6258df8f13ff33ca5d964b1ae5dcc40992582975791f5d861c0da48bef223644609246dd64e79552f47d7568f55bd22701ab166f604823b1682a7e1a0ac35efe0cfd34cfaf48773c915ce8487705b37f5d3d714f1c5066aea87dbaa963815fe7c8233a7b562afe4229de64d7def4532c74778e873bff0586dc66343e2ad3d795b970b3f337f26fd3d97095eb1091e13c99df47135ad179b99ea06e1903781f17dd90bfe47a237dda3fdea67e4b6496ff13c3379ca61d9da0a505437d7d6a9bd4cd6cbbcc7528618d6dabd71a4024e7d664ed5742f7149428c22ffc521a1cea1a1ae479e445b230970b2a1f1ddd694d514154e6e413d855c46b201b02d9224fb0cc2a6df09d933b1cd69ec397724185180eef0f1d96e2d46c8c6eb222040b05ca970746387a9e28f38540515adcd81351cc075c83f6b3d9dc2dcbcf936d82f4b57e25e3a5fd4657669596ad37d0c55e415899ab82937f0a17a66d9c7203dcce187e8cfcae093522a7e0d6130ffa41b5578a7f1cc67eb0cf97472d3ef270828401e29e068bef4ab0e374fc76dd2e3133a87222c882db66e366388eb0ec040554e42262535c806af8b52ef06efd7704d6fe7f265986510805a6906003b3bffc92ef1b45cfe383b46327fd474bad3f85fc682f9de0be9da17ecab8269f729421f8f12fdf3fb0375e9adf5a000dc6da4eefcf828079a8c6a387e46445a8c857a75acdcc0b5b23841a0ecd73ad624c36ba9f1c06aec81f8e7e82c7132658100173e223b37447ae217bcf0c10bfbd963a8a3114878d413774fb11078600e4f13d14aa0255ec6b88dff4173d47fadaaef467ed95f592ff077e6c9564355f3d8e8b152e75cd9fc8f0627702ec26666f6a33f9d40f5408114b73a204b766374efb04e91fc476b079c78af8b5abe97d581858114853c9e55d5d4fdd4084f563b20ee7d86ecac0e3b5b9c56bf7de0ee720c4baa61e3d125ef16ec775de3afbe15d1afa7a704644747312155636170df0c0e86052de752e1240177d47894cb6379606199acd8ca2df71fa5d889804187f5b2f624f1e43d7e456efd91de7bfbf34d86c97470f6adbc7c2b412560400575738631f886c260e01fe321259ee37366e563fda994f6b3b87dc9ef9b380a790b50a4014296906080a5d2eee3a9203db17a39532fb65f8c9d0031973c97770186f551540725553d3056600a80697c3c27f5b5a7790fa5bcf1438b10e8a8fb07a3ee773e52836a61a0ae58a85db8419cdef6bdf93e0764f56ce56e6ed60c0c1115ab9e5520f3aa0285a65662ff18fdf411e08c835c58c726b1c2cc7f3c1fba8dc5f71f7e6c63571289836dbdc76989525fdbd1961ae6996b6dea62ee2b30d3ca6c81854f447a4de0d2ec1e9cffee96456b7b489c42fa7f9993578a57192c7215d7e70fdbda295c2ffc3f68fabb3b2ac0ccc4d6be3c818815300faef55cce4edd8091b616aed0febaaf98d9f38a90c625887dabb136a99cb7ff9286c08fae8a5124d5af37b6f9780d7fc8a6b7f145a04ac5ddfdb8dbe63b05cff0e0639c7d098fa82a7f2d34cb6b46f24e0d9769a55dc63c0d60ee84d8fb47f208e7da88adeced6697db235a6ecad49a203add6cff1104a9dcd2513d473fe2ba4c323d77c1cdb5d851a3e0c4b7ce8abdcc78f27f1bf21813fc3b74caf15977c669de777b8006c97dca03f31fd0b1c45944aaa0f3a68dd6f84337b2f12ca81966387d75c70bb08037beb1dd65179f7e58c190eed015aa07133c5f021f043d107a7ce19c000cf0882fd5bc9ccb6a8d62bf8a73fc3f434bec38d7f5c0cba2d9ad9d4ca8b058e02a259898fce1c515f31b28d29810cb07015bd2e59c3419e7c03a5e1268d28f6829e29c807a9726312998b23ec901d91e666a44d05561feffd7d1f6b0d4285d96c0df8dc8456f0045ff130a9da13194c582b3eeb87807f13917af47c39328d8d362963b8a7d59f80c5fb9d9bf4d56395daff0da512b0333c2dd31aa12fc7d38c8dbe23aeb9c738f59a875185f4952b3d161ef718a76d40ada10c679d8903bbb9164195a3758ddebbdba7fc294efbe3a5e9aeebb9460ea709ae7e57b8c92de5eb78cd3de8662240f705e24672ada1577ef01d365b7dfd6d18fe6cbeac5f5472e4b9a52aa25c87b6139c1c70bb9cc151598f2b4f141cec4baa082aa5cfe6c96878043274bd545be239008b938a4b2c90ba65902df19e7d2a5d960bfb40065e538243592d381c3f3400bb5588c438c9b20a126f2efe2c626ecd6c18d32fed424938d5d9e34ded5a0eb51ab2f461acd537230afcf1159d9916c57208569e81870abf29ebfded27876b0f47f2ba02f3fe11f18145be88e7197725638d69de1076f7d7ace890b878b377524dc1857d2d132373de9679193adf1041f9d9b1e1e0d52d04538886aaed20469fc15dce7cf54f5a8e8ec0f928398704d7d57f4dbcf5e8fe70d1780e0bdc7f30b277b2b112ade9c362176b440af762e2291ebc84a9ad95654120a69fdfdf2489a219c9858caf20df0a41b93520c8b89d054014909a90a0c5691692a9da626caabb40df23d00c10abe9bf2d8feb8c03eab0db35344b2e0ce6909b56c451d07512557428b9ebecd706c966073ab5624747098e88dadce7dbd365d383dd70b2967707f26f11d5bc6d5a569c80995e1a605292648b3468c49b3bb3a2b9177f586de9b0fa65b0b161fffec389f1e2ef5957472cb0cc0fb2f18a52a04de2f58fc71fde3d0a365db0f37d63c19676eced3a1c9b1c21ac60cbfc74d54c1d810092296ce1e39d639a14974ad9206f3266761a1d9dadfddf61dd83f61aeed244ff500850465f5f5041968c093dac42deaf3698661498140355279a9912829e458c6013f596a1bfdf738c50785184e81df220e0190d8cdb403c22e04d0765578aebe476f70943421ba459838b12d378cf68d7e8564b898f0d1e3cd2899c04ba51c26c5337ddb5ce100164add7f116568cad50a1af4d1b9ae079ef28354f15c873694bd904603aee7787c23128ea9c393b3a97ff0e8fe1a884b0501f56867484cd0aa150ab0423253ebdf2b1b9741f20c18d3aed7207fb2e4938989592da120e8a031362da843571cbedcf9ad36ebff462357776991c92ccf263d01f3cc12ab96534fd215817effbd0932fd4eed4b201bfb9778c1ac276122e539a2f2d43420292f5e0d6fcd05bafd722bbfe6399deef16c822697b03a786800207a5a018b80a2b4545400e2882a69bb642ada6132bf8b37d411b74d323db15ed7965c95be99cbf4718b0847a9eafc3f9cb35ae331d0cac1bb004bab5be04b105b9d9604a7aabf15dbff456fa575b74399a2822cbf302ea5798e0a58f44ac93c20cdc3c41b020097919ebf4c3c81191f275a90b64dd0b41abdae4fa51c3967b683cca4cc0401a7f497722d44acd2fa447925c9dbfe62db341e9980a8c3f394f70451f37d09959588155b63bfec1eac7b6911425c9a984b366a199040e024425ffb7a8b347b6f8a49ffccc8e2c5eb0a55af9aef89991cfb5da90078657a836331d7c4e07038fac9ffd73d8c4d5998cf249cf9aaa999ce21b1f57f21634da10e706c598bcc6c16d5e7af5b70fae8a8dcd39e3ac9b6d19ecd37c1b7ead6c21a942e872f9c09f072140fbfae527ef982e331aeccaf4224ad0ac6b518bc69e07c93856d6b205d531d243987fcc09a2a8407cd116f5e1a46d5564d07e3543cc80108e6c9fff753c5802c76d7934ef59f1e0ed94882886c980a0e8e8ffd14b9f0e1181edd7df6dd1dda78565e44ea64d9e73c3545286a2816a839d06f85010c5393991a1be1f2c54b81b21dea50b545965087ee246f826af79959ef06f5700cbaaa7535ac47027232419fa590b05f5ffdf92cdedbcb324b44ffd9948de7d249329dad50c42998f6a08a9f83fd267011a97f6500ec95c543dff42a13d5c8f3d7b05105778cc6186b52df6317952db5ee0b6fa23bd756bc6f177382070a7459338fd08ddda4cda8fdfc0673e2df8212bb033e4fa8bd2562476b8443bdb22ae833a098b827d72db4c5ad90c5fdb280415f21eb16bf951d1406dd81a19ea70c1f656a93db1e48df382857998dd1f27c6768fb97e9bdb896258e2371f6e8cf093cffcd2c41a094fcb4932da7c3e61410d0deed86724a55cb522c852d23b3cf7b4a12e985f307a187240eec1d7655b17d6f90f80cbb66b56f4932df6403bc71bd9c481508b6218f9e9179306532ff483c5fc16f1b5e93c443fceee85baf5ecb1eda89fa3f3251705438e7946a1990d6eb35e6b554510e90a7e621423484239b54bf82f47a1e112090860b96838feb707e77f271fd455e53fe948ec698175597cd940ab6e7a0b2f8b1fab893fe892d6b83df001be8254a38086343956b63467220d31596859b6e5a27daa2d648ba4b8b4f613641701b626a7be7ef77561240e79dcc09c626add25a9622f3a8aba227c565edd0d445c6297b27565ab2b91b5ee98e8bfd062bb1d04526d1c22610ddc19fe6712f385c12640ba3eae5ab4f59d35f86578b51a7c7956a7d7f93f2b9d9f8e9ec2448b97838aa9139a44a596133b216d664b14ea75de30fd50b65c96823f9f0c8004bda28b636a98bbf785e36d5f5ae4085226bbf3ca1027fa69b0d6574fa7eaa08ff4b29c4f7224a0dfbf05cbfaa61d485da4ca3e1d79c111adadf2dafd1a6c379df0502fe08f7b6cc32d12771ae82fdf75a690f33b3a4bfcf884ec46018b79a80130bdc3b71b35123046113b63554d77b91c631c4afcb5489fa03b4e713c992a6df8f5f6ffca884f377ffea970503fd813907a36e0c2470bfa172b82d75c017ebed4d2924f505118059fd01ba45ac167d1e80bb46ce1358f1f92f06e8d5c3870f003066eb9e3f618e4c022b7ab23d65546c8737d873d894d7d0e013d38de9b3fa7863fe2893e0565c00068d3ee60b4ea9d6b827477dd4a0f226dafc3d641020480d77b3b712de79d2567188dfe284d0587c35b59887a7d66f89ca365000cb88f5b9757fe2b5f248b9be56839bb3ecd48703d7e262134f39c57d5914b94e10dfcec08d73b2418d6b055666e4b52bab54a173fb057aaadfd908cb84c835df2bc09e2e69e0db92f0fdd176a41da0c892a9279a6f1192c4041d32bfcff82ea0e18a486e067377819770dda10006ffbb511f840ac44ceff63d982564683a46fdfc65c3ac85e2f110099bbbc41fd655ee1d5d46cc723a598ad00f04cd139822953b899fcf3e85349cbdecc01b9df16ba3a3df16fea7ac3583756be7f46c9dae825772f53fdd386041646d15132b8430ac47d453f713f4c808110503bf083408dfcf7734883224120e51aaee3a30d46019f7fc42f902293a2e9663a2e97d1bf5aea96e1a75cb4f78d8af26c5b6a4fbc8803b4e938e1b2da747187de23707c98e2c4b37d2af1d64508533b3fd6be51377bfe0301d8cfd4646a82c21f1617340aa6def3fce464934a4df831fc40c976c6fbadc6b12f69be9f9032ca23ddaa47fdb5c02af290488fc47b3ce78fc3b191f4d42491a4179e2d6f503e3fd7d214a000abfadca78c9014c9c1a2ed8e572b9a4182098d7e1a246b794dfb9fd6306acf54f503f639aa9f80516b0c35d91a20aea1f974fd33c5eaadb7dcb07bc2e222514657f6ecf53ffd3b3fc27ee7400e1d65b205722f8521664fba9686a86dd558203ffaaca040c9e8e0a0c64e1101e1358f8ed4860e02c01d1982f023d1c09128dc1525f781deeaed161e06293e11bd0d881dd9d870081a57c630754627f4ae27027926fdcb4898a03404ceabebc105b3e2c6f0f37a9951bd6651eac781f9fd7359739d748dc38f3ae76be80c42b266375849faf8a529c6735d1b0c5dc63a178904be72e8d725f9c0bfec330ff7fbf9e6ece50e9f2c99e6a809ad0d30cee1c3d1590358f62887d6f36581c51139e6d6daad1de42c03aa97bcb05c678fa279ce88dd3f3ba1786e1204ee4148a5b8f3c98d4d9c7b8683f0aa826145bad4145e439f7d0c3cfde87fa1a78d783374ac833b4a7039d48621304120bc0ec0399ad005f8961104fcd7a951c3f0cf281608f111a871821af2fcffcc2120054bc8db3f6fbdc35fc7b31027088837658dff0a4479ab573483761a5c460d47007c2ab859e936052dae00af90d79d527bb1d820141a12844a43fdff558a92e717f1ba64ae080c9f4133aa41dc0dbe490ea197f3d57006152091d9a126b7bdc31806ac4997b9866a55fb4c73bae89f058b3b1b480b0073ca252cec1fd5b53afd3fb1cf8b4482b434461054a56b99c82d2a28f37d480ecab8306880808b67e263a2bd79ebb2fd7851793778be508e5f2d399ef81396e330ad41e8516505cdd2ab48062ff0aa1ee4ad0756779352978551177f1ca85adc2787bdd168aedbf4c180e9687acd9f8a605494c584dc05b0418a20988d5c783c11a728e173c3355971929d4aa79204c48c4b8bdb3bc249e8148da65d922ee56a0e4e88fd23da7f6f707e0cbd262dd95c1cc923220329cd88554e3079bbcbc9a61c5fa66952ac9364d46e1bf5a6e20e439f81c18be69f198c563209ac1109ee777bd165b1088e593ea25b0e63de577e831edf87c65b0498ce6c4cc66a2de9bfdac911f1bcffe65daa68245f0cf8c78f0a89df36a2e8305dc7a43773c5a1bef80ebbe9e2bd9918fc0a460ec768730eefb391612eabf9cf9768daf608a69d418d384fdc2c72803b67a367440ec0eb3c579c3d1cdbff46f8f28f11143fe980567273fccb67b7ca8926da7b2ce0f662be278074dde2d192802a07c57170ec5c710fdb378852a0cbaba61d961b8a4217c5754cac8cfd927cff0d529b4b1c2c5d08f843c2c359ae425ca022937e9093dfce84c854e250e8c8b10efa21af63c33df78eb304376244d030e2ee2c2a205b3d667510542e1b2274d5f0f6a79a9b51827b0acfdcc28ad79a7108e559084b5f13ab6357df7eb602e1d19294322fbb6090dac544a44d19164f17c47da7d4c5337a1efb1009998aee3d7106802da43a1aab2a2016afefb34befda601301a30bf1b16cc7f921045fa5ebf4c0ecabd337293b2516078dace91577748bec985358eca5306fa9ad17c5bb20b793e7d48f68299b6e12bc4e692b9e5e308f908933f3e78c2d945622550c8f02ea84b844fcfb118fff025164747bb3e2b37c97428095a50d2965beee4252ec6da51010f4be3e5af4101052ea14a8672afc4f42956e8c6720e290b81df4db757c24a8ee9d5091086564bbb01fc9a06aa1662870a357e8cbdcae3ef5a0cd191ab4bb32007390ae47dc1767a4b80afb02c72cfc8acc77eca3c1669d039616046d03fb9f18b414c127197db0a56b7973eab3de4707074777cf045ba1760f9b849e5f4d5bbb97a67df061ffcfa45c762c8011e0b6df42b318bb8c59dd7ac48ba524ecdf3c62950089bf9e793999b8e390c99b89b448e3dec6f663bef336199ff25f432ad3d26b170c8001af3f06a9145abd0c8f1e94c4ef106ce3a5770586f69f0d089486b16624521c5900f19fe3f08fd6659f7519c1e30cc98d5da521a4a7e1f247546e7d880e0cda1459e344bd1123bfbfb563d73aa0f9c7c7e3268edd4482e5b4b53911e3a593e80155c92ef3933c157a0c85ffaedd3301bb20c65b4e707d5032d6ca53c9458ebeab8694e94668863fe5ad23388bd20853a51df245bbe6793b1788abe0b3a53ea311464ae13c01f5ba7c53e72b12370f3ec5c519b6984d4fb81ef0f57eae6a0d9e30fc7fb6ea77c9ff0b5a51332d8b025f388374e335801a19a9b60b220b600f34291aa4dc9754a9b0d4c717acef150d83b10a99407cb25dde1e823d629aab48d14ac66318b56ed6a499b6ad154644bca83e514998a8904feba5b0210bfae16a8e41f4c0594126b67213972604d80741996dc08a9d4a41909f1d99c66cd82fbb3861f1c7eb45c7e49401031efd8a391f0cda5d03e37622333390c7b4bfed4164c609f2acf2b7ed446619216b1522184e5319b5217249d8d0a42d397357c6369f470e9ce909859f48f5b7088796c18deba052321be0ee098e794e94ba6543e0f109fefe99589c55fbd98fa06120cd3ad8b5e0c5a7b423a70ca268e9246dc392f589e5eb4fa757653db0870417d64f0c921c92d9620457bc5039c84fbfda82cb216e160e2d27ae69955fca88aea4015020e241d5001860654ac4c13abaf037c6b2f04384e2a8b628ce48eadd48268f81378c9c85759bb0e0a2bf95e23b5f16794a5ff25a98bf495b6cf63fa8d3c6aa02c360ab348bf1677712e3e4fbe14408a647eb3c276766bd128ba39d375266c83d0d0455134e473b1b408df4afc54921f7acc194ea3e562862e668b9f5b1cc136a9f7a05c1566d88079a9a0a4190fb70d00c54fd29d11c398452e5c26bd3aa4516dfbbf1cd30e8b710f528a04a03a3401cd6c0ef3c4aa28cb5fb26a03eaf474358bb682789e744829ef7dbb9a6c738e5571d6388bf0ae1317905c6bb104c5abc236e0b5b61d3c79cc7d3feceba09b075b83ecf60fac4447d4a6d6ae312c1bcc492d5ee120f2687bd792eda44df816e403993a95d2685555d4ee4e8af1c043c3cd9e9ffda1b4a25651551a4e30a4107abb06b84c19f3678325c1c6670b71fd50d7964cd7b662ac56697a6a2ae211699a271bf1801313d39564cb6ac9dddd44589a6e55ea3aaf838b41da4d6cbf3a678c1ff0d0ecb9de03785c9891badf967c859fae3f71cdb51b55c346215f11e95f8f63e84dfea17da85f2b01a963694ee584a30df9a5cdc9464dcbb0b0c58db14fcf8968f247a90d3e602ea818c67360065b24eab175597258df3f8e5e94c0a5e48002ee394c0cd06bc9ecf0d002db4d77c4efb4ea2872653f6ae75f7a31b7ed783e2d4756eed96e3c4f1b80e06f40ed2341c66fbd70c648ec1b4b4fb228b6844a55ffa30e3ec4fb2d593191a6e9eff10aaf362e1ba2b50866e0a38d385cfd25e8f5481aa03a37f58f713fb021e9bb018324c75c2b2f63e2285e7a17c19acd68bae0aba2c7535ca78480523b805c9e4fbe24f3714637325bd162d0032de94586ffaeabd26162b01b5ee3f274969227ee4c8087070935d7157b0a171c96ddb1d7ff2c2f9c6444bcfdb2e424ef73462e8f831064bd5837e819df1187cdb8450898722692c8194ee5f29027d0e8d4fb6d36fc67e004a7791221e5e43b69cf95c7d983536c8f9f455c2c1694280d17502a3acbd02a38ecf26c518e7d3799b91b66c9d0b9606ca7c183bb97536feb293da1eacc854a3dfac22c7e39b6e9fbafff912a73f6269f4a528655234f5b7ab7db5866dbf27a27e5d1220a0a1ffa85b1e625edd41ef20d814a77c07cbfc5eeed7c1a05a1e3e981ff17ae04c2b83fe95935f0a15e1cc17f2a71ab2a29c8dfd59fe20f6da4e8096f4af850e5e732440a214934f8bcac85c9cf1df67ed93715406ebf75ae33823746750f156195a4833dcac7c659a6ff5643e1dd3f7dccbe8e711253b56a9e533852ac4cf7f38fc04b43e9d605620dad483446e56908f1b09e88a8e35e22483faa29e3685d480bd211168682a1bf4e0f7122be747661961f3c06916c35c7b7dba736732bbe76a97660500e2c5ed33c5d569e2b888a4dba77585ef62e536cfdf92473f6971c5d4f412df25ba314c0f5ae82879828f9cd27c2bab4c3343568f2c4a34a4827b5d498925a405f9e9bf32e68c653e7d411716605e71decb010f6a2943328a98a27816fde06496a7d2eebf4eb67029e4daae840a594b406aba3de667db73bab6ae89941eff9b616565bd3f33a7b82591df1c98726df64927982c4d8f42a0fbf01884e97e925adbb514672af858c5c52f8645841e8ae6ef97961a8fd743bb7e3d0e82b2c32b41968160a0d52fd63bdd6d7c6d3bce29fc7400a790448c3131ce2cee2ca6832bc5d07a240610bcfa3572ab93eb58752b62fad1e35a36240b1df3a33775bc8e0e82f771722f94f49406df5b88e71da542627aaca5d92e7735cdab456deb29a33ed9697534e7f3f900ee117e659491c2ac354264f3ab53f0ca61adb9f8c94acd0eb2ffcc20a0c28917ae102d64d119d69b8579d600d2c6db148f40278fd41636de3b331f696f0a9c527a9d77649739662ea06067b237e4de7d1a8b239f0c6efe702cc174e11309c3fa13dd1d2f2b6726fd954e9bd649ef5d5c08207d78c9cec2e0d8c3cc11a0711ce5c73b5cd81ded975a0b71972f9fddb8f8a04e608049ef65abd3a71752f0e304234316a03633ecb995ac5fb870b4a6a7d2b2779f9bff5ba46089ec8bb05c2297c748a90ec4ffd93751faba5912157e174a999a51f085863a1c8d599a4744b06f74e1a173b3baf36d2c43791759e04d659d30d6dafc939afda7415c690180dc061fb946885e2ccad12faa470b25309185e784eaffc965531c1df8df1afacd6023e7440840f75cd07c81e7a0dc8e0dcafa3b4da43ea6dd2c60c0fe1f80877721c07796b01d0c957f7328bc2cfbd4665afb14622f57aaa1d8b4b0c0e1483bf07a454cf4ff7a6e14239837687409642897bf648c0b810669fe7d616a9029f167c61feccf7deaef09ab59a879c7c19a2d8a53f58efb94f8913a11dcf6b14b1e9f4f8be2f3670feda944ea1ad2a820824e66f13c913eb5f53352934a66ac55f165d223017e40c70f951178e69c493279930761e943753c067013d7c23f786782fd148840187ae41745d21bc9f4f8a58a60990dab1e6aa267c477ec6987948e446f57542f05e5edaf22bd116493cf71e90e01439f0db80f75fcb25d9441e93aee9210af1a22ee7a956b0937ee3d01639d2fbb1493e21a36d8f84e12d2e01f2535713118e95002e81620ec3ed53dfdd36c321cd3c87cda220c7970ee6d338bf1d90486eac574f112ce5cc3d16fc394b99ad925439621d02356bf11d792532fa5b0e7215e6cd94a6e7455371fe30ab382aa50efb6369331498c549172783a37b2654111bb562eabedff474f271bdb5bbada24a44fb34ae03ac69524fcf643115b93709ae99825e5fac9659c4572950be5b38fb7e14105129dd041205aa7a2ba554949fcaab6cea522466dc5e22b994148b20d83219ff06f8689ef7c8b42e8db96fac8f0a4e6270ace65571e699ce4c0e27afa12b17c2a1fad1ccdf691c1b16b62baed4184a406fccc143cd3d64df8d611a859e509058f9eb0c6f4b962a4bd0e4d62b9566fa3e6ed94340fc09897d224831455d4f4298e651bfbf9ec0dce31c81339af53b22f4657bbff918832c53b4c9caec4a3e3012a0a159a9693a7890b9922f7b7cd0a6f04740f18acbf930f5c46b69334abed466af38f47668b9002ea5265fbb81186939e8f55cfa62d5d742577a0cb2d60819edebc542d40ad29fc12d4df5d1547803e0250b685dd436eeb383c718814def657fc8ff9f96a2ea446ba30596b3463e2c946a09ee269e096abb225a87d912fa96f5baa029347bb34edd70d05a923bbf54d2d67ebe0634a2263ea609bf4b1bf877db9d2bcad71327dc1578deef9c49c11db085dda2e6c31f99ffecbf1ac8b40c05c2f07bb7a68e07de967c5fbb451895435492f73a1ed6bbef2729f631ab21607e9f073860ff13b3cc82c96c35fc619ba1318b814fb12a3892c724260b7f51f5ba9dbd251577df2f336707e745fb42f98a4bbbc21d07121b57a8b842747f6a4373b4c51943de0c7ade0d91adbef653717ea91f90b72cd3aeeccb1f2503a891f772022b7b8b3efd1c7bb75493b5d37716fcd11ed679aae17a8e59ae9b67d738591c7ab2b4495a6c948187e9a65610846719de7ef43142b351fe6f8519a2a406350af5b902857e108beec1b821f17f364aef21bdc16bb1903324ea7bc19ee30f4dd1e4b5c2707b3c5c5cf1fc8a08f3b350c9f43367b3ffa731b42cab3fe6a4877372d47411c3f091f41d7bc7e138f1a6b68fd7b752894cae4c0f5c59a8140fbb68e0889a1fcc2bc250e55799687b0f6fe723c52c15c0cb4afb898b94cec2fb85ea99f0449705ab8450f9514fb2fe2b049e10667e5bad21e6d41f2d55eda5c974e58317144ca6951833b0b71453df1fecd4adab33ef15c06eed5a61f2a368c1e22464d9f542ab81305a2facd9e15e67718f6b2cf45299f9b417c4e7daa5fc09b07de4226733cfdbfb6d718f5d574f092607754bb7d7ecdd8ce9d4b8b5e6662bf9b87d2bd5a157423fd4678f0b67a6a5e3de32d6bb742ab1b787adb71dc0eeb6e8cb751aeb2f3ab1ffecded74eb40230dadb1f9fb938b58d68847a2f149d1c53e817a75d1801ff16c2321ae7e4b4657ed4b7101bf577befa8e996f8bd1fee92bd0c712f5b470de3eae04308311d27e0854f8e47cb9e58ccb0f611351ee7fdb0535a24f56748533089d10802224a2ccdd2cf216eb2458933be37d5b66c1a0c2c98b2b708d3965a56804bbbc10b2e705ca92531f7f64bbeb5773a7192997f33ef1766df2f291923b044a1850466afa4d912b92ac558eaf644ea49ef461250481efee268686fe4d21563c53df9fea723389271a521bc978cc36b06c4c047a5938d1420c688b8893e3e1fe5a9208d3ef1ca33665076ffc06596eec37fe9b65417bb807c40171317103f12d9d5f4a09281f03d603129f0461e4c52052c7183cd229388f9619ca44804a5c14f8219629024615de5c3d5bac51bf38e00404ef5fe843b0c6d71bd2f74a0891e9019313f31bbd099fcf3f18db5158f5e6ae47d2e55f74317885fc28fc9919b294f55c5c4e345bc8e2bfb134b68805a703480fbb369b5fe4a4efd62c14ff4343bab25a21224198f46c79c22db0006e628abc841c13807e885fe3fabec303d342a3833476c63851d13cdd83b142e0a83a4e526e718d4a4535fab89fd302e89e85f8bef6e3c66ea26ad5c049b950facc617fade63f02d5e94e5c9207f09776f6b350ab3b47b30a83f83ed77d2c498c44b519ae5e2d94a5d172fef7e7e982271a124fd6872105e24e270290de7f32d1f0ffc25aa57b1194e55a06fb89defbcd79f950633bf8712079255b9a3e7c34fd87e74861830dbb004bcf0e18f2ac7eaedc172336eadf18382062723927085cf5d3437d555e20a89d61a88f92916a6dad3b1a7844ad375af460278c9a8134dfa63274b286f61c4480a118822237084c90589c6ec10fe3d30e1636e8315ffd6286e927795bcc4e6391837939041486484ae478f9cab721e27d80d80b6e4176efda765e69f03c5e77de8ee4376b5ae29377f732441151252cc9bf42bd33c3c6b759ca622752d407aa61f28563c93614b11db839904d1a2cc387942e0624ab8c4bf3082ebc067d522e77509ec6274c5036ba4fd73ca28e553d329fa1405453b46c0ae750eb3ef7fbdcbbb4a03754d16ee272736e41f024e30da3f835abc1593afcc3bc11c027b8299a4d3dd8b6ed8f0fb78b86b932e9c0793f92495c77716b1cdfb057f86eb60e50864fd576ff3db999b735f0b29547ad8da067522972da6ab7364da64a79a26bfd5e9b9b5f39be4e0131733af4250641ecf2f131e80e65188c8e12eea6404b0dee0b52135b0e2f46394703a4947eeb9920208f94b3b31e391a459300abd34f78688f8341b4d7739552e41661bb9ce335f73d242815b3e1b567b1bc2015dbce086193a034ccc4bd547dbdbfe0a0574d8fbae7684765cec8cdc78452a496ae8d7b44b2b70b0323554077d880fda40861ff78c6f0a1109cf64eefcb86fd86fc8a8e8d922e1d08733aff91e91006dbadc57a5b10da2186e8a23f4bdbcbbe831103ec7cb342a4bee7046cf5765b72a6bffb9aea16ad6ad5ebc20924ddab833f3fc75573529c2f84f13476caf42ccb721013850c9181893db645747fa1b1b3c1523e0de87426d6422465ac2f0d3cc9454adcaeb88422aa5bebfffc19b3b6328d23e05efb519aacd2bbff4ad49eeadb2e71b449a3e85b4e48fdf842ecfb88d3e54dba617f02add7544625e7cf288b076f2ba03dc5b1d707a05e453b5a7e38b3d4b08625ff9ff930816e96be8fd9f84113d92c68b73636fde64e6c1fc41f65bf0b58860d5fa6b8dca282c4205c967a5a1b1cef7cbf5faa1fbd9d792e2208f891f8ef0c44c7947f0d49c55b254b4c3f9a76dd718faa7f2fe4a3237ecdcf8df1dee55ef4bee5cfcc9a98bba530a854bb63cc3295094a7719709eb2d0f155ea8b4650bdae1493e172ed05e6b481e7b441b6fa4ae637fbc7ea9bdfda41aae87cfe9c2c4fd1d4b7b6f4549dba87075a5cdaa20a34c49e7de63c530d321483cb971f1cde384575598a549f8ab41428b187425b7257bbbe9bfe5fbfac58ca046377daee97b756334f938421efe8167c25fe464de40fbe509046e42aa4a9614ec0711080b071090f5b978061f7bc08429c4ca3e35b480b89dc1b1c19659cd2a88ee336c1ca1466b25cb1a17eebc1f38902268bd2d8b819acaff50e450cf106dccddeb3afd212dbcd8548936dcda405f96f29f68f30c198bc1dd1c21e4a5b011fe0dda6516eaf0d2039a2c2db3f5cc21fd7585cd840f319e24512e17d15b811bd054ca64b3c1f34dbde99d7b2b638909f944fefd71cdf43de5cbf13cd636fae8fe46afdff2a5112005abf8ed412ddc7f6e188b62967caca35623001d705964811b4c02f143f5dca9ef50ce7d9d947af863efb34a92adc5f3d020122cfde23b6458b9490c83aa63158ff6817e620a2865c9b33fbfecf0519b07db612c562e2f05123e083dc17fc478eb9d9b295e6c06ac19e496bb15a0f99e6e6bac3dfa2b216837a3c51de92b1a7e13e7213c4d42f6374979a655d491ab45b44592ec19bad069a591657a40aea095b745c0d8646a3ae876c7a17cfbef04a372c5fde5c7d2cf02c8a2d00b8c7502f5c67af3e9e3aa71e9e86bd9ac52138acf7b419c5fea93d72157cd41de8ef8c61ffa6b4cdbcbb000c7b44dcfe46bc2057e113b670d667ef18839610801a7f382516624852b0b1719e92de5ba6447b3b43b6a2894e561fd80b18508a1f2bbbe59ac9f957079dd3a9d614bb06ace8fa2623ed4c263ff75c51fba3beb68479ecda18747469038f3535c5e193178bf35785e794adf098a68d821f19766f112494be5126490db3e919061e78ff522535cfcbb37d4e41239348b1ef8900352595a58316fca7445817cd756f2c26816485d4c13ef3a16ac80667579cca9ef4defdbdc99fa8ddc8e59a0410e2bfd839d90f540fbb5bd6b987427144df257244a704c8f027d6f1822af5916b63b76d41867c7e0750b75a1f6d728c3b276723daa5416056827dd699bab7b3c5b096bc98789c7f1785e8d39e11b7fa45c2fca10609a43b89fa8c96a123e91788ad35ccd8204b3d0d4091361e51b60726d9df6fbd7243f6fb1da2a41c9ac7c3d09644e9edf1b16972db7a49528a17cadf900b08354b3b18aa662f1fa3ebbf42209b60365b33a6bbe7eb0ec6576182ff46c426f18344d0b6748ad8ccf96d71e070c59538b79be3752a21162ad5a0646ad1f6fa224d1d9024831d15b31d6f6a835305edd9fd1b3b03873303ecd78dd8fa897a1ea3735acafe303142b3cfa9602b6663bd83e689720e1dea00fbe91e5d7f604ed0b4ed07ea2fcd4d435ee8e8f358309d3f121c0511a5648687c44e707af2ef0735d9f2f95d762440fea6e9dba9d356b430cb6d21c3e9be05f755e249e9e4b524933b80bfe0ebee26d414c8a1a9e603068010775cf3d417f652004bfa10b23e52b2574752150c2fa1dbc3afa6473030eb196ff9fc0b3358a18425504e46331e10a824fe88052cd05be669f0c81db798a5ff62a6a88eec876d4d0a66687344deac943c33cbf51d896d80fe718bc0e9ec586f412b834934ae429cafaf22a94f3dfcc9c47f735a93b93ec51dc45e3600893bf5647399af1bf39f3d0829f4bbf5f1b224f50137348e00d4500dbe818de33916d11e5b348ebcc358307ef217b9bdd7e0a5cb32e9359dda784ad806893d74efc6f6551288f00c4d9cf0d0722f378ed309daa6b72f504c57eabb773ddbf8b91e541bfed85177969ad90a1408dfae0f41585e27de3d71bf53ecd1415b5abce850a5ea6be58f6b59abc6f382920893a714943b957e283fb584b1cd459fe3047c7bb9c2bf4e7c46c14b5a7e3c8ed40a57bef0ccd21f7d4bb69d27431926c97678dfd17ae4b9a5324529edfe9524e65d97c270d5ad53f0598ed68995a2ecf0cc3ddd8d440af67b42619dcd01cc1bc441d3ebe1b3d7a09d989c00cafa06ecc4cdffe14855c4a53f95ae927a222c7f1f94e87f4ab5fd6bf6addf8a6bc0acf117afa18d1e214d13da12754b62fdf2a850099a3c706dcfcb99494b1d13f3ef412b13f6015954c97b32eb40cb42dc93b678c4e05d581e84553c03889847cc57ba8538dff333a71204036743be2bae5d6133b6c0a3117b683c917f5c41cf549afd6be7820f50d84f4e81911e81e92f8f079466af689066ad893d8571429c51ba2ab7a9687bcb4322916aa9080828e2f19b97432f418d25f00fc1a210834870e487f94c36d54e15b3907a91f3c1205f569822ee173b9ca08fe3c9ff864bad88b79f15c09283d99263ebe742d818c8ca8a4492cd78f703bc3b9837f78c827664d1bca283f0b15bf878d72d3b3496d6d4da37e7f13d4c4ee0c04e6de6c58685d75ddb89c61a7be8b06ffcf0ebd146677e312a73faaaba4c52ec74182a6085e7f5ad6797f1cb45f2fcc241f5bb1fe8a5dcd6856179e9723a236320efdb27f782bf443f0a39fe1e8b5b7a4d6919f3f2b6c9ad739e40cda91cab7fc6dda28d070099edda84c9a67ea4272bcfbfd9e8ec1105e31a2beffb0e44e0d1ed126d49f17b4ffd21b2a9b8f76ca6e6d7464a01953fbcb70123c199befccade27f231d58d833751d2872876597bcc22bd38fb0a218f477aaa47c48964b4f3e81ae59b0643372224cfe9924f7c61d27d5c8740ffed137f458f362a966f96c47e4afb1a1a34447e400718d00a42b3466577c112067fa461d2c4e0dec8793a4cc43e37ab5bee20916b36f9392f8f78f7781f9fa349c6200045422a2b3911d6505a1dff5c58256d2ede97d0924d9b8fb97eee89b2a31d3f057e1dc8847f3bb832f50dcee7d350a6ac217ce937f8eed8e9a12d8ba29c0cec103573a0a1add308e03b5ebaafe9b279868fc2208986655a777c1df8ccde2c1c880428a76288203b9b928b0bb98a407e460e8005801a82afd717253450da77592c60c9f8f5b5f9733bc5bbe47117ea065ddf28722e0bfa6742b96dfe398f0b95c1f84ebafc4150803b2fe3051d9438103d2a0ea06ab13de73c1998aa844b85f290553380cca1c680cc6ebe8e03003fa9fb9d1ee229d721c515bfac52a160cdc87d35906772256219fd2fb80d386ea183ba8c9e34cb1bc780bb7c6ffec63ca823c198735be64f5f81b42eb47c91031dfcb002d2f377e7d6786246b725888abd1214bf7b68398e9f5ba5c0a985caaea902aeed5ff1325294c57fdf575310789e20994efdb012e7e59ab52c988c902d17cd56ad27d5afd65ee9fd4bfa3386b606b39ed8c5e88abe430913e6f826682e00b66d872df12533e8092c8f7870c344852d445f5880e75ef569a1d7c4e59827e7513a5740bf30bdaca59d23474b9da3f7689483d601dbd40e4a1ca243f33685a69c325bb6868061e9e44e4a83f9ed2467f6cb1d82df11c360823db417cff46894408675a06eac803240f19e434d32510367f1ced61975c16f0dde1beb22bc030b8b64fd7686bc2bbf48e7ff48ccc14cc74f9d34912fe39f523bacc4397af79558fd0e83ff5a34ce827720cb88f6bfd45199a6fb7f9291b8f3dc8f447232cc3bad2531f61aaddc5b3815756495c461da0e8bdac6e6212b91686ff1e11e1893ea7d63223c180bbd214f5af4586bf88ad33fc47d5cc6b7c9a93e5350006b4fd91e7cbc7e8e3fcda44d684a3ef777f450baa49385d171ced49b2afe2f96a051883ca31d7b879d99fb1c49aa65e4ff733c376d438d143d4ea4564fb3dd97fdf8ec12799538e93ddc65e3a164781fda439e2471b300819a73b3ced73b482da6b043c43ce4b61e3e946eb55fc047a35fea6363e31cbf640253491a11ba3004958c2d509190181dc3b74cd73958ef15fa7a3f374af560bbb43d5c41e50ad426eefa8aa94ed1780a52f7a1814b676acf4342cb16be432f8be38df1d6ecb5deacb44f7b23f9498dba81555b55cd3afcdc64fce02bd0defdf658f068f26de766382a01a6cbf4a622b0eb48f66b5d0829c8b35e8816c61ac6b0253d3aa4c2cd363f6bb21a41c2b628a6a9e6f79821ae50031c65244b91e7ab06fea054efed5a4f5566b4e79ba5104d393c9ddb8cb3505cf186b4db3282c3439816e28c157c37d89c81511e6430cacb8fe4fb1e37b96fd050b607364a7105cc875ee25e8d20a5a6fa18085a982d8d5c3635d6adf2722ba4c43a518ae3b70997752f78e99d59690f43ccd500890b3cc0e4a30d97dcf5e7ceb12deb0dd74ce993dc159798b4f9f0c070e0ac64da6d323e0a41985ca039b4f0ffd80881b58659af39261d5bdca4216f6236cc397c45f29a2897e9aad9e457e85faa99d68aac8bc49563b3b48f351cbea60b0f0cdc7a3ead4917e2e81215feedd5e0ae1b2f2ce32489a8450ae71e2bf678a5ac00582ee958871ff4ad7f08db386abb26f29bb1fcc74f1e89c81976469dda9d36b346d0e69d4419135e4d271e926ecdf5517953782c3b3b7d72af8dc1532c707d3ec72466555d782e2d82cc5a7bc540810907677b50329ccca0d899c79180a5dff159dc96a6afca73d4396a910661971f095f09f210f7c6ad40c6938da1da24ae764487d438ff64891589653332f6860c19a44d28ac239ee388a814f6b910f9f872cd55d8a1943bcc3066cedbcec1d3015156a1eee8f5b6654e89634eda42a031a505004ff2ca680082af004ef810feaf00ccd2029e390e095a50138c7d5963f43060a3c0170f3baf28956c959de577ab534247cd8ab2d2781df89a90b9d6dc893d88ee5ed6d1f43a9b6792bdffe300604f42d990074fda5d239015a43538d365eb0f46f6d6abf2db855ed7e3252dc7f47cec211135d2d4923cd83ba3047f618d8011aa4b0cd1f4d93cb6e3f0c635cefb95d073c14054c5458fbcbfbb48f69c8a1e09682cc00346ca7a6beffa92255fdd664ba9150f6757081f30fb47915fa7230f3ef51617fc3a059f093057260afcc14223955f0fb8dd7b46d058d0b741047f877523842a1e315ff98e32e85f863f231c473fd19a728867b5f8c336e7e2ce154832e6971803fa511046a04d02765709c73dade5998367632d43ba4f103eb114da5a5c6807ef7df67d69f32b1ad05763a14c3b7eefdcc95a656b8fc8d0b9018f746021aaca369c8eca8e174b0f27cd5969dd849e348559d424ffd47367b69b0837798d1466ed0445720f95c7e3a6189cec431711d72f9ffeca9341f0485b0876d61c637a2cf6a44811cd00a1b58c962471cfa3ae536b6da20f822a9f53d799cd8c917b47bf4b734ac76b4134ca415bd79eb9b2778a7f67d99e674189ea7708ba9dda614434772d6f8d94e647a03312097a64f986c45a3ebed59b5218623c0efd784b343ef5da9622fbf32d80d7c2882dd0815407025129dcdd9b4b0488e33ba0fc42fe581a7edba110e2ffd2ba5e4ef6ff133fe337c8660698bdbaa91c038c2a3eca9111e91236647f3e1d3a2c582231cd6c84d69d98024e4328397661e5db40bb1c81c19a61efe42aff3dfe236d97085a7fe4e48fe2dc1698ab7124c946957770d2799909c5b52aa2cebf5fa2736dddfbe4996b65ae9726f63baa06f13a630ab6edf0506868121d16c0dad17bf6ea604e6f8dcb1f59c63505fd9cac674761cee7090f016142d4f1fcde067b6fd266e14df878b348abe87ba526a88bf728341bb8fe1b3fa23255470968eb69194d2963a9a04d61e461e33b42bff5c179f71c793775278197e85235f10d5f1acacbc62c12995a533a39384bd7bb2a350439818818029b6ed31764478bde67c25a5d53e0c83774a983ed2ebe9ccb97254eafe8a815272448577b36efd839b27dc8ca2f67e92cf5417cd17dbb79fe275188d0d8f2e441faaf2f4d2bae83c6b3df30851d8f3f4c65317ad615c16a3c1783f66a1789a98ec70f2e0622d04e406644c6fb2fd2995e8f5747305918c528564fe84b4dcf11eeba5edf5b03a207ea266d11ddf11eb8c0a5f38532abb311333d29d0babf7f4e84f93e9010c035acd4a030fad9aab237b17593c2685b45d47c496fa7decd652b03fa60f8224c9e9dd397109a4cd0e43b26c96d2fa0c4a7f652135739f8aa9fe97a179b6bdcd6f13601bded2099c155a02b0b3da6d9c0704183fd53e2d729609efdf3438fb1f72ee52a302484f020979235976ff592c6f2ca1fa66244da92a770e803ad08a15b1fb8039b7289fd1f12fc984d7a260d540608b34fdec67a886c96ec9185bc46c7b8ec6f3042b1d3ed5087d8af3d7970fce7b92f59dc82a1d397f7f5b12bf88f216c05b7ed2b050358790b192a6cb9f0db81e4b20b5f0ae7ec2c42278c97af3dab972e1d16797c538438becb1fac8cc63ea42e8c1986b5042cadb2086354df01135f7b0b52a6d6ca21a52075674b354511f0d80019325c24ec2da0df301d00873bdfe48239b4a6bd37a6ece93b3d37d7d479a6fa20112514fd7aa96a475fb21f78a76c3c8b564b6242bf1873457864e9f2487f6063fe4f49068b2aa3d81bfe42941b5b45153c74b9a691d365e11df3a1adc471a4dc61b845a4169774076c5c976faf7934646d6a883f632fd7fcb9087ecdb1067a2c6fdc8c67f40462b85d56edb5e7224994375dab9ee7b5a14a1494321fd6740397e78525f304b871ba828e25010c79ceb54205620f59fd69cbbc438a5bca9b2306d7c14c20f78057f11a53233dfe09083c08ee8ea32aae35bd1d95b4d8dd4613688810c4126ce4980e89a74b407be98b992b283c3d1aa9338aef20e59e3cd44cd164d58bf144399522784fe9933144af566854ae73c694ab42ae944e0c834fac42a327759156b41d5a8d71b8a00fcb4c8d067fde0a7e72b739a6294209ff44888b50bd01a0099eb9beb6af64d0b60f1e0339faac2593115a8c53b3720ab4a274841697c348243ad1eb8374dc2a4ab83b47b45a16c1695747eb3b9d495acd1b6f8045a41a6cbbcbf9f29ff2727b1d3a682c31545290306c0800639571f2e4b6e3dabbb09120deeb6d6e5e0973c4f9229c8bb88412e03f6667cc0805fd334b35a6743fc2706518646be89dfc577fd1cdbc84393454d44249ff71c25913e018ac8f428b4b64f6631feb579820a44e908a79d2e5f8a3d16dfbe69ace89d524d837838294c420578afd0ac2828846896c8d6cda1181f06f9846bf5e47a7e83b366bfba3464ea48296519cb26a46888588faa63498408e85137a95127323e64a301780adda08e729027f2621e710137bf63a4c883c4d052fbba2cb9a201336911ee31f0a787c398cf8ae8944cf873c32e3359e608b68fdaee7fd6cace223bd1c2911a2fd91b5e4581cf45abccd06fbe75418de5d1098a8aa9fcff171cac139879112039ccb9ef6daec1deb7903a49b74e353745a36adbf62b27e61d04eeb46cbfe122e468df066c4887df40387f4f723a4affeb4b6148433481d769ab8ce6f6048466606c7338a43dfd7da6f9ed1c4e200060c4154be6208c9fad2d5304b5382a5f708c97b23cd694ba88ef01001099502550300082d1038c0040219dd03c512ae4780510304f80bd4671480191bef24823013e68818992ba365ec4a0daa1ca98e3bf14863b82eceb0a329190263912ea6b7ef37357f2b8bc3ec51458b4d1e24850fe5e68b456cb72d1e82054853a8bcbb16fe3064cbd929d171b4181b9e101bd939ae5fdd0849cf96dba186cfdbd6ef2e6426074d83a14c40aae42111a266461f626839e096536856db7527f4e4bf660fab94554a4f90f143b1bb2865bc65c9928057a86b42b26c3da27db870cb5cd24786e8d2627c803f615395f054d17d1c281c2b2a94badefea4512aabeb6b167096988e97dcc1baa8bfe6057072bb4f4f30c0da1237c3b99625c43931cfbbc3ad37519329b435c71bc6773a0f96f1940b4298ad0453acc476efe2ed0cc3bfa5bfadb01869bc8afc8bb2a74e3540cf01fd8b885f0d7374e2441baad9295c06c6a7a37c8f7830f460c6b890212ef5e7433075bf1ad102af85cbbf9c21e93ac2414a1c1ea17ebf42ace194c37feb5f784877ea171712977ed087f277231ea91b0fc2899c4f8b7a6b1d315f2fa2f6d4de1b8b9161ec2c766b4f22429c0c37332be0ee7db56f1e260ae34c018763e7f459ec436a943b8c906414ed482b64308f2c74175ac5fae5c3c0f3ecd1225a426c77724866a2d0e7f17dec5df1e8007834ad7a2da07c892b58c278f07d259e68750011aaeaf34266d29399522d62e10a7c7b906bf07b83f6eafbf3af745b3e2a9a440b3ec09a7c9f8343107338aa04f93b2a06c54c6c3f1059a2ec4f27de1de9705eb5753a572d25c172c94e99974e44da8b11734d266dc5f136ea180c854569ef52549e3e50f3f96db4bc6c1e68c3e50ef0745595e66a54ca0e17e0e1cd2e8be37046f2d4afc3147812c80b412343840133a38ed672e8a2313bb4200f07f9215737d6bc215e0f69ccfbf480502fb94814c7a029a8191263a62fba4a23f1c30580ab4fa1c6b38b09b22bdacae648962b7d19637314bbacd8cf4014e46aea0f3e23ce2218cc6a6333d1f617c696c38a3ecc6c277f8df0d2cdbeac423536482696c9438a16d110979c328d8b91de60813c01ea0f9bedfe5e0142359ba096a9aa16a8fed6f24daefc6ee02298413d2b72fcac8f0ece81551f78a534f48015a0770c699fb42d7a0485154cfc294f721083483af84b1c12b0519dd01c25d282ab9c54ecacacecdbfb452de8a6adde4a4903db8044d70ee2d2146377bd1081f977d5a400217d68c0c47b7b7afa88eed7b098126a1d76d6c9caae7c64d9cb27cc0fc4456879f7bb6a31415196cdfba429ca949e290987caaadc60b26712a8d8820a8201ba837f838ded91a73c5af205e849b524b8dc07dacae1caa1cb8fc255813b76b51780ea6550297a4aa2676b5f0ba8914526107ad11a332ceaf7d12693d5062af7adf5ae3d65495e5a65f8d3184d3d2932a987be51ff1ee2aa65c1a4efd7096ce79ba1d629c606248c2be9db27a8fd84d6770ae5a43503272af3acee10361078a6ee7f1936ec72cf9d3f37d0632e7734627ac05db5b4da6a56d545ad6561fc4fd2579086ead1d6b9cf152daac183034f3bb5957f654a073ad6f323ec3d07cf5b0581bb961fb1273c18498d187611d75b00c7a9ecb36a44024d50df6d5829be3251e338edd9883cb8615ae39d423bbf32afec3102928462610780c7d478a63dcc4e0d9e40b18c2a9a9f90793132ca4fcd1ba34c6b058c95f527840762b2b44cc89dc8a4d8e7ccd3c1b820090f90902407a0473517a2bef98e12c449ac99fafa3d400719e6c33cf4e648bd7713cd85ff40a99bb50563e1df020f37ff3505afedf8c4bf074a308d3cd9a521dcddfe802012e12e2978074db87e68839242cd1aaa5bf45de5072515ffcfb0a919a19505a96d428ed54e76edd6fffd57532c00c1f5795c303ab9177e4a3700595a80967db0511f95467e8f7891513b8d740a1f8b7bd9bc620291a4fdc45340486cb4af7f870cf6caf4e75bb62b9ccc03c65e27dc11cdf09c1015d51e996ec8c175a2413eef8f7e5c37deb965bdb198e478c4b5c82bf1fe72aa1939c7c62d730365c7ed03b930763620c58e2d0339ac240c2c38f1ec70072f6be1907afd0543247d9500cfb309b3c7ce1df8c6505fa1c0f5d275c0995b862bf67b332c1681e88140a40765a86f50eabbb32d88ca6f60002bccfd92714233299b0907927385056bf0688c0d26e0dceb320141f82fa607003007af5753542d60332231f9a8df6981beff2185da5d14fea5147e6e9ce4ad7fd6ff5c144485035fe2f531624999ebe3c4bf53d9e958e06b2c9f0a768b029596f1f6f15289ce8cb02edaebc03d51467d37d260a35881424765128bff44d578c632932a044d4dd0111189af8c87a13be773d8432b34355e396a5ab478f5ba5bb1ddf613c03f99b8e7144b7892e49a625ebf6a7dcbc59a3a963f6d35821d509d4a532aff611cf242e2cc93306c6018a691c4f4c77679fb0ae2a25b2a040545ab0e0b7b24a11612a2cb09a37fa112f32934ad28d7038f2c515ac447546d919c457503a56d4ae08e898f3e3959cf99650107d6962e4b26d8efb3314ecc5a5b317d6ab66e7f643a4d3ff1e51d640f8a6cc3542ef97bd3529e32f87d3e1d25583f7cca8a121eaf28ee6a20a4a2434b258c56978dc3aa5644a81e83f020af915077f6865ddb750a1b3dcc857a7c6ed88deb3cc97cc8be8f39b73565de288d478c0f6bf6a48093c65381e431d7315d62babd2e7c6188fb062632ba47cbb02668035aae5b8f3a8a62b9fc69f701d1efd1527abcd038df2e435a2f57fdcec2fc8cfe53635328f2e1c6527f838ac35b5a10f8b9469aa46aa5e1e9b5e2dcc6f0df4e1fe51b03216ee8f49a1e9a6e1d806284c78611d61b4b610b60c1374e93cc2c2178e732b500fef282355abba06c806600533271afa5af3626d8e77e67ff6e3321beeaaf876ee6abb970df98ef0778287802c825bcaf4ca072d285dcdf559fecf313c857473be7ba70db5010c2809d069982a26416e1caa6b46e6461c55a35ac5a8bb6119e442c674b9515c9c02788fd205d7e12097cb1f33d54be15081df5d43a203a172607f3d665474486fa78e72250ca15bcf25d3c2d0cf72e6d4fd513e7fcb888649ffe10854c14660143b151179ffb8ac359c5671942778e9512acb4c0e9712bb011faa72ecc06b702f92d46380d46a58c1e6c3ebaad719e68e04f58a64118839d6604ba657bdf9e95425bc09af796fe14c42f3a5cd0ae1629e50fba2ca4a05e83abfc4629314f3c54a9892d9e68bf6abd4064d3fefb220259f0c34b3d0e05d24034382b264676ec0c1c83a2b711bb0f18a2d85617cf7784c0b5d5b143e8d901bf773ae5a48f2ff86d0e3a6cf841542a998016febc0a7caa0b68cfbf707081babfe7dbd5faaf6b7a464bd062fa87bb344827227587622561cb0d5a211507f9604850f9b4f022fa59a716dab5f9f763af083b687d6f1423d536432c35f51714d9f661460803f90ed80b8f8903c95ea3a686d8b4b65fb36087ffcf7395b9a717fb329fa67578b5aa4b7e660e37889233c927d9643970dafbcd6b4d4752b152b0adbfcac4a8e52a7aadacf66d338f85856b63f94a54ec939b6f6e50d2126a4e3aba37b97226ac1358c34fbc34e131fb69ccc0e907ed9d5a865589d6d74f0c400054ad40809cbb513ac08a9322f0a36711d9383d957bd272698bb024632789e8b5f94b2b78b5183acee5451f9fdded330d3135c50668c46348c79ac0c2c3a1c1714b8dbccae6cb47d62bfd3400f2966021d86f00e0dfe8abdcff9ba7964e62cac3b10ecd290ed09f82403adec72f0e93e330e5f031e3a3c9b16b46e85353a7eaf923d97e7841088bb34aed8cbdb9c60b41322444b7342c4d47250adf6ecb551095e8ac0cf3191ee570242f16743716382370128ce8664dec240ee1343387568e915d4594b3f981ab815daf015e64f8cd5711262c94f0cd2d510680f0ebedcbe2044c2b9fa6f56fab354de4a16d0d2f139aa826b110de61610fc94a81de3b7ca032e953adc40cf26822aa904a7dfe4ec3f03a342afa129333a222511b34751d0329ce615ed3b583322003cdd2d487eb396bd360fdfce290f7d454b3b073a5b58fc928758faf6f21d8d6780a88b0fd7c0baed1fdccb58640f8202a83f98eecf4a5af5888e36b1317bf7af889d082ffb091115bf3747b2c34fa4dc38c07b88177ad46e114223846c58b6acb2326a627e98c8c4ba6055e183554faa46c43b2a6e41911a63c537a8be0bbc99ff9ca0a5882e477ff629db70eb325598563ccfc497392680c1736af25feafc4586f412f850061cfd2c3f8e50fefaa486f79596cb0b126de49cdc55ecb9b78abec0b7fe07f022e6f5f545bf841d509d186e829e272de6aec925daa636e8a218e61ed93e9d74424a00b47df660bd8b4e8532149ce0a1b13ecbb372a586ce484c2d3d211eafa2e464b9f4d3bcec05f1d5efeab5d836fe5178f70adfe2982b43e9a842f42b8bdf4bc6167cfe8f5661e670c6bf8c4b6044a5f994432069680d35780997b076edf9fe3bb351830dec1f49c3147e4de54ced6929a63ffe5d81a3a301ce989cc5cc9774a02bed65c091d4af7ac931fb496c2e72e2542e346dbf5a85bf6d04f85699f2f87f7dcc2fb59bd445644849d7d133bbb94a5f4b7908e23571233e2265e3256ef93460fbdd596257ed5ce123a4c89a4bd7d7aeb30a26d8029ac0a4ab5e339d096139af7326a511bef477aeaae0dce8524260fe66aecd263fd7c828f6506f718293d6d7fba82efa12f974f7feb8ade436ebaf958d0cbd3eba190e2758b65ca741d63c7d73ce469b1dff893d6fcbd8b85deb6703902cd8f68e80bb074e5a8825a98a532591a4d45b11aa2fa6614870c9641ccf30286ff185efd9c677cc3368d50b5460a7396a74614bffc4844b164ae57c0661a8b4d7866825016e48a18395c480b0d2f7f4f9c7659c9393f3f605877f2c90f10c67aebf986c781f911d5496b1f54c2e8e44f8aa3da62ac19102e0e550a1e5807ba7577f5d47be7dd296a0e83d2f1e14292614407de6c763a6af0b291fcaa94d78074b4564ae9ceb9e5048d0851f1ac2dd646ada12f68785f867430199980220a4880fb64730c3ce5789ecf1a4683a221b85a14f24d71a7ebab8aabe5ff78047e82ba5720704f4715435e491b2e5d1623e5649809cb7a6732b4b43c14a5a2be378ea4cfff9f65637bf607ff8d3053f692caab577d5e475443891ddf0bef056f6b1f8a61c74fa208a7a4a9bd39f5c05c2372109f11a46bad749989ad83f16b21b56b83141fa747407ab717b93cb9e66ec0908fc351fa1281cde0aac5e6b1b6fbc6d415523be27ac16fe130af6e9674651d46ad2474bb5251653e352a562d682fdba4e3f1b81d0312bb04b2b1f6e1d69b7b6b0eef7ed05b493e34a38de4d8235100c0cff17093d43b687e4d3d4095960e04f640cfb1bb15b4dfe3f70dadeed69031d1fa007b9d16d8b8941de33fda4b6fad3d187bb82b238a4e5595b62f36fcb9689be7d47f63e0c5a3c7b412878ebd51914aba35feaf9a9b624396dd83cdacf94c219a67941dcdab26868f91fd0e88068fe3ca63d3174581bdb397bd825ac396543f09be6028bc2a6608dea4f7b1e03821a7b732bb5760a91d4806a0f4e402d583e9ae7f69ebf0c6927b6968fbba467faca6ddc2b0efb90099d14c1b90aba0bb5bebe24d1a3e8e9f020cbda13e5f6949c4f15b055fd6a616fed5060f22da45a41e96f533316b31420c5d08a392866093c0904671b49b4fe1fcedb20904d7e184a6a97bd07bcd223ea7c4216ecc1f42dbed2b9f03784f4775cff447b9498ec808c907499220f5fe75346b2f4e460f400bd013a06d0b0c1a3c9a640e843b5485d88fc869bb35fb48cc320629a424b088bfc2a0dfccdb7607b3def06ce3d29e591e173693439a4586bc5bcf9d4f1267c4a223f1af3b27b0dde9991880b8890a1fd64a6c45bf7166508260e27920e657fcb168678a76021809a9f6164031047e7b044675e1f6369c67fe02773b8d1bb10825b41d99aa9a49c3890a916089ce25c997eafd1aa9b0be953e4e7c2d32abbad20f46e3b05a4a7f65968d0caf45f49de11997a6ade9a4c97cb4d68fde349d37494ecf356a12f43ea569d906b1944b791fca150ef98b187fd86e99f87fcd25e13e4af3590d2e64731b882cea3989ac89b3ef1efeb6e4fde10658ab89dbe855d2691fec41142fc25a6bc7c212bf7f480b6d7b505688d43b0e66c5f5bf3d8529dae9db6547e54cf27638d34bced3c3945768c078d4a8da8712d951444816c88ad9c64ba97be0bcae5d804b4a5ef10521655ed1cc62784276cca1c6608d1b494f4d9a1abcd0fa3d2730566f4f4bcbfb36ee1b886e2b97e3032b13618c43b3f9feca888fabf30d93ba0f0846a40ac66f0c9406a2b2dcc55b5055f7a7571862a62b00aa5e1752c8103f25ccdc5cf24c21791c97f6a6f4e8d2914207a79a3e327f17ff06c3e04cc27dd408c72252ac6e149c468a9fdab156d186f03cf013e5a01946058219bf606028bc4c8f4251d74a779aceaa8f8cf19734eae44e8280dcf32fb536449e8a6471261c70c66b0acd6b4f6ca440213f03057b6788d53fec0a8e41c2cfcd22fb682a29bc3d52a6deba5883f0f8148d27d1390a23c30b7a14e1a202ce1da0bb208909583d2d65ded58dd5e4bdc644afc0e42f0c9127dd74450b13233bf3c3a94c9038e0fdb35dd3953882c908815d1e418121606b9ae9fad2b7d7bb370a32e577e9c9d601df26986fce07b330da9f73c9fe89d76414f9f06dea8810e7d7ba298c124c4e74193a91a76fe9d9ba873227c2d2d199361ba9145674aba6779773c1cf926d16bc4ccbaee9e9fe8b28f95c5b880c696cc1802287576e0bff37468a9cfed45fb698760ad309e2abffc585395e2b9f698c313574706770fced6036ac27dc7eb0102bd82017f6e4a3a9a50f74b5efda192b3f0fc2ffd2a2330f8bb1406746e260ede609f25a1333bc31a3c2df42b6134ba417d85bb58b75fe8b647a4afcb5cf5e6b76f7bee6a50f08aae17ff5aa967e6218da60b108b855c491fbb905d83d2ab4a6e9a9268316a937680023740312efb3df6e9b2ba6dcefd23c1e10597c30ed7147a5771e921e4ca06e12f4f556b10d94b723103c519a06bdc670bfa33ea5a9f80bde8c1f89e0f9a45cc2ffe7fd4fa05494140e9586e91bcf327283fea9889af13f465cf5a2149db73a24548c33ec32e39ef569e7f6d0fd8a902e672ff1eeefec205a4c55bc1c3406face0f80e08710f0ffb99de2d5e253f7a1ae42d32ebb470c343ba104cde6a4c22e3822f8b40ff83466f634207d6c207f14ff3fc722cfd15962b5db99ceda37f77f0f389ef45217aa8daf2c9627905c63abe852a1c1c0efe51e6e6a955233edec49651dae3d053c8c7a8467cba0d5a9e5cb18037c11b6358fdf8d995fda67a76f8029ac2e65fb4d21b1a327b891f9f5db675288154e3ee6f2f93caec9da32219c8d5d75b91f6ef90a28f84f337d68a1a759dd2ff642f62bc32f159d165f4d02bb0e137ada841e5514b96990001211821119f263b1c7fb64c507fc67551111bfe9884bd812974104f99b0df5952e10c232d9466541f0367d26b1f2e7ea03ff77c4321f3f1985f8dbc8419c0fe29b8539bb0dfa35ae05ec00ebccec02dff8480e2b172635311a5c6a46e186abb19c3a0ffec3d0b4e9fa144c0350130927d7cef370f148995f85c1d5ea3b4ac13f3b9e28c687b9895d7d5d7a72fa76d3d100c78af2360b9d4ddbd943e0b24d511ee549fa31754507d5f9e182cd82ca3d7faf200083da025023996a79377e7fbe0ea247b199269f4dd3dea121895afc43ffd53b39d10ee55a6f7dc765818dce9316bdf1556564c491dd8a32b35443d8cd6dce7b7a8d8e7f18574c603d162206dac8713a885a89340f9da69a42c7383e5042cf5808692f8904fdfcd2578724d854423233ba67f8d474af381b53e948c03ef6ad8fe7511551d3583a60636bed6ac68c08ae3dc7ecffb356e51c197be9945f6552b52e2c1ede4db448cdd2353f7db7efe0035449faf32db51d484d31f6ce23c2df503685367e3fee17b805c14cc6622c95a83db5927f3067ad843f8af6793c82be3ffb6258358dfdc286b3437f240de9001f2c11cd9ea1e5b05b9ef089231b2b85d82b0f7d139a488984357483b468de65a2a85333e1e62e7cbd6b0198833d37d9cd7e745abaa26a0391ca13fe8b8ddd4b721c7c79041e53d48a8547b69907e5e4376176ee057dd6c7933f7aef45f23112bd0f5038a3c2271e07cdd3db71935564c2578146b1c6e453b19f866942552b694c758770d0cdc0bacb05b2ea9c8fc3b08292b6dd572136cce67f9710c2e898b5befc070a9bb07a760e16a3db79164f88ff739d32b35485dbb80ab2fd4dcc9aab8d1483c4c4c3f3dfe50844068d492b69041893db95fccf638fd5367027a6eb78c67f9dacc10c35da3510ee5377e6a1542c62251c54b72d968d3263b7003c087eaa22aff155bb1076c9f42499c5f797bfbef61e151c4b9d74a3bc728a36309a7ded3756292a8eaaa229945e6613f6dbde35f22b5978f328059947e633b585ba4c3d15c02472094dfc66ecd4195ebbe11b7627ea4e55c5abd9d70752713e6a689e9f04de9e942b7bbfc85aaa943d578e9a14d529d5db4b68353edd44a1daab6958928671d3c33502a9d8b59942ca2e0724a7bf70640d5a8e569b2786ce095c3451362a9c069f14316640726d978158d99c76b0a9d1939502d133f93105f50561b1b9245eba10dddd0d3cacfbd11948832ce2e190c7a9f18e451523ba1314f37324abc63593b15e9f9500b79540faf12ac396c47bd1ab70445d03493f0a89d4d24b81e6361f03d04020a4281c9642b679d85851590603e8534430b780e5236fc6352a120529fccbf234226d13f7b721ae0810cce23419e35f96ff1d231873d8cc1bf17e9fe1ed9ea49b2745aeaf02406f6e91a324c25211d1d08ef29d280cba7c8b6f3e72888c0319695684714713be1053112c408e3a9dd4392cd93422f7e8433fa5e4b40780fcf7cfa3cd0968715187eb58546eae03442f35628b930310e0d8391d6d4f1d6760784bf88939990be72646e4bea9deaa321c1939ddbd2166e5dd8a2d723e180e8e70fc263ed521e9f1c6b191ea75629a701118f15a3feab3c312f2ab253bd658fc679894c42f553d5e70df2e557164d99d30a7ff13b913a1feedb66ccaae2d3c834ebffd66b2dac9009029d82760ae3c1d2fd4c80c5c97f62b7bd8215be6461fb5098dfbf36e3e1a6f853f6b061c72575aea494c1d52bd27b35e3fe2c3c4072bd4897bc41a85fb747450360409c6e30aec479d1ddb9989c37ed7f3c1295efc49ae60fd77aece6178b6449021d008ab432d55d20fcd5cc8a7def154e4455f2edad6182f3f3ac3564b13b5ef73cf54eb07c6018bc8707fd8b6a57988e432595488868d137fec99f545ff2169169c4d58fbd52906274c66bedb885c9b81cc0c4bcad36a207a157bb4194e57324698213bee053e8e22aa36d50c424100c33ea3b934b8a3d77bcdb33bf2ca8a1b3881e7c2dde19515048419d080740c0c99a929d894e90203b0b9b85a3617d93f646154c042313f238efaf3150cb5c27000594ba69f69b046a78747ddbadfda5c9cac12b34d6ab8de62538b88952f435ba137110a0487c39d46879e39db29440287e93184342ed9fbd441eafa95da2eb5c901f0873f8e0266eb187870b698a4c83f8dbc45a3467f08e55d472e2899ed3dc3b96706a26bc7eed369d8c6dd2a58a6cefb78c78fc7c3382efe9c7c92264de3d2ee2ad3c905092041cc3f2b11af8cea997878ac72d3de10d4a6d4cd41279b02f4a1d7bf4b41f4e89f1108455be5f4ce53d0a4f6e29891a7e6ecb6221f4a82f48b4457c9c0d7388fefee40d04c422e8c1aef5a91847c75e5d1221069d1c136459b16c68a49bae118c9956355e48895a7e8e160af63bd46e681e30aba8c8d8ce86f8916542337a89d9904ee0a40b0aa7caa4fb081f83ec56ab3175d1e109e32796bcf7a8f7cff6444a99c8116aabf118fcb32c9f5dc0cc37773a18729d244c6d00c9ab4968eadb1ee2a01936c7139c6c6aa1d9bb9358f6f5ee5f1902fd0f1a9f2a68f3977e03b2e15bc48bef02d6f67123c55a072f679f2bb21541104dca56fb15304aed1518757c6b8323fdcc3e2498cf25d6e79194dde11afb5e4b843f865d505314bd55863a41b83d34689bc28c60457ed6dc08b0b8db5c979768df8b9cc51ae63620c5432049c7df6175d96efac2a8396382734e7fcc6d25ea071ba05e3440e256296dcc2d739c07fdf7fec5cfe2bc0b30c0819a10267db813bf0cd1c2a1cbf8db708dd2d4d20dcea3b0fd65c91b9564a86d879fae37c30cdd0b7603091dc4ff5e99bd084fffcfe3b1a11440c065d65dca09e381c4fdd8610f4591b434281f5b6d81555561a30889f963686496a1c8775747d8ad920355d595924622217f7ebbf0caf7b4b15fb0fb14d1e3271df5efeab0ef1e31bf76839485dd3de58e403375fe5c3eb016b15bda9c6bea2d277e5747cd862ad12a2e7d07efe6e9c4e1af58c6b4abad5d7e605fc180fccc02942ed0b14c5ec61ffb237f2361dd2f2a8bdad03c9f109e26c93073732c868727e033dd7e3a0c0335b2191c2aa648d8c27006200f11af36ca384980cf2931917cdc7cb1707e2ee168cf829b626c2a6d3272feef82b811759eb80dee974be47d5014035609377bbbd010a9cbf5c92389cb7e51befa07b76e558136592d5dccb6d7f4208470f7048b9069b257c8db23685f19b0be06ac2bd616d07e42ef07ac5bbd3ff5911f4a9a7a7518501b4cc11f8ec44ea16c2e9ffcbe622fae32f3910bb36ef9ef59bc91958a326e6f340fb86d421ec0b65d04c4f3ce98a71c13cf993fcc43b4a178cd917130aae3ec0b343b821b6f104d994489be9218129ca2acfb4aa94f3860ba70780a4c5f7939952b16c44edbcfff36621cb0d965dddb092280713f257cc31ed192090294e153f2b7b6dc0387ca8f58c1e45f5dfeb14da64a3280a38f0199c4092d9cb4f60b154a253808f4f2f5391ccde1e35232e9f114834e6127e883c67dc2407c18160501e32a930fe362497d7d2704409aff82462d3f4d0b0d5f6fbcd94e0e9c037dbee7291b381ab67e52007c46653afd388032de6550a75d08b9dcf44f48b156d7c84b5818f1343401c2d0b851898c6ec2552d70748bdd79424f2451cf3f2bafb527e1f1be576a987d3288732e5f880566bd8e31db173b5926fcaff19f61f65e5e0245306b338747fc923abb7dbb4590cc92626c623ca62cff030e021a0106badfd123adff288167c78415cc1f2cbc898c04ffba623d731feb99fe7bde764311090fe05097c103f2c8b3f50f5148f910b58ba7c4302e560d1bd0ab469914367a3df6181429818cbf2f8aa71812c165ca59926dd4d2206fd06a36f33928ee847f4e68272b5e9fdcf29ce92435a1be5b407616008b8a721810d0e0fc83cb04badb0c6245f92e1765a0a2f3146ee98e5ee3db5502e8fdb0a57ae5c60f77904912af080daffff4918ea87551e2bc5c0ee3e9afe39a0ed99bf26b9bae2f62bad7fdbc0f8040f74b9cb325b70bfde21c3a036be26918f56935570782c5be05994d37614e7e17844ab3334341e9e55ca211270f7bf7d7da4768fabb0881c56815a4b00a5378240c7d81de4de674a8387bf4793327bc064d6a2d0ff6116027f310d0a86084724a15969c9ebc4bbfe495bf32f5bdfcdb4991f23f020dc3edd55538f6a7c05361f8e91533e4ca923d9d3abc3ae08f277b2aa83bff1fc7bcd2599c1fc0c86789102b48d1ea47cc7aaf73f790a53160124472238a68d32b7e5890727abadeac1c4491c32bea4853a8cc83eed7c82d1ac433246ae4907790508e1a1aa8fd93c54090d4eee8da500a0fcde5745948e87e3d4e1b98de54c6237cf1f60d57b7208881f5616085a68638730b239588e3315e58483f377a91a5e3e9c4a9a2e4f767163ddac9b284adaf638e023ddfcbb408af9a913570882973ea56476b24db7f86a7dddddc64d3588abac6fa3d0d8daeefae3083336e4d3018bcf969945d400223ccd4c403b4482c54fcb6f23264ff7d0f453c28118789d6bdbe73e93bdbd292446bd1d62cda7ffd7b1fe14622523246ca3c165527569bfc8e4a8e76da4d341ca87798873acfee1005d8e8a00308d9ab5eb73ca191251c31186611c8ae4d25eb8b36a376e5636c509d7d145a1ce42ec106b9ef187a79c76740f4fd23435a188108ab2dc6272d4e7a577df6c57da8ddc39bb70f38fc58809a7b182dcea50ea82d3851c74ffdcb2be7b451217c56522f690e29b8cc1c25b80e97dbd7c447e8ff1e8519f40eb80c7963409eb09afcd9246643593104abd206d5d8a48707ecbe51cee555a5ed3c2d2fa6dd17204888b0aa644d73a92f489581e8d3e9359b213078355a8c1dbbc55b3751e057c166bc21b7a792b6d35f40db05710b9951ca7fe7716f87bf529af18ba838e5a2384af1977b310fdcee0b4dc23700779e61b106b0bfc2f7a56d7eaad89d997a682f53f4c3d0436deafacb63e011339de01f4c4f290cc46f3109e64aaaeb8518efbf8e81902698a5258561e17e36c4d8470a25f51481a19048bcb2fd2d4ce0332e28d87fb8aacfb6e8d6559fdc76a57aff28768a0af7ff11b642a88e650adf3723c71f3145d61df4d33ae63289e701251d5b7a09f13f6b930eeb0fb494e1140009711f5fee9220ab11b0c340b34311fe6f188afa9aa55b1cfa74af0137060734e4411404e13e1744f5cd87d5796a7883273590ef2978490a8e84bc23bd384d51e9fbc8690fab2ded4c2a75e1e4526a01018a130a8d60c5cc3c35a34d66b7c2592fa1f546e7f1da66ce2fc84416587074129cf7107fb61ead8e08824c670320643ff9db05728d6589a9dfb419cdf3d90d9cde3936b0ddbec904dbf43e45c09f27f9ce07e201a681d423ceab1f708b497be6d1a67a120e656c79960885b223cc1caa9b81fe4a9dd0b9553a32f9592669a4f986194c5e33bfa612380006687c1f71c474257e5f5c6e4578170b75736d61b378d8f3a7222d23ffb483e03e0ea0a22ed5be2f5cedd827496e2bd0afac5f97afa672f10b30b91f71d36d561527a9399582f0ee28daba1930e6e8d1724279ac26977652526c217bf2b3e2404f7748a123e4c59461fcd3749db3bf8a8320e8c7e6a8abd054b250bd8ac62d8a904a81bcb883e13e4a15f560b52dbb289691f39f5b3a78cb63bf1d461c330773defb3c3f3387bc59988f1fbddc02bda6f86c1be469eb01fbf54784a8407e8292bdc75901c3aa1e09bfd03ef34004aa6ee1ccc216a03bdefa06c7a7c4c751288c1caccb555d4c90f602687462f2a7c0b99aaf706ddccc75b80e2126bdfdbc1c977577fcd6a412e4c8289d9920b6ce9742b52bf5e556813a1658e97fe425878953a4f8df703b6db9b7dc5196d75d38b899b963e490bf0e40207ce82b960acc4d6734931c9bf087acbfa920c4d14270ff00a34c0911e4e4876266807d04e8db4749546a04df8cd7f7489a3ec48079c6ae835e9ec7c315eb4426249afec905803da45a8595b70195f7e123cf0f94cb7ee01fbe01558dfa7dfa4e9714abfd35973347e7cfc115f4bf333dca32e4e5cd8a7a3857bd2b916e236d65c403b00d559424ce0e80b8625cfca2682f0212f48ac5be7613becb7855184f90c365e4bd7b9dd68a557fa0c4175db1911fda8991c0ec479711c1719942fb5080454ad8a701b205d31729a1a283024d8bba85f9517f40fb2f5497b8de36d8c57300fb2f02048ef9a9f1c570dbedf97f4594adde480a3c9d504a4ffc8c8814912fd3a2078a82ff9b47e541ce0006fc46435fb33817f267db67c7cd8b8b1b129fb164493cdf44c38aec4f2db72d2506bc7c3f10776f2bf2b946101b2f7e8289649b5ce9fdfef115ce417c99bf8cc1498dd4ac1bf2c0daa22042abf9f29c30a4963c795e19a56046b65a3d00aa8628ec05adc729609d49b8da8403d97a747d12fca532d699bf89fd39bba6288430a4b6ee89eb4b7f3f6cc2db20fae56c9cb661a32999cd36b8cbdcff12de442947e253ff93889c0c6f94c203c67e0ccbbe4aa7e0cd9e22517a7b4a3bc9a5ca0a023ac48b5fa46dc029ddd6040266cadda66774825b877da35a94b37a44b80d4b432bbd5865cb89c80f5458800b39f6ab6b29f43cd55df9e2558d57da52caac5f6de29d0532e2fadcd3534d942e30699ddf04467acaf9ca9cb3b64966b7d4091646f993bcabf9296988440508a7316f250c5a9498f729a43362c5afda4a5bb840aca8c4edb0bdab693ee10923c4b0406adb5f8e9ce9d018296b1eb640ffdb81937222949e414f338daf220da8987ce3612ce6dd19b0d5a263a90e8410e445a08549c37d49443a5f5ff0e22274ceb48f9724887098285552fad7fb0f42bbbf6e1f2b912cc2d345460da59d248a3c609354c9d40aed029bc7ce0505f18182032be8b61fd1fb9850e32a6c291a97081ed6668bbe8b0dd700fe04ca7a9bcc54f839b95dbca5e87ee49695aa9f324d875ce87703196daeb96e2734e1a8888eac523b97881380e9b9a2f2c6c881551118bd953c738f94db73d9b819eba25e0e30008c667fbc11a80624f38334a48bd6062d8f548e053ce5ebffb90dde51b9d74eff33412fc1091f56831f663c03ea9e3a0c4e25203779edecbe8946a149a52e62060d11180e28355b84bcb1f928b0bed880392642cb2314db8b41ec350e1ff091a39903c93f543209c42349e32d1a8cb563376bf68f60c7652755b5b76519854a04e216ed60495aea3087e7009bf5a747c83e5f5beb4b23784d8c242366b7b54c4a32d2475df801992793991ee81194a929f28c97655fd511e133d273b0242b08275ec8eadf2d41f44a6481d4020e06f998867090c1da700a7b3ac40f8ee83f28cd47f9e71b9a93814c3d6105549af8039c04a8c2236f08f41bd47e6f85db50a3de78420a4ab3463d9eb3262214efa783eb24012a0062952cdbb79e26764c1ffaeb2e4ccd17a4443a0b7cdab49d96f6dca96e95b685f6cbc96e45a64f1b720b1e9747cdafd2baf7a8997acba653900251a7110f32c4e0d0cfefac8060aedd6c6c5c3eee1d201952cde3a0abedc9127c6c3b84a1360f99937a99bf346bf95febf66be30ff189c66ae9ae80c9c21b63b9a5e3164878c46c9ac85f89a9417d3cad5247b85c7d0c9e77a95befcb72a4eaf4d9478202e30041a63f815c166a0a5ef00bcb3aecd50ae9e5d6be90924a7f66a00d7167a3a24f3b96236b63bcef667a45a1a1ec5bbd603aeade2b086b5f66ca6163dfcd2b4307f9eeac8a3d0a9ca1aaa40221be2cd28517754fa5529e0789a32bfd623435d9d661b2fe602c315ed455f4819d60371dd29b7a75a8ad62e321b7b4e5a94a2684287016fd7490e4a5d114ac75970a16f8da25396201db3e36a78b8c5e041cf07a7fe833da45e54ed509e0c730370624a2e684b6d4f9b50cdbb56b7467544d0ad7fc4acfd1a628c1e3a4299a1ba5d602c7da1f1f463e417eff8a63c7774827db3041e199613ff9368b8a211f1de4abbd735bb7ff94ce63d4d574b59b4545d55f230c720468a8b7b2ada26abcbc9b96bb062aff489cffc38b4cf3dd8451328e2dd3c8bac7d9cbc6fed5a6b1f131678eedab7e9aa35cd7ca1ed2d7447b10c4d6ae1adee9d5d3a9fcac77168f673a367048020c4ed86bc44263c0f6b885bed3948ea5ec89e670ba7b65e85dd042ade2adccadcdffcf1fd36f8e6084ad9331ce7f1c1253eb157c4878aade598b9c2f9dcf5f7416bb3d856d6719c44310b1f031492676f6844aaf1323038e28e4a2904c3c81c22b8cc36263962fefba22b7f8b824238b51c2bebdaab94cdddd91c530aaf9e85593f06cb10463ec5c6b0b4961bee1ee1570598c99e98451e98c1051a9084d711ea12300a612939fa9ea268d0cbed632220192f274435c6d37a8c74d11e517a5f4add6d39250906d31beeeac129ee02daf84d6aff3a3d382ffc228079fa6128f2d98af2ebd2fcef7e1fad839399500a4e48891aa92361f15c61ffdf956b59ccf4c14f7337c5abfd9bde1bc7ac477c17afc26e1877f54f65a7589eeb8894c69cced518e1828e157d9b0323fdcfa0093a69da272c6fca613d76c3540a0e20087d7b92a843768cb59b64f54e3634a1da188e7de5dc090562293e812af1302fc3ae8e0b47d2107ab7b0a4522262b7fd8115855aff0bff70e24fa41e0712a5358d36c0acd7386c4f638de6ba556110d489db2f47ac523dde43ecbcdc7d9c6f97d449b31b7989ef62b003242820ae28f1a7b80516462862e6aba8f5d11e2c09e3c42c04cd4fc7f58aa2d75962f6280cbb4cf052da2ba5e298c811f951114060d56147dba9ec5a64004acf2b7a5c60f085b6b1ec02c538b591b76407bd1fbb8c3d1079ecc9a85eb0e390047f47d05159efb06d5c8132c34f818918481ba1116520356e573ba1ccb065a3165bf86071f9fd4b39bde108ec4a9491afcf13795749df6dabc6755989a5eacf2fd638a1446b99207550fe88f288d72dcfd52765d42897e4d51e0fb94885f1c0704b8b13602bb2d71ed8553eb2af32f9ed09d12b6945e2eb3e4fe5a0c4416595477427e01ec812d44b9576a344c95601d1162746c628017a3074455294eaa13eb12eaec0ff53319e5702d061ca9a339a4ce780da6d875f6a01b50048f9ffb8a26fe4a05a4d617fb4909c8ae77df39d71167f130f705783f9870931bac4aeafc82bbaf55d55445b70b836123d7b35467ac1bec048c3876e3a0adbac9f2f544cd16ca41ab29547cabbcb4ba366e353033c0c7f84cf6293c30c61cf9282c2714d267b96b751d16c9613789dbb9edca06621282089adf37d16ff4917ce4b9c88842ab438fef3dfe88b6c596936ea8d5f3170eaba2d6f399c36e9df9c9f58225bfda1d06ab543cca3db5c18c5818af254d3fd935099f77aa7a2512c5822d84867324ce419018d27669e7d62d8238f0f91f5a5fae551aa224d2e2d062df14e9e6e072aac732c075b39085650958f0b61319112879887bd5eff7427e084d8879e9c658f2df42ef132d8c874feebbd1141c542b6e4ffbc48f4715140d985b1a7c2cb60cdb9ed4b3815e5c6cd74aa5a39fdc9f70cbbd9158bb9a0cc2f928ed2a3e1f9c81a05b8bd772e0967edb0dff04920c7543d9946793618da9c83b3098c04bfdf9522160f89d8e9447d87cc69e59afcdc184901317eed3bcea1b74f38f7faf5d5cf8efc471ebbd089e4152d26800b6da7d025b95d11e387ada19ec3606a0fe523a6547a77cef76730f6d5f3f5f533189e0a79e70e8feff8a049e016672a510c6103e4fdb314bc519245e8a1cbd441b6e0b9bacc0680f52352f24bbbb60953dc5da08b57ecf8cce95ab82b92765f547bd9bc498138fbcff0d75291557687e123ddf4419adcbc570369ef17398ad2db38d2ed4aedb9fc9d0a424752c28833480b9fa556a56e03ac760588c54ebe4adbacf8262199c91f592b68f6fa43a5451fe73994523864b18e54cb9f1af4a538d038641f6db085a496edccbd1f0f9f79daa212a0c4c59d5ec74bc2224014e8c9b9aae5ba91fad46f0fe8df059e96b279f0e6f832c59d2b836d917c015ae59144ae80a699cec5a531f1a71f0fd49a6ede97b4907de060e4114ca4cc0c4af9036ad2e32394696b34280f48bd169b9433bc10a7412c275bdba9bff58b2ca9b67375258a12b2774acd5ddfef025ff4edaff773266c1f57ebd5ec69b0377540d5bacd378613a759508740e3328a9933a7522b5ca129aee4f22751b95e9efa5a695d42e8ed2cd9fc1f373aeec076c55e1da0300efa83c5f58bfac9d775f98759a570c9d0ca7fcdf59c21629a8feef957c91ffa5aa5a80c269c69c983612f4f80d6738bd540269feb844a2a1103fa684f776fb1f5d6571b464940d63570c4d9df0f1de6b2f20ee3300c62b390822953ee29bcd4bc76ff19102c89aac017e4ddc9d55864b5699e137c5304b8c9c27048994f120567e3be2833538c44722241ed39153bce173074d340aaa3860426ac51d6fdde93f351399a818b8e4e7602d974813832335a81fa8f27369aacf5f391b80b50163d0bd9e31c199f7794facb6bf39eb0fa9e4c8737940f05d50ddf814df56c71fd044d8bd1eb87da0baa85eb992efd64f1408bb1af6acbdcded7db2bb6b76a0ad508fae04c2195ff8f93eee158cf97086aad27959f4da6a0ba1e7b2b67b86adb1ec6e6c4b91739c5518f4a9ee03744a2971a90faedac98b9d7e042a8a221e8a985a382152b3a57221ffa00bf6ea3b11dae3a5e34bab6d791cf95c42aacc7990a3ad85a8a01c1550e4acc1585760f0332148217f023f8756f8fecee267776a22c70dbd8ab5f866c1554b6b571cb33918e741ab32b0b3fc5b9300ecdeab71a1dac3777774f54011c16e29927edf3ec41d666ce8d4a9434bc9f62b751b74ffca11f0bb68b4564cd68dce3e2491117587acb5840b14cfb8f2bb17b4b8c80a966b657b21f0e580e51518757c133bfe785d93a6690c8615dce7c88093caf7110ba2c767b7a0cc35f8ad946325b108b7f64ec4ef28e9a4f731bc34e7bfbbeb03eb09ae721d337f0ada060f118524187d1d6229757c7dd1f60a44bc704b0ff574e883fcb770219b6e6dbedbb11d6ded642fa3e02550a90c9fb8f6a1ceb799f6071f11372893c000ef9f889845489f9f1aefbce281d1d6fecf1da23ae4d2dcc7fb498195755e99e1fc23a928b313f80a2db12804708efa75c2b8cad94f01262834438c80c01bffe41887841916f28bc321a3208bd74e28931e663399e0e91ec249cf176db2faa8940bd3b06d118a5cd3e0604b152a2041fb330a4995263eea5ad35dfe8d9df051bb5dc3a5dd53f446914e3e8c3cad4453fe01507df2421e928d8f28621eabf23a34617997a5f7233315bff59e47c9ad4e2159a1c36f459489cef4de1d1a9d4de8937752630c8c9487a22c512ce30a3fc470fe9538fdbd5a1529e3390676f8a7134c4135498b8b38693225270e4946483e0bfeb05dfabe6f608964355483e120752e6f5bd3ed9243151e411c7e742b13ed7d8fcecc697972b2669cafb6ca51fece4d8c44b5becb1edeb12137ff3b15bf6b87cca7dcc1920db02793394147642516598a6edc05b030bba33f87fc4441d39dfa44c9d6db36632b8a5c66ffea431f2b97f155a4ff7a9c22cc8d76d7826c98de5be11addc60c873611116d7f44921bbb07b234049b21cc7d302a322c7c1735de5c284f750c6a8e3445d31b07a046d1ce35fe996ca0439f07e20da97238c92c92c2eccc89bd36d1a21b1831f180b624d160a73d47d3079955e233716060c29002e7e12a65c887b6e3592d5598a174e581e59cf579316844389fa69f6400a93ada7d79ef6f4f4a8aa66287b33ba2d467bc1b97135d7894155f18ae01c406da8e9559e4df2a501d2dfaaf0833f2e04c197c6ff90fcab428d87ec4a7cb50ef9ecbc3fc31dc162786b1355c6f962466277fa594ba2634f47c0cfc532d9f22a108b9faf6881c0828558447754223ff8fa4838beed2ee6d98df8e885f28a5f64e71ff496bcadc251e609f44f3f1ea0d1fa41d994fc43fb575b8e54d7ba009bb1e777f79bda8a8f93510dc0d5c449105b4b1773f36daee4dfdcec50f61c8ccf3f90afd93c44a226c0e40c575dea038a480cb1866efb47a4dd5f223c279223dabd9b4ce0f48e4c56bafa6382419416c131922ecf7e210d70b8575c97849c35ca54c0b1aa4bcf1dacf5b7fec914d7eeea674c423bd2eff72f9541c3d0f781a6372c1104e4d358f268e4627dce528981c20b9949b4793b1a19f2b99524ea478712f310b354daa06d094e2494ba22899bf1ed50fa0121509fefa4811708a6bf9795b110ca28148c5dd93eb8324850849323ba62f83ac3c836565311a3a8a0f3f9688a4f5ad1d184546ccc64c1b7bba01bd00095eda2a8fbe567657b7d1d306cfd6128bfde0e5130d0d09a49248e271af4e72025c876691e884d888e78face4a162ff846e41817395700282409c7facbe5d5c4a8bfa97198f70c4beb11ddaffabb436742edf0d9c717786af0d9f2e93bbec3116630ad5fbb0826d6a4f48e112605883b117ac5d698ba5332c9edbad3cf2965fe8fd3b4454735711f16168570a03746cbdeffec4fa533e2a0c161a83d45a4813c63784e184a52b649420d58255395fce8a167ee3993622a59534d59b9d62bb167d74acd24b3a442d9e4a7561d668b7241263e2b5903b62f5dee6075c0364d069edd1b23d3263f16aa488c366189ec71dce5251ef47a1757b0359c4dc2e965f6fd1d0a52a6307a8d84e6bd95f27ef498b10ab2d9eab527ea203ed934ed12bdf672e22021e1a8a1b3d828305ec9137a42370cd5aa89450b3326b5ff912eba1b72b68a20b80906ff40ee367d7fcf2080ac05e0617b7259ff10fa796f94e61815a54d635b5b90b09b1654e8268367a14f8f52b7338ec0c862d25aac2ea8cc930da7b762676c415e7c63305e12a66bc22eae2ae53f3ef85d59835a8247933e18a471877e7e04023b908fe6a0df811dd64b84c5cc5b109b8f2380dcbd33061cc8d72fe232caffac3fb60692e4ee0803c40b36f85b6f6f0e796a076c65571e845a970fe26a1dfbea62fd97e743407613fb46348e1f4d3db57b0d2bdebbb5ef3a36037e2a17437e02ae52d03e09f3dc7fdf95d33d9d16d341161dce1037765c79f5ccf361417d7a78cf2c7afbd74dfe1c40165ab76457ae0a473ffe24deb947f533a37656264ffe6d344fdbd8acaebcb14d08368f50562f4e4fdfe821bc8404fa3e56b8109f4397f37bb1f84dfb3d8e576f148334eb675080cfc1196b37dedfbbdfec7a50ca221ac3f76f196ddd5cc9bc8883c3093054e85c0f8c1ef6dbcef475999d3b9c41f39eea82c8f9b15f8d8d8647a866b3db718c56a80c404b6465dd8cb76b292094e955576323c8b143e1125c78dcd3b98086a9cc8ad13820f600f9411272271aaf1e561a53e89a2425fbf580d612c7d91f017fe11918c75a30aee048fb8fe440707bf9bc55e2b3a3fd1e54e1c427c1ecb8850b0c49516017017e9280302e0edf7d013faac426bbe44589abc48ddf0ddf11484f57c6316779ec40aa67fe09dc8dfec00b13f095c7c91acf0770480455ca0cffcc6aa37ee42cfaffb063a7155e1a39975a13a8ee4e3a3495975e0b37a13400e39e39fb7274ff9e76f2fab3f99abd48f37891d2f82477c6cd175d4d9ed10592763f6736caf7fd4d8f4d0818ca36f5b53e486f3ef37d6732a196bf8e81ebde069df6d4e1f2a2c364de2ebbbbbed8cacffaedf77e67ca513c3679c5633ed7e3343ce357e752aede58cc982837bb5e0dcbf31bf857309b1bfe2d3b5f5eb85d43a6845fdfdf3eb3ddb06e21aea3ca39086d74baaae24b180c24a3ee895a20df96c0fed817a72ef9d8e8df41033929f80bf7b960f4cf949b313ea31229ea4976946280551ab3f959bafb81dc64aee9672a73f6caaff39b0a133645965a116d44491f62a3433dd443ad0234e0b69fca1559ca2225308df464db1612983221a28ceebcf9cea5908647710ad1fc875f110d23f85e4df61a8030e96cb5113d98166d16d92abd772963fe0f76724fa67b8279390f146a0814b4a4f40e5385e152fd914bb52c5fcffbcaa22e85856345e3d1d70e21973446a89e75e7c4f8730804c4510958616be581ac8a873d10f49915d356b18c0dc8c0fe4004835a2cd7378ad6ec2d7e04344f4b8ff087920d3167d533f1f8dac2412b03cbcfea19af6016b3616808ca338edefa3daeb8993c9f399d250dbab410f35281a9b2229b86f031e61f5806d18db56fb8d0e6ba594e502197c7c45427d328251e8172aa9d3d78602a1e1f877c5f4101d18295514d594c29cc938493a9b3a8df326a44c0cbd00002a24c27f845f35757ca32fada554315b7ba39d771d2a8a998f76348ae7a93aae331750ccbf16ba72bcd1e84c53b9ed3c2deaa31918ed2332bfccfe65cad075c537350fd6a26e157813140e439b9e73700edb296a10214dd8fc77a388878bb2a708df5869252fc5242f47aec5fe0500d6cc19901a9b80874c9fa22673def7912bc574a3534c6299a4d304a3337c4351c62893e9dca11de9a48986d380df078bacf28a1c1ac99daf24eb5afa14878f01e6afdcf8a573adf987817134aebf43bd81295415c7592dd757a4071a8f325185ee2bd7360e9d2dadbee48a81e381a5b04e5c3739732498b7169e3a09ddb6be3df50277aed650e596b0b366ead74f9e3937665d6c9300e5dbfa28e4a01bb7e05ccefe9b9cff3dfe26be16f6a622e4fc0b156a1e53eeef9f96c76f463ee088741f7edd3878d70c7017f12d8f8448fd05ad7e15e3ab0ffa52d5aa9d2d3d04d01cad8efac491531f345456a51b2d2493371bc28866fa9b7f14d8b5e23822dc4451cf70ef390e277e38f1ff95fcf9bc3341fd2a25f964fe0fa6d9d51cb82b1d8d2afae202bdef5a1a99a9002870702db39cccb62bf60ea1f0bcacbab857bb8c864add919f62c9d24195bcd84dbcf6dc9037fc11a5e0d899f27934935997d41b169416063e94876ac44fb385548ade38749b2551242769a2d43f773a4aecbde28841ff4829e164e760e764bb306559c18f0a1bc7898efe927909dc252571d16792827b59dfd4df6477e7657f2568176c56c72dbd947e55e2ff7d5ef90dd14d0b870921ba6e45ba17f1307ef900c7c2e0d26c92a67f4ae6ee086e87f3d61c64f5f9100366b236b563359d8bf73725691c1c50a4991eb534f5844f58ff04dbea812a897077eced49ae487d751650b8bb96fd7f9a7f4f0577a2edfd586c32ecdc0d273e2c2b07c77685f773db716804f53b2e34279764d65ec73ba52bc216da4344e3abe898a3f1b10b17c24425e3f83fbaa4aadfbd2a461124f03043d41706d1c14a5656d8c48747a3b08c80b3344f82f3d18c0e20f31c3754d8b9513d22a72779f315aacd6f49bb5f6893bb21c92512e8337b9854b4cb0d1975c94e622d6737196bbca8419b57919d5982abaa60dac9b4246222342139c4c952d79c95b1b66c77707a510301395d58fc797baed28a6b611111b9e6af8ab2d21620ada1309ee077f55fef583803d482b4b9360c28a5cb916111f4cb25ce16baf6cd274722619e276f13d492af7b8187740c03afb18707325339d6604438679374e0d7427dd68627d1f1667c8a59cc8b76c5d0e6fa86beae4ac7c2286a5ae4f022144a22b710cbb4e92be66b8ed31c7b99b2bdeb44be28eb9ce13b6d7a4b4c561ca844d3c1982a3a8f8fbc2b56d4c24adc7324a68a3657834a70324cb903c63742fe8c421bdb1a132db93894807bf5625e2e495b28959f84bc319503a511928534372a7bda05b32423cd5d945ffb252c1dfa5a33f7708f68fbec557e723eba9116e9a04b06d0646f921f905c37601539cc69377d9a0448788c69337443ec43324e054bb71ca46bf9aa29a1a435f928bb676738ecb8e13345cb08d0f6e993d3e100af75ce44cf96d3558d63f7b053521b9110c83c176667ee55c6a89e48bf24da3f6580d6b9e1322a8490f9387417515fd1ab3e88f79c269a24e574488b0fc1cfb97f877f9c6a33517cf8765a6dfd5f33ab0dfa15dab36e275bd5bb004778f00fa7b3b8dd080722b1c7414fda7bd09ea925aa6b2c667a3af24e91069b1df1df3ea032a3dde24b860ac17ef6cef4cc5334c155f6df74e3e09804dc12c0c3b98f826a9f75537318b105b8729ecc246878dcd2fbbab07f54735ef38acd989ca770e754d953f11e6ee93b61076a7cf3f39b3678b3b82b4cfe9649db31c1dc320be3fea1616e42b38ce097939db4fae32a76290fdcba1ce4c955dbb2f5039b73ee4f165d50a912562f2caf3b54b73d64b0385a96bc477423f8951c067d4f97e09655874bd11e3cbc6776c150156d145e08fd1fa207e0d6358e1622e1a831f8437cb9b32aabab42ea70c9ed70e7a7c77955e1e695c3025db50993844c33c1b11b3c73be5327615c7d8f2b18d0fefc0cc35b50f3084bddb2ee172897fc7fe0e05a1ddb9b753c06310d83bc1cb86587387bae701d75dfae7f3b631e4883f2734e3a2adc72aef436f6add6645be083e01cd21db9e391928082dc72b9c354c740b1c853c402ecb42ea1c592a6a86b05dcf28ffe2fc79a6e00f45be6ab217d6ad8eacacb861adc52ab0d931687da46e4b3ef718fd38488bc0e819c845b3e13525dbce31744ada74c50f0e134769dc7e160c02d5fea83b8434fcbfcfe9766382b51cf17cc78e3efa341fff550a829da21fef8e02cf42d8f9e3b962c2d8f30df7c793557a6a711af86278daa034419cc5858c4d6c518bc03ca49ead674e65228654f544e6ffbaf119d14b2a6fde5d3fde8f4b433f5cc3197964fb31a1b6761d224a1628f724249ae80830654ff41653c30a07fce8055fd897c8a23728132eab84b8f3ce1d828d583aec9ac4684c1a5535800965782fcfdfdc77ce301b10d2da7f37665eb7e5ba97c863b560abd5cdc9debb9f3563db8b0d305780b9577fc550de52cf19e5cfb2f237a762e9fa404f2727f74c1f2795a3e535543667947b3a70c3dca492d2b606b06532c92595e1183032f831f5de9ce6c1eae85c30ebb80d323f5287c5c7ade61b243c2b8a98a6cf787075e996d1ac1ba4e7cccff1f58e924a3b93ba3e18c016749a162db5a9614abe7c643a2ae584e88eb8f306865919b6b156dbc05e622af1c3ef23e2e54395ad5021642850f5de6b93ae71f8b6652a9ed9275517f6611c68add2566bd8fadcd767dba2fe61e44ba1197e4ff9cee527590317b03f111ad08ae97e6004c6a1325dcdee6521183d15b12af316a37f68f8d69a13799e212c50e2f444eff4ee8bc74551117413b252ace63f5e3baa4dab9f6bc8c585e42ce68f36f07c733255543546858d34a7047574e8521a6b80e3d1ca63509284306a4d673fad687cb04ed71897187fc58ff04b8c9963402c5a40aa2013223d204a95d8119386f3b2c8e8c0fac7fa1d7f1f8603dbd736dcfb4825e46ed99a85fbde46ff0e485d9e94071f6c6242785c4ffca815991168bbf9460aa8332410a2057393c0e11505656991795240b0605890e04038b8770f56df387906b6f4af5e866f021d245df9fc5d5cfc98f7b1d7d92947f83017ea61187dda8632b2199e247b838340bb4c69fa08a40050e90dc3adf90f019ab9ee3aec001588f3960f1fa03eb0659104f07e7b5bc41ac4ad4639e13dc8f19a26c337d624255fcbd105fa4f457b587c0e1765a8fd3e04c128e650b5e45c5d05ccfec15369cf675c4ad8e8430127277cd0a75200228881d1763157e3309732ff087134e2f26c9632a98344de983573c8b9776abe2037c80febb3fba15ad43a647191e8f05d49fe833f97eefc53093b39e2351efeafe738bc208efe95120f75755a43f5e4fbd9dffe43cb50bb5701e9032f64f19c6c38b56248d02739b113d3345e09120a33238072e11bc95203774d458355517c88ea2041d2e2cf12ff57038504f43502c5870da13c29d01c6ab7d61ed61b3bf69852671e5a57ec91f827ba315258214e25b63d4567c154d3e03c140ab6dca6050d32ccbec18e239ecef25ff035b6db855d44fb6759e6c5409f42768c0d6c124864a46ac1e555961f206b1e539ec0049944ecf6421e33fe9142c524fb44ef0b02bd5bc3f216fb8109dbae678c92d48e9c027ee0a6950c8c6b47f52c8e4ca667c4f5c1f2c5e404f3498b652e70f19f253d15f0f1c6a19a04dee3d63a86d4e7351fe04021b7734e3dc35309591fd603b6dbb2997554f39e1a393ae76f07d422aef90dc8ea282c5c0cceead34fb8b49d672ed1fb3087e4c0009f07b56e8f5c05676af4c92144384772786ef3298b9f40cdf9e075d52fd0d7d3c6e5c54cbf07183147ff82d1504acd8ee06c9a4faa8e06fecc5bb9e4d28195924f5ae459bf36409e0c368d3fbba571ca2f496e79af08be8244e9c94480e8ced9b102652c4b5f32d8be7ef45bfaa8621c0dabcee0ebd23e5fc63bb91f83041ebace201e5a52baf784586c7de8267eead4d2724dd0b95307cc110aa841ea2f81eca0da4fce98a15e6972427c8a05a371dc770f61614a32905c71b7eb2690dbfc438697d41f8612c2c6f4bdf6a655a3ec2f00713a24cf2dbd4f723b8dadd59cee7a8c7252714830aa92c57fb78def1869a8d3143b73c8e783de4bf0a10fd12dd8781d15e502688215b79459afc3233db1e6ecd52673f9780cd96dbe3121007f9a8fa886a237481634c6037f43989ac7cf70dbb2fa9597e95dbe55f06d5c7bfeb081399fc88814f3e1af3d23bc3aac2f9abe6526f5793f49ba561d1d99c23aa972ea09c4ef86ab33315b9a3dc9ec2855d31c01925b1c00552a794843f0f99c8df3d7343b703e99bef428e2215cf5a3b4242e5a2aefe11dfbebe262abb7203504137eb44c9a415bd16b51e313f896eef225e19597c4d50ca88318604bfe5899a2096aece95793e0d21dbbfe722b464b76fba1285a53f4c1fff13fb41ae4d6047df23b4346b0826c4a43107106d42d106aca65f6eff2225b6d158d02d4bfc26cfac1acaf332d9f65f32d276b930e06177578b9d806835860179f1846599b1822c754fe16f1815146551dcb7b3123cb59b50707f117facf3aca9282cc5a893c37681a0c102e88c584df076190bb604a04573ad2bc5d925a9c92f621599e0d8df7e0f97b402835cef870c6da097c27264116b8c22fd562888809ca86a336dad822371f09241a5a8deac0ffb9f073f6b0b4883dfecbc4f52fe606fcbd145c233fd25f311a9308531ef1dc55792d6afeba705d5da4bcefdb7bc4abed4edf7bc5baeb4745b3f8209ffb7bb6bc86815d101e8aab98453f914d3b8657a2b2dd2e17b827840ce007b5e78db9d162f8a68b80eed2299b1e54006a523b8cf3082d62db86fc3c51345bfa061dfc8fc7d5769e628d8a7e45dfd954199d9f01193e0b9323fea9005bd1e76719950d89990cc9305f41d0ba61afcbbbbe20922cab03acaf554b37005a4870542f1d5c5b3285fa69a7f344a49243dc5a766c285471fa8a276c4559b783efe203de910adf674d7ed0e0f2e2e266039de8e31eee2b2b7d02ce1027b3107ac254a6db5276cafe8c4eac87267c06cc10d72506ae323885504f0f0336c426a2eea9dfba9ffaf4b7cca62825fb845eea07e2a50321504c2ffc5c19d2728a44b0449beeed8eadf547e8c411dfbb1d2f8815ef259e03a6ee9188058052bd6756e14ec14aed0cc625fadcca59263db5bc8d2d8109aab1c369e6c56f54af7a21535fa9d2bb2c7977cbf9aff3aa83bbcffd3ef02f7f3d173f113729562eff036d196ebf7cfe3ba5891d03b018279ae5be3b4814d8fc6ab69d966a8b47850b57647bb98161fafa7750b7cbe5577c2d6c3805c1376df7a91d5343ce62fd6a992769aee99b3096f37cb167c5df7cd6bb6cb66000000000000000000000000000000f902c0f8dd941c479675ad559dc151f6ec7ed3fbf8cee79582b6f8c6a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000aa0b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a0360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca0a10aa54071443520884ed767b0684edf43acec528b7da83ab38ce60126562660f90141948315177ab297ba92a06054ce80a67ed4dbd7ed3af90129a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000aa0b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a0360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca0a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873f9d03a0a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873f9d04a0f652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f37921f95f89b94e64a54e2533fd126c2e452c5fab544d80e2e4eb5f884a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000005a0e85fd79f89ff278fc57d40aecb7947873df9f0beac531c8f71a98f630e1eab62a07686888b19bb7b75e46bb1aa328b65150743f4899443d722f0adf8e252ccda4180a0fa172c7225c779e82740fd5a7ee3c959b35f65da0030217bfdd9b7f491c92485a072ed12dc052358dc89ce62d77d3fb6cdc9a9c2f5d3039140bf60b02385dffba6", + "0x02fa0184580183080e6f8402faf080850e4f97cc0c831cf4a1941c479675ad559dc151f6ec7ed3fbf8cee79582b680ba0181248f111f3c000000000000000000000000000000000000000000000000000000000008d67d00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000161257000000000000000000000000e64a54e2533fd126c2e452c5fab544d80e2e4eb5000000000000000000000000000000000000000000000000000000000a039536000000000000000000000000000000000000000000000000000000000a03963e0000000000000000000000000000000000000000000000000000000000018037005b2ca73412216c1cc0181afef79b008c0c041b474000f13f4744552d5b8bbf38b01b3e3f42052760382a15100815a108d8ba8dee365ffed71bead97d429f4abae9111afb24f7e7f9b9fd39f7debd350c5a86383a8c1ed8055853698368f3e9663588f6148cc4023673c657ecfcfb82d5e8df446580aef981e0d22296746969d94bc0e28207e09cdb5acb7cd2331ffcfcf203b116e07f0f7af5e0473c3d080f0f9e6af3dfd3fd5de97c7c813a62099680df248b04954e1b180810e0dfffdbcc7e790d8d4013d226ac7108f997a7e2d192cd9366c6a8a6a8421b71d05633da803ce2356ff0201ac948386834517292c6519293e4c0de3e7d3582c76302626abb019711858334e32d8bc149d6067943042649c086aca2bb1d10c129c921337d1f6f525b4eb2a0e51e416b43a2aa5bb3a145cbb5484e38cbb33fda2cef97c3e7e6ef14befebd7ffbc96cd486f4376163fccbf1f777e9f9ba01d0b35bfc6018364781859a638001e6f7eeede7392b0c12639af017bae43b4aff6d42eb739e47e22c9333d0150e892c2d7302dd18b46451088bf064df9a58e42a4a4ba0ab2d142dc4cdde7f209404da222855ed93a9f4fb449c2b4dbfb4f0ef18433076648311208a400289e2f8ffb166fdbd0f33cbcaccfc9d33cd8f3492884a141111f662b30a3a876b1e0db7baaf8c890487039942a3da504b0114b88340acec91dc3a84c3741743c3387b51d38cd98d37422c9bb5fffb62bbf67b2484e7c33ee94643a65b89daec83c048c2f952b5154160a10184550f5746f275553960c72352604180851a20a63e921011fe62439838f831f859f252491298094ce0857a30ac4e5132301666b733bd13e3cb8dba94ba486703406aa0c9aced14e4892a32dd462a7453fd29eb9d2a7e4835448b8a1140d5a791684a54d472f464046a474d736235007d1a131d2d50c301efeda1b9180cc7c6f34c7d1bf0eed80cd390415dadb290bd923eeed6348c9518294fe7dd8ecba48f931481c1adc403565a87130e75fb1fe8ef4ffcb5e12892e905cecfcffa4b09ca9b8ad954e3cade790648e6a1216d20b06001109bb647bf6d9186eb65586bf86277ffcf00230429133a6634ca5919101762bace02541fcaca840f9188c63f2605713d340142895372163e13f1b1cf17028865d8afd2517fee1cad0c835d592ad6ffd526a8081447b5214b29975c09f4c60c771f30b8c57aa0856fa2469a5f2086cff36930c4b0afa37627456e2d323dd66625bc4e35010ae0fccd1256bc1963612cf400a53ea2cfbf0a92cde615564302bb304a1e23a8d901fae61f158611c22d5a9db795c3aabba5fea7703fe158b5a85f490d07302b1273315781120c6e1510c24aeb44428ae2f9fc245e9f66270de53a2a927f7cf0af9b55bd0f15dd04b1982daaa1b0837d78bf2f59715d10b2f3b3aefeab467726bd4a37b59d75fbd229ffb6419c687f7796c21be4b8195e62bf29458b39f894053ad2d3ac3c3426e2c04e1544df22ebcaaf68500f8210fc5086e923918563569d3ca88bbd475f4abc344be84e554069d2ab89e80d5492162dc86e450749360c1ea92d54be0fd8f7dc128708e5969c1712080930d34e0c2b58fe08fe49eb138142e1b9917c4a410c636e9cc5d7c8a9802702ce893eb7379f99eec02e802f094d284ff8d71d515ae2830173ca367a4412ae01dc831a8ec93e68cb9cac1832dbbec6a4a6f87180e5caf4b99bb48319f0583b1a3c6ff1aa6e9075dbee5eb30dad8435afaab5fe4b0a8319dbca1e9cd78522008da05b605672a9a580ae084762c404693f3d3ca5cd3b2b57534c86fe67b37dfdaf8e7309fa913b3a15d2010aaf938654b8bff0df9f68a24d9185fd3c6ada3e0ead73c758ff9bbb6dc40f07fbe17b504566f1799a05d450b4802e4b02fbd8f6189e4260601b999877cbfdef743ca4d75e6cfef251ac0d993090b3e4b0b5ce2f9b0d44904402e77f256c4e47572738a2e231e4561efd1a5d2dccabbd34b644dfd11eb2f553d63e997afd7ce228d2ec1ed92fa5476413adb41ee637efe8f48f32862f8cb42fa531b104c4bbe4536803f867c92fbb39cac96bb88ff48d572385430c01bf7fcd04acd63316b2703a10caed9d92bcef05084acc6f93156894c5cf0fc223b6541de01634a057b347230081afa2fe23e34840f4c64bba3aae8b755f0ff8e49d6d133aff9ecb20fc245f71786acb5c43a55e0b28f0eb48fce4fb5abe556867ccae8e280cde5d23c22d8c0b8b39302cf826b43f6ef7013162c98195d6c1bab9c1c28983d991c2815c6ca0921f35e6d53963d6567a9ca865b3a0e3fda1177c44239bbdb79a55ef437a42005c848e32aacb340233cb30ec3f5a98d399c73d31061c1c0bb5be1e7d26828b3480d39697460dcca16128e61a4d430d81ac1f9a0942788c8164fc02bfc19677865207780e8059493a6638ce7e1148db89ceb24a72f3d1e02141089ba9c76194d08dfb2328545b9f7d4c625885537ba8dc351232b888d1986781381f9b951af58ad020752659e21f1713193a081e9261ffcb1293024de84952aed8c6c9c7cf9cb7f90b9e37e5ad21bd35ff5f728f902d2c0a12c6b051e18b58b4b028f7cd0998df191380a6e156e5aa310fa2c96bb3f53105e7ffbcc9cedd22cd434e32075252176be1575ca165220b13353f3ab61eb57184078971d2099a7ecddc7b8bb40cb0737335385e5c3f35960a7b207e0754709edf0e3390e500acb8ce3b241c19ed734f18fa69435a0aeb718a241e213ae489acde57a816705460251bd22e03675cd60422152b997125d84ae9a9a46d11d5d3533118c862d6a046f998635d16aa7008f7038110fd822884d60a2e4b471b0489faf2d875bdfd687edb8c40f285f04ed8427f0cf049e5f58440bc42b0129b4027463f341a5833cbed5472a8bcb411afcef6802fc06e913d01835bd9c23d3e575fc6703d5b16902e59e30e749f2f164ae94098ca4dd6bfd9e795c3ee25ffee1d102ce687b4812d87a222484aa8ad982bf0ff4aa672b22677a114bee7636dbdc802d3a886073fc16a2307f4db03fc7fb21d2a5932789132a3f46c021e6a2a423d645bc1cb0a9c50bf6e0039bc9788c150c4b1567cc27f40c82fed860fd412d9314c4f312a27ac24aff66f16374cbcae7b5eb81b629e17c06315b3c380bb7e69a5de6bbdf45f4e40bfa1b55e17440d1adcd84c0422b18d6538105739109fb3f4fe4bfe87e337936a403d4e5121b1c106a7af9f5f3fd1d4b90a6513f95ef58e3e6736f24c92cf9e60c2e9d9022d0d9ddf9ace2fb91a84d21e4fa57330986e5333721e22d95fb22319951e6079e1fb437924a49ec29b09776cb0ab84b8dca63a872e8a903d35248f3c9dc3ab3ffaee2ee0d8a94fb9e6356fffc36e308e8a80c19e62b2915bce0edbc83c7ad0f843581a8013bfaec16339117d2721b65cae9f7822372986874180777a30c4b010252fa41858b04676797e5b86e494c65ff3b4f50d44b13eb903f167aa63f1341d2754db3dba1ad322aa4c42045742bcd71ef6996a88a16200750af73b26f6e0fcf4c7f890e612b60d63d4a9db247a08efd24fb5615c6088d1f3f794bea679d35c6f7f9f13786ab56fe741e54a7fed9675cd4cee20e8ed38f5223229481dd3cd3c19ff47c26465f9d068f3abb391d9ad9539f8ace3c19465907c4a822c591cb831afaa511674dbb0105433da241ff1f665441c96cc408731e82c5f43324ee43e6e9293b1704cdc7c69f65728fa759afd6bcb684478e390bdf539c866e9ea1341b244836b820553113cb36970fb21857b2913dddce63869ffeef5e7b0f28470fe77edfb8224fefa1498a10f5960e2e17739ac3cbe29b75f5b49d47b100ca5db46cf4ea2ae6cf15a9bc7228ed148c71e7101f29ade3e1897326d51d3d55e33442991d416d129926919214c83b3034191e5936b9d2af9577bf1100cbde1452948a17f25f01b251415d7c73e0d530fdae187f931367dd83b62dacf2cc6f0b296e006fee88cc55458db19e5f4d774081943d16627a67d21d82fbbc2b01c1dcdcb902c204ef77184ea4c3e13eaeb62117565e97ebc7a86d5532a73b4b1ff07bfa0b1631a0b2afdcb9159488681496cff365c5906311a976f451fc64a27cb37a65077d0ee19c8fee2d55ce6394e1e614520ce9febfa0f1ce10660f3cc5e6872026333656fdf507d6191aa4f766b7238ea9fc602e8eff309f60537f2a12801131a1497ad2633ca7f41c9d79541af9c602060c00f57f5cf35fba42cbfcab1604b1edbf59ba178a2dfa71445e13a242c1c00f68e90fe2b748cb86983bdffceaec8388ca0c8fe3344c77c5b40eaed8c8dac72bbe709e1c6f72c5cfe90e0dc44e5aecdadc66b908bec5e8d906209e5f887b9e0301e81a29631bc97d0d794780525251930770d6898ab986670a5e0aaeb09cdf71a6162f8ca7b1ac513d3edabc9320f9cc4c725d80bdecea6990e3051002356e4cfe546612c40dbd58eb86ab2334dd33cdbec999090ca72b88a9c87b1a1e3a9a05d3cb2cda0181ace171f49a5b22fb6a1e070778b0191f50515fff3f1a438f386bf1a596fc9ae6523503fa8998d34fc07ad6ad88bb6176cf33004e2923962a92334a1e00684c733f6a8fb82fac3d7a8cec415ea51ee6caf48d9f52fe6e669b621552e0749c2d695dc5763aab88d3c297c638016cbf90459c404a2b2058f6d0d49e105bca0d0e2868b581d3c4cbe8889b945f4604ca21e6fbe619e69885bad913f629a879913fd073cbe11e0ec9e30fac945f6dcfcea1736d9ff05bbabd0dced8ab408328312612ce1d26655ed4df29fe2e0b5805bcf376bbb314bab8b9eb63a0d881fa448a5193e6f2ae5a64ed46503996767ba535236e75dd1188e39558663751a98d99c83780db38d93ec0f01ec64deb1c3c4971f16fe38a0667f35b18d7b27d435fa93f416241a6394529e2000928f27e7deb7f5d51f6f87e8b4141889177b1ba0fede93e5d3d7ba8542ab3dc1b5d60298651fe89a07d8dfea23d1d2e2e9a0a050f9708ae76e1bb9288fe3194e13f751fbce34d5ec1651ac4bd81f951a1f4d5c780852aa426e3602720e3da8d6b8c4c31ea56f61df9e0688854c9bca8349e10bcea0b0c97942481a7c329da6967e542332fe7947abe5870e4500fed49b6260894e18ccefef2eec6fa63305dfe6624ffa5ee619963b571754289db156a010613f2c2f9929b04cd4051043c40d114814171760fe59828c5d10daf4c233017493d69c57e90cf909eaae27cf5a0cad269cb92d6f128d0e65bbd11cce403bf6b536002a305aa187c428f724aa0b17a1122aff37d1bb1ae2f194f246d1c6fd41aa3aa7117089ce09e7ae80265fea8f7b7d506d0c5893f4ff3d243e4f14c80db1a945c7011b07a1d9afbae4c4041f5dfa5a00084fab5e78917c2284863ab7c5c907eab255e69b6578e7cce064be19546c22e7b6b655bf6ebb923decc308473bed8b7fa8f012b57849b4e026d22f40371446db6c476e61ca50df0be304bb29e2d16f789d58823d23f1fd4fc2feb8bd7b30a35ab8d86c71146d96f27a2dfb1184a5a2702b0d378a519f38c0ab7cb186be97b1e5d0429c7275bc06461155d3a951fe780df7a0ee8078f823194bf2282ae9f9151d1a8e7c792b24ecf3226bda6c9f83f1a4c2de8c24c4c215a68bf83b944c1966480790ced60b2ba6649890baa17014f41dad5713e6a949284d8254d1c006e2314ecfd0af6132034151257d9cd041578674b8672d484caad6f8f6c1bd5a7d0f0353a7a8cdd050e84b10feffd7f663fcbb143f831f989c41ceee98c81ee657d62b38ed6806dce43fe9eb4f3b9cc4d4e1d542933b296a27ba35844649effbc18013f668b1972c06c4d0de01e5ab55d81261f0b114b1a6624b2a1d38260626c77540da11bc924c0193f234c167b47471048d7a237c49bfe8bea7a26ce7f2386d271d93563390e530acb88e42e113d7ea636bda43a8a63306855a9240bc0943a2c3b831c8e0234121045bd07699e2929ec937a1f39e7cf6b746e95c170d827a827a7e6b30806dffdd4f28d0b1cb12823743960461af911d12c064fba7632784a673a7e4225be41f132a2564616fd3d112651e36a154b052c5245efe8c7d869c922827b68cdeacddf7e37c404ae3c2afedcd10e4dcc323c6d1e703da9b147748ffc0e105184c9654eafed020fd1ec4d2a725d09c5f657a557a966b72d3c22073e3d028798068a7eeb10e168fdf108ffb7e1896ee4e7887c46e50b2e90197513d13adf2e52dce5045a42b48d80f050849b6df7c99370b65f073e2bb0f3435acdef0861f841be80efe7748d9699da3292f840fdc85376e35efa5df98fb5a42f6b91791a98075df1b6c2ee9bc2f8e5eb7e1b805f0c7d0827c9f1674b46ad977fef7e648d7c615443135f546e31c35d974a0268001d9487dc2cc276e8e97e21f84b0925bca1c9d2c1fe88776d203750752a0438f6a003c981a33521e4f6c5e3c24d36217acc8d0bb3cde58dc6a06011e8825204f744a908ccdc484c2d762e5fe2f1ef3449e48b79329a592128264d5213dc1bd9da4533f9a0b348f8c7e5080ce810c15a5e3ff7194c1c846b08ea439978ec54bd13455e337cec6ebb07a832620d063f7a3be759411b7e7d132ced01c852888982aa09b3248c202c118e1b670f51ae0d9d6895c9e34c022a466d382516184a89db28b2135768713df8919989ba85aeb00dbbb51542195ab0549418f3298d0f8e9cf4815bee893997f367fc2e0566a33b5ef966cde44e15f3d74592c0887e1b531f7430123fa13638e025e13b37f16f5c4699b913c36a826dcfb1493ab7feb0c56194f1c0185c1244e777d11589a345b38cb47954c8b8c8c9fc53528795fcb988ca426feebfca218497dd1e227624989fae326ad8fe6f62ebc63fc823ae121aaf8fb2d45c282b0683467b72bf22f1ae3bbf63d34cc6916d56aeacb2f47de704257ab84bcaa69c1ba5dd0fe915971a308520fcfc2980e95ed838077f5c5d4cc8ebb6a87f024c431615c71592fb49355f41ec1efc083e51b798a4ffd0df25d0437de2fda521eb96a09fdf82017e090a752a4f18c0e2d4a998f6bf4b7b06d544fdfaaad231f7fa6bad3647ae4bd6883fc7cb5275bc91e968521576cff7622a1bd3c975636ed455baa5d492f0a87afda2b5e91b5cba65413520c6023ba95579b54c6ef861b58954ce69f7ca6619212d7142bb2fdfa6897a2e4229c4625ace3dd9a40ddb9e406830b9d81e317fcbd4ca44a9d97d5825d18192c0cf2bc9695e2f20d6d28235f3b7d30fd154c29a4a1dbc1fbab84a75fc276d5c4b5831787b1753b0dfba8c67be1109644592eb9bd4b0a4c59a424458ca9ca4d031409366afb1cf8d8ebd7c0955a7c1b46ce0d368e352290fe5d4540cf158887358f35fbf82d63e1fe771f3c79b720bb31dc2d2d404d8d75b799296c7ae374086c82999729a3819c97e4a215b7e84fd7e8f2de6298b032a93538176315c5910bad9d1f5e60c36d14c82c5fcf2ba0ec7053be74303d46e30a8e5400a90ab87a35fdc575e58b53d581963002c8421dcc8a4816777c500a140f1e9cde937bf467a5975a4dbf36076838783fe0e01e93f71da45b0ff266c4620b07b7263a5be2bf4f35ddcf453799d2a85447bdb9aaf78988c26fb5ce5a0369606744eb182a9f1567084c99a4091394d4cf5da48924ebb4a23d7e376e14015364e5727656f7437c25b874d185a20786951f20a813202b4cbeac1ddea22166135efa5da15722c59b4509c3fb1af365bdaa85ff271f809b77e4438f327b6412b757f822027f710e708864a712eb0eef34eb448fc4e9a903748ecf5cc806bf4c2108874ef40909c3e8e24f4370d71644e2727534f9f7f3269681babf689153360adab5b90ed4cd1172e99a5f134214eb9df15665fcc9da425e0b15fcc6831116c983bcbfb40b82b7ca04e2105c4c31f8935dd024d8ad9d13a7dd8d88dc9b111f7e4acd565a577ea83ba29924a538db0ef82b5a9922544dc9c31c4c07bc127f9b15b5de49cf9e95ee81ede7afad6124d00529738a6615f9202b43bee8ab62f2893966ccad3483ae31dd6d5377be9d5a06c4e7e7186ea39256270a37f2fab222ecaf87ffb7b2ac1c40ffa031f8cf8bacca97d3f672607eb89892e24420c3f328f67edd520b102b05fb8570d1c78fb9c703bd144e35afb9d2e3c2e0c85c908925bd0a13dba060fa3a7173e99e5794eeff4e01d0b4bb60b1d356e663ffeaeaf9798302356b5d5c4b8c4d4af71cd765be94cb90251d6de9d80ca466751860d5e9ef59a8667005c22259ce5211a3230de19e4dc33110993ce3b4e9a2f2b32872d6e6677d5c1e1ba69c1145908d4286a406643a23f13b6d1d07fc1aad8dacb73f91aa5d6f1c98096eddf8de6c262daad06900e48469f95e51dc0adfbca8f91c7ed7e49f31640e180d271aef19eb0fd62f434601f8a4d3c1e0962258691da41e1cd7147ef891e7fd4fc316f3e104d9995f6014c48155df68375b1b63a7a3b8dda9b7cf5141ba270eead2fd218074e60fa313849eef755190e0c017f8869d478f20e4a56bfa9ada42d23ff4c9d170702046b336af8f124697bba9eebfcf4065dc669caf83fb5e4f3855f134f89a39a976ff287bf5f144248932571c0f4bfb4024dd0e070d5df3ba51d3a735a9d5649dee993f030aa67a69fe90467126380946c26da6a56bcbe71952a78fbb5d12a0dcc80241508342b5c30e50d071fb1de13c93b16f219777667f4a5eb728da5a662d9c2f0fdcde667a900408672fd757cb9409fbab6af50326a2571179d99e99f5d5ad4eb008598f8f93002c3e38f8a1c74c2ef42aed5c5a0fcb2d3d7ff2577d72100e2477a109a10d7bf81b02504f99f840601bc3ea17a7b42db354a5ae98472b5dd330a1f647b0b42ea2ca61186dd575ad94eb5872e00b0947a57e0b093325f24dcb5f717e58c71bef888e98d786cb2eb284643b3a08e9000d7dd5d1a203f15e7920f21f91c3f0b4a12cd1547ec4e9916f517f6be1784750882ce44388bee058707071b6323779636d2e692bab6542f5d67929863915701e25e63570062a7e1db62dc952268af521b7278e4f9787ef1a11d7cd3bda5513347fc375cb6e387f17414800b41eefaa9703674e696e8106a0b146bc3842d4f0391b662211eaca16712b81036495abbc9f8a295fd43afaf70001b68e22905907d7acab64305a403cfb5d97b73c617884a69b54afe449c64f745db8b9e5033fd639abc23c683827ca6656fbfd576f7a36365ad74c9d2c7d6abc7ddcddddcb92a7a4a382cf345bcced31cb494161e9ac7cb24d2de09e8312ab0991008c8ba9749cb43b288105e142cf2fbe6530252a736f34f143c3095f2b16454e09f08e2128085cbbdb0c0aa2f9175cfb45f0f63902b36c1c3f43f1d0bc9b939a968fb93047f02bc30e83ce4b4f5e890db43cd35a629f148e1b84629c7f2e731966103172e090665fd186503c1ae2c5a73bcf1ad1a8edf20a01350a829b6cc6e2fab768bc7c1c29a7f59f158e387610208ef78482e250cc085091101886af5d7a24ec7ec73adfae5477a51cd48752e7bdf6a450041295da5c2a84a12e93d5f8d0bb0a1be4adbea7a8ca6505d23d75be38c620983a016a73d21398985755dfabd8e4fa9b3b546d6f0c2e21fa85b3498d3e1d4ccd3b745938b679fdf383bec6ce43b2c07d14f879a49750737b5fe7354494aa00f85fdf42132a2ce46f85171b7b93a20c297bd2fc8b0be223f814ec228aac109689d5c7b2b9775071f564dbea9add651d214821b1d58c65291820ad3b87ff5abed50b6137745632e9e5aced5550f6851930732f2343d4b57d270de766b4bd523ce1e8dd8f4236de4fe4237cc6e21d43104ce28ed188338b809e1d44176b6bd9b4adaa6f370e12d8e9f6e10e94cbe142fa6dba011cd5a3be51d975895c83a71f70f7a908fc86ff504e7079979d05b85a33d8a33d73bd79b8466554e76fe4d18249f4239016c6798f4ba187bf4b30bd84eb75369604a0acff939bc7637f1ad2e6388f2568f3f00dbdc1a6d8d72a206a00ae76d8f12ae404299370afce524e6de576ee06f23ed63122becafa8674e7640f602a1eeb6613bdafed43a6139e6c0616131c88f6e39fd1fa998914b45c119d6d37888f2d6320cb6a8974fc81a87008a2b7c4df7f2e84a1d32ca73fd47a4ab703f4aa35a8157435344c2e6d9bdbd521c57ce3381c2010fd366ab411c6d77262efa012a8c11458858953a43e2fff75d7e9c4aae589fa0e3d7a30a5d66d7e05b2fd1595e537a9f941ad320958789d1ba937c623b18010bbcdbb23699c0590a222912246799bba7e7afd1c16ef8056422ffb1865b270a5aa7c3ce04516e8f2545efa6e20217cbc5102fb918dcdef0199fe6b26a8952dbeb1db70edd998250fc3c9b3253e3a6b9940640901b44317a0a37ffee22b4ebb917b362fce8e6826505408fdd0125929a88e8aab394d8b3e1abfed404c9aca947540cd5c17f3c522c7c136d514d882b77206a703fb4fd516ef3ea8b6d5ec8b60ad868d91bfa0de51564e3b1035ee5b19bc99e4428d8a8fbb04dca7fbd2d2fc7529a8b304a987ce5c477c81411703071d8b97ce05a3d54a0f9a1c73c1afe802938bae201f676b33a1e9fbbfc4fde1af8e990ecfaf4970f70802a022092c433a80e058e58718d620e12c54126df662d69a85fed5cc5ebdb7b52f0658a190535820f976f0066981856eaf60e254cc172677fbcaec3b40d9249d5cab695121864485294a4541d173600b10dafd78c637c8ed5f54131735987ee478ba99137dfe678f69097c25835b96781ee58c4a58e546352f60aeb9ef34530446d891e09f807bd25f7d57a16165c9a9f190332ea08c1b539ea544f3feaae0e957b03d19ffe085ab5c6a9cd3e90883fbe342ccceaca4c202edb51c425b87f047ffae219b420c592470fa6ba0ae5348dc2406df0f2a5259b7996bd867ec533322a68b8353dd398a4e5c1e110c68259b9aa4e2e4a92e7f57ed7d0a7f292fff2a7fafeb64b4a9fe6975653c645441c82d1ee34d769e2ad98683fed82d0363c5498d1da4c0ef17ce7ddd038c6447637dc9080a95d45fdcd16d81654d36faa7040911558e6f2ccb50d1b482283ff3324108fb5bd67df51cae2a92e466deba6874eadf92069c1d9b7528e47cfe5d25f7d0a5860ec87189946aff5b821f8f76520d088a8e00c8cf70ac45933b446e3610c4e83cf43f53bae7a22b24434bb24763a528e945870cf658cb3d2b570794568f08394fdafb88c31bf6bb7497beac8f85e942f0b55302033809d0d06666c036194decb95ec3ff4fe18612de9bb6ab7eee17901de13571caf48282b1ae84b2dd6bd80195a525697529371261759a280ff11e65685bc3bcc039d665f2ef9daf54d2ab28548a2fdf300d978103f5e2931013c59c8261a457d2d4fd8b53c44a1b8cf3c0df25523e25c5816a3fb5573e00f67906efa190308bb87d57c529e589e6c02ac5cd36451ddb49d6096268f0f4670748f33476350359965fa01484b8989cd8934e9ca655953b24c78aa8c223bd326325fecd67fd8b3fb3015a2c9001730bdc491047f50081152694dfcbedba165815c6220524102382351e4c04600472167d278173f281ce00cb647db39a27e95fefddc6a6594628f2b5262425a273fc4ec99549560c6c6b11a544b0c3655af03e4743680fde4aa11cd5d6a2c0b9f89965bf04f6a310cd6ff4b4162ddab58ce6ea23bb456f4e5ad96f667e7e6e6e3ec59782f64b5d91b702b04cd773451f9092f83b8abb5ac4db3b69abcc53cfe921568a8c6574ed4dae42c2c4e8087e456ce40e4383228569ea9b830e6dad8bc698fbdd7e5cb9d2bfbb0d0d3d1ee87ecd3c88c3bdb002e49cbb434568d3f6ce0b25c75592cdbf3e98bae5549141a6afece7d5d36afce15f35c5e854cff1bb2f972f84065d96960abdf6caa84f40761220b6be1188420d5ad4c1cd3de858018586f31ebacbda378696bf5d24482e73f2f5eb4e5dbacff07a61c0ed1f7dabf3ef111e927e9fe9d550d5f559592725fbf289ff7b5fdb3500230acde743da48153224f35b8ac2ab5f389dfa4f524af269ee4189fe459371caaa67915fa8fd9b41f43db50bb0f01299f2e232b3268177bff3e4f70d765f6dfe465c76d41ece0c308ca8461845001c4bb6547fb93f9696a970819c09d05ca28d7604d00dbd412be5506de844e976da30ac422ea807556ecb6669e560a1fe638000f50ee5ddf4865c204c01262060ebdbe37fd9f829967ad308eadb9fd2181c64f2052ef3c4cacaafbcdfa44d950a50393696f3e34db7b8fff3a1620cf14626ee8ed574dc6b77437b9d39da1a7ace6d03f2bfcfe50803592a61c575a1b3f7a8de862511f96e7b14b24bd374df91274956606c3abdc5a90b065a4c6f67429f7e30205fe9d11ea89837eae3bd0c83a903fab70c30f9278641e0b06b55c0091d6b2b084879e09e1f893d2be09f00a7883e64277387602735e843c24617ff5258a9bbc42afffda095468166a4df5d5b18d26e57e87b766665230164a700914134517a2517b065f550b48ae0cff1b8c85723fe9b1fbaddb9bf5d754b03d41f68a220ec3e7a340651dcfbcf03463a8942ec8da40d0a1a28d23201452b7bd1752e8bd4ba3330c1b1d243e5a8876df013edb0e7100f87d513c9d7775e3bad8a882249cf1a6f773b7b401999a4302d28c02c0f702067d185f9b97b85d2711f450fc56792bcafb20ce3472cab1997c918d37522ff672cd6512101207933c36b702647164fc56266b55657b52c96df0caef13c0fbf3f376966ceeb22191dbaba294ca5ee520956395049cbf3a53d727eaf637c9b2a0f349a710ac0a7f020a4bd18cd7461514b435202c4af5a2910481ed01f28ca03d4107f483f14b81942f95b22b5a66ec52eb993b57ba5f5d26386fd8f8e73d7328622381ccd910f608a208941142cf21763a72957b83d8443188a929d19c4256acc4f08a8afebedb10945adc1af221e32197629e12cc48792e84407cc888f57aa3a7066c8d70b3f70228c589b4883d122a4d4b036a48185f2acbd025408311bb004c069e4ed4fae489fd4d32e19646484c3fb27fe8d3b518c24fd0bdd6b8fac0f75fc5f8cecab38a4cacd35e156aa312844f74fe9fe71bd236df62fba043da7ac4226a742ca93b6275cac8fec090244d2db329706995a3d3b9971f0b94c5e6db4eaebaa8a556f6b3d02496810b4b55b620aa31b6182e573c960aadbf4eb5d48f261ac1e2c626c13f3172469b50310e826c133097e131be4d413723f19558404dc3584bfab3e7f38b8ff88654116de8010c8677d2e537a4f323885f08e0cab908bcf75451411f5a9fac72e5b5b73978c400b122412da53830c58d0631f57ad860ca5fc39301c35e96eb3effb0c64b1210288830491a74624f2b2c89a2cf265b2b8991f48bca5a962fa392d1b3dc0656ae3b26856323ac3ad2b564130896dd239751a72b4d08346410a0f0e4d5dc75b32ca9488008286f92c38236732591816d27878dcd312e3a76081ea2c8163c10f1fa3687994cf93a049c7729fb7a64143da8e70c5426f4f83471c58824b0e9c233519489270fb4b31e51615ec2b338bc344e874eb5faac2fab0be6d8b93b7a74d598e4a52dd34d961f6501986f09bb75a6ad830216478c0b89076190d03ad88784e962f8d13498e8a1e219e67520bc8f9ac76d009cb5c204ce88c5e96ef73c2abbeab16738b9bce53ad29b738e75393c64907b2129a30bf3bc25567507c29d0fe1ad3a6018699f4f67e3b87f18c18e29cbe268c3f8b00f5b5c186594729af15595f03d89fda1b00713fe161e4cd878b255703b47d1544d3acd33851faa9860f3aac6cc2858a77c11a27895b1b00443a78a9dcd193e5ea6f65e494132fcea7e8c39807be4ee94437b77ed1543917ddf4c1870d4800f7aadbffb5f90b87c9239b3aca0360d86e9cd4119acd8c8d1f4755c0570e5a3adb2ad27723956fd18c966ec0895d81fd03d79897e3e8aac14d92f1046342fdaf26c723e047fc05237d6a061ae3dfcf6dc647ed40997f8e7a19db639d0c25615e426994855d87145685a9ec5770ce46a7434ea0199c6966a17d1659b3f0c4c1feea7fa1ca0dd0648c816a7bad85edfade7297678e378b11e6754c31d38aa9128fe5a70786076bbdd6db905142ddff811ba7b374481646f4ab7ad0db7488866d21ad5f8ba828f8afae721cc75bf513c3e141a5ad87b4046a63fb3b705d7804159e3e04868a2d57d5976735750e8edc5283c5faa61ac5b627827e04eea4c1b7d638fb4041ee71116848d643b4b4cd5852a2b191ee51f043b086c8d75f333b3388484555aeab44098b3cd489cd96b397bc15b8898e19b9d0dd28f0c0120f9d7e10ec5f9ada0015966bd9715ce9d1323bcc6a2e09e4e632cb1e0267faeb8bff762f0c1cee20ad6b4ae8a1e6ec83773519a83c48eb032f34f6dd0394784025e07b3df2eda0b45e3d520ddb936275eecf18ca43761bd98c1ecfdeecf3265e85acbba31053961f17216915db3905311c238153db77a8487a4f3cf2c39490c1cac075c7f0e8f6220c4b403c138422ae618b52d8a9252a98021b4b4ca907cb7fa916c70b6b6eb365ecd6d3ef8cce88ec70b45af1722142268475b82be95e47b98e4b752440303b41d695a3efffbeefdf6473aaf32380522a975f190a6a998ef3d0ac21f185858f3b8e70ccab67fa880fdc8c4557257e012c1f042b7094a72fba452fdb7c1d64f515d94949b157bfbabef243cf7f5e101ed51730fb6070108e88fef135e44f6290984c0bb2aee8faaf6be7babfc20d8cdc3ef103483c9cfb87ee02116e9778d67321e1229fd5438c4d2e8adc12279f24e032e177a89785f01044d449a649842d7fcf02dc6ef196185c2b7e8ef08930adc97f7265a02be3f8a38c5ff102c864d50758c08b16daf62599bbc75b2c096c8b4272b9f36b1a0ced678b094fa175008301b4054e25d344293c199bd8266fa973df138f016dcd7f9d524132c1a5103b5255e7295851fbc39e35d5367b9a65afd4e15ef837dd3e5d6c1f8f65ed814a77e80ccd7b66948706d04a6594b6db2431f6d5b4e8306c55581787c59788fab5fc0f9f886797bf0ec5ff3a84ee2251e42be51ebd108d74b0f5b61167cf357c871931fb7129d5b5d60294c7f2d1752412a86fac42c0c7f3f0ecd03efae729c63d7b65f8fbb88fea86acc49d3848cdd18702b0737e1369281040966efb3975bf4bf41d6a45ad6a3719ce0c2cde18f74f603b75406c622ef41ef895ce84a5ad394fda7aee0d29f3a7d37002b9377768f09536e9d7389542cd133ba8579343da102ce9597e808d94207a4bb650afaac3bd4151a542dba799bdf096ae8675e48845095a9f0185c2f8f4dd1fc9a3c3d566c30d5dc55fd21f6cc54faa8c78ebf85b11570d27069cd50a32546af71a385f51ae74ffb99a3aba780a29a74dcd024c4939be2ab408728697df2f55b9f9ff172f3d32c82a4b515d29ce3f75dd8042c4de633380d446f56fd146a0e2e8bae1fdd32904a4e2c90a01229c23f2da9f1f51d118586b08accd4137f266fa91ff7280007d463ce8d102a6b8e9b0f9d5ae7045f7b5cd38cbf05d93ed4be4bbab8904a6166afd4033e018a75f259e0ccbbf52fa6d42d263d97d715a7ef154ea625b5393c5f74b56f54ad60a427789082984f27e79c1fb82295e92d83a306c71d7a494a2b84cf8b15a18e977ac647bd5e7220dbd7316a7fdd1494d56cf1bbdc1e885626fd0d0d8a7ec9283adc94c9c850190700b930a00977089b6d2cd99a9168b3daf690668353531bf5abd34e33632d6b0396839990c37ee3944632abdb2d566b146a3a4237db47a49a92b8ad12af845b6994e532756de701fd206dccb7848f431ee8ab33b3fc3f476f11aa4b57f0b363b2be6374894230291c4084e3039738e59e587cd6717b1020c143f03db63c4edfd22e2616d462c324fb1ee1ad74b9b129632a91a902c4a346cbd633870b0152316cdc9cb09e20e57ac9c6882a357710c85433d92803b2042ae4bfeebba532b4d54da89e1b7efedef057ddeb6aed4f5aa8278aef4e4bc6aff77991ed038bf3358848ad5571fb1a88dd132dcd3bbe96b54621811766f493f21a3d68f46fb8b8bcfc5e4f16612f3143ffea8edbf4be60224c0ba6699e6dfe0bd6f872f3b63936bbf48579af1e8accb28587ef620fbf4011d4ffc54994abb31e9a7c9b40b1965f68a3a7bbed048ff3ee10490548fbca268ae9f78e66d47c9294ea51031a277afc6c4d98ffdc1ae27b695f48353b7a77095ed37b3c2dfea4b5108c0489d9adbeaba61994ce21f0d6eff3ad6ff97ab5d71ae62dc0292a1dff08c471c1d9039d68f86128da0089542220fe90e13367254da884eb21b648c1e7fd02ec6c64410a4d542dbbf92516a92b2f94de7ff503ec5020387f1caf575f4e10d571e8f442e377f3fdd5f00075fdab7a2611e17fd3028fa0003c90b241c0a20c2f271d37658296087ad98a2d2e0012e50690d68f4182894ebb39f3c4a8e14006abadd551a2889f072ab8b1886d908fa052b29510b20461cffa597fa6e23aac7946ca33869e7c04299b87a696189a81a1970d5e26e0b2f3f44d5b9e32f7172d432d6b307d736dcb488f096aad315b2ca62c54190cbbb281336495ef08272219d622fed8e5632124869e0e73c6816b027c7fdfcd53d196b9e0baaec0a0573cfc36106278ed585361c30799cefc368746874baba86549eb7d8a928fbd553f6bbc8357171982b25eda5a10da1be533c11ad252e577ce303f408885cb90e8f7bf8b7566fb410edbb56de0adad1d67a2846cb2ef1b130cb5b1e556e25d5281762f5504ad04c755944af164d9370201d9b7933f3a0059c0601aa41233dfcfb2ce405f4fcc99911644ea3b3252e8a0b1a2fa23fa935622bbe94306d9e8e5470e97295d7e7660995118461d4e228c07157ad312994244611727beab206a0980630ff392596a076de8b77bad1b0ffd44766b801b889c3e27ebfd1f6a5819544c1fb09104499208d8b696c965e815343caf376c1b75010ad4cedd182e8f245e46476d7100150744d4bded63225e04b8ec8a5f2696797d45ea3ff958ff94c746bb7639e7579ab91aaa28043ddea16a2205d6b2ad05e5308a0239bb64410bfd65eb37435eff5a1e45ce6b3f1ba1b824645fdebe12e777ffe1ce0f3cec5b4f012b00017a2f30f86f18af493517bfe01ca6b17dd73d9d94a97c59890b719f256a9895591d344ab0e8c4fb0efc7f6053d37603124996b45e41cf408e8a6f040b259fd4d39f03dee958a46c2c7cfcf63cb5b1c18d7b46dbf1d7e268a2f0152f61ad4bfd6ef62307ef0ebc8d8c7d193fe9f04f430c16c6fbc042096db0a5fe17fec3324f9284a5ab1fcbb758bc7cc2d9f12bcc1aed3a20a197b5e940cd2d16628c809020306c55f967bc9cd32c5955d14f922c5bf2d77cd4a0aa97affcdda1ba80ec63cd47e2fd55c10e5095199d6ff5fc2438369be1c7e59614d83204a4b7af7e3de8c5dc372c9142a56e4f5562e236d40e84e5bad330638492f5f77cc9adeff5f08ebfa627e5321be356731ff95f81abab74589e28f24d2170ca85c829902ffae84baf8f6ca28234de3fe8f9e4975a0311d3c9b2f44de6062c3ef00eb03d0ac9c7b18a64b48b80f571a48d723325ec2a90805fda66b5f060a96f1b0fb1f5a35a3c08f9c77ff28ce8177cc13aab658cbdbd6af5e68e7e0df529353b8692dc40788befdb47ef192fdd047fd17e92141ad0640e9449621efc52f98d2e4403f3515702cc58cf970af87f6ce3f497ae1c0c2bc629431a12a26db652556c915df74c7f61c22d003a47e4e5f90802ea9681842d0062b3e0af9c2b8542ec125e3ee118002ec9fc3bf60128ee55f3c3753c74ed07c1b34e6c72eb6ed3b76d06bc96dc1542c3bdb0079f69f0dafa310dba8449202232c3a1351a481469a40fba05cf26fd77b4bf9b162243862f97ed5779cbd4bd87e842eb9fa71dc0adad35c94d04661aad8cdc77382f829a1551eec741b537c13f2887299e6c4481e51ca99b84985dea861e62c5911ab54130c9845fe96c5756da373ff036a80b062d424dcae225755518a50146cf1b0825a0f0c07ae195da316ee340c585d2e8ac75920df7c3a6a102e2dd6f0b6e59e0922e37fdfaa239525db8a9036a0e587c825059294d67f6ca44221f374d3dd0ebe97924b9753b59e3ae1c96afd6c1a484afca503b583589536d3c831bf96da3f090849d25e08d2d43b1c4ff50d5efee2b1e059d27cb519761cbedca03ff4b14327a460e88ce2d75e4d34d5f8d15fdf6d3e7c9da894fd27fd9316ce2ba5ccbd7965ffe4cb99188a94db02f708511fe4f718c4fe52740d8bee62edfbd0aab07bf51305d5dffaef24770b57b33ee5ce01a626d998b3e2320bd06b4d6212f7e44f90e5310b1aa0719a5d3e89224bf1603fda90f5689305bd660ca0649c1398115648049005f11eb4dbf369d22adf19290e88b6c8f30e9f2f6f576e33c259d738423ac00b08e07419b34eccb8b466148c9255436dfe16179a3b9fc81085e668855dc747ef1f4c6ec147d4f901925209901a07411f2254cf0f3409989b21cbf63b03521382453332a1af6902449a38300e1975b184a49284b39a9e14c0869a199805d1b384882f42b9b9b9a9cc32482f4f11de93700623afd8bb59dd57269df528d4973c2b03b561ec651020f77f254a651fcd73c20af27aa6a2c6d59a715c480c9fe8caebac1dfa9e5f8b6df16c6297405c96f5e93fe6ab2aab8b85dd4d476fe5d46f638cf0f864229f4953f3f9071ae01c523033f72df4181926e55c082d8883f39e65dad4bf0d376fd93b75688e840b3b0a6b7f3f66a62228d385616d6dc90bdcd41a665c961f7666556de75f7340deb11ceb5ad8dfdea6bb22cda805756c266ec90421ed563e3309c0a9a63e2204707cd4988a5de83a02ef5c543eac1e7efa09fa6aaf986e07cfa84b1602eb42d29848a6159586262d1b9546395e2a444828b11ad1d9464a3ff105cbec86331da5aa713329cd20c148132c73d20751b4dadf26e3b5117f6bfaec27c2dc064f7eb518ddac4eef4eb3629cfcfdfb08b82ca12420d587e86f8d41712b581f5c5987165e79e3568ae265f53d7aadb5ca6b9b19c35df9d9215662d5f9f9df8bed7f4b0fe15f8d65b8a32678f2accfa34912c595e9698780ab2e8001f9b8f8c98675937fdc7971284811a0cec7f2ce5444d7c0bbdf30319bfcc64f9201a10373332ede7b790e545bf930a2c590b6e6ef320beed63c5818aa1cb4feb24c8a80c9c0afc435cc605bbe4da9cc57659ed2e07f38b65d64f1963cc8cd75fce8bf2890878682e71f2acc49b239b4639698f04cee54adb63df73872fd3b5fa25f0fe6ccb1d359a4147eca732583d9bf00eb32550f084b9c86e8104310099cda3ecfc43fa66be2be7a8a9f77cbabdf5320cefe7b9c435eb695ec3c8db4836e74e435b7f20227f8d93ffd2f3b55eddf4617fed60766ef3c48af27ae4ca97fa90c68cf04db37d5abead4239c1e3612670101125b86608b6906b9971ac901b57869f482d141fbc52e007ed076fad6f35037d73af1bb682225363a67f7ec5450cc794e9b286a54243036ad0c799db4ec3e5c9999b2da047674c283cdbcc60651bbadb66d13a221fd13e0a2a66fe7d0d438e0ac1ed99a127cbd71d434486eeac6617a682191533ead57e9806c03302b6b042d3b645838b372f1b75b8ba26d9219b42ed7ced3657e6652341009a4286032260211f5555a1644950d442f7f609e5d4e0b571327a59f7c24af0e238b24023f43cb3459c58649bb70ca308dfc242977274908224507b2c24c7fbbe7e7788ce92386144d7410777522705de775981c7c2faff5f15d94b542ccdb61d431e1c7e6c1ca88d1fa763e6c91fe18577ff2ff144bb406322726877780fc6d0965927c53f70f87a6d75f3123f9ecf7de0b69edb67d81247b4f0501ae9f1d58e4f5a2adc06664779b2f9968bc1bbf33a24301a4ead34089b1f794552421a65e2b1e420244d98d7b9e4b60597f24a53515b3e4b2190c915e1209b2715d4c99a23f3f65fc6cd01e77c09112ac3279fab0f6e8ae436c700f0905a6749d3b086acd0faffb8b6055fdf6702629f78ee84283ad0dc5d99deb6c37384c7bf49a59584e4cf8cf07890d800ace0a2fae3c4c64236289744057fd713e796970f2074a938dd775fc6864c356455143e0158dcdd71eb9a7e691c0d5a45f26d0a5dff1ec77ae376517123f0a012099b0f11aa4e49f35b808ba28f26b26e501ae4edb84da33c421f81551b2563d6a0f4011e6c5f2c7bfc9676933731e4cc93ea32a87f7f9d9ec99652a49f7268b194a7aabfef581299eb8e1658391ce888505de1ec137266dfb6c9a19625147ecddea08a5c32b90ebe442c68489c84f3860414c59a26602093184048190431823bdc3858764711ad0d9eed61328e5147f21861601859cb68f0f9cb791473b81e3a5467b381a932c3dba38d4082a12f983bd0b8ff71752b3a9115f1a3b05f47e9e4b1460a59e49a779068fcaadc9f3f40b77da55555f926ef4fcbde9128e107c44c97d9a356b8b6efc40219fd141fc8c59184bb326a1ff5d2c95b96fd838f247e273b307e392c638001a8c40a042022b9de91a7cc59651c71f9d43f52fabe7beee7e54038c95029d3ba0ed0982df3980f15131b25454bd7fc2b6e443d30cad6a8d560ad8b4ba8f0b18a7ef773d565ecad7701f70fadf56b77bf4b89e98c8959c9687a41aa2d9127d3984737dd4b9b20406a8045fb05a9c05e8ea49cbd6c38465821cb24aa05bf5001a7dfee751368d3522f2bfec4d4384a57076127329ce488f2f8d79ea111ea2ef84b57b0024040ed7b8113b51ea699f0a59e2f5afccacddba94adf30289861f2e4c553aa9f5e3b73c347edbc4314dba1bb60da121f14fb82f06192dcc91d388f9c3d8205195909a0ab84c3e427635ff7f45f4191586a3ebfa230bd6714e3c4ace226c3774074efaf57bff6e00a7c7c03ce5444fa56d0a792034920db878ad5ff91f20e22ed577429df9f83f6942ead580e0f87abd701849e96a5111de5cbc68ffbb0eb0affefd8b22acf1b869dbef8751530eb3960a1e97661b95f3ba2c8bc72d974b5747161aad0bff8f2cb84804ac3be84755043852166ba98a2463df751afc5bf6955a18ea03750250d06eea8168b6b9fb7da66beba7e4744e0718aa9cc6843eb8b71817f4e3a6435951dcf46992d921e36f76f09e856309cdf5eafdd3d1be344ef48259bf9a840a5582ccf101fae206e10478b634063b1dd23dd34d0dbd192b35eb9622a00eacdcd10807f745ab2511a85d90af374e4cdaf4641423ea8624525edf7be5dae947c37897f2b93860cae718e7c6647837a0ea3d65b4601bb9293b965cbb365aba92a9e19a6ed0c11cb89634a8c396be098ea700ac94983ca8f3447ebb09cb4e97e6108c40df2e8af7929e7be16f6d52de9b0aa2a58d1437d4272dd82aca71e5c6a492d6b06ce64a7010445d7cf4863189ae52f63770052ba43dfce85fe56e403451f419b7f9d65f9cb5a4887363e2ce675b6494580cb0686cfec00824a9739b0c93c9f016c66b951ef24c247ed67668630ecdc4522f966e79bd488af9521b5cf9f25a85bc42bae83064b6aefdd6f55799ffa26043ece0fa7404282ca1c3dcd74364569590502db39facae19c63c37c14a6c5d38dab77f3be0da7b4b15ee14d1b5427316560f033579d4a20057bd7c7ec2d95d12ff6cbb4e56ee279bc63c0285c901d43aefea2361abebd79fa217f5fa93f15392f177d212f4bf5ced44e9962d1ea3d388e17be985c10bc94a95d037124b4af950ee19f089706bb27f826fb6a8a1822e7064ef559a79557ea5e70ee23099918b19f9bc8e4cf49aa2c300ad9bbbb563410c4f4afc496547a116d8f474717c1522962f817c8a6d9ca325a53eb607b842a529a0919da0505819bc7bf5ee2a6a184029d3615c8f894022c1ced58bc19c2dbabba0a8934e1fcf019d97a503908565864476e86ef840d6556c4af01a11254addbefe2e3aead9c0b54e0ce6c0e96fee745ce93ee38cf6bba55c67554d7352eab2404eb102611d05ff3d98686aac5c0159b10413e8a9b145a78838d15337680e372e0b3ca4cf2ddbe5eab9fd3897df3364d77343a78c4e68cb103361ec3f4657728f7ea643634d57726057511d15d3f3c7320b8de93b112d8b1c90e1eac1b309f90c9863e5d9cc64c0b67f78883023959cac573235dc5c1e6df9df816904e8d0a1dbbcdc8240021bafc1d5af5a21e3bd2cb4762171ad2773bebe0f093dbd1872138308bf9dca2272ac11b1dc1373ffc5bb6f5923b0f088fbe5d7b8b7522f6941d40218d826eff412692264753b4a2ea2867c2f011bb736595593a0a977fbbc7108970fb1d30a7fc2ab7050d741d8788d80e3667a690fceb4d4735c6e605cf92436042d795499274ab3303818122b223e88331f2750314d3fd1fa870122f44315123edde91ea17a60a5fdf1210e3bd66063a111245a36f47a252953b5c0a6dc32cc7dc0e9a8bc11774b28cbb0c5670bc330ff3f0902300283841c2b393e9f0ffd1ff343ae5104eb074079040610a0661179734da42da3ffeaa62998b4a435d1f5c4597625348257a62147b04771e44ff4252c51e2b4c3b7ccd8b857fb5e09b152cfa4d33ca3e84f0b8544a7729f6b50e94447157ba5c7a915be8e21f26e44a39f526defcd4179c85a09841a3c69a8891594cc99b09ae0f3ba10927d0d8624fbd48c7073c611230450218195cefc8cc2675971e8a946af8556bd5d987bd5d2df3a5bf2ef6569e62c9e5e860128af1e6cd37d71a535f44b659182fbc8da3493af9c334172692ad900c602afc23787076170e663ea329fcdfe7bff5983a0d79cc5e652f152b55470561ecda27f45b132e5ca91f071b71677bd3d44a93ad35030dae02c97db7323401318b864a26367b37d350c092220af060c87bb11d5a3551e1d9671ccdd0e9db3128fe62f6f0abda173316e68da1c66ada5b599ae45c857980f39a7d888965cc87bce7b5cba6daa3ff664e0ec15c14d20ff453a8e1412d6bb4d725856314e2222a6df55527c2671331268370d40e41da91bc7dad59148a7fbb2bb5849bd4d5e2a88ed58971dd0dfaae0d520a0ca5d42c619ea74ccb470ccd4a7465cedb27f4d2bfb244125ae4ad5592927d82326c89ae0348a7fcac393e4bd137c2f595a03592d68ab1c80e5136f287efa2eb602e0ea706c37f541e4585a23880d7fd90d5d8db437648897c5fdba9022ea13b73916a9070a8c22f6cec4043ccc1b3fce10f88cf6d71f572a39568452b0454a0e71e6ea345201baccd33d570dfa2fe07fe6f2598cfffd6d23bff47d3ebe59a1301c4f7b951f2ced00c3ac8328aa15759b81d16e9e0d6231bd1397fcf9d124c415cba6c77a01ae4ada0ef7637d8a4032719b7c18ecbbe65bfcff585768c452a1580facb670b175c54004bdd19392640eb23129d9c620419eafd7c41e801cc9a3d510848290983c31307b0eea1c4a52046c8a423bf1b724b921a58d95500772aa7a15302e09c7937876fd92dcf5f234b6e18c2057b42f5b74e138e7f588e58ac508d72769fa1cf9ca99a5d2ddc419d1c6e4cafbbf6f9d5d66eee9a2e973f5afcf93bf9acfec0112262a643aef104227f048fa2bff4912de26a23fb3bf7b70756a5f62953b5395b12540deb8ec30d40de29f3416462bb79695f9f7985197f3450c2afb70811cb6544bb21b8536e4c7b30705f1339c983d78a7eb413d2bbf9ba6af445d179ddbc673a5c71f0b1d1f8def0b2aac800f0940e326c9f2f04e9ccaa385100c7ab61e4b3fa3e2526fe23a2c1e6d50ecf62975c2e4d809fc8ac230f4ee8ec51247dd2da5fdb63b05969a8ede647f319d392c4dbb51f72a63a892e9b01e81579014ba206b2aeda822f0ad61c1f6ac29cde124a405416c0c0837e86e55ba6f1a455b8fb06ac94ff77ce9d65be59da5892ca7ff9974a7b05d7d9d523de63a04dd24624a6a0e0240460805212292b294f964df882c2d755f2de6abb946b4bed1e449da0e5bfb0e123ca2ebfbadb6481f268aa9046591ab291c49948620326b2fd788b4ec24060453856e66d050c62e8ca1d5e781e2ba2b2c450a97901517ac54b32200eced7c55cc15395dabe2aecee20f8ea2a5ad64bd16f8c7433d604bbc79bab5100a01f494c30f68752edd8a6919b4d01c3e3504349a8a1986d31ee2cf1741d1a3ea39a2fc582f74e29686e0c8d94004be2623ecd9374dbb894b76a06967cf6ce283dfa91e11407fce28d10b83cd3f2768c335c9a2a69fcf238c83e1c1e664fc8ed6ef1e0ab03870d456d1e01f05b9e14e46df9ff97d3a2b6e69b6db6bc4efd559e7eb55c2073d31ed69bf2b960dff8be82fc1185ddcc09a5da823682fac1044618d065b75e64aed289de86893b3471e52d83afdc5807ccc2ad9c9d37e3d28a9b5fbf7485908270851187c7ea8da0f063cf4357b82b1811325614c78fd6f14c0bdba802fd45cb43a13f38edec1dd552c00b726dd765fbc90a1dc0674f3d37c44c2d3f1552230314d070f2d704935711fe8401006502b7abb636f90a83ca709b1b6dd09a2c74d1587fff68cbf240ea673a7e3afae4f96e2830c76bb16c39ab1cd9f1d8cb3df7d73eba2458e3f89c597ca78e2ffacfe363d750045092e4b55caaf3100f36f538e04d752f27da7fe28239e5a3cbedbc4dde6c5fb82eb60fc3d4b3b21e9f8af774a5b73337ce176bc17862328d13288be27fed49df7f6a8cc8a933fa63c4f697b5572450e39e2dca0cb4081426164ecd1b1e4207906c8d862d5144813d85ad0ca44bb4ae09488197126d2864c39ce710d4cf8ae0dc77c0d77b1bc93ea5a5b06c19ff736422d9789c7bf3acd3ff84962b17991f9a74bafbba0845e72cefdfe26c6a0c7395c162525f43b8dbaf384616e1753d735c2e50203a98e0a502465c306a4050e6e8f94fb5f2beaf02c33942506ed93ee486d697ce12f06b20a6f65a129dfad068467bff0ee1a8e143e7a820501cf6686ec210d9e8dd74831161cb1ac6ee1fa6df06dc244e75f037966169b6a14b77e166620a6fd5ab5cc6f513eddb1e5e38fbb8a0b97859b29ec3d6eb88fdefe325c6f0c875d2c40439ed8c06ee32d45dac112474ff5f62deedf7e33a299a650cf53b835a4fde8844fbfcfe8c538e25a4cb213352d568c904037092b393e8a97265077cfb937341c5664d38e6cc4776febaa53c16560b48b3710e4e8ee99eecd97bcaf074bce4bf63091702e135378363b28b4bd9a69a8cad68294a8302942acd433e9b4cfe1df2bdeacb8fc429138ad6b76f50a17909dd034d28041904d7e45be663d09913bf6b88552d2a44fc847d275d49b25ddcce1cf267bb7c5e00f9addeddf57c74f040fb92bb78878354858eef9edce2f6ee3d2ff60bfd7089947f1b26e17479ca0fb5f0fd199448ec8d31ed83fe309e6e0520bdf90397a4c7761811d5175b9f9faebe0981db035f334e1d8c38ac1adde89316e5e14bce0ffde0f6aa1707dcfe57457ef112a925f9ea8fe77779eeceb26072126382f2b174199faa0e80930e359428929a0f5704e27fa060a1f45acd9f2b50660db7270a9b9752058b5e97580bd1a0d9af2de60d196a296a84b237e6ad93d26f1eac01d16fdd2a57b3dcebfb2fc1d8d884b064f303800326278cb888de7ece0e871d8b22c50344b648513f5bf381b04c2a2b3bb4543f78ad571dc85987cf38ef410f4550487d7842c1157b94d7ffd4841639a371dff84063ad5f554d2699b28e3836b8269e91feb32fded5682360d7f9334a986d7bd20d6a10c183a59f547755dd60a79a755bd5521d3339bc126ef5f62c2004e666d99c1c211fcee909db36754223ffe47571d137531034a0e1ff0cd71b1f3ae7a37f6d1116cc921bd7cb85e9d917989854e726e0e21c376a3a6ead188f223b53ae5854e9ab52e9f221017617cc68c55010a4a205441827a042218e4c92ff7ff90554ef798e84953e0ba29cd77d3713bb6a9e3b229e42091a64bd3e7b0fb2669614e4f9dfafd589e7f6701f8b1575e44ec68e8a8385726886748bb1ed05cf20e794496bcb348855265af6ae9f2a7ab63f23393dc09111481a1dced044722b40165d8dd608f5036d7886ccfb5d3fce8f9ed69c64ea2d8ab68f154d645b916a359916d3fad10fc1f4b5897bd6dab3c146931d6728abe86f9edf98b66299d9cb78f53cc6e5ad41a10570abc6308097f092afacf2dd94c7388a7dd72e80e72490b2f88dc78e7c2f7ef800c9ab97272c1d946b008e0da82ea4cd5472eb8503b99504598574d4fb104a79f42d4fd4c6a2aca3625677ac4ee59fda686e5f96df42c086bb349cea2a982ab6f11e78a0c7624f5c1cd71ef2822e63b18a8ab499d1c450f32285ef587e219c1ba9cd73743fdc3f5d8199864363363b7ce0f55e3ed61aeb84e969b5b23c278411ebe9584b917496ca1f6dd7afda09de5ae135c1a08de544f0449a55d9361f86f66957625f259969169e5832492597190a11a72acdd1bc1f8b72115db0f589ad5625dd4e92edb2f3bd58237fdd83c9cbde9ae4bf852d374c00b29cb83684e09e8419f2f66b602d717d25099ca4f125da47e7ce750950dbcfd8d602f8ef4e31db1791601635b2f41969e33ae695547bfd2cdd070588f545ef3e1eff6fc2be2bad19b8789f19158e7ee6943faf057e191790148b156177ac0808ab520ea918672917b6d2274b6991c6ffe42dbf5544a61e073008da97535ee1e08510958871c14e2190155ab82c6040cda74a06c740f1a7ae65e28509534253bcba418427dd6daf9e2616b68b6bfa4451da275779c93b0385d254d794e334363cc894486b4eed5fb5bb9be753c0ef83bc28aa17ba0e93c81bb791404ee11aa172862167a316e00bccc913449c22539dc5c6b7364ba600f5b38854e7472fd451d60bf4bcd3cac6c93e13a90be3a0fc1bd5ba1608a65fb4fffd777b4b07bfe89fb4107bcf9ec0d09665f47a8d5cca1254a80a5456d0d6fd27cff634a98c9b6ebc6ed1cf910975d7a6146da56452191beca2580c0482dab32d4d7aa92f88db188a9d24b12118cb50c00ba06f155dd11ed13cdb54c2c3f83431258b171918c3313d8811a3f0e3dba34b87444de7c2f5db52e1616bb54e32e7ae74968ee17f33cd3438a9de5b18574ae82137155f011c2bcc781f3994a12976eb23a8bcda18749b10d5e54214dff1b5ef9a44c0f1528fe9c93f5b23682c90de91fb0abd8cb4493dc84f718bf12dde2a26153d7b24e7f0d0ef5b73fc7e57412ab0f6b1ffd74260229e84e178f5915bad4be887dd54005a9bba98d1d40aee6fe843ff96d14afb58805fcaffb66cd92c46a7a17deafbeabcbc1aaf3b6f02a9e1f59ee7853be2c4b4d9289f352abcd3a86dfc1f43cb337184a88b8ef66989853e68b22fe9026fbdb5f971332ac3cb6b8a423a769ba917741a02d291d9bcedcd576945136640ef1aa2723973a75e897b1623e776da2ca9b55f4080bb0e27a9f9e9390e38b41b0b5f3b64cbc19c67bbe84ce94697d37a8341029c256b12d4655103f7414ce68038f2b63b5d82e87d5a873339ba6a1ee1541fd21c033a6d2209233c5ffd906de7475d6564deae14a28e9841fe01b6f53c45c1e9001702e47b27ee12b7fa61aafd7f740d81f39185f8952f896e8bc7d84103cce821d6524b036563fb6cb38bc5103195117706f28b209a7bfea0b316ce221c043388b554807381ae99cd60f8db2b11a268eea0ab8139ccfbe122d0973bdccd990677e9e813ab81aa4208bb6852e5caa9396b6ffe691579ce6fd3179908864133bda223b0b2525e07fdd9a5a0a18e77e57176ab83186a668fb82c7d590edcd29b8503ac1357ee401c4e105ff0a100dee9dfe452bb56c4e1480fe10fb3b92e7663c23af53c98777da20ca5020732dbe8975adb29e05aa2dc87e98e0a7b41a9fb499aaf51f953a0433735f2f2eb1b4766e0c23d76e9f2d3ed9b3c61fa017eef72c941af72d053c0ac0f592a4995b20062b7cc71b08aa5ce1b901175a1bac54245c411a24eba26d2e4da3bc2990fa8116b2be46b120c0104092d57de5bc004282e59fca7238622ba17b36c6f8606232c58580a6ba656293f85a359aa2d6f99a07bfd85e2a21039741b2378f2e8f2c74eac6d9d303ea1a733e371b89ce4fb287f93672e2410ac92aaefdf4d63d5cfe0b9d7dbed97b2cea1bdb26a0418d639c1089de163a41b627c0a8864d6eac3fec79f1c898845ee4bbabfff6e660fdbf75bc4bae46b936331cc7e413f49f6cf57ff7be50c0517982263a645e12f739f5f36790bc7579e190edd31f022450795ec8bbb72fa68bdeb70dc8ed1bd15af697bd3d1abd8f251ea46e18f01001ccb95eda946af11455cbfb7c299253617f506785adb059e54918f57d15b18f663ac0e600b4a9c9d575df85612f2e576ac840ddb444f6e0c83c5f86adf977475cce67f382bf252398fe03fb88eaea4927c935796fb4899f2632ad6243f4b25e763297458ef4989d2cb507d75f5752152df68d809b3a05c58cb46d4523b742bfaa6491b5f92d4ff11f9fec4b430a19153a35864c7d8bdd61609746dd2bfdb7240d3ae4c96ee5a487a978f36a7ef4f6f2cb2abbfb211af27f73578e138500997fcc762eedc2f17e62728b5ac9c4fee168b00735b73a9baab000a6a437d0c0fd17ae8ded5ddf3676c57a305f45a2cc7171264884b39e6863e3c223771878c21ac484c960057b580ac3e47e3bb1b1ad1b4c934a6941ac361bc0ec68c147b1a2749a17b395490d293ecfefed04f0499a0bd0a75915338012677a0f2505f396d89045941b12316ebc01a8a9e0faaddff17f988a13a94125bbad7a8040fa90b9c14d7cfd6b36f7e311a36a11a6c2ce758a2c56e3fd93fe8e8b07316381257fff40acee8e759b21c4975aca5337adaaf08bd225a7b7b0101436fbe2eda05564caff6ceba78cb5b976950549de250cbd75007445676e04979d3db626f50d69717d9e53fd16b925743525c388053fa7e50492e26e309d5d3ed2ae5f18bbf21d70a4cce2f643810e2476cee26cb6892dc69f957c2cbf1e3b496705ce14e25a3d701df555150af3e10e9fba651dcba27fb2820b275737d7c1d21c853d4ce45454e258bcc8e965fa6865433f72d9e74e6392d6d7f116edf145bb5b68829a4dcb009ba0d95593aff89b1c74c55ca5f378a97b42b8e0bbaf4ef21451b73127ffe91bd238d7069631231dbf36d899d685b021b2302045c14dbf1a746c6d8e14b9ad05b5ba18fd1438cc626c4b1ec835e710026f8bafa51f4e7ffb0098916c29ce5d4660a73ea29f6173a5c5229e20aded7478da687e0921b3057d0c8dfef62fb75826a2ea943bf368b0eeee6f88a8667c35dab2674c5bf033d1cbc1728aa82b9c228e2602473d22e51f955cfdff9d48778d91086c803c6169a7f31a52c2c4ec6209dcd332d20f7c2e871adc302210e44422c96cb8d812a512595939e54fb53893377f3f17196cfa084ed4d90f89dfea175d377a1b9316489c0cd4259802299a50aa166812dce88e7e4d859c94a46c274246517a7fc27ec908ba764883160b84ec0b77008f89bdcd15af2df6dc8fd29a630a027b19fa65ccbe5d59031684dbbc01ac68d10e38817e924031d718187777c8c3623b4a9d93d3ca8bb57f1c5c9d6c1f6ca7349754bfc98305a847a11dc8036a96137820b6f849ff8b392f47faf7b65513acf45d3ef17378ec1a5dc7cc649fd0df5a5e0fa1184addc3ce80ffbe0a91c7232c199ce1219aeaff119994ffb059358144c4404837b5cd4c5e4c3c2f51faa30fabbc33c92bcc9d158c0bee29ae59d6303f586a42806558a1e512e785482f71ee50d2a69e9004fdb5c52a05882383be7bc4e2bbb6a4b7cfe1790a6dd38be15ace9a35fc9f271bfd8999af4e032c4ba1b1033c504e224eab3dc56cc40a6d4820c5c6f505c52ffb982bea23666d40a311773eea8cade825880217d1febce5cd2fb6e68db912256a64bad4ebabfa1238463af02a708cf92d0de18292dc89952a8d8e7e1970b671261fa6a2e14768d6082096008e8f4c67f0ca920da2dacc86bd977f5cc07bc0813257e65670407bc3ac075070561dc1187002c97f4ffcffbae4e3776064fb61a7cbf252b122fd0e730e0f0004e6c302a536ee8bc290c831a53c453264d769387356c4c5d0abcee0cdb846ab813e78fdb8b4e06c7a514928876b5724f86e3eb99d0f3d4bf38c9d75913cbb930e21fcdfc73f82e3c017996860d03bbbbb1d6401c2b9ae95010991275071445e5e2af90e1427d4f809b08aeb92a42f78102af5c3dd354870c77fa0b3d1ea6de30efb243b8e8996da82045c6cf6ae8f83f4dd6902f9c7503c2014e7136779fb85d6eb5198eee166e8d7d700acebea4cae6951a23d6dbf57ac31522a88c21d175b41d8e4aaabe37269d45904c025089c902095cbab3b6fb4678e395e3517185941046fc901f6be12ea93a34e06f8284038f4df061b9bc9b52739be22bc79c0bd8fcbfa1394512b008d97afc68f04cc586e7d1ad0c8e7195a7c20fb88ee2899d9115764d603e614ddd35c0a31058d0387002d73ce568a7a6a610a5ebe9baccd5b3b8cd4390f1a9fe69ee0604cbd071b7044eaf6f0ffd8fcbf76ef28f9f5202fd71c2907caea9b988f228ddf2b321b81003e22e3ff50247f97f5772acf07f5fcc261d5c2901715a1f7d113dd8eb13205fb079f3734364ac8aaf6b1940af3f4365a44d5978685bb2210ec4c65059bb1d057dd0320a0f57d9182825bc6fe305d6b5cc7e92018e1425647f92e0d9c1c1d86d6fb760eeca49dff6b67909a8f80cad30dd173a7d7193cb7745ef4e46f13dca3f98c221606ea271f5c1cf8be098c300de8720fa0d18ec4dd288a5aeffefd37c5310c49dfbf03fe6ae4d893b393b11654d9f7ba979d45c1255a4c3c35fe09e5f8e149c31d082b06ffa6b7dff39653ed7349f8247068d3d9048b5349ee8808e0ca37ea4183c765ba81be42fea4ea802c7b842c06867db8d9ea007b90f313895460b629b2602a1f9e52efd727b7568ab65201184d818ed45741f15a46dd14fea234c87380269a529d0e3efc14ec479f810214cf966666a5390fb9e9d4aeff6043aa72bd4c1672a9a3d31dd6f55e395e5e2ce0dbf7ead5040723b97683f5b61f3c0955191fcbef2c068ab0691ff5551f299a6e00344ce835686f6cb8cb9e1cfa3ebd5aafe2e48d3b8d3d00220e22f6d1e1a4c33c5d56f95e379c2afd2ffa860c9124676527fa090f6455401c37dac61bee1f5f5e051accabb8890712873f6c4360f6dc3732131b90c28f0d0f75508127c356347e0a2d8d7d0887b7fe7c35e4b10ef0142dfd40d3a8e52b96e5d8dc53096ac8eb325abed71597138d8310d1c722b007adfdb2f2d2741b474d15650436df847c65f1d2ef311d86cd01994c3482f01a836e93c197cfb40bb42466d1c1b7249994753b82efa14c9077d3a004334801f81ec7b00a2eb61b31642c77e8f81fb05ee402011a4c3f052814f022d5171314e01f16449f79ce255d700f5fa8f0138f29f1e630c58aa20075f4e305782b2286015575858216c2cafc48299fd68f5ff77f728ce3475dad645e5c321a366857e3653ac01ea5f57df3c12f39e826b80c630e9839c733f728ca578fb1b71080eee62152bd231676273e43cfa685ee29709e4738f1a39ab48028af723a2c945b6b276d3c7de4d717f0852030957027ac13b749ce60176904b68b227c2003647c53fff1360a96859656d309dd0f44f136fc1d11aa5c739d3e910eb5d559cf999ce189818bfec6ffcf061a9e5b3e8fbdcddc283b236d82f0db697a131c6a5f65d6a101217c5d6361b69b273d6e372079201e4927b9889c267faf56c17c2a73187e50879c3dc5b56bbebb0fb9641ac8c61a18c87254fecc646fe71dfe71ae7558344d63361af1479f9e0a415746628013f817426e8047a0ed32386146842405d4831504031d40641506a043ea0aa47148fcfc0bce4365660f18c0f83619865a5dcb16cec597d5d54daf5117f2717397bf0b1a681c9a1eff638f0c78d6c1f9606dcd2418c7a8846bc60e9927371da9e1dd9645a58e3e7b54f12f81421180b63c6899afb3e07f8ac3c66b88fceb7f87d094a705956b76b37ed17fcb49ff4e7d4e39d8cdbae375bedb7cb2d3b0fcb19a2ae1b5dadaebf402ca0993a0608a27c5ab46ab2e8d5ad2d13aeed97887f2d19b4c5a36c6763a1e9c667abcd08d81d87b259985f7609d6430a633acb0e4c72821365e230b327165bfc639cf38b775dfba52045cbf085d8a51b93eeed71920fc21723682c1999eb338ffbdb046f3b8c74681bc408f12f9b9931fde809b8501b10884555714ff79ca594017794c0d7906db5c6132f9f4ced5be6797f7f75a0dd6539960eb04039704184140428e951c9f0f42d8eeaf5f36f3e0bdffd88b8d07d69ee79f29ca20690036b7d026e450505ff43b0b1c9005d839cf811c938649fb815dee7bb7eb6c4ce93bdb5f81416e1f906458a967d2699e0577fe635ca968857f8da45bd0319bc05841e5cf97fa572c76fe679baf4a0eaf81d395d8512f9eab3a159a66d19bfac615038e99771d37d45cb8f69407f607f5c10819544860a5335d83f0e2e7aee20dafdd253acf8e68a5124f2faffa312f2a1bdc71dae84ca5c5b384083d7ff7aff359640fa70b69235255989f9b90f6277bd3ff19cc4bd301e49a589cf918aae11dac83d4fbcea4152d66e07e2eae430fa6bb5b984c36995dc4882c4467d6145bb02c5ad412d7083e9d59fafa0c9b20887a9a9ff3e9ad9f49f3b59ecf4f8d30f06a20a87253773244cc63f764fb26e6c9de63be709ffa0df3023013ab6b2f861f28c7c3743a71e08aa65273cdda1d608e03cd0df2922be83e9b57df3ca90182f654f2c401c0353dc02b31a2b7c8b8e001a355d9f7095e0d32967b26e46c6013e037e115c6174dc8fec8f6a20dfcb062114e032f856fbad4d3fe9d30613ca7d0dfc589f29789aa3c163afa75768477127af3124f10e271aded1b23656ba6dd3401913f94ce13142edc4b51d7a5ee9154ec268f24158d626f38b3fcb396c0d37eaa585c8c31537ff9b27a01871aea7e137e8a5559e84fe909c5ac5c76035800458ecf1edc2274ccf008b3d4ca045e552559658d20cb4d80d98fad248d87e6a903e85124b5925aaa457a37880a93ae68882d72ecf8814ae312b389ec8627d7347d5fe2284314fe4892bbf60afe7deb860d4844f896ca2596f9b8fa3ec9b56f160d7c32b395ff37d12692093043de0780f3239c5354766936d14d4e14a30e6741254f4d48c4f5ffaab31106c6fa6631712bbef1eae11d605c709dc07993c425a75946fabc6e1756b1153f59ed9cf7e74b1df2f0e404cd5b1e5bb11720ec9289cd7c4ddb857923d53c68ad470fc6894d3813de322111a9d8f976a3a3d51e04ea55dd41e260e27943415853e484abdbca82fe8cf67f4c6cd0342753231aba7f6d652d4a54403d09014a9d8874c4fbab1844f5267c180768e8fa556a98c193afb3a9aed1b6db535b42e1442f412e9356ed16b33d65f80775894f4e1bcf79127322e739913a8a0364a1596dc812bac98a5fd4edc1619f085520e57a0e0759f209638945df6131f1b5c8bac16ffec1f45dc3892fa403215c2bd98dbd482d96a41efc7fac6121ec317c42e7a9378adeebabbcc9efffac6d18a5f4d0a2f8cd842820f0aa1b1b20f7d79b0fd4b7f620d237544c7199c889674423f9a4379983794a5e22fee4a501fb137bddd6529ceb2d44a69290cea099e0d3d1ff21d958d0cc5e9fdc7d3a1bc37614f290336a56a6a86bac97aef920f8d96dbca53f4e8488907c5d99d52f222127a6a614fafc2f0adc9824cdf77e10d8fa7ca10501ae25940c014127d760511048fc326f41c00d8c5908018103b78025080ab239534200705dae020420a8422b03008e4c38980381c8f39d0a00d8bbf30a04a2d79d536720e8bf68b496c9557e774b5ee0593a7d30f176df73b2ba5213e4f47267cf3b85d7c1d278b9f86b2a4152df6d7049cfcff892a0a86882facfa8a7eb3a5cc5b3cd10e89e88a1e058b10e708d5178d0eb8cbd029852c867646f1444f3fff6268b7c44c8886acdc3e0409f5345d9b85c01b0eda51d9f3f2d212a7ff352012fb88e9c35d3524737af5cec455efbdc78c5e8376438786b3de7a69d6f4dcbadb48fecdbd818cfd26efe134c264584f645daecebc228a402de1fffe2408fc22ca351fd2a02681259b1bd8705f91cb718795a4983d2e9bfbfb2fc59bba746e3793a689e88c47f1a5736e1143275f164d7d86c4b8b9b378725267f135e940de2f435e3e2e4e1e66067b764e560e7646367e7e334e330e7e034b3e2b1b2b4e0e4e4e530e3e3b5b4b6e231d1d3fc3d5da4035e1c7112e5035641b953cb8ac5a781a27cb91b9fba3b71067026a17e40a09f55aa22795eb81fc58f3f6f846dbda1162b327e461e5b28ea9cdaff7eba627a1237425577746199ebf7fbd3c63cbe2617351fcb9c41afb13b90ffab881a2513283255bca99d45f38ddf6bf6198c9eea90a5047501c81053f7040ebf1219fccb56a04372407e3b6ac60d54fd30b71bbaa9e3119d172e672e95b81fe271a7e1ebcd5fb16993ec1db634937002408a86c842509c2b4f203b91145f59a6a676eee5c16debb247ccfa9c58f054fca8fbe14089566786a58fbedc02c51f1baf1107a687aad9048e8d07b46ab78971aa2c198b17a17e4a9848cfd94cc4dbff49acc7724fee3555c2050f8a3f395a42ec075ac5c31e3a682f6557856491b22e8f8cc8dabfb85db77412df7c7e5dfa69502d2fda7ccf9f5ac7f33b287424ce059c0ec5f62360e3350a413f27ed0d4d90e2e693a5e2e07d13ec132df87b776716bbd126db42a33754079ce9b9d800feb483f0d0ccc699385d87e09849c4a5ea951cc3df2b79eb451bfaadec21b2d2527a782dfb744f78ec3b3ffab58b75257cad39c3e19a8ac37dfb22db12dec1081124e458c9f1b199b5a6424488c62308dae77319430de3aade58374dc81ec644377bd2b8b390d55a0bc4d958505c485184f11b1ebf69cc777d48dd0da970ad1a7dfe5d8189104e8e957a269de61989f98a8e7e1bcf2ee5cb61c08cbb46478d08bd8a0c7bfbb942e595907e29229193ef5ce6e9e3c78eaab8c05e1ab812493db7e7f1e36b2b6ea2d7855f567f5438314201151258e9cccf58bbadee2a7f6b06f1eef05f4a280c4a07776b8121868a2c98e1213c078ef18e51f325ec2394c0b8a154bed7d588fcccd22f8abc62a92c556679b89041206611230ccef4ccdb2eba4e57a228a04f6e13d2ebe6fe85d14c378ca43d0ca7c4f0fa55ec93c2488ae4a1c1dbe1987e1d229b02f1c9c4d3b252f93d014ae831c967efd14bfc4f9cbc1a442c7f641d2c36ad6ea84f74bf3dfbbb31dc5512f4d3e1cec7ee938b3abd1e9f7ebe3ec21b9d2bd685f1b41136f35d1b2da5a456f8dadccd1c4ca55d66fb4aa075a4a1830ceda621885c70990e82c3e2dcb3e92c2ef3b0a5026573e6d4b12e3b235f43e1d5a060b9671e6af44e66fc1e46e442a6df2039942c78f5b0ede083d3aac006cebff61e7246160832577c84f9442e6a4c4ed72ce4aa60fb3baa42adaca2dfeedceb0cb79fae1fa2dd34059197b465a655638967b677df7fd0c6d89db2282e802148d0a34fcefccf19d775befb6efbe7dc8e2ca9eea857f6aace666b1b2765b9fe2caa9ff7923980ebc748e8feb2a6ef8ca82ad28c3be67178771c6dcd8c9952741ef05d364a79866e1bd3c1af6805833bfa899ff863b56384bc1f0de1895ac597c73430775ff2875b3fb5a1ed4fe4b5e334b12d8eebdc88beefe98dec79581d7f3f52a780907f1eec25b395790274c90c8d1ae9189d0fce3486a928eb8955163334844e20dce30bcbdf232c1e403b2a24dc9a9f4c58d0d944c27a94d6780e747b6b9e9a50d28c896ec3119585b0790641442297ac115ca8ae87489e5117d8d4c3e7139b1915d5a178e3c1a3620ef825137622120efd8955348c69a427edfa9c86e43f69e8fc474c00edc2e7021944b9b6c190188477682e00a3d8a004e2da31509fd55c9876a2f7b877148c4a05806aef34fbd38a9762d1046461f4f700f34558dbc197bcc6ea832b336ae28d07c2b8b5cb8013cc33ca5d02df26241b298cbf8b3d6c872d4fbb18aab1d344aa48e9be29651be3e7bcad2c8d0f5b2a5818611fd990767176c9b4f252517c16d20f1c4f927e070610fd6b40b6657789b0d624dd813c8004701f937c4173fc63ee03929e466df69fe6766a09396d5fc845404df27d1c9656e080b5b24ba73f3f015103a39f42462a3e4d2666dfbb667c7417bd8b5d1794b72ec7af63f73290656797ce180c6208940b8f25ce713d4c03c1c1cb20009779e931d0a9381df374c977354384d90c04dd9f8183f99b14db8163c897a556f403017f8fdc3bae53a9d77c96f2919717ab4e8a9e6f9a4e2d7b5957cb05be20bd926500abcc23306109fd65a75144bb5a6244980515926c348258b7c818a350c05da58ec6fe6520cbaf569b91018ce05ef8cf5f6858765175fa275fd620c85f4be7fcc73085e7ae0b84ed507cf090d6c439d0ad44509171450aef7d89c5328d252e898af8a991915f174554e55f6981497123b105b90f6116b78495571cc9155549a37d82cd4bf233132b9063b6e5a4ce0a6704fba7fd831280aec443151608f4da3ab0b6c1a068b5e3ebd89308d4e4c63130663de84cfea38a09bfb2874fa1d40fc3969be4c65f7c69f7bc4b7cecd2698913430f54f4e7425feabcfbb221ede1f190d46217deb370777d34c7bce03ed244bfaf68a6623d1388bea2b20d67a36b5162d4793147ff05261858bbd8763a58c008c59f90193604e92f990a7e8567c104a39c2da38b07dcf26222d45f84f8c898ea16644d686a1aa6069812a52225eb0fa59d86271baaea8300dc7bf57df3d41bbeb02eab9bad0335cebafa4a5127074226a00356487c160b3e7cb6be90dd1c06ca080887b99ead13c6bd6097262e66e25894e480156e7d4162d56cd9d9a84e4411d20c02abcf8e6fb041923418c40603bbae9af85afe7d856cf0796ad7877aa7f7f8862cc2d492999a9f5b86f9fd6f77ac557a740915c0750dcced69c7c7a1372b55b96a91b73175877046974c35344e0a6b56e940de864fd94750128698391e2ec8611a6206bd6a4c278c6efc98bd685fbe155a6a4bd1296838e91442aab4b98503c960216e30eb8ef32f688246a18183c4364e12840d1c2e201a2dab035e488e406e858b350071b1aed44d5542d30aaf0434f3e9c0afe24b72ce46b47dd1251a5d0765bdc21a60cd4d91d164a14fcd0d81b0528475434819cffaa93f3da87e8b8dc8f9db2d920dc4b5abacb5df6e18b03a32fcc28116e425d8a7758eeb5edab3eb90008e65e5d8eddb2f7549ac38b80883e0ba9002524d8b714858d20f9a120e4ef8aab608eeb80a127741200dea00e55bde293f7ca3f9224d8e81f9ab588516ca7a49820a32a1fbc760aed1954d53a6cf3be01fec9e5775cff1002f8c6d7231a8493f124cb77e61de449cf588a50747cf9bfab04cea027e45bc30b4d9d42d362c5bc381b8e521e9df3469287d063f7a5979fbd0b72193ba7c99ba3621ede5389cea4310d400c4067f54e95647e315df3c53a4e73bd6fa10c97bed768e928f7522feff65d5d3250224d66652ea2f9c33ffb8f113d081f695359b1b7b21f85da59712f02982a6a752d84c048968052a39c95528e99c9d962fa44032f6b2274b38b4ec0a4cade8264348f3d932b5c14c5c71245eeeec30e305500eb8a5267343f3528ba97f6852069c6fce7c39fb3c64ee714e40b0b1c5578cdf7c74269d1d0624430c87acf4f58761ec71a6fd801de923cfecafdb50bc10dac141c6e377abd20cc9c446c785f4fad4da30c41b822b8c054fc4d4070070aea7a05b1efb25455f6b5155ee802d75f6493ee3d08452b1d253346c7689c96b4ac0a9ef0cc0add2b812282d37fbfa4b10d9ba4592ccb32a68709f288904d5eae1b71f14a710c6ad6020cb1293ff8c91a7c8afdf96a63b0e170708588bd9e99b2437540870941aae058ec706b2bbae2eb494dca4854b25571550e2f73f855238d4f9bb098565ad67da0b4856817e84892fbf1ad23ddf173d4a80751de73b3077988a05e2a3c705ed7ed90c12cedb469867a1c770240f7dd1b00d0ed334d43f0d8a6fe391ae52ffec5f1cea4f48a8c1df06e9010be6f39e7b20628800142a15f89c29942b322e8d92b2a02f85a9aa07fe6252935c01dc8f26a5cd972a70fa2da5e7c32d27d4d4f0bf27654b686958492bdc4ab0ac78cc30ff7dd00520117ad0040df9cd8f12315a5d5b1c7ac369493337f71dbed8853d6c8381c03a3229d79f61443410690080e830d0ee5d00a8b52d05cd3d643c07ba096d17b4baaf1c040997b1bb9662e30b8281bc23aa3c738be6f70dd75ce664a57378c2f0ee575ec484108e21030ba8d885dbda014f28a8fb1d17c09bbef0e0fd365d7051d088f9a3658376f92357afa944098d16fc7069c5c7367379587ead14a5457e2801a4e42ade62aab62ac7d2939ed77db45198dd401401dc599281488fa9b6f7f4c6d6715fb0acb38d6272c04eaa11109868d1450ac898a3b2c2fcc4bc87bd5ca6a4608644dcd580b48131c6038377240fb1c0e1bf5fcccb4ef0a670017950e96c9c5fbfdc76d2fc6a3ae8f041376acbdb39f1df6fc1a958931451ee904cd62fdd43656821eff9d2c18fa5ebce2c5a91e34cfcf6760a1de074dffbb017dc163343754323440e3ac99efc95e3a47a85faa082e5ced1c13f77868848af714bdb2bccd244f77583782a32e1e72c3400311d2d110876cc7888c1b5eaf2b90cd3feb7180c8f207c31ead502d1d2b39dd4d64a3e0a75fef4eaacbe014e68c0b9c14d7dad54f3e39e9d9eacea35e529ef37b38170358b45fcff98c81a94f4a550489011783ffea93b5ea52091d90d287164f6765a28916c1eb1b3dba5a2df7030e9d75aa417b6ef840100c37f8d246534c8f0a0ce2a79f2e020543ab090f7d20a41116a6c5246b4d4589bf50f565a1e0344b936357c9cd569c5165c9a658129d851bba2a271315f77a98339c1b0742267a50a75204eba5213116d4702697a36079b9f7b8747b95b84e27976fd5466698cf5b40796a11344902067801be2f438d4ff7ef8ca358e38b18cfbc88b1b5b0f5b567b45a36a449b099baf86b98592824b985f17d0ba9f0a47fe776ed286e83ac172c5318f3bbb3263ddd90f060c36c11fcca99f82d42a0817ae47968f84f2c6da99c42fce523a94f239f08671802ed8c01eb17b21ae19c1ab53c917518c83f05f9afa6a71068e3f05089372a6ec1dc86100ba3a3c8d4b7134b5f937884cd3b277afb67f70b76d749e757411805d4bbcedfc1d0da25200a8be42007ccdbf3e352ab24fec47e61b2e5f3adc1b95024a7c50affa4aaa1aa57e40fa779d820bb09373e417760ca48905a435a966e6fcf200d36af633cf1680fa88a9e3aa20c21ec69042c6e00afd9abafc803e6625214bf5f718969a423bc4e8702f8b9be5fe9dad7ee38ac1e1cd8256d9ad55e420f2479248e8451525a922e7e0fbf3c335631eca5cf1e9b1f6902550f04c420f3e4bbe1114bdd216de0cfaecea98699dfbb29e7af1be1d87af86158108a07b5035878f505c11fc72551f76fd8866eab5e53b425fc072600c94367e5a8d0fe03e39fc456e2feff84bb61bc7ab33df2c5c766d9f7056c06a6156726a1d9e78786116daff97d961106cbc468df8ccff1cd5693c4d5082f617156e599881cb60adee50c3f4b8725e5de63a5626ce787ce2e267e5b70e7aed1bbc17b005c154a3983d0f36118d01de42294d3cd8315b4b0d1e3e6f4ee8dde76962f062d7d6ea51e2c2c83c64e5eea9e1fdd94a50639d312118a1826e125672b8160938eaa42dbfa4c7e9a9d99d5b4857feb2c88c3e16741f3498064d3ed7152cf165c9bda27d9ab7d98a29d11773a70db243b97187d9c6bb19ac44924e6fb93061a59e4955aec6da6398ccd960a0607e6c687ccd1a129e270024e257c64e355402be87272bf0e8a5309fd7e04e6654e2af521f455ed016d4b535bbf1795cc73c5b72be1b5a63654d5e0d2a963ffabde1c368ae64213964e35538d8dd81059f591ca6eab9952479964ce6ad8890ca5085e2c618fa6579371b3fb72191d8d1bf872b54b5d697f79ef0a25059abfc2744bb690e491dd17175e7c8cc5a632ec8770ffe7f27d7d010afa5c341e69f0fa77052f43f48a64bd9171e122615e96b7ca0468abd6d2d1f750425a82d0e01ec74d6e8fa357882fe24d084d78fd03f8b843a93b2312feed8d089253cfd4e3b908c890d094a478b57d70da0b9406e3e78b647d9e7e3f1d839edbdd13265c919982515ebec8bc702771486c99fe66b959cca6ea81132d2575524a20f32d0ed9be3e0908471d96cfea5c59f54482a2afcb6697f138d674604ac889d1a8bc07dcb9a7f148c825b109ae0d24be7033dd5d54c6df68aa4e8a4bcd002e59e05cc21ac0ceb1919b399ee22a20824f703c9cceeb07513fbcc254efb204cd3a2c8d2a3ae42efd4ddd29f43daaac8f05d250f7218035986af1066d674a508cb478e31da742febd19eeb7e39f29839e651d6e49998a3d6b58f5f31bab5c0897fc4ce41f0a74274052be44d28b4bfc259abcf69c406dc39a459bb2923a13b2632bface5f5039a682ede10967a0af707be49f15d1a90a67a4c1ad693403fb5c767c254dc06440adc2caa97fc6d7cf8815442c029883b3d97676182398c7ad81f5e9a6211ccf30bb701eda6dcf18d4dda2fc69d0a46a2f0562eb7328dc9beabc65e15f3931a8232d15934497678bbf6e8c335ffa7bcf673f9f11e33e23585402ca521d86e9e2fc525199b7565e143db3579d3ef9c2a16dec8a8f618c47b342efec98c7db1486d0c154baf3f1b41f9b3da12590c370c30d82a1b0a57491fbb0cf88e745c7b9ad432cde3db595cc8cb68b06e266837d29afc0c5f71c56d666688515461ba2cbbaa833010627d5ae5408e2ae10043df5a3056b1ec5144914fabeebcdc5a9e2039304035285d3f10b4d5a73d60eba3a82d5beffe4fdee4b522b007ba55ebcc4b3f2de7bf2df77c279a7b7d6d58c0fffb7f6bca1cab97a1422249fbed1355002a475487f79a2dd7fd4df39c1dffd3898b28fcd7ccb51cee32fb91fa4775677a32f94fd204ddee5a343d921842e25deed1b938e1dce6f1b6dd16fe5b375517ad9de165735b59a62d6f644015a786acdb079aea562190883db2239ad7a49314512350c22a67b1ce2b17bc6855fd4a90d5d98f3da5958ea45f7230a70c37cd21fca8b9a895891f06df1883a961cf68237f23df96ba1d87e3be96f2fdb00598d3356557b3f51d76b4070c381d7385804cbc8b0d29aff63c811bd09586da7a49471d20a3908263d4f7c661071000756b98d9bfa6fd6b53737718f92e8c7cbd545cbb995b152ae7ff6fe7d8bf76805601d411f409c2284a53a0114e81e59b31db9fb6bdb6f1a3c00e5b9c07ffce0b65fe2007cc99f27f47a3b95c74018ea6c6720c6c56fef4d0b3ab5543ce8fea85244b70ade1a3bd76da7f96cf8e7b99655b82f7c1aa1f9b24d18d8f8134cce76bda3a2798900c02bf1255bed12fa56e9f7093c64e6e15cd13cafd891828a9915d185d856954e56366f60c8ec0b65a0757e136dfb18b25fab4eae28ae46d349e48ebaec9594575a733e920f176451c9317dcab9f0ac72186ed707193ea942483239094b97214a523a1ff323d0d7eaebe38e50d8cfbc9d3c17e9c150936c238411cbd61dd84150892b8b9ad24056fa0f202ead0a83c903d0aee17e21afe08d50b6cf9fa116ef6e60c403fc97be72b768934736ab8e24fd22690ffe7a75eb56174c15d2f4b51596d956519d16fbaff984b44a4682dcde25d518894a4766607757c3076808f795ea050532243a00379e2b479f2553e544df3b4ebc755d1081e1d33b97b7b20230e78ad45a43bd806196dd4ea65c5e5ec9140600333b0e870855d620b098593f5154fc44142b3a3cbec329ebc68b592b26eb4cfb50786c942c5c59f8a2385238d98c1476208c59e96650f75ce3ea0b251d00f512d199debce4bdd50c2b156add44178132fffe4c8cd1a06b05febacd3f40f0c4672bdf8eee7ec45bf24ec722f4d4b7ff56b6e277231c4f41495b45fc8c345b823aa0e214075ac0b2ccb4e9a683caabeabc8867747879c8140409a8326a5491abc21d41401208358c069f6fcc68a15a2bb53d18ab589e733e47f26745c1020344ef5cfdfdf93b3ba03f3ba634666e0513b6d89bd4ce6d3888589e7fd131e03a80da46e11d907dc7e70540a190090ae35416da74198daf50026f67da10e3d18bdda1da2248f35590b44ffe140a887a782b64e179b883fc466e0422125fe84ce69cbe7381151641edccdbe99a2842d91fc11022c70d638d69b678d893f03442bb2140f7237ac89a49a7dd54e3fb8987b50d2d128530025fc327b9b26c11fb4d3e13cc52398e0bb4738b8ef252c8223895f7eadce99b68017a40e073f902b8474460b4f10f9475b826fc61b8f0f9a4003a6571201dc9f9d0c6404713e0d29e63f3f38fc25e473f54545821df17362bb7db23cb32a94742c9eb55b29839d69c611c0f0f98192efbfd9abe42a2007b01fbf4f2a97877559a70ea4605c35bbbe7c6e21599c677c9c72d1125565f2dd3e369226a5bc3f216d2860c17b2d9a06a9fa3d66cf6270b36a01bd072f54b4de1f7f24b327a2fd479919596bc92be500a9204ee6464e5b3301cc4f8d3e54bb81305527542cb86cc70c68b0fc6adea8015483b4f4428529451a73b9f90a6918e7f3e15e9852ea85acbc3cfff33a1b70f8f85d100dddcce8ee9bdb11615611d1b04b781c57cbdb7e41e9e3bae545bf68a2246cab054f4be3e430c6b1179473c7128d2cb55b9fcfe3181595f41010a3a8702e9bd1793ad354a3612cc5b2464db5002e2b020341cf89ade9f3d58669113ae94abcaef08e2be5a55b4349b86f07c6b4e5ea965081c10b03b2740449f789b3f62e25c3d47e64dfc944533f2641dd89d5d5cf40133021138b716b3914625333650f811a117f5b600f323e2e8cb442e07c0884612add3718833fa6d17cbb8173e3272f2a07f69f16fefcf67330e337d27bdf957efca439e217cd9214c790380d188ac0c3ed696febe91c248b31d8050340d024c96a767ff3ba73da7e14fb1db7a399d758ce6be03bf56b941a5bcef57a1d9afa0d7fffefe709e3fe2a2ef2516e5d1e4a54ecf9ff1a3951d422ff681f79f55a6c7a6bbc94bba050650d1b187d7cb13b3abbde2550b5e68344990203dbb1ef1a2be5d9ddee7a772d90700dea727f4b555b739e7091e6fd19f4317f899a3cabddc9f1de617dd1e74301fa00eb275aa5c9630a3022801cc547b4a4122e0b6e4c4413755b5e666db648c6b5c6b1a53e0e5959e7b836fc3674e978829a1a0adeb49b6b6c67b319481b98ba4689ee502202cdea2b96f4df569ae3db4984eff67ef1f9e46bea062cde3106f3c5d58da167f50c69cfcd16af6276f5cc9c12f11711604922e4bb454888d9bad40b3564ee4b38cc08a3bdeb0bef35cf7ada3df414b9f02250ddc77bcaecc8cb14d2271ab371d58bafb449d68641b611feafbf7efeffdfe42188e31f22c002cc18896f60343da6e153046e4fb76706368e076c2ae75fb413be5f6753e6c7ba048835b7575c8a00ac01730866fb8d754c7acad1c53de72ac7664e1c988f06b7ff93abe4dd0fb6d116a4240ab9b18fc06912f97c464a8115cf803d78ee2a3adbfc582bb6402e1ff616fe4f65aa17bfd558df0487d23864beebe3deaface517bc16d3b76fa2603fb1fc39431dcf03e9c549b2ff2b087ec216b7f09cf8be6f6e7b429a88281ce822d2a2fd91fe495d20dc01298ef81933370352961a93923e4dd1331fce977b87e36a346606f773f8aec7db15d174113f40ef6eaca6281a139b8b7a2b08ca9de105653eb6da1deac8ef77c754a1d033d5c2ee190781eb8fbefe3ae51f144945efa2ec787f3000b8e9dcbddfa1e8b2df6caf422a30cb099ff974126ea2229bf13ff660bf27d10c34a7b8399de877098d3b11568e729ac52265c904fe67aacf4fa3ee871fb8b251c87c4fa9a4a08e6ff66fae0dad5896f7dafa948bed0830c7944c62514f33d1a83477dd667fc7d5c16201d01f08e163de6c1d13e8c0f3db64b86563b4aa7c8947ebf1811792939f9856136e02d0fbfb038f7fdd65229ba5fdb0f02d092bb36f007b45a7f277c00bef28efd7c9ecd942a8e2f3c5c4380213409160a3bf06eaa3546b17bc6889276f9f24e69b7714a94e38f177b019b46da5a53e3ae2f1bc296fa4a7e7fdef3173f7a29dff32dfd1d23db0e69b17f6a6587890ea620936ad5009e8e589486b213f76dd371ee56fb9b6373dae42aee5258fbababd2f0ffe3bf35634496135078fdbf92f5731143275eba0d7c77679c21b7e705bddba65d35936d14788aaffb8f44197bed7b37240ee6774baeab1972077b1a2940ffee7c7e5c56b9c44e820e0f10033cd0c65495e3b8d5119c1b4ff8b8974d5333607872430dec43b585e92b35de3cea1ad00e883b09aa40636eb62f6be1b37754bf0901a9cc52fbf99a37dda13f0288efc9c1f0e23c70c906e06a0001bfd35d0de95d9b772a85818549283dab9a113cabe8af3abfb9f655e36322b0240b94185c3f7eef96b225078a565f5373e2929b40cd834b9621ed9e78aaa277b5687538a6071c8e34fc677ac68174bd7854938a9092f0eecbcf52eaa7b9e327ccf47c65b758cfda311f40807d172b066fc3028e540c9b4f1a6d86917ba9fd1ea882598b747c96079f5ddf20ca20a67c3a5dfbba7391a8c5559736a7141a987a72d1696c61bfdfe5200c5b3f2d21f55111a724ffba3633999bed24393b73fd3dd0d0f41ba4ccd65023f1f00ca6152ac39aa7ae1d0e3d010d35fa5b26d92d6e578772f439ef81fb17534da1369f5214560711fc81a5c7d8d22827af091419df92d8c07fb906dd8609e2cd22fd25d97fac3ecd3be0bfd82d85f32bb7c58b902a9376e7adaf7a9fb38426c6e871c7397edc30676dc15bc2bc56f402c985c4b3a00c56f57f9e5ecb9e216415c5d67b0c149153765ba6578294a075c4ad941e2609272f1863bcddff627f2a93a93811db1ea67ed697dba445144debbf48228ecaf22ac426dc3463fd10dd6c9f2a16d6ee2a14c6038d4ef946bd6ca51caf6ff411180bead160af2dcd7a6135cb11084f2c965fac5effbf26712efb36072e148a2317d1b5539384209e95aa7b8e5746bbeaca3803523bc0bffcc2e6ae0fd89c5abb1e64423248a2812d5093c0dde130224a8f8882b976c76c40a2ec5695f1575cf058e5a163e740592d048d3f368898101fe41acda0b2693b6d0362fa11a3b2671f17ae6f6a2d2dd504620e8a960a9e0361620709a48801396b6e6ee316e7802efc7d9828b69f724c94544e65fef84b51ad5bf3e45d5dc2f4da30dd34a8fa540eb400185c2c8b24e8f6eddedeee3c01fa07b69143025e500869dcb3bbddedf777491d82532eb7fd22859610e27eb433c005942ef9568e37488573475e138fddd7b98fb29472d6df652f1f93e029adf65a7e4342128f3d50d6f1bc232533e9afb0869db71fb2ff45c35c5169256a571f3727799c222cff7de13a3cef3d3968756a79c127d270fcd87e37b6ee012519994950e52583005f59401bae29c952b3fb81534457ec033b083e45eebef44534ad2eb9f0efc194fd3c87fe428fb2bf9ed0b97120f97af138648783bc09df8b8774719f9241fc4852e2ed67626aeee2e202e806d521d5552583e6fbf3753b4949e8855d824c6d24331f792f67efc76e64b2de9c8950eca981a19300d6caf2039add375ea9e8ad7f2fa88304e42e789cfcbfb3e17c2b0f4522357877d4bd9c32a43c3b54be6349a83693cf65e9675d1744c0e11592553dbcc997a6e046651bb0bf4f1eb21a08a9857211efb190bc5a2a32f7daa4918fe56ca079ce9ce21735252a24885fe4799d07231eb6f048170c0eafac72fe20706846b82a298451adad0ddcea56e76c6690f9941b1f176f014ee0e30d34e4bca604ad0bb11e196843b5a73750c26f2b6d9e74b652a4bb6bfb99119b0c588c179fffafce3e54f4697de1d8b18c2f64bc257b521128308db49df3fb014688012565d4c40c06ff73bb5ea11cc1a9870b2e6da7f69d720f85e8998e281079bbd1191173aca0da0c1afe00daa95456e582d18ce55ab1c940a785965cf362e3f42826b1f3782233bb0b22e74a06dca1818981cfa6eb3aa9ea2d35922a6e7d144be09ada8b6655e549c4ddf44483b43dab0e884a5ffee57d082b8258fb1e05c5a0eb415eacb9e2ccee9a8d0dd22aee476b88447a87907a412cb647bf9a37bf1a2248df7eded9fb23d4a56ca86a45851f8da9cebe27a12c82d524e86bffc1dcc3dcaf5844e51b5bfcac87d9d6ec4d941ef5756439a08ac7db1a884b9884d87353ea3455e2b96201a2aa67e628ce3e5ae8efd883733c311c76c761eb52f239dee10d240991eb98afa719b65c398174e05b6e57a71fd839677e38f587c1e868cb0526491b0d4a5bac7b24dd97cdbcca7f98d0211886c0e53e269a910d24facd6d3a6d38ce32d6f376ae4eafae417d2a8298b6fcc18367412641644006321e38b489a26a565557f265c9d6351c236d11a4873a4bd08e6230e9f81a6a030a1226a16f6cc8a58cd44746a4cf64da1591004388f4503940a31f5a184a984081f175748182b4d53a5912ca2f63ace761e3e66aeda1c345d8f07177b82b730b2b34337ec8e2442ae87228fdfc325e7fde5291d7182eb19491b85c276132215b62d51f9760f7282d4f56dabfc11078a0d7b2c829d8678ef9ff5cece5ddec54a9bdd846d20e44987995a6eee0d4db2f268a4719450f7abcb2bfc4462a9846d7e3cd53beb59c484ce1a51694b215ed75e317e4e916ccf823fd45a8c0267c140909a403719e7a1d089a948a458a64a0efe9145182bd2030098571a3e718c9c07edc12aae1bfdd563f063191e50ad02b0a9e7f46c3d5251d1f0ddba48fcf163b50623fbd278e235d1dbdc1e376ff068e03b476013730481f3fea6a94a46a7dd549e918215051314307d38a900978c08c5865990dc1d9c1f4bed1216134b1d517501f18b13f7420200943985957e3a32816bff855da72f8748cdb7cde53e2ae37e53ec99a6dfe15b2f1d08a0c3edf0cf9c26d1baeb2220f2a65fb50d4cc48e3355dd452deef0ab3fbbe96a1dc0997e891df3979e15e93d8d96d41e5913f526cf8e786f73c8cb974ce625b837123d9bdd066901b0303223b461e0634dec1a99e3605bbe127e6acf8b9f7e274c23e1cac9c5c3039249c7d1134304f53b944886e91fa61d568e77d42c5a7040b3ab97996696327a7fb490bf3625cd1bbd1399497a50d4182c4246c61c099a621a1d32a3e636b39b320a967c3d00e397334e0ef66b194dfcd5c09687f1f782d97761dd122b108dc8655a06db37d0ad977613b9ddd113fa58d9164e6df2e2d4dc0103b34c297976d788939a543e7d700b6c11f777e1fcee2aa22b1f1351433fa2a3324943fc8fa4a2b563b306ef8be7cf345e731e1028764e3be74fcdc2a37125ef886d9efbee6ade3e62ba01ff7f86759941f9df14f12d7729005379894cd662cff1d8cd4e652193e605643a065f37ba254ce332448d12d48007ce4b1dbddbeb0cd0c8eb6a0c83e2956cc97f4b4698b2c4fb99135e3f6d0cd2fa510169bf74d9614129a8059e2a4f67c3e357a7b19f3a0451635f4e548f63933f16fcc16ec17b75fc2263749568d1a2e0bfb4b29a263567f6faa57339cbc985460b7a403da2a923e12b57e9f0702c76d3c1f6c8d5f3d674e1b3307c330ed77bc4f983cfe94b928077f994e7b94b29807b182b3c9f2e97d74a38bd85c114cba2d247e34220edc57e3ecc2d7af9af9e10000170a62e876df2543c4ad3788884ba56b5dfa8f37e14362c2bb792903bf1172bc0dc7a47d0b3cac17fdf7271be76bbc03f710261f07135e48a759e3d3c00f97d466b398059cac31033ffd8454d6e173c7d986cb050bbb3034b5add5c511228300092f647046f26f506446208d035ab21406a2527a5aca6603329668b23dc5d99289109d976fbc736078678bcf152517d7e4a58011097a744b4e620c489e3e0c80ccbd2f2f381474e493201a403a610d896e977a71d3044007a1848db8130b83f55a1883f339635f6d799f19f619c0cf12a6642e25a5cf03fe2a79fefd976e7ad57c246a78d5823bb691ed7fe14c42c57a160051438216162c4fd12c05e2eb6fb73196c28b52ac0b86f563e4791f074aae55bcd8af0a47064e6c892116ffe8d2aad9bd30fd8f59541bda21e8099e2250920c7a536afb48ba6d692946c205d8ce9c0daa7433a5bb8b65b6f6daae83e9a3c9f6c7f42711dd4ab5fc0154e766501b2b9b15549a99d31c8364f3cff65d0524534b7fffce63c465f822a847d555ef5c57bddfc1784b0572a6e7f2df88fdf1be6c941bd1b57af489904ffdae2a994dccb1fbd55df4aafbce5a1cccb7c2271e0f39a470844daf108ef21ef68346331f8357f37a4715e05bada76a281bf6354a6b906495e73b885208e60f140cafebb5f6f50f05faf6c4aa3657e879ddb94ed186aaa32f3ff98c01e0aefb91e298df10c214ad57dd45afcd1227c7827aae7bfbf5d1b502a7aca1ce85410c17c664e45c28b3d0e1cb2d2171d97931942270023cc1402723fbe3c69c75fb03cd58fa80a4977f24294e86648473265a9b7ba26f8d20698bf01b6c25d4b9ea625007e98eeef51ad42654d7a8a61d49b71d85a289716b07cba46e19f75c684b6f4883159e097c97e71565cab30d44de3d67d604a7b4b335febd413174715feb4a721708a04c4e3e9d540fcd92dff8f15b3f760e8f5515b5bcc68df81e868b244b231d351d62b9be6a29d025f5618e089d0b4de46bc0a9d13f43b0fa6dcc563ed3fd65df3a63558f2b455eec7d6af84cfec7d678681217431031c0eb43e8b4f3a0d308d0c85cf1af6d60992ec6324b5d4737fa6f98592ad1bc1f811e43e8a39c9f82c45d4d149e96e2a245cf165c2c63a52e43ccc03e019f284b69f70fff3feb6b4992192a4dae7dca578a844daa7644cef61ac1c396042fcc21ef1ccf254660e8998b4f87d8a591cd2f516575ee851d9d60c8be2702f4813966f320ab6d6d4bab00d42637bfaafc43968cd71a29722c4f03a82250f534094a0a612b0ebd2b9f39a18747bd12bd85eafdb8f2ecc99ca8800b5ad8f9e03f25ae0233febe3872dde6fd6f67ddeddf5beb77a4999bfbeec0487f127e42f5c92cd787168701967afa300f9534a929f80bb910b8ac03972b2c03f6e575385a10752bf50095ef431fb1fa546e1d0f37f181291eb96065fed591a2a7dc1d61f4ae47257151e3499f485071a93afebf3b81e64be524125b34ac44e303b092ea3c34d6a486d9e9cda09c1aa0ed4dadaff7027676d6eea6afa444c0955c131d04e6e768acac491279168f2507832817dd96988b7c3386ab27d5eede54aa5a0e208df6c113e4ffaa5a973b92029ee1f9cba82773fa861976d7e191145442d398818df2f7bccb0b7cdaff53920fd438b2afa02e7660bfe5cf49bdf0ff4f1c950d0acdc8db9ac718f567fb9783e60a4faf82b237d5adf4073427e00c04094e3a3fab748d305d5e69e545200d3efc3dabe68f43d117f0dc74a3a805ec144f416f8954e5836ce77d0ab72baa3afdc5696964acab1026be418facae73ddf8b4673d6299f8f59ca72b7c0271361e3aeb087d4a077ef0e4d5fc66940f48def1c875b229d9df0b1688ed8034ff799d9c257042b2f73298fdaf69e18a4697eae56ee8e766e5e766a5ee092ac19c1ca5ddce61bb2a20d0a056fbb843be386760817ebb817f1f048c1f884400449d443169c27fea9762b25d6f9fded0d1c973ddcb091e85c3b174fccb9ace843589c44bc7d09559f11ed019dc0ff8c15bfc38e6887fa55066f8dc2fcd90d1b24280bbf00e6755c02addad88f29b2550ee7e3128cef50ace952d1ebb6eddd26ac7e65fc376de0e900ba277b29a18da779269b80a7193765e9a7d1837c87727978c476907fa523cf6045817828bd2190bd8a40243fe02d09eb6d72c6f914d02e89ca29c4f03b6bbe2e4dbb0f6784a85aeb734c78537732b76073f5f3b1e1e2f5f5f6b7f1f572b4e5f2e0b0b7f774f372b7f4f6e273b2b7b5b7f7b7e0e57475b77770f3e072b7f0f7f5e3f2f67177e3b4e0f3767742d3cf32766caaf8f6961c666447bf6cd675904c5380e9cecacc603b99582d3ffc6307c02ae8429f7ae5e2ed1196e47049fe64191f2ae83970f7f4ff88f911654680e45ef8fbc9e48afb9d97a3a04459718d8cc6e145da51ac99e1fb0fe1779a9077090b26b58d660acb9317d86cfb9234fd75a39630b65f7c31c44937c0766d15ba1484d2fdb8efb46c0026cd362bd4b81d20d8ec59138c7994e5d33f719cf59b866f64cacd25d46d17e51a4dd261b0ea09afb48d824195fd5041a720a6342f2d3bacf4ac1bd78fdb41dfe63c2538035f16b743c2c5703bd0cf5e3d52e4184f543b2a8f86c31a0e06b8f0228c0b669534b788a876b0143e03bf9715013eded2f962877fe96a61213697446f430506bc11180bb7ddb34e0921d1f66e141d500d80ede551d56360c002e86fc6f0b39b4f9e628928292ce2c17e40400c54368bf1ccbb6417ef5159e16c65a3263c2ecd211ed4de2e99812248e9ed7e163877ab3617011d14c0c189366ee231194fc61545640f89a07a6c1d6c266d59964587dd56f8602c864047c6aec36713b97d541605c4126c770cf95a56ee2fe5d8759f9c92a4046dc4d74f675e26e81479b5c707c5c9647b4187c2f264847f864e1cc9060a8a0899ebf8afe3846014b46c03bd1fd9859a7cdd56ee23a4eb99592cae836fc9a866b649dc00c0ba3fac8f2c3731be3eeed4f4fe8b61bfa4ed5cefd9347cc1a47e0ef52b13741470eb0f016c7c4474317665f457a6b8070cd1fc88b3e79bb3e5ca374edc658f5deba387e500a8367d1b292b33bd7c0cf4d4b4191685510ce86b8dd140264e122817d7234edef62400b32cb6afddbe70200daa4fd366d526801b61a49692fb6c2a2550e47c9ce82d87160f2ca83f5a5d575f047f7fffdd9ec086a87d78aafa56b2f3f4bf0c9a857b266d730d9504c43a6aafeafe148b2154541ff2071b72c780e94da2ac526e1f450b5175f7d114602af3eefcb7c8488b16ab548861c09edcb3e975200846bb92b94b4f4f99a95f1ad2770f7fcf5ad33bfd6088353dab95b4700c0293f4a608c8a35ec8b2e4f6fbdf8e5be93831d88617355a945a25b53e76db23812c2267c10b13a4bb9b96ad3d3ded4e3bdcced276b1d90d9f29a1a49c08ddd00deb7d5de585cc1cd8a922ab1d6bac99d27d35a83b5babaa4dc50cb07234f9858d63861202701b3f62c7837fff170df54f0b3aa063bb376be48fd37a0ceac6d08fea76e777b76e5678baa766348ac0f9c5cbf9f0e721e0f642b5521cb893ca6699e2de6b3c30f75b0db44b5e906082f9988c38568df4f1601782432bc2b7f9110ce6ed655b4898d538739c21a1a7faff7f51e08bd9617f4130bf20373c8fdc7a02f78254bd76e2555fed22a103b1bb22ab4a4bad9d2af8918033e05059fde06391e571391dba845138b789f65ca6b03baa6191124e29ab668d534423b11d78274d4740c1aa1a86a34ffeafba2529fae804861bceafbec520009a224982fdf013a548ae5d74439b350e01b9f1afc8a54c5d0dab25c4df3ebece3a6b077b024d597d904471502a8a84018748e7ebacf520001009902f3e94fff258a5231fa7d4187bfeb3b30bd6f9c97c52f19c7e5c6bbe75b462dc4d4a73090371ef513c22d7b2d6cf8c8f555b1a117582857ffe8c867808d281bb1527ca341155362ff2dbc8b6ecaff2f44ed301689305085c3900558d9137e6aa19900718ed1c71b05bf0151c44d67ebb88d9f1684063b681b9e326b08f3decb60c394d46b827f71339f46a9818ae762aef4f4b47f6388eb85730b6d0339c65a82cde2300d65177f0ac6843be72fef0b46647e8a66f1ab00c0a10b67ff5a8b27810c35e1d0346fbc48dea599fe6d4290f65f1918d1e3dd784fd243ceab9772c96a1d9fe95e7d3fa9514b9820195d7754de4d896dcbe8c4eabdc32c77783f24765cd4ea8c50c04292d8b4dab450453ce5deba6d7785eef50468b16db755a22e4b76e15f3a3a05cd110f3609c1e60b9dc2d4121f4cb1719b69be8cd4471e44211996417ff4992b42bfbaa074f35410738eee1f1961b43ac43e257170d13e5954813447ba236da19645182ccdf9085c6f23091c2969e4c592070a6d0bb9a0dd49cc752d47114195145a4e4a0a1b5bad42c3fb9ed16199b7026c463f689f8352baba93ba546ade940ed955820fbe725459d79101695b9512746bae1d8bf4bd913a9ffd150aa4df4efd6282837c9911ff5cc1f911dfb79db6b03309f4617a8dc0dd8933628fb3b3b490beb745b3baa1191faa4e39e55caf54ddf751864e076876b43be0e570f259e77cba2c48c55d5e961c7e7ded6fbcbde55088bafa70036c3fcfe9ea662a8739487761e7b09847409c5a29b647622f4f08968d2d26221d108519c252b2e542cd49c7f4ada3c3fd436256a35c0ca62089796f7620f1d45dc27144647d4b320ed4e2c6456160e4e6c148b0c165860390be927169c8c8dcb6586fd6b3c7629bf793a9d59c3106bd60ba3473ec48f1d812d51b31c8f2fa6a4f58581293b89da6d0e31d5851803350b66622150776481fee863c54c390b13ca2499097969b6d44c50298111ce547e79662923a622d44bb3ca120162abb4ec2c5f9ed1086164fa239fc54965a802843457c702996d1c2d3409cc0cb2295333f4e42956eab2b4893ffe4bfbbff9826e4eafd0e593f9c18cdfccb3c88810e0f7f813f529c1d57ddf1531ef09b32472f2c09e9737088b23bd59be0e7f53e7936de8542177bbb76cc893e0ed0c701213011309131b260e4c5c98b8335131f1edc801d046a298432a219eac31732226bf1a274fd6ccbfcc08dd39126f469149de2c4295e4ab332f0064851093c12aa3f8dd0b3c1923242a859333c12bae223c44b0bb544cd524779c5aa24cf0b558340138c8ca009eddd0e489899e81f91599246a2b25abb3c18a892aa92a5195a92fcd969c0908c2954a34e14cc59767922a652fcdaa48c4ca8d3426d52d2fafd7e93266f819f342a7f476c6428d3836d23fd8427a10c2ba80a7f01a57f106d0b3e111a6a72325fdc332af73c56187fbccbd304bca66467f1b326ba70f872aa1672507d9c3fed0cb70081eed6d18de14b9b167220776ac0cda2fffac193d703619f1084883a85987c6682e40663bf1f6efc7915870352e426aa774648a0013c37510e4f3fb61e5a9f67d8b0034d722b241b8d342e9b253caf49527981389795bce2fd351649c02dae3ebd42efd4a21f3473eefabbcbf5a78fc076cd66f06c7a4e0c0dd4607ca5f1d1508555e31132ae7514479db1d8729e2a134bf32008a041bfd35d071fe96bcc858845a6c19593ef6655bf790e81bb51cfbfe4254bf1d41056eae3bf33b25cc6f2bc2d81d3a2726af3cc4357cc1dfbecf0d704634981605bff903d148d6ca5f0abbb578f384fa1f2154131f554dac86e102b7b9167f9d89c3509e3c7500beb1a6c6cae733eab693d737bada744c703eda7441c02acb598141c56090fd8b10cb9e38ad821c94b46fecf3f5d6cb4709196bea9ebda7b6c7be901a129c5106b4624c001f0bf8744e73d34fca9cb4c290cf0e7f8a499f5f3fb06a8e43c7dd94f99570305c6cea2969b910615b7104cae610422c4340e41acf2698e8d6f728b4ce6de9f7e40298befd29f9cb88cf5f3935340886afd3be9ca2b138f951a9c324682b6802b9cbcc3e802313ef45a36a0b5ad3ffbd204eac67e1b4ad25c8e63cbf867b63a5138422f3c3b918fcbf0712f7404294127a745a5ac3a2c69ea6a95016fd6f8d6fc18e6588a23265822f5b10c324aa7053fce9280464c462066999386746f8bf0cdb122c1124abd0a665e5bd2ab39ff04bef407f6ef06fb802f7b6f933670a63e627c4c314d8f40d02ae30fe58b6fc85f39721fc9e4f573b5143d00dbfc4b87fdae0394a9051a40996c1864152c3ae234b2ed8f73770a2a8ad6bd0a94b9b5283820493c562b11e25b121dd35c20404306560237205cc09bdba43f1b8b887ef8e8a643d93c6aae62674157318691d0870c3a2ede4a89f834874c38148762218a43d2cabc6ee320f4d91a630278f6af9f0343166835fd10978bccea53daf4dfb5207f8103813c373744361912d6f723d28046d6614fc78a9d7c0ff9348bb7e7607968ec2ec11bf42c860fe58f696c55bffec5c2a1f5327f8f7db9e392cd8639be1d78225b9ed0185efd604aa1c8eaf0c2ee4728df685928ec3f39c15a677cccf898306cbbbb654bc73e39e27827885dfea403c9c686ed3a8c3d58b2abfaec80c38316e0cc6858fc32b17426501965f38c5226b7fd4d2c930026d11888aa2ff5709a608d5bd8da273a138395fffa7100fd401826251f793d2df9cbb91dd0dd46b86f551be3774feab914d7e66c6eb89c03a5bec80fae2db6b12ce8b51b3b6f1b6b4177d52e77aefe2d11ae8739a718c203764ae6a781065c512d5b445394a6f13e22d9aa26db8b0acc1fc257cdee2928fffd6d26e1a3c6bfbc10097f2143439beeb185baa1c3239898dff832657d519b58f0a632d9c7146f3d44e00836a4d9a8a418a201b33f7643db5461add37b86c6ac7904068ae79756437c5e7bb010b1d4422addcbd960c65b3fbfa6639f0e48c013e48f4857908d1e1563b8ac1df02ea877dff74b2f12250a5b2ea954f15ea2181294b075028a79f9738868fe865dfbc32590656bf0f19002f4af71723a7b2ea229ecda473b69a69b25cf24e9c4909017018ee29c70fd5fa5bbc49de1bf4c0def20bf2e5b5897393c540f7f12fee69b7c92c8f2357c5d28fba1c6d6161dd823bdd9fc4c92f9bbc2e7087d1ffd53aaf7c56c723f550ccacfebd06fbdb5b20c9d102c54fdf2ba5bd6ce664ec4cebb7146f2ed5648ec2c89e76f3ef5993a946fb8af69a1cbff51c062a4638e3badf2ebe56146e85a40192a6d6c461a130d10c7655145508300e35805630abe7b72d79b4bc7b609a0ba97ce1ae1e5872f257ce67492c9c0900dd55d2267d4b1711c56ea29101b9d929fd35b96b5d3afdf7ee1b84a22fe634a4078f5fff5bfa6725b2be9880c0ab76ed2e091c7f5fee7efef443cd1817d063fbee22aa62abda944674856e3f01e8163ce125360cb45dff72a47b42d8eef0f34255d703febd0cd8b686442c4eb77720c848408a7614dfc161e9dacec38767e351fb9b19e08042d9ee3a24e96752f5b4cadd9e3615cd829876d682f7a59c4d4a287cb3dbe564ed1ae81667c45a26b8f7f98e27035217b41819d3dab50b9aba6d2e4bd23b4626d81c4ff11f446ae554fdfb1bbf458981fc3376ba8e72bd762438dfdf6cc92e7a287ce5a751f2a1a0e48a8f1ef384b03cdf0529e67e7d6f00afd0abdfc01ceb21e3d5fa0e0fdba48ea03bb2c3ba141c135cf9cf955c9c63621125a77a31218a2cb94577b9154d1c34bb5c3ed465cd131e07ddc8c2409686b4528b2de5db3cad21fd65e47dd97224f8de54e0696e7b3837d386d39b9180b8535c0f5308143fe19bfe93d8afa07f3a2e7bfa31d8f5765e049ca74634a97f8be198faf8883268019a7aca771fcde96a6dc8b59fa5e32687f74b5f590b7f8abab29807c46c3cb8b031c82cf3a66aedf5b0347da8b05d51b25cd298ab02679adb2f9ad20f063ccc0d0be5e1793f86b47afec3546e68304f45e2c85c506a715634652b624acc86e3e7e24bae3e634994f6e0b1a7af18a61359d0adb700dcf67c819f03d1959dfd1d604295147f54b938369b769fd018e623cc8dbd91f2f9f6c35834f98fe4949e1bf2b78dc798fe64af784beabfc6188b2364fd53b67f41e29dcd02bb58f4c5083b4cadb860acf8d7f4a5f61aaa0f0fa5779ca00effbb2568414145b9df3b85e8c3fdb7b4bd9072e9bbb93fffec8e37f415a87c2a3b4972aeb372b2f5a70b88db058ebf3f96b97627c7bbfb88d6c3999ed344c308d80937719eaa0318709af4e4a9fde510cce30a391a7410ecc50a79c60039d008538f17eaf30bc6d012e029f6fc02c74e639dd4102583fe76dadbe9a1f34aaa725d4cb43030c286a30cdc15371fefb818ec01b3109e7fbc6285fe697cb61a133ef57e9cf38c4765948334c009822562e49d2cdfa0e83c6b96ff43b551cbe0c8f74299fa4daaa808db353ff2deee54ce8bf11fdfd2d76549140b50ec16316ac0725b497a79cb8dd786dde19295152236571822d6c22dae20a480df8d37cdb280aeffcdbd34bded604bc403e7b1cf59ab45f8713171a6587bdc6eef3171132406d586c03b7116c0ee115b5dfe7fa13aa91925fe8e8a43c66dc6521adf5048e3e5f1a85d56be51ceb1ae6a112b92a5fe5848926699b4540950210d61b2faaf21a3238ff922f03c34ddece8cab9724884872a99a2b24cab772282aa688c9c04bd3dab598218d97ea92595654646074b8b49d3a77c2ac894aa4cc6f4fcc7df7c3f2ae8e2276507f3b2eefe04c1f9dbb7dfc2d1134000f5ef6b09772ac50a533a21e0c54871318c756bba8aa0ebbdbdc2525c0dd8f88afe32033fcec357116ab5425622c5773d8e991a17ac7973e9b436b1da28d4f2806b8d10b408c99af96c188d6e36467a9ca316299fc8475be3928879e87e995e58cd07071ac28048d2abb3690dcde818077596abf36a7c8303349b6540d3de1fcca497dc3f0e73a110c03f924896611b264d33a549c8bc36c3e5f1ef7958e9f8d8c9d7bc3755a16f9f21f3df8edfe16c4680788b553400b7403a69e34d3eb0bb3d35f6776d97600cdc0f0536ceeef6b26ec411273dc9b1af1b649c1f62e8258e703585f85aede5ce4a6b6c00d8566bafa7d74676e5bac3a3c99bfb209a755b460c9ad7a02c34af616d47849bb82ba9ac96b060370d56f6c0dd83e879c87fbce6d0157f4f70c3d5ef7b0f38499ad8e278c6344d40141e8db5436d9bcaa3c812811b051e2dc082aa26221a341c596cc2a3078148811952e068675fc196e147459febd812a13cb4505b709386e2982da7f17b4baf597e3a039da7f453a126bba5df6b61f5b4da860e5a671d605a00b6e74f23d07b8a8152b78abc4ecb4ebd33c5f3f31b98088e43cb9bb730d353e6fe79ad8bcaa8b49d950f3449eaae850152eafd5e67e13dad876d90a7d89bcc7d48c72d84a6f89dd003379feb0483604eb5d1ad2ec5f67e96ed6c2a4cee0999adeafdc8310c7ea7c1e8b926e70cdc32ab7dec1d8efd36a21e6f3723dfb695ebece46bad9b853ab9278d41580696b00dae1b3edcf51eb99ad0c5248d292c1768e21c2044c665f90649e98edea307bbf99ff39d66e2e0c8a1518c0e7b1a44f7c87266f8da4123f36ce4af8b5bf566328d55aac18e68ef812f48401d4505e0a72eb737fde69abd7f62b270800e9cde42fadc6f83ac0c0096e3a5fe40e27d51ac9ebee1f0458a2d3874afc1f5330a0dfd6eb674940b37ff8c961ade831cbc3864873a08611dc113b07f162bb927e68bc2813b9ea8d82cbd5ad1407b46129dd845cc163291627148167ed9413fd843040b201ca76d7b4a838b0e63789ead3d73fa41ec129687374b947786671ddea12228c4f176ab9f20bd08aaa8483489ac744e54e41f5bca05952e7638114580ce4490591fefab124496f4c65910a5ede2f45bc7971a28ce3b11b3f3ee1d7c649a3f5cad58a6e30ebb522355485578e86d98657cb9ae302e188f00c66f21bd1d3fc7838bb116d22394ace2246780831f4f6581c06ff12025ed905c4a268d0a0aea2e097c5c8f4735b4317dcb689958b9c5c245053931a437f484adf8ea065b0a2c2a23092fb7b194e89a0179f00592fd5331327d8ff226b411d06b2479daada82956f51d60ba4101713eb6ba535e1e7d23ae0884b460b0a9dea3a965e524727144c8867b162bbab19976fcafe0ad01c77747cc75fef3182698020671ded895c59791795ae55ce0e519e828f621cb90577d2ee996a2ecf1d73b7cfa172e2312ffe1a06d574caaad8de1cd6882fec0c6982580fa8f158a43cc6edbd7604ca1a7c7647bd4d7e80557ff44286726f6de7aaa10eeba888fc7b52c99df6fd3154fd1bd9d68a41c7b8c0a99c3d3c2f0b12f8f39b8b19558a989ce8e0dc17800776e1f565eeccf97718195499de10117601fe6847e7e0b0178bac4b401f80ff254815ba4e46e09f35bc8f8b83d556be1b103f41d7e2a8856e4ee3382c14ecdf7b09d3644da2b676d015492ae114754dd7f270e46c4abf1e13720c78256b18f803d1234e33f0d245025944a11b0ed4afce4145727b4ee1c8caa1a0f31d27ee6754aaf8ce044695e17bc748adca03286eb172f02ceb2c3bda7b83414367c684247846f2c932bc0e76bc89498c88dbf0e67a77d6a07b87c5d8482a1dfd0c34558f3850f69fc8dcdf21ec33e12f21aa14e7628b399d1cd9940345df7b5d23338fe4e1b62a7d0edb61fc04c603547cc388784722ce6ec255fbb58b5e464c6f7be65fc7b59763dc7d6c01009962e38eac62768fe9050b347c2986c2ed2400000657e16d421ef748bf7951ecaaca807662a3a27cfd2b2f518e4870cb6813085e9123d06b62513a02362e18b1e03dbd024b21670346447835817324921ff0feefa85a04f92326fe2c09b087734ad8e108415d49a077b4a1afd21404ac4c1e33829105731622f86cf48ff645fe1856387c96456c95878833bc6420f5895511bec677fb2d35d01be84f2b6b6c2362ce53a0b3d2e3263649286291cb12509851b45e08f7ce08c9b5b1c2afa4818b912da1090afdf6b8baa16c0a5494950c6d8a6ee8e39b4063cfad8d0c5257b2c0c7432627fe2f344c43957395f73c2c6f5bb32ac034df6184502dadb161177417523753bdf503363c7804173ac1ae5266477abb5312f3de15e5bf19bd46ce83bc4ca873eab2b94e7a7d5b4a632011e00b72a551cdc9c4e97f3a0cf86ac75b7575e13b267e77392c439a63ad3382124df01d3086056e12f180a450b49897b9d69a5adde6d1bc9915ac84d9cb544bcd44f0a65dcd9b928222499b07961b08461d1089a03b19890f3e7df328e69ad4cb8ece078c7098a4edaa6a14b466f8b981055f20cd478f9da02010dc28f1990805b37df437ccf57136d90d611e4532921597981b92ff292f94e3889c4c4abe6ac025b2b2a3b695c4c86a98404d9d0c4e978aa88faedb26437e9aaa3e1c1643f3ff8578e07c96cbc8481f39495fafcc20037c3af03022f4c91853a26b6922ac40a33f97ab839118e7f6c5aeeddb025166ce0b7f7872dbfaf784a51f0590aefba300a1ca75af4b08bd1145ded617122ac9b68e9707f5df576a7651d4fdd5f16ea7f8449d6f9953eca1350860656bd805cad03f344517d0db5964100e7d278e824a503985ad3f2ebbee17e065ec52fb8a3bd3b1d09ac7d627b5d2d3de52f2c5a99f89861275a1ea79cb9543b7094f6c3fabb9b433ce2fbb08383cbf734b42320538c7dfebff11cd1d7c3a3da31890f331a2c78e396cc74ed110f7c44bb1fe5dbe83a5c3734de75f5d04dfff4396d0538c53181d0e0842409ad8575c05134f87706a5505d0baccc87a685b32c0e1e242e338f5f029bcd8412ed1b12e77afa64e057a61196b6e6e11e7f6408a06c52c746d87b0946396a97b2b8310850289c2c341adac75fd871028aded555805cef42d413a8dee635c23b9b6efdeb693b8b4eb639a88d0db39e6f74dd7037af9fa974d006a15175d65b801348a9855ffecf61e44bdb79c2dd71ac1216cc65b639edcaafd445fbc3c15817a5bc14f49a2b48faf91b6fd2c3bae1270713c747faccd2366f466d2b557fe3971947fff024d83945c8da881d833ed773cb1e100554470f6780266600f8ff892127524c3fe7c86b96e6dc090251b146f1dbc0cdff412c450363e0a32b8321d916b88145eaa04cff3a45dced912a5c74df28cbb00f20798e8f1a0d23efbf1f5dc6f8d24befb19075eba727212d9d85aa1369cc0fe745003c1c6eb9ab03a1d43686b8075f6325ddb6bb5d731f8adbcaaae9cbbff1386f7b8c1495f755e01d6ef84ff02afa85da35cd10ceedf1a0456ebca749904d0f75ff9d61aeece4eca8b63f04e0ea1fff441722ac97a8aabfc37bf7095d1777f91f30bb569726472e899b5dae0278aefe06bb8b14d05ed7f2dea56269fe82b4dd8ef85e1b97199684f455472e0e753e4d8b774c57061db5d37c3d440dc521ca65ec339849e5dd26b4da846c259c5fd6e6b39931bb749b0b7d3a84a74579d64eb1063558c594602856b05bc2064a95d372ec408a0fc13ee5348f665efffe8e7e29607ecb1c17f7a8efa4eccf3d7bac195c1aa63ec02ab3c72193b274b944fe834cb7032e59e74b695e6a0c7acf343161a2a24d7e54ee3a0fb9770e0ddb074ad8700c8527737a43392471784714cd4fbb779173610b46b81bd9800dea6fe244b161bf097ac1f1ff8fc69b5fbfbdcb8219206743eac29981c52ae4ea6c78ac04ffc239061f918f4aa8f8b1ca19625605e14c3bf3faead0e1bfc060b38eff22d1339b73cf5733a3c8308fb35612ec50abef98f0547e56c5768719ab170028126cd4f6bd8042ad47d57969e81437f4e472f5fa8e8a2765d8d1a298ae76c4ca0015a752585bf10f1aa7591e1fb2c9e3073f48ef301afb9556dccd879229002f6af7fb349520f325e0aa92a097fec30e4a112be773e27d3699d8204381672ef5f4639dedcb59edbb442c52036b65aab248568569e22a59a7c4c54101873b6c739ef2cb80f01cf66fac744d00425395bcce1a06d268f76394c525c83b237e2ce825f9ed27b8c5d81d30aec16ad7d354fbd9d4b82c4edd80b6da5aac8d1f6e91d72fc7ea86b3297ca470f0ed1ee009951a40ab1902857287ef2ccb9b69045c6a8b411cfcd0b2361bb4b90125eb97ccd6fa494d91c12812846a6fa17108ebcc80a7d31564ddffcd1b4afdb34b4176e549d1ef6ba764fe83499c21032ff9c5aebfc169eda4334b9add4c78efd1d2b975316541c4d2b4779a2ee9c1ec5d44026a7481aebfea33845056925e939e7edb979a6f48aa0e3abcb09f75fce4d9176f5a0d57a7441f11f7fa6b6f41efaabdccbffd856370f6b5c78c86163ca1e26bb90f91d1639c370b4fe5e8e2d44c66027a0a673f21bd6a6f1893a32d284276ccf1163d7b636be30fded7c6a01931dbb5eab64700b61e6945eed3f5101e9b85b849755c05f98aa68df4df7fd02d05e668f234ff655a78ee1c41976609691f20959ef37a431e26328e36d998c72e2d1301fb272d47aca89c86ce7cf318ff2d39cfc9c5b1b901f07474e64dc7f238c3fe10001dcdfa9a8ff030f84f689cc55e607ef28b33121b4e8b1455bf27a6171353c028e0befde1784831e8027ee0f4b2086e37803881d255a3134895132a97c951357dde01e929992921860969dc2a96281120d21914060730c334bc1ca69982831c71827107ec24ba8d695a0f05f5ffae8f6b7eac1b357497c9235a3f04213aab5e22f831bc672d48e4e721bd7a93c6aa2ad9ad00d45d99895c86db8eddddb995771ee90f7c6d2e545696772c7abb5c95469764c2236b1b05a456df347eaef4551075f88cc8d341bd857b528970fe12c311747e2ec58eaec7451845fefc71c0d5fef2e861158f1e86eff921c8186234458a5cfdb067d922df1324adb7b2c12d4c3d01085ba982787285deed68bc141cfcce8a2601c606090fcdde37da86c0b6697b42173d93b0b72d7dc525290febd190829865691b275992d2e4dde3e2a808f6628c5b09a0142959449c9a841a591b88c5cff6e86351df1f712a41908471647ebd9561572eab15ff8795d0afb59cce227d12a917c436c7e93608d2336bd3f10bc03362f9d56a418855649c64e23c95a96545936ae493085fba5ef740a9b367f73746e26af018d214ccae9d3a2d6b496e3a4ab683329581a0668858093cfb2eee178e0ddbe0afeb0cdcd5bb516a97847ec786c4a464e007ec2158c9c3443f320b0983bbd09b625356189c2dbdd78b4b45a0e5d826d3923762c61fc13de8de0a0741757ba4ba415cd287e4ed2005767238f861c6967f8a66cbeaba83f854eed48bcaf8e1a0a2ec782998659dd7f907399f754733f15d6d556e131fe3bfe28a67e500fbe5d235356386d8af14fbd6f13104f5152924035aed757b28e69705b72c4dda0ea877270e87fedcff83cd104aac36c2c835cd4aa0e27bbe36ab16115c604dcbe85f1ea64dcf8406e9454c115c177dcf565505af96567421a63cb39502d1782fcb962816c093ee6e8db9a0d67d10be0dd71a6ae24ca87cb8fdd10734ff0ba6350c13644222e68f44387eca2fb647bfec29ec1228dbdb36ab2618d368276ea8b1342e1cb897a7c436761e3ecdebf3a5ae3b3bce44a16b389ebfb787cd35c424d02ac3ceb0f6920af7844f0aa8250c01167792a6f3ca07b7a8393917d05299e09fcd0a464df6c6bfc2e6ca35343028fec261c23f26cbf2a6f3241f6e5da1b062f5ae9b788677c1c5d1f190787108958ace8f3a6f74184cd9a77d2289db119423e5d95b7c0c3f52b011f5636043d8da7397fddd44fdfba7e2dd8736ff638640bdb55b89f8e2c6146aca389ea7b8808e5fbbeb3fe3e6ffbf23f297249a01346a1f29bc9862a1279d5dee6aaf49fa48d939ff2ac95289377be55f46a64c4fc8447eadfbda9b87c42a5684b3e85ebfef75f7b2ed4eccbb959bcbde5601f8b641036e7059b7e2cda50e8affb1d8bf15651de9d6871b85b75e8699eb4ec7ba650d0728e8d56e116c3ffd0d5c5ffe8694d7a05ea4ff356c90ff938d564ab5172d9951ad24114f30f38faad085cc969fd52a592c06acdd36fa5eef01f661cd3f2a8d5e913f3b7cec767f1a95b76a79bc09d01a428128abbc13144ac55677089c8fe8963f51f86b5022937150fdaf8dfa34372492d7000fd7c38bf4d55c04a40a3f9b330711d775e3d181294dac161c3e76254f136bfb75016b0ed397d65409fdc2241d329ecfc58882bffa252e7d8f04f1bfe3a3c0d296c35d303d360f1779a5ef666be3e2cdda2993c5675979bd17a4a2f448c8c797c242c2163220de244d84c333db908f1d2c9ad3fb790ffd61e367a3c7bdd5f18fab6a9cd552c1ae287fd3f85779b4ca2ba0c37f81c366b1c5a8fb63122d7331f27ce879266da57535558db3eac99f46fe59c3cbdfd4ee0228126cd4f69d2fa39afbfd4cc8796b689e063bcdc94ff8f45e2c48f5f3e1b4f78fe0f38d9a3f8e63b4fdc474507ef0479adc6e625f0a70f1f8cf4e4990bffa2ab72a978dbf2661562d2139ce12fbbce31bbb4b32ee03b2fc7e26a3aabb69e2ec3e93408be1e63915ae8edfbf4bddda96b4a4b6987d5c30af921c420793d9d296dfd32b338863b8b0bfa89242b5b207b09734cf65d555517a92c5abbef88edcf13e32f24d41771aa43980985018e1858ef8ae8895138ccc9f4f839cee90d0ab0b351d88807078928d01fa1df2f0270e83baab1a4e3317525cc55cd70829d1f3ac29e02b3f1bf036461c6837b70e19a9ef1da221fca1433dafd586c6d31220e3e164799e94147181403b04818143176d9f9d2c6262c6691daf2741f8ed0cbb5f2a35c400e162c1c3e3bfa711d771965e6468d7c15e259f8575f73f19a8c9a7f4fd8ad88ed80f6b036e0c2f0c42b226d3c9230c445f07ff43e1aee24499195aea0a78d835bde5b47c45c0dc544eed6142e86167dbfc3829b9e5a2b9a35ecad092d41417b54a9cc9dab1ba2f235953f2feccc4ff9cfa0a60e7ff4ab5f67ae343b21fcf903489a6a176e30f66d73881e924817567d86b057f5587412d6ababac5a1a52563530abeec446503b16d0194e45f78e20a819fdaddb6d5b2b12316925c986c12f26cccf9ff7bd112b4916176c2d6d4de4280cabdf35757e26920c7969ed858cd4a68f7c8cda51b17e77f1e3b95cc7c01fef1d66f002def68cd1509a15d9e8986867113c41193b6bcb6c187901193a3a0517d888945c744db9f65186c4234dff0b468ddccbb37bfeff343918aea3b8771c44675773a40d6c046408be10d67bef2965d0d60c215fe75ea1e894b98a1f5c0ac26307ace5010676526ef069746ae99fa83a09611c6e296245954425ec3e1f46f50f188e87a676c53c1d89bb7ff4e58a9f28c310c904116c1fecfb1f7946c5185a2f9cd2fcb57fa2ab9bbaf4606eb7c0045c57ec3b7fd13440f82470bf2d1dfa01f47daceb8df4e3418bb95a0147bc46ff6c70359f80527997f62c62dcc03b2e292839339d85ca3833d544dcbbb0a2ca1251d4e3f3445ecfcf4c9f3e820dc75ea20f7dba73b268f051bdefc92ec18d8fed036b20a0dee0ad05a2a03725a246db712333f0ef093f34044959ffa62228e8653d1f01009ab6a3889541d33c6f9ef3a712777542c556b3f6b9da38e2f31d4ca57ffcd15eaf3968f1d01444dfdeb64a587114b67c41e2d8ad7317316ea7f04f7db6564538dde0e9f29c33ac2be82e8fe402623e827813fe2194e6584b4858522a22c9a8bf9dc63acdc81fc719ebb26edfc0f73cc280a6ed34e16d7d914f5b40794f9437db3d9ca5fe875a13e4f0669bd4371e963fb13691469a30c902a4aa1a68da700219e148e5a36d93c9748340230d39cf43790c42521a4786e2875fcacf937cf733c8039a5e0c73929611043593122bdc50316a7ffbe80693a4247a7a99bdd3f68a771a734a7464f0c6983d1a13e7838773da9bbfcfb7df8b12270df9de33fc3c60f900b45a2dfa3dfab9aa82490a609a65b036134d5224f501d95347222cc8d3010440ad525145cb67779500acf94ba83373b1f515e89c3144e887f682792934b05bd6014ac825d700b1e1000c28018900564765238f954a8811ad0057480316006ac012be008b8006fc00f840211201e4802e9401628044a403550039a8136d00df481516002cc020b601958039bc006d807f6c0217002ae813bf0083c81d7c0e7e0bf1208211b80623900500100f398b5c7676a990b7eecb43b68d3faaca8995683dab0e74c8977780c07730ed1522e5476f45de52a7e208b6d5b8de1d4f2f652603728f9e6cdfd89baee7669a12583dbd2bfcce92b99cdf37cbd35e237aebd76ceb46f247ff2c37b46645f5e44931d94eeb5bb63c18807d5e44ab8f094eefb3d0d425da68867ead40f8559f6059536d1459f053d8452f220b1db60847479f9cd4a04c28a178af8a410c0805959802ef5bde415b475d5126dde6f0d2ec14154da04888473ba10da9b896047bc7d725a0040eaec9673b9c249c980244c0562c1081dcdf79f4b508fd0ce2ff68e822c3b205858672ce362782465f7d2adc37434904cd47b5ab589e78040f7199a3e68fae9e6978639ef5915c2a87a53bc55b6ede165cec6ce8312d6798c7ff8260ab088379a54389c69e786a647b23cd54c79720f0440e2463488b3a5633a54fab052d96b878f88087931c456b36fc8a158b14a3d233a07cbf934fb561189131339e4865213740f2cf83eb1126129dff7847f65d5092e50afef7525c1b48a7aed815abc2cced11676f65fd5dd639be8d3c0164e19a50d05ff131397e0997c29627065af938df29875fc28477d6a2656cd9c774fa8dd844c528ee3bcf94b930b11e987614fbc7f0a25cc8b26e68748620af223fb52e9286741fd6b26ae5922410f848de607e2fdb49173794c71c8d1351644e732b1851fb43eeaeefd55c80b45f20c0d2c506733044c3b11d0f852669b85d8d621d4490aea3dada206ac60a3ed2c167e833d66fd3ada6ffe8d8e8154b27fb0a3467f16a93bb107a69808a50aeb814ccb6df6bbdbd3d784c68d1c43836a26aee40a7102a4fb688649da79e303c7e22e58996a9d8aa40e8accb6ac6cd42a0434942739a41ac4f548826c25591e36f6a5e828b0b2bc8ddcfa773d27ebca0a7e4a6d507a78249c653b8492ec886af2dd05de25bb66392eab8cee9e58001a3dadfaa1a8103d0ab1fce3bebcc6e489d14cb4f0d5be468f8f20de3a6ea10c35938c078167240c790d65b2226d1e1d945fed0968e0046d633c980949628ad851787d3907587f6f42d93d5ca46ec3f10f8905a189451a1c03a037605f8ae82e010f07d4717c0bfd5933096c53f057401e2379e5732d6ee2f0eb16641970140492be5556726f8b253fb5b7981b8982bf8af544534a342cae07d45a8d2f2596e1a696e9d574bc82420c7675e86464698f60ed1f6d55f33569e1100efa506409d02b147e908bc9a0c19130fb5244774754c3cfbc8aa468e2b44aebdc82f9b6b35800d14ede3005b310bbe413a1362d69d35088fe2ad2088215410a6c89e830c54e15d79c004da9990c262ac49805f55c267432c9463957ef7ffbca8409e85d3e5e559d9e0a6d76534ad046754a947b5a656c6e415c571d49b74334e5d81c57c1129c22f924398f33b93e7394b32f8596992ce1447603cf42536b6e243207029821098507d1762198fe1bfd8ae31ef87a8a33e9d1f0dea5cd81623201fdd8f8524867e442ec6d173e9a5673d909c1a34464d92e15f8ff4db233c9db60b31f0a4759638948a9b8520c8fda14b2bca68f79242a28d0ca320ea1c479920cb5e321b41b970ef99df39994685a914689ace0360826cea33be8774be58e911b908628a10c84c2cd6c6f0ac23696097c7b478e620ea67261a2d9451acf988285a502b12f457417f0219944651b15c51bec3afe7bc82be02cec9f0af99cbf9b8fd96b6e8eb2b27713c51eecdae57358a9acab66f10baa955585d8f66ad63b9b7690a7a259237721e43d259a17526afb4408e1ff0009abbf4e4f580fb84ce4c8cf921fa24e08f8b915f281976438bb32bc9889055d124dc178d1fcfcac193307ea140a3572c132757381a3393597671ddaf8cb2c07c602a93666fdb96a8beba13cccf95ae31814eca8d1bc224df45dc1b952c16f70630e6efb6b295b3b514747ff6a0b53a2d93597bde907cbb6721485c2909e78961dda2f2b9659602125fe136322042d2ad1f4cf2d487116665f0a63196683ad3992e586824afcd0c937d703a243a18f5c1c727aaa4705d6f4f46d7d7af852c43df1ede75bd8a4fff547372d043014e9e7c209f43a3c914a3384314eaf39f7c638718d043fc85655882c615fea24f25950d2c1aa87d38fe45361bc4361ccaac83f7ca8eaa6ec6731cbb048904ad642b95040a9df5da13439ce499829fabb48b3155650e74408fb522476611ad8315778c902677ecc2345216a902363c807c1eff6815b738c583404bec026c81473c1b02f8596d97dd557a6990141cb6a6e56280a1a81ac6460d289fdb72074728bacb2849fa0b2252ac29b021222c1c69712ba7b7756f85954688d96d55ce1680e7c13590eb568c0c23bc1e2d71ec1c274835f83482e5b0986c2c692f008bcef9c948edcc4023eba7700880ae9d7c2b7634ca92273ca9483d46bc3cb276e3b3c5a51a2b9b12ae834d992895d5538ef8d2cbcab88a5ba8ab1fd103c4cbf1440a0ddc2577da7a4ef925d5aba63a9a7783fd1ea322dd054c135c0be948861ced9d9771fa7a055a7954007a5c585421f5e0964d48fc19506e331ca9af5e3b927e7120c2a5475c0d3aa85d19f4f0975748fb70d8d5b5c5756fa85060ef549b3ad9e853f5f9083309a9ea5f0a0c4315dde674042bef14b3211e4635d1cd211b31cd59d4888b29d622de4eccbb796a529aa26930a40bf168aa1bc6a1426db1aeabc8227a0a1cf2d58e21d0da21bb18fc25e5c0a96307e8b8c359cd3d9adc725f4df4654b544652c57502bb02f8574265982f518aa88d69567098b0a3a837a2d4c7fe7554bdf309ba160203e472e2a9f9c44b53394ba7a71261c617834d444fd658fc6ce5d11e7e309e682665fead6028cd6d55c4511330245b2542356996213773e1c9408411b8ab40c7405494925531c7d247902dc65f54e79d42342d13fd555ea98039b46faa530a399d85e1aff11920b9f89361669790e40b0932c6c527474f931466549f5e3a91f6f26c8c72c2519f03d1602451d7141f3b700b43565682a180bba12aa5272fe5ce4dd552fa7665f951e0c19e34d03f532529565e753c2c3102dea7f506419d6df101ffb1a45783e9fc541ef315bd4c44e12fb43b0d4400c7072a7ad0f02ed02ff7b9536b1f23743d697ab9bb560a8f25d8ba2589c7e222adae846f551878c561c50cd1255e400d050b02f758936d75cd56b6f76e02c9ae5c05434b28da532edba5d7bb6c8f327920c7e5682645fcac4eebe2f35423b0f10b4719a555848c175da5822e2a6ec103cd1946b91f723da5ca495ae290427d897228931499c235ee52124147ed231ec01bec247ae047231365c08975245cbee537387d0e3f50748f7a434027d091b6750d2b5a8b12f457467e2c926d8e6738baadf77fd55be01402ee01529996764b8d8a6b14a2568dd78242e0767b705d945a177a445f146f0fc6d242aa3266e95a5a2f9668f65958700a984b1bb7e6138724329059ade8abb599a4dd1acfe741c8a449c8213c1652a31a9382b0af25dbf25e2adc6d6eb87ce23a0b93a12a54c7bc08c82852402b8c39bd44041af761f256344ea34f17f214efd647af5da4221f5dd9160beadcd862b7933e4df56e7c66772a7a1e82635cb3e6c298aca6ab545c81cf731a545a81b77809b74b77a889ee262ca8479a6694f49dfb45df325b2ec4e55413842d171bf8823c3fca88a02622f7339f783ee28ec8de2055fb9a0223fb2268116aef8716d94b4eeabc37ca2316ffc2f033f31f9af0662b3e0e1d03b2f6bb7a875199f77fe5eafcda865c5235c151b1655c500e1065151130400be9be5419429f5c14246fe49fe3f6448220aed701f8efe677ae5a7d30ec3957e4c607e651cc0fa754b32938f8c2ec34c03db18511ae84aab2f5b7fae2759b73701cc912a74f988748621571b73e4764ab5eecdd87c09c29cd57153041709478ef00e54543885adce95b8dd44d1836e3a934aa9ca34c9efd50daf01d1e21cfc898d052b72fb93802b72b4d2e80b7857ab8d7192b406cdbdb0e49eb8832064ef76385e3ede94cb7907c47fb39ef27b79750d9084401fb34590a5b36b43be364b8f54e659f1da4e3e84e1169aa7dfe0f04abcec454d318e78cf10b893945d09d619c206e4672e99d99988f30aeeace4a32952f2d0616d3e6d59fd7faf41ccf458c677fbd15d2d14df6f00bccf1c55c8e8a0558c00ee4b9778039e05f718094ea8bb56600a91d073897964620ee78324219c49264201c1c3dd2e312d2a440bfbe1503b2820d799424c3db7377ff9b6f545d9dc1a2218d06994e0b247ea6f8e9f45195be99c1c92f65652459491efea9cfb8995a7c5d5c05e5edd9ccc6134cf44dd095a25c3f0b507528b671e421a88e08d4dec60780296c9531013a4bbde9a2343035d8c14839723b4bcca1da8945d3f758ecf44215240e20725136a321b7d2b840d5f1331c2a6587893a82a890458f2d36b6ee50c8f911eee6c457fbe7adf60ab5debaaa6ff81cdf1b533fd7061674071fc74a58412ffe311fcf97749a6700a18c48b3a380d909a79cbb4f615b4369740fb5368224ead171de83cb81ebdb3d884f18700962981f14ac585ae069127e395d6216d669d14af9ab5bea678aef6c30ad7a087bf76b388e9211171d56622de898f70e4db55b1f4f6873b38ad23679212d10b2d2efd079be90026ca7a4ddc9aa9939066d7d75846df4d5b9df081b9d9e516575c7b189a055f8ce988ecb6327495ee098416162735176765be81406dc72de17841770684c4b44b36c3fe10e03fe4dc94e2828f2c7bda22b6ecdfb263c88524f53b951104b336ce1ccd7f4c63705967374f3c62ef9d4793c50bd028bda0f7c06d450106f3b11699d7ad9e2717464c464e821f495b685677cf0c779f3d9b0ed27873ed1c0051c0ad12ac3b5a75c17ef9aa3eb62c40b1cc92b3b6dc33a64e0f1ca0ca2f37ca5a93078dac4114dea70ad31727b6327e6f3fb2c0bc0ad19a0640efcfed9835d0b7f1e9294aaba739e3053384ff6a74e1ce4fbe1b5a4e4aaff0af163e5c647c763a77d06781413749b18eb57233d36aa50a640ab95ff3dbca3621520a0ce06402d10f24efe54a7fa7a05afd7a8085a3fbf06314339bce83c9b178347d0e369bd84fe2592e909b105d45c2b0988f9a8f693cb4cdd06cc8e33a1640a29774367941eba86e466efef98df45497d9ebb925969b9ec43f513b6528adc2b1350c643972900d075d2b94b32d4230ce0ab2f3f9f878c936b79ba8c2f1777b40e62f9cf30ca3c692d37b5ee50997b6bd97648e08c3ebca68a12da7c676d78a4873053022dd9806debf776ffdb341aaf46d2e4e56e48852e36988227caf0f1e50ac95ddc4ab7ba8850e88275770cf3966011e39ab7fb0e96cad2760c0e407de65eb60e471aae89a5c068db6619c91cb588dac5dfe3f3be60d0449cf1f002ad008c45c825559507bfd6e3e74c3de18f28ab1ae92c9ebdeecad4b1ed82bd201b33611a9dc5ca4f8b28020b879833416508509dbb2a69d7291acba96b887767cc0123e496ee5f35bd90e56ccc096fdba9a41194e4b24d7a189db5a3f79c374b2dbedba4798f5defad9651c569611c057e01f20e432fc4e64f8a1724786a626ca30a303ee7e1ae8f4e630a96ed991047532c42143f063c82de6dc84a7b181852186feb8de19b6cea2e2104500810c200bc2671f316d8013ba26444398be1b1045f88368e60a595e6323d455618fe0f5b7b4f12007d0ae34ca44e5f234196f4c78d1f649184f31e27b840c39f400529c17872fdc5edcdfe6ccf8d1ec4d5b1242ac4569b9058111691c86e46b6de2a647bf7f15efd06f3186e61e3002aef646883f799d0c6ff2177184ff148b7aefad0f9c36662c6e0f5e174112a424235ec960efaf1e9e0e01db930259f238188e90ac0c5c5ea85a0ca349d885c39f643693a1916a287509540d6083188e169c6ddfbb2b7b1e17bd6bc8a06f32feb2118ef4df0c1dee53224c4f18498d629a92d098c9e6454d59eee7f405201e37a22d2938b0a08b3deca688a8b7edae1113ea4f5112cc040e76f954d8c0e1d654a484cae14dda8b4a31e50d52ddab5a107fcd09ac2292c4a192879ae7db8975b131408079cfe17921e85c05e92cbed36e99966688851950620d32f3dfaa3fb16961d9135a9919553f70f909bc67b01341749365dab254d90c3403aece61c7a5fc26ef9bcf03752ff4196281e4b84a623f6fde242e4b24a623aa3bdb80ad0066c506e7c481e15668174693b56845224ddf0e11917680c9b063514cbbbb18997be024824d6e87351d481f89cb66610634921c61f3d938494a0952921719f4f17c0e4746f11cd70008f13a84738a7d91df40a738e294ebca49c6ef14ac7c3c14d452fd78a561f02161a5c2067dc7ce91a88d9a0560f396e173d80277496decfc99605248d7f684e4ecc02e695a1ee9f867ae3249b2037af55908ac1e6988c06c97a1503f047bc0335f4301d589f6279470e9cf88ecbff15369b99403d7decad6a037c4e10a9c6ddf3ebb3fdd7f4413713d3e0d25ee07cba06fd7deee00ffc7cf6bab780a5f95cce578b0ec966f97e0d18ad86748f61a4b1dfc1f67468586864affec7e1f3420dd4c208713b37a73f1d83df9bd0ab679ee10afbd0987caed8ba01baf69a4d1933dc3f8cbc8045f8c06c942df8d8bf52805dd212ac0672e9f56b81c3c7c7e10fe680c750ee687078f5a89504eb52558e6dfda91939a45f6e1f5197217e31686bd8dc2241b9b01f23302ff71fe889e380d74d86da80175680d5b9d112faaa6d60c77ec6c7425d0885790ba3df002a8b7b52047ee20decf6fa88b9680e741adb43706218c495b6e7d0eb40185c489d96e1066903b2967ff9f1bea300e6763cc101065ddf260c57e97303d4d19f51512d1b0184e9b66e414aade722b92622e099a76a4da1361155b7aa325c5765b4e885d8b4d0058857efa8305c0a77a8f1b8af7c9e7e0f84ff8e2ab1a62ae655d209527c87752585ac1a1ac28cbe4e40d2033b58efaed0762ee84616759f02513daf9374364e1317870d20321b56cd8a22040363d0711bcf9947b885e1591a917da7805deab3d93a4a2536c91df919fba2a12c2a170daf1acf910c45a3c8e790dad672681e38aef2e5e7d969fe3ca7bdcf75ab91405fd419c123a9487f291e0f8114c7c2c6d42c58c93c7fdb0939e20073d8996aa14d6a68ea618e38ac2369e8ac3e9978110c7858d16075e1a8a2b535217bb6c32d4dec1403e67b9e606e0add511169fa8b9fe8b062e6a93c61986a2265d5ce905ab1be9533279f7e2807e2824d008949fc7b11dc27481ce57186d8a656cd587e2e19208e1141385747f3912f768d48bef4f1ecc9a6a0218408611dfcc0433fa8e4f6c8bf635bbb2bde638803cf523277439a7d54e65ca401cc043b43738b5ffab3fef3337404ee9023f0339d1479cf8488ab3d36c36f3efb7015269c35570f55cf143e0bd954fd492702cedaa15aa03b16829a61fb1a98d33386f42e09449e4deca7a9177969382ec4fc02e9bf0564f57fd536500adc6d6a7fcf7b2c8dbd6e442fb330510e03afd08ff7316bfa1b95e2a2bb843860c3c9f75f9db1e447e59d5f8a8d9f8771b92c2e554c2d4fbdb0aafccac96eae91a2e7e60bcc71ddb2a0fcedac6f92a58f95eeabdebaf7b25a5c3af250ca5ffdf11d01ba95da320fe53c462ce242be49b73e28fd6bcc11ad0341151f354cbd595a174b7513986e40f6bc4a3a1bf781e80db1bcd1fe692dd97ed8cd6af64da78ec6fdd8df7700c8f35df0d437173fd723b4fe29509f8334e550e466a7bc7bc73fb89b499e3628cedfe43fddee4484e1361a1f0c5efe2c4a410fc4a3cf0d40e3df0dde26eb1f286bc3738a660954c463b2271f9c5662f6cc93256a2c9819bd1dfeec67234bc9c7e490dcc9379b92f868442f45c95cd847d040303167a5569fafd713fdcf898ccc55a4d0df2a1dd204727da57d378a5630a50f30457b07e1e5600dc0d566a3efa2242d3b258f2358ddcabbf18f3f3d1526de1017707e892681bc7f8111ce752fa95f0575ae287f96d4441b40b28d43cf0d73f86fa96ce22696ec847434835276296e83f8305920d87d27738f012089c9e32fb687068e16b0d3f3418ea9017be593c439596a2e8454cfe8722305ac82108b763810e3af72f1ab0fbde1aba6e343875d0d97970c335ae0fca2c9dcaeaac905d3a694033157f6cf5949a0ed331782b65d8957fe466e777f8f77150e821cc0bb9cca83f7745444255f516c29ef920429e59fd7e489edd926da2c574bd4121ab621da3e2678289604df113469f4d0fe1ee6d20ee1ec680e268f7472a35d5e89f9585df4734de5a3fec6ee8df9589c5dbd1ea2b4c0cbb6d1c47c14a165d95cbfe37df7cf189112524e08accc84e671d91a8e01728665af17525700e6239964708878d5e992f497bf769ae7974638d8afdb9c87d08de55cf17acd2c351e3c0bdf1846bacf551c988f5272f958785c8d27516336edf68f9b77e472576aa7e992549fbb2d6c35019e1fd9b1bc94e707fbffaf3ae09c6f67a62e0493f5b870f404c3844bab8539eba0dd87c7a28ceadaf803182e4071baf78de08b1308a1e05b03978cd87043c921188320685c87540b54c3f05f59fec5cc9b99cd50ba7be3654c44bc499434cd6a4303356616b72ef7aa22632b89f8bfa6dfdd6b7cf5996c2234f5b8074d75cb979a721787c5925617f9f3c923e390a685cfced021df64b57912a8d25ba776408c910cabad470fd61fae00116aa89d8239fb43e762a04da771d6733747551252a4aa236dc9f01e858837088eef1e08c7705c5ad761d2f9a8a56286aa2bc72ed1ed2dce4d492ec12f1d23c53eb5956cf342a72bae7c99cdcfdd6102d60d80a38940abdcf055244419f870da8eca1ea11832209bedad4ef18c89d16f63da7cce9bcc1a1a37d074b59da7513c76ec0ade0cc492f79822eff6fcffc5670feadeaa11714f6b8eebc134a50de0d40682652b420552fbc9390275977cd6bb9c320709a75397cb571e9efaba3b71cde898819c5db316bd92c80a40cec909ec7ea90ea159d2bead911c17366094e54097f43dda19bc9e74b8236651d1af2497aab72f9636d5922bdad5d6f242bb94f006a476ca0f8f993865066da6902b351a94703f94aa4392d44ab8d3562179216f3540e40f65666fb008bd6f8a514de54cb5f14d73d26f3363c7cd53a94e020ab0777e7d0014508985b90f6c01ba06e69831cb983ac162ac47b68c68dd2d4e7fbb88f3455fc6ce098b6720d60cfe2334abd41d4bca8f75384b939eac3aaacbbccb3bc95d7bd7ab454a4292926c0fe785b689bd6cd2eefa4322773e1ae5ba9b052e7b3a0f48bb4ebaf49c0b8c983601d9165b49d714be2f2d98510f6b449e3659280e62e4982af3367d2ff30e8436e7e3300b3a3f4b425f9500406577876e6930f6d18c726b9d8f8d22d581f8a3813376b5123edd772b14e39f9714c86af11ad7bff210b4d239a98b8659fd9038c5a074bc8108ab15426e49a7954a49ff86c74ec6340d3060477a3993cc893dc0ea4a762fd00842dc1af42aeb0b4359f21668547f75b0f5bc880ea5272e4e6a79b590c728451a685e0aea60eadf28c804b1e891643a966d2549d198ad31f509552d781310961760b3c0583aa39499695d29e27505818cef43edced1046bb622ef682bb1be7dcfac4a4d7f3c933e4f3d5c297edff7219bf0d6b1ce6b6c94aa067336e6c1059f7d0937e0a35bf2b211595bfbb42989feba63890a43f64a56853f6ed811e35ccd12fb5e1b289b2e1d111c6a3a5efa1be1f80068b4bd2a8f0a5a1c1a7621bcd4183a50a51caed22a8fc02f8a42f1bae331ac535ab13f05086efce578bb085f3d978a3b39930b168be3418fcf119080d098159d3394846ad701187b45c0130c2d47e1f0609e57e5f681b044a2eba5f043bfc0ff53287eec3d86ff985c087d1de02d03f0a5abc3eeea31079fb1422daf4c1d3f756a2baff92da74d97d313ca2ac369ceba3690f181094bfe64b36202c9cec77c696286b9859aba685de23801a8f6054a9856c7ccf0098d6f1ffe67872e1d9f2e18ab64aa5e15d8d5696ac7cae29e80a1bb254a9aa164cfbd91c54908c6312af94fe94d0597cb9d241b1cff7c751727904da078e611b59c27ecf3cb8ff898e2dc83b0af85e9ce4de3ccb858618825e0117e58248bf0611f444a829da9ddd82788ca3e5cb35628a19b9d7a811338aa65cc1c8390db51fb96fddaf04f8cca0265c0cf02ee1ca5a2d87ea77824bfbf7e88ea89ca7ade1dd7abb980da469f39fd830e6ae886d1cff107b380023d81b10becb6a5b2ff71e6ac409f8c320e2fc4f3b10bf59315dd8f1b7d1c4a0cd1422da9cfe00d3d0497307c79f7ab812c4c8ae21e8a06b499f6da30430813c6c9cf1a44b59a3ce2ffb06cb70fec10e3442d9c1d0d09a6a715b5184d0dbafb945223756aac59e45951612bd8f0b7a50e583e72a0b1c6d93df7ee466cec762ccd7df81d79709c099c03e5a6ee2b8ae7dfe059ef8447b424f3f7224b983208efea19d7121e89f6d078448c9d54d289ff297619b169369507ff6180dbc1af78930110446d243b90644849950b619b029e55035348b89f52fa5f63fca68e3bef7e9dead2d364e75c185ca9cf137ff8d3b4d773a913a91ae5a906844513235e547dd45aa1ef7721c3a83df591061e589b8721675e199214595d26ff79f8ef296000c68ac7d76884655a9765555762a0e6e5089db167a3a08ba68998142f2cd29d4c20130fabc71be887a27a9d46278187b887107e7a2c3d614c34b01dfd67a93bf45cf0dd25fc96375e8932e69a36ffc5c34123aa4b707a5033c615cec4a4baf4da71d495dfb99fddf5f65c65feac67a757f650cd1c54bc0c2cbaf38c5aa04c5a18adc04d8f017eccd45d9534e7acfacf6f71ddca1f12bd0ce1f066263e12a8142a67bd23e17d5241fc59e6995bf85f987d8e7b4079760e30b0c7b153d7f7680de72497a7f8df07458d89e4cc7a5a0267f4e4354205c81a5a89a91aa3706413c5e37e12d404f386a2f6a23146238ba02e75f03daa11327975ce0802996a08c2a970ba3d149e01b6613ccae611d232a8d984bf94c6d81bf4500dece3270f87b44e2b27cdd525886e7f536ad1b3bb3569c4ebca0978c886551050d69adf0177e55d45cb5be87c99211a54d6657f221babe56f6d8dca0a4e9c7b299d64beb2d7833db49193868c6549a0734d487a654ff426248445d1439389303ad72b62504742d9974770696bb4cc68601b05f14b5e6ce227cedc1b6fe9b5908a2702fcc18d5e19c0b09d2cb0d7fb0cff4d8df3cfd0b0d2f1dbfab2d0ebcc763857a81327bc5f6c017a03e02821cb983787f7f724baa992eb9befb445d57b9dfde7f1015d055970cc007f18e9fb2eec33787e3fa487d51ce8a939008ad23cacd04431896fdc750e91a7217ceb51022c5f9fad59a921829d74a6d957b877234be0e81f984a370b45e7b2cc7edae2990f94728164c718547a1f4c90903a93a5383b6ec4e943fe9073a11d3b90b7752f1d55b3a09bc487d56ecf29de2562b09047cb3660c4c431654fa9b145f4b7916483a225fe0598ec13f454d850bebcbfeb8017c3eed6faead293c4f7c7c5adc440b0d8712291b92f3a572d425973fb2b1bc933b806ecfeb410b328099eca733eaeb1e9a9b2c2b9a5e71fd462aa655f5f39872ea418eff537184e5fdb1c98b9e38015ebb9db844ae00f0ae0ed6d31deab545ef3f5cc4d6be6c9c1b6cf755a7693ed56105afd775dd32b3f8a9da493ca6be3c4fe4af2f0457b42a02ee7d8389b1083dcf648bfed419a087d7ca3b52bdb0386d14bde16c2241bb29e6103015c424d52932a39b3461e7218e39fcac86e8c00585a5766ee3978ef94a3095368b08b6be4dfd4077b8b86fa084d843d60fe246ed80314a93a7068ffa1c1ae7877cf7ae53a6cd0be0295c481b646feefe58100d0ba63f1bce06213488d39ecc8601a7a03e1cdbede299115602f1879028f7a23d304c8a2dd00d849cdbe529c0fea7527dfacaccb7f6f33e512695a66f4902e74315b379890f0d84ce56f97bb93ea73ad1ff10f248b77f9afbc2c29e557c85b7aca606da8e4342f9151311fffb521dfc39212a8661da2f2436fc3d78e7d72a2ab8f5402fa6f0778ccae932f1f9d9c7f1335e5f77e20795788f07ac98583e150a2d246a788c3657b8e529750e80a7b9409f456cdd6b6e02013b166115805b465ae368eddc5e64f1be746706ff7ab7a39fd32cbb36b78e63dc2f962669ec8d33f9f534d89f386717c8e1144b604cfac02fa1457e0f45b637efa851767723e2a7016394460bb39bde47f789765bbe6014d8028836a6db73f20226a0e3e8291f49f03a79fead15f1095c82bb7ace0c6b4f6828239d1f3536dc41ca0c50579bea05a5eeda60a03c6a3b06d4f2ee59dd500ff921acf1b75d53dc3e086eed0573479f881ec8625e3ef1fa11a2c99112f3592e14c6ef8193408ce7ab4dcf3fdd7ea75356671a8a7c6632ee76eb0dddca258f9b5f3ef13137817b267db96a5b93956eb290866eefb8ca54a6fa7915aab33b1290d53af4d9e6158daf4679d73de9e172e5a3978149898e8dc1a5786f913dd07d9052e10d2feb738d73beca989e5b3475faa2fbbe82a20dcc84c63d13c902468dec516930d29af4cd2d818c7b995e252f44389cc6f31ebcb2db93aa54e7a76209058014ae8ec4a46542352ce99ab89d0d102afae87d5251caf83c16b5e573747d8fd22a2ede277e54e0b6fb1f1863a9f6395335c904004377bdd33030bc1c433a599c7c07f3ef08fb6a9e05a7f626b40cd534be8c3f452aa4bd78407861246d40b8e604896634bc6cd7d6ddf5195ef96d075587ffd7eb3558eacd8335b6e361764a151198013f82fa159d62e7fea45dc7b8583202163e44ad187d63f88d2306a92cd85b4a7ec4224919117752ebb12f4ec27b1b1ded9e294654a620d06dde0b530d9798d35fac0b5768e3ba9e9f7c6d4ddfdfaaa858dee1b83f9cbe52ae03917fdfa8cce36ac08a2c2477937c666c4620f4b2a15144df5f2ecfe944113d59187f244d512e3534cd6c6f03f4366a1350e2b6e072a23164af1bf171122e51b5d88815bb3f5f59dd50d2abe3293fc3a9284da9edbef276033c5a579b48246b3eb9c74c7b367dbb2ae04a445b69433d2d93bee32374b2d422f047422e99fd135370f26619870de4ff4bda407980e1b06949aaff3222b26b8c3b0152d6badf2677aa34d09088cf2760d5349f9a2ad52e4f9fbc6811213a37856901dadfd2d76aa9389e808087d3f4c6c32ba5510c118c1792ced9dad1622163232831f74ec24fb491f5c15327473980cafddf629544a793b707653cb5410d2ecbdfbd3997936b0bf5b2baf78572d825f9ba9514f15a09dc8b45d5a912faf50d3ba64a0aae5164dd82f3931974bacd7441e81488888dc479d3fd6a913652113ed40af47fb0b01840eccc0b148408c422ca1080b6e17d91d7d2b5a38137722d986cacef250f7c3ee28b2c107a418516feb65dba03c9ef55df91448189d2d26d8386d3b47fc4e44ff173f64d7586dc513061b2c94f61a28b8bad7a9845cf1c3a3c3399da4b3c0acf6452b6d12829e1d7036e439e812014facfcbbbadfd384e55d49268bd8573af5fc432047d9b9cc58d585fa95d38b3ae186a9958a8838dfb88281a7eae4e3738c6ffe9a0b8e02871b1a828a145b10f0ded4493ff117e68530679a73ac25fca2bd046c662a7c3132eff74ba0d8ec2255e6944927010292dfc7b738f974cd406b8ef60b6660ea3cca37c01f734bf933917ec41ef9f1e4affecf45511a096e98acae23e98ef1fad305e4cd69126abbc8d336e82ff6f0f77020cf614da0de6e3ad417ee263950c43d4ee14923734956ae54e3ab87edc81f6dbcd4daf305ef3a17b09f2bab481deff484eab613bd35c1ffaf8e95d3c23f9f0b5b72010306ffe553c025d7717d51babcd146b58f67c2a9b4bfc89ac98ba60e0c8e140b67b9768289271673269c3f26c3a6e248d5455aacffcf4f31f09ffc5d5c4aaa870d9e9bf28e7815168b0cb36b7532ada9eeacbea7a5e0350f5e6647439d617651949dfb398399cc7b3310db77a66e3a76c1e8458f3495327aac30fadf29821b4699abf2366515451bcbfbe931ad0c1ceea30fed7928e86649eb6c32d000156888ac870f8530b16c87a9ef4a074e11cfb06c28a72f8d670fcaaffba17bda3e1fde1629d3395fe737ed3e3847e69e163bfecc649964dedc51a690d73372931caf4fe7400459e816406639a023991cada3f9a4bfa589f06471b12ce9743630e411895c525dd57aafb0ab0fa3dd81a1a454559c0397dad93927fbcc5f018859a4cf8159254e641a79c34953c7c190c0e78c7fc24286ff49b5e66a179e6a1ae0b5d31ebb2e3d85bc03e9943eeb9eae73a07c0040604a3435fe80dee4263f5cfddd14a845ef2e14a323b5aef851665edac7e51b06d61c51b84f8408282d5db8c1867b13573ebe01e71670562aba707116ebf6391bd416d12457476319c785cc5f9dff515f50d91ef6bb4077e00d5eb0172e40ee2fdfd859a3b1f13404c52adab33da43891145f1d0c5f2b10d76e7ebd3f44710641da9a22cfea393720c46667f8c012be60645e9f5069ce2d45d999a2eaa5393509f4897deb34bc79b0772535a5206dde6b0596bec71c17cc03c77ae2c5901fe5c03dabe4fb2fa0edbe57062eee1b980754e0c0f1eabad72a6032ccce49492504f360741df46abb22f18fc3a98f02a9e7b57dedbf205257e2e8637244d5285a376fcee4edb1ab484883ec850a6333e9a68c006900558d26eb3782ad58d55fe8afe429feeb7da3ab210713ff46fb10c75404019989d6d51bf86fc8ca695db39244a2bab9679b91b4986d62fe0faf3c5c527952f931d76d72f2078b495b6bf5f91020e5d97d6fbd3b1f049f2df8f95553d0db6f860aa103045a9538da69165a532078167a319a50f04816d9c64ad08993a6aeb5a87fe0de93346c204700be0329aa6a0a85232da1f161e2f059111709b0acc0cc70261af5ef2a8f2e2a40bad42e9683d1d91f043038bf158b69849ecf64050cd1219eb65a49ad52004c003131a6ce439203331d9e7267d334386b493323fa39edb9b8a5b998464f55d0034a5afa005fd548df37f6fde3d9cf796a17c2a4dc3519bcd5a51a454afcd691c31873b3629f2144a6fad692ab51397771ac04198c92650a02a93eca5a193c3a6d115abc02582e8000a9ea4952f1583a42a554d81de55184c5520035c07e8f68ea9d610080c67317c0f08318e754c106dbc249eb082f568c72669e5235a8571dec89fd8730012275c3668a3ec49a3fbba1825be3261ef51cb417c1113bdfcbf2819b50bb59a24df0067cab4d196896d3ac1cc42aa878aaaaec4ec2a1b4851e8f8de03b3a1ade6fe3193052fcb28949dffc086961bb2443f9b7054986d200e9b5a6977fcc1c3d83d36c64b05307cfed1add45b8a37dd0619e455f32b8a65b7abea5ebb93bfa0a4bc86b443fd75034cf0933d7cff79fa35e430c4043ec46fb495d2fd4048727cf9dcec2d6d26746e055e61471eb2c247ece3502b365071b59caa201f8de702e57744d3b339378a8e03d28c6658e6fda95948a17798e46234db55c67ee47be9d5cb0b500624f6512c6f07b15005b30d42b5784c4a433eafffc53bc0a365c4e95bd250b1433634621a62799c0aa282799e443b76fea718f056dde9bc675145c16cd1a46f2d09a3ea0f85b0c618c6b1657bf68be395a132f3589092e621105a6cdcf2c7185e7c749f020c792ac154776a872d5f7fd07b5b07362b7fb31696db57d28537fec7677308390bebf1afaf45a81998e39113c99dce608f75a2d194c2feeb0a17eca79c76f837ea4e3747a7d83097e9fad9aeeed6fce7f8c347aa236a9e46f091a31c7818c2b673683ebd8f2660d337164a787f8b30425310825bc8cac537a30297cf9e19288f4d1a4364eafebf03fc9243cafb6b82a723c176a5b8cf6fdec836141fcce2b026b7aadd8a73a38a8f729be5dd85b275b6c9ae49db02e40a36b67dfb054c63a4ef4f8bc2a5adbe4fd0dc8817fa2cf2a27d2675b662378b7c7382c79d220acb698014921acecfc7f510e75bc3efabe8b41fec5262f5cb5968e1384884177341cb0bb77ae87d1ebf5d927f4d4a38b2ab83ee72908c975c5730ee90730e39c24e99e813610928dc543c52e3a6a670caa74d9732825fb134ddf92d2acb66d520677e83edbb76a370d5767467bd3ff7c665ef8fb643379d0346bbdfc6b1606932ba9a0009097cfdef86b2be5a4b36316c7e3b51dcf6263988fec0087505bb11e293701464c29f73a0ef4fd9580f974b932286264fbb18b4c7423544e648f8fdada26fdc0f44132ce8d41942e91dd1bbbb1d92098af8cdcde8c6043589cb0a3bf6fa0711e097bd86efd95026c8845acc0a4f387eeea0e7f181c9d25d289b9b25ddba494a1b82979d3f1eddb91eefd707d0fb1fedfaf80c36e4992b16dea9156a432cf39aded7b2c3e9284476e79ffc812458a30393ac2d2140214690ccb353497bc0690ee13003b2e83ae6ab72eb9f2dd551f5281d4f317967000f1485125165ac11e3e8e5e86f6e9dec8ff1ee2d422a55ffe223b5212e121ddc01490078aa62c11e4e15218d42ca913570c90f40766180a5d4c55b8df9d68247207ebe657ba439e62803d68381328333e69ea51e888da98486303111084184143ca79f2b049d3b0a7f51877c3f1497ff6571861ef6d7d97e986aa517f65ecaf04f9b3ce887e99664596ad59636af85bf2adf064553e4ec92c6b2cc560093ee24f650155bdb25ae4086e63117c6d8eb48855ad0c5df7083a29a88c5884b0f0f73fe927be66fd2c2bd1b07dccb416d0f64ae33246d1915ad97c20919fa7f48223bd51f7d99d728879288faa7f31a8d25f5c34c1abf7962dddd0df425e7a161c6f880ceab78cdc3afe2aa1ccdb0d7ede3113e43467075837e3c099dfe2fb02415c164f288e4e6d4004e5a5d49df863384f15830df7c2f2a91ec8fd16ee3a712f264235023260139ddb0b5a71c895bf6bf4840156af3b93375694a9478d9617141522d6565e70375d427f08d34d414f6bd5ad73cdc650e024832ff14468cedc40f3d27c39348487214e41b27a0b4e3bd7d288a0d36fd4ee37b8928bc21f1fe67f4cd3f45f68ba3c1c99a0145f3b6d82d766e47740a5b001672dc948ddcc5e7bf1aa736e649ea07215b956cc0802060ba0d7a11f7e64b8be6f6af1e698e13d92ec3d412e457bba947855074a7038ce7ab4ffeaaa9aef0a6d08286bf38ea0e99ec33c4e10a9cd5e6c0a4a10383e1375bbbe86a1b7f89ff68c1105c437e301344af8fa8316fb4123be43253c7b8a9a659a4e3b1441632a056abafd921c6ee86c58434b1b72e710795a0491fbcb9659b2893da318e7594fe1a315fb9848eb922e9df132d7d49fcafb20a17f6af111f1d21ddbd5ff24284c49f27acf4799df6485d19ef693072fc1e2231bf78d5abac124a3ff3b24255af6a9b27b59f10fe7c5afd4efaae19751abfea9102052500b092250f8c08cbb58e2bfed362223712bed68e536938cd051c7f818e7af90e2ce04080f9460fbd1912798951fdead2d6e7c43a51b74170f163435fc0763ec1e94ecc93fe60fb599e180860f9f63451eff2d5c1c8509f98edfa64aad163c470682cbabbc56490ac321e756b125cf744695bf14cafb9fe1b03715ba50505257b0452c8bb127b58b67987a4592f037cfe1fd3104ab05ff60d9e26b3d1962715e12e29494eb27a8105f5af85d3fd5f1611445201ed3f9d5f2c27a3b8795193a95c625ac37a51ba21593efa01322e1caf7fdf969213d2d65d37b03fe4caa1ed77a1377a72ff047830a483c380f41f2a26c4020d5c2d62f7fc781746c37817a8332587ffe19fec75402d66c45277c74cc3dc3f6aa9e45e29cd92c764b986580a93121d87a4089bc798aeeb24a9eaa81dedef5969177f6425a7aacc8422c36dd515473a3372511c27d062ca39e4bc9185ae8c06c787f9929d7cca4f6a54b5d1ed9af96492f34b20a68597611d4cf601aff8514ee06c200369d4185e6e5447ac20d5f332dddb70d7df5d185cfe88acecc22f54a06728f8e278293909f3443219bd3cb0f2a0c5d77d13b282391a119e5b7bf497f5eb464c72c2cc880549e69e73063b29a75ceea5b3346b56e4b97ccf3091a50fb5ddc5591d4096bf383c19a3f79cbf7e1083d3525784f2980f6031c309dd895d43695c9b546cc524fa230577946419228339332b60781b2e1a656f69a06a13e9ebeb24a20586a7bf2e68c2f1727769c0ae4334b0e171bedd19e9c23907de90299341bcf4fb43e179f6661c8f191308af768e71833dd7fc12eacdc8cedcf9e428bdd7f5eb187a27cd22f52553f9a72f4404b43483d57c9868ac413ed35a6e1ab53e6ae4021d38386e95ca47de3c1f6890c7b6d8bb3a8c220528cd8a7eef5cbea0fbc9abb96890f8edfa13c16423bd507695e914583d068a760c66c84a3fee348874bc0e27aa23227e13afec9726280164a7133c1a1d694e73f62fd09ee0760446116b44086c73e02f5d2dd8124bc527d6bf779793146794a92648b8f343b7538369931afcbce0b5e34c9eb4d733fb087efd12598e2b70eca971b15a44383842b9c42f4ffd2c58245cc2cca41b05a5498d8007eba6280477be0e670004fb274c327273b93121f5af39ce0d1ed39967e69b50b20cf54f36d2335bae19c4cf7d7041aa93fccc9f52c9ddfde5cbb6d577e0e23c641c74ac6c4aa530211e631a97f3f7363387466e4325e07e886d1d27f5570cf239e3e0ecd6d029e2d6825150da62cf74065dbcec613272ab08dda2d7d8c7395677634da7abc02afc42aa288ff52a5e036fa04460842351c68435187c74f3e7921c8f5177fb6d79f9d31dfa704d361deb35be8e19c34f809cd5a1fffd9ba68debd3dab4eeadc6c693767c1fa3cc82db0b630d22cd3b57eee93c2d2524d0083eeea13dd0b6f83b1511bb98d015779f6481c751d82a2bf9fd3fb32f24cd34c33eb7c87ee39e4ab2a6b873a660a08bca7303fc53f520c72005c9b41f6697dd3f34663a647dcdb49567c6a70238ba209f1a05268dc0ccec2d509b33e4b47133e4186de9de8bebeb9e8dcb8cf98b6bc826f631371cffa011f435ece8b3c4d2bf2f2ee8cd8147c3a3c653d61275004b9574a9935fedb8f93862df2ed5a0ca87c2a0cf5699be3026829722b6b6975f8c37f7aa29c5eb2bb03a5767b4b4e8623f7cd0f601a284f21e818ea5a67ac5b7f08d7e3846779602276f3541d82e6c125fc0bc64b9c4dd5c09c40372f864e63eaa14ca109574f46896e99df53ad4cb9bea7a4ccc265e3405ae6b3b54f37b38d97811c484a15253a90bbee1e2c107247d7f18bc03af5813752cdba6a38a6af479b3c6ff26550d89307c6affd723e56e44d4e06d3fc3c0675f5d3b2efe1a8d3a1a91a4f4332d8663672b285709c448725188025d7088a97a0baefb36e43c39a9ae4e5cf3b3d71370bf46f3a35dd959885573cbbaa5f5e4bb7d9581733179e65314af269701f36452c54527772429fe1f643fcf498fe1b032cb307c68d0b3c8bff2b04b8db411880f02f16fd287b6ae8fecec7b3a4326cd6df49533e985e6ac7e66c384d846c92dd353148eed7ca65b9b22b3e0957320c995f9a742def59e6f59760d9a00cd70373cad8975d52668f25b83a7587e71243d21568f7e88c5da3b04aa50aa7bdfaac4ac75b158c17d1e9837a5e477d48fa44096cf5fa33b28b80b41fa331ca713a83c79b88cb0cd2bf84bcf889c3f21ff9d2691035015e803469a7107a54b0e486d34cb8d896e132c2d5d5ea10bdd20ba710260453c3bf95df02b4e87a5adf95ff31bb3e2d4ee3112c6405a8a2405f5d56b76e34e2b663fc978545a1ffd8fcce7bdce350bbab90f7284d19a0630e30e4b89ed344129eae8e3589833c9a6dee6136192e8b0e895c516f9c17c5eaabecdb737c897ea22215675f8ce4e464b66998bebdd4452b9b02c76002f0cc267cefeb9965038ed50e7f82ac22cf68753e7015bbc66c4eab85fe8812876b100ff20257561d70eeb398e8212fa719cd5e68d849bf5e7cbc090f95e3796edf84107d433cef5156cb66e6a4c4533c4640e3a38221d58307dd8196b2d8867bdf97608284711594cd52dd567119deff6fcc128d396af7332161472799629e7b6d98cfe400f0d4de2edc31671f3c73593485613aaa6850f023a211a4df08fdbc6b676a340a47f7df7cc34e1f4c250e35bf14527ec7ec859cb3e61104916ee339ef43db2839a8bc54906e7a715d9d57031dc27c8980c48f004f42c9f7f743d8756a12040412af7380dc82acc1046b4a1bee868d6603a9bab18479fc3391a0002b6e210f96431700c6670267af8a2d619c2dfb26d970e9f1eaf33fffeee0538bdaab15345f6673d84fbf5e69d5d9c0cc8e66b50763c8366e51388a5df3af0f351ca7fe007bb5947385eb4c557f5b7dc9bce8e2b5c910659bc75ada0bad2f3e7aa430237d3ca5c521b550ba44c3ee0593f32db45f13d08e014536ddc1a34dec0269e0cc58cf5310aca0ff729fc22c234bccd6d2820be819ca6028115b60732f51dc5ffccca8669b5c526496e94e6ee7b3a42a49d17a7760f3816dac0c58c21488b19499758d11496be2cbbc9aa92ba10a7bb30dbb0517af1892768c95d84bf7e0329a56a9da977fd4b1c2073eb221713e25f62ed83af4760fed5fe88baba01aa78bf26023325eb2cb830ceae8c702e831cbc82159e6584b432b81d5ee4bf32ac692b71fd53658f67066be564662f87a557d70583d680830e9a0364c2f50613403b5e53151ad0576735608c376613104ff2d2124281a91f793b32965db6608ed2307c577b43afac73be60dd265dcbe5ce3d6911fe52804fdfe9820e95c5230954c508dd50b91717bda72d83137272e44f2a0fc723dde7bb34de5f0b3c1e15366bff675271f42fe5c4301be52030ce8615ffe15efb37ef1f26427063bfd2d8fd540172051b1faa8736f441c1ecf3614580bcce21832a65128c88461625f8762c97b52bc269f17576ddf0b5c906ae895355337d2888810655a0396db8b5f50e32bb891a0595a66208676eb4680e6c76f1a12326a770f283e3e12ffb7c9910257f9bd52ca4c62a976c64fca27cdfd6d821b54e51ab3bc3de93f7f41a4e44fb6d11fe81a8528e29f9261e59a9fa7f553234e7938d71bafc1de8110d2a94928853e161a2d3841c0d09bcd57b1f4380dfc7539c1c87c6693c86312aa99e98d04b0aa28068b9d0fe049e7b00b1c313baac65b1cb7513e1a7d42fa6d4fbc6069b55a1dc6e3f49dd8b35cf97bec583e96945d7977d98c71885001af71807cf227c9e07c9a23b69727b82c2692aacd854b8dd6a2b7630efc634744ee9eaeede0aa459ffa4cd6cb539b5dbe1cad2fcf8bb38e2a7b8c44faa9347b2e5e1f37df0bbaf99e8d1befe646e60d54a2e3d67f23f3cea48fd52ead174e2402262a2a416d5c012958fa5588c76f9dfc7b1d7de3735bcf133d2c3c7297ab63d3ab08911d83d99a7a084dd8d6025edcf73af8a4137b45167cb2abd42738f9279c6d3b3b55dec101c7d22cdbea88dc78f64d0b6cf6c4b3c61437c517ce55c2b2571b8e5f8fdb9f9abfbe608308622a6648ce6dd9977feb66559d341ec2e3ff62723ec88381de43681bc3afe6d4d264800bf0a74426f77e2af07ef7ab39616603b1a696ff94666fa9c78b24f8ef3dd1d45591185a8f5dc6bfb0c32b2bd89986503661a0fd6243aa245fe0b2be3fcdc6f4a3c2e0a492be259fbdd2db90c7e87e0e24c251dacd88f356682c3933ba71ef1b0bbfec29102e54542ea95f8f8c50443ab666e6ff3ef223e9e52b631e907a171357641331f02ac8524e3c5beb90aa626dc95d3a08390d14d277a5028c779b38f461ae4acd18da9d9acd1f1a53781ea91a720895190260c25ad470f1b8533de1c5d334bec892fb26489070e0cc4658fe5799667e8a02bb8172cca37f5a70f0787907424e4e67cd538698221c525ccf5d00056e5bc82733c2170d0e1bb4d7c22da917e289b060f026732882181d98724334ce427132dbe10d08bc6b816bc69cb369cab8f9905cb2ab54236a3e7b414ca6ed38a911f0216bab22043d2cfe6a3668930c5d3dd99e87774f02f4e6465844998b8fa2590d82f9bfcfe826d9ca59d0ffbfbc180ea74b3735baebba2580f6701a26a271c58f8a5ccf0d282fc03eb0f4df226795600d27549c7e1f3e2cf08c93b3e5f0d1476fb45b6d6024b371948dceeefd9390028c6e8013fa0d24c50c59b204758059e64fac9a321035f4099aef8e9aefee0c95571c90d6e0589fb8da8dcb0618c910e7ea9e55d1d822d31357107feea9d5c876d46bda26107fa04f8c9eba9c2eaa6770a6ac3d6c99374941b6ed10876d515f010c82a2296865b2256d9b80e7ed4e65cb31c247b547771388311c0798039cd5ab7c0240d0a6e7101fb6ea418f7f04522f1c5d65beb7ba8d3ba072cc066ac61dcefb6c2854768b9c61eb2d7aea00b90de7ed8cd5ba818331310a1b2b6e1b62aa36010042c2c62d59aac8bf6d53c75878f9899f5ef10c261e4491f544964e187b82aadbc63a65908c29610bc5ac891be6325423ff439f25bf4e27bf1ef63a9390e3fff644b7db3cecfa2a4717b7fbf7a3dc0490002051c02a8f667883d6762af355f2c5e6d05fb60c9b9c625832a9839fe86233496c019c82d50ec1f3e2e85102325f6b84acae26f5983c5393c8f2f861c894808739c410033b4ea5d54c38429bba6244b2abdfa74ccd3b33dfb8b9b6906a61b009faded17d8c2a66f88a35a727093343c009cb89160c816d5c25a43a9da00528e6cf1991d6865aae468d9a3b578b192d3f5bb825558d9cfb0e1fc15004ff2d43ede52574a58ac36ba5d06ed0e06725cd99ed03003e63a892730e7f77d7b3da07d8264a0b01a55718d5858d5b8bc5021c6d6231cdfb6b9e848ac93709934124590c8b229202f524d37b74fab820c0ad59bbcc9b80a134fd68f5332f99f7ae0560f729c285483383ce4a81a53d930625570f50ab58a91bee6780a8dcbaa28b1767e80a10a52f69b299457df5eecacd23a366a64905f8c48cae4e63b37eab0cdd8d64207d81dec198a4bed71ba7499fd0c1bd3023edd524f9dd261b987039ad1abcec420f313f28a03156647dda8cec55a881ce7a4d66a0f2ed2eec2e4205bbf1aea2e09cbae81eef70ce9e4877d331cfc29c0561cc359a69402997d0d68db9137b3aeea5d19271e877dc2b7cf3a459fe0bf46600322e5adbc5188388ab39da37dc67a32825f4cb099c3c6da9c85a570e742e419afaafbff4e1e7c459d7fa8993e2d00037b2a23705912f27978980e653bc059e69257b3ef721a55807c6331ca64bd7e212c5e4f83935e2adb3fb6af8675e462aa1970c983bef6f0a0e0fc4f39dc9a050ba01b65c0ea8c512807708003df991d79a7f4b82913955f958468b7c669b02a1c2d164e9e140f780ca8562cc98391a710ad55291415d66c648cbdeb0f01c40778149fc95b838e5490062d0c3effbb8c54a61dc9ac6630c92c5eda31c516c02dbda46255fc964bdfec21a6c3ac89ba1f2621f787a497db62997d9fa58e9be377bb6b1b7cabe65538563d5d3ebaa3062dbfb38a65e681497509beeebfb0e57c2512e954ba54361d44d94e009b3bdc33453661b607ac4028a1787b90d1f785d38ad56fddb0c775280fd9bcb1d06e721da03e60452c40c1019cdac2dd43fa510130fd9b100047ee1329e305d6ded7627b091723f31fe1521a4d290a128ec8e35056011cbeff4aae3cdedda1f91160fa67dfcec05e0c5c152ab453b0ec3b3ffb3ca0ff1df165f49e8ef60136f2ec610ff0873a83085c4306885789bf451407b3d0d59720d58bf67cd8a11a577bd6ff3c70776864009255ed5977e564139f06befbad996ba8f65eff998628ce7e8ce206a0058a247b8160249968ad954005772844f664d3e30573c4ec2d1482a19f78ff1305f94d77850bf542b6c8951d23ee307a58fd814d48e98bbdf7c8192a89d44046a88e99e45568a90fd07f366876dab7c50023eaa6170a9cf98e134e403cfebb322cf9ab4bbcaee969bd033cfc513b6ee2c214a8a53fdc9e4fb82bd4d240c0b658dc2099fe3c2adc8ebb7cd3b70d25278f4478b627b298e9000bd748d6e6a6a4542fe4297d4cd4286bf8aceb23c3bc869c204760032633426ece235f7c434fe06f644c4cc757ce232f00d635c8c71d973da6b360723f92eeded639eb229b6b7f95093f0e1d88a31b6f28dd3e3e3e6d234ec3fd23037767aab3679fd290fbb65f05ce08cdb63c56fb5d9bf8e83b9292c24ebcf7465a5b457cca9abfa1d916f2fef957ac9c2081d05f705d9f1b854bec28abdf8f5a9181924ee0ee147af2e1bed70ad2f65c3943c66c114f9780785e7ac233f1d9a21e90b23f630fc8947f925123f4ac8a9d60a0dd7956e5359d0838bb9e480d79f44bea4072065f1f79625a29985c61c0642791af1d068a11418d519166bb21e5fbd836ebde42b862f49b2035f81896c541ffd0e9ac5bda5e11b1ff1638f58366958f09c4f296e6b8621e42eb5e462e0401da48a778b0a78cf6357b543fe8ab642479b236c5a03c56b40af8cfe754b13e574501507a4dcbcabd1fdcfcb6270a4e3d6904599afbf2914caf870544e871895f5d9b4b2673438a6f362eae60538d77794d080108518f91074c8e64ade8627e3e7db73e4d41a4d10ba1fa3a3c0e431e2ac4aeb4017a3f75e32ff3e453181e7e5017f4533e9a5be2d3879811dbdfbaa3294d8d51ca2250101f28d09a12d98bc6a8a3bc66c93719bcf75c9637dab06b29741fcb2c39ee1bba7022787db5bb1066777be065de971979e1e13b275206511f2ae0ad7b30c30fd9de11236d0f642da9d83f97e0ebf552af86e95360ad8f1c54959d0b4b9649409e38ac3e05116b757f7842bafb4b186183a019b9dace2575344d69b04e50ad735bbb1e0cb8b49bc235548bf247baf365dff45b16678087c8374bb7bd5ce7e7e2dc229aa000d9af39a7cad43097fa849acf63f58e50fda73c9b35228d6e42f1641916e6d4f18072b3fc8d1074fc1a8cd8f0900e32b5333d7f5a9433489618cdfb5a514c09fd2bf6190c0db9a5b81924b3ed5a5d1d220081fdae0ea65854d6d2a1f5c8747204498fdfc6b27de9add94a9045bfea97b59d01626f28f7e23be8d6fb920e0eba5a6f5435b109f530ea2d2cf2c359356b72f982c72e36c7b70c74200f74c0b94118229bae6a307c01cce59a2d596ce53bcefd2dc88a046ff9cdd81c6c890a17423a704bd3845de433e88e86c2c630e412dbafc696a1e0f72576b2b875c32458dd7e7273f5d4c745a933cc04443535690071c444c544cd44c38467a2676212d3acc21e13d5cb714c003bc3d88d3a49ea912c67f111472b2a266e8eaeff9cd56665ac3bfd2188ad44133e0df4827f1121c21726d21781a906c0a5b94b8c76b5cc4bd5e9080874741519e83aa75bbee893c73c0a53f3bf17e050f47435c600d9629a23a13c3401c1ae716d4ea3d0df0c0c95121d7793548d74b4e1e2afdeea5be740ba712beb312a381534d21a95d25dcfe99775078f3b0a7fb7c5877077e72a5c22920ef7209ebf7ca418bd29fa1dcaac789b2902f3334205c8556216a377d78d334014d64577058f2ff9fdb4cd2b923d8949a6c85d82d8757044e77b71a3cd44dac168d35740120566764295d3ea0385e0fba82183539ebbccfc1214e908e27e68af2fc64581b74dec218df24073368edb1cfe7fc86f73d35cf88c3ac7e0bf9f0c2786314dc285b1b3b05c0854697f7d6b719170ee33c05cb4286466f414cae7ee91f83bdda60b4fde67fed60939f7649b67e18ec03b8546cf517dee908fcbbbfa17dca7ff0f5453c4df4738f7bfae1f6d3ab4949f3775fb3b7fd1f764e3e0c48a4039d464dc115ff58b6aae95fb39f8be0e3988a5cda68608a7876850661b0be3cd337b32164516c54df69fb2119a1e5dd0132d87174c26fca9cf33c0467e913b0d30549d6b20ebe9455e6b646e3afdba12390a4fe4e793bd0b7d15f6952c3f417f3fd57fb2096f2db1335ed7075b903225bdadc7ab755a0d0ab480172c5c6cc2922bd6e0b71c7d14f87c3c73f2c3265d17febc02ddd88eb192e5fb81a23c428859cced25a010e57214693cedd3935334c29bec08b679e5ff7d8680d8fc99a24f131d7ded54c7e5437912f3474fcd1ac57db483288a7aa85e379874b2e46833fa0f55d05ad94d0d54c9d5fe7f8306358288da787cee336b4b63fe4cefac717655d3f1a6f50adf52283677dbc30e165f1ca1a7b312bb562dfa872a1521bbaa7006f6fc6a8c23fbe1c43a74332b144a2d2e39adfa8e77991cb479c671464e4f996e8046bc77141d520f6647304d3f935f4dd1af1e19a9fdac41cb428f43c2467af879d84601fad66f5385eb35a41111f34e6dd3a9565b80d544a5b7a391a095bbbb5aa0ab6e995e113c879fa8dacfebd2be85549dfa41c5fc21f120a24e85ece67cbe1f4964295fe70618232c347982dbc0aa39a259b7febe272b4e9cc8b73a6240e2666698ec5b80da4a65dc6149ad64e64270b31883f8a3b6966e8a35dd65e52cd8d71017db322849b094383532c51af2f63acfb06444e6eb2b51fb1beb697fffba21de3d464601043f4e4385458deb5aed6232dbbcca94eae921840f1361c0f65ca1adade4bc93020aafee9ed6c507b9f61e51f1a6f3f4d36b73ac0c152c284f83deebed3002d36859301f6ba2f7c33522846dd91d55ab3211e2e775905a16ee447773f7dab22aa8c0d908eba336427b57cbb4ef7114af9ae5684b7cd5e8b52a756831ef8bf98eb1ec055943d6e84866c6b2273a17f0975e6760c791db34de0c1bb373f0bfbf627af2087c9479d3a90c3e865e9f60a7f2e333e81b19074d628bb87d6c604aefa239058f0cd1a3765108d01d7cb71a44bcb771b4b3d991f73d851c5f61f16f1b6e3e273841e5a8645e875c71fc099013d5886ba09cc67e642d827e0692aec13925b8c9e8ff280f4493439a2c14f4b2191a410035a21f0acc408e485751174d63055835dffed81bbf67a744307fa8cdc60d32e0d03c2e2d8113631b6f3f8b86dc70a329582d7a4b8fdf917611a513f5250e8bf1866efebe5047aa2723d253b272311f05c4607cbca09cf0595bd49d58f88c588c0b45c1d8f176803448f7c9ec9f79d93a3680cdea61742778ffa3d51d212d42c748fd939610823cbe3a65b4770c70bfc3966b5b41034259b65185e021cb6d673c731e6460d38d4f444b0bfd3bb00f44f8b34f93248c9f246996af7d1c6325510272a3a2b191e50f37d6cb9e8abc05b1f3bb22d956b797b8b53d972baaea4c68336a973f77f355e753448da9696052f9fbaed80146560f9ee87f291e85b1e114eec1ca2c1d689416aa9b5667dcc392c1133f7e737640e064d1f3b9226a4304a09b679ce6dfaec20c116ef0db9bd5396ed967c939f24519f60f615c06ed958d02b021989b329f441caae6098f8dedd944fd669f0a3d6ec88d63a19266a4c5b2cc22559578682d7b042bd4cbee27b23b059a5cf32978449fbeec4dd34e0d1ad7bd1f08417663dda5e62fc4b71c617d716aff9ab97829df1ffedb54dcc34940bdf356ea67eca3d9e61305f8747432e27d25f6b1fa3b174d367dc4b2062715acbabfff1c99629491030f36e564e80a7e45fcd0bead3fcaa107946988ec28af3b3581f18373b2d846a105dce983bac59e0c5c6d43855f997a1148963d972e8be93034e3fedb7245c94664e626b8bcc9b3e1f6019dec5916c3aa528434d5cbba49edc86de4ff6efc6359788b2daf66585c3735ba76be095abd78c477e77856e0e5e8c9c4869ab27a91330517810c6e7be1c80691779638b4e13f22c2ca6e523f2256cf266a58f1bdfb442d3e77360e2a773f999d9cac20e07b499e5bc653103b6e34ceffe6729f5b71a7840131f0488307547f519016a1ac08ae32202bd71211e8af9f3cea1a901c8b38a670ebe9954155e6e9adfec8666600548ef0b8163e07461212d278d1def67e90601810fd313cd809e77947289a8913d801befea42fda231d4852bf7c7a0b436223ed262b65a49bea335fb86a5c7347ae4c8fbe80e32914ba5df86a6e94d05e5425ca0af89912d2a4de284fbe7824baf6ada80d5cd85b2c6a3ed95f54392a22287d111486feceeb77808d2233e4229a6f0063b9d5a72580fde3cd0eaf0ce2544f06c3daffc046be213c5ca828f092bc86641e5162f46a153c09c0c6c7c69b7f9e6e2929fcbe1ab2997f17e1ac713bd71169ec0cb722f21bd93eae6e2089b442d38360233e2b0e33553a861f5ab3895dbf2bd4eeafdcafb39fc428d0573fac0ba93ff4f731ad862a2155a3536edbb6f133135dc0dda48696de1a25d8ae3f5aa1af04cd9d94294a913651b8fd6378fe757609512bdd01561bf16fd3fd2ec4f284c9656207a7274789d18d6afdd704d2284821832a992db78e23aee0d146fec240e0ba78b16c3943c65af8c02f995f18e418449f7e4ebfa9152352dbff26d3bdd981caa62627a99c1c6a3f69709ac5d8e0522b56db64ad897965365ac19be29a226648382a176f507f08c05aca4b38e071653ba935695d6bddcf80ba8b761d3a0281962cbf512e0c3d9e001832ef7eeeae9a19296a75f6fb1d1283169065fd0b7698a7d40ed44a452a4c89db8a5f7615bd022fcbb5f7afd1e788682cb7debbe856ee7fc9bf72d08937513fab1283952ce8607a6975ef86911fbf54fc2b3ef562da0ba505c75e08558da4c114b2bbfa7ba119e4018264efeef255cfe25374f47e177a5f0494db5390dbc6cbbafc7751e40f38b8f36aeea431a8e1035a8c8d11346ad153883bc8a9fc0b8fa1a2046f6835b2a461641d201810c6ef3592c4a47c13314f213d330735fafa6a346c27469faf82513813b628c4631c2ddf9ca9dd05f9f7c3e5ab095900ee7ec2c542a68b38746d7ebd1f188933798954061068de87c8f0f0d3b556f82e9756f377756e1c79d301fe0da5adb990b874e23512a878adb621841bc1e44a17c457c7e8703f917aa68b596489076b531da34fd850fae7118f0612441af870cd1a31648fc43997bd6a273a88ec2ec98c4668c51000165fc2ee77c49f226ea59de06ba179821cde7226f7c60e2bdf5aabd4d982ab99f0daf04169a4006c72f0301e69732b4a0a6d16a207df3922ab1b605171fb9fefc53c5b40d5c2a9f67a40c4339a3bacc5eaed150247bf9319e5a59f7f716028c80a6a2952fd342d34c7694486fd1ba56654ccc93000281dd96bc59d20f5e5af5ec11318c3b4b4f0833f6a7479d4f440c41d9443fa7107e48b4e58287f949a708e30adeff1bf1e99b8e08978c10b8496a86b6d2c42d7b99c08e74a1508ea8d1b5eaaedfe62a8f42689358ed2ebbb3b522d0827a54824357de3d3229e730c17a9e2d378969c9a5752a5b1f7b99dff8f88cbc19da7a71d055600f729dbb261a16ea71c73aefb0d551ed49fe6f8c5fd127b99e6ead18fe1797e9c13fe2a025ea540a6bfee2f76fff3cbd6935ce227c6753b4ededfc3f44e106b8de951c3fe3f4338df6300632581d965ca397f87ffe2fd79f98b16dff14b024ddd738fd0577fec6ff5132653eb0858cf342b231b64722f74951762870e9bc9630ee678e6a88a18cd4fbceb4a8206f333c2be2542c4d1c297f6569619b438824f5674bd1ca07a573b7450f49842662c00ccd877e5d7277767a0ec23d39ce08176d7bf5466dff812b50628bd8fa745758c4826bfe382d47d4ae85e32c37084b5b8fee7f317eceeb0eacf988d7a212268616763258e57794b4bf74ac9e7063f513d51aff31ed19251dfec251722318737fa278136c9e1a53fa9336cfd402042b06e799d771a94a4e9668e9da82a34d4650d3e165c70eb7b29e17113634b0b70c6779e352f1162d83dc8f1b8e3095329a36929bf6ede0e9ecee8aee6cb07577540cc2e1adde004be4d10b6a9f90baf35272174da2c6074c4150b176edb98c278957b6ed6fd3f78c2dba8462534014294332e949c1bf149ac561aa9ab8a10faffb016d53ac14614eae219e20aca180c1034dfcd2a20be784b62376ef430e4fc8e1a5e9a61b1f94f38db0e27fda52150cc0ac5f8f61f7afc5d056a6d161b8bcd4bfaf527f1ed54ba3dfc9464c9993f1e572334f75ce6c42b3b0296eae7577032c18792952ad1ef24169ff28edcd3e23de1d6343d1a2ff81c876711de4b302172431e4f1745d81cc6780e799ff966a3a1fb8ff83f40d03f532458a7c574a548b8ab77802e18548be8af4af6b33e4da4e1e4f607b408a917b443cf422b32803bf2e252617d234b52aedfe1a8ab5b1dae131e8501c577a70a81e9d9d54b9b672337f52538c0f61775f1e2346752ffd4460c10e219f90d2a05cc4800a2715f2b6a42e7feef3f8e1b0341e1fc0b8cb32e872a7c4f3fd350f4db0ced230c2174e852da9ba240e19682f62fb66d9879cef4b28b5383dbd5e35ba2feb9e0c07aba72c9f8cefd7889beaa629d71e18485891df8b6c904d3136cbc57fad1b59fd8b17f884a175fd2bce5732c112b32d627f8c54465f7a3272491f23b18b2fdff74dbc700cd3dc3a3e432d244dacbef5fa0fded6f534ce4ff9822e0139b4e4cbf406f02312a47690f025a7707b5320572e40ee2b94dc04ffcf60c573bb2833b7a20f27f3bdbf7869fbeff9ba3fe61e3162e57d66bfc6b3626a7aca36714f91315693bba27d22a9a0fd1d078c8872e05cb07e71deaa1f63da9fce62e492164f337ed6feff8151c316d4d8784bca39692db13f00f68e6eb99440f9bdf5c253b69b2d04a71eed648deee4109d6afc68a36218c7a03121c5531a4b0b414df1d67b2783c695639fca8993175df0f5a27b9790b4e83716186d5423a40c562182f9e4232a71199ae8b9a26f859c6f40fdcbfcbbcb162218d2c15db964b516ea6e1ed5bfed808bb696a4ac15e6a7dd0edc5263b4392659ad0d5c86d04e027f2967848025b4980ebc29c0c8f6ea854ffa0a254a772fcf030a987e27949c0abf08b6d006a748f86e1f5cadb257cdd8280e279dbced673dde3b996b4ae8813fa4ed67a5484a569f8246d1cbb53ddefa5bfff91ac7b38a5340b001ff9bf28462f8f22053a354d3b1a8dae14d430b82ba52e369079b3726415ad03ad54978c2e1844a5508b02a8fe2edf2207902e33d37838a68e638aa05d5fc1a43525b6f074dd972755ca3a71b52ff615a4c7e8e4374c78446d8be03777b62ccc3e8bf6a0eececafee666ecfb4fbf17d9a16c37a7714559adb543a3111f24bf412243e04820acd51d5d7edbfc1d4ba6a5ba9c4b379ccc14df2e4a858a5b66842be287013507a43c76bf673d1e8a963de60e2cb3154454cc82f385f013d9cdc43234125059226aa516b36114f4c79934a2f951ad6f84f2b70dc9a09d111eddf6ed0c7b3e4addfb32b7cd13219184954da41e774b4fa2cc8ce1cf3c68961784d9f67ffe66d61c0f7c2401eaab6dd2a301a8554a5dea35945ad99ccf96f643ff8f65a4d50148b6e7f5a7133e5271a8cbb74a261ff00a83425805073c38557368ce1385cb78ab5c976e5e024582609bf2c857771292dcd2c544ddff70a3d00f1a977851425a7b3dd9b066c51f960a8abdea2292fd46aef1f72bdf4a92733ba75c1e79cdf106fde2137c9f2c023687d9950457b3479697c9e7d8083e5a2dfbf95825d356dbe1598a5bf4f21bc7d5a39a3966fd21409587883cabbb4678d7af292715ce636c9dc8c417fd9fba1b479fba0de2f5f0897008764470a4346bc9f32fe6ff849338c3611bcbd2bcf29f1c91f7b8332fbfad4faf961523149a81dfbd341f8125469f6b9e6672c7b354fb392db7558218781ba41b0beec418235ac07b943569f134b52c25a94366440c2f1a1d12ee5bcdc233a89aafc3a1b1230c7afc00b4f077eddc7895881cf3ac871db62bdcfb04b271163462603e0e209ea0938fc7f8a05a5b38da638c0fe1e4fae0119cfb6b5fc714ba141e06f24bbc50c0419590c35d9d9506091b66feebc34cd53713d13c9525c549269af7d255483555cd2a64f51345316cf2da16f3bafba360749f9f181ba4f18e65a4ea8864422acb5eb1b66e1ec89286aabc4091f9b86437b85486f90321720b4b7a1f86a4044f56da62b2f805f905fa495f2dd1e63de210f0fef3e55f98132d2d560c7b99a20d33f7e46a08597a4e093f4a34d4325e66359b2709c41a8403653bdcf251594c0983bd3c0e26c203c05ca0c204f9011c4f8cf7a2ed683a9a8639422559a3427bed9eb11f643c7a1fc543146a98a1457c9c623a17a92eb57b839137d695f27eeb6809477ccdfcb8dfa0e9bdf944ba8bf255429cfea398479e9cb087c1bef5f73567bf2a4512d9afb747216377cefa130ed336ce405840dc024e49e829099093f350369ef46ba581ecf78f297edd4fb32b7c92db59f7cf3b5f231cadeeb6af289da33b2b63a5c834dacc92bf4b1fbc503e9af7968e149695fe159aab71914a4e80e3c3c6121fe5942b51d9a2c84c31e5063a85fe635cbe7eb530d0f639f86fff833814126804bd0e4d63b82fd34dd431e1b90f1b555094e976bdfbe1dda09e64c2fe006b3c8c6c098bbf775a22d1b14fc3ed8998a24f906ebba8241d040a3199d19226e1cea2f21a6f16084dd820cad015dfef8e1e6a01ca4a5f1973c4ecbf1897f890e41d2d3c293db54a118007750a9f6824c5dedec84bd2f875b4a699f8fc1914699e4f204f608c5c5b486c3085005bbf1917e7fea796a8b6e71eea915450219e44db4b91118bc35fa1079bb9d55a01fc45f95c7b261409a5ea12474cd5f6381c4ca7962e25f86a0c4a082474135a198b47854fbfe758ae03d397c06463850bd4029bdeb389cf6a2fcc5dca28b26a0952984b00ea492470e55ca6a7e681315f611fb79b95a1bbbc78573e2844759c3310fec6eda8d7260f683f12dd6d409ae9f5e6f48e7746ff7ffa43f4734720339160bab5d2aa1d1e657e1b9011d45aaa448968041abd99d6224541add5747a197903cff463a79f2971a7a738ff2672c7f366fd7569e8ce0f28f462f21e218f563af7fbe50102da9a18bacdfe60f8fce7fb8137234e31f98f66ac3c982d8cc72d03c0b07d8cd4e61ddcd3fbf2c9a95bb1a5f7eb56c3f969c762426ed262e20e874423fefdff773fcb1405553f2527cb79a6780e95d9c127ea398b6e838cf830f07a2ab1ef193ca9fa5cdd4d11a0ecb29c1fe0528f9f59d8d5646b38b5745345869d49cb0176a5b4016dedfbb7f4d72d100c146e0a82cc64bf96245a38060fb80da80358fcace0d62529f50b59fc54ca76860f5fa244f4ab52996cd4564ee8806100bb2894a4470b0737aa5298270bf2382f67d3dde27414d94e2fe7d2871a1e27590939dd153489b85ea3296dfb6f0f1864649c852132290512d0eb29785dbc5d9b190ffc0844ed125a2222b2fd042c8d2d94363fad51420438558dd0d32c0f3ed821a64c79b0eba363960a066416d44ff2a9d4e8a6a1b5a2efeca7115ccee86f8ea8b0105f047243ae163708d38ee91b2e59779426faf0dbb582be6f159c3d81dd0f8507f72c01d97b1fdd6dd1bf2c5f846ac7bcc42460179825944fe2979595a2f869f58879806f361058111e3fee0604e85ebd9c678ef11591118c618bbf69146b0e1f15530e25862fb0f03e2fec764068cefc125d0cf49f8c3f32dad5a2681b95fa57c74593f99fe52eb7968eef7f1e304e5fa45794d582ac1bcb6b7352e104cc8e69ba1de6ec0efbd28d694746e6d863d40fecf4fd5bf7374f48e96bf6fb1d600608446d2dc59cfc184fc3d9d26682aaebbff558a216f897fb807b84104acf28c176fec726084c1af78098f997886b97013f6955fc662388f77010813a36d2904b886b93f08d2b3a46b5dfc135aebc97b17b873e8c685459bbcbd2fbec22161c02fb06a63f0b28e94ba482e075e19ac8806c405b2c25486a9702d3397528c0bb616af6026de413cf8edbcf6dee09db38112126589028efe0795ec8d892820e7ba653f8f69b2124a24bb6d73c881e5e6492c05fd1782398b94f4374d9e58eb2b2c90b03d08df17acdcaf3edb44b87e83692b6623adb47e8fea8096dd90adf6757716ce1d401e7bdb8ce98ee84a4876a39379ef4ad13b47f67ed6af74e3eebdbe8990ced26d973faa714f71be6d5eaeb977a014e0c33c9b8803e0786a6bc112b12e7cb232189c1dd2a606547eb1436c9f2db325d68b4604fb0f79123425b6a89ba3f91db098b8661af9d3cea4ed461b216a38427c6b5e1f8dc8344d60f170bd7c109d8c757b2577417cfb3688772fa547d9082746ed816e542d154a00aa3ac2703fcebe60345dffba504af2acb73c2a2fe1cfec9b11b0716f1f8895ebfff8495788b76ad93f8cf07927d9c4824904aae14c40f43131b36c67721fbbe8e5a817b74110e43f8c7bb5f215ad9deb7295a904eda874e61ed4f337ee27f40a5c67e8d1858896e8664e8ac20ab087ddab7bd13b6e1f44301ac7f95c633d5cd9c16bf5062cf84ae3f44572a250eac66d27488c33f37148db501928de03783baaed55a096a383da0df6feab688f5ac2228cf854d07b72c7615673095d13c677442e7d589dc1ad6b14291b08768491ba2e749caf10d9831de87bdbb5618ae67fe97c6132afc471608ccfd20fccc3f424072ece3557ff5ff06fb687da17b7c1731403afa908ca0769eaaf76733e5b7edd4ffb96935527cf0b11f62bc60330d4c197b48608ac0f8b211df16d2dea64bbb9e877ad3de874395c8800ffbb668deb0d55baee0271ba2a7f1d86f8d210f07b7e24faadc366cbba92b047d62c0320dd20bb2a1645301d5052671820202fd24b7eca341e300b5b5b1e47531bd3c1237378fd668c7f9f4008d5c86f5b914f09f77327159823e6a9b231b4bdcbd7909b584c5783f40ed491d68ed29ebbaa2eeb824e9f04674e4e782cde708d48a2b08178e63197859d1b05286c4109c685e234dd8acdaa5e71e17e5a37eda4ff96f84dfaed29dcb4f8ef204ec4fb28e629845fa0b2c3636c9592f78aa3d369ad6218c126c9261630f3c19761ada022bca0e6203f5c2411107262700d546b4ec044f92cf3f41fe33ce631fde2bd7efc20fee10ac711285ab3daad17c1d10fc578e0a1705eec1f3d9437484b34c5daae234caff4624690ac7a4c6327469e639561bfde6ee4fad88011423d0bd7abebf7b25fe9252dfdb3227daa1e324b6e8778d8b668547c5e7ce887a9967561217438ae55d58c6818591b17e31309a526474613ad62406b3a262a1f6a956e3476e30bf22e12c2c95231eeb7f6d541b0d292432d86fb648c5dbedee72ae222d680e6392ef50845f916d4c2dd2ef193bdf2d8a4397f62f7b9f24137123d85fe0b8ef893292a7b3a46ca06cb9af8bc8acd75f7867a3c8054011ed5dcecf44ac261190c7a6147dfd49d269e28e0ec410b9612f2dd7d83354a90ce103e444c3725d6052a41179bc4a8455277b4d0ed42fa68c3b3445719f3b4d3d0b0ec2f43af8fb747bb39c63d49ddedd1f63141e447858d5ca5fb4214b583eda5079028580904977179b72cebfd9db950570b822d210065a6c11359dc33a2148569d24fd889b2e69d1e90c769fde4b24721154f4dfabdab76ee54a84c7841bb285225d2d218ce4537e5c5537ff4ee6a00a1ee2f399ca5ac9765089ba2ffc4ded3fac8360793f25bf2036fd9823e0fb01ca6479c474ad6ba9563af65b5e559748fce767d271761148a6c432bb7df10667f5fadaa266131e4fcb9b5ebeb164456a3a4f3636ebcd8d1be764c9e48831986f88e2322d231410d2f5c31d687c6e215951c4bb0826201652af3ecc49761c40ec125d37b3733f8305253ef8d543c6145358d3f671b43c3c5b881cfadcf5bbc29cae5336bab4e228f8c3101587b219e15396010e01492e8093e36d9d3d39c8986bfffaa7c6510ba32c3658b0fe54780a11cd6d3591fbb90bfc7a5163e0050db6dd82ef58c5f43e9be7b55b6b306c361ab3c682cf068009a44a15c15329b1a55f6ac84e84392180cfade8d7b137dc24219f8fc544b83e6da077e4e778d5dfbf6df4595c57cf3d7811bfa0e398a2a7df54760b2015a453d88e099ecec4cdc2dfcbcc8b9c8468272d6d44fccfc8224312c0d9be043d52e1061cfd9467354769767b1f9da31ba6776321c4fb556b2e1dbde90f54ae54561c193b2020cb1e29be7b1f47182bc03acd5f1bdc4e01f96171b40ef5d8efab2de9c8b53e7fb52baf93ff7d3b05f939c5d3781a4e77899391bf869f88fd13c489e2001de9ecdc2abeccd554f45e92233db761164626b9c278025898a84804209b485ec12a181c3c9849cb515b3b5b73603328ee171ac1350e12b0c581132355023e1a86910d5db4495c2a6f79c3d22e057f09f3a4538df7435c480b9f7e16ce4034e08986c0881913a9244517cb67f78b457bd5cff2afc7273192274ba7a5864dd03464439bc0544e7f21596ef3e0fa2e275a12481407b4618e23e75f61faaffc36dcdbe1ce2b9c27b35e7c9d29301f271c4b89a29ab4e83bd2088a5ac63ebbee04549fe1cb05aa423b2bf5c288726922176b94bb900b47756279573cf0ea9ecf0ed47715dc606d5b3a73c8cfd679dcc1785b17173e82766508d05e20878fb0ac867409229b110e2494f11e3cac65dda52e64e28a516c7a45a26b4312fe657c5919186495a5765738d1e3ed9c9170304e1e7193d91b003a9de906ac69833cf8af35ee1ea31fa7b5b3cbec986c5e108bf6d80244995244dbf713f3f24b0f6ecaa5fa9d7a2ee031f3869d231b6e47b34dba951cd157a4aad9d46b489658659836b1b6ce93315ccb897dc082e95970e6b3d1ebc81048bd07e57989cadbf6037de0ae9727760586833eebeaeb77c7e87cb6996682137862f4ed9354279bdfc14a6e9c6154a237f324d33e57d2e60e290e6401c2d387161806b2ea3b517fe1dd5d0578cb70b13cdc1526ee674c79cb52caa6192abde6cba6702bdd924db448520bb3d77cbf6d51dac683124e2f12ddc03e728fed28d3beac9e5f0f05367c4d40425b3332692a1ffab3107896cadf742a348e5d09f2e50335be0697b84323d3af1438fe9f47e8222f7144b6f325544c90d0959f649cb3e214dc2c14fdacf2796bfe5e97f3acc1d7f2cf4bc854e426b65ca6723fc31245094e929e40a5ea75f4247ac6de624b42378fd4a4e36ea690d459faed3d3b7d29d60e2b5ddea420dc3fb43e759b6a113b0cd0df45977fae1559c5df3a8f4300adbba61904e6c12375e13e44d13ffd40fa324deef1c8070e7b6d81cf1e97b8f3ac9635c970a51732326a740303f2bb18f6e42680076a0eea4dcf0ab71f53b7d076edc90893f25b844838b7db3766eac166ec996e6549b42fdd990cff1f163e81bf3e34fa178bb3186059923675e667dee12510048363244da58ff939b4b0efa108ea7679dc87421fe28eb486e142d4804a5fe7906c769e8d195abec8144fd567d7678cba8b39d826b406429e3e0ad3136117dec8d996b338480bc0dd1ea3c3149138348f216a3e97b96318d169cf70afab4de5907cb0971648bc383e589eea37d8ce614f58e5c29957a502d9d0e3a3f5b92834d9fc9dc7a5161ae37788a674d008459f3df383da85ca09f3eb06389986a88d1196651a985c4567fc8aa43e89cccb2c70412129e1c80d3327e7e9eb5389e2d82c55e4af508d599a22eb44776d52989bccda991c445763efc65b35748451405ce19db034efaca4c794a79b962fbe5ecf2fef53da149b71ba06045aa8b0500a3137a523acf4870d93ab1cf1b1a6f64a9c2cfeae4534f3ca0a8051ec97d60f5f8df72694a38a0e21daba4fb2f1aa65fd671d1a1f88715b771800a32bccbd82558374d114279c2240a669aa89a04651388d50f2ade437c67add02086071d4316d165e735ba85eb4f8e7d19fb30c97320714a8e424ac4e477256be727a5fff98d07ae262d4fcd90b279bfc16c76cbd4b8e42302da96f594b7f5d734f2a0b0d35906a86793f419ac2a90346bcfa9d6106f02e50230c65478f653b410750e1e5125c57ffdf73b7d69423cfd648227f45d02a2fadb00f354ade69e23e7ffd31839cdfd15d1020f8fb9224940df3586e5b03afd165fabc2190399b06075ba295aa001a5902fb6163411314fe0b2eb50cd7ab11a6c124f790be40378d6cfe431549472b8d1f1f2dcb039302284e7c5d4330d1556d350818da7ddd3aefbf4700a2b07795c947eeda6257dca73074036a4ab7711e6de335e81f8ed95288569a740880a7232c0f4d3db61b5248f6150ee740dbfdff21d143f64807d8c038343920d1c11cf7df6bedfc38a368f4ff320c70b85c954528ff4ff65f7036f78301f7dc09c58ec7e0ee5569910dafcf77495b45761b559ba74fcbda1ed57eb644ed80d95db02cb8c05d871ea1450540e310cc7e1e0f010e73906964ea1cb39b1cf6b7265ac01ee6c20e3ae761846415a9e1cfde938558d7f692df6f4d9d018394126c70078808498957861e8348d15319d7e047ddd3757b99c815e4847fdf8b7080c82e46402f6fe801a2aa4b881e82db77fd992afc18b386bae2e8e03d3ef9614d43fc3ddfda6ca9600f5bc3103327745e2ba16d73ef58a1c0ed2d5ceda1fa355c2b13a4d500606fd61e170d1c89c26f141d026098e6506f110633ae4893a117a4d5ec52a456b61bdd2c9b9944233b4f5c058db84b0751af04008f5677d989fb038dc3ff99bc6d7d06395ca3977c5380e546e1f3de1bcbe7f27d10804ec932ff8f8cabc7a6c517f47e302592232b5f520bc74edcfd278e38a3e862699deae9a99aa91005b0cefdee3e114d81f31e1e556fc1d827eddfe35576e7349db07a64c099eabdde63d9c695c0979630d9245a02d247a17a1e4d5ee20e59ade1d1307803ab1d11b37dae4c7857b9c7b061ea5fd59d88d7da5a15ccf0db3a5ab1d819ccdd934540ba5a7b836479509406d7eeaa3bf6a7cc714871fed7faa478a209a4533b79e55863bd450754385e39171c5130412f2f805b973c46151defc9a9a20abd5ae1fb4f8b73f987b957e4d915f79f081dac7898cc03a147561f5dfa21dc26b2a0d8f266fab3fe3053a9e19099e7a03d51f36b087b58b735dab4970163006e940c7111a04c670158e7b009c222380d489ba314bf64d164eabc2ba30eef259cacb6ab9e90b29f394c2dce6c9ae1c6fa166e8d090421f7291df441ed3ae0b73e7a3989df101b840e0821f738e409e0b184806c53000512bf2bac2c7f69fa6f81f525ad06256ce755fee28eafe6c8eceaa406e9d39d4965c78d56593e280370e7e4045dba6ba3c1afce63cd8e0373351bb9a59c42a5cffb1cb15f83f479caf02ac32935f9604a9963dd23ae120717bda61d055aef632f4c2eabf0afef08679ac9d8cfffb19ff316a77e6c9ffd28c4c16e41ce41ec6010d1ff7a3c8d3963ec2810d16748cd09379dec808cddca0674b4cc39520252ad278ec3117c285afe12aa9af1d24f9664501136d00a145ab228df68a63970ccb02994820f2a3de807a0a7fd5fdcea2dcfb8b1c45b210fd383ffd7eefce1b3fd1357edeec34a86272d16fb9e05835b4e9da39821fb6a04d947ff8340ee453a7e18a503e614c42df7c466e78bc9402ffd336bc8dc68d1999f2090ca77b27dc47117dd427a2aa45cf8180630d0f909f6ffd8e7c09a20baa847f8425180d3b0b2a4519488cdcd189971d9571e99b2a72142de70c9280c12a5c6cfd7435eeed7f155ba16e51a5566cdb6714f1ade6718de89df6cf9e0f2d34a9ab7792549468336ee5a4e5edd62327ccd81d62b84f2273b5435651840cc19bf4345aed0fc14ad852366fad037a775e1625504823b2e55016d577fc2173e3b7d2a54367be5c0b65c0d4dcb7f6fb23540dde08eb848ea32f055fef86f7f1adfb2200152ac841b1f1cb999ff01ac1fa46e7f0deb3ef4fa40ede6da4b1c5ab5a0acad40cbb6766be0a728554cec72b694b3077d1850d3e30ceddb7ac84216fd2b11d8585e384e5f942be6485aa2db556eee3fbfcf8084cfbde93534e6df7ec3275982dccc005c43a6808972138fac6adace23e5d4f5e775ccd3010d2fdf8c82d9e48c525bf8c983b29b390c2dce6cfae9b5fdf9817b38062e8c45fdb6718ac96c48ed4c0a65f679e99cb68b465e5e46f46a6d297903daed8abb8eb8eeb312e08aba3fbc83612a995755b32d23fdc4720a7216e70b4aef6d3bb8610f7ea64c8474a0310f48a03d0804a8eb4d20476e202ff3fd02c4a020f308acf7f05b647d951c167b62829aae08674be940be851664755e6750848940d639d3d3a58fb7e305820f5645951d965873046e9dc1fc4f3cf312d38839dd4a23e8b1e7cfedb5f1fb2e25347ee85797cc66c1535c52e480b8217ffac4b99d06b39633ae7b345d5661f350dcaabfc29e48d5006ac6561c9c240bd694cef74df1f39e1eedbee4cacdda1e910eaa2421e7733f708c2b9f30dc15fcc2409d8d4c25dd5107caa3ebca9c997a538a736b4b085fe819e0a863b07ba1d1f556589e1be56366122f2830549cf4956685dedd0ef60c3a52cc4de19f98665029e4a9c99ad239f747a328f56b6dc3b0eee392a927197676ad2add85c9c0eea90ee92443ab76c69822f8a780ebf3cb83908ea7d67b809f1fa1064384cb3806f65f26287a8ccb29a783f4693deb6cecdb04b31e19385704e30c06d8946f0f94b31fc6a9e2180253f651379a0bbd6e0f8bebde4709b1ec2146f49b466ae38145259b1486f25f8e525d11773633a1ba2c7827ce593befca85735bd69656dd314b4bbe2d50b117acfe1fa728a2bc1aef7b77a3c308c7ce76de49590c0d944e6f335f06b52104409e8bdd9a12c92aacd7fe879126d7e2b97b850035d304f9dfcfb0cc6155367d5b00433ab128f8520c3b9f0c777b4ce89b9f4171ace5266babe061b8590f4730370f3ea6279e9330e05238cc41df721801e58bb9fe525af7e4012878a47f2be68cf4c3e04900fbbd22d140906a0109cd5db2fb89dcd46728b56d341ef1cc315ef0fc53d0f97461f8cd60c23511142de5c5ee57e20929557a847c518d1bb9687551041974d33a430b40f0fceed4fbd2c6e2ede06bdc42d05420f5957d9b0d8a5a188c0852032992c3db401acaef4b528042f9d80c3361f4ced2adde9fcead248d86bda930bf9357fe2bb0dc1f1fb2f5b8564aed045e57d05c44246f3f2ff03df94664fbe2394315a6e3ded980afcd23bd111262c75a79e85fa1210936cc448306f9e0bad55cf4afd42189297308757cc00fa1ecbd1c447aa6d4e4c2164372af6f874e3235ccbe2edee1bd8d9d2d71af77f52a2e90ac694080edda5e4fdf6d1839b4c20a277e2bee6cd0709a4230b9f560478f8c5614e14f321c92f06976543570119aa219625e23a701b3b385710b6a58c5fd7f4a387506acb10dec056056e61a06a6d09baab1d8d6cb7c33adf70d0d91a91c195f64bc45c10182216492bb5829a4030c1ed1b4f1a789956cdda83ebb6689a67271747329d4e7df0ca3d8818ba26c5ce5261eed4fe00004baf181cbf623188cfcaa918303d4edcb7425cc12bc5cb68f4f1832e2332c5bf0c3a0ddd7b36da15ea225770b3a64ba01327d412729d1ae029f3f86a88a255d2b91bc810a98feb58494b9547d3e3e9605588180ae190bf2540c7ae4451dd274d33024009b3fc31219a4867b82c9cf1e3f5f85f8baf3ef112114ef765233495be7a502be6a14384e9b6127b08161490fe13e741f29a9c39d69ff254e35e2fd3c013f4a6b23f0e7897a0f45999f454f54c239a59148181feb445c89a27299eabd843762373ae586f6515ee97d278e418d12c618f3568ba9a02840174510a451915744b1bec0f8e03d98c923ec23e5d0c3a1a88de57167ac7f28d7de0c68292369caeb61b9e182eb4d1e68d2f162ab1bf62c5a16c121b788077d753fd267dd8e20d2a3ddb01b4e7191b3714b3864f8d6e15ac1860b44242626a26d65802bb95d8fbb1e76ea1327764a8c61fbe7a652cc576d6019806e7375435df58e5134c13c882cdab0bd92adeb9ae8f02e68030ba83632ddeffbf56774b1d4f55527fe59862b0b22829c8626f51137d28c5fe5fa8a0983f76b307b661424b7b1ef15222bdd29fdc94cb035ba9145e4496815d3d7eff4bd91420d3364927ad13b12c88dfdb4c279e524f1b09085e44856844a000cd749c99126de9a69ad14cf8799917e435def9fd0ea652407c5988173a1557f3a20d7e733ed332f0cac20309ca50e16a07559594a5b4784f565b009e7dcaacfc4e5b3bdc56ff5dd0a0f898090d78e0fa7ed9b9f88d512e71497cc526a12ee660cae3c06c9f5c9a27b86f53685cf634b65c9e41590de82ff9d3ff025a1c5d752374fac01f119d0bc77954f497e8b7c944d4bbf2887895802f895e9544264d89c537c603d17180db91ca9bfd838ab8d74af159103a58f3d01db9d7acb9588ec7a9e4ee4b74677bb20dcd7be7749463147fbc887d3d4bbb201d097d86b69c0ef0a13bdc8e64086d7c20067a32cc5666cabb0ef4c8c3880f8a05ee9dc14b330150b8da2aa993572ffd22ed608c6fe225f269f7bc5adc571201bfdb12dfcef328673bde90f2ebc9bb7c5485cab261d9e0fc799d3626f3f0aca58752e369708b45658eb88008afe255cf24f50b9ca1843f76b2b1b80a9130ee1c460e167f140f34b8df65214e99cbadf8088bcbf56783a1e6c576616b523e27a7ebd048ce2b5f2e53d9589ad5b9a28d1e1272b151cfbda1f74c82300b9828d6ddf85cb95388e0358e0066282559b477b8b5ae0ad6898af22c3f639765faeb22a930c95459e869afca6382482dccb0bce5094c54a8b9b899af6784ecf14ed16538408c4ff2f9cd0e0dfa4979d903fdedd2c7b6593f2944eebc2295d6c635730c7fd40471dabb50871993ff7b1bd89f458e0973f469d6daad8103f266e5869c85f8eaa1902c883fe710a2ff31d3522b26dd7feda9f72b3a3a5beed7a7ebe18692e81cad1deb1e50da063ac171bef8cd7c14de37521b4575b29115b886d35cff0659cc27db3c8a57e6bf075dc4b160c0c33fc6bca537f720aa39e42b9d01ad24d0c9f6a8c2213d206177eb14791f929a94fa157f5d7f4ce32a1a3fde916e2ea0a5f3ca929fe2095dd07b8f6c5c7a86da07aec34a26056c05185c715663e23e876d5c1abaf942f9cb58e5bb85d26834e0634513a801a37e7f16c2542ae10167f18711e51cbf657efbeccfd8d471ed1b1a09c58724daed88bc68da07921b562ad04ba8d2c36e1c9ef638d1044476a71f3fdfd07542ea5b089ea891b8997c5ac544540e4fa5829bf1a2e55fb1c8443a5d8d6b493cae0f8057e97499bb3433e9f92ffd6812608a043f1d7e2ce1360a91d1517d330046baf808c31cde8fc1612edd1675df38b55a008ae3bcf2908061e5da5fbef9af7dcf2d27e435f834023cd86afa90645acafe982cfcf6e40c5dbb0b85c2c5fa85a68225cd74d84ac3aabf1e2e9a631aec2e5374b46c2c593c92d8d64a2ddc692b1cddd6974477d1ff30f66607063a5cc5dbbf6d332f34ba868c2d158647845857a87e71e3a56aa3b7eea9f40be794e31d5ddd1a1e2b58a7fd2f07f0ce21a270072effdcffd97e2d9b20cfdf2e770912426b2c8b478dd897c0ee5d14e4034249653d081b1df2debbf1169cdd5d22bf21f797ba7c679ecf61e68f632c1662078b61e68d0f581fcb281ef3f0c174c17e555a16927f7b516657ef1b1ed26e25a1547e179224697b0fdd4d3319021f1ff32187658d8c619fe7a2f3bed6e04b387d66c9730ee778efdcf35ca0d772e772886fbafe0f7de27be0009d90916dfed6d90af6697d46e5dfcd5b9b17024f301a359211f1d381dc6b9f462f1e3627c847655c68a24c1564fb59c7a871e9300d8b7cf8d38152fccdf8f5acb60fa3a85f6fc11d8e4eb4a5a0e664830ea4e3b3f3dd65fdbb41488b223c09252ac9ac02fdca4a5ea10427582715776be126c51c6b8bfd4193fa36c164bc3c3d72812fe2f1c4144014fc34d5d700ccbc660774d3677a0aabf3980b9e8bf09508de3dc42e44bc3dacaa777f0ae9059c94be96ee35424ad700a1cc3c054fa3c0c857fde6d13a7c9f91886dae564c902ee4ced51aad1af993fd3faa0aff831918b6a88a0eed24f077826af1e28cb00e97536340e4c1771c6ec3fdd99ffed37cdef9fe16632b65b8f9d57e61672541841148c97b8cf6787d281925bf28b00db65c014f48ac776ada1a40ac82bedc20ae6ad9ea054a1e388a38e0220c8b14282b04e5d5f61667ff096a5f35db3da9b567ff4e0a20109dc87d43188428cc472c78d6f27874905935a11f18e9d2773da2175c1ac4e5d594c0b2c851a5604f20f5de4d2556f72d63627b26f6659b2a54d0c67207412d864cac125a8606827ff42376bd2d473f81b7f51bb90a8e047f6a17c8d529cf250d135bfd88209dec8fe7d8a00a2d3b76a76f53864b549b31bd2c8bc1a82e57aec22c7fc6ff1b844a2755fd8cc7f6ae3cf100c73fe7e0be8d608627ea9cc4cd5acfdeb9150ac623e6d0d138350a001621f799467a15405c3f511745629bd5e780c3edf0c58436bcf98fa6fc2ea634b6a14ce30e2a3141a7e615fee8b22e2768fde5b7a13677a1d46833e63bf659dfcc703713522a13fd4d4ad6a5a7990a003694ae97ff6fc47de8e93c22f545856d54c77bb52de7ac40e5e0d17ed937ae70c807520a3a103194ffed4e5ed3159832f99e3a80509d33b4ab7c29f44385afb503c9090627af7ff3164fcc1cba1852cde82f79a4cff2f6ef10b85670299902f88c3882571a4e8b056828bcdbd4176285004c9f1b57f1724fae7c9e89f18ba6f9d308512c589498049d079cf7655144418937027a37b14ecd87d3b18fae5ab7e2c697239cb01eb0e86a17c14845b5a98ec0ec55aadffb87f22186a1a3a7219d6458220835edb098de73a09bc5b65def196c96030bc21a6fcce54982457fe0c45e38f5103d9da739ccbd68b3ea7933630974b189e49c84bc7ba190430699a1bc9916fa701f8e7542b6cec94d3808a84af81e44b1708a9ff15cea3b6c7cfe0e71c8b4f96e54fa6eea4b85c47db1ad8f05f74117bc40351f179f60fd3b55f40b284b785dd0d4ccecb7d777383bd4efe3c783a1325f0ca1ff8cb32450103bdd1136443792f48379345de8def22433097a3eb7d2f2fc628ce09fe164b5fab8afb3081e49bc7e9789d7f61c2eb675d50f5cf16a4a5c5b493f185952c9db712b6402304169bb15174c28a6c4998cc83879faefeeede82cffe1a9fc41233f8349c63feb0d907b2b9c12f04f6390f8f6f6c507a0f3f5bc04bb1149b931a768eb66eca203117ddcd4298c48a928a389fb65b5426aadec2f69ef7707cb554fd19f37716c75a19e7e30b4851eb0029f03c36cfa76ee9cafab6b80039ead859c6ebebc168cd3abc6b30afa78e14dd3746b6046cbee8555f6d8258d4d2c217f5d006ede35056b97d28db4d3182a177ca157d457b33227c36944c05c21829814537c5b0d17dd444f5c49297fe78106487768bbe3b9f200ffe87fa12250dd97ddb36b4cb8f3f40578bdf6c749272e20166481bcbefb60d7cfbf84757ed902197a2e5558c349ee18f7cadf0d2fa8f9f44f365cca5556eb87452e9400126a6a3a35de54283d30b08fcb1416bef542bfec38b21085d7e788ade312533ff5f05040c039c27d84960ee0c6cc4560ffc56303d7b28e322f444aaa9e7d91747d70c22b751458fb0002eb0ebda3c7e7f063e00388ff1ffa4681d13568b92fef0d63f2710c4063f89962bdd966b9e6593fcc28defffe0335e93422ad3ae39b374e462feb7beaa9eb8328595382993557c165330218abb374ebb4b3cbaa01d1f9d8c5ab52f8297c18f21ceec6d1aedce94aebcfb18726696e66d85b22cf0a5fc9916cd16ba9f3d8f640edf0fddd4d3775b6fd2736f83e2bcffa75bb6b9ce8dcfe2160ee46ed16346670ae655dd9de087a7a8647c4d0c6e30efc44d436e40a279499d7deb47bad93dc7989fb59512f465ea4f02d0afbfff717e4eedc9e82a78b3e05b01d8ea8eff154632d0c5d13f2ff201b9a9e8f03215859df14a560b11f42a08f197a9a6c7eea996b47acabb539baeed3015c5fed07af42e3c409a39e0f389182573cca09b6039d9b023aec1bf55d14a5e720e7a46d33f8f80999817c1f1c412754d2f421ff1fde98d89dafdf237bbcaa271e9f156d51e90401deee9aff2f1ad6ed151b504572b961048c9360fb130c02c2c81a05a27eb9ac741af1fbae7e978204fc60c854c8104c76d6c1651e13d6b8b3a3a8ab5eb2f7385322d67080cf88bc109e679fe4fea9a35f734493f9a63de0cf375ed7294a392b557c4bd7f1e1c20d0f5c7cde08c490de95e12f9172380c32436cae36322347eb236c3e5afc1a0b4e8f80e06b3c9d8ac233a626eb00c5f88f663cf3e8d03f10a9fe4bf36bfadd523b9f235b01f548faf53d6fbcb70ef5bea4e773c234e7af520a0dbd4485aaaa7a1e1ed0a8969d9044b95ef5c4dc3f67302627eaa435dafba395e50964bc524026ed53b9f24bccc14f24a64b36fbeab807b5fc05430a023516436f3c79a5f87529df0437d0292918221ebbcf2a7b73757d4b6da401347fb8f3d4c517040d80ead2856e4af000b0f6909abb4c2cce71397dd6050d648104d1465d33b12d51f3ce897327888f3072fba4834f3836f5798f0ecd592eb70913e734c8637a81b45725001fe42430f391e508b0c38e99e7a6a32134974834d49328ca049f93865c441784fbff2b6038ddaf3548d7869d8e72babefa199b21182f3d1aa4881e566f0e037b859729763d5e9a38f9b1991550899a9025804807d988182a16238deb4988843ce387ddf9b14e128fc7d53c9e11f44ae0fff90cc8ff08fe515857fd20d36fc7f5d7dc3bd593c1df90f6c38213932ddee639b57f32d3ff8dffe9dbfe22aad0f027dff547de6cc5a436fdf753e646ed7aff4b087ccfb79e9adfe2b4da7f4135766b52ccb2ff75ac3c812aeeac422ef7056392a37e05931644e94930862f739dc3e808b58cccd7560fe68bafbb444ac8a69851ecbcee82113579179e8f330f70e35abac5fd879c4463152f11c424ac3ef6db98f767e3cc217eda383774a89939661aa88f71e687b8ecb55b12fae8fb6410b09a4dc3b93bfa8d6e7eef0a6c3057c97b69b7113d9d2be68765858eca176c8d7a27dc747c06df1eaac99753cbb3ca749ff8ba1e657879b6bcb31c7111aa6962e8d20b0ad7e8b62c6cc2738e0c4ee0657cd64fc0b371723247d5d75701f39cef0783e96e28e89060b3efea453b8b72f3180586ec599e9006348d834d3d484a6b03f7ed368bac33d391beeb0d6dbe33ad789eb227a232c2cbb599a33d4426cf65abfbae9cc4011ba7c4d696ac94335da14bdf7354187ff6640eb0c03aedc05334f4b8ff54162ff1860e7bb3eef63b294f1dbc27e59940b5a1650340fcf4108e6a8db2caad8925dc0d543d7e2a6bd1cf9f12b88aa90493339578c9263947a9e4f1c9e58d205d5b17ef4df4a10f290946f0b9c309b15579b26c2a69fa953a96b8732fbb5930d5c3825f0479862214ef3e030d20295f9493613e36c2a607f48f3d38d88e1fd8f68d880aac5c6de553b821d86438974dcb51f07d21f82b586d9b588a3f6789082bf8cd33c82da6f0490a47722e0fe089b30f81756465d6ccaf92dae3f52fe37e04cdfb236851dd15cd75d9ed994197a35bcde23a57bf294ef9d0db254ca903147b800d051860c1cd897d0801e95bb39af1f3fdf5eb303dcd49c4e529ec68ff724e8b8fa75deed21c1a90e6c0a3b25b4b82a4d635a069b570fdfd1118adbfb6532d21789c493498aa6fe7aebafd70132e55e0a29f7b502f2dd04bc0bd9595f52a5c5e783c4429ec56c9cc3ae1349ee6bcc1ac37ebd7ec3031d70f70dfe3c73d19e7e811d10d4c6ac0755242f87cb5535a73907ba8328139406179c68f165f70d626add7f1b080422f8feb7e9efe49497b6e9d4643b8bed31ebcb0850757ac0daf284d3590b3e8bade5b1b3be8b333db7d3fe6bd65cb439ef897447c669e12abc148069d4ac694fdeec3eb481426e0d2cc43464662935ab3adc2c05a2c054cf8ab60b13df02bf5c0f856489e20e8a0afb9a86be6a5aaeed7c62819acb4fe436e078933ff02aba058dfe27f547a75ce0e0b2eb41775c70319677eab4fc0305dc174d09086de7634cf65772506571b1e0889872099d65137219db1d236aa7b47d14a63becbf1aa2e3523d253f52251b6cc472453cee7a26e5068dd3c35341683288c3f0f5a16c05c080f820eea0437c8b686b8bb4b6f84052d78d03f86acd2ab94bf3670fda8c80d46f389dcb6867143ff1611c1b87d5960af58292ced48ee07c5b667c281281901b5beb5a53102dffe34a51fe2c887557ad7cc3a0d625b71ad34a41eb6dbc8f42a4aadb68f67ea5fde34ad9899d3c3d6ffb3b1a1d874c0a3c039a7b6f239d466f6d8eaf57a1c88ba703f8342f3ad7edc1264d907239cc0886f899f8ef83540505777831beee5aac665667cee0d0f205c1acc6accff388f3bf18f3e20dcc64cb47278e46c3f0bff3a8f000fda817dd25c6cc36bed3962c36ad07f493a206b23fa915e14615c8f9fe92dd6a8369c5016908ea2fa6196f0e60b479a07e01891bacb58807d9a319a643cfd8e8c3f4335c6b20a8adfb2b14ee5e898edbcb341f9beadd4567856cf3f01b64a44efca651273c622deecf26b6e9fd26da8a6ec94efcd4d2bcc59bab9b567b71fd1ca543a344e65f1089b815812f0ea0cbd0ae214f376e98a2ac6d1627e1adcbfbc5836b7d8d3f979a5e4d07523ee08db3ce9412cafee6aba2df4befcf5bec44c8d2437e45f60e4e67561b80c1a8fd50c0d5b73ca250902b895ba3f461d7c17a91164795234c2fdefedfa2c14d6ca9e43f40a98ae029c35373bf1b5199be708524487cd58fb0bb4c148a5ecdefdd20a33104070aa41af5b79ec12a34f813b9187b7149464d7a7d9564efd72671c0dc44345dc9c5866c9228ecff88c844166fc91b326df05565e44586542529a30427aad890956f7950c4846521a09c7d182f13cc15c933bf239b88444c77c1503b4969b59938da954932d46cac31de9da1097a37d8b1f5e552944fb596cdf0d9d9ddff39d7a023f2397f265dab810cfbe47d186dd9077b7858a85a278ed8d44f31f2c7fdc72ab8958aa3c5f34306c376548d27578d4e8b1313f7ff51b4e31ec461529cff297bad1d403100b3a220d1ca969d5775167f1a3fc5ab043126ecc500259afd739b1f62da78665934ce35194df68c4043ed5d39280dd5c1fd449628f1ae0bffd2809083321bb6ae01d2598869fc15c8e6dd0311b6129c01530ec5e2986478426004b9e043a30f21bd579552e91eab24a56eda28287cc7b06a843914af3ed9c914a9d1fd017018689cca39f3b1cefc2f4ec1dae645463dfbf1ce309761cb6d0abd60e823bda116d72c54c2b63a30b8dfcf27d16de26984e5ad194da218578d0026ed6663aaad039a994714785fb5ed6732c0509fdf15ae0a39ea3ed3fbd0dee2d78254cfa5753f49a93205382c17970cc38fdfc65cddefe2e287bdc721e647b890ec58d56818a3b8d5fc7ab866fe73b1ff6e9f45eaeb673fbf813664ac0d99df0fea15223e4aac022a223f7f19e497eb3950d4290163a7e05ceeb73084956b45a76a560b40f018da71d47256c34d1ba3901aa5a9df98b7da7a6f1a4c1c6cfdcd13613d95aa03d26d2400b46697e056a7fc5795569fe345001bc6bf6fb5c126c8714862106f6df1fb2108a2fc15feb51a3b434a5881db69cabbe309b5baeec4c525c75d178d2ca46a57809abeae2fc4b0435f25dabf43029ca40fc602a04ec4e16f7ef93dccd4b7ef7d2a9f31406bc153cdf7043e39c0d79c93f9a12a9149ce1827381b4b024ec42289f8c1412bf193c8f0c848e7f50d0b55869d13fbd7c5de3251da73005b61b64d23d292f393f9ac3a4f2d74fd708a52d70be414480f98fc91d343934bd827ed82e6f75880431a19927897a00e9984c214379489b92c90cfcbfb6b83c713c2661de7bb1dc5de060829f6fcbb6fca36c477105fe2c5a872862d1de9336a1d754903c8156c6cfbb8aa262794db6492a088e552f1d32a737fe0cf465b49cc83734d6f929e39866b1d64585b5d93d54021ac7bc235ef10846def5fa2e67caaa7bf735df7615a59d61d81daaf90f3f25be623321ac9d25ad316ff3dd9e3fc945bcf22709d67f8d9a0ab2ca7268ccb05ba147d4da3bf9af5acfee6628cac23609a5ef4a15d07fa70c3543df0a5d94d8e57d7347075220e1d2969e0d82e37f2eadac42045186c70cb0a6c9ee9ac0d00f087772cd466f1d0490cd10e2d5de7bf9121c78e38a64cb2cee5a3592cc4d2b23bb1e5cfcbaf3362edd6f26d7ccd30b02b8f9200cfb75fb8b3e3fe7898923f60ee265b452fc9c222cc954f91a21e9c093b857992c9eccf09a0d991683925a348895ce97c7e915b95bed877b5acfaffe297e3368814e2a7127f81805b2535abf9d0e46ceb68ab83963543f9bae14d8a0f65da1b8378bd65e0526973e0035a0415de0f12d4537e37fc463cc2496bc81618f58dea8506b79dca87e84ae78bb7e020d129f4618fb812b585776165c11cf0364a58a947bb3b72aac151f46d040fddda30fb9bfe9572f5c999e6f1b449d4dd1e580880af5788bb66a8e0fee70b685028d965c7fa7a3358dc0f1c6d1df4aa68c8609b3dbe25087869fa1124bee83e609d27ad088eddcdedfa4c93142ddf70f9e8e826ef9ff3f9ec7e9b800b26dcfc973a435393411d1234f074f3a2b038eadca0ce7b8614b5ca8063aad189004802b77d902b04e73163be4a94b3ff0438cfa0bfa4805854ef943a3fab4e4c0e23b9e4c6be70443c0e9964d27a51bacd2645bff374ff5ab17ff69e61ddb56af0175ca8c4b9180b29c0aa35317b13c04caffd35e45ca47219636b9ca0a366536ccf1e3028d220fee8be4ea6868c21d1017e9faf98cadddd05c6b5fb8c6a9b7a99db4ed56006ea00b81f2f948276ff6fecfa639c30c9af2adc9311c513d5678f8d3e9455a16e7f929b350b7d231b8c55bae2e11e6f8b8a91f4dd0e3ab66d2df6669fadc09a0280b62768ef83bee2edbe5cfedbdab897783a75f0bbee2ce1e0a423103b9be354bdad23dc86bf3b69a9a833a004b312b46b3fab686104aad5514f3fb7c5642816f5640e425d11435d5649bcb2ac76738c4812cb3f43dc112b73ac8983360119a65353f9ab22850e26cb7369f22cc3d23bebf15f83aa94c7bbf513bff06209a56cc61eaa1bad4f5e4ab73b76686d8ed1d3d4648cd85f478cf6c3e475a2f55e43450e0767a7afab2162ea763b078efc3f3452b9c49115f68aa1af27c32a2e896a15dfdbe31c8b3e42f1fd3da57cbde1d086266cd158c6355bdbe4e5379ca5dd5a6daab889e0c5a8c378fe0481b70cba449ea0d0abbe87587b0800b2188fc7a7c8c35f3eaec7e395ca5a7a8378bc2b9413569f99d5d99c9ccb1b640e5b2d63cbdd9536884c5b5135760a415a7b92f8ecb2a3c65f73ea51532b1a0d79f6f4e06e75b7fd62fa819a2f85df98feb84bf1c4a8ab2da1d957d82987c41d0284aa7cdbaeed187f83014e16dddb2b1ebb2509d593c3af09fe6530fa237bb84766d08ec492bfdf4ab8e3c7cd10bef2de148716216e6b4c5b76ad562e2e0638c093a3e5ae598a180df194043729bec82a26819f9995bf7f9ee1333b05480339d745060dc0e431c96a98de76c1bc396ca3597493c5bacb3029b85dc16877603da06ff2c08de34a9dc80df64a9775cd44eba02c35216ffbbea0d16931234268c4fee4108a0c1ad2065c08f3baf8a1929e32491aba8bf3a3ea09b2ea0c7317512135268c3bf3f25f2ddb2008000aa274230e1d0a228d459fa922e9e021a134ac4d441f8ba7ce6c5675c3c0db86a6132dcd33e4bf7d47c35420f43b16d4f7916fc33a1791a6f7f17813441ef82952fe31806c68fe2be15ea86a5b77358d1ad794ed9a9fa1406efb0e41022aa68b4cff60fc981fcd885b9e44541fec90a534504ac3ccadbbac970789170de15033ef77231b70abff37c971ea31247124ad0079a78de27be4ef8acd47bd67d2cb1e8e06cfdbf19874f562e063ad21ca0a224dd62de5371233034112a6c9cdc7744e53b6c970c427caff35cf9e5a845acdaa6eb2bcdf527da9240ee94519395c6c3a4ce6f3b7d0922e76e73b551002f671c0b0ff5c7dec5c1ad294a4834541c59df6393e830cc759f5ebac3423aa21d0e2f223bab28c51d924b26974182ef54ff6cf1d15504fcc1b3dff5bac460a66ba0314227f73f170bf38c83ea8120a8daf4e9b9da7b4f476575a58d982784bfeaf01da594be3eab343d1a277bb5f1155cd60b902f0af61ebccdfc1128d6230191128fd234f57c4d0fa33c362c3733eeb1e33e42e3f40add179107dcdc5b2985243436f241e8e7a3daf6eb1e25772eb4ebea55e9307249c0c5f429934d4d25c2978cf76f3737253d87a1eafd5c0c9c67d5a4b3b82fefe5551876dc832f8ef76e7ceab82479d7b7559383acbf1a1235de3c9da1913513ddabf678c2b8c0bf60ff704b95532bd30be54df664f3677ca81f99c69f23177f087e9af704f1d57f328b6560591700c336775c398f0077f91a370ebc69583926c45e3b0c79c275b540f30804ac1dbd6cafe7ebf5728bb0395e4f7c94f51087163646641129bcae84d914201c0fe6b4de95de79bfec3e068ec3d6b0644f846373bc27b1b55afb07c9364b24dbcf6c59810755d2b1aa51a766e8a1b2398e216d26e19d548f171b385cb0f958af5f9ccc9cf5a73562ea918c4ebff1f646c2bcc5f09c9fa8180e10ab8d295b1c87cc10ed9086abb5545bc033364e7d1c708bba2ff86a1751404fc4b062be6ba0857899d45def2c0f7341bccf3db5bca24150cafa5f51cefd0922f1dd0f9f1a404e773c6109cb410e56cee743f4a50584052aaeafebac4bd7c615fa0db28783ed53905b35b90439587f13ca74a4e0a3382bc135642caa20a1b471be668888dfdb7c868b3c91982028dbe3f16c479703132e8a1e95684b85fc63cb18f32d73e4089724403d5bb195600cecceb70c89d2dadf155f164e6afcf582bda6058207b5c308751afc8f16b66a8ea153d20082acd04153a033972878192b5fbba884100e1cded845f836afa7fe3f3e06faa7aa1e33b53b6f5c206148aef9afc422c3589e50334214336dcd009b96ec3519572b0dea98e985cc5697cf13af12cbf6c662348c494f65788092cf9afc3af8e84c66292998ef3328b69993b2a7ffc4529e86f54b7d2f31e80d9393a61841032800ac9d6ef568a76e621015a49af8b7e81001b91a2621af3366d5599497a8ae3945871bc95f6ff366725a6a371134f8bdab704dc83587bf990abe92bf7279d39406f31f2c578a4cc58dd2048e6752b462c1f5c3b2d73078cbf27daf7f0b2050a92fdce78cc79fc7b6fe137449ef2c2428c88876e588f270e6a552230ccafc3eee4eeaf55affc1d4c8cfa4d9e495c0388c2839a72add0c297f27594a66f43b5704f7eea833626a096682c3cafd0a6da3a0e099713a30aec06d90a80616614bcf16ed6f6ae323bc5b2ee5b413ea2557cb79c816392013ef599b003a0c5e76fd96f9c49a992c1487a81487a7b1a79128843cb6e4e32da4d47902517e980d009f624cc09639e2679781db520f204201fa1c8e9763dbe68b623d11f774ac2bf0716e0165357ec323fb458e919cb01dd0c9fc6d0baff1f33063600d7c0f8c0f5b7bda92d0cbdaad00b60be59f82b10a7e45837365a32991ee705b4f51139e49d1ac06570e4a7e4990b20fec9f2affa8af07412d89eaae2f462a47266b70d37dda35b13dd105ccb9f6259838d074b6ef52ae07f5298462088b8828d6d9f15d3b4ca91f2406010ea5f2512eb7eb6bd92893c42d971fe42cfbf38278fa4ef8cc83003061a6a33bd096d4efd84267286ec35495ea07b7b9e5ac4ee33a23598086d7f7704d7504dda8f25ce9f47dacc4d28d8c4cab17592174c08d58455fedcda03edaf0183748059aa9db57c0ea66bc17c1fe283733f657abab483b276524812e02446007c426f387fd0b40a9849df66d551d45be719b8ee49d3be6d2b6c43da9a5ab296017182c6dc47d48eff7513675c0fa90ecb845fa30dfbb3846144f5c0b222b7dfef0e10a132194c7743d24bf59c1b2270c2599bbfcd9fad3ed4ea0e721b660d3268f39b1390d3ca63e5829c35bd962a783fae45172028f19244a585964e7dfa3a9d50b3064bdff64be5d3113e1745b1fa6359ec44ebf67b4a6594e98eac1d2c632909a643a8ce181c662e2a5b8503ae583c8a009c281d84b9ea2c52601dd61add819b4e8e022e574e430490701775bcd5daa6969cf9e0936288f2dac71ea639214cd968df23eeafad335733e016054ccf4f1c77fc73cbfa695c343d4efc7f42654166b09008acb902a7c3c9b1037208409b33676a29dc6bffb03f9c50fd6f0b4ddd37c1f553d38a6ef87865b4dca2ec52c134c405f649a8c7ec39809f4201ac2a97b21e11ee90e679cfec1a3cdc0281fd3cd596415f1ba9e56cc6c8169c99620833db3e8ef6171ff2ea770a5f83cdf30701ca0ce89fe778129b541aedece5c08274cbdffa7f0380158e1eb3daa47af2f27ddf0267a86414c41315ff0d4f6818bcac900a5f6b2ad6f4f0d31f06660c87415e080d477fcb8086316c960d7975d790dcdc5c0f5e4043c59efac807ae4f712f498b018c64f85fd5d4170c15308d0fb8a4443ec26498055cf29a7ce57836e167677593b803fb3f7e24e74b1064effc3cdb11a4bf9bccad81b8710e5ae6249024b531c3eae28c324df64428ff638179b979938cffdbf2ca432426149a0ec7a3da2da5e816959c0bfbc043c678aa1108712f19de2bfb3513dac84986f71434742d5afb5192c9c8b79a79e96900f73ccc96decdbeb3c61a0b0c657f70f30e06f4eb758b8ba059caa145f8dcfb2e09c0b991af4ee9cb3040dba49deda930463ad68df6ce5c75503caa85442e771a7f7f3319bc4fbff3266ec81666db0afe02f701667b692d16d76d57457a483aea6e52106aa980014bbd65333d8b14e66405dc3f72b43fe12f6022d3f2a484ef1c673a3d1771a842431fdadd199218574fd8e174c4a42200c916dda7ecffc2ba454e0b66a05b5f51222a56beadab45705acd5afa21780d189ab9117abd797ce109c7a5e92f19957fe730a27b779acd414c2660b62fb7d48e9418982090beacd8d731a1d102d6763fbaa8bbc0e4d78465b64f65fe8570962c7b86b9e62fab121a2743d369249bef81523ebe357a06defada4efb27833c2003a5cf8f7f18d85abb75c8a26d7ca9371608a771a36f6254025abed60ec09abf0ab752b7ffe8e7317ab7015e27cb5887b37196495a400e4e8dc21fb603f92cbcbf76783c714fad6d96ffcbfabf70a51b8365a6069eec4f22e25027b3fab91a58ac5cc71ffceebfce570172051bdbbe5be38183fd93c4d18bfcc3795008eaa1ba1fb3bf09d1766e7c563a5bc06b61f2a7becda7a33c0b8b373b7a024281c62034a3809936bb483a8494aee10b0e838630e16fb6b4c1d669171adf965c8c37bef2f7bbcc0515fb32a6e8d1749ca1944ea68f6f6eeb3482d377ea93b5a532da70ab6f74718644f868ed5b044a2efe2a06f06a58fe53667d4029bbb83e3c3365029f2d84326b9fd24f983d9c860795418201fee77638775b3b63e3215d71c69f3b3885f1c447df1fdc07eb0952fff0ca52b07e7c154afd92d72f610f2b3f4f029684bc56d302ffc82291de902ffc438dd52bb59a6af14c75fb1bd97240fa3f0450a17763b20de11a0fda1fbc122bb3e1348be2b48b292d3f43f9e8cca2559c7fff784415569a9a3ee3a4ae028a6089ef50bb40d1ffcef64e33e1bfba22af21d027506845f884e2148cbd644faad5c0144b78f32590fda9c2f0fb2fa0f09f1abfbaba8c3436fe72b09d219f98d67472f9e217e2081bb33780e7c31222cbe421ec77253c10ee7df388cc45c2a7c1f1b307e938ab28dba235f6a1147f8576db12aa79dd0988e69b83742a9c840c6359587f55e84ad0e0d569b2bb44765b27f464862ffee9732ae3b2174be103d09a6c957ed4cd3ae3a62e2b92f98e8bb83f1e1fa0fdbbc02876bf2b9d782a0c3272e200daf027d316e1bff68f65cf102b872e3571cce0d3eb5ac40af8cd988446185e3a9c118bb4b36507cebcbb19e01c4768c95ee9ef42ab0f5d88df848ee2a30e8fc9650aedd672c4a5fb3b2b117e0143fb5d89e5b817886f0121607f1b1f1730a9de4682d2fda3a2c08fbd0fea3a456b7e9506d3ffe2ea7f57099c83bdd54f48231537f2cb4f581967e7588ec489ad9a31015b5d8e9d7f8e2ef2027041da340193ab812ab7d175a5571a035ed7dceef15e524c66e34a4851460787612c3c369e8338a9e11e5f33a7aeac00763b66ead175c723153da65e64f06df2f73e062f8fe4ef485f44aed708ecc7404b82eeaed9115d99ed06d759d72e99db9d5990cf51ece8d5c2315a58b0c531ceb67e3422cb4279e1d02b650e05936fea7d4f0a5c6f0e9a14722b7ce788f3d187e6ff1feea1f0b3f95488fa5cd59c0c32270ba2a221b883188983055e913ff4e9661ee0684c93382c1f76e9bc1daccf22816ee547c41c0c2d56096e6a9907e15e2f199ce21b9f6b466fa3ba29291e564711ec4fb399323e323e0f774f5b8eb76b04e0c4493a047d3ac5ead04ea5f18683f0ba98aea795b8bd945cc2cb12a3e779d0f08b3000d028329c7e4f88933da4d936d0c947c19a407a92e59523cec634dd32027ca3c93bc06f80fe1e1c7a94ca8118e6b943910ef598cd79bd642e3d9767f6d72eba731175f347d07a9dfd3b4ae3f9749ebb66787c64414e61a68005dd67060eaa1b33b3555205e4633e57e4f542f5fec7179d73cf92a952c8bb2bcf2173533f27b8348d1b5950cfb8c26664106baa8b2ffa9873832cd5e4fb233be1c708c5fe61e6c7f01d81847a22d50c877fa7550a9ce813b5c899af344a80dc879a03b13095d98e7e3198501ac7bdf1b8964e65e5be38226d3e4f6c6f07d9225a569bf4d065ede12da69d710a03e766d010ec9fc4f94f9c4bd3f888233b61888b9a94531ea61fbaded635b9168efbb79faced3fe1411654e76bc5cdde0bed3edffe8bae651676d4cd0a8816ecbf4b9ee6c374d5bdc37ed2671dd0ef9067a24b82796f0521bb75b542781bc10dbfc70932fdf7feae183e23ffd53caa20f2c63e816e10aed9fee04305dc73d792e5eca3b4dda060ad1876a4c313eb68967401cfd103df01e1454393744e07c68895dac41e681d95410db0a93d5ce8a0f7ffa70e03b07e9c2e891deb44e318f0a44bbe5fa4d81fcf1c3946dcdc5052ec7641fdc16c3f21f1ffdae578510deffd47ac32cbfafa06008f3f6288b40eab71bbacd0939176589cffe54db79258dd91d4233b0f68b02af48d0aa1475be2158e147b33ffda3c9e47eb12b3a3fe3064e116d315bbe13604647a3c85686fbee4ee4dfd533fc07e93e49afc2770e4200c4fbe9a9abfd646cc7b969449679b50929d4b0a7d7902c3a4d1ed2be580293a976e5c6cbb38564fbb614569a6e3477930a2c74f15512bf9e2d26f1487b4a10eb8d443acc4048a97a0fd5e291b2bc89e7649cf039d94832d18acc81ee5e86e5c35efedfa69c142822aad47ae78e22e0414a2a025879df42656cbbbb93b5c94523a18ec7614b4ee77ff0f6cc10eb4bb83ecf08a790058938841a5ea5df836d18720d4254be1b38bac4c114a8ca300a7c3fb3927d73fcecea764c2325a351135a29a0202e4496c21993bd220215180bd2b013b3e2e3b627bac50edaaa36b00d63cbc35580db0613abe13e1656dc02652b1156c471b1792701e4942f44c47d8d1938ea88366ad6907b059f0708825c5da13474414b2a0a52809c26852579f54d3b8f0f38f0f53863e0bc091ecd6020fe58764c5f7486df2b34968a210de526557d70e49fd35638d920d12b7abaf10e32b67abed368fc7dd436bf6a851434b95abcffd428aa69d601dc34aa5b6a9e398c1d3d93bb01be611343b70adb217fc6faf8381db3911f30789b8c1a1785e99a99cbb515f1ee5d5bee3d57f754a696a31c8153fe6dff5e11379898469a6d4f62b8c6508178ba3595065798e9016a371c77cfad6dbbf5bbaf5384550abca67b0d46e447ddf3ac82dcac7b1b3b99b74c2f2291352f07e78b02fd7fbad2212e3eb1b0ebf9e203342125952d40d046b29e322ce50258d4de3159d0fa5464aed56179efebc2677029a953734c5e4dca0d72fd5be650d6e2b32561fbc1e318d7a1d3ba4fc56008c4cf170bb8d61fade669a11a44465bd9d285a56cae61f2351c3d68aac3c198e8aa11f604de1859570148ab960b26c739c684f8e0f1cf9efdfdab2bc9a69ecb89559b180c53e13a8d8356b0c09ab17541194198235a51e86c9c96456b08a367a2c8562677d06dfefcd5718a40b8d34c8cb10a856dbdfa61e88ce5aa764f955173f1dedc5214943673f958436d7f0a68d4902bce33e2ddbeac39e5e05348f2220472b8a26200035210a8ec1b6833449cc1af1b474eddfa7efb3f1e6d2e995dcc43e44eebfcc821b3efde9e447f313ea27dd35d5e37d3ea08d4495163c4a6a414d2bff4c12e575de0195a93320b4ce12f5396568ad643d6c9ced0d74eada3da400fc91339dd395d2f266c9190003187acfa7c1a3c33d8ed5d53dc1f15cfe9c8eee6d64a878f3f17bc7646c92bc1c00c855ae3dc56ff644bad929545bca08b5da3244bc728ab1758fd7e4ff0f069b85da46f0337ccdd9ad2601f38d01157bada0c6c1fcfe4a7bfde9d27e3aad4de4dd7b04ffe0fe2d8b55da2afbdebf0c6da32d038fad8d4ff5efb3e2debe80d23debd900c1cc45318e2a64ddeb0ecfb51c93c18213aa9fd766766e42ab79770f7fa7f31201325526939ea0de85215124632bc1c56f03cecbee470e326e4c58757d55277d08bf79e139210dfa003eb423b53f3686c6d8b00c95c36e736a4d26d91b35f32d5628baf1594c377b79880b9f82e439085bab56aa33eeba9f9bdcac60e9410586e8228b2ae21ae2d3cfc4eb598ba0e2103bd313ef51ceb4e8f781b25fd516b03101bc39084a6ba1fe6f2ee48208e4322484bca1988ab23f48fd7afb352fc5ee051a0afb54b2b60254189dd188cc6679af3179ea430b5dc2e6f974f4a69895ca35dce5927ba2ec52930913be8797617e285510c2e33640e44b8284d0501babe31c7d4da7d11c4b89b1816721440a845ba92cefbb98b6baa4bd8b6e9eec663896f3ae54252e3bad265957ed14b24ca2df5a700e38403c6ddf3efe33165cd1803602c12984144a83457c8192d0e448504a45f0dfef00a0ec4660b4ca882d755bb1df69038dafbf142dbc47d0833ceec83055d99975a16d154af19c188c1953c0afda2243d20f4b2e9734e311b8b2bed8b5042e750f74fec50cdbb82a04ad488f0671790105cb395f896e9cf17c28ec8ff8a56ef7b8b05156d7f0f5630c6fc2a726cadfe0b21ad7e1ea6d1dfae4dc201d46462275f46c2d19ab0ba5c1cd46080d2095947184f67e2da8ae8d4c634cdaace19afc2c4864193ed6b52c739bdccd2f2ca6cf9d571215fbb888b0cfaf25440e59ba949d7bdfb205330aa8c3a7001fb954e9a96b02fd93d4474701465e44b7af35feaa42b8574ecf378ba3ee89904df4282d5cd518a1390d598f9d16410232e43c0d4bd593bca8c3da15c3e61fcf9bd14c20bbdd4beccf5a993882de5540de090b5987b77c7e0f36c6c25366c42099a9e7f002fabdf32c08b72faa4b7dbf3d1054b95b465198e89ce25bd5a3cfc553cd247a6b7a638d259348425947d7168cd57b815ad18f2aef803550e7012e2d434df508d051b871a7f0e63c72a1ecbb59ad74a75ccbdaeb2d9d52d66b0a1c30c8f051fe0ca6d66e31a23a7d9b941612225548a46ba22c267b5c57bbd2f4c65986ccfc4135ff592936a5051d5b6ee0b8c09b90990660a078c0ef90830c31334119a20b7d8b8233f27d42a9a824e8904811a0f747edeace765c521860336ccda4aa9a532f3ca73100cb9638300d1c0ec10d220ca321df4c17a3bf208cdde6e4c6ff7a2adefd004b4d6ac7958d642efa8edd12eb00a35b08e7cc05d91e5b597b2857d6a55125319c22c4856ac2117f33c9ef0f633b9048bf930841c33fe139c27833f978c4ee6a575e8136b53c38fdd857534b448b2594c3f9030807553224169ce2d2ff6354bf7b3f2cd46c9a782e2c627f202a5efb58e4aa6f27db77aeaefda185004042bb736976c25d55b3010b10615f7857ddfaa9e87eea7b8a45ddb849ebfe19eb00cf9e739ca4d0a70a635ba8cb94d254c185fb2f448bdc973c90c1cb59597bbba1ceae21a5e40a3e97acb54470ae070c50103b679250bb7b7d095aca38be077b97cfafea088af98c24d6504824f578948107338f685cc51b571879c03fee588b4777e80a1cedd171c87f5ecdcc5ea855c30f4354c3be97daf4b5e0b38a31652f6245f7fa2c309ce447331b1ee7346fce7960316c7b63cdb64f329bc811598b5d8f10c81146610f0bb78421f225daff5aae7ff6b9a1548aa078fe10fb678619b0ab08e9731ad851f2dd2c6a4ba92f9c3366553250b1c58e23648679fa38bbbe3c23f0e73fe97c255b2ffcd89bf6c0c86bd7bea76aa98667d5ab6330ee7e8ffdb4c4437c79cceadc947d0bf02faafd18a3ab62b6733fb6bea092b95f5fecacfff9a61529074edd779203f168c44a568a85eb38872f4d01a9478025e6b9ec4bd392d042b20a1524293717270fe8020a63997ddcba18043ac8a92eb9abadbe00cda729039eb77240b75848daf2112ebb94a3ad2bd95f1ca4d4379eef461c536fe184e48ec06a1f4e6dc9c2a786462430c460876416ecdf549504ac4e17e0262822d0dd84e8f812902e3c45bb0280ee1d089b9383b9a2d67b0bc2aebed9bd6cc790c596177688da0ea07a85dd0cfbc067c9eec5beed84f68f5441a545f380cd4d79ab7d91d1c5d9b841bbfdda6857ab44feeefea9ba4d077c0f309e70c0af68b5078440a555a042702047aeafb2ced70e70de06542d69754144f089b10abf5a46f5f7cf9645de824091617c422afb3e0c89f1d44942c26d33c36f9d2eb27f26a22c64f67bde8f2ad7ef898f8e29de6698948866840f87c5114b7fe349a149abc22ef7ee188e3efce1062d3a627fe07a061a3cd6c134860ac8d8366a924f0a5aa3b957e8195ff87231c023b8e97ba0f45422d7e6516af714787f682b653b36476de918557d90a413150b71c7125b370d151de36ae9108fc72448a981c315b85d901137fd2f727459c5f93128c6dcaac7d70aea6db5fa3464209306ca40805059e3723adace4d6b1b5e7186a0803e8f4ed72782b52391e80b30fac272c42ce33414875357d43e918a05278d09a7c7fa8d939c128c89224de89653a8da592cd38b53ebc2c971ebd3a09cf15a972d5f86c7fbeb80a793c176d52cb544e1872d6a16fa6fd98691d7a39a189c28ce364094c88efedf2e658aee42030e57e06cfb9c9316614d1ad4f71134bc82bf0ea78c64e1e10cfa25b23606f6bb01fe474be850307b1e817846c614c5a716e360f103de9675c4a9794c88159d9e71837e707188706ded84e84193e77457929f9716b4fa97517693b64f0dae216a080a659e8d96aad72e976f8cb38975790f06b11221930f1d1e8c31cdd6273f1415214f51a5f01b388311c0b1c40693059d1ff19c45df5c2b891033cd0f57b13d634e08392abab2fb1f4dc180989e07c30688c82ae75bd5f139bae640d46529dfa6076afc839b9ac97bd250531f4395e98671477ac6a62bb608d04b41e7443cfd65772065267e716dab3cb18a2b7941aaaed8f643eee6ce4e35ce099c667ff1c04b3b88f6f2e397bfe94b608cbf3c3b1396e61ee828362f3a2fb6a7933a7c0210ed3f635d15446349e586ff46c8bf1d52a1df1d3e7173c2aed3a9a0e3aaf62f54cacedecf611f1ce6e5a591c70cc2e1f9cc98a427cf52fd89c078cf92770d38751d3ce697b0f8356042962d8ad500abdfc8f8192d20e1bb38f9eb62b74fb7c60cfefee80fb881658e06267ea8ff8fd7bf4ef41c9490ab3d8a38a7b65cf6667dc1fde9ba5e55928cd3b3d9127c8256d9c6796d69c447e57765b5c8a5be9e4e564da609f60945e84ed9288a4450df5017e40e20f800e7d3f5b475cd26fbc19b8bd3bdbde02930a66d6d94d4a18cb41ed7e148b36fffad9bc46bf9afd337ebe4c815bb3fad59a53f2b40428f314b42aa61a149795efad7087b64e9a381760e62e706fc92cba5d4446e800b635086ee21b7669538eedded1004091363ef18e4bf29dedfe30335385fafaaad79cfa72bc3f0c3c9c7fe3d67da70710f17d4fbae172b3e1fa31d8e808ba885010ca09f5996e0f7e02689ae4106099dd73fa01866a2fffcd79a6a1160fe5f9721600210c267e5344d6b6b0c566bcc53f991c0fc2eb5f955a9e99fba4f093e93be11bf52ae55f9926a80bfc1e5cbe56323219d01cfb0d9df195293af3c839878f5fa378a078dfe0db20700f343522a643da66b51dba8cf5d00589b8ca99b9ca768d86a4ab57f61a7e717b10020b420c3984bd92d175eccaf5ee927361a855c7ba8abd9a6ff3417e24b2727ee2109dc428651704a2e637a7cb4eb56196b0818472744e6aca0c9331e3704dbdb41c2b5d91b5b3f15be66369e96db53de1b7787476ace2e99dec402412b3f0a309bfeeb77374e49fe231ffca6892ed512a557e06d14ff22393852e7529ddf4d6436b63c807f8a52b834314eb20fa2c8282e834c8713196100386deb078f34f7b75d5f37c854bae3f0ea874d79431af17108c52fa3ec7b6429f1ec96cc5c10abba868833512b34eaae1094bc43209d601ca4421d1895d86eff666805df3be9857011fc4148be47d637de2a72d3cf7caea7889b7a0937b8b0089cf84de05b85866d5da4c395357e24cef937bccc16e018978def527a855f6effe840dd2d39cf8ca449267862edfa8f8abc7f093fb351cdf93404897d53c1d0fb228dd87bfe71a3ce9957e57eaad9f6777261c075608f177e4bb7cf0b92009883cb5be147a8f8532dd6e7808bc3af3efe1dc347047217e575b6b479f64ef7859b39cbbaffc9a469853b7a27a190d3e1e3d7997bcab143c3217c46824b0d074357d10d8d3dd311221264bcb40b0ecccd3776c7e4e5b694adb2ba9dde4bab30a9542bb337b42024ba09debfd472175cf8c6927ca447d55fe7630f2a4c55b8cc5188c60261807f45ab4bd3415556ae19234a560624eb65d901b906f80c2359d598f1c3165f2f96f22fb04f1c9a62b69efe5fc966c8eab3c686e422bcba1fee26d716a13bb4e0700abd2bb52f322c3c3b4a2219d54522749e8494b9f3edec8e27d547649806d0ae95f358cd33d69ab0c02b6f035550add7fc84e5f96cdd7d7e8f7645bee8e821fea8472c77daecfaed66aa4a409ef0ea9fe0403446fba9ae341ab0d195008f2a109b67f0a1f31781ba3b07473c21f6bd77749767abada3b72d53f8c1e59bf12ba734b86ad970ab507eae40665d38429e2e3c9fb192d118aa6a4dfaea521361ecd2108813d9eff815d6c418ffe179407617c966d1cdfd24dbc8042799e353ff1f47b0e947d2ec01b7c21620327911e4dd6d6c8c0bd8f099a1738b06deb86dc2a25cb2ce07437a7ae817330b90e8a50e25f9fcd0013f0989bf925fdecba76366ced971611229968b77099febeb1d0c5e2c1bd373288c44e78b8966c33e8c68a3e76d0896d33307838d5d49c080cdc82e34f9b5feb25756b8af59972a9da601240b29d2600c69269d09515c2092fd838853722cca77ad1c9d4de126740dd1041c97b0335c290d4ab681a1ce009f133b59db0b561c50575795f16431c7b7a2ac80d67dfffefeabb87b9c40c8fad7c315468bddcf128ce1db57eddea27f0874306135febd73690a11e33d0e2b4876df0d3f2e24abbda4766a7a2d3c670e459f3424abd2dc93472c094181224cafceb5c377517045d20ccdb6b12bed3c492b40663263f4ae5f2179b44cfee1ff5c1748be472e84fff55ff0ac072de9f29c5b16592b534e44fe1262abb47090f84597fe1bcac4cfe62326d399a7ec5c93335ca1edb7ab2dac3d2668d7889ac2e26617951e904d65b7bf2d7ef84ed75c9fdebffeaed11e83f99246b54f32f2ebde190eedd45fef985e49c5a1e2be5dd22f3fc15a0b29dacb7951d093bc93dafe3aaea9a289925080a2d9ae2a02f74f6ff3ca3a224b9e46f1a5f34fbc117f73e467bfdf779b4d1e430f16262f342b7a1dff14078a7cda783b90e758ff35e5375133d3f023de2e7b19f90986d380e644a25e265201c7b1ec9c82bf9b5effdc8ffdcedda7efc4306ebc9bf8facede6a0db33defb52fdabe4f32346e4cbaf0f0133a43bb0985c0df6110a67a65044377106c39abf6898c789e69bb5dc67972dadb67ccf64b2acfbfbc47fed3f37385ca68ed8813b5425cf8626266d4e9dc6311c1f7aafc75b08e01b69fac16d290c316ef4e6da74e2006c86f3a7a44e3ce580880c02e1d13627f228269065970b5294ebc900b3b9d5ddbebc0d3b7330345298b5d3d60f3b3aa548f55bc99960e41baf5ff12bb27eb2a9c0cb9a6e2d391559165c1f31449a77e3e87dd125707e423c483fa477816db519542559e363fabe8b6e5b6f8e32819a4e2dccd10a433426b4de29919083dccff7305f434358400e838ad2a0352859e4e53d5b215aca0f3085dbce194d4dbd3c0ee295bc33b271efd570c2e522234e8685237638c483348d0c0da4e728ea71aae543d8c589844cd3fb504fb5cafb7c59dacf4e3984efc0c2e271caab298ef29bac7ca1be7fbbeef07701083ec25eabe2d90e78fc52f77cc49c44ef9138bdc5af0d05c347970b508583004aae2a1e6b160ab42d98e483e7a7670fcefd630edf5858f9fcfc0c8f0281591466e4690390f1c2658ea8eb966d3db1d2642dc7fc624d2a28540961fbd6356f3bf487234cdb7ea94f5a852fc988c6f6f55422832976aa1471fcb2594923b15f204f0f37e57a5da7be19b1250fff03b9dafb39d88c5a3afb6c0087e037d5fcdfedba51369198cd1c51d22bffab0369df077bb4ac07df835bdde17e50a1ddf11fb541de3f06c4ab156407edc427eb3a6b8672d097809e7961bf5c6da0064eb71339fed8c7dab0b9680a9699cf4e2cfee71f4d7e9d6413fcc89b379af2cec079e434cca6e8bc2c4d8990e88054016b107fc844a6b40a9dcb852c15de61b1e41bbff0d3184a1f4ad06e49d7d31b4e17bab761659d6ad7a5bf77ef97edd14bd2a4dfe654a7bab469c5c70c941aa36aeda9a67a576c3dd7a24002b65670fb28a828de37ef5c1a88c30d2590d313d34e96964220e2d450490a71adc179f369d3241becc58f7dfa26896bcb8f9867018ab6c9ad5acdcf294142099dc133d79c4c510cec93d1f52e492b4d64b8cca5a281514ee1589d47f87f66c030f00cc715670abd7694cf5fa83106f3925131eb07645b5b040d7973671698451377e97a4f5146c4fa3eb72953a34c72e7a7fe50f04b78801cc265e322f5be4f026906683c2fe0d124d84e4d37a895e840ac887c6f12312d2748071b5d03b82151c733026b6fa7e7cb4e335add0264068620ee61942885ff20bd77f441badddfbf7e16abfaeeb606bed5f43700e1bce697165f1e7d03ffecf91895e73dc9a5e8ea0d9873873acde1f3bf1928a6153864251dca17dc0e2041c6c45226f35ef39fc07b892a7b4d2fe3db87efbb48ffd2d716c23211358c79fd300e18c2cb5bd5fa0726a99ee415bc3fc6fd82f8883b5318c68aae2ff387c22f7c97d61219e677bfd7af98acdd18ca2c7516e765cb411b72cabd40726c04428447dd186d75654fe4c3b7eeeab5cba64a7e4304b0acd50966da473b6a3caba33d36f02fef20769a1324a6debee8e118abbc62eaacf414276bfc267e9aebf3fe8e4e61af5acbe9f689fb46928a0368001f8e571c68485a59a01ccc7c6f512cf3ffe7d13f8abe435d76b8b65b2a993f241027ca279a68c1f60ecff958e1fffc71850f3b031fec6db6fe9fa0483951134fc4734deab3968f4b6fe3f881cab6ed8c6b14f7449eb4e1fb4fa49f0e4789ca082d18ecfb8a0bdb65edc6df8b86d3130ff8436e34d45259eb076bfcd471fd1f232e9fa575c56f6f34e112e7e3bdeadefb8284884f2b5330135a4f336813891635c864c9236a494544a79a7036cb59d51ca6d0c210c7ceeab3026149e67dd3dfb56ed23036023fc3a1b9045d17f7172fcc95873cf65ca4c1556f7cfe9ff28dd2b52de87f17dbe5d03134420c52da508835f5c399b2b844d440e37891a676329ce3937c42990b2a65a4dc6a2cbab47129d57abe91f61b2bdca04fdd975bf436ba3e833b9f644af3aaa6a5c99886f3e569ab9ed99022c7cfebad1e92682836fe3f5a0df5dbe2ea0a7217ded88dcc6302d8c890e31262aee3b14f2ad8a412f656b88ecd698292cbb15c3b89e453c9308b6366c9b94448bd11ea8e9d8522f46c9877eada2ea9b559eaf75eb6c673f1690656272bb2e27461c39af4f50388e026a15ab4c500b1f59942336f942a3050c343e01780388522f1956b4038d7135a003b1addd26c531aa6997cfc1911c30ba40ad6c36c6322e53a59d24f589dc9c26715f6fb3ef8049b68a82e954ade0d5ac264a673945570073c9802b90e1d44fc063aa1addfe75a9b314135590cda875e6c3ef12a72292724eec287d224aa3b27445aa1be6f30155897bbb0044ec80e43a2539d5e54b5f6c19eaa84fb28a7c1b4e0b49e635eed1c7a03d20142a3580aa61063972874ebb7b41083511377df70731c7200cee6d9f39ddfabf01856dd796ea3fa1269993dc38f9d25b68183ce97a18513f085907fde3b01756c7be58eea304ab03fb2123bbf37908fb9b53ea52dc77a46dc4c7cd3f1cf580b75d7bfd4ff5372c861fa1a7e22796ebbb113cc07cef66bd32dc05b3eb27dafce92be8a56d22eeffa29132a316523758eff5999ee677230b1d2c22fd18c2fb2165c17fe7ee591c847e038a1801cd998681b7752b15bf145bc8ff7a362c93e526b53eb23cc172b516a54bb4b55427f167eb509ebdd504362902aecc616bc92a46c4ba7c3b28c1f658abd4766ca5549c866078bba0f69ddaff5ea8edfffdd519665f849fb0eaf521ab7818a7d5fc6ff70a894246562e39a7cbd13855e9861da6c3b83e26cba61fffeaf575ac8bceb0e286e7f768d5abee6cda2651549de0cb641c5f1c6a9eeb59d020668966597491caf4251cf717ef393b9a54b06d3c8bd2773d48fe0bac24bccdd68c7654c2a89b66c60ca7ab716cc34b87546b1a1e455892aadf10af84d11c182b3ee1124b88232228d33ea4fe9b7290426e25854a308663e18b4d506352c4e62c34a35a78bf089fd46528d47fffca624a389abc748350bfecfd63b46c6cb3dbb4f0b04720669ee911894eabd7005240d6408c04fe1b9d19316fa05e1502467fbc43af115e3ab7db545ad7f2d9929b29b231f01e089606a04d5bc1dd3d8cc3c63c5d20a138aeb118633bd5806c415f85feaa4e47c7e6546518adf274b61be08a7c48f8884cae5d63f60eedb392cab00a1e049dd1817733e46a15913bb60ab6a35644f4c4d1bf7632ab3e5adfc58e41eb00f863eb38527b46d01d6baa27d36e21de44ffe588971704cc77faa0103e88ae84434de6c2308d7c2cd099723159c3fc33dd5f8e2453a852436c72726bd7eff92f367eafe51bf62f19a66efaa6c6d1ddf050f891bd851adef9bcde541245e255e44e5e4100426f1c40997970a42a7ef74a9988c929278b7236063e5bf793e2be786190947291bb253de4edfd75c2e3693ac160b3dc91042faf291619fa9e18c8992f1f828c47e3f33c57ba9ce053a72dcd6992080072051b1734b77c1196e153288cf686832072faa5c760933ac8547676f7e2676cb0bdb368baeae15aeadbac509906cedb5099327bd4847b63ac6066284a85e512c051f6b816f828f9f2f1430b9e497a6890f79f2d2e7f1b3c2b3d59dd294c0f2db66a76a3ad251cac9720e116fdee21014af34a28bf96715f2c4946ab2218e859799a7f7e712020ab9ec02fa00c526cd03824c47965024e899f3de747bcfa6800c22b6c5b49b124ff011020ca9f2c77217a25343529e5954be9f113ba1a6a082c8d5aa87797f2155ea0617374d309a51bc120ab346b54d74241af3b1add2f39737692d26b6e87b214f1dd2c99f22a8ea88a129cde9156d8d2a56361e06f9ef01356e7f0a01159b91b7a6b93f1301385bd9344d4bf6439a6b0a43c94416642702e3f066e54b96cc48062d9e4593ff4fbe2a9c45fdf48c30858cf8a6ff94d0f1332ae0f88bccc47756ccd3643840ac1e670befe72dc79d8c9cafeda148b8d64a847bf477ff93b29378d0094e0b817420b8f10f6a9096c5ad2b5fde21c453aa60999b8202d7320ef697b4c1cf231aefab92d0f8e0be2d71ce2c48b89e9bb07a8219812916517148c1b93edc1c484515f9bd74c850fb19912629a878faa376a6b505ca2f306302c7b7835a7740aead1f20c55a86bc0322314ebc7603e88640b39f12c5f7ef6538337258ba227f7b23589aaaf4b00ec0c7112bc1bd08293cec0ce48949168aa48c31cb5f093396531fe39d2bf63ca5e658330dc3ad6359351c596472647dad6fba3a651961806f2a586601e0bfec4e30e82375fb1c84b398b2facab2f0a7f61b6701a38ae848b634f7da50add7bbb6716fabc17268c4d490a953d419d1e5ed43fdaa9c9fe1054c5b4f6ac41439448d24bfd8bb61cc28e246af3abc433a5ec0f44d22dc4f34b21ee9140bc11b34fe98a2e6c4b2a26c392bc5fd03e2f5453e7ced164ad415241d7adceab781c429fea497cacd1eb90e0e8ae64d0c7e27c1e8b13166bb5abcb47619b17955f4a3469fb87db7c71be822e3236bfb5f7beb4136fba3279bf3b46e744e2df03972ac81d0cb97cb5d36098f3d61251cd14f968efe3cf5f9053ca3de53f197108a91e1107d8ea3cd0e4b5a4432faca4d5a659255f0109b5b3c684ec5af254a7a67881f2b5ea79a15a5fbb4fb9d69c7962ad4010744320c575dd9fdd61b687c4770b1c881b18600be3f51b3bae88434ac1867d61bc903f1afe9ead176138ab279263638be029c3ad1defa8c15baee155dbc81d7f1346b151862c2398f93d1c4ac1b033f1291cc2af3a0a061587757ec248085dccda034df8fb32c4befed267e2c0f3666d9b97a7366dfc56c28c1c95a721619682510c81e662725c788f5c20fab38fb41f08d80e4677f915d313e4252f9afcadcf23cef7260e2686f27c9933724ba2a19e0a07ec2a822a723e10b993fe64c62b2d196b7a66a0aaa2a7f505c31ff6214ba125db845c10675d0ee80f2f69fae5745689bf64eb6749e23b9e79d28c18a02f183f9d6f38e5989a9dd30f36f64d5c36cefd47b636fedb8216969ae165b8f26234ee4d79768a4b53008f21c20ded0b533b61665f609a18754940fa2fddfe77797645b33f6c68ace64fdf0471860e2ddc9d50b1277261829b0144f088782a4cb0a9a7797263dc4f0204042d97bcb4ad1d8f51235d78369132ce0c4128ceb17eb683b6a2ac25d581b465e6aac47ed4e4d6802c42878af093b11b97ae0d15d1066d5b7e122e9f42bc2986b584264d333c70681b98216011dfc5ab1961843f55340fd3e6bc89d147ed53da246b8e4ca8a9cde949ab332742f71a1c2be906373655508d63cf0c4c6f42a26dac5baad01136c4631c9de29907cd779eeb95b41a784fefdd1d339478035367c575a124f786312f94ece41420f2710b049969fac95a6aada7d57cbf3d0f425d5cc0bb60335d9f3c84ff537ed601e65325dc50ddde19848a1f519f5ff5efacf78ede15d9c0e285b18bded2341a7fe39c740a1f99affd5519b788735340fd69bbbe74536932d809597465dd50928357455025bc97de0e817ffe1d961b62c15e8f15c004fa39aae53324b461bc8a54b183a04c99df4cbdaba378b432b9d4a4023fd39092b2bb62c91a7a2cfd729310abe0497aaabff34d5f227620cf0799fa5ee80d2393278edcbc674fc5db0a3f90e957d558bccd171af936d62e70921b5a0f2cfe96b26ceab854b90b7d6d27308d73011c350595a7677967caa0b527c73acf5aca98f1ffef93d69a16c8512cf9db7393a9f7de6d39e147c625759912faedc52836c5a369adf1f4703039d9d108c85c5adbc145404f8075bff4cda3bddab3e551eed6b4d7e8a9f2269ce6340a0a845ad10f065842a4d01717587d3fdcb5ec444b37618949d42e3cdfb1d4f34255898aac1c6c03c68e998f375a5bc89051f7a634cac95fe0a72b0c3194a1a112d6cff330053658d0de56232589572b2b0d9a6ca5cdce5aecf48f0430671d22f16c15b605e63d067f559f10ee05ef8ea83a763a3b755ca528eb1314daad073b2608191c7ed1056be96f59886c130050f1fe48aefd5f16f78f3c081aa6464057ac0af9674dce638e2d6eff21f371c19834f496238a16581ba251dc755dab205549a71bf3f750e2b8e193327b79c53d332e6ae6dbd152c8c22eab3cf6470b07996af69dee6e3fb43f6625ea0ed1616a5d87ceb4d09a23c169922515a669f2c987eda8a64c3678b3b37bc0808f0d10a1627ecefefa661c643dde50f13ecdd3e8cd60dc987f296136d4f28a0d00ec3a977fa41fe9b2feaadf14586f8ff00b2e7a71912761c4e707c42df9bbd5cb88ff6421095d7e222d79f408b331edbf39f7745e88f56e9fb3c3641e818b0271bf852dc856f2a58c60955cb915653343a1f19a49347d7a78941923006f26ecf4b4c3be1cb103ceb69adb7b89a8ec654cb5945494f47f54c56126a7be46676e593befd78d4735521b701e40fb74c94c2c5fa05cfd1e9cbb21200a68f91095711d8ccf3f6d1ec953fc955d4cec3ba323db8f552bac0cab76f3c3178b9580686ca2b4627e931896f6f4845f73c17a5c0e94ab2b72418945e2b39d41d5d77a8f1fdafe53cae75aa05f676497e7837d699dd73d6280cb711414f2a8fb6b4b0a6ed63dad35ac165198bf35ad6757d545e6dcc7b4da31fb023d62247a11eb861f74d0d5d52af1d03a9f8f5c8a1ff83184573609e5f4bbf49180b716733836ec5683a105f1b615c324a49bf5b053789d1480b1a788cdfc1be8af634ec17aa899cf00235435d72558ebf418f3807536e15a70798a4760022e7b12f3472e31fdcf1dd4e2181173c3d1961647dc86d6453f833de4d0acae41d083755abacf3d95ae9ad3cbb4ec4f59d976b6c18194f96063db0bdf0e010e4e5c30fd121935a3413515d2512c73b6cbd55ffdcd7cf2a2d8a9f8356ec44e476b74f04038e9e251b74f6de40169cc45ce38dd658a36bc3623538d8c97c9adab4651b30b4ac1aea9ffba8cf44792ab136e6962917dc3cecc145e1493fd280b545f501a5f9a49160cdfcd67f41a1dd436efd5ec2f2ce6b893bbd57d0c1f7e2f6c598446e2dcd21037fefd797b62c1e01c49c99309e0c85b1299ab6147e5c7f2fcdcffdc402060e092359fa3a587f1ac7ebee7523543e504c23cac7afc5c83918547dcb6edb3cbd0dc79a06386bdfe0989f8a69325a237a941123a22451fa04f7565a0c8cb95ae37f8de73395f12202c9553c539dc5b665f6105646bf26436fddad8b37cf8d73ef6d67d34348bb4ea982f9d32bc9f8f2e7439b742bd16c81541000fbf13e3b4ad5df0202bc4a3619d8215f7b0e35a185ba8a6f13c6809a693b55b11b094d0c715817d108a21a74b6d426ae3d887545a1d592110318eb88ac74dcf20c7e5319ad8ad3de93a4b6473d38b18a7735a2c74614c3704d001148f655d73e6cabf4d4b242c0f731ef9d56cca6badb61d44d613030ee9871d30263382181c271cc1faafd1cfb6b8a591c2f39f56236bfe5592e300cf9f4af2bc52e536225a3e382fd85885fac2a36a3e667e23465758ba7a55fbf82ac4631cedcf75bf69541f1db85b23e661edf85cbd412ecd7b7b3d65f0a44c310943f58a4a3b1090929be7caacd205661dabd6d08d91e6172988ebba8416e1fd29b5394f6f59d17685d268ed99b98bf94eaf344a686c530abebeefee6dc085fe58ff55aaec2eb04c9cc983326bb7ee9ecfbf086ff322c39622d887756524c41f026aa3cd594848667e743ecba84816c4a06555dd98b4e2c4d2e70a9a73a5d7f74330ad8a2c7f9445768b5084f62687dbc1110f1cbc52e7fa738aa21285d3eaf5217e820bb5e81e1a3dc751ff7b2661308496b010e576ec1fc543bc243bffdfffe6f75afc68f5c854ac737fe71148c994b456268548781340dbec85914a348533a48530a6fd1efb0fbd1a5f83678af247fda55ecf9869c1dfd29147fadcbc5078e75de8910b9757ec4d1caf094d6bc719424a53b9f8e38b839085d4a2aec4845a113090b088b0129df4fd694ce8c077922597133e18817a8785539516f35bce0f7f8e1badab7754ce16bddba848bb416a162352957d3495ae011eb709229fd75003551cc570d713ad986d3bee30d09cc11a43a4e8399a90e64f7867adaf44105c900ebcb9f432228684bcd0f2ae3b3fc698623c0242ef52051df058d1ef64379b2a5fe8afeaa2d687374d08c94a302fc02852c4a3dc08ed761d3d0052c04946eef665b84c7b33687ecd6c6f858101d947e5af06d87fcbd21cdc74c97fabeae64f2b3c5c43ee7984ac3eaeabc076afb8d03078d5df93712d6f2d047b55768f9b9eef4462f2a23b960f663e88f7518dae62addbe6a530c55f78c6e110364b8ceb2619abf3ad0f963f5cf5fb4ed743a38668a8c3a30d1330a551b83b3ac0ead2299852f3d556e8f6acebd6deec2e3c79002a1d3dddadc0e55f817fd7e3d51f5771eea5bc4324fe22e225b53c91cbca75a64b8a0905262488959d091aae66fdd52fffdf31f7a84283fe1b5c2657c91ffcc524adba765f42a49b81d7e0a76cae7b84345818804041f9f487a9f4ef06596ff98a9192f10c53baf1c0c075f51445a32a2d0424f3124057ce5c514fa2b36a4140749d8b36b4a13f69295feb27edd97abdacda3b267397641c02baa743bd1c1c861270e9bda414a6779ed6ee2fe190fa7dbc6a68f8f6a3eafbd192b33ecb36aad15a7ad8ca1564c470c3e8b391f318ce698f45c993ec27d5b6ec5d4be937ebfa82c0feb228d8780bb8b57f56904009704f14d955ed5c6c06dc15ffb8d18102b145ec87026d2de4ed25bea959c443077f3d3bae300e2aafc5cb8bfec5143748e12c3bad3d005a8d38cdfaa89d43a5a073c9a8c776bb28ecec6a42f1e48ced0b4efe9a67e7d5c380f38f9d263b35358b4992b26a9054035d43c26b6c3e84906621ccd5caf1db8e6dc1a37f9e86e9a7b9fe8715392bc13bb6607f4bc29482d84ab89b71ce2857c739730550ee9ffa5a2b4893ffd505ff016522c529cac7ebc24f0cac9152206a31941700561a5253fd9714e18b8ebcdf80e68f384be3d39781c4cdbec65669904ec29accd183b1f1435823a77a3a8db6256a1f60463acaf1d0df64381c7ec64272515d05df5946c07b39213f3cde5602ba20140a5a7319c14aac7cb1d323d3676dec1e8424949185243fa3b1ea100280034f7d467b4c22e5fb1e59559234dad738b1de8d62a2a051bf8a13396dccde0172c7dbc16a868a3b7a2cf2fe34b00374e25e4fc3c672f2518cd18e1559c53905000000000000000000f902c0f8dd941c479675ad559dc151f6ec7ed3fbf8cee79582b6f8c6a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000aa0b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a0360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca0a10aa54071443520884ed767b0684edf43acec528b7da83ab38ce60126562660f90141948315177ab297ba92a06054ce80a67ed4dbd7ed3af90129a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000aa0b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a0360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca0a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873f9d04a0a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873f9d05a0f652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f37921f95f89b94e64a54e2533fd126c2e452c5fab544d80e2e4eb5f884a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000005a0e85fd79f89ff278fc57d40aecb7947873df9f0beac531c8f71a98f630e1eab62a07686888b19bb7b75e46bb1aa328b65150743f4899443d722f0adf8e252ccda4180a0e1968202c85e3b5d912a0b5370f48abef3d4ab876863b9b74dea5594779b62c2a07f23d9d32d6117f3c9484504682d2311d0f6231df9c98f254b3378049e03fa56", + "0x02fa0186580183080e708402faf080850e24f0b130831d1ec3941c479675ad559dc151f6ec7ed3fbf8cee79582b680ba0183248f111f3c000000000000000000000000000000000000000000000000000000000008d67e00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000161257000000000000000000000000e64a54e2533fd126c2e452c5fab544d80e2e4eb5000000000000000000000000000000000000000000000000000000000a03963e000000000000000000000000000000000000000000000000000000000a0397140000000000000000000000000000000000000000000000000000000000018223005bdf1e1445b071001088ec97d80344116c1c4200619f9651d46bd2ea7f8d9f0915ef9628ed4d12b41907698af2ef3f42639fe4fe3cbfcd3fe7defb125a106b82b161448073ddacc5c865c322ca8feb849f6ced5f973f2a1d80732e107c7a1097f1403d010338b7ef41b7703204893e2951122d925221917a0e4a4848f5090111a442d0932d0812155e411cd2cde62e2b6bed24fa0e1ed54d4420fffff7aada961f322829919c5275385d49a793beff70f009c911a414d83e3c43b7940a4ea58e457cc8b449918a11d1952932994a4f1599264d513e2f9e64f21374614958524886698ad3284e492f2414f9582cd30a01a4500553576915e4fb448a98ae18781898e4e79153790e404df92452a85116d25466aa3c559ee9fb59d6beda6776b3a4a72a53daca8a569a5559d5b62a1d9effbfefc7114638ed15ed955288519d759aeeba74d7c304134d3ccd120e3f48e0c33083f23401167814bf276ee7dd7d5111a292488c62aaffbb874bd29999f74be577fec47ee1d98a8513d926890a96551a024920902c092cd45a0a44fdebac9e0717b22efc257deda50d6cd646d85bb6c0199b6c5b8424429615c048c2f892598b20a14e0f95d3e1e0a10075646c3bf4034441b20b02f1077f073b87e86d2b84425191005c63522fa9c031b66d27699c653752532d1fda1f32c4a1d1c0a00e30b88744363500c2d0c3adb68d7f689b33caf27afeae093d14a430f80080719d07bad49d0f3f7480ed81084024b87dc4308f012b008f4247b67014665a3ebb0764d1400ca2b70e0a995342e593d4b8d569c307bc1ea100e0c7a942c4bf12bea0a9d975c61562859f7634fc74f131b10a1c8193c96114779132117f13e03e73cdf55bffe71f5062ce38df4b5535bff834570d6a3becf5fb39858b108e31df13159f0e31bd92813fcf54c1990b5150895ccd5035a6a5479ebd19ad16cbfd62c5bcce02646086c2d8ca42624cd47c5e9e98aaa587b8ad752ce17f33ddbf4b0bc19d283c0044920b9009034e24a52a22f7e0cd2ebbcf8f0aa1c979704d66e9aee97494c21b47ffac51776d022d757ab0626f89fa471e2b0d3b11201d6d94167d7228517e4da4962b6dca223e186180a48836eb4f33b272731bb8fc0f1e1b42f8a599d5e3c5cfd1a6e6cf4163c2199632e0e828400219bb3f53a944f931be7d31fa8528fd5520b143189195cc893c427828c93a99cb4e170919c0eee14d5cdbcae46e796001064436c4ebcde3f9c06837947411c6ea641751bc8483c2391e4dbdcaaf91f66881517e57ce131a177ff7f6268e812e6fb695ec27bd5e619b2e3c90f4610b53bed75cda3ab1af95d131ceca38ed63e5a087bb355a2c23e140ddf6aa45e125f6f37054dea75e444ef0518741eab66ea50c56855744bd8a292b10d405d867a430c42162f1b34a09a10f89eb0dce87a09bac527f209d78b5069fea00dbcd0887d1b973822c84a42e87ac08b801a2fc99542c7fcecd032a5c854dda35668560d3f80ed6ff8941ed10730aa63f200079ae06e2399321d8a3ea706f5058a1c0fa65762ff4dfb7c61500578498a8942b02fff90dd91265df0b1d29e3e55b80c1586caeff6a97036cca94b92955029e220f0079f8997be2ff656b8b1286b5010dceb869cebea089d5ef3f34fae6c7ef342173428780ea13cf45907ef9a91451c851618cffbea24cff1306b8dbd51cc0418990d1b05f09ed9abdafa21e8401eb69e1050a33805a63d92f2413019162f61f5c9205f042e30009cc1976fea8bc9bdeccb2950ac9465a682947f712b98a0204f4cbfe6a876dc38fed7fdb5b868371d86bb8c902beb22d1eb30f3d0a2cf66f103decb0f847404553d1be4bc51b14d2a54878b4d5478e9e353bbb7bb54da18b0ca9ba55d00cfc6008485b1d8861abc14261cf1b0017ed74626a6dec94c5a95fec20590ad5c87573892865bc364b50bb6a2544ee5781e7f63abdac01e9a5dc43508a46715a6a37c31629f60071e0ca71c187e352e23b360b385673a35d2ab60179a599b9da2c51215835dadb9b9729faaf336cc41a68188efd79d611e9af6a4ff4744b9371a6998268abf266fdcdf9d0193a3df56dd6011e0ca2e265d171e85b3578e8d3f058904b474e38f51bda6e6c465f9a603a37ece8c8bbb0bfb560b42311580e69c99091de8aa25fcf209c8d07d91ab34e486047f2fae4ea8e0fdff6ffcfc844930d5bd748a14cb82fed6fc8568c04374c0dc79878db486642dff62e80014ef83d84ad3be90afecb31ea696f40f66dafd3db5cf5132759510c87cbd15ba935720a0a8afd125c56ef10148a0777d61f824fda2cb07a4f57a0fadb064b89c5fe188eeed9c677637e571c961c44979c05f583008768a876fdaa0e25edc6d6131febba885b19f015e54593f0837f04704df6231481dec3d92b68ff82e8482dee4de08e62ef1b889681bbe4b246c1349df38e16f8e69c1567c1df81b9600835c3799e39f183a41e8d1b88cf7ea2a638ff417985ea91bb626f59f908ea00cce3193b618e85e1f98e113d98d58302da29a3070ffdc36ab40452004056c3061853043964829bba0bddee4c587ae95be145483d7ef6a7576745873c2e1066c0dbcca68b15885c8fc93d7c3f9a715d87433a17e507d80ff4677027f031f169212e3a8bf209c021aa1475c8476569f00fc6ae63fb69764c37ded951388455febd8698704dacd6f5e1cdc0dd39f75b98ea814354376beb3a961e42205341a70e838895e664b192704862ed71db6e5e71c5c6847b1c66eeeaee6b8000081ea53c06f143f587b5f8970d5f5d49c96f676cda408d02dfe65937142692993dccfa0de2653aeb5f1c54f39ace3e1978722373b5c19bb59f405686e57341a9c5b2e8275be6f13e95ae4d82d091046ec663690b1ef6cc0bea0fd2a3b40e0a8a4d0a2eab47cd888482b00802dcca036b5fb1d7dc6d05e502c82c51a0ab8e9d29ed25e3edadb2f748830ac81957d600202726849811e94c037afda10cfd1fb22b0c400097ff445db91f04483d00214e15147f6dd6dcc3fb17aa978a4f7189e26767ede3bb75eb8a34920a0168afb73db56effdf5925a3d213b383f15b34328b7e2713bf0d7def6051960face9d764ce183d419cd912105129f18c310c68bf0cb1c697cbdb0f405c30ff8535ed0296b1f4081db0d6a6a3a52d8586b68a5314d7ee6a97774cb0c028af83e4200105241c10e3de5be204f5baeffb333324cae376e0a8500311c32577f8c048407d28d901f227437ad83e2828b639b8ac3e4a805023d48b231590399508173a6bc68af35399ef2d7609c7223e1fd3eb44e7939eac09815c6aa652aaf4f78300ffb6eac2e61816f180adbdb40476dac09c0e318aaa5320719b267427327d695301893551b2591d9ae0a79bf345c5865daf3c751b9b734ba9ddbada2a3fbedb35c23979567202fa56f3f77d349e361fc0c519eb7701583e9e43c939d2a5d11b294dfda991b38a72b4b71e8c64be8f7ffef6b58b07d547a2090530c60fce5a2bc602156c9ddc779a5d56ce8ff6c5f5db9f86943640e7e5217657c896aeafd8a2d67d085b0410078f812ddab682e44df03cf53c50830ed0ad3afa7e7450d0351a0d5552cfa2af2e55db60863f953e20d89c08ec0337303244148d04361c1c88b1d5e5014aeee45cba04a50f214e557c9d7494bb882d821b2497d2438b3937fae105903c112482a912112f6ac0cd9293362f372abf698072711920460ab1336eb20288223f00bc1467ab902ca93cdf9d469538c30fb19591836450fe1836b9546bdb8daf7d8e0bc4ce5b6bde53df9433f5a73aaecd0d5d5a94fada5bb1502d4011eafe2536d64f2d7483606ce155638ad3f2d41481e324711c7c54f013099d9f6035e051be85b4703086e5cd589a80d789a1699e9feb73b04b58df2feacc654cf18a6570fa7de3fd845e10c08f04b61fbe4eeaf020bc1c86c5d1db366b5710d7e9cf61da0c31b1ac58a18216efd800152968ca753d8ea1f59517d91566fffddd9969a5dc6148255b0be0c7aa57fb810a8680b443a06ff7e168351cd08c272a3bbca28c0aab25f53bdbdd7d68f7e80565dc634449d10d59dca2a0702438f35585ac8ac35efb110afa0c6d634c500ee83cca5147364ef5b896fea7527a2bb854334f124a79b4c0448e2c4de958c54ae34f42c68f07569c21dae992ddf689055e726aa03509d62eee8c6050718393292ba74ecf68c52cc12eff18537a00a0f882c9820bb3d79e6da9d6b5dc26950b27348b1782d18177dc480e937bb39f5b72cbf2a87439e78a0a59a87eaaf7b1307c4380f1d72e54c1781ebff0efb2ad8d75043855b349d7556107409e848b510a5062f9b4502953140150a9d9f7e7ba7878cf207266fbd904909b9721442b01fcb4430be7744da37a17ba6e3ffd15f07e9a7e5d037cf5adf7bb34e52786adc484dee8c8c438a6e4538eb25657af5feda22005d211d08ef482abea790d020b25ee9cc604f5a02a2156d45f8834ed52661572e4d3fab72d15c4b049217895dba1d077d34121c62bf3a9a5531ed4259a95b4c230b8babda215995b2c0ab5416520663668bf4aac9cc946e30a1a2376e1c4caf0276545f05b2e6309c34f145ade4f9f0dd00de222d9f8f39feae4faa6245069226b938f1fde47561e8acddc3352b46e2475df217a3970e09cea6ced00cba703750ad73d0305c5d695541201f61b697983c16598ba5d3727075abcad97fec5e0c63391b1e7da30cf1ed4ae9adf5b9920855ecd157aca04050ac9286d2f64dbf6be87eb504bf876a32887a4744c209481a9a751f914437b21fdff5caa0068924c3eb18e7fd5781a021fbd5d99dcc33a288eb3a61fbe878047e68ebea5b20f6a16153c033894f07210f08b57a12ee29ceb5464112f7680cef4022d3f06aaf043bdd9de143f154116fee0340000f7929daa643f0870966e5a4595b8c5c46dff23b295eab575bbf79ef2df816172599e90d5e9e8633790219477fe1f91504f58b51542344aedb33998b997694893c939b8588f47ff13be31276d102437ce1b9b18c1d116cc554af8c4d6d93f96e6808438e5e7f84513d02c50681d3fe78f414c45b2a9abef6f81ebf44c16346cff5b31116a3c7f51889147d79ad0244b9c0d41205ae51b62d559b48ce44014db653ea3ffc5f30ee06c384e450ec0a6c618d937df3382a7bff6ae39525ab6ae086a273efac82c56144e65f6b4954430788e599acbc1ef5a62c9628ac64b67eec2c09f1b0aaf5f9914f1a047d7b8639dc80ba868fd344b2a9d4e17ee2116271dd3c59321fcf75bca072f09c84174b0eb83fa362f5031b7cc1b5288cd9aa8dbfbbb5bb058521b80d213a709a847a653f4689f2638d0525f94d5b1de7a83cdb847a78589c909cecade979dd6f824c8af41d377de3ef5bb341e64d29023c3d117930ed1893d68dda7fc14a55c0d4ed4140de35745694dfd8b13bad0c43518fa8463da113e8b80bb82cb566c8784e862e33561aed297172e2a2bbc9544af7fd3aaa555d384ac8594c88abb5e3e5cdac70ea64c589e92bf6fce8738ab41521bea8d3d7a84de6b923704e35b336eaf3678b4ca1541497e036d6ab5f2ac009c71c0720cecaedeb48fa6b8a42a0f85e682a6ca6a60c0c2071a614296101e9896d402c26b5dd72043869017183a4430f2785dd1ead6ece9da7fea8f69cd2c434a6dfdb71444c5e3c2791374d0ebf9ef9f95aedd4585c3e48b6acdaecfd9b32bb5be6aa929b6cebefdc7bb53ae6fe06d583ba9d0a3ebeaa4c7f955b4c1f6d5d666bed047993c561bad0bf1dcb8f6bcfd6f735c96ddb2e018aa81a77923dd05d45b705f92fad60524f931f4dd3abbcf0d8ecc91838d752b7e9bf8604408321548b9f933b6e7a3495f444c9834a91917ca6138f581526a7b81f68307b4be445fd1a0b4cf2ce04ee2f1b7ff9b465061876b87edee6b3a1746b486f59f3821d80f7d1e30d8e061d3df43d2eaf1ba3bb93d477cd9f09e15c46c323dc91c0ce9c702fd00a49184846b10d1f3b75c00fb22d3c04482e126fab87daf3de9538337784288387b4a673c29865f10e727592fc819a1d15de8da1c1e1a54ffa22cc864efdb6e05be81258aadb9d2dd23aa76eb224ba4221d69cb4edabcde2c1a8ab4d47f20e15c21a065cae5851c70b21e6d5c5eda436577272542521dc6e25fc7b5acd79c5a51789470910e7749a199e5d9090818caaa94788c6266c550a4494b00ab12bdb8eadff563d7359cd9e631242c47576d0a3c7146c12d9d0ee75d337331ef4b93688b812c957eae30d4808610deaf827285e0a2a26fecab0963d1880dc9efd54c99f8a547d5f8b31a9d01f6c84001257845edbaf99c2ef7aad569b07ef9a4bda0275bead7a0bbeaaaaf6f295fbd2e3e16ca612d459e68bc40abd1f7dfbec23fba067f2d3f24f49916c0daa0eeab7b7b1ae65a537e9e07d0a70a96a1516e73a4d2c4d725a3d640db2b83ab9c6eb92d23b092233cc98a28a3d0f190c691abaf8e192e84a834b8c873026d1a8ee1758ed6457a5ec406511fe61a571bfff584e9222bc1954c588b3d748a8bb8b50e90314e2ccc62488891050fcd63deabbfa3e4235408f409e2a085fa679eeee70c4ff8f37a68b79df0ffbb6eec2f4159498464785ac69f30cf1335ea6f775d3e2063af5cf74b5f75a2dbb85e0d1b11a2cd46583b9bb19f90fe92424a70a0c1b3ca795e04d4087181c2748d4943ec8c073ce2cbec0a5b6f2597ce4af6c0c494ca5f12c28111139dcb05adcfa21fb5acba85e8d986851532c890588f1acfecebf925438d4b80768f2868fe7903c23054fc19159beb1646834da0d3042ac25bc2e43d50e5cffc40601487be032c5190ed4e618c89d7f30037805a19944ebe4a0db571860abcd7421593847b57a178e26b0b6aebd3521ce805c8cf04d9f600e8350328c88406b7f1e9f48a1af7ca59cd95f84d374321d6daa17f652bf247dc49528e341367a93037fcc6f296da24fdc09d0b4074ef3181bf1ac0296f86ebb2c902d1c9b93fa7ab1314fed73bccd53feb358a6e8652e4723685acca4b323e6ebec074802340d4f8c67868366bd1f31c05aefdf55612f998ba0619d64575a6db32d4b786265e8e2dcd5a40071741926b2ccd03d6a8401e3e0785d6769ae06fd42d8d3b3ac42f908639a8ec48e2a8adc4e822703d986262be89eb6da73308ab67050ec1005c9f276dd2ac0cd48cb2c51fa8b06e79c4155b46e6779746fe42a8651ecfd2fdcf45308866d7feee367e86fbe089ec5d52634b3c419530404fbf44462e348eae0385fee6eabd56ac1310adc104bd7428d3fca2e5aaf38cdbae525ace507df4cf77e4186b5e828e0c3adb6a36bfc72823018161b2facd32bd8a7d8eb8c9ab47be2d3127789a16edfbe323a5c6dddd0aa32a9190344f8cdd3c4d86a9cf8b0abc03a0c1cf4e42cefbc7981febb00ab30f3152b838309c06bbd6554d3fc4c25349597fb483c453d8286b8c1ed2981e5c30919852973b85cfbee5aa323f9e7b2a765cd28a90a6375a24b3b195de31f8c9d47f1fafbfede33ba3c55e28b4d2f1a341c2a39132bfbaf9d80b599e1999cbf75fc594702cdc4d2eea9b52a5f80819715f0bfa920f2e2b922ee36802c8bfa1cd75c63e4c2f8946ab6663189a5dc6ca126b8dffa61017357cd528a12586e08cfb41aea1efe0bb2842c8ae36be6a9f3ebea4ae382a56934dfd7d62b17e7f5245b904fd933d365d950487d6ab80cb3d444d89aa4c59ef83a94a8faa6ddb1e2fb4394a554f22854052f0c4fb8654f1855999e5a34c15aa3a4f7fe69e431b6407bc642263f777b315a41c24b403de78ad19f2ce3190e26592a190357a6d2d3efbb04235c947d1690d5b7b283de3449c8e8c2ba099dea8468ec46f8348a5b5a9f9b0f657cc601e5f89fce5462f53dbe3566347f2ef4c3dfbdf479c87e4bbabb8a3bcd5453ec1e85a9c146ad83f9570e304f708b3565d79210bb9959992787da4b59faf3eef75de7ffc7fdd4fd951af03ef112bb4bfe212aa8c4f190a8493cd6e1cf30ea6389ead3cc1bb411048dd8651ff11597dba91408a92a9137d3114739239102c1c0421f48a5f34973e3287b9081cc376b332772919eba34ccdb2edac538c815bb0168ea034c8fd6983e913491d0ffb6a7a5b40fc7ea3ef1754989058d55490ae2790b990c243529abb4d6833a077622e308255d2c4f4dfd1796b46b86db6c506b55bb427037fa390bac3702ebc83b41244cd8c5cbec5a14e09a4b64ece459537f046f60d5bb2d6d0e639541baf8ab4b10acb667f8d307630a787034e360c491b3cc53688d4faffb218c48000d33524008da0ff0bc70f34a351ec2c83e29f90c3891b0d48b3a0f93fb387a85701b552a6816f592e07ca1edba69ef4c2add48f4c97fdd9524ebbfd323ffeb7e459a49cbb44504f9b5dc358ea2f571a79b6c6b368c33444589934ce93c58f6684a52aa431f7b4c0d1a0ab1f049838fc18b05a6b5949ffe921d8d6297a718126b3649b23adfa9b0013f19166c1074810506f4bc2c8142616a4d5ac5ebb8cd6b50b6e78ca864a28dff12b249a405a9cd663fd5b2c292739a1b934a44da9d247a1498dc5a8de97d62c1e02f7fa82787b785facdb079c6eb4feb8a35f9bdac28d6faa3dc08922e4261b83572ab02978042166c3a15950f2fd9f2c13c844eb3c37ada372aeac69cbb33a05bb8643eada1b62fb96094ce9c467fe7680de764562d0b447a7bda05653dc3f1aeab027ad8b58f351554455a8b31113047cd701d0ea551042f1398b9ed7e72b18ac64fdd6850861c7881bf60b1e3eb7f101d525106e9fb1642fafc6ff9a47b8123427bb5df5c61e7852c7ef8854b33176cbdef3c7384636cbcc99a2f2f9801b91ef9bbbe2f26f330efef3ad02d4b16a1b52607d01c219c7fa64816a5b1fca6cc80f91bce59a60b6c1013165c95d2d0747d05f7ba09f4526aa54acc52dc166321876198de84eda457b321fa8f7c38667915ed986048631aafdff4091963cbccd1198924e356435dc08326fd17cf24676ee778b0bcd47296b0775404ac45334e5850947ddb3d4a8ba5f878110b89ab20d734fe5744bce263873ad0c335c392ee73048e64c51404aa8d330cdabc551e07519f32dc6b7fb0afddb1ae1b2cb97c4b727e8f947d839c4b938924410281937cf0739c9b6f9ef77ae43800aa6b695647d8760d262b0975151d876e8b721b88e480f10a2fbeb65e75d18c18e8a655b1a2ca13cdf2cc41b0fdfb26e17315d5cac4f4a71d2be3d11eee94fde0e554d8d68ba95f30d85915bd8921d39a24f557e690524d046fbf377034a63183e15c3229e5014e4c1bb8e67e841c5b9573dddac63fa0fc385bf06dce7ceea3160c86571d514d01dade6b8a1508380d46268a4657e4873e1c66b6253cdab8418a56c3487714192f39f2c5e3b729b5b0ab5afe68994c70546d964d1f6d84d8ff566347850066da16db9dca21b7e3b4760c4f476d026895f850afbb996ff2c73c9a17364c46ebb2093d99af0eb96303ff6e3a905e5871a65efbc9094afeba01ee365c7a6b46def61440c4a29a4f4baca29aa3877e71dc27116cdad1ca02f3e0e024c2b6095a8454f20b07b390aba9974b47e552832419e0eef70cb7a7ea402da7d1cbb90d3ab0c86903810a28f3e96a047d71571488abc678d5f6918321c362093ed4fc0a5e536724117692f2fd219b396e473dfe1797efd6eb47fb4d7c6faf3754e27a0576d499f2534cfdd2ee0e6b991f4b355c3c7d2ba2fb7270434c4f07e83dfed38b4a806edebe4aa0ea6ebd056f40fd3b37c44f716ca18185a5836aac814800d50258f6e14df50c595fa3dd141af8f7661f7d9d3ceeb14cb942ed7f41b3c2c946bed5372588f41412891962f227f3dfbe4bbf812fa4c6b60b92e52b026e2560f3a9777a905f55061ccedf9515c9ace4398e32c1b4ed6e61658c37f207b55c318de7a37611e997cc4ba453aeb6ebc42a00526385a806a8f523dfef4e93414121893ff3ec06505c095a27631402cfe7e5722d9d5d96e76807800ea8ef174dda093c4828f3ca41fd2b02ec4e70c97e350ecf7128e3fd64011eef796c799309cbd1fb765d2bbfd6f06b9072cd0b4dc9f7826b105c8e80dd8274c80a0fe9cd8121524c889b991f4fdf1c74038b10631ad1360d92986e141909b7a62d9692cd40156db075b1d450d043f4c11b92c5fb54e29981c300061de423ef203be8978dfdba969f8b6e1a337fe35b822f0287438113755baf2d67640fef5547b3c8386e2f69521a338f77dfb5870591c9683576bceca82b85682ab25db7d1622275f8f20b6614093ada99f077fc1d62ec9778b99f5d9e1537e0e6aca42a3e3c9ca0c42f34828881f192a9cef6f6de1220c2c3a00ffdad7419a1e3d33eb4622512a2fc01b797a7651fe8a5bbd2c00dbc3a880d2021bf87543f28c68b3eadd83dd40b78bc99362b894fea1948ee6ea19ef69ed4cb50a5a1bfbda64f57a01a40a19bbbf6b8d308829d35e037f08f264c28b6ecfcf8b0d29fbbb8c329c12ec3a2d91d28f7d7c725f4e212875ad9aa020754a2bd6ed3411929709d248ceb7d2b3128ab15ef8131425e551d564dd933601b8b310ff441bf9775ae1845e941f8ebf26668d18458a5feacd42835cbd9d9026481e2de0ce8e640a11f93c6781f04f91d3e7a1a8c344e3bb169e07f617d5fe5842e7f5dea7098124da6ce7a748cfdaf0ef596e98a214bf014adc8565b59e687d1d83e4b11bbb973a98e4ff344e9bdaa2b0a95431bd81dbd4b7426c0d6da768102409447ad03fbadad281cfa9bd0f28f00c9588e8b2136d727660746fa6388b145c1e48a8d9bf8d1a2cb766c19a00e5f00ba5d94b840c8ed4047b36f5c7c1b367c1cc631473452efeb317251b339041d7b3f422074ef2d231956b38d47f81bb0070dbfbafd87e15338db9742c0d11aa8f55d8747cf54ea373f23f232f0c1395888917254fc7fffc13e1ab7770e75a15609dd5d2ce6d7343074028ec1747d1fbcc36ff0b4e9b2acabeaabc88ad1264eb5c054a26ee64007dbe38cd01f9bef7d5ea5932cce8f55ba51e17604ae01cefa47bd19610e370264ee712923cc00089c458e749f2f065a8723275df31a05230e1236a1d1ec487b4a3ef0f55c005e3d682a9813db5c32401ab8cf5e0d371f775714affe7938d7a11f49cb7bc14ef0af9d99300bb302cf4d637bbb89b86f56bdf458689116b567a9e504d8631180814a6a4f8f45e06b2e7e1c71637f3e451fd3bd37098b29c170ff9e030e86cbb054553f977124c29de0149df774c264b715e0545a4717acc2431bf7aaaaa6996c92b3e3e85f9481529177d63c7dffc4e8570714e79bd0680b7afe84822e5ee7a0d65f28760da82f6f91b7d0bbfc1ec897d78e6b6b95f5354b9e1a00999969ab25672a5a3670dfe90cc527df624d14c4ea322b89e7e018ed5c82ce6f5c2e86bc50435bd8e9732186bf237b7637364c88d6b514cd463019b04eef49cf3d9d365a75c2780a5aeebbb02a4a470745281e94e4416800c4a041177a059ffa276404fbf1aa7c8ebb27a025192bb53ae1516b2e15ecfdb16a2ede5fa24c91c9099e66c2432e1e41b633a7f870ab82ac2c2cb21eb211c4b4de096c4901151f107c360ae011b7634e2111a7b4fa81bef116eea333628ed6b587c625f3959e56b66f80efbaf5feba058d00190ac1bccb244f801606bdaa28478f126efab4a1636e16ad2a91db8d5ef049f8461c39727322b3a692a505aabc0a35a77695cb52feadb8cb1a9cd5b0b23285c8a604cdf3bb10bcf199f3b18084d3f570a651f14b427e382f2fead4ddfeeb412ae97b734a358ce61413df20871e1b67df5165c9d69b05634bb1308dd918b6aa65319dbf57ad931826e9f19c6ec59aa9a15b60d41426346143c0e39713b292c8266dc2f2032f23b72efd32eccbff5063caf1019bb6327599c007228a60c32a3f7d94beafafccac5b93b8654cc0ab2347140983fab46dcbd907a748ba7656da19fc8bd8ec2be3ff9a93fa9424a24641efedc9f706b45d384a06c0b41fb1a723aa49c8b26a8a6658e63679386ee7b1d425ce722a13e6e45eeaba17e270391b955641c7fb026dd3454c79a09e07652bb07b8f2f7db5395d1966975ed96e2df0b2d1b7d161e8d7fd51c78823a8061e9d2ddf5dba55596518392c592156e4db8f8a124f16057afac4049ad68dcbe8ac5d99289eca892324c957425a0bd9dc7be0e1c93b2c75ce1b404a1b58f8f1f92cbef0487d0203b0621c67d19ba0eca1b91062fcc34bb93f72a71724fd6be58d2a71dd07e56f5e60d46b91fe89e8d5765b50bda6755f428e93588d9eddc3865b07bdb88a8b365051658475658b56d7026c10a20770bb813fe687ee1ffb0016bee0b38c7756990d6ec5d05dea68bbe91827ef8890e900d049d4cf9120c10e7768533a56dbac5b91e7a58b27a1a3605c64474e144296977ad70ab171ecd29236d14be526a386fec03dbf6530fe3db453c4ba18d332bd6aead56fc3270884eab674b924240a76d27f7277e200f898353b0eaca08a45e11cfccd51fd3007ec96b4463ffd5d4a8d095defdb9e23733d342df01b42894b9b4ce597db7bf6a151a52917b0d7ef5d273f7a16e434e69f164685b753615e4ecaa4360f840ae4b2a64a772f708a793ce9dc692a9d1ad773158d7a508bea25a9711b92e286b7e944a5378b2264a45ce0eec1c0374944dd56baff6c241493f88cbcd50e5918ed8504c1b6e706765518100f09a1bd91c1f7080edacd5c52d8eb584a5e4d3d8fd782caf12f19442b6f31934b4ff8762c44dd05e5ab82bd1d845711b1e051fbfb1d8d66e25a81ca906e21e228428d9605458e6eb19daef7a926fa01ade691ebb9d6f47d950d67fea17d1beeaeeae52d53feb2916da5e870c4d9c9e1dd06dd7fa233e0705c5360497d5b3b70515855660be6c030f7c8075db581a828083206733e826a81090818b02c2ae1aac3ab4f6fe021776d3d36482b754b3152568bc7503209e95ac4922cc52b84ba897341f0e9b6d5d77fdc240a38b00022703787627a3a7d0678ccc8ec675d311fe45cb0d514e964d653acd5a23da9d16474eb9f847fb1ab93cedf4a21ce64150d6b5a6ad693b53a054d7409bf3e6dcbefb1a8766c1408190459eca91ca0a0d613b237ab7ac8a5c6f03afedf088b1d3dc4271ae960424b096a9abbf5cff1533d172a9426275f8c524cf2484193ce6e58b28e1a8f86f6d059a4bfd1faa2260b473cfb45733dd7bf3ccac08d67cc66510dce11fd689009886d7b81f1c15f41d861c05223d94951545c5e6bcc63e41a125133420520d46b44a542fe6fe145685f92b023da3075b91becf45ea2feb3881597ca553f871114f26ee64988dbf6fe173a8766213bec43ca2133f4804caa99f5f9d6389a15fb71a6992cbf0edd87d40b8043c125b14c76403e37ce7166141ba5e4b8db84ea2d1cc6bafb013fa35ae95a44048b3e663be5175daf1c519f67495362bbced03a6a2c5e13ad894c53542c1bd238cfc096702c8d4f55f4f41bf316f9235a6e5b3ff26a334d4d2c3c3f82d2ae4be11bccd443c4693469ab7da10b20dc25cb244d809354778c2f2fe9b72d198cef497acadba23790b6fc09699b273242b9603fb2fa2f175d5d2d648ecfcff6f937e7f6832a5ad9cca3626565a0c31f7e38a47e62472de00311eec93c7bf5477cc42d89e4150880b651df3eb1a7e615e166b5ac9d368ff2f76c66e8dbfaabf98c73ba44b3214323e2828c42a2e68848a68e1d4f438f4b1b4a500075627ab6cfad8065bba23f8d9d6a8e85301d292473f0dba67e6232bda7e35e2787051ea0b422eaf3a6934288042e1febb6d79f2b66e0fcf743c104c6f06283534444b5684878006e1fbf3f697e395fd6d614b3f2b0d4d9b852bd592e3c0aa3e16518ca1f8664046e388d20bffe21558218a87caa96cdcac1634e02483e0a30d05da0f7ec7ee5ba2609110b7eed99cbd3d800f18a6ade1af01c817ea7ba329e2ec17fe5be9a274b37d7ec8f66e196a977fc42d560d913dde3344801a920c90b98e804808b72691e11b59ea9afee231165c17a4adcfbd6edcd08c162b2e6a2af6e58ed4a2069f095f42db146d6fe7cf5a2b0b30795212d4eed9a9a919b1e13ad23aedb69a444c3247fc02265580b84b0d2be1c536667ae71296dd0f028f62fe9a78163c84bc088a77dabbf8ab48fcf499060e8af50f2ea98f929aeb050903b6569501aeec4c64ba7bf203d247900a85f8e33f9da71f3e73e4eecf8708b0f4cc2b1e62c0bccdf6fa31ffa19f3712bd8b36eeded6f8959aa7a9d00c6dd56c7ffc9e1a5f35f2053880b05b54be7798a408db497e81e50cc71170dc70c5610cd4b3b706e859c163ed30a44c047ff3690efb4471d17db8a6362725d01e8698d53bf64c09d4a1ee917304473d8a0247fe7fe2fe82a8211c9421904f4a75ff234fe3fab154c7e3420df726e294dec2d09ba13e5844400634717d7d098893a7580a72f8243f240c954f18c64241bda05605e9773e6f6ce4eb3508ea36659195e39508eaad436b2a96f52c3badcfeef92fb33662451e854ba7d24e8a751c259855e1dade8196ffc0be38ca4fced35e02a2f0200009848c158f6b2d56f9d5818c4151aa031801e85b563f03d1cc98915c3d4f09e361e2103eb43d1ff8ef8f01052c58634a601195a27e3f94a8d4e5d0519335f17b9d50175aa2f008eb263ea9ebde494b158aeb4179e59c1f75fd0de34a148b674046630729221463d1a605cad9714155f215f70559f5912825dc3aff954155c1ed468362c0a30bcdb4fe6fa010c6a753e841877a8f2d113a85675e274c9014648b303fc6fef7b94076c57cdc537fa9f94610259db227bd4ff2b05899567b0959e9434bea2c1eb4373de0e916862f809a94b312d44cac483a964a04709284889bd3fdc1d57c96a27c66f83632cddc215334fbab45bfbe8d6ca8080e72ecb0ea946f068a161d1d93ff58b2926f4b7642aeadc6ff7033cc1e952bc72ac6c81bf2ca5ae3a542a8a01838e5e2bb6d85406e22553d9863d35e1275921aaa521156414c923d8eb08c46932b5cf787dda53c9cacbcef70cc444d5c6cd469518ca80098d0f8fc7353f9bbb79120a2e279067818935e60c4b95d56dc99a21dbd8014f20d8c826077fc46db10dba9bb6fe141c13872d0d3e7b063ea0163633ff6951dc4627dfc02bf1e489d096d4fc3eff7ea5792568fcc63ba664c45030f76800e0ad5f10433f6675c43ab29032a3178195421e35f0335d0c23c90d2edee3a98288949e230ab79ce3d477c937d8eb7c385a72f25057caf6bb2651b68a3c561bca8a471e7c5b275dd4b6151b35ddfd175e99cf736739a8c77586ae627183a74370363fc87795da7d14fe5acb68d6e043a0add6dc3e34c4e85f9ed16c9e5fe2f36dfb6a879d39462a436f29e12d779d58d0bd5e7d8a87e11151faecf4f8ef2341ff773dc8f2af24785e34d57abcc15f07b2317e966d3283c9d947620d0fbf25ca686fcb5976e53ddc3aa8bb620db215ddc5b8f6bc2a2ebd1e3af85366470d864b75e8be3e4114fb54c6547ea271e39e9b0b00a1528da05699a206c6d9c7196c232c299c94e4e500976efa2290dbbdf2b1826cea2080f74431ca34dbbfce44097baf5f8075d10cf23f77b0aaf652e5b20972df12e12ec639a9f9e7f7cfaca269e5760e35c7be3454a9d882644bfcf10f66d0606c5a1df42172e98412a98dc1cddff94544fcafd52da63dd2a2dcf87100d721e08494f86deccf9cd74f8c31f53ea239ca4685988811ca7d2f3a3dc81acb77864b422f717dc66ebcdaf6001a07e4542267149778c2e1c09d670f6b864539983a7c934e3cb10a4fae45616021d88c90655407c082303e8d8beec4bd04de3fa7c8783bd87c1df6e33f57141b0b4eac383634e43108bcdc4d813d85b95d782f3408673e98bf0267ce149431bf71ac4be830ad33affff344b7bd90c08ea8e39fa019083165a0e9d6a4143acfb54a218d00a7a099e2f78e3980a1e798be159b3824f45d7ec11ce1bce19479be4e3462bf1e203455a1b8872ab28e92ff3be4ca54b065f186bfeddbdb09e7000a29475f08ab3de00f88dc4d09dbda8e554b59c1d04ff1e363b1ff4e872e54896ccae5b3051dc17de525dbbcfca076001c0f661f1ebdefd037fefaee4faf0d4e7d48f787b17728fb5960dd1a31de59a6d66c581949e5901469cc6a45e0b9c627b92d3c44f8f7869e7aca131dba02217a6059204089a746bbe21e02ea1559f7a39f297e8bb90c38c8d8157f8154b314c067e940f45405a60516706814edc2f657adf98c87a43a463d35e5ff2594c3fd79144b4a841e2dd498e1ede9040dd0208c1cd78dba1b48ea8f372a26f67fda7f86124ecd881d062138e777c49f14f7fab1649c81b44cd363a874743ece051cc6285d452f3f939497c22991c78390405239e1cf8a56301827c6fa369e221ef0d45e165f042a1e07211ca25115f0d7677fdfc48fbd54b4a5d2081b206e61978748b627467279efebd129f20dba13f8ceb72ddd9dfa34fe26ea026aa2e7d4118404ff00129fa8378bd500976d136c6fd41c779c3824df3eab5e0a67fe24ae0ff2b26ae5b4f0399d05f9ac52281ff220b48b3bacb253286615f8ceb565afa8ffaca6d791675806b59dd6b9756eb62601458ddcae1a51465a5bd2c71695b4a0a83fbffe428cf97f04cf574f2de3c24c7b93070ab1a8294f90f1611d95d994cf4ae65aa2685b4f3d4cfbb0b24aa58aecd273ca7f8458414e4e4646963e4ecea04d73bc66048fa70b4393cfcf2bc0a32fade2e9f6ca5bb1768872b2d512d33fb1de305da9d00291176b9fc5a6611b7ccf1ffd7d05217889a8f63d4a8b340a333384e990efed685a066baa3cc10353f3a84d319d4581468d9ab48561b9db73bc8130a6b9ea3c952cd7bb048fbdb6ceb9c56e4e2ecfffd0022081afa2318bf1f84fe1dfb08fabb04631e3356a89ce88c0853b495ff2469f5dc015ee1c591488158e8e622243b58114c6ea6a609c40e0993bc1daa9aecf6b77d171ab7ff903be84eb1f44536a7b1ae4849f2cd8af0be36a0dd815eb29632e339a7a847ddc8c52739502cc9b93287bf26cc50c1d56a4f522dd5c9a1ede5c41a50b6454f745880cd345d84fb56e1bc539234b190b67dba64e9b214209a5ed89973b13cc9072d4affae991ca5234fbae00321a00500b46369fdb442d28a86795e2a61553edb7f77a28c2da7ddbad24f7f8f8fe0821da76936f18150fefe94ce5529879ffe695c186a09f13af7e18896d6390558a66019e171477b0c83cd7b63d3f69950384ba14cf5d0805f2caf5c9765dde9b37189b313de555fbdb141b57bb87376fe879ff34125503b73fb379d8a921d5b020e058ec704018758bb20650eea8add50ed90fdb25baa1c4689aff58ef2647ae9ccaea70a935681fa59154a3e81a9156e3f48f5a95fcc0fdadef57628f0614d8271abd273af3d8aefe29154b2ce1e977c2a177ec0e81a58c1ef145edaa2f836eedffd672628dc00d1053d807d61ebc7923c369ce25f7effc96866ddba887d7d5d08013d87121c7e1736295e8a877c135c9280a1bba7fce804b7ec84167e2026f038947735b605b4b6ee6339ef55cf2f4428e1c3b331b5e4eb953d888170600cf39f2dfdbb578b1ba33f2ff1a7b74e1ee2a20fff80211c474e60147753d72a40a655379f9900ee1feb67553ef3a586565593c6dd9e51cbfa33e1520b6e8df8523245e26f966b89c277d47da40e88c690e05b29243478ffc8985a2f87f9fca99c4a6393e3a9fc359f802087ca79f7878232fe6acebf862aa3a83c67f42424e96837a3ea25271c3ad0ae1d2033d1c598b6f0874942f2e8c2439ce44f93125b1b3c3ab4b6f258b293e62be2f8a5ba3afbdd0ade19dd66007d69bf0c527c889d34cd325daeb2d7e4cb3433140e9fee0a6b7f2e8096792c1093e914ff84f3244fec7b2def2b29ed27de9a6fb2d9c120e9d77c78bac4c15f0d60159fb539bf750310070f1a1170c4468cb5fd0fec04b6ce3648164ec8e1364f190c7121e8fe6c94810cbca13c90ee29888d6f920c2636b4eb8bfd92a2e4c9c04cb66d15fcd35656922bcb6ad43ef94421d70c24fc305f58312629e7c9b4b510b0d63e24f5375ffe9aaaff3e351a99bc2f7cf86da91d093b8f19a9886907ffc6ab687d31e6e50bdd0e90b32122a586f0dfde0eef7e6567fe8189e8c604b22aacaa6d7c402bd0dcb5bd656601969ef9a92ab5aa3ab51e914613156223e8f26ace74ae2c7518c8ad1b36ee3e36835cb9282c281aa3a3f477702818edafbe202598d822d124ea846741da3d12dd00d850ab0b3fef3c71fd1d9d0317a778bbfbbb36d44a80efe9f4efd60de03d83fa97018ab62ea05c44e9d3c20b75b154f407010902326225c6d3f1722cd64e764c0cde80399dc66beac9de2f86eae944d8c138405b995d8d696e498497c542207e8d3dc8afdc5aaac83bfc8d3b3a75d0cecdec1752df8682625b3e0b72fb4f7a4cd8f2f4beeadaad4265f3f7431d1bb1d12c302a8d4636d5f043a34a1620c0abca58ff160a80dfa3773587f6f046c758f14c70191c47b9eca63060f43134e73d915091d0118f0101de82f9fe39c9f0ead7b2ba2e421dea8eff855dd6c6f772d781ce800bc772e1d307c4dba04ad0cb802220f9911a8aa9ca52266a21bc3e75cd00b58e6b60fa18aec01e7689290afff64cc6fa5448d085c2fb154519a44e865f7cca56337d2c74e6f1136b8c3f419d875ed7ba40b6ce0c639d32f0763dfc59827fe324a44773ef2f20e248456411102078d93806180693f6c6faecf1e093cf1d089835a978651addd631920f17ea4ad306b4ece24e449ae011e0f433c40b26e1a0fe20a01cf83bf1e8424bddd019ff91412de24043a092b261f290db2209d23e9bf7db3950a1e89c69646984e7ebc6b5108d08bafd8b30cb3978759219b5ca5a375686ee020e1e0ffee6851e10536fe25e8954a762fc4fd73d08c509089c29f1a63c55c77e48c6180859ca686cdf8c9cbf49f8f668b9c7545e882f3e0d2c2038216e7df36b78118b62ed6ade1bb82281d18281410f78510dddad14263085fcd7261b5075a94211a49121792dde077dbfebb47b1d305d03c987e3ff2b88620c8ab3566d75a4a2f45e73d1961243c608b4ac1917df9e35a96a949fc8f21b5ffc71142694cfa8ff8901820fafc96a4eca12c304d52020adc31e2299e95e0df5fe3d55ed206eccf29e2e402ece0aabdca1e0a8bf48780773df3b795b24b459966f0c4728a91a0ec40750524877d279db0ae479e2905a095344c4798b164db7b74e080aae0a1abab2dd971a2c62b848a1b2cc1cfccfe9947bcffd997d793702f96e28db75a9cd83d6d4797ddb2ca2d6dd89d35c1d7d791754d2652f7e24502912491b7f96d4d9cc85a9f216fba299076fa5659d6c32543eb0b06c1dd3121cf8420eaf3bf644e4f52699b6a4afb15df6adfd0711862c822df4368e87b5e9a9aa0310bba1afbb000a8a7ded51fa90212ef52140383a5a29990518c2ea6994ca05a1aa8f88b4e8a9959b824a890d0eb7aba004e2d274c7ea70f4916003909eb0fe20e03c366826a7b6b5ce676fd24752ec7a6c6e947193cea31a5e0b22344647346950205431f86b700cc3fa31741d33b3f11614cfd215c2e22937b247680f3cff5e32d04d9c00e14f20453fa4b415ee156e97df42c643c4f534ee7bb113eb631407e854c0d649956ebd62e4bf94cac7ce77163467ae40ad3f86583b4db418d7c329a2aec4f7b7e790b5c7fdbf851bc383ff63cee0c03fb5e3e8026800c74c55fb8e15fddc0d6089b07eb8490dc34f3d35ae51b748c56ec56b989d9909fcd08b1f733266e07cf2fe0229d03f96943d7d09d6eb5c6f06bdb8be9e919b2ef4d1e6f950b425532a85a9f59b84b174a4581944ce586d691c89548b6c5ee48ca8faa2ddd6294eeefcd3406ca811a52e0fb8441eedcd1d4b55a249b54fe630de32dd8739600e96cf2deda5e3714f99393af4465d1c0472aafcd7083ad023fc48ae86c10984255cf6b4c98c95666242868ac70ef8bf77c24191115b991cb4fa0fa2a76907bbc8f74b909ef3dd0764c842f1bd30dc10c2cd7fb672456203c963c99cfdd145c39e501bab4781db1c38af948ff3d68251260b96ad6a49e011ad25ac4a5aea3c3e9cf02ad9f7d71ca7db2c21680d32b62a2668a720eb0490fdf401ae6c5af36b8c2b6ca527acbf4fb4afbd1986c3d1cfdd1c54324abacdaa5476914faaeedd07ecea2bfa66b793c6606055943ace585b8dd808e2557f5a588bebded380d3ee0cf837fb40fe4d0b1a5df797693a17a86c5fe8564692ca893bd86c593855cba070443ed4aee9036df36c351575398034879f517248af791f140e2a682458401bc9c35fb6d08cd67c5c7adedc534d9ea5f9a249758000bbf4cfe44b4904b1e4acd5413db960f5cb969fffa9ef675ccceab6e680bdbb671bcd39cf193b8bb1de909fef0af567cdfc7d50c5bcb727bb74b9425e5786e82cd98105131211516cfb8777541f9d9b890e6402b12e7dfdef5152e8fe046f326b9818a27e2a9748769d0b068f3a427e8fecd97d8721301fbb2a06139f36347aa08dbc5d784214850a9568279980a0f0a98792bbf66e7e09d33739919aa568f7b0d5e0da0e728d7a02dd8a482b4828b7b0da93ce99b6633ca79e7acf19f9639c1ceaafe56c1ac1d22a27148a66e2a8aa1f158af5e53b0ab56c5a3d28ced2340c79cefeb0be5a3a32bf4c3cc784f352fbb79f87513c63b11d9aa9b9452bbb715c3da69e6dd20f027419bba76169dcd70a4fb2b6edd8e2baa7031b28327c55abce2fb268e2b1d9da06da9b468487c73cdb17e67e7e87640afb0a0a7bbec8689b2c18200ae67895e842df263112b6efec05a3a67ee9e23a3678168dd5425e934e2004b82072d4c0625630b2a0dff5c0bc413327d7d7eb97241db2393a9fbaf976a190afc86ed074d3993a9f4b76c9ae17c43ae5fb05ca7664190b2608264673cf201fb48d0b2db6fd6736f70c6c0db4de0f0847f2e1364b92a67201a62aa5f383d8e9fa6c5def016dd322ec140c48c5d7524cd11f4fecda1bb113741b43362abab645d568cb336a417c5bfa5f32fb5beed8dd8f37de92cac9c4227e17b88144546cdc02f48097dcfc1d79b46026503a26717652ea472e0de14071a81dbd9ef925a5a38f80c5a8064683b71fde9f6e13f8671b56d38f9518d6192092a0ba1e2d1bec797aff5cac444a8d452e83b513d052a0c88a9e671992fd249ad45a2a319ed49c3f8fc89c2a5217a5379995521663b417e71a374a2ebe71f8cd39834a667c06928e9aecb2fab560f74e4309e48907491dd422ee763099c47e10e0b112e921ae35b9b6da2083bef45bcaa9a7a8afaa0b851a72d9da0b5334f66337d038c24699d412ca666bc03d811f71aad1800d675b718e1550de60864ba2b6a4ea583f055e3e1b8f5faac93e6b17a49ef947118abbdb4f3e1894dc09fa6743744869317fb13587a0de4758aa2ed4d9c2d97e143426113135d03a00f19bab5eeac3f2e18b2f2c2a86f767ff234197cd67b2a4968ffc26bb7839a837f0eb85d459d0f6543bf8f108f24e7e149358357bd079b70e8d3f46f0b77363d6868bdb637d7dd8af8397521532767f2a254e862f6ad037202e26a9a1f99cf46848698968e63d45ee38504d9ab68db5e16ac2cd024ef4ba80da091572714d9ea08b6a1a0e5e83e8d43e9fcf6cb2eabde1bbda6cf668e0cf78e3c75857dfbc8cb9cc9c8b6c121966dd836d8edbacf12c1aa82b4e8087131d9c015ea0e31506adf0b33a4c7728e625b997363239585c1ecb2106c28172fc8520b661fef82a549f707d0264c353bcf68cadd70df3ee89a238252183e040dd6a4dc51a59e681147ead6cc558688d54841ab2d88934fee8f6ac4f73048b071e84b4b066618064ddce72aaef4711cda80f23bde082b6776e08d7772a00d5b89ccf7a91c8087be29770f68b7c928ac9f60f85903c63633c575b0e07c820c7e226f683fc5a0b14df3b43476d5f921b443e0d21678b0813cc4688c8242e0ce490fdb1ecce573415c2b87e4293cff69bf741940125e37147852d4ebca1072a71a73ba0d1efd25f71a6875ec9506cfe0182fa76ef26ffa13cb0fe37035d8826ae7535ebefa35c247199919d164b8cfe2c9473505729b7c17a86418f66abd5fe4dcfcaff08a70a456192e21616e81d997fecd8a8ee783190c3791698c3fe53e6f1da3f60c5bf1bc42d1120206ce0897398f0d5bc1cf5b27aa4501c1d51684ab0fe44369bfce8c0cf92aec0d75dfb8d4dfd90712cc5645df19fbb316da65da34b81065020fc4f8a27005e2db78d4ba2f4c08bdf72abb4e88d9fa3f96995dcf494e21a5b830d3ed959b99df6c32e0563050a1512d19eccb692f4e496cff9fccdf4601f498cad6c83de6fa1a5e385fe6b4499d744fda1c1ee165c7e6166ac9e7db818be7190fd641581b8fea8687f31f2b9efa6cd3f8b01c5c55270f7533118280eb283238e50b16d1ec66ca135802f5bff49af37ece6490b41c0ccc51146690bc6f8469deafc8848d8e5e64f05e9172ba4abc10f77d425e0dc6d213dbc95d3ff14c1a4000b3024a61fc2f5d8d237e278cf76f87f0de3c4dadbd774a3384e0cfeca13e7dde712117a86224424978a8eaa90f976f9f62e34de06115adf031620ddd63a477c11183338bcfe47af8e0ca0f2e3c3b012f2e1bd54747477754c82a1ec9b4b5b80220bcdbd6b66363a1f4753b99c2a5ec49e6d384a31489ead191ce59047ceecffdf33f21695ea04acc6cea9c9145d66e481f5df582232bf44888c9698ef08ea3d46d2ccdaf905a248c177c07e00e4bb52e3d2bce1277c99fa4ed21fb8bcfbecc1b12f8f324f1e000d797d43847a400b248c635b997490c62df7b5cbc11ae8fdecf93dad9014e43d57953a0fc51a988ce8df180f2e8f94081b257d7d18cbdc56b9f6f7621eb598324e8d046bc605572b9ea9b0271ae6c4d21f04e4020161635904aadb09e9ca799a9f582e74022ed082c204bc8b593f23e84342a35dc059a3d3794cec694ac2c52be7cc9bd099d978bf2d8e9aef0266e60b9b06b63a60b542ccc97e5073f1ba09315bc0173dd546aa844242009cd984f804f56e8a46f568dedf741130153749fe7d3672b0e65bdbe1db63f33c2b23cc361a9e02d469cc99a228dbf0f962ec35cf332c458c678eb8a235644423b7a2cad3cbc9dc7360ac4a0585ab2b4adb1e119d8066e32fc474852f928d765b858484c88c8cae886b4751cc86e2fc47516b2ccc445b3a5a1cd561596a263b245b502d1e95ba7cbafe8c9be8eb4540e4d8805b417a7dd1bfb3de3b765f68058d13c52a7c47d564f82bb382bce6fbb9645cd57dc51a611150f8fcc4fb630ff7fb527684eddf36c3ffa0ce506e4081a7aa2c650fcb942e83118e33ae34a4ad409a1a4add1e3f4f359b6f5ab6778a2e6fdb55612808a0395922724688de556144dd1522b34f14fbb3d9382f5ed4cd8019403aac2fb7bd410f4cebd9f893a50844dc0017cbeafc15d51efc368514f94ffe3118490b2884200554b7fb404da252d5b027e7dc79832a15071fd8ba1c359b6e382881ef8041601c8b83c28c27d6f3312666907aa996020306fcb8a342f78c12d5d63fc57715213d2a11dcb891fdea859f1d9025ba7f8d3b01f2fc9611078b9744f269a916241d0a0aaafa4d93ba576b429bcd3acd2b6f3a44706516d9e7201c0d4b9370c818cf6a015e252fa6b1689a5b21613af07e9b1e6508ca0ffa4db2f349a65814441afc10e9d8eb51e64bcb34c6c09609dc09b8de19745121717e7a885283d58729c4334aee6bea7434709f85baeaa2d8e706f611c7fbfc445217e918153b1a9cfa5e5f3ad076112e90acfb83cb6f86a758392df630330ef2083029d2589135e8ca1e10498ec6624d74b20fbe07a51784c1f9f948e0bdc9fb33b18d37f1a2af05aed383cdf5959853687bc9e8563db547766578e3227d81a3feec6588acb3e5adaa1e5c1e6607f9a880e01f569450d066f08da8067924627695fc0090e433b1323e68b403a6e27456004929e0b50083e5cdbd0a799b5ced4bd89f9002287b89c42ed3d127f3ad5f25c87d9eef228cd5df4b8e41246f80aeb4ac7e5238d001e1347cf1d6f8ddfd7baa07afaea7f00bddae49a2cee567da095d6515956804feb979f37b99310341dc37f47e25474516a1b92c9cfff71948174e7523eb43bb7ddf569362645d448af15946147b7f855324a18ae2c65ba2948d62136a1094cd4e58324d946bdadcdb9ead2552f36406309bba43378d8789f0e7c73fb5733f2fa007249634c2fd5944e05b71cf25ffc0973ac6175a787f34d270ef447fd5fc1daa7dfb8b6ee74304141c497c10ccd892cabf9e96682facd0b4a78a539b3a5dd8b3a62a76fa9bbf83559c639be34a647bbfbf7918abb5361fe65712787823ff3eab34e7cca3a931d97b311a74fbc580a36b720169bf23f7760a075fb845787a0e81ab52d33d0b6ecc7ff712f6e11e25380df65d156a16c454a26b733617096673caa1fdb024b38b045763056f96924ee2af0235957a758d2860bfb8b2546be6d0a0745b389fc3a0f84728f3d7f87f39a2fa6fc69f5a5e22c4822c79bb82a05decc8d76e6ab7807e7ee304d340f03b0d76fd9810c2673a8bed262fa9486c406dfd870d08d922393d3a83bc738b7a618a8b14a0678449bed7615350d73b95d19afca8707fa44c1a0fab0967cd804b0841188fcf609712a2c394c7c603edbc3bfeebcabd89dc9f68de21af1b4bb4063e154ef3ed7be76e76a38ff3fd1420077bb17a762c97a77c276a2200084334e351912815741d0ba6c4f5c31773acbd49d5d064e5cae5e38ac7d2cbbf3336a89cc86cfa9ab87446d08dd886a98ccb38ad428ff6d88818a92c0f48945dea048ba7f0d2c0401ce24918128a37e9713d8f401c5110ce7c6f5a30a888ceeba31032f37530a78a9faaad835a0de3467b4a638dc68e0f2eb762b44dd51999566611e63dc86fc9a3235f32807284ff8534e6785f16f9689b19d20bfcff3bb30e8c55f9cc164988c11a3cd062d0e0e9b6324b9c194f10f0c5dd050247e4eb8bfc754580e506d83cd7f2cf7da33e01275c7c4b8be3490513e9efbf1265a336c58a5c0e13c1e908143f4c02561ee757361625108f83e90d4896c3d3949dda059ae386d541c7ec959b61b05d4401d906efd09c90a28749fe068f799b34bee39b6424d8f192ac01a71ec660c84d2b505e6cf5d2c8f4d6cac7350e242876b1f3354b73d1715e1797f89f3d42353e01d001f03c46d6afa9e4faf68f965b2396ef6cff4f4715a639c49e5c15339a8dd708dc0bdf6290ceed70d7d9f1e696031847210e0c08abdce65dda5f8843de7a1c230bcf3c7bcf87cb244b06ad7129a65bebfd1b8f3da73060fdf28d441117d35157dad1b5d401d25a4306eacfd27efb7a96361747865876679d0818c1c90b89dbd0588d4fa646395b95d39ae4e6031f55b3ec58fecbcf6c341f0daa256b785522e557bc0664c39ad475caced09f31b9f49afe87fb191ef58ba5fe20f8fc6c8a9a88cee4d7d76db335215668a919fa8edf08946aa5849d5a2dfe48823af0a545342c1a5e7236b067239624fa82ec17e2d2f3a1f12a69f316fbb5b95a44eea5bd28d9fe2c61c32785f566ffe78a59d5c62b69dd40df2d4a0d1ec44830a1d11e9caf1ca2d88a342511761ba338648af9c3d08604977b153776ef13895ec3d1c6cdcbc45993ed3fb99b7e60b2f27ce5a813958e4cf1112cc7b05a3e570b9dcacf52457d61afce190eaf6f88b0f730fc20c2a9cd03634022f312e33c7c2bb2f5328fadc8b72b8a94885ae8bfcbdf4d7ea5cff58d0eec5d3f8a41860619e5a3a28ddc69cd8f65936a9eec81d43b0099290e47621c7904e5283088a01d8e160061e551af996470463efe754c536a75c1a8c59775cd9f1474f09159b9a5ddc0a28ce8f16699c3f47540edaafacebc3fbe9542bd31d2474d5788873a09aee420d78020cceedfd6327ae08f6ae393bc0d4102d4ece05e6e5886a8b108ce2c0b9a7a50edcd05aa5d88f84659ce1d66524055f46931c84b44b6795ac792a80ef365dedc4d8b017586d745591639f6da7b9e1684197356432121d811bfa87e082ad34aea639dbb643b9053b916b982a6968ac1a96d73bbda35c52750d87436a3ce37273056079d33ba2af61d3698a1efc668ee87e79ce7098cf73259d84d872b7e94db57a73b0cad6f3b289d85efacab1adda30774b05a3d027ca454c77ab57d7ef33e2a4a9e2da3e4cc64c2b4b2f38cccba1a7c584e1f898f7cf869a1b1391072963d9a49cc0b026dfdb40bd77fd51e5041d132a09de547978221fbcba6c72f9afdbb015c14de5bd8d052dc40bec9d3fbd27b7508d78f3e663df55ed312763f774bacae9076c5f06768a430830e180dbbceac62d07780290a3ae58f53a2da36b89aa9b989f16c121203cae453ca63fdf48f17d985df255a9ffb584cda5e3c83945b7bd71e92354b59b1da7f96f29c92b11c72f2545c88070a1f724e721a63fe23de13bd8854f8e87cff0757819752975156048b1db41a6d18be4a5ab9f6c77720b4fbaae439d8d3ddc377aa4bd82f631305ff45360f8935197bfd5f28d7a45ddd6ac6865e93cfa56b3612a1201443e1c0152cb1e8443ac47d2ba664a59c6a7c4cc766c8f300ce9142b69b9a8d1c621044b41f02a724786ab223f1109a5b7bdc2a88a8024ce439044da24b8879366b82ad257afd1d943b595965243ab0d9d4ff268683d3f64f4a90ee07c55f99f1e7b5c64ae99bb1a2076f82d468d38f83d54ef166d24293d02fe33ac86f28fafcdcee8c5f660e226a8936930b3ca497b7ab1215a98f58f96a4089528cbdfe1ecad569b7de3f52746342fdd26e4755f0424dbe023bfe235ed90ad73b3ed194b34c96fcfb4a568a3cddec7388527f10c8f4ae61a024c8a74cd0ea182954d3e82418bfb4a509132eed5b6c5c251b4d1b35038c69f00dd8ebff41b989da0e8dfff81c4f4c2bffd7826c47b91ef958e84c40fb83050a8cefdbc3c6e4be763ae49ece48cf1eb4819959a86f0faf21404d951078f717c8d963e77af39ce188ffaf1d962918444923b548c5f90e9aca23e8f50f50a6a17238f7314306336455c51fd6f25722df08ff3308a479f3a082c7f9b34f96759ca8ab5d338e6dec9f374cc65ad7043448e0e3da14ec441734e0be7f108d7ee1c7f19bafb5d404c1375879fe61f7bd9b0a247afd7fa8cebbfd3b6dedba5fc021141bf914d46fefa8e8708609feacd6bda97f3cc9b79d20ccc23e4bad4301504244d19b3ceab292178daa47a08d46941da6ce9d3f29047f1f1ebbcab0e286df5de2abded6e70b7da6da84e0723e233bd270a0d21eaa53349b229646f81f7f4bac524871ea09c1cd0c663feb3fca261312627140eb1a828a1cdddd3af584c8b39b2827f624761184c0e6094a7ca2a85978c49781c1e0a0ed38d200ea795a8c60f0765ffa0f11c949588fac20fa4af2fde08ee9e6cbe3b9fa7967ada17c924eb4ba161c21b0f1436d2a32248a04cce90632796330e5fb7333b77dcfd0e726b2ca0822b114f88eccb208da1115b7e150d54e055c02e150a917b4d820902252011f31f2972ff27fc1006fad71af9ee315f96a5fcdc5f4d1c54b50057b4a26e18c2a4b363561f3ef50006314a6ef32482960f403d6d372b82c8e796a4d485d36e872de80a79f523289bdc0a9aa5b9c1b31e536976f0ba3824fd52764470ba29d416710065c09de6f0ae9b02d719a91085b64d64c955da8368550f8974a431438f3bd2e7409e497b3a4d106a1174e3048f04786c05dab57b56104bd243907ba5922ecb9e29fcec5d4b7bb9527077a4d71903c4fcd80a5952e4603173d248487e78fcd2135645f19bf407c4e2c1939c5a3556ca004dba6f9763ae91790e54c14ea5b5b94a4b7c1110a2abef49916a4758e0878a1273e2dbc2168e3daf0097dfdd5ba0a708d18da2e5ad2a681ce0860b44fd54c18e4e3d54c54bbaf724cfb4b6813f6af51ecd968d07e218c44fbd6879d83808d5c2a0d081b0b8375f4388b2f11433a22be408dc9c8ccbeee66ba7ff3ea5cf8086f3ce9eb080c82b2333d289549ff37b5f9cf184f2a814e854914878ef111bc4b64322cd00f1ba6e588bf3a36708950ebdda1b985a23dbf8d04cf00f96ee0aaf14d606c4c023b4fee2072368995bdba5916490e0334dd0e4be9d4173bc07d1675df1744e4eca0990c8014fd41047c106817cc4fd17f7712d75328da168187d68055b92f1d6db8c1fcee36f91104a74e58a8abfa3226dd4f52a310c92acfa375d4be860be47d0167a636d1ae42bbbc8da57b706a3c3a2b477f3de87508e2a76c8abe9dd08f04849775e505f0b3052785977981170f587cbe0a64e0d359ee0fc8c3d4cb32f4512d9a7cbc4cef07a1196ad5c37369504f72408d8702d3d8ad640f7046e7273be66afcd14311c9a5648f521183c6b368c33f477cc5f5f39e87c264c355930a4d91858e402d5f7c307459eb58e37f8bee393eb851e201e58837d3474dbda28f2ad63c3ab41de95b03ed9683d9e06fa121a092fca168d0ee9621028c7ca956bca4166e88550c1f99fe6277379247d10662d0a1849a6e95b1001888fc3d0f82281df80e4c32d757f48010eb7121614d4811acfbf6bf8ccca1345c11a43b8ddd53f0693c2b8d05035985486babacea2c2ebc9a5da889f25c07adcff219cdb54cf5fee3d0389d9111e581d2a6f6860821e8461cb37d65b055e5b445edba4e72e81e3813cc7e2ce2808380f5b1fcd344184c21c9d816c88bbb7f6f0174689ee52ced91322efacb56898f672eb8bb3bf7fae47315dc64853d2738d83b04248fc7efbdaeb4abeda98bf0d09c5c56a1ec5b4d19143cd677b8adde5ba1416f71f01113fdaf3ac8caea0c81a6ea40a31631ee1370be81fb73bddf6fe412c8ca7e86210b3befa01e347e5de3a690f814fffc8652fdfecbbdc12cdefce4c73120d5f51a2aea265d51ba03d412402392c581c6b66343a1358b2995c28a38ce112df71df301b0dc5ce2c0b7dca7fcd7fde2e05f723fec07996bb23a2ed99a28d27abe8268f19602fe42cf3ba352021db640d9339b8de4e9e49321cd447a39bd9f4ba9ced081127381d699322ad19abf33f48fca4af7c30403a1158a0c9831fb01e42340295268ee0dd402e9dcf713fe2634f93c480ce91ec5075ed1c7888b43e710038952ebc4bdff443105f43f745f85a54dff7b418505a1edc8747a047cbccb1ed036849c9c68e1d18ac052e3b50a3d01e3d397e378c65341973cf879eacc072272309def0af9921cebe3631d14904edfe9e7d7888992127a925319b9c4927fee66c646f4eedf80e262c87836931a71bbd69921d53b6226b0787e9bb3c5851b317768afa6b2b9cfd55fb655416af6b880cdf2170f8633f300516ca37b391558fa975e5c737ceb32b87f9e635a5f702f51bff7d0fe2d6252ea581888e8cf7af48a9a6cada64a1c9bbffe719af075ff0ef34e781904932d58ddddced10119f114eb6b4671ed258c835722ad8c806e8e5876995f88731af50fd001da23c21ce210bb1c762be1005e787961f5e44b8641f0d37e3bc7572656cfa7b671a681796d6a9fb7532e6655b83fb01f5c67004943dea551f73f6268bc4863f7035be9865b8a26a55bab8b78b1ae30e55b58768a5b1288844aab41fd7f418abebf748ec13f2d1211a83a0f0fd3668c0f4ce041aa4e17c4bc3a7d8da2431cbd94b4b26b19bb87afdf4577428a2705e7b88fd42c96f0e692c8540de894b0507b3a7567980cf90c0902f4d5ab9020db63356339e82bdac5adf63fa694a62b7bbcc9b0eb40ce05475fb6f273c3438a313889215d57eeb3d81a981390ad59eea57c382bf2b94516a8f05a318c96efe98ff76e9708d3a2d51fdfc83083a06b2c1f487eb7636d34e967e0b077b42e1ea10718cff50fba366a96aebf599674f823bcee64c024d4af9d2c26d342d3abaa23a2ad6b73af9ae78f1a4f0404f7bafd69d7fc332ec3c3a2a7a1e533de7a49ac4ca83a1b34bd610e97b91c0e7e090944b650a9b1227d521d4d5f93f9ce95275f5c54099f9de8405183bad1fa9d42c386fe7e1aa7f0f0c712556fbdd2a5458d0b506f910edf266332d2ecad44f5cc83585289fd79a8e99706b7eab546c9e0d1ffe3fbe99cc8c0cf45115858d0e3f75eadf9f628523fd39a3aeef8857d88a13a8407e982d761060107e81e6350874a236bae70db4121c910ef786e921b6a6d4bd01a14ce4988a6e1407a76dd3fc619a8977f37032d6b6d85b5699a98f8786fc5ac76ac21e721741d223a8037109d0cf5e642c05d229e3b54c0613585a3bd89495f07843783b3f0c27e447ba4c7bfeb17b443619457db622fe46b4ebea267792050e682388acb1537df848a87a726888196b783d98986793173eb69296bae7aa72e563c8f0db55f9a767d05bd88097c8c8b7e7c70acbf17402ae0ff114b683f61fd827a121fe492a124cf970238dbb9aaf8483ece896c328147820fbfa0c497aab0c017f6e4525332e3048e975c9afd2483567951362ead0410d5716ba0fea0add2df48037f4141b137d60ef6bd3c0826cbe754428ba330d697b90c29af9b403ddebf6cd9dfade145802573a3e02401bcd13339b2dd41a5c87a68e9de53c638f9c562e107805f3ad3e63b2364b2f64feb456a72447d89d245d7e2fdb2b3c52bca1477a9e48d81e493089955b7ed3ef7b446f5c15cdba19abf9496282e05a8a427a64c28a546d6d311cdf4b84212d6895826cc00c2c3c709c2bdcce0496a0ba5145e69f9118c926719a75dff7a8be1fd9fa0d41cc32ae5637a5a8a495459d33e87470613ee70fa99c280090f505a93e92c954907865d8e25c8d2cfad3acef5ab1cc53eeefdaebbb0585db059a2ec3e25288470bdf18332d26f6fccf4a9b72b75dd3b33b37101ca6fa0547faa08913f3a15f44d41a177c897bbdcbb348ea1c0af0b6bfec19c8461f2ba07039c7660e3fb58ebe5c9f867840d046d7d9915b002d4a08783a168f83f81377d03b5d520d3fa53e264e158ed6bce3ac7fce428b294c7d79f500b094b64dd012ed296a954b7254170cd1e70ea7a3388e6ec9af2a2ea07b5b208f5cf16d1dcfea82fb2ebcf445bc544e582335be57b4fe637fbb8cd038229529c1876b32659087fb3019bd03a63c050087bb8f79f4ababfef9b3909e325f9277b4ae78b18b1d88a48163c2f42d24123268da63df96fc4aecf63bd680dcdf1d27f6970ea9272934700fbdeb57a1c0202c3603ac1d78ddd6506249a3f529e8331c825e3b68b12b3c3e24adfd331ab84992de2b4835bbf11f535bf046983db6643d4bab242e4eb34066173789b5f07feb599f05b7467012ed71dfde4d8a6682c68bacfc13e1600a5e7567298c89909235ba7684d178e0743d4aa956c406f218ff44ce996fc8a7feca30990899b0b9d8c4a9dd90017b132c32cd4c18f880a7b463dee4dcdddbee80ccf6411e78d1c4a71f7ec1e5253220935078f25c4ad766eb21771fc100ce8a58436295c072d031b66358584d7e95a0a54f7dbfe3572fc513efd70e338bfbb2da9e13e799bf698df66cb64cec7d9df1ced00f507d09b9777e08608ce8c6ff74cc91ecdfdda38f078c54cffa6242e80bf55a302aff4fff33cefd72fff7851e705287df0f300e1a6a9db170db8b0061310a3c9c64e1fb50e6a5fd5ee404163ef730db04d7e8ffdc0fa3563be85229596460fced3f6ab6bd4d8740557e955515ca81bdf40a661aaa3c1eb5bd44b4f8bd0650d56ec75a04b8327e55c524647ac158e4c984d0ac90d4d043090dba56cd4647117a5a2f3156f7d323828d677b51d85d3ded515d6371a0be5b1c39923e2d27f4c5ecb176dc11c81ce84dd79f662d2f71c7b934ee3469f7196b78b061eabc6877856a09702254ec10e6484b6a9c317ad7b1212b363d2eefe57bc9844f1888630272cf5525c0a823971e6445363fa0294d4a95857dc0afdec2a701779ada2c7a9e2be5965afb2fb127fdcbeb828f1eb66877daa6151f8f86125eedd174dbec31631c4fa5f701326085855ee96a00237a0f2992f5e65d85bb76023fe0eedd0a4fbec602fd811269fc901e4121b68d1c21500bfad23399d167693db32bf39f01b9fb1c56b1cfa41f80c879cf66e4c99674ed3a1e6eba2077df7d8f87d8571afa54e6c0d3b9dce84182b23022a663ed2057018789ee769f46d3c025ff856320a13bab256fc669e240b878f170956a7b96f300ad56c400143f3061a30e17540e40ee7bf9c61051759d02e09ebb442312fdc67944b12d5c22eac93b03c7e344a5dd1fccad1fceaa0b086f097d602845c15a2a10b349c082608e8cebde04f49aebbb8b81676194e6e54f3603fe4537152ae759ca458bb0af92f1fedb42f40f74c95974abff9e952edb7e5198cbf7257bfd57d0a879a190ab8e1877664f96893c736abb844dd3af4ceadff2a46bfc48af0dd6e4e6f1f69dadaeec56fbbf6fbca089168bd4ed433cf6de90448e128b5b78842ab98c50cee9a9f405584021a56229aca292a48fd52bcaa1f734c03e6f7e5a332ae8ac225587fc8228a3ca7d20e36a97763cfc864bd48b9555a1e3d85e73eb909bfc9a8fb313ab98773357ce913945e27cd23efe675fcabef5ea8ea9c52d85174a46a3045b9aabb4f7cd175b6e859d34ac399987910ca7c47f555b6bce1d52995f70c5d1356c7f299f2b87a6b54da941b35c7febf06d05b9f1c2b1aa4813246317bb9a023fdc388839597464081529f897e4d7c7527ad47d8b61deef6a32261e22aa04947025150690368326690a23fac7f4cb23a404ff4b236e913d095345b8096c98717d09da001cb11220028fac895394dd7eadef309c9a9a3b0c8bffd3f79806159a4250ad75d37c412f0ae840eb282b773fe9fb69ed6ad9ed4ef13af10359e8e0a7e3e12c5f4e1412f374a824719901de98420eb2207f404f6e88ffc8456e750b2306df5a2baed3cb2140fb2782b5407e00da0d56d2688e9b19dc41c34b160239392d7605432ff5917698e732e9fd18578e46c9b3251e36724c41911b07bbe708e1b1968321cedf318b06691cf45f533bc5dd869ad2b6b4abd146db5f2fd465e53733937cb8b8280df5109aa5a5e2b9008e59264e00eb91eab92232bfe7c564b8a9de3ecd4216d2237803cc7576e5d7dc18a661eb84e70e1199383dcb09347701382b2053d65e09342756520970293a3f76f55dc969fcc535381a83071d3c078eaacb91dcb2b7776fcaa1f6b570a5a64b3887d8862ba288764b6a9fbdf865622aca64ba57a18c6b049dcb1bb122618c1ccdebd1e6c91432e3afd326e64e7e1fbef57f57068ad5b07013c41150e671715124ddcffc20c67620f9081725a245f125358259aca088f634e7bed8da00e9d84b755342906238524977f61a7e89b46d616ac279568bf01d3f1c93550124f8168f9000aa18798c458529611e21d4d7c32fc928012d563c47a7024f312fd685e64817f1674f711ea985e4422fe21d9015b140e7c8a544b5889a041242602abb92268a90429b4b24edc2b20a280cd795053f67d8c06bf2c5d2c798e2d21830db2cdfe55528c0b731fcbfa2a0f7b543b972753416564e27e9f6b61026512125a940433129fafbce020b25d423b997c2cfc736bad2b9c75b9e8812e98a85efaf008eca361a220f7c1bd50002182d808d8077d59db34879e14f701bedcfe91e844fffe7fe064084afa28175012063a80c4e0bb8175dad282efb13651681331305b87d3f49d61c1464ce3b4ce4729445ad91bb6be799b20cf5639c346f4ada47299286a42df809a6a686cdef07297fd9024efb31d90e3894c31828d64ad1d5d050fa4f51895e02f0814dd54fc48cddb170701eb55200c42e71060545b62e4af630d1c8687276f1c20c9872b4e4453551a70bcd8ba0bd1778c5c3e47367e06dea7b753b8bc261e5f64a0155d65cde796ff0a06ce4632c29aea5090d2f3cbc37b11e38f54d104ac053936e1f9ef9fd2291f792fca8892eb65fd948fda0f79ad771b14fc65d7b6e119eae23e168459dcf8cf0543bb14d4f41c503fea677d266f480e014eedb07ec3e2c3df4628831b4b557564216828e27a928ee65c0ca4ff72473c39289aa0fa47a4e9090d2b6b88fa32894c73db3c7c4004a5e79e8c8c0c2055ad32230bf78d257bfc0774f6f91420eef2fb6039921f40faebe14510f8a69bff708a0deff9464d9265751d768448a0063e2206e8a9699bc3f0cdd9ce3df33acf5188a0edb3d1d0784d9101cdd4920fd098339a38490b6f5fc6780252c18ffb8a44ceecb634e62b169e548475b1207bba1c92c06b5f925a2ecedf38d78ce56682e94d68799d689a40c4ccc65162c676e799c9b83cce24ab309487028043dfb57466ec6d0468468723b47c00edffd7e9f49fb4e5926391ea1dfe04992bdc3cbbb28f46a1d7e2225683f50c786b671a721ff497b56b3faf1f8b04a5fe5a161c53cc325fec20cb32a51686ac7800ed140fea00426b8712d686e7908a68abf52f666a2e3d78990e155cacfff3f2ffb081354711b237cbe3fed781676d017dd0bbadf769f212b496d5ca751e1d349188d50b8edd020020e3edf290511ca7ca854a2354fbecb14a74bfb0a997f180f8dafe8ceeefcf6dd422248f24951937d216f1b2a345b9a1fe3ebbb7e4dae079ab77030f9257e9d5d6a2f00a97549d51073177b9c13f2eb59e9f11758239ef0b235e5f1bb5c13bcf305d312da0ce6dcc5a8e406bfd92260aef98eab78b72c3d3c9ff25b5a23b977916069dd35d7b87ccc75326fcd480905f09e7dad907b2463fc30db8e5b6f0d04b7346c8315709e26bc4d86c20ae131806a70dd8da8a68426994aa9ace3aa43e6551c290811bba43c22a700ab2d51cee8ec77f2a8f608e84a0f95668aed15e6e11645aa3f85a0fc9f5dd1d897f7017650838ac1fe2d2a3b722b6da49d04347b2b2a67ed33ba5248701394fc7b3f43115d0d4928f8677a1d615c0d3c6e13e17bf636106badc723d00abf96d358b1d0bbdfe3fb292d080d937b12c656679bca030e8615332c89fb5661b44492d22b98239bfe1fd84d5b20a62ab49f46bbcce4726799b36b6d06037857958194369522d67dbc16f91ef412475d9307a525ba081a8ce61d7a0b3c424b4272e976022613b9c484b2f23722777d7288103a9332978a11217f9f8202d06487d385cbcaec9c14c6493708cf320ecddfd04e55808bc28d0db59600f25bae5955ed48f99eb160b18ad9b0306a6a73c56afac0de5494f2b0ef4db499cf10fe6aa6bc8f74e48b1bbbfef6ac5e900fe3c19f6e48007fd6fa902b4bba9215874d1e7cab524489239a4369a1a10cb5ce1f513e30099c411ae6192228609a0eaca35b967eee16e0ee451e240f05b9cd45391d517f3b38ac066b256664a25668036ba303da40802519ca10019c802c79101c3d93f8dd4a9ed02e980392c5ea861c08730f0bf533b7500c57f15d88e05501b0e2daa596cfe2342053145b4c035bc4765f53d56b41ec07e85eb7ff890042eaeb35ccaa0673cc58dd083c8a15b16814b8386fddf237b863cbe9201ba3c36cae4fd5726f3c39e3e66e12b167c1bc44c1889c078df567d7194165f99b39c31094a8f6a383b785dd3fc6b748a573de413ffdad6d7aed55ec01d9213b79ab0932f2253c8c35621eb6dedbd9c9580f6e6f2edb429da22d871d0c6537708ae608651ca94ecacb8334f09b536a95e111d006b538ca4213af6471363c47b84eb4f322b3e1de43687a6499e7410ec4ab318bbffb0f5be54bc35146bc238eb609603c58bd9fdde5478daa711e2a908746926cee657aed7b0f4855e6f52d4f1170fa3fd31a660f419aa3703836e6a8361c5786b15a304d13d752bac2d549d6ac97256040016f8865eeeff01dade22fabe6fd9b7c8159a0fb5f95d82faa123106bb816b2f281340aafb8f5ca110c845fa2b2d961be94968e313539c941ecfe871358cb8342564b093290c1bcbe06dbdcadafc7dd7b5718bc83e52c92c381bf6d723c4ee5ef448cbf4ce8fe9893743b28ab7d8b1dcb4582ded97571f6a393007556d57290c898a5bae88aa814438d9c408d4571bd6dc0b22df369b390f00b073a409dd71912af70eb954a79f892ba7990e8b9d91d7435ae8b73bab208b48ffbe56d9a7888065e691dfe0d29b1fd7d51c4dfe8ef159e169a5b71352db80665ff01745a1ce4db7256b8a18e7b9f76727234218e58be579e91a33e3d18007709caa1f8aa160021315cda603d6e11b40439fcc5b33eb5082fb9e72584e30ab3f622b05cab84422906c38177bf94198c107fd91875c4a7bd0ad47ce18ff2f3e8bebff3409f5854e2ff579002e13cd7dd2bf502c4d48dd1cc985f5edeae861e19e8da6741e2fd9da849985323c324e6c42f7527d76afbbac9eb88603cbb21b0f04ee6a9f8b61cf0ee7e8421452e62ac038d63997c926f033c1e6eff1d4721d119ad8242d76b5b4aa9eec136f12928a80fa1a8094f8120ccf47f0223e69128deff590af9e47f31ecc7f8553bb01223f5c0c6bde4e26248bd04c017a4a53de4a60ad35288b5d98a58aa17f856337af4ded57de92101cb6dab05bf554fa420ff4e80f9ad486e19bbda482f711450897e51dc8607557298b0d88b8e513f582f2511a8a4287512d2fe49b3fdb0d1c6f0c36d1108d7c9cb11ed8f31dc5ee2b93ea6d4a550f5f657f8324811032b588baa67c36eb703c4b3239ea23dcddd74503dca339282786d5a01bf1473cf5d40efff8505d7288dc0c5fd271307f218a0725d7312a7698650ab29efb281c9e51754eb8be4cd0b03ee816dd09b785080aa729ea65b8c86699756c848125ebcbd06eff90f215cd043c07db2c0259f7e5ff34e8b760823cec5ebee0bec568759f800cf5fd9156c0bc1277406e1c0941ac2c59d59c01caf10c3454cbc8fb9c1e071ebde640a5455da12edc627350da0e3d1b9144e1329c9bc92445bddd483b9acf118f58fe758e51829dd79210a2da216051072166fde6601a62a781fc2f31eb0b16b57b070f06f7890af0e0b9d22b357dca7d432be055b2d1ee287ea280b3607aaef0c898f249811d1420f835f05d0502e18d24fe492c58a826466ccaf134d14e9cceeccce571672d26bdcb254cbbc037aba7789de64b139654332fccb170cffcefa5efd759e1b0eaeffd2fceea35604edeea8a7cb35c84b9ff1d5ca1c5099f4d4350ced9a6163ad9eb0456904df135857d1e3fc1630b203f4fdde510fa9ad5132cc501ca6f8975cdb0cfec7876b7214a4e3c4553be538e039259560967158e39be82066169508cc36f70a5ea7848c3ef84c87ea9f25cb046d0c40697df212f63a428be820e16d101d796817d00147890168c7d2faf38d62f37da9febb7839ca6a85783f3d888ba8eac3085f58ea9c98e5f6838c6320fafc24d5e0e5f0ee39d1c79e90c5407793c0e3c94b8549c330c99ea73f7d611c66e5aea0efb0db60bce0526351548fbae610b09ac342c18bbc1303f4061a1d2359cc354bbe59fe2f17e71f3cae6216937b506a59fecfb8786b47c4703a584bfbfc59b9737dc6cf9b61f26f72c97d9ceb227bba946292cc6496aa03c82855adc20975e076285c34a2420975d3b8f059c116f2ae1f49ee36f34acfa3a1a1c39730ca891863b1eb13c74fed382afae5fb31fe69e90d34292f5919f304afb9b5140c83b0e388eb46b9a2daadd89b2bf58c951fb7f2001ff07340d680ea154b403d5d66fd13423b848ac1d6c2afb4328f4f1d81c0f4fb7f673908ae3fb137e55372e080872cb491526c85f80bb9188d1b59fa310c2b01ec5bfa95ef1e4887964521124c9142f32d020ed1e8be6e1e7f485732a0e1d87fe2f49f0f5639a3caca04649bc8e538881859f28d3fce1404f9bdcd397751c30136538de22f55512a4a70a5fff7dcdfd2df79b8d101883b35dd06d1e106ba975c98f87f973b4e2a73f9f5d9e1543d724adca5c7fc35a329f614e0009904c5921a45c03e16e499ca2edeb35a9232c377eca0f4d257f51f9dd8141acbcab1356376d327805aa18bd32dc4fae239488fff3e861b3b13f7ce0f947b7ce7edf8721a0529be17eeef61525df450a14436d31b3b519bb90da151739d06922e671b6dcb378cbe16f61cee8a28430a6d99d29971d74e682a09a999e4ee60134d2f1eb329fa4180fb4c0b6b291b427279af6b812a082ec83599d53e6d66249679b5fb802d03b88940a37cddfee5cf524faf05ff7926103897741090a8984ced5da1bc42136acbf1ff0d8a60829636fe99ba4f94115ee7c82d61072e2748e2424a5d3b095c00e72a3732c42e0591c42ea3f51eb3f607013df92d74de5fb0a5408f0497c460a1c077a05fbce5f2235b75fb633ce1ff44f8003debb2aaa6bb12d8451a35cff392b81a9b5278f5c67dc184209ca3e27f388da41e7fd8d6a75ac1370bab47c7c5dc74c02a8cd5ba9e5e59290d834740425f6aaaedf9a353cccb5cf96379c147106623f572f2c79095f3ae5c97e9367c2b7ff53c0f1ea09c043230ae66b12feb1a30f741cd902706e54f048d70df42f4836b0d5bfdc9f1dd84ea2095b19a481a14a3714d598774d34781a405314224a42a16cf5df3878a764963ce5ebfd18079dbcc52d7910da85117a03b65ae559d4d7411445e78651d787d5c4447bf0969751974b97a8d6c4522d3509bec0883808689771eff0553cb94dbf863f1e296c0306f15eed24c24b12fc62ee47cff99be00d9f9b43b084ffec2077cf87c06bf5cb8eafa6e24bd592a0bbeb9312e6fa6bf067ff853c032be527939425337f2113d152a757a4bbec875d65c5bbf6b7d6d07176e8f30d33456386bef3c60f920f23a6042c588667c1cd26a6edf04e8fbc8138440ee41c0a38c574f10be16f0701114911817f857c611b96bb93ce8276654d14241ff10a306a32532d1ba8caa3d6caf976a74cfb5dcf03d23b3550ceff71ca0150dea4015d57c4654c2529b9a3032f1a0cc85768b4aa415c6f81352a6fe7d037072ecc3917cac6741f29ee4774b55ba5967a28bd4f2abfd4ec09d332412d49a8e6e93b845d7d680301789aaadd11a97d589eaae17425973691d901b19f1ca7152362ddd5f5ae3433d8d8a5fa90d4f9af762a7e8618c0bdf0c254139dba9be0bbe73484092ef698eca4873b3ae6c1783b66b1428edbdbc36b2e822c02a4082e4d06485462bc4a20ce87abe28eca258b589a31f433b1c2fa49bbf4396c61c5f30b3052e5e8e00fd81d38ebfd31078bb8a0ef9a89708f138eccc77fb2965aca9a32ab69fad6a108236704fe6ad8f2c98adf1322555b1d7342726a72e4e5bb4f2e5e6b7a9dfaa1400cec74d13ddffee68184c7b630a1041eeb8a18f3abc5d2f82d39b005460f9ee03d3e8e1f94890fec3eac03c902ac9e046c24e547ed7fac099428dc66f0e01636b87e9bdabf9ae5ac03f9d89a5fdc9be4abc932b5b24188749689bd4c8c95b86c1571c5c5260315ed91412110ab06284058dc7ee63b27c58031e7c9eead17249be4a8ca903ac7cfb03c6619b1d40695682857e912ca642bf13fae5a481634a012474867ce34b32589ffbe6e195bcec58739bb992880d8e26a321fce7fe650564a5a80164f4ba449408f45c2fcb84b3f82875a5e50e6649c1aa4f7ea4eb13a52e7d1ef6365395bf8eab57788f73df8e2444c3e736546139fa75569547eef3f989467c76be4e7a70b6eec9fa57f6459a97f003b66c0b7e56d200204de9e464c531087a760468ee0369fa26b0184c4132bc2141245c48a594c092883c61507aea559facefd519bf17ef88a35f12fcf05ed1ee99ab5edbe49c3505ead22370fa031d2b870026dac08a0606c1307117f4595936e03c2d85b3788bb6615511f6c6e3af0ccb835a5649b9ccce5c93040ad1e7d80f0c9a80bd93ebedf43fdeb7c7c3d0db0d88810e5ffaeee1948d2a33d7c897f249c324e58ea9aca41acea1f28697f9efd63070e7f80e6a20eff1fa89cc9be649f9dc4717071fe8e2942e13dd69390d6a6f836653627334fa1b83ef11b9ebd0ae959c03465bd4f85818a04968fb6c3b21891d07c6192f895b76aa0c4066cc7b58cff86fe6d124537c5f0f254c07d90e862be88613a2c59b9f1425901027f6db580415e0da1e674d37c3f96491bd3848a4e331a0c8940ed410d0fd58b4c504e5d791a6244a32c130c198086948fe4f55a05946fc4af600e9cdb2343385bdd98fcce38d336ff0faae44a6eb880f5ac47ffc123ddcef4f6c376e1e2e94b53c21f804109a620614adcc0b4d1db2e6cc5b198a3efb67aa5a57097617e98e21bb6f26f9eadf7ff32ab8af5540f701d2427d2d92caabd0999842d730033965c9fe894ec0b3e13d9e1564af7153fe33759ff70dd313d2ffcfe4b546ab234aaed888293bafad63fcadfe13792d83ec12c2ffd77701408e7fb8fde3de645e8924c01330c1b656d9790d0b466bccab2e6e2c185ad498276230296631972a94b1e34c36aaa00b87a2e691bf22d0b6161a194f152514ef832e519c8d0840f3a263766c3d785a41cf662996f654e01ceef84e72cbfb04db34cfe2cf1f716189fc25792e3fc243b38c5bf3ac155cc607ad1f0498fc1ba1fc824d4c0d15509f6b559cdf17df6d846c3bea26d4bf010bd13bdb7b0684d80f5c26914a718e9264d0dc459dd9b2c8ae9ca4be2efe78b75db22615b1eea081844ebd54e671e560a6f69094e85cec86ebd3ac9bf5eec74fbd26a249db038c8910926524deeef9bdea298b7c8f8a4b6670b726cb5a224c2ea2e457674556d0f7a04ecf940926d2128f82e090d0bfabdebf1dfd947ce495de52a6f059336897e8e01c08000a8800487926f565f983d295cd92da6c9faee588334f617b47633de14e5f120119ba8913adeed2a46267adad8eef44c402626537428331bfeda2a9e5bcdbb461010ab28e0f645bad8c95da211c293588ec56bcb724d2fe0a03379638fffed286a3f9a627dc0d0309bc1de35c663f2a272f122332d3dc5f250e0ed3565b837c79b366e8ce146184bc141ed008a63d9ddbabb12a6b19b21890f7e19d6d649db19edaf78e45eda899549ffe3843822f0434ee6a8a9f369bfb4007889ecc96c0cd03572e4cd1369822e75a4c232fc8ab2b9937c8d83e647f5f15ff711f404682454a043f81a2eb3d96bf88f9830ce33d14bb28afdf98e0cd55669aba1c892debdc46c66ff4070179a93b38b096b1f7d945ffc13cd3c434379a7383c974b5d409febf74189f93be06a23fde9814ee34543d5bc24aa6d86cbf48feb4e3a0e4e3156643fd9c93a729fee900b903d1a12292f2e3a262189247c6df141eab39ea69eaa6646e3b60d5a6760f7bd3eda63c179644b4a6662a4d0374b08742bdeddd26451773a11c18a3ef336e71cdccaafa7914ab31d9aa77402231fa5c8ce740ede1fd79522b0084f5e543a10ed5a8cd059d440e1da757d6f7489089147f41af3e09ef6df265f6341888438fb55e58429dc9d9ee98e834a37d1f7648329546b526e038e6af01215c0b12c285d8aa98379ad372cf791ecca2428ce54fc3d51a5789d4da0e6a87bb2d0483b367f4c067b05c7479e963c624e6146222d9c42f496c007cb4fc875150d61b6bf9044b2d74da10dc6413b9ab79be488890b767091fe5b78d504f4eed014559fa9040355d7bf2d17da348c691118a2271c90faf09c1f39c790b6b584bcaeb407d7aad55f650651cd389f3d1bd9f091128532fc9d7d3b32995085341b83ce4b54150b9c21c1d94af15ed359ed0ffe885debbc36407840182666fd34e247a52786f505a8254d1d9eaea3535dc55b0c5180b0a70cd2edf0272c8d92230f4a69e8ee33c2893c82b2db1796815aae1058cfa8be96628ec7c2ac9c91c71d0f65208b5db8a6f4619755a291a08f1582c6656120f2194a6808421616146b9d714e09bd11e4e9ba83bc15a67bc6caf4abc97d1ff0e465c262574d3be13b41ee54349a0cecaeaaf02b111e8a55222dcc4f03d85b1b2568d5388da77e9fba7a6f963df44777a602169196e04b507bc8027ec5b7ed9c47d53e6f2fcfeefb5248dec94e88b8247ec74e13eb1828446d3b45673d3b503bd1af832d5311bd2da2477a8bb4267d13c01d810e9ef9fc099fe42b9e153ed3872b208a9a9ae2bab3199c9da54332eedbf7fa17fb37e32bdd1b1915b84076a4d6fd70e131f2628ed53309409be9ae43d3937880eb03110848dc28b2c26c5a0fb5c8c66403c456a360c84a3f2da47a2156218cc2c29dc8d69f90be83bceb5b9ee1b1cc67490fac8ea896fc5a7d344f4b25b515ba6eb3dc0700b13d48e13da46c4840fb8ecd4c85b0901c8257c7a4c0de62db44c12e8539530b7659cbb7e475edbda8e89533b5d313a2de78b116ab4ade723c2bbb2f0e32d2528128aba98827e1733240cdf882e3825e0860667abec9d8706431bda11e83bb108b6eaab295c5d85a401b48a62bf40ee10ac63f625481c72fe2f614fe2f218d7aa268015d977638ff6724869781d09ce7b5b2a7887bd1fbc0cd3fdfb35f5697d3f94771b1c5315233843f5f83219f9d15ab27cb90e0b1fae5014461484c6f24ea2348cd59f6e480b997267e886240ac3c03154e24deb335b29b001f502efaa9d5286a2d0926534461d4e61ff76060d6fdd747bac793016b6c213a43ac0a8067ed3621c029b1874d847d2222be4fff0752e8c93312a784c8e65211c48e7a10c29a5667540dfc526cc222f8c805cb87a0222da5d705ec73f478c616a0bb4365c3f97dc7f858568293127c4a16b6589117b4086da3ee70649dff0177c1bf4ead279b5535d3923f316cad354b8fa1752f16a0689d550d5c43cc61782f0a916439c2dec7f23c25ffb42f474437500e293645df2beb9c3cd8d22b501debe296ceb2b4d0f08cec3deaf49b214f3ff82f4e1a51ce9c12d6ed9c2b347f1c3a819549e2b8588576a377d98561e100e766848903225b49c6bf01a736f52c38a9c2f005723a6b16a7bd716b2f80a91137189f94b6164eb24dc24623058a622ae2218f6ed901bff3015e09f8e84e3584f9c065fa2a4875e0d4feb8554620ac9b4dc0c0d8bc980ed47f02b50cfa6cc0d974dc7ad3675336f2a1e7bf7c8df158e25fe28a3ea59feb0fb3ebe4db676e38872d83de190b7783a075e537c10961a06df528dfc8a22fd5fcb2064c1ceac93d1482fbd84c20d82718f7545e4e69d5deac4020604b84d8f8e394747412641b33929db84f59719b15497a9c562e6befd9c3a2cbfa9112de6e1e8ed4b980f4ae6162defaca782c2191240365b2c5b3e7e957a7470a264d6012eb974b8b4c439bf424512abfbb5b628d64b1fd06534b9f768ea0eb34587539ffae4128a523a96ae7c570bd7311d62abda2f9135cf3833c188626c11e7a8ec4f799fe3052e0961c0d72a3229c48bfaa1f45e6c88cb34b94e88516e386c281007116616f3515fb2a440969ed04d7783f3cc5194079b5c0c035c61f9836efebfa18247314ddce85fcc84480347a06f9fec7db14b8462b2aa7a81953ec16080c636b2ae26d4e8c93af6d6f9b28c632bb628c3bee9b95ab5d681200c48e517a781aff52f726efe16f3ff81d58601e967428be565a72395c924ed8c21079078a06c80a59e7fd4be72cd3cdba0a8247f759caad323fdc440d07b6cdd84c77e9285d158e9635e63fd2d278d447b7ad4d271d898e011a27a25cad1464249330c39d03fcc3a85dc7c12407b18cc06cd6b244d6cbbe2a9fffdb3c3c75f5d47cb026e7c982aa9c82255b6a09815d3a0ef40020aacfddc6c29eedbd47cafd757ddb538c54df92c8a0939cf5c3d04d3bfa3cc445c48a137e1a298ca01ced7c8c613a4eddf68d20c2ec5b85e63998535ae6c7aa65c41335f336742ba267bef1bb02e923cc704681fd5f40b4c8a769f9fbdc61db0c46b95c599798333864207c6c40d56f89e4d3a5656c1fad6079583ccd4822f5884db8c95ffcd6b252ca60b8c37c612790dcfdb7b7370e43ab7c4032a79c3cf3ac37c5986437d779b29cf635b4a40c7dd817e1aa77e3b2326b9cf6aba6ea11a7f04b70f22369e432f33d802d77176f7b9101fa5294812faea30ad6acfa0179eda1870e2a585248d863df68fc069541775d984403d12a2214df8a8e60ec06562b4724c929014dad8dee3015b060e822971ac214d04a0a76b8e64681ff622e00032ece4e8017e7f267e7fcf8d3309de9ac5bc961993b484f0f1ccf94e8303b824d0014a8ab46806fe0ea8c11d17ce438437387cfe8e4099ea2286bcde7327a7a459dff8296a7c33a33b4827700cba56e61bb61d02ed816ec8876b2f28f24057d3fd6ae0ae59ab40adf6e39e0215f540809ba3b0fd612a57c88329ee795c785b208a238ca4b375baec9f7783301efa289a7fb33a3dfc0107b8d31d87fe02690a2a090a04a636b00cbe38d88f5f5d6c0b8409f55b30516233a75783887ea50f4d4b41334f08f8b341ac7cecbc69e0b55d828d09c2eff5d802ff21d5081d8b1b49dddef268fa8f376f57b13cadfb6cf8ff00188048d38aa2f55c19915d744513ca36bbef8f4d153f567cfd00340a1318a5e9869778b52679463240fcc221d1a8e546b8356e9263b30cd50d2719d334c893c33114c6825829e9d402a98ce858b013d84ac5229610652169b3c7f98410df290f6993209367ee0aa3a72d2024fe299f2beb09aafb7cbcee04c8bac44abeaf19da3757052511d0af4f50fff8157393d81acc0e246e3252ada0e590b8e90da1f1bf6bc45a898cb329f7651b70728e0a462397096771d787c120b506a9c9fab450bed0205336c7ae4be5d29709bc7f532b4f20d0687f6bcfd08d9ba3bf0eab4acbf3f85b2c89fdb002b39d735c8d4d3adad8ce695e1d1075d7c1c094b6bf82e22f88e2ba28a6fe4160c5d2b0f470ebb1705bf30f12e3d7f88b7d52acdfbe08968a08c8f3ec03dd29c007190e39006f8cf2418add94faf354dd638de7f96167806e84cdbbe978ff3011b030ec8caf81c9c9824abe9c6527abb6e300a722911d06b54aea903ff1b6c1fb24dff9f6a0592e47d3aa2694f5011f59d18fe65becab251b294ced6759b36e22f7504526366141db2c36f554015266ade704d215ca8d792885bc9b1307f1530bf797a226c17c2096e94b84d490d0cb6c3589bc5677b826081008bab0489b445dbf623d44b8b212436cab9a19d514fbbe9b8c51a0a7e85059584ad78397ecb16012e600426b2d8acece8ffd620ede3fe8ddcb7b2d1c8c9c5a032a8ad4f99c3d078330bb6543424ec97b3f04e0c8437fa7394b8fcdcbfe0b99dffe955887163332c72f5dbb222f2346e556099a18a21ddb081583e574b3133c91a7bfe3d94c2b8a57a9ffb199c9b24cbef08a0fdb137f4c2bf60039ad86090ac6905afeb8be73427cf72e8d59e727c84dc3dc808c15b9628a450e7580fcb168d0629b85c63e90831e23156b25e98062cb49d08c334f2c6c083bdb67e80d49ef45e81e7aacb0936cef7f70f8e1e1a7670a2789c263fa7332b5ba9003e126d2dee13d08399959ad0d7774b899bc7fd49770cafcc8ab49a77e7c74066610342ec5331804f5b48e44175ba9effa8f6fb402e28d2be2fc533826e8fb47c51cdb41a174427761af1ef3c17c0ed4866681e0d57b5453e9175fb3332a8e60499efccd04bb8670c9c42f5a4070afd72f0dc10b3f6a84186b0ef2dbfa02337096b96a4fe1f6aa4504091ceabdc9ce0f00c58694146e922e90bc6f78ade74353859636a23712628539e746877f9946ddc54c11226319071cac14c701d86a290a55f8c340f81fd8504db0d12267f81eb47d2c6cb82effedb8e3bad0925d36ce99033121e430e0fa96a8992e94d1857e48a3ffbbd3ee8b16d40c1419c32748ba0c677440ee56d41ab65258faf16e32c15ede2dc8fd4c6211314fc006326e9103a1211872976e2ad6f69c1345e336cbb72c7f2dee2921a538283a04a71ae6fcce119752fe032e7555df02d516638458dc23735916d4f706242acfad54d1e685c141144bead79d99ffb48ca5559922c52be72a9566023b358cfd33522cf0b5e21350f739dd3e7e2403cac83dfe49864545460c05563cec7991459acef6b243efe72487dfbb1112f1314ca25466d28e02299020f10eb53c1903027482770db5c58cc50139b38aa14ae682c46ed563084b694b566ab41f8646ee6005fa36cc1474b78f4c0d532df7da0d8248e8dfd2c24f05ba22f60c48e93e93f1c147e59803731329d552f6092beec00d8be90da9467ac8f01c2a6c8471148ae90e742691993c9e626218b14576ff2c1fe9b56beddf6bd98d223e9fba018fba23968840ff2bdd00e17ec7aaa413b03e9f9e3eb7bcd232e82579018d10aba2bd00126d3bfedcd2c9f94afbb2c520b92cc5d88e9e476a1c1751af28fd4a0fcbb1f557afa0eadd124fff15d5baf84ec3cd07cb1dc63090a09c0d37f6a7d870c5f18f177ee2581e0b674f0d3145f9e45e68a805709198b4981fc64258719e060cb9f44f6a5dcb64c11712a63f4b1a7f38c2f9cc73f3979275a550b6bcc8236ba78ee4e594ac1fc1d9e00e1f03b340a7e4ac929c33dbaed1117610f810d0c7f7089cec7eae7c4e93e931b8ca66578d020f0fc2c7d7d576db0e7137bff16f7b7ff0b0812e6f0080fa2f5729d5c3ec5fea22348e718c04bcd39d795900e083984b3203d790f46f62aa7ccbbc23e3c71980dcd539da9ad924acec3cfe929ca83a2366d54cce7e45c4f28906c13e283421231a9cae2580112daff7a9f61a2a32e8293a63bae5b19abda9dcc7c2f5c79fcc4e80bc73c4317b33fbb8a717a7598429422424dede7bdc5128bd759960fc81cc1e8936ac31a1148cb0ac8c39cca81559d7b7197cd59ae642bdeab1ba2a6bddd43ecdc6392d61d093fc83dac95c446d1c7902648335368ae3bf221893c9b5846863a3c63985dd1b6ac9a9b3046d2f8a968b2c8c7ac404f90260d83a9a65aa18226d4e668b88ebabf52edf9e34845238ed7e4204523d217c7c9f1e1f46c3357170de07c47f1c26b7828610378d60c6b89764122dff6790ac09c85ae22ce77a033fc6326e03b6e7d354cb4b160a6c1282242a1c0a357bd21f4237f198eabfc9e0d90e075b9cb75a125f2f8212fc347bdb1dd40e88b7438757d3294a34f067797179b3f7a6609be60c4447ce86a6a2f884e05c31da23a12c45b26c7b5e6058959e53c5cc7a13752f484192ae949adadce017a25f2bf50a3834389a061de414ad72e9094bd7a7f4597cd4a4b8b9e14bd65bf37ea8c5564aea08f11023453dc8f69eac247570f7e3af255d71aca1173be18360ac8d8a049ee7f21f0f3e535feb5d40a64dfca49c509f5e9a9ed29db7013713f46df2606cb2fc10fc15af4a3140edc483429647a5cb716ac91941960a0a39a3fcc036403eb86d54bee831623c0526cb15e152bf9c397f74e4904f9edb87fab24ffe1f977bccff483308703380aae8af451b7a8fd8770976515422606e22bb262f35d7b7ed575635ab61cbe8c2a006512c76a3815ac55f2f889fbcf6c953f6b2660216a92e3b6acabca26bf5c024161e49007e26cee487e833e3f2654f7857200be0892b0743c8ac3431ce75affbe8f2208b9ddc5e87b0882b7fdea60e111ac0bec4b7f3d46ce0f8ef810c70feefc67e5896f5dfbef5d9d0ef5d0451caef644ffa423a787ea3b8552ed5a58a879ac8d35a24562ba5a3502a62bb6e2081d2961ef69d2d8f480f3ead4bdb5d50fef7d03b7a089f7e1f313fe2b6a558860e1067007d225ae1b4ddf2d334e7225656105c7d41e1d631d29b2ddaff104a64d2ae2150e0fca922a09d360fe6fa469ebf45e35ee7270bbb82748becee3da929e16f38e1204172d6dc54d389d7ae72dc4075a559a39b885f221d8a158526e2e51a658280d2d096ca6f02e6069ead9abed5b5005fb6358724bd352877083c067a367837fa859f8bed2c7b60498c073ee9537c25933e9c35da692cb81e8a401a8f2c3f74b12c25cfe39fe0bcdd7e3ad77ae8608d0354c0567adcb9853964fbf6565015402ebc837065aa63650452e17a5a8abe934bcd842841d24417885ee42bce43d9f5b1ee1ffeeff2120200ddbd541a221ee3218811a99703fd60b89356b07a1ad4f8eea1dbd521e337ba8f81b81cab548f3885bbf13b87eb6f5caf3af63f566ea76f02b7ff593d0615297534db3d004e165a5cb328e1557c7f731905e515376617890ffcfa114a14f4167139c49a3682d21cb473f58b44e99c75bd41518811bb1d7192b682e3e994bdd24e0390f047d6b998fe5a9be347639641dbf0e0a8377375b7db6c46d3b062659eb5750731250d3eae632a3a01bb41fcb477fe4f6c83daed5aeff8cfa14ee24c55f28b4c3a060fa2e8f4cf515eeebc05c52490d7c9e6e84f4672d805027731b447928117e782914b606765fc99ca8b8ff9936299e2bb71e42225c295c06eb0582e441e6905597d42df877ce709f53f8becb6e91bc27448f332e679b4d78312395667136ea9143bfed3f1dff85b5be6fa3ad27e48656cba54f21634a2cdb6b683ddebd3636214e7a6fa82d26d2dd4a017552bc39288454779b2cc9b0ec74ce9d3f011f5d90663e701fcf336c6ebb6eaa4333a4200e8adfbf97bb906dd535049c2950a15d0321afb18d4a5eb51d76dbf9689ea63a900d4932da07603c1ce39fb7a7f559a98683cc454b9c6ef65c437cf73e38fd52f352ba33341bd00e8bf734870bb0b00f2c2b740c93c36fab4217f04ea6fbe17158f4a3a5f395d5af8d5e9233e6f2f5776a09fc4b7909eccf9efc626b90b841c56f4cf9ccb5d1b1e1041b7d0d3d3bdc93c494fab3b1e7972f4a9bd8252efdc767f614faa524d72f0b044f19f187162e2d82291c4cf8293992b4184e3a1ba8dc6928b3dc93cbaea51d14871984c92915c9aaf0c912b2a45a3f2450f7e235d947484ccb94b68084b78acd4292ad14f522e443bf89c2fbc677ddbe760adadeb8122e6308491e7e71b037e7263072a3a5b7a891f88c5019e12be8d51be19b67cee5dbbcb596e26dc49645ebfea717680e7e4c1d2067b908d6a37f540bc2484030d257aa37fc49eba8c317d27aed4af2e33352e6a3351685b0ae6ca21917f813105128aeb5fba86bdec716ea182461461cb749f02e464bb058f9e483fab2b15a0f568a0bf8af8d44abca5792b5c3175d7f9f341c3f1da3651028c0f15d94b5873da05fb454fd0dafd00bee03f605650265c8c927c8efbed1c12edd4f48f09865395b95ae0ea7d154f4648a375f114a4759209838fe2210794f6575bcd4195bd06457c90eb1386887e2c83e45871ef7675bbd38b44551479d858da309838dbf86e64bb8ae1c9bb01427fc7825212e5a5f0419097e1ecd0acca2e7e6fbd99b38e91f249c4f7b6a21a78664f606d896c0ece8de5f56a04960536f0800c14617cc4e2587df20ec87ca8b2d44cfc81434aac8601d6ce65324346bd061d1de022dcfa63282876e651b46ae37ffaa50e26fa8887e671a77477f12d2a69443127f74eabb41b17d150464487e496f7502e16ea3bbf8e9f8d9325c10e35213a6c4248b6d47a4c592e747e3e86d21881984d7467e9cde7f42252b2e28477eced0f023aab6108c15a43c50faaf1fed5f9d8327a3d10e28ec47153b0a707850f05ce1301b9ebd01c7528b2db851dc5e886f852ec7ebb611953747fb5b96c9da85ca1361ae6077f3a888d68ad198eb05389aca005c78492e55bf02cd07d95fd7336dd209d23b08338c5319f00f03caf56992894745c2d36a6aaecfb10422c16e66ee12b936b5d290f6b3a337d9aebd1fc258dfc33629a864f3d9e6fafd4f8d71a819c7737baf57386e17966580748758bd2ef353d780dbc4df2c5bc83b2972399fce8039683c408065d07013a6322dfdeeff94f15cfcb4cd9df8fd80699152b577a05893df662ac96dcb23f904ca85b12bd33986fc1a038fff2ae668db154acc2af33a95534d8fb10b3cbf863e2333124321663e550e64b80793d172f93104f583affb9ad3939bae0093a45fe409c0d18d938ef096ff6ee6857a99f968683149e76bb0ebee53234d4c9ba78b463da9c4dcaf16c5545b8b6af2de76d8bf584b76de02d2443d2b97ce793ea3a75301848b54a2e56223c6690852996f7b21b288543bb35ce2f319b4558830b53fbb026e120e82e27bcec15e2586691ba49a25e51baa372e2f4a0bd41ea0f0a2fb0f641dda07cf9a01d69dd00054d2acb57b4ef17a328a82fb1501e99a73e01a77defe21ecdab4a3e393b432d3e75cce7ab3949c2774b6da7ae7fea7416d84403052ba985ea6c1b6bcfb600f1963c53aca9b0da319f3cec8e788fc688a983264f041452830b3ba40bdcb4639564f5832c11993c31604c475b8f088929301d7ef526b1e84d65536c3c34a2a1bf2b8b5ff0c1f8b3caf22f3b9232029d685d412ad5b64e680f9ab17c218407dd7fe8fcace9af143dec2b1cda1fb0de01fb6ffe200e87d08ba603a512ca483e2d229a0a5acc863f70c0b36fb033163448de18ad134c503cb577b53ac06a57065c4a43b2d59c4e605b63693ed85417b0a1f430de49e2cf6f3671e9c0c770186b517808f7e89261c2216c6bc739e4d2f3da5603d42bad7435bbf570c5352fde6ef76160e9b7aa632a3bc2550ef1eb369fadff4732e56b207f1005443af86fd4282af09e8c361d27f56f8fb51782e865c9e07ef298f53232b443233e359b7ab9ea93a379c4769e4fc4a7e3c1e51fb63e76bfb31237f6a4257957552e7ec2bda6b55913024a7b39049c9074228182793c31968f75153c739fb7f71f1cb8b79c202e06ff02e5a05d57b8b12d5792c084213d6425e510d5d6a4d5c1f34c2a04b2293a53460b65338e2f2d08e585ada438116f77399c1359575def552c0015a6ff6340b57e26d299419877590bdacbd11ac529f5c871c92f5c24ae0e0515d6dde5e225c2f3386aa9c1526c06aedccc21516efd936b1fd31758d8dd94d52d9e97d8f98340f0a61bd029622d4b3b859285d8e5985ddd91044428b9fb78c8ce547d20a550d24bd6225933814c22bf2dd9edb6c5ff5c77eebef40eccd97e5379f50d86856072abefc149d5b03ac079cc8bb4a16a17c9e9ef1ac1d54bf2b5d9da081aa63b7ee2cb67c7f4689995aedf197aae90d748966c066e2018544d02e58dfaab211dbe3f90b634c29bbfb9215d036f8609717fb5f97edf6f1085d70d3cb4790333e4d915983ce8aaaee799fd61847b193526e7d1ac39c6ec07e27e938ff1d4387a7ad6d822ca910a4d4502459ef6def0b3e9e94864c36433e050c7a5aaab6a8cf2fc41d55ca7efd26a6a3f1d8685425f5d6a76738b68053b714ca9a406129b495565e24e4122d49beee7a0fa413e736a25c94e420209d439770f11478dfe03adb99324b79aff72325e3112337240a097ba21bb43974f842d9872c754042752e82cc6463bf9857e6b57a49b5ba9b6c22e2cf77e25485e106d960752a0d33fb7c3b490bf38c8f7cf6dc2a71dcf05cec1dbd722422ba7a59b34b700a942c6eeeffa6a239f88cc98ff574e99042eda501383a0366c59b4ffde880edba0a5553a6650bc1b6d9a20bd6e459d52f4a867983368ae2c606bbceeee9c3ff6933a270fbaf1185ef5def747e2512db01bbefbe102a3c57d2aac0a2ec8fa704d8eedaf58f1a4f9e075c6418b8de54836167158227553cce3bec58de3192b65665aaa4d9d9d4fb60ec1f2e4231d805feda6e82a54b419edd1759cfbdcc820e413a5aad032269d38f22c4081443b2262cf6106a95df42874db6c2cafd439fb494b0ca345eef4d56f14ff148c83ce2fa49f5ca244782e9673142ca76a98677d64f834ea791342e709a5d37b9121c64334f159c1ccfd20403992075e23523748b4a4c00b1e64b0f176a135243604a996222a79ffc10b792450e39a887d395f416929f5fc3073d4bdf26027d3920c0144f0a0a58152685a1de33799d3cb73bb44a8ce6b57dc21a8fb5c4f81cbcd471fd2f50c6776cb332e94bd8a688751d335d8e7ef55de903f99929698f204dfa6c828bf0471cbb8a020d7dd00f9e53bfaa12d10d43911b7c3d59c089b3ed8018639b4468bbbfaca055cf16db24daac51b8d75400041343752e8af0b7192fab307848106a6ce36fcdcb59af7083d7a7f0426756847e07c15c5facc2332029282ce3cce06357b200e47212ad4c595f03c9ca1812239e6780abf73a09e14ab40930a7b192ab19c55cb55d25f3f76b21d7aa73c5e58b752cbc7768c710ca756d3209a8ff3d1f196fb2e9681a9cca4794f5bda8f5ea41962096f2a1ab8d4e0022a411de0a3d29bac7b6e1f850b08ac96fc0b828ad8e9f44c9083269ac8760b1fc61b9af8c078434d1db98fd2b31f599f84ecf43ae220e2fd8c6fa08ec201a91450610e4035a64e0bc385647f4473ca1595d6183a68ba163d3ff2e4d23b74c110c7281d0b1283e927168a3fa8a63c43f44a1c1dc4edb87f5af8fdcafffcaf80ec11a94f0134e536dbc0a5ea455488dc5e51092ede0f142f1afa9e8f8a3a1659d3a768d54575d4d9f474bf6bb72869ab7dc185d1714df87e1ba919f505dabcd79790256515d7a300124fef372795b79e5c409f09d11820ea6e7548abfe5de90dc7abb9434f2bbcc1a195402138f14c119e659d6294716ff6190daef80ca99484fd95724cf8ba184cdd47679c2509e11c6fdc286537c8d65511b4d0be608a52f10a02392f617210637a7fb7b87886476851350c38d6b029ad7a0d567f98c6b4a05fcd8ba8ef76f39de4e74bbb6642c89c18c01fdbf33a3f59f0cc9022db85460bcf77de9d4d43afddfc0379d860be289c2501f1ba6b1d527f0714b6c6a710cd6527ff6c6afa9a80faf368152c579c5415439ad7d6c143a6b55c388ddbde53d6a48af542e02a9282b14ac32c16a3a9cdda3bd18dda6401aaf993c0df540296540af03c435fcaf0618267f29d75eaddb61c72e352670a2847745228ee6c9355c9b78dfaaa79c15adcc043c01452945ae57a3c7725d011f71c5303e61631ce802c8e3097e1141540879b24f716df8d6d326ee1c14799505d3172254955480d8cfc45f2d2fe830d9319b6ffcb449f239369f65025949292a43b7d3546fdd0c81bc42d58ea063a42cfb10f1fffc1ea3b74d43e8a57b8b1459310937bbebcad5caeadada80dd53424cad7966db5389f0b32442d0cbd440f0ff1a7e043cc36b9e92bee44c18acd5e5b86901b7a546db6b1f07f111ddce4dd0efb4180fd0e1f29c37c2daf5ce4a3eda5b51a095d05311bf68a775e84746936a07189d168367792f6f05666b9c0715bc91efd6ca4e5d17479cc433cb1d6cb2953821a2be402347d23f41da8473136008bc46d0dd14ff0d210bfb5d7491f4bfe2fd663a67aaf49df76c256ed6d8883eff7817945902894d8a9c7fd999cca11a0a1fee4d2c84ffb89a7abeec65039a8e7f2afbdf25702db0b026437d680ef8e08368b9464c256c46d23d589ceaf940a08e138c5ca454edc443c93fc892b9bcec7f74a7745fde8676368b1cf525b71a3e10762cd476b20258cbde6bb04a65017d3700b897814e0421f5004c912474d547585d0bf6abb7d415c635837ce813c501ff4b722aa37c1d7dc7122a1ea4492cf380e76f325562826d70b540556e71d10840dd19b8f026a3fdd770ae7e519def73a9da84882f065394ad9163e41019ccac17776247622559a0ca3e7bc1a2ad76260e2b8bdc1532b01edf765ec340dc7f444dfdca69773eabda078bef40b4c3902fddbd6f680cec9562eba56a15adad5901a7a717a3ba01bb04c826ac837d24899e5733c15e7bdcd22dc789650cf7b882451ac593938cfe9d3ec056b78cbdefe6a074143618620c677585ffe415d0cc885e4da85723b137bee3d423e8dd01f7c7d427026f378f101a2c8cade27d6c936f85892c148e2833ddca99e879d4495c421112ef0584b4bd4dc7ee53986b81bc697e9ebbcf29475c4ebf62c17c89a7088aa83ba7150abc840440eab6496f8202eba20843ffaa3abde38adf842162e53c5cc514df47cc7879742765469972ccf3ede7a7d0f3e44f1176a39c61ecebe90dcd47796913811717516451bd4e51465cc9b7dd2a6abdb5d40a6333714e49cfda0f24dc510697c78c7c934e84d76b1495dd2b09d77a4e9b9e40ef0cfe19b047e7d90ba00daaeba07436bc3b97b124ac536e27459812006b1bdf08b7c4145d837902acab15674da0e0852854c747fbfa695c3e22f0e20c95e250e8b88a8f97ea7405d42491923ffdf7c96a7cfee5040daf4863475b9f2aee635cb493ff6ea7ee87b35b9dcbedf6e95e5950c5353080a8b8703dc99e128c6192293c3dd1f7277c2b7abb3c7ab3fa1e49a35a570ed2bbf65925e48f99f702b91477aeb16330dd4f4845dfadc9d913fdd8f0f41d5e825086dd8d3f2c586ff319c04b98f5e7e9cbd17854fd4a09f6cfd4c9ae2ee048b780aaf2906b880dad9a4608fcd37d73509d2839596671634b5354012fdd27f61221ba31a0e61ec05bdcd7ddf24276d04a444b9a5452cfed8e57fff53ba52fa028e5f3ee5f54626ce563c748d49286cdc8ae22dfb6d78ffa403034a9de83c1f5a31de56ca78f01046517baf7ae402136b56b5ffbb4126066478810fa8157666f0fb48f3efc00ddd205aff6ee45068982c00b0e36b10b133444abe4e204f1ca5912df5a2e617b42eed613d90d89a84b11fbfd151fbfedf94de1449b5cadb7c1e3964dbd30328e074585a402a0da4a5109335ee03161c6ab7a6ac32a92d8f0d2304badf9dbe6167e24b14adf362e19fcc5dcae2b4e24275115efcd5baf35626fccd30fa9c0b42c561cdf965b291362673fd990efec58af9139c5926a046a33023e0e31748a3dd31d0a803c112258ae85750095bd1a7bdf48300e93a4c3a39445698688550a6c1d8e6464b24d09bb93d163b525a8f8fc16f149d81346cf07aceaf5c4c87a27e87bfb8f57e60b6415a07328bbf589afc4a75abbca41d20d8e77dddf550506cf2ed3c12477f398379b89f6adc3e2041a6cb729f9a1d4507e619f3e8efdb56852c5b4d7d243d99312121ba6ce90f76f1d6fd2c0b87a1c19be4c76d8a7024874f39b17a00df2bcb6851527192a46899e3a45a03fd540462648e135cd52d19e97955e87df1df38fd06a1722304cc7ea24017043b67197b5a50d58e06927c7d4e5d167c65351382419a5e3080364cd40b21ee90fb0aa7cbd6bad46b5f1109e6ed499909d99e1fa220ab5fffd1804b9c8204ffa34f943383f98838fc7407fa811e7b6a2be44d7b38b99bb2b57b82baf4d91cd037df0c678021a07267d050da231d603e00aa09adb3017119f412e137831145be3bedfcca19bef608e506e118e6606139209f12a8df6d3088a9b4ddf0da6713342765fce7ecd2fc33415b403a98233519163d90ad12a836843641b62e110ac7f4cdd95dcbe5f97c9332f6d736e96398d17970a06412f8f543f2422b086eb3da5b7ff1f3a1ad6fe0680f0534db7bd7fc8850eb3219dd55530002d519e195c00052858cdddf9f590886c374ea340a7f9ed172fd001bc4ad9ed35729f2e3d391bc331d88d25b81d5baf7733ffe8449ed90a37d84b07138f9fefb5e709dad8dcd2f796323bc27fc008b702117c91317282932eb71d95ed6b28d75aad5a037e0d74588c1cf10af3fa5d59d8f6abacfd3bbc51f269f282fe95a7c0a5074f651387ba510acec422eecfde6db424ecdcb7d7be86ecdfc6c1ebb10658d80a2dfcfdfe9c5fc708f4945f0a7b832dd7ba083e5b893b7a25de95b1b976f6a1a83a9369b3f280f54433ed7dce9ea3c87dfb403d4134087d34a66c7f505a661db37fd0ed7e586fc2fcac9c63f878a761a4c5a2e5cb390eb7af3a78ff3eaf07c740608d9a5632b7d40b23beb8680b2613119d73d9026b35a793feb9ec6e82a338430cf58699bcb10f69c4c74cdd2a54a0837a54e18b861086aef03051a51a565780c682c7d8f5d16537d4bfa74e73d1c9994d6ac07b572a9c4dd314072ab4a1923116cddadee57704b5a024be40c8f08f6e5446c0dff03b2b1cbcc246564d502a1b01d58933600e4d18b260c3d1ce8884f345a7d3e6f95d237afd199c4ce60b98ed0f1223110935bd1470e48b6dcb74190930f1df8da498ce2f877d4f139f290bf6c399db1807cb9fe6b9c3c1b1f6f63817b34b0c815f4c686bdaf6ff993c283136b4975df4caaeec0b0e3a2330e6d584910d865db2167b338d70293f2f6aaf0d4f6418fc49342e71c6577e986a7a44cbc2fd1c613ee64f9b119d7f42220f08eac76ed9b1b0a45a113e4700d9be34417aeec80dddf35f3266a82da09c9e974b703bdca625244df6f8dec0d5f364337ccd6d0bd4815af42c88c5c9dd90f5b1513652c67b08f04e55cd3240d9a8b1a44910992099a09c694eb934cf181f3cd3848903c17e1a0f241505775122e4682904fa2b086fb4cfb24a6a4c7d50933b0e58e62e6cab7bce6f54ba413e77c501f8ae6e2930b1942f098cf4aee788d0fe3d22f0f083c4c11129162018748423a173d1362ba87ad00205ce43dd97ee7712733eb4573341982be36ed1ec56557426e1a356088fd5e10356c99715c2bb76e6fb5b85cb7b762849f5cefdf4554bc765466c50414a66ea3a75ec607346f0dce5d1d7f41659f866d559e46a4f6f96244a4fb7723e590c49555996824a1acd4fdc7c6ffdf4deba66387b6bcaacf2ea1130aa57ad95226658a2ddbf28c80e2744fe69b80d2f96d75fe19e04ead92061bd46dde558c6b2c46d7fc244e8fac4ecc213c0cca9ef5609cbef4722c2ba0ade779bff2b7cebb7aac6ea2c82d289420961c53ea75a4a8a2164d7fe5df4d63d8fbbe26e22ae3cbedb898ce42b4e95cb75bb116deb69ceece5d2ebc2add8dd1d536a0bbecab77c43002da4e1fcbc141ede821a01525b00c4ecc5b1bd2b855c2301acb880e6c3d3f863893f65ea7ad0f6df3a0c306556ea1e94dfa93a5ad1cf2198ef16bcd7ae0ea84384994de8156870b2038b1bfc46b82fa174886f54b4ea3e292fcdd50597c17171517337cf02f535976e60fea71577c5a5cce4bec532270f2d24d0d2e426c25d3efd0a654f272c0b9988d83d5e8afa519631d77da42c20443d08b5c19e444180aec6a19228db9db9d671852420b4d9504432d0dec65c95784bbe7889807e06efab514d5e8bccacdf820375e8fd03a38b5dfc37b4318009bc3ddf5b1c2ab04501b6e3b3c487edfeb6196dab28cd0ed855f479c6c0e84a8f30cb643f7b2308e9d320ca9bf2d97943648a59db7c9c942ff2f7a6e63d81a2fe41352c9471ecc6930ab979fa5e1f1a46dc44307f8919752143512066dd3503d1bc6ea745e6426b6eafe78d0028f82ea707c2db8215710c5e9da4c1d5bd79159e3fb63f3b3ff500c10f2661626b8fdee672d4943ff90fe2bc03f0964dd335c5821ebc10b0fbd8454d2a95176e12797bc66d733f0928e2b01e52fbea4755a7f65d74a237dfd2ecf98f26981a0b774b3e66864358631cfd7ae1c1b34221f0b38f2bdef110be5f78773db023e768a02b796387ce80d3e2e116581bf0b6e525dc9e86dab8fbdb1b1dfac33fd5f1dfe966223b3a441c3f5f26fb97ff2594a3f0890cd6c341696dee94ab3d4927752f10c715bd0ac302f1ac2f0c6d82fcf1049e52f906094636c6be3cf086052ee02f167cfd8a848647188235f9deb15b503c46aaaf67253c70b950b962ee0d3b983e8a7e06433cce61d648be24dd86126e0bc5e915bcca280ef44bb5f2c445c00b141a46e207ebfd8ab2892e9f21dba4d1ac4903f77e233fef1fc1e0fa82496f70089a843bd9767829c70c72eaa99eabbe02c29356924eeb81b4ba3e7db740d69e86c13e273d74f9a50de299e470d2cfa82ed2ea9062929ac48aba77335861e8cfd52b62534313b94b2980a0015f9b79e4262f4fa2f83cc3d2e379fe230c0ea9adf26de40c9edd099fb73bbd6740057f3fb650279016081d6ebc8f0351e9bfe6879bcb4868f2b80f1abe08f48cf529a6ffcb39d78a718c3f722537bc50be232078a2f9cef9e6a3c5b6841e992ab3f92e14b605e27a8439ddc1f67feeba1c75ad68eae1a126ef119e4fe2bdc44859ecada517c92f8ad15a1c94ef77f9deda11acb56829329b5166b9f8a808601da5a213dfd69ea22bcf14ea21e56bb66e0f558c57482f3ab408d1a6b14e9edb29285b011d48db2ce12ceeb9c117101eb91a46ec1fc08fda2e02622e850033579052ec6225bfe1e0ff7a0e1da6f04ccedcd2d9242bef8d3a41c480a8eb91be078e03a750d83e8f83c38efe0fb04cbcacff1d8788c087128ba1cdf01602c4f0570eba58fa1c3323b5d1b69ce24df4f91ff614e42b747b4bbc9bacb822e89a4b798b0805ddfec61a47983ae917e5381c69c8394e5c9bccc64bc81d899fb81f28afe7ab9eb3ce5a0d03c01418c60a3f86bae498a1c0b7add46505c0da40285f13358f8f295a5123dd4b4b259d4baa23538824a86062245c5dee1b9238a99bb5bbb79bbbb7d59fe62d856d433c5bf4c99b37693771fa057a03e66b22d2b03f967a044f630f33dd687fa3cde26ee3aa1568e6a4689be8430e48b5538ed69fa3b20dd17539720f6f4a73c19a8b438617997acbf20226886200a40cca5e450b78785781b465d24e768d66fb6574b6c02d32aa479d78341686a5b7268f45407a03a36525c06690112100ad160bd311d99c11225802a6ecc75606f7f9e560f8f8edc1b9737aa54899d72e3021f9c138782fe81315fe5f8db441445e2b96f62c77e0e1d863a5577bb6104209ec88fb6b7dea4a48edf9bd1db632ce5ff50e9ee498f1ff7e3f6ce3976598866aef355c51170a46adafa95e7b8d7caba297d12995a24e804fccbf2c89be610ca9b59614ade3f1dec713b8a776ec2f03641f8f154c38cc083d22442e683fbeaeff570a9292583911e13798ad7e329a18f0134a89c71b5b10e033fcd76c2ff6285c40ba97a03fee1bfde555e9812a2a01f0418f70c3f9a64f83d608d00a9d72df0ed0903bac452c28001fd9ad5ebbfb7c5f91c90661b83937eeedad46ec940ad24a28149edff8c82506b9eeac7da32e53c75ac4ee71eadcba131cb5251e2c0567760805356b9c9b01ffaedaa2deca2ceceff54b5f81df63bf2234ae0d34b0fc2b9effe533b7c45b18f1e2a38fcf20e08cd547c8e53430ec3938f3fbfd74f37c023cc767d94d19e4e446fdfbecd6b7c1f0c0612918616ef9000f9128c415542979673465a7a56b688b8ae356988c430e0749abdbf4fb9f0491fa18d02df70503f21bcb614d6ee53fcc87aff29ef66830210c3c9f7212ca515cee2b51d71d135c19411d0f6225890f5b00a78078207a914e900436ad9a4751f2584b0c5e4008342dbf30c2efba4dd634276b84a19f421383caefdb1532e35f754e06f3daf027712e86147aab5469240423f559ea3e9140612f0910f132e37ec87993c6d7bae99497518bfad8867611f5607df7a421a1a934669969a520cc6c1b06ed07571b1666e6f32be8caadd67736c9df5f037bee23f53ca32a5db18d315c8f0bed3728b0a0cd0ca5694081498a494adbc3b52b164e0d60d7645d79106fc75811b44dad2a55efd5e47a6c1b89465cc4e8de44cf5ec141c79aeed63d29e200c5726656509b870dd614506fe9f37edcce1257d2f22a0ef650444d0f73e62b4ef75a455513228bdc0a54203058e646d46c82b7e23fdafade17b278173811831f3729acd7267d3b46ac496ae12f2b3ad663bba042f5c0872aad4fb80a158c86edff7b0c9a678146b083cf3ec8540459aa167c15820ed9a1b31d9cb54e74373d8e38aea365d4992ecf7bcbfbefbdcf4852df832a3d81dd0c53f50c4303f6f7daca19a46e6a623a4a4878224c8cb9754205557e03246933b89d4aac08a2d05475bf1de4aea219ffe41740b5e5b0aacdc88e14f8b312cdbad0b84936f0cd994974cd6433673b30f90eb2aa5e57f0a7850bcfcffc68df7820763c89c4c520b9c731d22ba79af3603d84081c06f00521746db73fe87d2ab2fcc68b8ab23318d3cd01fa50db52839ce4f04d3b2ec27730aff99d01abc6455c8d8fd59bf2288bc1264833061e8d420cea51a5a7bb805c85b5c0d6997e17e4e8bf709274b8712c7e16d7e95979e6446684d195f2158a74049c5ea545f111c912492aac08b19c4f05b0175ffffb1e2807a9d4c95e1f3931ac7821e163f91122aedb366628a3c45f709af2b2675d200e623e6692b0545e9634421570813f88eeb8d5ef5388f2de18403c5e8f419e42a45e6db9a76cb640c2887a0e5efb5e946912e70bd8492458e4ae4816a73753395aa639cbb72e85a067875283f64385a13c9a04c98d14a651596f85f874288b114bbe2d8b75d63eef7656fa3c0a1b43c5660436d124b411449c4f7af4c879c3e7a56e0f05768097568c9157228c8078ac2dc2e0ea74dc0f840ed289c722cc65645135af5780c2b4c3aaf8d92985bc882983c94bee7c895c6b8afab61b62ab9ce30668a8ec612a1f87d7e42185d36511ea566403bc155960e516521b19b1a0dd5efdd35e43038d41844102d7657f9c838013ce9c305911b7df1194c81459e7126b17a867e7e2936eab6dd423fef3af94137938539ff5528af478837a0c1dcbf086ffdd91a52b4db7c3db166dcd51cdcf6c4bcf010215ecbfc7d34e902dede3726fc9ec4b8ec15bc494fab2149f24b02293ac0720a043ac88922d1438c4b3533f5a0093fe880f8654b8b0ca3690b91528bfb84f34734a06847a57fe04d322c28fb89ea05ca8eefbfba97c5881805f04ad8f19c6987336fb9da3be0233bea211522123deaf8508c7f8f77047bec5166c5d13e7a61590b1feabb7bff0cad4048ec5bc329b4b283ca8dbc4a2734fc6a33d35e6db681f36219d30455eeca2750e863f0b13c7804840976b10cd14a54c61a58251717389e44cd0b87ba96a1a250c6c8b79dfc876087736468a468db150937bc171a5920b13a5956f18eca72b7b42cebb2d1511cce134072ebc0f209bcc9bfb1b6f723fee505eb5c44d7b471f423a6d02d1b214366c3fd877da96ff2964fc44d4b0bbce828026cccb2e2564881b7cd4de295e0a32d85464077dc47f24808ade7ea2fbb75176d52ab8ff4af07abadfa875f4ed1b1392861c941b6ec761ad04a8c623e04258c1045a6e51434ac4757fab679a71685e3c107f4201062c1f7575d246ec24bc7f019f69d46a4046ee14a65fa2caec786ac15c356dff68d8be6228701d5b661af3aba0e8e8f029795d799d01bae0c02fed756567e2ecdde66f1ecb5590d060769876295e3693d0d48f6d51d33ed9620caae7abbb2c7928861723b7b18ae1d11eba30cf2f651fae40fabc985cf5e873c7b1e942c95aaec5c5ab9f571a232edbac22d4ca900915024c030c424d16e97a87b4a96fe4f82dd9f434aceb80cdaa73d6df86a65aac59b302b0accaf1fda346508707feb84035c42955ba900b951a66a459cf2311bd3898f0c1521336905b50f03000a157015281da5b63e2e85b92b587b7d12cb99940077200024ab0f29b585fdc50f9454a17dceea255d7af5c0e6b8d08c3818d6f4aca75734b114db86b3f7c2a0428d892ee2e08cdcca672de62bb7f989ec2345e26f74843bf1a1792c07ed4718525c011c904e0ac0e29962e3d4e9a3cf83bd9acf7b0cf0483008a8b5a0da36bab2cc16e41a098055bf471eda1aea2dbff272d746667b171661416ec80098f5a32bbae6227b6311366ab2ca18249a0204b03377a2e233a124f112a32af1cf76d349836e7f1030cdc83b8a95fd1570a6f198ef78f5a0c17c1c7bde99daa7f1a37a49c0c7c2fb011888dcaf4a869ee231675225b11323bdb640b571d7f849580a0f63d5222cd81d90a4b2742a211eba905eb3f5b5c753e7faec0ca7e4f666c5c116efd19d443f21c4cbd143538673f1c0f0c0da9641686247459a8ffb342df608da9c677e2c865aa756255cefb4fea90eca8d8b711096d02ec6cbd3fea14af8b36118d9485bc3a70e4ac6eeb13d559959bf1824623eedc56fd5cf47077b4f0e97131def6e125d24f74176f433e2adc6670768fd44133353cffbaf3dde0baba5e45abafe20a04946fa678fda79f48baffeca9dbebb2d7b8959c9e877ee7eaa1957c9aa08157b209f39fabce8ffa7244a99259926e3afd29d3490fab5bbe6bd68e8f35fbcafd25e658b77810f25a21e6d71825899a9f8fb6189fbaf76f64f2ecd331e3fb8b87974f4747df0b1366eaadde5ec11697c96cc383f9fa422cc8e94499be72c14b3fcdef5f45b7eb1a154eb4aa6ff5e7140750efde6839de6279710f7ccfef5ff6fb9a5ecc2023a90d079fdecfdf0610c186bb6700d372c50bbf41d26446810fca0c4f1a8cf856d16062193bd9f41265efc5511b8aebd389f83ea63cae2792dd857904e7a48a855e1969136136c0668e26f42505be2c201c9ece62b8f98df43190dec11a49deebbe0218ebc5b25ff6630528c8e9ac2aca1b9c333310d274a3b6d5ace8c2b9746dd870c50b4ce0a61944566c2f58508e4d1df4f8716d4a75322d67fa5d3ae3e97f0b1f0c114d37a1b404d8e032510ebb27adec72e3b386f436a0f75ac176ed459d16703bb88cc8bd5eb4b56c79a33cbcc2a80434e4d8df50d3acf311213ad5713b3c90b78029196f50a02d1e8dae46e720942be5f9bfea5627fb2e038e67bbf3182785dc3b53a20830a82205f4a4b308ce1e8e545765f91d407f5500bf0d055010da586360a43cff4db92ea9c580011c83ebc018057b52014debc50914a4a68f2b582509a152b7b41b6e73a514fdfe3c3484960cde9961e88ba2e35482f5f6b89c4a4fdac069ec2ae5e013d04f4b47a1e7da27748955a66b6e9bd70662602b742167b5e79368899df390544eadf5050ec6d9efcd093824240b279422113c92b4258f0cc5301f2275cfce67d1fab4f2627d81555eee86e04e860adf57722c0fbc6726f0308080f0284f703da801283c2414e174cc154d19ad12c8776d50224215b6b4971b1433171538afe7c9da3bcae68dd559de981c7f6b6907f084d8f351ea6c895a6817624c5813e6f281050440c50c405c1d8390fc8df6b18d65b413a69c1f61f32d601f2400041e7b2d440709b487f1030a0dbc84a6c232d756ffacd7ecd4a7229746fb746c3ce675a556e133bb501490d247ce2fe295dde941b572914446fd8d908eed1cc01c375e5dc8d8d8f09b9c6aeb76ea49182be43d9a18be12c5cd2b9a1e3e6adf888c6924ea11100f8206d388c3e82087b29142605cf5506480a50fc7fec2786263f447fa69ba97c42b9b5e44c202bf161a47d627688b03634a46d1448354175bdd994d2d7e789731a73f55b502e5cb574fd27452135a5df6f7032df287c85dd7ae9afe7b8db0a9071fd760a6ad8921d17e5e421325d2ee7ae2b0b31139a23aff933eb679810057a18d1fa1cfab1c49afe01167bac16ccfdf2a32ef6a307f53a6f53be5d24470c1a74bcfce88895722f787d99eb708c142cd4d4d06b81390f30ef410cc701edcc46d5a7758e26943ac5167ab94559937194027cc425b99f6f7641f89e8be775c050fa4a534fcec41c95ba1c5d94b2218a555fa90b0c2b5473ee1a16e063c8950ef4a01b9022ca4820fc1f3a365f1091301354cde4043533c71199aafd344c3ba6f420f7ece89108a84f3c0ad375f74a90573e5a23be42b62f3e61fd6effc47443901a25e347f7e04d8caf41d9cf9cce71e779be27c97da779e74e3e17c4b67a64c5723ad5ae16d59673daae655f4d80e47e1a02e2d68e82dacde493e3db5ed063b9cef13d5cf729f199127eaaa0e6c2d3d2f67c44e6efdb0810e5884f18b975760be0baad80c6456780040eb3e9279f21ae072e2ae9d66a19a49e20bd2c424a8d9e96aba5b16866d67ef809c48c3e6c557a0e2ec38071d7d9717bee988daa9d5ba070e1d742dd1aa80b1cff8d455a0054b5dfcc34647505e58696d6d2dccc5667f690eec6f1a1491d37028cf57daa8e3037bdd9fbac0d5edaac8fc3119680a0f2bff8d676ef236000fa41b590d81fe5b5df3c0151d6682fd247c291353ccd86c0d1b2bc09fbe61477efeef1cb658683647fcea6a397a4c2328e45bf4bd8424eba2c67b2314ecf49091ac393c2e07403b393a7d39a3deec7904aa6608db8f330108dff1cae3e3e78bd6a4d62c1554c55e2a9e5b441975e4414f72870a4233a3cbd036207a00ee964955269e657d3e66d84ef49f525ea8ec903b2aafdc2d56412b823c39ac816913cd985a71edbbb3c40751c287aee83b283be88e8e79556d198f20edb067ca75a6d5cdf5384277b83bc12cc64c0061d4d53b79d683e398a5513306fa06a4d76a110c7b32f127b15f5be109cdf117de8f6b5ed607cc99400e8d9fdbbfe22adeb8a02b57f5177670589fc7424cee81e33ffe0c662c317d38f107facd235d019f25a5904b3d76d329d92eef1579c1b1d84add7b067f8df76d836ab883dfa8d5d9c116c5ae79aadd78742f657e489695e6f96feee8ef3dff08d11f9a34eacd050c2c23e2186d52bc68d955de08a00d45c8272bb8483ec8c6b8ab05bea624dda49549c918ed53ca21b09be1dd217f8285069030df03a7265c8616dd6d238f8bbb54eb7e1f71f43e5215c813ea0a3ed85e761b3e8d69a5a2ec6ce2531cde10d69ce12928d224d69f39a54161591bd2068b201e2119bebb8a5791609cb3ef7ebcd15ace2cd18335be18c8014a61c14d1540edcaf2830ac93b1fc0f6203d9a2a788d22935f5718c350deb3260f32e0ec0e1a14fcffd6e2e2ea777160894d27f5a2f68bd2c3eb3deafda8a83aa4f1f91eb60eb77a3d2d10808ec67d8717f07b544a93d9b52a226a8303e114325b1b5e1302867a77df54906e84dd3538ca4dc602e0a606ac09f6c01d6fe9924d8ba8605f0c349228d757ceb484d75cc7ea68f3d7efa5be9f83e640212e4a0d493d3d32ca0cb99852a81bf6dd9f83ddea53565ee9bcc8096791f99cdf91d32282d4c5af3bb297ae4d2bcb541246852f55703f22c1e96331d66db6f9b286db00130a5c7943a3567ef022b5881fa6fda939eecc6c1706940ba830cacafc07a6fa3dd8597e6803db0f756b4d2b471fa82f9333b6ef490b37f4644bb050634cc5358f663dd47f33326e5265d80f1a8d12a91fd023524d7620bc5da5c7dd0c1309860c07af9dfc9cb5e3b44359d4d3d5199d06492c23b091bf838bfad82d361cd10710d0a5517a1f0ef0f0266e63c1d08fce59e13937939780669a5dda9ce91a5f6a01be9ec668917b1a66c073af74f27a5646804cb8a4bb79a860af8b8731b1e94338efe8190cc24483e65f7ee00675b72293dc5289b951514aba53861c5d54c270b2e690235ac3f53c59a87de2e15ec0543fe377e6821af6207e58333fa47b03bbc152762d33f90f1ee3f07f73ed2ad70e2ba40f6027b3d5e40366fb85cc8251bdbcb15f637d6608f56e58d43fc456f2141c394cb5df53e0c686ccc50bbc413317326f426c45c539ac9498bc5035b097b020fc495d30e6c4983dfa27370ee03a510d2d25728de076d109836def5c1a36c34657a5bf7da03eb1fbd4ec33ad2038768430d58e0a5a018c80819ab8188f163595f545514b0db0997e21d6ca0313ef2957bcce0e7e547bb68daa0cc6a166747c5eac4175e9b0cae7595f19ca9b952c401dd1bbf1935c4cfcda4e3221f9731aa4b6f40c2a6865e22cfcbe91be85f0ac46a94bf551fa3d2f3a08e6c90225201df8cfce00f587901e79189e12eb574c51f6a7890d11c58a32c90ddf8329c589077e19c9ffc65b101abc9d2291b9a5929643755fc79390fc9fb86c08f3d7411c380683cc657f94414572008934e415056f7d5fd265bf8897bf007314feb8876bd1740b4bf832be7762e67a50b347bc75af04e1240795c43ff1b4017ce7eba2653fed30ef0cd038f0fd6ecdf02d278953c15f248c28001b9a3857c355261bd1adcea7367bc8a41e5c92ae9473ad3caed180f002f545d700b42bd7d196c736b486dc62c22fc22a7908da6c1b9a3e3c8c5b7a7683e0a72fb08eff60bddd792af87533f147d814e53e39436e8ed4f7094d3365300f308d66d7bd63795b4a633d9d6fa99a3e15396e4954bfe95cd3718b2fd47c5489e45c3fb22f0a7cda20a56cda3da653ee64422321dcd6903d65c8c52debac39c96b1c9ee610d75f04717bbb455525bc22834bc9636dc29baa18fc206044b410c3bef4f06a311f263f499ee62ec680e80a9e978cf9be5beced15404fa37df7505717f12570c6e9a948cf88de8a90f7a1e4ad1be2f4bcb26dcbbc0495b1a3ec826ee4d0b3f627de80d356bc4d83d7204768cfb1def3ac0e7d040d33dcdfd4881207587fa8bef4549565d9be734bf4ff4eec5cb3a95902d5d4a24be57119fd716b59ef86699f56fba56997fa1f34b6904904f1f4402e86a9113b36737ad630f70841cbe6b6e7f2ef0b8420ec7acd6d36223879a59953ff02559e4cf4e8887537dd69eaf504ab4ce6eb412b157787bcfe9a7cf192c5bc168c4fb4b3b2a0e18e31eb03583fd61dd479a7960f6ec6a4df9a8c015b3fadb28bb832829da391de756e8d37a4219fc958a754d1d059a642fc3103777c1c4556aa266a263f5dfeaf38302bfe2f997201ef357150d26d6a9df82159aa6126bf987bdb6a420268fd75d7d6836b8ea06e20cd6dee53d6b6201a994aaff348821087c5a9ad04c4dec5e4fc8f763f8b018eec9cfca2bb14fd40b44e3b76148df42466ef6efad1aded97db9dcecc54ced988931e2fb3577970704c729230ce332b7527981245e53b2e6d67d1aac4d61d0d766bff5697730031c2e6fbfa10768be390b0e76f35b1eceaed57fb3e64fbc9fd28a69a01faad937a927ea3df6fc9d7b6e8df61f9a8e08d76795ef58e0df7e384439253fe3b59f602682bea89c6285f1a96d75a4435a34ff98cbc9f7aa0a89f71b38c73eacfeca0acfef9c72b8e5b62458f68b4ef27c33f1591d665552430c0401c786067c5351fafeefb9dbc85bd4b4078b0b2176e2221eaa8adf779389fdc530006259f6e951eabf18742609eee7402f9c08716a05671efc43ac08fc25856f1aa4ad2a0110b1e11cdd435359ce59c144533870c0901e898d94841bf3fa205fac6deb44c1149b58367492634d875d2f6c293007a89d4df4ff00a32347e81683a6a610a3b544de4156388435a864442503498e63d401b50aa0db74db17c40214dd1da4e80fe2f542a5d84551ec07fa4a9f1fffe51718f0c9b704b25706501d30eec18b88e6a4f146d0146175e2b32c04e3916d7a5837b14e45cc903aefd0da7c66f69eeaebbfc4f743ba87cb921efd062662fd2e876f43b492e7bf2be13b8d8b1c57d8ccbd8556927aa167c5944ebee2ae43214c503effbfdccc6d24ac316e211ece0951a29634d19a0ed310552cd724aed277145a0c8501ff86e8aedae2cc0acfa3eb410f571dd8de2d550794f57afd34e6d17f3c1c7b5200c5de7cc14aab21f45d9fab7dd34a121cd98205146cbd3dc6b42faecae1176f518d08d5c7a9b40e346c2748d10f6cf7039bde00508789052ae9aa9029079a05ace7650fd6315a8f44354f397ee9315fbc9be81480823cc362415975d653b05721e1ebd91078bcb0c5d6cce315b46dd24411e79fe3cfda40f4856139a3a285fd77f5295576641cac5f7fe49298f884cc11a38e8a3f03e9f4f55fdab043ed906ac75b8045256605e8153a6da919930695cb8fcb58fee3fe39a50caea58177485ff366dc071bb199e06e7ceeaf87e72fc68f957dcb0a20ad0e4ca0c95f7138a6a983ee0d86b02c6219d77415ab43a037775b6f0bd36ded21ba1eb26954dec06f109217fdb635da2c741ffda7bdda019eb53c9c3827230491f86d749273917b9d8591f40e6ac8891a40aa90b1fb278a2b3eec7b390f4d8d7a89459c856ff1c8841c3b7d1bf503b079a65cf3bf5e9a689ab6c56c2dc4dfa9f96fe4c06daba15b4d3369e6cfe8dd197894af35d2290e781f95bdb6ea926826fb413c5cac90bf99251234a143c83312e6925b97093f6cb836c532ab2b86c0bc36c6ee4276f78f1abe6d4de459a19f49196ccbaf5088536eb092eb03c5191c725d89e24c471a9065470ad35f22a05c634d852661d2c1d0c2cb134d409234d59f8e7adce1419e11658b915ac4cf5f345f0415fe7ce45ac20e5c45ff9dda18829125690e9d4d8e2579107b1b5d6122e1c5268878d0566af4c2d5fa8783ff8eda767285583ff2f51f3140f6458320f94bb88f284e6f7e18c714e266d913f8f75ce9b156438adf9fb22c9f2c8436e25082e9d7be819d4ed67a70db103d777dd434884164b89f9e170d5be78c14e0accd1526f5f0ba6a1a85e24d7a998b78a6c32f5101c1210b902177a8455d1583bece890a6f26554e67e9fd83fd9fb85e6469de0bb9382a31ef7d909076578b52f262a2566b1efb554a50d36c095e5fcb2988fb13006b6af2b7d527f9b1fcc044f5036a796f56280e083cedfa3af7935bcee878bfc5dd0e222b8c2fa61beedbde9a4d54c2d549b8a784304e0f3aca67dfaeab7ef5ecc2f878e13ad49b9e6ab9adbb158752ff63e14256f47a462c2a0976ef3c43bb810c54d2cabc4766ffdb384d33176ed84220f41cbf864ba2c2e79674529bc535fc7fa0036274ce583204c59736f2433400876beba95404ad2bdd17dfee0755f9f18bfd823e597c874ec1b8758d886558fa5acd9e0c0ddde69b01b81b334e7c2f341711b9566a601c00e7f285c507db67949abddd2291d798646ec144a4f9264006e9ca1745d4f26fc16e8f38e0eea197565dbfb04009c490fc986200093c7e028355d9ed88feacf5a3ada05d09c30c9ec75d40760059f7f4830b4d5421011a52c34b2e2e3c772105568e3e7b6a209c32bd5ccd3e107c4ce2d04676d93ef8e703b451870a78f147f4ac47c1cc3b23703074cde9abc0b126803c01be1892b9d65e7f07fe52350900fe58d97f059a4407cf78735432e08fef0e3c01f9ab87ff3847fcc7bf46021554f5d8a671f5a5019594e4e13011499b3768c23bdd91859821818e365ea1422ae5863675d4737ed5c1061124df3a3afcbaa0ad520474829786c559bf928b2b892cc50b69ae08fb3584e67d9a61e6ddd070c825d8aa2fe6c4df177ef2ae7e937c3ac92ea8387d97e86ad9c5b0fd9badc88244ba94497ebf53d2142d9fd4640c79b71d38804eda9a8762153c03a48fefe93259f72d632c9790fdffa9c06a8189073a1a31ac0e88b266b158d6e14128fc8228e2ffe3fc14456d4f2f5b7f97db3b233fac350e6809b0987a1b522af2bddf1c7f501894562ab6d6d58d58019b2c68098a308942539649c9f5d044b1f3afbb98160faf08b743e5c90bc6943190d10c52467717b301e4bb5954b91e294e3054a462141cd423b4e6129c05a14f49389950ff19337950e67e57268e62042b6ab56094060674519c97b50fd5c2ec9c4a098190d7fe61ee5a88e37fafc96e5d07e838642282aae9fcf99618008016e5faf2ce665c1ea8fc4b596b9b94f9045080e20623c5165d0b98f0f4e9144c20ff49874ff5c4cfb8097ffa4dd01507d8142e3684cdd8f6e6b76fa61676f4741768630e0d7821e4ac0ffefb74f93151c983cd14613f35fad7a3561483619fa0da69efbec5d4b71041abd2ef5ba9c23aba6bee0e67c7e554718e778e80b8970a853d6e48f3eb2d55b0c1fb0ee9faf91572172c46a0dbdd72a3bf4d1b5507a8c0613a30663c37a87ba91860b5e73926898f699e185d95c1c09752bb8a1fec45f9796d4817f3ff58570f201a298e4013426f5edb0b6fc4964b5ed9ef9bf84848e6e7a9e5909fdb4484ac38624b1d22adc86c5b9f6b15365dc2c520fd7c09b59a54973191a0ebc515201521ed41fec1d2a81354449e8b46260459d4b9042aa48431fd8fe1f2d7830bcb533ddf4cf4084f4c655d264320f1774d86c02786e09a52e61ebd49fa85aa4a527e2ba5f635bad0f47c3e869dc0772baaefbbd42fd15919c214ba9fc843e97036aa2f43a7a9c7569ea578a38f11ba8bcae25d0017efb4cf1324e75dd6888659887edf8b03e288a4dc036eeafe5b0073ffbcd736cff2e2c12c99e73563730d8936de80a52d354d617e3490c1fed28edd51c3197003c1f6701d6d0c6bf7528fe54b1f5c7b243aa5fcb73e120561944f215b2f41e2fc10f73fe5a75c1d867f8a7f805e98f63d48a9ce3b1254675b1ea585e0d32fb3ff99d0b4d44e4ab1e53fa1a462fb7e65c613bd42f5be0cd8f069f3e4398b91651ccd8b78d332f704b5bf1a3b6677c0949cb790ec57b0557cb344323d0444653fbf76ad6beef62ea57be9314376cb7c9e9f92af6ba8bc573df3af319a62494ada8443b57bd7911f71a2df34349a8f7e7d04bdae21b116be8aa2c0af7592366315dba135c42c79b2765281b51dc3e9ca34c62642a49bd2816c2a051836a9d600e14c6484639ad51f7a77f4a501565c060dfe769615f0f76d7171c0a9034c7f0623be6d33489aea51b55c5ad7ff0906f3da83836cb63c0aac344e8bbb08b89d2519d43e3987c3e8c7673fff830354cb06b11a1f8e9ea3209e24f5aecc95415bead271ba006fc455ce81a02d19fd24a3a0d0e0345f15566058c9a3f1f25d803a0213390bed4e6d5d3ce5d47e82e8bedfad5ee35a86c9d1a1cea20eb46164f7e3813b8dc41bcc8e62493fc8a864dc6c76108dd24f6d364903b93b8bf512a64d3664f663b0759fa6bc5edf734d74d0d58f146507972d02f47f66c80ce0e6777d93d53a240703431c6f4a6ae8af9abbe8721fef4aa9ffcb5d46bf2bd9f55d4f0581544cd5518f726c9de78f5027356bbff862f13e39039c16d11a36be52e62963e4296d104fdb645a04cea2eb7b2990bba60745bcb5d75286a734394bd8d4d42ae9a640ca9ca14768483a054e00ed2f6208b1a732f9c2d19b54c9292b3897696dcc5a660c0b89253e06590613f8aedd27196528246a0a7808d1fb74aafc7e41efc6041edc90920932b5c8bf9d596624f858c24305e5ecbaa0eebb9d3c0da3c462b716fc3709554ffa18e1ee6f3de7a4c2c60ce879bf0d385a9f067fc2806f9c322b190e85570941f11904d077575d8d2e42245e39b6026c39af120eb2d856ad4a5b6ac8f4bdab9bc9726bcd7ba49536cb61a525e2a04d5344d46511eeb33044f13d310f6c218d4a7e81073485fb4409d27b0e0d1b91a3c8ab0a86f48cb3b5313fd0f19f8531cf98705eeb0dc5dd2702a2b5ce7660ef4c101116eab30733881ebf6e0758abc7e29cd0c6c85a463199b6e51df786135b90e331247d138c8efcbe75447ec706d4548ba5ca23df9360db7a104064bfb48a76d39618389634973410bf8521a8e821ca376d8510b599f0f55556ebe1503fae8cecf064795b9b2f817b73e023f1f05aed22c9bca9a37653987fabe3584aa5dfecc25e886d9893a6f521489170472c888c9a89b742a18877e398096a0c32d300f416434b263a4aed4722ac629ce803f77a393e06422a9882651b30f3dbf119f3919373885cfff5ab4a43ceedbbcb7bfffb246a1cda650969e639184ff0c33e2a1684a38b0dfa8017c42fd66f02318fb7c60ef2505d9dec8a10cd8c24a306fe8f9d49ddcadfc41d19d02ffa5b861d5ce8d9f56b02befaf5606cbe8518c553194f4a2efdaa3e4b4b9b71562dc2978bf959da324737351b4b5a82439c855bdd4f9ac8b8a4a36c6a55a42cc5207a96b02106c28142e4cdebeb7e49c10dcf5d691e63cf53db6b2ba369e37ea724a1937268c0e2ad81ee6be042ef83ba06cfd5cafda9c473dc0f3d08bbf24735850f2217f665752c9eb35cda54430c5ace59adff02fe4f8ab89be64484efad642f3c8d00bb0eebf96e0d7bb8897c025f48a84c5aae85b14dfd175b2d20230b923d942b5e7c8308def8a2ad13cd2d91647457fba79579877ffcde45a426c92957b9a9b7b350faf747498db65fa703ed208c6355718265c405504ffe1db1110bde369cfa1f97544afc4c9be1be0e66c5042ff28f2d6ab23e7407b1f96dbe217507dcd92b7b9515453440ae4cdb7ee767311203e4fa4e448f81248d2d0f2e0b3554e545a84f06e497af6271feb34312a4f3d18e7e556b2132b11bc3bb2d62906eeb8b323ccedca0e69ab3bb47e58d0311ab29fe00d2982649c3cd7e1ef16628ddbb04152e38881f4d5570b418db0ee3d499bf263044f475173ce96f105aed46949cf21fe1be24700ef7ecfdabb8c8e08853ed968c06a0f0dd0b2f6b56dc71234f763c2318ded678e4e7c8b42f499ec991df3e2ea49679bb60861e8008565a1a9a4df9d14b2b32af3f056406e7600808934df109ee20a4004c798e343661acf6dfc51f6986a9443bb2d6629b3fed512752ccd72a1e5cce2dec3e6c26d87f7a3189b249e116f8852ea32736e71bfa938d89a2c7a1af264f5a79017cab54a100bca3f86a3354452cf5518135cb72dd54c67bf2084e2c69ecb714ddba050899d33079a9dfc820057ef6d8b6eaa36b5f6c69edae3fe3fa88556499133240105ee51eb73e0efff81b6f5ccf1da7ed42d892a9e2321e353f23bffae496ac1722d06f7110b93c2b768dabe0dc020358f2b712014190d261323fbeadbead988c1d206b9668933dbea7748da02109c995e675363ea33bc4ab4c0b987238e9c49002c301d4a502d7d3d2ac3583cebfda19ff7aabbcb06d9d4ae86cc807023719e7a0ba01b8b60ce79ee9656e8684acabc0195812d2cfa1ba9d1214954ac2891b9140cd9652bc48c8ceb09f86a67689500c9bd115f746cfb4def67518b1ef8aa79d6b58791380a0d2a6e3e028cb4038e40c83b75c9252a36965dd88790cce94f3ff2dda2cf395453b2ff9b862d75e06e61c7dc32c22315f59387957d7786199a8ceb0fc781bd408a0fee183bf585f9fa84bf7779627c8e438b4a63289c72b018a30e8ecbe15b98bd21d8e3ce5233a0681697d8d51b6f5094ba672fdd9f29210b13ace793e1f945a3b0ed0b4e3f83dcb3b9edf5f84b4641a6d9fe9d2b61e409234bd92b2cda5c8e61b0d6cc82b0cab2f397dd64676afb31ab934e15df785bd49a8e85347f898dbf4fd40058036d59d8fa634cbab17269d0d23bf4db609f469755869954957a12139ff70f5b05eb228e9c4bb5ee8b2cc0e775078719d5e431e8198bcb414cd28edd9571ab22e0582aa68ba4d2cdcce5d7a33a179bbcc81609952b5a42e16323541ba56f90491d00d0deb711110a377593616b175b99f80dbbb7f4660f3ecfcc849cf4a274ae1ec4993370c39ac7dc83ec8c7498db6ca215d0ed9bf7711dc58ba1ad93ac1e5ed3f7f0916ca194baa7c71fea4d6dd164444434bb3c9086d5e6200b022474b19fa82136e8504e693babe95831a739434f8400306005aed6470535050b7ef7bfe3e9dc13347f3782dd0a64075b0540f8a5067ff869d0500389c734664716db500ecfbff753816a0d72ee60f921de97ab0d9c7f7bbb44e2cabb0a6732e57e0db59465b4ae862b69edaa425f61ff2f229d1c1b55e0a0213624f1a0c44a3fcf850f5615fb39883f37f06a9d97d014684ae545edca63feac7ae37e7ab16b2e797bc99ad4dbd8ae84c3017708fe3827a13af08812eda8988d53f27566ce847ac913a43c3797033a4c8c5d4fe0fa5bd3cc0a9ea1e9a8c0e42f4461c62baa84eb2fb65b8e0273747b00ec17bdea49e48ea46146e61df1b0656de03d71dafbec87ad51ca84dc1fa2812a00f68ed0ef208553ee87a685456628a11dd825b3fadf92b1c2a2329800180afd1c4a3f8c33e2ed46892f8fb6a51b2e96518389213f82feecc85f7caf309d949124664761dfe35565db1ca23dedefe6d93b73c61b911fda94256936631c3434c8791f50de07e7ab0e7eb42beeae878c26ea11a87a6a8b66d5c968a341d7dcd2d48d520c10c9a8b952947d7e8720f4a72d4fa312170ccc197d94b99c917de94c5efc3e36aaec3e39f3542056b4fe1cd663ea23ac8d4e74638f4496a2ff246186f05f357bf9ae2a91986a2b3d7a227a712eb78b7a361aa7924384a8eb4224addbeac737c54c772c26e01bb73b61eb29d141312cf57fbca59f0867f818c19989107c77c38ededab8071585dc572abbebfaab3dc0e760ee342294cc016569131a733e985616efa4afce95ed9eefbcabe5f58ea7cd9b497920e6c5ef00e7386b51a7f5573d6089ba4a2e3ccde72c075da6a402c9ca991993e9ce56974c7c4d8b23c1ccee790bcc1098a79765ba89b537e2dbd3048b7177cda24d19da154c7ceec9cd4c3cdf1d22e493cf7b9031286e2fc2f674113a648faac0fd82c278f8a8168efdd9b20a4a8504e6a25da23b4b844b0a894b152916d5ca861c7db655fec77e520037a6c6be2a310dd531eede685068fd2d114304ecb034eb6e5bd309c9ce711e2e20ed26b3452203bd3175b67c7573273cff35d522adf8c3ba5e328e99a25e3bf218b7ca7e8d98245da5582a2ec30e84db4b516c6a6bc2f68bba68609e5b0a21f046277fb545d9a4f1f3c57c7855dcc6e08e148ed0b4189bd04aec99c21e77fe00d3f390ca06cb2fcaf168ad68a83ae68fb1da72ebe705c46f487d213eeb7e7cd0b7bd3428becad6c5a71d166e4b15efae5c8893c3ff8ed1033524da85fd3989106113d05ab547446b98e869509030b1c5cf83ff5a16534a386379e38c8a504c53fd336a992970dee86b4c8752fc28fede9f20921e6af498faaed9c12682fd5f893864bf7afffc4a382f6427bb71a7a7bc6e488c4e0fe1b79b71ab9e226ccdf8c55fce1900fdbd6ebef595e3c7bd233d8fd83f10bd97eafd4790a49f1696d34d681a4a6bfda0789245e2f69f2c9bc3849544a5d047c28e9087eb78d9efab70e4676e22de7665942aafea1725f5c379f6b7bc326367ddb07a95220c240decdfdacbdc5b345cfb4f143b422e85d6c6f070f241d3ee81f8dbf70bd8e4870c7314f0a2dd9dee5b8ad6286ececef92b0329b15cccc44e5fe0287d3e74d70290792b3e6a108b00689ea58e4e2120a6ae9f7bb4269b8132a8912d3bcfc7a51dacbeae810427639be5cdcade7793750aa77e04600c82e46f49c567bc7f68fb1dbc782d55ee8c62647952c9417187da6dbf9edf6250049e98ef7d4954a7b6f16f21e10a47b4b8683a03e666695ddf8a4f90cc8fc5ba3d8f59d7a4ededfb389e55780d4b18e4ece85abebcef5ceabb2a396199016b6ef0a33a86802a58be6b9d2ebae5a6e3cca07281194c894bc5d5c11d944c4e9cbb6c65ed81f6a705aab758e91f97aca6b9bffdfe01365b0753fe32a3693c7d9b953147505061d4cc39c5d15123ca0fcaa113ff29a12bccd95adfea484a2bfb0f5aaad199bd76e9b1a8e50f67dea17794e8c0af76c88019897c244161c8d7bd8450d142f1f327225d28d104addb1564dbcd50b4289faa13dc2a7d274e29ea483cfebe73f8687c98548abd9c2dc948be44077a6516bee1fa5ba8b0a8fc586a8fd11359eb2aca8cef5e33e8de7e902c73719e7e32e70ee0ca6d414b486f4850cb2670481c737b106d9f069b15fda0eef73029972101b9189fe87a97d4f051ba3ed1dc6b81bd12e7d975dd13d0feac5797fd9267b5985ec9081e98b421e8c446499588fe5de224a6ba0f320e4b93fe6433b3db007d5f6ebad142013139ff1ab96ae286ba690535a24d177f2fc03f4e7a3816474bd700089b012658cb0c8ccf8d6f2d9939f3f2cb0d6d7a85017f518da742d640b9216ad4b3f41147fdd675a4fd8644f37a731c335c77a9794d0d52db53ab564e4451472fe21ebc3c7e59f63f6d87e88b0efb450a910d143d8e460fe15203fe2cc3ee1fdaece85bbbebc80df74596fb10eab75ed3bc51527424e2d1d6016b1ec4c7308346730cbb89a6c7710d5222407a36b375b96b12ec8853c882fee1de02de5f69e106a3e1a11463f8dd1150e7f0623d8de6e3aae555ceb1f7276e2a75fa177c96c83c3029c4c0339e2fd05ae06235286f2200c88d2a37f929ef921052c6f657df69cce29a62fa967ea644673b893b7d200aa3ba21f23d4c3a373db0537a433879fcfb5699153b3f79afe821a24d2bffac084e44d44ce28f6500d9147ae183cf25a595ae919b37b736863ae3d22a11275a60f60bbea318b3257efb6e2aaf025c7fefecbbd6fc3e39e3333ec1639c6b5047fbaf6154c38fddf823c502ae4405fcc38479d0d537ab72c0a925b1877525de97d21c0403c4a934eebc3ac95514468a5625cfd5fc44c6a584147a4149c8f370ec94f2de3110eafb4951133b929dab60b7f62eab3d0269d8950457f1a675dbfe2d9d98cbd2f1028d46f9a31db8172d84d28f6b95623da109ff96812444876da646e081543b82e4ed29a8532833dd34bccb96460c15017991aad2bbc8d1249176cd53cfe16482017402c755c86a23b68bd61b835b39aad73eaa3824cdbf5d14ebf6b4230967dae177cf8937b28192389c5f5172ff1c732ecf2f0f83e31794e7cea21dc088a170793811e20573f739863e63f264d6752a7998a0fce6456c2a9769ab8d71dd2633fda30a082e45244e8e70d3d25c837d7c6faa79a1d4836904a2a6f4ee2e1933bcdf32a94750b027fd2fa32c0242fcce60973c5247ede80238ea251df63133cd2e1888eabc369734379af412e02567d8cfba80e12ce29c34ad616033c6605639da2310beb34a59101aa3bcadfb407f96423229e788e7ecc0d933b6ef384e8171fb0b28d0e7e77764b0db0f93a99909dce44ca83b4df8648f0f1530b13850b173095ace79ba5c2f528f80035eb85c75b58d2ad91f17db0253a0657ced215691ed3aade8445e643dbea7e43aefe9f3fbdea3475d7b35322d4c16324a20c37f0e78392e79f19a3e9f4885dd46220c86b6e5c5a103e9522b9a52a5d0b3772be0bd7f9069d25ff0ea55c10b7abeed4cd04d8f4077b1f7ee14fb98254f68f4e201585085bb793837f422a5b0ca8d4f8d10374f9553cc0abf359bb3e182b61def4ebabc3b3916f42c39f17faa3c1676099c112fd4eef1ccbc939605c000bf709ac20098b2787564a59f0dbc4a9bedaa44b862c40df53b1857f7d1c9a4927db7e2cc4bd6d946951d66a75969ee42dfe6f3924440513f058681fc8d667d010d8ca40919d9139d5d10f915acf6b40a7656764a5e79406d24ddd4e35bc98b440e76ed76c1332432ac703cdb9acd76f876209ca4e63b7af90438004140dedc6e0e3d227b659dc75c6dcff65d4a41f019367fc1b6462bacd27f171b7adacdde4af93824d9f99a8bc418139f1da5d9b5b4d3700d32566cb53a051bfdd3d7c43fcdb1445a66da0adf2bb29f41f81aa272b015e3d42882a4300dfd02e1e7146aadcb4edb50239f2ec1dd2271974a660094b2c9cb5381fbf27847ccc213f9a6df5c1c6873eee5b4c9eb6f51982e48e946e0f7fe3c536f65a722cdf5cd1f763e71eac8b4c74193ec02bc2fdba3a4879bd013e0aff5984fae30671bc621457792306162c666dfce02e9a835f72e7fb312f139559cd86e41e64018eb1e9a4b5f58445a47e6c1f3e6869e3bc64fe8e165821877c74f9beeee17be1f7f501f93a1c01975b7b540501a8e6a1765a79a6cf8ebe75ba407343d3c66f146dfcb34e3447fbac8735cb568a5d5c9c47d532a10eaf267eb2b7c55ce58c8cf156433dcc574c212612beea4dab9773fe8d9d9ccddb3a334540a80bbcd24ceacbfda5d0dd91adc2b36adfd112241b4d74572833d58e9715f45f47a383c2ad858a460155775d6d9bcdbb97aeaa364bff127ab5c4d518be0107841aa7bf3109092ed68d2fbee9373b3c170beabedb03748b0a12565cffff8004453d1ab5c15b6984c69a80dde52c4966274aeb2f97b95e94ce6391e12a101b282034cca3ea9aee2dbe2a8ef5861445b04610cd1b62a664f198e41c102e37dcd95630f526d3d74e4d354cc344e7e56ec173097e6243db5c2c3018d0880013a7b36b1b003fffe6fe033bf64a8e7aed47723acb3da3ed0a65af8b65796098ea56e2ccfdbe9362a25fa02db3f8e6ebcf919d235044c1364670456c458723eed4a6a599c020114a6c71df9158315773df10c373b3c8a35d0f4708eb4774b445937fd90623341124d562c45097b87e3c864eaf49580d47c722167fd7bd79c5bbeb6482baf38d641b19bb287488ff09a8d746c62035979edabcfaddca72d4e783e01080e8d42c0b05284da076ae0e2a8417782bdc7408a35ea86893220a5eb9454dae7574a42e3bfeb77daac14c200857d1a1693fff84d73354591b7a5d02aa7e94209158c3d9d3e5b428cda74a62d9d70d34f7bbdddafadcdc13bab0bff774005c8eb21d01f4b638c649fa54812ca8f752eb5a58955ee3d70dbe8cb95498e085b78da047d8c9c9553e9ee2b85a872fc962b98752c57cd5b590234fcba0e6f337fa29c55e787999ba5ff487162acf723afa9de1d6f5b58ecb23200f28ec20b63fad4881a2e5ff25e1790bc713b490e79a5ce2b03880c501919d409272de8536e310613f29c8b98255a9c329145447f363e7ea75b8ad4bdb9d6418f0e505e85770216ab1cfe0914d94d41274fe9fc324fc3940456bde52584d5033331096d1e78f84a5c2c73c0cf78fdd727a3cb0cc1a6e71b4d38ded069227be3ba2860eb0656d84601069da721a8e5400790ad8e535371d7b32ffe91017873a295f7a9999660c3d44598ae7fbb7c9d1a3b800058f6b632e730c75e91a878e37539cf05e7451ecd40ad6dce8f972274c630b1d0d489b750876881973fc75dca67ea01266312ddde93f35af11c7850a0712b6f2f7cce7d9d6ce6ee71421ca886bdbc83672afe61582cd37b33c94ed75f5814ccef30ce0e3761bbc8d2dcf3a956c3042e0a9d212a2d651eeed44be6ea504536a42a40759aaddbfe10b52ae1fc1464099e1381236d4483d0283dd341c0e8879d9c11a3847b235ac92dc18a3056a72c2309181da92e2aa47bd74876b65b4bdbef5fd086d6290e4a9eba2255e7740ff5e37da424cb0a2c552229c82e2128be65b8b060ece30a267efec31b3fadb5bd41eaa493fe0317489a64bd54bacdab9ac376bd8f303b82327c30e537639d21aaad5788fdf73b80b8981121afeb96f78877b5a9a8bc109b8d5ca4dab91943bcba64d6498c81333c2231b1d1089758686fe515585f29c58c2d4664c10f01a03225a373a49e8cf2869fc5f519d4ee8cf0130fe9aa90ea77a2fabc25ff445a009a466d24ae0ee7d96d1965bc6698280f20a3d4ba2a712c3cce5013df5dbd2bb9fe824108f4abda0566e205d7f70c461e00745bba5f7cf31331713ebe9e21232e0305a93c971f94e1336d4a55ff11cb8bef838852415dea263f360c2e91bbb01ac432282d60311fb10c7abdb8fd71f03d168c4895c03f9a8cda80ab891e1f29256b40ec6bf66bac0064441406c10d736d18bff37ea48d265b577554e10fe103b2059dc67058813611f36bba025360b4f90e7ec9de12bda188e964c91bf746680f37c30b85ff15d56cccf3b34714d9d75854cb3f4d0db925f353c28f174415a5eb450787c6d207b018fa001d0ea043ce1dbd4e9772e4146bc0ec7dec81a6ebaa142062e562b5dce0d322a6e3afc2c25dfd27f6279439083d578dc7ac58e4d112a2add91bcb20df97b507a4c048308b783ad049307d0bd1e6a5c4a0735bee3244c9d8654006fe28aaf8f6df7c020a2f7f8f2afe9d69c29e75023ea59ecdcb1bebcbf546c8789d421569ee0c3bff8ccb4a5015ec7bf2dfbeb65ac1bd16536c1fa0f4ef41cbbfc7fe1351b6ae83ac386e13a0d7cce100b4231bc3f0898003f45e37a93c67b1d4fd5c0776c46c3dbbaf15bdc082bd0db648eb3ed6462010ac1c728a7065d970fc4ce954dc4bed98f53adb741cc612bf89452465c2ca0491e35d0e61a42fe068d5a548553f1990875e9016fdb5c02cf1b3502c4e80deca3e129b70b85a7d37755edec01ca02a446037ecfe0007d9857e3d339e4ffe1b037535305a9e86067a304f5ab020966dd0698f88513d030ad01e48ed20b442e6cce8ed5336b5907cef9a7692783bff98580cd5b2c644de21ad4a78a35b38483bcb6a3c436242886c6ae59cf5110c99aa9991663d32fe4eba1658a4ca8dcf133a56cb3d4de467620ff7f883bd7c721f529286660a21ceb0ae42729c3e81150feda827fd80393fca63abf1b8e5c1947d296df24c64ae9bb841d5d58ced6e2f0f37753a1254e5cdd085e877c276a0f9d71f7b8379c7d7ec16afeaabc63d3bf57189dc734578135e6ee4977856d9cb1df420df29200002bfe2d78a9433d9c743e3a13b6878edb57d7083ae8bc4088f63860f429e383003cb88ab9149acb4bccbf86383c32c55bd09f6538ee640c5dff6999c6311a36e662198e943901c4d9f3968a778b90ea408649ceae6c088b5f1ce434a20ce6a00689c315e94c1d00e743efa6b5f52319cd438f3b38c2aeeaaa6f52927775df7330ae6a818983fbbbff9229bdc19b567b4cee06a55c154f62befb02f14d91c7db869e1a762f8b28482bc4daeac0b8ec92d5a19505e9d38a0daabd2a12e59e5978d39e0868a690198dae6e87d80f02fc40e33f279c27632d6c9bd847b310d4e9afab5d5c7384eb4230f1a25d19c49803f40881112615561df8a9b7f7625c70de26b599416a4b6d8debe6f2da25192ecaf8006100fb2162a1584bf915f35e19d7633c989aeaa236636c3ec4f91a5772fb1002359757fd1da9b8cf107767375cfcc9b2c08df128d9ebb2f7771ff66ffacb582b79f4f6047232f5603eb17c13b15e9ee86b989bf61d8a1c05a6fb3e788cd9961aeea9923b96f76062ff72aa7bfddf9b5ffce6a707488abfacc8e1200f9ef19299d8c28e108cb57f6b2ba4d64050e8b580e3d392f320c0aae32e00c9ed0705c5c1c50321040ac317146dce9496cba1542b9cd79d70fd43db439df54e0d95cc7eac3fcdb8af018bf794b463161add5d2ef2a65491e5d46e020d821d200577f290d202a46d461c321d3d4bd6ecac59b459b9dc17c53524f72ae38077764412dbdfccbb3092e388f63d467953b8fd0f41c8a7d5f577d062f96f7803835c168c72097ff7db3e9b3a93c0a01f7fc27ccb848ae4699ae878f370ac3bd2754eba8a639c33a1a56a4d3ee3a5174c2c994340e673fa6ba4260eea6c43297f36d1700c308e20840de8fc4f9a501240dfd540f307d568d68c68eb2e21e88cf3b1c85eedeb714241308453e78c0f75b61edc8c26c22b04aad6916503da3718023dffe10d43928b6e9a80291f7858decdce60c783930f25d33c95dc2ddf63bf51e58cefbdd45c6b48f2aea4974061f10e0505062623e875771183d192a359669699313faa61e73e7a521dab3c843bcb5ee116208edf8620f70687030349964f2afc56ea7603ea1bd154ddd6a96dbf0987152d988c76062c314e87cedafd7bc6a5cd37203e6522fa26afbc8be5dffea0e68ee734070d34c2bb77dc8b8777b8de0f1ecb6db23f6879e21220b8d6124c282b086d210305eda42d31fa0b5b22945840a684503babeaaed63c7f97f2cdc49d5976553498fd21646c6f65c015874b4c81ae79e13e05d9264827f3b18e680f7914358a64c4cbc09295b0afdca54bdff9975562ed4be4ed90314c7f7e1d783015802caeae35fdb22f7bd18f57a96f70f38835ddc3c1789954576f6ecd38c5313b3d4f036da101095a2d3b311346e12ada851e7a4face652206712e126337621cf99b3e50d9918aae11f91f08ea33db3102ff774be1319bef7e1ef7f772458f4a40e2e23803825f6cf1e201a43c1685c20bec9eb06c53e89a0a4e9dbb86a58ebbf5dc775834775c1aa312be720c72995470835352a062629574bf30b8aa5997409fd4860511bfc1f3d61b7be9a7282397bf4a3a688114ac5380aa8edc314d968eda2682a908ea5ad90ef0e0f75f1c3d3e0fe1b0e430cd90196f040bdd6a05d8228942d17c2cb1d520c2615865873d11bb8933ca9d7c5db598b28cc8fc35cccc84480f62d55ad7dc4385541e5a06e0705a5e881bcc678fbfc0be16975af66cba7a8ffe8a046ec12cda41dc77487c6f9682c94887580a903e8743347323c4fa87ed9b114ac046191454984834d87044685b1f44f60d646a75db63f79e63d74574ee9ca3f9006a8cc2883c73c35a73d52224634264e76e2f5becf061c11682596ba69fdc475d0a4f008cc1cdf3437bfe94b86680853071bc948359990af9e2e7e542357ff3f2ae530561ec4cab11a966d32ce1a1de410ee44420c8401c1396641460e20ce2d0cac6cac274c4d4e2785bf43e2d87a54661f5dd730c6914046b3af49b4605946b3cb9088ae0e7d9dd83fd479a001f8b75477ab14de39858fcff06849cda2ecf4ec02100594ea9d9e9e9c80fcfa79112e533ad079fb3714b18c62c1d0809e182267afdf3938b22e9ff46beb9cb36233e8f2ee592d31050d7e93f6fda33d5aa6784bcdeb5d2f34cc2a8a2a535d37d7b52686bc992ba6fd9a8b7d67dfe620cb565b6ee7d0ae5690bcdb41a201db936685026c5f76ff4bfc836d3917c4f9001c7e25a87d304120e8550d42b2b693579f7a3e4b90dc7429f8cf530c8b043f821bed653646906aceba7604f2a945582fc99f2dbeb2786cc1c10274a32d15b2112cf90e5f58e4a746d8831036f50d47d6d7eb207067bfa3f5ba22291bc8b1406b32491638511f5d4ac8bac92b7880d2cce1e36136d22164e1ea5ff200b582567b33a85092cde16b852748f3bd5dc9c95b722fa8f4c71d2a43497b2c4dacce47f4b497fe20a0b7cef2882b57c85720572ece074babd84e868703d53b47072c4c92d5398d2d37d09400d9ea3eae5af45c4c261cfd589c6ed1af4050745ad543b8d162d4fb6c55a1036cffbcaa0c25f34f00bb0c2d892f34fb2aa71e21c9a4c3b0ea62148b6810101b4a6b11e9049eaaec0343e39e90f92c65053e7102b838a59ff622cb5d1446d085359aa48ded534405f8fb4af8b207a530808f0b9c09da145459a41061932b50b90b91707bc549aa9fe57c0961cfc81ddcb2dad3177cc7077dec9ee5b5281c970fdb3f54308ec41c5854f82b6062448dadae4bc905cbd891eb888d8c56d5d180d6d6c5c664428f2e96288b90778a51d47cc5ae241b1f39f1380f5bb73be58bcf2c08c6819c13c8a0e790d282bf6b9dd4171be43a6c0f0f77862488c99a5afdd5d2dd3bcb2bff9fa823e4fa9bace4a3e37fa0b1698f0f44018d57c71e30112a5946a218e6cd02fcf2a309066f6b480b230637b3dab6f0f92bea61dc940de7728db68ae39d25f5a951dae1bf0294b3b16ab100cbfffeaa6f489dfda076471bd6b8ab65ea1bcd3b15663912a7aa90780dc95135548d7ff0114e06ddfcbb3cf262f1d018c53db7c2676acda570b29fbc812ffc8c74d23bfcb98e595d0646b13548a05ee9d868cb33bad4a63487f768531d2e63c449d6c9e1ced5cc2951996bf564758e6a6833bcaae7fd839cd54a9af621e4939c6e485c9774b1ecb8fed368c79202cebfa916c20a6e8bc188c3c6a6f1234900b4aea866622956062b97fb18acb59b395af749c45829573fa4c7e4d1402d7ab5a976d7bb50931d09a596a9b1e1274286d143c0acf8d92001353649cbf1d7cc48a2c532aec6fe6fa42fc857a959a8e32118922eb25805fb4964e4dc08ea5a18143bd56af1811b4d7db24a0494a5cc8b190535170ba110c0048198974df5851b2893b38e890f4a80dd68e75f2c360a26ce93a22f4fce61f9984d395921269882d8aaa859e6b1512448fb541a079c7d4d3c3c31799f8427551e347630313df4f5762f5d19c6d4b26aeb59e078534deb9c88ad8f0902353818556331bdd38b4bd2fb766f2b37deb9d15ad8e231b060f72bf1b3c51ddfaebe461e345eac7cb1b2e1bb68f5e4723cc8976afbeb72c95fa4182f7519b3a24adba4dffec9bf232f4ab97ca5516058c4e027f87fe6726f46ce696ba95c495f572f565d8bb4b543d2b93320387f20a56926d65adaa5e9fe40e4792ac6f77d1338f6d4e940dbc090d699a0a8481bba2a36a9e4a1e6d25ea7d8eecee922e16c84103e434c95df32fa7e8d58e38a6c2e433e00c9abde9172580d34c90f1cf54318ddda440ee0ed116301af2daa3da842facbbcb88f4c237d285fd5011d3cf54b0a06d9b38cb9d0a42d93a98641d96fabe868b348ae176045ccdcf59a0f4d43c7929ca2cc92acff551fce5a6be726afaae25ac3072181e19a23c305fbf9f826812bbf2e64b98d0c289882caf47f3a595970c429f55544b3bf6ccb152d9a8827c13194028655e7401a03936fc829e34e24bcfba2085ca40a83591e1f1039fea6e0b2665e0d807dc51009fabbfa32ab1f834745f75ad94d7f10b0f87544b29fc59ff18f528503448cf9b9f72738499ee247f39af36ad3cb4de2232065ded5f4f3c09a5d973508147e1311afcb7861eadfc673cbbffca1de01e2d5271d7079a0a915ee6030068bdfb1c9696c5a539d2b47d9f19a03cb12562fd472053f175eee36c7ab716c3e2ef3b276382b114067cdfea9d04fed6eb5de01612f90abbf0a831335e615d5e8215567a3aaedb966fbc4c0bc5bb013be319b1244bcd156b7980b74621dd62261f48322083b074586c925a3936eaf9d6c5fef0cbced51a13df04d982a91c29ceeb3f367f6fc7b376ea6f52b42afc7feb365a4ea59b6c0cd6f07dea48386388f378a1fb230e6f874ee697f328a43f931e320114b703f06ff4771355cf9a0bfcac89cb8672c0e554b46db6a4771a8a765316ff89a290ed10b7287c2cd3c3fdcccb5a7d74395033dc1efb3a2783a2957e9f664622be0ade6875a88884d58f64ae3115e96d20c85f5b9dd2e8a27371b2b2d0ae0cff99f6bfcc3e7cd7bb0c73fb668cff039510b36ba2c4cfd2780dacc9c09d9c059f1e6d0d67cfec2d8636968937cb86660fa6369011bdce0321e11af2614c388000ab9d7f492744f10517bdf9cc9b5236f1eac0d52736f9c06d726d0822f5b8b2de7254da24f20da7d897f3d46c8a09d857c2eeb3be1be16ab1910577f2a7a5b59a7d36dc15125c88b5cfe356552247d01b538f9c9ba9404547ebd130ec894d51694fe16fa2a2d6a36e829f5f676b8124bb1e846d8c553236020bb4e721fa545955e777bc58d0bec7f76c1fcfff3382e85ffde56cb915aa34d29f9a2d762e8bb81d57bb048dc9ccb0f365d135339721197a46914c3b1e3cabbe017100db55e4561d812a1c8e1d5b35bf033fa7546d08d1bb097f30a111fb4ebbc482b8b20d533bdbbe78b4f2940b4d81e8044708152916e51ca259cf73c6ec858dca72a1591294261889ac167756a2fd08a7142d7a47e758af7dc5a55f1a281047e8d61b8bd3301f60072927d3fdfcf96dac8c5bfbf3ae4d60e421287e1c36f8a798f643a6a76615404caf55caed81333ca9f7addbe8d045281b881487effe973ba08ca6617a312e490d4b48f1c199b5f283bef2d13226f82829cb5a07866d3988858f32b7ed95ec3cda187ff35e36af4effb289b6290a76b4bd576dd7a88dd30758375bd3ccad9f602fa3ade8bbbc03a207588c608c8df81fdfd380140adce5e0c4aa824a3f50de5094c82aabbf6ffd26aceabb635836a0eef0b858c069030e9335649ef0d1b212e5ba47719473fad34da0ec4b5acd13a523ffa1cd76afe4ed042b4eacdfab336a99477807ef974120507749e1caa0d18dd51895e358e8813313de5371e2f90b28ea3d7493ac7d7dc33ac6c7f0560586f8892c4d001a5aaaec7a0cf223998ff697922e89b0082ac6b901bc75ee8185f1941f4f00e5c36a9a6d3613e530728de7f2d3f629c4324006f5dadb3734b99c00afeaa0c545dbb0874e5e3ef43fadb4e8a0fa291ae31160cf2cb2cb8705fd9784df2b6af781495fa7554affa7d0492927322742f8c194a45fb631dd878a27cd52345fb23dc5d36cc6b7b71e41c56deb5f19788368d9017d3aaf32d71151bd97ed13f58980b3c6ca0727ef3e4f3bb0711b6d5b287ba82cf64dd21347393caffdd5e09d5207c365e937ff6af0964385dfc5d8dc0debf5e9542e773b815e6ac36cca829daab6ac949c3b2f9710863fa2349b58f7fccbd35565807e608c442ca60c5e161986f7918cf3bf97a124c152a36a0132990f7e2e8f2582df6933c638f7041eb8b11500b60eccfa4f78ff06044024ae948c5fb29f1e6320f70f88c3b30ac176c82631ad8c68b4540681d1e30d4ce421c941cba23618f1eff764a4edc1a9fe1c63aa2e6d848a2adaa73749108357ecc3a086d4131d1a31bea24cf87c564ba49abce47a021d05327413113f428bd9ffac4a8d4a937c024da632552d4a7e38873bdc4968db8e5931b46babe044367165b0ce1380d51c94292c05f1d189183b20aa4b2f9333710b575cc1dbdf9e0c524b8a1567ec5d6841283f647067a19cc19385684e4a3613f2e523cfa57212f7413dc115c420037ed8f4c5165afa275ae0afcaadabb041e9b3d33360c1ca4f2445a953149828026207ced4384667a83fc9709633cfa996e76378e1333ababccd70ebdfe54d9a5993242f6cf9f22c421b0c48a089b87b7b91fe6fd58404342bbe72644c1f36a5fe2e9f7d1a15c769c32a1df9bb3a8a2cb6876782b1bdd75e6f430d1e303eb9a826115837f5c0f7492eb1deae699be618589b6631c263a13bd55338100d067da2108fb58c9655d2df19727db2d430c0abcff85706b6ad19fb99112d090d3ee69bd04d92efa16c9b3306ca8547baca0eb132fe9e3c85b878d7016d1eca9970486354263892df7ff348d5c9a51858b762cc88fa11bdfc99940e43c288def9f45387da613586b4e21da438d92bc9a2f43beacadaebc717ae3d5461f0a2a3a71fdd6f71f97c884ff1a62b5f5c2566cba16e24b866548359fecb00c1c5576e05920c017c54eb389291cb7c24c2bde2572f7867d491c8ed01c59f992724776afa541f4f517548f06da5c0b36afbc549cee9029f39e95ea7c903dd273c92dd1c5519b45493b98459dd88b98ffdb3b1000d22b94054e28b1b20547a6ebfec345e9703c18b3ff29a7545ca980cfe52f9b4c6e0f00f80c724ebcbe2c6a7530f94b90145096ab7aec367b89c9db84327ac21261f03e13a9d22f58c7c6f288cf25ad0507e252454b0dd0f75ab7185ab65cf5ec682d5338414cf71c274937d0fe39a3e894a0888616099e002ec91ec97babcd499d2ecede0df39df31e92286f91e510da4c2746f038d7db6dae3f755dbc7ce9d26d4ef081bb8f74dd0aa72956b9b12b06479d9bd2c91c80fb757eaa96aaceb6ca38adeaef289ce84fa64b510fb711ea03a4f642443f7ed216069263ba39eaf1988cb7f7d5fffa4acc375e9efe59f1d69f970fe984317de568d9b59230ed995efbeb5259f93f52edcfe37af5b0b0dd9198dbfb41b161e6593fd6a97c3e0638e975cc87a0579b13117224d643505a5fa748645753312da94557d947c18775028742515a955c6f9a0643d353077300054874d5bef29f1aaa550e0efbc690b3247825002fb858553abdb97c38237d573c1e03f9637e493de58cccb6e46eb608126bfa578044f1b9a3357d8980718b66c54cc826fc09e420ac25e3e6897abe08cdb29b7b720da55be06e7c92c1f2d04c2ba284b27f3bacd3d3e452472271d1738b177233139b9a29cffeeb600bbc03847fbd64ae9dea2b27f8950e9938163f8d0695e17e6f7165ec609e445989a90a5f48c58c4f506171fc7aa5dac526da8bf8bf3508df8ac658f64e29a01843f1aae6ce491f7d50e93cf9e89fe53af1ab5b6b52d962f4757652fda4a3cd11e5ae031a3b28b8e85febc7627fd267284a1fc612c07fd40b6fa1975510a79251cbd6f087b4235ff496ef3797850a916e9b65ae4a5882ef0ba9c1f53afada26f6640f22cfec7300d01f1f78fd4edd8cc3adf4b4308f8cf618929ecf7d36e13c4743e31873d324ae64cf5a221269727554dd8453f1105063b26ccbade7e916c96edd0c44590ad5a41d147c1df76e1c87cdd845c4085e0376793335e74a4ab1ebaedb2efb19085a31335a179dbf9e3cd9c8d60a30907fcbe9f38c06cc1dcd8f807e7327e58d9cba5576e504926968687c2b3de9ac0326ae3d446c66a3762ae92a28a8ce27d5a37ceb49dd3a2c9bb3a475f843176d7c56276e661f30b19e73260a8737e681e890eb7aa78b1d8e56eba354974d323020e61f87d17d7096ee666cddd523c3174ec9a2db3f285f6f479d3911e76fd9a5a101f501eaa3631edd0e7f374ab63a02ace93812f610d8ad8425e162a5e6c7d9616dccc2fbba798ab14e63050be1265be85651428756169bd01f2c5e6db863e4a1130870fd6c6d2bc096a99bb07fc32937795142aeeb1c075bd9658964e6342d02cdfccafb2bbd41cd23954b61fe837f62252d6382ebc7d32dc74db0bd09df91de9d8610b6d258bb98b84fb92fcd895f0b59247ec96381a9ca090724942178dd1d64d8f66a57e2ac801d7bfbf8b22bd87fb0ee4afaae509827746b948de4e8b6c110c294813a58dfc21c6e39a72263c10ad0dcff878abbf64d26319fb634860e3c70eadaf84923027d07e825dfe4cf2bbeddeed4cf17f9b575efd2b813366b39a614f909cc43c7bb82dafa4cff769ec5b0f449e3cf9f499c49afda8850bdcb6a6cbbab8f75c83ce43d18fb45d3fe08e9088508cad671198b88ee741e2d04ee6f6107a4f90faa978226804c10a6e014bcac9e2fc1b165f65573b3ce79d4a230293271cabbe7c92df19c865b122c4e36fa06e4c71e04cd3c60570fc6d4f94fbbfa5d4322df861e042b9d8a3d97e1636a86328581bb1a6651769362f51114660717216a96b5532bff53311f606de1e71ebe5edeaddea5870aac310575c0822020e0245eada80949f50828598bc6bafc750e14571e21800d45a6e7b77bf93bdc32901ac09c7bd52a09418180b1981ff45c1db6cea08517bb2ba5911596df999ba0c2e533239b703eed67b478a83cbfe619c0a84c9e897252a157b3e5b1684466ed998a49afd2c768399bd6d596d9bde2babc492fc7cde3514bd3b0476566e427802648dd868e79aa4aebe351b733915bd90d1b68a36c5e86041a2a07d27ddf9f207a99f3f33262a6434f37c40c0f7f03030dc8b9f87864aeb5db29cec74fe62612d65f74ac46e07b85690b5fa866cd86196c22f290f8488d272e4d4593aa1f3d74c0765e6dfdcbf63469bdc9fd5b403034d9215534b17760069ff3ae37cf5b4b1011c083ae5060d64ebd36ecdc15cf94a179220ecc088cfde3a8d90accba3aa8a9297e819d52cb8bcdf4c7c6a4aaede4675e383f5458efe20d2ac85a7557a459ff431e5f885936824bbd914d4f006954eb789706ad04b01116a7f59c7d9f9f78685156cc2164cf4cf4f5d2730a68064d53b14d2a09949512f8c87a60a63e77e2ddcea6488a23bf4e07d24f85ab2317362a67ddeb14e96f00c8342e7d640a62acac81f5ca68178fdeff3baaf4ac6623a2b2f0ee6f2447d3efac8693e9d28ec0c5734eb4fbac2101f15cbdad6b6308a3cfeae6d3dcfcb7b214610dfb7487e42478539b887609666d3bc0527266b2b421f17342fb77b7c6dbfbfda902b82bc6b6a3d78cd7681e517cf36fc52cc5e857bd2bc1ff3a8cce9994d707848917688fefaf1748555940f51d80035dcd24067f32ec4d86e8e0242d18d971c7c39ccd6738b7133408b40371b8e6dc3bef0d8bf9f909477f24e13b399857f2caf6e479a6409bd78e4d9f4a94178d6cdca57a622dbfc145a34f4d0a3ca1af1414ce9fe2fc0b6615a74784384dffd8c4673c091e570c06d0f58300b3378a0e6a3394d6782421f7587912cd5af299653f0f8853e16a579ffcadf2ee81019d08262ddf78024b4f60ca9c687dfcf8abe2db60fa5d2bcf201a0e94813475ed88d2d19f433665bb79719f7cf56d84e642bcfe8c071df03435a9fbb6fb6f26fc9042f026f37f01284e22ec5b4018ea7232cf011e11cbd5244eaee686422dea52f0a3143d1eaa9c7d8ce9025ab4963c5385226584b1578cf68c12b9ec068644eeb973fed2c23b16532ce72d690d8c60e30cf703c86b783b3206b77407645b6fc21f77a25b211cf1184d10e0770fc75b6f56fb78d500fac523c659a4c4fd43c51538395a2cb342094996f3996bd5109f58a721529483da04d953e03933ceb9dfcaa90f781fe846273a8e4354807a62103f51f17d3d14d91a6008c9f056db2ed1420808dee30b685631106879f328a3ba12330e68a40fb8e0379cec6449e7aa9040c9e24db319d901485d8f970a0a82fce4f6d8dfdba3db58240db0383d4a8741a21d8867661863416fbfcc8293ff8b8dd7646dacf7e8ef097313b51722b442314e1caf47c3aff331584b47fbac2ce8d43599b47b9295eb4f6f730d86828d0b5b8e9759124f079d54a75c9f6c69178a91e5ae3e561bb24f2f0c584233deda758e98f9d0e8fc3f4f25d588566cbf6f0a9d5ed85d4063e33529bfa67173d872ed8871ed0bda845dea17b35da4a078b2e27515999bf7cfb61e369b1fe7e411b0b9e52b6f9f95dfaab917cbcfe7c2f9f3d7db5930dced149d192c2a68926e1d209ce258b3b7e92fcd69686a88e5f19f7a2dc927112a96dd1da8989d4de3c3880c94d2918af7930e02394677aac4401d12e5e9c9008bcf10503ea6aea609ba09789d05b9c8cbcc9921045213e9de63dffb2d2757a9baca917ae47fd8288346bfd6f140cbe02586478f6ea8933c87e445b778fec0ff1516f8856111ccae91afd550a7b36427f206b77f551556a5e6d0af7258823b004cd503d6d31e7f4bcca41a00ea671391e4fc916ed29c22d860440aca2a90cae6cff8567034fcf85d2a660ba01adf3dc9bb07be64fe8d313087b1f484a4753d441f27d7d49e422aa097a437567d80b35dd07895f1f8ec6a043bcf542c4294df7bbfe0b3d93311673ebe4abdee01ce26aa8999dca175744b8f6d9acaa55a84560b49c5fafd0ca0c1621419f18fd9cc8973d5f677ad8204781a7fa91735af6ac67e9a83f4109b62010d19ed8f3c77ccefc1ca247269bd33a5e6677f0af5e7cbc5df9c62dee99c4cc32a9eb30e074af598195824c960c3f46b05e3f141ed6c0b57ef316da7fed8ff64d6fab01ce2d3673a82e5570fab0f023f5824e3ed789041cb4e2c39ffc79419c8eca29a9880869476cf3f1695e27354e9493f3f56cbbfe9362a834f6f468ffbb6e5877ab48945240c87cc51ca749034035e1414c99a1d351c4dd02833e2e36eb2487477137c015f6c319b09f5990e08c239bade582328d7ab0152c3259fd507ddbb046961f60ecfe27e7155effdef1ca3050cec3770c825a772efb5a0a362d9595249e0c05095429d674079ee1bec891b9f7322cf43b3e04ce12424699c1f2e71f2270551f7c5d70f82a6f992b28e971acb29a48e0cbaa96a0322dfa1755bde2d565a1ff340d2ffce1e8cf111c44154ae144171cb63f81b2a114cfe39724239dd87bb65e7318bbf59781af1308d6827bec50ac82a348461c868a68f793aa2ddfe6ecf0f995ae8e8962d16d9a9c51a37669eeac33f6e5e54431d62cdcfd3536a5348e36ccd8da2700ac92cff26528023f230bb2193da7c5a4fc3eb31ddf557e55e9e72042edc3ac416bdcc4544507f1219d8886cc14933594554e2f9b6edf8c46fc3dac2339ea7cce2e70f38a4d756ee7948f022305f7e9508bd48f04555d4e2e5c142fae92411c821250613d9cc8b17d8e3ced5649f48182ea242996db5a0c36492343174cdbabf16beb4064d588e2228c1b3bf0400608e0315eefa35e11d907f53de61e2346989e788e89316b47b60fa75b82353a64bd6494a85ff0079a4555ed145be4048243e2004effe40942ea7a5f417bb4bf5785cf6fed5c6f983b4836a3e9d36b91e9abccdb023411bfcc0580f4fc5514dc2f6cbad5881b035185ca192ae38b79094d556a07675aaf8a9ff53f35f903ae35ffbd93aadf15859c7aebab57fdc636b99e37fb98d051a6f33500f956c2e6b1d8fe40c507559ea7f479d3dcbc98ef66ccf6efef661a9463d24ae49893e87eafcbcd2de3918e88c5d8a08a2a4a9a7db5f0874da88eb6de6bb1dd8735ebb4ebc3fc9928ef836c4a53f970b2dd71efdfefdbe8b3df8bdd0b79260e037142af4675708ad33466a2f98e92180839520b8ee52025858ff7c1e7017d92e65f150850b4a3924c595ecea22060248ed8ebe197d0d92f14d3b90bc4c95793ef282c15c5ee5b17d4ec9eb8e21835e33d922763cf009fb79296fde28a3431b3c039e42fa7216a81988ad04b4691fe722acfd3d44305e1e665b9b774985f63c6d0af39d7380d7a8b32c567eca7c6f9a00a196afbb1689682a79433b6b662646766aef7a3a462f8de32822128c63cb7d32419d5806014aa369fda97364b9c409a4699560e8345775c6e8a811bb699a232c65d92121ca29d0ba4f0c4d93f3fe47c7a3cb094d3858d898c08cecf48f52e88d8c5f812791a8037119400f02db15ea5f17c0ef1a55ae5d69ba492ba9233894e07bb9a698b6119486d18f298007647d083d5ab322c4090ffc8f39a8edd1ac4fd3e9826bdbc4b0f17fecbae42ec5d430b47912322e980a1353668c6865f5b45aac3ac9f13d067711247d8f928900d0e05d19d8a2f51dd9b201a7ef8aa8bf678f260a350f0af1d9f2193cf1672f02eae84207ec0a6c1345302279572bdf8bbd7b159acd535f30de577df88b9a222a604aedd5024a4b865668716f3ad01b76bcb531dc4e0cd94ee93b7fec825f7c700144c505cac7b94f6d20e90f946e63d6055f617f93cf97225feb1fd79c4a73b2765a824bcc385b3b0d7283e6e3995a5f39420525b69fe9b88975e075e0083d7f5b10005652db85bb81f5016ef09cf7afcd5694776a17c1655c65989700330b19497e4b90f391ba054ade7555e1dd0e8c8f1552f67e24974acdee008cfe2d4d0fe8eb53170023c6dfb77a96fd09f5b9bacb6208b8b2fe57b54318b6dff6c158fe44d56d7a2fe4ed1db3c7f5cf92de5e3fe0f11fdff01137de90e405af95e034bcb7a7fdcc910d08647c7067ed5db0a097fe06b61cbe23ef7be6119c1a5d67252331574cf3017e98a9a6cf6c9e5a7d8554e3bf874905b682b57f2e676c1e7d76bcad275f8dbd93894d0094f3ca8cc354b973c59a8916ed3d994dae9220d24573d173550611ea344a6dee5f50161cf0b8dae0729d3ea2ae5076a63d74861d30729133b5ddecc2e1035c341a8088b79001e80ad7f385d0debf1fa5025dc0bf8b6f2112414bb12ac5a70f593f404717a2c2b1ccd108e14ad4d2093e50a4546be2d124bcd5871403efedb4f828130c209f8ffc95e645d080ec443859275df52ecc33b58897d74539bed909da14f4f7de91d5c731007a385093b52ce545aeca1e3144189c95d80e7338bd306c7225cbca02947a2e47c423c14f8bb4024a0d492673538fc5b66a55471c466c2c8abb98526da74634f74a1aeb6cd99177679f4f3c8711dc897b31df26596e5487c329c4320ad020c4229f5fb18d51e121ef2a685a1d09763bd8f66dd367545a02346afc312b4be5142ca97266db73b6fe5ba57ee9423f0aa9af73b3b8bf6e6f40a321c57c746ab9d740902d6fc8b10537484f417949529f8b01e61a4dddefa469ad2a3f8fb0d3b93863a37b816ebca6fe0456154e4c5359a60d5945a980685604d5f54fbbd97df4dca80602747fd37c56c1c2dd47053a8dae05e78458336b6bbedf7793ce46ed6898794cd428421bb5dab748548ecab96d4abc5cfe4878fc14e6e751fe59b604af93f678f1d103e80fe1214f44f6b9409dacb7ffab4138ecc3fb6076189b4b8db6b8a61961d23d5f68ecaf9ab3c73519a1c38bd9e9aa92bebcdf148638e064ec178f5c2ea570a44f7099d90313cb08529af03d207ca34175e5ddaa6be4b3a8ac2b36b12b17691dd25f3112f2adedaa83fc0340d9948fa7383a7863a68387f300bdbad9ec01f5244736c310053ebf5d5470a0bb2234edfe30a0d127453ac8825be814750a04f483623dfa37385e90d7ab4b923d63f2a97556fced3f01e3099c17a7518a94bb50e9d026b76b93759354b782af4b2c6d872b0f2092ab2650c7ed99cd82b8f63241646a3aec741241ece601a9b9f119787e2138eb8d684b17093f1d35bfdfd76263ae3384b78858546f83fa09dd665aa146737ba8f73157f524e6b588e67eb825660254603aec45a3bc5083d4f32c030f7d87d2e2cb9fb57d70e794b94a2520b15c7a94efd42d8efa0b33069adb583949081502b87b95b22f13b5a8b2d2b2696783b321ba0e251b922c11dd85bdd3262c9742f1592b557ee455e474c8943cc4f7ed0aa27f12a230a20b225f7f90a18bc8f5123709f0ef4e380c763e1e7bf9091d48b84a44d6b263136551139a72e0ea2f64c2f9134dd7905fc2456c6d518c0f4932706d844f43c7a929e604778a9781df105297a3ed69d0153b45bc57c0b40e1b9101932655debd582b810c7dcd36d0b6c71f2174705f0e2fc36f4226dddfafddfe6a76f1b6baad3fb07a0f3e975079a4237756c9b7dfbdcb8fbde150fe179783419c973ae8142b9bcf5d2f4ae6a568fdd7ab1e4a7aa80168ac85e127e97ee249e4170d0795102bd2bcee538b9fb9bb2ad430831037b09923db4ea436eb9a04894cc1f64de74ed14b78ed01f65d2dc7d4c6535190674f89a5257e2b780b6b069c96e17ea6656c65aefb7258643c88661febf5651a4f372d8b45491e663641d8495e878c40e1a0ce5ef75d04d68774373858ac75c1276c6d4adb3cce9fd0e0fa153ef9659f99b4e7e071e99cd420c7f3c6ea30d99ac4eecf12110cfee55fe73ab18c4818f15c4adf225044f14e77348b0ff40b43d03dfedd7531ea9d087b8ccebdc5c87dfda8ecfbcfeb2b2f503dfdb99ce9d267ac7c10acd714d1f25fb6eaa7336a3f2f6034892cd1cad20155074ca833f7e7c46fa6552be4803bab85830ebafcedbbe9d9c75bb245563736223af7d149819b32e45ba9037c3a158e1c8d1fede78d07171a11155bee2eb277cc993e7c6c5f0a02b30224ad1beea16321ba6a8f10d54ec6a3ca4771bf56269e4b258a8a2033d192099ce9649100198aedf041c8871a8e8bf1dd5ef4366aea10a1c1f33038e1810f8f2abc91c817f1b391f03c67ebd718e1fc5a54c5af374e54ea59a3004d7cfe27551a93518727845991e47f12a43471c593d9f5545c2e91a6941b65bd877c9002c21a7bfe151baf29d69f9ad4fd1c8086f6da8230703b64fd996c0ade1d923149ee8a801928f4080bbcfdf1bc3fabb831a4be83e48f51ac5cad466a5cb6acd8c9509d300b579abb773165f3807b7463770c31108f226f9296aba7e3ff33039d889c6fa313ae3d08fc209bb5f16144017aad908af773b14ddbc58331f5e52637a570dd8a4410e37d3911e7990653a07e811f03d4f94ba85caaade2e12e730818c9a782c734fc4911408024d1cc12075b5cf3b1d2de088f1edd506ff79c01a3cdb4fb02eb68cb60c836273724473d35c0735921ac4c163efe51491930602699dc6fa0b6d49d8eeb96e0c8e853e8901e5cd849718f8b0c6af9dfa72fbb4b021a0ada1f21904b817b20ca859ca4737a6c0eb302d9d9aad50c0c3892199bb137c3fd1e8dd4589cf1e42e47777415d3b4979527919da10327b3477b8330a2b4af4c2714f4f8f4992e08ea377dd0207030bd91d57280d4a649c475891049fba55df2371c414b00d6eb29dbbca62a3dd31960a12e58451992ad56e80ac6d55a618e7301e1aa23cb1b1258fb7572439ab2fed48e47b2fc0117e9826fc57dc15e8464d25438d271bb9c42ebd377cdca1a7ab854fbbfe5883a1752fa017f3b443912d7c0157a5ee60bbb48aabe36e8b6c4af78a9a634c289a4a7cc88e8b1c070c109447470eafb139abe08e465a781f2163ec0feecf71451ec3e1160ad22e0c05fed3aebabf381a4e5a410ee006b154a329e2dfa810a47688bbb6ef5a98820c0f1f6e7c60778fb108c10f9c0d390e2a1a982342f578d7fe138711e5cd8fdec9606006df21d665c6ea687ec6b2f0af301f97d8d6d84ef76f6a26e3cb1b68dd384681af4f75b8aee3ebcc3d4785c09eeab7ee1ef172fb1124038c80df6d0f31889f3c828de8b2f60876485bf2bfa7edfb339a0785c76787ffef1bc905a00a443f7205f9ac43ca2f63cb9fa428915be73e4a6b0a4ac9027d2bbde8b2c4d1bd133f17f127abdca8d5a97803a255ccd27922dcbb14bffdb97de71c72a5e50d17425badeee9fb7cd35b5dcc53cf448d336da906b58eeab0d237e6ba30b56fe9654428c03f9abd96f5694e9dc6e7e3ff2db9df3cdad95e0f174e212ffdbbde9eec089e1fd1698de6cb3009a637675cbd001b1273b4f794970c3f1b7d64fea646154e2356b7d72c51ffc763ad9dfa9511408832061a803d3befbc90bf1f40a2f156c4b41642379e2c14fe8da73bbb09f555daced3626f643cf182eeff775c494a3e47d8ee29edbe05b37e7a26838ab04c99c60089ced70d906254323acfeafe69c5a0e65d18a4234e44582c3f7457bf0be28ea63e64c1353e78de6f55a601c88b09ecd3deab5deb9ae6294f4ff006d890bdd1112f3f60dd8cec3ffed123f8d216df9c8b11593e0664dea847d10d32886b4c6318fb199c863f9a81d5644a12fcfe469405ca9c6f785a23360fad42628748db19c8e5e0658f7435ad85f28be4503fd87630f0150c4376e35317205289c529d239962fced9818a7f5ab5dbf8fde9468de7a82ebe294dee71ea19f2e3d29b0161f7df76ff7df2bdeeb815e53c26c361cd1964558999edeecd935867e3fe252aa95c7240ac2444cdab9851c8096e0369f4d035df9f8e88b47f3a766a5de1aa3f9f80c4c06c6a0e42e9899e82872fe8d947decc04f6b00416f318ac8d49dce67754aaaae34e88e1d2d209c85e0c39984c1f2cd40c142ad85eff188e0ce45b53ead550fbe0984573b4e3377bed8b4219ebd0a5e1e1cc9c65da1f9847fac62fe3510d4c385809080f3e0af063bd5072032735cd8be9a46e0aa968896a4ea14cf9b5962e5552a90115c1505beb5fda1bad0a2a903587d2c603df81a4cd9ae44703113996255fb1f9d00e30fa3b70e8f3a77363f05902665dbe65130b02d29660b1041db64c78140a74c535effd2aeeff5bdc81ac72a7a5917a14cc012803451fc5ffa3362b29a6ce35e6bce348bb2bb1a654bbe31cb99fc84eea504931a7e9fcf8853f5e5452a31de62f00c0bc969da35ea90670c056d28b1e0b298cf37117f73358e69c9a1ca07b5284797c57821400c4023e713a032ef36ffa95cb238bb4ba4d7fb1d59563ca003eadb9f644562d10f0031dc7f7b082166e9dda2e202623fc6fbf21d12112be056fbd23536ed70b6eb8140df37e7ba008713ae7b86c707f61293da123b6f16f2cf07679d3bfc8aefa3a4f10e30b9f1ace5a713aa6a752cb95641100b7ac4de2827de50bbd210edbe7e85f8d2087ee4992fed5d39a55f7cb6e34d7f9941ac5127efafe2b52d588e3f5c11efdb601115ff885959156b90c6209386bab912e3da74716cd100793325f42ef9375606b0a257144196cc311fd12187dfc877530319d6eab53827833d3aa6bddb750a1fcf7344298d3924c7ca40944d4fd1b48923184dd65cfdd384fc8fef354a4ac1d30e0c200875b292e96b26ef3a3ec1e57dc6d7acb59e894ac9c8cae7567b3fa26aea917d83685aa326ace67514f1d95f031c4eb5d01c4b47443f0890a970d2fddc738f519d13f08ffa35abca98abf9fe48e3f8e30ca77334a9539d15904a9a5f8d97ccb7d56d1d487fba3dca9ffeb7461615d91a95a84090ed15582ec7c1d3c141b101ae755218a8cfffa6d10887d2c27aae4a8dc27c6d04c647384d7e91a0a34cdf55599382f23cf6d75b148c4bc2abdfbdd8d04ec620880fd267dab3c9ba1e336bc152a86a46834012a173580f329bbf998269d321bae05070ad562fdb4b48d37f3bf6e04586b9b6f5720f49a73e6c5db24d82e3253b9e79b73f3fd0e240f012403393cf2260579e3d138145675d225ed94b1b2d1bf468c7784ef1941dd6ca7577ee5d2de70918d401b753b4d35450a0a3be9e44b13722daebb79b3f0ce0417cd7ea96876473bce38f0182094c56db381de0226abb9cc216ea8fe27aa915ffb1d6e7a7964fe09f93e298a11d122b6d6c82c8d3daf069932a51c45cf765557b45c3ca4156a109f13f26e9237d9d048be386a32010e1d42e11a469328e5bc6e305a0d82b3d46c3cfdddb9c42f2999b101244fd77eaa32e5f1e5c3fa45d2f73b8e779adae44c2d2dde9db120a11b5303dcaefacf24c0fb8578ea3f7b693d7ee97cc020a9254ce68ea0596dbb61757c9da66b17e83fd44e3c538d6bb3692ae01de062cfd2ba462d6a82778b246a1aae36aa3bf632a3634bf7e878eae0008b0f68919e5b799565e2123c5dfd04f51efb2188c4fffc679880b7605c7173ae81103917e291d073e1de8e516303c1212f51abd219a041c3ce98a06228be467f380dd75eab72da02ec938de16fc8574f948e3b30dd42b7090ade7f72111905331284e2c4da39b861b88cd6992b6881a92ce881c43d83f90553d52c703c3afdbc32258c1c8080cfc7f4d6fb16e5eed17204810ffbf774bfec799847a6d98b9653b4c3b82aabaa21dc60baa6d1ac75e9f9ed6afebbfaf46abf72e3fd2732018f56b7091cbf1d516584e375a2eade14a45ef5ba887dab9fbc9d3dec4456630ede0dedd8ca9d48e7132417cea5696ea4804161f8192692f5237459a0e8fbdf9303f8d0dc2d6486d40e66609052ba297c659853b703b369cdfccec7b4d8500c98c4aa8539a95cdb4998420c6040b25c5602840a5451f6185e65d67a49775905e1502c8c3f3289f28d2da2f92f59f1f2f97f3f3c8a9c62c608198488595c65f77bcf14bdf799cc357d03ee7f6cf850a38dbad77616d97c7d3b0c37fb5322b02bed1d9f63b9e5983acfc854422d18cb3547c60365f3714adaf81ab6ce0df20565a0572d834ad76f9047ec3485d91b6a73c00141dff5bcd819de4fe7d0f6d4e5d5741c9454766f06926b619c7c2b81c011d5e86df844cbabf674c13a5bfe88227b7a77f134fb372a3ff1218f7460f92f54e3f084fba8cc2062a34c93090b7d8aefd5e1d43267912db966a315ad752f07d71463f2704fa04dce18323ea709af0869b121e220a0d96f1222c0dc50216da5ab21de8ef3c499b3ebe4a54d45d93890d29fe321b1bc3817aae5fc83c720b2e73a3522470f81a80630c9a70924f2893d037f3aa161a520cef925600e275073f60ba71e092ccb129f24995cc9034104f9503e6c3e97cb9b56f6f7b9ae8377095cf0add29f6166208e7617f6bab84aed7b704ba21f2f2e49c2f48a004b55f5f888c81bdc2466482eb207de4c4a36609263ad62ff7fdb848109b76f84fb4c5c311e3fdc3fea818c3c566c2270ef8f74bfcecbd05f0cfb0909167a49d0c5519e0f80f445cabcef45f43cb6a3e5fa370b849c9b90c37cccad2a0efd0041464f009bcc818687998aa605fad4426c5d9b12f730a33eb24310b5ec8741cd401258f34a0c3780726d2f95997fea745472b83669c092b1ab0c3b93d16627042130690e7afb6ef4347712962847b1092c840e648817cc27094ffc43f9e999ba710e6eed637374ffa7b8d16197a97599920fafd1249153ecb4bc43a9956554466830d048c49105ce8c11074ae86a8ef93be19bdbffb9a90ba6bbbc1446886ba01dbacf7d27ce75d9ee4fbcf31de8cf854da16087825ba932527ba51816dc3b0638e3e5221bfd3d3bd10224814aaf56eb79cacce425490c82ccfa1de4c751748936e736a19e3a06027a49664b7bb1d26bb7fc49f0c02d9f692cd08f31ddae7f29b673c9ce4644517bea295f7d5b1874679f77cad1dd5136f06252b54b43975f9f5fce8251fe5ff993166edf48a8aaa960b74a7939b470540b052a673b5259510fd5d00dbeb30110f1c5fb31831fa5228a6f9e3b6edd35195a31cc2d78eb1a62f82ae994ccbb914b136c649328695e34f714976e6181e784b07021dd0fb9cb89447643fe45e54ba7df0c88ecb73cab3b305d22469c6720a6f5b0bc2b213fdf69496d7eaf8c147b3bdecfa076f25bf48eed03671502f6ba574133902205d1a990eb4fd4b6d390c8b4962ba9d62fd5579a011f332876b79ee229f1cbddbcd51bbb99310aded035d6a60c1ad77ddd956f6a1adb995f4218080d476ba107d0d20bf9c6385c6dd70927ed2b9654c4717e26ad523acc6f35df6ecb3da008324422cd8c37caf0737c789d9ebec48d6216057e01984abc47414e484fa197ffee0b63882c0d17796e7f96446f8696ef1a1a1526173fc1bc249eb37b7d4bf033f9d22660cc735fd4559ad5479be0f25ae75df149d5bfb56341eea43fade4ca58a6542460bd303a8ba27b4ee7775aee2847e70747bbf42fdec889356e1b98df984ca19a70c3c0e8949d394d6ae93207259a309d73790914f4a678afad4c2dfe8ab2420d3bad23dca4010c5891067b3583fa252b4d38c73e5b8c62196b9ad68536f65e2496ead60bfd406b1f177b908306297357cb8133d94760c176c5c517d8253156ee0ffd316956bd001b466b00af921b8589dc43c11255c7f9b9a46d12fec7bec423f7de7b51e98dd93ab03891bd4bc18ac195a108ae2c6714c2ec338bfa866f129180286b8ac182c207001d42fba5b8762392247bcfc0b91d25c70a34f9db85ac13a37615022323147c1ea4894e48e2a52f006c7c976ab7f04d388ff079c377958b4f8bff974fa08726a83520e9c5a776375f76effe0d80c8990bccd5b59d8edee40688c9710cb36460493a297bf9e60b8848259d70030dd858a4a5020c0540eabd3c940a042de79542ab146020fe403d6f3147fbca4b21c37fc24b6e93a590578236a0736f5defbf45d40dd02bdcc4d259380648a1465f438dce3ac6f207a4a187fee56f644fe23fe31d5a6b2e3e57233202519415301e2cb2c38316d6cbca6f9ec8384e1577211ea0c37cf7d25169b01914f2124218a7f6608c619d63b4daca0fd11c1ea244c38644319d2a2920efe5fee92da8deda983e196940468b3dfd5b27dab8025c796414d9fc810afa7ed0aa256b1d56a2640e43df8fe73c698139fc7738fc7c66bca26f70a33d5521e01b59b9295c3abdc3741afe0fb8fa88d0d52eac4689e200e34367b0e9f6cc7ea7a6b4bb411874be2d09cd0d31abb22608d1058ada3809256c5a24a05ddd30b0f6afe294e518d862d920bf1e6c9609d6a516d5cfea0f6a81dc9809101231a504a472a5e97c0281121f2cebfbc9213f5d62a92dddde1bfe433238883498152a6804c77893863436f8366b28693cb7a39dd48b4d2f1c38c3f250c50cef37eafad5bdbe1d78bf4e8863ae9b145351678c0d9a71571debf1dfa9b93ddeabce846a01b2950091f619fbe89fecc025bcf2f0f5b186593c0bd0af47f04f58096f9f3afc379de4ca5dbd38b01a491114694a0ac02a96c760d6d3acfb5c7832b42ea5d6dcba002bc254e5e92f237777c7c08a3a4f63e78df2cda73e86522ecd4679a7d47f82ea70bada1e9e9c312ddc9ad835887963938fa259b3d535155ac8759369ef8ff1f9b38ab65eab8a018ee643fa119d9570708ed21847a27a3f659573a293a73b212459f2fe7c0c53f12e851863d28465499cd9716ab05412ca0a1a1fd316694f5017504191a2a1c3dffeb466fac4c8424cc48fe25662b1fdd2c75abbc8670416aa8757062d5c75bab1ad6f9c68d99dfbfca604e11a6008f9f964f5c30029f3ed31bacbfbe35cb674423e1023f47f24c32cc6c242e11b5656d2647f110d050d2fe38e97e3df027cf956a4ed3d90a92d0ad86e6fbda07cffc39848b0bc25da664ed9d72b90ce301d64794255743c7ce785ed6dfe4a0b47d12dbf46d3383f2c10564148f3edd0d588838ae3c0080a50aa4497f197cde4f270557703d7f6b44d6972153b46cb6c0cc6d32536e67978052ff01da97e199654496c852d2c10e8f9b378e042b7a7d529831d2e8b417585fedae0086f51a2162d64711b72587a2cb567fe2aef7a9ddeb4f87946ae640b66dcbb8550afdebd9bb2a41cedf7927827230586edc1cb4603fddcd30e0a794ce94241ebf2890783141980001c92e8d972b6352def71804efc7736cf66e8960b69f4fc18dd325b9d06037259f38735f36cab3ed182541d5d3682e0167c1914d3c0e558ed2f4e90b2d91ae661388b14ab1c0786c75fe14b858fa80b0e5130cd6e200051e6ee2db83aa8f68720afe28828c170d17d6773c4498e42eb57bd855ecdde2aa97050a3be6df4a27ee763c296ce1dc99f6dfb01c35df2786f93c66dd1b15f59b481fc22500ed78855100a4c0f212c3a14149c3a88deda78f30660b2061ec7f2790863811ac28217dc515f94a6681066325b9af5e206bfa29693595080f57fdabf80f8f4627d378065b16af82a38ae7e5e03f5604d9de37d80082f23863b4aab9a9717777304da336095b3c82375cb6cf386e78d4aeb610b7fae66240d8df9581ad69a778e9d3d984ebaffb6f8ba966d839351efc7f67f4c2e4f425c6c35a285ebdd9021ec7c66b6ae1b747f557b79486efc7f01babace0e611220e651c6c1b129038a684528a6c79b47b426e28821b92e12cff58019af4a7be0e8b58b6776753de7b807562c0cc35013fdd2d3c88d2d4250d21e434413ad4e005722bc05f89fd6ba5c006d63b6e7a2814365e53d577906fb18298fe67c852b2778a17bd970aa98fcdee5fe953abdc9538d5f26d62b3e7b69f137978dfaa312351581c88f1388e0471565668c31e2a0b2261fd42c1daaae4855ad94de281dc447b732cbbed5824779daec8a2f62549542471a7bc09760e30a206a574a4e2ed757a1cad4302da78062f0732a644bf7f413f2dfc6aa049bfb98a7b2d7c5475aea32972cdae93a32b18d4c696b24cb2d6c8d3ba80523a1b78960127ed2eb911322c4b8f6ea8933c23ea3e644e51a0c185928eb67cbb2fd4c25096a946ab12e315c43d080e8e710ea8b1f76d720a5e10dde7c1a5cefddcf5836cc168f1f0be5cc81f3bc4d9346983c1880a94552095cdae79f87298a27e9a9c9484a95c2218df1d1fd969b7f7de2bab419c901de987569360617b8382e1b36a7562aa7a8bcf32e37165c1a720620747cdd900a11d1038696cf68c030ea553ece3e5dcdbb841229ae9fe15de6395a5e84aff2569f91ad1d74d510a210986c372f3a6d02eb0624fb492f5f5f80e5de925f179740aa575b3409d0db15224a0a1a6fdd16dc5553ee5803859f063de286ec745c9f5883ada467ac3ed3260c69c30193c96d74df7cda13b8c0d1f7c140b85ae4825e12787a27119a7ba9dfda93a967ecd018f3ed30b2cdb06c16c92021333259ca10a5f35b04cef1415463090297dc406010d15ed9e84c371c9b1aac041dd036f048ea8e3cdeccbe7d8250f1fd324cb7bf6eeb6d8716a44a28cd4c8b333043a2103735f39c85be1a18f9d9e9ca70570acc33e7f3d7a2aedfa4c4fb05e4cfeac16a58b75a09c51cb4da29c8c4bc91d64c7fe90106f96df1cd99f8ae5ec2872557d4c3578fa2bbfb2575ace930b08e155dc1274ffcebd072ad5db268337c4e8338b5d342869204220723f88372c994704ef99acf867ba80b3eecccc7b3bbe4e85737f58980c6059519444f608bfbd69857ed586091dd565a2c2b3c2a8d3237a91e45b7cf5909a7d06616dfcc79a085de9df6247642de033838bad4afdaef0078b0d0f28523aecf7e6786f655dd27458f451c740ea6945feea5ea12b60da8f8bdc2f6e5954215d5cbfafddb08a9b201c4f5b84fe915da81e908a714a25d73dd102fbeb42681f307c7b6ab82eaeae96450a29cadb40e007b494be1b512199f5f2933e04dfde4114992dd0e5e383c8ff3aa59d569a1ab076de013ac4ad8f0707c57a5ae1fb53a0226d5da57eaec99c00e6e60c4d333836eaf44bb46f59825a0785cacdadc2f58300b5c2cefb3c2ecf21a83f526be3c6f1e5b4e2073fe6ef654739eb581ce816f1c50222c26f8b27168b3463116a6ac1ab21c85499b7e592b17613b38242e5eaafaadb845cdb2f8b3e6d359211e6d6fca227c888bc01c5506c26d1c9cb09b66fd72f5bf50f9d2412c83f390c86aa95cf93748e962afc95efdc04b5f028f04260fb7f242dd495ac9500488774684db98d31f5d4450c93e8279bc583dd9230b0f51a9ed9d9b95f36e8f7dc01cee154363e70a5ace94f9cf8d81cb8001b764a3c52dce86f79a0847cf1bf81c25a92d66f2807295735828efd604242bd9b482920f73f61bb5066ee0b7ef0ae4cbeb4e81c016bbd3fec08737c0e79066308156ddeb59103bf1124afb430f8366b82bf54d807b3710c5877e45c83221916b7192252cf90d3c6ebdfa93b1434ca09e8372193ee6f992a7bd60a32ca8474548e3c6beaea372fec1513f87ff2cba09cc0f9134cff29be6db832b7a264e4c9d52588971c49ace3075ab02aae6186cd101249545632297e3a3413910ea6b7c45dd15818c69b1cf4e97ca74972bcb77f9848ff3b869fe9143d031b7ba33442c590acd73156bfaba501ed7f0afe2c3bbd70fe24791c7441c218f96815d0939b28a4e163ca3f30fc49851cb275f04cec955c6e7b7d60f38f265419054afbe89ef632f42d7371853d5e7b4938f97eafd43a27362847f5bfcdfd8dea06bfba4e3aac546ab1f5d4857346e395cb0b5e1fd50906a3480e02f6cc3492c7c87a8c568acf691272c2f3ab7aa2f29ebe985ffae7ff784e6dc40b03e90acb54ec2d64b2c879bbd039e7c3a0c9b345ddfeb6a6f1e0f1e0f0bda6498c773838ba47e48cc3e60df5f4d5a37ab2ec2746875c486b5ffb4d43559c55fca93c75a5d5b33b31dd7de56a24f489efa60c0e737ff7971e0a109e9295e539de51a316a99cf3541692c981e99323cfc4773ad71f1c9cb5965a2e133a1b1945ef6918b776284f7ff79bea5176c84f528c1f697f5c168efd33e7fc0ecce7732be7486f141954a571fd33f52fae37adc0478234f1ee0d3d387dce2d58fd1bd981b1139630fd479f62cd327bb2c1a5ff1c34adef01b05ac79bb010e26c30ccc3b894c9cc8bf772245112acf8715b7780d754e5646eab2e8ebdee2e18d0fc970f345e5f8071fbf94c76aac8250c87fa34c202b685ab32090b28054a6ed6e969b863c464ed78f680ad1c12b70e580ee1c0ef1b2404da373cdc967158ce485b17897b679c10c4dbf7c689e1b5e4624c66c5400256b790b75e4f9fe0129a56582bb7c4c38a1e93adff72741c5078da45eae9d1185ff904feee7217cc0bd63ab5e89e70b954faaffa47ea24d1d324b7764d1a0113ead61ed8680bd225540fd3846c6237605bc291c842df2f428d45264074352ee9a989e8472c2a8c5b2a011c10f926f393824815073b1278660fdde183d2099834721e551527624124051e0b5eca48e16040b4a935e1e4405c58f24484a0895c26ffc91a59271b640bbc992841224c64881c3014560313fb072c98387c9206b245fca9494420d860c0248312b48a03a6a68521486c0992a00906ac1b0e44e004416c0992a0092622b5f020123841105b8224688201eb4600113841105b8224688201eb46041138413c60600b900f3501002a2a60bd8fcb6bc8871a9223691be198c49c1f0819204b1442283044295420a2126a04510b0d926885b69fe8885ee88122405804ec09439030120b63bf0834262661028a206113b47794194820493cd60c0759684a62c9808b8c8ca67a4f9fa7995c1ee5585c68d0037b99a6e62867ba6a6a6202316a6202196a6202016a625ce93531ae1e8289482d32863511ae2080304a4c845daa30ae22820108a3c1d414762545448bae9f11a94b7dbfab89f403e11283f80759080040974049dfbf44a55eb45f3239b77ddd91f8c2ace920a0b3a10dd6eb52f7b6fbdddbbf86e29811ab6076d984b0558f7c085beefcad7cf2539226146898e786ec381c624ee0e086b920a51712c370bb7e13faa1ca21ddd8a943eaf260de9cabc8dda9c9b4483ecad460044c36bb15d37b8ddc432bf6fd8b30c1477b577c9299e483dca640a902b4301bc2a6e6be38424512f58ab4f4287356d065687b6f76ef63716baf7292edfb07b26e58d355f165404cf2200b6a50dd91348c2ddfd3c2c03be732e2bacc178fd2fb2f241911676e7a6e94ea2dffa2c7567ab6450469927aa6504a6de9940c316468a133a54aa952aa2689ae9c166aa8484c8191b0eab4a4e111f0890c21c1f10bab9588d410e2bc08fb2b84af221d57042e0a759fa0e2421c139662c1e444ea97b0aa089623241c815b82c90af84f686884d648c4f28a0c3c11022932c1af729aacab98a009a8a6ed40fa9ab603d14f725b573281133481133401112401015ba35aaf693b10312275a95977351320212640424c8084b804c8dfcf909f465c63ec96839fda8c29d65902b4f2e69379dd637daa6281e228f2aadf1c9bd0880a776ccee7acf65e03e55c718c1687ca765d5edaf9e3d0c753b42987923a67fafb3cdaa50d910f49f1b1cf97dac6d24011434f27993636414d9c66a62c4d1daff15dde2fe309b83dbd42954de40531fc31cd20218083ad0a25e85380a92fda1232ed71a5ff5c4f5282319da38aa6d3bf889e022a71152f729f41a7999427318810235fe60b64861bdab775d7ddf1988caaaae3d245e82c27fe3571054636b74043e5d12c6768e21c9982586c5753969fd01d9d3d8b66219c4672c951ad03b74a602d4e915d7b2af5208d02e5287383b84bbe968b27aded65a5f4ce9e9676b482e20ca7aba0cae576ade8c40bfabd8c82685727ddcee85245243e50916011a1fdf3654de416c013d8c8f78d04b76b82d365e93ba2bcb35fd74d257f19bb349d67819eed5e940ef9afcf0310accf973a68eeec3e107d5f7a4badc031e11b8c7e2e900a6bedd9967387eb7676fc32b9db5a8b9e3d3822db57269ae50b4da7754b4276cac550edba7fdcb1c9d4bb2b4757763cd5367662cf1039eb7c817095d734213f84936eec8e3702eb9e6a9a71f24b3f58a3b805dfc6bdbacb2658d17633f7dbcc28826125194c484481b3a8f57b903907d0315074c6a25a8bc6028c6b10026d3e582e115798eb7a0ae24da132d090e5703fd13089d6e269d880e857d6f96cd6855e9f53cb6b5e6341ccb2f8b74ca42592d077301b953bf25e42b80d1f534933eabaa4b8220a6db7110a7c95ff4a7ba6881e86c736b3041f777500c3f4bb706931613893ef857d09d50fd85485f0d0acda9ed7b8590e06686d462da7770072db08a753feed43233a7bbd719b8f669c6bee39c0f3358013d08fb282bf58a1fc0cba103189ff89a09fbc22fa904e003d9bd034bc045197f27d5f1ddba3e8344bb6dc4699bbd763332ca6e19b1f8178a01920b47b00819c62bacd946528f72caf6b4f641b6591db83a74b1115d6761cfeb196698da7b81d205920f60748154ffe2b2a82d0cba922b41798d1dbec9cb83f2f45875f20c9c91d14d21130a01fe582aee73b40c8e743d97394292f191954f9da4a32101d8c5861e6f14c8fd06450fdd6a44bd0d1762002343e035f47cde854e2f3931070a70b250cf874d1cc76e75a5e6b61ee9abb9c51cb7f80f32e726cb9631f1ec1c1aa8749bcfc75a5964a415e2af0fbaa531cd1dd186be5fe4678527b5cf207229b114eed83609efc6d19609ea1e1e2fe8490131a1d9508c1622bed428df004cecee5fd7b00420504efebd9cd3c16b310b5b272f09433019d0addac2430b988938374a36e3c3108eb9cd52701b45d0c7b6faff56845b8214a43f9e74c9d0058c63c09298d8b8cf15aa0c4cf78170c0ed20ebc82dc3bbb35ce5d6bfd5c2ab5543262ddd03cf532626ffa38e097e9da14c5691ba764a07f67d553d2c000641a90a0ff659552429498c4bc671d8ab218e22210c4c45aa9bb48ecb96473fac4edf5f60c717ee02c84a6aff7860b6fa8ee5105aba687bed05055241dd31eff1d171894700e17c196301177fbb30dde1f3b02f497d3cf4eeef7444508a45f06d3a231c7f234c8dd8cbdce5cd43383f7a127b57c7f9658d9273f927af47fde6dcfc06c32aad04f5162efd14ed0ea10694632dacdb755caf7dafac9d220021a4199e2fe6d10a51f14a7064fcf98ba7a87db6034c41a87a20236fceec4d0d03c9851f8113a7054b6455f7ceaf044ebe593d0571fdacffe0d0ad99bff226d2a0313b793973af41b7a2ca183f4dee6c0a8c9a0c51a19fde4ee6477b5b1703362665f7474569bd57a435e68856744e98c20989187a8f8b24b5e2b57ce0c65e8d785433fe66059014138c148fa099dbf6df5e5b19b288468f2bc762c28e9687361735277415b4dfd0093b2bc8d5e54baa86e4932ccd7def3a686b747d680c641437d9b62dfe4a70daf6cf6f10a1d810783bdd0f17630d5173e09edb56c0fa9ede7d3be81aec415fd2c1e239c9cfd789eac9ff21d7f314306a7b2d064cd3431b9ad9db1f613bf0f344aef7a9c570725fc40ed9131eb5f92d1e36579b980347703d636c190a08677d57759bbc9930cca4edad106c09ce27c28602398fa4101c4fa2996b856a501e23d183cc2ff38cab8100dcd50c21184e82942c0e37a35b45707812a1a01a918c3d532106f9721eb724acd4e30a6ac18e868ab76559ed6c7024dfcab012e69625221d4115bf839747d4c638e127473c5af0fb464b8e3ad986d10bab651e451bc1b8778aa38697e271320db67231aa22ce453c581107483375eac194c25f0b8c9f980e9237bc0b1fcf4c7292853c1130630337e3f551632e038deadc65056cc9511b0f2df8b1edda3bc4460a7bfc2fe7764042702cbda75245d6d756eb9df1ffec64c32c75d2feea9737b8edd50dc50a367ff917aded7abac33d99c2613861d6f838da7b0d5251c8be620dcc9216b5f719f1d80a4471f1ce87bbf9735b32c97eaeb961438ac7d02e188e8fc7c5afa1a5fcab3c1bd31eeecc56ecd07d9862ecc26a7b338613d2f49774060ae9a043dd528af03963fb6618fad0c339603fd7614a1da3753d2b0b098623a4f6e2eccf53db0b8c2efbd44e5ec787edd9ad4e6e81a720d2f588d7c17e387714080b39a814032961b2624cc6cbdac9853ee2894f2e7ce330d102c1f9ef00bb33bba83ba3f3ea3ad33413fa7b8997eb53b6c31140eec2a5d73ce37fd90153ab5421cf03baa820d4ede4d29f132fe19dd7d7bf817c607d4be59f420b52fac162e08618ff29e88a35ac22912ccea897bcd4fca153ffd99ed7d410924a0d206900d4a701b957c3ca8d302415d2e7508b2d7495c7b21051e4de987edf51a829c718370ea9e367c5eca5e383a2e1b8eb6fa103f8271e1d5b569fccad237e80dd22b310cac967e0ea547ec0fee09f40669ad846effee04f63da94c812c0c90030c4894b309b29d2e7ea79b4d0615fe5dc4eb9bfda9c735082f11fb48c745878dbb3faddbc06f0ca9abd0f6382b078f378c9e52cde6c145ec289385eebea50b98f4beaf6969339e7ba31523dee1a5f94dc8a4fb3bb3ce27842fe1a8d59f9b980a498388742b2b7dff0aafdf38a8d95f4e1a81ff10de2f06949b063e5926991ce994a711669dddbadf428487defdcfeb0ab88deb149e5969fad39fab4dfe8daa8bee3d5650b067e05549b18d533f7ae5448c27d890f1a24953bb800e6d01845b37d0ab6ffd012a423f064ccd34519fb94cb14bab1be4239b7b9e7ec9cd4b587219e1e701384e4e26147de92820316d763cd021b0f59c6a4cb70b54c42e3242db0ad5c42733bebaadab575347d9529c391afcc3f7c7d2306e617dde21adbd8d8d9fb5d8ac9838d020b1113cbc5049382c937aea807fb9c37a62318bebf27ac4adac5c8a3ff054a09def17c9029ef25efbdc22533fc56872618777fb712192f78f56dc180898641f9b15837b31393fc6f0b5dde8261f9e580d8663abc2b769348a7c408738b8f64ab19e3ef5e8e017eef6942681995c52e25131d3a4fa38127974581c8b7f3e08f892993afe8e740ca877fb808fc02b533958f67d51b33fd193e676f413b9c35f0dcacbeaa17a9ab10d98b6ee115995a6fa182df4d969077541cf36c453e667c41400d254ca814dfbda0e7447f0899d3560837a325da6055934e2c27daf7ce11c78e5e1c0b1892c3bf44a78f878f742b55ec435add508bfac164ff3518bad9bbb23a7021026544b2d5f5fa57edeff6bed067a7e96de55a33f0de33c38782219fe3ed56f3ae9a50586bc13936028e979b0571cca220295f7b3f0e236ff31efe6afe9209ec10244c3aaeadb943f3ca68e726934e723ab2e5bb1a79c37adfed7d66f0264f6133a04f0507b44a29f191161cfbf52a9da4235f837fb013d761d66c318720615905ec100e50f97d89c2c42c02e46fba3f3b70b5da2f508d743e0b51e76da657ce212f9e5975b31db1fd1e3b28059de36826dd21f33dfb0436e9d8ed25a11b8e5006cc6d1341004d149258ab573d97d889ec2904bdbc589cbe4b76a644dca857437a9a0f4202d2287ac5dba546a071a2f66debc557e265727a87bcfb7bcb75ab6d7bee9176e0e3a1044685b7c42d0d925623dd48e72396503991692bcd12622e30f1698e1bfc4b3c65c981e36c5ee5d896fd02b8b9ad958d52d7c4cd60130ae28fd1190fff33bf6a703a009fcc8229447c63e678fd01d2e23e1e6e598c0fd39b411c26d2466aaa75cce56a1643da4f28b3e34af3bfaa2d127712f7a1fe11a9ea6679c863be07a36e480890269196936a09b429e8c82f60964828d4018cb73a4cac3befe79b1034d97a4b5132173299e515592dbfb4751439d483ede58defe98f8cc2492fad3d8f165ced2f6531aa0cbecb408b375f61f97511e63a196f90f43d97a92c8a40345ac1ce219151d6721e6f02737c303acd6ea783b7f4127e9ff7f72a44137e6eb40c768877c11f35d047e90beacc2f4e2eabbed8839e6b8f6b063a6afe288f858d6984e60480741968a429a4656909da2c5a34b2db1c05e52e472b5b08025fde1badec8a3ec640ef3a46a87981dea70545679a2e38f3e2d0f8b171d041228f21ffac70307bb12ca0bb27fa4e02938b1903beea10b4f397314141f4bda1481d69c275c2400e0906f1e9cb365e3804da47b278a68901e4b8ad459cc8327de437b1be80c889e6614077a63393bb8e31759dc1ebc3959908e3b31db2fc07faa0f3191935282c404019341e7c61556f9e4b74a1719d7b6a7f1c3835b94e35030215b58c5a9a25e77d7815613f6dc920387213a53e119e1cf2ee415c62b41bc6b9bd9ae89f6af73fd6b5a1d20aefe251d010b69714c0e4fa91c1ec85025b8934eb73f41cda33c5e9c8b730abd08ea216ebfb624ed000df454874afa8e1d36fa13e45b57a46e09271ce8afea1a273adef39a2a33566a46f6903d9311f448c0d0ded8600f950d76db180c0881853f0d8a0ccc61017cb33e2cfdf01f6c7eabb9847ae8d0d728a443a7208a75357392820ba5cefe3c6f734d1523e55a29181d772f6b434ed6f4741964b609358c3f1fc4f98bed55bf3e901506393d6f65e927dc4f63407d85d5da1b82f55e653ba0eebe6db6330010767afb42492011957a41334881cf30c5c7ddee19f0c18842ce8981e65f9401607d950bd8d8f563975af3a7a8cde50d37f712c4d904188453e7932b0093ce5275b50568d5c27da592fe8e2d09a0f1558f392a9fc88ed7d6c9de86985e9b95884626a441ea6b78e6dc916c6419eccb816f52e56b7f6bce289e4f08c7bf8deee56fc6fbba39a0423dd085464546f4ed5bf280db0df17afdc8386d575df989f3d2542c074c6bf1edec7cee19b3be015757c9cd2e6860de58e4fe11a031f5817e1332d5fded109311b2569b90975c5844168ce4b098e3e113fad6f6b7804341e2567db3e3dcd12492d10826e3ecb9c4c8d50fa651fda5c137a0a8fca32a7c29830a8a0c4f299ee2376610813b1750e7d7ea96e8181c666652fac978f37e7e24986e483daaf88ccc437fdbbddee0ec2b498743ebff45a3e5b1009b7b2a1cc253d8ec394dcf6a9599f4b8be627ccdc5ad5f33c101b0461535a994376f69d056d45eedd3c1487d708c8a1617c89bf32e31afd8b973b5072a70acc714f26fea54145b778d8ad932d3178aa04bb0789509e436c383ccce117b0bbac67317cb3eaaee863ddc5e76d317874deef19fcd69b5ef3f962035596120d8c040b6a31dca9f1c513590941cacba3f01347299c00a2c8e66634990aa75876e7a793b5e11886ec71a7d68ced40ef9f73b7152e200b085f77c48d8d3176e8df7073912cc8f83919609b2596c4f4482a82232c8ffdad5dc2e6e6503899a5930e2704410147052def3476c4044000d5c2d15c0903816b4f5a1ccc91f309879af2efe264f761e4a9f0f0ede8457961fe6a966aa519ea411e28c1253718572ac3773896aecd7c18fc35f6c03068e0a0c4c5e53d7922b5c9fa03e4c17a5ca06f3b2a5d235b8a0f2479a69fdcf9403f3bed7b999649e651cd5b2724882dcf2814108b59148006589b0cd13016ef4fc294e5113297c614d165536de3f0fb1c190c062420813b8fef543f9d8e1ccac2efb666049297804b5dec2b9cb1359da5b3b9e4136c15968e55a895152378bbca8f360d774f36245d683eaa95b1466da54b230ebcfdd069bff0c9a838c80d3bf1a1f15ceaf1e868e78eca083289570be2e411fb40bf42f5691590caa8b3be61f2b14200a438c271a42287fd27ee3b42481345387d68681d9945dc5e954cbc94b0ae7c7ee5c2cf35bed912020794afc9c54001fe4c8017f7d392e4ce0924433f915038914e177f53db3e6b59dd28c735deb73c9be92d5ce1ae428db4006ece87a0eb50d7f356a62f295f27f02a02a06d57e03fc211f5f6332633f525ef85a2e11fd2040c7220106093874f593a9bf266e5fd3c9e2dbacf3a5bd0d7399115132c78f7d8f407679fe8ea64fd39e6669e0d9f70211f7bbcd6a02f4f4d43d1d04cce71379156bf514a40dcd694d1b49aeb787b882ec199dc5f4394a2c41fc27730dbbaa4a59f6d3136314433e3c4d04690268eb48a7e007e5006e9d9f0ae6245c5eaefa1fed12d7efaad074cadcee5a5773e9dc4cb985b16e582a2c4d9735e188b396d0514add2268a0a5a0d39346af65c6206ff63ad39afdb099b478de21ae832aef1ffd6c97052f684109372deb10b1ba51d15698c2b85f200a98409d2a35bee2e29491f98591dcbb49859489c4e86f4d79c554a08df686a7c8e3df64cabfc8fc6d0bac8744b680ca97a8ea68613d7bffc2a9d838dc87794cc42e97c83f575c5fd0681c573977135f89102b1b82a43b076b65025a35a03833a07a51ecdffd262590b836323eabd7c601764f762e591b2bc88cd9df8b3336365c55e6715a24abed67ce38cea3a12dfb00eac5e8774ef75d6b7a25c1b3557384145d1760e03d1881ee77a47a73abaa3c4fe2e1f0ff96416ffb62f490f55a063ebed12b9b614d0597892ecda72a6b24575ba049eaf85528be617375be59c1d6ffb44d7525af26f8ef4085792e2fdee179e4d7653d2986d74b37554986c9cbbadea1ad4820eec68fe4b4db6e925f310294a4c1741bf7efd573311e84e43d12de7f22377d27efa85e163ee047c8aa9aab555d5c9faa84057207724f04ac3ed4d769dfcc532cabc76d8de8e73f1f7eb0734eb8b6b509de10d9e93552886f82ad62a8b0459d3fcb926ec1ebfddb2026b9f8e9f66c1570f0475bd6f1a925aa9ee78f49b60cf80f07d6c669e416daced53d2f180d95fdbc966a7508097139b1f1285fcf5d69caca4320b800be1af6110e8c0fc5491df0b9524a815adae5c18a1790f82fa19dc2840ae6e7281c702d53ce0d44240efdc8121953f83baedbf0379249cc03665d71d53dda9068aec869935d22b603e69799999931f83b543998e7d633b68b108aa310a69e1acfb7412a14863e7872f209ed559848d7eaaaf9bb5e3e3e6adcb22801607e18938864eb21b1bfe8b3623a83dccb6590dc22f5294ce18a4a3fe53a0dbf2f18cdf940789fcd2f1a2ad98e2fb0330d08df70776399cfdbe5a72217a19215576ac71d8473241546410834eec85f846fa49a9f69f01c6b147608cd4abfcffd8351154f9cd462048f02e4affff003ae998a52ba808fb332dca6e85e71b0038cbe2b6b2cb87d656fd73a3eb9e6b0b02987af53b7879578b060ba53147eeb0ae485a6442049f418e36761eedf37daa72d1f92d526abf509af9f9dda1336196c931abc5c7a33abeca8f78efe2d94ee4f23e11f70fbef83c57a5b9f94ed021cd85499ea5ee34dfd09b44ae4a6035fbcbb4ac9da17b68ec92aec51b17083e8fcfebf0cca5b5a70fe69c0ca5ff8bfee67921034c8f5bdc66cd3c21fc49347cf4f7b9e34fc148def62795c96a4738d52ae1df93e9fa7fbc9695061f4be8719a8242b78bf8f3c5a9a745428645ea9785f60a0dbcc258039a4eaa8fe73596fef53c11cc7733714f06fe427c82ca0107bde2afa6fbc58b6f96304add20e69057a5c4ebd2e6058acda988f2ecfd6054c578eb7a1ebd3cc059bb11ea3c8cc425e1395a8f5804cb4f7c4d67c201e8b24fbeb13e5737190c8fa1f8e0da60c68bb9b28fa1ef556b0efd5bd23fab0a651096aa638847ae2ecd03b9d3d46ca27e7374843a676f2130b371df2d7326292d2adee09a35617c6467f5fc4bade80fcc606b6a52833906a9fb27f2b9f0cf35b6090be3f87286203cdcc8d5afe0d68c4f143c94823c562d95c6458b864fbcd65e5b0febf5b37e9f01e524e9a6d70ef1009abaf1eda8e12bc29e61382bc556450bacbbdbf2c7d438c3fb3953ffb8548824d6bf09ec591236abb427c1d1a4023d38b268fdd19ac81b9f74428ecf7e91e96127e3938151c8a6e3178de29cd6253341d498d6dac205a14a41d998c8afc0da7991f97af91fa91b0e1824831853edf8a1ef7bb90c05c9ca040f5e85c3c5a85f5426c5d0b7947317a835873c05a8e40cb7f3c06eae0b3a7275ab25605d93a25339fe174e182846425488dc2b22b9bacaf65ccd2063e5f3c5415ce04280eaa8b0f1a7ea519c75c0932e5aaa6199bdadd61a8da55b193638f8941b7dc45c6768b938f5e49d45eb86d1168bc590126be434a910339a1a5d51eb06cd86dda0cb9619cc7ae6051f424b0fb08c8b7f1bd4875672a2edd5e971f992adce7170ed1faa4d55bf35a70d18cca6270b4031e352c1f5241bf89f1f11740fef68dc45f2d24aaa4d33834c2b286ab2daf2e1f30ac48e43fc6089112e367b7d640168397f9dfbf7a541a6d42de96ef2c72bfab874a703fecf227260efdec70871e1eafda07e872a76e3e84a7459d0efa9c995a3e1d48c5eb1dfb8e9d7efea06ca180dd2a9ee39251d5d8d4fd00afe2c6bdca0ba675f0dab5c25553da6bac0588bf97d08198497f23b97ef980b83e0a73cd89320cc93d365ffa23ddfae581662ae56d57842f865184e11f073c56daf41eb30839fe01ebc3e4df0e578840b8545fe1797f426f3c574679d4068c22a6ecd433619cbbe3144a3e856f293c3e18911aa1eff8f52822db5004fc3380cb79dbca7eb6f18a2f8e8546b824dee0f044d00b131e559e8b9b285459a9e989d0446879fba12afbc32be2a21fb670d38de8a908e60a56fc38a686043a11e84783e46208766d507eb9f5b1c4b7ce018e6356d76bea0c6d5f1bfaaddf65b4bb1284338fd643dd10ea5137c3e85107b86379867c26dda8638196b227c6dfb2dc50f4cb4115981ec71e1f7cc70a7a1c2ed7388f37352744859a8eefd298906ebd2e3504bc9ecdbe39461edcd97b5e59910560bfe2aa6c56c30bc58753fa1a8d15998c5cdaf08d64abbf84d8e89cd5b725e93f7d19c76d913ef045ef80c44c8228da4d6786524e263251ecef40ae0d86b8a5d3b4926ff9ec7e585a68cb547113a7eb119eb29a86a0e0261aafeb1ebd943551b5fb46a65496f30870e93e829bb8e9bca0f3a3979fe06c4c9380f99c5507e414ab8b5fa9a91bb9ebf6b5495fedca31b8b8d98731c4d24c93ae02e5f528a766272089fdda6efbe035dd97c52f8c95dee1954bb330a1ff64dc0cc53a4070daf15f031d85daf749a17899a9e12dd1650f6aaf8aea927c0748201906c938d00570908ca50e32803d0a8079665b95ae9b069196a3cc1ab2333d3fda4d16b900004ce6fc9b702bb75f7d93543de23c04d92c6b4c6c0a0040080086804a40400030a855b05cb176fd97e812f38db244e6ff4c6fa795a2a458f0cbcf5d12fa692f4e3ce171019517f52edac1d8d15cd2231a4b3986d12d7bd39be778d17064a606483b5671ce5665ad316bb60d49794471bea91ca2f3cbf796a01aed8ad68b930a2479bbbeb48209443a8b51b2cfa3c67682d6574bb88c7ba92a0b6a44fe12a13f63fe1058513d5f95a079d89f40d07775ddd6013ab37dc8ba9736acdf46ccc95c8508b3290dd8ffbf0b7a335f0e4db9a22fc3b0c7c0c22e4a539ef18e676da52a7b55a44622664ce86622df2ae31330186bb5d53fb08bcd36f9c21e30b351c62bc2d2f297a54d3280beba82c26c176ff6a9b13d1e3e6fe6091ea05516c211f5b57addba9720efc7bafc8aa7de03e445a35536cfde9692dc9146635036b66948e4c51b7ad23608c8783dbf3a1c5384aae0034328fea22b7624ef3456f1cbbe3a1a0acecc507b8cae01ab1c7b0d9542dbbca11b306c7665d53c19c8a345805f14d06a218ce47f2c9388f10364212260d32365b8c991f8b808fc73bc63b320db340bdd4560560e22a322deb24c08ac29d95ed33084e753a5a377bb540344bee8aa3f529c5ef1b80c7d9507cbe140997e579e56397df68b5d47d3b4b69badfe96e471b81845a62ed498e3e702f3ee0e30e8a7fb626890484e19c94cd96baa7bab777db19b0e4cf0bb16b9bc2a181d118e47113ceec5f5cecd7f815b04a17bebdd2de2a5b25090453daea383c1b249c6d23a6ad595834ef340c544d1435ed19c07c7d7881e3ac1edaeaf0f0cf7505bfee3abcf842c6dc3ab82252fb9134ea01e6798a43c7b6afd72c01b1b2c616d0ad5b5ae4947ec9fee1cb5e93173098c50270ee474100e98daba4430253b218d16f2930a362affff138f029df06921024d1f11f1f55d15bce51f6d4b60295ea2e71e636598a0df800a56309b9827a5bd1e6877ecef78872b06808a9209ff51fee7d4d0625cdb7ffd1d9dc3183a64dd02bba55fe67950874d1ad0588ec1dcee45b7120fe2341c9835e48d0efa2e2163d6de43acfec63eeee0959cc0ab8b9493881584060cc5679179ae01ea93534ba87e26b34dafa9e82bc80f4e0b9f0f3461979c56e8acc877e4ebac4a44cee5d483d0fe0a13412c27de8f10c2d44de6d6b476668f62897a04620abc325d2e4a3d6717403c9e98f77c1d32fc388dc08613cefee761a7d96447487b83394feb68d28e31102f0badc19760a34e095a43bb42bbdf6f68b183e7ab9a22c8169e059f625095aa038df5eba0fbc993c16e552d40f5fe27e6bc8f5535a8dd71a4e771b2b8bfdeb7238857f755963ee893147dffea0b12d6a215f57d07a6201c06e553552f78ab5697d3ea9360ba84869aec1b6c444b3ef3c13fc2a370763d7746fffa594bed3970185b814f94f8dd10e160849418e8c15798bc85ac9519e8e8b0dcf1ab9a9f4362499f510c24d7d6032a2d9e3e8995cacb0b953a7ff667a270bba9de7aefe20e3079511fd9574d7694a55b0a88e51f78bdfecbfcf3da078b92583842deee043bd891a0ec7d5a31d1754b5e21e0fa3c38fad61fe8c5e8dbf133cc10667ce04505f25514322f8e4aa04ea7ad509e7a81c9fdda76c92fe97439a432d35cbdb324ea86005d39d7a9ec6deb3a49f03c902a933ef2dcad2eed2356550c97e85bfd87cb14176f6e268164545a076a6601d2f5fd3e46e645937a0ca88bf8df9e5fb44c40d3cb0ddc768294ed2dde7ff57b688c2f2b06b494b33f8d53170ed6f6d5d96c6fc269e6a9ff4fcab119eeafda03e40d1d5242a99d6f4aedf494132fa74813536c80d0b5d7d24d7d09b35dce9f7e3806dac96bccbeccedf02141ff7532a9706b89228ab483cac80c98fbdef0663339875885e4049250711a87fa89890ed6a78a229ac3cfadd0e09434c54df9ae6dffb350ffa4847bd1cd429f23b8f6418bf4bb6cd2845ee4d10eef7edb33202071ac90afe86e1f93f44b4b0f533fcb7a791fff4a7a80c37b5484ecb3878c493d52ab131dc81f6bcdc575123511f3bfe610366bc56adf08543853c5a2d1c776bd28c9f1e1e09a2eaa3e45a54e90651290aeefabc11fb0dc019cf52a490dab54b1aee1ab63d3b6ad5df1af3ae957995851caf343e99e72209758bf71e0634ed6ca41e0e25d0925a46a890e296ad2817c614ab6f15b4fa7b2c4ff636a8c3b24f61b55996e364ce6934e2874fece1b5cab00cd8d2fd0436c79421ebf60e21c54a329550a0d76b1e2517fd5e4d77cdc97162b9d7fc38b26f035cf965985b8ff818c73490001ee218afb9970f609801fb60dba88fbcde491eab5c39632c7250b95419f56b62800ed79ed6fd38cfb2f50162ced6fd751adb488701066ac74222adc395736559192f9904213f41db701e506be94846adb5bfda63af8b2783d2ac35d9827498a96e411eac3fad739b481c615270f7058b23ad476626c4a78b018bfda98ef5658a9c0e7afc28efb4ecc927b119cde0237da29f071011a60dbdaa30bd35675525420a20e5dff7f443fbaf0eca8f71958ad1ebd4ca53978bf3dc97dd6725dd9f1daea22ec9937744c1e9bc7952ad50b84f3c87df8abd492bb1c1e1baa43314cb878bd78d854454e79108d979d6482fea937a9021e7490d8183fada2d9826c5ed4e64abcfb841184678c72a65040fd8c69a6f46a69eab2fa9a469d4a2c0c0ff9f12897768b8474c370c8b8014f0d5dba990038899754ead0026bd4099ba2f069cb4d49b47f7036b2e9ae56aeae134afec9ffb7f7e56c52f5c008d494556aa464f0d601d5bdb9f9869e1d60062f7e3ca6c79afbb26def9aa176a81ef582d872be466269896795454c3aed9b5b0b991b54cd9ce03be5893a8e4299bbb2b86619f30e0703bc3f8951d772191c8be12dfe263bf59089ebbaeae328c03298ce8165f8bfaa22a1fc7c28a229519a5c322411a7e53aac2309635e82b2ebfcaca07ffaa7ab991c25ffb258fc866e564e30931fdfbe90903196bedc712933518c1ffc4384d27513cd8850252210d551dc0fc43840e437de7ec8ed4f65612b2fe54ca8c085b0c73e217ddd6456bf0532aea1ae711bbecafa6b055880c10d03a1ff40f074f7bdf18ad364b8c97f9bb297e6719553287df6999d70d73c547e952722a4afe9e17cdb20dc1b16be2f22ef4344abefdd2a7c7c840e7ef496892c4f9a8519d28ec0ec94b20cf832f880d2aa8d85aba9e854e415aa14b31c996016bc88d0bd7da8268b592bec5f9fc03f9bd1f92976b5f0ceeafff051bb4a9e6e125f3fbd1d92284d0eba8012a52cf5195804084214a83b74568e7b9aba89ceeb7072797c00d47608add560a36ea6c3d5e480a5185ee78d842666517c5758c11716bc294d18e1457a44e84f04b4752379cab6a8f3cf4955aa223e229ce830a5e7c8c5c70f106237f45f61ff8c5afa0f2a1059f3128d9017dadd2245e1f0c01a1c1b91d494468712a8aab0c3e55448b7fa0ab15416eaaa6c96c982d939155e0a873595d68883c3e4f0a4e57b0f632cfd56e311a27be05d77dde60df96c8bc0331db18d2a1c3b0e9405cd641d8b03f40f38fb4921d35aa294baa547e35449e087f4e2e8838b719ecadc7a14cb0f692813fbafff929b7298123fcb5287614cfe8fe252be4ee4093c3f589d2c9fd164ae63badc3722698d498e2e95717909495c5dedd5e4c979c09ac2103eafc4a91a4b253fa32682ff43a31eb4929204611532ede8c3c3375a8ac4e7c05246eb44a17742a2808b8d1fdf3636c8bd2f71d62aeb0cab75555173b780c893a2a3fd65e271c6048c6b14325b0b4b6fea7a57ed0345c998bea3db17527200572e3b9c317cdb1e0f80358815884967e4269067de16db56ce61e8fef1514a34c26408ea783600bd90eaa097ebaacb5271b04bac94d240e5fd80a00297cebba84e5bd5837a46989d78e0bb7e78fc20c087c06b52849ee199d53b9c1824b3638521d57bcc3c87061a32be7b6dc1d8e7c7d33fb69779766dbef7899e5744eaf22c99bb535632fd464e65192505e02a82f9bbb85393052cf605eea22e950cf8e4be03e18f5e4299b5ad98cf964955dd2d85c9add8e6eb2dc214d8782a0cf32e84ad3cb217a839b46fde82015db3f879b68abfae40ebf91fdf9cafcbd5bb3b4f02e25737c065fdd78ccb1431036ea5087361766a79206e89d4850be1721cb4624f26afbc234e5a6df4ac9b7cfb55016e613f7668534edbbddb5bc604abd48a55a5809940fe538769b6ce0963c15432b54dbe2e82a022ec462d0800f9bac755e9f8a2efa2174662f70fa549230105d7f1bf595ae46b70ae186087b5ade8f05bd694e632e6aec99c2652962fb57ca72500e635af90221cd6e16bdb91127b1c5300b5e8ba6a7a6cf7469d7c417aa1cff75f425d552f3ec3e66c0d70d6668ca6a0484c7f10f0721a3f2bccf4ab769c6b397917b4aa4d30fe4be42617ad6e2df0eecf10f08a0b08e698660ca3ca36966ac2e1e2989b9359e1647d77c0883ea3ddec9fb12c4f52d181c35bf5ca24681be64cfd945541e49d151ed3a906c7e2f9a5c30d805dffa6a057b2c8f947bda82935f78078967c4601a4d4a84670c8332e8d702b443316e80d43c8421d455ca41afd7d4ffc655edc5abfe1121323173e5a541a01c8d4442b3c4c04b68918fbfa032bd9bf499e6ca3bf70e1613c727eccee76ca8eb6a6a54277acb72c5c1f356c47b5e03f3ebe84bd4decda0f45f740439e6c9475ebb829414c421446096a7b7f5fd189576e38b92532456c9a5040841dc4a66e1679e92491061304cc1f463e1d11c73a2a6b10c696f7a4dfad83467df981dfab3abbda47d68543760d447e9183d2ea2b2354ae2be5bb4644a27df743f068f857e4b7f7c1dc90822d22ee1a7d5c04a460f9892ab12ad0afa3ff3f83d3d5c2f817229511fc2b4c60910240754de70a33475fb7b342ff21496ce540c240ec78110406ba4eb020000c0c12e5f6a7c703d6c2ba9aff8f54d67c0bea42f3d36d11cd5f074f34fe31a38ff80904d82bcde9936634e71ea32e167f268c747bb1deb534beabeca102c1dca4f86725621cbfe085046f81284c74bed6e47ae1a3f52bc8c21a4fb93e10948f6babbb48ba4849b5484367245215cc0967824ebb3c44550dd52309c4b8cbb8360a40b2b58d86de52bd2f31353a3cf7dc9d8903a1e6bf899149b7309b6136a6d1272e019badb87ed0897073a2e7bfbc5ec7bc039dd2e5b33d7b1b1481e2ba0b9dd317b1c6d46afbea6440a12562e2233b8c23e21806059f790e5d84e4f1a7971a12de56235b9b484c226a818a43255b41bc3fffa6fc582fe145ac57a518caefe9ce3180dc196b7e97e545bc11a16b782e21132e833c891708d24314a9bc157af9fc5143dfb4a74d4461ae6ea6cfdd2e85ae70b504f42bacd334be87b8e71fba1011a2dc7a74107b78976a7b3fe24da1dee093f45449e8327eae38d0f2d4460be47453dd72eace13b0b1bf45798879c369f900ca9e583b9c245a32fcbcdf61e380595f0afc2690ba266d8f77be6811627aaa1442d3d2b4444ceebadf1767485d0edb693c827becef67f5aae06f62242393ee6fcd7d9933bb873c2addcfd7338b3c6a5b1574e27e35f831ece955f7f6fc3ed74ee7fd256f151fa27fff215ff28d9722fb298a2713bcf9979b1caa0d6119b48c5ff06b82ff25dd18662dff097a05e996117fc2071bcdd5460621d22edb6b1301e9e7b1d6f3eb5c2d007437e21a304f509ca8b937ccf53da390679d82d4942f6f7847742d53adbf87c8c775ff76bcc125b747f0c9745500855318b0e0b83a4060cd049fae697b0a149971952cc18e9d1b2ab86e6254351308057eb5bcef05c3246eacebd6df6041c5801d273371ff562693be76f1f92f69741daffdfc16dd3a8600f65435bcc38e82aba1bbc5bf17987b3e2a9a1812dd0e020abca1974a28a328c6cb941f0f4ad6c432caa261cb297b7b67a243372f410a1eda19a3aa7be3714eafaf3921c14c33a068b3533d689c88fb683e320a28e3405d9eafb6cff59a6181aa4adf84ca9c1bf8716ddf56a648944e235761aa3384a3feefb39d0ee5db935f43e64470c331f1da0d9f3e96d7894eef9ff80d7455c9307f7dcc84fe39d10455df97297ebf07cc1b709091a29373d39b7555fceb7480b6a6cf7df1f61768fd198bea64310498b7c017b4bcc73c47a80bf15f3f99188d61349e1fd3a34f9b5464fa7c3fb226c83bc31d5d323dbafb3e81298934e08f5859264c92f42dd47ec88decd1982def4bd9bcd5a1f5adcb30c7156ff9b3b46a333ed101b1458ebb739f3990a84f6535f2ebd618e474afa477106a7c83790ac6dfd9b18c75a0e3ed138689cb69f0d642529753ab42df7df0111ac11e5b037cc3ebc33387804e671e67a15891d699f692a1b4a74ca145503e24517014d7d0dbe1aa272f3e42fb335d6eaf2bd27c223b8cc761e81bf5e8bfea727602ea14ccf75f924431202531a1fd7af1465a455703f958fee41ab8e5d776a33f9a8e93aef6e395b4503634897c166c5479bf09a932235d09e393b1f96a62f0e38cbd85e7376d1de435b95a9074c0b998cd0cbd9d224dde52e4d3aa8daf679b8b215b7f03deb1a1e2056cde0337065ce1bcbbecdbe608b9350e73d11f26dce7ee714846ef67ac1ca83d79636c7544dc7b3153471c377ef6aed90bf0e01ef72f7e56d62210f4eaf2ec0536406005e94131f4c66ce018d017b742b6f96bb85fbfba86638b33982d33a29eebc56de12ac4e36e3f534beacfa58e802fc83a109fe0044de271f53fab00ab964ae90469772f353fdea01cd3de84df7191d1de11582e79a67a46c22c066b1dab96ee9e2e4257864766a5429def22cc66b0b07703404b4ebd446414648d415cff7af000785bab88bc5c71a85c3f9b2bedcaba8d83d4c65d8d3373e941c07c7a0fa427dde60f6a37ee3e4fc1881370a05135f560c2bf5861dcb1d73a72d5a0b9ffdfb855e2209c865281dafadd0c0f201ad2d50f6f31aeb5a52e41cd5ffd0b8bdff04b7e5eca6b7d8d3b152b036d885cffcca6e9e2a7a149aac29d8b12c0479516152796bb1169978afff36feb2256de1e8f43084642a7abbd122b996a39e30f3feaf5c464696a4a6f5c7a82f8fc6ad3aa2395005cd637ceed5712e62e07e523434ed7263f84f53ec7270ea2f7fe2539a1bb5f8262fff611c554b91e21e8e2c1fff90325a0078c468101bb407ba82d4ccfcb8758795bf33eaa9525fbaa97971865d14c1306c902f5bcc05a22e1dfc4e334824fc5e0d21292963ac65d6bffa1a0d15c52e6759cc26d4a13a2ad3a7962f2572d3a0898d3237d73fd8ca5c574d5ea5ec94dec13f9e28d4991aa3f1d5ca014e1938dd562deb4a25da222301ac9d5c460a8ba7a1d1b54b777aed2e458bb658d29eca31cf306d7f906d91bc78e7555ce3a44b873eeb2ab23ccf05e2fbf1d3dab0dc154606fe469179879467b1a0f3a05c4a2eb76a813cf9fd293020fb9b831e48fd295d4ebba05a98da45342f0c229400884d1d0f1faf6e461d16996e1cf470b7dbf5e97541bde6b9c2ee166117992df90cb5fe0bf2c5e57e2b36fd8afff530cb642b2ac9370ab5f721e924318acb1b37a37e033e4da58d5ffb36e0bd49300ddfe1cf37006d9cc5a218a57b78c5ca1447f1b2af16daa1fa45bfa3050bc09b86fbb96be536f9bf5fa97a38cfa9e93939919d4ed4662e67aadffed274a723223a5b50a5e8c982ba7a6a3e70af5e2ae3d3fe243cacc3d8494d82ff41d5b4572e26d16e60f6df069784670b273beff27b1b35c0e4be9f3ea0f38b4b402aa389f1864b1e4aa040e073c99b26f61f8b4d8a70b247c428d3e53a7f87af4411b69b2a3a3725200751959633753d1206d511627684cbb2ff273a82acaa3620f1410a923cd163cf2fd9512972ae52be08dee5914e1b07bf380dd00aaf53006e9551e738a24d0c121b2a58fab4d11707b5670dbcc91490d5ed18e0dd14d58ffb7cd93612304ffd17e5bd4c44895f81f2f1b9833d1736aea2b768bfef8e9aaa87799951e0eb9c1b8f2394915c98c946eaaeda3f19e767080349e4866a168a76f49b495629c344690cd47f85f8ada56a38ca68000540a82fa9d009cb531841965ff55e79409c005f3f9be9fb080eea51e398faa72e722e6e441b0900588338bf7e3d37c6134f3dd0a57eb690f0ad730582783b893ad14fe7745e7fd5d6d293549d663ccfa71d715e5f5df56051c3bb392fcd00dd749ae56fd4008ef5e18774b38ed28c9922625ec2eeb1b5c6bf455d4defff513c2bf4ea6bcfd9ae0bc1e8a4404cb2e04ba072bc0f0c386f53d60f3ee82138d5f3801eb136edb20997ec9bac8b82b43d0361ac3302fa1f06575ed48a396faec0c11600731470f9d120359a20f853acad1c169db2c5c015cc32b18f613fec996dafca58af9a981e2db48383a58f05e158cefbb1f02c8353584dd98aad92d4ed352b229c83904214ae6a4051729d68643f0a646119651e35b025e9aa6c4593523fb9e83b994353273c432288ffedebca39d1a48afaa18dfe952cdf27a94e50eee1a45e683f4e7b844f4e468562a0624209656b11c5dc4fbbfc3fc9cfccf9c1f036af516cebc6715ffafff4abb4c97e0a4b57ff349439b5d4786d11a2c57273d0696b7d629d2f2b922b6afac89c03f90d75b37a8aa23eaf8b40870d66485931c7bf6729051c5c9797c4d6bb9a3b1d955f3fef24646ec2e4a1c515b54fa6e21d5618cc5a4edf8d80067a1cabf03fd48d861c088341d03bdfc854804c2f83b2a886b45cd2a4342d801dfa6ce53293885cb0f44abf97637851e8ed8a9a8ae674770abd143837c0adf5238975a058096fbf093c4ad530154eddc19b60cbd78513a184150b5c5d190f39d7253fb70cc166cf961cf6c16ebae1112cd876c8d1521eb81a74a6ef179396e8c17612221d5ed5431324df0b014bd2cf688992c5dfd9e91e56f37ada072675ef2e0cfca9db094ad0cadd0bee1ec28de48532358ca376e75123ec32c0c955e5a708b067cc914bd4a2361b2d403ae97a06c87c777d63d5e8ca27c9e36130c971984254812fdd16697b79a4d97346761df61caffe4d0b8253b379e6c6546bdc785d4aba40afe4de5aa5e7ce200ee4a4317a22c9e424aedc9d5323f45b3853c2f466b2124a6e7142cf9cded7e03652fc8924eed2e11e978dde9a5a4933f3ea6381aa01b09e10c1105b7a28f88a8d4f1268a3579551e7cef329d318308842248dd8b6fb0faffae04f1d74513970f06017908a637c3ed6fbeb3936578fe5db3fa54a12f3d7ca04396227385fe8468cbdcfbcee938cd37abbd6f7a540c9779f6cf0a01947dc4e8ad794be611144687476cc7a8ea4c4ee6bec5e883b8bf8308fb03baa838a0dd50ed88860d7bfbead686ad12b9cba9ebc11f99ce80f5e173c4bc8cebaf3d8c7b5bdd806765f0d40aa1bf60d3bad604864206d3e0e76e42ec9513d2a28c77b5d65306c1293253e78ffac74d26e256382bb8705340fbecd8b84d25fcb90d422583fb87684d9fb26c92c16bd3f357b16b212e27a30190dbfaf98912e54ecef0e1f7d5e8ab1b5fd6110e376ecc7bce281f2c224fe512fe9ad1cc4392bd9eee6ca0401f78b99815e5fe366c93db38e9a973d397c7a8c7d5482640a133f8eff90709dca764635d28f0ddc35af9d7e6c5de45638c22d7e0d25193b22f55c3ab1f04581f40eaa0a2ba6ef044c8d556d133203335cb6cc0be38a8edb6a6ca66e033cc083449359047f863e29e27dfb80030e172bba8f2ffc0afb4657f2371976a9a554119177d0e904dcbe3dc1c9d5922f00405229774ad65b118235a9482cbfc14748b7b3d2fa70238a2798655f98c6bb264a0c77b6874625f0a7422bf575907b7c4a813ee01213b09befdcc63a15eab329c3aaaec6ef8797583d801ec77dd16b7d91c71dbfe7236c3bb2fe1c4044dcdf4851d80796885a36933c80a4fef6fe26ed3b87bfd940111b17ab734aaf365c527b228b0789418d1f2a6f13b20e5b2eb4725ebf9db1a83f5b0398a3352acb5ac7db65b465779b6088ec9d84062d4ccccfef087e26f9bd661d6fbb871563b9af9c19e00a87a9bc776561398899e20e023ee9f934eeb60d1e15a13090756cb0bf38c8c1b2778bace257fc3c258bfe1a229657bdbf688d3a69fd0364daf01e9544985605556cba37ff9c00ccd45f964b57f609782d94f257f5a34e5089627ed00d5f8342758c9f7fb45924017df4d81bb3912e8c5d770c86c45033b7b5de6d07fa49f5ec82005782bfbb2da60ad01743c5c39c42fee27eac58a6cd85d30f78d6d06ed6590c7077832b8448e9dd3d17e4ca641c183457b78dfa023239907d9d410d222f10f848a660b912bec2aad69cc468965e53721d4fab1078409e7099bb445b1503a5a200fb7e2f1a2dd7a41223f22555f0ba2e65e4bd667b094a219acf28d2d5056ec3e41de9ed17b7bfa7a96a225ad3b958037aeca3d475bbc55344a4a9a46b90384c38395f144c93c63728e9890dbdf39c5b29b1e3d71e8b0678035fc3f119369e27bf41370dee6e0726f1d8d2f663c2733b6cff30be440071483a4c636525bde5ad4b9846a579d2241b0456e68e5fcb4aa54c5a40d36df4d0265661c9eaed14f46a48b8b184d965150b6d44d488aadd65ef5a90acd43cf9b554de2f3bf8b02f9b79b4743b606f543980ca11532f7a54c0d82f1ec5dcdc2ba5bdc3b07a0332b3284d8d92e61a889789d78b531e5d25339bd25ed0a7d2134c547f0c9d05d6514a9bfe80a5b6f1c59e2f29f5f82e57cba742b0d6775532d11aaf70eca803d7f453dd15b0ec4d8db4af4e2f28f8ccbf4ca820cfd4a40bf018578f43fb0c31c1d54e34fef052e2148bfc9d549fcc2ad725f8b10ca7d72d91c138473d20e720f9bf5124d61c081e2c716979c05402907e0ce27fe5e5e58eea236fc7c5da8155bcac17e4e7e032067d25a9e4a72334b99100efda705e253ed764803632a82c6d7ec1a06d1a68d7607782f88865f5901141872581fee4e15371a094aea22fde35eacacc8c3c68e5cefcd9f5db1d327e25d84862bce5ba3175120b8bce1f15a68a9f5927e05f4ce2d5793102874a0aa0adf28f8b4fbda0cf4742fd90d5a5b2bcdccb578ae4df12fda56373b1a0fa38c0a9bd4f187937413def7e7546ea5388e51e9047e85c82f223c8c850dc4e3f62d7ebbcfee3abb7ec87f40fdd984a5a0cffbf9f63747854b17b360fe94de5c62fd20ce1a2d7e006e30ed080fcf632bf70e5bdfb328672f07691c9f9d652089212d489a3e4a61bd2e7dfb8c534002a43926a513a2e3dbe4be6bb4f46afbd2c02ff8db6e147f11e4233ba98e1e6284eb913115b347356ee76fecc8d50667ab5dd2f94cfcfcfa1d2eec2408285e6e9ee26f83e4148d8a510d766e28f4f778ca892bec41fdd01d26003d860e16a8126e4dfc2f54a1067f308a4b5cd725c9abd2be306b583851f99eb1a4cb7616b403477fb5c065796c1d63f9a7851639814f254f9bb378e3e3d5b27e1c4e5f02eaae8ad09bb79977544d1f8c9c70dbdaa31f5149d99af0bcdce9b3a5f3e80b9075ae5dbcc375811cf384e399ffe5016dbfbd9a912e82462aabff6183f1bfdb617785d35faed8fc005545f48f7936e1dc5d60be79011bfd6a1ea94131feadf1a1b2fb10b3a5640ea460aabc24b2e8d3e9c7f7b7d6a4ea368c76b532d8dc286aeb6326bea1fda87b157dd61ebe25462dd58cc67a1f8d1dff77b627fcb0d8144ee08971cac654c2320403614a260c062485d894a6534046118a11430669cab2310159102741401028a60162e8208ec21034b1c7f35bb2363f080429a8fcdbd02b018f064388d4635efdf948b3de19283a6b7d9adc3ce3a96b6642f001814fba4612e050f6a0565f434ca8b46a34c76532b8a9043a0a78933cd57677d9ab85946812f0b03bf8a73e9bfef0b0335a4689134420e4d15bb6047e7568c22714ef4af3e9abdf29afc4b51a40000570d31a7eccdb775dfc952a63a4f81f4815125fc33b0d8adeb29b0938ef74165de818a53bf6bb130961c070ba19e7d13c6c0f5ecd992fc14ee12b13822eabab2bc80587bb384f1d39f634a07be0103e7adac0e10ad3bf3d4293d04cbd808b2a0d54ca4335f32a9d634e84cb7657400825d60b746e8dfac1940fd21d5c42a04d434bdb95de4e3302f4eb2a4119f6b7e2e1d89f09595621e9af545f17136957e284327928f591397bf6a4d7ce3f90d669734796406f22aa6a8b3ad6e48c5698c730cb2402de5e82376b8966eeac7256ca5f8dc685328fd00aea54134d3bc99ff6f0742dcbd439b488446c93509a5279e76949aec98c11110962df4e9ebedfbb3e50696cbb449f331e6911ffec1f7e544f204d7309ce9d35b36a0012f29de2a77f7c891e806847ebfdca485d8fb6a3365a3963ea3011b3f9c840ce60509e6f0b67fddef69fb8a9fc62c69d595cee5b2df203a1bf092e7f0d745ef2224b2480774bd160ae05d227a841f316f3af2b6357635ea0f80e967a0bb4eaeac495379bcaff713cea48b3cdbfa2732e73a1b3c14fe37ca8dcd91407591d8c53f7effcc942cf5fd76d7d7bbd739435a356ff9d5e17a1c4da74b6f5ae207b7bf0a71a18a0bd0512585287e037b031d5989716934ac27607d46f8b92a434cd84f1b08b49a6fa537db8c540e1a3d804e53de85e1c7c0d07a70dd0add3e895c9f9811e19a0bbb4e98e2ff8e6f6ac87d97ca88a5a9c1978f18be74ad3b64d4699ad30af12bb0e508c4faff108fa36739d4ed7229151edcd831424c5f5e903258e82b01fe0d6eb320d6d987eb6b7ccf98bb18f963c8d1ffca9850d1abfc862171db7b26242c8be3d8acaf18085ad3122c7f9d1ccb340b4c5bdb9ee8829d50f4e5ca2ad5876d1d6450b1540dce6229fe0404f1e4b42c35ae2d1929b45edaac855b74ceac7f3820fcf4e46035fcb80931fe439e793b9affbcdc7825aa01a6abc5b77d6c6f4ebae0cc2dea8536f099a41594307dafcf98ff925ecc829e7ac4e271875aea27a113c9bc063f3a094423531af7fdebeb917612b833513aa8eedfab81238937a0bc9316aa00e466e593aa1b456a07e52d896e735e0b1cc90b053ff9b40489b1f2efa8c93f427b0b994fa6ae37bbc649ae2cd19283a167ac7c2447b3a6aee724fcc61cb251c9ef2a43343fb0faa9db507b8adb9e5da971c527a683bb35f16cee348ee5cd4e82923884960b52d8dda8acf5e43024704cd18fa64c3c601d3fc58c83769a1423cbff884df3511cbdc04c99a8a6ce5c5b0837e53e682a4fdd9516b3109a42b318076a3845a18c0f8a332140f23498fd94a6db5670956caaf2661d231996e254a0269a8d40b6a0e02d2f5877908047c38685788f9ad24357cb79eaaa7e62a97d11ad2bfb1c9eede800b712c057ff171ea88c15b7bae7b978366442ecbfe58ff6393a7ea30c4fa107e4b7a9f7c890e6daecc04fa5f0689cc607cbd76926a706f0d0d34c7c72d01a0ba79c0696a558a2b200f36199be2e37cd370c5a9f067d24880c91fb612ee9031cca8b48308d1c9c0071d276e68f16a3e0549ee2028f501eca82cbfac36a8bfb801e4674839f37a3e4d2e2003c20346d00c35cc1bc1fb6c36d0fec8bab3b1f1fa39999a4e16b97b1d812fa32176403ebadc4e2b392d0f3bc0fdb34f727dc01fd499848eb3eefd831ccef93ce4ec7c3e97e4de32964b47b53c5ff5b8630968eba2dc23db8b780c6493bdc9ff43949106d5fd171608033a20bbbae6a9f82db33f4c0a06b98f174e395c7ab163d648c8a7c2de1c4f32be67e1d13eb8fc5169652e9392fab59893569e32aa8060c725acd24cc65871e1aec09e801ae845efef991af9bb69b5b3ca6c3b5b74bd3cca6a9a6eb3017cad6d9d725dbda8e9227597f28a8208fdb25483a7f1d4f9753c398f647685523331c3a4e8000d4c6f264485b6cb83d1bba3c4779c330b81094053a30c00c988c709a9a24815f5d3052522ebcf1eaf8acf08e64bf5aac5443fbe7ece3aebfa7bfc8d99bd10845100b0c61e4c2c91c9bc310a56c4e88cab4b38786ba9ddc189fa3f468d689b4bc79c2f198322ccfe07daa7b059ea68fe6c0e1748f69e66e0a8be898749e42487b15f6d03170b6ea420534e8f7bb57e7c32bc8bd50152b49de51406ebb25bd418dcdfb0da679af3cf4450e12e9fdd125e2302712da4875f1feb4bab3bf8178b61db8d7fd523c57d15ab06b7186087ffded9a7004815bdef054a40ade40a1c960fd0bdae01f09788803f35d2e99f3275a36466e67ef8f220d705833120dd8808899199f197c803a2547846fcf70a55e0c4c139497493f422eacc49fd520408f2228b633fc05b1652aa3aaeb453f65aa534aad3ca8473b8ed8a9c85c0c4857f65972b27a0b39c9b2189929ea21ba199fa7ed433ebf0d563cacf30ffa9be60961768dfaec8d3707c624055df5435b4b01afa7890b22631639f6e20ac1d62bc8a04d23c20edaf4f70688bc0d07db1c6d94597eecceeda54501951b50e008e20c9818ca81c2c1d6381f014f55c4aacbcc7065dd33cb767ef764adae12bd35f9413e2576c7ecee55e12ed522935a7a03db2a068f3f0141479e447156334923328714b851f09f4da874269293cfb978439d72110fe78f5910d96f17702fc7d9721de5b2f8a9c0714338a226dfa1ec9319af0a675db0544f12b2a223a1cbf24729f3452ea4f334b3edf324b4a2318ffc2ff0d9dbf232005bba4c7132300d429f9e5a14c88eb49e15525b26d2e29e3e1cbd39b9a08ed01bd8c279ed38e3ca0277ec5ecff008a7db63d8fc40f1a540641829feb0705e6d987cb7df355442eff981fcdf73d3cf44899b533d02e5fa356394fd1b29bdf23817b6b70f94308e156849d263f031aa46d38198beced4f85a13a815fbbcae79661ff83529aa81665de8058cb6701964053316cde7ac288e2370261b38568f1697247139a39f8ec98e5f456d4b94c624fcb7c0c76beeeaeb940a50a9677d5df57aabab297439ee554d538cdda489aa139468829fbe5b8cfa6ff3a60ef53a78b7bdaaf09fb830a0ba1e17bdb5ade507f1792271a8cb0ff0f2f483047ed3b1ccaf73685ba1f787bddb08ceb3fa66d1255f13815c82e3be515a67b892910a7674889d8528404cbbd3998777485a0fda96e70b7d3ba44bed5f1bacabd0abe719ce3cd3fcb29ed3a1b9c4ff6b4be5da94546b9276e1c1716aa848ed70bed0042c7098e7dbaa0d5794feb76359940b8a9df8ceb8abb1655205baf8a566bf11e6f9181d2b2b62b5e38a81842698741024979ff7533efc5f1f111d6fd604257201c1863b58f42824463f2a316df40082bcb216e852274a991bc8ffe78f96fa9fc9e0388c85b3eaff3622ae39f07c1817841147cfe8df394008e2bf374df7deb3949f07b3bba058faeae5177ac8955931395a2001317372523f7e0b7a3fd7001aba6d0446f88689e67712331352603837a64f666f2fd47584cd70c6db7faf7bfff5f1faa877a954c2a200678521e4343a108845fc65039b7ca271e8cedc092770c787f81b1d9e5ce0ffb71a7c2705d7cd15058347ebceba53b2296df54cf7c827a376523d07350ba9a908701bb68946039a4b1fe5ee643517cf8c5386dfb8df5bb33679a58d1c469ee89f0057505e23ea50883cb9bce08fd7efbaf8cf29bbf8c178224b7b2358eefe3bd1de262fe7440e7340e90b5532dd78c02ac3937b947a3c6a0e97c96005d8d9ed59603b1cb50cd2ebbcb9748350366c4c45023b7135d935a1a5ae7a323a97e0ad2767c95c32c55d4c7e949c810bf84596845353f4cc9f3ab716bd6f8cf3450dc1cb22751cf33860387d6fce5320a7e303f66aa9828539caa22add1e03126be458dcb279e36796fb971629a1b5843020dd55f5140315d6592c86d405f1646321e5f569d1b2a53cf1a96b9dec7f59c8559cb82f94a851e5384e382a1a8e0c8926852d1c571607c518b3bb9132dff1974093553fd3b19f4fb87a93ca2289ae90462e975ff6a040f544daf508ff7630b6d4e71e7fe6372b619930609e51767e99d68b9101d2d93980089f4cb548db34c64ba2f034af15c8ae240c9860cfdc0e68b3c51f6eae28e1abb89c8c07b24a5aab01950280808901514040480a83b27559bd92e0c82abf680e75bba3fdb624ac863256f35a154311cbca3ed0c70ad53530079a010679a4bb50f012a0887f7b745f3ac02a2375cfbf2e6a29720a0c56288bed3924ba650d15f027682bb4fb12a705dc0ebd356aab996d4f1bebd1344e672ffdd36179f4f421474f147f4b12c60c89fb10c806c27a6df63bf402670f8714b9955b0a8d775158cf77be744af8152c38dac60410c00c009a54226a7d4b0d6e03644d6c6a617165be58a28e8e14e08f81434e9bb463c5e40c5d8462c88bf73285ddc7787dff7113ce9c139fec7bdd9a8e310757c488af07135292da559c04744b09c8624c5c314f74650bd9d6805b9001d71fdcab6adacae4b5d20401ea88731fb4738540e9626d55294e49809df42894ed30324f2d321d5a4e577faf3d643515fdcd7d5f56552d4d837a201219d38f63f0a6bb0529c096868c1e7adc9297b409750e0c25af68a43d2cff82fac5f40b8a2c0f0df9a5a7abb88be513c2be918459b7ba09bd915d8b28d690bb074796fe85afcb40784cfddcb4369cc79c0b5e3f157c7b90384a7684e61a42edf6c775da7c23f0ad1830984398e4114887953c362ea9f4e10caf6b3e98f44713c1b2c5fbae2c4a7f221bb319306c1f64e87e7f4715436f9af5b408d821550ca292da0ef30b573c1df1a86c4b5c8a0fece7076da67ddefa677551d4616c3ad8f8324a1d1bb52dff20fe9105ed9857d01f73bba98365d6ea771cd11567b6bbc91c9b662eecd07d64640b32cbcb7fe619abb9ff6995e52e7946452c7a6f8a6ccac901b8d57bde1847283cd0309b2e498f9642fe3e06730021e55bcd01c0207db4f53ddb3d94cb34512bb8890bd2d94eff99e228b95897f5340e10353762184e112fc8a0f3f1aa852d2bf560f6a24acf9bb6d85411bf5b90501c8cfd075085fe2cf69d19fdc3ae3d3009c6f9f712a2551792bc3829f3f0adf697388a8c61d10d854aa82e07ee34d6965bff5cef4c7f78775d32269b49368a1497e00e8972c9bfa37015d9051676a3b7711c15588d03e93d7baf9169f6438718a46aa14937fd73d2c3c100d7ecebb6c669879e716e1784fd48684df9d39c353332b18902050c505cf822bad36ed39c2f8b80336cd9e15b22fcf78cf0b0e1f7e5873ee000b1e4a3f672b9dfb3eef787d9b3e91ac62ff9e8cdedd7f3081e320d9ef55957c6d8d0042576968d2fab1f702baea2c581fa478f8a6ed93a2970e35e67b4b315a454e1c9747271a256fd457775a4090f5cf01f9144e3ef4327abc87188690868c21a27e02087465ccb645d9aec1dfc82f6774ecab0f65dc4b25c7d5e3056f0cc2909ddca451d7949fa5e30f910287bacc959e3d5935551dd776b4a53a9af3b7663e8ef972d22f00a96b06e635a1ed8c397a1e0b237eb0959a8a26318e364e3e68f739d6cce009e78948f87140b51626de457e14f305267c53373aebc3bf73dc2d37d7a498906fa93e80fcad463b1a6e4fc28c4e06b7582587e0820d760317df7bf572111ac72f07da180c5f5c4eaee297ef68aeca4c90ec324f24ab889ce0f50f507f9e2b8f1b5da16e0504013d496d887793590df1e10afb2ca853ef55ff3f90fcc078b9c370b86e95ccb507051aa8a018c47c72e26444feef922d34afb8e6ed091f48b24664c1a2b1788f1708e24e9c0d1fe0564ca9d016b9cc5f3b09fa2e62e580650541cd7d907eb344f7cf4e2a2eecc3d5ab897ba3adc37dde5b83ceef3e13b0eed3f0a4e335ef0008b3bd018036a2683667158fc3d3009ea7a641df0f073839db5e3a2c9c47ac766b53265db12e1a3b9b238c20c84d1700f14b4e4f62e299012d87c58c9cc730a2154cf0a55109d07d133fc3c3c71252e036ed6c7a07aeee9c1759be60bd380a2f4c91b8854fa8f4d38e84ee9f45dad4335bf379d0c72b6d5c32b7b5535451d0bf0645fd7ddbb1590341559ea4624c235f281aeae3c46702049ab5d09141843e3831876a01627a03993795bcdd482f34c59b7141a4608af40aff5be18d3f4d5a5fdb0aee1ea1b6fe256e01b5433d9cbe284f727cd2e36ff5a7c3f3a459b3ede7f48ce7d7950a67d123d2fa26fecbcf6e213b5c5a4d17c43c1b32c600f247e5b5a0c4a4febd844e81df214b83fbfabf18573a841b47a575d00f384a194a531546ebf436fd6721dff246ce6867538994d06d2f586ace692442ded47dbef5341d02b62fde75fd7968223055cd97b5996fa1e29f40d60aa833217a881457b7301a38d06bf1686d9dc71cae6de01968f722999260e089471724c6a549501760add7a7d4ee0b4884c2587d32f284f6bc05e83f00523d86b5db39224f28dc39128cc85a71d1b3b7f42e2163375cb744a37158e3fb97e534d064b1623b77f472b95ad3b1c7908b8ea45b4140fe20a48dc2bf370737f506b01352ab8b5bc1c76c9aa26815acd510418fab44dc3a20fa76b4829cb8d52ea61f995ad492daca519b36e1dba50c389b70ae9e7d50288a53c1c576990c21f50ee9dcdf0d4905849589d2bb30f09e571fe4cfd086bcc8c45d99afc8d3327bda744f5678bfa177eda2a7f00b40c305636924cdfb7e16025cf7bfea131582b502b9790b65caa0c456aa07f53021112a67b0ced03dff4f38133569e650a15311793376e2cda6b19037e1174f8e07ab8633cd45ce82edce7155810e38968ad2028bbb9dc2b690a287151071d03f19863b6d577c2ee20d9c9ef6a6298e5462c06b844bb448415bdd709b22c08ae6c42b04aca33ce1e5c13bbc569ffee962259806c81824432676d65ce506af29578dabc0e904f1e01b0321955160cca6182bbe5fa6e058844845c1f710b4ae832035adf8014289521d8acadd37a20ef4800f3d7c80b23e39f3da71e59f7dced4b8a86c09e25c0286729c9d42ffa9680594596f8823d01920da81a6c06b022e0af60720313f1055d883cdee899ce139e3fc29e6f9f36ab189581248f43270122a5f38ae3f11ab964a55ccb3f2e1b00443c1a89478ae2ef55cfb6a835673a0c4c482090641b15e1feeef0ef27ecdf6dfbce43da30e2e92e77ceffb667364c279887e31205991dc0c5d4b2a8ff9fb5cf61b201886db092cf1c57c47b98b5b7afbd99113a2dcc22e7f4adae7506420efdfced58017b52da82d37e45e501d8dac401639c3d11fa5ed51e86da44489b4b020a3a53a842d77ffa09e5ef07b0d53b401ed1e35ed8f8c94018b4338f04c103a36f9e0a7f844818cdb9e2a3dd80f4e049fbf7a97572609f9d63fd4451ae8e5a0eaa2fed9f771568796ed2cd479fdc79a1bba0c016b2fbef8573ede420e625c62c5ab600849da922cf8c8031e0bf9247036d73ec69d8a8ac2b7aafcf7acdbd8b6b7a87ae527014ff99231c156ec7880facb205a4d96f55818051e167fdd2bdc7a128c6815b186a1604d8f6c864006ee86050f163cfcd3ddaf51fffd8b1e670adc6917fd41400399f278f4b342cb23b60491dbef65b2948ae90d3714d5041b59eff067830e12a0ba4627a13aa37cc980bf78a44703918a042cae34b341d18b64243bfa5e99205f3db3743c8c1757a5be2fbfebab7ab49e8c6a8eefea05f942370a3b462dfcdd30385c108a3e3dcc81dbefc092077a9a0f0b39ab07a465990f551d9b3fd45f4e8624ffc32a002747a7d014baf8e7cc0d229b6ba3701bcbf94e40be9561b32b7d70eefd4ef7e21b54f57468a61372a3794d21bcd24962923e2dfc6db48e9ab5962f69c999f7ce9d7d2c0933b2b199bb71761cfad9fbb905f68cac49c9712fd46b411c315c7b4cd66c87dd04cbe3ab7d186e986ffbe323a04ee32de3a5121577a58fe83ec991126df707c8b5d175ef0d1493b44755a2419c7f5b287c019d819a84a1a3f94a4eb21d0878c9eb8a996c06768109ba8790dbfb8e4e40ae81ce1214c8994ada6377d55d8188ffbb46dcb8b84ebda0dcb8e17c4fc4e21262ec529098d74e9206720be69c09bb58ba28472e93dd6a9c009390db7e855a1e36d451da9a10eeeaf228ca6c37a08d1dd2b49cf408461dd7e3e2a30c481f1f265e1ec8a084b3f14286e49e90885a70192012489f989848ace936bf7904e78c8c090b982b0eca7c38f7f7260be8fe5596178b5c4befee99df1162bc3c3b283c9ae5dfc77e7ec99f75f38b7ee17871e85607ae7ff35499ef78e826d1fc7964efe26c7b25976d8c5fdc8d4f84acc2b17456ebe54c5dd077af6252ec8c7b2a3f00323c16f4281938d825c659f35e1d9d30ce2f16128a7ee8c6b4f27864c611dc5c30bd4e20b02922b31b0d7463075c69ee2f634697e059ba66ac9d5bdc83313fb6bf09268301a99533c1281b3898123d670d53806e8681989707969ed169fc48772b28d38209f089fa859682bfc35a3afcd78dfac03f0e6ad2c6f5e3b48fc37f0c95eb70ad655cbe3c088868e20b234c520c02ccc3a453cc2f5f4d59e68fae0dbf58c4dcf724e63a98050433ecff258cfdc7a0be44bfe8fed75eec391df784fbecffe28bae9b8dc5fcfa87be72ed1fff0f4282bdc3e83f494691fdc38c9af4f61f1862b337ae2ec3d76c2c7b1dd2eff56626f8e28ad5349efde82a9b1497af7c26ec480b7c63278689b525e10c70ee6ab59fd9c59dbc2516ebbe36460a2151bf8ba6a79e1a83db4ec23bf52c8a8751b92c2b5b6ce03769d465aeb0785925057c5004787ebf8d8b13facbc3858b7fa54aad9b372e11da696a9f31e272c25cdd48ba67d1609ac2dc3c3aa7756c0e54566fe49d4cd6167913c9abc76d17ac513868868abd6d5ebd2f57428c366df787667eb0ef477014443ecc1e3ae8a9797897a855e3139a17f1c063e5bc42e28842a732ab976cb69356cb36b7d78fbd6997fa2a151d9d1dbf39ed64575cb18585a843963e737a1a72b7871626886a1a3dcf516b36486abdb99fb3dfbf0f22cc7fba210fa2b9f160e82ab2b1093313262446028986fea6a19723fda6a33bfaddfbb0c240d0dd6739f303c03f173f536f986305ff1915a9db504f7b689f4108712c6d6b2159f89d9c1f8e0d0af5f93932db518c173dcc18edd67516d4b8765aa83acf3cfa2a12b0f87f23ebbe305c89fbbadc2a8a528c54d2ebd85291ef46f42822e7384aaf44ee01600c5bddcfa46e532e038df64761b207de4f0b993d2ef5608e9a06d04575c08e011fd815d53516ab4ac489388e526e1068fc543133eabd9f25de9acf76b0aec878e576180f6c865f6c72a18096596ae103e06153fa5b331a5450f065f1e9be584c80051d56d86d51fd18a75b67fe08007bfe678e0053069fc8e060e2a71f2b5ce9183fbdc529fc2c68413ba8400e34e5ff16ead6dc9d45edd5aa2b95c5b996ba40f6cbe2847934d2a80f88685e1fbf281ec28f0b7a2d19de6c2f6e448b340c577d7285aee9ac301534b3ae1cffd4a0db0dbdf538702d8f80c8a03aaeb556dc084c8d9804fedaecbf59fbe8f58258e3b62322b81b7fb060a2daa118a0f13ac780d53c51a18f6965caa3209e75225accaad5e249c03820320cddc73e216feb1ad0c3559a4bc89991a44e84e2949dd60d603d73a020387850083e88e0c298074006d939dd20aca4854f99f0471bc57017114928a20245225653d295ac7b85c4523b67389882837f885fd3a7326fbf7f3cc4991c23d084ce221bf0b3ba26e8ee91e31cf61604455df1555a0f5b2ec4714cd240003119e7ffb2afc48d4c474afe9b8844ee8a0ef2254695a6486d33987a6c9aca87e7f0dbd90819d2a28cf1c4449d5f2f43290b118c40570885cf45747a80de914096d04321bedbaa10bc6b62c52b9765341392e3e288665d0b2e4dca2d25b3fafabd7ae6ed5d748013b8939deaf390cd3dcac9d95123bbc47ac0b64ca058ab6048458105c80e886b34c51d4693e9e57357f6074efd577489b2f0fb94a123ac1625a0e5c5999d4754348501fb9369e354c0e9aa6d432daeef609f5535a58958f3f4da581d21d69d5435ef5d8abc9fa5b79b9c26a54bba9339e2f49fd79164d9fbb3b56bdce01b15ecad9ed3460438de0d745da4c4b03ddf64f24c61eaff1bf71487c518759375ddef935305f41b7503e8b240ac99393c1479c4d96fa55c920dcbade3420501473ae6ddfa8419f9e995abca60046ad7689366e9f9423aa94c4d492142033bb1407c169a531311d3d9637fb927ee302bc50af4f1bf259339cba97beda9658457fa4355a7e5ea2e33a558ebffdaf5bafacbcbce880f88adf626c3164a4df493bebcd87af7d961a26ed5f47517b2ead0124647e62127031411a9791c460a5712cbb0c90c077e27fc90085f8cac92b743a6621c0fbd17934cc2d9501969a4b4eb570388dd2dbc168f50d81d1df5fb9f477ee5d4f2f2559e18fae6a33bab3ae905454a0c5e5a7c0ef443ad46820c0cf2c1cf463d0633fba3891f5a3653066bbeb817b628077534686531632851b2170a8a0dcee59c62a851baf1bca65c324e653418f5459d990b425544a043e3f91680ef808f06b5ab628518e02b21a18f0a01d0db144052cb400589a2e086b8c697ae970c907e1020ae6d7f303d65bc0c6015a5082c94d50fe55e499f0e60c78107a84c118e5a54395a44ab1d7f60655d3d9d06d48a5cf51982a03fb97d59b17b2907f5cc5de527a985fb42a8a0ef60e4a8d4e5f4be33cae2daab5b8fab0b9428d47286ae79c6a5588187c6967e40ba08d527021c32ae1560aef76a4548c9ddd23c3176382fd9b0d21602edb05f5c7a38fa2bad98c8cb4ac6780ea87da0bb3ee00206a0e269aee3ca10b675af2d3c27fa50561e8770bf9b03f1b03e00f58630de3a582cd0f231337f9f865a85aa4ce557df68e77bf998a6bf94d590fd00622d88bcbf93eb040b9aaab39d946ae21ffb11e7995435e29225c4518b761ad06556dc6a0169e2b1cda2e5ab1c5c68fb95fe0da39ae1a2bea54273720e479c3396c5b424de0520e68128ddeb8d82d34fb5d9db6086c94a9f0b7650601e406dea04bc817c7b334b2fdd4a79416d7d6b3b6160a038a9059d8f998a5b4b0c845f9470d6fdb6ca36359cc5fb0ae40df274eec0d2bef92143181e564cd2675c6262be7250ac96299f63d58ba79fa0facdfebab54aacc28fa10f0df95b0a1117134f8fa9c8fdc3705f51389287c12c2d3ed5dea88eb9ec9551b8fcd71cd4f1acc1d1f7eb15fad03f423daa1aed3a77b14765a501d807dd9c031a6b96e7184a0e6ff01bed06a7b214f54dc2a5b38984eb4c98fda391085c60441febfe20e0c276270986fe4122661b5ff7959b4b1ea46c092d923881a408bc9015cb1aa634d05c0ffad21f5cd141afade0effe702086c0e23bc9038e9726e4cca8f14f38c64b0768b4a30d438324401eca61aa2fdacacdcea456e23c4a4d91fcd5ef961bf79dcdb71e0f785bbb0f6adf666edba5847e1d62b9fcb16b904d7ff03ee21a7f2f015ab437ac33ccb6fd14b06e57da8ce2ad7d1e11fab2f26cf8d781766605e95d36d26074effb14ea63c9b0c37d1f3a02934ce0b2c6e48536b291e2acdc25f359ff0b1e43e387c86d403e0ed66ed1434f2e2dac0efa56f9d4d72f52d37b59c6ef12f1fdf0e702e90d186bdcd40c034a457256c2eaaba4b658e8d0d2b6db352199493d438fa594000000000000000000000000000000000000000000000000000000000000f902c0f8dd941c479675ad559dc151f6ec7ed3fbf8cee79582b6f8c6a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000aa0b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a0360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca0a10aa54071443520884ed767b0684edf43acec528b7da83ab38ce60126562660f90141948315177ab297ba92a06054ce80a67ed4dbd7ed3af90129a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000aa0b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a0360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca0a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873f9d05a0a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873f9d06a0f652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f37921f95f89b94e64a54e2533fd126c2e452c5fab544d80e2e4eb5f884a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000005a0e85fd79f89ff278fc57d40aecb7947873df9f0beac531c8f71a98f630e1eab62a07686888b19bb7b75e46bb1aa328b65150743f4899443d722f0adf8e252ccda4101a09f555619c4ed056b4f2385e5b6fb5a874d040bef66d6998283e391bd9a91221ca062ede1de03d21b277fe9406c914f83f0461057e1782c0a71d03cb10b950cda4a", + "0x02f8b101088402faf080850cce4166008301ec7b948707f238936c12c309bfc2b9959c35828acfc51280b844b3dd411d0000000000000000000000004c9edd5852cd905f086c759e8383e09bff1e68b300000000000000000000000000000000000000000000032a4fb7a05fba004f1ac001a0e9e0c4385db7f0f7254952e6ab4ffcf866ca32826d7ff6b03b0155bd828437c2a0686ecffd2315b97178a90308e3ad0dfdfbc05b2338f7a744f839f0db594d61e6", + "0x02f90332014b8402faf080850ab5d04c008301cf9494d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef00000000000000000000000000000000000000000000000000000000000151e7000000000000000000000000ae0d376d7a0c05a7d78ce1d6990adcbeba67314700000000000000000000000000000000000000000000000324e964b3eca8000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000011013ee13788b544e1cd9d4551b99fb67908c0af827367536a61c6577c08697943e2324bd61b8e4a36f2d1f3430cbe7ec39761d78043880041cf1bb61c108c8956a5aeedbe0687653aab42caa3d0242025d1b2397fe9caf1d9009a41af910168adb3788cea6ec4d59e48145c770ea33fccb805b64a9de0d222f3269e43650725efe0e8fee352be90eeb0db1aab9246705d45e3f6f474286c92b39c29d24e1540cbac6b511830578ec7670b4dff6193e87227dfc43a90f6646d4387c88db7fc37c4448445a78ffda7155f56089e57902f63c1c27d8e2ab2ed652e6d34499f7d191bc7bf9f7f765a5bc763a11afba72bfef3197e2a0ea92ae1518867da46e04e482db871b72a8cda4f4b6b15160104fadd87ffc251bae62d115fdd86cd63d640da0342ff59f2bb35f6825ce36c0c017d146b7d459e6b820ccb581d72dd281dd3dee0ad9751a222f9fc2a6abe41b9070595ef766eb6e478f38a433a495d4d0a0fa8f02765177d6493d379f8243cc6871811f8ad9c00a8e42218bdb8ec55dd8d7ed4be8c76c1c930a16790a27d5c56e6136892ff1bb31c5eb678bd7b29adccea97cd67d7fed8664df0b0ef45be009c7182631961ee883d8102e542af6eadd5a3098ed1866b8614da6d5761eba4253b79baf01b17cf793a6056a1204b3457acc3cc6264b2f1729c555dd226f68ac9786871adb4125748b57f44524ee6f108c017fa8db8340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec001a0666e3c97d134e6014f44091c633aa6566c713483482d9927a32b4861683f0074a03a2e8e0b3499c7e001295c9892ca060e1d1e0db7639116d13786116a320d6687", + "0x02f87901822f558402faf080850cce41660082c401940000000000a39bb272e79075ade125fd351887ac888ac7230489e8000084d0e30db0c080a09b87636ac160fb01cb7a14d27348b6cce0a9ce42785838be6d63c893aa82baa3a0112163d1c9448411fc3c1c864f441df6ab0da54d20d2c618651dfca39d47193d", + "0x02f902fc018203058402e40d20850fcff91b8d8302ed05943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad88011c37937e080000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2aad700000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000011c37937e08000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000594907df5a164abc86983000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000055a380d134d722006a5ce2d510562e1239d225b1c001a033bd3211f98ccc049ae4f90d948e326815d684251207cbd2c3eba6a06460b4bda069ebb2026ac1c3a4d3b6112c5ffa3db8fe6176180534d32e07e5a8a1791ea97f", + "0x02f8b30182048784028f297e850a5899c27c830186a094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000f46fb27ec20ae6171b6484109b21ae9b723af74300000000000000000000000000000000000000000000000000000000017d7840c001a04a1c91c977440c133d353f3952196deb01a28aad1102174c50ffbe64d35a8d62a03794e47ac37354b4b516bab988a5ada1773c75fddbf0c607022af88d63daecd1", + "0x02f8b1013284027ae63b850a5899c27c83012d7a94b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb00000000000000000000000038647bcda8340a7ec10703ca423a7a632e5e8ea400000000000000000000000000000000000000000000000657b3801b80b40000c001a05b447cd2f77bb71cd6c3bb3b6d2fa2c08f1cbfd798b5b37fc220b04aaddc981aa04f4a33fea11833f4aebec8cda4b19f51f43c86b16f706198881b56cb8ecace7d", + "0x02f872010c84027ae63b850a5899c27c82520894813c16051667ded55e2cb86f63b6cc81218972b18701ca2ae5fc73cb80c001a0e3191e3e9a4fae9cbe054c71d271c74ad640fdfc8badff7c6827d4d73551f507a0468eb101f8746dfb264f07f0fb08af9977299f1f7d60097842c324ea00cdffb8", + "0x02f903b2018084027ae63b850a5899c27c8301f10694c059a531b4234d05e9ef4ac51028f7e6156e2cce80b90344e1c8455d0000000000000000000000000000000000000000000000a004bb4a965d8e000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000a004bbaf28b6a3a44a00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000012791fb7a91b1b3c60815bf9bbbe54cdf00f2d3f084e77ac99942e036d3e01bd8057786c6928d7d897c1e7ec93b1d836084c3398014f766b0a4e857403dc95468703d7f29aa1ed31f46c0028ae2d565629c4a97798a8b976da0370d21fb95bbf47ce46f8f26a32c8449fcfd5c25a474469dd181689ce67188f3631258302ec94723efee3ee6093afd90c7dcaae7ecdc5639a9bff58587c6c52762594b635d3e8320c5922da3e335b38871f1225273aca5f1da9f1ca0be1f54594f9e4219f5c3fb96be551d7209903fc8512fc0e62917dce5a2c5639e173a61a7c9990f128638bea62b8f696c075a0d7480fdd0d8bc03d0834d2f5a86fc7c64e1f45a419bdbd4df3d038d5b291a1f627517cc2d75ca3e4bb5c2c3b28d68a0cb2c662b10e264f10fae687a10f3943c38de5f59624cb400f4b82a0b985ce78f9742ddee7d548aacc59b091ae32988a1af9bd4d0a68cd651be3e9a68ccfbd49e4fe4babfba1c8a009c639a5d127dbd4c142bb36f6b82c1d115684578f978c9b1c11c1478f5b5117e2754d4d89aa46b18ae213bb25157ee5fb8b20d88fe2b2e81f2629c93de9173cd7c8fd5e17bd6e2dbbe8a56472070b4af2c009dab576ece1cadc7355caca63d7af7b7dbb4216f2389571e08cbec5b3e3986681d0b9d88f13a47cc9a55aac7f7419d6411ee03323e3dc5c6c2e77f3d93d20d7e729991fae4bb544fda4ab659e5a01c5ecef3f38904031cbedf8f8d77f7533385b9176d0ebe964055755bea7fdd7a73b3bdd1e5318b1af41fa68346461d94bc4793ebd12fd81ce5d0b74b62d096838eac080a0cd94731ce42773b6b1b5830149d4e003d99dc8384ce6fae6a8e485ff843e6967a0243b33856f7db715612632e73a78a4fd53a0b31e962f2203489ad71dc54c0937", + "0x02f8b1012484027ae63b850a5899c27c830171bd94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4880b844a9059cbb00000000000000000000000067d39ecddeb6a55c036bdf0295979a7b6bb5a7b3000000000000000000000000000000000000000000000000000000037ba039c0c001a02fffd250246b9daac1283d8113918fb1fe98afae9e83930bc616a5d5cd6d5fdca068d90ce7f7a39c23e5a8732f75cd0a140c8e44e1e34e162a844298c5f5751716", + "0x02f903b2010784027ae63b850a5899c27c8301f10694c059a531b4234d05e9ef4ac51028f7e6156e2cce80b90344e1c8455d00000000000000000000000000000000000000000000008b6dab94f5c0b00000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000008b80d8228c84f7b00c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000012c79d53c9a7a164161311911a3c33533c2c74ffbb4b88cf164e68779319dab8dd241012219023151cd4226dbcb1270eaddf920dec8919949f260f5375fd90c7ee208b31641e1d918ec4816b92a8b870b0410def69d5269974e9a40c65a5f48b76d7446741c70712ec3bc408c00315acba7df1a43d9e98d484b21546a68866bb06b08c33db93023668ac1a958153c3b519ce4488cfe2c1a9a27295d03618d262704cb60fc535d433cefba8d4e97c07e054749cd93d61b1fcf19419b702d8a0c786c2f1db2f6bff80bcb997960c0d03a323641bd0f37d6375d2a8740594be1810499813bb36a917a3801d1ed4228a19de027d3cd10c64e12398c8e836a4e25c01fd6b643f5d9ef94bb41ab758c49cc538e1510573fef366310385c2ffa1683237ae8e2981597c63559b53e7563e9b6917feacbc507590fcbcef99899f1aa9b7ba9a04ee2bdbb631e63e0dd22288842600cfcb55d8cc971725b082745bdad690cf40411952d1ef65dcb635cfcac9e2f74543cbeccae33aa05191f1422bc9085e9c43ae7ba5306728c30ee2345a3e3e81d025fce344f8e7e1f2b4a7b79c52ad7f6f327f5520e52bfea7881a8a82b097985d1012e306bad81a7f4ac189081dcf5d9de582d335e95c2a827957891e92ae6e48698388ab48babaadcefbb51b3c7515d2dfe613bfdf5deb667a1f9ae577ae021a46608d9a140d92c6e79a344f8b9d198102f8c71d637bbd325b87ab4c094dd4ef5df9a1d62c6dea6d0f573c21dbfb086bf7fbc617f85f57eb6ae6a910db84ffd7eea166608f0587b82a0d02fa84ac8abd81c001a0ecb9a0106aba31dafbedfe0c77a5054a867ec350ceaafde6655330e17c51aad9a05472964a01241224b46789835b7bb2eddb2659a3e1e3aff00539c7d9456e822f", + "0x02f90334018206c884027ae63b850a5899c27c8301350a94d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef0000000000000000000000000000000000000000000000000000000000016440000000000000000000000000c6cb96cc1727ec701e5483c565195b01e3c1da2b00000000000000000000000000000000000000000000000fe2311b9e95740000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000118732a908110171cdd152f0a3fc1abdfedd326cc62d279c4f28a9b5595ce81215f864fd8afddb03cbcc72cc8bdbac50ebb3ad793ea229920c2e0a33fa3d31403168e65f5a67a47911aeebae614c59384d9b710e06aeb53f8b397a05c84c12e037c758d2c4672089b0b54ef8003e632bf4ceab8f16fcf3f60aec362b30d52cc44b5ff0a66ce5a0cddee227f20435920ee5354c1a27f3a71113aeb5e4124dbeb7e9f684b97327d4179b5cc4f84d7bbe1a7016bcfb84c0d07c56698884b96b4a6d8a8e757818983df1d3b28746cd8d29174466c10786844bb9200baccbaaba67578cda6b884a929165392c4c002206bd42d59137e97cca3fe6a31099161f5f5e28307902cfd27c9a729e8cb6dc30a9180273dfa3d67a2b0bdfe98d15d80068eea87d55d80453cd5dd41b0a179fe877b90d8d8e6a44423ff131890fe611ed2ca7ee67a31f3ed77bb9215bacf9b47da600d53e372ebd97552ba37731a731b2b490c83e21a90b94a8d5891299de2a8fe58144ac34ba0b0f5226bbe54fd2cffaaba4bfcd67e931175e5b4c8b0a956f3d164cde10179a7583ba29bee3eadbc2acd1f0d6df9677a941d7cbbd94ffdf154c6736b146b862f9de6449d0d550ac055f19596abe3817ee8a14f49b7efe1f8351d9e474eca711776c9d4b2f80a01e0889a1e8a3497dbbba44476a13c02cfed0b524896278c0bfc2ede44fcc65c1b9efe49e33a5ae340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec001a0f413a42bbb6c7766e0bca787f8fd339bc0e9fdb5a170f37a469e15fd3e51f47ca064ba5cee705f894a66816f51749e824c6d06c5d61e63511889f1ccf2b656a6a7", + "0x02f8d1011484027ae63b850a5899c27c8302d57d94401f6c983ea34274ec46f84d70b31c151321188b80b8648b9e4f930000000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb0000000000000000000000000bdff5cc1df5fff6b01c4a8b0b8271328e92742da0000000000000000000000000000000000000000000000056bc75e2d63100000c001a07b84b299752ff51bbe9044c23d2e00eae36dcddf553f0c9b7ae8b15ef15d4d76a071178b276c2229e62a6c13d780d7fec337f50a25166d1ac649dfa85c1df34826", + "0x02f8b0012484027ae63b850a5899c27c82cb1a94b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb0000000000000000000000007c26a37ff4c8ba0c1b6168962357af069f5cf5c40000000000000000000000000000000000000000000000019274b259f6540000c080a03e9792907cc384488940415cd89f881a489e7de53941e6dce224e9cfd9eb16c3a046e768ba26b8d79b7efee4ef9630e1d5cb9c347ed2a5d99c9bca7a246bbeb9de", + "0x02f897015084027ae63b850a5899c27c83015f9094abea9132b05a70803a4e85094fd0e1800777fbef876a94d74f430000a42d2da8060000000000000000000000002fcf7eaeae8a981300e290f1cd38435a25fd8972c080a02abca7a9bc2e5893ef08421b904b44d7ff98ac11696ad65953a87dd0580fe644a00b6d8abce4d09e0d056aa4e07f752e899327d0f497dffd5f1175a6d75e1f250a", + "0x02f8b20181ac84027ae63b850a5899c27c8301120894badff0ef41d2a68f22de21eabca8a59aaf495cf080b844095ea7b3000000000000000000000000216b4b4ba9f3e719726886d34a177484278bfcae000000000000000000000000000000000000000000095e57656aad8fb25f4000c001a0888717178b845b5ba2021bfb48eed6373c9c1b35ab3c3199e9fe4c08c475ab7ba012497eceaa72947f3704b314f9599a88cde11852e59453994c02d0c13a5e317c", + "0x02f891018202f984025c1cf785138daa3288829b7194c02aaa39b223fe8d0a0e5c4f27ead9083c756cc280a42e1a7d4d000000000000000000000000000000000000000000000000004bbe6d529c8000c001a0a31ac549502c1065a233d3a8b2701c0696c5b5b72742d9ccc9d4c5ac4ef6d82ba0131dc6fd75219cd0c8d4403420a60acf2a3e5f666557031aa8bb2546da343cfb", + "0x02f8b301820488840255f2e1850a9a1ae67e830186a094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000caff156bae012babafc155b87e8c7cbcc94fa73a0000000000000000000000000000000000000000000000000000000001312d00c001a08d3dbf07a9abe69f705971bfe4a9fb84f212464c0c2eb37a68b721b4361fbd7ea07351f95594f96ee8a2710879d90e0df71697ad94b0e5c6657a907ab6c9a3aa92", + "0x02f8b1014d840255f2e1850a7a35820083012e8894b131f4a55907b10d1f0a50d8ab8fa09ec342cd7480b844a9059cbb000000000000000000000000a8f02eefbf996f74830b833ee15c8eb1480bf1fc000000000000000000000000000000000000000000000096684ed80d4a7d0176c080a03c04f09647d9697264f6046da50039823f3d3919f495cca499cd2b317a021188a07ba1f490e5f3a5f1e39a6e9cf52f74566960dab3094273e3ac530a0d414fbf3d", + "0x02f8b30182048984024402a2850a6d274f32830186a094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb00000000000000000000000078680dbc25dee0c01b0897b8439345ce1683e3560000000000000000000000000000000000000000000000000000000002160ec0c001a0e7b7ddb074a2e81fe9221c661c7f04db1ef9c4cf3ed9f2bce1dee0e4bfdf3a69a03afa2e314f35665969eacf3c6380e976efee109d8fbe53a9f5eca43bd0bd755d", + "0x02f8b0011d84024402a2850e14ddd80982b66194c5190e7fec4d97a3a3b1ab42dfedac608e2d079380b844095ea7b30000000000000000000000006131b5fae19ea4f9d964eac0408e4408b66337b5000000000000000000000000000000000000000000002f00399d4efa8be7bed4c001a06757aca218063c654b6963a2c5d00be2285f3d4dde4269f3f1be64365444b50fa071369dee66f770103d6f530b337cdbcb9b29172e8fd02bde63443a4721c410b9", + "0x02f90379010284024402a1850df0ccb90c8301e7479469460570c93f9de5e2edbc3052bf10125f0ca22d872386f26fc10000b90304b17d0e6e00000000000000000000000000000000c18702f6e8994fa8929ccb3bc11c16150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232bff5f46c000000000000000000000000000000000000000000000000000000000000000032b00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e097c54bd6e689850ba559f911d839513a146c6c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000004d0e30db000000000000000000000000000000000000000000000000000000000c080a0c8fb0e9523d2e14a5c7cda5cf77e992406b00ee1e1c0858077570bce1cdc1e7da06ca7f945f2022058e7e8bc32d8863edac3c0207c1b5c9f9d4b6fca11bde37c2d", + "0x02f9035b0124840237ddc9851363ec0bf783034dbc94881d40237659c251811cec9c364ef91dc08d300c8761e9ac8a028000b902e65f575529000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061e9ac8a02800000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000136f6e65496e6368563546656544796e616d696300000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004521c9ad6a3d4230803ab752ed238be11f8b342f00000000000000000000000000000000000000000000000000610e596dec14000000000000000000000000000000000000000000001038ba11f47e80675858e900000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000db531c166c00000000000000000000000000f326e4de8f66a0bdc0970b79e0924e33c79f1915000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c80502b1c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000610e596dec14000000000000000000000000000000000000000000001038ba11f47e80675858e80000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000180000000000000003b6d0340394cb9e147b8b288e38615ae04f442a037bcb99fab4991fe00000000000000000000000000000000000000000000000000fac080a02b8db4a6d4b2518400cb078e9c533f9c38b4209ef428ec341a41abe79342dcf7a046d12b626a1bc12d40f0e35738e7ec00cc8b4eac46505e3c401f992c26b0c3f8", + "0x02f8b00161840237ddc98513004a65eb82b70e94ac5b038058bcd0424c9c252c6487c25f032e5ddc80b844095ea7b3000000000000000000000000881d40237659c251811cec9c364ef91dc08d300cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a0aa10d5e5fc7223177ccf4d506104043b308579c83627e5e1a651b658bf4f2b82a079f7bc679ec874485ecc88bfbe609f96448b935648e389391d82c743cb3fadb7", + "0x02f903740162840237ddc98513004a65eb83048f5194881d40237659c251811cec9c364ef91dc08d300c80b903065f5755290000000000000000000000000000000000000000000000000000000000000080000000000000000000000000ac5b038058bcd0424c9c252c6487c25f032e5ddc0000000000000000000000000000000000000000000003fce4ee0d0a3114dfff00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000136f6e65496e6368563546656544796e616d6963000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000ac5b038058bcd0424c9c252c6487c25f032e5ddc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fce4ee0d0a3114dfff0000000000000000000000000000000000000000000000000175054bc1384109000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000035c251d8ca8a4000000000000000000000000f326e4de8f66a0bdc0970b79e0924e33c79f1915000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e80502b1c5000000000000000000000000ac5b038058bcd0424c9c252c6487c25f032e5ddc0000000000000000000000000000000000000000000003fce4ee0d0a3114dfff0000000000000000000000000000000000000000000000000178503ced89c7950000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000200000000000000003b6d03403802acec89594353c0cfafeb97b3368a1544edeec0000000000000003b6d034006da0fd433c1a5d7a4faa01111c044910a184553ab4991fe00000000000000000000000000000000000000000000000001e1c001a07df4ef996d2f377e92dbf974c93ba5d74f94542eb104dc18b88ff68fc8f3a38aa051944af075a6e0a09438dd4849ae54cd295cd863da47b470f39b37a43de82873", + "0x02f8b00153840237ddc9851363ec0bf782b71294761d38e5ddf6ccf6cf7c55759d5210750b5d60f380b844095ea7b3000000000000000000000000881d40237659c251811cec9c364ef91dc08d300cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a0d5fd4213ed6462f0020c5e17ac04d843b370c575cf30b998df33dfe1f1ac3b90a043e40f0efa5162262927d66562caf3ebf52eb5575b4da17d4840723696b241ea", + "0x02f903540154840237ddc9851363ec0bf78304d71b94881d40237659c251811cec9c364ef91dc08d300c80b902e65f5755290000000000000000000000000000000000000000000000000000000000000080000000000000000000000000761d38e5ddf6ccf6cf7c55759d5210750b5d60f300000000000000000000000000000000000000000684bb78722fdca33b5d149c00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000136f6e65496e6368563546656544796e616d6963000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000761d38e5ddf6ccf6cf7c55759d5210750b5d60f3000000000000000000000000b528edbef013aff855ac3c50b381f253af13b99700000000000000000000000000000000000000000684bb78722fdca33b5d149c00000000000000000000000000000000000000000000000c9df82cee9a43adef000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002acf35c9a3f4c5c3f4c78ef5fb64c3ee82f07c45000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c8e449022e00000000000000000000000000000000000000000684bb78722fdca33b5d149c00000000000000000000000000000000000000000000000c9df82cee9a43adee00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000381fe4eb128db1621647ca00965da3f9e09f4fac800000000000000000000000d1a47332acad7498af1efdba16158e11317eca4aab4991fe0000000000000000000000000000000000000000000000000121c001a0deddaecb2790f66ea83aaf2c329b4892f04fd90c0f3590986d9fe27946b5f000a02a67a210d147b633543787a213f370a2f7bf1c3b5ebdddbc2ab2b907f431fba7", + "0x02f8b1018186840237ddc98513becee03782b9e6949625ce7753ace1fa1865a47aae2c5c2ce441856980b844095ea7b3000000000000000000000000881d40237659c251811cec9c364ef91dc08d300cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a0bbd2417497a0a84e6021ac253cfb25b3877190ca4dd54ded96dfb2c54045294ea00a8ccb7e0717172be7fc98eb2ea9837125955c02dd7ea3bbf817cb08f5e9eb46", + "0x02f90355018187840237ddc98513becee03783035a6d94881d40237659c251811cec9c364ef91dc08d300c80b902e65f57552900000000000000000000000000000000000000000000000000000000000000800000000000000000000000009625ce7753ace1fa1865a47aae2c5c2ce44185690000000000000000000000000000000000000000000001175e20984c25dc799700000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000136f6e65496e6368563546656544796e616d69630000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000009625ce7753ace1fa1865a47aae2c5c2ce441856900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001175e20984c25dc799700000000000000000000000000000000000000000000000001fe184bad716b8e000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000049839213ec5fc000000000000000000000000f326e4de8f66a0bdc0970b79e0924e33c79f1915000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c80502b1c50000000000000000000000009625ce7753ace1fa1865a47aae2c5c2ce44185690000000000000000000000000000000000000000000001175e20984c25dc7997000000000000000000000000000000000000000000000000020298fe8b769e380000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000140000000000000003b6d034048200057593487b93311b03c845afda306a90e2aab4991fe00000000000000000000000000000000000000000000000000e6c080a059274d263200b58de64bd5b6b4e2870a5d31980fde9b7a609e243e607d46d12ba028ddc7178997f8f8b9bef8dee39edc73128e15f2e2f39f391794d3411b3444eb", + "0x02f90232013c8402321261850a7a3582008302208794af9ba9f9d7db062a119371ea923ed274e398116380b901c4d4dfd6bc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f2ad0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000041681f92e2672de5ccc985a0df77bfa70dc9724ac089e41aef7b1a6076b5811ea9518483a459ca5d247c3146c3505e053e3d690b9b6f22ca23eee349f4de123f871c00000000000000000000000000000000000000000000000000000000000000c001a0fb6c12ed3d1af23643dcd7c9a647aa22097674678e44fbea34b2b0a1149260b0a07486831acf77cfa39a2f60e3fb91cd16ca6dabc29848e1d4825b592d15578d15", + "0x02f8b101058402321261850f1740c9c7830176f794d1d2eb1b1e90b638588728b4130137d262c87cae80b844a9059cbb00000000000000000000000028c85b08a2454ef405b845e3d108baf5d8d6801f0000000000000000000000000000000000000000000000000000002540be4000c080a03fedc0abf2edd7ede2b85515ccb1ee771b508ab7379619f47dd3d33bc2e847d1a07297b706f5b35f8953d9ca97027432a0680e146f68a53baa6007177cc133205a", + "0x02f873012e8402321261850f87688ceb8252089463b6d51c562a9e2fb2650c28c05d27b11bbcae2288016345785d8a000080c080a0612dff6683243894502490cf89854b3caf33f00764aab02789e52cc26b5f430ba07b245fe3d7ace87946b836e244551e3d7d33a64b394bfcae5e0521596eaafc0c", + "0x02f8b2018204e98402321261850f1740c9c782b73494bf7bc9e63635dc11b335d52b0349d0100a53a1a780b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000000000000000000000000000000008d0a10c782e0c080a0eaf6bbaf2779a49ce771c0ed11563f5748230d2f0f47558be738e332f1100a28a045c11052b00a265c9bb02efdc66dfc858a908ef4d58fc628f8c0edc89687171b", + "0x02f87201198402321261850f1740c9c7825208949129fe4b97011d32b35281fe35c05d2fd36773e2875ffceeda38d67780c001a0d3676e754d5e0129f4fff2c026f22d183771abc22143fda675e0ecb960b765dda057674cbfe8a53020105b740243d675a240bd46da34de8453fec627420a735fed", + "0x02f87201328402321261850fae8bdf9a825208949664d678323cf4a682787ca7e9a2335e4730cdf687121acc68ebfb8c80c080a0e8e1a87d79920d8c2bbfd3e1f3a8911e715aa570ae8176e4a1c5b8ffbc8725b9a0093feabcff683bc7ede046b7eec213a9e1d63b850406126952df6b0024318b17", + "0x02f8b101628402321261850f1740c9c78301107a94dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000c66ea10b13d6d8de3fd2d76bbd3e180cb675d4e10000000000000000000000000000000000000000000000000000000253e6f6e0c001a0a5a4289bff6268cd720a5ed72b37259be39144f21a2f837b00c03ff0e1914fb5a04ba55a9752bd2bc6245641fe1718ca2bd0f5aa454a1b4537b849a30af9fc1dd5", + "0x02f896010e8402321261850f665f461d82b2789400000000000e1a99dddd5610111884278bdbda1d872386f26fc10000a4497ecfc5746172616e74756c333030330000000000000000000000000000000000000000c080a0aab15b74e697c021bdd41ab7c3349610f30e6caa18b378cd6d8232f1809ecd81a020c8c4d08051ba6b7ebbf59fb66d6a342db393f699a543d384d1a7e004669f71", + "0x02f903b201358402321261850f665f461d8301f10894c059a531b4234d05e9ef4ac51028f7e6156e2cce80b90344e1c8455d00000000000000000000000000000000000000000000007649553f44be58000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000764de477a6da2c66dd000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000122b9301f12211091b5c1439304c70ac05b9f731e4b92755e5b4dbb87d890840f857eff4b70c6b9355c6cbdaf703b95e55d08aadcfa2a9098881fb337310cfd4cd0a110fe6777b61957ad3dac33eb927038d72bd0cf174a4aa2b5175bf371b2c45fda40e189bb1d92070b809e2aebfb3ce647a7b9f1d20d2a42cf5d35d92c1dc91be3058238dba0224dc1aa0d2b878f84fbeb44c7efe01b4513c29e2fd111a22689b0552d665418aa10950d1af733f89963b93f7bb13d7e98a43ebbe27c267ced2693613bb2698a7faecf270600b396f443b8adcffb83e1c52220a4ff2936540187f9e8c9e3746eee08d3b0b785853ca6deade552f8c7047b088123db7d71c0c68bd8adae3ff0991e54e12f875737f233a101e9f9c432a35c29ca5f5e5406b973972753f61b1d1a1d53e57cb49ac4ba169ade3c9f832cfe9ca051e7ede3a33fd142a15c1ebb77497f2693f6d6f1c1a6ca12b7375776a1048963d8d68dbd8fff367b009585a7687772a860b48bb4c14475230a654fb77e00f0b892ec571cceab002616c23c7359f7394255e917c6f10afad171615c27142b5362c58c805e91554d5c99568fe3f7a990d0f00b2714b7105fecfa26db4a56489b71f088208342c09247751e549c0b5d29e5f473b4ce26846c3973dc05e90bae1daa1156eb69fb68c9d08a7d0a6af883df133f4dda40a2bf9d18ea6e9b3b90b30974c74803005be777e854f5656ba40bc7ae01e2b8cb95cffecd7cc1fa7a3a3e69fa5faf5d26f1771383bdd1e5318b1af41fa68346461d94bc4793ebd12fd81ce5d0b74b62d096838eac001a0fd3b957de505fb31d475834c4002bf2f7e30f3d0cde973d7190f63ab1265ce73a031aa05fe24c95420ad65d3646968a7c8ba10ed8c098a01053fd52d774defe80e", + "0x02f87201028402321261850f665f461d8252089484b2d08156c84c4b13e3bf2063ca67de2c4c134487dd2fe856e049a780c080a050eb5301a47738ac132057ff095d8faed6cb9851b6542458cd1ddfd3677f4e81a02e60ad73e18be1a79cd123f0786ee8678db91f54b1842e68a8dd65dae28c8159", + "0x02f878012a8402321261850f665f461d830181c0941f75881dc0707b5236f739b5b64a87c211294abb883782dace9d90000084d0e30db0c001a08ff2d140a8f881038cbaca7841060ae30b7a0287f8a67acbc13ce75cbe124eb5a0704a4495b1ee4bab7706891891975e8d1c3dd4c4cf1961f213264907298fce86", + "0x02f902fa01088402321261850f665f461d83033622943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad8802c68af0bb140000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2ac9f00000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000010be622fe2c756a700000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000f05897cfe3ce9bbbfe0751cbe6b1b2c686848dcbc001a0d135dc7244e37da9e1c2a04b15b14cc9eb737e9cbf71d2eef98bca360349eb99a07091c3c0e4a7b0f096a2bc27c2f91e520e3fc34ba7383f9a67e7016dde75cbde", + "0x02f8b30182048a8402321261850b2e2b96d4830186a094dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000092064b31442367f069493f51ed4d14e032d6bb9000000000000000000000000000000000000000000000000000000000200b200c001a0888c2a41170e984ba0fede837f2a07cfbb16d3cebfad4fb21e7da4a5375f4e8aa07c40d7fa2e7837f609ecefdcf29f364c8e27f1c934aef3ae662fc4eff1d8f190", + "0x02f901130182018f8402321261850f1740c9c7830184c8945954ab967bc958940b7eb73ee84797dc8a2afbb980b8a4381b46820000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000060bc000000000000000000000000000000000000000000000000000000000000665a000000000000000000000000000000000000000000000000000000000000080cc080a0d6e97ab62a9e2e044fc02ae5218db2757bf45897a1ee026cc303db9c1d8d09a0a05382552b59535ecd7bedc1e4da05aa24855f0776fcda86fa4e79e4493f4ad23e", + "0x02f8b1010d8402321261850f87688ceb830163db946982508145454ce325ddbe47a25d4ec3d231193380b844a9059cbb0000000000000000000000007727bb09f657285e725622dfac1fbbc4cc4d53d5000000000000000000000000000000000000000000958d7fe0d736a62fa70000c001a0f01b03a797aeb89befb1c7140e083b7cbeb4395ceba8189c1ce0f2afab48ce4ca011136de86153e7c87766c59d296f4cd6b7600f241f88718a0e21caa04f82a36a", + "0x02f8b001038402321261850f665f461d82b9e4948881562783028f5c1bcb985d2283d5e170d8888880b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a02c4f89ac1bbc03e4461cb9929bdf07b55eb85324e18d5d7a93ee51d227fb2ab6a071b2f31fe8281fe87d1548211bfe53ea7f78d70733209c298758af43aec406ff", + "0x02f9043201548402321261850f665f461d8306f60d943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b903c43593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2ac9f00000000000000000000000000000000000000000000000000000000000000020a080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000443459d45c30a03f90037d011cbe22e2183d3b12000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000661a375100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad0000000000000000000000000000000000000000000000000000000065f2b15900000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000418acf0eed453892c33c18956611fd7a453fe67a59c15fd5c282901aa18408b2490a64767efe3bc039078bd51e6523fc1b0a4c865573e251143aed0de81888d1d81b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000005347391d799baea63a00000000000000000000000000000000000000000000000000000000bfd3336d00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000443459d45c30a03f90037d011cbe22e2183d3b12000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7c001a0950ce9740b1731bc910d705f2f8d7ac4fda429b7d655b8b2a28f3fd35598806fa01ee72c60f665e808ea7abdf5689a53a2dd9f87ea32c7545d92cda728b0392064", + "0x02f9033201808402321261850f665f461d8301351f94d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef0000000000000000000000000000000000000000000000000000000000014b19000000000000000000000000a63226a58bc0a378345e1622d511fef821a59b0400000000000000000000000000000000000000000000000324e964b3eca800000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001194390f2af59eaddfeb83a00f3fb4cab380b45172291136b83fd65f440631df09c269d1e7bac8c3bad9dcdc53e93fb917005b8ba8460400614616102cb366e9d660a930137e79674b56407ec34603eb2de1de0f2e71ef4e14e10d136b0877205c134c47fccece94b8cb074c85e89f114ed00742cfdfb597fee4ce7df3a6fb3886c48cec8b35efcf717891800b365e63d0e671d78109237a781f2a68076e2f70b6f4248d05bbc39284bcdc74880596219f6339797f60b8a37b26bb551eb97061e5507ec8848681e807efebd3b96ba7eea42c9b927eee9bb1ab064bc16f92a6d1554766b12352d059d144d019d9874b20ed0bc28fe4d4840ab773e5f26bed046f701839fa2ea0726ec1e2ef4bc3a210984aba417da6ad2ba67cfcb41564cbe89b9a8c24af951808954788e3be16411bb7d2e53581e4e957bffaabdbe4677a74938c88903050e582f4a73ac9f7d26b7de55baa5fae65de19fbb7f810cd5caa79cdbbe9055d2b141476a1d8c3885d7bda017ec8dd69549650f4740cea4896f8452a6e09fbe6ad021b6bb92e73c49e57f4128f03b034b3919d0a71c72f6a584a153ae1591b25fbbf6e15798754c79aa53f46bb2c72ba25bd77457c639d37bf351fb0973817ee8a14f49b7efe1f8351d9e474eca711776c9d4b2f80a01e0889a1e8a3497dbbba44476a13c02cfed0b524896278c0bfc2ede44fcc65c1b9efe49e33a5ae340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec001a0f1a5877f11434609b67135e6df4fed2711197927b2f950d430f1f6133630317ca00fb410b65167655b67813c5f2fae1f0f0c638619df7c0dca84cea9ac249f5108", + "0x02f8b101068402321261850f665f461d83013157940581ddf7a136c6837429a46c6cb7b388a3e5297180b844a22cb4650000000000000000000000001e0049783f008a0085193e00003d00cd54003c710000000000000000000000000000000000000000000000000000000000000001c080a0f8a54ccda0ece2e5a204929251e1012df3edadc269518bdff0e7f7f4ca593249a016e81a85f7393e612d7da187e900eb91049de308c465ab3af66053df1a152b80", + "0x02f8b101038402321261850f665f461d830108179477e06c9eccf2e797fd462a92b6d7642ef85b0a4480b844095ea7b30000000000000000000000006131b5fae19ea4f9d964eac0408e4408b66337b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a084e06bf2909bb553f239c628069e6c20635360500dd4173d5028ebd6524ff83fa05e04527a3c783d15e137489a74cd4bf68b7913f13cf5b0743df3c68b01563040", + "0x02f901f201058402321261850f1740c9c783020f0394762340b8a40cdd5bfc3edd94265899fda345d0e380b9018423dc86580000000000000000000000001ee2019472703d22dbcac3145801fd514394045a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000f0ef0e6a1fd61f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000c080a0fa014677216ad9bcb693bab30b366a9c2f8ab1247b20f480c6da1afb0e32533aa051687ec70efb085d30d94cccbc8a9a45e6609e8718ad8e7b079edce0911936bf", + "0x02f8b101018402321261850f665f461d83012e8894b131f4a55907b10d1f0a50d8ab8fa09ec342cd7480b844a9059cbb0000000000000000000000009c036b0d0b39a0a411c0cd7df36211695103b65700000000000000000000000000000000000000000000008f4c4a17ac4a4fb00cc080a08d8c6c2c49aeae62f43940c12e58f5536ba7fbdc220c314ab497e75239bd678ba07c22d1c0bfe6d99cc349129d477f1964117e93f08a8cae3ae50d7bb02b849f11", + "0x02f9033201078402321261850f1740c9c78301352e94d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef0000000000000000000000000000000000000000000000000000000000013814000000000000000000000000eb661f50946347553a806e9aaee5bcfb9c8fc58300000000000000000000000000000000000000000000000cbd47b6eaa8cc000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000011b6b3ac0e6e42cf52b27202f6b03f9a3f2437bf5461304be35cc6b5ec4b21dfc0b4ed981b6908b70a43ff47851a37ca3257ac71c9dd8f38721784acf084bc62b7ea012460b205f5377bf2139e6804712c97f1dc6a360f19de92560c3e6d4971fb4a1de7b45fe51e2561b7410d9d3c068473cedaa81b54079e987ae664e6594ffb4fba75bbf5238ea11efdab4216f81103a5b4d2774dadabe17e661979086f6c38ce9e370619b475db925c715d75616759dc6bc50ab8e165d9ba012fe327063ae7e89d04777570f1d8d5f7d81cab855a0de5458fdb08350fb9c296bd4f24e1542f787c6412a2a82fc3a92835edb61bb023ce0f6c83fb7dcb9cecfb47183f58d30c8947ad445981bf9ed186485f714321853be4db42ce142369baa0790512b4e5ab9630148f919b4cb1785db3b6c3cc321a6c3e9167dcce46616075dcfb83a694c407ad21985c0a7b220c77ec1c4d2ba832cd5e2b80964ba4b60ced2b5967de3919578d7be013075f6f887937e87075ad37f49a82d0be743328564015ddc49e3faa3a2daa97f744d166ab5c9b170efc3e9fcf70d2dc968e4cba43ba29ed414753c8439869e225fee3df7bead8c9c011e7e36996bef45fc334cec3a7b3dd000cc2801845c13f25cbba3d726231691cc1678de0936fe89df8d408c9bc344d58d0ae0a46e70d0e09debcd1ba9ca8ff28fa3dcc7b1318cdac64c0b387c56304d964a2f86643f31da169680b58a8548f4d3144a13fdb0eb53a2844abdea2d4a0c76a82ddc080a0b0cb26b52bd73f1dfec7e0e428942e18fa7a7f9dd925b84c6e5d9add528b987ba06b1d2869e0ebe01dc7d0a4837a15c88cd2c9c130d5e6f1a45627f658d5c9a716", + "0x02f87301108402321261850f665f461d82520894fc1c0057ad6a3a645cccd87dfc720bc5cc1137d18803311fc80a57000080c001a0127ff81d34a94405b5521e4afba7f4ea406e9458640d10342364e6d254073696a05cf94fcd762510fb197cc9077483bd4b223d87265bbec688658a3bce0a072f56", + "0x02f8b20181888402321261850f665f461d83010ad694a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4880b844a9059cbb000000000000000000000000f860c6f05b8b4ec01713f7b633e449d7842fe8d600000000000000000000000000000000000000000000000000000009df3ca800c080a0faa297d6e8ed0deffa1c0ae96c6ac7677eccf6963a7fec95970904fe5fc305f9a00d24e3bcaf3b750b5491f5efe90d1d6a5cd8dd519fd8ef6608f6a257a1e4555e", + "0x02f8b20182015e8402321261850f665f461d82d477949caae40dcf950afea443119e51e821d6fe2437ca80b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000000000000000000000000068a021666bf7e80000c080a0c49ff78e1ba68873b04719c0f3fba1bd8066327297575c2776073660fca27639a033d9e60e2da790459e57e8d9379a14b396d18c130697cea37b1a73362a7abaa6", + "0x02f8b3018207788402321261850f665f461d83010ed994dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb0000000000000000000000000cafe46342839aebfe3c1681858a63e7e001d12400000000000000000000000000000000000000000000000000000000c7ee7f3dc001a046371ed81f873bfb11de0d4395f81d2eee06539c322d325f10d41904ad7dbef3a05bab90e3a2258871f3f5feb86c8c3fb15126b04b3be7afbde919f4dd1a74e4a5", + "0x02f903340182026b8402321261850fae8bdf9a8301352394d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef00000000000000000000000000000000000000000000000000000000000054d2000000000000000000000000360b74a47f58405bdecf33811b1f2ca37dc6632000000000000000000000000000000000000000000000001e3fce3b96dbf80000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000117643c34564ee65554b935216a2fceeb1f20a5fa2c7ba3e0ad43d12495b0f2c779da74ed53b314419f0ee67673bc7d7c69faeeb8e6e145a3bab84e18546ccf9c388a670d0a3dd378436388898006318c7b29cc7b32e8e4d21e53d12415b8036e5b19ca4dfb85c3d81a67894640d96d9d04c35c25f6c7f2f0d4617511af7341d8b0f89e3d06b6b60eabea0c10c26f6c2f0ae052eee97dc56979d10934d667254f8ce58e2dbe02ac61991b93dd27420057aa9a5b788d2e6b26980e5b99ed22d62ccffcad20cb3a231eb9207b9d5ee49f21e33cc9fc9b49f5298ef95210b73031edff1de20088c7d63878caf5894054b43cbe49f36c335e2197241558d0f9320257667aca37604c499f561893e445d902b7350939f1d1c88cd4b50f402be2109027d457494fb896986cfe3f181244b524cde7eeb2d276a549017e92ccd0ab84e8579f2eaacc6dba099e82f6f93ad3d883a6a716e2fa31b35e9bceb0facfb2cb0129d7945c56895971f627fe10741a146767da1ac6d8523026e96448b5ba6cf8b2622cff34b45f6af108a4107137de77c7f9c0b613280b7edc9e12445fe2d195f2fed4cf815d551368b549329d7b042ede0c28c494ad193986346b46361f9af93ae17715588c2b8020767b738ded790362d7cc47224f2cf2342d412a9bf1d274da0ce7dbbba44476a13c02cfed0b524896278c0bfc2ede44fcc65c1b9efe49e33a5ae340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec080a011ab8a91c7641ba407d70b75dd58cf4bdc6c93f53019e2aa831e270c81979d5da04637e3711453560bbd56160381a063fa4f003e11f85de2c0291c52fc9931c65f", + "0x02f902fa0181958402321261850f665f461d8302e771943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad872386f26fc10000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acb700000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000002fb15de259f41666d587900000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb86982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c001a0238952662913d078c6cc41f5c08a8ff28d7b9fbcb358bd419c882da293ae4fb6a062697ccd2dff92d0838a87f9a47000ee37c210fb12f0ce361706ed820459b624", + "0x02f902940182015e8402321261850fae8bdf9a83049f81943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b902243593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acb7000000000000000000000000000000000000000000000000000000000000000108000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000050d75868eb5367a808c00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009c7d4fb43919def524c1a9d92fe836169eaf0615c080a04b0829056df8d5a983429457be58ed9eafb0b5f8981135af1a046e703ec613fba024b45dcb081ad974933469c511b1b473a82f6492f182433ef647c219b0169d67", + "0x02f9033201148402321261850fae8bdf9a8301351694d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef0000000000000000000000000000000000000000000000000000000000004c340000000000000000000000003080feedb94968cff5d729fb55b45c247ea0c2d300000000000000000000000000000000000000000000000324e964b3eca8000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000011195b88203e4a838c3fb718e9c2cc16171d7b93cbfdcad09802188cf5acb2e8df6dd3e179fd476ca82414a6fb0402eb7e932871ff012e5acfe1682f6b1499ae29c1a734e4ba86efb452dbe3461e05c012708c648e33ff37cb9089d1ab8d0e3be68f6282c330423e1ef0039c384b96852eec776f20e32e2d7b5115e12ad6d06aa3ff426b08be3f4f00af57a3395f9e053a61b393ab060171dec92875c40efef1eb724ccbe9c6841f384292df597a050035e18db429f9bbcad88e66cbc50826d518f68208432406e8a3bc5214b9512a2879b0509efce80e9418149c93824ba5e089764d0168ff19e33702a6db13ccdab0faaeb78f06b164ba03733d50d19673b03baf510202f9fb2fa0341e20fbcccda0dd2c451ea8e8075ccaeed299da743b0d8478230e05e4cc67202d1fb5ed9cabbf75fb682fc5691e856a992e862676316e7505957b9a137898a6e3540b9ce378d86f6bf7bd68b963cb8eb6dc40a3941024ab4e0d0d831d1cd2d01aa888afbc977b387fefa75dd096c01e5a0e8090fce0f5085ef2cb32893e0a26c5d7f075f7ffa6f7fe9ea3258030ca715d74316c694bac6e9407c090febb3a91a6e3f839b6a54c1bcfcfc56dfba4d0ca8a3535168fa5b3b0866b8614da6d5761eba4253b79baf01b17cf793a6056a1204b3457acc3cc6264b2f1729c555dd226f68ac9786871adb4125748b57f44524ee6f108c017fa8db8340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec080a0a5b9c63ba5e1623e80d1e7ae86eb0e7e5fc524562675cc605bc457e71c257a81a03136b1acd168a591260c63c5978d2bcb8c57e25f9155ac3d6a970f17eacd5f93", + "0x02f8b901018402321261850fae8bdf9a83045f7f94d5ef0650ac086c630040981b604a0da99db03a8d8802c68af0bb140000b8442c65169e00000000000000000000000000000000000000000000000000000000000003530000000000000000000000000000000000000000000000000000000000000000c001a0365520ff5101529d569acb144a236b6a38a78e8fe965cd519ce0cf27eff2a1fea04882d68d6a99ca87973c6e964e4124eba2178f3790d1e3fefe97e43f2298ca03", + "0x02f87301048402321261850fae8bdf9a825208949508050753dc8290f0ee277b4fa4a6f6ef4a21ab880640b1c362f9253680c001a0eb00cad830ec22a2c8a0a31b15d2ea7464941fea00ab79aaa6870f9dbfaa18a5a01560f042fb9119ad01f0c43afaae30a4dc4618523e04064240f068f9821df739", + "0x02f8b001438402321261850fae8bdf9a82b5fe940ab87046fbb341d058f17cbc4c1133f25a20a52f80b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000000000000000000000000000000054f7866df32245c080a0778a20e2115ae2a7eac6c0de139fa6becb66b25dcc2592d3cd6d9355850e79d2a02f7a10195e35556da897c41fedbda5f9e414536c7edca6f7e4f567cb1d50e5a1", + "0x02f872010b8402321261850f665f461d8252089463c138ab7ae4e23838e144bbe30b1e57c1fb13b787354a6ba7a1800080c080a04f5ee5b0dd901bb31c48d8cc04e8d007f0ce2638338d30ef77df5969b0ee6d44a0422780cb971372138b8e98f841bf86081279726a0aba9ee6d0944a6e57fcf619", + "0x02f8b101048402321261850fae8bdf9a83012e8894b131f4a55907b10d1f0a50d8ab8fa09ec342cd7480b844a9059cbb000000000000000000000000d539cbbc9b94ed0aa45ec11e8899ebecc4c3775100000000000000000000000000000000000000000000008df0a9582533a3062ac001a0446fd470dd2c2026ce8aad395e47ce5440816dd65beb06c325fca6dec73e10e6a032aaaa2f4091277f3b0250ab91868cf5cfc21cfafc3475542212c7297223b895", + "0x02f87201458402321261850f665f461d825208947035779ecce3e39c8a2d9b93e56c455f9d374a6a871aa535d3d0c00080c001a0fc5fa7e99a4312edfefcd871bbd93ed8f5764fb8eee2528209ec1ba2c071d163a02ee13da09ee628e447e7069891355a29cd038565909307eeb001b48dfe0ebd64", + "0x02f87301138402321261850f665f461d82520894740b03827195bc8514794228e198553d05da958388010bbda1790ca00080c080a019ad73040edff4b600feb890f422b67ec8c85d6b8a20688eb79d894a3ff41daba0427f80bfab9117fe63fde57cda3ccc006db04feff7f2ccc375a28ed4b9509e0a", + "0x02f902fa01078402321261850f665f461d83033913943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad88013fbe85edc90000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acab00000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000013fbe85edc9000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000013fbe85edc90000000000000000000000000000000000000000000000000019875e1fc7e1612a2400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000040e9187078032afe1a30cfcf76e4fe3d7ab5c6c5c080a0a55c8c8017fb1c975aa1b70377a47a6a5f9fa6c89592a46ff4abf56f7c15881ea071390df75d19121e064ff54aa7a4273a28571351cb087bee86e8a8aaffdc8300", + "0x02f9011901808402321261850fae8bdf9a83061bf794daf1695c41327b61b9b9965ac6a5843a3198cf07880e05113270345b6db8a48b886bf20000000000000000000000000000000000000000000000000e043da61725000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000d38c590f5b6d0000000000000000000000000000000000000000000000000000000000000014fe80d2652aa4ca20af5d837942e8914ef0cfb4e3000000000000000000000000c080a0760619a801b84b6895b003ef6ba2297c57fa99ae12ed38ac693d5c706913116ea030884a4619c877166355130809ca2389ff434e44bbfa602091535d181104fd27", + "0x02f8770181868402321261850f665f461d82b16a94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2877c58508723800084d0e30db0c001a08a7489c7a293d32745bef66a0520f35b8bd4e3163e65f8178d1ba90430cbfb64a0455b4911858d8c37b35a02bb38d307f2ba552a5340dd909bd353d847c5ad932c", + "0x02f87301078402321261850f1740c9c7825208943215cbe32ea8ed8b814020d37679a1f3c1556a3d880de0b6b3a764000080c001a07f7583133d837914da04ad9ef2061992dd3e8be6d185e5c285872d4f4746b265a07716f7d4db4b8131bc9fda79c8cdaa7fffb5279158b7efc76d642c899cf709a6", + "0x02f902fa01808402321261850fae8bdf9a8302d7f3943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad880214e8348c4f0000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acab00000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000214e8348c4f0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000214e8348c4f00000000000000000000000000000000000000000000009fbb4a25ab41e66571749d00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006e1649cef61fa17d647b9324d905c33fea71d020c080a0cddfcf6fe79417317dc0211e40f9ff1c3330f5b71035e6ec37a95b87d361abe1a00c369af641631aaee98f57f0ff8ad8788c608eafb962c20ac931c2f426bef1fd", + "0x02f8b1010a8402321261850e39ef311283010c1d94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4880b844a9059cbb000000000000000000000000aa6f6b7cf8933c693d4f6db5ae1cc09ba46f040e00000000000000000000000000000000000000000000000000000000e1e56addc001a0d3506d0ae42af70ad1980d0427c536576d577c9178399ef129214ab5cbfa489ca0486c96e76a64be007467182af020afe697c31c8f38c00eccbf95607f28b5563b", + "0x02f8b001018402321261850fae8bdf9a82c95794b131f4a55907b10d1f0a50d8ab8fa09ec342cd7480b844a9059cbb000000000000000000000000bdacd9db71c5d6693c459999011a42ef2338b9a70000000000000000000000000000000000000000000000821a476ac5f4ebdbcec080a0d62805f6da63d7748d6bf6580759260b0547e4b4f534d4b3bc9a0095afda522fa0488c353d4585e031f930c0f6d3b7b59b5a864298eca842d97bc1d540a463736a", + "0x02f87201188402321261850fae8bdf9a8252089441b4340518e7cf5c3b1c8aaa3cf12eb30f55ae3c8731406966e33d5980c080a04aa7eb08cee25ced72d3671b4ee325baf481425e8b4cd8ea6d6bef667bed825ea00e43cd2d919503b5cac05529d0e71d67bc4863ba4754d1a907876c74aab8b24d", + "0x02f87201268402321261850fae8bdf9a8252089417eb0db3ff2833bb8378ba07c2181182e043942f87581b77f66e000080c001a009c0527ea340cb11878b4a5131a382a7ed709102fac5ba1d7c71d593334d4831a02710b1644acfaa2d0d4c61220ea69b66545e0631a21fb1f7703331faba61e846", + "0x02f8af01548402321261850f665f461d82d5e8940fa0ed0cbe0412379cd181320c93448968c76c1c80b844095ea7b30000000000000000000000001111111254eeb25477b68fb85ed929f73a960582ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a0bbeaed1d2b16360bf416147f0c48880145f7c5b0047f62308e64b1bfb766d81b9fbbd0da1aae8d6ffa9bec0cc9996bee8ad52df23a3d5d5e9bbb7ea74d0ddb2a", + "0x02f872014a8402321261850fae8bdf9a82520894cdb464940593849637aeaef6dcee5bf84870e9ef8758d15e1762800080c080a0df64057ec01746587788e568dd88b08b359021909560a1c644af381d6e954321a0026f09f973356426576b3d1478b366b2ba2db214efc5948d890bf6ba6f8a728c", + "0x02f890012b8402321261850fae8bdf9a83012dfe94ddcf9101a653053caabb692de87e1f13396be09280a45926651d0000000000000000000000006521a22e4412450924294f8a46693ef4c7832bf8c080a0c4ca739952648435b50647e81ebe61150a130e8f1fdb8d7a862a9c1a14fa5e33a03eb3f4c186199c85874b4e770988b50574a5894597d833da03878469094b2a67", + "0x02f903b201098402321261850fae8bdf9a8301f0ee94c059a531b4234d05e9ef4ac51028f7e6156e2cce80b90344e1c8455d0000000000000000000000000000000000000000000000a6db469844dd54000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000a6db5cde0771dcf5b400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000012cdd74b9d5714df3629f3fcd00641d8d316e40279bc811e185f456a7808d155e36e52c93b17649808499dca6e9e56eef3a9683b8d153b8133f1dae24848d5aed7cdb2691f7d62ada7d47dce8a1f5ce763919ea139a6d50bb38767f4b00d9ff0c73cfc26e4af3c94e82c9393007e1dfc8a612143a7f63aab14622c2ea2248870d07f8ac339415f28673e70d865819abce96771946d9fd402d66c3a9dca92e7ac442e51f21b9ed332a971e452b7f4cc3e3572dacf58ef25d7691ddc797791c5379da7882dd925b43f381e0c13236402659c1496eb56a743375a3e46e7c84cfa25bbe0e4eb21c8aec1ea433c4435ddaed13c853e8fcb78ee48463b9b609cceea517dc2e6d92165ef7efc5f930d1d027d54b76a415d792516da7972a240898f2aa05cc7287899fa7801130a5cfe51000b39fc6274ec55e225c31b7bedf517a7853d95ce6f2dbb05e6f0f7c08b1309f9a611c1a4b497f62c72b491cb136b69985104c83a63eb04969561d7c36aef460924d0218bd47aab003dcfcb9f518e80f9eae339203ec2b486c6acd2e21b0bb2702207d3a21b35d4fb613114ee252ad6a97c953d7d39df87016ace7efeb8480eadf4df45f07bfeb149c2ccb6b25acbe0ca7ee734df4398f883c3ec5f9daa4a132dfa3bf9e0aa65c2fb4fefade4e7b7ba796d20dcaa9c4e09daa1573e7616f99d98baeb8da41b5022cae119a423c520f47a9a9f35dce35d50a6905ba18322eb5c4416a44e1e083d961e1e3f483dceeddb7251b8e8fbc617f85f57eb6ae6a910db84ffd7eea166608f0587b82a0d02fa84ac8abd81c080a0aced45c5a93c26c891be8df1ff0a9a48304722009579db27ccb96006d31e8629a04ada4f98c7048a3af2df6ef759c86ad77a1489f5703e8de8cb3924c3d6881519", + "0x02f90334011d8402321261850fae8bdf9a83038e3594881d40237659c251811cec9c364ef91dc08d300c80b902c65f57552900000000000000000000000000000000000000000000000000000000000000800000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c59900000000000000000000000000000000000000000000000000000000001a93c600000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000136f6e65496e6368563546656544796e616d69630000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000001a583e0000000000000000000000000000000000000000000000000000000049ce731d00000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000003b880000000000000000000000002acf35c9a3f4c5c3f4c78ef5fb64c3ee82f07c45000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8e449022e00000000000000000000000000000000000000000000000000000000001a583e0000000000000000000000000000000000000000000000000000000049ce731c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000009a772018fbd77fcd2d25657e5c547baff3fd7d16ab4991fe00000000000000000000000000000000000000000000000000dbc080a0052aa2e2c98da00b5eb229fd856fe757a30e3343c88ab8f41dcf8092e0eb523fa066445249fd428f61e36a064bb5661f8d71e8e0e28ecbfbb16648d5f776d526a6", + "0x02f8b10181dc8402321261850fae8bdf9a82b56294c02aaa39b223fe8d0a0e5c4f27ead9083c756cc280b844095ea7b3000000000000000000000000367e59b559283c8506207d75b0c5d8c66c4cd4b7000000000000000000000000000000000000000000000000002e2f6e5e148000c001a0809603385b6eff734fbcedeece19358442c2140fe8f7f927db0626e2ad29116fa0505d09de9e5a2f1ae0e5740a0b518c47278abb398e2726bd47fcb47bc6edaefc", + "0x02f902fa01088402321261850e39ef311283034cf2943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad8804463c5e3ed20000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acc300000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000004463c5e3ed200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000004463c5e3ed20000000000000000000000000000000000000000000000000049eb04a6aa2488eb2d00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d584a1edb3a70b3b07963f9a3ea5399e38b136c080a01f3c164efc72911c467fa444708a983edb6753bc1c2f38944a8e21f033e2b724a06da500c1a4f8eb0d601dfe4ed057dd0b01932e630b2e8ab97f13b54c8bb80030", + "0x02f87301168402321261850fae8bdf9a8252089494e23ef804909b4c85d90489aaada343bafb93b488017508f1956a800080c001a0a581e17beea46b95ce6d4d415e864bce39a63580817e83dc6c1ecb7229301003a01de35e5fd95f86fa37bcd2d79d29ea1ec2e0a24056aea2aacf91d1b2bd203767", + "0x02f9033201138402321261850fae8bdf9a8301350b94d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef0000000000000000000000000000000000000000000000000000000000009e8a00000000000000000000000064f8f38c4e39db50f76809acbf946bd6768818a6000000000000000000000000000000000000000000000007ea2832757708000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000011459ea156e342e9957607f69e5470ecc5750e233afdba5d26c09030180b09da68603d47bb83621572e33c6844d33c22ac6d9aee8d5e1df7aef7e9bb1d46f865af97e740e3096213cb9ac6046ac8c61367d74cae92196249bed25bf9dab3b14e812c67d0a792097b6b04157c69853966a55f7647ba08909f37952cf89bb3b2dd128f74a429e5306e7995f593c421da51e04d4bd0ec06844152144a84829b95b13d2a959f83fe00fb9fcdbcee3830f1eb3b4fc0577e442970ffe4242501f6e072bff5a862cff38ae60778ae4b561ed9a3fc4fdaa2d3424198a3ef80e5f8c2836211b1f9d7d013ded25f0395e37a937d83965dd2b8db715805cad78958f053f40900abc2decfd6081a33a7a8e2e1836f94ef10a167146f67afa9b85d8daa37aa36ba4870774461ab6eadbafd2c2abdb849249ccd5af4144df5443ebf2dfd342e553f789a8a5986783c101f8ef7e11a253d87a07ed759ef2f71e05bbfe394f43e68284e9248e641ac65ef0d5fdb167961f5e76aa1d90d2eb49580b5470dafb3019a3cd786957bb72b9c8b91cdd7cdd256f1f7a3c401d12ee4f26e629afc69ffb97c8ee4df041f6d001a4c29f64bcb7dc7037b295e66ea154b33e6058d3ef6551f90fc7391105bbfc6265234e9cebeffa9b2e702d2341a1364e88c56b2fde302cbd6fdb2f1729c555dd226f68ac9786871adb4125748b57f44524ee6f108c017fa8db8340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec001a0c99925d1128e1289f412238946c5b481ab27e59fe9b07d81dec02a78270c493da0572e4d32df8e4524232dc684686367909abd423091dc0783e1792daaeeb23e27", + "0x02f8da018203518402321261850e39ef31128303f0369445e563c39cddba8699a90078f42353a57509543a87023ce4e8c9728db8642556e453000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000010c97e6672ea772e6417b8cf679f4751f4006a80000000000000000000000000000000000000000000000000000007ff2fb10a2c080a0800719cd161e4acc2fc714942f46e0f45974d107a20609a69403bb44e8e4432ba05d41cc8ca167f8f5b3e6ed3907026ce84be5b384c0fe17df1e234f300f5f9644", + "0x02f87201018402321261850fae8bdf9a8252089440d6bb06eaaf0bd7515b484990874d74c9f7f1ea8703468b8360cd4880c001a0591cc2128d0b836f61ce7ad5591243f23aed0bbb644346ab3cf0faa5b6e81847a06faa75e33018613337c391be9ba715dfdd4bc8edd84689f50086978b467d417e", + "0x02f902f201588402321261850fae8bdf9a8302d102943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2af1b0000000000000000000000000000000000000000000000000000000000000002000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000bc437a25d298be5d000000000000000000000000000000000000000000000000d92dc384510bb70500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002b7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000064c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000d92dc384510bb705c080a0d5b0f49bd4594272a90dc96fc681c68dbb3aa2790bf00bb94a66b32ec9a72e4ca007b2aa900824a87c39aeb6de0952886529208513d69dda2aef071c023145efa2", + "0x02f8b001218402321261850e39ef311282b8f3947865ec47bef9823ad0010c4970ed90a5e8107e5380b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000000000000000000000000009a2c7453e23bfcbcf5ac080a0cec872d692a946f01c84c45013b8f29b1b43c0e73cc67d6e4c7545b013955b36a00845f954b1e99117e79d15325fad9352c5a35f71f2aa51f8508c6b0fb071eb94", + "0x02f8b20181e88402321261850fae8bdf9a83034129941fde0d2f44539789256d94d1784a86bf77d66dd080b844e2bbb1580000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c5949f4826178dc0c001a019e33ac01e4b6135deec9db4707428e16e9dfc9512061c923fde0f7ce836449da032a26b7be24065311f39efceadde5b10eeff49a4e9dbf78ae9395a095899576c", + "0x02f902fb01820bea8402321261850e39ef311283024cc3943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad881bc16d674ec80000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acc300000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001bc16d674ec80000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000025381c2ccdc3c8eab7b6f590600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001ce270557c1f68cfb577b856766310bf8b47fd9cc001a04a470a8d5731aa8dbf3097cea4a6dcd9c2bffc97b29d0b39892709a5b95ce2e49f1c17299853f33cf2bf3554b6b51bdd22eb18c1df6d22e393a639bd943db58b", + "0x02f8b101018402321261850e39ef311283012e7694b131f4a55907b10d1f0a50d8ab8fa09ec342cd7480b844a9059cbb000000000000000000000000019f57fe47ee03764ec59e62512bde462bcbfb9300000000000000000000000000000000000000000000009ebb79bcfd6b808000c001a02c310cc3f06fc46e1b5dd7353bf6ee48f4766d1bdcda2e321807dd654aadd55fa020cce70e17f0b0195a71428854d13f44f6934955a6171bb120af149c5a2f168f", + "0x02f87201688402321261850fae8bdf9a82520894b5046b48d661d23262f00192c802dee3b167d4618710d807fba35dbc80c001a00afbb3c2fe4aeaa879871d537868ea6ea70ba36b0dd072eb1edfccf79316bf28a05cec9fac287501cc4bff0b9e7e07850647222d7be48f4cc46c397abab0bdcf7d", + "0x02f8710181d38402321261850ba43b7400830747ed949e87a268d42b0aba399c121428fce2c626ea01ff8084f9fc0d07c001a07544666461b880044a9fc37bbc7881c9a0a52ddb441aa751b5b612fe9fdfe8d0a05aa76d304d32185eb7b639d8ce415533da40d666c5734366c58803dd024ffd30", + "0x02f8b101038402321261850f665f461d8301771c94dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb0000000000000000000000003e62edf533e5e24d759500a181d1a91358b91f0d00000000000000000000000000000000000000000000000000000000b2d05e00c001a01c7616624043c0604cb53f6e7e92afac9951bb2a8ec76b588b473b5c8cd41845a07c37c73160dcdd4aab110ad23a5cb635599ded0b788bbae64acd8a0cd8286726", + "0x02f8b101048402321261850e39ef311283012e8894b131f4a55907b10d1f0a50d8ab8fa09ec342cd7480b844a9059cbb00000000000000000000000080aef925cdacbdc872c86767e2127876f135603400000000000000000000000000000000000000000000008df2be4059bff2062ac001a07870f8bda58efb84836fbdd5ee18243dc6b490b0e62dc18421b002b4fa4ef060a0386f94ec97920be5c6973f9610af782ddaa582d159505bd5b0f8d83749a44792", + "0x02f87201018402321261850f665f461d82520894520d450e6888eccd6feab7ff7e0877f848a88b5c878686273f1dec0080c080a0643531f92d8b90845906b743483541a3f2ee552eb07fad8540b32f5d5c21425ea0405d0110a52158aa742e7bd30c57688c5e771e95021537ecfa14005287748dd6", + "0x02f8b3018201458402321261850fae8bdf9a83011340944c9edd5852cd905f086c759e8383e09bff1e68b380b844095ea7b30000000000000000000000008707f238936c12c309bfc2b9959c35828acfc512ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a0dff9745d53eb7ba30969d879635db561f9e1de02187bda51e8fbbdc52ba82c4aa0598533e3de1be5bdf61f20031991708a7329c58d8dcd5a2ba8883706b604e34c", + "0x02f902fc018201ae8402321261850fae8bdf9a8303a887943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad88018de76816d80000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acc300000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000018de76816d8000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000018de76816d8000000000000000000000000000000000000000000000000000000000126fc0ec1a300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000055a8f6c6b3aa58ad6d1f26f6afeded78f32e19f4c001a0e9c37333cc67dc844f0c0d9601858a218a4ea7a88031bddd9d8825b53b57f7c0a054800436e1d309c9e0e24af54e760cbaeac078e7cc828f6f3841671a3b918116", + "0x02f8b001428402321261850f1740c9c782dc2994a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4880b844095ea7b300000000000000000000000002950460e2b9529d0e00284a5fa2d7bdf3fa4d7200000000000000000000000000000000000000000000000000000004a817c800c080a0ecd1ef10f6a488aa9e47a55ca4b386617aeb0f05b132504cceadf93cbadaf782a0682ea66910c9794b9cc5ba164bc82244513e767a5448c3a3e479490e07faee29", + "0x02f8b101808402321261850f665f461d8301312b94d9016a907dc0ecfa3ca425ab20b6b785b42f237380b844a9059cbb00000000000000000000000090512978adfae4214f93cf1fd9a2f8cbeb787d48000000000000000000000000000000000000000000001503c1c8c53e5e3c0000c001a00b75bf0fee9f057d9238c9cfeb683b35064d390751ef2893260ebcce73167662a05da2a183650767de2471f7e82682bcc6b0d022a8a73432b8d6d195d8a68ac75e", + "0x02f909fb01819a8402321261850e39ef31128301d8c49400000000000000adc04c56bf30ac9d3c0aaf14dc80b9098cfd9f1e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000004c0000000000000000000000000070effa80cdcef37d51bdf4d21687aea75a0197b000000000000000000000000004c00500000ad104d7dbd00e3ae0a5c00560c000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065f01a44000000000000000000000000000000000000000000000000000000006613dbdc0000000000000000000000000000000000000000000000000000000000000000360c6ebe0000000000000000000000000000000000000000bf53845b1aac54050000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a7d8d9ef8d8ce8992df33d8b8cf4aebabd5bd27000000000000000000000000000000000000000000000000000000000002dc743000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000019faae14eb88000000000000000000000000000000000000000000000000000019faae14eb88000000000000000000000000000070effa80cdcef37d51bdf4d21687aea75a0197b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b8bdb97852000000000000000000000000000000000000000000000000000000b8bdb978520000000000000000000000000000000a26b00c1f0df003000390027140000faa7190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022a392c68f60000000000000000000000000000000000000000000000000000022a392c68f60000000000000000000000000006c093fe8bc59e1e0cae2ec10f0b717d3d182056b000000000000000000000000070effa80cdcef37d51bdf4d21687aea75a0197b000000000000000000000000004c00500000ad104d7dbd00e3ae0a5c00560c000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065eb0b6c000000000000000000000000000000000000000000000000000000006613dbdc0000000000000000000000000000000000000000000000000000000000000000360c6ebe0000000000000000000000000000000000000000ae0ac953653ac3130000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a7d8d9ef8d8ce8992df33d8b8cf4aebabd5bd27000000000000000000000000000000000000000000000000000000000002dc743000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045f1ad4c03f8000000000000000000000000000000000000000000000000000045f1ad4c03f8000000000000000000000000000070effa80cdcef37d51bdf4d21687aea75a0197b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f161421c8e000000000000000000000000000000000000000000000000000001f161421c8e0000000000000000000000000000000a26b00c1f0df003000390027140000faa719000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005d423c655aa000000000000000000000000000000000000000000000000000005d423c655aa0000000000000000000000000006c093fe8bc59e1e0cae2ec10f0b717d3d182056b00000000360c6ebec080a0f914337603ed396f49309eb469913d540bf8b219865b54d9f0bd6fca858dc4f8a059cbfa1bbfab5e2a64c869035ba9bb9ed4b38c65c8e9d56729b2b887da0848d8", + "0x02f902fc0182011a8402321261850fae8bdf9a8303850f943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad88089aaeb710be0000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acb700000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000089aaeb710be000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000089aaeb710be00000000000000000000000000000000000000000000000000021fd8d54c8a1a6aa900000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000092f419fb7a750aed295b0ddf536276bf5a40124fc080a02ca1283699af78c33a3495a916e6d2c80952a207d5b6b1926680c8189db422f1a075019e52fd77798dbf46645ec64a3ab0cc7a210d1b2af04b9a01a249f3a46cbc", + "0x02f9033201038402321261850e39ef31128301353194d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef00000000000000000000000000000000000000000000000000000000000187ed000000000000000000000000f4911146e6cdcc96ae815b56b8388298c537738200000000000000000000000000000000000000000000000657b3801b80b400000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001142bbdf020b113cf51b28f72251e1b3e56af83da9c0048420be1c2270b1ab3c46e509b711b43f1232760657f7251da5ecd0179d570b573da53980346917fc49c3ec343469e6cf9e24d3051c5a6c4984530ee0c901aeb1cdcbeb4253532843b95dce9231699f13e37785baf293bcb31782e86a18d029eb3b38f04786be62c1c32c403345924a187b9a26fd82a08b0bf266f98a6fd9911e5da8b1dd0b16ce1df0ea8468f44289d07a72c1c4f870094d10788d0fc84d8ea6a967cf0b7f61d4ce72aab9b8aac9c5cccb7e2808a1e689ec061ef63333593533be416dfaaf74b9f90c5aa83c6ff7ba48fb889e7d24d2a36f49754e03788b8b36c31706f71e2db2d2235e2c6d99045e917b4d3dda6d9e293b307ae53327b1820a3cf8a0c67605a5f289a2928682849565f421514661d8715330ad1a241928bf8d83523495ec2c4ebcc795a631ddd37b735aee465dea76255e51aea695a97df82ec9785ffb0435d4c45ef64e9248e641ac65ef0d5fdb167961f5e76aa1d90d2eb49580b5470dafb3019a3cd786957bb72b9c8b91cdd7cdd256f1f7a3c401d12ee4f26e629afc69ffb97c8ee4df041f6d001a4c29f64bcb7dc7037b295e66ea154b33e6058d3ef6551f90fc7391105bbfc6265234e9cebeffa9b2e702d2341a1364e88c56b2fde302cbd6fdb2f1729c555dd226f68ac9786871adb4125748b57f44524ee6f108c017fa8db8340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec080a06f23a1578049eb8f39cee2f5e7ab89755d486ca0f2bb392985845e4c4cf50de5a005c159f86dd33eb5fbbc258a91909e2c5a367d5a0838c8c05df21c0dd56ebdc6", + "0x02f90414018202ab8402321261850fae8bdf9a83039e7d943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b903a43593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2acb700000000000000000000000000000000000000000000000000000000000000020a080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000661a376900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad0000000000000000000000000000000000000000000000000000000065f2b17100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000417ffcaddf095b0303ee401928a659fc673ce89f80aeeef0cc0c940335de8bc5f05c9e9888d3f054c1662a4a4504bdbd088d49d4b4e56f7f5b9a7c124e4e8e26401b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000002ee250abdfbfc88c000000000000000000000000000000000000000000006362d1c07eb49eb6f68000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000007e128e823d2b9b22edbda43820aa1a72de99613c001a00aa1cfdd24173f8776d9857822e57c41b9f134bc674988e8f15f8d52d93b16bda00d033b3fb17d3278c05148bec2223404932e8a662d6b969a4b0ce78dff568c62", + "0x02f87201078402321261850fae8bdf9a825208948f9a34c5655d655e0c72cc2ac2baff6237ec9eae8732f2c07088bd1a80c001a0716bf0fb605692dccf06dad462b78f51e4259d49af321ea21642482da596eb15a075df8c5132be45ef1575c56959f8b660204b79a5654044a8351a1059d1af2acf", + "0x02f87301808402321261850fae8bdf9a82520894adb6505de4bf5f7e87aa54eb1586518f81ca0bc88806f05b59d3b2000080c080a03feaceae0bc6a141cedcac08f607562e6614693e2102f97b4273b0233947245fa0020fc611bd8310bd2caf5af4aee7be7fae83e67d82f8c643614748e162837486", + "0x02f8b101378402321261850e39ef311283012d7a94b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb0000000000000000000000006559ed7d1e4c8eadd407b99743a04041b947f3ea000000000000000000000000000000000000000000000014b550a013c7380000c080a0a6fda06cb1ad38960010baaa8e7c4e96991887ec17dd57c044e98bb1d72d15f6a03a93c21f8104f447a94373429ecfcd0328ee4c5c40502a07189f6daeefdc89a2", + "0x02f9033201808402321261850fae8bdf9a8301352194d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef0000000000000000000000000000000000000000000000000000000000015e12000000000000000000000000bdca2d6d76fa87f07da633bed8aa5cd99f54147300000000000000000000000000000000000000000000000324e964b3eca800000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001174faf49ba37521b6299a3e122ffd0c10f1cb000b089bf1f3ca1d896634420e0691d721072dba71ae5aa4ab9ce65c43ac04be3884f2c58e67935e85d27afb9af6cec04ef55922a0b77226360667129b02d0aa526ebe84b4eec5065ac6a7a333f33e55412762011e4b76339829004ad810d11c3abf195f033ca723d9f1afe020a7fe6742148d063a197db588ffe6f1f98308511193cd1250041921bd29c43642a873e2796b2e2b2b4c199648bd88333d05da6d9d31e581323c5dc91984bb2578edc41d6274dc9d1831cc5d28ffca4132232e3943c7bddc8c466177e72e1f1340f9b46b02646e19bdf59d0d52c54d4c615453fc49575b3bafb7fe2c766e53f30e960306f3f0072da85007681ae3604fed525fb716fb74c09dd3a161c5d5338a15a5514fe5f0afdadb1a2e80520463204153130876ae643e71ddfc06db3fc9fc8c03ba74cd8b2f9eccd6cba6389f38e034aeca7d8689cb1654506a5098b9022733994e77e2b564c62994d516b9cd40d483a9f948b20974ee4745b46f8c6eeaa31b67cff34b45f6af108a4107137de77c7f9c0b613280b7edc9e12445fe2d195f2fed4cf815d551368b549329d7b042ede0c28c494ad193986346b46361f9af93ae17715588c2b8020767b738ded790362d7cc47224f2cf2342d412a9bf1d274da0ce7dbbba44476a13c02cfed0b524896278c0bfc2ede44fcc65c1b9efe49e33a5ae340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec080a0faa5d5268e85876488a433c7ca598406ea6290ca654ec1ab81f940d92c7d4cb2a01d57b38c084d14169ddfaccd7aa759cada15caac60636d439c5b9b5a54477f55", + "0x02f8b10112840220b02a850ef8b4cd3b830131f4947d29a64504629172a429e64183d6673b9dacbfce80b844a9059cbb0000000000000000000000002451b9dcf9b1279f560a9f586899c8e6c2d0d91c000000000000000000000000000000000000000000000002f6d89368268eaacac080a00d764ca9ae21e18e30e5fbe5f8dcf3a29de9878fbbf07afaf857c695e88cd148a02456f3d685688211923cb9c212ebd4a83b6af84506c5e908734085701d3a1dad", + "0x02f8730102840220b029850b68c6e97282520894aee4d040e7d1f3e6f4e007c45d288c4b7bd82d98880275aa22c24bca3e80c001a093b213f5aea575ae7d2473c51f7e174a54079008ed490b2768fc2c0583e49bada07dfbb0bf9f03bd8aec322d58568fbff79ecada55453fac8e5ce338c72961fd6b", + "0x02f902f90180840220b029850b2e2b96d483031c87943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad876a94d74f430000b902843593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065f2ac9300000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000006a94d74f43000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000006a94d74f4300000000000000000000000000000000000000000000000000000000002394e7f30500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000014fee680690900ba0cccfc76ad70fd1b95d10e16c001a0dedd004eaed6394dbb0ace2360ad8aeca6761edd5c37942e22e95d002e2f5ba0a05cd64b717110f7a325753d35e090440ff008a16c4c1e219a3eb296a95dd1d704", + "0x02f8b10102840220b029850b2e2b96d4830221649406450dee7fd2fb8e39061434babcfc05599a6fb880b8441c5603050000000000000000000000001bd63db8c10a2ce6e5b446307eb4844138abfc320000000000000000000000000000000000000000000000000000000000000064c080a056cba33abbf6f0687c5395725cd3fb8b8cedf8f69a0238829264ff5b683d70cea0253e6ed353b10fba09ee59b257251955d3621710e6ed2d8e8f30e68186c0f8e6", + "0x02f903320128840220b029850ab5d04c008301351894d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef00000000000000000000000000000000000000000000000000000000000087b90000000000000000000000005623caecbf58946a0d48ff9318fa2557182240ab00000000000000000000000000000000000000000000000657b3801b80b4000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000011c46b990f036ae2d0bbc6f92afbef84165af0752306b24f59fab076ade5e33a5bb726ec2f8d8c06c8ae03285ff6187f299427706dd771227879fde474093dc2349d5ae5b08451bdc4e4cda8dff3f969a3450bbb5b85ca063750ce970dc5c45e3c7ee42591b0a66796986b0b98b1e47553393523eea18031c24ff7846394351ccb3d712b4046720470c6efeaaf6da20396728830864e458d115bf88a29e3982af2ed93ff9975f5c637adfdbaffa3969289b0cff21a73d5231e19397e6d9ae0c727eb3d2dd45dcf6dd79cfc42f7c84a46d38c4b047067cd029a20cb587d6ffa5c0b10a92d06fef594506e64c6ebb47736315b9db59c71d8b280845419e9e3b9006c5de4e53809eb97fb41bd529c09e512d8a72f7272f197ef95b352aaeba30140aea49b85e2162932173820a2b7154b9e0426201f0083910ab53ab7319ac686a56ea2260872ca3292b36fd35b2c10ce42a040de5744769e8e38cdbf33e75f449986bc2ce833985f7494bb689e96d7e4e4d3d7abe974050379da073c7b9796b00261ebb67e5256edc37569e7e11581c7e07b8d53d41a78984e41a812276041dbbdcbe65e3e9fd7ef63acd4ce98bc0621334261f731945adf4118d41eaaa662eeca3f1845c13f25cbba3d726231691cc1678de0936fe89df8d408c9bc344d58d0ae0a46e70d0e09debcd1ba9ca8ff28fa3dcc7b1318cdac64c0b387c56304d964a2f86643f31da169680b58a8548f4d3144a13fdb0eb53a2844abdea2d4a0c76a82ddc001a08707ba7d8a4348edac70661692dfc15d93998f970314f5952e03ea9ed637b07ba0571ab50ff584286e9020318ac277cfac528c7c6a038e37364f022f2f9619d143", + "0x02f90234018207bf840220b029850b68c6e9728302208794af9ba9f9d7db062a119371ea923ed274e398116380b901c4d4dfd6bc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000065f2ab75000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000415a4ea69da68b9aacdadba48b130c887c2285ec857221ba923063a0b0bfbccfa801484944382b81aee3537c71b763893b6385a363f2395e9ecc7f3ecafa899fbe1b00000000000000000000000000000000000000000000000000000000000000c080a0d234d32bdc0d78898539df7f6abe9c13342ed4b36cab9fbc5ff9d23385a844e3a0017d643dfda52cb190cf237999797e46e405dec578497470e4e185c7f9e7928d", + "0x02f8b10102840220b029850b68c6e97283012e6294b131f4a55907b10d1f0a50d8ab8fa09ec342cd7480b844a9059cbb0000000000000000000000003996989b5ecb2e968e9cbabf1666aaeae21173fc0000000000000000000000000000000000000000000000914e05bea1d5080000c001a0a5c46c0bac56c65f6de1518e77158ade4e4e64c89c1e50bca25271413ffc6d7ca033d8a84aba11a9409fe9891ba8fb23334c22020bf9f62c078f3edd9c0cc272e7", + "0x02f90332010a840220b029850b68c6e9728301351594d4b812dd7134f632c947ca11a2fb0f49082a248380b902c42e7ba6ef000000000000000000000000000000000000000000000000000000000000cb9000000000000000000000000081a10688b294747d4cbc97c3cbcde68dd81b79fc00000000000000000000000000000000000000000000000b1cf24ddd0b140000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000118931c013269fa3868e5ebb9f99a2e634fb1b5500c953ea97325c997d3788aa715f1ff830392a163d437f6c1fc55e596da7d7b1571c001b47262fd979992ab1c972c01fdc16a5a86df15b6278833290870f4a02a990b99f2ddbc0423ac60bac0d50a3e859b29dd14f494ab8a77ac7aa36e39e0d9a39db658daa4c2994b391f75dea97cbb74734d1739d758e528c3de92aeaf9e191f9439fc2f59accf5cbae8eb10e8f84a19a8e363db712a02051654e15ae78ae31c8585180234e40ba9a0698f1c0fd87dfbaf9df473f78f39ddafcad6f2eead4fe54824f8bc3dba6df6fc327807fe9125520aa869739d06ee7e4169e75871e4325e2b642790c7b3a8090cfef4188fe4b376d05bc1d12a1bc91367d4a3eec9b43d3a66afb8aa29c443828e197e473bf64a203c428b430b04056ff7a1d5aec62aebc5f5df8c4260f29d8b342ab081e31b1fe1d272506080926e8adcc56748a87e4ffdb8e78688e89ff7a7e518aa921a90b94a8d5891299de2a8fe58144ac34ba0b0f5226bbe54fd2cffaaba4bfcd67e931175e5b4c8b0a956f3d164cde10179a7583ba29bee3eadbc2acd1f0d6df9677a941d7cbbd94ffdf154c6736b146b862f9de6449d0d550ac055f19596abe3817ee8a14f49b7efe1f8351d9e474eca711776c9d4b2f80a01e0889a1e8a3497dbbba44476a13c02cfed0b524896278c0bfc2ede44fcc65c1b9efe49e33a5ae340559eadadb3e2ca3d8f89f796bebe7b6ab26f40914495b23cb29e64b2dd29ec080a0e8238473c8e41ebfe341df72d402c8c0b35edaa96fa9393586b2ef1cc4057a16a0166dc8645fb72d8818cc7dff6bfe393b3e4a0cdfd959fa7377e7cb879c762c6a", + "0x02f8b00104840220b029850b68c6e97282b68c946982508145454ce325ddbe47a25d4ec3d231193380b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000000000000000000000528a0c1763c7ee5b9ef0000c001a0664178682c745e9b3f397333f97dc61599ff9ede8299bdfc15b8bf868dcc2e14a03a497d31c3c1bc9b12577d2d111916ac7a4f0eb2307950fbfe205bc5aa5ef3c5", + "0x02f8b1010c840220b029850ba43b740083012e7694b131f4a55907b10d1f0a50d8ab8fa09ec342cd7480b844a9059cbb0000000000000000000000002fdc20f6fa8241734a75128c5fefad18abff48770000000000000000000000000000000000000000000000948751d51b30617400c001a066098701097d00d5fd400901979998b94f436f08bd4d50d07d534ea16a123741a064bd8771fbf422264534adb9f40722af08e4721235d1d39b9e0dee2c38cb00c4", + "0x02f902f401820161840220b029850b9e3d482e83048d0b94c36442b4a4522e871399cd717abdd847ab11fe8880b90284ac9650d8000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000084fc6f7865000000000000000000000000000000000000000000000000000000000009cd19000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004449404b7c000000000000000000000000000000000000000000000000022bdf74a5001413000000000000000000000000f333087c317f6c7eab71af59d894edf55f79feb8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064df2ab5bb000000000000000000000000767fe9edc9e0df98e07454847909b5e959d7ca0e0000000000000000000000000000000000000000000000002fac65a3525eac0d000000000000000000000000f333087c317f6c7eab71af59d894edf55f79feb800000000000000000000000000000000000000000000000000000000c001a0437d3d1e56edeeb5d6dbffabb5de5b3fe60ce3c72bee37dd22df1cadff2cc2f3a02c3b6770de93dd30bddc41a06229448576b643da3a9d592cb0632b1dafdf1c7f", + "0x02f8b0010184021058f5850a8a2aa89482c95794b131f4a55907b10d1f0a50d8ab8fa09ec342cd7480b844a9059cbb0000000000000000000000009dcf825b01b3635623d901aef85cf431f09f79fe00000000000000000000000000000000000000000000007bcce5b6ed1332dbcec001a02308e4661a772da3b543bfabef345ef466e09dad64c74ad0867d8f2b8074e885a034911fc9e300f431b0fac2f0b9b0b21dec47655ad9b545d3a2efe83f56c01548", + "0x02f8b10181ae8401fa70b88516cf46e34882c8f094b528edbef013aff855ac3c50b381f253af13b99780b844a9059cbb0000000000000000000000004a300e437f98009b4a089bc9b4abdc135a7147d000000000000000000000000000000000000000000000000cbd47b6eaa8cc0000c001a02261daca00b379393cbb2fe127b15d8778a4b7e36430eb335b2bc16a1c194feca010a19a518c45589b5c4ade62ac228a50920722d5b7360f0d333c523437336185", + "0x02f8b00181a383e4e1c0850de7dc35bf82cb1c94614577036f0a024dbc1c88ba616b394dd65d105a80b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a02703d70b06b6e19a6db9be9479616e6623784db3b46ff994e360e8e572a59777a0248227295e09c5937b8a0a740bff7bb218f3e0b42bf9f195693c9e9466d554fb", + "0x02f8f2018216218398968085111ade37ac830301339477f0de655885dcf6b6942ea5b3de171dfd3f5da980b884eeb858b5000000000000000000000000000000000000000000000000000000000000997e000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000083bc1b65fb8397718c9ff6a786ec9d0117a0b6e1000000000000000000000000000000000000000000000000001c60d39552429cc080a04e9b2f821a25e502f584ac52716daa3837db0a353a5b61895067474c2b203a65a07220680fd91ce369e32cb25d85eabb51bcc001a83593e17a4f89e14ae2abcca6", + "0x02f876018309fe9383989680851510cd35be83015f90943a72e72939c80ab9413ad9c6ca790ed46b184a17880484a65efe3c000080c001a0f48c69a77f0fa660f97d4f64cdbbbdb5948e987a15088100a81562c069418126a059ffe793bf3e17d0d02fda78bc12adafd5b22d647a20f42f2570855dd076be73", + "0x02f8740183051017839896808515699cce3e82520894f48e53fa5cadd0728aaca90ee7e1c6132020993787175f60d3e2c15c80c080a0534c6a9d9aaeda4e9704b80b44339c040885f0d6bc5106c8c141aa487d7a841da06515ff0bebf9cf9c5a5fcee0f0dd7673bfce41f5b0e91cb0550a7e8ce7cdf818", + "0x02f87201830bbc2a80850a5254153d827d0094388c818ca8b9251b393131c08a736a67ccb19297880185a6d6be627f3280c080a038cbd7a4589d49f061b88da94c6d16e085faed4ea61f60a744d781bea95862a3a061eb4b1dc235a3fdb04c589150326d7e49089439428c22ced7bc7ddb559edd37" + ], + "withdrawals": [ + { + "index": "38350022", + "validator_index": "171011", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18545672" + }, + { + "index": "38350023", + "validator_index": "171012", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18561699" + }, + { + "index": "38350024", + "validator_index": "171013", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "62582115" + }, + { + "index": "38350025", + "validator_index": "171014", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18489815" + }, + { + "index": "38350026", + "validator_index": "171015", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18546820" + }, + { + "index": "38350027", + "validator_index": "171016", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18534476" + }, + { + "index": "38350028", + "validator_index": "171017", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18539498" + }, + { + "index": "38350029", + "validator_index": "171018", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18573549" + }, + { + "index": "38350030", + "validator_index": "171019", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18486098" + }, + { + "index": "38350031", + "validator_index": "171020", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18511761" + }, + { + "index": "38350032", + "validator_index": "171021", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18501732" + }, + { + "index": "38350033", + "validator_index": "171022", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "62418961" + }, + { + "index": "38350034", + "validator_index": "171023", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18490087" + }, + { + "index": "38350035", + "validator_index": "171024", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18515931" + }, + { + "index": "38350036", + "validator_index": "171025", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18534555" + }, + { + "index": "38350037", + "validator_index": "171026", + "address": "0x8626354048f90faafc212c07ec7f3613406b1b32", + "amount": "18550274" + } + ], + "blob_gas_used": "131072", + "excess_blob_gas": "0" + }, + "bls_to_execution_changes": [], + "blob_kzg_commitments": [ + "0x97d62d4572935295f909f243714201d9221215bfcc91af6546d28d2e52040577a77957256c530ca25974f6a814511b1a" + ] + } +} diff --git a/cmd/blsync/engine_api.go b/cmd/blsync/engine_api.go deleted file mode 100644 index d10750e295fe..000000000000 --- a/cmd/blsync/engine_api.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2024 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" - "time" - - "github.com/ethereum/go-ethereum/beacon/engine" - "github.com/ethereum/go-ethereum/beacon/types" - "github.com/ethereum/go-ethereum/common" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" -) - -func updateEngineApi(client *rpc.Client, headCh chan types.ChainHeadEvent) { - for event := range headCh { - if client == nil { // dry run, no engine API specified - log.Info("New execution block retrieved", "block number", event.HeadBlock.Number, "block hash", event.HeadBlock.BlockHash, "finalized block hash", event.Finalized) - } else { - if status, err := callNewPayloadV2(client, event.HeadBlock); err == nil { - log.Info("Successful NewPayload", "block number", event.HeadBlock.Number, "block hash", event.HeadBlock.BlockHash, "status", status) - } else { - log.Error("Failed NewPayload", "block number", event.HeadBlock.Number, "block hash", event.HeadBlock.BlockHash, "error", err) - } - if status, err := callForkchoiceUpdatedV1(client, event.HeadBlock.BlockHash, event.Finalized); err == nil { - log.Info("Successful ForkchoiceUpdated", "head", event.HeadBlock.BlockHash, "status", status) - } else { - log.Error("Failed ForkchoiceUpdated", "head", event.HeadBlock.BlockHash, "error", err) - } - } - } -} - -func callNewPayloadV2(client *rpc.Client, execData *engine.ExecutableData) (string, error) { - var resp engine.PayloadStatusV1 - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - err := client.CallContext(ctx, &resp, "engine_newPayloadV2", execData) - cancel() - return resp.Status, err -} - -func callForkchoiceUpdatedV1(client *rpc.Client, headHash, finalizedHash common.Hash) (string, error) { - var resp engine.ForkChoiceResponse - update := engine.ForkchoiceStateV1{ - HeadBlockHash: headHash, - SafeBlockHash: finalizedHash, - FinalizedBlockHash: finalizedHash, - } - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - err := client.CallContext(ctx, &resp, "engine_forkchoiceUpdatedV1", update, nil) - cancel() - return resp.PayloadStatus.Status, err -} diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go index fd22761d3c45..2aa3d9a24ed7 100644 --- a/cmd/blsync/main.go +++ b/cmd/blsync/main.go @@ -23,7 +23,6 @@ import ( "os" "github.com/ethereum/go-ethereum/beacon/blsync" - "github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" @@ -87,16 +86,14 @@ func sync(ctx *cli.Context) error { verbosity := log.FromLegacyLevel(ctx.Int(verbosityFlag.Name)) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor))) - headCh := make(chan types.ChainHeadEvent, 16) + // set up blsync client := blsync.NewClient(ctx) - sub := client.SubscribeChainHeadEvent(headCh) - go updateEngineApi(makeRPCClient(ctx), headCh) + client.SetEngineRPC(makeRPCClient(ctx)) client.Start() + // run until stopped <-ctx.Done() client.Stop() - sub.Unsubscribe() - close(headCh) return nil } diff --git a/cmd/geth/config.go b/cmd/geth/config.go index cf4cdef76ce1..76c6484fee6a 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -44,6 +44,7 @@ import ( "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" "github.com/naoina/toml" "github.com/urfave/cli/v2" ) @@ -213,9 +214,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { } utils.RegisterFullSyncTester(stack, eth, common.BytesToHash(hex)) } - // Start the dev mode if requested, or launch the engine API for - // interacting with external consensus client. + if ctx.IsSet(utils.DeveloperFlag.Name) { + // Start dev mode. simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), eth) if err != nil { utils.Fatalf("failed to register dev mode catalyst service: %v", err) @@ -223,8 +224,14 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon) stack.RegisterLifecycle(simBeacon) } else if ctx.IsSet(utils.BeaconApiFlag.Name) { - stack.RegisterLifecycle(catalyst.NewBlsync(blsync.NewClient(ctx), eth)) + // Start blsync mode. + srv := rpc.NewServer() + srv.RegisterName("engine", catalyst.NewConsensusAPI(eth)) + blsyncer := blsync.NewClient(ctx) + blsyncer.SetEngineRPC(rpc.DialInProc(srv)) + stack.RegisterLifecycle(blsyncer) } else { + // Launch the engine API for interacting with external consensus client. err := catalyst.Register(stack, eth) if err != nil { utils.Fatalf("failed to register catalyst service: %v", err) diff --git a/eth/catalyst/blsync.go b/eth/catalyst/blsync.go deleted file mode 100644 index 4877cf4c6361..000000000000 --- a/eth/catalyst/blsync.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2024 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 catalyst - -import ( - "github.com/ethereum/go-ethereum/beacon/engine" - "github.com/ethereum/go-ethereum/beacon/types" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" -) - -// Blsync tracks the head of the beacon chain through the beacon light client -// and drives the local node via ConsensusAPI. -type Blsync struct { - engine *ConsensusAPI - client Client - headCh chan types.ChainHeadEvent - headSub event.Subscription - - quitCh chan struct{} -} - -type Client interface { - SubscribeChainHeadEvent(ch chan<- types.ChainHeadEvent) event.Subscription - Start() - Stop() -} - -// NewBlsync creates a new beacon light syncer. -func NewBlsync(client Client, eth *eth.Ethereum) *Blsync { - return &Blsync{ - engine: newConsensusAPIWithoutHeartbeat(eth), - client: client, - headCh: make(chan types.ChainHeadEvent, 16), - quitCh: make(chan struct{}), - } -} - -// Start starts underlying beacon light client and the sync logic for driving -// the local node. -func (b *Blsync) Start() error { - log.Info("Beacon light sync started") - b.headSub = b.client.SubscribeChainHeadEvent(b.headCh) - go b.client.Start() - - for { - select { - case <-b.quitCh: - return nil - case head := <-b.headCh: - if _, err := b.engine.NewPayloadV2(*head.HeadBlock); err != nil { - log.Error("failed to send new payload", "err", err) - continue - } - update := engine.ForkchoiceStateV1{ - HeadBlockHash: head.HeadBlock.BlockHash, - SafeBlockHash: head.Finalized, //TODO pass finalized or empty hash here? - FinalizedBlockHash: head.Finalized, - } - if _, err := b.engine.ForkchoiceUpdatedV1(update, nil); err != nil { - log.Error("failed to send forkchoice updated", "err", err) - continue - } - } - } -} - -// Stop signals to the light client and syncer to exit. -func (b *Blsync) Stop() error { - b.client.Stop() - close(b.quitCh) - return nil -} diff --git a/go.mod b/go.mod index 49bce7c1ae85..15113972f527 100644 --- a/go.mod +++ b/go.mod @@ -54,8 +54,8 @@ require ( github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 - github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 - github.com/protolambda/zrnt v0.30.0 + github.com/protolambda/bls12-381-util v0.1.0 + github.com/protolambda/zrnt v0.32.2 github.com/protolambda/ztyp v0.2.2 github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible diff --git a/go.sum b/go.sum index 70aa4cdb607b..df357535db3f 100644 --- a/go.sum +++ b/go.sum @@ -249,7 +249,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -395,7 +394,6 @@ github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= @@ -467,12 +465,10 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e/go.mod h1:MPZvj2Pr0N8/dXyTPS5REeg2sdLG7t8DRzC1rLv925w= -github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 h1:cZC+usqsYgHtlBaGulVnZ1hfKAi8iWtujBnRLQE698c= -github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY= -github.com/protolambda/messagediff v1.4.0/go.mod h1:LboJp0EwIbJsePYpzh5Op/9G1/4mIztMRYzzwR0dR2M= -github.com/protolambda/zrnt v0.30.0 h1:pHEn69ZgaDFGpLGGYG1oD7DvYI7RDirbMBPfbC+8p4g= -github.com/protolambda/zrnt v0.30.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax/2lMsJ4Jw= +github.com/protolambda/bls12-381-util v0.1.0 h1:05DU2wJN7DTU7z28+Q+zejXkIsA/MF8JZQGhtBZZiWk= +github.com/protolambda/bls12-381-util v0.1.0/go.mod h1:cdkysJTRpeFeuUVx/TXGDQNMTiRAalk1vQw3TYTHcE4= +github.com/protolambda/zrnt v0.32.2 h1:KZ48T+3UhsPXNdtE/5QEvGc9DGjUaRI17nJaoznoIaM= +github.com/protolambda/zrnt v0.32.2/go.mod h1:A0fezkp9Tt3GBLATSPIbuY4ywYESyAuc/FFmPKg8Lqs= github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY= github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU= github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw= @@ -868,7 +864,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 14eb8967be7acc54c5dc9a416151ac45c01251b6 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 21 Mar 2024 13:50:13 +0100 Subject: [PATCH 091/571] all: use min/max/clear from go1.21 (#29307) --- accounts/keystore/keystore.go | 4 +--- core/vm/analysis_test.go | 4 +--- crypto/crypto.go | 4 +--- crypto/secp256k1/scalar_mult_cgo.go | 8 ++------ eth/protocols/eth/peer.go | 8 -------- internal/era/era.go | 9 +-------- metrics/sample_test.go | 7 ------- p2p/discover/common.go | 7 ------- p2p/discover/v5wire/crypto.go | 4 +--- rlp/decode.go | 4 +--- 10 files changed, 8 insertions(+), 51 deletions(-) diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index e62a8eb25738..5c978cf0b422 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -500,7 +500,5 @@ func (ks *KeyStore) isUpdating() bool { // zeroKey zeroes a private key in memory. func zeroKey(k *ecdsa.PrivateKey) { b := k.D.Bits() - for i := range b { - b[i] = 0 - } + clear(b) } diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go index 398861f8ae7d..471d2b4ffbac 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/analysis_test.go @@ -93,9 +93,7 @@ func BenchmarkJumpdestOpAnalysis(bench *testing.B) { bits := make(bitvec, len(code)/8+1+4) b.ResetTimer() for i := 0; i < b.N; i++ { - for j := range bits { - bits[j] = 0 - } + clear(bits) codeBitmapInternal(code, bits) } } diff --git a/crypto/crypto.go b/crypto/crypto.go index 734feed5cac3..7f7171f730a0 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -287,7 +287,5 @@ func PubkeyToAddress(p ecdsa.PublicKey) common.Address { } func zeroBytes(bytes []byte) { - for i := range bytes { - bytes[i] = 0 - } + clear(bytes) } diff --git a/crypto/secp256k1/scalar_mult_cgo.go b/crypto/secp256k1/scalar_mult_cgo.go index 8afa9d023b07..bdf8eeede7df 100644 --- a/crypto/secp256k1/scalar_mult_cgo.go +++ b/crypto/secp256k1/scalar_mult_cgo.go @@ -44,12 +44,8 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, // Unpack the result and clear temporaries. x := new(big.Int).SetBytes(point[:32]) y := new(big.Int).SetBytes(point[32:]) - for i := range point { - point[i] = 0 - } - for i := range padded { - scalar[i] = 0 - } + clear(point) + clear(scalar) if res != 1 { return nil, nil } diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index 94f28f240f86..f53782a05318 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -42,14 +42,6 @@ const ( maxQueuedTxAnns = 4096 ) -// max is a helper function which returns the larger of the two given integers. -func max(a, b int) int { - if a > b { - return a - } - return b -} - // Peer is a collection of relevant information we have about a `eth` peer. type Peer struct { id string // Unique ID for the peer, cached diff --git a/internal/era/era.go b/internal/era/era.go index 2099c2d575c7..22715a82e5a2 100644 --- a/internal/era/era.go +++ b/internal/era/era.go @@ -229,7 +229,7 @@ func (e *Era) readOffset(n uint64) (int64, error) { ) e.mu.Lock() defer e.mu.Unlock() - clearBuffer(e.buf[:]) + clear(e.buf[:]) if _, err := e.f.ReadAt(e.buf[:], offOffset); err != nil { return 0, err } @@ -248,13 +248,6 @@ func newSnappyReader(e *e2store.Reader, expectedType uint16, off int64) (io.Read return snappy.NewReader(r), int64(n), err } -// clearBuffer zeroes out the buffer. -func clearBuffer(buf []byte) { - for i := 0; i < len(buf); i++ { - buf[i] = 0 - } -} - // metadata wraps the metadata in the block index. type metadata struct { start uint64 diff --git a/metrics/sample_test.go b/metrics/sample_test.go index 79673570554c..9835ec1c3003 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -87,13 +87,6 @@ func BenchmarkUniformSample1028(b *testing.B) { benchmarkSample(b, NewUniformSample(1028)) } -func min(a, b int) int { - if a < b { - return a - } - return b -} - func TestExpDecaySample(t *testing.T) { for _, tc := range []struct { reservoirSize int diff --git a/p2p/discover/common.go b/p2p/discover/common.go index c9f0477defeb..1f763904bb1f 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -92,10 +92,3 @@ type ReadPacket struct { Data []byte Addr *net.UDPAddr } - -func min(x, y int) int { - if x > y { - return y - } - return x -} diff --git a/p2p/discover/v5wire/crypto.go b/p2p/discover/v5wire/crypto.go index fc0a0edef594..00fc3b45644a 100644 --- a/p2p/discover/v5wire/crypto.go +++ b/p2p/discover/v5wire/crypto.go @@ -129,9 +129,7 @@ func deriveKeys(hash hashFn, priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey, n1, n sec := session{writeKey: make([]byte, aesKeySize), readKey: make([]byte, aesKeySize)} kdf.Read(sec.writeKey) kdf.Read(sec.readKey) - for i := range eph { - eph[i] = 0 - } + clear(eph) return &sec } diff --git a/rlp/decode.go b/rlp/decode.go index 9b17d2d81084..47801b209085 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -1105,9 +1105,7 @@ func (s *Stream) readUint(size byte) (uint64, error) { return uint64(b), err default: buffer := s.uintbuf[:8] - for i := range buffer { - buffer[i] = 0 - } + clear(buffer) start := int(8 - size) if err := s.readFull(buffer[start:]); err != nil { return 0, err From f46fe62c5d1d25ce0e9869ecbaf0e5722d2bc2f5 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Fri, 22 Mar 2024 04:38:24 -0700 Subject: [PATCH 092/571] triedb/hashdb: Avoid setting db.cleans on Close (#29309) --- triedb/hashdb/database.go | 1 - 1 file changed, 1 deletion(-) diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index e45ccdba32ca..7d5499eb693a 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -619,7 +619,6 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize) { func (db *Database) Close() error { if db.cleans != nil { db.cleans.Reset() - db.cleans = nil } return nil } From 6490d9897ab00290d188b1893d1874e977fb4c66 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 22 Mar 2024 20:12:10 +0800 Subject: [PATCH 093/571] cmd, triedb: implement history inspection (#29267) This pull request introduces a database tool for inspecting the state history. It can be used for either account history or storage slot history, within a specific block range. The state output format can be chosen either with - the "rlp-encoded" values (those inserted into the merkle trie) - the "rlp-decoded" value (the raw state value) The latter one needs --raw flag. --- cmd/geth/dbcmd.go | 168 +++++++++++++++++++++++++++++++ triedb/history.go | 72 +++++++++++++ triedb/pathdb/database.go | 30 ++++++ triedb/pathdb/history_inspect.go | 151 +++++++++++++++++++++++++++ 4 files changed, 421 insertions(+) create mode 100644 triedb/history.go create mode 100644 triedb/pathdb/history_inspect.go diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 1d885bd58d20..4e91a4ff25ed 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -33,11 +33,14 @@ import ( "github.com/ethereum/go-ethereum/console/prompt" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/triedb" "github.com/olekukonko/tablewriter" "github.com/urfave/cli/v2" ) @@ -79,6 +82,7 @@ Remove blockchain and state databases`, dbExportCmd, dbMetadataCmd, dbCheckStateContentCmd, + dbInspectHistoryCmd, }, } dbInspectCmd = &cli.Command{ @@ -203,6 +207,28 @@ WARNING: This is a low-level operation which may cause database corruption!`, }, utils.NetworkFlags, utils.DatabaseFlags), Description: "Shows metadata about the chain status.", } + dbInspectHistoryCmd = &cli.Command{ + Action: inspectHistory, + Name: "inspect-history", + Usage: "Inspect the state history within block range", + ArgsUsage: "
[OPTIONAL ]", + Flags: flags.Merge([]cli.Flag{ + utils.SyncModeFlag, + &cli.Uint64Flag{ + Name: "start", + Usage: "block number of the range start, zero means earliest history", + }, + &cli.Uint64Flag{ + Name: "end", + Usage: "block number of the range end(included), zero means latest history", + }, + &cli.BoolFlag{ + Name: "raw", + Usage: "display the decoded raw state value (otherwise shows rlp-encoded value)", + }, + }, utils.NetworkFlags, utils.DatabaseFlags), + Description: "This command queries the history of the account or storage slot within the specified block range", + } ) func removeDB(ctx *cli.Context) error { @@ -759,3 +785,145 @@ func showMetaData(ctx *cli.Context) error { table.Render() return nil } + +func inspectAccount(db *triedb.Database, start uint64, end uint64, address common.Address, raw bool) error { + stats, err := db.AccountHistory(address, start, end) + if err != nil { + return err + } + fmt.Printf("Account history:\n\taddress: %s\n\tblockrange: [#%d-#%d]\n", address.Hex(), stats.Start, stats.End) + + from := stats.Start + for i := 0; i < len(stats.Blocks); i++ { + var content string + if len(stats.Origins[i]) == 0 { + content = "" + } else { + if !raw { + content = fmt.Sprintf("%#x", stats.Origins[i]) + } else { + account := new(types.SlimAccount) + if err := rlp.DecodeBytes(stats.Origins[i], account); err != nil { + panic(err) + } + code := "" + if len(account.CodeHash) > 0 { + code = fmt.Sprintf("%#x", account.CodeHash) + } + root := "" + if len(account.Root) > 0 { + root = fmt.Sprintf("%#x", account.Root) + } + content = fmt.Sprintf("nonce: %d, balance: %d, codeHash: %s, root: %s", account.Nonce, account.Balance, code, root) + } + } + fmt.Printf("#%d - #%d: %s\n", from, stats.Blocks[i], content) + from = stats.Blocks[i] + } + return nil +} + +func inspectStorage(db *triedb.Database, start uint64, end uint64, address common.Address, slot common.Hash, raw bool) error { + // The hash of storage slot key is utilized in the history + // rather than the raw slot key, make the conversion. + slotHash := crypto.Keccak256Hash(slot.Bytes()) + stats, err := db.StorageHistory(address, slotHash, start, end) + if err != nil { + return err + } + fmt.Printf("Storage history:\n\taddress: %s\n\tslot: %s\n\tblockrange: [#%d-#%d]\n", address.Hex(), slot.Hex(), stats.Start, stats.End) + + from := stats.Start + for i := 0; i < len(stats.Blocks); i++ { + var content string + if len(stats.Origins[i]) == 0 { + content = "" + } else { + if !raw { + content = fmt.Sprintf("%#x", stats.Origins[i]) + } else { + _, data, _, err := rlp.Split(stats.Origins[i]) + if err != nil { + fmt.Printf("Failed to decode storage slot, %v", err) + return err + } + content = fmt.Sprintf("%#x", data) + } + } + fmt.Printf("#%d - #%d: %s\n", from, stats.Blocks[i], content) + from = stats.Blocks[i] + } + return nil +} + +func inspectHistory(ctx *cli.Context) error { + if ctx.NArg() == 0 || ctx.NArg() > 2 { + return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage) + } + var ( + address common.Address + slot common.Hash + ) + if err := address.UnmarshalText([]byte(ctx.Args().Get(0))); err != nil { + return err + } + if ctx.NArg() > 1 { + if err := slot.UnmarshalText([]byte(ctx.Args().Get(1))); err != nil { + return err + } + } + // Load the databases. + stack, _ := makeConfigNode(ctx) + defer stack.Close() + + db := utils.MakeChainDatabase(ctx, stack, true) + defer db.Close() + + triedb := utils.MakeTrieDatabase(ctx, db, false, false, false) + defer triedb.Close() + + var ( + err error + start uint64 // the id of first history object to query + end uint64 // the id (included) of last history object to query + ) + // State histories are identified by state ID rather than block number. + // To address this, load the corresponding block header and perform the + // conversion by this function. + blockToID := func(blockNumber uint64) (uint64, error) { + header := rawdb.ReadHeader(db, rawdb.ReadCanonicalHash(db, blockNumber), blockNumber) + if header == nil { + return 0, fmt.Errorf("block #%d is not existent", blockNumber) + } + id := rawdb.ReadStateID(db, header.Root) + if id == nil { + first, last, err := triedb.HistoryRange() + if err == nil { + return 0, fmt.Errorf("history of block #%d is not existent, available history range: [#%d-#%d]", blockNumber, first, last) + } + return 0, fmt.Errorf("history of block #%d is not existent", blockNumber) + } + return *id, nil + } + // Parse the starting block number for inspection. + startNumber := ctx.Uint64("start") + if startNumber != 0 { + start, err = blockToID(startNumber) + if err != nil { + return err + } + } + // Parse the ending block number for inspection. + endBlock := ctx.Uint64("end") + if endBlock != 0 { + end, err = blockToID(endBlock) + if err != nil { + return err + } + } + // Inspect the state history. + if slot == (common.Hash{}) { + return inspectAccount(triedb, start, end, address, ctx.Bool("raw")) + } + return inspectStorage(triedb, start, end, address, slot, ctx.Bool("raw")) +} diff --git a/triedb/history.go b/triedb/history.go new file mode 100644 index 000000000000..f663cdd7c248 --- /dev/null +++ b/triedb/history.go @@ -0,0 +1,72 @@ +// Copyright 2023 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 triedb + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/triedb/pathdb" +) + +// AccountHistory inspects the account history within the specified range. +// +// Start: State ID of the first history object for the query. 0 implies the first +// available object is selected as the starting point. +// +// End: State ID of the last history for the query. 0 implies the last available +// object is selected as the starting point. Note end is included for query. +// +// This function is only supported by path mode database. +func (db *Database) AccountHistory(address common.Address, start, end uint64) (*pathdb.HistoryStats, error) { + pdb, ok := db.backend.(*pathdb.Database) + if !ok { + return nil, errors.New("not supported") + } + return pdb.AccountHistory(address, start, end) +} + +// StorageHistory inspects the storage history within the specified range. +// +// Start: State ID of the first history object for the query. 0 implies the first +// available object is selected as the starting point. +// +// End: State ID of the last history for the query. 0 implies the last available +// object is selected as the starting point. Note end is included for query. +// +// Note, slot refers to the hash of the raw slot key. +// +// This function is only supported by path mode database. +func (db *Database) StorageHistory(address common.Address, slot common.Hash, start uint64, end uint64) (*pathdb.HistoryStats, error) { + pdb, ok := db.backend.(*pathdb.Database) + if !ok { + return nil, errors.New("not supported") + } + return pdb.StorageHistory(address, slot, start, end) +} + +// HistoryRange returns the block numbers associated with earliest and latest +// state history in the local store. +// +// This function is only supported by path mode database. +func (db *Database) HistoryRange() (uint64, uint64, error) { + pdb, ok := db.backend.(*pathdb.Database) + if !ok { + return 0, 0, errors.New("not supported") + } + return pdb.HistoryRange() +} diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 7bdb6132bb57..34941a274d4c 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -487,3 +487,33 @@ func (db *Database) modifyAllowed() error { } return nil } + +// AccountHistory inspects the account history within the specified range. +// +// Start: State ID of the first history object for the query. 0 implies the first +// available object is selected as the starting point. +// +// End: State ID of the last history for the query. 0 implies the last available +// object is selected as the ending point. Note end is included in the query. +func (db *Database) AccountHistory(address common.Address, start, end uint64) (*HistoryStats, error) { + return accountHistory(db.freezer, address, start, end) +} + +// StorageHistory inspects the storage history within the specified range. +// +// Start: State ID of the first history object for the query. 0 implies the first +// available object is selected as the starting point. +// +// End: State ID of the last history for the query. 0 implies the last available +// object is selected as the ending point. Note end is included in the query. +// +// Note, slot refers to the hash of the raw slot key. +func (db *Database) StorageHistory(address common.Address, slot common.Hash, start uint64, end uint64) (*HistoryStats, error) { + return storageHistory(db.freezer, address, slot, start, end) +} + +// HistoryRange returns the block numbers associated with earliest and latest +// state history in the local store. +func (db *Database) HistoryRange() (uint64, uint64, error) { + return historyRange(db.freezer) +} diff --git a/triedb/pathdb/history_inspect.go b/triedb/pathdb/history_inspect.go new file mode 100644 index 000000000000..d8a761b91689 --- /dev/null +++ b/triedb/pathdb/history_inspect.go @@ -0,0 +1,151 @@ +// Copyright 2024 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 first { + first = start + } + // Load the id of the last history object in local store. + head, err := freezer.Ancients() + if err != nil { + return 0, 0, err + } + last := head - 1 + if end != 0 && end < last { + last = end + } + // Make sure the range is valid + if first >= last { + return 0, 0, fmt.Errorf("range is invalid, first: %d, last: %d", first, last) + } + return first, last, nil +} + +func inspectHistory(freezer *rawdb.ResettableFreezer, start, end uint64, onHistory func(*history, *HistoryStats)) (*HistoryStats, error) { + var ( + stats = &HistoryStats{} + init = time.Now() + logged = time.Now() + ) + start, end, err := sanitizeRange(start, end, freezer) + if err != nil { + return nil, err + } + for id := start; id <= end; id += 1 { + // The entire history object is decoded, although it's unnecessary for + // account inspection. TODO(rjl493456442) optimization is worthwhile. + h, err := readHistory(freezer, id) + if err != nil { + return nil, err + } + if id == start { + stats.Start = h.meta.block + } + if id == end { + stats.End = h.meta.block + } + onHistory(h, stats) + + if time.Since(logged) > time.Second*8 { + logged = time.Now() + eta := float64(time.Since(init)) / float64(id-start+1) * float64(end-id) + log.Info("Inspecting state history", "checked", id-start+1, "left", end-id, "elapsed", common.PrettyDuration(time.Since(init)), "eta", common.PrettyDuration(eta)) + } + } + log.Info("Inspected state history", "total", end-start+1, "elapsed", common.PrettyDuration(time.Since(init))) + return stats, nil +} + +// accountHistory inspects the account history within the range. +func accountHistory(freezer *rawdb.ResettableFreezer, address common.Address, start, end uint64) (*HistoryStats, error) { + return inspectHistory(freezer, start, end, func(h *history, stats *HistoryStats) { + blob, exists := h.accounts[address] + if !exists { + return + } + stats.Blocks = append(stats.Blocks, h.meta.block) + stats.Origins = append(stats.Origins, blob) + }) +} + +// storageHistory inspects the storage history within the range. +func storageHistory(freezer *rawdb.ResettableFreezer, address common.Address, slot common.Hash, start uint64, end uint64) (*HistoryStats, error) { + return inspectHistory(freezer, start, end, func(h *history, stats *HistoryStats) { + slots, exists := h.storages[address] + if !exists { + return + } + blob, exists := slots[slot] + if !exists { + return + } + stats.Blocks = append(stats.Blocks, h.meta.block) + stats.Origins = append(stats.Origins, blob) + }) +} + +// historyRange returns the block number range of local state histories. +func historyRange(freezer *rawdb.ResettableFreezer) (uint64, uint64, error) { + // Load the id of the first history object in local store. + tail, err := freezer.Tail() + if err != nil { + return 0, 0, err + } + first := tail + 1 + + // Load the id of the last history object in local store. + head, err := freezer.Ancients() + if err != nil { + return 0, 0, err + } + last := head - 1 + + fh, err := readHistory(freezer, first) + if err != nil { + return 0, 0, err + } + lh, err := readHistory(freezer, last) + if err != nil { + return 0, 0, err + } + return fh.meta.block, lh.meta.block, nil +} From d9bde37ac3a5a9569a0c0a35f8c872932d640802 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 22 Mar 2024 13:17:59 +0100 Subject: [PATCH 094/571] log: use native log/slog instead of golang/exp (#29302) --- eth/downloader/queue_test.go | 2 +- internal/debug/api.go | 2 +- internal/debug/flags.go | 2 +- internal/testlog/testlog.go | 2 +- log/format.go | 2 +- log/handler.go | 2 +- log/handler_glog.go | 3 +-- log/logger.go | 3 +-- log/logger_test.go | 2 +- log/root.go | 3 +-- p2p/simulations/adapters/exec.go | 2 +- p2p/simulations/adapters/types.go | 2 +- p2p/simulations/http_test.go | 2 +- signer/core/auditlog.go | 2 +- signer/storage/aes_gcm_storage_test.go | 2 +- 15 files changed, 15 insertions(+), 18 deletions(-) diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index 50b9031a27c6..857ac4813a7d 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -18,6 +18,7 @@ package downloader import ( "fmt" + "log/slog" "math/big" "math/rand" "os" @@ -32,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" - "golang.org/x/exp/slog" ) // makeChain creates a chain of n blocks starting at and including parent. diff --git a/internal/debug/api.go b/internal/debug/api.go index 482989e0d0f3..c262201e3b7f 100644 --- a/internal/debug/api.go +++ b/internal/debug/api.go @@ -24,6 +24,7 @@ import ( "bytes" "errors" "io" + "log/slog" "os" "os/user" "path/filepath" @@ -37,7 +38,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/hashicorp/go-bexpr" - "golang.org/x/exp/slog" ) // Handler is the global debugging handler. diff --git a/internal/debug/flags.go b/internal/debug/flags.go index dac878a7b1ff..19222c8325f9 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -19,6 +19,7 @@ package debug import ( "fmt" "io" + "log/slog" "net" "net/http" _ "net/http/pprof" @@ -34,7 +35,6 @@ import ( "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" - "golang.org/x/exp/slog" "gopkg.in/natefinch/lumberjack.v2" ) diff --git a/internal/testlog/testlog.go b/internal/testlog/testlog.go index e5ddf9cfeb0b..3740dd1f242c 100644 --- a/internal/testlog/testlog.go +++ b/internal/testlog/testlog.go @@ -21,11 +21,11 @@ import ( "bytes" "context" "fmt" + "log/slog" "sync" "testing" "github.com/ethereum/go-ethereum/log" - "golang.org/x/exp/slog" ) const ( diff --git a/log/format.go b/log/format.go index 391e9a8dbbba..515ae66e98fc 100644 --- a/log/format.go +++ b/log/format.go @@ -3,6 +3,7 @@ package log import ( "bytes" "fmt" + "log/slog" "math/big" "reflect" "strconv" @@ -10,7 +11,6 @@ import ( "unicode/utf8" "github.com/holiman/uint256" - "golang.org/x/exp/slog" ) const ( diff --git a/log/handler.go b/log/handler.go index 7459aad8913b..248e3813fc2c 100644 --- a/log/handler.go +++ b/log/handler.go @@ -4,13 +4,13 @@ import ( "context" "fmt" "io" + "log/slog" "math/big" "reflect" "sync" "time" "github.com/holiman/uint256" - "golang.org/x/exp/slog" ) type discardHandler struct{} diff --git a/log/handler_glog.go b/log/handler_glog.go index f51bae2a4a5b..608d955572ad 100644 --- a/log/handler_glog.go +++ b/log/handler_glog.go @@ -20,14 +20,13 @@ import ( "context" "errors" "fmt" + "log/slog" "regexp" "runtime" "strconv" "strings" "sync" "sync/atomic" - - "golang.org/x/exp/slog" ) // errVmoduleSyntax is returned when a user vmodule pattern is invalid. diff --git a/log/logger.go b/log/logger.go index c28bbde56840..5672344b0c5c 100644 --- a/log/logger.go +++ b/log/logger.go @@ -2,12 +2,11 @@ package log import ( "context" + "log/slog" "math" "os" "runtime" "time" - - "golang.org/x/exp/slog" ) const errorKey = "LOG_ERROR" diff --git a/log/logger_test.go b/log/logger_test.go index ff981fd018ca..d23e16e57241 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "log/slog" "math/big" "os" "strings" @@ -12,7 +13,6 @@ import ( "time" "github.com/holiman/uint256" - "golang.org/x/exp/slog" ) // TestLoggingWithVmodule checks that vmodule works. diff --git a/log/root.go b/log/root.go index 8662d870637b..91209c46ad1c 100644 --- a/log/root.go +++ b/log/root.go @@ -1,10 +1,9 @@ package log import ( + "log/slog" "os" "sync/atomic" - - "golang.org/x/exp/slog" ) var root atomic.Value diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go index 17e0f75d5ab9..5df2d7649cd8 100644 --- a/p2p/simulations/adapters/exec.go +++ b/p2p/simulations/adapters/exec.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "net/http" "os" @@ -41,7 +42,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" "github.com/gorilla/websocket" - "golang.org/x/exp/slog" ) func init() { diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go index fb8463d221eb..a26dff7a8229 100644 --- a/p2p/simulations/adapters/types.go +++ b/p2p/simulations/adapters/types.go @@ -21,6 +21,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "log/slog" "net" "os" "strconv" @@ -34,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rpc" "github.com/gorilla/websocket" - "golang.org/x/exp/slog" ) // Node represents a node in a simulation network which is created by a diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go index c04308fe0bf8..460ed72d7fc8 100644 --- a/p2p/simulations/http_test.go +++ b/p2p/simulations/http_test.go @@ -20,6 +20,7 @@ import ( "context" "flag" "fmt" + "log/slog" "math/rand" "net/http/httptest" "os" @@ -37,7 +38,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/rpc" "github.com/mattn/go-colorable" - "golang.org/x/exp/slog" ) func TestMain(m *testing.M) { diff --git a/signer/core/auditlog.go b/signer/core/auditlog.go index d2207c9eb8d5..78785a3b02e8 100644 --- a/signer/core/auditlog.go +++ b/signer/core/auditlog.go @@ -19,6 +19,7 @@ package core import ( "context" "encoding/json" + "log/slog" "os" "github.com/ethereum/go-ethereum/common" @@ -26,7 +27,6 @@ import ( "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/signer/core/apitypes" - "golang.org/x/exp/slog" ) type AuditLogger struct { diff --git a/signer/storage/aes_gcm_storage_test.go b/signer/storage/aes_gcm_storage_test.go index a223b1a6b4e7..b895269f9597 100644 --- a/signer/storage/aes_gcm_storage_test.go +++ b/signer/storage/aes_gcm_storage_test.go @@ -20,13 +20,13 @@ import ( "bytes" "encoding/json" "fmt" + "log/slog" "os" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/mattn/go-colorable" - "golang.org/x/exp/slog" ) func TestEncryption(t *testing.T) { From 38eb8b3e20bf237a78fa57e84fa63c2d05a44635 Mon Sep 17 00:00:00 2001 From: George Ma <164313692+availhang@users.noreply.github.com> Date: Fri, 22 Mar 2024 20:29:12 +0800 Subject: [PATCH 095/571] all: fix docstrings (#29311) --- beacon/light/api/light_api.go | 2 +- crypto/bn256/google/bn256.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 7e5ac38420b2..1bba220d3129 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -146,7 +146,7 @@ func (api *BeaconLightApi) httpGetf(format string, params ...any) ([]byte, error return api.httpGet(fmt.Sprintf(format, params...)) } -// GetBestUpdateAndCommittee fetches and validates LightClientUpdate for given +// GetBestUpdatesAndCommittees fetches and validates LightClientUpdate for given // period and full serialized committee for the next period (committee root hash // equals update.NextSyncCommitteeRoot). // Note that the results are validated but the update signature should be verified diff --git a/crypto/bn256/google/bn256.go b/crypto/bn256/google/bn256.go index 93953e23a95f..aca9cf62de1b 100644 --- a/crypto/bn256/google/bn256.go +++ b/crypto/bn256/google/bn256.go @@ -29,7 +29,7 @@ import ( ) // BUG(agl): this implementation is not constant time. -// TODO(agl): keep GF(p²) elements in Mongomery form. +// TODO(agl): keep GF(p²) elements in Montgomery form. // G1 is an abstract cyclic group. The zero value is suitable for use as the // output of an operation, but cannot be used as an input. From 064f37d6f67a012eea0bf8d410346fb1684004b4 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 22 Mar 2024 18:53:53 +0100 Subject: [PATCH 096/571] eth/tracers: live chain tracing with hooks (#29189) Here we add a Go API for running tracing plugins within the main block import process. As an advanced user of geth, you can now create a Go file in eth/tracers/live/, and within that file register your custom tracer implementation. Then recompile geth and select your tracer on the command line. Hooks defined in the tracer will run whenever a block is processed. The hook system is defined in package core/tracing. It uses a struct with callbacks, instead of requiring an interface, for several reasons: - We plan to keep this API stable long-term. The core/tracing hook API does not depend on on deep geth internals. - There are a lot of hooks, and tracers will only need some of them. Using a struct allows you to implement only the hooks you want to actually use. All existing tracers in eth/tracers/native have been rewritten to use the new hook system. This change breaks compatibility with the vm.EVMLogger interface that we used to have. If you are a user of vm.EVMLogger, please migrate to core/tracing, and sorry for breaking your stuff. But we just couldn't have both the old and new tracing APIs coexist in the EVM. --------- Co-authored-by: Matthieu Vachon Co-authored-by: Delweng Co-authored-by: Martin HS --- cmd/evm/blockrunner.go | 4 +- cmd/evm/internal/t8ntool/execution.go | 50 +++- cmd/evm/internal/t8ntool/tracewriter.go | 81 ------ cmd/evm/internal/t8ntool/transition.go | 24 +- cmd/evm/runner.go | 5 +- cmd/evm/staterunner.go | 2 +- cmd/evm/t8n_test.go | 104 +++++++ cmd/evm/testdata/31/README.md | 1 + cmd/evm/testdata/31/alloc.json | 16 + cmd/evm/testdata/31/env.json | 20 ++ ...47543268a5aaf2a6b32a69d2c6d978c45dcfb.json | 1 + ...7543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl | 6 + cmd/evm/testdata/31/txs.json | 14 + cmd/geth/chaincmd.go | 2 + cmd/geth/config.go | 1 + cmd/geth/main.go | 3 + cmd/utils/flags.go | 39 ++- consensus/beacon/consensus.go | 3 +- consensus/ethash/consensus.go | 7 +- consensus/misc/dao.go | 5 +- core/blockchain.go | 188 ++++++++---- core/blockchain_test.go | 2 +- core/evm.go | 5 +- core/genesis.go | 41 ++- core/state/dump.go | 1 - core/state/state_object.go | 23 +- core/state/state_test.go | 15 +- core/state/statedb.go | 38 ++- core/state/statedb_fuzz_test.go | 3 +- core/state/statedb_test.go | 55 ++-- core/state/sync_test.go | 3 +- core/state/trie_prefetcher_test.go | 7 +- core/state_processor.go | 21 +- core/state_transition.go | 30 +- core/tracing/hooks.go | 275 ++++++++++++++++++ core/txpool/blobpool/blobpool_test.go | 41 +-- core/txpool/legacypool/legacypool2_test.go | 13 +- core/txpool/legacypool/legacypool_test.go | 13 +- core/vm/contract.go | 17 +- core/vm/contracts.go | 6 +- core/vm/contracts_fuzz_test.go | 2 +- core/vm/contracts_test.go | 8 +- core/vm/errors.go | 120 ++++++++ core/vm/evm.go | 185 +++++++----- core/vm/instructions.go | 46 ++- core/vm/interface.go | 5 +- core/vm/interpreter.go | 94 ++++-- core/vm/logger.go | 43 --- core/vm/operations_acl.go | 3 +- core/vm/runtime/runtime.go | 9 + core/vm/runtime/runtime_test.go | 14 +- eth/api_backend.go | 2 +- eth/api_debug_test.go | 3 +- eth/backend.go | 13 + eth/ethconfig/config.go | 4 + eth/state_accessor.go | 4 +- eth/tracers/api.go | 65 +++-- eth/tracers/api_test.go | 5 +- eth/tracers/{tracers.go => dir.go} | 49 +--- eth/tracers/internal/tracetest/README.md | 10 + .../internal/tracetest/calltrace_test.go | 72 +++-- .../internal/tracetest/flat_calltrace_test.go | 17 +- eth/tracers/internal/tracetest/makeTest.js | 48 +++ .../internal/tracetest/prestate_test.go | 10 +- .../testdata/call_tracer/inner_instafail.json | 12 +- .../callcode_precompiled_fail_hide.json | 17 +- .../call_tracer_flat/inner_instafail.json | 16 +- .../nested_create_inerror.json | 15 +- .../call_tracer_flat/selfdestruct.json | 17 +- .../skip_no_balance_error.json | 15 +- .../frontier_create_outofstorage.json | 189 ++++++++++++ .../prestate_tracer/create_create.json | 62 ++++ eth/tracers/internal/tracetest/util.go | 53 ---- eth/tracers/internal/util.go | 81 ++++++ eth/tracers/internal/util_test.go | 60 ++++ eth/tracers/js/goja.go | 196 ++++++++----- eth/tracers/js/tracer_test.go | 33 ++- eth/tracers/live.go | 31 ++ eth/tracers/live/noop.go | 96 ++++++ eth/tracers/logger/access_list_tracer.go | 32 +- eth/tracers/logger/logger.go | 161 +++++----- eth/tracers/logger/logger_json.go | 56 ++-- eth/tracers/logger/logger_test.go | 4 +- eth/tracers/native/4byte.go | 31 +- eth/tracers/native/call.go | 178 ++++++------ eth/tracers/native/call_flat.go | 76 +++-- eth/tracers/native/mux.go | 116 ++++++-- eth/tracers/native/noop.go | 57 ++-- eth/tracers/native/prestate.go | 190 ++++++------ eth/tracers/tracers_test.go | 40 +-- internal/ethapi/api.go | 46 +-- internal/ethapi/transaction_args.go | 119 ++++---- miner/worker.go | 2 +- tests/block_test_util.go | 3 +- tests/state_test_util.go | 29 +- 95 files changed, 2782 insertions(+), 1267 deletions(-) delete mode 100644 cmd/evm/internal/t8ntool/tracewriter.go create mode 100644 cmd/evm/testdata/31/README.md create mode 100644 cmd/evm/testdata/31/alloc.json create mode 100644 cmd/evm/testdata/31/env.json create mode 100644 cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json create mode 100644 cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl create mode 100644 cmd/evm/testdata/31/txs.json create mode 100644 core/tracing/hooks.go delete mode 100644 core/vm/logger.go rename eth/tracers/{tracers.go => dir.go} (71%) create mode 100644 eth/tracers/internal/tracetest/README.md create mode 100644 eth/tracers/internal/tracetest/makeTest.js create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json create mode 100644 eth/tracers/internal/util.go create mode 100644 eth/tracers/internal/util_test.go create mode 100644 eth/tracers/live.go create mode 100644 eth/tracers/live/noop.go diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index c5d836e0ea61..0275c019bc61 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -26,7 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" @@ -51,7 +51,7 @@ func blockTestCmd(ctx *cli.Context) error { return errors.New("path-to-test argument required") } - var tracer vm.EVMLogger + var tracer *tracing.Hooks // Configure the EVM logger if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(&logger.Config{ diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 0735a05d6ac2..3c09229e1c5c 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -17,7 +17,9 @@ package t8ntool import ( + "encoding/json" "fmt" + "io" "math/big" "github.com/ethereum/go-ethereum/common" @@ -28,9 +30,11 @@ import ( "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/tracing" "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/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -119,7 +123,7 @@ type rejectedTx struct { // Apply applies a set of transactions to a pre-state func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txIt txIterator, miningReward int64, - getTracerFn func(txIndex int, txHash common.Hash) (vm.EVMLogger, error)) (*state.StateDB, *ExecutionResult, []byte, error) { + getTracerFn func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) { // Capture errors for BLOCKHASH operation, if we haven't been supplied the // required blockhashes var hashError error @@ -222,11 +226,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, continue } } - tracer, err := getTracerFn(txIndex, tx.Hash()) + tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash()) if err != nil { return nil, nil, nil, err } - vmConfig.Tracer = tracer + if tracer != nil { + vmConfig.Tracer = tracer.Hooks + } statedb.SetTxContext(tx.Hash(), txIndex) var ( @@ -236,6 +242,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, ) evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) + if tracer != nil && tracer.OnTxStart != nil { + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + } // (ret []byte, usedGas uint64, failed bool, err error) msgResult, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { @@ -243,6 +252,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) gaspool.SetGas(prevGas) + if tracer != nil { + if tracer.OnTxEnd != nil { + tracer.OnTxEnd(nil, err) + } + if err := writeTraceResult(tracer, traceOutput); err != nil { + log.Warn("Error writing tracer output", "err", err) + } + } continue } includedTxs = append(includedTxs, tx) @@ -285,6 +302,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, //receipt.BlockNumber receipt.TransactionIndex = uint(txIndex) receipts = append(receipts, receipt) + if tracer != nil { + if tracer.Hooks.OnTxEnd != nil { + tracer.Hooks.OnTxEnd(receipt, nil) + } + writeTraceResult(tracer, traceOutput) + } } txIndex++ @@ -310,15 +333,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Mul(reward, blockReward) reward.Div(reward, big.NewInt(8)) - statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward)) + statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward), tracing.BalanceIncreaseRewardMineUncle) } - statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward)) + statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward), tracing.BalanceIncreaseRewardMineBlock) } // Apply withdrawals for _, w := range pre.Env.Withdrawals { // Amount is in gwei, turn into wei amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) - statedb.AddBalance(w.Address, uint256.MustFromBig(amount)) + statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal) } // Commit block root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) @@ -361,7 +384,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) - statedb.SetBalance(addr, uint256.MustFromBig(a.Balance)) + statedb.SetBalance(addr, uint256.MustFromBig(a.Balance), tracing.BalanceIncreaseGenesisBalance) for k, v := range a.Storage { statedb.SetState(addr, k, v) } @@ -398,3 +421,16 @@ func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime } return ethash.CalcDifficulty(config, currentTime, parent) } + +func writeTraceResult(tracer *tracers.Tracer, f io.WriteCloser) error { + defer f.Close() + result, err := tracer.GetResult() + if err != nil || result == nil { + return err + } + err = json.NewEncoder(f).Encode(result) + if err != nil { + return err + } + return nil +} diff --git a/cmd/evm/internal/t8ntool/tracewriter.go b/cmd/evm/internal/t8ntool/tracewriter.go deleted file mode 100644 index e4efad112f74..000000000000 --- a/cmd/evm/internal/t8ntool/tracewriter.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2020 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 t8ntool - -import ( - "encoding/json" - "io" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/log" -) - -// traceWriter is an vm.EVMLogger which also holds an inner logger/tracer. -// When the TxEnd event happens, the inner tracer result is written to the file, and -// the file is closed. -type traceWriter struct { - inner vm.EVMLogger - f io.WriteCloser -} - -// Compile-time interface check -var _ = vm.EVMLogger((*traceWriter)(nil)) - -func (t *traceWriter) CaptureTxEnd(restGas uint64) { - t.inner.CaptureTxEnd(restGas) - defer t.f.Close() - - if tracer, ok := t.inner.(tracers.Tracer); ok { - result, err := tracer.GetResult() - if err != nil { - log.Warn("Error in tracer", "err", err) - return - } - err = json.NewEncoder(t.f).Encode(result) - if err != nil { - log.Warn("Error writing tracer output", "err", err) - return - } - } -} - -func (t *traceWriter) CaptureTxStart(gasLimit uint64) { t.inner.CaptureTxStart(gasLimit) } -func (t *traceWriter) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.inner.CaptureStart(env, from, to, create, input, gas, value) -} - -func (t *traceWriter) CaptureEnd(output []byte, gasUsed uint64, err error) { - t.inner.CaptureEnd(output, gasUsed, err) -} - -func (t *traceWriter) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - t.inner.CaptureEnter(typ, from, to, input, gas, value) -} - -func (t *traceWriter) CaptureExit(output []byte, gasUsed uint64, err error) { - t.inner.CaptureExit(output, gasUsed, err) -} - -func (t *traceWriter) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - t.inner.CaptureState(pc, op, gas, cost, scope, rData, depth, err) -} -func (t *traceWriter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { - t.inner.CaptureFault(pc, op, gas, cost, scope, depth, err) -} diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index a9489d069a70..5aa554e13359 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "math/big" "os" "path/filepath" @@ -80,7 +81,7 @@ type input struct { } func Transition(ctx *cli.Context) error { - var getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { return nil, nil } + var getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { return nil, nil, nil } baseDir, err := createBasedir(ctx) if err != nil { @@ -95,28 +96,35 @@ func Transition(ctx *cli.Context) error { EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name), Debug: true, } - getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { + getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) if err != nil { - return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) + return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } - return &traceWriter{logger.NewJSONLogger(logConfig, traceFile), traceFile}, nil + logger := logger.NewJSONLogger(logConfig, traceFile) + tracer := &tracers.Tracer{ + Hooks: logger, + // jsonLogger streams out result to file. + GetResult: func() (json.RawMessage, error) { return nil, nil }, + Stop: func(err error) {}, + } + return tracer, traceFile, nil } } else if ctx.IsSet(TraceTracerFlag.Name) { var config json.RawMessage if ctx.IsSet(TraceTracerConfigFlag.Name) { config = []byte(ctx.String(TraceTracerConfigFlag.Name)) } - getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { + getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String()))) if err != nil { - return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) + return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config) if err != nil { - return nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err)) + return nil, nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err)) } - return &traceWriter{tracer, traceFile}, nil + return tracer, traceFile, nil } } // We need to load three things: alloc, env and transactions. May be either in diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index b8e8b542b7e5..7f6f5f6be0fd 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -33,6 +33,7 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" "github.com/ethereum/go-ethereum/eth/tracers/logger" @@ -116,7 +117,7 @@ func runCmd(ctx *cli.Context) error { } var ( - tracer vm.EVMLogger + tracer *tracing.Hooks debugLogger *logger.StructLogger statedb *state.StateDB chainConfig *params.ChainConfig @@ -130,7 +131,7 @@ func runCmd(ctx *cli.Context) error { tracer = logger.NewJSONLogger(logconfig, os.Stdout) } else if ctx.Bool(DebugFlag.Name) { debugLogger = logger.NewStructLogger(logconfig) - tracer = debugLogger + tracer = debugLogger.Hooks() } else { debugLogger = logger.NewStructLogger(logconfig) } diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index aaf2b00f879d..fc2bf8223f30 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -63,7 +63,7 @@ func stateTestCmd(ctx *cli.Context) error { cfg.Tracer = logger.NewJSONLogger(config, os.Stderr) case ctx.Bool(DebugFlag.Name): - cfg.Tracer = logger.NewStructLogger(config) + cfg.Tracer = logger.NewStructLogger(config).Hooks() } // Load the test content from the input file if len(ctx.Args().First()) != 0 { diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index ad36540de56c..7e0bc36cbe40 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -17,9 +17,12 @@ package main import ( + "bufio" "encoding/json" "fmt" + "io" "os" + "path/filepath" "reflect" "strings" "testing" @@ -321,6 +324,107 @@ func TestT8n(t *testing.T) { } } +func lineIterator(path string) func() (string, error) { + data, err := os.ReadFile(path) + if err != nil { + return func() (string, error) { return err.Error(), err } + } + scanner := bufio.NewScanner(strings.NewReader(string(data))) + return func() (string, error) { + if scanner.Scan() { + return scanner.Text(), nil + } + if err := scanner.Err(); err != nil { + return "", err + } + return "", io.EOF // scanner gobbles io.EOF, but we want it + } +} + +// TestT8nTracing is a test that checks the tracing-output from t8n. +func TestT8nTracing(t *testing.T) { + t.Parallel() + tt := new(testT8n) + tt.TestCmd = cmdtest.NewTestCmd(t, tt) + for i, tc := range []struct { + base string + input t8nInput + expExitCode int + extraArgs []string + expectedTraces []string + }{ + { + base: "./testdata/31", + input: t8nInput{ + "alloc.json", "txs.json", "env.json", "Cancun", "", + }, + extraArgs: []string{"--trace"}, + expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl"}, + }, + { + base: "./testdata/31", + input: t8nInput{ + "alloc.json", "txs.json", "env.json", "Cancun", "", + }, + extraArgs: []string{"--trace.tracer", ` +{ + result: function(){ + return "hello world" + }, + fault: function(){} +}`}, + expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json"}, + }, + } { + args := []string{"t8n"} + args = append(args, tc.input.get(tc.base)...) + // Place the output somewhere we can find it + outdir := t.TempDir() + args = append(args, "--output.basedir", outdir) + args = append(args, tc.extraArgs...) + + var qArgs []string // quoted args for debugging purposes + for _, arg := range args { + if len(arg) == 0 { + qArgs = append(qArgs, `""`) + } else { + qArgs = append(qArgs, arg) + } + } + tt.Logf("args: %v\n", strings.Join(qArgs, " ")) + tt.Run("evm-test", args...) + t.Log(string(tt.Output())) + + // Compare the expected traces + for _, traceFile := range tc.expectedTraces { + haveFn := lineIterator(filepath.Join(outdir, traceFile)) + wantFn := lineIterator(filepath.Join(tc.base, traceFile)) + + for line := 0; ; line++ { + want, wErr := wantFn() + have, hErr := haveFn() + if want != have { + t.Fatalf("test %d, trace %v, line %d\nwant: %v\nhave: %v\n", + i, traceFile, line, want, have) + } + if wErr != nil && hErr != nil { + break + } + if wErr != nil { + t.Fatal(wErr) + } + if hErr != nil { + t.Fatal(hErr) + } + t.Logf("%v\n", want) + } + } + if have, want := tt.ExitStatus(), tc.expExitCode; have != want { + t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want) + } + } +} + type t9nInput struct { inTxs string stFork string diff --git a/cmd/evm/testdata/31/README.md b/cmd/evm/testdata/31/README.md new file mode 100644 index 000000000000..305e4f52da07 --- /dev/null +++ b/cmd/evm/testdata/31/README.md @@ -0,0 +1 @@ +This test does some EVM execution, and can be used to test the tracers and trace-outputs. diff --git a/cmd/evm/testdata/31/alloc.json b/cmd/evm/testdata/31/alloc.json new file mode 100644 index 000000000000..bad5481c4a31 --- /dev/null +++ b/cmd/evm/testdata/31/alloc.json @@ -0,0 +1,16 @@ +{ + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x016345785d8a0000", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "0x1111111111111111111111111111111111111111" : { + "balance" : "0x1", + "code" : "0x604060406040604000", + "nonce" : "0x00", + "storage" : { + } + } +} \ No newline at end of file diff --git a/cmd/evm/testdata/31/env.json b/cmd/evm/testdata/31/env.json new file mode 100644 index 000000000000..09b5f12d8834 --- /dev/null +++ b/cmd/evm/testdata/31/env.json @@ -0,0 +1,20 @@ +{ + "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentNumber" : "0x01", + "currentTimestamp" : "0x03e8", + "currentGasLimit" : "0x1000000000", + "previousHash" : "0xe4e2a30b340bec696242b67584264f878600dce98354ae0b6328740fd4ff18da", + "currentDataGasUsed" : "0x2000", + "parentTimestamp" : "0x00", + "parentDifficulty" : "0x00", + "parentUncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "parentBeaconBlockRoot" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "currentRandom" : "0x0000000000000000000000000000000000000000000000000000000000020000", + "withdrawals" : [ + ], + "parentBaseFee" : "0x08", + "parentGasUsed" : "0x00", + "parentGasLimit" : "0x1000000000", + "parentExcessBlobGas" : "0x1000", + "parentBlobGasUsed" : "0x2000" +} \ No newline at end of file diff --git a/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json new file mode 100644 index 000000000000..cd4bc1ab64cc --- /dev/null +++ b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json @@ -0,0 +1 @@ +"hello world" diff --git a/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl new file mode 100644 index 000000000000..26e5c7ee4ef5 --- /dev/null +++ b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl @@ -0,0 +1,6 @@ +{"pc":0,"op":96,"gas":"0x13498","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":96,"gas":"0x13495","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":4,"op":96,"gas":"0x13492","gasCost":"0x3","memSize":0,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":96,"gas":"0x1348f","gasCost":"0x3","memSize":0,"stack":["0x40","0x40","0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":8,"op":0,"gas":"0x1348c","gasCost":"0x0","memSize":0,"stack":["0x40","0x40","0x40","0x40"],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0xc"} diff --git a/cmd/evm/testdata/31/txs.json b/cmd/evm/testdata/31/txs.json new file mode 100644 index 000000000000..473c1526f40b --- /dev/null +++ b/cmd/evm/testdata/31/txs.json @@ -0,0 +1,14 @@ +[ + { + "gas": "0x186a0", + "gasPrice": "0x600", + "input": "0x", + "nonce": "0x0", + "to": "0x1111111111111111111111111111111111111111", + "value": "0x1", + "v" : "0x0", + "r" : "0x0", + "s" : "0x0", + "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + } +] diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 17aab678768d..dc45661eaecb 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -99,6 +99,8 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.MetricsInfluxDBBucketFlag, utils.MetricsInfluxDBOrganizationFlag, utils.TxLookupLimitFlag, + utils.VMTraceFlag, + utils.VMTraceConfigFlag, utils.TransactionHistoryFlag, utils.StateHistoryFlag, }, utils.DatabaseFlags), diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 76c6484fee6a..3f3ed510f355 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -179,6 +179,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { v := ctx.Uint64(utils.OverrideVerkle.Name) cfg.Eth.OverrideVerkle = &v } + backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Create gauge with geth system and build information diff --git a/cmd/geth/main.go b/cmd/geth/main.go index d79d23e22687..8ec70aedf93e 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -42,6 +42,7 @@ import ( // Force-load the tracer engines to trigger registration _ "github.com/ethereum/go-ethereum/eth/tracers/js" + _ "github.com/ethereum/go-ethereum/eth/tracers/live" _ "github.com/ethereum/go-ethereum/eth/tracers/native" "github.com/urfave/cli/v2" @@ -136,6 +137,8 @@ var ( utils.DeveloperGasLimitFlag, utils.DeveloperPeriodFlag, utils.VMEnableDebugFlag, + utils.VMTraceFlag, + utils.VMTraceConfigFlag, utils.NetworkIdFlag, utils.EthStatsURLFlag, utils.NoCompactionFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b38f33b8dd7f..7d78c7b31f49 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -21,6 +21,7 @@ import ( "context" "crypto/ecdsa" "encoding/hex" + "encoding/json" "errors" "fmt" "math" @@ -538,7 +539,16 @@ var ( Usage: "Record information useful for VM and contract debugging", Category: flags.VMCategory, } - + VMTraceFlag = &cli.StringFlag{ + Name: "vmtrace", + Usage: "Name of tracer which should record internal VM operations (costly)", + Category: flags.VMCategory, + } + VMTraceConfigFlag = &cli.StringFlag{ + Name: "vmtrace.config", + Usage: "Tracer configuration (JSON)", + Category: flags.VMCategory, + } // API options. RPCGlobalGasCapFlag = &cli.Uint64Flag{ Name: "rpc.gascap", @@ -1889,6 +1899,18 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil { Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err) } + // VM tracing config. + if ctx.IsSet(VMTraceFlag.Name) { + if name := ctx.String(VMTraceFlag.Name); name != "" { + var config string + if ctx.IsSet(VMTraceConfigFlag.Name) { + config = ctx.String(VMTraceConfigFlag.Name) + } + + cfg.VMTrace = name + cfg.VMTraceConfig = config + } + } } // SetDNSDiscoveryDefaults configures DNS discovery with the given URL if @@ -2167,12 +2189,25 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 } vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} - + if ctx.IsSet(VMTraceFlag.Name) { + if name := ctx.String(VMTraceFlag.Name); name != "" { + var config json.RawMessage + if ctx.IsSet(VMTraceConfigFlag.Name) { + config = json.RawMessage(ctx.String(VMTraceConfigFlag.Name)) + } + t, err := tracers.LiveDirectory.New(name, config) + if err != nil { + Fatalf("Failed to create tracer %q: %v", name, err) + } + vmcfg.Tracer = t + } + } // Disable transaction indexing/unindexing by default. chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil) if err != nil { Fatalf("Can't create BlockChain: %v", err) } + return chain, chainDb } diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 9ffed438a877..4e3fbeb09a7c 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -358,7 +359,7 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. // Convert amount from gwei to wei. amount := new(uint256.Int).SetUint64(w.Amount) amount = amount.Mul(amount, uint256.NewInt(params.GWei)) - state.AddBalance(w.Address, amount) + state.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal) } // No block reward which is issued by consensus layer instead. } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 5299afa610d0..cc19d12a56ae 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -570,7 +571,7 @@ var ( // AccumulateRewards credits the coinbase of the given block with the mining // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. -func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) { +func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, header *types.Header, uncles []*types.Header) { // Select the correct block reward based on chain progression blockReward := FrontierBlockReward if config.IsByzantium(header.Number) { @@ -589,10 +590,10 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header r.Sub(r, hNum) r.Mul(r, blockReward) r.Div(r, u256_8) - state.AddBalance(uncle.Coinbase, r) + stateDB.AddBalance(uncle.Coinbase, r, tracing.BalanceIncreaseRewardMineUncle) r.Div(blockReward, u256_32) reward.Add(reward, r) } - state.AddBalance(header.Coinbase, reward) + stateDB.AddBalance(header.Coinbase, reward, tracing.BalanceIncreaseRewardMineBlock) } diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go index e21a44f63de3..45669d0bcec8 100644 --- a/consensus/misc/dao.go +++ b/consensus/misc/dao.go @@ -22,6 +22,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -81,7 +82,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) { // Move every DAO account and extra-balance account funds into the refund contract for _, addr := range params.DAODrainList() { - statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr)) - statedb.SetBalance(addr, new(uint256.Int)) + statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), tracing.BalanceIncreaseDaoContract) + statedb.SetBalance(addr, new(uint256.Int), tracing.BalanceDecreaseDaoAccount) } } diff --git a/core/blockchain.go b/core/blockchain.go index 1b41d777329e..12fdcf72456c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" @@ -253,6 +254,7 @@ type BlockChain struct { processor Processor // Block transaction processor interface forker *ForkChoice vmConfig vm.Config + logger *tracing.Hooks } // NewBlockChain returns a fully initialised block chain using information @@ -295,6 +297,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit), engine: engine, vmConfig: vmConfig, + logger: vmConfig.Tracer, } bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.forker = NewForkChoice(bc, shouldPreserve) @@ -421,6 +424,25 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } } + if bc.logger != nil && bc.logger.OnBlockchainInit != nil { + bc.logger.OnBlockchainInit(chainConfig) + } + + if bc.logger != nil && bc.logger.OnGenesisBlock != nil { + if block := bc.CurrentBlock(); block.Number.Uint64() == 0 { + alloc, err := getGenesisState(bc.db, block.Hash()) + if err != nil { + return nil, fmt.Errorf("failed to get genesis state: %w", err) + } + + if alloc == nil { + return nil, fmt.Errorf("live blockchain tracer requires genesis alloc to be set") + } + + bc.logger.OnGenesisBlock(bc.genesisBlock, alloc) + } + } + // Load any existing snapshot, regenerating it if loading failed if bc.cacheConfig.SnapshotLimit > 0 { // If the chain was rewound past the snapshot persistent layer (causing @@ -452,6 +474,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } rawdb.WriteChainConfig(db, genesisHash, chainConfig) } + // Start tx indexer if it's enabled. if txLookupLimit != nil { bc.txIndexer = newTxIndexer(*txLookupLimit, bc) @@ -1783,6 +1806,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) return it.index, err } stats.processed++ + if bc.logger != nil && bc.logger.OnSkippedBlock != nil { + bc.logger.OnSkippedBlock(tracing.BlockEvent{ + Block: block, + TD: bc.GetTd(block.ParentHash(), block.NumberU64()-1), + Finalized: bc.CurrentFinalBlock(), + Safe: bc.CurrentSafeBlock(), + }) + } // We can assume that logs are empty here, since the only way for consecutive // Clique blocks to have the same state is if there are no transactions. @@ -1800,6 +1831,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if err != nil { return it.index, err } + statedb.SetLogger(bc.logger) // Enable prefetching to pull in trie node paths while processing transactions statedb.StartPrefetcher("chain") @@ -1813,7 +1845,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) go func(start time.Time, followup *types.Block, throwaway *state.StateDB) { - bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) + // Disable tracing for prefetcher executions. + vmCfg := bc.vmConfig + vmCfg.Tracer = nil + bc.prefetcher.Prefetch(followup, throwaway, vmCfg, &followupInterrupt) blockPrefetchExecuteTimer.Update(time.Since(start)) if followupInterrupt.Load() { @@ -1823,68 +1858,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } } - // Process block using the parent state as reference point - pstart := time.Now() - receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) - if err != nil { - bc.reportBlock(block, receipts, err) - followupInterrupt.Store(true) - return it.index, err - } - ptime := time.Since(pstart) - - vstart := time.Now() - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { - bc.reportBlock(block, receipts, err) - followupInterrupt.Store(true) - return it.index, err - } - vtime := time.Since(vstart) - proctime := time.Since(start) // processing + validation - - // Update the metrics touched during block processing and validation - accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) - storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) - snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) - snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) - accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) - storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) - accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) - storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation) - triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing - trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update - trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read - trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read - blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing - blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation - - // Write the block to the chain and get the status. - var ( - wstart = time.Now() - status WriteStatus - ) - if !setHead { - // Don't set the head, only insert the block - err = bc.writeBlockWithState(block, receipts, statedb) - } else { - status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) - } + // The traced section of block import. + res, err := bc.processBlock(block, statedb, start, setHead) followupInterrupt.Store(true) if err != nil { return it.index, err } - // Update the metrics touched during block commit - accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them - storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them - snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them - triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them - - blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) - blockInsertTimer.UpdateSince(start) - // Report the import stats before returning the various results stats.processed++ - stats.usedGas += usedGas + stats.usedGas += res.usedGas var snapDiffItems, snapBufItems common.StorageSize if bc.snaps != nil { @@ -1896,11 +1878,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if !setHead { // After merge we expect few side chains. Simply count // all blocks the CL gives us for GC processing time - bc.gcproc += proctime - + bc.gcproc += res.procTime return it.index, nil // Direct block insertion of a single block } - switch status { + switch res.status { case CanonStatTy: log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), "uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(), @@ -1910,7 +1891,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) lastCanon = block // Only count canonical blocks for GC processing time - bc.gcproc += proctime + bc.gcproc += res.procTime case SideStatTy: log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), @@ -1931,6 +1912,91 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) return it.index, err } +// blockProcessingResult is a summary of block processing +// used for updating the stats. +type blockProcessingResult struct { + usedGas uint64 + procTime time.Duration + status WriteStatus +} + +// processBlock executes and validates the given block. If there was no error +// it writes the block and associated state to database. +func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, start time.Time, setHead bool) (_ *blockProcessingResult, blockEndErr error) { + if bc.logger != nil && bc.logger.OnBlockStart != nil { + td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) + bc.logger.OnBlockStart(tracing.BlockEvent{ + Block: block, + TD: td, + Finalized: bc.CurrentFinalBlock(), + Safe: bc.CurrentSafeBlock(), + }) + } + if bc.logger != nil && bc.logger.OnBlockEnd != nil { + defer func() { + bc.logger.OnBlockEnd(blockEndErr) + }() + } + + // Process block using the parent state as reference point + pstart := time.Now() + receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) + if err != nil { + bc.reportBlock(block, receipts, err) + return nil, err + } + ptime := time.Since(pstart) + + vstart := time.Now() + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { + bc.reportBlock(block, receipts, err) + return nil, err + } + vtime := time.Since(vstart) + proctime := time.Since(start) // processing + validation + + // Update the metrics touched during block processing and validation + accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) + storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) + snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) + snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) + accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) + storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) + accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) + storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation) + triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing + trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update + trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read + trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read + blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing + blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation + + // Write the block to the chain and get the status. + var ( + wstart = time.Now() + status WriteStatus + ) + if !setHead { + // Don't set the head, only insert the block + err = bc.writeBlockWithState(block, receipts, statedb) + } else { + status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) + } + if err != nil { + return nil, err + } + // Update the metrics touched during block commit + accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them + storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them + snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them + triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them + + blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) + blockInsertTimer.UpdateSince(start) + + return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil +} + // insertSideChain is called when an import batch hits upon a pruned ancestor // error, which happens when a sidechain with a sufficiently old fork-block is // found. diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 4fa759129c9a..f837397a1dd2 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4287,7 +4287,7 @@ func TestEIP3651(t *testing.T) { b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr)}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/evm.go b/core/evm.go index 73f6d7bc20a0..4c12e2aa02c4 100644 --- a/core/evm.go +++ b/core/evm.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/holiman/uint256" @@ -136,6 +137,6 @@ func CanTransfer(db vm.StateDB, addr common.Address, amount *uint256.Int) bool { // Transfer subtracts amount from sender and adds amount to recipient using the given Db func Transfer(db vm.StateDB, sender, recipient common.Address, amount *uint256.Int) { - db.SubBalance(sender, amount) - db.AddBalance(recipient, amount) + db.SubBalance(sender, amount, tracing.BalanceChangeTransfer) + db.AddBalance(recipient, amount, tracing.BalanceChangeTransfer) } diff --git a/core/genesis.go b/core/genesis.go index 3f1fde8dfca4..ee0e322f8013 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -133,7 +134,7 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { } for addr, account := range *ga { if account.Balance != nil { - statedb.AddBalance(addr, uint256.MustFromBig(account.Balance)) + statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), tracing.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) @@ -154,7 +155,9 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa } for addr, account := range *ga { if account.Balance != nil { - statedb.AddBalance(addr, uint256.MustFromBig(account.Balance)) + // This is not actually logged via tracer because OnGenesisBlock + // already captures the allocations. + statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), tracing.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) @@ -181,6 +184,39 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa return nil } +func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) { + blob := rawdb.ReadGenesisStateSpec(db, blockhash) + if len(blob) != 0 { + if err := alloc.UnmarshalJSON(blob); err != nil { + return nil, err + } + + return alloc, nil + } + + // Genesis allocation is missing and there are several possibilities: + // the node is legacy which doesn't persist the genesis allocation or + // the persisted allocation is just lost. + // - supported networks(mainnet, testnets), recover with defined allocations + // - private network, can't recover + var genesis *Genesis + switch blockhash { + case params.MainnetGenesisHash: + genesis = DefaultGenesisBlock() + case params.GoerliGenesisHash: + genesis = DefaultGoerliGenesisBlock() + case params.SepoliaGenesisHash: + genesis = DefaultSepoliaGenesisBlock() + case params.HoleskyGenesisHash: + genesis = DefaultHoleskyGenesisBlock() + } + if genesis != nil { + return genesis.Alloc, nil + } + + return nil, nil +} + // field type overrides for gencodec type genesisSpecMarshaling struct { Nonce math.HexOrDecimal64 @@ -252,6 +288,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g } else { log.Info("Writing custom genesis block") } + applyOverrides(genesis.Config) block, err := genesis.Commit(db, triedb) if err != nil { diff --git a/core/state/dump.go b/core/state/dump.go index 55abb50f1c5a..c9aad4f8e234 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -57,7 +57,6 @@ type DumpAccount struct { Storage map[common.Hash]string `json:"storage,omitempty"` Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode AddressHash hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key - } // Dump represents the full dump in a collected format, as one large map. diff --git a/core/state/state_object.go b/core/state/state_object.go index 6dea68465baa..910f4963411d 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" @@ -240,6 +241,9 @@ func (s *stateObject) SetState(key, value common.Hash) { key: key, prevalue: prev, }) + if s.db.logger != nil && s.db.logger.OnStorageChange != nil { + s.db.logger.OnStorageChange(s.address, key, prev, value) + } s.setState(key, value) } @@ -399,7 +403,7 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) { // AddBalance adds amount to s's balance. // It is used to add funds to the destination account of a transfer. -func (s *stateObject) AddBalance(amount *uint256.Int) { +func (s *stateObject) AddBalance(amount *uint256.Int, reason tracing.BalanceChangeReason) { // EIP161: We must check emptiness for the objects such that the account // clearing (0,0,0 objects) can take effect. if amount.IsZero() { @@ -408,23 +412,26 @@ func (s *stateObject) AddBalance(amount *uint256.Int) { } return } - s.SetBalance(new(uint256.Int).Add(s.Balance(), amount)) + s.SetBalance(new(uint256.Int).Add(s.Balance(), amount), reason) } // SubBalance removes amount from s's balance. // It is used to remove funds from the origin account of a transfer. -func (s *stateObject) SubBalance(amount *uint256.Int) { +func (s *stateObject) SubBalance(amount *uint256.Int, reason tracing.BalanceChangeReason) { if amount.IsZero() { return } - s.SetBalance(new(uint256.Int).Sub(s.Balance(), amount)) + s.SetBalance(new(uint256.Int).Sub(s.Balance(), amount), reason) } -func (s *stateObject) SetBalance(amount *uint256.Int) { +func (s *stateObject) SetBalance(amount *uint256.Int, reason tracing.BalanceChangeReason) { s.db.journal.append(balanceChange{ account: &s.address, prev: new(uint256.Int).Set(s.data.Balance), }) + if s.db.logger != nil && s.db.logger.OnBalanceChange != nil { + s.db.logger.OnBalanceChange(s.address, s.Balance().ToBig(), amount.ToBig(), reason) + } s.setBalance(amount) } @@ -502,6 +509,9 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { prevhash: s.CodeHash(), prevcode: prevcode, }) + if s.db.logger != nil && s.db.logger.OnCodeChange != nil { + s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), prevcode, codeHash, code) + } s.setCode(codeHash, code) } @@ -516,6 +526,9 @@ func (s *stateObject) SetNonce(nonce uint64) { account: &s.address, prev: s.data.Nonce, }) + if s.db.logger != nil && s.db.logger.OnNonceChange != nil { + s.db.logger.OnNonceChange(s.address, s.data.Nonce, nonce) + } s.setNonce(nonce) } diff --git a/core/state/state_test.go b/core/state/state_test.go index 9be610f962d5..c6e6db906e8c 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -49,11 +50,11 @@ func TestDump(t *testing.T) { // generate a few entries obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(uint256.NewInt(22)) + obj1.AddBalance(uint256.NewInt(22), tracing.BalanceChangeUnspecified) obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02})) - obj3.SetBalance(uint256.NewInt(44)) + obj3.SetBalance(uint256.NewInt(44), tracing.BalanceChangeUnspecified) // write some of them to the trie s.state.updateStateObject(obj1) @@ -106,13 +107,13 @@ func TestIterativeDump(t *testing.T) { // generate a few entries obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(uint256.NewInt(22)) + obj1.AddBalance(uint256.NewInt(22), tracing.BalanceChangeUnspecified) obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02})) - obj3.SetBalance(uint256.NewInt(44)) + obj3.SetBalance(uint256.NewInt(44), tracing.BalanceChangeUnspecified) obj4 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x00})) - obj4.AddBalance(uint256.NewInt(1337)) + obj4.AddBalance(uint256.NewInt(1337), tracing.BalanceChangeUnspecified) // write some of them to the trie s.state.updateStateObject(obj1) @@ -208,7 +209,7 @@ func TestSnapshot2(t *testing.T) { // db, trie are already non-empty values so0 := state.getStateObject(stateobjaddr0) - so0.SetBalance(uint256.NewInt(42)) + so0.SetBalance(uint256.NewInt(42), tracing.BalanceChangeUnspecified) so0.SetNonce(43) so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) so0.selfDestructed = false @@ -220,7 +221,7 @@ func TestSnapshot2(t *testing.T) { // and one with deleted == true so1 := state.getStateObject(stateobjaddr1) - so1.SetBalance(uint256.NewInt(52)) + so1.SetBalance(uint256.NewInt(52), tracing.BalanceChangeUnspecified) so1.SetNonce(53) so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) so1.selfDestructed = true diff --git a/core/state/statedb.go b/core/state/statedb.go index f90b30f3994e..24914927c29b 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -19,12 +19,14 @@ package state import ( "fmt" + "math/big" "sort" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" @@ -56,6 +58,7 @@ type StateDB struct { prefetcher *triePrefetcher trie Trie hasher crypto.KeccakState + logger *tracing.Hooks snaps *snapshot.Tree // Nil if snapshot is not available snap snapshot.Snapshot // Nil if snapshot is not available @@ -165,6 +168,11 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) return sdb, nil } +// SetLogger sets the logger for account update hooks. +func (s *StateDB) SetLogger(l *tracing.Hooks) { + s.logger = l +} + // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. @@ -205,6 +213,9 @@ func (s *StateDB) AddLog(log *types.Log) { log.TxHash = s.thash log.TxIndex = uint(s.txIndex) log.Index = s.logSize + if s.logger != nil && s.logger.OnLog != nil { + s.logger.OnLog(log) + } s.logs[s.thash] = append(s.logs[s.thash], log) s.logSize++ } @@ -366,25 +377,25 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool { */ // AddBalance adds amount to the account associated with addr. -func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int) { +func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) { stateObject := s.getOrNewStateObject(addr) if stateObject != nil { - stateObject.AddBalance(amount) + stateObject.AddBalance(amount, reason) } } // SubBalance subtracts amount from the account associated with addr. -func (s *StateDB) SubBalance(addr common.Address, amount *uint256.Int) { +func (s *StateDB) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) { stateObject := s.getOrNewStateObject(addr) if stateObject != nil { - stateObject.SubBalance(amount) + stateObject.SubBalance(amount, reason) } } -func (s *StateDB) SetBalance(addr common.Address, amount *uint256.Int) { +func (s *StateDB) SetBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) { stateObject := s.getOrNewStateObject(addr) if stateObject != nil { - stateObject.SetBalance(amount) + stateObject.SetBalance(amount, reason) } } @@ -440,13 +451,20 @@ func (s *StateDB) SelfDestruct(addr common.Address) { if stateObject == nil { return } + var ( + prev = new(uint256.Int).Set(stateObject.Balance()) + n = new(uint256.Int) + ) s.journal.append(selfDestructChange{ account: &addr, prev: stateObject.selfDestructed, - prevbalance: new(uint256.Int).Set(stateObject.Balance()), + prevbalance: prev, }) + if s.logger != nil && s.logger.OnBalanceChange != nil && prev.Sign() > 0 { + s.logger.OnBalanceChange(addr, prev.ToBig(), n.ToBig(), tracing.BalanceDecreaseSelfdestruct) + } stateObject.markSelfdestructed() - stateObject.data.Balance = new(uint256.Int) + stateObject.data.Balance = n } func (s *StateDB) Selfdestruct6780(addr common.Address) { @@ -823,6 +841,10 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) { obj.deleted = true + // If ether was sent to account post-selfdestruct it is burnt. + if bal := obj.Balance(); s.logger != nil && s.logger.OnBalanceChange != nil && obj.selfDestructed && bal.Sign() != 0 { + s.logger.OnBalanceChange(obj.address, bal.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn) + } // We need to maintain account deletions explicitly (will remain // set indefinitely). Note only the first occurred self-destruct // event is tracked. diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index b416bcf1f312..65cf278108f5 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" @@ -61,7 +62,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction { name: "SetBalance", fn: func(a testAction, s *StateDB) { - s.SetBalance(addr, uint256.NewInt(uint64(a.args[0]))) + s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])), tracing.BalanceChangeUnspecified) }, args: make([]int64, 1), }, diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 3649b0ac589b..bc8c63447963 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" @@ -56,7 +57,7 @@ func TestUpdateLeaks(t *testing.T) { // Update it with some accounts for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) - state.AddBalance(addr, uint256.NewInt(uint64(11*i))) + state.AddBalance(addr, uint256.NewInt(uint64(11*i)), tracing.BalanceChangeUnspecified) state.SetNonce(addr, uint64(42*i)) if i%2 == 0 { state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) @@ -91,7 +92,7 @@ func TestIntermediateLeaks(t *testing.T) { finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil) modify := func(state *StateDB, addr common.Address, i, tweak byte) { - state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak))) + state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak)), tracing.BalanceChangeUnspecified) state.SetNonce(addr, uint64(42*i+tweak)) if i%2 == 0 { state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) @@ -167,7 +168,7 @@ func TestCopy(t *testing.T) { for i := byte(0); i < 255; i++ { obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i})) - obj.AddBalance(uint256.NewInt(uint64(i))) + obj.AddBalance(uint256.NewInt(uint64(i)), tracing.BalanceChangeUnspecified) orig.updateStateObject(obj) } orig.Finalise(false) @@ -184,9 +185,9 @@ func TestCopy(t *testing.T) { copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i})) ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i})) - origObj.AddBalance(uint256.NewInt(2 * uint64(i))) - copyObj.AddBalance(uint256.NewInt(3 * uint64(i))) - ccopyObj.AddBalance(uint256.NewInt(4 * uint64(i))) + origObj.AddBalance(uint256.NewInt(2*uint64(i)), tracing.BalanceChangeUnspecified) + copyObj.AddBalance(uint256.NewInt(3*uint64(i)), tracing.BalanceChangeUnspecified) + ccopyObj.AddBalance(uint256.NewInt(4*uint64(i)), tracing.BalanceChangeUnspecified) orig.updateStateObject(origObj) copy.updateStateObject(copyObj) @@ -266,14 +267,14 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { { name: "SetBalance", fn: func(a testAction, s *StateDB) { - s.SetBalance(addr, uint256.NewInt(uint64(a.args[0]))) + s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])), tracing.BalanceChangeUnspecified) }, args: make([]int64, 1), }, { name: "AddBalance", fn: func(a testAction, s *StateDB) { - s.AddBalance(addr, uint256.NewInt(uint64(a.args[0]))) + s.AddBalance(addr, uint256.NewInt(uint64(a.args[0])), tracing.BalanceChangeUnspecified) }, args: make([]int64, 1), }, @@ -536,7 +537,7 @@ func TestTouchDelete(t *testing.T) { s.state, _ = New(root, s.state.db, s.state.snaps) snapshot := s.state.Snapshot() - s.state.AddBalance(common.Address{}, new(uint256.Int)) + s.state.AddBalance(common.Address{}, new(uint256.Int), tracing.BalanceChangeUnspecified) if len(s.state.journal.dirties) != 1 { t.Fatal("expected one dirty state object") @@ -552,7 +553,7 @@ func TestTouchDelete(t *testing.T) { func TestCopyOfCopy(t *testing.T) { state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) addr := common.HexToAddress("aaaa") - state.SetBalance(addr, uint256.NewInt(42)) + state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { t.Fatalf("1st copy fail, expected 42, got %v", got) @@ -575,9 +576,9 @@ func TestCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -648,9 +649,9 @@ func TestCopyCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -717,9 +718,9 @@ func TestCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -766,7 +767,7 @@ func TestDeleteCreateRevert(t *testing.T) { state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) addr := common.BytesToAddress([]byte("so")) - state.SetBalance(addr, uint256.NewInt(1)) + state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) root, _ := state.Commit(0, false) state, _ = New(root, state.db, state.snaps) @@ -776,7 +777,7 @@ func TestDeleteCreateRevert(t *testing.T) { state.Finalise(true) id := state.Snapshot() - state.SetBalance(addr, uint256.NewInt(2)) + state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified) state.RevertToSnapshot(id) // Commit the entire state and make sure we don't crash and have the correct state @@ -818,10 +819,10 @@ func testMissingTrieNodes(t *testing.T, scheme string) { state, _ := New(types.EmptyRootHash, db, nil) addr := common.BytesToAddress([]byte("so")) { - state.SetBalance(addr, uint256.NewInt(1)) + state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) state.SetCode(addr, []byte{1, 2, 3}) a2 := common.BytesToAddress([]byte("another")) - state.SetBalance(a2, uint256.NewInt(100)) + state.SetBalance(a2, uint256.NewInt(100), tracing.BalanceChangeUnspecified) state.SetCode(a2, []byte{1, 2, 4}) root, _ = state.Commit(0, false) t.Logf("root: %x", root) @@ -846,7 +847,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { t.Errorf("expected %d, got %d", exp, got) } // Modify the state - state.SetBalance(addr, uint256.NewInt(2)) + state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified) root, err := state.Commit(0, false) if err == nil { t.Fatalf("expected error, got root :%x", root) @@ -1114,13 +1115,13 @@ func TestResetObject(t *testing.T) { slotB = common.HexToHash("0x2") ) // Initialize account with balance and storage in first transaction. - state.SetBalance(addr, uint256.NewInt(1)) + state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) state.SetState(addr, slotA, common.BytesToHash([]byte{0x1})) state.IntermediateRoot(true) // Reset account and mutate balance and storages state.CreateAccount(addr) - state.SetBalance(addr, uint256.NewInt(2)) + state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified) state.SetState(addr, slotB, common.BytesToHash([]byte{0x2})) root, _ := state.Commit(0, true) @@ -1146,7 +1147,7 @@ func TestDeleteStorage(t *testing.T) { addr = common.HexToAddress("0x1") ) // Initialize account and populate storage - state.SetBalance(addr, uint256.NewInt(1)) + state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) state.CreateAccount(addr) for i := 0; i < 1000; i++ { slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32()) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 052c166578f7..b7039c9e1cb7 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -61,7 +62,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, c obj := state.getOrNewStateObject(common.BytesToAddress([]byte{i})) acc := &testAccount{address: common.BytesToAddress([]byte{i})} - obj.AddBalance(uint256.NewInt(uint64(11 * i))) + obj.AddBalance(uint256.NewInt(uint64(11*i)), tracing.BalanceChangeUnspecified) acc.balance = uint256.NewInt(uint64(11 * i)) obj.SetNonce(uint64(42 * i)) diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index 711ec832505a..a616adf98f3a 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/holiman/uint256" ) @@ -35,9 +36,9 @@ func filledStateDB() *StateDB { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie for i := 0; i < 100; i++ { sk := common.BigToHash(big.NewInt(int64(i))) state.SetState(addr, sk, sk) // Change the storage trie diff --git a/core/state_processor.go b/core/state_processor.go index 9c8beaa7f5cc..b1a8938f677a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -67,6 +67,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) ) + // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) @@ -86,7 +87,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.SetTxContext(tx.Hash(), i) - receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) + + receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -104,7 +106,18 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return receipts, allLogs, *usedGas, nil } -func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { +// ApplyTransactionWithEVM attempts to apply a transaction to the given state database +// and uses the input parameters for its environment similar to ApplyTransaction. However, +// this method takes an already created EVM instance as input. +func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { + if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil { + evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + if evm.Config.Tracer.OnTxEnd != nil { + defer func() { + evm.Config.Tracer.OnTxEnd(receipt, err) + }() + } + } // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) @@ -126,7 +139,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta // Create a new receipt for the transaction, storing the intermediate root and gas used // by the tx. - receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas} + receipt = &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas} if result.Failed() { receipt.Status = types.ReceiptStatusFailed } else { @@ -167,7 +180,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo blockContext := NewEVMBlockContext(header, bc, author) txContext := NewEVMTxContext(msg) vmenv := vm.NewEVM(blockContext, txContext, statedb, config, cfg) - return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) + return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) } // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root diff --git a/core/state_transition.go b/core/state_transition.go index 8fcf4c093dbc..a52e24dc4395 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" cmath "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto/kzg4844" @@ -263,11 +264,15 @@ func (st *StateTransition) buyGas() error { if err := st.gp.SubGas(st.msg.GasLimit); err != nil { return err } + + if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil { + st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance) + } st.gasRemaining = st.msg.GasLimit st.initialGas = st.msg.GasLimit mgvalU256, _ := uint256.FromBig(mgval) - st.state.SubBalance(st.msg.From, mgvalU256) + st.state.SubBalance(st.msg.From, mgvalU256, tracing.BalanceDecreaseGasBuy) return nil } @@ -380,13 +385,6 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, err } - if tracer := st.evm.Config.Tracer; tracer != nil { - tracer.CaptureTxStart(st.initialGas) - defer func() { - tracer.CaptureTxEnd(st.gasRemaining) - }() - } - var ( msg = st.msg sender = vm.AccountRef(msg.From) @@ -402,6 +400,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { if st.gasRemaining < gas { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas) } + if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { + t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas) + } st.gasRemaining -= gas // Check clause 6 @@ -456,7 +457,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } else { fee := new(uint256.Int).SetUint64(st.gasUsed()) fee.Mul(fee, effectiveTipU256) - st.state.AddBalance(st.evm.Context.Coinbase, fee) + st.state.AddBalance(st.evm.Context.Coinbase, fee, tracing.BalanceIncreaseRewardTransactionFee) } return &ExecutionResult{ @@ -473,12 +474,21 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { if refund > st.state.GetRefund() { refund = st.state.GetRefund() } + + if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 { + st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, tracing.GasChangeTxRefunds) + } + st.gasRemaining += refund // Return ETH for remaining gas, exchanged at the original rate. remaining := uint256.NewInt(st.gasRemaining) remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) - st.state.AddBalance(st.msg.From, remaining) + st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn) + + if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 { + st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, tracing.GasChangeTxLeftOverReturned) + } // Also return remaining gas to the block gas counter so it is // available for the next transaction. diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go new file mode 100644 index 000000000000..48cb4d20275c --- /dev/null +++ b/core/tracing/hooks.go @@ -0,0 +1,275 @@ +// Copyright 2024 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 tracing + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" +) + +// OpContext provides the context at which the opcode is being +// executed in, including the memory, stack and various contract-level information. +type OpContext interface { + MemoryData() []byte + StackData() []uint256.Int + Caller() common.Address + Address() common.Address + CallValue() *uint256.Int + CallInput() []byte +} + +// StateDB gives tracers access to the whole state. +type StateDB interface { + GetBalance(common.Address) *uint256.Int + GetNonce(common.Address) uint64 + GetCode(common.Address) []byte + GetState(common.Address, common.Hash) common.Hash + Exist(common.Address) bool + GetRefund() uint64 +} + +// VMContext provides the context for the EVM execution. +type VMContext struct { + Coinbase common.Address + BlockNumber *big.Int + Time uint64 + Random *common.Hash + // Effective tx gas price + GasPrice *big.Int + ChainConfig *params.ChainConfig + StateDB StateDB +} + +// BlockEvent is emitted upon tracing an incoming block. +// It contains the block as well as consensus related information. +type BlockEvent struct { + Block *types.Block + TD *big.Int + Finalized *types.Header + Safe *types.Header +} + +type ( + /* + - VM events - + */ + + // TxStartHook is called before the execution of a transaction starts. + // Call simulations don't come with a valid signature. `from` field + // to be used for address of the caller. + TxStartHook = func(vm *VMContext, tx *types.Transaction, from common.Address) + + // TxEndHook is called after the execution of a transaction ends. + TxEndHook = func(receipt *types.Receipt, err error) + + // EnterHook is invoked when the processing of a message starts. + EnterHook = func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) + + // ExitHook is invoked when the processing of a message ends. + // `revert` is true when there was an error during the execution. + // Exceptionally, before the homestead hardfork a contract creation that + // ran out of gas when attempting to persist the code to database did not + // count as a call failure and did not cause a revert of the call. This will + // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. + ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool) + + // OpcodeHook is invoked just prior to the execution of an opcode. + OpcodeHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, rData []byte, depth int, err error) + + // FaultHook is invoked when an error occurs during the execution of an opcode. + FaultHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, depth int, err error) + + // GasChangeHook is invoked when the gas changes. + GasChangeHook = func(old, new uint64, reason GasChangeReason) + + /* + - Chain events - + */ + + // BlockchainInitHook is called when the blockchain is initialized. + BlockchainInitHook = func(chainConfig *params.ChainConfig) + + // BlockStartHook is called before executing `block`. + // `td` is the total difficulty prior to `block`. + BlockStartHook = func(event BlockEvent) + + // BlockEndHook is called after executing a block. + BlockEndHook = func(err error) + + // SkippedBlockHook indicates a block was skipped during processing + // due to it being known previously. This can happen e.g. when recovering + // from a crash. + SkippedBlockHook = func(event BlockEvent) + + // GenesisBlockHook is called when the genesis block is being processed. + GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc) + + /* + - State events - + */ + + // BalanceChangeHook is called when the balance of an account changes. + BalanceChangeHook = func(addr common.Address, prev, new *big.Int, reason BalanceChangeReason) + + // NonceChangeHook is called when the nonce of an account changes. + NonceChangeHook = func(addr common.Address, prev, new uint64) + + // CodeChangeHook is called when the code of an account changes. + CodeChangeHook = func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) + + // StorageChangeHook is called when the storage of an account changes. + StorageChangeHook = func(addr common.Address, slot common.Hash, prev, new common.Hash) + + // LogHook is called when a log is emitted. + LogHook = func(log *types.Log) +) + +type Hooks struct { + // VM events + OnTxStart TxStartHook + OnTxEnd TxEndHook + OnEnter EnterHook + OnExit ExitHook + OnOpcode OpcodeHook + OnFault FaultHook + OnGasChange GasChangeHook + // Chain events + OnBlockchainInit BlockchainInitHook + OnBlockStart BlockStartHook + OnBlockEnd BlockEndHook + OnSkippedBlock SkippedBlockHook + OnGenesisBlock GenesisBlockHook + // State events + OnBalanceChange BalanceChangeHook + OnNonceChange NonceChangeHook + OnCodeChange CodeChangeHook + OnStorageChange StorageChangeHook + OnLog LogHook +} + +// BalanceChangeReason is used to indicate the reason for a balance change, useful +// for tracing and reporting. +type BalanceChangeReason byte + +const ( + BalanceChangeUnspecified BalanceChangeReason = 0 + + // Issuance + // BalanceIncreaseRewardMineUncle is a reward for mining an uncle block. + BalanceIncreaseRewardMineUncle BalanceChangeReason = 1 + // BalanceIncreaseRewardMineBlock is a reward for mining a block. + BalanceIncreaseRewardMineBlock BalanceChangeReason = 2 + // BalanceIncreaseWithdrawal is ether withdrawn from the beacon chain. + BalanceIncreaseWithdrawal BalanceChangeReason = 3 + // BalanceIncreaseGenesisBalance is ether allocated at the genesis block. + BalanceIncreaseGenesisBalance BalanceChangeReason = 4 + + // Transaction fees + // BalanceIncreaseRewardTransactionFee is the transaction tip increasing block builder's balance. + BalanceIncreaseRewardTransactionFee BalanceChangeReason = 5 + // BalanceDecreaseGasBuy is spent to purchase gas for execution a transaction. + // Part of this gas will be burnt as per EIP-1559 rules. + BalanceDecreaseGasBuy BalanceChangeReason = 6 + // BalanceIncreaseGasReturn is ether returned for unused gas at the end of execution. + BalanceIncreaseGasReturn BalanceChangeReason = 7 + + // DAO fork + // BalanceIncreaseDaoContract is ether sent to the DAO refund contract. + BalanceIncreaseDaoContract BalanceChangeReason = 8 + // BalanceDecreaseDaoAccount is ether taken from a DAO account to be moved to the refund contract. + BalanceDecreaseDaoAccount BalanceChangeReason = 9 + + // BalanceChangeTransfer is ether transferred via a call. + // it is a decrease for the sender and an increase for the recipient. + BalanceChangeTransfer BalanceChangeReason = 10 + // BalanceChangeTouchAccount is a transfer of zero value. It is only there to + // touch-create an account. + BalanceChangeTouchAccount BalanceChangeReason = 11 + + // BalanceIncreaseSelfdestruct is added to the recipient as indicated by a selfdestructing account. + BalanceIncreaseSelfdestruct BalanceChangeReason = 12 + // BalanceDecreaseSelfdestruct is deducted from a contract due to self-destruct. + BalanceDecreaseSelfdestruct BalanceChangeReason = 13 + // BalanceDecreaseSelfdestructBurn is ether that is sent to an already self-destructed + // account within the same tx (captured at end of tx). + // Note it doesn't account for a self-destruct which appoints itself as recipient. + BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14 +) + +// GasChangeReason is used to indicate the reason for a gas change, useful +// for tracing and reporting. +// +// There is essentially two types of gas changes, those that can be emitted once per transaction +// and those that can be emitted on a call basis, so possibly multiple times per transaction. +// +// They can be recognized easily by their name, those that start with `GasChangeTx` are emitted +// once per transaction, while those that start with `GasChangeCall` are emitted on a call basis. +type GasChangeReason byte + +const ( + GasChangeUnspecified GasChangeReason = 0 + + // GasChangeTxInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only + // one such gas change per transaction. + GasChangeTxInitialBalance GasChangeReason = 1 + // GasChangeTxIntrinsicGas is the amount of gas that will be charged for the intrinsic cost of the transaction, there is + // always exactly one of those per transaction. + GasChangeTxIntrinsicGas GasChangeReason = 2 + // GasChangeTxRefunds is the sum of all refunds which happened during the tx execution (e.g. storage slot being cleared) + // this generates an increase in gas. There is at most one of such gas change per transaction. + GasChangeTxRefunds GasChangeReason = 3 + // GasChangeTxLeftOverReturned is the amount of gas left over at the end of transaction's execution that will be returned + // to the chain. This change will always be a negative change as we "drain" left over gas towards 0. If there was no gas + // left at the end of execution, no such even will be emitted. The returned gas's value in Wei is returned to caller. + // There is at most one of such gas change per transaction. + GasChangeTxLeftOverReturned GasChangeReason = 4 + + // GasChangeCallInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only + // one such gas change per call. + GasChangeCallInitialBalance GasChangeReason = 5 + // GasChangeCallLeftOverReturned is the amount of gas left over that will be returned to the caller, this change will always + // be a negative change as we "drain" left over gas towards 0. If there was no gas left at the end of execution, no such even + // will be emitted. + GasChangeCallLeftOverReturned GasChangeReason = 6 + // GasChangeCallLeftOverRefunded is the amount of gas that will be refunded to the call after the child call execution it + // executed completed. This value is always positive as we are giving gas back to the you, the left over gas of the child. + // If there was no gas left to be refunded, no such even will be emitted. + GasChangeCallLeftOverRefunded GasChangeReason = 7 + // GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE. + GasChangeCallContractCreation GasChangeReason = 8 + // GasChangeContractCreation is the amount of gas that will be burned for a CREATE2. + GasChangeCallContractCreation2 GasChangeReason = 9 + // GasChangeCallCodeStorage is the amount of gas that will be charged for code storage. + GasChangeCallCodeStorage GasChangeReason = 10 + // GasChangeCallOpCode is the amount of gas that will be charged for an opcode executed by the EVM, exact opcode that was + // performed can be check by `OnOpcode` handling. + GasChangeCallOpCode GasChangeReason = 11 + // GasChangeCallPrecompiledContract is the amount of gas that will be charged for a precompiled contract execution. + GasChangeCallPrecompiledContract GasChangeReason = 12 + // GasChangeCallStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules. + GasChangeCallStorageColdAccess GasChangeReason = 13 + // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert. + GasChangeCallFailedExecution GasChangeReason = 14 + + // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as + // it will be "manually" tracked by a direct emit of the gas change event. + GasChangeIgnored GasChangeReason = 0xFF +) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 279750c73f2a..85e13980bee6 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -35,6 +35,7 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -545,19 +546,19 @@ func TestOpenDrops(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3) - statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), uint256.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2) - statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000)) - statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), uint256.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), uint256.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -676,7 +677,7 @@ func TestOpenIndex(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr, uint256.NewInt(1_000_000_000)) + statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -776,9 +777,9 @@ func TestOpenHeap(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000)) - statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000)) - statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000)) + statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -856,9 +857,9 @@ func TestOpenCap(t *testing.T) { for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} { // Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000)) - statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000)) - statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000)) + statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -1272,7 +1273,7 @@ func TestAdd(t *testing.T) { addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey) // Seed the state database with this account - statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance)) + statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance), tracing.BalanceChangeUnspecified) statedb.SetNonce(addrs[acc], seed.nonce) // Sign the seed transactions and store them in the data store @@ -1352,7 +1353,7 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) { if err != nil { b.Fatal(err) } - statedb.AddBalance(addr, uint256.NewInt(1_000_000_000)) + statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) pool.add(tx) } statedb.Commit(0, true) diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index c8d3a76b83ff..fd961d1d925c 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" @@ -50,7 +51,7 @@ func fillPool(t testing.TB, pool *LegacyPool) { nonExecutableTxs := types.Transactions{} for i := 0; i < 384; i++ { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(10000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(10000000000), tracing.BalanceChangeUnspecified) // Add executable ones for j := 0; j < int(pool.config.AccountSlots); j++ { executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key)) @@ -92,7 +93,7 @@ func TestTransactionFutureAttack(t *testing.T) { // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), tracing.BalanceChangeUnspecified) futureTxs := types.Transactions{} for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key)) @@ -129,7 +130,7 @@ func TestTransactionFuture1559(t *testing.T) { // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), tracing.BalanceChangeUnspecified) futureTxs := types.Transactions{} for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key)) @@ -183,7 +184,7 @@ func TestTransactionZAttack(t *testing.T) { for j := 0; j < int(pool.config.GlobalQueue); j++ { futureTxs := types.Transactions{} key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), tracing.BalanceChangeUnspecified) futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key)) pool.addRemotesSync(futureTxs) } @@ -191,7 +192,7 @@ func TestTransactionZAttack(t *testing.T) { overDraftTxs := types.Transactions{} { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), tracing.BalanceChangeUnspecified) for j := 0; j < int(pool.config.GlobalSlots); j++ { overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) } @@ -228,7 +229,7 @@ func BenchmarkFutureAttack(b *testing.B) { fillPool(b, pool) key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), tracing.BalanceChangeUnspecified) futureTxs := types.Transactions{} for n := 0; n < b.N; n++ { diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 7ffbf745bb8e..68d7b6f411fa 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -33,6 +33,7 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -253,7 +254,7 @@ func (c *testChain) State() (*state.StateDB, error) { c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) // simulate that the new head block included tx0 and tx1 c.statedb.SetNonce(c.address, 2) - c.statedb.SetBalance(c.address, new(uint256.Int).SetUint64(params.Ether)) + c.statedb.SetBalance(c.address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified) *c.trigger = false } return stdb, nil @@ -273,7 +274,7 @@ func TestStateChangeDuringReset(t *testing.T) { ) // setup pool with 2 transaction in it - statedb.SetBalance(address, new(uint256.Int).SetUint64(params.Ether)) + statedb.SetBalance(address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified) blockchain := &testChain{newTestBlockChain(params.TestChainConfig, 1000000000, statedb, new(event.Feed)), address, &trigger} tx0 := transaction(0, 100000, key) @@ -307,7 +308,7 @@ func TestStateChangeDuringReset(t *testing.T) { func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) { pool.mu.Lock() - pool.currentState.AddBalance(addr, uint256.MustFromBig(amount)) + pool.currentState.AddBalance(addr, uint256.MustFromBig(amount), tracing.BalanceChangeUnspecified) pool.mu.Unlock() } @@ -468,7 +469,7 @@ func TestChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - statedb.AddBalance(addr, uint256.NewInt(100000000000000)) + statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -497,7 +498,7 @@ func TestDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - statedb.AddBalance(addr, uint256.NewInt(100000000000000)) + statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -2660,7 +2661,7 @@ func BenchmarkMultiAccountBatchInsert(b *testing.B) { for i := 0; i < b.N; i++ { key, _ := crypto.GenerateKey() account := crypto.PubkeyToAddress(key.PublicKey) - pool.currentState.AddBalance(account, uint256.NewInt(1000000)) + pool.currentState.AddBalance(account, uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) tx := transaction(uint64(0), 100000, key) batches[i] = tx } diff --git a/core/vm/contract.go b/core/vm/contract.go index 16b669ebca27..4e28260a67b7 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -18,6 +18,7 @@ package vm import ( "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/holiman/uint256" ) @@ -157,14 +158,28 @@ func (c *Contract) Caller() common.Address { } // UseGas attempts the use gas and subtracts it and returns true on success -func (c *Contract) UseGas(gas uint64) (ok bool) { +func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) { if c.Gas < gas { return false } + if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { + logger.OnGasChange(c.Gas, c.Gas-gas, reason) + } c.Gas -= gas return true } +// RefundGas refunds gas to the contract +func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) { + if gas == 0 { + return + } + if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { + logger.OnGasChange(c.Gas, c.Gas+gas, reason) + } + c.Gas += gas +} + // Address returns the contracts address func (c *Contract) Address() common.Address { return c.self.Address() diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 33a867654e71..a6af31f58456 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/blake2b" "github.com/ethereum/go-ethereum/crypto/bls12381" @@ -168,11 +169,14 @@ func ActivePrecompiles(rules params.Rules) []common.Address { // - the returned bytes, // - the _remaining_ gas, // - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { +func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas } + if logger != nil && logger.OnGasChange != nil { + logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract) + } suppliedGas -= gasCost output, err := p.Run(input) return output, suppliedGas, err diff --git a/core/vm/contracts_fuzz_test.go b/core/vm/contracts_fuzz_test.go index 87c1fff7cc81..1e5cc8007471 100644 --- a/core/vm/contracts_fuzz_test.go +++ b/core/vm/contracts_fuzz_test.go @@ -36,7 +36,7 @@ func FuzzPrecompiledContracts(f *testing.F) { return } inWant := string(input) - RunPrecompiledContract(p, input, gas) + RunPrecompiledContract(p, input, gas, nil) if inHave := string(input); inWant != inHave { t.Errorf("Precompiled %v modified input data", a) } diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index fc30541d4596..6608ff09fcfb 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -98,7 +98,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) { in := common.Hex2Bytes(test.Input) gas := p.RequiredGas(in) t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { - if res, _, err := RunPrecompiledContract(p, in, gas); err != nil { + if res, _, err := RunPrecompiledContract(p, in, gas, nil); err != nil { t.Error(err) } else if common.Bytes2Hex(res) != test.Expected { t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res)) @@ -120,7 +120,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) { gas := p.RequiredGas(in) - 1 t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { - _, _, err := RunPrecompiledContract(p, in, gas) + _, _, err := RunPrecompiledContract(p, in, gas, nil) if err.Error() != "out of gas" { t.Errorf("Expected error [out of gas], got [%v]", err) } @@ -137,7 +137,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing in := common.Hex2Bytes(test.Input) gas := p.RequiredGas(in) t.Run(test.Name, func(t *testing.T) { - _, _, err := RunPrecompiledContract(p, in, gas) + _, _, err := RunPrecompiledContract(p, in, gas, nil) if err.Error() != test.ExpectedError { t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err) } @@ -169,7 +169,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) { bench.ResetTimer() for i := 0; i < bench.N; i++ { copy(data, in) - res, _, err = RunPrecompiledContract(p, data, reqGas) + res, _, err = RunPrecompiledContract(p, data, reqGas, nil) } bench.StopTimer() elapsed := uint64(time.Since(start)) diff --git a/core/vm/errors.go b/core/vm/errors.go index 004f8ef1c83c..ba3261c797fc 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -19,6 +19,7 @@ package vm import ( "errors" "fmt" + "math" ) // List evm execution errors @@ -70,3 +71,122 @@ type ErrInvalidOpCode struct { } func (e *ErrInvalidOpCode) Error() string { return fmt.Sprintf("invalid opcode: %s", e.opcode) } + +// rpcError is the same interface as the one defined in rpc/errors.go +// but we do not want to depend on rpc package here so we redefine it. +// +// It's used to ensure that the VMError implements the RPC error interface. +type rpcError interface { + Error() string // returns the message + ErrorCode() int // returns the code +} + +var _ rpcError = (*VMError)(nil) + +// VMError wraps a VM error with an additional stable error code. The error +// field is the original error that caused the VM error and must be one of the +// VM error defined at the top of this file. +// +// If the error is not one of the known error above, the error code will be +// set to VMErrorCodeUnknown. +type VMError struct { + error + code int +} + +func VMErrorFromErr(err error) error { + if err == nil { + return nil + } + + return &VMError{ + error: err, + code: vmErrorCodeFromErr(err), + } +} + +func (e *VMError) Error() string { + return e.error.Error() +} + +func (e *VMError) Unwrap() error { + return e.error +} + +func (e *VMError) ErrorCode() int { + return e.code +} + +const ( + // We start the error code at 1 so that we can use 0 later for some possible extension. There + // is no unspecified value for the code today because it should always be set to a valid value + // that could be VMErrorCodeUnknown if the error is not mapped to a known error code. + + VMErrorCodeOutOfGas = 1 + iota + VMErrorCodeCodeStoreOutOfGas + VMErrorCodeDepth + VMErrorCodeInsufficientBalance + VMErrorCodeContractAddressCollision + VMErrorCodeExecutionReverted + VMErrorCodeMaxCodeSizeExceeded + VMErrorCodeInvalidJump + VMErrorCodeWriteProtection + VMErrorCodeReturnDataOutOfBounds + VMErrorCodeGasUintOverflow + VMErrorCodeInvalidCode + VMErrorCodeNonceUintOverflow + VMErrorCodeStackUnderflow + VMErrorCodeStackOverflow + VMErrorCodeInvalidOpCode + + // VMErrorCodeUnknown explicitly marks an error as unknown, this is useful when error is converted + // from an actual `error` in which case if the mapping is not known, we can use this value to indicate that. + VMErrorCodeUnknown = math.MaxInt - 1 +) + +func vmErrorCodeFromErr(err error) int { + switch { + case errors.Is(err, ErrOutOfGas): + return VMErrorCodeOutOfGas + case errors.Is(err, ErrCodeStoreOutOfGas): + return VMErrorCodeCodeStoreOutOfGas + case errors.Is(err, ErrDepth): + return VMErrorCodeDepth + case errors.Is(err, ErrInsufficientBalance): + return VMErrorCodeInsufficientBalance + case errors.Is(err, ErrContractAddressCollision): + return VMErrorCodeContractAddressCollision + case errors.Is(err, ErrExecutionReverted): + return VMErrorCodeExecutionReverted + case errors.Is(err, ErrMaxCodeSizeExceeded): + return VMErrorCodeMaxCodeSizeExceeded + case errors.Is(err, ErrInvalidJump): + return VMErrorCodeInvalidJump + case errors.Is(err, ErrWriteProtection): + return VMErrorCodeWriteProtection + case errors.Is(err, ErrReturnDataOutOfBounds): + return VMErrorCodeReturnDataOutOfBounds + case errors.Is(err, ErrGasUintOverflow): + return VMErrorCodeGasUintOverflow + case errors.Is(err, ErrInvalidCode): + return VMErrorCodeInvalidCode + case errors.Is(err, ErrNonceUintOverflow): + return VMErrorCodeNonceUintOverflow + + default: + // Dynamic errors + if v := (*ErrStackUnderflow)(nil); errors.As(err, &v) { + return VMErrorCodeStackUnderflow + } + + if v := (*ErrStackOverflow)(nil); errors.As(err, &v) { + return VMErrorCodeStackOverflow + } + + if v := (*ErrInvalidOpCode)(nil); errors.As(err, &v) { + return VMErrorCodeInvalidOpCode + } + + return VMErrorCodeUnknown + } +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 16cc8549080a..25b5bc84e8bd 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -17,10 +17,12 @@ package vm import ( + "errors" "math/big" "sync/atomic" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" @@ -177,6 +179,13 @@ func (evm *EVM) Interpreter() *EVMInterpreter { // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { + // Capture the tracer start/end events in debug mode + if evm.Config.Tracer != nil { + evm.captureBegin(evm.depth, CALL, caller.Address(), addr, input, gas, value.ToBig()) + defer func(startGas uint64) { + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) + }(gas) + } // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -187,44 +196,18 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } snapshot := evm.StateDB.Snapshot() p, isPrecompile := evm.precompile(addr) - debug := evm.Config.Tracer != nil if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.IsZero() { - // Calling a non existing account, don't do anything, but ping the tracer - if debug { - if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value.ToBig()) - evm.Config.Tracer.CaptureEnd(ret, 0, nil) - } else { - evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value.ToBig()) - evm.Config.Tracer.CaptureExit(ret, 0, nil) - } - } + // Calling a non-existing account, don't do anything. return nil, gas, nil } evm.StateDB.CreateAccount(addr) } evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) - // Capture the tracer start/end events in debug mode - if debug { - if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value.ToBig()) - defer func(startGas uint64) { // Lazy evaluation of the parameters - evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err) - }(gas) - } else { - // Handle tracer events for entering and exiting a call frame - evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value.ToBig()) - defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) - }(gas) - } - } - if isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -242,11 +225,15 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } } // When an error was returned by the EVM or when setting the creation code - // above we revert to the snapshot and consume any gas remaining. Additionally + // above we revert to the snapshot and consume any gas remaining. Additionally, // when we're in homestead this also counts for code storage gas errors. if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + } + gas = 0 } // TODO: consider clearing up unused snapshots: @@ -264,6 +251,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { + // Invoke tracer hooks that signal entering/exiting a call frame + if evm.Config.Tracer != nil { + evm.captureBegin(evm.depth, CALLCODE, caller.Address(), addr, input, gas, value.ToBig()) + defer func(startGas uint64) { + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) + }(gas) + } // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -277,17 +271,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } var snapshot = evm.StateDB.Snapshot() - // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Tracer != nil { - evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value.ToBig()) - defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) - }(gas) - } - // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -300,6 +286,10 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + } + gas = 0 } } @@ -312,27 +302,26 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { - // Fail if we're trying to execute above the call depth limit - if evm.depth > int(params.CallCreateDepth) { - return nil, gas, ErrDepth - } - var snapshot = evm.StateDB.Snapshot() - // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { // NOTE: caller must, at all times be a contract. It should never happen // that caller is something other than a Contract. parent := caller.(*Contract) // DELEGATECALL inherits value from parent call - evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value.ToBig()) + evm.captureBegin(evm.depth, DELEGATECALL, caller.Address(), addr, input, gas, parent.value.ToBig()) defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } + // Fail if we're trying to execute above the call depth limit + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + var snapshot = evm.StateDB.Snapshot() // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -344,6 +333,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + } gas = 0 } } @@ -355,6 +347,13 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { + // Invoke tracer hooks that signal entering/exiting a call frame + if evm.Config.Tracer != nil { + evm.captureBegin(evm.depth, STATICCALL, caller.Address(), addr, input, gas, nil) + defer func(startGas uint64) { + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) + }(gas) + } // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -370,18 +369,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, // but is the correct thing to do and matters on other networks, in tests, and potential // future scenarios - evm.StateDB.AddBalance(addr, new(uint256.Int)) - - // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Tracer != nil { - evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) - defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) - }(gas) - } + evm.StateDB.AddBalance(addr, new(uint256.Int), tracing.BalanceChangeTouchAccount) if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' @@ -400,6 +391,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + } + gas = 0 } } @@ -419,7 +414,13 @@ func (c *codeAndHash) Hash() common.Hash { } // create creates a new contract using code as deployment code. -func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) { +func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { + if evm.Config.Tracer != nil { + evm.captureBegin(evm.depth, typ, caller.Address(), address, codeAndHash.code, gas, value.ToBig()) + defer func(startGas uint64) { + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) + }(gas) + } // Depth check execution. Fail if we're trying to execute above the // limit. if evm.depth > int(params.CallCreateDepth) { @@ -441,6 +442,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // Ensure there's no existing contract already at the designated address contractHash := evm.StateDB.GetCodeHash(address) if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) { + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + } + return nil, common.Address{}, 0, ErrContractAddressCollision } // Create a new account on the state @@ -456,15 +461,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, contract := NewContract(caller, AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) - if evm.Config.Tracer != nil { - if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value.ToBig()) - } else { - evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value.ToBig()) - } - } - - ret, err := evm.interpreter.Run(contract, nil, false) + ret, err = evm.interpreter.Run(contract, nil, false) // Check whether the max code size has been exceeded, assign err if the case. if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize { @@ -482,7 +479,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // by the error checking condition below. if err == nil { createDataGas := uint64(len(ret)) * params.CreateDataGas - if contract.UseGas(createDataGas) { + if contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { evm.StateDB.SetCode(address, ret) } else { err = ErrCodeStoreOutOfGas @@ -490,22 +487,15 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } // When an error was returned by the EVM or when setting the creation code - // above we revert to the snapshot and consume any gas remaining. Additionally + // above we revert to the snapshot and consume any gas remaining. Additionally, // when we're in homestead this also counts for code storage gas errors. if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - contract.UseGas(contract.Gas) + contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution) } } - if evm.Config.Tracer != nil { - if evm.depth == 0 { - evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, err) - } else { - evm.Config.Tracer.CaptureExit(ret, gas-contract.Gas, err) - } - } return ret, address, contract.Gas, err } @@ -527,3 +517,44 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment * // ChainConfig returns the environment's chain configuration func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } + +func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) { + tracer := evm.Config.Tracer + if tracer.OnEnter != nil { + tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value) + } + if tracer.OnGasChange != nil { + tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance) + } +} + +func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) { + tracer := evm.Config.Tracer + if leftOverGas != 0 && tracer.OnGasChange != nil { + tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned) + } + var reverted bool + if err != nil { + reverted = true + } + if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) { + reverted = false + } + if tracer.OnExit != nil { + tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) + } +} + +// GetVMContext provides context about the block being executed as well as state +// to the tracers. +func (evm *EVM) GetVMContext() *tracing.VMContext { + return &tracing.VMContext{ + Coinbase: evm.Context.Coinbase, + BlockNumber: evm.Context.BlockNumber, + Time: evm.Context.Time, + Random: evm.Context.Random, + GasPrice: evm.TxContext.GasPrice, + ChainConfig: evm.ChainConfig(), + StateDB: evm.StateDB, + } +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index ac3ea4bcd62b..990bdbf925ad 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -20,6 +20,7 @@ import ( "math" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" @@ -249,7 +250,6 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( if evm.Config.EnablePreimageRecording { evm.StateDB.AddPreimage(interpreter.hasherBuf, data) } - size.SetBytes(interpreter.hasherBuf[:]) return nil, nil } @@ -590,7 +590,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b // reuse size int for stackvalue stackvalue := size - scope.Contract.UseGas(gas) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation) res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract, input, gas, &value) // Push item on the stack based on the returned error. If the ruleset is @@ -605,7 +605,8 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b stackvalue.SetBytes(addr.Bytes()) } scope.Stack.push(&stackvalue) - scope.Contract.Gas += returnGas + + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { interpreter.returnData = res // set REVERT data to return data buffer @@ -628,7 +629,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] ) // Apply EIP150 gas -= gas / 64 - scope.Contract.UseGas(gas) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract, input, gas, @@ -640,7 +641,8 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] stackvalue.SetBytes(addr.Bytes()) } scope.Stack.push(&stackvalue) - scope.Contract.Gas += returnGas + + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { interpreter.returnData = res // set REVERT data to return data buffer @@ -679,7 +681,8 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt if err == nil || err == ErrExecutionReverted { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.Gas += returnGas + + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -711,7 +714,8 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ if err == nil || err == ErrExecutionReverted { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.Gas += returnGas + + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -739,7 +743,8 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext if err == nil || err == ErrExecutionReverted { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.Gas += returnGas + + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -767,7 +772,8 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) if err == nil || err == ErrExecutionReverted { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.Gas += returnGas + + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -802,11 +808,15 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } beneficiary := scope.Stack.pop() balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { - tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) - tracer.CaptureExit([]byte{}, 0, nil) + if tracer.OnEnter != nil { + tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) + } + if tracer.OnExit != nil { + tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) + } } return nil, errStopToken } @@ -817,12 +827,16 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon } beneficiary := scope.Stack.pop() balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance) + interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { - tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) - tracer.CaptureExit([]byte{}, 0, nil) + if tracer.OnEnter != nil { + tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) + } + if tracer.OnExit != nil { + tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) + } } return nil, errStopToken } diff --git a/core/vm/interface.go b/core/vm/interface.go index 25bfa0672067..d7028cc7c7e3 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -29,8 +30,8 @@ import ( type StateDB interface { CreateAccount(common.Address) - SubBalance(common.Address, *uint256.Int) - AddBalance(common.Address, *uint256.Int) + SubBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason) + AddBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason) GetBalance(common.Address) *uint256.Int GetNonce(common.Address) uint64 diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 1968289f4eaa..8b7f8b02bda5 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -19,16 +19,18 @@ package vm import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" + "github.com/holiman/uint256" ) // Config are the configuration options for the Interpreter type Config struct { - Tracer EVMLogger // Opcode logger - NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) - EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages - ExtraEips []int // Additional EIPS that are to be enabled + Tracer *tracing.Hooks + NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) + EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages + ExtraEips []int // Additional EIPS that are to be enabled } // ScopeContext contains the things that are per-call, such as stack and memory, @@ -39,6 +41,45 @@ type ScopeContext struct { Contract *Contract } +// MemoryData returns the underlying memory slice. Callers must not modify the contents +// of the returned data. +func (ctx *ScopeContext) MemoryData() []byte { + if ctx.Memory == nil { + return nil + } + return ctx.Memory.Data() +} + +// MemoryData returns the stack data. Callers must not modify the contents +// of the returned data. +func (ctx *ScopeContext) StackData() []uint256.Int { + if ctx.Stack == nil { + return nil + } + return ctx.Stack.Data() +} + +// Caller returns the current caller. +func (ctx *ScopeContext) Caller() common.Address { + return ctx.Contract.Caller() +} + +// Address returns the address where this scope of execution is taking place. +func (ctx *ScopeContext) Address() common.Address { + return ctx.Contract.Address() +} + +// CallValue returns the value supplied with this call. +func (ctx *ScopeContext) CallValue() *uint256.Int { + return ctx.Contract.Value() +} + +// CallInput returns the input/calldata with this call. Callers must not modify +// the contents of the returned data. +func (ctx *ScopeContext) CallInput() []byte { + return ctx.Contract.Input +} + // EVMInterpreter represents an EVM interpreter type EVMInterpreter struct { evm *EVM @@ -146,8 +187,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( res []byte // result of the opcode execution function debug = in.evm.Config.Tracer != nil ) - // Don't move this deferred function, it's placed before the capturestate-deferred method, - // so that it gets executed _after_: the capturestate needs the stacks before + // Don't move this deferred function, it's placed before the OnOpcode-deferred method, + // so that it gets executed _after_: the OnOpcode needs the stacks before // they are returned to the pools defer func() { returnStack(stack) @@ -155,13 +196,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( contract.Input = input if debug { - defer func() { - if err != nil { - if !logged { - in.evm.Config.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) - } else { - in.evm.Config.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err) - } + defer func() { // this deferred method handles exit-with-error + if err == nil { + return + } + if !logged && in.evm.Config.Tracer.OnOpcode != nil { + in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + } + if logged && in.evm.Config.Tracer.OnFault != nil { + in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) } }() } @@ -185,9 +228,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } else if sLen > operation.maxStack { return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} } - if !contract.UseGas(cost) { + if !contract.UseGas(cost, in.evm.Config.Tracer, tracing.GasChangeIgnored) { return nil, ErrOutOfGas } + if operation.dynamicGas != nil { // All ops with a dynamic memory usage also has a dynamic gas cost. var memorySize uint64 @@ -211,21 +255,33 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( var dynamicCost uint64 dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) cost += dynamicCost // for tracing - if err != nil || !contract.UseGas(dynamicCost) { + if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, tracing.GasChangeIgnored) { return nil, ErrOutOfGas } + // Do tracing before memory expansion if debug { - in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) - logged = true + if in.evm.Config.Tracer.OnGasChange != nil { + in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) + } + if in.evm.Config.Tracer.OnOpcode != nil { + in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + logged = true + } } if memorySize > 0 { mem.Resize(memorySize) } } else if debug { - in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) - logged = true + if in.evm.Config.Tracer.OnGasChange != nil { + in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) + } + if in.evm.Config.Tracer.OnOpcode != nil { + in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + logged = true + } } + // execute the operation res, err = operation.execute(&pc, in, callContext) if err != nil { diff --git a/core/vm/logger.go b/core/vm/logger.go deleted file mode 100644 index 2667908a84d1..000000000000 --- a/core/vm/logger.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015 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 vm - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -// EVMLogger is used to collect execution traces from an EVM transaction -// execution. CaptureState is called for each step of the VM with the -// current VM state. -// Note that reference types are actual VM data structures; make copies -// if you need to retain them beyond the current call. -type EVMLogger interface { - // Transaction level - CaptureTxStart(gasLimit uint64) - CaptureTxEnd(restGas uint64) - // Top call frame - CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - CaptureEnd(output []byte, gasUsed uint64, err error) - // Rest of call frames - CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) - CaptureExit(output []byte, gasUsed uint64, err error) - // Opcode level - CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) - CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) -} diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index f420a241058b..289da44be3aa 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/params" ) @@ -169,7 +170,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc { evm.StateDB.AddAddressToAccessList(addr) // Charge the remaining difference here already, to correctly calculate available // gas for call - if !contract.UseGas(coldCost) { + if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { return 0, ErrOutOfGas } } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 46f2bb5d5f64..b587d6d5a044 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -123,6 +123,9 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { sender = vm.AccountRef(cfg.Origin) rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) + if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { + cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) + } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) @@ -156,6 +159,9 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { sender = vm.AccountRef(cfg.Origin) rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) + if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { + cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) + } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) @@ -184,6 +190,9 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er statedb = cfg.State rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) + if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { + cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) + } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index b9e3c8ed661c..45228e78c41a 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -336,7 +336,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode b.Fatal(err) } cfg.EVMConfig = vm.Config{ - Tracer: tracer, + Tracer: tracer.Hooks, } } var ( @@ -511,7 +511,7 @@ func TestEip2929Cases(t *testing.T) { code, ops) Execute(code, nil, &Config{ EVMConfig: vm.Config{ - Tracer: logger.NewMarkdownLogger(nil, os.Stdout), + Tracer: logger.NewMarkdownLogger(nil, os.Stdout).Hooks(), ExtraEips: []int{2929}, }, }) @@ -664,7 +664,7 @@ func TestColdAccountAccessCost(t *testing.T) { tracer := logger.NewStructLogger(nil) Execute(tc.code, nil, &Config{ EVMConfig: vm.Config{ - Tracer: tracer, + Tracer: tracer.Hooks(), }, }) have := tracer.StructLogs()[tc.step].GasCost @@ -812,7 +812,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.PUSH1), 0, byte(vm.RETURN), } - depressedCode := []byte{ + suicideCode := []byte{ byte(vm.PUSH1), 0xaa, byte(vm.SELFDESTRUCT), } @@ -825,7 +825,7 @@ func TestRuntimeJSTracer(t *testing.T) { statedb.SetCode(common.HexToAddress("0xcc"), calleeCode) statedb.SetCode(common.HexToAddress("0xdd"), calleeCode) statedb.SetCode(common.HexToAddress("0xee"), calleeCode) - statedb.SetCode(common.HexToAddress("0xff"), depressedCode) + statedb.SetCode(common.HexToAddress("0xff"), suicideCode) tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) if err != nil { @@ -835,7 +835,7 @@ func TestRuntimeJSTracer(t *testing.T) { GasLimit: 1000000, State: statedb, EVMConfig: vm.Config{ - Tracer: tracer, + Tracer: tracer.Hooks, }}) if err != nil { t.Fatal("didn't expect error", err) @@ -869,7 +869,7 @@ func TestJSTracerCreateTx(t *testing.T) { _, _, _, err = Create(code, &Config{ State: statedb, EVMConfig: vm.Config{ - Tracer: tracer, + Tracer: tracer.Hooks, }}) if err != nil { t.Fatal(err) diff --git a/eth/api_backend.go b/eth/api_backend.go index 48c46447c5a0..a97942599c97 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -420,6 +420,6 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re return b.eth.stateAtBlock(ctx, block, reexec, base, readOnly, preferDisk) } -func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) } diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index 671e935beb13..1d75c4c041b0 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/triedb" @@ -73,7 +74,7 @@ func TestAccountRange(t *testing.T) { hash := common.HexToHash(fmt.Sprintf("%x", i)) addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes()) addrs[i] = addr - sdb.SetBalance(addrs[i], uint256.NewInt(1)) + sdb.SetBalance(addrs[i], uint256.NewInt(1), tracing.BalanceChangeUnspecified) if _, ok := m[addr]; ok { t.Fatalf("bad") } else { diff --git a/eth/backend.go b/eth/backend.go index 81d84028a5f8..e6f9c05950d8 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -18,6 +18,7 @@ package eth import ( + "encoding/json" "errors" "fmt" "math/big" @@ -42,6 +43,7 @@ import ( "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -199,6 +201,17 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { StateScheme: scheme, } ) + if config.VMTrace != "" { + var traceConfig json.RawMessage + if config.VMTraceConfig != "" { + traceConfig = json.RawMessage(config.VMTraceConfig) + } + t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig) + if err != nil { + return nil, fmt.Errorf("Failed to create tracer %s: %v", config.VMTrace, err) + } + vmConfig.Tracer = t + } // Override the chain config with provided settings. var overrides core.ChainOverrides if config.OverrideCancun != nil { diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 420a8b147a7f..fef7f29f4e28 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -141,6 +141,10 @@ type Config struct { // Enables tracking of SHA3 preimages in the VM EnablePreimageRecording bool + // Enables VM tracing + VMTrace string + VMTraceConfig string + // Miscellaneous options DocRoot string `toml:"-"` diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 526361a2b8a6..770532cbfe73 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -217,7 +217,7 @@ func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, reexe } // stateAtTransaction returns the execution environment of a certain transaction. -func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { // Short circuit if it's genesis block. if block.NumberU64() == 0 { return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis") @@ -244,7 +244,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) if idx == txIndex { - return msg, context, statedb, release, nil + return tx, context, statedb, release, nil } // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{}) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 0add06c8f69b..7a7c5e48d901 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "fmt" + "math/big" "os" "runtime" "sync" @@ -86,7 +87,7 @@ type Backend interface { Engine() consensus.Engine ChainDb() ethdb.Database StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) - StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) + StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) } // API is the collection of tracing APIs exposed over the private debugging endpoint. @@ -277,14 +278,12 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed TxIndex: i, TxHash: tx.Hash(), } - res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) + res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config) if err != nil { task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()} log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) break } - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number())) task.results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res} } // Tracing state is used up, queue it for de-referencing. Note the @@ -598,7 +597,6 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac var ( txs = block.Transactions() blockHash = block.Hash() - is158 = api.backend.ChainConfig().IsEIP158(block.Number()) blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) results = make([]*txTraceResult, len(txs)) @@ -612,14 +610,11 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac TxIndex: i, TxHash: tx.Hash(), } - res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config) + res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config) if err != nil { return nil, err } results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res} - // Finalize the state so any modifications are written to the trie - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(is158) } return results, nil } @@ -659,7 +654,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat // concurrent use. // See: https://github.com/ethereum/go-ethereum/issues/29114 blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) + res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config) if err != nil { results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()} continue @@ -794,7 +789,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) statedb.SetTxContext(tx.Hash(), i) - _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) + vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.From) + vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) + vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) if writer != nil { writer.Flush() } @@ -851,11 +848,15 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * if err != nil { return nil, err } - msg, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec) + tx, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec) if err != nil { return nil, err } defer release() + msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()), block.BaseFee()) + if err != nil { + return nil, err + } txctx := &Context{ BlockHash: blockHash, @@ -863,7 +864,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * TxIndex: int(index), TxHash: hash, } - return api.traceTx(ctx, msg, txctx, vmctx, statedb, config) + return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config) } // TraceCall lets you trace a given eth_call. It collects the structured logs @@ -924,40 +925,49 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc config.BlockOverrides.Apply(&vmctx) } // Execute the trace - msg, err := args.ToMessage(api.backend.RPCGasCap(), vmctx.BaseFee) - if err != nil { + if err := args.CallDefaults(api.backend.RPCGasCap(), vmctx.BaseFee, api.backend.ChainConfig().ChainID); err != nil { return nil, err } - - var traceConfig *TraceConfig + var ( + msg = args.ToMessage(vmctx.BaseFee) + tx = args.ToTransaction() + traceConfig *TraceConfig + ) if config != nil { traceConfig = &config.TraceConfig } - return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig) + return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig) } // traceTx configures a new tracer according to the provided configuration, and // executes the given message in the provided environment. The return value will // be tracer dependent. -func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { +func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { var ( - tracer Tracer - err error - timeout = defaultTraceTimeout - txContext = core.NewEVMTxContext(message) + tracer *Tracer + err error + timeout = defaultTraceTimeout + usedGas uint64 ) if config == nil { config = &TraceConfig{} } // Default tracer is the struct logger - tracer = logger.NewStructLogger(config.Config) - if config.Tracer != nil { + if config.Tracer == nil { + logger := logger.NewStructLogger(config.Config) + tracer = &Tracer{ + Hooks: logger.Hooks(), + GetResult: logger.GetResult, + Stop: logger.Stop, + } + } else { tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig) if err != nil { return nil, err } } - vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true}) + vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: big.NewInt(0)}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) + statedb.SetLogger(tracer.Hooks) // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { @@ -978,7 +988,8 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte // Call Prepare to clear out the statedb access list statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) - if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil { + _, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, vmenv) + if err != nil { return nil, fmt.Errorf("tracing failed: %w", err) } return tracer.GetResult() diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index d8e4b9a4ef3d..3254f4961fc7 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -155,7 +155,7 @@ func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reex return statedb, release, nil } -func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) { +func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) { parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { return nil, vm.BlockContext{}, nil, nil, errBlockNotFound @@ -174,7 +174,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), b.chain, nil) if idx == txIndex { - return msg, context, statedb, release, nil + return tx, context, statedb, release, nil } vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{}) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { @@ -666,7 +666,6 @@ func TestTracingWithOverrides(t *testing.T) { From: &accounts[0].addr, // BLOCKNUMBER PUSH1 MSTORE Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")), - //&hexutil.Bytes{0x43}, // blocknumber }, config: &TraceCallConfig{ BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, diff --git a/eth/tracers/tracers.go b/eth/tracers/dir.go similarity index 71% rename from eth/tracers/tracers.go rename to eth/tracers/dir.go index 7b43b7cf834a..650815350b37 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/dir.go @@ -14,17 +14,14 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package tracers is a manager for transaction tracing engines. package tracers import ( "encoding/json" - "errors" - "fmt" "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/core/tracing" ) // Context contains some contextual infos for a transaction execution that is not @@ -36,17 +33,19 @@ type Context struct { TxHash common.Hash // Hash of the transaction being traced (zero if dangling call) } -// Tracer interface extends vm.EVMLogger and additionally -// allows collecting the tracing result. -type Tracer interface { - vm.EVMLogger - GetResult() (json.RawMessage, error) +// The set of methods that must be exposed by a tracer +// for it to be available through the RPC interface. +// This involves a method to retrieve results and one to +// stop tracing. +type Tracer struct { + *tracing.Hooks + GetResult func() (json.RawMessage, error) // Stop terminates execution of the tracer at the first opportune moment. - Stop(err error) + Stop func(err error) } -type ctorFn func(*Context, json.RawMessage) (Tracer, error) -type jsCtorFn func(string, *Context, json.RawMessage) (Tracer, error) +type ctorFn func(*Context, json.RawMessage) (*Tracer, error) +type jsCtorFn func(string, *Context, json.RawMessage) (*Tracer, error) type elem struct { ctor ctorFn @@ -79,7 +78,7 @@ func (d *directory) RegisterJSEval(f jsCtorFn) { // New returns a new instance of a tracer, by iterating through the // registered lookups. Name is either name of an existing tracer // or an arbitrary JS code. -func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (Tracer, error) { +func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (*Tracer, error) { if elem, ok := d.elems[name]; ok { return elem.ctor(ctx, cfg) } @@ -97,27 +96,3 @@ func (d *directory) IsJS(name string) bool { // JS eval will execute JS code return true } - -const ( - memoryPadLimit = 1024 * 1024 -) - -// GetMemoryCopyPadded returns offset + size as a new slice. -// It zero-pads the slice if it extends beyond memory bounds. -func GetMemoryCopyPadded(m *vm.Memory, offset, size int64) ([]byte, error) { - if offset < 0 || size < 0 { - return nil, errors.New("offset or size must not be negative") - } - if int(offset+size) < m.Len() { // slice fully inside memory - return m.GetCopy(offset, size), nil - } - paddingNeeded := int(offset+size) - m.Len() - if paddingNeeded > memoryPadLimit { - return nil, fmt.Errorf("reached limit for padding memory slice: %d", paddingNeeded) - } - cpy := make([]byte, size) - if overlap := int64(m.Len()) - offset; overlap > 0 { - copy(cpy, m.GetPtr(offset, overlap)) - } - return cpy, nil -} diff --git a/eth/tracers/internal/tracetest/README.md b/eth/tracers/internal/tracetest/README.md new file mode 100644 index 000000000000..8c3d5d275f2c --- /dev/null +++ b/eth/tracers/internal/tracetest/README.md @@ -0,0 +1,10 @@ +# Filling test cases + +To fill test cases for the built-in tracers, the `makeTest.js` script can be used. Given a transaction on a dev/test network, `makeTest.js` will fetch its prestate and then traces with the given configuration. +In the Geth console do: + +```terminal +let tx = '0x...' +loadScript('makeTest.js') +makeTest(tx, { tracer: 'callTracer' }) +``` \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 6216a16ced9c..896d4d8a88d4 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -18,6 +18,7 @@ package tracetest import ( "encoding/json" + "fmt" "math/big" "os" "path/filepath" @@ -31,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "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/eth/tracers" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -141,15 +143,19 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } + + state.StateDB.SetLogger(tracer.Hooks) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer}) + evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { t.Fatalf("failed to execute transaction: %v", err) } + tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) // Retrieve the trace result and compare against the expected. res, err := tracer.GetResult() if err != nil { @@ -245,7 +251,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { if err != nil { b.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer}) + evm := vm.NewEVM(context, txContext, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) snap := state.StateDB.Snapshot() st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if _, err = st.TransitionDb(); err != nil { @@ -260,13 +266,13 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { func TestInternals(t *testing.T) { var ( + config = params.MainnetChainConfig to = common.HexToAddress("0x00000000000000000000000000000000deadbeef") - origin = common.HexToAddress("0x00000000000000000000000000000000feed") - txContext = vm.TxContext{ - Origin: origin, - GasPrice: big.NewInt(1), - } - context = vm.BlockContext{ + originHex = "0x71562b71999873db5b286df957af199ec94617f7" + origin = common.HexToAddress(originHex) + signer = types.LatestSigner(config) + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + context = vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, Coinbase: common.Address{}, @@ -274,9 +280,10 @@ func TestInternals(t *testing.T) { Time: 5, Difficulty: big.NewInt(0x30000), GasLimit: uint64(6000000), + BaseFee: new(big.Int), } ) - mkTracer := func(name string, cfg json.RawMessage) tracers.Tracer { + mkTracer := func(name string, cfg json.RawMessage) *tracers.Tracer { tr, err := tracers.DefaultDirectory.New(name, nil, cfg) if err != nil { t.Fatalf("failed to create call tracer: %v", err) @@ -287,7 +294,7 @@ func TestInternals(t *testing.T) { for _, tc := range []struct { name string code []byte - tracer tracers.Tracer + tracer *tracers.Tracer want string }{ { @@ -301,13 +308,13 @@ func TestInternals(t *testing.T) { byte(vm.CALL), }, tracer: mkTracer("callTracer", nil), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x13880","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0xe01a","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, + want: fmt.Sprintf(`{"from":"%s","gas":"0x13880","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0xe01a","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, originHex), }, { name: "Stack depletion in LOG0", code: []byte{byte(vm.LOG3)}, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x13880","gasUsed":"0x13880","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, + want: fmt.Sprintf(`{"from":"%s","gas":"0x13880","gasUsed":"0x13880","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, originHex), }, { name: "Mem expansion in LOG0", @@ -320,7 +327,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x13880","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","position":"0x0"}],"value":"0x0","type":"CALL"}`, + want: fmt.Sprintf(`{"from":"%s","gas":"0x13880","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","position":"0x0"}],"value":"0x0","type":"CALL"}`, originHex), }, { // Leads to OOM on the prestate tracer @@ -339,7 +346,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("prestateTracer", nil), - want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52647880"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`, + want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex), }, { // CREATE2 which requires padding memory by prestate tracer @@ -358,7 +365,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("prestateTracer", nil), - want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52647880"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0"},"0x91ff9a805d36f54e3e272e230f3e3f5c1b330804":{"balance":"0x0"}}`, + want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex), }, } { t.Run(tc.name, func(t *testing.T) { @@ -372,22 +379,31 @@ func TestInternals(t *testing.T) { }, }, false, rawdb.HashScheme) defer state.Close() - - evm := vm.NewEVM(context, txContext, state.StateDB, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer}) - msg := &core.Message{ - To: &to, - From: origin, - Value: big.NewInt(0), - GasLimit: 80000, - GasPrice: big.NewInt(0), - GasFeeCap: big.NewInt(0), - GasTipCap: big.NewInt(0), - SkipAccountChecks: false, + state.StateDB.SetLogger(tc.tracer.Hooks) + tx, err := types.SignNewTx(key, signer, &types.LegacyTx{ + To: &to, + Value: big.NewInt(0), + Gas: 80000, + GasPrice: big.NewInt(1), + }) + if err != nil { + t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err) + } + txContext := vm.TxContext{ + Origin: origin, + GasPrice: tx.GasPrice(), } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) - if _, err := st.TransitionDb(); err != nil { + evm := vm.NewEVM(context, txContext, state.StateDB, config, vm.Config{Tracer: tc.tracer.Hooks}) + msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0)) + if err != nil { + t.Fatalf("test %v: failed to create message: %v", tc.name, err) + } + tc.tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + if err != nil { t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err) } + tc.tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) // Retrieve the trace result and compare against the expected res, err := tc.tracer.GetResult() if err != nil { diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index abee48891767..cd9791db2a50 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -16,11 +16,9 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" - - // Force-load the native, to trigger registration - "github.com/ethereum/go-ethereum/eth/tracers" ) // flatCallTrace is the result of a callTracerParity run. @@ -103,16 +101,19 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to create call tracer: %v", err) } + + state.StateDB.SetLogger(tracer.Hooks) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } - evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer}) - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - - if _, err = st.TransitionDb(); err != nil { + evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + if err != nil { return fmt.Errorf("failed to execute transaction: %v", err) } + tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) // Retrieve the trace result and compare against the etalon res, err := tracer.GetResult() @@ -124,7 +125,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string return fmt.Errorf("failed to unmarshal trace result: %v", err) } if !jsonEqualFlat(ret, test.Result) { - t.Logf("tracer name: %s", tracerName) + t.Logf("test %s failed", filename) // uncomment this for easier debugging // have, _ := json.MarshalIndent(ret, "", " ") diff --git a/eth/tracers/internal/tracetest/makeTest.js b/eth/tracers/internal/tracetest/makeTest.js new file mode 100644 index 000000000000..306f10719009 --- /dev/null +++ b/eth/tracers/internal/tracetest/makeTest.js @@ -0,0 +1,48 @@ +// makeTest generates a test for the configured tracer by running +// a prestate reassembled and a call trace run, assembling all the +// gathered information into a test case. +var makeTest = function(tx, traceConfig) { + // Generate the genesis block from the block, transaction and prestate data + var block = eth.getBlock(eth.getTransaction(tx).blockHash); + var genesis = eth.getBlock(block.parentHash); + + delete genesis.gasUsed; + delete genesis.logsBloom; + delete genesis.parentHash; + delete genesis.receiptsRoot; + delete genesis.sha3Uncles; + delete genesis.size; + delete genesis.transactions; + delete genesis.transactionsRoot; + delete genesis.uncles; + + genesis.gasLimit = genesis.gasLimit.toString(); + genesis.number = genesis.number.toString(); + genesis.timestamp = genesis.timestamp.toString(); + + genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer"}); + for (var key in genesis.alloc) { + var nonce = genesis.alloc[key].nonce; + if (nonce) { + genesis.alloc[key].nonce = nonce.toString(); + } + } + genesis.config = admin.nodeInfo.protocols.eth.config; + + // Generate the call trace and produce the test input + var result = debug.traceTransaction(tx, traceConfig); + delete result.time; + + console.log(JSON.stringify({ + genesis: genesis, + context: { + number: block.number.toString(), + difficulty: block.difficulty, + timestamp: block.timestamp.toString(), + gasLimit: block.gasLimit.toString(), + miner: block.miner, + }, + input: eth.getRawTransaction(tx), + result: result, + }, null, 2)); +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 38097ff334b2..dee2bf492e5b 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -117,15 +117,19 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } + + state.StateDB.SetLogger(tracer.Hooks) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer}) - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - if _, err = st.TransitionDb(); err != nil { + evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + if err != nil { t.Fatalf("failed to execute transaction: %v", err) } + tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) // Retrieve the trace result and compare against the expected res, err := tracer.GetResult() if err != nil { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json index 9b45b52fe9ad..ed3688a942e1 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json @@ -56,6 +56,16 @@ "value": "0x0", "gas": "0x1f97e", "gasUsed": "0x72de", - "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000" + "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", + "calls": [{ + "from":"0x6c06b16512b332e6cd8293a2974872674716ce18", + "gas":"0x8fc", + "gasUsed":"0x0", + "to":"0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", + "input":"0x", + "error":"insufficient balance for transfer", + "value":"0x14d1120d7b160000", + "type":"CALL" + }] } } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json index c796804a4bcd..a2386ea9c713 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json @@ -63,12 +63,27 @@ "address": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224" }, "traceAddress": [], - "subtraces": 0, + "subtraces": 1, "transactionPosition": 74, "transactionHash": "0x5ef60b27ac971c22a7d484e546e50093ca62300c8986d165154e47773764b6a4", "blockNumber": 1555279, "blockHash": "0xd6c98d1b87dfa92a210d99bad2873adaf0c9e51fe43addc63fd9cca03a5c6f46", "time": "209.346µs" + }, + { + "action": { + "balance": "0x0", + "callType": "callcode", + "from": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224", + "gas": "0xaf64", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x13" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "call" } ] } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json index 4de08f2ccaf1..611e50e2c046 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json @@ -64,9 +64,23 @@ "gasUsed": "0x72de", "output": "0x" }, - "subtraces": 0, + "subtraces": 1, "traceAddress": [], "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x6c06b16512b332e6cd8293a2974872674716ce18", + "gas": "0x8fc", + "to": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", + "value": "0x14d1120d7b160000" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "call" } ] } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json index 28e96684b2df..f3a7d9a94610 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json @@ -70,12 +70,25 @@ "output": "0x" }, "traceAddress": [], - "subtraces": 0, + "subtraces": 1, "transactionPosition": 26, "transactionHash": "0xcb1090fa85d2a3da8326b75333e92b3dca89963c895d9c981bfdaa64643135e4", "blockNumber": 839247, "blockHash": "0xce7ff7d84ca97f0f89d6065e2c12409a795c9f607cdb14aef0713cad5d7e311c", "time": "182.267µs" + }, + { + "action": { + "from": "0x76554b33410b6d90b7dc889bfed0451ad195f27e", + "gas": "0x25a18", + "init": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0xa" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "create" } ] } \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json index 74fd87cc6c4d..3c5d6d9f2b07 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json @@ -63,13 +63,26 @@ "address": "0x1d99a1a3efa9181f540f9e24fa6e4e08eb7844ca" }, "traceAddress": [], - "subtraces": 1, + "subtraces": 2, "transactionPosition": 14, "transactionHash": "0xdd76f02407e2f8329303ba688e111cae4f7008ad0d14d6e42c5698424ea36d79", "blockNumber": 1555146, "blockHash": "0xafb4f1dd27b9054c805acb81a88ed04384788cb31d84164c21874935c81e5c7e", "time": "187.145µs" }, + { + "action": { + "from": "0x1d99a1a3efa9181f540f9e24fa6e4e08eb7844ca", + "gas": "0x50ac", + "init": "0x5a", + "value": "0x1" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "create" + }, { "type": "suicide", "action": { @@ -79,7 +92,7 @@ }, "result": null, "traceAddress": [ - 0 + 1 ], "subtraces": 0, "transactionPosition": 14, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json index 96060d554539..6911ed4b32af 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json @@ -59,12 +59,25 @@ }, "error": "out of gas", "traceAddress": [], - "subtraces": 0, + "subtraces": 1, "transactionPosition": 16, "transactionHash": "0x384487e5ae8d2997aece8e28403d393cb9752425e6de358891bed981c5af1c05", "blockNumber": 1555285, "blockHash": "0x93231d8e9662adb4c5c703583a92c7b3112cd5448f43ab4fa1f0f00a0183ed3f", "time": "665.278µs" + }, + { + "action": { + "from": "0xf84bf5189ccd19f5897739756d214fa0dc099e0d", + "gas": "0x1d5c", + "init": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0xc350" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "create" } ] } \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json new file mode 100644 index 000000000000..c46fe080f7f2 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json @@ -0,0 +1,189 @@ +{ + "genesis": { + "difficulty": "7797655526461", + "extraData": "0xd583010203844765746885676f312e35856c696e7578", + "gasLimit": "3141592", + "hash": "0x4ad333086cb86a6d261329504c9e1ca4d571212f56d6635dd213b700e1e85a6f", + "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226", + "mixHash": "0xdaca4c8bd9a6e6707059736633543ebf50f97c07700a9ed55859b97275c19ea5", + "nonce": "0x894c15d74e8ae8bd", + "number": "469666", + "stateRoot": "0xf9c50965ffae3f99310483a7836c545a025cc680303adaf3671dbeef99edf03a", + "timestamp": "1446318401", + "totalDifficulty": "2462705215747880313", + "alloc": { + "0x0000000000000000000000000000000000000004": { + "balance": "0x0" + }, + "0x0047a8033cc6d6ca2ed5044674fd421f44884de8": { + "balance": "0x44f5ced08fe37cf7", + "nonce": "872" + }, + "0x1d11e5eae3112dbd44f99266872ff1d07c77dce8": { + "balance": "0x0", + "code": "0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806338cc48311461004f578063767800de14610088578063d1d80fdf146100c15761004d565b005b61005c60048050506100ff565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61009560048050506100d9565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100d7600480803590602001909190505061012e565b005b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905061012b565b90565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018a57610002565b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b5056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f631e3b3aafa084bc51c714825aacf505d2059be" + } + }, + "0xe48430c4e88a929bba0ee3dce284866a9937b609": { + "balance": "0x26758774d51d8677a", + "nonce": "261" + }, + "0xf631e3b3aafa084bc51c714825aacf505d2059be": { + "balance": "0x0", + "code": "0x606060405236156100da5760e060020a600035046323dc42e781146100ff5780632ef3accc146101a5578063385928321461021d57806345362978146102b65780634c7737951461034a578063524f38891461035c5780635c242c59146103ad578063772286591461044a5780637e1c42051461052457806381ade30714610601578063a2ec191a14610696578063adf59f991461071b578063ae815843146107b5578063bf1fe4201461084f578063de4b326214610890578063e8025731146108d4578063e839e65e14610970578063fbf8041814610a44575b610b20604051600160a060020a03331690600090349082818181858883f15050505050565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050505050505060008260006000610c0b83335b60006113fd8362030d40846101f5565b6040805160206004803580820135601f8101849004840285018401909552848452610b22949193602493909291840191908190840183828082843750949650509335935050505060006113fd8383335b600160a060020a03811660009081526003602052604081205460ff168114156114b557610b57565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050506000610d5885858585610841565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375050604080516020601f8935808c01359182018390048302840183019094528083529799986044989297509290920194509250829150840183828082843750949650505050505050600082600060006114068333610195565b610b34600154600160a060020a031681565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375094965050505050505060006114008233610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050505b60008360006000610d5f8333610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050505050505060008360006000610cb88333610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505050505b60008460006000610f288333610195565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375050604080516020601f8935808c0135918201839004830284018301909452808352979998604498929750929092019450925082915084018382808284375094965050505050505060006113fd6000848462030d40610439565b6040805160206004803580820135601f8101849004840285018401909552848452610b209491936024939092918401919081908401838280828437509496505093359350505050600254600090600160a060020a039081163391909116148015906107115750600154600160a060020a039081163390911614155b156111fd57610002565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760649791965060249190910194509092508291508401838280828437509496505050505050506000610c0484848462030d40610439565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050505b6000610d5885858585610439565b610b20600435600254600160a060020a039081163391909116148015906108865750600154600160a060020a039081163390911614155b156114b057610002565b610b20600435600254600090600160a060020a039081163391909116148015906108ca5750600154600160a060020a039081163390911614155b1561134d57610002565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760649791965060249190910194509092508291508401838280828437509496505093359350505050600083600060006111618333610195565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375050604080516020601f8935808c01359182018390048302840183019094528083529799986044989297509290920194509250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050505050505060008360006000610b5e8333610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760849791965060249190910194509092508291508401838280828437509496505093359350505050600084600060006112a68333610195565b005b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b93505050505b9392505050565b91508160001415610b8d57600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610bee57604051600160a060020a03331690600090839082818181858883f150505050505b610b51600088888862030d406105f0565b610002565b9050610b57565b91508160001415610c3a57600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610c9b57604051600160a060020a03331690600090839082818181858883f150505050505b610b5187878762030d40610439565b93505050505b949350505050565b91508160001415610ce757600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610d4857604051600160a060020a03331690600090839082818181858883f150505050505b610caa8888888862030d406105f0565b9050610cb0565b91508160001415610d8e57600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610def57604051600160a060020a03331690600090839082818181858883f150505050505b604080516000805442810183528351928390036020908101842060019290920183558184528381018d9052608084018a905260a09484018581528c51958501959095528b519198507f1f28d876aff267c3302a63cd25ebcca53e6f60691049df42275b6d06ab455c679489948e948e948e948e9492606085019260c086019289810192829185918391869190600490601f850104600302600f01f150905090810190601f168015610eb45780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610f0d5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a150610cb0915050565b91508160001415610f5757600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610fb857604051600160a060020a03331690600090839082818181858883f150505050505b60006000505442016040518082815260200191505060405180910390209350835060006000818150548092919060010191905055507f4e65aab8959da44521dc50a6ce3dfbd65016d8cfab70a47ea7541458206c4d5b848a8a8a8a8a604051808781526020018681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561108e5780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110e75780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111405780820380516001836020036101000a031916815260200191505b50995050505050505050505060405180910390a15050505b95945050505050565b9150816000141561119057600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f150505034849003925082111590506111f157604051600160a060020a03331690600090839082818181858883f150505050505b610caa88888888610439565b82604051808280519060200190808383829060006004602084601f0104600302600f01f1506007805491909301849003909320600184018084559095508594509192918391508280158290116112765781836000526020600020918201910161127691905b808211156112a25760008155600101611262565b505050815481101561000257600091825260208083209091019290925591825260069052604090205550565b5090565b915081600014156112d557600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f1505050348490039250821115905061133657604051600160a060020a03331690600090839082818181858883f150505050505b61134389898989896105f0565b9350505050611158565b50600481905560005b6007548110156113f957600780546006916000918490811015610002575080547fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6888501548352602093909352604082205485029260059291908590811015610002579082527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688018150548152602081019190915260400160002055600101611356565b5050565b90505b92915050565b9150816000141561143557600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f1505050348490039250821115905061149657604051600160a060020a03331690600090839082818181858883f150505050505b6114a66000878762030d40610439565b9350505050611400565b600855565b6005600050600085604051808280519060200190808383829060006004602084601f0104600302600f01f1509091018290039091208352505060209190915260409020546008548402019050610b5756", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000004", + "0xde5cab2c6836c23f6388364c9a0e20bd1c8c7e6c3b5d0339cd8a2f7c4b36208c": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0xf65b3b60010d57d0bb8478aa6ced15fe720621b4": { + "balance": "0x2c52a97273d2164" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "shanghaiTime": 1681338455, + "terminalTotalDifficulty": 7797655526461000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "469667", + "difficulty": "7793848077478", + "timestamp": "1446318425", + "gasLimit": "3141592", + "miner": "0xe48430c4e88a929bba0ee3dce284866a9937b609" + }, + "input": "0xf91ec7820368850ba43b7400831b77408080b91e72606060405260018054600160a060020a0319163317905561036f600360609081527f55524c0000000000000000000000000000000000000000000000000000000000608052610120604052604c60a09081527f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707560c0527f626c69632f5469636b65723f706169723d455448584254292e726573756c742e60e0527f58455448585842542e632e3000000000000000000000000000000000000000006101005261037d919062030d417f38cc483100000000000000000000000000000000000000000000000000000000610120908152600090731d11e5eae3112dbd44f99266872ff1d07c77dce89081906338cc4831906101249060209060048188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc8887604051837c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156102255780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f11561000257505060405180517f385928320000000000000000000000000000000000000000000000000000000082526004828101888152606484018a90526080602485018181528d5160848701528d519496508a958e958e958e9594604484019360a40192909181908490829085908e906020601f850104600302600f01f150905090810190601f1680156102e65780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561033f5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151979650505050505050565b611af2806103806000396000f35b5056606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b50561ca083d25971e732af3acb0a223dea6258f37407bf2d075fd852a83312238fca7cdea01f5a1189b054e947a0a140c565c4fc829b584e7348c9a7f65a890fe688e8b67f", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0x0047a8033cc6d6ca2ed5044674fd421f44884de8", + "gas": "0x1b7740", + "gasUsed": "0x9274f", + "input": "0x606060405260018054600160a060020a0319163317905561036f600360609081527f55524c0000000000000000000000000000000000000000000000000000000000608052610120604052604c60a09081527f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707560c0527f626c69632f5469636b65723f706169723d455448584254292e726573756c742e60e0527f58455448585842542e632e3000000000000000000000000000000000000000006101005261037d919062030d417f38cc483100000000000000000000000000000000000000000000000000000000610120908152600090731d11e5eae3112dbd44f99266872ff1d07c77dce89081906338cc4831906101249060209060048188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc8887604051837c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156102255780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f11561000257505060405180517f385928320000000000000000000000000000000000000000000000000000000082526004828101888152606484018a90526080602485018181528d5160848701528d519496508a958e958e958e9594604484019360a40192909181908490829085908e906020601f850104600302600f01f150905090810190601f1680156102e65780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561033f5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151979650505050505050565b611af2806103806000396000f35b5056606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b5056", + "error": "contract creation code storage out of gas", + "calls": [ + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x12c54b", + "gasUsed": "0x106", + "to": "0x1d11e5eae3112dbd44f99266872ff1d07c77dce8", + "input": "0x38cc4831", + "output": "0x000000000000000000000000f631e3b3aafa084bc51c714825aacf505d2059be", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x127270", + "gasUsed": "0x26b", + "to": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "input": "0x2ef3accc00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000030d41000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x18", + "gasUsed": "0x18", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30", + "output": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x124995", + "gasUsed": "0x78f5", + "to": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "input": "0x385928320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000030d41000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e300000000000000000000000000000000000000000", + "output": "0x55bc8431ce52389ac668a9b14a0943290cb7263732251186e960bc8b249b5f32", + "calls": [ + { + "from": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "gas": "0x0", + "gasUsed": "0x0", + "to": "0xf65b3b60010d57d0bb8478aa6ced15fe720621b4", + "input": "0x", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "gas": "0x18", + "gasUsed": "0x18", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30", + "output": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30", + "value": "0x0", + "type": "CALL" + } + ], + "logs":[ + { + "address": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "topics": ["0x1f28d876aff267c3302a63cd25ebcca53e6f60691049df42275b6d06ab455c67"], + "data":"0x55bc8431ce52389ac668a9b14a0943290cb7263732251186e960bc8b249b5f32000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000030d41000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e300000000000000000000000000000000000000000", + "position":"0x3" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CREATE" + } +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json new file mode 100644 index 000000000000..909a1eabe38e --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json @@ -0,0 +1,62 @@ +{ + "genesis": { + "baseFeePerGas": "875000000", + "difficulty": "0", + "extraData": "0xd983010d05846765746888676f312e32312e318664617277696e", + "gasLimit": "11511229", + "hash": "0xd462585c6c5a3b3bf14850ebcde71b6615b9aaf6541403f9a0457212dd0502e0", + "miner": "0x0000000000000000000000000000000000000000", + "mixHash": "0xfa51e868d6a7c0728f18800e4cc8d4cc1c87430cc9975e947eb6c9c03599b4e2", + "nonce": "0x0000000000000000", + "number": "1", + "stateRoot": "0xd2ebe0a7f3572ffe3e5b4c78147376d3fca767f236e4dd23f9151acfec7cb0d1", + "timestamp": "1699617692", + "totalDifficulty": "0", + "withdrawals": [], + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x5208" + }, + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": { + "balance": "0x8ac7230489e80000" + } + }, + "config": { + "chainId": 1337, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "shanghaiTime": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "isDev": true + } + }, + "context": { + "number": "2", + "difficulty": "0", + "timestamp": "1699617847", + "gasLimit": "11522469", + "miner": "0x0000000000000000000000000000000000000000" + }, + "input": "0x02f902b48205398084b2d05e0085011b1f3f8083031ca88080b90258608060405234801561001057600080fd5b5060405161001d906100e3565b604051809103906000f080158015610039573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b039290921691821781556040517fc66247bafd1305823857fb4c3e651e684d918df8554ef560bbbcb025fdd017039190a26000546040516360fe47b160e01b8152600560048201526001600160a01b03909116906360fe47b190602401600060405180830381600087803b1580156100c657600080fd5b505af11580156100da573d6000803e3d6000fd5b505050506100ef565b60ca8061018e83390190565b6091806100fd6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806380de699314602d575b600080fd5b600054603f906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f3fea2646970667358221220dab781465e7f4cf20304cc388130a763508e20edd25b4bc8ea8f57743a0de8da64736f6c634300081700336080604052348015600f57600080fd5b5060ac8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146049575b600080fd5b60476042366004605e565b600055565b005b60005460405190815260200160405180910390f35b600060208284031215606f57600080fd5b503591905056fea264697066735822122049e09da6320793487d58eaa7b97f802618a062cbc35f08ca1ce92c17349141f864736f6c63430008170033c080a01d4fce93ad08bf413052645721f20e6136830cf5a2759fa57e76a134e90899a7a0399a72832d52118991dc04c4f9e1c0fec3d5e441ad7d4b055f0cf03130d8f815", + "result": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x5208" + }, + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": { + "balance": "0x8ac7230489e80000" + } + } +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index 95d292c9240b..1913f352ddb7 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -9,59 +9,6 @@ import ( _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) -// To generate a new callTracer test, copy paste the makeTest method below into -// a Geth console and call it with a transaction hash you which to export. - -/* -// makeTest generates a callTracer test by running a prestate reassembled and a -// call trace run, assembling all the gathered information into a test case. -var makeTest = function(tx, rewind) { - // Generate the genesis block from the block, transaction and prestate data - var block = eth.getBlock(eth.getTransaction(tx).blockHash); - var genesis = eth.getBlock(block.parentHash); - - delete genesis.gasUsed; - delete genesis.logsBloom; - delete genesis.parentHash; - delete genesis.receiptsRoot; - delete genesis.sha3Uncles; - delete genesis.size; - delete genesis.transactions; - delete genesis.transactionsRoot; - delete genesis.uncles; - - genesis.gasLimit = genesis.gasLimit.toString(); - genesis.number = genesis.number.toString(); - genesis.timestamp = genesis.timestamp.toString(); - - genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer", rewind: rewind}); - for (var key in genesis.alloc) { - var nonce = genesis.alloc[key].nonce; - if (nonce) { - genesis.alloc[key].nonce = nonce.toString(); - } - } - genesis.config = admin.nodeInfo.protocols.eth.config; - - // Generate the call trace and produce the test input - var result = debug.traceTransaction(tx, {tracer: "callTracer", rewind: rewind}); - delete result.time; - - console.log(JSON.stringify({ - genesis: genesis, - context: { - number: block.number.toString(), - difficulty: block.difficulty, - timestamp: block.timestamp.toString(), - gasLimit: block.gasLimit.toString(), - miner: block.miner, - }, - input: eth.getRawTransaction(tx), - result: result, - }, null, 2)); -} -*/ - // camel converts a snake cased input string into a camel cased output. func camel(str string) string { pieces := strings.Split(str, "_") diff --git a/eth/tracers/internal/util.go b/eth/tracers/internal/util.go new file mode 100644 index 000000000000..18a372d192a1 --- /dev/null +++ b/eth/tracers/internal/util.go @@ -0,0 +1,81 @@ +// Copyright 2023 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 internal + +import ( + "errors" + "fmt" + + "github.com/holiman/uint256" +) + +const ( + memoryPadLimit = 1024 * 1024 +) + +// GetMemoryCopyPadded returns offset + size as a new slice. +// It zero-pads the slice if it extends beyond memory bounds. +func GetMemoryCopyPadded(m []byte, offset, size int64) ([]byte, error) { + if offset < 0 || size < 0 { + return nil, errors.New("offset or size must not be negative") + } + length := int64(len(m)) + if offset+size < length { // slice fully inside memory + return memoryCopy(m, offset, size), nil + } + paddingNeeded := offset + size - length + if paddingNeeded > memoryPadLimit { + return nil, fmt.Errorf("reached limit for padding memory slice: %d", paddingNeeded) + } + cpy := make([]byte, size) + if overlap := length - offset; overlap > 0 { + copy(cpy, MemoryPtr(m, offset, overlap)) + } + return cpy, nil +} + +func memoryCopy(m []byte, offset, size int64) (cpy []byte) { + if size == 0 { + return nil + } + + if len(m) > int(offset) { + cpy = make([]byte, size) + copy(cpy, m[offset:offset+size]) + + return + } + + return +} + +// MemoryPtr returns a pointer to a slice of memory. +func MemoryPtr(m []byte, offset, size int64) []byte { + if size == 0 { + return nil + } + + if len(m) > int(offset) { + return m[offset : offset+size] + } + + return nil +} + +// Back returns the n'th item in stack +func StackBack(st []uint256.Int, n int) *uint256.Int { + return &st[len(st)-n-1] +} diff --git a/eth/tracers/internal/util_test.go b/eth/tracers/internal/util_test.go new file mode 100644 index 000000000000..6a467314cc86 --- /dev/null +++ b/eth/tracers/internal/util_test.go @@ -0,0 +1,60 @@ +// Copyright 2023 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 internal + +import ( + "testing" + + "github.com/ethereum/go-ethereum/core/vm" +) + +func TestMemCopying(t *testing.T) { + for i, tc := range []struct { + memsize int64 + offset int64 + size int64 + wantErr string + wantSize int + }{ + {0, 0, 100, "", 100}, // Should pad up to 100 + {0, 100, 0, "", 0}, // No need to pad (0 size) + {100, 50, 100, "", 100}, // Should pad 100-150 + {100, 50, 5, "", 5}, // Wanted range fully within memory + {100, -50, 0, "offset or size must not be negative", 0}, // Error + {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Error + {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Error + + } { + mem := vm.NewMemory() + mem.Resize(uint64(tc.memsize)) + cpy, err := GetMemoryCopyPadded(mem.Data(), tc.offset, tc.size) + if want := tc.wantErr; want != "" { + if err == nil { + t.Fatalf("test %d: want '%v' have no error", i, want) + } + if have := err.Error(); want != have { + t.Fatalf("test %d: want '%v' have '%v'", i, want, have) + } + continue + } + if err != nil { + t.Fatalf("test %d: unexpected error: %v", i, err) + } + if want, have := tc.wantSize, len(cpy); have != want { + t.Fatalf("test %d: want %v have %v", i, want, have) + } + } +} diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 07c138bae47b..7e4930f81dbd 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -23,12 +23,16 @@ import ( "math/big" "github.com/dop251/goja" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/internal" + "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers" jsassets "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" ) @@ -41,9 +45,9 @@ func init() { if err != nil { panic(err) } - type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error) + type ctorFn = func(*tracers.Context, json.RawMessage) (*tracers.Tracer, error) lookup := func(code string) ctorFn { - return func(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + return func(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { return newJsTracer(code, ctx, cfg) } } @@ -96,7 +100,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b // JS functions on the relevant EVM hooks. It uses Goja as its JS engine. type jsTracer struct { vm *goja.Runtime - env *vm.EVM + env *tracing.VMContext toBig toBigFn // Converts a hex string into a JS bigint toBuf toBufFn // Converts a []byte into a JS buffer fromBuf fromBufFn // Converts an array, hex string or Uint8Array to a []byte @@ -104,7 +108,6 @@ type jsTracer struct { activePrecompiles []common.Address // List of active precompiles at current block traceStep bool // True if tracer object exposes a `step()` method traceFrame bool // True if tracer object exposes the `enter()` and `exit()` methods - gasLimit uint64 // Amount of gas bought for the whole tx err error // Any error that should stop tracing obj *goja.Object // Trace object @@ -134,7 +137,7 @@ type jsTracer struct { // The methods `result` and `fault` are required to be present. // The methods `step`, `enter`, and `exit` are optional, but note that // `enter` and `exit` always go together. -func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { +func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { vm := goja.New() // By default field names are exported to JS as is, i.e. capitalized. vm.SetFieldNameMapper(goja.UncapFieldNameMapper()) @@ -217,30 +220,62 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracer t.frameValue = t.frame.setupObject() t.frameResultValue = t.frameResult.setupObject() t.logValue = t.log.setupObject() - return t, nil -} -// CaptureTxStart implements the Tracer interface and is invoked at the beginning of + return &tracers.Tracer{ + Hooks: &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil +} + +// OnTxStart implements the Tracer interface and is invoked at the beginning of // transaction processing. -func (t *jsTracer) CaptureTxStart(gasLimit uint64) { - t.gasLimit = gasLimit +func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + t.env = env + // Need statedb access for db object + db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf} + t.dbValue = db.setupObject() + // Update list of precompiles based on current block + rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) + t.activePrecompiles = vm.ActivePrecompiles(rules) + t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64()) + t.ctx["gas"] = t.vm.ToValue(tx.Gas()) + gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String()) + if err != nil { + t.err = err + return + } + t.ctx["gasPrice"] = gasPriceBig } -// CaptureTxEnd implements the Tracer interface and is invoked at the end of +// OnTxEnd implements the Tracer interface and is invoked at the end of // transaction processing. -func (t *jsTracer) CaptureTxEnd(restGas uint64) { - t.ctx["gasUsed"] = t.vm.ToValue(t.gasLimit - restGas) +func (t *jsTracer) OnTxEnd(receipt *types.Receipt, err error) { + if t.err != nil { + return + } + if err != nil { + // Don't override vm error + if _, ok := t.ctx["error"]; !ok { + t.ctx["error"] = t.vm.ToValue(err.Error()) + } + return + } + t.ctx["gasUsed"] = t.vm.ToValue(receipt.GasUsed) } -// CaptureStart implements the Tracer interface to initialize the tracing operation. -func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - cancel := func(err error) { - t.err = err - t.env.Cancel() +// onStart implements the Tracer interface to initialize the tracing operation. +func (t *jsTracer) onStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + if t.err != nil { + return } - t.env = env - db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf} - t.dbValue = db.setupObject() if create { t.ctx["type"] = t.vm.ToValue("CREATE") } else { @@ -248,43 +283,32 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr } fromVal, err := t.toBuf(t.vm, from.Bytes()) if err != nil { - cancel(err) + t.err = err return } t.ctx["from"] = fromVal toVal, err := t.toBuf(t.vm, to.Bytes()) if err != nil { - cancel(err) + t.err = err return } t.ctx["to"] = toVal inputVal, err := t.toBuf(t.vm, input) if err != nil { - cancel(err) + t.err = err return } t.ctx["input"] = inputVal - t.ctx["gas"] = t.vm.ToValue(t.gasLimit) - gasPriceBig, err := t.toBig(t.vm, env.TxContext.GasPrice.String()) - if err != nil { - cancel(err) - return - } - t.ctx["gasPrice"] = gasPriceBig valueBig, err := t.toBig(t.vm, value.String()) if err != nil { - cancel(err) + t.err = err return } t.ctx["value"] = valueBig - t.ctx["block"] = t.vm.ToValue(env.Context.BlockNumber.Uint64()) - // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) } -// CaptureState implements the Tracer interface to trace a single step of VM execution. -func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +// OnOpcode implements the Tracer interface to trace a single step of VM execution. +func (t *jsTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { if !t.traceStep { return } @@ -293,10 +317,10 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope } log := t.log - log.op.op = op - log.memory.memory = scope.Memory - log.stack.stack = scope.Stack - log.contract.contract = scope.Contract + log.op.op = vm.OpCode(op) + log.memory.memory = scope.MemoryData() + log.stack.stack = scope.StackData() + log.contract.scope = scope log.pc = pc log.gas = gas log.cost = cost @@ -308,20 +332,23 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope } } -// CaptureFault implements the Tracer interface to trace an execution fault -func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +// OnFault implements the Tracer interface to trace an execution fault +func (t *jsTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { if t.err != nil { return } - // Other log fields have been already set as part of the last CaptureState. + // Other log fields have been already set as part of the last OnOpcode. t.log.err = err if _, err := t.fault(t.obj, t.logValue, t.dbValue); err != nil { t.onError("fault", err) } } -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { +// onEnd is called after the call finishes to finalize the tracing. +func (t *jsTracer) onEnd(output []byte, gasUsed uint64, err error, reverted bool) { + if t.err != nil { + return + } if err != nil { t.ctx["error"] = t.vm.ToValue(err.Error()) } @@ -333,16 +360,20 @@ func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { t.ctx["output"] = outputVal } -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - if !t.traceFrame { +// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *jsTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if t.err != nil { return } - if t.err != nil { + if depth == 0 { + t.onStart(from, to, vm.OpCode(typ) == vm.CREATE, input, gas, value) + return + } + if !t.traceFrame { return } - t.frame.typ = typ.String() + t.frame.typ = vm.OpCode(typ).String() t.frame.from = from t.frame.to = to t.frame.input = common.CopyBytes(input) @@ -357,9 +388,16 @@ func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad } } -// CaptureExit is called when EVM exits a scope, even if the scope didn't +// OnExit is called when EVM exits a scope, even if the scope didn't // execute any code. -func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) { +func (t *jsTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if t.err != nil { + return + } + if depth == 0 { + t.onEnd(output, gasUsed, err, reverted) + return + } if !t.traceFrame { return } @@ -375,6 +413,9 @@ func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) { // GetResult calls the Javascript 'result' function and returns its value, or any accumulated error func (t *jsTracer) GetResult() (json.RawMessage, error) { + if t.err != nil { + return nil, t.err + } ctx := t.vm.ToValue(t.ctx) res, err := t.result(t.obj, ctx, t.dbValue) if err != nil { @@ -384,7 +425,7 @@ func (t *jsTracer) GetResult() (json.RawMessage, error) { if err != nil { return nil, err } - return json.RawMessage(encoded), t.err + return encoded, t.err } // Stop terminates execution of the tracer at the first opportune moment. @@ -397,9 +438,6 @@ func (t *jsTracer) Stop(err error) { // execution. func (t *jsTracer) onError(context string, err error) { t.err = wrapError(context, err) - // `env` is set on CaptureStart which comes before any JS execution. - // So it should be non-nil. - t.env.Cancel() } func wrapError(context string, err error) error { @@ -578,7 +616,7 @@ func (o *opObj) setupObject() *goja.Object { } type memoryObj struct { - memory *vm.Memory + memory []byte vm *goja.Runtime toBig toBigFn toBuf toBufFn @@ -606,7 +644,7 @@ func (mo *memoryObj) slice(begin, end int64) ([]byte, error) { if end < begin || begin < 0 { return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end) } - slice, err := tracers.GetMemoryCopyPadded(mo.memory, begin, end-begin) + slice, err := internal.GetMemoryCopyPadded(mo.memory, begin, end-begin) if err != nil { return nil, err } @@ -629,14 +667,14 @@ func (mo *memoryObj) GetUint(addr int64) goja.Value { // getUint returns the 32 bytes at the specified address interpreted as a uint. func (mo *memoryObj) getUint(addr int64) (*big.Int, error) { - if mo.memory.Len() < int(addr)+32 || addr < 0 { - return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), addr, 32) + if len(mo.memory) < int(addr)+32 || addr < 0 { + return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", len(mo.memory), addr, 32) } - return new(big.Int).SetBytes(mo.memory.GetPtr(addr, 32)), nil + return new(big.Int).SetBytes(internal.MemoryPtr(mo.memory, addr, 32)), nil } func (mo *memoryObj) Length() int { - return mo.memory.Len() + return len(mo.memory) } func (m *memoryObj) setupObject() *goja.Object { @@ -648,7 +686,7 @@ func (m *memoryObj) setupObject() *goja.Object { } type stackObj struct { - stack *vm.Stack + stack []uint256.Int vm *goja.Runtime toBig toBigFn } @@ -669,14 +707,14 @@ func (s *stackObj) Peek(idx int) goja.Value { // peek returns the nth-from-the-top element of the stack. func (s *stackObj) peek(idx int) (*big.Int, error) { - if len(s.stack.Data()) <= idx || idx < 0 { - return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack.Data()), idx) + if len(s.stack) <= idx || idx < 0 { + return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack), idx) } - return s.stack.Back(idx).ToBig(), nil + return internal.StackBack(s.stack, idx).ToBig(), nil } func (s *stackObj) Length() int { - return len(s.stack.Data()) + return len(s.stack) } func (s *stackObj) setupObject() *goja.Object { @@ -687,7 +725,7 @@ func (s *stackObj) setupObject() *goja.Object { } type dbObj struct { - db vm.StateDB + db tracing.StateDB vm *goja.Runtime toBig toBigFn toBuf toBufFn @@ -779,14 +817,14 @@ func (do *dbObj) setupObject() *goja.Object { } type contractObj struct { - contract *vm.Contract - vm *goja.Runtime - toBig toBigFn - toBuf toBufFn + scope tracing.OpContext + vm *goja.Runtime + toBig toBigFn + toBuf toBufFn } func (co *contractObj) GetCaller() goja.Value { - caller := co.contract.Caller().Bytes() + caller := co.scope.Caller().Bytes() res, err := co.toBuf(co.vm, caller) if err != nil { co.vm.Interrupt(err) @@ -796,7 +834,7 @@ func (co *contractObj) GetCaller() goja.Value { } func (co *contractObj) GetAddress() goja.Value { - addr := co.contract.Address().Bytes() + addr := co.scope.Address().Bytes() res, err := co.toBuf(co.vm, addr) if err != nil { co.vm.Interrupt(err) @@ -806,7 +844,7 @@ func (co *contractObj) GetAddress() goja.Value { } func (co *contractObj) GetValue() goja.Value { - value := co.contract.Value() + value := co.scope.CallValue() res, err := co.toBig(co.vm, value.String()) if err != nil { co.vm.Interrupt(err) @@ -816,7 +854,7 @@ func (co *contractObj) GetValue() goja.Value { } func (co *contractObj) GetInput() goja.Value { - input := common.CopyBytes(co.contract.Input) + input := common.CopyBytes(co.scope.CallInput()) res, err := co.toBuf(co.vm, input) if err != nil { co.vm.Interrupt(err) diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index b7f2693770be..d643289a64d7 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "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/eth/tracers" "github.com/ethereum/go-ethereum/params" @@ -61,9 +62,9 @@ func testCtx() *vmContext { return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} } -func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { +func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { var ( - env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer}) + env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer.Hooks}) gasLimit uint64 = 31000 startGas uint64 = 10000 value = uint256.NewInt(0) @@ -74,12 +75,12 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon contract.Code = contractCode } - tracer.CaptureTxStart(gasLimit) - tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value.ToBig()) + tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) + tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig()) ret, err := env.Interpreter().Run(contract, []byte{}, false) - tracer.CaptureEnd(ret, startGas-contract.Gas, err) + tracer.OnExit(0, ret, startGas-contract.Gas, err, true) // Rest gas assumes no refund - tracer.CaptureTxEnd(contract.Gas) + tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) if err != nil { return nil, err } @@ -181,15 +182,16 @@ func TestHaltBetweenSteps(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer}) scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, uint256.NewInt(0), 0), } - tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0)) - tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) + tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0)) + tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil) timeout := errors.New("stahp") tracer.Stop(timeout) - tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil) + tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil) if _, err := tracer.GetResult(); !strings.Contains(err.Error(), timeout.Error()) { t.Errorf("Expected timeout error, got %v", err) @@ -205,9 +207,10 @@ func TestNoStepExec(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer}) - tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) - tracer.CaptureEnd(nil, 0, nil) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) + tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0)) + tracer.OnExit(0, nil, 0, nil, false) ret, err := tracer.GetResult() if err != nil { t.Fatal(err) @@ -276,8 +279,8 @@ func TestEnterExit(t *testing.T) { scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, uint256.NewInt(0), 0), } - tracer.CaptureEnter(vm.CALL, scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) - tracer.CaptureExit([]byte{}, 400, nil) + tracer.OnEnter(1, byte(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) + tracer.OnExit(1, []byte{}, 400, nil, false) have, err := tracer.GetResult() if err != nil { diff --git a/eth/tracers/live.go b/eth/tracers/live.go new file mode 100644 index 000000000000..ffb2303af4f1 --- /dev/null +++ b/eth/tracers/live.go @@ -0,0 +1,31 @@ +package tracers + +import ( + "encoding/json" + "errors" + + "github.com/ethereum/go-ethereum/core/tracing" +) + +type ctorFunc func(config json.RawMessage) (*tracing.Hooks, error) + +// LiveDirectory is the collection of tracers which can be used +// during normal block import operations. +var LiveDirectory = liveDirectory{elems: make(map[string]ctorFunc)} + +type liveDirectory struct { + elems map[string]ctorFunc +} + +// Register registers a tracer constructor by name. +func (d *liveDirectory) Register(name string, f ctorFunc) { + d.elems[name] = f +} + +// New instantiates a tracer by name. +func (d *liveDirectory) New(name string, config json.RawMessage) (*tracing.Hooks, error) { + if f, ok := d.elems[name]; ok { + return f(config) + } + return nil, errors.New("not found") +} diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go new file mode 100644 index 000000000000..7433c288408f --- /dev/null +++ b/eth/tracers/live/noop.go @@ -0,0 +1,96 @@ +package live + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/params" +) + +func init() { + tracers.LiveDirectory.Register("noop", newNoopTracer) +} + +// noop is a no-op live tracer. It's there to +// catch changes in the tracing interface, as well as +// for testing live tracing performance. Can be removed +// as soon as we have a real live tracer. +type noop struct{} + +func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) { + t := &noop{} + return &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + OnGasChange: t.OnGasChange, + OnBlockchainInit: t.OnBlockchainInit, + OnBlockStart: t.OnBlockStart, + OnBlockEnd: t.OnBlockEnd, + OnSkippedBlock: t.OnSkippedBlock, + OnGenesisBlock: t.OnGenesisBlock, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, + }, nil +} + +func (t *noop) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +} + +func (t *noop) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) { +} + +func (t *noop) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +} + +func (t *noop) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { +} + +func (t *noop) OnTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) { +} + +func (t *noop) OnTxEnd(receipt *types.Receipt, err error) { +} + +func (t *noop) OnBlockStart(ev tracing.BlockEvent) { +} + +func (t *noop) OnBlockEnd(err error) { +} + +func (t *noop) OnSkippedBlock(ev tracing.BlockEvent) {} + +func (t *noop) OnBlockchainInit(chainConfig *params.ChainConfig) { +} + +func (t *noop) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) { +} + +func (t *noop) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { +} + +func (t *noop) OnNonceChange(a common.Address, prev, new uint64) { +} + +func (t *noop) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { +} + +func (t *noop) OnStorageChange(a common.Address, k, prev, new common.Hash) { +} + +func (t *noop) OnLog(l *types.Log) { + +} + +func (t *noop) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { +} diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 766ee4e4b95c..fc7713b24527 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -17,9 +17,8 @@ package logger import ( - "math/big" - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" ) @@ -132,17 +131,20 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } -func (a *AccessListTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (a *AccessListTracer) Hooks() *tracing.Hooks { + return &tracing.Hooks{ + OnOpcode: a.OnOpcode, + } } -// CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. -func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - stack := scope.Stack - stackData := stack.Data() +// OnOpcode captures all opcodes that touch storage or addresses and adds them to the accesslist. +func (a *AccessListTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + stackData := scope.StackData() stackLen := len(stackData) + op := vm.OpCode(opcode) if (op == vm.SLOAD || op == vm.SSTORE) && stackLen >= 1 { slot := common.Hash(stackData[stackLen-1].Bytes32()) - a.list.addSlot(scope.Contract.Address(), slot) + a.list.addSlot(scope.Address(), slot) } if (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT) && stackLen >= 1 { addr := common.Address(stackData[stackLen-1].Bytes20()) @@ -158,20 +160,6 @@ func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint6 } } -func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { -} - -func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {} - -func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { -} - -func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} - -func (*AccessListTracer) CaptureTxStart(gasLimit uint64) {} - -func (*AccessListTracer) CaptureTxEnd(restGas uint64) {} - // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { return a.list.accessList() diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 2b36f9f4922f..ef1d47146682 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -28,6 +28,7 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" @@ -108,14 +109,13 @@ func (s *StructLog) ErrorString() string { // contract their storage. type StructLogger struct { cfg Config - env *vm.EVM + env *tracing.VMContext - storage map[common.Address]Storage - logs []StructLog - output []byte - err error - gasLimit uint64 - usedGas uint64 + storage map[common.Address]Storage + logs []StructLog + output []byte + err error + usedGas uint64 interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption @@ -132,6 +132,15 @@ func NewStructLogger(cfg *Config) *StructLogger { return logger } +func (l *StructLogger) Hooks() *tracing.Hooks { + return &tracing.Hooks{ + OnTxStart: l.OnTxStart, + OnTxEnd: l.OnTxEnd, + OnExit: l.OnExit, + OnOpcode: l.OnOpcode, + } +} + // Reset clears the data held by the logger. func (l *StructLogger) Reset() { l.storage = make(map[common.Address]Storage) @@ -140,15 +149,10 @@ func (l *StructLogger) Reset() { l.err = nil } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - l.env = env -} - -// CaptureState logs a new structured log message and pushes it out to the environment +// OnOpcode logs a new structured log message and pushes it out to the environment // -// CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +// OnOpcode also tracks SLOAD/SSTORE ops to track storage change. +func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop if l.interrupt.Load() { return @@ -158,49 +162,47 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s return } - memory := scope.Memory - stack := scope.Stack - contract := scope.Contract + op := vm.OpCode(opcode) + memory := scope.MemoryData() + stack := scope.StackData() // Copy a snapshot of the current memory state to a new buffer var mem []byte if l.cfg.EnableMemory { - mem = make([]byte, len(memory.Data())) - copy(mem, memory.Data()) + mem = make([]byte, len(memory)) + copy(mem, memory) } // Copy a snapshot of the current stack state to a new buffer var stck []uint256.Int if !l.cfg.DisableStack { - stck = make([]uint256.Int, len(stack.Data())) - for i, item := range stack.Data() { - stck[i] = item - } + stck = make([]uint256.Int, len(stack)) + copy(stck, stack) } - stackData := stack.Data() - stackLen := len(stackData) + contractAddr := scope.Address() + stackLen := len(stack) // Copy a snapshot of the current storage to a new container var storage Storage if !l.cfg.DisableStorage && (op == vm.SLOAD || op == vm.SSTORE) { // initialise new changed values storage container for this contract // if not present. - if l.storage[contract.Address()] == nil { - l.storage[contract.Address()] = make(Storage) + if l.storage[contractAddr] == nil { + l.storage[contractAddr] = make(Storage) } // capture SLOAD opcodes and record the read entry in the local storage if op == vm.SLOAD && stackLen >= 1 { var ( - address = common.Hash(stackData[stackLen-1].Bytes32()) - value = l.env.StateDB.GetState(contract.Address(), address) + address = common.Hash(stack[stackLen-1].Bytes32()) + value = l.env.StateDB.GetState(contractAddr, address) ) - l.storage[contract.Address()][address] = value - storage = l.storage[contract.Address()].Copy() + l.storage[contractAddr][address] = value + storage = l.storage[contractAddr].Copy() } else if op == vm.SSTORE && stackLen >= 2 { // capture SSTORE opcodes and record the written entry in the local storage. var ( - value = common.Hash(stackData[stackLen-2].Bytes32()) - address = common.Hash(stackData[stackLen-1].Bytes32()) + value = common.Hash(stack[stackLen-2].Bytes32()) + address = common.Hash(stack[stackLen-1].Bytes32()) ) - l.storage[contract.Address()][address] = value - storage = l.storage[contract.Address()].Copy() + l.storage[contractAddr][address] = value + storage = l.storage[contractAddr].Copy() } } var rdata []byte @@ -209,17 +211,15 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s copy(rdata, rData) } // create a new snapshot of the EVM. - log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err} + log := StructLog{pc, op, gas, cost, mem, len(memory), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err} l.logs = append(l.logs, log) } -// CaptureFault implements the EVMLogger interface to trace an execution fault -// while running an opcode. -func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { +// OnExit is called a call frame finishes processing. +func (l *StructLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth != 0 { + return + } l.output = output l.err = err if l.cfg.Debug { @@ -230,12 +230,6 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { } } -func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { -} - -func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) { -} - func (l *StructLogger) GetResult() (json.RawMessage, error) { // Tracing aborted if l.reason != nil { @@ -262,12 +256,19 @@ func (l *StructLogger) Stop(err error) { l.interrupt.Store(true) } -func (l *StructLogger) CaptureTxStart(gasLimit uint64) { - l.gasLimit = gasLimit +func (l *StructLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + l.env = env } -func (l *StructLogger) CaptureTxEnd(restGas uint64) { - l.usedGas = l.gasLimit - restGas +func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) { + if err != nil { + // Don't override vm error + if l.err == nil { + l.err = err + } + return + } + l.usedGas = receipt.GasUsed } // StructLogs returns the captured log entries. @@ -329,7 +330,7 @@ func WriteLogs(writer io.Writer, logs []*types.Log) { type mdLogger struct { out io.Writer cfg *Config - env *vm.EVM + env *tracing.VMContext } // NewMarkdownLogger creates a logger which outputs information in a format adapted @@ -342,8 +343,25 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *mdLogger) Hooks() *tracing.Hooks { + return &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + } +} + +func (t *mdLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.env = env +} + +func (t *mdLogger) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if depth != 0 { + return + } + create := vm.OpCode(typ) == vm.CREATE if !create { fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n", from.String(), to.String(), @@ -360,15 +378,22 @@ func (t *mdLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Addr `) } -// CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (t *mdLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - stack := scope.Stack +func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth == 0 { + fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", + output, gasUsed, err) + } +} + +// OnOpcode also tracks SLOAD/SSTORE ops to track storage change. +func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + stack := scope.StackData() fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) if !t.cfg.DisableStack { // format stack var a []string - for _, elem := range stack.Data() { + for _, elem := range stack { a = append(a, elem.Hex()) } b := fmt.Sprintf("[%v]", strings.Join(a, ",")) @@ -381,24 +406,10 @@ func (t *mdLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope } } -func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } -func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { - fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", - output, gasUsed, err) -} - -func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { -} - -func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} - -func (*mdLogger) CaptureTxStart(gasLimit uint64) {} - -func (*mdLogger) CaptureTxEnd(restGas uint64) {} - // ExecutionResult groups all structured logs emitted by the EVM // while replaying a transaction in debug mode as well as transaction // execution status, the amount of gas used and the return value diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index a2cb4cd9fc59..6fac2d115922 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -19,58 +19,59 @@ package logger import ( "encoding/json" "io" - "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" ) -type JSONLogger struct { +type jsonLogger struct { encoder *json.Encoder cfg *Config - env *vm.EVM + env *tracing.VMContext } // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects // into the provided stream. -func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { - l := &JSONLogger{encoder: json.NewEncoder(writer), cfg: cfg} +func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { + l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg} if l.cfg == nil { l.cfg = &Config{} } - return l -} - -func (l *JSONLogger) CaptureStart(env *vm.EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - l.env = env + return &tracing.Hooks{ + OnTxStart: l.OnTxStart, + OnExit: l.OnExit, + OnOpcode: l.OnOpcode, + OnFault: l.OnFault, + } } -func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (l *jsonLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { // TODO: Add rData to this interface as well - l.CaptureState(pc, op, gas, cost, scope, nil, depth, err) + l.OnOpcode(pc, op, gas, cost, scope, nil, depth, err) } -// CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - memory := scope.Memory - stack := scope.Stack +func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + memory := scope.MemoryData() + stack := scope.StackData() log := StructLog{ Pc: pc, - Op: op, + Op: vm.OpCode(op), Gas: gas, GasCost: cost, - MemorySize: memory.Len(), + MemorySize: len(memory), Depth: depth, RefundCounter: l.env.StateDB.GetRefund(), Err: err, } if l.cfg.EnableMemory { - log.Memory = memory.Data() + log.Memory = memory } if !l.cfg.DisableStack { - log.Stack = stack.Data() + log.Stack = stack } if l.cfg.EnableReturnData { log.ReturnData = rData @@ -78,8 +79,10 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco l.encoder.Encode(log) } -// CaptureEnd is triggered at end of execution. -func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { +func (l *jsonLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth > 0 { + return + } type endLog struct { Output string `json:"output"` GasUsed math.HexOrDecimal64 `json:"gasUsed"` @@ -92,11 +95,6 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), errMsg}) } -func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (l *jsonLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + l.env = env } - -func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} - -func (l *JSONLogger) CaptureTxStart(gasLimit uint64) {} - -func (l *JSONLogger) CaptureTxEnd(restGas uint64) {} diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index 1d8eb320f600..137608f8847d 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -56,12 +56,12 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) {} func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) - env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger}) + env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()}) contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(uint256.Int), 100000) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} var index common.Hash - logger.CaptureStart(env, common.Address{}, contract.Address(), false, nil, 0, nil) + logger.OnTxStart(env.GetVMContext(), nil, common.Address{}) _, err := env.Interpreter().Run(contract, []byte{}, false) if err != nil { t.Fatal(err) diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 5a2c4f91115f..6cb0e433d27d 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -23,6 +23,8 @@ import ( "sync/atomic" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" ) @@ -46,20 +48,26 @@ func init() { // 0xc281d19e-0: 1 // } type fourByteTracer struct { - noopTracer ids map[string]int // ids aggregates the 4byte ids found interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption - activePrecompiles []common.Address // Updated on CaptureStart based on given rules + activePrecompiles []common.Address // Updated on tx start based on given rules } // newFourByteTracer returns a native go tracer which collects // 4 byte-identifiers of a tx, and implements vm.EVMLogger. -func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { +func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (*tracers.Tracer, error) { t := &fourByteTracer{ ids: make(map[string]int), } - return t, nil + return &tracers.Tracer{ + Hooks: &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnEnter: t.OnEnter, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil } // isPrecompiled returns whether the addr is a precompile. Logic borrowed from newJsTracer in eth/tracers/js/tracer.go @@ -78,20 +86,14 @@ func (t *fourByteTracer) store(id []byte, size int) { t.ids[key] += 1 } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *fourByteTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) + rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) - - // Save the outer calldata also - if len(input) >= 4 { - t.store(input[0:4], len(input)-4) - } } -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *fourByteTracer) OnEnter(depth int, opcode byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { // Skip if tracing was interrupted if t.interrupt.Load() { return @@ -99,6 +101,7 @@ func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to comm if len(input) < 4 { return } + op := vm.OpCode(opcode) // primarily we want to avoid CREATE/CREATE2/SELFDESTRUCT if op != vm.DELEGATECALL && op != vm.STATICCALL && op != vm.CALL && op != vm.CALLCODE { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index be9b58a4cd3c..3b6350658038 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -25,9 +25,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/log" ) //go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go @@ -59,7 +60,8 @@ type callFrame struct { Logs []callLog `json:"logs,omitempty" rlp:"optional"` // Placed at end on purpose. The RLP will be decoded to 0 instead of // nil if there are non-empty elements after in the struct. - Value *big.Int `json:"value,omitempty" rlp:"optional"` + Value *big.Int `json:"value,omitempty" rlp:"optional"` + revertedSnapshot bool } func (f callFrame) TypeString() string { @@ -67,16 +69,17 @@ func (f callFrame) TypeString() string { } func (f callFrame) failed() bool { - return len(f.Error) > 0 + return len(f.Error) > 0 && f.revertedSnapshot } -func (f *callFrame) processOutput(output []byte, err error) { +func (f *callFrame) processOutput(output []byte, err error, reverted bool) { output = common.CopyBytes(output) if err == nil { f.Output = output return } f.Error = err.Error() + f.revertedSnapshot = reverted if f.Type == vm.CREATE || f.Type == vm.CREATE2 { f.To = nil } @@ -102,10 +105,10 @@ type callFrameMarshaling struct { } type callTracer struct { - noopTracer callstack []callFrame config callTracerConfig gasLimit uint64 + depth int interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption } @@ -117,7 +120,25 @@ type callTracerConfig struct { // newCallTracer returns a native go tracer which tracks // call frames of a tx, and implements vm.EVMLogger. -func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { +func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { + t, err := newCallTracerObject(ctx, cfg) + if err != nil { + return nil, err + } + return &tracers.Tracer{ + Hooks: &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnLog: t.OnLog, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil +} + +func newCallTracerObject(ctx *tracers.Context, cfg json.RawMessage) (*callTracer, error) { var config callTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { @@ -126,84 +147,13 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, e } // First callframe contains tx context info // and is populated on start and end. - return &callTracer{callstack: make([]callFrame, 1), config: config}, nil -} - -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - toCopy := to - t.callstack[0] = callFrame{ - Type: vm.CALL, - From: from, - To: &toCopy, - Input: common.CopyBytes(input), - Gas: t.gasLimit, - Value: value, - } - if create { - t.callstack[0].Type = vm.CREATE - } -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { - t.callstack[0].processOutput(output, err) -} - -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - // skip if the previous op caused an error - if err != nil { - return - } - // Only logs need to be captured via opcode processing - if !t.config.WithLog { - return - } - // Avoid processing nested calls when only caring about top call - if t.config.OnlyTopCall && depth > 1 { - return - } - // Skip if tracing was interrupted - if t.interrupt.Load() { - return - } - switch op { - case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4: - size := int(op - vm.LOG0) - - stack := scope.Stack - stackData := stack.Data() - - // Don't modify the stack - mStart := stackData[len(stackData)-1] - mSize := stackData[len(stackData)-2] - topics := make([]common.Hash, size) - for i := 0; i < size; i++ { - topic := stackData[len(stackData)-2-(i+1)] - topics[i] = common.Hash(topic.Bytes32()) - } - - data, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(mStart.Uint64()), int64(mSize.Uint64())) - if err != nil { - // mSize was unrealistically large - log.Warn("failed to copy CREATE2 input", "err", err, "tracer", "callTracer", "offset", mStart, "size", mSize) - return - } - - log := callLog{ - Address: scope.Contract.Address(), - Topics: topics, - Data: hexutil.Bytes(data), - Position: hexutil.Uint(len(t.callstack[len(t.callstack)-1].Calls)), - } - t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, log) - } + return &callTracer{callstack: make([]callFrame, 0, 1), config: config}, nil } -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - if t.config.OnlyTopCall { +// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *callTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + t.depth = depth + if t.config.OnlyTopCall && depth > 0 { return } // Skip if tracing was interrupted @@ -213,48 +163,92 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. toCopy := to call := callFrame{ - Type: typ, + Type: vm.OpCode(typ), From: from, To: &toCopy, Input: common.CopyBytes(input), Gas: gas, Value: value, } + if depth == 0 { + call.Gas = t.gasLimit + } t.callstack = append(t.callstack, call) } -// CaptureExit is called when EVM exits a scope, even if the scope didn't +// OnExit is called when EVM exits a scope, even if the scope didn't // execute any code. -func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { +func (t *callTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth == 0 { + t.captureEnd(output, gasUsed, err, reverted) + return + } + + t.depth = depth - 1 if t.config.OnlyTopCall { return } + size := len(t.callstack) if size <= 1 { return } - // pop call + // Pop call. call := t.callstack[size-1] t.callstack = t.callstack[:size-1] size -= 1 call.GasUsed = gasUsed - call.processOutput(output, err) + call.processOutput(output, err, reverted) + // Nest call into parent. t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(gasLimit uint64) { - t.gasLimit = gasLimit +func (t *callTracer) captureEnd(output []byte, gasUsed uint64, err error, reverted bool) { + if len(t.callstack) != 1 { + return + } + t.callstack[0].processOutput(output, err, reverted) +} + +func (t *callTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + t.gasLimit = tx.Gas() } -func (t *callTracer) CaptureTxEnd(restGas uint64) { - t.callstack[0].GasUsed = t.gasLimit - restGas +func (t *callTracer) OnTxEnd(receipt *types.Receipt, err error) { + // Error happened during tx validation. + if err != nil { + return + } + t.callstack[0].GasUsed = receipt.GasUsed if t.config.WithLog { // Logs are not emitted when the call fails clearFailedLogs(&t.callstack[0], false) } } +func (t *callTracer) OnLog(log *types.Log) { + // Only logs need to be captured via opcode processing + if !t.config.WithLog { + return + } + // Avoid processing nested calls when only caring about top call + if t.config.OnlyTopCall && t.depth > 0 { + return + } + // Skip if tracing was interrupted + if t.interrupt.Load() { + return + } + l := callLog{ + Address: log.Address, + Topics: log.Topics, + Data: log.Data, + Position: hexutil.Uint(len(t.callstack[len(t.callstack)-1].Calls)), + } + t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, l) +} + // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *callTracer) GetResult() (json.RawMessage, error) { @@ -266,7 +260,7 @@ func (t *callTracer) GetResult() (json.RawMessage, error) { if err != nil { return nil, err } - return json.RawMessage(res), t.reason + return res, t.reason } // Stop terminates execution of the tracer at the first opportune moment. diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 266ab9900146..37be64310c47 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -25,6 +25,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" ) @@ -112,7 +114,7 @@ type flatCallTracer struct { config flatCallTracerConfig ctx *tracers.Context // Holds tracer context data reason error // Textual reason for the interruption - activePrecompiles []common.Address // Updated on CaptureStart based on given rules + activePrecompiles []common.Address // Updated on tx start based on given rules } type flatCallTracerConfig struct { @@ -121,7 +123,7 @@ type flatCallTracerConfig struct { } // newFlatCallTracer returns a new flatCallTracer. -func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { +func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { var config flatCallTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { @@ -131,45 +133,31 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace // Create inner call tracer with default configuration, don't forward // the OnlyTopCall or WithLog to inner for now - tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, nil) + t, err := newCallTracerObject(ctx, nil) if err != nil { return nil, err } - t, ok := tracer.(*callTracer) - if !ok { - return nil, errors.New("internal error: embedded tracer has wrong type") - } - - return &flatCallTracer{tracer: t, ctx: ctx, config: config}, nil -} - -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *flatCallTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.tracer.CaptureStart(env, from, to, create, input, gas, value) - // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { - t.tracer.CaptureEnd(output, gasUsed, err) -} -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *flatCallTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - t.tracer.CaptureState(pc, op, gas, cost, scope, rData, depth, err) -} - -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *flatCallTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { - t.tracer.CaptureFault(pc, op, gas, cost, scope, depth, err) + ft := &flatCallTracer{tracer: t, ctx: ctx, config: config} + return &tracers.Tracer{ + Hooks: &tracing.Hooks{ + OnTxStart: ft.OnTxStart, + OnTxEnd: ft.OnTxEnd, + OnEnter: ft.OnEnter, + OnExit: ft.OnExit, + }, + Stop: ft.Stop, + GetResult: ft.GetResult, + }, nil } -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *flatCallTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - t.tracer.CaptureEnter(typ, from, to, input, gas, value) +// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *flatCallTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + t.tracer.OnEnter(depth, typ, from, to, input, gas, value) + if depth == 0 { + return + } // Child calls must have a value, even if it's zero. // Practically speaking, only STATICCALL has nil value. Set it to zero. if t.tracer.callstack[len(t.tracer.callstack)-1].Value == nil && value == nil { @@ -177,11 +165,14 @@ func (t *flatCallTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com } } -// CaptureExit is called when EVM exits a scope, even if the scope didn't +// OnExit is called when EVM exits a scope, even if the scope didn't // execute any code. -func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) { - t.tracer.CaptureExit(output, gasUsed, err) +func (t *flatCallTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + t.tracer.OnExit(depth, output, gasUsed, err, reverted) + if depth == 0 { + return + } // Parity traces don't include CALL/STATICCALLs to precompiles. // By default we remove them from the callstack. if t.config.IncludePrecompiles { @@ -201,12 +192,15 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } } -func (t *flatCallTracer) CaptureTxStart(gasLimit uint64) { - t.tracer.CaptureTxStart(gasLimit) +func (t *flatCallTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + t.tracer.OnTxStart(env, tx, from) + // Update list of precompiles based on current block + rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) + t.activePrecompiles = vm.ActivePrecompiles(rules) } -func (t *flatCallTracer) CaptureTxEnd(restGas uint64) { - t.tracer.CaptureTxEnd(restGas) +func (t *flatCallTracer) OnTxEnd(receipt *types.Receipt, err error) { + t.tracer.OnTxEnd(receipt, err) } // GetResult returns an empty json object. diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index db8ddd64380d..c3b1d9f8cafa 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -21,7 +21,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/tracers" ) @@ -33,18 +34,18 @@ func init() { // runs multiple tracers in one go. type muxTracer struct { names []string - tracers []tracers.Tracer + tracers []*tracers.Tracer } // newMuxTracer returns a new mux tracer. -func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { +func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { var config map[string]json.RawMessage if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { return nil, err } } - objects := make([]tracers.Tracer, 0, len(config)) + objects := make([]*tracers.Tracer, 0, len(config)) names := make([]string, 0, len(config)) for k, v := range config { t, err := tracers.DefaultDirectory.New(k, ctx, v) @@ -55,61 +56,120 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, er names = append(names, k) } - return &muxTracer{names: names, tracers: objects}, nil + t := &muxTracer{names: names, tracers: objects} + return &tracers.Tracer{ + Hooks: &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + OnGasChange: t.OnGasChange, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *muxTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *muxTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { for _, t := range t.tracers { - t.CaptureStart(env, from, to, create, input, gas, value) + if t.OnOpcode != nil { + t.OnOpcode(pc, op, gas, cost, scope, rData, depth, err) + } + } +} + +func (t *muxTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { + for _, t := range t.tracers { + if t.OnFault != nil { + t.OnFault(pc, op, gas, cost, scope, depth, err) + } + } +} + +func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { + for _, t := range t.tracers { + if t.OnGasChange != nil { + t.OnGasChange(old, new, reason) + } + } +} + +func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + for _, t := range t.tracers { + if t.OnEnter != nil { + t.OnEnter(depth, typ, from, to, input, gas, value) + } + } +} + +func (t *muxTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + for _, t := range t.tracers { + if t.OnExit != nil { + t.OnExit(depth, output, gasUsed, err, reverted) + } } } -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { +func (t *muxTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { for _, t := range t.tracers { - t.CaptureEnd(output, gasUsed, err) + if t.OnTxStart != nil { + t.OnTxStart(env, tx, from) + } } } -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *muxTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *muxTracer) OnTxEnd(receipt *types.Receipt, err error) { for _, t := range t.tracers { - t.CaptureState(pc, op, gas, cost, scope, rData, depth, err) + if t.OnTxEnd != nil { + t.OnTxEnd(receipt, err) + } } } -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *muxTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { for _, t := range t.tracers { - t.CaptureFault(pc, op, gas, cost, scope, depth, err) + if t.OnBalanceChange != nil { + t.OnBalanceChange(a, prev, new, reason) + } } } -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *muxTracer) OnNonceChange(a common.Address, prev, new uint64) { for _, t := range t.tracers { - t.CaptureEnter(typ, from, to, input, gas, value) + if t.OnNonceChange != nil { + t.OnNonceChange(a, prev, new) + } } } -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) { +func (t *muxTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { for _, t := range t.tracers { - t.CaptureExit(output, gasUsed, err) + if t.OnCodeChange != nil { + t.OnCodeChange(a, prevCodeHash, prev, codeHash, code) + } } } -func (t *muxTracer) CaptureTxStart(gasLimit uint64) { +func (t *muxTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) { for _, t := range t.tracers { - t.CaptureTxStart(gasLimit) + if t.OnStorageChange != nil { + t.OnStorageChange(a, k, prev, new) + } } } -func (t *muxTracer) CaptureTxEnd(restGas uint64) { +func (t *muxTracer) OnLog(log *types.Log) { for _, t := range t.tracers { - t.CaptureTxEnd(restGas) + if t.OnLog != nil { + t.OnLog(log) + } } } diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 3beecd8abfed..f147134610c0 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -21,7 +21,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/tracers" ) @@ -34,38 +35,58 @@ func init() { type noopTracer struct{} // newNoopTracer returns a new noop tracer. -func newNoopTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { - return &noopTracer{}, nil +func newNoopTracer(ctx *tracers.Context, _ json.RawMessage) (*tracers.Tracer, error) { + t := &noopTracer{} + return &tracers.Tracer{ + Hooks: &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + OnGasChange: t.OnGasChange, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *noopTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *noopTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { +func (t *noopTracer) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *noopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *noopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {} + +func (t *noopTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *noopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { +func (t *noopTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { } -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (*noopTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { } -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { +func (*noopTracer) OnTxEnd(receipt *types.Receipt, err error) {} + +func (*noopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { +} + +func (*noopTracer) OnNonceChange(a common.Address, prev, new uint64) {} + +func (*noopTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { } -func (*noopTracer) CaptureTxStart(gasLimit uint64) {} +func (*noopTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {} -func (*noopTracer) CaptureTxEnd(restGas uint64) {} +func (*noopTracer) OnLog(log *types.Log) {} // GetResult returns an empty json object. func (t *noopTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index b86c5c461c7d..b353c0696067 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -24,11 +24,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/tracing" + "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/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/internal" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" ) //go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go @@ -37,13 +39,14 @@ func init() { tracers.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false) } -type state = map[common.Address]*account +type stateMap = map[common.Address]*account type account struct { Balance *big.Int `json:"balance,omitempty"` Code []byte `json:"code,omitempty"` Nonce uint64 `json:"nonce,omitempty"` Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + empty bool } func (a *account) exists() bool { @@ -56,13 +59,10 @@ type accountMarshaling struct { } type prestateTracer struct { - noopTracer - env *vm.EVM - pre state - post state - create bool + env *tracing.VMContext + pre stateMap + post stateMap to common.Address - gasLimit uint64 // Amount of gas bought for the whole tx config prestateTracerConfig interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption @@ -74,76 +74,33 @@ type prestateTracerConfig struct { DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications } -func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { +func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { var config prestateTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { return nil, err } } - return &prestateTracer{ - pre: state{}, - post: state{}, + t := &prestateTracer{ + pre: stateMap{}, + post: stateMap{}, config: config, created: make(map[common.Address]bool), deleted: make(map[common.Address]bool), - }, nil -} - -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.env = env - t.create = create - t.to = to - - t.lookupAccount(from) - t.lookupAccount(to) - t.lookupAccount(env.Context.Coinbase) - - // The recipient balance includes the value transferred. - toBal := new(big.Int).Sub(t.pre[to].Balance, value) - t.pre[to].Balance = toBal - if env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time).IsEIP158 && create { - t.pre[to].Nonce-- - } - - // The sender balance is after reducing: value and gasLimit. - // We need to re-add them to get the pre-tx balance. - fromBal := new(big.Int).Set(t.pre[from].Balance) - gasPrice := env.TxContext.GasPrice - consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit)) - fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) - - // Add blob fee to the sender's balance. - if env.Context.BlobBaseFee != nil && len(env.TxContext.BlobHashes) > 0 { - blobGas := uint64(params.BlobTxBlobGasPerBlob * len(env.TxContext.BlobHashes)) - fromBal.Add(fromBal, new(big.Int).Mul(env.Context.BlobBaseFee, new(big.Int).SetUint64(blobGas))) - } - t.pre[from].Balance = fromBal - t.pre[from].Nonce-- - - if create && t.config.DiffMode { - t.created[to] = true - } -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { - if t.config.DiffMode { - return - } - - if t.create { - // Keep existing account prior to contract creation at that address - if s := t.pre[t.to]; s != nil && !s.exists() { - // Exclude newly created contract. - delete(t.pre, t.to) - } } + return &tracers.Tracer{ + Hooks: &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnOpcode: t.OnOpcode, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil } -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +// OnOpcode implements the EVMLogger interface to trace a single step of VM execution. +func (t *prestateTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { if err != nil { return } @@ -151,10 +108,10 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, if t.interrupt.Load() { return } - stack := scope.Stack - stackData := stack.Data() + op := vm.OpCode(opcode) + stackData := scope.StackData() stackLen := len(stackData) - caller := scope.Contract.Address() + caller := scope.Address() switch { case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE): slot := common.Hash(stackData[stackLen-1].Bytes32()) @@ -176,7 +133,7 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, case stackLen >= 4 && op == vm.CREATE2: offset := stackData[stackLen-2] size := stackData[stackLen-3] - init, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(offset.Uint64()), int64(size.Uint64())) + init, err := internal.GetMemoryCopyPadded(scope.MemoryData(), int64(offset.Uint64()), int64(size.Uint64())) if err != nil { log.Warn("failed to copy CREATE2 input", "err", err, "tracer", "prestateTracer", "offset", offset, "size", size) return @@ -189,15 +146,62 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, } } -func (t *prestateTracer) CaptureTxStart(gasLimit uint64) { - t.gasLimit = gasLimit +func (t *prestateTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + t.env = env + if tx.To() == nil { + t.to = crypto.CreateAddress(from, env.StateDB.GetNonce(from)) + t.created[t.to] = true + } else { + t.to = *tx.To() + } + + t.lookupAccount(from) + t.lookupAccount(t.to) + t.lookupAccount(env.Coinbase) } -func (t *prestateTracer) CaptureTxEnd(restGas uint64) { - if !t.config.DiffMode { +func (t *prestateTracer) OnTxEnd(receipt *types.Receipt, err error) { + if err != nil { return } + if t.config.DiffMode { + t.processDiffState() + } + // the new created contracts' prestate were empty, so delete them + for a := range t.created { + // the created contract maybe exists in statedb before the creating tx + if s := t.pre[a]; s != nil && s.empty { + delete(t.pre, a) + } + } +} +// GetResult returns the json-encoded nested list of call traces, and any +// error arising from the encoding or forceful termination (via `Stop`). +func (t *prestateTracer) GetResult() (json.RawMessage, error) { + var res []byte + var err error + if t.config.DiffMode { + res, err = json.Marshal(struct { + Post stateMap `json:"post"` + Pre stateMap `json:"pre"` + }{t.post, t.pre}) + } else { + res, err = json.Marshal(t.pre) + } + if err != nil { + return nil, err + } + return json.RawMessage(res), t.reason +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (t *prestateTracer) Stop(err error) { + t.reason = err + t.interrupt.Store(true) +} + +func (t *prestateTracer) processDiffState() { for addr, state := range t.pre { // The deleted account's state is pruned from `post` but kept in `pre` if _, ok := t.deleted[addr]; ok { @@ -247,38 +251,6 @@ func (t *prestateTracer) CaptureTxEnd(restGas uint64) { delete(t.pre, addr) } } - // the new created contracts' prestate were empty, so delete them - for a := range t.created { - // the created contract maybe exists in statedb before the creating tx - if s := t.pre[a]; s != nil && !s.exists() { - delete(t.pre, a) - } - } -} - -// GetResult returns the json-encoded nested list of call traces, and any -// error arising from the encoding or forceful termination (via `Stop`). -func (t *prestateTracer) GetResult() (json.RawMessage, error) { - var res []byte - var err error - if t.config.DiffMode { - res, err = json.Marshal(struct { - Post state `json:"post"` - Pre state `json:"pre"` - }{t.post, t.pre}) - } else { - res, err = json.Marshal(t.pre) - } - if err != nil { - return nil, err - } - return json.RawMessage(res), t.reason -} - -// Stop terminates execution of the tracer at the first opportune moment. -func (t *prestateTracer) Stop(err error) { - t.reason = err - t.interrupt.Store(true) } // lookupAccount fetches details of an account and adds it to the prestate @@ -288,12 +260,16 @@ func (t *prestateTracer) lookupAccount(addr common.Address) { return } - t.pre[addr] = &account{ + acc := &account{ Balance: t.env.StateDB.GetBalance(addr).ToBig(), Nonce: t.env.StateDB.GetNonce(addr), Code: t.env.StateDB.GetCode(addr), Storage: make(map[common.Hash]common.Hash), } + if !acc.exists() { + acc.empty = true + } + t.pre[addr] = acc } // lookupStorage fetches the requested storage slot and adds diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 6ac266e06d61..3cce7bffa19a 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -89,7 +89,7 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableMemory: false, //EnableReturnData: false, }) - evm := vm.NewEVM(context, txContext, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer}) + evm := vm.NewEVM(context, txContext, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()}) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) @@ -111,41 +111,3 @@ func BenchmarkTransactionTrace(b *testing.B) { tracer.Reset() } } - -func TestMemCopying(t *testing.T) { - for i, tc := range []struct { - memsize int64 - offset int64 - size int64 - wantErr string - wantSize int - }{ - {0, 0, 100, "", 100}, // Should pad up to 100 - {0, 100, 0, "", 0}, // No need to pad (0 size) - {100, 50, 100, "", 100}, // Should pad 100-150 - {100, 50, 5, "", 5}, // Wanted range fully within memory - {100, -50, 0, "offset or size must not be negative", 0}, // Error - {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Error - {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Error - - } { - mem := vm.NewMemory() - mem.Resize(uint64(tc.memsize)) - cpy, err := GetMemoryCopyPadded(mem, tc.offset, tc.size) - if want := tc.wantErr; want != "" { - if err == nil { - t.Fatalf("test %d: want '%v' have no error", i, want) - } - if have := err.Error(); want != have { - t.Fatalf("test %d: want '%v' have '%v'", i, want, have) - } - continue - } - if err != nil { - t.Fatalf("test %d: unexpected error: %v", i, err) - } - if want, have := tc.wantSize, len(cpy); have != want { - t.Fatalf("test %d: want %v have %v", i, want, have) - } - } -} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 863849f4da6a..6009d7003193 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -457,7 +458,7 @@ func (s *PersonalAccountAPI) signTransaction(ctx context.Context, args *Transact return nil, err } // Assemble the transaction and sign with the wallet - tx := args.toTransaction() + tx := args.ToTransaction() return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID) } @@ -506,7 +507,7 @@ func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transacti return nil, errors.New("nonce not specified") } // Before actually signing the transaction, ensure the transaction fee is reasonable. - tx := args.toTransaction() + tx := args.ToTransaction() if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil { return nil, err } @@ -962,42 +963,42 @@ type OverrideAccount struct { type StateOverride map[common.Address]OverrideAccount // Apply overrides the fields of specified accounts into the given state. -func (diff *StateOverride) Apply(state *state.StateDB) error { +func (diff *StateOverride) Apply(statedb *state.StateDB) error { if diff == nil { return nil } for addr, account := range *diff { // Override account nonce. if account.Nonce != nil { - state.SetNonce(addr, uint64(*account.Nonce)) + statedb.SetNonce(addr, uint64(*account.Nonce)) } // Override account(contract) code. if account.Code != nil { - state.SetCode(addr, *account.Code) + statedb.SetCode(addr, *account.Code) } // Override account balance. if account.Balance != nil { u256Balance, _ := uint256.FromBig((*big.Int)(*account.Balance)) - state.SetBalance(addr, u256Balance) + statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified) } if account.State != nil && account.StateDiff != nil { return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) } // Replace entire state if caller requires. if account.State != nil { - state.SetStorage(addr, *account.State) + statedb.SetStorage(addr, *account.State) } // Apply state diff into specified accounts. if account.StateDiff != nil { for key, value := range *account.StateDiff { - state.SetState(addr, key, value) + statedb.SetState(addr, key, value) } } } // Now finalize the changes. Finalize is normally performed between transactions. // By using finalize, the overrides are semantically behaving as // if they were created in a transaction just before the tracing occur. - state.Finalise(false) + statedb.Finalise(false) return nil } @@ -1097,10 +1098,10 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S if blockOverrides != nil { blockOverrides.Apply(&blockCtx) } - msg, err := args.ToMessage(globalGasCap, blockCtx.BaseFee) - if err != nil { + if err := args.CallDefaults(globalGasCap, blockCtx.BaseFee, b.ChainConfig().ChainID); err != nil { return nil, err } + msg := args.ToMessage(blockCtx.BaseFee) evm := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx) // Wait for the context to be done and cancel the evm. Even if the @@ -1181,11 +1182,14 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr State: state, ErrorRatio: estimateGasErrorRatio, } - // Run the gas estimation andwrap any revertals into a custom return - call, err := args.ToMessage(gasCap, header.BaseFee) + if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil { + return 0, err + } + call := args.ToMessage(header.BaseFee) if err != nil { return 0, err } + // Run the gas estimation andwrap any revertals into a custom return estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) if err != nil { if len(revert) > 0 { @@ -1514,18 +1518,18 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH statedb := db.Copy() // Set the accesslist to the last al args.AccessList = &accessList - msg, err := args.ToMessage(b.RPCGasCap(), header.BaseFee) + msg := args.ToMessage(header.BaseFee) if err != nil { return nil, 0, nil, err } // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) - config := vm.Config{Tracer: tracer, NoBaseFee: true} + config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true} vmenv := b.GetEVM(ctx, msg, statedb, header, &config, nil) res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { - return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err) + return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction().Hash(), err) } if tracer.Equal(prevTracer) { return accessList, res.UsedGas, res.Err, nil @@ -1794,7 +1798,7 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr return common.Hash{}, err } // Assemble the transaction and sign with the wallet - tx := args.toTransaction() + tx := args.ToTransaction() signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) if err != nil { @@ -1814,7 +1818,7 @@ func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionAr return nil, err } // Assemble the transaction and obtain rlp - tx := args.toTransaction() + tx := args.ToTransaction() data, err := tx.MarshalBinary() if err != nil { return nil, err @@ -1883,7 +1887,7 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr return nil, err } // Before actually sign the transaction, ensure the transaction fee is reasonable. - tx := args.toTransaction() + tx := args.ToTransaction() if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil { return nil, err } @@ -1931,7 +1935,7 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g if err := sendArgs.setDefaults(ctx, s.b, false); err != nil { return common.Hash{}, err } - matchTx := sendArgs.toTransaction() + matchTx := sendArgs.ToTransaction() // Before replacing the old transaction, ensure the _new_ transaction fee is reasonable. var price = matchTx.GasPrice() @@ -1961,7 +1965,7 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g if gasLimit != nil && *gasLimit != 0 { sendArgs.Gas = gasLimit } - signedTx, err := s.sign(sendArgs.from(), sendArgs.toTransaction()) + signedTx, err := s.sign(sendArgs.from(), sendArgs.ToTransaction()) if err != nil { return common.Hash{}, err } diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 2751d5b5aae6..bef6082ead4c 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -364,41 +364,71 @@ func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context, b Backend) er return nil } -// ToMessage converts the transaction arguments to the Message type used by the -// core evm. This method is used in calls and traces that do not require a real -// live transaction. -func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*core.Message, error) { +// CallDefaults sanitizes the transaction arguments, often filling in zero values, +// for the purpose of eth_call class of RPC methods. +func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, chainID *big.Int) error { // Reject invalid combinations of pre- and post-1559 fee styles if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { - return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") + return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") } - // Set sender address or use zero address if none specified. - addr := args.from() - - // Set default gas & gas price if none were set - gas := globalGasCap - if gas == 0 { - gas = uint64(math.MaxUint64 / 2) + if args.ChainID == nil { + args.ChainID = (*hexutil.Big)(chainID) + } else { + if have := (*big.Int)(args.ChainID); have.Cmp(chainID) != 0 { + return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, chainID) + } + } + if args.Gas == nil { + gas := globalGasCap + if gas == 0 { + gas = uint64(math.MaxUint64 / 2) + } + args.Gas = (*hexutil.Uint64)(&gas) + } else { + if globalGasCap > 0 && globalGasCap < uint64(*args.Gas) { + log.Warn("Caller gas above allowance, capping", "requested", args.Gas, "cap", globalGasCap) + args.Gas = (*hexutil.Uint64)(&globalGasCap) + } } - if args.Gas != nil { - gas = uint64(*args.Gas) + if args.Nonce == nil { + args.Nonce = new(hexutil.Uint64) } - if globalGasCap != 0 && globalGasCap < gas { - log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap) - gas = globalGasCap + if args.Value == nil { + args.Value = new(hexutil.Big) } - var ( - gasPrice *big.Int - gasFeeCap *big.Int - gasTipCap *big.Int - blobFeeCap *big.Int - ) if baseFee == nil { // If there's no basefee, then it must be a non-1559 execution - gasPrice = new(big.Int) - if args.GasPrice != nil { - gasPrice = args.GasPrice.ToInt() + if args.GasPrice == nil { + args.GasPrice = new(hexutil.Big) } + } else { + // A basefee is provided, necessitating 1559-type execution + if args.MaxFeePerGas == nil { + args.MaxFeePerGas = new(hexutil.Big) + } + if args.MaxPriorityFeePerGas == nil { + args.MaxPriorityFeePerGas = new(hexutil.Big) + } + } + if args.BlobFeeCap == nil && args.BlobHashes != nil { + args.BlobFeeCap = new(hexutil.Big) + } + + return nil +} + +// ToMessage converts the transaction arguments to the Message type used by the +// core evm. This method is used in calls and traces that do not require a real +// live transaction. +// Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called. +func (args *TransactionArgs) ToMessage(baseFee *big.Int) *core.Message { + var ( + gasPrice *big.Int + gasFeeCap *big.Int + gasTipCap *big.Int + ) + if baseFee == nil { + gasPrice = args.GasPrice.ToInt() gasFeeCap, gasTipCap = gasPrice, gasPrice } else { // A basefee is provided, necessitating 1559-type execution @@ -408,14 +438,8 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (* gasFeeCap, gasTipCap = gasPrice, gasPrice } else { // User specified 1559 gas fields (or none), use those - gasFeeCap = new(big.Int) - if args.MaxFeePerGas != nil { - gasFeeCap = args.MaxFeePerGas.ToInt() - } - gasTipCap = new(big.Int) - if args.MaxPriorityFeePerGas != nil { - gasTipCap = args.MaxPriorityFeePerGas.ToInt() - } + gasFeeCap = args.MaxFeePerGas.ToInt() + gasTipCap = args.MaxPriorityFeePerGas.ToInt() // Backfill the legacy gasPrice for EVM execution, unless we're all zeroes gasPrice = new(big.Int) if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 { @@ -423,40 +447,29 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (* } } } - if args.BlobFeeCap != nil { - blobFeeCap = args.BlobFeeCap.ToInt() - } else if args.BlobHashes != nil { - blobFeeCap = new(big.Int) - } - value := new(big.Int) - if args.Value != nil { - value = args.Value.ToInt() - } - data := args.data() var accessList types.AccessList if args.AccessList != nil { accessList = *args.AccessList } - msg := &core.Message{ - From: addr, + return &core.Message{ + From: args.from(), To: args.To, - Value: value, - GasLimit: gas, + Value: (*big.Int)(args.Value), + GasLimit: uint64(*args.Gas), GasPrice: gasPrice, GasFeeCap: gasFeeCap, GasTipCap: gasTipCap, - Data: data, + Data: args.data(), AccessList: accessList, - BlobGasFeeCap: blobFeeCap, + BlobGasFeeCap: (*big.Int)(args.BlobFeeCap), BlobHashes: args.BlobHashes, SkipAccountChecks: true, } - return msg, nil } -// toTransaction converts the arguments to a transaction. +// ToTransaction converts the arguments to a transaction. // This assumes that setDefaults has been called. -func (args *TransactionArgs) toTransaction() *types.Transaction { +func (args *TransactionArgs) ToTransaction() *types.Transaction { var data types.TxData switch { case args.BlobHashes != nil: diff --git a/miner/worker.go b/miner/worker.go index f22242841f77..9f8d9f663f86 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -265,7 +265,7 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (* snap = env.state.Snapshot() gp = env.gasPool.Gas() ) - receipt, err := core.ApplyTransaction(miner.chainConfig, miner.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *miner.chain.GetVMConfig()) + receipt, err := core.ApplyTransaction(miner.chainConfig, miner.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vm.Config{}) if err != nil { env.state.RevertToSnapshot(snap) env.gasPool.SetGas(gp) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 53d733f1c44d..04a04fdc288c 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -34,6 +34,7 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/log" @@ -109,7 +110,7 @@ type btHeaderMarshaling struct { ExcessBlobGas *math.HexOrDecimal64 } -func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger, postCheck func(error, *core.BlockChain)) (result error) { +func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { config, ok := Forks[t.json.Network] if !ok { return UnsupportedForkError{t.json.Network} diff --git a/tests/state_test_util.go b/tests/state_test_util.go index c916d26d412a..367688e57f9e 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -227,15 +228,15 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bo // RunNoVerify runs a specific subtest and returns the statedb and post-state root. // Remember to call state.Close after verifying the test result! -func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string) (state StateTestState, root common.Hash, err error) { +func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string) (st StateTestState, root common.Hash, err error) { config, eips, err := GetChainConfig(subtest.Fork) if err != nil { - return state, common.Hash{}, UnsupportedForkError{subtest.Fork} + return st, common.Hash{}, UnsupportedForkError{subtest.Fork} } vmconfig.ExtraEips = eips block := t.genesis(config).ToBlock() - state = MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter, scheme) + st = MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter, scheme) var baseFee *big.Int if config.IsLondon(new(big.Int)) { @@ -249,7 +250,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh post := t.json.Post[subtest.Fork][subtest.Index] msg, err := t.json.Tx.toMessage(post, baseFee) if err != nil { - return state, common.Hash{}, err + return st, common.Hash{}, err } { // Blob transactions may be present after the Cancun fork. @@ -259,7 +260,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // Here, we just do this shortcut smaller fix, since state tests do not // utilize those codepaths if len(msg.BlobHashes)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock { - return state, common.Hash{}, errors.New("blob gas exceeds maximum") + return st, common.Hash{}, errors.New("blob gas exceeds maximum") } } @@ -268,10 +269,10 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh var ttx types.Transaction err := ttx.UnmarshalBinary(post.TxBytes) if err != nil { - return state, common.Hash{}, err + return st, common.Hash{}, err } if _, err := types.Sender(types.LatestSigner(config), &ttx); err != nil { - return state, common.Hash{}, err + return st, common.Hash{}, err } } @@ -292,26 +293,26 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh if config.IsCancun(new(big.Int), block.Time()) && t.json.Env.ExcessBlobGas != nil { context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas) } - evm := vm.NewEVM(context, txContext, state.StateDB, config, vmconfig) + evm := vm.NewEVM(context, txContext, st.StateDB, config, vmconfig) // Execute the message. - snapshot := state.StateDB.Snapshot() + snapshot := st.StateDB.Snapshot() gaspool := new(core.GasPool) gaspool.AddGas(block.GasLimit()) _, err = core.ApplyMessage(evm, msg, gaspool) if err != nil { - state.StateDB.RevertToSnapshot(snapshot) + st.StateDB.RevertToSnapshot(snapshot) } // Add 0-value mining reward. This only makes a difference in the cases // where // - the coinbase self-destructed, or // - there are only 'bad' transactions, which aren't executed. In those cases, // the coinbase gets no txfee, so isn't created, and thus needs to be touched - state.StateDB.AddBalance(block.Coinbase(), new(uint256.Int)) + st.StateDB.AddBalance(block.Coinbase(), new(uint256.Int), tracing.BalanceChangeUnspecified) // Commit state mutations into database. - root, _ = state.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number())) - return state, root, err + root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number())) + return st, root, err } func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { @@ -456,7 +457,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bo for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) - statedb.SetBalance(addr, uint256.MustFromBig(a.Balance)) + statedb.SetBalance(addr, uint256.MustFromBig(a.Balance), tracing.BalanceChangeUnspecified) for k, v := range a.Storage { statedb.SetState(addr, k, v) } From 6f1fb0c29ff25318e688c15581d0c28dcefb75ce Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 24 Mar 2024 20:51:34 +0800 Subject: [PATCH 097/571] metrics/influxdb: skip float64-precision-dependent tests on arm64 (#29047) metrics/influxdb: fix failed cases caused by float64 precision on arm64 --- metrics/influxdb/influxdb_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/metrics/influxdb/influxdb_test.go b/metrics/influxdb/influxdb_test.go index c6f2eeac6277..5879af7cf6a7 100644 --- a/metrics/influxdb/influxdb_test.go +++ b/metrics/influxdb/influxdb_test.go @@ -23,6 +23,7 @@ import ( "net/http/httptest" "net/url" "os" + "runtime" "strings" "testing" @@ -37,6 +38,10 @@ func TestMain(m *testing.M) { } func TestExampleV1(t *testing.T) { + if runtime.GOARCH == "arm64" { + t.Skip("test skipped on ARM64 due to floating point precision differences") + } + r := internal.ExampleMetrics() var have, want string ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -69,6 +74,10 @@ func TestExampleV1(t *testing.T) { } func TestExampleV2(t *testing.T) { + if runtime.GOARCH == "arm64" { + t.Skip("test skipped on ARM64 due to floating point precision differences") + } + r := internal.ExampleMetrics() var have, want string ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { From ae470044878f15beb67eb7e66c117c9ad48f3a7b Mon Sep 17 00:00:00 2001 From: deterclosed <164524498+deterclosed@users.noreply.github.com> Date: Mon, 25 Mar 2024 10:16:44 +0800 Subject: [PATCH 098/571] eth: fix typo (#29320) --- eth/handler_eth_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 297a6bf154ed..a38059ca953e 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -390,7 +390,7 @@ func testTransactionPropagation(t *testing.T, protocol uint) { } // Interconnect all the sink handlers with the source handler for i, sink := range sinks { - sink := sink // Closure for gorotuine below + sink := sink // Closure for goroutine below sourcePipe, sinkPipe := p2p.MsgPipe() defer sourcePipe.Close() From 14cc967d1964d3366252193cadd4bfcb4c927ac1 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 25 Mar 2024 07:50:18 +0100 Subject: [PATCH 099/571] all: remove dependency on golang.org/exp (#29314) This change includes a leftovers from https://github.com/ethereum/go-ethereum/pull/29307 - using the [new `slices` package](https://go.dev/doc/go1.21#slices) and - using the [new `cmp.Ordered`](https://go.dev/doc/go1.21#cmp) instead of exp `constraints.Ordered` --- accounts/keystore/account_cache.go | 2 +- accounts/keystore/account_cache_test.go | 2 +- accounts/keystore/keystore_test.go | 2 +- build/update-license.go | 3 +-- cmd/devp2p/dns_route53.go | 2 +- cmd/devp2p/internal/ethtest/chain.go | 2 +- cmd/devp2p/nodeset.go | 2 +- common/prque/lazyqueue.go | 10 +++++----- common/prque/prque.go | 7 +++---- common/prque/sstack.go | 8 ++++---- consensus/clique/snapshot.go | 2 +- consensus/clique/snapshot_test.go | 2 +- core/forkid/forkid.go | 2 +- core/mkalloc.go | 2 +- core/rawdb/accessors_chain.go | 2 +- core/state/snapshot/difflayer.go | 2 +- core/state/snapshot/iterator_fast.go | 2 +- core/txpool/legacypool/list.go | 2 +- eth/api_debug_test.go | 2 +- eth/gasprice/feehistory.go | 2 +- eth/gasprice/gasprice.go | 2 +- eth/protocols/snap/sync_test.go | 2 +- eth/tracers/api_test.go | 2 +- ethdb/dbtest/testsuite.go | 2 +- go.mod | 2 +- internal/ethapi/api_test.go | 2 +- metrics/sample.go | 3 +-- metrics/writer.go | 3 +-- metrics/writer_test.go | 3 +-- p2p/discover/ntp.go | 2 +- p2p/discover/table_util_test.go | 2 +- p2p/discover/v4_lookup_test.go | 2 +- p2p/discover/v5_udp_test.go | 2 +- p2p/dnsdisc/tree.go | 2 +- p2p/peer.go | 2 +- p2p/server.go | 2 +- tests/fuzzers/rangeproof/rangeproof-fuzzer.go | 2 +- trie/proof_test.go | 2 +- trie/stacktrie_fuzzer_test.go | 2 +- trie/stacktrie_test.go | 2 +- triedb/pathdb/history.go | 2 +- triedb/pathdb/testutils.go | 2 +- 42 files changed, 51 insertions(+), 56 deletions(-) diff --git a/accounts/keystore/account_cache.go b/accounts/keystore/account_cache.go index 4ed1439514e1..f7cf688e62af 100644 --- a/accounts/keystore/account_cache.go +++ b/accounts/keystore/account_cache.go @@ -22,6 +22,7 @@ import ( "fmt" "os" "path/filepath" + "slices" "sort" "strings" "sync" @@ -31,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" - "golang.org/x/exp/slices" ) // Minimum amount of time between cache reloads. This limit applies if the platform does diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index bb92cc2adca5..f24071007b27 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" "reflect" + "slices" "testing" "time" @@ -30,7 +31,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" - "golang.org/x/exp/slices" ) var ( diff --git a/accounts/keystore/keystore_test.go b/accounts/keystore/keystore_test.go index c871392b82ec..23ba31dc910f 100644 --- a/accounts/keystore/keystore_test.go +++ b/accounts/keystore/keystore_test.go @@ -20,6 +20,7 @@ import ( "math/rand" "os" "runtime" + "slices" "strings" "sync" "sync/atomic" @@ -30,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" - "golang.org/x/exp/slices" ) var testSigData = make([]byte, 32) diff --git a/build/update-license.go b/build/update-license.go index 70e2de06c776..58e8b16045c6 100644 --- a/build/update-license.go +++ b/build/update-license.go @@ -46,13 +46,12 @@ import ( "path/filepath" "regexp" "runtime" + "slices" "strconv" "strings" "sync" "text/template" "time" - - "golang.org/x/exp/slices" ) var ( diff --git a/cmd/devp2p/dns_route53.go b/cmd/devp2p/dns_route53.go index 21a32f9414e4..a6125b8263a8 100644 --- a/cmd/devp2p/dns_route53.go +++ b/cmd/devp2p/dns_route53.go @@ -20,6 +20,7 @@ import ( "context" "errors" "fmt" + "slices" "strconv" "strings" "time" @@ -32,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/dnsdisc" "github.com/urfave/cli/v2" - "golang.org/x/exp/slices" ) const ( diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index a34a41dacdaa..2b503d62df93 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -27,6 +27,7 @@ import ( "math/big" "os" "path/filepath" + "slices" "sort" "strings" @@ -40,7 +41,6 @@ import ( "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/exp/slices" ) // Chain is a lightweight blockchain-like store which can read a hivechain diff --git a/cmd/devp2p/nodeset.go b/cmd/devp2p/nodeset.go index 7360dc5bcfd9..4fa862de14cb 100644 --- a/cmd/devp2p/nodeset.go +++ b/cmd/devp2p/nodeset.go @@ -21,11 +21,11 @@ import ( "encoding/json" "fmt" "os" + "slices" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/p2p/enode" - "golang.org/x/exp/slices" ) const jsonIndent = " " diff --git a/common/prque/lazyqueue.go b/common/prque/lazyqueue.go index 59bda72fa7e7..ebe53d5e6b01 100644 --- a/common/prque/lazyqueue.go +++ b/common/prque/lazyqueue.go @@ -17,11 +17,11 @@ package prque import ( + "cmp" "container/heap" "time" "github.com/ethereum/go-ethereum/common/mclock" - "golang.org/x/exp/constraints" ) // LazyQueue is a priority queue data structure where priorities can change over @@ -33,7 +33,7 @@ import ( // // If the upper estimate is exceeded then Update should be called for that item. // A global Refresh function should also be called periodically. -type LazyQueue[P constraints.Ordered, V any] struct { +type LazyQueue[P cmp.Ordered, V any] struct { clock mclock.Clock // Items are stored in one of two internal queues ordered by estimated max // priority until the next and the next-after-next refresh. Update and Refresh @@ -50,12 +50,12 @@ type LazyQueue[P constraints.Ordered, V any] struct { } type ( - PriorityCallback[P constraints.Ordered, V any] func(data V) P // actual priority callback - MaxPriorityCallback[P constraints.Ordered, V any] func(data V, until mclock.AbsTime) P // estimated maximum priority callback + PriorityCallback[P cmp.Ordered, V any] func(data V) P // actual priority callback + MaxPriorityCallback[P cmp.Ordered, V any] func(data V, until mclock.AbsTime) P // estimated maximum priority callback ) // NewLazyQueue creates a new lazy queue -func NewLazyQueue[P constraints.Ordered, V any](setIndex SetIndexCallback[V], priority PriorityCallback[P, V], maxPriority MaxPriorityCallback[P, V], clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue[P, V] { +func NewLazyQueue[P cmp.Ordered, V any](setIndex SetIndexCallback[V], priority PriorityCallback[P, V], maxPriority MaxPriorityCallback[P, V], clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue[P, V] { q := &LazyQueue[P, V]{ popQueue: newSstack[P, V](nil), setIndex: setIndex, diff --git a/common/prque/prque.go b/common/prque/prque.go index 0e8c9f897fad..ec8351020a10 100755 --- a/common/prque/prque.go +++ b/common/prque/prque.go @@ -18,18 +18,17 @@ package prque import ( + "cmp" "container/heap" - - "golang.org/x/exp/constraints" ) // Priority queue data structure. -type Prque[P constraints.Ordered, V any] struct { +type Prque[P cmp.Ordered, V any] struct { cont *sstack[P, V] } // New creates a new priority queue. -func New[P constraints.Ordered, V any](setIndex SetIndexCallback[V]) *Prque[P, V] { +func New[P cmp.Ordered, V any](setIndex SetIndexCallback[V]) *Prque[P, V] { return &Prque[P, V]{newSstack[P, V](setIndex)} } diff --git a/common/prque/sstack.go b/common/prque/sstack.go index 5dcd1d9dd0c4..ee6d7c0c3ac5 100755 --- a/common/prque/sstack.go +++ b/common/prque/sstack.go @@ -10,13 +10,13 @@ package prque -import "golang.org/x/exp/constraints" +import "cmp" // The size of a block of data const blockSize = 4096 // A prioritized item in the sorted stack. -type item[P constraints.Ordered, V any] struct { +type item[P cmp.Ordered, V any] struct { value V priority P } @@ -29,7 +29,7 @@ type SetIndexCallback[V any] func(data V, 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[P constraints.Ordered, V any] struct { +type sstack[P cmp.Ordered, V any] struct { setIndex SetIndexCallback[V] size int capacity int @@ -40,7 +40,7 @@ type sstack[P constraints.Ordered, V any] struct { } // Creates a new, empty stack. -func newSstack[P constraints.Ordered, V any](setIndex SetIndexCallback[V]) *sstack[P, V] { +func newSstack[P cmp.Ordered, V any](setIndex SetIndexCallback[V]) *sstack[P, V] { result := new(sstack[P, V]) result.setIndex = setIndex result.active = make([]*item[P, V], blockSize) diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go index a97115121b82..8ff0b3a70ff7 100644 --- a/consensus/clique/snapshot.go +++ b/consensus/clique/snapshot.go @@ -19,6 +19,7 @@ package clique import ( "bytes" "encoding/json" + "slices" "time" "github.com/ethereum/go-ethereum/common" @@ -28,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "golang.org/x/exp/slices" ) // Vote represents a single vote that an authorized signer made to modify the diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 26cebe008a88..4ef7a7b3aee6 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -21,6 +21,7 @@ import ( "crypto/ecdsa" "fmt" "math/big" + "slices" "testing" "github.com/ethereum/go-ethereum/common" @@ -30,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" - "golang.org/x/exp/slices" ) // testerAccountPool is a pool to maintain currently active tester accounts, diff --git a/core/forkid/forkid.go b/core/forkid/forkid.go index 76825d3befc1..4db366da8254 100644 --- a/core/forkid/forkid.go +++ b/core/forkid/forkid.go @@ -24,12 +24,12 @@ import ( "math" "math/big" "reflect" + "slices" "strings" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "golang.org/x/exp/slices" ) var ( diff --git a/core/mkalloc.go b/core/mkalloc.go index 12c40c14fbea..201c2fe7de8d 100644 --- a/core/mkalloc.go +++ b/core/mkalloc.go @@ -30,12 +30,12 @@ import ( "fmt" "math/big" "os" + "slices" "strconv" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/exp/slices" ) type allocItem struct { diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 964b3a311de5..8a69dc6babe5 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "math/big" + "slices" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" @@ -31,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/exp/slices" ) // ReadCanonicalHash retrieves the hash assigned to a canonical block number. diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index 70c9f4418962..779c1ea98c2f 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -21,6 +21,7 @@ import ( "fmt" "math" "math/rand" + "slices" "sync" "sync/atomic" "time" @@ -29,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" bloomfilter "github.com/holiman/bloomfilter/v2" - "golang.org/x/exp/slices" ) var ( diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index 0502d9cf8596..9b018bac568d 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -19,10 +19,10 @@ package snapshot import ( "bytes" "fmt" + "slices" "sort" "github.com/ethereum/go-ethereum/common" - "golang.org/x/exp/slices" ) // weightedIterator is a iterator with an assigned weight. It is used to prioritise diff --git a/core/txpool/legacypool/list.go b/core/txpool/legacypool/list.go index 7db9c98ace63..b749db44d45e 100644 --- a/core/txpool/legacypool/list.go +++ b/core/txpool/legacypool/list.go @@ -20,6 +20,7 @@ import ( "container/heap" "math" "math/big" + "slices" "sort" "sync" "sync/atomic" @@ -28,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/holiman/uint256" - "golang.org/x/exp/slices" ) // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index 1d75c4c041b0..750cee5e44e8 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "reflect" + "slices" "strings" "testing" @@ -32,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/triedb" "github.com/holiman/uint256" - "golang.org/x/exp/slices" ) var dumper = spew.ConfigState{Indent: " "} diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 8ab57294b7e8..1c7f8ba42a26 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -23,6 +23,7 @@ import ( "fmt" "math" "math/big" + "slices" "sync/atomic" "github.com/ethereum/go-ethereum/common" @@ -30,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" - "golang.org/x/exp/slices" ) var ( diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 3fa70e41a094..c90408e36302 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -19,6 +19,7 @@ package gasprice import ( "context" "math/big" + "slices" "sync" "github.com/ethereum/go-ethereum/common" @@ -30,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "golang.org/x/exp/slices" ) const sampleNumber = 3 // Number of transactions sampled in a block diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 9bfc9bcb5c57..ab7c493c0320 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -23,6 +23,7 @@ import ( "fmt" "math/big" mrand "math/rand" + "slices" "sync" "testing" "time" @@ -41,7 +42,6 @@ import ( "github.com/ethereum/go-ethereum/triedb/pathdb" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" - "golang.org/x/exp/slices" ) func TestHashing(t *testing.T) { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 3254f4961fc7..02809ef57e54 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -24,6 +24,7 @@ import ( "fmt" "math/big" "reflect" + "slices" "sync/atomic" "testing" "time" @@ -43,7 +44,6 @@ import ( "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "golang.org/x/exp/slices" ) var ( diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 29bd24364e3f..c7e656d2e7da 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -20,11 +20,11 @@ import ( "bytes" "crypto/rand" "reflect" + "slices" "sort" "testing" "github.com/ethereum/go-ethereum/ethdb" - "golang.org/x/exp/slices" ) // TestDatabaseSuite runs a suite of tests against a KeyValueStore database diff --git a/go.mod b/go.mod index 15113972f527..ab268da0685b 100644 --- a/go.mod +++ b/go.mod @@ -67,7 +67,6 @@ require ( github.com/urfave/cli/v2 v2.25.7 go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.21.0 - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.5.0 golang.org/x/sys v0.18.0 golang.org/x/text v0.14.0 @@ -140,6 +139,7 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.21.0 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 5636309589df..b9ccf2bf7d46 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -28,6 +28,7 @@ import ( "os" "path/filepath" "reflect" + "slices" "testing" "time" @@ -54,7 +55,6 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/holiman/uint256" "github.com/stretchr/testify/require" - "golang.org/x/exp/slices" ) func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainConfig) { diff --git a/metrics/sample.go b/metrics/sample.go index bb81e105cf9e..e4735fb6fffa 100644 --- a/metrics/sample.go +++ b/metrics/sample.go @@ -3,10 +3,9 @@ package metrics import ( "math" "math/rand" + "slices" "sync" "time" - - "golang.org/x/exp/slices" ) const rescaleThreshold = time.Hour diff --git a/metrics/writer.go b/metrics/writer.go index 098da45c27b2..c211c5046b7d 100644 --- a/metrics/writer.go +++ b/metrics/writer.go @@ -3,10 +3,9 @@ package metrics import ( "fmt" "io" + "slices" "strings" "time" - - "golang.org/x/exp/slices" ) // Write sorts writes each metric in the given registry periodically to the diff --git a/metrics/writer_test.go b/metrics/writer_test.go index 8376bf8975c8..edcfe955abcf 100644 --- a/metrics/writer_test.go +++ b/metrics/writer_test.go @@ -1,9 +1,8 @@ package metrics import ( + "slices" "testing" - - "golang.org/x/exp/slices" ) func TestMetricsSorting(t *testing.T) { diff --git a/p2p/discover/ntp.go b/p2p/discover/ntp.go index 3f9157808f12..c8b82ef7e876 100644 --- a/p2p/discover/ntp.go +++ b/p2p/discover/ntp.go @@ -22,10 +22,10 @@ package discover import ( "fmt" "net" + "slices" "time" "github.com/ethereum/go-ethereum/log" - "golang.org/x/exp/slices" ) const ( diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index d6309dfd6c69..f5d4d39bdbb7 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -24,12 +24,12 @@ import ( "fmt" "math/rand" "net" + "slices" "sync" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" - "golang.org/x/exp/slices" ) var nullNode *enode.Node diff --git a/p2p/discover/v4_lookup_test.go b/p2p/discover/v4_lookup_test.go index 8867a5a8ac75..691ce4be3f73 100644 --- a/p2p/discover/v4_lookup_test.go +++ b/p2p/discover/v4_lookup_test.go @@ -20,13 +20,13 @@ import ( "crypto/ecdsa" "fmt" "net" + "slices" "testing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/discover/v4wire" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" - "golang.org/x/exp/slices" ) func TestUDPv4_Lookup(t *testing.T) { diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index eaa969ea8b69..4373ea81847f 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -24,6 +24,7 @@ import ( "math/rand" "net" "reflect" + "slices" "testing" "time" @@ -34,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/require" - "golang.org/x/exp/slices" ) // Real sockets, real crypto: this test checks end-to-end connectivity for UDPv5. diff --git a/p2p/dnsdisc/tree.go b/p2p/dnsdisc/tree.go index dfac4fb37208..a8295ac9eba6 100644 --- a/p2p/dnsdisc/tree.go +++ b/p2p/dnsdisc/tree.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "io" + "slices" "strings" "github.com/ethereum/go-ethereum/crypto" @@ -31,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" "golang.org/x/crypto/sha3" - "golang.org/x/exp/slices" ) // Tree is a merkle tree of node records. diff --git a/p2p/peer.go b/p2p/peer.go index 65a7903f5863..e4482deae9f7 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "net" + "slices" "sync" "time" @@ -31,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/exp/slices" ) var ( diff --git a/p2p/server.go b/p2p/server.go index 5b7afb4565b9..a5f3b8d190a2 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "net" + "slices" "sync" "sync/atomic" "time" @@ -38,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" - "golang.org/x/exp/slices" ) const ( diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go index dcafebb265d5..4d94d31c0ca1 100644 --- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go +++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go @@ -21,13 +21,13 @@ import ( "encoding/binary" "fmt" "io" + "slices" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/triedb" - "golang.org/x/exp/slices" ) type kv struct { diff --git a/trie/proof_test.go b/trie/proof_test.go index 5471d0efa6bb..93cf32abbf91 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -22,13 +22,13 @@ import ( "encoding/binary" "fmt" mrand "math/rand" + "slices" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb/memorydb" - "golang.org/x/exp/slices" ) // Prng is a pseudo random number generator seeded by strong randomness. diff --git a/trie/stacktrie_fuzzer_test.go b/trie/stacktrie_fuzzer_test.go index 50b5c4de52f7..57a31d115f5a 100644 --- a/trie/stacktrie_fuzzer_test.go +++ b/trie/stacktrie_fuzzer_test.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/binary" "fmt" + "slices" "testing" "github.com/ethereum/go-ethereum/common" @@ -28,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" - "golang.org/x/exp/slices" ) func FuzzStackTrie(f *testing.F) { diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index 203ebd99a9ea..58115bc33a40 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -20,6 +20,7 @@ import ( "bytes" "math/big" "math/rand" + "slices" "testing" "github.com/ethereum/go-ethereum/common" @@ -27,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/testrand" "github.com/stretchr/testify/assert" - "golang.org/x/exp/slices" ) func TestStackTrieInsertAndHash(t *testing.T) { diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 68fb4809f01d..7099b2b381f2 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -21,6 +21,7 @@ import ( "encoding/binary" "errors" "fmt" + "slices" "time" "github.com/ethereum/go-ethereum/common" @@ -28,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie/triestate" - "golang.org/x/exp/slices" ) // State history records the state changes involved in executing a block. The diff --git a/triedb/pathdb/testutils.go b/triedb/pathdb/testutils.go index 546cb819b83a..0c99565b8e28 100644 --- a/triedb/pathdb/testutils.go +++ b/triedb/pathdb/testutils.go @@ -19,13 +19,13 @@ package pathdb import ( "bytes" "fmt" + "slices" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" - "golang.org/x/exp/slices" ) // testHasher is a test utility for computing root hash of a batch of state From 5cea7a6230a6f070dd484aa6d883605f148445a4 Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Mon, 25 Mar 2024 10:03:44 -0700 Subject: [PATCH 100/571] ethclient/simulated: clean up Node resources when simulated backend is closed (#29316) --- eth/backend.go | 4 ++-- ethclient/simulated/backend.go | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index e6f9c05950d8..db3209aee2e3 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -101,8 +101,8 @@ type Ethereum struct { shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully } -// New creates a new Ethereum object (including the -// initialisation of the common Ethereum object) +// New creates a new Ethereum object (including the initialisation of the common Ethereum object), +// whose lifecycle will be managed by the provided node. func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // Ensure configuration values are compatible and sane if config.SyncMode == downloader.LightSync { diff --git a/ethclient/simulated/backend.go b/ethclient/simulated/backend.go index 0c2a0b453c1b..d6fb886ad891 100644 --- a/ethclient/simulated/backend.go +++ b/ethclient/simulated/backend.go @@ -17,6 +17,7 @@ package simulated import ( + "errors" "time" "github.com/ethereum/go-ethereum" @@ -62,7 +63,7 @@ type simClient struct { // Backend is a simulated blockchain. You can use it to test your contracts or // other code that interacts with the Ethereum chain. type Backend struct { - eth *eth.Ethereum + node *node.Node beacon *catalyst.SimulatedBeacon client simClient } @@ -129,7 +130,7 @@ func newWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (*Backe return nil, err } return &Backend{ - eth: backend, + node: stack, beacon: beacon, client: simClient{ethclient.NewClient(stack.Attach())}, }, nil @@ -142,12 +143,16 @@ func (n *Backend) Close() error { n.client.Close() n.client = simClient{} } + var err error if n.beacon != nil { - err := n.beacon.Stop() + err = n.beacon.Stop() n.beacon = nil - return err } - return nil + if n.node != nil { + err = errors.Join(err, n.node.Close()) + n.node = nil + } + return err } // Commit seals a block and moves the chain forward to a new empty block. From eda9cb7b362b02c9c4550d77385997ed86981757 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 25 Mar 2024 20:27:50 +0100 Subject: [PATCH 101/571] beacon/light/api: improve handling of event stream setup failures (#29308) The StartHeadListener method will only be called once. So it can't just make one attempt to connect to the eventsource endpoint, it has to keep trying. Note that once the stream is established, the eventsource implementation itself will keep retrying. --- beacon/light/api/light_api.go | 106 ++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 32 deletions(-) diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 1bba220d3129..8689877d8bc5 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -17,11 +17,13 @@ package api import ( + "context" "encoding/json" "errors" "fmt" "io" "net/http" + "sync" "time" "github.com/donovanhide/eventsource" @@ -416,39 +418,34 @@ type HeadEventListener struct { // The callbacks are also called for the current head and optimistic head at startup. // They are never called concurrently. func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() { - closeCh := make(chan struct{}) // initiate closing the stream - closedCh := make(chan struct{}) // stream closed (or failed to create) - stoppedCh := make(chan struct{}) // sync loop stopped - streamCh := make(chan *eventsource.Stream, 1) + var ( + ctx, closeCtx = context.WithCancel(context.Background()) + streamCh = make(chan *eventsource.Stream, 1) + wg sync.WaitGroup + ) + + // When connected to a Lodestar node the subscription blocks until the first actual + // event arrives; therefore we create the subscription in a separate goroutine while + // letting the main goroutine sync up to the current head. + wg.Add(1) go func() { - defer close(closedCh) - // when connected to a Lodestar node the subscription blocks until the - // first actual event arrives; therefore we create the subscription in - // a separate goroutine while letting the main goroutine sync up to the - // current head - req, err := http.NewRequest("GET", api.url+ - "/eth/v1/events?topics=head&topics=light_client_optimistic_update&topics=light_client_finality_update", nil) - if err != nil { - listener.OnError(fmt.Errorf("error creating event subscription request: %v", err)) - return - } - for k, v := range api.customHeaders { - req.Header.Set(k, v) - } - stream, err := eventsource.SubscribeWithRequest("", req) - if err != nil { - listener.OnError(fmt.Errorf("error creating event subscription: %v", err)) - close(streamCh) + defer wg.Done() + stream := api.startEventStream(ctx, &listener) + if stream == nil { + // This case happens when the context was closed. return } + // Stream was opened, wait for close signal. streamCh <- stream - <-closeCh + <-ctx.Done() stream.Close() }() + wg.Add(1) go func() { - defer close(stoppedCh) + defer wg.Done() + // Request initial data. if head, err := api.GetHeader(common.Hash{}); err == nil { listener.OnNewHead(head.Slot, head.Hash()) } @@ -458,32 +455,42 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() if finalityUpdate, err := api.GetFinalityUpdate(); err == nil { listener.OnFinality(finalityUpdate) } - stream := <-streamCh - if stream == nil { + + // Receive the stream. + var stream *eventsource.Stream + select { + case stream = <-streamCh: + case <-ctx.Done(): return } for { select { + case <-ctx.Done(): + stream.Close() + case event, ok := <-stream.Events: if !ok { return } switch event.Event() { case "head": - if slot, blockRoot, err := decodeHeadEvent([]byte(event.Data())); err == nil { + slot, blockRoot, err := decodeHeadEvent([]byte(event.Data())) + if err == nil { listener.OnNewHead(slot, blockRoot) } else { listener.OnError(fmt.Errorf("error decoding head event: %v", err)) } case "light_client_optimistic_update": - if signedHead, err := decodeOptimisticHeadUpdate([]byte(event.Data())); err == nil { + signedHead, err := decodeOptimisticHeadUpdate([]byte(event.Data())) + if err == nil { listener.OnSignedHead(signedHead) } else { listener.OnError(fmt.Errorf("error decoding optimistic update event: %v", err)) } case "light_client_finality_update": - if finalityUpdate, err := decodeFinalityUpdate([]byte(event.Data())); err == nil { + finalityUpdate, err := decodeFinalityUpdate([]byte(event.Data())) + if err == nil { listener.OnFinality(finalityUpdate) } else { listener.OnError(fmt.Errorf("error decoding finality update event: %v", err)) @@ -491,6 +498,7 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() default: listener.OnError(fmt.Errorf("unexpected event: %s", event.Event())) } + case err, ok := <-stream.Errors: if !ok { return @@ -499,9 +507,43 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() } } }() + return func() { - close(closeCh) - <-closedCh - <-stoppedCh + closeCtx() + wg.Wait() + } +} + +// startEventStream establishes an event stream. This will keep retrying until the stream has been +// established. It can only return nil when the context is canceled. +func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream { + for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) { + path := "/eth/v1/events?topics=head&topics=light_client_optimistic_update&topics=light_client_finality_update" + req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil) + if err != nil { + listener.OnError(fmt.Errorf("error creating event subscription request: %v", err)) + continue + } + for k, v := range api.customHeaders { + req.Header.Set(k, v) + } + stream, err := eventsource.SubscribeWithRequest("", req) + if err != nil { + listener.OnError(fmt.Errorf("error creating event subscription: %v", err)) + continue + } + return stream + } + return nil +} + +func ctxSleep(ctx context.Context, timeout time.Duration) (ok bool) { + timer := time.NewTimer(timeout) + defer timer.Stop() + select { + case <-timer.C: + return true + case <-ctx.Done(): + return false } } From 100c0f47debad7924acefd48382bd799b67693cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Mon, 25 Mar 2024 20:28:55 +0100 Subject: [PATCH 102/571] beacon/blsync: fixed blsync command line params (#29335) --- beacon/blsync/config.go | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/beacon/blsync/config.go b/beacon/blsync/config.go index 1b0b0dbff935..93ed81306c98 100644 --- a/beacon/blsync/config.go +++ b/beacon/blsync/config.go @@ -72,9 +72,9 @@ var ( ) func makeChainConfig(ctx *cli.Context) lightClientConfig { - utils.CheckExclusive(ctx, utils.MainnetFlag, utils.GoerliFlag, utils.SepoliaFlag) - customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name) || ctx.IsSet(utils.BeaconGenesisRootFlag.Name) || ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) var config lightClientConfig + customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name) + utils.CheckExclusive(ctx, utils.MainnetFlag, utils.GoerliFlag, utils.SepoliaFlag, utils.BeaconConfigFlag) switch { case ctx.Bool(utils.MainnetFlag.Name): config = MainnetConfig @@ -87,24 +87,37 @@ func makeChainConfig(ctx *cli.Context) lightClientConfig { config = MainnetConfig } } - if customConfig && config.Forks != nil { - utils.Fatalf("Cannot use custom beacon chain config flags in combination with pre-defined network config") - } - if ctx.IsSet(utils.BeaconGenesisRootFlag.Name) { + // Genesis root and time should always be specified together with custom chain config + if customConfig { + if !ctx.IsSet(utils.BeaconGenesisRootFlag.Name) { + utils.Fatalf("Custom beacon chain config is specified but genesis root is missing") + } + if !ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) { + utils.Fatalf("Custom beacon chain config is specified but genesis time is missing") + } + if !ctx.IsSet(utils.BeaconCheckpointFlag.Name) { + utils.Fatalf("Custom beacon chain config is specified but checkpoint is missing") + } + config.ChainConfig = &types.ChainConfig{ + GenesisTime: ctx.Uint64(utils.BeaconGenesisTimeFlag.Name), + } if c, err := hexutil.Decode(ctx.String(utils.BeaconGenesisRootFlag.Name)); err == nil && len(c) <= 32 { copy(config.GenesisValidatorsRoot[:len(c)], c) } else { utils.Fatalf("Invalid hex string", "beacon.genesis.gvroot", ctx.String(utils.BeaconGenesisRootFlag.Name), "error", err) } - } - if ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) { - config.GenesisTime = ctx.Uint64(utils.BeaconGenesisTimeFlag.Name) - } - if ctx.IsSet(utils.BeaconConfigFlag.Name) { if err := config.ChainConfig.LoadForks(ctx.String(utils.BeaconConfigFlag.Name)); err != nil { utils.Fatalf("Could not load beacon chain config file", "file name", ctx.String(utils.BeaconConfigFlag.Name), "error", err) } + } else { + if ctx.IsSet(utils.BeaconGenesisRootFlag.Name) { + utils.Fatalf("Genesis root is specified but custom beacon chain config is missing") + } + if ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) { + utils.Fatalf("Genesis time is specified but custom beacon chain config is missing") + } } + // Checkpoint is required with custom chain config and is optional with pre-defined config if ctx.IsSet(utils.BeaconCheckpointFlag.Name) { if c, err := hexutil.Decode(ctx.String(utils.BeaconCheckpointFlag.Name)); err == nil && len(c) <= 32 { copy(config.Checkpoint[:len(c)], c) From 738b5a586e329965539877434b695bb61015d4c7 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 26 Mar 2024 00:01:13 -0400 Subject: [PATCH 103/571] Removes some leftover `err` check (#29339) Before, `ToMessage` was returning both the resulting `Message` and an error while no error is returned now. Those error checks were probably leftover from the past. --- internal/ethapi/api.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 6009d7003193..c5a99588e6d2 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1186,9 +1186,6 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr return 0, err } call := args.ToMessage(header.BaseFee) - if err != nil { - return 0, err - } // Run the gas estimation andwrap any revertals into a custom return estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) if err != nil { @@ -1519,9 +1516,6 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Set the accesslist to the last al args.AccessList = &accessList msg := args.ToMessage(header.BaseFee) - if err != nil { - return nil, 0, nil, err - } // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) From f2a6ac17b255fe037bf528bc8368e61051cd4df4 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Tue, 26 Mar 2024 19:26:44 +0800 Subject: [PATCH 104/571] eth/catalyst: fix flaw in withdrawal-gathering in simulated beacon (#29344) return after reaching maxCount --- eth/catalyst/simulated_beacon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index 4ae60ed4907c..fecd83f2762c 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -63,7 +63,7 @@ func (w *withdrawalQueue) gatherPending(maxCount int) []*types.Withdrawal { case withdrawal := <-w.pending: withdrawals = append(withdrawals, withdrawal) if len(withdrawals) == maxCount { - break + return withdrawals } default: return withdrawals From 1dd898c24e85980a3ba9fcc203f00a3ea2f060d6 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 26 Mar 2024 15:04:15 +0100 Subject: [PATCH 105/571] tests: fix panic via state test runner using json logger (#29349) * tests: fix panic via state test runner using json logger * tests: also invoke OnTxEnd --- tests/state_test_util.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 367688e57f9e..416bab947264 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -295,6 +295,14 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh } evm := vm.NewEVM(context, txContext, st.StateDB, config, vmconfig) + if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil { + tracer.OnTxStart(evm.GetVMContext(), nil, msg.From) + if evm.Config.Tracer.OnTxEnd != nil { + defer func() { + evm.Config.Tracer.OnTxEnd(nil, err) + }() + } + } // Execute the message. snapshot := st.StateDB.Snapshot() gaspool := new(core.GasPool) From 58a3e2f1802eb7dd8e893a6a7be7f009edeeffd8 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 26 Mar 2024 07:21:39 -0700 Subject: [PATCH 106/571] core/state: perform updates before deletions when mutating tries (#29201) This addresses an edge-case (detailed in the code comment) where the computation of the intermediate trie root would force the unnecessary resolution of a hash node. The change makes it so that when we process changes from a block, we first process trie-updates and afterwards process trie-deletions. --- core/state/state_object.go | 29 ++++++++++++++++++++++------- core/state/statedb.go | 25 +++++++++++++++++++------ 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 910f4963411d..33b593f06992 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -298,6 +298,18 @@ func (s *stateObject) updateTrie() (Trie, error) { } // Insert all the pending storage updates into the trie usedStorage := make([][]byte, 0, len(s.pendingStorage)) + + // Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes + // in circumstances similar to the following: + // + // Consider nodes `A` and `B` who share the same full node parent `P` and have no other siblings. + // During the execution of a block: + // - `A` is deleted, + // - `C` is created, and also shares the parent `P`. + // If the deletion is handled first, then `P` would be left with only one child, thus collapsed + // into a shortnode. This requires `B` to be resolved from disk. + // Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved. + var deletions []common.Hash for key, value := range s.pendingStorage { // Skip noop changes, persist actual changes if value == s.originStorage[key] { @@ -307,13 +319,7 @@ func (s *stateObject) updateTrie() (Trie, error) { s.originStorage[key] = value var encoded []byte // rlp-encoded value to be used by the snapshot - if (value == common.Hash{}) { - if err := tr.DeleteStorage(s.address, key[:]); err != nil { - s.db.setError(err) - return nil, err - } - s.db.StorageDeleted += 1 - } else { + if (value != common.Hash{}) { // Encoding []byte cannot fail, ok to ignore the error. trimmed := common.TrimLeftZeroes(value[:]) encoded, _ = rlp.EncodeToBytes(trimmed) @@ -322,6 +328,8 @@ func (s *stateObject) updateTrie() (Trie, error) { return nil, err } s.db.StorageUpdated += 1 + } else { + deletions = append(deletions, key) } // Cache the mutated storage slots until commit if storage == nil { @@ -353,6 +361,13 @@ func (s *stateObject) updateTrie() (Trie, error) { // Cache the items for preloading usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure } + for _, key := range deletions { + if err := tr.DeleteStorage(s.address, key[:]); err != nil { + s.db.setError(err) + return nil, err + } + s.db.StorageDeleted += 1 + } if s.db.prefetcher != nil { s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage) } diff --git a/core/state/statedb.go b/core/state/statedb.go index 24914927c29b..e63513d8e19e 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -541,12 +541,11 @@ func (s *StateDB) updateStateObject(obj *stateObject) { } // deleteStateObject removes the given object from the state trie. -func (s *StateDB) deleteStateObject(obj *stateObject) { +func (s *StateDB) deleteStateObject(addr common.Address) { // Track the amount of time wasted on deleting the account from the trie defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) // Delete the account from the trie - addr := obj.Address() if err := s.trie.DeleteAccount(addr); err != nil { s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err)) } @@ -917,16 +916,30 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } } usedAddrs := make([][]byte, 0, len(s.stateObjectsPending)) + // Perform updates before deletions. This prevents resolution of unnecessary trie nodes + // in circumstances similar to the following: + // + // Consider nodes `A` and `B` who share the same full node parent `P` and have no other siblings. + // During the execution of a block: + // - `A` self-destructs, + // - `C` is created, and also shares the parent `P`. + // If the self-destruct is handled first, then `P` would be left with only one child, thus collapsed + // into a shortnode. This requires `B` to be resolved from disk. + // Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved. + var deletedAddrs []common.Address for addr := range s.stateObjectsPending { - if obj := s.stateObjects[addr]; obj.deleted { - s.deleteStateObject(obj) - s.AccountDeleted += 1 - } else { + if obj := s.stateObjects[addr]; !obj.deleted { s.updateStateObject(obj) s.AccountUpdated += 1 + } else { + deletedAddrs = append(deletedAddrs, obj.address) } usedAddrs = append(usedAddrs, common.CopyBytes(addr[:])) // Copy needed for closure } + for _, deletedAddr := range deletedAddrs { + s.deleteStateObject(deletedAddr) + s.AccountDeleted += 1 + } if prefetcher != nil { prefetcher.used(common.Hash{}, s.originalRoot, usedAddrs) } From 723b1e36ad6a9e998f06f74cc8b11d51635c6402 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Wed, 27 Mar 2024 04:01:28 +0800 Subject: [PATCH 107/571] all: fix mismatched names in comments (#29348) * all: fix mismatched names in comments * metrics: fix mismatched name in UpdateIfGt --- accounts/abi/argument.go | 2 +- accounts/keystore/account_cache_test.go | 2 +- beacon/light/api/light_api.go | 2 +- beacon/light/head_tracker.go | 4 ++-- beacon/light/request/server.go | 4 ++-- beacon/light/sync/head_sync.go | 4 ++-- beacon/types/exec_header.go | 2 +- cmd/geth/attach_test.go | 2 +- cmd/utils/export_test.go | 2 +- common/lru/basiclru.go | 2 +- consensus/ethash/consensus.go | 2 +- core/asm/lexer.go | 2 +- core/blockchain.go | 2 +- core/chain_makers.go | 2 +- core/rawdb/accessors_chain.go | 2 +- core/txpool/blobpool/blobpool.go | 2 +- core/vm/contracts.go | 4 ++-- core/vm/interpreter.go | 2 +- crypto/signature_nocgo.go | 2 +- eth/downloader/downloader_test.go | 2 +- eth/downloader/skeleton_test.go | 2 +- eth/filters/filter_system_test.go | 2 +- eth/protocols/eth/handler_test.go | 2 +- eth/protocols/snap/sync_test.go | 4 ++-- eth/tracers/api_test.go | 2 +- eth/tracers/internal/tracetest/flat_calltrace_test.go | 2 +- eth/tracers/internal/util.go | 2 +- eth/tracers/js/tracer_test.go | 2 +- eth/tracers/logger/access_list_tracer.go | 2 +- ethdb/dbtest/testsuite.go | 2 +- internal/era/era.go | 2 +- internal/version/version.go | 2 +- log/logger.go | 2 +- metrics/gauge.go | 2 +- metrics/meter.go | 2 +- metrics/metrics.go | 2 +- node/rpcstack.go | 2 +- p2p/discover/metrics.go | 2 +- p2p/enr/enr_test.go | 4 ++-- p2p/nodestate/nodestate.go | 2 +- p2p/simulations/adapters/types.go | 2 +- p2p/simulations/http_test.go | 2 +- p2p/simulations/network.go | 2 +- rpc/handler.go | 2 +- rpc/json.go | 2 +- rpc/subscription_test.go | 4 ++-- signer/core/apitypes/types.go | 2 +- signer/core/signed_data_test.go | 2 +- tests/init_test.go | 2 +- trie/proof_test.go | 2 +- trie/trie_test.go | 2 +- triedb/pathdb/database_test.go | 2 +- triedb/pathdb/disklayer.go | 4 ++-- 53 files changed, 61 insertions(+), 61 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index fa5461895af0..227a088b7d0e 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -127,7 +127,7 @@ func (arguments Arguments) Copy(v interface{}, values []interface{}) error { return arguments.copyAtomic(v, values[0]) } -// unpackAtomic unpacks ( hexdata -> go ) a single value +// copyAtomic copies ( hexdata -> go ) a single value func (arguments Arguments) copyAtomic(v interface{}, marshalledValues interface{}) error { dst := reflect.ValueOf(v).Elem() src := reflect.ValueOf(marshalledValues) diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index f24071007b27..1a9f9a4714cc 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -51,7 +51,7 @@ var ( } ) -// waitWatcherStarts waits up to 1s for the keystore watcher to start. +// waitWatcherStart waits up to 1s for the keystore watcher to start. func waitWatcherStart(ks *KeyStore) bool { // On systems where file watch is not supported, just return "ok". if !ks.cache.watcher.enabled() { diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 8689877d8bc5..ceb4261c3c9c 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -289,7 +289,7 @@ func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) { }, nil } -// GetHead fetches and validates the beacon header with the given blockRoot. +// GetHeader fetches and validates the beacon header with the given blockRoot. // If blockRoot is null hash then the latest head header is fetched. func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, error) { var blockId string diff --git a/beacon/light/head_tracker.go b/beacon/light/head_tracker.go index 579e1b53daa9..6036322f014b 100644 --- a/beacon/light/head_tracker.go +++ b/beacon/light/head_tracker.go @@ -56,7 +56,7 @@ func (h *HeadTracker) ValidatedHead() (types.SignedHeader, bool) { return h.signedHead, h.hasSignedHead } -// ValidatedHead returns the latest validated head. +// ValidatedFinality returns the latest validated finality. func (h *HeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { h.lock.RLock() defer h.lock.RUnlock() @@ -64,7 +64,7 @@ func (h *HeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { return h.finalityUpdate, h.hasFinalityUpdate } -// Validate validates the given signed head. If the head is successfully validated +// ValidateHead validates the given signed head. If the head is successfully validated // and it is better than the old validated head (higher slot or same slot and more // signers) then ValidatedHead is updated. The boolean return flag signals if // ValidatedHead has been changed. diff --git a/beacon/light/request/server.go b/beacon/light/request/server.go index 407eb69f497e..bcb8744b38a4 100644 --- a/beacon/light/request/server.go +++ b/beacon/light/request/server.go @@ -212,7 +212,7 @@ func (s *serverWithTimeout) startTimeout(reqData RequestResponse) { }) } -// stop stops all goroutines associated with the server. +// unsubscribe stops all goroutines associated with the server. func (s *serverWithTimeout) unsubscribe() { s.lock.Lock() defer s.lock.Unlock() @@ -337,7 +337,7 @@ func (s *serverWithLimits) sendRequest(request Request) (reqId ID) { return s.serverWithTimeout.sendRequest(request) } -// stop stops all goroutines associated with the server. +// unsubscribe stops all goroutines associated with the server. func (s *serverWithLimits) unsubscribe() { s.lock.Lock() defer s.lock.Unlock() diff --git a/beacon/light/sync/head_sync.go b/beacon/light/sync/head_sync.go index 9fef95b0df79..5ccc2e18a2d6 100644 --- a/beacon/light/sync/head_sync.go +++ b/beacon/light/sync/head_sync.go @@ -101,7 +101,7 @@ func (s *HeadSync) newSignedHead(server request.Server, signedHead types.SignedH s.headTracker.ValidateHead(signedHead) } -// newSignedHead handles received signed head; either validates it if the chain +// newFinalityUpdate handles received finality update; either validates it if the chain // is properly synced or stores it for further validation. func (s *HeadSync) newFinalityUpdate(server request.Server, finalityUpdate types.FinalityUpdate) { if !s.chainInit || types.SyncPeriod(finalityUpdate.SignatureSlot) > s.nextSyncPeriod { @@ -111,7 +111,7 @@ func (s *HeadSync) newFinalityUpdate(server request.Server, finalityUpdate types s.headTracker.ValidateFinality(finalityUpdate) } -// processUnvalidatedHeads iterates the list of unvalidated heads and validates +// processUnvalidated iterates the list of unvalidated heads and validates // those which can be validated. func (s *HeadSync) processUnvalidated() { if !s.chainInit { diff --git a/beacon/types/exec_header.go b/beacon/types/exec_header.go index 3085c3de6978..dce101ba2009 100644 --- a/beacon/types/exec_header.go +++ b/beacon/types/exec_header.go @@ -36,7 +36,7 @@ type ExecutionHeader struct { obj headerObject } -// HeaderFromJSON decodes an execution header from JSON data provided by +// ExecutionHeaderFromJSON decodes an execution header from JSON data provided by // the beacon chain API. func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, error) { var obj headerObject diff --git a/cmd/geth/attach_test.go b/cmd/geth/attach_test.go index 91007ccf65fb..ceae3a122e71 100644 --- a/cmd/geth/attach_test.go +++ b/cmd/geth/attach_test.go @@ -48,7 +48,7 @@ func TestAttachWithHeaders(t *testing.T) { // This is fixed in a follow-up PR. } -// TestAttachWithHeaders tests that 'geth db --remotedb' with custom headers works, i.e +// TestRemoteDbWithHeaders tests that 'geth db --remotedb' with custom headers works, i.e // that custom headers are forwarded to the target. func TestRemoteDbWithHeaders(t *testing.T) { t.Parallel() diff --git a/cmd/utils/export_test.go b/cmd/utils/export_test.go index 84ba8d0c316e..c22aad64b817 100644 --- a/cmd/utils/export_test.go +++ b/cmd/utils/export_test.go @@ -97,7 +97,7 @@ func testExport(t *testing.T, f string) { } } -// testDeletion tests if the deletion markers can be exported/imported correctly +// TestDeletionExport tests if the deletion markers can be exported/imported correctly func TestDeletionExport(t *testing.T) { f := fmt.Sprintf("%v/tempdump", os.TempDir()) defer func() { diff --git a/common/lru/basiclru.go b/common/lru/basiclru.go index a429157fe50a..c60f59706605 100644 --- a/common/lru/basiclru.go +++ b/common/lru/basiclru.go @@ -174,7 +174,7 @@ func (l *list[T]) init() { l.root.prev = &l.root } -// push adds an element to the front of the list. +// pushElem adds an element to the front of the list. func (l *list[T]) pushElem(e *listElem[T]) { e.prev = &l.root e.next = l.root.next diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index cc19d12a56ae..9800bf928882 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -568,7 +568,7 @@ var ( u256_32 = uint256.NewInt(32) ) -// AccumulateRewards credits the coinbase of the given block with the mining +// accumulateRewards credits the coinbase of the given block with the mining // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, header *types.Header, uncles []*types.Header) { diff --git a/core/asm/lexer.go b/core/asm/lexer.go index e025c6f363c6..630360b10646 100644 --- a/core/asm/lexer.go +++ b/core/asm/lexer.go @@ -127,7 +127,7 @@ func (l *lexer) ignore() { l.start = l.pos } -// Accepts checks whether the given input matches the next rune +// accept checks whether the given input matches the next rune func (l *lexer) accept(valid string) bool { if strings.ContainsRune(valid, l.next()) { return true diff --git a/core/blockchain.go b/core/blockchain.go index 12fdcf72456c..567225527f59 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -639,7 +639,7 @@ func (bc *BlockChain) SetSafe(header *types.Header) { } } -// rewindPathHead implements the logic of rewindHead in the context of hash scheme. +// rewindHashHead implements the logic of rewindHead in the context of hash scheme. func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash) (*types.Header, uint64) { var ( limit uint64 // The oldest block that will be searched for this rewinding diff --git a/core/chain_makers.go b/core/chain_makers.go index 1c42ab0c9af2..419e9d0458b2 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -482,7 +482,7 @@ func makeBlockChain(chainConfig *params.ChainConfig, parent *types.Block, n int, return blocks } -// makeBlockChain creates a deterministic chain of blocks from genesis +// makeBlockChainWithGenesis creates a deterministic chain of blocks from genesis func makeBlockChainWithGenesis(genesis *Genesis, n int, engine consensus.Engine, seed int) (ethdb.Database, []*types.Block) { db, blocks, _ := GenerateChainWithGenesis(genesis, engine, n, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 8a69dc6babe5..e61559993c29 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -695,7 +695,7 @@ func (r *receiptLogs) DecodeRLP(s *rlp.Stream) error { return nil } -// DeriveLogFields fills the logs in receiptLogs with information such as block number, txhash, etc. +// deriveLogFields fills the logs in receiptLogs with information such as block number, txhash, etc. func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, txs types.Transactions) error { logIndex := uint(0) if len(txs) != len(receipts) { diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 6dbcc9dadc05..f1c2c10fc965 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1226,7 +1226,7 @@ func (p *BlobPool) Add(txs []*types.Transaction, local bool, sync bool) []error return errs } -// Add inserts a new blob transaction into the pool if it passes validation (both +// add inserts a new blob transaction into the pool if it passes validation (both // consensus validity and pool restrictions). func (p *BlobPool) add(tx *types.Transaction) (err error) { // The blob pool blocks on adding a transaction. This is because blob txs are diff --git a/core/vm/contracts.go b/core/vm/contracts.go index a6af31f58456..299143760833 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -182,7 +182,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uin return output, suppliedGas, err } -// ECRECOVER implemented as a native contract. +// ecrecover implemented as a native contract. type ecrecover struct{} func (c *ecrecover) RequiredGas(input []byte) uint64 { @@ -457,7 +457,7 @@ func runBn256Add(input []byte) ([]byte, error) { return res.Marshal(), nil } -// bn256Add implements a native elliptic curve point addition conforming to +// bn256AddIstanbul implements a native elliptic curve point addition conforming to // Istanbul consensus rules. type bn256AddIstanbul struct{} diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 8b7f8b02bda5..edf21b17d710 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -50,7 +50,7 @@ func (ctx *ScopeContext) MemoryData() []byte { return ctx.Memory.Data() } -// MemoryData returns the stack data. Callers must not modify the contents +// StackData returns the stack data. Callers must not modify the contents // of the returned data. func (ctx *ScopeContext) StackData() []uint256.Int { if ctx.Stack == nil { diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index f70617019eb7..989057442b6e 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -167,7 +167,7 @@ type btCurve struct { *btcec.KoblitzCurve } -// Marshall converts a point given as (x, y) into a byte slice. +// Marshal converts a point given as (x, y) into a byte slice. func (curve btCurve) Marshal(x, y *big.Int) []byte { byteLen := (curve.Params().BitSize + 7) / 8 diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 2468e1a9809e..0fdc7ead9c3b 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -57,7 +57,7 @@ func newTester(t *testing.T) *downloadTester { return newTesterWithNotification(t, nil) } -// newTester creates a new downloader test mocker. +// newTesterWithNotification creates a new downloader test mocker. func newTesterWithNotification(t *testing.T, success func()) *downloadTester { freezer := t.TempDir() db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false) diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index 2b108dfe9361..3693ab095ff6 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -94,7 +94,7 @@ func newSkeletonTestPeer(id string, headers []*types.Header) *skeletonTestPeer { } } -// newSkeletonTestPeer creates a new mock peer to test the skeleton sync with, +// newSkeletonTestPeerWithHook creates a new mock peer to test the skeleton sync with, // and sets an optional serve hook that can return headers for delivery instead // of the predefined chain. Useful for emulating malicious behavior that would // otherwise require dedicated peer types. diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 6238c9773522..4a0f40cce934 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -442,7 +442,7 @@ func TestInvalidLogFilterCreation(t *testing.T) { } } -// TestLogFilterUninstall tests invalid getLogs requests +// TestInvalidGetLogsRequest tests invalid getLogs requests func TestInvalidGetLogsRequest(t *testing.T) { t.Parallel() diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index fdf551ef210c..934dadc9a5b3 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -63,7 +63,7 @@ func newTestBackend(blocks int) *testBackend { return newTestBackendWithGenerator(blocks, false, nil) } -// newTestBackend creates a chain with a number of explicitly defined blocks and +// newTestBackendWithGenerator creates a chain with a number of explicitly defined blocks and // wraps it into a mock backend. func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, *core.BlockGen)) *testBackend { var ( diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index ab7c493c0320..f35babb73109 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -839,7 +839,7 @@ func testMultiSyncManyUseless(t *testing.T, scheme string) { verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } -// TestMultiSyncManyUseless contains one good peer, and many which doesn't return anything valuable at all +// TestMultiSyncManyUselessWithLowTimeout contains one good peer, and many which doesn't return anything valuable at all func TestMultiSyncManyUselessWithLowTimeout(t *testing.T) { t.Parallel() @@ -1378,7 +1378,7 @@ func testSyncWithStorageAndNonProvingPeer(t *testing.T, scheme string) { verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } -// TestSyncWithStorage tests basic sync using accounts + storage + code, against +// TestSyncWithStorageMisbehavingProve tests basic sync using accounts + storage + code, against // a peer who insists on delivering full storage sets _and_ proofs. This triggered // an error, where the recipient erroneously clipped the boundary nodes, but // did not mark the account for healing. diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 02809ef57e54..36caee0dda45 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -61,7 +61,7 @@ type testBackend struct { relHook func() // Hook is invoked when the requested state is released } -// testBackend creates a new test backend. OBS: After test is done, teardown must be +// newTestBackend creates a new test backend. OBS: After test is done, teardown must be // invoked in order to release associated resources. func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { backend := &testBackend{ diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index cd9791db2a50..7694e94c6ce1 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -171,7 +171,7 @@ func testFlatCallTracer(tracerName string, dirPath string, t *testing.T) { } } -// jsonEqual is similar to reflect.DeepEqual, but does a 'bounce' via json prior to +// jsonEqualFlat is similar to reflect.DeepEqual, but does a 'bounce' via json prior to // comparison func jsonEqualFlat(x, y interface{}) bool { xTrace := new([]flatCallTrace) diff --git a/eth/tracers/internal/util.go b/eth/tracers/internal/util.go index 18a372d192a1..347af43d5111 100644 --- a/eth/tracers/internal/util.go +++ b/eth/tracers/internal/util.go @@ -75,7 +75,7 @@ func MemoryPtr(m []byte, offset, size int64) []byte { return nil } -// Back returns the n'th item in stack +// StackBack returns the n'th item in stack func StackBack(st []uint256.Int, n int) *uint256.Int { return &st[len(st)-n-1] } diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index d643289a64d7..05adedf265d1 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -198,7 +198,7 @@ func TestHaltBetweenSteps(t *testing.T) { } } -// testNoStepExec tests a regular value transfer (no exec), and accessing the statedb +// TestNoStepExec tests a regular value transfer (no exec), and accessing the statedb // in 'result' func TestNoStepExec(t *testing.T) { execTracer := func(code string) []byte { diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index fc7713b24527..fda26a81af7d 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -86,7 +86,7 @@ func (al accessList) equal(other accessList) bool { return true } -// accesslist converts the accesslist to a types.AccessList. +// accessList converts the accesslist to a types.AccessList. func (al accessList) accessList() types.AccessList { acl := make(types.AccessList, 0, len(al)) for addr, slots := range al { diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index c7e656d2e7da..51eaca347483 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -514,7 +514,7 @@ func iterateKeys(it ethdb.Iterator) []string { return keys } -// randomHash generates a random blob of data and returns it as a hash. +// randBytes generates a random blob of data. func randBytes(len int) []byte { buf := make([]byte, len) if n, err := rand.Read(buf); n != len || err != nil { diff --git a/internal/era/era.go b/internal/era/era.go index 22715a82e5a2..2b9e6229018a 100644 --- a/internal/era/era.go +++ b/internal/era/era.go @@ -239,7 +239,7 @@ func (e *Era) readOffset(n uint64) (int64, error) { return blockIndexRecordOffset + int64(binary.LittleEndian.Uint64(e.buf[:])), nil } -// newReader returns a snappy.Reader for the e2store entry value at off. +// newSnappyReader returns a snappy.Reader for the e2store entry value at off. func newSnappyReader(e *e2store.Reader, expectedType uint16, off int64) (io.Reader, int64, error) { r, n, err := e.ReaderAt(expectedType, off) if err != nil { diff --git a/internal/version/version.go b/internal/version/version.go index 0daea02b57e5..2cca54b20f32 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -65,7 +65,7 @@ func ClientName(clientIdentifier string) string { ) } -// runtimeInfo returns build and platform information about the current binary. +// Info returns build and platform information about the current binary. // // If the package that is currently executing is a prefixed by our go-ethereum // module path, it will print out commit and date VCS information. Otherwise, diff --git a/log/logger.go b/log/logger.go index 5672344b0c5c..8b03b68fc86e 100644 --- a/log/logger.go +++ b/log/logger.go @@ -156,7 +156,7 @@ func (l *logger) Handler() slog.Handler { return l.inner.Handler() } -// write logs a message at the specified level: +// Write logs a message at the specified level: func (l *logger) Write(level slog.Level, msg string, attrs ...any) { if !l.inner.Enabled(context.Background(), level) { return diff --git a/metrics/gauge.go b/metrics/gauge.go index 5933df310786..6d10bbf85660 100644 --- a/metrics/gauge.go +++ b/metrics/gauge.go @@ -74,7 +74,7 @@ func (g *StandardGauge) Update(v int64) { g.value.Store(v) } -// Update updates the gauge's value if v is larger then the current value. +// UpdateIfGt updates the gauge's value if v is larger then the current value. func (g *StandardGauge) UpdateIfGt(v int64) { for { exist := g.value.Load() diff --git a/metrics/meter.go b/metrics/meter.go index 22475ef6ebee..432838f4ef7b 100644 --- a/metrics/meter.go +++ b/metrics/meter.go @@ -173,7 +173,7 @@ type meterArbiter struct { var arbiter = meterArbiter{ticker: time.NewTicker(5 * time.Second), meters: make(map[*StandardMeter]struct{})} -// Ticks meters on the scheduled interval +// tick meters on the scheduled interval func (ma *meterArbiter) tick() { for range ma.ticker.C { ma.tickMeters() diff --git a/metrics/metrics.go b/metrics/metrics.go index 9e0ac23dd511..c7fe5c7333b9 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -30,7 +30,7 @@ var enablerFlags = []string{"metrics"} // enablerEnvVars is the env var names to use to enable metrics collections. var enablerEnvVars = []string{"GETH_METRICS"} -// Init enables or disables the metrics system. Since we need this to run before +// init enables or disables the metrics system. Since we need this to run before // any other code gets to create meters and timers, we'll actually do an ugly hack // and peek into the command line args for the metrics flag. func init() { diff --git a/node/rpcstack.go b/node/rpcstack.go index 253db0d564a6..6d3828ec2b0c 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -597,7 +597,7 @@ func newIPCServer(log log.Logger, endpoint string) *ipcServer { return &ipcServer{log: log, endpoint: endpoint} } -// Start starts the httpServer's http.Server +// start starts the httpServer's http.Server func (is *ipcServer) start(apis []rpc.API) error { is.mu.Lock() defer is.mu.Unlock() diff --git a/p2p/discover/metrics.go b/p2p/discover/metrics.go index 56aae24285df..3cd0ab041403 100644 --- a/p2p/discover/metrics.go +++ b/p2p/discover/metrics.go @@ -44,7 +44,7 @@ func init() { } } -// meteredConn is a wrapper around a net.UDPConn that meters both the +// meteredUdpConn is a wrapper around a net.UDPConn that meters both the // inbound and outbound network traffic. type meteredUdpConn struct { UDPConn diff --git a/p2p/enr/enr_test.go b/p2p/enr/enr_test.go index b85ee209d591..4fccb0cce9e6 100644 --- a/p2p/enr/enr_test.go +++ b/p2p/enr/enr_test.go @@ -48,7 +48,7 @@ func TestGetSetID(t *testing.T) { assert.Equal(t, id, id2) } -// TestGetSetIP4 tests encoding/decoding and setting/getting of the IP key. +// TestGetSetIPv4 tests encoding/decoding and setting/getting of the IP key. func TestGetSetIPv4(t *testing.T) { ip := IPv4{192, 168, 0, 3} var r Record @@ -59,7 +59,7 @@ func TestGetSetIPv4(t *testing.T) { assert.Equal(t, ip, ip2) } -// TestGetSetIP6 tests encoding/decoding and setting/getting of the IP6 key. +// TestGetSetIPv6 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 diff --git a/p2p/nodestate/nodestate.go b/p2p/nodestate/nodestate.go index 1e1757559c02..8052144465a5 100644 --- a/p2p/nodestate/nodestate.go +++ b/p2p/nodestate/nodestate.go @@ -823,7 +823,7 @@ func (ns *NodeStateMachine) addTimeout(n *enode.Node, mask bitMask, timeout time } } -// removeTimeout removes node state timeouts associated to the given state flag(s). +// removeTimeouts removes node state timeouts associated to the given state flag(s). // If a timeout was associated to multiple flags which are not all included in the // specified remove mask then only the included flags are de-associated and the timer // stays active. diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go index a26dff7a8229..f34315f17097 100644 --- a/p2p/simulations/adapters/types.go +++ b/p2p/simulations/adapters/types.go @@ -299,7 +299,7 @@ func RegisterLifecycles(lifecycles LifecycleConstructors) { } // adds the host part to the configuration's ENR, signs it -// creates and the corresponding enode object to the configuration +// creates and adds the corresponding enode object to the configuration func (n *NodeConfig) initEnode(ip net.IP, tcpport int, udpport int) error { enrIp := enr.IP(ip) n.Record.Set(&enrIp) diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go index 460ed72d7fc8..cd03e600f35c 100644 --- a/p2p/simulations/http_test.go +++ b/p2p/simulations/http_test.go @@ -838,7 +838,7 @@ func TestMsgFilterPassSingle(t *testing.T) { }) } -// TestMsgFilterPassSingle tests streaming message events using an invalid +// TestMsgFilterFailBadParams tests streaming message events using an invalid // filter func TestMsgFilterFailBadParams(t *testing.T) { // start the server diff --git a/p2p/simulations/network.go b/p2p/simulations/network.go index 4735e5cfa6cf..0225a3bbaafb 100644 --- a/p2p/simulations/network.go +++ b/p2p/simulations/network.go @@ -535,7 +535,7 @@ func (net *Network) GetRandomUpNode(excludeIDs ...enode.ID) *Node { return net.getRandomUpNode(excludeIDs...) } -// GetRandomUpNode returns a random node on the network, which is running. +// getRandomUpNode returns a random node on the network, which is running. func (net *Network) getRandomUpNode(excludeIDs ...enode.ID) *Node { return net.getRandomNode(net.getUpNodeIDs(), excludeIDs) } diff --git a/rpc/handler.go b/rpc/handler.go index 792581cbc0ad..7b8f64aa7be8 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -388,7 +388,7 @@ func (h *handler) startCallProc(fn func(*callProc)) { }() } -// handleResponse processes method call responses. +// handleResponses processes method call responses. func (h *handler) handleResponses(batch []*jsonrpcMessage, handleCall func(*jsonrpcMessage)) { var resolvedops []*requestOp handleResp := func(msg *jsonrpcMessage) { diff --git a/rpc/json.go b/rpc/json.go index 5557a8076040..e932389d17c7 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -266,7 +266,7 @@ func (c *jsonCodec) close() { }) } -// Closed returns a channel which will be closed when Close is called +// closed returns a channel which will be closed when Close is called func (c *jsonCodec) closed() <-chan interface{} { return c.closeCh } diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 3a131c8e6bd2..a7dac705c959 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -235,10 +235,10 @@ func (c *mockConn) writeJSON(ctx context.Context, msg interface{}, isError bool) return c.enc.Encode(msg) } -// Closed returns a channel which is closed when the connection is closed. +// closed returns a channel which is closed when the connection is closed. func (c *mockConn) closed() <-chan interface{} { return nil } -// RemoteAddr returns the peer address of the connection. +// remoteAddr returns the peer address of the connection. func (c *mockConn) remoteAddr() string { return "" } // BenchmarkNotify benchmarks the performance of notifying a subscription. diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index e28f059106f3..0d66887d5832 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -704,7 +704,7 @@ func formatPrimitiveValue(encType string, encValue interface{}) (string, error) return "", fmt.Errorf("unhandled type %v", encType) } -// Validate checks if the types object is conformant to the specs +// validate checks if the types object is conformant to the specs func (t Types) validate() error { for typeKey, typeArr := range t { if len(typeKey) == 0 { diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index 1cf8b4bf3813..bb21525507cb 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -671,7 +671,7 @@ func TestGnosisTypedDataWithChainId(t *testing.T) { } } -// TestGnosisCustomData tests the scenario where a user submits only the gnosis-safe +// TestGnosisCustomDataWithChainId tests the scenario where a user submits only the gnosis-safe // specific data, and we fill the TypedData struct on our side func TestGnosisCustomDataWithChainId(t *testing.T) { t.Parallel() diff --git a/tests/init_test.go b/tests/init_test.go index e9bb99dc7d01..effeec2b8654 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -108,7 +108,7 @@ type testFailure struct { reason string } -// skipShortMode skips tests matching when the -short flag is used. +// slow adds expected slow tests matching the pattern. func (tm *testMatcher) slow(pattern string) { tm.slowpat = append(tm.slowpat, regexp.MustCompile(pattern)) } diff --git a/trie/proof_test.go b/trie/proof_test.go index 93cf32abbf91..fab3a9765082 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -198,7 +198,7 @@ func TestRangeProof(t *testing.T) { } } -// TestRangeProof tests normal range proof with two non-existent proofs. +// TestRangeProofWithNonExistentProof tests normal range proof with two non-existent proofs. // The test cases are generated randomly. func TestRangeProofWithNonExistentProof(t *testing.T) { trie, vals := randomTrie(4096) diff --git a/trie/trie_test.go b/trie/trie_test.go index 920594fdd24f..87a0785cfb04 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -1066,7 +1066,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) { } } -// BenchmarkCommitAfterHashFixedSize benchmarks the Commit (after Hash) of a fixed number of updates to a trie. +// BenchmarkHashFixedSize benchmarks the hash of a fixed number of updates to a trie. // This benchmark is meant to capture the difference on efficiency of small versus large changes. Typically, // storage tries are small (a couple of entries), whereas the full post-block account trie update is large (a couple // of thousand entries) diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index a41cf4268aac..21ece1beb121 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -305,7 +305,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode return root, ctx.nodes, triestate.New(ctx.accountOrigin, ctx.storageOrigin) } -// lastRoot returns the latest root hash, or empty if nothing is cached. +// lastHash returns the latest root hash, or empty if nothing is cached. func (t *tester) lastHash() common.Hash { if len(t.roots) == 0 { return common.Hash{} diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index 777e4ec8a750..5d0d1c39375f 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -58,7 +58,7 @@ func newDiskLayer(root common.Hash, id uint64, db *Database, cleans *fastcache.C } } -// root implements the layer interface, returning root hash of corresponding state. +// rootHash implements the layer interface, returning root hash of corresponding state. func (dl *diskLayer) rootHash() common.Hash { return dl.root } @@ -68,7 +68,7 @@ func (dl *diskLayer) stateID() uint64 { return dl.id } -// parent implements the layer interface, returning nil as there's no layer +// parentLayer implements the layer interface, returning nil as there's no layer // below the disk. func (dl *diskLayer) parentLayer() layer { return nil From da7469e5c44feec120555c8f697f75b94b2884bb Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 26 Mar 2024 21:25:41 +0100 Subject: [PATCH 108/571] core: add an end-to-end verkle test (#29262) core: add a simple verkle test triedb, core: skip hash comparison in verkle core: remove legacy daoFork logic in verkle chain maker fix: nil pointer in tests triedb/pathdb: add blob hex core: less defensive Co-authored-by: Ignacio Hagopian Co-authored-by: Martin HS Co-authored-by: Gary Rong --- core/blockchain.go | 9 ++- core/chain_makers.go | 107 ++++++++++++++++++++++++++++++++ core/state/database.go | 2 + core/state/statedb.go | 5 ++ core/state_processor_test.go | 105 +++++++++++++++++++++++++++++++ triedb/database.go | 4 +- triedb/pathdb/database.go | 24 +++---- triedb/pathdb/database_test.go | 8 +-- triedb/pathdb/difflayer.go | 28 ++------- triedb/pathdb/difflayer_test.go | 6 +- triedb/pathdb/disklayer.go | 34 ++++------ triedb/pathdb/errors.go | 20 +----- triedb/pathdb/metrics.go | 1 + triedb/pathdb/nodebuffer.go | 13 ++-- triedb/pathdb/reader.go | 94 ++++++++++++++++++++++++++++ 15 files changed, 358 insertions(+), 102 deletions(-) create mode 100644 triedb/pathdb/reader.go diff --git a/core/blockchain.go b/core/blockchain.go index 567225527f59..70d0fed6891f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -147,8 +147,11 @@ type CacheConfig struct { } // triedbConfig derives the configures for trie database. -func (c *CacheConfig) triedbConfig() *triedb.Config { - config := &triedb.Config{Preimages: c.Preimages} +func (c *CacheConfig) triedbConfig(isVerkle bool) *triedb.Config { + config := &triedb.Config{ + Preimages: c.Preimages, + IsVerkle: isVerkle, + } if c.StateScheme == rawdb.HashScheme { config.HashDB = &hashdb.Config{ CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, @@ -265,7 +268,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis cacheConfig = defaultCacheConfig } // Open trie database with provided config - triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig()) + triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(genesis != nil && genesis.IsVerkle())) // Setup the genesis block, commit the provided genesis specification // to database if the genesis block is not present yet, or load the diff --git a/core/chain_makers.go b/core/chain_makers.go index 419e9d0458b2..13d7cb86c043 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" + "github.com/gballet/go-verkle" "github.com/holiman/uint256" ) @@ -418,6 +419,112 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, return db, blocks, receipts } +func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, trdb *triedb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts, []*verkle.VerkleProof, []verkle.StateDiff) { + if config == nil { + config = params.TestChainConfig + } + proofs := make([]*verkle.VerkleProof, 0, n) + keyvals := make([]verkle.StateDiff, 0, n) + cm := newChainMaker(parent, config, engine) + + genblock := func(i int, parent *types.Block, triedb *triedb.Database, statedb *state.StateDB) (*types.Block, types.Receipts) { + b := &BlockGen{i: i, cm: cm, parent: parent, statedb: statedb, engine: engine} + b.header = cm.makeHeader(parent, statedb, b.engine) + + // TODO uncomment when proof generation is merged + // Save pre state for proof generation + // preState := statedb.Copy() + + // TODO uncomment when the 2935 PR is merged + // if config.IsPrague(b.header.Number, b.header.Time) { + // if !config.IsPrague(b.parent.Number(), b.parent.Time()) { + // Transition case: insert all 256 ancestors + // InsertBlockHashHistoryAtEip2935Fork(statedb, b.header.Number.Uint64()-1, b.header.ParentHash, chainreader) + // } else { + // ProcessParentBlockHash(statedb, b.header.Number.Uint64()-1, b.header.ParentHash) + // } + // } + // Execute any user modifications to the block + if gen != nil { + gen(i, b) + } + body := &types.Body{ + Transactions: b.txs, + Uncles: b.uncles, + Withdrawals: b.withdrawals, + } + block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, body, b.receipts) + if err != nil { + panic(err) + } + + // Write state changes to db + root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number)) + if err != nil { + panic(fmt.Sprintf("state write error: %v", err)) + } + if err = triedb.Commit(root, false); err != nil { + panic(fmt.Sprintf("trie write error: %v", err)) + } + + // TODO uncomment when proof generation is merged + // proofs = append(proofs, block.ExecutionWitness().VerkleProof) + // keyvals = append(keyvals, block.ExecutionWitness().StateDiff) + + return block, b.receipts + } + + for i := 0; i < n; i++ { + statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, trdb), nil) + if err != nil { + panic(err) + } + block, receipts := genblock(i, parent, trdb, statedb) + + // Post-process the receipts. + // Here we assign the final block hash and other info into the receipt. + // In order for DeriveFields to work, the transaction and receipt lists need to be + // of equal length. If AddUncheckedTx or AddUncheckedReceipt are used, there will be + // extra ones, so we just trim the lists here. + receiptsCount := len(receipts) + txs := block.Transactions() + if len(receipts) > len(txs) { + receipts = receipts[:len(txs)] + } else if len(receipts) < len(txs) { + txs = txs[:len(receipts)] + } + var blobGasPrice *big.Int + if block.ExcessBlobGas() != nil { + blobGasPrice = eip4844.CalcBlobFee(*block.ExcessBlobGas()) + } + if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil { + panic(err) + } + + // Re-expand to ensure all receipts are returned. + receipts = receipts[:receiptsCount] + + // Advance the chain. + cm.add(block, receipts) + parent = block + } + return cm.chain, cm.receipts, proofs, keyvals +} + +func GenerateVerkleChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts, []*verkle.VerkleProof, []verkle.StateDiff) { + db := rawdb.NewMemoryDatabase() + cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme) + cacheConfig.SnapshotLimit = 0 + triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) + defer triedb.Close() + genesisBlock, err := genesis.Commit(db, triedb) + if err != nil { + panic(err) + } + blocks, receipts, proofs, keyvals := GenerateVerkleChain(genesis.Config, genesisBlock, engine, db, triedb, n, gen) + return db, blocks, receipts, proofs, keyvals +} + func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { time := parent.Time() + 10 // block time is fixed at 10 seconds header := &types.Header{ diff --git a/core/state/database.go b/core/state/database.go index 7520923eef48..188ecf0c86a5 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -209,6 +209,8 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { switch t := t.(type) { case *trie.StateTrie: return t.Copy() + case *trie.VerkleTrie: + return t.Copy() default: panic(fmt.Errorf("unknown trie type %T", t)) } diff --git a/core/state/statedb.go b/core/state/statedb.go index e63513d8e19e..981eea7d6f92 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1156,6 +1156,11 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) error { return nil } +// GetTrie returns the account trie. +func (s *StateDB) GetTrie() Trie { + return s.trie +} + // Commit writes the state to the underlying in-memory trie database. // Once the state is committed, tries cached in stateDB (including account // trie, storage tries) will no longer be functional. A new state instance diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 7718c0cde483..dc9cb203bcec 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -422,3 +422,108 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr } return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) } + +var ( + code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`) + intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, true, true, true, true) + // A contract creation that calls EXTCODECOPY in the constructor. Used to ensure that the witness + // will not contain that copied data. + // Source: https://gist.github.com/gballet/a23db1e1cb4ed105616b5920feb75985 + codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`) + intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, true, true, true, true) +) + +func TestProcessVerkle(t *testing.T) { + var ( + config = ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + Ethash: new(params.EthashConfig), + ShanghaiTime: u64(0), + VerkleTime: u64(0), + TerminalTotalDifficulty: common.Big0, + TerminalTotalDifficultyPassed: true, + // TODO uncomment when proof generation is merged + // ProofInBlocks: true, + } + signer = types.LatestSigner(config) + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain + coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") + gspec = &Genesis{ + Config: config, + Alloc: GenesisAlloc{ + coinbase: GenesisAccount{ + Balance: big.NewInt(1000000000000000000), // 1 ether + Nonce: 0, + }, + }, + } + ) + // Verkle trees use the snapshot, which must be enabled before the + // data is saved into the tree+database. + // genesis := gspec.MustCommit(bcdb, triedb) + cacheConfig := DefaultCacheConfigWithScheme("path") + cacheConfig.SnapshotLimit = 0 + blockchain, _ := NewBlockChain(bcdb, cacheConfig, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) + defer blockchain.Stop() + + txCost1 := params.TxGas + txCost2 := params.TxGas + contractCreationCost := intrinsicContractCreationGas + uint64(2039 /* execution costs */) + codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + uint64(293644 /* execution costs */) + blockGasUsagesExpected := []uint64{ + txCost1*2 + txCost2, + txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas, + } + _, chain, _, _, _ := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { + gen.SetPoS() + + // TODO need to check that the tx cost provided is the exact amount used (no remaining left-over) + tx, _ := types.SignTx(types.NewTransaction(uint64(i)*3, common.Address{byte(i), 2, 3}, big.NewInt(999), txCost1, big.NewInt(875000000), nil), signer, testKey) + gen.AddTx(tx) + tx, _ = types.SignTx(types.NewTransaction(uint64(i)*3+1, common.Address{}, big.NewInt(999), txCost1, big.NewInt(875000000), nil), signer, testKey) + gen.AddTx(tx) + tx, _ = types.SignTx(types.NewTransaction(uint64(i)*3+2, common.Address{}, big.NewInt(0), txCost2, big.NewInt(875000000), nil), signer, testKey) + gen.AddTx(tx) + + // Add two contract creations in block #2 + if i == 1 { + tx, _ = types.SignTx(types.NewContractCreation(6, big.NewInt(16), 3000000, big.NewInt(875000000), code), signer, testKey) + gen.AddTx(tx) + + tx, _ = types.SignTx(types.NewContractCreation(7, big.NewInt(0), 3000000, big.NewInt(875000000), codeWithExtCodeCopy), signer, testKey) + gen.AddTx(tx) + } + }) + + t.Log("inserting blocks into the chain") + + endnum, err := blockchain.InsertChain(chain) + if err != nil { + t.Fatalf("block %d imported with error: %v", endnum, err) + } + + for i := 0; i < 2; i++ { + b := blockchain.GetBlockByNumber(uint64(i) + 1) + if b == nil { + t.Fatalf("expected block %d to be present in chain", i+1) + } + if b.Hash() != chain[i].Hash() { + t.Fatalf("block #%d not found at expected height", b.NumberU64()) + } + if b.GasUsed() != blockGasUsagesExpected[i] { + t.Fatalf("expected block #%d txs to use %d, got %d\n", b.NumberU64(), blockGasUsagesExpected[i], b.GasUsed()) + } + } +} diff --git a/triedb/database.go b/triedb/database.go index 939a21f1478b..261a47dcc2c7 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -108,12 +108,12 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { log.Crit("Both 'hash' and 'path' mode are configured") } if config.PathDB != nil { - db.backend = pathdb.New(diskdb, config.PathDB) + db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle) } else { var resolver hashdb.ChildResolver if config.IsVerkle { // TODO define verkle resolver - log.Crit("Verkle node resolver is not defined") + log.Crit("verkle does not use a hash db") } else { resolver = trie.MerkleResolver{} } diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 34941a274d4c..2e7c66280426 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -59,11 +59,12 @@ var ( // layer is the interface implemented by all state layers which includes some // public methods and some additional methods for internal usage. type layer interface { - // Node retrieves the trie node with the node info. An error will be returned - // if the read operation exits abnormally. For example, if the layer is already - // stale, or the associated state is regarded as corrupted. Notably, no error - // will be returned if the requested node is not found in database. - Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) + // node retrieves the trie node with the node info. An error will be returned + // if the read operation exits abnormally. Specifically, if the layer is + // already stale. + // + // Note, no error will be returned if the requested node is not found in database. + node(owner common.Hash, path []byte, depth int) ([]byte, common.Hash, *nodeLoc, error) // rootHash returns the root hash for which this layer was made. rootHash() common.Hash @@ -132,6 +133,7 @@ type Database struct { // the shutdown to reject all following unexpected mutations. readOnly bool // Flag if database is opened in read only mode waitSync bool // Flag if database is deactivated due to initial state sync + isVerkle bool // Flag if database is used for verkle tree bufferSize int // Memory allowance (in bytes) for caching dirty nodes config *Config // Configuration for database diskdb ethdb.Database // Persistent storage for matured trie nodes @@ -143,7 +145,7 @@ type Database struct { // New attempts to load an already existing layer from a persistent key-value // store (with a number of memory layers from a journal). If the journal is not // matched with the base persistent layer, all the recorded diff layers are discarded. -func New(diskdb ethdb.Database, config *Config) *Database { +func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { if config == nil { config = Defaults } @@ -151,6 +153,7 @@ func New(diskdb ethdb.Database, config *Config) *Database { db := &Database{ readOnly: config.ReadOnly, + isVerkle: isVerkle, bufferSize: config.DirtyCacheSize, config: config, diskdb: diskdb, @@ -208,15 +211,6 @@ func New(diskdb ethdb.Database, config *Config) *Database { return db } -// Reader retrieves a layer belonging to the given state root. -func (db *Database) Reader(root common.Hash) (layer, error) { - l := db.tree.get(root) - if l == nil { - return nil, fmt.Errorf("state %#x is not available", root) - } - return l, nil -} - // Update adds a new layer into the tree, if that can be linked to an existing // old parent. It is disallowed to insert a disk layer (the origin of all). Apart // from that this function will flatten the extra diff layers at bottom into disk diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 21ece1beb121..30edef2760e3 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -106,7 +106,7 @@ func newTester(t *testing.T, historyLimit uint64) *tester { StateHistory: historyLimit, CleanCacheSize: 16 * 1024, DirtyCacheSize: 16 * 1024, - }) + }, false) obj = &tester{ db: db, preimages: make(map[common.Hash]common.Address), @@ -550,7 +550,7 @@ func TestJournal(t *testing.T) { t.Errorf("Failed to journal, err: %v", err) } tester.db.Close() - tester.db = New(tester.db.diskdb, nil) + tester.db = New(tester.db.diskdb, nil, false) // Verify states including disk layer and all diff on top. for i := 0; i < len(tester.roots); i++ { @@ -588,7 +588,7 @@ func TestCorruptedJournal(t *testing.T) { rawdb.WriteTrieJournal(tester.db.diskdb, blob) // Verify states, all not-yet-written states should be discarded - tester.db = New(tester.db.diskdb, nil) + tester.db = New(tester.db.diskdb, nil, false) for i := 0; i < len(tester.roots); i++ { if tester.roots[i] == root { if err := tester.verifyState(root); err != nil { @@ -625,7 +625,7 @@ func TestTailTruncateHistory(t *testing.T) { defer tester.release() tester.db.Close() - tester.db = New(tester.db.diskdb, &Config{StateHistory: 10}) + tester.db = New(tester.db.diskdb, &Config{StateHistory: 10}, false) head, err := tester.db.freezer.Ancients() if err != nil { diff --git a/triedb/pathdb/difflayer.go b/triedb/pathdb/difflayer.go index 10567715d2e7..6b87883482c9 100644 --- a/triedb/pathdb/difflayer.go +++ b/triedb/pathdb/difflayer.go @@ -95,10 +95,9 @@ func (dl *diffLayer) parentLayer() layer { return dl.parent } -// node retrieves the node with provided node information. It's the internal -// version of Node function with additional accessed layer tracked. No error -// will be returned if node is not found. -func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, depth int) ([]byte, error) { +// node implements the layer interface, retrieving the trie node blob with the +// provided node information. No error will be returned if the node is not found. +func (dl *diffLayer) node(owner common.Hash, path []byte, depth int) ([]byte, common.Hash, *nodeLoc, error) { // Hold the lock, ensure the parent won't be changed during the // state accessing. dl.lock.RLock() @@ -109,31 +108,14 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept if ok { n, ok := subset[string(path)] if ok { - // If the trie node is not hash matched, or marked as removed, - // bubble up an error here. It shouldn't happen at all. - if n.Hash != hash { - dirtyFalseMeter.Mark(1) - log.Error("Unexpected trie node in diff layer", "owner", owner, "path", path, "expect", hash, "got", n.Hash) - return nil, newUnexpectedNodeError("diff", hash, n.Hash, owner, path, n.Blob) - } dirtyHitMeter.Mark(1) dirtyNodeHitDepthHist.Update(int64(depth)) dirtyReadMeter.Mark(int64(len(n.Blob))) - return n.Blob, nil + return n.Blob, n.Hash, &nodeLoc{loc: locDiffLayer, depth: depth}, nil } } // Trie node unknown to this layer, resolve from parent - if diff, ok := dl.parent.(*diffLayer); ok { - return diff.node(owner, path, hash, depth+1) - } - // Failed to resolve through diff layers, fallback to disk layer - return dl.parent.Node(owner, path, hash) -} - -// Node implements the layer interface, retrieving the trie node blob with the -// provided node information. No error will be returned if the node is not found. -func (dl *diffLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) { - return dl.node(owner, path, hash, 0) + return dl.parent.node(owner, path, depth+1) } // update implements the layer interface, creating a new layer on top of the diff --git a/triedb/pathdb/difflayer_test.go b/triedb/pathdb/difflayer_test.go index 75890b8a8371..bf4c6502efbd 100644 --- a/triedb/pathdb/difflayer_test.go +++ b/triedb/pathdb/difflayer_test.go @@ -29,7 +29,7 @@ import ( func emptyLayer() *diskLayer { return &diskLayer{ - db: New(rawdb.NewMemoryDatabase(), nil), + db: New(rawdb.NewMemoryDatabase(), nil, false), buffer: newNodeBuffer(DefaultBufferSize, nil, 0), } } @@ -58,7 +58,6 @@ func BenchmarkSearch1Layer(b *testing.B) { benchmarkSearch(b, 127, 128) } func benchmarkSearch(b *testing.B, depth int, total int) { var ( npath []byte - nhash common.Hash nblob []byte ) // First, we set up 128 diff layers, with 3K items each @@ -75,7 +74,6 @@ func benchmarkSearch(b *testing.B, depth int, total int) { if npath == nil && depth == index { npath = common.CopyBytes(path) nblob = common.CopyBytes(node.Blob) - nhash = node.Hash } } return newDiffLayer(parent, common.Hash{}, 0, 0, nodes, nil) @@ -92,7 +90,7 @@ func benchmarkSearch(b *testing.B, depth int, total int) { err error ) for i := 0; i < b.N; i++ { - have, err = layer.Node(common.Hash{}, npath, nhash) + have, _, _, err = layer.node(common.Hash{}, npath, 0) if err != nil { b.Fatal(err) } diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index 5d0d1c39375f..ec7c91bcacfd 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -94,27 +94,25 @@ func (dl *diskLayer) markStale() { dl.stale = true } -// Node implements the layer interface, retrieving the trie node with the +// node implements the layer interface, retrieving the trie node with the // provided node info. No error will be returned if the node is not found. -func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) { +func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, common.Hash, *nodeLoc, error) { dl.lock.RLock() defer dl.lock.RUnlock() if dl.stale { - return nil, errSnapshotStale + return nil, common.Hash{}, nil, errSnapshotStale } // Try to retrieve the trie node from the not-yet-written // node buffer first. Note the buffer is lock free since // it's impossible to mutate the buffer before tagging the // layer as stale. - n, err := dl.buffer.node(owner, path, hash) - if err != nil { - return nil, err - } - if n != nil { + n, found := dl.buffer.node(owner, path) + if found { dirtyHitMeter.Mark(1) dirtyReadMeter.Mark(int64(len(n.Blob))) - return n.Blob, nil + dirtyNodeHitDepthHist.Update(int64(depth)) + return n.Blob, n.Hash, &nodeLoc{loc: locDirtyCache, depth: depth}, nil } dirtyMissMeter.Mark(1) @@ -125,14 +123,9 @@ func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]b h := newHasher() defer h.release() - got := h.hash(blob) - if got == hash { - cleanHitMeter.Mark(1) - cleanReadMeter.Mark(int64(len(blob))) - return blob, nil - } - cleanFalseMeter.Mark(1) - log.Error("Unexpected trie node in clean cache", "owner", owner, "path", path, "expect", hash, "got", got) + cleanHitMeter.Mark(1) + cleanReadMeter.Mark(int64(len(blob))) + return blob, h.hash(blob), &nodeLoc{loc: locCleanCache, depth: depth}, nil } cleanMissMeter.Mark(1) } @@ -146,16 +139,11 @@ func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]b } else { nBlob, nHash = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path) } - if nHash != hash { - diskFalseMeter.Mark(1) - log.Error("Unexpected trie node in disk", "owner", owner, "path", path, "expect", hash, "got", nHash) - return nil, newUnexpectedNodeError("disk", hash, nHash, owner, path, nBlob) - } if dl.cleans != nil && len(nBlob) > 0 { dl.cleans.Set(key, nBlob) cleanWriteMeter.Mark(int64(len(nBlob))) } - return nBlob, nil + return nBlob, nHash, &nodeLoc{loc: locDiskLayer, depth: depth}, nil } // update implements the layer interface, returning a new diff layer on top diff --git a/triedb/pathdb/errors.go b/triedb/pathdb/errors.go index 78ee4459fe50..bbf2c9e37cf2 100644 --- a/triedb/pathdb/errors.go +++ b/triedb/pathdb/errors.go @@ -16,13 +16,7 @@ package pathdb -import ( - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" -) +import "errors" var ( // errDatabaseReadOnly is returned if the database is opened in read only mode @@ -45,16 +39,4 @@ var ( // errStateUnrecoverable is returned if state is required to be reverted to // a destination without associated state history available. errStateUnrecoverable = errors.New("state is unrecoverable") - - // errUnexpectedNode is returned if the requested node with specified path is - // not hash matched with expectation. - errUnexpectedNode = errors.New("unexpected node") ) - -func newUnexpectedNodeError(loc string, expHash common.Hash, gotHash common.Hash, owner common.Hash, path []byte, blob []byte) error { - blobHex := "nil" - if len(blob) > 0 { - blobHex = hexutil.Encode(blob) - } - return fmt.Errorf("%w, loc: %s, node: (%x %v), %x!=%x, blob: %s", errUnexpectedNode, loc, owner, path, expHash, gotHash, blobHex) -} diff --git a/triedb/pathdb/metrics.go b/triedb/pathdb/metrics.go index 9e2b1dcbf55e..a250f703cbab 100644 --- a/triedb/pathdb/metrics.go +++ b/triedb/pathdb/metrics.go @@ -33,6 +33,7 @@ var ( cleanFalseMeter = metrics.NewRegisteredMeter("pathdb/clean/false", nil) dirtyFalseMeter = metrics.NewRegisteredMeter("pathdb/dirty/false", nil) diskFalseMeter = metrics.NewRegisteredMeter("pathdb/disk/false", nil) + diffFalseMeter = metrics.NewRegisteredMeter("pathdb/diff/false", nil) commitTimeTimer = metrics.NewRegisteredTimer("pathdb/commit/time", nil) commitNodesMeter = metrics.NewRegisteredMeter("pathdb/commit/nodes", nil) diff --git a/triedb/pathdb/nodebuffer.go b/triedb/pathdb/nodebuffer.go index 8f84c2b44207..4a13fcc44e8c 100644 --- a/triedb/pathdb/nodebuffer.go +++ b/triedb/pathdb/nodebuffer.go @@ -59,21 +59,16 @@ func newNodeBuffer(limit int, nodes map[common.Hash]map[string]*trienode.Node, l } // node retrieves the trie node with given node info. -func (b *nodebuffer) node(owner common.Hash, path []byte, hash common.Hash) (*trienode.Node, error) { +func (b *nodebuffer) node(owner common.Hash, path []byte) (*trienode.Node, bool) { subset, ok := b.nodes[owner] if !ok { - return nil, nil + return nil, false } n, ok := subset[string(path)] if !ok { - return nil, nil + return nil, false } - if n.Hash != hash { - dirtyFalseMeter.Mark(1) - log.Error("Unexpected trie node in node buffer", "owner", owner, "path", path, "expect", hash, "got", n.Hash) - return nil, newUnexpectedNodeError("dirty", hash, n.Hash, owner, path, n.Blob) - } - return n, nil + return n, true } // commit merges the dirty nodes into the nodebuffer. This operation won't take diff --git a/triedb/pathdb/reader.go b/triedb/pathdb/reader.go new file mode 100644 index 000000000000..54dc98a5437d --- /dev/null +++ b/triedb/pathdb/reader.go @@ -0,0 +1,94 @@ +// Copyright 2024 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 pathdb + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/triedb/database" +) + +// The types of locations where the node is found. +const ( + locDirtyCache = "dirty" // dirty cache + locCleanCache = "clean" // clean cache + locDiskLayer = "disk" // persistent state + locDiffLayer = "diff" // diff layers +) + +// nodeLoc is a helpful structure that contains the location where the node +// is found, as it's useful for debugging purposes. +type nodeLoc struct { + loc string + depth int +} + +// string returns the string representation of node location. +func (loc *nodeLoc) string() string { + return fmt.Sprintf("loc: %s, depth: %d", loc.loc, loc.depth) +} + +// reader implements the database.Reader interface, providing the functionalities to +// retrieve trie nodes by wrapping the internal state layer. +type reader struct { + layer layer + noHashCheck bool +} + +// Node implements database.Reader interface, retrieving the node with specified +// node info. Don't modify the returned byte slice since it's not deep-copied +// and still be referenced by database. +func (r *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) { + blob, got, loc, err := r.layer.node(owner, path, 0) + if err != nil { + return nil, err + } + // Error out if the local one is inconsistent with the target. + if !r.noHashCheck && got != hash { + // Location is always available even if the node + // is not found. + switch loc.loc { + case locCleanCache: + cleanFalseMeter.Mark(1) + case locDirtyCache: + dirtyFalseMeter.Mark(1) + case locDiffLayer: + diffFalseMeter.Mark(1) + case locDiskLayer: + diskFalseMeter.Mark(1) + } + blobHex := "nil" + if len(blob) > 0 { + blobHex = hexutil.Encode(blob) + } + log.Error("Unexpected trie node", "location", loc.loc, "owner", owner, "path", path, "expect", hash, "got", got, "blob", blobHex) + return nil, fmt.Errorf("unexpected node: (%x %v), %x!=%x, %s, blob: %s", owner, path, hash, got, loc.string(), blobHex) + } + return blob, nil +} + +// Reader retrieves a layer belonging to the given state root. +func (db *Database) Reader(root common.Hash) (database.Reader, error) { + layer := db.tree.get(root) + if layer == nil { + return nil, fmt.Errorf("state %#x is not available", root) + } + return &reader{layer: layer, noHashCheck: db.isVerkle}, nil +} From 304879da20200f6912d241ccd471e140d3487093 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 27 Mar 2024 09:35:33 +0800 Subject: [PATCH 109/571] eth/protocols/snap: check storage root existence for hash scheme (#29341) --- eth/protocols/snap/sync.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 887a50775d79..7915a8eba84a 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -2201,7 +2201,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { // If the chunk's root is an overflown but full delivery, // clear the heal request. accountHash := res.accounts[len(res.accounts)-1] - if root == res.subTask.root && rawdb.HasStorageTrieNode(s.db, accountHash, nil, root) { + if root == res.subTask.root && rawdb.HasTrieNode(s.db, accountHash, nil, root, s.scheme) { for i, account := range res.mainTask.res.hashes { if account == accountHash { res.mainTask.needHeal[i] = false From 8bb8f23bb25ab69cfb7065d7dbb3fd6e5f6227a8 Mon Sep 17 00:00:00 2001 From: Pawan Dhananjay Date: Wed, 27 Mar 2024 17:45:57 +0530 Subject: [PATCH 110/571] beacon/engine: Fix json param name in GetClientVersionV1 (#29351) Fix json param name --- beacon/engine/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 60accc3c7917..8281fd794c5c 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -313,7 +313,7 @@ const ( // ClientVersionV1 contains information which identifies a client implementation. type ClientVersionV1 struct { Code string `json:"code"` - Name string `json:"clientName"` + Name string `json:"name"` Version string `json:"version"` Commit string `json:"commit"` } From fa5019de196274afd2426d300cab01d60b2a0c56 Mon Sep 17 00:00:00 2001 From: crazeteam <164632007+crazeteam@users.noreply.github.com> Date: Wed, 27 Mar 2024 20:16:29 +0800 Subject: [PATCH 111/571] accounts/keystore: fix typos in comments (#29336) --- accounts/keystore/keystore_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/keystore/keystore_test.go b/accounts/keystore/keystore_test.go index 23ba31dc910f..f8922a3f3f2a 100644 --- a/accounts/keystore/keystore_test.go +++ b/accounts/keystore/keystore_test.go @@ -343,7 +343,7 @@ func TestWalletNotifications(t *testing.T) { checkEvents(t, wantEvents, events) } -// TestImportExport tests the import functionality of a keystore. +// TestImportECDSA tests the import functionality of a keystore. func TestImportECDSA(t *testing.T) { t.Parallel() _, ks := tmpKeyStore(t) @@ -362,7 +362,7 @@ func TestImportECDSA(t *testing.T) { } } -// TestImportECDSA tests the import and export functionality of a keystore. +// TestImportExport tests the import and export functionality of a keystore. func TestImportExport(t *testing.T) { t.Parallel() _, ks := tmpKeyStore(t) From 767b00b0b514771a663f3362dd0310fc28d40c25 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Wed, 27 Mar 2024 16:12:57 +0100 Subject: [PATCH 112/571] t8ntool: add optional call frames to json logger (#29353) Adds a flag `--trace.callframes` to t8n which will log info when entering or exiting a call frame in addition to the execution steps. --------- Co-authored-by: Mario Vega --- cmd/evm/internal/t8ntool/flags.go | 4 ++ cmd/evm/internal/t8ntool/transition.go | 10 ++- cmd/evm/main.go | 1 + cmd/evm/t8n_test.go | 8 +++ cmd/evm/testdata/32/README.md | 1 + cmd/evm/testdata/32/alloc.json | 30 +++++++++ cmd/evm/testdata/32/env.json | 12 ++++ ...48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl | 61 +++++++++++++++++ cmd/evm/testdata/32/txs.json | 17 +++++ eth/tracers/logger/gen_callframe.go | 65 +++++++++++++++++++ eth/tracers/logger/logger_json.go | 64 +++++++++++++++++- 11 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 cmd/evm/testdata/32/README.md create mode 100644 cmd/evm/testdata/32/alloc.json create mode 100644 cmd/evm/testdata/32/env.json create mode 100644 cmd/evm/testdata/32/trace-0-0x47806361c0fa084be3caa18afe8c48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl create mode 100644 cmd/evm/testdata/32/txs.json create mode 100644 eth/tracers/logger/gen_callframe.go diff --git a/cmd/evm/internal/t8ntool/flags.go b/cmd/evm/internal/t8ntool/flags.go index c2eca8cc217d..f2606c86d18b 100644 --- a/cmd/evm/internal/t8ntool/flags.go +++ b/cmd/evm/internal/t8ntool/flags.go @@ -50,6 +50,10 @@ var ( Name: "trace.returndata", Usage: "Enable return data output in traces", } + TraceEnableCallFramesFlag = &cli.BoolFlag{ + Name: "trace.callframes", + Usage: "Enable call frames output in traces", + } OutputBasedir = &cli.StringFlag{ Name: "output.basedir", Usage: "Specifies where output files are placed. Will be created if it does not exist.", diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 5aa554e13359..2b5eaa65aae1 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" @@ -101,9 +102,14 @@ func Transition(ctx *cli.Context) error { if err != nil { return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } - logger := logger.NewJSONLogger(logConfig, traceFile) + var l *tracing.Hooks + if ctx.Bool(TraceEnableCallFramesFlag.Name) { + l = logger.NewJSONLoggerWithCallFrames(logConfig, traceFile) + } else { + l = logger.NewJSONLogger(logConfig, traceFile) + } tracer := &tracers.Tracer{ - Hooks: logger, + Hooks: l, // jsonLogger streams out result to file. GetResult: func() (json.RawMessage, error) { return nil, nil }, Stop: func(err error) {}, diff --git a/cmd/evm/main.go b/cmd/evm/main.go index c3e6a4af91ba..f9a2a075d0ce 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -152,6 +152,7 @@ var stateTransitionCommand = &cli.Command{ t8ntool.TraceEnableMemoryFlag, t8ntool.TraceDisableStackFlag, t8ntool.TraceEnableReturnDataFlag, + t8ntool.TraceEnableCallFramesFlag, t8ntool.OutputBasedir, t8ntool.OutputAllocFlag, t8ntool.OutputResultFlag, diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 7e0bc36cbe40..5a74491c3b2d 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -375,6 +375,14 @@ func TestT8nTracing(t *testing.T) { }`}, expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json"}, }, + { + base: "./testdata/32", + input: t8nInput{ + "alloc.json", "txs.json", "env.json", "Merge", "", + }, + extraArgs: []string{"--trace", "--trace.callframes"}, + expectedTraces: []string{"trace-0-0x47806361c0fa084be3caa18afe8c48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl"}, + }, } { args := []string{"t8n"} args = append(args, tc.input.get(tc.base)...) diff --git a/cmd/evm/testdata/32/README.md b/cmd/evm/testdata/32/README.md new file mode 100644 index 000000000000..508ac970dd5a --- /dev/null +++ b/cmd/evm/testdata/32/README.md @@ -0,0 +1 @@ +This test does some EVM execution, and can be used to test callframes emitted by the tracer when they are enabled. diff --git a/cmd/evm/testdata/32/alloc.json b/cmd/evm/testdata/32/alloc.json new file mode 100644 index 000000000000..0cd44939552d --- /dev/null +++ b/cmd/evm/testdata/32/alloc.json @@ -0,0 +1,30 @@ +{ + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "nonce": "0x00", + "balance": "0x0de0b6b3a7640000", + "code": "0x600060006000600060007310000000000000000000000000000000000000015af1600155600060006000600060007310000000000000000000000000000000000000025af16002553d600060003e600051600355", + "storage": { + "0x01": "0x0100", + "0x02": "0x0100", + "0x03": "0x0100" + } + }, + "0x1000000000000000000000000000000000000001": { + "nonce": "0x00", + "balance": "0x29a2241af62c0000", + "code": "0x6103e8ff", + "storage": {} + }, + "0x1000000000000000000000000000000000000002": { + "nonce": "0x00", + "balance": "0x4563918244f40000", + "code": "0x600060006000600060647310000000000000000000000000000000000000015af1600f0160005260206000fd", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "nonce": "0x00", + "balance": "0x6124fee993bc0000", + "code": "0x", + "storage": {} + } +} \ No newline at end of file diff --git a/cmd/evm/testdata/32/env.json b/cmd/evm/testdata/32/env.json new file mode 100644 index 000000000000..4f0833e711fa --- /dev/null +++ b/cmd/evm/testdata/32/env.json @@ -0,0 +1,12 @@ +{ + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentGasLimit": "71794957647893862", + "currentNumber": "1", + "currentTimestamp": "1000", + "currentRandom": "0", + "currentDifficulty": "0", + "blockHashes": {}, + "ommers": [], + "currentBaseFee": "7", + "parentUncleHash": "0x0000000000000000000000000000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/cmd/evm/testdata/32/trace-0-0x47806361c0fa084be3caa18afe8c48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl b/cmd/evm/testdata/32/trace-0-0x47806361c0fa084be3caa18afe8c48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl new file mode 100644 index 000000000000..b6c5237baa03 --- /dev/null +++ b/cmd/evm/testdata/32/trace-0-0x47806361c0fa084be3caa18afe8c48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl @@ -0,0 +1,61 @@ +{"from":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","to":"0x8a0a19589531694250d570040a0c4b74576919b8","gas":"0x74f18","value":"0x0","type":"CALL"} +{"pc":0,"op":96,"gas":"0x74f18","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":96,"gas":"0x74f15","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":4,"op":96,"gas":"0x74f12","gasCost":"0x3","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":96,"gas":"0x74f0f","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":8,"op":96,"gas":"0x74f0c","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":10,"op":115,"gas":"0x74f09","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH20"} +{"pc":31,"op":90,"gas":"0x74f06","gasCost":"0x2","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x1000000000000000000000000000000000000001"],"depth":1,"refund":0,"opName":"GAS"} +{"pc":32,"op":241,"gas":"0x74f04","gasCost":"0x731f1","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x1000000000000000000000000000000000000001","0x74f04"],"depth":1,"refund":0,"opName":"CALL"} +{"from":"0x8a0a19589531694250d570040a0c4b74576919b8","to":"0x1000000000000000000000000000000000000001","gas":"0x727c9","value":"0x0","type":"CALL"} +{"pc":0,"op":97,"gas":"0x727c9","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":3,"op":255,"gas":"0x727c6","gasCost":"0x7f58","memSize":0,"stack":["0x3e8"],"depth":2,"refund":0,"opName":"SELFDESTRUCT"} +{"from":"0x1000000000000000000000000000000000000001","to":"0x00000000000000000000000000000000000003e8","gas":"0x0","value":"0x29a2241af62c0000","type":"SELFDESTRUCT"} +{"output":"","gasUsed":"0x0"} +{"output":"","gasUsed":"0x7f5b"} +{"pc":33,"op":96,"gas":"0x6c581","gasCost":"0x3","memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":35,"op":85,"gas":"0x6c57e","gasCost":"0x1388","memSize":0,"stack":["0x1","0x1"],"depth":1,"refund":0,"opName":"SSTORE"} +{"pc":36,"op":96,"gas":"0x6b1f6","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":38,"op":96,"gas":"0x6b1f3","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":40,"op":96,"gas":"0x6b1f0","gasCost":"0x3","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":42,"op":96,"gas":"0x6b1ed","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":44,"op":96,"gas":"0x6b1ea","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":46,"op":115,"gas":"0x6b1e7","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH20"} +{"pc":67,"op":90,"gas":"0x6b1e4","gasCost":"0x2","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x1000000000000000000000000000000000000002"],"depth":1,"refund":0,"opName":"GAS"} +{"pc":68,"op":241,"gas":"0x6b1e2","gasCost":"0x69744","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x1000000000000000000000000000000000000002","0x6b1e2"],"depth":1,"refund":0,"opName":"CALL"} +{"from":"0x8a0a19589531694250d570040a0c4b74576919b8","to":"0x1000000000000000000000000000000000000002","gas":"0x68d1c","value":"0x0","type":"CALL"} +{"pc":0,"op":96,"gas":"0x68d1c","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":96,"gas":"0x68d19","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":4,"op":96,"gas":"0x68d16","gasCost":"0x3","memSize":0,"stack":["0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":96,"gas":"0x68d13","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":8,"op":96,"gas":"0x68d10","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":10,"op":115,"gas":"0x68d0d","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x64"],"depth":2,"refund":0,"opName":"PUSH20"} +{"pc":31,"op":90,"gas":"0x68d0a","gasCost":"0x2","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x64","0x1000000000000000000000000000000000000001"],"depth":2,"refund":0,"opName":"GAS"} +{"pc":32,"op":241,"gas":"0x68d08","gasCost":"0x67363","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x64","0x1000000000000000000000000000000000000001","0x68d08"],"depth":2,"refund":0,"opName":"CALL"} +{"from":"0x1000000000000000000000000000000000000002","to":"0x1000000000000000000000000000000000000001","gas":"0x658d3","value":"0x64","type":"CALL"} +{"pc":0,"op":97,"gas":"0x658d3","gasCost":"0x3","memSize":0,"stack":[],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":3,"op":255,"gas":"0x658d0","gasCost":"0x1388","memSize":0,"stack":["0x3e8"],"depth":3,"refund":0,"opName":"SELFDESTRUCT"} +{"from":"0x1000000000000000000000000000000000000001","to":"0x00000000000000000000000000000000000003e8","gas":"0x0","value":"0x64","type":"SELFDESTRUCT"} +{"output":"","gasUsed":"0x0"} +{"output":"","gasUsed":"0x138b"} +{"pc":33,"op":96,"gas":"0x65eed","gasCost":"0x3","memSize":0,"stack":["0x1"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":35,"op":1,"gas":"0x65eea","gasCost":"0x3","memSize":0,"stack":["0x1","0xf"],"depth":2,"refund":0,"opName":"ADD"} +{"pc":36,"op":96,"gas":"0x65ee7","gasCost":"0x3","memSize":0,"stack":["0x10"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":38,"op":82,"gas":"0x65ee4","gasCost":"0x6","memSize":0,"stack":["0x10","0x0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":39,"op":96,"gas":"0x65ede","gasCost":"0x3","memSize":32,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":41,"op":96,"gas":"0x65edb","gasCost":"0x3","memSize":32,"stack":["0x20"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":43,"op":253,"gas":"0x65ed8","gasCost":"0x0","memSize":32,"stack":["0x20","0x0"],"depth":2,"refund":0,"opName":"REVERT"} +{"pc":43,"op":253,"gas":"0x65ed8","gasCost":"0x0","memSize":32,"stack":[],"depth":2,"refund":0,"opName":"REVERT","error":"execution reverted"} +{"output":"0000000000000000000000000000000000000000000000000000000000000010","gasUsed":"0x2e44","error":"execution reverted"} +{"pc":69,"op":96,"gas":"0x67976","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":71,"op":85,"gas":"0x67973","gasCost":"0x1388","memSize":0,"stack":["0x0","0x2"],"depth":1,"refund":4800,"opName":"SSTORE"} +{"pc":72,"op":61,"gas":"0x665eb","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":4800,"opName":"RETURNDATASIZE"} +{"pc":73,"op":96,"gas":"0x665e9","gasCost":"0x3","memSize":0,"stack":["0x20"],"depth":1,"refund":4800,"opName":"PUSH1"} +{"pc":75,"op":96,"gas":"0x665e6","gasCost":"0x3","memSize":0,"stack":["0x20","0x0"],"depth":1,"refund":4800,"opName":"PUSH1"} +{"pc":77,"op":62,"gas":"0x665e3","gasCost":"0x9","memSize":0,"stack":["0x20","0x0","0x0"],"depth":1,"refund":4800,"opName":"RETURNDATACOPY"} +{"pc":78,"op":96,"gas":"0x665da","gasCost":"0x3","memSize":32,"stack":[],"depth":1,"refund":4800,"opName":"PUSH1"} +{"pc":80,"op":81,"gas":"0x665d7","gasCost":"0x3","memSize":32,"stack":["0x0"],"depth":1,"refund":4800,"opName":"MLOAD"} +{"pc":81,"op":96,"gas":"0x665d4","gasCost":"0x3","memSize":32,"stack":["0x10"],"depth":1,"refund":4800,"opName":"PUSH1"} +{"pc":83,"op":85,"gas":"0x665d1","gasCost":"0x1388","memSize":32,"stack":["0x10","0x3"],"depth":1,"refund":4800,"opName":"SSTORE"} +{"pc":84,"op":0,"gas":"0x65249","gasCost":"0x0","memSize":32,"stack":[],"depth":1,"refund":4800,"opName":"STOP"} +{"output":"","gasUsed":"0xfccf"} diff --git a/cmd/evm/testdata/32/txs.json b/cmd/evm/testdata/32/txs.json new file mode 100644 index 000000000000..0530fd60e62c --- /dev/null +++ b/cmd/evm/testdata/32/txs.json @@ -0,0 +1,17 @@ +[ + { + "type": "0x0", + "chainId": "0x0", + "nonce": "0x0", + "gasPrice": "0xa", + "gas": "0x7a120", + "to": "0x8a0a19589531694250d570040a0c4b74576919b8", + "value": "0x0", + "input": "0x", + "v": "0x1c", + "r": "0x9a207ad45b7fc2aa5f8e72a30487f2b0bc489778e6d022f19036efdf2a922a17", + "s": "0x640d4da05078b5a4aa561f1b4d58176ea828bfa0f88d27d14459c1d789e1a1eb", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + } +] \ No newline at end of file diff --git a/eth/tracers/logger/gen_callframe.go b/eth/tracers/logger/gen_callframe.go new file mode 100644 index 000000000000..b7b2cc288180 --- /dev/null +++ b/eth/tracers/logger/gen_callframe.go @@ -0,0 +1,65 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package logger + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" +) + +var _ = (*callFrameMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (c callFrame) MarshalJSON() ([]byte, error) { + type callFrame struct { + From common.Address `json:"from"` + To common.Address `json:"to"` + Input hexutil.Bytes `json:"input,omitempty"` + Gas math.HexOrDecimal64 `json:"gas"` + Value *hexutil.Big `json:"value"` + Type string `json:"type"` + } + var enc callFrame + enc.From = c.From + enc.To = c.To + enc.Input = c.Input + enc.Gas = math.HexOrDecimal64(c.Gas) + enc.Value = (*hexutil.Big)(c.Value) + enc.Type = c.Type() + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (c *callFrame) UnmarshalJSON(input []byte) error { + type callFrame struct { + From *common.Address `json:"from"` + To *common.Address `json:"to"` + Input *hexutil.Bytes `json:"input,omitempty"` + Gas *math.HexOrDecimal64 `json:"gas"` + Value *hexutil.Big `json:"value"` + } + var dec callFrame + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.From != nil { + c.From = *dec.From + } + if dec.To != nil { + c.To = *dec.To + } + if dec.Input != nil { + c.Input = *dec.Input + } + if dec.Gas != nil { + c.Gas = uint64(*dec.Gas) + } + if dec.Value != nil { + c.Value = (*big.Int)(dec.Value) + } + return nil +} diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 6fac2d115922..d66b8c4b8ad0 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -19,14 +19,41 @@ package logger import ( "encoding/json" "io" + "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/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" ) +//go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe.go + +// overrides for gencodec +type callFrameMarshaling struct { + Input hexutil.Bytes + Gas math.HexOrDecimal64 + Value *hexutil.Big + Type string `json:"type"` // adds call to Type() in MarshalJSON +} + +// callFrame is emitted every call frame entered. +type callFrame struct { + op vm.OpCode + From common.Address `json:"from"` + To common.Address `json:"to"` + Input []byte `json:"input,omitempty"` + Gas uint64 `json:"gas"` + Value *big.Int `json:"value"` +} + +// Type formats the call type in a human-readable format. +func (c *callFrame) Type() string { + return c.op.String() +} + type jsonLogger struct { encoder *json.Encoder cfg *Config @@ -48,6 +75,22 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { } } +// NewJSONLoggerWithCallFrames creates a new EVM tracer that prints execution steps as JSON objects +// into the provided stream. It also includes call frames in the output. +func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) *tracing.Hooks { + l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg} + if l.cfg == nil { + l.cfg = &Config{} + } + return &tracing.Hooks{ + OnTxStart: l.OnTxStart, + OnEnter: l.OnEnter, + OnExit: l.OnExit, + OnOpcode: l.OnOpcode, + OnFault: l.OnFault, + } +} + func (l *jsonLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { // TODO: Add rData to this interface as well l.OnOpcode(pc, op, gas, cost, scope, nil, depth, err) @@ -79,10 +122,29 @@ func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracin l.encoder.Encode(log) } -func (l *jsonLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { +// OnEnter is not enabled by default. +func (l *jsonLogger) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + frame := callFrame{ + op: vm.OpCode(typ), + From: from, + To: to, + Gas: gas, + Value: value, + } + if l.cfg.EnableMemory { + frame.Input = input + } + l.encoder.Encode(frame) +} + +func (l *jsonLogger) OnEnd(depth int, output []byte, gasUsed uint64, err error, reverted bool) { if depth > 0 { return } + l.OnExit(depth, output, gasUsed, err, false) +} + +func (l *jsonLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { type endLog struct { Output string `json:"output"` GasUsed math.HexOrDecimal64 `json:"gasUsed"` From 7aba6511b0cbe910a0db9d345487d2c6ef301e53 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Thu, 28 Mar 2024 19:06:44 +0800 Subject: [PATCH 113/571] ethdb/dbtest: replace reflect.DeepEqual with slices.Equal (#29382) --- ethdb/dbtest/testsuite.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 51eaca347483..83a13c8cff64 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -19,7 +19,6 @@ package dbtest import ( "bytes" "crypto/rand" - "reflect" "slices" "sort" "testing" @@ -149,7 +148,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { if err := it.Error(); err != nil { t.Fatal(err) } - if !reflect.DeepEqual(got, want) { + if !slices.Equal(got, want) { t.Errorf("Iterator: got: %s; want: %s", got, want) } } @@ -160,7 +159,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { if err := it.Error(); err != nil { t.Fatal(err) } - if !reflect.DeepEqual(got, want) { + if !slices.Equal(got, want) { t.Errorf("IteratorWith(1,nil): got: %s; want: %s", got, want) } } @@ -171,7 +170,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { if err := it.Error(); err != nil { t.Fatal(err) } - if !reflect.DeepEqual(got, want) { + if !slices.Equal(got, want) { t.Errorf("IteratorWith(5,nil): got: %s; want: %s", got, want) } } @@ -182,7 +181,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { if err := it.Error(); err != nil { t.Fatal(err) } - if !reflect.DeepEqual(got, want) { + if !slices.Equal(got, want) { t.Errorf("IteratorWith(nil,2): got: %s; want: %s", got, want) } } @@ -193,7 +192,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { if err := it.Error(); err != nil { t.Fatal(err) } - if !reflect.DeepEqual(got, want) { + if !slices.Equal(got, want) { t.Errorf("IteratorWith(nil,5): got: %s; want: %s", got, want) } } @@ -262,7 +261,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { { it := db.NewIterator(nil, nil) - if got, want := iterateKeys(it), []string{"1", "2", "3", "4"}; !reflect.DeepEqual(got, want) { + if got, want := iterateKeys(it), []string{"1", "2", "3", "4"}; !slices.Equal(got, want) { t.Errorf("got: %s; want: %s", got, want) } } @@ -286,7 +285,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { { it := db.NewIterator(nil, nil) - if got, want := iterateKeys(it), []string{"2", "3", "4", "5", "6"}; !reflect.DeepEqual(got, want) { + if got, want := iterateKeys(it), []string{"2", "3", "4", "5", "6"}; !slices.Equal(got, want) { t.Errorf("got: %s; want: %s", got, want) } } @@ -314,7 +313,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { } it := db.NewIterator(nil, nil) - if got := iterateKeys(it); !reflect.DeepEqual(got, want) { + if got := iterateKeys(it); !slices.Equal(got, want) { t.Errorf("got: %s; want: %s", got, want) } }) From 3b77e0ff4bcce8c0c9f18f23625a6fe69d17bbed Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 28 Mar 2024 19:06:57 +0800 Subject: [PATCH 114/571] core: remove unused code (#29381) --- core/blockchain.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 70d0fed6891f..680875373454 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1552,17 +1552,6 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. return nil } -// WriteBlockAndSetHead writes the given block and all associated state to the database, -// and applies the block as the new chain head. -func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { - if !bc.chainmu.TryLock() { - return NonStatTy, errChainStopped - } - defer bc.chainmu.Unlock() - - return bc.writeBlockAndSetHead(block, receipts, logs, state, emitHeadEvent) -} - // writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead. // This function expects the chain mutex to be held. func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { From 3754a6cc922f88f50ed0479cfb836676936384d3 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Thu, 28 Mar 2024 19:07:38 +0800 Subject: [PATCH 115/571] p2p/dnsdisc: using maps.Copy (#29377) --- p2p/dnsdisc/client_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/p2p/dnsdisc/client_test.go b/p2p/dnsdisc/client_test.go index abc35ddbd3d3..77bfd8c1310b 100644 --- a/p2p/dnsdisc/client_test.go +++ b/p2p/dnsdisc/client_test.go @@ -20,6 +20,7 @@ import ( "context" "crypto/ecdsa" "errors" + "maps" "reflect" "testing" "time" @@ -453,9 +454,7 @@ func (mr mapResolver) clear() { } func (mr mapResolver) add(m map[string]string) { - for k, v := range m { - mr[k] = v - } + maps.Copy(mr, m) } func (mr mapResolver) LookupTXT(ctx context.Context, name string) ([]string, error) { From 7481398a2471f52de277627cc473190f0c2569c8 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Thu, 28 Mar 2024 19:13:41 +0800 Subject: [PATCH 116/571] core/state: using slices.Clone (#29366) --- core/state/statedb.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 981eea7d6f92..8cdcbc40c32c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -20,6 +20,7 @@ package state import ( "fmt" "math/big" + "slices" "sort" "time" @@ -243,9 +244,7 @@ func (s *StateDB) Logs() []*types.Log { func (s *StateDB) AddPreimage(hash common.Hash, preimage []byte) { if _, ok := s.preimages[hash]; !ok { s.journal.append(addPreimageChange{hash: hash}) - pi := make([]byte, len(preimage)) - copy(pi, preimage) - s.preimages[hash] = pi + s.preimages[hash] = slices.Clone(preimage) } } From 0183c7ad8225f82e2c23b9bc6329c19d7f0269c5 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Thu, 28 Mar 2024 21:09:21 +0800 Subject: [PATCH 117/571] eth/tracers/logger: using maps.Equal (#29384) Co-authored-by: Felix Lange --- eth/tracers/logger/access_list_tracer.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index fda26a81af7d..e8231461b0cf 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -17,6 +17,8 @@ package logger import ( + "maps" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" @@ -71,17 +73,9 @@ func (al accessList) equal(other accessList) bool { // Accounts match, cross reference the storage slots too for addr, slots := range al { otherslots := other[addr] - - if len(slots) != len(otherslots) { + if !maps.Equal(slots, otherslots) { return false } - // Given that len(slots) == len(otherslots), we only need to check that - // all the items from slots are in otherslots. - for hash := range slots { - if _, ok := otherslots[hash]; !ok { - return false - } - } } return true } From a3829178af6cec64d6def9131b9340a3328cc4fc Mon Sep 17 00:00:00 2001 From: Brandon Liu Date: Fri, 29 Mar 2024 00:35:40 +0800 Subject: [PATCH 118/571] eth/tracers/js: consistent name for method receivers (#29375) --- eth/tracers/js/goja.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 7e4930f81dbd..82666155ec76 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -677,11 +677,11 @@ func (mo *memoryObj) Length() int { return len(mo.memory) } -func (m *memoryObj) setupObject() *goja.Object { - o := m.vm.NewObject() - o.Set("slice", m.vm.ToValue(m.Slice)) - o.Set("getUint", m.vm.ToValue(m.GetUint)) - o.Set("length", m.vm.ToValue(m.Length)) +func (mo *memoryObj) setupObject() *goja.Object { + o := mo.vm.NewObject() + o.Set("slice", mo.vm.ToValue(mo.Slice)) + o.Set("getUint", mo.vm.ToValue(mo.GetUint)) + o.Set("length", mo.vm.ToValue(mo.Length)) return o } @@ -863,12 +863,12 @@ func (co *contractObj) GetInput() goja.Value { return res } -func (c *contractObj) setupObject() *goja.Object { - o := c.vm.NewObject() - o.Set("getCaller", c.vm.ToValue(c.GetCaller)) - o.Set("getAddress", c.vm.ToValue(c.GetAddress)) - o.Set("getValue", c.vm.ToValue(c.GetValue)) - o.Set("getInput", c.vm.ToValue(c.GetInput)) +func (co *contractObj) setupObject() *goja.Object { + o := co.vm.NewObject() + o.Set("getCaller", co.vm.ToValue(co.GetCaller)) + o.Set("getAddress", co.vm.ToValue(co.GetAddress)) + o.Set("getValue", co.vm.ToValue(co.GetValue)) + o.Set("getInput", co.vm.ToValue(co.GetInput)) return o } From c39d00e316943fa613f10ceff262482ea3aa2c65 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Mon, 1 Apr 2024 11:42:50 +0800 Subject: [PATCH 119/571] trie: using maps.Clone (#29419) --- trie/sync_test.go | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/trie/sync_test.go b/trie/sync_test.go index 7bc68c041fdc..7221b06f59c0 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -19,6 +19,7 @@ package trie import ( "bytes" "fmt" + "maps" "math/rand" "testing" @@ -837,13 +838,6 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) { tr.Update(key, val) states[string(key)] = common.CopyBytes(val) } - copyStates = func(states map[string][]byte) map[string][]byte { - cpy := make(map[string][]byte) - for k, v := range states { - cpy[k] = v - } - return cpy - } ) stateA := make(map[string][]byte) writeFn([]byte{0x01, 0x23}, nil, srcTrie, stateA) @@ -866,7 +860,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) { checkTrieContents(t, destDisk, scheme, srcTrie.Hash().Bytes(), stateA, true) // Delete element to collapse trie - stateB := copyStates(stateA) + stateB := maps.Clone(stateA) srcTrie, _ = New(TrieID(rootA), srcTrieDB) deleteFn([]byte{0x02, 0x34}, srcTrie, stateB) deleteFn([]byte{0x13, 0x44}, srcTrie, stateB) @@ -883,7 +877,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) { checkTrieContents(t, destDisk, scheme, srcTrie.Hash().Bytes(), stateB, true) // Add elements to expand trie - stateC := copyStates(stateB) + stateC := maps.Clone(stateB) srcTrie, _ = New(TrieID(rootB), srcTrieDB) writeFn([]byte{0x01, 0x24}, stateA[string([]byte{0x01, 0x24})], srcTrie, stateC) @@ -941,13 +935,6 @@ func testSyncAbort(t *testing.T, scheme string) { tr.Update(key, val) states[string(key)] = common.CopyBytes(val) } - copyStates = func(states map[string][]byte) map[string][]byte { - cpy := make(map[string][]byte) - for k, v := range states { - cpy[k] = v - } - return cpy - } ) var ( stateA = make(map[string][]byte) @@ -972,7 +959,7 @@ func testSyncAbort(t *testing.T, scheme string) { checkTrieContents(t, destDisk, scheme, srcTrie.Hash().Bytes(), stateA, true) // Delete the element from the trie - stateB := copyStates(stateA) + stateB := maps.Clone(stateA) srcTrie, _ = New(TrieID(rootA), srcTrieDB) deleteFn(key, srcTrie, stateB) @@ -999,7 +986,7 @@ func testSyncAbort(t *testing.T, scheme string) { }}) // Add elements to expand trie - stateC := copyStates(stateB) + stateC := maps.Clone(stateB) srcTrie, _ = New(TrieID(rootB), srcTrieDB) writeFn(key, val, srcTrie, stateC) From 6c9f7029823cac48291558aa0a76cbd653830f51 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Mon, 1 Apr 2024 11:45:56 +0800 Subject: [PATCH 120/571] core/types: using maps.Clone (#29398) --- core/types/transaction_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 76a010d2e502..361b977611c2 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "math/big" "reflect" "testing" @@ -515,10 +516,7 @@ func TestYParityJSONUnmarshalling(t *testing.T) { test := test t.Run(fmt.Sprintf("txType=%d: %s", txType, test.name), func(t *testing.T) { // Copy the base json - testJson := make(map[string]interface{}) - for k, v := range baseJson { - testJson[k] = v - } + testJson := maps.Clone(baseJson) // Set v, yParity and type if test.v != "" { From 8c5576b1ac89473c7ec15c9b03d1ca02e9499dcc Mon Sep 17 00:00:00 2001 From: Delweng Date: Mon, 1 Apr 2024 20:53:56 +0800 Subject: [PATCH 121/571] eth/tracers: fix base fee and set blob fee in tests (#29376) Signed-off-by: jsvisa Co-authored-by: Sina Mahmoodi --- .../internal/tracetest/calltrace_test.go | 22 +----- .../internal/tracetest/flat_calltrace_test.go | 14 +--- eth/tracers/internal/tracetest/makeTest.js | 21 +++--- .../internal/tracetest/prestate_test.go | 19 +----- .../testdata/call_tracer/blob_tx.json | 67 +++++++++++++++++++ .../call_tracer/inner_revert_reason.json | 3 +- .../testdata/prestate_tracer/blob_tx.json | 3 +- .../prestate_tracer/create_create.json | 3 +- .../prestate_tracer/create_post_eip158.json | 3 +- .../create_failed.json | 7 +- .../create_post_eip158.json | 3 +- eth/tracers/internal/tracetest/util.go | 36 ++++++++++ 12 files changed, 137 insertions(+), 64 deletions(-) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 896d4d8a88d4..31b2ef6d16ee 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -27,7 +27,6 @@ import ( "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/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -39,14 +38,6 @@ import ( "github.com/ethereum/go-ethereum/tests" ) -type callContext struct { - Number math.HexOrDecimal64 `json:"number"` - Difficulty *math.HexOrDecimal256 `json:"difficulty"` - Time math.HexOrDecimal64 `json:"timestamp"` - GasLimit math.HexOrDecimal64 `json:"gasLimit"` - Miner common.Address `json:"miner"` -} - // callLog is the result of LOG opCode type callLog struct { Address common.Address `json:"address"` @@ -125,17 +116,8 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { // Configure a blockchain with the given prestate var ( signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) - context = vm.BlockContext{ - CanTransfer: core.CanTransfer, - Transfer: core.Transfer, - Coinbase: test.Context.Miner, - BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), - Time: uint64(test.Context.Time), - Difficulty: (*big.Int)(test.Context.Difficulty), - GasLimit: uint64(test.Context.GasLimit), - BaseFee: test.Genesis.BaseFee, - } - state = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) + context = test.Context.toBlockContext(test.Genesis) + state = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) ) state.Close() diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 7694e94c6ce1..ec7a944b91de 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -61,8 +61,8 @@ type flatCallTraceResult struct { // flatCallTracerTest defines a single test to check the call tracer against. type flatCallTracerTest struct { - Genesis core.Genesis `json:"genesis"` - Context callContext `json:"context"` + Genesis *core.Genesis `json:"genesis"` + Context *callContext `json:"context"` Input string `json:"input"` TracerConfig json.RawMessage `json:"tracerConfig"` Result []flatCallTrace `json:"result"` @@ -84,15 +84,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string return fmt.Errorf("failed to parse testcase input: %v", err) } signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) - context := vm.BlockContext{ - CanTransfer: core.CanTransfer, - Transfer: core.Transfer, - Coinbase: test.Context.Miner, - BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), - Time: uint64(test.Context.Time), - Difficulty: (*big.Int)(test.Context.Difficulty), - GasLimit: uint64(test.Context.GasLimit), - } + context := test.Context.toBlockContext(test.Genesis) state := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) defer state.Close() diff --git a/eth/tracers/internal/tracetest/makeTest.js b/eth/tracers/internal/tracetest/makeTest.js index 306f10719009..3ad7a5df736c 100644 --- a/eth/tracers/internal/tracetest/makeTest.js +++ b/eth/tracers/internal/tracetest/makeTest.js @@ -33,16 +33,21 @@ var makeTest = function(tx, traceConfig) { var result = debug.traceTransaction(tx, traceConfig); delete result.time; + var context = { + number: block.number.toString(), + difficulty: block.difficulty, + timestamp: block.timestamp.toString(), + gasLimit: block.gasLimit.toString(), + miner: block.miner, + }; + if (block.baseFeePerGas) { + context.baseFeePerGas = block.baseFeePerGas.toString(); + } + console.log(JSON.stringify({ genesis: genesis, - context: { - number: block.number.toString(), - difficulty: block.difficulty, - timestamp: block.timestamp.toString(), - gasLimit: block.gasLimit.toString(), - miner: block.miner, - }, + context: context, input: eth.getRawTransaction(tx), result: result, }, null, 2)); -} \ No newline at end of file +} diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index dee2bf492e5b..9cbd12669489 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -25,7 +25,6 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -94,25 +93,11 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { // Configure a blockchain with the given prestate var ( signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) - context = vm.BlockContext{ - CanTransfer: core.CanTransfer, - Transfer: core.Transfer, - Coinbase: test.Context.Miner, - BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), - Time: uint64(test.Context.Time), - Difficulty: (*big.Int)(test.Context.Difficulty), - GasLimit: uint64(test.Context.GasLimit), - BaseFee: test.Genesis.BaseFee, - } - state = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) + context = test.Context.toBlockContext(test.Genesis) + state = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) ) defer state.Close() - if test.Genesis.ExcessBlobGas != nil && test.Genesis.BlobGasUsed != nil { - excessBlobGas := eip4844.CalcExcessBlobGas(*test.Genesis.ExcessBlobGas, *test.Genesis.BlobGasUsed) - context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) - } - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json new file mode 100644 index 000000000000..549acb1fe6a6 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json @@ -0,0 +1,67 @@ +{ + "genesis": { + "baseFeePerGas": "7", + "blobGasUsed": "0", + "difficulty": "0", + "excessBlobGas": "36306944", + "extraData": "0xd983010e00846765746888676f312e32312e308664617277696e", + "gasLimit": "15639172", + "hash": "0xc682259fda061bb9ce8ccb491d5b2d436cb73daf04e1025dd116d045ce4ad28c", + "miner": "0x0000000000000000000000000000000000000000", + "mixHash": "0xae1a5ba939a4c9ac38aabeff361169fb55a6fc2c9511457e0be6eff9514faec0", + "nonce": "0x0000000000000000", + "number": "315", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x577f42ab21ccfd946511c57869ace0bdf7c217c36f02b7cd3459df0ed1cffc1a", + "timestamp": "1709626771", + "totalDifficulty": "1", + "withdrawals": [], + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x272e0528" + }, + "0x0c2c51a0990aee1d73c1228de158688341557508": { + "balance": "0xde0b6b3a7640000" + } + }, + "config": { + "chainId": 1337, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "shanghaiTime": 0, + "cancunTime": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true + } + }, + "context": { + "number": "316", + "difficulty": "0", + "timestamp": "1709626785", + "gasLimit": "15654443", + "miner": "0x0000000000000000000000000000000000000000", + "baseFeePerGas": "7" + }, + "input": "0x03f8b1820539806485174876e800825208940c2c51a0990aee1d73c1228de1586883415575088080c083020000f842a00100c9fbdf97f747e85847b4f3fff408f89c26842f77c882858bf2c89923849aa00138e3896f3c27f2389147507f8bcec52028b0efca6ee842ed83c9158873943880a0dbac3f97a532c9b00e6239b29036245a5bfbb96940b9d848634661abee98b945a03eec8525f261c2e79798f7b45a5d6ccaefa24576d53ba5023e919b86841c0675", + "result": { + "from": "0x0c2c51a0990aee1d73c1228de158688341557508", + "gas": "0x5208", + "gasUsed": "0x5208", + "to": "0x0c2c51a0990aee1d73c1228de158688341557508", + "input": "0x", + "value": "0x0", + "type": "CALL" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json index ad0627ccd660..0108c93ae020 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json @@ -45,7 +45,8 @@ "difficulty": "2", "timestamp": "1665537018", "gasLimit": "11511229", - "miner": "0x0000000000000000000000000000000000000000" + "miner": "0x0000000000000000000000000000000000000000", + "baseFeePerGas": "875000000" }, "input": "0x02f9029d82053980849502f90085010c388d00832dc6c08080b90241608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033c001a07566181071cabaf58b70fc41557eb813bfc7a24f5c58554e7fed0bf7c031f169a0420af50b5fe791a4d839e181a676db5250b415dfb35cb85d544db7a1475ae2cc", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json index 315481aff536..c3e7387f02e2 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json @@ -51,7 +51,8 @@ "difficulty": "0", "timestamp": "1709626785", "gasLimit": "15654443", - "miner": "0x0000000000000000000000000000000000000000" + "miner": "0x0000000000000000000000000000000000000000", + "baseFeePerGas": "7" }, "input": "0x03f8b1820539806485174876e800825208940c2c51a0990aee1d73c1228de1586883415575088080c083020000f842a00100c9fbdf97f747e85847b4f3fff408f89c26842f77c882858bf2c89923849aa00138e3896f3c27f2389147507f8bcec52028b0efca6ee842ed83c9158873943880a0dbac3f97a532c9b00e6239b29036245a5bfbb96940b9d848634661abee98b945a03eec8525f261c2e79798f7b45a5d6ccaefa24576d53ba5023e919b86841c0675", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json index 909a1eabe38e..893c60444310 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json @@ -48,7 +48,8 @@ "difficulty": "0", "timestamp": "1699617847", "gasLimit": "11522469", - "miner": "0x0000000000000000000000000000000000000000" + "miner": "0x0000000000000000000000000000000000000000", + "baseFeePerGas": "765625000" }, "input": "0x02f902b48205398084b2d05e0085011b1f3f8083031ca88080b90258608060405234801561001057600080fd5b5060405161001d906100e3565b604051809103906000f080158015610039573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b039290921691821781556040517fc66247bafd1305823857fb4c3e651e684d918df8554ef560bbbcb025fdd017039190a26000546040516360fe47b160e01b8152600560048201526001600160a01b03909116906360fe47b190602401600060405180830381600087803b1580156100c657600080fd5b505af11580156100da573d6000803e3d6000fd5b505050506100ef565b60ca8061018e83390190565b6091806100fd6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806380de699314602d575b600080fd5b600054603f906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f3fea2646970667358221220dab781465e7f4cf20304cc388130a763508e20edd25b4bc8ea8f57743a0de8da64736f6c634300081700336080604052348015600f57600080fd5b5060ac8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146049575b600080fd5b60476042366004605e565b600055565b005b60005460405190815260200160405180910390f35b600060208284031215606f57600080fd5b503591905056fea264697066735822122049e09da6320793487d58eaa7b97f802618a062cbc35f08ca1ce92c17349141f864736f6c63430008170033c080a01d4fce93ad08bf413052645721f20e6136830cf5a2759fa57e76a134e90899a7a0399a72832d52118991dc04c4f9e1c0fec3d5e441ad7d4b055f0cf03130d8f815", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json index 205b472dabe4..fb85b31a4897 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json @@ -48,7 +48,8 @@ "difficulty": "2", "timestamp": "1709022197", "gasLimit": "30000000", - "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0" + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0", + "baseFeePerGas": "7" }, "input": "0x02f902af823039408459682f008459682f088302b3538080b90254608060405234801561001057600080fd5b50610234806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033c001a0a8cf4729b7e4664687abb3e2559853d7d489eb441519be2a17493061fb4c3a03a04b5a904ba8a6e59c6c40049c4d14a73233aeb8a45b38403199f304630dc0d453", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json index 561ead05b6f8..ae7f7e97f5a9 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json @@ -1,6 +1,6 @@ { "genesis": { - "baseFeePerGas": "51088069741", + "baseFeePerGas": "4573728117", "difficulty": "14315558652874667", "extraData": "0xd883010a10846765746888676f312e31362e35856c696e7578", "gasLimit": "30058590", @@ -64,7 +64,8 @@ "difficulty": "14322823549655084", "timestamp": "1651623279", "gasLimit": "30029237", - "miner": "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7" + "miner": "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7", + "baseFeePerGas": "4002012103" }, "input": "0x02f8b4018312acfc8459682f00851a46bcf47a8302b1a194ffa397285ce46fb78c588a9e993286aac68c37cd80b844fb90b3200000000000000000000000002a549b4af9ec39b03142da6dc32221fc390b553300000000000000000000000000000000000000000000000000000000000cb3d5c001a03002079d2873f7963c4278200c43aa71efad262b2150bc8524480acfc38b5faaa077d44aa09d56b9cf99443c7f55aaad1bbae9cfb5bbb9de31eaf7a8f9e623e980", "tracerConfig": { @@ -83,7 +84,7 @@ }, "post": { "0x808b4da0be6c9512e948521452227efc619bea52": { - "balance": "0x2cd987071ba2346b6", + "balance": "0x2cdb5f8e62cc9ad1c", "nonce": 1223933 }, "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json index 83266f6669cf..f5adb1af65d7 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json @@ -48,7 +48,8 @@ "difficulty": "2", "timestamp": "1709022197", "gasLimit": "30000000", - "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0" + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0", + "baseFeePerGas": "7" }, "input": "0x02f902af823039408459682f008459682f088302b3538080b90254608060405234801561001057600080fd5b50610234806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033c001a0a8cf4729b7e4664687abb3e2559853d7d489eb441519be2a17493061fb4c3a03a04b5a904ba8a6e59c6c40049c4d14a73233aeb8a45b38403199f304630dc0d453", "tracerConfig": { diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index 1913f352ddb7..a74a96f8a489 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -1,9 +1,16 @@ package tracetest import ( + "math/big" "strings" "unicode" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/vm" + // Force-load native and js packages, to trigger registration _ "github.com/ethereum/go-ethereum/eth/tracers/js" _ "github.com/ethereum/go-ethereum/eth/tracers/native" @@ -17,3 +24,32 @@ func camel(str string) string { } return strings.Join(pieces, "") } + +type callContext struct { + Number math.HexOrDecimal64 `json:"number"` + Difficulty *math.HexOrDecimal256 `json:"difficulty"` + Time math.HexOrDecimal64 `json:"timestamp"` + GasLimit math.HexOrDecimal64 `json:"gasLimit"` + Miner common.Address `json:"miner"` + BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` +} + +func (c *callContext) toBlockContext(genesis *core.Genesis) vm.BlockContext { + context := vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + Coinbase: c.Miner, + BlockNumber: new(big.Int).SetUint64(uint64(c.Number)), + Time: uint64(c.Time), + Difficulty: (*big.Int)(c.Difficulty), + GasLimit: uint64(c.GasLimit), + } + if genesis.Config.IsLondon(context.BlockNumber) { + context.BaseFee = (*big.Int)(c.BaseFee) + } + if genesis.ExcessBlobGas != nil && genesis.BlobGasUsed != nil { + excessBlobGas := eip4844.CalcExcessBlobGas(*genesis.ExcessBlobGas, *genesis.BlobGasUsed) + context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) + } + return context +} From fde90443a4af0c8a0c0d7bdaf833a223de560cb3 Mon Sep 17 00:00:00 2001 From: carehabit <165479941+carehabit@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:05:53 +0800 Subject: [PATCH 122/571] log: replace the outdated link (#29412) --- log/format.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log/format.go b/log/format.go index 515ae66e98fc..54c071b908c7 100644 --- a/log/format.go +++ b/log/format.go @@ -340,7 +340,7 @@ func writeTimeTermFormat(buf *bytes.Buffer, t time.Time) { // writePosIntWidth writes non-negative integer i to the buffer, padded on the left // by zeroes to the given width. Use a width of 0 to omit padding. -// Adapted from golang.org/x/exp/slog/internal/buffer/buffer.go +// Adapted from pkg.go.dev/log/slog/internal/buffer func writePosIntWidth(b *bytes.Buffer, i, width int) { // Cheap integer to fixed-width decimal ASCII. // Copied from log/log.go. From 31e63fcf66188504e0b1941059394cf5df49bc17 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Tue, 2 Apr 2024 16:47:15 +0800 Subject: [PATCH 123/571] rlp: using maps.Clone (#29434) --- rlp/typecache.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rlp/typecache.go b/rlp/typecache.go index 3e37c9d2fcc7..eebf4cd61164 100644 --- a/rlp/typecache.go +++ b/rlp/typecache.go @@ -18,6 +18,7 @@ package rlp import ( "fmt" + "maps" "reflect" "sync" "sync/atomic" @@ -90,10 +91,7 @@ func (c *typeCache) generate(typ reflect.Type, tags rlpstruct.Tags) *typeinfo { } // Copy cur to next. - c.next = make(map[typekey]*typeinfo, len(cur)+1) - for k, v := range cur { - c.next[k] = v - } + c.next = maps.Clone(cur) // Generate. info := c.infoWhileGenerating(typ, tags) From e63f992fed51d5a576ea2890cd7eb3000c9e6884 Mon Sep 17 00:00:00 2001 From: Miles Chen Date: Tue, 2 Apr 2024 17:25:19 +0800 Subject: [PATCH 124/571] rpc: fix ipc max path size (#29385) --- rpc/ipc_unix.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rpc/ipc_unix.go b/rpc/ipc_unix.go index 33c1cad5494a..588bf6260566 100644 --- a/rpc/ipc_unix.go +++ b/rpc/ipc_unix.go @@ -25,14 +25,16 @@ import ( "net" "os" "path/filepath" + "syscall" "github.com/ethereum/go-ethereum/log" ) const ( - // On Linux, sun_path is 108 bytes in size - // see http://man7.org/linux/man-pages/man7/unix.7.html - maxPathSize = int(108) + // The limit of unix domain socket path diverse between OS, on Darwin it's 104 bytes + // but on Linux it's 108 byte, so we should depend on syscall.RawSockaddrUnix's + // definition dynamically + maxPathSize = len(syscall.RawSockaddrUnix{}.Path) ) // ipcListen will create a Unix socket on the given endpoint. From 0bd03dbc5597175d79067270c0710604cba489cf Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Tue, 2 Apr 2024 17:25:57 +0800 Subject: [PATCH 125/571] eth/filter: using atomic.Pointer instead of atomic.Value (#29435) --- eth/filters/filter_system.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index c32b837eb477..d8b41a425973 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -95,7 +95,7 @@ func NewFilterSystem(backend Backend, config Config) *FilterSystem { type logCacheElem struct { logs []*types.Log - body atomic.Value + body atomic.Pointer[types.Body] } // cachedLogElem loads block logs from the backend and caches the result. @@ -133,7 +133,7 @@ func (sys *FilterSystem) cachedLogElem(ctx context.Context, blockHash common.Has func (sys *FilterSystem) cachedGetBody(ctx context.Context, elem *logCacheElem, hash common.Hash, number uint64) (*types.Body, error) { if body := elem.body.Load(); body != nil { - return body.(*types.Body), nil + return body, nil } body, err := sys.backend.GetBody(ctx, hash, rpc.BlockNumber(number)) if err != nil { From fe0bf325a68504292f910240f8da6243defffa71 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 2 Apr 2024 20:25:06 +0800 Subject: [PATCH 126/571] cmd/evm: reopen the statedb for dumping (#29437) --- cmd/evm/runner.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 7f6f5f6be0fd..f179e733e657 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -272,8 +272,17 @@ func runCmd(ctx *cli.Context) error { output, leftOverGas, stats, err := timedExec(bench, execFunc) if ctx.Bool(DumpFlag.Name) { - statedb.Commit(genesisConfig.Number, true) - fmt.Println(string(statedb.Dump(nil))) + root, err := statedb.Commit(genesisConfig.Number, true) + if err != nil { + fmt.Printf("Failed to commit changes %v\n", err) + return err + } + dumpdb, err := state.New(root, sdb, nil) + if err != nil { + fmt.Printf("Failed to open statedb %v\n", err) + return err + } + fmt.Println(string(dumpdb.Dump(nil))) } if ctx.Bool(DebugFlag.Name) { From ab6419ccd8b11e041e27f8865f59ab111a2c6161 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Tue, 2 Apr 2024 20:56:12 +0800 Subject: [PATCH 127/571] core/state: use maps.Clone (#29365) core: using maps.Clone --- core/state/access_list.go | 12 ++++-------- core/state/state_object.go | 7 ++----- core/state/statedb.go | 10 ++++------ 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/core/state/access_list.go b/core/state/access_list.go index 419469134595..718bf17cf742 100644 --- a/core/state/access_list.go +++ b/core/state/access_list.go @@ -17,6 +17,8 @@ package state import ( + "maps" + "github.com/ethereum/go-ethereum/common" ) @@ -57,16 +59,10 @@ func newAccessList() *accessList { // Copy creates an independent copy of an accessList. func (a *accessList) Copy() *accessList { cp := newAccessList() - for k, v := range a.addresses { - cp.addresses[k] = v - } + cp.addresses = maps.Clone(a.addresses) cp.slots = make([]map[common.Hash]struct{}, len(a.slots)) for i, slotMap := range a.slots { - newSlotmap := make(map[common.Hash]struct{}, len(slotMap)) - for k := range slotMap { - newSlotmap[k] = struct{}{} - } - cp.slots[i] = newSlotmap + cp.slots[i] = maps.Clone(slotMap) } return cp } diff --git a/core/state/state_object.go b/core/state/state_object.go index 33b593f06992..1aa7946fd0aa 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "io" + "maps" "time" "github.com/ethereum/go-ethereum/common" @@ -47,11 +48,7 @@ func (s Storage) String() (str string) { } func (s Storage) Copy() Storage { - cpy := make(Storage, len(s)) - for key, value := range s { - cpy[key] = value - } - return cpy + return maps.Clone(s) } // stateObject represents an Ethereum account which is being modified. diff --git a/core/state/statedb.go b/core/state/statedb.go index 8cdcbc40c32c..f2c2e7a798ef 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -19,6 +19,7 @@ package state import ( "fmt" + "maps" "math/big" "slices" "sort" @@ -750,9 +751,8 @@ func (s *StateDB) Copy() *StateDB { state.stateObjectsDirty[addr] = struct{}{} } // Deep copy the destruction markers. - for addr, value := range s.stateObjectsDestruct { - state.stateObjectsDestruct[addr] = value - } + state.stateObjectsDestruct = maps.Clone(s.stateObjectsDestruct) + // Deep copy the state changes made in the scope of block // along with their original values. state.accounts = copySet(s.accounts) @@ -770,9 +770,7 @@ func (s *StateDB) Copy() *StateDB { state.logs[hash] = cpy } // Deep copy the preimages occurred in the scope of block - for hash, preimage := range s.preimages { - state.preimages[hash] = preimage - } + state.preimages = maps.Clone(s.preimages) // Do we need to copy the access list and transient storage? // In practice: No. At the start of a transaction, these two lists are empty. // In practice, we only ever copy state _between_ transactions/blocks, never From 12dcc162d05e87b6492c065458f2d7310b3cf791 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Tue, 2 Apr 2024 21:45:25 +0800 Subject: [PATCH 128/571] common/lru: use clear builtin (#29399) --- common/lru/basiclru.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/common/lru/basiclru.go b/common/lru/basiclru.go index c60f59706605..7386c77840a9 100644 --- a/common/lru/basiclru.go +++ b/common/lru/basiclru.go @@ -115,9 +115,7 @@ func (c *BasicLRU[K, V]) Peek(key K) (value V, ok bool) { // Purge empties the cache. func (c *BasicLRU[K, V]) Purge() { c.list.init() - for k := range c.items { - delete(c.items, k) - } + clear(c.items) } // Remove drops an item from the cache. Returns true if the key was present in cache. From a83e57666d5a691883ab2890b63bda1b2c3e1c64 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Wed, 3 Apr 2024 03:17:34 +0800 Subject: [PATCH 129/571] eth/fetcher: using slices.Contains (#29383) --- eth/fetcher/tx_fetcher_test.go | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index 4a62e579b635..3d3ef81edef6 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -20,6 +20,7 @@ import ( "errors" "math/big" "math/rand" + "slices" "testing" "time" @@ -1823,12 +1824,12 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { continue } for _, hash := range hashes { - if !containsHash(request.hashes, hash) { + if !slices.Contains(request.hashes, hash) { t.Errorf("step %d, peer %s: hash %x missing from requests", i, peer, hash) } } for _, hash := range request.hashes { - if !containsHash(hashes, hash) { + if !slices.Contains(hashes, hash) { t.Errorf("step %d, peer %s: hash %x extra in requests", i, peer, hash) } } @@ -1850,7 +1851,7 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { for hash := range fetcher.fetching { var found bool for _, req := range fetcher.requests { - if containsHash(req.hashes, hash) { + if slices.Contains(req.hashes, hash) { found = true break } @@ -1891,12 +1892,12 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { continue } for _, hash := range hashes { - if !containsHash(request.hashes, hash) { + if !slices.Contains(request.hashes, hash) { t.Errorf("step %d, peer %s: hash %x missing from requests", i, peer, hash) } } for _, hash := range request.hashes { - if !containsHash(hashes, hash) { + if !slices.Contains(hashes, hash) { t.Errorf("step %d, peer %s: hash %x extra in requests", i, peer, hash) } } @@ -1909,7 +1910,7 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { for _, ann := range announces { var found bool for _, hs := range step.fetching { - if containsHash(hs, ann.hash) { + if slices.Contains(hs, ann.hash) { found = true break } @@ -1925,7 +1926,7 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { } } for hash := range fetcher.announced { - if !containsHash(queued, hash) { + if !slices.Contains(queued, hash) { t.Errorf("step %d: hash %x extra in announced", i, hash) } } @@ -1984,16 +1985,6 @@ func containsHashInAnnounces(slice []announce, hash common.Hash) bool { return false } -// containsHash returns whether a hash is contained within a hash slice. -func containsHash(slice []common.Hash, hash common.Hash) bool { - for _, have := range slice { - if have == hash { - return true - } - } - return false -} - // Tests that a transaction is forgotten after the timeout. func TestTransactionForgotten(t *testing.T) { fetcher := NewTxFetcher( From dfb3d46098520e90811c6ada3f8e142789c25832 Mon Sep 17 00:00:00 2001 From: Ng Wei Han <47109095+weiihann@users.noreply.github.com> Date: Wed, 3 Apr 2024 03:18:28 +0800 Subject: [PATCH 130/571] p2p: add inbound and outbound peers metric (#29424) --- p2p/metrics.go | 6 +++++- p2p/server.go | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/p2p/metrics.go b/p2p/metrics.go index a6e36b91a8d7..a2ae213b70bc 100644 --- a/p2p/metrics.go +++ b/p2p/metrics.go @@ -37,7 +37,9 @@ const ( ) var ( - activePeerGauge metrics.Gauge = metrics.NilGauge{} + activePeerGauge metrics.Gauge = metrics.NilGauge{} + activeInboundPeerGauge metrics.Gauge = metrics.NilGauge{} + activeOutboundPeerGauge metrics.Gauge = metrics.NilGauge{} ingressTrafficMeter = metrics.NewRegisteredMeter("p2p/ingress", nil) egressTrafficMeter = metrics.NewRegisteredMeter("p2p/egress", nil) @@ -65,6 +67,8 @@ func init() { } activePeerGauge = metrics.NewRegisteredGauge("p2p/peers", nil) + activeInboundPeerGauge = metrics.NewRegisteredGauge("p2p/peers/inbound", nil) + activeOutboundPeerGauge = metrics.NewRegisteredGauge("p2p/peers/outbound", nil) serveMeter = metrics.NewRegisteredMeter("p2p/serves", nil) serveSuccessMeter = metrics.NewRegisteredMeter("p2p/serves/success", nil) dialMeter = metrics.NewRegisteredMeter("p2p/dials", nil) diff --git a/p2p/server.go b/p2p/server.go index a5f3b8d190a2..5b9a4aa71fdc 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -771,8 +771,10 @@ running: if p.Inbound() { inboundCount++ serveSuccessMeter.Mark(1) + activeInboundPeerGauge.Inc(1) } else { dialSuccessMeter.Mark(1) + activeOutboundPeerGauge.Inc(1) } activePeerGauge.Inc(1) } @@ -786,6 +788,9 @@ running: srv.dialsched.peerRemoved(pd.rw) if pd.Inbound() { inboundCount-- + activeInboundPeerGauge.Dec(1) + } else { + activeOutboundPeerGauge.Dec(1) } activePeerGauge.Dec(1) } From 7bb3fb1481acbffd91afe19f802c29b1ae6ea60c Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Wed, 3 Apr 2024 14:08:52 +0800 Subject: [PATCH 131/571] eth: simplify peer counting logic (#29420) --- eth/handler.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/eth/handler.go b/eth/handler.go index 0d27e061c49b..c7c582af407b 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -466,9 +466,7 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { largeTxs int // Number of large transactions to announce only directCount int // Number of transactions sent directly to peers (duplicates included) - directPeers int // Number of peers that were sent transactions directly annCount int // Number of transactions announced across all peers (duplicates included) - annPeers int // Number of peers announced about transactions txset = make(map[*ethPeer][]common.Hash) // Set peer->hash to transfer directly annos = make(map[*ethPeer][]common.Hash) // Set peer->hash to announce @@ -525,17 +523,15 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { } } for peer, hashes := range txset { - directPeers++ directCount += len(hashes) peer.AsyncSendTransactions(hashes) } for peer, hashes := range annos { - annPeers++ annCount += len(hashes) peer.AsyncSendPooledTransactionHashes(hashes) } log.Debug("Distributed transactions", "plaintxs", len(txs)-blobTxs-largeTxs, "blobtxs", blobTxs, "largetxs", largeTxs, - "bcastpeers", directPeers, "bcastcount", directCount, "annpeers", annPeers, "anncount", annCount) + "bcastpeers", len(txset), "bcastcount", directCount, "annpeers", len(annos), "anncount", annCount) } // txBroadcastLoop announces new transactions to connected peers. From 1f8f1377e62d2ca8aba04f0df7772ed665662bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Thu, 4 Apr 2024 11:00:27 +0200 Subject: [PATCH 132/571] build: upgrade -dlgo version to Go 1.22.2 (#29448) --- build/checksums.txt | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index f92f739a2fa4..27577285b821 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,22 +5,22 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.22.1 +# version:golang 1.22.2 # https://go.dev/dl/ -79c9b91d7f109515a25fc3ecdaad125d67e6bdb54f6d4d98580f46799caea321 go1.22.1.src.tar.gz -3bc971772f4712fec0364f4bc3de06af22a00a12daab10b6f717fdcd13156cc0 go1.22.1.darwin-amd64.tar.gz -f6a9cec6b8a002fcc9c0ee24ec04d67f430a52abc3cfd613836986bcc00d8383 go1.22.1.darwin-arm64.tar.gz -99f81c10d5a3f8a886faf8fa86aaa2aaf929fbed54a972ae5eec3c5e0bdb961a go1.22.1.freebsd-386.tar.gz -51c614ddd92ee4a9913a14c39bf80508d9cfba08561f24d2f075fd00f3cfb067 go1.22.1.freebsd-amd64.tar.gz -8484df36d3d40139eaf0fe5e647b006435d826cc12f9ae72973bf7ec265e0ae4 go1.22.1.linux-386.tar.gz -aab8e15785c997ae20f9c88422ee35d962c4562212bb0f879d052a35c8307c7f go1.22.1.linux-amd64.tar.gz -e56685a245b6a0c592fc4a55f0b7803af5b3f827aaa29feab1f40e491acf35b8 go1.22.1.linux-arm64.tar.gz -8cb7a90e48c20daed39a6ac8b8a40760030ba5e93c12274c42191d868687c281 go1.22.1.linux-armv6l.tar.gz -ac775e19d93cc1668999b77cfe8c8964abfbc658718feccfe6e0eb87663cd668 go1.22.1.linux-ppc64le.tar.gz -7bb7dd8e10f95c9a4cc4f6bef44c816a6e7c9e03f56ac6af6efbb082b19b379f go1.22.1.linux-s390x.tar.gz -0c5ebb7eb39b7884ec99f92b425d4c03a96a72443562aafbf6e7d15c42a3108a go1.22.1.windows-386.zip -cf9c66a208a106402a527f5b956269ca506cfe535fc388e828d249ea88ed28ba go1.22.1.windows-amd64.zip -85b8511b298c9f4199ecae26afafcc3d46155bac934d43f2357b9224bcaa310f go1.22.1.windows-arm64.zip +374ea82b289ec738e968267cac59c7d5ff180f9492250254784b2044e90df5a9 go1.22.2.src.tar.gz +33e7f63077b1c5bce4f1ecadd4d990cf229667c40bfb00686990c950911b7ab7 go1.22.2.darwin-amd64.tar.gz +660298be38648723e783ba0398e90431de1cb288c637880cdb124f39bd977f0d go1.22.2.darwin-arm64.tar.gz +efc7162b0cad2f918ac566a923d4701feb29dc9c0ab625157d49b1cbcbba39da go1.22.2.freebsd-386.tar.gz +d753428296e6709527e291fd204700a587ffef2c0a472b21aebea11618245929 go1.22.2.freebsd-amd64.tar.gz +586d9eb7fe0489ab297ad80dd06414997df487c5cf536c490ffeaa8d8f1807a7 go1.22.2.linux-386.tar.gz +5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17 go1.22.2.linux-amd64.tar.gz +36e720b2d564980c162a48c7e97da2e407dfcc4239e1e58d98082dfa2486a0c1 go1.22.2.linux-arm64.tar.gz +9243dfafde06e1efe24d59df6701818e6786b4adfdf1191098050d6d023c5369 go1.22.2.linux-armv6l.tar.gz +251a8886c5113be6490bdbb955ddee98763b49c9b1bf4c8364c02d3b482dab00 go1.22.2.linux-ppc64le.tar.gz +2b39019481c28c560d65e9811a478ae10e3ef765e0f59af362031d386a71bfef go1.22.2.linux-s390x.tar.gz +651753c06df037020ef4d162c5b273452e9ba976ed17ae39e66ef7ee89d8147e go1.22.2.windows-386.zip +8e581cf330f49d3266e936521a2d8263679ef7e2fc2cbbceb85659122d883596 go1.22.2.windows-amd64.zip +ddfca5beb9a0c62254266c3090c2555d899bf3e7aa26243e7de3621108f06875 go1.22.2.windows-arm64.zip # version:golangci 1.55.2 # https://github.com/golangci/golangci-lint/releases/ From 6b39e9236c278d9c4722505bb88a769fd21ca4b8 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Thu, 4 Apr 2024 17:58:44 +0800 Subject: [PATCH 133/571] beacon/engine: using slices.Contains (#29396) --- beacon/engine/types.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 8281fd794c5c..fc77c13af707 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -19,6 +19,7 @@ package engine import ( "fmt" "math/big" + "slices" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -132,12 +133,7 @@ func (b PayloadID) Version() PayloadVersion { // Is returns whether the identifier matches any of provided payload versions. func (b PayloadID) Is(versions ...PayloadVersion) bool { - for _, v := range versions { - if v == b.Version() { - return true - } - } - return false + return slices.Contains(versions, b.Version()) } func (b PayloadID) String() string { From eea0acc54959df779189dbfc972578ae56ac4d33 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Thu, 4 Apr 2024 17:59:54 +0800 Subject: [PATCH 134/571] log: using maps.Clone (#29392) --- log/handler_glog.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/log/handler_glog.go b/log/handler_glog.go index 608d955572ad..625a03640381 100644 --- a/log/handler_glog.go +++ b/log/handler_glog.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "log/slog" + "maps" "regexp" "runtime" "strconv" @@ -145,10 +146,7 @@ func (h *GlogHandler) Enabled(ctx context.Context, lvl slog.Level) bool { func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { h.lock.RLock() - siteCache := make(map[uintptr]slog.Level) - for k, v := range h.siteCache { - siteCache[k] = v - } + siteCache := maps.Clone(h.siteCache) h.lock.RUnlock() patterns := []pattern{} From 2e0c5e05ba355a722eb6eb9bc338de4949eee20d Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Thu, 4 Apr 2024 18:19:48 +0800 Subject: [PATCH 135/571] p2p/dnsdisc: using clear builtin func (#29418) Co-authored-by: Felix Lange --- p2p/dnsdisc/client_test.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/p2p/dnsdisc/client_test.go b/p2p/dnsdisc/client_test.go index 77bfd8c1310b..01912e1eab61 100644 --- a/p2p/dnsdisc/client_test.go +++ b/p2p/dnsdisc/client_test.go @@ -215,7 +215,7 @@ func TestIteratorNodeUpdates(t *testing.T) { // Ensure RandomNode returns the new nodes after the tree is updated. updateSomeNodes(keys, nodes) tree2, _ := makeTestTree("n", nodes, nil) - resolver.clear() + clear(resolver) resolver.add(tree2.ToTXT("n")) t.Log("tree updated") @@ -256,7 +256,7 @@ func TestIteratorRootRecheckOnFail(t *testing.T) { // Ensure RandomNode returns the new nodes after the tree is updated. updateSomeNodes(keys, nodes) tree2, _ := makeTestTree("n", nodes, nil) - resolver.clear() + clear(resolver) resolver.add(tree2.ToTXT("n")) t.Log("tree updated") @@ -447,12 +447,6 @@ func newMapResolver(maps ...map[string]string) mapResolver { return mr } -func (mr mapResolver) clear() { - for k := range mr { - delete(mr, k) - } -} - func (mr mapResolver) add(m map[string]string) { maps.Copy(mr, m) } From 8bd03341689c992d633f3988b3a7fbc15aec75e6 Mon Sep 17 00:00:00 2001 From: guangwu Date: Thu, 4 Apr 2024 18:20:54 +0800 Subject: [PATCH 136/571] crypto/signify: close tmp key file in test (#29444) --- crypto/signify/signify_fuzz.go | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/signify/signify_fuzz.go b/crypto/signify/signify_fuzz.go index 457af044d1b0..239a2134df8f 100644 --- a/crypto/signify/signify_fuzz.go +++ b/crypto/signify/signify_fuzz.go @@ -134,6 +134,7 @@ func createKeyPair() (string, string) { defer os.Remove(tmpKey.Name()) defer os.Remove(tmpKey.Name() + ".pub") defer os.Remove(tmpKey.Name() + ".sec") + defer tmpKey.Close() cmd := exec.Command("signify", "-G", "-n", "-p", tmpKey.Name()+".pub", "-s", tmpKey.Name()+".sec") if output, err := cmd.CombinedOutput(); err != nil { panic(fmt.Sprintf("could not verify the file: %v, output: \n%s", err, output)) From 9dfe728909bc7ff0709c69d3f090804d2516652c Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Thu, 4 Apr 2024 18:24:49 +0800 Subject: [PATCH 137/571] p2p/discover: using slices.Contains (#29395) --- p2p/discover/v4_lookup_test.go | 2 +- p2p/discover/v5_udp.go | 12 ++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/p2p/discover/v4_lookup_test.go b/p2p/discover/v4_lookup_test.go index 691ce4be3f73..5682f262be76 100644 --- a/p2p/discover/v4_lookup_test.go +++ b/p2p/discover/v4_lookup_test.go @@ -285,7 +285,7 @@ func (tn *preminedTestnet) neighborsAtDistances(base *enode.Node, distances []ui for i := range lookupTestnet.dists[d] { n := lookupTestnet.node(d, i) d := enode.LogDist(base.ID(), n.ID()) - if containsUint(uint(d), distances) { + if slices.Contains(distances, uint(d)) { result = append(result, n) if len(result) >= elems { return result diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 71f8d8dd0899..20a8bccd058e 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -25,6 +25,7 @@ import ( "fmt" "io" "net" + "slices" "sync" "time" @@ -437,7 +438,7 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s } if distances != nil { nd := enode.LogDist(c.id, node.ID()) - if !containsUint(uint(nd), distances) { + if !slices.Contains(distances, uint(nd)) { return nil, errors.New("does not match any requested distance") } } @@ -448,15 +449,6 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s return node, nil } -func containsUint(x uint, xs []uint) bool { - for _, v := range xs { - if x == v { - return true - } - } - return false -} - // callToNode sends the given call and sets up a handler for response packets (of message // type responseType). Responses are dispatched to the call's response channel. func (t *UDPv5) callToNode(n *enode.Node, responseType byte, req v5wire.Packet) *callV5 { From 9cb8de87037be7c38343b2f84c534887e7525c5d Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 4 Apr 2024 06:26:10 -0400 Subject: [PATCH 138/571] internal/debug: convert legacy log level value in debug_verbosity (#29356) --- internal/debug/api.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/debug/api.go b/internal/debug/api.go index c262201e3b7f..5e93585bf83d 100644 --- a/internal/debug/api.go +++ b/internal/debug/api.go @@ -24,7 +24,6 @@ import ( "bytes" "errors" "io" - "log/slog" "os" "os/user" "path/filepath" @@ -57,7 +56,7 @@ type HandlerT struct { // Verbosity sets the log verbosity ceiling. The verbosity of individual packages // and source files can be raised using Vmodule. func (*HandlerT) Verbosity(level int) { - glogger.Verbosity(slog.Level(level)) + glogger.Verbosity(log.FromLegacyLevel(level)) } // Vmodule sets the log verbosity pattern. See package log for details on the From a851e39cbecf116ef2dc64f0b37b0300dc762931 Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:50:31 +0200 Subject: [PATCH 139/571] core/types: use new atomic types in caches (#29411) * use generic atomic types in tx caches * use generic atomic types in block caches * eth/catalyst: avoid copying tx in test --------- Co-authored-by: lmittmann Co-authored-by: Felix Lange --- core/types/block.go | 16 ++++++++-------- core/types/transaction.go | 14 +++++++------- core/types/transaction_signing.go | 5 ++--- eth/catalyst/simulated_beacon_test.go | 4 ++-- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index 1a357baa3a41..53054f52d3b9 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -197,8 +197,8 @@ type Block struct { withdrawals Withdrawals // caches - hash atomic.Value - size atomic.Value + hash atomic.Pointer[common.Hash] + size atomic.Uint64 // These fields are used by package eth to track // inter-peer block relay. @@ -406,8 +406,8 @@ func (b *Block) BlobGasUsed() *uint64 { // Size returns the true RLP encoded storage size of the block, either by encoding // and returning it, or returning a previously cached value. func (b *Block) Size() uint64 { - if size := b.size.Load(); size != nil { - return size.(uint64) + if size := b.size.Load(); size > 0 { + return size } c := writeCounter(0) rlp.Encode(&c, b) @@ -486,11 +486,11 @@ func (b *Block) WithWithdrawals(withdrawals []*Withdrawal) *Block { // The hash is computed on the first call and cached thereafter. func (b *Block) Hash() common.Hash { if hash := b.hash.Load(); hash != nil { - return hash.(common.Hash) + return *hash } - v := b.header.Hash() - b.hash.Store(v) - return v + h := b.header.Hash() + b.hash.Store(&h) + return h } type Blocks []*Block diff --git a/core/types/transaction.go b/core/types/transaction.go index 7d2e9d5325a6..d6de9ae73e1b 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -57,9 +57,9 @@ type Transaction struct { time time.Time // Time first seen locally (spam avoidance) // caches - hash atomic.Value - size atomic.Value - from atomic.Value + hash atomic.Pointer[common.Hash] + size atomic.Uint64 + from atomic.Pointer[sigCache] } // NewTx creates a new transaction. @@ -462,7 +462,7 @@ func (tx *Transaction) Time() time.Time { // Hash returns the transaction hash. func (tx *Transaction) Hash() common.Hash { if hash := tx.hash.Load(); hash != nil { - return hash.(common.Hash) + return *hash } var h common.Hash @@ -471,15 +471,15 @@ func (tx *Transaction) Hash() common.Hash { } else { h = prefixedRlpHash(tx.Type(), tx.inner) } - tx.hash.Store(h) + tx.hash.Store(&h) return h } // Size returns the true encoded storage size of the transaction, either by encoding // and returning it, or returning a previously cached value. func (tx *Transaction) Size() uint64 { - if size := tx.size.Load(); size != nil { - return size.(uint64) + if size := tx.size.Load(); size > 0 { + return size } // Cache miss, encode and cache. diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 70dee0776e7b..6e5f6712f81b 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -128,8 +128,7 @@ func MustSignNewTx(prv *ecdsa.PrivateKey, s Signer, txdata TxData) *Transaction // signing method. The cache is invalidated if the cached signer does // not match the signer used in the current call. func Sender(signer Signer, tx *Transaction) (common.Address, error) { - if sc := tx.from.Load(); sc != nil { - sigCache := sc.(sigCache) + if sigCache := tx.from.Load(); sigCache != nil { // If the signer used to derive from in a previous // call is not the same as used current, invalidate // the cache. @@ -142,7 +141,7 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) { if err != nil { return common.Address{}, err } - tx.from.Store(sigCache{signer: signer, from: addr}) + tx.from.Store(&sigCache{signer: signer, from: addr}) return addr, nil } diff --git a/eth/catalyst/simulated_beacon_test.go b/eth/catalyst/simulated_beacon_test.go index df682b49d96e..bb10938c359d 100644 --- a/eth/catalyst/simulated_beacon_test.go +++ b/eth/catalyst/simulated_beacon_test.go @@ -74,7 +74,7 @@ func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis) (*node. // send enough transactions to fill multiple blocks func TestSimulatedBeaconSendWithdrawals(t *testing.T) { var withdrawals []types.Withdrawal - txs := make(map[common.Hash]types.Transaction) + txs := make(map[common.Hash]*types.Transaction) var ( // testKey is a private key to use for funding a tester account. @@ -110,7 +110,7 @@ func TestSimulatedBeaconSendWithdrawals(t *testing.T) { if err != nil { t.Fatalf("error signing transaction, err=%v", err) } - txs[tx.Hash()] = *tx + txs[tx.Hash()] = tx if err := ethService.APIBackend.SendTx(context.Background(), tx); err != nil { t.Fatal("SendTx failed", err) From e3bdd84e9881041e6004ebc3e78c1211d58ebe83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 4 Apr 2024 16:51:10 +0300 Subject: [PATCH 140/571] core/txpool: repair the limbo Billy too on unclean shutdowns (#29451) --- core/txpool/blobpool/limbo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/blobpool/limbo.go b/core/txpool/blobpool/limbo.go index ec754f6894ec..32381a393613 100644 --- a/core/txpool/blobpool/limbo.go +++ b/core/txpool/blobpool/limbo.go @@ -60,7 +60,7 @@ func newLimbo(datadir string) (*limbo, error) { fails = append(fails, id) } } - store, err := billy.Open(billy.Options{Path: datadir}, newSlotter(), index) + store, err := billy.Open(billy.Options{Path: datadir, Repair: true}, newSlotter(), index) if err != nil { return nil, err } From 15ff066a24964ea16742420abecc7e4ae5e9bce0 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Thu, 4 Apr 2024 21:52:38 +0800 Subject: [PATCH 141/571] trie/utils: change Div+Mod to DivMod (#29413) * trie/utils: change Div+Mod to DivMod * trie/utils: gofmt --- trie/utils/verkle.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index ce059edc6438..52e41f524352 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -206,9 +206,8 @@ func CodeSizeKey(address []byte) []byte { func codeChunkIndex(chunk *uint256.Int) (*uint256.Int, byte) { var ( - chunkOffset = new(uint256.Int).Add(codeOffset, chunk) - treeIndex = new(uint256.Int).Div(chunkOffset, verkleNodeWidth) - subIndexMod = new(uint256.Int).Mod(chunkOffset, verkleNodeWidth) + chunkOffset = new(uint256.Int).Add(codeOffset, chunk) + treeIndex, subIndexMod = new(uint256.Int).DivMod(chunkOffset, verkleNodeWidth, new(uint256.Int)) ) var subIndex byte if len(subIndexMod) != 0 { From 35fcf9c52b806d2a7eba0da4f65c97975200a2b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 4 Apr 2024 16:30:27 +0200 Subject: [PATCH 142/571] beacon/types: enforce fork order based on known forks list (#29380) Co-authored-by: Felix Lange --- beacon/types/config.go | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/beacon/types/config.go b/beacon/types/config.go index a52da5212eee..7706e85f6c3f 100644 --- a/beacon/types/config.go +++ b/beacon/types/config.go @@ -19,7 +19,9 @@ package types import ( "crypto/sha256" "fmt" + "math" "os" + "slices" "sort" "strconv" "strings" @@ -27,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/beacon/merkle" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/log" "gopkg.in/yaml.v3" ) @@ -34,6 +37,8 @@ import ( // across signing different data structures. const syncCommitteeDomain = 7 +var knownForks = []string{"GENESIS", "ALTAIR", "BELLATRIX", "CAPELLA", "DENEB"} + // Fork describes a single beacon chain fork and also stores the calculated // signature domain used after this fork. type Fork struct { @@ -46,6 +51,9 @@ type Fork struct { // Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types Version []byte + // index in list of known forks or MaxInt if unknown + knownIndex int + // calculated by computeDomain, based on fork version and genesis validators root domain merkle.Value } @@ -99,9 +107,14 @@ func (f Forks) SigningRoot(header Header) (common.Hash, error) { return signingRoot, nil } -func (f Forks) Len() int { return len(f) } -func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] } -func (f Forks) Less(i, j int) bool { return f[i].Epoch < f[j].Epoch } +func (f Forks) Len() int { return len(f) } +func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] } +func (f Forks) Less(i, j int) bool { + if f[i].Epoch != f[j].Epoch { + return f[i].Epoch < f[j].Epoch + } + return f[i].knownIndex < f[j].knownIndex +} // ChainConfig contains the beacon chain configuration. type ChainConfig struct { @@ -122,16 +135,22 @@ func (c *ChainConfig) ForkAtEpoch(epoch uint64) Fork { // AddFork adds a new item to the list of forks. func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig { + knownIndex := slices.Index(knownForks, name) + if knownIndex == -1 { + knownIndex = math.MaxInt // assume that the unknown fork happens after the known ones + if epoch != math.MaxUint64 { + log.Warn("Unknown fork in config.yaml", "fork name", name, "known forks", knownForks) + } + } fork := &Fork{ - Name: name, - Epoch: epoch, - Version: version, + Name: name, + Epoch: epoch, + Version: version, + knownIndex: knownIndex, } fork.computeDomain(c.GenesisValidatorsRoot) - c.Forks = append(c.Forks, fork) sort.Sort(c.Forks) - return c } @@ -181,6 +200,5 @@ func (c *ChainConfig) LoadForks(path string) error { for name := range versions { return fmt.Errorf("epoch number missing for fork %q in beacon chain config file", name) } - sort.Sort(c.Forks) return nil } From 7ee9a6e89f59cee21b5852f5f6ffa2bcfc05a25f Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 5 Apr 2024 19:29:44 +0200 Subject: [PATCH 143/571] signer: implement blob txs sendtxargs, enable blobtx-signing (#28976) This change makes it possible to sign blob transactions --- accounts/external/backend.go | 15 ++- core/types/transaction.go | 20 ++++ core/types/tx_blob.go | 6 ++ internal/ethapi/api.go | 15 ++- internal/ethapi/api_test.go | 7 +- internal/ethapi/transaction_args.go | 4 +- signer/core/api.go | 5 +- signer/core/apitypes/types.go | 141 +++++++++++++++++++++++++--- signer/core/apitypes/types_test.go | 104 +++++++++++++++++++- signer/core/cliui.go | 8 +- signer/fourbyte/validation.go | 5 + 11 files changed, 302 insertions(+), 28 deletions(-) diff --git a/accounts/external/backend.go b/accounts/external/backend.go index 6f1581f9b806..0b336448fc17 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -205,7 +205,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio to = &t } args := &apitypes.SendTxArgs{ - Data: &data, + Input: &data, Nonce: hexutil.Uint64(tx.Nonce()), Value: hexutil.Big(*tx.Value()), Gas: hexutil.Uint64(tx.Gas()), @@ -215,7 +215,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio switch tx.Type() { case types.LegacyTxType, types.AccessListTxType: args.GasPrice = (*hexutil.Big)(tx.GasPrice()) - case types.DynamicFeeTxType: + case types.DynamicFeeTxType, types.BlobTxType: args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap()) args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap()) default: @@ -235,6 +235,17 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio accessList := tx.AccessList() args.AccessList = &accessList } + if tx.Type() == types.BlobTxType { + args.BlobHashes = tx.BlobHashes() + sidecar := tx.BlobTxSidecar() + if sidecar == nil { + return nil, fmt.Errorf("blobs must be present for signing") + } + args.Blobs = sidecar.Blobs + args.Commitments = sidecar.Commitments + args.Proofs = sidecar.Proofs + } + var res signTransactionResult if err := api.client.Call(&res, "account_signTransaction", args); err != nil { return nil, err diff --git a/core/types/transaction.go b/core/types/transaction.go index d6de9ae73e1b..6a27ecbfecee 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -446,6 +446,26 @@ func (tx *Transaction) WithoutBlobTxSidecar() *Transaction { return cpy } +// WithBlobTxSidecar returns a copy of tx with the blob sidecar added. +func (tx *Transaction) WithBlobTxSidecar(sideCar *BlobTxSidecar) *Transaction { + blobtx, ok := tx.inner.(*BlobTx) + if !ok { + return tx + } + cpy := &Transaction{ + inner: blobtx.withSidecar(sideCar), + time: tx.time, + } + // Note: tx.size cache not carried over because the sidecar is included in size! + if h := tx.hash.Load(); h != nil { + cpy.hash.Store(h) + } + if f := tx.from.Load(); f != nil { + cpy.from.Store(f) + } + return cpy +} + // SetTime sets the decoding time of a transaction. This is used by tests to set // arbitrary times and by persistent transaction pools when loading old txs from // disk. diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index 25a85695efc9..ce1f287caaf8 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -191,6 +191,12 @@ func (tx *BlobTx) withoutSidecar() *BlobTx { return &cpy } +func (tx *BlobTx) withSidecar(sideCar *BlobTxSidecar) *BlobTx { + cpy := *tx + cpy.Sidecar = sideCar + return &cpy +} + func (tx *BlobTx) encode(b *bytes.Buffer) error { if tx.Sidecar == nil { return rlp.Encode(b, tx) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c5a99588e6d2..f682f2765887 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1865,15 +1865,14 @@ type SignTransactionResult struct { // The node needs to have the private key of the account corresponding with // the given from address and it needs to be unlocked. func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { + args.blobSidecarAllowed = true + if args.Gas == nil { return nil, errors.New("gas not specified") } if args.GasPrice == nil && (args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil) { return nil, errors.New("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas") } - if args.IsEIP4844() { - return nil, errBlobTxNotSupported - } if args.Nonce == nil { return nil, errors.New("nonce not specified") } @@ -1889,6 +1888,16 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr if err != nil { return nil, err } + // If the transaction-to-sign was a blob transaction, then the signed one + // no longer retains the blobs, only the blob hashes. In this step, we need + // to put back the blob(s). + if args.IsEIP4844() { + signed = signed.WithBlobTxSidecar(&types.BlobTxSidecar{ + Blobs: args.Blobs, + Commitments: args.Commitments, + Proofs: args.Proofs, + }) + } data, err := signed.MarshalBinary() if err != nil { return nil, err diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index b9ccf2bf7d46..6aad4097fe84 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -1037,11 +1037,8 @@ func TestSignBlobTransaction(t *testing.T) { } _, err = api.SignTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address)) - if err == nil { - t.Fatalf("should fail on blob transaction") - } - if !errors.Is(err, errBlobTxNotSupported) { - t.Errorf("error mismatch. Have: %v, want: %v", err, errBlobTxNotSupported) + if err != nil { + t.Fatalf("should not fail on blob transaction") } } diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index bef6082ead4c..f199f9d91253 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -97,7 +97,7 @@ func (args *TransactionArgs) data() []byte { // setDefaults fills in default values for unspecified tx fields. func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGasEstimation bool) error { - if err := args.setBlobTxSidecar(ctx, b); err != nil { + if err := args.setBlobTxSidecar(ctx); err != nil { return err } if err := args.setFeeDefaults(ctx, b); err != nil { @@ -290,7 +290,7 @@ func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *typ } // setBlobTxSidecar adds the blob tx -func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context, b Backend) error { +func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context) error { // No blobs, we're done. if args.Blobs == nil { return nil diff --git a/signer/core/api.go b/signer/core/api.go index a32f24cb18c4..23ddcd0a2036 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -590,7 +590,10 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args apitypes.SendTxA return nil, err } // Convert fields into a real transaction - var unsignedTx = result.Transaction.ToTransaction() + unsignedTx, err := result.Transaction.ToTransaction() + if err != nil { + return nil, err + } // Get the password for the transaction pw, err := api.lookupOrQueryPassword(acc.Address, "Account password", fmt.Sprintf("Please enter the password for account %s", acc.Address.String())) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 0d66887d5832..2dbe2fc4a682 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -18,6 +18,7 @@ package apitypes import ( "bytes" + "crypto/sha256" "encoding/json" "errors" "fmt" @@ -34,6 +35,8 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/holiman/uint256" ) var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Za-z](\w*)(\[\])?$`) @@ -92,12 +95,21 @@ type SendTxArgs struct { // We accept "data" and "input" for backwards-compatibility reasons. // "input" is the newer name and should be preferred by clients. // Issue detail: https://github.com/ethereum/go-ethereum/issues/15628 - Data *hexutil.Bytes `json:"data"` + Data *hexutil.Bytes `json:"data,omitempty"` Input *hexutil.Bytes `json:"input,omitempty"` // For non-legacy transactions AccessList *types.AccessList `json:"accessList,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"` + + // For BlobTxType + BlobFeeCap *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` + BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"` + + // For BlobTxType transactions with blob sidecar + Blobs []kzg4844.Blob `json:"blobs,omitempty"` + Commitments []kzg4844.Commitment `json:"commitments,omitempty"` + Proofs []kzg4844.Proof `json:"proofs,omitempty"` } func (args SendTxArgs) String() string { @@ -108,24 +120,56 @@ func (args SendTxArgs) String() string { return err.Error() } +// data retrieves the transaction calldata. Input field is preferred. +func (args *SendTxArgs) data() []byte { + if args.Input != nil { + return *args.Input + } + if args.Data != nil { + return *args.Data + } + return nil +} + // ToTransaction converts the arguments to a transaction. -func (args *SendTxArgs) ToTransaction() *types.Transaction { +func (args *SendTxArgs) ToTransaction() (*types.Transaction, error) { // Add the To-field, if specified var to *common.Address if args.To != nil { dstAddr := args.To.Address() to = &dstAddr } - - var input []byte - if args.Input != nil { - input = *args.Input - } else if args.Data != nil { - input = *args.Data + if err := args.validateTxSidecar(); err != nil { + return nil, err } - var data types.TxData switch { + case args.BlobHashes != nil: + al := types.AccessList{} + if args.AccessList != nil { + al = *args.AccessList + } + data = &types.BlobTx{ + To: *to, + ChainID: uint256.MustFromBig((*big.Int)(args.ChainID)), + Nonce: uint64(args.Nonce), + Gas: uint64(args.Gas), + GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)), + GasTipCap: uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)), + Value: uint256.MustFromBig((*big.Int)(&args.Value)), + Data: args.data(), + AccessList: al, + BlobHashes: args.BlobHashes, + BlobFeeCap: uint256.MustFromBig((*big.Int)(args.BlobFeeCap)), + } + if args.Blobs != nil { + data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{ + Blobs: args.Blobs, + Commitments: args.Commitments, + Proofs: args.Proofs, + } + } + case args.MaxFeePerGas != nil: al := types.AccessList{} if args.AccessList != nil { @@ -139,7 +183,7 @@ func (args *SendTxArgs) ToTransaction() *types.Transaction { GasFeeCap: (*big.Int)(args.MaxFeePerGas), GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas), Value: (*big.Int)(&args.Value), - Data: input, + Data: args.data(), AccessList: al, } case args.AccessList != nil: @@ -150,7 +194,7 @@ func (args *SendTxArgs) ToTransaction() *types.Transaction { Gas: uint64(args.Gas), GasPrice: (*big.Int)(args.GasPrice), Value: (*big.Int)(&args.Value), - Data: input, + Data: args.data(), AccessList: *args.AccessList, } default: @@ -160,10 +204,81 @@ func (args *SendTxArgs) ToTransaction() *types.Transaction { Gas: uint64(args.Gas), GasPrice: (*big.Int)(args.GasPrice), Value: (*big.Int)(&args.Value), - Data: input, + Data: args.data(), } } - return types.NewTx(data) + + return types.NewTx(data), nil +} + +// validateTxSidecar validates blob data, if present +func (args *SendTxArgs) validateTxSidecar() error { + // No blobs, we're done. + if args.Blobs == nil { + return nil + } + + n := len(args.Blobs) + // Assume user provides either only blobs (w/o hashes), or + // blobs together with commitments and proofs. + if args.Commitments == nil && args.Proofs != nil { + return errors.New(`blob proofs provided while commitments were not`) + } else if args.Commitments != nil && args.Proofs == nil { + return errors.New(`blob commitments provided while proofs were not`) + } + + // len(blobs) == len(commitments) == len(proofs) == len(hashes) + if args.Commitments != nil && len(args.Commitments) != n { + return fmt.Errorf("number of blobs and commitments mismatch (have=%d, want=%d)", len(args.Commitments), n) + } + if args.Proofs != nil && len(args.Proofs) != n { + return fmt.Errorf("number of blobs and proofs mismatch (have=%d, want=%d)", len(args.Proofs), n) + } + if args.BlobHashes != nil && len(args.BlobHashes) != n { + return fmt.Errorf("number of blobs and hashes mismatch (have=%d, want=%d)", len(args.BlobHashes), n) + } + + if args.Commitments == nil { + // Generate commitment and proof. + commitments := make([]kzg4844.Commitment, n) + proofs := make([]kzg4844.Proof, n) + for i, b := range args.Blobs { + c, err := kzg4844.BlobToCommitment(b) + if err != nil { + return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err) + } + commitments[i] = c + p, err := kzg4844.ComputeBlobProof(b, c) + if err != nil { + return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err) + } + proofs[i] = p + } + args.Commitments = commitments + args.Proofs = proofs + } else { + for i, b := range args.Blobs { + if err := kzg4844.VerifyBlobProof(b, args.Commitments[i], args.Proofs[i]); err != nil { + return fmt.Errorf("failed to verify blob proof: %v", err) + } + } + } + + hashes := make([]common.Hash, n) + hasher := sha256.New() + for i, c := range args.Commitments { + hashes[i] = kzg4844.CalcBlobHashV1(hasher, &c) + } + if args.BlobHashes != nil { + for i, h := range hashes { + if h != args.BlobHashes[i] { + return fmt.Errorf("blob hash verification failed (have=%s, want=%s)", args.BlobHashes[i], h) + } + } + } else { + args.BlobHashes = hashes + } + return nil } type SigFormat struct { diff --git a/signer/core/apitypes/types_test.go b/signer/core/apitypes/types_test.go index b5aa3d1e9347..324ff8a840d3 100644 --- a/signer/core/apitypes/types_test.go +++ b/signer/core/apitypes/types_test.go @@ -16,7 +16,16 @@ package apitypes -import "testing" +import ( + "crypto/sha256" + "encoding/json" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/holiman/uint256" +) func TestIsPrimitive(t *testing.T) { t.Parallel() @@ -39,3 +48,96 @@ func TestIsPrimitive(t *testing.T) { } } } + +func TestTxArgs(t *testing.T) { + for i, tc := range []struct { + data []byte + want common.Hash + wantType uint8 + }{ + { + data: []byte(`{"from":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","accessList":[],"blobVersionedHashes":["0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014"],"chainId":"0x7","gas":"0x124f8","gasPrice":"0x693d4ca8","input":"0x","maxFeePerBlobGas":"0x3b9aca00","maxFeePerGas":"0x6fc23ac00","maxPriorityFeePerGas":"0x3b9aca00","nonce":"0x0","r":"0x2a922afc784d07e98012da29f2f37cae1f73eda78aa8805d3df6ee5dbb41ec1","s":"0x4f1f75ae6bcdf4970b4f305da1a15d8c5ddb21f555444beab77c9af2baab14","to":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","type":"0x1","v":"0x0","value":"0x0","yParity":"0x0"}`), + want: common.HexToHash("0x7d53234acc11ac5b5948632c901a944694e228795782f511887d36fd76ff15c4"), + wantType: types.BlobTxType, + }, + { + // on input, we don't read the type, but infer the type from the arguments present + data: []byte(`{"from":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","accessList":[],"chainId":"0x7","gas":"0x124f8","gasPrice":"0x693d4ca8","input":"0x","maxFeePerBlobGas":"0x3b9aca00","maxFeePerGas":"0x6fc23ac00","maxPriorityFeePerGas":"0x3b9aca00","nonce":"0x0","r":"0x2a922afc784d07e98012da29f2f37cae1f73eda78aa8805d3df6ee5dbb41ec1","s":"0x4f1f75ae6bcdf4970b4f305da1a15d8c5ddb21f555444beab77c9af2baab14","to":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","type":"0x12","v":"0x0","value":"0x0","yParity":"0x0"}`), + want: common.HexToHash("0x7919e2b0b9b543cb87a137b6ff66491ec7ae937cb88d3c29db4d9b28073dce53"), + wantType: types.DynamicFeeTxType, + }, + } { + var txArgs SendTxArgs + if err := json.Unmarshal(tc.data, &txArgs); err != nil { + t.Fatal(err) + } + tx, err := txArgs.ToTransaction() + if err != nil { + t.Fatal(err) + } + if have := tx.Type(); have != tc.wantType { + t.Errorf("test %d, have type %d, want type %d", i, have, tc.wantType) + } + if have := tx.Hash(); have != tc.want { + t.Errorf("test %d: have %v, want %v", i, have, tc.want) + } + d2, err := json.Marshal(txArgs) + if err != nil { + t.Fatal(err) + } + var txArgs2 SendTxArgs + if err := json.Unmarshal(d2, &txArgs2); err != nil { + t.Fatal(err) + } + tx1, _ := txArgs.ToTransaction() + tx2, _ := txArgs2.ToTransaction() + if have, want := tx1.Hash(), tx2.Hash(); have != want { + t.Errorf("test %d: have %v, want %v", i, have, want) + } + } + /* + End to end testing: + + $ go run ./cmd/clef --advanced --suppress-bootwarn + + $ go run ./cmd/geth --nodiscover --maxpeers 0 --signer /home/user/.clef/clef.ipc console + + > tx={"from":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","to":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","gas":"0x124f8","maxFeePerGas":"0x6fc23ac00","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","nonce":"0x0","input":"0x","accessList":[],"maxFeePerBlobGas":"0x3b9aca00","blobVersionedHashes":["0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014"]} + > eth.signTransaction(tx) + */ +} + +func TestBlobTxs(t *testing.T) { + blob := kzg4844.Blob{0x1} + commitment, err := kzg4844.BlobToCommitment(blob) + if err != nil { + t.Fatal(err) + } + proof, err := kzg4844.ComputeBlobProof(blob, commitment) + if err != nil { + t.Fatal(err) + } + + hash := kzg4844.CalcBlobHashV1(sha256.New(), &commitment) + b := &types.BlobTx{ + ChainID: uint256.NewInt(6), + Nonce: 8, + GasTipCap: uint256.NewInt(500), + GasFeeCap: uint256.NewInt(600), + Gas: 21000, + BlobFeeCap: uint256.NewInt(700), + BlobHashes: []common.Hash{hash}, + Value: uint256.NewInt(100), + Sidecar: &types.BlobTxSidecar{ + Blobs: []kzg4844.Blob{blob}, + Commitments: []kzg4844.Commitment{commitment}, + Proofs: []kzg4844.Proof{proof}, + }, + } + tx := types.NewTx(b) + data, err := json.Marshal(tx) + if err != nil { + t.Fatal(err) + } + t.Logf("tx %v", string(data)) +} diff --git a/signer/core/cliui.go b/signer/core/cliui.go index b1bd3206ed3f..e04077865d5e 100644 --- a/signer/core/cliui.go +++ b/signer/core/cliui.go @@ -128,7 +128,7 @@ func (ui *CommandlineUI) ApproveTx(request *SignTxRequest) (SignTxResponse, erro fmt.Printf("chainid: %v\n", chainId) } if list := request.Transaction.AccessList; list != nil { - fmt.Printf("Accesslist\n") + fmt.Printf("Accesslist:\n") for i, el := range *list { fmt.Printf(" %d. %v\n", i, el.Address) for j, slot := range el.StorageKeys { @@ -136,6 +136,12 @@ func (ui *CommandlineUI) ApproveTx(request *SignTxRequest) (SignTxResponse, erro } } } + if len(request.Transaction.BlobHashes) > 0 { + fmt.Printf("Blob hashes:\n") + for _, bh := range request.Transaction.BlobHashes { + fmt.Printf(" %v\n", bh) + } + } if request.Transaction.Data != nil { d := *request.Transaction.Data if len(d) > 0 { diff --git a/signer/fourbyte/validation.go b/signer/fourbyte/validation.go index 58111e8e00c8..0451bda91dc0 100644 --- a/signer/fourbyte/validation.go +++ b/signer/fourbyte/validation.go @@ -36,6 +36,11 @@ func (db *Database) ValidateTransaction(selector *string, tx *apitypes.SendTxArg if tx.Data != nil && tx.Input != nil && !bytes.Equal(*tx.Data, *tx.Input) { return nil, errors.New(`ambiguous request: both "data" and "input" are set and are not identical`) } + // ToTransaction validates, among other things, that blob hashes match with blobs, and also + // populates the hashes if they were previously unset. + if _, err := tx.ToTransaction(); err != nil { + return nil, err + } // Place data on 'data', and nil 'input' var data []byte if tx.Input != nil { From 4458905f261d5d9ba5fda3d664f9bb80346ab404 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 5 Apr 2024 21:01:39 +0200 Subject: [PATCH 144/571] signer/core/apitypes: fix apitypes breakage due to bitrotted PR (#29470) --- signer/core/apitypes/types.go | 6 +++--- signer/core/apitypes/types_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 2dbe2fc4a682..eba9d7768f99 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -243,12 +243,12 @@ func (args *SendTxArgs) validateTxSidecar() error { commitments := make([]kzg4844.Commitment, n) proofs := make([]kzg4844.Proof, n) for i, b := range args.Blobs { - c, err := kzg4844.BlobToCommitment(b) + c, err := kzg4844.BlobToCommitment(&b) if err != nil { return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err) } commitments[i] = c - p, err := kzg4844.ComputeBlobProof(b, c) + p, err := kzg4844.ComputeBlobProof(&b, c) if err != nil { return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err) } @@ -258,7 +258,7 @@ func (args *SendTxArgs) validateTxSidecar() error { args.Proofs = proofs } else { for i, b := range args.Blobs { - if err := kzg4844.VerifyBlobProof(b, args.Commitments[i], args.Proofs[i]); err != nil { + if err := kzg4844.VerifyBlobProof(&b, args.Commitments[i], args.Proofs[i]); err != nil { return fmt.Errorf("failed to verify blob proof: %v", err) } } diff --git a/signer/core/apitypes/types_test.go b/signer/core/apitypes/types_test.go index 324ff8a840d3..7ea32f298c6d 100644 --- a/signer/core/apitypes/types_test.go +++ b/signer/core/apitypes/types_test.go @@ -109,11 +109,11 @@ func TestTxArgs(t *testing.T) { func TestBlobTxs(t *testing.T) { blob := kzg4844.Blob{0x1} - commitment, err := kzg4844.BlobToCommitment(blob) + commitment, err := kzg4844.BlobToCommitment(&blob) if err != nil { t.Fatal(err) } - proof, err := kzg4844.ComputeBlobProof(blob, commitment) + proof, err := kzg4844.ComputeBlobProof(&blob, commitment) if err != nil { t.Fatal(err) } From cc348a601ee816d6c0e2c4d7246c810f3b61e798 Mon Sep 17 00:00:00 2001 From: georgehao Date: Sat, 6 Apr 2024 17:09:30 +0800 Subject: [PATCH 145/571] common/prque: fix godoc comments (#29460) Co-authored-by: Felix Lange --- common/prque/prque.go | 14 +++++++------- common/prque/sstack.go | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/common/prque/prque.go b/common/prque/prque.go index ec8351020a10..cb0d9f35801a 100755 --- a/common/prque/prque.go +++ b/common/prque/prque.go @@ -22,7 +22,7 @@ import ( "container/heap" ) -// Priority queue data structure. +// Prque is a priority queue data structure. type Prque[P cmp.Ordered, V any] struct { cont *sstack[P, V] } @@ -32,7 +32,7 @@ func New[P cmp.Ordered, V any](setIndex SetIndexCallback[V]) *Prque[P, V] { return &Prque[P, V]{newSstack[P, V](setIndex)} } -// Pushes a value with a given priority into the queue, expanding if necessary. +// Push a value with a given priority into the queue, expanding if necessary. func (p *Prque[P, V]) Push(data V, priority P) { heap.Push(p.cont, &item[P, V]{data, priority}) } @@ -43,14 +43,14 @@ func (p *Prque[P, V]) Peek() (V, P) { return item.value, item.priority } -// Pops the value with the greatest priority off the stack and returns it. +// Pop the value with the greatest priority off the stack and returns it. // Currently no shrinking is done. func (p *Prque[P, V]) Pop() (V, P) { item := heap.Pop(p.cont).(*item[P, V]) return item.value, item.priority } -// Pops only the item from the queue, dropping the associated priority value. +// PopItem pops only the item from the queue, dropping the associated priority value. func (p *Prque[P, V]) PopItem() V { return heap.Pop(p.cont).(*item[P, V]).value } @@ -60,17 +60,17 @@ func (p *Prque[P, V]) Remove(i int) V { return heap.Remove(p.cont, i).(*item[P, V]).value } -// Checks whether the priority queue is empty. +// Empty checks whether the priority queue is empty. func (p *Prque[P, V]) Empty() bool { return p.cont.Len() == 0 } -// Returns the number of element in the priority queue. +// Size returns the number of element in the priority queue. func (p *Prque[P, V]) Size() int { return p.cont.Len() } -// Clears the contents of the priority queue. +// Reset clears the contents of the priority queue. func (p *Prque[P, V]) Reset() { *p = *New[P, V](p.cont.setIndex) } diff --git a/common/prque/sstack.go b/common/prque/sstack.go index ee6d7c0c3ac5..6865a51e2366 100755 --- a/common/prque/sstack.go +++ b/common/prque/sstack.go @@ -49,7 +49,7 @@ func newSstack[P cmp.Ordered, V any](setIndex SetIndexCallback[V]) *sstack[P, V] return result } -// Pushes a value onto the stack, expanding it if necessary. Required by +// Push a value onto the stack, expanding it if necessary. Required by // heap.Interface. func (s *sstack[P, V]) Push(data any) { if s.size == s.capacity { @@ -69,7 +69,7 @@ func (s *sstack[P, V]) Push(data any) { s.size++ } -// Pops a value off the stack and returns it. Currently no shrinking is done. +// Pop a value off the stack and returns it. Currently no shrinking is done. // Required by heap.Interface. func (s *sstack[P, V]) Pop() (res any) { s.size-- @@ -85,18 +85,18 @@ func (s *sstack[P, V]) Pop() (res any) { return } -// Returns the length of the stack. Required by sort.Interface. +// Len returns the length of the stack. Required by sort.Interface. func (s *sstack[P, V]) Len() int { return s.size } -// Compares the priority of two elements of the stack (higher is first). +// Less compares the priority of two elements of the stack (higher is first). // Required by sort.Interface. func (s *sstack[P, V]) Less(i, j int) bool { return s.blocks[i/blockSize][i%blockSize].priority > s.blocks[j/blockSize][j%blockSize].priority } -// Swaps two elements in the stack. Required by sort.Interface. +// Swap two elements in the stack. Required by sort.Interface. func (s *sstack[P, V]) Swap(i, j int) { ib, io, jb, jo := i/blockSize, i%blockSize, j/blockSize, j%blockSize a, b := s.blocks[jb][jo], s.blocks[ib][io] @@ -107,7 +107,7 @@ func (s *sstack[P, V]) Swap(i, j int) { s.blocks[ib][io], s.blocks[jb][jo] = a, b } -// Resets the stack, effectively clearing its contents. +// Reset the stack, effectively clearing its contents. func (s *sstack[P, V]) Reset() { *s = *newSstack[P, V](s.setIndex) } From 74995bf8a169bb9d07333e56623ea039b8664710 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Sat, 6 Apr 2024 18:05:06 +0800 Subject: [PATCH 146/571] all: use slices.Contains (#29459) Co-authored-by: Felix Lange --- cmd/devp2p/internal/v5test/discv5tests.go | 3 ++- cmd/devp2p/internal/v5test/framework.go | 9 --------- eth/filters/filter.go | 15 +++------------ node/node.go | 13 ++----------- node/node_test.go | 3 ++- 5 files changed, 9 insertions(+), 34 deletions(-) diff --git a/cmd/devp2p/internal/v5test/discv5tests.go b/cmd/devp2p/internal/v5test/discv5tests.go index 56624a0ca8e9..7dbd3c3be5e5 100644 --- a/cmd/devp2p/internal/v5test/discv5tests.go +++ b/cmd/devp2p/internal/v5test/discv5tests.go @@ -19,6 +19,7 @@ package v5test import ( "bytes" "net" + "slices" "sync" "time" @@ -266,7 +267,7 @@ func (s *Suite) TestFindnodeResults(t *utesting.T) { n := bn.conn.localNode.Node() expect[n.ID()] = n d := uint(enode.LogDist(n.ID(), s.Dest.ID())) - if !containsUint(dists, d) { + if !slices.Contains(dists, d) { dists = append(dists, d) } } diff --git a/cmd/devp2p/internal/v5test/framework.go b/cmd/devp2p/internal/v5test/framework.go index 10856a50bcf9..92a504815009 100644 --- a/cmd/devp2p/internal/v5test/framework.go +++ b/cmd/devp2p/internal/v5test/framework.go @@ -252,12 +252,3 @@ func checkRecords(records []*enr.Record) ([]*enode.Node, error) { } return nodes, nil } - -func containsUint(ints []uint, x uint) bool { - for i := range ints { - if ints[i] == x { - return true - } - } - return false -} diff --git a/eth/filters/filter.go b/eth/filters/filter.go index f2b92d5a99da..2f59026b73ed 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -20,6 +20,7 @@ import ( "context" "errors" "math/big" + "slices" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/bloombits" @@ -347,16 +348,6 @@ func (f *Filter) pendingLogs() []*types.Log { return nil } -// includes returns true if the element is present in the list. -func includes[T comparable](things []T, element T) bool { - for _, thing := range things { - if thing == element { - return true - } - } - return false -} - // filterLogs creates a slice of logs matching the given criteria. func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*types.Log { var check = func(log *types.Log) bool { @@ -366,7 +357,7 @@ func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []comm if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber { return false } - if len(addresses) > 0 && !includes(addresses, log.Address) { + if len(addresses) > 0 && !slices.Contains(addresses, log.Address) { return false } // If the to filtered topics is greater than the amount of topics in logs, skip. @@ -377,7 +368,7 @@ func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []comm if len(sub) == 0 { continue // empty rule set == wildcard } - if !includes(sub, log.Topics[i]) { + if !slices.Contains(sub, log.Topics[i]) { return false } } diff --git a/node/node.go b/node/node.go index c5cb552d2737..6cbae68591eb 100644 --- a/node/node.go +++ b/node/node.go @@ -25,6 +25,7 @@ import ( "os" "path/filepath" "reflect" + "slices" "strings" "sync" @@ -278,16 +279,6 @@ func (n *Node) openEndpoints() error { return err } -// containsLifecycle checks if 'lfs' contains 'l'. -func containsLifecycle(lfs []Lifecycle, l Lifecycle) bool { - for _, obj := range lfs { - if obj == l { - return true - } - } - return false -} - // stopServices terminates running services, RPC and p2p networking. // It is the inverse of Start. func (n *Node) stopServices(running []Lifecycle) error { @@ -571,7 +562,7 @@ func (n *Node) RegisterLifecycle(lifecycle Lifecycle) { if n.state != initializingState { panic("can't register lifecycle on running/stopped node") } - if containsLifecycle(n.lifecycles, lifecycle) { + if slices.Contains(n.lifecycles, lifecycle) { panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle)) } n.lifecycles = append(n.lifecycles, lifecycle) diff --git a/node/node_test.go b/node/node_test.go index d1d1e5dfe8fa..82e814cadade 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -23,6 +23,7 @@ import ( "net" "net/http" "reflect" + "slices" "strings" "testing" @@ -116,7 +117,7 @@ func TestLifecycleRegistry_Successful(t *testing.T) { noop := NewNoop() stack.RegisterLifecycle(noop) - if !containsLifecycle(stack.lifecycles, noop) { + if !slices.Contains(stack.lifecycles, Lifecycle(noop)) { t.Fatalf("lifecycle was not properly registered on the node, %v", err) } } From ccb76c01d7b1ce4d77d2bb309419cc78f42659ca Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Sat, 6 Apr 2024 18:16:25 +0800 Subject: [PATCH 147/571] eth/tracers: use slices.Contains (#29461) --- eth/tracers/js/goja.go | 9 ++------- eth/tracers/native/call_flat.go | 8 ++------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 82666155ec76..5290d4f70995 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "math/big" + "slices" "github.com/dop251/goja" "github.com/ethereum/go-ethereum/core/tracing" @@ -529,13 +530,7 @@ func (t *jsTracer) setBuiltinFunctions() { vm.Interrupt(err) return false } - addr := common.BytesToAddress(a) - for _, p := range t.activePrecompiles { - if p == addr { - return true - } - } - return false + return slices.Contains(t.activePrecompiles, common.BytesToAddress(a)) }) vm.Set("slice", func(slice goja.Value, start, end int64) goja.Value { b, err := t.fromBuf(vm, slice, false) diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 37be64310c47..f8d38ddd2d5b 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "math/big" + "slices" "strings" "github.com/ethereum/go-ethereum/common" @@ -228,12 +229,7 @@ func (t *flatCallTracer) Stop(err error) { // isPrecompiled returns whether the addr is a precompile. func (t *flatCallTracer) isPrecompiled(addr common.Address) bool { - for _, p := range t.activePrecompiles { - if p == addr { - return true - } - } - return false + return slices.Contains(t.activePrecompiles, addr) } func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx *tracers.Context) (output []flatCallFrame, err error) { From 8876868bb831cef307d7e72c6848bd0943ba1e24 Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Sat, 6 Apr 2024 03:17:41 -0700 Subject: [PATCH 148/571] log: default JSON log handler should log all verbosity levels (#29471) Co-authored-by: lightclient --- internal/debug/flags.go | 4 ++-- log/handler.go | 7 +++++++ log/logger_test.go | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 19222c8325f9..361dc6fcca6a 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -231,9 +231,9 @@ func Setup(ctx *cli.Context) error { case ctx.Bool(logjsonFlag.Name): // Retain backwards compatibility with `--log.json` flag if `--log.format` not set defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead") - handler = log.JSONHandler(output) + handler = log.JSONHandlerWithLevel(output, log.LevelInfo) case logFmtFlag == "json": - handler = log.JSONHandler(output) + handler = log.JSONHandlerWithLevel(output, log.LevelInfo) case logFmtFlag == "logfmt": handler = log.LogfmtHandler(output) case logFmtFlag == "", logFmtFlag == "terminal": diff --git a/log/handler.go b/log/handler.go index 248e3813fc2c..290e38150956 100644 --- a/log/handler.go +++ b/log/handler.go @@ -115,8 +115,15 @@ func (l *leveler) Level() slog.Level { // JSONHandler returns a handler which prints records in JSON format. func JSONHandler(wr io.Writer) slog.Handler { + return JSONHandlerWithLevel(wr, levelMaxVerbosity) +} + +// JSONHandler returns a handler which prints records in JSON format that are less than or equal to +// the specified verbosity level. +func JSONHandlerWithLevel(wr io.Writer, level slog.Level) slog.Handler { return slog.NewJSONHandler(wr, &slog.HandlerOptions{ ReplaceAttr: builtinReplaceJSON, + Level: &leveler{level}, }) } diff --git a/log/logger_test.go b/log/logger_test.go index d23e16e57241..2ea08585475d 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -50,6 +50,25 @@ func TestTerminalHandlerWithAttrs(t *testing.T) { } } +// Make sure the default json handler outputs debug log lines +func TestJSONHandler(t *testing.T) { + out := new(bytes.Buffer) + handler := JSONHandler(out) + logger := slog.New(handler) + logger.Debug("hi there") + if len(out.String()) == 0 { + t.Error("expected non-empty debug log output from default JSON Handler") + } + + out.Reset() + handler = JSONHandlerWithLevel(out, slog.LevelInfo) + logger = slog.New(handler) + logger.Debug("hi there") + if len(out.String()) != 0 { + t.Errorf("expected empty debug log output, but got: %v", out.String()) + } +} + func BenchmarkTraceLogging(b *testing.B) { SetDefault(NewLogger(NewTerminalHandler(os.Stderr, true))) b.ResetTimer() From 7aafad2233b676b7beaf56e89f82360704d669d0 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Sat, 6 Apr 2024 12:22:55 +0200 Subject: [PATCH 149/571] core/vm: better error-info for vm errors (#29354) --- core/vm/errors.go | 1 + core/vm/gas_table.go | 11 +++++++++-- core/vm/gas_table_test.go | 3 ++- core/vm/interpreter.go | 7 ++++++- .../call_tracer_flat/callcode_precompiled_throw.json | 2 +- .../call_tracer_flat/nested_create_action_gas.json | 2 +- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/core/vm/errors.go b/core/vm/errors.go index ba3261c797fc..e5efc952d440 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -31,6 +31,7 @@ var ( ErrContractAddressCollision = errors.New("contract address collision") ErrExecutionReverted = errors.New("execution reverted") ErrMaxCodeSizeExceeded = errors.New("max code size exceeded") + ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded") ErrInvalidJump = errors.New("invalid jump destination") ErrWriteProtection = errors.New("write protection") ErrReturnDataOutOfBounds = errors.New("return data out of bounds") diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 4b141d8f9a5d..fd5fa14cf5d7 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -18,6 +18,7 @@ package vm import ( "errors" + "fmt" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -310,9 +311,12 @@ func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m return 0, err } size, overflow := stack.Back(2).Uint64WithOverflow() - if overflow || size > params.MaxInitCodeSize { + if overflow { return 0, ErrGasUintOverflow } + if size > params.MaxInitCodeSize { + return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size) + } // Since size <= params.MaxInitCodeSize, these multiplication cannot overflow moreGas := params.InitCodeWordGas * ((size + 31) / 32) if gas, overflow = math.SafeAdd(gas, moreGas); overflow { @@ -326,9 +330,12 @@ func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, return 0, err } size, overflow := stack.Back(2).Uint64WithOverflow() - if overflow || size > params.MaxInitCodeSize { + if overflow { return 0, ErrGasUintOverflow } + if size > params.MaxInitCodeSize { + return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size) + } // Since size <= params.MaxInitCodeSize, these multiplication cannot overflow moreGas := (params.InitCodeWordGas + params.Keccak256WordGas) * ((size + 31) / 32) if gas, overflow = math.SafeAdd(gas, moreGas); overflow { diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 4a2545b6edfa..02fc94840d60 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -18,6 +18,7 @@ package vm import ( "bytes" + "errors" "math" "math/big" "sort" @@ -98,7 +99,7 @@ func TestEIP2200(t *testing.T) { vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) _, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(uint256.Int)) - if err != tt.failure { + if !errors.Is(err, tt.failure) { t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) } if used := tt.gaspool - gas; used != tt.used { diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index edf21b17d710..406927e32158 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -17,6 +17,8 @@ package vm import ( + "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/tracing" @@ -255,7 +257,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( var dynamicCost uint64 dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) cost += dynamicCost // for tracing - if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, tracing.GasChangeIgnored) { + if err != nil { + return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) + } + if !contract.UseGas(dynamicCost, in.evm.Config.Tracer, tracing.GasChangeIgnored) { return nil, ErrOutOfGas } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json index 3c1e370f91c7..5e2726155445 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json @@ -57,7 +57,7 @@ "gas": "0x1a034", "init": "0x36600060003760406103e8366000600060095af26001556103e8516002556104085160035500" }, - "error": "out of gas", + "error": "out of gas: not enough gas for reentrancy sentry", "traceAddress": [], "subtraces": 1, "transactionPosition": 117, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json index 132b84df3618..a00ea7a93b89 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json @@ -57,7 +57,7 @@ "gas": "0x19ee4", "init": "0x5a600055600060006000f0505a60015500" }, - "error": "out of gas", + "error": "out of gas: not enough gas for reentrancy sentry", "traceAddress": [], "subtraces": 1, "transactionPosition": 63, From 0dc09da7db47de4a9a9eb6ea335e2e367fae6015 Mon Sep 17 00:00:00 2001 From: imalasong <55082705+imalasong@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:29:49 +0800 Subject: [PATCH 150/571] all: replace path.Join with filepath.Join (#29479) * core/rawdb: replace file.Join with filepath.Join Signed-off-by: xiaochangbai <704566072@qq.com> * internal/build: replace file.Join with filepath.Join Signed-off-by: xiaochangbai <704566072@qq.com> --------- Signed-off-by: xiaochangbai <704566072@qq.com> --- core/blockchain_sethead_test.go | 4 ++-- core/rawdb/database.go | 3 +-- core/rawdb/freezer_test.go | 13 ++++++------- internal/build/util.go | 2 +- node/node_auth_test.go | 4 ++-- signer/core/signed_data_test.go | 3 ++- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index b96ee12c9952..8b77f9f8b20c 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -22,7 +22,7 @@ package core import ( "fmt" "math/big" - "path" + "path/filepath" "strings" "testing" "time" @@ -1966,7 +1966,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme // Create a temporary persistent database datadir := t.TempDir() - ancient := path.Join(datadir, "ancient") + ancient := filepath.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 9cab30bfcd1f..7b2c0415cbbf 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "os" - "path" "path/filepath" "strings" "time" @@ -172,7 +171,7 @@ func resolveChainFreezerDir(ancient string) string { // sub folder, if not then two possibilities: // - chain freezer is not initialized // - chain freezer exists in legacy location (root ancient folder) - freezer := path.Join(ancient, ChainFreezerName) + freezer := filepath.Join(ancient, ChainFreezerName) if !common.FileExist(freezer) { if !common.FileExist(ancient) { // The entire ancient store is not initialized, still use the sub diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index b92cd7b734f9..93bc2c225442 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -23,7 +23,6 @@ import ( "math/big" "math/rand" "os" - "path" "path/filepath" "sync" "testing" @@ -398,11 +397,11 @@ func TestRenameWindows(t *testing.T) { if err != nil { t.Fatal(err) } - f2, err := os.Create(path.Join(dir1, fname2)) + f2, err := os.Create(filepath.Join(dir1, fname2)) if err != nil { t.Fatal(err) } - f3, err := os.Create(path.Join(dir2, fname2)) + f3, err := os.Create(filepath.Join(dir2, fname2)) if err != nil { t.Fatal(err) } @@ -424,15 +423,15 @@ func TestRenameWindows(t *testing.T) { if err := f3.Close(); err != nil { t.Fatal(err) } - if err := os.Rename(f.Name(), path.Join(dir2, fname)); err != nil { + if err := os.Rename(f.Name(), filepath.Join(dir2, fname)); err != nil { t.Fatal(err) } - if err := os.Rename(f2.Name(), path.Join(dir2, fname2)); err != nil { + if err := os.Rename(f2.Name(), filepath.Join(dir2, fname2)); err != nil { t.Fatal(err) } // Check file contents - f, err = os.Open(path.Join(dir2, fname)) + f, err = os.Open(filepath.Join(dir2, fname)) if err != nil { t.Fatal(err) } @@ -446,7 +445,7 @@ func TestRenameWindows(t *testing.T) { t.Errorf("unexpected file contents. Got %v\n", buf) } - f, err = os.Open(path.Join(dir2, fname2)) + f, err = os.Open(filepath.Join(dir2, fname2)) if err != nil { t.Fatal(err) } diff --git a/internal/build/util.go b/internal/build/util.go index b41014a16f0d..e57a4e3a9a04 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -175,7 +175,7 @@ func UploadSFTP(identityFile, host, dir string, files []string) error { } in := io.MultiWriter(stdin, os.Stdout) for _, f := range files { - fmt.Fprintln(in, "put", f, path.Join(dir, filepath.Base(f))) + fmt.Fprintln(in, "put", f, filepath.Join(dir, filepath.Base(f))) } fmt.Fprintln(in, "exit") // Some issue with the PPA sftp server makes it so the server does not diff --git a/node/node_auth_test.go b/node/node_auth_test.go index 597cd8531f79..900f53440cb9 100644 --- a/node/node_auth_test.go +++ b/node/node_auth_test.go @@ -22,7 +22,7 @@ import ( "fmt" "net/http" "os" - "path" + "path/filepath" "testing" "time" @@ -98,7 +98,7 @@ func TestAuthEndpoints(t *testing.T) { t.Fatalf("failed to create jwt secret: %v", err) } // Geth must read it from a file, and does not support in-memory JWT secrets, so we create a temporary file. - jwtPath := path.Join(t.TempDir(), "jwt_secret") + jwtPath := filepath.Join(t.TempDir(), "jwt_secret") if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil { t.Fatalf("failed to prepare jwt secret file: %v", err) } diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index bb21525507cb..a4fe7a22dd0f 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -24,6 +24,7 @@ import ( "math/big" "os" "path" + "path/filepath" "strings" "testing" @@ -411,7 +412,7 @@ func TestJsonFiles(t *testing.T) { // crashes or hangs. func TestFuzzerFiles(t *testing.T) { t.Parallel() - corpusdir := path.Join("testdata", "fuzzing") + corpusdir := filepath.Join("testdata", "fuzzing") testfiles, err := os.ReadDir(corpusdir) if err != nil { t.Fatalf("failed reading files: %v", err) From cfc7d06cc91122f44d09592ddc616fb189bc4ca4 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Mon, 8 Apr 2024 18:58:37 +0800 Subject: [PATCH 151/571] signer/core/apitypes: use slices.Contains (#29474) --- log/handler.go | 2 +- signer/core/apitypes/types.go | 13 +++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/log/handler.go b/log/handler.go index 290e38150956..c604a6230188 100644 --- a/log/handler.go +++ b/log/handler.go @@ -118,7 +118,7 @@ func JSONHandler(wr io.Writer) slog.Handler { return JSONHandlerWithLevel(wr, levelMaxVerbosity) } -// JSONHandler returns a handler which prints records in JSON format that are less than or equal to +// JSONHandlerWithLevel returns a handler which prints records in JSON format that are less than or equal to // the specified verbosity level. func JSONHandlerWithLevel(wr io.Writer, level slog.Level) slog.Handler { return slog.NewJSONHandler(wr, &slog.HandlerOptions{ diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index eba9d7768f99..9113c091c5c7 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -25,6 +25,7 @@ import ( "math/big" "reflect" "regexp" + "slices" "sort" "strconv" "strings" @@ -386,16 +387,8 @@ func (typedData *TypedData) HashStruct(primaryType string, data TypedDataMessage // Dependencies returns an array of custom types ordered by their hierarchical reference tree func (typedData *TypedData) Dependencies(primaryType string, found []string) []string { primaryType = strings.TrimSuffix(primaryType, "[]") - includes := func(arr []string, str string) bool { - for _, obj := range arr { - if obj == str { - return true - } - } - return false - } - if includes(found, primaryType) { + if slices.Contains(found, primaryType) { return found } if typedData.Types[primaryType] == nil { @@ -404,7 +397,7 @@ func (typedData *TypedData) Dependencies(primaryType string, found []string) []s found = append(found, primaryType) for _, field := range typedData.Types[primaryType] { for _, dep := range typedData.Dependencies(field.Type, found) { - if !includes(found, dep) { + if !slices.Contains(found, dep) { found = append(found, dep) } } From ed4bc7f27ba071403484240fa71b4878c4ca9756 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Mon, 8 Apr 2024 18:59:17 +0800 Subject: [PATCH 152/571] all: replace fmt.Errorf() with errors.New() if no param required (#29472) --- accounts/external/backend.go | 2 +- cmd/devp2p/internal/ethtest/transaction.go | 2 +- core/blockchain.go | 2 +- internal/era/iterator.go | 3 +-- miner/worker.go | 4 ++-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/accounts/external/backend.go b/accounts/external/backend.go index 0b336448fc17..62322753daa8 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -239,7 +239,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio args.BlobHashes = tx.BlobHashes() sidecar := tx.BlobTxSidecar() if sidecar == nil { - return nil, fmt.Errorf("blobs must be present for signing") + return nil, errors.New("blobs must be present for signing") } args.Blobs = sidecar.Blobs args.Commitments = sidecar.Commitments diff --git a/cmd/devp2p/internal/ethtest/transaction.go b/cmd/devp2p/internal/ethtest/transaction.go index 80b5d80745ec..cbbbbce8d94b 100644 --- a/cmd/devp2p/internal/ethtest/transaction.go +++ b/cmd/devp2p/internal/ethtest/transaction.go @@ -102,7 +102,7 @@ func (s *Suite) sendTxs(t *utesting.T, txs []*types.Transaction) error { } } - return fmt.Errorf("timed out waiting for txs") + return errors.New("timed out waiting for txs") } func (s *Suite) sendInvalidTxs(t *utesting.T, txs []*types.Transaction) error { diff --git a/core/blockchain.go b/core/blockchain.go index 680875373454..fa112c25039e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -439,7 +439,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } if alloc == nil { - return nil, fmt.Errorf("live blockchain tracer requires genesis alloc to be set") + return nil, errors.New("live blockchain tracer requires genesis alloc to be set") } bc.logger.OnGenesisBlock(bc.genesisBlock, alloc) diff --git a/internal/era/iterator.go b/internal/era/iterator.go index d90e9586a4e6..cc4f27c20190 100644 --- a/internal/era/iterator.go +++ b/internal/era/iterator.go @@ -18,7 +18,6 @@ package era import ( "errors" - "fmt" "io" "math/big" @@ -80,7 +79,7 @@ func (it *Iterator) Block() (*types.Block, error) { // Receipts returns the receipts for the iterator's current position. func (it *Iterator) Receipts() (types.Receipts, error) { if it.inner.Receipts == nil { - return nil, fmt.Errorf("receipts must be non-nil") + return nil, errors.New("receipts must be non-nil") } var receipts types.Receipts err := rlp.Decode(it.inner.Receipts, &receipts) diff --git a/miner/worker.go b/miner/worker.go index 9f8d9f663f86..4924952478e5 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -75,7 +75,7 @@ type newPayloadResult struct { receipts []*types.Receipt // Receipts collected during construction } -// generateParams wraps various of settings for generating sealing task. +// generateParams wraps various settings for generating sealing task. type generateParams struct { timestamp uint64 // The timestamp for sealing task forceTime bool // Flag whether the given timestamp is immutable or not @@ -131,7 +131,7 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) if genParams.parentHash != (common.Hash{}) { block := miner.chain.GetBlockByHash(genParams.parentHash) if block == nil { - return nil, fmt.Errorf("missing parent") + return nil, errors.New("missing parent") } parent = block.Header() } From c3465cb5ba94e8ee4153319416db9484406084ee Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Mon, 8 Apr 2024 13:01:22 +0200 Subject: [PATCH 153/571] core: fix dev mode genesis difficulty (#29469) The dev mode is nowadays in Merge-mode from genesis, hence the difficulty of the first block should be zero. --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index ee0e322f8013..f05e84199ae4 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -582,7 +582,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { Config: &config, GasLimit: gasLimit, BaseFee: big.NewInt(params.InitialBaseFee), - Difficulty: big.NewInt(1), + Difficulty: big.NewInt(0), Alloc: map[common.Address]types.Account{ common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256 From 3c75c64e6bbf64f842c6f725a595713262c2f8fe Mon Sep 17 00:00:00 2001 From: seayyyy <163325936+seay404@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:02:56 +0800 Subject: [PATCH 154/571] core: fix typo (#29438) --- core/block_validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/block_validator.go b/core/block_validator.go index f3d65cea25ff..3d49f4e6a3df 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -132,7 +132,7 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD if rbloom != header.Bloom { return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) } - // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) + // The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) if receiptSha != header.ReceiptHash { return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) From c170cc0ab0a1f60adcde80d0af8e3050ee19da93 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 8 Apr 2024 21:48:37 +0800 Subject: [PATCH 155/571] core/vm: reject contract creation if the storage is non-empty (#28912) This change implements EIP-7610, which rejects the contract deployment if the destination has non-empty storage. --- core/vm/evm.go | 12 +++++++++--- core/vm/interface.go | 1 + tests/block_test.go | 8 ++++++++ tests/state_test.go | 13 +++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 25b5bc84e8bd..36bbf0d3da67 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -439,13 +439,19 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.chainRules.IsBerlin { evm.StateDB.AddAddressToAccessList(address) } - // Ensure there's no existing contract already at the designated address + // Ensure there's no existing contract already at the designated address. + // Account is regarded as existent if any of these three conditions is met: + // - the nonce is nonzero + // - the code is non-empty + // - the storage is non-empty contractHash := evm.StateDB.GetCodeHash(address) - if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) { + storageRoot := evm.StateDB.GetStorageRoot(address) + if evm.StateDB.GetNonce(address) != 0 || + (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code + (storageRoot != (common.Hash{}) && storageRoot != types.EmptyRootHash) { // non-empty storage if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } - return nil, common.Address{}, 0, ErrContractAddressCollision } // Create a new account on the state diff --git a/core/vm/interface.go b/core/vm/interface.go index d7028cc7c7e3..30742e96de2b 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -49,6 +49,7 @@ type StateDB interface { GetCommittedState(common.Address, common.Hash) common.Hash GetState(common.Address, common.Hash) common.Hash SetState(common.Address, common.Hash, common.Hash) + GetStorageRoot(addr common.Address) common.Hash GetTransientState(addr common.Address, key common.Hash) common.Hash SetTransientState(addr common.Address, key, value common.Hash) diff --git a/tests/block_test.go b/tests/block_test.go index 1ba84f5f24b6..43e3d99b3e8c 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -64,6 +64,14 @@ func TestExecutionSpecBlocktests(t *testing.T) { } bt := new(testMatcher) + // These tests fail as of https://github.com/ethereum/go-ethereum/pull/28666, since we + // no longer delete "leftover storage" when deploying a contract. + bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/self_destructing_initcode_create_tx.json`) + bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/self_destructing_initcode.json`) + bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/recreate_self_destructed_contract_different_txs.json`) + bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/delegatecall_from_new_contract_to_pre_existing_contract.json`) + bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/create_selfdestruct_same_tx.json`) + bt.walk(t, executionSpecBlockchainTestDir, func(t *testing.T, name string, test *BlockTest) { execBlockTest(t, bt, test) }) diff --git a/tests/state_test.go b/tests/state_test.go index 6ec5c9d857bc..6f53b88722d6 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -54,9 +54,22 @@ func initMatcher(st *testMatcher) { // Uses 1GB RAM per tested fork st.skipLoad(`^stStaticCall/static_Call1MB`) + // These tests fail as of https://github.com/ethereum/go-ethereum/pull/28666, since we + // no longer delete "leftover storage" when deploying a contract. + st.skipLoad(`^stSStoreTest/InitCollision\.json`) + st.skipLoad(`^stRevertTest/RevertInCreateInInit\.json`) + st.skipLoad(`^stExtCodeHash/dynamicAccountOverwriteEmpty\.json`) + st.skipLoad(`^stCreate2/create2collisionStorage\.json`) + st.skipLoad(`^stCreate2/RevertInCreateInInitCreate2\.json`) + // Broken tests: // EOF is not part of cancun st.skipLoad(`^stEOF/`) + + // The tests under Pyspecs are the ones that are published as execution-spec tests. + // We run these tests separately, no need to _also_ run them as part of the + // reference tests. + st.skipLoad(`^Pyspecs/`) } func TestState(t *testing.T) { From 70bf94c34e4a6320c865a90cbfeec38a0aef7378 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Tue, 9 Apr 2024 14:22:53 +0800 Subject: [PATCH 156/571] internal, signer/core: replace path.Join with filepath.Join (#29489) --- internal/build/util.go | 3 +-- internal/jsre/jsre_test.go | 4 ++-- signer/core/signed_data_test.go | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/internal/build/util.go b/internal/build/util.go index e57a4e3a9a04..aee8bf0fc8af 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -27,7 +27,6 @@ import ( "log" "os" "os/exec" - "path" "path/filepath" "strconv" "strings" @@ -112,7 +111,7 @@ func RunGit(args ...string) string { // readGitFile returns content of file in .git directory. func readGitFile(file string) string { - content, err := os.ReadFile(path.Join(".git", file)) + content, err := os.ReadFile(filepath.Join(".git", file)) if err != nil { return "" } diff --git a/internal/jsre/jsre_test.go b/internal/jsre/jsre_test.go index bb4ff5fa4f0a..18ef39e2f470 100644 --- a/internal/jsre/jsre_test.go +++ b/internal/jsre/jsre_test.go @@ -18,7 +18,7 @@ package jsre import ( "os" - "path" + "path/filepath" "reflect" "testing" "time" @@ -42,7 +42,7 @@ func (no *testNativeObjectBinding) TestMethod(call goja.FunctionCall) goja.Value func newWithTestJS(t *testing.T, testjs string) *JSRE { dir := t.TempDir() if testjs != "" { - if err := os.WriteFile(path.Join(dir, "test.js"), []byte(testjs), os.ModePerm); err != nil { + if err := os.WriteFile(filepath.Join(dir, "test.js"), []byte(testjs), os.ModePerm); err != nil { t.Fatal("cannot create test.js:", err) } } diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index a4fe7a22dd0f..d0637010baa3 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -23,7 +23,6 @@ import ( "fmt" "math/big" "os" - "path" "path/filepath" "strings" "testing" @@ -386,7 +385,7 @@ func TestJsonFiles(t *testing.T) { continue } expectedFailure := strings.HasPrefix(fInfo.Name(), "expfail") - data, err := os.ReadFile(path.Join("testdata", fInfo.Name())) + data, err := os.ReadFile(filepath.Join("testdata", fInfo.Name())) if err != nil { t.Errorf("Failed to read file %v: %v", fInfo.Name(), err) continue @@ -419,7 +418,7 @@ func TestFuzzerFiles(t *testing.T) { } verbose := false for i, fInfo := range testfiles { - data, err := os.ReadFile(path.Join(corpusdir, fInfo.Name())) + data, err := os.ReadFile(filepath.Join(corpusdir, fInfo.Name())) if err != nil { t.Errorf("Failed to read file %v: %v", fInfo.Name(), err) continue From f447de936c31e6a64470f3c102da85f245fe9640 Mon Sep 17 00:00:00 2001 From: Mohanson Date: Tue, 9 Apr 2024 14:27:13 +0800 Subject: [PATCH 157/571] rlp: replace reflect.PtrTo with reflect.PointerTo (#29488) reflect.PtrTo has been deprecated and superseded by reflect.PointerTo --- rlp/decode.go | 10 +++++----- rlp/encode.go | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rlp/decode.go b/rlp/decode.go index 47801b209085..0fbca243ee0d 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -158,17 +158,17 @@ func makeDecoder(typ reflect.Type, tags rlpstruct.Tags) (dec decoder, err error) switch { case typ == rawValueType: return decodeRawValue, nil - case typ.AssignableTo(reflect.PtrTo(bigInt)): + case typ.AssignableTo(reflect.PointerTo(bigInt)): return decodeBigInt, nil case typ.AssignableTo(bigInt): return decodeBigIntNoPtr, nil - case typ == reflect.PtrTo(u256Int): + case typ == reflect.PointerTo(u256Int): return decodeU256, nil case typ == u256Int: return decodeU256NoPtr, nil case kind == reflect.Ptr: return makePtrDecoder(typ, tags) - case reflect.PtrTo(typ).Implements(decoderInterface): + case reflect.PointerTo(typ).Implements(decoderInterface): return decodeDecoder, nil case isUint(kind): return decodeUint, nil @@ -262,7 +262,7 @@ func decodeU256(s *Stream, val reflect.Value) error { func makeListDecoder(typ reflect.Type, tag rlpstruct.Tags) (decoder, error) { etype := typ.Elem() - if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) { + if etype.Kind() == reflect.Uint8 && !reflect.PointerTo(etype).Implements(decoderInterface) { if typ.Kind() == reflect.Array { return decodeByteArray, nil } @@ -474,7 +474,7 @@ func makeSimplePtrDecoder(etype reflect.Type, etypeinfo *typeinfo) decoder { // // This decoder is used for pointer-typed struct fields with struct tag "nil". func makeNilPtrDecoder(etype reflect.Type, etypeinfo *typeinfo, ts rlpstruct.Tags) decoder { - typ := reflect.PtrTo(etype) + typ := reflect.PointerTo(etype) nilPtr := reflect.Zero(typ) // Determine the value kind that results in nil pointer. diff --git a/rlp/encode.go b/rlp/encode.go index ffb42b29977c..3645bbfda012 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -141,17 +141,17 @@ func makeWriter(typ reflect.Type, ts rlpstruct.Tags) (writer, error) { switch { case typ == rawValueType: return writeRawValue, nil - case typ.AssignableTo(reflect.PtrTo(bigInt)): + case typ.AssignableTo(reflect.PointerTo(bigInt)): return writeBigIntPtr, nil case typ.AssignableTo(bigInt): return writeBigIntNoPtr, nil - case typ == reflect.PtrTo(u256Int): + case typ == reflect.PointerTo(u256Int): return writeU256IntPtr, nil case typ == u256Int: return writeU256IntNoPtr, nil case kind == reflect.Ptr: return makePtrWriter(typ, ts) - case reflect.PtrTo(typ).Implements(encoderInterface): + case reflect.PointerTo(typ).Implements(encoderInterface): return makeEncoderWriter(typ), nil case isUint(kind): return writeUint, nil From 3caf617dcdee9fc1d2e9070bfdba370b20231884 Mon Sep 17 00:00:00 2001 From: cui <523516579@qq.com> Date: Tue, 9 Apr 2024 14:33:36 +0800 Subject: [PATCH 158/571] core/vm: move bls precompiles to correct addresses (#29445) core: make bls precompiled contract use the correct address as in eip --- core/vm/contracts.go | 18 +++++++++--------- tests/fuzzers/bls12381/precompile_fuzzer.go | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 299143760833..bef8575bb545 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -111,15 +111,15 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{ // PrecompiledContractsBLS contains the set of pre-compiled Ethereum // contracts specified in EIP-2537. These are exported for testing purposes. var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{10}): &bls12381G1Add{}, - common.BytesToAddress([]byte{11}): &bls12381G1Mul{}, - common.BytesToAddress([]byte{12}): &bls12381G1MultiExp{}, - common.BytesToAddress([]byte{13}): &bls12381G2Add{}, - common.BytesToAddress([]byte{14}): &bls12381G2Mul{}, - common.BytesToAddress([]byte{15}): &bls12381G2MultiExp{}, - common.BytesToAddress([]byte{16}): &bls12381Pairing{}, - common.BytesToAddress([]byte{17}): &bls12381MapG1{}, - common.BytesToAddress([]byte{18}): &bls12381MapG2{}, + common.BytesToAddress([]byte{11}): &bls12381G1Add{}, + common.BytesToAddress([]byte{12}): &bls12381G1Mul{}, + common.BytesToAddress([]byte{13}): &bls12381G1MultiExp{}, + common.BytesToAddress([]byte{14}): &bls12381G2Add{}, + common.BytesToAddress([]byte{15}): &bls12381G2Mul{}, + common.BytesToAddress([]byte{16}): &bls12381G2MultiExp{}, + common.BytesToAddress([]byte{17}): &bls12381Pairing{}, + common.BytesToAddress([]byte{18}): &bls12381MapG1{}, + common.BytesToAddress([]byte{19}): &bls12381MapG2{}, } var ( diff --git a/tests/fuzzers/bls12381/precompile_fuzzer.go b/tests/fuzzers/bls12381/precompile_fuzzer.go index 763ed56e9f7a..4df4db73d138 100644 --- a/tests/fuzzers/bls12381/precompile_fuzzer.go +++ b/tests/fuzzers/bls12381/precompile_fuzzer.go @@ -25,15 +25,15 @@ import ( ) const ( - blsG1Add = byte(10) - blsG1Mul = byte(11) - blsG1MultiExp = byte(12) - blsG2Add = byte(13) - blsG2Mul = byte(14) - blsG2MultiExp = byte(15) - blsPairing = byte(16) - blsMapG1 = byte(17) - blsMapG2 = byte(18) + blsG1Add = byte(11) + blsG1Mul = byte(12) + blsG1MultiExp = byte(13) + blsG2Add = byte(14) + blsG2Mul = byte(15) + blsG2MultiExp = byte(16) + blsPairing = byte(17) + blsMapG1 = byte(18) + blsMapG2 = byte(19) ) func checkInput(id byte, inputLen int) bool { From 1126c6d8a57f1b7d9af0b39ac52f6eeb435f66f9 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 9 Apr 2024 14:37:18 +0800 Subject: [PATCH 159/571] core: add txlookup lock (#29343) This change adds a lock to the transaction lookup cache, to avoid the case where reorgs make the lookup return inconsistent results. --- core/blockchain.go | 21 ++++++++++++++------- core/blockchain_reader.go | 3 +++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index fa112c25039e..788804b72eaa 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -244,6 +244,8 @@ type BlockChain struct { bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] receiptsCache *lru.Cache[common.Hash, []*types.Receipt] blockCache *lru.Cache[common.Hash, *types.Block] + + txLookupLock sync.RWMutex txLookupCache *lru.Cache[common.Hash, txLookup] wg sync.WaitGroup @@ -2290,14 +2292,14 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { // rewind the canonical chain to a lower point. log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "oldblocks", len(oldChain), "newnum", newBlock.Number(), "newhash", newBlock.Hash(), "newblocks", len(newChain)) } - // Reset the tx lookup cache in case to clear stale txlookups. - // This is done before writing any new chain data to avoid the - // weird scenario that canonical chain is changed while the - // stale lookups are still cached. - bc.txLookupCache.Purge() + // Acquire the tx-lookup lock before mutation. This step is essential + // as the txlookups should be changed atomically, and all subsequent + // reads should be blocked until the mutation is complete. + bc.txLookupLock.Lock() - // Insert the new chain(except the head block(reverse order)), - // taking care of the proper incremental order. + // Insert the new chain segment in incremental order, from the old + // to the new. The new chain head (newChain[0]) is not inserted here, + // as it will be handled separately outside of this function for i := len(newChain) - 1; i >= 1; i-- { // Insert the block in the canonical way, re-writing history bc.writeHeadBlock(newChain[i]) @@ -2334,6 +2336,11 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { if err := indexesBatch.Write(); err != nil { log.Crit("Failed to delete useless indexes", "err", err) } + // Reset the tx lookup cache to clear stale txlookup cache. + bc.txLookupCache.Purge() + + // Release the tx-lookup lock after mutation. + bc.txLookupLock.Unlock() // Send out events for logs from the old canon chain, and 'reborn' // logs from the new canon chain. The number of logs can be very diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 9e8e3bd4195a..8a85800dd877 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -266,6 +266,9 @@ func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, max // transaction indexing is already finished. The transaction is not existent // from the node's perspective. func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLookupEntry, *types.Transaction, error) { + bc.txLookupLock.RLock() + defer bc.txLookupLock.RUnlock() + // Short circuit if the txlookup already in the cache, retrieve otherwise if item, exist := bc.txLookupCache.Get(hash); exist { return item.lookup, item.transaction, nil From 0bbd88bda04698c457077318ae8442e2611ea3b0 Mon Sep 17 00:00:00 2001 From: Bin <49082129+songzhibin97@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:51:54 +0800 Subject: [PATCH 160/571] all: use timer instead of time.After in loops, to avoid memleaks (#29241) time.After is equivalent to NewTimer(d).C, and does not call Stop if the timer is no longer needed. This can cause memory leaks. This change changes many such occations to use NewTimer instead, and calling Stop once the timer is no longer needed. --- core/bloombits/matcher.go | 6 +++++- eth/downloader/beaconsync.go | 6 +++++- eth/downloader/downloader.go | 12 ++++++++++-- ethstats/ethstats.go | 5 ++++- p2p/simulations/adapters/exec.go | 5 ++++- p2p/simulations/mocker.go | 10 ++++++++-- p2p/simulations/network.go | 5 ++++- 7 files changed, 40 insertions(+), 9 deletions(-) diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go index 6a4cfb23db19..486581fe23d7 100644 --- a/core/bloombits/matcher.go +++ b/core/bloombits/matcher.go @@ -596,6 +596,9 @@ func (s *MatcherSession) deliverSections(bit uint, sections []uint64, bitsets [] // of the session, any request in-flight need to be responded to! Empty responses // are fine though in that case. func (s *MatcherSession) Multiplex(batch int, wait time.Duration, mux chan chan *Retrieval) { + waitTimer := time.NewTimer(wait) + defer waitTimer.Stop() + for { // Allocate a new bloom bit index to retrieve data for, stopping when done bit, ok := s.allocateRetrieval() @@ -604,6 +607,7 @@ func (s *MatcherSession) Multiplex(batch int, wait time.Duration, mux chan chan } // Bit allocated, throttle a bit if we're below our batch limit if s.pendingSections(bit) < batch { + waitTimer.Reset(wait) select { case <-s.quit: // Session terminating, we can't meaningfully service, abort @@ -611,7 +615,7 @@ func (s *MatcherSession) Multiplex(batch int, wait time.Duration, mux chan chan s.deliverSections(bit, []uint64{}, [][]byte{}) return - case <-time.After(wait): + case <-waitTimer.C: // Throttling up, fetch whatever is available } } diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index d3f75c852703..7dfc419f4e9c 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -289,6 +289,9 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error { localHeaders = d.readHeaderRange(tail, int(count)) log.Warn("Retrieved beacon headers from local", "from", from, "count", count) } + fsHeaderContCheckTimer := time.NewTimer(fsHeaderContCheck) + defer fsHeaderContCheckTimer.Stop() + for { // Some beacon headers might have appeared since the last cycle, make // sure we're always syncing to all available ones @@ -381,8 +384,9 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error { } // State sync still going, wait a bit for new headers and retry log.Trace("Pivot not yet committed, waiting...") + fsHeaderContCheckTimer.Reset(fsHeaderContCheck) select { - case <-time.After(fsHeaderContCheck): + case <-fsHeaderContCheckTimer.C: case <-d.cancelCh: return errCanceled } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 6b26822e22b7..941f575aa898 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -1276,7 +1276,10 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode var ( mode = d.getMode() gotHeaders = false // Wait for batches of headers to process + timer = time.NewTimer(time.Second) ) + defer timer.Stop() + for { select { case <-d.cancelCh: @@ -1397,10 +1400,11 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode if mode == FullSync || mode == SnapSync { // If we've reached the allowed number of pending headers, stall a bit for d.queue.PendingBodies() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders { + timer.Reset(time.Second) select { case <-d.cancelCh: return errCanceled - case <-time.After(time.Second): + case <-timer.C: } } // Otherwise insert the headers for content retrieval @@ -1567,7 +1571,10 @@ func (d *Downloader) processSnapSyncContent() error { var ( oldPivot *fetchResult // Locked in pivot block, might change eventually oldTail []*fetchResult // Downloaded content after the pivot + timer = time.NewTimer(time.Second) ) + defer timer.Stop() + for { // Wait for the next batch of downloaded data to be available. If we have // not yet reached the pivot point, wait blockingly as there's no need to @@ -1650,6 +1657,7 @@ func (d *Downloader) processSnapSyncContent() error { oldPivot = P } // Wait for completion, occasionally checking for pivot staleness + timer.Reset(time.Second) select { case <-sync.done: if sync.err != nil { @@ -1660,7 +1668,7 @@ func (d *Downloader) processSnapSyncContent() error { } oldPivot = nil - case <-time.After(time.Second): + case <-timer.C: oldTail = afterP continue } diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index 6e71666ec121..c845db1164f5 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -544,10 +544,13 @@ func (s *Service) reportLatency(conn *connWrapper) error { return err } // Wait for the pong request to arrive back + timer := time.NewTimer(5 * time.Second) + defer timer.Stop() + select { case <-s.pongCh: // Pong delivered, report the latency - case <-time.After(5 * time.Second): + case <-timer.C: // Ping timeout, abort return errors.New("ping timed out") } diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go index 5df2d7649cd8..6307b90bf81c 100644 --- a/p2p/simulations/adapters/exec.go +++ b/p2p/simulations/adapters/exec.go @@ -303,10 +303,13 @@ func (n *ExecNode) Stop() error { go func() { waitErr <- n.Cmd.Wait() }() + timer := time.NewTimer(5 * time.Second) + defer timer.Stop() + select { case err := <-waitErr: return err - case <-time.After(5 * time.Second): + case <-timer.C: return n.Cmd.Process.Kill() } } diff --git a/p2p/simulations/mocker.go b/p2p/simulations/mocker.go index 0dc04e65f921..8763df67ef39 100644 --- a/p2p/simulations/mocker.go +++ b/p2p/simulations/mocker.go @@ -65,8 +65,13 @@ func startStop(net *Network, quit chan struct{}, nodeCount int) { if err != nil { panic("Could not startup node network for mocker") } - tick := time.NewTicker(10 * time.Second) + var ( + tick = time.NewTicker(10 * time.Second) + timer = time.NewTimer(3 * time.Second) + ) defer tick.Stop() + defer timer.Stop() + for { select { case <-quit: @@ -80,11 +85,12 @@ func startStop(net *Network, quit chan struct{}, nodeCount int) { return } + timer.Reset(3 * time.Second) select { case <-quit: log.Info("Terminating simulation loop") return - case <-time.After(3 * time.Second): + case <-timer.C: } log.Debug("starting node", "id", id) diff --git a/p2p/simulations/network.go b/p2p/simulations/network.go index 0225a3bbaafb..2eb8333cd600 100644 --- a/p2p/simulations/network.go +++ b/p2p/simulations/network.go @@ -1028,11 +1028,14 @@ func (net *Network) Load(snap *Snapshot) error { } } + timeout := time.NewTimer(snapshotLoadTimeout) + defer timeout.Stop() + select { // Wait until all connections from the snapshot are established. case <-allConnected: // Make sure that we do not wait forever. - case <-time.After(snapshotLoadTimeout): + case <-timeout.C: return errors.New("snapshot connections not established") } return nil From f202dfdd478467ffa44217fe414ec8c31a793dff Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 9 Apr 2024 12:12:02 +0200 Subject: [PATCH 161/571] core/tracing: add changelog (#29388) Co-authored-by: Matthieu Vachon --- core/tracing/CHANGELOG.md | 69 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 core/tracing/CHANGELOG.md diff --git a/core/tracing/CHANGELOG.md b/core/tracing/CHANGELOG.md new file mode 100644 index 000000000000..77eda4ad7627 --- /dev/null +++ b/core/tracing/CHANGELOG.md @@ -0,0 +1,69 @@ +# Changelog + +All notable changes to the tracing interface will be documented in this file. + +## [Unreleased] + +There has been a major breaking change in the tracing interface for custom native tracers. JS and built-in tracers are not affected by this change and tracing API methods may be used as before. This overhaul has been done as part of the new live tracing feature ([#29189](https://github.com/ethereum/go-ethereum/pull/29189)). To learn more about live tracing please refer to the [docs](https://geth.ethereum.org/docs/developers/evm-tracing/live-tracing). + +**The `EVMLogger` interface which the tracers implemented has been removed.** It has been replaced by a new struct `tracing.Hooks`. `Hooks` keeps pointers to event listening functions. Internally the EVM will use these function pointers to emit events and can skip an event if the tracer has opted not to implement it. In fact this is the main reason for this change of approach. Another benefit is the ease of adding new hooks in future, and dynamically assigning event receivers. + +The consequence of this change can be seen in the constructor of a tracer. Let's take the 4byte tracer as an example. Previously the constructor return an instance which satisfied the interface. Now it should return a pointer to `tracers.Tracer` (which is now also a struct as opposed to an interface) and explicitly assign the event listeners. As a side-benefit the tracers will not have to provide empty implementation of methods just to satisfy the interface: + +```go +func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { + t := &fourByteTracer{ + ids: make(map[string]int), + } + return t, nil + +} +``` + +And now: + +```go +func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (*tracers.Tracer, error) { + t := &fourByteTracer{ + ids: make(map[string]int), + } + return &tracers.Tracer{ + Hooks: &tracing.Hooks{ + OnTxStart: t.onTxStart, + OnEnter: t.onEnter, + }, + GetResult: t.getResult, + Stop: t.stop, + }, nil +} +``` + +### Event listeners + +If you have sharp eyes you might have noticed the new names for `OnTxStart` and `OnEnter`, previously called `CaptureTxStart` and `CaptureEnter`. Indeed there have been various modifications to the signatures of the event listeners. All method names now follow the `On*` pattern instead of `Capture*`. However the modifications are not limited to the names. + +#### New methods + +The live tracing feature was half about adding more observability into the state of the blockchain. As such there have been a host of method additions. Please consult the [Hooks](./hooks.go) struct for the full list of methods. Custom tracers which are invoked through the API (as opposed to "live" tracers) can benefit from the following new methods: + +- `OnGasChange(old, new uint64, reason GasChangeReason)`: This hook tracks the lifetime of gas within a transaction and its subcalls. It will first track the initial purchase of gas with ether, then the following consumptions and refunds of gas until at the end the rest is returned. +- `OnBalanceChange(addr common.Address, prev, new *big.Int, reason BalanceChangeReason)`: This hook tracks the balance changes of accounts. Where possible a reason is provided for the change (e.g. a transfer, gas purchase, withdrawal deposit etc). +- `OnNonceChange(addr common.Address, prev, new uint64)`: This hook tracks the nonce changes of accounts. +- `OnCodeChange(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte)`: This hook tracks the code changes of accounts. +- `OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash)`: This hook tracks the storage changes of accounts. +- `OnLogChange(log *types.Log)`: This hook tracks the logs emitted by the EVM. + +#### Removed methods + +The hooks `CaptureStart` and `CaptureEnd` have been removed. These hooks signaled the top-level call frame of a transaction. The relevant info will be now emitted by `OnEnter` and `OnExit` which are emitted for every call frame. They now contain a `depth` parameter which can be used to distinguish the top-level call frame when necessary. The `create bool` parameter to `CaptureStart` can now be inferred from `typ byte` in `OnEnter`, i.e. `vm.OpCode(typ) == vm.CREATE`. + +#### Modified methods + +- `CaptureTxStart` -> `OnTxStart(vm *VMContext, tx *types.Transaction, from common.Address)`. It now emits the full transaction object as well as `from` which should be used to get the sender address. The `*VMContext` is a replacement for the `*vm.EVM` object previously passed to `CaptureStart`. +- `CaptureTxEnd` -> `OnTxEnd(receipt *types.Receipt, err error)`. It now returns the full receipt object. +- `CaptureEnter` -> `OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)`. The new `depth int` parameter indicates the call stack depth. It is 0 for the top-level call. Furthermore, the location where `OnEnter` is called in the EVM is now made a soon as a call is started. This means some specific error cases that were not before calling `OnEnter/OnExit` will now do so, leading some transaction to have an extra call traced. +- `CaptureExit` -> `OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool)`. It has the new `depth` parameter, same as `OnEnter`. The new `reverted` parameter indicates whether the call frame was reverted. +- `CaptureState` -> `OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error)`. `op` is of type `byte` which can be cast to `vm.OpCode` when necessary. A `*vm.ScopeContext` is not passed anymore. It is replaced by `tracing.OpContext` which offers access to the memory, stack and current contract. +- `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above. + +[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.13.14...master \ No newline at end of file From 34aac1d7562bf141fe6da1d4f3cdea8819e7b23b Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Tue, 9 Apr 2024 18:14:30 +0800 Subject: [PATCH 162/571] all: use big.Sign to compare with zero (#29490) --- core/evm.go | 2 +- eth/backend.go | 2 +- ethclient/gethclient/gethclient_test.go | 2 +- ethclient/simulated/options.go | 2 +- internal/ethapi/api.go | 2 +- signer/fourbyte/validation.go | 3 +-- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/evm.go b/core/evm.go index 4c12e2aa02c4..5d3c454d7c47 100644 --- a/core/evm.go +++ b/core/evm.go @@ -59,7 +59,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common if header.ExcessBlobGas != nil { blobBaseFee = eip4844.CalcBlobFee(*header.ExcessBlobGas) } - if header.Difficulty.Cmp(common.Big0) == 0 { + if header.Difficulty.Sign() == 0 { random = &header.MixDigest } return vm.BlockContext{ diff --git a/eth/backend.go b/eth/backend.go index db3209aee2e3..04ee82efeeaa 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -111,7 +111,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if !config.SyncMode.IsValid() { return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) } - if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) <= 0 { + if config.Miner.GasPrice == nil || config.Miner.GasPrice.Sign() <= 0 { log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", ethconfig.Defaults.Miner.GasPrice) config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) } diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index d562bcda1f01..1cd9c5389b89 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -299,7 +299,7 @@ func testGetProofNonExistent(t *testing.T, client *rpc.Client) { t.Fatalf("invalid nonce, want: %v got: %v", 0, result.Nonce) } // test balance - if result.Balance.Cmp(big.NewInt(0)) != 0 { + if result.Balance.Sign() != 0 { t.Fatalf("invalid balance, want: %v got: %v", 0, result.Balance) } // test storage diff --git a/ethclient/simulated/options.go b/ethclient/simulated/options.go index 6db995c91752..40bcb37bd178 100644 --- a/ethclient/simulated/options.go +++ b/ethclient/simulated/options.go @@ -46,7 +46,7 @@ func WithCallGasLimit(gaslimit uint64) func(nodeConf *node.Config, ethConf *ethc // 0 is not possible as a live Geth node would reject that due to DoS protection, // so the simulated backend will replicate that behavior for consistency. func WithMinerMinTip(tip *big.Int) func(nodeConf *node.Config, ethConf *ethconfig.Config) { - if tip == nil || tip.Cmp(new(big.Int)) <= 0 { + if tip == nil || tip.Sign() <= 0 { panic("invalid miner minimum tip") } return func(nodeConf *node.Config, ethConf *ethconfig.Config) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f682f2765887..f965c91375a5 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1497,7 +1497,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH } else { to = crypto.CreateAddress(args.from(), uint64(*args.Nonce)) } - isPostMerge := header.Difficulty.Cmp(common.Big0) == 0 + isPostMerge := header.Difficulty.Sign() == 0 // Retrieve the precompiles since they don't need to be added to the access list precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time)) diff --git a/signer/fourbyte/validation.go b/signer/fourbyte/validation.go index 0451bda91dc0..8bff011925f5 100644 --- a/signer/fourbyte/validation.go +++ b/signer/fourbyte/validation.go @@ -20,7 +20,6 @@ import ( "bytes" "errors" "fmt" - "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/signer/core/apitypes" @@ -57,7 +56,7 @@ func (db *Database) ValidateTransaction(selector *string, tx *apitypes.SendTxArg // e.g. https://github.com/ethereum/go-ethereum/issues/16106. if len(data) == 0 { // Prevent sending ether into black hole (show stopper) - if tx.Value.ToInt().Cmp(big.NewInt(0)) > 0 { + if tx.Value.ToInt().Sign() > 0 { return nil, errors.New("transaction will create a contract with value but empty code") } // No value submitted at least, critically Warn, but don't blow up From 9dcf8aae4742cc4220065489a5bdcf045c398616 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 10 Apr 2024 17:02:45 +0800 Subject: [PATCH 163/571] eth/protocols/snap: skip retrieval for completed storages (#29378) * eth/protocols/snap: skip retrieval for completed storages * eth/protocols/snap: address comments from peter * eth/protocols/snap: add comments --- eth/protocols/snap/metrics.go | 5 + eth/protocols/snap/progress_test.go | 154 ++++++++++++++++++++++++++++ eth/protocols/snap/sync.go | 142 +++++++++++++++++++++---- 3 files changed, 281 insertions(+), 20 deletions(-) create mode 100644 eth/protocols/snap/progress_test.go diff --git a/eth/protocols/snap/metrics.go b/eth/protocols/snap/metrics.go index a8dc2b582432..19e9151824cb 100644 --- a/eth/protocols/snap/metrics.go +++ b/eth/protocols/snap/metrics.go @@ -54,4 +54,9 @@ var ( // skipStorageHealingGauge is the metric to track how many storages are retrieved // in multiple requests but healing is not necessary. skipStorageHealingGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/noheal", nil) + + // largeStorageDiscardGauge is the metric to track how many chunked storages are + // discarded during the snap sync. + largeStorageDiscardGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/chunk/discard", nil) + largeStorageResumedGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/chunk/resume", nil) ) diff --git a/eth/protocols/snap/progress_test.go b/eth/protocols/snap/progress_test.go new file mode 100644 index 000000000000..9d923bd2f507 --- /dev/null +++ b/eth/protocols/snap/progress_test.go @@ -0,0 +1,154 @@ +// Copyright 2024 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 snap + +import ( + "encoding/json" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +// Legacy sync progress definitions +type legacyStorageTask struct { + Next common.Hash // Next account to sync in this interval + Last common.Hash // Last account to sync in this interval +} + +type legacyAccountTask struct { + Next common.Hash // Next account to sync in this interval + Last common.Hash // Last account to sync in this interval + SubTasks map[common.Hash][]*legacyStorageTask // Storage intervals needing fetching for large contracts +} + +type legacyProgress struct { + Tasks []*legacyAccountTask // The suspended account tasks (contract tasks within) +} + +func compareProgress(a legacyProgress, b SyncProgress) bool { + if len(a.Tasks) != len(b.Tasks) { + return false + } + for i := 0; i < len(a.Tasks); i++ { + if a.Tasks[i].Next != b.Tasks[i].Next { + return false + } + if a.Tasks[i].Last != b.Tasks[i].Last { + return false + } + // new fields are not checked here + + if len(a.Tasks[i].SubTasks) != len(b.Tasks[i].SubTasks) { + return false + } + for addrHash, subTasksA := range a.Tasks[i].SubTasks { + subTasksB, ok := b.Tasks[i].SubTasks[addrHash] + if !ok || len(subTasksB) != len(subTasksA) { + return false + } + for j := 0; j < len(subTasksA); j++ { + if subTasksA[j].Next != subTasksB[j].Next { + return false + } + if subTasksA[j].Last != subTasksB[j].Last { + return false + } + } + } + } + return true +} + +func makeLegacyProgress() legacyProgress { + return legacyProgress{ + Tasks: []*legacyAccountTask{ + { + Next: common.Hash{}, + Last: common.Hash{0x77}, + SubTasks: map[common.Hash][]*legacyStorageTask{ + common.Hash{0x1}: { + { + Next: common.Hash{}, + Last: common.Hash{0xff}, + }, + }, + }, + }, + { + Next: common.Hash{0x88}, + Last: common.Hash{0xff}, + }, + }, + } +} + +func convertLegacy(legacy legacyProgress) SyncProgress { + var progress SyncProgress + for i, task := range legacy.Tasks { + subTasks := make(map[common.Hash][]*storageTask) + for owner, list := range task.SubTasks { + var cpy []*storageTask + for i := 0; i < len(list); i++ { + cpy = append(cpy, &storageTask{ + Next: list[i].Next, + Last: list[i].Last, + }) + } + subTasks[owner] = cpy + } + accountTask := &accountTask{ + Next: task.Next, + Last: task.Last, + SubTasks: subTasks, + } + if i == 0 { + accountTask.StorageCompleted = []common.Hash{{0xaa}, {0xbb}} // fulfill new fields + } + progress.Tasks = append(progress.Tasks, accountTask) + } + return progress +} + +func TestSyncProgressCompatibility(t *testing.T) { + // Decode serialized bytes of legacy progress, backward compatibility + legacy := makeLegacyProgress() + blob, err := json.Marshal(legacy) + if err != nil { + t.Fatalf("Failed to marshal progress %v", err) + } + var dec SyncProgress + if err := json.Unmarshal(blob, &dec); err != nil { + t.Fatalf("Failed to unmarshal progress %v", err) + } + if !compareProgress(legacy, dec) { + t.Fatal("sync progress is not backward compatible") + } + + // Decode serialized bytes of new format progress + progress := convertLegacy(legacy) + blob, err = json.Marshal(progress) + if err != nil { + t.Fatalf("Failed to marshal progress %v", err) + } + var legacyDec legacyProgress + if err := json.Unmarshal(blob, &legacyDec); err != nil { + t.Fatalf("Failed to unmarshal progress %v", err) + } + if !compareProgress(legacyDec, progress) { + t.Fatal("sync progress is not forward compatible") + } +} diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 7915a8eba84a..d5d6fd6d69e5 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -295,11 +295,19 @@ type bytecodeHealResponse struct { // accountTask represents the sync task for a chunk of the account snapshot. type accountTask struct { - // These fields get serialized to leveldb on shutdown + // These fields get serialized to key-value store on shutdown Next common.Hash // Next account to sync in this interval Last common.Hash // Last account to sync in this interval SubTasks map[common.Hash][]*storageTask // Storage intervals needing fetching for large contracts + // This is a list of account hashes whose storage are already completed + // in this cycle. This field is newly introduced in v1.14 and will be + // empty if the task is resolved from legacy progress data. Furthermore, + // this additional field will be ignored by legacy Geth. The only side + // effect is that these contracts might be resynced in the new cycle, + // retaining the legacy behavior. + StorageCompleted []common.Hash `json:",omitempty"` + // These fields are internals used during runtime req *accountRequest // Pending request to fill this task res *accountResponse // Validate response filling this task @@ -309,8 +317,9 @@ type accountTask struct { needState []bool // Flags whether the filling accounts need storage retrieval needHeal []bool // Flags whether the filling accounts's state was chunked and need healing - codeTasks map[common.Hash]struct{} // Code hashes that need retrieval - stateTasks map[common.Hash]common.Hash // Account hashes->roots that need full state retrieval + codeTasks map[common.Hash]struct{} // Code hashes that need retrieval + stateTasks map[common.Hash]common.Hash // Account hashes->roots that need full state retrieval + stateCompleted map[common.Hash]struct{} // Account hashes whose storage have been completed genBatch ethdb.Batch // Batch used by the node generator genTrie *trie.StackTrie // Node generator from storage slots @@ -318,6 +327,30 @@ type accountTask struct { done bool // Flag whether the task can be removed } +// activeSubTasks returns the set of storage tasks covered by the current account +// range. Normally this would be the entire subTask set, but on a sync interrupt +// and later resume it can happen that a shorter account range is retrieved. This +// method ensures that we only start up the subtasks covered by the latest account +// response. +// +// Nil is returned if the account range is empty. +func (task *accountTask) activeSubTasks() map[common.Hash][]*storageTask { + if len(task.res.hashes) == 0 { + return nil + } + var ( + tasks = make(map[common.Hash][]*storageTask) + last = task.res.hashes[len(task.res.hashes)-1] + ) + for hash, subTasks := range task.SubTasks { + subTasks := subTasks // closure + if hash.Cmp(last) <= 0 { + tasks[hash] = subTasks + } + } + return tasks +} + // storageTask represents the sync task for a chunk of the storage snapshot. type storageTask struct { Next common.Hash // Next account to sync in this interval @@ -745,6 +778,14 @@ func (s *Syncer) loadSyncStatus() { for _, task := range s.tasks { task := task // closure for task.genBatch in the stacktrie writer callback + // Restore the completed storages + task.stateCompleted = make(map[common.Hash]struct{}) + for _, hash := range task.StorageCompleted { + task.stateCompleted[hash] = struct{}{} + } + task.StorageCompleted = nil + + // Allocate batch for account trie generation task.genBatch = ethdb.HookedBatch{ Batch: s.db.NewBatch(), OnPut: func(key []byte, value []byte) { @@ -767,6 +808,8 @@ func (s *Syncer) loadSyncStatus() { options = options.WithSkipBoundary(task.Next != (common.Hash{}), task.Last != common.MaxHash, boundaryAccountNodesGauge) } task.genTrie = trie.NewStackTrie(options) + + // Restore leftover storage tasks for accountHash, subtasks := range task.SubTasks { for _, subtask := range subtasks { subtask := subtask // closure for subtask.genBatch in the stacktrie writer callback @@ -861,11 +904,12 @@ func (s *Syncer) loadSyncStatus() { options = options.WithSkipBoundary(next != common.Hash{}, last != common.MaxHash, boundaryAccountNodesGauge) } s.tasks = append(s.tasks, &accountTask{ - Next: next, - Last: last, - SubTasks: make(map[common.Hash][]*storageTask), - genBatch: batch, - genTrie: trie.NewStackTrie(options), + Next: next, + Last: last, + SubTasks: make(map[common.Hash][]*storageTask), + genBatch: batch, + stateCompleted: make(map[common.Hash]struct{}), + genTrie: trie.NewStackTrie(options), }) log.Debug("Created account sync task", "from", next, "last", last) next = common.BigToHash(new(big.Int).Add(last.Big(), common.Big1)) @@ -886,6 +930,14 @@ func (s *Syncer) saveSyncStatus() { } } } + // Save the account hashes of completed storage. + task.StorageCompleted = make([]common.Hash, 0, len(task.stateCompleted)) + for hash := range task.stateCompleted { + task.StorageCompleted = append(task.StorageCompleted, hash) + } + if len(task.StorageCompleted) > 0 { + log.Debug("Leftover completed storages", "number", len(task.StorageCompleted), "next", task.Next, "last", task.Last) + } } // Store the actual progress markers progress := &SyncProgress{ @@ -970,6 +1022,10 @@ func (s *Syncer) cleanStorageTasks() { delete(task.SubTasks, account) task.pend-- + // Mark the state as complete to prevent resyncing, regardless + // if state healing is necessary. + task.stateCompleted[account] = struct{}{} + // If this was the last pending task, forward the account task if task.pend == 0 { s.forwardAccountTask(task) @@ -1209,7 +1265,8 @@ func (s *Syncer) assignStorageTasks(success chan *storageResponse, fail chan *st continue } // Skip tasks that are already retrieving (or done with) all small states - if len(task.SubTasks) == 0 && len(task.stateTasks) == 0 { + storageTasks := task.activeSubTasks() + if len(storageTasks) == 0 && len(task.stateTasks) == 0 { continue } // Task pending retrieval, try to find an idle peer. If no such peer @@ -1253,7 +1310,7 @@ func (s *Syncer) assignStorageTasks(success chan *storageResponse, fail chan *st roots = make([]common.Hash, 0, storageSets) subtask *storageTask ) - for account, subtasks := range task.SubTasks { + for account, subtasks := range storageTasks { for _, st := range subtasks { // Skip any subtasks already filling if st.req != nil { @@ -1850,11 +1907,11 @@ func (s *Syncer) processAccountResponse(res *accountResponse) { res.task.res = res // Ensure that the response doesn't overflow into the subsequent task - last := res.task.Last.Big() + lastBig := res.task.Last.Big() for i, hash := range res.hashes { // Mark the range complete if the last is already included. // Keep iteration to delete the extra states if exists. - cmp := hash.Big().Cmp(last) + cmp := hash.Big().Cmp(lastBig) if cmp == 0 { res.cont = false continue @@ -1890,7 +1947,21 @@ func (s *Syncer) processAccountResponse(res *accountResponse) { } // Check if the account is a contract with an unknown storage trie if account.Root != types.EmptyRootHash { - if !rawdb.HasTrieNode(s.db, res.hashes[i], nil, account.Root, s.scheme) { + // If the storage was already retrieved in the last cycle, there's no need + // to resync it again, regardless of whether the storage root is consistent + // or not. + if _, exist := res.task.stateCompleted[res.hashes[i]]; exist { + // The leftover storage tasks are not expected, unless system is + // very wrong. + if _, ok := res.task.SubTasks[res.hashes[i]]; ok { + panic(fmt.Errorf("unexpected leftover storage tasks, owner: %x", res.hashes[i])) + } + // Mark the healing tag if storage root node is inconsistent, or + // it's non-existent due to storage chunking. + if !rawdb.HasTrieNode(s.db, res.hashes[i], nil, account.Root, s.scheme) { + res.task.needHeal[i] = true + } + } else { // If there was a previous large state retrieval in progress, // don't restart it from scratch. This happens if a sync cycle // is interrupted and resumed later. However, *do* update the @@ -1902,7 +1973,12 @@ func (s *Syncer) processAccountResponse(res *accountResponse) { } res.task.needHeal[i] = true resumed[res.hashes[i]] = struct{}{} + largeStorageResumedGauge.Inc(1) } else { + // It's possible that in the hash scheme, the storage, along + // with the trie nodes of the given root, is already present + // in the database. Schedule the storage task anyway to simplify + // the logic here. res.task.stateTasks[res.hashes[i]] = account.Root } res.task.needState[i] = true @@ -1910,13 +1986,29 @@ func (s *Syncer) processAccountResponse(res *accountResponse) { } } } - // Delete any subtasks that have been aborted but not resumed. This may undo - // some progress if a new peer gives us less accounts than an old one, but for - // now we have to live with that. - for hash := range res.task.SubTasks { - if _, ok := resumed[hash]; !ok { - log.Debug("Aborting suspended storage retrieval", "account", hash) - delete(res.task.SubTasks, hash) + // Delete any subtasks that have been aborted but not resumed. It's essential + // as the corresponding contract might be self-destructed in this cycle(it's + // no longer possible in ethereum as self-destruction is disabled in Cancun + // Fork, but the condition is still necessary for other networks). + // + // Keep the leftover storage tasks if they are not covered by the responded + // account range which should be picked up in next account wave. + if len(res.hashes) > 0 { + // The hash of last delivered account in the response + last := res.hashes[len(res.hashes)-1] + for hash := range res.task.SubTasks { + // TODO(rjl493456442) degrade the log level before merging. + if hash.Cmp(last) > 0 { + log.Info("Keeping suspended storage retrieval", "account", hash) + continue + } + // TODO(rjl493456442) degrade the log level before merging. + // It should never happen in ethereum. + if _, ok := resumed[hash]; !ok { + log.Error("Aborting suspended storage retrieval", "account", hash) + delete(res.task.SubTasks, hash) + largeStorageDiscardGauge.Inc(1) + } } } // If the account range contained no contracts, or all have been fully filled @@ -2014,6 +2106,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { if res.subTask == nil && res.mainTask.needState[j] && (i < len(res.hashes)-1 || !res.cont) { res.mainTask.needState[j] = false res.mainTask.pend-- + res.mainTask.stateCompleted[account] = struct{}{} // mark it as completed smallStorageGauge.Inc(1) } // If the last contract was chunked, mark it as needing healing @@ -2409,10 +2502,19 @@ func (s *Syncer) forwardAccountTask(task *accountTask) { return } task.Next = incHash(hash) + + // Remove the completion flag once the account range is pushed + // forward. The leftover accounts will be skipped in the next + // cycle. + delete(task.stateCompleted, hash) } // All accounts marked as complete, track if the entire task is done task.done = !res.cont + // Error out if there is any leftover completion flag. + if task.done && len(task.stateCompleted) != 0 { + panic(fmt.Errorf("storage completion flags should be emptied, %d left", len(task.stateCompleted))) + } // Stack trie could have generated trie nodes, push them to disk (we need to // flush after finalizing task.done. It's fine even if we crash and lose this // write as it will only cause more data to be downloaded during heal. From b9010f3e872492c1513c853cb5f3f8ce03eff2b5 Mon Sep 17 00:00:00 2001 From: Newt6611 <45097780+Newt6611@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:30:15 +0800 Subject: [PATCH 164/571] rpc: fix comment grammar (#29507) --- rpc/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/service.go b/rpc/service.go index a180b8db93e2..c13b3c0af046 100644 --- a/rpc/service.go +++ b/rpc/service.go @@ -227,7 +227,7 @@ func isSubscriptionType(t reflect.Type) bool { return t == subscriptionType } -// isPubSub tests whether the given method has as as first argument a context.Context and +// isPubSub tests whether the given method's first argument is a context.Context and // returns the pair (Subscription, error). func isPubSub(methodType reflect.Type) bool { // numIn(0) is the receiver type From bd91810462187086b2715fd343aa427e181d89a2 Mon Sep 17 00:00:00 2001 From: "forestkeeperio.eth" <87507039+ForestKeeperIO@users.noreply.github.com> Date: Thu, 11 Apr 2024 05:06:49 -0600 Subject: [PATCH 165/571] cmd: fix some typos in readmes (#29405) * Update README.md updated for readability * Update rules.md Updated for readability and typos --- cmd/clef/rules.md | 26 +++++++++++++------------- cmd/ethkey/README.md | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cmd/clef/rules.md b/cmd/clef/rules.md index 112dae651220..cc4a645596a3 100644 --- a/cmd/clef/rules.md +++ b/cmd/clef/rules.md @@ -9,14 +9,14 @@ It enables usecases like the following: The two main features that are required for this to work well are; -1. Rule Implementation: how to create, manage and interpret rules in a flexible but secure manner -2. Credential managements and credentials; how to provide auto-unlock without exposing keys unnecessarily. +1. Rule Implementation: how to create, manage, and interpret rules in a flexible but secure manner +2. Credential management and credentials; how to provide auto-unlock without exposing keys unnecessarily. The section below deals with both of them ## Rule Implementation -A ruleset file is implemented as a `js` file. Under the hood, the ruleset-engine is a `SignerUI`, implementing the same methods as the `json-rpc` methods +A ruleset file is implemented as a `js` file. Under the hood, the ruleset engine is a `SignerUI`, implementing the same methods as the `json-rpc` methods defined in the UI protocol. Example: ```js @@ -27,7 +27,7 @@ function asBig(str) { return new BigNumber(str) } -// Approve transactions to a certain contract if value is below a certain limit +// Approve transactions to a certain contract if the value is below a certain limit function ApproveTx(req) { var limit = big.Newint("0xb1a2bc2ec50000") var value = asBig(req.transaction.value); @@ -70,7 +70,7 @@ The Otto vm has a few [caveats](https://github.com/robertkrimen/otto): Additionally, a few more have been added * The rule execution cannot load external javascript files. -* The only preloaded library is [`bignumber.js`](https://github.com/MikeMcl/bignumber.js) version `2.0.3`. This one is fairly old, and is not aligned with the documentation at the github repository. +* The only preloaded library is [`bignumber.js`](https://github.com/MikeMcl/bignumber.js) version `2.0.3`. This one is fairly old, and is not aligned with the documentation at the GitHub repository. * Each invocation is made in a fresh virtual machine. This means that you cannot store data in global variables between invocations. This is a deliberate choice -- if you want to store data, use the disk-backed `storage`, since rules should not rely on ephemeral data. * Javascript API parameters are _always_ an object. This is also a design choice, to ensure that parameters are accessed by _key_ and not by order. This is to prevent mistakes due to missing parameters or parameter changes. * The JS engine has access to `storage` and `console`. @@ -88,8 +88,8 @@ Some security precautions can be made, such as: ##### Security of implementation -The drawbacks of this very flexible solution is that the `signer` needs to contain a javascript engine. This is pretty simple to implement, since it's already -implemented for `geth`. There are no known security vulnerabilities in, nor have we had any security-problems with it so far. +The drawback of this very flexible solution is that the `signer` needs to contain a javascript engine. This is pretty simple to implement since it's already +implemented for `geth`. There are no known security vulnerabilities in it, nor have we had any security problems with it so far. The javascript engine would be an added attack surface; but if the validation of `rulesets` is made good (with hash-based attestation), the actual javascript cannot be considered an attack surface -- if an attacker can control the ruleset, a much simpler attack would be to implement an "always-approve" rule instead of exploiting the js vm. The only benefit @@ -105,7 +105,7 @@ It's unclear whether any other DSL could be more secure; since there's always th ## Credential management -The ability to auto-approve transaction means that the signer needs to have necessary credentials to decrypt keyfiles. These passwords are hereafter called `ksp` (keystore pass). +The ability to auto-approve transactions means that the signer needs to have the necessary credentials to decrypt keyfiles. These passwords are hereafter called `ksp` (keystore pass). ### Example implementation @@ -127,8 +127,8 @@ The `vault.dat` would be an encrypted container storing the following informatio ### Security considerations -This would leave it up to the user to ensure that the `path/to/masterseed` is handled in a secure way. It's difficult to get around this, although one could -imagine leveraging OS-level keychains where supported. The setup is however in general similar to how ssh-keys are stored in `.ssh/`. +This would leave it up to the user to ensure that the `path/to/masterseed` is handled securely. It's difficult to get around this, although one could +imagine leveraging OS-level keychains where supported. The setup is however, in general, similar to how ssh-keys are stored in `.ssh/`. # Implementation status @@ -149,7 +149,7 @@ function big(str) { // Time window: 1 week var window = 1000* 3600*24*7; -// Limit : 1 ether +// Limit: 1 ether var limit = new BigNumber("1e18"); function isLimitOk(transaction) { @@ -163,7 +163,7 @@ function isLimitOk(transaction) { if (stored != "") { txs = JSON.parse(stored) } - // First, remove all that have passed out of the time-window + // First, remove all that has passed out of the time window var newtxs = txs.filter(function(tx){return tx.tstamp > windowstart}); console.log(txs, newtxs.length); @@ -174,7 +174,7 @@ function isLimitOk(transaction) { console.log("ApproveTx > Sum so far", sum); console.log("ApproveTx > Requested", value.toNumber()); - // Would we exceed weekly limit ? + // Would we exceed the weekly limit ? return sum.plus(value).lt(limit) } diff --git a/cmd/ethkey/README.md b/cmd/ethkey/README.md index bfddd146775c..a7f5316f4565 100644 --- a/cmd/ethkey/README.md +++ b/cmd/ethkey/README.md @@ -50,4 +50,4 @@ contains the password. ## JSON -In case you need to output the result in a JSON format, you shall by using the `--json` flag. +In case you need to output the result in a JSON format, you shall use the `--json` flag. From b179b7b8e7c9cac7ac21da385dbedc9f24ce3755 Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Mon, 15 Apr 2024 14:34:31 +0800 Subject: [PATCH 166/571] all: remove duplicate word in comments (#29531) This change removes some duplicate words in in comments --- cmd/utils/flags.go | 2 +- core/state/statedb_test.go | 2 +- core/vm/contracts.go | 4 ++-- crypto/signature_test.go | 2 +- eth/ethconfig/config.go | 2 +- p2p/simulations/events.go | 2 +- triedb/pathdb/errors.go | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 7d78c7b31f49..1265864e4426 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -661,7 +661,7 @@ var ( } HTTPPathPrefixFlag = &cli.StringFlag{ Name: "http.rpcprefix", - Usage: "HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", + Usage: "HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", Value: "", Category: flags.APICategory, } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index bc8c63447963..edde6e825472 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -1178,7 +1178,7 @@ func TestDeleteStorage(t *testing.T) { t.Fatal("delete should have empty hashes") } if len(n.Blob) != 0 { - t.Fatal("delete should have have empty blobs") + t.Fatal("delete should have empty blobs") } a = append(a, fmt.Sprintf("%x", path)) }) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index bef8575bb545..140d0e087da6 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -1008,7 +1008,7 @@ func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { func (c *bls12381MapG1) Run(input []byte) ([]byte, error) { // Implements EIP-2537 Map_To_G1 precompile. - // > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. + // > Field-to-curve call expects an `64` bytes input that is interpreted as an element of the base field. // > Output of this call is `128` bytes and is G1 point following respective encoding rules. if len(input) != 64 { return nil, errBLS12381InvalidInputLength @@ -1043,7 +1043,7 @@ func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { // Implements EIP-2537 Map_FP2_TO_G2 precompile logic. - // > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. + // > Field-to-curve call expects an `128` bytes input that is interpreted as an element of the quadratic extension field. // > Output of this call is `256` bytes and is G2 point following respective encoding rules. if len(input) != 128 { return nil, errBLS12381InvalidInputLength diff --git a/crypto/signature_test.go b/crypto/signature_test.go index aecff76bfbda..74d683b50758 100644 --- a/crypto/signature_test.go +++ b/crypto/signature_test.go @@ -71,7 +71,7 @@ func TestVerifySignature(t *testing.T) { wrongkey := common.CopyBytes(testpubkey) wrongkey[10]++ if VerifySignature(wrongkey, testmsg, sig) { - t.Errorf("signature valid with with wrong public key") + t.Errorf("signature valid with wrong public key") } } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index fef7f29f4e28..91f2c8d33010 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -83,7 +83,7 @@ type Config struct { SyncMode downloader.SyncMode // This can be set to list of enrtree:// URLs which will be queried for - // for nodes to connect to. + // nodes to connect to. EthDiscoveryURLs []string SnapDiscoveryURLs []string diff --git a/p2p/simulations/events.go b/p2p/simulations/events.go index d0d03794edf7..1131185fb914 100644 --- a/p2p/simulations/events.go +++ b/p2p/simulations/events.go @@ -30,7 +30,7 @@ const ( EventTypeNode EventType = "node" // EventTypeConn is the type of event emitted when a connection is - // is either established or dropped between two nodes + // either established or dropped between two nodes EventTypeConn EventType = "conn" // EventTypeMsg is the type of event emitted when a p2p message it diff --git a/triedb/pathdb/errors.go b/triedb/pathdb/errors.go index bbf2c9e37cf2..498bc9ec8107 100644 --- a/triedb/pathdb/errors.go +++ b/triedb/pathdb/errors.go @@ -28,7 +28,7 @@ var ( errDatabaseWaitSync = errors.New("waiting for sync") // errSnapshotStale is returned from data accessors if the underlying layer - // layer had been invalidated due to the chain progressing forward far enough + // had been invalidated due to the chain progressing forward far enough // to not maintain the layer's original state. errSnapshotStale = errors.New("layer stale") From 3705acd1a97b2cc9bbb092b326a9d8cfbc42037a Mon Sep 17 00:00:00 2001 From: yudrywet <166895665+yudrywet@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:40:42 +0800 Subject: [PATCH 167/571] cmd/utils: fix typo in comment (#29528) --- cmd/utils/history_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go index 1d8e48344a2e..b6703c59ed32 100644 --- a/cmd/utils/history_test.go +++ b/cmd/utils/history_test.go @@ -83,7 +83,7 @@ func TestHistoryImportAndExport(t *testing.T) { t.Fatalf("unable to initialize chain: %v", err) } if _, err := chain.InsertChain(blocks); err != nil { - t.Fatalf("error insterting chain: %v", err) + t.Fatalf("error inserting chain: %v", err) } // Make temp directory for era files. From 84b12df09e0a67e99a3943f26ccf1b6e6c19a85a Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 15 Apr 2024 14:54:51 +0200 Subject: [PATCH 168/571] core/rawdb: add sanity-limit to header accessor (#29534) --- core/rawdb/accessors_chain.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index e61559993c29..5a4af5bb877b 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -316,8 +316,8 @@ func ReadHeaderRange(db ethdb.Reader, number uint64, count uint64) []rlp.RawValu if count == 0 { return rlpHeaders } - // read remaining from ancients - data, err := db.AncientRange(ChainFreezerHeaderTable, i+1-count, count, 0) + // read remaining from ancients, cap at 2M + data, err := db.AncientRange(ChainFreezerHeaderTable, i+1-count, count, 2*1024*1024) if err != nil { log.Error("Failed to read headers from freezer", "err", err) return rlpHeaders From 67422e2a565784edaeade7d3bb747dc13f6863cf Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Mon, 15 Apr 2024 21:58:17 +0900 Subject: [PATCH 169/571] p2p/nat: fix typos in comments (#29536) --- p2p/nat/natpmp.go | 2 +- p2p/nat/natupnp.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index ea2d8978293f..94ef1f4b68bf 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -26,7 +26,7 @@ import ( natpmp "github.com/jackpal/go-nat-pmp" ) -// natPMPClient adapts the NAT-PMP protocol implementation so it conforms to +// pmp adapts the NAT-PMP protocol implementation so it conforms to // the common interface. type pmp struct { gw net.IP diff --git a/p2p/nat/natupnp.go b/p2p/nat/natupnp.go index c90c4f3de8b7..f1bb955892e0 100644 --- a/p2p/nat/natupnp.go +++ b/p2p/nat/natupnp.go @@ -205,8 +205,8 @@ func discoverUPnP() Interface { return nil } -// finds devices matching the given target and calls matcher for all -// advertised services of each device. The first non-nil service found +// discover finds devices matching the given target and calls matcher for +// all advertised services of each device. The first non-nil service found // is sent into out. If no service matched, nil is sent. func discover(out chan<- *upnp, target string, matcher func(goupnp.ServiceClient) *upnp) { devs, err := goupnp.DiscoverDevices(target) From ef5ac3fb7ae5bf41a465cc32845631f01ff823ef Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 15 Apr 2024 17:35:35 +0200 Subject: [PATCH 170/571] eth/filters: enforce topic-limit early on filter criterias (#29535) This PR adds a limit of 1000 to the "inner" topics in a filter-criteria --- eth/filters/api.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/eth/filters/api.go b/eth/filters/api.go index 59103ac03ca6..56a9de1b215f 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -43,6 +43,9 @@ var ( // The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0 const maxTopics = 4 +// The maximum number of allowed topics within a topic criteria +const maxSubTopics = 1000 + // filter is a helper struct that holds meta information over the filter type // and associated subscription in the event system. type filter struct { @@ -539,6 +542,9 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error { return errors.New("invalid addresses in query") } } + if len(raw.Topics) > maxTopics { + return errExceedMaxTopics + } // topics is an array consisting of strings and/or arrays of strings. // JSON null values are converted to common.Hash{} and ignored by the filter manager. @@ -559,6 +565,9 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error { case []interface{}: // or case e.g. [null, "topic0", "topic1"] + if len(topic) > maxSubTopics { + return errExceedMaxTopics + } for _, rawTopic := range topic { if rawTopic == nil { // null component, match all From d3c4466edd43fff9ac30162073795d8776070c5d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 16 Apr 2024 15:05:36 +0800 Subject: [PATCH 171/571] core, eth/protocols/snap, trie: fix cause for snap-sync corruption, implement gentrie (#29313) This pull request defines a gentrie for snap sync purpose. The stackTrie is used to generate the merkle tree nodes upon receiving a state batch. Several additional options have been added into stackTrie to handle incomplete states (either missing states before or after). In this pull request, these options have been relocated from stackTrie to genTrie, which serves as a wrapper for stackTrie specifically for snap sync purposes. Further, the logic for managing incomplete state has been enhanced in this change. Originally, there are two cases handled: - boundary node filtering - internal (covered by extension node) node clearing This changes adds one more: - Clearing leftover nodes on the boundaries. This feature is necessary if there are leftover trie nodes in database, otherwise node inconsistency may break the state healing. --- core/state/snapshot/conversion.go | 10 +- core/state/statedb.go | 4 +- eth/protocols/snap/gentrie.go | 287 +++++++++++++++ eth/protocols/snap/gentrie_test.go | 553 +++++++++++++++++++++++++++++ eth/protocols/snap/metrics.go | 31 +- eth/protocols/snap/sync.go | 170 ++++----- trie/stacktrie.go | 148 ++------ trie/stacktrie_fuzzer_test.go | 16 +- trie/stacktrie_test.go | 87 ----- trie/trie_test.go | 13 +- 10 files changed, 965 insertions(+), 354 deletions(-) create mode 100644 eth/protocols/snap/gentrie.go create mode 100644 eth/protocols/snap/gentrie_test.go diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index 681be7ebc01f..8a0fd1989af4 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -362,15 +362,15 @@ func generateTrieRoot(db ethdb.KeyValueWriter, scheme string, it Iterator, accou } func stackTrieGenerate(db ethdb.KeyValueWriter, scheme string, owner common.Hash, in chan trieKV, out chan common.Hash) { - options := trie.NewStackTrieOptions() + var onTrieNode trie.OnTrieNode if db != nil { - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { + onTrieNode = func(path []byte, hash common.Hash, blob []byte) { rawdb.WriteTrieNode(db, owner, path, hash, blob, scheme) - }) + } } - t := trie.NewStackTrie(options) + t := trie.NewStackTrie(onTrieNode) for leaf := range in { t.Update(leaf.key[:], leaf.value) } - out <- t.Commit() + out <- t.Hash() } diff --git a/core/state/statedb.go b/core/state/statedb.go index f2c2e7a798ef..d3d383389c23 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -981,12 +981,10 @@ func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (com nodes = trienode.NewNodeSet(addrHash) slots = make(map[common.Hash][]byte) ) - options := trie.NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { + stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { nodes.AddNode(path, trienode.NewDeleted()) size += common.StorageSize(len(path)) }) - stack := trie.NewStackTrie(options) for iter.Next() { slot := common.CopyBytes(iter.Slot()) if err := iter.Error(); err != nil { // error might occur after Slot function diff --git a/eth/protocols/snap/gentrie.go b/eth/protocols/snap/gentrie.go new file mode 100644 index 000000000000..8ef1a007530e --- /dev/null +++ b/eth/protocols/snap/gentrie.go @@ -0,0 +1,287 @@ +// Copyright 2024 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 snap + +import ( + "bytes" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/trie" +) + +// genTrie interface is used by the snap syncer to generate merkle tree nodes +// based on a received batch of states. +type genTrie interface { + // update inserts the state item into generator trie. + update(key, value []byte) error + + // commit flushes the right boundary nodes if complete flag is true. This + // function must be called before flushing the associated database batch. + commit(complete bool) common.Hash +} + +// pathTrie is a wrapper over the stackTrie, incorporating numerous additional +// logics to handle the semi-completed trie and potential leftover dangling +// nodes in the database. It is utilized for constructing the merkle tree nodes +// in path mode during the snap sync process. +type pathTrie struct { + owner common.Hash // identifier of trie owner, empty for account trie + tr *trie.StackTrie // underlying raw stack trie + first []byte // the path of first committed node by stackTrie + last []byte // the path of last committed node by stackTrie + + // This flag indicates whether nodes on the left boundary are skipped for + // committing. If set, the left boundary nodes are considered incomplete + // due to potentially missing left children. + skipLeftBoundary bool + db ethdb.KeyValueReader + batch ethdb.Batch +} + +// newPathTrie initializes the path trie. +func newPathTrie(owner common.Hash, skipLeftBoundary bool, db ethdb.KeyValueReader, batch ethdb.Batch) *pathTrie { + tr := &pathTrie{ + owner: owner, + skipLeftBoundary: skipLeftBoundary, + db: db, + batch: batch, + } + tr.tr = trie.NewStackTrie(tr.onTrieNode) + return tr +} + +// onTrieNode is invoked whenever a new node is committed by the stackTrie. +// +// As the committed nodes might be incomplete if they are on the boundaries +// (left or right), this function has the ability to detect the incomplete +// ones and filter them out for committing. +// +// Additionally, the assumption is made that there may exist leftover dangling +// nodes in the database. This function has the ability to detect the dangling +// nodes that fall within the path space of committed nodes (specifically on +// the path covered by internal extension nodes) and remove them from the +// database. This property ensures that the entire path space is uniquely +// occupied by committed nodes. +// +// Furthermore, all leftover dangling nodes along the path from committed nodes +// to the trie root (left and right boundaries) should be removed as well; +// otherwise, they might potentially disrupt the state healing process. +func (t *pathTrie) onTrieNode(path []byte, hash common.Hash, blob []byte) { + // Filter out the nodes on the left boundary if skipLeftBoundary is + // configured. Nodes are considered to be on the left boundary if + // it's the first one to be committed, or the parent/ancestor of the + // first committed node. + if t.skipLeftBoundary && (t.first == nil || bytes.HasPrefix(t.first, path)) { + if t.first == nil { + // Memorize the path of first committed node, which is regarded + // as left boundary. Deep-copy is necessary as the path given + // is volatile. + t.first = append([]byte{}, path...) + + // The left boundary can be uniquely determined by the first committed node + // from stackTrie (e.g., N_1), as the shared path prefix between the first + // two inserted state items is deterministic (the path of N_3). The path + // from trie root towards the first committed node is considered the left + // boundary. The potential leftover dangling nodes on left boundary should + // be cleaned out. + // + // +-----+ + // | N_3 | shared path prefix of state_1 and state_2 + // +-----+ + // /- -\ + // +-----+ +-----+ + // First committed node | N_1 | | N_2 | latest inserted node (contain state_2) + // +-----+ +-----+ + // + // The node with the path of the first committed one (e.g, N_1) is not + // removed because it's a sibling of the nodes we want to commit, not + // the parent or ancestor. + for i := 0; i < len(path); i++ { + t.delete(path[:i], false) + } + } + return + } + // If boundary filtering is not configured, or the node is not on the left + // boundary, commit it to database. + // + // Note: If the current committed node is an extension node, then the nodes + // falling within the path between itself and its standalone (not embedded + // in parent) child should be cleaned out for exclusively occupy the inner + // path. + // + // This is essential in snap sync to avoid leaving dangling nodes within + // this range covered by extension node which could potentially break the + // state healing. + // + // The extension node is detected if its path is the prefix of last committed + // one and path gap is larger than one. If the path gap is only one byte, + // the current node could either be a full node, or a extension with single + // byte key. In either case, no gaps will be left in the path. + if t.last != nil && bytes.HasPrefix(t.last, path) && len(t.last)-len(path) > 1 { + for i := len(path) + 1; i < len(t.last); i++ { + t.delete(t.last[:i], true) + } + } + t.write(path, blob) + + // Update the last flag. Deep-copy is necessary as the provided path is volatile. + if t.last == nil { + t.last = append([]byte{}, path...) + } else { + t.last = append(t.last[:0], path...) + } +} + +// write commits the node write to provided database batch in path mode. +func (t *pathTrie) write(path []byte, blob []byte) { + if t.owner == (common.Hash{}) { + rawdb.WriteAccountTrieNode(t.batch, path, blob) + } else { + rawdb.WriteStorageTrieNode(t.batch, t.owner, path, blob) + } +} + +func (t *pathTrie) deleteAccountNode(path []byte, inner bool) { + if inner { + accountInnerLookupGauge.Inc(1) + } else { + accountOuterLookupGauge.Inc(1) + } + if !rawdb.ExistsAccountTrieNode(t.db, path) { + return + } + if inner { + accountInnerDeleteGauge.Inc(1) + } else { + accountOuterDeleteGauge.Inc(1) + } + rawdb.DeleteAccountTrieNode(t.batch, path) +} + +func (t *pathTrie) deleteStorageNode(path []byte, inner bool) { + if inner { + storageInnerLookupGauge.Inc(1) + } else { + storageOuterLookupGauge.Inc(1) + } + if !rawdb.ExistsStorageTrieNode(t.db, t.owner, path) { + return + } + if inner { + storageInnerDeleteGauge.Inc(1) + } else { + storageOuterDeleteGauge.Inc(1) + } + rawdb.DeleteStorageTrieNode(t.batch, t.owner, path) +} + +// delete commits the node deletion to provided database batch in path mode. +func (t *pathTrie) delete(path []byte, inner bool) { + if t.owner == (common.Hash{}) { + t.deleteAccountNode(path, inner) + } else { + t.deleteStorageNode(path, inner) + } +} + +// update implements genTrie interface, inserting a (key, value) pair into the +// stack trie. +func (t *pathTrie) update(key, value []byte) error { + return t.tr.Update(key, value) +} + +// commit implements genTrie interface, flushing the right boundary if it's +// considered as complete. Otherwise, the nodes on the right boundary are +// discarded and cleaned up. +// +// Note, this function must be called before flushing database batch, otherwise, +// dangling nodes might be left in database. +func (t *pathTrie) commit(complete bool) common.Hash { + // If the right boundary is claimed as complete, flush them out. + // The nodes on both left and right boundary will still be filtered + // out if left boundary filtering is configured. + if complete { + // Commit all inserted but not yet committed nodes(on the right + // boundary) in the stackTrie. + hash := t.tr.Hash() + if t.skipLeftBoundary { + return common.Hash{} // hash is meaningless if left side is incomplete + } + return hash + } + // Discard nodes on the right boundary as it's claimed as incomplete. These + // nodes might be incomplete due to missing children on the right side. + // Furthermore, the potential leftover nodes on right boundary should also + // be cleaned out. + // + // The right boundary can be uniquely determined by the last committed node + // from stackTrie (e.g., N_1), as the shared path prefix between the last + // two inserted state items is deterministic (the path of N_3). The path + // from trie root towards the last committed node is considered the right + // boundary (root to N_3). + // + // +-----+ + // | N_3 | shared path prefix of last two states + // +-----+ + // /- -\ + // +-----+ +-----+ + // Last committed node | N_1 | | N_2 | latest inserted node (contain last state) + // +-----+ +-----+ + // + // Another interesting scenario occurs when the trie is committed due to + // too many items being accumulated in the batch. To flush them out to + // the database, the path of the last inserted node (N_2) is temporarily + // treated as an incomplete right boundary, and nodes on this path are + // removed (e.g. from root to N_3). + // However, this path will be reclaimed as an internal path by inserting + // more items after the batch flush. New nodes on this path can be committed + // with no issues as they are actually complete. Also, from a database + // perspective, first deleting and then rewriting is a valid data update. + for i := 0; i < len(t.last); i++ { + t.delete(t.last[:i], false) + } + return common.Hash{} // the hash is meaningless for incomplete commit +} + +// hashTrie is a wrapper over the stackTrie for implementing genTrie interface. +type hashTrie struct { + tr *trie.StackTrie +} + +// newHashTrie initializes the hash trie. +func newHashTrie(batch ethdb.Batch) *hashTrie { + return &hashTrie{tr: trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { + rawdb.WriteLegacyTrieNode(batch, hash, blob) + })} +} + +// update implements genTrie interface, inserting a (key, value) pair into +// the stack trie. +func (t *hashTrie) update(key, value []byte) error { + return t.tr.Update(key, value) +} + +// commit implements genTrie interface, committing the nodes on right boundary. +func (t *hashTrie) commit(complete bool) common.Hash { + if !complete { + return common.Hash{} // the hash is meaningless for incomplete commit + } + return t.tr.Hash() // return hash only if it's claimed as complete +} diff --git a/eth/protocols/snap/gentrie_test.go b/eth/protocols/snap/gentrie_test.go new file mode 100644 index 000000000000..1fb2dbce7568 --- /dev/null +++ b/eth/protocols/snap/gentrie_test.go @@ -0,0 +1,553 @@ +// Copyright 2024 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 snap + +import ( + "bytes" + "math/rand" + "slices" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/testrand" + "github.com/ethereum/go-ethereum/trie" +) + +type replayer struct { + paths []string // sort in fifo order + hashes []common.Hash // empty for deletion + unknowns int // counter for unknown write +} + +func newBatchReplay() *replayer { + return &replayer{} +} + +func (r *replayer) decode(key []byte, value []byte) { + account := rawdb.IsAccountTrieNode(key) + storage := rawdb.IsStorageTrieNode(key) + if !account && !storage { + r.unknowns += 1 + return + } + var path []byte + if account { + _, path = rawdb.ResolveAccountTrieNodeKey(key) + } else { + _, owner, inner := rawdb.ResolveStorageTrieNode(key) + path = append(owner.Bytes(), inner...) + } + r.paths = append(r.paths, string(path)) + + if len(value) == 0 { + r.hashes = append(r.hashes, common.Hash{}) + } else { + r.hashes = append(r.hashes, crypto.Keccak256Hash(value)) + } +} + +// updates returns a set of effective mutations. Multiple mutations targeting +// the same node path will be merged in FIFO order. +func (r *replayer) modifies() map[string]common.Hash { + set := make(map[string]common.Hash) + for i, path := range r.paths { + set[path] = r.hashes[i] + } + return set +} + +// updates returns the number of updates. +func (r *replayer) updates() int { + var count int + for _, hash := range r.modifies() { + if hash == (common.Hash{}) { + continue + } + count++ + } + return count +} + +// Put inserts the given value into the key-value data store. +func (r *replayer) Put(key []byte, value []byte) error { + r.decode(key, value) + return nil +} + +// Delete removes the key from the key-value data store. +func (r *replayer) Delete(key []byte) error { + r.decode(key, nil) + return nil +} + +func byteToHex(str []byte) []byte { + l := len(str) * 2 + var nibbles = make([]byte, l) + for i, b := range str { + nibbles[i*2] = b / 16 + nibbles[i*2+1] = b % 16 + } + return nibbles +} + +// innerNodes returns the internal nodes narrowed by two boundaries along with +// the leftmost and rightmost sub-trie roots. +func innerNodes(first, last []byte, includeLeft, includeRight bool, nodes map[string]common.Hash, t *testing.T) (map[string]common.Hash, []byte, []byte) { + var ( + leftRoot []byte + rightRoot []byte + firstHex = byteToHex(first) + lastHex = byteToHex(last) + inner = make(map[string]common.Hash) + ) + for path, hash := range nodes { + if hash == (common.Hash{}) { + t.Fatalf("Unexpected deletion, %v", []byte(path)) + } + // Filter out the siblings on the left side or the left boundary nodes. + if !includeLeft && (bytes.Compare(firstHex, []byte(path)) > 0 || bytes.HasPrefix(firstHex, []byte(path))) { + continue + } + // Filter out the siblings on the right side or the right boundary nodes. + if !includeRight && (bytes.Compare(lastHex, []byte(path)) < 0 || bytes.HasPrefix(lastHex, []byte(path))) { + continue + } + inner[path] = hash + + // Track the path of the leftmost sub trie root + if leftRoot == nil || bytes.Compare(leftRoot, []byte(path)) > 0 { + leftRoot = []byte(path) + } + // Track the path of the rightmost sub trie root + if rightRoot == nil || + (bytes.Compare(rightRoot, []byte(path)) < 0) || + (bytes.Compare(rightRoot, []byte(path)) > 0 && bytes.HasPrefix(rightRoot, []byte(path))) { + rightRoot = []byte(path) + } + } + return inner, leftRoot, rightRoot +} + +func buildPartial(owner common.Hash, db ethdb.KeyValueReader, batch ethdb.Batch, entries []*kv, first, last int) *replayer { + tr := newPathTrie(owner, first != 0, db, batch) + for i := first; i <= last; i++ { + tr.update(entries[i].k, entries[i].v) + } + tr.commit(last == len(entries)-1) + + replay := newBatchReplay() + batch.Replay(replay) + + return replay +} + +// TestPartialGentree verifies if the trie constructed with partial states can +// generate consistent trie nodes that match those of the full trie. +func TestPartialGentree(t *testing.T) { + for round := 0; round < 100; round++ { + var ( + n = rand.Intn(1024) + 10 + entries []*kv + ) + for i := 0; i < n; i++ { + var val []byte + if rand.Intn(3) == 0 { + val = testrand.Bytes(3) + } else { + val = testrand.Bytes(32) + } + entries = append(entries, &kv{ + k: testrand.Bytes(32), + v: val, + }) + } + slices.SortFunc(entries, (*kv).cmp) + + nodes := make(map[string]common.Hash) + tr := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { + nodes[string(path)] = hash + }) + for i := 0; i < len(entries); i++ { + tr.Update(entries[i].k, entries[i].v) + } + tr.Hash() + + check := func(first, last int) { + var ( + db = rawdb.NewMemoryDatabase() + batch = db.NewBatch() + ) + // Build the partial tree with specific boundaries + r := buildPartial(common.Hash{}, db, batch, entries, first, last) + if r.unknowns > 0 { + t.Fatalf("Unknown database write: %d", r.unknowns) + } + + // Ensure all the internal nodes are produced + var ( + set = r.modifies() + inner, _, _ = innerNodes(entries[first].k, entries[last].k, first == 0, last == len(entries)-1, nodes, t) + ) + for path, hash := range inner { + if _, ok := set[path]; !ok { + t.Fatalf("Missing nodes %v", []byte(path)) + } + if hash != set[path] { + t.Fatalf("Inconsistent node, want %x, got: %x", hash, set[path]) + } + } + if r.updates() != len(inner) { + t.Fatalf("Unexpected node write detected, want: %d, got: %d", len(inner), r.updates()) + } + } + for j := 0; j < 100; j++ { + var ( + first int + last int + ) + for { + first = rand.Intn(len(entries)) + last = rand.Intn(len(entries)) + if first <= last { + break + } + } + check(first, last) + } + var cases = []struct { + first int + last int + }{ + {0, len(entries) - 1}, // full + {1, len(entries) - 1}, // no left + {2, len(entries) - 1}, // no left + {2, len(entries) - 2}, // no left and right + {2, len(entries) - 2}, // no left and right + {len(entries) / 2, len(entries) / 2}, // single + {0, 0}, // single first + {len(entries) - 1, len(entries) - 1}, // single last + } + for _, c := range cases { + check(c.first, c.last) + } + } +} + +// TestGentreeDanglingClearing tests if the dangling nodes falling within the +// path space of constructed tree can be correctly removed. +func TestGentreeDanglingClearing(t *testing.T) { + for round := 0; round < 100; round++ { + var ( + n = rand.Intn(1024) + 10 + entries []*kv + ) + for i := 0; i < n; i++ { + var val []byte + if rand.Intn(3) == 0 { + val = testrand.Bytes(3) + } else { + val = testrand.Bytes(32) + } + entries = append(entries, &kv{ + k: testrand.Bytes(32), + v: val, + }) + } + slices.SortFunc(entries, (*kv).cmp) + + nodes := make(map[string]common.Hash) + tr := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { + nodes[string(path)] = hash + }) + for i := 0; i < len(entries); i++ { + tr.Update(entries[i].k, entries[i].v) + } + tr.Hash() + + check := func(first, last int) { + var ( + db = rawdb.NewMemoryDatabase() + batch = db.NewBatch() + ) + // Write the junk nodes as the dangling + var injects []string + for path := range nodes { + for i := 0; i < len(path); i++ { + _, ok := nodes[path[:i]] + if ok { + continue + } + injects = append(injects, path[:i]) + } + } + if len(injects) == 0 { + return + } + for _, path := range injects { + rawdb.WriteAccountTrieNode(db, []byte(path), testrand.Bytes(32)) + } + + // Build the partial tree with specific range + replay := buildPartial(common.Hash{}, db, batch, entries, first, last) + if replay.unknowns > 0 { + t.Fatalf("Unknown database write: %d", replay.unknowns) + } + set := replay.modifies() + + // Make sure the injected junks falling within the path space of + // committed trie nodes are correctly deleted. + _, leftRoot, rightRoot := innerNodes(entries[first].k, entries[last].k, first == 0, last == len(entries)-1, nodes, t) + for _, path := range injects { + if bytes.Compare([]byte(path), leftRoot) < 0 && !bytes.HasPrefix(leftRoot, []byte(path)) { + continue + } + if bytes.Compare([]byte(path), rightRoot) > 0 { + continue + } + if hash, ok := set[path]; !ok || hash != (common.Hash{}) { + t.Fatalf("Missing delete, %v", []byte(path)) + } + } + } + for j := 0; j < 100; j++ { + var ( + first int + last int + ) + for { + first = rand.Intn(len(entries)) + last = rand.Intn(len(entries)) + if first <= last { + break + } + } + check(first, last) + } + var cases = []struct { + first int + last int + }{ + {0, len(entries) - 1}, // full + {1, len(entries) - 1}, // no left + {2, len(entries) - 1}, // no left + {2, len(entries) - 2}, // no left and right + {2, len(entries) - 2}, // no left and right + {len(entries) / 2, len(entries) / 2}, // single + {0, 0}, // single first + {len(entries) - 1, len(entries) - 1}, // single last + } + for _, c := range cases { + check(c.first, c.last) + } + } +} + +// TestFlushPartialTree tests the gentrie can produce complete inner trie nodes +// even with lots of batch flushes. +func TestFlushPartialTree(t *testing.T) { + var entries []*kv + for i := 0; i < 1024; i++ { + var val []byte + if rand.Intn(3) == 0 { + val = testrand.Bytes(3) + } else { + val = testrand.Bytes(32) + } + entries = append(entries, &kv{ + k: testrand.Bytes(32), + v: val, + }) + } + slices.SortFunc(entries, (*kv).cmp) + + nodes := make(map[string]common.Hash) + tr := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { + nodes[string(path)] = hash + }) + for i := 0; i < len(entries); i++ { + tr.Update(entries[i].k, entries[i].v) + } + tr.Hash() + + var cases = []struct { + first int + last int + }{ + {0, len(entries) - 1}, // full + {1, len(entries) - 1}, // no left + {10, len(entries) - 1}, // no left + {10, len(entries) - 2}, // no left and right + {10, len(entries) - 10}, // no left and right + {11, 11}, // single + {0, 0}, // single first + {len(entries) - 1, len(entries) - 1}, // single last + } + for _, c := range cases { + var ( + db = rawdb.NewMemoryDatabase() + batch = db.NewBatch() + combined = db.NewBatch() + ) + inner, _, _ := innerNodes(entries[c.first].k, entries[c.last].k, c.first == 0, c.last == len(entries)-1, nodes, t) + + tr := newPathTrie(common.Hash{}, c.first != 0, db, batch) + for i := c.first; i <= c.last; i++ { + tr.update(entries[i].k, entries[i].v) + if rand.Intn(2) == 0 { + tr.commit(false) + + batch.Replay(combined) + batch.Write() + batch.Reset() + } + } + tr.commit(c.last == len(entries)-1) + + batch.Replay(combined) + batch.Write() + batch.Reset() + + r := newBatchReplay() + combined.Replay(r) + + // Ensure all the internal nodes are produced + set := r.modifies() + for path, hash := range inner { + if _, ok := set[path]; !ok { + t.Fatalf("Missing nodes %v", []byte(path)) + } + if hash != set[path] { + t.Fatalf("Inconsistent node, want %x, got: %x", hash, set[path]) + } + } + if r.updates() != len(inner) { + t.Fatalf("Unexpected node write detected, want: %d, got: %d", len(inner), r.updates()) + } + } +} + +// TestBoundSplit ensures two consecutive trie chunks are not overlapped with +// each other. +func TestBoundSplit(t *testing.T) { + var entries []*kv + for i := 0; i < 1024; i++ { + var val []byte + if rand.Intn(3) == 0 { + val = testrand.Bytes(3) + } else { + val = testrand.Bytes(32) + } + entries = append(entries, &kv{ + k: testrand.Bytes(32), + v: val, + }) + } + slices.SortFunc(entries, (*kv).cmp) + + for j := 0; j < 100; j++ { + var ( + next int + last int + db = rawdb.NewMemoryDatabase() + + lastRightRoot []byte + ) + for { + if next == len(entries) { + break + } + last = rand.Intn(len(entries)-next) + next + + r := buildPartial(common.Hash{}, db, db.NewBatch(), entries, next, last) + set := r.modifies() + + // Skip if the chunk is zero-size + if r.updates() == 0 { + next = last + 1 + continue + } + + // Ensure the updates in two consecutive chunks are not overlapped. + // The only overlapping part should be deletion. + if lastRightRoot != nil && len(set) > 0 { + // Derive the path of left-most node in this chunk + var leftRoot []byte + for path, hash := range r.modifies() { + if hash == (common.Hash{}) { + t.Fatalf("Unexpected deletion %v", []byte(path)) + } + if leftRoot == nil || bytes.Compare(leftRoot, []byte(path)) > 0 { + leftRoot = []byte(path) + } + } + if bytes.HasPrefix(lastRightRoot, leftRoot) || bytes.HasPrefix(leftRoot, lastRightRoot) { + t.Fatalf("Two chunks are not correctly separated, lastRight: %v, left: %v", lastRightRoot, leftRoot) + } + } + + // Track the updates as the last chunk + var rightRoot []byte + for path := range set { + if rightRoot == nil || + (bytes.Compare(rightRoot, []byte(path)) < 0) || + (bytes.Compare(rightRoot, []byte(path)) > 0 && bytes.HasPrefix(rightRoot, []byte(path))) { + rightRoot = []byte(path) + } + } + lastRightRoot = rightRoot + next = last + 1 + } + } +} + +// TestTinyPartialTree tests if the partial tree is too tiny(has less than two +// states), then nothing should be committed. +func TestTinyPartialTree(t *testing.T) { + var entries []*kv + for i := 0; i < 1024; i++ { + var val []byte + if rand.Intn(3) == 0 { + val = testrand.Bytes(3) + } else { + val = testrand.Bytes(32) + } + entries = append(entries, &kv{ + k: testrand.Bytes(32), + v: val, + }) + } + slices.SortFunc(entries, (*kv).cmp) + + for i := 0; i < len(entries); i++ { + next := i + last := i + 1 + if last >= len(entries) { + last = len(entries) - 1 + } + db := rawdb.NewMemoryDatabase() + r := buildPartial(common.Hash{}, db, db.NewBatch(), entries, next, last) + + if next != 0 && last != len(entries)-1 { + if r.updates() != 0 { + t.Fatalf("Unexpected data writes, got: %d", r.updates()) + } + } + } +} diff --git a/eth/protocols/snap/metrics.go b/eth/protocols/snap/metrics.go index 19e9151824cb..6878e5b28058 100644 --- a/eth/protocols/snap/metrics.go +++ b/eth/protocols/snap/metrics.go @@ -27,21 +27,28 @@ var ( IngressRegistrationErrorMeter = metrics.NewRegisteredMeter(ingressRegistrationErrorName, nil) EgressRegistrationErrorMeter = metrics.NewRegisteredMeter(egressRegistrationErrorName, nil) - // deletionGauge is the metric to track how many trie node deletions - // are performed in total during the sync process. - deletionGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/delete", nil) + // accountInnerDeleteGauge is the metric to track how many dangling trie nodes + // covered by extension node in account trie are deleted during the sync. + accountInnerDeleteGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/delete/account/inner", nil) - // lookupGauge is the metric to track how many trie node lookups are - // performed to determine if node needs to be deleted. - lookupGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/lookup", nil) + // storageInnerDeleteGauge is the metric to track how many dangling trie nodes + // covered by extension node in storage trie are deleted during the sync. + storageInnerDeleteGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/delete/storage/inner", nil) + + // accountOuterDeleteGauge is the metric to track how many dangling trie nodes + // above the committed nodes in account trie are deleted during the sync. + accountOuterDeleteGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/delete/account/outer", nil) - // boundaryAccountNodesGauge is the metric to track how many boundary trie - // nodes in account trie are met. - boundaryAccountNodesGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/boundary/account", nil) + // storageOuterDeleteGauge is the metric to track how many dangling trie nodes + // above the committed nodes in storage trie are deleted during the sync. + storageOuterDeleteGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/delete/storage/outer", nil) - // boundaryAccountNodesGauge is the metric to track how many boundary trie - // nodes in storage tries are met. - boundaryStorageNodesGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/boundary/storage", nil) + // lookupGauge is the metric to track how many trie node lookups are + // performed to determine if node needs to be deleted. + accountInnerLookupGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/account/lookup/inner", nil) + accountOuterLookupGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/account/lookup/outer", nil) + storageInnerLookupGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/lookup/inner", nil) + storageOuterLookupGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/lookup/outer", nil) // smallStorageGauge is the metric to track how many storages are small enough // to retrieved in one or two request. diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index d5d6fd6d69e5..b0ddb8e403f7 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -94,6 +94,9 @@ const ( // trienodeHealThrottleDecrease is the divisor for the throttle when the // rate of arriving data is lower than the rate of processing it. trienodeHealThrottleDecrease = 1.25 + + // batchSizeThreshold is the maximum size allowed for gentrie batch. + batchSizeThreshold = 8 * 1024 * 1024 ) var ( @@ -321,8 +324,8 @@ type accountTask struct { stateTasks map[common.Hash]common.Hash // Account hashes->roots that need full state retrieval stateCompleted map[common.Hash]struct{} // Account hashes whose storage have been completed - genBatch ethdb.Batch // Batch used by the node generator - genTrie *trie.StackTrie // Node generator from storage slots + genBatch ethdb.Batch // Batch used by the node generator + genTrie genTrie // Node generator from storage slots done bool // Flag whether the task can be removed } @@ -360,8 +363,8 @@ type storageTask struct { root common.Hash // Storage root hash for this instance req *storageRequest // Pending request to fill this task - genBatch ethdb.Batch // Batch used by the node generator - genTrie *trie.StackTrie // Node generator from storage slots + genBatch ethdb.Batch // Batch used by the node generator + genTrie genTrie // Node generator from storage slots done bool // Flag whether the task can be removed } @@ -749,19 +752,6 @@ func (s *Syncer) Sync(root common.Hash, cancel chan struct{}) error { } } -// cleanPath is used to remove the dangling nodes in the stackTrie. -func (s *Syncer) cleanPath(batch ethdb.Batch, owner common.Hash, path []byte) { - if owner == (common.Hash{}) && rawdb.ExistsAccountTrieNode(s.db, path) { - rawdb.DeleteAccountTrieNode(batch, path) - deletionGauge.Inc(1) - } - if owner != (common.Hash{}) && rawdb.ExistsStorageTrieNode(s.db, owner, path) { - rawdb.DeleteStorageTrieNode(batch, owner, path) - deletionGauge.Inc(1) - } - lookupGauge.Inc(1) -} - // loadSyncStatus retrieves a previously aborted sync status from the database, // or generates a fresh one if none is available. func (s *Syncer) loadSyncStatus() { @@ -792,23 +782,12 @@ func (s *Syncer) loadSyncStatus() { s.accountBytes += common.StorageSize(len(key) + len(value)) }, } - options := trie.NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(task.genBatch, common.Hash{}, path, hash, blob, s.scheme) - }) + if s.scheme == rawdb.HashScheme { + task.genTrie = newHashTrie(task.genBatch) + } if s.scheme == rawdb.PathScheme { - // Configure the dangling node cleaner and also filter out boundary nodes - // only in the context of the path scheme. Deletion is forbidden in the - // hash scheme, as it can disrupt state completeness. - options = options.WithCleaner(func(path []byte) { - s.cleanPath(task.genBatch, common.Hash{}, path) - }) - // Skip the left boundary if it's not the first range. - // Skip the right boundary if it's not the last range. - options = options.WithSkipBoundary(task.Next != (common.Hash{}), task.Last != common.MaxHash, boundaryAccountNodesGauge) + task.genTrie = newPathTrie(common.Hash{}, task.Next != common.Hash{}, s.db, task.genBatch) } - task.genTrie = trie.NewStackTrie(options) - // Restore leftover storage tasks for accountHash, subtasks := range task.SubTasks { for _, subtask := range subtasks { @@ -820,23 +799,12 @@ func (s *Syncer) loadSyncStatus() { s.storageBytes += common.StorageSize(len(key) + len(value)) }, } - owner := accountHash // local assignment for stacktrie writer closure - options := trie.NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(subtask.genBatch, owner, path, hash, blob, s.scheme) - }) + if s.scheme == rawdb.HashScheme { + subtask.genTrie = newHashTrie(subtask.genBatch) + } if s.scheme == rawdb.PathScheme { - // Configure the dangling node cleaner and also filter out boundary nodes - // only in the context of the path scheme. Deletion is forbidden in the - // hash scheme, as it can disrupt state completeness. - options = options.WithCleaner(func(path []byte) { - s.cleanPath(subtask.genBatch, owner, path) - }) - // Skip the left boundary if it's not the first range. - // Skip the right boundary if it's not the last range. - options = options.WithSkipBoundary(subtask.Next != common.Hash{}, subtask.Last != common.MaxHash, boundaryStorageNodesGauge) + subtask.genTrie = newPathTrie(accountHash, subtask.Next != common.Hash{}, s.db, subtask.genBatch) } - subtask.genTrie = trie.NewStackTrie(options) } } } @@ -888,20 +856,12 @@ func (s *Syncer) loadSyncStatus() { s.accountBytes += common.StorageSize(len(key) + len(value)) }, } - options := trie.NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(batch, common.Hash{}, path, hash, blob, s.scheme) - }) + var tr genTrie + if s.scheme == rawdb.HashScheme { + tr = newHashTrie(batch) + } if s.scheme == rawdb.PathScheme { - // Configure the dangling node cleaner and also filter out boundary nodes - // only in the context of the path scheme. Deletion is forbidden in the - // hash scheme, as it can disrupt state completeness. - options = options.WithCleaner(func(path []byte) { - s.cleanPath(batch, common.Hash{}, path) - }) - // Skip the left boundary if it's not the first range. - // Skip the right boundary if it's not the last range. - options = options.WithSkipBoundary(next != common.Hash{}, last != common.MaxHash, boundaryAccountNodesGauge) + tr = newPathTrie(common.Hash{}, next != common.Hash{}, s.db, batch) } s.tasks = append(s.tasks, &accountTask{ Next: next, @@ -909,7 +869,7 @@ func (s *Syncer) loadSyncStatus() { SubTasks: make(map[common.Hash][]*storageTask), genBatch: batch, stateCompleted: make(map[common.Hash]struct{}), - genTrie: trie.NewStackTrie(options), + genTrie: tr, }) log.Debug("Created account sync task", "from", next, "last", last) next = common.BigToHash(new(big.Int).Add(last.Big(), common.Big1)) @@ -920,11 +880,18 @@ func (s *Syncer) loadSyncStatus() { func (s *Syncer) saveSyncStatus() { // Serialize any partial progress to disk before spinning down for _, task := range s.tasks { + // Claim the right boundary as incomplete before flushing the + // accumulated nodes in batch, the nodes on right boundary + // will be discarded and cleaned up by this call. + task.genTrie.commit(false) if err := task.genBatch.Write(); err != nil { log.Error("Failed to persist account slots", "err", err) } for _, subtasks := range task.SubTasks { for _, subtask := range subtasks { + // Same for account trie, discard and cleanup the + // incomplete right boundary. + subtask.genTrie.commit(false) if err := subtask.genBatch.Write(); err != nil { log.Error("Failed to persist storage slots", "err", err) } @@ -2155,25 +2122,20 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { s.storageBytes += common.StorageSize(len(key) + len(value)) }, } - owner := account // local assignment for stacktrie writer closure - options := trie.NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(batch, owner, path, hash, blob, s.scheme) - }) + var tr genTrie + if s.scheme == rawdb.HashScheme { + tr = newHashTrie(batch) + } if s.scheme == rawdb.PathScheme { - options = options.WithCleaner(func(path []byte) { - s.cleanPath(batch, owner, path) - }) // Keep the left boundary as it's the first range. - // Skip the right boundary if it's not the last range. - options = options.WithSkipBoundary(false, r.End() != common.MaxHash, boundaryStorageNodesGauge) + tr = newPathTrie(account, false, s.db, batch) } tasks = append(tasks, &storageTask{ Next: common.Hash{}, Last: r.End(), root: acc.Root, genBatch: batch, - genTrie: trie.NewStackTrie(options), + genTrie: tr, }) for r.Next() { batch := ethdb.HookedBatch{ @@ -2182,27 +2144,19 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { s.storageBytes += common.StorageSize(len(key) + len(value)) }, } - options := trie.NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(batch, owner, path, hash, blob, s.scheme) - }) + var tr genTrie + if s.scheme == rawdb.HashScheme { + tr = newHashTrie(batch) + } if s.scheme == rawdb.PathScheme { - // Configure the dangling node cleaner and also filter out boundary nodes - // only in the context of the path scheme. Deletion is forbidden in the - // hash scheme, as it can disrupt state completeness. - options = options.WithCleaner(func(path []byte) { - s.cleanPath(batch, owner, path) - }) - // Skip the left boundary as it's not the first range - // Skip the right boundary if it's not the last range. - options = options.WithSkipBoundary(true, r.End() != common.MaxHash, boundaryStorageNodesGauge) + tr = newPathTrie(account, true, s.db, batch) } tasks = append(tasks, &storageTask{ Next: r.Start(), Last: r.End(), root: acc.Root, genBatch: batch, - genTrie: trie.NewStackTrie(options), + genTrie: tr, }) } for _, task := range tasks { @@ -2248,26 +2202,18 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { if i < len(res.hashes)-1 || res.subTask == nil { // no need to make local reassignment of account: this closure does not outlive the loop - options := trie.NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(batch, account, path, hash, blob, s.scheme) - }) + var tr genTrie + if s.scheme == rawdb.HashScheme { + tr = newHashTrie(batch) + } if s.scheme == rawdb.PathScheme { - // Configure the dangling node cleaner only in the context of the - // path scheme. Deletion is forbidden in the hash scheme, as it can - // disrupt state completeness. - // - // Notably, boundary nodes can be also kept because the whole storage - // trie is complete. - options = options.WithCleaner(func(path []byte) { - s.cleanPath(batch, account, path) - }) + // Keep the left boundary as it's complete + tr = newPathTrie(account, false, s.db, batch) } - tr := trie.NewStackTrie(options) for j := 0; j < len(res.hashes[i]); j++ { - tr.Update(res.hashes[i][j][:], res.slots[i][j]) + tr.update(res.hashes[i][j][:], res.slots[i][j]) } - tr.Commit() + tr.commit(true) } // Persist the received storage segments. These flat state maybe // outdated during the sync, but it can be fixed later during the @@ -2278,14 +2224,14 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { // If we're storing large contracts, generate the trie nodes // on the fly to not trash the gluing points if i == len(res.hashes)-1 && res.subTask != nil { - res.subTask.genTrie.Update(res.hashes[i][j][:], res.slots[i][j]) + res.subTask.genTrie.update(res.hashes[i][j][:], res.slots[i][j]) } } } // Large contracts could have generated new trie nodes, flush them to disk if res.subTask != nil { if res.subTask.done { - root := res.subTask.genTrie.Commit() + root := res.subTask.genTrie.commit(res.subTask.Last == common.MaxHash) if err := res.subTask.genBatch.Write(); err != nil { log.Error("Failed to persist stack slots", "err", err) } @@ -2302,8 +2248,8 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { } } } - } - if res.subTask.genBatch.ValueSize() > ethdb.IdealBatchSize { + } else if res.subTask.genBatch.ValueSize() > batchSizeThreshold { + res.subTask.genTrie.commit(false) if err := res.subTask.genBatch.Write(); err != nil { log.Error("Failed to persist stack slots", "err", err) } @@ -2486,7 +2432,7 @@ func (s *Syncer) forwardAccountTask(task *accountTask) { if err != nil { panic(err) // Really shouldn't ever happen } - task.genTrie.Update(hash[:], full) + task.genTrie.update(hash[:], full) } } // Flush anything written just now and update the stats @@ -2519,9 +2465,13 @@ func (s *Syncer) forwardAccountTask(task *accountTask) { // flush after finalizing task.done. It's fine even if we crash and lose this // write as it will only cause more data to be downloaded during heal. if task.done { - task.genTrie.Commit() - } - if task.genBatch.ValueSize() > ethdb.IdealBatchSize || task.done { + task.genTrie.commit(task.Last == common.MaxHash) + if err := task.genBatch.Write(); err != nil { + log.Error("Failed to persist stack account", "err", err) + } + task.genBatch.Reset() + } else if task.genBatch.ValueSize() > batchSizeThreshold { + task.genTrie.commit(false) if err := task.genBatch.Write(); err != nil { log.Error("Failed to persist stack account", "err", err) } diff --git a/trie/stacktrie.go b/trie/stacktrie.go index f2f5355c49e8..9c574db0bfa5 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -23,8 +23,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" ) var ( @@ -32,62 +30,32 @@ var ( _ = types.TrieHasher((*StackTrie)(nil)) ) -// StackTrieOptions contains the configured options for manipulating the stackTrie. -type StackTrieOptions struct { - Writer func(path []byte, hash common.Hash, blob []byte) // The function to commit the dirty nodes - Cleaner func(path []byte) // The function to clean up dangling nodes - - SkipLeftBoundary bool // Flag whether the nodes on the left boundary are skipped for committing - SkipRightBoundary bool // Flag whether the nodes on the right boundary are skipped for committing - boundaryGauge metrics.Gauge // Gauge to track how many boundary nodes are met -} - -// NewStackTrieOptions initializes an empty options for stackTrie. -func NewStackTrieOptions() *StackTrieOptions { return &StackTrieOptions{} } - -// WithWriter configures trie node writer within the options. -func (o *StackTrieOptions) WithWriter(writer func(path []byte, hash common.Hash, blob []byte)) *StackTrieOptions { - o.Writer = writer - return o -} - -// WithCleaner configures the cleaner in the option for removing dangling nodes. -func (o *StackTrieOptions) WithCleaner(cleaner func(path []byte)) *StackTrieOptions { - o.Cleaner = cleaner - return o -} - -// WithSkipBoundary configures whether the left and right boundary nodes are -// filtered for committing, along with a gauge metrics to track how many -// boundary nodes are met. -func (o *StackTrieOptions) WithSkipBoundary(skipLeft, skipRight bool, gauge metrics.Gauge) *StackTrieOptions { - o.SkipLeftBoundary = skipLeft - o.SkipRightBoundary = skipRight - o.boundaryGauge = gauge - return o -} +// OnTrieNode is a callback method invoked when a trie node is committed +// by the stack trie. The node is only committed if it's considered complete. +// +// The caller should not modify the contents of the returned path and blob +// slice, and their contents may be changed after the call. It is up to the +// `onTrieNode` receiver function to deep-copy the data if it wants to retain +// it after the call ends. +type OnTrieNode func(path []byte, hash common.Hash, blob []byte) // StackTrie is a trie implementation that expects keys to be inserted // in order. Once it determines that a subtree will no longer be inserted // into, it will hash it and free up the memory it uses. type StackTrie struct { - options *StackTrieOptions - root *stNode - h *hasher - - first []byte // The (hex-encoded without terminator) key of first inserted entry, tracked as left boundary. - last []byte // The (hex-encoded without terminator) key of last inserted entry, tracked as right boundary. + root *stNode + h *hasher + last []byte + onTrieNode OnTrieNode } -// NewStackTrie allocates and initializes an empty trie. -func NewStackTrie(options *StackTrieOptions) *StackTrie { - if options == nil { - options = NewStackTrieOptions() - } +// NewStackTrie allocates and initializes an empty trie. The committed nodes +// will be discarded immediately if no callback is configured. +func NewStackTrie(onTrieNode OnTrieNode) *StackTrie { return &StackTrie{ - options: options, - root: stPool.Get().(*stNode), - h: newHasher(false), + root: stPool.Get().(*stNode), + h: newHasher(false), + onTrieNode: onTrieNode, } } @@ -101,10 +69,6 @@ func (t *StackTrie) Update(key, value []byte) error { if bytes.Compare(t.last, k) >= 0 { return errors.New("non-ascending key order") } - // track the first and last inserted entries. - if t.first == nil { - t.first = append([]byte{}, k...) - } if t.last == nil { t.last = append([]byte{}, k...) // allocate key slice } else { @@ -114,19 +78,9 @@ func (t *StackTrie) Update(key, value []byte) error { return nil } -// MustUpdate is a wrapper of Update and will omit any encountered error but -// just print out an error message. -func (t *StackTrie) MustUpdate(key, value []byte) { - if err := t.Update(key, value); err != nil { - log.Error("Unhandled trie error in StackTrie.Update", "err", err) - } -} - // Reset resets the stack trie object to empty state. func (t *StackTrie) Reset() { - t.options = NewStackTrieOptions() t.root = stPool.Get().(*stNode) - t.first = nil t.last = nil } @@ -346,10 +300,7 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) { // // This method also sets 'st.type' to hashedNode, and clears 'st.key'. func (t *StackTrie) hash(st *stNode, path []byte) { - var ( - blob []byte // RLP-encoded node blob - internal [][]byte // List of node paths covered by the extension node - ) + var blob []byte // RLP-encoded node blob switch st.typ { case hashedNode: return @@ -384,15 +335,6 @@ func (t *StackTrie) hash(st *stNode, path []byte) { // recursively hash and commit child as the first step t.hash(st.children[0], append(path, st.key...)) - // Collect the path of internal nodes between shortNode and its **in disk** - // child. This is essential in the case of path mode scheme to avoid leaving - // danging nodes within the range of this internal path on disk, which would - // break the guarantee for state healing. - if len(st.children[0].val) >= 32 && t.options.Cleaner != nil { - for i := 1; i < len(st.key); i++ { - internal = append(internal, append(path, st.key[:i]...)) - } - } // encode the extension node n := shortNode{Key: hexToCompactInPlace(st.key)} if len(st.children[0].val) < 32 { @@ -416,11 +358,12 @@ func (t *StackTrie) hash(st *stNode, path []byte) { default: panic("invalid node type") } - + // Convert the node type to hashNode and reset the key slice. st.typ = hashedNode st.key = st.key[:0] - // Skip committing the non-root node if the size is smaller than 32 bytes. + // Skip committing the non-root node if the size is smaller than 32 bytes + // as tiny nodes are always embedded in their parent except root node. if len(blob) < 32 && len(path) > 0 { st.val = common.CopyBytes(blob) return @@ -429,51 +372,20 @@ func (t *StackTrie) hash(st *stNode, path []byte) { // input values. st.val = t.h.hashData(blob) - // Short circuit if the stack trie is not configured for writing. - if t.options.Writer == nil { - return + // Invoke the callback it's provided. Notably, the path and blob slices are + // volatile, please deep-copy the slices in callback if the contents need + // to be retained. + if t.onTrieNode != nil { + t.onTrieNode(path, common.BytesToHash(st.val), blob) } - // Skip committing if the node is on the left boundary and stackTrie is - // configured to filter the boundary. - if t.options.SkipLeftBoundary && bytes.HasPrefix(t.first, path) { - if t.options.boundaryGauge != nil { - t.options.boundaryGauge.Inc(1) - } - return - } - // Skip committing if the node is on the right boundary and stackTrie is - // configured to filter the boundary. - if t.options.SkipRightBoundary && bytes.HasPrefix(t.last, path) { - if t.options.boundaryGauge != nil { - t.options.boundaryGauge.Inc(1) - } - return - } - // Clean up the internal dangling nodes covered by the extension node. - // This should be done before writing the node to adhere to the committing - // order from bottom to top. - for _, path := range internal { - t.options.Cleaner(path) - } - t.options.Writer(path, common.BytesToHash(st.val), blob) } // Hash will firstly hash the entire trie if it's still not hashed and then commit -// all nodes to the associated database. Actually most of the trie nodes have been -// committed already. The main purpose here is to commit the nodes on right boundary. -// -// For stack trie, Hash and Commit are functionally identical. +// all leftover nodes to the associated database. Actually most of the trie nodes +// have been committed already. The main purpose here is to commit the nodes on +// right boundary. func (t *StackTrie) Hash() common.Hash { n := t.root t.hash(n, nil) return common.BytesToHash(n.val) } - -// Commit will firstly hash the entire trie if it's still not hashed and then commit -// all nodes to the associated database. Actually most of the trie nodes have been -// committed already. The main purpose here is to commit the nodes on right boundary. -// -// For stack trie, Hash and Commit are functionally identical. -func (t *StackTrie) Commit() common.Hash { - return t.Hash() -} diff --git a/trie/stacktrie_fuzzer_test.go b/trie/stacktrie_fuzzer_test.go index 57a31d115f5a..5126e0bd07ce 100644 --- a/trie/stacktrie_fuzzer_test.go +++ b/trie/stacktrie_fuzzer_test.go @@ -46,11 +46,9 @@ func fuzz(data []byte, debugging bool) { trieA = NewEmpty(dbA) spongeB = &spongeDb{sponge: sha3.NewLegacyKeccak256()} dbB = newTestDatabase(rawdb.NewDatabase(spongeB), rawdb.HashScheme) - - options = NewStackTrieOptions().WithWriter(func(path []byte, hash common.Hash, blob []byte) { + trieB = NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { rawdb.WriteTrieNode(spongeB, common.Hash{}, path, hash, blob, dbB.Scheme()) }) - trieB = NewStackTrie(options) vals []*kv maxElements = 10000 // operate on unique keys only @@ -99,10 +97,9 @@ func fuzz(data []byte, debugging bool) { if debugging { fmt.Printf("{\"%#x\" , \"%#x\"} // stacktrie.Update\n", kv.k, kv.v) } - trieB.MustUpdate(kv.k, kv.v) + trieB.Update(kv.k, kv.v) } rootB := trieB.Hash() - trieB.Commit() if rootA != rootB { panic(fmt.Sprintf("roots differ: (trie) %x != %x (stacktrie)", rootA, rootB)) } @@ -114,20 +111,19 @@ func fuzz(data []byte, debugging bool) { // Ensure all the nodes are persisted correctly var ( - nodeset = make(map[string][]byte) // path -> blob - optionsC = NewStackTrieOptions().WithWriter(func(path []byte, hash common.Hash, blob []byte) { + nodeset = make(map[string][]byte) // path -> blob + trieC = NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { if crypto.Keccak256Hash(blob) != hash { panic("invalid node blob") } nodeset[string(path)] = common.CopyBytes(blob) }) - trieC = NewStackTrie(optionsC) checked int ) for _, kv := range vals { - trieC.MustUpdate(kv.k, kv.v) + trieC.Update(kv.k, kv.v) } - rootC := trieC.Commit() + rootC := trieC.Hash() if rootA != rootC { panic(fmt.Sprintf("roots differ: (trie) %x != %x (stacktrie)", rootA, rootC)) } diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index 58115bc33a40..f053b5112d3f 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -19,14 +19,11 @@ package trie import ( "bytes" "math/big" - "math/rand" - "slices" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/internal/testrand" "github.com/stretchr/testify/assert" ) @@ -381,90 +378,6 @@ func TestStacktrieNotModifyValues(t *testing.T) { } } -func buildPartialTree(entries []*kv, t *testing.T) map[string]common.Hash { - var ( - options = NewStackTrieOptions() - nodes = make(map[string]common.Hash) - ) - var ( - first int - last = len(entries) - 1 - - noLeft bool - noRight bool - ) - // Enter split mode if there are at least two elements - if rand.Intn(5) != 0 { - for { - first = rand.Intn(len(entries)) - last = rand.Intn(len(entries)) - if first <= last { - break - } - } - if first != 0 { - noLeft = true - } - if last != len(entries)-1 { - noRight = true - } - } - options = options.WithSkipBoundary(noLeft, noRight, nil) - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - nodes[string(path)] = hash - }) - tr := NewStackTrie(options) - - for i := first; i <= last; i++ { - tr.MustUpdate(entries[i].k, entries[i].v) - } - tr.Commit() - return nodes -} - -func TestPartialStackTrie(t *testing.T) { - for round := 0; round < 100; round++ { - var ( - n = rand.Intn(100) + 1 - entries []*kv - ) - for i := 0; i < n; i++ { - var val []byte - if rand.Intn(3) == 0 { - val = testrand.Bytes(3) - } else { - val = testrand.Bytes(32) - } - entries = append(entries, &kv{ - k: testrand.Bytes(32), - v: val, - }) - } - slices.SortFunc(entries, (*kv).cmp) - - var ( - nodes = make(map[string]common.Hash) - options = NewStackTrieOptions().WithWriter(func(path []byte, hash common.Hash, blob []byte) { - nodes[string(path)] = hash - }) - ) - tr := NewStackTrie(options) - - for i := 0; i < len(entries); i++ { - tr.MustUpdate(entries[i].k, entries[i].v) - } - tr.Commit() - - for j := 0; j < 100; j++ { - for path, hash := range buildPartialTree(entries, t) { - if nodes[path] != hash { - t.Errorf("%v, want %x, got %x", []byte(path), nodes[path], hash) - } - } - } - } -} - func TestStackTrieErrors(t *testing.T) { s := NewStackTrie(nil) // Deletion diff --git a/trie/trie_test.go b/trie/trie_test.go index 87a0785cfb04..6ecd20c21894 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -963,11 +963,9 @@ func TestCommitSequenceStackTrie(t *testing.T) { id: "b", values: make(map[string]string), } - options := NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { + stTrie := NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { rawdb.WriteTrieNode(stackTrieSponge, common.Hash{}, path, hash, blob, db.Scheme()) }) - stTrie := NewStackTrie(options) // Fill the trie with elements for i := 0; i < count; i++ { @@ -993,7 +991,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { s.Flush() // And flush stacktrie -> disk - stRoot := stTrie.Commit() + stRoot := stTrie.Hash() if stRoot != root { t.Fatalf("root wrong, got %x exp %x", stRoot, root) } @@ -1034,12 +1032,9 @@ func TestCommitSequenceSmallRoot(t *testing.T) { id: "b", values: make(map[string]string), } - options := NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { + stTrie := NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { rawdb.WriteTrieNode(stackTrieSponge, common.Hash{}, path, hash, blob, db.Scheme()) }) - stTrie := NewStackTrie(options) - // Add a single small-element to the trie(s) key := make([]byte, 5) key[0] = 1 @@ -1053,7 +1048,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) { db.Commit(root) // And flush stacktrie -> disk - stRoot := stTrie.Commit() + stRoot := stTrie.Hash() if stRoot != root { t.Fatalf("root wrong, got %x exp %x", stRoot, root) } From e4ecaf89cf5ee6233094f738c4978020fe63e237 Mon Sep 17 00:00:00 2001 From: Marcus Baldassarre Date: Tue, 16 Apr 2024 04:37:18 -0400 Subject: [PATCH 172/571] rpc: implement Unwrap() for wsHandshakeError (#29522) --- rpc/client.go | 2 +- rpc/websocket.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/rpc/client.go b/rpc/client.go index eef6ee21cf05..05b87ae96cb7 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -431,7 +431,7 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { } // Wait for all responses to come back. - for n := 0; n < len(batchresp) && err == nil; n++ { + for n := 0; n < len(batchresp); n++ { resp := batchresp[n] if resp == nil { // Ignore null responses. These can happen for batches sent via HTTP. diff --git a/rpc/websocket.go b/rpc/websocket.go index 538e53a31b7c..9f67caf859f1 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -122,6 +122,10 @@ func (e wsHandshakeError) Error() string { return s } +func (e wsHandshakeError) Unwrap() error { + return e.err +} + func originIsAllowed(allowedOrigins mapset.Set[string], browserOrigin string) bool { it := allowedOrigins.Iterator() for origin := range it.C { From 71c78bf56da29dc8b85cddc9da09eabf18131ee8 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 16 Apr 2024 01:38:25 -0700 Subject: [PATCH 173/571] rpc: close Clients in tests (#29512) --- rpc/client_test.go | 4 +++- rpc/websocket_test.go | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/rpc/client_test.go b/rpc/client_test.go index ac02ad33cf6a..01c326afb017 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -253,6 +253,7 @@ func TestClientBatchRequestLimit(t *testing.T) { defer server.Stop() server.SetBatchLimits(2, 100000) client := DialInProc(server) + defer client.Close() batch := []BatchElem{ {Method: "foo"}, @@ -342,6 +343,7 @@ func testClientCancel(transport string, t *testing.T) { default: panic("unknown transport: " + transport) } + defer client.Close() // The actual test starts here. var ( @@ -592,6 +594,7 @@ func TestClientSubscriptionChannelClose(t *testing.T) { srv.RegisterName("nftest", new(notificationTestService)) client, _ := Dial(wsURL) + defer client.Close() for i := 0; i < 100; i++ { ch := make(chan int, 100) @@ -708,7 +711,6 @@ func TestClientHTTP(t *testing.T) { errc = make(chan error, len(results)) wantResult = echoResult{"a", 1, new(echoArgs)} ) - defer client.Close() for i := range results { i := i go func() { diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go index 8d2bd9d802bd..c6ea325d2926 100644 --- a/rpc/websocket_test.go +++ b/rpc/websocket_test.go @@ -187,6 +187,7 @@ func TestWebsocketPeerInfo(t *testing.T) { if err != nil { t.Fatal(err) } + defer c.Close() // Request peer information. var connInfo PeerInfo @@ -273,6 +274,7 @@ func TestClientWebsocketLargeMessage(t *testing.T) { if err != nil { t.Fatal(err) } + defer c.Close() var r string if err := c.Call(&r, "test_largeResp"); err != nil { From f437307877f4c8e423f787de5c9636b985d322f5 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 16 Apr 2024 10:53:43 +0200 Subject: [PATCH 174/571] core/vm: update gascosts for BLS12-381 + use gnark instead of kilic (#29441) This PR updates the bls contracts from our internal implementation which is an unmaintained fork of the kilic library to the gnark-crypto library that is actively maintained by consensys. It also updates the gas-costs according to the EIP --- core/vm/contracts.go | 226 +- core/vm/contracts_test.go | 4 +- core/vm/testdata/precompiles/blsG1Add.json | 208 +- core/vm/testdata/precompiles/blsG2Add.json | 208 +- core/vm/testdata/precompiles/blsG2Mul.json | 208 +- .../testdata/precompiles/blsG2MultiExp.json | 276 ++- core/vm/testdata/precompiles/blsMapG2.json | 200 +- core/vm/testdata/precompiles/blsPairing.json | 200 +- .../testdata/precompiles/fail-blsG1Add.json | 4 +- .../testdata/precompiles/fail-blsG1Mul.json | 4 +- .../precompiles/fail-blsG1MultiExp.json | 4 +- .../testdata/precompiles/fail-blsG2Add.json | 4 +- .../testdata/precompiles/fail-blsG2Mul.json | 4 +- .../precompiles/fail-blsG2MultiExp.json | 4 +- .../testdata/precompiles/fail-blsMapG1.json | 2 +- .../testdata/precompiles/fail-blsMapG2.json | 2 +- .../testdata/precompiles/fail-blsPairing.json | 6 +- crypto/bls12381/arithmetic_decl.go | 84 - crypto/bls12381/arithmetic_fallback.go | 567 ----- crypto/bls12381/arithmetic_x86.s | 2150 ----------------- crypto/bls12381/arithmetic_x86_adx.go | 25 - crypto/bls12381/arithmetic_x86_noadx.go | 25 - crypto/bls12381/bls12_381.go | 230 -- crypto/bls12381/bls12_381_test.go | 13 - crypto/bls12381/field_element.go | 340 --- crypto/bls12381/field_element_test.go | 250 -- crypto/bls12381/fp.go | 167 -- crypto/bls12381/fp12.go | 277 --- crypto/bls12381/fp2.go | 252 -- crypto/bls12381/fp6.go | 351 --- crypto/bls12381/fp_test.go | 1411 ----------- crypto/bls12381/g1.go | 434 ---- crypto/bls12381/g1_test.go | 284 --- crypto/bls12381/g2.go | 455 ---- crypto/bls12381/g2_test.go | 287 --- crypto/bls12381/gt.go | 121 - crypto/bls12381/isogeny.go | 227 -- crypto/bls12381/pairing.go | 282 --- crypto/bls12381/pairing_test.go | 230 -- crypto/bls12381/swu.go | 158 -- crypto/bls12381/utils.go | 45 - oss-fuzz.sh | 8 + params/protocol_params.go | 16 +- tests/fuzzers/bls12381/bls12381_fuzz.go | 44 +- tests/fuzzers/bls12381/bls12381_test.go | 12 + 45 files changed, 910 insertions(+), 9399 deletions(-) delete mode 100644 crypto/bls12381/arithmetic_decl.go delete mode 100644 crypto/bls12381/arithmetic_fallback.go delete mode 100644 crypto/bls12381/arithmetic_x86.s delete mode 100644 crypto/bls12381/arithmetic_x86_adx.go delete mode 100644 crypto/bls12381/arithmetic_x86_noadx.go delete mode 100644 crypto/bls12381/bls12_381.go delete mode 100644 crypto/bls12381/bls12_381_test.go delete mode 100644 crypto/bls12381/field_element.go delete mode 100644 crypto/bls12381/field_element_test.go delete mode 100644 crypto/bls12381/fp.go delete mode 100644 crypto/bls12381/fp12.go delete mode 100644 crypto/bls12381/fp2.go delete mode 100644 crypto/bls12381/fp6.go delete mode 100644 crypto/bls12381/fp_test.go delete mode 100644 crypto/bls12381/g1.go delete mode 100644 crypto/bls12381/g1_test.go delete mode 100644 crypto/bls12381/g2.go delete mode 100644 crypto/bls12381/g2_test.go delete mode 100644 crypto/bls12381/gt.go delete mode 100644 crypto/bls12381/isogeny.go delete mode 100644 crypto/bls12381/pairing.go delete mode 100644 crypto/bls12381/pairing_test.go delete mode 100644 crypto/bls12381/swu.go delete mode 100644 crypto/bls12381/utils.go diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 140d0e087da6..4ca151c3656f 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -23,12 +23,15 @@ import ( "fmt" "math/big" + "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/blake2b" - "github.com/ethereum/go-ethereum/crypto/bls12381" "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/params" @@ -673,26 +676,22 @@ func (c *bls12381G1Add) Run(input []byte) ([]byte, error) { return nil, errBLS12381InvalidInputLength } var err error - var p0, p1 *bls12381.PointG1 - - // Initialize G1 - g := bls12381.NewG1() + var p0, p1 *bls12381.G1Affine // Decode G1 point p_0 - if p0, err = g.DecodePoint(input[:128]); err != nil { + if p0, err = decodePointG1(input[:128]); err != nil { return nil, err } // Decode G1 point p_1 - if p1, err = g.DecodePoint(input[128:]); err != nil { + if p1, err = decodePointG1(input[128:]); err != nil { return nil, err } // Compute r = p_0 + p_1 - r := g.New() - g.Add(r, p0, p1) + p0.Add(p0, p1) // Encode the G1 point result into 128 bytes - return g.EncodePoint(r), nil + return encodePointG1(p0), nil } // bls12381G1Mul implements EIP-2537 G1Mul precompile. @@ -711,24 +710,21 @@ func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) { return nil, errBLS12381InvalidInputLength } var err error - var p0 *bls12381.PointG1 - - // Initialize G1 - g := bls12381.NewG1() + var p0 *bls12381.G1Affine // Decode G1 point - if p0, err = g.DecodePoint(input[:128]); err != nil { + if p0, err = decodePointG1(input[:128]); err != nil { return nil, err } // Decode scalar value e := new(big.Int).SetBytes(input[128:]) // Compute r = e * p_0 - r := g.New() - g.MulScalar(r, p0, e) + r := new(bls12381.G1Affine) + r.ScalarMultiplication(p0, e) // Encode the G1 point into 128 bytes - return g.EncodePoint(r), nil + return encodePointG1(r), nil } // bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile. @@ -761,31 +757,29 @@ func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) { if len(input) == 0 || len(input)%160 != 0 { return nil, errBLS12381InvalidInputLength } - var err error - points := make([]*bls12381.PointG1, k) - scalars := make([]*big.Int, k) - - // Initialize G1 - g := bls12381.NewG1() + points := make([]bls12381.G1Affine, k) + scalars := make([]fr.Element, k) // Decode point scalar pairs for i := 0; i < k; i++ { off := 160 * i t0, t1, t2 := off, off+128, off+160 // Decode G1 point - if points[i], err = g.DecodePoint(input[t0:t1]); err != nil { + p, err := decodePointG1(input[t0:t1]) + if err != nil { return nil, err } + points[i] = *p // Decode scalar value - scalars[i] = new(big.Int).SetBytes(input[t1:t2]) + scalars[i] = *new(fr.Element).SetBytes(input[t1:t2]) } // Compute r = e_0 * p_0 + e_1 * p_1 + ... + e_(k-1) * p_(k-1) - r := g.New() - g.MultiExp(r, points, scalars) + r := new(bls12381.G1Affine) + r.MultiExp(points, scalars, ecc.MultiExpConfig{}) // Encode the G1 point to 128 bytes - return g.EncodePoint(r), nil + return encodePointG1(r), nil } // bls12381G2Add implements EIP-2537 G2Add precompile. @@ -804,26 +798,23 @@ func (c *bls12381G2Add) Run(input []byte) ([]byte, error) { return nil, errBLS12381InvalidInputLength } var err error - var p0, p1 *bls12381.PointG2 - - // Initialize G2 - g := bls12381.NewG2() - r := g.New() + var p0, p1 *bls12381.G2Affine // Decode G2 point p_0 - if p0, err = g.DecodePoint(input[:256]); err != nil { + if p0, err = decodePointG2(input[:256]); err != nil { return nil, err } // Decode G2 point p_1 - if p1, err = g.DecodePoint(input[256:]); err != nil { + if p1, err = decodePointG2(input[256:]); err != nil { return nil, err } // Compute r = p_0 + p_1 - g.Add(r, p0, p1) + r := new(bls12381.G2Affine) + r.Add(p0, p1) // Encode the G2 point into 256 bytes - return g.EncodePoint(r), nil + return encodePointG2(r), nil } // bls12381G2Mul implements EIP-2537 G2Mul precompile. @@ -842,24 +833,21 @@ func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) { return nil, errBLS12381InvalidInputLength } var err error - var p0 *bls12381.PointG2 - - // Initialize G2 - g := bls12381.NewG2() + var p0 *bls12381.G2Affine // Decode G2 point - if p0, err = g.DecodePoint(input[:256]); err != nil { + if p0, err = decodePointG2(input[:256]); err != nil { return nil, err } // Decode scalar value e := new(big.Int).SetBytes(input[256:]) // Compute r = e * p_0 - r := g.New() - g.MulScalar(r, p0, e) + r := new(bls12381.G2Affine) + r.ScalarMultiplication(p0, e) // Encode the G2 point into 256 bytes - return g.EncodePoint(r), nil + return encodePointG2(r), nil } // bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile. @@ -892,31 +880,29 @@ func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) { if len(input) == 0 || len(input)%288 != 0 { return nil, errBLS12381InvalidInputLength } - var err error - points := make([]*bls12381.PointG2, k) - scalars := make([]*big.Int, k) - - // Initialize G2 - g := bls12381.NewG2() + points := make([]bls12381.G2Affine, k) + scalars := make([]fr.Element, k) // Decode point scalar pairs for i := 0; i < k; i++ { off := 288 * i t0, t1, t2 := off, off+256, off+288 - // Decode G1 point - if points[i], err = g.DecodePoint(input[t0:t1]); err != nil { + // Decode G2 point + p, err := decodePointG2(input[t0:t1]) + if err != nil { return nil, err } + points[i] = *p // Decode scalar value - scalars[i] = new(big.Int).SetBytes(input[t1:t2]) + scalars[i] = *new(fr.Element).SetBytes(input[t1:t2]) } // Compute r = e_0 * p_0 + e_1 * p_1 + ... + e_(k-1) * p_(k-1) - r := g.New() - g.MultiExp(r, points, scalars) + r := new(bls12381.G2Affine) + r.MultiExp(points, scalars, ecc.MultiExpConfig{}) // Encode the G2 point to 256 bytes. - return g.EncodePoint(r), nil + return encodePointG2(r), nil } // bls12381Pairing implements EIP-2537 Pairing precompile. @@ -939,9 +925,10 @@ func (c *bls12381Pairing) Run(input []byte) ([]byte, error) { return nil, errBLS12381InvalidInputLength } - // Initialize BLS12-381 pairing engine - e := bls12381.NewPairingEngine() - g1, g2 := e.G1, e.G2 + var ( + p []bls12381.G1Affine + q []bls12381.G2Affine + ) // Decode pairs for i := 0; i < k; i++ { @@ -949,53 +936,125 @@ func (c *bls12381Pairing) Run(input []byte) ([]byte, error) { t0, t1, t2 := off, off+128, off+384 // Decode G1 point - p1, err := g1.DecodePoint(input[t0:t1]) + p1, err := decodePointG1(input[t0:t1]) if err != nil { return nil, err } // Decode G2 point - p2, err := g2.DecodePoint(input[t1:t2]) + p2, err := decodePointG2(input[t1:t2]) if err != nil { return nil, err } // 'point is on curve' check already done, // Here we need to apply subgroup checks. - if !g1.InCorrectSubgroup(p1) { + if !p1.IsInSubGroup() { return nil, errBLS12381G1PointSubgroup } - if !g2.InCorrectSubgroup(p2) { + if !p2.IsInSubGroup() { return nil, errBLS12381G2PointSubgroup } - - // Update pairing engine with G1 and G2 points - e.AddPair(p1, p2) + p = append(p, *p1) + q = append(q, *p2) } // Prepare 32 byte output out := make([]byte, 32) // Compute pairing and set the result - if e.Check() { + ok, err := bls12381.PairingCheck(p, q) + if err == nil && ok { out[31] = 1 } return out, nil } +func decodePointG1(in []byte) (*bls12381.G1Affine, error) { + if len(in) != 128 { + return nil, errors.New("invalid g1 point length") + } + // decode x + x, err := decodeBLS12381FieldElement(in[:64]) + if err != nil { + return nil, err + } + // decode y + y, err := decodeBLS12381FieldElement(in[64:]) + if err != nil { + return nil, err + } + elem := bls12381.G1Affine{X: x, Y: y} + if !elem.IsOnCurve() { + return nil, errors.New("invalid point: not on curve") + } + + return &elem, nil +} + +// decodePointG2 given encoded (x, y) coordinates in 256 bytes returns a valid G2 Point. +func decodePointG2(in []byte) (*bls12381.G2Affine, error) { + if len(in) != 256 { + return nil, errors.New("invalid g2 point length") + } + x0, err := decodeBLS12381FieldElement(in[:64]) + if err != nil { + return nil, err + } + x1, err := decodeBLS12381FieldElement(in[64:128]) + if err != nil { + return nil, err + } + y0, err := decodeBLS12381FieldElement(in[128:192]) + if err != nil { + return nil, err + } + y1, err := decodeBLS12381FieldElement(in[192:]) + if err != nil { + return nil, err + } + + p := bls12381.G2Affine{X: bls12381.E2{A0: x0, A1: x1}, Y: bls12381.E2{A0: y0, A1: y1}} + if !p.IsOnCurve() { + return nil, errors.New("invalid point: not on curve") + } + return &p, err +} + // decodeBLS12381FieldElement decodes BLS12-381 elliptic curve field element. // Removes top 16 bytes of 64 byte input. -func decodeBLS12381FieldElement(in []byte) ([]byte, error) { +func decodeBLS12381FieldElement(in []byte) (fp.Element, error) { if len(in) != 64 { - return nil, errors.New("invalid field element length") + return fp.Element{}, errors.New("invalid field element length") } // check top bytes for i := 0; i < 16; i++ { if in[i] != byte(0x00) { - return nil, errBLS12381InvalidFieldElementTopBytes + return fp.Element{}, errBLS12381InvalidFieldElementTopBytes } } - out := make([]byte, 48) - copy(out[:], in[16:]) - return out, nil + var res [48]byte + copy(res[:], in[16:]) + + return fp.BigEndian.Element(&res) +} + +// encodePointG1 encodes a point into 128 bytes. +func encodePointG1(p *bls12381.G1Affine) []byte { + out := make([]byte, 128) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(out[16:]), p.X) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(out[64+16:]), p.Y) + return out +} + +// encodePointG2 encodes a point into 256 bytes. +func encodePointG2(p *bls12381.G2Affine) []byte { + out := make([]byte, 256) + // encode x + fp.BigEndian.PutElement((*[fp.Bytes]byte)(out[16:16+48]), p.X.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(out[80:80+48]), p.X.A1) + // encode y + fp.BigEndian.PutElement((*[fp.Bytes]byte)(out[144:144+48]), p.Y.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(out[208:208+48]), p.Y.A1) + return out } // bls12381MapG1 implements EIP-2537 MapG1 precompile. @@ -1020,17 +1079,14 @@ func (c *bls12381MapG1) Run(input []byte) ([]byte, error) { return nil, err } - // Initialize G1 - g := bls12381.NewG1() - // Compute mapping - r, err := g.MapToCurve(fe) + r := bls12381.MapToG1(fe) if err != nil { return nil, err } // Encode the G1 point to 128 bytes - return g.EncodePoint(r), nil + return encodePointG1(&r), nil } // bls12381MapG2 implements EIP-2537 MapG2 precompile. @@ -1050,29 +1106,23 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { } // Decode input field element - fe := make([]byte, 96) c0, err := decodeBLS12381FieldElement(input[:64]) if err != nil { return nil, err } - copy(fe[48:], c0) c1, err := decodeBLS12381FieldElement(input[64:]) if err != nil { return nil, err } - copy(fe[:48], c1) - - // Initialize G2 - g := bls12381.NewG2() // Compute mapping - r, err := g.MapToCurve(fe) + r := bls12381.MapToG2(bls12381.E2{A0: c0, A1: c1}) if err != nil { return nil, err } // Encode the G2 point to 256 bytes - return g.EncodePoint(r), nil + return encodePointG2(&r), nil } // kzgPointEvaluation implements the EIP-4844 point evaluation precompile. diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 6608ff09fcfb..5c4d2ba61aa5 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -372,7 +372,7 @@ func BenchmarkPrecompiledBLS12381G1MultiExpWorstCase(b *testing.B) { Name: "WorstCaseG1", NoBenchmark: false, } - benchmarkPrecompiled("0c", testcase, b) + benchmarkPrecompiled("f0c", testcase, b) } // BenchmarkPrecompiledBLS12381G2MultiExpWorstCase benchmarks the worst case we could find that still fits a gaslimit of 10MGas. @@ -393,5 +393,5 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) { Name: "WorstCaseG2", NoBenchmark: false, } - benchmarkPrecompiled("0f", testcase, b) + benchmarkPrecompiled("f0f", testcase, b) } diff --git a/core/vm/testdata/precompiles/blsG1Add.json b/core/vm/testdata/precompiles/blsG1Add.json index 184d765aa1a4..14a6b16df829 100644 --- a/core/vm/testdata/precompiles/blsG1Add.json +++ b/core/vm/testdata/precompiles/blsG1Add.json @@ -3,728 +3,728 @@ "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", "Expected": "000000000000000000000000000000000572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e00000000000000000000000000000000166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28", "Name": "bls_g1add_(g1+g1=2*g1)", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e00000000000000000000000000000000166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d280000000000000000000000000000000009ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e522400000000000000000000000000000000032b80d3a6f5b09f8a84623389c5f80ca69a0cddabc3097f9d9c27310fd43be6e745256c634af45ca3473b0590ae30d1", "Expected": "0000000000000000000000000000000010e7791fb972fe014159aa33a98622da3cdc98ff707965e536d8636b5fcc5ac7a91a8c46e59a00dca575af0f18fb13dc0000000000000000000000000000000016ba437edcc6551e30c10512367494bfb6b01cc6681e8a4c3cd2501832ab5c4abc40b4578b85cbaffbf0bcd70d67c6e2", "Name": "bls_g1add_(2*g1+3*g1=5*g1)", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Expected": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", "Name": "bls_g1add_(inf+g1=g1)", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Name": "bls_g1add_(inf+inf=inf)", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000012196c5a43d69224d8713389285f26b98f86ee910ab3dd668e413738282003cc5b7357af9a7af54bb713d62255e80f560000000000000000000000000000000006ba8102bfbeea4416b710c73e8cce3032c31c6269c44906f8ac4f7874ce99fb17559992486528963884ce429a992fee000000000000000000000000000000000001101098f5c39893765766af4512a0c74e1bb89bc7e6fdf14e3e7337d257cc0f94658179d83320b99f31ff94cd2bac0000000000000000000000000000000003e1a9f9f44ca2cdab4f43a1a3ee3470fdf90b2fc228eb3b709fcd72f014838ac82a6d797aeefed9a0804b22ed1ce8f7", "Expected": "000000000000000000000000000000001466e1373ae4a7e7ba885c5f0c3ccfa48cdb50661646ac6b779952f466ac9fc92730dcaed9be831cd1f8c4fefffd5209000000000000000000000000000000000c1fb750d2285d4ca0378e1e8cdbf6044151867c34a711b73ae818aee6dbe9e886f53d7928cc6ed9c851e0422f609b11", "Name": "matter_g1_add_0", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000117dbe419018f67844f6a5e1b78a1e597283ad7b8ee7ac5e58846f5a5fd68d0da99ce235a91db3ec1cf340fe6b7afcdb0000000000000000000000000000000013316f23de032d25e912ae8dc9b54c8dba1be7cecdbb9d2228d7e8f652011d46be79089dd0a6080a73c82256ce5e4ed2000000000000000000000000000000000441e7f7f96198e4c23bd5eb16f1a7f045dbc8c53219ab2bcea91d3a027e2dfe659feac64905f8b9add7e4bfc91bec2b0000000000000000000000000000000005fc51bb1b40c87cd4292d4b66f8ca5ce4ef9abd2b69d4464b4879064203bda7c9fc3f896a3844ebc713f7bb20951d95", "Expected": "0000000000000000000000000000000016b8ab56b45a9294466809b8e858c1ad15ad0d52cfcb62f8f5753dc94cee1de6efaaebce10701e3ec2ecaa9551024ea600000000000000000000000000000000124571eec37c0b1361023188d66ec17c1ec230d31b515e0e81e599ec19e40c8a7c8cdea9735bc3d8b4e37ca7e5dd71f6", "Name": "matter_g1_add_1", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008ab7b556c672db7883ec47efa6d98bb08cec7902ebb421aac1c31506b177ac444ffa2d9b400a6f1cbdc6240c607ee110000000000000000000000000000000016b7fa9adf4addc2192271ce7ad3c8d8f902d061c43b7d2e8e26922009b777855bffabe7ed1a09155819eabfa87f276f00000000000000000000000000000000114c3f11ba0b47551fa28f09f148936d6b290dc9f2d0534a83c32b0b849ab921ce6bcaa4ff3c917707798d9c74f2084f00000000000000000000000000000000149dc028207fb04a7795d94ea65e21f9952e445000eb954531ee519efde6901675d3d2446614d243efb77a9cfe0ca3ae", "Expected": "0000000000000000000000000000000002ce7a08719448494857102da464bc65a47c95c77819af325055a23ac50b626df4732daf63feb9a663d71b7c9b8f2c510000000000000000000000000000000016117e87e9b55bd4bd5763d69d5240d30745e014b9aef87c498f9a9e3286ec4d5927df7cd5a2e54ac4179e78645acf27", "Name": "matter_g1_add_2", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000015ff9a232d9b5a8020a85d5fe08a1dcfb73ece434258fe0e2fddf10ddef0906c42dcb5f5d62fc97f934ba900f17beb330000000000000000000000000000000009cfe4ee2241d9413c616462d7bac035a6766aeaab69c81e094d75b840df45d7e0dfac0265608b93efefb9a8728b98e4000000000000000000000000000000000c3d564ac1fe12f18f528c3750583ab6af8973bff3eded7bb4778c32805d9b17846cc7c687af0f46bc87de7748ab72980000000000000000000000000000000002f164c131cbd5afc85692c246157d38dc4bbb2959d2edfa6daf0a8b17c7a898aad53b400e8bdc2b29bf6688ee863db7", "Expected": "0000000000000000000000000000000015510826f50b88fa369caf062ecdf8b03a67e660a35b219b44437a5583b5a9adf76991dce7bff9afc50257f847299504000000000000000000000000000000000a83e879895a1b47dbd6cd25ce8b719e7490cfe021614f7539e841fc2f9c09f071e386676de60b6579aa4bf6d37b13dd", "Name": "matter_g1_add_3", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017a17b82e3bfadf3250210d8ef572c02c3610d65ab4d7366e0b748768a28ee6a1b51f77ed686a64f087f36f641e7dca900000000000000000000000000000000077ea73d233ccea51dc4d5acecf6d9332bf17ae51598f4b394a5f62fb387e9c9aa1d6823b64a074f5873422ca57545d30000000000000000000000000000000019fe3a64361fea14936ff0b3e630471494d0c0b9423e6a004184a2965221c18849b5ed0eb2708a587323d8d6c6735a90000000000000000000000000000000000340823d314703e5efeb0a65c23069199d7dfff8793aaacb98cdcd6177fc8e61ab3294c57bf13b4406266715752ef3e6", "Expected": "00000000000000000000000000000000010b1c96d3910f56b0bf54da5ae8c7ab674a07f8143b61fed660e7309e626dc73eaa2b11886cdb82e2b6735e7802cc860000000000000000000000000000000002dabbbedd72872c2c012e7e893d2f3df1834c43873315488d814ddd6bfcca6758a18aa6bd02a0f3aed962cb51f0a222", "Name": "matter_g1_add_4", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c1243478f4fbdc21ea9b241655947a28accd058d0cdb4f9f0576d32f09dddaf0850464550ff07cab5927b3e4c863ce90000000000000000000000000000000015fb54db10ffac0b6cd374eb7168a8cb3df0a7d5f872d8e98c1f623deb66df5dd08ff4c3658f2905ec8bd02598bd4f90000000000000000000000000000000001461565b03a86df363d1854b4af74879115dffabeddfa879e2c8db9aa414fb291a076c3bdf0beee82d9c094ea8dc381a000000000000000000000000000000000e19d51ab619ee2daf25ea5bfa51eb217eabcfe0b5cb0358fd2fa105fd7cb0f5203816b990df6fda4e0e8d541be9bcf6", "Expected": "000000000000000000000000000000000cb40d0bf86a627d3973f1e7846484ffd0bc4943b42a54ff9527c285fed3c056b947a9b6115824cabafe13cd1af8181c00000000000000000000000000000000076255fc12f1a9dbd232025815238baaa6a3977fd87594e8d1606caec0d37b916e1e43ee2d2953d75a40a7ba416df237", "Name": "matter_g1_add_5", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000328f09584b6d6c98a709fc22e184123994613aca95a28ac53df8523b92273eb6f4e2d9b2a7dcebb474604d54a210719000000000000000000000000000000001220ebde579911fe2e707446aaad8d3789fae96ae2e23670a4fd856ed82daaab704779eb4224027c1ed9460f39951a1b0000000000000000000000000000000019cabba3e09ad34cc3d125e0eb41b527aa48a4562c2b7637467b2dbc71c373897d50eed1bc75b2bde8904ece5626d6e400000000000000000000000000000000056b0746f820cff527358c86479dc924a10b9f7cae24cd495625a4159c8b71a8c3ad1a15ebf22d3561cd4b74e8a6e48b", "Expected": "000000000000000000000000000000000e115e0b61c1f1b25cc10a7b3bd21cf696b1433a0c366c2e1bca3c26b09482c6eced8c8ecfa69ce6b9b3b4419779262e00000000000000000000000000000000077b85daf61b9f947e81633e3bc64e697bc6c1d873f2c21e5c4c3a11302d4d5ef4c3ff5519564729aaf2a50a3c9f1196", "Name": "matter_g1_add_6", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000002ebfa98aa92c32a29ebe17fcb1819ba82e686abd9371fcee8ea793b4c72b6464085044f818f1f5902396df0122830cb00000000000000000000000000000000001184715b8432ed190b459113977289a890f68f6085ea111466af15103c9c02467da33e01d6bff87fd57db6ccba442a0000000000000000000000000000000011f649ee35ff8114060fc5e4df9ac828293f6212a9857ca31cb3e9ce49aa1212154a9808f1e763bc989b6d5ba7cf09390000000000000000000000000000000019af81eca7452f58c1a6e99fab50dc0d5eeebc7712153e717a14a31cffdfd0a923dbd585e652704a174905605a2e8b9d", "Expected": "000000000000000000000000000000000013e37a8950a659265b285c6fb56930fb77759d9d40298acac2714b97b83ec7692a7d1c4ccb83f074384db9eedd809c0000000000000000000000000000000003215d524d6419214568ba42a31502f2a58a97d0139c66908e9d71755f5a7666567aafe30ea84d89308f06768f28a648", "Name": "matter_g1_add_7", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009d6424e002439998e91cd509f85751ad25e574830c564e7568347d19e3f38add0cab067c0b4b0801785a78bcbeaf246000000000000000000000000000000000ef6d7db03ee654503b46ff0dbc3297536a422e963bda9871a8da8f4eeb98dedebd6071c4880b4636198f4c2375dc795000000000000000000000000000000000d713e148769fac2efd380886f8566c6d4662dd38317bb7e68744c4339efaedbab88435ce3dc289afaa7ecb37df37a5300000000000000000000000000000000129d9cd031b31c77a4e68093dcdbb585feba786207aa115d9cf120fe4f19ca31a0dca9c692bd0f53721d60a55c333129", "Expected": "00000000000000000000000000000000029405b9615e14bdac8b5666bbc5f3843d4bca17c97bed66d164f1b58d2a148f0f506d645d665a40e60d53fe29375ed400000000000000000000000000000000162761f1712814e474beb2289cc50519253d680699b530c2a6477f727ccc75a19681b82e490f441f91a3c611eeb0e9e2", "Name": "matter_g1_add_8", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000002d1cdb93191d1f9f0308c2c55d0208a071f5520faca7c52ab0311dbc9ba563bd33b5dd6baa77bf45ac2c3269e945f4800000000000000000000000000000000072a52106e6d7b92c594c4dacd20ef5fab7141e45c231457cd7e71463b2254ee6e72689e516fa6a8f29f2a173ce0a1900000000000000000000000000000000006d92bcb599edca426ff4ceeb154ebf133c2dea210c7db0441f74bd37c8d239149c8b5056ace0bfefb1db04b42664f530000000000000000000000000000000008522fc155eef6d5746283808091f91b427f2a96ac248850f9e3d7aadd14848101c965663fd4a63aea1153d71918435a", "Expected": "000000000000000000000000000000000cfaa8df9437c0b6f344a0c8dcbc7529a07aec0d7632ace89af6796b6b960b014f78dd10e987a993fb8a95cc909822ec0000000000000000000000000000000007475f115f6eb35f78ba9a2b71a44ccb6bbc1e980b8cd369c5c469565f3fb798bc907353cf47f524ba715deaedf379cb", "Name": "matter_g1_add_9", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000641642f6801d39a09a536f506056f72a619c50d043673d6d39aa4af11d8e3ded38b9c3bbc970dbc1bd55d68f94b50d0000000000000000000000000000000009ab050de356a24aea90007c6b319614ba2f2ed67223b972767117769e3c8e31ee4056494628fb2892d3d37afb6ac9430000000000000000000000000000000016380d03b7c5cc3301ffcb2cf7c28c9bde54fc22ba2b36ec293739d8eb674678c8e6461e34c1704747817c8f8341499a000000000000000000000000000000000ec6667aa5c6a769a64c180d277a341926376c39376480dc69fcad9a8d3b540238eb39d05aaa8e3ca15fc2c3ab696047", "Expected": "0000000000000000000000000000000011541d798b4b5069e2541fa5410dad03fd02784332e72658c7b0fa96c586142a967addc11a7a82bfcee33bd5d07066b900000000000000000000000000000000195b3fcb94ab7beb908208283b4e5d19c0af90fca4c76268f3c703859dea7d038aca976927f48839ebc7310869c724aa", "Name": "matter_g1_add_10", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000fd4893addbd58fb1bf30b8e62bef068da386edbab9541d198e8719b2de5beb9223d87387af82e8b55bd521ff3e47e2d000000000000000000000000000000000f3a923b76473d5b5a53501790cb02597bb778bdacb3805a9002b152d22241ad131d0f0d6a260739cbab2c2fe602870e00000000000000000000000000000000065eb0770ab40199658bf87db6c6b52cd8c6c843a3e40dd60433d4d79971ff31296c9e00a5d553df7c81ade533379f4b0000000000000000000000000000000017a6f6137ddd90c15cf5e415f040260e15287d8d2254c6bfee88938caec9e5a048ff34f10607d1345ba1f09f30441ef4", "Expected": "0000000000000000000000000000000006b0853b3d41fc2d7b27da0bb2d6eb76be32530b59f8f537d227a6eb78364c7c0760447494a8bba69ef4b256dbef750200000000000000000000000000000000166e55ba2d20d94da474d4a085c14245147705e252e2a76ae696c7e37d75cde6a77fea738cef045182d5e628924dc0bb", "Name": "matter_g1_add_11", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000002cb4b24c8aa799fd7cb1e4ab1aab1372113200343d8526ea7bc64dfaf926baf5d90756a40e35617854a2079cd07fba40000000000000000000000000000000003327ca22bd64ebd673cc6d5b02b2a8804d5353c9d251637c4273ad08d581cc0d58da9bea27c37a0b3f4961dbafd276b0000000000000000000000000000000006a3f7eb0e42567210cc1ba5e6f8c42d02f1eef325b6483fef49ba186f59ab69ca2284715b736086d2a0a1f0ea224b40000000000000000000000000000000000bc08427fda31a6cfbe657a8c71c73894a33700e93e411d42f1471160c403b939b535070b68d60a4dc50e47493da63dc", "Expected": "000000000000000000000000000000000c35d4cd5d43e9cf52c15d46fef521666a1e1ab9f0b4a77b8e78882e9fab40f3f988597f202c5bd176c011a56a1887d4000000000000000000000000000000000ae2b5c24928a00c02daddf03fade45344f250dcf4c12eda06c39645b4d56147cb239d95b06fd719d4dc20fe332a6fce", "Name": "matter_g1_add_12", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024ad70f2b2105ca37112858e84c6f5e3ffd4a8b064522faae1ecba38fabd52a6274cb46b00075deb87472f11f2e67d90000000000000000000000000000000010a502c8b2a68aa30d2cb719273550b9a3c283c35b2e18a01b0b765344ffaaa5cb30a1e3e6ecd3a53ab67658a578768100000000000000000000000000000000068e79aea45b7199ec4b6f26e01e88ec76533743639ce76df66937fff9e7de3edf6700d227f10f43e073afcc63e2eddc00000000000000000000000000000000039c0b6d9e9681401aeb57a94cedc0709a0eff423ace9253eb00ae75e21cabeb626b52ef4368e6a4592aed9689c6fca4", "Expected": "0000000000000000000000000000000013bad27dafa20f03863454c30bd5ae6b202c9c7310875da302d4693fc1c2b78cca502b1ff851b183c4b2564c5d3eb4dc0000000000000000000000000000000000552b322b3d672704382b5d8b214c225b4f7868f9c5ae0766b7cdb181f97ed90a4892235915ffbc0daf3e14ec98a606", "Name": "matter_g1_add_13", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000704cc57c8e0944326ddc7c747d9e7347a7f6918977132eea269f161461eb64066f773352f293a3ac458dc3ccd5026a000000000000000000000000000000001099d3c2bb2d082f2fdcbed013f7ac69e8624f4fcf6dfab3ee9dcf7fbbdb8c49ee79de40e887c0b6828d2496e3a6f7680000000000000000000000000000000000adac9bb98bb6f35a8f941dbff39dfd307b6a4d5756ccae103c814564e3d3993a8866ff91581ccdd7686c1dce0b19f700000000000000000000000000000000083d235e0579032ca47f65b6ae007ce8ffd2f1a890ce3bc45ebd0df6673ad530d2f42125d543cb0c51ba0c28345729d8", "Expected": "000000000000000000000000000000000b5513e42f5217490f395a8cb3673a4fc35142575f770af75ecf7a4fcd97eee215c4298fc4feab51915137cbdb814839000000000000000000000000000000000e9d4db04b233b0b12a7ff620faefef906aeb2b15481ce1609dad50eb6a7d0c09a850375599c501296219fb7b288e305", "Name": "matter_g1_add_14", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000130535a29392c77f045ac90e47f2e7b3cffff94494fe605aad345b41043f6663ada8e2e7ecd3d06f3b8854ef92212f42000000000000000000000000000000001699a3cc1f10cd2ed0dc68eb916b4402e4f12bf4746893bf70e26e209e605ea89e3d53e7ac52bd07713d3c8fc671931d000000000000000000000000000000000d5bb4fa8b494c0adf4b695477d4a05f0ce48f7f971ef53952f685e9fb69dc8db1603e4a58292ddab7129bb5911d6cea0000000000000000000000000000000004a568c556641f0e0a2f44124b77ba70e4e560d7e030f1a21eff41eeec0d3c437b43488c535cdabf19a70acc777bacca", "Expected": "000000000000000000000000000000000c27ef4ebf37fd629370508f4cd062b74faa355b305d2ee60c7f4d67dd741363f18a7bbd368cdb17e848f372a5e33a6f0000000000000000000000000000000000ed833df28988944115502f554636e0b436cccf845341e21191e82d5b662482f32c24df492da4c605a0f9e0f8b00604", "Name": "matter_g1_add_15", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd80000000000000000000000000000000000874389c02d4cf1c61bc54c4c24def11dfbe7880bc998a95e70063009451ee8226fec4b278aade3a7cea55659459f1d500000000000000000000000000000000091ee883cb9ea2c933f6645f0f4c535a826d95b6da6847b4fe2349342bd4bd496e0dd546df7a7a17a4b9fb8349e5064f000000000000000000000000000000000902d7e72242a5e6b068ca82d0cb71dc0f51335dbd302941045319f9a06777518b56a6e0b0b0c9fd8f1edf6b114ad331", "Expected": "00000000000000000000000000000000122cce99f623944dfebffcdf6b0a0a3696162f35053e5952dddc2537421c60da9fe931579d1c4fc2e31082b6c25f96b500000000000000000000000000000000011366ffa91dc0b7da8b7c1839ea84d49299310f5c1ca244012eed0dd363dbcf4ad5813b8e3fb49361ef05ea8cb18ffe", "Name": "matter_g1_add_16", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000043c4ff154778330b4d5457b7811b551dbbf9701b402230411c527282fb5d2ba12cb445709718d5999e79fdd74c0a67000000000000000000000000000000000013a80ede40df002b72f6b33b1f0e3862d505efbe0721dce495d18920d542c98cdd2daf5164dbd1a2fee917ba943debe0000000000000000000000000000000000d3d4f11bc79b8425b77d25698b7e151d360ebb22c3a6afdb227de72fe432dcd6f0276b4fd3f1fcc2da5b59865053930000000000000000000000000000000015ac432071dc23148765f198ed7ea2234662745a96032c215cd9d7cf0ad8dafb8d52f209983fe98aaa2243ecc2073f1b", "Expected": "000000000000000000000000000000000113ccf11264ff04448f8c58b279a6a49acb386750c2051eab2c90fa8b8e03d7c5b9e87eccf36b4b3f79446b80be7b1d0000000000000000000000000000000004358a1fabfe803f4c787a671196b593981a837ee78587225fb21d5a883b98a15b912862763b94d18b971cb7e37dbcf0", "Name": "matter_g1_add_17", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009f9a78a70b9973c43182ba54bb6e363c6984d5f7920c1d347c5ff82e6093e73f4fb5e3cd985c9ddf9af936b16200e880000000000000000000000000000000008d7489c2d78f17b2b9b1d535f21588d8761b8fb323b08fa9af8a60f39b26e98af76aa883522f21e083c8a14c2e7edb600000000000000000000000000000000034f725766897ed76394145da2f02c92c66794a51fd5ae07bd7cc60c013d7a48ebf1b07faf669dfed74d82d07e48d1150000000000000000000000000000000018f4926a3d0f740988da25379199ecb849250239ad7efcfef7ffaa43bc1373166c0448cc30dcdbd75ceb71f76f883ea7", "Expected": "00000000000000000000000000000000167336aeeb9e447348156936849d518faee314c291c84d732fa3c1bd3951559230d94230e37a08e28e689e9d1fef05770000000000000000000000000000000005366535f7a68996e066ab80c55bb372a15fb0ed6634585b88fe7cafbf818fbfebbf6f6ddd9ca0ff72137594a1e84b35", "Name": "matter_g1_add_18", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010fcfe8af8403a52400bf79e1bd0058f66b9cab583afe554aa1d82a3e794fffad5f0e19d385263b2dd9ef69d1154f10a000000000000000000000000000000000aba6a0b58b49f7c6c2802afd2a5ed1320bf062c7b93135f3c0ed7a1d7b1ee27b2b986cde732a60fa585ca6ab7cc154b00000000000000000000000000000000079e5a154cf84190b6c735bc8cd968559182166568649b813732e4fb4c5c428c8b38e8265d4ef04990c49aa1381f51c8000000000000000000000000000000000ae08e682ef92b4986a5ac5d4f094ad0919c826a97efe8d8120a96877766eae5828803804a0cae67df9822fd18622aae", "Expected": "000000000000000000000000000000000a3d66cf87b1ce8c5683d71a6de4bf829d094041240f56d9071aa84ff189a06940e8e1935127e23a970c78ca73c28bf6000000000000000000000000000000000b2adda87740873c0c59e3ebde44d33834773f0fe69e2f5e7ede99c4f928978a5caaede7262e45fd22136a394b3f7858", "Name": "matter_g1_add_19", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000013c5ebfb853f0c8741f12057b6b845c4cdbf72aecbeafc8f5b5978f186eead8685f2f3f125e536c465ade1a00f212b0900000000000000000000000000000000082543b58a13354d0cce5dc3fb1d91d1de6d5927290b2ff51e4e48f40cdf2d490730843b53a92865140153888d73d4af0000000000000000000000000000000008cefd0fd289d6964a962051c2c2ad98dab178612663548370dd5f007c5264fece368468d3ca8318a381b443c68c4cc7000000000000000000000000000000000708d118d44c1cb5609667fd51df9e58cacce8b65565ef20ad1649a3e1b9453e4fb37af67c95387de008d4c2114e5b95", "Expected": "0000000000000000000000000000000004b2311897264fe08972d62872d3679225d9880a16f2f3d7dd59412226e5e3f4f2aa8a69d283a2dc5b93e022293f0ee1000000000000000000000000000000000f03e18cef3f9a86e6b842272f2c7ee48d0ad23bfc7f1d5a9a796d88e5d5ac31326db5fe90de8f0690c70ae6e0155039", "Name": "matter_g1_add_20", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000053a12f6a1cb64272c34e042b7922fabe879275b837ba3b116adfe1eb2a6dc1c1fa6df40c779a7cdb8ed8689b8bc5ba800000000000000000000000000000000097ec91c728ae2d290489909bbee1a30048a7fa90bcfd96fe1d9297545867cbfee0939f20f1791329460a4fe1ac719290000000000000000000000000000000008e5afc16d909eb9d8bdaaf229ad291f34f7baf5247bbd4cc938278f1349adb4b0f0aacd14799c01d0ca2ed38c937d600000000000000000000000000000000006cf972c64e20403c82fee901c90eaa5547460d57cce2565fd091ff9bc55e24584595c9182298f148882d6949c36c9d5", "Expected": "000000000000000000000000000000000caf46f480ae2ea8e700f7913c505d5150c4629c9137e917357d2a4ba8a7a1c63b8f6e2978293755952fbed7f0ad8d6d0000000000000000000000000000000002e62e715b72eebbc7c366a2390318f73e69203a9533e72340aab568f65105129ffc9889a8bc00a692494d93688c7ec0", "Name": "matter_g1_add_21", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001354dd8a230fde7c983dcf06fa9ac075b3ab8f56cdd9f15bf870afce2ae6e7c65ba91a1df6255b6f640bb51d7fed302500000000000000000000000000000000130f139ca118869de846d1d938521647b7d27a95b127bbc53578c7b66d88d541adb525e7028a147bf332607bd760deac0000000000000000000000000000000013a6439e0ec0fabe93f6c772e102b96b1f692971d7181c386f7f8a360daca6e5f99772e1a736f1e72a17148d90b08efe0000000000000000000000000000000010f27477f3171dcf74498e940fc324596ef5ec6792be590028c2963385d84ef8c4bbb12c6eb3f06b1afb6809a2cb0358", "Expected": "000000000000000000000000000000000dea57d1fc19f994e6bdda9478a400b0ada23aed167bfe7a16ef79b6aa020403a04d554303c0b2a9c5a38f85cf6f3800000000000000000000000000000000000b8d76ccd41ba81a835775185bbf1d6bf94b031d94d5c78b3b97beb24cf246b0c25c4c309e2c06ae9896ed800169eeee", "Name": "matter_g1_add_22", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003f76a6dc6da31a399b93f4431bfabb3e48d86745eaa4b24d6337305006e3c7fc7bfcc85c85e2f3514cd389fec4e70580000000000000000000000000000000010e4280374c532ed0df44ac0bac82572f839afcfb8b696eea617d5bd1261288dfa90a7190200687d470992fb4827ff320000000000000000000000000000000005728a219d128bc0a1f851f228e2bf604a72400c393cfb0d3484456b6b28a2c5061198656f0e106bbe257d849be159040000000000000000000000000000000011f6d08baa91fb2c8b36191d5b2318e355f8964cc8112838394ba1ded84b075de58d90452601dcfc9aa8a275cfec695d", "Expected": "0000000000000000000000000000000012e6d6c518c15cfd3020181ff3f829e29140b3b507b99251cc7f31795128adec817750296bce413bac18b9a80f69ca5000000000000000000000000000000000131ee9b748f6f1eb790adeb9edd0e79d89a9908368f5a6bb82ee0c913061cdfffe75d9ba411a49aa3f9194ee6d4d08a9", "Name": "matter_g1_add_23", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009439f061c7d5fada6e5431c77fd093222285c98449951f6a6c4c8f225b316144875bc764be5ca51c7895773a9f1a640000000000000000000000000000000000ebdef273e2288c784c061bef6a45cd49b0306ac1e9faab263c6ff73dea4627189c8f10a823253d86a8752769cc4f8f200000000000000000000000000000000171696781ba195f330241584e42fb112adf9b8437b54ad17d410892b45c7d334e8734e25862604d1b679097590b8ab0a000000000000000000000000000000001879328fdf0d1fb79afd920e0b0a386828be5b8e0e6024dfeea800ffcb5c65f9044061af26d639d4dcc27bcb5ba1481a", "Expected": "00000000000000000000000000000000111c416d5bd018a77f3317e3fbf4b03d8e19658f2b810dc9c17863310dfb09e1c4ffdbb7c98951d357f1c3d93c5d0745000000000000000000000000000000000af0a252bff336d5eb3a406778557ef67d91776a9c788be9a76cff7727f519a70fc7809f1a50a58d29185cb9722624fd", "Name": "matter_g1_add_24", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001478ee0ffebf22708a6ab88855081daba5ee2f279b5a2ee5f5f8aec8f97649c8d5634fec3f8b28ad60981e6f29a091b10000000000000000000000000000000011efaeec0b1a4057b1e0053263afe40158790229c5bfb08062c90a252f59eca36085ab35e4cbc70483d29880c5c2f8c2000000000000000000000000000000000231b0d6189a4faad082ce4a69398c1734fcf35d222b7bce22b14571033a1066b049ae3cd3bd6c8cec5bec743955cdd600000000000000000000000000000000037375237fb71536564ea693ab316ae11722aadd7cab12b17b926c8a31bd13c4565619e8c894bffb960e632896856bbe", "Expected": "000000000000000000000000000000000d2b9c677417f4e9b38af6393718f55a27dbd23c730796c50472bc476ebf52172559b10f6ceb81e644ec2d0a41b3bb01000000000000000000000000000000001697f241ff6eceb05d9ada4be7d7078ecbbffa64dd4fb43ead0692eef270cb7cc31513ee4bf38a1b1154fe008a8b836a", "Name": "matter_g1_add_25", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000150d43c64cb1dbb7b981f455e90b740918e2d63453ca17d8eeecb68e662d2581f8aa1aea5b095cd8fc2a941d6e2728390000000000000000000000000000000006dc2ccb10213d3f6c3f10856888cb2bf6f1c7fcb2a17d6e63596c29281682cafd4c72696ecd6af3cce31c440144ebd10000000000000000000000000000000015653d1c5184736cdc78838be953390d12b307d268b394136b917b0462d5e31b8f1b9d96cce8f7a1203c2cae93db6a4000000000000000000000000000000000060efeece033ac711d500c1156e4b6dce3243156170c94bc948fd7beae7b28a31463a44872ca22ca49dc5d4d4dd27d1c", "Expected": "0000000000000000000000000000000003996050756117eeab27a5e4fa9acdde2a1161d6fbfff2601a1c7329f900e93a29f55a8073f85be8f7c2a4d0323e95cc00000000000000000000000000000000010b195a132c1cba2f1a6a73f2507baa079e9b5cb8894ea78bebc16d4151ee56fe562b16e2741f3ab1e8640cdad83180", "Name": "matter_g1_add_26", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f46bb86e827aa9c0c570d93f4d7d6986668c0099e4853927571199e1ce9e756d9db951f5b0325acafb2bf6e8fec2a1b0000000000000000000000000000000006d38cc6cc1a950a18e92e16287f201af4c014aba1a17929dd407d0440924ce5f08fad8fe0c50f7f733b285bf282acfc0000000000000000000000000000000018adb42928304cbc310a229306a205e7c21cdb31b9e5daf0ff6bb9437acee80cd8cf02b35dab823155d60f8a83fde5cc0000000000000000000000000000000018b57460c81cab43235be79c8c90dcda40fafcaf69e4e767133aee56308a6df07eac71275597dd8ed6607ffb9151ed9a", "Expected": "0000000000000000000000000000000003c7a7ee3d1b73cf1f0213404363bf3c0de4425ab97d679ed51448e877b7537400f148f14eba588ed241fea34e56d465000000000000000000000000000000000c581b5070e6bb8582b7ee2cd312dfeb5aaf0b0da95cf5a22a505ffba21fc204e26a5e17311d1f47113653ff13349f57", "Name": "matter_g1_add_27", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010cde0dbf4e18009c94ba648477624bbfb3732481d21663dd13cea914d6c54ec060557010ebe333d5e4b266e1563c631000000000000000000000000000000000fb24d3d4063fd054cd5b7288498f107114ff323226aca58d3336444fc79c010db15094ceda6eb99770c168d459f0da00000000000000000000000000000000001da65df8574a864ab454e5f2fa929405501bb73c3162a600979a1145586079361c89839cc0c5a07f1135c94bf059f9c0000000000000000000000000000000002560df402c0550662a2c4c463ad428ab6e60297fbc42a6484107e397ae016b58494d1c46ac4952027aa8c0896c50be3", "Expected": "000000000000000000000000000000000d7a539b679e5858271a6f9cf20108410eb5d5d2b1a905e09a8aa20318efbe9175450385d78389f08f836f5634f7a2f0000000000000000000000000000000000fb624e5f6c4c814b7d73eb63b70237c5de7d90d19ac81cac776d86171a8d307d3cc8c56da14f444fe8cf329ab7e63dd", "Name": "matter_g1_add_28", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008c0a4c543b7506e9718658902982b4ab7926cd90d4986eceb17b149d8f5122334903300ad419b90c2cb56dc6d2fe976000000000000000000000000000000000824e1631f054b666893784b1e7edb44b9a53596f718a6e5ba606dc1020cb6e269e9edf828de1768df0dd8ab8440e0530000000000000000000000000000000005311c11f4d0bb8542f3b60247c1441656608e5ac5c363f4d62127cecb88800a771767cf23a0e7c45f698ffa5015061f0000000000000000000000000000000018f7f1d23c8b0566a6a1fcb58d3a5c6fd422573840eb04660c3c6ba65762ed1becc756ac6300e9ce4f5bfb962e963419", "Expected": "0000000000000000000000000000000000849bbc7b0226b18abbcb4c9a9e78dca2f5f75a2cbb983bd95ff3a95b427b1a01fd909ce36384c49eb88ffb8ff77bb000000000000000000000000000000000087d8d28d92305b5313ca533a6b47f454ddce1c2d0fa3574b255128ef0b145fa4158beb07e4f0d50d6b7b90ea8a8ea8a", "Name": "matter_g1_add_29", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000159d94fb0cf6f4e3e26bdeb536d1ee9c511a29d32944da43420e86c3b5818e0f482a7a8af72880d4825a50fee6bc8cd8000000000000000000000000000000000c2ffe6be05eccd9170b6c181966bb8c1c3ed10e763613112238cabb41370e2a5bb5fef967f4f8f2af944dbef09d265e000000000000000000000000000000000c8e293f730253128399e5c39ab18c3f040b6cd9df10d794a28d2a428a9256ea1a71cf53022bd1be11f501805e0ddda40000000000000000000000000000000003e60c2291be46900930f710969f79f27e76cf710efefc243236428db2fed93719edeeb64ada0edf6346a0411f2a4cb8", "Expected": "00000000000000000000000000000000191084201608f706ea1f7c51dd5b593dda87b15d2c594b52829db66ce3beab6b30899d1d285bdb9590335949ceda5f050000000000000000000000000000000000d3460622c7f1d849658a20a7ae7b05e5afae1f01e871cad52ef632cc831b0529a3066f7b81248a7728d231e51fc4ad", "Name": "matter_g1_add_30", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019c822a4d44ac22f6fbaef356c37ceff93c1d6933e8c8f3b55784cfe62e5705930be48607c3f7a4a2ca146945cad6242000000000000000000000000000000000353d6521a17474856ad69582ce225f27d60f5a8319bea8cefded2c3f6b862d76fe633c77ed8ccdf99d2b10430253fc80000000000000000000000000000000013267db8fdf8f488a2806fead5cffdcbb7b1b4b7681a2b67d322cd7f5985c65d088c70cdc2638e679ed678cae3cc63c80000000000000000000000000000000007757233ad6d38d488c3d9d8252b41e4ab7ee54e4ef4bbf171402df57c14f9977dd3583c6c8f9b5171b368d61f082447", "Expected": "000000000000000000000000000000000c06fef6639ab7dceb44dc648ca6a7d614739e40e6486ee9fc01ecc55af580d98abc026c630a95878da7b6d5701d755c0000000000000000000000000000000007c9a7f2bc7fa1f65c9e3a1e463eb4e3283e47bb5490938edb12abf6c8f5a9b56d8ce7a81a60df67db8c399a9a1df1d4", "Name": "matter_g1_add_31", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000189bf269a72de2872706983835afcbd09f6f4dfcabe0241b4e9fe1965a250d230d6f793ab17ce7cac456af7be4376be6000000000000000000000000000000000d4441801d287ba8de0e2fb6b77f766dbff07b4027098ce463cab80e01eb31d9f5dbd7ac935703d68c7032fa5128ff17000000000000000000000000000000001975bc52669187f27a86096ae6bf2d60178706105d15bce8fe782759f14e449bc97cb1570e87eec5f12214a9ae0e0170000000000000000000000000000000000ca6106d6e6487a3b6f00fc2af769d21cb3b83b5dc03db19e4824fc28fd9b3d9f7a986e79f05c02b3a914ff26c7a78d6", "Expected": "0000000000000000000000000000000002fbf4fba68ae416b42a99f3b26916dea464d662cebce55f4545481e5ab92d3c40f3e189504b54db4c9cd51ecdd60e8d0000000000000000000000000000000008e81e094c6d4ded718ef63c5edfacb2d258f48ccfa37562950c607299bb2dca18e680a620dff8c72dedc89b4e9d4759", "Name": "matter_g1_add_32", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003299542a0c40efbb55d169a92ad11b4d6d7a6ed949cb0d6477803fbedcf74e4bd74de854c4c8b7f200c85c8129292540000000000000000000000000000000013a3d49e58274c2b4a534b95b7071b6d2f42b17b887bf128627c0f8894c19d3d69c1a419373ca4bd1bb6d4efc78e1d3f00000000000000000000000000000000109f6168a719add6ea1a14f9dc95345e325d6b0e56da2f4ecff8408536446894069fa61e81bdaebfc96b13b402fad865000000000000000000000000000000001806aa27c576f4c4fa8a6db49d577cd8f257a8450e89b061cbc7773c0b5434f06bacf12b479abf6847f537c4cbefcb46", "Expected": "0000000000000000000000000000000014e0bd4397b90a3f96240daf835d5fb05da28a64538f4bf42d9e7925a571f831c6e663910aa37dcc265ddd7938d83045000000000000000000000000000000001695d405d4f8ba385ebf4ad25fb3f34c65977217e90d6e5ed5085b3e5b0b143194f82e6c25766d28ad6c63114ca9dcdf", "Name": "matter_g1_add_33", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000121b540a0465b39f2f093112c20a9822fc82497105778937c9d5cdcfe039d62998d47d4f41c76482c31f39a79352beda0000000000000000000000000000000014a461f829e0a76ba89f42eb57dffb4f5544df2008163bd0ea1af824f7ff910b27418a0e4f86cb8046dc1f3139cab9af0000000000000000000000000000000019d3623a7866933e2d73214ceb2e56097a1b047db5943c3ecb846890aa02250126e90fc76a729a952cef895bd154cc7d000000000000000000000000000000000e87c376bbd695a356ef72226ac7ef6a550d99e9693d8485770a686e568ae28c038ee201d3f2ea38362046236ade91cd", "Expected": "000000000000000000000000000000000ffeab47985bd9b3e10ce27c6636bbda336dcf540cd37eccc3faec2adff2d97dd126633bd83a7d3c8c73c3623bdf0ba2000000000000000000000000000000001992eca4b1e924b360d57ca98b543ab496a8b55bd288d23f03bcc1b22f6bc76d95b12f47c3e305812097253c73b876dd", "Name": "matter_g1_add_34", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001383bc4d6c748d5c76ab4ba04f8fcd4c0fed9a49ea080c548893440819833ad72a8249f77391d5fbff78329eb319d3830000000000000000000000000000000016404bd07b6c6480af2d23301940e61817ee2e61fc625c100b31e1b324c369a583b61048dd57ab97b80b1fe6cd64c5c300000000000000000000000000000000163aaecf83d6c77a5d7417e73f5cf9d71a6aedfd194b2f3b53c608d06a228190f4f79ac57b029d77504c72744df4ecc0000000000000000000000000000000000416e6f9ca188d16daa2c28acd6a594f8fcb990eaa26e60ca2a34dfcad7ad76c425b241acedf674d48d298d0df0f824d", "Expected": "000000000000000000000000000000001812bcb26fa05e0ab5176e703699ab16f5ef8917a33a9626ae6ff20f2a6f4a9d5e2afe3a11f57061cbaa992e1f30477f000000000000000000000000000000000680acf0b632cb48017cb80baa93753d030aa4b49957178d8a10d1d1a27bbdc89ac6811a91868b2c181c5c0b9b6caf86", "Name": "matter_g1_add_35", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006bc68c6510c15a5d7bc6eebce04f7c5fce3bb02f9f89ea14ab0dfb43645b6346af7e25a8e044e842b7a3d06fe9b1a0300000000000000000000000000000000053ee41f6a51c49b069f12de32e3e6b0b355cd2c3ba87a149c7de86136a5d9c5b7b59f2d1237964e548d1b62ec36c8db000000000000000000000000000000000aba7362eee717d03ef2d4f0fef2763822115fcc8fb9e2e8243683b6c1cde799ebc78f23812e557de2cc38e2b4a2e56700000000000000000000000000000000170833db69b3f067cf5c4c4690857e6711c9e3fcad91ca7cd045e9d2f38c7b31236960e8718f5dd4c8bfb4de76c6c9b9", "Expected": "00000000000000000000000000000000196ffe76a4b726fa8dd720cc1cd04c040724cb18ec10915e312eaa90d124100b08f0ce3a7fc888f46914319a3d7581f4000000000000000000000000000000000e2612357059ca6dbb64efb98ef19370560c9e83e2aad7ab2d9015e2444fe4d8c796b5577584aac9f63258beb5ae863c", "Name": "matter_g1_add_36", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024ca57c2dc2a7deec3082f2f2110b6788c57a8cdc43515044d275fe7d6f20540055bde823b7b091134fb811d23468ce0000000000000000000000000000000009cd91a281b96a881b20946fda164a987243c052378fcd8fee3926b75576dfa1d29a0aaca4b653da4e61da8257721808000000000000000000000000000000000a98ae36c690f2e3be8100f43678be5a1064390e210328dd23f61f5a496b87398db2798580edeabc6273fb9537fa12880000000000000000000000000000000009aedf77bb969592c6552ae0121a1c74de78ba222b6cd08623c7a34708a12763b5ff7969cf761ccd25adc1b65da0f02d", "Expected": "00000000000000000000000000000000072334ec8349fc38b99d6dea0b4259c03cd96c1438c90ef0da6321df2495892de031a53c23838ca2b260774fa09b5461000000000000000000000000000000000e4535767c2477c4f87c087540c836eeffcd0c45960841f9c3561a8a5f8e61ab98b183b11192b8e7ea1c9c7717336243", "Name": "matter_g1_add_37", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001305e1b9706c7fc132aea63f0926146557d4dd081b7a2913dae02bab75b0409a515d0f25ffa3eda81cf4764de15741f60000000000000000000000000000000011bf87b12734a6360d3dda4b452deede34470fba8e62a68f79153cc288a8e7fed98c74af862883b9861d2195a58262e00000000000000000000000000000000015c3c056ec904ce865d073f8f70ef2d4b5adb5b9238deaa5e167d32f45cad4901aa6d87efa2338c633e7853ce4c19185000000000000000000000000000000000a15f1aa6e662f21d7127351a1655821c943c4cf590e3c9e60c9ab968b4a835f87fb8d87eee6331ee4e194e5f1ea91f4", "Expected": "000000000000000000000000000000000140fb6dcf872d0a3bff3e32a0cb4a7fb7e60ee4fb476bb120c4ce068e169d72e1c167d7fda321280d5855983d5a9af800000000000000000000000000000000108f54a4ec3ba26dd614f4d94c5c82652583906986158ad40ffea54c17703fa4b0bd7806633e1c0318d06e8dc7d41cde", "Name": "matter_g1_add_38", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000012662b26f03fc8179f090f29894e86155cff4ec2def43393e054f417bbf375edd79f5032a5333ab4eba4418306ed0153000000000000000000000000000000000f26fdf1af1b8ad442ef4494627c815ca01ae84510944788b87f4aa2c8600ed310b9579318bc617a689b916bb7731dcb000000000000000000000000000000000307841cb33e0f188103a83334a828fa864cea09c264d5f4343246f64ab244add4610c9ccd64c001816e5074fe84013f000000000000000000000000000000000e15bbeb6fff7f1435097828f5d64c448bbc800f31a5b7428436dcffd68abc92682f2b01744d7c60540e0cd1b57ab5d4", "Expected": "000000000000000000000000000000000a1b50660ed9120fff1e5c4abb401e4691a09f41780ca188cea4b1c2d77002f08ce28eb1caa41ee3fe73169e3651bb7f00000000000000000000000000000000125439ac3b45c698a98063ab911364bd3c6dd2a69435d00d6edf89fc5566b33038e960a125e5e52141abb605587942fe", "Name": "matter_g1_add_39", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001837f0f18bed66841b4ff0b0411da3d5929e59b957a0872bce1c898a4ef0e13350bf4c7c8bcff4e61f24feca1acd5a370000000000000000000000000000000003d2c7fe67cada2213e842ac5ec0dec8ec205b762f2a9c05fa12fa120c80eba30676834f0560d11ce9939fe210ad6c6300000000000000000000000000000000013866438b089d39de5a3ca2a624d72c241a54cbdcf5b2a67ebdd2db8373b112a814e74662bd52e37748ffbfc21782a5000000000000000000000000000000000d55454a22d5c2ef82611ef9cb6533e2f08668577764afc5bb9b7dfe32abd5d333147774fb1001dd24889775de57d305", "Expected": "000000000000000000000000000000000037b4e8846b423335711ac12f91e2419de772216509d6b9deb9c27fd1c1ee5851b3e032bf3bcac3dd8e93f3dce8a91b00000000000000000000000000000000113a1bf4be1103e858c3be282effafd5e2384f4d1073350f7073b0a415ecf9e7a3bfb55c951c0b2c25c6bab35454ecf0", "Name": "matter_g1_add_40", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000181dc6fd3668d036a37d60b214d68f1a6ffe1949ec6b22f923e69fb373b9c70e8bcc5cdace068024c631c27f28d994e5000000000000000000000000000000000b02ca2b0e6e0989ea917719b89caf1aa84b959e45b6238813bf02f40db95fbb3bf43d3017c3f9c57eab1be617f180320000000000000000000000000000000017440fd557df23286da15f9a96bb88cfbc79589b1c157af13baf02c65227dc0a5bdec6f2f300083ff91dae395ed8cb75000000000000000000000000000000000ad09b4290842cc599d346110fdb39ededbb1d651568579564e274465f07b8f77eeaf00fece0c10db69c2125de8ab394", "Expected": "0000000000000000000000000000000007c158b4e21566742f7e4e39a672bd383e27864505acef4ef8c26f8b0a9db418f9c088b555b8e9eb25acf9859b1207b40000000000000000000000000000000016e06a1ace89f992d582af0de7662ef91c0a98f574306f6f6d0d8d5e80166638d2deef70105cce2e9b20faa9d6315510", "Name": "matter_g1_add_41", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001329a75975b714c861064d743092866d61c4467e0c0316b78142e6db7e74538a376a09487cb09ee89583d547c187229000000000000000000000000000000000096713619bf088bd9e12752cab83e9cdd58296ada8d338c86a749f00ba014087a3836ce10adaaf2e815f431235bff4f0000000000000000000000000000000000d7ccc3a4efdfe1a92a88e453933b8216016091f1b9d575faf18a5b3abf90daf077813167a3f4acce7359472dee544bb00000000000000000000000000000000128008c075ab176100e755cbb8de5b9ff0e9a78114f862d26ed030d9c1d1dea1c21ec8ae4d82a84d3ff5ae4c1cd6f339", "Expected": "000000000000000000000000000000000b84f9de79c748e37797c629cb78b86b4b736b199f161b30147b5dacf6eabe0b54afce40d5dacfe9a8ee8da5ef5b49de0000000000000000000000000000000010277ad094bb9a3b96379b1366dd90125b51a21ebeb4f776a81d9d9c1f37ab58c32a884a26fa32c83783ed0eef42b820", "Name": "matter_g1_add_42", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001195502bc48c44b37e3f8f4e6f40295c1156f58dbc00b04b3018d237b574a20512599d18af01c50192db37cb8eb2c8a90000000000000000000000000000000002b03f02b45aa15b39e030c4b88c89a285dff5c4bbfe16f643f3f87d91db774f8ab7019285fda0b236ff7eec16496e5e00000000000000000000000000000000008da4a93d5ffcdaa0adc736a59f0c187ae3bf11ecb5e9e6f6aedea976a47757739042200b4c4593c2dd5db555425531000000000000000000000000000000000a6fdb2d4160c6c35223daa6fa10d0b1073de07fe4f2eba28e65ed049ff8d8852ed0538b30759fe7a0d944009ddf9a6f", "Expected": "000000000000000000000000000000000d740bd1effd8674250618af0358ad0b83bbc787f0264af9c2ada72fa5431be909e82155da1de0211f46fb307e9949f0000000000000000000000000000000000ddf62c91d587a14b64feef07da52c081b40fbbf9a0f2eae8b66022e0850fc94de6a467e7e4f580c7f2c806f6c6ed8cf", "Name": "matter_g1_add_43", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d7e1651f3e172dcca8774a7a0d58ab47178d3e759933289e1d3eb0da414160ff9e890a608bf8ccdf2820c4aea6e11cb00000000000000000000000000000000185e8671e2ddb8e36380e39fe4eafefbac9769935603c28caac7d3f7f0f3e8ad14e925024b55aeb67d68b219875c9d790000000000000000000000000000000003258d7931a1d72ab6344c7e96c0dbd435a7909fe68cc679c08ca9b62f7a6a04863082cbcfdbe9a736625d895e4f3bdb0000000000000000000000000000000009ee3e470e2b2cebc955ba3444b7e478f887138e36c13bd68490689122627269ea5e7ce22dd9c69792394a24187103d6", "Expected": "000000000000000000000000000000000af674691f5d87655f0066188fac5013f31b4169a0181d3feb7ac3beae0d9a3429d4125f099ee344f644a2de8b941f9f00000000000000000000000000000000042a9603b8e4a6c37d59ede3a1398f5f80c5298da66de575a204ee28811d9f7c7c0dd40cef3769bd72a2156b9eb620c8", "Name": "matter_g1_add_44", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001454d4a82163a155446467164904cefd7e1e3c67ae99bf65c581a75c72716fb011e2fd030eaf3d36977fbb0ff5156e2700000000000000000000000000000000123f973ab6bd3c2e5b0512a0c77ea0ac3003fd891e1262137f9444cd07b927b564e618205ba09220320ea1aa4564e820000000000000000000000000000000001833807f1ced52399305419450355499a63411837ee61ad681559d59561db18511eb1e8ad3161e7fe30016b560d18b8f00000000000000000000000000000000198b11b31586e17964a4a4ccdee85703163d2106481833e71f26327a589bafb43578d08d87f6cb19c7a04b4ca92392bf", "Expected": "000000000000000000000000000000001081c3359a0fadfe7850ce878182859e3dd77028772da7bcac9f6451ac6455739c22627889673db626bbea70aa3648d50000000000000000000000000000000000f4e8766f976fa49a0b05ef3f06f56d92fe6452ff05c3fac455f9c16efadf1b81a44d2921bed73511dda81d6fc7478e", "Name": "matter_g1_add_45", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000178e6828261ee6855b38234ed15c27551bb1648ac6ec9a9e70744643cd1f134b2309dd0c34b1e59ddfe3f831ab814c90000000000000000000000000000000002ec930fb58c898ede931384c5a5f9edd2f5c70b8c3794edb83a12f23be5400949f95e81c96c666c1a72dffb50b811580000000000000000000000000000000007dc719ae9e3f1e11d3ed4747a546a7b973ccb1967adb1b3066645a8bde9632bcfa3530e768f088ddbc022b169e67cbf000000000000000000000000000000000bbf9cf884b19c84045da1cead7dcd9fdbf39d764ff1ad60d83ed1e4fd0ce0554f0fb618203952cf02a7c4ba466c66b8", "Expected": "000000000000000000000000000000000f60d66fd1ed5eb04f9619d6458c522cc49f5ace111aff2b61903b112559972f80ac615591463abf2b944c4f99d4c03e000000000000000000000000000000000001a1abfa869be2cda6bd7e05454a8735e1b638db7e1b3715708539c2d14ade53069c7e68b36d3b08cff80837028b7d", "Name": "matter_g1_add_46", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001ea88d0f329135df49893406b4f9aee0abfd74b62e7eb5576d3ddb329fc4b1649b7c228ec39c6577a069c0811c952f100000000000000000000000000000000033f481fc62ab0a249561d180da39ff641a540c9c109cde41946a0e85d18c9d60b41dbcdec370c5c9f22a9ee9de00ccd0000000000000000000000000000000014b78c66c4acecdd913ba73cc4ab573c64b404a9494d29d4a2ba02393d9b8fdaba47bb7e76d32586df3a00e03ae2896700000000000000000000000000000000025c371cd8b72592a45dc521336a891202c5f96954812b1095ba2ea6bb11aad7b6941a44d68fe9b44e4e5fd06bd541d4", "Expected": "0000000000000000000000000000000015b164c854a2277658f5d08e04887d896a082c6c20895c8809ed4b349da8492d6fa0333ace6059a1f0d37e92ae9bad30000000000000000000000000000000001510d176ddba09ab60bb452188c2705ef154f449bed26abf0255897673a625637b5761355b17676748f67844a61d4e9f", "Name": "matter_g1_add_47", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008d8c4a16fb9d8800cce987c0eadbb6b3b005c213d44ecb5adeed713bae79d606041406df26169c35df63cf972c94be10000000000000000000000000000000011bc8afe71676e6730702a46ef817060249cd06cd82e6981085012ff6d013aa4470ba3a2c71e13ef653e1e223d1ccfe900000000000000000000000000000000104ee0990ba4194916f670f44e254200971b67a18ed45b25c17be49df66e4f9b934bac8c1552ecc25bdaa3af55952076000000000000000000000000000000000591094d9d89afe025ca1832d7f3e60444f83e72403a434b42216b6c4213980d29e4ef0c64ae497006de550c1faa9425", "Expected": "0000000000000000000000000000000006db0cc24ffec8aa11aecc43e9b76a418daac51d51f3de437090c1bcaabace19f7f8b5ceb6277d6b32b7f3b239a90c4700000000000000000000000000000000069e01f60ca7468c6b9a247c79d18cf3d88bf5d1d62c76abf9237408edeba05dea744205ac5b501920f519bb847bb711", "Name": "matter_g1_add_48", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000120ddc1cd9e3a7b298673b1036d162c31dbb35d6e83b39b2564b3be16e446a836c96907e8a6af1e677e906bf5ed73159000000000000000000000000000000000fa57c1436615442bbb049d08ac46e501c07736cd239298752bb94d1904bd38cc687759987cadd99bd3c4d45ba07193a0000000000000000000000000000000004840d028d0c0f056aeb37b7a8505325081e9822ef26046f2da72f2155c20987dd51f4b5577c5395e24288b71d2ce5140000000000000000000000000000000015f231a233e997633c1d6492e0df358fb658ae29d0f53928c8a0578484c899a699178ca3223772210063aa08991c3fff", "Expected": "000000000000000000000000000000000fa72bf2d7d564cc4982b9f2cdca743d2ac14f0f1be4218dbafb8b93a9277e55273487a5d2857fd3f731ac4ee469a6a1000000000000000000000000000000000fce44f886453c6ca5ebde9af41d2be92d1126e9897d72978a179dd7eebeed6242b6e9718604ab0c9369529a0426a575", "Name": "matter_g1_add_49", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e3ccaa4fa358a5a885094cbb0b8baa106fbcca66edbe31511ac2f6f3d14edbd8701979d6e4690853555c625091392b600000000000000000000000000000000175bdd42583cbbf733242510c152380525aff7649273acef1ec20569804ffba7f029ca06878dbafde84540cece1738220000000000000000000000000000000004877b97faa1d05d61ab65001110bf190d442cabcd6d4d1b9c1f0e513309aebd278f84a80354dfdef875769d00ec2c7500000000000000000000000000000000187066cccb5008bc2ffd0bcd1b227a5a0fe0cd4984316ba3cfd5113c4632a04c56cbda8d48993bd0dd50e9b7ce2b7ee9", "Expected": "0000000000000000000000000000000019ecd38afacc6b281b2515270157328e18039d51574bae0f7e0ef16c3f6da89f55ddee9e3bbb450ad51fe11edfd9f18d00000000000000000000000000000000088a5e292761bbf7a914a9f723de099035e91bd3c1fe9cd50728a4ceaa4fd3953683f30aa8e70ba0eb23919092aa9e22", "Name": "matter_g1_add_50", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001bc359baeac07a93aca770174ea6444aac9f04affdaa77c8a47b30c60ee2b527c061a4344139264e541d4134f42bfd0000000000000000000000000000000000cbf7a31e6fef4f4664bca4bc87ec7c0b12ced7224300aa4e1a6a7cbdedfcef07482b5d20fa607e3f03fdd6dd03fd10c000000000000000000000000000000001881f5aba0603b0a256e03e5dc507598dd63682ce80a29e0fa141b2afdadf6168e98221e4ee45d378cee0416baaadc49000000000000000000000000000000000070d255101319dd3a0f8ca3a0856188428c09de15475d6b70d70a405e45ab379a5b1f2e55f84bd7fe5dd12aeedce670", "Expected": "0000000000000000000000000000000011ccd455d5e3eba94567a17bcd777559b4ff1afa66fd6f05f99c69937404290a2f1c83cfd6c2c25886ebff4934332c0e0000000000000000000000000000000010920aa3d5974df25530610ef466adce3d51fd6a508d4b1111739c586dfd7ba9040836e075fd812fe111d92f25b67f51", "Name": "matter_g1_add_51", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006b06ae8cb0981bf5167ad51e19d132db77548c4376697f855c8397b835743c42771096ed7b0a4b18af9494e42ee89aa0000000000000000000000000000000005aa892b0a056ff61706430f1daa3f0263dc01337eadabd8a7fd58152affd9aaa329e8c11ea98692134d9718cb4119bf000000000000000000000000000000000b53e5339f25bcd31afd091362874b5042c0b762ed7425341331630addbc4dccc299936e1acdf89823c36867d46c6f28000000000000000000000000000000000fc3c6b522268511dd52826dd1aee707413d925ee51aeb0e5d69c0e3eb697fabbc14783b5007e240cc0c53c299a40ada", "Expected": "00000000000000000000000000000000060773b9b8f3babdba3db27089b7be3e6e287a635dbae19576039d34ae18a0e6413278bfa280570f6329ae05cdb693fd00000000000000000000000000000000075fb9527f99a8c8db41e67baaf1deafffd2c134badb1b3478a26b5501b31dca858fad6f0d52f412d5631ecfa72eece4", "Name": "matter_g1_add_52", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000015dc9f87213e4781863ad43f6bbccd547967d9bcf6a35d95d530cbfbf0d7307981aee5bc4ccd41254841651717393a0300000000000000000000000000000000166ce33c0482b5957c6e746c16908ba579d6402b230bc977d3ff29ac2a4a800748d9c14608f2519e2ac4d1fe4daf29b2000000000000000000000000000000001693f4ebab3fed548784264196fb01cf55311399f47cdad74a9543bda5d1ca682a00ee04bb0b3954d5a0f00ceef97a750000000000000000000000000000000017f4019c23bd68e84d889857c417b17aa96c780fec3c1ed6ca75100cc70c97a8bb8272ad4c6de896d76dc2a1b09c7a61", "Expected": "000000000000000000000000000000000a3ea8afdc83794f18f9a9427bcd60a355196925d38fdf74ab09d4a08279647b2da6f1fbe30948a785497d6c6dddc2a9000000000000000000000000000000001263c88f1ca3e574cafac21641432d45ee01e1b05eba95716565922abe28c7f0fb004c255afcbfa10cf7959bbe6b00d7", "Name": "matter_g1_add_53", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000171fbc9cec717964c4324aa0d7dcf56a59b947c24a9092157f4f8c78ae43b8e4222fd1e8acdbf5989d0d17ea10f6046300000000000000000000000000000000148b5454f9b9868aefd2accc3318ddabfe618c5026e8c04f8a6bce76cd88e350bebcd779f2021fe7ceda3e8b4d438a0b0000000000000000000000000000000005d5602e05499a435effff3812744b582b0cd7c68f1c88faa3c268515c8b14f3c041b8ae322fe526b2406e7c25d84e61000000000000000000000000000000001038eaf49e74e19111e4456ebba01dc4d22c7e23a303d5dec821da832e90a1b07b1a6b8034137f1bfdcddeb58053a170", "Expected": "0000000000000000000000000000000019258ea5023ce73343dcd201ec9be68ec1ee1cb4e5b9964309d801c2bc523343c8ebc4f8393a403c7881e5928f29db14000000000000000000000000000000001423bf52daefb432162ce2bd9ef78b256ff3b24d0a84766b87119489fd56ecf6156b2884c8a7e1220e493469723cd7f8", "Name": "matter_g1_add_54", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018724e2b9a2f383329207ee85577805f35d5c5bb9f6903e3c962e57ab7eb9d1639d1e9adbde53499863b299f576325a00000000000000000000000000000000016d2c22eabd4a06a5ae67b890a25fbede7d0e96c625b80329b19be6aa861f44b6e85778130d0bdf69f2abd491ee9751a0000000000000000000000000000000002626f28d421d9d1c28f5e1eb5a51ada9610dbdd62cd33c4078d2fdfc18dbd092e2847cf705ba5fcd8c1a60c1cc34a3b0000000000000000000000000000000001f7b8cfdb7e406c920f5fdecae45fb4be736f209480ccb455f972c6b1a1aebdd5ba116903c46ded72ce37cd8836e871", "Expected": "00000000000000000000000000000000081d674f5b9c7c64673c39fe33f4f3d77271e826dcb4dfd2591062e47c931237e8539ef9c886c9e112eccc50da4f63fd00000000000000000000000000000000141b700695839110ed4ced5f8a3f4fd64a8086805358ab4a5abd2705592e616cd95ff01271212ca9014dcb68d8157ba0", "Name": "matter_g1_add_55", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010fcf5e5e478ac6442b218ce261878d8f61b405c0b9549512e23ead1f26a2240771993f8c039fbce4008a1707aeaaf25000000000000000000000000000000000f1afe9b199362f51cc84edb1d3cf2faf8e5bc0a734a646851ab83e213f73a3734114f255b611ec18db75694dcb0df91000000000000000000000000000000000259e307eacb1bc45a13811b02a7aeaaf4dc2bb405dcd88069bb6ec1c08a78905516169bd3440a36921764df0ef3a85b000000000000000000000000000000001263372b675124f6cc19ca16842ba069c5697dbf57730875fe72c864a81189d7d16fe126b5d24953a0524f96dbac5183", "Expected": "000000000000000000000000000000001908aa3a640817e31a4213156fbd4fd39ab39eb931091670a0e06399def71a689e67286f90d38ce9f97cb85f6488d9c8000000000000000000000000000000000764e46b6b82aa2f8862d28e9d543a751a9de855645377b9633cc098c2110ec6ed4fd30f0044ea5868c93f950f6cfd24", "Name": "matter_g1_add_56", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f75bc9feb74110697c9f353686910c6246e587dd71d744aab99917f1aea7165b41deb333e6bd14843f28b2232f799830000000000000000000000000000000019275491a51599736722295659dd5589f4e3f558e3d45137a66b4c8066c7514ae66ec35c862cd00bce809db528040c04000000000000000000000000000000000a138203c916cb8425663db3bbff37f239a5745be885784b8e035a4f40c47954c48873f6d5aa06d579e213282fe789fa0000000000000000000000000000000016897b8adbc3a3a0dccd809f7311ba1f84f76e218c58af243c0aa29a1bb150ed719191d1ced802d4372e717c1c97570a", "Expected": "0000000000000000000000000000000004ad79769fd10081ebaaed9e2131de5d8738d9ef143b6d0fa6e106bd82cfd53bbc9fab08c422aa03d03896a0fb2460d0000000000000000000000000000000000bb79356c2d477dfbcb1b0e417df7cb79affbe151c1f03fa60b1372d7d82fd53b2160afdd88be1bf0e9dc99596366055", "Name": "matter_g1_add_57", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000a87d0ccfb9c01148703d48993de04059d22a4cc48c5dabd2571ad4f7e60d6abfbcc5fb3bf363fd311fec675486c2a20000000000000000000000000000000000a896c5a84cbd03e52ae77000eb0285f5704993664a744a89ff6b346efd2efec1a519b67229a3b87e1f80e6aa17e29460000000000000000000000000000000019f60f2cf585bdbc36947f760a15fa16c54cf46435cc5707def410202a3f4fa61b577ab2481e058b0345982d3e3d1666000000000000000000000000000000000a70b7bbc55e1f3e11e9eb7efd79d4e396742de48d911ddff8dd0a7cf10422423d5e68021948e1448e92c2e07c194776", "Expected": "000000000000000000000000000000000a87e7e115ccdf3c2c1a2716491d449c3f8329e73d264088f4af444d43cf05f8be0410da273ce7eeb32969830195b7e70000000000000000000000000000000010a973d6e4bd85105bf311eb0dcfdc0a5d38dba1c099206b60f2e2df4791fd58846bf19d83769506e1561212920b4895", "Name": "matter_g1_add_58", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d35ffa284655a94c3050213f4f14e927c162818bbfd0480bad2e07000dd3081274056715c96408f243589d83365c9f20000000000000000000000000000000001450bddfa14033ed8cdb94386715013ed9b2c4f9d65944e9d32c0b3545a085113e173e5afcfccb78878414a464d318400000000000000000000000000000000109bd6e0636a7f96ffe2ce8e109171efaacfcd60189c7050259ddedd15dd257e11f2585bbd84e4a3f4d8fc5fbc0289cf0000000000000000000000000000000019b420d778da53aed81b48f2c9b9eb399e771edd5e124a41577452b409ca2503e2798cd25d791f489352fc7b7268ae23", "Expected": "00000000000000000000000000000000162bd29f2de10002c1c446bd9583e89751fb91703ad564e7951d41673e28d214729aa9b4b9875c397989df197c912d5f0000000000000000000000000000000004d393181871c93714afab6c33c16f68ec391fbfcad606ac65cc1d070949c099e21f710e2fe0dd4e4f50f99ea2167a7e", "Name": "matter_g1_add_59", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000344cafaca754db423544657de1b77025164ccc702f8d45697fb73602302a3cb4511c38f0a76a37415d683398f35556500000000000000000000000000000000120935947070451885bf0c328bd83def193831ab9353844a01130074f16a1ff4d20df8459b5ad6a57d5f1959d37aae920000000000000000000000000000000012bb529b45ad7875784b62a7281d025002f15e7f86cc33555e7472df60da2cb15d37c8bf628142818c0711ee9047fb4d000000000000000000000000000000000baa801623312d95e2b51ce86373fea516007e468f265d974c2327c1779830db180bed6dbe8a64f0959aad26eaafb8d9", "Expected": "0000000000000000000000000000000010c4b328d264893099d89ba81b0765d0642bf36b0ac043be090c7b4f7987d21a906228c3c208c4ec5123d577efb0771f0000000000000000000000000000000016d08ce3bf755da7d4bae5f4b06b37845c17a717329c547e941be93325a04e9a5095d3f6e6c6f9ec3b1a740f59d88919", "Name": "matter_g1_add_60", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008797f704442e133d3b77a5f0020aa304d36ce326ea75ca47e041e4d8a721754e0579ce82b96a69142cb7185998d18ce00000000000000000000000000000000144f438d86d1d808d528ea60c5d343b427124af6e43d4d9652368ddc508daab32fd9c9425cba44fba72e3449e366b1700000000000000000000000000000000002c9e50f37ff0db2676637be8a6275fce7948ae700df1e9e6a0861a8af942b6032cca2c3be8b8d95d4b4b36171b4b0d400000000000000000000000000000000050f1a9b2416bbda35bac9c8fdd4a91c12e7ee8e035973f79bd35e418fd88fa603761e2b36736c13f1d7a582984bd15e", "Expected": "000000000000000000000000000000000f798f8d5c21cbce7e9cfcbb708c3800bf5c22773ec5b44590cdbb6f720ccddf05a9f5d5e6a51f704f7c295c291df29f000000000000000000000000000000001483903fde5a968dba6924dfac3933cd39f757e2f89120f4ca9d03aaaf9e18252bdb5c5d3939471666b8a42aeb31b4ed", "Name": "matter_g1_add_61", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000000707c711f77bb425cddc71ecf96a18b6eb0bed7f012c4f6cc9431003f2e1ac17f7c1f68c4965a4fcc273a3db93451d000000000000000000000000000000001211464c91c7e78b00fe156da874407e4eeb7f422dbd698effb9a83357bf226d3f189f2db541eb17db3ed555084e91ec000000000000000000000000000000000332cdc97c1611c043dac5fd0014cfeaee4879fee3f1ad36cddf43d76162108e2dc71f181407171da0ceec4165bcd9760000000000000000000000000000000015b96a13732a726bad5860446a8f7e3f40458e865229bd924181aa671d16b2df2171669a3faa3977f0ee27920a2c5270", "Expected": "0000000000000000000000000000000001c762175f885a8d7cb0be11866bd370c97fb50d4277ab15b5531dacd08da0145e037d82be3a46a4ee4116305b807de6000000000000000000000000000000000bb6c4065723eaf84d432c9fde8ce05f80de7fe3baed26cf9d1662939baac9320da69c7fe956acdd085f725178fe1b97", "Name": "matter_g1_add_62", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004b3c0e8b240b79c55f02833c2c20fa158e35c941e9e8e48247b96cb1d4923641b97e766637a3ced9fbef275ca9bd1ea000000000000000000000000000000000b4e7355aea3488234552d3dddfa2d1ad3164056407770e6c54f764193c9dc044cb7f2b157a1c4153b2045867d6f99c50000000000000000000000000000000003ebca978ea429eedad3a2c782816929724fc7529fbf78ea5738f2ca049aab56c1773f625df2698433d55db7f5fc8ca2000000000000000000000000000000000d2477f57b21ed471a40566f99b7c2d84ce6b82eaf83a6c87a7c21f3242959c8423d4113b7fd8449277b363303bb17b0", "Expected": "00000000000000000000000000000000071dc0f985703bd8335093779de651b524c02faca5fc967766abd3f6f59176d2046d7a14d18c0b757b8c9802e44ebcd300000000000000000000000000000000154e5cb66be8979ee276e8e0f240557e3f7dc074c497293af589256652da21d66a6e6b00ca5bfa6f89963fbd5bc6cf48", "Name": "matter_g1_add_63", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001465358836eb5c6e173e425f675aa231f9c62e9b122584078f2ab9af7440a4ce4ac2cd21ce35a0017b01e4913b40f73d00000000000000000000000000000000170e2da3bca3d0a8659e31df4d8a3a73e681c22beb21577bea6bbc3de1cabff8a1db28b51fdd46ba906767b69db2f679000000000000000000000000000000001461afe277bf0e1754c12a8aabbe60262758941281f23496c2eeb714f8c01fd3793faf15139ae173be6c3ff5d534d2bc00000000000000000000000000000000148ad14901be55baa302fa166e5d81cc741d67a98a7052618d77294c12aea56e2d04b7e497662debc714096c433e844e", "Expected": "0000000000000000000000000000000012c4dd169f55dfb5634bc4866f7cbd110648b5392ace6042b5f64aba3278f24085227521b7834864f00d01ec9998dd6800000000000000000000000000000000102d7a495850195424677853da01d70caeb6c0af5270bcfffbc2d4252c0f3680518cd8d2a0a6dbbbc7b52923a5b26562", "Name": "matter_g1_add_64", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ab6e2a649ed97be4574603b3b4a210f0748d8cddf132079e0543ec776ceb63902e48598b7698cf79fd5130cebaf0250000000000000000000000000000000000d55b3115d2bfcd1b93c631a71b2356c887b32452aae53ffd01a719121d58834be1e0fa4f22a01bbde0d40f55ad38f2c0000000000000000000000000000000002218b4498c91e0fe66417fe835e03c2896d858a10338e92a461c9d76bcecd66df209771ae02c7dcace119596018f83c000000000000000000000000000000001990233c0bae1c21ba9b0e18e09b03aeb3680539c2b2ef8c9a95a3e94cf6e7c344730bf7a499d0f9f1b77345926fef2d", "Expected": "0000000000000000000000000000000010c50bd0f5169ebd65ee1f9cd2341fa18dd5254b33d2f7da0c644327677fe99b5d655dd5bfdb705b50d4df9cfce33d1400000000000000000000000000000000088e47ffbbc80c69ec3c5f2abe644a483f62df3e7c17aa2ff025553d1aaf3c884a44506eff069f4c41d622df84bbafa1", "Name": "matter_g1_add_65", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001654e99ebd103ed5709ae412a6df1751add90d4d56025667a4640c1d51435e7cad5464ff2c8b08cca56e34517b05acf10000000000000000000000000000000004d8353f55fdfb2407e80e881a5e57672fbcf7712dcec4cb583dbd93cf3f1052511fdee20f338a387690da7d69f4f6f7000000000000000000000000000000000160e0f540d64a3cedba9cf1e97b727be716bbfa97fbf980686c86e086833dc7a3028758be237de7be488e1c1c368fe100000000000000000000000000000000108250b265bd78f5e52f14ef11515d80af71e4d201389693a5c3ef202cf9d974628421d73666ead30481547582f7abaf", "Expected": "00000000000000000000000000000000168af33c85ae6e650375ed29b91218198edd9135683f6a1428211acdcbf16bdf86f0a95575e47ee0969587a10fa9f3c90000000000000000000000000000000012d9f5d692c870b3da951b6d07797c186a8ddc89b9f08a1c0b8f0f119f10ca0b155e8df5424cf48900ad3bf09ce6872a", "Name": "matter_g1_add_66", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001bb1e11a1ccc0b70ce46114caca7ac1aba2a607fea8c6a0e01785e17559b271a0e8b5afbfa8705ecb77420473e81c510000000000000000000000000000000018f2289ba50f703f87f0516d517e2f6309fe0dc7aca87cc534554c0e57c4bdc5cde0ca896033b7f3d96995d5cbd563d20000000000000000000000000000000002fa19b32a825608ab46b5c681c16ae23ebefd804bb06079059e3f2c7686fe1a74c9406f8581d29ff78f39221d995bfd000000000000000000000000000000000b41ea8a18c64de43301320eaf52d923a1f1d36812c92c6e8b34420eff031e05a037eed47b9fe701fd6a03eb045f2ca7", "Expected": "000000000000000000000000000000000b99587f721a490b503a973591b2bb76152919269d80347aeba85d2912b864a3f67b868c34aee834ecc8cd82ac1373db0000000000000000000000000000000007767bb0ca3047eee40b83bf14d444e63d98e9fc6c4121bdf04ea7148bcfaf3819b70dcebd9a941134e5c649da8f8d80", "Name": "matter_g1_add_67", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000012ecb4c2f259efb4416025e236108eff7862e54f796605cc7eb12f3e5275c80ef42aadd2acfbf84d5206f6884d8e3eab000000000000000000000000000000001554412fc407e6b6cf3cbcc0c240524d1a0bf9c1335926715ac1c5a5a79ecdf2fdd97c3d828881b3d2f8c0104c85531f0000000000000000000000000000000002a540b681a6113a54249c0bbb47faf7c79e8da746260f71fbf83e60f18c17e5d6c8a7474badafee646fe74217a86ca4000000000000000000000000000000000fe2db7736129b35dc4958ffd0de7115359857fb9480b03a751c4fceb9ae1b2b05855398badffc517ae52c67f6394e2a", "Expected": "000000000000000000000000000000000bc719a8397a035fc3587d32d7ef4b4cfd63d4a5619ab78301d59659208f86df9e247e5d12650acc51a3bca3827063a900000000000000000000000000000000150d5519380a65b1909b0d84da374484675d99b00b254d03e423e634a012b286e3fe074e9b0a7bb24ff52d327249a01b", "Name": "matter_g1_add_68", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000010dac3e5885cc55f3e53b3fdd5d28b2d78ceeea2b669757a187de0ce3f28b586e451b119cdb7dc8b97d603f2bb700e2000000000000000000000000000000000712a9656fa95abf8c8c5d0d18a599c4cae3a0ae4bda12c0759ea60fe9f3b698d3c357edebb9f461d95762b1a24e787900000000000000000000000000000000019d917eb431ce0c066f80742fe7b48f5e008cffa55ee5d02a2a585cc7a105a32bbf47bdff44f8a855ade38184a8279e0000000000000000000000000000000012ee762e29d91a4fc70bc7a2fb296a1dcdd05c90368286cca352b3d5fffc76e3b838e14ea005773c461075beddf414d8", "Expected": "0000000000000000000000000000000008197403ab10f32d873974c937ef4c27fbdb0f505c4df8ac96504705d4851cf951fb0263335e477063884527b21edf160000000000000000000000000000000005396f1affa20ca8530b519a4d5d400969f0c8c8731ecc0944e8086388e89a7ff7c16d9a2a90780972c4762b88a0f0af", "Name": "matter_g1_add_69", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001889ef0e20d5ddbeeb4380b97ed7d4be97ef0def051d232598b2459a72845d97fa5c1264802ab18d76b15d8fbd25e55900000000000000000000000000000000135519fb1c21b215b1f982009db41b30d7af69a3fada207e0c915d01c8b1a22df3bf0dc0ad10020c3e4b88a41609e12a000000000000000000000000000000000d280fe0b8297311751de20adf5e2d9e97f0c1bfe0cd430514cfddbafd5cdcb8c61bd8af4176cc3394f51f2de64b152400000000000000000000000000000000039f511e890187f28c7a0b2bd695ae665e89b0544c325a44b9109da52cc6908d81e1a27163a353ab275d683860c2e007", "Expected": "0000000000000000000000000000000002baea63055f72646189bdd133153dd83026f95afad5ce2cffbee3f74c8d47d5480094b2b58b0936c78aa33cd9a8f72f0000000000000000000000000000000013e600456a2d76f5a760059e0ba987b881c6bc10d6161f388d7a9d8b2031921054edfec46afbd80b1364d8e8f6a5a7a2", "Name": "matter_g1_add_70", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008726a32d489a5ea1c1b314dc4d400d995d0eb8b49d47e65a6ac8fd0e6ec0cda1c637ee314c0c5d1ad72cd3588ebf925000000000000000000000000000000001849697df83d625fc5cdd722c76faf542a42506fc3479d8127eee7af57611c7d6f33a7f9dba5d3c420fab33ec19305f50000000000000000000000000000000015bad24d12b5d68558e961a17dbc3e1686e1b918e6192ebe6f3f71c925177e61d0162e018ac81126099effa0cadfa185000000000000000000000000000000000de73182569184b3d79dcfa8c27f46ec7a31fe8a3fd73fe26eec37a088461192bdbcf4d4b37b33b6177d6fde015d1631", "Expected": "000000000000000000000000000000000ced641c930387432d512861eefbf2d6131017154f99a0d3d24da880dfd2aaae91c2d9634053fab8b85fc11a7884d30600000000000000000000000000000000122071c0e87fae5031c850dccc4777c3ec9d8463bbc4ed84364d4261bc9d38f696a4320d53eea926a75ed9fcc9789a07", "Name": "matter_g1_add_71", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001688c63e325569855bc2e51d668cef112b2479efa33519fe7f45eab89e275e2c4652cf8c2814f179935ccf1d24d8bd0f0000000000000000000000000000000011ebf7d4984237ac0173807f31be64575e7cccb36ce94e666e8149b9c292ebdb68d30ed4ba68f8e00982ee7780b256730000000000000000000000000000000015cdf7dafedce64aba34e1f18c57b28f297629c07ee96b732029b545cf5ea6afdf926daa6a48d1250c67aa2a8b797d370000000000000000000000000000000004867352f86267dbe8e32806e4ed02f1487e036051068f8e06d02e8dea6d3773b422e065d2db27c89ea69246d0185351", "Expected": "000000000000000000000000000000000e2c633351d627a075acd1e373bec96ba41b047f0307201f4b7c9978c1a72243d0b18113604cc421b8f66d76ec9b1360000000000000000000000000000000000844e258d602bf9aaa35ce46c4c91c80dd9337053d8ab22c1163a0571fcd1488a2ef57476e2b66dd9c26963b28284d11", "Name": "matter_g1_add_72", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000bb6f731b345bb1319b9acab09c186449a51dad8b6526251bc58e958cfd933137067e6f778b019f131cc7b23e08a0706000000000000000000000000000000001979a4f3e444c5950d0e2d71f97e99578b3058a6e414dfca313b898c4e02787e6eed89a2d1b05f31cff4af1e12bbedc300000000000000000000000000000000077eb801bcde78e9dd73b58d2429a907ea0f5600a8005093d471be373bba23ea70bf828c766ccced6a46db84b440053f00000000000000000000000000000000101af9df2939089d72e42fe2dc3de3e32be8f4526a2263ebd872d0080ed4a152107bb3d2f56176bf72d5ae8bd0c30a3f", "Expected": "0000000000000000000000000000000010205c6be10a5fc5390b0e5ae47a8a822c8e9a7a96f113d081cde477ec0de7bf0e8385e61780b2335e4297edb35bcc6d000000000000000000000000000000001796af180463ed70cf330791c8201ee3f0fe52993f64819291bda33017285fcc3a515669b3d48a411276c849fa021f6f", "Name": "matter_g1_add_73", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000078cca0bfd6957f9aff9731b45fdbdbeca6691f6fe6bf0b7847859c77478037e14864b202b235953ac7da231367324c200000000000000000000000000000000096ddc8631aff282d14d1878ef6bc537159abe9dda5732d0b2fe3668e184049cc19e05fec4666a0df204182edb9b0b8a0000000000000000000000000000000019b09bb7dddd11c5d0e304dac120b920601dd3a3505e478c88850cc701c17eb02aa7bfb20e4017a62fc4fb544d4f9e8f00000000000000000000000000000000048ad536cf89576d4cce83ef065bc16c47f1a28ae27bd71d30d8f2177a9c6f8b2ed0cdf872ead71bc5a1252bccb4a7e0", "Expected": "000000000000000000000000000000000fb047098a1996a625cd19021f81ea79895e038756878d8772aaee9b6bbb66930e474dcc04579ad58f4877b742a890900000000000000000000000000000000017da74a4caefc55794a36eda7938371f42265cc1f2d87d41883152db82873daeb59642e8e663afddd4f24536a1f52b3f", "Name": "matter_g1_add_74", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b3a1dfe2d1b62538ed49648cb2a8a1d66bdc4f7a492eee59942ab810a306876a7d49e5ac4c6bb1613866c158ded993e000000000000000000000000000000001300956110f47ca8e2aacb30c948dfd046bf33f69bf54007d76373c5a66019454da45e3cf14ce2b9d53a50c9b4366aa30000000000000000000000000000000005f84f9afa2a4a80ea1be03770cb26ac94bec65cf9cb3412a07683df41bb267c2b561b744b34779635218527484633e30000000000000000000000000000000013ce1d1764961d1b0dff236c1f64eabec2ce5a8526edf6b0bccb9ea412e5a91880db24510435cf297fcc1b774b318b65", "Expected": "000000000000000000000000000000000f4ca788dc52b7c8c0cb3419ab62c26db9fb434321fc6830837333c2bb53b9f31138eecccc3c33461297f99a810e24ad0000000000000000000000000000000006785d4f9cdf42264c00fdc4452883b9050eb56e2f6e46c7b8fc8d937dfe4d3ad5072d969a47c4811b36d3887256d0b9", "Name": "matter_g1_add_75", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000007c00b3e7e50a860e99cdc92235f45a555c343304a067a71b6aaade016ef99bc50e3b2c5e3335d4bdacb816d3c765630000000000000000000000000000000000f8a45100cd8afcbb7c05c2d62bfedbf250d68d0fde0a1593cd2ed2f5f4278e1baa9e24625c263764e4347ed78cce6c8000000000000000000000000000000000f0dd7a15dfc39dc2df47cf09761498b0b363157d8443356e768567f5a6d5913c2a67f12d93df2dcf50756bb686836b100000000000000000000000000000000055914dbda5b115222e738d94fbd430440c99bcc6d2c6cf7225c77756ffadf765b2d83447d395e876b5f6134563ed914", "Expected": "000000000000000000000000000000000ac0f0f62202d09cede55ca77b7344b46fd831b41015eb357cac07f0fa49c2564c2e9d5c591630226677446a9100757c000000000000000000000000000000000ca21d0128ef933fc1a48c1b4967f56912513e63a416d86ad40c0a4590b2edf88e4e8a286338b8b176d8b341ea480277", "Name": "matter_g1_add_76", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001517dd04b165c50d2b1ef2f470c821c080f604fe1a23f2fa5481f3a63e0f56e05c89c7403d4067a5f6e59d4a338d0b5c0000000000000000000000000000000007b6b1d032aadd51052f228d7e062e336bacda83bbce657678b5f9634174f0c3c4d0374e83b520a192783a8a5f3fb211000000000000000000000000000000000a6ff5f01a97c0f3c89ac0a460861dc9040f00693bfae22d81ea9a46b6c570436f0688ed0deef5cdcc5e2142f195b5c000000000000000000000000000000000193a17880edffe5b2ebedf0dc25e479cac3b136db9b6b24009ea0a9ca526d6dd9714d10d64c999d4334baa081b9f2fbe", "Expected": "000000000000000000000000000000000b728d4ae4b45fae9a9e242524e95e44f175356726da50f46236f690eec17fdd5edce5df1253383378dc8f9c1fee98ae00000000000000000000000000000000131d28a5eab968c45ddc86b82f220dcdeab7c009c7c61986ee4e55045c024e1bcbe76a4e35000b5699ccec5858ba427e", "Name": "matter_g1_add_77", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000475e66c9e4e434c4872b8537e0ab930165b39f41e04b208d74d3033e1d69dfb4b134ae3a9dc46347d30a6805508c0420000000000000000000000000000000019e585e1d9adf34a98a7cd38de35aa243d7853c19bc21747213c11240d5fa41ff3b21ae033dd664aaac8fa45354a470a000000000000000000000000000000000b35fcf625cde78fba1b70904acb97d7eb449d968e8013855d44292e9c3b0df3cfbcace6f292ec3c7717e25490bb4c67000000000000000000000000000000000af57abd87df55034c32dbe68bd1c0b47139fc2c3a8887b7c151e57b57c9002070337c8dcb2ce2687f9f007d48dd68c1", "Expected": "00000000000000000000000000000000178a19966b5b0fa70c138be7f5ea51d5399c7b8dcc5171cbef82ecb1451aeccbd1ed29170a27f404ebf6daa2ec99bd69000000000000000000000000000000000b1b748494806175030f6b5e2977c58982bd6ec6662d69237f0521351653c772a40035f2504ac8949fb448a901379fd6", "Name": "matter_g1_add_78", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000002291ff240598e2c129ea12292e4a2fc86e03da9bd9fbbb8bddd6f25797003a4688ba2ed3bafd8dfcf0ddd44c3288c1e000000000000000000000000000000000d7541c9c54a95f3789ca7637348378f8956fd451c3266c8f1a34906bf1cf8e7499fcf8ad1f1a73dafcf71b86833ff3b00000000000000000000000000000000177a51fcc81580ccb7a8873fa93eaf860ca8fedde13cdf3eb53f11e66a1c1e934b82ee9251f711c5c479f33a22770c47000000000000000000000000000000000a0edc9a58f4bb414aa0aeec7bfa6076fb62bdbaee987192c18855adf4e813e7103b943e1dddc24754acfa90600a5750", "Expected": "0000000000000000000000000000000019195049a2d457709e284c84c72a211224efc4d7d46d25c9a537eea94149b06506df02a2a4e0a6428263e9605eaaacb500000000000000000000000000000000061139f9a70ce7cd87ed3a701163bde247382295f557b47a3a0a880d2780f015e8ac753eb3243f9ad138f92c3a2257c5", "Name": "matter_g1_add_79", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018d31bd5a7e94ceb18d803969a2001c6eb3bfbcf82c27e88ca60d4c46807d12f116ca71c67d27270c2332205a4ea11bb0000000000000000000000000000000010b6db11d4fc3a2b449b8fd189d2e4ed4591bf4258d7b92b3eb152048cb3a3eecb87782691e9b954377fd1f34b38cb0d000000000000000000000000000000001552982822e0b64a6204b27da0e192873bb5bd2997784ff0b6ed53801b402501a665c17f0a379fd946ab1adfae43c6af000000000000000000000000000000000938359655fe135dd2a390f83e27273feb68387ba94f2b6f7c15389f8272d64231ebe9c8271de90ff2358d935359ba85", "Expected": "00000000000000000000000000000000168f958a40e85341d90012e134976d1a5839e807948410cc0c81a50961552c052bb784c50da4c734f6aa583777c22b28000000000000000000000000000000000d26998bac6ec11bc5fcf6fe7262c984d6500cd5b21af979048b940e20054f8d759f8a011f3e09d01d10f9cf8ab150e1", "Name": "matter_g1_add_80", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000190f4dc14439eccc46d46c5c9b15eeba0bbf2dbca11af4183408afdb15c7bfa26f107cf5fda0c1e0236aab95728eac2e000000000000000000000000000000000c47feeb1a1d2891d986b1660810859c1bba427d43a69b4e5ddeaf77116418138bfc2b7b4aa4c0cc6df10bd116721d50000000000000000000000000000000000d94885dcc21b0b98821b6861a4d094e9eb5d5adcf7ca4275c5b759abbf9a9910f3b38073183d54a0569ecbbc1e9826400000000000000000000000000000000034a54b4bbb3f128608a866f5f5c554cf6ad7899f6650ca663a5bd5f1a3e4471e35a2440644c0e4e0a56080936b46d12", "Expected": "000000000000000000000000000000000d4734ab1bbcf9e30cf142a7aa9e8cde1b3c88d92397b8d7d48c7a7402561feee58a810abf67776e1890489efe7f8ec20000000000000000000000000000000005be9e4af0c0c183c43601339f162345f7c013f5941167cd925057e91c4641e19091a20123a36f2e803142833c0bc1ef", "Name": "matter_g1_add_81", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d8000000000000000000000000000000000062783335b87300c97b38e03e5b1318d15a499b29a473c187f930bf34bc1214b4d822725678cbde978c7b5ae6d4bad5100000000000000000000000000000000014f16cbb17e7f63284d8a75968a4c8fc8ee7f37233ed656d696477c507c23e7c7eaf54001f44c93deb14c298aa6f94c00000000000000000000000000000000169bde83e861889c50b2138c76531a5866235d515a6fee4da7aaf8e8b903f2848a9fe7bbd55eac7f1c58ce3a88e7249d", "Expected": "000000000000000000000000000000001400f774b2d932c6b990da6e1b3493685e8f51d429e0c53e9af1b4a2d3876781b790bca4a1bc28ce0240ea21be24a2350000000000000000000000000000000004993fcf5723b7e02095d4ba73ff3194bbe36027bc9099b57084c91c7e7d50b76331bfb06d3c678d3e401bc3f7fcc577", "Name": "matter_g1_add_82", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e4979375cd880e26d00461de629bac880c12e24ede4a7c702f151c34a728a69a021e37b6a1af520a5f47d3a33f8c8a80000000000000000000000000000000013b5317e3ff7540048b19ceebd47c15538d7eb3bf402823b9c348c464afb1000ce0f7ea4c1cb668af5c8cbf77e6a92510000000000000000000000000000000009acc4b4678b4b645fde47d1b75a5dda8caf6696ad2bf312dd5c12d7f3ab50b95152f5fe59842650c8a1a785f345c3ab000000000000000000000000000000000b672989004fe54f4d645e40cd29a21418151134fd2b90a68185040ceff141ced7f7ece1fdd9137c32589fa04b105a0e", "Expected": "000000000000000000000000000000000fcb0ab180a69b0a230d9dba98099fdce4969f82fc7e7ad93352a7c8dd448bb0ba9c7d62f53d5dc80506bc36190d9bc700000000000000000000000000000000047b7306f4a53c21d42993c50f2365486d02dac495f2dee4f8971a4af308396fce6c90f3cfde857bf7a2c6bf5d0d8aa7", "Name": "matter_g1_add_83", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017f16cffb737dadd52b3c5be258733dc47301474b7351c8dcb8ddb4c519018be08b64efea3336f2b6cfa78e0669dccf9000000000000000000000000000000000ae10eb4f791aa31e5bd7b6c4d68b04c6744262d8f5e9469b3987b101ff5a3066794e05694a9167b7050c3944b6d84f6000000000000000000000000000000000198e12ade128447a240e03e024183c401d605cab1ed81f0f5bb7bc4c7cc9c889a2a01f59c0e37a0767a927719e5a95d000000000000000000000000000000001946e39fee9b76ce552108b339b9b24d11e43d3275ac19d2d4bc745c409bdc3f7c473a60c4d3a4d2cc3b598ae0d66880", "Expected": "00000000000000000000000000000000050b45f896fa40099cda8b1f20ab88644915c16f926589cd709e00149b12922347fa7122175424cd44e8875f217b9ad7000000000000000000000000000000001122b7e9b1509efe5616368b14085bdd36fb7adb85cd5a7f23e327548986f5298c045a602b6ee1265d53a4432a4a3c0e", "Name": "matter_g1_add_84", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000062168f0bfd29c44074430158708a1e3b6808bae633ce9506b32eb9124db1a0668d83f2076adffb568ccf289a61685420000000000000000000000000000000016aead8bd8c4d5ddc444e15bc83e8f14d377d5e8d756a0255f1387506b9a9add69592241dbd9cab95474d55ac47388620000000000000000000000000000000009c48aa2681b3005b24075bb3a122ac100cbaca872f761f4398edaba9dd9da6d04d4a4925028297dfe5f77c2b0b5c821000000000000000000000000000000000ea95c646fb68aa458e69c267a6ca640a6a24d40bdca0161246e4521d13c46facfc1ac86dfc0a804cfa6665cebeec822", "Expected": "0000000000000000000000000000000005325a499aec678ada9eb673d366fe0475e885d5188e2fb687a96949e8f782852fba962197976b868ec083c512bfb66b000000000000000000000000000000000c4d6fcacc8d82401882bee355b37930d83e3cea2e4a7bc133e65a3e0af919b25fc3f30c333873da9406845ce42dbb87", "Name": "matter_g1_add_85", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c60b948942652a8214d8776b77a6c559ca77eb3a537b0a9abadc3058eac8c1d7840f091acd6c0056d5a71468a2b1ceb0000000000000000000000000000000019049c394e547b9b714b5969adcf068b381def6af2b27d1d361d06e9576273a8febb5bf94b5061ccec7afdb5642c0ae80000000000000000000000000000000008e8799a6cc0339e94e861692c81eee53e8a7b326523d5344b416bfbce04290585ef56018834cfd93d234bfa2943369f000000000000000000000000000000000fa1b01aab0878adad693ec769fb68640931c355b3802c51d4a3772300be5b16ceecdc8328a229b3b9f3639170db96f8", "Expected": "000000000000000000000000000000000685ec14da61c48bcb697966aca9e27601db43f0fb1f32e026fb33738eecfbb7012aa1ca3acf36a21fa846730245add70000000000000000000000000000000003fc52a1c3342b12271bbc178545bb20e96e8f1fde673e51f3d27ab5cb42e60aca49c6077e0f687be59b2d25cda9718e", "Name": "matter_g1_add_86", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000013fe38343072af8ef1d8247c3d46b4fd190086ceddfeb767787031368da6a6a6ae849cfc26a24ead499338e37fa337e30000000000000000000000000000000009f7d7b21882455e9f1f24ea120f3eb69f739c1320c37eb2b17e0a271cb03ac6e2b0c55d3518548a005f28b5748b7f59000000000000000000000000000000000bb3a76287fb98fe668cb0a5de603c768340ee6b7f9f686a22da3a86926d8734d2c565c41f94f08fa3ef0e665f4ccb520000000000000000000000000000000016c02dbfb307c96d5b9c144672fe62f3e9cd78991844f246945ee484cbdef2a4c1b001a017cafb3acc57b35f7c08dc44", "Expected": "00000000000000000000000000000000021796fd6ef624eed7049b8a5c50415cc86104b2367f2966eb3a9f5b7c4833b9470ef558457426f87756d526d94d8dfe000000000000000000000000000000000f492dca3f0a89102b503d7a7d5b197946348e195954d23b8ab9ab7704b3bccecaa2123b8386662f95cd4cfdbbb7a64d", "Name": "matter_g1_add_87", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018c6df81d810deaac0b143edf79956c92af7941f7b279db345f838bd583177912fc2eb367616ae165e261014a4d7b1b900000000000000000000000000000000146696840e8e988d0eab90ea935dd8b5f1272bbb81eb524e523c57d34ad7c5f0f3b721566f51dac4774826b84cc1c82f00000000000000000000000000000000127420ff97df415e336cf3e24c39c161fad630c45c7ccef80f1831c4f5ed54da12f2c49a161e72bc70285fa0498e46d00000000000000000000000000000000013e605c21014f72364f8bff392ce64a10078ea537237fa282d5dd252ba1677b84b8c15d7925e54a4ab36f1feb13d3064", "Expected": "000000000000000000000000000000000ae916770455b0a63717e81802f5a7fcfbcc3e260b7adeca02a61a520c338d495eea29c4f070fd6efc1b8d23eb285e4c00000000000000000000000000000000134784e092744df573ba78f7d6f3cf1ed19491a0fc7ddfa02d3ca043bcf102fd40c33ac44b03a947308e3cc7af41c2df", "Name": "matter_g1_add_88", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c6b634d90c2664b9fa4ccbca35913d23696825350e21f0a6dd5e9abb17497a0a499e1b7b928a57ba8c730158f63b75d0000000000000000000000000000000009d569f05e69a38231d0f636e1ef040af059a00db4ff09bd2ad82b7e04cc041a33603c2eb9b148e3b1412bdef9740ab40000000000000000000000000000000016f41e8b098839944adc12481e5f965657a4faedd4f4cdea51a9597a6a0356989e791a686d3d2ee6232ab93683259c6b000000000000000000000000000000000d27b4a56b2cc2216e61eb41061f9a586a704652704906f7fe0eab869ba00d34205ea66f7a02d337d08b916598494e52", "Expected": "0000000000000000000000000000000012842c9d7f4309f6e40124a071d317f5597de419db0d5a8e5324a517f7b61dfdeea2fb4503ad7cdd8deb8aaa5c412554000000000000000000000000000000000ace4d9f98ee6e8a4416ef14d64f26dc49e102e69eced46ef829a352e58e8c1a7e1f083e3f4fc07f24ccd1685dedf215", "Name": "matter_g1_add_89", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018129b2f00be24717c906d215beaaa136758aa1730bd0bbe9c0de9b3cbb3c0ea47911817fa322b907cc6fc720cabde05000000000000000000000000000000000e8b0f968ccb230517ef8980be559f410a2c4035a1101e6796d4f7a5ee5c93a19c111d38930bd5bca69405fc35fea7c20000000000000000000000000000000019e7c8d182e3b674dfa21539613f7de5d4872d4f4732307a5c6d95ada7e81a01bc25bda34e0b46634e0b0b32cd47e8ec0000000000000000000000000000000008149237de73ab46d5c20dfd85b07f593c0caf2e2e364335450e3ebb478a9f6b9ac0af89174dffd92eda2783a5271f01", "Expected": "000000000000000000000000000000000875289fdaead079a283aafe4de7035c88662642b6bba389b17583f8e3b5801dada6e46bd897af961997665e6ed4a55700000000000000000000000000000000050a6b9c1db35865df0a042d27a042ff4b8d3bec2fba6a3a28a71c5a574620dc05cda0e70932ce9b8966e4592220c147", "Name": "matter_g1_add_90", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a4700000000000000000000000000000000193118d1f237c68a8a0961fb220c0fd6a08853908a039dd57f8ed334063e5316bf83e8c3c3f44420734abbd7ddda31a6000000000000000000000000000000000c0f33f2d76366af661d6fa58a8b5aab207d35ce03899e495f7ddccedf201d9816f270468b207413a2ca70380c798fc60000000000000000000000000000000002a7dc7e2b163e65cadf93b5d682982288c8f36d08b1db8e0b1cb40cd3c7231f3f1672da42b4679f35db2076a8de5b42", "Expected": "0000000000000000000000000000000019ea92820dcd442358db359146797aa82beff6154946b1ea14dccae05e8252b776b817dc044a20764e3514cd22799c0b000000000000000000000000000000000ed929fef2cb11e8b6b9b5d52bfde82080eda747f0c82f33b9cb87019476f0c128e6b918a4486172dee2884ba538ae5d", "Name": "matter_g1_add_91", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000217a4c563d730ef545e452038813301933ccc6638321ee5e217dad0be2e3ddc855a14054d0d72b6bcc692a5fb1ac7300000000000000000000000000000000007025f1c4a5f85a9c1587d4d4a2e620d83d60568343940ffd85e6b1e4fb0f0f53bb08c4f48bf6f45a7dbc3722ecc951e00000000000000000000000000000000118fb45274a6b0ca9fe2654821e3b30caa46444f7c64b1921cf16dfd56a43916947d4fb6968d718a59a30ed38d65ce3000000000000000000000000000000000110e8e73e640bbea6927cd770baaf887c8e0e0c58260bca489c39b6dd7a24ab8c0c0a2495133d8ff8c7afb9790b37faa", "Expected": "0000000000000000000000000000000009452bd0a167683e30c673ffd4e750c66a81edf309a8d2d6dd915c358b30b0ffc001c4165b1b17bf157a0f966bfd91d00000000000000000000000000000000015df0b1ee359dd3e35a7b2c33edbb8e92b18804ae3359a369c6a529f5561298e6be9a3498c9477f33353124af7e91968", "Name": "matter_g1_add_92", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009ec00ea2da59d937d3154d86dbed2957667253401bce9de80e0ffe6df32f36b06404b9e3af08e912a0b4ef091f93efb000000000000000000000000000000000dd8d1bd66f4accbc9d0c7dabef7af72f51c67a0d61384647533ad92bba44a312f0be0fa52163176f1aff4e64c00aefb0000000000000000000000000000000005dcb54cdf9635db275540c16307fc9f07b4ca5cd91e3977e4b95b58e8103e40ed9fa74752b2a43d95b6acb6f5fcbf440000000000000000000000000000000007ef8457752a47864ef2698176a53990e4822421ecf83b2716251e3ce69151ab2767d4a6611a0a6e0e40a57164ffb94e", "Expected": "0000000000000000000000000000000011f1ac702a06699dd64b63ebdd8b5381578f63b603c63c3a47413fe764af239ab7024712320f3ea3daefa6bd3cd3dfe9000000000000000000000000000000000918bb83a22b4fc66247e007c17155c4c2ec6326131c10fe04a5f9b82ddeca3d21c7c397a70a3949fda4d766540c85ff", "Name": "matter_g1_add_93", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000014153e01c9e495c5c01c82b3cad9eaf20cf78369ccbabf57fb160ded309cbd1caea3d3df38a7ea5490c67f168e9acec0000000000000000000000000000000001648030be79658c134e016a211d311841988065957b35e9bc1580fb6e05e291e747b7a960a50e26a2a3c0cd1634c35850000000000000000000000000000000006d3335e092616363e94436bb68be89667c706564ba687f4a3494fcf7da62fd9ad8ae68cb76524926c261983711a14ad000000000000000000000000000000000f085a3d013592c402a380e2e8d9019864a775e7b8e8b94603c8cc1eb1def1e91075fd5675f76534397e2a7d76c2331e", "Expected": "000000000000000000000000000000000344951ccb5e60d1838f7793fcf8b765f5f252b69e1cfdb4bd3c20692c8ffa01afbda6950974a65f6ac74afb9da5942e0000000000000000000000000000000014f5f0e6b99a04d1c5c2adf96c53dd41f8c01aab8db4f0e6d7fc5eab27f6c03c429632db4e1c21467c09d8a54066a4d3", "Name": "matter_g1_add_94", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001555535228eb9a24f460df9894d59aa06fc848a8bf8d6c3b51653b1d85734b3c5a2bece161309bd478d356fa198d579500000000000000000000000000000000144401f7eb69f6321eae8dad39dbe2cf4ae58e455474701dd9f1b62c85c7536813e84eb4f9def511eb62e5194288728b0000000000000000000000000000000019e2ed6e9757e2339d013078fac91c966045f7a1416a56135d75e603c2021a8bebf4acbf6c0d5ba911f66510e9a7ad1a0000000000000000000000000000000008b8585444ffb3bd4fb6ee23e8128142aa72fd574a506151a0eea8979cbd694e03897caba63771b0490d46063bc5bb57", "Expected": "000000000000000000000000000000000a449fb0da911c544887b24860bc5fcaaf054041cc80f16bbb44c796520bee454d0d06f84fd5aa179a44fd4fac9f144a000000000000000000000000000000000fca81401349089caaef9156a86c64271c77235c9efd136dcfad9894450b076cb3dd1a05bfa1e62ef904435eee5d2250", "Name": "matter_g1_add_95", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b767f399e4ebea34fd6b6b7f32a77f4a36841a12fc79e68910a963175d28cb634eeb8dc6e0533c662223c36b728cce2000000000000000000000000000000000cb3827fd6ac2c84f24f64789adac53439b4eba89409e12fbca0917faa6b7109aa831d16ca03191a124738228095ed65000000000000000000000000000000000f4a256b4288386545957a3ba28278c0ce69a8a412febfed1f952ca13e673822bacb6b7751ea75893b680ea363aab66400000000000000000000000000000000152379d006e74798199f83b0c6c22a98440ef653d7f0a8c5e3026bcdabec8be59a3cc291ba05860bd0639c5c5f5bee26", "Expected": "000000000000000000000000000000000c427721953e139d4f12ad2a3f8f91a4caa49875a87001b619c8a6e909a7da8ddd9dd026bf56d5f85d49fd17527106a800000000000000000000000000000000018add2816914ef51a289e707ba0224fcf0b7bcfa4001487e90dbdce53f1b596e1f5872de32fcee6f63bce4484ccbef7", "Name": "matter_g1_add_96", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000150b75e9e9c03ada40b607f3d648bd6c40269aba3a1a992986dc005c9fde80bb1605266add0819641a0ca702d67bceed00000000000000000000000000000000083b43df032654f2dce90c8049ae4872a39f9cd860f08512930f43898e0f1e5625a5620818788797f3ca68134bc27d220000000000000000000000000000000012dae9aee13ed6ad52fe664bf7d2d0a1f134f0951d0d7ce5184e223bde164f6860967f9aaaa44fa6654d77d026c52d2a000000000000000000000000000000000f71889d64ec2f7da7319994883eb8bd1c753e6cdd3495036b630c35f07118a1bc10568c411ecbdf468a9cdaa9b4811b", "Expected": "000000000000000000000000000000000275b8efb3a3e43e2a24d0cda238154520f0a2b265f168bfc502b9cd4a07b930756961ae7e4fe3f01a5473d36ce3356200000000000000000000000000000000113403d5a968f01ba127dd8ef6c8d7b783a10d039a6b69c617032eba7122e9297f3ce2360c829ae64fdc9794695bf173", "Name": "matter_g1_add_97", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000cba419694214e95a3605a9b748854d16c8e6e1ee151c907487d8189acfac1361b790a5e78f43593152027295adf8df400000000000000000000000000000000110813ff6e0ddf3427e2a514d3f0bfbadcaf9dbf039e0f93fb9643d1e62bc2469fe84cd9ff0d585bdd1037255bbe54850000000000000000000000000000000004e9dd69012ab596b5d3f1f8e4593b448685fcec4ab3394008178b137b762ddf9150cbb8dbb74c8af45bd8baab9a6c4f000000000000000000000000000000001132b66a2127885774062732127951f051c9c3c9b5aba02406e3f3cd4ecfe2dbf6614ebaca3bfe9efbe4f6e5b15ba0f5", "Expected": "000000000000000000000000000000000594c808954bb930bd038806500c9e3fd6460a83554e945baeeec2354a3805f046c76aea62c249080f16ae8e70f8fa6b00000000000000000000000000000000046924a32fb3f2df9a52615e45eeea2fa3ac0e2ccd38458194ada6b4d993ecdc0f441e41d0ea37599254a06aef68b9ae", "Name": "matter_g1_add_98", - "Gas": 600, + "Gas": 500, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000106df8eba767e90cce0eabdaacc24d8e226c6865012ef8cb1460de5a319d443fdc6b4f4e58fb668943e0528b1809da10000000000000000000000000000000019789f464c95c179af18704c0b67b881991880f75ee7b03b9feafa3eafcd0f7d30a17fdd9cf439ff7fe683adca2083b50000000000000000000000000000000017a81b957a12adf474a2913e8636f169ea9cd10be62c16b88f95f5caf661f158a032a9f7d249fdf2765caa1564bed0570000000000000000000000000000000017fbf2abc62dc2678b65d509e19c9c9c5d961c72565649a078da8dff98be6236ef314e9ff8022f639ff565353345c230", "Expected": "00000000000000000000000000000000002c8bc5f39b2c9fea01372429e92a9c945fad152da67174f4e478fdead734d50f6e2da867c235f1f2f11bdfee67d2a7000000000000000000000000000000000c1dd27aad9f5d48c4824da3071daedf0c7a0e2a0b0ed39c50c9d25e61334a9c96765e049542ccaa00e0eccb316eec08", "Name": "matter_g1_add_99", - "Gas": 600, + "Gas": 500, "NoBenchmark": false } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/blsG2Add.json b/core/vm/testdata/precompiles/blsG2Add.json index 64ca2006dc23..a4a6fd929e51 100644 --- a/core/vm/testdata/precompiles/blsG2Add.json +++ b/core/vm/testdata/precompiles/blsG2Add.json @@ -3,728 +3,728 @@ "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", "Expected": "000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3", "Name": "bls_g2add_(g2+g2=2*g2)", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf300000000000000000000000000000000122915c824a0857e2ee414a3dccb23ae691ae54329781315a0c75df1c04d6d7a50a030fc866f09d516020ef82324afae0000000000000000000000000000000009380275bbc8e5dcea7dc4dd7e0550ff2ac480905396eda55062650f8d251c96eb480673937cc6d9d6a44aaa56ca66dc000000000000000000000000000000000b21da7955969e61010c7a1abc1a6f0136961d1e3b20b1a7326ac738fef5c721479dfd948b52fdf2455e44813ecfd8920000000000000000000000000000000008f239ba329b3967fe48d718a36cfe5f62a7e42e0bf1c1ed714150a166bfbd6bcf6b3b58b975b9edea56d53f23a0e849", "Expected": "000000000000000000000000000000000411a5de6730ffece671a9f21d65028cc0f1102378de124562cb1ff49db6f004fcd14d683024b0548eff3d1468df26880000000000000000000000000000000000fb837804dba8213329db46608b6c121d973363c1234a86dd183baff112709cf97096c5e9a1a770ee9d7dc641a894d60000000000000000000000000000000019b5e8f5d4a72f2b75811ac084a7f814317360bac52f6aab15eed416b4ef9938e0bdc4865cc2c4d0fd947e7c6925fd1400000000000000000000000000000000093567b4228be17ee62d11a254edd041ee4b953bffb8b8c7f925bd6662b4298bac2822b446f5b5de3b893e1be5aa4986", "Name": "bls_g2add_(2*g2+3*g2=5*g2)", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Expected": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", "Name": "bls_g2add_(inf+g2=g2)", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Name": "bls_g2add_(inf+inf=inf)", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000039b10ccd664da6f273ea134bb55ee48f09ba585a7e2bb95b5aec610631ac49810d5d616f67ba0147e6d1be476ea220e0000000000000000000000000000000000fbcdff4e48e07d1f73ec42fe7eb026f5c30407cfd2f22bbbfe5b2a09e8a7bb4884178cb6afd1c95f80e646929d30040000000000000000000000000000000001ed3b0e71acb0adbf44643374edbf4405af87cfc0507db7e8978889c6c3afbe9754d1182e98ac3060d64994d31ef576000000000000000000000000000000001681a2bf65b83be5a2ca50430949b6e2a099977482e9405b593f34d2ed877a3f0d1bddc37d0cec4d59d7df74b2b8f2df0000000000000000000000000000000017c9fcf0504e62d3553b2f089b64574150aa5117bd3d2e89a8c1ed59bb7f70fb83215975ef31976e757abf60a75a1d9f0000000000000000000000000000000008f5a53d704298fe0cfc955e020442874fe87d5c729c7126abbdcbed355eef6c8f07277bee6d49d56c4ebaf334848624000000000000000000000000000000001302dcc50c6ce4c28086f8e1b43f9f65543cf598be440123816765ab6bc93f62bceda80045fbcad8598d4f32d03ee8fa000000000000000000000000000000000bbb4eb37628d60b035a3e0c45c0ea8c4abef5a6ddc5625e0560097ef9caab208221062e81cd77ef72162923a1906a40", "Expected": "000000000000000000000000000000000a9b880c2c13da05bdeda62ea8f61e5fc2bf0b7aa5cc31eaf512bef7c5073d9e9927084b512e818dbf05eab697ba0661000000000000000000000000000000000b963b527aa3ec36813b108f2294115f732c878ac28551b5490615b436406773b5bb6a3f002be0e54db0bcebe40cb2e2000000000000000000000000000000000bd6e9060b42e36b57d88bc95b8b993da2d9d5acd95b73bad0509c2324212bcf7a94a46901932c0750535d00008a34f7000000000000000000000000000000000a374afd32bc3bb20c22a8864ce0dafe298bda17260b9d1d598a80830400c3fd4e8a8f677630eae5d4aa0a76a434e0ba", "Name": "matter_g2_add_0", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018c0ada6351b70661f053365deae56910798bd2ace6e2bf6ba4192d1a229967f6af6ca1c9a8a11ebc0a232344ee0f6d6000000000000000000000000000000000cc70a587f4652039d8117b6103858adcd9728f6aebe230578389a62da0042b7623b1c0436734f463cfdd187d20903240000000000000000000000000000000009f50bd7beedb23328818f9ffdafdb6da6a4dd80c5a9048ab8b154df3cad938ccede829f1156f769d9e149791e8e0cd900000000000000000000000000000000079ba50d2511631b20b6d6f3841e616e9d11b68ec3368cd60129d9d4787ab56c4e9145a38927e51c9cd6271d493d938800000000000000000000000000000000192fa5d8732ff9f38e0b1cf12eadfd2608f0c7a39aced7746837833ae253bb57ef9c0d98a4b69eeb2950901917e99d1e0000000000000000000000000000000009aeb10c372b5ef1010675c6a4762fda33636489c23b581c75220589afbc0cc46249f921eea02dd1b761e036ffdbae220000000000000000000000000000000002d225447600d49f932b9dd3ca1e6959697aa603e74d8666681a2dca8160c3857668ae074440366619eb8920256c4e4a00000000000000000000000000000000174882cdd3551e0ce6178861ff83e195fecbcffd53a67b6f10b4431e423e28a480327febe70276036f60bb9c99cf7633", "Expected": "000000000000000000000000000000001963e94d1501b6038de347037236c18a0a0c8cec677e48fc514e9fc9753a7d8dcf0acc4b3b64572cb571aebbe0b696640000000000000000000000000000000000d9739acc3a60f6dffb26f9b5f1fd114a21f2983deea192663c53e012b9f8e1cabd4942ad039badbd4745ddc0a26a91000000000000000000000000000000000b4206dcdb80d62195febb6773acab25fa2c09a2e4be9416ca019faeb72f1fad1dfdc51e8cea39b371a045b18947d40a00000000000000000000000000000000100758b888fa27e9258ddd5d83409e8aeac576874bc399b33b8bc50d77fce5358cb091d42f9a1b1ed09be3f200959989", "Name": "matter_g2_add_1", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003632695b09dbf86163909d2bb25995b36ad1d137cf252860fd4bb6c95749e19eb0c1383e9d2f93f2791cb0cf6c8ed9d000000000000000000000000000000001688a855609b0bbff4452d146396558ff18777f329fd4f76a96859dabfc6a6f6977c2496280dbe3b1f8923990c1d6407000000000000000000000000000000000c8567fee05d05af279adc67179468a29d7520b067dbb348ee315a99504f70a206538b81a457cce855f4851ad48b7e80000000000000000000000000000000001238dcdfa80ea46e1500026ea5feadb421de4409f4992ffbf5ae59fa67fd82f38452642a50261b849e74b4a33eed70cc000000000000000000000000000000000a69d6d9f79e19b38e6bf5a245dc820bddbdfe038d50932f76d0e4629d759f8ca6d573fcfc39256305daedf452f9fdf40000000000000000000000000000000015f5949369e58487afcecf8018775d1b0a73e913bf77e13d2e5a843bbbeba7d1978ca27ae8bfc87d30f567dd396b980e00000000000000000000000000000000182198bb38a0353b8db25389e56ab0d8679a1bda008a65dad77e4c95bc6804f6311eb16c761e1a5e2a5f87cfada49fa4000000000000000000000000000000000eb5483959e98c30e71db52615f63521378b156f142d46f3bb285b94aef39d80feacec335b797c5a68dc17ba89d43e0f", "Expected": "00000000000000000000000000000000079e4fc2190d3441fa76c2d925d23b81e353e09e9138fdde51234195e564a32c98aa0d240f051298bf966d17adc2d6fb000000000000000000000000000000000aa327776fa7e15000dd548fcdc3a1cc6f9d0ab33046dd4240a3002962131b738ffed579945a348c795cfcb33682cf3b00000000000000000000000000000000179232ec56602d1ff79861cbfa2edece34b296541483aa65fe0cb493f520b7722cfffbe04294dd054770a38bf75d927b000000000000000000000000000000001826b88a6b411330757bb304a380487a02f7cf421115b84b3f468d11a83dbf304ce7a5661f4f01299d3c7865305a0006", "Name": "matter_g2_add_2", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000149704960cccf9d5ea414c73871e896b1d4cf0a946b0db72f5f2c5df98d2ec4f3adbbc14c78047961bc9620cb6cfb5900000000000000000000000000000000140c5d25e534fb1bfdc19ba4cecaabe619f6e0cd3d60b0f17dafd7bcd27b286d4f4477d00c5e1af22ee1a0c67fbf177c00000000000000000000000000000000029a1727041590b8459890de736df15c00d80ab007c3aee692ddcdf75790c9806d198e9f4502bec2f0a623491c3f877d0000000000000000000000000000000008a94c98baa9409151030d4fae2bd4a64c6f11ea3c99b9661fdaed226b9a7c2a7d609be34afda5d18b8911b6e015bf49000000000000000000000000000000000286f09f931c07507ba4aafb7d43befe0b1d25b27ecc9199b19a9dc20bc7ec0329479ef224e00dece67ec0d61f1ca5ae0000000000000000000000000000000014e6ed154b5552be5c463b730b2134f83e0071dcdadfaa68e6c7c7f6e17dabb7daf06e409177bc4b38cfdb8248157618000000000000000000000000000000000f145e998dc6eb0c2b2be87db62949c7bfa63e8b01c8634248010fd623cfaec5d6c6c193331440957d333bf0c988b7b10000000000000000000000000000000002a1ab3eea343cfdea5779f64b3bddbf0769aded60e54a7507338f044310ba239430663394f110e560594d6042a99f1c", "Expected": "000000000000000000000000000000000f69e3616e7122bf78230461bb1f4b194988adc6149372691d8794d0086fba0870a2255a2c79cc3426e7ba4d032fc2ab00000000000000000000000000000000174752301e05dcd62f7a3ae3357344e64d1c94835b2b742ac24449ee2728d693a0df10c3beaeb45d1b4af4ac2bdbb8b200000000000000000000000000000000051a761a3ceb275ec28a2a269b5ded1d9fd11a617c958e73c07de3a92ac480aa82c7d2a1852d291804e734526277f5740000000000000000000000000000000009bec9045ea89d5d16588e3373cc977f6d975d0e2213b171403a9b2ca460b3b2e1106b474185516d4200655b17a179a1", "Name": "matter_g2_add_3", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001156d478661337478ab0cbc877a99d9e4d9824a2b3f605d41404d6b557b3ffabbf42635b0bbcb854cf9ed8b8637561a8000000000000000000000000000000001147ed317d5642e699787a7b47e6795c9a8943a34a694007e44f8654ba96390cf19f010dcf695e22c21874022c6ce291000000000000000000000000000000000c6dccdf920fd5e7fae284115511952633744c6ad94120d9cae6acda8a7c23c48bd912cba6c38de5159587e1e6cad519000000000000000000000000000000001944227d462bc2e5dcc6f6db0f83dad411ba8895262836f975b2b91e06fd0e2138862162acc04e9e65050b34ccbd1a4e000000000000000000000000000000000d1007ca90451229d3780d66d3aed7c9d8fc82e9d45549e8586600e38eb6763f3c466e2f6ba6ba1dafd8f00cc452dda20000000000000000000000000000000001d017d920a262b6d6597bab532f83270f41526409510e80278d1c3595ceabb9ceba8ae32b1817297ff78ea7a0d252e8000000000000000000000000000000000935b7a59d2e51bbb2f9b54ccb06ebee9d189fa82f0e97d10c8020badb3de7fe15731b5895faed8cad92ae76e2e1b649000000000000000000000000000000000792dadd48a20040ad43facedc109747411895180813349d41d0e5b389176bfb15895d41665be8d1afa80835ef818eca", "Expected": "000000000000000000000000000000000c079610e6f8770d65352f911863b6cb4fcb25cacc4a42f75e34e29e977c93244a6241cf3d5bd1040ce7d8987996f87e0000000000000000000000000000000010d08d8f6fa8ee7042c0891ea0c3b9b59a79da52cf3a91627c79d456212e3f6f39e1f69aa0053bbdb4076a3f7d05e5dc00000000000000000000000000000000069047218b0ac1e07650ac8f4a1b9235f68408f543517c4ae3c0ec47c79b468713c704ff3680edc8abd1bbed7a5fa75d00000000000000000000000000000000137737706162e02cfa75ce2154d57c9a3520818cc04626654824769ad92ff7977942f3881a28284ea47c14f353772d0b", "Name": "matter_g2_add_4", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019c31e3ab8cc9c920aa8f56371f133b6cb8d7b0b74b23c0c7201aca79e5ae69dc01f1f74d2492dcb081895b17d106b4e000000000000000000000000000000001789b0d371bd63077ccde3dbbebf3531368feb775bced187fb31cc6821481664600978e323ff21085b8c08e0f21daf72000000000000000000000000000000000009eacfe8f4a2a9bae6573424d07f42bd6af8a9d55f71476a7e3c7a4b2b898550c1e72ec13afd4eff22421a03af1d31000000000000000000000000000000000410bd4ea74dcfa33f2976aa1b571c67cbb596ab10f76a8aaf4548f1097e55b3373bff02683f806cb84e1e0e877819e200000000000000000000000000000000095353ad699b89ac82ca7ef631775b2b3a6e3ed8dd320440cdb929baa428e63cb902a83857cc0e2621470544c69e84aa000000000000000000000000000000000892559ade1060b0eef2cbc1c74de62a7ff076a3621e5f0f159672a549f1201f2ffb3ac12c8b12cb86ae3e386c33e219000000000000000000000000000000000750df4632a7126ddb08658a4001f949b9764d9cc43a9393cc55d8fdbb15d4a1186dd87a6433d111888a7804540ad9fc0000000000000000000000000000000017554bd444665df044b91b0b2614017bbfcd7acc7f8c5a16cea2861235578ce2b27dcced9fba234999fa478cd3f6e42d", "Expected": "0000000000000000000000000000000004dd5dfe38fa70625216ecfec60ea8d38602552726f0fdfb8f392362ce845fe0fda76894d0e456796e08462bb941579f00000000000000000000000000000000195a85cd0685f4053ee539de7e04fccd2380819b291f89cbcd63d5a0015b3214500284a7c6568a71f52bbdbc38be410a00000000000000000000000000000000107c211bad49c7dd8555e30f2500c67e7175eb98a8494f3d5309c65a93cce89572b7b5489428eaf3f0a5c1be323c5352000000000000000000000000000000000c11f978150ac35722679cf79443b3706d288c968116ddedc1f1d0fca8cd746e3c92dc006330be14886c53c41feebbf9", "Name": "matter_g2_add_5", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000147f09986691f2e57073378e8bfd58804241eed7934f6adfe6d0a6bac4da0b738495778a303e52113e1c80e698476d50000000000000000000000000000000000762348b84c92a8ca6de319cf1f8f11db296a71b90fe13e1e4bcd25903829c00a5d2ad4b1c8d98c37eaad7e042ab023d0000000000000000000000000000000011d1d94530d4a2daf0e902a5c3382cd135938557f94b04bccea5e16ea089c5e020e13524c854a316662bd68784fe31f300000000000000000000000000000000070828522bec75b6a492fd9bca7b54dac6fbbf4f0bc3179d312bb65c647439e3868e4d5b21af5a64c93aeee8a9b7e46e00000000000000000000000000000000175dadb6ee656ec6aebf8d0e5edaee3f119c74e0ea64e374be9e8ab9fd3d085fceeedf4ed8de676ebe9065d83b0542ad0000000000000000000000000000000005cd6a875329c23e4918976cf997e93e403957acfc999f8159a630d21ab6f1762925c063784237262bedc82402ad81bb0000000000000000000000000000000003274bcb8db35e50164d136c2a98b5a6d2fb5f9767d0ee11c1358bf7ca5ed96d9122f8c1051ba3c658cc89777d03dfa5000000000000000000000000000000000380a240443dff85b6542f75db28b87c39e278cdb8d9627efbbc63b229e6ce783f6fb0114c8e91c2fd6ea71c95bb99a4", "Expected": "000000000000000000000000000000000fb33caed4de22cf341bb3e04d41c0198b064c1d371a24f5cf59595ab4a1edfd379916a40cc405d35f0603b2f8fb987400000000000000000000000000000000131ad6172c20b3a1cc2542db037de1324086fd9cd140ae97987980f260023d91b24504181af6fcbcfa242f48e99559320000000000000000000000000000000004a0404c00789459395f5344544041785d10f2fe74d4bf484966f5e9b6b4c4c8cb113a811a4fa82a1cdf8e3242bb418900000000000000000000000000000000086ba6a914f3f07bdc6750fcf6baf76124a17964bf9eb9a12982e8a28ca04360da3544b69436d5663e4e94bf7189529b", "Name": "matter_g2_add_6", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000690a0869204c8dced5ba0ce13554b2703a3f18afb8fa8fa1c457d79c58fdc25471ae85bafad52e506fc1917fc3becff0000000000000000000000000000000010f7dbb16f8571ede1cec79e3f9ea03ae6468d7285984713f19607f5cab902b9a6b7cbcfd900be5c2e407cc093ea0e6700000000000000000000000000000000151caf87968433cb1f85fc1854c57049be22c26497a86bfbd66a2b3af121d894dba8004a17c6ff96a5843c2719fa32d10000000000000000000000000000000011f0270f2b039409f70392879bcc2c67c836c100cf9883d3dc48d7adbcd52037d270539e863a951acd47ecaa1ca4db12000000000000000000000000000000000834cf1b4149d100c41b1bca0495e455002eb6596bddcb94ae48d0c65957e8b313372f8e0d6e57504664b266f38293150000000000000000000000000000000000de2875fbd14760bac4c2cc7d3f239177efe9f7f61f767be420d44f24c9fb863efd60dcd732986db8c5b72470617ea60000000000000000000000000000000000bc9535ebf11c2dcc8c7d3bcd09d7d14035635fccb5fddb7df29ce8855e79f99809781d6ffbbcb33d1227314609abee00000000000000000000000000000000039bbfb4d969d702255e3be7f255a97529a19687ce38cb70637c37894d4102591feef428b0afe8c9ef50310ae3b83091", "Expected": "0000000000000000000000000000000019c8a1a206c0006a3033377abba4c31c55710a094d8c9dcef7560818e90411861ce7d189e2763f8fe69bf75e719e4efe000000000000000000000000000000000cccc6bba8691c210aa0a67d26584a359fab94041d853160abd9669893c0d398c805cc37fa3c33bc5ee5ff915b985c45000000000000000000000000000000000e353c1993c36763acec2a75495560e743d099b565f3de195e011afcacff3d60502801f47695da7dd589af81e772eb7800000000000000000000000000000000100c6123cf08eab6c59d78b414fa504ed10c204851289b0598b40ac31971fa12cfda4ef7cd2d64f9797d4d2b193e0bd2", "Name": "matter_g2_add_7", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017fae043c8fd4c520a90d4a6bd95f5b0484acc279b899e7b1d8f7f7831cc6ba37cd5965c4dc674768f5805842d433af30000000000000000000000000000000008ddd7b41b8fa4d29fb931830f29b46f4015ec202d51cb969d7c832aafc0995c875cd45eff4a083e2d5ecb5ad185b64f0000000000000000000000000000000015d384ab7e52420b83a69827257cb52b00f0199ed2240a142812b46cf67e92b99942ac59fb9f9efd7dd822f5a36c799f00000000000000000000000000000000074b3a16a9cc4be9da0ac8e2e7003d9c1ec89244d2c33441b31af76716cce439f805843a9a44701203231efdca551d5b000000000000000000000000000000000fc09c241899fa6e8cc3b31830e9c9f2777d2bc6758260c9f6af5fce56c9dc1a8daedb5bcb7d7669005ccf6bfacf71050000000000000000000000000000000018e95921a76bc37308e2f10afb36a812b622afe19c8db84465ab8b3293c7d371948ee0578dbb025eed7ed60686109aa0000000000000000000000000000000001558cdfbac6ea2c4c1f4b9a2e809b19e9f4ba47b78d2b18185ed8c97c2f9c2990beadc78b85c123b4c3c08d5c5b3bbef000000000000000000000000000000000ea4dfdd12b9a4b9a3172671a6eafed7508af296813ec5700b697d9239ae484bcf7ab630e5b6830d6d95675be5174bb2", "Expected": "0000000000000000000000000000000009fc3870f88288c680b43d63d3bb5305b99fe461e59c07be981b8819fbee0d1fdfae0c037e830fbbabc40cedac7919720000000000000000000000000000000018bdd4903da4d14fa28af4c2cddcb708238cf68673ce77a04a3926c4aaf17d39a831c5401e84dd042d6adf595a1763710000000000000000000000000000000002c398f0e8ad9752f4aded980bc5de2d91118db06818d815c11e818ead47e7065823737db8e304bae32969cab065d1ff00000000000000000000000000000000180642a633c3aa402e5c0b18fcb6fe8c115575b863abda59b5d91997ab01014faefc975d0aee994f98cf37ce79eb95aa", "Name": "matter_g2_add_8", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e25365988664e8b6ade2e5a40da49c11ff1e084cc0f8dca51f0d0578555d39e3617c8cadb2abc2633b28c5895ab0a9e00000000000000000000000000000000169f5fd768152169c403475dee475576fd2cc3788179453b0039ff3cb1b7a5a0fff8f82d03f56e65cad579218486c3b600000000000000000000000000000000087ccd7f92032febc1f75c7115111ede4acbb2e429cbccf3959524d0b79c449d431ff65485e1aecb442b53fec80ecb4000000000000000000000000000000000135d63f264360003b2eb28f126c6621a40088c6eb15acc4aea89d6068e9d5a47f842aa4b4300f5cda5cc5831edb815960000000000000000000000000000000000b36d8fb9bd156f618ab8049d41dfe0698218764c0abb10e12fae43c8810b8e2a5201364e2778f6f433b199bb8f9a6800000000000000000000000000000000000707eb15411b63722b4308c0ed4288320078d2463ae659ad4fb3f9ef8124f379df92d64e077403e50727388adb59ac00000000000000000000000000000000158e1249d5b91614924acb23899c6bae408697dec0982c10d0459746499f4e6739afb9d5129568106ed1a1caefeaa9640000000000000000000000000000000019e841562e4aa75321143f8ce1e5ec6158fa5cb8b98c839a486188260c18ee8a7600930f23aa39eac2eb520d6a0fba90", "Expected": "00000000000000000000000000000000199600699a6108599c638df8f965d73b5de4ca74598df281ec95c539de2c7eff9767569692d8e0ad120fcbb3d9335b95000000000000000000000000000000000c42b11e2585ba93521b3c968e9dee07e4f5168c11087d8d750795555a105df70c969bfa79b1ab4e5fc8d81657235d08000000000000000000000000000000001370daa4699daa99e9940fe04f69150e6f752798cbc0e66c91c3bd46149d935c1815f32d7f14b510e16d475044eda9cc0000000000000000000000000000000016c7a00be10de5732795cc3ee2951e58cb9d42f9b05d02fbff1b83fab5d3ad830cb8178092b76172108d7a53afe8c539", "Name": "matter_g2_add_9", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000159da74f15e4c614b418997f81a1b8a3d9eb8dd80d94b5bad664bff271bb0f2d8f3c4ceb947dc6300d5003a2f7d7a829000000000000000000000000000000000cdd4d1d4666f385dd54052cf5c1966328403251bebb29f0d553a9a96b5ade350c8493270e9b5282d8a06f9fa8d7b1d900000000000000000000000000000000189f8d3c94fdaa72cc67a7f93d35f91e22206ff9e97eed9601196c28d45b69c802ae92bcbf582754717b0355e08d37c000000000000000000000000000000000054b0a282610f108fc7f6736b8c22c8778d082bf4b0d0abca5a228198eba6a868910dd5c5c440036968e97795505419600000000000000000000000000000000186a9661d6fb539e8687ac214301b2d7623caedd76f4055089befba6ef2c96263d810921ad7783d229f82783c9def424000000000000000000000000000000000447f3e20caa1f99fbaccab7bde2bd37fe77cea691ebf2b9499f95bbbb77afe72b7039eb0c05970b61360fcf8ade73730000000000000000000000000000000005e11f828eda86c10a1d7929def547ac06885da278afae59c5d95453caf0a2d8ed186fa7c6d0a7ab6e9142cfa4b338190000000000000000000000000000000003d954e61b6ab71042b19e804efccd4956b56662f27f70a9255cec0c464b86c0e83721ad3785dec62dd4a9dd3d6d5d53", "Expected": "000000000000000000000000000000000669cc8a3acae17f99f805afb9012a38851a9e8d4fd9895a9946c29fc859849c24d7ab7b6278c449cfbc5f1d7ea1fdbd0000000000000000000000000000000007a9095be808d0ebc99bce94e851d2a7cd3e1977b923064ab5bbed2347cf18f3343e60120fa051d12fe27da3146cb423000000000000000000000000000000000f1e7f75887651f67457f6dc064d7c11934035d15fe4dc40bab970160ed1b1aa230a3fb84dc1da08770d847c0216347a000000000000000000000000000000000efbc62ade1678cd70eb38c644038bf19e52b0859f65747068d9f3124762d951e4a6ff05f34b6d14919774f8409adff5", "Name": "matter_g2_add_10", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f29b0d2b6e3466668e1328048e8dbc782c1111ab8cbe718c85d58ded992d97ca8ba20b9d048feb6ed0aa1b4139d02d3000000000000000000000000000000000d1f0dae940b99fbfc6e4a58480cac8c4e6b2fe33ce6f39c7ac1671046ce94d9e16cba2bb62c6749ef73d45bea21501a000000000000000000000000000000001902ccece1c0c763fd06934a76d1f2f056563ae6d8592bafd589cfebd6f057726fd908614ccd6518a21c66ecc2f78b660000000000000000000000000000000017f6b113f8872c3187d20b0c765d73b850b54244a719cf461fb318796c0b8f310b5490959f9d9187f99c8ed3e25e42a90000000000000000000000000000000002b94534aa0ba923bda34cbe92b3cd7a3e263741b120240ff5bdb8b718f094d3867e3fcabeab4a7be39c8f8c4fdd10d900000000000000000000000000000000048711cf6a82534d64d072355cb8fe647808e7e8b2d9ac9ed52eb7fe121647a721dd1234c71ecd163d91701eb7331cac00000000000000000000000000000000141ef2e23a1ecc7ef2ed3ea915492e79cfffe60b5e0de8441e878bd0653843d79c724e3c5ebe2321361df99f8932ddc200000000000000000000000000000000085513b4009f29b3e00a91c2c4be418368560802ba4194cbd2f4fa3d72a55fcae547014434514a8b2a8fe3e0b28d2773", "Expected": "000000000000000000000000000000000e25a38d0ce2aabd2538c95ed463f226e3f29ce7f10e1be27af2d3db741926d557178c4b125af8789b40480d8beec0890000000000000000000000000000000002a94b7c57fe2783d055a537004a3b67e41f5374da0813094f5944fbabf4d27eb576dc8b21ccc15f8339df14ff8785220000000000000000000000000000000008b9efd8abfa4fd71a8eafdba9df38360ef0b0a117c0052528d1c24df5032635eebc7b201439f5de858514666c68cd270000000000000000000000000000000012a2fde51f6f4a98435c325dc3b1ae846bc33a5ffb3b13fbe3fde2f74dec0aa815fa8e42392b3dbf798cf547fdb4db0d", "Name": "matter_g2_add_11", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000576b8cf1e69efdc277465c344cadf7f8cceffacbeca83821f3ff81717308b97f4ac046f1926e7c2eb42677d7afc257c000000000000000000000000000000000cc1524531e96f3c00e4250dd351aedb5a4c3184aff52ec8c13d470068f5967f3674fe173ee239933e67501a9decc6680000000000000000000000000000000001610cfcaea414c241b44cf6f3cc319dcb51d6b8de29c8a6869ff7c1ebb7b747d881e922b42e8fab96bde7cf23e8e4cd0000000000000000000000000000000017d4444dc8b6893b681cf10dac8169054f9d2f61d3dd5fd785ae7afa49d18ebbde9ce8dde5641adc6b381731734598360000000000000000000000000000000009143507a24313ee33401955fc46562c9b20c9917df3b40ccbd7ed43b1349d4551cfd98a4976d6fec5fc289460c8d89900000000000000000000000000000000060566b79df5cc975e669da8ca3a7fa91bf3f5c9fb871c3d62f4a3e79dbc341b89d38b588e5414bc385d5e3cbf3ab9310000000000000000000000000000000016bf40b8cc4c01a87aafae0c4439b623a51ba9a383756a550b69d627d6f45209f0d87e4f9be9edff35c986f7b9c49e3f000000000000000000000000000000001842d9172bce51a164fbdbdb108d0faae07e4642f21c80e40ac31e737657472ae3dfe552b65349629c210a068c4afc0e", "Expected": "00000000000000000000000000000000067265782d58b04a2ef3dd419cee506e076e49d1119e28db1df7f0e22cba9bbdabc560084cda50bc8db3915fa9c489a30000000000000000000000000000000012448a61fb2f6fd8e355111b671f0e888304284b72d5688091f2ed00edf7ccb7e5bd8a733a910d6964dde07d393798470000000000000000000000000000000005f687356ff6c634eb46613be8e98540107e706714434faff54510234d4aff42ef7752e154aed63fa8ff905ec0af628f00000000000000000000000000000000180dca84a37c964b30f5cd11a090e54acea102f1b884319f8d1252a37bda005512ffc39dec8e33af0dde0d37993f846f", "Name": "matter_g2_add_12", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ca8f961f86ee6c46fc88fbbf721ba760186f13cd4cce743f19dc60a89fd985cb3feee34dcc4656735a326f515a729e400000000000000000000000000000000174baf466b809b1155d524050f7ee58c7c5cf728c674e0ce549f5551047a4479ca15bdf69b403b03fa74eb1b26bbff6c0000000000000000000000000000000000e8c8b587c171b1b292779abfef57202ed29e7fe94ade9634ec5a2b3b4692a4f3c15468e3f6418b144674be70780d5b000000000000000000000000000000001865e99cf97d88bdf56dae32314eb32295c39a1e755cd7d1478bea8520b9ff21c39b683b92ae15568420c390c42b123b000000000000000000000000000000000ab19bbddd661e9db8fe4cb307ecebdc5e03efbb95c5b44716c7075bd60efcfc67de0bfd7c46ad989a613946c90a4c1000000000000000000000000000000000120800e7f344cda816299fa37f603ade06beb3b10907f5af896d6b4e42f7f865b756f14164db84411c56cb2ea81f60be000000000000000000000000000000000f688ddd257e66362af1437b6922d3397a7c3dd6dea6bca8ebd6375e75bf2de40bc287cbf3434388191e56b92949c83b0000000000000000000000000000000005252465784aff8c1c707da58b5808c69583bf852d68f96912bc53f8dae4536b09ccbbd25a49d9e744118992b92b6792", "Expected": "0000000000000000000000000000000012a29d35c9af52f172787c90c5a3e77ed29d66feabf5d7bdd6bfc14dd9a05d402976b84d44647628c908d1816f4e7100000000000000000000000000000000000caf3c372e36de557ecd7eba02e6a79b1b4cff30343119df7a23662c8512095e051ae2dc27e577635c74a260be2b084c0000000000000000000000000000000002ceca293a58bc9beb4ee9a0679eab037f5cf7b326d65c0efeefdbf384ad8e4bc08a3a75a02e6b9cba8963e65d6e76ef0000000000000000000000000000000004631773a6590bc89b49a75bbbe2e732f9466ba259ef7a04ae69b6aa5d5a2621c1918eb213101f6f7eeee4656a7b1472", "Name": "matter_g2_add_13", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017eccd446f10018219a1bd111b8786cf9febd49f9e7e754e82dd155ead59b819f0f20e42f4635d5044ec5d550d847623000000000000000000000000000000000403969d2b8f914ff2ea3bf902782642e2c6157bd2a343acf60ff9125b48b558d990a74c6d4d6398e7a3cc2a16037346000000000000000000000000000000000bd45f61f142bd78619fb520715320eb5e6ebafa8b078ce796ba62fe1a549d5fb9df57e92d8d2795988eb6ae18cf9d9300000000000000000000000000000000097db1314e064b8e670ec286958f17065bce644cf240ab1b1b220504560d36a0b43fc18453ff3a2bb315e219965f5bd3000000000000000000000000000000000e3165efe00f69aee84ac56d2161f07c017abfaadeaad34f8c96799d68bae0e6f9b557bbf9137e7826f49f29c58d1ef9000000000000000000000000000000000de0dce7ea371ad60f21f2cb61cb582b5072408a7efc91edf05b36a1a3b58fd9e6cf808d75157eedccc8f1c93a8ae07d0000000000000000000000000000000016d911943d80427385ebac1d1b293914a9e4dd9db06c1d6a758192d63c8fc9368e02eae7fb0e3a7859408f215cfa76ca0000000000000000000000000000000007bfdc6afb8acec625e50ecbc08a5cdb7862b795866323679885ba5cba3fd51f181078e03fe35e96e6383c077eed1bf5", "Expected": "0000000000000000000000000000000017f155ed9911ec56d71d63d57556de071ebe89be36e6bc9943ec068a70dd5a6f045dfb9fde5c1e29d52c9fc17579452e000000000000000000000000000000000a60d62ea549edf4b11f62f2321f39d41bf11f3c4f858dc7db85b1dab1b7644e27eeb1d022d6082f59c65155068d2c390000000000000000000000000000000009d309145fad15860e556ec4b4aecb415865954247c2034d5bc96026e4d6f7612af6e2db99f4e462acee2b303134b91b000000000000000000000000000000000114ed157e3d020c5397cba7e10cb864aabb47461f166a6724614e689274ae74c505fb6ebfe3e88da0d6c272a15a0527", "Name": "matter_g2_add_14", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000018244ab39a716e252cbfb986c7958b371e29ea9190010d1f5e1cfdb6ce4822d4055c37cd411fc9a0c46d728f2c13ecf0000000000000000000000000000000001985d3c667c8d68c9adb92bdc7a8af959c17146544997d97116120a0f55366bd7ad7ffa28d93ee51222ff9222779675000000000000000000000000000000000c70fd4e3c8f2a451f83fb6c046431b38251b7bae44cf8d36df69a03e2d3ce6137498523fcf0bcf29b5d69e8f265e24d00000000000000000000000000000000047b9163a218f7654a72e0d7c651a2cf7fd95e9784a59e0bf119d081de6c0465d374a55fbc1eff9828c9fd29abf4c4bd000000000000000000000000000000000a68dccbe3452731f075580fe6102b8ee5265007ee19c56d95bcb096a3a6ac444f4145b980f41afcb0a865853b279bc600000000000000000000000000000000164767ea55a9038ac2dd254d8c8a4970dba93dacdf5416aecaa407914719cab165e7a32784b2c41652a86358737d831f000000000000000000000000000000000da9441fbc6578c85fdeca49082c9ebbf183de894d67c65158380ee56132d3cdb44b100d72b6d3b82688defb75d2aa390000000000000000000000000000000017d570e4f6e46550679d5d12c347414da207060f594620e2f8db66df8e0b06c912290b207a268e782d4b45db19a199db", "Expected": "00000000000000000000000000000000118e0c81f9157395578f0fb83b179721de2af3326d13189cb8f43911d8c3268a11fd9702f09f14c115bbdc43d5fbc08b0000000000000000000000000000000016a548df8c87f432c31e4e32c3e5b4d48d6f29fbe391d1181174be9dddee450e7e96bffe8c9f23692ccc080116592944000000000000000000000000000000000eef72a5c698c58f1d2ae9415da256b54d7b1ac37a1d1b88727c0afcfd854a41973c6cb10ecbc3a90050fe3d8d3ce8780000000000000000000000000000000019b16ca8f955dfd21830a3f7fafcc97d7de977bafe1983892988aaedd430d22674d97897d24c1643e99bfa6256df4bf7", "Name": "matter_g2_add_15", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000000eb3c91515d4a41209a73564741a8ccf901a624df9db22e195a5d02d24b7bc0a12756b15b8d006cb991a7e088eaef1000000000000000000000000000000000704ce8afc808b0161f6f61b22d990d713ae398779e6e74e9b5771daf006ce0bba3a8088edf75156f0e48b92ee8409b00000000000000000000000000000000018fe81e05aff0620f4bdbe4a715e015650497afab62921eba0ab86b649e5a2fd3d54041868928519f537e36448688a0d00000000000000000000000000000000162bd97161201ea3c26f8dd1204a9c6b61b762bdf573cb5d20b6b255f30208ca7d96aa47b46fb8c6bf0922075f1c1ca800000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e000000000000000000000000000000000af1a3f6396f0c983e7c2d42d489a3ae5a3ff0a553d93154f73ac770cd0af7467aa0cef79f10bbd34621b3ec9583a834000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e", "Expected": "000000000000000000000000000000000f2bf3f69276d390c9fc2c15e9f5f5d0b3cf9a6eb028c44811b481f376ab60e17d33a04b78348e46eaa94332c5f16ff8000000000000000000000000000000000bedd0437fb3f4baef87e56f33c77fcdff6a5512571cf11fd9605697abd8763315f1fe4bccf04acc6e971d6aeefd9c1500000000000000000000000000000000067c3ff69733baae2fb4ab77cddb7563047c428b40a257a375f8cf8c9d230a6619f7932b86e0836fff0c1c60d2c4dfd900000000000000000000000000000000057526faed8d62aa10e89add5a338320c748ca1f96ba5ceb579efec69d17475571fc4ce6fce3a93398ea88340f0e969d", "Name": "matter_g2_add_16", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000135aee0e30fbcad798738c10d4aebcdf50c89ce516325f655fe763dce54ffedf94dd74168611e5ae879b5bf5598d62dc000000000000000000000000000000000c728e672cd8b3bf9341bca929c34118b566cd3a80452d7015bee9d5cdc001b1f5c678d4b2cc4f7cac353e7bf326ca1e0000000000000000000000000000000014809aa22e2051e463fba6d49fbb060d0c7f599a0fc5409d34e71f34817e7beb1251810ae6eee1848c60796fb8647dea00000000000000000000000000000000145a4de777d86025d50e12f9a6615ecb9bdd41489992d1b643dd9aa549acbc63b04b0bdfd14b6e45c70f165e9a8c91be0000000000000000000000000000000001c2d8d353d5983f22a5313ddd58fdc0d9c994b2915dbc87a9b65b7b98ff00b62e140a27dc322d42b3ad190c1b3728dd0000000000000000000000000000000010412f3625947b38bb380a6ed059f1677b7a7afcb91517837c563dadd0e285b95740a200ddff6570d4d92bb636b625bb0000000000000000000000000000000015f4f9a480a57bd1b2388532ab045a1ba93d2f6589a3022c585fe06a1d611165c99d70be06251812405c9c37d6e9f7730000000000000000000000000000000001a78e6c5062a6634a56e9853ff5afacb2e7cf31fd0ea5f0d8c8ac6174c88133cf2f63450ec4590544c9a0e37daac1f9", "Expected": "0000000000000000000000000000000004fc19f8fe47e6acd37567016704b07f906e8741fcb196f697e1fc24b0204292693ff424bf1c5e407f5bcba5a3b1ab85000000000000000000000000000000001816f992c3c461fa6d2014ced382a35b0d70e61927d72b4d661434efff3dafe2f4b6cc91bb1a5dbf809f10f3ed7f36de000000000000000000000000000000000dadf7f7223ccedbeffef31c97df7e01f99299da71b589c8828b65715012aa343d7e041dacc57b34a6b5f84523a7938100000000000000000000000000000000167f7e73e22df81bd2a7a6f14e940a401bf414e5d18b3aa610b2a82ca8f46aecb5721d0092b27f8968b2302c37957268", "Name": "matter_g2_add_17", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000009a58b7116dbd6f550f8ca98071813130ecaa9ea86d5275eebc36860690fa048c9ebeb46600b2b63e847bff3e38ed0d00000000000000000000000000000000113ffc0932c041e0e34b2540c485eb74f5029b339cb60bc88a8a749310f33f330dea137e5f340044fd689264af66696d0000000000000000000000000000000002642da3c2c7b6688aba0b19ab29ac72e35caafa044863c364ea8833fca850289de52c0963bc33d7bba40cb5f568718a000000000000000000000000000000000552d35ca054da2f148c119454f6760607b351f2441921a2be17da2cc10902d71571c5554f132e60df79679428fa07e3000000000000000000000000000000000818e567aea83eaf3142984bb736b443743659626c407987b604a30c79756081fa6ae6beeb2e6c652dbfe9cf62d44e3900000000000000000000000000000000193f0317305fde1046acda2c9491e376aa67244f68ef6495845d049e1293082af91f880be935d9d8ad0e25ad918caae200000000000000000000000000000000109224b8178be58ea4e4a194ca66bef9d14f6fc2c625d25feaa4f32e0f4d72d91024d96839bc96e6a624c5ad6221bd94000000000000000000000000000000000e42decf8a987efaeb4ede37236b637e61249bf6245679be7fd4d633e2d814ed4748b73890ad3c4fcbcfb4960cb67ae7", "Expected": "00000000000000000000000000000000041a5783c748247f05457d30d16f93431e9046a236d5025cc07a27b9f2abaaa556e2df65cf0f0015107253fe94d8b4dd000000000000000000000000000000000193638bf69c7508c4b12808a62e89883c34f97ded6e1b5dcc3f28191e5c7fd901a72a85ae386acccc9865f8144b1bd500000000000000000000000000000000180e8184ab583da58b77b8a4d108a366dff3e3b336ebc5c9153fa815188edc95e7067ef25f7d79526c295d634bc98f5100000000000000000000000000000000125b147100f6df0cede8e22151b3423b1dd364899fdee103c71a44388ff002a367627a2342e15833644bcde61f2ef6b6", "Name": "matter_g2_add_18", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018fbbcba3d4b1e548ceaec4a48db62a2420ff29a67af332ee7ea3f902f84e6c375fd33abc33d945c5bca25603979f9a400000000000000000000000000000000072ff416994364bdc6535f36c82212afa822cd94fade69f11eb38dbdcd37c7e22af55fe05e6a826dad822073656eaac10000000000000000000000000000000017bba179b847278a4878b6faeaab3b1f4bd7540d22817cd9aff95557497f8b9d286657b6162c0f89f7820becc637dd550000000000000000000000000000000018e2bfed71aa9b11fefca2f0db8bd9b8c69540267de50bec4fc90a6e9741891465c9761d19282e1100b3707eeb598b31000000000000000000000000000000000ca0d865f8c8ce0a476f7a6edb3ce4bd5e6c3a8d905d8fb5a10e66542f4325a9963c2f8d96f804f4d295f8993b5204df0000000000000000000000000000000005a966f6254f0ef4f93f082a97abe07db56f00c2ade047d2f0027edef6f00a0dfecaa24d50faa778fa29087302211f7e00000000000000000000000000000000121c51da366557c09af1bbd927521da88dfab3e2e9a95b6effb0a968795486f281f0c887e37f51837557b9e3808987130000000000000000000000000000000001a5524975400b1e88f3fff8dd34dadf5d75564cfc0026df31ee9c2c1d48b0f69a48e1e4a48cc4b7db61f023a7915780", "Expected": "00000000000000000000000000000000095fda8adf3981f4468fb82aa0ccf80e55138c922c6422cd8e67f53ee63e7a390bc345469e9211a1f8d810cf4ba27d0a0000000000000000000000000000000015c19b6af21f75e8e53fcefbae1c8d7f97853a8aae5fa62e606cfc92ae71890702ef9dc5609d3ca8fefd415fbd820c04000000000000000000000000000000000007b7e908766d34c5d99cb7cc76d5d5ea83c29ae1d9b83b163741bc9962e293926b1e251b546ce0c1268def728da78100000000000000000000000000000000084fbd6253211f7d66d52b7f14360729d54b2f94c52f2b76e521dc3961c40b4f19944923f64c6425a44eb158a9727a4f", "Name": "matter_g2_add_19", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019efd37727dfaedf697fcda7a59847dbda8ca7cdc92f34e68691d682e20ae6545ac104d6660fdb8f64a051e69298eae8000000000000000000000000000000001225ace0fdce456dd888c9672503b68ef77b2d11caf1265a767a6ea14911e3ca03fc153f18dfe9d95e0cc68b7b8a3a8d0000000000000000000000000000000008a6b059c1c4da046cc0b1b5d7f33270aceffa607daf6d0d078c06f940604e1a0b4adf01a4091306e3c7eddcf3d95101000000000000000000000000000000000f79bae5260a2f114ffbb9273f3049d3ebb002500a57ee0a7d157d86957f43f87a2e026fb9892dacaadca5ee04fc8e170000000000000000000000000000000002b51851ef3b44481d13f42e5111fa4fec04be0bf6acc7e59dec3a8c8113e5bb7b604c6dbdc5e8eddc2a1ffb81bc2baf0000000000000000000000000000000018ddb483ae75402852b7f285277ff7308ff78a3364cca8b0e0e1fa9182de275fd55c1e8ec3dbde180379c4280787ba8000000000000000000000000000000000170539890c89a4f91acd59efd413b5d1059f0c8fd8718e8f722e865dd106a4eb02e6fb0cd71b34ebc4b94375b52e4dd60000000000000000000000000000000001c2e9392f5d4b75efc5ff10fe97f37e2671cad7e4710765866e92aec99b0130e6ff1314502d069fb7b5f86bfce4300e", "Expected": "00000000000000000000000000000000121e7f2eb906d0b31b8ce5cc46638428b6ee57a1ee70e4ec3c2bc044230b9b86875abe0862145b442c0e34308efc690f00000000000000000000000000000000139120d0a10b82737561d0b3fda01b6df69d9beb7dbabf3ddda036f9b4c317f3ac1eaf400013fe5ad664bea44a73b336000000000000000000000000000000000a923184b381027d8cb3f82708802b204566b2b8bb6a72767aa396324d8a26b4e0f0cb92fd1914d77a4e9af2f1ec31e3000000000000000000000000000000000409732f2225cb5e5c002bef17512519eb1a18bf6c3d7f834d0c7ac8a38433c88b550b3f443d259313eb1133620ebf0c", "Name": "matter_g2_add_20", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000016d2b73eeceee17d3bff3aacac9df9ac1c4248d9ea7d6a503a757f7bb22fa6970bb6f5cb5ec154785f7252e1508b382e00000000000000000000000000000000081edc68bbd8db7b10be06ee23d090bd54f9ca07ef24dfed7df7bb05f8cc26e6889dbd40ea203fd5cca5cb588199f9e40000000000000000000000000000000010d3478508619ea9493b4330e2fb9150024cd32dc1378f824788a884a4a30fbf39c630f465557bf0c6d69b4cbecf89f9000000000000000000000000000000000f20c9b134db5d8b7756800c031bf5962fc560ba95d4bd9157b16179f1a37ae08696a2be455ad8d018aead6adcc69b710000000000000000000000000000000011bbc566a10eadf16009c1d2655cfae6adfb0f56f5e55b31dc000414be1b4cee9a0b9f7d9eab4c6829037c327914d5640000000000000000000000000000000009b28329096d8644dfcba6e92477eafff29f7477da4581ce76d1493f03034d7f5d3acaadbe42c76a83ca51db79d456d10000000000000000000000000000000019f75a303fdede5d97f3e521b03ef6b9d7c008d770b59ce3ac38900b340895e008342701ad1b41830b9c010936f4ff1700000000000000000000000000000000161aa1853edbb56fa3bd685c9c6b88e466dfa3c4f194f6774b4d9b1f30b016993bd0d65e8e9d6dea6caa196ff735bd67", "Expected": "0000000000000000000000000000000006a200642d5cece5eaacacb36000b4b897e8d8c661c8282f90495002aa515c7638183cf1e80a0b35e953adb92b6bb845000000000000000000000000000000000e88d4cda34e98df4d727fda79b67961b5b8efb1b125ef2a8eafc481a2cb2fa1530e59a091f31c25cc49d38f545491ff00000000000000000000000000000000082f38c1a1c35981f537547dc3b59331ab8c5e8dd261df58fe6f0c44ef1e65d0cdc1980e1a62f6248f38d0afe91e5627000000000000000000000000000000000eda1002e202e9ee4df5354cb87760d4df32eba1eafdad27cb0636879370a8f93be0bf2a30f15f2fbcd7e52c1bdf6b05", "Name": "matter_g2_add_21", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003dce67181d23af9729e9fb0653d7f79c890fba27de42fada93123e112c4a468fa889921192db8047d86e4db77c60266000000000000000000000000000000000869a1e39d42d9bb0cc0568fdad16abbdac3194af893ebd8dd8f8c2c3c855abefa5fc215412168acadc88e658e83f5570000000000000000000000000000000001ef139a75194f3c4b1378c2b66dd304d179460bac0a289405cd8faa3ff66a7b6e54eb7b8742a68150b1e098630135c40000000000000000000000000000000003892b5a645af916be2c6c7fc0bb08fb5f39341d3c68598940554e1be11e1be75af920db0c8710ed13c78edbf683f17d000000000000000000000000000000000ae7289aa9bf20c4a9c807f2b3ac32f0db24e9a0a360c92e5ce4f8253f0e3e7853f771597c8141d705062bef12d4fea80000000000000000000000000000000001d2f610d79110f93145faad2e34f3408316b1dc3a72852e811b324577d9037035e24af25002ddd100cd9283b70ddcad0000000000000000000000000000000012947315d5c0ec670619125eed0de3dd259a008baee4379b82accf2391e70a2bdad264cda04c3bc1b5394a62559fa0ef000000000000000000000000000000001239e687c4d3417c3c9b655035f8d8a649c255f9a8e6f03b785eed0d416a1cd6ef7c8b45563acb4616af24f64dbccac4", "Expected": "000000000000000000000000000000001341cf3316152ae8d57ea2194224f04756690133d2e02d077dc271aa577278e346e0ff66e8a49ff8c983fd34546e1f6f0000000000000000000000000000000016c9093da650643f4b4061e1c6e55da6ebaf9f234bef8325aeecad3863a0a2f53e1cdb2d54aa8b075ce6e6632fb4cd660000000000000000000000000000000011eaf3dee010bf2a16c5fbb1f7aa559cd4d831f087d9dfad4e157a6d2b6495e370d9791cbaaae19339a65726ebfc3b910000000000000000000000000000000008476d793305204be414819fce2ca70754a532682876277bc0586514f2096ba9998ae848c722ead6722d5af9395ff77f", "Name": "matter_g2_add_22", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000264dd4b477f5db65edad28c7153ed919a863c5c5661e0125c5429b323e055fd69c33142dfc6ed9c87082e2be4675e1f00000000000000000000000000000000046ea088a2ec94d3a1f1f97949f1ebc49690c453d316cc46534fa253b34b30323b6071d147d64bb94e02fb4db07bb0c400000000000000000000000000000000013692a33bb1348486eec40a9e93a4ea3810c7b4d3188cd07e235a2c898aa87ee0d17682fd24f4d978f9fb028fd26e2900000000000000000000000000000000115f8b64c00cd5cd344a7b5edc0ef0bb85a3e8f0f9dfb28f8ffe12db3e0d222c2d45dcdba0fbdc161c5d558bc71aa097000000000000000000000000000000001179ee329771b5913d07818e70f6ce5a58d74ea0b573eaa1bd3d97e45d3eeb27fcc7d37dba127af7a38354cb6ff48f7c000000000000000000000000000000000c898abe6eb76ef99f5143cfb8d840a918bcc9096ce25caa45d0bf5d20814cb01b024f1fd2cbecb6bef65d9456070dd90000000000000000000000000000000008e2a4fd746e86f90484f9b9b7b47b6afe5833762e515ccb276c554f00df88dd9aa0fb792c5f419dda0465cfed838e7c0000000000000000000000000000000012b5e6f7070c0045ade96f548ed6428c5030fa20c6f6f37a42fde9dbb5cd01def0fd8585bf8aeef913e7d42b9ef22efa", "Expected": "0000000000000000000000000000000009792d98ab9b90c2467ad0d070ea44f382ec7ad5290a59d889313c5a55d7b8e837333ad7ecfd97221d405cd6c549dc8e0000000000000000000000000000000002b92dd07b61faec23f48b8a7893dae29509fefd688a978bc2e870d4cd6f963d708a0611b4aa65f5644fbc6ba4c5e66b0000000000000000000000000000000011e46a283946a8e033afbf7c14ce3162a05867809d7de94a090c8cc2cdca8bb79add21f6e2fa8d7f39ea6d26cd37ea850000000000000000000000000000000000fddb7cdf1f1126e7a6780e4892601121b289a386ebce0caf96cd392ddc57c47e3f9284889fd8a18fb330d6c40bdf67", "Name": "matter_g2_add_23", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000014c83d58d90db4821a0411fab45f83fbc05f7d0d7a67ce75da3ae568978d15f4c1886c6fa6086675c0045efb30d818400000000000000000000000000000000001e68691123451f4c3df6dae62c6a63855ec3597aae33a8a10ee274e902e9aab1460cc9c79726312df0ee0ce90c8d3c00000000000000000000000000000000018a39eb3e3c6c7fb8ee304e55d15e209afe2fe278dda93552a7b9f51fbd778da1502eb6775cbc3f832f8320fa0686240000000000000000000000000000000017c15910fad1ca5749aa82a5a2fa98b0ebb37e92912547fb1741f18c34e0d5fc3a307b928636c25f0320d71cb9d31062000000000000000000000000000000000fe2e61bc8e9085d2b472a6791d4851762d6401fd3e7d3f3ba61620dc70b773f2102df1c9d6f1462144662fb2f15359700000000000000000000000000000000031f160cde626ca11f67613884a977fb5d3248d78ddbf23e50e52c3ba4090268c1f6cd8156fa41d848a482a0ca39eb04000000000000000000000000000000000eb61ba51124be7f3ee9be1488aa83cbd2333aa7e09ae67fef63c890534cb37ca7de3d16046b984e72db21e1f5c57a8a0000000000000000000000000000000006bf6f5d65aa7d19613141018ac8bf5d1e6fe494a9f30da215a2313a0241779006bce33a776aeedae5de5ea6ee5a9b9e", "Expected": "00000000000000000000000000000000054dedc002c5f2da8c6e0a0146bfe5c83200b276b074e6d6f2c397e1208f152d3ea3e8f0da7da62cfd2a028d4c94fe5b0000000000000000000000000000000012ff307f86e266e7a212484a169d3e81df98217c6f715176913b0d383cbe4e790212da7feca0cea66df09d92544fae010000000000000000000000000000000009c211438dcf8ccb664b535e73eff304b92aa2f568aeaeb8e10ec142f92b211bb8147b250dad77d508cfe353667b6f150000000000000000000000000000000009d1734f4ecc88fd56f412f9243c387b9da659faa3fe7295580a6b7519b1980bd074339fa9b0bef44dcdd0cf0c4a629b", "Name": "matter_g2_add_24", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000fa96d9fe01c18732e8d6454df9bb1f482c4b9add837ce9c354c72d49c2d44ec694674aaf0e6d6a095cab7ebb57ccd9a0000000000000000000000000000000001f8ffe3fb7e9e311e0f6949c07c26a0febb181e37b2268bb5e125fc3a100323740d1ebaa5e635dba3770fdc2ce4ee860000000000000000000000000000000012ac42095fdb677720ab3f14bf0afc55c95b43d28d922a5f8cb0bd841306b978751d24546e3a6474976961d0768f29e9000000000000000000000000000000000baf9804d99039c9fe966a696c64bdacc9673b0906b4deab108d34fbbaa3b0905d50892278570564017b96828c7e1ac900000000000000000000000000000000196044a5cdbc5300ee837dca745a44379070e9297697f5db28df4a37307cc740abed45cc778a3f4e3b8c9890ab6c3c70000000000000000000000000000000001176f5de6a3577ad67863bd3d9152ab9e8184964c6ac276e95946788f5a76394047580077c0971d874a40d510eb0443e00000000000000000000000000000000147dd55dff69213c5760e8d22b700dd7a9c7c33c434a3be95bd5281b97b464fb934a3dff7c23f3e59c5d8d26faa426bf0000000000000000000000000000000019efcf03ddb0934b0f0dba3569809d5b48b863d50d3be4973b504244414e1e1db56adff51d33265ce102b320c552781f", "Expected": "000000000000000000000000000000000896a38ce734c550c178786092292e737d44fa5f503d6d3b66c75e6bb70b59d1db9e8baa1ea3e256e2dfd8a942311e75000000000000000000000000000000001231db96a35229a4c7507b0ec193491446a0b43115c27d18b3715fcd4aea14d4e5c99db5934e73bb0b86f1bb91ee96fa0000000000000000000000000000000000d6f95d5637b29ea889c028dacdcb484d8ccdb243da4d5ff49e5ad82f234d414dc1484e9ed6cba1b5940eaabd3066860000000000000000000000000000000007de052fbb76902e06e1783fa8afcbb54a5069b4c5e9cee78d43da2cf76f24843a740a9eec6fe9b8f9bc4ac9baea77a5", "Name": "matter_g2_add_25", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000014ce6d88a7c5c782562aa101550f1af487296adebd9dae8252698ba04fbd58b92e2216de6ffd474d5992f97d9f22800d000000000000000000000000000000000ce92a04f5c8a99ca0e93992448222519fc454bda5d1d8638a7bfde968386e4ba0dcd1da59cd81d4c4dca3e584be0275000000000000000000000000000000000cb570796f5c8f7b8aa02e76cb8e870d3365fe4dce5df07ec286a0a821f922b4003d5b69c0f1588206d9544013e268c400000000000000000000000000000000098056a033d9cdae86aac02de3a444471854b909680719154b44d4f55f30087294e39e57643c692d6da725b8592390800000000000000000000000000000000005d8edbabf37a47a539d84393bb2747d0a35a52b80a7c99616c910479306e204e5db1f0fa3fe69f35af3164c7e5726b50000000000000000000000000000000005015082d6975649fbc172035da04f8aeb6d0dd88fdfac3fbd68ec925dc199413ed670488dc6588f9bd34c4ff527f149000000000000000000000000000000001312d53088ca58dfc325772b8dc0e1b20cebf7b2d5b6b4c560759987b44060bf4a59a68d1a5623bbb3cc5b0bc3986b810000000000000000000000000000000012110cd462c6fabf04f67d652639d19640c46f51aadd6c4f9a6dd7806cffb6192d95c198f4c8284151feaa2e2a0dbc1f", "Expected": "00000000000000000000000000000000156914a9137e52abd4579599dea4c0f857eed0457ee1d80635d3a6ccf0c766ba8ab1b6f989711fbdf125c4ff06b597ea000000000000000000000000000000000c60184e8ab32019ce20d2d137130f657c8964406fe4abb26da232c9c5dbfab243837d700c88d6b9ea4b8f0a2f514281000000000000000000000000000000000dc3e6e3acb898552791431859943d0a83fb4ccd62e4ab2a971370a93a99a9dfcdbe4c42535aa063354e0f2cd48308c300000000000000000000000000000000025be02da875d4990d1f0be626ce634c4856ea91f88f636bc27e313e73897c9c13a1e3ae70c1227dfd4fba97f521d6af", "Name": "matter_g2_add_26", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001214aacb0a5e6b7a40369a83c07fa8cf1786ce7cbde2b5a501d9c1292532df7822d4fde10a31fc0cecce3a7cfe3311850000000000000000000000000000000004f9669d8fe4f884ae93b2505710e6e45b19b7aa5df8cdd811f09e547efc27d21024cba05e2dc9d057055f30ec72d9df000000000000000000000000000000000a852b821b31cd27eca19712a636aa05ef2cd82c36ac1c2ca240edc7d0172b42a72c42d3cba583a5b5129ac1c9486e270000000000000000000000000000000007bd8419e791a5cea04993509e91a980d3ae4987a5b322400b6e4a4f2b636891a1c7ba4de96b53426dd556532403d5a300000000000000000000000000000000117fd5016ddb779a6979d2bffe18032d9a5cdc5a6c7feeaa412381983d49ab894cb067f671163ccbe6225c3d85219db6000000000000000000000000000000000dcf01077dcce35c283bea662f4e4d16f871717eb78e630d9f95a200cc104fe67b0d69d95f6704d9812b46c92b1bc9de00000000000000000000000000000000121f212cd7251697ef6a7e3aa93eb0d7d0157cf1247d4411430c36c7277bf8acfccc4ed8590b5e8d0f760e0e4ed7e95a0000000000000000000000000000000007d22d78b486f575e01e21e1239cbedc4628ba7e01ecf4a3459bd78a9716e2969f26ea3f2449685f60397e1ab2aa7352", "Expected": "0000000000000000000000000000000010124c1c1c10868b570d2969ebc3bf5cd6bfab13ddc93f0fd2b8a1742eb8e04d31063bb81c52b92e253128d4cb4413a60000000000000000000000000000000013f89997cd2ddae00cbf24cb66a92146c553c6fae41cdfaef14d49078729f239ad2661937dd0d4d6ffd7076b03e0aa84000000000000000000000000000000000ba2ecf990cd846c95b35ab60d4f97f5814c8189190df9d521b3dae462f2d44db006a0daecf6b82c1459006bf82ef7c90000000000000000000000000000000016dc129b83cca5b3c699628d081306c5fa61faf9dda5e92894931714037628fb829c595bf64d4a7fa295f136ae244601", "Name": "matter_g2_add_27", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005ef88bf38b2f998dec7302cde829076e6cf69df23aa0bf6bbb39fc0d3d8b5eafba74efb928b1de0eeb3d86ec82612300000000000000000000000000000000011f47e9583997b19c36616e4bf78d6ddd6d67937f493986250ff02aef6e6e7ff074559af2f20a5bf1d67158e4a199cdb000000000000000000000000000000000007777c8eb259a836e6459b7bdb642f878d869fdcb31b105d01f280938ef5377f2775874c099dcd394abe70f17d595b000000000000000000000000000000001607379d1cd34e2d0ed765a339b21433e9aa489609b92414c6b5a05d796085269c288d739717def9db3502e055086016000000000000000000000000000000000224cbea61c5136987d8dbc8deafa78ae002255c031bb54335bcf99e56a57768aa127506fca1761e8b835e67e88bb4dd0000000000000000000000000000000018cbf072b544df760c051d394ff68ad2dd5a8c731377fa2a5f61e61481ad5b42645704a2d083c7d45ed4774e5448141e000000000000000000000000000000000740b8b7d7bce78a51809713656c94cf98de72887676050f65f74c57cbe574278dd3634c44e057ea95babcc3d230e3c40000000000000000000000000000000006696058a191c7012a4ee7c973c2005ac51af02a85cbb60e3164809a583b4431dda2b59e1c9ceeb652b3ac7021d116a6", "Expected": "000000000000000000000000000000000a66f36f2437db57473bd8b7670994f1cfeb8b43c0ceae358e63a5e4e52b737fce6b3d24cc4de593bcd44c63f2c5935900000000000000000000000000000000070b7ad970f03a38c8a31452cf11422159cd3331d746031781a5861e26f54efbaba63dcb1db8bab997eada9c3dac39cc000000000000000000000000000000000ba4a9d7350adca1ae64e722df11baeea77c5fb75c5b52c8c46b9d863a70bfed1ec47888e907213f4ed4dcaedd37f20f0000000000000000000000000000000008a64244f1870a1dbcc4bd4d5c9eb5cd5225713dc73aa22bc46b1cea36c88a66f85251a8a9ba7279c88bd5dd37a06f7b", "Name": "matter_g2_add_28", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d6e3068c082b68312141aa68f1540ea1415e93e7f1762b6f06ff408a9995542da1c727a13355c19f8f418a44de1a95d000000000000000000000000000000000dcfcf2ab12b1a0e521ab402aaa4d32ff649a5a97892eb6ad98487c3c73c35601c313b8130ad12e9098d16eed3bcc2e00000000000000000000000000000000013777b1eefa4af03dc44e4e054eb7a3a980a9c55644900b80346be84b970e1754d1f4ab771adc9249e4accf88a23fb400000000000000000000000000000000002f53b231f1209c6f8b52f99a78bc2147c951ac89b341495f4a60a6572985ce2bc823625099ec214bc9ceedb2deea3ff000000000000000000000000000000001522e0a4ccd607f117fc6fc8f9abcd704e9850d96adb95d9bfaab210b76bfb2c5dc75163b922bd7a886541250bc1d8630000000000000000000000000000000018a6e4327d633108a292a51abed43e95230e951e4476dc385ceea9c72ed528bf3e06c42d10cefbd4aa75b134936e4747000000000000000000000000000000001198587188e793ad2ec2fa0fa1d0da9b61ed48444fe6722e523aeac270f17f73f56b1e726ab811bb54a6e42e506d70a20000000000000000000000000000000004bedd94182e0f16c71223ac3d68ab327d28ee0ccdcd2c2db07faf69e1babe3fbf3ba09c28b146eca7ab047b59294703", "Expected": "00000000000000000000000000000000079f89f2defd1f97efe0ba1db28523abc88cdf66efd39918a600a07c5ed5b72ab9d3354a172735e7749b5f6814a48f4f0000000000000000000000000000000009e361b8609be8057e5b3c99eaa1727fdac17edc59239af17f55d72c8b8daa89726f4ae240c742ec4b02fbd89d45c46400000000000000000000000000000000121b475a2ab50357ce80fe01fc461195029de20f61474b0773d80434253adfc268a775e1a0e3b7df5e85d1ff8c5008960000000000000000000000000000000019a76aef4e04136b1ad0d03586a3d8608ac4573715f18d5fd6907d03e5fec7c5659e15c19fd87f242da972b651dff5fa", "Name": "matter_g2_add_29", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000161c595d151a765c7dee03c9210414cdffab84b9078b4b98f9df09be5ec299b8f6322c692214f00ede97958f235c352b00000000000000000000000000000000106883e0937cb869e579b513bde8f61020fcf26be38f8b98eae3885cedec2e028970415fc653cf10e64727b7f6232e06000000000000000000000000000000000f351a82b733af31af453904874b7ca6252957a1ab51ec7f7b6fff85bbf3331f870a7e72a81594a9930859237e7a154d0000000000000000000000000000000012fcf20d1750901f2cfed64fd362f010ee64fafe9ddab406cc352b65829b929881a50514d53247d1cca7d6995d0bc9b200000000000000000000000000000000148b7dfc21521d79ff817c7a0305f1048851e283be13c07d5c04d28b571d48172838399ba539529e8d037ffd1f7295580000000000000000000000000000000003015abea326c15098f5205a8b2d3cd74d72dac59d60671ca6ef8c9c714ea61ffdacd46d1024b5b4f7e6b3b569fabaf20000000000000000000000000000000011f0c512fe7dc2dd8abdc1d22c2ecd2e7d1b84f8950ab90fc93bf54badf7bb9a9bad8c355d52a5efb110dca891e4cc3d0000000000000000000000000000000019774010814d1d94caf3ecda3ef4f5c5986e966eaf187c32a8a5a4a59452af0849690cf71338193f2d8435819160bcfb", "Expected": "000000000000000000000000000000000383ab7a17cc57e239e874af3f1aaabba0e64625b848676712f05f56132dbbd1cadfabeb3fe1f461daba3f1720057ddd00000000000000000000000000000000096967e9b3747f1b8e344535eaa0c51e70bc77412bfaa2a7ce76f11f570c9febb8f4227316866a416a50436d098e6f9a000000000000000000000000000000001079452b7519a7b090d668d54c266335b1cdd1080ed867dd17a2476b11c2617da829bf740e51cb7dfd60d73ed02c0c6700000000000000000000000000000000015fc3a972e05cbd9014882cfe6f2f16d0291c403bf28b05056ac625e4f71dfb1295c85d73145ef554614e6eb2d5bf02", "Name": "matter_g2_add_30", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000047f92d6306bed1cb840f58fd57b5b71a5df7f86dbfa55a36636cb495e08715cd57f2f3e7cd99a1efc28b1d684de1cb0000000000000000000000000000000000f4eb02d687a1a6105b4dbd740e2c7924689d558e6cbfee768dd303cc8dd0fd887f5eec24b54feccf00f473ca3f54ad000000000000000000000000000000000edad68c4d536912816cf6ef039c3dd0535dc52189583270b3b038e2c67b213d943bf384ce69c4a9dc526d7ef309f25a0000000000000000000000000000000006ff4a6b5129ef026d1d5704bf7fc0b474de92b5cf39722f165e73f4e7612d6d3bb40743e4b7b42d0dad5d5d6a2d4881000000000000000000000000000000000805892f21889cab3cfe62226eaff6a8d3586d4396692b379efc7e90b0eaad4c9afbdf0f56b30f0c07ae0bc4013343b30000000000000000000000000000000007853f0e75c8dee034c2444299da58c98f22de367a90550dbc635fb52c9a8f61ccc100f70f10208944e48d09507fdce100000000000000000000000000000000064afd6b3ef7ff7ec34f1fa330877b42958a46a7698c6d21adf73bfdfcab7793b312e21e5988652e655f2d42edb8a673000000000000000000000000000000000ea8a2217c3dbcc0f6e562de9cb2f334c896577d0b3a7108d96b1aba2d705dbf531e870d4023cec2c053345501324233", "Expected": "0000000000000000000000000000000013f8cdab447ef9be450b87f941c96d4e93d5efd811d80c6a910965728f7dc496dec132f3fbeee5d1e84ed7c24ca9c2a8000000000000000000000000000000001537d5caa13ddfac93f0f86729c743d9a68175a78c730528b581fb54b1f4d020473b3b766e3882a485ce5d02ab381c33000000000000000000000000000000000b370903684ede24f3df80e3834ed414a765cdbad98f20c49bef8663a82a468d3911d6bbcdc021e22c252e83a857e55800000000000000000000000000000000100cc8d05f071904753776c6092a38db84c5de751bf93216131a0f9a50bf78a722344a14b3be2a9207568d1f669d208d", "Name": "matter_g2_add_31", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017b32e613cb38b41dcdf3c8bb9187d731546977fbffd79fa7f66e3d6aaf9e1af6eca2fcdc260c8f90818d7148ba2f4960000000000000000000000000000000007e4d26606a47c874c20e8480a9f5815e5b577bccd783b775d10309eeb3d2102c7a0abc3324679e44362f09e7a4ada67000000000000000000000000000000000cb6f12ac8b49cfa36b957591293c87b21af0a949c55a28a90ab0fce88fb5cb7645e20ab2edd284f0ad1377dd95ac10e0000000000000000000000000000000014c96b5dcbd3150eeaea5c2bc27750cf88b30a91933a3233a4d1d9b357a80cc20d135e43a344e718dff5c79045c31f860000000000000000000000000000000011798ea9c137acf6ef9483b489c0273d4f69296959922a352b079857953263372b8d339115f0576cfabedc185abf2086000000000000000000000000000000001498b1412f52b07a0e4f91cbf5e1852ea38fc111613523f1e61b97ebf1fd7fd2cdf36d7f73f1e33719c0b63d7bf66b8f0000000000000000000000000000000004c56d3ee9931f7582d7eebeb598d1be208e3b333ab976dc7bb271969fa1d6caf8f467eb7cbee4af5d30e5c66d00a4e2000000000000000000000000000000000de29857dae126c0acbe966da6f50342837ef5dd9994ad929d75814f6f33f77e5b33690945bf6e980031ddd90ebc76ce", "Expected": "0000000000000000000000000000000003c5498b8c2d4765a270254dc927c6edf02acf0759540ddad951ea8c097bddb949ea0bf19942accd615bef21e8572dff0000000000000000000000000000000004c17bb648909bdddab4dd86560cb6b341e96f58c515ce471281f226181bded16b358b56d72e363f9ec491b8a9dcd92c000000000000000000000000000000001828973958204f8ab8cd13f5af5f3529f368a149bfe931a8002b61a61895457fbcb0cc6874631bb55799c884b998d8b9000000000000000000000000000000000f61460bf61bbf3ce38917850bfd3cece1e3955ce29d200c6f8aa89076c70919c02668678edc0bcf94efc9e9ff6a650e", "Name": "matter_g2_add_32", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001ca1141ba9542c56de8991b313c6ae42fcecb6751b0b81b8cb21ed70d5008f7ffe831766b89880a7fa6dfdb09a2cda3000000000000000000000000000000000e6766b17db165bba564ac63ab88d3f8f5eded07a40b48644e60d3223d30458e7dabe404cab8d6f9fe135712ef0b1a43000000000000000000000000000000000dda3e6c87382fa762510e5cac721fd2b654f002f5b9a3767a8c6d651ccc582e80e3f68d6913cda30f9f51ebcfc7c98600000000000000000000000000000000059a7dac5bb6b504f2bd603d486700fe22c14f25254537b2c9079c2b45d36c7ce56854c5699cc7649b533194f51a9045000000000000000000000000000000001755d8a095e087ca66f8a118e0d2c7d5e4d8427dda8fe3049080f4aff12a8746f8c2679c310f4be0d94c5bef0414a7a600000000000000000000000000000000069c84c6419ed5c0441975ee8410065a56c65f07a4b545ff596b657dc4620c7405fd4d092b281e272773d2281a6359a8000000000000000000000000000000000e751ccbd475fe7eda1c62df626c1d37e8ae6853cc9b2109beef3e8c6f26d41a5e4e0a91bbc3371c7ab6ba780b5db41600000000000000000000000000000000184097644c9b44d543ebc0934825610590cc9f8b17ed08e9c06592bf85591d2702b18cf48a70b378926057e541eb8ac5", "Expected": "0000000000000000000000000000000002c6104b3494fdef86d53f87bea68d313188c0908b935fb3b9f636ccd401c6e9cbd33bfcdd437e1a0150d0e4b9c3a881000000000000000000000000000000000bdc88396f807d1ba8d4d6e284d008b5e40445ce32c23a0178824fdbb6db3c5aede7687eaa2f12249125cded57052ad2000000000000000000000000000000000c7004365c1d3027997b55bd258dfc61ae07a762666fba2a14aa2ca116673fc03a6f694c069f53cd915fef6d37513101000000000000000000000000000000000ec17688d8f53e2c92502091c859cef4fe9a57ae984cb1e72686bf1f0656b10246293cae4b96214a38dc76cf2709bd59", "Name": "matter_g2_add_33", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000090f4b85961ce97cf7f99c342d3627105d790f611e19721a43d8a0febd67ae393d77a02b999108efb56f0397dac22703000000000000000000000000000000001112f23595d1613c47486eadc37f9b1ac3b3c3973b3fe964d3b67c3996fe2eacd9df5c287b0cea8e9475d146fabcf9e70000000000000000000000000000000018f46f7ba3c9af34c1025c2d460f0be966e68944928dbd55cc7fe00e5def598d80b0e3801e48a74963c974ab4727a52100000000000000000000000000000000096845338d5cd2ac44e097607d6a1a05c241eda1941991ae9edbba965d9029032c46da7218b5b2338e6c58898bc4a820000000000000000000000000000000000213e5d2d46523203ae07f36fdeb6c304fb86f552fb9adb566711c31262629efb0b1561585f85d2ac7be174682229bd8000000000000000000000000000000000b3336b5a4f7c0d16db9615e77bcdd55b7cb5b5c1591d835f34f5c1f1468e3cef954608667fb97a32e4595f43b845612000000000000000000000000000000001869606dde1688e5ae9f1c466c5897fce7794f3735234b5af1ad3617f0688529499bbdc9f0b911840a3d99fd9c49150d00000000000000000000000000000000001bfd33df4a6059608ada794e03d7456e78317145eb4d5677c00d482ac4cf470053d33583cf602feb67b6f972c99739", "Expected": "000000000000000000000000000000000a44e6a48ea0a95667f607ee66290cb0094c964baed779bd6656941db28e30a7e9effe49a617be9ab376af4f535cc28f000000000000000000000000000000001933b87310bf5fa60b1abcd13bb7ac3f2ec0a278f6a0a70c953a2905ac1d3bc5a70cf1da885af45d1c7680bb4f7ff74c000000000000000000000000000000000597ce9f1bf7efacdcb0250427d0341e142226aaea060983175ea149912c5c4f3019fe87be6d87d186a8f562fc3059eb00000000000000000000000000000000198b5a891722a237a5e23e3004798c8d3f069af3267152508e283b4549fc5e8388330343f80e606eba30af51c99c7020", "Name": "matter_g2_add_34", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000aafe45ea7cb8b450a51263eebc28c1ded662972bee512e24fddaf64f43b74b66032523b3b104a4e9f6b62394436c6710000000000000000000000000000000015cb27e1fedfba2d1679f78a388f90b22bbf3e7d090f0ba972fa8e72f6e31c446f628fff929953712ef6e425d16eba5c000000000000000000000000000000000df9931893cae713042bf722db6ce394b6f346587278a154c271d8511e690417eb6dc47efbcebb7c2fb9e77f1de9fde800000000000000000000000000000000106ffa395ef170c99bb5742428ae88fa4fd7a94476985c099e3b700b7403d083281fb71a19640c6bc2321e27bcb33fe20000000000000000000000000000000004ac6e6077d4eddd0e23f30cfd64b7aa1525c85424224e70c15d7535e02aea7a312ef24ba2dcf70b926acb851da2530c0000000000000000000000000000000006ad07d3e8f45cedfb4279913bf0a29e37604810463d6020b4fa8c8c4977d69cffaa33e1149706f04eb237194dcafa520000000000000000000000000000000002c536dd2f05f4a7eaa33fd884262b22a2ab2a88e7b63cb08ebb67fc0f143da7d6b18dd394c424161f7cf703acdc82f50000000000000000000000000000000002d1d9ff74e20ea9b03c478784f57e7a58a21ca2b1e552319f33305f367f5ae4daf8138505f953db4f86c0ec1d96d5f0", "Expected": "00000000000000000000000000000000047c2ccda315b9c013e87bc9168b3b8dd6d463403f1cefd824fa9f93a99f4c4f98fac5f97e4237f76b1ec91042f99bd600000000000000000000000000000000036861fd0a69cbc851741475905441b51af12c5b2aaee6ce9a27a01a43db810be9c7d6fa401406e98e327703404b83a5000000000000000000000000000000000310cbdf53f6cf8d87e2d178869bee4359a8dd666986d869761a79963680a33ea3ecefd40a1e558acae5ded2ca04447300000000000000000000000000000000108bbb28c73ed7e76a51a78e4d15a2c88c25e05c7127ae89d4347cda00be231b5e70e0b0562caddd4a7083efa4516722", "Name": "matter_g2_add_35", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010b1f8b1c492a56936da905b8738affba6bd29ae5fffd40ba6b31325181d3b489a81b23dcb69f6e71bd29bfb388e5a8f00000000000000000000000000000000116a115303b4774da59844e457844232d088062d920db67b2a8450a194be7e5340ebd4d106454fd9a03c8f50dbb1e119000000000000000000000000000000000eb521edd61b38006cffc43ab72d395d669dec196846fa4d6d43521da6c2fc3bf0994ce7556a3cffec7751b3bc5703ff00000000000000000000000000000000073cea36eccaa1c78deefb6029903c2b6598301bdefa9759719c3b590fcc5a6a4d3d4d19f552b33f4a3126a6e6a84486000000000000000000000000000000001913ce14bcd1d7bbb47f8efd92d7ffd155ed1990a1dbf1ee7d5e6d592a92bcbec6e865199362950afd6c8fc49b3e10a400000000000000000000000000000000020df729079e76cf06f84e3355e683e093dafad38c2ba92cf7a9faa0515f2f44d814f971046ea20116cc4b0014d7ec350000000000000000000000000000000018db123e05404eea8707f9356f417c3966312b9e41765a6fd8449879ddc4c9850c38434481b235a5bc35db1b8ee86d43000000000000000000000000000000000b4162715717e9065a3849a9294cfe39b351e57ab5a6790f3e725ad9fbf0e4b9d6a3554e872af9c37df33bb896dada5c", "Expected": "00000000000000000000000000000000137d23ed3fa0d7e5928af8d1f4bdfdef08e0b4c0f3bf6f51ed28960ce9805eb8fb254233bb18cbfecbadba95e112fdb80000000000000000000000000000000018615147d7a8cce1dfed6de25cf2fb52f54a243bed4913e20e66673f47ecddad9c5e4ff9653f522180de4b90ddb3ad17000000000000000000000000000000001521f12116b13f785b5211aaf438aa6668bbfa318cf0ed6d91aae963f6f00d32cc5f25d3a02bd902ccc25f847ee2db830000000000000000000000000000000014263b23396f4facdacf13c79864157823db724350bc640abf8fb6d62663cec1069eef9db56817660510e2417b51c616", "Name": "matter_g2_add_36", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e3925fa085db73c1e67b29ae90f8773f83be5ec684402e8e2360ffee8a8368911e584843e42b0d470de78591df6ea6300000000000000000000000000000000075c7efdeeb16609b4a47ea442af4d75238fb7534fd96cb236a7886809d6adc2b62c8ff72bdb041bc51c1a71b68219e300000000000000000000000000000000088b4eb0dd185e51b737d797334590e982b7b0a5f109fc7d0524b2465c2c0457964eba5a6d2d4d99fb628f21f15a776c000000000000000000000000000000000fc79f6b38f3356972669290eeadcd992a22bc1191606b663a1e148aa58db3938f0fc65e536bc5811c50d9c7f03d3e370000000000000000000000000000000008be924b49e05c45419e328340f1cbcdd3350bacf832a372417d8331c942df200493a3f7f2e46ad2cdaf3544cfd8cd8600000000000000000000000000000000028cd100457f4e930fc0f55996a6b588c5361816bb853d1f522806e5ec1c455eb200343476feeb07ca77e961fc2adc1f000000000000000000000000000000000f6adad0a3bab3610165be2fadb1b020f25488a0af3d418b7d7cf1165812e17aefcbc23308ebcd31d22ba4ca5773dd87000000000000000000000000000000001657ff792e3d89d5d35767bd0cc788411b0420665a5e0704f4d2399b9d9a5ad3c027ee030fdf495e5a6e2a4c69d05712", "Expected": "000000000000000000000000000000000038f9df6c14f84b8ef8045010c8973e5c2f8d2e37268f6a674298de7b15cae82361ebbfaa00ea1cb2653c5d00886b45000000000000000000000000000000001376f7e2d5621aa9d6f7ce45ed11de7e0e1095ebeea976f78eb83189c6852ee199840c14059c233bc3d40efbeeb5eb36000000000000000000000000000000000c7b0e53adf4f0fc5172f903e3fc479539348241edc3e277f30ae6b4fc419aadcfb73a8f8a09a1ae1dd885a6250de0040000000000000000000000000000000007a00b57ecc8b056436ecacd7e0fd346b906b15042e9a700f54f8c3b1d251c566e0c55bd34f7a9e30f1566b7f2ab16dd", "Name": "matter_g2_add_37", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b87c47605fc060a8e3677e84ce9d14b9309360a13c80d040c625fbf0108f829300cc1fca409a0f9c96311cd4a9a21e60000000000000000000000000000000014c4088f1e7935cf6a1d2475b84497ce6a250ee2c0c991fe51a2f2836388a354824b02d9cf215328dfce3f546713e21100000000000000000000000000000000120e59be3ecf35674eac6cdc559599b273f13f28a529770fa156f8e519734c451eefb35023639f32049cd19ea0d945a3000000000000000000000000000000000f97755b62a8cb8f861ea02c77819f0b58181aecf612d92180ba9b475f0b4888b922c57f6a1c619dd5514620a1cfd9e2000000000000000000000000000000000a5048d860b997a9fb352e58284ebbc026622d9be73de79b2807a0c9b431f41f379c255a2db0dd67413c18217cb21b7200000000000000000000000000000000045a701a3f46ca801c02a5419c836b2ab3d74ebd6f4fd1e7dddb1965b49c9a278f6e89950e7c35ebc6724569d34e364c0000000000000000000000000000000004cb55008ccb5b2b8ece69fac7283f5a9ef9e622e2a0e42bed5bdd77faa550882643afc1759b1a327c4f2277e13a3d4f000000000000000000000000000000001690dee40c6c824dc2588fc47dbf93f68ac250b9357e1112db72ded905ed7b101b5f877bdc42d56afb5b6202403a91c4", "Expected": "0000000000000000000000000000000012662e19e41bfacc0c792f5183596bc7f1986f9bea72c626e187d72111b6ef3f36f5afeeb640cfda99b7044c0d0b846900000000000000000000000000000000050ba08e1b9fe95dc67e6ee1ce60664b291c80fdb59729cdea75dfd18f22fb88f837b439fd119c46c996787d3008194b0000000000000000000000000000000004ea0f488fece967675abdd3c42f8fec25b547cfc45d42fba14bbc55ad7e1a75296a679113d0671cef0aec0c2165f4a0000000000000000000000000000000000f617f51800b09150a7560505079c785ab45cea4705992fc0325edaf4ceb30e1f0bec35a31898db5f810685e55634076", "Name": "matter_g2_add_38", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005860cfb6be6720118623d2d8ba05e686df22744b948421dd3cc1b1691e00d9b5d00d00195b4acf7a7b043f764f3f1c70000000000000000000000000000000012632a3313dd611e8d969bddd556c2d79ff387603462ac78ded3a842981697bdac34ee6f1f4744ed2ff16100874ac24000000000000000000000000000000000112b94c317586e343acadeca611c485c3ea172bc10dd39158c1e678007130062a921b53826d7be6286963ff822f1066c00000000000000000000000000000000040de8c0dadd2a6c2a7ea0fa43e1a5f2f5a6be3fcb0de6875d8cef1ee2daad87125d12f6869c4dd3d931b296f1df2fb300000000000000000000000000000000153cec9690a6420a10e5a5a8ca46fd9d9f90e2a139886a07b375eeecce9083a5f5418e6baf64ef0f34176e432bc5343a000000000000000000000000000000000d87c1f37f83ae78a51af9c420e2584a64337d2d2dd8dc3b64f252c521901924e5eec1d9899594db5e64c93c7a01ef020000000000000000000000000000000017078538092ace26cc88b94360871fc9a6bb9992172158ef3a16467919955083accf8d55d48c7ec462a743dbbca7b448000000000000000000000000000000000289b703157a02fc1d687a5aa595495be8bbb3eb0d70554728255a44b7820e0ee82d984d5493c800f1d9d8ca0c9381dc", "Expected": "0000000000000000000000000000000019c774e968049bde2188e844c3413203bfe2c4355edc8cbc2cf6f977c34c0a42a206194e6eecba3c97b24558048f3aa700000000000000000000000000000000081ccf6f111575a946341759b9faa13f3608998fbf4ea3b547804737e30fc7e33495caaf2aa328b19bd48315c5c7f9e2000000000000000000000000000000000a4098536041cfb808176c7cd8e980eda613a2b390e8d63d607caaac26db02fccad6d87412b90cb4b3e186bf9ccd31be000000000000000000000000000000000d3c784c6587b9f786c06099a62aa639f40535b512ac2440912f04dfcd1cb5851b7378f381fcdf02d4e58312eb7e442f", "Name": "matter_g2_add_39", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006fcd2c4fe848e9462ba1112baad39031c210952adbdd06293a622ffe2d1c6e4fcc8773ec8913717018b97bcb9a554fd00000000000000000000000000000000130a97442f3273b7b35464545e7351faf71ead9b8996c63889a45945ed82bba29bff5014776c6185219a5234d8475c92000000000000000000000000000000000491d571bac5487b866022a0714be11b38bfb296233845cc434a50be1d35f516b8c6b046fe3d0a8f4f95ac20eddea01b0000000000000000000000000000000017e34b04e6fdf152c848f2432b7bd84b3dba3915f06eb77efb8035750aca9d89e92e1d1bc4871105c440d639e8d8b05500000000000000000000000000000000057f975064a29ba6ad20d6e6d97a15bd314d6cd419948d974a16923d52b38b9203f95937a0a0493a693099e4fa17ea540000000000000000000000000000000014396ce4abfc32945a6b2b0eb4896a6b19a041d4eae320ba18507ec3828964e56719fffaa47e57ea4a2e3bd1a149b6b600000000000000000000000000000000048b3e4ba3e2d1e0dbf5955101cf038dc22e87b0855a57b631ef119d1bd19d56c38a1d72376284c8598e866b6dba37530000000000000000000000000000000007c0b98cda33be53cf4ef29d0500ff5e7a3c2df6f83dfc1c36211d7f9c696b77dfa6571169cf7935d2fb5a6463cceac6", "Expected": "0000000000000000000000000000000016fc7c743c5ba747640a6494fb3c30caad5a1e9719a1994d0ca73bd1645fec118a2887acc8876d105102241c10274cd300000000000000000000000000000000058a42a0095a7388fba7ce71dbef4ecfd2018c3fcdde14afd2be26588de4689d8de757e1e3ff22645fb8c17aa60265850000000000000000000000000000000010bb622f649e346834b95e82f93ae83c71c0a65df7842c4ba88df7f6eccb0217ca9377167a6d14777e0474c24821f8d70000000000000000000000000000000010c180c685ea3d0146eb82c007fec3efd129880f18f838f1cd2f80181f5a4884d6b5cc8247430fb0c1701a57f9d1d485", "Name": "matter_g2_add_40", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f1b8df4e8fdfe32eaf227f5af9f2befc85073468f10b81d32d0e126fe2b0cc8e8adb8afcac73213b6ed95e8e843b97c00000000000000000000000000000000004e3fb435ae0fb2d8bd091f250aefe5922b353a64e16abd75627737f3bc56639f8b40652cae69c73ff1969925b0afdf000000000000000000000000000000001003aed7cfb00efce49d6b1a8eba27df87479a4d37bd7fda6121549483b669a1a761204b0dd28262bf27e5c8e180540f00000000000000000000000000000000114fbca7caf782b3296d0b26b4c362bf50acaecb8bc5726b2c99f904ec3d092d5d40991d0d30c8e79fddaa45f04a75d3000000000000000000000000000000000b6069a2c375471d34029d2a776e56b86b0210c35d3eb530bf116205b70995e4929fc90349a7db057168dbe6c39857970000000000000000000000000000000014251a0a154731f73513b99d830f70b6fc4bcf05d11f52d2cbe9795ee8ffc5a5f717ad25770b8ecad6d0e9f8066e0cba000000000000000000000000000000001172684b21c4dfe02a55e13b57bbf105c954daec849d4c6df5276b02872c004fdf09d24f4eef366bc82eb72fe91bf70d000000000000000000000000000000001151aeb9441c5a8fabe80867b5c791420645241eae1400bbcc064d75bedd39de2ef585138fe9f65725efa1b1e5888d03", "Expected": "0000000000000000000000000000000019419b635c3742cecffee02ee7e2b1f18ee9ff15e647ca0abc4398ddc421ae7e0444e3c1ec377def9e832d8e64fd40e2000000000000000000000000000000000d9b4abfdaf3b4c7bf00fa07579befa10a3418d8fa0f3a9c31e59ae48b0de50fc8e6d583aaa4d0fe6048bdd1a9c60eb60000000000000000000000000000000003c96d57034ec97c4abef1c2c81f4d4b0f4b6eb1e9dc5464bcab28572555b9b874df80325941501c3766fd7e06bfe7360000000000000000000000000000000002dbb3d72385b562ddcb9a80400ab3770f00d22b880cce2fce1641042b9da669b22b2fbc97617648c25ab644e661e2fe", "Name": "matter_g2_add_41", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017faf481fd4cb0c373d21d7caad40e93d9a86e62d26136892fbcc6f6e48205543aff00c45e82fdd1d3e0e733de91e7000000000000000000000000000000000012e14fcb9ad4d9d15347cf004745ed4bd92097eeeb41c4cbcb728a234616363589d8f5ad4cbb61d31a8aa27627723c7e000000000000000000000000000000001513dad1ff27e053902e779e35d04cab648939317830144ea775c435a4b55e13fa2fef03a1256abf5c187487c25a774f00000000000000000000000000000000139da29de8587c7d0ca9237c37a116387385e9cea453b9e2003a37ede7aa0a3f4c1df55255897f5975b662be33622dbc00000000000000000000000000000000161b70d0f384e589d8117938602f3d696f941c24e3c1ca5a9be090b670456c9df315d6fde52daed55c9d8335928a7a3c00000000000000000000000000000000186bb9e6f5ba70dd2c66a641d3b711844977939904c59946d4e9f49ac2d8c00890a43ccb20d4a62bfff63ce4a0a44e8e000000000000000000000000000000001995b9d697bded656236430e78726f0f6ef963db9a5a24d455c12db38aeab0f8629e5dc2d04920156f2a057d69613096000000000000000000000000000000001119b13caf82c18fadcb65c9c166914bfd822534bb9def3feae6c9e572c97c84e97fab3b345cf59358436a404075493d", "Expected": "000000000000000000000000000000000d32b00154a5fe75c576c098419744ac36b911ee800f94bd598ff9b6adcaa39c836bc158c5d6af72c9e715a242d0fe710000000000000000000000000000000006e057c13885d6c05f5d92061fdc4d532f10d31d472c371e71367fef7c5fdd3741e665321d1119b895660fba3770431b000000000000000000000000000000000bfe695c3364e15479741e974f838649e789a76d073e552aaa60981fbc6d185eb7b297fd59e51535965214a02f5cd67e0000000000000000000000000000000014f0a27412248e3163e5f82fed02a25d953b336b0201692f08a3e8e9a9d223b736c70c1a39826a0888fb02a314e223fd", "Name": "matter_g2_add_42", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c118b147ee3489f30c6ecc0256a314ab674110588e8b69ca6d265fc270c3e5b767817f861140cca5d7c6be4012d1ffe0000000000000000000000000000000014800790654726959fd876b035bade0da744fb36ee5b304f228663a531345120267c55ac19fd66022752010e5bea7cb30000000000000000000000000000000000193ab7ac2f151750356b6e178557460c9c2672b1736d19a20e3fa28082479ca60021aa68edf2524f1aa826ee70b65a0000000000000000000000000000000015cee9ac55ab45abbc57d0ea6ec9ee49f6c59f6b94f99589dbc08ee877d3a261ad77f5473fedd72ed7206647eeafb6ea0000000000000000000000000000000017d1ffcad218efd8b09c68eba34dbbc30b0a62ae250368ee37e5f6fd40479b8580563416afdbd92c0622c341331e20a30000000000000000000000000000000009f0eb3805ed78aa3952a0a437966258ed38cb72912756253a7a2f9113f0dd9a4e187062b0423e0587d93e904d88f50d0000000000000000000000000000000001bca57e985906695e14882f2aaeef75de5009e8717eb59962e978aa11e9d0a4d9a9e203df774cb1e993b1c6ecd6048c000000000000000000000000000000000695b11cc32740c91546eb7d554ca8b1f3afc942ad977345031be8b94b78b57a87ab049ca2d3676e039efccbf24d0c47", "Expected": "000000000000000000000000000000001566022247ce012b7de92c8495876b4de91c36448f4f7e00f6e154185d38a735e701dda989ae9e37d332a5e60af5d06b00000000000000000000000000000000065aa42560df7990df2098827a55ceaabf3ec592c53d2f20e5dddc1481ee64381accbc8e58601428d33589b3af78a4b70000000000000000000000000000000002d9b0cf8bfd1adf76bca80ca351a4340f02434090518807e07ed76440497042f13a0cd7a9c30086872d6f145808fb290000000000000000000000000000000015daaa131431e3e78a6221091640811fcf88c835ac975a041a7ab50bc1d06b80e6a3c9ae77d2390fd14cc9bb009b47cc", "Name": "matter_g2_add_43", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ef203fab794a0ef29eb2ebf00076134e5932e27c99d6d445695b9df2afe7563602e318caf5d44724a21790ca0ab0d180000000000000000000000000000000013b9b1b1d3e98b61b0f1a0ef3a1a4ceed57b6c01849a4ad66a86332b3d27022cfccadd3567e6709d2de5b23b23dba43f000000000000000000000000000000000c1fbace49684f4be32ef6178ac3a95ea3f50b11494340fb73dc5391d50bcacafb3bf0f2631fea9c4ec47327d644489500000000000000000000000000000000040f82812855aa3e3aaba826d5810c1049cf44e86e44e23cc6da437971b529d2f2676c73e1fb9da52640c981fbd710be000000000000000000000000000000000546a0cb9d9f1ef9ec4a1e576fa0047557a56c0217baed8691c4085b88c84a0e12d44043aab8671393d02c4a764407ee00000000000000000000000000000000131884c1386980a181353548da9602db70ab495a661e76235c4b0a32b54acb0dfd8846e17bebd731e8041c4aebb8776600000000000000000000000000000000135b3db43511dbd8b3bd5a91880d6da1a2bd1383000e0d6f0a521bf88a5836a3b5f7cb9c0c02aa861a1c2d339f3c11f20000000000000000000000000000000000e1337271bd3302a1cab762161ccfbf2a18b7800e6efe58cf897d4adbfe4cb3bf14f4b59307fffc548179bda70c18bf", "Expected": "000000000000000000000000000000001290bff629c93d992ad2cc709317c48980b0e56a32fe239258c7aec75e4523e0bc0b81319e100d10568a44847869a8d000000000000000000000000000000000055d9098e08eabdf2b883df35efebec9f6afb16d651ebaca1067e2129146268664ec51c8a4f28f13a250f3e9883053780000000000000000000000000000000002424dab6f0d18ea8bdded2a72bcf87c13307d27d53e8ec35e91eeab97fcf3398135fd436c530c609fd47a3508472bad000000000000000000000000000000000b25d0db1e28b98d4f9d3c77c0b71489c51186105d93be7fc2cf8c72b8abd8959340114635e705e698b0f257855ea4bc", "Name": "matter_g2_add_44", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000060d7a718dd02b147c265f71eb136d1f31781b12a41866b4f86d7374b93dd10058c192cc0fba928373b1526e1a5d7d7f000000000000000000000000000000000cf29275373c0573ef22bf87919faf5444847203c7dc6d2e18986152cc294be04a5b1a4b0536797158113a15276c4fc6000000000000000000000000000000001016d5b9d4d200d7b4b7cc3836b85d6697fe14db350badba9978c7b56983dd1a7e572640ee0372b0a4e2079ff4c1abf2000000000000000000000000000000000f2768d104d895473ddf8c6b3cd0e7c22458d0037eca6365c766879a07c95037ee0de00d32c974d767080935abbe0be100000000000000000000000000000000113dc3354146ca79eb103b31b61fe8bc6f33dcb9c59a7c39d989bd9411c1afce4239034f84e6b00a084be061c73e69c0000000000000000000000000000000000ae33bf68f24978c7ea9fc58d8d76047ec45d01fdbc880e6a5ba02a22a49a3a8253afe0678ecfa6013f4849da3401df70000000000000000000000000000000012c5b00376a1dd31378ec44f2dc8e321e17185d903cfc5c15345a01c33f2f151b21b938d31816550594a7a1e7216c5b00000000000000000000000000000000013d79f825c44775c68e90932d0496a5cae53f04a1edb19f8abeb5948a3dd325dfec4a8b6f58c7fbca9cf3c09b909d8b2", "Expected": "000000000000000000000000000000000cb2998b4e634bc83b5585b0683b7b561f260eefb826719bdc3c95e8ae51f8f7b442d75d69e0f9228dacde2ce80ef4e60000000000000000000000000000000014d30d1c02122143868ea01b454a4f33432d875f8ba66e6bb1e02fc161bb5f9298e673339a9183a15759f8b94b519cad000000000000000000000000000000001068bf3c768e8c9e9058805050394ea820b5f60bea6d271f8e1fb665d3b7931ab0cc03dff4cbd24577b2c254a956e8200000000000000000000000000000000008b7f4148bd1f4926d2a84497b60a48701057ea08855bb9a2f838d2464e66360a59d058d9072f1416023cc72045af558", "Name": "matter_g2_add_45", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017b9ca4349fecaa43ce911c0b256680edb8a0906ef5460fc4d2004579336df1e19560fe960a7a7cd74bb6e8272e08960000000000000000000000000000000000d5b96dae738db59cc67a51c61bec6deaeefaaa51e3259243fa4b142ef59676231229ae386ce699fbe18c4c00bf9d49400000000000000000000000000000000111b79f4b68dad16550a13334d09dc38336a75a5da23a17b5064e2d591aa3dab4c2e982a9f730a7633070504663a24610000000000000000000000000000000018f6d3616a7eaf17c805a88c9710039644d01b61aefebf76717ddcda6f4bb34aa15702de1e92bdb27b27f3409638da900000000000000000000000000000000006ccaf6c08f831be9c99a97714f5257a985cc2a29b5f5c81bc8d794dd0d8d1a41eb5413bed654c0140dbacfd0dda9e1800000000000000000000000000000000144e9cf91580800dfaa47c98ff7d002a576be76d9e44ae1f8335a3f733e1162af0636372e143174d872c7ea89f4c743900000000000000000000000000000000101e143b838c8a3f5f80fb1412081091b875230f1e2f9cf374d4bcd595392f6daa9552dbb6d5834e27b1b3dafe061ed300000000000000000000000000000000072463400b3e875395a1cdd31d73d51396e34347cd86d9f6f43f42253b3cdb24b89ed7434b1522af95ba1ee2d29ed1bb", "Expected": "000000000000000000000000000000000a7843a1d67360b8a6976aeda2e4e98f1ea229a4d84b947dcf5ed8215173d5cf783920a7714f5b048778df30f01a0bed00000000000000000000000000000000035663ceafda9e5bfe934cff725b36b258f12afe749f907a560a06da4abf8380853f8de31adf14d62cdb310d8740e29b000000000000000000000000000000000f210d576aa5d4cdf5aefd8e55be099c422debc217ddf0151b8801f7d16456c97d1e134b40e6d71d296ee2518e50af9d000000000000000000000000000000000219efb35c68540c6bb0ef224e68dae6f7d48425c2908440072f5f63eec3c8e750b559c73e33464d0b5cdabb50fc4d3d", "Name": "matter_g2_add_46", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000aeb5c087644595d0912879f61959d2731ff55260c682ed2bc5fc55c13964ef7c1f70aeb55876d2264d558c31371ca69000000000000000000000000000000000e173848f4570525b03a2b2c86f4dcdb8b28dd6d18c1354cad31028eb1b8b44432c2346edaace093e3954c7fa6d338a4000000000000000000000000000000001949b0902506d111ef6318edcd7a58ca4d69f5804a028aee73c3786cb2db168c6a73b77194f7a021ae6ae43ac78ade340000000000000000000000000000000017c5e28ba6103d97e2f3d3611c0c78f06406e0da8a49ae29c7d460b52f75136920784cd500aa3593858b877697eb8424000000000000000000000000000000001354146aa546754e10ada6e0fe98f04f5f3a3f8a8350d0295e02b8e9c80735b04c3061412e08ddb13c80ac36e5638e540000000000000000000000000000000012ab26513534b4dc1b71eec46b73199c4157ba9369e66fbe4d2d8f62237fc7c6fad31854ebd878f989b8c5cf35c7cfe0000000000000000000000000000000000eb731bc99cdadf7f2280385c7e17d72d34bcbdbdc725d5bc94e841036115e8cb95df08084221696f9be479821fbdd7400000000000000000000000000000000143ba7d3f66445249d9a81a6949f24ff40e7c4d270fa044a8b80200a4369b07806c5497a0ef9e9dbb87b9e63694623ee", "Expected": "000000000000000000000000000000000ce704e650605f747cbc0bc76e82de8569ba7b3d897eac2bf5f79aba17ef4c989731e959c0bc0b7988000a9b0aef39430000000000000000000000000000000003cd3f3d978d6c85d98812ea0e3d21149bf4151ad1bef966ced124ad62dc7cde55f16e8d08bb1ad54d3a23bb73795d8f0000000000000000000000000000000019d37a20fcf6244c2898b271535e3b8f279eaac5d8fb1ba142096da383488eba28a21d038d7a9d3f9e8a008d6d3ee1d20000000000000000000000000000000001ba9c1720a4ef07ec752efa1ddb629505b3586af415c916fb0ed2953cd8943d9343268f438db860f0bced3e690a66b0", "Name": "matter_g2_add_47", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d4f09acd5f362e0a516d4c13c5e2f504d9bd49fdfb6d8b7a7ab35a02c391c8112b03270d5d9eefe9b659dd27601d18f000000000000000000000000000000000fd489cb75945f3b5ebb1c0e326d59602934c8f78fe9294a8877e7aeb95de5addde0cb7ab53674df8b2cfbb036b30b9900000000000000000000000000000000055dbc4eca768714e098bbe9c71cf54b40f51c26e95808ee79225a87fb6fa1415178db47f02d856fea56a752d185f86b000000000000000000000000000000001239b7640f416eb6e921fe47f7501d504fadc190d9cf4e89ae2b717276739a2f4ee9f637c35e23c480df029fd8d247c70000000000000000000000000000000013a3de1d25380c44ca06321151e89ca22210926c1cd4e3c1a9c3aa6c709ab5fdd00f8df19243ce058bc753ccf03424ed000000000000000000000000000000001657dbebf712cbda6f15d1d387c87b3fb9b386d5d754135049728a2a856ba2944c741024131a93c78655fdb7bfe3c80300000000000000000000000000000000068edef3169c58920509ed4e7069229bd8038a45d2ce5773451cc18b396d2838c9539ecb52298a27eebd714afacb907c0000000000000000000000000000000004c5346765a62f2d2e700aadccf747acb3322c250435ce2cf358c08f1e286427cabace052327c4b30135c8482c5c0eb9", "Expected": "00000000000000000000000000000000160d8b4bef36fc3d09af09dcc8357067c22e421f3811deea66faec42a2f00fa4aceca8725cf99062613126a9fd7bf7210000000000000000000000000000000004e8691a42c8f3ce0e7c0470446689e9d2b3cf57d55fad7387d624857f977cb9c6864c87bb4b6a2c17538478ac5fb5960000000000000000000000000000000015e20f6baef033efbd38081d5a10eeb3c67d89ebe5cd652110b778313c9e86cffb45231616d5b67e9ec8b7be15980aa9000000000000000000000000000000000af75dc221050256015fecc2bd8113b42afc9c624e5d28d7ff8312af499e34a603d66a4304f263729b440b6266538316", "Name": "matter_g2_add_48", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f20a07526a082e88630a0256d134a8a5e8ada07b1cead39ee838dcbb30904e9016107fcbdf1f8ba182308dbe0b043d20000000000000000000000000000000014fb7732f67abf60c03ac902577532d0acadb5f3db0d6397a42ba693526ad74f2c61a0195bdc9704aaaf12e65aa6d88b000000000000000000000000000000000018cec4fb81c85d304588d11f8b9c51f5a053df11463e5812a1b2e6c7144522ba36bb91adf219892d0007cee470032e000000000000000000000000000000000b8e52d958a12a9037e8be9bc0d5045cade2d6ea05c6e68462b3a30b5d4ea34e5fbad173761e4e216b2e6958c8983b28000000000000000000000000000000000dd75b4aebed3bd6bd020c3af671aaed67bf1582aceb6c8b5a476968c0c500753e4d0f3276341b79d87af38850893d92000000000000000000000000000000000e9b3be06afd6157eb6df52be4f2db2bcccd650f720661f8d6fcff3f71d69e152e17100ce60b7b90a7f798c4cdd02209000000000000000000000000000000000f6fdc4e5dceb555c9eb4c912fedbfb3cb1b842345f73ded02cfaf8d397c4378809721094aa4a4113a368e0787effeb500000000000000000000000000000000143ac06258c579c11c05569669a2a10babc63ecc86f85c91791d8ea48af700a2067c5f13d2700b8d5cf59bcca8fbf7c6", "Expected": "0000000000000000000000000000000013edd8f016f6af49e9bc461ca14c438a32eaa3d1270a5acec99a666aba3f0a7e7eccea81720971cf4432bfa94cd18392000000000000000000000000000000000dbea5617e44c82da828844a5a4a1426d43422fd0158204a99f53cf9821f82f0bb0130a2123297a6941f695e172d9c5e0000000000000000000000000000000005f65a445e9f2d57dff2b210209f9faeb1c8b446454de4724d990aab20bd68362dd7ceb5b95de361c129855abba83f7e000000000000000000000000000000001219ecae79d62d3039e642369353993b1ece049331f06be256f06b01a1c3b0c617221c8d8f0bf4b6a0abe1191a3ee8e2", "Name": "matter_g2_add_49", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001468cb35a60898ed129f30c261b8431df6a154c250ec16d85a22f8717593b2c21853d123da86d977a7938c5ed74ef23500000000000000000000000000000000011f4e28e31b5f9e6877192a5e632d8c1ed7ca0c42e6e9902ca68f1c2de0f648c6064436012c5c7b14bb8d1078e02f2c000000000000000000000000000000000b25114b2697ca7eb1e6effdd1054893a188fd382d387ec098f846c1137a9b9baad01653b963a0b0bf3cb50c3ce3563d000000000000000000000000000000000c1d241cb03e642c1752b1e1886472477c19a2801ec032dc220c3243952f882094119bb92b621b654b766bc900d2d4f7000000000000000000000000000000000057bbf62cdf3c56e146f60f8ce6b6bdebe7aae7d9410c6902c7a505b589ae26ce3ab67d9b8da047185f9d37ab27595e000000000000000000000000000000000843e55c07bba3573592d3f649938654a5c51f9ced0f92bcb3e4f431141fe91a1de3695324b21e31dd2ae0a328055cc500000000000000000000000000000000192f3e8ae2588f9223de77f5e872115f1edec96d6a0f403a47879410c2562e79853c9a706e423b83fbf3154234edb6f80000000000000000000000000000000015084258d58fd1a07bbdb2e90df5a56ae15a787037eff4fe55f660e45f04820c6fc8982303b5e82074cf0cdcbde61307", "Expected": "00000000000000000000000000000000158da32df45fe3e9102010bfd7faf3fde936bb8e52f68262ef479ee825a0d7169ff753aa042883a5403103a9bdafd2be000000000000000000000000000000001800a5776a47f52d2af08144364a6cd7442a0e2fc214a2d8d285a29bb7bd3a0293e89f0a1856223a527100d0abf12899000000000000000000000000000000000a6079d18ff3367c47fa61a57a967b782f3529bee93f452ecebd4f5c404b3e1769c100da9b8aee4258b5191ae1dad9a90000000000000000000000000000000011d3188a927e8f13aecf7f8637be6ddbbce309393a94fef77923c286244f8531d3e137e031d8c1af829891425afd53a3", "Name": "matter_g2_add_50", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c80d4474390fa791ea5f2f16b41506d8ae13ee0993c8d31a07712687298ee7978a724999500c42400d2f788a5a36067000000000000000000000000000000000592705cc5a8875750a4e6ceb42aa3bef5593eda9e8212702a2e08ea70277a2a66526bc5237be33c8449301544da35e60000000000000000000000000000000000facabfbd15284c6433f17b0e6035d4fdd84d3ad2dd30a27d52809652ff6e7a684d7724697919100567ad0c3e1a26320000000000000000000000000000000006a0fc4e2af69ce15a356656f5d182a2cf213d76a6047a05a1a3375909d245f5316b91333d2141c0817438f0d87bb52d000000000000000000000000000000000bcec23e092111b38a2f7dc957cf455312ffd33528d084204314492440d29248cb5719346a4f7a490d17ba149e30de5200000000000000000000000000000000194605e5680cc80bd2685949efa3cce90d345b9151ba72f3adf226dd299c23464c4344a42b8834131a51a4156038585f000000000000000000000000000000000477b55bd7fff14e0d1807bfc21edb9481be01c12abb1460d78b1aafe42953730167e32e694c2ddfb0d442e8cea57d460000000000000000000000000000000004b884c6ea36f189dbc3c0e9cf88f08baf5d868579998f63b752e61fcce3cf2c901bb9b51959d3597c4ef53cff41fc26", "Expected": "0000000000000000000000000000000019294d87be784f0f8fa29de80d45a697bcb694b32f3f6d7641d4b08d8a7ebdad0ef78ba5ccafd6b7f240e1cbde019c51000000000000000000000000000000000645f7851644e1e7e255d0b3dca769b987ec3ff2c9eda42cab65dc39be2f9858c31f307d59f6a2caf9dd932d873d2b08000000000000000000000000000000000e8e93f39ce05a11d40f3b52262980c79ecc52939dd02b94df3e5034a57061d040b0c8894189f4626f37bee485712dd00000000000000000000000000000000001e0b7c9c3d7456b2c0ad842083e9ce2a00da91cb1aaba371ff4b9370f0f2c08f4b53b8e5a3030c99b2957cbe5f9e967", "Name": "matter_g2_add_51", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003f629618e1fc3018bb836301ccdc59022f0a25cc9c5de6e4c31fa08feea525c83256235e4ec8364e77e5df478f5f62c000000000000000000000000000000001120d6af221ba6f4351bbee4c2c664a769adb17872646df2c408f70c99ea991ffced4eab50fa98be1bb9426915f125930000000000000000000000000000000015cd16b028ce3d58b10aeb84b783475d894ab3f0cfdf7104ebb4f3417a038107128f07518dce548271061cb8c97e88af0000000000000000000000000000000018379875b68bc26107f9a068e5034f29dc2ae7e8830f8e9ecddc53fe7991206646cda33d37b31a47a977b46be58d761800000000000000000000000000000000073341309b6fbabb18f3cf0842817905e9248db98b582dc0efb2b741a80cdbb13d0df4bce920f257996b95029891a36f0000000000000000000000000000000012d19e09dc254bd1e84afce75aa215c96dd38bcac3f6d4cf08d9e2e8d20345b7c534a0b14ffcdfd4fa3600730e2eeac800000000000000000000000000000000183b7b917aaaa94f0ea9959273ed4701102346be2a9d72531bd18fef908ecb0579a6ac10ed42a91f1147fc3a05b2e81900000000000000000000000000000000070983b1582a97d9797782e4f960a298aaa8ec509720495acdbf176d8ecb9ec9e041c2b5ed6b7dfb46fdeaae3fb34150", "Expected": "00000000000000000000000000000000040f355021ba50c9a3b2b4267668ac8d76dd88991be984ab5bab9c96faed6dcc6e8eac78ed29cd6f7d687dd55cc5d5b70000000000000000000000000000000017853cf0a39332e3c7d75b08b2940d693ac7cfdac46719787c22b55a2ab1036d6f95b68075f1c585942843aa486f17bf0000000000000000000000000000000008696feb333417a7262e8976d1546b6d0a9d5970095485b18efcdee8993b16f42e6dbfdd08d30c45fe4af6a5e203de07000000000000000000000000000000000ec26926720243124ca505c0e04923f3cf5eeca2abfdaf4388960b87c6c1713fc54cdd1c825e2ea359cc67b3bebfa2f9", "Name": "matter_g2_add_52", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000036570783711b381830e35878fbeb187b84884a9a0e88c38e84124515b470e6ac18157e1499026b27f4f731a961eaf330000000000000000000000000000000008382838c18d56c046a8db495babf8d14c915622d7917ebe10cf7da7ecb65f174cddb9e70d0262ada961b396c5511b410000000000000000000000000000000015f63ce982aa581dad5c71fc79251b7f6336c4e78a4a0f4cb6f87167cabd31cbec987d7af4f11dc6d693a0b0774864130000000000000000000000000000000015c001372fe0530a3f50fb8b30e75ff4b264d673e0448211d082c7a9018f583b4d01790019874596c59c68768cfa3e69000000000000000000000000000000000dca3b392f75583b5266a8def02bd66bf44f26b8a0a27aced57299756cffaf9e1af3538beb08b2a5939b745c8f016fee000000000000000000000000000000000d7feafc9ec0935d5b7be7cd5e2a3c57b667aba9fcc87fd5b8a585010be6958c4e7538a6d2a1f46c9641ff7b8598d74b0000000000000000000000000000000010f7bf9f6711ba723bb71a004a90109ee22be6643d56d410da18103ef44a1b3d50f10c4b94222c7f05fd3c28acbdc8ee00000000000000000000000000000000007af41f09e6d0adcb1935d6a93ea1f6156fa0157a63f265a3a7ceffe82f6635b8511e7e8f21e8f3be7a73513ff597b1", "Expected": "000000000000000000000000000000000f3dd56c416db1c06fd27e18fb852c9e1662fed42005e253230a7a8f7c3e0b8ce637666e1d20952c219cd2068d6865f1000000000000000000000000000000000aff045afcbefcdcb5255805a86e8af3de881e5482188c487d15ad1b799cf551c1d48c7665028b05ceb2e82e15ea4ae5000000000000000000000000000000000e0e6ed04926aed1f8c6a4e13227bf2a99d9d6d349a9c86214373be693db702a0011b4423defdb7d842bcb6f722c70b100000000000000000000000000000000148b1af285c65b12eef498f1c9e57a673e7a3803088c56e32aaae13dad3977dda8d3e27809094f8d8ed607239610a1a6", "Name": "matter_g2_add_53", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000074d78cdd35ea17a3013e2301fe9f80f2d20d270a25fdead37eed7697a52d152612543781763e6035fa5452ab12cce25000000000000000000000000000000000e572236e1c203a1c0f99e6ec978458c1a143a6a650eee27cfbe406bb2858fe5f30222f468d119703c2f442bc644ff3000000000000000000000000000000000125384343fe132e16a9fc15efe1b3a9e47289e0afc4b44d492e33a6216edbc96d66c1ca66944a8296e7695f27f414c5b00000000000000000000000000000000084c2cbf0d7c932c3098ded7c70d4411eed882feb0f79e0f7f1c31f5fccb6d53fb57de179c3ba5754bc5e532c3784df10000000000000000000000000000000019e05ccf064f7cdad9748d328170b3e4bcfa6787dbfa93011d16f6d031648faa10dbfb7cc4d7c884d75480c4c864bb75000000000000000000000000000000001999d5f54ee66b3c0dedf9f46450e0ed463fa9c6cd9e0db317a35ec6ce78efae9bea9b64e3b2aaf7f70fbcace71b075a0000000000000000000000000000000003a6cc74cc398f38d535b4341faa37c968daf2009c3f05ace1f938b33bbe4002d81d18d30c2c856b21afe7a22b83c37a000000000000000000000000000000000452d1b2da6392f9df1bfd35e4575c565333703b2f83f56e0a88a0c8195968c5321296b07f6750584e23597304a5472e", "Expected": "000000000000000000000000000000001220b3da7e7d03823458bcdcee82db56957e5aec335e9b543ebb0f3cf4fe3cf6ecacb6198c886b9abbdaa42f528b4963000000000000000000000000000000000138233b166547e9e9ee9d11048e2d2579b2b111af5cab372d36159c4c45e28d836d733a1265e8833da64f461c0a32cd00000000000000000000000000000000005f860a0c72034f1a928501d9f549e5c2a9dc72670272fbf35a0b301025c0fc751d55ef6fc2c5bf7ff42df7693f3dca0000000000000000000000000000000012c73105adf97bc0dfec1f56153c57c6fdb9d68341f4397b72f5b6c667873ff7ed5cc841451b391e33290cec256395c7", "Name": "matter_g2_add_54", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004d46066439c3ac559cce863c58316883651023990180470d2efd06e443a7caf3a514b54f15ce6e850d32779215bcf4a0000000000000000000000000000000019ce904b6c9c3de59f7d5017f60f1978d60c564f94a0f1964c24c876d1139a7ffbeb6d0d4884bbfaf5f2f189af6904a50000000000000000000000000000000015f1989719e69be95f25dda9358fb98aae2819e0deb7e2d291e2c01e85ba26a9da421896c6b6e2ed20f609b533154694000000000000000000000000000000000b287cfcf1dd7c6d735c1358dff15393ddd6c82e7a33c5d8005c4234cdf823c76a4725fd74cad74b3ec51df67f09af0f0000000000000000000000000000000004506802747afd8777904c46ad9bf0b06859a1b395ca3474a93ca4151ca158d2fd41b3a21e0ce0bc950b3241256e10d800000000000000000000000000000000115f41d2c173c3c2c7ecdff1a4aaa3c2e67c803db7a588d6143fe913961eef743d8b1f9d32e3ef1fc0475f41572faf780000000000000000000000000000000007a9cf48dbe005c5c59b2c731cf4117e5fadc9cb2cd8f486f1ed58b2909092ee8f36d88b8f719db94715641b418ab4240000000000000000000000000000000004ba40d4766b91bf8da1cc2526f62791a1b5f6fc24ffc54b522dd30cde2d29a6a6f81e8429d518710843d43705f3b4e6", "Expected": "00000000000000000000000000000000014933a0923416428b5fe5be7120bf399ab62ca091b07d03da3fd2ff080b9c411c3cda3bfef40c8450ae31c412dc5feb000000000000000000000000000000000214229a73780d4f260364649e9eb2ed751ad3f687a832a3738ca2cc81a3acf12757651e88c4bcd79239bc0b0c40e5a6000000000000000000000000000000000548f20fa375e578084e085ee71df5f8ddaec1db03a1415938d9521b5d9c914b5295835fc07263cdbf49d7802551156a00000000000000000000000000000000063ecd9efe55229a76fc848728e940183c23bf47363cb34c5a49837e6df8a5f0dc29d7108cd10ea08e82ccf017d246d1", "Name": "matter_g2_add_55", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000006b37e2226957d639fcb0bcd6c20b3c7b8372e7347a14b970e01c67c1859fa97c754ce588d0f835ecc053549d963ab4000000000000000000000000000000000c6a5fae8be3a32e3f70a4202a1ab6d97183964b9f7b9a084c49922cd9e0e952b0bb66c5580f0e0c417e079493bcdb4e0000000000000000000000000000000017b6132f11adc0d5d693ae7f3a0f89f5779708083eba23e03b0c9265e4e60624e1fb6940e8ee49d31618fa6389b1b50b0000000000000000000000000000000000a45c5f6df71359648aecb6434bad1619c39f10e279a02b3cc9725d0256bcd126843fc9ed29cbe02a32cbbe79774a330000000000000000000000000000000019cc0ec24da141f27b38a53aef0b3d93c4c2b981c1b248014be277002d39d7bde66f6957a659a89adcd3477dfe4f897a000000000000000000000000000000000e4c01d7425e35be84e3cf806aa76a079cf4557732980f7e8f8ce9a879483e28f223694ed8dd45706e12272f4c7952820000000000000000000000000000000008ceb842a17953578013ceee519a28ef1b37f73e13564def5ffe08a64dc53aa680784e26138176c89269477ee003d16700000000000000000000000000000000159791b6f2c26ed611ca40bfbd2059c15cfec9d073a84254ad9b509ef786d62d17fdc67ab13092cf0b7b3482866f4c32", "Expected": "0000000000000000000000000000000008a71a08d2c4e2ba3d8774dcb42d3e96c7f72d36fb3b880a4049b078d8257a7a9a51b0b34c093568baf4aa6de70e709d000000000000000000000000000000000daf83b5ad4b91b557982fc4b9b7dbed2998aa39fc4658ba671f5f27b3888dfec7602949cf626c9e6ef21171acb185600000000000000000000000000000000013a7ffca291d9ba8790ca0462c54c147aa22e03a2413b756f27583155932aee65060924e46db321b3fd6f22ff7f54041000000000000000000000000000000000289d7de10285285279aee024e52476fa6fca85550f7af183a161e395d72e1339b629c64127f96bc85858d80e73dcbe1", "Name": "matter_g2_add_56", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ffed009c78ba9af8cd33af7b7697ae4dff863bb92365055baedd2299b7f5b5e8abb84ed434f7223c3e309ca53c08aca0000000000000000000000000000000003b2370c837dd6291818efe7c9af62dd51295c418739ecc509d42c92e2c97d12a9fa582946e176e8153fc9a273140b2f0000000000000000000000000000000001e63438e8b4a0462cfdff64a281ab4a7f48d51b51325817139f8ee683484f8695f1defc0c3efcca81d5fbff06cf9c54000000000000000000000000000000000192fc391cdc1ed6ddbd317f2f366f2ce25ba27b8c0f09c733e7bc0c0697544399a3a4f1186d139a8f6399ffa88e89a6000000000000000000000000000000000040d03956c821010969a67c91a6546800c5aa7ac392b16a9895136c941f4ca9f378c55446161562feace3b5b65f3c4f000000000000000000000000000000000e4b299f9fb25caec655d21c390bdad3c1256ca29faa33466a13aaa6d86310106d95fc8d8a0409fbd228fd3be7965cdf000000000000000000000000000000001272c63693873e1dabe2c2739310f627d3d9b5bcaa615402c3849ffd8dfe72b40fea4a068064655f2c8f46f074e6518d0000000000000000000000000000000000161a8e5e1de10938e5bce241ae73d76173022127822d744b23e656095c28f2f8d142ceb48b72a1dbc36b6143f8af95", "Expected": "000000000000000000000000000000000a4ed8d613cfe4f5dbda1d0c6812d0edee45ffc2667323c3828f8ce4ab55c119e92a82f2c3d06afe3adaa4aaccc18f8d000000000000000000000000000000000fe10c5e185f3f8ba81c93754132d76e05eb3543d8aaa8a2d0c98833ce5fa9e2b84420d6e3412e005cf89d11f5400a510000000000000000000000000000000004ac5f8cc614e3833b3b6dd9eee9ac29501002ba9054554314a4c516bfc8cec870995e811f7892811346574f3c58b2ec000000000000000000000000000000000a6bed54d8ed4ccb09211ae7773c604edc6ce51a05c9acc94e8167026906d387af681fb33a40e72e85cb076e072db7d9", "Name": "matter_g2_add_57", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000002e105e0eaa418d58019a849b89accf665a94ffb0bdf308a11b99b521de7af8ddb150c0e3b2e9c54cf5456b6105bc81000000000000000000000000000000000691a3b3986fbe1c0ea22329364454f37f645d6abe9310e883b9191ce512347e074e18e28b88c2adcc76190a549b80b40000000000000000000000000000000003f3a37a763c8d0d99a3fe36923843a22cb0fa18ced48493b2510fc99afe5b7699bbaa6c2ecdad8aaf72969354f121a1000000000000000000000000000000000f4bbae00205f54eb10c83d928d908fbae342b76050e33c51b6e282e02b3c1f132a4728dee4ea95455c25fdfc112f254000000000000000000000000000000000b50dc0957eccf5ad941b148a3824e82464bb7345a05125a0aa64f6ba34e34e767d4f679e9916faaacf82b3c79c9bddc00000000000000000000000000000000087152b3cb0db88776a7144fbafc1b210d150b637ca7148e3df600989231bce613fcf8e310fcc53aa2dc934bcbf86a220000000000000000000000000000000018a236ea02b1971d6e193a6eb92e1298956679d86864042fb6a0c36dd91c0e385944d779dedd0149fa8a1b3d6a07949d00000000000000000000000000000000048eac7d116b5a7906bce070e2b51ee7c4c493f1415abdb6fd2d35676036d3b741d14b7135419645a6906018e9d3f150", "Expected": "0000000000000000000000000000000004d145ad2575313a922667b897052063139eef8c61dd375eb055c4a5c52cfbed35391a85df915e1eea50d000b9b6bb5700000000000000000000000000000000071cc73c16a234e99faba9b04fafaca1a943f2bdbb68dcae0a1742acfca1f90c5f69464aba42be6c18be31f79ce30791000000000000000000000000000000000bf725a2f4d7d33c66fefeefce13fb5649a68a93fb7086c943a7bd5663b5788a5ceaad7fd2a219ade832dfb3c0022a5a000000000000000000000000000000000fef4a2610610afef43da2161b86b25a8f6e30ed90053d57f5ee0a10effcdd2af769d32ef6843804b2b6590f95eccb4c", "Name": "matter_g2_add_58", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009a3e98fe4a98582ce9f274965f376cb45e8583775dbadf626cb1327c1f8a25b293b97e7f8f31ff72ba7e8e769ff25ef0000000000000000000000000000000018e4785ccb76c4897087c8a4242ddc744c6a0a53a4a844254153c23d6f16d4ddb945252d13f93101613f4eb0b1e2b8320000000000000000000000000000000011b81d344eac04d3471b1edde5e51f31f97bea3396580839fa094db58cf6bee371bbdc045fb60c3ee5c6cd5d3f6d3c4700000000000000000000000000000000073476bc5b1d52ff4ca89c3afc099417f473543fab6e59cf9de8a19705dc4bf2a210b1e6de4dfbde035c312be0c70c5600000000000000000000000000000000094fdcc2119b4f674b5639653dfabcac59c2adb1ee2ec06c55c3f148c9361351ff0acb2519e4638cb2cde98efaec8f4400000000000000000000000000000000051d5edcbd6eadac808222f0423bada165fcb98f98a89f335c981262b0ca7ea1c536d41aa41b49b25f0c43f53c95384000000000000000000000000000000000003c96c6f20d7ac31ee7ca77d11e8d25ea78cdf13e5f4d317752320e059e19196f14c15b5a18ca712f3a7cc6f09be6d4000000000000000000000000000000000ebd71f61fcddf1652675f577bbaeec26b892dd954965b057ffb431d6e37cc5425a2a42a0059482c2bd75adb2a120b0b", "Expected": "00000000000000000000000000000000151ec7c35a67b878420e198ee7bf359d0668ab61ba1a0bc2e5e57b1b7b18838a015464f9910b659fb7d1e10af2801d86000000000000000000000000000000000511536f34067fe931c6e829e22443eb838f0c938eeef6f839eb322d72e2011dd1c33c504dd044e3cd721065d7075b520000000000000000000000000000000010c486f846242024f9bf40d805c8e33ecf1b44cfaa04455d5584db7ebc32c0d29e8742c61886d4ebae93f22c518ea87300000000000000000000000000000000072e184c836a853fd1153eabb1b645bd35ef72eefde4a52db169acdf2d8d68499398599cb4002994c6f4936de1da75ef", "Name": "matter_g2_add_59", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c414b95b298b9c673001173ba7e5ee3e03926f28068481cfa0b469ab556f8fceba9fd0a815180ae0b82c265fd4c6b7e00000000000000000000000000000000054a242c1cc1a9c710bc23305d09c2d613ee8eb3840b37943bfe83f9c1db456ab4436ad319fcdd8684db129d76c95320000000000000000000000000000000001683711c0c7f02e67374f190eed1ce6559479d6d199f43fb5b0ce7df7774a5cb21c86b3b3498855d9b69c5763acd8c4300000000000000000000000000000000062f87085dfec847af518bd71c078f994b090c3b27c6eaad79772ab58afa43993db52fb08649a32629d61c3db12c87310000000000000000000000000000000014b0862ac988a169342a4abacfebc5e7e7e8f8ff1166c6ca8fa53613c5fc28fd8b02d9c8d5e7a264b2fa59cd33a0f33c000000000000000000000000000000000f0f79631e7790192c18187144388373d52653cf11dd076688877fa9b5cf58e65fe4332874c301563089b9b3fa2322e4000000000000000000000000000000000174ffb89d7715866562d9882acb81ce40758644ca3e0decd546c8f5c349b24fce88214956e7540fac36bcfc105cf34a0000000000000000000000000000000003e06c5f607ccf1e2991828034fcdf91106295e7174b4dca21926169451ee58e737d535af45073e2378206e03c81c421", "Expected": "000000000000000000000000000000000642f215b772d17a3aa45ee3aee607321c02b4f7a7df3884259a25ce78c73e9536d46333fa388e506fdc79c708bfd9de00000000000000000000000000000000145864ce36521fdb641761be541a27bbd3f4797b923a870148bef1d5b4b0d463c0a7c8ef07954dad464510d836105e05000000000000000000000000000000000ca038e667fe68111b583dfaa95f88d3b9e46c0798abccd1476071435067e6c0e2fa81d25db6e1175e60efa1705538b9000000000000000000000000000000000cf1cb1b155e4ea47077c42a1a99c3f11f8b27516a808b5e73498ee12363652bb46eab7e55de93513cc2d6272f26a537", "Name": "matter_g2_add_60", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000083eea9b5b2d5ac5f7ef51ca889a4317322d098a408a741827fb3419eb12a51c07c788c2798cb37635e224e99bbc894c000000000000000000000000000000001312ec00f4b3a4305700b44b3f215779a9a8bfcf5b5d3a7f237a33c5484099ec9bc5c8537fae768e2c0ec62168f383d6000000000000000000000000000000000cf1d5d05d11e1d07074dd34211d0f00eae1df4dc550c55bd2fdafaffa1ad36abd5da30c5d3a5aa2845b1d95a5cb571e0000000000000000000000000000000015223baa9f2ea4b04fdb05b05bf3a94dcabc5e64189aeee39c380de9a34fe6b4253f5795f70bbe51b80e1aec1eab71960000000000000000000000000000000006a3a773638c0b4a13e7ea399ac319f5ea55ed533aca32a933d69d8198ae997a66d1e32a02683e7fc5c1ec597106848f00000000000000000000000000000000155ef036f60a5b11697581265293cc4c6eebd3fdf500540529b6997c27a3be31212aee5cdfea6cd95d6d5bf83a8ce5aa000000000000000000000000000000000b15d92f2301075ab0e3215aa72cf9b130bc8e1bcd9fa36375c4b9d7da430ae3e2b24f417336d8729f44542ee7f561d300000000000000000000000000000000197d90090501e8cdea28eb7963231f1a7b5f716cc3a086acb6e7626600d6544132cac943e8d5cefb5daf0a2f8d400629", "Expected": "00000000000000000000000000000000128c909854a20ccf9e8e396b617b36f233909a5f6c3524c93cc659d22afe0e7058a438a5ee4345bed914288c64802e29000000000000000000000000000000000239fc43718cd27855ee5450cc9be5be5d9bca8188c22601242a1bb4269ca0fe62ad5e12b2c65558cd3dfc89ea31205f000000000000000000000000000000000a0aec9527febbd35bf041a901b0b35e5e0d48a2d6d733bb557d0767798369a7ccf2f1c278710eb764f721821f9aeea300000000000000000000000000000000194931bad52daa16a648ccf1ba9a4768e5e2900fee4f9bf46ae07d1aa605aabbfe96684f5d2233c0b254cb4ad5517775", "Name": "matter_g2_add_61", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000011a960cf1978aa2ce1731b857fd91d2f59d4b8d7c6871ef6f4f85aeff549a2f397949d11a4793926fe7be37f3a83d11c0000000000000000000000000000000001954f056834d6e3b16043ef1acd0a47a353300257446e9a1db7e58bd0d7c4bc9ceb3db51ae01cfed9de99621e96934c0000000000000000000000000000000002e2fe460e71b65595ed93a0010e5ccd1a2c16fc4e0d345e7226c947f29720d2f3f54282f79cec086d3fb1999b9629b300000000000000000000000000000000060dd8a7ccb613f1521168a8a322aef9f84d9708a893f704f4fc9a19e2493f25620a47e0fff1bc1e212e65e92873b4f20000000000000000000000000000000006a90568fa25b401756e3f86b5300c4d3b626dc6274f4685e8a9f56ec5ca2afce36a1fdc6d3414edc8780c4e650f10dc0000000000000000000000000000000012e41e8e0dd10b3ee31fa866753aa5d9db7669153b141114cdb2ef7fa6df5db27aef0cc70e76a741eae504b038ecf2300000000000000000000000000000000005c35f3372f1ec9845bd04ea722fbed2be1388abf59e622dd3dafb4b3af49bc5fba9e20235e7e58973fedf4b8b720691000000000000000000000000000000001111d18d621070509805d306a31c109701288fd55d4c0644349deb080c6591b6e852b4f7e009b80019513de7f2fce17d", "Expected": "00000000000000000000000000000000189ee5ac642bfd0b612058f96e63acb1feb6b4dce125bf0ea1e56e846775af1a8b0864d4ece6bd96c3b5dbb04e2f6c33000000000000000000000000000000000073d57ab79314e38267ee8015de3156f2c1d5dfcb6655a150b9ab4a3bc9eeddf7b37b3681c49611e02abb012770b3f5000000000000000000000000000000000cfa1363275c7bc5bbb9bb7c03e7bb7f6d6d365e39fccbe62cfe0bb93280527c9ea99079fdf9871abed035b62079856b0000000000000000000000000000000010048e4e96f26710d254110650de36460be2a8302badfc2da8b26147da498e4620e79b4329033fc3f3a9c99b1e12aad4", "Name": "matter_g2_add_62", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001472caba61c2f1fe4b1d0912b114c25de103ef4351668f22f3a158d7a347539a7b6656044bd490f036ca3e29dbdded370000000000000000000000000000000015f8cdf7786410b409f218164063c99e77d8f72f03882a6c9430ec725ae574547d3ea3cf30c3ad2c9c3febe6c30b1272000000000000000000000000000000000ccbbed85c2809433fbcf22d6490457dab800b21cb4de414c7dd1804a0bdeb7142f8ffbb2de921c2c9eabee6a6351026000000000000000000000000000000000a404f42c48e3ca408d3f92079b99805004da928f128206d8904ecd7fcb14121c7d9a9e7fb69accaff921315ef3d5372000000000000000000000000000000001310a8cebed1491bb6399abe3a08fb25ad6ca00feb5db62069bc5bd45a57c167aaf06a628a3f18aa990bb389173855b100000000000000000000000000000000134655489380a9ae9cfbc3f4c6a1aa5b6dbe0a994e681915602c1d197c54bf3da6fb2df54eec3634ea87bf3fa92a69740000000000000000000000000000000000e7e532ee4b892af39f8a3db7a05cc77a6eb0b3d977c17076bac4a52d5ba003a0ac1f902a4257791a45370eb88426a70000000000000000000000000000000016a556050e4905fa74b5061e3874f05cc7a6c5b049bd3bb7c34adef5a77c393239a600542a4401c3e61978ee6515a30e", "Expected": "0000000000000000000000000000000005889133be5f447013d779f2b9b0033667c5af87e1c8a16d239ca3ed238920004d87e00119ded46658026c26988ee63a000000000000000000000000000000000d4ed8fd88f7e1394f2b5a65588bf1c461a292acafdb77703c2790ef249f2de695524293c826252c94967a3ea4a3a28500000000000000000000000000000000001b5ff0aa278c7e87a89d4748aef13b516c49b7dc9f7cd5e0448dc6fd860a7a8af7183a198eebe6c7dd549fef806db00000000000000000000000000000000003c9e40ed44427cc3cf886ca2db341ae31f015c542b857f6702d25cb5036e3e6abeb8d4bf9a0e203281ab85ad89ce0da", "Name": "matter_g2_add_63", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b52f05365c4df20a7290aee71a7e030615d1a2a971167884d835c24e756a0faf6ed0552341c561446c7fd3d5e887d830000000000000000000000000000000018718ef172c045cbf0bb132059754b62414097eef640a781db6ad521af5a24d78c622d9402033fa939f70aad0510a1ac0000000000000000000000000000000017e969e44b4910304b350b5d442bb6a0b71e1f226cb4603cc8b4dd48614622f3f4e1ddecb1894046649d40f261d94e030000000000000000000000000000000004dacaeb9e05b9d60ce56c17312a092cb988bff426b8a718cdff860186935507a06eddbc4a1a29e4ef88db83fc4b6e77000000000000000000000000000000001360612f80227a2fc50a2dbdb3a49db16bd9f0ae401e2fb69408d990284cec05a1c29696f98b16d83a3dab6eac8678310000000000000000000000000000000001223232338ce1ac91e28b4c00ef4e3561f21f34fc405e479599cced3a86b7c36f541370bfd0176f785326f741699d2900000000000000000000000000000000179c34ba9578d5ff90272a2c7f756794670a047f79a53215da69937152bad0f86576945b12176d3e13cac38d26335c51000000000000000000000000000000000dcc715907e4e17824e24c1f513c09597965941e3ed0aaad6d0c59029b54fb039d716a998c9c418110bd49c5e365507f", "Expected": "00000000000000000000000000000000093b692a68536b16913ef38c3bba7b19ba94a6af1c36a2e54b8ac1754a29c29882107cde142deb95365af00f2d1f537e000000000000000000000000000000001035e70852f38f860a1a04f33081e84f3ed17d83ad894a6800e7b8b9259067b755fe7e08d4c1b297c6d53064ab8209590000000000000000000000000000000013d38db0d8575131865bd7acb6cbe994812bdd8bc7f51b810bc382a6eb379d442c47be20a2c8e751fb08ccce8fea68690000000000000000000000000000000000bd114951193e3bd58cd0025e0b0c807ea073b1c1f7bb04a2a00771b6442e70ea20e1124572ef5b74d2bd87c93c82f5", "Name": "matter_g2_add_64", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019829d5799eed5a081042e4646d46fb6bead6d3b9893a4240867b25ed6af6a3e154514f244466d80e3b9311e060bbd7100000000000000000000000000000000156157a654db2813cb9c1b4da0a3ee192fad076bb2767020fc5fc00e967c1a35a367ffa375703e1181b3705ace9dd28000000000000000000000000000000000093385a6a9dd0ab996df54b23f47f4a49b3f379e11bc8331016ecee6161fcddd22f6d49fbb21f098873f1e17424dedca000000000000000000000000000000000d5b5b0f2ce81e755b4030b33fe3a8bdee38c2c60ed3b4a88bffb9207cb762c0a5c699ff424c000ab080d763abc5438d0000000000000000000000000000000002fec3b2e25d9300b9757cbe77857d7220d91a53fc29f3b7a0da5c4e0815882d1cc51a40a60fa8e1ae01296c209eda0a00000000000000000000000000000000041ff1a77aca41f7aaeec13fb5238c24d038e2e566b611203c430d7ac6251d545ed4a60e9e0087d6baa36272c7b1c853000000000000000000000000000000001643567a0f22b90fefee96c8e2f5851623384c2c68bce9589cdf64c933d494a8d805edce2fd18a6db80f4819391dd1f9000000000000000000000000000000000e4e40ab1969bf9f00ee3b984947ae95bf7b9579bdaeeee926638f9566f8ab26debb4c8d4009535cb6422b2c2ab7282d", "Expected": "0000000000000000000000000000000006db1eef1f614613ada8383e63d631484015224902ca38f58ee384a70af0a0575b0e7063675d2dd997ed8a140e2598470000000000000000000000000000000010d7b833f050f18ff4e3a8d0df227a9494dad9cbde88f68802b23e87387622a5333dfb7bcdcbfe2d4d137cb532ef4a150000000000000000000000000000000000c9c40ba972ee0be2823625a23345fe352d701cc8bf9a153d5a55c205ef1b7e5544d0a7f65aaa24bde8d77cb4c31ab3000000000000000000000000000000000402f170c4c3ebb9b1e7d64765b66ba9b8d45b2ea9fe9517626f38e00a11d180e1f8872bf80f6322bdf3a8dd90732ae9", "Name": "matter_g2_add_65", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003af8c25bdbd0dc1cc344d55366f15555709a74e1f0d8d7050cb6b487759db6200401b7868fca3c2ad26e6362a30e6250000000000000000000000000000000013f8b6ffe30f9a133fafe64461d305cc6b2cf5aededf68ba396d4e00df651531c750a3d94dd77bc5c6713b939b18fa19000000000000000000000000000000000dde97855d7728f409d873b83b6879b45ace5b73f317687fbf478e594a959ce21d4d751db646ceb20432e8311e67404f000000000000000000000000000000000fea997323cf29710cf0e3d44ce682e039d6cbda155e43c94dc8cefc5e94000de4b9525123b9615b5f1019a46ef37ad300000000000000000000000000000000123a19e1427bac55eabdaec2aeeefadfca6e2b7581a5726c393bede2efd78af04e6cb986aa8d8d5c845bbbc28d62e7a00000000000000000000000000000000018026687f43591dac03a16fce0c4b8020469ec309bdbf9f0f270cf75e262abf4ae55d46f0b4ff130b7bbe2430bd0c9f4000000000000000000000000000000000a27fe0a29c761ce29a731ead969b1db3ae9ef4c05493cc370a128d97ef956c55d9a500991b3e7bf9600383633778ebb000000000000000000000000000000000dbb997ef4970a472bfcf03e959acb90bb13671a3d27c91698975a407856505e93837f46afc965363f21c35a3d194ec0", "Expected": "0000000000000000000000000000000002dccab673b26be02d2c645c82a2c73290f0eb053e07d4f81d4d315d9483e57c58b65cfabeb0172934b9fbb52ad519210000000000000000000000000000000011c34a27c850fe319fe89399e7680064caf6dcbad171c3a23c45b9883ee06ccc3482b2b81e5777759ff81b16bcc1b0f500000000000000000000000000000000119adca3e2b052c045124f021fceb03c979e6eec0a270c7f4ab13674e461839a4d3a10fd48da4e9ae750a238a2649ace000000000000000000000000000000000fb5210677e1096cb5448bcda16646d6dd29ff8a0765c5aa51d83fc952a5ab8063aa96e97f33abf701cb8688c989c363", "Name": "matter_g2_add_66", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000cdf60e3bb018407eab162822468255bcffd54cad9127054bd1c30705a4ebf1afc7f539cca6ba4cd070b44410ec751150000000000000000000000000000000009a2e3e5993b6a7007dedbbd21737a8c0aef3ecd4607953c4a24bb3fed97ccae01ae1cec024443f300b570a66e9ac3bf0000000000000000000000000000000008a21fed19e9ec2a741ade7767b0c9f39b79c3fbe34aadc9eb3043583768d893bf927d26231759290c7dd9c4f158d5a10000000000000000000000000000000018eef4ff88d63149d2632c9db586a4af0606644b16c82fbb0a3b869f1ff924c59acc8efbfde7bc604497ff68939cdd0800000000000000000000000000000000000353798691ffba215b6458a47823d149e4e2e48c9e5f65df61d6b995889f3b0e2b34824e4ffa73296d03148c607c26000000000000000000000000000000001190ba585a928413dc3cef3d77b2cff99b053cadcb13b2529c74171a094d479a259678dd43a3ef2a2e597223eb7fd35c000000000000000000000000000000000eb3f5d24d1a4f520032534f6f81a6806c54df33cbd10c30203423aa4f33620b474cda321e924802b636daaeb34400470000000000000000000000000000000016f004f1dfbf140de042e4f57303928a576d9064f2da5b3ad392331f5c43327c7d2a6fd57456d5ef58b54a3e5ec27508", "Expected": "00000000000000000000000000000000056489b2248ba672501069ab6742016cc8ab2af50a119239bbd3c0a4b9b56e014402b78bf62b2b37bf4645c3bd3d95b800000000000000000000000000000000046956432001feaba6d230da27a72e8db5c8eb3d52f00616f87b55c951217095f337a302562cda789e5714c4391ac27000000000000000000000000000000000172c2a583c9563fe02d43b2b767c4ee4e3990fbabe4ac536d64cfcf059f0e38672876289bc86915b6344eb398fbc4ddb0000000000000000000000000000000008915b0edade80caee9b386e4a560ff4b9dce33946ee992649466315786e139e3ce241ebbdfa7ee28fad7e6214e65666", "Name": "matter_g2_add_67", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f5d47911596c46c0c08cac5f5e7f6d0609874da4ac1bd4e0e59c393273a5fe31a756c7cfff2a01d19e79d209d7c6d3e000000000000000000000000000000001010f864eb6624132d4436d18db7f5b34727060dc426c109886be88031e3c155490cb3fb09e1fbccb7912875477c6d840000000000000000000000000000000005cfbf1c2ae1b80a8c7cfb2cefedd907b0552794f4fda101ca1a723b18de8cbce30eb54287e1847cee3f416cd8b45f2c00000000000000000000000000000000084fa63781f7eba9c7e911ae5866d485bc7e90603541c55d1ffad8b3cf7547fd57fb24b14002560e58410b828513e1090000000000000000000000000000000018b0cd0360c5d5bf8254725c19976345cd84d32d0d770286444fe29dfdbc495dd58407ee8d48ec1004971f249453b8460000000000000000000000000000000009a6ea13f5a5a279ec3bb86cc028a1685d84135ed5fe99cd6b6fb380a42c3af5497e3ba5ea558618487cf953172a376d0000000000000000000000000000000002a36d5efd3381c35ff4f361cd813a96c3e5185141c5985073b45d1319c5f392442b7aa6a253b7eb22d1b5052812be00000000000000000000000000000000000f745dd17966b6befa7f740ea360241162505d6269226ffda90546863d0fff124d8fea13c763cfb69c2f8f12b81d431f", "Expected": "0000000000000000000000000000000005b81843ef3f98c6a6686f1fbd26f77248497ec3d41aff4be5968d13ba86f86309b0ec4792d74220ad8ef147bdee9aa90000000000000000000000000000000019825376b243f3e374b6e9e7e51e0c969bc72b39cde1dfa09187a3c7c5c2c752ee16fa5a4c8fcf94464287419b3a3845000000000000000000000000000000001308cc0c77219034a9fc3018f1d668a41e6959476aaaa5461ec73d7155c6a68fb08e1fdf8140e18270cd338c266a83f4000000000000000000000000000000000fee2a6e245e3bb570c3b605f7ad805bcd68e9a1f2bb2282f92e2a2e83b69e275b21b923f33a65defa8c4224934aa588", "Name": "matter_g2_add_68", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000124870cfa469136c638e0cbf15802f2699aacb66d7e4c2965c6759dbca4b7e47941ad9ec37a84db1afeeeaa65a7418e4000000000000000000000000000000000d4503049a6a53536bdf41dd832a6ecf3f10554887da7e389cf940394e1d88db94369b7947436546eb6c6e82c48dfb9900000000000000000000000000000000053f9a6e1f05b67cf553073358009a172e2ab8b43572a974da1f3de85a29103b13d7e67b2a359297172d27dba5c61439000000000000000000000000000000000abc29f50ddc1c113c73700b9b9796890cbf48818ba981fdab2db27ef1c58f4c2e4595b99eae397d40990ce2f6c9317c000000000000000000000000000000001431c5161fc51024c5708496a1f9545c3d4c05ef9e2c91154e22ebfe251017fc61ba54c679ba2ad6b8314bfd8d6272c900000000000000000000000000000000098f2e8b6d3fcf9fb27e912af57b45d3d35a7c5471b9ea2c85262c0efb44c435cd949f23d7d40f14b6b6d4d92cb8412e000000000000000000000000000000000397dbdcc3edf976e8c507f5e70299da8c7765772115bf8edf7dc9024050c2ed98746c2bf7dd4400ab1fb89af991e43f00000000000000000000000000000000139bd5f917f59e2cb6c41c59024c12cdaf95285f3947b80267f36e3bd2701f9548b561c49003fc5ddeee3fe7bc8f5b5b", "Expected": "00000000000000000000000000000000166414455bcd0e8e40397f4cafa9628d1a092beaef62d35211cf49779ba98df5c1d692f650c1fcf0893a9d4ae1926b1c0000000000000000000000000000000003dd898d0725ee899b913042da8566a1379aeb4dd5f0222ac784205b4e74f32858ae490f981801b166a01fb96266dbeb0000000000000000000000000000000019f0fe4f12b113b337361b977aff7cc7dce50bf37c2609b9f311ce340d30225de178999b73345ef49625518e52aa4d7800000000000000000000000000000000090bc07c6270901d706a8d28d512b07fd0e03013d94d4e43eafbee59677998bfb7c2a58aa93571fb49c35518b6331bca", "Name": "matter_g2_add_69", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000007d2aae9794b7a7de97f7146c0ee8415e09e56fd42535bce6773cadd6f7ac09c4eafe2e926cb7014377e54c703eaa9dd00000000000000000000000000000000172a4a33ccf99eb0473b2c44d30bd53159afae0c7706ad128bccf6258974d5e5761f9be43e618cdbd96027aede7fd5860000000000000000000000000000000012601bce2171c6e4c2968a3efdf1491285f9e4ab37cf973ab5c8e224ad5b40e1b6459ac89090c73deb8fc79fec7fb8e200000000000000000000000000000000112a6443116e6f98ab348e57daa3971b5fa506e40515e1611fbed3e7dd64c5c1e991e0d2539a70eb93e3da0f573d6b22000000000000000000000000000000000caecf650a12bb629ebd3b978ef9c2d4486f8ce21d515451ecdf01d27740f41b719d5a952e737c83641953a8c8b3a1bb000000000000000000000000000000001641ca29ff6016af335499dfc7167b3d961a25b7f61008c27b3cb13d3cb28fb5096413b1c7f1ca18e5d3b5017d6fed1b00000000000000000000000000000000197ed996d62fc0628d8ea4adee487df31c794e05e7c327aaa140c6be0109031bb763c5f84bc35a0597dc61e93d23a9bf000000000000000000000000000000001056c1f3c6ae36be26430d142d34b0e807685c79935496414e004cb85900d85a18454bde9c0f2650f19db35eb3dd468d", "Expected": "0000000000000000000000000000000019ce0f31d9ebaed0ea1d12d4e232bd3ad48373fa465af44f1c8015102b624d2f8330d1323fb2fec524e83de0f6699ad7000000000000000000000000000000000915d65fef96562ea3b76f3152aa1b8e445ef50fa66dc487ad0c04cfd7a33b5ee48aed919eb81fe83b1f4dca59b4990d000000000000000000000000000000000e4731ec887261f29475523f7dfc5d21cbbc1b883439701a33cd58bd24f5d447267707c2b60ea38b04510be7dd10d72b00000000000000000000000000000000146a679d7a81aac5952645b2635f24b96393529ab9571ecc1078c4c20a77e59acc4591b9f45df00428250c5e31b1a8e9", "Name": "matter_g2_add_70", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000030372914b83644fa4db1958831e9335c72ab7a811fb337696221a3290e4c54bc10c2225f8fdc3a9f62632ba2f1594500000000000000000000000000000000114205926609470b6022d24046a1997c048e6d2cf6043397892c967692161c0ceedf409bf5e1199a64eabb1ff8de23640000000000000000000000000000000017cdecbe73779855b7b94920d4bc8ad057ce51c5481a5579650df8a5bbc421030d2ac44568217c4dbb13d7c639760236000000000000000000000000000000000f194fa814bfa7396697bd812d9449d06fc61b580d7a86429fdd1ad376e21ceca139356d7d13964c3c684563675711c60000000000000000000000000000000009c7164f8d40c7e9ca571c46f8edf1c4a961779e55f6b10ffc44d76da78adadb83195d757949be39631c6a53d2d67fae0000000000000000000000000000000012cd5149125e7cc21bb5349be7fe03d5854ee73ba515021b6dc87e81ce1e1fa3e386fcb0de80977b9329e72ad54f929f0000000000000000000000000000000008789ffe0a8676c6a56742a30a48e5e65b88aafd71859d704fb9f69e5e274ccb6942bc51ad36c5671406052aacf19df9000000000000000000000000000000000c7607f4fc69a25aff00a54369f213c4587404644358da4abf26d151dfa4905ba9731dcfb12e2a3f2c551cacd0f4e47f", "Expected": "0000000000000000000000000000000016790155e57f7103d9e325a1f3a64c0b8a1875365eaa0c01c515538b64bd8265e8392e755a2f7314c37ec09026f13d290000000000000000000000000000000007bfe690fc4ab166b29de35e341e8faec4bc3c2d4ea2d42c9f4166c0d748b92b743ba646c86ff9e570612c75bcd522a9000000000000000000000000000000000c11b9ccf990162b772099fdb4266716b11dcf46c5abd12d03caf222c571e2a9e28cfb47e11db05162967ad4b430930e0000000000000000000000000000000000bafe02785607bae144d9ef5391fef02b9f2fd5dcd436e2506bd40866d8726eb83c223e09c00f3b8895181c6710912f", "Name": "matter_g2_add_71", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000015d4ae1521acf897344c3a76261754ff99742585af4a0ee86dc473a88fd408091404df1da9d8bb291db68bc9c07d6b2b0000000000000000000000000000000008ce160213875c661163990f3f7ac219ea295db5e828354864517ea8689ec15d35c6df78ff14cb276e0c97ffd7fbc09a00000000000000000000000000000000038a3ee211e777d6d6b7ca6c7a0d2130f1a071c030eebec412c3a0f14c3584e7c5cf15de254a8f141a8210a90249ee5a0000000000000000000000000000000019f7ec6b2fcd8b3190ab37a6e843340d3f3fc092f5772a042edbd5bdc967b96e8a1dc9e435b8463496aa1301f87d0e5a00000000000000000000000000000000093c423917d10edc429acd927def56ab4f07254b3892762aa7056f24224528aa0f528fe8538ca996ca63506c84af73270000000000000000000000000000000003fd3ba68878485e25ccaa2539eed0a97743ae9f5b848e9d83c8ea60f7ad0f1cc6d94a59498f79dcab2bfcc2fdbacfed000000000000000000000000000000000b060965391bfd4afe3271c6ddb91eecb8c7a60451c469d63bb178b1361617000f589c33c35b5deda2f072c6edf2eb370000000000000000000000000000000011c8c988379cd2b82cb8ebd81c3e14d2c01c09dde5690b97623c0876c7554f52ccbaa33d17fb0f0cf331cc85749340cd", "Expected": "000000000000000000000000000000000965966a8a463de1f3bc49d9873668e87f54d95612231458dc8b885681cee8e2835482b4bfc476153c41b206f427cbb400000000000000000000000000000000183639fa14dd74c33e8696496a3ee269160f88e5daca4fdc468724d9b6af8e7d0706867cdb1bcc608029b89b94c531a800000000000000000000000000000000026257fc32efaf241c7712b0a7e9f881763d8fa0711a452d9b71ea25e973bffd88433cba768f1e5b3ea15bdae9cb9428000000000000000000000000000000001527afbb6594dc0f472673606fb8f4797fc855bde4d308ac1acdaa26f19a70f80f2d2bbf3498b53b887b79fd6273231d", "Name": "matter_g2_add_72", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000fa7f8fbfa1d4ef5f001a451c55ed261dee344025e599884b29d086e15665867932120d33bee579d5eb1b7e6c7299f310000000000000000000000000000000001f06356f793350b17b47a623059a068800ca1eab6089c7c146182990063e8e23bbf40d95a42bf6e976224b680b75bfd0000000000000000000000000000000008807f6606d2302450bfd8b38fd4147b851ff59762c1ff48f9442c4d7b77a32c5e023821eb47fca839a27fde60e5f61d000000000000000000000000000000000c5b92f1ca9c20d4b6b11d794a5853824cff20d9267a20a7aaa4bed8bfdc728c4d4d50feb8f0b569757b97f473138db100000000000000000000000000000000039d8e90425810a0b2fb5c915905863eb2da363ad4188e42cedce678bdd0f51eca0a96b78ab9e082d59dcd10e3c3c97a000000000000000000000000000000001973250dc31d16f658323d021dddc5439ef4396b6ed735f108cd7b27feb1b508daf863ab6431a77ec0b10cf7e001244f000000000000000000000000000000000f05a111b41a54e0ca78c3a1fff3b80bee7c1505a06b9a4faf36a73b87121d2952cc4f4c4e0dcb6633cad12b0caffc620000000000000000000000000000000018daa0f9a2bb347517eee63463b9d6a5e850446e8a94d0986f2921bf81a9f7541e8fee9d7bbb6d9181021af945fce3e3", "Expected": "000000000000000000000000000000000018123e82a5572e6b6c62d5db07448838df9db7f7d15dac1adba1fd924892c8bb3c417354e838f706564a9ac282c2ac0000000000000000000000000000000016613fc38997d39b2761aed3485de4d7c273e8392e434185605e968ed942b9d4712cd0d538ed5ed1317870d0cafcae27000000000000000000000000000000000354365566b6e43f8b7f4b94a6343146f35ba3abf61a204e9c976b1ad1a90d4d493494c957def69ff270371c1c8d953100000000000000000000000000000000066adbadf1b69dd16cf19349c82e362be4a3768551599b81a4853ca524a24326e6c9dcc38b5a60ed6fdeb3cc4e7973bc", "Name": "matter_g2_add_73", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001191410ec6c5ff628bd25d35965f5e9fa7f3c3d8c0a9a1ee7ae37437a97c25e221110d892e2c7a0e9c8e386774eadb80000000000000000000000000000000003be30c25a18cdab139277232d8888f6d13112c9556895af8030f1893114d5845d895df9afe3c6f9ff7ffb1919adea9200000000000000000000000000000000197f6b4e38be0358a3f1722664c61e62587ecf5467f8aadc3a236b47682a75cb76bafb18a5c556b321d5da49cd4bfd4e0000000000000000000000000000000002e4ebf7f22d929b7421a600e67fa2e64a59edd87a2e2eb9dce1f06d3c793f1a812bcdd510e654d44fb4c1de8c64ba9f000000000000000000000000000000000eff44a5e3b9fc8ffe31771fbcabea6efbd68384c5931216a2b7465aaa2566ee116b7daeea632677f35379107f7334f0000000000000000000000000000000000c3c942373f69c2c9631cef1c6bbb1a4567d5b95500409d4f2c6bf4a66ee263e6f167e22790badea0eac4a541a9035050000000000000000000000000000000017d9e9e2008501981068cb0403e73c270d99defd468cc9dc2d5bbc57750a4a58236f8f7a8df4f8b607095b6a80e7de49000000000000000000000000000000000ebddf4fc74f25be3c358b72a20d1c093f980adfc943b898266592f691e11413c60151a0085d6c9aec8c2d329abbac0d", "Expected": "0000000000000000000000000000000018ba8af47c5cfa552374cb1b25ada1ac785381f2da0501f86c9e7b11cd4417e64095a5c4bdc2480ee10d215ae2296063000000000000000000000000000000000a2e09eff98280f6a9863d8b8faf8871b44650496eac1aaf90fc2b256f88e937101407d722c95fa76846776d4e6bf0dd0000000000000000000000000000000003824f5bf25fa4aec5a9e044703e5564122bec11da155c01ba8ab8344265516c1063983235863d826f68bac455327c65000000000000000000000000000000000ea72f8c6768736800b141b477610e37477d926acaffaa1951a5bfebb042c94c065e984a8812430153d529dbf07ce2bc", "Name": "matter_g2_add_74", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000011c6f1dbccde640f63ad7d40089779d01075e26269421b4ce12fa5341f58ee9110f17d08dc1052426f2d00da2dd70b4f000000000000000000000000000000000740b147bcdf06705971c113a5cc12fb37345dd59f2cbb5ff500ce2b347fc5a8199cb3007a871670d5093f28979cfade00000000000000000000000000000000046563ea98b5e85b3c42222d5e0d8481e6aefaf077a1b99f2b4eefb397ec846aa3659aacda569054c9c8b9b69750272b000000000000000000000000000000000812d887943506d68e3525ced9b979354539b7b14003a3169e0084c26326b92be67346920c9a99ef0f9638e8991296fe00000000000000000000000000000000081da74d812a6718e351c062e93f9edb24eff830be5c44c3f21cca606f5b1287de8ba65a60d42cbf9740c9522fcdc9eb000000000000000000000000000000000eb1d38fd394b7e78dfaeb3b3b97d3d928c16472ee74ae0be1ec3efa510b9bb64cec369793219ceab55a0ed0ece23de80000000000000000000000000000000001fdc4256cc997934a65c68ab9767b09c7aad14b5765dbeedb72ab2429231cb333ab9f9143414359376d76857e8972d9000000000000000000000000000000001362f417875259b47cfd9e4c5feda52b949dcbf5b8178318428fd3e70c384020e58f515b9a24af5597cfa037d42491c6", "Expected": "0000000000000000000000000000000009f1339cff0b58b00a871add058929ffebdc58cd1bd8a9c2c965c63e1843945b28138008cca8bf7b7cc9afb69a11767100000000000000000000000000000000011f65b337710a4043e1fa58bb41d80d505e2aee434b6978129c80fa1b124db89e61617e89bc0e596507566f4a484e9f0000000000000000000000000000000017560f768496ed583b3522c4a013f8b96073197e5b53e9041db6dc935a266111e21d8c54fa33b7bda944a573f6e1f07d000000000000000000000000000000000168a0742af91f42058e6501e122b6fc50dc966c2f5981372704694544aaa68fba2b6483752fa2464526d5072f84d8dd", "Name": "matter_g2_add_75", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004c8078fe8567013e8d05a546934026cdeee7d485e30d739407db16fefaef53ed7bff0f9adaaf064aff014ac919d91c600000000000000000000000000000000107cc17f485af7f22e07cf14c5cad6368323f720511fc9dda677b360567f769e47a77f61274927ef9b7be48a77357ec40000000000000000000000000000000001487f0880a6cbdac33ca35b9b65e4ead9d8c2e9180c993bdb2052060325aff8c62668c643f0cd9b4bb1f06a3dc74285000000000000000000000000000000000d4b2d062e31fabe8d2a329dbd6417673a519f455739d140246f2b3e43e20f390088c08e545bf0419d796ac71aebb519000000000000000000000000000000000b8e764aa5afa4a6e8227d1bc720eeffd72d963458a4963a3bbe697d3da11186a30d90f7a4eda5630f6967095816913300000000000000000000000000000000085d05b570cd58def6ac2f7e80dc18658dc5d0e6a1f5a5cf4d18745e03494654eb1a6d5399ec2c5288890ade446317d00000000000000000000000000000000010fb029e35b3f6e156b8751415f180ee3960cd3bb6ba9b8e456715ec70b1ba1410b8bfb77998f744d3f462533b59e26c000000000000000000000000000000001472654d9aa210a41d74e3661e05a9eb6b292719b46aa65f94b6abd514bf05f679dae89d21008245d79a381b0d7f51be", "Expected": "0000000000000000000000000000000005daf8338637bddeba63c788d78faa622e014efb84d3ac1d655d15af06317fe31d1782b2990354bd507632844cc87f2700000000000000000000000000000000185550250e2d9eec798e8b8c483dc37e2a917b304a6036e8ee518a0738d6bf946d99f6b7ee352b1a259aa894d53a8e1300000000000000000000000000000000105a4865d66ed4bc4f51dc52ffcf284615593d573b6beac490c3ee8e08ab83a529c8dd062d762d1d70b9b3290b6e8bd50000000000000000000000000000000014f598e5d0e40090f29aec1ecaccbebbf2a2d6889bbb9439798924db41b70c0cacdcf1e8ff6906f61943e9a8a1ae4fb5", "Name": "matter_g2_add_76", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000811e9b0acfc10830c074c5a4d9f4d9382461eb523a61dda0b77f1c43b285fc5c1ef3a1fafd923addc9a6e904505a255000000000000000000000000000000001113102d015dbb509f0b8d0d0ebb4d3711c4f0e1e3d55fb0af247dd24be4fec9d6fe3ad73fbdcfe206891bcebefee4dd000000000000000000000000000000000085aae9e58fb97b96ca3c089acab7bdbd0c3adae141bf61075f5c13145b0d07113f1075dfb959bc7c2d3d3b3a06ab2a000000000000000000000000000000000bb5eac8125807c10270d94e5bcf278241d6fa82f68e41b5529b28aebc88870af55881db526f7bd221a8c4c0b29a1b7d00000000000000000000000000000000042280b112fdbbd94f647e5b1f4b51d864f85063a5b66e1f1fe5b1a8d280f9bf1db81ad3588f93f8801ff1a3f66b96330000000000000000000000000000000001e0887904228790d03d8b6d17bebdd8659deafa2ebd9b07069ce89fe228824a39966953d14dda1bd6ccce5faf16e4d7000000000000000000000000000000000520cfc8c536a1d4e685c4eacbc2000d70abd72e1bf8ce3839d79f5cfa069ed31aafb15542f23b8d1af678bab05a2d410000000000000000000000000000000017cfffda12d21c98b79ac31c5bb696783afb7d69c2bedf0fb070cf7714959db14957a4763564b65b7ed214d7b48d399c", "Expected": "0000000000000000000000000000000006b63929ce97554659ae731d60d11abe858383e39a67007877f68233cba8179777c0dfe511fc730448da3f1c4347f85c0000000000000000000000000000000016d4df414c287b0871c69f9745a9ae68ea3a1ff41ecd17d87623338bb8750bf12be52caa81537bacee06cebb86f894890000000000000000000000000000000007ad72c98e2428b90bead3616f1b31b26e978cd3f9b6b759ad53056098c18932c48ba78d3da112d7a738d7a9ba21d84e0000000000000000000000000000000010dfcfc53d0458296686fd7e0555593e0378d2cb176d456abebfd8322012bc9b408bb180d4237679985457e689131705", "Name": "matter_g2_add_77", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001335276775545fbb4c701beb57cb34312108c9f1d46b4aa4b09a16faf0e648b4e80848bf5e75ed8730715f0107afc9820000000000000000000000000000000006ffff8736bab41b4ee5681b741a81fc870e648001027161144254d04c678e4f954e9f191bd8b26201aec681cbf0654b00000000000000000000000000000000026ede90d14fa0885baad21f9631bae058573251cbef5757bb8cfad061f3bdc78834fa5862dea19a2236c014b0f1652e0000000000000000000000000000000009844d0cf7f6f3401145d8d720defa577ca46b49e04e39c4c139ec6811a574e7dd5ce3acd00d1ce9496f10dd15c6d94600000000000000000000000000000000137e91115129cbaa1ae2bbb79abe5505436bb51ddceeb011d56dc5c3c396b6b00067d6e6108bafca40fc717737487b27000000000000000000000000000000001592fec7d33bffa7f3eebf038e3194513736cc41a143471fb8c55a44c7521c07e4d8368e5c6ee21ed0478f949f3e224e0000000000000000000000000000000007f786ea1cc7cd69ae1061d6b914278dfc7ebe8a714aa8cd04323860314c3b4b36054169dd5c6c60e67bfa3902d216f50000000000000000000000000000000019675b09a4de34af3c6e79452b57b31b6d499200e996008a9e7d1c910ca0ad2a352dc39cb3fd7333182476095b7aeec3", "Expected": "0000000000000000000000000000000009b166f124b5b85875834b5b0c088ab79a2dcf262240b284f57722e78b6eb56a192cd32544c1bb93ef492fe6d7a6216b00000000000000000000000000000000189b9792982b51b13cc3fc1691e0569b6c8d998168d3a3376e63ca60de4b30a84ce8d04fb265bdcf73f158d8e316bdda0000000000000000000000000000000005b99948b635750040b5b59568f0e8bacbfd512db2ae52c5032cd23eac18ad58d83b8f78cd26ae979ce2abeae8e1f3c3000000000000000000000000000000000d0b6561a49c358101b30f714563bfefc72e0febea857b1ce78cfeb9508b0108c2089c9b35cd694bc8c0ea8afc8d047e", "Name": "matter_g2_add_78", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010192b925fca096682acf138833b12d96bf97c9a2e69e4266eaaae1785b9008f36082e23e2d42341427edce24449935f000000000000000000000000000000000d5b24a94adadbf542aa663114096bc670e1b6c99f3b661f55de121922452534faed7f68d6b431fcf6f3e379d7acf6b6000000000000000000000000000000000acdbcae49206b749d8c0d21017a33e689ebe26804d1fe7c863a2ea4210c3559805dcf73685702bc56e644b4e02614a9000000000000000000000000000000000092309d684fcdf44bfa321d473060dc2d8a8c66c51419894a3fbadbf1b56179c31dff25403b970d543f1dd0e19e56cf0000000000000000000000000000000016aed55f56416b8f450283c4afea4c606100eed9bf7b8fea9ab4d04797a7bfe3bf0f10cf229f8ce3156869d75beabe6b0000000000000000000000000000000007e5c03e51a513c6f77179bcb5f7d147dcee32426b4365b1c95f434be7f83a5883d1ee5b0e01a636b3e5377542314b75000000000000000000000000000000000fbe421858e4109c51de57b77da4f9c4c1f950099532d9e30e2f7a8b8b4fb9f708cde1a497050d0944e089978b15321e0000000000000000000000000000000019f48a0bf0f27df65ba766a65e831a0801a4ebcd1995a6002a803f88aead1503b7c39fde8ef5c4672020307241958a88", "Expected": "000000000000000000000000000000000bbb59d3e6b0b4d86ffc89bbfcf543a5b8ff922f1999a1e06c501a734b19dabd54632132c865c53e5287f69f06942a58000000000000000000000000000000000a3bb94431530879a7fb46b317d4f3d65b5a790739b396c78521a20e1cfad9c44248c9576be11c70970a49a1914ceffd00000000000000000000000000000000198df068ac5d3cfb9bd6896ab64495f4b9933a72872679ac3a46764478f043e9fddf17a7ef85fb72a8dc1a722804198400000000000000000000000000000000155c1a9db0c90634a6d214e996b13252bd4db3a4ab84ca7456ac3e7899e6fa096904a90f1150026307a1cac8de00c6df", "Name": "matter_g2_add_79", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000014441b14765eee30e8131a7ef62c3b59370f2f6f0dda20fb2a3654fa09492bf695de1d1a8f250bfde3c7d2ed805ffaeb0000000000000000000000000000000019d813f8be2519e89d42a9fd3fef09d44a996d6a4713a9c224bee10f0ebb196370d6231fad810edf9cb4c875f08357890000000000000000000000000000000001a5abea13e909bbefdb51ddc699614366f271b2f6490ac8efcca7759833f3feae11057ab1b9ea32311e7b6ea6de110c0000000000000000000000000000000003ac2bf3c5486ca176e34ec5212165cbe04fc9e8c375e3e999a31fe014eb824ea3f2d06b9cf8b86ce3a76960cf2eb4d70000000000000000000000000000000016114be17b400ba35875d9009b4d8974023a57d32508c9f658a0d82a8efc6b379ce4a3dbf5ca7130c5581f5008806934000000000000000000000000000000000c68cd7b9d3c3d6c559fa3d52da48ebe68e40a44863c332bb90dd151d1281dd3faa34e6c7b07c277affbdbc1b0a43cfa000000000000000000000000000000001233421a38d77c59bbe1b83992a7a6c964ede5ef83c5a72bd1ba2c0a81b4205ce9a6925718cabcaf4a72ca3d216fbffc0000000000000000000000000000000016b8c22b35af7d925b5c68b6b7b63442e051fdc45542f233f2d97106c4b960eeb47f204c659d16a3a0d3b65ee38ff148", "Expected": "0000000000000000000000000000000010684ea0303f0e76b60eb96c470e1f0466f1f2b073bbedc1a0c0df1d2f6c66d77cb90ef9bfa4fef6a6a9eff8f5c66f9b0000000000000000000000000000000010e7ced79bbf01ae9f65d26894c73a905514296f19561ab4d00c0cde31737d01e7b4e8b8e6050054a7a17e8acb74d49d00000000000000000000000000000000174f771a98e262825ff2db7571f5f5475007d2f73a2c265f24e2929671bd173596b8b163abd46b868a644dd464dcc7cc0000000000000000000000000000000001cbffc9bb3195672ea2d998b169f853d3d4b4e147379329b1bbe69ce76d08ad78f87fdd876af227a050c31884fda084", "Name": "matter_g2_add_80", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000598e111dcfeaaae66d1522be2a21131350577253a3f33bdd74a04b0bfba2940e73b62fefa8f0c34c4aa91b633f6bdfd0000000000000000000000000000000017fefff7d94afbeceb33714e9b5480c3a2f3eabf9d7f6e8507ae54cb65f69b21cd7d04d23f24e3a272c589f572b91864000000000000000000000000000000001652e3f5a99ba8dfbcd1f90de955ef527947642054be603c1b84b24bebb579b78e2a0be426ec21d32783a0e55f0178dc000000000000000000000000000000000a6c9ec91e8bc86ab198416cbc76239f0ac0b903f40310ee1f2066b01b08191538ca913c2736f53f23ef37fea13d527500000000000000000000000000000000135b96feb4f1e712661ce0d13842de1198c589f335141ab1fd7ffc6b9d58de82c300e9fe6dacdefe8e68b6db9298da5100000000000000000000000000000000046a3563d167d8b0a9f74e0c6514fdabd795110cf48caa014947ca90a9eeda3d07dd7dce58d3f2b7b86fab1143946b560000000000000000000000000000000016c917abe637da21e60378ea7c2682306aded4ff17ccfea742e9ba63590be1b0fd5432ff0d3b72cdcb15943763cbb6bb00000000000000000000000000000000153bdddfe73f21c3593b128d3885f621935585ba1715e1d989e87cf7271897eea3917b81f0f342790f0f7a330ca0c68f", "Expected": "000000000000000000000000000000000fa306f630d06c801e0203525c75fd6065bd12bcb3c4d45c7e02b597f85a53fae1e65a969feedca75068433547e4632d0000000000000000000000000000000004b1bdbc29f19f6484ea4648c70eaa47cf5bb07bbc255bb72dcf68a7b661de433dafb682d51321369cd3372288b2b9c400000000000000000000000000000000136671654b24e1ff2e8223ba747ded51f5c826b6e2c0f02e2865fc35d15045f41952835800406f60f966d1f241914726000000000000000000000000000000001007b5e8ed7f0d25091dd959d89732e9df02561a829ce013f5ad1adb8d6d828a8ce87b52d39fda1b5dc2b581ca420e22", "Name": "matter_g2_add_81", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000072e022c168461905f798e87425f2eebb517e473cef98c255d0fe434863ef5811920af65bc946b29d489b5dee1066c56000000000000000000000000000000000e7a9872caa82d191f6014c845e1b3ee4ea1ee89852b546a2c85ddbfa3c1d4ce99002e3d7732ccb8cfbd57d550285ab400000000000000000000000000000000144be65db373f6401d76e0ee64e51076b861e8fca596dd6a7f3b5735c23b0cd13248404fa0969ecaa701663a1032f48a0000000000000000000000000000000014c9e9c5cffc4518889f7742440053678ff1d9fb1a1a103d0c1f762b10655bd5849ce98f4bc5eae80bdd9e767aae452300000000000000000000000000000000117821e6c87bb0e04882e95d36dce18ca33a2c8bd0efd5532b33d597804c08ff1799b2d64a95cc84bd31ba45c3b1e822000000000000000000000000000000000887c07c8a9ebe3154950746a4506ff192bb4a05dccb0f4a1a8ac2b8ca0da07190129ba44d9bc8e6c2666027c67d2ddc000000000000000000000000000000000a9e191c9775f57810a511c8bd3dca14b3328e20f0983ca72e42e561b5dd1693209b42a11f2faeecd6307dd34cc01d60000000000000000000000000000000000146061b13546754c74a705776656100a9577f1ff939a82ba990d6b885b27c450f824555829bbb19f9b1f636991799cf", "Expected": "000000000000000000000000000000000fb74d9ad4de11df81c48d10b9a14fde8353ac47dc902b4420be4c086332be480552e26fc42b7c0f30e34f740bf9a4e6000000000000000000000000000000000612a7e23bbb525f91084b122dd4cfce4074c9e6eedaa7cddb58a14e0b1eccc2f08296baea3eb3e003e576fab7c557ea0000000000000000000000000000000016dea145df47a2c5262893c273c6158ee14d44c3740981c161624a6e9ebb982a52c1eab6160c3849f2bf3821d953f4c3000000000000000000000000000000000e920661772b8b737f1a663badead0e89aec4cbb86e6dece5d4db8a673e75b844bfe81662dff671658cb8386c16a7f3c", "Name": "matter_g2_add_82", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000948d0f0c20715f8658e1f2b4f9d32d851e584287225a2f47735a1f4c241b07f8d7c5dd8c13bcdf84e97d49817d4d88a0000000000000000000000000000000013c064548cb756b48600dd535af8eb5b9138f984bac0391df2e90a204fcb6c36017df910031864d802a2ff719856b336000000000000000000000000000000000000b7eeb7c9a01be88e573f196c2a531635baecbc8cff9af385455af3757301436686596ec7fe3618af26953c49f7450000000000000000000000000000000001332f4dbd5461ab9e2c8b3c19c6ff407a071018c92d2c17c1d1d481c24565276c0f55eee8692016c1fd76d70f44627c0000000000000000000000000000000011f9a369401d2c376c77b4b414e345e6108b11594b26521b51afe6318648af232bf9f1455a99dc2f9b0207cc78339510000000000000000000000000000000000863492499f4791e71bd8d58dd2444a34e66dd3e3ca1cb3669f4182fafc9ef080a1d8111b3dd754f2405032350732b32000000000000000000000000000000000e96f685e6f87677cda23177f9fe7fd15726ab31e4d85a5725e93d558bdf61437dbc2c9ebcfc6a94705fa70de88a81bd00000000000000000000000000000000157ce060a46912c992587fde3db4c64a705ab7115717031778176f6ea311cb352f3a76f4839be4658470e4b0b9854f77", "Expected": "0000000000000000000000000000000015930559743b21acaf390b557fb960d3021f3cde80630d8867a063d445f860c8a01037057de1929be16d879416b12a6c000000000000000000000000000000000c6074c54c83f717700f61c5b6bfc641502121b59b196a1f8c5f2945e5db1bca0d7a94fdae96bfeeb6204c8c3f4d048a000000000000000000000000000000000b3a78454479c0990e4c65e4f831606c7eeeaef0faa86596350c9e43e84ae959a0f32c8d03d1f631d9b2ecd046efcda6000000000000000000000000000000000aff797d7572f20b06bac75bcf8cef879df11599ba7f8b86eaa28692d1239cff22841b66e28662309e81a6a599e79ddb", "Name": "matter_g2_add_83", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d3ee70610b5029a28e586f0f3e65bb19a263db3438710fcb8073e1b25f83db50eb5bbb9d75cb20952a225023f747baa000000000000000000000000000000000682f7d5cf9d182b20ee88683f3915e8c9b03074a373e573aa57232de4e997bf155acf680e365aa0988989dfad102b2e00000000000000000000000000000000143962963e230a9154dc328f9583f5be6923a3b10ee7b1d0cd5f5cbff13913d8ff78ca315be7387900a50b94449884c0000000000000000000000000000000000f4f934b42452d41cc20d7b1ec547bcbcbcc10f215364ccf2b864db23a09d06e94c7a87165dcb691f4975323486757ad0000000000000000000000000000000000a8382a5f73a7d15c3ee35e5fcaf7142e6d91d71ef30ce7da9c8db2f80c95441dc93674bed244096b71aea40d43c318000000000000000000000000000000000733e9a022695ed6908caf6ec7e67211c6d5ac16ba3fb8e244227f5da787e69e7311fac1e8d102a2d84e6ba98903ff6e0000000000000000000000000000000016002a054bdf3cd916b5f8aca47d97feb170e8864da2eff8bbbf19a5b25ac857dbe6daab97dfe15a4e82455d154652e2000000000000000000000000000000000efc6f6c595368288f5687e710e2faebf12bd63a0ca34a527c05f1d925fcedd23c5e2b6708194069a36f858fa510ee41", "Expected": "000000000000000000000000000000000351bad2f1fd9adc84280515c2d9e538b69dd63ac93514987ecace75d6bc4585199b742eae0d357d587924333721a1d90000000000000000000000000000000003e495b544aaf19a6415d5558170b8686968dc922367c5c8c212fa1f2785535fe0e71498b98b9a39c8b1f2384956170a000000000000000000000000000000000c7040f34872eea5f98ddc78737dd01fdafe75081cf66ad5c7c900674fa90257105b4f4fc59103dd5b92727a072ae462000000000000000000000000000000001312bdd27ef038d4a89b12c86281975bb34b435d42642fe0732709baf55e9a0ecc0ede8a4775a33e880aa2e1fa7b7ed3", "Name": "matter_g2_add_84", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005f0fd4080e26971ab16d33aeae04220ae23781da3179e38190082f1d167514bd73bc8ef976a2f333570e9f56a6c05e6000000000000000000000000000000000e159905d29b52ba61575c3a263093017783e1028b3701ccf060c165ba33a765b5265a9b1681c1759bfe2c9c401275e9000000000000000000000000000000000c5ac0bc29a49a7c37d772954da850e6b5e301e230552be9a94017d770ebe2cf4dcfaf104633623e024aef6db57892900000000000000000000000000000000002228e7f42a9409acab49cca82cacf306f6c6c29fd9f7e2ed12fef2d16383cdb7bb2b39ad598b301072c615232db1fa800000000000000000000000000000000050b449c2425926d961af37c4c88e671eac676a1f828def54b76dc04960d0222fb5832ed44c45d5fbb59549d9d24c236000000000000000000000000000000000c6e811987b30ed77c804e647f867186d425411e514e9bf31099cc0f695195729ae970766b2738a928e776511a44f8a1000000000000000000000000000000001408beb1c3951d79fa43477c5af6894ee3c2ea9605f8ae64a78b51ee7e16ae9641134a9a75735972dbd7b53dd4c9f3bf000000000000000000000000000000000e6c6c9405ff001faa8d8c06bcbd75ee91140f477ef8283d3c5eb3039f16543ca9e7e4162177a7499edb6f3fdb01643f", "Expected": "000000000000000000000000000000000d521781f60198341d116fa5cd9e2b5c2fe51f91f6c8318f351df007c96086f6c3baa5cd2b9b4f442305695dd9b01ac70000000000000000000000000000000013454fc15b1d182bc98d75947547b3bbebef6d5e2d38ed7c67d76eee8da89ea2be19280af4760282fa7576412d5f2107000000000000000000000000000000000d866015c84de74c24dde252542d0d3823f435203c71cda140af235d88f3f4b736e9d75ec32c09ab73bf74083e76866e00000000000000000000000000000000147dfb5f53a9cc61b6788c911dd8649c09cfffbbba368c1872a31cfe3bd6d6427d7b00163d39f8e0b81fc4c40dc60b87", "Name": "matter_g2_add_85", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000180569ce03e4a0155285e733adb18fbca71225507a7adf01cb8e8648891525305e92087f58378f4fd8455d5632ad660e0000000000000000000000000000000011ab84e42f10154e306a568d7cf7bc381000f0add0500cb508f695a3b283ea69d140aa0ad48fce2d2d6fcafe60761078000000000000000000000000000000001136c3016474d6f475609606e8d0269fcdab9fd3188a512681cbc41eedeadfa3b3d9355e5b4503e8b5c3665e49fdf3ab0000000000000000000000000000000003f56cba1b9cb4302099b16b09c2602dfab80d1151685ef78e5054cd454b319adf8b5998053a5b9fddcffa020595e3bf000000000000000000000000000000000a8679f08643ff1c4db54e58de15a4828fc80e3f9d80a932b26b49d5c13831b1dc5dc29af2e080eb08e71938e5010fc400000000000000000000000000000000110957f7e9f8e0806bb3d2a811b91c926feab046ef983495f3f768a6cc6e4a6d95bb92facb77d989e53ce5489aa64b3c0000000000000000000000000000000018a8b48aabc6c003a58593a40b55e54b122994f9ab58cc229d1a0e6a3670244cfe73854f07117dc77dd5c2c81314a17e00000000000000000000000000000000062f6a0a8b9dd56001f0f57f82bb7468d709fb8f33e6729369b015685995ef27abebff9dda55c38b0d9e88a1e0b9fc6c", "Expected": "00000000000000000000000000000000059fffdf2d79b4a297f6912e3035cf0b07db9372f3485150e00d60bbe2e7d86f45b5c2ef062dd92c7e8b1e2be5e9bd140000000000000000000000000000000016acdc57e7231b020268373ddc8b8a7318ead02a8c7181165ab045208409373eaf57ace9a6db1fdedcaa477c7a0ff6f40000000000000000000000000000000012fe630f7de8ef5a129b99faff2de080849bf3b59aae1af042c29b1cc49c8825a4f28c4ccffedc6d568f306416b5bb90000000000000000000000000000000000d86ab3e49ffdc7c2485ecbd00256af83e7f3f064d212ea91245d86ca75e3c7f28b42fa9496a5ccc0514cffc60c9fb83", "Name": "matter_g2_add_86", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004d79dab9eef873f3415d66172bab7166ce0c71f322529bdeffa915c1b0d3fcd645c91dd3450ba61593ffecb95edb91e000000000000000000000000000000000d611a207d3222bba199fa083d0459675cb5fa00839fb4c9034ad868fc1e79d653c18651771431d6fb6b6b5ce8cf6f7a000000000000000000000000000000000ce802ecb106a4f0ca4efdcc058dd0e29deb6a5d30a2c15c8eda896bcdd3ac19053c10105328d239b26c5ddbdb3a95fc0000000000000000000000000000000001073e142621ecbeff6f81453660362545751f992ffeec3a83477fed3e6215a709ffe0d17b65d3369f8f3913bf000e84000000000000000000000000000000000ba48cbd776dd03a5b69aed3a31b7d151a8d98cd9adc3b9987cf2ac94644a364ebf3d30cf31742e2152aeba0eebc9ceb0000000000000000000000000000000008793a44c730949a9e50e9439d579ff0991dfc49a67a29b1701989ab065e6e937b14ac1bbca5a3dbf79a61837ad18394000000000000000000000000000000000d81a0809479694fde24e5a3ee7d32deacc25e77f241024666bc3372e80379a722863ea8105f345f1d09e462fc5a8c6c0000000000000000000000000000000001a5be923f1ca5ee876d660fbca5896f1634ef6a83ff8c64dca4ed76d1db2ba4875099fa5a39a09f839731278b307fb1", "Expected": "0000000000000000000000000000000012ba9a8fcb69d15eff147f663a5d7927b6f3f79330eb9ee625e0100b146597554debfcf97a3afb51387a73554522ed0e000000000000000000000000000000000a63a990d6454d4db6d58642eb3489f79e517fbbcabc06f2eaa00c4b6f9a07aae97991f169d90af3461b7a62db276e00000000000000000000000000000000000a95203a1628a6ae2551df832f7ab94ffcdbf985e4c9744e244214c8e8b8079af05a9321d1e49b7240c2bdeeb7b783280000000000000000000000000000000001ec747203be73526d3f943e0af814dbede34020144bf247eef9a6ac2cfc83ef63f18a73d3baae18bfd8d5e83d0519de", "Name": "matter_g2_add_87", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000bd84f04b3858b1138b1b429c7216d5d1b1e99c1e0fec26440d59b1ad79788c2d5583122c2ad769fcaa6d10d816a1f1e000000000000000000000000000000000387977ed1ce5da51dca230531bba53d17d3de5d593ec576cabfe6463d5164d7153025dbd4cb3525c4145c4f6b85fc76000000000000000000000000000000000a19c943a90fec6921367a2edc5bc38a5c59839cdb650766a2d2d068242463dd4460bd1d0e7a7fb0e3d2104704b8b3730000000000000000000000000000000011d99d44b200feebe00bd42809e3f67a23cce88a07165416cbfaf4db14420f99e54d62db4280d2c99ca0bc3dc41eddbe0000000000000000000000000000000008691df5b245399f24118badfbef3e01a4acd53dc9ab149e407c733df6122fa91f5cbe2f9d247cdbac18b266d3d8f18300000000000000000000000000000000053e6eef4ffdbe239c8bbade8cfc90461d54f281ee6180c271412bf2d64e005d3f0291d3401c324e41067f4dfcc4b2720000000000000000000000000000000000b76cdde0e1205c918e6e6d324ac3f35d42ebe9bb101f1cd8955acdfa8836f22f1497bced2c93495022b0c335bcaaae0000000000000000000000000000000018340c2a8b079b88595aa50e93251d12e3a5aead2d2add3b72ce82e03a26525aa45fe9b379504392edb0a2a26d7e99dc", "Expected": "000000000000000000000000000000000eefda9046a950c232c6244a79c33e7135d0896bc57839a4f971030220e3ca8196cd0ad75269f3cb5586a384dcd17f9f00000000000000000000000000000000195ce623693996f5ce9e45b4e285adb969e6771e6b0701fb5c95715523c8cb93aa641583821a3b360ad6f4ea1aedcc9f000000000000000000000000000000001553a4d0f965d26fbaba56294591935bed63c84abfedbb9d5c61f3d43484ea71600935fe3c8b6b137d7a9074d907e86c000000000000000000000000000000001673c42c88e4acf8ca38680694b80458f988403a4bd667468506452303000d13649c4f610b738a94ff88b65053731c08", "Name": "matter_g2_add_88", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006a186aa584a466a860849c78e4922889c95a4ac6f39c99029fbb422c43d699a8baa51aa4ef51ff99557babeb3e9506800000000000000000000000000000000065fb15b5a0923bdb52dbefc7e9f1a898e32f17d610bac829235446fc5e1913fffc8176e0fbd33091505761f1d06d8920000000000000000000000000000000008bd358698fd073f660ed608462cfcef1da9a59b10905f1d98c4fe66958e56802814906430c10fc25a4d351d91f91cb0000000000000000000000000000000000a53638b1b6c6eeff468e099446300ca7c7bd899c6494682d14fdabfa9cead0bb37a0325d99e7d0ba6341cfa1d257ba800000000000000000000000000000000042120affcefe4735ae25e192d1cf34e40afdc6d2ebdacde2e23d30709fecfb71960bc9131e3702b27b6fcd5c7a98d170000000000000000000000000000000001998caf5163b0dccec7c8423c4c56a7d0f0b26d9034f707ed07f636f42dac590a2674c1667d70be385c4e626815c6640000000000000000000000000000000011d7aff6c4512f68031aeb94ce3733ac43659f9fc58fc94c05d99ae80a7656f66b3e3e86843387d1c10f51b4284755150000000000000000000000000000000012a9e7f3804c6b5b25410a82758cd5b6ea1eb150c696b0d67d92cf9eb1f8e17752184d94a4ad2645b1520d6aee1094ed", "Expected": "0000000000000000000000000000000007145ce58cbe48405392edda6022ba8942df055ab582ac402e7c9a0a951cc6a38cd147903f042273e736f30849996cd10000000000000000000000000000000011b457ba464ce818a34a11afc3c0007908091fb528836691e6eccaa9a23ea90cdc746769c4b7ec73efb1f2878413c3b70000000000000000000000000000000019ca519fa6a91cb7e83704daa9b92da9bb70b003f9e9bfe9f323430bfec9b19b01005aa9fcd19d5b1ac59dbdab0c0d84000000000000000000000000000000000ae356f5e5de0d7662bab8d947662bf87d792a3438ed477cf6ed4b27c935b1dd76a5aac446d4dc36db544d4aea40b505", "Name": "matter_g2_add_89", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001070b98c6348a67e996626ec2752f45e4c007e9c9668459a777c03fab633c10236a1c5be99f3fd950542d5648ef9e88400000000000000000000000000000000073a564401cb1a3a53334c0a55da261814d27b86ebf40b02a76b20973ba2db92e42c138ca7790261c2d70401c984bf470000000000000000000000000000000004212d8a9e4b01f5c6814a88561c2c6143eea61327b031a2e0e4bd056c12dd7098fdfe4d1511bb441ad42b55b584a7bc0000000000000000000000000000000005c5d23824b0fe05eb962194550681c57c1566b315efa8ebc90b3593d7d86ad18328baab8118c9f47eccc0757588591c0000000000000000000000000000000001462f8080d9b51235a8aa652445f509e3e13e3073769e9a047e8b2bfa5b227f4354bef017d18bf06f7ec98c169abf1e000000000000000000000000000000000070fdbc18112b49bd83f4347922797f2bbd68bf2592ad59041c97948ba7a091bdb3622c804803ad605604ba364dbdca0000000000000000000000000000000018bc90cd83e1271bf0e39b0c80989f0ddcffc960ae466c64ad340cc32607dbdc73eac5b9145e1339fa02a0c3fafcc1df00000000000000000000000000000000124c4bf66a5e015f142e9e4b26421414a60e54ed76c6d4acc0f20b24a25ddf5ec7ef1f561fac9d470a94bcfb2f2698c5", "Expected": "00000000000000000000000000000000135c42c10ef97279e3d152b18cbb8dac11ca8c805dd1d80818851424f592e7522589ec7df6748b5c72d0808399e629cc00000000000000000000000000000000083ddf3843434937e05ba9e101096371fd8fb34f226bcd517716200003ab9855f7aea94980c57a6b933494cc57afc562000000000000000000000000000000000be9215d936a49538442189c9a0bd3be07d4b0b1d14aa45afcdebc1fde17d33b66f7dc36da1ea5411549577f5a1967ff00000000000000000000000000000000176a4a4962c4af75a712e5093ec2cd5cb5c0433aa0657809dffbc0bc02b1ce303ac084f39a5721d482d41412d391317c", "Name": "matter_g2_add_90", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b1b3053774ad5515a20bd4c556d2b3ba95fe74fd0c955069c7f933dfd718ede90ac295f5a675f1c29dcd9701978353700000000000000000000000000000000145746ce88686021a0635bf6f0aa2f77c48bdb364cf4ffa804a57f95bd69d24eead05fbee24021c1ef57e1c7c7b894b00000000000000000000000000000000010ec4795a0762b86f3b83de1198698af67fd1b1be3ddef48f35cf82bc96d886fbb4c75064f51a9cfc5f61630c95d0ad1000000000000000000000000000000001465e31f58892466b8ae4b76a239d9f8d1ecb1834886344013cd1df0be13591798868d224d38213a6d75b02a1fde0ff200000000000000000000000000000000156901359e5b399168e90ccad27a054d147aa9c4a731294180e395e8e2d458f5537fdac591cdc82fd8bffa4c9fa126ed00000000000000000000000000000000143872757c0a25d85e95a86c5e09175fdbeaf59bae3d1e8a367902d59c662cc3a293ae252443b3201671ad1dbaed8ca20000000000000000000000000000000017f93d49ec5c34cdc31931cbe2d5b3ad7a6dcd3ea864862aa7b41d5b2f4618c9c92da01e246ff8f34240bcf1de4c1c450000000000000000000000000000000002180a95dbe57c43171e2607593dd3b54344bdbf409dcd0c5706a9a72ad0e26ed60b9e4cb17ea4e7b460adc5a6f6d2de", "Expected": "000000000000000000000000000000000bcd916c5888735aa593466e6ab908a05af528f34a7901fb60feb1f51737c73612436c192dfdecf927019724ab2a9b7900000000000000000000000000000000187d4ccf6c22381d0c40c9d7820ff8efe6298c6dad0caa25402412661737cb482dba2719c3a50ec08cd022230952dfc600000000000000000000000000000000164510d4f2cf1e14e039561f1baf82bea678d0065e378d5bb7443fa782e6ab2a3bf7e4ea125d6415a8277c60f5346468000000000000000000000000000000000281f2e28b73eca4db9966456b75de9ae3830c74ac928fc4c36b4aeaaffd47ee587d948f68056df2826ca2775415a53a", "Name": "matter_g2_add_91", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f39e731e6ddb7496448c912ae314e833d28208252c7f8e27bcf7eeaf1da6e2310538b4ef0d55401c6552e91fd70691600000000000000000000000000000000069d3612f924961f827497028737000513548ad8e104acee28f014e730d4752a583cb9a893e6169b71966a1c4a4ad2dc00000000000000000000000000000000090899907edcbd336bd4fdad0dd67c578ced4481a25b864b32aef920842689a2c23265277a6e1d4a1dc1b5047a9f79a000000000000000000000000000000000055ba64e2502baf68e46c759fca30247a080464eda2b32e7cfe539e545d6aac6dafb731c2c45749e50513979cecbeb5400000000000000000000000000000000162ea8f985c83d59361ee6beb49cf2a797d8c909e2eccfc61fdc5359d5ac9b10fbaeef2eebea1667b5b9bf8f5d603d6e0000000000000000000000000000000018344ca9d4913e817264ed8119fe4d136f2041b0a99d4b5fe7f2b7f268256eec9fceb27fa61c4225f47babd17759c01300000000000000000000000000000000034f7418d96bdbe4f1ed5996fc9e9e99233a5cb3aad717b3717e91ff94fecaa67250ba5b27dcf59c6e36aae08d22983a00000000000000000000000000000000100cd7ea3c342aa2c15e9c6121a1cfecf611235add08290cf9cb8ea54e8ff523e17a0b5dc41e6d07992e5927e3ff6157", "Expected": "000000000000000000000000000000000cceccfefe04f94e0b67b29b5df8007930665006cb5a59504c3656b8c0bfb52324cdf50fa2722ce15b0ded0efa7fc85f000000000000000000000000000000000cdf34c330c0125f524f0711197639f8aca3e7c435f8c5ea30b78e9622c4bb72a7e584980cb4c3c6ecdd0689daf36b6a0000000000000000000000000000000004b1505d7fb65f6c06ef23aef85b16f3d991218187c5782fb635ba805da463cec9cfdd670c53d680c603adb827a4460a000000000000000000000000000000001104af6bef6482ae64b3b6b39664ec06c39bc18fa91b7b4e5bfcd444c827bab30ef548b28ef5487582d88fbc6d7983cd", "Name": "matter_g2_add_92", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000042f1c8b9fe81cdcabea047d0998a1354ce09d62a14f1d0e9d188e2f35f2e1845c2b090c5e157595b33108c67e6c184c0000000000000000000000000000000018e69d3564d4ccc0306e1e6b227b0f961aa9afcad59d4ee1737f980dc876609c59a4c6a3506f987467beba0764b857000000000000000000000000000000000012ce5883156588cfe0f4838f819f985b09f1eab40a5ea8e30fc5d70d029a01a4537641248f4c21dd203909e0170737c80000000000000000000000000000000002888eb9778a4045feb5899dda258657b9f41345731ba630fbbf186b3be4b58ffc7f48abb65b693b573a73f85440a7a70000000000000000000000000000000001cdfae9234096578b9413f926ef8c6831f2c0f700e25d7553a746aef44238e493f8032e09f67f2fed9676c9611f60e70000000000000000000000000000000019c8bae08d3926997146f7827f00cde863684dd4050ea5da64f6798e7a930d3c1f34046bea0f44232594f5469db566280000000000000000000000000000000013574b997ee8988aa81db0e2ddb98be2e7005603076fac5cb246f65c869aa7bb3f148c8dde970e34e5e5efce023e633c000000000000000000000000000000000998bc9d41c5d527360fc4e68ba067d3778cf5cf00e5959b5ec52c1595aabe6e2e92d40cb34faa84513d150568c8cfc0", "Expected": "000000000000000000000000000000000e1ef3003fe3181f690224cbc7008856e1251430ce3cff56a1965c89a892604398f5101d1bec7ff1590b0cc3d23b854600000000000000000000000000000000185b4d4b5fd8313c31542bd1bac034046ddc705b41a034a00570181503a6ea4c2d808bba0478900064270fadf3d655920000000000000000000000000000000005bed63ab9898b89f92027c04ba256569e6285c851753e12760129c98899bcbab34b62172906a1ea4cb056d4d0a5717c000000000000000000000000000000000961129a3e212c7412018d7407d7ad16412feba8c138f4f6ba69daa1a25c6b23f3466bfde6f5f0d09ab67248a2abdc68", "Name": "matter_g2_add_93", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000051982b46a819c74105cb36da871fb2415328a1531d155856f6551bd043eca62ddb61f24af429edda830fda31e22cd340000000000000000000000000000000006449e5bcdb5619aac542f6633ee3e06a4fd56a3e1ce4034efc608131ff6ead70ca63e70f494f519d5c577ae7119c8c200000000000000000000000000000000153f4f5dddd5801fbf7f88a735b9170d24d5b63861d50cde9644579dcff277cdb0d5fbfc3b3b819a1172de05afb9135b0000000000000000000000000000000010fdea84983fe6c08cdc4b4ccd462bae2ba791ab5209363b10b3ef342c9a5e92184e9d8be1419e3d88402bc05bad5fa2000000000000000000000000000000000c78d84157dc0b102c3843e4c8e88f244cc1b2a27043e07b2fab694a58f93d47e4cf9ca1158a8e30e3d43f94a20d33b50000000000000000000000000000000004842fe0df312f735a9d8af0c2ff7c561ed9cf4add5e3e9402bcff1190f3f36ca91de8edc9472b3ebd27ee2d9afdf8770000000000000000000000000000000008c7a67b89960da4309888bc6ce31e7efe74867165a8aceda7c7290f8a92687100ccbcd39d4d5a67f21f4b63ecc638320000000000000000000000000000000001cd7978ce28629ed1a9c5433c555b1ebb584f80909599282467e7b2471f591bea1d73e7b0a247aed7de4f1fecc01204", "Expected": "0000000000000000000000000000000001504c47ab0c410b32d5f1fe3d3996dbf1b21c5ef5aa3a2862a9d561b419f818f0b32b8e931c65fffc393ce7beec70ee000000000000000000000000000000000217e9fddd2551a171a13183ae3aba6bc5ce99e8f3587b92a7cffc738b478d8293b8c71989cabf9a55c5f5077249345d0000000000000000000000000000000003874de865d93650a95af4e153fe557c45bfdc4837bd6e209b8f05ad12b8fdee6432675cd92fd739b7e98e56e7ef16b60000000000000000000000000000000011303c0c7ec1f434cdf07c110da5f0bcd85935c3a0ce9fdf5546ca61edbc2d478562dbd9aa45a5f8d96e033feac2fdd6", "Name": "matter_g2_add_94", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009b011f793d9a939d916d058ffe91b58138820a646cc450389b3074ae3715d06ddec1075afecda71c65c7ca085210c740000000000000000000000000000000003d4d20f4b93c1e90a0a06bd534d8b4fd64e4c4aba77ae42cf4c5b2bd95f8b02ec4069ea246ff46404e6c9eac632fbac00000000000000000000000000000000051e88c3adfd4d6a02d3f03812362a6cfba3a6c69b9aeef75b51106cc7f1750293d61e31f0ea29b5d7aa56debb6d2aff00000000000000000000000000000000086d9c4ea6769cdf49ffbbf7351023b4aea640e8c90f9291222fd0b5984bca4d481bf7e10df921406a34804e6a09f99d000000000000000000000000000000000e619d79792ac685030311a31a21203e5172d2e5d20ecf69a1e64158e7fe903b3695fd15432d3ca35562b5a8bd9cbdc20000000000000000000000000000000012394a621a503d1d92df3306649a6c6979816cabeb8f8d27450ec883c4e75f6f7411f3bfd068dc8dee58cdb8ebbd91bd0000000000000000000000000000000001652a688dbfd63a1c89452335bdaf248c97c9c6e5a3ad5a126577a6b9ab57075b22987ea8697b459611a5ab164f328400000000000000000000000000000000058a37347c5637808632ae6e8f264e8bde14ebb0ae69828f962f51b728321fea57c5a97ab694f7db175efe7a17d36cb6", "Expected": "00000000000000000000000000000000101ed22b16502de0d83303134a97db17ce956faedf47256a9ac86004bcd3ed112a71328a58f98a85977a7f22eb1352c3000000000000000000000000000000000e841a88d10493f301af54c5fe07a31ef90de106a6c87d5631b6967fd017f561a56176a5f3544dbb34b9f94040ebd2770000000000000000000000000000000001bde3c0076f26973651cedd3da97c7eda24451bda856026d1e22d3b65c66a3fcbfbf506b4b664b5fc06fca2d712d8a8000000000000000000000000000000000ce553ee3b7d5389798cdc5af8569aaf477b5b74ca1138454dc61badcf3ecf5e0ee8457e374b5735d0b8408b04fdbcdd", "Name": "matter_g2_add_95", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010d48bf523f3909cf90aa58a9517ef5421f1212accd5e8a0f830aeb15a587e215ca9c340bb846b1d0474e43840b2af79000000000000000000000000000000000cc1a3976caf97b9d59f448f6d9f413eef8904f360c0cf912fe942b38d7fcc637a17038973a133608ae769d3e389b18a00000000000000000000000000000000069a6122c6f0ec68834b7617c755a7eb33a80a25acf95859da5ff03316447182f122d20d993b04e79b6fe859b7adf5a8000000000000000000000000000000000058c6f8c297524319bae6722e0a957d1ba0f75ee3a8aaf06148641c67925d15780e419a38ed7e07410e82769da74f2d00000000000000000000000000000000030dfbb89bbe5c14a7a55e68edc4fc38eaee9fb539a6b2f941264c7dc295da5712b0af0f2bbcdb74f785dc9ba038b0aa00000000000000000000000000000000132b4e02fda605a69251a4a6289c47536f9735dd90908ed1fb619b3ab808b3a1f1ca3fcc8f4b35c9864ae311c15747f80000000000000000000000000000000005858ece0bb09e55e012450551025ad2a6d93a15d29619433742851a62d987e7f8bfa6c6faed76493a27060ef5f51805000000000000000000000000000000000dd6b393e6d1b8d546e3f5ce69bc1737399e6ababc628f25734030e10d82b5e9370edfb5da15566d80e23d2fbf8aad5f", "Expected": "00000000000000000000000000000000182f90f5d3ce3f5ff2d91430376144583247def83b3e83524094d57c0f1be98b1c4946964deccc25fc303d6450edfbac000000000000000000000000000000001844806f711735c5ca18ca48e559a9e327b87b91d22a5ef161da7874668130e21a9499728fbc2c88366bdb59f8ced0cf000000000000000000000000000000000815e7cff14b4ceaf26d1cda5c267f432fad294b6baa239b65d886ffb039321f9e24330ae738a35298c6d1ec1ce1c95f000000000000000000000000000000001188a4a2f0920ddeccde1a47a0636aa7c404fd77fb9c828e4fdb5406df80ee6c258c2d4a89dae5e2a2b05210df9100d7", "Name": "matter_g2_add_96", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000156ca5e80be8c8c03a5506ce9abd22a9d4958c372678c0caf6f1329898507dfcb1f06a9464cf080bc6881fa5b7df1ebe00000000000000000000000000000000088174d486b4086b931010da298a399e15b60a113e08f571e096d3a4e94b57b3a684711318796eeca9319119b201abb30000000000000000000000000000000000b96ff68505c088cc03a1c2dc363b05bc8544728a12b29569bed137780523123eb17e68f4632383c252d81bca0c5ca9000000000000000000000000000000000486fc6e5224c5fad56234c41856e60bee4a6c1046f673bf7d5c1bbb603b141fc91074da5f9d3d41b796a2ebcebd9e740000000000000000000000000000000017032b16be8656cf23bfe0abc8c9e6aade223fa9bea6fe25f95a025da79cea6adf38536eae3859b25ad1af1756b639cd0000000000000000000000000000000010975ed27cefbb43bafad0fd14c87ada8e84525e1d199fdf1e77caa0b718214b33e547a42a040ee3bfd51621a20d22fd00000000000000000000000000000000133d29aa41f92de37523d281eebfe91103f017e5fb390f6bad9a2a4419fa4702bfa04847edbca1da96eb1ad563a92c8a00000000000000000000000000000000014af850de7e800ebee4be1a33c7e3b30aa94106db7defa148568ca3c8d82edc97ab5769ac40162d3728687cdac201a5", "Expected": "000000000000000000000000000000000cf42f2ccff2e0cdda7e5f1d7652680650b4afa523c8f9a554ec18b905c837a189fff73982cbccf903ea492ea902b87f000000000000000000000000000000000d38219770f669557cdb623f2476b5f3f7478422b016123bf86a17bf75848548d1a1ce96a292637b8d52481321d80fbe00000000000000000000000000000000170d8722b824e3291b570ba8e4f9279c1dccdefb95cb5b7a94d27ad8a93513737f12d18ef3153c4e12b530bc457af34100000000000000000000000000000000021aee9e5f578328caee3177a4e08303c3b5533e288dcb75f94992db3520a6da16f4201e60367240b29c48d175942cef", "Name": "matter_g2_add_97", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000121fe97c62e068988ebff21d8129d52aa903afdbb62862c7fd99564d9ad72182ab1f3a1100223ae486cd76f6938e123f000000000000000000000000000000000968ddedb04f52140160061828b5f88dfd09aaf37df625ee6f66b9500d6608df31c7edf86296eccf8f9918b051a5e4df000000000000000000000000000000000b7491cb8f6252e3861d7160feb0afdd736d27886863ec0909a7cc711a9b71aace18b17a00a2999dd57ca1a74f148516000000000000000000000000000000000fdb280093ef45b12b694ca3390a865ee18e4c04b231e2c98cc28706d4cefaf4e654582ee03f34ecf1dfa9674489d55300000000000000000000000000000000185aefe71f24281e5b03dd41e6d6d45fbc8975beb175118de7568bff0a9ccf917e9df97dc26bca16e8da06b0e9a8e7bb000000000000000000000000000000000015b326d401b827fdf556e4a24a3dd6c8036b1c849751b5ae3c3728cad88f931b06e3a345523a723481193f7afeb67800000000000000000000000000000000054ca16b4c87293002c31e64ad303e8f040e11de8b45c5fb9aca9dbec59b29dfda8532a8ef5ae6a92ac8ea90ee4303e0000000000000000000000000000000000b65a233a7731366cf24c801724265215a8626b1290d86c60bf1e74b021b0b44d7d6552f936fac7b5e60cf1feaa1d82f", "Expected": "0000000000000000000000000000000010d1b2f595166929347e06c1debefead06334f554dc31f320cb844abdb1810b5f7c4b933ff8072dc03d303f4a6d0d09b0000000000000000000000000000000013ab41dfca0a7cb0c58c2c19e02f675a94d9e73312cfe2999dbac34e6a80bff9472506b48690f24ad3171ad495f445420000000000000000000000000000000015bfd0db53fd4da538caa3aee7a90a669cb84460365696ee79b190d09a6d4c3f08965de7fff4efeae435db52b97d213b000000000000000000000000000000000182ffc4304b911b47b092ab678edd63ed5f5e8a9069daf9247f3bf9c0dd149cc9992728a13b0a236fc9b37714b35882", "Name": "matter_g2_add_98", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010d001a09cf5dc3276482185f26ef3f75d28cd6d2667eb08a7fe06c03b99f3b6c4d82390739b6867a314291cc642a8b2000000000000000000000000000000000587846a460b1f37c2e7f491f9a097b4e86e1943d9cd0999313f65627b3907f09b5d5ac1be376a313a959dd136f7e9b3000000000000000000000000000000000af439695556e86b102926d3b40e3e54cc84464e120de3b4e3c5541a6a5bca44151fb0594009663764c1824518b13f020000000000000000000000000000000003bfd9418c1e57269e222152d321b83ae090f216cb422956dd1fcc464f68526cb4a05cdaefc7bbe6e81d4ffe27d64db400000000000000000000000000000000085dd8bfc00ba517dc8d7ddb49d711d35bd36f9fe3843689019e779624a032d2f023533b8184b73042d1a1953d2885e50000000000000000000000000000000009ba8d5d36e6efe02097a3206bbed68529f0cb9875ab81deafd886d9243bfec8b403d2abe713a2ec929b93305dd2da220000000000000000000000000000000007f8f90ebb2771136a92023901ca85e87fb7c8b1a40f88ae564a124bdd0ff0bc27ea98612a817e2c871fb4bcea3bb06600000000000000000000000000000000152de417d02f1d14e5899201db8fd5db8ecb40ea8d415dcdedce8ac70c28d851db68e9aef94506a50ec28145547a2d68", "Expected": "0000000000000000000000000000000017555399f979745302f08210de5311a6401b6b181100b3bc6b6d450f0f62079d2f02d7badcb164f50dfc46a975cbd6720000000000000000000000000000000014aea86c06e4c1fbf0711a8cfced2544c7624abc7ae7906cd992bdf575a702540c45c2117e221446ba09960cbc9048ac0000000000000000000000000000000002fac56960c4989a84e02ce36e8970c2e847ee45579d31ca77f042bf96505af574af822da084ae64b22ff876610ba9a5000000000000000000000000000000000a481cfea2aef8975c80a297ce5a185dacd25649d41f8466d3c63d786e3c264a8e4ccab5ef6b80ab1260e86ab6d5b3f3", "Name": "matter_g2_add_99", - "Gas": 4500, + "Gas": 800, "NoBenchmark": false } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/blsG2Mul.json b/core/vm/testdata/precompiles/blsG2Mul.json index 886b0c6adf3f..ee9d50fbfbc2 100644 --- a/core/vm/testdata/precompiles/blsG2Mul.json +++ b/core/vm/testdata/precompiles/blsG2Mul.json @@ -3,728 +3,728 @@ "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000000", "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Name": "bls_g2mul_(0*g2=inf)", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011", "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Name": "bls_g2mul_(x*inf=inf)", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000000", "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Name": "bls_g2mul_(1*g2=g2)", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000011", "Expected": "000000000000000000000000000000000ef786ebdcda12e142a32f091307f2fedf52f6c36beb278b0007a03ad81bf9fee3710a04928e43e541d02c9be44722e8000000000000000000000000000000000d05ceb0be53d2624a796a7a033aec59d9463c18d672c451ec4f2e679daef882cab7d8dd88789065156a1340ca9d426500000000000000000000000000000000118ed350274bc45e63eaaa4b8ddf119b3bf38418b5b9748597edfc456d9bc3e864ec7283426e840fd29fa84e7d89c934000000000000000000000000000000001594b866a28946b6d444bf0481558812769ea3222f5dfc961ca33e78e0ea62ee8ba63fd1ece9cc3e315abfa96d536944", "Name": "bls_g2mul_(17*g2)", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000039b10ccd664da6f273ea134bb55ee48f09ba585a7e2bb95b5aec610631ac49810d5d616f67ba0147e6d1be476ea220e0000000000000000000000000000000000fbcdff4e48e07d1f73ec42fe7eb026f5c30407cfd2f22bbbfe5b2a09e8a7bb4884178cb6afd1c95f80e646929d30040000000000000000000000000000000001ed3b0e71acb0adbf44643374edbf4405af87cfc0507db7e8978889c6c3afbe9754d1182e98ac3060d64994d31ef576000000000000000000000000000000001681a2bf65b83be5a2ca50430949b6e2a099977482e9405b593f34d2ed877a3f0d1bddc37d0cec4d59d7df74b2b8f2dfb3c940fe79b6966489b527955de7599194a9ac69a6ff58b8d99e7b1084f0464e", "Expected": "0000000000000000000000000000000006334ba1e361fd94bbd98f44b75ae9ec00ecb4d3467b5528870b1a1fa9a7d04449f12af90bd4c7a1e3f29e717d6d19d3000000000000000000000000000000000bf4cc1626393956915845ea7ca43d30a59c7196fbe309f2d5ee6de7e40c191d29821dd6aae46abecf634b904de8f7490000000000000000000000000000000014aeb09e252cc74610ab956057d4ac5af95cbea8a6baba9e5062643dc037d6841044cb38b22d7dfb978fe0b58f94cc3a0000000000000000000000000000000000fdcd73452fc1ced1c06e6271410a48dea05afbe889a692905e1baab8d72418c62531aab8b74842b51016f0a9cbb93d", "Name": "matter_g2_mul_0", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018c0ada6351b70661f053365deae56910798bd2ace6e2bf6ba4192d1a229967f6af6ca1c9a8a11ebc0a232344ee0f6d6000000000000000000000000000000000cc70a587f4652039d8117b6103858adcd9728f6aebe230578389a62da0042b7623b1c0436734f463cfdd187d20903240000000000000000000000000000000009f50bd7beedb23328818f9ffdafdb6da6a4dd80c5a9048ab8b154df3cad938ccede829f1156f769d9e149791e8e0cd900000000000000000000000000000000079ba50d2511631b20b6d6f3841e616e9d11b68ec3368cd60129d9d4787ab56c4e9145a38927e51c9cd6271d493d93884d0e25bf3f6fc9f4da25d21fdc71773f1947b7a8a775b8177f7eca990b05b71d", "Expected": "0000000000000000000000000000000010e70bef8eb893377e7ff92168d7acef11c9efab990fbded728b173b94e1d99e471a8357f16625d353287086543551850000000000000000000000000000000014043c1f00221c439e5febd12724a9224bccf0389914461644daf329208e869b1bf149880dccebccd440b1748d15e944000000000000000000000000000000000f7dee1e7d122e410b29a9eb011ee700c2f230cf8f611e196ec66e153c1fc331175532a8f9b060b573bddaa705430c2e000000000000000000000000000000000e1f659470eab7c0741bc8777ac9fc8dcd11a6f1b30ffb4265e96b879e795a4dbf851d1149429dcab95464e89f334627", "Name": "matter_g2_mul_1", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003632695b09dbf86163909d2bb25995b36ad1d137cf252860fd4bb6c95749e19eb0c1383e9d2f93f2791cb0cf6c8ed9d000000000000000000000000000000001688a855609b0bbff4452d146396558ff18777f329fd4f76a96859dabfc6a6f6977c2496280dbe3b1f8923990c1d6407000000000000000000000000000000000c8567fee05d05af279adc67179468a29d7520b067dbb348ee315a99504f70a206538b81a457cce855f4851ad48b7e80000000000000000000000000000000001238dcdfa80ea46e1500026ea5feadb421de4409f4992ffbf5ae59fa67fd82f38452642a50261b849e74b4a33eed70cc973f40c12c92b703d7b7848ef8b4466d40823aad3943a312b57432b91ff68be1", "Expected": "00000000000000000000000000000000119a5147fe9ddca7123f721b5662c1a44b0964c37a214cdf3a4fd34166e3b25210344e65220c38ec84d0e3b5ccc7e46d000000000000000000000000000000001642dad5dacf4295b871fe9b2787f0861f158807b2b6c01c2dce12ab053c9472bd3cb98de5dc33f40053ff45ce5c9af40000000000000000000000000000000005bb5761602b6639f2ecaf79f2d1f853fbdf75f4b3852b90808b858993a83f8a0da8a2ce7072aa91e3b6b3ffd0b3d1e20000000000000000000000000000000000a75143b9551d4ae41fb8bd71fdba7826b994c65904d9189a5ac5130a59cbb9d8dee0e016735565148fc49823d3969e", "Name": "matter_g2_mul_2", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000149704960cccf9d5ea414c73871e896b1d4cf0a946b0db72f5f2c5df98d2ec4f3adbbc14c78047961bc9620cb6cfb5900000000000000000000000000000000140c5d25e534fb1bfdc19ba4cecaabe619f6e0cd3d60b0f17dafd7bcd27b286d4f4477d00c5e1af22ee1a0c67fbf177c00000000000000000000000000000000029a1727041590b8459890de736df15c00d80ab007c3aee692ddcdf75790c9806d198e9f4502bec2f0a623491c3f877d0000000000000000000000000000000008a94c98baa9409151030d4fae2bd4a64c6f11ea3c99b9661fdaed226b9a7c2a7d609be34afda5d18b8911b6e015bf494c51f97bcdda93904ae26991b471e9ea942e2b5b8ed26055da11c58bc7b5002a", "Expected": "0000000000000000000000000000000017ebc9446f8c8e17dfeddab9188d0c808565da29c0bdbbc4138a44ca3196c4564853be28286b66660cda36832d6940010000000000000000000000000000000007f29a9583b4ae83d3913dcd72590a3f20f39eb5a6d36663c1ef433058e76550085b9c01bf797d98d0eef45cc22ff8c50000000000000000000000000000000016eeaeb123b12d1913ff1e50f974228c79f2b995609d2e3835c8e1d68773b0cd484df57b86111cdb75de1e19eaf062e500000000000000000000000000000000002f5688c1286aed42309896bd65d1826dc64dda615238fa9043669806968b8e0e1e3e77ef192b7df540aaf0ed282a9a", "Name": "matter_g2_mul_3", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001156d478661337478ab0cbc877a99d9e4d9824a2b3f605d41404d6b557b3ffabbf42635b0bbcb854cf9ed8b8637561a8000000000000000000000000000000001147ed317d5642e699787a7b47e6795c9a8943a34a694007e44f8654ba96390cf19f010dcf695e22c21874022c6ce291000000000000000000000000000000000c6dccdf920fd5e7fae284115511952633744c6ad94120d9cae6acda8a7c23c48bd912cba6c38de5159587e1e6cad519000000000000000000000000000000001944227d462bc2e5dcc6f6db0f83dad411ba8895262836f975b2b91e06fd0e2138862162acc04e9e65050b34ccbd1a4e8964d5867927bc3e35a0b4c457482373969bff5edff8a781d65573e07fd87b89", "Expected": "00000000000000000000000000000000042d0c1941ae0ed5e8787437ad5e2753bba02185317848e8ec2e425ac954e0efb1bca534725adfe87e8507851ee337af0000000000000000000000000000000002db55ae8126cbe86327aab880381a81205e33a351d172c883b9cc184799866a8db5a6b4321496e05d3ef62d00416d9a0000000000000000000000000000000012c45444403dd62d7be3e7658dd85909204751dd7d085f6edd38c0aa9185d3c32407d8c95bba371b380f788d0dc48e0900000000000000000000000000000000111421c6dd0db595ab731adfb4bc76c84a61197cb023b6f17e7176c443f20a4b6f8cd0a00cfa61e831ed20b3c6a84d98", "Name": "matter_g2_mul_4", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019c31e3ab8cc9c920aa8f56371f133b6cb8d7b0b74b23c0c7201aca79e5ae69dc01f1f74d2492dcb081895b17d106b4e000000000000000000000000000000001789b0d371bd63077ccde3dbbebf3531368feb775bced187fb31cc6821481664600978e323ff21085b8c08e0f21daf72000000000000000000000000000000000009eacfe8f4a2a9bae6573424d07f42bd6af8a9d55f71476a7e3c7a4b2b898550c1e72ec13afd4eff22421a03af1d31000000000000000000000000000000000410bd4ea74dcfa33f2976aa1b571c67cbb596ab10f76a8aaf4548f1097e55b3373bff02683f806cb84e1e0e877819e2787c38b944eadbd03fd3187f450571740f6cd00e5b2e560165846eb800e5c944", "Expected": "000000000000000000000000000000000ccdb2a0b670f199a9b61198e6a2ce2117075733e6a1568c53ca493dc3674c6ae85be2491d2ed983f52e2c7040824afc0000000000000000000000000000000004f52450d7e041c561c00200d5b142b32f2df2e2156e4f6c15d6c00e185e135037a1ed6be15e2ed920daa00e2f9bc8da000000000000000000000000000000000f39c38c18f03ce6baf1d016cf32d7387269940280f2e8d21db4da33dbd2d24ebb93ae3dff9f79b015eee25813d677c700000000000000000000000000000000189df61f7f1025fa6fdd0a4708ff1d53db7d414019c4828de2520af3d36776062350061c2261e46e746a6475fdeccb2b", "Name": "matter_g2_mul_5", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000147f09986691f2e57073378e8bfd58804241eed7934f6adfe6d0a6bac4da0b738495778a303e52113e1c80e698476d50000000000000000000000000000000000762348b84c92a8ca6de319cf1f8f11db296a71b90fe13e1e4bcd25903829c00a5d2ad4b1c8d98c37eaad7e042ab023d0000000000000000000000000000000011d1d94530d4a2daf0e902a5c3382cd135938557f94b04bccea5e16ea089c5e020e13524c854a316662bd68784fe31f300000000000000000000000000000000070828522bec75b6a492fd9bca7b54dac6fbbf4f0bc3179d312bb65c647439e3868e4d5b21af5a64c93aeee8a9b7e46eaaee7ae2a237e8e53560c79e7baa9adf9c00a0ea4d6f514e7a6832eb15cef1e1", "Expected": "000000000000000000000000000000001388a59c57ec8ca5e68b99631abdafca1b71352ac35003a55bbc415b48b8171857adda31123ec86a6ed9e1060d56aa67000000000000000000000000000000001471913b1ab5bcf9336665d3d44232b4e58da70285b7b8eb1dfd7c54442afb28c339f56e6389f89b84db0879e1ee058300000000000000000000000000000000022101b4de40b7180ea17bb36bad0a668a8def3e7361a96fbfabcfc4cdbe6f607ee4ee80d0eb2418b848ad056520092900000000000000000000000000000000103cda694792af5a51e04b6422600a0ea6f50808ca54423cd4f59dfba633daa5afea49c85b900f52e182610efb62fe7d", "Name": "matter_g2_mul_6", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000690a0869204c8dced5ba0ce13554b2703a3f18afb8fa8fa1c457d79c58fdc25471ae85bafad52e506fc1917fc3becff0000000000000000000000000000000010f7dbb16f8571ede1cec79e3f9ea03ae6468d7285984713f19607f5cab902b9a6b7cbcfd900be5c2e407cc093ea0e6700000000000000000000000000000000151caf87968433cb1f85fc1854c57049be22c26497a86bfbd66a2b3af121d894dba8004a17c6ff96a5843c2719fa32d10000000000000000000000000000000011f0270f2b039409f70392879bcc2c67c836c100cf9883d3dc48d7adbcd52037d270539e863a951acd47ecaa1ca4db12dac6ed3ef45c1d7d3028f0f89e5458797996d3294b95bebe049b76c7d0db317c", "Expected": "000000000000000000000000000000000cf5cb957a752ce9187940f63b13080790348814debf84b91e74fd6e822c2735941d61d50d492439475bb3ea7aa849ec00000000000000000000000000000000012e546ff33dee9875510a68301f46d89e6175f5cd9a6e179fb8599a580e9478fb8d92038982551dd29041d8185c7474000000000000000000000000000000000d52fb57bf2996dbbacdbcb4088df38e77e25598b91bcd5e41eaa27b1398eac150586b142f068d5b498e0ce458d3e8950000000000000000000000000000000012295e1d1039abe7a5fea51a04a34e9e8d44a0f24b8c032680703c119d54274d3bc2e548854021ab027b693e43964314", "Name": "matter_g2_mul_7", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017fae043c8fd4c520a90d4a6bd95f5b0484acc279b899e7b1d8f7f7831cc6ba37cd5965c4dc674768f5805842d433af30000000000000000000000000000000008ddd7b41b8fa4d29fb931830f29b46f4015ec202d51cb969d7c832aafc0995c875cd45eff4a083e2d5ecb5ad185b64f0000000000000000000000000000000015d384ab7e52420b83a69827257cb52b00f0199ed2240a142812b46cf67e92b99942ac59fb9f9efd7dd822f5a36c799f00000000000000000000000000000000074b3a16a9cc4be9da0ac8e2e7003d9c1ec89244d2c33441b31af76716cce439f805843a9a44701203231efdca551d5bbb30985756c3ca075114c92f231575d6befafe4084517f1166a47376867bd108", "Expected": "0000000000000000000000000000000008e4c57309339400ac9b6b5df16972c272d47cf69ba7baf89afa4f4e72703999c5885253cc35686f6c8d277399da2a390000000000000000000000000000000018ad4e1f105f16b0dbb4eb089c51e709c25e407e54b64346224b1abbe15d62fabb231e36a69eb05a9ba7860f772634200000000000000000000000000000000019994d20a7ecc0f234ccb6b1793fa7d1ece64b3e157c579fb05a8c6cfcdd6f5456ac1f4c1beadb69206988ab543bb8bb000000000000000000000000000000000d435e74bed382442ab83ec90dffb91336137932524bfcf9753fa5ddfe038d0b98a045c8ec9deb53172e5662d3fd67e6", "Name": "matter_g2_mul_8", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e25365988664e8b6ade2e5a40da49c11ff1e084cc0f8dca51f0d0578555d39e3617c8cadb2abc2633b28c5895ab0a9e00000000000000000000000000000000169f5fd768152169c403475dee475576fd2cc3788179453b0039ff3cb1b7a5a0fff8f82d03f56e65cad579218486c3b600000000000000000000000000000000087ccd7f92032febc1f75c7115111ede4acbb2e429cbccf3959524d0b79c449d431ff65485e1aecb442b53fec80ecb4000000000000000000000000000000000135d63f264360003b2eb28f126c6621a40088c6eb15acc4aea89d6068e9d5a47f842aa4b4300f5cda5cc5831edb81596fb730105809f64ea522983d6bbb62f7e2e8cbf702685e9be10e2ef71f8187672", "Expected": "000000000000000000000000000000001425890b6c46c5a07a79127de4ddbb751227dca4481ab7c2f601bf22b8f6a149767c73bfbf57ee399c0f2d0b12852a0a0000000000000000000000000000000012cce15f53fdfffb5f71de3567b0c0adea65b9321c85677c574787f7048c1bb5e2dc985b65fbc48115aa129e6000fe4100000000000000000000000000000000041398497f975289fb9fc6ffe671a19fdcd3753c82ffd3b2084574107bf7fadc8de462507f4484c32df39967c3751a480000000000000000000000000000000007514a7f246006e714d4a8cbb4e89d81b951b5c41a05bcf35f61283e888074fb3686fb6ecc1a66e491ea1e1ce0738102", "Name": "matter_g2_mul_9", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000159da74f15e4c614b418997f81a1b8a3d9eb8dd80d94b5bad664bff271bb0f2d8f3c4ceb947dc6300d5003a2f7d7a829000000000000000000000000000000000cdd4d1d4666f385dd54052cf5c1966328403251bebb29f0d553a9a96b5ade350c8493270e9b5282d8a06f9fa8d7b1d900000000000000000000000000000000189f8d3c94fdaa72cc67a7f93d35f91e22206ff9e97eed9601196c28d45b69c802ae92bcbf582754717b0355e08d37c000000000000000000000000000000000054b0a282610f108fc7f6736b8c22c8778d082bf4b0d0abca5a228198eba6a868910dd5c5c440036968e977955054196b6a9408625b0ca8fcbfb21d34eec2d8e24e9a30d2d3b32d7a37d110b13afbfea", "Expected": "000000000000000000000000000000000b24adeb2ca184c9646cb39f45e0cf8711e10bf308ddae06519562b0af3b43be44c2fcb90622726f7446ed690551d30e00000000000000000000000000000000069467c3edc19416067f572c51740ba8e0e7380121ade98e38ce26d907a2bf3a4e82af2bd195b6c3b7c9b29218880531000000000000000000000000000000000eb8c90d0727511be53ffcb6f3b144c07983ed4b76d31ab003e45b37c7bc1066910f5e29f5adad5757af979dd0d8351d0000000000000000000000000000000004760f8d814189dcd893949797a3c4f56f2b60964bba3a4fc741e7ead05eb886787b2502fc64b20363eeba44e65d0ca0", "Name": "matter_g2_mul_10", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f29b0d2b6e3466668e1328048e8dbc782c1111ab8cbe718c85d58ded992d97ca8ba20b9d048feb6ed0aa1b4139d02d3000000000000000000000000000000000d1f0dae940b99fbfc6e4a58480cac8c4e6b2fe33ce6f39c7ac1671046ce94d9e16cba2bb62c6749ef73d45bea21501a000000000000000000000000000000001902ccece1c0c763fd06934a76d1f2f056563ae6d8592bafd589cfebd6f057726fd908614ccd6518a21c66ecc2f78b660000000000000000000000000000000017f6b113f8872c3187d20b0c765d73b850b54244a719cf461fb318796c0b8f310b5490959f9d9187f99c8ed3e25e42a93b77283d0a7bb9e17a27e66851792fdd605cc0a339028b8985390fd024374c76", "Expected": "00000000000000000000000000000000048ea2c854a0df7b10a2147db6eabcb16eba340644f737fc99663d1ef26d8ed688c2baaa7d7699c5f540d7605eb48485000000000000000000000000000000000c959efb835d48d3e7a8ce643764f27c365f6248a88e39092e3a6498f04ed851c55b796dacd62ae73d7edf23aa45fefc00000000000000000000000000000000114337b8caa68cea6f22a25c0ce3b247cadae24c63fb02c6a98a728b54f97b12b1473c8e23f55338326b9575a637bb2e00000000000000000000000000000000033167b0668ec650581815cefab61d13661f4cbc6e01711af0aefb699e1979b551d0031c603ee5f6dd4f716ea7aa4a6e", "Name": "matter_g2_mul_11", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000576b8cf1e69efdc277465c344cadf7f8cceffacbeca83821f3ff81717308b97f4ac046f1926e7c2eb42677d7afc257c000000000000000000000000000000000cc1524531e96f3c00e4250dd351aedb5a4c3184aff52ec8c13d470068f5967f3674fe173ee239933e67501a9decc6680000000000000000000000000000000001610cfcaea414c241b44cf6f3cc319dcb51d6b8de29c8a6869ff7c1ebb7b747d881e922b42e8fab96bde7cf23e8e4cd0000000000000000000000000000000017d4444dc8b6893b681cf10dac8169054f9d2f61d3dd5fd785ae7afa49d18ebbde9ce8dde5641adc6b38173173459836dd994eae929aee7428fdda2e44f8cb12b10b91c83b22abc8bbb561310b62257c", "Expected": "00000000000000000000000000000000142f6b71471f3665ee6269cf598fc3587a62523f9753eec48a2461a2e313e376828cf6d1a9ffc9e64353c8a668718736000000000000000000000000000000000153647cc4a5aeb8ea52f845c415651e167ace9f331c1d73eccbbe20a4014f9e1158c281495206de4b841839438a595500000000000000000000000000000000151d07c3f83217e63b332a6c47e91ef2418e9c658353f8b644f23266f5fbc727562f0935b4d892db947cfbd0757ed61500000000000000000000000000000000035bce4bd2d8261e21476c325cb68e581f20513eb5e0e6a0ddbfd4ac4674bc323590b6f52d0cd50010c13642e7e03daa", "Name": "matter_g2_mul_12", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ca8f961f86ee6c46fc88fbbf721ba760186f13cd4cce743f19dc60a89fd985cb3feee34dcc4656735a326f515a729e400000000000000000000000000000000174baf466b809b1155d524050f7ee58c7c5cf728c674e0ce549f5551047a4479ca15bdf69b403b03fa74eb1b26bbff6c0000000000000000000000000000000000e8c8b587c171b1b292779abfef57202ed29e7fe94ade9634ec5a2b3b4692a4f3c15468e3f6418b144674be70780d5b000000000000000000000000000000001865e99cf97d88bdf56dae32314eb32295c39a1e755cd7d1478bea8520b9ff21c39b683b92ae15568420c390c42b123b7010b134989c8368c7f831f9dd9f9a890e2c1435681107414f2e8637153bbf6a", "Expected": "0000000000000000000000000000000014e83f87e7f66d8ed880ca46a76a5d3bbbacf2dafe1ee055f04af568738f4c6ddf2a93e1810b616da6f64f25c35a7b5a0000000000000000000000000000000003d14447254b61168d36f92710f95f7100cc8f278b0bc9528da763a18a5386b3f5b83b96f4dc426e4b0fbe755bc986790000000000000000000000000000000017f1a79ed64abfe5e960fda02cf3330e6ef5612c1b8639386959f86c970adb797bf077a468273d37996a65685f75ac30000000000000000000000000000000000d973499a7bf7132541c0976bf2e9bb26a2b6cfa5bda720352fa7a180a6b8fe95befcc13de5a2efe58be934cf7d8e664", "Name": "matter_g2_mul_13", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017eccd446f10018219a1bd111b8786cf9febd49f9e7e754e82dd155ead59b819f0f20e42f4635d5044ec5d550d847623000000000000000000000000000000000403969d2b8f914ff2ea3bf902782642e2c6157bd2a343acf60ff9125b48b558d990a74c6d4d6398e7a3cc2a16037346000000000000000000000000000000000bd45f61f142bd78619fb520715320eb5e6ebafa8b078ce796ba62fe1a549d5fb9df57e92d8d2795988eb6ae18cf9d9300000000000000000000000000000000097db1314e064b8e670ec286958f17065bce644cf240ab1b1b220504560d36a0b43fc18453ff3a2bb315e219965f5bd394c68bc8d91ac8c489ee87dbfc4b94c93c8bbd5fc04c27db8b02303f3a659054", "Expected": "0000000000000000000000000000000018bb69dd6db0beb468242265c382de5ac342d465b5f72d4e5a24c67a48272d9a1f3af28e0bd3712e16a854c5d91c616b00000000000000000000000000000000072fbcc86b7dee9c2dc177dbabdbbbddb630c98ac3bf3737fd22f99e2b2b690175d9c5aa4b577f78c545dc6a5d2d03c900000000000000000000000000000000161c4218143ab1f0387f19bccdcd08f9caeb2d1331ca890741799ff1b40533076b6a96a910714176c770b25d2c17715300000000000000000000000000000000063098cd9d1eeb899724b40a2d10ac951ba0277db09aad639957f58541dd391fffadc5d97833bb9666b054e12debfa92", "Name": "matter_g2_mul_14", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000018244ab39a716e252cbfb986c7958b371e29ea9190010d1f5e1cfdb6ce4822d4055c37cd411fc9a0c46d728f2c13ecf0000000000000000000000000000000001985d3c667c8d68c9adb92bdc7a8af959c17146544997d97116120a0f55366bd7ad7ffa28d93ee51222ff9222779675000000000000000000000000000000000c70fd4e3c8f2a451f83fb6c046431b38251b7bae44cf8d36df69a03e2d3ce6137498523fcf0bcf29b5d69e8f265e24d00000000000000000000000000000000047b9163a218f7654a72e0d7c651a2cf7fd95e9784a59e0bf119d081de6c0465d374a55fbc1eff9828c9fd29abf4c4bdb3682accc3939283b870357cf83683350baf73aa0d3d68bda82a0f6ae7e51746", "Expected": "000000000000000000000000000000000e43672f1bc25e7e0e64a3fd26cb246bdbd6fb5c9084afdc87c888634916e6a6cc9a351cc67a6ac77ab8e132ed6cbee3000000000000000000000000000000000dee9612527c8ee9c574a4c51f5d3504ccf1d5781b59c78ea15294332c6acfdcc7bc68853e70f1f72524c930e4c3d2eb0000000000000000000000000000000017eba629eb14a0636926275f1c2109318ce8818d8171c69fd371751b6de47bda5b00a0b0e3765d05bab7b8dea9add90900000000000000000000000000000000052f0a4cd9b91695e1e58ead1da1480fef08cecef63896aa51ab16da373b99b3b91767a374645ac5932d9c7fd21d4636", "Name": "matter_g2_mul_15", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000000eb3c91515d4a41209a73564741a8ccf901a624df9db22e195a5d02d24b7bc0a12756b15b8d006cb991a7e088eaef1000000000000000000000000000000000704ce8afc808b0161f6f61b22d990d713ae398779e6e74e9b5771daf006ce0bba3a8088edf75156f0e48b92ee8409b00000000000000000000000000000000018fe81e05aff0620f4bdbe4a715e015650497afab62921eba0ab86b649e5a2fd3d54041868928519f537e36448688a0d00000000000000000000000000000000162bd97161201ea3c26f8dd1204a9c6b61b762bdf573cb5d20b6b255f30208ca7d96aa47b46fb8c6bf0922075f1c1ca807f80a5e502f63375d672379584e11e41d58d2ed58f3e5c3f67d9ea1138493cf", "Expected": "0000000000000000000000000000000019b7ea673dad96c8352870136ea262c9ed105550cb403eb1e64ad598b2145fe1b95e5d61f1b5a6ebec47568c67b68086000000000000000000000000000000000f06ff9bcf2ba284e705b12ef2311f1a9b867ed742ee0737567b5c878547b18394b82c2bb97e16586515728245692cef0000000000000000000000000000000019dfd2d8fc4f2c989c7e1016e147f336174c84d380bab992bf1adbffe96d93d4d2d1d1dacdba3adfaf283b184478229800000000000000000000000000000000068d230422006004cd88ab0dd46a84af3905c7a1d329446cc23c1c5adb401a86a9fa76aaf577f77c2678cd8de8685ed4", "Name": "matter_g2_mul_16", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000135aee0e30fbcad798738c10d4aebcdf50c89ce516325f655fe763dce54ffedf94dd74168611e5ae879b5bf5598d62dc000000000000000000000000000000000c728e672cd8b3bf9341bca929c34118b566cd3a80452d7015bee9d5cdc001b1f5c678d4b2cc4f7cac353e7bf326ca1e0000000000000000000000000000000014809aa22e2051e463fba6d49fbb060d0c7f599a0fc5409d34e71f34817e7beb1251810ae6eee1848c60796fb8647dea00000000000000000000000000000000145a4de777d86025d50e12f9a6615ecb9bdd41489992d1b643dd9aa549acbc63b04b0bdfd14b6e45c70f165e9a8c91bebb169138f94093d5c1c6b253cc001ce8baf78858dae053173fa812d2d1c800da", "Expected": "0000000000000000000000000000000015ffdd83355978ebfc386e13987effac0137ec628fff1667ede29cfcbd05e31cf8323959dd0247c20cf28978dc242c790000000000000000000000000000000016b1f810da2ae3c2ffbb6b83c47ef03eb0f298ff4c304ab0dd7b97207949d62858458d789c86c0cd474c34fa720ad3b70000000000000000000000000000000002a2e1463d5e795e6a25998a848b079363efc7d0337c3803385f4f17f11726b04108adfd87a811d709cbb6750c969526000000000000000000000000000000000289a3f472799c06a84bb1f377a36bad910220e1017884545159fe1b2505e8e7473882fcf324ba0d9125495bcbbc7226", "Name": "matter_g2_mul_17", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000009a58b7116dbd6f550f8ca98071813130ecaa9ea86d5275eebc36860690fa048c9ebeb46600b2b63e847bff3e38ed0d00000000000000000000000000000000113ffc0932c041e0e34b2540c485eb74f5029b339cb60bc88a8a749310f33f330dea137e5f340044fd689264af66696d0000000000000000000000000000000002642da3c2c7b6688aba0b19ab29ac72e35caafa044863c364ea8833fca850289de52c0963bc33d7bba40cb5f568718a000000000000000000000000000000000552d35ca054da2f148c119454f6760607b351f2441921a2be17da2cc10902d71571c5554f132e60df79679428fa07e3e40608bdaf3e7764358a64a920cbb33ab4d571c7b3092e1ae11d9697f82ed833", "Expected": "000000000000000000000000000000000b02ddcfbf391a2d6953261c786945093b09377352473a86cfac6456a811233809434b566b9301eea3105eb86922efcc0000000000000000000000000000000015430deba91113b841303120f0738012d77207e9408474998df5e68d0d61f1a64afb947ff93116ae766ca5325046e263000000000000000000000000000000000ab7094055919f6f707b458cda552f25104d95e4ec8d020ea4c17ac1d7efef5c4c3a769120718f1d5171eb8630a3018200000000000000000000000000000000161e7209f8c98e511a698fbf01735798cb632ae1afe00870654ffa0ba93a549edf4b97d60f03974ab0964cd39298401f", "Name": "matter_g2_mul_18", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018fbbcba3d4b1e548ceaec4a48db62a2420ff29a67af332ee7ea3f902f84e6c375fd33abc33d945c5bca25603979f9a400000000000000000000000000000000072ff416994364bdc6535f36c82212afa822cd94fade69f11eb38dbdcd37c7e22af55fe05e6a826dad822073656eaac10000000000000000000000000000000017bba179b847278a4878b6faeaab3b1f4bd7540d22817cd9aff95557497f8b9d286657b6162c0f89f7820becc637dd550000000000000000000000000000000018e2bfed71aa9b11fefca2f0db8bd9b8c69540267de50bec4fc90a6e9741891465c9761d19282e1100b3707eeb598b31d411519f2a33b07f65e7d721950e0f0d5161c71a402810e46817627a17c56c0f", "Expected": "0000000000000000000000000000000006cb218607a1f66ce361c89fd20edc3f00421611adc9aa52ec35d45e023174962c863f740ac36c984c2b466cfc4827a900000000000000000000000000000000152b22d46e9660da8b1be4c5b14da613731e750ff7eebaf879f7074bf3c33e1528a2c8479e0178707e3855b49f85f045000000000000000000000000000000000c928cf78cee2c8b9da8215d33d189c5636df1e8e9bdaf143aba7ed40f29490ca2328b4a20cfc56f62e4ce49d9e77f14000000000000000000000000000000001574b7a9c3931933160ad4eb17400b6297210db47bca034bc1b5d17a0cb8c41834636b9123e625e5eb0b01738cd6b9af", "Name": "matter_g2_mul_19", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019efd37727dfaedf697fcda7a59847dbda8ca7cdc92f34e68691d682e20ae6545ac104d6660fdb8f64a051e69298eae8000000000000000000000000000000001225ace0fdce456dd888c9672503b68ef77b2d11caf1265a767a6ea14911e3ca03fc153f18dfe9d95e0cc68b7b8a3a8d0000000000000000000000000000000008a6b059c1c4da046cc0b1b5d7f33270aceffa607daf6d0d078c06f940604e1a0b4adf01a4091306e3c7eddcf3d95101000000000000000000000000000000000f79bae5260a2f114ffbb9273f3049d3ebb002500a57ee0a7d157d86957f43f87a2e026fb9892dacaadca5ee04fc8e176bb3f9e512311699f110a5e6ae57e0a7d2caaa8f94e41ca71e4af069a93d08cc", "Expected": "0000000000000000000000000000000003e17452a80996203fdc4037db072c452f9eb2dae689c77c88b299d7ba266d111ab2b9c4b24149968d72cd143a34fc4e0000000000000000000000000000000014a057d7a50c9b0f34712ff8008770080bfa671650fef43c82726257da180dfb9672b266d4c54d65fdc677d917e6c5b80000000000000000000000000000000013b452c980bfc4a484637b578be100753aee9dda9487d5ee5c017c689dda838fc673804369328192d780d60a9a3de0f700000000000000000000000000000000103aa86d1807de242a6d4fa4a49be6c91cd757df5808501acfca44940733c6a524b851ac962b99a9be41bfc8d6254478", "Name": "matter_g2_mul_20", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000016d2b73eeceee17d3bff3aacac9df9ac1c4248d9ea7d6a503a757f7bb22fa6970bb6f5cb5ec154785f7252e1508b382e00000000000000000000000000000000081edc68bbd8db7b10be06ee23d090bd54f9ca07ef24dfed7df7bb05f8cc26e6889dbd40ea203fd5cca5cb588199f9e40000000000000000000000000000000010d3478508619ea9493b4330e2fb9150024cd32dc1378f824788a884a4a30fbf39c630f465557bf0c6d69b4cbecf89f9000000000000000000000000000000000f20c9b134db5d8b7756800c031bf5962fc560ba95d4bd9157b16179f1a37ae08696a2be455ad8d018aead6adcc69b712a0c988d97e86dccaeb8bd4e27f9e30fad5d5742202cdde17d800642db633c52", "Expected": "0000000000000000000000000000000007c616472f9ac60f749979c6f870b587425d514395ed07558ed287fccabc77f0c90872f3885d0780bcdfffedd124eb3d0000000000000000000000000000000019531e9c25e84a2a968a85d9f1ab61a372ebc59ba5bb7a2bbb3c0d6e4c9d04061b28fdc719735e97ccd5f7243a58cdc70000000000000000000000000000000007772d3cff12bbee916a6569edce0c6dbc2bd8a794919a4dd7bc37024c8273245210511b8f6da551fe626b7b840833f300000000000000000000000000000000186a3e858a83a7ea1bfdaac65c2df1076059aaa193961559792373886c68acd2f9fca61b166a0ee55084a6ea122ec3e8", "Name": "matter_g2_mul_21", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003dce67181d23af9729e9fb0653d7f79c890fba27de42fada93123e112c4a468fa889921192db8047d86e4db77c60266000000000000000000000000000000000869a1e39d42d9bb0cc0568fdad16abbdac3194af893ebd8dd8f8c2c3c855abefa5fc215412168acadc88e658e83f5570000000000000000000000000000000001ef139a75194f3c4b1378c2b66dd304d179460bac0a289405cd8faa3ff66a7b6e54eb7b8742a68150b1e098630135c40000000000000000000000000000000003892b5a645af916be2c6c7fc0bb08fb5f39341d3c68598940554e1be11e1be75af920db0c8710ed13c78edbf683f17d0b299c14892e0519b0accfa17e1a758c8aae54794fb61549f1396395c967e1b1", "Expected": "0000000000000000000000000000000008adebaa95d10b9fc0f1a1f0d52dd6741517d2ba23e3f9e7a9221039684ae226ea602dbb50df0efd44b2b5bf7495c0b50000000000000000000000000000000008e276e78ead2473602d37cb9f2f589f9c60514a1fc5c215acf487bf57c935467d29945d3d671b41a8e47c9495dbf5c9000000000000000000000000000000000fab06240cb8cbe9afcc4ebebde50c2881e4bc4d4f2ed09a1065e3620e6344fb3c5f3019250ca4edaeae4902abb7400d0000000000000000000000000000000003fa6c48ead374be1dd45c8417ca8234c15ddefc5039151e6cd7fb27f866e134cef2f59ac9b2ec1b26896eaec9213549", "Name": "matter_g2_mul_22", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000264dd4b477f5db65edad28c7153ed919a863c5c5661e0125c5429b323e055fd69c33142dfc6ed9c87082e2be4675e1f00000000000000000000000000000000046ea088a2ec94d3a1f1f97949f1ebc49690c453d316cc46534fa253b34b30323b6071d147d64bb94e02fb4db07bb0c400000000000000000000000000000000013692a33bb1348486eec40a9e93a4ea3810c7b4d3188cd07e235a2c898aa87ee0d17682fd24f4d978f9fb028fd26e2900000000000000000000000000000000115f8b64c00cd5cd344a7b5edc0ef0bb85a3e8f0f9dfb28f8ffe12db3e0d222c2d45dcdba0fbdc161c5d558bc71aa0977064d43d6802ad4c3794705065f870263fef19b81604839c9dea8648388094e9", "Expected": "000000000000000000000000000000001412bdb48546014adf3c4eac4dbe79ba700f90c8030b063828fb01be5977bd73107533a4e8030c8d9cbdde9bcf10649a00000000000000000000000000000000126d3e1006abfeddd810cb1e12c898cf5f543e414438e600ce4c94cd8dbd1e17c0f3b9831add397feda74362eeace6fb0000000000000000000000000000000005b3159638afa34f219513cbcbc51567b16fd5598b85e6ae0d232021133cec25a6269250df2ab7b5ace726e9e2fbf0b0000000000000000000000000000000000c35bfdd1c10e903da6d41e9afbe65b0cd66addd7893fde41dfda8e543a93938cdeab52cc9bbdbe61f93d651bd1c923d", "Name": "matter_g2_mul_23", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000014c83d58d90db4821a0411fab45f83fbc05f7d0d7a67ce75da3ae568978d15f4c1886c6fa6086675c0045efb30d818400000000000000000000000000000000001e68691123451f4c3df6dae62c6a63855ec3597aae33a8a10ee274e902e9aab1460cc9c79726312df0ee0ce90c8d3c00000000000000000000000000000000018a39eb3e3c6c7fb8ee304e55d15e209afe2fe278dda93552a7b9f51fbd778da1502eb6775cbc3f832f8320fa0686240000000000000000000000000000000017c15910fad1ca5749aa82a5a2fa98b0ebb37e92912547fb1741f18c34e0d5fc3a307b928636c25f0320d71cb9d31062686285a0e22f177fe3adbfc435e9c1786752dcf3c11b723539789b0cdeb0647b", "Expected": "000000000000000000000000000000000bcc781f144bc148687875789fd8c54dd820170984b6f8ae75855f7e45619c1d2ff85c330b7743e447b5fc831dce9277000000000000000000000000000000001409aaf3c94c9a6b5123c82a7f311af7c2f60e9b197d49fb5b010f84faff972151b383a83c106de43454f8097005f6c800000000000000000000000000000000064a91226da8b9cb587030f1f4afb0d422a51e4d55212f26c621abc06fc0c57a473a9be75518a5f4f9a7f8d4aaba69830000000000000000000000000000000002cf239343bb77865ceabfcc1fe34cc9be4a1ebc3a70f16f8b7cb84eed5843524f95673b01466d6cbb0d8d9dc00793e6", "Name": "matter_g2_mul_24", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000fa96d9fe01c18732e8d6454df9bb1f482c4b9add837ce9c354c72d49c2d44ec694674aaf0e6d6a095cab7ebb57ccd9a0000000000000000000000000000000001f8ffe3fb7e9e311e0f6949c07c26a0febb181e37b2268bb5e125fc3a100323740d1ebaa5e635dba3770fdc2ce4ee860000000000000000000000000000000012ac42095fdb677720ab3f14bf0afc55c95b43d28d922a5f8cb0bd841306b978751d24546e3a6474976961d0768f29e9000000000000000000000000000000000baf9804d99039c9fe966a696c64bdacc9673b0906b4deab108d34fbbaa3b0905d50892278570564017b96828c7e1ac93176b6724cf984632daf95c869d56838ab2baef94be3a4bd15df2dd8e49a90a6", "Expected": "0000000000000000000000000000000006bbdabfe104b62d22e78bc8f3446a86cd5f10c4c5a54501140768b55a7e6940b9952c9a90a14d8fdc7c04600195cd6500000000000000000000000000000000172e718c926cd393bf303984518432693c304a2758174dabba303ff4c0289b5bf5376b61e8821abab322d53e88f71d480000000000000000000000000000000000a2f84fbdb5b05107a0a340e81b56ddf6d03c23848448f841dc44f07cbf8a575289cf6d53986f581fddb0f2d07e38d70000000000000000000000000000000005cbc10f143a9a1fe23f670a4c47d385f5c7069d8c46580322d6939122b2d39d185d6a8c2e51e88a1d40fd2e82d08b8f", "Name": "matter_g2_mul_25", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000014ce6d88a7c5c782562aa101550f1af487296adebd9dae8252698ba04fbd58b92e2216de6ffd474d5992f97d9f22800d000000000000000000000000000000000ce92a04f5c8a99ca0e93992448222519fc454bda5d1d8638a7bfde968386e4ba0dcd1da59cd81d4c4dca3e584be0275000000000000000000000000000000000cb570796f5c8f7b8aa02e76cb8e870d3365fe4dce5df07ec286a0a821f922b4003d5b69c0f1588206d9544013e268c400000000000000000000000000000000098056a033d9cdae86aac02de3a444471854b909680719154b44d4f55f30087294e39e57643c692d6da725b859239080d76db3dcb659eaf6c086be6b414a494dea4bd30aef8450ae639f473148c05b36", "Expected": "0000000000000000000000000000000011769e191fe258ffd1922295a9fe877ad5a52fde6e343730f8f5ec6cdcd584f8ed1dbe0f55b5dd81f5f78b7437f02abd000000000000000000000000000000001253689089e9192d10a45342214425de36740c120e49f596d24658941ce2b2ecfb50e879be0125e3d159088f88e234f10000000000000000000000000000000017b642d1b5a953f47fff8f0649263f16f41a0ec0397d5a81571174aeb85431c352e2bf6bafa6894d2e6cdb5eafff16d40000000000000000000000000000000017b3438d0ddbd2ace1e63802013b5bac00d31889dcb2d9653a6f6412d157aad2fc45267322a62129087380bec65ec169", "Name": "matter_g2_mul_26", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001214aacb0a5e6b7a40369a83c07fa8cf1786ce7cbde2b5a501d9c1292532df7822d4fde10a31fc0cecce3a7cfe3311850000000000000000000000000000000004f9669d8fe4f884ae93b2505710e6e45b19b7aa5df8cdd811f09e547efc27d21024cba05e2dc9d057055f30ec72d9df000000000000000000000000000000000a852b821b31cd27eca19712a636aa05ef2cd82c36ac1c2ca240edc7d0172b42a72c42d3cba583a5b5129ac1c9486e270000000000000000000000000000000007bd8419e791a5cea04993509e91a980d3ae4987a5b322400b6e4a4f2b636891a1c7ba4de96b53426dd556532403d5a39915646de2449b3cb78d142b6018f3da7a16769722ec2c7185aedafe2699a8bc", "Expected": "00000000000000000000000000000000089a07bf63b8029e0506393828d8593b94b73c750815552f9a3c74ef7470b5810bc27212ba02ca6fdcd97e1e28a52a1e00000000000000000000000000000000051a93291d4b912f0a594d45c0264a9073663a9ec75e6ee81e13e79383d96e9330bab845fd1e5163e5b28c41c4a854c40000000000000000000000000000000016610bf2b2006207046e489294a132937edbdf95caf508f0df3bf8502e641aab9c44903cde75cff3c1f86873e06cc58c0000000000000000000000000000000005d33669fd8a6256dc55f513bb93cce8bae62a593eb8903cb7d7902a7727efb8fb4bb2e5058441c30b99f146ff5394c3", "Name": "matter_g2_mul_27", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005ef88bf38b2f998dec7302cde829076e6cf69df23aa0bf6bbb39fc0d3d8b5eafba74efb928b1de0eeb3d86ec82612300000000000000000000000000000000011f47e9583997b19c36616e4bf78d6ddd6d67937f493986250ff02aef6e6e7ff074559af2f20a5bf1d67158e4a199cdb000000000000000000000000000000000007777c8eb259a836e6459b7bdb642f878d869fdcb31b105d01f280938ef5377f2775874c099dcd394abe70f17d595b000000000000000000000000000000001607379d1cd34e2d0ed765a339b21433e9aa489609b92414c6b5a05d796085269c288d739717def9db3502e0550860165061073223f066e35242772385c67aaefb3f7ea7df244d73369db1ea0b208792", "Expected": "0000000000000000000000000000000005aa23543088a9a833d773a71275e73fc3081e13c907b8a04a330df7d6c06618fe69e644e0ee55869e364d3561e40f300000000000000000000000000000000010eef9238d2c520f32243f07161f3e35b15fc949b9401baa1a9c5df7d50b2cb3bdd237747735b235862bb57322fd9d090000000000000000000000000000000012dcc16496c95e39ecfd8f0514b5ab2569d89826d957478cdecd4e827095034e974039b37e767a0f25bf057ed715aeb00000000000000000000000000000000000d0593865fd2172ebf1b94c7511ab7d433a276bf833515146adb6d79b6e09d7c18f4c7f4d3241c14d01a4ad0f31580f", "Name": "matter_g2_mul_28", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d6e3068c082b68312141aa68f1540ea1415e93e7f1762b6f06ff408a9995542da1c727a13355c19f8f418a44de1a95d000000000000000000000000000000000dcfcf2ab12b1a0e521ab402aaa4d32ff649a5a97892eb6ad98487c3c73c35601c313b8130ad12e9098d16eed3bcc2e00000000000000000000000000000000013777b1eefa4af03dc44e4e054eb7a3a980a9c55644900b80346be84b970e1754d1f4ab771adc9249e4accf88a23fb400000000000000000000000000000000002f53b231f1209c6f8b52f99a78bc2147c951ac89b341495f4a60a6572985ce2bc823625099ec214bc9ceedb2deea3fff396ee22209271ea0bda10fb5e2584e7536e8bb1d00a0dd7b852b0aa653cd86c", "Expected": "0000000000000000000000000000000015785bae0c27680cca2097ab52306207a61ba9903723f574091ef5e57c2e871e076d7f46e6e39f65a01e183e7bd822f000000000000000000000000000000000071110a384248664db46f21d87b455a3ad3c43782c68304ce17f52cc8579fb2e3378995d6eb3b8c97665e5fb7de665fd0000000000000000000000000000000019153a01c2b3c5d481474a71e5c67f27fae3232a0c8f1655ddd4da6b4c79870bfb0b6beb4af8c54aaf7e9251ad41d639000000000000000000000000000000000c58375439a93e0763467c6a11dada3e579ec53a968c9b9c1a446cf3224ea0c89c9ec218a8b78de91fc12f087e722f94", "Name": "matter_g2_mul_29", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000161c595d151a765c7dee03c9210414cdffab84b9078b4b98f9df09be5ec299b8f6322c692214f00ede97958f235c352b00000000000000000000000000000000106883e0937cb869e579b513bde8f61020fcf26be38f8b98eae3885cedec2e028970415fc653cf10e64727b7f6232e06000000000000000000000000000000000f351a82b733af31af453904874b7ca6252957a1ab51ec7f7b6fff85bbf3331f870a7e72a81594a9930859237e7a154d0000000000000000000000000000000012fcf20d1750901f2cfed64fd362f010ee64fafe9ddab406cc352b65829b929881a50514d53247d1cca7d6995d0bc9b2f0d3d4cf46265fc0f69e093181f8b02114e492485696c671b648450c4fcd97aa", "Expected": "0000000000000000000000000000000004c7495c03fc3fb4d0fd4e0e660d6424de9e060eac72eee3608ba95bac294a3a62d246f42dcf3b575ee1cf8e20a9106100000000000000000000000000000000091140aee42a9dc875f87f3ba29beff95138790140f8bb522c6c15281b3545995f9c13b0b73ae691317e674295db6526000000000000000000000000000000000a945a215b2861427e0fbbfc6fea04e79edeaa1eb87df5db8e5e017cf98fde7b8d5a04a1b2129a4aadd2e3924ecc0bb2000000000000000000000000000000000a43f8d3d92a03b7bd4c8a34ce31729ea0b8e6b051c30241dca2db31a02b6e537071a914d8f0876f944dfdb613540c6d", "Name": "matter_g2_mul_30", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000047f92d6306bed1cb840f58fd57b5b71a5df7f86dbfa55a36636cb495e08715cd57f2f3e7cd99a1efc28b1d684de1cb0000000000000000000000000000000000f4eb02d687a1a6105b4dbd740e2c7924689d558e6cbfee768dd303cc8dd0fd887f5eec24b54feccf00f473ca3f54ad000000000000000000000000000000000edad68c4d536912816cf6ef039c3dd0535dc52189583270b3b038e2c67b213d943bf384ce69c4a9dc526d7ef309f25a0000000000000000000000000000000006ff4a6b5129ef026d1d5704bf7fc0b474de92b5cf39722f165e73f4e7612d6d3bb40743e4b7b42d0dad5d5d6a2d4881915b717562844d59623bc582f1a95fc678cf0d39af32560c6c06e3a74023c89c", "Expected": "000000000000000000000000000000001821e14e70e12c7caf2a1ab651eb81dd61c4e1eec9a02fe4124abb865a7029e066f03b62e6ecfcf0fbae5151272b524f00000000000000000000000000000000044ac4a7399d6a67e7ee8cde3f5fe20b0a745462c870926f0ce8554061eba5bd62a8a08c798d8bfe30fba5567d47c7ec00000000000000000000000000000000178b8f061ad9282b3b2057f20c115c91df994ac40aacd05b7669e934bc7d650a0cd88f9fe17d7b766e34bed587ead58200000000000000000000000000000000188311eea279ddcf75f8dd82643ca3efd560ddbe6c8f2696cf7da03e65cc90d97b9f9ce99e29269644d8b881e624cca6", "Name": "matter_g2_mul_31", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017b32e613cb38b41dcdf3c8bb9187d731546977fbffd79fa7f66e3d6aaf9e1af6eca2fcdc260c8f90818d7148ba2f4960000000000000000000000000000000007e4d26606a47c874c20e8480a9f5815e5b577bccd783b775d10309eeb3d2102c7a0abc3324679e44362f09e7a4ada67000000000000000000000000000000000cb6f12ac8b49cfa36b957591293c87b21af0a949c55a28a90ab0fce88fb5cb7645e20ab2edd284f0ad1377dd95ac10e0000000000000000000000000000000014c96b5dcbd3150eeaea5c2bc27750cf88b30a91933a3233a4d1d9b357a80cc20d135e43a344e718dff5c79045c31f86d5c1c9fa11c36b86430cbb1f3ec10ebbe3787d0f5641d6d7fb96c810eda202dd", "Expected": "0000000000000000000000000000000012496dd3c1278b55bde81f6944c4bdb71869f5e5e21db7b1425ea32fa1dbc8c301e7f5e68cd7629c91650265d1361e690000000000000000000000000000000004a1251591efdbdbeda21eb89165ca61a2e090a73426451b6933d939161364c4064a67a90f859a7713fb6a9c5321d5a200000000000000000000000000000000163bcd07d030fd6ab8a8e0bf39b136dcb34f03925c3fdadf55e94a90bfde0ecde5c51d2f4d06954aa6a96c913f2ab4610000000000000000000000000000000016dc065a852ef9e038d93cc583b4a71db9b96a7e7a819dc530598f1ae256368438f52e4b709f15f56279b9c7f9db8785", "Name": "matter_g2_mul_32", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001ca1141ba9542c56de8991b313c6ae42fcecb6751b0b81b8cb21ed70d5008f7ffe831766b89880a7fa6dfdb09a2cda3000000000000000000000000000000000e6766b17db165bba564ac63ab88d3f8f5eded07a40b48644e60d3223d30458e7dabe404cab8d6f9fe135712ef0b1a43000000000000000000000000000000000dda3e6c87382fa762510e5cac721fd2b654f002f5b9a3767a8c6d651ccc582e80e3f68d6913cda30f9f51ebcfc7c98600000000000000000000000000000000059a7dac5bb6b504f2bd603d486700fe22c14f25254537b2c9079c2b45d36c7ce56854c5699cc7649b533194f51a9045c00eb20fe7c292f3ad820a074d8b3d8d24506612752d8677c2d6ca24f556cc45", "Expected": "000000000000000000000000000000000a2397fb3a3891d1703eb2112357c5fb8acb070ba9f3a39050be6f05b49b8d2488e94adfbf849c8b4a42e287077e9fff000000000000000000000000000000000cf2c02a97addbc1584091e411f9a07135f1fcf989dfc8ae29155ac90b214ce20dc11a1fc75dfb697694891d934abf0f0000000000000000000000000000000018fd4af647bf0456aff9ef80969613829f8eb837205df552aadca46bc3bf9838e0ff2515d3fe869f80d78e2357091d8b0000000000000000000000000000000003c5671ea4723498359f29d49ebe974099da3dd59d21065a721f7a4f14dc7fb1de3a67a707bfa4bad7058312632c6113", "Name": "matter_g2_mul_33", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000090f4b85961ce97cf7f99c342d3627105d790f611e19721a43d8a0febd67ae393d77a02b999108efb56f0397dac22703000000000000000000000000000000001112f23595d1613c47486eadc37f9b1ac3b3c3973b3fe964d3b67c3996fe2eacd9df5c287b0cea8e9475d146fabcf9e70000000000000000000000000000000018f46f7ba3c9af34c1025c2d460f0be966e68944928dbd55cc7fe00e5def598d80b0e3801e48a74963c974ab4727a52100000000000000000000000000000000096845338d5cd2ac44e097607d6a1a05c241eda1941991ae9edbba965d9029032c46da7218b5b2338e6c58898bc4a820f661d7b30fb11bef70e15b257d7073885468a380862202b2d705a84827644b5b", "Expected": "0000000000000000000000000000000000676bd7ce63d8b58cc1e5399ced9b495baba4cef9503c44760f92d6d9e092d6d5308fa88144491eda6c571a8c308786000000000000000000000000000000000605cebb4c20bc9dff0258f75a825f55f23a32cd0804dce56bf3cf2f19a3504f0345e0f1b839d4d5920aab19b363ae19000000000000000000000000000000001512f95f60a6dc79dd9261c321328ab8e22ff314e7582d8de83aa3bf280805cba8ba6d359a620fa6f0564396a45ca9760000000000000000000000000000000005837474ba78e0700c77141d70af1d8fb95a97cbadc95996faa93c2e81b7c8877d08d5287f83219a24bc0080e630e39a", "Name": "matter_g2_mul_34", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000aafe45ea7cb8b450a51263eebc28c1ded662972bee512e24fddaf64f43b74b66032523b3b104a4e9f6b62394436c6710000000000000000000000000000000015cb27e1fedfba2d1679f78a388f90b22bbf3e7d090f0ba972fa8e72f6e31c446f628fff929953712ef6e425d16eba5c000000000000000000000000000000000df9931893cae713042bf722db6ce394b6f346587278a154c271d8511e690417eb6dc47efbcebb7c2fb9e77f1de9fde800000000000000000000000000000000106ffa395ef170c99bb5742428ae88fa4fd7a94476985c099e3b700b7403d083281fb71a19640c6bc2321e27bcb33fe2346ce87c847376c8967cc18297e6007dcfacb6424e1d273930f38bb0e88fc5ca", "Expected": "0000000000000000000000000000000010b2a9b32e431c11ceb474942bbbd6915a3cff64a74d67570fadeb7447c5abcf1bb35c822d4441565322ebf75e61f64c000000000000000000000000000000000b75a0212232af0a59440482a1f953cc29bcd35272ef407925eccd70c1dc4705dc1e97d2da604996d3c52155d05d77500000000000000000000000000000000018751bc59f5907cbd7f1d503bc5aa266f4109fd3133a1c4c2e58e4a17250a40053b4489da4825b4c368b0f4947baa6240000000000000000000000000000000019b41fa1af9488596b09c587fc33e044d51674eb6087c647d5a762d85e38a587eb5482687d9346a1a701bd3a8bd36a61", "Name": "matter_g2_mul_35", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010b1f8b1c492a56936da905b8738affba6bd29ae5fffd40ba6b31325181d3b489a81b23dcb69f6e71bd29bfb388e5a8f00000000000000000000000000000000116a115303b4774da59844e457844232d088062d920db67b2a8450a194be7e5340ebd4d106454fd9a03c8f50dbb1e119000000000000000000000000000000000eb521edd61b38006cffc43ab72d395d669dec196846fa4d6d43521da6c2fc3bf0994ce7556a3cffec7751b3bc5703ff00000000000000000000000000000000073cea36eccaa1c78deefb6029903c2b6598301bdefa9759719c3b590fcc5a6a4d3d4d19f552b33f4a3126a6e6a8448639a142c443a666499a880aa1cb9f523411bbc8e5554de099ab485b6c2c2e57cc", "Expected": "00000000000000000000000000000000054836eb7ef9edbe914bc16d1498e0bc3c978bbed2518802c2f8e1c0b59fee482cce0ae8e805c33861d4cd595f6b8bf40000000000000000000000000000000007dda36d55aa7a890aeaecf2528a390c98d9ecfc8a5c78c2a6def30de55b90ae408ab770cf9a9a4663ba601c4f5765a00000000000000000000000000000000007ff7b24c8ed9fca572069e72b1e93978cea87a0fac7ba60f54aa573d881f21b73012b010e9c0fc9324aa7697bae0c4a0000000000000000000000000000000002d9773bf294efe64021e755e4dd2936a5060bbea5688b6369ffa3b94eadcc58cc3986c74ff365301be1e6c785939b69", "Name": "matter_g2_mul_36", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e3925fa085db73c1e67b29ae90f8773f83be5ec684402e8e2360ffee8a8368911e584843e42b0d470de78591df6ea6300000000000000000000000000000000075c7efdeeb16609b4a47ea442af4d75238fb7534fd96cb236a7886809d6adc2b62c8ff72bdb041bc51c1a71b68219e300000000000000000000000000000000088b4eb0dd185e51b737d797334590e982b7b0a5f109fc7d0524b2465c2c0457964eba5a6d2d4d99fb628f21f15a776c000000000000000000000000000000000fc79f6b38f3356972669290eeadcd992a22bc1191606b663a1e148aa58db3938f0fc65e536bc5811c50d9c7f03d3e372c01b7795c2d16b5bbbb1e107be36cc91b25130888956b0cdd344de9b4659447", "Expected": "000000000000000000000000000000000902c1082ff09bf93b91c9ef5e447bd6832fec9297cdb065f11fc5ee626e6e8834cb5d74775c586609a0394e6114e8820000000000000000000000000000000018e414a40c27430b98246fef556e74dd3dd7adc601e3c05b79f8c29169780a173be9a725df3318d71b6e82abf97930bd000000000000000000000000000000000f924fa88f43c86ec98b34379b9a649c7564ef0dc596c95df19522fd50fb3a37cae031e891a7a7aa6a5e6a9062c3726a0000000000000000000000000000000006bd3340412f64d02d0cb3ac44d1f31cdb1906e56dbfb66d86b60a74cd26c1e241963fcd8bba4109c428db0bb083e81f", "Name": "matter_g2_mul_37", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b87c47605fc060a8e3677e84ce9d14b9309360a13c80d040c625fbf0108f829300cc1fca409a0f9c96311cd4a9a21e60000000000000000000000000000000014c4088f1e7935cf6a1d2475b84497ce6a250ee2c0c991fe51a2f2836388a354824b02d9cf215328dfce3f546713e21100000000000000000000000000000000120e59be3ecf35674eac6cdc559599b273f13f28a529770fa156f8e519734c451eefb35023639f32049cd19ea0d945a3000000000000000000000000000000000f97755b62a8cb8f861ea02c77819f0b58181aecf612d92180ba9b475f0b4888b922c57f6a1c619dd5514620a1cfd9e2c712943d8795a6104f024b9701c70b09cdee9494755bbab0576e2c7f7c9d4828", "Expected": "0000000000000000000000000000000001415fbd8afeeb5796460a9095f14a8f3f6fe0374d4cc4160f030710a6d4d3a92febcf4dad770de3a3ba1a2efbd858210000000000000000000000000000000015792220c7e53262b56224d230a8a4b32019c77548704ec16da5ce167854305e6cdb9924c248f222d6fe95a8383af7890000000000000000000000000000000001694329d8e0f41256b703a8bb6548f1d9e0749a55c124c9b60361b4cb1daee24fcf272327ba598022a92815764fc8570000000000000000000000000000000003350658842c5b6fc5561a14df27d950a00c5bcc13d6d9d014bfd6dc95ec1a030594625f41d439b90b05275a0ffefdb1", "Name": "matter_g2_mul_38", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005860cfb6be6720118623d2d8ba05e686df22744b948421dd3cc1b1691e00d9b5d00d00195b4acf7a7b043f764f3f1c70000000000000000000000000000000012632a3313dd611e8d969bddd556c2d79ff387603462ac78ded3a842981697bdac34ee6f1f4744ed2ff16100874ac24000000000000000000000000000000000112b94c317586e343acadeca611c485c3ea172bc10dd39158c1e678007130062a921b53826d7be6286963ff822f1066c00000000000000000000000000000000040de8c0dadd2a6c2a7ea0fa43e1a5f2f5a6be3fcb0de6875d8cef1ee2daad87125d12f6869c4dd3d931b296f1df2fb3d4d77f6246c57d398c57848db8d3f986c475a41a23d424cd3cc2b362c1b99f2a", "Expected": "00000000000000000000000000000000054c6cb26c8b0a9a4700e0b95348e6fb1190c577eba03a44e84fe7744c543321d02c4d8f55c03f984b44ffbd899ac53a000000000000000000000000000000000e7ab8da5d573cb88a78f6a6ad2b307bf867777f79a643b6ec89d9cb208711c85d7d2cf8f8ac69a8b322000fc7866024000000000000000000000000000000000fbc5926b9dcd9e4d1ca1a2b43dab5c98aa20b37aff0868c54441de44eb014e5283010642717fafaa95000f4313e14840000000000000000000000000000000003671ee05bc20bead72f2306203dad55cf20b13d3bb2cca079bf4391411b85ed4df55e1426645d73b6935889d4450c58", "Name": "matter_g2_mul_39", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006fcd2c4fe848e9462ba1112baad39031c210952adbdd06293a622ffe2d1c6e4fcc8773ec8913717018b97bcb9a554fd00000000000000000000000000000000130a97442f3273b7b35464545e7351faf71ead9b8996c63889a45945ed82bba29bff5014776c6185219a5234d8475c92000000000000000000000000000000000491d571bac5487b866022a0714be11b38bfb296233845cc434a50be1d35f516b8c6b046fe3d0a8f4f95ac20eddea01b0000000000000000000000000000000017e34b04e6fdf152c848f2432b7bd84b3dba3915f06eb77efb8035750aca9d89e92e1d1bc4871105c440d639e8d8b05541776ed9d1029918af4c5113a6110139b8bd7f938caa204373a28ddaa51430eb", "Expected": "0000000000000000000000000000000013fdd394635f42a926a2324b8cb870b5995772ef4e25ebc1da41dc5bf724f747da8d95a28dd703b5ed65ada5555c8b5b00000000000000000000000000000000118fd550962d1de8f1e60c312643ec7cd306f0bbcc932739270595537c8d290ca7e20b962fcde570bd2ed7ea43009fe70000000000000000000000000000000018b25fef4b75fc7649a489d078311dfb6da9909f472de7bd9bee9c3ee353f345c83119269ab797fabdbede41e0fe6169000000000000000000000000000000000b7c2a73741f6944ef4ce8fa20b2900612645c224818b7faccf6597827fa07f7262295f42be5f34a751a6400495f7eaf", "Name": "matter_g2_mul_40", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f1b8df4e8fdfe32eaf227f5af9f2befc85073468f10b81d32d0e126fe2b0cc8e8adb8afcac73213b6ed95e8e843b97c00000000000000000000000000000000004e3fb435ae0fb2d8bd091f250aefe5922b353a64e16abd75627737f3bc56639f8b40652cae69c73ff1969925b0afdf000000000000000000000000000000001003aed7cfb00efce49d6b1a8eba27df87479a4d37bd7fda6121549483b669a1a761204b0dd28262bf27e5c8e180540f00000000000000000000000000000000114fbca7caf782b3296d0b26b4c362bf50acaecb8bc5726b2c99f904ec3d092d5d40991d0d30c8e79fddaa45f04a75d3fa64411438542922a7bac10806efaa633d31d37c0b223314a8b6221155b9c425", "Expected": "00000000000000000000000000000000177d29de8a81db2e515d4241e5f7e3d35de22bbcf9aaa616b057cbf2dab57ab8d98213cdec82a2034964f3e1def8a4e3000000000000000000000000000000000a0cce8113eecb064a60ee2c470dfae8b3921f8da2c7ad8dc918b355ff44542b007add28a44848fa8d8f8671617431ff0000000000000000000000000000000010470fcc723286327e951e758fd0474de394778d0c1ec5fe6f263dea1957c60f05dc8f9d82b3c6a7d73b3e783f35ade500000000000000000000000000000000098a6ed331f03da7ccc9148f07b19b132152e15d9fdaee5cc092524b33795edf2b458b4e8383c5e29affd3f025094033", "Name": "matter_g2_mul_41", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017faf481fd4cb0c373d21d7caad40e93d9a86e62d26136892fbcc6f6e48205543aff00c45e82fdd1d3e0e733de91e7000000000000000000000000000000000012e14fcb9ad4d9d15347cf004745ed4bd92097eeeb41c4cbcb728a234616363589d8f5ad4cbb61d31a8aa27627723c7e000000000000000000000000000000001513dad1ff27e053902e779e35d04cab648939317830144ea775c435a4b55e13fa2fef03a1256abf5c187487c25a774f00000000000000000000000000000000139da29de8587c7d0ca9237c37a116387385e9cea453b9e2003a37ede7aa0a3f4c1df55255897f5975b662be33622dbce7002f41c6acab677a0ad023bad2a61b11c1b7221d944018b5ce60bb61e87e96", "Expected": "0000000000000000000000000000000018a1f1a60172a65abc8f2d855ee7510c1e0af9bada084325027bd493ae86ea2c62c15ace7f63562a82cb80ee7095661b000000000000000000000000000000001736b977fb52eb1b466cec3d42df7e89047784f0e8362eb6425e37adb1e84d0438f5a6e82c7b31d59b0959a5f4aaf9310000000000000000000000000000000013ea0f849830f8e48161e840295637d8596b32eb576560289620b797b14bd395d835e8140b69039c904ef1d07a82127b000000000000000000000000000000000d7f58873701c138cb7e18ffc36cd0e47b07d70448ddd9fdc4b947003fb29cba0775916c752d531e527ab744c277e5da", "Name": "matter_g2_mul_42", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c118b147ee3489f30c6ecc0256a314ab674110588e8b69ca6d265fc270c3e5b767817f861140cca5d7c6be4012d1ffe0000000000000000000000000000000014800790654726959fd876b035bade0da744fb36ee5b304f228663a531345120267c55ac19fd66022752010e5bea7cb30000000000000000000000000000000000193ab7ac2f151750356b6e178557460c9c2672b1736d19a20e3fa28082479ca60021aa68edf2524f1aa826ee70b65a0000000000000000000000000000000015cee9ac55ab45abbc57d0ea6ec9ee49f6c59f6b94f99589dbc08ee877d3a261ad77f5473fedd72ed7206647eeafb6eac26e55f09b787c0542878e4d720027d9ea465f829a4e0164cf618c5d9cde49bc", "Expected": "000000000000000000000000000000000290fb3f38937ce4439ceaa21cf3b31db8a22f9f5ad9db0fd7d38ca978192bc05d41152f8f86ca7b2ee0bb58e125f57f000000000000000000000000000000001775913fc24699bf08f25fb946fc6527178ebb821c654b7bc69f6f86b5168fc42057a5d3bfdc53b3d57fa1ac05f7a0930000000000000000000000000000000017b9043cde8dbf500ad90463250a49f56b35713f2fd9a35d8391fc36c78c083e39674592a98cb857194ef9e73a62a397000000000000000000000000000000000e5e62e39433d443e7d2d32754d2ca2556cf6deea45e5076ac040e3d6de14e9965c53f8c65bd98ae7d17ad3a26f3accb", "Name": "matter_g2_mul_43", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ef203fab794a0ef29eb2ebf00076134e5932e27c99d6d445695b9df2afe7563602e318caf5d44724a21790ca0ab0d180000000000000000000000000000000013b9b1b1d3e98b61b0f1a0ef3a1a4ceed57b6c01849a4ad66a86332b3d27022cfccadd3567e6709d2de5b23b23dba43f000000000000000000000000000000000c1fbace49684f4be32ef6178ac3a95ea3f50b11494340fb73dc5391d50bcacafb3bf0f2631fea9c4ec47327d644489500000000000000000000000000000000040f82812855aa3e3aaba826d5810c1049cf44e86e44e23cc6da437971b529d2f2676c73e1fb9da52640c981fbd710bebba67cc47e38a129ab1140fbcf0386ddba2feefc919aacdce6059a27a1e2efca", "Expected": "000000000000000000000000000000000d9927347a9ac9b0290e68143fbc6a5f4476604c3fa5ae87e729a03ca055e4c6543f9245a4592e195180d88781e46ac900000000000000000000000000000000175e0ee8de4002b18f32f70f1bfa9e0be87288cddf1c436428c2969884112bef5db19e041cbaeb23596e25cabea3777300000000000000000000000000000000074ed9e981818102b9ba818d478ba27033eb38e3fa19cdeb9f5820e59a64dc451342a160359c54bc8ec7d866b62080ef000000000000000000000000000000000a853930020bf01e20816d3aed242e00792b0d0e78fb15403fc3cc255f0dbd99ea6ae1d59d5978e562be4862b3317324", "Name": "matter_g2_mul_44", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000060d7a718dd02b147c265f71eb136d1f31781b12a41866b4f86d7374b93dd10058c192cc0fba928373b1526e1a5d7d7f000000000000000000000000000000000cf29275373c0573ef22bf87919faf5444847203c7dc6d2e18986152cc294be04a5b1a4b0536797158113a15276c4fc6000000000000000000000000000000001016d5b9d4d200d7b4b7cc3836b85d6697fe14db350badba9978c7b56983dd1a7e572640ee0372b0a4e2079ff4c1abf2000000000000000000000000000000000f2768d104d895473ddf8c6b3cd0e7c22458d0037eca6365c766879a07c95037ee0de00d32c974d767080935abbe0be1705fb566367d9fc142c4194b0525c16672b843aac1160f9056ebb115e80d377a", "Expected": "000000000000000000000000000000000e9c290ba8a22f7bb3f7dfdcc9f5a221a5ce838d4fa85a00473a4dd830bacf583dd91a6a6f78d2ebb54a4c1bb217f793000000000000000000000000000000000dc51b0ae8bda6d28c51016764fc028258171d7c7646393228692aef7f1dda4a83e53553f63d6ba996d4c0a802bc967f0000000000000000000000000000000014ab155029dd35206811be9ca4efbf762a1673367e6b57528f79eb50008ce7c3b49a2d25da0ae68ac4030ab4bcc0daba0000000000000000000000000000000008cd743bb52e7908aa973c8518eaded75fc2858f4edb25fb7f2e09900f0abd3ac87e93cf1068bbe0c7d99619aa7a6b76", "Name": "matter_g2_mul_45", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017b9ca4349fecaa43ce911c0b256680edb8a0906ef5460fc4d2004579336df1e19560fe960a7a7cd74bb6e8272e08960000000000000000000000000000000000d5b96dae738db59cc67a51c61bec6deaeefaaa51e3259243fa4b142ef59676231229ae386ce699fbe18c4c00bf9d49400000000000000000000000000000000111b79f4b68dad16550a13334d09dc38336a75a5da23a17b5064e2d591aa3dab4c2e982a9f730a7633070504663a24610000000000000000000000000000000018f6d3616a7eaf17c805a88c9710039644d01b61aefebf76717ddcda6f4bb34aa15702de1e92bdb27b27f3409638da90f7bfd990cc4dac62a0d730f56b4eb1c1ad77ca9cd58b089c23c2f6efa00b7fa4", "Expected": "000000000000000000000000000000001746a449993b0684740630f3f0e46eddfa135371e33e8de4dfe553c78845399e63bb3da48798b35df48d27e1f991954400000000000000000000000000000000057e0fb1113968858981c9803166d8b3eacc91bfad320ea0e610fbc5b276da1b46d74fcc54183ba61d1b2fe6743097c90000000000000000000000000000000000b3a178ae3b739cae3e80f3f44db42d8c465a5cfe4943b449d4c3b7f4ad153916c6cf4fdfece14a00b271222c72764300000000000000000000000000000000041c8b293ded0c647f2e4d6f9b35304179b723c3e6e421a5cb103e561d1655b92e74877ce22c99f22a3700c3aba9ebb9", "Name": "matter_g2_mul_46", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000aeb5c087644595d0912879f61959d2731ff55260c682ed2bc5fc55c13964ef7c1f70aeb55876d2264d558c31371ca69000000000000000000000000000000000e173848f4570525b03a2b2c86f4dcdb8b28dd6d18c1354cad31028eb1b8b44432c2346edaace093e3954c7fa6d338a4000000000000000000000000000000001949b0902506d111ef6318edcd7a58ca4d69f5804a028aee73c3786cb2db168c6a73b77194f7a021ae6ae43ac78ade340000000000000000000000000000000017c5e28ba6103d97e2f3d3611c0c78f06406e0da8a49ae29c7d460b52f75136920784cd500aa3593858b877697eb8424807c5a41ae2baa1e10ebee15363d1d4569f731d77a418998108f5dfae0e90556", "Expected": "000000000000000000000000000000001103cc395acf81772955bda38f951a81c5a6a476c0b5e1543616a5a7a7be22dd487ab2a8586524891300adec5225b4020000000000000000000000000000000003479a08e2811ae9aab0301d66ada470935984d7466201f3fb28c610c0b5f67e7305f5ad3514cec5f30b51d0aae775d40000000000000000000000000000000005ea37a6d20c1ad0978da68ded3a5bfcc5ad8fe81e39b525fe7d1f2b2b1ab0be7ada80173b1d0b7fe1e06ab6354e64b10000000000000000000000000000000008f2093151a285dac511df1755e99a652a1cad0af3a019650fbdead1421ba8e84afc9eb0a4fea651f365d72f031a0ca6", "Name": "matter_g2_mul_47", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d4f09acd5f362e0a516d4c13c5e2f504d9bd49fdfb6d8b7a7ab35a02c391c8112b03270d5d9eefe9b659dd27601d18f000000000000000000000000000000000fd489cb75945f3b5ebb1c0e326d59602934c8f78fe9294a8877e7aeb95de5addde0cb7ab53674df8b2cfbb036b30b9900000000000000000000000000000000055dbc4eca768714e098bbe9c71cf54b40f51c26e95808ee79225a87fb6fa1415178db47f02d856fea56a752d185f86b000000000000000000000000000000001239b7640f416eb6e921fe47f7501d504fadc190d9cf4e89ae2b717276739a2f4ee9f637c35e23c480df029fd8d247c7a7e300bcb3c740fd1f693d4c8915c4c46dcb627f6de6e4847f123623cd23bac7", "Expected": "0000000000000000000000000000000019f79677ea0e011e5c9a892a407646798b05be05337c73135cb771abf101f450bbffd08e125f077f5ea989decc009b9f000000000000000000000000000000000ed15f35966024cf1de2926108151e976dcb0d51b2736b0877d79de81f6fccb9dd299d14855f4e257cae33ab7455b95100000000000000000000000000000000125e2fabb5cc95c0a7890e9ff2b70102a97a03f2d11d915cf4332dd049a467333e12ebb27955c0310ebdfe2afb3173ee0000000000000000000000000000000011718167000f9b749f1615610a30023db4b986364da5bbdc4506c726624a073548a94307b282590cd8a43b4900a1afb2", "Name": "matter_g2_mul_48", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f20a07526a082e88630a0256d134a8a5e8ada07b1cead39ee838dcbb30904e9016107fcbdf1f8ba182308dbe0b043d20000000000000000000000000000000014fb7732f67abf60c03ac902577532d0acadb5f3db0d6397a42ba693526ad74f2c61a0195bdc9704aaaf12e65aa6d88b000000000000000000000000000000000018cec4fb81c85d304588d11f8b9c51f5a053df11463e5812a1b2e6c7144522ba36bb91adf219892d0007cee470032e000000000000000000000000000000000b8e52d958a12a9037e8be9bc0d5045cade2d6ea05c6e68462b3a30b5d4ea34e5fbad173761e4e216b2e6958c8983b28b473df5e282565a0783d23e65e283a103ebbddb5c884183cceb62fc32d0e9602", "Expected": "0000000000000000000000000000000005af8fd9e79568b46fc42b2c1bac62d115365834e509dab032f66425b7a571a4bd3bf702299d3c5f36c372750b3281f30000000000000000000000000000000018499089f306b3c9f7a645ca2f9aabc4e57c046992fff87e832e21e21875c6adaca050ea8bd7043afec3a36ecf8eafae0000000000000000000000000000000000827fa0f46134e2dff80088129841f0469ec7360fd8b9864e9ed99c5fd3458e6360661ab4c671846681d491b8b823d200000000000000000000000000000000120f829e8d0ffc360a14eabaf52bc653b1e90a36c0a8af806ca745fa306a9739e31435039a377e0748caf5e80c2b0b09", "Name": "matter_g2_mul_49", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001468cb35a60898ed129f30c261b8431df6a154c250ec16d85a22f8717593b2c21853d123da86d977a7938c5ed74ef23500000000000000000000000000000000011f4e28e31b5f9e6877192a5e632d8c1ed7ca0c42e6e9902ca68f1c2de0f648c6064436012c5c7b14bb8d1078e02f2c000000000000000000000000000000000b25114b2697ca7eb1e6effdd1054893a188fd382d387ec098f846c1137a9b9baad01653b963a0b0bf3cb50c3ce3563d000000000000000000000000000000000c1d241cb03e642c1752b1e1886472477c19a2801ec032dc220c3243952f882094119bb92b621b654b766bc900d2d4f7a048ef7cf5d1f6f625ee3aba091147c389ebebc5b8f3d285e16ef4e8afe5c013", "Expected": "000000000000000000000000000000001745500b00e5ebc6f71c779ba0b0f8d6601a065c550ca19de9562455423d2ccb507e659b0dce982faa841267fb1a27d90000000000000000000000000000000009c36b54f12d130868ff9b9b61b714fb1067dc91637c09614c51b5aafa2cbe3ca7dce0f3e366d4200cbf603ad4fd630000000000000000000000000000000000172e543708bb853712d81c000c9f9f2378e628b4d13b074317e95deeae98e11e7f917f91e02a0b18cfe9b25f1b83f16700000000000000000000000000000000189fc572ff6a8c6606ba0cea7da7040898d9ee85a58f12fade8c5a22031ff26c2f9cc612bc6e1b82a0999fa93c6fdfca", "Name": "matter_g2_mul_50", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c80d4474390fa791ea5f2f16b41506d8ae13ee0993c8d31a07712687298ee7978a724999500c42400d2f788a5a36067000000000000000000000000000000000592705cc5a8875750a4e6ceb42aa3bef5593eda9e8212702a2e08ea70277a2a66526bc5237be33c8449301544da35e60000000000000000000000000000000000facabfbd15284c6433f17b0e6035d4fdd84d3ad2dd30a27d52809652ff6e7a684d7724697919100567ad0c3e1a26320000000000000000000000000000000006a0fc4e2af69ce15a356656f5d182a2cf213d76a6047a05a1a3375909d245f5316b91333d2141c0817438f0d87bb52da9b63c6bf36997118d58600c1e429c105a379b9e8b0de934ab9f433a4fa63dc8", "Expected": "00000000000000000000000000000000013c6f777df97ad3ddab9b7486d54d1bacb3b40ad3035b47a25a66c02e8866955e27a8ee52872c8222ff7466c1310bad0000000000000000000000000000000014a5eb510d7c743e824f4daab21c43db4d6de8ab2e825d13ae0e186aaba828d7b4a2343a11011a8ec4ea82f456e394a70000000000000000000000000000000017a55d3827b78a9c5ea792b705eba7777df74951930791b17ff5b861e98a4488f83007c073c3e904ed4ee328b6f6171c0000000000000000000000000000000019bae02f8d6f1e31dfa09f4feedd5217ade66f6e8248aa98b273574f72aef83d5048534ed38acab9e0eb4c64f4389af4", "Name": "matter_g2_mul_51", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003f629618e1fc3018bb836301ccdc59022f0a25cc9c5de6e4c31fa08feea525c83256235e4ec8364e77e5df478f5f62c000000000000000000000000000000001120d6af221ba6f4351bbee4c2c664a769adb17872646df2c408f70c99ea991ffced4eab50fa98be1bb9426915f125930000000000000000000000000000000015cd16b028ce3d58b10aeb84b783475d894ab3f0cfdf7104ebb4f3417a038107128f07518dce548271061cb8c97e88af0000000000000000000000000000000018379875b68bc26107f9a068e5034f29dc2ae7e8830f8e9ecddc53fe7991206646cda33d37b31a47a977b46be58d7618f228da17f49667c113d2bc2a2c8a338f80be68496f5145b4be21a5786ca6d46b", "Expected": "0000000000000000000000000000000006490c327790b4c451f93197d7db24211a3b4b5f573a6df409206b4bbfc36bd10d2d0c989889efffd8f4daa4a68b211c00000000000000000000000000000000168f224738db3f07af77494f52ea5e957812a1acd62615f0eaa95c1d363cfceff29be9cf3be5329bb41175a0231ced4f000000000000000000000000000000000321f06b55f7dbfd4900b329c914f9ab9be2794e51e54498e18f83ece5bfd205131fbc254bfbf624d57ec2954b05f6f00000000000000000000000000000000018ec54f3e09bb2a6b112b575f9481bf1c85666133051e9c0ab53369d14eb90e27d2ed02dcda1250d5d539df0d0cda37c", "Name": "matter_g2_mul_52", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000036570783711b381830e35878fbeb187b84884a9a0e88c38e84124515b470e6ac18157e1499026b27f4f731a961eaf330000000000000000000000000000000008382838c18d56c046a8db495babf8d14c915622d7917ebe10cf7da7ecb65f174cddb9e70d0262ada961b396c5511b410000000000000000000000000000000015f63ce982aa581dad5c71fc79251b7f6336c4e78a4a0f4cb6f87167cabd31cbec987d7af4f11dc6d693a0b0774864130000000000000000000000000000000015c001372fe0530a3f50fb8b30e75ff4b264d673e0448211d082c7a9018f583b4d01790019874596c59c68768cfa3e699431e18a462fba704216b516e819fb3392e315b0c92a7411a329cdafeb511244", "Expected": "0000000000000000000000000000000001641b4ad10da5089164809d82ae47f74e27eaebffc2a2ca3c1b924fc69c1ea80ba3da78c78e86957f6a24e7f75dcada0000000000000000000000000000000014e781e4fe79ea1654460f4b0daddaffb29b287efd8168cb20d7ac6c729f684c5f2a7cfa87885accee3a797febc904c200000000000000000000000000000000001c9a44547f0c5b1f4df190285644c5a31df61e3de7da085835ebda917d5e4163f2deea9a83d641a4759fa3108567ad0000000000000000000000000000000014c3d2a79d80687fd6e6aa423257644fa5d0cf641aaf6a7c5675a810767904166fabd9a2ced0727e3badb932e46fd181", "Name": "matter_g2_mul_53", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000074d78cdd35ea17a3013e2301fe9f80f2d20d270a25fdead37eed7697a52d152612543781763e6035fa5452ab12cce25000000000000000000000000000000000e572236e1c203a1c0f99e6ec978458c1a143a6a650eee27cfbe406bb2858fe5f30222f468d119703c2f442bc644ff3000000000000000000000000000000000125384343fe132e16a9fc15efe1b3a9e47289e0afc4b44d492e33a6216edbc96d66c1ca66944a8296e7695f27f414c5b00000000000000000000000000000000084c2cbf0d7c932c3098ded7c70d4411eed882feb0f79e0f7f1c31f5fccb6d53fb57de179c3ba5754bc5e532c3784df12051041bd2f12f6e6e29924139770fe209b7bbdbcd6c0bcabbf5021a7dff2d83", "Expected": "00000000000000000000000000000000129554de7de9a2b73340d94d96f0356a2d1c0524cfb007d76a75f462872e831f45553de05f5b6a1f9eeae37af7f6b4c9000000000000000000000000000000000b1ea2a649ca13a3dc7882f2423036670f68aa05792a8fcd72524420e37381a9ca80dfea701fa5e6da57afa534059617000000000000000000000000000000000b7ff27aba408f9759b5109600cff66c03cdb4bfb3dff64a4838d0516fa46bfcf429fcf9d5cbf74a27f70fdccdb1238c0000000000000000000000000000000005a99aec88967fe775c691d443e2dbd45080eec97e686ee6d7b32e801efe6563315bfafd5c7622d0543519cae4417029", "Name": "matter_g2_mul_54", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004d46066439c3ac559cce863c58316883651023990180470d2efd06e443a7caf3a514b54f15ce6e850d32779215bcf4a0000000000000000000000000000000019ce904b6c9c3de59f7d5017f60f1978d60c564f94a0f1964c24c876d1139a7ffbeb6d0d4884bbfaf5f2f189af6904a50000000000000000000000000000000015f1989719e69be95f25dda9358fb98aae2819e0deb7e2d291e2c01e85ba26a9da421896c6b6e2ed20f609b533154694000000000000000000000000000000000b287cfcf1dd7c6d735c1358dff15393ddd6c82e7a33c5d8005c4234cdf823c76a4725fd74cad74b3ec51df67f09af0fb96df57a600dc3b5aabff5b1034886d24f6fcf035bcacaaec738deb2cfb8f852", "Expected": "0000000000000000000000000000000007997a499b2194cab634750a189cca6783ff17d866d66f5998603f8639d2242e8039222c65b0d14001167a9b09afb58a0000000000000000000000000000000015050fe6b335884a225efcfea4acd025cfc05e8f5fe9a0e22a0c91b55664c118d79887de91f1ae6cbc081f6f55f0067000000000000000000000000000000000195b23c4c2c087082c30600ff00485d169dbd360643d163f1db363f270cd7d4f177c36b4c291d50da4101e67b229d0de000000000000000000000000000000000df596ba2350ff7d3e75b4cbe5f8d6b2cc0e14b3bd6dc021936e3371ba64031f6266fb1d2951801309f22bfb1c4b27e4", "Name": "matter_g2_mul_55", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000006b37e2226957d639fcb0bcd6c20b3c7b8372e7347a14b970e01c67c1859fa97c754ce588d0f835ecc053549d963ab4000000000000000000000000000000000c6a5fae8be3a32e3f70a4202a1ab6d97183964b9f7b9a084c49922cd9e0e952b0bb66c5580f0e0c417e079493bcdb4e0000000000000000000000000000000017b6132f11adc0d5d693ae7f3a0f89f5779708083eba23e03b0c9265e4e60624e1fb6940e8ee49d31618fa6389b1b50b0000000000000000000000000000000000a45c5f6df71359648aecb6434bad1619c39f10e279a02b3cc9725d0256bcd126843fc9ed29cbe02a32cbbe79774a3378176412b07eb7f423f23ffeaa0ee642590e0b7016bc063f3fffa93e1e35484c", "Expected": "0000000000000000000000000000000001fa243b548f8f5c2e5d7736ca6fa95b74dbfd31f95fd532b94f81a255c73e7c0e000e20f9ca6750cb0dfdcd2c1aea8a00000000000000000000000000000000132a893a2326bf61962e1855331a53667e6279ed7358bc84c4a7c218b6cff1d3f449954f56daea72bc2779c60f1113400000000000000000000000000000000000091dd23c75dd8266f556bf27ba54c95c3ccab06168e4e6d0747239722afb20f3db27454c6db3a88daab0ef10659a66000000000000000000000000000000000d3b2e3fd358aa3dae983e87b5d1fce6d5688e66ced6e3a2c96b8d48041557295d5932af6532c13965d4b383fb252518", "Name": "matter_g2_mul_56", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ffed009c78ba9af8cd33af7b7697ae4dff863bb92365055baedd2299b7f5b5e8abb84ed434f7223c3e309ca53c08aca0000000000000000000000000000000003b2370c837dd6291818efe7c9af62dd51295c418739ecc509d42c92e2c97d12a9fa582946e176e8153fc9a273140b2f0000000000000000000000000000000001e63438e8b4a0462cfdff64a281ab4a7f48d51b51325817139f8ee683484f8695f1defc0c3efcca81d5fbff06cf9c54000000000000000000000000000000000192fc391cdc1ed6ddbd317f2f366f2ce25ba27b8c0f09c733e7bc0c0697544399a3a4f1186d139a8f6399ffa88e89a69c4b5627d84e153f3a4ecc14ddd6baaf1d62253a0f88d3af51be18d991976da0", "Expected": "0000000000000000000000000000000005095d1becff61df906815842112c6508d6cade4ef5f4b7418f5f01e8c5a383addc1c572237613dfbbb88bcff80e4a44000000000000000000000000000000000bd2561e7bfbda8a48ee038855e37b03fee805689452e9afaf0da4185e0c194e407ce7149b713c689d25f953da36dd1f0000000000000000000000000000000015ba3ae4d4238175425ac5dcbd9e6e9e055b8c1b7752931b524fb546f7bee8723ef2e69351450c6d1ba3c366a22355e20000000000000000000000000000000008c17d77dcfda00a1d75ea0087c58e74263ce5ce4066e979c66397de8e236708831c3a9ca6b35ade8038a28930655eb6", "Name": "matter_g2_mul_57", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000002e105e0eaa418d58019a849b89accf665a94ffb0bdf308a11b99b521de7af8ddb150c0e3b2e9c54cf5456b6105bc81000000000000000000000000000000000691a3b3986fbe1c0ea22329364454f37f645d6abe9310e883b9191ce512347e074e18e28b88c2adcc76190a549b80b40000000000000000000000000000000003f3a37a763c8d0d99a3fe36923843a22cb0fa18ced48493b2510fc99afe5b7699bbaa6c2ecdad8aaf72969354f121a1000000000000000000000000000000000f4bbae00205f54eb10c83d928d908fbae342b76050e33c51b6e282e02b3c1f132a4728dee4ea95455c25fdfc112f2542ed270764791aff081f1dc8051d22b8e18803a7e310393f21bb4a495a445cd45", "Expected": "0000000000000000000000000000000005cabaf39b93d7fe15ef6a7a3031df58219bce702a5a77162551a3d916c22e8ec9af2aa20659e7c4ce5f6382a5f82726000000000000000000000000000000000dcefe1a48d8c239164b54771118f7520ac11a7a6b72d8e17be1cd788cad2f26d3a0d9113e6536426800a744be9f0d4000000000000000000000000000000000199d95a44a4334c87aed273a0184be9602ba443d5b8d34f3495b04e927f4687fb88487f586395c7babb4f218fdbecf8c0000000000000000000000000000000010972032f9cb3e8f45447bdd06df82656fbd3ce38a9f7564c6e5d62ea3596c9b7e0a94046f1c65bf0452ca25b15a885c", "Name": "matter_g2_mul_58", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009a3e98fe4a98582ce9f274965f376cb45e8583775dbadf626cb1327c1f8a25b293b97e7f8f31ff72ba7e8e769ff25ef0000000000000000000000000000000018e4785ccb76c4897087c8a4242ddc744c6a0a53a4a844254153c23d6f16d4ddb945252d13f93101613f4eb0b1e2b8320000000000000000000000000000000011b81d344eac04d3471b1edde5e51f31f97bea3396580839fa094db58cf6bee371bbdc045fb60c3ee5c6cd5d3f6d3c4700000000000000000000000000000000073476bc5b1d52ff4ca89c3afc099417f473543fab6e59cf9de8a19705dc4bf2a210b1e6de4dfbde035c312be0c70c56fbfb7606b64eef0460b8f33a0be54451fb655ce0b81db89eb7862f392450354f", "Expected": "000000000000000000000000000000000f250b5e47ef616be106a3334e2f516061eec8f7ac69f08f6dfaedecd76fb1c9685ecdac2c3ddd534e3947d007ab177000000000000000000000000000000000073819a6de38303725aa3a9e5a7a9122b4d1e60ee8deb3554b5e06ef5e60d71517c2279c5066af003b32cdf83b7fcdf200000000000000000000000000000000070721107ac6dac198f7ed1a7f84697cbbc3199a220d1aaf82e6f015963bad863f99190f18a482f730254cef753ba22d00000000000000000000000000000000169910eb30b8fe1ad8f84c4a132c6c74a6ff06ed6e792af3baa6619e3c8aa6cc3e6f687299467ec9554f9e91bee77aa8", "Name": "matter_g2_mul_59", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c414b95b298b9c673001173ba7e5ee3e03926f28068481cfa0b469ab556f8fceba9fd0a815180ae0b82c265fd4c6b7e00000000000000000000000000000000054a242c1cc1a9c710bc23305d09c2d613ee8eb3840b37943bfe83f9c1db456ab4436ad319fcdd8684db129d76c95320000000000000000000000000000000001683711c0c7f02e67374f190eed1ce6559479d6d199f43fb5b0ce7df7774a5cb21c86b3b3498855d9b69c5763acd8c4300000000000000000000000000000000062f87085dfec847af518bd71c078f994b090c3b27c6eaad79772ab58afa43993db52fb08649a32629d61c3db12c87318a29fcc442d0c2446697e94dc47181dca7a314f9073c06aba6dc55aa79978d7d", "Expected": "00000000000000000000000000000000106e892e336b2155909946ab73b980ea761cfe8c48b13ae8a5302eacea08b9cef3e60d5b33c6ec4033218ae5761433dd0000000000000000000000000000000015daeaee59f3b4cc26d3da745661e74db8fe1ea115d50ba49ef5e6151a9ac2f3135f0232235cac7a53e1e8a70eaf0476000000000000000000000000000000000ff494d17c735b934c2c7fb8f413103188fdb116fa8f4d4e43262968ab0fa1bdec23b0d4d8b1c2defe624092de36610d0000000000000000000000000000000008f70b7e9f2d7083774fbce3bff58a1c73fbcbcd9cb049cba71c0c3f0c363517c8956240bcacdfb7934d4c67b1bfdd2b", "Name": "matter_g2_mul_60", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000083eea9b5b2d5ac5f7ef51ca889a4317322d098a408a741827fb3419eb12a51c07c788c2798cb37635e224e99bbc894c000000000000000000000000000000001312ec00f4b3a4305700b44b3f215779a9a8bfcf5b5d3a7f237a33c5484099ec9bc5c8537fae768e2c0ec62168f383d6000000000000000000000000000000000cf1d5d05d11e1d07074dd34211d0f00eae1df4dc550c55bd2fdafaffa1ad36abd5da30c5d3a5aa2845b1d95a5cb571e0000000000000000000000000000000015223baa9f2ea4b04fdb05b05bf3a94dcabc5e64189aeee39c380de9a34fe6b4253f5795f70bbe51b80e1aec1eab7196d5b468797b4af1978983faebe59a28f34956dacf5b7f65d25548bcedb518f45a", "Expected": "00000000000000000000000000000000098f32b35e3b7dc1862ca1ca3c76d009f016c6b91c227f2cebe8f1fe87567d936bf1c54103bec31b3552c077c0242fb40000000000000000000000000000000005380a66d48d348487624a15b63d2ecf6976b5b599901101ea8b1f57736649b4397f6679ecab0ae29573695a921ac475000000000000000000000000000000001710c368f70a2b9cc92ec65c4c2ca35fd63440eb350f488e7c6646f9c42bf680eb62a887d533a91e47988221b46c868200000000000000000000000000000000033c3327da938dbe4630dbe16838229d7d427f3adf18dee6fa26b1c8067838922c1bce78cce08d590ee1acf2baebc7df", "Name": "matter_g2_mul_61", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000011a960cf1978aa2ce1731b857fd91d2f59d4b8d7c6871ef6f4f85aeff549a2f397949d11a4793926fe7be37f3a83d11c0000000000000000000000000000000001954f056834d6e3b16043ef1acd0a47a353300257446e9a1db7e58bd0d7c4bc9ceb3db51ae01cfed9de99621e96934c0000000000000000000000000000000002e2fe460e71b65595ed93a0010e5ccd1a2c16fc4e0d345e7226c947f29720d2f3f54282f79cec086d3fb1999b9629b300000000000000000000000000000000060dd8a7ccb613f1521168a8a322aef9f84d9708a893f704f4fc9a19e2493f25620a47e0fff1bc1e212e65e92873b4f2dbc6afcdd409e5d50d7b655580f1144de77f3efe5d6268032eccab7deaaad997", "Expected": "000000000000000000000000000000000404587c60a4bbd8b5b929ca2ec2a9ff2ba4733f4f2877478a669b238d65ca130cba398899f2910d6de04615f8ffc99f000000000000000000000000000000000940659b3e6de7c3d8de9169a28e68dad433bda78de0991fe4a1d404e5f4babcba9d57c7f3d638aef264642f87c61fc8000000000000000000000000000000001676ce240e1ff70ab03f94f3ba3acd31725ec306ce1fd707e29ec22cf91746216dd998d03ba13a79dedf878fae38d68e00000000000000000000000000000000098a81422511f77191ee15d402614c86f9447ab78a89cc348414108f36857a1929f2b92ced78752ab3604f276861803e", "Name": "matter_g2_mul_62", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001472caba61c2f1fe4b1d0912b114c25de103ef4351668f22f3a158d7a347539a7b6656044bd490f036ca3e29dbdded370000000000000000000000000000000015f8cdf7786410b409f218164063c99e77d8f72f03882a6c9430ec725ae574547d3ea3cf30c3ad2c9c3febe6c30b1272000000000000000000000000000000000ccbbed85c2809433fbcf22d6490457dab800b21cb4de414c7dd1804a0bdeb7142f8ffbb2de921c2c9eabee6a6351026000000000000000000000000000000000a404f42c48e3ca408d3f92079b99805004da928f128206d8904ecd7fcb14121c7d9a9e7fb69accaff921315ef3d5372807347519f114e78f99617f6b147ca833bff7be962c9b1e1f32b5babe6067d7a", "Expected": "0000000000000000000000000000000010a4ba6952d22a51dbb6762a3f9bd09712c2be5a98bf0ef298d7a7e3a9735ab0d3bf39e40b334895c73a36c218ad24b50000000000000000000000000000000002860f38ef61b497bdaf4faeee7b406007981c17246cfa36cee906452ae85e1c1c6385898ebadc3b4ef8887fff25b8240000000000000000000000000000000002dbbca9034fb17c3f37727d44c027cdf47c36f3f628ea9385fc9fc371d23f22d983656caafbf1cd1f8bdeff4ad7669d000000000000000000000000000000000b7e71b65765c4113a7884771952268a9fe10576f745038912e6877c78372cd261220793b888c43accba1646e902fe14", "Name": "matter_g2_mul_63", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b52f05365c4df20a7290aee71a7e030615d1a2a971167884d835c24e756a0faf6ed0552341c561446c7fd3d5e887d830000000000000000000000000000000018718ef172c045cbf0bb132059754b62414097eef640a781db6ad521af5a24d78c622d9402033fa939f70aad0510a1ac0000000000000000000000000000000017e969e44b4910304b350b5d442bb6a0b71e1f226cb4603cc8b4dd48614622f3f4e1ddecb1894046649d40f261d94e030000000000000000000000000000000004dacaeb9e05b9d60ce56c17312a092cb988bff426b8a718cdff860186935507a06eddbc4a1a29e4ef88db83fc4b6e77830630695c8dabe9aded1b5365bf93770aab7e9ef4140a2bbde2f0a7b109724d", "Expected": "000000000000000000000000000000000e9c1a6d591be4da37fd6dc283b8d899b625ccc96371dd3d7731aca66cd2a978810497171f2aeded64fa2b10e480de2100000000000000000000000000000000006d2ad7287847255002480627782d513eaf1f68a3d583d4762fc156b8eb40deae6969fa8a7d8f8aae923800091386a00000000000000000000000000000000003c7eae0eda08df9b9eee2605a44fbb486e3bf2e409aaa1c8f38c06f969ff1f74338004b01288dce99be26a837e45d3a00000000000000000000000000000000178174d2f569a9392eddd2715ceba8762c5bcc6325217db5e5f970d6fde069d0e48a824e5b6ca017891de175c92f6b29", "Name": "matter_g2_mul_64", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019829d5799eed5a081042e4646d46fb6bead6d3b9893a4240867b25ed6af6a3e154514f244466d80e3b9311e060bbd7100000000000000000000000000000000156157a654db2813cb9c1b4da0a3ee192fad076bb2767020fc5fc00e967c1a35a367ffa375703e1181b3705ace9dd28000000000000000000000000000000000093385a6a9dd0ab996df54b23f47f4a49b3f379e11bc8331016ecee6161fcddd22f6d49fbb21f098873f1e17424dedca000000000000000000000000000000000d5b5b0f2ce81e755b4030b33fe3a8bdee38c2c60ed3b4a88bffb9207cb762c0a5c699ff424c000ab080d763abc5438d184ef5eceadfd77b3a4092696ec34d0551c88e434567638623740b7d5f9e3616", "Expected": "000000000000000000000000000000000ce12c9010b4c4afbddb459c1b46063a8488277948188b4ec0b739e1cebb5653681d0e43a0d2c6b3f842bfc609bbdee3000000000000000000000000000000001123f60cedddaf4385e63758d64d4facdc443854176ec199ca0df0a9c258517f2512594f2441a4b9a68aa9a2b4a1f4bb0000000000000000000000000000000007cc6f77d181d13bd9736ee23a33b25b0bd969760642ee19004e095ebb8e2b3c0e09321eb15a2f7961803c0fb10b6ffd00000000000000000000000000000000004d8dbf2f0c14b07ebed2b9cb4bc87df78ac8a34ef0b05cbc2c6fb8e8156415399fa52dfb968ef0e6ec697030fb003c", "Name": "matter_g2_mul_65", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003af8c25bdbd0dc1cc344d55366f15555709a74e1f0d8d7050cb6b487759db6200401b7868fca3c2ad26e6362a30e6250000000000000000000000000000000013f8b6ffe30f9a133fafe64461d305cc6b2cf5aededf68ba396d4e00df651531c750a3d94dd77bc5c6713b939b18fa19000000000000000000000000000000000dde97855d7728f409d873b83b6879b45ace5b73f317687fbf478e594a959ce21d4d751db646ceb20432e8311e67404f000000000000000000000000000000000fea997323cf29710cf0e3d44ce682e039d6cbda155e43c94dc8cefc5e94000de4b9525123b9615b5f1019a46ef37ad3a80d9efab033e920061cee8f8d7ea6023cc05f08340642613628b39e7b7fd0af", "Expected": "00000000000000000000000000000000172805bc715a8cfb2e25c384214f4005aa6d3b809a0ad95322209851ef92151526a9d01a914c4d7f0c120b9bf3837010000000000000000000000000000000000473ceaa092a5ac12f38b4065477672deacc08e553d8e9e6391bac0d9ca50015934cdbc340deb05aca916cf50c7915b30000000000000000000000000000000012e85461fbd26c2d0235acf5c8665750656819bb939e8fae77a8d526ca23443aee395a985cdd4b1eb700311fb87e91a7000000000000000000000000000000000246d45fdd88448c93bedf4799becfc7c80e67abd483f2a0aa41e8bbb3f38cbc900314436364f1db6e1d88595544517a", "Name": "matter_g2_mul_66", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000cdf60e3bb018407eab162822468255bcffd54cad9127054bd1c30705a4ebf1afc7f539cca6ba4cd070b44410ec751150000000000000000000000000000000009a2e3e5993b6a7007dedbbd21737a8c0aef3ecd4607953c4a24bb3fed97ccae01ae1cec024443f300b570a66e9ac3bf0000000000000000000000000000000008a21fed19e9ec2a741ade7767b0c9f39b79c3fbe34aadc9eb3043583768d893bf927d26231759290c7dd9c4f158d5a10000000000000000000000000000000018eef4ff88d63149d2632c9db586a4af0606644b16c82fbb0a3b869f1ff924c59acc8efbfde7bc604497ff68939cdd0845111c860f6f5725f99b225c53b9fe1a70150e7ce922bfe214900aaa2790d145", "Expected": "00000000000000000000000000000000122e1f2081cbde0055fc34d2fe61307bc333b35a1e0772a0cd6fb25338c89824bcf2f066bc7b571b2fb314ca7f45106c00000000000000000000000000000000027ed81b54372d858a6ba2faa65fdc132efbca6ddcd56c3625bd9267cf0ae04f6d342209b995060f584be8d40020669500000000000000000000000000000000002a03427a093a3000a1bed9eba91a82dc2f2fcea1a16a1fb8af29c4988b589abe6a505ec87a82864b3c683beaa6420f00000000000000000000000000000000134bf64871d69a72e42766c2903fb4589b84d7772a62f7d2f8f8d02a914f4d3a278c680c626ef4d69de8aa88b57589a7", "Name": "matter_g2_mul_67", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f5d47911596c46c0c08cac5f5e7f6d0609874da4ac1bd4e0e59c393273a5fe31a756c7cfff2a01d19e79d209d7c6d3e000000000000000000000000000000001010f864eb6624132d4436d18db7f5b34727060dc426c109886be88031e3c155490cb3fb09e1fbccb7912875477c6d840000000000000000000000000000000005cfbf1c2ae1b80a8c7cfb2cefedd907b0552794f4fda101ca1a723b18de8cbce30eb54287e1847cee3f416cd8b45f2c00000000000000000000000000000000084fa63781f7eba9c7e911ae5866d485bc7e90603541c55d1ffad8b3cf7547fd57fb24b14002560e58410b828513e109c07041840216d60ff445cf53b273a46016c8ecefefb53550f8bafc79966f863a", "Expected": "0000000000000000000000000000000018fa44efeabbd1cc47dd9b1a1195ca921c99c77ed43a44502aad27b6c663f5ce2623382c3ddf208f42e3eea741281f4300000000000000000000000000000000138d11e497e3c5656bc8fc0ae4322a0bfb6fc20e249a47a103b164aa3d9fdbf7df4b1e3b0842b4b12568a31992a151f000000000000000000000000000000000182490d6ae35c1208c0d608984df4988d057f3ce5a25073c77cd5b224a5892768badb1ad5cef8f41d1d2022573098c320000000000000000000000000000000002a6e0523781ccdebb75063dc7ad1a9526f9ff8ea1364bae487914f254c0eebcbb2cfc3715fecb9599bfc2f5feaa62d2", "Name": "matter_g2_mul_68", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000124870cfa469136c638e0cbf15802f2699aacb66d7e4c2965c6759dbca4b7e47941ad9ec37a84db1afeeeaa65a7418e4000000000000000000000000000000000d4503049a6a53536bdf41dd832a6ecf3f10554887da7e389cf940394e1d88db94369b7947436546eb6c6e82c48dfb9900000000000000000000000000000000053f9a6e1f05b67cf553073358009a172e2ab8b43572a974da1f3de85a29103b13d7e67b2a359297172d27dba5c61439000000000000000000000000000000000abc29f50ddc1c113c73700b9b9796890cbf48818ba981fdab2db27ef1c58f4c2e4595b99eae397d40990ce2f6c9317c29b031b82dc8c9f4ea9524793b54207d4e13a548d73297f2aa6241aff57abfd0", "Expected": "000000000000000000000000000000000dc7488491433d5b3924105c01ffed4f30b755d7253d867fda595e7d80197823e56e4d182d5ecc72d8ef1ba9bca15a310000000000000000000000000000000007bfeeadd6fc468ef6340a2b394c155bf50808cb11e89adb0de5499fbdde91760e9531c1deb23050286a15e5910f1d5a000000000000000000000000000000000f096db706b08485fd577f37b7bd232b5a10c3f80c25bcf82f7a3b666c6efaac8e856bfe5f7dafb7457e33eadcb4133d0000000000000000000000000000000004460d1f25159ce6df59efbd7c693355af4634dadeaee2ced68124b2a887698c10e9c4b40c4f4f9c8444acb881ceff65", "Name": "matter_g2_mul_69", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000007d2aae9794b7a7de97f7146c0ee8415e09e56fd42535bce6773cadd6f7ac09c4eafe2e926cb7014377e54c703eaa9dd00000000000000000000000000000000172a4a33ccf99eb0473b2c44d30bd53159afae0c7706ad128bccf6258974d5e5761f9be43e618cdbd96027aede7fd5860000000000000000000000000000000012601bce2171c6e4c2968a3efdf1491285f9e4ab37cf973ab5c8e224ad5b40e1b6459ac89090c73deb8fc79fec7fb8e200000000000000000000000000000000112a6443116e6f98ab348e57daa3971b5fa506e40515e1611fbed3e7dd64c5c1e991e0d2539a70eb93e3da0f573d6b2263d26ae92119c7b06d83d7e2922e06559b1740eae315c6623d3e543c9bf54258", "Expected": "000000000000000000000000000000000f1aa4a7a22c568c41270d24824138bf9ffc763a5356b7c0bc1d051a0a0db12616700d9214972b63eeb2a398d27dc83f00000000000000000000000000000000020d0c2ff8f93db6b415c2a01712034e46bdeb6e665a5177a3877db9f5401d3dccb99907ef843062e394c1428983725a00000000000000000000000000000000088abeb6fc3ead45d5b261b7d684f168ca8f5f163cf338863e6b102dc40e2cd0ede97c47460ad6f560c27e95c8b71ca8000000000000000000000000000000000ca2e5cec212d581c737928512118e2f51a0d74070f40a998b7b06d22b9fc754bb2fa5499308058be9ab81521d057414", "Name": "matter_g2_mul_70", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000030372914b83644fa4db1958831e9335c72ab7a811fb337696221a3290e4c54bc10c2225f8fdc3a9f62632ba2f1594500000000000000000000000000000000114205926609470b6022d24046a1997c048e6d2cf6043397892c967692161c0ceedf409bf5e1199a64eabb1ff8de23640000000000000000000000000000000017cdecbe73779855b7b94920d4bc8ad057ce51c5481a5579650df8a5bbc421030d2ac44568217c4dbb13d7c639760236000000000000000000000000000000000f194fa814bfa7396697bd812d9449d06fc61b580d7a86429fdd1ad376e21ceca139356d7d13964c3c684563675711c67a02c61a7a75342ee7f0745886c0ea2a73c21500aef8078d21d20b7216c2990e", "Expected": "000000000000000000000000000000000cfa23c46881893f6c50d238a83669deb520a7fffab4f912f77df7cca43f6827a1a0ae0b3f36c8f116ecefa33b8bf37a0000000000000000000000000000000014b7e5c18d2f9bfe15b0c1af3bc6e230039a341e135837d123e91cde9cbcda298c66b93f692232c912e5d7d3d6331c430000000000000000000000000000000009c8984999ecd3a4144ccb925d3e5cae5c1662dfbf8871013b1cb2946482fcb075c489c61b8d6261f2574b44da3fc1ce00000000000000000000000000000000196e7feab383211e4825cf98219c63bf9f45a72d66030219cb585d5d25237a01a97f00e122db6a51325022e69e7d8cdb", "Name": "matter_g2_mul_71", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000015d4ae1521acf897344c3a76261754ff99742585af4a0ee86dc473a88fd408091404df1da9d8bb291db68bc9c07d6b2b0000000000000000000000000000000008ce160213875c661163990f3f7ac219ea295db5e828354864517ea8689ec15d35c6df78ff14cb276e0c97ffd7fbc09a00000000000000000000000000000000038a3ee211e777d6d6b7ca6c7a0d2130f1a071c030eebec412c3a0f14c3584e7c5cf15de254a8f141a8210a90249ee5a0000000000000000000000000000000019f7ec6b2fcd8b3190ab37a6e843340d3f3fc092f5772a042edbd5bdc967b96e8a1dc9e435b8463496aa1301f87d0e5a81b0c87102055dc2901826875d5e85a794befd93fccca2b9c0a1f70ef5610d83", "Expected": "00000000000000000000000000000000005c0282830934ea09c9f51b52cb6dee75b874b155c63076dbac2cbbf220863d55557ff1b7d681fa185435df1522f49d000000000000000000000000000000000a1680ebbb185c8e7d8a197a523a7a5e618f97c46670622034d312b3eeef140150e03b00ae3dff8d9f1d872f3d3dca380000000000000000000000000000000019bd2eb4bc25f5aa6bce206f0683dbbbbb002098a118fcfb060c1353a310c2baa1063a782bafcf6ff6bb8edaf6f1597a00000000000000000000000000000000082edf49a0435e0b9f3dc7f207711d66004ae688b18f5b62fd1596899ee8edfaac7da38973d81f12200018fbe8151572", "Name": "matter_g2_mul_72", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000fa7f8fbfa1d4ef5f001a451c55ed261dee344025e599884b29d086e15665867932120d33bee579d5eb1b7e6c7299f310000000000000000000000000000000001f06356f793350b17b47a623059a068800ca1eab6089c7c146182990063e8e23bbf40d95a42bf6e976224b680b75bfd0000000000000000000000000000000008807f6606d2302450bfd8b38fd4147b851ff59762c1ff48f9442c4d7b77a32c5e023821eb47fca839a27fde60e5f61d000000000000000000000000000000000c5b92f1ca9c20d4b6b11d794a5853824cff20d9267a20a7aaa4bed8bfdc728c4d4d50feb8f0b569757b97f473138db1ebf66fce49c6beb12737fe05e3adc0a51ecfa9144ccf6253088dd1a7a483de07", "Expected": "000000000000000000000000000000000b8a715c1c2792a30f7ad752a808b621c34af1fb7f1e3392a36ca9481a019108a21e3ef338a1d05f2f23ac3e2cc42ed500000000000000000000000000000000101375c9de592031c55a7a62189fd3fa3c565abf7c64724796dca3b1c7a6e6834a16ef1c4e2afd6ce2e69487260f0028000000000000000000000000000000000cd385ec8245431d3b1aff88453db7f66a5d7888a5c1e0dd0abe9ac7db752933a343b8be53b7bfffb704768ef0a3dc5c0000000000000000000000000000000015d55c8cddb8715e25fa260d1e1fa672ff76eca7c80d19d00678fb9d08759b810cf266ef0a7e9dd749a576ce07240fa7", "Name": "matter_g2_mul_73", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001191410ec6c5ff628bd25d35965f5e9fa7f3c3d8c0a9a1ee7ae37437a97c25e221110d892e2c7a0e9c8e386774eadb80000000000000000000000000000000003be30c25a18cdab139277232d8888f6d13112c9556895af8030f1893114d5845d895df9afe3c6f9ff7ffb1919adea9200000000000000000000000000000000197f6b4e38be0358a3f1722664c61e62587ecf5467f8aadc3a236b47682a75cb76bafb18a5c556b321d5da49cd4bfd4e0000000000000000000000000000000002e4ebf7f22d929b7421a600e67fa2e64a59edd87a2e2eb9dce1f06d3c793f1a812bcdd510e654d44fb4c1de8c64ba9f0305523dc79dc4b905e65587fbd095ed57aa42403d2df5dd489db8f50c99e9b6", "Expected": "000000000000000000000000000000001311de31229f1825d0bd2c9d726fd71e05828a20406a4705ea65f441537486338022bac4e552bf3c25e15717bee00ba400000000000000000000000000000000052e082cbe36c854a028a041981fed87d39fb218a88208aa1096e260a3932a1155db7f306c32d133070b0a5bb6d161760000000000000000000000000000000003269d4afd20002873f4305018a4432c1925eea28486d657cb458198ff2df9d304bdfc7455233243b1712d8663591d460000000000000000000000000000000013376fb98929cbe7f7d090d1c9d5c4f6332bbf25470aa03c35a70481931e4bc91c937029a5e11d2a3418eab698361227", "Name": "matter_g2_mul_74", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000011c6f1dbccde640f63ad7d40089779d01075e26269421b4ce12fa5341f58ee9110f17d08dc1052426f2d00da2dd70b4f000000000000000000000000000000000740b147bcdf06705971c113a5cc12fb37345dd59f2cbb5ff500ce2b347fc5a8199cb3007a871670d5093f28979cfade00000000000000000000000000000000046563ea98b5e85b3c42222d5e0d8481e6aefaf077a1b99f2b4eefb397ec846aa3659aacda569054c9c8b9b69750272b000000000000000000000000000000000812d887943506d68e3525ced9b979354539b7b14003a3169e0084c26326b92be67346920c9a99ef0f9638e8991296feac23d04ee3acc757aae6795532ce4c9f34534e506a4d843a26b052a040c79659", "Expected": "00000000000000000000000000000000021166263d1a443d5b2eee9aeca3678ae4c2b44d556a7cb9631d47e4fa3bb05ecb94d6582f4ca0cd787027fb5f2efab60000000000000000000000000000000015335d034d1a0ce78e1246a16e35e0075f73d4a392da1e05c11388084cf80bf31d499e57c48f4be6e72d3abc7b387ec6000000000000000000000000000000000deac4ae1900a4e1814624fb4b8c7a3149fa9cff2ca97f02e7d6765e034a1532a7b8475ef7aef5ebb851063cf4b9e79500000000000000000000000000000000161e3af03f226278a07ff3b08e5788f6c5029b2c8293e7a7e3ae11c4d78676b60dc0208cec6b82e1714d976007fbb389", "Name": "matter_g2_mul_75", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004c8078fe8567013e8d05a546934026cdeee7d485e30d739407db16fefaef53ed7bff0f9adaaf064aff014ac919d91c600000000000000000000000000000000107cc17f485af7f22e07cf14c5cad6368323f720511fc9dda677b360567f769e47a77f61274927ef9b7be48a77357ec40000000000000000000000000000000001487f0880a6cbdac33ca35b9b65e4ead9d8c2e9180c993bdb2052060325aff8c62668c643f0cd9b4bb1f06a3dc74285000000000000000000000000000000000d4b2d062e31fabe8d2a329dbd6417673a519f455739d140246f2b3e43e20f390088c08e545bf0419d796ac71aebb5198586d7ad8fc3e4fb42981a4415224c0d976ebe1c342e9bc1cd66d35168bae33d", "Expected": "00000000000000000000000000000000120b4434babedbd8ff295a6e2ed5fc7af0548d7e60663110050be797584c0cb638988201ae7707cbedf0c8b3dc5ced85000000000000000000000000000000000d2de0a260bdd241a145e3f68a6de48da4c65107a500e02bfeae6ae7dc428026c7c3e9bdda9a3069d2744705df2eda9b0000000000000000000000000000000018a237906c0e277541c4f00c4c2feba7cb2c9b87709c18b62b7c36d78fc118cfd65c127765e01dc0ae5875b9552bb45300000000000000000000000000000000197485daf54e98e097b6bca24b0738682969256decbf3ebc05f6982e4608829f37e2877937b3f26b88efc3deeb4bfacb", "Name": "matter_g2_mul_76", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000811e9b0acfc10830c074c5a4d9f4d9382461eb523a61dda0b77f1c43b285fc5c1ef3a1fafd923addc9a6e904505a255000000000000000000000000000000001113102d015dbb509f0b8d0d0ebb4d3711c4f0e1e3d55fb0af247dd24be4fec9d6fe3ad73fbdcfe206891bcebefee4dd000000000000000000000000000000000085aae9e58fb97b96ca3c089acab7bdbd0c3adae141bf61075f5c13145b0d07113f1075dfb959bc7c2d3d3b3a06ab2a000000000000000000000000000000000bb5eac8125807c10270d94e5bcf278241d6fa82f68e41b5529b28aebc88870af55881db526f7bd221a8c4c0b29a1b7d6e7db0fbd2a7327c85054b4c0de9727dc0b051058f8bb4ecb1dcc7f825781712", "Expected": "0000000000000000000000000000000005de82540aa67c69b962d292133b09e6593961da8944ce02557141abd19ac471f766b4083db85c67a44b65dad2202488000000000000000000000000000000000cd999bf3cb004074fe9f355cd8dfaa7b9d3439d902fddd2fd0688419b5b7f8c4300ab26b658936a90c0b8e1488249d1000000000000000000000000000000000f97ae779429a5afaf7a3343586eea84a4e76f00a1852ce42a4940babd565bc8d61bf72fca9b123922f1ccfb1db8c06b000000000000000000000000000000000935960fa941c27e74234a07857ee680f53c31047235c6152d1669724bdef37ba642cf4e0dd355443ea470e6430def8d", "Name": "matter_g2_mul_77", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001335276775545fbb4c701beb57cb34312108c9f1d46b4aa4b09a16faf0e648b4e80848bf5e75ed8730715f0107afc9820000000000000000000000000000000006ffff8736bab41b4ee5681b741a81fc870e648001027161144254d04c678e4f954e9f191bd8b26201aec681cbf0654b00000000000000000000000000000000026ede90d14fa0885baad21f9631bae058573251cbef5757bb8cfad061f3bdc78834fa5862dea19a2236c014b0f1652e0000000000000000000000000000000009844d0cf7f6f3401145d8d720defa577ca46b49e04e39c4c139ec6811a574e7dd5ce3acd00d1ce9496f10dd15c6d94685cc8d88273d4aa822f44a447cc22f5a58c420bcfe757a459772825619669a72", "Expected": "0000000000000000000000000000000001b0aba02b0e907c03d2f4003083c824ce60f2f55f70dc6ec7c7f81f3d0ef4bf533b4c94833e36e8aa7aeec18b7255de0000000000000000000000000000000004fc227a6ae303f3006f75193cef7c653e6bddd28fdb843b41c7d39966a701ba8fcf611efa71abf059d7d98833480e69000000000000000000000000000000001077fddd0bf3d5c80eec653916f9095e900cf165315d74a872219285f62b5412536e43c4cdbc120ec5c7753318852dfe000000000000000000000000000000000ccd90e01c1d4a00f0d9e29a88e8134f2cf68162da66bd343645a998730190114a6921c9b048dda58b60b42a133287f2", "Name": "matter_g2_mul_78", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010192b925fca096682acf138833b12d96bf97c9a2e69e4266eaaae1785b9008f36082e23e2d42341427edce24449935f000000000000000000000000000000000d5b24a94adadbf542aa663114096bc670e1b6c99f3b661f55de121922452534faed7f68d6b431fcf6f3e379d7acf6b6000000000000000000000000000000000acdbcae49206b749d8c0d21017a33e689ebe26804d1fe7c863a2ea4210c3559805dcf73685702bc56e644b4e02614a9000000000000000000000000000000000092309d684fcdf44bfa321d473060dc2d8a8c66c51419894a3fbadbf1b56179c31dff25403b970d543f1dd0e19e56cf5b6e462d809f8bf1a62f276dcb27e42d9aa0ce33fc4e149e87181aca70a4ccc6", "Expected": "00000000000000000000000000000000185520023714580a3f235e24316478b8260565ffabd39670811519066844e131e337bd62ed2069bc6d2305e6638e539700000000000000000000000000000000055fc74cc7cd3fc393d5b5ab2419414effb783ff4da2516e5465a4acc195339c7b5238be4e0744b3d7fdbce46ca7f5dd0000000000000000000000000000000005f584a0311c02d611c15163529130a2fb3dc853083e7225b791ce5ff32d5ef7039c80edfff317ce9ddeef84443b5a51000000000000000000000000000000000f9d5acb355f767cc6286cc09f6df232532f9a0e9e4ed1fe28788abecb200e22066c23f3ac6c49c47071cbb023e70183", "Name": "matter_g2_mul_79", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000014441b14765eee30e8131a7ef62c3b59370f2f6f0dda20fb2a3654fa09492bf695de1d1a8f250bfde3c7d2ed805ffaeb0000000000000000000000000000000019d813f8be2519e89d42a9fd3fef09d44a996d6a4713a9c224bee10f0ebb196370d6231fad810edf9cb4c875f08357890000000000000000000000000000000001a5abea13e909bbefdb51ddc699614366f271b2f6490ac8efcca7759833f3feae11057ab1b9ea32311e7b6ea6de110c0000000000000000000000000000000003ac2bf3c5486ca176e34ec5212165cbe04fc9e8c375e3e999a31fe014eb824ea3f2d06b9cf8b86ce3a76960cf2eb4d7535b53ab5f1c596eb966f57867e021d0f3b099e17bf384479c959794b17d6a4b", "Expected": "000000000000000000000000000000000ceb56d75f3aa1548c50d7780ea1e33c3d069b2f37e7f96be6a8ec03266fa8d0868822afb3b2e54750722266f6032a8000000000000000000000000000000000080f15b7f9f2c22f1afacf558267b5b84f3a6d199fd3349eefa2e46c4f332849c0955d19d4513151dc0f3b566c0058440000000000000000000000000000000013305f8ff6080f7da05c28155c0c2bc1c78d855cdcff0bb2c6b82cd5107d7a070d0830e6705f6832ed5baf75a659c8870000000000000000000000000000000018f4e136859b4ceb230450f9abde0325a4d59db98279d7fbab710305ff53250dae1c8789cccc27586c9b9df5c0c4722e", "Name": "matter_g2_mul_80", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000598e111dcfeaaae66d1522be2a21131350577253a3f33bdd74a04b0bfba2940e73b62fefa8f0c34c4aa91b633f6bdfd0000000000000000000000000000000017fefff7d94afbeceb33714e9b5480c3a2f3eabf9d7f6e8507ae54cb65f69b21cd7d04d23f24e3a272c589f572b91864000000000000000000000000000000001652e3f5a99ba8dfbcd1f90de955ef527947642054be603c1b84b24bebb579b78e2a0be426ec21d32783a0e55f0178dc000000000000000000000000000000000a6c9ec91e8bc86ab198416cbc76239f0ac0b903f40310ee1f2066b01b08191538ca913c2736f53f23ef37fea13d52756e0512ecbc5a1b02ab19bc9bee4d3d9c721278e07b7a6e389c4d6443232a4035", "Expected": "0000000000000000000000000000000002a0214be95f020c70221fb4fb6856af7ce3845a4b607340f85127b52f8a204efcd94a152835860a4ddeef84946671b1000000000000000000000000000000001767777740a9922a91c39a36e2cdfcd544df902b31812ffc88418dab7321f73406ab142055b5bb264c187f2d4f2d6f9d00000000000000000000000000000000026e6941364c74997506df0f9fbe6b2769839e8b7c7293f4e63d13bd7bee90ff779cf82adc2f23c569d1e13826cdb0e4000000000000000000000000000000001618ab2ffd4b823b9c9776baf849641240109b7a4c4e9269f3df69a06f85a777cb4463b456023b7001adac93243c26f5", "Name": "matter_g2_mul_81", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000072e022c168461905f798e87425f2eebb517e473cef98c255d0fe434863ef5811920af65bc946b29d489b5dee1066c56000000000000000000000000000000000e7a9872caa82d191f6014c845e1b3ee4ea1ee89852b546a2c85ddbfa3c1d4ce99002e3d7732ccb8cfbd57d550285ab400000000000000000000000000000000144be65db373f6401d76e0ee64e51076b861e8fca596dd6a7f3b5735c23b0cd13248404fa0969ecaa701663a1032f48a0000000000000000000000000000000014c9e9c5cffc4518889f7742440053678ff1d9fb1a1a103d0c1f762b10655bd5849ce98f4bc5eae80bdd9e767aae4523a79fd15e80b694122dddb01f836460b3eff99e61ea6309d6b395c94fb5a43dff", "Expected": "00000000000000000000000000000000054ce66b9b0b3cff6637d6cfdd788719d4e33516b98402d8fba54725309307711fb576299ba99104d4e7df0deac9ea2500000000000000000000000000000000055e06ff52cda9116a98ad3709f788d39db53844b7db58a57af52848ce1c59ec2a1f083efe79c5994b9291a2d1020fb900000000000000000000000000000000040c9ad63698ec78d06b41bdd6f5eed089b67f106348f9300f822a2d61ea1e5d2ddda0efd1025825c99cb0e243573f7700000000000000000000000000000000195dd00c48186f8d1337ca857aea02c4d199d638133e9cbd2dfc5f633502f656343746ec2a416465c3c0d4e9d53fd097", "Name": "matter_g2_mul_82", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000948d0f0c20715f8658e1f2b4f9d32d851e584287225a2f47735a1f4c241b07f8d7c5dd8c13bcdf84e97d49817d4d88a0000000000000000000000000000000013c064548cb756b48600dd535af8eb5b9138f984bac0391df2e90a204fcb6c36017df910031864d802a2ff719856b336000000000000000000000000000000000000b7eeb7c9a01be88e573f196c2a531635baecbc8cff9af385455af3757301436686596ec7fe3618af26953c49f7450000000000000000000000000000000001332f4dbd5461ab9e2c8b3c19c6ff407a071018c92d2c17c1d1d481c24565276c0f55eee8692016c1fd76d70f44627cbd012914a96253926fdaabec06944ffcdb4637a05e3e78a9bcf1b21b68b9dd9b", "Expected": "000000000000000000000000000000001141b59af8fe6cafdf2e247fcb0ee4642a9b4022b6d71163ec9b6ac2f7d10ee3c5c0173ac686b03cd6a7086b039ec786000000000000000000000000000000000f05ba6973c5d865ac5c037583b65eb4eac826b5a04a7ebed1e10bec6ec7dca93b1c2eba70ee0189fd552d5023f2a87c0000000000000000000000000000000002e54475940985ad2115223c5ea3a4c95890f3e9992e3e1a6df2170ab77143bcc5d29b9dcd1ed3bf16e545e9be21a8640000000000000000000000000000000019acc4705955761518cea482b83e3726dea8d1f66a5f19b06cd7ff95828e15d1b139077e0d274b0e6fb86c027844d97f", "Name": "matter_g2_mul_83", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d3ee70610b5029a28e586f0f3e65bb19a263db3438710fcb8073e1b25f83db50eb5bbb9d75cb20952a225023f747baa000000000000000000000000000000000682f7d5cf9d182b20ee88683f3915e8c9b03074a373e573aa57232de4e997bf155acf680e365aa0988989dfad102b2e00000000000000000000000000000000143962963e230a9154dc328f9583f5be6923a3b10ee7b1d0cd5f5cbff13913d8ff78ca315be7387900a50b94449884c0000000000000000000000000000000000f4f934b42452d41cc20d7b1ec547bcbcbcc10f215364ccf2b864db23a09d06e94c7a87165dcb691f4975323486757ada300c7e1041d94df0e0201e1135fa6eafc98bd33b2dfbe4c59b546a52538c07d", "Expected": "0000000000000000000000000000000016fb5839fde95111742255b33f040c41dbd0f142d1daa8abc7c63008ba9f63f07381d9d6128240ae9b6cac5befad84e5000000000000000000000000000000000389a11727c356b8f3bdb6a73bc2f6d2d73d33d287365283359521dcac64f17810bd58c0ec5bef4db253bf630bdd9599000000000000000000000000000000000629a8af1bd0c1b1b6d7e447bb779663d7bae8e895e09418bc350e644d7022fa877496f30e2018f5dd1c9683b2715adf000000000000000000000000000000001950185d2574fe0c8277e3f93f59dc5628ec3487911ba9c3194a2f716116ff0bb9a39dde802dcfaa61633ad7657a578f", "Name": "matter_g2_mul_84", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005f0fd4080e26971ab16d33aeae04220ae23781da3179e38190082f1d167514bd73bc8ef976a2f333570e9f56a6c05e6000000000000000000000000000000000e159905d29b52ba61575c3a263093017783e1028b3701ccf060c165ba33a765b5265a9b1681c1759bfe2c9c401275e9000000000000000000000000000000000c5ac0bc29a49a7c37d772954da850e6b5e301e230552be9a94017d770ebe2cf4dcfaf104633623e024aef6db57892900000000000000000000000000000000002228e7f42a9409acab49cca82cacf306f6c6c29fd9f7e2ed12fef2d16383cdb7bb2b39ad598b301072c615232db1fa833e9cdb10fc117afb17803b61a2bca7de1d190a325639eb23743f51f28294b33", "Expected": "000000000000000000000000000000000024c03edb9b54034eacca4b321d51397348c57f406b074b16a9d6215e03f842380f5358f5c095fcf5bf3cabcbabdc260000000000000000000000000000000014e62dc442135d729f65090475fb408ebae132cdf2c2932582af887ed54696f3cd15b163f11285b99e8d8f809aa2e65d000000000000000000000000000000000438a2c99df216c67d92b99d9ee8cbd0e9751e538074d146767bde9675ae3a05bdae051efcdc6bbddeb1b7a8288370ed0000000000000000000000000000000007c462a8f5720e442e1917bf75fc3c3dafab6c39c80d0b93d81d1db4080f6e199be092b4b025e7b02efce4f30d00299a", "Name": "matter_g2_mul_85", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000180569ce03e4a0155285e733adb18fbca71225507a7adf01cb8e8648891525305e92087f58378f4fd8455d5632ad660e0000000000000000000000000000000011ab84e42f10154e306a568d7cf7bc381000f0add0500cb508f695a3b283ea69d140aa0ad48fce2d2d6fcafe60761078000000000000000000000000000000001136c3016474d6f475609606e8d0269fcdab9fd3188a512681cbc41eedeadfa3b3d9355e5b4503e8b5c3665e49fdf3ab0000000000000000000000000000000003f56cba1b9cb4302099b16b09c2602dfab80d1151685ef78e5054cd454b319adf8b5998053a5b9fddcffa020595e3bfc48b98edd9c229037751d02e58f3d4234d9a3b0ad9ae4947ae14beebb274746f", "Expected": "000000000000000000000000000000000e8137c15436264b5960c27d0c22be7fc5d56a12f43b3832ad0d7f5abddbaaccefd140e2f7c476b99e6fd9b3a52743600000000000000000000000000000000019ee3caa56f0329a2e2acb8907b3edb21f4eee73e312352796b51282e097f9b10af61805d5c222332888737c7f8e227d0000000000000000000000000000000012cb9c610391940fed7882a5cba08eba4226c36eca8a2ed22fb5e752e0a1a5ec556673e47013258b499268f1de77bdf100000000000000000000000000000000031b769f606fa25b81a982db86a1cd442ed738019e7e64728ecf485cddcc17d9dc271146196178740b9f05f56627b061", "Name": "matter_g2_mul_86", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004d79dab9eef873f3415d66172bab7166ce0c71f322529bdeffa915c1b0d3fcd645c91dd3450ba61593ffecb95edb91e000000000000000000000000000000000d611a207d3222bba199fa083d0459675cb5fa00839fb4c9034ad868fc1e79d653c18651771431d6fb6b6b5ce8cf6f7a000000000000000000000000000000000ce802ecb106a4f0ca4efdcc058dd0e29deb6a5d30a2c15c8eda896bcdd3ac19053c10105328d239b26c5ddbdb3a95fc0000000000000000000000000000000001073e142621ecbeff6f81453660362545751f992ffeec3a83477fed3e6215a709ffe0d17b65d3369f8f3913bf000e844228758d2cf8105f2ef11d83018157a3119a44874dc34d5f0bddb533f50df52c", "Expected": "00000000000000000000000000000000080807a0570b628549629d2eeee39de773badaccefb76e01efaecb0ef0356f535d32c3947f0613bc7d847ef8c8778f02000000000000000000000000000000000e8c091ea30465d204ace72015cbef29645206390fd92ba7c4aa0fecae4ecee53c0b06e1fece99511efd8c7e9cff1a8c000000000000000000000000000000000c881c678c94d80164bb3295acf4341fe6c726ca64a1a015c890450e719b85720f41f80369f99ad3e7e3169ede0113e00000000000000000000000000000000008a2fe01a7100afda40091eb0b2b14cd00b7a4d8bb5cf9d9a3847970a94f2035fec7f292c04c38d7e49890e612830aeb", "Name": "matter_g2_mul_87", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000bd84f04b3858b1138b1b429c7216d5d1b1e99c1e0fec26440d59b1ad79788c2d5583122c2ad769fcaa6d10d816a1f1e000000000000000000000000000000000387977ed1ce5da51dca230531bba53d17d3de5d593ec576cabfe6463d5164d7153025dbd4cb3525c4145c4f6b85fc76000000000000000000000000000000000a19c943a90fec6921367a2edc5bc38a5c59839cdb650766a2d2d068242463dd4460bd1d0e7a7fb0e3d2104704b8b3730000000000000000000000000000000011d99d44b200feebe00bd42809e3f67a23cce88a07165416cbfaf4db14420f99e54d62db4280d2c99ca0bc3dc41eddbea417c96f0cf4355a78513c77cdc676a7b09125802c8045756da867e0025a36f1", "Expected": "000000000000000000000000000000000d17f6d9460566d0543df2666d6ade685565e668521a87fabc58148343085415fee92c32907311c9d04713c34bf7690d00000000000000000000000000000000185da28f07b86885031ff5cda913a85b0e4d07673f456ecf2a9f0fd1b21d99e22442f9b705039252d57380b6a42912050000000000000000000000000000000014a4bde5973ef43691b61b3c0f6c2fdb4bcd6ea88e53e2787a7d93ad6e05ee2e69f2799712520f72b3c577ee278008ec000000000000000000000000000000000d92a565b3d8d0fded054a75198b31c521e3223650cdf762fbf7b851f7ac0fc66b8c86c20b905117585704c23b27e7db", "Name": "matter_g2_mul_88", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006a186aa584a466a860849c78e4922889c95a4ac6f39c99029fbb422c43d699a8baa51aa4ef51ff99557babeb3e9506800000000000000000000000000000000065fb15b5a0923bdb52dbefc7e9f1a898e32f17d610bac829235446fc5e1913fffc8176e0fbd33091505761f1d06d8920000000000000000000000000000000008bd358698fd073f660ed608462cfcef1da9a59b10905f1d98c4fe66958e56802814906430c10fc25a4d351d91f91cb0000000000000000000000000000000000a53638b1b6c6eeff468e099446300ca7c7bd899c6494682d14fdabfa9cead0bb37a0325d99e7d0ba6341cfa1d257ba846561328b7689b0a89014823537cf9eeaca6ea5c56a3e58d2abfc2ee455dfccb", "Expected": "0000000000000000000000000000000008b1ebd753364a5a0a6296ab48b348f91668525c0d5f7edc4f2d29844592f34a209f9e77f94ebb38ba76bdb3f96063ec000000000000000000000000000000001062e0ff0a67372207052e2520d8b2823764a5075c94011afd6c60288e187ec77e08db01c95dfa195f2409b58c9dc4e5000000000000000000000000000000000cc2b87b613d97a716586f371c457fa869c2b8d1fa1cf4b9e8c34bae23e0544752b997df4711d0712ec11d3a9d96ac2600000000000000000000000000000000140eae891c87c2026f0b1293df2bd8ae2dcb0ab3f8de74676f37c905334ac1f53fe4b75511691dcf108fca51abcd524c", "Name": "matter_g2_mul_89", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001070b98c6348a67e996626ec2752f45e4c007e9c9668459a777c03fab633c10236a1c5be99f3fd950542d5648ef9e88400000000000000000000000000000000073a564401cb1a3a53334c0a55da261814d27b86ebf40b02a76b20973ba2db92e42c138ca7790261c2d70401c984bf470000000000000000000000000000000004212d8a9e4b01f5c6814a88561c2c6143eea61327b031a2e0e4bd056c12dd7098fdfe4d1511bb441ad42b55b584a7bc0000000000000000000000000000000005c5d23824b0fe05eb962194550681c57c1566b315efa8ebc90b3593d7d86ad18328baab8118c9f47eccc0757588591ccf6c3fcd4b9e6b72853934b306a078b1f2fb17879db4a0a93d484abbc2b746cf", "Expected": "000000000000000000000000000000000276a138edecfc9378be4e241d64cbb48bfa6fd4fb1788f8bda870d5ec8b2132fc9ec888ef84c43a50b7de0527def36800000000000000000000000000000000153e90d52c747859f88223555bc8bc4e8b6fc846fe7028de728a4dfa085c6e350f9f1d12b9dca4ca8e07377648544400000000000000000000000000000000000cef00e7217da6df0a6d85f40be69f154300c423e86e54e513b2491e65002e308445238082da69aa9e5e83b5f4fc17dd0000000000000000000000000000000008da1da2a0d1da9d2158b9408dd9b0eaf414d237b8219fa7661e40c1a88eac2f9735d0dd6ad67b85aab85952369e8287", "Name": "matter_g2_mul_90", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b1b3053774ad5515a20bd4c556d2b3ba95fe74fd0c955069c7f933dfd718ede90ac295f5a675f1c29dcd9701978353700000000000000000000000000000000145746ce88686021a0635bf6f0aa2f77c48bdb364cf4ffa804a57f95bd69d24eead05fbee24021c1ef57e1c7c7b894b00000000000000000000000000000000010ec4795a0762b86f3b83de1198698af67fd1b1be3ddef48f35cf82bc96d886fbb4c75064f51a9cfc5f61630c95d0ad1000000000000000000000000000000001465e31f58892466b8ae4b76a239d9f8d1ecb1834886344013cd1df0be13591798868d224d38213a6d75b02a1fde0ff2f6787b565e8d71be6fdb0c97c4659389c800a2047f668b366214adc716f402d5", "Expected": "000000000000000000000000000000001484993096c210c7bebbc4c0bda24b44a70e982b2528215c0e8578ea55f1181472758caf935aa0a3d6820cdad753e2f90000000000000000000000000000000011802324a6e03c3174bbe7261ecf3812c1a97e1be27269214f232274a3bf82775d47c5fdd70fe1c57155068b296d394200000000000000000000000000000000050f43c874c1cfb5fda81059cb7b4808492632fa20369dcfb611e503ded81a49dacff253e31d7e27ee84bab79e3c5d53000000000000000000000000000000000ef945b6f210fb09bf0ad5bbd4b5a6630f43304ddcb396807c967eb5146741f7432bfdcbd7e5f3d29917781efb62e6ff", "Name": "matter_g2_mul_91", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f39e731e6ddb7496448c912ae314e833d28208252c7f8e27bcf7eeaf1da6e2310538b4ef0d55401c6552e91fd70691600000000000000000000000000000000069d3612f924961f827497028737000513548ad8e104acee28f014e730d4752a583cb9a893e6169b71966a1c4a4ad2dc00000000000000000000000000000000090899907edcbd336bd4fdad0dd67c578ced4481a25b864b32aef920842689a2c23265277a6e1d4a1dc1b5047a9f79a000000000000000000000000000000000055ba64e2502baf68e46c759fca30247a080464eda2b32e7cfe539e545d6aac6dafb731c2c45749e50513979cecbeb5440ed91f6ceb2ccf87e4106a16227a3cd7b2821b4f3a6e629001f78ba1aa7346e", "Expected": "00000000000000000000000000000000028233bf12e8dbd8510f119be30ea1fc13b755c6ee3ca2a3637a3bf8f73776c9d1fe231b713396ffc579ef9320a05b150000000000000000000000000000000018e7c00b8047d64ca0c5df54486439c5fb3d1414c2f71cf8a3ed591b7c45bf18b37473daeeadcb625eda638885ddb9870000000000000000000000000000000018b89c9b6bf9ece36f1eac08fc35ffc9f7f964a0a9b19d495ae1361fb4bc98aef8770efb47d9961aff694b878d659818000000000000000000000000000000000eb2fda2c29c6761e35ca4c9772bb232ea0d297582af4f50ef76c0b74fefd414b535e356c069f54ef5224225e95be6e7", "Name": "matter_g2_mul_92", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000042f1c8b9fe81cdcabea047d0998a1354ce09d62a14f1d0e9d188e2f35f2e1845c2b090c5e157595b33108c67e6c184c0000000000000000000000000000000018e69d3564d4ccc0306e1e6b227b0f961aa9afcad59d4ee1737f980dc876609c59a4c6a3506f987467beba0764b857000000000000000000000000000000000012ce5883156588cfe0f4838f819f985b09f1eab40a5ea8e30fc5d70d029a01a4537641248f4c21dd203909e0170737c80000000000000000000000000000000002888eb9778a4045feb5899dda258657b9f41345731ba630fbbf186b3be4b58ffc7f48abb65b693b573a73f85440a7a7ae8ddfcdb4748981acb9b2037c017174a140f2457fb0148fe807fd194a9f7be5", "Expected": "000000000000000000000000000000001239935827fb2a269ab064a3ae2bff2555f89bb3a71a47ae815ef755fc1363a89d20326855cfdd0e13f6c85f727bbe120000000000000000000000000000000012fbba047478b5f5b07a582200271a0c331d6f76864f9b6c6ef8ae6b0965eda481eddaf72c7a887b21719164c633d39600000000000000000000000000000000017eb4353b413437244983554a639a9253d105395ff9652504df7700d879cd9a32d5f0824b1eaa532bcf2fea34f8f08800000000000000000000000000000000054ea45475c01ea0557fd143b21c7bdcab6d287bf6bf4f88b6fb06e02ac6fc5ba96f323bb1fda3a1c4d8f42d01d267b2", "Name": "matter_g2_mul_93", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000051982b46a819c74105cb36da871fb2415328a1531d155856f6551bd043eca62ddb61f24af429edda830fda31e22cd340000000000000000000000000000000006449e5bcdb5619aac542f6633ee3e06a4fd56a3e1ce4034efc608131ff6ead70ca63e70f494f519d5c577ae7119c8c200000000000000000000000000000000153f4f5dddd5801fbf7f88a735b9170d24d5b63861d50cde9644579dcff277cdb0d5fbfc3b3b819a1172de05afb9135b0000000000000000000000000000000010fdea84983fe6c08cdc4b4ccd462bae2ba791ab5209363b10b3ef342c9a5e92184e9d8be1419e3d88402bc05bad5fa21268803aeb58a2d57fc797358fb456d5cf96afecb1ee0d2b90782aa0d652b8c0", "Expected": "0000000000000000000000000000000015a145e379b7ecf4566a039b753f91e8ad75d9e9c9a20725ce34a900eb9a1bdf66cabee2100208d7792a963d1fb8c02f0000000000000000000000000000000007f0ca14fc4e34bbdf5008d632dd112c7368e037ce019b7c4ec412000ac02302c85ae64f9ab495361fa5b620e46420aa0000000000000000000000000000000017c00a08bba18426dda40e773d79733030b5b3b199a62436ed06b773fd1f10688e8af00e8a223cdf242bd1ebbedbf634000000000000000000000000000000000a17365cd9f7655793682b72e342227048da0cff88f6ace33ddab548ba126017e4b7f7439373a893e3b5803e662814b8", "Name": "matter_g2_mul_94", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009b011f793d9a939d916d058ffe91b58138820a646cc450389b3074ae3715d06ddec1075afecda71c65c7ca085210c740000000000000000000000000000000003d4d20f4b93c1e90a0a06bd534d8b4fd64e4c4aba77ae42cf4c5b2bd95f8b02ec4069ea246ff46404e6c9eac632fbac00000000000000000000000000000000051e88c3adfd4d6a02d3f03812362a6cfba3a6c69b9aeef75b51106cc7f1750293d61e31f0ea29b5d7aa56debb6d2aff00000000000000000000000000000000086d9c4ea6769cdf49ffbbf7351023b4aea640e8c90f9291222fd0b5984bca4d481bf7e10df921406a34804e6a09f99df9a8a4e5c65973b785c1e2637937de239bb0fde34b786dceea66f6bb12eb4169", "Expected": "000000000000000000000000000000000081b4dc78b74250a82da9d803876add659411cfb467860b2ac6f0f68929d6377deb71d6acc9ea8fc8c1286b8f92056e0000000000000000000000000000000002c5fde71346a255ee9dc896f654eb2e0c66f4cb4c51541d2bbccf2463ecf0085a22b9d2bdc5bef39d80c4477824f116000000000000000000000000000000000ebda0cd8bf6ac7e86a1bdbe44ed1e15f8ffa1fff92afd67fb564306882f35037b61cf0d93f278f15149c04a2e83041f000000000000000000000000000000000fc38aa811f5ec015f10a99bf175f1479d4983c9d2180a5e3da88b4e9b62ef50560ff0a6c2fb7bda4c46c54551f8390e", "Name": "matter_g2_mul_95", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010d48bf523f3909cf90aa58a9517ef5421f1212accd5e8a0f830aeb15a587e215ca9c340bb846b1d0474e43840b2af79000000000000000000000000000000000cc1a3976caf97b9d59f448f6d9f413eef8904f360c0cf912fe942b38d7fcc637a17038973a133608ae769d3e389b18a00000000000000000000000000000000069a6122c6f0ec68834b7617c755a7eb33a80a25acf95859da5ff03316447182f122d20d993b04e79b6fe859b7adf5a8000000000000000000000000000000000058c6f8c297524319bae6722e0a957d1ba0f75ee3a8aaf06148641c67925d15780e419a38ed7e07410e82769da74f2d070e7e2ae2751a1f71962726a31f77553c2da38f4fecda435b6e5459d5e833b4", "Expected": "0000000000000000000000000000000007b46fcfb2cd8efe32754306ff2f503d7434168c1c3cbd7c80470cc5a5c8bda10a80bfc0129da349724d2d6431c5ac90000000000000000000000000000000000e1078f4f4ca993d90accbfc036219507bd22d00930ffcfe1227780c00914fcff845698b2541510daf59cc83d8b947e7000000000000000000000000000000000b7c6d9951570e685d3a71b19a38f5485f974f85fe8cd4b4c196d33a18750b278b6d374483d81dc3e15c9b8b9b5dfdd6000000000000000000000000000000001003a239ea4a2f213f0f646bdb62cbe4f98cfaf7298d8b2e0eaa07bf3f939e779caab5ffa0033467c5b297166df657d7", "Name": "matter_g2_mul_96", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000156ca5e80be8c8c03a5506ce9abd22a9d4958c372678c0caf6f1329898507dfcb1f06a9464cf080bc6881fa5b7df1ebe00000000000000000000000000000000088174d486b4086b931010da298a399e15b60a113e08f571e096d3a4e94b57b3a684711318796eeca9319119b201abb30000000000000000000000000000000000b96ff68505c088cc03a1c2dc363b05bc8544728a12b29569bed137780523123eb17e68f4632383c252d81bca0c5ca9000000000000000000000000000000000486fc6e5224c5fad56234c41856e60bee4a6c1046f673bf7d5c1bbb603b141fc91074da5f9d3d41b796a2ebcebd9e74d16aa883a20307f5436354bab32b4633e83178f33626af3edb14f82724b8e125", "Expected": "0000000000000000000000000000000000ea29b1e059560fec21c3692d4e632a45c88a807c953fa23dbedb271b049d7fc717333b498ed12573a896f872e795dc000000000000000000000000000000000de0d10c47df92010a6635e3403dd6e91a1bf35bfcae82c1008998e86aa2d18a6cfd3f2f1207fde3bb39b723ec4d3ca60000000000000000000000000000000005e2aef9cd37430b15e5e76b2c7870630d255f630c12e865caefe308a39833e00319406746dbb2af3ed32135e91eed49000000000000000000000000000000000c229fad41b0d27ad7b5db33188fa70b97f22e323e429ef65fcf98f5339e908c31df8859b863356e0fc90538c5c49cf2", "Name": "matter_g2_mul_97", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000121fe97c62e068988ebff21d8129d52aa903afdbb62862c7fd99564d9ad72182ab1f3a1100223ae486cd76f6938e123f000000000000000000000000000000000968ddedb04f52140160061828b5f88dfd09aaf37df625ee6f66b9500d6608df31c7edf86296eccf8f9918b051a5e4df000000000000000000000000000000000b7491cb8f6252e3861d7160feb0afdd736d27886863ec0909a7cc711a9b71aace18b17a00a2999dd57ca1a74f148516000000000000000000000000000000000fdb280093ef45b12b694ca3390a865ee18e4c04b231e2c98cc28706d4cefaf4e654582ee03f34ecf1dfa9674489d553041390a2209b80f7c64d14965cc2f515d5fbdf37953f75c4a0203bf0d9fb674b", "Expected": "000000000000000000000000000000000444a00cfd258bd46f659b09eef17be9929008d3d1c65e46cdc762eeaa2f0b52abfd636e6094e21983fad8171194c71a00000000000000000000000000000000090833e68614be5bf298e04e44527480cb35128bbdecae15eb95d6931a718f66869ddb68352130b4dd8a921ab3f26d080000000000000000000000000000000000994015b1b55340c3839d48320d178b2ffaa0bbff038f7aa63d4dff41a217582fae9613bc537fdeac8d0670c0cf479a000000000000000000000000000000000fc486e2a1680c10ca28d4c3bb22dbccc9572036512645bf868e7693ae4591569c973f9ea26342a573e23a06c2fb4b70", "Name": "matter_g2_mul_98", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010d001a09cf5dc3276482185f26ef3f75d28cd6d2667eb08a7fe06c03b99f3b6c4d82390739b6867a314291cc642a8b2000000000000000000000000000000000587846a460b1f37c2e7f491f9a097b4e86e1943d9cd0999313f65627b3907f09b5d5ac1be376a313a959dd136f7e9b3000000000000000000000000000000000af439695556e86b102926d3b40e3e54cc84464e120de3b4e3c5541a6a5bca44151fb0594009663764c1824518b13f020000000000000000000000000000000003bfd9418c1e57269e222152d321b83ae090f216cb422956dd1fcc464f68526cb4a05cdaefc7bbe6e81d4ffe27d64db47cf23dee8d95d94046678f3bdb4b0ea3d4e3a1a2f07f582e2a98ad6eb7562cbf", "Expected": "000000000000000000000000000000001375bd5ee66c330796bd8381a26cefa3f40f8cc8de42d4d59a7adbcd3852e6d632422e6ad9a06a6e497b23b17b1df87500000000000000000000000000000000165d8e7be17ecae9bf51a773da705aea42536d0fa3a2206267da50451f5104ee241811dd0e6710a80c38df77b126c009000000000000000000000000000000001559572407aff34969f83c394d2b095a7ae9f53a8e6c923910f256bb87b6ec076fa6acb85465102fd24d34031f88f7510000000000000000000000000000000015ff9ba89b55ef75f63732dec1e64106d7a912a6657fcc970dd011a03b5364117cca46d6cbafbc0c5049db10fa83fe6d", "Name": "matter_g2_mul_99", - "Gas": 55000, + "Gas": 45000, "NoBenchmark": false } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/blsG2MultiExp.json b/core/vm/testdata/precompiles/blsG2MultiExp.json index b5b63625ac9e..2138db409256 100644 --- a/core/vm/testdata/precompiles/blsG2MultiExp.json +++ b/core/vm/testdata/precompiles/blsG2MultiExp.json @@ -3,721 +3,791 @@ "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000011", "Expected": "000000000000000000000000000000000ef786ebdcda12e142a32f091307f2fedf52f6c36beb278b0007a03ad81bf9fee3710a04928e43e541d02c9be44722e8000000000000000000000000000000000d05ceb0be53d2624a796a7a033aec59d9463c18d672c451ec4f2e679daef882cab7d8dd88789065156a1340ca9d426500000000000000000000000000000000118ed350274bc45e63eaaa4b8ddf119b3bf38418b5b9748597edfc456d9bc3e864ec7283426e840fd29fa84e7d89c934000000000000000000000000000000001594b866a28946b6d444bf0481558812769ea3222f5dfc961ca33e78e0ea62ee8ba63fd1ece9cc3e315abfa96d536944", "Name": "bls_g2multiexp_single", - "Gas": 66000, + "Gas": 54000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000019d5f05b4f134bb37d89a03e87c8b729e6bdc062f3ae0ddc5265b270e40a6a5691f51ff60b764ea760651caf395101840000000000000000000000000000000015532df6a12b7c160a0831ef8321b18feb6ce7997c0718b205873608085be3afeec5b5d5251a0f85f7f5b7271271e0660000000000000000000000000000000004623ac0df1e019d337dc9488c17ef9e214dc33c63f96a90fea288e836dbd85079cb3cec42ae693e9c16af3c3204d86e0000000000000000000000000000000011ba77f71923c1b6a711a48fa4085c4885290079448a4b597030cc84aa14647136513cec6d11c4453ca74e906bbca1e1000000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000176a7158b310c9ff1bfc21b81903de99c90440792ebe6d9637652ee34acf53b43c2f31738bbc96d71dcadbbf0e3190af000000000000000000000000000000000a592641967934a97e012f7d6412c4f6ff0f177a1b466b9b49c9deb7498decc80d0c809448aa9fa6fbbb6f537515703000000000000000000000000000000000031d84356ef619e688a10247f122e1aa0d3def3e35f94043f64c634198421487ca96af5f0160384bba92bd5494506c4d000000000000000000000000000000000db8fefe735779489c957785fa8e45d24e086ef0c2aba2e3adba888f0aeee51385a82898524c443f017ee40be635048c0000000000000000000000000000000000000000000000000000000000000034", "Expected": "00000000000000000000000000000000158d8ef3d5cdc8a1b5ce170f6eeadec450ca05952ea7457a638b8ff8b687c047799eb3dd89c2e3c6ca6c29290b64f5ab000000000000000000000000000000000807d135b6b007a101e97f5875e233b41f12bd2ffd77fe1195418a73a4c061248118ea1049aeea44750cd5ec83bcc1ae000000000000000000000000000000000f04136354f45a85a53fb68527bc8fbc7e8c1a0056878012b548a97bfdabcbd3fb8eb3ff187fbe65e1ce233afd2825050000000000000000000000000000000007b15428114e2ea094ba1e64df4c244f80aa2f75bbbf21a407bc84e80bf2a5ad787d02ae8a90cc1c137f0d898edb1684", "Name": "bls_g2multiexp_multiple", - "Gas": 126060, + "Gas": 103140, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000000000000000000000000000000005b000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3000000000000000000000000000000000000000000000000000000000000205900000000000000000000000000000000122915c824a0857e2ee414a3dccb23ae691ae54329781315a0c75df1c04d6d7a50a030fc866f09d516020ef82324afae0000000000000000000000000000000009380275bbc8e5dcea7dc4dd7e0550ff2ac480905396eda55062650f8d251c96eb480673937cc6d9d6a44aaa56ca66dc000000000000000000000000000000000b21da7955969e61010c7a1abc1a6f0136961d1e3b20b1a7326ac738fef5c721479dfd948b52fdf2455e44813ecfd8920000000000000000000000000000000008f239ba329b3967fe48d718a36cfe5f62a7e42e0bf1c1ed714150a166bfbd6bcf6b3b58b975b9edea56d53f23a0e84900000000000000000000000000000000000000000000000000000000000b7fa3000000000000000000000000000000000e7a30979a8853a077454eb63b8dcee75f106221b262886bb8e01b0abb043368da82f60899cc1412e33e4120195fc55700000000000000000000000000000000070227d3f13684fdb7ce31b8065ba3acb35f7bde6fe2ddfefa359f8b35d08a9ab9537b43e24f4ffb720b5a0bda2a82f2000000000000000000000000000000000701377cb7da22789d032737eabcea2b2eee6bb4634c4365864511a43c2caad50422993ccd3e99636eb8a5f189454b18000000000000000000000000000000000782c14e2c4ee61cbe7be6e462a66b2e3509f42d53ff333efc9bfe9a00307cd2f68b007606446d98a75fb808a405d8b90000000000000000000000000000000000000000000000000000000004165ef1000000000000000000000000000000000411a5de6730ffece671a9f21d65028cc0f1102378de124562cb1ff49db6f004fcd14d683024b0548eff3d1468df26880000000000000000000000000000000000fb837804dba8213329db46608b6c121d973363c1234a86dd183baff112709cf97096c5e9a1a770ee9d7dc641a894d60000000000000000000000000000000019b5e8f5d4a72f2b75811ac084a7f814317360bac52f6aab15eed416b4ef9938e0bdc4865cc2c4d0fd947e7c6925fd1400000000000000000000000000000000093567b4228be17ee62d11a254edd041ee4b953bffb8b8c7f925bd6662b4298bac2822b446f5b5de3b893e1be5aa49860000000000000000000000000000000000000000000000000000000173f3bfab0000000000000000000000000000000019e384121b7d70927c49e6d044fd8517c36bc6ed2813a8956dd64f049869e8a77f7e46930240e6984abe26fa6a89658f0000000000000000000000000000000003f4b4e761936d90fd5f55f99087138a07a69755ad4a46e4dd1c2cfe6d11371e1cc033111a0595e3bba98d0f538db4510000000000000000000000000000000017a31a4fccfb5f768a2157517c77a4f8aaf0dee8f260d96e02e1175a8754d09600923beae02a019afc327b65a2fdbbfc00000000000000000000000000000000088bb5832f4a4a452edda646ebaa2853a54205d56329960b44b2450070734724a74daaa401879bad142132316e9b34010000000000000000000000000000000000000000000000000000008437a521c900000000000000000000000000000000049cd1dbb2d2c3581e54c088135fef36505a6823d61b859437bfc79b617030dc8b40e32bad1fa85b9c0f368af6d38d3c000000000000000000000000000000000d0273f6bf31ed37c3b8d68083ec3d8e20b5f2cc170fa24b9b5be35b34ed013f9a921f1cad1644d4bdb14674247234c80000000000000000000000000000000008b7ae4dbf802c17a6648842922c9467e460a71c88d393ee7af356da123a2f3619e80c3bdcc8e2b1da52f8cd9913ccdd0000000000000000000000000000000005ecf93654b7a1885695aaeeb7caf41b0239dc45e1022be55d37111af2aecef87799638bec572de86a7437898efa702000000000000000000000000000000000000000000000000000002effc7b302730000000000000000000000000000000002142a58bae275564a6d63cb6bd6266ca66bef07a6ab8ca37b9d0ba2d4effbccfd89c169649f7d0e8a3eb006846579ad0000000000000000000000000000000012be651a5fa620340d418834526d37a8c932652345400b4cd9d43c8f41c080f41a6d9558118ebeab9d4268bb73e850e10000000000000000000000000000000015f4b235c209d89ce833f8f296e4cfb748e8abce6990ce1a5a914b9416c08e0d3a26db89625915c821a5f152b7fa592e0000000000000000000000000000000006fcacb3ee6650a1044852d61c9c20bedc8ee90aad97de8e24670a9ef57483e678db11dd95428915088d76e30cb01a370000000000000000000000000000000000000000000000000010b4ebfca1dee100000000000000000000000000000000018405e4b67f957b6465ead9f5afc47832d45643dc3aa03af7314c6cf980fa23dd3bb8db3358693ad06011f6a6b1a5ff000000000000000000000000000000000c48e0d4f9404ae0a7f10774c55a9e838bb09d3bae85b5eaa6b16b0f4dc2354368117f3799c37f3f7126d8b54d3f83930000000000000000000000000000000007e61f4ec5bc9e2cc8ca471ce4ed40e729b1790cd2c0d9c1cb50e615ec7f346636e77e1cf632c881c07c5385898607620000000000000000000000000000000011dfaf9281901dd356fc5dfece21898a93d9ad9e4e246dd6e18d3ee46d58ab7e77401a3e8d04057e5638ed74fb95688100000000000000000000000000000000000000000000000005f04fe2cd8a39fb000000000000000000000000000000001796abe0d9e4a703962be528e6a5cb65c60725886f925db0e2a89107ec248bb39fa332bc63bd91d28ae66e0dfce8f754000000000000000000000000000000000fb665f5a7559cb0fa1300048a0e6f1ab5547226e86f8e752dd13c28eda4168492e3d3bf2f8a6b230dd57f79b1afa9910000000000000000000000000000000003422dbbe4a06a4c6c9fdf35e54f74b4ab1528abb7249e99898e6fd7affebc7aef95bf82d328dc01d63c25f6a735c35d0000000000000000000000000000000010aa5504b469427eb3584a286191149f5c3c5a745f338278dd95337cd2336d3c4e7532d98eb189fa543824953e7c1c170000000000000000000000000000000000000000000000021c6c659f10229c390000000000000000000000000000000009303f04d568e289a35102b6df883d5ed620355c0eb5d02236718cdaf99fba6e19ef5cee2996268eb9a53ae1ee09bce3000000000000000000000000000000000190be857d602284393305bfe0a29e29a6982ed3f04ccaabafb7e59cdc7eda85c22bc3e8690355c7a0fb7590ae40f1b00000000000000000000000000000000016efd497a0c5c6b59a1fdf2b590eb67a7da8cbe72f49084e7050783ff12a783cad1859e1a0b0ec8ff784c703617670330000000000000000000000000000000017a957ea4d53f4fc8412cb015ae91b38445cdb3e7078d875c465c941e0d9a852c78d90b31b6b6010efe8bd5117e831630000000000000000000000000000000000000000000000c01a881f8abc4d8843000000000000000000000000000000000173ed58056bec9874464d3f23c3e7d3d429d6c8a167fc7f39368830eca839d0eb8260d64ca823f6c785c71f85893d8400000000000000000000000000000000123372d7d4c91a249df8f3e4f8e669087b252ab5d8cf2529a87e4ed3622e4158cf17dc44b473d5debd273261383e8a0f0000000000000000000000000000000000c500eb55ab86381a1725f339f686c7e38ce9113493736f57e999badc661b5b8494d220ded0711e841228a389abdb820000000000000000000000000000000010a4025d823c4262367c53f50e67cffa046e4a1e7c69ff30373772e49ecb310de3b313d83cc41f40a00205722f233e270000000000000000000000000000000000000000000044496e633650ef8f6fd100000000000000000000000000000000152110e866f1a6e8c5348f6e005dbd93de671b7d0fbfa04d6614bcdd27a3cb2a70f0deacb3608ba95226268481a0be7c000000000000000000000000000000000bf78a97086750eb166986ed8e428ca1d23ae3bbf8b2ee67451d7dd84445311e8bc8ab558b0bc008199f577195fc39b7000000000000000000000000000000000845be51ad0d708657bfb0da8eec64cd7779c50d90b59a3ac6a2045cad0561d654af9a84dd105cea5409d2adf286b561000000000000000000000000000000000a298f69fd652551e12219252baacab101768fc6651309450e49c7d3bb52b7547f218d12de64961aa7f059025b8e0cb500000000000000000000000000000000000000000018461a3d444ec527fcbf4b000000000000000000000000000000000027513925b419f6c581788578379995290ab9478e08ecd1999d5e1a05c58144d2f9f06fb8c7fd1586f3ef6a973a3ed7000000000000000000000000000000001292b2ce751f6f859ec7882e14083eac9841b035f9d5ed938a81579dbce07dec2c0202b7f6b25226831cd9c578e893d00000000000000000000000000000000017f36da49414d7706209d52840250eea6f33970fd7eac448ee122f24c62f6a6e09757aa29761160be0f65ba3ce7a153a00000000000000000000000000000000086d471f958f3ff679805751b183fb6310e871ba72bbdefd59c58e95ea62de0820d5affe601757e318abaa5a0c2715bd000000000000000000000000000000000000000008a0eb53c748001536d7ffa900000000000000000000000000000000090721a089bbbb130c21a529be0ede9271a91a2dde9cb2a8e091a19fd2c0a40c390ac2bda8304085c2d6e38e520eae44000000000000000000000000000000000cc64109c67b342b6dbcf86cb60fca7ad378ed6398d89076ed108685c57a07d26e40ed3d5c4b3560b21e519db5875d49000000000000000000000000000000000b0ddd488f5a6f61f087cdbf011b50209a4460c8aa8c5f48c0b30d9cf6cf24259f4e7badc42e1b7a33352949ae566fc100000000000000000000000000000000038430e8db04d205d81aa1632d23919c06f89260c7ac5850bd8b780f8388e53db3a3ddfe98cc55d1c686e582f85b0c8900000000000000000000000000000000000000031133a6c7d698078a7ec7e113000000000000000000000000000000001800ecc167bb714100f31e7610cd3fd010ca299b394c01b1a89afd11b051e92989f6336db5e6d3212f6b04673526d83900000000000000000000000000000000070401d9bba01c0445e0a682406b099f21d16d9c348cc97156769084055ca328a145c134b8c8b58f019d62882b2965de000000000000000000000000000000000287f071bda99b0318e386b27a492a6823a9664084b12acddeda34cb53f827a362ba97c0e652c37bd9d6023041d8c8d8000000000000000000000000000000000fa708ca7dd917541cd02281e525d3367b5ebf5e9353103e1f83f3b894d03d8be7e4d819c123492788855d1fdb63f2e000000000000000000000000000000000000001171d5c4909480aae3b110d01c1000000000000000000000000000000000ef786ebdcda12e142a32f091307f2fedf52f6c36beb278b0007a03ad81bf9fee3710a04928e43e541d02c9be44722e8000000000000000000000000000000000d05ceb0be53d2624a796a7a033aec59d9463c18d672c451ec4f2e679daef882cab7d8dd88789065156a1340ca9d426500000000000000000000000000000000118ed350274bc45e63eaaa4b8ddf119b3bf38418b5b9748597edfc456d9bc3e864ec7283426e840fd29fa84e7d89c934000000000000000000000000000000001594b866a28946b6d444bf0481558812769ea3222f5dfc961ca33e78e0ea62ee8ba63fd1ece9cc3e315abfa96d53694400000000000000000000000000000000000063376fcdf64c9bcbeeff0f9f9f9b0000000000000000000000000000000004b6570b4a6affe97649b0dd7a0ad0df160b37c332a8a7348dd3994cc6b1eb65623b4a9f0a3f320e7278844e261546530000000000000000000000000000000005f8fb4cf5e5313f403f15c59c79b9cebaec78291f2053c49d6427f40f2db2aa659d3a8fed7c7b07b7a5680c7b95ab5800000000000000000000000000000000045cba5ec3fa9acd1b11e1f28a01ebc028f89f96f814513453c553f58785baca8abd4150f334b405fabb925b71f4f4dd0000000000000000000000000000000013daf00b8f53af776c2e8c08d55d164aa15027611188e294230477dc1c926102088f0451222fd2eff9802db8b884ab9c00000000000000000000000000000000002344b4be368d3b617df4aa8dbdbc190000000000000000000000000000000002b29192945df0a74eed138e431962f1d39978202d247335ffbf29d8a02e982c69e96b58d7d92528baf5c422ed633f1f000000000000000000000000000000000d52c7a82fece99279de7a49439c0ff8463a637cc6003320275d69549442c95184fd75ee5e7122e5575af7432e5159290000000000000000000000000000000006ddbaad6cc16c9e62b0da9ab0196dffe92253fcfb2df9aa2076d3f16b3284997d6558cc4432d2aa1705452c4e951e6e00000000000000000000000000000000175f906a99c9d65c4647807879e5eb781532db184d28a326ef9691f8738af067b6a80147bd69327d219fad7c850a7545000000000000000000000000000000000c896c3f9d64341ba7c5f8a06271dce3000000000000000000000000000000000c86c92c9598dde7e6fc5e05d70a34c7a14cff5f400f33cf6cc26e6bf6d9a0bbc421c00f3360721f51974d76be43bd38000000000000000000000000000000001137d93502ef32471f47890a181d7823b3a86dbfcadcc930ae53952f528d617e742a52e4f243c615cc28163dc31bd80600000000000000000000000000000000088f7f8bcbc6dfcc8005b8308cd4780d574d8530e95e7831e52eb2c9a88b846852e111a8389e3d3a67accf78b08326d200000000000000000000000000000000149e43fc675dd3bde8b89cfeb29456f130bbf674cea0266bd1b2e7de23f9a7294096327b452728411ca58acc949777fa0000000000000000000000000000000474d97a9cf29e85d4a35f6102fe7984b100000000000000000000000000000000186a1da343cacf1815b9c8b6c807f536249dbfdb59d77bf4920ad2198a0d83ada21f7c39de6f06a5599f22571cab288d000000000000000000000000000000000ba1ec44f95121bd622932b84bbb4b3d279f69c494ee44db68e3165c86b627ba5e397ee197313fb5b775972798997332000000000000000000000000000000000783e7493e9fb106fa0d085e7c03eb816468d12c65d9b77643ed07c02583d491f4db5db44e565d50d8ccaa9ad8f7f8e80000000000000000000000000000000010a6a5fd90cd5f4fb6545814f5df065b001074bb3f29f649dd2612815df3a19a320f7754dd3d458e48e7fb1b4953978f00000000000000000000000000000195894e95ca3e59929612e77c1075322aeb00000000000000000000000000000000129c4945fe62538d2806fff056adac24f3bba8e17e42d82122affe6ad2123d68784348a79755f194fde3b3d448924032000000000000000000000000000000000528590e82f409ea8ce953f0c59d15080185dc6e3219b69fcaa3a2c8fc9d0b9e0bc1e75ec6c52638e6eaa4584005b5380000000000000000000000000000000018dc3e893f74729d27dd44f45a5a4f433dcd09a3b485e9d1c2bd0eb5e0e4c9024d928ddc426fdecae931e89885ee4db4000000000000000000000000000000000d6ee02e1fc7e52a8e1ef17e753065882c6fcc14da61da7ffe955fe84a9d2af9ba57562c69db3088652931bf124b0d5300000000000000000000000000009027ceef3ee429d71b58b84919d9a8d5418900000000000000000000000000000000131747485cce9a5c32837a964b8c0689ff70cb4702c6520f2220ab95192d73ae9508c5b998ffb0be40520926846ce3f100000000000000000000000000000000101e147f8bd7682b47b3a6cc0c552c26ce90b9ce0daef21f7f634b3360483afa14a11e6745e7de01a35c65b396a1a12700000000000000000000000000000000090ca61ed16c4c1e80acfef736eea2db0d7425d9110cb53e6c4a2aa3f8a59ee6c60bdce8df5825011066d44bef84d29600000000000000000000000000000000028207394adcbf30250ac21a8f1db6283580bc5e39159930552e5edb25e6215c66b6450296edc80dbc3a2acd125dab1600000000000000000000000000333e268f0b5b1adf76b88981fc305f03ce4bb30000000000000000000000000000000016cfabbe60d1e55723a0ff72cf802f2d1cf13ed131e17729adc88522a657f320a336078a9399c8e61a3bbde3d52fd3640000000000000000000000000000000009aa9a3c2a6d49d286aa593c6ff644f1786fa9ae471bdb3fe70b150a9ed7584eaa886ac057c30005c3642f65ad5581cc0000000000000000000000000000000001d417894c0cce924955a795b188b27951f8438a5485404b921a42fa79dea03c10e29d0390df2f34d7be13f360a7fada00000000000000000000000000000000189b0b3a04e6c613899d51231dbf0cba6a8a8f507ebed99d24fba7ebac6c97a8859ffde88e6d95c1a9d6b4f0a8f3c417000000000000000000000000123717b4d909628d6f3398e134a531c65a54e8a10000000000000000000000000000000016cad7807d761f2c0c6ff11e786a9ed296442de8acc50f72a87139b9f1eb7c168e1c2f0b2a1ad7f9579e1e922d0eb309000000000000000000000000000000000d3577c713fcbc0648ca8fbdda0a0bf83c726a6205ee04d2d34cacff92b58725ca3c9766206e22d0791cb232fa8a9bc3000000000000000000000000000000000f5ea1957be1b9ca8956ba5f6b1c37ea72e2529f80d7a1c61df01afcc2df6f99ced81ac0052bd0e1e83f09d76ad8d33b000000000000000000000000000000000aabced4e2b9e4a473e72bf2b1cc0ce7ab13de533107df2205ed9e2bb50fa0217e6a13abcd12fce1bda1ccf84dac237a00000000000000000000000679956d49265608468757580db6b8b1821c2eb13b", "Expected": "000000000000000000000000000000000728c5e6e69b9103d82358cb6ba3a45a677df1c3eb3cdccf694fd71cee94f1e591b8021b0eef638cd9a1d878937b5b2d000000000000000000000000000000000ba9bcf9ccef956f2af8dc4c3fbf1cc8f3f284b04ae8710af6ef4fb36301254c777d4461858fb38fdeeb72c0d8589af5000000000000000000000000000000000224b80a57d30bce4c752664f3b5b5e3443aefa6d4e95dc334821f754b8b8d8fda4e73d03cbd4070d43b18324a686b500000000000000000000000000000000016909a02214c6c0f6682895aa99cf6cf0a22eab6f0b574437ef9c36e9df32ac3b8c5adb9f6b8827df0ccf51b16f824df", "Name": "bls_g2multiexp_larger", - "Gas": 409750, + "Gas": 335250, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000039b10ccd664da6f273ea134bb55ee48f09ba585a7e2bb95b5aec610631ac49810d5d616f67ba0147e6d1be476ea220e0000000000000000000000000000000000fbcdff4e48e07d1f73ec42fe7eb026f5c30407cfd2f22bbbfe5b2a09e8a7bb4884178cb6afd1c95f80e646929d30040000000000000000000000000000000001ed3b0e71acb0adbf44643374edbf4405af87cfc0507db7e8978889c6c3afbe9754d1182e98ac3060d64994d31ef576000000000000000000000000000000001681a2bf65b83be5a2ca50430949b6e2a099977482e9405b593f34d2ed877a3f0d1bddc37d0cec4d59d7df74b2b8f2dfb3c940fe79b6966489b527955de7599194a9ac69a6ff58b8d99e7b1084f0464e0000000000000000000000000000000018c0ada6351b70661f053365deae56910798bd2ace6e2bf6ba4192d1a229967f6af6ca1c9a8a11ebc0a232344ee0f6d6000000000000000000000000000000000cc70a587f4652039d8117b6103858adcd9728f6aebe230578389a62da0042b7623b1c0436734f463cfdd187d20903240000000000000000000000000000000009f50bd7beedb23328818f9ffdafdb6da6a4dd80c5a9048ab8b154df3cad938ccede829f1156f769d9e149791e8e0cd900000000000000000000000000000000079ba50d2511631b20b6d6f3841e616e9d11b68ec3368cd60129d9d4787ab56c4e9145a38927e51c9cd6271d493d93884d0e25bf3f6fc9f4da25d21fdc71773f1947b7a8a775b8177f7eca990b05b71d0000000000000000000000000000000003632695b09dbf86163909d2bb25995b36ad1d137cf252860fd4bb6c95749e19eb0c1383e9d2f93f2791cb0cf6c8ed9d000000000000000000000000000000001688a855609b0bbff4452d146396558ff18777f329fd4f76a96859dabfc6a6f6977c2496280dbe3b1f8923990c1d6407000000000000000000000000000000000c8567fee05d05af279adc67179468a29d7520b067dbb348ee315a99504f70a206538b81a457cce855f4851ad48b7e80000000000000000000000000000000001238dcdfa80ea46e1500026ea5feadb421de4409f4992ffbf5ae59fa67fd82f38452642a50261b849e74b4a33eed70cc973f40c12c92b703d7b7848ef8b4466d40823aad3943a312b57432b91ff68be1000000000000000000000000000000000149704960cccf9d5ea414c73871e896b1d4cf0a946b0db72f5f2c5df98d2ec4f3adbbc14c78047961bc9620cb6cfb5900000000000000000000000000000000140c5d25e534fb1bfdc19ba4cecaabe619f6e0cd3d60b0f17dafd7bcd27b286d4f4477d00c5e1af22ee1a0c67fbf177c00000000000000000000000000000000029a1727041590b8459890de736df15c00d80ab007c3aee692ddcdf75790c9806d198e9f4502bec2f0a623491c3f877d0000000000000000000000000000000008a94c98baa9409151030d4fae2bd4a64c6f11ea3c99b9661fdaed226b9a7c2a7d609be34afda5d18b8911b6e015bf494c51f97bcdda93904ae26991b471e9ea942e2b5b8ed26055da11c58bc7b5002a000000000000000000000000000000001156d478661337478ab0cbc877a99d9e4d9824a2b3f605d41404d6b557b3ffabbf42635b0bbcb854cf9ed8b8637561a8000000000000000000000000000000001147ed317d5642e699787a7b47e6795c9a8943a34a694007e44f8654ba96390cf19f010dcf695e22c21874022c6ce291000000000000000000000000000000000c6dccdf920fd5e7fae284115511952633744c6ad94120d9cae6acda8a7c23c48bd912cba6c38de5159587e1e6cad519000000000000000000000000000000001944227d462bc2e5dcc6f6db0f83dad411ba8895262836f975b2b91e06fd0e2138862162acc04e9e65050b34ccbd1a4e8964d5867927bc3e35a0b4c457482373969bff5edff8a781d65573e07fd87b890000000000000000000000000000000019c31e3ab8cc9c920aa8f56371f133b6cb8d7b0b74b23c0c7201aca79e5ae69dc01f1f74d2492dcb081895b17d106b4e000000000000000000000000000000001789b0d371bd63077ccde3dbbebf3531368feb775bced187fb31cc6821481664600978e323ff21085b8c08e0f21daf72000000000000000000000000000000000009eacfe8f4a2a9bae6573424d07f42bd6af8a9d55f71476a7e3c7a4b2b898550c1e72ec13afd4eff22421a03af1d31000000000000000000000000000000000410bd4ea74dcfa33f2976aa1b571c67cbb596ab10f76a8aaf4548f1097e55b3373bff02683f806cb84e1e0e877819e2787c38b944eadbd03fd3187f450571740f6cd00e5b2e560165846eb800e5c94400000000000000000000000000000000147f09986691f2e57073378e8bfd58804241eed7934f6adfe6d0a6bac4da0b738495778a303e52113e1c80e698476d50000000000000000000000000000000000762348b84c92a8ca6de319cf1f8f11db296a71b90fe13e1e4bcd25903829c00a5d2ad4b1c8d98c37eaad7e042ab023d0000000000000000000000000000000011d1d94530d4a2daf0e902a5c3382cd135938557f94b04bccea5e16ea089c5e020e13524c854a316662bd68784fe31f300000000000000000000000000000000070828522bec75b6a492fd9bca7b54dac6fbbf4f0bc3179d312bb65c647439e3868e4d5b21af5a64c93aeee8a9b7e46eaaee7ae2a237e8e53560c79e7baa9adf9c00a0ea4d6f514e7a6832eb15cef1e1000000000000000000000000000000000690a0869204c8dced5ba0ce13554b2703a3f18afb8fa8fa1c457d79c58fdc25471ae85bafad52e506fc1917fc3becff0000000000000000000000000000000010f7dbb16f8571ede1cec79e3f9ea03ae6468d7285984713f19607f5cab902b9a6b7cbcfd900be5c2e407cc093ea0e6700000000000000000000000000000000151caf87968433cb1f85fc1854c57049be22c26497a86bfbd66a2b3af121d894dba8004a17c6ff96a5843c2719fa32d10000000000000000000000000000000011f0270f2b039409f70392879bcc2c67c836c100cf9883d3dc48d7adbcd52037d270539e863a951acd47ecaa1ca4db12dac6ed3ef45c1d7d3028f0f89e5458797996d3294b95bebe049b76c7d0db317c0000000000000000000000000000000017fae043c8fd4c520a90d4a6bd95f5b0484acc279b899e7b1d8f7f7831cc6ba37cd5965c4dc674768f5805842d433af30000000000000000000000000000000008ddd7b41b8fa4d29fb931830f29b46f4015ec202d51cb969d7c832aafc0995c875cd45eff4a083e2d5ecb5ad185b64f0000000000000000000000000000000015d384ab7e52420b83a69827257cb52b00f0199ed2240a142812b46cf67e92b99942ac59fb9f9efd7dd822f5a36c799f00000000000000000000000000000000074b3a16a9cc4be9da0ac8e2e7003d9c1ec89244d2c33441b31af76716cce439f805843a9a44701203231efdca551d5bbb30985756c3ca075114c92f231575d6befafe4084517f1166a47376867bd108000000000000000000000000000000000e25365988664e8b6ade2e5a40da49c11ff1e084cc0f8dca51f0d0578555d39e3617c8cadb2abc2633b28c5895ab0a9e00000000000000000000000000000000169f5fd768152169c403475dee475576fd2cc3788179453b0039ff3cb1b7a5a0fff8f82d03f56e65cad579218486c3b600000000000000000000000000000000087ccd7f92032febc1f75c7115111ede4acbb2e429cbccf3959524d0b79c449d431ff65485e1aecb442b53fec80ecb4000000000000000000000000000000000135d63f264360003b2eb28f126c6621a40088c6eb15acc4aea89d6068e9d5a47f842aa4b4300f5cda5cc5831edb81596fb730105809f64ea522983d6bbb62f7e2e8cbf702685e9be10e2ef71f818767200000000000000000000000000000000159da74f15e4c614b418997f81a1b8a3d9eb8dd80d94b5bad664bff271bb0f2d8f3c4ceb947dc6300d5003a2f7d7a829000000000000000000000000000000000cdd4d1d4666f385dd54052cf5c1966328403251bebb29f0d553a9a96b5ade350c8493270e9b5282d8a06f9fa8d7b1d900000000000000000000000000000000189f8d3c94fdaa72cc67a7f93d35f91e22206ff9e97eed9601196c28d45b69c802ae92bcbf582754717b0355e08d37c000000000000000000000000000000000054b0a282610f108fc7f6736b8c22c8778d082bf4b0d0abca5a228198eba6a868910dd5c5c440036968e977955054196b6a9408625b0ca8fcbfb21d34eec2d8e24e9a30d2d3b32d7a37d110b13afbfea000000000000000000000000000000000f29b0d2b6e3466668e1328048e8dbc782c1111ab8cbe718c85d58ded992d97ca8ba20b9d048feb6ed0aa1b4139d02d3000000000000000000000000000000000d1f0dae940b99fbfc6e4a58480cac8c4e6b2fe33ce6f39c7ac1671046ce94d9e16cba2bb62c6749ef73d45bea21501a000000000000000000000000000000001902ccece1c0c763fd06934a76d1f2f056563ae6d8592bafd589cfebd6f057726fd908614ccd6518a21c66ecc2f78b660000000000000000000000000000000017f6b113f8872c3187d20b0c765d73b850b54244a719cf461fb318796c0b8f310b5490959f9d9187f99c8ed3e25e42a93b77283d0a7bb9e17a27e66851792fdd605cc0a339028b8985390fd024374c76000000000000000000000000000000000576b8cf1e69efdc277465c344cadf7f8cceffacbeca83821f3ff81717308b97f4ac046f1926e7c2eb42677d7afc257c000000000000000000000000000000000cc1524531e96f3c00e4250dd351aedb5a4c3184aff52ec8c13d470068f5967f3674fe173ee239933e67501a9decc6680000000000000000000000000000000001610cfcaea414c241b44cf6f3cc319dcb51d6b8de29c8a6869ff7c1ebb7b747d881e922b42e8fab96bde7cf23e8e4cd0000000000000000000000000000000017d4444dc8b6893b681cf10dac8169054f9d2f61d3dd5fd785ae7afa49d18ebbde9ce8dde5641adc6b38173173459836dd994eae929aee7428fdda2e44f8cb12b10b91c83b22abc8bbb561310b62257c000000000000000000000000000000000ca8f961f86ee6c46fc88fbbf721ba760186f13cd4cce743f19dc60a89fd985cb3feee34dcc4656735a326f515a729e400000000000000000000000000000000174baf466b809b1155d524050f7ee58c7c5cf728c674e0ce549f5551047a4479ca15bdf69b403b03fa74eb1b26bbff6c0000000000000000000000000000000000e8c8b587c171b1b292779abfef57202ed29e7fe94ade9634ec5a2b3b4692a4f3c15468e3f6418b144674be70780d5b000000000000000000000000000000001865e99cf97d88bdf56dae32314eb32295c39a1e755cd7d1478bea8520b9ff21c39b683b92ae15568420c390c42b123b7010b134989c8368c7f831f9dd9f9a890e2c1435681107414f2e8637153bbf6a0000000000000000000000000000000017eccd446f10018219a1bd111b8786cf9febd49f9e7e754e82dd155ead59b819f0f20e42f4635d5044ec5d550d847623000000000000000000000000000000000403969d2b8f914ff2ea3bf902782642e2c6157bd2a343acf60ff9125b48b558d990a74c6d4d6398e7a3cc2a16037346000000000000000000000000000000000bd45f61f142bd78619fb520715320eb5e6ebafa8b078ce796ba62fe1a549d5fb9df57e92d8d2795988eb6ae18cf9d9300000000000000000000000000000000097db1314e064b8e670ec286958f17065bce644cf240ab1b1b220504560d36a0b43fc18453ff3a2bb315e219965f5bd394c68bc8d91ac8c489ee87dbfc4b94c93c8bbd5fc04c27db8b02303f3a65905400000000000000000000000000000000018244ab39a716e252cbfb986c7958b371e29ea9190010d1f5e1cfdb6ce4822d4055c37cd411fc9a0c46d728f2c13ecf0000000000000000000000000000000001985d3c667c8d68c9adb92bdc7a8af959c17146544997d97116120a0f55366bd7ad7ffa28d93ee51222ff9222779675000000000000000000000000000000000c70fd4e3c8f2a451f83fb6c046431b38251b7bae44cf8d36df69a03e2d3ce6137498523fcf0bcf29b5d69e8f265e24d00000000000000000000000000000000047b9163a218f7654a72e0d7c651a2cf7fd95e9784a59e0bf119d081de6c0465d374a55fbc1eff9828c9fd29abf4c4bdb3682accc3939283b870357cf83683350baf73aa0d3d68bda82a0f6ae7e51746", "Expected": "00000000000000000000000000000000083ad744b34f6393bc983222b004657494232c5d9fbc978d76e2377a28a34c4528da5d91cbc0977dc953397a6d21eca20000000000000000000000000000000015aec6526e151cf5b8403353517dfb9a162087a698b71f32b266d3c5c936a83975d5567c25b3a5994042ec1379c8e526000000000000000000000000000000000e3647185d1a20efad19f975729908840dc33909a583600f7915025f906aef9c022fd34e618170b11178aaa824ae36b300000000000000000000000000000000159576d1d53f6cd12c39d651697e11798321f17cd287118d7ebeabf68281bc03109ee103ee8ef2ef93c71dd1dcbaf1e0", "Name": "matter_g2_multiexp_0", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000000eb3c91515d4a41209a73564741a8ccf901a624df9db22e195a5d02d24b7bc0a12756b15b8d006cb991a7e088eaef1000000000000000000000000000000000704ce8afc808b0161f6f61b22d990d713ae398779e6e74e9b5771daf006ce0bba3a8088edf75156f0e48b92ee8409b00000000000000000000000000000000018fe81e05aff0620f4bdbe4a715e015650497afab62921eba0ab86b649e5a2fd3d54041868928519f537e36448688a0d00000000000000000000000000000000162bd97161201ea3c26f8dd1204a9c6b61b762bdf573cb5d20b6b255f30208ca7d96aa47b46fb8c6bf0922075f1c1ca807f80a5e502f63375d672379584e11e41d58d2ed58f3e5c3f67d9ea1138493cf00000000000000000000000000000000135aee0e30fbcad798738c10d4aebcdf50c89ce516325f655fe763dce54ffedf94dd74168611e5ae879b5bf5598d62dc000000000000000000000000000000000c728e672cd8b3bf9341bca929c34118b566cd3a80452d7015bee9d5cdc001b1f5c678d4b2cc4f7cac353e7bf326ca1e0000000000000000000000000000000014809aa22e2051e463fba6d49fbb060d0c7f599a0fc5409d34e71f34817e7beb1251810ae6eee1848c60796fb8647dea00000000000000000000000000000000145a4de777d86025d50e12f9a6615ecb9bdd41489992d1b643dd9aa549acbc63b04b0bdfd14b6e45c70f165e9a8c91bebb169138f94093d5c1c6b253cc001ce8baf78858dae053173fa812d2d1c800da00000000000000000000000000000000009a58b7116dbd6f550f8ca98071813130ecaa9ea86d5275eebc36860690fa048c9ebeb46600b2b63e847bff3e38ed0d00000000000000000000000000000000113ffc0932c041e0e34b2540c485eb74f5029b339cb60bc88a8a749310f33f330dea137e5f340044fd689264af66696d0000000000000000000000000000000002642da3c2c7b6688aba0b19ab29ac72e35caafa044863c364ea8833fca850289de52c0963bc33d7bba40cb5f568718a000000000000000000000000000000000552d35ca054da2f148c119454f6760607b351f2441921a2be17da2cc10902d71571c5554f132e60df79679428fa07e3e40608bdaf3e7764358a64a920cbb33ab4d571c7b3092e1ae11d9697f82ed8330000000000000000000000000000000018fbbcba3d4b1e548ceaec4a48db62a2420ff29a67af332ee7ea3f902f84e6c375fd33abc33d945c5bca25603979f9a400000000000000000000000000000000072ff416994364bdc6535f36c82212afa822cd94fade69f11eb38dbdcd37c7e22af55fe05e6a826dad822073656eaac10000000000000000000000000000000017bba179b847278a4878b6faeaab3b1f4bd7540d22817cd9aff95557497f8b9d286657b6162c0f89f7820becc637dd550000000000000000000000000000000018e2bfed71aa9b11fefca2f0db8bd9b8c69540267de50bec4fc90a6e9741891465c9761d19282e1100b3707eeb598b31d411519f2a33b07f65e7d721950e0f0d5161c71a402810e46817627a17c56c0f0000000000000000000000000000000019efd37727dfaedf697fcda7a59847dbda8ca7cdc92f34e68691d682e20ae6545ac104d6660fdb8f64a051e69298eae8000000000000000000000000000000001225ace0fdce456dd888c9672503b68ef77b2d11caf1265a767a6ea14911e3ca03fc153f18dfe9d95e0cc68b7b8a3a8d0000000000000000000000000000000008a6b059c1c4da046cc0b1b5d7f33270aceffa607daf6d0d078c06f940604e1a0b4adf01a4091306e3c7eddcf3d95101000000000000000000000000000000000f79bae5260a2f114ffbb9273f3049d3ebb002500a57ee0a7d157d86957f43f87a2e026fb9892dacaadca5ee04fc8e176bb3f9e512311699f110a5e6ae57e0a7d2caaa8f94e41ca71e4af069a93d08cc0000000000000000000000000000000016d2b73eeceee17d3bff3aacac9df9ac1c4248d9ea7d6a503a757f7bb22fa6970bb6f5cb5ec154785f7252e1508b382e00000000000000000000000000000000081edc68bbd8db7b10be06ee23d090bd54f9ca07ef24dfed7df7bb05f8cc26e6889dbd40ea203fd5cca5cb588199f9e40000000000000000000000000000000010d3478508619ea9493b4330e2fb9150024cd32dc1378f824788a884a4a30fbf39c630f465557bf0c6d69b4cbecf89f9000000000000000000000000000000000f20c9b134db5d8b7756800c031bf5962fc560ba95d4bd9157b16179f1a37ae08696a2be455ad8d018aead6adcc69b712a0c988d97e86dccaeb8bd4e27f9e30fad5d5742202cdde17d800642db633c520000000000000000000000000000000003dce67181d23af9729e9fb0653d7f79c890fba27de42fada93123e112c4a468fa889921192db8047d86e4db77c60266000000000000000000000000000000000869a1e39d42d9bb0cc0568fdad16abbdac3194af893ebd8dd8f8c2c3c855abefa5fc215412168acadc88e658e83f5570000000000000000000000000000000001ef139a75194f3c4b1378c2b66dd304d179460bac0a289405cd8faa3ff66a7b6e54eb7b8742a68150b1e098630135c40000000000000000000000000000000003892b5a645af916be2c6c7fc0bb08fb5f39341d3c68598940554e1be11e1be75af920db0c8710ed13c78edbf683f17d0b299c14892e0519b0accfa17e1a758c8aae54794fb61549f1396395c967e1b1000000000000000000000000000000000264dd4b477f5db65edad28c7153ed919a863c5c5661e0125c5429b323e055fd69c33142dfc6ed9c87082e2be4675e1f00000000000000000000000000000000046ea088a2ec94d3a1f1f97949f1ebc49690c453d316cc46534fa253b34b30323b6071d147d64bb94e02fb4db07bb0c400000000000000000000000000000000013692a33bb1348486eec40a9e93a4ea3810c7b4d3188cd07e235a2c898aa87ee0d17682fd24f4d978f9fb028fd26e2900000000000000000000000000000000115f8b64c00cd5cd344a7b5edc0ef0bb85a3e8f0f9dfb28f8ffe12db3e0d222c2d45dcdba0fbdc161c5d558bc71aa0977064d43d6802ad4c3794705065f870263fef19b81604839c9dea8648388094e900000000000000000000000000000000014c83d58d90db4821a0411fab45f83fbc05f7d0d7a67ce75da3ae568978d15f4c1886c6fa6086675c0045efb30d818400000000000000000000000000000000001e68691123451f4c3df6dae62c6a63855ec3597aae33a8a10ee274e902e9aab1460cc9c79726312df0ee0ce90c8d3c00000000000000000000000000000000018a39eb3e3c6c7fb8ee304e55d15e209afe2fe278dda93552a7b9f51fbd778da1502eb6775cbc3f832f8320fa0686240000000000000000000000000000000017c15910fad1ca5749aa82a5a2fa98b0ebb37e92912547fb1741f18c34e0d5fc3a307b928636c25f0320d71cb9d31062686285a0e22f177fe3adbfc435e9c1786752dcf3c11b723539789b0cdeb0647b000000000000000000000000000000000fa96d9fe01c18732e8d6454df9bb1f482c4b9add837ce9c354c72d49c2d44ec694674aaf0e6d6a095cab7ebb57ccd9a0000000000000000000000000000000001f8ffe3fb7e9e311e0f6949c07c26a0febb181e37b2268bb5e125fc3a100323740d1ebaa5e635dba3770fdc2ce4ee860000000000000000000000000000000012ac42095fdb677720ab3f14bf0afc55c95b43d28d922a5f8cb0bd841306b978751d24546e3a6474976961d0768f29e9000000000000000000000000000000000baf9804d99039c9fe966a696c64bdacc9673b0906b4deab108d34fbbaa3b0905d50892278570564017b96828c7e1ac93176b6724cf984632daf95c869d56838ab2baef94be3a4bd15df2dd8e49a90a60000000000000000000000000000000014ce6d88a7c5c782562aa101550f1af487296adebd9dae8252698ba04fbd58b92e2216de6ffd474d5992f97d9f22800d000000000000000000000000000000000ce92a04f5c8a99ca0e93992448222519fc454bda5d1d8638a7bfde968386e4ba0dcd1da59cd81d4c4dca3e584be0275000000000000000000000000000000000cb570796f5c8f7b8aa02e76cb8e870d3365fe4dce5df07ec286a0a821f922b4003d5b69c0f1588206d9544013e268c400000000000000000000000000000000098056a033d9cdae86aac02de3a444471854b909680719154b44d4f55f30087294e39e57643c692d6da725b859239080d76db3dcb659eaf6c086be6b414a494dea4bd30aef8450ae639f473148c05b36000000000000000000000000000000001214aacb0a5e6b7a40369a83c07fa8cf1786ce7cbde2b5a501d9c1292532df7822d4fde10a31fc0cecce3a7cfe3311850000000000000000000000000000000004f9669d8fe4f884ae93b2505710e6e45b19b7aa5df8cdd811f09e547efc27d21024cba05e2dc9d057055f30ec72d9df000000000000000000000000000000000a852b821b31cd27eca19712a636aa05ef2cd82c36ac1c2ca240edc7d0172b42a72c42d3cba583a5b5129ac1c9486e270000000000000000000000000000000007bd8419e791a5cea04993509e91a980d3ae4987a5b322400b6e4a4f2b636891a1c7ba4de96b53426dd556532403d5a39915646de2449b3cb78d142b6018f3da7a16769722ec2c7185aedafe2699a8bc0000000000000000000000000000000005ef88bf38b2f998dec7302cde829076e6cf69df23aa0bf6bbb39fc0d3d8b5eafba74efb928b1de0eeb3d86ec82612300000000000000000000000000000000011f47e9583997b19c36616e4bf78d6ddd6d67937f493986250ff02aef6e6e7ff074559af2f20a5bf1d67158e4a199cdb000000000000000000000000000000000007777c8eb259a836e6459b7bdb642f878d869fdcb31b105d01f280938ef5377f2775874c099dcd394abe70f17d595b000000000000000000000000000000001607379d1cd34e2d0ed765a339b21433e9aa489609b92414c6b5a05d796085269c288d739717def9db3502e0550860165061073223f066e35242772385c67aaefb3f7ea7df244d73369db1ea0b208792000000000000000000000000000000000d6e3068c082b68312141aa68f1540ea1415e93e7f1762b6f06ff408a9995542da1c727a13355c19f8f418a44de1a95d000000000000000000000000000000000dcfcf2ab12b1a0e521ab402aaa4d32ff649a5a97892eb6ad98487c3c73c35601c313b8130ad12e9098d16eed3bcc2e00000000000000000000000000000000013777b1eefa4af03dc44e4e054eb7a3a980a9c55644900b80346be84b970e1754d1f4ab771adc9249e4accf88a23fb400000000000000000000000000000000002f53b231f1209c6f8b52f99a78bc2147c951ac89b341495f4a60a6572985ce2bc823625099ec214bc9ceedb2deea3fff396ee22209271ea0bda10fb5e2584e7536e8bb1d00a0dd7b852b0aa653cd86c00000000000000000000000000000000161c595d151a765c7dee03c9210414cdffab84b9078b4b98f9df09be5ec299b8f6322c692214f00ede97958f235c352b00000000000000000000000000000000106883e0937cb869e579b513bde8f61020fcf26be38f8b98eae3885cedec2e028970415fc653cf10e64727b7f6232e06000000000000000000000000000000000f351a82b733af31af453904874b7ca6252957a1ab51ec7f7b6fff85bbf3331f870a7e72a81594a9930859237e7a154d0000000000000000000000000000000012fcf20d1750901f2cfed64fd362f010ee64fafe9ddab406cc352b65829b929881a50514d53247d1cca7d6995d0bc9b2f0d3d4cf46265fc0f69e093181f8b02114e492485696c671b648450c4fcd97aa000000000000000000000000000000000047f92d6306bed1cb840f58fd57b5b71a5df7f86dbfa55a36636cb495e08715cd57f2f3e7cd99a1efc28b1d684de1cb0000000000000000000000000000000000f4eb02d687a1a6105b4dbd740e2c7924689d558e6cbfee768dd303cc8dd0fd887f5eec24b54feccf00f473ca3f54ad000000000000000000000000000000000edad68c4d536912816cf6ef039c3dd0535dc52189583270b3b038e2c67b213d943bf384ce69c4a9dc526d7ef309f25a0000000000000000000000000000000006ff4a6b5129ef026d1d5704bf7fc0b474de92b5cf39722f165e73f4e7612d6d3bb40743e4b7b42d0dad5d5d6a2d4881915b717562844d59623bc582f1a95fc678cf0d39af32560c6c06e3a74023c89c", "Expected": "000000000000000000000000000000000153da66acafe91b6f13cd739ed3342197310e4824e7aef2e3414654c2678b8d09b296c3f928f3cc489893420031ab800000000000000000000000000000000010f501a96b86343a7c8d8c1250577cc9be6ffec81b5175ed07bd14988c5bbf7f2f3e7111df7d941d0cd267ea191d6ac70000000000000000000000000000000015e0d88894f7f83aacb6710f6c03ae60db8844dd3beec160fdb1df746b1f38a5e23def0893a0b39bee47c97af6535fcb000000000000000000000000000000000bcc275115e87f2f88c4afe8bf4faed46e6ad0c0357884356a26120591ba283f06b464c4853217865b1d2301965f2bd4", "Name": "matter_g2_multiexp_1", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017b32e613cb38b41dcdf3c8bb9187d731546977fbffd79fa7f66e3d6aaf9e1af6eca2fcdc260c8f90818d7148ba2f4960000000000000000000000000000000007e4d26606a47c874c20e8480a9f5815e5b577bccd783b775d10309eeb3d2102c7a0abc3324679e44362f09e7a4ada67000000000000000000000000000000000cb6f12ac8b49cfa36b957591293c87b21af0a949c55a28a90ab0fce88fb5cb7645e20ab2edd284f0ad1377dd95ac10e0000000000000000000000000000000014c96b5dcbd3150eeaea5c2bc27750cf88b30a91933a3233a4d1d9b357a80cc20d135e43a344e718dff5c79045c31f86d5c1c9fa11c36b86430cbb1f3ec10ebbe3787d0f5641d6d7fb96c810eda202dd0000000000000000000000000000000001ca1141ba9542c56de8991b313c6ae42fcecb6751b0b81b8cb21ed70d5008f7ffe831766b89880a7fa6dfdb09a2cda3000000000000000000000000000000000e6766b17db165bba564ac63ab88d3f8f5eded07a40b48644e60d3223d30458e7dabe404cab8d6f9fe135712ef0b1a43000000000000000000000000000000000dda3e6c87382fa762510e5cac721fd2b654f002f5b9a3767a8c6d651ccc582e80e3f68d6913cda30f9f51ebcfc7c98600000000000000000000000000000000059a7dac5bb6b504f2bd603d486700fe22c14f25254537b2c9079c2b45d36c7ce56854c5699cc7649b533194f51a9045c00eb20fe7c292f3ad820a074d8b3d8d24506612752d8677c2d6ca24f556cc4500000000000000000000000000000000090f4b85961ce97cf7f99c342d3627105d790f611e19721a43d8a0febd67ae393d77a02b999108efb56f0397dac22703000000000000000000000000000000001112f23595d1613c47486eadc37f9b1ac3b3c3973b3fe964d3b67c3996fe2eacd9df5c287b0cea8e9475d146fabcf9e70000000000000000000000000000000018f46f7ba3c9af34c1025c2d460f0be966e68944928dbd55cc7fe00e5def598d80b0e3801e48a74963c974ab4727a52100000000000000000000000000000000096845338d5cd2ac44e097607d6a1a05c241eda1941991ae9edbba965d9029032c46da7218b5b2338e6c58898bc4a820f661d7b30fb11bef70e15b257d7073885468a380862202b2d705a84827644b5b000000000000000000000000000000000aafe45ea7cb8b450a51263eebc28c1ded662972bee512e24fddaf64f43b74b66032523b3b104a4e9f6b62394436c6710000000000000000000000000000000015cb27e1fedfba2d1679f78a388f90b22bbf3e7d090f0ba972fa8e72f6e31c446f628fff929953712ef6e425d16eba5c000000000000000000000000000000000df9931893cae713042bf722db6ce394b6f346587278a154c271d8511e690417eb6dc47efbcebb7c2fb9e77f1de9fde800000000000000000000000000000000106ffa395ef170c99bb5742428ae88fa4fd7a94476985c099e3b700b7403d083281fb71a19640c6bc2321e27bcb33fe2346ce87c847376c8967cc18297e6007dcfacb6424e1d273930f38bb0e88fc5ca0000000000000000000000000000000010b1f8b1c492a56936da905b8738affba6bd29ae5fffd40ba6b31325181d3b489a81b23dcb69f6e71bd29bfb388e5a8f00000000000000000000000000000000116a115303b4774da59844e457844232d088062d920db67b2a8450a194be7e5340ebd4d106454fd9a03c8f50dbb1e119000000000000000000000000000000000eb521edd61b38006cffc43ab72d395d669dec196846fa4d6d43521da6c2fc3bf0994ce7556a3cffec7751b3bc5703ff00000000000000000000000000000000073cea36eccaa1c78deefb6029903c2b6598301bdefa9759719c3b590fcc5a6a4d3d4d19f552b33f4a3126a6e6a8448639a142c443a666499a880aa1cb9f523411bbc8e5554de099ab485b6c2c2e57cc000000000000000000000000000000000e3925fa085db73c1e67b29ae90f8773f83be5ec684402e8e2360ffee8a8368911e584843e42b0d470de78591df6ea6300000000000000000000000000000000075c7efdeeb16609b4a47ea442af4d75238fb7534fd96cb236a7886809d6adc2b62c8ff72bdb041bc51c1a71b68219e300000000000000000000000000000000088b4eb0dd185e51b737d797334590e982b7b0a5f109fc7d0524b2465c2c0457964eba5a6d2d4d99fb628f21f15a776c000000000000000000000000000000000fc79f6b38f3356972669290eeadcd992a22bc1191606b663a1e148aa58db3938f0fc65e536bc5811c50d9c7f03d3e372c01b7795c2d16b5bbbb1e107be36cc91b25130888956b0cdd344de9b4659447000000000000000000000000000000000b87c47605fc060a8e3677e84ce9d14b9309360a13c80d040c625fbf0108f829300cc1fca409a0f9c96311cd4a9a21e60000000000000000000000000000000014c4088f1e7935cf6a1d2475b84497ce6a250ee2c0c991fe51a2f2836388a354824b02d9cf215328dfce3f546713e21100000000000000000000000000000000120e59be3ecf35674eac6cdc559599b273f13f28a529770fa156f8e519734c451eefb35023639f32049cd19ea0d945a3000000000000000000000000000000000f97755b62a8cb8f861ea02c77819f0b58181aecf612d92180ba9b475f0b4888b922c57f6a1c619dd5514620a1cfd9e2c712943d8795a6104f024b9701c70b09cdee9494755bbab0576e2c7f7c9d48280000000000000000000000000000000005860cfb6be6720118623d2d8ba05e686df22744b948421dd3cc1b1691e00d9b5d00d00195b4acf7a7b043f764f3f1c70000000000000000000000000000000012632a3313dd611e8d969bddd556c2d79ff387603462ac78ded3a842981697bdac34ee6f1f4744ed2ff16100874ac24000000000000000000000000000000000112b94c317586e343acadeca611c485c3ea172bc10dd39158c1e678007130062a921b53826d7be6286963ff822f1066c00000000000000000000000000000000040de8c0dadd2a6c2a7ea0fa43e1a5f2f5a6be3fcb0de6875d8cef1ee2daad87125d12f6869c4dd3d931b296f1df2fb3d4d77f6246c57d398c57848db8d3f986c475a41a23d424cd3cc2b362c1b99f2a0000000000000000000000000000000006fcd2c4fe848e9462ba1112baad39031c210952adbdd06293a622ffe2d1c6e4fcc8773ec8913717018b97bcb9a554fd00000000000000000000000000000000130a97442f3273b7b35464545e7351faf71ead9b8996c63889a45945ed82bba29bff5014776c6185219a5234d8475c92000000000000000000000000000000000491d571bac5487b866022a0714be11b38bfb296233845cc434a50be1d35f516b8c6b046fe3d0a8f4f95ac20eddea01b0000000000000000000000000000000017e34b04e6fdf152c848f2432b7bd84b3dba3915f06eb77efb8035750aca9d89e92e1d1bc4871105c440d639e8d8b05541776ed9d1029918af4c5113a6110139b8bd7f938caa204373a28ddaa51430eb000000000000000000000000000000000f1b8df4e8fdfe32eaf227f5af9f2befc85073468f10b81d32d0e126fe2b0cc8e8adb8afcac73213b6ed95e8e843b97c00000000000000000000000000000000004e3fb435ae0fb2d8bd091f250aefe5922b353a64e16abd75627737f3bc56639f8b40652cae69c73ff1969925b0afdf000000000000000000000000000000001003aed7cfb00efce49d6b1a8eba27df87479a4d37bd7fda6121549483b669a1a761204b0dd28262bf27e5c8e180540f00000000000000000000000000000000114fbca7caf782b3296d0b26b4c362bf50acaecb8bc5726b2c99f904ec3d092d5d40991d0d30c8e79fddaa45f04a75d3fa64411438542922a7bac10806efaa633d31d37c0b223314a8b6221155b9c4250000000000000000000000000000000017faf481fd4cb0c373d21d7caad40e93d9a86e62d26136892fbcc6f6e48205543aff00c45e82fdd1d3e0e733de91e7000000000000000000000000000000000012e14fcb9ad4d9d15347cf004745ed4bd92097eeeb41c4cbcb728a234616363589d8f5ad4cbb61d31a8aa27627723c7e000000000000000000000000000000001513dad1ff27e053902e779e35d04cab648939317830144ea775c435a4b55e13fa2fef03a1256abf5c187487c25a774f00000000000000000000000000000000139da29de8587c7d0ca9237c37a116387385e9cea453b9e2003a37ede7aa0a3f4c1df55255897f5975b662be33622dbce7002f41c6acab677a0ad023bad2a61b11c1b7221d944018b5ce60bb61e87e96000000000000000000000000000000000c118b147ee3489f30c6ecc0256a314ab674110588e8b69ca6d265fc270c3e5b767817f861140cca5d7c6be4012d1ffe0000000000000000000000000000000014800790654726959fd876b035bade0da744fb36ee5b304f228663a531345120267c55ac19fd66022752010e5bea7cb30000000000000000000000000000000000193ab7ac2f151750356b6e178557460c9c2672b1736d19a20e3fa28082479ca60021aa68edf2524f1aa826ee70b65a0000000000000000000000000000000015cee9ac55ab45abbc57d0ea6ec9ee49f6c59f6b94f99589dbc08ee877d3a261ad77f5473fedd72ed7206647eeafb6eac26e55f09b787c0542878e4d720027d9ea465f829a4e0164cf618c5d9cde49bc000000000000000000000000000000000ef203fab794a0ef29eb2ebf00076134e5932e27c99d6d445695b9df2afe7563602e318caf5d44724a21790ca0ab0d180000000000000000000000000000000013b9b1b1d3e98b61b0f1a0ef3a1a4ceed57b6c01849a4ad66a86332b3d27022cfccadd3567e6709d2de5b23b23dba43f000000000000000000000000000000000c1fbace49684f4be32ef6178ac3a95ea3f50b11494340fb73dc5391d50bcacafb3bf0f2631fea9c4ec47327d644489500000000000000000000000000000000040f82812855aa3e3aaba826d5810c1049cf44e86e44e23cc6da437971b529d2f2676c73e1fb9da52640c981fbd710bebba67cc47e38a129ab1140fbcf0386ddba2feefc919aacdce6059a27a1e2efca00000000000000000000000000000000060d7a718dd02b147c265f71eb136d1f31781b12a41866b4f86d7374b93dd10058c192cc0fba928373b1526e1a5d7d7f000000000000000000000000000000000cf29275373c0573ef22bf87919faf5444847203c7dc6d2e18986152cc294be04a5b1a4b0536797158113a15276c4fc6000000000000000000000000000000001016d5b9d4d200d7b4b7cc3836b85d6697fe14db350badba9978c7b56983dd1a7e572640ee0372b0a4e2079ff4c1abf2000000000000000000000000000000000f2768d104d895473ddf8c6b3cd0e7c22458d0037eca6365c766879a07c95037ee0de00d32c974d767080935abbe0be1705fb566367d9fc142c4194b0525c16672b843aac1160f9056ebb115e80d377a0000000000000000000000000000000017b9ca4349fecaa43ce911c0b256680edb8a0906ef5460fc4d2004579336df1e19560fe960a7a7cd74bb6e8272e08960000000000000000000000000000000000d5b96dae738db59cc67a51c61bec6deaeefaaa51e3259243fa4b142ef59676231229ae386ce699fbe18c4c00bf9d49400000000000000000000000000000000111b79f4b68dad16550a13334d09dc38336a75a5da23a17b5064e2d591aa3dab4c2e982a9f730a7633070504663a24610000000000000000000000000000000018f6d3616a7eaf17c805a88c9710039644d01b61aefebf76717ddcda6f4bb34aa15702de1e92bdb27b27f3409638da90f7bfd990cc4dac62a0d730f56b4eb1c1ad77ca9cd58b089c23c2f6efa00b7fa4000000000000000000000000000000000aeb5c087644595d0912879f61959d2731ff55260c682ed2bc5fc55c13964ef7c1f70aeb55876d2264d558c31371ca69000000000000000000000000000000000e173848f4570525b03a2b2c86f4dcdb8b28dd6d18c1354cad31028eb1b8b44432c2346edaace093e3954c7fa6d338a4000000000000000000000000000000001949b0902506d111ef6318edcd7a58ca4d69f5804a028aee73c3786cb2db168c6a73b77194f7a021ae6ae43ac78ade340000000000000000000000000000000017c5e28ba6103d97e2f3d3611c0c78f06406e0da8a49ae29c7d460b52f75136920784cd500aa3593858b877697eb8424807c5a41ae2baa1e10ebee15363d1d4569f731d77a418998108f5dfae0e90556", "Expected": "0000000000000000000000000000000013b49054c3957d1e77ba2dc3ef75775bab9f0e9f76b33ff22e244e897b8ab80ee0749c81eceea259e99b5d2a72251e5f0000000000000000000000000000000012e017e4354ef86f73ec51921cbfdd01e3113cff044a049bdd34e36401712420790cf718bd28afa280ad12104c1851ed00000000000000000000000000000000097f28bee5d903e3c6de14e834d5beea5c847c3106742978e586ba7e913f8b631a69c473aa10e19df9795ebfa3ea6a98000000000000000000000000000000001953493daf65b974b549bb98e735da44b543d6fcfd97176fdc7f6f03617d90e6bb952a607fa8e5791df5dc1c9bba2286", "Name": "matter_g2_multiexp_2", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d4f09acd5f362e0a516d4c13c5e2f504d9bd49fdfb6d8b7a7ab35a02c391c8112b03270d5d9eefe9b659dd27601d18f000000000000000000000000000000000fd489cb75945f3b5ebb1c0e326d59602934c8f78fe9294a8877e7aeb95de5addde0cb7ab53674df8b2cfbb036b30b9900000000000000000000000000000000055dbc4eca768714e098bbe9c71cf54b40f51c26e95808ee79225a87fb6fa1415178db47f02d856fea56a752d185f86b000000000000000000000000000000001239b7640f416eb6e921fe47f7501d504fadc190d9cf4e89ae2b717276739a2f4ee9f637c35e23c480df029fd8d247c7a7e300bcb3c740fd1f693d4c8915c4c46dcb627f6de6e4847f123623cd23bac7000000000000000000000000000000000f20a07526a082e88630a0256d134a8a5e8ada07b1cead39ee838dcbb30904e9016107fcbdf1f8ba182308dbe0b043d20000000000000000000000000000000014fb7732f67abf60c03ac902577532d0acadb5f3db0d6397a42ba693526ad74f2c61a0195bdc9704aaaf12e65aa6d88b000000000000000000000000000000000018cec4fb81c85d304588d11f8b9c51f5a053df11463e5812a1b2e6c7144522ba36bb91adf219892d0007cee470032e000000000000000000000000000000000b8e52d958a12a9037e8be9bc0d5045cade2d6ea05c6e68462b3a30b5d4ea34e5fbad173761e4e216b2e6958c8983b28b473df5e282565a0783d23e65e283a103ebbddb5c884183cceb62fc32d0e9602000000000000000000000000000000001468cb35a60898ed129f30c261b8431df6a154c250ec16d85a22f8717593b2c21853d123da86d977a7938c5ed74ef23500000000000000000000000000000000011f4e28e31b5f9e6877192a5e632d8c1ed7ca0c42e6e9902ca68f1c2de0f648c6064436012c5c7b14bb8d1078e02f2c000000000000000000000000000000000b25114b2697ca7eb1e6effdd1054893a188fd382d387ec098f846c1137a9b9baad01653b963a0b0bf3cb50c3ce3563d000000000000000000000000000000000c1d241cb03e642c1752b1e1886472477c19a2801ec032dc220c3243952f882094119bb92b621b654b766bc900d2d4f7a048ef7cf5d1f6f625ee3aba091147c389ebebc5b8f3d285e16ef4e8afe5c013000000000000000000000000000000000c80d4474390fa791ea5f2f16b41506d8ae13ee0993c8d31a07712687298ee7978a724999500c42400d2f788a5a36067000000000000000000000000000000000592705cc5a8875750a4e6ceb42aa3bef5593eda9e8212702a2e08ea70277a2a66526bc5237be33c8449301544da35e60000000000000000000000000000000000facabfbd15284c6433f17b0e6035d4fdd84d3ad2dd30a27d52809652ff6e7a684d7724697919100567ad0c3e1a26320000000000000000000000000000000006a0fc4e2af69ce15a356656f5d182a2cf213d76a6047a05a1a3375909d245f5316b91333d2141c0817438f0d87bb52da9b63c6bf36997118d58600c1e429c105a379b9e8b0de934ab9f433a4fa63dc80000000000000000000000000000000003f629618e1fc3018bb836301ccdc59022f0a25cc9c5de6e4c31fa08feea525c83256235e4ec8364e77e5df478f5f62c000000000000000000000000000000001120d6af221ba6f4351bbee4c2c664a769adb17872646df2c408f70c99ea991ffced4eab50fa98be1bb9426915f125930000000000000000000000000000000015cd16b028ce3d58b10aeb84b783475d894ab3f0cfdf7104ebb4f3417a038107128f07518dce548271061cb8c97e88af0000000000000000000000000000000018379875b68bc26107f9a068e5034f29dc2ae7e8830f8e9ecddc53fe7991206646cda33d37b31a47a977b46be58d7618f228da17f49667c113d2bc2a2c8a338f80be68496f5145b4be21a5786ca6d46b00000000000000000000000000000000036570783711b381830e35878fbeb187b84884a9a0e88c38e84124515b470e6ac18157e1499026b27f4f731a961eaf330000000000000000000000000000000008382838c18d56c046a8db495babf8d14c915622d7917ebe10cf7da7ecb65f174cddb9e70d0262ada961b396c5511b410000000000000000000000000000000015f63ce982aa581dad5c71fc79251b7f6336c4e78a4a0f4cb6f87167cabd31cbec987d7af4f11dc6d693a0b0774864130000000000000000000000000000000015c001372fe0530a3f50fb8b30e75ff4b264d673e0448211d082c7a9018f583b4d01790019874596c59c68768cfa3e699431e18a462fba704216b516e819fb3392e315b0c92a7411a329cdafeb51124400000000000000000000000000000000074d78cdd35ea17a3013e2301fe9f80f2d20d270a25fdead37eed7697a52d152612543781763e6035fa5452ab12cce25000000000000000000000000000000000e572236e1c203a1c0f99e6ec978458c1a143a6a650eee27cfbe406bb2858fe5f30222f468d119703c2f442bc644ff3000000000000000000000000000000000125384343fe132e16a9fc15efe1b3a9e47289e0afc4b44d492e33a6216edbc96d66c1ca66944a8296e7695f27f414c5b00000000000000000000000000000000084c2cbf0d7c932c3098ded7c70d4411eed882feb0f79e0f7f1c31f5fccb6d53fb57de179c3ba5754bc5e532c3784df12051041bd2f12f6e6e29924139770fe209b7bbdbcd6c0bcabbf5021a7dff2d830000000000000000000000000000000004d46066439c3ac559cce863c58316883651023990180470d2efd06e443a7caf3a514b54f15ce6e850d32779215bcf4a0000000000000000000000000000000019ce904b6c9c3de59f7d5017f60f1978d60c564f94a0f1964c24c876d1139a7ffbeb6d0d4884bbfaf5f2f189af6904a50000000000000000000000000000000015f1989719e69be95f25dda9358fb98aae2819e0deb7e2d291e2c01e85ba26a9da421896c6b6e2ed20f609b533154694000000000000000000000000000000000b287cfcf1dd7c6d735c1358dff15393ddd6c82e7a33c5d8005c4234cdf823c76a4725fd74cad74b3ec51df67f09af0fb96df57a600dc3b5aabff5b1034886d24f6fcf035bcacaaec738deb2cfb8f85200000000000000000000000000000000006b37e2226957d639fcb0bcd6c20b3c7b8372e7347a14b970e01c67c1859fa97c754ce588d0f835ecc053549d963ab4000000000000000000000000000000000c6a5fae8be3a32e3f70a4202a1ab6d97183964b9f7b9a084c49922cd9e0e952b0bb66c5580f0e0c417e079493bcdb4e0000000000000000000000000000000017b6132f11adc0d5d693ae7f3a0f89f5779708083eba23e03b0c9265e4e60624e1fb6940e8ee49d31618fa6389b1b50b0000000000000000000000000000000000a45c5f6df71359648aecb6434bad1619c39f10e279a02b3cc9725d0256bcd126843fc9ed29cbe02a32cbbe79774a3378176412b07eb7f423f23ffeaa0ee642590e0b7016bc063f3fffa93e1e35484c000000000000000000000000000000000ffed009c78ba9af8cd33af7b7697ae4dff863bb92365055baedd2299b7f5b5e8abb84ed434f7223c3e309ca53c08aca0000000000000000000000000000000003b2370c837dd6291818efe7c9af62dd51295c418739ecc509d42c92e2c97d12a9fa582946e176e8153fc9a273140b2f0000000000000000000000000000000001e63438e8b4a0462cfdff64a281ab4a7f48d51b51325817139f8ee683484f8695f1defc0c3efcca81d5fbff06cf9c54000000000000000000000000000000000192fc391cdc1ed6ddbd317f2f366f2ce25ba27b8c0f09c733e7bc0c0697544399a3a4f1186d139a8f6399ffa88e89a69c4b5627d84e153f3a4ecc14ddd6baaf1d62253a0f88d3af51be18d991976da000000000000000000000000000000000002e105e0eaa418d58019a849b89accf665a94ffb0bdf308a11b99b521de7af8ddb150c0e3b2e9c54cf5456b6105bc81000000000000000000000000000000000691a3b3986fbe1c0ea22329364454f37f645d6abe9310e883b9191ce512347e074e18e28b88c2adcc76190a549b80b40000000000000000000000000000000003f3a37a763c8d0d99a3fe36923843a22cb0fa18ced48493b2510fc99afe5b7699bbaa6c2ecdad8aaf72969354f121a1000000000000000000000000000000000f4bbae00205f54eb10c83d928d908fbae342b76050e33c51b6e282e02b3c1f132a4728dee4ea95455c25fdfc112f2542ed270764791aff081f1dc8051d22b8e18803a7e310393f21bb4a495a445cd450000000000000000000000000000000009a3e98fe4a98582ce9f274965f376cb45e8583775dbadf626cb1327c1f8a25b293b97e7f8f31ff72ba7e8e769ff25ef0000000000000000000000000000000018e4785ccb76c4897087c8a4242ddc744c6a0a53a4a844254153c23d6f16d4ddb945252d13f93101613f4eb0b1e2b8320000000000000000000000000000000011b81d344eac04d3471b1edde5e51f31f97bea3396580839fa094db58cf6bee371bbdc045fb60c3ee5c6cd5d3f6d3c4700000000000000000000000000000000073476bc5b1d52ff4ca89c3afc099417f473543fab6e59cf9de8a19705dc4bf2a210b1e6de4dfbde035c312be0c70c56fbfb7606b64eef0460b8f33a0be54451fb655ce0b81db89eb7862f392450354f000000000000000000000000000000000c414b95b298b9c673001173ba7e5ee3e03926f28068481cfa0b469ab556f8fceba9fd0a815180ae0b82c265fd4c6b7e00000000000000000000000000000000054a242c1cc1a9c710bc23305d09c2d613ee8eb3840b37943bfe83f9c1db456ab4436ad319fcdd8684db129d76c95320000000000000000000000000000000001683711c0c7f02e67374f190eed1ce6559479d6d199f43fb5b0ce7df7774a5cb21c86b3b3498855d9b69c5763acd8c4300000000000000000000000000000000062f87085dfec847af518bd71c078f994b090c3b27c6eaad79772ab58afa43993db52fb08649a32629d61c3db12c87318a29fcc442d0c2446697e94dc47181dca7a314f9073c06aba6dc55aa79978d7d00000000000000000000000000000000083eea9b5b2d5ac5f7ef51ca889a4317322d098a408a741827fb3419eb12a51c07c788c2798cb37635e224e99bbc894c000000000000000000000000000000001312ec00f4b3a4305700b44b3f215779a9a8bfcf5b5d3a7f237a33c5484099ec9bc5c8537fae768e2c0ec62168f383d6000000000000000000000000000000000cf1d5d05d11e1d07074dd34211d0f00eae1df4dc550c55bd2fdafaffa1ad36abd5da30c5d3a5aa2845b1d95a5cb571e0000000000000000000000000000000015223baa9f2ea4b04fdb05b05bf3a94dcabc5e64189aeee39c380de9a34fe6b4253f5795f70bbe51b80e1aec1eab7196d5b468797b4af1978983faebe59a28f34956dacf5b7f65d25548bcedb518f45a0000000000000000000000000000000011a960cf1978aa2ce1731b857fd91d2f59d4b8d7c6871ef6f4f85aeff549a2f397949d11a4793926fe7be37f3a83d11c0000000000000000000000000000000001954f056834d6e3b16043ef1acd0a47a353300257446e9a1db7e58bd0d7c4bc9ceb3db51ae01cfed9de99621e96934c0000000000000000000000000000000002e2fe460e71b65595ed93a0010e5ccd1a2c16fc4e0d345e7226c947f29720d2f3f54282f79cec086d3fb1999b9629b300000000000000000000000000000000060dd8a7ccb613f1521168a8a322aef9f84d9708a893f704f4fc9a19e2493f25620a47e0fff1bc1e212e65e92873b4f2dbc6afcdd409e5d50d7b655580f1144de77f3efe5d6268032eccab7deaaad997000000000000000000000000000000001472caba61c2f1fe4b1d0912b114c25de103ef4351668f22f3a158d7a347539a7b6656044bd490f036ca3e29dbdded370000000000000000000000000000000015f8cdf7786410b409f218164063c99e77d8f72f03882a6c9430ec725ae574547d3ea3cf30c3ad2c9c3febe6c30b1272000000000000000000000000000000000ccbbed85c2809433fbcf22d6490457dab800b21cb4de414c7dd1804a0bdeb7142f8ffbb2de921c2c9eabee6a6351026000000000000000000000000000000000a404f42c48e3ca408d3f92079b99805004da928f128206d8904ecd7fcb14121c7d9a9e7fb69accaff921315ef3d5372807347519f114e78f99617f6b147ca833bff7be962c9b1e1f32b5babe6067d7a", "Expected": "0000000000000000000000000000000000fada9f43b29abe15693d047adc277814cb94694cab3be56b92312ab7666649b8e9d92aad81f8e487be0f74b9ce8c250000000000000000000000000000000007f6891775811a325cd7f548011ad4c705ca0327ea0484d938ce061c913a7ee6978293c3258c4b865d5c2325816c39990000000000000000000000000000000016761f859beb90ea03aa35e954d112da02daa8e76de80297afde9c29cbfe8ef4d42dad535917685a99b2a91b1f952ae50000000000000000000000000000000012a4f24ab88341dfb8a60c19993b8abea96dbd7033d3686c40903728b4fd4da7d07961f2584b51e9e6c05976d555757e", "Name": "matter_g2_multiexp_3", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b52f05365c4df20a7290aee71a7e030615d1a2a971167884d835c24e756a0faf6ed0552341c561446c7fd3d5e887d830000000000000000000000000000000018718ef172c045cbf0bb132059754b62414097eef640a781db6ad521af5a24d78c622d9402033fa939f70aad0510a1ac0000000000000000000000000000000017e969e44b4910304b350b5d442bb6a0b71e1f226cb4603cc8b4dd48614622f3f4e1ddecb1894046649d40f261d94e030000000000000000000000000000000004dacaeb9e05b9d60ce56c17312a092cb988bff426b8a718cdff860186935507a06eddbc4a1a29e4ef88db83fc4b6e77830630695c8dabe9aded1b5365bf93770aab7e9ef4140a2bbde2f0a7b109724d0000000000000000000000000000000019829d5799eed5a081042e4646d46fb6bead6d3b9893a4240867b25ed6af6a3e154514f244466d80e3b9311e060bbd7100000000000000000000000000000000156157a654db2813cb9c1b4da0a3ee192fad076bb2767020fc5fc00e967c1a35a367ffa375703e1181b3705ace9dd28000000000000000000000000000000000093385a6a9dd0ab996df54b23f47f4a49b3f379e11bc8331016ecee6161fcddd22f6d49fbb21f098873f1e17424dedca000000000000000000000000000000000d5b5b0f2ce81e755b4030b33fe3a8bdee38c2c60ed3b4a88bffb9207cb762c0a5c699ff424c000ab080d763abc5438d184ef5eceadfd77b3a4092696ec34d0551c88e434567638623740b7d5f9e36160000000000000000000000000000000003af8c25bdbd0dc1cc344d55366f15555709a74e1f0d8d7050cb6b487759db6200401b7868fca3c2ad26e6362a30e6250000000000000000000000000000000013f8b6ffe30f9a133fafe64461d305cc6b2cf5aededf68ba396d4e00df651531c750a3d94dd77bc5c6713b939b18fa19000000000000000000000000000000000dde97855d7728f409d873b83b6879b45ace5b73f317687fbf478e594a959ce21d4d751db646ceb20432e8311e67404f000000000000000000000000000000000fea997323cf29710cf0e3d44ce682e039d6cbda155e43c94dc8cefc5e94000de4b9525123b9615b5f1019a46ef37ad3a80d9efab033e920061cee8f8d7ea6023cc05f08340642613628b39e7b7fd0af000000000000000000000000000000000cdf60e3bb018407eab162822468255bcffd54cad9127054bd1c30705a4ebf1afc7f539cca6ba4cd070b44410ec751150000000000000000000000000000000009a2e3e5993b6a7007dedbbd21737a8c0aef3ecd4607953c4a24bb3fed97ccae01ae1cec024443f300b570a66e9ac3bf0000000000000000000000000000000008a21fed19e9ec2a741ade7767b0c9f39b79c3fbe34aadc9eb3043583768d893bf927d26231759290c7dd9c4f158d5a10000000000000000000000000000000018eef4ff88d63149d2632c9db586a4af0606644b16c82fbb0a3b869f1ff924c59acc8efbfde7bc604497ff68939cdd0845111c860f6f5725f99b225c53b9fe1a70150e7ce922bfe214900aaa2790d145000000000000000000000000000000000f5d47911596c46c0c08cac5f5e7f6d0609874da4ac1bd4e0e59c393273a5fe31a756c7cfff2a01d19e79d209d7c6d3e000000000000000000000000000000001010f864eb6624132d4436d18db7f5b34727060dc426c109886be88031e3c155490cb3fb09e1fbccb7912875477c6d840000000000000000000000000000000005cfbf1c2ae1b80a8c7cfb2cefedd907b0552794f4fda101ca1a723b18de8cbce30eb54287e1847cee3f416cd8b45f2c00000000000000000000000000000000084fa63781f7eba9c7e911ae5866d485bc7e90603541c55d1ffad8b3cf7547fd57fb24b14002560e58410b828513e109c07041840216d60ff445cf53b273a46016c8ecefefb53550f8bafc79966f863a00000000000000000000000000000000124870cfa469136c638e0cbf15802f2699aacb66d7e4c2965c6759dbca4b7e47941ad9ec37a84db1afeeeaa65a7418e4000000000000000000000000000000000d4503049a6a53536bdf41dd832a6ecf3f10554887da7e389cf940394e1d88db94369b7947436546eb6c6e82c48dfb9900000000000000000000000000000000053f9a6e1f05b67cf553073358009a172e2ab8b43572a974da1f3de85a29103b13d7e67b2a359297172d27dba5c61439000000000000000000000000000000000abc29f50ddc1c113c73700b9b9796890cbf48818ba981fdab2db27ef1c58f4c2e4595b99eae397d40990ce2f6c9317c29b031b82dc8c9f4ea9524793b54207d4e13a548d73297f2aa6241aff57abfd00000000000000000000000000000000007d2aae9794b7a7de97f7146c0ee8415e09e56fd42535bce6773cadd6f7ac09c4eafe2e926cb7014377e54c703eaa9dd00000000000000000000000000000000172a4a33ccf99eb0473b2c44d30bd53159afae0c7706ad128bccf6258974d5e5761f9be43e618cdbd96027aede7fd5860000000000000000000000000000000012601bce2171c6e4c2968a3efdf1491285f9e4ab37cf973ab5c8e224ad5b40e1b6459ac89090c73deb8fc79fec7fb8e200000000000000000000000000000000112a6443116e6f98ab348e57daa3971b5fa506e40515e1611fbed3e7dd64c5c1e991e0d2539a70eb93e3da0f573d6b2263d26ae92119c7b06d83d7e2922e06559b1740eae315c6623d3e543c9bf54258000000000000000000000000000000000030372914b83644fa4db1958831e9335c72ab7a811fb337696221a3290e4c54bc10c2225f8fdc3a9f62632ba2f1594500000000000000000000000000000000114205926609470b6022d24046a1997c048e6d2cf6043397892c967692161c0ceedf409bf5e1199a64eabb1ff8de23640000000000000000000000000000000017cdecbe73779855b7b94920d4bc8ad057ce51c5481a5579650df8a5bbc421030d2ac44568217c4dbb13d7c639760236000000000000000000000000000000000f194fa814bfa7396697bd812d9449d06fc61b580d7a86429fdd1ad376e21ceca139356d7d13964c3c684563675711c67a02c61a7a75342ee7f0745886c0ea2a73c21500aef8078d21d20b7216c2990e0000000000000000000000000000000015d4ae1521acf897344c3a76261754ff99742585af4a0ee86dc473a88fd408091404df1da9d8bb291db68bc9c07d6b2b0000000000000000000000000000000008ce160213875c661163990f3f7ac219ea295db5e828354864517ea8689ec15d35c6df78ff14cb276e0c97ffd7fbc09a00000000000000000000000000000000038a3ee211e777d6d6b7ca6c7a0d2130f1a071c030eebec412c3a0f14c3584e7c5cf15de254a8f141a8210a90249ee5a0000000000000000000000000000000019f7ec6b2fcd8b3190ab37a6e843340d3f3fc092f5772a042edbd5bdc967b96e8a1dc9e435b8463496aa1301f87d0e5a81b0c87102055dc2901826875d5e85a794befd93fccca2b9c0a1f70ef5610d83000000000000000000000000000000000fa7f8fbfa1d4ef5f001a451c55ed261dee344025e599884b29d086e15665867932120d33bee579d5eb1b7e6c7299f310000000000000000000000000000000001f06356f793350b17b47a623059a068800ca1eab6089c7c146182990063e8e23bbf40d95a42bf6e976224b680b75bfd0000000000000000000000000000000008807f6606d2302450bfd8b38fd4147b851ff59762c1ff48f9442c4d7b77a32c5e023821eb47fca839a27fde60e5f61d000000000000000000000000000000000c5b92f1ca9c20d4b6b11d794a5853824cff20d9267a20a7aaa4bed8bfdc728c4d4d50feb8f0b569757b97f473138db1ebf66fce49c6beb12737fe05e3adc0a51ecfa9144ccf6253088dd1a7a483de070000000000000000000000000000000001191410ec6c5ff628bd25d35965f5e9fa7f3c3d8c0a9a1ee7ae37437a97c25e221110d892e2c7a0e9c8e386774eadb80000000000000000000000000000000003be30c25a18cdab139277232d8888f6d13112c9556895af8030f1893114d5845d895df9afe3c6f9ff7ffb1919adea9200000000000000000000000000000000197f6b4e38be0358a3f1722664c61e62587ecf5467f8aadc3a236b47682a75cb76bafb18a5c556b321d5da49cd4bfd4e0000000000000000000000000000000002e4ebf7f22d929b7421a600e67fa2e64a59edd87a2e2eb9dce1f06d3c793f1a812bcdd510e654d44fb4c1de8c64ba9f0305523dc79dc4b905e65587fbd095ed57aa42403d2df5dd489db8f50c99e9b60000000000000000000000000000000011c6f1dbccde640f63ad7d40089779d01075e26269421b4ce12fa5341f58ee9110f17d08dc1052426f2d00da2dd70b4f000000000000000000000000000000000740b147bcdf06705971c113a5cc12fb37345dd59f2cbb5ff500ce2b347fc5a8199cb3007a871670d5093f28979cfade00000000000000000000000000000000046563ea98b5e85b3c42222d5e0d8481e6aefaf077a1b99f2b4eefb397ec846aa3659aacda569054c9c8b9b69750272b000000000000000000000000000000000812d887943506d68e3525ced9b979354539b7b14003a3169e0084c26326b92be67346920c9a99ef0f9638e8991296feac23d04ee3acc757aae6795532ce4c9f34534e506a4d843a26b052a040c796590000000000000000000000000000000004c8078fe8567013e8d05a546934026cdeee7d485e30d739407db16fefaef53ed7bff0f9adaaf064aff014ac919d91c600000000000000000000000000000000107cc17f485af7f22e07cf14c5cad6368323f720511fc9dda677b360567f769e47a77f61274927ef9b7be48a77357ec40000000000000000000000000000000001487f0880a6cbdac33ca35b9b65e4ead9d8c2e9180c993bdb2052060325aff8c62668c643f0cd9b4bb1f06a3dc74285000000000000000000000000000000000d4b2d062e31fabe8d2a329dbd6417673a519f455739d140246f2b3e43e20f390088c08e545bf0419d796ac71aebb5198586d7ad8fc3e4fb42981a4415224c0d976ebe1c342e9bc1cd66d35168bae33d000000000000000000000000000000000811e9b0acfc10830c074c5a4d9f4d9382461eb523a61dda0b77f1c43b285fc5c1ef3a1fafd923addc9a6e904505a255000000000000000000000000000000001113102d015dbb509f0b8d0d0ebb4d3711c4f0e1e3d55fb0af247dd24be4fec9d6fe3ad73fbdcfe206891bcebefee4dd000000000000000000000000000000000085aae9e58fb97b96ca3c089acab7bdbd0c3adae141bf61075f5c13145b0d07113f1075dfb959bc7c2d3d3b3a06ab2a000000000000000000000000000000000bb5eac8125807c10270d94e5bcf278241d6fa82f68e41b5529b28aebc88870af55881db526f7bd221a8c4c0b29a1b7d6e7db0fbd2a7327c85054b4c0de9727dc0b051058f8bb4ecb1dcc7f825781712000000000000000000000000000000001335276775545fbb4c701beb57cb34312108c9f1d46b4aa4b09a16faf0e648b4e80848bf5e75ed8730715f0107afc9820000000000000000000000000000000006ffff8736bab41b4ee5681b741a81fc870e648001027161144254d04c678e4f954e9f191bd8b26201aec681cbf0654b00000000000000000000000000000000026ede90d14fa0885baad21f9631bae058573251cbef5757bb8cfad061f3bdc78834fa5862dea19a2236c014b0f1652e0000000000000000000000000000000009844d0cf7f6f3401145d8d720defa577ca46b49e04e39c4c139ec6811a574e7dd5ce3acd00d1ce9496f10dd15c6d94685cc8d88273d4aa822f44a447cc22f5a58c420bcfe757a459772825619669a720000000000000000000000000000000010192b925fca096682acf138833b12d96bf97c9a2e69e4266eaaae1785b9008f36082e23e2d42341427edce24449935f000000000000000000000000000000000d5b24a94adadbf542aa663114096bc670e1b6c99f3b661f55de121922452534faed7f68d6b431fcf6f3e379d7acf6b6000000000000000000000000000000000acdbcae49206b749d8c0d21017a33e689ebe26804d1fe7c863a2ea4210c3559805dcf73685702bc56e644b4e02614a9000000000000000000000000000000000092309d684fcdf44bfa321d473060dc2d8a8c66c51419894a3fbadbf1b56179c31dff25403b970d543f1dd0e19e56cf5b6e462d809f8bf1a62f276dcb27e42d9aa0ce33fc4e149e87181aca70a4ccc6", "Expected": "000000000000000000000000000000000b219032a2461a5fd1e43361c46beeae92e30247acadcdd241692abe81691c295ba38a1f0a2a45ae76b1b95d7d0fdc460000000000000000000000000000000016905f64e581aafe928520adc27c24703e7adeb36dfbb416a159cdb9b9a26c9cef0821ccf52f5ea5253b7c9d78769e9d0000000000000000000000000000000015cfff195b2123aa140f963628c41deaf19dfff44d26a38de4547c3d15edef10fe9f65b1802dc374d7ba8fb62117c8880000000000000000000000000000000018dc725cc8d8919a7414b7866fdc54c4467b0f87cf99fc9b36cd65c0ec526e32649f9c57495657a93487f1f2f5769168", "Name": "matter_g2_multiexp_4", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000014441b14765eee30e8131a7ef62c3b59370f2f6f0dda20fb2a3654fa09492bf695de1d1a8f250bfde3c7d2ed805ffaeb0000000000000000000000000000000019d813f8be2519e89d42a9fd3fef09d44a996d6a4713a9c224bee10f0ebb196370d6231fad810edf9cb4c875f08357890000000000000000000000000000000001a5abea13e909bbefdb51ddc699614366f271b2f6490ac8efcca7759833f3feae11057ab1b9ea32311e7b6ea6de110c0000000000000000000000000000000003ac2bf3c5486ca176e34ec5212165cbe04fc9e8c375e3e999a31fe014eb824ea3f2d06b9cf8b86ce3a76960cf2eb4d7535b53ab5f1c596eb966f57867e021d0f3b099e17bf384479c959794b17d6a4b000000000000000000000000000000000598e111dcfeaaae66d1522be2a21131350577253a3f33bdd74a04b0bfba2940e73b62fefa8f0c34c4aa91b633f6bdfd0000000000000000000000000000000017fefff7d94afbeceb33714e9b5480c3a2f3eabf9d7f6e8507ae54cb65f69b21cd7d04d23f24e3a272c589f572b91864000000000000000000000000000000001652e3f5a99ba8dfbcd1f90de955ef527947642054be603c1b84b24bebb579b78e2a0be426ec21d32783a0e55f0178dc000000000000000000000000000000000a6c9ec91e8bc86ab198416cbc76239f0ac0b903f40310ee1f2066b01b08191538ca913c2736f53f23ef37fea13d52756e0512ecbc5a1b02ab19bc9bee4d3d9c721278e07b7a6e389c4d6443232a403500000000000000000000000000000000072e022c168461905f798e87425f2eebb517e473cef98c255d0fe434863ef5811920af65bc946b29d489b5dee1066c56000000000000000000000000000000000e7a9872caa82d191f6014c845e1b3ee4ea1ee89852b546a2c85ddbfa3c1d4ce99002e3d7732ccb8cfbd57d550285ab400000000000000000000000000000000144be65db373f6401d76e0ee64e51076b861e8fca596dd6a7f3b5735c23b0cd13248404fa0969ecaa701663a1032f48a0000000000000000000000000000000014c9e9c5cffc4518889f7742440053678ff1d9fb1a1a103d0c1f762b10655bd5849ce98f4bc5eae80bdd9e767aae4523a79fd15e80b694122dddb01f836460b3eff99e61ea6309d6b395c94fb5a43dff000000000000000000000000000000000948d0f0c20715f8658e1f2b4f9d32d851e584287225a2f47735a1f4c241b07f8d7c5dd8c13bcdf84e97d49817d4d88a0000000000000000000000000000000013c064548cb756b48600dd535af8eb5b9138f984bac0391df2e90a204fcb6c36017df910031864d802a2ff719856b336000000000000000000000000000000000000b7eeb7c9a01be88e573f196c2a531635baecbc8cff9af385455af3757301436686596ec7fe3618af26953c49f7450000000000000000000000000000000001332f4dbd5461ab9e2c8b3c19c6ff407a071018c92d2c17c1d1d481c24565276c0f55eee8692016c1fd76d70f44627cbd012914a96253926fdaabec06944ffcdb4637a05e3e78a9bcf1b21b68b9dd9b000000000000000000000000000000000d3ee70610b5029a28e586f0f3e65bb19a263db3438710fcb8073e1b25f83db50eb5bbb9d75cb20952a225023f747baa000000000000000000000000000000000682f7d5cf9d182b20ee88683f3915e8c9b03074a373e573aa57232de4e997bf155acf680e365aa0988989dfad102b2e00000000000000000000000000000000143962963e230a9154dc328f9583f5be6923a3b10ee7b1d0cd5f5cbff13913d8ff78ca315be7387900a50b94449884c0000000000000000000000000000000000f4f934b42452d41cc20d7b1ec547bcbcbcc10f215364ccf2b864db23a09d06e94c7a87165dcb691f4975323486757ada300c7e1041d94df0e0201e1135fa6eafc98bd33b2dfbe4c59b546a52538c07d0000000000000000000000000000000005f0fd4080e26971ab16d33aeae04220ae23781da3179e38190082f1d167514bd73bc8ef976a2f333570e9f56a6c05e6000000000000000000000000000000000e159905d29b52ba61575c3a263093017783e1028b3701ccf060c165ba33a765b5265a9b1681c1759bfe2c9c401275e9000000000000000000000000000000000c5ac0bc29a49a7c37d772954da850e6b5e301e230552be9a94017d770ebe2cf4dcfaf104633623e024aef6db57892900000000000000000000000000000000002228e7f42a9409acab49cca82cacf306f6c6c29fd9f7e2ed12fef2d16383cdb7bb2b39ad598b301072c615232db1fa833e9cdb10fc117afb17803b61a2bca7de1d190a325639eb23743f51f28294b3300000000000000000000000000000000180569ce03e4a0155285e733adb18fbca71225507a7adf01cb8e8648891525305e92087f58378f4fd8455d5632ad660e0000000000000000000000000000000011ab84e42f10154e306a568d7cf7bc381000f0add0500cb508f695a3b283ea69d140aa0ad48fce2d2d6fcafe60761078000000000000000000000000000000001136c3016474d6f475609606e8d0269fcdab9fd3188a512681cbc41eedeadfa3b3d9355e5b4503e8b5c3665e49fdf3ab0000000000000000000000000000000003f56cba1b9cb4302099b16b09c2602dfab80d1151685ef78e5054cd454b319adf8b5998053a5b9fddcffa020595e3bfc48b98edd9c229037751d02e58f3d4234d9a3b0ad9ae4947ae14beebb274746f0000000000000000000000000000000004d79dab9eef873f3415d66172bab7166ce0c71f322529bdeffa915c1b0d3fcd645c91dd3450ba61593ffecb95edb91e000000000000000000000000000000000d611a207d3222bba199fa083d0459675cb5fa00839fb4c9034ad868fc1e79d653c18651771431d6fb6b6b5ce8cf6f7a000000000000000000000000000000000ce802ecb106a4f0ca4efdcc058dd0e29deb6a5d30a2c15c8eda896bcdd3ac19053c10105328d239b26c5ddbdb3a95fc0000000000000000000000000000000001073e142621ecbeff6f81453660362545751f992ffeec3a83477fed3e6215a709ffe0d17b65d3369f8f3913bf000e844228758d2cf8105f2ef11d83018157a3119a44874dc34d5f0bddb533f50df52c000000000000000000000000000000000bd84f04b3858b1138b1b429c7216d5d1b1e99c1e0fec26440d59b1ad79788c2d5583122c2ad769fcaa6d10d816a1f1e000000000000000000000000000000000387977ed1ce5da51dca230531bba53d17d3de5d593ec576cabfe6463d5164d7153025dbd4cb3525c4145c4f6b85fc76000000000000000000000000000000000a19c943a90fec6921367a2edc5bc38a5c59839cdb650766a2d2d068242463dd4460bd1d0e7a7fb0e3d2104704b8b3730000000000000000000000000000000011d99d44b200feebe00bd42809e3f67a23cce88a07165416cbfaf4db14420f99e54d62db4280d2c99ca0bc3dc41eddbea417c96f0cf4355a78513c77cdc676a7b09125802c8045756da867e0025a36f10000000000000000000000000000000006a186aa584a466a860849c78e4922889c95a4ac6f39c99029fbb422c43d699a8baa51aa4ef51ff99557babeb3e9506800000000000000000000000000000000065fb15b5a0923bdb52dbefc7e9f1a898e32f17d610bac829235446fc5e1913fffc8176e0fbd33091505761f1d06d8920000000000000000000000000000000008bd358698fd073f660ed608462cfcef1da9a59b10905f1d98c4fe66958e56802814906430c10fc25a4d351d91f91cb0000000000000000000000000000000000a53638b1b6c6eeff468e099446300ca7c7bd899c6494682d14fdabfa9cead0bb37a0325d99e7d0ba6341cfa1d257ba846561328b7689b0a89014823537cf9eeaca6ea5c56a3e58d2abfc2ee455dfccb000000000000000000000000000000001070b98c6348a67e996626ec2752f45e4c007e9c9668459a777c03fab633c10236a1c5be99f3fd950542d5648ef9e88400000000000000000000000000000000073a564401cb1a3a53334c0a55da261814d27b86ebf40b02a76b20973ba2db92e42c138ca7790261c2d70401c984bf470000000000000000000000000000000004212d8a9e4b01f5c6814a88561c2c6143eea61327b031a2e0e4bd056c12dd7098fdfe4d1511bb441ad42b55b584a7bc0000000000000000000000000000000005c5d23824b0fe05eb962194550681c57c1566b315efa8ebc90b3593d7d86ad18328baab8118c9f47eccc0757588591ccf6c3fcd4b9e6b72853934b306a078b1f2fb17879db4a0a93d484abbc2b746cf000000000000000000000000000000000b1b3053774ad5515a20bd4c556d2b3ba95fe74fd0c955069c7f933dfd718ede90ac295f5a675f1c29dcd9701978353700000000000000000000000000000000145746ce88686021a0635bf6f0aa2f77c48bdb364cf4ffa804a57f95bd69d24eead05fbee24021c1ef57e1c7c7b894b00000000000000000000000000000000010ec4795a0762b86f3b83de1198698af67fd1b1be3ddef48f35cf82bc96d886fbb4c75064f51a9cfc5f61630c95d0ad1000000000000000000000000000000001465e31f58892466b8ae4b76a239d9f8d1ecb1834886344013cd1df0be13591798868d224d38213a6d75b02a1fde0ff2f6787b565e8d71be6fdb0c97c4659389c800a2047f668b366214adc716f402d5000000000000000000000000000000000f39e731e6ddb7496448c912ae314e833d28208252c7f8e27bcf7eeaf1da6e2310538b4ef0d55401c6552e91fd70691600000000000000000000000000000000069d3612f924961f827497028737000513548ad8e104acee28f014e730d4752a583cb9a893e6169b71966a1c4a4ad2dc00000000000000000000000000000000090899907edcbd336bd4fdad0dd67c578ced4481a25b864b32aef920842689a2c23265277a6e1d4a1dc1b5047a9f79a000000000000000000000000000000000055ba64e2502baf68e46c759fca30247a080464eda2b32e7cfe539e545d6aac6dafb731c2c45749e50513979cecbeb5440ed91f6ceb2ccf87e4106a16227a3cd7b2821b4f3a6e629001f78ba1aa7346e00000000000000000000000000000000042f1c8b9fe81cdcabea047d0998a1354ce09d62a14f1d0e9d188e2f35f2e1845c2b090c5e157595b33108c67e6c184c0000000000000000000000000000000018e69d3564d4ccc0306e1e6b227b0f961aa9afcad59d4ee1737f980dc876609c59a4c6a3506f987467beba0764b857000000000000000000000000000000000012ce5883156588cfe0f4838f819f985b09f1eab40a5ea8e30fc5d70d029a01a4537641248f4c21dd203909e0170737c80000000000000000000000000000000002888eb9778a4045feb5899dda258657b9f41345731ba630fbbf186b3be4b58ffc7f48abb65b693b573a73f85440a7a7ae8ddfcdb4748981acb9b2037c017174a140f2457fb0148fe807fd194a9f7be500000000000000000000000000000000051982b46a819c74105cb36da871fb2415328a1531d155856f6551bd043eca62ddb61f24af429edda830fda31e22cd340000000000000000000000000000000006449e5bcdb5619aac542f6633ee3e06a4fd56a3e1ce4034efc608131ff6ead70ca63e70f494f519d5c577ae7119c8c200000000000000000000000000000000153f4f5dddd5801fbf7f88a735b9170d24d5b63861d50cde9644579dcff277cdb0d5fbfc3b3b819a1172de05afb9135b0000000000000000000000000000000010fdea84983fe6c08cdc4b4ccd462bae2ba791ab5209363b10b3ef342c9a5e92184e9d8be1419e3d88402bc05bad5fa21268803aeb58a2d57fc797358fb456d5cf96afecb1ee0d2b90782aa0d652b8c00000000000000000000000000000000009b011f793d9a939d916d058ffe91b58138820a646cc450389b3074ae3715d06ddec1075afecda71c65c7ca085210c740000000000000000000000000000000003d4d20f4b93c1e90a0a06bd534d8b4fd64e4c4aba77ae42cf4c5b2bd95f8b02ec4069ea246ff46404e6c9eac632fbac00000000000000000000000000000000051e88c3adfd4d6a02d3f03812362a6cfba3a6c69b9aeef75b51106cc7f1750293d61e31f0ea29b5d7aa56debb6d2aff00000000000000000000000000000000086d9c4ea6769cdf49ffbbf7351023b4aea640e8c90f9291222fd0b5984bca4d481bf7e10df921406a34804e6a09f99df9a8a4e5c65973b785c1e2637937de239bb0fde34b786dceea66f6bb12eb4169", "Expected": "0000000000000000000000000000000007638fa4e8823dacb40ece440f8f1e57cc5c3851f94357a5325207db92380dd57a7c8709e4d00b670e8af1b77368285a0000000000000000000000000000000005b66a6e6b13ea0eb367a61ffe7c620d9edf5563cb4cc0cdfa68b99d9691cf9a40efd967c1e880238eec313eaf4c92ad0000000000000000000000000000000004f7156c69ea88a71a0af2922d1caca24055d40df058eef02bbf95d864156f62fb0e17d9fccd193840c36ad8449bb4f7000000000000000000000000000000000b8f46fd695c5d96d939d42c65c3b709d32f134710a67909dc4bb43d752521a8d4f0465d0590f30f06ce42bf5f8cac28", "Name": "matter_g2_multiexp_5", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010d48bf523f3909cf90aa58a9517ef5421f1212accd5e8a0f830aeb15a587e215ca9c340bb846b1d0474e43840b2af79000000000000000000000000000000000cc1a3976caf97b9d59f448f6d9f413eef8904f360c0cf912fe942b38d7fcc637a17038973a133608ae769d3e389b18a00000000000000000000000000000000069a6122c6f0ec68834b7617c755a7eb33a80a25acf95859da5ff03316447182f122d20d993b04e79b6fe859b7adf5a8000000000000000000000000000000000058c6f8c297524319bae6722e0a957d1ba0f75ee3a8aaf06148641c67925d15780e419a38ed7e07410e82769da74f2d070e7e2ae2751a1f71962726a31f77553c2da38f4fecda435b6e5459d5e833b400000000000000000000000000000000156ca5e80be8c8c03a5506ce9abd22a9d4958c372678c0caf6f1329898507dfcb1f06a9464cf080bc6881fa5b7df1ebe00000000000000000000000000000000088174d486b4086b931010da298a399e15b60a113e08f571e096d3a4e94b57b3a684711318796eeca9319119b201abb30000000000000000000000000000000000b96ff68505c088cc03a1c2dc363b05bc8544728a12b29569bed137780523123eb17e68f4632383c252d81bca0c5ca9000000000000000000000000000000000486fc6e5224c5fad56234c41856e60bee4a6c1046f673bf7d5c1bbb603b141fc91074da5f9d3d41b796a2ebcebd9e74d16aa883a20307f5436354bab32b4633e83178f33626af3edb14f82724b8e12500000000000000000000000000000000121fe97c62e068988ebff21d8129d52aa903afdbb62862c7fd99564d9ad72182ab1f3a1100223ae486cd76f6938e123f000000000000000000000000000000000968ddedb04f52140160061828b5f88dfd09aaf37df625ee6f66b9500d6608df31c7edf86296eccf8f9918b051a5e4df000000000000000000000000000000000b7491cb8f6252e3861d7160feb0afdd736d27886863ec0909a7cc711a9b71aace18b17a00a2999dd57ca1a74f148516000000000000000000000000000000000fdb280093ef45b12b694ca3390a865ee18e4c04b231e2c98cc28706d4cefaf4e654582ee03f34ecf1dfa9674489d553041390a2209b80f7c64d14965cc2f515d5fbdf37953f75c4a0203bf0d9fb674b0000000000000000000000000000000010d001a09cf5dc3276482185f26ef3f75d28cd6d2667eb08a7fe06c03b99f3b6c4d82390739b6867a314291cc642a8b2000000000000000000000000000000000587846a460b1f37c2e7f491f9a097b4e86e1943d9cd0999313f65627b3907f09b5d5ac1be376a313a959dd136f7e9b3000000000000000000000000000000000af439695556e86b102926d3b40e3e54cc84464e120de3b4e3c5541a6a5bca44151fb0594009663764c1824518b13f020000000000000000000000000000000003bfd9418c1e57269e222152d321b83ae090f216cb422956dd1fcc464f68526cb4a05cdaefc7bbe6e81d4ffe27d64db47cf23dee8d95d94046678f3bdb4b0ea3d4e3a1a2f07f582e2a98ad6eb7562cbf00000000000000000000000000000000196f78b64fcc342ba4f4edf34a3080ec950532a5de21a875dd061f09351def5ba3b85745a561e38117a14c20d33a14610000000000000000000000000000000003929c2bc55f323d57dc3529bcf6644e61c941b72b424d69969c1cde7a804d157045bbf6d5b79a3e6686509e11ecdac0000000000000000000000000000000000f6b659818510cde463c52cf00bd99da045c80af4d5cd0e55f9bdd81f34169fe869c519f37a98ff20c56db554469087600000000000000000000000000000000129709e97757724e765f6600c2b1928286efab55ec8d16876a2a3210bf9d31cc5425265d0576a2d5469cbd9a6c8c27c012adc8edb64db5bf0ed6724f3b54140ed6c81ca65ef9d1b38c8bca6a62bfd3c60000000000000000000000000000000009f5f167c9b61a0ef76415fcceff04f3fa57071c2d79f443ef8a7e6049cb1352f650ebd8f358904bb432d42772c29afd000000000000000000000000000000001524a875d73e03c53b92465bafca582479110611bac6a98fc7d76966e9781308a10cb202289c0776cf5c36515733ccf900000000000000000000000000000000002b1acace94a6fe196b217a9aff413fe0bcb55122ce9e344942843e5afba0d5f2cd0bba14c9c8cb9dd1c3e9024918fc0000000000000000000000000000000018e4f85c7663e596182603862adb559635fdf16ba35fbce7278680ea289f871bcf6755d85654b2a37ae77a37e77ba06ed1535bfcd68e8136808edf89967fbbf76b7f58d1a8ac95ebd4944b9e440f20b20000000000000000000000000000000018ee4b4855f866781f38a618c2fe4214c63034620ea5b72361079b0a5c2b2d6fb9ea73fa202db3a2678cf07219cde81100000000000000000000000000000000180870513afef93870ca64e2363fa1aa43a599db97f3b807ada1c25ae331c80b8ead5cd69b6f5a65a083606591de90ff0000000000000000000000000000000010afd546703baa35a9eabaeb45d301bd5be115557bbb4ff2a0e493668ee790e947eeafcaa923f62ca00b8e635994e39b000000000000000000000000000000001089996b218aacde4ccfca4d2f66d79fe161d962baaf2d6696e1a76ea40af4ae7195e8cf9f6417ffd054f20b65ddfb104c576996d90abde581afb58903cde4b9443eeb65e21b0d68c578e04c8f28f3d30000000000000000000000000000000011757ad74a3fb341c8eb6862978ab3fb5e8cfc8fdbda7d82756532a890d61919cce931872ff339843805e00d8c62ec4200000000000000000000000000000000060783a06e93e82cb08e5dc1aa31202ba11676511300e186ae8e45248b7fdec3b7d5b6849f8b79b8f78ad84f36218544000000000000000000000000000000000ecfd8ab18066fe3408fd20f2a4478156e9a19a09b58da76486c9f6a013d861960b6b99bf49cbecfa8c9d01d5615c1bc000000000000000000000000000000000b45709845d35d7b560745375df79fb95df15e85b96cc1b98cc832c74621339c609018d153bff93f2f5493a52b7326073c558cc615b1c61c9a42b8b0ab4668ffcfc9e95bbe958e72e7a5500058e6b0bd0000000000000000000000000000000003f9de90222619216852356052e9819d7c6e8ff91e0c6f1d8cec832770ed9001db4569fbf579ab16964d76ae7d1b89e900000000000000000000000000000000010b7cf8f0d283cc22942ed73c599115763dcfc1ddc98d87979fc3dce2f33ca3531cc2909d94f86736dda2a4e94a4f0c000000000000000000000000000000000b0aa4d947644cbc7df8d1927cdec66a68862e5a806e25554f27cc1a3701f429fc7097497ad0419e21cc403b472c8ea900000000000000000000000000000000146270ecb66e1763437b824f2ae122f72f20eb93fb30474691a0a192ceb932b1dee111fa44954075335ab360d31ee68d61301b4957a468e2817db5914ff102bc96460a2c5c15e78bd42884b1223fa71a000000000000000000000000000000000c977cb8de4b6e2e33d916f74eb4e42f089d22b54b59fac9aab0e4cafc8aa2b0f8c55d7251662b3499ea140e322dbbff00000000000000000000000000000000106944a9c2d2ecd08e109de29095f3460128bb751051a1f079acb58b6a60b0bb5f52e63d47b688f4a382a77c3b039eb5000000000000000000000000000000000d2f8be1c78995d54fbccab61f816b6ec52dd19aee6aeedc0e4bde2898b2d07c2925da0440a38c4c965a823fff10389f00000000000000000000000000000000183b5d15b243cc5d9584842ab1a0a1e01ad87268728d72aa8c0d7ec6e7069063a11fdd1525d2b30b35e4568da7c44c5495cd2686d24a5bdda0bcb118a2c0eb5ccfe411ec452e1beb3adbda7e93ea367c000000000000000000000000000000000f65ad4c21fddadcc49a8f7bc281d2b7901707f51a67122179fe97da46ea5e1bc6e70d68eb4eb6776307510a67e972620000000000000000000000000000000009003dc68cb0cdec4a502436718f066348f1957ae65ecca8d32c5fd776215cb9a098c0ffe56c92d79dd68d251f49f13e00000000000000000000000000000000038ecf0bb98ff2e84b388c58059ba0de0cff3d5881ecf01d668495ce81b76b00323c665ba88309af5552b7950cc8c08f000000000000000000000000000000001924aa0f460659f552458fb469467a2925fcb2420d4fa6249310456853be3d08bd5c37a3f0a9d6e94e434391d20cccedfb81d555d1e2df92cdb487a888fbedad976dce54b5c46a39893edeac21a12d6e00000000000000000000000000000000189c3ee691387fbbcffdb147c880218c3e5c0bf78c44461ac1bd3ecd5d4b85225e46cdb068049607fedfcca14882e289000000000000000000000000000000000260efc08531083db2839d1413c90968e87d79bc1a2c730f0020e40beb92e84b73ef43e80f7c61e1a30c0cee11b3cb370000000000000000000000000000000005c852ca0aae2c575c65ef18b624f50a32c007d299f24a3ec6cacbcef1d6e3bdba9650fd7d639bdc60a3e107ee9c013c000000000000000000000000000000000321c01a9de69d6b89db4ed88dd48261ee28facc5e26511fb2833fa45edfb58051c8c3ce9501e8b4c3cab9c456705889bfeed84bd95fb955d1b1045c059ffd051324dc8966e504164e54f76f02eb1b8600000000000000000000000000000000183d50635b22e4d620130e0d4008e3bfffae5dadd7e34f4496899ca54eb4d9e3e95c54ae1d9664609c58d02ee5eff65500000000000000000000000000000000029e3b4496a379464302b1476a4549db371f5d6721704b1d6bd35e2344d7679f8a61a0c3b12f287fd86fd247f9652cea0000000000000000000000000000000012c6a3793fd23e955708f5aeb4d6efb670d25a38a67813ecc72f899cd5f926ab7ef198bf6d591328383aaf54f756c66b000000000000000000000000000000001914d3e4b6ea96bb91333468fe8f3bb74636e9a4f2ed198e9ff01b49ba02791d5bd63224f6a38538aceb777168bef688e3b308b95f6d496e6d5b910b6aabef8d9f868471653e8254ab4d49d593180d250000000000000000000000000000000007457f2601621a99050d8993244f026b9a62ff7055b325e6f1edd1cf54065785f003cf7c8a4bb1f7bdf14e220e490ada000000000000000000000000000000000928eb76b428dde37546a27f3d77605c293738f448fbdd6d618747b0de04004aa4419cc5601600419c6e1d470c15982e0000000000000000000000000000000008074e9f5473492dd2e536f7b305be4e5c564cfc9218934d03dde6dc5118064ebaa5c26fdd1123a9c31336c37c1234900000000000000000000000000000000002bba1f9b7da6abd2b322c8f11c749b2a284552eab25a77d21b38b028da477a3ffec1901a015e81fe2893576a41e4c0bd4ea92e0e776be341c8444d4040ec121a2847256c5c9bc918adb28618548b0480000000000000000000000000000000003760958eac45397eca1a1d951a80265a728dc3c584f7dae111e7ce04248885321b69b334b00cdb0334a362676c2d32f000000000000000000000000000000001031e4a63129ec40da5fe9dacfe148a67662eaa00e1fd5c30336462371c167348a10e50f4dc18469a1a6b76485f77e12000000000000000000000000000000001412dbf993c557323426b486f18a91d16b4baa2c497b30fb332a710ac901c96d46a577d04ea87afb08258aa6d204a1c9000000000000000000000000000000000da015ca09ac0c3245c090f39852218f46fea62198fba35ebc4a7f14887943c3bd1bbbfbfa300611e45f419b33988e404c07f5188e4c6270a7e9e2f551683c4f9dc943ffc7ec279d15816a7f4910b8d30000000000000000000000000000000015c9121f72e2425cc8aa4c878907628dfe75a903b7f756b9e13728372cba598859d20a92a8297d95e1fbe25fd1cd968300000000000000000000000000000000025a3faebfa53918efa733949f914be08b791794bd4963f0c3fd78df48b14ad214374b08299327575c0731b54eafed76000000000000000000000000000000000771782ecd9980da521618af2f9eb55d91d67b20ba615c7b3cb1a48d483ca405fe99a1cdd17e4dc7aeffce586987d41900000000000000000000000000000000136000da90a76d538f336608ce877be943025b4c8bf15880ea9c1c001c20c954292d362dac9783b7bf66b8d51ddaf0f2a819a0438efd7ec0c1e3eea07ba201af6a832fecec818adbb781ad0c23e81dae", "Expected": "0000000000000000000000000000000014cb24001bd933b1d5866cc3de9f4b8479fe23e4fc26dd210f9d06e7a05449b9f5ac4e2f48fb847599f625824336bf1e00000000000000000000000000000000033fdb2e899427f1cb9757022c5b614f08c64b53583486148b7431311a6f15aea3b968913fd5f3e9b624705351074be600000000000000000000000000000000035420be9c7ae3203d0dec61ecea70e22e62f50368be870e74f9a7349453647a7f61d2a42cec6522164cca0c7081d4de000000000000000000000000000000000fea43388e9f6e31d419c7f9fbb9839b4cec04163a7b401d8f7de73a4560fbfef4e272f1db9c9d5b37693378f139452a", "Name": "matter_g2_multiexp_6", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000039dc2b60389f6c893c44072f4db23e7df4c2f299d6b70b70784d9370d9ff8e5413872c227074d429db999d30dc9499a000000000000000000000000000000001702273db356abe7a3f91a9fe4bf56584f13de4069a91daa6c0b552089bef60da98d32c615aa5610842dd8a507f9477c00000000000000000000000000000000095285e8c508ff12da79e16e0391dadbe9a823c586a049e729596864c3cae117305c05f009f9e8ac032abaec8a63f8de00000000000000000000000000000000078fc70e926decf7aa4c2e4b395e88f367757dc47a4cedcd5e632c456a4c160393837196af474948ce6ad53f830ce8aeb15af019ea2de662bf187930caea19d0aa07a74b49fa7d1819a539e06e4c69ff000000000000000000000000000000000cc3cb5e7b033cff3e5cb01ba29ce8e9f4a93e836ddea7d417f7b07ba8aa71a0efae2e1d7a8ec70bdff12d84d229245200000000000000000000000000000000019ce3c830505324b9bc7cda1fbb328150d71310f06a8424dba861d67a7bc0428beaaf697646d22cae9e00477cc8066f000000000000000000000000000000000f6ff67efefa5636b104a0351c90fd3e89a32b8a9beb0d123d3d6ae42eb5e8bbc19c7a972e27762daf852259c65fce6f0000000000000000000000000000000018d98c43fe5b13b701749f4a5dc25f0e713d241d573639fcc73429226bb131d448283338a909670066045c65789bf9e7064a6af51c1d499c4c28556ad1255af7467bc750bf2db2842d626647bdb3346100000000000000000000000000000000003cf82958d68429503265dcc7d88a3763cca32baefe3c8d32564cf30e8e6b8255d4a9f6a76bce1da473b50287deda74000000000000000000000000000000000bfa9cde6c06b2a2ff8f877ca90b3827d0aa0408c4ccbed23ad461433dad71017d4dd387f49c5febdeafa17d06ba784e000000000000000000000000000000001770fe70513533d91c83449ea52964cd8b449aa81f71e71995db5b19ceddef18e2919439c80e10086e670be669696e4f00000000000000000000000000000000194c20491c9d5ed827cd9d370b9bbec55e4a7b1c34ddd1d80201e7019d9487a747b4fa57b480dbdd09af73aa4f5fa0e9a3daea5a083af43711fcb09282b66882ae5b5b8e1714e9186f33ac0dfe48b7ca000000000000000000000000000000000a79d9e0ff43249ff54526c5e1cd55a9bce93adf272508871326c933d526602dc9dae5b6f129a0f1c38139ed1c39be5c000000000000000000000000000000001458b554e0387c1ddb9dee9f4e9fba9c81c15807f496442f4b7210267912b9439a19f95dc80a1e09a0e5cfe750f43c8800000000000000000000000000000000012c06b19ed4e8d5d1b9fed56bc5bdaa3bf0112db997e33aa14899d53e1bddd6aa91dce7e9d25473b66b8578d398981f0000000000000000000000000000000015369b2228e728894f2fd7c2d8c41ac3550da4f297de445cc0f0ef7134c478f526987643cb5408a0bbb79f5f983c085ebd682acd154f6e16a583ca4968d28471653375ef79df078b17b2cd9634258dc10000000000000000000000000000000016649a8231407074af5ffa93f9db5a2ddce8785be8ee77149602d6afa24ab30b26d2f74bdb5f7464333924a817e242e50000000000000000000000000000000001b990f5ed0b23e113042ff004236646c6eacacd99d1d73fe0c3d9351ce8d622327e827b2c0556802c5657f8f06062a4000000000000000000000000000000000f002a2a5ca90285f9b2fd429721c2daffcae5fe48c571ebacaf475606f96cc8350ce88a850ed75e5aae59d445249bf00000000000000000000000000000000015157fe1a767dabc185a8dc8fea3cb208fd995ecd9acab762638faa987f8367ff7c1a60b657be6e9461acc9df16381e5562223d3fae1d303a01ee4642fb4cc70f21937ba7fe377260fe82262a8455a7700000000000000000000000000000000073884ffbe6deff99cb4b0ae1c0e91e2f4a8c2c7296339b1d7e117d5d47ab055743d643155680740befb379a1dcab666000000000000000000000000000000001995bdc23991dd4cbd973e915a16691fb860490bb54011384c553dd14afc37fe673d13950c1e7eaa29c324fd9304624c0000000000000000000000000000000012197a19a498cd94ecbb3a409337b04e76e1a52715c40203add20eb80f7eac66f3386242d51bea34ea016d778248836f00000000000000000000000000000000101069ff0af2ac4dc7a5bf7bf7b56d82a310d67cebc41a9abf1e1af489e1acef3e726fe9571b4382777573712663e26caf1d0fdab6185e1c3f9f621ddc169ba92584db0b40b6ace7ed563eee0090629f000000000000000000000000000000000849b88e7ff52d8136a120f924b20b45ea9ae654a0fa037b62f3c275f0661091038a4c1d6ce7d50512e628b6b397c9f6000000000000000000000000000000000e50e82e9b368f2e316d41febab6b0f626d6588b7217b4e28eedbdf50a4abc9039be9e66c97790d12cdedc90873993e2000000000000000000000000000000000bc5d2bdf06fda1e1d1f5c5eaa7988dfdd790bf4d952f5d3a532bb59edf619dafcbc29274fd3661a35a3f15933b1849300000000000000000000000000000000162e5ce45499e620d0977fa26a291a8e75943c4b5a2a80be395ac9b89767ea5a06606d6b75ee4c8a286d2ea5a197baa5e910487c91f3839d5961f02a67f3b357206e406ba207dde969498e40d4a26e880000000000000000000000000000000005c11afc970544b96fc1a4cbb27259e19b5fd588d1be1c8f19eb4f111882292a463c951521388cb8cb743e5a4a1b57cb00000000000000000000000000000000013dc433dadc122376b75fedc923386a7ba5a363678fcf9edf165a50e160dadcc151b6f402648193d9ef960f5e401030000000000000000000000000000000001893af155aca343bc29989ec2b5a583d020a7558c7663accf6f3e40d0a8eb98ac548e933eb8e2d5fe3550927acc2ed4900000000000000000000000000000000043a79bcbaf07bffe6c6890d95c7e74d127446bdea51a0ba3adb164ea39684bb3ac552020ca28b86e34692c9b36f4384396d32c2c9ef685120995d2244756bd45591618597306193422f3b5df4b075d2000000000000000000000000000000000e6946ddc8a9d73e5b140af80cc91b31b9a226a945a9574f0629566f7ee7650730c5ed758cc30442770ed1602b84175c000000000000000000000000000000000da0abb9f5bfcad73b3f24903e9ef887c660447332e5457e4a5764f6628c04d6fe903679b8dc8bb3aaacde410812286a000000000000000000000000000000000656016c01d3405dce9f7d40e47976bc8a84abc370e7e42849dd0bd93ef1da0bc88e428efea43dfea37dd834cf246d69000000000000000000000000000000001939b2c92c8299d7ec1dbeb9f291c5e1c9481e10df10e6ba18ae695a780aec5a185ed4c7e82dc2bb5af87a74552c2ea32087e21d775fbc2c20dda715e46c9c4970394e40e991c78ecc13a2a5d0b0f30f0000000000000000000000000000000000942901572722e5005a9ef5f948c8cd6f557be8d114d2810d3cca29933a94de3c7658e7e28675c2a49f138d9c98c524000000000000000000000000000000001908e8b815e95ec07a90861ce53f545f0cd44aacc47df40c24d6cbc61e7b28fb91cfb1cb3c67b6c5b38c34fcb2ca35710000000000000000000000000000000017bad3616d8e510e325d9166790239c8c817c68ba7fb937fd5fb70a4219265edf6625b52ff26f0a34c0bf481c482b2c600000000000000000000000000000000023ff8a50a9c0e9ee829ec81972386ea012df5e8476d8c342df6b98fa1faa1382ae921c2f1018a918868672450355c44f44043002a94560d725da2ac44f30cc5f14f52dff5671c6689efebd803b1df7a0000000000000000000000000000000014675ab3efd44bffae321791e6fb35a24b9c07405d9985c685795df2db183ee9dadf18c76cf4095e1e0695dc2c08c4c4000000000000000000000000000000000835f2cf09647061ced2bdf4211bdaea408148100f864f47ff76c0c63a43e44e8ddd9e01709b6ad129bd574d71a1a63c000000000000000000000000000000001017eaeaa6eba76923ff27e5848e5f3b09e7b2b9d55b2cb7068f39defa8628d1c8cedcbb0e1cb5810febc4ccea712b7100000000000000000000000000000000054c873449c738383e9fc2f0f74a6334904171fdb704f5ac35a483ba19a8f661187d36fb35014af9ecf88225466c86e48624c83d846ad2e53f3f8ff5ffd3fca8723e6cd431e89ca29a4d662e82004b60000000000000000000000000000000000439ae88636244d5e09607960fb033e4217343899d044b21e61335425b94a5067c941e83e5a77f4b0690e1de037325090000000000000000000000000000000003a67653818cece3ff0390d097f1bfbea9ba954a85710f5c24d1de1893f25f2863991fb9f330e60cad725708e70384b4000000000000000000000000000000000243394c3459a3af236189ec6155418c1916b854a20b980ca1044b48e23b725dab7c60a48e89f642423c805c117e64870000000000000000000000000000000004c8c9fd9f278dfe9f5e24e0f5b42699bb9751b56520827afc2fae8393c690a63f10e92f77c4a10b0c161408da9bf505b2b2a8a42887ca6dff5b5364d88962068496bee79cbe74de0e8a06209feb38320000000000000000000000000000000011ba67024503301ec72bfad101a48708e3521c8a23c6bf2994078690041cf7eb75675cf5f20c8e82d11145e31751a2300000000000000000000000000000000008ace953ed2eaef19595cc7c9fb1806d26cbf1e888075e3985b28f8d93b9c0b4c820c8e8b50fd4e0b23923d428da3efa00000000000000000000000000000000054ee6f7247296e0748d0b52148a97b930e69991a242767d80bd6434d42b0865a64d3ce60953fd2631aef873d8b2acf3000000000000000000000000000000000077748b724301a8bc48efd1cd66086e727e9872e4efdaf55ba90ad1bed7e229a9cfb79013333b50efb46090ac0bdab488ecb5976f63a38d7f3d8c8ec441b705563c5e3d899870ab5d2ff84467fffefb0000000000000000000000000000000005008a1d62dad51132ad38a226e8abd7421392414acda61111c728713a2ece284b04d75c2bc58d355bb1d3061415010200000000000000000000000000000000189725b7fc48b8a648237021e9a2334247f1cf18ca50008b813978db01667ba08f00b23b3aa0e015f549ff2d5e5c535f0000000000000000000000000000000010483cf2310f64cf0baf556cb2f2828a1c15922547bec03cdb182a316aa86b5473f03373cf7e59a9a78f73193c1caf520000000000000000000000000000000007f635394301441bdc57dd1f4f97656f4218ebb139c13a17e12839091e2e81327f3353c56880c608de824a07a17b2bdd951f4960d6614b098249eb9420077ea5ad11e38d1694f4df33719d1127338f44000000000000000000000000000000000daf4090a229a1ce946064cda1c4b19c88100c8785c69f2eeec3aed12065787ab0abd797ceed07617d55a9c70ac3020c0000000000000000000000000000000011d77fc28355f61037cae3a8342bdf8d11e963495ba3b5d67055f790b1fd632b23565cad77a3d9968d364e4e2a553c9d000000000000000000000000000000001038d7e8fedea873c864b79d1cf8045485299a2bd4d26c5ab5c8d4a073e2c3fcb38cb230dc6ab7e8e228cabc6ed97da50000000000000000000000000000000009de9209ed14d62625ffbf770e8c528594aeddcaf1aaeedb4f3ca973e7b9f9f1a40370cc74b154f3bc641665d8e4d96b7056c7d93d8453be369831dc0575df6438db488780d518a53d19b8f5d22d506a000000000000000000000000000000000a6b0dc04591cbbb1b82a059e08b488fd66edca0f2d264c352f81cb6ec45e50f0af16917fa4727ee9888f84b6c888c60000000000000000000000000000000001369ae16bb0743f65cdfc8082dbe0d588cf8aa5406a095c3deefc27eb3ed462dda9dd4921cde6a1d878a805cd144515800000000000000000000000000000000124e08d4de6e831229005663df4e4bd5bb7af56dfb13244c50410e6d0aea420ba19208bf1a774207e0e0170ad3a9b4f60000000000000000000000000000000011b2973743034a2c362281b11a1ac1c89f59ace09f0a53afb0c2ceb061726c7aaefe274f6dc04e5d0dea2b687a00609a8aa982de1583c25307e9e2c8cf2469a0b1076c6be2fbf12caa8584f34988221a", "Expected": "00000000000000000000000000000000136ff52e440da609b6b73aa838f2eb9791221291b7b14d902458aa7aa9e37114c573edbe8cef7a98dd07275a8c3fd650000000000000000000000000000000000ba625eb47be09ac8cd1e2ec9015640f416af0e3e0e79d39ccac600ea08bdae7a2bc9144f13168a8cec03ce66b9daadb00000000000000000000000000000000095c51e81b5881b009b28006286c704ce3b002e4ca50ac8ea8e574d1e9665a5b1efdd60568d4a4a656ca6a2d1750a39900000000000000000000000000000000143c0c4b3b720fcd0b044a6f420961e2b7eb5f9f1b0d200de56ca8b02709d819f47f0a6ea7d6b49c4f30520586a45616", "Name": "matter_g2_multiexp_7", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000da4cf56fdbaa9004bf8ffa12d5cfb3f296ba5262dab079c91bdbadd6e41ee5f89912bffd5df1643146bce1f0e021b3d00000000000000000000000000000000150227356e48f29443a0ab4536e7a2f86f9e63840e23bbf1b091a59f52c27978bd6a15b29b105132298de45e51134da50000000000000000000000000000000017f5271c97d84f55f8b7ee0d73267bb69cdc7565c470a4b531f9dcd29596eaedf46e61bd79e71e5ade7d000c1c1d81bc000000000000000000000000000000001322812590e6c22bd90511ed72553c1cdb0ba83487b00e3adcb01a9abb438f365ca23fae9ee4a953544253696ddb0bf1a18ca15f0d931619363f5ee56bd7657b2298f228cae8d185c9d062910193e9c40000000000000000000000000000000007c59f94693320b01b56b36f8d1c39fc9e01bad289577738e648771d8940778276cdbfd59f07926e516fcebb70592de0000000000000000000000000000000000aa71d6dcb0b225526eb92b79891ef920634a007b87986fc0f776f85195ad7ec2d84b9bc684add947df8ff42c33b034d000000000000000000000000000000001362cbd6cca3d5c1ec68928be38aca5de1f224e7cd4f5c3ab1c2cd589bbd7c31022d4adc51720bedf2580d2acfa0f06400000000000000000000000000000000162bf0f38e19ddca9aaa370f988be9b35461d2a0f46143e8663f1fa549d0afa1596f029cf2f800b027b90d1eda6ae8a2b54274927eb29fea0cdc464271c918826d5249b2180a52a5020480d1020c9795000000000000000000000000000000000eb12a92fe65f79c646ba508fa615d09d86e582c3337ae16f66cd3bd74a9caa9dc17defb4b4e67ad62f0665c9ad1b6cf00000000000000000000000000000000058b6ce2582c46c0fc108a37e1d2713ff21ec8b1d8c18da0e69f0dfec7f2f327043e174e16d9d64f9ed4d3818a302bea00000000000000000000000000000000068192bd2ebc0a23092bb98c23f5792e179913c4ff1f23eb27296a77e83729803764b8db3b7ba4fe154ca467475eefb2000000000000000000000000000000000482b16e876aa90da6da35e0d7495a04d5b0a1d084c61821f23e1ad63cb1e66ef5975a3cef9ecdf2e696e9d9b50bf9b65849bffc842c21277be88dfae0040c54b072ff526731947cbec0cfe963f2d0dd000000000000000000000000000000000b712fffce3e63362bcc246da566a14139a3d12807ba83ab3520b0aa3aa20cecd5718e2b7e00f24e6fa705315bc2175800000000000000000000000000000000057a66fb12f27e4a5268e56805fe2b61b5ef019b31fcdd861e2b0beecdffe1a3a69e8d193815f97740324aaa40ce34a8000000000000000000000000000000001080a9e1133f37288dbc3835e45b6611fe84ec4790e23e5ff84a2f72bfa2837f55cae9177e5a3a918adde777b7298a9200000000000000000000000000000000142dcaefd73d7f6342e87fff8c6cd161389b6049fa077f35076eadd2b4aa66f3a1819bf8272cac1c28cc02bb6440dc42aeff769da1b62fde321d46c66f8ee7f2129446d805ab7f7bd586268de8f57c4300000000000000000000000000000000034c0f8249d6aefe4cdbf84d151ea9f84add42ade087048bbbf9de4a412cc805dd9b608fdcfa34fa224066b5f06d18630000000000000000000000000000000009e235ce5eb936bae00d3fecead8859e6d909da3d57bbe0a8aefaa5efdc94969a1cb2e12642c0099bca4e7bbf9833469000000000000000000000000000000000b6fbab498c2706f0efdb4effaf79218cf4b652a5205eabeb84f05a060da8cd18c8154a3d37594485ba50a8228f27f6800000000000000000000000000000000130ab70e17dc73f773df99cbe3f978bcd3fcb92a8226a1450239d209cc6969e2cecdc0bf3cbbe9a9c1de072bffbccaa952c9e56cfe957b924c9c0294e1c1f12474331c662c8e86288c97e6a8b8b5b20200000000000000000000000000000000031a2c10e95b841ecfcbddee4b458385e5650dec9a2d1e50216d9fc261a9829eb5fe894e47f171c8fd2f4d5d89771341000000000000000000000000000000001378471c7f770672ee82b70fc87af5ccacdf8995df9ce48aa9fc2f638105a2fdfa48b615970665ae4869f1e2dc7988e8000000000000000000000000000000001969517c503df5560628555a8780138e4c340d9d49d8fac4a8a11c894d283d49fd06aa81e9f0db8f015d9372762dad75000000000000000000000000000000000f5c2d9b7fc33167a6e9b5a5fb8c5d16ca009282edc05cbc8a048b835b16ba33515c226174d6ce5f9836581611ab403bdecec569d223c724d162250ed1d074ed9f4080aaae3f44b77df05292be48ebd90000000000000000000000000000000000a6a32f2006c4b7804e99011d934ac91b1b3fa6f5d02c574cecd6570bde1e998f135449dfc148aaa8fb8757d0a7299b00000000000000000000000000000000198beb461b59f57b85d858b730fcf853d967a1592e5e5787fd81c6a3d9d9b40c1cd7912cae21a47aaf78df5540604cb4000000000000000000000000000000000955701e84721866683b4eaba82c2df8a89bc906fb0a3cde565d314cd7278b0c56936205cc8ada10b03e69b93c48067b0000000000000000000000000000000004740253653a0d6cb15c76e145dc0b1f811bdc964f7d595b6027bb012b42409deaa8da83e6ddc3f0f7b4b237eb62b537915ac9453b831c41becd3c1f412cdf5379e9cd5c80bc6df92ecfc5005356d2aa000000000000000000000000000000000f88e1e30674934bf1062ac619f1834f35f804a958e82121255f8087ae08f10525e740ee53d7514e0ee7c49e324513c700000000000000000000000000000000019d554645696b7beae881ef62297283c5b68ad3fa9a84a47c29cb53449d33d6ee7a5a3cb83b6acb75cd41ac3f52fec40000000000000000000000000000000004b32776966e52e8a72c88a689d6c56833296d384e2059d8f615ccd3616972074987f839b4689d5610a88addcd836d930000000000000000000000000000000000fd4d21b00d81ec993d2350f1fe360576fa983754a7159c2e81024a00931d84e419e8b5231ba8cf8f05a0ee6ccea7e558fa60bc7cff4edde18301af2348faa69ed4f31d437decb7d4fe51142d179e6000000000000000000000000000000000177830cf34186191fa295b7f279bc819d8a53452e2114dbfe709971584ec7a2da7453aae3e64f4b14c261e22314027c3000000000000000000000000000000000ebf2aac35fe070403a4b7a5c2f102c67300bfd68af7863b45185b37ade1bc53d46772062189f348647e74c77caca4a600000000000000000000000000000000128dc7846b2dc5c453ba5fe4675d0c22f4d7089624ede05b0910c34ae623d4671979fd73455b35b61a57c51fe2895adf0000000000000000000000000000000008e33a3c3735be035b550613c712b220595a83c1953b24b3efd38c5913fc23df823e00ae5a1c2ea8a8eebbb93c5c721dc29be0b271d4e22d39e9e06db9e50845515880f30c5bfac80bca39a2d8d61ea0000000000000000000000000000000000a060a957a8da4384e3436110657110653685bb621c32810b6516c690a00c13e37f70185958beb0ed886aae5cdd611a7000000000000000000000000000000000b5afbc85e274049985eac230b2aede7b2df1485c9539a4a4eb6aea406d0f6515ad8bbece7155fb0dfb2123919fb8af9000000000000000000000000000000000afa722987390440a33d5103445dcef42cc4a3c461daa076d56fd38e0b220016ed2bb8e99b9a8da4af96b7da64ba90950000000000000000000000000000000013ea6b8d327191e53bc71fe43fda305a4a0584cad04048afc0480f179955cb27f2ac8791d847036470ffeb47aae36877dc8c2e971a3a4b9909dcc5cc6a0de50286294ee15f441521e0f1d2c3ad3a76e900000000000000000000000000000000032b490f795ac3242b8c7185c9e19f0440ecee3a65263dd4e4c9a431571deb7339bc6e2d73ec43750f6f027bcfd674c400000000000000000000000000000000076ab4ab3e8ed6ea3b882fde5cacb3bd094567288699e11f368c3f60f4283c5bcee7b4c5debeac541ead983f5936d9f80000000000000000000000000000000012aa2060e421f4f4249e83ca0ae1752dfa2b7ca958821841a18f05071a35fb9c1448619bd96f8a7adb2202d3ffda8eb30000000000000000000000000000000008b24f29ee7571f31ff86574e654a5d849acbe92653ae1a1d2baf4c9ca6e67da4937bfda51a70931a6e60d90162efb4f21c9ae0132a4886820115e71e280d33378a04344f635c769fffe91e89fa7ea47000000000000000000000000000000000c8b41e5c47babd6ea113c0ad9f45a75d1ef6bd313b768ac01e6f581ef6630ada623c1a27d4aadf543af4055de7f6b73000000000000000000000000000000000a0f73af06f8f0115bf17f7c5db0a6bdea77a8e3d8fd0b52b0d4e2c558f1331f655dc272c86d98bf166b532ec8e45285000000000000000000000000000000000499b55964186bcc6986e7744c52babf47e274e47a202abf6f816bc748baf846df2b5ced2a5f61fbb0aa2047bbaf82db000000000000000000000000000000000d6c2a9a3fa5d0524f772cca2c7e72a5f2da1a6a1b9550997e7a6cac5b6b6c37693a01d30bebe4b9c742b63bd31487a1e1067c01d5565d0f387516d9721f7f4e5253d5af8353db4a55500e20a95f3c9600000000000000000000000000000000143220e1cd08ffaa6db4795ed4aa35f3b12cce724fcad005367328972f2364f34096e32f1f1cb7a4287ab636d0030322000000000000000000000000000000000f2de47a37a55edbb75ff0bcc446611d690d7f9efdd09ca1ebb6f1d64a330bed420bcc85aed8b95316fcac3aa7d1f2230000000000000000000000000000000016afb044b8b8c64547e000f80b25576aa329a4319dcd4f1bbe15d12e6f3bbdddbb52140e6297c637311ef0c7a31cafab0000000000000000000000000000000019e6803c07fbaa075093f6a69f9dde05ba3d3f58e67389d7f096e56df49f8270008ed422b64fcdadf7cbbc8334037682a23bf766a1e1c068e6e8e4b60391583ac197ade53caf0f8a43c53d1bae9f13e500000000000000000000000000000000134125416c7908cb4454ce6aadb30df46042ef2a6b4b69b19fafcb9ebafe8b5579046725590266cfd10fa26e1b5ff3dc00000000000000000000000000000000073f4147cce24e13b9eefad7c69b457acf126bf278a58a26a7c7c6b482edea6dca9725d7e5e4138b4ec81bc2505ce2e60000000000000000000000000000000006125caac1061cd6c556f4cfc122df8e949622a46ca707b48ef088ee5623df058bada1bc0cce1399f0be1ee86225f13000000000000000000000000000000000146e398c161e29c90c8a4fc44bfd5b3dba6f9e80ead561fa3d91ca5f416e06318dddcfe5147ab5def858fb025a1562352c505d4fd8287a897e01517ddbd7d7ea9d26ae4f58fbca172e5265e2b62858b6000000000000000000000000000000000944942effc77ad02c5ddb052acf86f3a9dc4127dd032181450295464b49ac1dc0047790acb378221fbeebd4c92886820000000000000000000000000000000018e1d201b38d88665696ee6cef11fb19f7daa7f11c5a5ccc73e6b66ac7b89df8437c9f07132ec8b69e13f63424ad694c000000000000000000000000000000001463117fdcf17f28956a42677b3ff431cc17ccbde067b91ecd6fae51e1e24ba8d594ea368d041656022611ad3ed44a6e0000000000000000000000000000000009715cc5add17395b7ddbcb961269fc5d4739d799fe9554b3c9e9f59c895ca5df8ec75bda05cbef3e6a165f7987e78662908006c06ceb9188651c59d434988cb5b51a5a75772ba71875444c65ddf0f4f00000000000000000000000000000000007c07cf1ac9b8b28e3d2f1f4ce22b8ee46e99914ba20c7362c679559a1618a906c6ea65c475ebbeca4947019cb6fbec0000000000000000000000000000000008b29f72cda71e0bc2246ead57b2f758b741b9232d87be75331275a5cd63afc9aa98b0e42c1b82cc258e93c97e596a81000000000000000000000000000000001512548a4bbd537a4d5baf673fb76ea7e35b2977216e7b29a6375e1f92049d7b7d5fd5d8b4ae6191f5592b738e149a5f000000000000000000000000000000000cc9d646428135296919808c6ac10c142e769bf71bc1490196dfdd4e1fc7b84e58155bfdbe77a9e684622ffd83e97ad3e8e8724c80f3527de5f0b2b98ecdf0b8d0471e63c0763a89da8a21a70dbf8399", "Expected": "000000000000000000000000000000000ae9da7d12d0a03cca3b41ad869f762784cacb988eac7ce904ec9ff47824e058e2e211e2285f9fe2aed0b4385949b4540000000000000000000000000000000005b0c873d20f7be1410d39885ce4f79884eb6ae2b2f27510d6f6874dacf2a66c64e56b7aacac61ec88261624936e695700000000000000000000000000000000076c6076175ad748dd68fee64431e5e4ad013797de4528287e7226c3df90233799ed5c8b36848c1a2e1c02591a013d270000000000000000000000000000000001f7f6972121d38ee2d10c621a38448ed12271f7e0e9e4567fe1b5fcb469c7906196fe92c66c37f8c5abc91160fea8ae", "Name": "matter_g2_multiexp_8", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000139cbf360b10e59c20dd4155af2023d5dfe0681c62351dd541cbed41b6a328aa44b862d1985b132a4d4ca61c95b61ebf0000000000000000000000000000000004af6b5a0f7a02d5c93304be0d31959bb4b1a7a5838dc3f9cf50180c4eaf3d32e68c006263d75f9735c8f0b5f811d3cb000000000000000000000000000000001644937e5ff3b8d2005a2f3b0984917837d44412362a121be481526173a4c61e20d61076aa10b4072b79743c5f7f4c4f0000000000000000000000000000000009bd399b55a59550dd876f35e54a5803058228bd6ab6c9a66e438cae473c63816c96bdf378ad426a236b58b90e737831e14282bc687a00264b4e4678ff238d5205f6b6fcc10040d9b4393e93f76297a8000000000000000000000000000000000f343e5118d7dc3a38e9975a5f40084ee5f2305e45a8aed28ef105f76345d9f5646b4f3924b92978846b4e605b78fdf400000000000000000000000000000000017e61a2ecf9b3403b43f5a10a97cf5088b4f98e5a4513b0912ea7ecef44e6809f10dee60367cf2fe3e903dd68c2a97c00000000000000000000000000000000039f37f414338cab0e12f99b2aa1e3c02cbdee3406d1bd17c359ba899b7cdcff605f894530895aecb469f41628c3da120000000000000000000000000000000001b78bf69f1b7168d735fb4b7b135fe70db79f50e792eedea23f83cee9b48e092536c2ed146c7499cf047c5b4f0a08735307650d6cfc681508fc7b8dcb5291837582eba6588132f46ab8fba674a1f5af000000000000000000000000000000001342346f1b553e29e661c9f6c0a24d8f788db98262d6af86af55d313a37eeabed1183e367ee3d83faa3f284b260e786c000000000000000000000000000000000960c8af3f7e6587cf83baae447491e73cf41e637e1efd730e3acd9793717e57b85530584942e7a030bad3b91a76996300000000000000000000000000000000166daca4ee2cb9516b5178cefef0553115dec8157f6194d24d191cfe6340406071883c89246c0cd5f89bbd5d0f1ee15b00000000000000000000000000000000187f668086b9b6307899d301bdbfec915cf24ac0be10d6897b0677e4f1de6a241f3dfb19225644858be0941530e67d0f7d6a25511ba63f0b7ebd2189cfc4c551083ac92b144e30dd81d27e59dd86e22600000000000000000000000000000000032c3783e701bcb651aef40c91682eda03f9d90f252740612c85a5727f8bcc41a886b328d5ce787031c08ace235ff465000000000000000000000000000000000b0eca06f9fb69ebb46d0af56d3d934b333514d7f31208b4ee2fb92009e6041749028a78246a0adc324034a94503e80d0000000000000000000000000000000019eb24ed35f6c7ae53047814cab14d51ae6cf336d140a17e794d5cf18450b7fac3e6f990e12d340291459197bd353861000000000000000000000000000000001983a596485e657deaedf01614dcd5f4ec515c0050e8068ea02c9833d0b165c0f467107a50da0d8cd43bfcb59db6e710eac8e5cf13de6db37982390c8b6b0474795f479584960748b7ffed881285e2df0000000000000000000000000000000002f1c29ffdf7bf20fb8a13363393d5f1cca5dd9af82888f0102030fdda641abd5532ffaa2669c0c4159a989cef1c5bdb000000000000000000000000000000000bd548079899d49cd368bf5c246aa168fc8c777bb84a7930258502c8424a4b68e1ab20dc9ef39c307e52bcafadb0c8e100000000000000000000000000000000070c18918f037d5fa1aa005e2c80ce6a80b4b24d33ce72a2bd824f9a061af1db236f04d6041314310b31b805b8a674800000000000000000000000000000000014422b173840da655aac6ea4b7a04313d5d0675bcd565258c73039f879176e51ec0c8a9deba9c78c33179a5ba54492012c134652c27da0a0272b0783551ae44db6bf592ff299b48c50c550367d470b5b000000000000000000000000000000000a1be8e39a47dbe0bd19b8108a5bdac582e1d11ef7fe28df1f12da52924e734e1d591e8e33ec20c6d5af5bc8c1161fca000000000000000000000000000000000eaa7a7cec93b8d5eb933103b52a35b3d58214feb8e2de0bba3a0e57e7993a9df0dcf8089142f57f8e0d1d303588ce9d000000000000000000000000000000000089fbfb389ba448eb77722994178ee3cfd15a27be4ed6f4d4ab6ea1a4c10d6ee8424beb17d08190fb18ab8498d4a4fb000000000000000000000000000000000ab02df2eb474735e28c45b915299230ce159816419fe9c99a7da397b7210590705262ee14c2a244f4922c35bcb119338dca9ff432bb483ad726bd20cf96b07ab6f07170a1449f0f1b50ddc6e1a0253800000000000000000000000000000000006508fbef44d36cdc6fb37b6324810ab2a1d94e39abdf09d530df34714168105e23a7d6f7fd9caf31f263b658f16b76000000000000000000000000000000000b5bb1802813f9f8a16991d41275ae6d18532e3dcd2eae091da7256aaddd501855e775b779959fcef2822685725cd43b00000000000000000000000000000000052146ee63ae277911fe491420651a96994a30c7d1b19bab32eded008a125369baed2ec5a963bfd863a83c29bc1afb23000000000000000000000000000000000a180d79335347a8be350a92491760c6bf1fd56604d4d99a1c49bcbe50b2d04b7cdde55b4aea8ddda4bfeb8e79ab6ce4146433a0738ab1b044e059f49a8af8d85546d0e34eaa0edf2b2a6ee466c0def80000000000000000000000000000000015dcdc17a9afbf88b54af22ed2168329bc43ba50d374c0507c790f37f9669d0af167328d50d322a827d45f39724d2b2600000000000000000000000000000000169b83f2567e921a4319fc03b2a7eeefd2aed79914bf608d9e0a54aa71b9cb3e09f1cbfbadaa520c0f77f547fd407ea50000000000000000000000000000000009b7a8ff8388c85a0fe3860f26b09b81b5dc51e00a8961fdba96eb462e1334e9e28a2cdc4be49dd8b96c548c64921718000000000000000000000000000000000243782436fe7cb20a3242a3a21402a43a2c4fcbe77cc7182ee3cc04f4795c269d8a64ddd25e89ba4fc796747b608092de0399ce1ed861c0ebce1d4e811ea0a3d87e21a54ae34e6b5e1284cbb94973680000000000000000000000000000000013ce6856b6df48e4c9e3fc0be0aca5b139e1b874de6ddc148c1c23a846d61e7a531cc889bab99706668a3b69d32b9160000000000000000000000000000000000a459676071c7f3065a6dd7632edd5842db34aeda8fa0e7d7a8ea29f842ebcf2c5fdfa74ee7685caa51481c4f46952240000000000000000000000000000000010c1d9ebf7bed9195cf0bfefad6ba45f1bd19a9a7d340b7c630b9953923efe4907bd75a3da066fe3d49d656f3ed91d2800000000000000000000000000000000039189de73332d5b5a160c296a195cb9d8a736cca23a92948d513da7e4fc46e1ed9c207e86751b3cf1310d8a7284877ec2b034594fa53a0951e2116db1b063345fa42dc8c870e1146f1b00f626dbcfdf00000000000000000000000000000000129821e97c65ad3801c011792f4c099e19919d7d03bf9fcba30b3735586bb7ead7d4f9bd10bc5f0e5cf1dae82d5651ef00000000000000000000000000000000038cfbe45bbdc494988a2dc72dea6a7e36652f5e5a2ecad41b4aeceec05dc4a389e54cd3aab349adbe32e65206eb481b000000000000000000000000000000000bbab53f2be2c471d6e9cbad719a73c00b582d0983e25e1969c0be1faa56b1dfa5b7b55797b3340cf8c7eabc560fac71000000000000000000000000000000000b0db19410e552a2f7889c2204a93c5cfc71c360329e3be3171e88fc7aa1e993a5d089c28b1a8f8fc80d93ba194c63ccc1e6d9c5f8911014f0f540211af5184d96fdfd47c03bf2d7bbbb3bf1a330017b0000000000000000000000000000000019320bb8d29b7b5a7130b87a39e87e271b96656b5a2749f13208520634009c26f9829401d3e21cee5a757782c6bbf9ca0000000000000000000000000000000009b37068d72463e72f3a89b9093c1b09f01770e647b5ff7daa50e0679bb76404cf7729d5575a39f5b9b3b371893967df0000000000000000000000000000000019ff29e41db50c736e12f62d76a28f4ca4f6b0f4f61aee00cc0e9dd4e5a75c0ca965b82698f704c604bb309aa5b457f100000000000000000000000000000000062c352a554dc4bb96b459378c21ec6446e15b868221b2fb745d31dece854bc281bc22827d84ea3b0fecfe5d156712ce6df5a133d3332e1f79f41201f8cb2c8c8d4d1ab0f640c4de6bd6e34884a77aa200000000000000000000000000000000021c52e82b0012537b57fd92fc276e8de842a59355cc15d69a52effcfaa7cc43dbda0c34e1b9af44c2db8e9356b9c71e000000000000000000000000000000000371a6da5dd39092b6108f631a0f4c4401464a109ea1e5d14e262c8a9577e1421d41734d2c3ed73645cc13ef3988e9e90000000000000000000000000000000004054159263ee60f6b1882ad7c376c738c7ed87e6b34dfb4be2fd7aa29ede414c2c6c3ff098c53f22a1c1cd836a6b0600000000000000000000000000000000012d7af6b57c688e1ce90e9f2796b0e525e775fcb6be65f5d2fbe3d1ce1e5d948dcb098c98d495a6e3dd813527b4635258e7219a9d431c597fe9700d43da8b545072f5a27a9f1af99053ac0494087dca1000000000000000000000000000000000e53128fa5392dbae9e40ab1ff0149d5b577d9d30dcb85eb5e4fcdc17c7daf2ff1d6fafd4a1aba88d2e7aeb45a01afc60000000000000000000000000000000012972781f214511e9b78d276767b1b64bfe5b43215c7680c0063b6974f703b209b2929470dbae16f9767a7cba5311fec000000000000000000000000000000000cf6b37c5a60851d03752f68eaeaf37ac67c661f644cf507c5458cb5404d0ce903c92ef66a657b25ce07e5cf5d956929000000000000000000000000000000001835f202705c8b984a4c7a6cd219c718ab27a96671574cf7cb618235d19e9046a15212e0da6233f15f18bbe192df29c38efb8a7a5e48d5f4a011a4aa0dbab22ede62c903414d005d507ea3d77bd47a6c000000000000000000000000000000000d01c6e8e34e646911391b012680f0dd8f4b8d77c10192ac09ce57b6524f0eb8c7f83ff8f26d856e0945d7a909eb790000000000000000000000000000000000070fca42e34dacce0051f9e26c7c0dc328fe652110976df6df77af04202831dd095715af1714b60a99f2177e86a3443d000000000000000000000000000000000063ba43df0155373df59b009a8083b9f62004327b16ad455037487c5b8325e7eaf57a4d05c533e284004be6de79ad1e000000000000000000000000000000000870c2e5a7d26ba54bf0d45ddf0a4c3011152dd12a5e01a80e42bc4dcc784c7ffdb66f9d6d69ac445c1d9aa29586245147f53e2c06664e1daffd7d9b114e12d4190d5d0fa2244d61a13da915c39b8d53000000000000000000000000000000000d84ca02ffb6d3cf6eb27a143ece73d5bf006ff61569f0eab00c5a512c5b46e1fc21e8031d1a578010c9582d75e1faa8000000000000000000000000000000000a41249cf01ecd23d06f6a3bb8573186fe47e5165ec0d447df62bfc236f4c203b4feb8e2a4785648af86646cfb0c4e32000000000000000000000000000000000244fa6caa86fd27e044145557697ea89baf718746711c8dde334a2c5ae3c73d7a0e04fed6289ddfaf26e47a9d26b09e0000000000000000000000000000000017db897060c0a8e3e5d8eca9970407b46dc2c2ca0c004d50a171450852f585268bfa8a379acd01b6d4685e04c0b8c106fb109d9a0a7b62c7c452bdf0a2853c4bf65e5439fdc83aedec8c0bf73a16b55800000000000000000000000000000000071e13963e20eb1dfb671aa4a090973e4a4b7ad3578f8630db8a865847be46c796e6f9e095a9ce558b93d702f8f8572a000000000000000000000000000000000dfc4c89ceaad07e3b4c35d96e8534122ae48421cd4443de478ddf9a8867ffdab279ad745e55c87b731afa7700bbdb110000000000000000000000000000000015dd6b0c26f6821177d0cfebb7f1481a971e7601fb24ea365a0c3127a5b1042eab69446de05b61cb6ac0576752f87aa900000000000000000000000000000000156326c52bc78c82f5cb4aec5de35e3c128c5561dc80da2cb24d68a7e912b1f2dac2078508fdd4ec38769102c082f0f74b0a931b894fbe61115fcf52be51d44afdcb96c94117c75adffcd8729b0a699a", "Expected": "000000000000000000000000000000000b537dc10a6f518122665f7d78326a4728a2889325e5be7da7e25e4752c680fd786cdaadfcc426343a9844efbbce8f2300000000000000000000000000000000085ba3a04aa8cea82b95dd994f5b3bdf0dcf63f13909aca2c2d61e4275a7ea22445c953b927ebc6b0987e98b553469d40000000000000000000000000000000019cec2e9fab640cc88073bd39e46cd571324904b1950fa8f626e2725936d80daacce2487f46ad23fa8af9c6ca0367fdb0000000000000000000000000000000007039a0e11cbb8bd940eaf4a192bb94ff8c6d6c79f775fa67821b5ba411641c09dfe9fac4cf45eb5fae52d2fc4beb6bf", "Name": "matter_g2_multiexp_9", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f73a297cd6444809aa11b0756167e71986ab31b52b57d3c0aac5637129b8702ff21ec649541e79644c27f0017c8ae3f0000000000000000000000000000000016f96d6ba02aab604dd918cc799cee61cda4c0164ed9f07d4932fc4ac3eeb92b1e6b40dd7b18cd8d26056b486e57ed290000000000000000000000000000000012156f3ca3aa1e79014dfd92fbb6c785cf0ee449a8920b89ad04355e0fb7c8ea804bbad082b4edc9abd3b24ab0df2b61000000000000000000000000000000000d51b5f62a6e70816d7671bcfc52f11bdac6221a23287286af78605b99ae8bd0c722e485bd0381b958a85f61e05de68368ce22e379ddb8352d12eb597c179c7089c6388542909876c69ee377b14054e7000000000000000000000000000000000acc52d0fca02c3228cd2e5202c4eda297b8227bf4e64308226bc487e5b64738efa4c07a3738397f90251ea9a1a9da29000000000000000000000000000000000b85b853826a28777a5767d5b1966ce12fa8999ceff5d6deab5c947fd19d19de9c103bb920bad615186d132ec22187320000000000000000000000000000000006b5a83827dc7b3580579ab7976a70ee160b712580919b6f5d4e180165e50f5a1698fa7cc63846eb1f5e6df955c3eefe0000000000000000000000000000000006c2957d8adc55931900145388583e5c2d5f6bd784e022702801c38534d2c92c6df9f95d022aa6d800e1e458eb7f313061529338195b665f1b80c4b95b7c3a26a7229884be1f4be9d49e1274a9ec3f810000000000000000000000000000000014e4c5991f9f2ee262019c1344a0843756157dc85aecb15718217a2fbe23fe0843992dcd3953ebe79acd85517acece0e00000000000000000000000000000000076a18fe710aca2875bc102f21782c9649f107684a4edcb0c4538f1a2890a2ae5b46a182d5470e620375327965b6d37700000000000000000000000000000000142a0fb19b28a034d326121458628356561e50cd3a471ee78bade0733597b8b90f647f5199d4b5b1ee6be4e1870bcd310000000000000000000000000000000018f8b5933848813cc2c1a0f079b095d565e7875ba6693eaa10967d496fb47257c9c674f301349dd8f2d22f8857f9d5ca44d740a72e6c8b5632314408022093618321c8c0a8cf2fcd9ebacbe43505a01c000000000000000000000000000000000db331d2b965dbc053b01a61e671d2ee6b04b072b6494e482f48f12221f23e3b1ccebf48046d92b4be2e4283c77f51380000000000000000000000000000000016704f3e1ce14f49df400592ce29627833ed1dbb91ae5f00779eef94fe9ab313c3e7c8da940085034e1a49158043599d000000000000000000000000000000001956d492f5764c6de0b8e9a716766c762620ebd3265a95b47a8ad2c0614c337692108800e22abbe321d77a6cc17f4b880000000000000000000000000000000017149865739d6aed0f2a4c3c71c2d02f8080d9339025b03f89a37a165fe6e5a4cbd489b5fc90bb2cc432e5baab213c8424872a78e340ccb077259aae65d6c448fe6bfb64daf4e2b6ecce2cc9525e35a700000000000000000000000000000000036804da102cce975f980ed5a69e0464241b5de87238f9892c77fc2b6e5ceb00d7a37a45b5520fce5f094f8b9510f49b00000000000000000000000000000000049da8b6c974f2d680a80d2007333f15702f1517d3dc11395662ca1db945c795bf64167840c4df0fda68a69e127b2d590000000000000000000000000000000000e94cc66f1ffb2112e37cbd5b4feb7d65032c2e57260504a42816aeac85648558f6997ef12028655103a8cb9de1297d000000000000000000000000000000000abf7703ddf6995d5c29124ba9a3f890854fe0622d547a4f24d6a60b036ec9e58f7ec2deca5a71e1fce2210cf810e2f901a1d84826bf78f493417a06a800d58dba688800026638316fcf9ae534436fc00000000000000000000000000000000008d22e456c643ce680f5ea14553a9c249a43d4f92d94135dfec85bc58967ec01135507bd8ac3954b5876c5bebcc1179800000000000000000000000000000000022029d4abec7fc9ab3bfddf2f462660bef7449c4093144d9b7d6f9e84f4f1c947855ca6e09bbb3bee4db096978ae0dd0000000000000000000000000000000014beddf6a3fbcd621e2a592e1c87952ed277163ebf390896f7c668944d6e0a026d3df74b0fc877ed560527a80b981d1e000000000000000000000000000000001414af918645ce0d4d1f670333fedf286b01213408019e327d3cb9321f06fae311b598c2f78bb578e85692e6cb787a52c5a3268a8ab5a12214b266aaa4eb562aa05dd19575a7f3ba2d549a25f1900cb800000000000000000000000000000000129f1e25d96b8c879710a81b727b31d27ce9887c245bf908a3768f3606870ca6bfa70dbf5135819d36582d55f230e94c000000000000000000000000000000000e91eaa33e7cacce4e1d6d0fe905c72221b534a72cd51e1de79a25ef0c06ab454a849a241c023b0f82aa07de28e35869000000000000000000000000000000001379e390f2f0f3636312465469b532d876529d58dda8b024b6b81d242af47b5720af4360d5a3172ad80fd9fd8a14ba2d000000000000000000000000000000000775992d5a8ae0640af845fae03dd0b2197699f413f90f6130d21db0dab042324094b36acda26ed86c65821d2d8a29d9e62a7b00d2be967df04ef56121c95c8736efa95e1faa0196e1f4485da82b3c3c000000000000000000000000000000000f5420156358ddbabf31fcc94678866f899e38747e79dba8ae280704c4b199a03eb423ceed18b5cba7e7ce84583c84a0000000000000000000000000000000001127669ef3ba3785a859aa4e942e8fc3181f2703b0ece6ddbee8830d7ffbfe498794f1ca2e67c3ad39ebd33e838dbc5300000000000000000000000000000000138113386846310db8e21fb8bfe40035cd89e51736b491d5f2d3cf5672e6836c25f62eab80f25ab49d16dbb83796aa5d000000000000000000000000000000001711d74ef4995b473239a574fb8ea6edc6eb7a88793a093df4652da240d069c5bf9249b58e9b1e11f7d6619cdc28a5787a883bf845d1ed04e0664d814cf0b49cf8c3e8b8594ae5d2834c753851ed7803000000000000000000000000000000000d32ccc6598af8156f1c5b35e69e7c7f57f9fe18748510605a2a81b4ee09882bf3fb26abf50206cd57c77924ebeda8010000000000000000000000000000000009043d364e0637c60223f9a5db8c50e983746fdf4c9f7986d27f5f4f3a6df487592ea42078f14efcb3eb1b7e81d058eb000000000000000000000000000000000233495c4961e71cffc2abcde4007c0d587687aea905f3ac5758d0f8d9020197adb6f9d7b86a542b8efffb05dce997130000000000000000000000000000000015b084e773e66ab1459825b6e6dba055a96e4dc1d94ac0b640e906e0a9f12d2124a58537c458e6e1b571311b93acc26c0f474e8f4051c4e91124c14895fe9e2516b315d805b79013caf830524fce8880000000000000000000000000000000000e4b859c679a90c03ea4d4b0b3d38211f685db053aede0f7f359f712e1ae808185758546877502d57200da2c2137f37100000000000000000000000000000000173b24ca19436b51aae22838674c41c752536eada3197de6efc98303eceb3e6e8e47ee6679e61e3cb5c8c734c96c98720000000000000000000000000000000005232b8c97a4860a23999d6ed6d173d300ed50b77c7b3ceb4e8407d9d6877a6004e2f76c553bf458b7cfd8d1e6fd364e0000000000000000000000000000000018a115201e3f4eb308c16656b3ca0635e6284169cee3f28101903ce1cab0659c3d83a449918df6e58e8af2e001036b8d9b3a5790750825ab75ab7422f833c671b95c6c58619189db66a6215ce907381c000000000000000000000000000000000131232788aa3038a6b8a055a896af4f8129e3dd3397dfd90ce86b3e09a775e5b5e19f4387f4c02200a36bc2a1e09d98000000000000000000000000000000000eb8cc0455cbaae97dfd05c1246d3d5ee58c286d263184ae342f5c0ef432355a574bb9fb8ec67634f999b6d1419f2b6900000000000000000000000000000000188b8a85a6b255408f074b3cab66b95e0e1a1b5b8965034246dcc196f2bb84aca3a78907409826370bd65cd4c4d0bcf30000000000000000000000000000000009603984f6d9876e9c235621fa817efe45727fd8c4f76abb7b0796ae721701161b39ff7cab4c57850014e7f1750954ab6607a48ba3fa5c033a1ef90260ada14ee50c95e5167bf801ddbd3acb77c3b3880000000000000000000000000000000009003b42c08b5c7d3ee9f6abb96e08e6f537da25cd0cf7eb85a49067746c03566e133b54153380286ef5725db5b41058000000000000000000000000000000000f09b7b754c255e0e3b8435ade64d6960285759495659dfdb9b117806397baf8d3c87e30bee02c9e1b22fa3efcc58f300000000000000000000000000000000003582c08a8de4bbd20ebfa833517a75682618fba2702b6c71a4785f70dbdede4e86ad8e04aae1f50a6bb75842ab74aea000000000000000000000000000000000ec013f22e64a4d4fb6f964e8319feb1ddbcfb71329186545d9b9d7f97d1f6a56c8aad03d20e9c30966ca932e1f2bc67030db724eadd2f487d31dd4354b5c0321a7983aead21759807bd893217c4d40500000000000000000000000000000000025809fb06c8a31f31ca5b4a5c795bc93355c78d9a2a4c1d707e32ff2a71d94cc1bf7b709cd5d6a183cb05fb6b5f360c00000000000000000000000000000000127bd8c9ee6388905ffe59bb0fec0e42b4aa44be74e5961dc2353e474baabfea86c41c6173db413ee28681a6bfd3ccbc00000000000000000000000000000000181f40dd8581b9adb2981dbcae27c7e906138569ff41a833ed3e6ee4fb0baccf2ccbe5b28ae2ff8e08c4f534116b58c40000000000000000000000000000000005cdd822cb47f35f31e0cbc26f6c957d51c6880369af94fd84daa1f1ca95e41e240b910f031585842fd2dfb170d618aa88e71d0be8fd050f6dbb8b2fb3ae2a9e593bef7a5163255aabeb07282e8793e30000000000000000000000000000000004a06984a3916820368076ab8cad6ffffded2cf1e67ac33f539ea8fc7a79580c1969e55b2a2fe3b31de912d6606c20780000000000000000000000000000000008a1152a581b6fad2a23aa8b0b51cbe523e701193207c896d08b99a672dc047498e565a568b79f8f9188767ba95212be0000000000000000000000000000000003539e82e5b88ef660b6593fdfd9591ec23e7109642f4aea0570f1f8f8e00822d2af277632ba74910459535b35ad47120000000000000000000000000000000015d3441f621c7e6922c489e474f80ebeefbef66cc59e4350b6f803e409034b7f498be2dedc97d902590fc1e296fe983c26989184bb87a586b8752733f9ce9ea06422c6a898f0f402cbcf760a7a21c95c000000000000000000000000000000000f775e13276c2e32dfde955009422557f332fb42dd9ccc3246d2b080e3ec44d910aa734478899698a9b04f6fb1a8f922000000000000000000000000000000000460ee4df6dd0184bcdae6d53cb66967c2213fa878a829c3196664f8d594ca6d60bb2a56f93bda3b0d2e6aac0a1a222d000000000000000000000000000000000fc9bf81d4cc80ba4e4df7307f976c2ec1ea2415df3c263cc970583824cd83703aa994daaa6e5c20450da2ba90a242830000000000000000000000000000000011f08ecbda9a192b232e8330ccbccb16a26bcf4791707f2cf52c2e11a8b3993221666563a772d82f4665804275b03b613d1dd9cc44b30a4623a4d14861688cb678bbb8b2f8ae3ba140f60e64c05514b100000000000000000000000000000000027fe7ca0fdf1cab9a52e304e55350195492abecce4289b0f1c02235412bb012803e7eb59e23c665ea86dd4f74c35c440000000000000000000000000000000011301ecfc78ada92885bcba8af75da6cbcb448e0c49511f3ea306f4ab944f5bc114e72f473cdadee2d0e84021905c5300000000000000000000000000000000010eea529fd3162ad7b49638a70f6f2c26a6844251b2c2f9f8ba54cd334914e84e5a1ba9c7b4e7a8b9cff1a909db78bc8000000000000000000000000000000000b8a6235a7310d52fc8050bcc484e6ecf299099e193f91bea9db31fae71fbd14978984a9e6de10939d0fbba96314b0a55639d80f55e24e05e3d943340e324f6738a593a915a6bddb40f01bf12f73daef", "Expected": "000000000000000000000000000000000de312093622aabdc7523cd72f568060f4236c7287d61c3372bf81d9bfebfda2795c3182d508f0268d8f445f6ea0a5f3000000000000000000000000000000000b027f117583406916a8f139d47227bbea28502ed0df91cf0841345435376c944a587c3b4bd60f8ae0be7c7bad1c8199000000000000000000000000000000000e9a7b96136b26b0044b11288d35969c17146241aa529e581a8fcf000c33fcfff2dfe1e55c0fb63f6032d0b6b0cf81180000000000000000000000000000000002a442e740ee390d87ec657fc218b76adad7f6a766cbe8f34f4824ecd1587deb3706af77a95c1d5f8e79eab1dc482c45", "Name": "matter_g2_multiexp_10", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f54bcf1637d03854cc2b785e52bde25de7e45308048ed8ec0169069c2124871782bd9d26471014d039c9aa022e1a99d00000000000000000000000000000000106698139b096a5a79d43321ea64adb783011f04e5779625c9f77e5c390b46ef0d249387e978e64529bba2db8d7aef2f000000000000000000000000000000001668d5261a4ba37d79c76f44eae9ce2aa3e216c5fbf6cd2e90c6a73cebd8b59600303afce70de3e83a08c20de4609b100000000000000000000000000000000004b1b122cb55e688f8297913b84d466c6f3d99c09f4b039660238c8bcd0b7f6977851a6ea4b1deb01346db06d75180c142fe1e5b3c0245e5cfaa1ee8dd8ccc4ea8878ce2272d152fd8b24032297ac01800000000000000000000000000000000192a28dbc40d5ceee4d33b5c2778cacf8c3ed7d3227e7ea0d6fbaa7cd4a81134b63415f4f1960656b1fed15023ce3a4400000000000000000000000000000000138f296c45594a930b949756d0ae14dc9a720bb2bd9e93c7895268121a086a9d55c10135962a172c02da1eabfcb8caa20000000000000000000000000000000001605ef8182fa13a09a6b7661472296af2b0fdcfd7b051e7cf1d9e6d7c7f4ad9521d7732733399bfd5d09a088f25d215000000000000000000000000000000001928f2e5d47d7273e035114cbdeabaca724409a56056b4e95a4ca3b2222716b3a5368da3ed406d73f43e9571d1e04902253bdc5565b6ebc219a75ab74dc5ffd304c94e67160389f87111899ac07a71b70000000000000000000000000000000009b35f132a903579d82cae6a321c1ec7fb0281c3e82e9af05c3b2830ecb4a941da5b1637c1bf0fe9a39fcc9ceb0d09d8000000000000000000000000000000000eef9c0846064c866ae07b3709091b8bd48bb6b20f995b44fb49e030b5cb6d78b7f8201704b53697190a5e36e9a4541c000000000000000000000000000000000a98a5d0d5640d6399a3580036f0e5cd693a7cfaa26438a00767d5ffc0777b83c516316d9cd4597cf8601544038f4d9a000000000000000000000000000000000e59541068a62f105a0d26a5f79fa5fa8b41b2211f1fe674d84dd853663962d64a7f70e785b51ac3cc07267c73400fe6acbf64f93f6f85805517ddf0358ecfea1fd58a3666b8dd9d3773a28590fb8a13000000000000000000000000000000000157f58b1c7152a7f931bccd9a79073967ec28855a6d74fb8727f59c5e3728fbf07a5032dccb28eb8d8b24229f2dc1880000000000000000000000000000000019f41bbbb853edc1fe3ee82f901e613107dd4ba1d880284ee95a2c4cfb2220ec1408f8bff14defe59775136bc75b4a1f0000000000000000000000000000000015538789157505a0798aa36fdd171e0bb14bdac75339b35805807c18bf9175d877360748f97a8570754af0e28e89df660000000000000000000000000000000010500aaa99216aa979acd66c5b0cea2a6a973f1cd10c412e823c61cb897bce54d783a6c0acee22cf9052166a4bb5adb8d9d3f97893eb4f14f21f68110f612a444815fbf2f76b8399ba6045c8a44270df000000000000000000000000000000000439729e13e6a9b5baafdaac65783ce79a5972791610a333224e61104d15c746d7cf8350e619f0f72cb73635f6795c5f00000000000000000000000000000000092e3c976a4a5424b09e50e6513a9e1f427356ce161e742be31f0e589e9ff862460d41281f0bb2d27b1837a70a5938fc000000000000000000000000000000000e0e51e92ac3cabfd999cd72b67cfc488e150b11b18f9a31b1c2338fd4f2c58937521b5a107752c342e67666b99fc42500000000000000000000000000000000023d8884aa3f556e98e006960293230ac966ad18f3f715e6ab31a6bf0872c04e6f115fb1608cd87ffb369ff31012a11705fb554531f53b8cef8d93566df80878baa96f92bb54aec19445980b1a1f6c34000000000000000000000000000000000be33bc145611afdbadc636e9d7cb7e3a9c92c32f6944a2b7b5f44c248a0754c174e3286ad307fcdb2ea02a3578aa588000000000000000000000000000000000457de1fa8642d302065319b1d32009c64e7d941fb43d1b3cf455248664b1db516379df87aee05a651c132eab8aaccb5000000000000000000000000000000000a711f3bf1bda60ca49271e8a3143330cf924328d3ac6f7a802c15be1d7413e300f398274f338e6bfd0225cd8ba25fff000000000000000000000000000000000a786c5c7b4f1701e292aaad9b2e47bb883409aae0c44ae813ba48f401f4e2146ea0b1d85f2ce862b6ac9ad3015d4b14d79ba2c485f0aa0e35212fd7fecf970258903bd2427c4c8b97c2c425ee1190990000000000000000000000000000000007d03697e195a6b714fc9785b49e54e219694250cf5fe77553434eeced15422de3985f8c736996c1763d4b9248a7a7e00000000000000000000000000000000015841a70a168d2f356a8ad929e2d1433b782351f4833c51b50f3a1af48a85468c2ec02699550d21bd919203df73abeeb00000000000000000000000000000000170902520080c46faae2bf35de396d56921bd0279fc889f0187adbabb9ae52b849269d8097d5b3f331dd5a817f9b2ff40000000000000000000000000000000016846a000f037eaf5953b7c4b477e441ca4fa738895aa24dfb0ef01a4c8fc21a318d40a9424e151380084578ca413b3344c7017258bb979cc9bb8acbd3a3e62eac7aa152db46cd7398ef07edd031e4f60000000000000000000000000000000001a50509bfb12040c0271b231c566d13510e6ba84448e59685f5bfbf5b008fdc64cd5e9456beabd23ac011b071e3a5fc0000000000000000000000000000000014a964c9faf1752170ca40cff1b9b4fa17f8d2b56a4c4bd7ffabb65798771cd624ba61ee43160e70731fb9b07af8ecc2000000000000000000000000000000001822ceaae7bd0a734f57b67e4834cfb00a6b415459d81c7d380a2e5b5c795eb1b6d63ddffb1131cdfdf0d76852c75a70000000000000000000000000000000000c5a1575b30e5470151ba055f577a0ea49cff869614c50194829e53a3e1a95847fa387a0f45d537cabef3a5925e61c432583e821328ae90a7db16b20525228e8d915bc8d46a642cb0a06dfb64168cf1c0000000000000000000000000000000018cab86a0d70fa30b4df3e05a91eef57f6505cbe4bb7284de56d420ef3bf315be9249eedfae92561c643bac2c92301ee00000000000000000000000000000000098ca598ccdffa9bc9d464d51b46ed8a8f22a87ef408cfa45fa7f78ae2dcb9f861d9d6a571f6fa702a71e783ee3395cb000000000000000000000000000000000c073c0a323c3051c302c0558463a5c030539d74b440fdcb16b42ad5ec097e10c16bd9a651d149dd719fb1fb865420a9000000000000000000000000000000000164e622bfb8ecd5eaf691abad9db38ccc64ff0fa1784d26db8c8fbebc929bc6d4dd471321e01233d55fb4a9661780b5506f22d323a740553d6107e651c192c1dc6e0a0161a82351f125f08c77e53fdb000000000000000000000000000000000fa48147388181e8d0033004118848c50c6425f2e5f91945a17abcff4d11928d298c092d60184e75e67c7ddb9eaa8255000000000000000000000000000000000c535bc54df050c1ba8d858a346d3a644e03fe24873b7dc3e23518d44b06fcb3f52b4be6f11d3b66f0180a0a95dddf680000000000000000000000000000000015e279a2893c205dadc8e1cdebd9c85454cd4b5d7537f984c8f9d451f8316620279357e218fef87339f1728fa317fad5000000000000000000000000000000000316e343ba68c8a762f4c8f2a5c20f16abc4a7a8365556c1625df832219670619b6dc70727e9bd9a64ed491dc22cb9d57f1bc0e1ebff8f935330c35573f9fc3b900606da9cca9a36b425977af47c7ca60000000000000000000000000000000011dc72100cdf676e41f21015fa7c57897da8260609467ffd38c17868a4dcd2bd5d4d72e89cd0db2de83618222ea3b5cd0000000000000000000000000000000007e074f73287faf304f618478566b91c8e191b229ab40743081342e676be09c2523681cf7ca6f7a396f8589a4ae18a6d000000000000000000000000000000000ff753a16c16bf0dd1de9fa9316694214aea6f99b81f66b6bffd58837c00d7f5632ed5f8f4cdf32ec59c29241ed5e28b000000000000000000000000000000000851e26675814612bcfa639fe567633e1960578a0c8d2e6568418f633eebc109e6c8af97e77bb28ddd47c6bba8a7ba724429b85fae16200da6eb8f62e95e027c24aa6ee2a145f6ef225139f29aaca29c0000000000000000000000000000000009eb2f172db0fe9ac0332381d929fa200a97047f6e732570d23fe27f5ea3013fdc52fd0b5ee74a4387af44647b75f956000000000000000000000000000000001355f8e1cf45443855f2d62dba0fe45b2bfc4e0d06aa7aec7e4f7f9c4e25b33d9c46a01c224517bac9a1390a9806ed4f00000000000000000000000000000000179d47a62a5c847f47341b1ba58f2c3b073c5282f925f57efed1fc43db04185955075255e4e4f6c209757ddae59101dd000000000000000000000000000000000ef5f74d4b13754ceb3b468879f1a8befb8bbbdbb143eceabf2dc8e68fe6cc8e1ea4f3eca1b23a1175c9f5f5c4c20d3454a852baf21df9f4ec8d711a48e6ffb36be8c09c8c60eaa090876236b2eae37a0000000000000000000000000000000005b70a4d5b91b85971aef26b1521e12904b7ad224f25e31ec6ef59856cc702043a3eb975bf21dc8e4fc55171a3865bbd0000000000000000000000000000000007cf7c3e75a837545b53ca3e175a275dc6fe42fb88678aad45910d150ea9c6c94eba615429540348bb2ba8efacbb20e60000000000000000000000000000000002eacb469f5f8ee6c9f557a6ddcc854e955c5b9203b4ca5dd2e097d3e021479e13629863eb5ff17db46a17d3b0227f58000000000000000000000000000000000905e66f3a051b304b110a8682169fa749ba0de7763d3af7edc3e40f2d22ce7b6aa00cd06d2c82d74f3a9709d955f44e13814a3c6386b19f7b93c2c4e0eb1568e8bd3f0012a1ae1357b127c33808aa0400000000000000000000000000000000060ac9ce51426d360eff0d911d9f97a86494340bc5c5ba31ef146b55ad3633ec57a700f04b0cb9d4e91e13c2cc5e68a8000000000000000000000000000000000df205ed85e27c25ce27270384d7c3e58c4e0a9f214d74cddfbc7904eb3115e7bf204375df7558c3e65f7a81a942c5160000000000000000000000000000000007a220d42ca8906013479442d7204457b3ff37c9ee70d64f9f6858ba788b7fc13b71d33ad527c6fc673ad8940b0f01cc000000000000000000000000000000000ad481ef549de13b174d82fe88fa57b7e31ecd8999bcdb0c7a8735ab619a13b1e684b9473f0c59c734567cc08c76ecd6aba0fb0440b2461ef64af6ec5f15db381714fce1da6e03ca962cfc94bba26d74000000000000000000000000000000000366f604228e2dff2348a462c56e0043037d1b415ffaf155e72c559d185c6b0a0d125585d060f159a8cdad959af631f5000000000000000000000000000000000f69e829a0995914ac122299d4424b4e2e120fa4913939d2f18f9d1496e7255d00ff0829c20521ef47bb0dee06c28dab000000000000000000000000000000000a3efb4a376281a60f5246d8fc10bc23cbb9cb71037f8f57271a9b01f5e0340a562f9acf0e9a95b8c65ab7a5cd95520a0000000000000000000000000000000004a4ec86e2b04bcb35c7840d85cd1dfaa88e17ffb557ac591640ed8e563cac891793b92e349a7903c6c1f88d26a01c88c01749cac36dbbdba5662687fd1ea5391ef9d0bbd24e05bb5904a20fa6a1e11e000000000000000000000000000000000f5bcc27c243ef65dfbfc0de6d431706ab20d6cf6408ca989a2bc1c52b78ab63de6f58b70bfcaf6878a2746f249b6b160000000000000000000000000000000016a4c9e8ad0634e8afa8606a1a7bd1d8cc0815dfc6906b6e6446e0ceddba4a4a2df979d27cd07b8982a12550bc700fce00000000000000000000000000000000051f8d972362caf0a8a39045bb468112f2e73afa392079f8a4dc4c3a3cbb8dc224c21b6633a5ffbad08796ba2f8df44b000000000000000000000000000000001825aeffda04705ded9c702ba30d24b9fe8eb7cb106ee5d4e4ba029dcb57bc42c74e74e92ef8360cf130590b838645429680fbd6e6c7b1b14b000d3d18bf93242c74662ef108d711d85d8d442e415ffd", "Expected": "000000000000000000000000000000000d0ab61b29ddea1aee0ca4e81b5369f37cf45be383f64ba0b1a5a74b790d7264016ee671959444c94b8e6291c5158ea90000000000000000000000000000000000152bf3709c56b3add8e3396d17abcfebbcfeb230529ea8144d6a120a0a6aa83cb284e40ffb9fd9a96f8a2f7244212400000000000000000000000000000000041f516a7cb2a7137746d028b0739c79ffd8f7535f20ba3728ede32504fe058baaf684cc7677967aa46777818b1fb6630000000000000000000000000000000009f1035729c55cf6ee090983a54d8c0574bf96342901f471a2e5380f11f235a075b0e157c38c456b6eeeaa10b87d3afe", "Name": "matter_g2_multiexp_11", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000011ada4731ae7df493e405383603a8d79ef77f3fd14fe7b8bd9d2afe068998cb712e84927d5e6ea6e94d7f10270fd193b0000000000000000000000000000000008a14eddf88826dc3be792a0c1f7395efdf91454cec7e26c89f6beda37b194b706dbdde8745129e821b6f4b4ea6118490000000000000000000000000000000011c29513e8a826e6b3eefaa20ad841605d04b813cca282fe02dca0f588b9a579b2195b0b080cb6d12c1a7881008117f8000000000000000000000000000000000689c67d05ca379367fec99439e3806f827218ffaae995bf38dd8e2919fb2e751f426525cc2c6ead3b9aff2e377fc99e1ddff10527bb64de6ee2e3ab4959ebef9e7a6964b7482f9fae396b2b9b0cff9e000000000000000000000000000000000dd683a8e4ad54b1a95826a3000750c6e3cb250ab5d6add63c21b182d736b220d917d4e70044ec7101c3bf8ac620e1dd000000000000000000000000000000000f3e411cc6800b304fda1373ffa60c7718e20bf3e2e5f9784a81b47e398888b366e1f04f48f5aa070a661b5e2148d4fa000000000000000000000000000000000b0f8d0b695e000158ba80881a9256ed9dda5a7f53b550bf3b5c67ab160060fcbf5ce07fe38253ce037abedf4c6f08d1000000000000000000000000000000000bb92d407c457e9ea7b9851770d2743758e162dc9cdff2dd54b8271c046f642729cd2f10576013adac84a46d38623b932943fa2957d267019309f4fe5b6725379d893dcc270ff7f35b3811ad1d8d12b100000000000000000000000000000000023e880685aa69b3480bf2b7f2aed1181e094322da9e79c9263d50a49ba4fca713740bdb55886fc81c81a51045b35139000000000000000000000000000000001707049fb8b7ad278be2949b9eae2e28bde9de1d9eb964eae582541c2d7a8afc4c1489624a0919047a167028b8c77e3c00000000000000000000000000000000062dbb2bfce2f67c32b87ec2fa01ebf7deddfcbeda2fcf0ef094b1be77b7411f657e745350b6d2da16fc83a96f6f20e500000000000000000000000000000000062daeba038c7bc379f56ac371745b91fdfd5b4cbbe50d9619bf1d077f3cde966f81f9b851ebd206f2609a780b6dbd681551a3c2d0391fd8dedade892e8e2171e652d2a9b52f2288451c55f77fac788a000000000000000000000000000000000b553826dd9e2252c9da74c2bf1bf850df3f9c37439859f93df3fbceb7cca4fd949dcaa7fff31c9e06f41e51ae0b30bc00000000000000000000000000000000187810711ea5911a437a62e2ca483983bf2535ff9301a1cfe1b4d41902ef689f8d86f817a2a7c77128e4ce1ef6b037d60000000000000000000000000000000010170cf5f2ce08211cfc41bf54cfaa16584f833f7b97b2f6bc436eecc56ef44463690ea1f5c8c2a8f69d93a25206282b0000000000000000000000000000000001e627a68dbab6b0d05c85e49b966a769461ec38c38fd94992839bd0d46e06410fa7a48d418d65a8285f7852e8af4b318eb2fa94a5c97c28d95008dd1fe60137b34c2e763292d1b86993c02790b8c91f0000000000000000000000000000000011ebe2edc3de58a57aa9ab4d6626d7b93235ed24efc3d75c1ecae376c00beffc5e89ec509d243f693d327f7a4551921f00000000000000000000000000000000088ca2fe0651e4d8f3958454640a58ea1cdd804bfd2700bb1bb8e26ac50f2d7fc8c292f94b0bccef5735c4548025735400000000000000000000000000000000154936de8932279cd39ae803a5d814864953f647a5334bad958222de765250e4bc847e02979689dc9cfe1993486b5750000000000000000000000000000000000c7ce07c9746c6d72dae11e243acbe12dc23423f870f3130b244eef34524d547fe0b2c4b704ecb6b2e6c32f5675ce67ff72ae1def6c988f9242bff0e683b8d2a5c1aecfd6ebb9442131ec5b5b825d0f600000000000000000000000000000000031ea855125d75321a2a86a93e72fb3869dede7531dbcc1cb07ea2a352f3c6cd913275d0d43ccc370f4539f668f205f50000000000000000000000000000000006c4cadb11361f164f5899c6b57c0c6d8af365d902f4575c9d2d14dfd880501ce9ce218544b44bf07f0f04ed68e8f315000000000000000000000000000000000131332638026fd25b1a849c984f9dedd71e64fb52a61968666ba80238673077ac00b9e09817426ceac8c308f475303c000000000000000000000000000000000c7634af796e7aea4d4d83c9972fc822dad951d2473210ad82706ae0aa023ea85c1c467bdda68881094ad2a4f54cb33f331451748146f0564ab0d91b09db87e8a6ba8b14f8329bc041911616195f9fc0000000000000000000000000000000000fcdbf0083065e13deee2020bb6e47cb9e482df3768ce569f1f7c0e1c6083c97d9f08444e67857c2dce40e4a7b8d50cf00000000000000000000000000000000010f246e8ffccc2e752049f638617e122773a6f10220cdcc0603d24f1a94ca7c100f8ee2d9bc7c0a931fa0385eee456f000000000000000000000000000000000f8b68941df75cac3d4b6b3bee43fb357c8f4e56309d8509fdc62620a085d7ee58f52c7dff28525a449cabfd3b7ab3dc00000000000000000000000000000000019f934ef0c7c40786b073d38cb3e4623544cad59cb63440d4a6e76944d491f6b982e3a5e84124996634687d4618418316d298bf591bd927aee24a37c5ba508c3bc121f5150fcd1a70c1f27a79da7d73000000000000000000000000000000000c0208c1f3653fb3a5e2acbbb42f2598b22db1a714d616ee6bb501c3338e80db34d517c7086d43ddc77e0134dc5a4f290000000000000000000000000000000000a528245342e44e36f8e02e7259749e63ecfb38cb0609075e871701f2b3bb0765277b78d28cc3ecb7aa8c9e3b27eaf10000000000000000000000000000000010446583a905864064400f9ef168a122d179d46a058525c9be8a65a5d2ac5e967d51185d4964f81a5571123717210d050000000000000000000000000000000017da91a1d0358271b11a0aa524341ba1ee8c31bed15efc4c9183d60c6e1842ec4383070a09914fda991a63d55efa8f2156be810c3fa86e35bc935fc2b27971c9c41d03c8ab7b6c8869db90b6e0986ef400000000000000000000000000000000176c64efbfc9958b9c8e71b55e9fdf525d4e5a0265ff01ba95bcd5c6093bd063726f8e277d00b138fa4d8c8f80afc4e200000000000000000000000000000000183eaa6c3c605828852ab5e8a9432bcb87411dd18d574cc2491f1a280e7a267ff9ccc80b06c22e95107a72f22ba2fafc0000000000000000000000000000000013319d3a8564ffcd6fc7accdded740127ef205e8299b390d21e96b2609cbb463569c878f36191d43927868b06dcb912b0000000000000000000000000000000000fbde0ad8e89f5458007ef6ba0f01d0aba04217e06745a5571eedaf544443150f59117b56937f533b4974e5d57c41cbaea4445926775a6baffb4dbeb249dfe3b3e0c29f2a579927f540d8f6451553ef000000000000000000000000000000000c044a5116e175ca1d1ae59d400de24e4f47132251b4b3dccdf458623c36b4d3d83abc644a2247ac4d0e3f195d12e7b000000000000000000000000000000000048dff6bf65f158b19b992167ff8adb5c858a154bd68bf0c84e41351bf47a8f870cc735d1be5d9afc62bbcda2fcdb1c20000000000000000000000000000000008c5539746d2610eea22e79b3fe5b33a47fd3bf9991d34c6f9d824a46458480b735c0051d7b4e4909fdb1f2a1a4e4b3a000000000000000000000000000000001936558ac97acd903a29d07c4aea399227ea13fd6dea820813c5519412c157e1a477fcfbab60a787c6b3834eac4522889ee0e58d08779add74b68dd75e82df172b719cb5a772b0bbb34d3401b9f212ea0000000000000000000000000000000017d978d60fc89b0429c1a6424231fe9274cedad5d78d9c4ac5aa2dd5e70e8238a0bb1904bb4b6ee5de5cd1ac514c62a8000000000000000000000000000000000d4ce85a95dbc40f405f4e7ebf9121cdcd22766737c39618ad0fb3e10a6e53be1faceaa96073b2a877ab808483ec9b6f0000000000000000000000000000000016c61599ae4da787fa6db233fc28f5c56f7133d403901800ab5fa19d058fb27ecb34ca2e56ffa7628ed004c9e62092700000000000000000000000000000000001e64e4adfdafbb423b1b9f8973738c690713911f68f658d234e57dc35b9554e0f7ba345dd7920b429a12b9c74775222773d07cb9d20744a2c3ac88082a8d6606acdc892666753793a2b8bb81116cc6d000000000000000000000000000000000908ebe27a1bdf0b9e56325c00ea3814527005793ea97eafec541c01cf2d7c909d2521a5fd475589a31e297cecfd5e7000000000000000000000000000000000017e3c40c60cd369ce5a90f6c4aff14896cf73fe06432e71940bd8086e36c2353d6bf9dd414bcf92889887e2d49fbbf5000000000000000000000000000000000ded856e5b2b139487b3816351584f06582a933af2bd4573a89aab0a41af01ec1cb928a7d8035228302032d399bc7caa000000000000000000000000000000000833b77c5d5c98ad95a144c0f167fd3bd62b03f4ad721561ed1d84c7137dcb19521f781bdd3ddc22afdd52c75146e101f6bb1445e9146b117bd0c95b009fba670a5391874dd314cefc884bdb0a4eba680000000000000000000000000000000005c6f28c5ebd981fff3aacd70eb18f134bffdc8507d1a3aa153e5787b68fba7f4a94c43045d2676aaa992754783ae87800000000000000000000000000000000148ff39e8062bd488accfead42a684f781c4ee579af6204b5b8dabad9022b029139b1f3670fc270710ced9a53253850c000000000000000000000000000000000ff50eca1a92f123e2534b3289f37ffd5d4e05f7678017ac20e35c2deca054dbe376c5529cddb5e58973f5c60914f251000000000000000000000000000000000b58298ba9496fe32891f4c1cff25395ac5a447205cedaadda4dcb929260ee55781916ef5e4e39793fa2831142111226d4158de4e23d793ba77c24a70f0ad07314927fff34361b0d74b25e8922512d7a00000000000000000000000000000000184d156f881f7d10d2f196b7599db85ee826c9c95383978ed68918756f642a2ed1c951503251b0778dcc39598d79fc8a000000000000000000000000000000000952168761380e8fc90a4966e94b8d2b88a784f6e607c99d9af1aa902506f59d6879153339fdb7b8acda178b9bce4ef90000000000000000000000000000000009997621d4e17c76b7798ef2f99d3c0a7519cce278cf718789cd8227b2b1459af7fbbc93078aa0aa361167b1d1c9363600000000000000000000000000000000005369eb3a77d2e26f9907a2d930f39dbb87634346cf10525733aac8ea10eb918d4043d2a05ff8e80b9c69a670e17f15c629ef41d5a2ce49fd81930406f19e760a47074e159ce372dd67e7ea46ad706b0000000000000000000000000000000019bdb390c66f7d28cfaa91bcb34c5c55bf93a9f2345ea396f18ed33ff2221a39cf68c5514fe091f7882e82470efb1fee0000000000000000000000000000000002d0b48d2c0377b0dffca247b7625f9901f86e2161626b4154bc25d6c643a48e9addd260298bedaa80e42caa5b9fc5b10000000000000000000000000000000018a2b0a760652e546eeb42e857ca48f59741eed91822c17692e9c41358b213c82537c9c6898713a13a241cca627a7dc400000000000000000000000000000000079c02f41fca45a56d9d8e305141b4fe8f98d102197e7864065d342e6b07f65b62632e0c12660f37de4d698c0df3d0f3c718651715ab786b4855092ed21be41b499b7824d0bcf68ad31b31ee4cb730d5000000000000000000000000000000000c0448fd4ebe9b5615653336fe0a618fa281b0fd7d72a8f956a5fde84f7d356b6be853bf823436bc0b61a603636db9ef000000000000000000000000000000000dc4f2b4d810c4290e263098576cac393fce137cc901b3be23507cecbda7d86d18022cf8e1a7df4b1298520ae5c9314c000000000000000000000000000000000a39413967b558dd8a6b2bed972687d984fb9abd0662a266680f8c90f1897e2aca1ba37b41d7d3fd47406bc5fa3c5b7f0000000000000000000000000000000000550fcbe5bb75afdd8d5f387798a8e83a8dbb6da4918c24eb2e5d2d8acd3512f6649a4ac9c8d3e6794e6f4f8a87687bc685a2872c4980518fe60c61e2276ef53c007166f7eceb355b4cd533f42c00b7", "Expected": "000000000000000000000000000000001654e242002aafa89c6fdb9e8fe2c197ad2f8aad11868568dd39d68ca35919f94308a80303655bc83fd130de6f9723a900000000000000000000000000000000062b5a064840a5a28b4991ae949f9508586447ad5e8c463593503c0e5857c5233b7ce7ac03e555c2675f2e320e8cee6a0000000000000000000000000000000017d65fbd7caa69629f66be8b201f53baee5ef2957a3c04fe384ae82959105342b52483eba6bcc1442763c677f515f6cf0000000000000000000000000000000002ef8f8ed1114cc9d299e59003c61d62edf8971d65b1b621779bd7b270c4123eb629f56dfa2e2723501588a0caf1847c", "Name": "matter_g2_multiexp_12", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001392409b92282bccbdaa0268e1173e60911754eb3cdc28a52e93f4d82ec99026f314dfdc59b39a4f988100f9c30cbd1e0000000000000000000000000000000016b3c555d5c196551ba715c6c334a668bcae80f5a17f038038d35dce34843f79968a90e2102f0faa22a93d3240b58d490000000000000000000000000000000002daf83727fdf45dcc1a15adf47de3f8a1724cf4d34116f52106a9e6b22dc24a288e89b940cc57e5a6bb87ee70f680a5000000000000000000000000000000000446009fa3555e4a056a820efa7da52117c15eb105af57985d8e9b33b0b22fde6aef9bad30480c2b8c1246519795f61fc067ecd54e9ef59996493f846ecca63bbd7ec28da586f0b8d41bfdc6d97a35cb00000000000000000000000000000000000372ead514d53007690843484c966361661816e0d3949b868176d7a9bea42064f49113a74f2572a6dca7afa0642fa5000000000000000000000000000000001199d3ea66fad87074e62a0b77d3fb962db17dd948f30c38f5beb0e44e1cd11d9172b878128e9a64a08394f13cd786f60000000000000000000000000000000018b7db157bb326ee2f72d4df2b1e0ddf0a90401ccfca1d4ffd6379c62acf5d6e4176a23ded2f81653038d56d848b4fbb000000000000000000000000000000000a932cc9740812c8bde33b68d94220690e0f55618b7e51d3e3fc29d0cb9a8d42b8f8e1efbba5984c3c1007c9a80fae408b5112baca5e0f2bfb885c5041189612918d203a117d886bcb3b27df7e64d17d0000000000000000000000000000000015798d10386f6d24caed3859875be5fb1a43ac753f725f28da6b3583bd9c0e404d36265c2305d7d194e2ad84bfd2bafe000000000000000000000000000000000ef2ea5f3b6e03e3c9693d6db60019f2efa4ea586bdb7623f03bd035c603e8996ef2ea7cf745aa31f60679ca04f93875000000000000000000000000000000001792a66785a3087a80c4b8652c1e4db8f602cf75c1a6955f480a977f92ea262965dad84061f6045177c831dc4a3bf8400000000000000000000000000000000006ea3862318974d6347639ec0d70afe748f4edf32b9e437fd98f38eaf72168a153cac180c2d67bac8a358e3a4d57a2b32db7ad39ec8129e9e9206bd46cec6a8ad3362ade1beaa97befe148f6c67a9c2b00000000000000000000000000000000000974da7500df70d888d5876e7c61bfffcdf830b49bdd40edf65a2ff476e9add35eaf9451a2166e9781805192ffd7ac000000000000000000000000000000000cb2e7152b5b40758b18caea356dd8e095f400282881207c4b79d10d741756e526be261b98b726d5cefb668dcf73a0a00000000000000000000000000000000014aeebb995d464f4d77bbb72f15d9078936b5ab68eb8022bdd97d050576dbe46e6010eb72250c8ccf2a59138efb38f9d000000000000000000000000000000000cf7162768e8eb50e21d3c0a076c7bac4920c70f334336037fb40e57e0efa91eb025356ac3f0988a6b127408a02eb53fe2400a11d9a67041824b97a96f0ea9da8848e7990373655d76e8bd4eb84df5dc000000000000000000000000000000000b1d6214796b4775c2b50e634a549ed104e6ebc0e032967b17eece6cf88c93aac23059f263faf3c3f38463270320135c0000000000000000000000000000000013ffa3894a36226664ff53ba9256d39c6312303f5cbda6847b4f68c56134b7d731e74bd711014fe374f909a081a7d02a000000000000000000000000000000000ae4590cdcb1367392635d0f8dc6b9557abd16290fd1abca6da354646d8585a7c9432978dc616e5fc38cd71d55f139c200000000000000000000000000000000124a7b5574ef52359b4beabcc56d3286db8c8fe4ca4718f75da28d89a8a95efb878c18b48360dbcb6fb50a9f18f0d559aa2d17c409ade92566ddb3913806723d41067540a36a9c283bdacb273c5b258a00000000000000000000000000000000148ab0e847ecac963f0156da025dbc52e765cd8827fd55ba2969da6775649529226ab13ab8537ad0b89e8f1ebc8648ea000000000000000000000000000000001395b1adb6a56b91c3621a4ac5886a7b13ec00f1c74d5317eb74a766eae655e09e269ec48cdf740abc38f4d6fe52dd0f000000000000000000000000000000000f70f77f07ef2909033665bc05cfeea7df6ed55f2f0b1b87d9f247b6c07c7e22f516840efe68005c3953a2702573a9b400000000000000000000000000000000166a334a711416cab180cc498308487b281711f2d1b832c410ebb4c591af54b154fc8c8d7ac9a49a241f7a3840acbc75e5e3d21862b64e09a0893ece646de60cd66aa483662125ffabc46cc52f1cdefa0000000000000000000000000000000008c19bcbdc2ef26a30dd88f3e35dc7fbb3c81c0224cbcd6b12c90883f3973bd7089636f997e5f213fbdcb79514c551c600000000000000000000000000000000058620cba8ed5b738167e809cf71392aadfe8f384a4cf397d10f674cfa914e9e02bb1518e42f16806214fec52d880f6100000000000000000000000000000000048ac1120d26e4173bb33a58c0ce86329cdbe9df6a6f268c8d5ee4f1d6110f9d81cd50c46256198a2462d50be3e781270000000000000000000000000000000010af13ba791d554720f5075d46d03b55c0c1dccd679cef5a7d439ae868d3ff2780cc3ab151feb72b8b92905a205e630449510ab1b7850badf58cacad67fe47135f6524f0d160f3013e8ff1c881e469e40000000000000000000000000000000005c30a126c94b87c54270d0f23a486c3b36a8b491bbd805ae0d5f2bea818a87ff5aaed2d5e6317b786ab5a23f1cb48da000000000000000000000000000000000eb2d4663eca7f8433f10e84984781a57fffcb8f9535518721521ddfc7a4958778915ea3c57bef399a453b8ebc10befb00000000000000000000000000000000161947f57d97a858e5b3e918dbb22dbf28629e51e81335a9bf105d0fd660ef80087c8d69d8db9841cc69fbb5e7f81487000000000000000000000000000000000c52b6a559928fe4ad984a0569c081f3f71eed3d5b0d3c14d1a23afa45594e0fbd94143348390bee178720fc603145ab713aa69664a8c721cefa7d6dd3fe9f92432b4d350621d5297805fcabb21ff8c600000000000000000000000000000000071aa47d392e1a7787b37c52acedbb4632d5549fc11b79919bab7d22f1bbf1c3a239df622b8824b07f6e35e627283b8500000000000000000000000000000000198e72e05388021919dfc1b2a58ca72bf7655cc6c9b62abe3b45cc782ccfd4a2334780e451b8a6b7c311887036813fe4000000000000000000000000000000000e20cbedbafd96c42612e146debae48c7fab4846b20ad0848c4c42c6aa0603e72f94dfc938ed9e3a9886d221ccbdef70000000000000000000000000000000000c861d1878e63e313e672bebdadd3fdbb691cff5fecbc24da895febce2eef0a3c774a8a9d751498e4fc8e2b71daeb40dc040d8bf0a787346560fa3b100b2dd9adb3f7ee716b8103abdd9609363345ae40000000000000000000000000000000005f7cd2205fa2e17fb9896efe3fbe110e1fa59db1ae5f8d6b5f4510abb4da867933d4fe3caaadc4457dcbb35f1b9c62b00000000000000000000000000000000126f2ef6022a7211fa865c1dbdd5b84d96cddff424b06647acc462408f2d31f34ce898d76e1e124db7c39e08dab0bff6000000000000000000000000000000000987f916ad6f718695f3c40703c59ca93eba38931b45d7c33c64c9f75556f075b744dfff8a5f21489b3db6c3846ba09e0000000000000000000000000000000013011b8c72f3853738e22957f742b05ec428ab0da28901800f787b7c3678449acd0359fee93c40c69623aa4acfc0a81017b811aeac4fb7d91abc655f8a4392176f9060346073c957ef903e25d10935a00000000000000000000000000000000014b88c0586fa18333ab11a79acab8e12c6257f82a4ed16d929768a60a3a5d780a22101c32ea9b0099aa2816f18a0351a000000000000000000000000000000000de0fde69efd2cea7ae08d6d2443883002e0b4e11da253222429f6ecc67ba8d282eee84d7f46e0ad00b039a2c2ad226f000000000000000000000000000000000aedfa0a5a8b7577dcc1094469233f8b07e6fc32af26841894d498d70c6a9a046ad636086def948d21e39833c5b6c5a70000000000000000000000000000000010ec6aa0efba4995582585bb67f997f60741648156324696312d17656baf6aeb3e2db0d1a272912fab2fe81d139e971cbd1f096026159218836a46b9801a4f0c43189324d20220aca777b826eaf2575200000000000000000000000000000000004a847c06abc8ae7ce6e6ff0ab856889dd3e9697a75e3cd4d2af9e06d4c2fc48c0562289348ff52f4d9855ad03d83aa00000000000000000000000000000000075673bc79bafa9a64de6bb0e9dd9fa29cdc9c82e90a7348593eec673cbbf22b1eca436ecf767d45852ed888a3f23949000000000000000000000000000000000f3f8543d1e667404b4564dddba4d7c11d13881fcd8ad774c8eab8fc599f55147c353cd6e163cd7b9d5da55ebc13c2e800000000000000000000000000000000069edec7e7d26962d88a89dfad213daa36046bb2851e5d67adbaa227220f29f83ea67cd3747e6724f148dac28308604cf221dedfc21098ff9a9507e493d0fdb1efa6029fcdab23a016515078c76f7627000000000000000000000000000000000c945e83822896974116663d3e2769f3df5a70d55b8392c1f6966e330951f3cc5688742d4588648a6988b928b9fe00100000000000000000000000000000000003e94b7ff7c71d633ce69bb44d0ba1bfc7c27a5ee618e703aef81a45ad61771a2fa8e3dadddf7c8038f1f65ad7513801000000000000000000000000000000001727d768c1b51066d2af87a9da3e24ea2a75b0f75b8ece70727f9f54ab77d841e7ae01c9c0760f4186d02a28d6f8ddfb0000000000000000000000000000000000a273f9395cd49b646e90fd2526d5c93fd46c7366b715546529c9edf5cb3d274c9947c21a03add3e7b20612636a6745ba5b30d1397bf28100f108b84e05107ddd6cae2e82f1973ce187e8c3a7d02f3e000000000000000000000000000000000c996c16a16879bd3194ac366bbd11b5863123ce6fdabeafe56407600e5d49c92ba68ac1256e1515dc9256de14ac26de0000000000000000000000000000000018c584d8a4f14900b2fee70b50b700199ec2372b731dd1380f42ec7fd3d01f0c9a007554059b85946c1c4f4e2fc504ad00000000000000000000000000000000073d6c7d671762e5398e4c9d57f6b68c3d97dfe0d01783f124256fac236f03b774db58b79cb4d5558e1ebf18bb9e19680000000000000000000000000000000008eb2b95e17fdda916b08ff2819cecd2eb031f41c8299b308339b7d9836382ced75e8eb1514a70356882d3a43227a9bc19aadc83d1db9140af303c0492d2b9bb9e2b53ddb62cd2132bdf8ef62aaed683000000000000000000000000000000001029fc28cd502caf3ea3619f6fd04bf457e6a452b5cad680ec2d4f8222a5ac2daa92b880bda76016973494e605ab28c60000000000000000000000000000000002c672c7571b5d8e99de6e47e0a2eb71c6d9bd12baf2b083e6f88598b32c4644d1486aef582c5936e622058bb141db1700000000000000000000000000000000033cda383a77d5b3adbb0809e834993c56717f81f8c66ad2d97f2b298d5a46f7b29a74d35da09271b7053a05af096393000000000000000000000000000000000132da041c6e3e1d68bbd2223f8531eabde8e180b36b2cd0ed4fca248f255cf3eeccdc5f61e1c581ce54edcfb2b73e0787eb6fc40b00246910626ab66bfbac96ea09242d1d70496466e4d681942050700000000000000000000000000000000009721f22bc49f68d703a4dfccc3bae791caaf0d73892bafa6e9da465ddaf0fb1a069ffdd55306acff2407da64c1c5a0200000000000000000000000000000000056c0a4804a19aeaf1b4fe52064e43de8e5d41a8d77de054e2cfdff078eaf468d123d7317818d1bad1bf3469c0070b680000000000000000000000000000000007f1f318aed043d9ad7bdd53eb6a8c3167240fca75925b04795210700463c93a66ed64851195df1bafbbe4227d7db5ff0000000000000000000000000000000007b8945e258311e7672e842b91b540fec9ef4a79296956a5cba3749c0ad95ed83d7b0b48384ffb3188459e997b86695d3bb5926f36808c0024ea7388998b4cc8c6c48d32917f6456b39d514143c6eded", "Expected": "00000000000000000000000000000000086a1ab4c19c27f70aa422e8292752c50b365d6fe3eba21e8f2ed51f283df0446020834ad27c18b5c7285d1156049bef0000000000000000000000000000000007288f40fde69bd350ce1f4d0f68e645f42de319cc032250b76fe4fa305341e244e5b2366751d5311105e3ccd30e701c0000000000000000000000000000000011d0c487c4eceaeac009b694931f8eafaf8eecd6028f14a4de33d2940bbb747025eecd509564721b50b7186910f81949000000000000000000000000000000000366f0c901fb859b4bae006fbcc9ec7e456eedc7366c899f68090fbd457c37b03ab99ae982872c7888b65c1a056c134c", "Name": "matter_g2_multiexp_13", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000072f3f03bb09ca30239dd8302b05e0d9dc4e43ea33e865864a82578c35eafcf6868bf0cd9431b92b76f00990b780ffa400000000000000000000000000000000170b76cfb7944ea5ea055aeedaface3e8f0fa4d0ff657fb9d5311f3af6e736da84a5e2bef5188e20f76fb42591267fd9000000000000000000000000000000000d85300009165a8da9cb8e590f7f8d372e4264df150b1551185c80e49dbedaaf872ef69c5763fc3713d0c087c89f21050000000000000000000000000000000003ba59b682174ee61630df95c8e2b1c48ffc8f7f8508c21f3bbe8f7bb3266521fcc06c8f90fe5126d872707872db6d59f44b0204792359895b448bfe6ffaedc14d54a6d72be7a49718c0a933807a399d0000000000000000000000000000000004e8f16480c2f080a13b9f2b66e6480132d76c4ef76e8bac995a8e33280073ed5610865260e154b32f75f527d89620b3000000000000000000000000000000000f9ca48d732a8055d22fbebf3d2bc1e1c9c815c184f594ad2337731709317ea6a205478ba05ee9271d35a19dcad4db5b00000000000000000000000000000000078013b9290284e7ad528a1bb9a2a64b3ef43964c7226ddff8ca16ab17b4a2e8a2a7d921ba924a718587954f586a954800000000000000000000000000000000004aa76bb1122116cc0c04d65265d8652f08b411632a732a9e66d7932801b77c4ad398d582e446968f7f4966e9167894de25977e7426cd5652559626ff8b195ab7ec679de987a6a22a6a0e366759dea000000000000000000000000000000000145de5d101498bfc7c57830eea2931663ca1165ec85b77654c866b04ba6a28bfe710c1aac9876a68cc6ca119708eaf0500000000000000000000000000000000096f9df9d5723e8379f2d09c76a3fd059be47d2c2ed8905d333b2464f72153c5f50b6345980626358839ac691c26c967000000000000000000000000000000001788ffa765c19758da6eb6c38e793190c64d4a7b116576f6827fc090b0f65304988f6a95cf4397f82b7691fc43960ee8000000000000000000000000000000000746e040d7aafdb06a31ba3d7b590dd28f0678badc261a93dc7bd9a605047ec67ba86b2b6dd72637a449872674d6b5982e7ae497b44f531fe203a599622954804c06d5348dc17eb1537e750006584b21000000000000000000000000000000000d8f3cfe1cbd2629f3899313cff16ca3d8f964ec1cc0508341936a7b3b49240db1116b2c3de28f9bc45cdfacdb5fd98c000000000000000000000000000000000fa642ed31293e44211b34bb28bd5b389ae6d0510cdab46c89756f31795506fccbdacafdff21b0127e80557e5ba9afdd000000000000000000000000000000000715a8951cb358b0d8cc63377799a9a61ecc85dac795d726fe60e429d492c9ca843be2a2633c17f830f199335e5d7741000000000000000000000000000000000b88a23fdac7d35fc135b45d7565854bf010a75f072b32c57ca4d0979c111aadd84c71df6792dbdc8e975ecd46a15df2e073adfb5ab96730c53015a4ab6210a35a37b2331ff5123e00798c33e040a913000000000000000000000000000000001171be5820b5a19c045abea399f2b8ab9905d2aa367c6c8c0f84eac132d26150b759a9c029414f1c8f7e4880214446c200000000000000000000000000000000147f0877321f2709183f0b617a7c5ce898db508a3ced4148cc9f7af011fe8040e90885ce817aa956d9f5d19dd968f6220000000000000000000000000000000000acb005c11481b214a17e3cca02c2af266e4c8cd928e3c4e221d866e9f296a2e913bf34c4e051c7503a5e4e7cd7449900000000000000000000000000000000125f45d0af1c010cdf8438bff0f406007853e566fa646df40a581f65496197755eeebaf4f0f77e1e936f399dc4c6c020e6e752d40d411f1ee6e67f48109c9a059226b446601047a2189ab815a3fe13c40000000000000000000000000000000019cce3f872af5cc515ac4cd7825a5318ead5b464d50349909a70b415a8950206974ee0d4203f208d8e6d14690158f5720000000000000000000000000000000002e08e8accede11afe3e2d085f35c08d7d414c26a9caa992d5a090a43c9b0c0cc1471f3693f9d342a973da65189c888b0000000000000000000000000000000008a984ad2ca60c492cff2e95d541d71e33b269b10d3df107c0513dad5af511c51806068da6cc7226df1cf5e5a2fbe707000000000000000000000000000000000fcd3ad75bb0a5c046cf83be3d973bb3685bc717d7b8262fb8205935db6e632472496907f7c965fc6b52042ce69999f9e657fda33cf4ed1aa89dbc19d58fbe3043acb5795dfb8c0cb97620f16f8f24350000000000000000000000000000000014ccaf7594d8ff6157f9439ba63480d3d07f44e62a86caaea510d0ec456cd8c6c4b42cf9e38713213eb4942ed45df2ca0000000000000000000000000000000015c2061c532cda006addd2fd6ebbae458197d55fb336f75ca7decc05dc6d421a65495b71ed11874aaf24a0ec13a7c65000000000000000000000000000000000101f953aed7f23b5b6208032f05b818e0147079b7764aa3134dd9e4a316bbef0309ac378ca3cff3bdeab9ca56cb78e60000000000000000000000000000000000c76a2bc721a4d3ead95af79ec24be9b7624bc80d7debc07e388e52ec621082b9a69f48d157b168af4aa73629697f784c73458e18d6f832f362dec7c49140e6523ead045131a1b719b0c836c1ef13a79000000000000000000000000000000000761832bb5b530b80c668234ab5996bdc225c0c696ea07dcc61c330320404827ada9d58d658e230fcb39a96b339b830e0000000000000000000000000000000001198b85418421d96ebfbf436193b411a3a89c206d006291bd23254ed5fe12ccdad15725a34d962005c0ae60e202bb86000000000000000000000000000000000c1d7ab83b1d2ad57a407e248492773a357c06b83c16c6ce1490e84bc4a3cbae395f160181d2bcca3edc34b764754ab0000000000000000000000000000000000f1e9f0cf96d7671763739b6c37fd442f0e816c49d9c8e001d322397e9d6741dbf8769ef9eb83d08ab024294e279a02838cb0a2b191f538b30187dc730a8c665bbfce8186883500baaa6c3242a0d147400000000000000000000000000000000063049bc3282934e29f3bb3dee432bdad6193a5d2247270e88887cac565f4b986e1b3b2af5387cfca64f0d50bc0ee1640000000000000000000000000000000019f0f05fc7f8bf2f0b8ed375690b53b6dafd0a07c49fa55d36e040798334700a3aafc4995bb90de9c4dc0e077ee18b58000000000000000000000000000000000fbe702d148609dc8feb3ac11c5eac8e32a2f7221aa135cc33a585e9f4c97afa1658d8962fd96e26e0c4c1d5108229ef00000000000000000000000000000000061fe418d3b440e84728091a4996119b515118900f54a6f2da2ad5592f48ebc17bba50b59ecf435de3cb892a123ae9d18a27de64d41d13ab67c1f7b1a7390ab4dbba7d219dfeb31255f9401d5b3c62f80000000000000000000000000000000011e8ecf1e341f0146c59a79a8428bb01d2399d3f87d90d057f63e6cb9837432154d17975f70df175a016735caf85120a0000000000000000000000000000000002a5bd53e4f4c5b9682e1af1f7e09dd305e7342d1688f62885b5e59f173a9fc731cec481559ad693030004a5fbd90a9d000000000000000000000000000000000f9601f95e12bf05c35deb204558d44a60fd630c05f4060b7bd9ff943946e8eab507422afe00a3e7706b8ed013f712c20000000000000000000000000000000003bf6fecc0c7414a69c2b48e2c16e88d988ea8ae9d8b59017ecb89394732a20e4321cb5e4fb071aec7d2736220a4553780030798960729d63db70b8bc3c0030e80d9b8ae766e3330128557e6c34442f6000000000000000000000000000000000549f6464b657eac28f838c6a8bcfcb7a189d6b3b9712e19c1a23503ac209da5f2ad4df83acd505b0231f00eb88515c70000000000000000000000000000000001bf4a46dfdd70542e9d8cd6d6215174cba28f9adbff31c02482ca38205cb4afa2f7fd65ecf57b39e4ee5cee320e33800000000000000000000000000000000012d04a693d565f96566b7c313c47d272fef0ecc828493b0841d58f6bf690a77cb72824a656442e288460ecca7cf05504000000000000000000000000000000000b33eefd5df8b098e6505cbe655a483ab5c6e417a4ed55420beab95e8614c8538dca9296a7848d6aa0495a173df6d0b80d32b6969af54dd345f42320ea96def3c6f4dfd4e22a82686b7a3c57a0df5250000000000000000000000000000000000fdd9702ed88aa857254c3ba50b484bfc324e583659c57055e4b09eb1662af2f70b547a1eec139193a0d3c75b565d3b200000000000000000000000000000000193df0fbc5f24065008b5e98c4c4bf9f1e743a6ee60c3700ae4a9108639e540384eaf1f9d7a60b8b6a5d79e1f34949f50000000000000000000000000000000001022f8a254d17e448cadfad35b7a54dd2fb319c8f9ba219874bd8280a5077301ff4332d731a75646cd93bbf31331154000000000000000000000000000000000ca1eb350844ddd0a65a4ad56e1a96821de2c6633a4a45be976577c223e367853e2b1ecf2cc40b8595ba5591ae8e40f3969848f1b8b36bd28967b762168edb451322e2f0c4b99b7f9112c9a66093fb3f0000000000000000000000000000000001f9cda056a0f8803be581634562e975223b5311f4752b189cb6bd6df1ca5e3824bbd2889b9b93da59e4f08d482734240000000000000000000000000000000009f43c25de25c5d76ee1a03691aa434de6a063bb3a1133b045797a279346fc938dd2636abf0c4bbcb528c9c28d3105c40000000000000000000000000000000012afc29245da8bcd3c0d96c4ee61617cd9ecf42a47c2ee822003af26aeb4e4de8e432ffb6b2d8241090b814401a8676100000000000000000000000000000000053edfd98742dc70d510f1836fcffa6a3ba9ffd4904c7f5559b48e49dd21071401362d0b39bc0d786b7ee2e84a76af0d957ee08a513c5e22bbec04722575a9b4f3a1343db0ae5beef4e66fbbe1ac90440000000000000000000000000000000001dc3f016ea1a74ae50c21c1955ca1eb4a911026a1e72b316c7bbdc708caef63f0c1efecbecce8901d65bbfcaae429da0000000000000000000000000000000016ce9301888808323c9baf6402d7073fb85ebcd389334cc69d7947e345748ee44b2d6aab3ef818beb21b54a19ae4f5b5000000000000000000000000000000000c49817753eb6459cdb4bc737d3710b5f044bc544c8d92c8ef138ec9d83889664267e1a5691f4bc3fa235ecca2a973a500000000000000000000000000000000074a8450e35f1da18e6de05960e21b7059ece8972c36f000bba9e24488730a44ce3ce200c437e06703addb3b442a790a8e0cf0f590f77d13819001916d2c58a654d0b9d3c47c842f2d649cb2570dc0d5000000000000000000000000000000000bc1f2e9af093ae8235c93af098e692e697ea0ab4c8f53019a6e950f7072b56d5eef6b3237710f1dd1cd1970668d06d0000000000000000000000000000000000d9a63f7a13ff9755c6a3832e3c4c852919514523092367fab7886cac317e564d57fb4042ef40e696edce868e697c45700000000000000000000000000000000129a30657466460db13575dca367105c27d631eead330319b084adfac591f5b3b94988925d778e6d4645d1d2816baad00000000000000000000000000000000005ad64d6e761a9a301589547929f4952ccbfead278cbf6658255a075966340f185d5f356679fb02ff2197468ed7de19a71a8c2a479dec43d644ec4113142e666bcefd6d729d4faccbc147effa836ddab00000000000000000000000000000000077d1e5b35c224e2cdc849c02e800c0b80d1c19f3d74d9eec34c40f56bbdb9e2b5d2ef274991dca843755f91a50826fd0000000000000000000000000000000014f3b653e0df0c608b75dee3496a7af04a828e6fc5604f16ed49c39686ec757e96adb0a667853006a8331c3d63ae4ec2000000000000000000000000000000000aae011375b337940f2a53d9091d3581e8197e79251b19c7fba01de987721a9d6fa694b7978f0abf877f46ec26147c98000000000000000000000000000000000aaffbd468a2eb86a3cff59e2e9b7ab88286d2bdd19c2e789b1a68810f0cdc76171a2661ab54e81b17643ff0275eafd72d2d59a7f138327a20263d6338d2a92fa5a2f741daefe9aa81d06f20a6fe3641", "Expected": "0000000000000000000000000000000010a2434fd3150f6b9b491d3a51226bdd457504077ef2ed5a11ceaa8284900d1b84039a34d5239a863809369bf20a704c0000000000000000000000000000000007934f34fd50a98225fe6578d3f34ae5e5ef5e104bb9cb398b2ca4f09048ec39cf52e7fdbac48d45212e9e4c1dcc6e120000000000000000000000000000000013ee70f1b52cb8b07ad957a7565b3e3c56306392cf7b5aa29047b23e5b41fb3239ac3611bcb16ba7c7ffc4213e3d9cc800000000000000000000000000000000035840f8ecf56359dc3239945720ad08702b4ea8d0fa9bea3bfb234431df4618e960a1eea87da72ba4d9443f14bb87a3", "Name": "matter_g2_multiexp_14", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d04bb9b75bc8078ccfa85e27d32e137ff5f05f9241b19ea835bba2fffc9255a4a3028c0caf9c32d3d27666e1394fe820000000000000000000000000000000013f59c3d8aaee34230cd7715a32e4a45487b9b16ce68d178f95461229a4d0fbe7d31edc7208a7338eed08e65847f8f29000000000000000000000000000000000d63ca2bafaa54e93ea54846b26f88b4c6749953f9cd00c670914cca279b794c1fb5e2664fce44b8c04f01c68698a8b9000000000000000000000000000000000b5188b4b7ef78d3662baa01b1813b4a0b0f855e11397584a460d56f594f11ff2e5d708a23a8e64d0ab337c7076872527740a826d524fdb7969776bede5ada468a0115229152907cb2b050760c18c8e20000000000000000000000000000000019bae57568c879cd743f7def43b6b994f29782c6a0c74734f35b97042a916da00daaea34f321481e6cc4749e23297c1c000000000000000000000000000000001853fd11d4688b027146a07edea647502e80750de4e5e2d105faad3f71ccc90badcc750f76f1b02db3bc0a1a635b2bbb000000000000000000000000000000000b1e45b90e6a7032179236f13f01ab664c32ee5728414ac0d6b9d79510e8c5bd0f5b62e6c59c1a3c88998bf45636cbab000000000000000000000000000000000ed16c2f88b5b8d29d7e01633e2876322caeb740251b034e5e898919f836ae73f0296c62253a0329ee8f71fdb5cac3a1d226f56bf3935ea95d976fde5790ba0584e5bbc78b37279aed8e50389899b9e9000000000000000000000000000000001455764f99e5eb0e0371e89f88bfee1c43224b9b5202746bd151f72336285556acc5ff36bd8ff87378249e82214cc5e500000000000000000000000000000000007fcee74e5335d96714e4d1a7c6f5c211b1a460efa283e0d0578c6c1f56dbd252198eebf0625362973c40d95fd890d3000000000000000000000000000000000ede26cf87e604507230ad996788e85799cc07245cf7191a6c3cecf0bfd5747b3a277cfbe41252808df6da19f005de9a000000000000000000000000000000001855991a4dd78dfc6088e6a43a64b56c8d86a0278b899bc8a1979a40a287979dee567217b006ca71374156a96b79c176c133e1989ac82e4d1c9852a6c7156a34b05784a58231d59e3cc875ac5834d5c8000000000000000000000000000000000cd032a7dfed029af020bfa249e6adccaaf5bcd2ccf33736281c4fce9c6e2b2e87fa828cc20301269d8e0579ffb866a1000000000000000000000000000000000765c4d6c4062cfbf7e24f9772dcd812f7e707f2b0ccf9043faf10018326834934df121924abb74d736b0da47554794a000000000000000000000000000000001540fa51e4580ff73e58def90a6f19557dec3c8306e2317ba0c25ece3eb4f8c39beb57741b3c4b9b8554fd2597743ce6000000000000000000000000000000000d875c822d0ce50dd638254cd4aad5dea1443813689a940d72cfa5db9309b171299ca3d69b137dfd37f0b7538a0852750fdae1b53f6442c4378774a981c90d282d5f8793feb2334470c873491e41740f0000000000000000000000000000000011c230689175cc672c25f3c56ef4eaf2bc5766ce424f6c596b40ab24fdbfa56a955205419c149058dffa4d86a48ad35d00000000000000000000000000000000078d493ce3a8038134541ae5f2a82b5e0590218a499dfd78c7a9c06b92307003fb62d6414d6c04b22f2877c3de0b65ca0000000000000000000000000000000001d53c22a622c5d91df934783f8c0cb7e370043ecaf99a0554987e6c5120a0e5f4ede023a9ad988d30d945a2132ba5770000000000000000000000000000000015b1f36a00fee95e13443c9f6e67935a840cedc7c3fb7833ece8e180991909922f59d4f4ecbbf23f16bf5ee7f0b5851b70f1de7cc5e6a2cf7dd4b6e60ada67ca47e7b9417bb5f599048fb0c9b2abf33d0000000000000000000000000000000014adff1607236910597a951ae169a7f56d6a3b4e0f44ac63a247716bbbf61feff7865d075f79e4108cda6c0731fdcfef000000000000000000000000000000000d740b13885c268da876898b77914bf4a002beef5bd2a3edefbf366e45ebcdf593ec6d9ab21e983fcae9a0832986182d0000000000000000000000000000000002a0827e812e983898351d9f03f660317d41669b0fa378e5c7667b73df299ddc4a32a529ca887a53245d7e1f946623b3000000000000000000000000000000000bf09a2de1a8ccf24a8a65dda72adcb96535ea7235de87f05d27341738b0b4ab16afbc5b37c97e255118dea9bf180ec2ca82cffdf59b742a736ae9a6d36f7840c46c20c126ec054f47ad52a22948d7210000000000000000000000000000000015fbbf7e8c26e2f41be32daee2c81390b9bc4413aabb053e3a88bc6117377bc16011e81ed167370b72f84f0e77c2b8680000000000000000000000000000000013d48a27d06ff00048b19879493a5f8ca52b7154be2fcb468b9de9edd1395750434b0e95ae6dd941e84fd6d8918455bc0000000000000000000000000000000012fd2bc91286dd46d68d87a3f8793db997ee684dec6b2de1c4202e5e7eb0e4a8a21222e3dcf80e1ae4a3a92474107d330000000000000000000000000000000004d8b71978c9025dabb3d1b1b3c7f4f13f166514b8b356fd064842269a36c6f1c07f150c03510af7d0913103afda4a68fad69492cab4ec7eb89ed37f1e7fe898ff49ffac4ef2aeb75d9c6b544109a08f0000000000000000000000000000000007d679ac21bd4634b415ef8e0e3670a8a1d673f6a4f7f3786b92d55458af980b035e4dab165a3b773ff3469fdd9d5135000000000000000000000000000000000fdb82db6e1096e73322050f828ba41b3012496a4fc4cb481f11fee338243aae20b205ee06887e28f6ba6dad00445f9d0000000000000000000000000000000017e6894b48f60b3d9b4184d58ab9554851e285a1d445b4d97cb1a7ed5a984ade8b0f62ab11ca75fdb280cc0e526108ca000000000000000000000000000000000c03b61690cdd9a4c6c83d03749db72c8946c21a944fb292866cf3a2dd1bf3dcd95743227709740ce8124319d0a540555af71c9baaf54967683f8553f72abf789da465041ee5a92c9ce1ad562c91c4d7000000000000000000000000000000000289f850c4834153f36bfc4855f89e9437a172c35a856117f8b841e5ad4ef973d3aa33fa73d8dbba4b9b2101708006bd000000000000000000000000000000000700025f22c0460613c05f8941f8a79a4319325c37c2b8f099cd910df5c0c27121a9de0e40adc7ba0fda61ea637b47d600000000000000000000000000000000069e17e00d4d726e8eaca8235c88967a7c093c70e5a46b1863ad097acbe233554048838a0a486a72cbed7001c83a27db00000000000000000000000000000000016ce4afb84c1a9e0216f23bcd2dda0bbada6a4acca78e1e0d765a5290f6f4929f6d0eeaf1306fed3c9766ca7c7268acc7effc9a7fe773a420ca430c58bb94e7baf26b9a97b618a15e7a18b31e5914f10000000000000000000000000000000018ca46a89dadcd3b54f60fdf9a7b97c95b9e0668ed9329bbe4121e588a1ba773c9d086dc35b699d65487f428c00ad8c30000000000000000000000000000000003ada6835a93310d0ada01bd7fd6778bd07e718d1ce05aee2b4990bf32322fa94ca898a531ec6e3b8cd7ae3bdc77e0b70000000000000000000000000000000004a8abd2b9f7449213e63ecdb435e5e13fe2aaa31a2c38673a6adb5e96f4dd383dacab391787f6c17579c78a1cefa5450000000000000000000000000000000002a8768d98ccda80149a767e9b5a3b0bbbc0ab4b5f696522c8f1c664f1d27f2f0a6690531672ba2070355c0e77095dc02d5a3d0370f4a58c21016d208609f1d3e7cdf43abdb85199bfc67dd12f589b8a00000000000000000000000000000000048fb58924bd5952d3bd7b1cd57a1dae6c1034df3a420c1151737f88760e4b0e78fa3f891a0dc32fcb50f89e67b0f08300000000000000000000000000000000073e9723c80eae7685db774d3e2bced53a52f24504fc3aff98e2becf8d59c6e83373ed024ec1ca50101d2d613abd286e0000000000000000000000000000000003b64c8e9a1341bc6a444a871843b3add7dbf04bd1810e1d6da7d31c7c2b7a264c362ac9a366dc8d93bcd9392c6056f000000000000000000000000000000000064462d424e54f50e9849a2bba1b0caae966a8618fda0f8965b1a841dd2173872a44a18ace1e2aecc8e3546a9558d7013549b86ed3fb880269be22b9cb8be6f24385bb5e24bba81bce9fd5b72ce2ab71000000000000000000000000000000000c40c8da9281a8b43478c28b2fe59a3cbad0a818e2077d40cfe44624dc2e46f72d4489cccf63eb8460d02f895e78edf5000000000000000000000000000000000735d768f6ac999a47c88bc2f3375f01052259dc69011480e468d8963ea8eda74726c4ef32c8feba52878eaf5c0147730000000000000000000000000000000010adb3ad214b17b963586a10701934727edf05fcbdc94d98255632647d73536decd0c91363840e1b55f29f7d32f650410000000000000000000000000000000019349045e6fd25960c03336888679cb53409027f35a1f211b40d24ebf724866c085a978ffa3a91d989da1a7902bca018c8f6dd56906fa13144dc87c31b53186b0683cad220ab2de89d2fb515bb269cbc000000000000000000000000000000000a5d2dcc05e218b0633e0a965b6d69a3c6c1c7837e1fff7ff75cc9ee93a112f8e34cbc95bd9dd8fe6ed22f2e9221aa110000000000000000000000000000000017d2e5d2c0578b1ec26b57c3305b209c979bba6925756892f031a7462ec44e8a4a2527e6aa2fc13bae91dcacb8c7a30f000000000000000000000000000000000d437edb45ace50700db548db68b9e8376b3039fa00cb98dd00cd197c14d0f92c8a3945127c43b10b34bef7894fa43410000000000000000000000000000000010d5a2e442a2eb35aa85fdaecf094c1e1f307dc9bcc540693d7206cc4e0d050ab900f17fbdd0754b59bd2aae705c60149ec934eddc44729d05f193ac927fbcb022288ffb2bc7d4f46d1bfcc7efacef940000000000000000000000000000000016c36464b426c3066aead1aaaf65ca637e93279e8ccc9d838b9b3ff1aa7b896f36de506efc2b0864763cb6ecca4926f30000000000000000000000000000000006d88d5764fc854ed7d7cf1c0e210496ce347bd887da2a149a09679469e98c453d85115afdd2fc4987b64a88c4a6f0a200000000000000000000000000000000053edcc0ca4c205423ee6a7031939379e552bd2d2657f8f25370c9f0ea0a947e77f18b5f218f98d12d720667844f3795000000000000000000000000000000001292909190854cee4499faa602af99dc49d1354a71278b439e983bd89e6c504fa5fcaaafb6ea26dbeba9850bcdfc1f69bd211ec887635ca841c4608fd00bdc0f5fd0f6365dcdfd7d6f4c36f4b25b5b1b000000000000000000000000000000000997e79a7549ada9ee0233b3bf9289df3ff797595f4b5eb2e7dda6977ca981c1c4a2b91b924812b95418f1b1d9d0cb830000000000000000000000000000000000256b830e80f238e8494387429d727a91cf5d323ea87f7dc143058c05e11858796adcdc677429d1db4dc2415cf23808000000000000000000000000000000000cab529c6b86beacc57c874f07108d1df7d98fbd59fce44c48afe9eb2dff823f4869b620bbafc121b4ead2cf244974de0000000000000000000000000000000002774906c1a0acd87de224a9450617db37f8f36a0a192f5daa2774eff0b73aa79b4804342999df761f8572974c697c6010bce61d4e35770e7737636c0f9a664eefa948662d3d22d1f1708fa48d3043de0000000000000000000000000000000012abd02540073017011e186586023adfca36fae454350b2015a796b7991eece65b63964fcdf581b4b51dbd7ddd506ec3000000000000000000000000000000000ccd3f2d9280908d4b30e924e4a862810a92e1a880cb56e842a94a2a5120956e8713f548ca279d66d06ab23e4976e54e0000000000000000000000000000000000c052ed00fde2cab515694d8c004de910e62d07c462345ffcfbd3904a0171b970bc58d99c5833059315283004f3390e00000000000000000000000000000000008fc4860366074ec0c7aed2c6ffae7c93ae0a81067edd8911b4c53393ebc0f23243823aa7aa2b2e987cb510f6e0a55a65c86930c1d142985bf85ce70bbad170947e850e5c6ac7803fc45980dd37a57d", "Expected": "0000000000000000000000000000000006ced307065868b6d082bd205bfbaea3b0a8cfdccf831bf154563b5a942154622b0d7689819b337479480d19aedd85e4000000000000000000000000000000000c0f04fbb26cf85c2c22763f3e78fe255d8d1f45ea47232ab58f5b785ad9f2458b0b28f3cdc25c4dfcb47d59957ae10700000000000000000000000000000000120e38740eebbc3eeea9beea483e70d6a9c30a5abd61b86e5f94bf65ffb40fb92c8d246edbeca425ace175f79c9c8afd000000000000000000000000000000000d5a503a26e50f9be34c2e64e4a80402ca6e17f09db1b334a9c1f6318f3e7e63b3847a7ca38ae6aa7c96ff94bf5de842", "Name": "matter_g2_multiexp_15", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000036480931a5a585ea54b6dbb01759eb1d86804e3f03326188c71f859613722e662c453096431171a49eecf8653f14d470000000000000000000000000000000015fcd6a30b9d59a90d8595ca1758eed7d6810d2916638dc2cb637aa09b16b5ba4920df7d21fc0b923453a6c7d32f056b0000000000000000000000000000000019aa4d8e98808c2fc1273d383e836876b087ad5a7d01743bded01314bc62ced94052d75d312a18839c1b33faa9e2e5160000000000000000000000000000000015747ce0f1171c0d0ff1fee9dbb2e5673b9db0b0c3618cc8bda474f378db58ea42184f907593f3d6fc2fa215cabb7b2308e559e394a9c1ff07a45bb3e022f9c212eea4ee5b77db1c5b93ce72c0512b79000000000000000000000000000000000222640c1d64948daac3ff93e86ecc96bcf9c93559266529a37ef1372a81952431673d69f1220e07b8aa0a4f3164c83b000000000000000000000000000000000db593156078821cd0ce0270e8a444d0d204dce0583774496620bd4752839f3451e505aeb3db568048739c7e71d279b40000000000000000000000000000000019932ad2c7e857c2dd51f7846534050b9243e388260cd47a91444fa050a9154eca88ab4d29a37def16d4a11d35683f2f0000000000000000000000000000000004d15ec653a72256ac6b616e9870b0acc7d46286893c0eec523dc27bbcf5fe596204cbf83ce71c2690af67b3616794225e55826db8d12169a31ca27beec80554954f522b56f7994c62bdb527c2438d5d00000000000000000000000000000000180622bfa9a1c452f343ed21a3e9c6fdf76589cebfb9a3f0a53782a3e7c9d066294e10699c386b5d0525003289f0ec580000000000000000000000000000000006615ff63c856302dba6d4e25d1070fe873e0c4950ee5ba8bbbd4b94ceeb181f1ee450acfd22f21010b88f0b88375777000000000000000000000000000000000cfd3940b5eeefa92d775792affa34371d13f3098ede3007e06510344ac8483debadd5a2baebafb5ddcb45a9449768b200000000000000000000000000000000145be0107a1e3acecc89a116668f9887579ed7a72abed3f4236930edd3f18974465c99ada86c4980c88768824216170f1362e8e39ec661cb3c5af64e0001cc94701194344a7404f1ecf7df0d5633eff9000000000000000000000000000000000820e74e6d0333b6b36590ebae78960d019065f1681ce68a2a01a2522496c840c668575a57f9fd0f50b87f928a41b0de000000000000000000000000000000000dee60d90e96019cf2bb552d016419e92dd358ff97039a61838b0a89ccbbd537f2b435cd11f7b6e75a4ec6675964e7fd0000000000000000000000000000000002ca767de9fbf8af7c73d41a07e1c0e38e3fc971472e11928b65393a27354b2d732012dc57f498f94c0b933565a7493200000000000000000000000000000000134fe97b24e153f0e9a27d3fe7b89999c6a19e353325e0746ead013198b8e00ca6472fcbd2a112aecb9ddf671aaedd9174d3d66cde7c4c8a4499708a0c6f7c4da458eb970b6ca87e23601c702365b6de00000000000000000000000000000000031a9c29323196ef31030ba73827d228e56fd5209eeef0803a189e0c0e5b186ca1f342483eeac99e1e1b12cf490856460000000000000000000000000000000010deea45a01370602bf57a1f81413e8d3b337d7a1a33f9525e4ff7003454d1da2cfb1a9b42c4a654320f91fe7d04b6200000000000000000000000000000000002bafb7b7452a173a3971c2ba1768061a043307d2c32767056f18c1bf8b066176937876a87055e54675876bc1b2d2fc3000000000000000000000000000000000b5c77dba3b4136a7efaa8c2e28f39e88afbf26a7313b52ad6e390da4d948209d96e39aa08eb52200dfb890d7e88b46a389e0d43f2006449fe2de506dcdba4cd0e6077e2228f7d8b6ec9d8a4129c494f0000000000000000000000000000000018bd1ea5ee8e39c43d442e9c6fd22706e582cd80051f18334c4db2ea91ab019f54bc0074c8f0e52e50367197a797e7520000000000000000000000000000000005c0bcd1b047fdbdff25b138248bf4da4c013beff7dd3030c348d6b2b8724a147cbc44d570db5c4b273c94d0b99bc2290000000000000000000000000000000018e033935c20be5940863f7e9e39fcbdc29ba031e58c10beea90cc48e9da9988fdbf108bcbd87948058f386928f81fa800000000000000000000000000000000107d179204db7b288315e8aed7b92ebfe53b7ad2366d5d7944b3df68d9d9faad023e477213f85214047645bc05fd4cde5f8dc332cb31e43bc2e551356cb8d1533c6e567d34622667e7e4e3ddef352f03000000000000000000000000000000000a7b364fbd3bac7e2f2e7ee501db2d248bd73a76c2a12a3e51718b56ca9a8ded14b83b8cf0b5bd46f0c26896a65fdb15000000000000000000000000000000000eafea7128fe20ddf740a6396bf18ff5f2652a0317ea9b6e934927c3ee95b59c7dcd51f7c895b3989d40ae5f78ca508f000000000000000000000000000000000bdce57be904236a8df532c2c0072165b5cbd4103e9061fcfc0a45a67e4b25d11b9f816f63fc0eac4d6d3e10d2764c4a0000000000000000000000000000000012419f94ddbd8275054f8f89fdc27a74afca2eef314393236fca65705354e5cc0a470818999c96b5087997813823e9be0dc7052044251fd360538fa6d5dec9fcee53faf2f07de5d8df212d04f968a0b60000000000000000000000000000000011e4010d0cd7855a92cd5d4954ad735363c0c2ab00053db5e078f34e772969d8c492892329cb95ea8893b4b7ff7aaa5e0000000000000000000000000000000013badc54d90a19b84d76b30fef8e3ad2cb268204fdaa50ae951b63e48aec9cc6d585751dd48e4a8d4659b835f38f8da8000000000000000000000000000000000460728f686b9b15cc19ef135af71312e174860284c3f0e7a84cf85a5c934e2bb6cadee8e482d88afe788a796605f79d0000000000000000000000000000000019a50c06ba307d83452a30fbd862270652cf5c7a09b150fcea858a8102ce3b1e9ec13b6abfb323d63d2c4edf209c7cafc579dd4f361fed9084d9c66a3ec4c6af5293710ba5299df3abc4cbaf5802b5360000000000000000000000000000000009faa74f66ec0384f0458893c0026f73688c764e8df9ce056a88a2ed0b84ed8f88d1b683443a3269a3db838f8aeb808a000000000000000000000000000000000949c4be2708c1aac86aff39290ab6a8e0f332e7a098bbd64227a175473d9dfe136e07548b282f69a94a15e2c32dada10000000000000000000000000000000014f2c7c7da781e2f50803e3a948381c3c439b127949f79824df1e5722c206efccd6c0ec5dd75ef63d8b1fa301c83356900000000000000000000000000000000176753460d241f38aff41bafdad51688ab0dc9a5fb3643977c7b9d282ad4532fcca1e725715227780ec28bf1c32bbc1d69f0f3c3f516ae34fbecf45f4636c22acffbee765952b332c0f3d8cadb9c93f10000000000000000000000000000000011982264c8c078518cd0adb05034761224e9063654904e06fb5e5a6eeb1f45e4ff3da661f1232693b79336215dcc0cc40000000000000000000000000000000010c96c872160d2de03a16e85f2828d0cf2dd16a3389effacce46b5b5eecfea1042a77de653da5a1c0380a84c435723fd000000000000000000000000000000000a4ad2d9956bd407c555b26c192c6bf59bf89e40d9c6f9c90780bba313a39db71a73e7633397d47a3f58f61c81edee77000000000000000000000000000000000a7f912530d27a7bf74e01d8e48890cc66f72d14950554991ed1edfc504062ff6bd3cb6941bb398df9fde3cefd33fc0676618f1954730111e572937cf0c9f7b3298a11d18cd890cb419f732c766bc6210000000000000000000000000000000015bc12aa9ecf417fa5bace8d9e5dc4a418555eeddde1da8b624bf7d6e1873ec4a257d5f6dfc058a8d9b02528e699abb70000000000000000000000000000000015b41567f8c780f83342449f27094bc20a839602ae482de14b92e40017e7acac8857db48a2d27f1f1a625883b6e5255e000000000000000000000000000000000cbe79ac0718555fd8fdc38b68eec8be83b32499d2654be44888e45a2d610b0e81ae12fd56550524ad85b5a632db32ce00000000000000000000000000000000069f46b5baf4357d8010869685b3828c0dbf6e2338598c9b42dfecf0b22d803f95fca716115f74c77778d414cbcbd881fbb9f2400ed1dec7ea63d2b26bb3e9c2acf70117e3026626f6f88a07876177880000000000000000000000000000000017ada4038189c544902167be958e43ee133730e5cd329e572dae2d853b694f5ff8032bd9ab41cddd11c51e8284970f810000000000000000000000000000000013eef75e6d28deec945ddff33128c199fa52565288d63677c824b8d56a6c29eb98d34c5834e84865be35d40c1c59a40c000000000000000000000000000000000e2fb4f9c7ba6bdac1d4ff5055be609abef7fecd7923a753a704da537c0ff41951552420bd78d14cf972dc84fa3f5dd9000000000000000000000000000000000805376b814b8a59435310d49a43081dd7ea36dc7dcb40d38068ae9085b3ea9a3b2249234234cacc76724d8ef84a2eaca0170d7b7604b8951a95d49b6697e2d0cd2a41c3671d8f96e936cca911dd516d0000000000000000000000000000000002288860f2d671c84c5239313b7f6b82e31c3976e6d310e15d3bfe1c566e2ab5d86ae6ed0df02530f9f7893ba419f1870000000000000000000000000000000017365bc096e260f8dd7b189fabe10eb66923783b41fff70a149251576b3b465c13230dd0af13cde562751dacd8298335000000000000000000000000000000000fa8eb9c818df27181b45a74b333ab481dc7212e417c4e12634816f9e177064f9e1101deff26156d26bc6574db9617080000000000000000000000000000000009379598bf02222e1ec37a721b9ea31a3adc33524c6a41bc58da06caa3da3bd730659f0a80f793a0fcb9c07b43ca929c2c2afc06f19e627e9ec0edf1083823d30ac569346040965e1c92e0c15011c90b00000000000000000000000000000000136870e08ff5fabf36410629ce5c23470eafbe73a7dceb633df5c1492e39445b86ce15c22bf4c421cfd0adc6518e78c30000000000000000000000000000000010aefa3cdf1225da09b796430d096807a83eb2fd5a58db3a4bfc5e500dcfcd472fea3077f0c059620f4ff708f37c95a90000000000000000000000000000000019ee2c62ff860338af623c535979ed31c42c0d0b2f82cd56c153e80e6d92bec9ce39bc8e8f285d1efd1c1e969521dbb50000000000000000000000000000000008ed69eb0a16c8a35d507bc3a50bfc97e18143fef611263715aacf5400cb1aa285b6d2ebf2ec219d2fec477360875a03141d0ff346e46a20c2498a74f910e9bb2d5d8530afc7ba47c3525861c9e8c5920000000000000000000000000000000014abc4eec64f2611197d0c1322c3248eadb725049379e64682f2b3d7f83f7bcea11358d88f52711b3020924b6ddd84790000000000000000000000000000000009fd78c5d1d2043d83be30a88f046f5b633c6dbb11bab25fa3037bd250b6b9d9394327aae25d1939f777fea9f3df46960000000000000000000000000000000010f413640aaa16a95afba98660f9e1b03a8f3e0a7a3d7f2b971f71b5e3d09016ac2b410f97d20471f48621d5a363e9e6000000000000000000000000000000000154b5df93298a5a14a6157819e38db33ae7f2d11dfd13f7f2a92b2fd9b053fbd25f10a8c45db3026f6f583bd56eee0f1d688a1aca2a837e0a353039294a9988a7111ac134a6a8a68e4f881e7486025c000000000000000000000000000000000f1893df99adeff5e4042c4c5e8557e53f7c34efcb2a7953d5347f81d2f4a75ca0273a3845f54e795ac1c1f8ae7240dc0000000000000000000000000000000004856b05d58898be6aba07fcffe487dd895144c7ac8fa8bb1a37c61e73bcd062ff541d510e24c5bf005c8351d3ddf61c00000000000000000000000000000000178b22c2c698dbc4929b119474a741ef44d6275fff5ba058d9debe9475e71398e464aa14a6712c5deeb5010d1c7758ba0000000000000000000000000000000005ad09389c35c45f349e6dcaf1cdb3b63648b3df427ea0c2a371f45634635f9253957ba6987df4aca6cba4cd472308a31b59c33ff02791031e7a9424c781ff17a209d132af06f5b825df363fbd902cd4", "Expected": "000000000000000000000000000000001090d83d501373cf07c75effb1c85852019b39eb0d77226823aa3c1054d4e408e82fbf0f4420a30144c611fbb856748c00000000000000000000000000000000120a1e3795f6d5c4ed5b886256c611bdd209677f8324b7091cdd7cab11788b1c0f780e8b4c38b84d7c2ea528123d4783000000000000000000000000000000000d250df34d906ed421eec2a78c2ff4ed4eedb717358d7ca879d58ff5b4d2d72521082dba6ac5d10859125e32c2c8b490000000000000000000000000000000000476adaed9d80cb1545be505496222dba1f0ea85d38d5bece0663461e0e9d47abbefe95303c926db008d08b8aa162e27", "Name": "matter_g2_multiexp_16", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e1a9066289392b0b0b8f0986366c2975463c9cbe7a74f2eafcb3b8b6d4ee3226ea5886aaae374341bc76b53b165e22a000000000000000000000000000000001557cd01b61b5f2361f6b558a87c67f2778e11c21734b7ed25f72a88cc62cbed396d583de4c2190ae6bbfd096c33bf73000000000000000000000000000000000eab68305118d7e7076043719ac1e13ecda4497df2cf392d6aae4b7753f114d30aae3e8535742947636901feac4b620a0000000000000000000000000000000002cfe5014446556b82d60adf874cef25e58eabd035deb4717c93bf0361f37a4a67aab70b95627326bd97f111efeed57f58fef5bc887b7caf72f2a533fe1455ae523841bd49b4adf16cfe87edc6f573eb000000000000000000000000000000000c8fa30f6055357f6b697f2115203428b8005ad03286d2b3c805bf3d4dbb461c30e6ee8b0973ef41f884b91e857c53500000000000000000000000000000000005e1c785feb4c4fb7e960233d431d51a4fe471f10321251d018a950374d2a686d52ee8cdd855a29e770bdc1bc565f471000000000000000000000000000000001158d31faab483832d39f5431a5d8aeb952d6a63b82ec019f235b5b2e5580df8cd91b46cd53d4a90b9db354b38c5a1710000000000000000000000000000000004a389b09be6fb7ffd14d7f3359b17991e93d92a1c0b9a89faceaf71f5ce77a1875aaeb7a0ec3b2dfb363c47dfc9875273b243b83d44158a66eb6d31e7c4ae1f4b3ddbba81b2cf9a654ca7c4ea2147ad0000000000000000000000000000000010587118c5f90b545ee707466ea2c5f378e6795c260235cdf9876aed8bd753aac592ee05e23882ee77f4a13bff97f5940000000000000000000000000000000000a0344aed244b90c4fb9ac337edb01429e09f951062b06025a5212300f5471a95f28e09bbc715417a6d98423b518c3a00000000000000000000000000000000128457cf374e5b8864b8241f476da093f48553d609a5f30c0f0f235ecf7127231237b6c8802f2904a8304c7c237842620000000000000000000000000000000004d55ff04eb09b33ebfe90f2a0966a1b59cc224215c0359a4ff0c09e60f9fe7ad8342868184d8cfcaa1d8c28328864241ea87af09f6e62111c48993c408efd3db9ebe218ac68f61a461ad9ec1306873d0000000000000000000000000000000019e6992c3da47715bf379a668a15668508e7ad27bac647490be8e82759b9b79c996735aa1bfdc3cef217750e4ed36fce000000000000000000000000000000000828f782c5bd4f2de3570a4930db2c020f75f93adc98aa0e48449d29c7a3b0d5c349963d956bab7f985ba6ffe59c90ec00000000000000000000000000000000062c7a730d286e895c57b75907713ebf1d20650b5e621f270f1d22a2ca480d022346def4102a62eebe867210e4b6122e000000000000000000000000000000000d6c29462ad449ee6cd122e3dc00d56dd5caf17a2510e5305aecfe85626cf73adb401ec2192eb693158650893fa67412a691b9635e38a46e2469811405ef6325ae7ef88a67c1d1c5b05806da329f27e000000000000000000000000000000000098de9ab41c289a05ba5a774eafe27d91aa8272fe9f81fadefba9a0cc0e31de20f808ff454a8647c44f5aa632742af9e000000000000000000000000000000000c96019bd5cdd62df1642656f0832ac8ff6aab86f671e18c1c7023dc16b8ff54a8e3e446b19682a23b73ccb90da2fdf0000000000000000000000000000000000178e3b4366b2517d4c19fb40551be6979d46319d7040682241b046f10ab88d269dfc097ae02952d46e69cb1cf159da50000000000000000000000000000000008341bfe1e2fb999f0c3f4e79523c720edd332401f9dfdb8dddba8d1342c2c1fb20ae2fd9dda92c7bde5a0c95ad971f80d9a35f474325d0f065442805cab3beae4a186b252ebae54a567dec6695588f1000000000000000000000000000000001004d60af8c21f7c62fcba1c5c41b94fc77f64b89abcd23a218f0da8f47d2ae6879ddcde52f3e6feeae2dc7b2720577d000000000000000000000000000000000b8e8a7da87aa62ca852e2984b0f12b85052fdd03883f01f4496df0835d1cafa48818b5ff1e3cb0e9ecd66054540a0d40000000000000000000000000000000009c16854580ad8191e3e80a0afa8da759a8b2bfa7e0d556418b5c96d97e88a12fb75a91cd68c2f4336c3ed7ac99199fe00000000000000000000000000000000195ce9c562c460c7e715908991ea8b017b81561b45133427f63cdfbe8f65202bdc8e8958ab0977b3a244cfa32fb35f37c20e998acda67d406a238f16bc2b3066a6d69d2436577b8900a180e6a71b0a01000000000000000000000000000000000107292f77666064b7d80d73ea8f3b623170ef79ccc7c228b8366675a422a0cb8491586a2e4ab1a067c31396cd670a8900000000000000000000000000000000126f8136dd61d61b2a9c0f4af3ed44a3cec3ccdedc74821f341d200601a7bf0a17079c824de6cfe28467e843d0c74d2a000000000000000000000000000000000bcec8afcc7ee56b36d6d08b51f61454c8fb15ec5baee1117ed55af8fc85f68674250334f79b0fce632e75623dd173210000000000000000000000000000000016624d64660b63b70ed197f6a675911b02b0bc6f880348faa6ce4727af74127c509ce8535d8dc8db5ae2d71aa497e0756fb773cde356e2edac3afd2bf703b59161162dc1e915873ecf606dfc0e6efec5000000000000000000000000000000000f57747c20e1b3923c7e1d8bd7d877736cccc0e0829837a086d62d48cb54f323d90b57ca3339fe4b256df529bff11363000000000000000000000000000000001940327a1b319dc4212e7a553d3f49904660722c89636f6a38604d96771fa0fc71f57674b7aa710db4275822c2b89903000000000000000000000000000000001956b81bcf961d16e50c053ca07ae67cb8597138f34a9dad4d82e0e8d23a7e08b751682d588f229311bc63f9598ef448000000000000000000000000000000000208981064443e8c72987945e399b45b74e529a0bb75e99b7d6744728e5c182a6b0a10e449147bcb0b0cbe70edcdd845bffc1a58dd06752a2a77abab835d089599b4781ae51ab998ff3c5b68329068bf0000000000000000000000000000000018c35ca3a63053fec853e8fda5920b560f1be28431f2f4b08789c7a202336c8905a5ffffbf69ae4427f267b1e13288d60000000000000000000000000000000019de96be76bd93886cc486c2671b5b0d731b568638b1b830a52dd4c481b9a1fbe2b3cef14b46e25f1188ddb3c158da6e000000000000000000000000000000001813ab16a11c79eb3d3d47ae7d9a7c05401ee91eb1183266d23077ec4c0c8f3ac7188eece06876025dc3fe271d65d4ba0000000000000000000000000000000004d2a416dc874e956fd6d29a3fb96195019f4136561b4c127541ac171b5a6b229746af6d6e535a8017e64ce06709e52e57f35cfd74f62fa39f919400f4d692855a4b4e9f91920e4306ebb2e772a484f4000000000000000000000000000000000623b7a8a1c24dcc603f01589e6679c74c4ed3452894e536a4cea69e99047092acc877dd0bb395b0cb693cb1702a64a00000000000000000000000000000000013de9dc75e42f12e905d729a52f25bb1a4125f5edb435734649281bdfd41083716d0797b0a80d842c2503d09cc61162a0000000000000000000000000000000006453c06f56dbaabd4530160bcd5312b8a148dbe19fdf9f1e44b7b047a73ee9ef9d981116d00269942ef73537885eb7a00000000000000000000000000000000075376135ff3acaecc0eeea32f8dc15add57e8f0297d053ffaa0fb0a8fc4418c5b142f96b6b9ce9eee2f949c960aed682d1f3709700634653374fba5a94d69163ef616a72a63d462afd9f01c9ddba84000000000000000000000000000000000120d088fc12210c1f5f6cc3d1091563f9a37d4d0e0d2c305b479f4d7e893c4d5c8170eb164e34e4843a21c9eb193d11d00000000000000000000000000000000159de80db3b1f0ffc5fa8c93e1bd54cf8ae19cbc9018a5dfed86179cdbc976c1c312212080ab221806bbe142d496e7a7000000000000000000000000000000001103abb75a78220218cde4bc4c59ddb5fb647ff808754dda200bdf586ee9c47a09e03762bb726b085928ddcc998af3ee000000000000000000000000000000000bff4bea17eae0f2ff3e7f99bfa91e6ae8aea28f6f3fb6080eb644861defdefc26befbb7874f612edac0cecf70dfb275614ed9a08dfd406df00719d5eeacfb0a96413b608974fd0aa1d4c6176b968dc00000000000000000000000000000000012dde607a2d4452c6c060054c8adb6307743edea3ccb6ac34c275717f177f0e454d9e33d4391208198cae39d7eb6f6c00000000000000000000000000000000014cb4d8bc98060ee68a8ddbc44b83db5cb6d09f09b0d608357629251c35e44383e97058d0d68fe2df3bc47424a5dda03000000000000000000000000000000000c14fbb6c844fbf896fbd3cb3464a83aa4c6e9a7f0450ad96a07527df6f1eeeaf587f60a990bd6abe7aeaf5eb46f362d0000000000000000000000000000000001d9468774318ea711b79f16303ce86288cee312af296f1c9f607ef5f97c7d1cb48a7218775c8aef00c227ccb586286e7c1dd2e5e5f630fb1d07e8934dd3ab029917e7775e401c0bcf7e1fd83aef728400000000000000000000000000000000181e7f8d0ec7a4a7858bc96b61484c24dbb9dfeb3746fd3a231a8e442369e3e83516ee6043b1c06e7e2043dc86f6c75e00000000000000000000000000000000184c1d667c0ece59f18fd2eeafc66f1ed530b7d5f4560a6c886429caa13255c63dea01c3e357e3408af58a39420a8b28000000000000000000000000000000000a8475ea694cf607246a1c50064cf90cbe50ad5cf8006934a1fdf1621ba38d20e70860a2b5aecc05acc60943224cadb60000000000000000000000000000000008afa03c2df8e83fb64523c57d0daa7cfbb7af6a4bf2960ebc64515a61a659b2c37ee661050cd538fa00cb34746a371b64e9d16cb61f2bcdef30cf544d97e078fccb999b96a1da0eeaa0bf232f01995f0000000000000000000000000000000008b33a297c8f86f1e9d7166f9e905283c8e1581e582b879caf48585d0bca3608fe46d8d9f6e7c90855aee9d92283d7a40000000000000000000000000000000016962410d6b4b6f91437617e84bfaaba49de0369b8748d2e2dacb63b421e0d7de4514e7fd3e0dcbcfba8baa4915610d0000000000000000000000000000000000efdab72953b870d0e113efa7c183d99aefc100ce59791aabc72423aff70a5b74c577c06ca94bfd6a7722199b4bc22660000000000000000000000000000000013b18e31700987dfa4344384f9b41e72afe92c39bc961333cad3e7d0a5efd3842a5e849cff5655c4673f720fd0127dca35bca9082d66c06761f702dd439faa4957caa70ce0343268787f41a2f4bc0cbf0000000000000000000000000000000008b86f70c8d8b03b0e9a8975776d7fb0d08f95eded0a0124551d363c2df57124e0e89bd45ddd1cc75c258a4ae2f87916000000000000000000000000000000001120eef9eaff7c308b629deafb060d2c12b20b57562007fa810a2191d99fabe9c7d3c364caec1724665ef556de66b57e0000000000000000000000000000000007698bbef6dcea67a2c643342ab2a0f830c329fb6244d4a98512daa8a3c9d808cd2acc0cebbe3da920053ad73eb7cdc7000000000000000000000000000000001155b6beb28fd88d252c6b407bb9f55d22103257287ce77353bea580c90173b5c3d49080b319ea28817d67c52bead96f7980eac6c8db86ef83748d10b210835e53baf8cc9f607915df272b6e28ac6b2800000000000000000000000000000000142b28509d72f9e3be9ee916827fc1a8dfc4ef7ae2b72eebad5db605fdb2dfa4492b50cc3e472df1b52baa6e2b0eff5500000000000000000000000000000000134d6821088ce4a8b42383d5a43a32bb0cdc96c85f304a2601292670633d5e231b9dc479d199829a9ba9f39c162318d5000000000000000000000000000000000636da344fcb0fe50ff3e22f8591418f64cfc722b2860b4a5047f973f42e4cefb93c2f8eb8a14b4d150758ecbf3cf712000000000000000000000000000000000e6fd06d5dca702cc9f199f7583add86c82f7b530d4dfb9faec36dbb669cf7c1cd1260c7e4f3026824eeb5b979e9fdaea256ebae4b204b3888d7bd244bbff26431ab5890098870f13800bb3be3e842ca", "Expected": "000000000000000000000000000000001684f447f8929ec0187811f66e985f0014eba46eaa87de2d4ac2347d10c0550e4044ec7792d9f315c50081dc2097ebdb000000000000000000000000000000000ee0c46efe930bc98f39dee8cc6a792744e84de4fadec035d25ee8ba82e1c53264d0885a1fb05b2b8dc9c6a1846c28320000000000000000000000000000000003a5ef98843099235a2ad9522c9cfce1908bef77b45794e7df9eb38a4854460031829e947a118e8160365fbec3725b85000000000000000000000000000000000dd205e195abef6a4cfa7da66f022a418235e1a1b2fefa6bd3ddf8a3851d8ca8c27652bf87ac644cd189ae55e3cc7808", "Name": "matter_g2_multiexp_17", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000064698182f90c20ed6f6da7248cea32a291f901876a900d344ce4dc1b07822b480519cb8d891b5ee4f33b4efd90742cb000000000000000000000000000000000e7e9d2e79ec4b07015baf69a283f6a4abc8d7c1699f3356fdad6ea9b1c70e41e73bc14e500634d73749f9900eeb65f5000000000000000000000000000000000002ddbf40619ea5123c100e2d6553213e37883fb34f0f0f2124795dd971892d5c9051cd4aa78b9d20f196301ca9bb4d0000000000000000000000000000000017a07b32fbffdbf7a80f0437eac1ec5fff5a68f3b053482f034064992158b604bc34489dfd41a24ffba806ccb871fff15805f2e8013007c4f6d8abf441728eda8d742ea2f1df545f85d092f50ca8275c0000000000000000000000000000000018b4de9c04fde8b708408efb3aa7f24b5f7bcec14e7d06fd5a5b36bab528e5adc0bbb1e378a5ff6fcbc95aea530ffc6a0000000000000000000000000000000010da98267770a47e5ed14ffb3dbcf537dd14ae5eb79522c772a7a2833be214690db0b4e86621de1842d88018fc0f348400000000000000000000000000000000135548e2eec9ae7c3d23618d8286db13a5a628fee04fb6ec9da980f3a46838899cf965c1cc6f562e71d5b5c7428cabc8000000000000000000000000000000001669fcee7804df9b7bef32e2ffeaf285e8501842efe87c9e827fce872dffbf92255d3c3a2fb5c382ab7aec0bba1ae0e5502d777b25f3112ba2264022e2f28dfb6e5d5239ba097e9d815928be44b6a62a0000000000000000000000000000000010ed20c069bb300a27571adabd239e70b767af90b91c4d0e93d88278a6da47b7c12fcfaf62ac0a7b9966968cc9f3770b0000000000000000000000000000000017273eddc25cf41f2d7734a3866711e83d4f2823ee6a036942799f837d5ceff10dd6022ea25e3c1e28c7b14ed8f4e7c5000000000000000000000000000000000f201f314f66f6b2c6e1365c0fac7b187d31bc45b5edaef5243b5488e26581dee24de4a5fe493bee44165cc31d8d72ef0000000000000000000000000000000009dfbdd86633edfacad6b78d292141a1e653a1bfd8c48a96b2f6bf8271ed6033c0511628caf2ef258eb64cc8b63d8e5be7d64b471cca34ab0c91f61ff26719c7186dfcdef13895d37ead407873736a740000000000000000000000000000000005c4a4a5ffcb4a39c8809821ff275360ff937070cb97a791cc9ec45f429256a6d2d6127248b6ab0b6c71c30c4fe84ff20000000000000000000000000000000019fa60f481c5be953c9c7dc86903a89af0ca2b4205be3a00d793d6de7103852e147ebc7d983c6d6e8cd99e681241ad440000000000000000000000000000000015b3b2eeb0f81ff8a2624e2ff2396bc69feffeef62b1b6a1e73ca4b9e60506c2950fdd23a37cf56387b8794449d3237f0000000000000000000000000000000017021a69ceba3446dad9fcfd8cbe5b89b61372f57d43a8d2e2c8f4534bef6b91408409dfda9438f24526f7e6bf1f4240e5723630020fdb48e44adda735943c91ad7d1e12f3c32d823833eacfcc8b02ba0000000000000000000000000000000007c8f07f22a3412fb4638cb704751959cda4e42e4612edaf5b1f22c8f9ea314508353445114bab6c07ccbb4b0d0bfa6b00000000000000000000000000000000062d087155c8722d0102c8e5084f95f5f58ed626d48197297d21d2108ee05f70f16d595ef73e8e1207a3c0b013fe16710000000000000000000000000000000003b6652934f3acd4c91c6c521c2476bcd2594a939ff2e7ebcbb0f451fcf0a656a518dbd4f36f165f9b2f58054e9f778f000000000000000000000000000000000bbf21158227e0ad5461de9ad8bd580f9e65327dd4e23f1ad55618f6b0aec45aa6076fa88557953ad15d385a074bc7d96e9e37bd811b76133c12268d325ebbd6656e7ed718cd777458867dc98b1b3bc50000000000000000000000000000000019e336d4d342f110eeeba9773b8e351f26bb56361c77fbf12fd9fc218fd075ae38b95f4a8a5ef830fc2cd92558b1711e000000000000000000000000000000000a112725046ca3b6cc43207e6b36f38d96ff98dfe3444d67ee3f4b0208f3b8543768dc9989f936637d7819e7dc5740fd000000000000000000000000000000000527682076572d8cca15e47a2faf62b129baad29afed22d32ea47983a8d0b138653c1353bfc6fbf9fdbec2efe36700f90000000000000000000000000000000007e3c5aff373b5154ae66f978fcd66d09cbebc7e0c96b4a4cf23c4fa5f2fa655410c7f1ce597a3f5f155017720f7c50f7d46516db284a3938e672ad3c6bd40313d77c5d643ffcc59e3f55ad983cdc0ed000000000000000000000000000000001865c265ed4606ed16056c0b28f953119751d7272bb33b9865eed312ba23b32d01733ad5446cea5873c2bbe37fdfce7e0000000000000000000000000000000007018aca1e7ac211921cab1cc6bb18874d2f39f00d916b8f3d46a088a378f3c9b49ab8a296d0aa21608f11b144a0c687000000000000000000000000000000000210561c0bbe5a9f4b2237e5bdf88bcd73326d395277deb2a883526978df90792993e6ee520c9d5ec0a6f7ef5c6b3542000000000000000000000000000000000cdd344124b7b5da556f64ac5d651a6f9b74427fd712007310d720f3236724e2284aab812d739a87f3a1bfe8737dcee7586cf63c5e52b44aaa79cdda6dd6fa92c6fce11d867b2ff5a04c9e44e0b3930000000000000000000000000000000000024494aab30849df790185a4f939954b724c387c9a366fbe833b628577654174f705d05e7d7dbcd29b8873aecd55df0b000000000000000000000000000000000863054fe3e4838d2caec7103e3d0453e86a17fff0dfdb84dd819f31756032e9e97b7be89b636e5e0b642718f6da217b0000000000000000000000000000000015c8bb4fcb6d9cf941b722136d8d76d847fd6d5c643f4c0049c9746e76e49726fd463ce7899f4df66d04e5d48e523e6a000000000000000000000000000000000f101bea4e1bf610d2782ede91da95eb2b0be9ce60485465b9e94cbb9530b416c4394862f0ba7ee8067bb48e94c07c53efaac96bc5f686d6b952e7082236622b737fda0dd3900bec71654bdebc8ba2e40000000000000000000000000000000002dd11f4dacf3d9c46579182df1c1c45a364a8dc1eb7aa7d54d0141306f1c23bed85235783a22b8e6dc4adc35f9193ab0000000000000000000000000000000010d1c642fce533039e98712bdfcda86eaa62d2d69b861ec4fd835488732fcea414cfb6f3f8414152f9d5398c73a74fd2000000000000000000000000000000000c6759b75b1e3fe86c00fa124d09c5b7438ad61fd1bb71695743ed7793f39b7a0fc99b055201ac1e3aa07ccec61b24a80000000000000000000000000000000017580c9341789484fb31386eccc9c344539a09f1c4421dd124b1a0ce61f2d0528942f7fe8df67c6b2bbf782996def47b39d6045573dafd09ab2a0d8ab6e97b0ade43bd79d820749ecf19cf7d99792ca8000000000000000000000000000000000d9c48a111c8c74bce8cd78d127999531e46a411b2f0be3507226766bc8abd088638a237674ac62e0fb7dd4a86d09b79000000000000000000000000000000000073675bb81e2bfe6adb5cd929e0b7280f5d60b3dee7f797d65ffbefc2c2944a9c7207648bb096f13292ff4440c3f03f00000000000000000000000000000000024d2e0d5ba1a804520c72331fa23a2a326d461177fa527473240dda130f4ef893870e893e1dbf7c5dbb0178dcd29b3b0000000000000000000000000000000002a4c9487485ec33f8fb347d246ab0d41b883bec30d2a5e88cccafa676569f25ffd8341cdf6c09f68afae442a574f3334c4a2ff4ce4b633ec8fe0bfea42ccc329b7d3fbce96c26989b3c7a391c9e806a000000000000000000000000000000000c1965a745e42853b4d54739b2dc507d68d80b330360a4020e4412ba5422daaae313fb9597c98575c66ccf351e62a527000000000000000000000000000000000844439e6f08a411e61d37b5b2b07921049432e1833e839b00d6cc11227dfc8770ad9ca06037043668fe7ce3bf3ce84200000000000000000000000000000000152ad6fabde2e0310c978404a5244209a9363cab1f3ac9f71339cdad6d40c84f8e5a8a196283b581d0209ce90e1e3c6c0000000000000000000000000000000010eb6af62c7dba122b0e24e8326dc906370bcb4ba791c47630f05f657a228c20e010c065b93537ec84fa14a756b199789af09ef1f27cb83189e4e13f3801c08d3a2adc8b5f88717954ee84499defc0c40000000000000000000000000000000001febb2cf2d664e4a277cbf08fc1fbacd05db415a12329f7be551ed56d67f0b5dcc917d1b02951657bff3a26bd8c178d000000000000000000000000000000000018af160555292b2f7ce27112c1d60038b564f5427d62604387de97dcf48e4473107f91936b5e8008065a1537f7ca340000000000000000000000000000000016bbad2a7f5451098294a7cab2fe10d206741a99b128dde5eade581d02ca849bab3662fc3400fbe055dd93a418aecf0b000000000000000000000000000000000b1e9586cc1b357da6e58621ce09288e62a79517144f6c6b867359251baad6d40217578d49c1501f23206b125282bdf4c72c1dc1efefb775a1bda754ff17389a6b6b6bb25e22697847d24a117eb8974b000000000000000000000000000000000b88892250c848e7bc7bb7e42cfe1048a1f61dc546929211846f49501ad8c7c8817f5b5b99ed092d5a2236d59d9c8eaf0000000000000000000000000000000011680c6549f6b7d9d187a6409d40cc26554df654083f1e8a47dde826149d68da756adfb1b65bbd219f79a10d8454e881000000000000000000000000000000000f9596121dad98bf7acb3fd65fe7e0bdc8924e2390341c11d9cc9cbb0517f988ff79a5e1d60bd89449b5f042f0d0b0c30000000000000000000000000000000008982832ef53bafc23ea817be378532b95b5872217093e7c7c2f4512d03a9c9a6dbb7950563a520781c7ae213fc82897b4a0c7c2e611a24c722975ae882dcb4b45e6f6b41cfc87e8c766beefd5b10bfd000000000000000000000000000000000ea5bc2f8bc2b4088d1fed7090ba389577b11a3ee0775cb3f0657ab5b07a6709d3a18fa5fc33554dea235c60baae4bb100000000000000000000000000000000196b6259b06a4c91a0bb0adecea134c8609cf983c2c87158a69c9de3b6768510fc56543a84d1266dda78d90c3b0516ac000000000000000000000000000000000d0222d8ef278cd0d85dc8765fa7c4256394a5ef61f91301af6c7422b4cb17889224c75ccecd2df3ddc9bac98b493863000000000000000000000000000000000548809ce26cd498816ef1222d062b1ebb7313a07e99e3aad1431f984e9b8ecfd43357ea57da7e0c6c011c5d5400f7ba986d48aa5b00fc16c36dcad061d10937b55ec4deee63cc2841b7ebab84f910d2000000000000000000000000000000000b95455351fbce6f73de0345a195f91bf96abee361908cea6c4dcde72048a13a9a23991a75b9c988ba0afd9491d15696000000000000000000000000000000000305f29b05fed06ffab484cb065d4852eb323fda8c9b7c0a78843bd7143effa95cbe5e50c1a0c3a9675bb5381709b6550000000000000000000000000000000016ebcb25f1b8e8d7a8f7131455ed2be084bdcce40034e7ef24a47fc29e447f912c20c7c9910e025aab975cd2c8cf1a96000000000000000000000000000000000d84a5de7a5fd8592f6cc2bc7c3d93c06e26185787856c922d95eeee345ddfb7cbbb60b6d992c5ea4dfb33101f2ef1dc979d4df836daac0960fbbb8919d2f90c3457cc987153def711d6e8a12fb14363000000000000000000000000000000001377d654f80e933c4598aba1f637d1e37d66a96680c3a89a762f412e187817ec08f0ae897b08206a73f1a423b742261900000000000000000000000000000000014b71954b9bc22ac22cb2d7d7f373c3238c923205b223cce6c219175df2bb6d7258ae46d6cdb019311bd386275499fb000000000000000000000000000000000a08ef83b67bc972a67b9174d0e5b1536af882d505d03464c9a97f68061aa319d612de9db84e1e7b12fc3015fc2973b20000000000000000000000000000000005f716d0ffc30005e4a744092704a9e29f58fb06bf7d8d6fdbb95a4c0eeb5c39452cf662721ea3e0bcc67f25931a109425ae495ba75cdd0bfe200ee24d813e1aa93c100ce861c9ed7fa5537e11778990", "Expected": "000000000000000000000000000000000c53f0ca8901f4751be4a478088b30dce70b9ecc382455049df9ce108eb0a8d2696bb325fe9ebfd7d967ab5b9b2c2bd800000000000000000000000000000000033460babd2984a5d8b7002409349972f518364e92648927e223d7a3b648e952482c06cc713bdc29ab83f2646e9398510000000000000000000000000000000007cb9dfe603dc070151cc477ec5bb5a2a949062e8442399597c5eff8f1decff538cd0aef1384256dec73746e63a6c66c0000000000000000000000000000000016b56ee9b21c533b9c464178d14ba5c92a90e6a54c3ed319f487c2082b1ce1d0ff81131a5fb3dd7d13e0fc1d9ad9e4a1", "Name": "matter_g2_multiexp_18", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000104e0b91821c59290be48b97936458af89078b176b5585ca9a79070c7050309b01df4b0bcd84f137f58304d90599212f0000000000000000000000000000000013b00ece925fd17a8effc43e21d982553ab2764b13defaae5e5419cb9a23ca7436cfc44088c2aded63785e4f07b6e186000000000000000000000000000000000267cdd42febf0706675b60af8c0953582ced84dd5ae870815654cffa46eb14b747fb8fbb3b014e59c929da49c6908050000000000000000000000000000000011c5384d7c3e0f4fd66ba4b4c2ab60f6f78f9930e1fed233263dad25294814d9e2aaba6388ee9f924e2a323693b6e43bbb2a329761a3d6a2e4d9d63d7bbf7fc6fd321ec0344cc4d7d1b6565c475ee9670000000000000000000000000000000018158ad70994584e6f2443b8b96c1e4772a00fa0bf74865c76000eae470eb02cff627579126cc465046d4e088782557b000000000000000000000000000000000d72979d455733756a0849baa8afd79e18960f3f6dc9676c33d1663961617831f3266015cb998fff28b78300c87c2a73000000000000000000000000000000000056192c20cbcbde6099256a8f40c78a32d3fd212fe9c511951c7523a3559f60662e070f5b5e5f87b1686be0bf6cc890000000000000000000000000000000000c7b7e8ab7486012d95af5b2474ce15db612bfe1508852b8d99f4402d0e4f075ba056c19df3caa3a93bb4db89443096143cbc3dd7ec63ac63618a9e5da1f9c3fb952c6fc6972dfec6caf1a415a0aa79e00000000000000000000000000000000005a2741902dab47e8d38992180a9670faf56d1849dbeaa75b2b4ded93ee5494184c8658232e9131a8b08ac9b5460bd400000000000000000000000000000000189077d5130b3a4d7d4c3074633fb12739f95b8b6ccb082dfa61d845a389e6ca7aff835fa0f194dc349e1584b3141507000000000000000000000000000000000f226324f242cbc5f616c4a897f82bc5503ab1963ca38f30070c7c9916ef6bef5caa7e2e26b3f9fe68a1d59f19a9831d000000000000000000000000000000000a999bdfa10e4838ca69694272b0187f7d0198d6db0fd85eae688424fb09baa165c623dc6da567fe034d7cf9f9a0087e733a3a84eddaf3af8c5009646a899f6ae8cf233f535e360e29e2952088ebd7b6000000000000000000000000000000000fe85d976befdae8fd0ad33a4404415304afad1c5698b91bdc15abb4f268807c906410a6ca827320f5271c8fd4c8d6fe000000000000000000000000000000000cbff7963daa20c1d20717bcd47b872b3ecd5f38de1a467ef50936f13d6aebd978116a736cb6c5d676c6a9525bb0b7fc000000000000000000000000000000000c3d20ba17a21bbfe873d88e9221571f1bae7f02f35b8e677c9c42907673d765150c737f0011fdbaf4faa883b0dbf0280000000000000000000000000000000013482c68a5e1084faf12e8aec92cd9f0692b173556ac8ac3c7519beb4bd75f847f41ab9432421c631b14c885c001dce25112b5912aa3cba657d8de3dc8138fec92b391d5f988b82e19f16fe52fafea71000000000000000000000000000000000f9091a0df2c989e12a844c447287b704803d1532a3ecbcc890e6f6a885a54b969c53323c105b3d14d12f2cf766b8ac8000000000000000000000000000000000e54f3a9def8b3a9f972726e606195849584b7197ab70a28cf5644cde15e70bb6e3044042b649825adaf5e37c2d5e614000000000000000000000000000000000cae412d8a3ee3c5af38d7a65bdf2440d9cc2d6348dce0791f4a7e71ac483d7487b6c789be0a401777de3f57ec65de820000000000000000000000000000000014df09fd2ff406707004f6afa366d06bcf8bf18f5fc4b444b07c98b3f358247c6056a6337f5b53c35db45904797fb4455683e0b33b5463bc71283f0625269b2b33ead69c1eb7b23a996c31c514d06937000000000000000000000000000000000a8aa422e1d58fccc84615f9ca4a4743cf5efe3a1066c9819f05042100bb8784fcceffc8b3a739f549b42f34d62629e7000000000000000000000000000000000c737cf78b10e82fc0cc9823891f1a5f1e9229d61e8f369c589512d01e5180246db46e4f09e811464c6e1ad930226d390000000000000000000000000000000016017354434899e2285da6ff4b27fbaab633d962197d2ff4fa5f688c4a85e1817434cbef13a6b018df4e359d7b9ab7cf0000000000000000000000000000000001433c364428ac69ce4f5678aadfed4e6d076241519310686de01572da5cf78af4a98b3502519beb0dcf04b748d08cac5bcc597c5ed7f79173942a0250e618c93cd0917b37b5f354d63a2c02a576080c0000000000000000000000000000000001f8b803f3f76aee9825a9a960cd2f9e8aa931568b32be6169036683b4e6d8c4abba6bb73b137c7c6d6b6ea92f2023ab000000000000000000000000000000000fe9edeab60bb55990ad2c85c8fc9341e81de54324652c08c615a745813f08153bab3849dbeffcf4073f087f7c0cf0f6000000000000000000000000000000001955289b1210fa31542bd89f95188d60751b32e8d54f1d4d280975850e57db7b151b872bd431c528c22fb89c9b8784af00000000000000000000000000000000079c8a56c72adb9fc9baa503db394635abb10264dd43c60f2c82d041d43240321ac1028688d92c4696395d8840d52f15f2613a8e50fbc6683ecdd7c7fd38b4caa8e5dc9778909fc8680a58b16ebf40da0000000000000000000000000000000000b0fd79e62c6129fa115d821b8f2a58a4564f5ccbb14088f59d5e6a17a64e803f32bf8e5a415aac4d6491612d95ee8f00000000000000000000000000000000008d837b6c70468e1e10f6b979b7c0694d65942aac48b5baa829c191579186314ea35fe440e6d843fded02b95f9816890000000000000000000000000000000015a05bbc4607b113b37dc0b4b8add23736e0f1bb1e48aabc15500fa6941b17153918d256b6442687a432dd9ca9a198c70000000000000000000000000000000003546953d97306266bdd359d4daa939e05c0466691de59d2dbe3584e2ebfd9a9e1516cdc9cb643c5d31731835dfb07c657a747bc919991ef9b7b10388bf3f301fd910f807ccd31e322be46580a71b7c60000000000000000000000000000000009a4366299290c3c6651b22865fb22cc972a05ca5981f5682574851e41096d531e375e981c4e1b1cbfebbc70a41bb6ad00000000000000000000000000000000001e6fe2097fca2afb8385a3100dbd5ee1b7ae972e06ef9f5e34eb9fbdc65455e1c822299e06a9dd5a3f71a0c1efd44a0000000000000000000000000000000005ad2ffa8861848c46722a7924ece68580fe44e03157c982b7133361e974b59dab7b75358fe498fcde9f68b5b99f23e0000000000000000000000000000000000adac33e0b7e6740c980a4f297917fc4fc13f53a71909f2eecd0067656c6f82c3b371cc638509151bf937f8257aa415d86ba09829f4bbb383e2e131d554c42edf1065022975655c07df2b3445a3e6cbb000000000000000000000000000000001462d509503d2c33829c3fb5380199b79b970c2ae7f944e54a6d0f0deab3571976916cfc311ea6ce6128c467665fbbd10000000000000000000000000000000017f6fe356cb0dd5bddd489c26669f0f365260bb48a5f862e9bfb778a7ff5392938b905759718d050f7d93f107236cc75000000000000000000000000000000000d9b3ca93c5133cabf3d3daa565bc6b51e63b7e37f68f3bcc43b9b3ee7db15f8bb33052eb7e332ae3e9ffafb17cb77d60000000000000000000000000000000017d6b898d9799385990c9dcc3f72ed93333486b98349ef106a230a71d768b75cf56cd946f5952075bc41f26dca9c83c003fd5e91f590fbe171aa3f006617b20ad645626c970c2351e048b2ac3773213600000000000000000000000000000000158e5e008796c10f6050826c29523864d06e68977cdc95d281a8606924aeed0b475ab152bec5bfca8e0ec53691b307f50000000000000000000000000000000006fe8e75328c067546eaba93f4be2b15513bae4a3458112c3ffa457d15c23636816fb469f071889380f31870d713e949000000000000000000000000000000000b9b21cd58f8742ed094e9b770182f6f3f855204d869e53c02d0c242a133e957c53c9fabc827d6379b39541170be313000000000000000000000000000000000014eaae1f0789f0b1e8ad3b452b4ed3ff87bed49ffedd13c8c35c35668c33537b63050c06a5bf3d88d516cddac13b4c935ee16785c004dd2a01920c52d3244e2160fec2d17a519974d4331527cc627910000000000000000000000000000000019f976b3584ffc188424614fd287eb79f060c55e9b3dd2f3eb99760a7cb5b70e2b62a0895b05e7cce2e390853fed61b3000000000000000000000000000000001117181241fead3865eba4804ec2c14f571aef5351d5bce29399113d007cd4e9c262af1c77daf9183346153e562864b2000000000000000000000000000000000f823f71035a4870be2ef20bc94e97d74d18c0a1be9895fb27c54df1f663df6f9e6e45ea5fe4502143a84c05e517b02b00000000000000000000000000000000141250f392fabd4566e0cd3a472a4b2971a432a3a5e1d9c924866c7a9516322bfa691e9dccdd5ef14c561bca6dd70ba204a6d6e29336015d99e107cd312e300bd54f815c785f6008c47c99fa008452700000000000000000000000000000000014d6827b9bc782863491bc7c544263f58dc04c18e08a87ca2fbb5799c4aa70bc039416a85dbba67dd83bcc27b70748670000000000000000000000000000000016c2816e93ea9d4bd6e42a9720cb89d637d88e00074da3300c6409be98a03403e9ac15f83167cdeb13800ad174ac47f10000000000000000000000000000000002aebc0116a62f93a6e86c7fce86745618e08f4aa9cebca7b520e9176bcdf1521cb2bf7eca7f7af9487fdc82dce76bb50000000000000000000000000000000010684e3254207c4ccdd49e4775198df981afcf7d9f89b894e204c5dd84ef42b89fe3e2f6b9278470e6cde4d3f4abb3b003f9cd3873dc6243748e16e4806f8eaa339edcfdbf4408a8e41a3df80c9816210000000000000000000000000000000010ab1d5494509060c9784b4744a0572a9466d6c374524a6d338ea12ac5ad89519217c462c3487e398325439311bea86400000000000000000000000000000000197568cb53ce03f00aeb04278f355da862be757366dad14ca6d30b3a537df9855a1196010773768a91cb4bb664a34f0f0000000000000000000000000000000001fee249315794d30eaf929f44b99e07927194c6015ff34a4530698d7d68239240c9cc48530d52ea06218a826a655cce000000000000000000000000000000000645b5d701bf3422228576467120935f014c754dd68bb3555b50aff5ca04001a26298982c97a64469aeac3432784efca34135a2e7853c74725bdaee1ceadead7b4c7d729650df6544bd525c05c94234200000000000000000000000000000000113e17730f8dd7258157085c30cd9d1950a26c848b55e3a8a55865eb567edecfb09f32ba27fb3e2096ea00c30f31ced8000000000000000000000000000000000076db9ccf8df9530b64cd43ef7b496d1f432885062406028901bbfc5882fd12533f84eb12aa2ce8b7adf9dd980db0870000000000000000000000000000000015e487de49f1e494ce9907cf0ed31fb0a159c5290538ad969b2c8a504986dc9cccf7c74a61f622154e928aa2dd689c0800000000000000000000000000000000195e887083a98fe3f50a9ff4b342e004398cdfee55c4b02a4db0f65a77d3c0b142a45201674726c96d5f79f8604d61860033fdcb731830951dc3c4b33f06310eca51762cb7279039b3d7d9ace93c5f2a000000000000000000000000000000000d80c7e50973205585b20a068c64957cf4572eea40e32ffa8b759c38c6ad6f4468421f2fd6a6f5da1b0d008f625b3e6600000000000000000000000000000000009242dc1de055aea82b3b917f88b6232c550c3aff41241a7e54caab4c234d29b5d8138968846f7c754d73ab3b4e7913000000000000000000000000000000001188c31a9d8359d737576f4ce7a7900314aca0eb3b51baeccfdc9245bffec49143a11b3331f9126b01de0c307aa4e44400000000000000000000000000000000104ef4835124fa6b30dd551653aca25db5a544af6782cd0b1e7d26178253e0e33cda77428fc1dbcfe6114a758cab5c814c8112ebfe12bf44e84796e8b0cd03a93d2164d6edf1f06a5c520330a177da87", "Expected": "000000000000000000000000000000000e79d18633c18ac818786bba87d09c9bb1571e179d8769f8fb82e2e2b7a6a8695c1f4f06deebcb84524e8facdcb49d0500000000000000000000000000000000149d0231fb030a1bec170decd307c10e72cf1cca55c8a1b67aa94ce61e4c7d2ddfd0b8e71598e1abb054355dbcac1528000000000000000000000000000000000090f5be784dbafb0a8aab1516c773720341de6176017e0fb43a275d60de54c1189144956d4876d989232b362b90851c0000000000000000000000000000000019dba28eaa6706361f285b3abebef68f764204c74ee93ea011db01c19591ddc6f98799fb3026c3c223effe4489a7c676", "Name": "matter_g2_multiexp_19", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018a6a982acce5693e632901f3136eded40071e8c7caa7887f302c32621c5bcf9478991ca519978b52f8f69415c0d070b0000000000000000000000000000000013420ab920c8ecad5b2f9aaf9b0074c2386b0b08c81923558770d4c4a6b206a865af8322e9755706cd5e595bf0ffe564000000000000000000000000000000000c0e5bf5465d564e3ce86d6b742ca687448e6952439b1ff44b86ee6461464e07f8039e8ae7a301c6caee7eb99e38fab10000000000000000000000000000000015eb8751b750af62f57971e88b436658758bd5712f98861fa07328d2b11e8725fb55a2a00252e0be06b0c73aac0f7b8cdbb32a4fd8b9dc58a382a7e436e23f49a134915372553eee8c605436221acc80000000000000000000000000000000001328927910ab502e573188271108706152f562b1d5f6ec074f8f9ec5eaecc6cd5e8284a060b65d26463d22c8290ea4ca0000000000000000000000000000000005a1fcc348122350981dd5090c865a2aeb851ba8b6e0443c32f48b157ba673ae5652a70390888b3458afe6fe975321700000000000000000000000000000000019edc749a9799c8d3df75d4024791943a8fa02ba0cac90b6819f0bc42687b044457bc7cc6073506e8fc19af37f224624000000000000000000000000000000000fff20fb2b554b63758963c1583b996ad450cfbd5ca9952e38f38a8994809096086ed86311f7d73a0a5898ac261ce09e57df9664d3e17d9d46a886efde4e37e38859893113558843bc019699eeed8ec00000000000000000000000000000000002a7005dd32bddf1031f27c2ab999604c048a37c39734db48a30baa86c61ef626cf82084651ae9ba8a265333060a408d000000000000000000000000000000000421bf913a25108b8f520b2becc6f8064029dc046d0d5effbef31f0af59eee71cfce83fec8dda7983d50c6d5cbc8329a0000000000000000000000000000000016c75708f1dbfbeae3b06e5e9a7fb676c27100b99deece14d979b32a9c3cde6e9e96c8560a00aafbe6e7decc84e7e2780000000000000000000000000000000000ce23c27b5128bcffa424fd1d181d21b06b77bd6549ca5eba9a28cf18bb9a979270f6a5807c640dde57a0cd4f3af8cbe2b433b7a95c26e598002cc00b7904816d59baaba79bae7c6a7c26dcc48a487e000000000000000000000000000000000690c7ab321c0c93b5ae4ed77843ff4030e4ffb504c685d28573e98836e8e56dc19d662ae9f496a346bf2a8be5396741000000000000000000000000000000000fbbe3861a8d202b10801cdd606b50db0ad6ec7b923b90ae81ff5443676c3399e249e9efeb47b72d2b0a54cb0594686500000000000000000000000000000000148a27016968f0258e5eafe0a8182c22091873a5a58b27aa2160674584e06d5b2f46fc57a00617af18d0688df75294cb000000000000000000000000000000000148449d00b3d1b5b43b08a0c6e909a2d9c66920b60224a2c6a2521f0bad35b99e3bff8be0effb2f7f34438662d7a4882897583b53567bcfdbc63ae3e864a9cda24bb732694a6b27415c5212c7f45a9400000000000000000000000000000000026b55509b81befaf6baa682a3e92a0ab423fdaa84d2897613fd31acd9e1590f81581ba0ba87d68af76b01c36093e183000000000000000000000000000000000c675e190570bc5173b8f508d5bd2768c83e7f56a08cddbc636792dd75386939942827617c4aff8628a74b74195adea20000000000000000000000000000000014f59f38ae9e77f3a76478ecd47f32200567bad11f191d303cf15d7801ae7b5a3286095fc8726acc9818914b27a776bb000000000000000000000000000000000da89fe9493b2d9d46596d80162f5831d4fd8cbb83b46e84e95d5d684eb927022ee62ebc3519442007fdc543701f97bd2f7ff17e54d759eb9c51e16cf6f12d645bf2d091427416b4edbe1dd21947b4d900000000000000000000000000000000170e52a240a7ccf2d57ae92ea8dabe62ca4b458a5da42319ae89cad22ebf13541b0daccafa1b1d3cfcffe81b500c4cf400000000000000000000000000000000174879425f3bfd40fb74a88e3dc578e45b0e0eaad94da009e4076dc42d234d78248ec3a035666dd6de235f87e1a47bcb0000000000000000000000000000000005aee47acc3260d11fe0ca16050a29f92763b3cf8ac78da52b3b2b3e26d8ce7b6ccc187fcd81695aa456e9b94a84269b0000000000000000000000000000000005eb297abf35b51d57474b4989dd8f793005bf8e82e49859c41b786ae39217b2321299829198bda4aaa261a2723d43d6ce0a097efee666c22d1dd0ae8c8e11283aae781e1deadceb3ebbcbc5e5280a61000000000000000000000000000000000e49e94cfa35d8ade2b76865cc8be04737d00b48b195078c8085cbe782232a544cdb548373bd8ad0282674ba5c96fe0700000000000000000000000000000000047d59661f095c41bcc27da5f260f13a3fce334bba216b45df548894bdebc691fe779ccd63d99a9872973ab165a90c01000000000000000000000000000000000772e9a9c22bc7352fdf74915bc464de99ecd96420ef1af6e8bd5a05d73fff89c78e28eb340d4967e906f28afe1320490000000000000000000000000000000018bccff27bf9d7cb2159b9f2d1faabbf8591b53ca8e67e661d9f44f6dba6296e3e46ac32c50128bb5fb076cb8f214e277b2baa349884b54b542e3993210ef002f70c6467c7d512801f0003da789c00580000000000000000000000000000000002d947e728a3b376de520bf78e56452930de42544241180906719a24d72df65f8250402ccaf14d69935b1ecbb0b4d34c000000000000000000000000000000000d5614ec77a9f31915dddb3e4bb533db001702891a45f0bbac49e73d9c19a235a00442b52d452d77018f883706a616f1000000000000000000000000000000000dfc6a73a8e36b7b2d0614b1c6f7bf1ae284ed740c768f08416c0c09a601fadf3e4d7b17a93601b1803d19a04ccd570b0000000000000000000000000000000010d6a8e4eca2e818d6dff13faf0fae44a7fb90be436a9ef3aab05515a35cebfbd53e9af866cde1745f0e2c3b045486dd2b94d087c3ea101649ed57ff308dd3ae0d25a1ad8884763cea1b0b7c56a3834e000000000000000000000000000000000d6c5a6fe9b4d4580f8e1d89f0510bf5dd04e113d6ae5db04af2553bc0eb3a32fb881300f638fb33f7c4bfaa10b063660000000000000000000000000000000013e001b08191707ad98e21b3e0830286c6f3bf587b971dd4ce39e55f06db427676626a5c31c4a67a996a5725ec8f402c0000000000000000000000000000000012f86ed85113ed1abe9dd3826423911e63df0dfb51ad3d1e0e0318ae95991a6a11150176cec77f9c83268a322cb7e934000000000000000000000000000000000dda719cd2cf1aa769f94c21af20ab076b8f024e0a4903e38ddaca21b6bcd6f00baf7e1ed23259f135eb8bcf9c3f97c44f8c35b920a35b71dcf8d15a8a826e5a7c2a2c4f1ac2c2e3a6d100363e7f541800000000000000000000000000000000195ccfb9038bf9e637b88c83c552ffbd562357792513b15f703bffbd373ebaed715a6772fa7e6e5678c2e6422811dae1000000000000000000000000000000000c5a110f31d71b12cc42974003ba39d99dfd91769c2e93393449083a9b84d31473e3a7dff7ca40164e6e7215b03f44ef0000000000000000000000000000000006233b2dcfed96559b565928a494f2a50c2c375b3d7c60ee6b286c538f4fd5ca6f8b2a61654fd04d679bb3e05b9bcb03000000000000000000000000000000000d42233b7b5ad809c735c89c455ba1e8fbd623e1602bc729c01d362368666e4f90e7b076e32468041f3f5665c6fddb0d0ae6101fac82c10267770e74a0ee16b5be6eae2d455d742303a3c624d52aa726000000000000000000000000000000000f6d53de4f8b20de19b2fcbe8a6b8b8ec4bb801bce7363f89b133532ca7ce4925312e23c618a0182d158037c0d0bf07e0000000000000000000000000000000006ce094e24eb14b9bb1b4a1838d8b6da5f53b5c5799ab8dc8934b488cbabf698b99abeb016259a4e1b0f626d27f2c950000000000000000000000000000000000874aec7c8ac360e3980a6e2cbf3f7468f1df7a8d9158f8bdbb0f387d19f3b05326a081129576251ec41a926f670e58f000000000000000000000000000000001711c9b2ed7e2f789b29073f180e46d0c373d6e75c587ece67b8aaca1e9d9b43a96d04dfdcd42f943eca48e240b72ba8002fb31d0372e7730499b26d617b53ea04821c6eae922326d755a0df31b559ae000000000000000000000000000000000e8ddf88269aebf190bf9bd7a8276de92ff6039e479e42a490fe4ef00f646b049eb8ec4b8e073caa000bfcd86ee8724a000000000000000000000000000000000a9623655c0121ea0575de714e53c9e304fa3309f00828ba0e786112781a38bd458cd67864ab17929448171b5937c1d900000000000000000000000000000000198fccc4a333322599697e904e9096240b9c54f89ee6db97475beead62ebf730da1a179409133698ef13abe1310689270000000000000000000000000000000017b059ac08a3fcebde5888bec4d7cc2c70b147b3b1483fd001330637ff1c036faebf292801204bf2ba49350795708dedaa846e68337f4e9c99dde506a3af792732342e3b836376d4816557fc1fc9b916000000000000000000000000000000000a36274f33b4dc09e03a5ad648af0913e5ee95af83df8b4f2a158456aedf0a0528f9b4832b11162dd67e4d22b26e9f940000000000000000000000000000000008ce96d8bc0aaf2dea732dea188870d398b1f3c266b9bf019e1046cca05002416c910e02e998a1604a17c333c65c99a0000000000000000000000000000000000c1a0e4a80bb0331a94ed14570053f941a0438794e6f19d976cc62b3806a565697720ea03c2531004f13453991bd99bf00000000000000000000000000000000184bdae93abbe4d931a6a51ec85bc330d6181da2d34f2cc530e56b6803515ba87f5719fd6fce6a1a8bf1ee5a968bbfbedf9035283f1afc294ee68b2668870aa45e483d208483d9e967b11990cb55d8600000000000000000000000000000000016c3782daa55312a7cfa02c3be73ed75f4b726df5592351fffae19121b5cba73f427d35d5a2df7c63e2a5c68bf57f3800000000000000000000000000000000018b608343616eff759d512c97257f2103cb0909afb4c24a1cc9d8204274b7c9ed51bc762a6280e223a6116a9b23d1f1e000000000000000000000000000000000c687c11a879ec285180cbae3d2e4219df4614e238d4cbdff148ce5a8d21647c489ade3bf6f738052f149fdbc76c8bf6000000000000000000000000000000000936b34fea3a2633b9aa32244329891e332745876d05f95e4efdef859b23ceab4869db562555e5c8edce87a6fd075ae54005df80aa522e889e7720a9f2e44e6e7e19c3160ea282ec87a4b446d7b1c45f0000000000000000000000000000000000d4636a5e13bb59878319af6bb7c98e5d247c2c9cc970b9cec98027de2d4a8ad12d50906fe302c3d055c499a3742ee30000000000000000000000000000000002b0214bb1ee887a7ff10d458fe35208573456f685ee2fb93bb470762c9e27595cb00f2eae7574c8467e417c63c2a960000000000000000000000000000000001710d130f91861230562cd7ab87984ef45916af8e1168fb17b9765183d9d3f9b2c81c649687842de495a757471e28067000000000000000000000000000000000dd15fe505b1364f134ee77e5e3c1a497a20849b6ec7e201813677a1569a9f5a9edbe3df4c36bdcf9ada139b20e048ec893c9daec43032946a9e892dce960e07d29b304000378145148b9a24afd151570000000000000000000000000000000009a48d7c55d24ba49f890791d0f6a8a5ae08a19177575dc0d734fa37b52c3adc45b31b5e485a5d4a5533470c3549f5f900000000000000000000000000000000090f680c6fc1f0588add04ee03bf821868b1ce588e3ebe384dae657ba7885ef74da0bdc98d9d9594a9b979d5b50b93df000000000000000000000000000000000314f6aae1e99dbe3ea9ef85db7e1693a30869f48e05cdb073bf8e14865a671e75abb875d1b41f13d4eb74fc802299c70000000000000000000000000000000013c698b76dd68d1b9ab41672c2b07cb9a63168497d1144b51509b602c5acd71ca6cd049616d949214d95ab7a906a8f8bf685e6bb7713f8fe202c05dfd18003eff261456026a5185ee9e68aa821fe7c5b", "Expected": "000000000000000000000000000000001747f6d3154e0717435fa023754f115ce2a2b3241b62525cb2833473d84a8ccf4c95e3ea030f2b8b0ccc61124095ac86000000000000000000000000000000001827ed7d84a61c21268857036e91c732b304f609f285cdc4736c951fd8954b10267a8505f25d8be666792358632058b400000000000000000000000000000000121ac61f59051e6e89a7c1e2fb4df4b3a5b7773f46495a99e55348454e1d9d42254e5e11b841a1654ff9c80b157389c70000000000000000000000000000000001bc60cd06879980bc6ef2ca109d31f12cac28ebe4d2a934076d720b12f430e1bc4d4260f40045cc7a862726521a69dc", "Name": "matter_g2_multiexp_20", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000012a6984f0f8967c5ae6b13569a62095b5fe61ec607daff1845961bdd827c00fd56ef864802673dd21d90560fef6cbea00000000000000000000000000000000085ececa080d0f4c996d46c80a1fbad2ac9cff8b3e324aabb67182d79f941927050f025b633fd5119f30bb29b8e4b6f2000000000000000000000000000000000987518a5edfd5ae2616fc60000e117a4f1dd1db68195c3fb68d8cc639e4200945b2864d41ad86fb3e11c504fc1f9766000000000000000000000000000000000310939c7e11b93e5773cfd36fa70020c85396e525840742f994110e20019769abcd339db6881291639c193b987b68ae94b3c88e51af5822177b85978526036a426c9ca1077d594618ebb8fac4cdfc89000000000000000000000000000000000ec6922dfc74009c3750ce2540558c7c1e05cb45a5d651b96427c615d8fc563219215a0ee431c0a4827e40b26c4f8d3900000000000000000000000000000000040a4189d002a0e1ec600e71303575e82414e6400f06b9abf57151a28835d454f56421a6dc4049902bfb94dc0e9967ee000000000000000000000000000000000dfefc7c163c34cc004e9d97d812b2717d4736d0d1c722b6bf1a29676a32c8b46878d05a2d137cb7fff5fed8c0f02474000000000000000000000000000000000e3f0c9cbc778693c8ba88af8306d45477493ed6be1bdd9c81c65341239eb510fc948142cc30b73f570819b38f13e20f6e456b39f4efe6581657f5c701c696fde8acb59e856943f15cdd639c1fa68ed70000000000000000000000000000000013705ca4ecca16559713df65b376c7c5825b4f63d001ebbfce9cd1b592af5f2ddb38ac7c5ce3c5f7af4f39f909887e8b00000000000000000000000000000000179efff38ea1044e91ccad467cd2b49438079ccb4d0fc692e79e0bc374abe064fb9979c4a1f4b92c15cd1b042b501d5f000000000000000000000000000000000b6fda2dbf6339af225515681184843f1a9bcd72f7b1389f186f8d0e048ac16e20967c28e087cf09d7bcac597a85398d000000000000000000000000000000001946fca8c816e1e11187aabc40dd2436533d537ce4639eb2d08630ed2ce402c1806b6c2b3e04a960408fd4d2049849bae5d306f46a31c14de7b2940104d0a4424ebaff805a81f1c4a910566057c81604000000000000000000000000000000001802064095d029d3897725eeb93ed6e3b090390769026120aab6977d0de264a262aa312c5777ba322c9eac29e5396fc6000000000000000000000000000000001410f17820941e6a67b1b4993496cdcf0d4fa2d4fda3d43ee985f2606b1408aa9c9ce412c80c90a0c876cb5ecb76878c000000000000000000000000000000001514e9b2c65ca86713447f2d5bb8395fe8552e059829afc68bc43ba9267ef41ec6d69d06e7407a731bcca77ed5d9716f00000000000000000000000000000000025b5bb18cad46179fab15b2ccef17858f9259a90ea4548852b8c6fca69f0ecdf0b175669bacff1625a7143e762514194ff6d13bb0967945ff3b6fbbc104296805e4fedc3c25bb55b75cc997834de6b700000000000000000000000000000000146eaf5da57b6ac788f8caeb4b2ebf7c8999e03dd839977046ca834fffa7e57cd949e3fd44999a007b5dcf3c8621ba2f000000000000000000000000000000000d859632d3424ffe4227ae14856e05c4e750545cf276c97aa9ec03ebde334144eea670dc68e92b61fc775e477a2154040000000000000000000000000000000010b44279c0c80886e52fde5e71726422da2f9457ff86b21426d80356fad95d5ff3a7491002364d9de5ca99c2500f344d000000000000000000000000000000000851b769a691f0ebb53ee3693833881fed8dc6d9e5f1dfeaf4ab1aa7ad54e2fcac246b70d81110451ed78044a98d1547de4fb2dea292b76d8130e6aa8aff5edf0097de935b252d42a777d4d9b8615ef100000000000000000000000000000000131c9a76109929fc977a0a6eda0a7c71cfc744f5f3654e2221ce84c70787598e24c5d8049f92a7c4d78fdb869cbdd1ed00000000000000000000000000000000049872d2c7d472e090d2975daa64fd96f33e7f934e739633b1d7fcd5e771673ed8820752a0d5c8b0c6933318293a4f27000000000000000000000000000000000dd68fbb592a3957ef893180dd758f75978042add36c91b7bf87c4493b0baa875e1854fbc09e6856688cc241b76ab5a20000000000000000000000000000000006143699816cad8ab7583a72b6064fadb6caeb51c8625ddbf7b2911426cf438534da1bdd13e22cd545495c486c9733f7bac5c50a3a8a37111114c22839c88ce4072940c06f0d8b6d53fed155d0399ed70000000000000000000000000000000006c14301984607d569ad1bd774135e7c9e328be1fe54c3b543276bd06bc0bfff11f299a5eb43b5218c3605011d0ea6d80000000000000000000000000000000012f0a848022f95f4884380a5b8e3637a41e3c399a8d2765aada85dcf4b7c2b559122f792850430681a58ca153be2768a0000000000000000000000000000000016b4cb233e1bd59b7b362c64620eaaa5029c173a05e2278774ad6ed746c70a2f6e76c237182f5d9d790966ae69da5d44000000000000000000000000000000000c277d54a7a72c8528188f6cf29d934cc66471607e5e30d493cd11be6b203bdf734aaf37b686cd7101e8599b69446991c3f37387bad1af3a896a7e66a80dfce2df1709fa252b6fbe4334d02bdced432900000000000000000000000000000000169a3928266375dd5793b7504727f939ef0ed52d69e569b1b75a0e094698b37bc70472578beaeebfd0c3df4bce6177810000000000000000000000000000000008936d470dbb86db1567bb2fe7c09971c6d12b07208d9b1b403c20fbdc05ef8984dd576457fc6989470e40ebfe4ceed30000000000000000000000000000000009cdec9d80f2bf3ebfa9a3316e4250741d0d089245df2fd3c9bba4bac1c2dadfe212682166a0962f78c4bf25b618da900000000000000000000000000000000016521411286cabf3fa2c8f72ca62ca311738fbe63717fd12916a4c9e6af9b05d1f5d65cf60e84d9fc5f7b7645fe9bad570fbf5da3959a49fab7e97b3df3f2a38d16d714dd798a1f04ec2cbf84fce76910000000000000000000000000000000006a827f6149a320a74d9d8c1ae8861c1cb963b3eff899710eda642dae6ed4dbc247a22131758d9f843c62710ce083208000000000000000000000000000000000c83a9fd96bcfd4adcfc6d5a47e84108bd763366e91bf06a7431c6c3a107cbe5647da99ee6c1e57c376d366b21a923df000000000000000000000000000000001604d5c0364afb5503b0e1d52226988d7f7f043ce95e7c0a09d7f96e24a58f089156f0e6d19022138170c1b4b7dd33560000000000000000000000000000000019a11c86f78ce462f46e0462052cc3d342596b329fb62a282a59bbd64c345bd266922b1540e40aac147681754643c2e3e538bcefab5d8d0be5fc143e632e86fc065af3f2f621f293b914980abfd6a0c70000000000000000000000000000000015635de295c16841bf44c73639f047f735175e8906301746837838d124bf0d2a1ebaee142393ce9a0d58107c7cb036e90000000000000000000000000000000004fbbd4252fb901d0737d1bf4da62010c06d690a9584c7631ef5d36f1d8c37486a83f2a1e2db21f05c993fd117c662e8000000000000000000000000000000000f4cfcec1545a08e0e0298753ebcef5f61bfdb7c1b9af71cb4c2f783e4fa3948945d357e8302d99aca96df0cb0fc01a3000000000000000000000000000000000f543dad6d4b797f6fe0b00215a5f70f6340ac6bf7cb0bdfc5bc7698dbf0647e4098413dd19ca7af01685edaaa190c6e30b921d8cd2ca46aa6f3e0dc6ff08d77972fb0a248bd39e90a1e9f32be9e892a000000000000000000000000000000000ed552e94021d0912a0e7563462570cb572b189569eb847bd12ebf976d22343b9ad04d400ae98fa184b10ff36720f12700000000000000000000000000000000178727c3e6ff33be9894ef26347b104023ea0bcf79c1a33afc26ac0ee9879344964fada757118829214cfcdbbc0c5a30000000000000000000000000000000000b0a6a575afe5b0c1e287815612fdd3838ab39e8ee7795855837588614715f6687910c42217ad52c1b8721a9e1c908dd0000000000000000000000000000000018cdbf244c78cae1993400ae164b42c09dab4d8e3707a69e25ffa8d0b96b8270c022c0375f933f16f45c9274132a0a633a5ccd9436b15d4d04a8ee9894c116190062c4e7cfabb047b585f3aa1eeb460500000000000000000000000000000000070636611f903f55cc9499481bc3415a6de62d5e6bf8bfa82a8ce665f85bcf01690118441961ff46ff701e361db208500000000000000000000000000000000013d22dff8f6f86f659ad17ef91d90a70c180538f03e10de20c445d22e637015d51a311a3daaed90712d04c9a3d992d12000000000000000000000000000000000db3535057db95fc262f8adfd7f08f3237fde5f0e2aab589d4ddcd9c23aadc437e13644dd3b3534dcb17936a7c610cf200000000000000000000000000000000044c177d4484c07fb04d1dd477b188a2c157973cf26075001d14d2b07ebb9dbf8e495dc23b32a2419621e1c129b08c5ac7a5bf2cfedd7048be7ac7d2ff19d4f8bf0a94295ebdc5e792393e0e4bc27d56000000000000000000000000000000000e10fd069f2f5fddaa0112e70ae89d1ecf034defb24e2923731a7c0068780177c186fde92a3c254a1cbdd255111a4b7c0000000000000000000000000000000018363e01e86e2e922ba435651ad892bf9288be14b54dda821c397ae6167f9478c8132e92b1c2cb0c4037a4e020f08291000000000000000000000000000000000301b5ad2d5c35ebdcc7e7cd1ebf0405cf204d6f5e30ae6f46d20534eb6d7013682c5ae1bba76d2811124ebded0d2a590000000000000000000000000000000015fb3a8afad778031d04e094cbde5f02dcc89ad7b7d452c6c8f41be336a4c8b26e75cfc685b8776cbe5a487f09c304083563651d5f5729a0ffca6b383d884823aa3b0215fa057bffd8142199a16e4ffe000000000000000000000000000000000a7880b00f6a3e959ff1bd207fa503eff6e7279e701e37b40735e2bc8bf49e355e92edcaf23aa3654bb26fbfb07b5fb100000000000000000000000000000000113d9b792f4e3dcd958664a8778dc4b177c430d8db9da7805595e40293ef2c0a40f7a843bfa70ec134ed89a453f9da50000000000000000000000000000000000d7f92148dca4a9c96c47a0eb284f1834cf3d141be7c0d9a7a060af6e28e45620d8255e465e9a0d8f78b2ffe17d6b04e0000000000000000000000000000000004e7917a8f3070c656d324c9a816236842fbd6147d326652667e7bca0666d214233ed136dd9464c4ac619d46c28e2393833323c3a668541ceba18375531c3781dd98525b49dafce4c4b3188c90f3f4b500000000000000000000000000000000160cb05390b54151f6b154b396bb400a91fa83d77fabdf31fba349d1bf3b5dfb6476ad4d714af2a2963e41b077bffcb90000000000000000000000000000000012885f7ec8e780cbaa90a465b5706cf07d45bda7755ae3477c79adbd7956b926e0ef5303fc13f0b97349ff8b754dab500000000000000000000000000000000009ad7509e9e7f5018ae3d1280e881ec12129cbf825cb6606459211ed7b358a97cbe430e94dd9f5e4f6b74fb7287f862e0000000000000000000000000000000014d5d2ac2dbc3d5a061f4e52dbfa68e1eb1d3c818ba26686a3171e310c63cfeb188030b83407070019dc5c42dd079413d422e21fbffa7d55270eca9c96bbefa29dd915aca266071673e970daa0ca9c050000000000000000000000000000000008ee93fc610712411634079be0bd96c3969b48955fe5478b7a31c3ba7639c18291034167eb62e6b15c16b0dd5145edf500000000000000000000000000000000158cb1731b71905d7b958c5407f090a2c8a9319017719da143a3f4f3fb3982abb83b8dfe14facb014321b4f5edb5e41d000000000000000000000000000000000a9f98f775f06055ac1f137cbc1f95f4afa0d1c4935f536ba2e0569d874d9d76b7b86f71afcea07e2e785c7a6ee1c84400000000000000000000000000000000072f8988dd1ab0fa8037d3620068b34848c65e20dfc90612d123b6f9dbcf9d9d699d5ea73739d31ad54c22116365ab983ba7ea9ffda87131452b24a9efcdc91d1262d0d7550e5a6b787eace3577159b0", "Expected": "00000000000000000000000000000000161203d8db1381722644f87b04f47e4be2ea2bb105ea0e67678bc8d29f8a8a3247f8c05e057af8f98032faa93d896aaa000000000000000000000000000000000d3af4842627a095a2dca99b52d802b2ef8c8f3d09873ffe39d224333fceae84bf74780956904df6c1dcf5ba31be218d0000000000000000000000000000000001c79fae014e55e5d0239645d618593bfd5aef665b3e636dac5d191a8b88949d207cf0ae9822ce8e1997de302b386b8800000000000000000000000000000000136314cc68b372b06e7771d82b7ce7bfd0e9fd306787e07629f831c7aee853bed80172121949a940bc59c4a0b76f0819", "Name": "matter_g2_multiexp_21", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000099434adf799099f2e6e2fda4c905e1543893462133ba216aace25836db37b3dd5bd80af1a8c31c7fee56b5ecf9a0acb0000000000000000000000000000000008a6890e5bcacc13e116e3fe2d772ff49839803e4f81d6b088ecb7835b1ed44f2bfa04de1d46dd352346cdee71774e37000000000000000000000000000000000e94fe40225e863b7bdfab4cdc0c1c8d1399554ebbfa3f2c95ddeda74b3dff03d5cc78e295accdc9f02f3f89b4953de3000000000000000000000000000000000b23f2912fdc7a5fd1de69c1f479228f8ffc9f97c40845808cf17a6fd8131ea60285640d32bcd64c9be71d419aae82fb16aa2cadacb129598aa459bb2e6b7fb26d1bcb7a49617b6ef8e57018c3db1f510000000000000000000000000000000004c6f5aaac90132b2d0c6a4e70354ed2e724df7c3e6298eb9ae4ea92e3c7981944c89140c52e893ef2edb2773ab36bcc00000000000000000000000000000000021e813378be9ec30395b917ded5a0424fc7eab0abfdcd2328f725bbd6a1dace0a5aadebe40e10470df0c09b3f4b68440000000000000000000000000000000014e3fee16a833f8c543860ca438d763f764f488463601741a2331fa90efce9f6d54ee0fb7978460a1ab838039d398918000000000000000000000000000000000dec8bb882fe6028a4155e6e2bf48ffd314b5519dc4560f8f7410209214c4a8e37b2b36facc53f4db11ee63ff11f9f228c02014d5392d30863a12102d1c9315839b5611dccfdb489207f9186625138500000000000000000000000000000000002d107029bea087a2d53b6b371aae06c695fa85631450f4ad92c8948b09ed568b28948f80f1455cd22e2ad44697290b00000000000000000000000000000000002fab10cdd8bf17a633c8b3ee8ed2ce783f64bf978c384fb7dbd7e4f0da50b65eb9530365d982bcc17ab91a29eabc065000000000000000000000000000000001369237fb3241ac291a868e6f4610a5103d93aa915e954f18bcf348ece1560a12451723b96ad5fe162a6107dabe1c986000000000000000000000000000000000cb70b7064a2f94efc86060431ba4dea38bc64822efa73c76f3a4500ad23c452c8f2e72713b066a45bfa49559d14a719d960ff678e1b46ada4f866adf354ba8c1514df10ebe7d88d2c8de117ef5ea2490000000000000000000000000000000005ebb9c8202cba234851cf5e060a4114c6fee0632f37e0c52aeb852637f362ce64403347d336c32617cc59f23cc7c93e000000000000000000000000000000001126827b6a0a8adb698854c0089276861e3cccfee420512f0966df78ea0d9c55e85a0536f14ad40e649b8fe4384c836c000000000000000000000000000000000998549680649b294d506c529ade746aeb087f75d62a246b7abfb69397ed67f0f2ccb4811219b35aa894b2f87e3fcddb000000000000000000000000000000001027b604f877ade32df8de6162251acf2751a9bd770c21f22dc819a4f5515bb276a246ad667fe7881965f0b083d1f76304753af76295f72295645243ffc87ffc2110c9d8dfd20b464760ad965d7a97940000000000000000000000000000000005d1484bad44069b16d1ef4e9ca1db70ec6cd82eca645c2fbd4029ab4ca33d79780ebc144d8774d82518c1fefaab38530000000000000000000000000000000019abc7063361ed64a5750b70bd59283e6a61d55d49d8c2ea2f1be8ea425f040d3865c399a66c253bf38355360f06cdd40000000000000000000000000000000010a97b13b3b579ab5f7fd9801d9e4fc40f3b2b2acb9f21bfcdc6b6a3168720fd0abc2f77ccad01be6a6e268fddf3759c0000000000000000000000000000000004126b5454050d761047e5da23c0b2f9370996589c04f255a1ce8ef37a3a7c8078788a0125e4aa86aafce8df33f322d3d1b8760cc40d093912fb073c5012f910ae90f0a979cfe6d81c603adbb98289030000000000000000000000000000000017aa7a3f1ebbdec6abe12abea12ef50a3daabbf96a5f2ebfb517885f0b7aba1e927c682b15521529cb9e1f87c59be99e0000000000000000000000000000000016e23f7effbb9dd34ec1f6974115e7f0d23cc4553d86e6d61a0c98f47d09510e06b3f987c5bcf4bc30e20ae9684da74e000000000000000000000000000000000f3905dd4f99cfcfa6152db53106b4d1f6e24518a822da9388d8ca1dd654a4b8315697328571691f105d1abe9aad3dae0000000000000000000000000000000006bfd10d33df9326a55b35aa6d2bc3e831d4c3b5959aaa35613156e5e19343b74e34ed2670c43ba1a45cd3d91f055c9aab79d640b042664b23667d6c60ef9a5d59de72aee57a78d75752b350ce56d8da0000000000000000000000000000000016ca071d741363e7c3297355e49cfbdcf03d419813ed7b329cb2b2a26fc6a46cc52149ca3e9ca3ccd7284cfed97b985d0000000000000000000000000000000018da360fdee88e806ea1a61c01e86687f8e5359730c36c876ad2acb0297bbc1ae13d790d1edaafdaed65db9dac02a74d0000000000000000000000000000000005a46e4572f667b46aee36b8d377c249de25e797b31b822474aa647ee68cc7d40b083fd0a1d938e2b8d85508004c73f40000000000000000000000000000000011701bf88d4287c98996ea561c1ab2f29a5da9138338c7c7539a5fc8355efab6f58e240df4b0e0cb7f01df74bc8010501d1a2965e995bd4380d4ec52fe8e65e7fd99b1ca9f4f0c656adf7051c4b9a99a000000000000000000000000000000000576e79e507d250eb4040197064b8898b0142b3a2551875935f91f22705bfec6da156c7858fbf77028d4a00957553bea0000000000000000000000000000000015d39a325181d6d1a809b1236f4a1ba66a9bfa6c448470425aa5c8ef9fd00b5481c51e8752088dad62e928b3180408df000000000000000000000000000000000aafabc2f68a4933c7d734660e422ba154e37dd90114272e948f79db4ca51d5ca75d504cf74f2dd0479871d69a08386f000000000000000000000000000000000b017c731f63bbaa8fd0b0d9c17140060429f515d2e85a938d10f6529deeae4818c29b9a628802d0ffbbff720339b7bf2cfbf2abd851d2c1f55c56d4f8b11b196c020c2584cb03764580d410d66784d400000000000000000000000000000000028c4dacba5f33ba66368c19491f4baa6aea4f309afafcc8f464f2886b1d05b6397142d02f0295fd50825819621673a1000000000000000000000000000000000849e1b630e8db8ef039f280f8d401957f807ca90479745b68c3db1b5ce3a02fe2c099ddf9c387d7ed76ba75d6a9be9700000000000000000000000000000000013b43fabc3d4df82058db215a69776ed5dfd4c773d7a013dba3b4ef5cf65e25f79d7f76a06ca99132d6fd1fdadb59d400000000000000000000000000000000072cde8eb3d3e1a7f7e4a9eedb8e56f5e103db6de6ccf833f818f02a0706b2043d4ba0d5473bbb6472e8aeb28364e1d8214edaf16742762baa58a3d22d5bb2305cb03a1326adc68adcd268428f82a1e00000000000000000000000000000000007a33b95f42cb1d1ddeff3a199ccfd9a5d47c9fcb89dc09b5b3f59dde2b47d24ff29931920b76ecf6deacd70e83576970000000000000000000000000000000014c0a63e0152f06cfc32e6034b7829f9d9d09aca0a6ef821dc61ae8d99b77d76c1b2fafb2a14938a82ec72c4041ebd9f000000000000000000000000000000001433135cd913b05b3f58b2e9c1a3bbb951d2cf6c92fddb21bd5e1d9c44e464d5fe98f0791044d56e50b81a83ef6cb271000000000000000000000000000000000be12ce3bc47bf69a13762343b5e39c2a2f285896e5d1b73c55203cae2f32cccbb4f7b8230b2026a0c8b2f63db5e5bedc1f38916d6bdd5d379967dcd058ebce5887ef2bccd5fb7c2bcd758e374a195e2000000000000000000000000000000001494984d478784b2ab3ba27464109f99172033fcd5780a48fbd5a2144354157f6fca2d70b15b0081dfd306ab4239cecc00000000000000000000000000000000078aebc22025af53c6542abe56cf72ce5eb11d3f19212a0f7442d0a0df907c8aabe0ec01d1245ca237a691e685011bb8000000000000000000000000000000000415a1804a46f4595014ef29b12d99b89600aab1d98352437ab8342abf479bb2215bc687532e75f140918b3d030ad4520000000000000000000000000000000015e7b0dae7e3e80eee3c7a9ed4c739288ac2192f7d80b2c8cf9934cea5719081803b207623c771051d7694e705744dbf1cb8c8303157f23987f8a2d206f3add697b9d0a303393008429e93cd35711f74000000000000000000000000000000001470f82372e197a21aaf46cb2bd3c0b77c3428bf2ba073311e75eb65471a8164753ff1d989560f1ce477952bb6555200000000000000000000000000000000001645b5e5b4bcb5f6d34ac841e3a80f09a86a5edcb7f2a7e7bf549b022c0073e01be82e4c9e5c8e8de76ba367595639af000000000000000000000000000000000b43f6572553154e2530fb448d5bf20c3a182cc190149d3b1d75b60e45baa048f44884500fd02c434f9f7eac01dbe4170000000000000000000000000000000014adef5a52d76a267f87d9a8b5e9f570e7775ca4f6a55a5afbf80baea311b1866fa0689271799a654eddcfe36a6bb64c61ca9ab9c3df673b7ff8be098cdadd8354c17becdf82e7e99ce264174653007a000000000000000000000000000000000345a2ffa21eb06fa1d76fd81b1239147688093c6a44a40cae37f2af26add812884bed3e8b4643675b1a45320c64f7a8000000000000000000000000000000000c58eeb5ffdf886d6319ead9e6e190300ceb91d58abfb79c0a322de3987eee73ab82092eea8e1249e83ab67e33b303e1000000000000000000000000000000000763a3fba513b6731fb501aab39a4697f3e4de89125c6884f9782bfb73e6e062f17d34555a04a8e2959ee4e1a2ee284100000000000000000000000000000000024180dde2d23cd88cd29c8142d32435d0db57b8ce8e309701fdb963533c1cdc2595e3bfc01d8c0d08d594e096afb34a681a0861df30946911d789a5da1f5b89c38fa1a8c0407b608122a18be05955da00000000000000000000000000000000022d2e7502c4d9587df7ecdbafcbb813b1812d76655cb7f9f57418d5ac83d4f60b84a0ab5b53a5eee3c3954aa9fc70cb00000000000000000000000000000000083212aa1316561a079cb8d027bc8f89161fc828d050c8837a24fca6f7f94b6dbf10d6032fed895a427f07827deaf3cb00000000000000000000000000000000021552b99dc02a051ea3af1b1bbd0a7ef64088c3aef4a58b18a29ca05e1f442f8ea2c8fdb3642ee94c5df501ff6898f40000000000000000000000000000000001015a7987d329cd1eb5f991c270643a05b8e1bc35467130e9f53c5d96fc3c8336a00c060dfa2d3165358b51b6a521e56f0798b448ea0d10c84e2a8896f153b1ac3b84c5fed6a4ba6c932260bf01d34e000000000000000000000000000000000c19c3b9d7c7f520968d8531966cccbe6f0c3fa0938480ca3591b7489febdabd56a70ae55cc309e04d7acb3de6f41a3d0000000000000000000000000000000002ddc64023f0de2730d3affb695927eaba50ecb91cdf1f369a511a8cc8dae8913ada2d8f27a65e75deb9b8b648e4e2e00000000000000000000000000000000000311ef260debf2310fc31fb8ecc802200e11400909eba24b14d9500ff47c1c36ec540eb970c9262dac947b0c2053d6200000000000000000000000000000000199c19645375dea7602b74301adcfd9af259e1c7c20f377fd10d56b719f7a6e0e57d780c976124e0675c2a54aae3e0f5a8b7de8f34053facf1338b54cfbe38dad73121a0429663f484277af9a230abe600000000000000000000000000000000123fce6b793de0ce2d31f2c7c4218fb20f9db68946a7d57914174ea773d6e6fe1fbb1de141c742e0a8154fa1d81a91f70000000000000000000000000000000019f75536e004a61c6d7f466bfa06ad0c9375a1028eb7746406e7c71e551dba249b5c6284f635fe26989aeea69075b3fa0000000000000000000000000000000013088eab16ec77c7ce7e84236337e395690169a4ed7e44e23d233d36d5d25e6afde794cca2bee88fe749851a71aabe24000000000000000000000000000000000e627130da43a6ede3bd6f2fcdf008c8f5c7b7b1fa56cd3b367d3096317948bda115d732346e73b731d1921a1da6aaa18823cdb73dd076ad95679a9d7b11145c12a81b825477f799300d1fd761417c2b", "Expected": "000000000000000000000000000000000e3b85a3d6628e097a3d962f3c9aa37e3c5be43faf2a12cd9830ab33c4a904eda23027735bba563d38ae5ae8b302864b000000000000000000000000000000000c92be62cb091056d981ab8872292017cc22ae4eeb0cee03a60cb5d57d37b264fbed2d752ae9dfd76c0bdde1f1dd10500000000000000000000000000000000019e172b23249a17924b890cda6a65287039d0c32b2c0833409816cb21ceb73ac95928234ccf566287400a2ed7d9de771000000000000000000000000000000001276e206235392fdf65e4ea6210d22eb7afd7783caa0777ff0af719cc1822579d5b82fb4c30f07dffe7d68c649b9e2fd", "Name": "matter_g2_multiexp_22", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000a3d974770eda8c742e5d380482d36fabe18901b0217485141c3841003aeac4459ee28b280550e4643d0f50862bf2e2000000000000000000000000000000000369c2bf3beae4e8761f6c06d9bf5261bbedb177e609c81c9bd81ed0a17573b6e10e7f0512e06109cacc3d483918ed9400000000000000000000000000000000030253d0a050986f49c77ee20ea8e3e07de3ba72c39ffda877bcfe569eeb29598588f5a7cedd9e2e34491a059ac4e707000000000000000000000000000000000ce201f07353bf82ec894ec66c7012d17f3c7968b28b45e88f091510e1646380f902c1c5b036084f9497e9a91476dc2c9f2e54f21b7f2116c30d6e444ca82fe800435cbbd72a98a6d22bac92039c54070000000000000000000000000000000018f493dadbcd93df2c614af310e5aec4fac9e502843b8ca8c3de739315d9e9a380f826e2470c96bffa8789133f458d0a000000000000000000000000000000001768f8c3da107b9ac30a12b99f2f3a0f21483c0be334377733cee6024d85af91b03c7ea1c548b42e7a7869141816917a00000000000000000000000000000000076cfc99c16c270d2f6e34aff84832f9ee6493ab757b6361cc921823fe9c30f1c9b1664b650548dba767616bec0fd5d80000000000000000000000000000000006c5f580c9556ed31847b1a3527ac0b5b5f15b9c9197d3cff061c1cf72dc5c96cb5fe98535a4dca8c4e20c8c02158466c8cecea241dd6a924c9b9cc3d390fbf40ab897208ce9d3e4a148b2c30c25e7eb0000000000000000000000000000000010e2d7eb4e874a9c72a98e4c36701a9fa11051b683ac8ab9ac20d14929d72ff7b92a9048a11bde92dc2696467fcb48e6000000000000000000000000000000000eb29e621e9d0af8f661eb1ba90b307eb542dd84a486568f85e19055bf7b8f0a76d34acf276897a01349eff2c36e4b43000000000000000000000000000000000b5f890f22658b207dea2d721d90a8f5991ea2c5ca06b8d1b293f60959ed424dbd7052e010e594a5ee0feda1e93bcef4000000000000000000000000000000000082cdd4d8452078e8b853f196dd76505ece5e98df3e6a8bbb21f422755af23c5ab261accea48d8e4193d6c884773cf6e428fab2c596f23bc3c9e9855b74295f52caf73cb7371c93c65370583f7fef4c00000000000000000000000000000000077501a457d5f0946d25a4c5eede1b7fd80d90d502bca47d8cc40ab2f9a6d827d7323e7d4035f3d32b02401141f0a89d000000000000000000000000000000000985410246c1db01b42728ea46758906883586cba5618b66c21a3cf58cb98e7c6e0dfbabc5505d1d11ca9d047fb6d25f000000000000000000000000000000001775f4008f688882d02355b6eaa1ab108f239890f71238b36c76228cf2f575cd15f15293a62a72f6ad0ff17d7e8ae79f0000000000000000000000000000000004b6967a5ee180d8b92e95c5ef26baa56d8509e1acc710237083d19269c1c5a1f2d1680e85f0bf040747be1d301300b0f7d3d755410f77a0e4b2fad0f184fa9312b559785fb04c6020432465799ebe22000000000000000000000000000000000fee170589e8a3d3fdd93b536347af5002e59e8ef2ac8327a7e9f382560ee9bc36b3f636a3f99fba8be7b5ea3dfbcfc600000000000000000000000000000000032380cb6c043e3f9ef7169da12df1c6529d776b049c7061df660df841840933e514eb7ea3152ddac38daa2c52d66191000000000000000000000000000000000620ebccfd931eb70ec688110975ea24b7ee0f9937841aa1b7bf4f45af88b732b76a26299f0fe48259fdf08abefb4314000000000000000000000000000000000dee6bb8c198363fa4107996331aac07216b82208242c73736be31e14e4e04d97a56a1c22479dd94997acb0d32abd3b0557b05efdd02ac9d8e1453c82a321d798f3106bd18764140faede610ae01fa80000000000000000000000000000000000eb60e98d6cb4e4b3e58271d47261d05be892eebb9a37f6831ff19d0bf2fc235e655f0eb9b01494868bc082c58ed82d40000000000000000000000000000000007254a64a0d94340bcc2b0142faab2d73e8189dbaf52ad0c3a9206e802193168b8eb03cb18b0e4f1cc95b98b943910db0000000000000000000000000000000001e0051fafaf454072051d2aa9512ba2367778aa1617cecf6a7f989d69c7627c9070c349d363f56711f172d43f5730cf000000000000000000000000000000000f4141c8a45448fecce09908ddb42f7b5f6b5bb53b9e1ede0417bee327644af5c98470e8b5364642fc7435f84be1ab443313884abc4d430c06ae843d263f2efc1bba35f6cc270de05551e1f86096bb7500000000000000000000000000000000049c28e0bc677ccf54f4cb46e953a057ffad624752332fb9ee5295438fd5bd61abd2199a0bb729bb7678cf3077e32ec10000000000000000000000000000000007138a996356ca3f5d63bb5a36dfe901254459ed515e18ec8d91fa747a691b40a19878d9a6f1dc74e4f18374a399d38f000000000000000000000000000000000a621b36a3cf04e6a5cb699fe4ff7fb8b3361207186848e81972fdaecf667ceb35f413bd68772f7c1f77c1d3f43a3d610000000000000000000000000000000010becda5a06f3f077218d4387158e4a1ca5e0ef24d4ed304723ed5dd96da7cc9325f7e4ae16d9d6c348577697aa6017b8faea236e782a8fbe27ab15f051ed007a61e25247f1f259b9300974f521f30c800000000000000000000000000000000163ee307e0d0c3b61ade05a022ce2bf315d820ee8ece60f93d63a150e02be843a2eb2240a4882c29be2c7403932c348e0000000000000000000000000000000001fc8e9ca23e8dc8457df8f255db3b434f52cddaf05819dba7df1c5bfed438f756c8b57442197af18bf83fe9ee2b765200000000000000000000000000000000109cbe5279ccb592bd0b33b1a482df53459c48cd0913549739b784ba7ad32872377c2e3924c4d45064b0cc4764220513000000000000000000000000000000000d789795d556a37a375d83120a022f57e26da6e6f9aa3e40e1f32ed04b50fafc4d40d0b9b20a26e4d230dd789e20823013994f5645c6ce83741e48ae472674921bb2d9b8abb7d04ddbbb85a3f2f7f090000000000000000000000000000000000960654bd6e6a6b2f7d87c3c4d6e3fe6c684a50b62f7acf82a67075139a614c056a41cd49769960e229cf07468fc2dcb000000000000000000000000000000001727f2dbcc8d889127060de0079207eed1e094259b59a20fa42ab2783bfd176da00e61a65709dcd60402398fadf30710000000000000000000000000000000000c17805a01e64c320601e0ef521b6573e9c2eb354157cf0412e5c2b13f826759310907c4b77164f5899958cd30f78c030000000000000000000000000000000010fb286ce797c0429ad3385c709259b55cc962ae02c814e537e5261e897b7ee1b7c660273ec908110f997b166c14f5c181eda24db328588e8c670ab70431ddeebb0749b431bc1bfbd992c91f35d59b180000000000000000000000000000000015d96a0f988f4951206aeda63af85910db49ab817c83e218ec74cbbf5f34f81279d8a3f2fd1f3000f73b8c5550af3fd600000000000000000000000000000000186d2eca1cac226227d8981324859126864b84e8dac563b4d92357591c2416c93989cfd9e1ab6ad257dfeb168d829a09000000000000000000000000000000000a8a7247a3b09583cd2d4949721160573f1f88221e6eae833128914555a594f21a3fb2bfe3b1f01f3dee90f7772dc97d00000000000000000000000000000000132361ac1950756549c957c174cab9ef586eb2057a4eb22f49252cae032975f56eb0cb7ea70810afaf5716afde5b88015bf25b5070829e3d5a66ad24ba9930f3ad64767c51e432b51bdbe2fab470688d000000000000000000000000000000001328e22bb83331adb09dbed0a8c58040a3564fcae0ec85794f26c077de69cc0a7555f011e028879cb3aafac4dbecab33000000000000000000000000000000000a93db348adb3886802bab1e993f5d7275360a5b0466845055d5274e44716f3e1d03a6e1796ed4de4c157dc8a2d92c39000000000000000000000000000000000dc0879a8e9556b7d9b6d5dffce5e648f835f10acad3afca7a73b0fdd5d5babaa74a1ca80aa4f6880d9b015501e218a20000000000000000000000000000000003f7ae8207de4a179ae48cffc8c6e926455e46ef9e109c08be3ae7401bd36e0876642ae9ac4fd75a74c67ffb7790e265a9535c082e11b366cda0000d8ed0f92ee30fd2c4364c163a718518321c5e85d2000000000000000000000000000000001078f43093602a2dacf9b5dd7ec41d47bff02e0dd27a996b58c73febca06e3d977c2fbd73f63508243696ab5d8b97b980000000000000000000000000000000001841869086e850ad97b3122fa51c437113d2bca14deaef5715c354d3845f6829f6aebe668844352d5af3509c0d8da7800000000000000000000000000000000047c42e83194143b9e977fa1babf80d455fc86cf6cb491ef8306a1c32bbf8c868e11bb3308dd5f65fc2942b3e49ff5c50000000000000000000000000000000000872ce87ecd22b39b14c9036e971a562d51c5122bb10939cdfd1945dd1445ac9f5de06b70931aa5c86cd0fda51b89952c4cb49adce0292e259e92b229bf7965864a945de86eda3ce0bc9f1a6dc8b7b200000000000000000000000000000000157820de2a134081eb47b1800ec72630348583d77d512b4c6a8c8e581810471a2f57a8eb6b0af87a91960424009ff124000000000000000000000000000000000378cf11b0a2848b06412aa754ddbee5660730001db073724caf902d4b4894959f035a8838e28554b0efc2388f2b4f27000000000000000000000000000000001301d15f290dd11c3f8e53407195e02dbf8f13e4fe25fe38e84740753b5a0032f8dd07df3ce46ba424f6772b3aa66f4f000000000000000000000000000000000d166040d457187232f8f38f2beb1e0e0864105595764022c282867346166e46eb789786a7ec7c00b0446207e9ac1ec05e927f57aa85b2df54b4bddaa041d43766c8929c8b9146d723806ee0cf042275000000000000000000000000000000000793797c5bce4b1cc3bcd751c5ae1d293477af96a0e7c6bd392ab4410f806a53088cafeed51754ee7e60e61dc200ccb00000000000000000000000000000000019d595730af1f3039e37494b86a638a528d8bd24c429e3f8bc97076c7463e7f2618e23bd3f300bc7e7a4674f14f8295d0000000000000000000000000000000008e245c7590888fd8dd58f93332b81f48b6e3acd3cfcf5f3b28df654eae1172f52ef5a121707aa9cb111b0b402d1bfa6000000000000000000000000000000000a7c6403659e1a0c2dc7cc2e9b57a452bf553e96388676f4bf4a6e26b3ca2d3cb82006850d8340dacd65aaa0d20e6fba606ee8a5fdd9890b8017f6c432a45517d65328f13f3a2bb42d7115c02929db7a00000000000000000000000000000000054c37e8acadcec8a795619647d4cf1081a0592de02bef916f847936a1736e74cc3b7ee018717495def8b4ef1d098fc9000000000000000000000000000000000291d89d152b414fb5e7139d6d0bdc7b5b9de1fc44b49f895ae08718b631f7652bb4a895fa11149b9a9db30c344108ed00000000000000000000000000000000107b30992ced35e4ba874e436bed5d88aadf0a0c944ca3eb8319539017bdd652feb7483ab6c705aa17e845723b2cb46a000000000000000000000000000000000895dd8e04114fde4a4cf19925004a72f617f2ff146dd650a2cdbeb12977dd2b34ea7d655dee16ad9560b144b81212f5c1a77ccb4b32a762d60b37827ad6c3448c33af6af861c131adb5920ba3c2b85100000000000000000000000000000000005cea2e036a8ce057e4dbe2d9d786eb759c2a75934580480f78d2e228c3150a0a1d8c95ac5013aae3ab6e35f524d37b0000000000000000000000000000000000e18c18884209f9e4fb17431248a5f8d29c616a58af16e949f4317c2e117b80d531a39800dc70f6b161b98ba040a8af0000000000000000000000000000000007c42ce885d1bae906128589b72f2e6c18e4eeacb78c853e923e6eb785c073b6490b2f6b3dff2276916d96770ad5019800000000000000000000000000000000132d809c37c341eb0304ec933a6b11bf9ac0d2a13ead818ab6ee03ccc94160b405066381dcdb13b6ee3f5dca48ee10ef47cde609c38eabf457cdbd1e0c5366bf523dd5801d66a0282bc187d80417f455", "Expected": "0000000000000000000000000000000009406918e2dd6f06f4782ed110e29516a911f47133ad8adc58f5780de916a8973ad60e05ba931d66de7545a92f388c20000000000000000000000000000000000041cbd52cad2a5f4c8353c7153b5711ec23fa8bfa2f34f5e1a16d8a14cfd47c237766880debb992a05ba9ed0353beea0000000000000000000000000000000017d4211c827379b310956371129011a92d62d11f0ee5b0cbad9eea2d3f2a95d364717713fd0c544747338725adf27248000000000000000000000000000000000a61903fb81064614c9c6894c7f3954aace7611cedf6bab8e751f0c203bcab827d296016947c071d7b6ccc742e28ee9f", "Name": "matter_g2_multiexp_23", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000007f90813f8c3eabcef04dc1bc9bbafe1dafe220e2db24e4b714aab2b164d7ec9df3e6a3f903e8b7b96df2ad8297381d2000000000000000000000000000000000e34371e51c4c952a0f38c4aaa5fc2324971ade310af2f36ed511fc5fd7a602a551ef77775fcd0f1fccc718710239561000000000000000000000000000000000787edf7a6ed6b50afcd7c0d3876d8919273428bc49833e3503f650e48e788b15cd82eab2672f612025d796bb62d72bb0000000000000000000000000000000006b49e631ace4f72c959919df5d64c537537ccaa3d1890ea9a1d70f9eacbaaa2ec361edf2d4880c9810976c6073028bc3c79fe6374bf8f91bf7851ff935a124b54fdb5db498d2d37939fcd43bb93d29a000000000000000000000000000000000cb63d7eef2d6614d1f629756b3a619a221033207d1621e4ce4791db4248500649b91ff07cd2f1f06eae3a9be5b6af080000000000000000000000000000000019aafbe56da1569959019033e8cc785c9b98bba6b069603969e7ff1150f023706b461913ea7949306a44c3b7d199e86e0000000000000000000000000000000005cdc3a7004f7a7f79ffbf4c4ba7c5dc30ecc62f270a5c231406fa63d82fc64f45e94779cac851ff8443040fd3b2ea6200000000000000000000000000000000040f30dc98e8668194c9278b189e0c0f7b76a4c686ce26a4a96b93190938f07c5b813670e206eb6b5da29624a1b6314ba59fcd2baa47621ebd90c5cd12b89f2a533ae86d537fbb61a14b1a80982c9257000000000000000000000000000000000a5a1bc231f803ae272e497f812ebb663c2ce8b43a366717fc6349264823ca93e29e30762c1a366d8680f81838907f59000000000000000000000000000000000a88fd59ee380449d632d7e1b926210d984d5298fa807570a63a63828cfa55c6e2f01b7745848281795dae36e562181b00000000000000000000000000000000025ad34537909e07beaaff09f22e91e76d93c668d1b45cf6845ab8ba0129e417b758e85a7100a31a9037e307f454bd370000000000000000000000000000000013590106126231b1c616a5dd7aa7ed6946aacdacec963b507907950d6ea11cf1f5b59f819a43eeebaf51a1faa7daa8e719ef9fdfc5f0c4ac41255eb172d485317c124211498a8b9a74c0bfda15b986c5000000000000000000000000000000000938d43b9747c926c3e2dfaca2d6f1e6d61d5a621ae08c66a5baf33d9241771509689f9ea7d75af607d76b66faa8fbc2000000000000000000000000000000001889a48a74966b9748f4a6128dc3d75a69499db1ba1bc9aa3a9428f0efa898b5f78a9e2dae942d3794ab3d1157a1d305000000000000000000000000000000001129c9bf343f476541980b85229c5c25289ca62173e29b75de431b572c8f01f64ec1aa4625dff9e7df535194c7f4e6e7000000000000000000000000000000000fe95c71f703dcc71cf409b332f66fd69c330758d41832236a510ec4bd9a28c4732434d4c3f97445e6301e3070153dbbb8ba028831f429d027319a92fc0f30def8b97a43da456ddc79443d9f8df72cc10000000000000000000000000000000007649efeb3e0bee49b9adb13f8e5d7db1c06d7fde08a3f3082194153bf4b3615aff1450e47fae88ac93f55a389a319da0000000000000000000000000000000008334731582fb1b6125d7ee1da0124fe88f0c70a0a3f6188636976c31ba6a72beed927fe598386f328e4ae534729a57c0000000000000000000000000000000010b57d80fce5cdc90bc93b3bc7a1affadd19fb00aeec2ca9a6287bf4e40fb74616986a44f2f7d945f58501a965f37f3000000000000000000000000000000000180dcae46ee41bccd422b3cc2b34cad26f6816dd08ba51b2f12835e7439ae2d46933de28ac04bbcad68a188e7e90ee8dedf8a6d86471f58c69c1a5e7518c69c34165e72ce84fbe0b7f69d9c2717e5d4d000000000000000000000000000000000b419b675ccee2509daf66e5da4031b08792e1181140b30489ae21f7925305d8cdd8a104580ae5938586d6b8e74f750f0000000000000000000000000000000012e070ab7118991a20b27f1a87fba1f5815665d76269f0d3d460a6b701e57ffdb4fed2c53fa63a3121c74f67e770f31100000000000000000000000000000000124218ca85f235eac3471e0acdabf73f79afdd4bbc159c1e34c641b97f03735e4c3430264f2d94f640486488dd1067380000000000000000000000000000000011c24f4fa1862779f22a628edf9d3cebe0f7593964b642f889201ae85e8fa01e00e48355053f5a7c6d920dcf6a7ee1d60dbaac3f5e25ca3d1d50ebb31258ec4450feca1e02c84672ef15c49b4de2cebd000000000000000000000000000000000266bf0d9d5a4fc713dc0fcc6ea6edae0b326e22cd97bc49c48a7ba398fc87d7a0c7141ba24d80df454de66c2b5a55fb000000000000000000000000000000000aa8f95c7cd61733b0a260149d6608a73d6c1f989afa8cb2aa4098e1fb5a66b4ad5a5c1c4d901aa79812385fd507f02e000000000000000000000000000000000a6b4929df13e1fe7f0a0cf699a7fbfaa97d7527cc3ea1f728ba59def2e75fcf3490199bd42e93b7d47985a307add07c000000000000000000000000000000001719321981d2085ba31c9fb131d6b79c7df5d10d6ad0b5015454329697860121e781093fdde1f19e897dd6f2c272f87a109ccbb8fcd4d4651b84f4708799d84ad0a717aedaf5a76d2970a7b93bd23d37000000000000000000000000000000000431002c9926aa7d2b06412f544a868a7d48fb5f077dfd098febeeafc28b876c434daec809e5cbf50ff2395ae7e456560000000000000000000000000000000005a15f713b6eafb09495cfb1c89e9421515a07a99ca0f208883f11c430ffe6f2592dbc41bcee5db36385a26f67cd26bb0000000000000000000000000000000008dd30fdd7767486844967c5da0803b52282178287b8ef28e14f07b487132fea3a82d86d414b4d0a25b3dc538be11b500000000000000000000000000000000002dcee67e2d17b3106dcb9f4117456a037ae1996e8f7a09b179baab1ee8345c6d01eae554d3f40da86bd79a04702fbf76326fded2b8a3fbf7637bc25bd201d20e3d4d724806cfa678ee039a39c24e86a000000000000000000000000000000001629fcc374e99fa8303a715fb5077f266b13367bbc0098b5463d3298c0892f83127d6b7f751446575b88858bc742586c000000000000000000000000000000001100783c10618752d25c235e1e76dc64db94adce05651fb8df0a5ee7c299d35b1319f7009b857892ddf9e90c91f7d23b0000000000000000000000000000000000ab6996e4935131becd5df288dacfad1e69b41e200ca7dc841ecc180a81b9d2ca14fc8a76a4e7bd6f924bb9f473de62000000000000000000000000000000000ae9b22f8dff29e5e0a2ec5b5641f53fb5e1ca03130b49d0c26696ca4b439a9d998d9a364ac9cc5ec52df699318cffeae005efa8ee75dec8a013029292976e107a507ec09e3c34fb4baf2979fb759f1d0000000000000000000000000000000019c557ae1c12ff8a7c00b7c9e4bc3d65c92753549c193311a38a84bccfc090052a2219461a9691affe2d67ea4357cdeb000000000000000000000000000000000cd35c5dd126bd4b90dd671f29953c5a49a14b6b3fe946991416edf235c3eb3d574613d27b05cd879518fa7dda3ed39a000000000000000000000000000000000224392063b0825fd332bbede23588c1912e7670a013a99da5507f650dc4284431698a5b4e8c180269af8bb30e4fc8450000000000000000000000000000000002ab8d3250d4bb8ceecc8ca2003f91420d0ef8a7dbc2361e5e7fbfcb59471a4c525856bf796a2c2608d219d215cf83fe3917f8baf17f71222166cb9b6c4beb2e57d0d054cba3f7fd3a28cd3dc4b409490000000000000000000000000000000000911417908c2bfe4f63a388f699b31b47df1ea0ec289ee3f96ffd0c71f3deade00d1841aa56b4bebc2adcd3068adf920000000000000000000000000000000005467c7e58e82089fa285c28ea22c759c7806d86fbdcdcc8e09e847d6330922a61bc331ae3b5acce777b7809ca98213f0000000000000000000000000000000010f376fb47933b1f701dd81cebaebb2d8d8f5510a26fb3e9e156ac5ecf2b943c5fa2812d52da542e6c335abad8ecce3c000000000000000000000000000000000dcbf467432acfa4eb9ba11a7cdf02f9110f44ac371128ff8f1f98fc70e4554f057a4608180bfa54d99fd2da010594f6f0f73e1b62561f5b0fbc409e6534ad9e37d1c0724b35cdd3f94bf6489e500fbf00000000000000000000000000000000179aaa7119f6fb986714c03b6db16f25eca7172d24cbdd318bebb633bf08920f9e2a8136c94e3ec7c19e57ab51531b3f0000000000000000000000000000000005937c484213ab5b2ca8ed1c5c90e8d2a2f1bac044b88c04b301ff2fdbe67dc4ea42779d919ad510cabfa2ccd178cd9f00000000000000000000000000000000183cc23fd64514ead63f55d375a07af7cf2a56aca64a887dcc542f8a396468a6abc776170a5d4b4bbcd4dbac285e7ffe000000000000000000000000000000000ce12228dec2f84219904d9ac7923f122a99803a9b34749ca68ba385c178811685c19a492aca2e1123ee82a8a9cb90fc3ea24fb6447f2493c78a267daa158eabb70c1b60af8175d0d4594c99122cb4420000000000000000000000000000000009612bf9130e17110f8b15aa6f3317071daf3433bf6d008c383bd5c2fdc7ca03f25ff4cdb483de3c84c0ef9e579f38c6000000000000000000000000000000000c40172540a7e20eeedfe02c37aabac07165cbf04830f20fa76fe8b05c826e7762c9f7567a0fb972212bf736e627948a000000000000000000000000000000000f49e5b1929ad3ed5c07670c471710baa24e8478a50f72a5b7bbc23a66cff91d30a3d68961fbc2e6e8003d08196f325c0000000000000000000000000000000004ba098f915ba9e934384682648ed8d4e1cbaae60d596655fcd9c05f4b049ba0d278730dba5ce3fd4892531a3153bb955ed307c01d9e29a0571de07c62d5fcfc80749f02b8dbaaee9f69dc9263e99188000000000000000000000000000000000449b15ecec6d6fe5cd32437b54218f62527157aa6344c635fcec8f8305c8b6e44c93105984e0832536237606f07792e0000000000000000000000000000000011e40e8aaf75f5ff8e4040f725ac27693d7b24805a2539ff54b3a6e90c048875ea9609fb8fb3d8de63ca1118876c172400000000000000000000000000000000006ef2a24445f728b53cbf01e5b076acfa7761a84d8261cf1a1b99cc32f330f32fa5ded83d5cd51cc284207adb2451ee000000000000000000000000000000000977966380e772670447b15ad9917035273eb71a21c37607a761aaec808909fcfed50679769aee1573d73cd241de6624877f31ddcb55d961bf9bc09903bd927451390922d647d589302855141cf5cef500000000000000000000000000000000074e475c0ff1a51a24be3c964c45c41f767f890dec82712d92a965be504fee43fcc6c0684b2b17c5b294a3eb7ceff1cb000000000000000000000000000000000597b7dd287f3fb27e35a9e4e1718b6b1a4addf9e95e93aeaa25aa34023669368b794a08fdb178d9bcda2738534d1962000000000000000000000000000000000a492d648393bfa317165ccb552e045fefce5b3444d5ff770f43a08a68efefe7fce1216114ed1495cd00f832538198180000000000000000000000000000000003d85cea8063828ff025ba599bdf1efe0412ed5ce06ad5faa841c6400e4eeb6aea1470d48f4e66fc768d7e7bfebedb37145c1442ab82241f56c27dec2cd4dbfa9fc3cf1ab72bc521ab32a82346f8f6070000000000000000000000000000000008ecc3dd40da2a7a348b4817d9c84242f2f07c5d0ef810dc08311e9d4090d6d96d68b6c725ee6c24de076c71754bc4b50000000000000000000000000000000018fb3a1dc4e0dd9227fba310236a6db7953f0b716fa995b928a2a8de38edb97eca09fe2ab385037dfdcda2ee577e677900000000000000000000000000000000062fce7fe7810273a80760d9f4b3be9e7c821f38ed3e075210d3aac6aa7a763e3cda56465f88b34540b408ac850742080000000000000000000000000000000006fa94466cc47990a80ae6a310ea765590a0e646b5988925f03cc7e30f04fc0a8044b403212290b2fc46c77e84a9028dde4d1470f6cbce027465b4dc2a3deaca14e34218910aa76cb45d47139b31df88", "Expected": "000000000000000000000000000000000f41bad0a932e28096e51482c646dbdf294aa7b91e0ec258670e7674864765c76989a936fb440bfbf4268a49f450d3230000000000000000000000000000000018282b76521db98f589b1c14e603b6f5d27af357553bca761189a38a944a11c66480f7ddd89d17e4aeddc8d78a2b3a0d00000000000000000000000000000000007efc4a90dd97f1312047ac78a3163dc014c42a44c7054daeefd5b72cd0488832cb6396e02ccff09e4171d790954fcd000000000000000000000000000000000e790fe8323fffc96705a42ca071532d5359641ff7cf8714789c9c578717a054c811cdb581df8b6a43729c6c3e3255ab", "Name": "matter_g2_multiexp_24", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001304e0ce6a4baa6e0545fdb314523fc91f73eee157249b94f284ba7390b12b23b1c849c45a563ac82b62a2c48aec24e1000000000000000000000000000000000a2d0e9e222db70d49d1e85f587d35bdf5e8328aad14343d296f95b152a79c83a4858cafc350a5df1ad0194c49bb929400000000000000000000000000000000199efb09b34d0699eb4bc1c57fef9cc5d98453bf522c504fe7897e22bd0596a3a6c310eb351e15e3f6609b074b240f7d0000000000000000000000000000000016b69f12ce30ad1a65150094e29d4cd82fbce5dc343517ba9e5d89245ec083c44af9a3dad2169f713d3b01fdf70d20642576b42e0728db912a78eec2b7b4c96575e341e86a7592a07a660c11e0044839000000000000000000000000000000000b3ce4ac12861052c602e71906a7c9f3e2186bd2b6eaaf222d8e80b48baee537065ce78372ed936e6728b9642ba1fdb9000000000000000000000000000000000e8186561d23515bc58c77769c93db76dc9c62bb715b283cbfb71462451120a6ded736cd8a292a6799fbad7617d9aa84000000000000000000000000000000000368a6dbc7daaab0a786257c813b1a25c97468732c27cc759fb921cbc3c9a37a46d7dd0298771c447d36ef0a10579ff5000000000000000000000000000000001348d5e34cbe54e3a6b357c4e651acb82d2dc40ef9ed8bb89f0cdf0882ec6a737998f4e4dd61e296d101cbaabccdc3e779f9205ef0e3a85199c60ad9267349fdc7b6fba4cb765ab21750eb3dcfc48d8b0000000000000000000000000000000004ebb53c462239a78bf13f29856ddc4d78645c457a656f3cccec9d3c032ec19c26488f39e0f5bf0d38424f9e3a9bcc870000000000000000000000000000000002fe1949365831f7c38b1cd6cf2e22345c4ce40cd73def77889c214d1077d70e39578e8be4fe5998f59d47cca7917280000000000000000000000000000000001152f2df1512013a42ac056b75802bc35c1883efb345cefda8276c594b061a0b0f4a49d8bafa6fe251658ee76b2493cc00000000000000000000000000000000094f90cb386f7933b2ffcdba5e46e09cbd7d537c12bc223e76d3a88ce9063a7b3574d3306365d65dd4c6505f1dceea53300679b7be7c71224247e8034f5d30a63f8707d92d843a703f0fa93160f6571500000000000000000000000000000000169d9469c53e55768c9312680ee82ee581727e28cdb1d6fcdca25d0c03f3da2ad6572039f12c90b09cdb843bc506e07200000000000000000000000000000000174528257f6d3542f754ecbe97eeeea7d196ee4dd01852f6cbad87fbeb4dd7d3799588f17aad129a15549bb787468772000000000000000000000000000000000c9ab635bdaca1c488538c0830453ec6ab3b2b62447c03ff6ffd2712bf62e02a63c76c79d41644ea412e733128685c45000000000000000000000000000000000172ef0fda359bab149c8c04f583f4ace4d1b148426e993996d278f79ed2c6d3933d6cc5fb62ec4869aadc773d3084ca0454b01910548432a0f706818a98151e38ff9e854f1faa95ad41a7239b5cc4910000000000000000000000000000000017060fa73b58957d12b3996d67b7baa8b7f0943ad52e80e5c4f8830d33dc74c0a39e08594b647945b402299ca861f7b10000000000000000000000000000000001efdc7f783f9977392e2797a3e0bed222d5b661d056aa0c7e04a493bb9b18048bf72aded134941ece78d63df0a0868d0000000000000000000000000000000011355198320af05f2121939e6489f31e9e13b3cbb2cb30c9e675854cb8ec038f80aa2f4b6f995774b36f5f1b6a84298f00000000000000000000000000000000172e18c490d0cd5ba2449362c0ab296212dbe69ac25515d0f91941d300051320f067f946dcaf999554f55f1f616adc0f3685617371b27ba8898ce7f30776d817ff09ef68a9d6721d4a923ed244ae82060000000000000000000000000000000005854f4dba62d1dbbf3ae16f70792f1bb39f111309b454a6400d2916e619d4f70764ecfda7eae5c28cf1d178ad53fe6d000000000000000000000000000000000ed0bad1f5d69a0e621d137746a9ecc764931ab89f24ca827e0340ddc03571ed697f63e79cc58b946e8462099ce4b1d70000000000000000000000000000000011de76edd1cc2f9ba06b98593a24a7a011f2701b451ea3ccd04361ddb678e06d91a676e3f11b62c68cfc05242cb8a859000000000000000000000000000000000599726b5f5b93d414f9310383ed9414e4675d644f83ebaa63dceb2bddc7dcfcbc17c7aaaccd0ee32b0875952554b4e660cb5aa2a0cd1e8c3fdc06a3a1f6f9b6d52a8cc2e98c85b8e258f72d03efc25400000000000000000000000000000000031110347cbea2756b5fdd549d6c0b8f4036f5718d41dcd6c854a91c9df29bd464774be479d0efcb8a3f82cc7441a6c8000000000000000000000000000000000e24a52dccfdda3689c87395e45dbd46156676d9eb2cc09dab22ef7ff0acf5ea243ff117c82b147994d65aee8605b2fb000000000000000000000000000000000e0cd6ea0bffc591c13c48bca0782fecf8e128b0b842aecb06f803a223d32cc350db869b7a77f8e31b05f36bddd587ea00000000000000000000000000000000042ff4ab4596d610638ad23eea904a82701cdf61f9e2dc5832a70e11e717711a2d0e72f32f74706d385a9567426b4713addb1fe778c84242953db87d2307b40eeb776f17767c3a4311b5d2ffd738f151000000000000000000000000000000001517efd853800946aa37868b525e58fb488bb69755ccec806afca2d21bd3a30ba46c39cdf694ad0ca92841760437c3c1000000000000000000000000000000000e5591c339e88544660380d6362f4119c5596f910d4ceb96ccd4c4d9672efc50805b6fedffa0a48d126aae69b241d3640000000000000000000000000000000010ea5babb0de734641f63eed2eba6124377b5c55e429987917c0bd109d7904766a10b0d2dd123413816d0fbabe25050b0000000000000000000000000000000000efc89ee2ffa56193129062ca55a3350bf50e8fc7d586fae3636a70e3577987fb0f8674d383def4b41225e490d3d81528416b4b4e965a5f024723fbad6ef2f65a1381e70201e26ccb40188dc3d0fae8000000000000000000000000000000000dae4277d62e3f3dfffb80818a5ba5c371a48d73b92d69a168ebab897ae8be206fdf776e9f955136d7f7f7b2903040270000000000000000000000000000000010ca635ee2e49cd6c951d75ffddd11557432726d26564239c611b139329a28812afe21f094c0585675f4f233233743050000000000000000000000000000000012378b2ec31119e508fd9ae0ccc4c2603b6820283284a278fe16864e5a18cf7992d850c1d6ebd1253103c219bd95ca4c0000000000000000000000000000000018cac4f0660240045214034cfd8a7e40bf0aa12f97a23c4e27db0e05bb25f4d755276a91a4e882a0be63437a522943ab78077a51f88236dba6d16d7fd681c631510106b0eb7448df456eb9ce758e74cb0000000000000000000000000000000002fd5571c818322d207d58fe0a898a045a26c95c2490765dc9ac663a0de78ef5fbd05b20ea96dc5388d5b2ccf13a5e320000000000000000000000000000000006ff29ccb768da45061ba4e01c90459ededa5e79513917401e7e37151095ccd4656aeb9cb7c083cf27b69377295934cc000000000000000000000000000000000414d34eac47430495be735eb5c4b1a68372abeb43658f27613a9c8b78f17d9074174a8deeeebb1f9cda5d6198bdf89d0000000000000000000000000000000010b11bf63b8c39c1370e8fdbfdcd149fea88eaf1c0a94a51bdd061e4c41abc626a448030bf9ba880032e9f1642caabae871716e790e1a0120fd26d169b8ffe3fcc0d03683dcdba7d2f953f05444076ce00000000000000000000000000000000023eaa08a44eebae674434b013ae9992c75690a3d0de53e4b05d1c0dff249feb24a12432bcb5defe25ee4e44a56b27eb000000000000000000000000000000000f146ac27e685cca04afe8fc58fe853825f5b0009e8831eb0d0121decec23b25bf8521da2fab1508a3ad8254865fbee70000000000000000000000000000000004af1a525d3c33e0b1629cbdb90c56a88d70a28037c87db81c59bcbc811c8f0b98aa9dd574436c9f600c0e8e2d194c0400000000000000000000000000000000170efb5e0e69e46a21ec3b972265bc04b9d5ee926254f61c0e18fed013922e00f1897cf69889576bb5d54810486e7f2776ed0a27553db6ac6d3959ff4c9bc5807fb7d4f0a56095ed2bbe31dbfa41827700000000000000000000000000000000111c832a96329d6db203fc8b6bb5b7db01521529c91c74d9cd71dc78d067b36cb7eabf1af80129a7a3f44b719235927400000000000000000000000000000000097339c17816795238629d4ca6c243a14e9e227e9bfc30370dbb9e1475f6d03020dc35559675121792436bacdf9eac4a000000000000000000000000000000000805870a1efd1fc34c9b576b77418ee8c0d36aa9caf9994a051e1d55b49275f34cdb55edc74ffc267c5776c8d0e113ed0000000000000000000000000000000001513afdfc2f000e3b725fcd0428fe72ab2413ff2aa91b44458a5249c9a160ee27bca01d2fc2e230f4a80454769961af95ce72b30d989889c8779c4056e441bbcd93629efc2877d36d27f670711e21c4000000000000000000000000000000000485b3b1f812b4a28ac87d16f86d8d634e85d49d6dc460646e1224de662e906002c44a1a269c3bc011fd22afeb2d58df0000000000000000000000000000000013ba0752444a794cd00c99eceae51e61c382d0abb26e5e0e595d59321447400e8a8f7d97390bd217fb50bc22cef34b2300000000000000000000000000000000184515a36024d0bf71d9fa4cc5165363ff94ee9f8579bca653ebc0620a9d3146fba70a2f4a9f6bd3777101de0d32e327000000000000000000000000000000000e041422088c0343f7704e726d65ccc4216c4a1bde3668108983643663cf0249e992f9acde2dd8ff478dd26cd8d9434d06d220f64de05bdd6e1140c1e409fdc13f43bd31cd94e633be38ecf22ebd77db0000000000000000000000000000000005bbb0c55fdbc59992c83fc0ff03f677e58b6de6f8649141d88963ebfead9383d692015a7b765b727eacb6de250351ad00000000000000000000000000000000183057eca610b8e07fffb60d21bf2eb87981e6e881bba04ceff420ca38228fce2f94d40a993e2aef09e209f3990dd14a000000000000000000000000000000001231bc55242bea6b589cedd1d82621fb71c606ca9306b268379dbf83ddb1420dea228ffc05cd8b67c38206f3f006ef18000000000000000000000000000000000f2c943e7a8b0ee00fc4e4ba912b94f68f504d2783babb90a3781b666b31bd161af2f97a77813eab9ebba76040b04155257da8ac7d23c5ed965d8bfc76a642a36ea6ec4c45baf6882021372e8643f09800000000000000000000000000000000054bd97b9cc979006f734ec433e215a4e8afe468e69173384bc895e10ead3749d991ff8ff203abff30bf5cc0d2fc8c6c00000000000000000000000000000000066b73a98d5f5ae140a5784c5594892c849aa7f2db3b5798643f755743d401ca745d810fad5f4a33e5b3cf0fd7d96f7b00000000000000000000000000000000007caea93ff5cc6ffc033717220a215ac4ed7283945ae77e62320a0bde13f2153dc8dd401297cd124b4c67a4f3839dfc00000000000000000000000000000000094568035ffff439e3d3201466f3a1d43414e3f6455627c5479c8b7c55130ccaa5007ace7ef6a2b3e2e5a4c9543dad9163d017ba8c7ed138b1bc70141abc5cdc3afbccd8b1db5a6b5f775efa62b8dbc30000000000000000000000000000000015eeef8bcbfac04112931e186f6fd48b7a8ea891ab364ce8266c5fd15f072f08fb3655e324795df182a5ed1c917a5db000000000000000000000000000000000028916fcb3b30a7f95321a0998e544f9f4f578be7a9f866cf72d6b8baccd93f8935f105ed26aceebb3f9c96073a8be180000000000000000000000000000000012b11f356a7e32f3d9281a8999363aca0ae5c1a058724cefb51583e5f217257d47ca76d21e54ab62260796b95f9d3ad0000000000000000000000000000000000d83c75c36cc8dea4aab47823edd26b4492da39b93a15fa454aed4175f28a025ad2c576ef2d76a66e666bedae95cef1a7a16e23e37ecffd514d47199cff249415a6d366fdfaa82450f0744520258955c", "Expected": "00000000000000000000000000000000059443f363ef0c65973d36469ac651eec6e52485a07a6d28112f4d0711802d182b7e6fc56d4f1aae51fe1c549247d885000000000000000000000000000000000d22118a6f1cd06ee14c63f0e005076bfb061bb85ed184b5444c08ed9dc35f77217b6daafeac89a973f2c73f00e0d3c800000000000000000000000000000000180430caa9917cbb40e3ada2de8d685b4daa99639669a643b8f5cf9a4a55d6162e9fd7f5d4989a1a6588feb0273669b90000000000000000000000000000000015d01fba1192f0f1acf8fb32fe790f0448c6563cf8ef5505d9378fa2fdd38bd99ba938077f71bb8eaa91a99e787e840b", "Name": "matter_g2_multiexp_25", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000012d948b5268524659e29cd407dbbe8f529e608193ab9452f936b2f6fc0b81d3a63a0e929329e2d89b5475dc2d73ebd8a000000000000000000000000000000001219e20a081837f4d4e33bdffda08a946bb9cd876e42e2f561ebfd18ec439e0104b43de61f47b8b7a0c346c33e632be60000000000000000000000000000000000a135c72c45f254cc1c260af803e14cd0f89c2ac3029629a86b05acd3440465aafa4cf84e69551ae772bb55802a90ef00000000000000000000000000000000052750c3a99974f9044531dee9129110b99572cf283b61e6606f1137a87de7344bf01d2ac2f8a1db8d815b6d9e7511fa26a9bd0a71fd58edf81459152782733536e960d27e35f9f84d00da256bdc118c00000000000000000000000000000000136b2f21aba94bbc8e5235951b1b186fd4ad221e6ecbea5c7279cc8ee8b01edecedddf48cca47624ee9b155a4c167f140000000000000000000000000000000019852d2bc9c8abc92503f3e7eec9fb20df108c23643ba8a2fe16c2cf085bb4ac079d3f065a1241067daaf401b662288b00000000000000000000000000000000018bf1a4e74ac9507b97a990f3a41cbae3f32e263e9937a8a62679bee93296ee5cd25110833eb5d136425bae0e9dcb8100000000000000000000000000000000096ae4bfaaf4f18d3e987d9f287fdd3dc9b497cc84867e757da52bd5f58688403e1c9cb432a2eb87e239879d52990ab5f1e168ab93674bd7f2bf73318a48ef17ef4464fbefd39f77c17ebfdb24d679b60000000000000000000000000000000016ebc2ee18515354b7af5d924c895ffd5556ad088560f89c59a4ceec229279d4075f732b884a6ef2bb2eddc11d27572500000000000000000000000000000000110282084ab6f3e76eeb9e5e8c56749992913c2404b003df9c2d01d72751f879538d23f612c8faabbccff45185f4c6a40000000000000000000000000000000017476677ebf052d13f60ac0ec5e572c398f1a478d60ce92a3de88a74a28688d786d30b1ea8008409e45697db0adc628c000000000000000000000000000000000a5e4239d938bfc7c05f3b3a850ebd5f7784eee7aca48c861eb4bdb1ce6321fc9c6bba997e143aba13a42f69ea14937397fb0d947d71a1b032070a12588b85065c19affd0db53e466f194f04f58dba2e000000000000000000000000000000000b6e16f2a6cb821abc43c447da207cc3013f2f750c844f42f0fdf47160a38501bf502073bbeb565122bb3de61b3a5ab800000000000000000000000000000000040f5f3aab5d416e9a084fa298814f894ba599315fe10af20f836e624680582413b4a54623cda8ae2663ee094e4db775000000000000000000000000000000000d32ac715a094813c7b46ce2e932365bfd62ec5e584e047b0c56ed6eca3c58268ae01be31b833be7ba5c2588ebb9859d000000000000000000000000000000000850b9044f129e51658a02cfa49d40a2b09239823cba4d8fe423fa1b4815750811daf745e7e02b317a7318aad0734ddc640f850bad2f22049f2f8aaf3ee57564fb38a847e428e252f003eaac465f7d670000000000000000000000000000000010c703e31f2d488812a387596c797d8d414e406bd82f238cea50a459d842502e11220ad82fce5dd36635792ff5770bc50000000000000000000000000000000010c11caa640708850e1dddd48bae22961a45029971d823b53030979b7d8ef2eaf2ed055436105697c5b0b31b1a9d0a7a0000000000000000000000000000000006b98568b2b7f0aada97310f7e14084a14bffe580ec65bc8fe5d19c6213c45dc1b8e1da5c6c1b8555729f6c781575278000000000000000000000000000000000f2c506f3e41c28a748656d1dfd87e812b3ba21815637e497a30eca4fc5de18257846f12b67919dd2d739477cf5ed0ae8bf91051da5bce0a51bcba6f4e1b3c9063743646f4e75e3e5a8cbc84e8112af400000000000000000000000000000000102b6d561172adc9316b3ec11f05e66e7affb1bdc70a364faffa57aa5938c2ac08863be8fe79ce3f627558fcb2ab1230000000000000000000000000000000000c5e72c271a1ee186d443a96d53f0ba0ce226c76aff2a7c3215c2110f96cb3301bd586f509edc45cd20e662756897b78000000000000000000000000000000000d546fbf485bb283a04fa05aa962ae8d77ec4d26f749d83b208f77247778e32a9a2f1483bd84488806e27b13eabf41d30000000000000000000000000000000005a42c6ce8d43d122bbf984e9777f5d1c15057f27e70fef44b97c2c6e7e2e303fcbad643027b7ff3167916f21a723ea98da771e0e827a52a2f7e79e0e5d93ebae04c1ed78cab87d4353f24ffc52099b3000000000000000000000000000000001788323aafb95f8761f87f771fa05a8e49be71e397849daef5877a7f486af13fa651be7a93bdd9465df7be4ff65825fd0000000000000000000000000000000014b7a56f3f7c12e39be76b3872c1ee648f62f9cb6a1842d869e00a5dc2ac8cb4ecd96ec2483d5eade5b0f9113133bb050000000000000000000000000000000009a30623632b757ae8d03ced0c1fdd1877718f8d84f34ebb42426284f73bb7e8abc31a5e5ded57a02d08adaa90abfb2600000000000000000000000000000000020b47acafefce7f617081e22b2bfc566acec6d2cad5063a79cf33e02cc8931bb698b72184a11fab73e0bb0aaec76c61d6cff707bff10fd53ffeff8e9400966d8ffba6d4ad6a8e7e456df10f8f5ebed2000000000000000000000000000000000d1190466f0e8f03d2cac4a5e63a13d7c6d0cac9f2065295e2de818773199d731f8cb7b2be5f6ef0a246401b345a2d560000000000000000000000000000000007d9c5d187494df79c25b6292527b0d6d8c50b6467bf76a1a1316556e48159a3b5dbdbd9fb0bb901d857f61f423d15db0000000000000000000000000000000013e4401fe76e3f1ef73bd244189cdc81fcc152f71449c11aab24c4fa1d123c5aa8c68a2d10fe88c1c6631778dc0bcd420000000000000000000000000000000004ccffb4296883b8690b2f3fe17e4e9ab24390084ac917ed28fa1e04b9758373abd348290d24c915dfcaf0649ddf5a87e00831cce307cb44e8dbd5edf24f1535b837277160d2cf6daa4e862e57fe73b10000000000000000000000000000000000f4baa5e531ae462b95362292d5366daa89f2fb2707c58568c094c58578e84a8d253fe1de26b917b84635c0aac3a63300000000000000000000000000000000109057e5c5451eb9f85b95aa5ed2615d2faccd0539b1e4481923e04cbdbd2ea9290969022cfa508d3fd050549c74940d0000000000000000000000000000000001c3e147ad9c31927207f2344fedd541316f4010e3de194f924c4a1450a221285b76ff1894f8b1670731007f44965100000000000000000000000000000000000909cdf5c56dc177daa1f3fd7cc31d79a4f6dfcd462c07812cdf629426b75bdaa297b9d7e67aefdbb58175a21e29edada8168d56385722f339a5b27fc25a88034d348e3d533ff4dc99d28536c1c09a770000000000000000000000000000000009b4c6bd1c460d2e93febfe523c1d54d6bf6af50838e7a10b732c1be8748a0752a517e7103d0ffa4507b086626fbfa8a0000000000000000000000000000000015bf2c13891dfa8dba35b5da1235563d4ee1dac33e89006f5c9fcf06f2fef7b31ca845bcaa8ac608046e8b01c8a61fd2000000000000000000000000000000001898dfd6a0618df821474b90542f261c1febbf2e566978b0fafca44f6dadc57202f88366b19d2c955e4291ac21beab520000000000000000000000000000000019287e1ac6b3eaf412e58511b40d87558e7cbf90dc8af2f5d33825b40fd2f2425d0be3a05d0a49076f4114350dcc601eb929ae82ded73a4876c041d2e52fa811882fb8e22690a27cb4ad3ca05169bbf0000000000000000000000000000000000c0993401c024d32cecc0d86d4cc52c200e59acb34fee2ae052837f467905e736a1118260ee12a963ca2df6e1a6c9d0a000000000000000000000000000000000103f78f0e7c9a5628a66efa91f150a87e67623ded2560aef278a8caab017fdcf181981952b450c67e3b4d3f362822a80000000000000000000000000000000000df01ff335f23652f1c34480d23c62d705572321c0e7fe92556e033dd3cf5b78a3d554585403a7f3c71744c20d17579000000000000000000000000000000000a0e2c9e2e34e5cb36e96b29231f702abb127a011c7ea3e21d59e5c55f745a02039a68d59ce8e29afac0752d1939106936999c516d4acdfbcd488d39e3073db9db6cdd0c0fd1d29d58294ace6d2d199f000000000000000000000000000000000eabff0e6ed9dc358881796441c48e722ea171f26011ab898c5a06758f61a629ae21d5a2595a22dc9855fd2e516b30fe0000000000000000000000000000000002732155a7a2791078dedfedfd3381281554c389bf9b5baa47593153a2acfd22a08557d7a1d49be298e416051b9137dd00000000000000000000000000000000116faa2e2a261e6a3e4de6ad80d75ee05aebae47872e2eed9cd91aafb94a706de673a05f1b86c0b0131cf148a90b2b7900000000000000000000000000000000009a04c09c2a4fce22d237bbe930392dfbbe5c82d480abefbb3be876015e2f5889a0922df6d00d4e94be0e9fb8d2f4a1fd0bc405e3970dc2bbd7dfe0c54b7c64543fc241000adeef4f7aa2f1dd2506770000000000000000000000000000000002a6402848507062e5c5d63b1207a1a41d3b941d21792391f2feff95035f1b4625541770fa5e0f87585cfca670976533000000000000000000000000000000000904095ce640605c957715e378ed733ddf1f94d3beb63543a50c8922ab9f8092755fcc65e2a1ed9232c8cddcb5816371000000000000000000000000000000000ec62b911b08d3e8618880c3784685b2c6cbb07a4aa4e348ab72e4f918152622ddd7748bfcd79f35675cb956d11fcd650000000000000000000000000000000013f651e9104d48a081cef2ae0648816b2b4b5f644a791514e94a8e3dd3001099c27d1f9860337ced1b177b4ad7cd5866c36afa3c8581df069292d53b8ce3e35ca136a0b3f95a894958105fde9c77e39d0000000000000000000000000000000016334abef2a21b9c1926b2086075471bc2d2d2f66b963a41623af91fd2fd50f254c008fa3bad6b53658c2486edcc94aa000000000000000000000000000000001063002a5d17aab2bbb5da49e8bde63a1f3c4dcbc8800f9487f47c6d707109c86d3cf7f9171643418b195e50d7483af4000000000000000000000000000000001213004f31fdd0b0df5d8e3677c4f48624691e2534c02881c6cc6875b9abaee56ed5739c2acd66cb1b10553ba066ef1a000000000000000000000000000000000fb7659081cfcf8beaed9c1daf9e92702977c37a54376597d897082a25f9882f1ae14e7724c0aeb9e002dee708c6b4eb0f0a2bd678c5858be2a49ca54de8716fdeec84e1935b8f44545c740417efa7e400000000000000000000000000000000078f06bdfcbc7c0cc491fdc8069314c8a395983f9a2e5c2d1bec360f36e365da377885f897d8d711e33270e3ef9dc4d80000000000000000000000000000000007d43394d5175e020b3a5d768b60ec763d60cb1bb37c0343930fa82e92fb1becde0a178c4565df320824bdadd54ecabb0000000000000000000000000000000012f9fc96355721c35a6f5439065d89cfca5345622b3f38041b41c036b9bc6bcc980498ddc7bcf807e1b97831c099505300000000000000000000000000000000105307b482467b881a59eda1434e31dffdea531603fd3c460aa8d4f58d32668228bfa585bbba2dae7346141af59190e2c8e420db340ef2c1b5c6a71645e303eee95cd93228770b639287b14b6a5c59ba000000000000000000000000000000001576521fb3be8c3178549969e54bb17b0a3546ac4aacb470e935359e36bea4f43dacc06c151a527f441ab9616e07f7b90000000000000000000000000000000018dff940a21768ee9b9450fee7259663bb29af645bda2acb4d43f4e9d631e0127073f2db04293266e6fd6fd3d005e3f0000000000000000000000000000000000ca6a977016c1ebf52827a5ad52e5efcf7517ccc3ff40df8141f6335fb6c77c3fb8f6b0dcdba2596ded7c3838577e28000000000000000000000000000000000150cc33b55586fac30d316cad6580cee0a070900fe7d540167560b79f4cf9690a5e02cfce9946cf67a95dedc9a7d9aa35398541eb5a03271e2ab5ec2aeb2da80e634f63a050c25de98ad13e9d63d09bc", "Expected": "000000000000000000000000000000000adf84ea7681c442731be8db9508a050d4689c42af8f7472491655356a86fd9a0afd91435bdbaee98db3b1d8f26203fe00000000000000000000000000000000090a7dadc0a14df481e44e2005c9ddc6e026ce2afaba7badd18492bd3a338dffc349b4a339f56221eb795314252d53640000000000000000000000000000000007390fbc06077cd167f53a16f347eaf50ce8c9d111afeabf3a672687441b80e66a66ba3fdb28e2ca8282f3ae3dc81be80000000000000000000000000000000001998f98e85285a428a2860c22a00d0b317854da4190dcb4dcd182ac249e13c51f5d5df5db6a0fd61d01232cbcacd5a1", "Name": "matter_g2_multiexp_26", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c868a2cce65692f83eedbfeef6f9823ae9382fa5ed23395ff2444807e72403d4f6ac861ecd3a51db841889fe22a033700000000000000000000000000000000111c9aa53da85a63ce1870b963415f0d5f812e061aa6bff57425038d1b65fff57a78bdb963bf2450001525a93011a28e0000000000000000000000000000000011770810c16367d075c695981dfa69b072b82b034f8ac371f26bb157f9f9d667aa555a5c6baca69d08f421cd569faec2000000000000000000000000000000000df6146b29bc8226dccfc95a325d791b30cba8ff2495434d75622b170a634ec7995c5b4c689c73582ca861dd21d8e1e49f99387baca30b9cf63ad10c445daa142fcae1ab3c0a366a068bb5efc9abb3a9000000000000000000000000000000000fb30aac6502ecdd3544f1879bf1b3f4c19fb897de6c3a7cbf08f36244aa8e9dea8aaf781f7509d3ece16ca144a601e40000000000000000000000000000000012304be931a1d7440d67740f50b1a281468b412e8b6c54c62b993ec609012c7056fc7e62405c7530e8f5136cacb5926f00000000000000000000000000000000182320f5d9211c08f3ba5d40ccca45cb0060a6d362b4422084617b9d8212e94a9b878294ac176b8f0e959bc124a753310000000000000000000000000000000010be6678910072ed9f932ab01a2d72f7374a2cc82bbd86a6006a495272aa89fd655e6719ab8b3a0643d002021f7b7ebb4283a1773995bbc97a6df107082fed4ba40e2d30c5472a25a7643ca9e78b8b8b000000000000000000000000000000000f1ffed9514ee81e9b3fef4162c8f4980fe0429e57bbc224a9c9976cef7d26ab61ea7b0cd42eda30da97e3f8f5ab5f0600000000000000000000000000000000035b9b349b531d85361a4618a172b510dbc924df671b3fa707b474d0d8b17d30dc8ed208d66be91dcb7632d2f05ce31d00000000000000000000000000000000010030dcf6695d44ad3236032e47f7aa25b9f55869f5207e7ac8641db8c01f5b59627dd3442a1834b8b1fc595e47cdcb000000000000000000000000000000000f91ad5c923572a75d32962567e7b1b0eb84a91d485c968b5aebf8b3a772c2f94e47bc1d5b333fe43574308a78e768ac7f4202d670fc3b48eaa92e925f48821d2ae057d90c5f184edcce9ea900ab51a6000000000000000000000000000000000ae11c60537bbcfa46a08cbc219122ed66fd0d42f90e68243c32010eb99942554c349c021f0e3635bb50f7ca3d106a3f0000000000000000000000000000000019a61254aaa5b51b4d354f444706ebb0bc3edb87ec2d83e830ffe0282bcaa3278e947d053d6678549a098129bace43da000000000000000000000000000000001100f48a07456f01e16bcc833ae0a2835c964e9b0aa850574dfd8b4a7f06d03059e9b4df8931740ce0621ec7eb31218400000000000000000000000000000000003072392a824c386859735e2d203c9d52c19796ccf8538bda3b1436b2f6815bc86d05287f29fd0bb0569a81a57f0c22a76cd8d292a7053c449cb98f13cf768c6e37da9d702af28c16dceacfaf9cdef5000000000000000000000000000000000392760f98883f9cf6c0f0a324b9a645cbae12b780896f6a3eee918c44a815daed156248d6afb25901521b323f6baa240000000000000000000000000000000006375c6629f30b7a36785269d691772afe1b95d6e1bfaaba9459c31086c2697e4ce77d148fe2ea166cc330373583f4730000000000000000000000000000000000aa8e338df7eac5a7b070a69d3ed1553a0c52fcd894c2bc8d1b8cf6ed38983c6c392a9a045ffe8ff40b39d18e7c87c9000000000000000000000000000000000cbc73b589cba1bd47161282642fe6f51f2b3edcdcad6020bdaef369d3f2c11ea9cafb9a7fdccfb89bbbe13560d42d1d97b7bf8acdfbb148814afee1df79aea17261dad6f78772111a6dcb021d8c79d0000000000000000000000000000000000e71692cc2342d1e93e0ce72be69013023d012dd2294249dfd69e1d610e2236ee2cdef22446f1996bd3309825989930700000000000000000000000000000000013a1bbd3237dcbe44e05234f7e41982f4fd951d3741a3e90345418af1c922d35edf776a27bfbeaf7a15658db67164bc000000000000000000000000000000001197a2ee5c2541e19b5368c97abf51fde3dd0b922c3d701d7d84552c9f47b38ca09a8aef8240abfdcb03292ade1ff04c0000000000000000000000000000000010ca3c22ff8a47b1c683a58086ed9d831a5c25b6ce5a1971989974b4760cc9e83a1bc8d819825989751405b242eba379efdbd5953bc33bfba09fe7b3ee22c46c3a86f557e4b5f272853e67fd95a0f9b0000000000000000000000000000000001306f8047ba1a3417e7993bba0dfee9077eabfc275af91d0b882a53199874e0777d8dfd29767186d922d49087fff38b20000000000000000000000000000000005371b760380a6d287e129b329e735413447969eb9048def44f5c5987a64323d2a5c81484c40b20206832b86a4af9c4d000000000000000000000000000000001552eeae620c42d0bc4593d7c8e2c8fb4d6dbfcdde68d57158a7dfe837a1870a73b45a97b02abdea174a475a7061331400000000000000000000000000000000033a6dec61540a5cd5773b76847dc5016b309c5a027639598f51ae5b1067b3f7a02f5ea11b0e1be77a3ac236cba15c929a331bb218b99fd38451483a10e8add23c9641b975af3897670884efef90d4520000000000000000000000000000000012ad5ff49459fd3a7940a69e2a78919876e9b3a4f0c142499e7b5dbcadb5c2b5d79c5dea972f0f0acdfd10ac53bcdd92000000000000000000000000000000000ec1be9cb379bf1e24bd5429a4a91857bc3ad45095d15bc5537c2ba39407e9f2edc5fbf711ef4287a73ea466d4f53c3800000000000000000000000000000000173605df66aaf51810793db1cf2021de6a7645ae84a5d439ee035b917d037d9f9ff072b5dfe8b9ac69feab60fe2d70bb000000000000000000000000000000000d0bd336825381ae1e18ca37bf6160ae32b653ec9f9dad159006e92c24b661f22b5629ba323e9e06ccc5887a962ec23fe9301dc826bfe2988cf93c29ca9f01421b75ba63c5ed2cee1599122012ada36e000000000000000000000000000000000f5e593c6588add92cac2c9467247fc6d900f20b4d3216c258f88f3334eecaccbf3eacda227e2da46cf520e5102a9cdd000000000000000000000000000000000458177ad6c190222e53e054546413c13216286d414e3509b7dc794dc0704afd26bae93ff630c6157d05d46d805a04470000000000000000000000000000000015df8a7720d389e6112707e37694afac2f97282676a89964deabefddbb3a0f1cbc885d4c875b945b8303c1ed2c0f46b8000000000000000000000000000000000e3c7f1af7cf5923dccfc1d25bd86088706a3a44f5fa7f97171228e8f2a2b18e9631b2a63bd5a75ee0bb83fcc91a45c30a1cb530e8b828542fa4114de6aa936bd2be5ef3a9b7a0e20e475022381d62d40000000000000000000000000000000017823fc8a56e6e5cb9924037ad6ad1b43237894a877572dfe3d3cdc1120fe83e01de112b55f7f334dcb5c6247c210613000000000000000000000000000000000daa01f90cd14d82d4fc40b60b463089fc6c0e567fa46bae69184d0e3cc5acdb1d759e3291e2781fe0b65c734ddde28700000000000000000000000000000000164e742b123c19e52e2d7a6727689181f323990a3f3238072f7cfd7fc0f55b7be4274c0df194d85060a81f3744d3978b0000000000000000000000000000000007c03a1678b6e91c1bfc66ce8fd419cea13c7cda3213856ad21823b06db94538153a15d43a9d4270edf77b9a5ed490e6cf2f0c33bd044e8c4468b4b7e137ae294c178e7b6c9f19878331fb93220db2cb000000000000000000000000000000001865bc91e645e2e24c3efa3afab8b0e278dcf16b29831f75b3eef0b342479e997b9c5f8ccf67c789c830609b3cc425400000000000000000000000000000000018dda7857f919a6a49f6bb465c27342c8fab6afe6350c43b98e91a3105276f3ac27268454e9a9c6dafeb2218ddc7d3cc000000000000000000000000000000000b098258ff8b185a5c59b46150954d52db5a5f68bc7975234491406131e4f1286ce79156dd1290aafe688f936ad34e31000000000000000000000000000000000b294e9ce904fb9e243d0790147b6070b10ff611a06e3f639aacb744154d02016ac08f6769732d4f6944ce9257680d49e5f460dacc592bb947ff6f1c15b8464824aa5c957a645a763138ac1581ac5768000000000000000000000000000000000e541a22a7a36adc06e445f42497596e1017a1d99de85bb945a195cb3cf0c14d39eb7a2aa994cf234eed77f6307cf6410000000000000000000000000000000002de753e41a16565e5ab1b61debdad54950e9930e04badc6e356f10711d7688befc6827040356c0f0a8ce4f8d7121b3a000000000000000000000000000000000f2202e34ca164f1a6c0afbe179b714b303d87ef14534fe3f4230180f709dc63af17f04487264b3dee6b24ec4d0a423f00000000000000000000000000000000004044d9e3b3a77d6a309780c870a65e05e1ac531c5420f6ed0056f5e728e2b83a968ca90d579db50c2dd395f7e40beaf26a9736f728e16d7b8ce0cc59e2ccc848c181459fff4321982c08e9cac5794600000000000000000000000000000000166d7692fd30dcd06b9f01ba2101870ed347840509b3242f7cecf91fbed91abc24b08b08cc39c508e6499a2f8bc3637700000000000000000000000000000000076ce6dcbc77812b4d5b44a50edba5a082cc36dc24a5cc348283a4ce1518198b56134c9807ef850edc9e36e9a282b9ff000000000000000000000000000000001261d9412245abd7ba3fc1597f34179e54766c49306725d42588545e14f4e450ee1c7af913ad7225275c57680c23aa6300000000000000000000000000000000096602b4eee053998555ce522c060d5e04c7961eeaab0145d38c9b13362624f54fcc8d0b77f2bbaf8c312a3279f06e4eccf0a9be4775d65bbfc894f8ca66fa6f69d4249ea7f6b076fe193f2805e64f940000000000000000000000000000000012be34c18145aac51a1494f4052edbeff14c2812ff494cb78198cd7d9db9e951aea80490c55c4ed926f6a96a2c337c880000000000000000000000000000000000536e46a63ec5ac0f2f4eaaad6df98322c6a981cf2fc8ef253269cef20a76ba1ad089c24cba4ad4680dc4192d66595d0000000000000000000000000000000005363b9acb66ee95713b63dad076529805c0dd8921c738e205e7b1d0410a3ecca0870aeb2e64cf45270d49b473371ddd0000000000000000000000000000000016749b2b09d889b883b6fdaf518345d4cf097a728b833e92c4d21b5c41c8d5cfc0758e895b60ad101a74bbb6be6ca0c5fc6bfb37cbfb10a1ffdfcb91d9a52883cb9a606f4ffa8849a6e07386dc9bb34000000000000000000000000000000000067a684b55fdeea39a29252b355700a4810f083909cf2c07a80b362ac1b4d58f5900c68d266f7ad81ea278c0931bc1ec0000000000000000000000000000000001b1f78d194d77cfb4a2116ce9e29438dbf38c52733b0295198159d7cadb2584d86a75c24aedeb36234a0becf9d38a870000000000000000000000000000000011fced2244cd959872a25c0c7bb4af6151d99e1aac079c606db4987b9ba111261d4a16e7d82362b865324824445a946f0000000000000000000000000000000002659e7016ad615ed80ea1ae020903431b470bc0341f8e0918de9b8d2e933dd9f2d9123e9e9d20bfb05d49f71c3c454cd94959e16f6d780628694075ba5aa1a476d89d8fffcf4b4ab7e6343c011fee920000000000000000000000000000000008f3c5de8c94a98dc5ad7846c53980384f997d1657f7349ad9b51376d41f4b21861d212fb6428bcf2347d8774f44156d00000000000000000000000000000000110b245b1e788da41dcbf60a3ac4987c1925696dfca85d450107f654fa1230adb9436d60c9e742dfb4e453ec4944c56c0000000000000000000000000000000011043b975e01df36a36307ba9234a18b97aadb9da509513b13e4f3c80432b0cc5e69a3bbb3cbab8df41bbcc92cdbf60200000000000000000000000000000000120aebda10c52a67d23842e2bd9a897cf38c58fcd11e4e8c5614db5e409a7c03111feebfe2f1212ae753497dc59d6ae9122f3a5e940ee7e5038421619daffb8a6f433605f37e78d863f814b51b2ec4e2", "Expected": "00000000000000000000000000000000021067690e6e001e3d0d01449a7257348c4ef68e66dd47b9014d7687d44749be1f33e6be95df6a204169ab7103dc2d3c00000000000000000000000000000000062efa0c36462ab0734128dab5da8635705bd1e1b540817c5805ed9417f176723eea92425db539e8763b1c79b9923e9700000000000000000000000000000000176c9af1970f026bcfa87e6f85a20ed498c28c6982e21bc050cdc29c0f0af832ed4424082e4862d985b78519cfa75b820000000000000000000000000000000018718b0d0fbdf4783cd0b01524ab153b891fbf08cad60241a3f3163d2c3496c36afdc6de62ab3c9a037f88ee408ce5f6", "Name": "matter_g2_multiexp_27", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018adf92d8da050c76118a3a3b2ee43955ae8b14ddc8ed64f5672f40de475f7e0ba6ff60c4b6ca3e863d7914e6de2cc330000000000000000000000000000000013d1e19011a1ea90389480d14fa608985d895e05edd9c28fb34646f70fd7bdb7857fa785b1e3c8a2997da6c3b5337ccf0000000000000000000000000000000015764827d9838c2b011660230ef9805af388fd997cc229c939bc5f4213d517dd837328c45b0b8ee1d6508cb70629b7bb000000000000000000000000000000000d58fa30a2d095ee8d946e50a027ac4cfdd557b3fd9c82dbf1536ddc0f42491a176ecbdb026306e6ebf1bb182a4e8199b3908c739d505a1d6fa85a6dfb7a155202710b45861f1a8a7ac7bb3274a180cb000000000000000000000000000000000cacfc8d0bc6f9db737c8a316043a6b52fd5946937467afc09ddd14e509a89f2445065ac8a8c56454d529d67793edb0400000000000000000000000000000000148b1b941f159d93170fed949d5f53bdd2603d78a49443ac0e2353130ff914376e018c3db3d12b807d105f2d50eded8c000000000000000000000000000000001382a3e98cfd072807214479900a8602bd666cac7f19be0443ba1354bfc05666f40384e9ccac314b5d0a2bec1c90ef0c000000000000000000000000000000000c12c2222f67a5adba78f2c0be5be95ed743e835857f4204cf47b67fa2eac45cd5985fd82c7a3904944e7b84737374b17e0e27a8a416eb38c989a66b84f037a5a24ef3358e20cd553f037a0a2461d31000000000000000000000000000000000197ff997d6c5efa3d7de8e16f26082bf13a2401d6df5f5c33c6614c36105f347e40216c907bdad9c1df6ebbd44f41c3f000000000000000000000000000000000f27a0bf92329730d776a83583177993b2b354a212a9c004f9f8892a750c477b8d1e68c13127f03b1629bc8392d06f5b0000000000000000000000000000000011b239cc6914a321385d907527b85713a0d842f5be80752f4c5758586dc1de944b6e4578bbe324f16838115e9c866bca0000000000000000000000000000000000cf93c5b48cd9de51ccaa45124217cabf466d07d6fdf4a7bb810443339ec4af5b74931bd07eb9fd31c284c05f3f539e0a3cbab01c34856b892aacdabe63d0a0c241ebc137a88c83ad22cf38997b211b00000000000000000000000000000000137b12f731ec925dc51e20a9c90323d14e1497e16b3a4b5651135054ef0e58e9b18167da15220b9a4f7d81e9a7648fc20000000000000000000000000000000000b2d3ac534e1e5b2c9ff4092c2d8dc5efd99121de7df953e5426eb33934ef07e41b196eca50f5a04a936881a05f2b2a0000000000000000000000000000000004feae2377d950717695606844a4873ed7b5f6703d7a63dc8b960b99b68efbba710c2db0f1371acbee314875b97ca054000000000000000000000000000000000f49ce3061e7254dc1bc8af3636a05e098cb96d81fb31e25da97c6266adf3c41a74d46ff32f4fbdb4cb7e4a3f69e827bb386bebe0e49b7f07b0ac61b15306c2515a1ad6fd76a1825dd29a60e845c0e4a00000000000000000000000000000000064ae3fd67250f2c6332e1e149ec09946147e12e0d871403e559b49aab68190a1454b3ae924727b6dcf6e1ab327c9d7c000000000000000000000000000000001131f91c7a0e1854bba3958b36083c27904cfbdb8b8cb3fe68cf578bd1cb6f7c6eff91d98e4b99086926c5d4272cc1f200000000000000000000000000000000071c6a92a8d460ff72d172c204c8a69d6b6752b8c1f731ec63f7f394c0c3a2a1bc15e865172f693f523c11cd4ab1f88e000000000000000000000000000000001193876df7f4a1cc9b337a41c9faebac2f209b9070bd75294c2a88d3091a1e55b51fad482fd2aee8f90458eeb7e981fb8902a82d33993a10c56b2fa3333cabf1c5d47a9c78354d58f70ce4807cf2062800000000000000000000000000000000025c20ed5572dd1c9a098f241d2965d8739878ddc57c017632afcf6e54964894adbd6d30f62f316c9c3ec7a08268afc70000000000000000000000000000000013bc3e930f4fd5766db8f04e1ebfaab2b67f620119c39d687c68619b3564f3e8b74666c9f8bed6c1f080a9e23e9c0f22000000000000000000000000000000000973a3cf19312f90843f1f013b05484064032557807ca67b2ded4a27fdac12d6cd0e1416c8998cc8635ce10046adfbb900000000000000000000000000000000108903617c78fc608eaf007aa13861c970557f2693b24e8a278920897be9694570ae6e6c7749c3eab84d5fa3af5164b1426a4e2317fee033a226a91a52a5830f9ac2cf5f329feb6bdb382438b8a39f2a0000000000000000000000000000000005695975c140fa14998e5916268bde2135cda80a45414fa85193fd6e13c6b5a6486898f590d76175d8ec2629c923e33600000000000000000000000000000000033f58b1cf67e51e9ad817b31919530cfdb5db5ca4a537d9b006b63399da49b2a5077bf5c3b3b4fb10b2478f466542540000000000000000000000000000000015c532e40ec04d9143e308895b2e7e3d3daee093a5840e1e76ab528fcfa5be57d9796ffd58ad5ab7df6f88aaf34706f2000000000000000000000000000000000b55747d1e8b66e2b2fea67229f2b7b17d58ef547ca841bea8db5b53fafaa18390f11b8170c41a5dd29331917fa2e348de0390c05fb0dc9b4a3f76b51cf952a11b909ce13f9abc9fed6a349b8efa98ad00000000000000000000000000000000001ee5ebf73bb40a5c0822350853bb5aeead3262380dc274faba6b04e58e7fb9d5a4ace109ffa5011e73e3d89ee6fd77000000000000000000000000000000001427659e5ab1f8b47edddd27c613b578890d4c66c835c0cf8e8daf19d0ae842f0bba5bc83ed7248adcd75cea5d222a270000000000000000000000000000000001d4560185690ac05e56c2d629d599bceee3ed2919c29e3d1ac54e80ae99b5eb2f93bab865e8c1eef7206f96b2bf4eb20000000000000000000000000000000016ecd3589e3703e5b0ef53790130d5074d2bc0fd5839d9c6ff905746a77e393f73edf53b98b99d9c87a1fee1086aa8657431db9e576643f93505b5b25836218759e736c0d650a5221a652338b0073eb600000000000000000000000000000000163850016261f34de2b831a0a8dd3f224adaa3cc279cdb40e0ae976bbf736dec26c55a6c79cb1c623870b62ea216274b000000000000000000000000000000000a79af5c054cd08608d4be1705058ef7b4ec38a8727560d960f0325d0ef915c049a89e76956d0296bcb6c96333c3470c000000000000000000000000000000000ca89379e558c7308edd25bf06dc05db857204e9351299ab66bf050c8f051341a6c15a02864c679f07373038de3fe87c000000000000000000000000000000001929f42ee5d9dbfd1f6656f61e6243ebf0eb491762b7f3608db3f3e9abf565ab1524f770cd2ade334885d7479342c92c6745a32591e359efa41e9ea93a016d2eedf1da112cddbf31818e8d687b36af2e00000000000000000000000000000000193b6cf7300e47ecd21a05a71b13a8de45418d3f67931789ce6111b8633b9f44063ca13ba8c8a598ee0725caaa3f277a0000000000000000000000000000000016884d982e2ec0fa7e59fb34ae8708d0bf4abfc260837ef4432e8e04474e504b85450db8af8e6809413c90268801fb3b000000000000000000000000000000000fb48a8331f278845979beb8cd21060355566af215ba44029455a03d0c016daf0f6b7c5773d1a99e893e76b4411a53c70000000000000000000000000000000007056e30143058eaea89a3065e1de768d49860b170d4c364a28d38475f90711fba62c1787adda90dd2d347da72680f4eed37a5f4bfca6b77ff9e4f7e03bfed52ecf02a8f84ed3da6da2787a4ee81ad9b000000000000000000000000000000000501fa9af88e28d4f0c0590a2624239bf1724ac7174b0f1d5fd7527cff1de9971d6aaf28ba4005e88e181daffee6b20f0000000000000000000000000000000007af5e30b5aa9ad206645ace12cb2b36cc1c6068e604184ca8bfaac5a4ca327f7c43a74d43417918da7df84e3bffd282000000000000000000000000000000000bfc0538d52f277d54749ed0b69697b4c60ef0c5483d21dda76533e15efedc9e2b2ef07618457d64bae8ef922c0b41f600000000000000000000000000000000048935cd352e999bffa613e3be0a9f9a063d5b5eb46cb5056e41ba214e87f871f216ff41ee297aaaf2994a7b6433f58d81633dd6e729bc17ddc596cb1f17dc6f0e50c052a0b8c5a4c83900d918a9eb560000000000000000000000000000000016ab1e8b6f41891e0b65f14397c0887b27ff27e7463333e0938a7a1a181dec603056afbefdb23b41bbfb2c05807289b8000000000000000000000000000000000980d0ea9ad5c87bbe1aefb708061f85faae1e1e3b01c55bd577631e5bea2b5ffaf5e2478f5a8df89447fb8a73559729000000000000000000000000000000000784d0c5fa243bf0125cb2c83a4040715197e99d507d71a3bd9ca396074cfda652c1ad0dd95c3cfae369e68d3431ee7c000000000000000000000000000000000e533bb33e6d269dfdeedf7d17c3e0c19f694d151e8eef801c326cbcbc463a42558f58cbc330bdff0d8d91e2974eb4cfc6b019d29219b57404baa955f66cf1b2ee6571ad5b80d471ff6db569e32a1a5000000000000000000000000000000000050f005b00f371a7308b5d7d7f67f7c00bf15acc518942607f32686feab5eb503391f964eb7ca711aa6c7b4e494d7eba000000000000000000000000000000000e2ee5092170ea3da0b1397023b2386c65ec8b090484353f2e5d64694aaeb8d5410ae22c92662fcfa21566d70173ef36000000000000000000000000000000001549723160fc7b8f5ef9a84bd1803f18b76698aa7a663d9c107c9ff6c6d02894edc80fd00d436f3a942c05593c5464ad000000000000000000000000000000001032f49e3527cc1f1355c65edb21220c6afc88919ff67ba99c65645cd3b8ca6662dd0146f6a90d92558b3f54815a361d6a76411ce02b4dfc84ddf62ed26508a2dfa5edb5a98a6a20dd69e8b8e7ad2f5900000000000000000000000000000000170b317e49f1304570a3a3e6bef78fcf8537a451ebcfef5afe3eac4aa1aa87dbf95d0f870fd3372d37efc9e663621cf7000000000000000000000000000000000269ae0677d71b2537078e96d2593482e4d41b6d1d2cbec755f307735faaf79c01fa27f1103cdfae1a9bdcb665f592c9000000000000000000000000000000000b115d5a9fb9fd9361d0573a8d68c5193f02edc1cf3fecf004c6603f118f28ff394220f6a9e1051a5d9d4b417290b7f800000000000000000000000000000000107b45614b18c2513f8c42a0032cf0f3f300157b39d2969ef7b126f17a9b5e8e9ecc5a61a2ed4db92134b0797f6a0ea35906098e4ad7e4eb2e996075c7cd660fbc399bc942f9080404b9d0758c4ae14c0000000000000000000000000000000003de39b056f8f0248b138437db1536b7bfee29af00c37fcd14c25c88f0f051eaa07c763d94c8ce497696311736c0b7140000000000000000000000000000000002b52981e828f8dc1cd371e6821d001e1f96d57a865a3c0a255298c43d52741b18fc60903d1a5ef6227061dcb243096c0000000000000000000000000000000016b5335f0f9516f52f2ed45fe723ded427206ba96af0879958f1f22795485b2867e953de3d9b3a9eed2c37f26838e1540000000000000000000000000000000004c860058c7ea2e6e4eb2a65c1dfc20b3070f89ff58ab99bb51a4eb9e7f0642f7b32d1d9f27c668a36a9e053a8d585f394ef8c281a9be3766fe784ae017d93f608dc2cb97cbb7dd3e3814b5ade845d370000000000000000000000000000000019cbbc125ca1b89330c21ef5b42fe0dc1e795271ce4a9ecabff04eec9029f756f180520f0e7b84be2e9fa4af395536ab000000000000000000000000000000001630cf0c4f3282689a3e01b5c8f9be3803f60238bbe9fecbb0d9e8e49f4ec9f6123c44840acb8cf55f8f6bd15579e6830000000000000000000000000000000012afb848bc0ade8f0c25c6c342bb651a7481be065a48944bbedbc14c095af8a4a048fd1e776126e2128f904afbcb17ff000000000000000000000000000000000dbc984f9ff907ce5553bb11a458deaaee0efea49d6816ed7abf1dee7b70cb18cc669d4808e75678bb898359c7ebedbe6feced33019b3b66d335f2118cd22b2952cdf9757fb3a0cff55b7c4f245fb438", "Expected": "000000000000000000000000000000000be6dee62b8c85e36a216d16c5477a7c58f03b992277af83d9b53b3b2169414b72bcb4a97e3667482e888738ff17c94900000000000000000000000000000000067337c69c37ef6f0ae59fddb84c46a2afe7fe047ddb57b3b80437609f1a21fa5a73420fa5b44704ca1cac6c7a99d9320000000000000000000000000000000017fe6f37d2410159e533374ff3812714dcd07610d75a53a5d502cf2f51e750c48858db1e109f6aaf724292c1402382f1000000000000000000000000000000000b8ecfe1f5f5d95777b0fe5d94fe81b82656e6e5a62b7591788baccd251d93e4bbc6857cc87cfe6b4ed470c33631ae22", "Name": "matter_g2_multiexp_28", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000126d4a9ae3550e31185aac9011e3f086517cf79a279326c264f51bee6615dbcc730d78055489b5602e91b08f96d23882000000000000000000000000000000000aeff5fc04fd06c26af8b048fb2d0d493525ba5c2bde30664e7371812d529ec7dbd584c056b05fe02179b7eefbbc45fe0000000000000000000000000000000017c6538d2801947cbb646d4ec8b70b1e24453f7a984db7ba73e3a5dcf595bdbad9703f2d846ab02491e5e3a5bcee0762000000000000000000000000000000000badf551dbedcefbe7c303a5c8a52151b5460caa22004028893af4d8a3fac30cb1da1e986f9124acd5db7a634657dbd0cb5e7df372d346fd13faa90b0d6961372ce2f32ec379e5e50e7ed8a13942cd9d000000000000000000000000000000000bed71c7d878e7ecccd8233e3e604e564cba0b1ce75f726f846f3a6e2f3b4f5b12a28b8638be647f5c33226edc2bc7fe000000000000000000000000000000001914c20aabaf1f6f82063223053809622ad82a3a54668bd600db1aafba22aeee5c8a07584e263c91cb0fc5fb809da63d00000000000000000000000000000000056d9cd8f79a90d16b36bde77e546f8b3064ba7dd0fde78d6bc538bd6ce12a4f32860205d5d396bab3d70deaaaccf9450000000000000000000000000000000012f7e420708b66132157a80753678de292998cb6c4f00244d3c47a6077b3401132b73c7f52369aa2a6a90892f7be4ed913a5fa1674c20c97d08608d200f3f7611010e6a25a790853ed4ba0c5aacf111b000000000000000000000000000000000339aa1471eddee8cc0a4e4db5a29c3e4e92cfbabe023995a79624614aca522cd459dfacc0cab346b1cedac347e1df100000000000000000000000000000000016cc4ee8cb72fe09e65616fbe9bea1a0077114ca841ae335f1f9eb5a0b129a4bdc77cc6dae8727d74fe21f0d870a43f2000000000000000000000000000000000098a21da6e983228ebbed0ec3704c9d2521e935506c0567e3bbf9b9c379ce6d33c3d0dd8f5e013b431f740964db634b000000000000000000000000000000000a7a38abe8e282544ec6c8740dce8559fd264393d0a5c9af9813b2430bdb92b3150eacb6732b9cc278d0d0e622b263ecace10870acf190b373c19ce615e20e5cb96d3c6be3ec155f2b29825f8476b7740000000000000000000000000000000019ed305bfe8d8bfcc20794832b3c117715b6a658c0bfeb629e5989f265cbb456e857e53d168932589e4ed2806db7c4b4000000000000000000000000000000000e2ffda25fc316a38f556b35a7a3acb1a2bfbc1f9469a1b6427ed1f216e113a379932b0547f5370be1017a1fa0266cfa000000000000000000000000000000000ebc493c9a79b8ba58f48b90b9d287c74f505dcb484eabda79ada987d63a4df04d671d4c4ae4b32f8ad5db6a1b80f37f0000000000000000000000000000000019fc715d26c0c7a0c291ad8319e2e8f2920c63b4d4ed3f0e2f376aeddd4f7bd9269175ac8d0f421b001e2e48634f3f238d9e38d9383f09cf0f8a8077f1d1dba091ff0abdf7e77c3b65c2df48d6c6f536000000000000000000000000000000001285ff533da833a3daae7d815b1b86feb6f20b7592af8b0eb76240f390ea48b69a75547b040e7282b71779f450d3510c000000000000000000000000000000000813d38fa21c1f3c87b9c97ac03e6aeb8fa23e0340a0dff4e3892c774595648743d0b8980a7bd21648ce9b16a245ac3400000000000000000000000000000000020a69dbfb736c64e4cbc800aa415729b24ec05e901f2c7ba38e49a21c3851dc03bd4f7ec829d4326fe6c13867069a07000000000000000000000000000000000d518f3944053c8f74c0aea1d054d89106312880de4479b3dfb45b00945ff8bb58b12f9a489fa9fcd87194a71475d0a1abeffecf9b404c6bb2e2d0c78fbb8609a38e3d3187587c3848e8f9781b7e9f440000000000000000000000000000000018c82052cd483eee7aaa421c2b998ab0b4b32326dadba03c1d923726697d3940b40d5109ba34de09439e833ebc19daca000000000000000000000000000000000e4feddc3eeb3fd1eff8316d5b0cba554714713e8a605a55909889970ea2c8c58bb6c568024709def73b29a5a76563c100000000000000000000000000000000098da4cd0281a16e2e3e542ebb92269c8208a3d373394b0af92dc8a2676f9f0b6e85fda9161e32558e0569cfc7b1f3df000000000000000000000000000000000b7b54b51821fc037f02167d2e640f8dbfd1472407278b4bdf47b958da39f28c64569c3199846c293bf60e86aa45f205adfe53846c0038203d8b8df0cb636aec7d4ed7f78b0b0c1734be448bace08f340000000000000000000000000000000003058abd4e3d49c86ffac9c95b1f07b66a22c42654dc4a2e3b07b87c22024a8bb0ee084a558ac22cc9fa286861fd77ff000000000000000000000000000000000fc9a89ee26c323df22add487a6bb278ca3f4c9a91eba4e067d5abc9dd3afededb4f98263e10083cc7ea224f28d3bbe100000000000000000000000000000000058eb015f1e14da860215d59165e12feb8d1317f652eeb76b3f08b38ed943c94e632dbf8145233dc93755e44e027553e0000000000000000000000000000000010897d5c2b481f9937d830b333e7649931e801a6bbffb7d9a3ee28ab1e27889691a9f0b9616a8437c3cda942bf07282206e9d4e41b628be51690b86aa8938db066c052f3adff774d35eee1e332312d3f0000000000000000000000000000000013b88963296d8c8197cafe160846ee11365b7a991b35cf5613dc57714aa48307f4dd9c6ff9704b29905c18a41a48010e0000000000000000000000000000000016a97fff65fca5ff282a818deb8100104308b8d9dfacddcae32fc2b6082331b44fa70580018930fe1ab9d9c1b13a59a20000000000000000000000000000000019cd2038acd84c2db1f0fa1b7eccc5f7ae3da803cb72c4a1e8390d49e0adff1d88a85696d9daaebce9c6b8a2f861fb36000000000000000000000000000000001271338587f06847770c72dfb3d9a657d05f8c7a012bec77a7d40a98cb1637ae99281c82668486119608b01feb25e6dab3d349b1546a8c235d60c41408c969a0fd42425f8b5ddc1fa5102d2821bde2c600000000000000000000000000000000173ed7c70f4683102cc6a276d192a8f3b189197d5ea5dc813c7d0162a1649e906f76a1c9a1cb1ace6e4d937934b72338000000000000000000000000000000000936d260b789b1a2a9d04388caab364049395be61d320aef66ce50f052eb462faaa2017731518675bb0e4a2f050e4f7900000000000000000000000000000000070bd1254cf4b209ecb40afe248f2e53c390636625460439952ca2977be021d93fbec264c31ced2a810e8a5e54d750230000000000000000000000000000000016ddc3312f8ed359792bd213d086a0ff1540e3e5a2dedf6c450fb96a9b6d1edff9bde31fbc04de382cf44694a631178229b83950e79750e9827ed92856e4d1e1b5f0b47c6bbf3611a1fef8f2fc47659c000000000000000000000000000000000aa4bc6e1a3e6c3c45a29db74b27af27b61856e2cf385ce0e5094ad53db4d31c4af45b5b234c66a21bf15018c13ece8000000000000000000000000000000000188affc993bf6c99103029c1e406bb1a693e4f1dc650907809ba3de1471d41095dc1866578962c72538ca85d09fcd22d000000000000000000000000000000000e487a7151916694b980e62b64ba49ffc54aaccfa0b0fbc5c14fa4a50d1bfda55698df5cd8570c07030f145c49a4ba9000000000000000000000000000000000084a05dced107d29a0fd4cf817ab67017ca33018d5c7302167d08c64c45c5c455fb5c907f21c39b8a86d037a126df4e76b5ac07fb4a184dfed685b93d2265cebd02a3296a3b0416cc6a115242079752e000000000000000000000000000000000ea7060a07dacd84287007a05b494bf19a03e5a759b0ba67624c54cac3562c0ca3fa6e444206614d00d6d6684b86bcb5000000000000000000000000000000000eb2f332f4481276f931d2192c1a9f6d7585e85f248a8ac95aed398cb61bda05230bf8b9c041c6f78be3b34668a9c1a0000000000000000000000000000000000faa038219f844e379d8cce55cb8f0fe2b55548a0a0e1e37e25ba4f432e6b1a6451b8f081c171490bf055f81cbfe5f8600000000000000000000000000000000037c70d4e8befff257c4bc98a4726a961f3e2e68e7e02f9f2c94aa8f5fc67a1da44d41394dfe376a6c04240e4cd5825f3a7a25ad9f02bf51fd73550ccde12374d9b151f2f6fe535bfaa43efc391f789700000000000000000000000000000000100a24d21c0ddb20d76b6d9fe642da5ac1de28afd642ab5c08574206b8b64d1fd822d295476bbdf2ca7e9267138034dd0000000000000000000000000000000000aa7e4f2f77acfe8b4c8f3fabd56b17415ee9bb182bca1db15c399479ec60382f980067b9d4c4ef7556d621259ae9110000000000000000000000000000000012f7a7f91a988fa661c661013736f0ec92b40f571ac15a47067bb847b09ba128d1dcaf8049b941a51cacece5db4e1eb40000000000000000000000000000000007528b0ea66b6ab8d5d318f5e4d1c0e9a4f504057dbb0397b614a1adb160032127f2ac35a1a98da70f023cd343a35ffd47944c8c814f143f746175ba0b2d75e2ae73730a265d869763f0e986c088bfcd0000000000000000000000000000000015d72b8d4e71cc092c2875de80f3d12e003804d980a4b1dd13cff34e9336397c4533b6ae3a03beb2f09312a605947a270000000000000000000000000000000005976027a98f7b0caf4cc7d0d71440d3e4fffb1ff65fbf32dc890b275b646f2a32600a6215d6b2f999eaec8e58cb6d5c00000000000000000000000000000000111583b7734be53a7d4d090486070cd3d9622156c52871ec79c83ca024880684eada56a36b58cfc3490e65de41e10579000000000000000000000000000000000fb670b553c2ed4c81962b149efd4b0c77edf6ee70eba88300cf264dda98190e550540fb9fb95748599bca3abadd752030f33b187df3516866f259ff959d57fa9c53323d5c851fdabb96e5ea470518ac0000000000000000000000000000000003900e7cc0a8e891dc4dfc45f08d97e73ccbe2021a560a92c493aacd9c0614ad100294b5d7ebd634ffe4e5ea301a26170000000000000000000000000000000011ccc136127189728a7036e85d233fd150d5483963c48074f9d8ff83a0791c950da380e717f2bd0bff8fc115e9e886290000000000000000000000000000000007d3e76bd1f22679d228b4ee50a60cf1bd1fdaa171372cfa34bf4136a091abf7e5ef3c6b3446fd41d5de68b563fc7ff3000000000000000000000000000000001107f636d9187155357bea75c943dafcfba2394a9300054026b46d6f9db31eacc06d1f64c2b139af297dc4783026d98f4da8401050f30459e026a207ca631f0684a10813c64ee86dbdf06b7b29cd9786000000000000000000000000000000000e3a4101f6af3cf0d5d5aa5a0ebc26852dc69f91c06e96c5f1c7f8e4528c3dd92cb6f629620136ec356f0657fd9ebc6a0000000000000000000000000000000008d34dc3e1fa8bc22258e23b504d442a11938370325c101f1cfa52f313724e0894be722646195fd078c1a49720cde8c900000000000000000000000000000000163730996c79787e7ab89030de2c26e26188187762fa128ba4378a398ebd906dc56d99cf228591f394396248665c196600000000000000000000000000000000008f0a8b3d003b6727834228798950fb7a3cb6b931bced4540693445a007b474f7459ede17f87158e932e4c9c094ab904d940555d48649f30026f70450b2caf2b8f7148b28bfd4349458ae89c323512e000000000000000000000000000000000cc2d30f7d3869abfc34719f40b0ddaf00f52bcee7ec09a16de51785d55531fa7fe3ca1544d7103b9caf7105d60d9e930000000000000000000000000000000002ebd8af0bd3f82dc9dca585feaa83071534b2bc2b3d2aadbe0d01d759ade77ecec3b3f7b72f82087365a14dc205add80000000000000000000000000000000011aa3734a4b9168d3c46944cd726bcb203b94b25a97437a6aaace9c84da708bb073ee10585f28bc41e0601567863c193000000000000000000000000000000000ceb4ae5a8b506d31e77e2a43f3af8ba9459b887a927ca5287edbc2ba7c7cbba85a6e4d35c099b7ec7bf7eb2814cc38ae140e30424d2cccc91be1fd3a62d9ee49c9d64fa062d9350b3fa567ec21bb06b", "Expected": "00000000000000000000000000000000192eb406b52075513584ae3c6093fb534270d716c79961d0a3c4bbc44096a2e8d28228363e2c8da54857945f1b983569000000000000000000000000000000000ee0d95748b13b531821ddd71a15fc529a2ce2c99a66f14e28f97478c3c2d524cb7c4cd7e71a1027030765554b8f50f7000000000000000000000000000000000610ab3e064532ce261aa2ba4f78721ac4f78661cc13fa09ccc279267e6f703f1bda17265a5eccb0061ce24d31e000ec000000000000000000000000000000001966a334b16e64e4dbd66119af97bd2b8d6afec0eb1b8207f437c00ab134ff369b3b3c1bf51b871a7fe8ad1ce93dca4e", "Name": "matter_g2_multiexp_29", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004c22bd94b82ed3b106532a58a0253daf51f579b9d746c624bbc6b58603942eb139c1b576241ca8fab5bf1c457112bd80000000000000000000000000000000010c6f7551d758d1128add57b110227296e060074e4cb934132368f079a794770ff406fc7717867df0f461f5c9fe56960000000000000000000000000000000000048f88afaf6eee5039b76c0c5b4b49671f6fd04f38bdee1b1c8f347a9dd4e6aef387b742c8f9a8aa387ab4d01fe4267000000000000000000000000000000000e7be987d0411dd7138e47ac00f9f07c4737d93aac501edd16362ea5a633c9071a6bf542d4db540d75edecdedc3a8f0ca57b2c351a7946a20cbae1fd789ecc5f77376b09e911749831e9b5680185b15300000000000000000000000000000000056a29b523b0cf85ab04b0a496e078dba5529cb9699e567ca42f9ee3e3f07b61ae29b0ce17cad23131375f624a366157000000000000000000000000000000000acb91d1f057c7aec1f7561614a95f8db2252cc879bbc2595a5f607d8b0ecd6e6e3ec19849eacfca62d870b049ce84910000000000000000000000000000000010d9459e07178af8e125c2f66de699cfafb5f87a63454e24d0ed88b6c804a9ff204f146ecf4d6db62234ace0a944acb20000000000000000000000000000000007256a68e23b43a3b6475b3cf209ec108bac13631ca448cc860672c65c1760a8299fe941ed5bcbbbcf63a683e86806ae8fbff9f8ac4ad10718d46a857ba28f182263bf2d13c8b6a00902af737dea56160000000000000000000000000000000003e33b840426a6bbe15b23fceba829bda9a5ab89d37e60133874f61bf1b10e05d460bb5d228cb178cfae2a5f41035d32000000000000000000000000000000000a9c5460c6443364d9f9440d101d92a0037343789ca0aab6dffcc2bf81e1aed312299a21556d16e55b1398334d9061f00000000000000000000000000000000015db251708253f7de13a5eeae5aa76fec415ecee1ffd88d882580da5da8d9f96c6ff90d920b329096a103dd71e7cfa580000000000000000000000000000000014c3a004cb6ab8465e05d965dc720b37084d98de424b160062f225dd0b67a8e62ae11a3c7bacaa129a568f3a243357ebb061de16f4f609c6947733b58c6444fa9549721fd9a2459652e8e4b8c69b5d61000000000000000000000000000000000c8fecac8bee21d916cc47b96a66b7a522ef4fea76fcc86ec490ff44b46fc01ac0446e3885e36ae7ab62a409ccffcca60000000000000000000000000000000011676ccef54bb27ab7db0b5ec025a9d1f29217030f3686e71564fa011d9fb598f44a8bed3da8fa7fcd10d01e3f66d86500000000000000000000000000000000093aecb91956215980854c6f19120777983a160e16026560c8076bdc4372f53065f9fee0f5830ea192aa5637590a745100000000000000000000000000000000035d773ef15d8d99b600a6a575eefd661aacb49d6540639223a454594570d0f00ba37340b63a2c8a0d4e53ee7dc2dd91355ed5b57b28451ad98fbacd5ae87551b7304e4ef5cf7b7dc443a66432406f9a0000000000000000000000000000000007b2891e9cea2a464742c7f962deb1566c9d4f9e4e7cbee1912a72c5b064211c39801bf42bd888bc239e6b4ba71d700300000000000000000000000000000000169cf5e706dff2945145d5ac14bd5fc8f7e7c3e5f7ce733c865e1882d236926c71853efbea26e13efe4eb0d0e7ed5db6000000000000000000000000000000000de9ee19c4bc2fac36debd4c91317e54f57e761866b134ba9a0e84a8d268b11674110ee8f91aa8a6b80eabee2e5e75ae0000000000000000000000000000000016d91408a670e4ee43ab8e21cc341596709113950d22bdf5073cd90f520667699e94f64f76290f1bebfecfd80a9e051430b6eeb01874ff4b0fb07dc9f23d8e45455c1480eba7fb3033942214e85a7720000000000000000000000000000000001982744a15e8163a6f2ee681bf27a68996682216037d67d91993fbbe040e16ea21a9cb600fc6a40e7289185393544c3f000000000000000000000000000000001131d7dd5a5b96ac1f4c4aa210afe7af8d371cc16d32289aad38c93afcc1d3be53716f82e9d14ce6b1c833f7f5871ad00000000000000000000000000000000009adedaf19fb8823ec55b803c9509ad98217730bfc6424c8b69a071e99d026492e7c8c4a06509491a3bbe5893988c357000000000000000000000000000000000cc60733a783c7df76541daddef2245e6d2b694b94649b13c21aaffdce124c1cec3fd8ed5a5d4d4eff3115ac933e5df989a697a0e8d2cf512edd2a3c3df354eb30a3eaf697779dd9270234b367c2b5ff000000000000000000000000000000000b366a80247a8e3797f1c711aebd60c99ec7caffda34514a3716154e900f2387c46f87f81af036a383e3f9234bd1b50e0000000000000000000000000000000004608b7cea13d08724a2cac691e61255ea7472537f7ff59894d511af7fd99ad72f0a7406271576300a7d1d56aea17bdb00000000000000000000000000000000141abedc914d3d1ed587162acbfddde60f7dbc1ee5e07fdb5f3515b87d1a29024c9e19f24e4c0e3979bd938aa4e798270000000000000000000000000000000010e72c6c0510495dd2c4ecaf13c1c6404654e1be369d1ca485c76d8c2304d60d69b90c2e171f18bf55668232e747825820b72463d54ac1d8f1b3f56f0f98861768b05d5174cf1883dd8eb0410420d56200000000000000000000000000000000081d5a229481fd297363e8e217bf1f94a00f54eb6e8a3f95f4de30081bb2b9edd82d53cf287e37b459afabcb73fea1d1000000000000000000000000000000000ab55f52ff7dc578ae8267fe3fa09bdb8174dc30bb835cab9851dbee7a1aeba82e83e07d5e79aafb34643d9fc9a0d1c100000000000000000000000000000000195245c7a762776bc1e81d7111e3b814088f1e0e7d686c3ee3e500cd0a7ad4015851563a1b8b592e491e00078187c66e000000000000000000000000000000001850c1e8edb0d6dab973a9975833cffee8b5243654bc4ebe64972e423799283707f9ad343bfa86548cd2acbe04ede5da3de7997113708f9d092836c2b0b59abf710d8401baea6de73ee0689436f035fe00000000000000000000000000000000000007e9191fa9057cd7df8fb83d497ad774735c242bce9bd34cfd21d3f8f2a8e37d1f38b592a61ac8a8d22a4287fc5b0000000000000000000000000000000010e36db1460fa65ea229402f558397c6fc57e9c8a4b0b9e85d9ba938196bfeffc951587353cb7c7d84479f60c087e3660000000000000000000000000000000004d86938bebb850fea82acd336c3900b241757dd937f831dd909ce548325955f103dd57611c0b75bf71412a6ac3d6ed30000000000000000000000000000000013990c82583007b693c1d6271c1e5820d7274c4a729da21a76eccbf7abab1f2bdd6c5d26e78d51476ecf154e4fecd1b87fc3d0560432dbb721f8a0610f0db31dfdfea8cd5ebe8da3fe3b8ac5358dd4400000000000000000000000000000000009104610d5887fb7cf6a866584cae30cfeb00e1241083b017ccb82ddc9d72fdc0d2b1d227c22ff6d8497495f44828efc0000000000000000000000000000000002235f959b071f21fd63282fdbb46b1dec27cc193f3e9988def691c73dddd789b6a1adb977a68e2661fb41d62280f229000000000000000000000000000000000ccd46984208f183f0b70c9152c01fdb8ac078ad1d85f41e3a24819da321d9dd9321a8d70103282abe6d8b981447f202000000000000000000000000000000001711057042a54ca76b0c3e7f36f2fd49e339b76cbd2e053d93ec2838848d359865fdbbeb9e75e408b4b316d60ce2741ef0b271f02031a126f8632e30d8b17cc5b57de7b8b873e0971ff392d4246a40f400000000000000000000000000000000001481684941fea0f66c78faa40aeb4b5254bf78c44df7e37b191c095ff12fc94248acf01d2aac5637e9536e73a82c9f0000000000000000000000000000000016b72eff2830f49b24b1e1317c95143cda8bc11b9dc4a91ff22a24e0bc1a244c7215ab1040fcfbc292ab236ac73cbd3d0000000000000000000000000000000013535421771fdad616171f7348cdf32bea7486bf4d836b8b95c69b71ea9915c099e256287aa119af53cf6320ad86664f0000000000000000000000000000000019ba0f36dc556fcf09f0a4a6cee53de485d03d846af7afb792d16220551fb5a42a4261f936b008babc096e6f8f68b63af8b5c136aa5e2d670edcfb5bee9ff6095d85a332ad55763fe1e5e8babd145c070000000000000000000000000000000014b2da0add872d6e61253d6022559f668bf192b4aafe0acfbbf341ada55b404d42b2b31182c1ad50c73673494ea5b7d40000000000000000000000000000000018b76b74e9e6cda8466a354ff66baeb935b5645cf9eca81f4b7342f7914c9bf35c57be402458c09781e66a89cba6e67e0000000000000000000000000000000019bc8c1f32ce934b7ccae6d8ca39a263939585d8f94414c3880fc7bb5a0a27d728708e7ebc42c5a935f769adcfc083f6000000000000000000000000000000001636b62bbbe34bec06253887b78ad5b3ccda1bc5d8baafe450f2d1a8e07334ca79a40c5c4a50b58aaed96408749e6f68285193e7c10646a4601787edfad3d76e19d5b013a0a954873d92bd5293d325820000000000000000000000000000000013c0fd7a8441b6eb2dabfe8c152aa480015f81139c46440741f3da1c50d18c17526c47e8b8c2fbcfaefabbad5f8a0b000000000000000000000000000000000009da839802e7c6759a87eeae5a05146e1d226dd828d4ef6d908b4a0431008f352539f3abcd3e4c532a3d8204e350a8510000000000000000000000000000000014709634973e4554d2379e439d099e9be8bc7ef031b6ea36a7a85d2ff5090b0e0de7cc1c6b6a004465edcf868ef5fd5b00000000000000000000000000000000146779393d82bde1eaa6205e69907a0536c782fa7fc6e11e5e62ad5468f4422b3688f2ff4da2af396741ca5e0f97de3835bb2175fff61894ccbb69d90375df627e925f1ac430a349e75580dd39546e44000000000000000000000000000000000ddb7d0380370830803a7eda2e9b694af71381990f182b5d1223992abb5afe9531bbef8b9dba239f411fc422210fdc930000000000000000000000000000000018b685009d012d72193043d09f8968f9a41ce2fed598a20536fe54cb26db1733214add38f73148e754e632f6d78f524d000000000000000000000000000000000b967a7b4ed1bcd9f3da16584b08e0c28d967cebe7a07069abfb3bbce94d26b6d95d8a807879b24fb1f5ea00091d6dc300000000000000000000000000000000039349785fdb7d38707d8136e9a8f650c4491c50d7425388b75fe30da56147992c3d662f22131ba7173b2550e613477fa25856e5fb9547c48d41783bf2cd13493a1fd71e56b9c7e62af84a1f6cdae1c8000000000000000000000000000000000455d7799cc1c2af1e219b23e8683113fec126bad1dd7a441c5d113b064b552ccb1e7314dfed1b11f42a18acace706e50000000000000000000000000000000014d2400aa3e2270714b656bd755c4bba55866d6e313f619e10f94de6d82b5343ae9a9483dc10c1a72a5a21e619a20a8b000000000000000000000000000000000a6caa6cf8609d23b7873c908e5321d064a9c107b5492d296d04f92c308ee705229dfecb1f908bca0024ca56bc125126000000000000000000000000000000000b31c384423c84316f65e03ba9e01a8f626236f76e4df4b8ce2fa053c1c1e6a9b8f0afbc253db8c9c5e2ce9f9dcf05c71155c0b9c4185025310e8020eb52abb6f2f1780da15e4ba81f3c9a88ed1b4a6400000000000000000000000000000000097938bb53db8d0aeca3f2bc180039a5dc5269748e9cf065cd88e59b30733d527e54cdfa224e9690581e8c7f0881241b0000000000000000000000000000000002d52d97d4dd415fb18348f4de78c65e2933fc45d5e5e1d8f0f0ca1cd52885704ab12609b91d6d2d1ce13eecc7fa0c2d0000000000000000000000000000000018b926a37a8e0ad836846d06c03a9b84db795fdfe5f15d1fd3e0f8fef1b2825b29ee3a503ffb2f75765cca49c2b3d4cd00000000000000000000000000000000073bac093e958a3a09543e060c81b35b6598521a8685629f77200cdc73b372588e66c247097e7c03492c0943bfac4d6bc5610b2707ce84ce67e82d5c0e5f5cd2c90925aefc1e39468ca86475012df045", "Expected": "000000000000000000000000000000000f79110c74f0e983f3d3618869af1d9b96dadba61f1d596294ef8a9412f946fa26cf63483528a57299dae48f85ada81e000000000000000000000000000000000e1a9cea3af1debcf7d6ef6f7b8566b5bb52d5548d4caf85925109228d7c9b50d65a1b24f089631e75a694f8e8dcaf040000000000000000000000000000000010efc1081f079e841eaa5a65cd7c945d4f37acc92c4ace9ae6c69a9a95d8cf569d604376b1c7e63558d022da90d269fd0000000000000000000000000000000010b7f55ffac8d57c89b664c36c20b2988a493de32f5a956c91b16ff67cb806298a59adcde12ead42d598b6ca3e1b94da", "Name": "matter_g2_multiexp_30", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017b139e5dddd53433362c49403838b3e2ecdd850a8df12d4dfacc0bb98f79d40966d62dfd0da1e721e7c0f298457d590000000000000000000000000000000000fa35e9c2e37bee1020ed99516174408ba2cf443fed115fe3a964ed86b5e5369e40291dbfbab477e339003ac85eb7405000000000000000000000000000000000e8fb87794860237066ed1b7ae7c2a783c48c52c2267f3e7295d1f17598b96232954e1eb6d6e80e716628f1db8afe48600000000000000000000000000000000083521e3a6d6e3f99570b747498520db5c89092b0077519c8421f9f41772c7a6e177c9cdca52f89a26c6036cadfafa8b32fac970e52778cc90396a5ba92ab98e26499eb1ff17d4bc4c1f78b64887d3f1000000000000000000000000000000000b1415e1dc2d4c1f5619b40e616d258867493d8624857e41d007f82ba8dc53f7ebb36d06f8348b94eedb794899e97df80000000000000000000000000000000001c01656fa47d62b4372361b80ea61501cfda47da5534e3e2aaa27b1e3c4de0bee0aa322e60c476fd4345340e5c00e130000000000000000000000000000000010caa407d9d265721d55f01dcfca52bde851ebd918e8fc4c752a41875940709c64599f36fae5e3ac7f211e1f67890d1c000000000000000000000000000000000b54a86474dd5f410290e4b4ac738fbba5e88c6debec17e38a52090b17ef371dc8feb0573e76c4b61d7688547a89f6a36583bac9672a77f2fe62bea4364aacf62d5e10eb3a757fa0595a81f76543e8630000000000000000000000000000000001649c78147fefa91100738e50034424244d22d8e1bb6a2bf471e4c9b29694a5c9476f4b129912bb09fece53aa87deeb00000000000000000000000000000000117a3e040c1f54b96c2435891a45fb9dd95774b5a55cfb306c22517e4ea72172332d893047f7eaa665fcc58dd21781f400000000000000000000000000000000105e8d80d46e6bab2bb9ce0525cbfc82e8b3320ee4a8b9c0086e21cf2b5895cb35abffedd1b5a9eef21f62a0a1dc48e8000000000000000000000000000000001437ee33abadc8ef6bfeca16c3edcf05480c3dd97db06e396e10d5180472f50074f43f9a031a04dcd11d803462fefadc5a8e1d77c9e42a187054c938a8a5b4bafa834021b727036ed3941b1c1deb9d030000000000000000000000000000000003b51b10efb54dbc2973e001f0bb634e36f689264484eb128de2882d6600a43ad548bc7d1def4541f0ed88a1fb37f3270000000000000000000000000000000009dd80dbfe6663ab04656856f192002593df9ef7f792dfa81f6a51c658c4c9ce5586a5edaffefd507f51ccb7e8c8101500000000000000000000000000000000144160d5ca6b2ad626e6a3424ff5139adadd3319940afa9bff7dc409ac1fc3775d5413ef4612b27fd22c02c1fe57bb86000000000000000000000000000000000e375ff490a626dd1d933a5c751c88cbd61803986fa8dc089ccbdeaa0a922758afbcdc30d29268fe0a34b7b79d0f76c139c02150e4e89b25563985c7802c0c43d00c721d521b54e767c1f509f584bf2b000000000000000000000000000000000997ade20fe9c0d3eb79e61a66a5c272d02af668b0f3c8201a1ea071737f3d2ee3b0764f859480e95be75ab8845b407f0000000000000000000000000000000003215194b6a363d31ece09b18700479e6093fa3472a23ef0133e3dce60a3d56b6fa984b900162c4ad56a6899aacf35c3000000000000000000000000000000001647647bbc399f40124c43510469cf613732d0919e22b478b2603d7553927584cd4b3a407e3ec6387c4a93e9e5373178000000000000000000000000000000000bacc8afdd70e927e21521b3f62264ad4f22adbc872439ff851d3d169a1c79a0d02bca2aabaa0b9941ab1c71d092fac12196ec0e9d2f572856217521fcc5e2869f16d5ec5fe76f7d350698f55ff0c565000000000000000000000000000000000b0c5981bf6ef5b85bbc504fb0196ba442fe87302346688165aa7df8cf2642548760e11daf5b3fe2e37b43379afbfd4a000000000000000000000000000000001086828b9560aaee5e28bcb50db8153c40e632b18c61ed4105bb7f472b6a69ddd8a2836f6605102931ee66b2f07e441f000000000000000000000000000000000f4d7aa3d1a281af6f8afb3d886774f4e4a64490232f63dbe16e3b8c4f626e9d07f7c668d09cadab3c92d6fe852427af000000000000000000000000000000000d92ea3318779b532cd81c9be44b1abb179a8411319a6f8fbd7e3f158bc970917d3e0b25f3f3f6c8e0764011f9bab0398df5017c9c35604f061a7095d976d08bb3570ef8fb518cb606cd39a3060157ab0000000000000000000000000000000000dbd83910f304d0fb2b6d8619c3a308c719f6454a357d9ced03b2882a50692c06cda7f4331f54eb293ed5aa079121fb00000000000000000000000000000000019c33ec829367dfd2610ccef9842ffaa5e4f35809657c22134fb09b024e07949d8370ba8ba1e9149060e9bd3babc19c000000000000000000000000000000000ac468b42925d2daacb8574d40064d393caa643f08767d20e72ac0fad1447a64d8743523312f3a91a118d3e51e1f52d7000000000000000000000000000000000202d1971fef2938cfd10bef5900b91cc4811939f66f1f5578a8ae0eacb2538d2a51c1e025449e1637b5173ab7fa3b6f7b82e7e565f8a521d1a9d0ecafc029f76b70042e1ec36c20e3789b49c7e50ef00000000000000000000000000000000008b6709123b9bd501360fa463dd08076c59177dc0e8035c49fa2f541eef3831e4c584c5a9410c68999dddda6c86fd9d5000000000000000000000000000000000fb94eb34355c636dca909cfa71f52471217b9bc241cd3e98907d4a5c7eb67d5bc9cdb0c73c1369d7950a014fe6069fc0000000000000000000000000000000002e2ee515a5dc96a664bb1f862f21a8d3b7f903fb87f6dac41c3541f3d83633f351ba8dc4661607d24b912dd1ab097da0000000000000000000000000000000008bee545e00e3fc283185a85511e09fd0253e191f52d5c0b440b10228041800c013db3c9322a835e4927c0ae0b21bc1e8260c1b7a249ba215f0dc127a41876f858b20f4422140bb7695c8f98e4c474d00000000000000000000000000000000006ba635e74538748c29aa7c5690a0530f2b1970554598a432d4ea6d2713a4d26786b6e80f67b2f39e218b19323654ea200000000000000000000000000000000133ca9e5e0d4a8200d3522d8e87dec3c72edc1cf16b7305af4abd466aa7a0e30159388d34c36ea030450ef45b7940ec20000000000000000000000000000000004724239afc773688ea92296bae8845f20793c05807a18d6f35f03bef295da06f8ac9dff438b720dbea7ea93f3ea9c4500000000000000000000000000000000149c12922fd69e1960274a8b91384e929fb354936c020911495e6e3c49faf16899ec0c6e87713ee2f0149bf808ac8abfcd68d2b074d038ee0d9887168dc16805ed55df26329a4c0e062c2124a6e5066700000000000000000000000000000000148a4fe6ca67b6c785d5d8a784d5e68fcd2bd08294ca37f296b6426433b805507b554eb9f0fadfa9d293e8cdb8547d4c0000000000000000000000000000000003700600c2b7bfea54801ac95ff7a2c069bace31ceadab2947a0641462089fb43f0b9697acc005a23007a923ffe97360000000000000000000000000000000001705a769ce3c9a7a91283e4068c602d85808980d6fb457345a5f9b2499ff8fb3ec8383049b9b7cae96bd2ac6106a07fd00000000000000000000000000000000052b1f4e8a48a5eb2b2580614c656393819b4f0ffea874be899e4964c7e32d54757f2d48ca7b50e47e8bf6d6ab8ee7572a40c2e796148ed1c539b0584b90cb386844fdcde5d3766cbfb1d1b58626fcd10000000000000000000000000000000012ff8ba50d587765e68f95d276e364c8c40c00b55abc929f9ec240985269eb096dd3cef5826cf6269ecf54bc67773510000000000000000000000000000000000959492d74cb34c8c9ca4a21ddee97df99c8a6e627db3ef72200f39e0402d56f0a9709596189c80aa3aa50793e0f1a68000000000000000000000000000000000f7e5dbe884597054d6dc5e80bf4d0d333025bddebc1fdb1d61482cf15bcb4c8a95ea29cdd0925b5b816cc0bb307387200000000000000000000000000000000194e940c041d71f43ffaa51fbb31eb63c23559069b42dbf8777f35eddf14edbc3f7762c7b354174a584507ad714948234a1e176fb26983e549aefff9aeb220f50e071222073422dc2c44abd85528ee2800000000000000000000000000000000101a8e54d1fc2357df60b0ef8872b729295218f29ff63f7a7b6a70b3ecdbfc6809eaa8dc1f62a664b9987e8e86154c6c0000000000000000000000000000000015b5ddd012b42e1a600d738e05b551d91e7fcf3cb36018ceda9b689b92022224990c11a6fa0b421d5610b7e59b7463c30000000000000000000000000000000016130be17fceab55387d43179cd943c85ce1ff1881c07c937b2cc0645ec9ebaf0e10718ec7fe0d720f49bed2b8caf15b0000000000000000000000000000000017d73650680856bc11619e6acc139e137f0a06476f5f8979b5ba7fb8123d85916915da60d1f2e8c84197eef518b350c2a62e07bb97ca3805ba2d30f39f44e70a7b2917889c26b84bac8f9739bdf764090000000000000000000000000000000007d26bf37a97d532ec93a3eac00d9d39b064ecd172ebd5e18228b1601eb7a2c272aff9d88d63781b4a587c2c8582eec4000000000000000000000000000000000108000e850bfbfb02d7acef97592e15ca721334eb51197511b0eb2bd3bb647fc8f07713487b0a0bedbafb106992de4b000000000000000000000000000000001868c0b2ba732731f7536851f8005e8bae7b16545b39190251eb2bf93dedbf0803a42ec24cebd151998b690c38c0346c0000000000000000000000000000000016faafe909a1f926333b12f5463231a71058aec31d73893687d3169c4c3588436f6178447eed307b642490199c507d63a14278fe7a08174660c08323de272b2110047a1d1d8bd0e3c7d76dde030e00a6000000000000000000000000000000000331338cbaeb8e304fbb9257bb80aff5d3e043d07dbc476dec2795347e4c25248caad06ad14f56183d2b6276c49ff98700000000000000000000000000000000167e9578304a1162de73914b02791468e14faa2e0f161aa57818b8a169b5933dfcab787ec0f4b23737011163dcaa02750000000000000000000000000000000010aadfd5cc781e73c31f2fb64e7981b2e28614aa18dc7b2d96d2bb4ed8c2ee9089d6ebe0cf85479b272cb049e934739900000000000000000000000000000000128d7ea54f338064cd2f041f42a1a1e77d8b9be4ee55f568786a36f87f965d8142207e518798061eb3e32fe3b0f1541d1f516ab5b36a59e6300a54d17363ffebba35fa0c64cadb21e541af5078545b400000000000000000000000000000000004539f22654b3182d4fda5ab8d4bce6f1268d4e402b6c29a4cdff3b5abe0618d33db55ccd1ff12b27b2cb0196ac53e0600000000000000000000000000000000177e80ab6aa8512cc9e4d65b06b2bd76e33bef9038cdc1ab97fbb9d896ae2ad884ea16407490653dbe972b14e9c30c0b000000000000000000000000000000000c280a4431e41df6515979a694ce292f220278178f7f36e23c8a4cb2b8a7ebc520901ebe34c72a26b2c8a60aa1a155100000000000000000000000000000000006a0b80538a6c8093f3655905af1c59c235567d22192758c28dad1b715045189a412e4c1edc26e1d8ac95a584277709b3bcdb23f9568e409271b5f907fd64b0cd81939a52a6db38fd8d95de76213f7b5000000000000000000000000000000000eb091007672a212dc4937b314576963d7561657cf1103820ce9bc34e4d46c24f4891a4a4ada648f8cdd2c30f670b86200000000000000000000000000000000166389a37e6e3c02317d68d54f29cc98d1d1df5853940555161d71df791cd92c483eaad87dc0e765b12408d6ac344f31000000000000000000000000000000000affd0d5734cbc27b192c0c0e464db48d3d76799d2c6a493b172127ef2df6ea18a33898828effeeaceb7a203e35ca41800000000000000000000000000000000155708b9756752c9b44048c91d71970fd2cf2a4cae6b0baec00629c81387c8261150e78f856093d81e816be6403f1ee91b716b02b3e94600867e019be166f4532d264e0aa65d723dc0e117aded59245d", "Expected": "0000000000000000000000000000000007ceeb14945414d96088a7900c1120ff182b2a93b09943c2fd1dc2b0b223f684b0d4c0b1b5803502582f2daf16d81d2d0000000000000000000000000000000008df450fb25534fdc456a8f41cc143a84729ccb082aaa2243c8f37e34a6670f5195750f8547444c49f7a898aa8567d980000000000000000000000000000000008c12d360078d5645b0e095c90d4fd37eb20f0ebbc6fa93fa5beda7e7c78eecc06e0d839268e2c303422ab1769402e0b0000000000000000000000000000000002bd594a21153d7c458b9f804050d05caf2d90bbf9d18def79eb8148b7f89e3a3ac21f84b87fd13c39df5b91cf73460d", "Name": "matter_g2_multiexp_31", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003e06e2dcfbd695e9bda0baee1276ceab637fd1fbe2d2d6458c923c35b00edc7edf4f9e797aea59ff8cfceada0615a02000000000000000000000000000000000a04a2ed5e42fac7f064b43d64151a6c517ecf22dbc7563a3e9f35f555a9992fe45cf6a728ba94607df7c96f7e0a334b00000000000000000000000000000000090fac97f9f524168bc930d26ea1627ceaf187398d6bfc5a019c8467d75cd31a41c7eb9fda35fc85bd92b4cfca92dbff000000000000000000000000000000000f37b91dc935c28668c27d38328a511148c1739b65f2816dc53e42a8f059c9b2be7417a6f97c9a2597b1a0f06b7afc65bcfdf0495e49dbb8a8f9a0dc517351f39a6d823dcd42715f329dc78400bd74fc00000000000000000000000000000000090b834a587521729426d5b134c6058bf7999f4d4bcc0812e8d8b3ebb050961321b5e93356e87171a6f12160749394ee000000000000000000000000000000000cd5148c7eeac4aaea4288b38a02b5a901a6e2805e2b1695ed98ed86cfa0d259d87b65bf3cc9d00b8548100a60a371d200000000000000000000000000000000026db1079b85411dea0b9fca383956af50b938a465f35347605c01f3b72b297630ee2fb5252da20ee0d8ba5071974ed70000000000000000000000000000000012ae26c193e02d7ae4a7a01181551085dec9fbcac811c45d5cef19abf736ca2514e1259811970af5913891abe22a75ecf095238bcee61ec1317c0f98ad4f8f9b39c5940cf37a8a3a676787d9dda99438000000000000000000000000000000000ed5d8a609aa4f3c65a89b8dbc9334bd3cec6c7763bff298acd6c260e4d3bec0088e15c5d82618571d13b74a2031eff1000000000000000000000000000000000c28f92f018e6f822912b6eccfab37432ab0ab9acab751f848401791bd2f16e32ac6d97948bd8a0bed2ddc1917f0db3b0000000000000000000000000000000014083be2539d914883172cdc70950512dfe7be8893b1ecf085d837c2e9ba7f03656c5a0e15373e04d300869620eb66d00000000000000000000000000000000002561b77cc2658c54d29f8d1988dd7448f59c80c02ee9256404d8ef5536ee50104cbc11b6ee1ab9ccbf0ca55e53c52aae45a6d64cac817cd479a501c77b6720c6777c6026dbee471b490fee9f242a6700000000000000000000000000000000000fff05aea33a9d1e8f7b227c80ae87c9e7589ba2804904b7d8386b24b0e5324e718f29531251969a972870a30c310630000000000000000000000000000000016ecb8f27a369df13e122c981e7ae37882b36d5492fccbc86d606aa1198f3e4ee7bb7ad0555e11949e6c1783d8f4cda100000000000000000000000000000000187f425b675cb12719a01ee3b78ea73d88f70805f72d6cabef6372ccb9d99008bdd7da54f155454c4c59f041deec86f800000000000000000000000000000000151c272d5cb67b3f801e103ee901deb4b3d3bef76ee4e1b2ce1b5e663ed292845ba012c732d38f9209f82e77f1f73cf354868215022673de608cb43a3cb74ef2073ffff34c54fbb43f19b22a02bcc2ad000000000000000000000000000000001791bd59815309f2aeb7b07df8afd89a288eb6f19c7e613f394353ac5398267e1388c97b17d83104446e57f94581a79c00000000000000000000000000000000154cc72ada5a9c99dea06ebec143a14271cf332b57c631725ab30e2d308d6b688ca08a79efb6fce632cb1216ac3d077e0000000000000000000000000000000012b4c6fe8c17274ef57539563a736c2f83c4cb473e9d075a976e18e193255057340f45de373c7d6e3fe5e08ad0dd97d20000000000000000000000000000000005aef16e11bd4e7787bd5ab4427276ecdf9c6c134b9fdb2ec39e87ae4a5b3b674b5ceee29bcdf804ebd7e83960d8d7ef7068c3ba82e52fce0223a9f28c1d42681c7863c94797d1786c1adbc3e6d10dbb0000000000000000000000000000000008e57f905fa202c7640500746b590791cf9d0f160a77e5eaa5a30280e513e8e801c4b6b04cc3f80d9403388571d180ba000000000000000000000000000000000da3c128ae234bc27824062832ac10aa9cd4978f37855a8b4cde3822f5b485fddb9a475a9805e795519d7f138a8199cf0000000000000000000000000000000000ec11b7e07710161fc557a56e04337f71aaa1a0f070cd84525965e53a1fe445c91ac07c618ec349997890ae893c165d000000000000000000000000000000000406b0eafbb8782d11f5dae2f6214282252af9ae9ebc5c17a81d4ddded40f05d0b534d14019bcb6cf4e49c4c182b90f00042b8005283c7b91ef4b3ff7e20a91349c8c3d1301c9b54b901e8348a7d186e000000000000000000000000000000000b1d456e66671dfa72ef3a56523eb939146226111fdbbeb697983928aebd5f50b0518db841a3d48912a7a780785c1f180000000000000000000000000000000007a15b2253496b78d270dd55b80bff90583a95283a89d40f6df71fadce56d103f0d365fe79256fa4f93b2d2bf4c06a2e0000000000000000000000000000000010829223166d38fd2c3041dd5643c9784da366a2ea8cbb3abdffb5fe43e975318c86de0ac9ec77c0126ee75bd209f7300000000000000000000000000000000004b124018e83e1e5e77bad42eb831798d450f8ff4a79c9b14f67f080047c491fbba45db79b2cf6015188f9fa6329e8be0a3eb64ce8fe140d94956b0685f91a5462dba1a90093e803dc617559a66d20da0000000000000000000000000000000011119be42b90c7857079a51695dd5be08e59374b0d1c7e12d0ffe870202e1f0c62bff84c9691679a82e610e788b7b5e1000000000000000000000000000000000c7a64524c5dd1bf10d16da7f15b39d05c9ee1620d4dcae79c60316a1f522b238e7934d1be897a441d0c8e621b67d44c0000000000000000000000000000000013045613a090d05d07310865d977c8e0bb1caa713b2249d6676e7cfd6f4e3ba8e667deabf9fdf7fd527685f7d251b178000000000000000000000000000000000dfee7f8259701b5726b6439a7ce77b92245499906502c7dfb384e29cafea61f3b1f21fcd7888231569ebf29d3035a61ec88ed0eac8d0f2f618530e91cdb9ea36b8d56c1001a6792a09e11ff65fc02aa0000000000000000000000000000000006d77669207bb2d064824cb56fc786c631936d30db630be3c08e18d7e95b1c26e2d4e7b2eddc2f946fba6e99acb2198a00000000000000000000000000000000168bd8f291f8bcdf8b5e9fa915f7f24856a62803bbbeb9bc38384149008d4e3129338035061631f1fbaceeccfaeef4a700000000000000000000000000000000146bf2dedc262557dec2b4545c94a37434e20e4900b1693e8fa9bda9a94dbd07e0a3bee5f3bedfa42148791f4951db7500000000000000000000000000000000138467700fd5088c76af2f77fea4b746f98701fc0578571997b0ac2fc343354ddc8b2dc57d5298dd4daf767573d8bd3d5f03e53ff983fe4886a3dfc03a353fb77927d7a0d1998a1c55ca7421a4bdac6f000000000000000000000000000000001536da0df7c91687339fc93608eb404c5f46adf4b9122b99b1e5cee0012e27ddf30934d8f669bd39091f8673aa3b3c490000000000000000000000000000000002deaa8f9349e7c551e39751b1454a00f8f7896d63110e8e42607e8023ae3070c4abc9885ed54ee37a82f6e5c68451e900000000000000000000000000000000079a62eb17f7b07d4117956d3dab5d16a7f90e98948d5c3caa124fcf755c73f060a90d002cf880f5246a87342717b4dd0000000000000000000000000000000001246f0f3ec2af7c0250ae14cc67b5a1d42309f06c6f47b89178ff7534c47e8413a26a43f27454c0f946c66634563d41cc1b04dc356bd348211ccc4c50d12cb382660a4f9526539c2a0c52b021ed216500000000000000000000000000000000046e4a08785de985c66c7417f9262d363b9acee07e250999a4a7124f101ec4d82e3e4b2b0d9736471329fd61d0cff13b0000000000000000000000000000000017bf1e20ac181780ced62a18c78b378fc0dad157cf30d6026680560b681f5755183bd30b4e454764c08edb93297590b5000000000000000000000000000000000a57cbe93254bb0796eafc0a57330e38bfca37f8b94c4d21ba656e5616239e1e18ba6d632c0129d30291736fe37a4ac90000000000000000000000000000000007f31df7dbe9abe15f4024d8f6bed93c92ff5bfbd7835e08e870eb1bc4a6f62b3809b922c6d5a7350e2e5a978c80a67397b584ee05c27d45390aba36772ed49d571837567e95f1fd3ba3fc1ba5916727000000000000000000000000000000001577abdf6e915c9c3b3fa50a4601709cd629397f2f91784528e4cdbb140065fc2a6ee3830983dcfd49a928e78cf530aa000000000000000000000000000000000d6f98df9e41009837cbb05bc3e3340d38e56a448fe396bd48acf03f061e7489d1402b36a84b3c56eb859437e9c406f1000000000000000000000000000000001912afae5361c3d8c6141755deeef26d1fadf6b0036b9d05b2e0c4d50f42328741f0423ac772fc66dbc922bd4a837ac40000000000000000000000000000000000616661f049b5c784ba05334b2931509e1e033bd203fe17f04cfe12e80e73eb7075beac9d379fc1c457bea1b6adf365752542cd551cafc5d50852526ba0a23d274317e1e4a6e75c0d19319e5853b8b6000000000000000000000000000000000f98fed7e4d67a513c746d2fb188597a605165d5d299072aad6d621e077845f93804d575a5796bfa726f529dbd90e014000000000000000000000000000000000adb2d0b6c02e4e8fcab11c7c8819e87f73aab673ff9dbc5c50fee751bc7a6a8d386c8f9fa830b5545f94a73ce6e1f1f000000000000000000000000000000000f08e05ac40655cf59ee3ea9f10fc900315c6f06ffd3b80853560559f580ecdd65aba5ba660c729e0bb9576eee3703710000000000000000000000000000000009da46469f4b8fcd8d2b016e96f6e6582fb01c75407c36c7f87b4a1cd8f08ad06e962a0ec2138ed6fabaa1cb0115f97e2f76a0fa585828f79553fbf3baac6a2776b782de66dedd6b734f9342e734ee3000000000000000000000000000000000047b45ad2ad4f7b5b72194f98b98b2150b5d73a9df2aeb2377beed9a1275a882fa2d849037ddb56af632489f892a48a7000000000000000000000000000000000e1b0d9b52c0c5324067857ba4701f5f20eec165be418871fc0f0adbc3a0bbdce5a33277a33b79013109b81e006c621400000000000000000000000000000000179c471e01e340d8e6fc0f737ec09f0180bd2dd2a86d0817f753d1e9a9f8cb18178e9de68c596dc6a824e6c3c151d8b80000000000000000000000000000000019405c1e571a9b200ff2949aa74647dae59d92a8669d4876ba23f1b4a12a1f9412412503c68acbd619cae3ff056bd346f638e6a70917c89811851109296a7225f9c7c5b3d7fe6d6ba6c7d1ee77db4458000000000000000000000000000000000ca8566b9bd088c471fd33fb7b1bf760ee12cc8b0cfa9ad92b45012cafef5c0772d9bd3bd9b266d6c3e3890c8f00057300000000000000000000000000000000055789839e786ecee7fb7d10f3876359fcc1bd6f2c5cf25c8337aff7fdeec9b43ffbe932cc4936bb708571a59e4339990000000000000000000000000000000013cf827bd57d8179d105f34c147665a072714ccbc114aa4e878d04ce66ca78bdabdc4867b3968c75dead147257197c6a0000000000000000000000000000000014a8dc5ac1858442ca627eaa194e1ba64091b5f9ace551338d770c92fb49ee12449dc200c8c35d70f9e0652b4d9b90da1c4ac944341dc68fee586d221db2a8167e833f18f012afa7c3844def6dfb26bc000000000000000000000000000000001124ea2b97a6d73c81387a51e814b9bdc951a773db2a32d50691be60f1d397cd4aadd9b06e4f49c32b12254e9f824fe80000000000000000000000000000000014cb365e9780feeeff3548f34a56548302ae0dc73402c40317fc819969ee9c4ea2a181381b94f82dd97a236671b456a000000000000000000000000000000000064b769c4b785d45472038aeeebd3ba9b28b3132d72023640ab2d7512cc6e31296c5330be5653ad6902e4e15e57e2c3e0000000000000000000000000000000014c7bfb1f142d69c17f73e23011aee0063a97a99d982d25ff72791a65c7a68941a80fc216cea8a49f3df2d0748b1f95db0eedaee9347b10ab7b346fbc16c10cc9db486f561f88b756c269ebbba23a7f4", "Expected": "000000000000000000000000000000000fb1227806c750e0eec0b865daaaf51afb74a88589d1c035c60dc1913f05c8ab18de24903ea876fda27b97a5eaa2fd7c0000000000000000000000000000000019903e1341f0285658164f9273b5c958060bf836264502b9dc298f75d4104d7a43b8d5dc0bb934a506ce1273ba839d830000000000000000000000000000000006e791347b54057195189e8b9f10fd42d170f37d455c0af5e92cc6a12e2c23990253be6855f4be6c84a708852c19a6f90000000000000000000000000000000005b72c361dca430fb2414b9d5a326cef8b77cfe5310153d6994dc1f8b9e74e8fbb43079e21956f428ed8aa48d6897e32", "Name": "matter_g2_multiexp_32", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000052acff88605f33a0cf1201e8101c95ca0befd443c087265821a7d954917a026d41ab24d29bdfd972bb52ff4ad6de14c000000000000000000000000000000000e134b2aac3f6270e43afd994302426796b1e362031638fe0263c0ec212b828a30d8321af34ef7bf260652150cf2293b000000000000000000000000000000000d6628f675008099e9a75e1294803e86417ab22670d36316798680289ae61a26821693f2f9efc8468721a1097c3bceb20000000000000000000000000000000006d66ffad1a2e0f39488fd3f6e0214c9407528c8bfb8d1ebe6d75596a3e3cc844d00fdf46ce7ff6cd6d67732874a24a484adc8cfd2e42abc2f0e0d7e9c4b378f73731905760bfeeef01c94f8d5c3cacd000000000000000000000000000000001160bf0f7f2915cfc64e12a5a91b7e2aac78d4c2ce362e7677dd0e9c0172b37fd1b52222a13c65819b87593ee32a9ba6000000000000000000000000000000000c8be2cbbd302b31b1ab6dcbeb57b4ad428447bca9159fdfd007f5375218d121673a010f2c7fdf83fb45883458fb068e000000000000000000000000000000000363d3d492e6e6901756bac13b5c32d55aabbedde878115aa41b57d27b49a0f017a61fc90b13a20e009989374b82f5dd0000000000000000000000000000000009302fc26e6d750ff9441d7471903cc296b320128de71f86c4eacc80ce0725e8eea6acd2af056abde2f61e0a349f9bb5bbd5d4a15998d733326ce23cced86ec5d5b410c29ee98a4de19f2662c3933dd1000000000000000000000000000000000b12aca17efc103cad500b3d773e43cb24df6be651963c0f30bca489f1dd7911ffc7204fcaa4511e161c6f75da4a5ff600000000000000000000000000000000179a36e9292d3f78a5fecbec1175f001bd4ac0ff3610f596aacdba29a12ea4844885a7c465e66d3883c7fc99d4a7e06a0000000000000000000000000000000016bfd0758b31f54f90eb8562bb693c45a92a297a3d302279c9e3cb8263efc0f31579a3af8e8f5a091d9a6a36776f445d00000000000000000000000000000000020f6c66fa554a5cb610ab05d194e7583e6798a113b8fff336c986f7358bb9fa6a7aab0b04be9b5c44a6fcfdd21999e83717aadf16301a9c8741d65c86ad7f849101e30b7b1a344643b100a8582a6ad10000000000000000000000000000000004bf40c1d2d3574ad7fe128ee376364591b6f647f939b0b556ac3fdb5a92873f17c007e926b8a39a97c814728f355bfa000000000000000000000000000000000b8669e10e0a538a421b717287455620b82574b96ed09f64db444ec73a67a3227503e1b4fd6869314214071399eeae0b0000000000000000000000000000000006ddea4adb703d7205b6d2af436b41b4bde3a8c5dbed9dd161c9b3b466ebf06beced64fca25c3bbb97f232315daa5565000000000000000000000000000000000d97248a25ddf0ebd0200c6abbcac9ecd9775cfc5ec8da91634e77488bb592e5ff277a9607fe721990f403dd73f746e622788b3597da7b9b106203dd0ea97527aa8f5149754bbb0c10bb6eca8a46d94000000000000000000000000000000000135bc4f28663a6d7d995f6b876ffb8e6ef1d2d0f232388aa5f390c57e8c48cb84d370ebc4bc267eae4466a019c9ed56e0000000000000000000000000000000008b6a9d13dd9d7014df6acb59f80b335a751fa2ba4dce63467aed18f68358f5cb743718112b3cb2d0b5add34bb6989000000000000000000000000000000000013a5389dba4da195f34fbe798b254403f0bc5632ed98bd6017ef24fff33640ae493c1bb7a77a0d3c97649230e455eb51000000000000000000000000000000000a69803a4cc237ddfebc51df2d90fa1ad03359f9635ac1646bc942546575d1558f5f2c3010f6e2207849ee697be41d093c21276fc1371060c226424eb9886de6897b15b075fc5a51aab4710e9dddd384000000000000000000000000000000001939c2431f8ac4ab19d2735f122c0424af2ef18c0028e155611237e86648bf1d74fcba3008f5c6aa30feb5d4a14a3f3f00000000000000000000000000000000174473eedb54aafc522973244ec2feb3f7e95e50a1e996d1100c8da4fa59428c280f76e9e7364906662c4d2802235aa5000000000000000000000000000000001021d15f8ae2f62dfd3862944bf3be88d86d8113f4be22544ae5e925d450044279c5bfa1bfca44cd5934b42a27096b510000000000000000000000000000000015e0f20efae92e1fe8dea2222ce808a7de9e9e861c333db139f8ac11d7c4fa9ae6e49f51095f6e16bc738dc6d094b4cfccbce4e92cf377f67244995badc72db0b80fe37c9b7d443595156fa41abea17a0000000000000000000000000000000012d70691721f5787ea2e2a652f9c65edaf763637f95c285a62d32dded18579b7257493e01eda19631d00ecdd4e27a9ff0000000000000000000000000000000014da9ef6076e646e7d5b52d1803d3a6d897664851c6de2a9b330e48695737e05f0369224c3eb357bf557625bb94e6ea2000000000000000000000000000000001554f68124a91be5b9f325394db23ed5db8f6c46eb46cb50e57947bae00819b151afbf4ab4949290ad41625499f42dc00000000000000000000000000000000009fc0d459e28cd1239d227e1d2f7d530b9d14ce5638cd308569300a791c997a51dd5a98aad703239a23cfe7cef7f47f6ff79345f31c107841ae388f6cf116d10bc696aec4933de56bb9affe7e20c649f000000000000000000000000000000000452580d6a37a07038ce3564a12c1c7391fdb002cf27a6df7e194b38f3c12a3026f2a8acfe5e634cf89140da256d0a420000000000000000000000000000000004b73c9a4f9d41b8b84e53de538e4b15198f50247e75c274c14f136d7d91dce4a62c5346bf11a105f035e29ccac3dbb70000000000000000000000000000000008a8a3b2705a82b551f8913853f682253e7f1f68c8e42f349337f4f1eaa5103f59430af0c4a124b6a739bf88298c5f6f0000000000000000000000000000000012f4220609899e8610809bb3a4da46e0688c285ba2e8750b4bf44a849cf15fbf5c016e8e8f9372239bb562e7f38916e921cf773387d5351aeab99971eaa3b207fa6a318ad60f1c3e16b7f68251f9c910000000000000000000000000000000001884558e709635c046bd6ea8872bda936ba4d5ebcf7a0208cd0a4ee08b69f36dd2e136ce655ddfd89a5b1cf8e48f5ef7000000000000000000000000000000001357e2dd9fb603e5190d7b7ee105668bca2ed23ec6a248aa71aa430c2b2755747b8dfa3b147eb51ea644bf0354a61ba000000000000000000000000000000000009b0b0a76c6980e62e4893157b85f59345e1ac81e1aad1e48acec44c4803e2a9080f0d193fb799e0277ae6f1058839e0000000000000000000000000000000014c984ae4ef5d9d319fc89895f34a7db02747f57b206b0b30e8c9757d4b47419e6c0c8378fdec5aba364936a3b1922ca2d69cfed6bb2d33fedcbd215dd4e9632a3cf86a4b2716406305f6a85e6090a050000000000000000000000000000000003e1bbb872db172a1fa615155f81aa75ee9760f8602e4135ef9f1640b7f9d54bda911a220d211dc4bb767bc2b5e6e23e0000000000000000000000000000000008464f23cf693b1d4545b6ce4aecdc8fd182cfb288c5ddb1f78ca578e9b16342c8178d886cbb6b8086c0fd1318c4ae09000000000000000000000000000000000af574c4d0fd86087e23daf6d9ce98765e1e445ef9152dbd68152fa4833ada0be440de4abfe7c07dbd4ee67f1a4aec9a000000000000000000000000000000000a8227b982f9286b03c4d49766687622206213d88cde007360df9b4ca5916c44ce44dbe6443577998b4b0d527d22593379cabae288f8a9a8cd54523c20825b8fb07886bbf0ba0c5c807956f268af4fa10000000000000000000000000000000012e31070a501a7df7be43dc23e23dafa32ebfbc10ffb4c53f5d36bab2af69db5a05ad64b9ed116560e40b71f9217189b0000000000000000000000000000000011cbcd38ec3c6a6d49df6a8d6e1029a0412b42bd3fe8b42ed625adeb5a2f631e97bfad302de82ae34f715962b5ba0289000000000000000000000000000000001019b1b619fde9fb885d3c5f03a4373358107af7509754ce1ab2deb67df536d05e07ca7d60d927c15b549502750054f90000000000000000000000000000000018f1768b7140484105cf3ad2daa7c565e18eaba834db3f6bdfc9ee37445f2d6f7dc2b4c986b7efd5373224d2c92aa5a81973977d8e8c592f9063c5a14a658990f9c3405643089eb58324cd3f05b5b5e4000000000000000000000000000000001847b14146cfa2e1700f368f414b6a66ccaa02ca2a90b40a8e2be2ee4eb66af77ba563d7507de63362fb18426b6149610000000000000000000000000000000005c028d2b344ccb6400b53134bd179028b8774000ace89369bc655bb9dcd1643aaeec830407ee941df5432ba27987e8f000000000000000000000000000000000c4a680e2157dbdb53ae761209d505b4cf6b18fef5aff1c5009ab41295e0ce2ca23bd7a4f983fb9d085e1d0dbc75ffe40000000000000000000000000000000013c0cc77a5d771f1df99d1530e65ba782604c1ecf67d08572609de9f18405b9b817c2643226cdc7c9ad35beebf87dab0a610bfd375a7b8d0b034c17c8fa27d4366b06c681131fa7daaeeeb08e25c2ca60000000000000000000000000000000009f32f2f83c21875963818872d243cc8c70b75234f53490eccffbf060cb3b9c53545c1c32025b271514f500b20b00ec10000000000000000000000000000000002491b571087a9e89dbdd039ccd2c37d5d8d25587495b2d7b0066e9dcca02d44b2c134b0128a9a1527396729f069df83000000000000000000000000000000000264e9c47f72b639597de8f26a42ca7d77324f8c0db705986fc3b40dfb46f47764b69c70037a68d76a5de49a278779a100000000000000000000000000000000090614b3bb302ed9fb78b8756524fb78d54a4390b27136087181342571f994b1a93faee28256d765a8ff4f448cc357c199ffe1dc2d7526338462860501d75380a5ed9d53e675125342afb6652a97437b0000000000000000000000000000000012c716ddf17fca0d974e8d6003d99aa90f06b201fd141c74d8fdf1167030d14dc732917d3c6f736c68fbde9df50c098a0000000000000000000000000000000000261ef2b47de8e1576aecc6e19ececf80ddc1f4e28b2ff27953a65199f65a6211db7326632cfe04d543895c727ef8b600000000000000000000000000000000044fd6b9b4a1bacb8b7d4c53c106b025ae78f17c3baebbccca4e18cfbdbcbf8b3ef88ed5bd9bb36d9aea9e24f4117e760000000000000000000000000000000007721612515fd075811ee804314acec9d389900c7ef883e866f71fba00c49d5c4dcc7a2b8e2366f5a93f4577926ed171fdd97465982b58e69993711a6a64134bc4e76b88ba1948af91ba3339e9b9d3e900000000000000000000000000000000122581659ab1712afc23c23c2986394de8e155bcf722e944ec05e7e42e05acc366d9a7abf2136b5dc68a8dcfd4a640bf000000000000000000000000000000000188842cf4ef54cf77c145acb685d3187cd9c842ba6705bfed846ace83dc4400c45120fc1d6a633ea879840d3d0c902f0000000000000000000000000000000005c8966862ed4458a753155ffe2c64655779860149641ee5511a46ec576798fdb5cd9521528df77bfebcdaae2f94b865000000000000000000000000000000000cc10d888d2b7a97666de99ac14a501b7e2171f074d30d947efd67d85226c312a7977cf923ddbc88c533f08a99f2045f786a2a3974c84752b32f29707805c71992d5d473f4b7bc1f0757d126607a1c07000000000000000000000000000000000e5af1420546c1a5a0e0c2bd9241bb7c7a26dd52f4f358fc868bea457a60bd4f6bc5b60b27069fb4f6760813a91ada740000000000000000000000000000000017426a65d239b1d9505bef2b476799c394fcc7bfdca36a1ee5a600351334dadc238b64cf8a667a25d4880a31b73c53a9000000000000000000000000000000000f151587944aad17429b51b1c16193c1e1c93cb412538d1475473666c997e012ce618eb841c4e9e064a08ab83d7fa60e0000000000000000000000000000000015c2e049c532db585807319c23ec077a51f288fcffb2cb6528d3697221e8542e3fc85d18b079ea1b217fae30858a36f285d33a7fbe6ac6eb42eb932dfbbca2f771ffad5e80fde686e5df9d34e9f83ad6", "Expected": "000000000000000000000000000000000c9be91da9bd8774f18efa3ae9248e4b03d11c49b377c372613b7e745882b2b23c49d518672e58eabd4d9b510a25d8fa0000000000000000000000000000000019687b9eaf5d68b0e795cd57055a74e44efb3e997cb038b7f1cbf08ca70e80a1655cdb04402c542a92ae4e435c22d0b90000000000000000000000000000000010aa1514402ce348d1d61b8d38b53017cd3977a84dc14445db64799cfe822b56a0adbfc5332093ce7ea1f0f438bf15590000000000000000000000000000000019ade30ba0faffcaede95aa272be042aef090f89d9ca25cb825846c4bf9e4c1dc575f8968c88ada51fac71f26fb01517", "Name": "matter_g2_multiexp_33", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000a1346771f8ba25fc44323d5290068e46b3f756de6d97aa934d511979a1486bc32173575639a7e54aea8eeb60f32a8c3000000000000000000000000000000001958ae7fce87db47a65a03402313b99f659ae02e8b62db3525d48dc9075aacc5e5abb50156e704701f3ceb18747e0431000000000000000000000000000000000f98778311e28b4081aa76a3f9546b94c29d86fe8e66b905265d74ee21928dc3ac463049f70d355d8caee5b59d65e07300000000000000000000000000000000185cc233ce72770ae26406476c1779858523e7c940d69adf2750695cb12440440686b6b918f4adb3b14aee9aceb6422119582dfd9cb80d44c17c5f62360e62f6736d186194f0f8483e34d8d18d832d37000000000000000000000000000000000ae2f565a44c8e07f2a136368798a44926cffd3c3a6d4c2fbf91763c20d2bd959271343b80eccec4d59a84394c7a3ce70000000000000000000000000000000009481a5fb276c938801133adf10dde3e7da2087d0bcecd3c9435b7de544271eb3b07a69efe7e168869e727868f24b0d90000000000000000000000000000000011774e0197866b1c8b3428d353d2c9f6326a77ab30d5595e2402a0486f03ca6ebb1e8dd335a60a772dfdd9a3dbdd3eeb0000000000000000000000000000000011ed2480d79f73a67a2adaa6da3ae4f1e1c28feaf0e4cb9aafac658901960129e40f6415ec80a31d72004899326f714bac0bd9b8746fd02aa70d8b8a2b5d3be46baecf9449d8cd3d620cf9efb3c615d1000000000000000000000000000000000a73b0d8c31af2deed481faec54095875639233bb09f31b1c7c745cb54778d1c8bd0a230e963ddd2ec8d178d31fc14740000000000000000000000000000000015a889b16be93d0b6dced01f5e2278ffde1cef0576d0b04b49996cc5252854f879e04b1ffeb90e222f4b9d5fa350767c000000000000000000000000000000000b53dc4d72e90330ffad17012bc7dd2e497cf8aa6ec73bf25c10427e23fd28137631249eabe9d0308c956dc7a9e92047000000000000000000000000000000000930cdc5d04ed2d1eb62937d9f72fdd733c07a5a0e392fd5216100216b1a2e3cde7053bf766f046cc470d92bebaf6290069d889881d5bb87dd65a9a02a7fe239bdb55ee54a6310bc987e7c5772404d7d00000000000000000000000000000000131c4e590400b69b3657f7c67272b1e3491983997993ee87c94043001d78e605965abf3c1a8c8c39cc08d5a5ef05520000000000000000000000000000000000124f71c136dbb032504da910958e8a7949f1dc5c061f21d50e439e01e67919891633b3bb84fa8a54c69b632f78560ca70000000000000000000000000000000014a4b1a05f1060853f4294e669a20b91f939793a6eada6dbc84fda8ab11509b256d8b785b252a3795f1d2b99a51df05d000000000000000000000000000000000be2489f1f91d7adff356236859679c46b6bf8c1b375e8bc8bd1e97830b5ac223ffbbda60ecda168bacc2c0b90ed25d3be658348e299bbf2438a0c013f86eeeb69a013b8004a4996189472f3372b326c00000000000000000000000000000000111ebb796e8770d5a69e724a8d3ca62ef1f13778baf4ba12bf462211d35e325ff8e455c85237a73a3046e531f2e2255e0000000000000000000000000000000004308b76b06067e0a07bda143341220809b481b40b78edb2e24e83aa0f003d209198825b5fa9bfd92597e27a4054d3ee000000000000000000000000000000000de74485713f5c95653e98b96aeefb79b59911a610c2a848a807653c19d50394fdb52178947c779134d24b6d396ca36800000000000000000000000000000000069f47a71ad765591f6335b962e7c2d87b556801e1e6c25b449edc83432612fefd405c952397a704e9aa5a924769ad4e9b9d0ec92ae7df3f52a95747659f8fa3ca2cd01e8d7ef6de384111246886bafb000000000000000000000000000000000a3f89408ee43c0ba6a7c9c479327ebab426d430e3ff212c65da6364b16195619d27eee83d701a2ec50bd4b7acfaa06300000000000000000000000000000000092715831af983f740ca2c673e7c9c47727d64165c59fce19dc3fbbdd0b6a7be66288ea1f033ebb5ae2b38b3762edaee00000000000000000000000000000000071ca6fa9e546d4bce965b2bd0f0fb97e6833f05cedcf66d43ec88aba411dc4d6db9f1591de22f493f49a1dab1a2701e0000000000000000000000000000000018f89932ec032fc28775d34d588169a1435bf4ad7e2ee11c9d6934dae31324ddb96b3ef88f95d1bb2e52c3c8d9c01516d2ffdf1237b4e03c219806f2dea745c94bf08924e1b9f11deeedf0db19da6f3f0000000000000000000000000000000011b5cc382164fc21c9a72cd85acf61c2a78d00a16a2dff938f0b36bfb3bb7075845a1616001ab53271a9a257a38312cc00000000000000000000000000000000139ba2f27e545d45027a0b11253532e28fa691170e08608472ce3b3f9a3e9398c5ee76953b1a1d01a5e79f194c32d1f5000000000000000000000000000000000d875f44829555cec695f3f4a28078b0a6f168bb0985793d003443b75a141936f3c7c633518890e0f7238416d46573cf000000000000000000000000000000000675420ed817ecd24bc5172d3e7df60ac4281b24ba91e8b5ca8bd6a8321f5c7312a6ba043fbcdc467c8a5c957590a692cca0751c9534cee7f14d11b7c8ccbb2c537a799df59f850bb125c6362d72e9c400000000000000000000000000000000107bde844286cd3958cc7a1314127322251699b51d8af8e6b57495497f21a84e05612b1569b54fc5639a75e9f9deef750000000000000000000000000000000002355b1a60e24e4879448437d2c1b12e58f02d7eba88583e96e9634f7e2c8c6886132ef0488918f665ae3f7b6977c7c4000000000000000000000000000000000fed531e437b70bc4a19ad63c61ccaab49afc50fad1f156b1c8ecba0e1b703f8aea61882c6327d4d8fdd072df9c4e73500000000000000000000000000000000182177409579ad53786539514753c696c8757b8c4d9b8360392f24b591e43ec20e84c0abe468061a9e5e879c5c81314217f890a1120daca4a1bc1bc0fa7529f0a87b5fd6ec385f12b270bc0f1a5281b40000000000000000000000000000000001fb25395089228772d6000025cb0356eb510c964bf7d0c12d47a6608fc18cc448e44880eb5ba8475cbe6418fc9d8fee000000000000000000000000000000000f3b9de9980e5afaebc59c56e02fd75fdad13013842ac035f8d5569a46cc67f0cee461a939aa5a3d8fec2966294207930000000000000000000000000000000009a223ac0edb164845eb8397e0cae4363fb2c8c996c3c5d722cb50be56cc3789c732763cfd4b61470886dc991be39f57000000000000000000000000000000001909f17b229eb351dfe8317a8273d846edf14ad5ee0ebe8cc2b595ebfed19b73983035e19ebaee3d05b1dea35968586961ca18257d9d989ec13d4f158b18ec17d59344f4558b6dae6c0aa0c2f37affb500000000000000000000000000000000081fa9eb8ca7d9db52380e4c408e6d5d668471bafbafd62ba9023fa08f6d300a45295b583677824c29ddc3254439cadc000000000000000000000000000000000e2e613043b1566674f791dca9d860a49a75dfa24dce3fe18f544a9b24ec5266a64e77386b672c93fc4d079eb8e76a01000000000000000000000000000000000f471b86ac5783d720e7d73e8871474c8665e8a109aba27c1172ca24217eefb0f66c53232df1672dc0af6ddf9640e10d0000000000000000000000000000000010667cb22a6a818fa7c729e40a7e70e1f31b0ecd568b54a4d352d5c9df8cf1072ebf2ef1e612efd96bddcbeedd8566430fc004ed8a135ad97cdd1bc4d0c3ccd15e65031ad7e3cc13ef2c260958bc43be000000000000000000000000000000000a0ed87b01f27f26380c6285e82bf2f12ef3016c7e7f3a13041d465825664573db47be6cf099cea615e21f6a5d759b6a0000000000000000000000000000000007afb2a1bd50fa0fd3174d70f1c8d5c229627a496bc9bb89d4f52d47b1862e14d704dddd80045e58d00336e898a996eb000000000000000000000000000000001698f30f824ee5cb71b3f2451953c371987433d2eda570f2a13262ff9e5e529e316b06ef6aadffc152803b076f22db9f0000000000000000000000000000000009eb1d5f3da7cfe9b40a70e1b3c3dae36436e8d068a79dcaa283905614676645c99a5a165630ad46b70bd6be8b1f21a8d8cfaa1037e2c81c6973b221dc7badf25ebe3fb4b42bbdef1124265df2c7ccc40000000000000000000000000000000005c4390b8f37cc3fb9f248470b505a5d9502d44e4a4459d1f56452cd9aec89d114f1402fa45935930fa00888a4860a9900000000000000000000000000000000163b0ca84b5cca4f124bfb5a13a4a3efa677a84dc89b6a61e69d0aad34fade528614e549a7b2326d1f6016bd0d35465a000000000000000000000000000000000bf450dc8af483a9f993a29cb47d5362c9f5ef38afc2fba8040e14514eb834fec6520a413fce5868aa9a2c7c3ff6617a000000000000000000000000000000001063619f384102949fa1f8353f0aaa5031234d736c54103df6ef6fcd0df02a19c3aef471f0413a1e19febed6395459a0c25ecc5d37659ebb0c9e21ea2f8fddc518e3d8faa99627b21faf105445f69d7d000000000000000000000000000000000e35db3017963d3a9d62b7e7fbfa13ce4f5fb46a90c1285ddc0fa481d9379b95a77e8cdd4aab5c33059bfcdcd82473fb0000000000000000000000000000000004fa27c663c8d21f041d15cb199d31cfcb96a56cd673b730dd111bf03cd954cc33799456674ed4d58e8e0dfa826a6b26000000000000000000000000000000000e0df4e7f943db5b5c27bafc7e1ce099b2caa64642bcd6336ef926352682fbe81a1945b266cba7eab52b16f4aa63eb8500000000000000000000000000000000020167756b8c68f535c4691b1249ca1ccf0a539f7274623ada824d0ba789ef44ebb20ec1ba51d46c0a42da78653d287e26cbb32382902d9b1963779070d749cbc4df1e7605f840819f2c04aaf89c732f00000000000000000000000000000000178037c6b5fd1c6c396d8aaadb712863557feb744d2cb9165ae5c36376d2c066f7b1648e083f81c2c96da6562e0b3c20000000000000000000000000000000000b805b4e1cd5d45d8b6ed9d4f604ac0b40f336b8123f7281df43a6e803f8688bd8087fc4d5fbae695d06efb0fa35e18400000000000000000000000000000000000a947562dde45f613ee1d15614940a2edfc770d733a60374f8e9188675d4cf973a5c1081c11fe5a1d93bbe85e6f47800000000000000000000000000000000059473d80c82c6ca06b4aa71d072f4751b3b053b53ffcfb4a84906ddfc36ec5918668a62f07054af1b241bdd4485edba699aa549077a80ff8732b5fc9df148a90f405bccc14bf7305266836566b7a98b0000000000000000000000000000000008b9d0916a9f5689b8fdac84bec3a49d0224dbadca6329ecc156da633e1332bcc6735ca3ecb228c22032dcb7b2f372d3000000000000000000000000000000000cac0c264add10bdc1217384a7379f65b93cf822418f7e4e2b48eeac45f068a61f805cedfb1665dda06e04cb726d245c000000000000000000000000000000001578e98a40a64da59154b1c3d757d8f1f8cdc500482c7b7d65b9997576f745442fbac654c19331977bd210df440372970000000000000000000000000000000015ef69f82e85c81d28893d94927068f14c6516eb7d09898d5d055cbb7a9b55c6d7f686f067ab164160e6d6a8f91ea19d40e2de1a2901f1380a383a741d79fbb0a041da5d7bfb92edab74cd483edf95230000000000000000000000000000000000a6a27b498285085139b8dd0c37b700997134337e696c84b5e0cf70ea3991cfb40ca3a3098a3b3a2fa31e91aac78eb2000000000000000000000000000000000bbd7ebf4301c5eabd4f448b89f1b227415cede3247a1c8dc56a02247efaa99dc78cf370f644ffc06cd2158fa25197dc0000000000000000000000000000000004535a402540474d53c084d4fb6d9e12dba6716ee13286ed758aedc1ef911b55c572640180a54cbc084ff57ceae8a4b4000000000000000000000000000000000759de2a9e0f3c04b4f629a682dbcadb2140e5b935845cb55bd267e230e08c6e8cc5426057473aa03ea2196203bbf6dc062b323592118868d547e83b731d15ba2c7bdb1ee4fdf73600c2584f1db0b45d", "Expected": "00000000000000000000000000000000134c29cc5c33c10f04b6c09b5db71b10304028d06ad6acd4f4b39b16823288085a84a0380a1549f04b3dc692cb8216d3000000000000000000000000000000000a0a9379d63527ab9b5f9c00be4acd54e5fd683a0a2f37c85ba570171c705eaadfb0f4e4be1a8836c9de86dff46138300000000000000000000000000000000006ce78f135dda5af34a0e069d7ef13fd589cec5a6128512bdae7f45f28b09c6e4b3cf638628c9f4783097cc00082aeea00000000000000000000000000000000141e710ce7a979dd1772150d0cb2d5b269d5cda50d1bf7bd0cd827b24f9cd8c1e2775f495cfec0428519627b7fede464", "Name": "matter_g2_multiexp_34", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018aba8353cc470b287a163fdb9b8b4cc46071543ee8261f928a7b856287946637d9b36b728a54e1df5f185a47f1556060000000000000000000000000000000001129541b2e3b2e1a553995b603dc3eee44a5ea440e687739ee9e1339dd79bd96c67231ac753d483e0ca96b27054997b000000000000000000000000000000000e1cdf3591aadeb56dbd80890ff7d5639a64847cec771a19c769df7da732a6d3179d3a89ce0052bd7c982af0304408120000000000000000000000000000000000f5f5f0ebfd2b632e15381ccbabfa88eb774f2c61801381ca73e6970965ecd54f5f3a9af7c152186af8fb75ffb5bc25764ab6f4c43630d5e79e8c474d76d8973a7b7bd1c7f1a985333cf1a6be5ccff2000000000000000000000000000000000e527e40c311edc5dcdbb4d0b70497eaee14533aa8ec57dc7cbd7d839fe6c6ae62b1fd0be2346a038de687d5cf5394d60000000000000000000000000000000005f9fc63027dbee5e0d55cd6c57daf5df7af0d138393a2dcdc71ef9aeeb204ea347f7d574e71f2ffdd37d8f05dc7979f000000000000000000000000000000000f8788034c9f1c9c2018a52326c046cdba8997199732152963819b663c6e58e9d6a0065289e2e25a97ce5627505900f20000000000000000000000000000000002a747bb3bcccdc6ea0af1bf1d0ce55de3f41b93060361b30c76063346b606322a76ed7eb260219c83aea0806ac7d8583280f1b1e78d2339f64b5b2f2bd77aa24623b79fe2c9debab4212f4ff564983b0000000000000000000000000000000002148c043e065132e978e89f018a5b728d278c95c9cd1a6f276bd13f0cb708422a62fa22f7b377adf33055fcb09a6a8100000000000000000000000000000000024c4c721a0574e53118bdcc3fd41f73176bc8264d2ff39673210525166bb3513016b5c9af67a47a7032b74a62effcef000000000000000000000000000000000797dfa8cad94896916b7d55fbbb3eb0eeb74f70231205388d0dda69dd8abb436c22addd22c1e3689093739af957b65200000000000000000000000000000000010dd2ea2d45528de8bf1b5c5dc3267fe8951e48ff5987e67ec52d58635521cf1905f1688894e3e23a659764880b2301d4d27ff9d03ab9120ac2adfeb36b070015f0e90782255ddc9111704c5fb11177000000000000000000000000000000000eecc0a4edd3cc3f70d3e0e43ba56b04cfb3f1ac23c657048a94318e622217572b0f929c73f545d6f5f5613920c0580200000000000000000000000000000000137a098ea8d3aed32c197a2d244a2e18753045b55cfe16874f79c728c664b7f23b10476f20dfffb2f80417c26dff4f860000000000000000000000000000000004a7789b02d7d95a2ce0c7bac39d5b057509200393450a47fd9d087a353f866921aa11185550537b98f3073650d9a1370000000000000000000000000000000006ed63730bae06403baf705da0e30c6c00739799eea4a312d06b8d7dc35cb43a4f1e941a69e55ddd7ab8ce42d8629fdcc66d5291311c7cdd1f33e5365ec0689608b3569427a8f6a9cd0b94b671472e66000000000000000000000000000000000ee7ddbf43f17f722dae84d34d26add8c1d732918b8c75c6b295f2f584075cea0c655911410b32c06868c1acf36aeaaf0000000000000000000000000000000018775682555d9f5a576cf9462170910bcdd083671ae2e4c8c6fa99a702548f1ce9afe90e681b00d194322b1a2a3be7ef000000000000000000000000000000000f3935bbbf58b91fe8176f3e25ad3fdeffdd6b369ae70b704d4e54d4fe32fe5987e73aa5aa975e958497340274577cf3000000000000000000000000000000000c088bc439d638d86aba6bb1e6e9f7540ac2da3b96080aed455edd1fbabfc141e26f125cc3a9cf72070a24f298dcc3ef4b718a5129659250640e333f4567043ca749063e63d87efd86a9995adfd3b8450000000000000000000000000000000018d8a47d1a13b9b8fb5a1625f9616ba120d5c677bcc996f694b7e15d251fc4bc938b0a7cb5b70f22b8e9f5b416c513210000000000000000000000000000000003d0646458bbee7ccab27f858b8ab0af0cf583da12a40ca5a954d7eaf97c897d379129a63d8131036f29c30c6e644149000000000000000000000000000000000d5466b50975c5a2dad96e4e24339eafc8c85c2497a6f19e12d96603596498654cabea6995a92c91b8319ce06f18d56d00000000000000000000000000000000191a96d62139f8219b9e4369a783400d045d72ab2dd83fd229e08a4ca73de59a11a5add86c739cb3bab4adc5e9f79685708891f45d7bee38fe382820260061e212c6cb9a8572b4d1854f3ab09409b05a00000000000000000000000000000000032eb1f7846b563e98fca0cd44ede4909b6e16a893f5ef01eaccbd7d8aa11710606bbbd0ee6480f7cdbdc9ffe66c3a9c000000000000000000000000000000000c31bb6fb537cfcbffe815d86ebfae1f5053ceb756818ede8a58cd84cb34d0eacc70ab9095f9db1691e4fb4bb816d570000000000000000000000000000000000a8fa1dc2f28277a4bf8fd9665d4b5c3baf1352d89890d4af94a3657cdac7fd72558da1e65cbc5bfac142f0e817be74f0000000000000000000000000000000005ff65c22ff0abfb33518791823c5f2202ea5f7258c0a507ab84460335ffc2cc8d7c7f670752a7647d6a6487ca0c9adb85ac0f94f300b004c7f20aafcfd9129d6c2590749504a3f08c4cc708fa30100300000000000000000000000000000000190379b7629f74bfb88096dc9ffcdecebae0d653410f032a35a811a09022679c9be19f3790af95c3205a396819e068e1000000000000000000000000000000000b6f114fc277ae8f0b5374dd349985bf955dff7fcb0095e0e1e137fb539814be78c924074bbab54f29dfb42f3e7df24a0000000000000000000000000000000002d86b0507c147142d03d3461bfea4c3af7e57a6edbb372387de24a27cfe27c44ee4b9571325a1b3f5e83eef450f2fc6000000000000000000000000000000000ac3b226d5e13c36c3a8ef0c8896d9af55bcc0cb67ac1cee57a5c6519617ec77af9af60ed44e0a8284a2d59816ebf848fdbb634bc0f99c5795f3c4d6a0efcda7f71427f1eaa1c5411caa6cb05ee3147800000000000000000000000000000000079cd4511e953e4d1b3f4f3bbbc66a62772018e809779fa39aaeeffac737cda9a6116293848f967577f03017f33231d2000000000000000000000000000000000ce3cf48be423a2fc0188b94f2a22579872e9ba140798e560ad107f63ab2b8c601831f89d06a4bb8e7a758cf836ddfb3000000000000000000000000000000000a6a90f735f215a79216fc4e7daffbf74775f38824952af72ac38c38a77a277483e34bc95031679494d76f109c0aecc4000000000000000000000000000000000d55fbce780d885cf817cd2126e7acf115ae9c72843af23c376f3a5d4307d1eefaa0f4691e7c09b5da1707aeaa5b675af5e4695c01849259fb969183de385ef30c2403e081067c2d9b6b5522c73fcf200000000000000000000000000000000008924efbdb46b9324bfb79b922ba8b7d83f5e5e4b3b736105e5339805838171801bcf17208f3dfe5c7475d4e45b6ad970000000000000000000000000000000007bc0096fd23f0c93f0dde8a3974ea3105574e031202f6316d5940c85164c6d6bb5b86078a0c68dc822c0fd1b3dc8cc10000000000000000000000000000000017276b3208b347388a5657b10e3c8e4a187b376e42352f76ee3ee88873217b6b8185022c93097cc116abdecf3cc64467000000000000000000000000000000001915ff932acbdeb52f07b664bcc47c3a5b096c6cec32da4d7044326dfe84358e49539fe50782538a901b99428446b0f50ea6fd588db5efc5fb2248634cca683d39d610886b59eb3077fa9612c368d7690000000000000000000000000000000009e295d229b543a17db1cc85c846111b7097bd169d19b410de78f8da9684e664922eae77c64b0db430aeb422016cfe7d000000000000000000000000000000000e29aab30a1da56b8590e9df67171cc1b9c847696b51147cc57ed6c3b55819cfa0992c67e15e4ca6de2573c9e16231c10000000000000000000000000000000007cc9990c6722645e320dd16a4be8adaab41f958f769ba0d22e235549a7457778cb9b14aa6ea5caa9e0bd43f8d04cacc000000000000000000000000000000000b2dab5cf37ae8e76b71dd8748c86e8823142792445fa0b140de31957d35bb7267e3d94e0dc92f4342d9f8560c5d9d86dc2060a3421c5a8336c80983c9a160345901a496c3a74fc5248fca081d09953900000000000000000000000000000000128e2aa795f8479da3ea2a4efd12aa90a6fb019d4da89fd372e6848ff7ee17da689d766c9e49c88c962eb4f682c56fff0000000000000000000000000000000000fd68bb80d6b2200297aacae1174275f864669e962d85c9105032d7a352fea548e9fa0629a6749c789fa0827a40190700000000000000000000000000000000175bc3918dcc972fb728f1d8cc30ce9887efc6e0b254d8d22af87f95cd4182129d494c43d11b028c4b9849f5520a4fc00000000000000000000000000000000007c5363f507a01c0b6935fee0413345bceaf1336cdd20f69060bdba2e411521a61a549e6159b2e006ffa16e3bd77e998e27e4afc3e6d59d0f5871b35eb83b46cf15da6c326e88dd8edf84031f58e23f90000000000000000000000000000000000efcd782b89fee74ebc037160c6653ccc104260b5f8989545b40d51ead6ad6ce6252e1232281c813e3c883af86e68ca000000000000000000000000000000000b68ed21f76ce131c089dc454dc48ef948cc7c6d5fd87d647db954c9eeab2f7f76ccc51a1cff8612e89bceed16ca03ba000000000000000000000000000000000cd776670d5171610046fa294fecefb42f9bb4d71baed4af65a09018b09ad9341789abc23c9feb85adf96b4203b0c0a0000000000000000000000000000000000ec4ca0091a28b73c9adbe7120f2bf1a84a62ebba1e86b1948389b1a1966c1de4c632a5e245ba634b53cb932f5847f6ecc7efff04f143e2d038de153861da5e04016a7eb17fbe6365de13069d088b1a100000000000000000000000000000000022f319bb5167c2b945a69a438f712df8975a0e262438ea687e2b0d824e2d1d14bff1065f50fd6ae92494f6f3aa9472b00000000000000000000000000000000198ce9e4ddb6b423788dbea82d75513f43cb43ecf1b27c8788f041248f01808644f60fd823e5862cd7afb4f7e8b6b6a100000000000000000000000000000000119dc1be1bbb7e678319db73055ccb88ef7efcf6119f8a9c43c69247ff264879a627f653a10a950e0dbe69155ebca4f1000000000000000000000000000000000692a0ef5a75d42524e3fd52ae073b0f2ddf6378f18a5dcef05af4868a899b93c7f1d2691883e5c85f97052ef1f4177d09a2c3dbb4ee4f485dc60dfbd94a358a7c62204c021f2d7b140187ee9ffdc4ce00000000000000000000000000000000102c92272571b73a7df754728d7293fd8050d9dd2b8605c3f7722e6de541b7fc6a81b01c1cf15e5241ee4ee1f81ab39d000000000000000000000000000000000af1cd6f23bbd3e9ef75eed6d6d99a7cdd24574881b3609e45c4adbf82e08259d14701fcc5b6338ecf52166aecca003700000000000000000000000000000000026a1a4c3eb54de2ba4509dc806db9efc7e26247d501cb59c525b8dd15d03b91abafa9ba5816c22e1f8ca159cda34bd500000000000000000000000000000000170b510ec227fe8534a2cbb0f405756491c4f6832df552bd23980ab0946725371b3c24fa8b93a38bdcd47e1026e1d2a0d9b15c065497392e4b477a556ad620d44e671137cfd570d53590b7528f8ff680000000000000000000000000000000001423d1707e49d2215f639df75ee0e13bc724efc7d099259179260ba0f17157c4efc4276844bfdc46c61ac2185f64beca0000000000000000000000000000000019ad06d215d3c819311938f89609ea7cc63fadaa11bcc86cf5f26370a966eaed1aca312c18176674b5aaca3ed8ca876e0000000000000000000000000000000013bf3f13e87f3ce29f0524094e2ab8e39679566add32e779256006dc92ce09f60d5bb9cf0452b90ece71a5f6981d77f300000000000000000000000000000000112e4901efca14686c30a883ecdafdc389303f4cf46345e229885c76d900b0aa084a957076009ce22ee36d4e285d410c9e2a72eff2ec29a65b417767e7090b73c2fb530de6c8f4e4ba30543946423b12", "Expected": "0000000000000000000000000000000016d1fce53fc4cf40acb0347c0983dda46383e4828c16985459ac89a2ce8d3c2a26cd9acfaa2ec899cc63b4c6bc351f560000000000000000000000000000000019c9626363b511a79f297dc79c5a3b7a2e5127fe49a2fac5bc43a4376f170404f044f9f84b82cd09a306012fc81e3bdb00000000000000000000000000000000062e324f3d7c5bd39808b762a5b009cb30bec14a9591477959339bf2de9ef27eb42a0eddb95aa5fdca9bb9d89b278cc20000000000000000000000000000000000f05225a4d3bf910b0ac0103594a90684ffc0c09e2c21744032e30470d5727be3c27621dc2377e9845ad78be67b856a", "Name": "matter_g2_multiexp_35", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c64577b78ff306186dc44131cf8bd946a68e65502c4af9613154a7e3ffea4fe4e59cac4a500894b470a74e66db1834e000000000000000000000000000000000b4311c295bd30174f17b9ab3544f1496b9655302a4b6026a113b1aca31b555ce7b2d812bf8fafb6b075f67cdc59b77f0000000000000000000000000000000012d7dc3db10ae6b4e3e99c655aadb71124a0bdcfa6e30ec13c7c977d39f83aba4979a1f45881813a3a68e149a40120a90000000000000000000000000000000001b958c47cfecd619c05a2c54315585d15fe377beff889602ecba6ea3b29d51f6480f09a0a8490e4c754045f0bfdc3eb7b9aa7e0bfaf135ff24720773ccd1e0a46fab6d678d91a14de137061e145fb9d00000000000000000000000000000000010db66653f2ca73e55d85254f62e8b558584d546913e4b8f530968088d90cd5c4bc164fdb77325fe0bb2fb1a5683896000000000000000000000000000000000a1af9bf84f0b351c8e8c082a79c7ccae768bd2ed40eede38666aab1901a6eab0cff258f440c8c8eb4854a824b9aab4b000000000000000000000000000000000444fa654afb57f1b01d10be08a330f23667af58e3a40c630a2e01c1809125b3ff8f76e8a39418688a023293ff1a45e90000000000000000000000000000000002ebb117ea107a3598b888dcbd5918dd0ca307b21d65843c6c28b3efab89d0e276e5d92283bbb345b674d4a300595425c6733c9bb7bd195622b96c4181e8c8837d1912fbadf77d6029f7fc44d793b48000000000000000000000000000000000105818a11efaeab4801d4fa7558b09bd56294be7f58e3e54fab1f4f7c243ceaf08c99a14c3128ccfd866b6f93caf989800000000000000000000000000000000091ca092e5f83a04e872e621e71d54dd6886d088718f60ed5b62d3e4c165d3ff2cea1e50fcb94fff251df0f5ee453cfc000000000000000000000000000000000b42051a1ef52f87536b9bca459fa7070ca17bf825950b13b3bbe9db183ef722f62af6c05c174c65d59b722e1d2f5b0e0000000000000000000000000000000002fdb4a5480418e43aea28e5041af6ad55a6c226e1eea1a0449a99b5a937375285feecabea95c2652da5113dc17d8ef4410bb66334c677397d04f59eade9630463065cd7da3c9d50580c7d66bbaf487d000000000000000000000000000000000d8f93b589678d4e93bdf8da7834bc8edab648ead731b7f5f0cc299488f07262877ee9bb1174ccc106204dcd3f1f416800000000000000000000000000000000160f740ffca48d3a10c43e591cf46c129507f10e65d76a031fded2930d6c2dca4c79d7813f63e4ff71aee09d672173680000000000000000000000000000000013c768a4889315faa3976c8e43b4d466ea594bd94773f270a198f2571ba9662d10435d1e541a492055c333eece9bb29a0000000000000000000000000000000003dcbcc9e6a0cd5741d77da88fbbc269202e8f944a5df5dc4f9145758654934d5e1eedd596325080382458961ed3d21ed97a16fc5b2c70829b15f73615286eba334de1f520b5f0f6a83d2578399cc0b3000000000000000000000000000000001344fb37c1d7dcab01a4bf6fa50c6bb7606f7db22b85a3888ffcc2e9f229f196881cd7c82160730727e49b9e6fea04320000000000000000000000000000000010c7b15a6355d3152eaada7a606031f28809f278a1d0e04d264b563185ac7d9e351295191a6a90ffc9c6dd33995265db0000000000000000000000000000000014438086226a061a1bd557dac24d9333e14cdfa3a7bb00ded4a450e8889a3028b174bf38ae1347e6aad19ebc1cf5ff7800000000000000000000000000000000105165703c4592cc4f1f489d78426a56434dc77327c13221b582dc25306f4c5bfe596f3e47abcb741ab553fa14cad374bdbac08202bbe5df1229e99c76c1727f7789e0f8c2002f0a2c195bdfc00acb36000000000000000000000000000000000ad8b55a198a5e788bb54c32112761ccba9863cba16d95ec9e30181376e7eccaa2741660f2c5f708300be058e566ae27000000000000000000000000000000000b9bbca7db413964d2ec113cdee2d7a7bcdb712d285655f6b2897dcac61456ba4d08e25e8c28627231824829bd7d13800000000000000000000000000000000001ae49c10675256651e3e038a2150d85993fa6f2a97b9bc02c693ed97ad52af34015176258b3b2546b81010a4381d85c000000000000000000000000000000000c8f9668a0a497420acff5207a07cf780e0b2ba78083eb0ed8eef76beea996210541bae2e64d825000f307d54cbe3b2b43da827b812ec6ac23b00208cbad0f2e8b3a32434aa61dde029683c34c1ab1900000000000000000000000000000000012990a66c132a31d60d182f729b52d9b57d9d1eb1988b6f0b4d9fa2847f26983078ef9bbfd0e888e14bf7d1f92d09e54000000000000000000000000000000000585215ffc2673a197bf9cc6c6424547886abc6ef5c6edfeab2ef0c42034a4a458fc7155c35c84a8e9e9d89fbd4aa25c00000000000000000000000000000000118fb4fe0d3498dd2b55e62272e95a1203f9fd22314921d3e044f1b162376aaa7e8154a4e2184b66451aba98729330c0000000000000000000000000000000000364b9032ab9cd9f599979c8a93acbdb831707f1f84fdc92844b58bc7e4d72472ca5b09c51b1b04271ed9f0e391552463c7a8f7bf434ce5e63ac9365448da8663745f66689b4b04968f9b8b1b6805893000000000000000000000000000000000ddf9e4e302169e195f4f88fed06e0c93fd1b542abbfeea5da5d47c662ad9a16b8f4aed7874354fb9008d073920e1e7e000000000000000000000000000000000043fd1a4b781f25e8747ecb3eec45ce90760e0d5dd701e8193a7e726684ccb8ff21f0219ba15e9e777d339a3d87a1ee000000000000000000000000000000001117d2ca429048056084e4847c7169b4c8ddaefe1d48079949f9f14e4d74f0e0b38a95d0f17389f61da7b2a6d8cabd1c0000000000000000000000000000000007adfc7d87b1c533b4439f6b30d38c694b65b3b321f3eec13cd7d923f1d5f117005be6c3ea901a9479d79fc553e34e6c51f2e2bcfa6ebf84d3ad83c57257b9032e5d62a8663ed5d77afce00f33382bc600000000000000000000000000000000115a81aebee0329b174c01458f8714b13ea3fb2dbfb051b27b29b940652f27e01a84e522626d12be80da7e1039e2baf6000000000000000000000000000000000d9e37d2e5e7160db30acf5593d1c282541a0d4ac0482f0759fef8704b9ec3ab1e3ed248e37c6be285e890ef1a520d0b000000000000000000000000000000000c198a22c2f590df2902c8dc2bb1ee427b33e9687767666140f9d3b51d73fef18a259d43d86fb3559b1ab0abacf547a70000000000000000000000000000000017e705af54ab76145a79e747167a4fec6ec3a16f3ceef86b1ddd1be144e616ea7d686bbccbd1c5c258e4546405be023d6d8b15ec8908bfe008414757c0c7f79b3079f9db86d91ac3ec8f38ae2c94d48b0000000000000000000000000000000007c4c31287ae0b3bb90475f84abdda36610f887aae311d8e97bf97bbdbdfb11d38c7de331cc9dd022926678e5180c0770000000000000000000000000000000017f4afe28adc4b24d16b9cd97aacd171c2104b13b079c643d664a7c924151a401c352832c4967c0e5cecec5f1d1dae290000000000000000000000000000000005a8aa8a3a91461e0ba256e44af56875f8d07e24628e738ffc057249d8380417884f40c84e76dc6ce5816ffc05c0d686000000000000000000000000000000000f84bb7385a6936b519e881a708541570a31a9d7897ab8b348a350adb0d30522567fb917c9b6db661b6f53f98b5e68aaf4723e85076d48389c3fb5a5df16b6bc6f7a69ca701632b1159677bd8a6f7bb1000000000000000000000000000000000a8726ea352582ed52ab4e440102963891f059cf5a3f4901615733ad560a99930efd8692f3c30256d58e5cfc4f0803bf0000000000000000000000000000000016a623dfeae872639d99e3b8209748642f20af796325630596b6ab6146783bd4f2247c7ae38d53ba9a3fc0cdd6f29087000000000000000000000000000000000e40709656e569e4fe90eb85d8761c6ce44a4272793ccb7635ce75d67d97464e8dcd8c32bd4ac9a36fcce706006915b20000000000000000000000000000000019e64802756896206a9600f2d888f3d307ebf958492b1b5153c06a11231e2d7d2f1786368447f380093a29117cc25da9a632938a6df169fb64daa55d2f874ef7629d5be41dfa0d50827c082333f0fca00000000000000000000000000000000019c7409cda6084edc6e559da9b361c96cf207f1e2cd63cabc9b86c5bcb07a59b43e9c6ae3e90a61c872f168ab89cb2c9000000000000000000000000000000001101bb63a452b766a085fb788937f6b751417dd8d905ee50ab5bf96cdbb9d7b68c1735460a71eaf9e9bf662734f495c20000000000000000000000000000000014a103871fe523cd01053a992eb9884ce83c6023bd6a8c2cd9ca60b8780118c88502c6980904f2d2bf9ccc9fb597d535000000000000000000000000000000001929f25d52ee6b9a44333237c732a63ce2abc80c5510bd67faad1d7adac96eac5449823f3a52ed18bb90b93d9640d0d1283a4da7f71bde54d4b7e28b2b23e2eb05d8b025e77e15810625d71faca6d6e50000000000000000000000000000000015b0a46692f57ccd2b7f53040dd75f30af0196aa3c5499049eb172b4d927f96a59c42a129117d6162a1bb31d2e8734a4000000000000000000000000000000001366dde2d9070a2c057744fffe78effdc328b122e356a6aadb10c3fd2e8badc0ff70bc6d18293b3c52428e2ba78766600000000000000000000000000000000016fd48b067b949ed75bae3e4db29b5785bf672bd01032a925d653f8a605998e1eff6c77ec39dcfccd417f1e0a9defa820000000000000000000000000000000004cf22bd706dbb1cf8b97187ed97636380871402b3ba9de58f174bf50a7a0b528749762c3f55f5f835a276e43b46e669d402b71c1fc5c3f3a4ed9edc73457a27ea427f83a784796e01b7a1451b3305b0000000000000000000000000000000000ff424ae9372af46de34210bb0bd670eb173bd49076df5caca4bc4293e742121267a20506f931a4ae77cc36fcbc8df4d0000000000000000000000000000000015a6815b47966fb84aad5de62e6d4280f9135e129f33fd01e667f4d6e1bf7204317fa7741f3cff3682e251437927131c000000000000000000000000000000000639dca43483b79ba8043130e508e91fe3f43bc362fd1dbb135a2eb8f3b94d5cc4af70f1101c790545a0eaf2408706e1000000000000000000000000000000000045f0a04a642bb6e4db34fbffc8adb19a24648554f36ca371fb1a851384a4516a57f1850f7d6be59ff67029ec4002de310bc47acb3aba7eaa490ec104ed9b2985f65c7347f69fdc67b76f6f43846a99000000000000000000000000000000000e796fd500cb1a25b834baf7335641f34ccf04ccf60f82367f0e5c8c7fce8e3030e7b916752bac8e3adc01cbf4b319ac00000000000000000000000000000000142e8bbac9cae69ba3dca48aec045e0c4d7028f73c254433f921b7240761c661cf8e774a21da249f7758234cf7607fbe00000000000000000000000000000000045a3d80767d116e89bab0e9de812ffe7ffdbc41b61f5f17ad16be5bdc9968e34f46b937c5f94f8197e21b358f44b5240000000000000000000000000000000006978b93018bfdbaef0d40f1278e831a1fc50b44fff39b7c93820a284d90b699981b1f422f751a33094ae7b5cedbbb2691b88ce9888e5dcfef70d6f960a456dbabc792571f2a98746b7d833e7fab98500000000000000000000000000000000003c3561f5d255cf1f83cb5f4df8e3b8d5655d965826d56867ae66da631f8e7d489f733f5824c36652ab00586d9c593be0000000000000000000000000000000010b3adb0017e2cea1b71680ca33aee368429880759660dce2d3cdf57b6cd7339bd8853e5efafb9a5aec3f7e22da676c2000000000000000000000000000000000cdf976e4c65edb79ff15178f6ec5bf0a77a30d97b799e433f216a2fe3eedb10bc6ecbee2974167128773cff43f1922c000000000000000000000000000000001599b60ee70d927849764880830b2e7355daf95eefef39ef61569a2b83b2bcced4dfb28047a1e5350cc87ef3cd5cf1d93e82cc1261ac3864266379b4d518e25c05bc492a8946b38b8a64acf47aeec4b8", "Expected": "00000000000000000000000000000000123af49ac2981e14a490a4a6792f21343497b562266a47487cf6c650769c810852e357445bc68f3460e7822e8cd1e3f000000000000000000000000000000000143e79853e4bf6d031e1116dac2c6eca4991b8a1f822fac1d352d2cf1b88df239d82df886f0b24b3e7f305286cc1257e000000000000000000000000000000000b621056a9de2d83c946b1e2c7a07f9beb8e053202407323e412c0d8f60123cfd5818067f57034fe1b1b5a3d1bb285a50000000000000000000000000000000001642fdff2c52d58d38201cf44c31e00df47ea1439e9896b5ac5e9372482f4ffcc698be46c2d375d57a72fc677a9fc8f", "Name": "matter_g2_multiexp_36", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000011f78204afa05c3717d3908dc7e4356ef96c426ef380b6abba3a5616d9ee01addeec3369967ed42e030c4b8ff9939c4e00000000000000000000000000000000175a19c86e7eff0f4e809a5105503ed223fe327ee4617f7f51257426fe408373899f39014821292a75e4cc4eb9f7f31e00000000000000000000000000000000052130dd3cd17840385db424802d869d7eac781365be25ba401b7b0e4025353c8dbf59e5997b5aac74c252192061299d000000000000000000000000000000000457f4fc7ac5d7d4fa07e8ed125df4c4e950e6ea926be9c04b6df3c3699a10e99af7ea8546b8ac70c3003468a75c821ca2a1148f1ba719b2da92c418fd137efe21a44dd4cce013ab36e57d97dfed92990000000000000000000000000000000005182a3af2b52102e09214d048a1a29d1e10b7ace6afbc4e6b1ebf16790be372dfb6d65cb8fe08c3dbbed8c5435a59a3000000000000000000000000000000000f2a1261463c09a88edac443ec3cea8aaa19659e8b7ec2e8a403dcffb1e50ebb3d07217a9ab057d8d097c075609c13900000000000000000000000000000000007d6525fea8fbb685fcf89bd772d48c406aff7377429fb199f27c3c3337f11f8e24c4d81c9026b469600d11e8cce51be0000000000000000000000000000000004b6d6102debaec16c34fecfeb444e7ba573b13b83ec375f14d2c541a0d1fa528ed6599a0eff4f8ca527c5baa579f762fec5d6167d7777169348cf81ad3eab5153f8f2f18fb5935c5ee5e3a759f9b5af000000000000000000000000000000000ba1f2b2c3f1c57afa0ab647d32af5d036ef18069a4abc9795dd9927ea274a718b67373230e337cb9374ef73b5e2303900000000000000000000000000000000016458ff2f5d600af9d2983f535c965a2a8aee48c0d95095bee642bb7bbab8bc87e3e7c3b52a787c53f0d1e00cb4ff32000000000000000000000000000000000d11324e812cd4fa65d20cf58f88a9bc9407657834d7a92f80bfd32c7085ffa2f9f78d7e18c1405a03de939bd0dbb06b00000000000000000000000000000000144a0f4d50bcb16942d22a12d28bf34d2b4c51512a3f11c130f1566aacbdb63ec3984df5569f41ef621f50d138883d0dda609e1c8fa42a993ff355a70d44dfeebc71a801daa36acd437daec5d7b645d10000000000000000000000000000000000d7b138fe445d7b7e130134db653022ebb389075ffb62ff9faa544cd0fdb9e78e313d0b1cb19bd812421d38d1e9996d00000000000000000000000000000000084411aa2719b729a1e299fe8a710f767009060f1b2becf2aaa92efdeea8c91239aa5d2504c6e7ad2e3f39d89ef00c1e00000000000000000000000000000000017e86dc0146c9bbfa5ea1e48f49918167dda13b31ba73311fd5cfdc12845b95b9e90972a9a4d36203be8c5920f8de5600000000000000000000000000000000150e4b6fa9cd9a609241d1de8a637c6ab25207bccf8e5eff4a97ed633b67826135172880b118037649407a3e1b1a0661bc5f7f5d096247ababa51852724ce9ddcc6acc7ab6180beaa1cda97dba94b4ea000000000000000000000000000000000ad7430b7778248d63a06e26119e5600ae97071fe8827b24440587e8bf6887b646f342741af69d20e243c9b45d7dcf24000000000000000000000000000000001230cba1a5a66197875240fe00c59b796ba1db5ea5653cc76bf43d6adce0db3a109168593beb39bb45688c1d124b9eb300000000000000000000000000000000144652474c58413cadf9b31715152052b7618e7093e931367a7ed0340e66d84c0471b6ec178e1730cf10e749e01815780000000000000000000000000000000009abdd0210f25d12146f2911a60035867f59cc341b35c73bbdf8f7a5a90d0bb6566c6ba0e868a3d62d3557436190f3f63222b41a59f9551e91572ae00582e1e41989ff5f8e2cd1ee1a78f55c2b28ecb40000000000000000000000000000000018ced3cd0c169693368fcf9c3dfc49fe248f0b9b5511e9407b8634d8ed7b54ae2dc4ac6ffde8b3dea70ca86ddc89449c0000000000000000000000000000000002f6b227e699dccf7ab1e0b1cba4cf9f05c4dcaf9fee6cd94bbb79f42bc9598fa23eb2c653a7654db73feb511b24829f0000000000000000000000000000000019785959766eb8b00ac2600d87240f2876e049725680f4504f59db6642ff8f82d4e1b856929643906c3be7807a2443180000000000000000000000000000000018285acdf25a475b37ee4da872debba4297fc8731eede6b22be3b0dff12117634de44b84a18042852ef419c3ae18a46b7431e5c1fe5f8d38c759bc48e8207695a3cdf07d4c1fd02f1009088539085da10000000000000000000000000000000019c7950b01e15669cc1f96fd94957535f32132ff6a5ae788f6f660024c332593942bd3e9603f862756edd4f3ab17b20b000000000000000000000000000000000bf3a6bbe10ad91d687a135f4863ba0332e9b04271d437a6a4770056e6b1ca34319dc895f9186482bbbc815aead03392000000000000000000000000000000000a3ef4d4f7a15da04a91ff079cc40040993a90e9ea21f53e31f7dede52dd513a97ece780374c5f3aa8c8b2e525ee31d10000000000000000000000000000000017749fc7761b06432632ac686d93484f08407504e58b04b3890cc2101f15d21f46ec0dc1e9028c8ef8df10f9ae929887d474e755f6ce9045baaed65c80f5a686547089e8cdf4ad2b7c2ce7c255cb5c730000000000000000000000000000000005a36af876edfdf26175c185c3ef005530e02474232ea659f5cf251c5de5721f1b44a25714967d283525632789331d2900000000000000000000000000000000130a6f5edf94736477143b1efc316f131b36d9658c484821be08e7f5b9c93f60cf34042858664db0ff0240addad8782f0000000000000000000000000000000004fedf49e6d49c074dcca96c01607da2105d8053861b4c677a69cff0f82e66a2a63f32f3d9fac8e6c844a1f77055bf31000000000000000000000000000000001528541de3a9d4a216c0e60c31d2b7c7cb91b839fc31307cc70f18e9b87b92bf5b9a9dc4eaacdec6e6bf7791e547d8a2976c8775b0eaa1e4aa384d222efc476305c7ea2d625cf5c67ea4368d7a9fccd10000000000000000000000000000000013faf7b2b8514f77021d8927a3b63bb7c57785e581f40ca82882341c13a9daf062a26b668844e58291366ea6ae2f179f0000000000000000000000000000000009060f9e1047f15f175fe95cb0914f4941bcaf071f24e856eae6f36263c812689a9217da277613c10c8e254a0933c80800000000000000000000000000000000154619e4ae3901789ed3ecdfc76069d8026a3e2cf142a144e8b58482233380690e378de6b81af0ed9b6536da1cc2a30b00000000000000000000000000000000040c1bce922503699e1fd5ac67725f11d7f9bb6903ff9204412f65355be69d73cd7330a3f7bfcacaa9b078ba6b9a9f839db274233c46caaa9c99690fd00fcbfa4eaaad7c41f8ae84313448c787165f6500000000000000000000000000000000103d91916d537379d6d8717b17ac5b7e9fedd98c24890b51c027cc086458259767d989b3ff9d6adad72bf977e4d378f400000000000000000000000000000000159c01ee371622378339518217dfc0570178aecc938b4a008dee1a6661ffa605c0f1472c107558ea791e0959d7dc1c70000000000000000000000000000000000ea3e10cbc3a55ef2dc7bde7a2e80666557e9e8fd9ce77e2e92c2c70777afe43c23072e263e1def56cae4b6d3772db96000000000000000000000000000000000cf1db638331c47f9080c04117ddab4ba79950563810d50e04af819f14ae0981f6e1e94a635fc90226c8d7beef0844354ac9f9ed46ae5aca33af9ba1c0fa5a2138d4ca02b962fd1d02b4636114ce19970000000000000000000000000000000000095c82c58182ae9a1ba14421c2966d687f7225ccd192b24097f997b471d13b46a048202712cb2d8b1be0ff40755dcc0000000000000000000000000000000017410aca05935a06942f673d1937a593423cbbd226f6707c5922306d28a60396baa08a941122dd4c583331c9481a734f0000000000000000000000000000000002c1d3a1262ce8aae42a6ed10d8020c31a468127e1a59d57d2d409ca9d14143d9fd21353b260edd8b387840580698846000000000000000000000000000000001512e29256b6b9f5a7ba4f79dde2c915b162e4881856258ac2050f02868842381518da4ed824243692b131710d7201f8ab300ee55e90ac046dbd772da788dacddf72c559d9378b39507987a9774301b0000000000000000000000000000000000ff83bf1d50fe35bb3d1bcb07b02d78a1b44d2e0c6bf82c600feec3897fae8b93c0ef05006c1322af0a732392dad86e8000000000000000000000000000000000d70c4957cb3615027cb950e4224d41849b9ff1b435ce936384fe17c4d7bc2883fdbba5123ca0c0c010651500557e1be0000000000000000000000000000000008b16fe9af45fa913aa7e5d01b5b58f946004eaaeeeb493759a5bc2b192d2dd71af24ecc5c6838b5e267ec2dfcf5c17d00000000000000000000000000000000038ca027c985af3cf60cda13e770fbe4919d3a5b413763c8ad155cb4903312822366eb986f2ec9e0804594ad4894e468275b22db781d5e8fd07f36788bc1219c4b4a13554c28d92a381adae111b265730000000000000000000000000000000003a313d6d41f1ebd6b98b2061a2d85943e52d89e4b8680611d41ea182385e154da24248faa1563e6ad79172f91a8763f00000000000000000000000000000000038d9388fe9169710e1a205ecfd03f674b47ba2275794469dbd5f193a55e00765c8eed026363b41afda417bdd8910ea60000000000000000000000000000000007a75f53d9b8e5eef19ef6f5fe8ce5d5308a1a7d02e0bf46f91a1e0cb22555752d82d8471c123269050fd8f35a272f600000000000000000000000000000000011f313127a036403652fb2f83c5122fd12c362ecba2251bd6c357a964dd758eb2a2c3053dc668b9a4bc071898d45cd46ec69b95dccdbf193d9ee4c51615c0b7be5ac6bed3f2559f0cb2755c634839ce7000000000000000000000000000000000a43335eb6ff3bf2daeeb1eaf44c2782eeb517e82e55203a247b7a396e26fdf85f93695753c52c68819b58c95f361820000000000000000000000000000000000c240b7896b3dd0c318dc9ffcaa001d20bff288def3ce42752d660fd705e1544e292a5a0aa3a9a80ae91cb47cb938989000000000000000000000000000000000e5195bcc4ee8b149a769322165b6a3157ee7d04546643390adc812b6296675dbd31168b268df869a6722a7c8f51c79d00000000000000000000000000000000004af7dc8a5c552f00d55b996d193a9571173ea829eba8fadfa7becc2f4149ee7c6c4d2c8c7b1970df33cc56e450657331e2bf1816a84c190eaa850ecfe1a9376123e0d0732d90ac3537668f8f18b9f70000000000000000000000000000000007860c3403607d4e13f738357e18bbcc4df10fad4aa25776f84d3c2758624a83aee0996146ba17a812384e1d67a7c54f0000000000000000000000000000000002169148d86b1f7a0ef75d9bd19b6d7cd66da4293fcf33fed9241544dc2564d980161a6bd959f3b43569312bff7a23cb0000000000000000000000000000000001897c121cbf5e82424cc50078ca7143a0c670f1217a9180cd2a4700e06aa895cf84c0af94b7c04bfce047a7d1f8443100000000000000000000000000000000040c1a0c4257f90bd83fece3c9372842a148132d2dffa956729e741ce996d229aacb04387d51a72630329230020b2235f4087feda4bd8205d96cd0bf6eee44c27a6669d7ae8e16c731849cfbb2324e1e00000000000000000000000000000000058c001ee1343c6cde55bbdc4c538f5d14b0e8c199fb822f080ad96ee764bd1908f92260ce60cd521919f223301ba1220000000000000000000000000000000000f8943c35e7fb8b58963719f1b9820153e0831cf81dd208176af7527781ceabcf6ed2e2276cbf374e0525952bace0c80000000000000000000000000000000003b43ea8c32a13c014b05326f7b4ad5b5fc1bb2367866a69373ba91402f4b45409c6d034898e8b0ec3b93c2878d59b72000000000000000000000000000000000101c371ab4d57ed2cf17dcb731117b1986bffc586529fc1edc630de1c6f4fdff1e10b0895907bb81d2ccd3eaa96c04a67b81583fcdc9afe5f35974dc9b6310ee8e1c92031a49c08b05555fc0d33517f", "Expected": "0000000000000000000000000000000007152d538d0f750901466c1ea34a16e7b0e1296a2a3740568812587affa5c0c76ca2055804e24f3415a403f06a717c0e00000000000000000000000000000000119c0c282d22a01524d87eb850789c4816e7dafdb2782b57c32409b1016615beeee2067443835466283543773cc8b427000000000000000000000000000000000d68137c3df081a519747c044950c3231ef82295eea5b7040843668195d4549c8ece4a91447e0ec89530bc51277535fb0000000000000000000000000000000000d81a4fa2d32ada3e08a7bd4471d45a6afd2cfad5bbfa3d378b1df2e0749f9b05b465be61cc9d1a0f4abd56dce03dbc", "Name": "matter_g2_multiexp_37", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004b153d6554c9879359052717457179d8318f8127eb73edc1d6ac2efb1ea9643c4357cc813d1df49730b77f995d6d449000000000000000000000000000000001533a450737b4bf8edada15446cf21ebf82aa7bec7943025dccc4784e1070fbce430699cf3a37a36a3ece692ce87639c0000000000000000000000000000000017b8afc300bd70a3221120f6fbc37a8e6158c48b476f00992c6f41808036765071bd0a76f7c641443b97ba523153947e0000000000000000000000000000000012f686b4759a3d5db2325508f148bfd6217e027fe261d3ed7b8fd0526036044dfb563e1c4399ec266e140ca372120e289f3c65c2c25c6c37aa45b1104745cb8ec511a165ffdb7e304f5478aa3add4d7e00000000000000000000000000000000061c8288b7bf2856c075a176d1086fc49f0359ca3e7c1aaf5f151e6462916a4e1b69b6decb18823759b620f7593079c0000000000000000000000000000000000877af18cfa0d029e7c9a5833b346c7fdec06e54d9641d3953d3cae0e8912bac7c990f8864c2adb6e576442c634865b6000000000000000000000000000000000331490f42993de3ce7cdd53afb4b310f25881710a23f601ed95961bad4e9cbf57d3077803908a91b65fc32d1a84130c0000000000000000000000000000000005aec079da804fc572bb8eb867acb93a24ffb6611eba920d2ce799c4c80cd8e73b3cefe989885167ab685365529b4f2a8fd50c46bade91a13d6dc5a06ee62e5e89e0ae7ee885e5516ca6c2dacc36f6f3000000000000000000000000000000000ecc7abf4f6f9692cf3a118cd01abaab4754c90d1a59468d402bd699992800c2994f47b2094878604bf7825f125133e4000000000000000000000000000000000662396427cc596458e880bb8a43dbe046deb85601e3c64556990de36e8637e8ea3b142a8195762910a83609ca311c3a00000000000000000000000000000000198b9c52be68d073910f5b26bdeada9e9b308e4541561a8ffb21fd8e69ec9d93b01ec966fba65be27ee53d4857a43e120000000000000000000000000000000005201975985cac810248e333ca714cbcac0ede46bb915d8c857837c80c805898d0f9ca0940819878a26d269faa02cb86128db1a106328916ca5d63c0b5722642febed26f00a89430d52ec3eae25a019b0000000000000000000000000000000004e61ad4818ea3c98ed3c0d247798a1a6ca6bcb35a1cb60bda9394272ec092c385661ab93a42af439f1b55ee8b9c0cd4000000000000000000000000000000000ee0b71ebf39e4009bdb310fe3b555cdc860abd47a67bf481ab36b5ed0c00bdca8082abfb75691d45e10c2f2d777be19000000000000000000000000000000000e9582e3b5bd580f3ca7ca1f58e39379918f2d04b82b418a91e133117a9703f7df4aad30d48a47e29aeaccf5b8e33559000000000000000000000000000000000113b4c068fd040cd3300a2d1ef658955b014e571e7c77594edd31968037c1fff241da88e7a88669a569462564e28cd7d45665afb6a864893e389511a0f7b2df74c9e45a86fb69f6bd79854e3a88c206000000000000000000000000000000000d8b0bf633072f19db61ea263a1dbeddb326738396caf1196e31e2cbe99a68e8c70f8db13cfdfa4fc4494e54c1ef28210000000000000000000000000000000009ceaf2a0c63604afb8a903195933fd1ada0e5314255be3d74a95679c7a7845785e22d2c0c206f3afd62110ac9810c2e0000000000000000000000000000000003a135b405f46ae3f5cbdd63f4964cdc5014c9f3405c2062ba17423dcd22b8f2011638d520ce0ec7bb0cb5b03e8ec01700000000000000000000000000000000066eafafe1cea67aa6de267c767f49d4a3fd44c28d45a920fe9b3cebdeded883d8960f5e9fa4cc179246918942b1428d28f5fd09c2c1819adf8e6d0e0f4e4681babff46757edeff3839e9691888c13220000000000000000000000000000000017e37a2f1c892fdc58ac3f72cc5a5e2b7c0c87333afb06de89f7a84b1267695bcd452925fb2f15f8b7b20aaa85a6b5650000000000000000000000000000000015b2919343962337a41b54076d6735a093190e1965faa33eee800f5eaa43c35f349aaf93f19977b6fcd19360b27edd6d00000000000000000000000000000000161afb1494482f953007038557c847e2cbf84c57c5f5b806e3b0178e71e3238305f733943bea7ad6f2bc290778638e6a000000000000000000000000000000000c27a2170fa584863697292e626e2539aa15f3c8eee65cbf1f1b7ced6297248d059fdaeb9c955437a51cb016d1ee97c3e6e61390ef88f20591570ec1fe71c3ed769ee8e234c7cc7303a4cdc065717736000000000000000000000000000000000313a30edffaf864d0f1c6bdafd7d1e563cef434d45e71489e9f9e4cc6700e44991a99220f53f0cf5e7de5f6e4098bf20000000000000000000000000000000010429081ebd2ed6fa07de6ab0b7bd559a26a43df99fca0a2252411b4554dc69821ccf3df1b05114da84a616ccee0a9c800000000000000000000000000000000131a31442f80da4621f7691664e9f8b467988fa039bd086a2d64f9810878b557614c27745b2e821016f648ec36ee797d000000000000000000000000000000001160cef9f5e4d022baeacdf10b3bf9d7ed5e50627a99e29df1be3667cb872b2af333f803bf426314369b490c2eca642aa83c5af2f9d10c06552ea7d1749cbfa7574b238433c1c0e4788efd0cafeffa57000000000000000000000000000000000b20ec53bc643bdfda1e3947b3773d748cce1992e2ae27c6b7460d90d48e08eb9240879a5a7d3dc3189f486706438dbe000000000000000000000000000000001024bae4a7f71d3d2fb8246e82d95664c4ee8bca4a380c293ea084f749911f984aa4c6f266ecfff69c4f57e20c0660ca000000000000000000000000000000000b58472d81a9f16d2fe7af87170ca0c8c51dada62a4b2a713cae053a0066fd268283a785ccf269e05d8873cd686d2f4a0000000000000000000000000000000016b68177bce92fedfbd90cdb752bc332f46fde6673911c016fb9cff4912d79d3267bf629c33097cf8979f2b913c0936d4bcc88d85a5a8a29dfad37ba97ab3a5defde4ec356146db8d10f33bfb36ddd37000000000000000000000000000000001030d5791bd2a27469d242c62403883ca167303d907839e608acd827b4118b752840a4eca0acbe5df0b447d6651e517800000000000000000000000000000000106d65f922581237f779ba3e66608729dfddb2c487bc927f34e5e39707f2c8a82e8c96af68e3257c7a9876a05a1b01d800000000000000000000000000000000115bec40b8fa914305b1d5a85b65f0811517d36839494ba69c929fc2422f7e8b85d78df4e1687ab0087287eff29c65430000000000000000000000000000000018d78a75ec057cfcf179fa2ffa7dba79cabf6525dabd69ab95b23dc8f293aa077e46e562caf447dd0913ac9dd60ec76b29d5d818e62c9791c320e01a3164e142d9804e9caa7f96b4c3b76baff38ee2e600000000000000000000000000000000023f7736d6de94b08d9e9efb6f32f8c17cafb1e1b9b1f3db6e58df72a451c3225d11f4304eb0d702b07a7966f95a11fb0000000000000000000000000000000007b3204f258c873a6fcb48d0b36c98ed5f99b424cf4f92a028174e0e93db2af549648ea95fa8c7bbb42b2a10eeceaf8500000000000000000000000000000000165d6e769b7df91374dfb44e18d43e03ae12ee10d8a618a20f67332cf96492ff514eb7de06ea53096e823770c686c32700000000000000000000000000000000012e69ca1e106411165c06ca15988362de583c4a05425e2f4aba4c14cef6d8d04c52c87b4fb26b1557801f55b02ee8ba971c8aad41e401ab6c49dccba28ef26acf4961978e94e633b72c581ac03621e4000000000000000000000000000000000e8e6bf1c8837c31446959242285e9b85978a5349e1f0b3447e380a7bcd6bce758bc6192cb880f9c09d6ad4a0ee36eea00000000000000000000000000000000199b361ad0b435d7a66b46a43d06e5898376a6c260b68c965f7b186fc75d2f321bf883646e7551eaba03181907d3aad1000000000000000000000000000000000a76e3f399f31cddc4dd4bc22187a68fba31fe2371291ab515d22730d320ae4240911c755750f687c7d26aed09da4210000000000000000000000000000000000cbc8dbc004b9253ba91b2238c92bbf7883360c7ce39f6e15592a8668654950a3fc5a94cfa97f5ddc60add40c32a3630659ff910eea5280dc5c24c542516053637a5dbea576a94a22acefc902e56568e0000000000000000000000000000000005448b623604262a9cf1a9a292c36738960e132bcf0ec8e61a510008c2ae0b51b31da25f2bcf0d7c0d4ce15b1d7179fc000000000000000000000000000000000b61df56ef891bac07a873571f68fe43f79438a31038cf8ff97393ba44cc47408e5a6d64e9ebddf0195bf914f141e668000000000000000000000000000000000d196ced22ddf11132bbebf6c85bb3006a194cebca975d74992ecfcbac546f0f25a39ed5d6100768c1f1a791f3604d12000000000000000000000000000000000f727cb947849d2d7b046218f084283e5513e8582229085f9f98fca522879543429cb8ab435aa3dbf01b68ed258d82c112ff32d44eb442a711250875d86a401d0dccc95e5ee39bec71738fd812d487c6000000000000000000000000000000001044bcb16b3384a1f350cbd62bae568c96932a364c16b34d91ab9b1035ddee93a02920ab4dbde2c6f254031909dc3a450000000000000000000000000000000004a29aae48210289e5f588aede0756ddf60724b8ac54de5d9159ea834d5da98b7a9d09a6f37bcaeaabc559dbdde58b6800000000000000000000000000000000112ca953b5ba652c715fd20e3b85c5bdfeaa7d577aa49aa4656d142c9c2afa3d8aee151338f59a199f3c0c3f6a430d6a0000000000000000000000000000000001ebc7a17da7809f9e744cf7f13fc437de34d3472f022493f58bb979e2282368f989ca0982098a7c377498f1d8d32583666b820fae2459b98f9bff20275a3c96ddcaf98a78f3f5fa4a2c0a26cea79352000000000000000000000000000000000e7c3d6bef4b1723479ab6724cf7858c221993357b194e5055db96b8168f8d78f72aaa4a2046be17ae9a7eb00695ec510000000000000000000000000000000015e85e85cec08133b86738e1f7a738de455930ffd5073997a1f1692c28044ac00b634b90eb24938cab56e286ca0dfaa400000000000000000000000000000000164646a4767ed69f9280f96be9a7f988d17c187162554239797436a0bf4c4ffa7e4f8387c3d2406a7528c021f56081df00000000000000000000000000000000197b1080bf3ac3ef7bd6123a55f20f1002f366d4efea9e14ed92fd2ef147e2b5d9251a302a85172235438bb2d35943a740a9181633a146d7f307ca7606cd45b8e721c46b955a6989d421baafd8e40139000000000000000000000000000000000db7cfdfd58a6ce9dbbcd5d65cbf22b5e1a81acc70f1c85651ba962d61fbd7ad83e5524fb9aa019c6bd75dade96f7d4e0000000000000000000000000000000011e269a390fd15ab1d52d38de78ec97eb6202604fab02c4598ecebc7635ac91ee564e751275a485fb43b933678f11fd8000000000000000000000000000000000b8597a00d2401664405dd1fc7d69786353c86cd4699af981fe869f266f9087b00df22a46ac34883173bead870798f650000000000000000000000000000000009117a49b3f2a8a850a0179b558319bdd19a5f1f4a45af0ccad0890e63b222d028536e9bb612093cb3f1068d262af90d662ac80797c633d8b9c8907acc2960ebdcb5bdad82d9fceb4411d5173b7411fd0000000000000000000000000000000002e1311abb9df5e4d76959276b6f725f13728844f8c7dfe5e25469cb95c6937a822282b3baa38817e24a6219601132bb0000000000000000000000000000000012820e6ddc50e19a8f98c15013ecc38901a4ef8ec2b79b85c7f7913da24404afa1c79045f1318cdf271028126f9420a5000000000000000000000000000000001794e653c5673e51a3ace631c1a1265dba07fb74235506b2149d42b90eb16afc26ec0ddc54d03f7ba2dd6a2503971fee00000000000000000000000000000000112479bdabb9dd057b325563c666910c01ef66adf47aa32f5a41bc9cb8234750985c266fcc329ea3704e2b8d9b15bfeb59401af15d9b83e2ad68cc8e2ad1508391516ba0b26fcc5ec6eda8b318a374b6", "Expected": "00000000000000000000000000000000168c90045dcccef35cfe8eb642924ec2629db886366fd9ebc082019690d103627865f0dc39ffdd2167111f68d8d03c89000000000000000000000000000000000b6f0928a32672983664ad15252b3f145afaa04f11d5f43a6169a2fbdc0b0a04902a183b25e38987c45579ac6d11011f00000000000000000000000000000000195c4d796989630f85df4594eb8353d44bcee76d82b73ff7a57069466337b49b875b3c1418d22d79716ffded7e704a6c00000000000000000000000000000000032db644ff8ca6a3b1ac7bc51ff783ce0cdb7bee8b2c21dcfd3adb56a3e210390756211f22feb3dd4f706e13e5cc163a", "Name": "matter_g2_multiexp_38", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c675cb5e90e45300619be91c752a5831ec47b4143c28330422cb57139882e776c1c5f000d6032cd87c16ab3b1c08ee0000000000000000000000000000000000aeb4e78724d46a55e5f101564bc05e0a1be1d80a781ce8a19607322e82c7ee59db9f53ec34c70bef0766a5b965f54b1000000000000000000000000000000000933e8d7c2420cc553afb1c88b5f64c7a39f78272b34b5611972dd5ced3f639ae2ed2aaba470abe829be6ca6d666ddaf000000000000000000000000000000000ac0a9b46323ccabf4b2024e3a5b4717cd8de9ed7de8a78e33a38037f802651a4b43380a746890d93289d547d94b61bb9c351c585d1920b8cfb89a5bcd72fe041b17f7bd091ba505b287778b0be4e87c000000000000000000000000000000000196597114fbaefb8108c185a85d0fff0f6bffecf056902b22d61cc70b49a747bb35638f5b663830a8d2ee15df9fd5a1000000000000000000000000000000000616ed44a5fe69da994e2ada03a1e09065964223333229f5f30ba7a452830848f599ee21810a95e3659cca495897bb710000000000000000000000000000000012d0631e524ee9d3c776c79137499f8c9fb752ca93e92497d89973033d60971da23f672f140c1a753b4d00d08a00babc00000000000000000000000000000000111159e95d131c8cbe8df75853fe9b3f24013daa083e57c5b716e77f6fd3872dcfe0156382c9d2778fe886621be19973ec42da11e95cebbeed0ebaecd31be24801fdec8b81f4046fea52f553c4e7910b000000000000000000000000000000000a7d253487591fbed97381b3a430404b87aac04073e5931ee0bfd9ea6e0d38a41090c6dc7f6a591336fc58a97a3bea8d000000000000000000000000000000000647c67f1816ae6fec39033c3169eb1ea89e5e20e755cfdea33572d6397e7e87635c7439eda4912361a32de313893206000000000000000000000000000000000e0cbd54634d070aa3c7a503df1171a5cc435d050def17395707bdf7a61cfd539348ee5a4c29c7845cbf0e5df0531f530000000000000000000000000000000007d006601dc1e092a616eb470be35b5d32742dc6a2a4d71cda8865f071dbba9d8a3a8cb10b486253b1633e4590e716dddfdd8996780460757702e34ad98f5f64a8c1e0bc8851d6c97f02749b8f77cd03000000000000000000000000000000000c502a19770a892b2fa1ba59900a36c0ed054a8bfa0c4e32bf471b90d0da9edca6c06b133c8f12e233b104262a81dbe00000000000000000000000000000000011801f159086d07833a691182595a42645513d316c084b2841445c4a63c6bbb402664a9a9a100e8d6436337ecbf398bb000000000000000000000000000000000f2b9bfd8ef6286bc41e9f47ffdd3efe437aad553c9da02b3c22ca04b5578d634c0543a07bea966bedf345562218c2190000000000000000000000000000000010be5ffe0cc9f580c74e027aad09c213189fa4b7aa92160ce813b8d398b2e2803294e1a730cf5c891cf1546c6bc91414f256ff23b38b3b986a62074c5a3e05e86ead9431fcdeb67512f6d502fcefe3c300000000000000000000000000000000132cd5220c125759a18c31313592eda774247f97b5134111b01ef28dad5c3ba4d3f13d1af9076d663f7e217258a6fdaf000000000000000000000000000000000f06a5b03daaf8f92f9a302f06413044ca0dcf2be81d9cf016120312fbd41b273650fbb542d419595fd2815a809c4b960000000000000000000000000000000001b11acf12cf46e40554a1d6a833566cec1b2750f3f72ef77496477831d5933f477d59463ba19c03dfbbbd02fcbb680b000000000000000000000000000000000b2aaf91827ba923c8a1c2fa1d6fb92384c9f48f8f77273056b94245114d1f3cf66fdcab330673ceb2e9dad6c1aed0d4c01b3c8bb0acb17198bde9adce3b0f7ed4cd8615f837aee928524b0984c99d0e00000000000000000000000000000000051858339be99d1271152bb390e9a2ec0c0760b7686804ba072c46db3cfc4472404a9f87d868a28f2aef16c9e989d6e90000000000000000000000000000000019a33f21d0bb8303f540bf26816f145360bd1e9a8229dbbe7981f1cb5b099e814f2691fadbeeed8e4c4b772bbd27e60600000000000000000000000000000000073eeb49aa7e601732dc0888ae6b0f5e8dde3d97b818155221f5ab8c599eda75b25c86f15ceecafdfb9ee4abe3419e10000000000000000000000000000000001507073b97d494de26e70f18bd1723d931cd2a88903ab6da2aac3b80fea78ce75caaa9b99375780d759fc4a1683950bd458f882b63c99ada33d8215111a6df21c8f7424eb2fe9f429256201d099413c10000000000000000000000000000000013b5422deb0e80bec71309d03fdba007eed33c3ce0fc6d4f9a0d063136b3b85a6fce90ee59956a9b91e1caa519f813e8000000000000000000000000000000000829a11eb50f3bb1a47b72cfeec9d1f63e02b9f7b2592174c481ea7b72a121645ecb36b3d1964b082bc6c7efb4483a180000000000000000000000000000000003d3aab53814f55fa97285af2dc6d32cfcf5a08032d2c15ac83ea036603e08a53e0d2b8d93a25dd969937c113e78064a000000000000000000000000000000000c938a68688138149cda64f168ac1466c401196eaaa44a464d9e345c422948767ad1e25d1ce4cc5996ac5d5dab61516b804d7a35e5731b111a6904e0998d90ce86cf612914152fe3d2fca0201a41166a0000000000000000000000000000000001ab96f0b60213855fe221fdbe2fb22da6bd6cad8bab8ecb747c9528d3511976236ffefb34afc462abfde13a99503cb900000000000000000000000000000000182fb121778cb002be3f90e2d6837a406edbb609bfae8fe59837aea6f5f6131a10791f92188958b57059b7b9a9d3a24500000000000000000000000000000000159cac269098d223ee6d145a4489f05875b6a546767c023dbea62b3cfba9f8518c9f4d2594d00ceac325f3d8ef551369000000000000000000000000000000000c0d2e4e7aaedec7e53bfebe8f7fe5115720e58768469b6673cee3473b08fb8cd1ebd0514689ef65d78d008889e3ed296f1629a801db6bb4066588ed79f75223120728c3a57f7129d88f7f877149223300000000000000000000000000000000079c40bd7fd2ce0f48806dd2e88850ba988e5adb0cc5120977da8110b07da264318fa034c0c213590a2616f0ebe40f21000000000000000000000000000000000905f41389be39361fbfe7641394d30870a079f230dacef89149fdcf81a4d1e0e10b9fa1c0c3ecadced9aaa19fa9dcc800000000000000000000000000000000192f50e08e497f902403df40a504a1b4b82f1957572a9ab7ef97f5ab93c6fb876d8b08f318244cba95ad5200fc2a6e34000000000000000000000000000000000be7ef45a14871dbb344a69c4036af4f994a22ef14540377d1144a92978a23c2d678cca47cbc18e8c036714112d11f7cfe80ddbcaeb784e24975b9a42801c89bdfb842cbde5fbc0c3d70c0632cfcdab80000000000000000000000000000000018d7410f0105ff03cc4ddd87a6e0b65ede4abd4609db5ae53720851c90255757e63c6482de4651eb1d3669b1e1a2f8d9000000000000000000000000000000000d4223be106693a672da890b64d2653135119983639f7052eb32051c34113022080ce2355a93a2f64a75d8e0578b2f95000000000000000000000000000000000764780391249d0c987270bd181a44f6260ef82eb00c06585db7ef09e8b069e46c4e0e659a081ab0fda491534b71b0ba000000000000000000000000000000000a8546031e6466ae43643462b7617703a63841d6d4cb0c09ce63b2fbe2c2ba7cc35367191d0313717b1daa665bcb54551aeff13de7bcc4bc2ac1b37e28ce466805757dda29c9c743eaea9da33f47f4fd000000000000000000000000000000001922491dee4e0f29a1dc090c9b48fe8e6d70c3441e532021985932005b22cedaeea7d9ce1796808d756b740ec63f8ca80000000000000000000000000000000005b34dae0e630be6a59ccae17b44eab4e7f10be2ee700bea15f9771a724f0979798617e129540901a8aa023630a446f800000000000000000000000000000000095bdf612289258b31cc79188566ceeef6fd66858b4dc060864d378cbbb69f951e9c6bfb3d1384014507ff29f9446f410000000000000000000000000000000019f06f11a833c06c1c9227255e3a1d74172e73b06675c547844065dbb909ad66bbc150ba396fa1ba22b7183c0fe80e96c4984739882bd2f882e12660815b96d2af7812d7ae87f5be034b88e9e04fa2890000000000000000000000000000000003de8082f828ec51e23c864a16147546ff60b5fa71897ff4c120556af5c6616bde96b6e53fa673cd1f8af503070bfacd00000000000000000000000000000000093013f75b6a19b5433b3b5ff044384ddfa258420c80fe81e0424e3102cbf9e550a946e56ba9746423ef745e33da51e7000000000000000000000000000000001227cfc3e9a8d6a71738c514c05766ed4f1f4605198f5a3ad8309c0a49499e4ecd34ba1ba7677d6d90203e54d7611807000000000000000000000000000000000a635221d514e58170ef299eb7f5b679050ee24c589cc7e348b2905a3cd1b7bcf2010cfe168f5aa60f4bfe15e59b4436e7f33141d383a1a927b7645656ff7a5795901a997e27003c5672ae4fbab4aecf0000000000000000000000000000000012ff0494d308d3e7321ad4c4000e9dcd19552d5e4bce8504760f066e2fb2509279b01f1568e3c3f6216bd5328cbf72db000000000000000000000000000000000038c6e8f0fab30b5c8e4323c1fd29527845c29e1a26c70b8e5284f7ca55fb55ad4ad5389b5280927b98907132f26b76000000000000000000000000000000000aef946b9b9e9fcabb36507c1cf441df2f5ccd71ef9281dafa5e25bf07d69556e4143ab402dfb38aa756bb6ee009a6890000000000000000000000000000000015f69bc7b0a6f2cb64fd0897b421e339fcc8637efced8bf33f5aed809a38b49a2e6376d18b1bff0ef70df1b7187ad048fba4674313a9727aa4b733832a0e06666d3e38184836edf786317de9dd055cbf0000000000000000000000000000000009e8450887137cf45b04184b3c6fedac6676cad416a7646e9980dc99a6d6b62164dbdfae7cc20edaacb84432627e6e550000000000000000000000000000000002acbd87ddca9dc775da01ae026f1c60f1cb5974ce40caef80cb0d2eb7839777c1f61eae0472c7568ec9d0ebb2ec7dd20000000000000000000000000000000017c295c458a9dd995d848e3ba585f8dcdec4185a953e4b8e3ca760eb3e815e39a8ff60416e1e6f974cf7e7b086ee4baf0000000000000000000000000000000003cd8725e1cadfbd80585bf5a19e086abd631d6787403edb4bbc785d1a81f6108f451ff642f4df17dfcf94dd6107352bdc0c4d0e34d8a16b3bfb51ffc9b3c353817e8e357c608b5075c173204963606e000000000000000000000000000000000b3cc99db523b3647937b694fc23281a74010079351b2c7d1ae4cc9167917f06c06e627c4ec44af6b09f2886ddf309b800000000000000000000000000000000001e2681dd123994627adc92e6ddd3ffb006521d8bb03040fe1989e4f709e4797d143cd0bb749de33c8109933c709e970000000000000000000000000000000017df13f532bc9894be932e72c609c0386d32390dee95dda45821bedbc1067043d46007b39b6ade871bd36d39a17dd04d00000000000000000000000000000000162db4d1e956fa5b5f9ef244dbc0c6d27718eca7dcc512d1d7b97bbfd2bd00cce7941d1b9a170da6341891773a729e9ae4e31f5b6629463311b9d3c8333c33c5b2e79761ffff9863acd9d636e1a9586a000000000000000000000000000000000f0e4b606ba0a175bf57d4478aa286640ce4b5507f9f9e354fd96c45443333f6889a93012d663d78956bbfa7c645bb9d000000000000000000000000000000000d85dc4d733f0498fcb10e1e814eb61245203d6c1a46181e5a388fda2680640a1271a68d645f8fb179c0dc3107fb788500000000000000000000000000000000185b02140f6314cb62bd7977042ffaaec41ba8788d356047488004d609ae680c2f0cdc94e59a3cf90b6651298b6a81d000000000000000000000000000000000038ce717d08d367a9f882f2241ae4cc0e8a31418498bf68d05805db2e162d053a10dcff85403dc473598089a78dec27e03f256e58f60307ac1888a1b0b14b56c7435213e271eecc79b4a6f88d102be4c", "Expected": "0000000000000000000000000000000004cb919a72e67c31b3409c28dca1d57833a5066c240d2889f5bbdd5540ab2a49484c2462b25da197ec8d93dc8f26ea83000000000000000000000000000000000e1ac1dfcfe22ed7ac52c701a7221b542ce72bf59d62cc49f95f8ba64c05060671098d40c83947dd1952494833a19b55000000000000000000000000000000001331f6ed8ea5ec9b9e1a14997c2c9bc9af2ca305b313e2bc5c5bd35308b7b451a362f8ad61d636dbf77d1b2388702d8f00000000000000000000000000000000186b85e656e45cb5ac9a2a2009353e45749b53dcdcdad4f378431a0e4a317652301f834617e14dfac9836c3c11512aca", "Name": "matter_g2_multiexp_39", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e6292b4d3031fcdeabe62921f0c562606b1ec6139b9c43938971d7851da4945cf69f39652425396ed1b2e70e65b9f55000000000000000000000000000000000e94bc63f3b8944ea6bd7bab811c013fd61303aa7713619faab85a271308bb220e2a94b26f5c7e4136a3d2761dffea610000000000000000000000000000000012313ef65ba41f8e0a57e9b810c13d23241e8430c6ab967a1a9bf5bd6308e89c135e00e789a5610694d146840fbd877300000000000000000000000000000000165ce83af7edc9e701eb57b332597305fedf4b939f3a13a95a0bb3d119c2a9204a4991388f7fb344ec8f15d32cab0eb5eb850f01feb55bb99e4accee0aea8fe6ed0bd29b2ca942ffe09456733aff10ea0000000000000000000000000000000005a88477765bbc8290b7eb137e6de78e62bbd929ca511cf0aa701f926440f21d33bcc6ac8f2ca5de57ee8116c685ba38000000000000000000000000000000000738074a9365c707190f882780b27dbe96179224103392b86c628b601e33b092a03e24a89bb6d1d1024862a9df6fce8d00000000000000000000000000000000188c713945046771bf852155ba412b4222173b6dec8320ffd1c59e9b36943c2c18b0dd3bd551b7b1367dde3e8031201a0000000000000000000000000000000017222294bacd664ec37e9b214407e5325eebe9753b430589de2eea13360783be52a479e2b0e9c5dc4907dd5f06a7fa822b373fd7e5806d227ca1f49ab0a7f8be2b5950906c8974de9f2cb4e13ed20a9a000000000000000000000000000000000c97299d7e18f41e538b91b75e962c3ce4e068202271b40469c58cfc477d7820e90a0e91d647e8ef5fc0cb822daefd29000000000000000000000000000000000bd1e11a3646c499a240bad708f97a49acaeb653aa5bafdcaba41c1c9d32d32c516c94a3db8816e0a43d1b1eceac7243000000000000000000000000000000001223ecf82c4622653ce84460c39afe8a967cbd87a2d75cbee1609161837c15b522480c4731c9e6de9c5c392ef1db18e10000000000000000000000000000000016c5e98d3d17c723548427868e3e6d7ef4bca339e41acef19e0710459bd4732de4a556b22cbb49b823c4ee656fa354f1babde7f3fdf9fba868b5eac61337be0d73517ac3f06c39b4eaceeb27ab6311db000000000000000000000000000000001125735092842142cb5387f1ef8fb69a3535e1f0ccce59661183d3104ec1ef79dd87a7fb36159bc67bd73ad403b46c1500000000000000000000000000000000162caf579539574199d56f4e756f1532c66278a55b4f67f4f4090368260f46023543a8a18d49e8c5783cb65f93d750480000000000000000000000000000000003accbc87996a220a625e36d5cdf05d8c16fb353068ad819f94ba8223cdf6436f8d822719153bdba620a07c5dd955fe5000000000000000000000000000000000b53c8a4b62466c998327e0c5ad65818ea383650bf0977d98a8a94fa9653fba276f7781af9f5a4e99052ee3ae65c283d5ba1635cf82b25b2d7e466717f5716c33f5f3e826bdedf19dbc1d95ff0c8052e000000000000000000000000000000001264608a59c0ee9a26568cdcea8801cc8cf6616773bcb0971234b2d987563270c7b2291fa035c8f2069ac99e16c68fc0000000000000000000000000000000000e839d8d982d6663ca4552527f4fcab6ad5e0a444e7b5921055c774871601d342a151133ae15bc76c023b7ea643182ba0000000000000000000000000000000012ffd0696b7e29b305412fb840c596b66b77ac2eed936fdbe0562541e4de6b3166a9991dbdfa0f79b78b4b86f11291de000000000000000000000000000000001777ece357f82d7303aa816237a0dbd3a1398574f4061dd2fbf6b32af38a65abf5ec9bc53bb8ede932db9cfa0842d53a1a0a832e5bbdf897553c1aed35fab43aa3f4510c1782115e14e5d56229de2dff0000000000000000000000000000000002b41743325db9550c3a84af80bc20c54b8b0b685d7f84d05d14dcabed2f450b91675aa8c5c650eb81151bcfbf1603b4000000000000000000000000000000000f3d3e69d475fe1d4259f18f193cd84a90b91589a6502588106f0a577d1c1dc4b2feeec20a4fc30b3e403d6ca9e03894000000000000000000000000000000000c10e2bd1335363fe958eb50981b99bfbadfd1c414830857b5257bc8fa6e26b50989d9adb5b3a2fa610b3151f8754309000000000000000000000000000000000008c825371319f4ebd684f76b567c4e9a389dce96068c101568dc8cafcc10896e3c20202b591a344d9a1c1be02310be9b75e0582e9ad7aa4a02ed5ffa22e55570c9f20e6a24e2186e8a2a2f838fa45300000000000000000000000000000000101d3f92fe64af93468229608007f50e3406719572acf265fb8b2a7051525a9cb67cf2e46fc8e098cf081e73f3b20c770000000000000000000000000000000017b1422f8208c2521e3896820b22a65bb2a9b47d7fdcd2ce57196123c1ce43c1db6d00f236d7582795d00ef33ad6d585000000000000000000000000000000000e261500a9c64f5ae107d6ccb57fa9151f5321ef4e80f0e271515f1eaaa5e3714c59bf97b39acca41b15d90c0505ba9a000000000000000000000000000000000c08c955b6df18444ce3726711d29c2088721fa0aa6e317c52a05f73ec7171ef8bd61047174c74afa1dea804c68a28e33b7252f8f3cc6341d490c5c4464bb36e012f1b05057f405aa907ebb2c983f646000000000000000000000000000000000985cdfb3934e0484805a1965984028d6c459654a3eea6ef66e867dfc737e1bbcd92e31020d5a4ddb7f8091cae2371f8000000000000000000000000000000001998c5682209153a261bf981e16bf1f7a6f8e5e566c1b0f975253ea62439e5b36c5e5060751f21941edf0d348bafd18a000000000000000000000000000000000c8822c1d6412bc45fea05faef33c65d5a6dd13aacf1279b9cfda2a2ee34df3146d45e3434ce8e5f242e9cf7d3ac27180000000000000000000000000000000019191b51d6664a3047aeb5590df2939b2cbb115ded70fafc2de4c2e8c2a955a957375314081a8838bf89d5a140b7b915f10427f6e461e7b63b781e116a4d5136ddc79ff86b71fa754f00c797c035412b00000000000000000000000000000000156fcfffbf01ff3c8a97e7bd99e59327d38c6f7f1083d068ae158d1901808b3c9ac96f95c2bcbdf5f74b36dd8ce58d7d0000000000000000000000000000000014c64256d1cce124c01fa727482caf8ccf007e4ae00e5277d984f31a11ce584e7633565c61d47bc8accdf7c28bb266b200000000000000000000000000000000052dc9f7fce4859c852d3d9e1e77bb7887ffd35d4d550726632acab3d4303ecf8b3ec7f4114dbd590ac20d748570899f0000000000000000000000000000000017abd1e5dad7ee06116a8131c05c9b48defaa92efc636ee34a2970d701c02b6be0345a58cd8749e582ebd105c02f10a06440c89f8b10ce15806938b7ad65ece194d2fa3cc8d7d5591bc1d52d010896af0000000000000000000000000000000018ce0fb077dfefd57f7943d432e12dc9bf92dfaa30f8341397ff8906b1abdf0c02b599edf85ba1e5bb6287aadc72d7a50000000000000000000000000000000019e5e9e3b0632ec10a26b7c1ec40248a9a8b230806c38aa24e47489a8aee5abb5450f6e5679e3f13c6ec7a79560689050000000000000000000000000000000006e257a74f45142817ea8044f403e98c99db8355d626c59e1d11c6859eb0dd1dc8af389f07562259c1f85411be6cbfe2000000000000000000000000000000000f463e345b004b1364894c6e8ab5d35bfbdf6b7544a576ed6b5c5398ca2074f67e2d80af1ff5b721fc126d3afadff1ef43f1bb26469b778edd10127e634fed4d749e25b41d8eba86eff2c068c33e714f00000000000000000000000000000000174231581338fc8c461c981d4949d18f5b753d27184ffb41568f11e178a271bfc69f8c73f2daed0fdbe5bdc7fdf8ef56000000000000000000000000000000001532474399d6a73501801e5f3fbfc6f13bdaff7a3ea7634568fe82745752ee15af23b16809be18788d295e044e29c05a000000000000000000000000000000000912eaef94ab1f3b3257b26c5e8bbe3f99eaceb8c7ae8da577ef98e24f3308abe6e6005ff674a2af01b4242f8ff87108000000000000000000000000000000001925cd635d0ce770f4925a3117721e96c316dd96708b096901ee04ce02e7b357428e4364cd488eeedf76352a26cc1d10a40251ec7a7e9f7cc29948b122010d9745752df3f4a9c67427a8b58122ad4e7e0000000000000000000000000000000005c4a7f26ef0416f34750badcbbb3bce075606435ee7f69b3589e21e37491f0b4a7a98c825ec222848f5e29618828258000000000000000000000000000000000381c5f6511c9f06ea1a76ca84adab4a26a3cde13e0825b3d81899d6ad3191628894d0f57787f854aeb9e4c57fd15d32000000000000000000000000000000000bd706a5b5ef0d4ee1b679a0af90c217ddf9242b7c39523c39657962952dc14e5e07d02154e05693bad08bfb24a2b19a0000000000000000000000000000000009f28a84aa5bd39eeb09f13fc8770fa7e2e053b6f5d7e6021da77f48b9c3807ad917ac671de88b28dd343c2847c5e8eee03e5eb477506c397bc1a5204b30872085a36b65b7a8df3e0e187f3022736329000000000000000000000000000000000a8ff1b15ddcc3684b4d4ecfb53473497feb8a04660350ab84e5719fdb0618d61acbb555174b0900b32341154eb7bec9000000000000000000000000000000001464d21df798c0242ac6aaaf3c579eb66eb8cd53eb1e5ab2727298ca61ea8ca4c7cf815bf5c9f94c2b76bf659a4e2da50000000000000000000000000000000003a25752a4360c84e9353b7f1ce74d5106cbd637ec5ecb03dd0752660fe5c7622fe2d0475a4db98f785307c6961f14b000000000000000000000000000000000163601a86f02900d214ff8fbd041934189503438c557138b6ebaca8ce3c109af50ac28074223fc81d6476a3a99559ac565cb04110bbfcdf00616c2826e253f61cf955756e94dffcbb6001f59ae4a93c100000000000000000000000000000000189597e6d618a20ecf9a87cc70b3e0eee69ffa4dba75056ebae93cfc3c2ebb368532b17d9f6c06f09e44d9f101397b2d00000000000000000000000000000000086ba610e490588e9385c8b6944c2bad1eb03058e927fb2f9740dbefb779bdf669a51af88b45985e8345b8cb168c13ec000000000000000000000000000000000db8b9cdd4a9bcfc9f7de144da0b33981e4dd53744cd260c4bf045d643a4ef5f25aa19edab7be0c7f8f5ab74a4b7f1820000000000000000000000000000000010198384a646807b16e2ed9186aed99ca3197b05964dd0348086f446d3ebb847907624f4e02f71a1e866d17a125e07e93ce1bb7cf7d7a55f0624bf5c4c35327b178923d88be748a9b079720c27b500e6000000000000000000000000000000000a293f07dc3f0da0da4bee671951175a4480a719d44cad3d627878ad2f17596f0dfbd6f43acc7a1f9857c5d1f453e5d5000000000000000000000000000000000be6382cc7a00d590f2aada3b4b75f01f8538caad2ade90227ec71e5661ae353e68789807a13f28b23b17dc0dafc19b70000000000000000000000000000000015a9ad5a6f1a511ffe1891ce260ce442996fe4d8515ca593e3e869cab9b18af57956b1daa43aec98a0281143b0c319fb000000000000000000000000000000001807a4ddb73a9aee58b54bab2b878bea8429cdc91384c8fa533a8c9d15c966350e892bdfce16d37a4048a763cbf25d71e2b4c64b363efef0c5525b0337bf407879755f060af451075f4345dea7e681a30000000000000000000000000000000015aa6b865796f88ffe770bf25612ad27942213131c566a446dc149fcc70a018230f1cc8b20461ba2c55300fd27930bb0000000000000000000000000000000000c39c4f229b23c0f65ed720d655121eab50f695864959a2aa49771b848730494d14597eb85ba35743f64eda897f95917000000000000000000000000000000000ad44cafa754f06e45dfab801998c40e5a9f56e4add5c8add1d7ed9e05d12459f2efe3f3367cbcd161f524c714f7782b000000000000000000000000000000001437b1f1a1399ce2a860f7c6517b14a2db264b2602c1c57b8eb04e165205842b483497e98e6b6f8a62e25ab8b0e722f04c85e47ebe2c26e0aa25661d3353b5d88c632182aaecb35303d8d47f01308a0d", "Expected": "00000000000000000000000000000000077b81fa5997de07738e1b34d8e17ef4a9bde516577a4290253cc759ceaae745e10a457204b9ed0069942e0b487d106e0000000000000000000000000000000015e79be67a752a46dd0605e9d07d738c5732b2b605457ce056deaa1f7093b0bdc91b4c81c4c5462a51bc713a7fbb86c3000000000000000000000000000000000cfd2e6043263bda2b97798e1a7dcb24c63aa7197f2749f92524329e97f93dcb56429d82c1d63c067d7ceb38e6c65b5a00000000000000000000000000000000026f352d2f93e6407c59d58742dbd91ced464a3746dc1ad9059e6bb9c146dc1e74235bd54b1d90bb3399865cd3102f3a", "Name": "matter_g2_multiexp_40", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001387fb972f997ed0cb97a5ccdaa759dcc3c2c7f4f15e5cc4fe74685e42cba75e778772d795847b45f274d32cd4960de600000000000000000000000000000000150b1ad31a3d434c1cbef877fde2e105d4a047dc34e3889d21544c2143e7b41b8e0024443a774bd1e09438293860a43f00000000000000000000000000000000065033cee91f5c4d429a074be3d2a8b001892455a11dc708ea73c0082bedb1cb8e8b567a6ea68a1296ad2b80e4b5b08f0000000000000000000000000000000001991ff6fb57e8cbf9d228f1a99697f785261ebce9d3c1f592389fc860b8d7a069896dd48debb8cbe0c43175cd2ecfff5bc589e7d89994400c511789cbcaea19b077e0b02d625e549bc6f2673ce40128000000000000000000000000000000000a0fa2d39d868737b9a0526296335256ab4894cc58ffd80bc6334e80d1314bdf017c8226b41ea135f6adefd07650ca1c0000000000000000000000000000000004334f7985211061dedc794ee8931ded12acd39d7e6a6ef44a749118d19ce8204d07935fe62fb2a8ea4f68f99d7c5f5d0000000000000000000000000000000018850a3fc8c851a06781511faaded1ce0752e7ef66da82c2464eccdf78c32fae306da3cfedaf76dad371cfbe012f2bee000000000000000000000000000000001296ca0b0e368429b122537b096fac77d6367988956a7f6cf70c7193b7033ce42fa0cccb8b84b9c78b16a68fd5f4c14c2c3d2a0cba111642a6354c117d494be805cad5b5c486bc47906a2d37a9cd9f850000000000000000000000000000000019deb7de7fa5254fdf5ef34fa616651ec70548187fb0bfae9f512e0bfe1f662783f06a9a99e434ced84229deddab9d240000000000000000000000000000000009c199ef916e6f6fe0677ab07beeff221a5687fa8da3ed3ad99a950b7f27159f857d1b561006bfffab551d240b764fb300000000000000000000000000000000148a211fb58b38072cf7c417c70d3ef92e9cbe22b31b2b626198add01dbe1ccfec32d333abf42140b9316312ac48aaa2000000000000000000000000000000000b551b57045365d842133e46814d5d0084248904960f8d2fb28e9623660bcee658582928703f86261cd70e95cd20cf3a530ff74626657262fb49460b2c6981155871f2eb5562581a74f968233c3cbe3d00000000000000000000000000000000185959a297a8f434cb9529a1f7bf9009fc1af3d09efb0a9dce1b9e7d30699da64e4b1d32cdb05b068621db092c1eb59c00000000000000000000000000000000106ef21e9031d108364e93ae4b5d21b0d6d78c2e86e0f8a7af27ed3d38dba0192954e8c716665333e5dcf21387d3f2b1000000000000000000000000000000000185d21efd7d613c409b6ddaa66eed70c235440974b2a9154f3711e3969061461f8824b4547c65e9db09ce875512ca2b0000000000000000000000000000000001aa46b22451afb12962bec5c6309feeb4acefdf3c98c1ea14275409b7111aacf7c92a8e024d01d4dcbfb1c91fc445a1d182ac912b005e90ab81d4f2a906da8309a69576a8afaa160fad2540ec049913000000000000000000000000000000000557370d81bc3da4c50980106b8e65ca2edc757a475194cef201c9edc0f50363cbebcf2750acab0b67e1020daf5660e7000000000000000000000000000000000462f1c1379be9bfed97a1a83a00428de63eadb6360393ba162af3762a99d7eae8549d0cee218e469e4997ada7b35cc00000000000000000000000000000000008aa5ead309fc703f6de980dd43c294530cc2b38b94d5281e9cd9b0d09f82f747a7107b700f1437f3abe36c01bcfed1b0000000000000000000000000000000014110a19d574f26e11e2163a981c3388c04854c5693e9033a474f1020d5f980666d84c60370950734c46663e194bf0ec42a002a460b51429e25f85ec4abaa580ac1a14315b1627bd52349b7b81a641d60000000000000000000000000000000015beff8cb3c79098bc73dc1ea4b240a4e0d094b3dbbd51592df6adc9c9847beb436ec83df6c55666e296fa843298446a000000000000000000000000000000000943aca2a6e57e9897ec764ee2911d9ff0a59d9e903c70a8494340cef2143895e79d3e6c03af2d6461ca199dfbd0ca0d000000000000000000000000000000000b812ba87c4989af07af44f3dfa87de119fea28ad598cb8e52247cf41bb8bd384c0d8913fc82e4cc2878065e797cc581000000000000000000000000000000000410ed148d1e354653f9d9d17c50026957fb03fec64964f2bee5eeea966b430e77f7b3538d9f4700a673fa07d0daac6b7a650dd3765032ac139d1b54ec7a5457c9e3caefa6af45d198433e5949d149ad000000000000000000000000000000000de0a9bbd63c59767938b555c7f9284d0885ca23019818c213a7d4f1594b028965da871cc5818240d155c05c69e4e25400000000000000000000000000000000079dee5649cc67700e9338799a9810d352a5c68098d0676e42e00bac31f37513944dcf47408288cb7f1cba121506a10500000000000000000000000000000000101a650e84352aaf3817b400da0aff40907aae3d2fcf16739f8ee8d5bfc62c2a0dd518201701932728a41134ea3f6278000000000000000000000000000000000f1f9dcc0b55d0ed327f667cebc052c4b6116fde5e3076dd6e447c3214d4c8847885be9547f95f341c42e7c7fa7e2c71bbedc44d54349cff199befba9531dd4120a51e2b830a3e356e68cff31bbe365b00000000000000000000000000000000148f706b4c93e739324e5db40d42025535cd33a32bb3f211add618c0e2022068384a5612da67150746896a2813a664e80000000000000000000000000000000007204ebcef495ca8232078fbf1539a4b46e89506a09dc008da457dee2792acafb6baac4f6cef2de15cbeb48bfd12bfd6000000000000000000000000000000000bf8900e48a4a56b653b1e02c3b9a7d81c2045dbf6297f1ac2acd69d1bf9e06480ea917e3a616243c3a30235abbc426f0000000000000000000000000000000005ebe0ddf4cd1aee76d0b3d03eab754664c8b36fb20ab1060900909e0e0a4abdb45bf74a0b1d40fece9bf73360f580bcbef3956ac71bfe97029b8e3f85923c2fdf9cf1ea6582b68d5a4eabc6b044c80d0000000000000000000000000000000007824d1c48bb2cc0f406e356f6e52b66392f6203f49dca7ce03ae6302ce3e8055d071cd812f97481acc654b318d6cae2000000000000000000000000000000000ae89f9eb1abe452efb7ca48f8f939d835f9a79e05211ed9f4abee06b93e34b17d920ddbca3d8bf18b96c3705c1a064500000000000000000000000000000000119ac787a7f3e9b7ee34070aac1a769430eaa8cc838f1752b573ac7f3c02a9f490de9600c856a55448598b149f5392e300000000000000000000000000000000193a3655a80e6e0b1278730600fd4f645d54947d193484131176b890ac197702333ea847317568230ad8af1280864096392f5b4291fbb18a93248e830b08fadbaad6434040c02b45cade73b77f22c2bc0000000000000000000000000000000012f66629836f0f57bdfd9bdeb2c9b7d6d5dc55c586e15d76aaa04aef06722bc8ca156fd1295b3063d738a85b3e8746d900000000000000000000000000000000097825c5db7289b1b9e640d19ecaaa81ee59e5b9884713f6d312604d8ac367634a264c316d73a9cf63358c8fb15f8c5700000000000000000000000000000000181133d027b97d8e2bef308a93b7ea2a35824dc7d01a3ed2f404fbe12ba3b3e51d94ec86cadf3da7dc9ecbaa23b411cc000000000000000000000000000000000a28a609d0bb015e375e74c087ce426dd3c20fbd8b374d3817c626faa81469cfd11a2a4e418a44f4d7ca621d0564bc4920a96f963375d7a294b584f2da699a6a00eb5781f46830987346cf4fe922a2f6000000000000000000000000000000000feca6f7e3cb286090fa3df9c5ebd10c06192fe14af58d46b827acf48fbd462f3f76d9d20670803946028437410ea52800000000000000000000000000000000183dc7085483bd05c27691c25588e33296fb610bddaac253af5b2262db38091650c1c3185d71a69d1a63770f95f381d7000000000000000000000000000000000189f9b9ea528bc2377ca3354fccf440fee059f5732dfdac320fb58541e74e444dbdcdc008c7b47681c05502f0b302f5000000000000000000000000000000000906162085e0e299a07e41b9d62668d4810b97d4be317bf376da537de7adb06de011f5f40af834593761b774771a80e4115cb4646c8996239f4fdda8c27a335361f0a19550d6eb0225c008408c47258800000000000000000000000000000000030cc52d7901d0360d10f344cecc8325412788cc30a912d5de3fa9bdab18db44efea235c5d34bab526f3b8ecee2cbb8d000000000000000000000000000000000cda35f561c19ebd85a445ce8bb1618b446c7013c07606ce58e0b5627a5c9e7cb200e2b8ee12a0564730279e75b469b500000000000000000000000000000000055ad0655a96f6dab5a432e7d2fef57a6a11113070444089df23b4b911e0994b90aaaaa2c62d06756f4704fa218f7c350000000000000000000000000000000011d22438d7c162d34802a664c254abaae07659902e1f1bfc2bdffa6c17eb11bff5276474cc3cec9507e28685f1c21bb0c8a8d98c93c392aefb64ce0c7ea455ba14c48bfbad0e3dc38d43abbc3276caab0000000000000000000000000000000001d04065373ce5d1ce47e00476f07708bb028040edb9ae7e8e00e2c6c460e1ab8b730ff510a25a3c8114c1753b7bf1ca00000000000000000000000000000000001c87217f150694a84a4e5aba8d188ebf7224e76b078dcaba4a91de6b4ab317966ce1a9267a5a27ce556c3386b086620000000000000000000000000000000003c8422590826e0999e7ae3ecba84edaed20fd7f1eba02b9daf1c46c2aec74d5fe63319047d37f5115f243ae0ddd4ffb00000000000000000000000000000000136ae093c3bd55ddaffc2494f3ba8176947cdf2f1ae408e7e786b23b6a65ba8c4131c83cd890386ba531b8637b3b042c8221622734dc6ccf6c7b84b387a3dfecafe187dab70ba373b4416ce3c505bef2000000000000000000000000000000000d09b92a559b8efe5224184fb4f43779d0b8c8f23587f4f74e2fc6fb1f94e8d2e0d591eb0702cf51a9eb402e79b46a0a0000000000000000000000000000000014ec2e4702f1ee1074cd1ad29791cf4903357e62570d16ac80c5e8ff73b255ee03a5ba070091cb2f984b2139de06a97d000000000000000000000000000000000d22fceaa48193756ce7331952a2d9a8057b67bede729e07cf8422bfc79f9ed2aeb99a9227af256deee9f8a6f227faba0000000000000000000000000000000015d9322c3a5a7ca404259c4cc7cb93dc3d46dd8dd9475756d2ce6fea527642f9230c7e94a804ecb0b4adec7963fa9cdcd3d1f427a25f5df025fa71244cb92dda9391d65b04756c41de0f67ea072c375d000000000000000000000000000000000e16fee11affc6714c7fc8fc5e7cce44d8afe645861dd2f0b8e58aa93d4f0de9b7e73020a1537bfbb0e2c8327c4aae03000000000000000000000000000000000b7745a4aaa8ab4593daa61e375d55f9043fbc7385ff229889fca514562168a4e769c5eeef4d564b41cff28b4efdb7bf0000000000000000000000000000000017f6c5b1fb00746b50ee4c7c743ae57fae2742617e5565241d012a0ef6067d9ce59be749a99886ce9836b648525d2e92000000000000000000000000000000000a3be81720e80f6aa0570c89613c78efe95d87ccb374e7f77065800590bc71d23ae097516ae1e97b498cd233221cf717b55c943fd9b11f2fb8a89f6c08a6eabe9434062354d845f1ac740e6043443f8b0000000000000000000000000000000008080a7d91caaf2470f9632575b43990a9523219d75994f1944979ed5b650be1e3c93eceeafb0875f66a40651f4c6dfc0000000000000000000000000000000007a19c4a6340e39230a33b12fe63e47bb0d1378420ec9e439f216699e512e4d70571a1670eaa6b60a5c899ac63360a250000000000000000000000000000000016898d22b2c123003480e3a01965a72de94cdfa39b20898c49e451dcf6a4727a1ebd629172aa1a1aa6897916cea192b4000000000000000000000000000000001217a373c78de9d3005690023b9e56bbed3073f13ca2408a27a3480578d8013fb9d3ee5cda95c3cdd091a5cc68d928da7b0c1d54e51b8572256aeb72bb032a5011a3e8ec5ad7e8b6e0397b9f6fc64c9f", "Expected": "0000000000000000000000000000000005829c932c80baa420602bf841ad9bb24fa25c61f33f5d88693207b81271c94eef54bb524aa830fdad8caf8c082bd4990000000000000000000000000000000000b8d184316c2471ec6875641ea83de4f9b7227041922415b38b07a0704d01f2585ec2701bb4ae0bf6a0c0522efc0c630000000000000000000000000000000001dd81e075620914254b38ca5a7287eb56f2f31f6f8fe02fa51488d45c7f4609bcf49972d0ae5ded76eed5a4c096939d0000000000000000000000000000000008067feba36999b58342ac54e48b0fe28245f8ac2498b60093082822d19854df5c3168dcd55ccb6b2cb397b77e712333", "Name": "matter_g2_multiexp_41", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000016ed84856b9f41be9bc6c025a9b79e2968e2ee6bbc27608093256c541096e2c9eda1159e6dcdaefe783aa59d52f28ee90000000000000000000000000000000014aabafdfe8c7369f93d5472a9c6c4d426e4b02c943488be993d04ed24aef5477f6d455f82b4af78381b8bd16f42b56f000000000000000000000000000000000af34789c6c923103633e5b1b9fb447b671ab05265c16488ca7224e49db21973487a5d3de4de40b9d8a97ac9b1966619000000000000000000000000000000001123a6601c5351a586f27f8264d4227f5e1df868a03e0c3df5c148cb523cdd178f96fbe52464fdab210564dfc22b29536f082a5ffb8baa38ffd684a4a70114343a1e723bfcbfeb57d0a85ad5e592d7410000000000000000000000000000000011b82d78cd9b53b8e7e5c14a7371f34f08546896bd59d1e7d8be15d21742180aacdd01b0d08da2cb24873ce75e166bd500000000000000000000000000000000161ae0d724085a6e801edf73443cca87995c2d6b37e962db5719f4c480cb830e379fa778fd2f29e75173e1c31daccaee000000000000000000000000000000000a2c2b89d00b7d19f2b0530889905c30cecbd4ed0b56ca82208d666e7576c32a6e90cf867ad87f19e4fd367a10c449a2000000000000000000000000000000000b65c0226743b573dad7ff25bf1885e3dec686cfd5da2862ab300fde4fc8fa9b587d0f2d11ebe1f6a6770bcaf2588f8f5160286a6d23c30595809dab6ee6523d7d235114d1b295087e024b4f6ffc80e50000000000000000000000000000000012d4f299998aa897db9e3194244fdd1dfb95225e3271383b5cc296bbc51c4e1af52e849d8244f82421cd198158918d8900000000000000000000000000000000110638a2f7cdb7104de8fffe29be32610063bc656e13168921501e1614f282bdc9fccff4eb3c479a42b240a2c8014864000000000000000000000000000000000b0adbcbaedbedd376efd20a417bcce562b87b7449cac1e90d44eb05930e6f558b35ef755457305da012a231b5675bc2000000000000000000000000000000000db6fa926c7e02f633730569732fd9239bbacf2042599e79a4bee76619872901c6f4ec4d4fbf3f84143a0d17b167130ebbca29b94b6583d46753473143d13a7aadb0b18d6d35d7423b8a004991fa1ce500000000000000000000000000000000166578f3087772545c0f47fe0b3efe32874d26463e4f262be65a3bb6b0fad7d0f779808f69362f3fe63c72f24ed03d70000000000000000000000000000000000a8e61e8193228fa1825cf14e94f68a5eecece9afb48b44871c5ad62510ee1fc4e9c60d5f2529b8685e6aa13ec91979b0000000000000000000000000000000008d25d81bc4bc92508c8cade33c305c11d71a06bd46f184b05dc406f0939f0e0967b02f15b4f7f6984c9fba0644ca8e800000000000000000000000000000000113660a7d2152346500a1578641aad4dac2919ce63d01d8ffa6dad72f524c888fc2e9d2876859859e47d8e884f170f86607c80069dab2a16e39370de32df20534aca46565cf573159a93c64f1f0c4a1a00000000000000000000000000000000160529ff217934c85cbaa8b347151539e252dbb502c015e8e45c128df2b8a737866737d5cf0eca6f76e4a16790cd02a200000000000000000000000000000000127f7b0e4f9351836db9c204386a199293955471dbcd7b4ee9186f0434b46dcacd1edc02fb46b4c377c4e62cec10cd6700000000000000000000000000000000094abac17b11600d7447f7ad0f21d98c14e439c4a4a6572b00c90e14d9fc54e85045d0576f74b054d384179afc0a70c80000000000000000000000000000000017165c32410a498add8e1dd55ae43f94be234ba3859fc6b4816d7436746add313f42b1fb49e0cb6c4b7341f0acd09db841c1f256e866d218b3ec20c132446945177d518573ae3f0e739ebcc8821bfbc700000000000000000000000000000000060e503ee1c5d3eae4bc0eb30fd86303a5c48c10cc7b4736d17b8774c78a8c97ee05b40d366b2cc9bc7781b1e4a192f200000000000000000000000000000000034e7012414edfc6a8f7b2c6049236b6fb77eb94b05d55b218851fc1e553514e6ad388fac08a24c33bea63ddabdfd8720000000000000000000000000000000004c832477a90683d417a00a698b69c643d6dbf82f5afbb83eb3946f8098d80de6f2d457c0a06d0051315f06e93b5e13b00000000000000000000000000000000048c3339996948974f2bac14d8a6b8430897644ec8e9cff9eb369557003aa2827a4f3fc3444c4df73663ebc9325ff317c72a47e2267010c532d676ee3c3ebfb2be2b7569f6f7a22f76733d7773ed383c00000000000000000000000000000000082466944ee7c62788b6fa77816094ea623d03c7aa2af249cfbfbf78eed26a76cff8c23c2295aac7ee1ef8dc84630003000000000000000000000000000000000a8f88adecc3f50d8eb329492f2c031e722f36627cb3b21415781156ef44954c5b8529ceed5978a37ae1248909d38b5d000000000000000000000000000000000e08f628aa014152b50a85bb6eb947d53c596d82c0d03594ed3b64c486b8630c880adf43fb1575b02e4eb8174a04034c000000000000000000000000000000000776844f28958d3e12a5c163dbd039e50df44b1c6215429381790175a609a339621475a5b9a06c3276c9177d2dd2b576c52f48e84a68d99124e678dabaf376c956dbe9603974283a9efc7c27e830e9590000000000000000000000000000000004477f153c0510d8e50bfdc2db69182c05d5ae9b94bb1880de239733e380e03d50001378432312b24b5bf0952c38396c0000000000000000000000000000000016663990dbe529a5658f2b3044bbd390ad430adaeffbd5306f758d86bd5422391bfa1d21e88c63300faad55e6a2d1d3200000000000000000000000000000000188f701658558033ce2c41101a611f74ad6d3cd075c195476bd2cd59a1a9dcfe937020737250fe418b4de435f8b3a0380000000000000000000000000000000013f8d3625309767841603329f56686a99e196d697802cfcf31f8b48f9c76f77a321276a0158a22b94e91d6907f6ff451e4fe662495bffd8ace4c1ddb39e612b361bf90a0f1bdf6c7fde2bcf63df1bbd2000000000000000000000000000000000f184d22f3c0431b031ee0ee7ae9598ffb511a2a56f5c9f15c9a4b0c53af2a10d22a311805786e303e234239326dd74b000000000000000000000000000000001062725b8c576e79e314f6a56ef9c41f05a65d7d0d57d8414e2ae9cb1a520b16ede7e418d3a9413c9c1660dd7508d5860000000000000000000000000000000012ef02fbe96f9a191804b6c4a0b65b6024e3e2b1f8cff986f5a950cde9a32ad50d4f7a72804b2d18b93250a63a7ae97800000000000000000000000000000000000b3b0333d61fc46653a7172f5a813d13ff5a48056f9689c78c4b18b8aa3afaeb7cec305d98dd600786351338a2185a651e67e96f64b80f4978fdc1cac90be538774e34c2f619f8b8e60cd2aa20f2690000000000000000000000000000000010c91e1dda48dc528f618f01abbe01db1a7b6dcb0d47b83c7b7db3331f7156f7b2d0f081458241467b0078935a7b4a4c0000000000000000000000000000000006f87f782979d2adc02e65b56a4906e50430cb4e0913636e9aa0364535c9d7ecd3b9433358e00caa8e90e84b7705bdfe0000000000000000000000000000000004635089c7706cfdb5a22ef643d1a9a5021847646ef01ea559d1b655299b65cd76a73b04149adbac612e7aa756cf30060000000000000000000000000000000002d83d82bc9fd66c558e00547a8c25633899584c9b855195c00eb3c8742d22c601982f244a03f8e0c5c21caee24405481a6ecd3db89a7f07344b5728efffd35a11f7380c740669f746fdf565905a1ca0000000000000000000000000000000000848f10eeba8ef9c7fd0e679767f6b6a2392922092916da8f13573661f84ec97c65717e55c65526cedd59dc1e096f0840000000000000000000000000000000013781974518487de12661bedfca5fe72205c51cab461b5757ff14f319d081e7845cf8e099892ea85470039713e8e48cd0000000000000000000000000000000004cc1a27d1aa88484fed40ceef72e6bd201e5ee276b5ec27624286dee112ece767b37c6f1f7846d71cc0f4042f04dc170000000000000000000000000000000004f7335d6a1463976d9fd86e2baa45d08ec65059b14449ebe4aae99971c5666cdc6e40cf0510ae99dbce97ae8b4598067db5ef4c1c174c2e5ffe5555f54f4e845c463bb5105381fb39eddc01103b1bf70000000000000000000000000000000003c1b1e0848bbe37e62f1ebacef1a574400d5048f1e09d935af2052da29140dc4074175e4d6ceb7c2c071331b2f3d1d3000000000000000000000000000000000e1c84d6b20553ddc5ab09049ec488ea2839c5818e31455a7b231cd0455e2945aefcbdc6c1979821a80bb4f77d46e91e00000000000000000000000000000000199ebb31e8800395a9c2e103c9340444c97004186929b52de33cb8d9396e7ab8d5af3fe6035d4463701ea41e341f577300000000000000000000000000000000081b3882bfdf83e67d2dc42b211069a4e93c0f173263f9f20579128391e7f2de70335df949b9c0e9b834b6e574f2f8cc14018f14c50d40d3324952ec22ed247c13c4cf10eacd32c3671757bd12b041e60000000000000000000000000000000018aa45c6b3898a5fa618f87f9a08a7234c1b94fbe38e2297a1f9c7a2e9de0ed83023deebd56560b1928c012c14dd7a860000000000000000000000000000000009ab80da6c519aee8aa1fa68c35bd0fac78b55f88d861e8fcd445f629054325d63cc4241f61e5596dad0d54c94511e4c00000000000000000000000000000000105f8253f37f5538a2c25587fd33ea61fdc744a7cdf4ff23a55e2c66a39040d4de5eeacb7e11c0d2a483d59e7c3186aa000000000000000000000000000000000f6b10cd6522a1e34c87c702f58a07858cb753d67da9625155bd433020775351a9ec4ff879f91a43f63be1c969afe675ed4a28dc3acaf2220ba56d026b292a7d017bcbe358dedc57556cf638517bbb14000000000000000000000000000000001618dd5de43a6bcde91a6a03fcd88fe59d1c8c51d3d85cd44a1920dabd2608a0b17a987b76eb8f5b20c7f1dc0abb383e00000000000000000000000000000000198034b7ab8fb8ff267a52a9423da95bc587eef8684f18639df5db44e50bae7fdea5c5e5ef37ff14937f86cc948a34e500000000000000000000000000000000106d1f017da463176bdf55e3ada78ce70da4486be42dd0095e3a8a0f6e59ed503324565b717b45ee38d90dd3ad13c10600000000000000000000000000000000112d425765fa2fc28486b95e49db63346188fc5a6bd0b7dffa4430dc82703eb44d98d726edfa4a275aa5db5028d01ef530fb17a38b7d0888eb02394eed26406bce9e92779251bdbcb432153a550c0850000000000000000000000000000000001326581ac1a1a960db1ff2e8b89b1debaae46d1e2d0aa6ffc6c7398f207abb699ac59186ae7222b5cae3abe64cb61c93000000000000000000000000000000000218753594c63ebe5fe503aab4dbe1e944b24138948542c7c43d92ccfeba5854b7bf1bbcf8078d85fb0b8701b8b092fa000000000000000000000000000000000c3ce8c17f75e78a8c9980e9fe125290d377a32ac46411876ef011e169e86e1458ac5e71cb4a446f6c640cceb8d5617300000000000000000000000000000000176966eac1e20586ad2a03b4a1598b4db1d7c66be70b1b22833e4afe0e0b3783572f791ddcd4eb70a88f4acc28b6fc7a980b5873a5d0f78c3b8582581349498fa997fe3c6b1abe0edaed594253359d8700000000000000000000000000000000099ac8430fa411e74082cf3282f9a456d3826a7df4f91ecf621e645a1abc057e1bcfaf9ee73f149bc447cf4230f2f6c90000000000000000000000000000000004e93d7fedc9e2d7423c9e111b4674a2bd83de28dcbbcc54ce4b324c96318a11603fc9ea385f1c02364ab1f6b5458481000000000000000000000000000000000bbb29d70fba5b12fadb02a24bfe3f6a5362c71fe5f964dcd0e01442781d0462a873501029192858027d612a8572e9d30000000000000000000000000000000010daa9960005562ca2d18eaf4b4bf081f194fa824cc77515c81b2c836627f21b732448f367e2cc1830ad0fa4ceb928e1619f5719c320320a3c45dcd6207575e0d8527c458c56d3decf1d12ead8a985a1", "Expected": "0000000000000000000000000000000002a61fead6801f41f2f27603cf34cfb4b917f2f85cba1f9c684995227653c9dde559e1e8497234fba9b2e4c119cbd9ec000000000000000000000000000000000085f73b8e835a10bcb9312931eb08d916d2b93a1da843fa2f4530cdb26e93b5dc95a555dbe8e50ca465b162661ce1d3000000000000000000000000000000001442fff9019b5476c217ff725ad95c92c17b42471ed7bcc121e8a0506755ec279d4e56d770a322d56f56bc6a6b0a41160000000000000000000000000000000017e7710c4639d51c4a79c5a2791101b52742df202b1827192872f168bd21020bd068160a587fc501782c1301c231a0d3", "Name": "matter_g2_multiexp_42", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001213b5d5704c454845824994769c8b300676e75bafdeb95202001161aede276ab7967ea7362d38e97ca1484cf9c342fd0000000000000000000000000000000008c7c1fa04bebe5a1fb8678370563db63e7a10b30747c2ddeb4aabd4fc0ec93220d578b8110c6bfe8a3a6ea2820f0db8000000000000000000000000000000000c4061a295120a00de52300ee625ac46566464e6702489467316e8c182ca2168052c50b5962ff47285866c17d213fc8400000000000000000000000000000000086c153169a9ed1aba10a6cbebff4911b37907d6398c441ad47da17988d512d822ee36f5217355b93c9d6dd8dcbc8e0b119d33d32affaadbf6c2b6243bb7b344a971270b488cf887334fcb15de2818cc0000000000000000000000000000000017929edde8f9940826ed739bc9f59099ce76e85950698ab0140784647023f96afa064aa4a49b9728f496515a0a807e5900000000000000000000000000000000198d98f430384c1e7fa9e2403d9c3d2f81873fb7b204378cec95b97e674e10a1a43af97db0488209904469989ce80a0a000000000000000000000000000000000afc9b5138999bcef35613e38bff4f81cf532e00346f5205405470b2424622826c746ddf0369c7bdf77467dcea5cff290000000000000000000000000000000019ccc05724b3e9966bf918f01312c80e8422b697be89365b6ca00eb31b0bd08fae942e90a75bf9da1b3d264e416060f1f1d832b355d7e0ac3653431528ad0a8f6819daaa19292a00c910ff0ff39f46d5000000000000000000000000000000001568e52c2760d895874527d1ac8597730578176bdcfc67aaf69ccda253f6616230811dac59bc27cc1e57b94b5743cb3f000000000000000000000000000000000a4ddeb8b56f105ed5f47a538052f3d38a23c0ceaa2dea241554e6508f82f47d32415ffeeafe5ae5664c936b78e07648000000000000000000000000000000000b3b335a390aa0090bfd6467d6cd02eea1ced347cdce3c9ed85dd46e38e9f2ae9642392c2875a27618ba8f2c555d5b190000000000000000000000000000000012baa4b29d116eec749353b7658af70d4d216189133db707e56068c8483af43ba86583862e6b39df13b88058536861b9e6dcfa50f6129544835b5a4568954264ea68d9e2e5d4370ee31026997a3fbfe90000000000000000000000000000000001888b83ca28c244a6178377b4ee6844dc916e28c3f56312ecc0e29d08e6254dcda39a36ccdc317d1908303db3c028dd000000000000000000000000000000000f4b73d9316fee42d60f8de402a7d07765508b84d8f2c1be1f3f9e802ed7b0c6c5fece3db95d5287225026e73de98ea4000000000000000000000000000000000f1b48122191e1bc421881de831293a80566b9a7f2c9836f7718afb69592d59d2a714cfddf88945b94fac7a50b743eee000000000000000000000000000000000f1c6b052dbd03795433d7ad122473f109484d50245021c8727d252145e7db7dadc015265d1547f9c748409d74f5aa33f7822767391d3b2331e8e1b81c659c6e0262f7355063decedabac9797a84f0f400000000000000000000000000000000011e8613c3a771a177b4b85f0c6f97a53fd7900cc23566aecbf115058d2863189c21be36dd5dd736f6d0ffbe88182b400000000000000000000000000000000017b2c4e8d8aad0a12fd7130789188bb63a08f2b243c8f7700599dd33d7e176f70f2b1818e56540ab3fa507878d96a46e000000000000000000000000000000000e2b5ad5ed3578dfdffa414a4a2142846b1232cd2de468725283e3f92b536d8ede74bacc236993f6f68a16fc6a7828d3000000000000000000000000000000000fdbf06ae4cfedc462f5913bba9bba2b5c86ecd0e298bf27a21317fe74af6ab15014c62cbfb617356548cf808599caf4b1ba1cd6a4a6c433624dec63547119c0d492e3f38afb04e5153d82e400631aef000000000000000000000000000000000b48aebc6525620b99cd83979658a35afa233d17849bd0dcabffcf3b550f875a386b6c0b4ddacf18a23843629072c0150000000000000000000000000000000010432e5abf862d3be10ac5677b9f296ccdcedf1480e45de631b6bfec42f20edf62034f7205f659f11fe5a6aa9d882c7a00000000000000000000000000000000011702a3590e7aedd6948bb94bcc874e0b8d77a18126ed4ba3753dc98953ff941495486c14c6d801c71fca3564ded9910000000000000000000000000000000009faa427c0a7da26c92b451c61f5b5e8804fe032a4cfa014397e430882cbfcff81bb22f9c15a8747ef455773c1ef65b0a41e184bcaa0721caa4114d6393ae2251fed84aef57c7927a170145308bb136700000000000000000000000000000000061a1ee841251bad461f89c52196bebb1cb4463298e88abd62cccd21bbd325ddb33d1306ffedb2734be76c18d80c8dfe000000000000000000000000000000000d05a5ce6372ce34b0bf4b19d8e05aab74abc1cedcc35a2d1d4db38813d1e5c1375d63ca0e8bbf29c510a4319d2aec27000000000000000000000000000000000dfc57aa8de28745b8d28db3769ab5ea26b5115d3e59e51ff19af8ba37efacdccf763ce682cfdc77685705781c3924870000000000000000000000000000000018c17d87411c4f8e0ca51b3eb4c3765d3846e0d1b75574f8e511b2f3e8c5ff53bf7618959ce18dfd9e4c6285e88f094f63cb451d8eb3565274793925a1869ca5a25fb19639449c71a761809f785568de000000000000000000000000000000000a0642094b89dc9c6c7c11c1e57ed542982bd246112884969d424a3e091ec4fd73dd40a5ac116f6c68216fd1e733cdc7000000000000000000000000000000000788c7a63eecd1cbc26ee6b14b09d0a3b7a17a848fc0551d50cb7497bc98287da2d9b898260eb678a8a0f446eef5c6670000000000000000000000000000000017a1298f90022ddff3fbbcca180e3f4da8760218dba595a067287a2473a6e10b93dcd54154cb64b6c078b083b42cd09000000000000000000000000000000000116e999b808dcaea0566c0fbef1807e160612dce91756b2cbcf4883b04a90320a0759bba21b41e6f4d8449b52e52f9a96a2f94d55f784ebfc6b6260327372217d6a5b9637ea5f9afc1a65f99c221c29f00000000000000000000000000000000064c95bc9c0e2be48849a349f16713791c37310f71b5d0613cf0706febeea3a56a0f0f1ac6b504524eba801e8b759f2900000000000000000000000000000000007088d2f41fc7e1147b92a2ee7062b9bec194d3a47eb9985ac1ceeef57e1a006571e7247a13dc95afcf9905be57e2a7000000000000000000000000000000000e6a0770f4315acd9e410fe58395ab8b20a08240a6948b762dfbbad3414bfca0ced4ec9da982bc9b8798b60dde78a96c000000000000000000000000000000000a70b53a6d71c83971167afe329ffacdd417bd7b228766851c3b43701a439f253a8659312db7e83a398142fe19332b527d889a3362f551b88e63463b7f0cc334fab3fdd302b630e419e362ec1eaaeec000000000000000000000000000000000002486eaf9b743d3aa6a1f3e1174c5f213bbf3e3cc0558d63ce40e3c03e1c2f6e8508248bb649aae1bc92f3eb8118a2000000000000000000000000000000000042b03959b40eb0641d39117f7af50dc7ff048697a57b80723aaca164e2dbc647ffe78fea0a6a4c07671f7db6d5b2dfa000000000000000000000000000000000e141eab29f52b9bd0ee44861f154ec1bd30abd715935a7958a19007e789a41cdb0f4b9cf7b3fac0b0d4d77637b510d00000000000000000000000000000000002cc2eaf89cb7a04d425d878a30b5e2e9858ae0b2a2ab28fb28a6db0c7283ad861bb6a92067e969e5721b43466e857db8bdd400ad873cd6ec546bff698171942d536b94e69dfef4bbf316a471d4b45cd000000000000000000000000000000000e0f7595e4c136b4d8bbd1eeb021df7dd2bcf1d9f98e4fa293f7edab635e019af87c138275fefacd806213177af40eca0000000000000000000000000000000005dc209d6c86f1871637998c10490a70371f9e00a68d1363dfaeb62046473dfb4bbd3b18b943439f75c45a1ee7f264a90000000000000000000000000000000003d215567d1e8f504a72658d48fa51374ac77234552c17db4033af780133d8516bb0769678ecb50b8b9eb950c2dd73e80000000000000000000000000000000004d780849b731012e1e5732d5f6d32c659a95c3e1c8f5ef4841fe82afc6f0aa309b1e02dc2554a4a4ee781be2be2149f63b496a64cfd15410192aee9912f869deea5a08eebd6b160667e12fdf23c44510000000000000000000000000000000007ecfb753be501d9f9b7ae7ceaabaa4fcb7b690ee04fa1a711a15dcf67e4422adef64a0f8118f93e67f24a2d1a2bcb36000000000000000000000000000000000a459e403d85972f7132641c05bb842416a7135009ff46b617bf0918e65cbbf33f76b98c10d901936e589bdf5de31ea4000000000000000000000000000000000bc6ec31a3ff92b4fae07cb73ad7bfa8423044048337b0ab9add09bf10fdf190a5f7996d157483d29fb29a681ed585520000000000000000000000000000000004c622e2bc606fefc8bd83c4a32f7353123205a6d3716b581c2c71360e5200ab069f60c256dfcb04b466c53cd61fc94470de38cb4627f53509eadb0918e562c6fa68a4cbdfa9f7578a8aaa8182f5315000000000000000000000000000000000125688e44f593c5f585765f30e9fee5e4f15247cf33ac78ed1744453385f49ac61128e23b1569ea33d74b207a5e72e930000000000000000000000000000000009d77360ea37298fe971569230159967012c4991255fb5337ca6d58cecc3cd44a024a9a044ac98a894cc97dea161844e00000000000000000000000000000000056b2dd9569f0698c732367cfb217af90a3d6dc15e2555ce0aa845616e4067a7fefb304f6525b539555a0a685f0ec5f20000000000000000000000000000000009acb138abacac351e03f7589d4bf29cbd331e93bf538578ca9466b759ea070931c786d35f74fad42261e2df431fd00316732c583e8049a5de38642cebab774d90d5f87601e3599ffc9af692ba532e620000000000000000000000000000000013515b0022ea946a8e679b9c0eac6cd67dbc4efc820f0b3d8984f12b7d154c0632a8d7207747284d49c498c79b6bb5c60000000000000000000000000000000004d6765ec6aa8744225c1e652ccddccc91fff7fa8182931c8648b3d8bd33b2177a9af03b2906da02bf117bea59aed3040000000000000000000000000000000006f1d858c4b223552f0aee466cff35d14b3ac6da35b8f482417e8f597514b065be315aec6662ea5c7784d3a9e2184090000000000000000000000000000000000345eaf0d72b9c11fe72261a2fddea318a8dab92a67ccb9438c11e61fd298a333cc42084d4ca127e09792e346cfe0f004a037e7562adfbad6b1ac48b8e4b6f277a788ea2f4416ed2900ed2791f09bc2400000000000000000000000000000000029ad10ed6d6d5bb591771cbd597a3a0b841c2347c89027126bfd1efee2ac403933beb99d08721232ab9b7354fcf9aa800000000000000000000000000000000198400d4e026c2463a07ba5a3974c869ed8ceb1f029bfc7f41b23dd7076cf4a83b17c27ad6506c852cd2cf7c4987f93100000000000000000000000000000000152bbf74cefb77fae8e825443e4ce09b4e223242187f563a236695294d0a5f540f0b29d6f93a54cf0a77900e936e61e000000000000000000000000000000000079f4759eaf044a80417345a1b4029f8d4cfc7e00fc625e815cb7daba2243a97d21e42b42ec968dc8647158fbe467088fa878f6a2e18b88d6badc5b42775e92c17974f3a18817b7769d44ceecac46b89000000000000000000000000000000000cf3148d0c30774104a097562cc83456d5d18643d5f7ad58aedd9327bf8e9450feee50ee893442b1cde87acb02b62045000000000000000000000000000000000011d4037dcc15d0c50337d71816a2b77428b8ddd530bc3b3c8550606229f88286ae94ba03578cbb5bbaf118916dddc90000000000000000000000000000000016160c8ec4e2fb780748aac279bc248b2e2f1092262f86d368d2f06a78ebcd27e929930c8f2be124e9d92dff5c6c6f42000000000000000000000000000000001980375281735390f48ddac9d00d4c6ee7312ed0797333a26a1684e09c9575e57bcecfc4a31b8d9597a8ecc703835e22c4f1a7d2b66e6202c957a649384cb277dbba769afd60708b457613f0f3372515", "Expected": "0000000000000000000000000000000019ff32d2901b7732df1a924eb3c099a9d36bf36cb32ab322f46a72d99d81c7942d0f2193a4aeb55cf079a2cc1707c7aa000000000000000000000000000000000193561d0433e1031fc51829504ca70e92e19bead2e0bad655aaffb6b41f5f75d18f04a162db7714f3f23da891ea91af000000000000000000000000000000000d010c36acbfb38d9dc2df6e6e21bd75deba5708fb1012eab23d06d78b1244d4daae38aa4f803d12441d91adfbaece7a000000000000000000000000000000001459ebfe65c3b2c9b2684042bd71201869db1a0248c740a54fbdafcf18fcdbcc7b677af43abe803362b462369237690c", "Name": "matter_g2_multiexp_43", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005b9860b565fc64146020647d1902e2a2d2fb2002b54bf5e21b6601124edf14d6e8836f938843fbd8c02ed8530953dac00000000000000000000000000000000104938181f16f16318d223febec3be3877bc57067fc23729d1f5552099125558cb21ee0eddc32ae0b0cc3555219eedba000000000000000000000000000000000211f809b624c4992a43e78a978ea32accf9e61fccef6bcd05155e52adbf4853340dfacebec9fa87e5417c045da25f9a0000000000000000000000000000000019bfe94a18da9ab4ea744389c17870ac96218d02178bf2ad502f166a3a1da8c14e3fc52038021503cd24042cde8f306d0241da9d8505208b4d3ba2521a42f28df7d06fc212e9e84931cbd30ae3ba2e150000000000000000000000000000000004fbb396eac2a1de9953febed9fb6e158a3b5a366f783d2105b562e8143031d7a1ef039e3fdcdb675b3d3aa4f4dcbe4f00000000000000000000000000000000155e23b5b70f1ce34fc229ad5c8bdfde7fb5dc0eca19596c658c1f8c38716a0a7b5ff59ff19a7a67e12760fa90eeafcd0000000000000000000000000000000002cc82cf87e7ac05be236104c1e668b5573674d9bd741f2d91d05c8a11af1f72aaa1dc20c73953fea38e6e069d2a43de000000000000000000000000000000000a7d1dcab00db0e7c0a239511d630526fb120defcd9453fbb57ee328f974a98721274144e48d22558edf25595b8ff4cc6fecab1334668102e47f1e7139059c1d715a1851a026a1580f93c2daa3f08a270000000000000000000000000000000010c9293b3c58d646a95c620a0e0a7a0a55cf43b4abaa0de1d5570fabca8d97c91afd67bd45aa234273715457da5a2894000000000000000000000000000000001454f8682f3736847cdb3f784a098f7c9e488629efc3820d49b36a2e928bbf736dcb3e1b30187c2c0090fff290dbf97f000000000000000000000000000000000a0fe3c635a81f20258db4f1031589afc8c7fd07f2fe1e5cfc8f3c40d08a958a3dbec537c51be2de99b849e006870b6c000000000000000000000000000000000728876e3fdc42273e8d71953de61dd5c03e7c31ab6ec56fc03cdf55c8f0aa4b4e5c8ed88c23c28568be0d864df026af4e2023c64a3b51cc3d82e262f83260ed4a5e9e3238b85077852fd501b52aceed000000000000000000000000000000000c9ba542189ec1828c397ace9639cf2ebbd1613356d8fb26d3c40dd00af1f43f5bbb25032561aeebba7b874bf39cb0d500000000000000000000000000000000175aa6e94a9e42cf809f48f51c48d60e74d61388dd217b55f3f63612c4565357581e5c39751a65afc3b7488caf5151720000000000000000000000000000000014c880d35d1d31793145803182584a8da003b0ee3c29c978b64bbfe4e1da82910a4539587ba350d393e1bf3169c5e4c70000000000000000000000000000000002a063b3fcd77180de632deca1ba89ec4ceeefefe9883ed9e7e06301a268bdf377c3a6e30859e5a39419e449dd27ebf5dc0a88f0aeb2b082dea6b50d591018330c2276830ed554840c10772403561ed700000000000000000000000000000000069edfb8a83760e09726f6d1c117d4bb3e499084b65e1e830ab30daf1625c37f851ac122f9f5c795912b5b6f7907ffe1000000000000000000000000000000000eb6e9b55869f65ecdf3ac46d0ee596d07c573f88724bcd802b4429392b9a56730a217a03286deb5103f70aba7a9bc46000000000000000000000000000000000e2803e1a646bd70c51806b676591b328cb20359aadc8e79d59e7c31e1ce2f1473b0b19f7a34f23aae09678b11b37432000000000000000000000000000000000b3c9fb5a39a6c40343259e12ff4fe5058f25619d145922e1d80c3f5d105a7495dd9a4da329a2e78afc31a87b2c5d5e2f68c9e76d9d8914f14007c968a31089041e67312c6a3e5d30e65efa55894ba740000000000000000000000000000000019da372143e30307a71c7b96ae0703301ed723814a35e270ef6a6b0c57144f494df1d3fa0ac369f59f3daf534070c9120000000000000000000000000000000006521d89d810c7542108de26bbc888482a3bcec8cb9b542db42d5d4af30d6c339a5b4e959da4f98dd6ef8075554f4017000000000000000000000000000000001387d9c684a0fbf615e7023c0f3ff47f4d2c5a9f748f0261656a09b23066c745420df0eb180c9716d6d0743aae7689a10000000000000000000000000000000014271b9d0b21cc69072333a6c03493321b9d9028149d24964a3773bcbe5045875c457aee11ab0682c2bdd44f098f363d80eb90c6cc25b3a48d93b94b698eff513da37210ba79d22d76a270aa97fd51070000000000000000000000000000000001dd881f3d2063adcc5638b4b3813a30e75fd308de3c9f42e5382fdbf097d5796ee9e03cb44752515b2459f131f58bb90000000000000000000000000000000010f491f4594dab938115343edb47b0087d1cd1bc12ef908e150ecbdb3a54d8dd51ab24a0e10c585f235ed99fbd3172270000000000000000000000000000000019d1665d452ce7fb6bb6da9782a55dcf12a1d9abdfd50435b8f2a1bc5b323c004fad35ff7e9aedfd414a9b68fb1eb1860000000000000000000000000000000013828087beeeb85e43e8540fbdf97af189878f5ddc1eb35c95aa06a26923330f3b8a2b43f835186865d6f5f6afdb2b9b067bfd893b12c79e13659ee9b5f22de71d806a85410c9a23dc43363915a606b100000000000000000000000000000000014964f3576b97c00a8c5f4372e2501944a1e4374a3c30e11376ea62e09d52d40d428887833bc2f06279b859c00c98a60000000000000000000000000000000019ed533a3bf469ce5b3e4e9035af177efe9e4f8b0a0e5dc9721dde49a7fc66fa31c8b1c8d5bcda1bf75a532bd2be356d00000000000000000000000000000000064ec4ed48d63ab62373adb7898bc904d246bf2b3790c3cd850524e50ec38e7fb4a364344a6a1dbd26f2ad2d0fccaa1600000000000000000000000000000000134aa3c6b72d39bedd8f9c619d206a295cbc05c611147d38aa7304e995089ce34ab1fa13c2d6c6807a88797dea20214b34abb11f7ed6d73fb81ce2777acd6bbe8839112c527ef4ad88b094cabdb4742a000000000000000000000000000000000a2a4c8b457d0d2554a2d439fd3b74b18843386aaa00d1b89a1c2d8ff7192cdd1d3a888994376bb7ddda4d16bfcaae3200000000000000000000000000000000155a7dc763caf6f0fe1ba9537c0f75d3e455c2d1c749dbb4aa7242b40a9740fe9e8e88af6017e8f743a9e4c5dc6ebc23000000000000000000000000000000000a693da3aee178e2f0489af77f671c734423032f30c0b7b48debd3b71e65dab7db12ab1e0e72d3ef686d6c1922aebbf700000000000000000000000000000000109c3476016884386d6206c94073c628375a02c8fcd3041e06b8b413508188a1d26ec5ddf84a77d059e9a039dc5470d08d6693acb1eb73f6ed1bb4f74f1062f720a7f2c0ecf2b5a944ff89feb2688e19000000000000000000000000000000000a07f457f5dee69e9ee746dd67f982914a2182b5cb2609d273d4122d57a32c195270c956361d78eb65449cf5e13907ba0000000000000000000000000000000011f149ce84c2a11ff818be3ff0f86c1b38a9555e169a8cf791c79828207b7aa89c84e8012a0c5d8cce4e89d758b90e22000000000000000000000000000000000d636e5b027e41809d7ec8bbbfd4bf641a56599a63a7678569404ec8d45c3b88c1d2969e6101528d4edf1ee9d8e793320000000000000000000000000000000011878eefa5ee49be83ea1f7a9cdcd4997ccc59a9669778b3f006429e1a22d3b2a051924f371a228856523e3a09bab59b29ca1b157e6a2b5b88d7467e851282491ed30382ba217b82ea5cc9ca0c6986930000000000000000000000000000000019e9a1950f663b258474b24c334bd256d3aedcd26dc971a745857bf1fe007da0aa00777db5c3e5d21294e99862bf8ea1000000000000000000000000000000000329a12fa0add36f259e401442bbe6e5f9139e4a46d5d091a2110d2561b5629211a1c1996f20d19327d1782340e7ce4200000000000000000000000000000000032782c94c6e45a88425438324f3a24ebf37f0be213424b1be52c878985633950a022f57f8d64af1470486aa3744f3f7000000000000000000000000000000000631556d52fdcee3529023cf20d46ea09ab3c642a7f4eca2878e4af88801d21b80b829c9aec9e73317252639c148676c40bb53575662fa0b726469da01c39df389efde3936d2eee18d7035704130ad6d0000000000000000000000000000000009eb122c61ec44afb56b64929040058a804311e0e97d3fa513a162748091304233480bbc883f6fb66080b563b308a24a0000000000000000000000000000000007d1d810fb8788b9f0cd04235771d7adbbdf8c6e67e8538b2c6f0f278755cc5e57ad720515ca558412ae1fe2cd40b74d000000000000000000000000000000000955496bdcbca8716245a130fe6eef44d13280b2d56f15bfc772f8ca66a52ca0a742e6bc273c28cfc858a3269f59beab0000000000000000000000000000000000b27aaa0d94633912c96f00ecc021773e5cf5e164e20c7a7222a58b0465e7baec4e67fb56ffe564c7a2904f36c265e61574a30a575138c44881c1c126be214c6b68335d7338875b8a398196f27510d70000000000000000000000000000000012e0572f5c84f6082dd05705a3fae738920ffff840c21e444f0ed002df16394afdc21c249b6f1837389c48719539f4c5000000000000000000000000000000000c26bb3ab52e3bddc219dc223daf472247547544e3a9ccc31123b82000b17ef325148935621edd36ced4e702ade1ee3e000000000000000000000000000000000c13a8f02dc3f209e9abf3d316fa843be9c4dd98ce1ca2edecf757bf2bb498750f6d96c28abd45d9c6cf5b8b6334b63600000000000000000000000000000000157a50d9034024dfc7b0f0db4ea0f45323d76c81bc844844ff9bdd0c13f2059066ec3060210aaba61bc074afd7ccaa286dd51553c4119255b31cb0aaad7391694f7dd29420420b513699747bee819a99000000000000000000000000000000001054edb092a7053eebc542f690e03139f2e25a0098c665741e8711c8a6b9582af47e467f74fff9aeea098b7732be72d400000000000000000000000000000000084f919e219de15e7f9ee122383c772415741e5b86be6ee7d2193a4f6be5c9cc9b2fe5e8beba26cd768bf2ea1b6ebffb0000000000000000000000000000000001822b4e8fae5bddbb36f5c226216471862af238be770d33c4fc1ec2777350db2f42e33a7ba468c317a128e8446ceff300000000000000000000000000000000130f704596ddb28ec6e335d9527707a75c97298407ff3fe17d3cba0cde4c21bfcfd1ae46272018c1db768c036f215182d88f049ab3ee2b01af449abce08ca14ea3b065f06a8665ae3510b4c04f42308200000000000000000000000000000000194dde06f8c54de9ab0ad72ba0de2241fef32fba30fd6f5e83fb7750bc120d51c461d75e495cee0d1e85f0f39aa9d3620000000000000000000000000000000010646496be02c658c82dc68eab86a4f784cf64494bd8441f884e8ff384cbb6ff3a4bf5126bbacaa556aafd652397a8a800000000000000000000000000000000109807bd4b6613acb3eb7d386e84166219e52e841c41185a269cc7cfc5f34e9ef5cd1fea29877749e0cef93a3b44eb1600000000000000000000000000000000020a388c668c9339e7aab15d03108317dea97720dd27a94cd3bb59b372b268d1a7d7d7409780bc4912c3f95acd42a57619d6e227185c538b122858ad5ae594720fa7f743f5805552152a213ebea64aeb00000000000000000000000000000000161506c4a2d57c852fe8c3dce63ec6673f05f99c1e032c8e591239616ef4469c4240482ce5985fdfd4a80f54dfa7024f000000000000000000000000000000000486c5b106393e544852c143c5ac4a882c79870363858b2c910ef4041d8803876cc55ef59cd6a41869bf5247f0db2c0a0000000000000000000000000000000000fe765ebf3c4edd3035c7bedd4aec918426898339d7aa004fd74bbf0e3236deeb7d2bbba56c31fd447816e301100a66000000000000000000000000000000001917c9cf16032e22cdd3f87f098a532a33c9fec560a88f9d4232f96cbe0fe945fbae6bcfdd2095cafe6e0b21071d6ec53f53123f01c4d0d4c18dd72ea87ebb5fcb559df255773fa0165f1432c229deb6", "Expected": "0000000000000000000000000000000015a88bcfa39f444cd66d0d7e15c4040561154c59b832c5ca895f8f8077659487581681cc8f13be136a35b4a573551ad00000000000000000000000000000000009fb6b87eba1edb3d1d23e566977eac68e8f1a28386fdca9d484c7e341c1b210390787418e2f2dff7a228e1cf10962d6000000000000000000000000000000000978de870dcd8d094072897707313b9f1a18d525e60a7cba2b2a395ffcc9d0f97f84e0784df36247d6c98824aaf3ec82000000000000000000000000000000000fbc6832c324d40f104bf82c8cda941212105131c26f630af1d3f7040ef43c6eb4486766b75a81433e46966f79953647", "Name": "matter_g2_multiexp_44", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000007517a941bec38d0e84d21508d8bdd6778a853d9fb4c5e953bcfe3c8fba3732ca0b7f6cb5c363f33d7718b1b1a68f8e800000000000000000000000000000000150c0d975481422ddec2a58a55b3d917b6b7c0510e75442c81ee856e267d7efa09641c6b79fb9e699c6b473cccde7f4d0000000000000000000000000000000009d37bf938ac30fae1cb3ffaa971ff3746ee4090d4bf8b11dff7710b3f2e4cc686813890e03643fd56fc99e847ae5e940000000000000000000000000000000010fabc4048e0fadad73d0481e290c81884f4578cfb66e0a83324739652ccf273b62204f126696a2fc6469ede39e00a9fcdf2bbbad52a3f5c0b3959d46a8c42f6f5250a93c3dcc636712a4a2baed289c900000000000000000000000000000000089b167ce7fa997ca0ad3f8bbbb358824cb41f525bf60352d5df99402af62cc6d768113d2c1ebc7fe8190c5f732fbfff0000000000000000000000000000000013dcd35865e27bf98f1f6508b32c7e9a989d528df0626228087bda0d8b456af3ea2f4be6732edf1bd8cfd0ab9576197a000000000000000000000000000000000333b0612d7068986d21e1cb67a1c7af423e98cb14aace2ce02f84d32a38f97bcdac465f2b22e5fafa6aaf0d40380e4a0000000000000000000000000000000010de7ba4f50b6654fdecc4fc6c41289bec50cff1be18be9d5c9d1f906ae843189bb43f144aad4d2a2cdebbc2697c974918adf5d8fbdf81f8e4bf2f622e2d481fb2dea06a1aaa289ce4f6e783eb9a98dd000000000000000000000000000000000fdddfceb29fd79c31b138ae8e41507f324abd5e3750da14f4f86176126a06380d53dd5f7efd00e7f94bc1370ac9816a000000000000000000000000000000000d8371c602e393a4be250583c299d069270a344953f7f07a5fe27f8617cbd3ebc91f423dc176b272339bb3bd8a9a348200000000000000000000000000000000193a260a417c9c46da0aaf139e3bbfbaa9f248943048396d95716b3be0b8a148a3f0ebcf7d6f9a318b16d2d850ec2f5c000000000000000000000000000000000be4d0f2bf6d746b930034eea8a19d73377617645c29153b6ae6d3ca6fb35a704b6a0bb658282cf93555c998f6fd054a650e995b73b63d068fd54f596cd9669fc3061f0c1da77ae7d0f5bec012f9ba69000000000000000000000000000000000731c0a5d076d6addb15c1e5d3143d41371f4835d77756418bee452d2f03b1e603230c59f87905fb67d5eccce65a45d20000000000000000000000000000000013bd198c023009190c65686468523eccb57c5fe7b159a1c5ba30c662a275fb24d69338ec9c023ee6a10a8ec9dc7968210000000000000000000000000000000018fb369923ee655839c7d996e264133c49f102978f18261faf2f8eef376eb0bdcb5af375ada2bc783e50df16737f78dc0000000000000000000000000000000009ab8e16e1d0b406adbb37e950bc3820ec13c882ec4483528ebac836726ba202bcf796e84abb3c16dbf6d1131b3854cc3350d4f13e25052b1162dad3ace76e5cda71680fdc89460d8fa88c0d157df426000000000000000000000000000000001401029d7cf8e7d2690a27c01b32008e273b5a33842dcf52d84f77dfa4b2a1fb290f56eb4ccddbb420b27e06a7a3a3b4000000000000000000000000000000000c464c6fdba702f2fbf4232b34d615e66dbb5bdf80233f695e9103272111a06a79f8972d1034176859d0e29400f5a9c10000000000000000000000000000000006cc97a29f4e694f0cdbb099278fa94140b40147f4f911de96a762f2bd28233598a892899a6329cc3cb854b56076787a000000000000000000000000000000000625811cad7c740758388f330c4a56ef30429ea4cdb9a00e2cd1b7f310184a2e6ba36ebdca57c87cebd5232f52c34d92283f0256766690c88df6cf7c968b9a96121d26d19672ce9adc84b699476a32db000000000000000000000000000000000d0a16b5d48eb062c71b91d74a0d25eca0d4bd7082de25199f33a9d3d598d137fbee2ac36e8f877c157be7438ebabd74000000000000000000000000000000000bf93533bf677050d9a77a5dbdbf7cf084b5d934d55318256712ec361693738d48ef27536476fdc93dd8e81f13d67a8e000000000000000000000000000000000696fbd8841e60300602aa5528391aa8b196d8c186d6124c842a0124a8d8dcbba637502f330c980b2f5a900be8e04d020000000000000000000000000000000017b0c51e699d2252f35619520af71775f9dd8c57c2ef146adeb72640bec2ca02a59680153e5c9f66bd513bd8559b9d66145cdeae7fd3f7455dfd2ea9a064c135f0a0a36990ea34929e292e4cdfa0f472000000000000000000000000000000000eee94b5148ccbb3642e582cf0a517b72e6ea019676a13b1484982de7f4be0346b7ed22979ba7303f6367294a3eb2716000000000000000000000000000000001502bb3964f6b3e862279e15fb105073e876c4e48c55c42f3737dc9efed82b10fe8e39438ccd39c933f5ac3c6768497e0000000000000000000000000000000016cd8c4b3be55474aef7081cb969b75ef5e7cca9bd0f9627928fe9931c6f869a9a49d0ae2cfb8346116eb3ced25d4a8e0000000000000000000000000000000012456eceaf32cbb6514e6211136475a750889caea18ff4f9d5ed7b378e6d1d265721a646715aee6b9f2098e954a88289d9cdaa979ab08b454dcb961e3cc4bb18f706bed93a72a9c1e105cd69c0b691af0000000000000000000000000000000007b5633f4a7dfe62f11065d44581f5060210f8e572d960eb85ffd0a903d8b989ce10449fc90b7e5646784a9f6df28699000000000000000000000000000000001710f252cb35d88f6bd151ed596f2d6455f050c5e25add394dbaf60fc036016ae07a5a8ed494b95875c02df3c523186a000000000000000000000000000000000bee19779dc6430ebee993f82a054fbd42e5b7265090017e5b2d2f1469bc96a5a188adf471d576a416f6a841081043df00000000000000000000000000000000038f9fb4159e4e6f596a17ddf45a00a9e4aede63b062af5eda045efacd3977e8dfd61c307834c08bb4c284638696e92ef262f9f7a26353193939bfbbdc50ee35614a3c099776f08b21e0c4c97521eb8e00000000000000000000000000000000197687895f22c4a639bcf2f494dd9e5a034610b0297528235f1d806cf032f5a86c5248a83ed6b12f0de27f5c6e6f49420000000000000000000000000000000011ccd5dd6d6ce553ade9b31503a9e6a6119ae329178706f051581e3cf0ee9d6fb527b340bab8c79fad1cd451c7edb4330000000000000000000000000000000011e9f051aacd69c8bfd2f0ecb566e6d38eabc43f276ba7a1b8e8ab093917dd1c672c61d6dac4651026823b9938d3601f000000000000000000000000000000001362c3b2e6fd9b3618df26ed28f96530c1915f0a4ecb647658d1ae4ccf4c000f3bd1797696c9ac5c5000dbe58dba8de44f0d2915e82c9a69f9e9af64a2c5cacf61ead492bf69912a35ad6a316f9914a8000000000000000000000000000000001819d13cf4522a9362bbeb0bbbb0a498c3f34da1c9e3b2c54d08f7c8acd9ee756983fe80405579effb79d673407390ef000000000000000000000000000000000f870e5978f4a6e3b655fb2a05541ac0673e7b10136adaf28be4dfc9022d4cc8a60e17d125dfe53fbe10c644ff37e02a0000000000000000000000000000000010207ef774cddd10db2bca0a051ceb12900c407ee265dea4615553c193d7475b5ba3198b7e0160740e4fd015dca33e1d0000000000000000000000000000000017937be546e06fd2eab4c969a029534c02fb770646d43edeb5e6c8bc0c2b5f35576c375bf860fd1087ce099d4377d24e25ed3f13198b69604c08b414562f67a67aa8dd4a7bd3c066874182d21ed9004d000000000000000000000000000000000db02fcda340fb27a3fd7da468c5cbed9c8dce8471843a8ddadae43dbec9957a0479aa52855d7a6dca99e7922432365c00000000000000000000000000000000163503d24f9af34058cb5afd8e9d5aaf29e141c8521eaac282f138466e834f0daa9ce14e0590b501680d5b47f866aa8c000000000000000000000000000000000fc9175e6d20afd9d194907f2eb311bf8134aeb96da72f6423610612f2ed20a074c113fe8bb632d9ad74b2f6e7e2417d000000000000000000000000000000000b4621f5e4465629648b62b7f2b77afe6470f9706f9bee5b3ccfa66c596842cbae26badc689f7f623360cb7fc1d416b84ae188cc115e9d492be64abefa4bd4c93b61dd42a7d213e1100b8108611a61630000000000000000000000000000000003c77c7efdab9a9e71283b034ef581a31faee417febfa99be3c18e8ab724c140be684ce719bc5a9ac5d3855ddbf3651a0000000000000000000000000000000011889b02b4a1150fc2b7191a95c5ee767f3c9b82a3a53591018242fa8685ee3b3542526dfdc00695a6cf046033b8eb760000000000000000000000000000000016d7463159c4e3cb635f24bfb944bc518369e894218bc49d7b7f0ea99240259f7ee2b4c26c6083dbc4559ffcfbd392bd0000000000000000000000000000000010a85df6294fd6406ca651f15494153e9802f0068bfa149e87fe4b1cc3071ba74940a21dfd55a8a77e7e2a193468a3d2eede725a693277356ce71ffd7814a77fcc30eeb3a2b8863fb91ca03da1cbe37a0000000000000000000000000000000016beec57d3049c382fc039ac96b890412c5e8075afcab599fb877f8639747a587e82241d9a8059a0bb45ad49959777d0000000000000000000000000000000000a70fba1b061dcf587f133035a3aaafcdace3b1e771d71887ae914919e5f52a99d9933307ec15b5f0a1623b9592824500000000000000000000000000000000005064161136c04f9f50e42a5cee5dce3fa0ce1dc0655b3785a852cb9741927f6c9b357ac1010d7212533d1593c83dba70000000000000000000000000000000000d50b992bc0eee37a15cfd32eda2c591fc4c4203ef84232d1a1e7a9888005bc00755d76b9d0345bb01ffa7525f2aa1e9d0618f898594b23ee3754fe390d6bdfa7d47fe749d6819e306935c1eab6b0460000000000000000000000000000000007617e60d8f67344ce6d2fb65cfd5b423a1fd091626da837dc8a51d6ffdeda9712864e8f30e45ae8df917e0e4625e59a00000000000000000000000000000000077c4aad14f870ba24703397ff0b33af2e50b026f3e0f13f3ec1aebc9ea3af98cc65ab56cce4045538ae6e5f410196f10000000000000000000000000000000004a31d0eff18afa87f9a53098cfd5d21e913c7519cb171f83d0b73abbf3e893a3ccd5aebb9f2bbdd3b0eb0326d37fd1b000000000000000000000000000000000393052e6dff65e01e79254af757f12eb1931e0b386f8cf0fa0782269f962ebc5d9bde46f5a4ad3806e88330aca59ff01e1c9420cfa91026286d7f986b538c13e8c97893995485308c69f053927f962200000000000000000000000000000000033aa108d252e9107f29cc7da79585d4525ff2a35d31479a099c7c011a9c4414d7bc5f8498f8a204134b2d14c5fcde5100000000000000000000000000000000121214465992bdefb970d420face6db75d531e67314a021d2877643ddf738fbe57625d286bde7f40efc1d329a2e85b6e0000000000000000000000000000000017e14f6cdd916b1fc949be8ba3ef9ae6cc16d64da4dd498b5458ea0c14eb7aab8f970f030aab26397110331da11a232d000000000000000000000000000000000c56ccda2a5cca61025253407e72967c767f0e7f2aa0b97d4e4a09420dcb882ff35039ae504a9c62b3f9e7bb0c2e7bbbe5095ed9a9181aee392888e3194ebf9c4a6d87b503f4668bb6cc0d290880a44f0000000000000000000000000000000010fb3396b0674b9285cc5d5a4e7a41ac002f2b43332c20a56f428d1e19e1d1bb6f886d3bf03f7b0fc509e52d75965e15000000000000000000000000000000001196b7c253c50da10815bdfd7930a69608187fc3ac5fbcfeb35b95754d3017a094afcdaea867c2f08346717dfce7bce8000000000000000000000000000000001021f178c53b7d7d2041a6419203d12ee162f27999dd8f79baa15c37a7401e7a6df6aa4192a310cc1a23bdb0b427d63c000000000000000000000000000000000953c75910165f11112583476574f3987495d33e5b1a5c650a2b30692592a442d9de36da49255b0c01a7bacaecc9b81adcece8ee33d3bf3188574e94a889794077035ee92473b7266d92a3c018771b4c", "Expected": "0000000000000000000000000000000014da1d424c936453600a4acbd3666c6188493d4da8b34d6bc508aab07e59e3680a9e3488e69d42a724c9486d70ed4fd000000000000000000000000000000000048c637348fb9a4c631a82ded1fa08d693cfa2cdd6cdffb8bffee63d1bb2ee8676512a1a8d375e7ab942b6d6bdda45c80000000000000000000000000000000000443264e7dfca91f17251c33cf72c56b045902b4db2eb10d1fd856f79b4130afa6f29f3283af7d3b8b2a9d8dd63718a000000000000000000000000000000000fb386f875190ac7a49d4742edb387f72c1ae0366ca5c71d5b7e385c11442941ce0fb9fe2014fc624fe93ab86ebc7aff", "Name": "matter_g2_multiexp_45", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000016a539a21320574fc25ffbc0ff10c821d6ad20674413eaeda6f4a31f9a028e21cbb3b224c225a2e3bc3dc221cec084cf00000000000000000000000000000000104e44989e2fba9ddce8e309f5d3fa3129f679d6456ed11137149b50adf8b22c1a148d47154450853e6797aba2b006850000000000000000000000000000000008b33b8cfc992efdf7d733803a6d08a4102e27fc4960ebe6ebdb7949c4ff5af76e55002d93a4f7204eff5f2dc4e37ef10000000000000000000000000000000017c35411c571c302c746a9b79cae892e988d50b4660564660de960ee09b3937b6f5b61fe37d09f1c02528f554210744aaddc845ad867f1e2664ef0e78bced8ff6904c5836e7c63ea3a9c858fd7b710b60000000000000000000000000000000009cd32594094d4744f59690cf8d7fd260b5ffb2a22945d938c035151861507ecaac9ea553e7b44fc4b3beb03b33783540000000000000000000000000000000006f4de33731b9b13b9cb395798769e54a0679d272c2d5175455e10c790debabae4ee02b6df08975efe806da9c4a208b20000000000000000000000000000000011859798a8383b7f994a1535bc0a96a114b90644d19921f0eec774ed58dbaa899dd3736cd1f4a4ff9bfacbc7370091d7000000000000000000000000000000000376c25b0f70427d4974c4fd1539d40996b6847fbb67822fa01cfd541cd3a3f8a9f3fe9f7ddcc3ce920a6ecb27dafca0c78cfc6a30cea34d3d3505f4f897631f67ba77913734f6c2895d871fd6d5581c0000000000000000000000000000000003a178f91a135d59dbd65eacebab293a3817d30e734c247f56a08812aa540a5c80e3f9908d86ad787bab27fbddd21517000000000000000000000000000000000672b3544dd2b91a626f37dbb389aff073777164e3e20dc572b18a2e5223bd323094e41bdbe2dec9bada227efb37dd22000000000000000000000000000000000f40f2d279c66f22bf0fedd129e02c96d8906f9f1ec19f5a5c1cbd5beb10942a066dd391b69920a0a697138f627a1b180000000000000000000000000000000016ef3caad858d323b752e5c437ee2043c8f691ca0f1862e80857f7cc478a689df97bde5b1d1350892c1adb03c5d2373ba1e40df9e1f7c84633cb3dc2223296887de7281ea66c5e1f2d5816334f7b280a000000000000000000000000000000001276e133fc5e708a3265646ef0a0122048ef95d7fb46f78b8dca57dabae0164ca986bdc74e581604ff31165f9f28dca50000000000000000000000000000000008a77611be0502d2ea7fbcf73774fbaec68eba36038e2f34f79caf07f2e4b7444efc49a4e85f88af585fd28a041f26c800000000000000000000000000000000181ab176e391190b1cae2e9b4105ca14cc82d15890b0ec127d8cdb46f30b704a089ac69e76f5b50575ed66176950e1120000000000000000000000000000000004031ce77fe9ee319b8db8f220ef4480c81568b3f6e4043c8710b559d25ad69dd38dda48b2e11d5aead18db0d1cc09b98810b9ce0020904dc1903338089c30e616ed0be03741572ce46946883874f4ea000000000000000000000000000000000f26e6d71e206c88dc81b8b8a5c05ee84a9f185e7b7f155253aa39104b5de5be7bb6cb6662df4f8e63b37fd1682721f20000000000000000000000000000000010058d13637c8da2e91c8cda7dc2cf1734a2f14b12b798e5c563ef9ef3624255a6e1c7550c37b547c35c55dc736a17ce0000000000000000000000000000000019ed470bd514f8bda8fdcd9c64f7626efdde0102907bd31551b1d1972aa14e1d361e1d58b17948909a669fa4d99cf3200000000000000000000000000000000013277afe1891807e269c22c9aa1598c12081809d888e0eb2513ca3f81308700893f74f176858ceed9c7955dcc0d8fc6893e7702da2ff9f3f14586a9ae80c8713743d61b915a7c379c1faa1b151406a9a00000000000000000000000000000000083664daa965c4173d6028e047794703a16e52ae459d3db0534d13c72d749d603edd668b9ce500677715e45216367c63000000000000000000000000000000000f4e87a65f4720cbfde7868eaadb34ec1916925ffd84e5407defbda0c39e1c7afcbc90855b275d528e7b63fd3707bd4a0000000000000000000000000000000004c9f689abe0d2dd3d927bad4b39ab44f6704014ef9a1dcd1966777129e1c72515b43c1b92ee60e9611245454683588b000000000000000000000000000000000ecc57b08b45037e62498135643cf077f01d216b5106551daab391446ce7bb37d40f41378c830081bb6a326f0105c2c4eca54e365faa35d2c9be259b53a1157b180a373813382f47c9154af18a2d83270000000000000000000000000000000012b84341bbad1eaf7fc8ebe56f67598821017365b6f3b4cc1f2355f868e8d55f9c0bed2943ada202a7d85cc884d8e6a20000000000000000000000000000000017693721988f73d77f7a41db108e428b0ba781ea88eab463693ec352cc13d394101b9a2792e0f30c77bebaa395a4776700000000000000000000000000000000093245e2919523cd57a0abd2e8a9c5cbe774bee957f26d3cb502b9c8c06483b850b031461dc2cb033d399651724f4fe4000000000000000000000000000000001530f7dbf6a0fbdc8b4f7a4d298b7824c15035428cb8df834907e25c64b8985186bb13f397b7b99ea7014ae65c428b12abe2079ecb3618de3accdf291d9479bec32bca1f9fe87b00b64a12d735f5b9a5000000000000000000000000000000000f323f01f2a63bc6eb1b565594ded14043c4ea5d1f0fbf20f39299052617c334e6126afd4273738aeb153c3561348b8a000000000000000000000000000000001525d1e1fa65f1b674feef74f6c81c82c3eeb709e597aedabbfc2b3262271b31d93818613ecdeb49c5d3a6a64f17a5d90000000000000000000000000000000010458c15bf46947a237dd1c61882b1561121f64890681bae5db6fbd24ef6c34b7fcb826eeee1fa328d9ef4d859faf238000000000000000000000000000000000e1f29275fe1805d02e069082d5e9a7acf69be17013e6c4c351277408d49383fe06f00137e777ba4aa49c29c25c6c0ddc541a44756ebda14aea95f1a1d05e7366dc0285305116b907fc89e777ce45f79000000000000000000000000000000000efb7373e11694b966d0182a9b01d1e52ec1e89cb18275921294e2d36333460b1e49fd420f1ab781b000d1491ccb0b11000000000000000000000000000000000cafcdc2c58fb3fad713ce1a38deadba8636c384243f9971e3930b961efaf303cac4eef1e8e4662636ff91eff1bf52a80000000000000000000000000000000007ea7441e1b2b0f1e42bd511c060b646c2d00bb3e6507beb5d17ab93ff68515b02f82c2dd43ce035ff660ddb0c104a77000000000000000000000000000000000bd04b88caf9dbd0ef5f89d12e72aa47d64212332b0ed871b7eb96b16295cf4810f6f20cc85fd4d1ce72119f80697c1b37d521d31de52681f1d9bbf64a12f9bc8fe0ac61aaef14d7e8d048ff09e6578b000000000000000000000000000000000c3d2d978e23a690e8422fd54f36fbee1f642611b6c3b2c2413844066159bdcd3703d1a392b030446af04b654f8f73b7000000000000000000000000000000000ae652fcdbd8e467ee9b447e61fcb811f8b6aa48840476c92daec3285785a06a81c1705fc2896c0843ab48eb92555b9300000000000000000000000000000000007088e6441cb85aeffcb4a9a0c81ebfc54a61f35c542be3870c2bb94d7081353322d4745747b0dfc3e5db07f9e48c560000000000000000000000000000000006c11f3e0941ea3bde0dd3a562dbbdad433f0b1e99ba34879e86f7951ddfb29b9e04ca62d54d7552a74e8cf1c3da3e704904a876d4ac1341e88fc4808508c89c19dd74aa8fb1dd7673cbc2d28e7d920e000000000000000000000000000000000c665f4417d0163820ac96c83cc2f09b1b3c000023d827e2690aad7357ff59e278832b992703f5f0016051ce0a4510cb0000000000000000000000000000000012f4b6688300b253fe868b3790f6d2f4fc16d81a49ff7a2edf821de16dc992d79482d66e443e0abb5da43df69f8d648d0000000000000000000000000000000009e033750a118d998b136cd671d0e760e3a617f1d6a994db8f6dfc391619f408720cc57fe550785306184b0c824705620000000000000000000000000000000018cbacd471e528535e22f714a841f110fb0484826e30f97842d65072b2790dadf0bd7b28df96bec531fbed1f3f93486b68911b04d8155f90c7c5c0cb519ee6ff14c0ae27ece0374f30fa148235e8cb49000000000000000000000000000000000c42b6fd52cc52034b04078a6565af2b43948695851393596e05f37f297dfaaea931a33f5b4c25980c093f8a742c0020000000000000000000000000000000000fdc7aa20e63743dd6ab32c82d2d6992b29779ec06eebd452c17d844159e90a7f3221f3e0e6b5805dc0f42dc3836d90f0000000000000000000000000000000003a2342a1bd528d701c2a6c72708a16df632f4e4b6cdb3ccc224b58b57af30b44556cc968ba3c0396a5e3f11568a73710000000000000000000000000000000019ccf76462668905c5687b7612a0bdfd4aac70f291d8b772e84fd5d4bcb591556317426471242fb5f44fd695c7d49279481e894ecd52a252cc76547513e2cf0a5cc6b20c3dc9c64c7f34f29a488258ef000000000000000000000000000000000c8fd4a171c5fbf584f567a1c10b20628e7e0d5d796eac4a9dd2376f8d488da25b9219c7c70709999b5553f8bba915ae0000000000000000000000000000000005d791c907984f2aaebf903a0ace52147745295f0c5e85964999a8fc74b64c8871dce358f26ed1b4af6c6f7f18e8f4c500000000000000000000000000000000110a453bbba72ac171876e0f6b4acd5b178816301e02586a143c2bcbfffcdbf593655408b9aaa4141b2a210599f452ed000000000000000000000000000000001025d5065f9801fcc1c1ebebdf67923b967ce985b5ca27ab5db8af7057fda23561a46b84fac5e793dd9af692c4d56cde72780ab3c48c8a102469799ba2f70d2fd9d324cf558a8c8b49e2ecdb71ae1c9b00000000000000000000000000000000023e5ea1909032676cdb79111a33da7ed788d2affbf4029b932eed843268f355dc92905db283d6617fbb530da3d704dd000000000000000000000000000000000b46f07de520aa17d597586cb0a6894a356757941ff9bdc2976f620e1bf1eec1dd9801d6baa2d7efbb3cc7073412ce8e0000000000000000000000000000000010022940611f418de9f9210b1be919d7506aca468fe5853675fe159d3e58685bcff6cbc2c1cb9e7d45a7bf305fca0eaf000000000000000000000000000000001888b5b0dd1648d9a27345f570a1278238957de1bd30c195d554750ea4b119e98b3989b912c4fad531de416c1533467f84ae1de8aaf498bd2d91bd828bc64e56482b225322b86529da703f47289c65670000000000000000000000000000000011dcc334a5037719256e514b2c3b0f36396d8cedcd77f33545842c686fa0f35558c397562a7e245f8cc412c776a2b3930000000000000000000000000000000006efd32c6afc56a07c813fe19e71f0248666c87e1df7e79b7afbd70178929e5660e85cea35d1c6f42b4c627a94ae0d150000000000000000000000000000000005a5fc2010798c793c1b407a577da0bf0e04b0478f19b7d0cfeff8e4e4fe2d581461831db165cfd17146c49a732c41460000000000000000000000000000000011dfe3b62eb87b039113152af74ae74137cba1762d4ae62d3cb0746272d1c42d3cb4a8fccd845a519fd0650a23a897a13256548db55ee9de70ebf6fa347d81bc50494b937ab1c3079977234a34cbfcfd00000000000000000000000000000000110e73e44734b7ab63f021727b75e735702f1acfa6669e0dc27111794ebee371734764bb165132af3a7e02f3605456480000000000000000000000000000000005fbcac7c7334cd0e6468feedebe077b80390833eaa4c28af80d29e75d692a10cf13058526fa5e5ab0fb635335ac8f220000000000000000000000000000000013f537ecc28685aba2cd60d0e3e787bc8104a3373177cb93107b63d39919c583ad3ad7a42e322249d7605ef035fe1af40000000000000000000000000000000014791f94aff42bfca13ab328a3e47b06f7da52e13436ad477cf55e53b54108d3aa531f0a5d73ae5ed7108d5cca1ecf7a575ae146524544307ee51e58a654d7324983a87e1b37d46cea1a4ec34114b44b", "Expected": "000000000000000000000000000000000bab02defb32b7938372d656feaebfb5431de1484361542c02519d20c6a500f0b0b112c331fe6f4eac3ec7f6ae4167e50000000000000000000000000000000000796b38c67df1361115bbf3a4afad2651664ef55b1ed02d3172f024f90a003fc3631753d7142aafffc64c6f6f57bf7800000000000000000000000000000000080d91637a93a9025e8691a400254af37cfde67eff7d3037d428596a808a01d9bda8025b7246fb00785cd1068b2752d400000000000000000000000000000000182a97624249f0c6d24672f04e2c93eff63fbe76cc11ace0f7193facd0655cc1e1ccb2d89d9547bc352a395efeb95afb", "Name": "matter_g2_multiexp_46", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000115b14c4eb9cc78eafedd2072be4555a3db9e61b5fe0139bf3e40a92cc37b4936c68576fee5692a80e4a9aef05a9b7a80000000000000000000000000000000019c828ea555a3c8d28cf0981e98609361b5bafa8b62e860d121c0f6d0f0dcef544784e8a5fa6a9f1d1a68b30e8e8a6f8000000000000000000000000000000000a2ef5146d2658609fd4eb98fcb5d42f6c6aac4fe53597128bbba3ba3539042ee5824f381c41dc76e2c6e4dbe0665657000000000000000000000000000000001807a12ae5f289ecde8ca0a913647d44209b13fae9dd6aa8fb4365a3beeb81652ec17cf92f6784c9ca5a077824ff6dc31129275f3ab3125db33d43b36c7de0ad60a6e9cb4457aa03275caea9635f0b0700000000000000000000000000000000186bfd109ea2369818ae2f466953eddfa763960caeee9d6f1ecbf6a3f854163342c26b56d3844bfedd8f227070f75546000000000000000000000000000000001877077daa2ea074b2868e86faf14efc6ed35a64161a77aec54624d9cb916c45de81b40acc3797c6e3338fcd7a42bb0d00000000000000000000000000000000054be1650d9bb6cae6a1ed08879668e4aa4cd139c8b07ce21d40fb1cf37f11de730ff13814a02d2d6d6df5eec4afe8470000000000000000000000000000000001612b5b7c613cb66d4134aa867d985682f6a544147e7865732887d4fbb191a9f5bdc27bfbefd397f38cb101a2d68b192dbcfd8680258eee451db60f3f42f02f388f87440d00badb0a725964042515c90000000000000000000000000000000015e2b23aa42f1e6a07b0a31dd4acc27e35ce1fb3333c3f330f2d88f112375cf24e6dd5afc4d245531e4e84f1f82230ea00000000000000000000000000000000193649f3b7efb346e0c1f7bc05b0910311270cd44b5803fa16e06655d6239f609363344bb7c16c2105e20709fb5ff0400000000000000000000000000000000002a6ee30841f471dd2ef13888ba03c9cb93c85cfd0f1d0a3927205e3f57fe291bba7eccbd2352f25cc4047097fbb63860000000000000000000000000000000005482d4a47d6e381f755c4756a761f0310d0d981523afcf288e47a1a643d6be62ac6410521e0f25828f469af6150f41e5a6f194abeb6b7c1c561aa820bba658f0277870e2a32f972f9d18ca361929b01000000000000000000000000000000000178ca460993d503e496633fe5230d895bfcdd0696d817a23ae94e529bb145a0861e4448d3bd48c55907be762192a8c4000000000000000000000000000000000015d2db77105a8ed6eadc05d3d1f26a54b3d1b812a58ab49a889f5b7fcf5ec08c2eea6ad09484fda29cc007037a1f6c000000000000000000000000000000000fd5628d61cd0835fe49fcbd2f17058f23d0ffaca4474923a2c0706d9333d9881125efa2fda56234a82158da3eddb5b70000000000000000000000000000000010ce4a0bcada5f92cc8898dbf5c108c0897322eb6a467662be569d9ed0f6e2c808e214b83969ebb86c84d38f67d20754579450b7aa155a3ab61e47e337ddbcd17b197de2dbb76008cfaa09d3fc806be4000000000000000000000000000000000fc4ed0ca43d5cb172deef02704579187a480cc977737070b8ed2dce48d3f3141619f37e985c220a2840ac01dc5667f900000000000000000000000000000000047a15e96760affa4e537a45aefaaab1e0e18052f63514a9f6544136c87b7cb4a5c8dfc0d9544518adc7932ce9cff5f1000000000000000000000000000000000c9be55c06f81e87de58a5c1df8d16174cf4115f81091937d98dad6c4780a9b8dae1081f8961fadc4f994ef62927664700000000000000000000000000000000165f9b1a8f23831a91be8077b18563c7648e54caf30895983cc26580241ca7c86b9b30408a9b27776286ed9f07bd8ecd4be94f96ec4a3d4e028644c63b2577a9ef849b403acc55e42432c3063a918d160000000000000000000000000000000006edc0d62ec31b14e87b2ccff3a21a7c8d38c3ba0ec48bbb8df27fb1acf58e1a87c4458dc2b770172460adfb9a9bd50b000000000000000000000000000000000ae80063df8d41d45fc43f3aa0881364ab5fcb9ac526ee22d3870f2edb0aa379e9d81780b0ab08a4cf308d819338deee000000000000000000000000000000000e0898453feebb51d9a1cd2bda36a307ff2eebf44dc8f4c694831218c42b51f723ffe521b356ad4e5f0dbbca9af9ab47000000000000000000000000000000000fd186dbc046dd02217cec3c7894972f71e5f00e00a40fb1521659a33e079b7a1f60b026d9055a50ae18aae5757ab8490983e6618e9e4208cfbaf647592e42b2d30de9e74e4943fb2bb49109a66302aa0000000000000000000000000000000012134b433877e0a7858e6c3b95b2a1dcfb0548b290b68c209642dadf550db1c636598ac43d101b13c2d8d5ed9602a73800000000000000000000000000000000102b5de123c449a078f6f06935c9537efc791ed8e5475ffc2d9e1d098c814abe56d4b7fc6501c315edf7e64a431c5183000000000000000000000000000000000bce703ba78f45a1c59c69429d3dda18243ba2413c5eab46d469f504da975c434eda451c85357738d6c7054755d5cec1000000000000000000000000000000000387724937bfd817a65c0e0411678cdc78df26ebd4a814d92b023710558701163349b56b80e6bb68a4401f2662a0525506615e300a924ab962e0b7fd0b044cae9516d96de603ee80695718c27d7fba0c0000000000000000000000000000000005abed9305bb79a0ef1cc70e7fc2eae35a8580cd3d1ffad73d3bdae541ad546b8f74b4ca76f8f374e31dbdaf1bd14be9000000000000000000000000000000000199b29da8d161ab3061a18debc8b7400415caf029ced47131e27d81a0f7f79b6ae5e570f34a4c74fb85fea1411bd6ea000000000000000000000000000000000b8a7c42f5289d20b1a55a42d53d49510d3871b6efbe560bb4d87029b85b930f787c3a42e225006ad62c68d5f96c2f8a000000000000000000000000000000000e74aad2b29a210cc316181863e71a1dce8866a088a072ad5972af57b813a2e968a5b16b294273acd6e81e9a5be2961dd77d3e9e64e00b9356cceb62209ad48fc89e69e2214aad2edeba1812272736390000000000000000000000000000000001587e32753adc85c98cf1322115772b0e282ef4e6a75944fc86091e81aad076508e3d727f4df0e30924fff6b67c312e000000000000000000000000000000000ae96d3a1b79985e56f80df8ac4d9792229ca580b156dbbe71a9db470447fa4dfa19fc8a8a2e2f0fae28a24b7d6153d100000000000000000000000000000000114101ad0d29ddfd2fc436d2a270711c444c8c257785f4b4c549e9c795f6dd9834d3744995d2188c0c968752a7f68892000000000000000000000000000000000d30d9cc1e2273af745dd47a596a2202ca4fb655f9f9beeb0a87631e2461f29206163fd921761fde69654cb02e23505c41f75c89ec973f65b11786e186f4d42ee2e85c40f29745d9f428af08a39d5681000000000000000000000000000000001611787ba658b64467b4a28e55ea24a3b230836af6c2a7072231045ee4ee38e02302a62688d6f988f76cb5e50eba40080000000000000000000000000000000008badcd59d6d30f26ca674753ae9257a853dbcf49a5641999634a9a35a97096b6096b7b058360bec2f9476a51eb0d781000000000000000000000000000000000d30154440d8bb5fa6538953a96ba404658817be8047fa7a3a86493f02399543220758e649948b804f2daf84fb86f7580000000000000000000000000000000014fbdd62f761fa675e4cbcb61083a910bcfbd1f8e37f1fb1915f60929b047c970b87be0730ddc20f9716ed8c9bea7f19c70cfb76a04d1a9e0d937292e5553ef371e20d5d3dd33611edc0da178e2e4a1600000000000000000000000000000000143d1f811644e3a51c735b708cb2f8a2a90311f9971c90b9ec8e45bdd6488638b6851dbc882205263887b4dd5dfb4e120000000000000000000000000000000015692a6b06e3bd3100e149c6be3cbf1566fb24531eb29036fc48f85d5da83316a38af4e714a17552024c1ca4a5e39d9d00000000000000000000000000000000172b9c88ed9a1fc2d5a7f147d034fa243d420b129343ff92b79bc4d836e380e5a7e388069e9af9026485e9d3f41a7aa300000000000000000000000000000000012e8453dc64f72653c4e9b3f6f43fdd01b896c642d21604f992dc5591f2cadf71de4099e1075a4ca4b7539f84dd5a908db878b7f5fe817599add432ecf262f19d80ac834bb0a0f983728f6e2c189c880000000000000000000000000000000003e9b6d23809781f50c0033e53d245dfebbba9e0c4d9f676ae61b80fb6e774509f62fad854fd9ea841d9905d48d943a30000000000000000000000000000000016a1ba62bc684bb1848b0ccba59597b19973b56fd9b1d9d06352de44aa79c6bf65409dafb54f859d4a7c32e188bbe19d000000000000000000000000000000000e782741a4b16c5838a8f6e542135221ab3c6ad180c85c08742992ddf0239388e273735eae76c656e61614da386ce2640000000000000000000000000000000001cf6752e88990c221af94e18744790c30aa6a158b10a1f6a56c2ee3c3f0fdb2fa7213f16764ac9e9f4f65e99e715ca170751fe88ad289c91dfcd3c3c61ce1e33f4146f03fc0dc77cde9b32b51c75fc0000000000000000000000000000000000810b0175d781256053c3c9188cee4f55620a6624bfbd2f4d2e70ee68a105bc7b60bafdb76794a048e9f25da976390d4000000000000000000000000000000000716095f8fd72d9350ca62ca3ec34d2228cb563d4e89b19b152787d42fbb750435aa6233d0a97196a9324319837be14f00000000000000000000000000000000178e939d87c37d4a2f49e1e5596945879f2f0f64419e3dfe2afa06bd58098e1ba57a9b60c32cd6527481ab3b325ca827000000000000000000000000000000000aed480a1da482e40ae610a9522f0a18399b0130202f9ca79e3573987f5f7ae30724feddb52fdd05817a96f7937aaf7984bf139cc0b6ac94697b7dc278063a74e478d47528da3f84f55fb0adfd851d09000000000000000000000000000000000133adb236d9eec3544fc91852278abe37a1da0f32a84477c0d93927d64af613b7452a5f64ddec7447779f42873cb157000000000000000000000000000000000f6bd940b51b7ec5a0d92ac77a55c296215e970e9a499793864dd69c3a8d583403e95c08b719b5d8eb0c37a8476d3b960000000000000000000000000000000007d4444062ae06e65b45c6105af53c487f6b275ecdb36f87ec7b71d5861a1bdd6d735e9a1fc5dfb476ab8c13a98b570a000000000000000000000000000000000e043cdc87c67157b5ea3e5ab1b243aef479b23861f8cd823bced140ee03dd1f8bc6cebb4bde4683ac3340823f4d55b8d19d9496e7ebca44354d5c6e1f6b8211eb06ca23a6444c307f92f5bc6dcc2dbe0000000000000000000000000000000018c35112c27caa6bfe9cf8ae55f51755ed349ee7e7141c99069dea07c21a6d8634778a91f4dc3d17da04966a9eaccab5000000000000000000000000000000001800c8a9b146dba27050ce63e78895bee2016255c59acc34fd5e6cb926c16a8fcd2e8a579fa02559b3c571cb08011bea0000000000000000000000000000000014afab23fd4ea54b1ef576a12a2a62d42b493612ef466483ee8c4e62908486c038598e72dbd9256166960db73259def8000000000000000000000000000000000899a99ae8b10da4bbffb6590d79aa33bb2adb2444a11627f05622c732b70f90cbd2779362349aede5b591e84b53a8a06940e3509e1fb090fa787fdf633a74380cd5de722678826224641e46a6e920df000000000000000000000000000000000567d6458d1a3e012c63adc8b9dcf32254c98c0b7021ec6a8d579dad47d501715d2e42a0837def225515d663e663c4f000000000000000000000000000000000178daae121366ce025c1dc2d3e72068fd40ba9d54b2b3724f7a2071a59d4f17d4766a82364540bc31a46398c66d0e7da00000000000000000000000000000000147b2851311913ea53662082acfba785d21915cf00cd154b1b495246e109ac37c3fb6c63aabc4fe71a0d37c81a40148d0000000000000000000000000000000000122b7b1a81888aee37fdd6c23d31c38e79f28945cd1798cee3f4d674e923fc68311eda8ce45a561abf9c5f0bfeb4297b27d21c1d6e06d9fba7b61fb87d364a7a6252c70b8ace2d3679ed87ce0fcf7e", "Expected": "000000000000000000000000000000000f5b941cda417cce69a30c1ba4a82cca71cb4b953d06d8e545c1b792ae22738dc006627da02b4344bb8be93a5a0dcf07000000000000000000000000000000000eebf4ac30fe0ffb905f81577466889666f801d4d6efe0fb8a663fbf1cbe76b2167243edfc6cde3f49d97d3040a9507400000000000000000000000000000000007ae6a99b86dc7ea95801776589472547ffc7a623009a592403a9710ca365510d85bbf20fa4519ca0e0ca208bf86a670000000000000000000000000000000004b5abf778c72bcc5b887855c582c042a4cfff489b0548785e4c1b735b19159be8a3f4cecf34c769a34cdefa722ba783", "Name": "matter_g2_multiexp_47", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017b47384e6302b140118d0a9247aeae2091607ebb413ffa232223bb42d16753b2ae48e5ad0265e33616b25f0c4234be600000000000000000000000000000000167be566292b835a42ac7c099d80e8a0b5d4ff91d842d4ff6026876aa1570ef9641e9c0cbd44d8578f6a758717bad6f10000000000000000000000000000000014f692d195979abd9c55ac132d0def925d4e158fe946fa7b0a010c475d60171a0951d4b68ae3c463bf1136600a1ddaed000000000000000000000000000000000ddba1f4236c5200aa52f8cb7e15fac1f20cc66dc65ed180745a3eb8308f2c851ed6c1e27e1507d3f902ce672d6f8d24facfcdf87c6ca0506b070abff83ce7812181c31729cc534497aa8dabe243351300000000000000000000000000000000023d08e255b244cffe911e43b9b48408f9fb3562edc2c27f405bb657731c885a58392ebbde9fc80cccee2404cc8547ec00000000000000000000000000000000088ef289adaf206afd2b72c93049fca2cf9292bf6471133c64ac4f42015b97bb9a23f6c34653e0218fd0abdefa56bcc60000000000000000000000000000000015cb78c1440f74b17125c547fe7a37611f01b83b91a351664c696e0f647bd2db3ffead880b96a327780026d74c9abca30000000000000000000000000000000004d1a63607b9a5c9ec31168d85fbbee77cea0ae93e98c8c1dde14d0baa72f91042b2b7ca489958344916ce79bcf286456546fa692d9cd61895526282193c90148099e2afa54f7903a5431f932bd5fa06000000000000000000000000000000000ea6cb7ff6a7f4ec38ba11e9945eb406dbb8517585fef6cdd64edc970efba244b071fa162f7c8e184acbf71c5d1e12160000000000000000000000000000000001ab80c0dced33cac8a6a085efce71dcd7021f6255684bb631cf5c1716021bece57b900b819e6eb6f5b755b74c677b6c0000000000000000000000000000000005465fdd51352cbcd8b804cd509526c3b6232976b8278cec3b7db7da14b77f78898c6240c30943d1418462cb7a5abf8f0000000000000000000000000000000006b6caa6a0d5f2d671b10217c0ce5b3962b0c3edb4f2918497c316ebbdbe1a15c803d7fc3413907346f0e7d03920005aa9c1460c1cbb2a552e3452d5c5535868ee9c2952ec3fdb52dd826c16ae3d00bc00000000000000000000000000000000170db23154805a04013052a388e14b5da00e65b35b8ce2dd967213a74735dcbfd28782cef1ffe9d384be3ecadd101e9300000000000000000000000000000000082dea309092976408a379f1dbed9d8cf91f768e2921e49ece458859c80a1d9efd4d5e588470bd669c777d16f9d2e7de000000000000000000000000000000000adba8ef34e197689228e6c4e13be75b3d4732872c99b865ce7733b7a42034d6d4d7520ef7ab712f60f1ff87bc4d9d8d0000000000000000000000000000000005df0788ec39430fcd0625f8e030d917d8e7c251ee6e3b0e79fc6fa5f6fac2ad736c818bd833e58ec61cfdff52c9c6ee2c36204b6a005a64819b06804eb94c311d78977b557e7acfa82e147b4d6ec62f0000000000000000000000000000000000922d8b5db6e415aa3acbd0d6065db1b492c92313260019ef1bda0fa091c4bf091de95846af1edb34516b1abf7d278e0000000000000000000000000000000019af4ecc4f278315ed90d67cf4d22ed6fc9af5c0d0ca654f6a74a3c4bc98588bf5347b4536f36ca8b4750c18464f9b7b00000000000000000000000000000000021eaceb11638bda8b4293991983f11cc60c1daa2287f4b4a6066374bac82d117ac3ea4ec73afc4372d254bfc433b8c3000000000000000000000000000000001037fe26a10305cc5dc11a65edc705be5a0082656cad53e63038ee57a79e16075df54331233229a129483c34d6dd92ec9160c5a553479a10996704c3eda8e57be88eaaf5d1efc8371e7e10d7d106e4810000000000000000000000000000000011e63dc251a5a1e2ec83741682d90588b6b185365b33dba45458b1f56324a4900b04d61af155a0edb0bdc2971b7aaa210000000000000000000000000000000002dc1bd5448a2ebb9a02509af8777616ba9657bd3be65519233f0187df77c49fc931bbd3ec0ad5856b2ec0dfde476a870000000000000000000000000000000019f0cf8baf100451313711bbb0a0fa318c14224933897e74fb727b585cc8620b7d741c9ca2f0d3cbe14a8749aa48ef3e0000000000000000000000000000000018448fa9e05f87d4991ae1c248413edc9a8c3ee789c9c005e691bfc9003191ff469e26db9e42e5758fac79309a62942c5e5a50e5dbabb7a56897935683f80a5b16dbef3c23461e241fbdfceea38e3ee200000000000000000000000000000000109b71c19cd36ef3078bbae25ce6d0e8f7b58e129407fe68ab09aa747bfb3e90c04ab804fa6b7a223c172146fdb14683000000000000000000000000000000000d297750ba112da88beb84b8bbf74ed134b59fc9496da3045aa6dbcd97c68425fd68b75508de113733602a5565f4c8a600000000000000000000000000000000149b8ba6e05b66d07b353f46ace4e583bb61ed18fdbcea0e941b8d9805d3168040186d1c961add494f98e4e7fe68824d0000000000000000000000000000000013a6877bd46557d23b9aaf371ee5a101227d7938c64503b04b39cc6cb4e8ddedcf5cb6865439c9f8b1bfebb807ce52e24a95b293daa2761cc456b9667517f499c4d9eb9eb1d82237e7a7819b5d44f7a200000000000000000000000000000000073f440c2704fae6c86aca3cee34591ec03c362c2c5153a5e82c7bcdece2af0c58a3484b448c8bf4da851800ead959df00000000000000000000000000000000075a2c26372b482a2420bd3c9952fdbf9e5fea906dc8a4deb9691f8745372805bacd68a4838a3fefc381a2ce946ed1780000000000000000000000000000000017575b016435782cd09901afd2ea6773b11f5a983bdd19d14668d75362f95d055b76e5bf6966b1bd7bfdfbe9a939e4b60000000000000000000000000000000001569d74258298fac89d0d91a9945780f4c08d7af7b942d06255ae590db6e8509c908c16bd2c2bb634279debb72f489b5e22ef32d111261dfcb5a2e8d23c8d920f013bd9602bbef45e6d4e0909abdef20000000000000000000000000000000017180e36b925e2ce23c46813d96b919ca181481efb5d1666c4a4e9c8031abdd9521eb8228c4e3f16de0b33da4c73588e00000000000000000000000000000000138965bff7c573546d80ef7efb3d45e87ed20f59adb0cd7ae148d09a97da7feaf1b0ef2455ca19381762768a7d82f486000000000000000000000000000000000360bd29c3f07c5b560e2ac226112a628839da9db18b052991eb2d9c54541c1b5ade9b3c2d7f446ad50050531228120f0000000000000000000000000000000007105978bcf13bbe2bf5c8f7d165998c3ad99b6a2794c90f5b61fb7bf2472d307df8fc9f4afe7ae1e40e7f0eee8ef9466e687c0ac8fab70de2416642afa1553bb38183d2914050602874491057f78786000000000000000000000000000000000f4434c5180ad10cd45dca62b8da790cdb912c255c0f33950f7039e3885b38fa9e9297c7b0a875380545839d8c4d4ada000000000000000000000000000000000d0dd1429e512884ac209f788b5832d31649a78a8966d3348a93f841be23c8e4e42d6ff0d6c27e8f43daf495c9582935000000000000000000000000000000001307377f55dfed30ac1a406671af1895218a01d063b025d25bdbc53f5f9d535e4cd8053c09b2cebb25d3a08365ab8ccb0000000000000000000000000000000004f5c06f505ed15aa7661249b7edd71855bbf47237e049aa951e1ea3ff88f98591518bac975ac628e417892f8e9e5523428f1a27ea15135f044643dc36a3f9c2b4446a3136bb11f696b0a430a7454b3f00000000000000000000000000000000083336fa0b79691b4875ed27b2bbd2d2586992940356f6ae5ddd2021c5ddd87f07f0a5c1e8d8a2654b99182cc2233e84000000000000000000000000000000001880f3824f7cef95ae5743de2e17191848d8d30f0469f455461c6559ebc75a7afbc86dfa3ee17f5470f74018ec335edd0000000000000000000000000000000007c2b26353e86223e5dbd4ed6d59f1170b9cc9dc600fdfbc6c73b96f2c667a82128b1ae5af0542b11a7d1efae87c75610000000000000000000000000000000002427b7eeb497a20cf15c10513cadc9ea612f3ae94e2ae833d281734e7b5d1d50e240659ac01da7864a95b4cdcf88744ae21ad8a6c9d75b51133e81ec34d66ca70a52529c5c3a2307b0e8d6f1c5e7d97000000000000000000000000000000000e72845430ebfb84f8e3cd3dd418f6dc528bf521aca4f9dbd798ed903ef0ea3cf21dd1409aa3759351be32b21d8e8cbd000000000000000000000000000000001457ad87f0957006192dff7d99815c35adb3635815e5d157542b9f52f1e9f8c0143a21a3be4dc1aea3a895689f4a316f0000000000000000000000000000000007e8544b1037ece2e5a9ea387e0f43b72e895e9c2ca4d205f12bf6df0b35ae62a4d62756221d6fff65b928b7358f48b00000000000000000000000000000000012c5c3167f6ef118c4044c0aafc85a337d305437d694a7bd6fb406dabb7364d9e90d74a8b327aba971421a5b3dd5d06988a23b118179ee2c34ad030993a2d2d70375311b95254c44254a32508abcb612000000000000000000000000000000001995d7cb79da7b6c5a0c8ccc5ba075d8d6d8ed3cfca85e8ecdd2b589986fa58c4cd4f045983e9184d79173678d618f310000000000000000000000000000000000f9f7f6bcff0f6fd621f3f8fcfebac132b3f0d52a34af33bb9830bd714d2982f3cc6674ad6ca668131a5062e5589df90000000000000000000000000000000017699b298a46829020e0299ab89ab6411af0a602dffb0e149053ff40ccaec71a908da02c8e611723cd06c16a8e5c0f2d000000000000000000000000000000000523b287383c1e47a6f31d397359941fe0bb8167aa11604ff8569969eb5ccddf4c4f432d2b6fe6f39204020e850d4f2b30eac099ededf0087275d1af828bbf79ef7fb0e77179a068f2ebfe4c749a98c90000000000000000000000000000000004760120239593cae5bdec813735ccc99a88129c707686cf43efbd48fb08d8da3086879a6042bf118879fcccce0736bc00000000000000000000000000000000105b8191431f701b365c66680cb4eb267681ee4da17ba55d47cf26d21ba1c0c3eeeabcafcc79dd87b6457bcc91e9fec600000000000000000000000000000000126ab502f66e732aabe02fdb2f7a665a9a43f6b4ff21c22fa976e7e434b08b606e9cf0f02459fd85f5a80a332fb3a62e000000000000000000000000000000000b2ef01adea6c00250f2f14c98ec6d6083c45019f3d166419e3a137667324f80c34b6b72e991daf72e2eaf9985d0f9287e8dcbf708682225fe3f71b7a687da23de5ed188e40585be0553358012132577000000000000000000000000000000000ff22a0db4f1b1679bde5853a7c2932501f191f4a9f25eed968a796219cef028e26070851a9036a05a04abd73bd6bd4e00000000000000000000000000000000097e9310749f52a4b645190069f4d52315f0eb2ff9cbbcd31f1781a68b2664bbbf27166e6e74fc2be2e5b1eb3f3d77a00000000000000000000000000000000015ca218d7d128095bd4f4b4f7bcf7666e92b905e551dd22745bc743ad0783b6ac44b841f87d3deac44617a7c9a341c55000000000000000000000000000000000a1cb723a4c378e5db2775f4dde9a6887ee3313401a64130a78b90d65dda3a5d9c8bcbc1a0d78c310c869a7fc4889954532cd42a9b698a2c2d22b1a620a7ec60daa9d1eb8ac36894603be7bb9b5e37be0000000000000000000000000000000018b30cc461a4e1fbefe209a709a21ae201bc6094b2d15f0d6dee5a55dd84ef56b62ab1b6bd513b27c84c638291f4205a0000000000000000000000000000000008a6f2082d6d510b280a270c09044ad31fb18b851ad2b38859138c9c2e4870fba6b607f682a798bf21a13bff116014d200000000000000000000000000000000150ef352d494a97d0a7ffe44903aba1611c8d81fa2788c0f42a6db48a71101e12f07318da5ceb1f0af3aa10cd4c26341000000000000000000000000000000000ffdf3b133cc926684e4624531569bfa09b1658e29ad9c3efbd5e9d18353ffbbfbf23a2ad80ccee88f8fa597416d47173ccd5e19892765e549a63238e664c732af781fddea558a117cb927bc4a1aceb5", "Expected": "00000000000000000000000000000000134f45e5409998e657923ca76ce92b7d2acc932308e0694bb22f121f8324d16bfce86f96c67111c8080289eada4b4fb40000000000000000000000000000000008d9063b7845ffc8400c0b7585e819043884f92e28f7e3ffa47a39e808cdbb034ef4230b6e19bebf083e939b6b686b0b000000000000000000000000000000000e95f8fcd6b5bcc9e00a580a99627d92fa7486ff5ea587df5dded24d1b0bb76d339f6765a5a2058a8e227f633ce36e91000000000000000000000000000000000393041eb33f2c63df3f40d8ea1e1a9eaa9eb0a46151294845e542054d503ef69b40b0b676b0e4f3e08f4d26c36a5d4b", "Name": "matter_g2_multiexp_48", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000042a220276f12fb4e81c40ecef3a0d86634b4d1c0acfdc463df4e7501289f0be385e03808d44be053e6ac98f403a8a930000000000000000000000000000000004e3dc92e155aeebdfccaaa1d24f49efc8b02e4d9ba8500a5b953a96e0fdd58519bbf1c279750eb8b98616e6bb9a3f6d00000000000000000000000000000000086bc212a83b09c7361540349767896058d5567d4342c607ae9c07fe5f123d9aaac95ded6cdff0825edb5acbce3e2b6d00000000000000000000000000000000062598cd6d5680a155b6349cd51d636c1350746d17fe0fff5195f164ba2fa51cf52f8662f43d555f7be6bb8bcacca39448da17551b2369b723bf932173a9167663f8389d2461b763d6a061df78d7ff1c00000000000000000000000000000000193e2c749e5bbe87dd5c306d822740969cd69ad6e156c323d217c08b18bb3f97c85aad63aed1e3a455ffa1b6d2a670340000000000000000000000000000000012a3dce63a88ae32a746e3812833569959021e1dd9518621793308f8f11d04829b2c3d0e0ec39fc48dfb8285b6852746000000000000000000000000000000001235488d01c380e91872fc57cbf618c3531a6bbf6cba9dddb9f07168cd459c9e866e44e9e5336369cffd8cc3a36cddc00000000000000000000000000000000010d85f85d6242b63f8421e92f1c37f64d33fed67e0cd3dc4b2b2cb4a7fc7637f9e049fc959720eae6d1f452159d48b78def52379c8b9e7c24d971c3456b85b51a63ab03761ec66c8dfac1018833e05940000000000000000000000000000000010889825c752d0ae8445a1d0f3510135b9672c30a781788698f637c2f535e35788d76492edce8ea091223d016b5cc141000000000000000000000000000000000577175035c86c022e634ccc9a5beb96a36aa068cdc36e5a4fc2028d5dd099c5296d30a916d3b720f2e051e7d72e4d490000000000000000000000000000000017b46e49ba08a0abb9394479d693d8097a140094d0ef1d1ba7761fb601a686b0b2b4d49abc2e393a99c5cb760299992b000000000000000000000000000000000820f8e52c1b09986a70bff04909b044f671c3933de43a6bdfcbe3712310274ed880d7adc4947490c7de095ea651e578b2225be6985b9c8fa59a2890da56427612a4334937761e24a33d37f0f951a794000000000000000000000000000000001776b92f683069fdc006904fef8e91f716d9f6bc46306b042228088545f0e11a41b40b60722d4f0483250391febc0ed90000000000000000000000000000000010d5052ef2504115e9d9d4ca81c7080c0868cbed605dc7673f7f94f5959c793c96aa5334175e58499102ff76f974ced80000000000000000000000000000000011d1e719bb69d842df4fc23e8dc4393067d00f6fa8ee42d89b462a546414b91f68dda5378fa093b3ffa764b5fc63b1aa00000000000000000000000000000000099d0784a200e5d2d38773912cf1a49e813c871ede8c50da03abff58ec1943d2adefe66bd2feed1c57f5a80253e091d0a64ce8ad619276bc7a00cb49faf6cc84b917ae6b37654363f5719a727a220291000000000000000000000000000000000d7287adbe0bc3cbb35ab8bfe69064faa83e3e64d73a0c64d960949e10070081a99c35d1dacea5a3b9bf312745acd6e600000000000000000000000000000000034f1995eb8631e080378b22a51ace902ebc9da4589c89ab557b6aaf685fcc74ec1fcf95f6b9a31b7a45cfc5a1610c640000000000000000000000000000000009f56712a46c0fbc199c12d5eb7abd60e660e2c6d437007c34954c6234a0496ad0adf68cf759f8ea30980c9a78175e1a00000000000000000000000000000000073fae1cb78c776188190a4d7223f7cdce9a36488193dc06898919ef4d5136099c3185d352028760c753e9eebb52ac240b891d638d7e76e0dcb230b1f9a7c3b35b35193c43a6c86f345f5a5bc9c708f500000000000000000000000000000000019944fc459fb601bddf10a3a7eb55f34713d396c3208a10089b8f21f4bf0a5e87e95ccf73e0bd90474d3e043f37a72300000000000000000000000000000000158445bd2b6d396a390a0bd5e26256587f980eae84d7a592b2b4d788c452d312b854427185a770084e1b4c7898962e50000000000000000000000000000000000ba44a1b912645354da7d8d9c694b1d5a9ff2d642fad31975171deef3adb0f8d92b2d3a8bef6ecbe0b8e90470b3938d00000000000000000000000000000000012a040a72ab035684bfdf57bf473ff59cd1ee01ec949dcc6066e5c8afad775ed55123859cdd74c7016a092bade7f991b571175eb91888222085fc2dfe0f4401ed6a1fc5df86c0c6b8e44fba6454305bf000000000000000000000000000000000317ca8fdec8c7c56fa3812157f9ca8e9bbf91013dfc7052c0795a04a1b4649b2147d9cb1a61f2c114a705e5133729920000000000000000000000000000000012b893d50fe5ea2eb528d1a04bc8596b10d4714a0dc38bdd5f0a275c07c846970106c3f7b5686685f5c809e93c57e2ff0000000000000000000000000000000014f018a0d13c4c494f4a6b7e836f0f2f46c4b7975d91adb93616a0555910f53574add03b905000f8492465c9b5488c1300000000000000000000000000000000146eb4ef1103b525dfb5c31bcb98e550245732fa252a814824258093a2397d1489df8ca0228d4f5df0a00d473d1566c454c9e7f7ca14c66b8431e25e6eddb4f20507d03bf124eb607957ca2f43a0c17b0000000000000000000000000000000010e9962dc19aae8e92abf32fb9c8eac44d77f587159af4e3b3a080748322715a958d953d3c057999839a47dcc840076a000000000000000000000000000000000ccafa9761e654ba54a46afff51384f1c6331264082e23f94fffd6c31a1b1b568a391eac79417657f40ce2fc9a154a670000000000000000000000000000000007276b111c94130b2608827156021815faf2be29ae42c454f3e2f95de98d2f5b98cea3eb18335a8fa00e5464f8089cf300000000000000000000000000000000053550896e867e237086098f4493caa2520e8c97a05e14d0ab7012d37b7fbbd42a90accbf0fe2ac99e78ccf0be5c9c58000579e1ad83015c8f02a9db5c38d0220368a80b309ee45bb952cac824817b6b0000000000000000000000000000000016b5bca8537059362147911da9e69ad3ecd3b4a7c43ee7d6d809f46c74c16bc7d69bfb5d7c727b4d5d8a356a0458b59e0000000000000000000000000000000010f3a7eefeb3033a733af7d20c3c5caff4c409305de8d71e08cb9cefbdfacda41bb975c92c5e5f2952c3c1e2bc6ca8cc00000000000000000000000000000000148f5b2bd65b71184ba6974678f709c5f9e3f1a020e3d4bedfa5f5f66478adac47f06ca2626c4a759b5eae09756cfe49000000000000000000000000000000001301306d1259059b5567154ef6e4779fedf98c29ea967ce34b78147c5730f202e1c12d5b5094219bf85fa62834329b45909a45c8b78350e3ca21697e9f56d5fc8fc2a01817b78a7f5daeda487768ed1e000000000000000000000000000000001741f739459f5d462fc9ab55c68101a5a3f2741c05b4c3eec6959b2aa5e12493a19d1b33a9aa89337add642458089eb6000000000000000000000000000000000300d8b7988522706c0690da52d0a67ae41344e43cfa05d22feb91eb8635bdb970810e993e0ebf8fd63ab8fe3e048d660000000000000000000000000000000007c003cfba125692b88feba85e7288bf61bb25e04b1462f7a39b4198737010224ce4b73a320c81b1f70119af34d381d1000000000000000000000000000000000a4870c9de67517f4353de23af21fcfadcfce55365ced33a61a19e5de52f98721b17c6eb382970e7c4acd81b80a7bd2f6d4e2277da617f0ad530b6209df6264e1288122b1b4d92da04fe334be17bd8320000000000000000000000000000000002eef52fc72d5aa0456c13808ba548cb765e11cd0bfd0599544793f57c8a27ee90880e6577af1b76b3fe32c4e71f4104000000000000000000000000000000000ea99a4f6772f8114cfb3ae9dc20f11a34880a86088511e5b7fe521d50470148b43f866eb5bf4f67c523266bb55117050000000000000000000000000000000004bd802b889e6d18df7dbd65f39a908cf5889e14be51b5ebd423ccb63e4e5b35e429eb0d4f384b811b47975143ea2ef60000000000000000000000000000000018dded357c546d709beffff2da0c08e8059c720023234c7b53d0ae85750b3e166cde7faf340697b546b8dd7c13b1ce7bdcba6bed6b8c42240c01df5fa0ea81dd96168c6d98ee9d5d4653edfa5172eb28000000000000000000000000000000001405ef521bcc60c55f8551fb2e2aa7b10117b2f96c03e8535e5bff48ae197b7e5fe69a40eecd25a67f430ca02edcc9d2000000000000000000000000000000000477d85a7dfffcc5a2a1048205362ec42b268e5fbd27ee7c8d4ca77b5c9db84dba482bc4b164f92db2c15cc518b3d32800000000000000000000000000000000060988548ede00aad3682fe827d1e993ed1cf118bec7cbe6f69bc160f030bf87c299d40047a4fb5ee27dc2814649a4580000000000000000000000000000000006b9e0579f82fcb8bc149e40b1199f5897ea48ae5eb58abd2002c923efd0f5275d24a579bd904e49b7447c4a03e3fbe423d168e01657e5c2da89a27e513bcbc6620b8c6082bd39880619bfe2b3a7317d0000000000000000000000000000000003cde2bfc5a865cac624d9018c37c1b5746b5394597d79c171b25f84d5fdbc76bb90ba5cf9db14b3b8e62ff91cfd79520000000000000000000000000000000017596885262075e45db62ca68ee5b99d12223bd476e36ed4ddbf5cd56a0c6e9db5d79e7f95b96b1bc323d7c9fc5447d800000000000000000000000000000000018333858871dd41cddb7ad2f179f1f341b2ef20bfc7a1d3cb235e3a1a181e0da7251911886f0788e0f868e16520c5a200000000000000000000000000000000098ce44092980cb14e89faa7efc2906051c9a51cf7b2757dbffa49fafa3a9ba145f809f1212c27aa620bf062e839f83c2a76fafc5e8e33852bbeb7ab8229305be84f5474427e0c6d2ed35c7bfe99faa1000000000000000000000000000000001180d554fd523a51e0decb92e0134c6064a17dd3aa7b11d590b9b6022f76763b1e20562da21e836e65374efafd78b77e000000000000000000000000000000000488686f793dde899a3f4936f07f9eda7918450966ca85b4715d6fee978d9d091bae1b5d2d04943365c076a849b3359c0000000000000000000000000000000014661fb2d305ec9e63d63e9951d0f081aeba99972b094c922d2797a1100759cfe150812821411205f563e22f01ef29c50000000000000000000000000000000013dd681200608466853cd3bfd20f146a6383151931079654962684d6c6fc3bd6900bb049483c1ca6d2819da456f67e3be3c7e4e95167faed1391e269785918a207490c6d186bf2537c02e52e414d564e0000000000000000000000000000000016c8c7a2a1a76ec05770f2d6c8df35003104c034c76323fedd49663daa759caf2f4fefbe8d44b3abf1dadfec2a06cb45000000000000000000000000000000000837305004aba2e322ae29e8f0109f1c756a44b21c72733019e63ff9886a639464090770d12d35553f0002ad028332370000000000000000000000000000000005c8f82ca2d4f6785e2d76ca3a3d1ac67aedf78e9ac833c52cfda6289e6f5d7a83befbeaf753abce12376889caec312f0000000000000000000000000000000013595cdc9181ca70845c613663367ff774f073774688dc58edfd0c58de5ae12df5acd04a673b645371940d7f7e1601045d335e3d96a9b25be7f3916e92fffd75abeef5b91a1ec577ced52a96f6a9b10c0000000000000000000000000000000010f1b8b39ea8ffcb6a96bacd1c00b413c93d3f8da64dcf9257a7cf0264831be23ca63ab8d3d1cea21ed8d83ecaa3a0c70000000000000000000000000000000017a9030fbee573cb71330007900723f85e9e82530283f713f72e68c1d9a5ff9552d0da469a4f38b66e30df1514f922a40000000000000000000000000000000018b9020986a49213d4f3b4b052cf2fb65f82b9bc2051f20b399f2784b984ccfa2752ca576d352c7d65ab218bb8d5df870000000000000000000000000000000015a375a3711f5e9f85ad7266b2d307cac09ace9ea36e149dde5e0d5acdbac3f62e1cecba8be51d88f2143c3070eddaf0fa563a70780837ffcf9a84456f0b4f6eda0d60cce6a8538ba10960eaf17362fc", "Expected": "000000000000000000000000000000000b668f602b9f56182b74be413d36b03d2266d7165386a7f1f0d25d336d06d2bc5659e80e54dc71f153883292df1cd8940000000000000000000000000000000013151d305bba39734538fe9a2717392bcd134ef1f8c1879740c8cce981a2d70c94b23f1a71a0596e7ead55a55eb186c80000000000000000000000000000000000e5e7c268f93d8a9d3ce45db2a95be906483aefa3831ed2ab2aa357eca0ca231927c0e5031daa200784cba33b96e51d0000000000000000000000000000000011d57d9a9123123f9fb56e990626346e5c76bbd1a4b3349c3f7bc44f05a899f9c4dddd67ce5a788f85b4fb172385faef", "Name": "matter_g2_multiexp_49", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006a7946b50749147573991c91f13cdef4e9558be37736e3d990c5750d31ba9711721b88eec529ea4b1dec1c935fafa9a00000000000000000000000000000000078d8a565b7f58b915c220882a73b6aaf100f2d54cce2524cc3a80d9b526c3058903668d17427a617ea045c3322ec502000000000000000000000000000000000733c6562cdcb28d740c64f50ee9d204af4ecc8de2c1719fb73c20f2580fcf01e1e494faf4386764e03920a4162049fb000000000000000000000000000000000421365fa828affe963d145d318065933d4d865f2a3d24469ab0db66dd09a574945f8a8b622d079a7ce1c6fb6c795a8f6e2ee781da12b984e7a08730a60f50c41cdd7c7c8b3f1f30f721923ddc34fb79000000000000000000000000000000000a4fdc68bda287bd819ebb0a296212ddd19cc76b042e134f1637c894ad64bcd8431392c9791f2eaaf94f6c8d189846760000000000000000000000000000000009d974fcb46fe81d81d62b24b805ab5108c9450e162454c3260ecd0d5356b7c263be5f78f6214cc7254e461166910d23000000000000000000000000000000001081fe3579cb4d8a7e7d43ca8cdda28e1f9ea8df83c6069f4162a2a0e68e0d5876b283193649018e754c5c8fef101f53000000000000000000000000000000000ca4faaddc4d14a6648e3515a8b9028190c17f771c7de086fe4624a3008d7e6e374c967f303d9511b9da1a95409e3cb3d51e0b65be993ddd2892ab8f47eab78352b177be4b3fb68f47c65f5c59fa866000000000000000000000000000000000117318e376f2c130e5bca89b3d700fe76e9603adb22a5ef353bb3b5a8f641c85deb4640fbaccf94e025a59fbf2a41370000000000000000000000000000000000433428497ed89a43ba07d816df224809a827194ca899924c3844650a3800952cda8db82f2f8e513994ed9893fac747400000000000000000000000000000000064889f1cb7d6ab216fcceef7c4abf89be14ef93be2d39bbba2b74d06999dec5ae1941b507709d093b28e030700cf866000000000000000000000000000000000957fcb8658497802e78b8250373f77acc4ec47fa2c87e78adbb2daef70240da640a7945895940f76bbb80bd36b4ba24fed4dd284df98923bfc3c41496d6e64a10815a8c474275e0cdbc9ed26e92b0ae0000000000000000000000000000000013f9771c105462fb6b975b0b2fd20d0accdd2d95d879c8019b08db394cd785ed9f151d0eb1adeaa63bbc2686d1172b0f0000000000000000000000000000000002062a5f2db0a01114a1c6e8c739f80f598f4e905952101a244853078298eb443be6839b59d4f0c7745b739cc89ad8220000000000000000000000000000000015b5485439f1b94fbb3a8f5ac6197f0dc0577863f39c44b34d4c5437b6a82a704dec17529654b3037a9ee1ebf14c8d8300000000000000000000000000000000154d750e2a660205812d428cfe79aef4e1059f4e231024a665889d112af37e6e17e04cd7c926b6240bf2f616a1f572dd7c36ec97c1eafc8a20a772fb7887d75568047ea32458b9ce74ad9ca058129949000000000000000000000000000000000231223930956bd2d36a89a0a0a47aa46b4763919455ad3a3581439d25a82c176569698fd5ca2b9429793ebb16c98e50000000000000000000000000000000000b5dd675af51c18d2dc76e3103da4409f6e8c1cc719a622d4a33aaae3f23e529c78b63c55b67fa999bdcc7095a4ece300000000000000000000000000000000010c971be55cd02e4c97031d3b25acfbf722e47e5179beb26eafaa72d4bd5f47cf280a99e0c3c4cdac05bf1572d01fcfc0000000000000000000000000000000002c1370919e6445994df1e25ff4a79c8cd8805f12e5d8c781e58f04dff68a97424b35d162d875ca2b3f805b4cd6d1fa641b2c0354d2f7d92b05043f193b718d78b457ae76e19069c8e1c2b77d7999d6500000000000000000000000000000000169938b4d3c859f97a0627bd1a83fde725eafb7ab77b22cae06d2a776569236d834702081e78d61386999c938c0259b900000000000000000000000000000000091e922f00828488e324f9fea652ce1edff83d9f479e843ed4bffee27805a5025e7a150719b354b5e61f381ebd24d4ea000000000000000000000000000000000334ba8044d7d47795b59eb089502808a7ab8f18e3d5e1cc49acdb5020b3973fd21d6d82557afd748dad88e45a7623730000000000000000000000000000000002299bf949ef249b5057c103ecd149444635b4f636a2fd0d073484404c1ff4ef71820260ea6529bee6f5b07f2ba94de35615370a76bb0a5f64d61b97bdb045b9669f6a0b7644b101d21a50483d8b04dc00000000000000000000000000000000076ab7838db87727fd653a3b561a2a5594518f296284bc24a7d215b1fbc0a6492d425078fd98f92a414dfcb3c92cc1d000000000000000000000000000000000022b71fb467dbd6d9b130763350bd06f52d20ff2cbd46cdea5e8b1525fd73bfd08f5ff171f9fa28050e9a3b296d3e9e00000000000000000000000000000000007e917cef0195fc589317d4a71c14022867dbc0db26c653052e2e382d0dbebe67a0f582bc0a27dd1dfb4703c545d0da30000000000000000000000000000000005b1d8651b86a403ad993c5cea4b6b82a0f8a9f8a59d4b94f10e68e9538a559efdde2007736aa9d04f585851a89af88fbcc38cfd3c6bdd32ed1d583f2bd14e175d61448c627f195559b751aab1ecf7cb000000000000000000000000000000000653c5f5b2d97239821d173036929dc716e78d835a80af55868dcc3e218bcebdc2a052d31f6a573572d13f3bbb14f241000000000000000000000000000000000cdbdc3cf52239a6d4bdadc273b00924de8730c03ea82bd20ec1f04375daa4497fff3a1726269a736706355e72be83870000000000000000000000000000000008e0285b177fcd768d3519062177fa1314c4370f872eaf10f3e0dc94e716dc6a67894d887f40104552336cbb5ed614f20000000000000000000000000000000000638db8269ea4c2fecd5b45955609ef6a1c2c6faf6ee5a8d777e0b38f16d1acab2da7fe7b6f6ebb315ccb345835a21d94c41471a2e4edf0f688c2f032036d41ef5f8a966871dd099dcdbced8b37e1c40000000000000000000000000000000005b4f74cd099eafa6ae59e7105873d4a46e8e5985faf2d26ca564125dca93b1c48187ed7afa02cde8b52df878e1aa618000000000000000000000000000000000cda7f9eeadda16ef757ee8a98be147d374d3a1d40790d20a1ae42c9ed38e4fe22be76ec4f807cf93fff5c6efdb50d1c00000000000000000000000000000000121219b0b0d236a89a857c02249cc04c22299d041d95296dd235b3639416337f5be4a2ebe92a50d192fb748d5d4dca0300000000000000000000000000000000112545a4677ca7d60645cb8bd98689c4aa85a68bb62dc68c0affca5a17ecf0a08fb9b91589d08712b5af4aadf31caad2dd297b192f1c907914ef949fd27a5ea5659aab659b83239c4433f7a4e24529f2000000000000000000000000000000001342460712b73ca0ef07d953c32d280a3441e108abdc2d133265160608986481df3563c5dca20f209ce078b13b49707e0000000000000000000000000000000003580a5b4a7f6d6e066ad9073f7105f6cc1ff35ef5e79a0aba7f48ff2b732c7aec72cc9c5f9233fc9c267d8aa37ac17c000000000000000000000000000000000bb7f32db8a4e341cd9f8dd3b5677dc650cef675f0923bf2e5c8b84c33d447daacbf68631c2388eac5698495e1ad5a3a0000000000000000000000000000000015bf9cd1aa585eda2910128f2b452569abc1c94bc8bd308ee92b6c7315a56fc92d6cba03334bc36c137c14eb1f198b07d30fdb174a3f5c06b78cbaee5b6e7a4c90551083d78c5164de6bb45ee5de23c100000000000000000000000000000000091bca266255d692cdfd10929802d79b474706d160033495decd11cb0758136ec3ae7fd4bb99081e44dd7f25224e009c0000000000000000000000000000000001fbba1ba796416ac22c92f3741e3b268d89fbf0307edf0f25c7c12b5cd230c41582ba69465686ffead9f8363dc0c297000000000000000000000000000000001139590315fc4d81e3e747a53e63ad856635050367ffc143c1422e324d5fe9e4fb90631ff8bba764a87b8077b571aa0a000000000000000000000000000000000dcbba28afd445a57db762d08338a26980b4efbd11668e4050d18234ce35a909d6b563a5d3e8e72892514431fabf0147aafc42f7fe6854866cb954367fa65c8072bd1b60173a2d45077421d6e25f2bb3000000000000000000000000000000001322b1f1388a9dd2853829bda1a5120250ed08f07c84fa398e59fa2577454f38f0a76a1e8db897bf15b4b50ff52a847c0000000000000000000000000000000017020d7de1dd424de53992c168d924c42f26231d184ea3cd9cfe64ad9c82ad067540b2d9ab18b0fd28477ac792a80c4a0000000000000000000000000000000000fabc0769b95e6feedc2165bd6d324b7d16247b79eebc1f09d849792255136538e628bd6ad9b86af7bcdfdd991fc31000000000000000000000000000000000144f39f792bf5585f4b49dcd3fcdbb61cc7ef471e08af4c15cfebb855f0ac8d5fd057c9486e53e8e1ee4f66bd5e943ad106da5f98d5e7cd9f4a1c8d6e50ea2236c2abdf1e08a0eca54555a59bcadbc6a000000000000000000000000000000000c27ac29db98fe3038fe5f537d5ca6faa240602abe11c6f530d9b18d763d6dda3fb25f9538d316e6527c114405ae54f00000000000000000000000000000000017ecc872183413d8065a99a2d1a73b70150e2c1fca2c13a731a39b52aebc6db79772e91f115a63f7b23e5fa231df697a0000000000000000000000000000000016b9715ce820b619274202b52d7e7bee9a17aaeb06c2ecab8bc77c670bd4c714789e4478178d94d2aad57e7bb0b7a4040000000000000000000000000000000002d0723a3386248d8597d2b63289300de6a16011a38985170a1652ff81ea70a78459b3ef252cc5ed26ff1ef1ecaf6a42c971deeba2f757970bcd4f5548a2767bd6c43e63f4c5fc4b157ef060a1f45aae000000000000000000000000000000000eb1ddb7306d8d2858fb57dac71f67473b813f37f02d73b17f375be86028176cc1dd84347f183cb7d427b861be34c3d70000000000000000000000000000000009a8811ec77eb21f2b33a591f2fe6d7b74b40c5045ceeee275912aeec664838f332bb49bedcd958ede0af0d0232e76ed00000000000000000000000000000000156e28ee3c40c6f18c6059e06ac8f7b39fa23e5962f640ef3afce13c169346a4c8e5c2bcdac8fa15921a4740cc5a0f2300000000000000000000000000000000084371522a6ebb1925c8fad3f20277c34e657aa71abf8ed7d323a10c14cbbb1a9e0e54bace32eb845e6709c1c58afc34a5262a021977dd79ab96606eb24a7c5ed650300dd68bc79f4b8378f58c6eed49000000000000000000000000000000000be2ef9ef38a5dcb42ad31b1415c8eceae625850db4306a26a0598d4a567936d75b701c81793fa7b42d158df2dcb0d5d000000000000000000000000000000000851b82b59fc15b89e33fb618c56d11a07116ea35850583a07066ed97b8a864f3766c0cf921d007a6cb43931ad4fcf8e000000000000000000000000000000000ea8bdfa3c5f000d7cb1b5cd69537e4104daa15ffcec06f40a91b972d8011e5fccfa911c55a07383cce6760c145c39e4000000000000000000000000000000000652a4165602978004ef702103ef18e8fe7decab1522a76486c742d29103e3bdf6dda2d3cd64ff1b5d5a76f4823bd363083b3720c20044fa41712039b6e9e776197391ef393c0935a0e9990fbc1b7a4600000000000000000000000000000000015ce5b43e1fd950b77e2baccae8c99b82f38bce09989fdc5d402420e7931a38b7fdac5a254b0cb9bd8fbb488d02493b00000000000000000000000000000000018c5b3ff46a04ed114bbf56399738e5d594ef8dd1d5e2e8dc23a0097893be3da4fa4662686a6dac04418fd2d344e36c000000000000000000000000000000000efa3e970a5cd0c7bdef6a2df3be9be18cce63c10c331a18d628bbeef30488ef73d866f3c8804acb3bd375542e99eae6000000000000000000000000000000000e966d9e2f2d47df5d661a89fafb6d4518fa1544ab7a56716df511cbcca99098f944a981c9da569cf95debb455842006d6f846581848f5dbb9e8d220b881d0327c4f3f5d4b79fb2c4dcbdb9bcf44b02d", "Expected": "000000000000000000000000000000000ef06b515addb951b24e5d61f6e6eededf5f93f9f17455e1b563f187f73394457b3b7c1b90ed454218f8782d2bc848be00000000000000000000000000000000167398608a87490fd17506166bf54636aa4dd6d3e8c4d42995bcb0262268eaf2a6d828b295434f45e3e53703aa67cdcf000000000000000000000000000000001602ec6519e4987a052f97eb222f505e241d99602c08ea9c41bc95796675ebf6a819aa0bf87319f29dfe47f45f3c8c7a0000000000000000000000000000000002ad4291ece7ea0fcc9f4440e88eef693b8dd53060ec847bd27d74cf71218eb6210a71895ff1f1f4537a901090f14de5", "Name": "matter_g2_multiexp_50", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000129cc9cf82aa30671e969148f058a0b8d275bcbb1c8da66e52998d9555dfaa075e2fcf39fc18f305940fbc972cc5c0c0000000000000000000000000000000001252482c1419ad72229a00d90f1c09d464e896f47db91e9680efe36822e99e1ca7a2b5ba8b17b5929fdbeff8993bb18e000000000000000000000000000000001287d5054bf5db038ec2f7b7a3b79848fcc8ca42f9e19d5e21d36d2256f97e0edc2608d19c17d3714024e1e9e86ae264000000000000000000000000000000000f6262669e30a5db67550cdce8a4611b9501d02cd4e950aeedd1c87c4f0f63c74f35c802dafcf91c988a154dd690103c67c44f7c8513472b51f96d526422bac628aad4c40c521cd7cf9e86eaf92838fd0000000000000000000000000000000019cccd010df3e668b1c3ec053e76c46e45d01a4fe02eb074e296df2a48e0e4eb647b06c40cf64a0048a8fcc2b0cfa6100000000000000000000000000000000018e07bc50657f3bbf736c38518933e91af29e3bafd776243296cca3a1d975116e8b428b050045a61069adb23baa22d3800000000000000000000000000000000154f51badda1b828346986264b01fb1be4c7e9b570ab63a5eb15cabe9412a2f9bbc6d5111c638ff5118a4f6d08ed055200000000000000000000000000000000064d4e607a8994c0bb65770a14a14ed1b68c766ac2aed45a44c0f7c7cd4c3ecdfa077206812cf9b24e35021060a3668d2d6f95d4b6216e4226f78e4fa5011c9becf98fe45a17dfd740fdd0ef36d8ba94000000000000000000000000000000000b9bae5f720d9bd3271a71d751e4c35c39ad30fa8a67846107ff769c455e42465b2a39dfa32861634d5e323878f56f4f000000000000000000000000000000000a1077046cf5c7a66452cec2193ee21c1ace50dfd79f707c9297737f13806dc05e9e1cc5d1fb4c87b250ebea5a4ca6c40000000000000000000000000000000013e1fbe1a9b5f2ccff51120590ac0cb00cab502726b43a6fc12459e27bad4aa41537d6f3cc94a81a170998768f6a0fc6000000000000000000000000000000000a02c551ecec1c7a415256caaec1b5485a42f9ca8d897cf26546ace1f2bc8c2d10a353b8b84495b8dab5e3c60881185a58c25d36216b811ee42d0ba629ab7a0f9ce7edd7234620c28e37bb3df3f042e700000000000000000000000000000000021b9ab3ad614816d7006efe688e1ae8cd99b0c4437d4363e557642a7cfda2000db6503b32db36b6d1ffe40d967c5efd000000000000000000000000000000000b7fb0ddd9eb2be9cdffaf8f8c593a9296c4c7deeb1c714c11863d71dab1e6fd309b75c41e25de3cb6089726b43427f0000000000000000000000000000000001277065ea9d208777d0fb7a6726e11c8330f0b3ed3c6716acd559aab19b2fdafceca8126c9facc43b9d80534c07035a20000000000000000000000000000000015e8c12065d601dd5ede75bcfceb7300bf6f9fbcdf68d2f093b7654d80d3e565135d64137dc401d691a45fe052f58a6850a5c6bb6b87fbe5ebfb0d182d425ee173973c6f2085c556b0fe60219b9f3c32000000000000000000000000000000000484c4f9652427d0649c33e93d666dcb15bc56669c00980c53357ecee874bcdbaa016236df65a4339dfbd44e4eb0823c0000000000000000000000000000000013836a7275c29c989891c94e756cee9d6c54a8f634fa570655ee44b7c1e34137edc33323dc0d1f3a0218039fd6f7013d0000000000000000000000000000000002e88c7d5fd87e97a0de1be95021821942a8004115fb4fdd9ad26b7e0fd171f9c7e6f962eb179bdb95ef960cf9396372000000000000000000000000000000001636e351a0ed1a260ffe0d1355e6da288792fc97a7310b040cb9fcd5c550d85d90572154d58a9847dd5a8a06456bb2e43b4bdeaf6643ed159f4a3e23c33ac486b33e1edbc5a097a47a6c2c753e5299d20000000000000000000000000000000007579785c14fa012cb5d6c116d34dcc15dfc908a29e90de3bbfb8c9b44e0b4258644440d7c78d751a007c10f98053bd10000000000000000000000000000000009f023538822ceba0883a0e3454121dafe8e5e61d4754b54e6417c989efa998334641d458591b3076b615937de065cfd00000000000000000000000000000000130fe7f2d5e0ffefa67ad3378690c53a6e68de5504f3691de0df3a24c309619bd3a345bc2bec4dcfb4b77255cbfe09980000000000000000000000000000000015bf85ed997eef4d97a81f1d75825bb4409cf86b8c8e5f4368cf1e4c803f9e1e23a2a96f7b0a08e5cff55a78761ebce21d18596bc392dd0b71e1216bbb20a0e5e2559a46789c36a146cb78c5aa8e3921000000000000000000000000000000000a95597e4402bbd17c20dda088f0134d42f14443bd519b3511b28fd8d395a0e50758386498388ea6ad0e7634587336c1000000000000000000000000000000000079f348d3de505875c5192f795cd77e2f7385ed447b06f2dbee18e85c832386b201cb3eeb21aac3f258d2c4b0434d48000000000000000000000000000000001895b1891a08ea42eb1f68698abc20394ffd66bf0c32979668950bfec5cfc8425314eec2ac17ba25f29133a8becc9f5e00000000000000000000000000000000146160336d881b24c6258a3a86c08d346900680324632b6d5d4582ee0865a7e5f2d01677e5e49c5a4179f8382e49d1566fb3669c0789ba6a5b00f14c14fe2edd15d37a742c9e36cae9ac010e632d75a40000000000000000000000000000000013cadc6c394efb2f93e00f3976dde34efe75adff34bfb6f5e1a150b79bb5baf6bf29fa149581fda48faa68653cb61e300000000000000000000000000000000005fd25362d87f9581a202b186d2786d2859faa9966a1ceae747dd7a48749abd424eb9813e44caada0e456ee8bd12e99c0000000000000000000000000000000018e6b279e2b545acf1da29dc0504caa5982522546f83d4d3389e1fd6cb5328d4a167926a00ccaca402b3a3cdc67d757400000000000000000000000000000000089a9992a36b476fee21abd50977dfee01d7c91b24b3e26d7c15b2301352069dad920f0ea93a3e477a48029eef35605f06c2988dd6b8e9aa116eea4e1f63dacf100019844d37d163c047567e8e1188620000000000000000000000000000000005200b78dba7e423bc23e87c5937b464e97405f6461d05bd9d1d0fbf8f3c8e64a39081f9e43b4ec416198dc44db897e7000000000000000000000000000000000bdba1ed07c4a570359863a1098a73830818b3fa5b222316a3e0692a4ec65e59ca6b4bf5f72f8c1384e73e807d272d6e00000000000000000000000000000000073fa3eef473707b6aff37fb6f829f0fdb7ae808e85ebba4d4924a185c3656eb2856896307b671080347cebc32e958bf00000000000000000000000000000000076b56330f07cfc0ab34e98e2fa0ce4702b296a00f6ffee07c3ab523fadc048a047ccea7a9003c090951e4ef698d14e5fbf8322f706b1972f73fe4e22a3dad29c4ede09163561b2810cfc3eb2ffbc7ab0000000000000000000000000000000007252747c8275f87b21bbac4071c1826d166d14e6205095e5299315d6b6a85aed995f9ba59a2163ce2c51a8e60eaaeeb000000000000000000000000000000000460a000fe29cca24dec469ba5fb729edf3e443bb032d488cc99102a614a5251915267db003dbf395132d815ba78f262000000000000000000000000000000000161c01cb4d0942faf2303c108604babbd4cabf5d3d30c13d7db9428a445c7f72d96a7405e22e4e451058a94e20068720000000000000000000000000000000010ccf8a8ec4e6515b20e07057fb8cbecc5defb87480f3e32a1bcd0cfe239e00daf6a390c4815ef6b85be1f07a4c4bfbc4a46618381ba6b991b2edfdeafa67aef1cfea066fbffdba24db25385963326bf000000000000000000000000000000000e6cf781162502d2a758d0f96946bab887591b7c9ec9f67a1b0b962e74ee514e84c14bf67ae3c0a9ea2a3e472b7ef59c0000000000000000000000000000000001542b4e97f1e8a64ffd51ca43137b0660f897f6b3d5c6fee598fc4dd03932c3658ea55e1e9e73376e51df278ddd3a3f0000000000000000000000000000000016dae882ba240343e752eac68122424320d1acb1fbc4bd26c3983dd91325f25e1b1f06213e0e06c142997a13fbeca597000000000000000000000000000000001138b71c95d4de320f02e68dae9bb0de3e5b317cb596532c5cc18ca588cc8566c21551d7d55d685591126b9d9e466455cd05fce871e4ff11e7a4e834061c65a0aab7bfa8a0128d460a493337c6e63ebf000000000000000000000000000000000904f6a09f3a5f5baac902c702b059835737c06f62c2ffe9101bac32f854e4d72f74031f5410a5941612b1aaacbb50920000000000000000000000000000000012f39e7022150b2be12cdd621ae23525581405021b21cb9e55972724a22b1aeb2e15b135ceade132d3310e050e607f65000000000000000000000000000000000a92b1daaf23524904d74c3f149fcd2c98e3a4c257113533e7cc59c4656b785aacbf0ba6b9df0dc17cf7c25f1ca698c5000000000000000000000000000000000a20a5d7c0aeb16ff498f46bf05e512784d120b9c3c8b2877411852d7da3abde9e83a6d00213bf69ed88bcbb051a486daba9e37ae0dbb733af820743d8e307fc02a3ce9b40032b16d0e9466903de9caa00000000000000000000000000000000153918807d7da07ec7014154f00a558ebe0d5fb48fba4c16488d61a826a1eec28e3828d6744300c04207e8ff1cb61211000000000000000000000000000000000a755480457896c5a3fde35658e73fae821151c43fb92e9ffedcb05fabad37cb68aa24e029fc33a2518398d723c4859100000000000000000000000000000000148798bdc5b14b90aefc38946db93be1754f15d78762f38971b1e64a53fda92b96b0a70ca2548baec882887ae7f636910000000000000000000000000000000012299fc413dbaa77cf8867e331bc0602c4fb32fe44a150217de9e6391374a9ed83781034e5775c4933e13cdfffd25a9e6ef151662cba4952416eaadebfe5e0fa0ca1d31380e1540c2d5e0181af9e317c000000000000000000000000000000000fdfcbcce1603198fa344487d2d4838b3ff23fc0a73a76222707d9f8623f0b87dfc816be8717b0b12667bee460ef40f70000000000000000000000000000000015036dff68139419db619912e2d19b7d2a2d637fbb8bffcd941aefe2eb4d24c1f7dc32f4f53d4cfce67785e7c328d6c4000000000000000000000000000000000fd575be9bf54128a9a1cbd366339c993ced315a840d60f8b77e035352bf705c01a9def713e8cae3001dc1062cc0723b0000000000000000000000000000000004015ed456125cf0f46fe0093b81ff9315d955d470ad756a9303f548819f339e137305c58e6f4d8db3c8bbfab90718d4f0a3851bd52ca52919dfd21efa6efc56f6dd5060ad969360b1a731e8f38f0f5d0000000000000000000000000000000016d31e68cfdc5823970c8c2ebc53c3d4517792c44e90c10f920a819e72e4a6966c59a691b905c8b0b612065c56d86ca40000000000000000000000000000000005096d516e416fdc0df552c2688c74f1c067a3e5e7fd782479bfa468096e6ee3e601bc23d2e38ae7500325765483250600000000000000000000000000000000092c994e9dae287bb6450607a4263bcf6267f0f66ba3e63436292af7f6bc8e4ba794a12792b6af49ef59b5fe50ff6d3400000000000000000000000000000000175a645988f33612e969e1d91b2c30e47ec655ad655d89cd8dac151c3bd194cd5a8c28b498b1cc2f2966b7fc37cfc8c532b41960417047a2258b6e9e228f3cc1130b296cafbb75f58731a81fcfe8c83a0000000000000000000000000000000008d09ee15c80facf7e32b15418fefbf7e80400acf37f2a1bc6ced88b1591bcb8f86b45b544646c5fafa71b5b103b927400000000000000000000000000000000060865ba68ed8fb3d0a05779c278352b22d4244edb7add23d985a2836d2772dbffc3c82c3134916e9b0900c9db6ead8f000000000000000000000000000000000dce53bf8aca1ed44bee47096dd988689c1e32e1e65a5f8dbabab7c4edba866132ee2c036aba5648d0dafa9a26405fe30000000000000000000000000000000003319995785be720860bbf48692d1507185d898187993865648ded74d3aaca45df939c6dd986db42a51bd13579a55b8f71a6f7f091a6a21dbfffcec2eecaa22d05252b60bf91b56811a833dde3fcfde6", "Expected": "0000000000000000000000000000000010643af30c3cdefc30144c5d7cab17c9c54adccb3294ae79fe5c69376011c159be1e43940640bf5d9012ccdbc997e2090000000000000000000000000000000002a22b08904ea9ca99103a01caad745dc2afb7b6d23e666770e81a97031de921f9d4d1c04fa941c433b8cd9cafced3a10000000000000000000000000000000010808e5518eb6cd61eec8820b9f279dba2423b1a3677e21fe3a0ca2ad49fbab2995de1c5adc9ac867de79e3b40ffddf30000000000000000000000000000000003ce1270644d71e0055345c7463d72dc119495bfa04a818dd398d944ca46deb0aee8c7936557754fa18225522fb79564", "Name": "matter_g2_multiexp_51", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000059234bb6d1b66985b79e6a2c6cd158d37fc50ccd6e50ad2fe3b6a02ae2ad35b8b2be92139265957ea698441e780532100000000000000000000000000000000066adc7083a7f3dd75a8e431a36632dfcecc2527f261e961335bbe8fc8329d992880736bb41fffe41484f68c38fda61a0000000000000000000000000000000006aa0794c27d3f60debbee292c28b430c159cb2874b9467312cb857a8777058580f8a2d3b9bf4b8b732edb185cca6ac10000000000000000000000000000000000d81f222ed6acdf29437adf26d2b785535cd6d61b329df98be04114c3ae68bc6854e275792fd48de3eedf6ba7f3849a2e56b63fc6ba87cf021c2f92baec248756ddae0a4f070df840db281283a4c9b20000000000000000000000000000000013dab8066757b8bcce2c9965e600c31b792463623cd5561f7f6d55c5a52c22efcbe48b8684fc2dca87e2945765bf565600000000000000000000000000000000198a0594b5e606b18201fe2706bddffe7bee6c583147513333230715d18295714055b984cd3ff8d1127f9420863e3a67000000000000000000000000000000000ef77ae1e991daea1fe8338cf236ba959b22df4b24f00c6c01483b6956c609b805ab89712f80892bc0160fa3775907890000000000000000000000000000000004d30f5a866a100dfe469d4d0c47872245c4cdcfb18d3ffa0de422691044b52d2b9335682dcbf67aafa9275712ae3f5512a50af55f47fdaf176d4885e4910c54428c8ef433ea0cb1d009ea77783559470000000000000000000000000000000008010bd5fb5e222618bf4f919c203dadf9a7b7597bf90e16772020614481a0963a8e8b1bd244661bd33e0d147be7663c0000000000000000000000000000000007e21f548efb869a28d6fe39b999ab7fedae9cd6cfa531fe608476ef30c8703951839476811838608dac1aaf9cd87eed0000000000000000000000000000000006cc674c464f80cacb2156fc1eb680938cb38cc166a99f72daa50f9d2c40f10ff07e447d7bd5e59b6b22f0dc407dd8df0000000000000000000000000000000010b160c58ea82bc3904302b1b4fe83d1883efe3c8f52c4e05a3d8681e604eabb1b7f533e61c51e9a172987383506e7b189a012158b3c18e19471fca6d5aba5fd004a337d49ddef5db177da187c8cf1c8000000000000000000000000000000000d4f8372d1138489913654a7567735be1eacf8c7fd497c2216bf77a94f483bd4a7daa2c8232581d6815af9898a7569b80000000000000000000000000000000013676a1f72cc2ed80fa24f70fe1c52aad9ac13ad6cad1f519649fda6ea3787d86ea164d9ac86de96436e9db4fb4aa44f0000000000000000000000000000000003f7644f7ddc9276ac36aea5c36451f3d5d6e4c508932b16d5677977108f04deace5e8cf0b3b3dee88c328b6030f3567000000000000000000000000000000001953cf03effb7de9e62937572850e9fdeecb74fb4aa655de1abdc6e065920e6d2e51ff28880f33341443b5e6652eff4827dd109f6df1d9851dae28bcb9e552c6b1e1b2dfb331aa955d3d0b6c4862253d000000000000000000000000000000000c76a5bcbd2a61172fdd53b351d143bd30d460e398c9d4b7094a604ab2c0d46d6112bd8a5483c9935f0bf6d84df04b9500000000000000000000000000000000116b15825b780c49fb24617dca620e939e2528e10c49f34971736c82cd35fd3965088595deb86eaca3d3239c6c78a84f000000000000000000000000000000000a0cdaa541dd96fefd46b303b88f1dd4d24257b910a596817f1d946873cfd60ae58a88aa687ba573832331e8fc158db50000000000000000000000000000000016259f7285de159a2c6d6d8687ed348ab97e8cf329ea5de49b6d708b6da5b806bd012ca3641c50f479d85921e20fbaefca96785c1ab66cc5c8e434f59cc1ddf76bd78b6fe660f7cf74cfb79d7f2c7f84000000000000000000000000000000000797e815a98d362e1d7e2ac1fdcb477ccdec8ecdf340d7bded36856ce30e92b661669b38ecbcfb0896b2fd75df9b734a0000000000000000000000000000000017916c559db6b4b28b798c2027e2c70ba1b940212df8a1649b9f6087120660d698bea81258e2007edd4aa7d0d535bccb00000000000000000000000000000000167170a76db0783a8c3228f8246502b15d342b019fb44a46b514f4ba2de3ac66e435941adc3d91874371561870ba87150000000000000000000000000000000010097a585eb9264ea96904d8534820be185d8d9e4b1616439a926c0ff8ceb6f2bc082e5712454690c9c05b8018a996235aabd1fba36142bd768339e091b15b7f5b4ea609b57947a7187c498bd9833c2900000000000000000000000000000000025eff57e1f37903056835d1b4133ce064c86947f35859817b2cccf1a5c3923ccca766b3e0affd20a4a6df62a45c31000000000000000000000000000000000011158fce4ade070629162b2b6cf1924696f1f7776f3d623cfa3d54c66fc17fa0299c6650b709a1472262fc0abe8d9557000000000000000000000000000000001828a65fb90dcebe25413566deacf0677a3993b39d68854b264fe7807097fbd3106ac618545d3a6a42e197c65f0d2a7100000000000000000000000000000000045eb8164b6ec874467286dc3626fad3c01be61f6a8a88e5f88797978463db648a9b8a1e1a2589364ef2879cb5f75423fbe608fefa5472c7d1611abfa402d2eddb1e54542f45d4012db8ac6d1e5016100000000000000000000000000000000011847bdf2f67b40aac3426716391da488a8f0462b68bd35a8c1c762591e2f426f48f979a646a094bce16bc99cef7fcfc00000000000000000000000000000000092d61e408120b1549fc8d2174572eb7ed3f679327cb89754f326fa72fbff79e98cf5ad9c94c14dd86135e9aacc98b98000000000000000000000000000000001440e2f4ee2ba254a780a31b02babca093a38e5a1ac09ff388080b6c60918ae5b26e1c0888ea0976527ba103b257d02d0000000000000000000000000000000019797e49808b756128866fae0d6aa7e755a1d6f07f7e6a877bee150fe9adf0cfe612350c5a0e31d68cbeed226fa56f2a28d57066cce439d8d0385f647ed5e9b29e8fd0528c1ed8455f37dcd81f4b62240000000000000000000000000000000016d723a64ee06a7a631509c6e64b1c8bbe199952da532dd92194147bce9942cb4a76f2358e6c7d263916fa36e2c0c09d0000000000000000000000000000000003d04ce655cad1d63748f6eaa9912d6474a34820986835f60c812aee9980d3ebc18d6fd856a6de9546be024b2e95126a000000000000000000000000000000000ea840bd7f76f8e944f95146cdc9692d97e6a2d7d16d4a7f054f81888472da4d60ae5faccb72d3a05781b399536ccb1e00000000000000000000000000000000155a1c43c39e9dfc6d96e01c981662900fadf1a46aa1c2fdb70bb34e94dcbe86c4f255e259c771ea8ede50b388ceb2f61208d8d328014a6b2c8b2b9edc70589cdd63d38f4e70abb41cff1b7693bf9a290000000000000000000000000000000008f189d97f7d82aad87fb71d090a5c99d94079c0b74beb3dc860d440c0f46727fc49104d671bdcbe5b9551552e18afc60000000000000000000000000000000010c4edfb64b8932a617c316820cd27d3f6ffa89b471949362762af8e10d25265b84ca2aafd3b14f33c39a4b533da60d60000000000000000000000000000000017ef3bb919b087fb6745bbf115e2929394fbc9c89f65e7d591f15da93ab785aa6828ebb6ced99d3506810647d28ed814000000000000000000000000000000001591d8213ab349017cc93f1fbe6aca6765dd33ac1f468621e2c79e30aa73bd7606a0e5ba1d97ff03e0029dbc8ab1c5f4d3a2044ed4f938c17684413625bdd281f685abea2e375bece77c03d697c82cc20000000000000000000000000000000019b3a2df3a9571b066eb451e34d8a38c0d90b6e365862bcd92ae76195956c21c59441f0cd03cc69abdf4ba069759b87f00000000000000000000000000000000082537ef7f4bba5f32db4443abc8eabceef643b0878ef83860d75ba508369a3b459cad96f1cfd872df99548f656b0f9b000000000000000000000000000000000b2fda5ba0c405c9481edd598181ed8a59a8a18462508af8c5d66988a7a58a5c9635d93b5e0ee310bd35e0091fcd4986000000000000000000000000000000000af7e15e0052576f82e36e7e2b614dd835a290e05f2ed9dad7f508b4c04e8d437e7e937a7f4c88b5e66b06e0beffc4df7fd81e27a577b5e79929614c069d6d52146a6183822d25cf1ef84d8afcc1f6b40000000000000000000000000000000017a1d5add5601010d138263b4793149a02e8f4f7cfaafb69fde7b843a51cf5f0634e26b6e5e3315420d44b0fd205230d0000000000000000000000000000000013ea863ebe1b1cfcf4164d78dbe8fc809d2b82ef3e5a2589ca1357e48dddf2696e910a90301ed910fae77a1e462a5b1000000000000000000000000000000000012b40d9f25dc5a61454ddf1fa9c38e87eee60e55938b411bff9cf2161ebd7d3fc930131a198e7e97dc90cc245164e7000000000000000000000000000000000054f19ed8e2682caeda10c252f11706e7f3b65c81e7ae0a617469babc5f3268fe5c0ce2e85d44fb6731e8ac132b97c3ac5d47ce35d4ede84a83c9860322f582ec00c872b4b035d5d340981fc29884f13000000000000000000000000000000000ef0378945ae4683666099be36de3e60b5bae9c3137b702e5e4e35afd5c1e81d033c3d6b1debf5bf36bdfc4e3af37759000000000000000000000000000000000c37074af84ff596ff2c7ff963d96968464d6c8d88b69af64ae883457d02ee9ec80720661f39019230a6531a0f2952bb000000000000000000000000000000000454e8aaa2830f07d86eac7aca1d7589fb06aed646146a1b90f4959b5caed73131ab231313b50c15213f89566ed87a3600000000000000000000000000000000143516cd7a1b8da41226cb828887a0b3314cf4f87c207d1d84e9c49f0f7e548ab99e635bd126d49fd2e4dcea98f3adf784ae256d47de2d49b1e755cb0e972f3b614f3e7ba779c65ce175ca3811021a7f0000000000000000000000000000000019384e15a8754c6d85bd298ed550a26b51b714745bf2980b4920d6e73f59e657d85d3e86baa9bcf7e971233daff99d02000000000000000000000000000000000229d233d605a1a9f060605ae366a263594d8fa2b7797358ffe4c62431b9718d155d24d80bf5af1c806f447b92fcfbab000000000000000000000000000000000bbfb66cc0c7bcf251141c540f712fe9a359d1ed36d228379a1f3791991cccb7dfe1a10d40667ca062cccd55c9e6b08d00000000000000000000000000000000150a4d7a003cb81423604c13d0c5175183ab5f459b96842939f5c4cfbb9196db4667bb4382d2d5c92b70800adf384569a09d0136d4dbb3abfabcac55db48b1ce302067f413283fc1a21744f1c16ef7b50000000000000000000000000000000016352fb8e2751f126fd0f889f2a62a85b95c50d6bda7704112e4487dc94417218b0daa1dd6b998662af2582c44b011c90000000000000000000000000000000016bf4c60eeaca103c90643fe0969c2c261e9697ddbc02279f0d5afb5c905a984ab2396db93555cc2dd5682a1525446d00000000000000000000000000000000014be742feb1215cbdcde21e974c74e23c7bbc2cbfaaace28cf1d4f2b5a77dde2f3910aea74bc200277e6fe0475208057000000000000000000000000000000000bf98dd3e3a8b13e487d8b1a35615b0c6b0f514f9b8da7d6402586f113974c8dc9561db797a96f4f8040c1765518d175650a6fba1a5eace6b455ee780ff266c324f49801832640856a80098f0eed0b7b000000000000000000000000000000000362935e552dd01b5fc5a15a76faae937d7ad086b0a67e9cd3558287274106623deb85b6410bb4e64c424d44335f3b1e00000000000000000000000000000000096f23a54cf57aa3306df0a0a4f45aecb9b09bfe83878d551a59c53e18efc5a9f177cb7fdaec1648f66cdfaebb15c61d00000000000000000000000000000000135271fbe0cc0987e82f3430eefa8e3cdcc1be4a441393bb3fac0b8e8f78dc47ba2b833d9dca4277bd60befdf33275cf000000000000000000000000000000000dc1b7512fa5f9d4ea3f4229d947f43d7dc46b7770aadbd7351b6d48d525d0144183f2c84293c63c68d5262851401ae0282cb1f8f6d6dd81e7c49176503a76837a96d7f2b084d29d11dd9c6548cf0a57", "Expected": "0000000000000000000000000000000001c11610b63eeaf9e00552a230bfee290ea49bf9c93cfea1b6f684c9b5a07f341b718a0070534e0da9e6ab1239d800830000000000000000000000000000000017e8107113714ebb1743c34d83be3acde096bfb6cf140e943ecd0831ecfcd097f58d25a45005db61551a01d9da46de10000000000000000000000000000000000c2eff6c7c25885c514aadecb8f0465a0fb4385eadffa082e8d4f497b10df2395be5e7760a87bc26772dd78701146b730000000000000000000000000000000011ad4e20f5c1518c72f75d67a897f30100dbb83365ef7729c3501c6f266d6002edcab8c8bc1f449c30ec3624cda13809", "Name": "matter_g2_multiexp_52", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010a26eda028649789d9e01232884e4e5a6b8e0b17169b9d64393e2568b09ac4d3e61a5996108655c24e76abe9e3fb7380000000000000000000000000000000015e4e36bcad524f8aac7f909fbb884e879caa735f80fe9890d7874be919ee727beb2a074984c047dac1d02b8712afa3a0000000000000000000000000000000012458946f1e853a7a45861a92d4ce707e5aebbf69edfe69190c0bb130141a10869e2a73e06785b568248d5b1f647e63e0000000000000000000000000000000004d8061f25edb5a510a2db9e1df850518156138c78ace50f4c9ce47734a0b14352f5283083a232602a070c3ce94c7bd93d7f8fbaa4225f3008649eebf42315785ccda2b9ce922170e606876881825cb90000000000000000000000000000000000baa40ea518227b007b9714ae6eb5a4e92883dc75e6328caa780bb2ffee7573dcd7e9ac47821ac449187569986bd2980000000000000000000000000000000009d43d61f070ae308c5c285915600dd9c17b7de63cfeee6fe33c9ba857b3c72e057bcb4d4ac2b492797e7d785997c18800000000000000000000000000000000185215a7fefb96b3ff9229cc3239c3ce5202a97e275ea9b1541d7bc0a2931d7e3b01942febb45c6e96e66e3605744afa00000000000000000000000000000000103ae58b8066dd62c46c14c593c768fda91b90e4840b5560c974ce69b86bd6d2c13f689b72cf9619e57c9dc8e3d3fb15e71e6cb3d4e19f4a70a4465df6eec6326f558ee1cb99aa540ad2a73c363a133900000000000000000000000000000000075585f862c0e0e031efe12f31e159f2a8b89825ce80fdf65906474f0155f397fdc666292f6a7384cab790f071335c49000000000000000000000000000000000eba3d37a5cae738ab99ed9475c2c7fbb88ff54edb8490017162dbb16c8225102158a266fd4ba7570ee6d5ff6cf3f5d400000000000000000000000000000000135a0b0a38c036919f8389eb7bdc505a375fd75d513eecf0cac134645d60fb6030a437ac6a0fbbd167b7a77a927b3b0e000000000000000000000000000000001688fabd4ad751598ca036ec5ef6d7b314980dce7d8652163e89fad01b233af64defbcf352743ec478af42587f58177dbdb2b3c3b8e91540dc2724537526fd8c0d4b85d2cc20323d71fa5a4f61b3f12a00000000000000000000000000000000062a74a9ba0e2e8d95fca478be8d18fc716243b1faf7365a55387fd7188021f53bbe780e973e7d16c9db236faff176cc000000000000000000000000000000000f949be3fcf9b38995624570fcc9e7df9964d038eca189336ec39d9e0bd05148ff7df0b48436a2cf6e249e52248ee8a40000000000000000000000000000000007472e7c366419a0cab844522c46356acdf6a12cffae941fae3d3b78e7a83f0446c945bdf7b247abccaeeaafec49026c0000000000000000000000000000000006a564e6860b97feff368fc9a349282112e591a7a6987fd10a2d4de8ae4384ce229b9db9a93445f727eeec55a6fe5a9def0c8574167a3bd3b794f057ed01865ea69c38023dbddb0afdc55dd9523ebab7000000000000000000000000000000000c073d2885eb125d3e7db48127178bea2c5bb0f09eec7081f15bc6fe6cba156914fe1b1fea6cf14a21a328d831523ec300000000000000000000000000000000010d93564b2facde13d29dac198c5f5fa314a0398f30c6fb7fc9575bc83d4e97edcc1c1d34f78728729442777718f54600000000000000000000000000000000136a4ffaacf0b4a607c677ed343c1ad41a1eca49c7c48fe73ab2f74084a07cff18f07f54a7f8ea1bfb7fa3667863bdc8000000000000000000000000000000000fb0c007a907ecdff7bfe2242097caf0c5001124d112689a74544fe4fd85be9771632e7267a1cc7e9f66d7e4bb4c954c3ccc75501428d3be8bb469ed0f2df7dec10e1d205e11a907cc30c4a76eee3cc000000000000000000000000000000000032bb9f20fdb19f578fac3008396f5dd0a70860f77f8ae7771fc6253569d47b72751cd56bd373dbc5eadf55b99578861000000000000000000000000000000000c4a4bfb5ca6f9c1bd69d7377c6da405afc3128338dfddd9aea19aec5e1e0f547e3febd28445af5e27469c87c4ac15280000000000000000000000000000000003b551547af253d07625028db4b9a8da2a857bc925620c5d561bbcd3e063eb460d9407cd4d4813800551e5d0d23a2ea40000000000000000000000000000000006d5c69a251e9a042c66bd4ee92d4f3cd4e79704b1b215c15b319e09cae0d798eb201be24f407340dbcefcf2cb87da5ae5e403f555fbc800f1342275f18a73dbb679bd31873ee87617090912a52d6a55000000000000000000000000000000000a5802e388f7605bbacd0bb65ba96689e223379214fd7a92de9a313f55d66cc71ffc9ab3f9979b75edf55647ad3b6c94000000000000000000000000000000000f86f968b5c20a81f18074803e1ec55ebd73bc87451c48d5bb61604ebae46538dcc9d21cce062abc07b4b9e89c85bf60000000000000000000000000000000000f9fceddfa8fb5bd76fb7c8986372c32ab9fae3c26e9fedae892bb55178fa2f3432e6eab5043496dcebef46b20bf5824000000000000000000000000000000000dcf7a118881aea4e6a0e4e305910d4e4a5f3d0a8800f52659ac26f122bd63c8aa2c5583f1121275adc9af1800a007fc97ea57a38598204c15bf65e7270a175460510848540ca4004286f3ca09eb59260000000000000000000000000000000003ee0ba2b1de438abe66769124b97a951ce18aedc8d9ed005628aeebd90efd316e7a3c60cb5a103d6f72e7a40ed8f44000000000000000000000000000000000119597c99a7a16d8d35937ea15539089741363153ef898d6bb177d9a9b6c5bb4b79728155eacc5d82571f398ac6c32a200000000000000000000000000000000116184ac845a28c4f96641ec19a07e1f8326bd45e2106148f40277ae6fcf200d64e326915cf5c927222def8deccd4ff8000000000000000000000000000000000f890258e70b973c0d69492b2e7d10ccb3997798503c0943af4255c13b3856ca4007b18cb9d638d5d9cca71c368cdfccc54dd8cbe68d5151e4428d35ec2d5b5cc7f5e455207c0788a695c2d7fff6735200000000000000000000000000000000171035755bd519af04efdd477d407267c5a8108bd32dd6d3f1b9555f15f37ce7598c096fb5301873809f0c000457a4a2000000000000000000000000000000000bd35595246a8337a426c50c02299f297036f710b0979c7f981c6909e835c0d9556cf64e2676baf952a787e10d604f210000000000000000000000000000000006600ff240aaa026941290f49ae8968e72293ae7c2af0df1b4ebb9373199b95fc91feedd2782ce819440286aeb2388c50000000000000000000000000000000015b2bbffac097c27944143cfb22e38ff8e50e79f2336e64c8496b0b25892834efb18a765e26f1408df1d64f4b9b78fb947ee5651c127d7c8ef65ec68fcd97d1dc228bffb5bf1278aed3eef8115a5ae72000000000000000000000000000000001064bd04edf96a3c76d2ace669ff72ee5edd87d32592213cb5a6a4a482154c1723bc19c7c530d164c31626dbf758d43f00000000000000000000000000000000176ac06390e3629bdfa282bf825c0bca9bc4e0b8fd90fcf2d4ee456d5bcb3ac2882d8406d2fd59faf10c8327b1962124000000000000000000000000000000000b58fbe4e14ee0af03d9aac4131abfaaba43c7cd92d530802516cb67343b382a6d2af9399d93b43d6e05f7ec827d5ae20000000000000000000000000000000000bfd241e3180cd5ce9de831b24ca50db23685bea7e008be0c6ead11abee338618728968c25a8e5a916cef8aa516667214ab6a1d0d3f87e7c9df0c14b6fd2f9d0cd755d5fce5f40bdc8174790901549b00000000000000000000000000000000183ccf0ddeb8573923694decc02b8f02162037156a8f6523ed178c13113d094521c3d9257febcfbd8f15acfe3d5d5c27000000000000000000000000000000000cf716097aabb07979ee435cf57ae36a3034283eeec0771bea24c9a1a15ea106201af8606d3fc28ad8ffbea2cf274458000000000000000000000000000000000b962565763c4cc155b2d9ea104e754e5fb4745303240688fee7e2256fbda82dfb515a51096be5ba0b111637b1a25438000000000000000000000000000000000df04aea745b9df2df0e34153269958d3640c1596fdff3fba696801c96371420a3619c5ace9210af7e0de4f408b09a7729b12cff5a72f27e15032844fae50e3cabbe31a69568bc4b5cfa884f62e7e204000000000000000000000000000000000e6be3275371e533a676f8d075bb2ab8b0216642ecde13425bce4ffa8ac51cb1b4c5c789d82387f5355c27f18da556400000000000000000000000000000000009fa3a3df5195203f967322cee54a15d1e0096922b6b881bb3bce54587fdb82931c0b87de7a9dd1a21b4389a34d161ba0000000000000000000000000000000014dd5455deaa5ea4f9b5a6241c2e8b2230fabff9e1ac08b359f029f4c7838201cb88a92a5b696ed47819e4866512fff300000000000000000000000000000000181085d630d1e24ebf79bfafa134c08c0e75626dd400ce500392adf4462028bc714ca07b28b8b8f15c9cf2934a299c3092c1b10d980826351c3d193a0f54a7dd78a3995efb02fe5b4525fca8791b1c4f0000000000000000000000000000000013b60e3be9d7d43eb42f7cc2c0a7efc81c175b696e82b034c87d1238db2798d9ad6534b86992653d86755b4f00cf989d0000000000000000000000000000000009dbb325624e698c76b9d697e4f7f03e502ae1cd43b49a0957fc067858e20e8c7ede3577f336eeccee58cad53eb727560000000000000000000000000000000007f2f50be2c6fbc500ea347cd14ca195af08b835814ca515d14dd2f6078eb6def2b9475c2ce370780acf394065032d0400000000000000000000000000000000109803d612b9e27be5725f162d061b9428f363493c17eb39c097032039387d96d0939a06466470ab62ff507ff762fba78f715f35fc967837facb515ebff3df502223c29e7089fe6d2e9120bd3ecfcd120000000000000000000000000000000008a9fcb462412c1065dc7c3623ba5a980e6f86cc813b5d8eca6b1b8a302ee4176cebc233411f2c9ff171332c66a0d46e00000000000000000000000000000000058d2e7ee02bbd4896b5bcaac0f2b09c16d1664209710945c1f7f1a53e24496d7eace99488debb32afe10d7fea442cb800000000000000000000000000000000084d7600bcb68d5e375457078672fa07ba2c87c8ec5f9eb7b61a0232988b197aff052e7125b33c6657729ce8a1c668e2000000000000000000000000000000000a07c42468c7c65fcc984bbfc2f05bf452daf17d57e669ee5992ce67517e1c93b5f7f4c9434d40f3b9bbdb3446ddb982a9e49fcb12c0b1e9bcdbda52e9852ee0e98fa0d43f7476b3d65ef5370c9460a3000000000000000000000000000000000ec380d15e0efd71958978b1f9298ced4cc3322e472d03830ebbaf2a4601c8371e6bc1cad047b0e1e429ecf6fc628208000000000000000000000000000000000b278fcc53b7527545ae1340c24158ff662683919717c220e7d2838a853fcc84ce3915f105a932872ca7f64b7cf096ba000000000000000000000000000000001520798dcd146c0b39ee727e8276fd998de0157a68587c2fde56cd82a9779b6ffbf745ec151210d1e9143856f24f01d600000000000000000000000000000000175d53b992d750b34f9daa39aec918a0ebb2f539db8057eff1409492c90f79a00f14a4c53445c028bef5d6372c9f80c680b0d6316c5d62d41fb0399256c5c46ebe2a12eaad835d2c7177bb7325e21d3b000000000000000000000000000000000fb3863bc7b468f1a0ab0e4701ea392bd820ec5cc2d7d86b58949002f24c972f51f0f82400fadebef13b750884b35f9e0000000000000000000000000000000008fca1b30d4e01991811679f261d11723086753e816239c8c7ebb60ce9ac0ea207011a69cdc29e3336e8f589b71bdfde0000000000000000000000000000000010696ff9d78b48743abdc6c1f4b44b4c960aa516623a24da515206d95e65286e453a8f275d98aaa09fefea29e71b5643000000000000000000000000000000000fb4b5eb18b6f6f8ee7dc734e8bdb625a403dcac6d0cae363e5a7f3a834c8eed5f01fbc4dc752e228c41f3f9d992bbe01b96434f34fa3e00ee0cfe548a2d2ca29a848cf1c52f940685caa9a227e32a61", "Expected": "00000000000000000000000000000000165baa8b143e3734169986e68a848739ca05330786012de260148cfd0810ffd5659210855f19ca92566ea0d6c48086ec000000000000000000000000000000001225672112e0476418288f381165292a9aabd009b0d9e44d9f8f00469b2c56698f5f985ab6292c9dbcf73bcf610080a20000000000000000000000000000000005418cba24a43fc7edaf2fe77422a0b2e8b38a45415e13654c6176c8f7cf6bb2b80401534154cd3b23e977af589eda9e00000000000000000000000000000000067126ad59105621cb0931ab8f386570b54977563ffd69c2231c56e7961f6df2c5d7b114e0b1ea176cbfc1d657127286", "Name": "matter_g2_multiexp_53", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000139cfd67c3365c5b4422063d7901108c9f33e233bf6413ba2e5b2ad62d188cb50dbd3dac0f298aef7c1d621249d4b0c50000000000000000000000000000000012fcc0d5d09cb3d86895f76ac3d3e9fa9b2495110b0276e7a039d7d2fc2e48fee646fe331c1d8e6f019898ddb43dd09b00000000000000000000000000000000159356eb3ed0d4f146dc929aa6c77057be5ffbb064432d3fc35d346f19f6c1f8552c7079e27f3188bcf29941375e62c9000000000000000000000000000000000fbd4e9a57aaaec40ef9bce8b76b529bd2261d373f05fd69af58d1f23c089497473e44e937b2617a92942af1a99d031f10e0acc22c43080ab9cea11a60866feedd57664bbe6c3f0366beff177f66318500000000000000000000000000000000022ce2d2bee57f7567e9b52ae8e913c79e3b2dad381802ccad317b525be0b503bdfa92722eb0c21fdaa31fce2421ae300000000000000000000000000000000001177074350288dff9dd85dbee758fee1400cebc173793198a96c0be3bb810d352720e94b9bdcc6f5a8951b3a86b2a0e000000000000000000000000000000000179e21de58ff76427f5ed7c8ca3058d0e5e81e436280aecc75a3d989d1cf11d41734de22bda74cf0dff175ac789532b0000000000000000000000000000000016abe94a49f071fcd5e24b5f3a837fe3fe7c7dc53416f59d0469d71f144f71ade4569bac3aaa202a8479c794bd251645cab0c230c354cbf1a3c13c23a36ae5f2d5d084d7aaeb427c580cb6b9bfd9df600000000000000000000000000000000018dee638031a3c9b1198cd4a4f267cdd66849e2b80e3d670897d9e058bbe772936d827eaa4e78283d42ecd25eb4b22e200000000000000000000000000000000009c04ef31cfda7c086a31341434a1698c1132fb5916d359a523b98d05d57bb38a1e2e2bb779d4762f9d4ec24fbf2564000000000000000000000000000000000a788450652e0bfae66889c66b0dab8d1972a626facb690f8e4ebfefc7e1a7b2b58f6eed02c1f10a74b140a49b6c5de50000000000000000000000000000000009e48b52f2b0548dab1c0d260144ad2e66a22e0f1781f94071b5a3a08311d11dcad6963b4339fa63bd82b4ff0dabe685290608899cce4b3d25f57519cc881eb748e9ee7e27f7b21d69f5d8ab3650c3e8000000000000000000000000000000001319607058637d4b796020cca79d62af5862b1c186f32d99c0ff53a830888f297ac4389582f9fd010534d824522e6fe3000000000000000000000000000000000608ca0b4806f17b59a805a3f9f75e7a33ac0791e05050d4eb19f2d4c845fa4e4c738c3309e24a4524b6bfe716949ab5000000000000000000000000000000000a6a6201ec077e113995acb81d4d07d0c4a085d367ed740d26c4a0c04ddf28697c1cf5e648b25148888617ba77ced5e50000000000000000000000000000000003eaff54800dfc8eb3ce647ec4ae8c1aab6a87d4853a1ea061a5e6367d8ebc94243837d4752a1933f7eee0ec1ffe68c8b71debbd9f3be5d6e65e837bd78605d5653fe63025c320cf49c035ae66d8ff5700000000000000000000000000000000122822c91bfc4f761b65f4066a94c0eb1f53133a1355c019f04003e84edc5095523b2ce87ff24bb42425ce979743ce31000000000000000000000000000000001928bc315800ae9936e5b763bf29b19a9aeb71268cb47706494598e0ea057f9dbdda6733d9ea165acade87bd89b3ec12000000000000000000000000000000000a87c1ee17bcd7d348ed1a5022bbc7438bfad06172584dd8e3b51db4b3b09645290382ba991df37db0ce562c950c0e6600000000000000000000000000000000127c80da591c3ff8d300bbdbe27e0aa21b5edc1c1fd8a5da27f58a4dec3971b3c4f9631bde244a7072d9c19f1c0a46be250f62ee2c2972e751b36d95a578efd2fa5e0a2c1e29475a3cee48a28080cb0b0000000000000000000000000000000004bcd0a0321c3c7e6161cd53254353905c27d965f57c9783c3fa7cd5c55a5820116415ce45491d5d1ccef6017ea4608c0000000000000000000000000000000013a30e19c43a1f466c0c3ebb5cf1b57c44434892b18a7fde18a2a29b09a5b4d13d26cef871d689d9855a73a43d22119a00000000000000000000000000000000066d6b3c9a949049413300ec0398d605277911d7be327b1d816cf25543d1b2d7c31d912f426021e612b56ca288b462450000000000000000000000000000000008549f4dfdf018073cc4e32ac930397659ae7a59ef42ca4f864b26e4635c2b7669186a107e9e91c35f04674d2be46051ad08c3d2c36085212542427c1760c72f22838be5286402ef87403f816f4fec950000000000000000000000000000000015900fb486bd2c066cea98e51d30424681fc3347a1cfaeeab65989d1adba104a362837bee51b8b953ebb520feb49aa6c00000000000000000000000000000000198ccab1f94fa910f755936e357a92d358e00cf406894b46adcfc301918c4fd7cf7200a1ea515343d577d920680c83640000000000000000000000000000000018d9380a8568adb92f8f9f67c315f2a837d542b32aa82d9bbf5db6dfea27260738bd0a03683a9988c6c3370563e7bb8f000000000000000000000000000000000528ad42f23c4e21a687f2303f495e962b0a90713d6ef3abbdce38ed166ffea9c132e50c5b002b2ddbbd4933e9a1aedf6ffa16b6fc4cc9509a2b8d8434fa0f4f38b4cb4eb1bf7f545f9f43b9190cad890000000000000000000000000000000017eb2587aef34b03943a170d91d99aa16ceb2a36df3068663382ff4c135083c998743f9145a2fd5dd4ce3bb8b64cf3fe000000000000000000000000000000001256fb29c7482e5469d64183e3e848e5bf32f9c495cc495c3f8cd8e46f71c3f9880f875cfe429677615a6803f849952500000000000000000000000000000000146e2f329f86ddf5b0b17c37aa2905122f457c2c812782bdc15e132468af48c49b715e3080da504d59414ceb367596f100000000000000000000000000000000022a8e385972592430e76bd952a700df8d35b32deaf06c60173d0048d6ea22dad95cc62300bc1a60c6452c41b32b504a1271d29abc5f972809461a1afa5eb186dff5e28f20311a1d8416f8d54fc4b2d90000000000000000000000000000000009c80b3191783d235814fc86653bf2f9a32cb7938111408087b6ab5bafc480583e7a2a32c6bee0ee4aa867ad5dbbf77a000000000000000000000000000000000a09af60eed6c47a6c2615cbfe62025530b35727b42fd812032671ca1eece6694aaae259b05906faf7fbb54362ea890900000000000000000000000000000000055c5f0818f41e5d73e8cd5f70fa77cf477cad8dca2a88b8970a3a25c8f38382268e439642518f1974c5b470cbf29699000000000000000000000000000000000834e44669043aed8ad47cccaaa7476ad830e38fc1def66aa7e8207e889ac0fa1a931eb1e90aa6e1cd694bb95056c3e63ce55b3b32ad29dca1a0c99771fc8f7179851995d5eac804458edede9b8dbcd000000000000000000000000000000000190f8da34caaf472ea9b0f41851f808bba402b9be4baa5d02d1bcb2f66acc3172abe78a49a653cd24dea402dfb972f670000000000000000000000000000000019931343d0e59f0f0a060bcbbeea92fc4670db510c017fd94e0650ace68c2925c627f373d8e755813c199b79c70369f20000000000000000000000000000000013ee811cbc036d2786d8ec0339627d6134b10517c8858f6c6db19a9319636459ebaa217649825ffba32a224175267de90000000000000000000000000000000011039d587f3323ea9d3c50027c427fbcbbf7e097533d8a5f7a61520f3eb548c399e401df0f51884395ad6a338c0a3500c6fa7aeb016b3e3f599846af83f426b9ab85b6857f901c49554d03d27a390f5c0000000000000000000000000000000011d5791e9bc632eb63bff86aa433e6df463a84570b779c913f67e77fcfefb6af48f3df2174096a511ac35eff64e0e5f3000000000000000000000000000000000282716505907931bc93748ba1729777b959d65aec5a78c9f829ae6f2a94a022116715a8c2a653a832a62625473a0cd1000000000000000000000000000000000f694a16ce7a69f0261a0ae19478003dcb61bf93a2ff39f940fc4718a38b9f4b6ab13527c5b438d22499ba29c0b5461700000000000000000000000000000000031eab53440757e4065804896e9e811d459665598546796d67472054fa60e5da8685d8e847eae342e44730056757c6287275a8d16c02389795d54ebdcb70a39fa885320d00cd4e5aa15967916e46c61500000000000000000000000000000000138862ee422bc0f38ce3e27ed3c1b71f71a03d61cc474d989b0cc824efc512ef173ef17bbfb2090997eb9435f4d23e0d000000000000000000000000000000000fabf1fac2ffa25d9c8cbd49b3db5dfdbee52adb947ebc1a3423c9fa2f9d3d29329b60ce0c1c739c7fc6d5a5d3b9e96400000000000000000000000000000000090d92e8763d4df49b8121a50affcecfcd632923b5fede480a3ee79128781f3f49b592d8f65d30adfc75d8a1922c41b0000000000000000000000000000000000074456b341565b13ee3862bd87b72f9d01754c7715751738c5b33ee85e3d8a6f731d7292bb485b5fb59bbf3ddf9b0d0dbec9767ed2dbde21fd8f315ed6292b5b0b1bb6daf2b62665c34daed00a679cb0000000000000000000000000000000007b85110889fed72b3654a8632625835cc041ff0a827f3e1b86c090d816d98cb3b4be66b6e573b3dc05b1998f2772f0e00000000000000000000000000000000160524507679ee021f4307e5a9fdaf01459cbb9a3fb9dc8be5599431e2a8bef38bf8a05d601580085da503dfcf57aab7000000000000000000000000000000000f98e2e7ae9cef2b1d954b7f26fa1755258112c496605c3c77408786d4b210e51c76f10870f558296993e0ddcec3d76e00000000000000000000000000000000068841825f5f5d8f622c1d43bfe090d11c6996688589c3d644ff5da47b94c0638128878d51dcf6d43637781f0ab21a68ff634fd89223733f407c242e52f034691036c7ca69f30e6cd444c561de9ebdaf0000000000000000000000000000000013ec97016dc3d6a3cf41edcc18f88f58b1b88cb2616bc2a8f96af3e7774ec1aaefe86a86135a20ab7592c874a33a8e1b000000000000000000000000000000000021dc7e4be6462d64ba6c09c2d326ca0164305dbf5ca1981f265a1e50f1a646748ce66ae07297230325937faf60709e00000000000000000000000000000000121bda2855503ef11b043301cf331a0fda6e5914e5ca657890ffba2542d908f8fb02c2c93cb4ac4fe5bb92eea757ca7b000000000000000000000000000000000386fdda56c778a7552dce451a6ade55cd24bf9eaeb837ebef898e2e868d05eb5edfe97bfa8eff8ab7cbfaca3c918910461d349e9711fa701b92b62dd3e3569d1203b6a35ac8600367a4df9a9484bdb0000000000000000000000000000000000763746ba87e8bb547180b0bf18699ff74f11154a06cd77a76cc9c264db7c48286fc52e3ef2d30ca914cdcc5c4ed46ad0000000000000000000000000000000018037afcabd273413eb4a712f5d1888249dc987a6fdb8befb92c02660604bd11deb33f283b37f88880cf1be2b2e71f1c0000000000000000000000000000000008ecca3d1652be4764720ef13a6ed6164a3ae89d160cc8c2c8c37bcbaa52db0fc0de84fbe2a19b93b8100556fce0fc80000000000000000000000000000000000c5727babfbc5c36c1d57b9f69c5b41823882e0196e9e0a89d5f4380c4257818d90b1fa6d782e774f2424209bf2e6b5fcc110fd7a6ae46ef78c0e26183e707eb5e0a2944e3afc09e435d56e91584b93d00000000000000000000000000000000142d41630fb9db2f9630e4d5f9c13069242fbcaf1dd02f93224174567c3f944fa02b9791a409d9236d89df6ad785e8ed0000000000000000000000000000000002fb5fa0b3a7cef16e5638f217bb946085fba870836c618a7db9b4394da9144850572daccbff8208f14c8082aaf1ef6f000000000000000000000000000000000a6be9b4a6a9b96d2096eb3a95780f11be1e13bcb6e625517191822403935c52cd40481bce2e782c42b11321cff2cb7f0000000000000000000000000000000019e2d94e35d608a50b5c8b371044f6410dd6c1988ec7a677016d4b52cc3f21b82fbaa7db897f7107d81a177c31f8e52467de5b9bee26b26b28f81d96e880a3f07dd04eb56c15314f1a789436e01adcda", "Expected": "000000000000000000000000000000000a6f3fcd812e3878cccc6967d49b104599fdaa80cb5dee7298c3fdc80477d277f2c68f1c941f6e03441eb176c222a448000000000000000000000000000000000a4007cc5586d677e7945dc8a5872b4839d5b256999166e7fe8efe4d56895f93be4659f43aaf68c6070babb6d3328168000000000000000000000000000000000cef5304a1077c8f31d72e6f1f91ef5a021d8ba64719b4527225b34e615af388d9b1391f65511eac209ff5e86244039f000000000000000000000000000000000c856e7847ea0b4a8334d124417b45a8689d5d9f113b99ebbe3af3f9aae1cefb236d751c40488a861a8f0e0326b42c4c", "Name": "matter_g2_multiexp_54", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001805009a7fc3d1705936696191c163a07ea992cbb4bec66884a2d58ac3fc0e16b6e0d2292caccb3541f39b7fd6098100000000000000000000000000000000000f3bcfcb0c400d3d06184563204bdee465de167c7d17bea2e2150fe12eb9bc3285f5693b222fcd224181f8d193b7d95f00000000000000000000000000000000028d60b7fc3790aac7f6b3ec32c4be626a2c64c6348fb8a1f39e58ee56b81469e04886ed9be1388958550c02ca9a75b9000000000000000000000000000000000b60ed8052e43e99d3c10a4b97ac3197ee3cc04ad857c5cf4d8ea1df2671084d02fb683f28f5d499910351354d5e6288624ab43047c02e30ba2ec671511d06f869bf736a9866192c5f2eea6c065acea40000000000000000000000000000000002ddb1a9a88e3a0697540cb008bceb075e87e2331f6e9b68f8ffec48752d93cfda5fee121155ad2a142c0ec42808fbc200000000000000000000000000000000144b694018840835fa9c50fdf62c2e32261a8350d2ef074dcf7d016af982316a0c6f9e5d15d29d3a54d8d25aac5534940000000000000000000000000000000010a3765089ada75e9eb61328756ab9ca7b8362cf86cc82af3cf43f390a0745954f28da72a6ea4eb904a040596795639100000000000000000000000000000000056b51dbefab453012b35fb6e06af06ee92e4e84e92a9967b379af760fdca4a3f10f938684a646fd70a2188721c92e98edfdf850c0d3e3903404fe3e0f523cd230cabc45946c4fcb6d0e5e05e388c23500000000000000000000000000000000169effb324d60b71dc7ba975e3d5f18700b34cb9017f482f64be37c4df01fb66ee9eb5870e43649225c9a88a0d499b890000000000000000000000000000000016c7ad9c5f7b65a9423f642d87621a5192d7548e1099d774a99a34dd4ec9623aa1168b9adab092b3cf450f369bcb627600000000000000000000000000000000123b35bbcd791ce0d00148cdb3d35ba39054a7126ca5ad3351fef1437461379ef639896b271276a9561b46e270f7501400000000000000000000000000000000161fca2deb729fc55f1102fb75ff466319f18510fc66d6cf95a8256118fca618682f00318b0a5297be873a2f7af1915afeb34852ce0f3b5730962023418ad6cb860716dcb526dc53e8ab6a74a6a3910b00000000000000000000000000000000073ad8c2f713288313185c3b2455ade93d58e70d5df6b8dfaac8eccd990fca6843778fe42cc8aa6f34ee44aefb49397100000000000000000000000000000000012eb9cf288a366adc58d40c9ea5f2cb5dcc5b04108e3822266ff20eed71f56bd74f1a2727f20d55917adf20b6c4d6a1000000000000000000000000000000001463db177fe5c0dcb899797f89da963731dd4e9e8b2eb77b465b98415dc95f6d5569df51bd2b08a13838f4cca4b62fcc0000000000000000000000000000000009c0bbadad98361209f36eb23a9eeff98f6eafc7d5327fddb6bf43898a2be704520a005b84c5b45c6a68bb7c98d65d6dcf25e64093bd92a8fb394511215a3fa674db86d7329ac5ea70ec77d24d4ac58e0000000000000000000000000000000013c63973ce6549ca3dfe8ea8e3bcd6b0bd88f7c73730834d9ffe2076cd4345090d0364d161ae8998af1048d102f22e5d00000000000000000000000000000000060cd24eea4177c9a5c37038d4cb62aeb709218fa8e64b9084e002f53a0c4c411825812c20df282345bc4a6aabfff6a100000000000000000000000000000000106ea864dd52933be02c1a79cbaf6dc81ae9a2d619bb368c4abc36226104f3b74fadfab906e36d4852a6412315223bdd00000000000000000000000000000000192e45153e4942c88bcce76098fa51782a81b53abddb4c07bd79a2391be68858e2d278969b9fe75bc652d02fe4db1a130b40db4f9e5c27a3208899f4f536880b97f4c69e7d889c0726d87c3fa27e097500000000000000000000000000000000101ca1625e9d4a51e08f5eb81387b361f6445eb307d9bc92acd29d62735d4e5078b1a9b36b94e4ea0a314703a85ac4cd000000000000000000000000000000000f134c460c6d931396a0aa397558975ee973e642f1c4a32a3d397051fe250daf4215ff5ac4b2863d570c87f0e32c8cb800000000000000000000000000000000008eeb127a38104351298ad77481c32bf51bc5d3910b03da0cc34062dd2a8766adba6891cb9fc579672276666e1242730000000000000000000000000000000010c896ecd4bdc1ce010da81a51dac96409079853635e57e5c3a5733956a5f5a9c3ea6838849e286ce0405dd54d7e32d6730bc7f68d8d371d0bc51d95f8a5899249b8db5cba0d21fd88ba6f86d8691659000000000000000000000000000000000be489a1c71246adaa1c1dd6d2ddfae9523fd1d58d00d4f189f56d08632dccc694e63b371db6922a7f3faa05afbf487500000000000000000000000000000000174212b6840a797f0fe9e209b41f55aa5dbf169a2e2ecf05de48c44e608f6cd6d98ff5269e5412defb431caadc8a09c3000000000000000000000000000000000f4501715c0c511703f6236caa82479b3368de430f2c2d95b39193537be0b990fec1ed8e4d94634ee6233cfa359b043d000000000000000000000000000000000f3b4712f95005004d99fd739affc532d2c4c45970316c1a43f76fa9b57f6676c709e8791c276237b92750f5bdc94492ef06360717cfcab15be966cba2836b97deeedd20a52f88c73e2a583b64c8e5f00000000000000000000000000000000003abd36736fec3e8b89863670666365b169d8510090a89007c7ff3a82fc62ed371544013a1444fedc4358e92ceec62470000000000000000000000000000000008229855468fc63f4024938cd6f41c6e6a5653319cb83f38ab7efb9e9d281166261e7c854bfc08f55a0a9ca47e54dd42000000000000000000000000000000000463ccacb341fc5874f6ba2d44efb5cd24e9409b2ce7f43e9d39466288dc833a45988261f45d34332f416a68c5d10ce80000000000000000000000000000000002baa086177394203a04ce1b46415983399e60986531967b690b1a13cf8ae039b56f0a00bf9aff357d51ac57f8fac8b282b7d8b8b9345bf13d0e113b662141f5ebfc5888a5ef8ea06f7d5d137324ebef000000000000000000000000000000000b25a203268100df0510e4155c594a144dbdefbb0ac95e02bb4b3799aee4e738ef4c52f03c6937cdfa7275c28f130778000000000000000000000000000000000c432347a2534e86e90ca346a7b8b40f45075727847fa3ae2f2e297baa14aca88ac6e08342f0d248a92e2c272841fddf00000000000000000000000000000000057ec8099e1e30329762ccf0641b45e1a226f7b66b80644fd551d6fb1f2136afb8e8ab5c6905ffc7c24e67d7f21863e4000000000000000000000000000000000a9e472aa993bea05961affd6782efe8f50d746928efb8fbd328fb50a254db861c90db8df7faa7da8266ceb47fa1a13a2396fe15751bca2c4a651445cef236a865269849908df53551802dd378b892cc00000000000000000000000000000000025484652f18e2b32e2bbe79916c8bad42902db5528fc45993e04daeca008f3c2ff38fe4b48c292f70a7dc57654233400000000000000000000000000000000008e403f472b60a6046fd190544a1d6b249dc97cbd8641c62613f4de0e0fa9f5456d843ece4ac2b9f4ffa2c0278e61829000000000000000000000000000000000824e0b9b03198597fa54252b3df9690df678e9c6d82301848939dc55ab25a7751bcc2b99786cd31960ee7030bf68ac80000000000000000000000000000000018d1d8c7f2b20f0ba66db616322e48ac8f1d6f4205f228ee8ee6cd13d1f64be9af338c11f511859baabea3e15d165fc09a5897c9596223ca4d6628ca1f793a000aa21a739a37faa28637692b754148f80000000000000000000000000000000002845c4255819ec6e97abddf4c9db7d91658dd1d55328ab0565144b377e20ca0743d93fddf68acc985ceb7f7431e30b0000000000000000000000000000000001577a5691f2425e65ffd59071c2bb167ad05a8fe23c11c7f7464764442ebb2f7a75a8d02594d4426c1ff022f7a6e19360000000000000000000000000000000012c6ffefcd3964362f1373348404d04d1849e98ffbef7b5ed5704d74b9550869e30a4df26e74b5304b85c7503f7487f1000000000000000000000000000000000faf3dc42113f27ac27aae36725221d04fb1ab46b59e16277be0758b8fad706fa237c0c7627771d8e8d3ad610f63619bf20a2973faf886556e5329363bd9b9c96424fcf2e953df90bfd011ec07bc66eb00000000000000000000000000000000044de166200ec06bcb88720e57b84cd8f9534d1fe303a26aca08cc35104ffd7e81a6473c08b28037118dd8a61d090e910000000000000000000000000000000000f4325ebaafc67945de2418c81f5da92da4e67866ab5965eff0f392cc527fc34ba4e7e16b91c26aa370b27eb6a07f6b000000000000000000000000000000000e1d77ccc1c196cf1cdf0dabbee4829d56e937372e9f5613e261ca07e19b3fcf10f7a45c490b98b5a64b955eab5c4f2a0000000000000000000000000000000004ba2e81f901b0da1ead004c76d43278d372456c0c0a8c6752597823d44994177734ed3f355aaa22f325ea36b7c9eba1f4ddb773155a27badba330ae5d26096f350e9ca2811feb227c4eee09d2baf32f000000000000000000000000000000000c115e270ffd6f2cb9bbb2a62e04c3bf7be9d7db783d292bed272c297773b39e9e51c75e5c79a6606ff7d0bb9ddd040a000000000000000000000000000000000a57b637126b16b23bdaa6a7cf2346f33778cebdc0c9943eb2985ba5c4114674cd596ecdb6959791139c36c22148ab8300000000000000000000000000000000177c7ed16c29d99d3d98c6facca9cb5ffe72e6aa63959dbb51d9382f0fa49b02a1652a398eb223e093516ebf134448c4000000000000000000000000000000000d6bd518678828f582fbb3b1bef725e66f442c4d3e6325fa571e13db492300d03c0188399a2ef9d5687a76e647873c0f52e4030b5a4bfa767ae20cdea7f464dd2dba51c9c698556d24b8f3d4d1afc82e00000000000000000000000000000000085d4f90336987f99d250067c2331e7de8f09a80d71fef0570ecfd99e409c1f405058bd3461c9f8ac5ccda406db89bca0000000000000000000000000000000015f310660ca6a0c06b458d0b840a5c1c476d5175d9ff6dce6334466d363d319939572a2b00662247be1ed0f4e6676f8b0000000000000000000000000000000011e9352c0f81bd3857806db678bceb2150848f2224ddfc43fb0c733f0689ab4fffde50d5ce04d54055d27d7702e5d2d40000000000000000000000000000000005d835d04dcf4199130d6a16e86cb97f4ccff58c496594b83524dcd88f5570212f06b744379288f2a737c7a82e897cedd32e0429e7934faa526475c5c7fb977c3030ed74e145eba21af2d2cc8461580f000000000000000000000000000000000f7c4e621c37bd3068a972b9d4211abf9026e438ac7f8cb341516f7e6aa4d8bfb3536389e9155029ce9e8d5d376eec1c0000000000000000000000000000000012a46cab2624797513f2acaefa26fb22c4bf29188881690c350593fd1949cbc243c9d1d7d27d9d76aaccd347359a45660000000000000000000000000000000002dc383d4f9b75907f74bace1769bb5bb1b27a597c9548310f2b5f90098596fcce6b5fe0c72bc8be9037fbf31050d74e000000000000000000000000000000001900deff7ddc62ac302c941e1d2a28a4bd2351edd7700042ea4c4a48145ef91688666d8d7de503913ea259f0b58809f21f700d651c67ca5b8d95fad1a8e412befdf691b074956bb8092938bda2ad26940000000000000000000000000000000018ac8048d58f7b1a9407d3101824e3640eb20633f8ffdcc97d43d1b25329a2a1e91added42801c03635ec904e627eb690000000000000000000000000000000000b499fbdbe2ed41dfd6c454796e1ba57021f355a4de8f60964c78dc685e2ffe9c90f5a1f6c9677514ae4a9c95c8d6450000000000000000000000000000000009d10e5e2bb69ea6fd820778f75a2a60627802a49128c3f999d8c1cc2ba56ed18acef354a2e06fbbdfa7e7a4ade7529a00000000000000000000000000000000082839d66a18763656c2ef7196a1d83bd162e1f109b54c5a6095cc7c436e8a4888c4001696958270f54f61b81b00b32d83052a3bd7a13bb1ccc22b9519c7ab12d2dec67924fd9f15f96069de22e7b692", "Expected": "000000000000000000000000000000001463ac5e269d286961036db48ae33fb868a28b0dd828c3a66592ff9dc115303bdf3ab78a8e1f5df68ed1f3b4c6c3f2440000000000000000000000000000000012c64ca0ac10ab616fc733f75fe6181814e9c204f9e4eb79487ba49e3a9746b9b7916a1d768f2ec573a4c4e226365f48000000000000000000000000000000000a06b5b745dd92adbe1f4cf30c79ce0c48428b3e3b05af1585c4ca12eb2e763ffff46b55a060913e1f77fc9b0b085c9f0000000000000000000000000000000006271931ce9c8b9cabdc932297f3c87128a5af25a9f77e71ea4e588f1e88686638e89a8e212c92f6472692be2e05fa5e", "Name": "matter_g2_multiexp_55", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000001bf5b74c1ac89d4bab4663943e19128619731e315d2d7b39675f7c43493b338020190a72cc7a6edf0b8838886a7fe6000000000000000000000000000000000713f413bab7919cd57c2de3349394121d6bace3c10df0e41a0ab895433d225b05cdb1587deb93ae6e56ec26a29c39f4000000000000000000000000000000000dfb11c9c0bab7e4d1ee39941d5f6b932ab473567be2329c94bb0b146c46fc1c2cda25dbef8ff9b0066bd4ca3b6da67a0000000000000000000000000000000014e399169243bd619be7f2120b2cae5d19b2f04185aebc7d948007c4d3345a9f45249273b6290c2e86448648868ac552c40774f67a651ad70f17393b386e9ea9e81682ffd78db7fbc17cc5084f3c7052000000000000000000000000000000000a67bca1f8a0b386b2a67158e80262f025b225535a294394584118f9a701e31e91b2c7eb8fc7e28538966b967c139dc400000000000000000000000000000000185e8aaeec9b9abb9f0d6f34e2480e9abc30208eb1c6e023d4986d544b356a387c323c9edb5c52f5a2f0bd59cca7df98000000000000000000000000000000001877ce1ca6e8b30df86de688d950755f2708fd6f933c07ae45fad1b3e43337f1a8454ca5d2a80940e8fee98fffe953a700000000000000000000000000000000117a0ac9d27292f967ff5bff2ebed5d2ddd9f453d6aeadd9106eb52b53447974561b621fdc1d973c055f1cdf824c367bccf1e36e063a5fdd4b735dc18bf07703b80c6b72f987c05641612d7ce73562c00000000000000000000000000000000009fc4e9e816ff495dbfd4f745106fc90c023d95bc64b809801d02dc7cead905177ede5016f537243660e4b7f54a02ea200000000000000000000000000000000180aceb6e9851a11a1e34502897299e7db3e09f4970337612634fd9848d1de2bb3de8ede690ca051a75add5810ff777600000000000000000000000000000000199f3c43d429fe8f73e20f81ea00c4e78294eaaa29fd67563664381db3cee2186b387b880089cf96fb99c2e22c95449d00000000000000000000000000000000040b20ec4e685f104be188d0f15a79f27cf34dd01f813275f6019a9ffac56e234b6c967c80745294d9fa46e0083cdd907ea75dd2f54fa6413ba77f10a11e12abea3a4b947116e1e7c9334a0a37c3963100000000000000000000000000000000189fba635109ca215bf3a09c3e44ad65f7eaf653e0929aed39042e3b9c8b1132c5fe7cfafddfdd0646514aa1f9e7e1c0000000000000000000000000000000000c28f598c80ac262ec7a0e0d1c867e01ef26f182c5df9ea7f88fdf8bcf3a5d2f06128526b1ce72cead8ab4286a0b8d030000000000000000000000000000000008051be3328df43b79dc9040ef0a0263d474acc0edc023f300cdf7c13088d1bb21b5f37ed81b38dcf8718bf6441605f8000000000000000000000000000000000d2d474723c6c246dc59e683be147b1a6bd6e7d3cf12aff7b636802a99954e7a13c9ea429b19833a985ca5649b1a998f6855c61bb7d72b022c16290c6d3ca9c1255cede8e0b827b43e40fbf01840397800000000000000000000000000000000058bf424fd68aac77c42a046f78a55729e6b5b3fcaf436d0d98354b426a95904b55cdffdd9a8892c9f56f170ca8811a600000000000000000000000000000000142c1ded08928fd155b89bcfaf9c8194f4569b4cdeb3bc7286f4dd79e822f5db497768220533b71be8c71d121e557020000000000000000000000000000000000a9c753686534bfcc295eba0a617f86d7f9e78d3fe6d52f26cede97a5b1f107210a757a2d89361645856b7b20e89185a000000000000000000000000000000000f745541841cc4b5352f659c2b7cfa8d51b07f91b0cb8c787b4492bb4b94ea27117695416e2806e57c38d7e565b9eac67fa8503101f392a6c6c27300b6992af3fcc48d47f73db67615a44de883770d4f0000000000000000000000000000000004445d4464b51d6b12f164a49ee3b610f11738d60cfa6e02f8c33b168d9d5db90e6cc558cd12c56069571567d91183a30000000000000000000000000000000009e4b96c2b533a16803a36f8d1f179313b7adbe6c4b90716855474ffb2fbe087df3fc0b4ef14cda7d958efc5c92574ac00000000000000000000000000000000104dff7c859eec61a0ff8e0d831bf9667226d5bdbe298400b4f9e3159a64b1bbc7cb9f4ff9604e3ced40bb0de0455ce300000000000000000000000000000000134bc2461459ed6f0d96aca02b62e3110c2009e1ba7d3258656e9cf97c2a1685faf1f61733ce6ac3af7ef4d73d0b43b1dd947617bcb7ca1c8fda0d49e6d950a84d60230bc2411d42ac32e3651f48524b00000000000000000000000000000000104e5709f8edd71f50eac1770ff1c2b21f5ee8cf5a310fd1201109d1b73cab69913bcfa2d27a8ba16d974e9841586ebd0000000000000000000000000000000003a4bedc6277c61825f6ea1f438c058a1afd494c384689a8479195646888eecc7953b8b8aec849fb5f19a20071261336000000000000000000000000000000000856ee8eafb9b3d25fde7e38da4acec624d1444337b87b0b1a660bf497ff37929b1ef9aed8e1fb0ffc6cacd8f0d1a1a00000000000000000000000000000000011b52192c88264df56de3d7b14372443e25183bb816ea1c0346f15a1f324527ef8531e27aac3112e2a497a0eff0d5485b4cbbc6d537ed2b69c2c32c84f3cea3d2db180b64861859368e98aca32bceea6000000000000000000000000000000000a696c83010719161b6624aa7756e6e84980518416554ac045a93b63c2561a68ca2ff2fd5b6d2d667822ae4e3b3a2ba2000000000000000000000000000000000fb8fdab4f177b0dee52bb5ba615b1d548130deb87b14d05d427984ec148a7a94efc4674804b3660d0f7aae2b49f7b1e0000000000000000000000000000000004914c0359c8e23a7e431e517cb83e5735cb2876e8b53ad45abf1e9eda06e736378ce03ff75002374d47f1bd45b08e8900000000000000000000000000000000139abe340c2d773cc45cfc75c47ff31b2dcdce27ada3e6d6c0823f37e4e693ca30342fe41eb96dde464d14668eb72c5e457bcb8c44a2d9d1facb39ba7ec8ede5d5962b3256d9fc2e68a1ee5a733ccbd100000000000000000000000000000000180345fc01e3fa349c45b1a7fdccde5f9ee70d7d65510e8b4bce654f2541fae7641ad86f9bbc1f02e93e94422433f8b40000000000000000000000000000000006cfe7026cd423be189c5ade8de197aecbc9aefd4cdbbd2aeacda816247ad59ae06a5c49b0e29bf1140f400d46845191000000000000000000000000000000000cc4f240a317ae9ce75b44fae87c92fe9b6de10e1191cdebdcc37ac200957683849d8a957216676db1af51fa0a2a1136000000000000000000000000000000000ba84d595661e5d9bdf9d268a3cc575fbb6b0d469b58b3e43f80694c78f4e9e501c4a4f9c42ee4518ed7189a1c36ca0c19f254dbf75f1c42046343b0060e71302bf6c94ca2fb8aec74fe7a47a3c9c3ff000000000000000000000000000000000fdf7e2372b01b5d926a18ddd06b4573248c02d7debf944312dc06f76ba08a7be460c451d296b71e9e81cf0956b974b80000000000000000000000000000000018326d0e1bfb4a62ab6f772b47ed7188035a62141e6b2eccf53a299028902a172771e8e46c0b1ac4833ab12045922b3600000000000000000000000000000000072107574145c6afdfc7d618f2dba2b8bb01d92007dafd476e4ca62e6053e5e9f2e34243ec2dd16ffdbe3488b925a0f000000000000000000000000000000000070e8491a835ae96087013b0f8da267a7ca5b0a600d71b8c76fee35f41d8b5c1ad82c5170b0e8d1cacfc7b7b13938e96f08cf27a47d89ae6e2ffb27870d613b9ae586857e4ea00670944a2883ba325af0000000000000000000000000000000018f4da37ff63f66d68c875def8c758d9a5adcdc408f0c12b3a60ee4a285e6702b1d5b9326c61f443dc71ae83c7bd21e80000000000000000000000000000000013a665e430141cff62c25577798473a645d20321490bae7689de6ea223a434c7d3b16ad004b24a82e2c62879b2408cf90000000000000000000000000000000011b0108562f53bd47d9f8ada54166854bf758ef3769ca1c3b7b006fec8707107fef0b6c7e59feb727646b74c27ec699600000000000000000000000000000000028799b52107d8965066e2f629b30c0edb490a0f4d0b6cdfff89a9f7763afbe6217bd42c2059042397b6c0443465fdc050aa333bb6b44086fe6211e89cb70b8467eccc228c09aaa1d589cfc24771a11b000000000000000000000000000000000c42cb42e389f32926ef09584516249ae332641b573ed29bc0884feda08d35c1bdc6c3d4a69fa15105de95010c6cc24600000000000000000000000000000000006c57fbf93c7959c562e0f3ef59966c1640c706fd18a6b539dfd711b0ad79643642038954bc866d42d1c04be375b95a00000000000000000000000000000000039ca3ad23b71693e02af36a4abe6ccd0dd4f4aa709f74d900b9fd015a2eaed55bdc2bc0749c995783a7615971e8a1f50000000000000000000000000000000009a08596b29da34466c8a7f46b805f1b6f2e48bbba614d728562981d3d4884de9a3c1980d398eadcf69e90c851d48526d9f7f74a5ccbd01afd985d3259739023cd012cd67fba3a4ab5597e94d8fad43400000000000000000000000000000000123dde5bb9b7ca11da9e08a9489cf07d147492be8041a5ad0b70715147e21d6017a58af23c47d77885a7830cfbbe5e0d0000000000000000000000000000000001527cec3c393d03e74ee8a7b1d6a8b6398945cd284b59a93fade9839863f0af591c287e89b3b45e6048f2f9b518208e0000000000000000000000000000000017ac3a2d9458bbd5f38d584b0fe4b35f3a452e22161564a7582465d2068b3ba4dc5e1e24a996596b1fb553d641996a4e000000000000000000000000000000000ee5ed5610a78dee181750e35a8ab91c001446f04124930c2ed85de74c6167009af45a6cbc3c59c4915334d7853ee12f85c00be7e66e318bed8e66cc41e7fd0593004bbca20f0dbc28efe4441acfc9ae0000000000000000000000000000000014d60c1d436e4486f35ec85bf2655ba6b752a36c86fd9088c0ce46363e75abd636052f876986fa0f4a59152998c0e4a800000000000000000000000000000000083328e38373f1de1049deaba78f568db818b1dc38d981ae92b968134d369ccc399bc3bd55c841755beb484cbbd60f4b000000000000000000000000000000001788850a5508d81df9af1f087356bf8e63b3c8a4e209403c4de7b3adda07684a08f9de6f1f8fd8dd4b2bb9b75be329cf000000000000000000000000000000001506a37d222173f0098f56b7c443e04ffe08b376e1563344e7bf22b1c9df0a1292f70ba51cbe554843fb93a7f535a4aabacef63d90ad11bbdf0c5fa2db2838c238ad3049a3f47b7f67361825efbc6526000000000000000000000000000000000d5f153952defdea9309269bc996a7714deab12e7644f8f8344140fe53034de538aae6c3af7b06687684edcd2c5dd19e0000000000000000000000000000000002da67345153c87ca65012b8703acbe777900953abaedca4770fd893275948d150ca3d6694d58bbbc9e62904448a8d2c0000000000000000000000000000000006e8c95d22f01fd9d56178d754f0892f46166282a27e6b02826478cd39119636e811c03fd835c714a59bd2f7da5ce5e1000000000000000000000000000000000b5ab6233d8dff50648d89cd65793640c06ea784d00aff329e882ae04fb466506cce3fb6c381b4eacef8b5305953f7b6473fa3d16e6431da14b8639d4fe316692db087a167a2c4f07307e770bb9e35ae000000000000000000000000000000000595edc440a5c94506a79f3b3fee818256d7c4185be40c1953b46765b2f925ed16a476b07a267570c727592dfc4a0d8d00000000000000000000000000000000079ad05473fca57f26fd068ed659e4aa4919847dd96e683e7d4b3a731cc9ae0562a693abeea4fd550e644b43b553118500000000000000000000000000000000176a9751dbfe727a442797551254cf904862c4d590892e019a54b72f6a5a124d268777b82e19d557690ccfb81cbe949d00000000000000000000000000000000164ab74c150cd151b70fdd7d63d0404214fc9cdafba3bc642aa798b1c301c287ff6d05ee7b3a3ce997072b8189d54aa62774741f87af1d6942dc4ed79b70b2d706f3db6b6d083eef0475334ef1e2410a", "Expected": "0000000000000000000000000000000017d73e29f1d555a10272043ac0900e80883c185ff7d087ee7f5a3b762213e658a42d1b4fdd435d1acb9d5587fa7e8243000000000000000000000000000000000ddc440795d0e4308577fe8439d43418641538711972c9744dfc8a4c206c193aa17958404bc387c7c2fa30bc678937f7000000000000000000000000000000000d7e43c0f99adcb02db99974e7615b4ca0de72117792ea515bb04c4bc8680a3fdb0afcf6a3bdfe16bf54c1d7336aa185000000000000000000000000000000000bcec1d7fc9f2210be80e90631810987801fdf60890ce197db041b6a62682fd7e181c6110956c5f5e9c196049e39100f", "Name": "matter_g2_multiexp_56", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000015425cbb7075a97dfa9409d7b014127396056dee6d4bb63ea285309fd91280fb691f9cb9572b544b332324f6cb3b1276000000000000000000000000000000000c5b9634e6748d5819396051322d9b7e0377554613a7fd8dc0c71cfb7886dc0ac29add7265af84087a9df5ae3799ae30000000000000000000000000000000000534226ad7324ed5600b5438b659c7b1e96f27ee1d77163f2d3073418f7ded5c613ca4b1a686764ecc43ce3388e0c32600000000000000000000000000000000198267e2bd474dc0415f47f5c87a11fe0945a91cc0bfc37d504ac53f9b9b0d087cd5dbc9b03972be03d4b3f9d2123945d10ffdd3797ad13e65a1115cab6529d0f87b91eb41d6265e694eed8f02667214000000000000000000000000000000000389a084d95445af6e0afaef21d3676794e45986b9520035111ccdbac4ddc1b23974a686a900616f878f3a06eec90db500000000000000000000000000000000064c75d1129753b5f399c1a5166a0f6a8f427d65ec2fd84d0c7339218e0a396681797bab68b33653ffb9820a6005fa7500000000000000000000000000000000147e199e8c08b9af38cb457b623d0fff32242b11e695f2adc0f136c5596db313b03c2466fb58e37c94704152e5c8f9dd000000000000000000000000000000000e8fe5436baf3470a19891b85d15486d1269e1b13098d837b0a510e71b0e6260700ea85f0bc6476217cc73615370cf003e5da5568a9427e0cbd7973a34c147ac2f3577d06f68280caecf8588ebf1591a000000000000000000000000000000000a39a2032858a57ccbfb940741f4ae21b318a56d5567cc0088ed52dddf1e0d5de60bd2da9b675212a9a28ec17fca7c0600000000000000000000000000000000039e2a4bb1b417f8a94b02cad60a3e1c4c4bc5a86a23def7cfaecbfd97d89a5104e0cd13870c9fbd010dfec3ad9b1df9000000000000000000000000000000000bc29c5623f9f18ec2af5bc651a65d89554705a349923ee15a9bfb82c114246b404a1dc1c24d65c8749e7c9cf62d963a0000000000000000000000000000000001496d76f7b8583a64c1627151589af876a2f5e7677611ea15f14606538f6052c56e9fc3ed145c313acea69a51547fb6145b5f1f156f3c823cc129568e7602694107608c1f9545edaa897df58d27b18f0000000000000000000000000000000015f83b2f998691e504aa740b4db38f5b0236ece3bc1ca933b79999d55b737bfec51e590c2127d57625a9b7c2960c06280000000000000000000000000000000001b7b117f5d722e320b7e90307ac1423aec5e30c29602d314bac9e5272ad3990d31999bf3f516ac78b2be0e16c0375d8000000000000000000000000000000000fa7992cd7fb679eb5f9f9a9febe9c3cf41a717c8f6fffbab5748572098407174f09457e13468165f1c7275d52f6c84b000000000000000000000000000000000737e95f62aacd12f8aebc288c5cfe052f34c4d16e7b44df4497d9a713b77485fb0efc09aef11c7b86eec4d0cfd9b03ecf6760be82cefac2843265be5fc0fd6d308c1ed06fc684c4693de25372f09ed000000000000000000000000000000000004d48d72ad4e77954ec6a5a62299f0472bc52b556cf3857019f8efdd694758f13029f9d6832ed672cc210f32033da8d0000000000000000000000000000000009b2394755d0319741d131b012ba0ece7e2044def20ae73fe73bcc276af9d807ad75be79202963f9a5c512a6ca53197800000000000000000000000000000000128f856fc4790d9fa68cd2a3c152d675453dd81dd64f0ab084c6dabce456f78c2bab0e7f315439b34f86e8fa61a33ffd00000000000000000000000000000000173dbb908ed617ffffb6aeb212cfe6c03f7ee51c84134fde67de2ad9561a897e28a0efa66257ae0c21ebcee3fe4fa68cd9fca4d166149ac9e6159ce95a06f790a96243662373637f0c6a59764b77b45e000000000000000000000000000000000bb7b84476d4b17f4ada0b6f50d34dfaecd611356862895c8d2fee6707c4aedbf565560d4207e43c179c5cd33cbb739000000000000000000000000000000000112d8b10c775218d318090dfcef55a903953f7466c50417125ec0b2c20a24fb50bd172331c0377d4f47aec99bd87a3fc000000000000000000000000000000000cf4e4b3c600053f45f350c8860e47621f50f3849872a91ab115f71a2b04657991217e2f0844b296d3a6bc33ee66e6a80000000000000000000000000000000008f625da164bc9d96be3e78df63bd1633a2951dbea0b98e359c6317abe6ac5799c4bb00bbc2c5d02048539e753019a6241733039312347a0c9d760c1bb9a1209a34a02b359a9c52a57eddced1575867000000000000000000000000000000000028db057ab9421eefd1fd481c91153b5c1ceb0f2dacb0097298cac986f036572c6ab0c8709325b3bc25bd494bb46c55400000000000000000000000000000000024be09301c9be4f726fbf7796e8336c50897e8534614c25f65c37bcfc6e724d530c2782bf483668fd08e91ad09484af00000000000000000000000000000000037bfdaa11660111ce0a9c3e18b5da74c004cb44882b1aea4173e18d3a17f04fefa3b319afaf4af9dbf3d4b9ddb2c3a00000000000000000000000000000000008f2138bf621237a286229fe762968a224358b030f6c20db58043c13727b516097b42d47781bd0f0df2b155197ca3946b21b18d883ef62084ce4bd353d7434d7e220e9cf6bd0e8d0bed1ad0a4ad94c7e000000000000000000000000000000000b4e2b058d6e77cf95be093375233e5c9c8ee0cb2a3aa93172c08faea111df81b9721a506180b7b45bdde4b58b0b7368000000000000000000000000000000000f7025cc33424a7c11eef47baef888535d938d50c0f40eb83ae86791834770e5dd95b30aebdd2c13eda3447d5730ce3b00000000000000000000000000000000088270ef05480ef8aac5c284358d8e06c3482c26279734b8513000019924cefeb396ae79f5d9bd863bdd9b22e3ac3c54000000000000000000000000000000000df75afafb138fb06bfd905c87035bc5d18c45a29267c3965131083d7e0112e10556d7693d424172a53e8d3120f0cf2aeafb6aa11296facbc13936bd2ba09a2cf9bbd9dab6ec8cc5f73d78c90b471a3000000000000000000000000000000000122fdd3c83c01c7cbe71f54d783181860e7dcf8406e3966e910f4d0ccddae3a245d6b1f94b1182d1917fd63960cd75d400000000000000000000000000000000043592e5797cc1409d6d42dacad628448799b24320acbda83f6ea9d232968efd021058f540e3bd73a7f95761efbb5fc400000000000000000000000000000000025b5a8577ec1064b5c557415a50e84c2302df97eb65860f979e5b1e261f47c0f305461681beb07e521cf03f0e21fd030000000000000000000000000000000017e86f3ffe72bcb71d46661a1537918d52e886e362d78ed756140a6b5083a4eebb5280b9eeb8a25251dec43a5cf509b13d39a61323c07f9f4656a6c5e6ba139da8175ebfb8a641de50cfa2290884662900000000000000000000000000000000122f26b4561d1f79a70bd0e401f25d50891c0fa0320579ef21aeed7c191fe1c75403a09260c3872cf74b798eb1587ebe00000000000000000000000000000000039a261d9f48b9eab6e89046f333ac328cea287993166057e9b99fa8a7d7eb3e7c34ecbb353b7427b235084f47f45d1100000000000000000000000000000000015d5e297317684bd0169c795d9dcd209452d024ef9a450c41beb0f6c7e6dc5fa0f3ae24c7cf2d7eef97bdc51788188d000000000000000000000000000000001487564f0e9d3e0d2d30ec9930a00f10093e29f2f195344f567960be323ca21231efd8528108dbee4d5ae4de3930ddedf6374d0849a4471eca96c5e715b10505c4c49664f341d04705fc688c8479cda4000000000000000000000000000000001965ac3a520c1ac39b86832ecbe226ae0474b76659076ccbb550a0daf41c40d424ceda084dd991f22cc53779085828430000000000000000000000000000000002e970a4248823049bb4339d21583fdce9540ec103d6e9530b89e39ea875b1c333f7f5f859be39baad34b374055baa770000000000000000000000000000000003460eafb3e54ec03fd5cc1d460e1359b97f5543e6231d61614c1225ab7545fae079ac8e65668b83d022031a7a54746b000000000000000000000000000000000321394863e7c70df3934d874613b7c9d6c331e59a599be593c82edb7a26eff9bee8e4befbf122240d2deb2d527bd38c0b7cb52b99abe10d1367f8d3def38221c18657a1114ceaa1c0673ab13a6e10870000000000000000000000000000000001a5eebe200ec041476457f8585cb4ccdda936cca4977d7701c44e0d4fc5d9c206682a23348013a055117028c16914400000000000000000000000000000000003519bd1dea70245e521988336eb41870599a877380c0a9eb19301f9b2caf963eb559070e23eaeefa4de0173bb1fbd8a00000000000000000000000000000000125707f5a8e26b28968dab97ef4654c315b0a118c20935e38a5a526d9ac0a0e18355d8c9f3f58c082de98691957e2d5e0000000000000000000000000000000010b58dd683f73a16d8bd5557b35b7003a761bdf7d90ef576de8acd420bc74f5219fe7f9d35667feeb3ddf1d568b56bf1f49b1fa80a321d4d100069b2c4b94cbda255d8e9f1a7f14ddf4762b76e4a386f00000000000000000000000000000000018267d8b83ca59d4efce7ee3d73f7b984f09556ea4fa5cff5997a1eeeaeb8bdc9185176d77ad0f4d86f2e429f4015350000000000000000000000000000000014114344d6b7c976cdaf2418d7f72c120c2fddcc65c3ead067482e7073e2a3a239af19f862ad247e3181b13f5236d1040000000000000000000000000000000015db961a093b248e83deea0ceeebfc3dd57c7cf8b48cd627c5c566a4f9bea30ff0ef9cab9287a0f520a72b02d9092a0c0000000000000000000000000000000015159439fbfb91d1e24af611563aee3eb498fde666a1014a9f645037995d72dca0ed5569da7ecd084208b7c228e8a2b2ad3625b0839cc1ab8c9798b2e9706ba6d7aa623f3c0ce0985bccb2ee5c05a313000000000000000000000000000000000e1780b32a7b17464cf514efc4bdb02283af396ffcf6d1ae023e07fae02becdcc3c467f89f8edc9173a71aad27b200da000000000000000000000000000000000c3e7fd95dd823338bdf3d82fd46c265a3f794d4065d83873b1aca66da5f80c5962c9dcf537fc315d024d8cab7bed89d000000000000000000000000000000000e4eb722080e24f54fac7eed4b94e7b1eedb081c3edd7aaf5433d00829929d8bdef940aedbdd7dfb0376b3ad5544d9cf00000000000000000000000000000000158c1ff057f7ffe6492097e339cc4ce56bbefd39658ad55e08d5407619d1cbea7c83b977a1583ee48897a5e9c0d9ce3e150e53fb45ba8ce5ca917010f26451220be51141fe21cfc1cc06a5557e8e7afc00000000000000000000000000000000138e8bc8cfaecba9fd1322a3c1682c9fc1286d78e5b6718da00acc69f811fe9f94c9f0dc9d80e9002c0022c6dfcf156a00000000000000000000000000000000021da679a068b2f5f473ceed588f07adc7f485003f7d2286a18c07b09b835881f4ab94c7d4ec742c33a7cf01801116fe0000000000000000000000000000000018a62c2f4a02b73f5a91f503b53332304afc9cd8769f236259789277599a203b8b304b38993835a87d7cc970ad514d2400000000000000000000000000000000179396865f859386df7c1b8fa84c4ee71c14daf695fc0841c293618e6f8c87fb56b924f3f91a273b969e8635d7f90985d69ec73df67feb970f1c7a3880ee84d948eab4d8672a6c1481d61efc6cd710020000000000000000000000000000000004a8cb437297722c0c1a9471ff083ce60ec40c908af4ebb570c87133df705e725e3209152bcff26a0d6e4602030610d3000000000000000000000000000000001832e55a9e703d727156e4677ef4f82b86c6764123c3ed1dd94ae3b46d7eed459114993968eaf8e21cf24c59d042f41d000000000000000000000000000000000f606d5ee57b188636334ad60057cec4008ace88f14ea06324edaecb26da627670b44b6ac57b9fa2717d03096010785300000000000000000000000000000000145bf70f90a9d98f56ed38b3506556a48a1340ca6161806d055d7a1382eed54e294564de7fdbf525b0012de3d25ab5c838f8acba4782dfbc02a14d4b1d7b2b0a582f9bd75642169707a475b1a7d2d7e0", "Expected": "0000000000000000000000000000000018ca453b9d832f029ac8c7c70df846be97b530e6e42de3ba6943a7d0dc00296942f88eba6a9cc3352900ff124efaf7d90000000000000000000000000000000002e4514102aa3f772f2659ae9f1e2a91c7fb749ea590a3cea2c1a2e0f7236f71e182374cf7ebd2fa086dd921c29013910000000000000000000000000000000007c025696cdbf403494c5fc7f9a10ad0c549f84d1e06c5c4bb22f7a039486909c540776224bcdaaeb3880ae9d745dbe5000000000000000000000000000000000b5b5b70fae8b3953ee6661a0f4a1be25596839482d78710e584d3bcd93dff2b0bf4c8b20974744667e25fd8353cec0a", "Name": "matter_g2_multiexp_57", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001265e90c564693db716f17d1a8815a8449e43b5a2d5446ca65160d864718cdfd413d5aa024e7581421c7222c29eb452b00000000000000000000000000000000133a6558baa53a2b8d239198e1dcd81af1ee46d55137177be467a99edf282edcd47b7861a3c822f9bd0df2e86aeb5dc2000000000000000000000000000000000d8287564bcedb1e57c3d74b0d484a9b475ce3f5b0322bda0e980de8891e2e8663abda99744b58032b8d7d3adddbac9500000000000000000000000000000000013cc35410d7fe07eac96abd2b35ff656e17b6b1eba2bd1d75ce5c87c5e76755ef9c2cce70f05cdec15d1bc44bf902d4cacfb05e5d10c41b06a487e9f8afa38759eeb55f0a5bc8640164bbb081c1fd2a00000000000000000000000000000000193f0cd6b4051cfd89f358cf6643528f0f042ae30ba3627d297b4fa2c2936426a9c1b65145b8192f65dfaad1f2fbc358000000000000000000000000000000000a92ca8943e64a391aa39126f093f2b530f556c1e3ea1b55bef1c264909dc93d260eec6420fb7a4e4a45f932d57951500000000000000000000000000000000005c7dc5832f744089d5fe034bc93e0bcca042ddd1b221cdd5958be86214831906ddbf82508dd91dccee467fd1625dd740000000000000000000000000000000011b11b3d24f44bcafbcb9baf62cef3f18b56ded696b73577375dae8108dcfb663d437e4cd9e44b7e6bf49741e058f8cb9a0b88d946231cc484550a87a548719f0a543c0698411f230a966cf602dc4de300000000000000000000000000000000073872ce0d74ea368df132897617aa8f941b67cf3fb395ca6c2f5bb2c551f17d68b0c6ef11e742206d6559796f06426c00000000000000000000000000000000156cc28eece7bed943c8410a44af112edd8576807e25701093eac0c9726f93da68a19c1d7b294f3ae6c84e32e7c2d5ba00000000000000000000000000000000050fe5987d5fa678be3d34c50fa6c5296f883e65ac3201c333b97ec0de00dee6187d2790c357a3f8822a174a534539a900000000000000000000000000000000177fee6e2d3909c0536acdbbdfc716f6ca19b6bfee7920a78ac9725c85114c69cd13152467e72270e35006b3c6caee8c74e3b5ff944bbbbf808f1f469a3380ee7dc37ebecdd8fcdbbd2f2561e0dcd68e000000000000000000000000000000000dd147bec9e0d1727c9d7597dea4a5b6b15c0a603dd1b586835580468148a502289fcc38194b2fccdcd8fdf0d8ec1904000000000000000000000000000000000186501fa4f3a20e80bf297e8ef1885b7d157617701839a3b524d61f35b2eb843ff0af13e253bbdef653a83e07a5871e000000000000000000000000000000000023eda2ed9d34aa253c8bf2f3b66b3c0c2551cc0e74f43dde2e429d9dea113a62572d245b44708bed79d662d9cba487000000000000000000000000000000001041cdaeb244803556e9b20db95f2a66830cbe47a68aea262865da50ab15ba658116657625318fe46fef393eeb6f3e2ec23064970a4ae4ae648a79edb193d98208418d3489e9b5b8517ebe99cc32b4d7000000000000000000000000000000000c27b1feeeb38068ee52b0fa440af2e3bcfd16601c8af983d259f2d15316b513ac3e89069bc141f02b934f2e474253ba00000000000000000000000000000000183f966cdb28f344ccae4cfda63ba6a6f29d00ab942ae7db7572cc09305e4f80c11305527b8ba38c40aae5f23165cf9400000000000000000000000000000000049cf59bbd6c26ab3e25b3cb94878271c73c0b4436573d612311feceed0f1668f4d79aad92360c1c97d60b540239ae630000000000000000000000000000000015f35eb8e4c40cb1297f7128d99b109ca75944c1943abe9158813432145a4a2a5663b55dbabfa48bfd9dd01907e1e8d3972fb60ccab83b6ce042c09ead82fea3d2cb891e21ddc5af7b5d8e334d5a3264000000000000000000000000000000000e5d9a671862733804f517dc9cae2190ef0005f26394e3161fbe771b9a486368871f4b1f10f405e45048362f437238260000000000000000000000000000000008100c6f96ae7af5fc86d9d91fbbefcc1bf5873dacaba9c3adf1b2833dd529d87f303a55e5d4098153377effd0f8114500000000000000000000000000000000010e4863a9b037d4ae6dff827a34be04c7f1627670b40e5cafb1fbca2fbf56af9ea6b24548db58e3119db64553d18cf200000000000000000000000000000000036a298ad5e8b32041a18e3f6c5847eaef20a5b63ddece41bd7dc4c4a54deb9c6d7002e6621aa01d78d64ec9991f68fbdb68c389b94c82f006fdc637696d8085b24897177d2992f504d4bcf5ff04d173000000000000000000000000000000000f62c0bad83c41887bf1ebd2644cef0577d793c2f3d67cbe43974f460a4afaf2e412fbf9ec97404e5e882ca0b23bd1a400000000000000000000000000000000191562ec9ace63ad2aae1f7fa977b9e0606e1da9775a978b2caafada4f6b3d9104562f2055fe037cd06df6093123a08e00000000000000000000000000000000156702c3feef1baf5ba202a25b9dfd5c1fc620e837501b0c5bcb85ec8b6e3e92bad1fc842bd1a0dac363e4bdf0fac87c0000000000000000000000000000000013a4b7e869ed9bdbf9671a5d8ca9145a2e97b6885d2a93b33f378e649e0e576be65bfe849119381057337315363bab2f4510c100005f2306f4b474d3843b4a79d04f0171afc5c66df70f631b0481dd330000000000000000000000000000000000a4b273438168494f0db235f535bf31893bb70f4119dc4741aa3c5e63e93b9a8bc001faaca10e37f36e130ef53853900000000000000000000000000000000010936551b148e16249dd934fcc83dee55279495c2a70d46dfc45945a69549657c3dd7cce00d8136e28d64b0c800344cd00000000000000000000000000000000115c053ac0b68573c3abd5f047b8fcd897e3d514945c5fe6efebf1921563d0079eadf32f7428ecb703d9163bc7811ebf00000000000000000000000000000000162e86af01daf552589b62be849e6176d74fa5da9b214a5cf2285802dbc44f346eaee5cc3d93a085740f74cf7e1b17e1dc682a2be4d67852d119795988c52230d8273648cc176ddc012a4b4da5a8636b000000000000000000000000000000000d77cb5045f7d4578621c76bf5b3db076661c72174508279280de3e92f0aa57057ab50180f0f908561a87d412636d964000000000000000000000000000000001853f9cdccf5e6e4b87231b153ea5257f52ff10dcb24cbaaaa95426d0231dbb355f9c47475d125ec1079b9bf26b23b560000000000000000000000000000000000fab825e06c2329a19de853a05c4bc65f16fa047eadba8e79607bb31b84ed6541b00f7f14b15687d67cb4cae0ef9c600000000000000000000000000000000005deaebb5f31a62fc0bc1af13da63d0af3c716df8c9bf00f1e831af5882b88974c49e8d35db2545747c85ac35156bb668af6b200fc8e6a57a954226d9a0254c8bcbbc55fd6c3db5cf8532323d4c50b4b0000000000000000000000000000000016faa5e91048badedcb33e83684d2670051c82b7a1d0ead0e28f4dddccb141a8ed1fa7606e4b6a3a893c55344263eb4400000000000000000000000000000000019b2c8758abe5d339afade4ad0c1d44d651f185f8a0030b81b136d5972510b353d43cef616ce04827d56255419831a400000000000000000000000000000000124b1e87f343a890fd690e384cd156da57f4f0fc5b1ca99c73bb0571332ec4c12d3ebe955e3ae792efadc1d5c0c67a410000000000000000000000000000000014cef10e4a9a41bf117aacd2fca5f1364a46b0c4aa0723a369fc6ede09dc76dcd8cb67fdf87ac49bd4bd9981a2e589647e2036f73e8cd5e42ad86914e192dd969465aed0c3b752986b84a0c2444c90b80000000000000000000000000000000002862fd5f38154dd452f65de0d3c1d54403cdd2a397ef416fb92e570913c543d3368a95fa114fcf48c3bb4b68895ba33000000000000000000000000000000000e7185443e5dbb656fcb9ed100949f8f7052ee2cdcba4f5c687a65a1b45bf66ede5c60b0c04845b9a870e004f8af8450000000000000000000000000000000001817be6d13cf2a67225b2eaf073e9f1614f3bd32cf5572766ace4a91f6b6be56f498b989f1c3dd3dbc9a819c029431dc0000000000000000000000000000000001cf41fe428b088a17b8ea93a653677705d5c024db530b8300752c6b100f2abe4c46dfc24afdaa2b3d53cd8ce0df1b6a70cd5c1545e76027c389645da1089fa88f675b5b6ef9217b584d7202b797f8520000000000000000000000000000000002eed272430ca3176988272e6157a18df7151bbfed5b90979752a02619ef467af8083208dcc9c7d926490b1283baa21f000000000000000000000000000000000a644f6137bde232c3a909b742d30bba096ef88b711ef100144276d0944487f9ebe8331483978a47c07d3a42c441310900000000000000000000000000000000042c67cdc10efa8301ae95d6d4f21cf152f04b235bad2dc5a61724cba64083f690b3158676ee6ef10f52dcc7061f7c7d0000000000000000000000000000000007018d0aed5abb744cb998f84140331fb2cef8d9e09c76176def48a85370c6247c2ac6fc726eea891b2041ad5edca7f0244041bcfc21ede8023ad80b6d4af4b2777c0204ca5f61854e6da34ff5e1145f00000000000000000000000000000000141c0edc966b7c845d4e68272c6a71f8ffb7fd8d56b7cabcd556a98422f830d7a81d123d701ce1479e84047328ac1f3100000000000000000000000000000000105c1164d721b6dfb05b6b69955b2f25db0e9fdb58600a3229dd516076087aaec05b837ade68bd2a19917eee7b9a22bb000000000000000000000000000000000da3dd97e693948fd6955ae52d493b3a2d2896dd4ad00a0b549d4d392e81593472e4f9435a8b7977f3d58e324c5b9af800000000000000000000000000000000068c531ddb26a2299cc584b5bbfb0235fd774a2447134c06e7de8b94993804958bbf1ee80728cc6db647e8a244462372ad7572da641373708bef008057aa5af1cc76ccb882bacc50a77b37d7047b1bf3000000000000000000000000000000001881432f4742dbe41bf774930413c98d49a781a48d6c64ee1a18f3076bc6c0e1214f92d5bc84ac65ee1c586c437d697300000000000000000000000000000000067e0a95f3eb826f3efeedc1882ecfa30b8b96c92f626aa324f4044ee74531fbfd50a221b1b0e0182d759d149d51427d00000000000000000000000000000000173f5be7098b756ea84f030e374973feb4f8811118ea6673db1db75ec6909303e571ec5a1d55a6bddf32fc80480cf103000000000000000000000000000000000f28540976a6ddb277df5951fe58e7310861af837cf31fe31c24f7b979f72ef1549372e7ea1ced15b655d24293dade7854b51c78093cafcb57c4c1f172d08257c379a9caeb5b5478cacb4887119a08c600000000000000000000000000000000188f296e218719bb9cabefd4f33d5728a1d280bc59c3d826a0f3b5338f92e6544a4cf36f1a493458e0adb246c01a415a0000000000000000000000000000000007dc8e4222c7ba78190a8e72ec7e6980e2581f51a8d6c41669b6fc9e16d50a2bf4d422af73398e76b2f39705eaf8a6da000000000000000000000000000000000b25a44523323301cc01b50d58726768c2cf61e691203dd34a0ce8d58fe4f72c1c33abfb2a56e0425fa9b7e2fe48e870000000000000000000000000000000000c6f11ea269d9061d2f462ac37401def1b2b28c47b84344d04d1f026add3237d99a586e3fcbae347a4ecb5646c8c569fae3bbf55186a89740af4da6c073d8c0e331542a2c972a49dd3bf65261dda6e49000000000000000000000000000000000c41a02e937f8cacc0be5d9f2d9fff0d6d4302fd252f32145974206463854b3a7d09b3b147cdf2d7536e970dc13613ab0000000000000000000000000000000005f9367f4e31f7e4d6e21664ac13d55f501f5368c1ca77fc439db60e1846861e6c4c3c44909469f88e02cd973499992300000000000000000000000000000000131fe6df7fff97f132bfcba1d2599a862c1feb514a05b4b7b0bccf49e00aaad043edae9346bf726e2eee498dbadf2067000000000000000000000000000000000e59044f0950a741da3881282697f4a1a522b026e493f6009227da4c0a963de622d5e421c30e0023f4118c9a036274f859b43915b15c509ab8930979312dea2ec9cfa9f679b004ee526aa5dbb25759a4", "Expected": "00000000000000000000000000000000144433ad3afca0a9581e7e87220a4944e26ef2eef6b887ce77d2a2559ced058e7349b36efa66c492cc75b014b3448ef9000000000000000000000000000000000267b90e45d7001edae01fb198d16dd37c43cadcd2ca87bd7cd1f0f65a95148144f5ddfe75d344eb4573c1376aa2728600000000000000000000000000000000050ade28b09b0394b08d128c089808021e4c65dac49d9fb45efb93792a4faf210230b650fc3ce810fb8d11947e9af5060000000000000000000000000000000003b1d7dd7c6d944d16724fd1bbfe0f53b6b50a70e133dc5998c82b51f817f489bfe1e0c361be36fa41f5af7c1577f2ea", "Name": "matter_g2_multiexp_58", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000a081f037738b0d812da43a907e7c624e331108ffb72104d82725b9c14dec8449f5ba0e8c1a3f1379cad2c3e7aa99f70000000000000000000000000000000000937fb5d8b3c258b7b28555fb59620f114816f0fad46818a5f100bf7dc3332a03d285eda18e31e4047cb2606bc53b20c000000000000000000000000000000001574e355b7570043bf36ecd52f9c4d9ff556146d81a1e9d088444805db9b3b678fb55774865ad34d21022afea2c154590000000000000000000000000000000009f70a5cc658cdab280ed65e13aaa319049b9534a222217a08168047ee2491f25a9d2620c7343a6426bc54a0700bdb4fa53d5989b63ee5f157cc44c684ccc7cb4c74338b12fbfb534ea33db341fa6b460000000000000000000000000000000015a76e89c8938b8a27e4857aaae8c942371b6979605adf774827e9438ef739428fc53b65d32e4e152cbc6a4de42b8bf30000000000000000000000000000000019494030ae0507eeff20b69b4913596c1b9ea6927157945c8295e273707013ef1f2cd08c058f6b469a6c99ad73acc28700000000000000000000000000000000122ea7ac21a27ca7c4b00207538bf561f688429999332c45de7545046acbd6d9e96d31f5f6a00595eeb212918a28d2920000000000000000000000000000000018b023e7da67cb8d9159746bf700f9e151fa60ba8f5a28b3739de005822929cd28c49b9dbb4ca8a10729dd24771730ff4d840680013af06920dd06bacc0ce95cf0cf79e8ccc0b10027f2d28c1d0049980000000000000000000000000000000007811c759634904765029e955c3deca648fba6a9da6433b50a6d2086a59e65811d52d41ed8ff2e9bd63a4c0828bc702c00000000000000000000000000000000182c86cddf5e20697462c829f41c7b49e7976880311b01ed4d12d7174340799f19db0f295263a2617182bfd1b49e0d1b0000000000000000000000000000000011824bc20bd1b27876b4f48aa8fe3063f826b6b2c3dd777fb8999a25d9139f218f6f288955274884ce96ef2dc6d34d120000000000000000000000000000000000dd310d5e141e4eb13380db828caf74f62878959b6b2df998bebf9306965f723fcd4dae7c25bf2f79ece3e8e9b92de61b67d661ebc9008669bb4e5cffef81a32baabd71667a72f1d202ced823f09c740000000000000000000000000000000005667d8c4f8dc3f4aa0021d1026a1d0dd0bc3576c49339262e84d20198fffe33a389d28ab1d782e9d19af761a2f097b40000000000000000000000000000000002803d5ad6393d7072e149f1f2ebf70cd8961ba3bbefd648916a8ac5a5eb893b71bb6015e201dc241537ad5890024239000000000000000000000000000000000122e1d0e0859b04143f23c4d2d2ffec09ca2ce5eaa9429dd0c047032d180bcdb10c106071d9f9701c006e5eb8ef88130000000000000000000000000000000008347a7bdb3b4f381b58ed3a128134c09563b345380ec948943e738347de5b5737540b57c28d00b9d060c60942446617ee495199ebdebda02179432d42d5d9c76eead4d4993cd09a93d46cac997716a5000000000000000000000000000000000b26aaa46a279c482fb395ddb84d5b4c9c70102c336cd565ca9eecf62cb96f59f634adf46af748826590fe65beea752b0000000000000000000000000000000012cc63256a9f73f450e86ee38c54ea78baa5bf87d3bc01320f7fbd85bf11e19f75d787b9b12b8f2c7634368a9023de880000000000000000000000000000000006392fe611835f6fd50229725d71d435f704f78cabd1b5569e1c5a89d4b11f911f0e34ec034369f972a80eb407938b97000000000000000000000000000000000f4ff2d6a991fde9093000d7bd9cecb289383d259346d83bc9bf5389d4c39c82a0e1d7deb84b90ef370e0a19fce28d2b3e038e473d6f965751ebc5f69eea6f37be88cf001de0c4e4b700823d8326f17500000000000000000000000000000000193752c40fa0f466f7c8bd26658f133d0283d2ac3b02eadd27b3e9681329307f91a1512fbc53e537f9e1025a3d68a7ca000000000000000000000000000000001106d751c9e1637f00e51e0be856405e6b69421d81bb30b9b8718cbc9cfdc36c80d2848bab0d5246da84f10b478fe48e000000000000000000000000000000000827a83f28678c4e39c4963e95c2404a70691885788e5457e149c0c45d4e8c74eef55223ed15cd75fad9f7209a6ecaee00000000000000000000000000000000072667f02b781c8e0a75d0ed8f3d55e668ddcc8c61937c80653e240c3a744c961055c782ca41b15211c0f1e1ba800bf5ab2af2590309c9b9177e4f6f0fa06339fa720cf1c9fc7c001785d7145a3c9030000000000000000000000000000000001419629aaf0baf779feca264d0d9846b987506125b0049ebc8b307c4e3ffe00da1284a94a012bfd60456a4a937b2e0e000000000000000000000000000000000119a801bd0a5a1c1b25cebbbcccc7d2bed9baa4995483f4ae94121a8c6cd0c3f90a26234f51590d66cc38b8bef9020d3000000000000000000000000000000001125bd15fd9814ddd15be0997a6961b6f1c05ce7944514371f10c8e5bde271c4b936d6537d91ebed740fbefe6b281a0d000000000000000000000000000000000982a2904a524b1fafc50d540506b8fb07c3b4978310bf3cf53ce570b1b05e746981bcfc06d59a78d170573b09347f3fc9551f12084ad7d4ce346f841fef785d644821b5c2d3c8db3145fc26e65666bc000000000000000000000000000000000b1da333e508ec6b0329747fef35cb926d922091d4a45eab7cb5358f20496c66e17e46874ed9600cf4252432c29aeb07000000000000000000000000000000000c757daad8f3ed7dfd64782548eedfe904f7ef3bcc11eefc4781fb37159d07825a4c9f3fdf9cb3d8f3944277bf25f88c0000000000000000000000000000000011160e21503d6fd61a2ca0212a7d48317186f259a987a17cc3eb04a6d9251736e4a66b739a8f3095684b7d91ce6f79730000000000000000000000000000000007440ec0f9197352a3148f9bb3d3dba9b1d5add903e48b50ef3f6879859b22ea0e31b46ea4ce566930d8853520abdd14ef5823541696ecb88d0c71e00a15282c40d4826220a202be09c47fd6891b93ba00000000000000000000000000000000070ffa4d522df8b9f62aaf36132bb1b857e177280a7b6d3af6bfc79b73ad3848241df18ca7f8993ae3d67005ead9264d000000000000000000000000000000000e32b65bf035bcb11f86c60a334622d2367797d0226761b58a7db8c7324fc4bb498a558eec509c2326fbd0e7bb8d3d19000000000000000000000000000000000dd291a760393c6e962818986727e5ca5d46544dc47eb49dd828c6f74caf0599e88c4293881714c425b0697944faa861000000000000000000000000000000000f7ead0be081467f3371ab92c249cea73dedfefcb6aa16a162c06e30605e104844c3dd194b4a89ad5230f596bef64f19e32d695dd02323d40ac1eb9452cc53376ef941237563b1ee380c9824a565008d000000000000000000000000000000000ca545b53836899e507880329799e4c1a1acc17275f5d71d87b9e41ccd7a090da854f9936254448c988ec772a813bb6e0000000000000000000000000000000016c9b03fd01394560497d6a03add63c034f96744d96a13a4ec92d28719018d1eba1465e4332e53f37f2aec4d93d4ab7f0000000000000000000000000000000007019f5201dce326d5a6a1ebecf3fe50e22335593bc9d3e62256351c591f0a1a577d916055d79c0b4abe191b6b8011fe0000000000000000000000000000000017acbe72fe30c386e463f3e9b35a474b902f6712b30af88ef340e6fc6ec0fe2e606c7e26432c2a4de33a12e35ce41868f5e23ff8acf88d18e53bb31476f10fef288e20e818431f9f0d2ffe1265e8ea8200000000000000000000000000000000057f856ae648279f2b6dd17584e1388e4dfdc9e870db48ee6ef5f58389ccd4ba17e074b79ae12b728c59e2f91bac5709000000000000000000000000000000000e0f39f4beddbf05fd700458448067b52c11e963b22603f10d697d6b6286b1449b1663e032bf7bea48f2051d8ded923f000000000000000000000000000000000022cfadc1dc399ef5f12afe1349d9274cd595a9ab6ef7ffdd68f8bd2d170a4a783ce0a7303878d809a16bb8073d79860000000000000000000000000000000007e301565124eb66d59a70897f2ac356e7b0c1bfd4e3b57e508ba0cb5c9c881f9de86b91fd5133aa2977c8e81138d66971927817449ba5f053d0ed1e567b53b1179c6b62a554c8be6764d7ce203f74e4000000000000000000000000000000000edf3fdbfb03bc07871079aa4aade538a97e1619b54d0692a7f5f73d7fbc8abbf680ea3a99325e03c0501ef174deedd1000000000000000000000000000000000b8c1b5d3c926d7da6e0583f67d981af5286a04429e857b0aa4b1120604f9c8c93f04e763da169137416dc9ec4839a910000000000000000000000000000000006ca2aa4c7109f043da9cd90bc801404685db802eb8bc925d9d098e7af3d9f95ca490790b2b1c77995c050aaebb935db0000000000000000000000000000000001f40a2090b63f94f93e8b61b5ba1ac62a37548342ad81a9bd99ce8339435a7d7477c3b9cee9b531a1ecdc85a72041555ce5d6f0e44a20d0a0e2f1cc523455b001dbeef772d84b2599daec66b285027f00000000000000000000000000000000021464dded318cfa86db1e4329f302bbeca7095d910c4260799cd2a60ebb20e60152868e67a48b86f44000f267d11c33000000000000000000000000000000000ae45fa46fc8e043c3df99bc0d87ffc5867208fde0eaeda782230341a8624b101346f35fa24e1dd67ab200f5d6fbc8a7000000000000000000000000000000000795b9afedbb128a46c1eb25c52a71375903adf7d3520535372d9af5023dadb1dfefdcc0cb546e9d218890123252946d000000000000000000000000000000001852511855bb368cec51c54d95b430259f05dba6bae53b5c42d69f31371c30cb611037fbd81393a896cbdb6240114549d37f7bca1a59f65982294755ddf8af7f1c953b6e482fee854e0d89e9b269e0e900000000000000000000000000000000113b883c6bc41b0673145bfeccda414af45efe5710f436977712e7227f38911cbae851dbe03928f38e310033458eed72000000000000000000000000000000000853e32773ef1f95a3936aacbca50cdd5eed3d08dc467d7ee834487e445fbdaeddb0df394bd0c91fdb06d2883c4dadd60000000000000000000000000000000013a7f9cdebb2ec37fad172d31a717f4b538a8ee74432c5a5e6410460eaaa3b5f24d223b76bde4277097e93087b7136330000000000000000000000000000000003d6f141b56e1e2e400fe821524017cd972678a7d64f660c313e6a8910b72b5ac04328d45945077aa2946931c8dbd11706d0535e3728b9e358d9ea82df4f1137db7a02f79c0cd0dd672e24092bf7f6b40000000000000000000000000000000016adbeb3530f6b451d870b2d8292a01143986cd9890c79a64764383575771b8608ea61beb2de87bc034d3b8a085958be000000000000000000000000000000001125d7cf83239e4341c286fe0c8739e7013b234814b26a079ffbffa329ee4705da81fd12f34f49d821690a11b8f83c5e0000000000000000000000000000000005873dc5c0baf0f3297d884ac7b652c749abd0405b96ba60fe396efa179a79fa55be76924b0690c9a528c605ad4f9e120000000000000000000000000000000000fceec23f479c72e0fea0d10d3394d7121bf1673250cf1ebe72eca60af82f232fbee342e2c8705434394d4e519fbb40f56d6810620e8da932c202628c2fa9f0a9f3fda3aa07c262924aa51685d2c9af0000000000000000000000000000000005ec966cfa28e105f3496f977a2f046fb206a190fce1a6062df0fa1946f274cde9f6fa8a71089af8cc2fbc2b60746cf40000000000000000000000000000000013c77ab66fa92a2411391d366a331a40accd120db1c6a656bdd92858826fcbded296293c13ee189ea3f34635de56732c00000000000000000000000000000000162795b6feaf6a63e6ea2d34f2bff2a4985ad26463b8fac69f8525eb0a005bd377fe7ff4aae820d361592d2d88f98f5c00000000000000000000000000000000044c9d5d3bc0d99693f5a0605ed467cca8b5dc7c7093294d14015b59bfd8ac6bd479b73ed52fd30d8bd891ed971912c571e7f672ad398f5c02c989b475d12ce86e6e242d36784308e56178f2a6a1517c", "Expected": "000000000000000000000000000000000c3bed2f51a60f9afa6655853ec2f0e9d46bdc1277bfedffc468d9f36cfc7ad9e70365fecc84a5a40d863dcaadabf22a0000000000000000000000000000000008c5894a4f93b02fa1deda8b556798fb7d71f53046ccc305588bfc00b68bdfc34b3f0bf154ce7cb50c9536ad45e65f300000000000000000000000000000000003699501ebb9698e98dc998fcdac54dff895457d2e4e0a0e2d65d275b5798dc016e921bf1f65fec0f284a563aee66ca70000000000000000000000000000000010389c73de7f6d860c972c1f09dd24137c898e92935c45c10565ef3da3406cf521647ef80688f6e799eef4879ca9a6e8", "Name": "matter_g2_multiexp_59", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000114b9c33bd09899c684e81a5a4e620eefa4e620c01c391a4df5caa75be462ec7ab027a9ae2c31d6643c48e3d75b6ced6000000000000000000000000000000001925084d2a1f537329e23c77b8a820c385ec5e12e4a145888882ec611e99b05b789d79bcab48326db4424309c24d1688000000000000000000000000000000000a1dc78c25cd16211a38bd0c70d24c84da1b83adb219e1b9c06fe6a6669d6e0281a155b4cec32d32751fff653aeef1990000000000000000000000000000000001daa74f19cce1086a87232464ba903938465da5e3e1f9ddc05a4b4dc13f1026e1b07af7254d515d2ad6960ea62dca1f77f9a79850b2fd5a281b22f52de085f12bd34e56808496e1c1388804f534d2da0000000000000000000000000000000018810adf0cc793c21726e9a27b7c558aa16b81af73f22629c478d293208a107fbfed4511d9cbcc25fbc2826bf004e7dc000000000000000000000000000000000356b25cbc7cf65107438125c930dff24b7786cbd7eb744d7f27967619d5cc02799451ac8814782eaf9aa331e6f8dbe7000000000000000000000000000000001164ab32ddbeb11c2c8baf7f311ffb01bcc367395bc7ecbe5642d344a8e879c74a554b3f9e4b6ed7db4ea0f872cf96740000000000000000000000000000000017704b1dfb111807d1f5d90c370a5b2968008a5ee9fd72262b6543c93fa168285c04931198f5195f1abca648722ebdc5630c1fdad9338fa5236f817bada168a737dd3685b327fb59d8a37329920af4cb0000000000000000000000000000000000a336a04a8fd8e18dd9a582da897016983d9beb0fdbcea6c88b7c0640620be52bff32afbe700599e3c08669c457b760000000000000000000000000000000001765fe4faeeb13fc2c007682c031ea7ff2899090e16a9a11959c5c3ae7881a1dd2c6d2b7f5f708a92349a2b0de4b92d5000000000000000000000000000000000e7c57db660133ebeadc2cb2054ab4ed16355466932685d4d11038e1e1f47b0349b68bc4e918dd48ef8e1c5d7cc53f7800000000000000000000000000000000169b629ddd7add588b91d9866a750570dec58662e43409031a5e25f1b2913c5c5a7a7cf666953c99835431f091ab1b140969599bed4899c3c47e1d4081027203c73233536cc6e45aaa78a4f1150a51620000000000000000000000000000000017d03e9855f3bbee719a15208ae24324ebf1879972ac134b027c9e03444a5736863bc55604158e81b38c7fd78ba4bee7000000000000000000000000000000000468f7c5478cc0faab7098dbcc455bf18525b56272c2d02cc1febc1825579a613edc6b455764ffc71c903a0704224a4c00000000000000000000000000000000067104ba5366e7e11bd4d516565d9cdd93d4390f2af3c1ef2ea3b1e84ee8e5c0e0fd8ac11ec9d2553e4cc13b277d473e0000000000000000000000000000000012e10495ba15b29c669cb9683b2fc7a45fe7ddba743b4a39677fbf85aa738480eb9da967eee69b02ef14137e102e240eddd438de35651328de7183dd38820ea2983488ba31d401094e59cacfcd1d031900000000000000000000000000000000078f8c17427847ddaa1665d206866231a5f36d3a7b4e8fa13910161566163006b5aa5d9696f423d0c44195de65326f21000000000000000000000000000000001613c465b65940f43c61b5e3c93313ae49d92728518d9cdfc57b49d6924479b70e281e724e04fa5f165b5999f1c1ed3100000000000000000000000000000000031741b6830c16d730619457d42767a51037fb4118e00bfd6cfcd8baea35ae76a5159bf1f4639fc2951f0b57446110e70000000000000000000000000000000011a618ffbafe4bad0a435d04084233495e5f7fbeaeb66d0d49a8177f562329b52a5ed4fdc680b791f273a7b0d3d4b349191f2b2cc76d848e456d07c84c0826a8861981dc84bdc671bc9b5882d387a41a00000000000000000000000000000000043c09eea638e524661c60ae3704fd1c18c46443ae134a0ab7b9a98cd398377febd9026c28b3e1e50de98766aaf0083600000000000000000000000000000000105918aa1476cf52f91b9ddb7c23ac18af3bd5269dbafc369713687010720affed6b12af9414cecd521cf0c7f5416c350000000000000000000000000000000019ab4a3eca904a15782f560bbbc8819dc09275f1f6d7c3b8e98aa0a96ec33dcb528284636b0f42ad0d503489d17161ff000000000000000000000000000000000a2abada18e79c548d5829991a65491ebcfe0e1a2c89a1e05f06a0ecd197797c5ffea0ae90b61f54c6b3fc844e0eb3ddaa76094782d0c06f2080d699b81aa04a60891046e0053d2fa757c7029df8f848000000000000000000000000000000000d457cb2c77acc8ba4b19ade0c724a2b6b0966ecfbbec8cbea745439b9bb7f3dde2febf9fcd6c5e6139fd7175e57b1720000000000000000000000000000000003154466283addb0d0b5d86a9633f8300960cbe8bf6a1405a3a040472542e9da63fd4f79a43d641a47c2b69a31298d3c0000000000000000000000000000000006599794823797f8ccea9daf0459b9d26e0d207f5fb95383c6b61eba38516b272e8ae6ddff2a9fa791e69c0eb25f3e470000000000000000000000000000000018be316bbe0416ad7deced1486d4e31490f5dc7e379c17542b7d3e9dc77bbae9c992e657c884db320cd51c2141a4abd2049a751a406657dacceb3721461417571a0104e11c1e00805becf71ee77eadf10000000000000000000000000000000007ba1ec5293d169b88ca4d2d92eacd51f0b8cffdb403632ea8ffdebc37f3997baf736771231335d12717cb45b51be31a0000000000000000000000000000000013505cc24222fb2ba9e25f5f3497653462f5b10bdd0dc88f9b16d5643a99ddd4a7749dfa6b566f41cd2da7c2b1ae93d2000000000000000000000000000000001465fdced698ca76d5faaa7e4faf1260cd5c4fd2939b16d3593e3588c92de3d003540ec989be9632fdba4ecae889ef180000000000000000000000000000000013a20cecd5e8f161ac70e40b8e9ca4c23e2b267690a3abea941c293b03acbbe4fc68a1e7b6d35b79ac46f65edde73a3e0502d56084d1be7179fb735e233978a5a3c2756d780cc0ea6a8aa92b1d1f7c4f000000000000000000000000000000001936436783f02f3a5307bfc0bd8c0a00ed8013508a440d040ed4f45b37a4e89986102964a328e93fabde6d9dc7ca424900000000000000000000000000000000000f16408b869303181b4b4877b554353b26a7b4750b711f3c41cc4b6682b2113cc772cf9bfcd0cf60e59ef29a5d0814000000000000000000000000000000000d5880e2ef94663ead736687ee725f7ce98fdc594230c1ac9e8345d39754bd616e261076aa5362776a6026129bff105c0000000000000000000000000000000006865ce3cdb5081e86535beb990d95ec3d75f67c7e881306607e4876c42714d627f8d548849aece4382d1c8f2b693bdc9787a6720b8db1b4f0e1d535833ed20b519a0e4d2e9fef75022aafef523713750000000000000000000000000000000016d941b6a0dc023fa2699c836b74e16c31b4cd51538f73fbb271d163519d4de1cb0f6ec2f8efde22c74ffb532c576b16000000000000000000000000000000000d10a7bfe9541a7b22d455f1b68cfe2422a83a070d93476aa0844670f02aecb36e9f41b9d66e8e9d0d67c0ba85c99f44000000000000000000000000000000000d7873f96d45fa8c9ba9cb4913a7b01c8e38876b6bb2a05506d23df0491bcffb42983ef663db85bc3cf755f476291a79000000000000000000000000000000000c22fdb83f9991c85b3577d1ed5a171f28460d79dbc6167b0c30b200235c512f999066eb1fa449115aab55128f8f2dde10b47b662e8cc8dd005bdc81dc6d98d0eb98f86b46c0c8f24481af9120e84a820000000000000000000000000000000010faf9cb9d0fcb487c9e86a2d2123105baa8691d82ebae8f5bb7d5ae7b7d8154837120eea86dfcd35ea5482a7ebf7f8a0000000000000000000000000000000014e40640eb6e8e38651a2eac05165f6cf5e0178b3711f34828766ff9db951e1348f0cdc652a78840dc24ada8b1c835c600000000000000000000000000000000129db7482ec62873591018a8399a8c5e4bf00e8bd9dd78dfa3d0b4cd1d93ce5ec7531e56d58b7a1cb3e58f062f6895ee000000000000000000000000000000000d8db3b54b6e71497faed107b31f5e44f328780cf01c62cb5ca00f99f10385ebb22a367cc89505640d1106a9ceec98c4072460e3c5349c8fec9944dc99762625262e84c70f10d0a92077a351335127470000000000000000000000000000000011ae9bc3ce04df2add17e57f260a72f88f19a1e44b0b074cccb7fd547035038d19e5f2228db46843343a69823decda370000000000000000000000000000000015ea64b6147ef76212bb5223d6d5ab9ca866799365683720866d8ce1117f60bd552a8e9981c095894258ca3c1bb5150500000000000000000000000000000000173bd5cb455b80b78951b15180fa7f8fb4725c1a12e5c53df1b9b31b45a29083e66c7116741d9aa93448c81b5e6014610000000000000000000000000000000007eba059855ab058c2066c643ef5268c864d09ec9962537d65a1686322c374eb5ab8eba4c4260ad0919dc18b4289a694f3177c4d865caebf1ef6565bc85e0b0bd51365a6f321e26b97cce887bc3f44d6000000000000000000000000000000001598471460ae082c2e2568602c99923193c913b9e803cbb7a4503ceff369e8c4bb3a19ad245c08192e12a2e9b3e75c4e0000000000000000000000000000000013b289bec9d97c529382388f7037749c10a64f915746d23d8f37e15db9dcb173b3a6d00bf45e67b8c70959472148321d00000000000000000000000000000000094a99f9b031a51b7d54f7b8865621b204c85d23fd66fe8ce007f0b852f8b5b895010745b2fc469abb670e38fbc41e50000000000000000000000000000000000e36daddab2134f65696ede36c50f90f9a1c56165e09243cd56fd3d9902d3c78cd85e7028f6dd466f6a8655da62ecefd393654ef7ad8687c8878c55a8240ae9df04805d3e2f194e960d5e498ae3ca17700000000000000000000000000000000050a818ce247367e8b57673d205d6bff8c650bcab7bf794dd32494669eff865fd4e05d7b4d35eb579eb475a3a0320ff80000000000000000000000000000000017ae5d612bdd46e1351dd1367c08c16ceb002a29832eba75e48d4c82e364f17c58525ee653a0940955b874da6a5bcfcf000000000000000000000000000000000eb2075367b42a0b3dfa30799ce1ab327eb583316d15b8cae21b716e6c7fd8cab96c67bc39e353f5e842e74995356c070000000000000000000000000000000018ca4b533da1baab37f05afc3ae0afe976e4f4530401d2f97176f5c73de3eaa75b8a34e8c6c0543ca0a08aeed28e478bdb9f942124a381b150f00a59e4579d0a2b7b728f62715633288fd03d01dd12dd000000000000000000000000000000000b3f4bfec920018663bb39c5520491da5c538f82138f03390c768e088bbb2880287196af937f1f70e215edd49d1872ea000000000000000000000000000000000037e7607a60cf235d8e4ecbe69d378dc02f0a8e40b7f23745e15a73fdcfc971cc8707d55a8c5b91d9a5f42c2f49c455000000000000000000000000000000000467df75c2703ccff1a01fa5bdebde210b61b5f3fa33e76e55be5dc953f4758c3a2c499cbd42b256ff5a2005949d9bbf00000000000000000000000000000000010d574c69050ce9e909dc23a76e9a2106870e8d8ce2a0e30d42cbfeea56ce3167535a9af1d453d4d8e6a450eff870638e6eb65778a328cf899f66581ac7a4a89e0e824c15573bc68c02cdaad89cdf24000000000000000000000000000000000907fb825f247c85d93fca36dcede9c22a409fa82fcf540593e8247c17875a1385fe009f0ff43853c404f6c96e2809ce0000000000000000000000000000000012bff10bd4162207870f6363342f2541804adc6a4e3f7b8be51d361be34def7a85fb39357c85a4e8df670fe39233bed00000000000000000000000000000000014f7e61ccd52bbf6d050c9d506751e03c8771b320872179a9f0161ac5736edc13bc133bda6239abba1ae09bd6c16f0c3000000000000000000000000000000000ca78624563584f8929d72668da70218a2da12b42c4b894108e6b103201372554fdd6b3bbbf2d94a9d0cf4053eb07d460940e3620c59504062e4e98b5d4c8cbccdb017c47a094d06253743c29465731c", "Expected": "000000000000000000000000000000000de8e87899b294575392d523ff6e153a7c2038302ac74574bfae7fb222558f2b4c9556be1bc2757b83ebc180ae710187000000000000000000000000000000001881c7688debe3ff795788c90397c3fe3d6d9f56da9221778d7b12f5a54d8c0a00e1a8d4bb9c0b1d578dff862516b5dc0000000000000000000000000000000014cdfdffbb956a20d8521ccdb214adab14975d22ffbac107b2c15f42e97bb823c6a3945a5b299d3226e2044e64f8d1ed000000000000000000000000000000000eb769b301cb7c0c976623badda4db8ccb18dc7322472b5fdb969393d5d82b3ce94bfa59dae06ece424bfcb88e24207a", "Name": "matter_g2_multiexp_60", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000164227fbb787b2d47ceea93faf1cf7890f48107ffae3628192235aa57658d9a2861db13fec0e58c347571c2ab0cd11ea0000000000000000000000000000000015478417b6758826b1d6fe0c562d43451e289dd50de31ef365ec70faf961ebb65b510c4788b6c7da2dda9cf56d3c8a74000000000000000000000000000000000f9e50d802ca8cbf80caec6489fbb24a2761db1245d9f7e820e6747bdd0855902ff211c427c00157ed9b1bffdf39eea900000000000000000000000000000000128f69ef5dbea5f80dbb9558a25f133b9ad77492250e0654f8fa5b55266f2fd26826a5c373afcd74990ebf768d6d8fd20f2f697ef6783390724e04b81d0e18dde6533eea9f72c1e10bc72c7b954659660000000000000000000000000000000005f7cfb31492dacae51caf4036d99d917fa13b0d2353bbce4e6547ea744b3a49b162deac2f107149ebc2f79e74828f720000000000000000000000000000000015ed4627efa9b318cbb52f518b734327f5d1cfbb097adc6184c5034620504181a298ac7e52759586dae2e107f121a9b600000000000000000000000000000000023e832638849599d9d7854d3ae18648e67e8938ebf606a7c86c3a7ea21cab8d4dd5d9cda5c482e05d351ea3ccd854710000000000000000000000000000000001849665396bc36d0301f4c9adbce81fd2f2d0c7f89925487d91a25c6bd0730ce31678694a319666cf42162608ef15a834680b934e67bd7518f0d6a3a809dc7faf845eb71d0247291d61053d5cbe0ba20000000000000000000000000000000012c9b607e29e35f260f3c4617b4217d5dbc6953eaeffaaa903710195e080d593972e7794897eb176aae3539401a483b10000000000000000000000000000000019cdae8d1d9035d1fc4b4db09e7da3c20d3b8777523155d407cc6565a71a6c951eca609d328ddbb165c2b5a3e6b081da0000000000000000000000000000000009c4629b67c1c50e5fcf316136bc645e9e62ffadac8495c084f97e32b0a3990b3b1019261f78de576ff7ffc89e36e2af00000000000000000000000000000000070a49e8892c5b523f5914e2341dde63127b694eef556de6dcff603da109a53b342363d9a854dda3d2833e25afd5b57eefc024dbceb522c02b88810ada9a814bfd085fb63d570663a64bc0658e5ad0220000000000000000000000000000000018d3c9259f70312c803dd6bac6488541f92482f7eb61ead71fa42bd5e2cca9338218d62835051bd308799beeed3b422b0000000000000000000000000000000005e0da6859601b6ada82b1826a455a846f8b4e54d9f22c3c639835a8a89e17ea2d76e2f49fb151f519de3e9adb78f0590000000000000000000000000000000010113d2fdc1e8ce0027b651cee6f9f6832b531d843db3ef7bf209aa00018715c1c42c68a82c53247a267929ea3c9363f000000000000000000000000000000000e7d1152af6448aca78aa7983013395f0dfc298848d86def6f017780e9cb144bbb21540a14a4d47b61d7a9b8c62376fc2c136f00c97a515076f6a0b63faf7e378f2cf04f8a90ac942fd70e25e683cbe70000000000000000000000000000000014125c81d4d7a8ea18004d798311f0d80c41c8e3a08366f686145e867192bbb13244f9f77217559cae72a150faba12a6000000000000000000000000000000000fdcaaf79c0607ebe9c8ca309d29d32284f3567a18dbbd23da9d96bad7269395ec2445d153711df4c883e8e7f7b02ab2000000000000000000000000000000000d34dd6636ef18b14f011fbeb62d33ec4358166f96f38a54c36b8797b51c1bedafa43d9f51fa4afcc2acc0cdd991997f00000000000000000000000000000000017337fab49d545caba55b763c23ce9bb3d3cc475f5ca37a15322e94c37825fc800cc7ee67bdcac66f9b5c22b03bf6558b033f2270ad2416d03dedd4bafb78ddc598810768fafd349a42438923ddfc930000000000000000000000000000000013434d32deb96edafc9a0e855281970b7c748c92b3472b34cc758dc3c17c4e6fdcf3190c910fa54a0259ef8bec75a3b300000000000000000000000000000000137df92ec14dd2fc02c0ec15a4e63547492154b4d4809e25f3ebbf24fe84255babfd6949770ba61637cc67e8ff299a2b0000000000000000000000000000000012fb20ef106e8cf3c79173e15dcdddb216c25a4de6797e411fd11d5632aef1304b36f8135c915c8c38caa2d778788f060000000000000000000000000000000014ef5cbe5711a815b9ff845e9201745f4117149b54ea3c6d1606060a192d513aa8ffe73425e37a42537773796b6fac8f202d0d506bbcd56c92bfc6fbab36bc96716de1af02aa166e7db2e2a0a4c19cd7000000000000000000000000000000000b1581a5def94e95e565bfd402cb84f2f21c181639c047d8f91044da84bb7854f5cb4eb3a6cdeb66569d99410ca3ec6c000000000000000000000000000000000d8029828f4ca245cafa7f396c25592ef08f6768e1a5b806450be6ca5b548cfb212d8c4787c3f15fe922f466dbe518c0000000000000000000000000000000000f51e01a044b6da437e3850349476437e4ff8b94fa190387099b17e6462040918cb2eba3b10d6044ff2123242005bd6f000000000000000000000000000000000991201229a856f88348381e1f2e282f0487e7daf1e5a4ac3854e66fa3d1303e3c20eb9eca605859e7d46dcfdd7615cc8329762dde1c4c91043a740a8b9639e83e809f749fc8c4853966cb2ea520620a00000000000000000000000000000000011f1bff5df413ade311b0bc3b46c4ecb11e386b886b71226987f14bc1a3a4b986412c2bfe8a4618ad5d70afacf4a3b4000000000000000000000000000000001972f49fa8b36d11d9c9d4ed6197261506b892ce6dfa932b87e686cb197560dfb8718aa413c38ee1bb771a5618c17224000000000000000000000000000000000e563bd240f5e18b518a792750c00aa5dfbea1f79b80a71369238ef15df9885d341d6901fb9168a2e74249f036e9a688000000000000000000000000000000000670e59ebf6e30b458ea505075840ed5348563efd536c31003d8d0bafdacfec7ba1ed401c616a3bab431a0fa71bb6188ea46572fdb37fe282203172c147715bf0a16e02a62bc79f33cbfe36703c95a7300000000000000000000000000000000071319574a93739586eda876ffd3be5d982e6fa04f5667873dfabfab83ddf603513394e0dbb9f418e725b02d2dc7b876000000000000000000000000000000000c6a8e0261da2ab499bf9a639a6e261e8c479f3f2b2d12992b41a3267e034c25373d4da4645626e6343e867466bf3626000000000000000000000000000000000045a0312dd5fccdd19edb65e24d5ba50e44689a9748ed9ec208320bd9eddf8d606b9340cd34ebf983e69a65c242fed900000000000000000000000000000000090b3dbebc7dd49e9f764e99c43b5915b67bdebd00d22c80e36e08873e5c5186bcd082dbce94f4f230b237d60cab7107b9e49472b9b74cefe5a951febe595b0020c43fd54150445fcdc4292c5ffe65f60000000000000000000000000000000007b04063dc315025b8545cef11be6b601fb4ae02597d75979b4946f3872764ffdbfd309f5ab3b36fe47b810f8320c1b40000000000000000000000000000000009361927d02192433a8d3c3d7871d76c6d88361774913067d16b68625aaa60f5a4ca19b6fd4140a5a11f92dec57d783e0000000000000000000000000000000012501f19b73fc6ddb4d194895e5cc2b89ca84defb7ae94f3170f25417965102fc195f38dfb7a2d88aa4b24e4a2fcaa4300000000000000000000000000000000141d0a0be60c32247f6cb0e0114251ac68c90fd43651d58c3108c728601ad6efc27c27a331a2f086d55aed54b3585fd1b6bfa1ec877010aeab030b96e80d2e27b45a93c6a99e2aeb3ccef22527c6e47200000000000000000000000000000000043f74a82ebfbbcf4abf3fd02eaa4483108a3446c9cf041bc67f5078d1774308ddcb3f918d7999d1e2c0876177cab6790000000000000000000000000000000000da7d4fa72dabb314ad8f68b61fcfa38627d1d7719bc07767f596671c58cca16e005d36e42413d03da3c643eb46b1eb0000000000000000000000000000000019f3f8f1a4008f9db1b604373d3566ae7c14a9147f80597a31839b83f0f8dcdfd829f7fa933fef3499b671867c3121fc0000000000000000000000000000000018bba4bfcf7629fcfa47935e36462cef4fa3751c7affa2ee2cb2fe3e3532d46ca1d247393ea190fb3f48077270d6a8b22810705458845232e851b33fdbcaab01966b8ed53b455873a966c1d6b89363890000000000000000000000000000000005a1e0e3a023f67aa7ab0109814f130a05c8c739036b98c70c8a8ddc1828d2cc4e2fcd16de4ef038a7373d15c78e81f10000000000000000000000000000000019e2bb467409b3dfae0b06244b4140de7f75cb105ab897d1ffb999c6b53bf3b60a3d11354815621c5d9f07962a237ffe0000000000000000000000000000000012e745499d5ed626b4762b57923bbfae7f1209408e7ecb8813a545c4ece0ec7c48a4015e0e264b47fa08fa82c39d3a110000000000000000000000000000000008acfd3c2a2e17be41a70ebbd1ca2cff2eda8a359e0969a389ab0a6fa51db5601b386dd035b26232be08d704a02033a7175fa4954e56dabfd1808f93d2686e0b4fd285bcb78b80d15e10e63ea8c7b646000000000000000000000000000000000fb464af51161f9c2758acc09d16754d4d8ac52a37baf2fb6ccd3bca3058bd3cd204de6c8a0bfcce8822f16ecfcd0601000000000000000000000000000000001819075eaa6d9e3f0568ecc2e507370f938a65169cea1ecc40c9cb4d02c83d7964254602e3d041ba0f93c24369fdf3940000000000000000000000000000000016c179832739a8129d2ef184f4d1231d24bc8d4093670a63d73771983152ec322b6a8c954565d61c2af76c4f6ef5e8a2000000000000000000000000000000000f6623578a4fa45614f4b74768adf65a753a35dacc84af005fa4d7328d733a09f12f709a7bb7f89060f60d4fac85780ae7dda7e5373d0e0afc3da1507416f47ea8b467a5b6c2fbde484aec8777ab7559000000000000000000000000000000000189724a2a0723e7727d224ced126e4288f4743f6855b035722f2aa36cf2f0a6fc23f6835c25222b670c15248884451b0000000000000000000000000000000009a57d85140f31ca58e38b4a99c4ef103f0a4af0d5546d416134fa8adce6ecca6588c3c56ba06b2f59015acc1a081099000000000000000000000000000000000dfc67b7644851c3e928ea33aaa0f745a18983edb7488b148736e81ec0c62345c11e3f0dfce729d893dce27ea249860e000000000000000000000000000000001712009a81e06a85a225a46fac056b139c8da05e6b72074ee4079316e490a06f51c62241e380909b86239d867d631be16aa731f9393d2bb32adf04f19884dd1a5e7aa36e46408b847222a153da95aea5000000000000000000000000000000000976746ae4d9325d5e8300b57ce99650f28055b5e020700ee5f124fa76ef3bdb9923101c3a1f46b6985b8203b4e8c60600000000000000000000000000000000057310c3b6cff6c849938f533b401b0cbe10b6ff3736c79a968009b2c0b90708b6b9a98b8e594cce09c579a64ead846d000000000000000000000000000000000d39511e47f33e310332178b8a0210e76e4d4c7408ff5c2374f5e7bde8335525e03897cb3e2bdfe59bb76b21cc6411df0000000000000000000000000000000010c46a621b7fb2e7ceab8943b3371475d3d6f132fb658b8c6bf299888711f1b344ebd4a5793ffe6a7a7eec8c66c80303985f367919b0f3c667b1c1cacedeb0be1f9cb175c899992ef55f14e9b7aa6ad10000000000000000000000000000000011ffff38891ee56cb1fc062d02f6c9993100f991a556445b5ee1b1b0d56d8e64bc6eea4d7f69a6b6dc55ce7d8b4ba300000000000000000000000000000000000d6cdd95d1ab2a11ab424d7aa596cc7e5de025c57217da0da143887d7dccd6fda0addae7c2fd9e0996bdd0d23128e807000000000000000000000000000000000499b3e69214fdb4db7dbecd619ef9c6b5c8343c808e4953f593cc89adba02b5cbc56a5e7a3046c6023c5cf305e54e85000000000000000000000000000000000d267e21606c16479065e47da8e3c058cb59f55a1316a87117a73dbb067ec26f406eba6a40b30ecb00f506bfd3c32f4da3041cc52c6f1bf62dee4c61b1c5e35b72ebff7e8e89b05353388b551eb10010", "Expected": "000000000000000000000000000000000650fe9f3cb3620e0bf1654a7f1dee503b79fe2218739bad608dba9f1e5330f325b4fb7c340f118eb10dd0776fbfe63c000000000000000000000000000000000bcbf1c6a684dea5ad6c1a540b3525cbc64c7c431f37213bc8b08c8d8915a331c07bc899d3a2ea72a9a4bb2c539cf56b0000000000000000000000000000000008fca1c364333f558c7284afa1be486e84bb035b049a2108b0df99395149de83549de153a784e4df2b0134317c85292b0000000000000000000000000000000002784cc1d11667bbd0759bca35a16a1baf49a21765c6c2c3bcdd4fc9697ef20f1274be5caa0f820d37e843bc38c68957", "Name": "matter_g2_multiexp_61", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000051646993c3aba532988d7baa07eaabeb8366853436b8b19c0fe3e14ed45fdc65448d749adf745291ab5ee62d4e824880000000000000000000000000000000002cec01290d8e51ccf751183dcad20bac20b8231804a2b6f87f886aacb61d31b14f2335629e97af0ae0546a17a4cca49000000000000000000000000000000000762afa7b94ed580fd07d5141a8e1299c6ec439bbfc6c1a4d695d9aba4ab5d6dec93dc4de47096d72e5ad87d879eea190000000000000000000000000000000014769208ce8a9682c8e0340f68a0290a7782c2b04e3c13027f0b23966eada2ffb2156f6e20539738535fa0ef097f78d6709a2e80dd96eb12edc481e3d58893bd0d789a499d5289072d58c2ea80b036cb000000000000000000000000000000000acc4e3ccc3574285c19d2545839d1da9db6770b078aa399262b7c91a7c41fb4c83fe7dd0aad19f4e3eb2b56273f664f0000000000000000000000000000000017851c99881677b89956fcdf1b8c5ca5dd0997d810f3fb89f7378dbf7964926cfde315f8722531d6d715b4932179eeb40000000000000000000000000000000005e374a4c7118a76e59cdaadebb1c4e635b4dd18665010249f3bc78d559455d27d547856573e264c98ba39f6f3abea69000000000000000000000000000000000a532979cfd5263c774f629027f7624799dd0f9d6a77f675d790a85fccccad6e93c00ff2e5536b8e9a92443af14611e69ff35bc510c86a9e72c3e9c6b49d2abca546f7a62330156ec09c6fe6847a400e00000000000000000000000000000000056f109801b7a4a36fcadbee7219c06ac74e4a3f7b81616076c33ba2a71d7ca0776b596fb25d29992fa26d416272a4b4000000000000000000000000000000000c02d7e6ec50b778a7ff36fbe5751ba32beb1c2024b17bd99b46239e6dd5a708d2fc689e8e8924902e0d80287cdbd6e90000000000000000000000000000000016f18df97f48aba4d1b64e71eb894904d02ee7f6ba425e58f38a08542319e2498cb0dada8dbbb81bb398c9c924ae44270000000000000000000000000000000017dce98b335f536909ce01647aaabb918942ba2468d9a07c5516cfd347e1baa02029d39de1b2602932630e4819f2f00f391dd27628d0808d4a0773509737597230d7849418540e1fe4498fd70d39d16c00000000000000000000000000000000005b23d6f76b8bd4f334e91771383856794d1dc65b365fbc0c94f21fff049761d7379f0d512c42ce13f878e0661712d100000000000000000000000000000000009dcf70c16f524ff540f132b35074cec6ed7dcc1f319432a0dd09b3ded0778ec9ad0f05d67ecf3ebb7947951fc4b25d000000000000000000000000000000001075fb15240d532a9543dc59cb0098cbd03da77c3bf85a0ef8be1560958f8ab57d3777fab5836ba98d67c721a4a8cd460000000000000000000000000000000003511525fcf6fe224eb87b13999d2548b6b8bb8069fd354f298a025b04a33f48be72d8e82a99b9aa34ce5ccdc1f1a59c94f11b10e4c45f15d811e3db4b947ee6414e262965d7b5c23a731b019e63d5130000000000000000000000000000000019039c69d52a66330d2d8572a1308bd88159f0383c041ee7605d0aa86f1d0fe3e884d0a2ad9c72405149b5fd204ec3db000000000000000000000000000000000942163eca08672af3827dbd876b9c1adeefcd5ae74a2768fb55f1e8b342aefbf76bc6546853a2b33e26fa866e60a4e9000000000000000000000000000000000c60c6bd103ba5bb5323b5107373cd8d706038bf5ec2b367a43bab72411523bea35985b974c756184c346626ab2622d30000000000000000000000000000000016c4a2fc8a9b3c54f65cd150c80a3bf70ae8dbacdcd37128514b4a881239023e427f0b0c8984ce219207c458bb380da970f7a0ee05cfc3f63d46a3151c20da53604628bac70d7b521b3be65d7b2abedf0000000000000000000000000000000003e3df9a8ce220be05f15904a3321a6805ab68bbd539479be56b2a870c3d61234e9cda8190bdc89f48e7f0dd9374e1d800000000000000000000000000000000040446db3ec43e3e67dce62efd741a4157e8ea2597a143f7d6273b66c7045daf31f72397b4b9d374328520893157c1f1000000000000000000000000000000000c3a7dde5b02df5f7c1e750a9ee5314a580cc6ed53d326a9157b507ebd6c2da314c37a7f1837f7fcff7e8754ab603b7b0000000000000000000000000000000005e617ca4eced853f8f2e9fdefef810c97eb27d5c8bd06c5b4ea50c03761c01e8adddfe27d2d72eed8cb25ea7514a4aabd991eb5e8ac8ad7cbf8fe64a5889b715a2409305f2366b278adcd2144d7be8c00000000000000000000000000000000104ccaee210aa8196010a6478702a54cb7ba49c80a98ecbf5c0920408ff8b4a7568212bfbf3561b6a7790520bb73bd42000000000000000000000000000000000870ddd51dcc76c8a97ac4b4f23819df48dc8a8798df0450d7a45d273f830c908541dcaab7b066bcd668b289c846ea000000000000000000000000000000000012fdae32b020a346ad5edc3bab360fb5ba55004ef3dfe5f437e841b5dd7284ddb3880051956c8068e49a3fd165143ac50000000000000000000000000000000019081bf768dae314fbecec408d687df5b6ecb32ec24b41f9febd583c05693f80345e6b9d81322ddc72616c1cc39a86811a9caeccc2a2058c2f5a271c09036d73320f9bcb31b7296a796ef94ca4599757000000000000000000000000000000001316b5ce5bcc168d76d2c862230ce604d02cd3d242c51c250bc6b6fe5c380c9e83fe7041049f2272481ab38f44648f4700000000000000000000000000000000079acfc2b9629da9c9f3394874e64aa00527de21e726f02db180f86cc0b9a97138c2c567832e287635721ca40469e00c000000000000000000000000000000000e11807dcd4ac69fdcea71e3e6a93dafc27afedf12c2998dbbb2e4f33e37ea736df73af791eae69bff84f3bb212bab47000000000000000000000000000000000e834a34fb63d9df68d683a26d79ecf8ff67066586e5f760d4468ad196c66d4ebf8605ebfbb7bde201f47b35cfde3a5d8ed4eec02c2af286ae19ad5f05642587cb9ad93196756d269c783a11f23393bd000000000000000000000000000000000990f115519d2125d47b925b613edc3303110e9040fa705211e0d772edb2e0f7f88ce521d1738a5f65c9d158e9d360c2000000000000000000000000000000000bb951a16decf9be8381d0c88726b53d90bb32cd8aeff962d48e43863e4eab1839bd80d7434c7eb808bbc0e32e92a4290000000000000000000000000000000013dbd5bdb7caaecc42ffd81f14be0ff3d8fa228ff121ed4f2f3ad5961fbce617d7cbc8133fd49e03caa62f7d1567541b00000000000000000000000000000000195fd9b85e19d0e3e1c93bab0380cad6f6f3bdbdcbf5c6ec32b7de7972421d0065cf0b265f6250c02eada67e95284bce26f20eee9bd019f9e0f5c794e22e770128737198b5f5dbaf5b7d18040443a0bc0000000000000000000000000000000009ca977266277bdeb985750df47353a6b81c5f0c473eb3369d25a01df67610bebf66a6de5727a465131404025e90441a00000000000000000000000000000000054410a13287ecf4aa18f543916fcd65b15cd5d54617433217b0a2b91a79fea764b511b3b270de3e8985e8f6a2fd8c380000000000000000000000000000000009a9802a03a7c9fb63c1eb13972cd42ea2df614a0972b914c4015c2e8630af319d12fc8108b4c88db9508a9a77d9e57d00000000000000000000000000000000094d83483bca296b20b7bee124f538ae9c659a84541f5c9d9fd22e98251d2b48051ac55ebe07bcc9d2e9109f526d60a6c470a66cd3428a44a7d095ef410126257175597a333cd36ce6c9822d1ee9bb380000000000000000000000000000000003f2d93ddb6d5983fd5521c1d1726addf662af0945aee54788855037f47a013d2fe595231792a05e1259c5e5a8c553a900000000000000000000000000000000004f4f4e7df5dee975fb440b5a217c27d9d1eb83a5ae280a2b147896f6bb864abe04459c17ef56d784d3c4a0b7ad3f3900000000000000000000000000000000069da36057aaa89cda458af4ee27fd9ec969c8f7612cbb153da0e010d67bfdddadb2941cfbdba8c43019a9f1aaf9c296000000000000000000000000000000001545b8325a80176ea148a3d9301debd7046f33a1b419b4ed01916a3d0a072037fd617d96e0bad32b208983ac3be7dda4e53fa8fb708204e619c221b8ecee14fdbcb1f94731ac2c858787ab33906c9269000000000000000000000000000000001536a81b203df2640bbe7e695b5fde186021d21685f24c25966cf11dde554d49bcefca64f16697509a9ca86e58b75eff0000000000000000000000000000000014348a2bd4907cf081f2f7bc944a98d3fac671abde029995377df190f7f60319b8de1698b99be39c821328e32a449c760000000000000000000000000000000000e18d4da3823addb2a6cef8336c83f99f390e23d7129365d57035d4363aac7e9c4da9f8000f086f7d2206666f990dac000000000000000000000000000000000d6ba54e2af9afa57ff4536a35e9b61c8d8fb3d431b653a0c66a2a4b8f11d9b5c45389f894d64485233d4183895921f3abf8de43c54ed59b936e1d55032eab5c9d9e04e83e4696d969c24167b4239f62000000000000000000000000000000000d88d5719e07e2332c54ba41f330c7763d2b2b7c4140d19b8b0972fae6ef902415de5f2abcc2342fce24d3ed8ffe156300000000000000000000000000000000163aa2c768eca58194fb76822deffc37cefe04ceb70aba38a51f507be7cd64c0755abdc2e49e7db234cd5d68575c2d7a000000000000000000000000000000000e443d9953468b8cea4eca4f5968e214888e2b95bc20ece39483ac551d4e180c0b0a41c4668c8ddaf761a0ac03fbcad3000000000000000000000000000000000691930530ce86a1354d73cb21ee32d968e6d89b12e5a09a7991c7d27dec302348af7f49c3e0de91e1a1838aa11651e795f59041329b6c3e6aef01d3410836852f79cc436fcf23199e0985c56f65c4f0000000000000000000000000000000000d7c6f9d4aa794f34596bb9af4d62363462d9804898ebd7c7db7544be1f46b4bde488ec59004adaa0cbe40aef525ce3f000000000000000000000000000000001094629b1428c4c284b7a64d0623e10ca0c4d395bccbfaad89d1a737a3887c10b714541f2681c33e674c3b99a36b7a450000000000000000000000000000000000d6812fad9c5ea365a64ebd3150238349d88b76d041ccaa7e637fdfa6c715d9d6dc3d3315cb95fd6919fe419d028783000000000000000000000000000000000eee5cb772ce02fe2a4883008f17570aebb902ad7c40b4024a5b24ff75b3aaa2b54ace6fb4601b1c62837a20204194dd740e4a207ab5dd4a0621fd65697f5d30b8ee1440a5f5c5e74a0dbc6b6391c1b0000000000000000000000000000000001026d21e075fb8921dd849c98252a565d39ca9f5a62a825e7e3e77ab5be6620e76e45047e51350c48d9a4cf98a1222a9000000000000000000000000000000000f6459a8287bb2da77404a515dd7a35f46a4aa49ef72cd2cdefbc5e5242872df5f7b7aeae6848d59afa1dd142ae7caca0000000000000000000000000000000011e3545151d4e0b034b950cd2f1a3fc2d29e9d53250ade2482b7ea6075dacf7e8e777afa1e8e612b45028205235265970000000000000000000000000000000017a869d75144ece603c04d39cb56a487895cc882fec613f40f6a66601bdbbbb7748ec755553257d654d1558b1104a981f49a3f82d25c6e0d69207e6dff010d56f0d99b28fd986c5711878dcb6665b1f50000000000000000000000000000000011602a23c9b5cc091a700114e5d3557bd4857c4fc44cb8628ef327ddeeb728927347438f123e2011f9cfda9b6dfc42e4000000000000000000000000000000000c4fad264ca95827e9cbb9783e36cb0b683fcc33038d47bc7ab6b65998770325588e5b910e811cf7d61fce13c3378d6700000000000000000000000000000000009b4711aa67e84434cabc289a78fae48ea86641a162d48b79bbcbfd56237705dd2d1e9ba3a18d737eec29eb8e940e58000000000000000000000000000000001160fc9e2a488ad9385140bb62ab48ee613c2284208cf2f92912e1b973ff81a5d3de338d9aa6881cbe437907890258fc8390fa1b452f887ef3afc7129ad8ceb9a8397f7625c2b249d7442566814ae0a9", "Expected": "000000000000000000000000000000000cd0d8c746ecc8d92fcf2232793282d7e0e17e0ec27ee851487eb7788f590db3487296061075f36c24f67cd4c4bbf36f0000000000000000000000000000000010c5e1d05070c27f19c228813051c6a830254542eb71469664c842695b219670dba8ddff858e2d147019847866f01084000000000000000000000000000000001799ca7d8f2637da761622b793a3ed3317d50b902a1cabefdfc776b0d0ef88b707b8a5c36786d5ede3d8a381de4e069d00000000000000000000000000000000129881a3b56e0014bf1dac4775f509f309c33406f2cf22df9a0ccd15c87ea48a868d4437303923127bf580b8d6ed0a8f", "Name": "matter_g2_multiexp_62", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000000d087c1b98f8c67c1bbc4389f21d9dab02faf46ee4223c609e7b9eb399132ae168bc12847c580f58edbb9255dca3b000000000000000000000000000000000065ded24bda39d2b830639fa511bce8dc770eb95e349d6874ce63b3355d23c1da3ee9771ad44e57c6c661b7453076fe7000000000000000000000000000000000fa3b2ef40a7c3d41f0c3a5f86afec252c6ce89bd1bf1f2192026e22fa256365360589c788753033658b1ba151797feb00000000000000000000000000000000105040ff4dc2bc435c2a82e1174e2ee0b94043d69074f01e8ed013da8c431f33c94a438a93b06774411780cdb72abbc8414ca9894bc15e6bca798544138689b2471f8171a5dc48eccfa36c83af142b7d00000000000000000000000000000000129c8c1db08ccd0dadd59b04df67a91fb6547d97ce23e59aa57cd3d38458e6baaa67285800809856e7e264d812e584390000000000000000000000000000000004a0be934248b4e142fc51745233b6d0ab2c46f53a8f9d4c84981e5eacff146ee6227de289c713e4ce24a4341572c9d70000000000000000000000000000000005916d14a8592af57a40418b10376e8e20f70929d2ba568c1fb70e343a1dfcf3e63c791cb639bec49c50aebd2f816fdf0000000000000000000000000000000018682c66a461a69b11d7c32f7aca07749e05a23fc46547bac121752aef64e9bb98a274d15a14faa93af8f284790acb9b99eac8ce85a1bc70c725a2f04aea3749d75d22c0df7c0755a5e76ab4d82ef9420000000000000000000000000000000001552053742eb89ae3d0b95be919c84e53919c898ada92d3eaf05605a19ac910091fc08a65e9764f3108877c837d478c00000000000000000000000000000000118e5d22f6df0e6bc7447177ce06659f94315478385372046b649fa6d39fefeeb492e6623e0160bc47233f4d3143e326000000000000000000000000000000000dd02c30cfdea5abd3550a9f28b546d82d5b3043f012de622d892062945847748ba820555fb811fb3382791ec43ce1f700000000000000000000000000000000050373898b396d9a641e2f2ed832c7619515fd9070852b891b4ce0b5bb5ea8b5e24248297d53e9db7cb946e76c4433fa49b25140d7967b0438e49f59a6b04b75bc8745b84d7350605be548c6b4b3aeee0000000000000000000000000000000006b465f4b9d60a3a14e119c54a7c35172bd648c86a7cf331e80ba849fc87b9dcd48410e3c9a07b634e83fc7dd71e5b9f000000000000000000000000000000000283ad9c77f549042f79c47b8a69e72164f0ee77aee50c20519d2b89029c63ea86dde2744cd21eb5d37e896c3abbdf56000000000000000000000000000000001668b08a87787928afe92d941240e503da07b646a34cf82ed09d4c2f4d479aa24358c8475eebd9bcfaa6bae17c430cfd00000000000000000000000000000000150e5b28bd901f7a2a9af44bfd6b78cc84900dc05e334de306f9a45f1e67708adddf4dcede8150a39670054f97a643436e30a51d55a1ac94089d0f3217c3a2182da6b02ce70ce7dd8e2d4e938bfefa9d00000000000000000000000000000000060d75764a92e30e80e7c1a6df1482585f4de901bbc36dd9d8978a76c12c739f85a9ba16741d0b19ed480fe2dc331e5b000000000000000000000000000000000024fd15c9e5b8872d2e9dae9ae96102bfb0e31d15e92a24316818862dd8ca7a6fef271d499fed5e0db6dfebc4c72e0200000000000000000000000000000000058cda551e1fcd701c6a3880b276a2f7536a26aa366a6425a1c42cf31eec678551f489a27f23ed5dbc76f19b0fbfae43000000000000000000000000000000001152e2cfdb584295563af8120c523a9f4c01cf72da64fcbe0a90a284d693a3089f299bc760166be062cf9f8efb6a951ad3da3db6492ff36102747d9d663bc6e9cf8f75b1cf77044989c7af3f11d66ae700000000000000000000000000000000116fc24e980b2e7ad6bf17bcd7c4f06e654bbf766ea0238a66d738bf3c2d41c8c63bd52f81553cca5fea91f5f9b74a2c0000000000000000000000000000000001078f19ecf785a5e0d3e764b7d6ea47b2d077b5eb222f4e6a9451f134ff0d77a0b9a3b53caf599705d131e3b17b6ca9000000000000000000000000000000000e44c07f00a1f198583a8ffca43da45d8e54e1f2a85bee7afff6c1c733b5d0b5712961c4b6d344869a8e4de3b34218e000000000000000000000000000000000083c78b3568cdf808b75d9ee2b03b98cd516bb16ca8cc35757f53f12119747bf6b5b0605bdffb2f079cbc69e99ee0bad6de8753f3df8be42b6d6ab578096426f852de4ff545d2e4ac12c3943b044b43800000000000000000000000000000000087ded6945bd6fae7a0aebb1ea68d3cd34588035531a6cb00fcf1b83e06f7ec21cd3486580165c1364027b43e238e34d00000000000000000000000000000000005a2fe8a9871273bb60cc7ebef44a361300a1033f3f0230a731f5723fca124ec9d305cfde45802482a45942154398cd00000000000000000000000000000000121eb94a41f9e133adf082ef651272c178d780a1c31ba8797f60a208ad36b4c703c9b6c08be845f8844dd14d6406734d000000000000000000000000000000000e5e3da7c91ab4cca1c9286020aab9795e64e667d55a5a700241f9589aa3519639f168d040a0027ac057f334a9f740aba28f7ef4b12c5097a15fa6394a4dcc3ceed6cf3c6240ec2ac949bc21a9f6447f00000000000000000000000000000000041f9117b426938acb40c905bbcba443c043bb55cf9b876edfa2ca051b6354124f0fa54d6a88ea172c3f5c10c6d921b3000000000000000000000000000000001828dc0b9533274db6afc802b2fadaacf57f28126094b6b9038ed5f6bbae0112c873fe5eed15bc49b970461abc2f5c3200000000000000000000000000000000107df6da02f106ae47718959aeba7b4fb4a8f0e2651560e2f2266a62566e13a5af86430b8800543f5eb6b1e96be79c69000000000000000000000000000000001628fd4a598813133de75cd7c96ff3711b6bc826806b96d07e5a89cd549592f0f51c84aa9ee0642cffae5630ca1ebae1a3d0eff3368b10d00566f35391bf43c9d204a4444b7eb91017f1b2d8a762d90c000000000000000000000000000000000e8fff44163cd9c2a4e148eef3cbbee19ab8f648da1a8d438be27d2b0bcab393fb7d49e096d9a7abed3d8f82c11c4e03000000000000000000000000000000001274335d8bde3d14924f8d7ba18fea82bbc85427892f18fb741c8ecc5f2d6d7bee74c68058164c55db3cb8da8597bfe40000000000000000000000000000000010c7fc728c094e47569f0e75446c399d20a1239b511e34d8d6193dd32df607dfaa4377a1825b3892a9f74ff4efa0d9df00000000000000000000000000000000067d904122a6581b5d5a60acfe8156dcb6c10ed083840e506487b5dd9117927663e0ad883fb91b4914778ae082de0a7eb90d76e660389e570bef756e9785e39b9748aecd7a34556bac8399aa5564d12d000000000000000000000000000000000a909706e3ce45c86f2c30de5e820c8c9eefef207e530fd504511827f5e6422714d3f4224afa6bbba22ffca533d647390000000000000000000000000000000013ff61472ddc0d70207692648087c283763ede668ae380b0b9d6ae6593498b0adc9d4e4fcc73b5cce250e7563f7577de000000000000000000000000000000000a81db69eca785373c4dcbafd8635b23a9f41265e91152f309fb2945622937e65b5c17656abf8aff042a1fd1e5e50341000000000000000000000000000000000c66269c3ccd9e91766d1a640789bde6de752d08ffe3b2955df8dad3d2a0b6cea9013af235cbfbccee8271a7242e310614f18dae096e4de75de3da284a5755efe51e912e180020a20adf1f5de43cb51800000000000000000000000000000000181f3f4a16696980bd0eb9bd10ff1084ffe90bcb65f12f505b25f0a26dc1d4e16987d486b2c0b117fd6f2e356b83a5250000000000000000000000000000000010d7be6788da3ec56c87acee68ea8a03e7d467f816060207bb163dfcf8a4e7721651bf2bb23d5bc390d50fb1ee6625a900000000000000000000000000000000196c1ac817493f51d9ca891b55fa65ad5192df83cdb63eb1a634ad54e2d627f7feaa68780418f5354e6cc09cdf2f6c5800000000000000000000000000000000190f36690b8d36f2e295b9625f23afef9d9babe87c1ba0303f60c6d44ec952ba6bf8356469cff9d952f8e26bdb86ca06e32d4645ce0172000fd74f30937261de89753caa716dd03a8b3269747f2349a1000000000000000000000000000000000f77df606f0611856c449c58393f4ee7a6225a5bee667382a48f59dfc747736a895d598f90ab26002dd0ed3a5a8f5a200000000000000000000000000000000012aa50d0ec440884fc6c2f7a0e8db8a5e79160f0c482209ae1a1aca2b9dfedfec6d6ea09252a373ea57905130220a4820000000000000000000000000000000004773f46165cdb19cae49cc42663316df39586c62be5b827535f138e1fca8dcf62ba42ab60ac6dcec85e8496f32b9eda0000000000000000000000000000000010c91923c2c7b3eb2cd9aaf0455c0eb035e38e5352d218b07ea23f50040ea58fd548b373c1bee9113d3d44fcb25f6ba08c8722e3e929ba21f1ed6c51fe5ad4940fb13d63e0293893135d0da5e6e0389300000000000000000000000000000000044b95fd5f0e049abfdc2adc699646afa5b0f64464779efacce85a5279477697090615933069992bf30036c6ac70dfe50000000000000000000000000000000002778e7dacc5566354c24ea1144613a5ce8a38eb56d53d230ca145ce83d5ed88596afe243df22cba10f423e64a7c103a0000000000000000000000000000000017e87cd2752d8674c373c557ab2b922e02620a070aacf6f5b3d3d07ca35d89ed2666da7246b800717c0e4763dc35f5f6000000000000000000000000000000000a3ed312e5f309eafaed486629d953970cb73f839bf30f506c2f393df4c283f299d6c643ae6c229430d919e8aeae8bd839bef6ccc893f6eed62e68f5f2a07812f2d3066b89653431e7e39e8596bc3652000000000000000000000000000000001082a0edac6267151c8ef11fac7614b74cf58b39b72fb71e4d66467ed4fb3264b177c691e569230f2a13a64b4a48c6fc000000000000000000000000000000000073a8d5f96ee580741bee1f82cacb6139d962fec34c44c648c8fcd0322796429bbaef083a11b4c8fa376d4c00cd79c00000000000000000000000000000000008d41e51dc2822e0f14b992511de799fe4db3783a05ddc1026a53faa89af000075ba5aa830ceb7551e51f0fff144c1360000000000000000000000000000000006bc4bf0bdf350af417160d06e8aebf2dde02c9b50be39b0c4dcb3a045f9e04f1f041f6de10328e287df6121247dd4e9c395ba8f2553e3eced8a42b221a710a5cd2a5ffe5834d3084dc260ae0f51698e000000000000000000000000000000000802e7b71127a15a279a629e89f194b51d19c4f329efd8ecf9fe69d340dd06068c8467da6ab39be25c194077d3ce2428000000000000000000000000000000000250172c787afe866b428748be8359d8e0bad161832abc108c850362c5839237483fb38678d77c94696260508907726a000000000000000000000000000000000d46223c1666f314f9a1e32a94f83d8150755d71252e19af91a3b460ab0ade2db2364d8c6217cb422095f0d9a1ed648a0000000000000000000000000000000002fc2849014717d1c07935efe601325e1842ed333897222f6de322dac8b50bf4d9859eed8880a34676af0d0e3277639053ef5568a766b6c39854ba059f3130b75d7fd870bfac2b00b626e2d71c4968e10000000000000000000000000000000004151d78d65b0c9eb26822e20d90ace8fac209a1f08f62ce722ae3effd7fcc476f4c0179e71b09fc181db96fb2ea4eec0000000000000000000000000000000013d17ef429483be98411947ca0771ce671fc38e27bd0aa4abcfd5ddf1af9e138404d86f4c2ed74702f80a573638d92f500000000000000000000000000000000178f2a7eb43b9f88acfa892b5868d7f7c5787a399c1c566de39ecedbfe88357fd5256ec57e1ba12e9784382c14331756000000000000000000000000000000000253a391373974beef746c4397654a30a68992fe9163f9518ff0ed9b7be37b858ac60c95259ab894bb6acfd123333b7fbadefc3880ca8dcff10b8b763f7d15f88965c2261b72ba879e3540a90c59effa", "Expected": "000000000000000000000000000000000710bfc39e92b0b9d15ee9bdb4959daa3a78f66aeae29eaeb50a0aa0460f3ff703c86eec8903011b4b61a0dea725ab08000000000000000000000000000000000856fe7a074d37786237cc14ff1bc53c735ee8133b231dd3fc63dfa0dbd1979304bcc7b55cd1bb66fd7529e15d15db5800000000000000000000000000000000014757f1fbfd4fa7935ebfe65e150519d6eb4f4831890df4b236dda98804b79862fb6699b587c3e568fd6de1e582409900000000000000000000000000000000000f7b54e4961dab9e94b1c4b897177dfa74be9937694a38207ddc9d6290dae1d5e122cfe4c8c31d853db3783999a7f0", "Name": "matter_g2_multiexp_63", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003bfd2535c6d8ffb44670bd02b5aa6f050f5cfae7266fc3225865bc3f34320820eaeaa952f80da51671f6d97b3df9d4f00000000000000000000000000000000026c1adc0ffc3fef9ccf018ff9a647ef5c69c5133fb4a6566cdcbd3180d9ee784f34d667edb1dd54ae292253b45576b4000000000000000000000000000000000ee90fb541becf96b4728f1859aee5ae74e30ba9193b90569b66b0e1d087eb81f30c21774298cb06e7dbee8f8aafb1930000000000000000000000000000000000a4361867bca952446f64c273735764e141eef43d156d6cbb6e68dbf3bc940e935f7bf3a77b57fca4bbc74bda2f26532c1a5abbddc02f453519563d6b6e05959d8de5feb493f7c58ea5e548cfec2df60000000000000000000000000000000004bdef85b0da28e0531734016e5953256c75c3620937736cf65de5f05b8beff294677668047a3b74f0f135b846a95bd6000000000000000000000000000000000b754df2aef855b4a0eb6f6aa03115ee8f38a31fc852381deef2b59bf23e2c885ae166030ccadd5673bacc35482f81e9000000000000000000000000000000000f1d760ac6dfb65b39c999211d4e4c3623c3fb8ea59cdcf926249a07285a8e4da1890327fed20ff07f12359f6d9035980000000000000000000000000000000009f2698239c8b452748126ffd83abec768edffb83dfa3dc7943fd499c8980e2d9aad76dc38b336a4a63eccf5c4150ce0b406eb0c097237556228f3a48b7e770c1707fd583b91b4b6b70f398b7dbb0d3c000000000000000000000000000000000cd724c51fd56528dfa688df46f71bbfc9144ff98958b559fca8fd05eda01c38c28630ee19579012b9913a393264cd90000000000000000000000000000000000aa1e55f2b6d9385ec6a9cbafcdbad157f7ebc06b2e30e2380ac54e71db5259cb919e17042d6ba6e045f1358aef276ea0000000000000000000000000000000010181ce9ffe235b6b271d570b3c2d6e1be60c53b4a98ef5e8d7d00b463e5bbc9d8d96dda881e58746090983d6f8edd35000000000000000000000000000000000333deb8b14f499319ad675f482fecd80f9a69ba369425decd441cd2ff5c3c77f11075f61bb1d90d0be850ff657d6b7cccc30cf1db4c6be6dbc5830ee37b5782c6dad215334163a9d9e4deb962186f80000000000000000000000000000000001581a5440fe892ee6eece5fc2227fe072dfbc440e0620a1e5fb505ff0b16d9e6033d83c83576b4b6ff87a807dc81b88400000000000000000000000000000000099b070a0d7497f33c1c478ac424d5564fa645d836a3d572d98782f08713d8e425b571433fee928475688db2b3a9a04c0000000000000000000000000000000011e1cbaa09a6361aff9e199e21bc52e98dfacc49ed83e732d4b4f2503b3bfdf85d029dead4412b6f3d7ea447e20d669b0000000000000000000000000000000005503e151d620e9a5a142e4f7940ed88375e7efc1109214141c191e9f38a32a40d3a92d6094584e763e0cf13cbb54bcc99461c0f12019b344a7f322900b64fe81e0d8a052c0ff5e977f58753b1b6edc60000000000000000000000000000000007c780f119bbccfd658f3f1b69ce9c56b1f5269bded713b6827d97d32b2a6deadcc02c410138d984d977527f3609cc2c00000000000000000000000000000000095aebacfa33928a916ca7b0ceac699c71620781b35cb2f3b254bdbd1544b728a2ec1fb35416ed7a8a3a630bc07ff8720000000000000000000000000000000012194abf7e411f4961b6f8a1e2ad052c27624ded863d7a9132d9c7ecd3b4074ef0060cd86adb73056323f4227ba5fa9e0000000000000000000000000000000002fde2be9ac1e8265f258a09eec85a70112ef1eadc3a91429c9206555933e2b89aaf7493fb833e33e5d61be28a12a1c2338ef9fa825e47b46483ed8fd2df64bc7b56da8aecbae704b7eff2e7d426f27d000000000000000000000000000000001586c65405e810e1d5b59304bb4555ca43c04a593671ec64d5ed2d2e626b1f8a89f48a4b21d38fb49909b8c614209a460000000000000000000000000000000014528cdf994e774b8fd54090cb45b68098c1ad9a351bc1f36a9393f3b4364f5beaf58fff6e5f8b21a85b67bc427c0e920000000000000000000000000000000000b48d8713aee51d80c79109fb8b4e0c6e32e25a7ca24dd3e7700f8f3195730375208b241b2c722af3c2295a1704cbb3000000000000000000000000000000001913cf6328429cf2966a48117dc74db0d45be7800f93cfbebf597fb48a8bdcae4fae2df7835f9536481f67261755da2a1dd6656a34f3b12e5568b9c348fbf4ecf50d65a89e63ec0936591f01e6cc7a4a0000000000000000000000000000000017e45a481449f167fd579accc896ac65aff6f1f7392df47d006b404de3cb7ebf6cb59d0913438f3a51e55a0ae3d446c9000000000000000000000000000000000cf4b7db343bea29af6e244a71880538b41b826bfd1d06a21512d00ce58f5d7500ab1ed77b446b1e3782df736bf3dbb6000000000000000000000000000000000525d08e134779ca7614784818876514e14b65e799b7832f61a63601fc491c8b9cb25430547f961cc1c22100170a2065000000000000000000000000000000000450cc2156c4716d0343f32aca82fd2d0712389b1aa984b31d51edc2aa0545c88ff52e470b15eb6b2c22e30f79864dc85202f32528e795e0fbe6deb4ef6e45efc70019520b01fa1d71d5505e42faa69a0000000000000000000000000000000004147c105ee8b4db68482b9d7f6a716ea1474b6c62efc41b9444ed1ef9e92e2b7010a1c1ecc59038ac37b385074a6bce0000000000000000000000000000000018a600a85c5c38be835d2e91a35cce4b59e5f5ac3b735fc007bf5498062beca9befc9c8ead58f9f21f6e08266b149d800000000000000000000000000000000012a476fcb81ab66e3101de2364cb609b17e06eabdff5246bf736eb9d5c87fddd404e8867578262f07a05731b04069164000000000000000000000000000000000c54a888678c28766ad17a18507e4bf5dc57dd394eb6e9b69abaf15e645cf4779bf6ccf4314d2756584647cf27af089ba2b39f2b893be03ab4da77ed518ef35b2e24278d707a20b67ab4d1e5972f9722000000000000000000000000000000000e809152c44cebdd8b40f0d22d57c3b31f29700e0cbc3e69f660bf7270e59093d84bf7ac358be7e45e799a75cf9c13df000000000000000000000000000000000c6c61f98bd4e3b7095fc7f1196baa98139087df00fae2a795e76544ca47e453f75929cab07c11cd3595de6ecbbbaff000000000000000000000000000000000171c70446c19fec3c152741925c8db28ab0d140720cb6a6c45e9bc66c012a421d12271889ea43fe1524944ff572fe6850000000000000000000000000000000006e4baa09b4660c69cace151e60320b771e56e7460b01442bfcf26823c17779034ac241b9365dbbfade770d2056eeecd892eb7c361f05e114a645caffce9437b7b43fa01dd66c1e75b30f3abd0209bcf000000000000000000000000000000001917a23350e94963e3a7488ac1dafefe9ab11856d405eff39d655e31ba808f02954b63e822613d3c6e5f358be04be4a4000000000000000000000000000000001620211b06288c16aa02f4404192e9f57a048e900f0ec5db9b478475f13b142f924c6de720031b3fc12cf869b422af470000000000000000000000000000000011e8ded9ad57e46713e7ac0044ee4edec12689cdfb98838a74adf1a35244e3d9a4a34c81323b089c10422abf26b044e70000000000000000000000000000000006f85c7478cec590fe3355a8d6e9557c5be084c161e090c72f1281be4ee56f36aa1e3c9c844eb45d9e295c15c4cd903efdafc3f57d6116163f1da9e70ea645243c5911cc4ad4a969a57c46c6b5c73acf000000000000000000000000000000000d555d9f23de97318dafb257cf444952bdd3e844e9ed5ce193c10b76f5179f0c6851f93af1553b128f34d3a7e75339f3000000000000000000000000000000000132704571a12a58f629dab48f1a3956392b40f801c2b3757c15f7be46ef1d9115d89920c460c0e2bb062b3cc1aaed7400000000000000000000000000000000152829eaef900fd2f19d6fdbb8f7eb3b02df35d218b494d075219b69016256e572eb7f555f6fbdbe17c59a666d190055000000000000000000000000000000000fe5c67c949b7c89a867301528f0ab24b04d31d6f18f575c475ab5a6098f7187eef20a9ed6e810684da9afd8de96ded6660a77b2be50eb72fd108644d913b9253209972fdec2d107213ba47357c96e9e00000000000000000000000000000000128bf3cbb5208d84dff719ced229921a889c9a4d02f5a508187662f03852531fb8be1f4c2aa9ef01de7720c352dbd19d00000000000000000000000000000000158d89a44b8fcf9ca8c96a8e516e130ae8af19ed71c2b8487ae300c3cdb546e248728bc58fd9cfef21107e0dabf44fc20000000000000000000000000000000012b70b42c8af4551267a94a795fe18e8d054291225438adaa33fe2edafa87742fc3709abcc7bada5d26e3a14649cb47f0000000000000000000000000000000015a853160b7666ea7d64aacd931314497ac7068a4b8bfe3a7deed85df2bb8dba277716a9d1ee50c56b2970016ada509d1ca575cca348dee9adfe68f8a78d39bb998205da2a5285c12141a77ee7af840900000000000000000000000000000000087c7bf08e085e19f0cb301d2e36478357e835620b1cde6e132c237ff6fc63e6fc16a8753550d50fb93a0a1741302cf9000000000000000000000000000000000615299ccefe4da879e5f4b01d6b6ef8358bb59ed8a2b365ec72003c16486d3266243db81f48855d81b6a25440bb861a0000000000000000000000000000000001498fd20640f39dbc03a474f4514e5e283256ac19468077af1c9ddaa40759dcf93afe256de1e49be6469fa106394193000000000000000000000000000000000cba50fc4919a29be2f4e74c261487dbf855db1856e8d5d008cc3f4ee5eb3babfdfaff878adae49b96db99d424bc4dab2e1e4537f855eb478274992cba4e3f50fd9e944f6246cd52dd1517b55bd7f71f000000000000000000000000000000001369dd82ed013474581ca1ab2d2133341d7c1d52065060d72b8317e899e79e9077bcefe6c76c3c7f67e54f76dd3c246c000000000000000000000000000000000405aa84d3ceb02bf8eae989a9cd65afa15451443af6f3cf5e70f5cd7bb8d413c57ac3893a7e8b888ae93a92dcfa2b20000000000000000000000000000000000378d003988f3c6c16d3b12ef47a4a49e2d3d2c7c67e384bcd510939581770aed92e06291ed3b7c742769f0d1ef740c100000000000000000000000000000000048bfa6550711a17d52f48377821baae6f3de6ad99ccfeb8302466047dfddee8005240cdc65b3ab11ed85b11f128624957f9a729aa01c8bf0271052202a077913a9e0c87201a367845f9b271c130e95d0000000000000000000000000000000013370ab697da0ff0a0efa8ebc7589b465374c983c13daee7b5451e8b299933eb5a4d255ffe4aa46782ae0916fd3990230000000000000000000000000000000002ee77be6e0b6fd260ad660a96100bf3259329faf2ff9796102928e70cd52c2bda8d0d1da1d484d7b023d3d59725d12b0000000000000000000000000000000014482fee88e02e61b847c08e61d7ae6fca2d993bbb69bf1653138150d5d7fed09cd5cd4097cb4b6368ea8023383477cf0000000000000000000000000000000009d0380d0d6fa39c9e242b9a67336d86445551658bc29fbd594239a76d7741ba388450caa244fb186afc36d35c8740e93017593cf311989ed8fedff72bb1f14f72cfe5bb7446ace5274d8ded54c1372f000000000000000000000000000000001537d4a47247af8f60f77d309666056c412ce089f3f011457e894f74fa4ad5168baafd36ed3294f5f61cc9cd8f87554500000000000000000000000000000000119e43382a846c8945e58dc7723a0f24b24d9cd487d436a156156a6da97795cf3f4ce382d21435695949b5137a2bf1d3000000000000000000000000000000000be5fd015998bd6043f124048c82e4d848e1b8c87442d0021390cba41c294de17648a47dacc06268606ba73cc95ae6e70000000000000000000000000000000000e05a3dbbf3da8320c40d51ac44c6380d56ecb460b0e7094819aa6af4d7c70d1541d4bc1fc5afd453b165f3d48d09a708bbe9e7a307e380c238ec1f8e2010a95fff8b03923ecd9b012f99e56c77a5cd", "Expected": "000000000000000000000000000000000b00b5c14685ddd17ee99c74598e6bfae5bb1c103f8ebfaec3a620ba57312f3093f9ad5eac820d81096dfece90e72ef8000000000000000000000000000000000dd81552160d449cd787ac27c76685ea0dc993a9fcf8ab182f1ff5d8a484a47c14c1c1a785285b44336c7f6fc0732a0c0000000000000000000000000000000003008b6d97a12868554d294faa26e2ebe2920add650f841adfbf0ee89af72fc4da5dc23b45b7ff191a58c17971b50ae50000000000000000000000000000000013f438d927f35b04bee8fc55693d5c97229c8548ff9de39fae6e26c26f89623d3b0c810b9be8dcf0445910e8eac5c58b", "Name": "matter_g2_multiexp_64", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e1f825b71cd9edcb231c178e160e37bea70108b369afb248edc7c6a59114c22e843fb5541e0f26c77a2b589ea88fb3d000000000000000000000000000000000d65d777e91920b17400955a4afecf82f67cd13f3e7c5d9c2076c4a4d8f7f26383d22d9977dfd0987f219a625c8a621200000000000000000000000000000000045716092850318c343f0dc5337df1a72f8c74dd729831d12103b46127c9180fb50cece34986a94fee6119e72d16a55e00000000000000000000000000000000083fac698ce800786719d1f6063c87d9f728da03cea2545b4ad8831f6c24bfff73e80f2c2fff1532f6d1fea60e7d438ccc5e9d01f6ea67dc3f943d57d9d8b5791d823592f7fae6719804c1ca097e651d00000000000000000000000000000000171d60b76698d4d3f14b4eacbdce9fa66b8c3cc7ecfb989439330fbf0d051d95f3007c389113346e614f5ec8cd170a2100000000000000000000000000000000151a96beb250bdeca3cdad1b07322040bf1cf2105dfa854bb24fa76c8abc25ef4fb924ff995da641244f9daccff2ff970000000000000000000000000000000007e5818778a8331cdcd1432b46abf1efcdf7e4aa8907fd42d5e7d14b57dbfc48125246b57587755ee1571be8b52d2c57000000000000000000000000000000000693eb562e22fa8ca4a655b76e43b50fe487ca1d65cc3867eaf793e50496f0b4658bd92199104c2ab92e4ac53c44db6f57b8fcb85e4dbc1969805d814e75b2b80f5cd1e5562bfc1e28becf731aadfc58000000000000000000000000000000001059d23ec6e472937d80829256db506d2d2deb37d4b750a980568cd5b0db085358a4d610d59009b64db1a9225f9f6f5300000000000000000000000000000000053d9ffc47672f1058856aa08e51aebd469111dcd129ed542454d6401e7893323f8a9c63641f499cd8617c7389518f8e0000000000000000000000000000000002b9b30a5e37b18af4bb02ae8cdd56f6a87820716ea1522a174a0d99c3716295ad0ff2daf663697cb56bc6053c9dba610000000000000000000000000000000019d3230c0bdc228fa0cfd5e0d8bb88be959e70e59d931d9f9e3683d5e65d8ba0d121fcea329b23c5905b80dac34de33b03edc53ced9ec5d7f302216fd30a81c3554a3fd04994f62b5e3da74c8b71bb870000000000000000000000000000000015a619addc75f425596f9a51c6cf2259087cf32afe9b1f07e346a2f4e1f8caa001dc10098d1287b89837f426d073982d000000000000000000000000000000001660598fcd3ab6a55423138ee72a4ca7b57277f6ce140f9f992dd9934bcda78513516df0d309a0e8ea151b2742dceddd0000000000000000000000000000000004cce7d84e0763fbbb54376833ddd7408afe3f741bc2b7e42fef3789a005134cc5540981a15a9f256e0e541ac58ff3b10000000000000000000000000000000019c20a0064f89d37548e06d63d8ff4fbf3584d5bcc2fc2757339b7c89db6d5da76d43b31da7364259187ed602e79bf4f976568ab779e335b8dc67a64f15b947e69cd3896ff393f51fbd3c3e3a157543f000000000000000000000000000000000d7ec5a27ac44daeebab7658011624c441e45924cce97d5bda354f1daf9362f5bce2ddf57151fa07f78740a7db170e8300000000000000000000000000000000121ee325f4252ae5cdd3e3495f36492d68d9dbe13249039d1185760e6e48a789744b2a9946a3d6478a64b378f76b0de300000000000000000000000000000000014c6c5b98c1e214f78b82f1b3be4c32c5013934b1231fec942b5591d3f0440bf63b1505cfbb7a8fa78a85ba58fd4aa90000000000000000000000000000000016aaea3bd0ae91b9d18ff89a40ae27b68d74f3a227383138ed737d59c19ac578da03df83f04c8d962cb9d6f84a15302f3aa5eeded490a17b1cfa66d409811741643b7beacf312b9d6c8e7e7e63579c8300000000000000000000000000000000188e5aed425a768f89f5ce09b2cc909b28c6a0165787c8e3750fca8e8162128ecf62ef0ff853d206d23bc076335008e70000000000000000000000000000000001cfd330da0d1b5b92b6533cf5a8b6b70bd93daec4373f28d669f5e970a947fd813ab1d1272b61afbd2748922b87c8c300000000000000000000000000000000002aec750fd085c99c3b9c3af62b6deddd85e49eba0293e6e8160b26a3945af546a760b8f8f85120d6a51d22313cd33800000000000000000000000000000000162a109abce2edef753ca6351aaa9cecdeac20919681c672dbb183b5b26649e885ff081b9d3687f802dbe20fda43462af9f1f9313bf966ea3b8f09bbe9dcb66a7f9e3e94e2024c49a72ccbbe03fe4662000000000000000000000000000000000f7ad6a1dd9f8cf52bef02ae1e82b0d20dcacfaa5c169a485bf8becec8b51373fae851ca29e64385f0b7024eb0bcf9270000000000000000000000000000000010412a7a710f842fe836414e2729d0ff2e145709d8f7b5e3964af3e0ae267ac53dac3db1e6d2b7f7671ec34b18c844a10000000000000000000000000000000002d3b96fab0e3b8fe44e316fcc5e35f06dab83f2c531a777e162f7521cdd5767ad0b6f877f876f73d2ff663d9b71f462000000000000000000000000000000000c09a98bf623e82a4d2d4b63fb867fab5d3bb1f85a0669c4c11cebaeb357c0717a0f246a9ce4064b7351dcf1e77cdbd393be64fc3763d06111961bb208a2b858aa1ff181781dda630ca41f0d45ef2a9000000000000000000000000000000000114270d35ebff55c0341776086d893513595aca3b200ab98c8b586029b19a360a04f2e77e90d382174296443ab8531d10000000000000000000000000000000008b88849c3cda9a23d37ec9f4700904edb24be95fbbe6d9e20ced0d52208b597d44bb9269830a1ac5cda35d0c0a03c9e000000000000000000000000000000001144466b13427c10ad7679567067dc47c671107064fbb9bad287924c9bdee653c395dc2654caa5b3013ade932fddd5e50000000000000000000000000000000008e14e3cff3bb57f0d87680a0c09d745c7272bd3c216ff9fde7c03df2caffc27e0bfd9f99912855c156a787200752c125d2a2b6008a3b4a4cb3a8c28864214c7fbe154fedab1f9ff8c96eab6a5f28fd30000000000000000000000000000000015cda76d42de9fa86f900a5180ff016155f31b9276c617ef664202848d2efd2876d412402516c0c3d26d49f71d894acf000000000000000000000000000000001307fa2b963fc19583b7e4ef2e9dddbe93e2505e8f4f00ec52db26ab411002136c1f646b1cda71e19480c767906a6d03000000000000000000000000000000000ba87b08173c841a2bfbe424584d4685c39bdd0f83f278f9fbafa8111102aa3acfad5aabbe032c7123631fb8b454255b0000000000000000000000000000000016c525c1dc247fdf34344168b7cc245579585fdbdd6fd783cbe60b727cd11ee97b87a86647f78dda207c98e65c2ee7e6854e742ef7c76ad438cbf30c30103741f57ebbcdca4d6c4f14e554dd1ed81b24000000000000000000000000000000000403887fd4429f44f8da7f17ca072f867e88ac046922ebe3e1e6c4f9d8e174399e7648aca924a557dbf7b29c540db33f000000000000000000000000000000000522324700fb6b2c43eb5b39e0da94cb60e234369543f530ea47f4aa510ec0fd79cdf4dd3ae046e21d78b9c0e35107900000000000000000000000000000000015e946b90984257ffe3814dcc3ef065fed1504f0790f3564c8bfad4e97cffdb61c0d73bb0b1dbe78c4266c773abd56b500000000000000000000000000000000078f604630074ebedbd836c463f3879cd5d4a2c947da0e47740ec369112f4fedd787ae59bea69aab61b91f05d92061036f4f00b2494a32844e01d0827ca78b06f5eb40b6769f36a04f20eea229c305f9000000000000000000000000000000000f722bfebd55f75f3bbd0a55492499c3a3f637ead0e54270042fcc88853df5bc5f11a3677efa26d31c28368e00c8713700000000000000000000000000000000182618bc8a4b3f6556d79848f90efd6883df90806a8358cb6852bde465a27a70644ac5d5040d4f64ec355763f1a384990000000000000000000000000000000015f717739a1cbb2eab30e7b1bd9b25f57ad56f36016b59128ea1f2089f2d1dd0128b455b1b0e9e3b320f68a38a1bdfac000000000000000000000000000000000b855788d6b6a7748aa923dea3163fe525a7b43f4619c1eff3f9219ec3d98ceaf34b97bfd19aa6f91f7fcff728728978191e47a0b0c72bd17319063abde7df51498cf0c980c46946bf80ae4c9864e2e200000000000000000000000000000000120048ace47bc1ab3fdc07713b91a9223fe0fffdcbeaabc8a61351d756f936e18177f672c5a4db7b9dc29bad16bb7c4c00000000000000000000000000000000101275492a6e843306f2927b6ab540d7a5ee925bdab40103b4ddd885e444e6a6ec2d6e99c061284a1967797d8a2e9e700000000000000000000000000000000002c12f17a5dd2c56aed0d308367f37510f83c94a4482e5f632161dd0517dc2d4f46a90bbc13034c63dbd04fe4c616e320000000000000000000000000000000000e4b9089155ce2178f26b058f4bfef57b73aafb83b0b78138a01890a167709f79100a1e4d797c5849473eb3486cffa4b7baf8816db56c0a602cfb4caa9089136ebde05722ad4838671e45ada5c716f20000000000000000000000000000000018180eee7e72b6a4bc2e60555236da335fe05fcbe2b3cca4937e73a550aeae6274122ba84ace78eff84d323b4196f58400000000000000000000000000000000147659347e0fac7a16c92950ea5fd115416072f339d7de3cc0f00ef369f5122ff050d8515effacc825c807f7e19650e10000000000000000000000000000000017bdbcae7f63052af9a7d8bd71dc98b6eca7ecf5eee7632959fe56ed51278099690c534ec33be4ace4612b0f516794aa000000000000000000000000000000000d6fa233be4d6d783bf973cca3740cbaf0f719827d7f9310f38d1dd9d1c1f125cdfca6d12fbf6a8e8104f79bf30b00647d9ac1699117bb9b8b90e2fb709eff4ea0f7882bdf6acc6885c9458703cbfb3500000000000000000000000000000000082f3beaafa575e86be53b4fe7b93835b00759f921933402282e5bb0e643a812e0e4b676ad51ff2c6f5332d777641cc3000000000000000000000000000000001760b87bc4d2c13122fd7acc6d629c9f9db9bc9a2c49634aaf33e258ceb3106bc2755b227c6660a1df1d92c60067cf5a0000000000000000000000000000000016a819d7109c9a12199eb98537a730908a693767cdb35a69b4c7329761939afea766f0b91ae405e273227330761a53dc0000000000000000000000000000000009d14d7138440349e83f5ded46d18b886ef3cd63e0e5bfa0a8b50985142b21a4733813ec347e40cabe28e6ec1e068c24a22b6c1a24eff71f0fc64b6aee8d3d2dd0827756f5c959f68f1216c2dea58503000000000000000000000000000000001676d7f489219b56c198f8494e156fc0672ae28dab20021b7a6018436c7c0f107efd2493ddc2a1cfb3ad490ef146348300000000000000000000000000000000001106e89fc098ce7bd8bead5d7f6432bc54501370ae6544f34cfd996b3b610f9cfc7ad366751ae1211b848aad7d93d30000000000000000000000000000000011f8f0bd037365b5427e76d57b018c1c644034b28d06c8f68c59bff45eb4a2c4d761d066d96c13f7e73dfd80c81704a0000000000000000000000000000000000fc826b5957613f35bfa36d3ce088dfbbd06c8f2e88056a22a9f35db561e06fa0378ccff29ba8b81cc12c7a504f8c704c0431e6877166686239f014008959332d9d009a801be6a1e68c2de52ee264bfc0000000000000000000000000000000014f0f64acb0d9638a68278099abf5b5da3aa087792bef15192cfe3689b69b7ec1aefbfa14e659358b5410d98d2eedac50000000000000000000000000000000015ca79c92e98cf8314a2f6319520e1eb7d4656ca6e51278710cefd9c768a25691fc58e983aaf858d3c8d0ed73e2beec300000000000000000000000000000000007a5192f1dc906693568291f163e9632c53e1f418a87cd25656064adffbf31863680468f3ea451fbd22ac990dc870b3000000000000000000000000000000000131d2e3f6956da8941e8340259b8a15aee9fc6f23573f9a348ee9a51bbca1308dc54e7b4675357e3a9c5971be3a5c16af833a784d22b99537236fb07ab7b59918783e35b89fc9692d7f76a03e024c94", "Expected": "00000000000000000000000000000000163da4bf7e159e05eec90318a8ddad4a59fb02d7ae2fe18795d38c3ccaf797188fa16577e6a421ccfb12ba1ed573c4e6000000000000000000000000000000001256654eef3352b09e0027277aec042519d99eb2567fce2cfa50a0c251c12d3593604739128171bfc13b3bfd1ce8f9e8000000000000000000000000000000000b8a46123bc863bed525f97166bcb77504eeeb66d2db207eb8342a3d18f7f5a99910fae3e6423c6e84e437a2c4b24363000000000000000000000000000000000b73cf08023c8572f48c132add67dda7a15def638a01b198361b9d21a4634ba76ceed9819b37c12e24f148d255483856", "Name": "matter_g2_multiexp_65", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003113ba8b216d933fe0c81f23f75942c0065d21d8f009d73b1f698281408874e33dd2750fd4298367b81827cf6fdad34000000000000000000000000000000000b8a921e840fc665a786d826f83ca5a9c8f00e7c802bce5473a7d1ebf63e8bb6cf5c4b426153508d874064d1f1dade09000000000000000000000000000000001492ab584088d23d3b0d1283904f9a8f29f9efe47950c6e9ffb9db2123f3f9820b906d672fc7f97f0bd38b8fc0ef44520000000000000000000000000000000010d321c2538f92aad4631af44ae39e63dc06becd2460f0cee0e526328d167fd6cfbcf4edfaafe32d13b5fe66c009533bb16c1bc60e1a9be9a82c93b7e0311e7516a57d687d8907599918df77b3b6caf3000000000000000000000000000000000ae75d01481a51294003041afc4802326ab878a3a75eafcda43cf873cc65e300d28aa986fb82a2d1d649e5be00f956820000000000000000000000000000000017640eeef8982250f88a4d187dcabfcc9adc3ee9194dbc3c04c741690fce5bc7cb07cd0b7c3497191d9ed8558fd0d24c0000000000000000000000000000000007527fd8dacb81b8d1abc746688db6a47211fa71556155d38361921c4bdb2a9e9921a3a540bcf55c6dd751b84c04a1040000000000000000000000000000000008de9109ba354d7426a5313d66cd747a54df347f0f86a3c0f99e9e4b68fc79641fcf98ab39fa23ef6f1a781c48f53f76cf301dfca76a83c70552c9cbc9c80cb20f0d82a70a9d887b04b150fa0764ce2e0000000000000000000000000000000017331b8367f07756e789f7edce4d22f6886656fed78ddacef6987a2751dd3d5d49011a050e7b2a3e11fc8d90266c9d710000000000000000000000000000000016959c303e11f23392f95c1402d1d1ad7f38343c711e96f18d03f832f76e3e81de789a6eaff797ae51079b13571334d40000000000000000000000000000000004266fd13db1ca80196a91263c79d1583b717fb61fd9ce5113e4cd94c59e605152b244e10e364b468c5a561c6fa9715800000000000000000000000000000000026f67cb263be83f3163856f091e9346651c29d4634e242da53b22eb6e66018d235b0f30f8833310dff9f3020e5bd3811cfb94c4e029a2126a9cf5561c677687f52059e4b7f8b7e7e73e5b1dd7f42129000000000000000000000000000000000114d8babd11c81ca2b8a7e193afbe0a8fce426b83996bae6f77201870e51c9355c319dd86b985272f73e0804c0f53700000000000000000000000000000000016f5ea7610891d0e72975816c08e6e25a75c7c42500655f26efdfb384241bbc825358a21caff347d00c8b2391501d15400000000000000000000000000000000199c8c74a79ee90c3606906bbb8cc163c214259e4d0127cee3283bcd9c1ebe4090ca7d7b180201910d3f6f51566d3bdc00000000000000000000000000000000032c785165ad4c1a2846e15318bd7cf5b42ce8b675cb18fcc4232e28701f225f1ea384b276e7a38b2c9e2e8b112f1911d8386fe6f4303959e58165b422e98c4813b1bad7808594473e4e66df09698cf0000000000000000000000000000000000842c65006caed9b53add048a2eea89e1b4584e1deb4365e3dcf8b9ecb02f337bccbe5d6929ef8c20461847f171fd4d600000000000000000000000000000000100dc23e6c1c6f6756419a9bad3133bba052f408a424c5239b8528ad4429a2bce64b72f1463625f7599ce43865581e9600000000000000000000000000000000125b4d71333274a16e52829ad5eaaecdda5c206063473dedec5a8ff4424def70e6f650926948dd2158b403f985a3421b0000000000000000000000000000000006a031e3c002702837e4ad28250b85cd94d42cf7b0d765b980fab95edded7636d13bdef1be63e66682c4e297d0cb2b0302e1c432f3b55ae87ab815647f196be3e138b2f6e9fe7acb9459650246187eb90000000000000000000000000000000003f7091a25da7d5afe6fa6b254604a1abe7a0c6ea11cc1a4167f5f648aa973d888383bc7e987b620d23e688868d318360000000000000000000000000000000016637f888efc3e057227cbefecb3037aebf8e330c3a794e51d691e3bc064237b98351beb746868aef977a83d1fe163ac00000000000000000000000000000000126d2884487984f851d1bd7d61bdb803321f263918e88e0677831563bacc9f5207358d1e9c76a5a25a66f0294f459e3900000000000000000000000000000000125c61b387a4462fa3bb2f06a4cfbd7df082d20cb23ee974aece2ec9a3b0c084d13a7ea83725a05d9f31b8033d2888ef9b0cc0ac499dffd627f5d19b87817dcd67e87561d5244a4b5698265f8c5b767e0000000000000000000000000000000006cf2bc7c691c4f8a64d0aa1ca3760d715b3188a2dd299ab09c723315acba8b0b4bbee819ba06cc564f0c875a63a415b000000000000000000000000000000000bded3d695e471f30f9d723f55826eda112eb0e3fbfb9a377cfa07d6233ed84108b92a79bb491a2971e9afdf83db8e9a0000000000000000000000000000000009b0e9928cb267508d4f9444c6ac3dc6f64f49a70c82c0bcaf4022e97854e5d9ec2612a2cd4d67642dc0451583bcb24d00000000000000000000000000000000009347dcfebe93a2f7674ad02ac48794e7cbffb04dd85b0c8c192fc85cfb9cef40fd11def6f63ae9a923960424eac6a02f3875f81fd39c9b3ec74eb269903dba4173d8eb0e41a196d3131252207ffa040000000000000000000000000000000013e8215c7bbdca445555c9fa0ae44e1905703334bade3294fc047ec262b9e4903880d52851967339eeadd666200b25ae0000000000000000000000000000000003b0bf4498103ac03601a8594b154b59a2a93d663f98ff8dbd2c85a1902e572a9456c629a12651aa87a1262102e1c770000000000000000000000000000000000e8bfd7d3fa0f773e6bcfd0d43a5c436862d1cb6a4ed715093c6782cd94699090c4bde597f65768e963fd0f8644e09b300000000000000000000000000000000064dab4d0d0c6b94c58b067337f2fac7d0d922cc822562b6bc941a794d96aac5ddb83d1d5844440d21d0a72a69303b8b2d8d4341822dba68c6fd58cfebd07b134c1d0c4e32ff63f7d59addff4df1ec3200000000000000000000000000000000098dd9a20f84fc26e78993a9de4d519aa2f8d343fbee501af945e5943e88425d29beb7ae54481b04175a07bf69b260a30000000000000000000000000000000007ef43e7a56e4e7d532420e152ce566d9055eadb4ef13d5698c49da905a4977fa8a7d3f51c8f5275582e1647984be61e0000000000000000000000000000000003755ee4432ea90f2197c7cc2e191dbbf7950c52a2c1b723f26d2aaf7a38c1b97efa29a312fed599f1199cf186400adc00000000000000000000000000000000150edc463f0a55fc70c2ffdd1f73a3abbdae459eb16adf79e96d18849ca638e6f41c6805b73755968be5cb110d81faa4efa3dab1d7cdf949bd938ca6ac371f953b3bbef1aec7ae76bda37db4c940b3d8000000000000000000000000000000000f7149602cbb3e5f2c5f8edfe59fc0fb8e1f03f89ea192bfe3990d87ccd28d4a80d7cd3003a8cfd669e1b6ff7e3cc5890000000000000000000000000000000006ffbc965bd06de07d8c0a9db8db5ab82d5f11afa1ad8eb92ed4453489f5899cc8c46ff02743956bed81229f64cf6efc00000000000000000000000000000000164cd3271ace4809eadeb1c0f769094272f3b66968690339bdb5da92e920cdc80c9d577ae4fa5b6426a5a6f46fba80bd00000000000000000000000000000000098f0a14a511ff424847d2b4d1b80a049b1f05ecd40af96b7a81def54486e4969011c122ca7dca3444029daeae2ecfc79848d3c53632dc461619c8c522013b83550ef3dc7fda197ba37c9cfe4340f5a50000000000000000000000000000000018409c0d0f37f4932cca87e24eb4d55e75dc98f938420ce036d43689fbdbbd839dc608b21d12a8af1d0a780aeac6617400000000000000000000000000000000109f2294669422a4946f926b1f106c2887893a042e3bf900559429c7fa484da4909216c8dcf826871534981021256741000000000000000000000000000000000a1ded19846e603b958d0bdcc9b554beca784b017d2a35ba117890fd0dbf729428bcd9823c7a378706220377c82a215c0000000000000000000000000000000000eafc89e30e4fc0544497e27674ec5b37ec0849fb382e608e09d0c1c94cb78bcb96ef4ea48e374aad1038881706fbcfcbfd192e917f2e0c4d6253c4e4755f30812149d1ce1ee4ae5540faf1dbfbc13a000000000000000000000000000000000e02cb3e099792ae7508321ce7afa323fd499de90c4006621ef5ce1054d0c934ae058a97ff8aeae0c88709c4d8ed0adf000000000000000000000000000000000e19318f5890320f17d5243adb4683a97e3e9763102c4fc93e3c3e3d24f4f61e0500be916c249dab00094b4ab048fe99000000000000000000000000000000000989faafcf6156472368b282313e076613cfe7ff135eb131b49e58932cbfafecf6585009d1f17ff8941d7f871be23e9e000000000000000000000000000000001167419d097ae8b96993b2e67da79b658adde1e12e43c71f27835845c7077f385612158d3e59fe2cb32b9418463e672679eaf11b3a30c7771ce63cec214416d798de20432670280d997b2f0631007d63000000000000000000000000000000001579b7d03d3d2c8a280e8ca113bcc98afa6a2705a5d228d92807a85cd5a1ee97510f632293a478c3fe0bd383f4b69cdd00000000000000000000000000000000107cc2e6bd02251bfd565b4b848adaa84babe9d4f083e827ceae6bacd9c9c221f0dbbef53278175bf27ebfe5949fcf8c00000000000000000000000000000000018d187c566690e4edd8d8abe5e0a448e352f622c96680378051228b6d081a4914aa51383326aedf45e351612ad6c5d000000000000000000000000000000000197427117a52f82aa6e931ecb0c5ffeec7f73ee8f44c5816935d26c06cc8285200ff9240d98cc244708e00669460f98b43077447b67f65e16a8aeb3564b2d13822e478dfb4a82a15a1c8fb7cc8170cc90000000000000000000000000000000019bd947df5a437a7f1ca2340bec628f2783cc1760dbc4a97ae10093aedd9f64e25ba79d9f4ce678f4fec91a3b1eef2d7000000000000000000000000000000000770e0c39988c9d8eca076464a3e10e274b06b1d2f6230e6dbd8dd59dd9c062f8958c6870c44ff196341bb9f65b8db38000000000000000000000000000000000a1833ef19e2b8e31577e5cd26e0a7fa46a5d25355d8b3dc0605f53714a60423556f3bcf17649745695f68f26570de0b000000000000000000000000000000000f449aed4120f3bef05506f2463f4546c7ea67b9e9110d3942dc256400d063dcc571305b1d4cd2bc3f18cf25319286e8eb64479b496c17d0587f6f26c62752881b6a9228643e8c43f21c441eeb643107000000000000000000000000000000000c1f9688ea64165f894e85b21761a9b2bfce891070103119ae71ff7acd164a57b0e054319631180c22f19eab8607f5b40000000000000000000000000000000005ba18dafcd3552af464acd469b133896e90c9ccd7e3bfc6e05db883f3c6aa1cc4610ec47f6354f6a7cff4385c56d2b3000000000000000000000000000000000fefbd9d78f48683b378d2d6311bf7ffaccaf7aa73a0bb4ce019a0c1d2e1673e52c724bf3a782729ec23d258043efff5000000000000000000000000000000000ea47ebbe3e858c5fcbf5b0cc9017d6ea23bda36e235d2aecbec827fdd2e4b042d1108d5f645b6dcdd786304e6bbf81b52b42f75aebdad1bf433917c025800c4f4e985cc077db3ba36f7484f95764e89000000000000000000000000000000000a313e1bf72d9a176bbad609631192c779e94c293463507edcd1c38bee8f33cfe6104d7169457ad5ffd9f045fce1cadf000000000000000000000000000000000af8db18938c51742b351fffddd74bf1137092ecb50a7e749391bacc9c1a19c7b9cf235b52ed577e7855d4ec1fadd940000000000000000000000000000000000febaa128de79274ef11d3e6378809d5b319796c653604723693c335eda175014b645604271429e3d449e756c85bcf6f0000000000000000000000000000000006adb29cc4ba053fea56d07225d2f7735651c0046f5cbe4a350dcc20431ed9457651d46a5d23d946959cadfc5500b7eae83106e9ea63791eb192e7a035bee27bd049b3a37f080076146eeeea6a769384", "Expected": "0000000000000000000000000000000019a5b588aff8853adcfa959afc5135807d00196a75acb3536ad4fc9a9df3803d919a2de7cbe9ff762913225577ebdbf6000000000000000000000000000000000ac8bde939ba2f164795804d96dfa8d3a1c4d9e4eafb000cfccd956c24f4d594b30bbf961917f625c86270cbe164cc5b0000000000000000000000000000000002de09fdf52aec0b91bbe99fe2eb9043b19975c6fd503815264ce030dd5e5444f0f4275ac9a07a49de775335d52ea3c40000000000000000000000000000000012457bb55876c482e5b907c765b476dfe6ebfe8e588cb7f630e58f78942bfca57e6c0d5d7b0ce80e48960e297863d212", "Name": "matter_g2_multiexp_66", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008f3f1f04fb80a23d348e3e25dac1d732265fd4a71ab8dad3718d268e49c79578e8e1ad1720e70357439e57df0791d64000000000000000000000000000000000fa4c15c76e395fa706a55d1909ede2163274a68b3e7afb8d2e0bb176f60c06f5a921c9ace35bd311bd79ae86340ba5000000000000000000000000000000000173633369e00c8c5528bd5ccf95c6af8b012e5a31941c134ad4541099c7c33c5ffd29a5a31e18be720f7ae85132cd6cf000000000000000000000000000000000800f5eaf7c8b1dd2787305ecc637a0bba8eac807a7b449410e48aed3dae2b4645b8459fcdd477fd92fa5ac6291b800ea4d710d2f632e3ed0ef69fa0219e16ba30d3efee99386f1a5c921f4548ebf64b000000000000000000000000000000000ea8057b2d609ac2130b21e0b4a41f0aca20ee7751f55d816ea42cfa4612b67c3c556b01b0bb1c5912a74c50a420407f0000000000000000000000000000000007fbccf8ce8d1a92756fe80b15c7d9342af4e166d3c1c7e35ea2fac34851cfd983633270c877224749365720fbcea54a0000000000000000000000000000000000885e173b73118721d28fd26f3a9c562bfbb878ce71091d7ae4b37c1f2625777d67955a2b7458af71077db7557171f2000000000000000000000000000000001754edbfc3f2af94c92e6754d6bb096bbc4b39bb1128dc6bba8b4d4d9fac6649598be90b06b9d5db44c4e77c0cd1537cbd9ae4597aaf582857b40096360ced0f044ea172551c6f9fe3a15e0ce290b56b0000000000000000000000000000000008a1a751b5f9a08e2bf5b2a58f62f0af6b8773f88e50f658ed220c0134e83c7031a288eb50a8a35016d2362b431d809d000000000000000000000000000000000d7f04d4a6c36cb3d105dc3915cd5d57f56692132681b3abca4b00e078c700931848e34ea1b7ec663f3886ff766fef41000000000000000000000000000000000a06c3ac81d6d0466e1ef21115150d04c8bd6dc3e4078e46eab213203c3226bb0c6500ae4fda591d6b8a791de598edb90000000000000000000000000000000014d849ddba2fa79b6a7107efeb46e9b6231d65384c69ed183acfb922d55b790d4fc7546afadc190b76f7da00103ef565efbcb4bad99b419820eec388f6f62ac8d87866d7beae6d431dfa48d4243b4a4b0000000000000000000000000000000014dfcb5fdb38cf09c1ecb284dd4f2de0c3d70f90d7c167a442d84e9a29bf43be62cd319b2dafdb6ead2c6596443a00090000000000000000000000000000000006220fc05c53f48e7e4104422b0660ab67fd88a695a201366de570f0ac0ad30421d5e37a1575e6b5ba35f45b441b297200000000000000000000000000000000077cb8ec1cb83c4974f6452ce0de630afc82e283eeb55d3b7e9969bb44bcf0404deae617393f82ac228b836c3cb6f95a000000000000000000000000000000000e2bdf539eb45a125112836008effd104e881aca397457004fbda4a40d152817801bd259434481f0509ab1838cdd1fd060d89acf5b49fd1f70fc54756c4bc1972cd8818e36efc37b422ba6a9318fa134000000000000000000000000000000000a09843630131cc6feeeee8aa8214408235655e4733badd6fe20c5cf1e45f6a61a5216e0cde937799437962706d3bfe2000000000000000000000000000000000ff518501614ed4a199ca9e9aad4e8efb8e9cffa9b4fa683093a49cef4669198a7893db998d5777f2cc8f4bb130c84360000000000000000000000000000000010ea66fb5224f4508ec100cdb611be133c4895a8de1b4c475b097494ff0f1ecdc1bf8fe467c630233cac2ddc07935fcf0000000000000000000000000000000009d22c0a45c82b0a19beb94eda0b93cbbe1f2e5f2d61279e1e1c93ba073cb766f5637195e6964a4814e588e44bb03f03386af376b9b393dde994da419d1f7aab60023546647f7b069ede939386bd6ee80000000000000000000000000000000015ca795fc7f0d169ba8abdafb1dee80b67e7dc616e824959f84c61284d6b2e0e8b9f99b414f5bd96d0e59b66ee706fd800000000000000000000000000000000042f473d1fa228961aad526efd003461935954abaae347dd6c9bc7fcd68b5f5138e57ab2a160cb19d1983089b58b51ab00000000000000000000000000000000188eb160cb968b4b048ce14bb72be27c228df1a6c014fa7dbec09a30aed8c71e8da59d3d5f8073b6a7d70d94c0e59dda000000000000000000000000000000000d467e6b05f033f3923667a82d5b489a5c90c99c5f68078aec700fc67a83d9bb4c09f3f00b9fc2cfd62bb098f885fe295ffca78eea65c00e1128f8dcfc96b39af1c4472b461ba5262307003bc972023d0000000000000000000000000000000003bec45d94f3073b2ca54d6332d36fdb8f5c801d9f70ccf6e3666b66ee06c0fdfd741f74cde1997aa205fb0318c9c4760000000000000000000000000000000014009b777b660264eedb35ec2e13ea586aa9438c47b3fbfd095ea3d8688a89c85bb4052bbd3edd450c19acea6372d0070000000000000000000000000000000017f26d3cfcb40fd6b4f3f1acb6d47a9b54c232aee484c7a8992a3d1accea794dc384fccefb0418d43e1fa7b399bdacaa00000000000000000000000000000000153c6cafbff3c53114c96d8caeee2880dc063d7db5edf5f14157117387f368c76b739553542bf6a9bc4ace3694de885a92837b4314e63ef5a153ea2ec4bd373cc3cecfa3e892c3a12aaac8ddcaf5905c0000000000000000000000000000000005d2481438c03493efc9f1e8e9ae6ab05b7430f7fb82e108aada0e886b14d769969d54b17b31e5bbb63d40836748f541000000000000000000000000000000000971deac599b2161a4baf1178feb81fd4798ad5cb063b1a0cbee7cc33b8fcec6c3f43d1d46d9ed45555187db636af99e000000000000000000000000000000000222acaf8df647744859e04104a5fcd546949feff6244e192a9031fc838f368aa465a3799779c637ef0087183f30731d000000000000000000000000000000000b8e8f1889816f89401b070db687aae47f7264c9be192a8d6e485ee71a5a688070d57ad8928d09d9a4925f1050e2c69e127ef2309c699a3602b0d86a070baef0eef90f539aac3cb6ff42cb19f284bd99000000000000000000000000000000000b8a5b0dd422469a8d6d7603e9f3179f443ef3fab0016afd94e93e2ea9e84b332da4b59f23a5257b99460efdf7d2aca7000000000000000000000000000000000c28e7068769c3a79bb8d92c3b89eca5d6eb42e3e18c2a7154f43a671f8670f878c4b110990c2e2b163ba4d1155319fe0000000000000000000000000000000001804302246fd07d86f4bb23f610af38deba8e324cdedbe5e61cf0941281cda8fb5dc211fbc0ce6fddf30aefa9563a0500000000000000000000000000000000015813fe0d6bbcfdc8e7e40b6141db21e1b490d846ffe82eeb3edcd9a024315193259612155b0179a4971e205738af74ba0f9a93c2fe35877ddccee5da39ce5ae60a6a19e72481319e3b3fa2eac614890000000000000000000000000000000011ac1ea4dad0f650fe0844ac3ab9434ebac6eb70a5f77c8f9c892cb4cb06639a15c63a9b820ef8f7a720040ae5b9e49500000000000000000000000000000000117da7999552e7886a25a939ada0944cdb15b5c468e9d1c3bf5b6af920e470bd648d24f3cb7f91e670f57a52cd65f7b3000000000000000000000000000000000a24147ef5f2b8ad888899c1db8df0a601eca9d76f1b934b1627e7eef3efe542f51205b96b5c00916688579ece81336900000000000000000000000000000000151863d964b12287ae4278c905341124985410f1ad6a72bd5c62230b7d8b0cddbea0c62cb2a7147afb5bfb03348be53363da2f227d636f10e814e360c2156e686e26ce3401dfd15f47c4ed277d05353f0000000000000000000000000000000001d32ea5faa6303c530790146df7cd5cdee93c0933b4cbc1c2b8030bf0a8d2600dba1907df1756152625cfccf8cc7fa90000000000000000000000000000000017b05f549751d090f42ce8a3ac5d959cf988ecdc485f51734d52c40a3e22a097917345978209fa74a0a05be0a66e5c6d000000000000000000000000000000001481fab7750380626b174602d9fcbc97555c516f4410193d2849443cf25ec22840e4fd00b225f98d81b38619e8844ce90000000000000000000000000000000001d56434066551c5bfbaf8c9007874abe57a6f78de9355a297bc117f2bc5e6e3f44b248037f400f7caf83fece0c00ba0ef79e3b6ce752d140c3dfb2007a08221d989038c921efff3bc4e150a6155a33e000000000000000000000000000000001667f1400973598ad3f56c2e49dcb5b556cc38ee3e5801ac4943f3c4554205d8fa69831e582a084aae1ef584feb0a1880000000000000000000000000000000003f0bb26ea548e498f05a5bbda8b8e536613f10e7165607ab77565b193f794664c8ab0a5ae2368d7483b77bc1173d14500000000000000000000000000000000176d8d294b4d975629c6a89bd6d45f9c3924a621259ab43d33a3d5aa1f423b68e3cef96dc103494bbb9036436c170f5600000000000000000000000000000000002f8ed87c584e69de59cdde02b6de9816c31a6efbebafb6ad9cecaf266f5bb9c8880f062dbc9235c91c668bae5051f4bc08091af8b8c6ea5c26f1a7d795132521350d774042d3a8c0523e86fdd23a3f00000000000000000000000000000000085fee95b859c52e44fcb2900a9aa590b1a5c2f981a388d6ad7b81ffbfe033f648c4a84e2119cb0484e178ebd3e220d100000000000000000000000000000000171e6ca074aa97981d2c2ab000a8bd12cbd5f5d574cb83158a6ed734e8f9b7aa4b74aaa43b7aae31b3f4fd3d82fd30ea00000000000000000000000000000000004fe6099a52fb491a0624a8d787d95617f6c64d16d20d1b3769f60d4721f7af66d7e3e905b3e08b2946ef7bff4806ed0000000000000000000000000000000004d3d1a56af91377ae6b00e192ad64fce6dd43a37592fa8706c9344b3d96b1f930e03be85a5ead3007f9016255d2df7570363101b87d685aa7314f6569fca0775bc6aaffabe136e6c336e8fa43dedb8a00000000000000000000000000000000155830eff04ec2f4dfca4f73403e408a68830bc031555433fd38ab3ce1035b5f882bcd6032aba69ecc43625546b4a3a8000000000000000000000000000000000ed5b698b1ae23769cf5b6dc2e39f8500fd8a881eb43452d67c6b84ef9f0b3c7d81db1909b646e92412acc7365923a940000000000000000000000000000000009f28ec2f949cddee9bbe2fac12c2c029f4e472afa1ea56d0edfeacdeb9f43a4a43b79ccdfbe8957b4cc16bbcac1857d000000000000000000000000000000001474b435131301db9e232ddf54569ba99bc476200ceefc15e4aaaf1a574c1de8bd2d63c8280e23127a7a036acae223b1997ff3852cd97c3a65bce9083ff66197fd5c70894641195514d556102f091e8800000000000000000000000000000000168475854829d47356d9a8dc13a94e8d169771ea0070d9ef45e666d5378dd676d603c2eb57a3cda072c11e0926b02d650000000000000000000000000000000008b493a9f4c19831341782fe6285db2f7e8250d72952351ddcfcae6f22a2ec0935e29d396ba32f72dfa4067d0e7ce7cb000000000000000000000000000000000d9e72e22f2a1522babc5f2e8dc7857ee690f60f7843ffe15a080d56bf63db86f124cac039cbfa16fc8ace4d6268a1180000000000000000000000000000000008f3db1f6c0e5e7b3bb27abd34bd877cc3c373c681a3abc88eaa91636924ee477ba5032801dda091dbc51936a90c84685ff95dfa306f91196849d752569b35812e1db7946708cd06df9db9ee75447bc30000000000000000000000000000000004e34bff7e9e3ede02df950aa0e8c5f4c5f85cd3be89d211e957a7de95b8e321cc11400c3dd5b2ba0d1a3008462cebe7000000000000000000000000000000000fc1047097f01fd2079e6357ed379ba39107ec41ed6c6dc17fa6248d52be2b1cc2593c9735a6cb48e6d6e0434028f755000000000000000000000000000000001896fc5e990aeb416cf21ccc73f02c41d019d0a2679bd533d0811b7c16ad3ad3a6988170fb2db030b5fa7c3e4df5acf4000000000000000000000000000000000b70e14ce1b54d7913b9f3782b2b8ff249967a6b871dfac7f54f959954febb2783cf20e20d1710e5526ef8aeafecb3d603c4308f0467520343825a91c0421f9c9c9d06957fa2fc051970f14085339e26", "Expected": "0000000000000000000000000000000008056d4dfcb593c10a877cc8a4accbf58f360256b76876ed2b33a07be3110f8e295ef459dd6fb10d12bd02a8276351f50000000000000000000000000000000005686da1a0da89074c6b13fe9913f5cd49e0ecfea46e06493510625f1393ba4cc2e13f023fbc7ec2e130bf9a4f7483ef0000000000000000000000000000000010cd660001f65876db5b2cb1a56d85171d4cbf037f3bfb0e01bf4430c479237cde5b6cce5839a4fb22b406846e757868000000000000000000000000000000000809d7711211d37df76cd1cf71001cbf02c76df67c83e4eccea3e05b11d196b5d52ad7c3d0a00d9f0ef5b018717fc3eb", "Name": "matter_g2_multiexp_67", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005d6cf50e3add0e5ac3016b394ec363d6145ed66ef56b07bcd33c90600e83b4277558695222062e02d1e2b0693858e73000000000000000000000000000000000de8caaa810d4ac39258e3d1656bf7f2fb7853a5963ecb989346abe90d5d35d3662f6e283cec7bc386a6a8638ac395ed000000000000000000000000000000001849ef86eec16b0612f214c5ed52c0d50a90bd65b623402879f2654fc578ab680d49af9afdeff546702304597a20f1fc00000000000000000000000000000000168707730c4e74eaa4e85e48e7239b9ba3e8cb74c24b7126a685da0fcc963b9f9180e252adf7d8c521deb1a2ce0099582849fab097a4f71bdfcfaf435994a0c6ac3671a4a9ed0402010be83ff95228fd0000000000000000000000000000000007d4fed2fbd9e9dd19e0af5c52637b2cd337e0bfbcef0384f182a56189a7e7304b9d2144266ffa79044be90cb7ede1b6000000000000000000000000000000000baabe8c23a10cfe85494c693d1b09fc8e43ef5f233052d5b6294dae14b4ff9e5ec240a1c00a16a9ddc27cf7b53bcc7c0000000000000000000000000000000001c595f193229da9acff04ef67ca444b0cec75db5b2c1921502e37eebdd2bb43ef47290fc6f1980abc75ef4c50034df00000000000000000000000000000000010fe7f3110ed3a240366ad7ba31d56ab993468dae2dc1b667a46c7759baa37b865d02834e14280a2ccc062af5bb2b7d6e6558521e301eabf09e80a509b46cf8ec118ee8586f4e46a7313a96dc37ba69900000000000000000000000000000000150350d8a771c79268606d6a5e1c147dc9d92e63fdc60b20be688bd52eac697aa5d90fe1b7b91321b2af87c47ac0d5060000000000000000000000000000000000fba8f4da448b8f2bbd99014bee2f9c581f2a974bb0b54f41a84a7fb359e9dbf88ba59a705504140284d486241e94e80000000000000000000000000000000003bb92d6a603bd93f8e987071a7385de68d10cfbde389eaf01ba6480caf1ad8aea03c84d1889b7d5b5c5f72e62a2d75a00000000000000000000000000000000193342a9f15109367030724946342e564507b26971caf75190e0b209e429a948d8b21ca16041a01010b68222db66a16b8f2f7c525fc0f353700fa823a5d32a93189699206c5ba5ed271a158ebb47674b000000000000000000000000000000000bc4a46eea57231cc64758560e3032a8ad8f1907b3cebd7a8faeb98c4216cb8a0c8fee09929ecefc4bee7955f4e799ba0000000000000000000000000000000009f9486257ae3f94a2ca48eb203e2ef44ecf866ddec7824e1a4bb3b89b320c38b3c46de8202480628c53c415433383a3000000000000000000000000000000000d8e2b5d0825b11344d16dbb2cc614c6b84eb1cb43f70d70e272123867b731775b429aacde611318b2700aa567a84c7a0000000000000000000000000000000007f720929287a70873e9f2f2031b66693eaa6e604668219aa5aff3f50e720b34c5fa3f5c66eced5c3e86e8b34a81b984c7e8adc0f0a042a32c733b5c3356cf4a7d648be51c1d78534ca65dd43a0c13e4000000000000000000000000000000001537ed68e203e56f31498efa314322694ebd74cd1dcc3145d534299fbdadd4256f20b9f74b895931a60753bde6ff9030000000000000000000000000000000000935c6ae847aa7f47bf427988665e5e18a32aa869e196cf9d5bac1349c650219a8d20e01bd8d49bc7e4bb8d464aee84300000000000000000000000000000000013e0661d7254428861cc3ed47c3fc9daae8b86db35d1c64f8ced3bc18a89202825f13163ff94ac0ebf046a0a99727e200000000000000000000000000000000039a6b0b2cb91e460d50eaf9600c29fd4f82a81c283ba4fbd9a7d103efdaeb1e82947f5cc1a7a1112ae6344c51119201650081a6720845a20164ef7c06ce1e73286a32dd64efbe57fe46765008dc9dd500000000000000000000000000000000071a6b0267806f2b9e0ba493960fe0e43f135c739a54c8daf5ef9ee348a281f19876f80c0dcea59dfe9457b49809c12a0000000000000000000000000000000009ac83690c30a4afd78f94b2493674668da4efc84007d2a08fc78bba271ed1f43e2a9e5909149bf0811c44dbe07c52f9000000000000000000000000000000000f5d523612fdb2e7dcf5da56720057dff6b0b80707cf5924d146c0c072edc0635c73fb04256e06c7c9355cfe77a7af0700000000000000000000000000000000168431fc569869ebba9b4a72371e3df232545b5fb95778baf3d9105930d9a89b4cb7eba430e9162a5589c7465e54ca3ac067d18b95591f7f14261f95513e1990f5a4f6908f94a015a93fe379726d5120000000000000000000000000000000000ce836522b983fe3ef6a502a0de4c599fad8a36a60d914218d5d2cc4d56d69eed8d27b2d50899639d1a0ea9dc7597f900000000000000000000000000000000014110ac048ac4c20e53f2214df8c06d77f0b3150077d027691cacd3715d4630a387d5819ef58eb1bce2e8669be330a3100000000000000000000000000000000178e5cb42f56df2f1b255a028a00df96c02eab0a79aa0ff3e9772fbe3eb62174728259b3a15e356e6d9666eb65fd6b7e00000000000000000000000000000000045197f136649b61d6e0e7b9a56674e769e2d26716ee7a63fd2b83b767a9ae96694e9cf81375d0377a1b27ea6dffaebbb448bb01a1963bf74e0fbf99329005af8e932074358d855ff43c213e02bf26bd0000000000000000000000000000000016a6a58301c243b0c59d6934bd926d6440b87b49f004f411ab0fdd924480175052f63f594c18007359055dc776e7f2d300000000000000000000000000000000176db4845cad46a13d9dd0f4077cd22b3458f64084c7325e9885f8ca341ce3ccd4f634f41efd6a70f16e1f0c9ae103a900000000000000000000000000000000068ba68f652c4f072a64d56618f93a1e148274b1b835433be878c06e11f65ff45b7cba0f67fbe80327abace68396da7e00000000000000000000000000000000047a699487964c98453207c98cc91c980c1ed37dc26e17748e6ee88e5f4c0ce424d87c82ca6db2264dc8aa9e437a5f25441fc4cb1ea8f86af8839aa40c35c0706f3a159b4bc902347009f744b73cee35000000000000000000000000000000000bf7e4a9751d4e3baa7ce9906f4378764e5384136944f6d3f3074dce66ed017759783c64fc381f0dd7512d6f6e55b4aa00000000000000000000000000000000006ae2a4fda156818cb5ea6120edf7ea39370eeecc3f306890f47a6dcfaffccbb69fd21f33fe491b7065838b277ad2b2000000000000000000000000000000000d3ce00c2f5febfeb232dbbb74fb0405bab86474d1d9c545c93b65c7892bdd58aa56225641074ec9b428efd9063085d00000000000000000000000000000000002552a8c1848fbefd6b039d6c4bd47c34dc34ab307163c4f6d337946f1d1b41aff2f7e37f5fd94012f0ebd21f97d18a83020a1ab853ef2018976e43cce2724105a2526b28d23b0226c49ff3d4a03d40c00000000000000000000000000000000105320cccd67b6ea78e96e66425a10a6911d2d348fac3231af583146273609fcd7fd27a19d4614fbdf05bcca0f92b927000000000000000000000000000000001204229ee1f66fb5a5dcc4ee978327e35d703ea310901be9c100af824e39d24a028ef8fce42370e5d734df02a26c145e000000000000000000000000000000000dd21f31f116681c1810bc36141cc18096cc113faee7db2c189abb7a746e398e272fa0cc61286aea0a5ec4008c8d03b60000000000000000000000000000000007911297718e98588844b9022c825bc4b37f2af30e1fc2d9cfb58b4500dffc8e9949afddd051e971fe78d4e1e7ad1b4a82702398b8c95c3a8cd163a8a3cb2a7a04030ef99404c325115e9a9312e8c1bf000000000000000000000000000000000760787190048e6ec8bc3bfc368f010e2f8aadd53164693a62b0d7207575bb2597bcec4bb382c57fe9053e90fe2f7159000000000000000000000000000000000ec525abbf13da64a8093c5d3fb800440f4c1fe798bcc71eb97bf2e0aa9e8be4b08afd2313f9143260058132d2607141000000000000000000000000000000000aa12c902084eb843daf7b351989bbab7a86acb62eb54eff0c7599bacaf44653c9fbf53f47f6ca72d22ea1671842eca800000000000000000000000000000000082f330d9a693f2bb9386fe5274aa79ac73a17688821f3c705120fb2aa76903627786a8614053f21a93e0aeb555de64e338468a325384a9367c90bd0450816a22849b845aadaf187c27b3f09800e791b0000000000000000000000000000000002ce7f08b8d5052d8bd07090744ca067700eaa1db61dad3e5086661850337bcab485c15fdd36c309a9e5169fd2a2b55e00000000000000000000000000000000073fa834cb4dc4ae120e738059749bfbd86b9e64fd71b1d372dcec8474f3341137ce8cb97a38955e9081f9bd5e07ab830000000000000000000000000000000001568df6806d8c3cfc9231802ebe5edc5d505198747a0adc24d0ac59f28d32b7b379d1f2c6b8352389057c7465692ded0000000000000000000000000000000004fb4b08a4fbfe197e924be3f7213a769a2bcd24109ae69a32a197b6212c5f50dbe8f46f5ab6044a4c779cd3e09d13bdd29136cbc4764346e7ae1af92fe64560f453821f96f32a42a2006b6edee75021000000000000000000000000000000000c07ff656904a47b0c7bf77540abc47cc6eee3e76b6ff0983151de9468ce3a860c427f3d5d489d096264159ab0567cd20000000000000000000000000000000008cce094ae1d9fff246a0e76cd67dbf9808c94554372fc4aed4879487ef240e45047dc201dd8bbccb613feb9c4623a0b0000000000000000000000000000000008a25297940a1bca1267fdce450b0cf43105eb4a21ab14562116039bc8379b1a3f58a7c117e9ba735bdec40f772465300000000000000000000000000000000000ae17a9b1fc3b0b7803ef48cb26643e8e78ef133f94bff5f87739182e662e2641e72383efab1f3ec58fa20fc816d56c675a59418f1462247d3bddda5937553e96d854b5df64a68145a193b2b1a7eb250000000000000000000000000000000002357e5a04b0dbd7f9a1709bce9b7afa12b10c7274b440b4dc3bf51a801d483804b1b4b9a096c3205a0e2aa7c0100c6e0000000000000000000000000000000002ff20af67f126c80293e44bb3c9ac74a94586a2de4146588c7ee8503530398eabc30f7e89322727739618087fa55de50000000000000000000000000000000013c6d06ce509fd557946479f2768f62474e6db04b2c92c5cfa86c023f79d05a387bd4c9aa618888476d4ecc93ba0995e00000000000000000000000000000000000fa477870c952f7506b879b17fb0a1c31771ee832ce0ab21a513fdd91b7a2a78a03d297c55558b834e255462b15520544a345719b40f973398a6fdaa2044037cacd7f6c361921c62053cd51f2e5ff700000000000000000000000000000000181336b8fdc03c02e23cd06ac975855caa2bbc1fe78a2fc7a9d0963c90a1f1f9330d50b88bf2526db6132d336ea5b8e6000000000000000000000000000000000f2d94d3fde2c0f67dae5a6ac12f713ccce2621303762e01961843eb9924d1d3c732b4c977d8cd0e5668adcd7dbf7dcc0000000000000000000000000000000005ac9ecab11c3368c75b0d396889dc34bd43ccf550d817c1dcdc7143c15d5c0e241add37328a7bd8556fde87d75d67fb000000000000000000000000000000000184704eeebead43f85b32d7f3efb9b9469f3ae10b73a2f034bd33e6e66da0bc36597d8e29ef5585443a655e24ffb68fbb38b4cd72eb18c3ac87860aa58b4b439712562f742f112b5d769415e9c19d0a00000000000000000000000000000000046751743f8f747e378738c265c1df3a368cd9570a2bd7636991045974c34039161fb0eddc6b813003e0908915b402170000000000000000000000000000000003341bea6cb81fc5e7baefd386a518d17a6f752c0e1ace5a9580a1b1649f5501c7b4639ba0cdbc33808d78b025a31f190000000000000000000000000000000016e3b9e8e189df73574a00a721440379589a7a6df09eca9a790e04c729400323b2110f63d547d83664c35227bd15b5760000000000000000000000000000000005ebd94e4640344e99e7e0f1619c6288665c985b90d99921ee61bbfce921265c4881a7e1034bcd840a665bae44467f5a94a849f6fb5a53bd5957e53ade1baee05702185b4d0fbb7c1cc0f46cb75614fc", "Expected": "000000000000000000000000000000000d993522760839abc960e99d62dca1021b52ddc8147929c4a064ec72570ffb3793205598cefab8490446453fb6da231600000000000000000000000000000000105db1e83fdff735d06d34574f962e70d84e2c1ceef4d8a8f14c2673633d7dbc7b97ba6dce9013f06fcfb134ffa2ef98000000000000000000000000000000000363be663cb0d36b8eb076df283b075ab9e568e460be804f197c51cf7ef611d8783ced304407d4c2540f1a4a04c18467000000000000000000000000000000000ab2c00473a2267682ecb356422aeafc893fab96a3bd27ae58d9b0786624c8fde446cf68bf8a003d9449702e345b1ace", "Name": "matter_g2_multiexp_68", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000a575d896b06c5ebd7459a70b9321cd0de082dce7dc0ce7e39581751d01b7db810bca80f39f521df0bf70ef642bd66a000000000000000000000000000000000ab497a9590deef40f6fdc0d4db2ae7b6ad9ab59f112a5a0671b48581f1f2b6a71602c73784ca6c0effce66a0a9c6500000000000000000000000000000000000af3812439e44981c91633f73d1a92298ca1ed426c98cfbdb50643cee36affd5fd02886349aa608f4b8a27452a51a96500000000000000000000000000000000013126db8b642d33dd988b745b07084ef86a228767f7e8bd45aac830dbce4136ca5febca5fda9644d3292203e27439d9f5b9d270fe31c772e9a0bb409d9f08a07887f045f906f30e2653d293b6c2c277000000000000000000000000000000000cc12f75fe5e6d6f082f9977dcce64c7858f3b6378112e7e083caf0c4b33b5811d62a1130c595937983905fbde8db1fe000000000000000000000000000000000308b803bcaf4f63affaea0206aa9f4770c21b4d191890602bb4151b80fdb42af0cd9f8dd2b1a3adfe28d0e49712d2290000000000000000000000000000000019f83af5cbee858fcbc9bca0f499222849b9e80dde7ac79b7c46785a484fecf274e0d4326469eca647cb223068a183d8000000000000000000000000000000000d0a8334171571bc63054c032299824523bd2476b1150a67eb17b84bba01d8a65295624202c3874e0302159951734702dcbf4fe86140c50618598be9185830bc1da11429162afe0528f00eb6698ec088000000000000000000000000000000000141cc01094391887f46391bd49fdedbaaf524cfc94d741cc7c8cf081dd7c425d81ea3e407be48127550012e39d2b0580000000000000000000000000000000014db31972eb242d6c2912b418ddf416fd7911f13aede9194559b05d1c9e12056deaa1e56c155cdbc231b39f4f9aa91ea0000000000000000000000000000000007b361beb6c156b5c8b92b489e6d6c05e32a4376d20ac3e1a54c94e678c88480779bb789c3e1ff7a021aa6d872c98551000000000000000000000000000000000215d270f2d3c5c5b9fa99a873fdc337f4edad6889f7a55556d8ccb5ee86b592453b74a720ef6a907bc342710cfd9cf91d7fb7121ef0baa85046567014620e1adfb9e8b3bc95adccbf2e0b0ea8f37c670000000000000000000000000000000017f5d31987655f8eaf046d6ea4025444924befa51c319b2bcb02dcdfde4d80a1c48049514e0b580e4bb59dd2fe40bb22000000000000000000000000000000000141ab771c08ad7c592725630aca0b2564de1ed8759eb3afb10a4bf451eb21d25e8d917f49bd5f7a06894baafdebbe790000000000000000000000000000000012dd82703c939cc5e7dd5bc3b924d744f0ef1a95fd0b9e57617e822e3fdda05b2e5a9959ec48cba0da40079da2253cc7000000000000000000000000000000000c53ff34d875fec4c7095af324d15921cd775873a3ba67740b2c123d6d482263b1cf93585dc810d19c68965cdbd9e102310d3b0535e78d803b477e5dc26c71bb18acfe66bd5ba5892d924d265afd6a16000000000000000000000000000000000a6514331035d42f58abf98b805f159921d8c4c935f88bb5493c580a6ce14a65e243424b41b3a9188e26a7f0c912a378000000000000000000000000000000001351e48b2d3f619887f4e83823dcd9dc15afb2800169ab78a2cd5ebdf25dcb6310f1051894bd2b549e509c55f5286f600000000000000000000000000000000007900972b84b6a76b2e686fa5757e98b8395bfc99da86eca122ce209afb39e8f3b07603cad92623774ed54d637e350d30000000000000000000000000000000002c68c42b3924b89a67764990478e48fc17aad4b5543bd38bcfee34fa1cae7535671f3b885852aecac53a30f28b0d4aa2fc9417e65cb76aa0093a7deb3d38c111c68f461a4aac57d8f09189f94407ee8000000000000000000000000000000000152d2c0e798d85e4dbf35dab808dd29d724e9b6c7ca7f53ffddfe1aef5976f2d3079eb1d3099e91b37d9fad7f1af5750000000000000000000000000000000015059423ee4e7201aa65e39116a2a49ba715b15e4b9547d18a0efd355de6f5a0159bc9047508bd3649407758d62887f0000000000000000000000000000000000e5a823fdc69f3928b22c542388f982f8131a978b08dde80d44e51d9eaed2ac4a1d5fa7392be6c7edfa33e833da4832c00000000000000000000000000000000044285f4e4ce526f96f9f512c5be754e0b0953744dcc04807ec6f041ba5c6fb9d5d395e93317064d50e61aae26810df0aa0b2d714aff175a0be2ba9e675a2be8936c42f15e304a146622a95dd6b3e3ef0000000000000000000000000000000019c457e369dbfaa130ee79bd33ca70d00a3797b6cf62126baec0c5d7c3fdcf5ba7f41195276dc412b6862b71560aeb77000000000000000000000000000000001206f67dee6521ede85573bbd5784d675fea42da16010544857d4e2d81b720b6f85f646fa23540880b44a6cde9a39f5d00000000000000000000000000000000142018ecd7c7acd4f4ae288e1c6a66594f1c7f31bdb9bade2b4dc4c6455cdc685b716382c54d67373831a19100185e850000000000000000000000000000000013b0b57463a3e4cbe063c0d4f4e998cbeb132a41c2877106ee60e83d4ef7d339a5432d30a3c149a42dfb1da9d61f34030227c3510ed6e4c7f84b11ddd2d6caa55e0e79ed59e1cc0cb325d55b5d145aa80000000000000000000000000000000008a463003900194e45fc2610fb461fde538b17c4fd516919000d423f5a1b582342ab9ec20d8eb6fda8fffc6a898e46420000000000000000000000000000000010eef0f7bf73e35dd75fb924bd9759c09aded9cce46b05e5d3c5eb3e93e5d5032ecc459e2220aa529d2f773c4b8b8c180000000000000000000000000000000002a0247f82a25468ee74da555218cdbb6405871f7097c24e89db3f3eab59b91ce48ac06e8eab2c049346436c846226a3000000000000000000000000000000001895b58a50c025e46a2cd0c59d5437f6eee75fac949adb7ee12d455c96206a33ec9ac17d5088fb773618fec131981ab6ad930000a9f82e082d408999b396aca2b0e435a66faba1d95e10fa0abc0625cc000000000000000000000000000000000cb0f13b0680c2f7de522a59f4e46fe1d4af3a64cd3ab97a2523ad3c3dc42f5e6760e06cf48e4db22ee64c5ed8273dd90000000000000000000000000000000016517038ecd2799d787c5b6ee93079c93f78de4a96449bc82699ddd6eebcedaa1d02981ab47c529652cc21663f1a665100000000000000000000000000000000067ae1dc093d4aa2ddd8b7127dc60745ce9c462a066106b099a7a07525597c72e4920bf64c2ea8a3fef3de51c703de8b0000000000000000000000000000000016374f51023e2448eee7c64115d85794996fadf4f76fd4266c45093c266f35be09e861d07ff194f3d15e310385705f0e1a6799cab8964c7b79b80e76be237ef49c2bdef5c99a38ea873af6e9d49790ec0000000000000000000000000000000017479396aeac06bd624a47e75b066d6daf5a37dbe515650cdf3e16be21e7d3a1f52a695c1c06382589eb7fc869c7d9250000000000000000000000000000000015c31ff36ed4eaec4d3927e62c111d062236e19fe6514236e6e3f7ff05ee96e3e4c084fcafcd21049a81faa1f84b7e7c000000000000000000000000000000000341b440e6c6273515fa7940d2f77018169bf6362b70a7b0cd6d66cd332ccc30e3ac48f7581edf47ebd137253a9c1369000000000000000000000000000000000cf424de046252efea9320b32b79bdab58e0e04f2916b4e8ef475da7b8ab85d8d5fc793a45ec6e6c035b6331a895d3efb206dbfd70e4b24bcc09ad35ce7b3aa62d17f18347f2bc5f15730202909c93770000000000000000000000000000000007c9111a85a6acb851e9cbdadf182096b720913ba3fb357dc2cbf2b8e796e9a8044b6df3ccadb740c73a16c3780c640b00000000000000000000000000000000059543a955c84a197d23cac22e15d82363c881026e41c57ee924da2a8c044f3021b29918d1db7926ddc2fc7a662ee7ab000000000000000000000000000000001355d8bcbea65a50c9b6ab59881e48e8e5f5592cee6aa69d5d01b033a84057cb6e74d911769bd2ab5f9722328aa204640000000000000000000000000000000011232571c95d0cbadf8e70454c851974efa4b326370249238db159a1224cc6d34eaad690e1840ad887a875b667ac1f193a607a7301bb7dc5b9c82d956ebb0bc54568d0654d725d4d5f13ceb6231e862e00000000000000000000000000000000088b7cbecf91721e01e5e4a08ea3b261febb58cdae3056d9316c3840b3e5720a289739568bec7b899f4b1f4f5372013b00000000000000000000000000000000001f8835d4b0e3b957e46b718b6bcd81acdb50ab85f10bb70c6343a23970efbe72bef89dbcb24d66e6a6be3eb55665a200000000000000000000000000000000046500afd292a31bb5a4a9bd7b5bd0fe608bb1265351edea69162e61f1623cf58e34e8e1a8ec58ca166e8203c86f84c00000000000000000000000000000000005d6cc367ff9c88fc8b6c35383f147b4f9e3eb21268a5a7405794441d449b3e1b44c8f66e30783e5f6c3567adf0d80171231e0fbbc2d98bfd1039a889acac471110d568b0a24ddf5eb3501adcbaac6fa0000000000000000000000000000000015bab57412cc5c7ee0147b0d2511b7836a14a82df06b4eb2b1baab102840ed04cad81da6e920ee000751e0727091c1460000000000000000000000000000000002f725e61e82980e6164cae7a2e30a36dd7245402f4933697607640d53fab2d5db57698be33a0c9b5dda14aa846db7c90000000000000000000000000000000007fdc589448887f6986efd817c63954d350511401333cb0df89214317dec0a82b06259ae9263f260fc7f21f98ad2630f000000000000000000000000000000001324e3bb46a1c69fc550fa8f2ae2d0ea74bc2d7159bed03c13a9d232233449e271ad1c3922dac5d84aae52606f77dcc0393c5c10d4bc4cd1567bca6960051f818e5c53704ce44dc4582767fef1092a870000000000000000000000000000000010adc26d73007e3b1cc58684fbdd7d197550658b4c66c702e9cd0f4e481f23a26c94c6798cdd9763110eefdca3d802050000000000000000000000000000000009138258ad1bdf6f9cdfb943fa32b42c4f1d834be536ed365d00126227c78b0df2776610fe5cf66a937cca3e0b088861000000000000000000000000000000001991db3a35bd2cd72377cd459502a84315422bed92890af906fefcc0acc4515fe7cacee1e4f360ba24efb23292482b8f000000000000000000000000000000000d10dfb682ae7a78b23b37b081efba32ff2011fcdae7b0f8a794a6ec33d71f5d6055f93e3b68a37086ab190d7d9bd7aed412195e347b680430c4528987859a1552ba8383cdc075c437ef19db6eff6e1a00000000000000000000000000000000182795b905320ee69281de833f37e040a3295e23be05ea7ae4563bd49d8b1fb02e95782c5c19645244633951cc29c5c900000000000000000000000000000000053368ee1412723b5c6465ee5ebddcfc00812e0e12e940f8485f44bce475c8897b324eaf7e66c0351ce9a6c92758c337000000000000000000000000000000000279f26c1e76e5f5d0fe1240c0956cd6025f6520ec303feb383b69525ebb6b2f199808a578a91368c3881a4044f37be50000000000000000000000000000000000ba4012c24dfe1038ec4b4565e1b321bbfc174cb197f0b0914bf1c126bdac9f423845f6742129670b7f3dfeaaa62df45b6701bc11c1ef3c9389710e4dd090e3db481c5400ecb91655c20694207a71f10000000000000000000000000000000016c27a3a950fc4857fc775441947f7ac02af9b3df6422874507b11f7b005c61d7d6a4a115d3759fcbd64633a8ad95611000000000000000000000000000000000e92954034df4f15450c32be31d4e146c4b0014a2b81e2afe755df79aa962afb05ca4d03577f15980fc6d8a34f2cc50200000000000000000000000000000000032db3e3c3617c16ceb1c8fae83e806744ca40cffb56bf9b79997cf48c55e5fea89db43b368cd922cd7ce30dd3984d82000000000000000000000000000000000d153fadc3854be49b2376ffcf4e5a46b9dfb4f54e580986767db13127e2d4d10e465f1ca932d79ca90f1971ddc0993dab45b07c059738ead9709bf36ab20b09fd3368f7aa12c6d9f3acf3f145c83fa5", "Expected": "000000000000000000000000000000000e1968e131e25d3f911284c369eb63aaf264ee82f4d9bd978b7d02470feab68ae82aed8509ffba875798a292f012c9180000000000000000000000000000000011488365570d9bff018ce6aa15e3d7e078368f09873ed5e0b827d1c25ef369d6571899c8df38a3df3135d0db814c87a700000000000000000000000000000000161973f4949bd72b9f010f017398778e0d7f0c8f77e12a87db1851af516b4540e3f4df314381f295c4d167fd9ac091a6000000000000000000000000000000000ae16f0a4a597159195aa47862585839485615095e538b745c1081ca73f202115a438d279dfa45bd3aef8d4043ec67c6", "Name": "matter_g2_multiexp_69", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000046eea8e5af344dc8600ba7e506e923f6c356f7ecb3b78bb3805c4561e808c1f570e122c4fc5a1fbe433b48ce0c15d510000000000000000000000000000000006f1ab405a46c825e104bc963d2b2f573f0d345bd2b08a952d8793c0297dce267a754b802ded4db478399cfa88e7e255000000000000000000000000000000000a5fc4a09019ac9649c07b623d2cbcd9f0cbb89d28c01b170b62544d8da8ba3f236ca3172ac754175a3db85d9b846cfd000000000000000000000000000000000f7580110db2549742f69bbc2850e4ab35a6e415bcd1b06220b9b009c1f4c99152289eedbcba2aa653f38f6b8460386b3ca13f8540eaf45ffdab5182883d32a1d35e7cd956092221cc40232efde6cd1e00000000000000000000000000000000026907ccf4d501265cfe67bc1c0b06840e9dd94a614c873d676b5416457d98a1dd744322887f1f1f86176b11a27d2830000000000000000000000000000000000cb08e541a5b32fdf51acb28ec64d3ea542c7bd75179fa3f74e9588156815bda9d027dcf5597d714aa001b2dd8a9553c00000000000000000000000000000000103ac1c03c16706d5936f216a6445577c96acd3a00a3d8a9c2c66e6ce568dd84a4c4db187a5fbde24e6ce60e037f53a90000000000000000000000000000000001da5cedccc02d0f8d1dd7e4d81c3ec47d432e81e941ea1452b112eaf40748a6634957c90f32fb0385dc5d642bf65acdb3c8b045ef559b76005875bce09a66b36f295070a73ec8dc66c86bca51fa5d4d000000000000000000000000000000000a0b8dd68918b58ca6b113e938f8a00b2595351777aaf32dfbf703ef3884f02c798f1b5bb78cfac32f196c1fe88aecaa00000000000000000000000000000000121a4104e374566f8d582f75a3c9b70f09628f116b7ab22679ee13a1691b0b0bdb0d737833fb606c746fafee5859f1ee0000000000000000000000000000000000b8bc89d718572ebdd6e3100769f2571cabdd79ef5ca9a4b9bbaa432b1a4dd752f9af9d2a9b1f1f32d76d4ec2d1636500000000000000000000000000000000129f1d760a12eb1a75fec1d2ca438189c933e87095b9fbf9a0371d64eb205d8f0932fde9ee2ab9f36f8b6e5d4b5dd31021953ea264f74bf64378a339461bff41c5193e17913c67be7e2a249c9737b825000000000000000000000000000000001499e5481ceeefcd2ff672df24e8987fb60872ed106c496178d71c68e9078409a80016e1f9727ed0d5922c93e821dcc80000000000000000000000000000000007bfb606c005c7da6b4ce2d974f9fdb2e3710c8f51f18257ced7663cc341ff81fe2e46308a2b62b13408965949a6f08800000000000000000000000000000000003fbd951e860e3a4724b667427fd9916ca4ba511a0dcac7b1125b14d8a4f4da82ddc0b0edab8ea50e911b0fcb5c200a000000000000000000000000000000000b43195a5f0263307e85408ae4eb046e06ddb1295a490ac4e0e654324de53d0dd023b8cc159d86b861dfcfdf7ebeee4a505655d72f1128ac0204539f0d823f076cb3a57a7e74e896b5019c9161d6486a000000000000000000000000000000000743bed2c17bea1ebddf750da504fe120f457cd3b1754c9413757cc48f7aef07eb4fa0572cb853cb72d68427e875456000000000000000000000000000000000102ddfe3dee27186a9484f74b3cb3aa366a79f0d2e36063af6e484f6a459e9168d7a4a6969bb720ec694a52db7ab34b40000000000000000000000000000000009bdf5b86aba4845adf9187ccf9c74b1fcabaa05764e41fcce4b38356b4a0ace8e7b16abfc7f7b96b785ad47fbf8e90f000000000000000000000000000000001934fa903b71d234c4341b2f49f8177334142e7c401553dad38e66a2c157fcdf7637165058955b7798a59051846dfb8cc4c861cde3f445e3a78d1498d98b2b947056cf578652e19be88da4a786af196f000000000000000000000000000000000ddde953f59b8591a83b0cdfce780ec23d052037c26d60cef36522d0f984f907315d7b41c8be9a9632f2b88e0ce950ce000000000000000000000000000000000b8d7bdd94a994901a434e6ea5d03ea45dcdb859e560833d8ea0bd9d20c7db9c16b2427eac27d8f1eb640b7d28a530fe0000000000000000000000000000000017b5b3a3097a74d9c1f1b23783723235b6148023b6b060234dd9e2f6fd05e38668167136c999d91249963e224f9bbcbd00000000000000000000000000000000133da0c217c31ca052800315aa8a3b934fc1f179e6247801904bcea1e28dec0b65632ab2690bcca3606bb1461aeb147b99762c5189cf154e24238e4b157caa1d8759002f69b289cfbf3f24f5dabf20bb0000000000000000000000000000000012778a6fe79b1f2b768432df036543cade95504bb7735ff547969faaa8db84e3588046a074838c9a551a4fb48f4a66140000000000000000000000000000000013288a3413d7e7edebd118463d5eea9f9ae2e10f51965480f9b5c244b05775d04079a1dc75ba0885aaa9e2e4bae1ac750000000000000000000000000000000005b766ad112b8d69f1a28079688942ea146f8f31616611909f539a57c58ec5e857da9fce415d683c1c6dcb5e74da9d17000000000000000000000000000000000907e5c3c83d3f12a68d6bf812e310f5a04f1417094301fab7d4f41007b9d01fc1bfbf739dceddef756417367ed5b1d0298b5f6b43074b8f0807086b03f5028709209310474c35c7ee232eec8579147c00000000000000000000000000000000090be6ce5ed09e45a6fd9ea3a9223fe43a835141c1c29d6b386e085846869f9c5798b80c3bddec8bc15171906dd417dc0000000000000000000000000000000019bdf67eb16f2708ca55fd20af8deca66e2ae270b2f2f9736fcf49dbdf7cee034cc956f6fb799f0e87c12f283a11448e00000000000000000000000000000000124a69c723cbd366d52919a72dfceb7e4cd9ca5b5cef1784bfad3f125b11d810328ea1c849602536af500261aa684f5b000000000000000000000000000000000bbf05318ffd81495efa4f4c271c8b1c669041a6446501788f49b8739a934f09de9d976fe7300b0ae861be567d35c992177bfb0218ecd8cdbc6dd9484e74e41be6971ec2911bacc8b53b9b4b8c70e5730000000000000000000000000000000010833a3e7329ad40c1a8cef296b015f6ac6542c612038ce00f13a99f673783cb7eeb14796485c168d21cc169065d051c000000000000000000000000000000000d3b1416b23453b893c92a6c7850cdc0e4a395459140391b1dce11055da10fb68f318c5561e1c12d991a28f3f544a5230000000000000000000000000000000014721dc58eada80f2d0574fb4e2c1c94c45fbd90c2d2fd666fd618a96f4736a5ecf34cab34fcbdcb19b6cf7b44098922000000000000000000000000000000001905d34029bf84617a956d1edae090853dc1b622f560c5289251447ab6bcea5700bdd80d6ffb2dc12fdf3b0267e74543cac52219796226385aebf9e85f5f179362d4149c33582a97b7d2aeb05a8e6a99000000000000000000000000000000000b4d380f4f4eb976e6121b933be8418c536f85994491b0b93695d50473615e41547ead326bab795d4d59524a61d607cb00000000000000000000000000000000104b7f4058c9b355d38908d715c311a53169b42d2434de0876f1c4ffce1c39603c4876b33fe3076528be15fe42849d3e0000000000000000000000000000000017e2fd647e7739366ebb606e8a326daa5c03cd2b726cc4cec7747cb3468419f1907126d7cba98bbbc659478ce3afee7700000000000000000000000000000000183be0a976dbb3b5385b544c194e111729c7a8d5aa98eba3fe1c0a5b69b5fe6e5d0164e96398cbc61eba5b86d91b3c94e03afb2efea85fcd035cb4ba09977b2e1c84a0d98edf88e9f8d2c4f116d0f50300000000000000000000000000000000023bc7eab817fcb9982cdac242cb6cc0ee1779bcefaecf144dbe57d5ae2b2ebfe9088f39f416a56de4b4dc04d4bbce7a000000000000000000000000000000001318e728c271746905788dd8f5ab22a3a10edce3fa063438e54ebadba22c29e461b2ed78a95a8f26a65b47022291b8df0000000000000000000000000000000010aab000b9c5de56623f18861b343ffa80da5ed4ae0d7767b7ed791bf3dd507fe7286447b6a07ea0fa12c19f2e4d8e8d000000000000000000000000000000000770e2909b5795a08d98dc66389655b1718e70b93c5bc6d805c3945cb5fc0092a5b390e6497b550988c28c58b6e016a3804dec43760dab29c161b8f4bddc52379a17f3168f684267cfbbc3505e32d5f1000000000000000000000000000000001259a4e36f5bce7d5f97184948d57fccd458cf7f2ae0c9e174f537bece01d744fef544447959cb73a678fe2c378ce3c900000000000000000000000000000000131aa575b2b94232e06879fa1f6f145a0bf5dd12456b698f731a72bc587e6def5054b3b2afb6dbbfc34fa5249dc673860000000000000000000000000000000011d64b923596c316b097a0752043efad8b61fbe068c58bec7a6766d9bc90ed965b3419dde3b96679426f72184adb8931000000000000000000000000000000001653af784cbad5a804e3f72716bb51e0c733014d587952c47395f953828566cbd7da811a3da1d48681998d569db00a7bed2d3daf616df3f0061f58c925e9dfbbf6e9cbfd4b0b3896a596919fb3d243db00000000000000000000000000000000077a9ab830f7683b7fb46676df09f72d773b65286c5f5ea86623306e5de51e63851c18d192c4c3b20af582bb7f017ff70000000000000000000000000000000016dc185f4158e249939541d35ae8230fd749988b9174c40c40b8c932aec625a7e94beaef9a07f492445d4675a01b7453000000000000000000000000000000000c107a895bfb45d33136db6251c76dc0461a235fa5d1ba7a5d216bfebe15691261b46c9816315c146becc328acb6b8c7000000000000000000000000000000001151cba240678efe61e3a36e169e314b3610e9d4df6650507f53ccf635d8f1277a80d86baa85a2d4c7e2af73934a7299e16797ed90581fd8c3cef1f30abaed10997f13461374ea649b29101959fd506400000000000000000000000000000000090a1ee6c611980e0421b72a122cb39257dc38d1e74ee41b809ad76e440fe307cf45e79afddd8d40b94382d48cdd4c450000000000000000000000000000000010f2e6e610eec7b7c2b95c1510af1af342ac19fd3b01dddf81b8961ead2cc57a8eca36c2f5747238eded5914e484c52e000000000000000000000000000000000acce0789cfff975b09d687ef79535c536f3b799157d3ff731915ea5b323ddd9f6f4750dc8e00a879d4e516bce8cb3e40000000000000000000000000000000008d8203dd13aee7363f6b10a9e1ae9b713bbc8b8fb2c56f05fa71e8d69ea571384d150e8fd01e855b1b0054fe7967a052f9f29432638c033ca84422b12ca80ac4ae85fa30ff56c913c5737aeb2c84d04000000000000000000000000000000000b332430c518d7dcd120b346440e5b6b48900b5c3656d84840823a96e5bf002816d583a989898cad9e09ba978ebc58a40000000000000000000000000000000004197b43877b833de7f69cc1a43ad8d6d3544cd10d42336d4b19a187f31337a37b10cbf48e72b77e4d8e1a1da68e5e4c0000000000000000000000000000000008887d5dd08f45034584f40a2a68254baf2104f9d6a4c2637ef79c5ff2503c246f7adc36559758a0c07533b66c3637d40000000000000000000000000000000009343819dec1d4569683de4596621c19785d5ed14ba13e57d94b1b1a108aa62cc8c55c58dfa18c06883ce50cc1364b95e6f1e5df7ff90c4a4fb9a071c0caf3a3997569538ab9837ed41d9d0a8d7305370000000000000000000000000000000003fc7f9a0804e7f1664f8cd3ca67b70ba128529a611c24214fd09674072a6b8d652ccd37bf5d4611424688213a41cb3100000000000000000000000000000000137a869cd7bde696035bd9353662e0d37d2aa0731ae55357df3bc43536b9210f360324cbb3670362cf9ef607b1919bca00000000000000000000000000000000045d9d39c04e257fcd912c54e57c86d2d4304e6a7cb95a83d2bff07964d0a5dd8b4e42bdb91a8b245e512395e6749f1f00000000000000000000000000000000120e5e4b04b8a744757812fc331e7c98b35624faa1cbabfc1470e4c0804248bfb0c53a484107a677a7d3f0d2b533e7530cf3283195707c30880e50ff5ef605b561c3c3c354fbe8108f93b36f212f9ef5", "Expected": "0000000000000000000000000000000002bed414afe9c7a630441e7b163280be10e502cf877e94b6521d14baca0087c5dcdfa39ff4a51c8376d99855e1e6f36a000000000000000000000000000000000dcd54727a7729408e682c6e213005687ed51fa7935c522312793fc58cdb273eec9c61cd8b056a26619fc8dc006b066800000000000000000000000000000000137286f4086763e6ccd5ee82d3bda712b26814a17c6a71006a3e6dbdd919e469bd0e744bcdb2074679e78a1e7d56ee7d0000000000000000000000000000000012d75de1310199c0e556d61d6c0395b406afba0f13bfb37486c05d66b446809e8b1a024e8fd2c55f1b82cf2aed99a5e1", "Name": "matter_g2_multiexp_70", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008b83142b22f6d6496cad0dea23c71355e7c5d98659580b5ee6e97eaccb9fbe523f7e3b925abbca3a38f67426f3fb35f00000000000000000000000000000000035f655a1b2d22ea21cf0081e78d7140bad08c4e66dd45230a113ff3b7a77e39f0f1a72991f85e2b00ff58b27d5cb54900000000000000000000000000000000105d04e38243ef1ad2f734a3c97e91506c5a7c5d95e9b8771b7fded8908f1be933a81a5769044b633d501c0df7b5d7fd000000000000000000000000000000000e670ae4af94d0df34a7f2d7cfbfcefa6eebcf2a6b2dc5b82068b023fe02ce8a279e1bb96d905ad4f2ffbd8214e47d702063b046a71c2674e35466657a85d8e02253b42517b033619e31a536659172120000000000000000000000000000000009051f1e636309016c5433cc7eb019c7dbb75b3a4a5b27f6927de08fdd9577e8eb9e12919157ed35bfd6607be7fc4de5000000000000000000000000000000001953b7a33695ede6d0792eba85567aa5052b8a58c1bdc94ee82b5001893c6b996d3e8f7af8b8effd6cf50656d8b85554000000000000000000000000000000000a2f769f00679b610bbe212c2f8045e7579a96dc6bff80899eb7715aabb1afe79421ad5000f2c7b85d4e0904e335ddfa000000000000000000000000000000000ec962a3d00fac14d05774adc49bbabaf46ae78325083c0020587fb85eb234387aaf6506f503fa988df8e9ecafb4a59992fa325cd07502c6576dfb93ee952fedb304022656597bf3bb03a2bbc471b32a0000000000000000000000000000000006823056a4da801cae430fb9e3a8663fc8f46bb6c180b743b7f9c7c7e3287f3feb1aad4be0e98409c74ff58004f8732e0000000000000000000000000000000015f7a3f692d55252fa5af5ec952f581b796d54089f13971fce2ef9062173664816dd9f37174294ed78681d8c8c5a9cd800000000000000000000000000000000154743c76f7de590a31cb96d46a0ec0fa88008b7d6684bd8f6fdaec70722afff7b6e88c1f0fb048714fb1072d30780e60000000000000000000000000000000006f3191946d0e7c1307a1a0d1ea9a26db195ec98ad88f9b8f08a03a3d48bbff1fa53ffc920f7db5ebd4c65911392bb834484e688799c3f0a3bbe00cec7322fba6245570685cd7df0d744473b72f03df8000000000000000000000000000000000355018079cd02dfcca15fbd2934a8e47c5ee89e679663488499ddd4abdaba7679fb1c9d2102317cf2798c47aff1ceec000000000000000000000000000000000c417d489a224fbba9999300eb65a23749194bf5302fdfaa33ff7daeb8d896e387e56600233038d5c5eb59f644a99b6a000000000000000000000000000000000f5a62e9d711293d4373bec1bc2637802938eb789c828939e6c42f10062ec171ac6110261165bd179206d649713f6fe3000000000000000000000000000000000b11f9fd0ef8dcac2e21ef09846ffe9f5a624ec246e31393b39082a47354fc9523dbd247f0059b6cc740d7a387b137f0fae2ef61a024e4d8c4ae277f6b1d834193df655ffb315da67afa4ee4ddcb7fbd000000000000000000000000000000000fbb5521cdb9c3a69d58e5c9cd7e4a50bf5469bda2603f5119f3209669eb3e374d700f851b0c7ac5ee3cc9de79e6a7ec00000000000000000000000000000000131ccc37581e64f6f9fdf675b9b63ceb67d9d5844bf512166f39b5bb09d8e031437c06b0ca01caae7ad6d8c9bbb9fd67000000000000000000000000000000000531cb0557fa18ef054dbff2e7e994f1af08aaea7557602a26fd6ff539ab3c0a73f1fe841177012dabed4a1223ffb5a7000000000000000000000000000000000a180e7a345d2b635be92888934608e8b6c17384c48c560f4cb9809ff995f8e70d83cd4cf0e96c458fc414e1275d2a993168a1007abd42bc398e317484149f2fa61174243fd1748deec6cc75e7c720a200000000000000000000000000000000125c83184f63dee35ffd2c0c7dad9010cd6a9735675099f24b465554ab3db727ee76b5b7ea603ead78795d33e37689a400000000000000000000000000000000141bdf7e270dcd356993327cdb5dabe38a5c5a9b53470d9a4aafc041c46fe8bc841089e337469bddab5d4f7fd3d6ccbd000000000000000000000000000000000f9613f6d05f38e3073f14d0c2557101a4864a7d6d0b5a2b931d0613f020adb99a1ab2037a39fea6e99fcfb47929827a00000000000000000000000000000000192d812e05a17d22c60b78c53fabcc55a0eef3656f8e84132faf16686ee18ab4d35767db9a384d42f392c40c7b0fe1c0f1525bba87baee35023d0976b4a2d87524ba74158f000e5501c6d06aed04adda000000000000000000000000000000000b6e1960e82586de19ffcf29a8c5f16cf2fcf5286bf42febef832767919abddc655a0d1bfa240cac8fdfaed5a1e8f389000000000000000000000000000000000fc1598454caf04414f1930f711d762f0d72f5cdc7a4053c92b916c742b00dd0f107aee111976c1b1218c4577deeb006000000000000000000000000000000000455d6e9e9bb848e0868c9d725edca1f50b279d0acef8c597927eda72763e3702f46b216919ac36b080b4865249fd961000000000000000000000000000000000174463cc7804796b4a6d8ff28d2e8cfd8361b2e38f368de30166cf3c20c474ea0a1e8d94749fc3e6468924a7d1369e62d3d7c014416f33724acaa46412348d350f93d334588d39c77dc0b8ffcb4cb1d00000000000000000000000000000000144e4b615ddb871bae85484c308423adceb5de387d0c7ffffdd2211b4ea28788eba9bfae96ffc46781e6d6343e2f501b000000000000000000000000000000000046e39cf43fd707ddc4b7ce9a8a22a2aa1e55aa63cae1eb23082f7b4b5dce49f32d2ff887b5108b40f98062c02d5613000000000000000000000000000000000b75b5460db2baca86528569b47209b5ac24930e2545cc6aa08c401a87ef2c4e233de537e5a857e533d0ba0981b24d7c000000000000000000000000000000000018f53b83072fe7daab226c831a89da63a0930ea86e301c97e639d0ee1609e298e2789d1a347bdb4afcd355fffd16d053bfbb1670b7045b6df689871d5d012dc93e8be65faa4a98a51db8501a4b7677000000000000000000000000000000000185b296e9c7209a9abcc3194b46be9a545666527ec9b0634a3e3be579447cb52330174c19e40e1667124552392a7a0c00000000000000000000000000000000158a053c788e5b914fcdcf1aebb4e21cc8bbfbcc20c4d692256b2ae48149f6644e1578f98d58b3e73d9768d0e7df643b000000000000000000000000000000001318ff4150bebd8fa612f4e84f89151d5c56c272969bc1f31a3c1fcbd8ded0e298914e98e1ca48248e9023cd12db0fd300000000000000000000000000000000076555254f382707fdb7419772a4978808a7409f59d1dbb8c9e648372e19c44573f5ce1888a2b570a83afc20e698ee44f944ee8d294d189226a6cff17456e2201d17d4dfcb78f58f8501870377a6e431000000000000000000000000000000000f4395e3f2e301ee3e18df3c23cdd142716c7fcfc23caed924f0561795948b0bfbed948a6f7c415ca615ee0ba4d5145c00000000000000000000000000000000176ad308c7fe8c3a1aa350fa82b8f8ec638f77bc703afe1042a6da22e5385cd8473ad789247f205214c9980532b12c7100000000000000000000000000000000092b0ec86c511992c66f320ad46c9d6d7c82df118a9ab2ce1f2c5611ff4e5cdc9193a39c3fc95f18ddf96e139688b00f000000000000000000000000000000000b4f671e334b7f22bd8d89d8c4eb8a52b04bbd4dd1259cc9caa1872093736680618930f3a469b3af4a00cb6e44b573f27de53613b7a31583ccb214726482b770029c0ed42f9528fa74da7d2d1dd915e100000000000000000000000000000000123b64561ebfe085238220eb1428b3a203acb01846d1e4428f3759db6cff4ed3c1b9d436706f28b77e3b92e2e39ecb41000000000000000000000000000000000ccdf1973693e4b43b6133563986f6c96e2b924895c813f8acdd0f39585e4ee95ef26c0d9d51d6ef88bb62305e51594d000000000000000000000000000000000f51693bd44b12188131ca84801bfee0ca853640c0a8d5b20123c97b369c98299ac04beeb27d75946cc6f45f8a07b5fd000000000000000000000000000000000804c6597810d2c75de94484873a67eae258fcc9577bafa778e13d4814ce099a5684b1cc94e0df5a59acc7b19328fb8bb0a9750cdfe0910c544668bc9b11ecdedf1b757ff69b61fcc838c502c2911bbc0000000000000000000000000000000009b02eea05c78a24adfb0187defb6810116e21894d8782605c1d590f8bdc10723bf71a1e5e5004b181504ac2deb142cb0000000000000000000000000000000015882389195128e20e50ec4f8d278e8b8791e362341be93c475064d640e1f8bb1c92a6c777d666f8644d471409bb9aa90000000000000000000000000000000000d89295f845f989e0fbc6e86e97400b08e39b2968fe6c9a141d1e92ec9c838a3d8e1ada5e44bb08189a5d514ebfc2f5000000000000000000000000000000000dea05d8e6ab50b8f8dd9632337948a60568724d5a03c7914e4a03e2af572dd8153effef1a7d5c2cb27765ef2c17bc5b4aadecb1111ff43894123648eea9e57685dcb7a25553233a374479c24f2f8899000000000000000000000000000000000bacd14447ede6af0e92e19b54c4f5b6ebfb94207efec3e9f385a4c84a7d670514ecbc28ab686b383e239ae7f9bd673d000000000000000000000000000000001698bc92d146049174b843dac8c5dadcee12d1d503b2d0e46ee68139dd43d3aa797fd5bd06e2b214cc9ae3647c98394a0000000000000000000000000000000018d20cf6c84446cadfa1a26192a04e16d2b2a053705a89abc51bfbfa35c2b03cd58021ad95a35364ae1e2da5d233208300000000000000000000000000000000113268e360006294fa0203ce58cbfd05d05fb625e1f9474c96c89c0ec1ea80fe834030592c2f1c182ef8a3d5c32caf71adde66cf749daf69a30f41ca00d251f7f1e93b0e7f916a1ba6b994d946b12ca0000000000000000000000000000000001727b6bfa9c601fe84a65c54f556887c4538cb5383a288156fec87420ae7f15da395886e1ac0e10b8fbbae8bf040f4ba0000000000000000000000000000000012127cdf02ada71f28ed036a417971b87fe443b8c65b7739795dc7067082cbc9f06f7bf10c709969281cd072490c06fb00000000000000000000000000000000134f1fa1d277d01e2811c118cf10e2de6324e2ba14efcf717a03c1a10dca0862ebde0f6328839da63d7d85f573e8501f000000000000000000000000000000000d20a036b715d18ac9e2dbe009dd0063a4b13b3ec6fd060a64c4ad2b98e05e069060179530410d154caa575d504c63b7b2f9b44c73a1a6dfba6462e1202166b63727f45dc3b8b3b73b5d06459a1beec20000000000000000000000000000000000bd5375e7f98d3972b93420a39fd6c31da86d0d9349ac3774bbef15c2240437cc0761b2f1245e805d2538cbca6f778600000000000000000000000000000000100232139641c8cd5bdaa75b77e1e1c8e33b3f9554e2ae00ec6315b82cc00a6a70d576d744e68938a299ee2b451558250000000000000000000000000000000004224691faacb007bde3e37db6c7486aa5d3b4259a24c8b7653238e7522604ef4ffc1eb3cecf719a1b7f52ff00c34399000000000000000000000000000000001156ceaccfe0396374c6dec5adb39f14b6f08a32b88ef7499756f5cc324a9f1553bf5dc106a97469f2c49be5d563e1100cdc89e668f7cbd53a2ef6597a48b93d7d9a78950d4f821f3935edf72649e0000000000000000000000000000000000010a549108e77f0ddeacdc795517ccdcb357f909264457cab22fac2b982d10064756d66d0e48af02a59f58eeb1e8ba14b000000000000000000000000000000000c68703ef1c1e93c78faebc5f7ccc69e39046fe8af92e12469e9fd6baee62a2e8cc06fbbb3def81ae5cc57f488fd9c9100000000000000000000000000000000064ffb6aeeed432629242c3843f8cbea5bf7fe78585763926c5c45dc3cb4d1c79b3715506d7cda18c531ef890b22a1f7000000000000000000000000000000000e0eeb69f28a552cc6563f5fdc9919423c4358a2b70ccd56b048c22111454f67107513cda2a5aa0efd2af25dc74a1c47e23b377ed80bc90a4645df09e825509eebf57f59d7a2aa1b9121ace80926ccf7", "Expected": "000000000000000000000000000000000b1913c672760f98fc6d4e96ad1ef200f99add6f233b17291036e187ac6692ab0a29a4083dcf86a532dd06efb3d9b8c6000000000000000000000000000000000323b703abed59a9824f34d97851546a5e78441accea4e3a933b9270f92a9dd1aa056858ebd1739659018a0ca13b96e0000000000000000000000000000000001603cb3ed75c09ae5da6b94eea6017dac0c40b17d9aa8b65b78f2ba17de051bf3f21109d9afb214d260a09391f5526c10000000000000000000000000000000019f3bcdb8f16d9a2bd11e3f9491266780aa9110f447e19f12f7a2d62dc4f2c7b5fa18e13792007f5f361e20656c8ffdb", "Name": "matter_g2_multiexp_71", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b7d06c16c77a57b5ed74d829ad6acd665e73d20f1d9285ebba67b60c0d1571e1b02cabe5dea44499ce6d40a83288aac0000000000000000000000000000000007e6ae768ee3d149c7130022f9883ed51e4fcf68c91327ac1fe85aec8083aa61a37e9afc25d3352e144aaf888f264ab20000000000000000000000000000000016f2423478e0388e8495a898c23d63a0929a2ee7cf848034e4c1adad3460c7070caf47631eb930678d3c85aaba044dae000000000000000000000000000000001587e63cdf50d6e0b6b3d7652ad0a0a2497e70259d73432831781641d3a76db4ac7cff1bef165fd8ba29200d7320e43475888762fd1de395fa80b6d8a751f280eca568de2947e953feac343fd6bd592d000000000000000000000000000000001181bebe3256dd6ed754b8a1d77ac07e9a341789b3f4a4988599c7c60a36f1e95d3e3cec52c54c0f0abe312ac358c28700000000000000000000000000000000189d224b2904bd45cd1e8fa72570a1e35c94680d03d30292892462664f9d7aca3cc45ecc0773e66a10248df28ba9a9a1000000000000000000000000000000000f654f4c8b02a891e14fccbd5a96228afaaf79ed8306c7c1267715bc934e5f2568ea06de2bcdc2a55ef708689d90108c000000000000000000000000000000000c0a413f16e1aab8b91a87e7027f067ffe7de65097da37d67f604a184c7e7a7af6fe59ced8c03fa32ab036862868b35018ce7941da132adec1eee8d81facdb5012a15ddfe0cd6751ebbf66ce6c495043000000000000000000000000000000000dc972d55b7e68f97191d988ae7be5f5301bce5c654b323d4c17bf6e070f7227c0789ee38af3ccc07b04f0793090c6130000000000000000000000000000000016288c405bb42b4e71d12fd0a798cfccc7d33aba0500f939f5fedbd0e071166169d3072befcc5549cc6963b6dacbef4100000000000000000000000000000000171ea4f6607d6efc875cd9cff203bc62eb83bdc05c07f702143c23ab2770f50f42738f748e6bb3bb5d6f51f40fea1d910000000000000000000000000000000000fb729cc9716bf2e9e30a598ee7c4281163b287422ab66b414da85b0b960102991c24cd023791e4241bda5b0f6ddd3424a0497c642dce3937d883ee25b0ea577c729366c7d67e2e5ff1ccde3b19a5dc0000000000000000000000000000000005720bcbc598c4eda697406dbb390c2aaf4bc22c794b4b664e9b85b7c2079b90f7678e69496a4a5cd3b46580b90a7a30000000000000000000000000000000001159788c3edf619cc5e6f77c4aeb4860764d46afac4cdce54cade63155040c631eed65c2fa11b9cdff14847950cddc2e000000000000000000000000000000000d61bf02587e2c61544ae8a98b4c742c26a3d6ca49c6ae1b19a9d69c7f8eca43cefd555c973145566f8332902217cec3000000000000000000000000000000000cc0da96623432a2c170f07a3aad2844c1c2aab9d1bb5d2183928c818e681c66cb3767be372be4ae65fa40bf5483258ce4e0ad0d478ccf5381470a3fc9b882639dde4a0147c7c82e50bb93431b07a1350000000000000000000000000000000016efffb5d4ecbd01567c1e6099c0f06644d4312c599579b4cb780fccc8a425f3d1263a5f0c957dda4508202a354162f600000000000000000000000000000000115686a37624ffa8272ec7dedb7a632ac568245918ed91be6c9116e0fde290c26b5291e5f57ba6a779750685b0f126ba000000000000000000000000000000001852662b92fb49b2f0359255db8a7a2d20bd37705b7994cef1eb8e318aed70fc37bb7af9fc0c32ab3efa8c0afad640570000000000000000000000000000000017a691c08724ccf0e668f2f4eeda692e9ac21385fea243dc62c37ca73421eaf51c3a60771da3fb3e3cb578de37d2d45d38573db9346a3c8de41af54048cc51a0edcb86f36372859d0d794f7560c8525b0000000000000000000000000000000006fe4276e8f2e23127853eb929ee4e0c6ec4a190d46ac222dceb995c2e1d8fc9f822806a877e6cf87cf579cb2862c25c00000000000000000000000000000000044dc671bcd516cf03ad98ccc55266688856a4e4e5a59d6a6bb93e9ca77c596b5ecd2db6f3cc6377a0086c53ceed5487000000000000000000000000000000000c3ca83688d20519423b2b5547afcccbfaaa088a90523272c7cdc9a9b0397340350f2a5ced2a8153d69c81cd79732bce00000000000000000000000000000000069916c468f22bad174522d7fb94b4b7d2a664743b4689daa5423f470014152387a29425642b50f9e50fb679ddafdafa02257ed12262d00e78bde574a9ebd2664484a446c03fe8cbb855bf92e56bc1630000000000000000000000000000000001fd452b8685b0806545e09783947551bc5f6446c9d15d079a8968a448a6fd6f8b7e91974b71a4b2c50954be299c4885000000000000000000000000000000000f28bdab0b0fd3e05d08ee2c51f1bc0d30380e3a7aa18d6e04b47018d6a8d2b35a8f06df3866ccb95ffbd9c5333ca94c00000000000000000000000000000000035f3aa1cff72df0bb10f1a6f8414aa2ad0289cd15f56d84061a7cc70562f1f12304c402c388e48dd3f34082aaf79eef00000000000000000000000000000000034730e3ad7a3373b97279a00dc7a053aadd088557e0da61b9aa132c5b402fd9aef73cc45dc1cb7f2076cb2ff27ae2fc76b9d21a3da0359a377c11a6d0a18bce7ea81d4128dc1e7618e6c35b9149d5c80000000000000000000000000000000009c91d800cb1d52501520b3625dd4c20173684bad8742c7ac4b35c0ce028556b6529de5cb7541e3c146b13f58ccae57800000000000000000000000000000000124259d345bf2f8c16215be4b6b7922f4e2d6b32f91c4b1c4f1d4974918fa9e6fcf10e46f0c0b55e2a7210d1a5336eed00000000000000000000000000000000072e6231244ed14aa0f5de06e2f953371995a567684b00e459113380c1434a8faaab8b28a0280336ae35bf1f90f1d4d10000000000000000000000000000000010289a63e0e5f1f35b7af22137e117a85df27874ba15df39b7c26801c169667a3afe9a14663d7ac0c2956f4eb70cf11fc9cd895d5d1ae0ae704e240c10d8ed4a01b319598d7885f7c3fffcd9b491f5fd000000000000000000000000000000000d0f22a9bcda47ffcd034618c15daebad8160f9ab6b3148f1cacb32e713df2ef19f706f14131f8ab1181b7ef7598e3e4000000000000000000000000000000001680314cd79fec583c8bc0842e1750b1318f94aa7700c6662aabd4c592ca61ad51a6876b686ac3fe3f508cb40192c31c000000000000000000000000000000000a172bd8e49637fd9eb611b590c68bda707931e403db35cde1c10bb74c389ed725aab54dcd7048285352c56c8bc5fd920000000000000000000000000000000012589683ff3f85ecb006c5c435ca7bfd9d5a6fd06eb625bcbcb18577cdef610d912e783f3986c965710269b1ff79ba972467604875028997efdf5139180a8d530a1e9f18c62ddac7753cc370bf25254b0000000000000000000000000000000009720c2b3a0658a4aba8e76e196a558bd155ff550b3e41bb5b43e7c5946bad803b1de64e342956a11627e7f24f69fef7000000000000000000000000000000000decf2262e8369d6a2b1ce07fdd257abe1c7610084ae2f347640c0cdb98c7cfa732dc609c18b7b6a51b47ebe4b07a586000000000000000000000000000000000e8a0158702ff6d6c3a7ed9fbc774bc329681130840d86ca3f26cf6642cb49e5f14ad95fff1c94151457b1d5a142bb5900000000000000000000000000000000035ae66137629e95539e09ee99b001d5b9a6ede79727d7deedcbeb5acf081cd05ad469ab06c265a5224fd5236db160b62f47637b64d28fb4facc31d5bed34b22e7b270431f54a689cd0fabd205e001ae000000000000000000000000000000000413d82d0b02ca706f0266051445c04f3ac594ad82e2f1fb4e8e0cf23a6c1087c29383238ad3677f170e99259e2fe93e00000000000000000000000000000000070af21f84895c0193f0b8174cb20b11f45c845a8d782b1f58182b149362e1368ba076ba702185fc54b5da94c3172f5500000000000000000000000000000000182e124ca29d66f9f6c370f6065f60928b6a8f445a74800d59209219add6cab0d1b79702c31d60e61cf56874a4eb6717000000000000000000000000000000000b94b733f76067a102cce9659292f31f3df2cf2770e3a83c1524536e29d0a84ea5c4883cb4e849830384dc7e157d8715474c3ac61d4fbece967fbd0599c9a92c3fe0e53899861f044308b0ea8df137880000000000000000000000000000000004b2feedd5badbbdff6fd0f33a4bee17b38cc8967fc72206246c349e1017ed0407fe08e0cd9208fa9e4e21eca4cfbc2a000000000000000000000000000000000df0d74d5cc17ea94457c0ee26ef24071700a0fd6bfc762e3ec69b8f1c096887f679e312f07cce8340686eb2716c9a96000000000000000000000000000000001878edbfff2efc5af64aa9a23589a52d63749b7ab2970f256874fe0cc15091c4511050b0a243d421dc6536f19b5977cb0000000000000000000000000000000015951da3b20494a266e4d014d0ec70fef4586c8656baf536a0ea9a48dfa041624e8154989a2fb106189217ca979ddbe8eaf9da65e0e1752a982601e9a070a7cc77d5007eb641fffbb78d2a1b02dcffec000000000000000000000000000000000657fdf40c829719db134acd6c2a9ff904681b1869f28512cbe2a64d93e5b62114a73bdc5260ad9a1f24a3ff191b7a3e0000000000000000000000000000000004e77bf63eb9c4741028dffd0591b4f525d533b455d35e51cd86c7884d63419a162b145752bde188d2a622251c087f870000000000000000000000000000000016cf02af01fa6750b4d862f0cdd5a87a79da7c3fbedb0fa356ef2e7419e25b3a2bc8cbfa97463d463d0ab349efaa3f2b000000000000000000000000000000000ea4468fe6a85d36ae990d0ba959ae050756805c4c769c829de475a2990ef1c46de20d5b466543978faae0f6045023e85158bfe535fbc342e31f32ab4723c0d9fe95a2c64cc4e59bd41d13a08ac811780000000000000000000000000000000018d42a2df8ca475be6bdc468a82c313599239b974ec3d27e8b8c534aa4d6b85d4ee9aceb15c38b3bade2bb1706a2c2cc000000000000000000000000000000000124d5dc60527faf48f5e9574308f8a328b410de1cb49f2cc6f76b8a1f2707f2d1a94bcbca0a97bc38f24545a8013b250000000000000000000000000000000018b690b3d1e3b22946a91ace004e1d8f92eb5beb284eb05b52ac5ba003d7bc387540d33d088a02711522e3aef7f74f4300000000000000000000000000000000103080d8bb379d961da06bc4c148cb5b056ae115b3a0e33f0a8c99a7fb7b7ceda35d3902e0733156d354dd0240e4bcabd66f5a8f37a7c6a32088897abfaf5a98bd4722c411bf4b52f0f5b5648e89df29000000000000000000000000000000000f4d068354cb5b51e5a86163978386533f8f9b6e388c5e75f7d9ff5e1ab6d1637717d251f2b723b7d683e26a274d610c00000000000000000000000000000000001ec5a0d408c55f247d62ffef172ef26e45c41029f1d04e36f0dbb4fe8af414b0f7fe7ec0cfda66a2855b58592486fc0000000000000000000000000000000000cb1b68045076f457746621cd415d743701bf3ecae8d52dd5582c3e0bfb38e6cf2651a5ebdf521afb1ec5b8066444210000000000000000000000000000000010f5672f813470378fa806abdff90edeb0239b00d85ff23a3fc6798779f46d6b43071d66f7742897a4e53ebf6c7dae719acdd24190589ae7823a42e8b59598eca12bf13b97aa9a0eec17f5f79a01e8df000000000000000000000000000000001422fbaf1bc2908be5900968af61ffa7b3af46e7250e4663ff321f42e2db057bcfb2106c433a9eef8fe20f7138b71d280000000000000000000000000000000002176e68cdb0ada2d7baea437bec8754ea293d14afb85a811f7a5d740d645a53e511b5605445b110174ceb5e6720e736000000000000000000000000000000000a69e992b6f4f7eaad2682cf9ac2e58faee9b3341e852543c2aafbff390ae067a641b2b5693319618fde413fdc64d6c10000000000000000000000000000000009440317af8f5c753b5de4648b06212256a39b7fb03678f1913b0a3d402a50e74e2da5d29c211cdf0b292c132759c36d0291be87a213b0a24c92df5ce42381ca378dc4b9aeb4cb9b6918263bea827bf8", "Expected": "000000000000000000000000000000000fa31d16d9625200c13a415fd61b7552646c62fb8db307e92c1ac3d2acc92336765a1db42407ab0f774ccf01291b9ee800000000000000000000000000000000156a77678873dcbe4832b9fc7f516eabc1a10f4a6576cfb15765cdf999a771a6a6d41021897dd783e9beb2db722a6fa2000000000000000000000000000000000ee4599a6ca9642cb4cf38f5f2af23271cc8c5bc6e2cf6bad572b618bff9f8677837104b93ca8942843fd5db5c30dcdf00000000000000000000000000000000138986714a4053618e66a85835d105f4aa2ef38ad18e34b2ee7ae30a4282f7e543c80c94bd12c244506e7fcba25f4c1b", "Name": "matter_g2_multiexp_72", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000083c515ef8509b12ab85ad7d0a816d986bcdefc14778efcb3bf7c2ab61991849f279ae6a9f5342880837c0d0f4a4eba700000000000000000000000000000000020cf5196b5d567fc429cb9ced7b55e4925e18c914caae216a736886a8d886c4bdf6d704bbd0ceebdc1975ef530c665a000000000000000000000000000000000f3d0a217c224434604d63cef559eed3864d2da62ac00d49fab8c2c6e22c688496adc30c8d591e21bc0be404b62083c20000000000000000000000000000000003d0bf7f25bab0bf2c768b44e10a6022650f7d5b7d568d502b9d0b28209ee69b1d952ed848572d3e966e8771c20becc4b14c6a38cc998df3583228080ea10f215a6e6a4b02ddb6d43e8f459d494a1ec1000000000000000000000000000000000cc4c4b7eb7e358d4133b65e635fc13b8a92229706a6dc5867171a60a99a8e343045a794c368f1133ae6cd2788c3a7db0000000000000000000000000000000019508aa39fda9c3efced287d2571db97045f8b7b0c7a9c9d51796aa8017fc0e5abb8fc994700dd5c9f755edb518e096600000000000000000000000000000000049f68b0ac142715cfb385161ee70e453f0e24e2e93f3f96c3d69447f3a28b180fe76989427b2e392c7ff939011e04ab0000000000000000000000000000000004903c0f8e0757dfd3f5edb4f54a0e292df15ff70757df7b0b04c99f590a3dd13c6ce7bbabf3e14daf9f3ec60e2379aafee8614394c8109338432ec72f2d9babba06f1e7b826b0f2558c3247c923b23500000000000000000000000000000000041128064ac768664f076116247e0f8a00adaaa824cd6fff33bf524d0c76e61203408ac13b294aa41f5c462cd42d3cec0000000000000000000000000000000005e150c27979ff1cbe307511816be900648957624caed1f08d88347061cd783179c615258fcf3619bc4bfa53d2513c610000000000000000000000000000000009d2b3d97d29386b93d7af014ea8f1cfe2c1db5a9aa0c17e8430b0fcde974a4e7b8b42ef041e9a7b1a8aecb97cefb52e000000000000000000000000000000000d86096ebd88b2cdaf5cda1e9ca6b7f12ed5def629354b0570eb084bc7139cf20bb8ebe4438f87937b8b554e2201344c28728d06cd90050e44a827b44f14ea35e83c9b58ce4c3a7a45aed6f31c94fb960000000000000000000000000000000018d677cd67e96b10b671d2ed9234d7708042ddfe6fb804d2e9371a80ad167004f9d6b92d26b3d3af34ab7caa0e03964e000000000000000000000000000000000e34a6c85187d328eb33c2d5b2ca96b5210d47a779ab810dcc380dcb7e6b3c334ac8fccd7354aa9108136e4f6dd4ea0a0000000000000000000000000000000000ab8f7274ee3fce1511c58661625c766ffb0ac68bdb835a948b09b7510bb573d49000000e3d3cea772bd71d79681e1800000000000000000000000000000000135ca42f2103905748a1c416d82170f7d24b49ff3f859d6cb7493cf89bbae0217529a9edc835be1f9890ce105877af630fda665c40d1da93b1f132070e0b7c8c2c0ea0e66993b5a3d7419a33d118d25f0000000000000000000000000000000007884edaacca499491580c8c7194c0d60ac6eba95f7a81f63742451c8ed21a223ca545d5cc1e648b9d2dd05016b4fea20000000000000000000000000000000014c78d5d1a93760096bf6da73bb41631e94d6a1b251ed0be7bda93e4c50568420bd4d49e4a46e5be4bb204cdb6b0ad5000000000000000000000000000000000128a860c23a183c5bdd18b4a1853cb53475f1a893420bdf3271cc4a65a827eba6b92e1f9e8ac0d10c73edec5160c640b000000000000000000000000000000000ac14b2170042ee6561c34f77fca40e1bd2d40d01798417dd954905135ed9b7772e5689e6d4e543d44a4563da8c3ca40c14f014117a74f21e0b698a257ae8e3d6091ba76bff7912abb6bd94d41886d0500000000000000000000000000000000144df2e76821c19167f60630f50c939b66867a82c2a5f807e943676c876aeaa2aef2126bef7fc431f0c7b39e648542fe0000000000000000000000000000000005e463627bb2d22c25520c27c05cdc75e1f2ee3b91e8088399ee42ad13ca217284596e5404b4370995f71fdbf1c1c7860000000000000000000000000000000012323010d6aba1bc6b1d6e7f7e8c7bbc0838564b279d5ae6279f7f7d3cb5d96273e27e7096e9a8540463ad16deb3780e0000000000000000000000000000000019102ac6bb33bd1c5a158a584ce32308b6ee5679dd6d2acdcfa4b9c54674fecad7489d1e39c05b1ded88e4ea93620724d81a1239ad2c945f1c560fd1674ac7e87d49aa41a1f4a5bfffeab1147c0ef7c6000000000000000000000000000000000faf210330693663c8a1d1fef78e211ed2542f7ffeddca3e19be3ba77ef211da1b8bb5abcfc96b692d74f8c7df40b0ce00000000000000000000000000000000134153a252fd8ec5d9aec08ba09a94c4416f95ff6f4ccce59bd400474c836af5bfd941f03384ca4bd5c56fbe81d96ea2000000000000000000000000000000000b4532ff1ceab2a3a177cb83a75c16a833a2ff28df447def351134ec4fcd608b2b75b1f8035ba7d40a737087f3e8c1c100000000000000000000000000000000127e3ed13384b69819b34ef8705fe9a66dd01b275f1f74c2c724420546b39c70cb7a8295a6c1ec4075ead4e3312b8b603a02689cfd2c353fc1b4d3913f5a43745fffe6a87a7c223ec3b25b321584a75c000000000000000000000000000000001351d0d5d531a63a5f56aaf1d7906b7ad2bfb4e9d823e2659bed4e05e7edc9179a7bbf13405ab5cf410b25c7d476c342000000000000000000000000000000000f0ec96128e058e8bfb6e0df1331887245dee87c4f9721fc7f1d20c20a2feea7a7078a4946803ac093477707598d59b70000000000000000000000000000000009399034e4aed13cbf197d8c4753285effa72fc53493ca316db11b39d5527b009aec6350d579f9dee22cd6d4cabd88ad000000000000000000000000000000000002f41ed0dcfa2437cad7b12a94501266d670ed6956196c438241aeb90474d17214eec5d5217090d28892d95f4e40055af95ab3fd062088ffbef6ed887fd39aa1d527fe7633b876187ae12e736fcf2f000000000000000000000000000000000ae208978a751f8921c6067ebab4190ac8d3608dbdf50222eec59460095b8ab2abadd97616c240edd0a9c53dd006e38c000000000000000000000000000000000905224b317a1e64d8af075b6db9de46ca4481458ad6bceaf726ba0f63e81e2a0322e79e70a5a82034abf00d47fccc300000000000000000000000000000000007173c3359f0c2e315d11d646a76e6f500c0922401e4bf9f4ccf2f0801a567fa653f287fdbfb878ba0d9ee12e25396ef000000000000000000000000000000000161d4cc71621e5df13d121c77105af195c2adff5fc6b656b0fc1dd6eb2518f474444d8bc526ae16387f23a4ab3f342f6541c6cf8217c2a95792900e8fc39581b177a57ca00162c57131ea4fb80a4c60000000000000000000000000000000000266af9991c393d3b55f9e0f22b0967d47dbc5b0c97947125e220c4bf9f4bc58d32ebc7bfb02b2e329c933ce41d0d8c00000000000000000000000000000000004cf5748aae8dbc1e4778dc85da575de2b6d9d346f5dc5ccbfd82513166384111f5e5f2f1c2f7ae367a22146d1fac027000000000000000000000000000000000095dbe68521b2cf51283a8cfea1f20eb7ae37e6e945c5f879ba4834d20918b74981f9e0eff4543a79ff4eb36d84a9c60000000000000000000000000000000007953cad14379ffd4309cef1ed6a2dbb73a93db0bd3a256753402e525bb62b10aaf22b662bb2c704865690af995e7d284b7c3f3c4ed10bced85f36fd6dac2646c65d3c810e6d2d116c38aa5e10b29c2d0000000000000000000000000000000010e99f318111baeb1b4611847fdaea7cbd5e3ae532af667ad2498fb2e97b1eee0297e2811c7ae854b882f616da7733fd000000000000000000000000000000000e56cea75b4c4e4c669a492a6723fd60e351a66dc5c34c46469dc36cb04d2c23cfd4aeaa23d0e9e83d5b78a1b77696ed0000000000000000000000000000000018f838d6a582a52a508cbd6bbbb9cf515e091deb7a640e141dea4018af6593c001dc43a8fe4819a7877d9ecf53d5752000000000000000000000000000000000119aaa2ebcdb6379f7ae972cb709990a3e8254f1025cef308281bf7057295e3099d1f3127f76bd2f9ce0a03ae0de8e8d7e33f394e96d17efa30d34f57eecc45d7b4ca150a31b8d0484578151d6e65c2b0000000000000000000000000000000008f837c478e874b857f1c939a26a02e13061d50728c10939ffcf5e862cb177993e204590699a28cabc7593056617d433000000000000000000000000000000000432d9e66dc78bb58ab98771e7e8b5fe51835f286b488e2df6c1991fd36c3c537f2ce30abf24f9d4fb13941189972e39000000000000000000000000000000000b202de3708984f44f7d05ccd9e574a2a93a285d5ca262017346580be273c58f13165437dc90d1d4103d3b9eaac536ce000000000000000000000000000000001873e1251d9ae9448de8e7ccb7ca59a21bcc0d07a2819d140c06ec33cbba559ba90647494a7ecdec8b609b58cf7995cbfde92a31e571ec03e509ac8a70ed5788869854eef0bf578efe6c5e6468315553000000000000000000000000000000000084e07b6576c73aaf43c0ef9c5666dc988ed93d1a106b71e4882fc0cfb5e710b91e5d5eff57327f5678f662f4a451d50000000000000000000000000000000008a29751f1653236a48adb5fbc59059c7137d36139574c6af97314bfbcc22f77a4c5162092762a26b5da7887b94f2da6000000000000000000000000000000000a4fd84c4d58cb9e18aeee180fb05f07c3e1d7ed8d09940182e9b4738744fa6faf600b6f720441e0ad6391a4d502ac040000000000000000000000000000000018b356be2aebca82c54988ab2a2ec58751ce7a815f3dd58a2218a638753d4734d38b74ca0e00bbc8681768f5d1a02b646f7de01ad0f7b4dcaee1123bb80a71d3bc1e63ca577a12b14ae2a11d8c0fde46000000000000000000000000000000000de0f22cf05620a5d4bdcf50ae179f23a9c089fd6eaeb14eca937d9e2480f1782a1c67df76e06191a9b87514daa8bbce000000000000000000000000000000001981cd1f260e7d96e55533b8e29867f37af507b4a58abd69e0ad6af2a55228ab1c82fc2de52deb7b7b7deae2fe621e10000000000000000000000000000000000d22a7a567ec8826391ee711768e612c403e3c16e20947ca5861185c24728b6c7e7756debb333e7acb53d86032d5748900000000000000000000000000000000016fad52e1e86b9e092955cefdf93a10f30db896fb519fd2ca12571d8dc8aa352cf4f8092e0e973d0b0c66df78433251e2c69d21d40813ee40a718f0ead36b51f3a50e9e4e4b2de8acd33add62bfc1d20000000000000000000000000000000000484bb2452158bca93dfeeedb40745bc5d9a9ad49afa20e6c29fc9ed1a8fde33ce508cc252ddd05fc486f8ef78738ac0000000000000000000000000000000003c2d6ff6f292b0f0e505fdfdd2940e72bf8c2837da4ec9c74fb593fe3318a9b9a8592524bb5d40f6c38ad871ab7b6150000000000000000000000000000000015f888ae2722713e1b5b02803a5b48d53116c1a4bb1191c9da77ded8c6ab49f1620b0f7c7867957d84503cfd3dca1be7000000000000000000000000000000000fd96baa382cceadc252eaf000d47d8c1e2085e9f274dd9dbb571bf85bba612836e1da2453fd914135842e2750796b54762d89025196aec4f87da2fcc5a9188b4dc7b1c014dd1d705223bf9fe1e7a7d1000000000000000000000000000000001820de289f62058920ac3d4bc60da023ac29c431ee429a10066f305d2b1a333ffaa906404af977cfd3212b53e66726b500000000000000000000000000000000094e448db84421e25cd03be3867125cedc7f77f286f404524757f3c1a9cfa28ab6771293da490a4d75852f515dfe1a6700000000000000000000000000000000097dec124970bc63d8f62f9133157d412f5ad3fd5eebb444568cf0fe2825d6ef6577ad302842f35570c9977638c6a827000000000000000000000000000000000490bdaabf4db27dce906cfacf3160c0fe25959df4af89301cbe6eeb29f72e4c55bb467841ba7d0750a59a32fc8b03d0ffb9f3e1d43aece3af1f59319a8228cd81e668b1e250d03350958dcac9e23843", "Expected": "00000000000000000000000000000000193358b283147ed5848559d4d1533734822b0248dd17b2effa80920a853b70e7fb683b08aad6ad4dbb91f964ad1b3bb6000000000000000000000000000000000649be60ba72734db4cc307a2fd8be57857f60660d0c496c0dad73794296552e17cb2eabb3537ce677edaac1c6997341000000000000000000000000000000000f91ce27345e86003c99d133eca50710c0722cb35af2ce442ebd74b46d659e0118be9bebf32111c258e4cb4ab795a2cf000000000000000000000000000000000d76ad65233522b1e079fcfef4dfa80f163682d7984d5062680a5dd4cbccd5044de4705013c6bce2140f7950032f90ec", "Name": "matter_g2_multiexp_73", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000013fe4afb94d08ae311b7442de7291a11e733d8e555f2da6f72bf99da780a8f8d357cbf3d8959f6aeaca7bf3f5b5bd10500000000000000000000000000000000025af713b18cbdb5a960371c2dd0317f4bfd0182f4bfd6b88d588b56fadc1a0398412e7e0a786c326aca8779ae384243000000000000000000000000000000000581c277053c15df8eec05c34267f62e63faeefa2d124c2b4b84d2a739ce5484641ce955fbecb901d1e8ca816690189b0000000000000000000000000000000005355dd304b9b60498a3fb1f08e1ba0c98db327365ca9a0365a7f1e5cb56aec43b7fd2b4aa104eac7b1c30b6f53cd422be285a119dc8cb32b1a0c5380af736114a32e9d1ca870abdf278dfa84444f70e0000000000000000000000000000000016b5b3a6fdeffe5b9a0244a333ada4444a2e03771f94433832a4617be696e467b4e88ed80b174809dde4242bbb51248b0000000000000000000000000000000003dee846c5b84f89734016e547c63c02e4be07dbbecc86f811e2d8d3245f91205bfc055882565371db532240da1a845900000000000000000000000000000000194d53bbfa962def4da2a9bc7129fb6242a3922fe26cc4e603528ff31393a31d03dfc3463704250ea2ffa973ad175153000000000000000000000000000000000333768faee332d7468119b9e0469bbc7bc98a482562ff2fd9aeb6d9c67daac9c3da1db41c9e12224a2eff2feee51778bc0535bd504d7b9658e459c2e79b86bf4e718baa82b8d6e624fba0eb141c7260000000000000000000000000000000001910ded86d79f9b043bb79cc4049e0652c13d0fb8db2f070d695124d7a42cc3a2238282fc8a424fcd8d9ecdab4bb6fad000000000000000000000000000000000dc8d6caf97416928d2d58466219f054c6f28f49b2bc04d8a80cd46a308bc95aaca3a8df1914ab0c7da341862fdf47400000000000000000000000000000000004380ca7b1f7ef96295589f78a1683a51bce4b2afe50bd6076ccf5d07d35e6cb2ec7f74fa35097b2c0b9fff3f4797c1100000000000000000000000000000000054f492d7442b1c0d1293277d95efe822faa7d8881b9afde20db58d6267e049b90d0c8828a6c12540f4ba1e7c9ace6d84f3fa09243c01748954d84f4deeb460f3ef78f9c34296c6a092952bc463d7284000000000000000000000000000000000bba4761eda87a304a80180c2447a1d5a52f743015ea7c728e70d6a5defe3139c80696f842da3f06586be8d506ca4bc90000000000000000000000000000000019ea930d5733f4a1ace9fa0139d412d65b2886b659770e388894592de0694d38876fcd86d14580f9b92518d5496fd44c0000000000000000000000000000000002bf5d9a36d641d1259c1b30397aeb071b88844c4cf17e3de0984129d7b4d67865157ee2f682e7cf9d968fc07ce43618000000000000000000000000000000000f9a4f29868654abafc7ba935aa22d3d010023ef5112683a037a6c69b9e89374b256b8e1329eb5ad306d9f2063c22c335d84733ccc41f71a11d61852fa336df566109c5538c2c5f5cf2af961e93797fd00000000000000000000000000000000004f194f21373f09f8cb4984169890ad3855e814a4768c84e9fc97dfc181c60114aae534a27d3eb225b2125131c754ee000000000000000000000000000000000e6f88880e9645e35806d193f5d16799d63e2f9edd8ae28df54d19875c61857b0a34819a70ba3e9c31f00b5826b0cdc200000000000000000000000000000000193293c6cfae9ae4b24519fb23469e2f8dc4eda8524ee0b00c7141587b07c8a26a29841d41cafbd24bfbea2034a9c18e0000000000000000000000000000000017433efadfe9873dea9a68177af3d5dec4a13dcf4a710422d52020d4d145e2523ec0b48acc533a1ac7068c08ae6aa28bfeeb95c32362014caedf2a9e066a775e2db0d1322edc86759faa99bd70c05b580000000000000000000000000000000011dc003f7542f6822cb872117fa658638dee2a15429aaa9dd576a7e895bc0a2160bc120558a32aab9e646354233a1afd000000000000000000000000000000000fe9ed8ba572ef7d1176176a31fa92a5ff3dc38b0183ea1e22618e3b3214ee78c53074d4c60b5056901c6f046f8210070000000000000000000000000000000006ef1c20c3bd88bd6787598dcfca52da4e5e0e7c7643af983c709b916e71fd15475da30d763ddba0899b182cbc070ca20000000000000000000000000000000001a38a2e54a44ade572ecde076038f5244f266cd99532024a377829a64c20fb2cfe1633367c74b5990febb08e776bc34edee2ea28b93b2daf4ff927991769a9c69ba16490b5676074e64f5e91fa994a60000000000000000000000000000000011ce7b2cba037e5f3ff19b36371d34e287eec807178dad4118c6d43aba68623e182aedbf911a2ae5cf3d0e690ec3ba790000000000000000000000000000000017a617453f391e6e2437d56ee831ba895084f60d1a5f342e19a242b9661c703219d90a157e1b55f005f5059c15c179dd000000000000000000000000000000000746ab134c7f4bc19583a4ea4991c7cec3f651a60582b40c17b2d18cf6e252d93d2f3c2a1a3399be70512ec9eab251de000000000000000000000000000000000698daf214f2de44ebfaa36379862bd9ffb40987dfc8e632f14738c93c8e5c3fc7be9fa9100fb5f7440311cab34fe1897a07e50c1fbf1b388e9264c762798c31fe76761508d070f06adc63130df07641000000000000000000000000000000000e4ac65ce62180ac602ad68098ee31cb747886e95a183e4f819d54af99850d70496e6952076084dc7bc2d3f7a273383100000000000000000000000000000000182c718fc9e5cc961426258e82594a5cafc36270af0eb50646d161fcc192c30d40d06647e14a282421638b31f378de940000000000000000000000000000000002bf448ebd27cb6270e1b87087796ca6534ff51ba0962f3290ee1d06dc18ed39fb736ec95632b483f44d3a9d0e45d1d50000000000000000000000000000000018b956acc1300e60b22bb936b2b52e2ae82e256f15f1415263157965179855137715c321d3765c5227dacb63ba2d6225f0056903b4508cffb6334bb5f645cb553a8cc61ea6765283f933686f172f8360000000000000000000000000000000000f5372651ffb40bf853f6f8396a7c7483c401b89b67e098ea888fde8d19e7552a006a127af1f3311203434126ffad85800000000000000000000000000000000050d7e89b21c7484cc5831885422fe7aa8e898df85cf7a3a275370623eb9660611610cdb829d3935f0d0955e0ac97506000000000000000000000000000000000f83a3f79f1dd110bdb8521e18a64490d567210801d77fa3c0c6e5cbc7285840da325cab7ab08494c8d516511eb189dd000000000000000000000000000000000f72904131be66380c5a18af4857ada7c15e88572197e100de1cfcc9fdb4306e446f2f330fefcccb41b676f24e3e0bf88031f363c8b0062b34d48f4c2e5bdba884005e52f77ac04c2f29dc7ef10fac0c0000000000000000000000000000000009ba6bbf102d390638ceb9259205a1856def2b3a4b5209eb3e4e54074347f71b6c06b70764fe85c8dfc9074067b8d00d000000000000000000000000000000000339c30631229eabc1230240942bdbcfa6e18f23bfbf88b7b8a8fa92f18e35d2f7336f0b819e875ac643b43e6d931e68000000000000000000000000000000000600cfeda6033ff51c3bf9182d22abbfbeb6db46c0fbe15ba82e72fee483744ba5a57ab2eab6f35927b4ba6d2b150063000000000000000000000000000000001530bba4db8a60bb6b7a05f72dbcd23044011d75221d114b839aaa9535400874472f94c849597174322291b5cfec4974cb146e27a9d36dc698e1982afc945af9500fc5aeba719d06d0c4e4eb245034c6000000000000000000000000000000000c636ac98557e22897fd101dc6c54d87060f460b4cf2c5a88ea14641e2a8a9395492fc5a946eebbba36dbe38f6f5c0c60000000000000000000000000000000007fe3a557aa93f2e9aef4ffc55d39a9172475e6595fd57409df3a7fe3d11558c4d3dea3396ee62f61190add83b85813d0000000000000000000000000000000015b04e0daf4a10541623e7523ac5fbe57dfff9ac17afaf4293c493c1982f3395980ec63046cb1d424c6dec91899202c10000000000000000000000000000000019617b191e9e493751b0a02511a18757330bde56722a72a29a399ace983db7114f84795e2b70bc9d670cc0095220454ed983f98fe5112a55c23591bf4e259d072f893944741d9941a00f907749e3c9990000000000000000000000000000000017472b8c1cb3ec528400649fe7c39e3908b16ed69b42d967e4d225b694544e8bc7ce5bec87019db5539f1de39dc6807a0000000000000000000000000000000012b1c4884c37037a94f84c15061df5ca6c05c5a35ad9b37e3ab8e8297c9000e715fd2bdc3f2b485e86c415bf656392a10000000000000000000000000000000002c21af2933029f04b344be76e18ce499def4a0671a97dd9b6a108d0fb23852fcdc56f882be0319978952ef04a207a6a0000000000000000000000000000000015eb31e80fb162d5fa392fada8d43648ef54d4f9ebcb0e9652dd501f55a8875a16a148d42e283ea8bb2c5a38bfcc8843a62f99ac46f986f2f29f0ad3da0310f061e691955c711850a2816ad7464614a70000000000000000000000000000000015e68e011ed063a9fd9cc8a806d8e3561e4f449526ccb6e5ce983ebc4fc49d61d26dad7db64f56ad5ab0b54fbdb76e61000000000000000000000000000000001617d7387fedcdd772a34b267a44315212d21b798c0fe1e7a9ed3caafb678910d9c9c3bd1fff4a3c8e339d0c90a865b8000000000000000000000000000000000e2b3c9b9cc10f41c4c0129d34c62d526aea47c77ded91a5ca3afa0da1801bba81def3ca66a978ebb2d1f3227ea82a9700000000000000000000000000000000096b6caf7b6f29e91bea370f91c2576c188b08b95f9df6c7df995fc9879c11cdbe2af86809468d472fcac8a89716d1d87ee01b0c9c6a6ca1fdac35d89c803bee3595f03d9d200affc5292d8a7c6720b80000000000000000000000000000000016daa86ec04f57c72395d96b6ea5d6ba7cf2d9d4a50eb90f7121545f17c1ee16216f4086481d91e59fc5ed8542baeb7e0000000000000000000000000000000017a783d60be67206241e0bcad20e371d86d47d88ba1293b73f32999b0a1646967e5d031a5b28517f035168d7c7d7927800000000000000000000000000000000058f24fbe4e9befd8abe364c961f0ca4d9083260234a939bf6103a3e8f10a8381a9e3d74af7c13f159e5c7dcf456df00000000000000000000000000000000000485c9448fe3a069eb024ec43aaf563a98da09c02c294da2a94a98a95430e25b062e8ff886fb5fca240fba1abf7cee60297fc700698c56877be6764f48a836d210bb33e99b5735da9837882269af9b45000000000000000000000000000000001230577527a0fde2e8e66b8c4d17594bdab8be1339866819c8890c600b35889d1e3a749fe15fd8182001e30e6420ca6d000000000000000000000000000000000ce03cccfa87229fa8d560884d8c7963276d79ae9873a23d550b4555cc4bda35a242dd2e70cc730b70cdf898609b3d8400000000000000000000000000000000174aab1f142fbb7a45bcdffd64c2d38b99c8919baf9651aa430bcd39613d7565196c18f0f4ee6fe05f5c40ddbcd4a67a0000000000000000000000000000000011dd23f59ca2a033ee5dfa50afb0c7ddeaec6d4f50e1866cca3f061fa03594216f005bc65b2c97ed1109c305e16222671b7ac02db15cebb8af459290c35eb5a86cf98b86d8336764c6bdda6698b49b640000000000000000000000000000000014e1cdf4f10b11f47c15d0b6b7dfccb6081d05d116c8149989cce4f1c53dfcd2d0b7443677b03d037710eba813f6f597000000000000000000000000000000000c8415c7d5508010e0db1878ca663d359525b290b2f02c61436e945145a7a4e1b3ff4e27ea1b2c8d3adbe737d8291b14000000000000000000000000000000000e424ece68003cbfaf65a54dba51e7b0942cc53b2fa9794b4deb6aef1dc1ba1719cba285f9a1a59e71a881eebffe2eb9000000000000000000000000000000001404f9a3146b7201b09c5fd678fdbf2111c48130e82cc95012e5aec1df7e64a3b3c727afee4f603e620925686e126c0f5d1a3f78a2c2ab7b85cee68ee670f50a176e988a341303afb7722917f442fab6", "Expected": "000000000000000000000000000000000e9f6bedba1f6e2a3ff33e0e4b18fbf8e77558bf42e89023df6338b03a648c591486c63c2ecc8ecbbce23b3ff9a7ae6e0000000000000000000000000000000013d2526d83b4495b5af645d5a1af7bd40bd0ebff125e0fa14f10d1c08511dc29643dcfbd25ca0bee5705a56b26c558730000000000000000000000000000000003fa442ab532094d47f1a9111c87deacb15d80ca6e76bfb5f9b9a209bfe196643351d778b0c6d6b274b4799f733abacf000000000000000000000000000000001278d51523d5d9aefc0d3783e745da54f74a88620f2161090a398defdebf82d13d5b5a21a5cd466352ab8685b034fa89", "Name": "matter_g2_multiexp_74", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000a497e74635fde8caaa5c9dfe666b1b40732e58b93a72d39c8a60c1f4b262e1f18f62229a30fb8257bf895352ac4d249000000000000000000000000000000000c1b2fcbd7f78d85c73ae55f67110b575750bec353e55761de0ff09a9f8a2d916c336655d8f6a78dfbae13fded5a9c36000000000000000000000000000000000173893333d998dd32cc3e82fd7ad8ce77003192ad2bfa1b1d2b43f9466898313276b922f9fbd8e83e86b67acfd9ad780000000000000000000000000000000004ed01b702bbafc73dc1e6846bc944be297ff08d1dfef397603294c7fe11668cd0670d386a8fa0f0f02c52d47f54a11b34aaf86eb77ce03f1d8eacab84d5ff98a565fd33a9a2c40f2a19d7c041a7e2a6000000000000000000000000000000000b5ec74a2150dcf5ebe09f39234c4dfec623318889d92b0bc1f197a69650bc48d28a1112306be763176b691c6915dc7c00000000000000000000000000000000028db19af73ffdd0111dabf9c7d6879cc7389320a249f108b41be8b1d4c259d5889dbcbb48b30a288e26cd9926682d1900000000000000000000000000000000172fe526c62f9cae49e6d3284170e6339d5af256441590cae9507c61f987eb495d340500cb761896163cb8ec631434690000000000000000000000000000000013bbfcf9cd3167b47b48af5f5ed7e6d45a5fa38192756c9e140eb89a85c75602814f767c57108cfa2f726e71f31548f808ab2065f1d2278caece0939cbbab4bcbe3eacdc80cfae6e4500a5195883de0000000000000000000000000000000000052d7a0f93142b36489cfa21d76c0eb96904a3ddd946a53b8a6730036d88d30336fd8aae3ab29ebf62a48c6e849ca66200000000000000000000000000000000198350abe8cc91bd675f26516d771422c128d5dc0af844c6c1af07bf04a1d3ad9654cbddf2de5b7828d1446c45e7828b00000000000000000000000000000000198f35692d5face8dda4b464ff48d650145242852fe189748783b1a2e48806294368ae0a99481bfe739fb4962f3b86a4000000000000000000000000000000000e3cf2e018a7e0acfee25bc3a82cb282cb377bbd72ce3044dd20e109d948f68720c27aea3d4663ee45b2de6f178a00ac58c69b55bac97a633f3ed7816e77e2a26cccc029f7e7429c86145ca4645eb41500000000000000000000000000000000150e6b03a3052d043da6514bf4ee09baf1a35b2a909473db33ea0bd4c6af7d7aee9a8366c1d08d2adc5998635eb0dfb0000000000000000000000000000000001370c2976b0d36fcb955e797087e6ccffc851d2450cd63833d6cbf52e1fccbbbbf9dc695ee45c7df01c2828051bcd79700000000000000000000000000000000048b5fad2fe0af7ccdf675328d8ff5e63b564d8436d04c55b23b6ab7d2aedbd25d614d1780963fcd03d569bed2085bae00000000000000000000000000000000141f94b4e7ba542707d0c3cb69f8dd79e499602952be2374cead840dc669c5ac57089c5fd60c44291703b872098fa2daae7faf23e841bd53683521cb3cf215577fa51f0f751714b6aafe5c740f66208c000000000000000000000000000000000eec51e0ddb8cf9914304e7766a7418e2854ca71367c1d2b3875c12b7dc5c7cc2fbc136037bb7ff72458027104ed3f270000000000000000000000000000000009fe5e8d1918f9b5865a8b97c2c2cfc8bd750a0ccbe2942070827a09d8e41ca795a86b2262b10462795f833c73e788ec000000000000000000000000000000000b95c9146f3f560ad880ca905b5f297e48905680b4613e91f393f72ddb042f6a6201628fb5f75fc23f2298cde66a6df5000000000000000000000000000000000a29a8fba7644ac96d77ee73a93dae23b03d81a57f6cd8cb4594b23571cc1f658f163081ae50d72e09c6513d1cd2c8bf72022cdd6d942158bad47a53a9b0c3be910a41036874975724a5cdd22c012871000000000000000000000000000000001807dd8d2bb40a642fef693739b1df12fc787db0f031306f31970d0f59f0c97c0894afc34b9a9913726a20dcb7d5191200000000000000000000000000000000096fe8bb5e911c1ed9985ac08d864c7020367f4259a0d074973a26cc421a44e8034a7007f6d1639285cf8acb8b2d64a60000000000000000000000000000000014026d43eceb26b9ab5bdd4139d4f94349b273e43f27737f9ad26d23454cdb1d35ea793d21f057359d28328a82d5290b0000000000000000000000000000000003dda2a84bd1f92524a8ede9f5e81f0f64b41b24510f4e0b8146496a776d5b509968f188c12c2d66cf755e5000cddb3b800ae0b956e38bc34cce55bb7e88f1370a30fc8ed0e3f1126c68c30792a2cabc00000000000000000000000000000000011246ad07713d1916c662679ab757c053e33def437d7a976533f0ce80ff6ffc259489c26524ea96898c3747c4127539000000000000000000000000000000000acf66265811a57e47a4c98b40b12a37c6f439550b18215fcf856c167b7218397d7d559f852fb45077945a5074f460be0000000000000000000000000000000009badf2799f1c43a2e3859123aca91e894f86d6298a06a9127249100ba270f2bdc79cf511691bf2d7faa45ffa17490eb00000000000000000000000000000000069438b1d53efcc4277ea7b41cbd28a19f80b5380136f62121e766bd2845e13d5cb40b2f15d508414876ddde491a3830a57c3322133d6ffac661c888995e7cb067ca1309f3e9178a266f1a410a79c01300000000000000000000000000000000112c4cc34da9e83207b5ea8a9251ac5f004546596f2294b3fd51b77ad8d8e98239d53ec4f527c7280801233175500b1b0000000000000000000000000000000011dd8627748c9a2b08524f88e560cd3944bfd1fa17e1d6e2e9cd025b04f2e3ed35125197136afa2848d24fb5fd19508900000000000000000000000000000000093219f9ffbfdaa60c5965b45a5d5bd923eb5d3971542ac147de3f591a5fbe31b30704a0061a524e2ddd05a45dfcb6a10000000000000000000000000000000006407dffb5580790e250a72dfe68a488431f61f45ec9df279217b8800f0ac1ab585d84e486487d5688735fe5aae75bacebe67f3d067b0d011abb31588d1b2fa9fdf8a56bc46b1a0196e926d4ec73040500000000000000000000000000000000107ede23f8e4f273ac2647fc251008905966dde32339c023f1da3c4d35d483a55b54f4157a303e68e1dd7fa3f3b14c8d000000000000000000000000000000001739327f282812fbcbeccb12e40df049284562d8986b8d4559787e1d5247eb6c83d6b838d099f36d8d0e32da2a7999a10000000000000000000000000000000005e5b6b2baede3ceae776da5adf075c1d774e83d6129ccfe7e835862686bb4064b187cc0be0cbfed37e5cc039f3a3fb6000000000000000000000000000000000249554dcfa53f73ef8f08daabf20c55301f75c8ce095cd794061c55e195221602a54ba54260980bcdb35685e41d0f4ffa1d6d0d1876a67337d66c596fbcd7eb22ee308e4a5f66cedff584f1441be6a700000000000000000000000000000000048b7fc5a71787231f1c7ed2134be528fc8d8f77102bda806ccbadf4f9bed79ee94b43c0fd3e5b1d776fe73d786872d1000000000000000000000000000000000152a1f005a64e16949d7249c3b391d5c1e0ded4893d0ce926cc666f0f88b64e8dd6ec4f92ddda18127ec24cad7e40b40000000000000000000000000000000013a2e1e7958a53307adf3beb32a88b7c493df0e37e074c9105da3c09bbaa01fed092fce2b1800790c6e8af3d30ec5a81000000000000000000000000000000000e2d405806764c75122c1b5e410673b28759f26af7489cfa6f35c6c0dd16c508af045009853f3329cda4a67948232bcef0c4ac919efdf3d0e649126da7f8ca3daa30b6ca6f3be6854c0f447a63cf2110000000000000000000000000000000000a71d61dbb3ae37230a2dceb54061d5f8c1ce645e20ec39785c229cf79aefe238959b2745e3b50e4b3c20c7a8e2ae27f0000000000000000000000000000000010e82b8dd5faed6bbd5755c4e5a88edbb3511d3f4442d1e44b82cf72a6414bf6558d29e8907b07f71c00f537637605bb000000000000000000000000000000000d8c93f1984b742b5a02777b706970215c7d8eeeb7377cc26c3af9005648c2eaea7f7a3177b6e049b132ef6bb4b188da0000000000000000000000000000000000ff082a252082499d70eaeba6d5514fc8d641404b48b2ecb256eeb40d9c6b68ad5af58556c9dcfc5667621c549b8ee760d8bf380bc2223efc779a747c0a36f8c2b18c3e821e96163bae14b18f3739f9000000000000000000000000000000000f4cf354b8de6dd2231448bb235af3c84daac2db49abed345da6ded50eae93982a4f2c27b07ce725a062b07fdd9058fe00000000000000000000000000000000076cf19408f0f0379c7e65a6675b9856782990986f5c6d7002e9c9c74b95ab875924bd7ad5e4812844f6d1f530e58deb0000000000000000000000000000000007acffe32f96f5e56557965e3db8dce87eb7140d93608cc003bf4a43fb261bb7360c576da0b7c4dccdbdd9cc53b5c5f8000000000000000000000000000000000eba1c668fd9323d42d6a82d9f075cec2d278cc57122e25ccd72cf8b5a569552cc6b0e9f88d23b9b7af18f3bfa0cc820006c3a7b5ae971e4b0ec34a1007a02cf8c55f067115ba00c5967f70a7dcef9d60000000000000000000000000000000006157cb6e2dfa2733d4c489ec0334f0303ff1ad410f329cb59f99a5fa3ed2cf84eb7d2f231078ba5db0954badb58425f0000000000000000000000000000000003dfee394f4c140e2cad61e8675b26f91244880d9a0b6798d6111090dc9d080563db5c89b7293dcaadc74ea5849a08aa0000000000000000000000000000000001aa1e0683014d5b6f99f469a0b7beefaf05a7ac0298bd1a3e2da409f6cf856f70bc067610fd705a851cd70054df9562000000000000000000000000000000001571b129f69f3a6717272ff75351fa053f46294f68ba3f859208d6c91ba5eb9a0f2133a5e139d04e38c7f7aa303451768f29e330b48230de23e0393bf1614cd26685cafb899db5a164497955d3e98be4000000000000000000000000000000000c4e84b7c8e46daea67c8090b27dc28b7867b89b92f56232bfd8ecd9968b865a057957292e79c6dc08162f9e91e6a4b2000000000000000000000000000000000b8d1eadcf3f1de6ee608a4a0ebb7defeeaf4e251bf07717a6a8e50c07223ca32a2ef290f26d0de14b1942e02acba39a000000000000000000000000000000000e901b546a4d3c68e4432f376c97f42ecf0724777956c4ffb1e6ca4fda562e57be788ecfa45ba3afadb439c2ea546ff30000000000000000000000000000000007ffe01da4fbda9fe5d47c3bedb4b92fdd71ad73fa272b071a7a7d1cdce7743a535da7dfe05a43d03368eb97fff54b2d861ffae8f62572938925593f7271a56e0f559b56bf97c454c38547a2185e2ce70000000000000000000000000000000008da0fe413e31ca68f84032f23bdd5399e01eb3b5ae47033c6834a39645d7b5cc2ec937067b91ac6d83035a86fa841f9000000000000000000000000000000000b950b982323f747782d9065dddca5332940058a604829e31560a6bf9b03ec72b09cfb87a1cd244ec694c7cf192c37ac000000000000000000000000000000000f4afddd25eac15d2248c71d76c9aa27323f75141820efeef1ab4f5003141053f138d9a7d1a901961d0f2c210ade27ed000000000000000000000000000000000217b1800c53d53459b00b8e463df1882b2cbafe85043f08093a5414e58ea7fd4dd933c601acfd7c154d0e4ce187468a2dd907071c2d39fe710215d174452459cc31d36007a1b5570a27ca2e42c8be55000000000000000000000000000000000046aed1acd19201553bb6a88fd6a6c0525ed44822d2a4ed3bca48a0a2b75e76cfcdced8f342b81ce03ffa72e667b3bf0000000000000000000000000000000009a5adbac43cca3402db016a2138342fae89285ab1fa16d7acaa9c3ee2b4e3df2641f7392355996bef7b1578ce1ef119000000000000000000000000000000000c8ebbcbdf2ac3fbb553a2e589f4b7c259a1621b83b14fd1927f92d9f6cb27e82507d7943ff5930f0c14b9fc38c9857900000000000000000000000000000000105b729f678db31d04ceae0aa37f9cb0b0319c4da9a1a4702a11bfe3a5f2f1f2af09b9cbd5ded5a930e2e65f4279a31699893c06db2dab559f2c374df4298707dc1815e55034dce920ae7b1df2ec8d23", "Expected": "000000000000000000000000000000000708e9b926f2536731b02b6b75305c549da58e312d9c53701a993624697af2f3469af34dd4634467f8c98a0f721cd9c00000000000000000000000000000000019185b84fc0511a048e3c39bc10334c91dc1052d323a31c8bf325479a2fa3e4228f8260c0e725c2b89d5a0319e6fbed70000000000000000000000000000000013c7c441d5cca81b48d43e908d6a3bf8b5057cf19e4884227cefa9b235103b46edbe01bada06bb9b620ebbd016d537630000000000000000000000000000000000431182c8a1eed66073956fe5798a894be396403c072e766cdc262b719d1779f960f4aebf61c1bcd4d005d3c7413e52", "Name": "matter_g2_multiexp_75", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000199f555aa5c651183f52470e36cde438422f41c9b2d1947510665254b74ba0bb9cdc6e6a1283b0c8f58d8f009eec46900000000000000000000000000000000018f1d8f22f43b4649300aa23ac92a2e8f17e7e3853b912bbc8e90588125c371084cb224c2d54dcecb4946ff6db53cd02000000000000000000000000000000000efed0bcc83a52f0faf9e260815da8d4e5286396081268485aab052a96af8eea0112be6cce1486b10b60551ad6c810780000000000000000000000000000000013a3b1ca3b9b7d50083c10d36997f5f521d4426af8d2905aa5d074ff37e218a0c96c74387485c2dae24c0842b7a74cf0d8555388bcc6791802ddb6c0f4cde44f45ac0b5d7ecd918bc34fb9fdedb65b94000000000000000000000000000000000efc5a5c506e94ad2754e235e2da866d9c46342f14d518f12510c93f13a619f6bfefec50c146d6d6170f190497eff229000000000000000000000000000000000fb91f34356005f38c9804250549554cfe67ce195d5e218e4e1b1a4fb904257bdb68d6dfb013e8e85fb5a4cbdbf0f21a000000000000000000000000000000000f09903db4c41fe3f11c6f0cdb7c31a131033e30f52cb66ba10c2e7da1ed8a225ef280d313630121701f9a490e8a0f5c0000000000000000000000000000000003484f7e8f7d67ce40b4cccef110bc255d91f61a4e1968a9ad37e25058eeaf39e9f1ff89c9b2e515388a7c1b49a84a2c33e5999498978d14c9de06f7beb2fd870f6f16dc42125fa496606e65c7466c0f000000000000000000000000000000000444215c3d4a7d62201ea1b69890e2ab90b5f5c6ff56fdc9908634c7489e785521b8dcd7ed409cf09c585cae8414a3250000000000000000000000000000000002d70674251a0c9ba76b8bf3b70547da77cde5592da9204954abd6d8aec82799cc0fa4fcd42139357043fc867b3d0e0d0000000000000000000000000000000018c57fafbad2351a3da695f8b523443e8c763dd7ab875caaa6a494a498cc40b1c0d44488e2dc80d1f0bce00a2c90c67000000000000000000000000000000000125d5a87ee3f558b5e1e7664b0cb95c195bcebd5e43b930fb47d15eee4fd50b3fdd0a401c9bb011c326acc77645440137894a51dcfe5a8fa4da1745a696c870b353fb03a31238b8744840a78084bde480000000000000000000000000000000018790123ce8b3b72d626493a16936c47770a9b06ca45b17c6fa5c7759f088cf98de8ce7b3b5d6082e9e42b39acf76f79000000000000000000000000000000000fea86cad8b40f315d8378550f6d3d831149339a8e8dafa77295859ddd2417e8f5c0ae2baad25fcfe00de14f45a537170000000000000000000000000000000014ad78bb2bce966d52b1fe1a273bc07f2f24b354465edef6dbb1e0123c7c3d7550983b3793ff1c7db846e88eddbf33c4000000000000000000000000000000000c0daa6fba40ec59f6b34d413130df5d9137297d1b7b71b83114a6570fef8e7f83d6f5689527164782f92da4b1ea12e8fb6a294589c816e18859cec34262df6490a2af6acc7daa3de861198c5bcf4b13000000000000000000000000000000001186b7c78952e5c32a9393eab07ad4532471595bc2c5d8137c61dd7fe6b6ca3aaba82dc205a559bdc15421a001b7270d0000000000000000000000000000000012d56b6fcec3d6511d2d723601cb8c9faabdcdd12efdd0e2bfd7c9292f2c3bd7f39c6e9aa53e6955727f88ad69c5b4f10000000000000000000000000000000006a5e56e4a42b04c03619c78232104f1f1f39e755058a19354eb230f2f09bf486b2586817aa6b88f27b884957ea0226600000000000000000000000000000000118c8521dd4866df907ecb252d9ce7a489f17d0f240d054a5dbff6c35895ef20b205236aa6e5be6f0825f9df87878ab783c4a3460caa35fc0e7342dd2da5c7b6aae818eeaf5a2cbf4794387180b95dfa00000000000000000000000000000000092809d18926c20456857826491f55cec17803e9e7d43f22faf4da18ede3bda15e3319539017ab20ed1de2bff490a33f0000000000000000000000000000000018d736b967eca64234f4e0018e5d6c902608e265037d9b8ba42dcc923b84ac62599e153e1c7d00e552ecc5aac57d1a5d000000000000000000000000000000001804aee99219354d4a5c46328f0658a417c85c6bc89af6db29a4911c4b0cad5638fac5ca61cc997fef3450cfb4a6c666000000000000000000000000000000000bf99dc4a400adda5bc89762e9011dae8ada23b284e52e2d49f75f1c75247f6282c95a36f7a72f896ea308131215404bd2b65c1580bb46e3a4cd9d9c4eb7dc998168c66982448abf3a4e08cd12f612b1000000000000000000000000000000000604f8bde85c0b26894e0de155cf896c911bca47533362a0b59ccdad0dd64108d33af8262d3ca2ca399306723f2482a8000000000000000000000000000000000ec10d3777aa54cd0cfd84b4062092ca3ac840a24e8e8aaad5f4c275e4d45091f838ae522efb1b2a0fa42229157297d300000000000000000000000000000000132cc70638d02186116773b31ec0e571a55c1cd78ec055fc647ab09cf4d3c543e0552d559b3daa4e99cef031e583e61500000000000000000000000000000000194a6a32a269692906b64feef9e4e8cd204e560b98db8c66380758d2123babae871273b4c571a1570a317c13a51d0fe9120892aded230949b83bfb2dbac054b83a9dbb852bd0ad85dd1d7f715852306f0000000000000000000000000000000016d05912dfff44912bf34f242ac85eb55bbb8a21625d45496c76d057f518352528c6632d6e8adbbccdd5983d13c26953000000000000000000000000000000000b10aa1402c15fd601ce605ade8f25531ea8f95cf592bf4ed86c4a3aa847dc8aa2369655ce5348da30a897fa8d71ffd800000000000000000000000000000000183f5a2f40da0a0f4598c6b9ea7b99f8cda1d85cec0e6da5365d7eaad1e9a3167bd647e5e654985f395ea72257f61e5d0000000000000000000000000000000014e615e2d5072c1b536ffa607f3a826ce297800b0da329fff397b6327800ecdc879e91f1e3ebc26c18e188e1ca66bfd66af9777a58539e5aa8b1fce0994e0e1cdb5877d93ed4db715c5aaf74d6a8bb1a000000000000000000000000000000000f3cd275d72a637bcce855e2e20727c6e5a1f15bc8d799231d3a7f61311d4cd2f58cf38448675aee9910c1a3d0b576210000000000000000000000000000000019efca445312f568727948c803d06b8d4e2c5289015740f2626fedbc0047d344aead06ef521ff7e139312fa41d1c107200000000000000000000000000000000141384e1c9f79e38bbb0bc1025c079741b93f56e150df58cf9a61ec27c2877c4188866fa197242965e3feb47a78c68380000000000000000000000000000000010638286faa6c45cf028e8e3d200edcb348560e2e35902927391401b3155240b62a40784db88e02b874e128e3a2132b5f37e2ed8e96921a0f9bff8b43d432b382d7b59938e269c381351ea49b8c1ba2b000000000000000000000000000000000c7fc4216767ed298206bc142862c138d78726e2d39afa18fe5732616c73a965d95cd2032d4b2f5a4d562be48ba6885a000000000000000000000000000000000928bbbd76b87f58ecc850e1aa4a2be11b15a81786aa7ca8cf0f6cc342db87b66c435f009f88ad97b747400fbcc651e10000000000000000000000000000000019f5ae9f06f2bc27a39bafacc7f3745fcdf8c78c9ae8a3c066ffd704aa4117eba773691ae43387b93e86d2e2de3688700000000000000000000000000000000014360a7ed73c05ef5fe651321f7e839c920bbc1896636143b88357cbf76e15da839bc7e1f1e629768d447c9d313cec8e23f4a77a2c34a370a9b59ab1cfad77212e433464d0195f0d2fd20c69141389f50000000000000000000000000000000000b9d955f9d28f9485d0bc4a961f0acbf09ee5fef38ccd81a2c73cf87a461ff1bf28d4dd1e0db3ea522299af67bff93b000000000000000000000000000000000889061e71866001b0760f68e20c7c0c033d782e6e6752f11502a0e8b6b70277a985dd13dd83424d1e5cdb9eb96a01c0000000000000000000000000000000000e05a26686667f44de2bef53c36c82f1fdda13dd3f7f8fe1fb026273dc4dfad18241d732ccb757e2b46ed8317dc69fad00000000000000000000000000000000038b55685b02231905dd9a62a709c0f015cf5650b3fa469462b3e9d06e3af8092d998c8e08ee61db1fd5583b0809a38996c59b0bc6dbf66f42cfee34413cc4cbdae7a61e232757c75474818591764d6f0000000000000000000000000000000006649a8eabb25fb7793344a0b29325a88294343f6c69612ee9d9002154a49791f6cd7b37b2bec69fa8ce11722e9f8a03000000000000000000000000000000000e10f2f3de16fce9b9817085f0130e1839d9aae949170ec16834732a9b12f589a2b00f17d2fd3416ddd020b7421ca20500000000000000000000000000000000016b51112b3c7c42a8c2a0fa7f286ec05cd07b6cea5675bf1132de99cf42b450b3c2a8f02ec821529a14a2a0fac3a751000000000000000000000000000000000f471ec8b65bde22e003500d1d422dd0d163abb424dd261fac588333755cc5124acde328085d8df852c61e024155564781c180924f1d982bf4b6a2bb1cac590cdfe84198fdecd87364e163dd988f9b1c000000000000000000000000000000000ec162d22b6516c309efb6a4577c5631a5807bebddc5fd1be5446e4a64785d49eed80eba2e89cfefe484ecb8d50440a600000000000000000000000000000000070c252caf6c56018af6b281b829a4fb8dbab850ba0446d233dcd4d87bebac00e3e5070bd41898dd561526498b153199000000000000000000000000000000000a0d76d1205c1f520d82c85bac4473ea7cf5f68022d95b1f04d06062197973001234d86921e70a94e478eea85264f14a0000000000000000000000000000000014c6a07f0d568f2103ccf8f61278e916458820bcb61fd91479b0dee874fe36c063a34bcb14ee434b68681d297637b5bfe44748b9eb1f44b5fb143cc8deaad23047bc5ecb8059705e7905c37625d5e2d3000000000000000000000000000000000aabac129385d145243c3a1f357ccc963ff14867ad039827488128ac639dc62fba82ace66f889b47d8eac39802bc1af900000000000000000000000000000000062bbbe8c72cd6f8626484bac159b7e28c6c8c3261edc6a05a30c308cc9e56db17eb58f62ab755f04a5c87e58c04c7550000000000000000000000000000000011a4a439d18501142350229778f67bbe0c9b948229dcecf70a8b09d1df6c54801a111c603301da2377d4198d09dd51e70000000000000000000000000000000017de3d9bc6fc5f415d04ecec013a635fa200699c496f4d0bdb5cea7d446274dddd0a7f6b06058fde43fc4f1457361558ae04d7723b7c9cb0574ba744bfed8f8a347ab740bdab99136aa71a6d635d0d98000000000000000000000000000000000c86590a02fb5c9568af4e69611f09980cb5a7e040c94ecdbe64e40005783fd3305a5657a5c6bebca7d20ee123a872b4000000000000000000000000000000000bc873a9bc694171d2606f4efa409897e03198a61b1bb16ae90f0d12345d2650d93c46e0c22b717e2f0504b8983515990000000000000000000000000000000001df9160ac3bc54c0121a9c69e9065f4266202f755c961bcb8641d13720b82ebd73eb3804ba44769fb2d75144442f1c400000000000000000000000000000000045e9c8ed2fe1e5c9a2a5bda75dd60f6bb5dcd0a805f68c1f662a5960b025ff29c8e21857d2a61bcd65c747d2a2da8ef6a794685a342ff25dd706e4df725e3466889d8f08a27ed2f32523b117f01a84e000000000000000000000000000000000f94df8d267339bb4f51b21014ca6d685f7657d0f0bca189e53cf19e0e5e05bfad773c0553daafd80c86f302b1907ba5000000000000000000000000000000000d92905addc028a1dfdad50e909c77662e10e4689e7c8a4a0174a3e1c746b361665b65e17fce02b6c067a5b8d7a6a6f500000000000000000000000000000000183444f0665790c48bd3c07545115a11f82463a092774234e7b33aac1094761f213235895e5e61ac1b0a15603bffe2140000000000000000000000000000000003cc2cbbf181fb023a5f6088d8a9793b17984b3dddc8c3ef1a9f82f8f436002610df60b2d35be212da9945bc8108c0bced3f23c51953e46d400802dde46c374178ef379d5c1b04d25449891f0d5623e5", "Expected": "0000000000000000000000000000000011f85691799cb76213068ef4f997af66c349bf707295b969d85fe637d4eabf54f3f29e739152aba5027c1b55317a27210000000000000000000000000000000019627f9570f07f44f326b5b3ee19bc477e92d813be2865e00da93135645e02e6fe5507ac4d50085b02149667794609fd0000000000000000000000000000000018fdc97bf0f88b2348b436d70ac4e28b5ee5ba21e21e94808b8b9e401c0c7d688974fe203ebda0b23abe38018876f4930000000000000000000000000000000019e28c9c936ea5a0b3b41871c3afaaabd53a93902e44a96dcb7651bce7e6143d81cb695fea8b94aa32c09ec030dd9ac4", "Name": "matter_g2_multiexp_76", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000703481cf48efe78fe8dad34184edd1765a1d01846de74a45b43d4721bf1af116c229f969868b0e6e851f22bdfb0451300000000000000000000000000000000063d316d495b1e82380c5b73bd61ce7f2159e7714c50e374e8a91dd56731dbe03a3378bf8afeccaba5fda73b4c2dd166000000000000000000000000000000001012cb2f6578065c93aeb673f447ce95fb42927ef9d12e07968ec04b6a604d785944620043dee5de4de33d59e67d64f20000000000000000000000000000000018cc7cfc360801ecc420d77ee171fb3eac3be0cf26b3f36a6cfb7c6adae7bb74c18071daed8fc56b8fa639ea138267928c8e071da1ae8f615631759cf33fdb876ab289a6bcfa6fba2693a58f8601dfd10000000000000000000000000000000011e0dfc437a65c6fe37bb9e554b5138f68a3c52816807bdf7d98f13cfaf86b37e9669f4e0db1b7865d910a309f16cc200000000000000000000000000000000006f2323e01591a7db1d3c7fa1a2ce4540cbe0396cc55baa3a3e13650a6f6b926a7cde0eebb45d359edd52137152fe360000000000000000000000000000000000066bfec8df4ab5f5f5eb369b34e8e22fe32abfc00ac58b68f2d3841248fe5843d6d29ad012249fb9ee851e40b940dc2000000000000000000000000000000000f4ea977d9249bc05dafb682a863ed17f7fba0a06c4a13cdf5a836748664183272eed96bc4109bc5beff61c5469e221f8371fff9230243d2e6cb6bdc4cd97260a8cf0362d18b9ba8df512d2a6f5563dc000000000000000000000000000000000fa3e3e77112774fd6d6b560ff88cc92ef8d009675d0ed65705398ce727cfe786684da50bcdfaffae97d19bdaddd81c00000000000000000000000000000000019e98284b8b9f53faf3b73902cc322dd80fc330dcaff2a7fceb55db6a4b0f7f667297f5e4650c797ee337985dc6b54310000000000000000000000000000000004e30acf2ba66d842575c8679caec607fd090f0aa2350464f3b6eef22e2b9a1d9d5fabb0f3909f1c19f6b8f27c53b040000000000000000000000000000000000ad76b86e32f84ad74bac68909da0c271571606e071b13bd92e387a8a16a1c4002c5a5e94ecaa1e8d2d6e051e19a45c763016c9a9cfbf336ebda090d3f2a1a1b265787e1917f0148f82a9c0b66b21dc100000000000000000000000000000000019bd07479b234bba974ca2f39b317d5f4be33afef66c1d69e53c44cb5e44c679775ba141f82486424110d186561777f00000000000000000000000000000000130002de0d453abe9052a5f70a9d55de74939d1c8e6ad5871a669a867861b1359322eb98539f4a21597d806aeca62d18000000000000000000000000000000000b2f0c649fdb37216c10762f510c3bb4c789dbd29c4f9a8ff39f74ed1a96609c60473a50f5ce3f6535e4af0f2f0a150c000000000000000000000000000000000893b9af710787361a32fbd19c380161c9a214a1bcf3761563424b8546f6068ba650d9caff3e42be63ebf4b6afa2de516c9f679167d5fbb29250834c9f65d3025606e2af20aedec309718f95ba01e90c00000000000000000000000000000000019805c0de5e232632228e2772dc79712e3d863bd6fe56932b29ee99870d2ce5eaf90c73632d1dcddc093e9b6b5b0f1d000000000000000000000000000000000405d77f4b3c44f99a956ef375879e62df033aa408127e0fee013b74675a8c7d999c6abd30f459693086bfdb326d67af00000000000000000000000000000000110f2c231998aca3d76e40055a05feb37eba76cdd10106719f2300f57906424d7eb6d9f85115b78b7371ee60e26d02b5000000000000000000000000000000000593a4721a67caa7cbbe1566611a1d48532c68adcdbb67f362c9ec21e08aaddf6b5e09a9a96df9a89bc25f11665f3a36aaa3300f5a2fafab132f5f4662c1d288210e7502ca2472d060aeea6f2eab2d7100000000000000000000000000000000151758f1921743d116f1c4adfc09cb68b3ff911329e2f6d6bcd04beb9c109568c796f328e1f04381a995fe89aebbc49c000000000000000000000000000000001388c73b1db46bdbe70540c99db46b730e157a23afea97648d73f9d5f7e8b073ed665eed9e9e2500152c87715f1c4d4c000000000000000000000000000000000284ad228867ed14ade5a327ed951ca50c87f0a669e59b7a75d17feb54bc5d685245448a912590179db1e84f1eed1e5b0000000000000000000000000000000017d3da7c167733dd88f1c39315e47cc80c3310cc431989d4cc50ddb22e9fa481c5dc02d94dbf806c4c8da16ba5b24905f6608f7c036c8fdc335601ac55e869215eb4e626f52bae813d45b827df2afd490000000000000000000000000000000016064871cb68f748939a839800afbb018fd5836914a2b76c51818e764628a76817c7ea329e6b2f9de653c8162a2a2e0c00000000000000000000000000000000082fa03cda4c617a780caaecd7c859c5251b56b61f70fb3ea8c05b4c11c030adb8a96d715c1325ef3dce9b20e8065b6700000000000000000000000000000000174a245baedb7e1bf1368212620b850151be41ebb00c977d85da499223c207ab6f1a1d94a51aa9e90d07764ec3615b3a000000000000000000000000000000000df5b81cf4b008480775ff3d7644f546a60382e92a98b03deaa4a20f831e69e14a893ffa731c4ae9ee237d747149a9080cd68c59b1371c7063dee5732182961be90b95247511a5b564d7eee8d2c7c64700000000000000000000000000000000019d36b8dae5e1083e687743f7494b7f9dd0923024df81e2f83c78743e227ffce588a16630201b9909daa6c9207b5f430000000000000000000000000000000015659059cfee7850e1cf0e49abeef2fe5837cd128742e62de20dc734f1bba343aee1c9f1a59d920a0519995561891fdc00000000000000000000000000000000102b7221257c40d9adabd0db3ec9f6348487187ea1110773fcb2ac5ce210dfed167a4d15e605e9d9e666fd092147a1c7000000000000000000000000000000001402ff9770d27d2d82efa6abe4a181e3c1d944e97a06f670d9e46b24f9900fb4a838b32e17482f25be9b6f3240870c02ea52329555d9b79eb1fd6d186df80b25245ba9225553f402cfa6037592f0b10f0000000000000000000000000000000001745ea52686f87a39fa42ddb5b0f69368db3757394fa7a1a93eb20c398c26415c8a7edeec7334df5b15345d6174126b0000000000000000000000000000000012b580e6fd228f087c7584cd95826e56d1c074cf16c35286c45d2067a362529d241c1e24fd22cc9727d423551de1a1f700000000000000000000000000000000104b46c42a706c61610f8c0434894c7cb9ef878cd0234f8aec0825cbb8297bed3de349e7f6037dd19a159103ca7753390000000000000000000000000000000010b781b3cbe6f415af15e37be7c60dc6703e6e79618cb3d8d9a5ea3b17c00822aef1eddacad66a646c009dac887bb070caf39f2a517d432d1653c37fd9a6c4a8a811107dae428f4b2af3b12e4b6acea30000000000000000000000000000000004b172c360fca555e65860c7a294960f506b562e012ddebad5803bc3f4b93159c16cedb73f339def9cd1beaa0912c93c000000000000000000000000000000000242e37775a042ccf59e99da667c67fc49e80e54a1b438a74fe306d668059ab4dc7d9e457adb45e1f91b3e6bef0a130f00000000000000000000000000000000186eb83ce3abe66b8760dcc0d375eb783d175b0b2f36cc08793d8a86cf76b7618b826f50c6b02ed586394abe4efec2f1000000000000000000000000000000000bf780324df1cc5de325a796f1fde367eb52dac76c0632915dfcaf01f5acd6ae890dbfc2e505bafeba7fed8fd63018c2ff0bad6dae80d5f47dd8c208fef0f3046cf1040112d18c596eeb934762977cdc000000000000000000000000000000001231b52c8a081add6e5c250caeb9467335933c2ed66826e4ab44561eda9259acf926f22ad0df8e8756aa51279d12bc9600000000000000000000000000000000051c46bb04d3e035d324de681c772e4561cecc6a5bc4ef0a0cea56618e09b3f39f5085e208229e50164bcdcd4abdefd2000000000000000000000000000000000ad7ee610398935a02c3a7139185409d7fd4681ebb74a239e15d1c092ea913016d3f585d8224cb1d109ac111660a94aa000000000000000000000000000000000903bb16efb052b99e9c46f3478b4acf800a173b35b0079d7728fc25c9415c8b05ad520f31e6a3c867245f64355cbc080d0c40e5d422685c5c83716380eed82392ae1dc6074a7edb5759fa34a61db2d0000000000000000000000000000000001788efb21597aaac29b7bcb9ad6cecb89267c757cfcd8893c32fb13c0f3e1af7fcccb9573dcffe8d9220292b7861cac90000000000000000000000000000000015f85d3686148ad62d7fecb71920981117cb8759ab249d0ceb45f9e4687914536a1eb16ccd0e185d1352a8d2b4a8ee7a0000000000000000000000000000000015d8ed94c0415ee0f7c9854841bac5821253bb2ed4d86a61f494cbfbd61614983e4279fb17802ca68aba4a0302ec1d8a000000000000000000000000000000000f950a4c8aa18f4605e1252c367dba1e170ad00376a8560c2fccfa7d5487b0d1d5885cec16a0a17d81b5a584d473853f7e93a16a443d5f981a02f0b6866536dadd276abc0998bedd76b168ebc8e31b82000000000000000000000000000000000da25ed9154121205ab6843f603a38a6892887d2725f16ff87a5218586c6139188f46da5a42b5e05982468e8115713ce0000000000000000000000000000000013c13ffbed4a60bcb8659013b022012ef3a4400f506d65aff7ffb1bd5a9a5e030a298e417cc1ec8ee7ebc06455dbe61b00000000000000000000000000000000132d83bd141c434326d4772de7f8772c30a6456de7adee7de66a04bece4c0d20bae5526c8eca5af5ef2eebd72c90d54d00000000000000000000000000000000131355c5e359081dc86e0b15c8aedb4f2016b41e8428051f5132258eaf4392fdb63a91452dc56aca20b7ad3263ebc8c92a1d13a64c03585715908744481c79f340b5bdcdd88d685ab8b91722ee7ab7190000000000000000000000000000000012dbe1327162e4176b4988cec23df0c1b0075d0dc51ea8afbbf98f00891511d9023cf7538c5705d59b6d6ddcc90b101d00000000000000000000000000000000036c12c7f7627b6d6fcba9a303248c38d784a3d1d0ff02e550565efbab68c5116e9a88faaaf09bc72bcc3358e9dad0ee000000000000000000000000000000001578ffb68cf12dc9a5ae6fb5d822324cec9e3f576ce08d45e24fec9203d36a6461c5b8ea6ac50233e8893b07ea6e71e00000000000000000000000000000000015cdb43c82b20b8ab270b942b9e625ada9283962a7ce95eae156aa4355e1123ff87ddb1cc85b2a94bf36102ccbec33fb2bc6979fa2e386abec058683c6d74de31af3cac21283cd5e4244d7edd94da9600000000000000000000000000000000017041e16975850e6445c7b4896955eb5eab383ad3c3031aef04e8fdfb65a6d52c9e647330bfbb0f0eab630c9f9ef7a12000000000000000000000000000000000b62757ccfb913ac4264692053f766e142697f598a3fe26e998119b63a3abc7fee03db32a8af36aa21181fe9ea89d12c0000000000000000000000000000000006bbb842a889d7ff3c1eb5e0b16e3a921a11d28a251c488a8a17a29edd93672fd15974a7e972a34c47283c583cf2d29b000000000000000000000000000000000e94e685fb1751f8720b8af79aec7b245ae8daa195f11f485f2c0c5dd68cf39eef848a402ce2342a6b3398cc7879c6010f1937936cc3766184e47f39acfe5af4497e8edf77ab34083135a9ced61d25ed00000000000000000000000000000000100d3fee47ae6c8c7981c8cc615870924fbcb34c2ed817d6862e2e6d0b4612222a4c8332c7d51b58ec59df6832139e1d0000000000000000000000000000000017270fa71c34ec84043ef64c5dfd61614b5b3bd99204f9f70994d71498219818a5f16843c67c668b06aa5ad3a6ba8a0a00000000000000000000000000000000057948c0ebd14664bf33fb282e200fa0e641764a353e8347586465dab0c79ca2caffbdc2c6d60b2d7c8cb6b088bd16fc0000000000000000000000000000000012747eb070f2de18f517648395109bc08b4af3f04d98e23eb6b516199b4eefc5df7d57baec736987139c7b03b573941f639a8b60a1849c71688a11e612b315439161717f525b5deabbce75808470166e", "Expected": "00000000000000000000000000000000128c6c0283ea35c10330502d6aa849a909df6b8dd927a24f08072135b8e21e40c495c42e742160363772569189d73ef40000000000000000000000000000000016d78dba1e0feeab46f8cd38681a9c2f6490ecc3a6e79b31caead256611d133090a4eaed9691a87b66dd1c2ee50d5f470000000000000000000000000000000016de93e176c950975abcbc692384996315a98065db6d6a6214472e5a338e291b36abbcdea1b8be6162fe578acd669abf000000000000000000000000000000000d7155e239e9b15ab64a538b0a0bd53936df4ebdc3ec9b0b1d494e4df780bd014425759e9743c9b262cf48cda01e945a", "Name": "matter_g2_multiexp_77", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000a653e0c24eee1cdf8e3652809de0cd159f2c541981a4f43936e7d41c0f97ffe2f1e1e0d1032f0970023f1d27241a16a0000000000000000000000000000000012d1d8d2f96db0e5f97be096c961e3b90ef3d88492fb756894979d2e8104791a5b9a43888043ce9e543691f15d2fdb650000000000000000000000000000000006ffb94dc3c2d07830498260ebe4641b2cb64df61cebfffaf2d4ab5b6ba92cd75de209e8d7915ee744c4db5352ff239d0000000000000000000000000000000011f25722cf9db77ef8adb9caa250175e12412e6350b494395a86c31e1f5dee6c89cc6603f1dfd08a70344cdc44aa0c2df3efcda934ec9d2ab05f25d618e5a483e830d0452a88e980589fcd7cfc39e5d80000000000000000000000000000000006177a74e3551770e7d906222590108bae7b97a5dd3bdd2344fc12e7005f2c1a188ab9dffe68f5ffb0cc36294106f15800000000000000000000000000000000041b140c46868767119a6ebb58562570732198854c92bcc070f2a8d9be91282a70c5ab99e75cc9e5064ed628aa5c59de000000000000000000000000000000000f318ee33fccf455e46add44922bb6e99afd4354bbc79d7550f8d12d3de4f75e5ddf4e62624b116f91aaa80a148adaf9000000000000000000000000000000000fe012bf88e152eb62c0c906dccba469abe591687573a59d3debe747b7d895e4b0755f16e67fa9193a2fd338c04d243a4507a696cc57c0bc49fb4d1686752c71c9c816d7d09bd66910b23810d475aa02000000000000000000000000000000000b26c6e0106d4efbacf2dd0d15df17209b1306f388f493c096429c031bc4a6a535b64cb02b400433f948fd6004df2fa200000000000000000000000000000000061853cf1a32fdf4c370cd413754ea584d3722a08d58575075a7371e57a7bdef95386ed72f91c4893377f6b551dd6b1d000000000000000000000000000000000ebf17e60718c8563a1029ba035dbbba75e7191b4339d5d33f64bb35f34866081f26f4815e01b02e8330e7b7e9c428cd0000000000000000000000000000000008ce40f92efb5c5be48c814018fbbe45f1be45f5b607a6600cecd50d8f791de7d91939ab61204c2a1337c3f21b2c9d26518c1259f23de4cecd5e3a40abef5662b497ebaf16240f40ecd651d2ba50af0700000000000000000000000000000000123ef52cc44f36326b33234ab3348893bc722bac3674e43385b201f372fe4ea3569d69d4d561e26f8ea903e017d7376a0000000000000000000000000000000005b1707ef61ff9acb9e8b4dd6922daaaa2d8a7558cb55b1b9b96eb6d57c23f50a7955763c9b5ef04f52b09be8d55f4b50000000000000000000000000000000015b6e35d14da61e7a7fcbcb0dddaf0071d8d2d89f7179f44851947a2b9b0535d6fa86b5cae9713a73bbed909a4c6deaa0000000000000000000000000000000013463e135b1fd460cf042dcd0226e229d60cc2beccd8a1832df241e65a644159722a14297c0033eb499e5890f0caff1e5561616c195ccc1345421d8a6efec48f0a4dc8e89ee89599839efaf95c386551000000000000000000000000000000000fbdf4a533d355e232723fbc97352fc5d7d3d199934883a61a9ea116830bdf9e40d423256225d9a3458134332ef6e817000000000000000000000000000000001195f0ad227941c5e383c48f546be34762d158e6cee585650b6ee987f7b98e802f678abac6646832b30b6e12e90948cb000000000000000000000000000000001820d5fbb5a62140c6e8cd105a70fc2f1ed84e254c839deadae5eadbb75e1c33a07ad12ee92900f55478e91958a3147a0000000000000000000000000000000013849bdcae33fad27f16e91c6d46b9678a00491e3d70a8db905db4b1d2c6f02a29392b5b77c1472052d6f4d49f14a16737c77734125181c72454bb2d37c3725cf1f9b6d6f42b721bca469fec154b3e2600000000000000000000000000000000188fe1e394b567d71099fa13b5c8a5891636d83b6b8a08f410b080658a0663deaae4dca1afe8b9023b5e8e573c752c92000000000000000000000000000000000f66c65dab8e1b2912fd5285a4c87821888532f5107075cdfedacc4d7f75c6a74b4828d0b4c3a2c0ed94576654a7047d0000000000000000000000000000000016af44a6df79c8c9b6f1d8aeca24e024c454d7b94c9ed386858dd35c4158cddcad1207f9fc3ac9e3b748c2314f875dac000000000000000000000000000000000315e5e4f78e9fcb93aac78025e95b8bf82ce4c840cf565e0a868b0aac22950d62f7becbf8039a16ca3ea66a7498327d981483aa66e04351f4340fd2b461165b9a9983e91c148da78d3c8e0c69e77de4000000000000000000000000000000000f9a61dd1b3034b8cd7408b0a44c8d02f4fe0e87778d5d34f5e884ccc9e2d51eca6b6060b46b66843e8247b3c794e19d0000000000000000000000000000000005c47fa7799a0fffcafbbe4694dfe8d0f47b60f712d6319e9a56ac459a636460e700e2af80f9c688208978aec7c413af000000000000000000000000000000000ab1c55fe2207865ecf12e372a341c776d24c08dba10702fce1cd2c01eda314852d81d0ccf1c3423c2a12e8960677f060000000000000000000000000000000014f8a1964aa3240d788ea40bb51abc50fae2736a34120ca9585fb2d5bba4e5cfa201c83be1e00ecd1c46fcb2ebb4eb809913da6f756005ca8ab900ab686484483af07df768209a16d807f8b88b9334d30000000000000000000000000000000006441fcaf5e68b10e7e511a95e56b9613453ec6468bb126c5eb12f204c9681c69b5c296320f92a6fbb0b848f8ab5fcd1000000000000000000000000000000000141de16aeca0a2f991e9fca4b6ce8fbab3d66ee3ee4dffb0124384a7d4ba51864a53e005fd34516c92ecab33165944a0000000000000000000000000000000008543656b5495bdb726109cd98fa18e405648fa88cbe2e5fea5380b7d0ecb207f0343dc7888b9945e55156977336226b000000000000000000000000000000000b53d4e392f304225b1ef363a3528daca1d3a6ad64ee99d58491863ea432a29cde5edd4f390de45a567cf32112ca5929188fb33fb359f21bc5bdfc85d39676c2ca0a1e619bf8a8e8de62da8818bd6cfe0000000000000000000000000000000002e0c55a43078df575efb2c99b27c5632dd1c08bf28b6c0558081a78de58e4258d1b57d94ec6fa157add04aee06e7b6e0000000000000000000000000000000006d3f4f0791431a56fb386f4bb8e6744cd19b10bd0f2e65e927371ab488d3735e3b83400ddb25ef9d740a8620821b0ab0000000000000000000000000000000011e9cdfec8a8f8eba0de6809485911711149ca0ebd0cecc033e2e5ddfc195fa7de671a686edd2f56e5f7da7328dfbec000000000000000000000000000000000171f188afd5d9568cc5648aefb65cd715c0293344b9aceac1031f10b4a1e4b9fa2ab11114bd58f28aaa58c10ee0eeac65525ab4c4468a2ec0beecdb7fb072f28260ebb3d9da1a4c274b2c11a087e814a000000000000000000000000000000001651d9bddf61e5e54f86609c2479513ae84b000ad7defd840d9619a8361922dde81c999d0e95d8a3044c46fe0360c2030000000000000000000000000000000014a68c248808e826a3bb50f3c1c1438483cbb9da8dd67a0c9633a47f733e6aa7deb4a13aaebcd50de6e8e8f00000424a0000000000000000000000000000000010c8a94b9e0ec9965f6c8bd0c4279102ab682a14fc3c22e9640d68f240ccecfead9a2c6e69f7c8ed369cce7e2da50d5000000000000000000000000000000000181493e8137fcfae203e1b45189fb828dc9eb56887c89aaf9aad0380fffada423f0ab48ed068ba4e67a2b01a16abbfe55ab5a55a5cfc49cf6c36b5718e108f8d006bf7fa1ec3dc7a7f9c02a2d1e3fc57000000000000000000000000000000000e3e33fa4d85a35e8707419ca6d4fb6a61ee6b07ce152adfbaf6b5f1d7ccc253b59f91e4545848b3570bfaa804ad9767000000000000000000000000000000000c923a4de074dce3ccc94698bf6445af5847c0e6f22f225c589f744ec83ed0810913af2a6d04bd55200ffc738b31b01200000000000000000000000000000000186961ed1c6039476eb6f13bf1b5f6627b3b017ece57a4a5f33db8ef12347fd507398a421932d3d2a1d009f65d06e42c0000000000000000000000000000000011e10ae0139f95a2f1144810894fb98f6e5e86ce67877b949a2a7134c446dfe53c23dfbfd12919b24975f26eafa249216ce7aa7dcd01c1b7059ad3cc0ebf5d19ceaae633160a968c33aac5dc6adb942800000000000000000000000000000000029265ecf3c81aab289c98d9cdb917749ceef56e2e4d59de2d6c83907f394ddd1cce9d093a20206c2c1c215493c41c49000000000000000000000000000000000986ad139381e4dbabd6beba179600e1c782f436f84a7bd58cdd96a22269f1d937f88f25059214fe2a781ac519aa621d0000000000000000000000000000000019e296d5b17f78b3ffbdaa2ef5228fa9dd65abdf6b2c5b0f99a708c4721797b3b156b8df98a5a879f17f095548555da7000000000000000000000000000000000349677d4719445d5525cd65e2338463d232eb75721ca51c48fe52d0fbd299ddbd6cbc12546f056bf212d5700c3c4100854bce63dcdc0cf408b43690abbbbdacda5f3ebd9d9e462f89f9f50a9f7bd44b0000000000000000000000000000000016f5d5eb3fc3ff178843a7d21d3dd628bda120321ae44206d88f07ac001651428e0da95d3f0676e1bbb969a300406ce000000000000000000000000000000000029121c539ef1d7b9888497a362fda2f8402adf10a1bee11b53cf3dfcc6f99d5026bc386f86a2eecd0c276494878104f000000000000000000000000000000001320a402922f2a0bb287464854be6782046dd9dae4c0cd94efcb8ad8e0f37b7889bc97a3c8b4d3b3670a6924c8ee23ec00000000000000000000000000000000101fa8bb2c90b755bfba9cd7a98790b7bea2ede4c806fbd9f2006d10cf87c44172d4ba46ea40fb75afbbaa2abc3b6e9d7603824b834a83c1c408243b51cd2c2d31e2ee763d69e2ad6d369bb6aa2396fd0000000000000000000000000000000003285cb099b04b6acd333c7ac76c839b6c09388792d5fa1f2af0821e49dfbf40a06803c4cca92512bb76d073129a48a00000000000000000000000000000000005b2fdbb25381b3b67814bf6cc0a4cc17271416d16ee369b723b1711d968c355b755183f0bce519709723250515ba32a0000000000000000000000000000000002c7062ba4f642b95e028a364b0698b801f48af3c336fa09d13d83ec6cff10d210b55b23cad1d999889c83df7d1ab7e10000000000000000000000000000000012cdfdc10bf46097083294259754453e084010f7ee928cf540d44c80aa4f601247223a318700bc24114e7603922d15ae923c86e91c48582f19409b962be361da5936db02b6862eefc288f9a32d5f54760000000000000000000000000000000000669d760352e34a407aef8e141fcaa9468257b12ec08ec218f49f0769f3acd5068c6dc9d251a1b2af02a2d091f8ad0000000000000000000000000000000000064a7b4026ee3115cb730e56c4b9bf3e1527dd0f0ac6015f43d30a2f3d8d8c2659cf50247e70ca3c93d7e0a404d9faaa000000000000000000000000000000000979ca2e81663ed61486c1f841c19d83549388d798da72feda82283406d4964bc9991f876a6032382c35b605441ee7da0000000000000000000000000000000008d92cf77b44c516c243f3e6a8a8d3f9d3d7405820ab972338f700de1dd9a66d33b4a70540a30f630aa81fe1cb5bf057e1b3071b561a80aaaadb5cc24b348a2b6012340d3aebcca7e2f56983a8a13bf900000000000000000000000000000000198831a40fec54a210a63f5e00b132bb1eca6408335b85a75e28be6a111beea3b99d9f2fe5091ab0eba0f082c201c14d000000000000000000000000000000000fe457f8d215f390000efbb7fe7193ba02a2ef78e9bff6539995f01604fdca9fa3c010276afb90215890f5a5df3ae21500000000000000000000000000000000076771823180422495d89c301443a9d1fa141716e5e27205b8cb6b461a3ded7e6f196c3976cd6ad56b2e6ebb6b3a70860000000000000000000000000000000007f666efc677f6f767828e1291bde0ba0ca445ddb2d69d5d2fa090ca49e697ce4e00f55d2b706454be6d68f012d76efbb6863b755d3dee61328a60f585531c436663bbeab9afaffac49b6f0b57614eaa", "Expected": "000000000000000000000000000000000e1268a5e2f654c4038647a910e6cb4bab1d6ca3562ad4a9ac18444c8b8a3fdfbd35acf37f9203041fd587a5175ce86d0000000000000000000000000000000005e701a8ddd15ecb0231b7625f7868c81467c140b2617e60440a9b348a192e5248b1b3c087545cfb6d173fafe48d32f600000000000000000000000000000000071327f52b1325bb664d32c513fb12afb96dd8da23dd91bc4c3e8ae5f97d6bf673a5d03bb8bdeb6da3144dedac200dbd000000000000000000000000000000001852b86d3ef45aaeb691f454a345ed61104cecf0f444e4d841f2bc0402ea1291ef056eddb3fc3929ef4623f31016c3b5", "Name": "matter_g2_multiexp_78", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000fcd3f253d018ef09a7c6e8f36662ab4190867a197e0c42a0b425dfb5fe61d57596ada28dde0b093676ce15d03406d20000000000000000000000000000000000df00598337060d603607f3b8dd16f277ce1882a2e9ced48e1944662323efc29b33c807653f31583a5d2198426019ba70000000000000000000000000000000009876c81a76986435d34c6d44d51cf1016c19ceed2432ef1e68decd64da2e31e42372c1a41a514b0eac0ac103ab6f43800000000000000000000000000000000121cf298ff8f610c64ca4a887c52cbe940333506ef2afecffe266b5b585ff737395e2c64adc23b5bd232250e67c7a62613ca0cfc742607bee58988df361d7cd5d809ba4fddb209c898cd555369fff566000000000000000000000000000000001885d5cdc3e0e0c8cffa7519e6914e5d85962d07633970c4174ae4587853f13970a1f5d7ccba97458b9b5046847ad29800000000000000000000000000000000105b7c0ba96d5ce32d7447351ded3e3f491a0e741e921447b91f22a23b64c2d749055a0593e5b47f0ff7815e1a4c9943000000000000000000000000000000000cb88fc10c94642ae7e1d7275bbfd51a2d40e9b29f3d51a1ceda577beeb131eae4b17418f9f358d47b4b9c9ca4960a3b00000000000000000000000000000000131a3e080b1d4e936d97d255b07b09a6210b5fe6900da87b5cc595a72de2b6ddb01809e2dc63ad460a2926dd8d3b3b2ebcca8ab454fbc576a2b910f140b23c23b14301c19e1f47989d78eeecf279862a00000000000000000000000000000000066b31c0bc4b3b9fe420dc095d551903a2859556d86e210c96480f1d31d449d85ea292e2432babdb71c151c7b215cd6b0000000000000000000000000000000019d79a60793957745077f9233aee7a4f096515eefa7c49473f09bbc73fa0ee13a2a30a08bd7f3bc1d5c412d671fc37ff00000000000000000000000000000000006882160e4fa8ae2c2d48ae389d8f023e2775adb7a815edeba13728b8f6b343c45788c8e9116445e9989e01eb43e1500000000000000000000000000000000000ce53ab2d81ebaf4a85b3e12a6175ad7fb6cfbae207a69a0fe2195ab916fcb582b097f09d9fc565b837925f68855c4b59f82ceeb6160d3256228d7a41fb3caa6f305b23142ab979e728356a13309e27000000000000000000000000000000000a30d335c035afe459dc262fb1bd24dc0bafbc08fae0bed47e4e204280eb96595fada9c4332df1218748921bfb1274c7000000000000000000000000000000000e37eb189560211d6fe56faa3b6e710878a21907fdc1a9f8becabca290c24b8831e28ebb48d06bd822300fd09b4d103100000000000000000000000000000000104842b88b9df6a7b8243494eb11eb62c89d1ccbde9f55fe221c2366d6bc9149178f177628c6fe7c7661318640295e570000000000000000000000000000000011df8599d72b85ade11261076e02c036be5dfa3b6fab4ff72ed7413a879c0a0742be6c36a32d0829a4e3171b0341c6a3995f7d2038ad02deddca34399e5b5653fa471d998c52bd52241840cdb9202b2c0000000000000000000000000000000019f6634435be45b099cc739fe5c2dfa01f61fd2d466d5ea464053e2d5acf2e0e9448b1bb7770b5ad426f8a872c5764400000000000000000000000000000000002bbd52efecb10b3bb6f8bd04a5751042d8598cc34e2837184cea2b5953ec125dee871d1f2f57ebc84849e3a7ee5abe2000000000000000000000000000000001962b716342df9c13c21d89ab5b8c4c0ca191440fa709627e0f240a7ba518f4c95adfc5973b6ed0af591bb54bd00937f00000000000000000000000000000000089eec676276c52bfbb2593ef0362c12a5f3c1a0566d5aa862f5f5ba1580f4dadb36c15fdcf0c3910ee14487ff146c8997b67e68bfe2d7fc256e6aa610dd91dc1b02c64186d24702ad8fa9f715b582a5000000000000000000000000000000001556d081a489eba4fbb0c20e22b8cab432a9f6ff459ab9b0e7ceacbbd46c8e24a2ee70151b019a1b4bfe47d934afede30000000000000000000000000000000008fdd7391113e8d9865ef48b60acf921b17c50744e6ad62fa24abaae54836b3d59a7441371bdfdcdb251d252a43aed7b000000000000000000000000000000000cc66cdb1fe32beb91b05922f3920060e7a95467381d62f2f036e6268af4128c9516780ea53e873993744ce932b901f100000000000000000000000000000000151f94dec958859ecaeb810c4b1cc7a707d0e1671cd4a1e3c811910bc8b95c6c944167dd280c7fed22f92ce7650beef998115b9f84e3ed6947bd6f0e3c65361cf360a65bc059515da852a72ec5cd178100000000000000000000000000000000004f88568c7ede48d7476175f1d2e7ded4312c24934f0d47794705621f8aa8a5072b86cc41e187f4aeeb49bff17a4c9d000000000000000000000000000000000ca6c579e86a68b4041150fbbc36da744d359028993681c34e66c537eb8a0a0d55aeb9b8da7fecb844104dabeb507805000000000000000000000000000000000fec63c57d3d3ca98cd1735b2f59217e163ca53b07b4fabc4415b98377d87e75f0fcc9b51c99a57ff61ca8d0016a206d000000000000000000000000000000000940e9f93f3ccbe74c7be93236a2c440b213a014ed51cb57fa053495c3d6f6c8edc08ba8e10be26e5faa898162d67fe327370e1037b709015e0bf178a41ac55774a813368e11ef7a764eb48abe75dbf500000000000000000000000000000000055e4dd9da22201b5eb64e3b9eff2eab614c48450424491a85c18e05f50659b88e862490edd11ff980b06696b60c35b00000000000000000000000000000000018fab38f58d3d541666bc29b9e94cb3940f1794b2aa851d079b9aaa1cf742b07cd6dc7c985c7e4d7d3fe683bb15d618e000000000000000000000000000000000534de5e1c1181e951b437fd17993e995fd4aa2f6b28fc3612cd4db615de742e12d66c03b9ced538c1c7cde27752c190000000000000000000000000000000000aa8580f1da71f2ae9ec26f3b6466813a40ba5bd3f89ed0d42695d420032540194617fcc2f13e36219fc0cc3886a69c36bf5fb297948e0ddc60ba26e49ef2892ca008e64a22ff2bb21ff70c56112f710000000000000000000000000000000001804ed7677fa3842bdc3eba708bf4fb7f7d4eaf2f1a46193c861595f64196398622df4358b9526f33663138b24fef1310000000000000000000000000000000011fdd7e1d0c5adfbbbaa69ce63c7c54525091289e4dfdfb3de772a8d5a958581cc23933deadcb8856540e2d0dc564dbc0000000000000000000000000000000013fcf17235506fb194e3adaab881c7aba4b87e5aef739e0547b858410e3cdbff0dab1980b1b30a7d03d617179ae545c900000000000000000000000000000000004eed0ca479cc458231ff969ebdd4e33732953e9f5610d78d4753b99c5f8cf73c742387b8e71b9be074fcc67acd71cf6b488b6b63cb8bf34efeedd9f95dff4d3d8c067c0d807bd1e20bd267748275d0000000000000000000000000000000001082b7796d35e387df689bcdda6e0316d343dc907822d1a873adea050374962b164ed27cea0e1b834997f8274e4c5438000000000000000000000000000000000b1905979a90c7a61f4ee2cf3a9f4d6ed4c724c9e216981b8ec34fb9b528018d237771ad620020efc2c3cb104df667cd000000000000000000000000000000000752663e72390108288ef4de3c3ea409c74e7051505b12083c41a2e8937eaadbd8cd61f96f7991722226fdd02dd8d252000000000000000000000000000000000f8e4eb7a3c78b8040a115c42b5d2fc69405f8334e948b8553f444dfef29bf3920892da431cd8394cf61f24e356e95694f661845e91de1c09f581c7612a25bfa0889f77c2add31b493b37d20bcce11070000000000000000000000000000000010884516bb9916084709351ed8768c6105fa451e08d5acb233511254ddbf4e72baf9c43b56b4d7dd129a38f5b34ee5f0000000000000000000000000000000000228fc5fffef746419cc69abb17cdc63ded44892b8c5d02f0c72bc8506a61d15a74ec4ea0e1d78f555ddec07f418539500000000000000000000000000000000048a4192c204b7441e871076d91d4f610c347c2d71cf495ffcb2e2ab808a8c1a549eae96e657d756d9a3b94db2892a2f0000000000000000000000000000000017a94d2472df89104ed96e24d166f922bb852b5ad80f80188fce65b08d39cc3ecf94991c6bec5dc12f9337e7c087db2f8b3bf8d5e529912b1b6e445f592a6d151c6f5d01d3b021a31a2669df4ce02aa3000000000000000000000000000000000f6293fb0e19ec85f43a1a02df9f59ad4fb0e49b16a216ce097b8ec59e781fdf176360d8492e8b77674ae2c0ddb1da70000000000000000000000000000000000e354d09aad68fce6cde40c787ba1e4488999d5b9f3fec25c9994b56bcccaaa746c958bd16ba271485f461b0d4e983200000000000000000000000000000000014fca0851b0bfdf2c69fb346f23b46135d2b7914bb49e297a0c1304d8c2851ff6bd0a0bb364938dd44680fe86cfe12e300000000000000000000000000000000164e23a53103dfa332e5ae09c7c898b95773c20f019d8b794a6b49594040e2e090db6a8047c943885dca95188e89a63b30e1c8f222019b877e66df0b6201b5bfc5b6c10aae340c55e74410a536ffb9b200000000000000000000000000000000146d37241ce4f71017e4423dd0bf907a12c1364ae9fc6dfe535c25e5e99e03ce157cbba2675829b396a69f92668107280000000000000000000000000000000000d5a992f5357615f436d95fa516212812f6811dd1f1921ba4129e84e3d487b6c97520995d8a65f6771dbba9d150c7ab0000000000000000000000000000000007b01f86574a9cb7eb3b9a19b6040055a5c11b13e7071078d16b9ad71f714ed28ad25db9511964b156ee34db22385cdf00000000000000000000000000000000154c29c6e2b21a75b14159b183e625c98a04be1850b22d314225e94b313619f641ead73130c1d6feb85abd8c9e172f6323a258d66f2296fa1c71065cf23c994eb8c6c35d35120d16790fec791ad215fe00000000000000000000000000000000075be2703b8416fa07a7cb6ae8841dcab1e36b0ea24231dba617a2fed3bebf8d952d31f68c149dd17eed136fe37b01880000000000000000000000000000000001156563f1401b731cc23c4be59e69b0e6a0827df4889cd9ef9e11310f679c1603a0d9c9679c29b8dab75ae51f49bfe3000000000000000000000000000000000663faacfaa92fbc095a5dd6b1f2dd141e248f84eff1716ee71bdffd4d28ef1f4c88828e3457e8ebf0daba1416d2d6070000000000000000000000000000000018f2871f5897aad9ff6ac45a9c0e78be8f312f07af5f1dab2bc4705558070abf367f1782af896288a7754da82bf1a5141ef4055b85f37b548dac2b64608d99ca293548bebe1e24355393520c34eda60a0000000000000000000000000000000001618a284286899f501f46c4761c93b68bc8ab3157144e4013e242e1678cba20a2d978ab53b4b43145dd6062748df541000000000000000000000000000000000c25da737368775e41ddcd9c64cf99a824afacb1d404f1ef46ec7fe4ffd89673648c5207551914e6e0d12c57e7d7682c00000000000000000000000000000000097ff49c4872e2da1f6c24fd6dd4667f0bef4eb30fc197d13e8b66adc425e39841dea011d79e4d775106a19ea1978f4c00000000000000000000000000000000147426b7d9b0bdc2be051d8f6cc4249014e1bbc2369bc32eca94684483f50ced2c07be6a320effddcc1ed5cae455fc92212529248c51c95b5b26961f27e6d44ef1c2b9233bb2ed32c3eee79ca6c6eb750000000000000000000000000000000000cf68f7ab056c4689af95b361ee3e3b1c1c48f18b5aa655cce1a2be217010814b3f07dedf6f9a7b835cb13e2afd7136000000000000000000000000000000000dd6d0fb94048dab34410dba4e682f020ed54a655099fbb6f6e94a31511960f0447d7e94143eea88195291b225d11246000000000000000000000000000000001864c6ad3f2f794239a179647d68734e23b3520b79952bda20acf2f5afe1b76bc18e35b852d35a5cf3b02a3ce86f640700000000000000000000000000000000015ea24562d7bc59d813b77b2a4943f9e98842b5a41c0c7026077a02ddfd3d5fecf352d4399f507fb12ada4ac495ddece9888dd839d9b8c236394c44d358f452a4588ae65d24ffe2bd345fc745de9d37", "Expected": "00000000000000000000000000000000080f0e50f90e001a442965ba7900997fcc89246742590b99add6d90428d3b61516664654bc8fb423f701e85a342a668100000000000000000000000000000000003fa9e84ddd754047649b7cfcf5bd78852abb298b3bbe6575c4c7dbc2e7595499a9f42f379a2463aa74f29e5c73a9040000000000000000000000000000000009e72d3c418726f6400b8cd8b9b649005f3b25ade40cd6f77a0c3cbdbef461e917d4453c9e07ded45301d21df4ec44db0000000000000000000000000000000015a06cac223217602ccfba4f4586cb184994bf08b324bf977dbb3884c394aed0622da7dcf5712970554d73b18e2733c5", "Name": "matter_g2_multiexp_79", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000007340f432a5cd5aff1a1d98c6ea1c94be24de2d15a4e112925586c30979e23a5db93643308d3299e370b1f26bdd09eac00000000000000000000000000000000155027caae88381a60af71b2fa770e58efccfbb7642f5ef6b1591bf77e415eb117ab564aff8d9ebcd576f813b793ad2c000000000000000000000000000000000f604238d1b28f010ce8e45f2fe61d3ea20b902a4debbabcd54ce0ecd44a9540fe2bfe847178656fef0a5fd7e6d012b3000000000000000000000000000000000d7f503ede395dfa5682aadedc98bfe28d3fbfb52f42ecabc9eebc0e0a6616d3671604709f28255f50b62bee641d2711f812322dc2a7d5faa9e4877638faf8492d84e0f4c4c65ca3aadcb7eafed2106400000000000000000000000000000000176e1f9eac4dab0d253c0ff41b7600437b53a5ac5278d544a9620648e0bc4dc56aff0bda973fd1338f77fa174d8b13b90000000000000000000000000000000012919a18343cc166e2dfb92ff07bbf838779ef0479985bb85b3b82f9d0632b3f7a19d387f725a21729a77c58dd4d1d1d0000000000000000000000000000000017eb269ed75fe0403021ce70505bb60a711c91c551931605bb2a0773fafa07aeb47cdda382c0aa64f40f5e6e0e6bc77d000000000000000000000000000000000bed8ca999a4691646124a140fcc17dec02b74bd28b599c807abcaaff13bff65aff3892897652cd33b4ba5e4cc0198a9c1f6d538c5b4ae15c84581f8fd4c61160ed395816557fde197e1a013ba41ba0f000000000000000000000000000000001344d6902f5fdbb59a4c975847db0191beac284eb17cd92360e59f42cd7796cf2aa282bbd4cb074c4ee10b489ee3f2f60000000000000000000000000000000002158eb3429d0532792532fcceecc404e95a879be68b3685ae94016ca3762438b3320553ab6d5fbda3a0b615a04d996f00000000000000000000000000000000118f6fd8f60edf7088a0b4b49338bfcfc9c38be230460d7516f317b27c07600f504c8cc87acb0c95515c3acdc1b125ce0000000000000000000000000000000014eb422d44ec6931ac9860a6a017a907e8ed76de91bb7557e818dbacb19fb51457a1f45cca91f1d1d75a3567a3375b5cf2f6a4713eb692f7667fba2a3dc35363c3ba163519d95757daddefae11a95853000000000000000000000000000000000f2c72c53fdb1b0cd13a1f20407c64c46e4a0e461778b0e2d48c4f20be7c655c639b38f758fa9199b8395f706df10e7a0000000000000000000000000000000016e6c75cdfbc20c5dbc2dbd1caa66be92911264d407ce3c689ef3ae1dca44dffacb4c0d8a78ac959e47ac5c454f607bc0000000000000000000000000000000011c5d80d52e864b0a46fb48488f497fb85f51ac040c77b1d01336860b972858c0a6e59914112f6cd6c1612c604d26f56000000000000000000000000000000001136aa7eb63d6f85d665d0539975a9a51a9a3f5bd8731910c32130b1ec8b07c39eb42e4f61e7d22bed933d9fce1810581022e50c3fe7b2a65aab79de6d9e47c457d197e145592dd0611b1dc39941513b000000000000000000000000000000001306612f5119d33f177b8804443d14d04c8e059e28f63aa10ac6a1b25975327f378d5d24f0236e05849f07e99af93ae20000000000000000000000000000000017340f8887292264d498f84fce4af83573aa6cf1d57d99d364f2b84e1734fa4f9a1e07ddc81a2135ad5f5e0ed2989585000000000000000000000000000000000f65073250019ea69339379aacbeae7520c1ae10c8912ff827b702bdab2e15404cfc939389587364d811054b7d9f2b350000000000000000000000000000000019742f83ba0c9d36aa1d595fcedc3cdfa6c6f08579e66b8956fb32ac03530114ed4266738c57175e7a10313c8dd42deab80011c7a4aa905d4db6d4f6ae46eac9eb8bb18613d4ac5e5567990d7e8fdd96000000000000000000000000000000000b2513f906db531d052e8e6f1cb8d7d3c41c7ec3158b370268d1de204ed8fe7618b64ae35029d1718153b5bdb8439dd90000000000000000000000000000000001664c367a2d4170f463c90351cb321608e2a49fca6f3258bf10d32c39747084cf9d2c38d5241888aaad97985cb09a450000000000000000000000000000000014de15b86461cda9f1be69f43a9ceadfe7b7d1548a206f3237d93c7c01ee554c4245fb73827ed0ab72b99a62215faeae000000000000000000000000000000000b25e458522be9fbdde4554b1a0d9af157aeb7d3ec1f89185b193c0429125dafa554d7a531ef9502d443a26112b940b8f397789685a736375ead2312874174795586e12b230669a90d072fa636128c7d0000000000000000000000000000000006862c0b0e3d7bc4507bea1df82080745aff21b7549b372085776be2f88aedd4cff00ab8258aa21e63340963bd0d937b0000000000000000000000000000000017199c5ec3a2dbc1f1e8d74648cf8da247e35cb07df22629b3845274d29e473819a31bc344f2a2bd6c790530cfcc0126000000000000000000000000000000000e7fd1ff41d86a02014229c5085c886988dfaddcb60f5c7c81063e8289aba846337d61bdde57e276fe6c65bdfb48751f0000000000000000000000000000000010efa6aaf7650edb0c74d30125e36cb67cffd1c7f57932d92ab4aaf36f8d9245d7c75dc2b3bc8f3f328589b16e26230e28e325fea39d61269c576626984f85ea43cd683b08c3ce111aac0005adda39c5000000000000000000000000000000000935de4b16f5f9c0accee77b5820cf36c24aad9953d40a2409b7e6040f09f85da7d2252843f9f8005316146caae539800000000000000000000000000000000008a8c542111951b32bb0b50f7631f8938d22e298193edffefa3e0f5c861ac8205ea9b865f9420ad74cd22b37c5cb56200000000000000000000000000000000012ddd660879a1f52ae6284e14f2ae6ea381ff3f321458cb76bfa566b04ae19f3793468d0aab652a82671be74332a3b7a0000000000000000000000000000000005eb148c35732f7ababc73861b71fe4ea5e25bcdd675e975fadd0a9e0fc54e175b2e39dcf0323f4a9802a68baecd25df3cfd9bc41303803a0b4edd121b818a126bece309dfee4133aa5314cb8a91d08d000000000000000000000000000000000bc351eebfd3f3c332268055af1655c8729cea44eaae803607198cf747280adc0d3dedba137828834af3e7179ccff4c3000000000000000000000000000000000d8a6cca17e1c6ceace7c0ab1333ba76ed6c3b114bf99ff80127c6a17eb0585bf6fcce871deb7385e9a8896a21c065ba0000000000000000000000000000000013222db97e31e28946adecda10c9ccc9aa9fce33e0aca51d6483d2f0c5bc3f33994ad516215f8333e22167164ef5459500000000000000000000000000000000144d3707b1898d35c65ae2c89b1570971a9494e8bd23df835f565059554eb7b5cb66a6eec890058316aef43d6c6ff55c8e08fed30e422868f37c422d1efdcc93912d55b0a731479af863dca4705e0c5000000000000000000000000000000000138da93a9a4948d41a6fc6d057a217faf5efad863b45ae8eab311360c033362213edb0ff90bad6c95f60b8e1131336e6000000000000000000000000000000000f41766d9b57b3210d315a2b8f90aabe591c1de6037ec79c0d72a283f0ac3094436bb97b82b7ad12ff4f471a41227bb50000000000000000000000000000000009aa4f5b674782b7adce6bf75ad676480f96a58d68dd7ef8d1fa488cfab794f06e7754e9315430189eed265913db8b300000000000000000000000000000000004e2a4a48f02079c0ed50c1daa91b1216af481a982c7aa64d8ba90449ed886cdeddd0cc08f1f8764f7f8c5988fe677f5674ecdf795b48d62f0db0f9cce057fe570d15c78f2eb7a77b66e4895a45804880000000000000000000000000000000019c927bbffd96aeb9342666e1974d30f9dc215e8eca41c24244c63c106331ddad20d64c79faf8c5baa45cd30b561e167000000000000000000000000000000000523f063de96c9b77bfe5c5045a007e155b45dbe68c5f1162884f1d942bb385bd34c2a37e5e67e6dae4a23d600d75d1f000000000000000000000000000000000c221006f5bfc8baf43826258d0588d7c0fc345d68de1add1693bb897959c2cfdbb9c165e82c0c787529cd7be85afbc50000000000000000000000000000000004218e3d52b42a4504611929f94024326f38e78bba2aba105db3ffb4a51f8906b060ce2302e22ded60714d652a234c1f288fc80d07393f629ef2732879332a253b49d26ca7b2bef7cc49ee40530b2b3400000000000000000000000000000000189e5063a36b0edd736bcd9f997f4b08c62d33b27560e2e2b7b40039e7c63b75757f23746e70a330110d975ca683941300000000000000000000000000000000013393485ae494b1f1467cac9a8840c695d619aa1a78c40674038c053f264c1e20481f2005abc7f0545346f5a982d05e0000000000000000000000000000000003f2be501504f4d37e12acdc54b3280671ca0762a063fd3bc04473ed5a051cae3767044c002b7ed1abe88b2143af08750000000000000000000000000000000009d5952af88514996336e1ff19409e3e4eb3079f6dea22f9738f4a331ce842b151e0b842b68cddc10a711afa6d3242b256e69f4ce8fbd8f86f546fd6d129f9760edce7c5e178dffaf987bf565e9bb7e9000000000000000000000000000000000a79444c673e630f46bbc5a9e06e8c023978a78e3c58d72910a04c3733ad873c0d0de61448076b2fd3764cc17d86d94f00000000000000000000000000000000110cfd215d67d4a091578203855fa0e85feb4dfd0076fbfad20bd092fb91b528a4117850955f5fb6568fc5844e17bbfc0000000000000000000000000000000012ece0577512182c50dbb4a485256e705410108d9ba9c8d57780d49e2e25a0f89ed1fe917797b902aafcb8f7d98fe931000000000000000000000000000000000217cf1dffac7ae162181d43ef12e3e88da4840f1573d7ffa271f64d8d54861099be37b644e96e650dc613975d8a00a4ab40e86212189e6f5925df810141c132eab20c123166cd8d3c6f40f5dcf1b1cd0000000000000000000000000000000010bec428b2865aa7c077c168dc28dc549481c6f8367a5b84cbbad661b0225cf0fda3e840d96c4e4efc36c20d48f23d5d000000000000000000000000000000000ded3a1e9e2eded0a11211a217f9355070361f0a5887a7e19c74edc8768000311cb9dd8513977ecfb45416cda0908cca000000000000000000000000000000000b99ffddc79e825f0b73f2d0229d66e51624d854d00bdee5aa7a884dcafa1888963e2a2149db0f6e40ce3c67941a391000000000000000000000000000000000147618970c71965684bdf0d6cbe1de189bd23bddb2b861c9636efdcb7a96dff27bb1ac70485b562e78485a1e8e56531cb96a5b6129c58113bca713e6905c026c0bfdb6d679c203cbe2b256b0a49ecece0000000000000000000000000000000001a402aba8fb28dd37f1be11fca037baa99a6b57188ccab66208a50bb6967dcacd1943cca73e34f6b2e2f72407103a73000000000000000000000000000000000c0bd64d043fa4e3ea566cb84f9139091891231ff500b67e5fd451805f79003f6303352a4f0c236063d60d9088fae88c0000000000000000000000000000000002861fa7d0222711ffcadac86e7b9e7b494f5561c22544bd0876fb6e1b2e680d0f7074c2800312cb233de2412ccbbc8600000000000000000000000000000000015945f0c83e738a17cb1283d08d63ecf12a7272bc62812006ed78254bfc45ca7c42306cb79bb16ed17bea600a4d62b5d9d8147c4453cdeed971242d316e350abead3dd08e93ee54738a4a5aed23affb0000000000000000000000000000000002268793f6872f7715d802c0d96f3b3d850249d8e70aaa97f19793d2c92e7cef384aaac603eb51525c7ceccdd0211fc40000000000000000000000000000000002507d680a2db16746810e966d1ba5547ac98d08c8402aed0859203e6dae0cbd87a9ddcc05119c1ca08fca2fd733882200000000000000000000000000000000192426b6438b2abc7386599afbe09081ed4908fbeb807a65bcb7c6676aa76e5e0c2c87612cd109cb124c73b9c8e0591a0000000000000000000000000000000017f125a2ef5246e7a19e1b2741b31b9224511ffefe63ccfffaef1b7949e88af573e267d6c7617ea97bbaee6d50eef67e1ba8e52986d3bb0421eb53b18ca8c21b9f7e631f16b99ec56748baeb541b32e5", "Expected": "0000000000000000000000000000000018c2f533f464f9768308a56209711cf9b6653e8d38591d782ae2374905f99f75c0d42c63af4b534056c28599a9da874400000000000000000000000000000000071d4d708f00875545f381e164f77183e14faab599e472b2857c15091254ddaf5c2e9df809875336f92ebcf5b7628da500000000000000000000000000000000099b207cf6ed022289c27393c32d0b83aed6c7b57323e746374c1a8e2ade071a5293168e72f7aab82f6c2e39b97b03830000000000000000000000000000000005dada01b4dfb6a52d998210a67ccedc11d6aca2405e0836280e2f7c8fd7c8dd271c815a2e9ea1dba6f1ab0d6e89d756", "Name": "matter_g2_multiexp_80", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000195d3f440857011bf9b764ff270b8ba1d9d13daf48933e49c12ea20d335b58bcbef1353d9698a7e795b4370ee385f12b000000000000000000000000000000000716c151efc6e611b5b15c749eaf02816a86e267428750741b167404a21116f2025d0d07c447b9c7bee8edcc2c7b76d30000000000000000000000000000000012ba0bf62b35327111d09b402db2b75b2e835cbe581638af2fdd6d06034774533e6501be3de84e7075e4184e11fd81a8000000000000000000000000000000000329b14859d004c146047b03870371f53936e078ddc69294ff1fd6f42cf2a354a921e5f2e5c125c454e20af97dcf769e7d39b55aadd47afa3cd35cb85a89e729ca236ada965b99f64ab302a84952babd00000000000000000000000000000000042286dd205ac86fdec3fee779059e2ad59adb62505f7b78606c128244b031c53dc40ebc2f5afdba348892d5ef4c10e7000000000000000000000000000000000f960010d4818846b3a0291c6fe1aa53bf0eafbc0e0968e3ee82324452a7c1a8041c06b4db9cd36a07c119c9fd2f9038000000000000000000000000000000001876da0dca72869708b8ff9ea0b74ad6be25ba82ccc76660246413a04344f2b72e5a7f6fddb58e9dc0bfaa6b33a5fadf000000000000000000000000000000001538ad1673f117493d998941d9356fb9907f70c279bde8ae8813b9c7b371344456f8e67cf02bf3401ee06d55604cadf9c41ece17a6d8b4a22994227b37a9d73e17a88859683afd5d226e113246e70cb1000000000000000000000000000000000d91319b4a5e047ffc8a68e10c34b2b90e7f3f08f9e3ec53ed12bba5f66c168c20c6583ba2016f0137caed834845f7470000000000000000000000000000000018d5542919674d2fc32430175405d806ae4abe3e1236df2188bf4c9ddf66c0974036e28414890212ff8dad244d11e3c700000000000000000000000000000000160b128f1ffeb97edf0e62dff85e3f90fa48567ab777a7937a2c0e4659df180fae4565107c2236a5f2808e42a03a4ab40000000000000000000000000000000003ee74d214ec491331fb9db8243e75570daba9feb587671496cea4b480d80ee162c6294c082203534bee450c384f645e69700dfa3b6e5fba735d1fec3b3adc90719ec301c406ac40673f4e5677da3227000000000000000000000000000000001951afa33800a366944c43bb42b8c5c8beb9ea2e1cead8b84e0f94af51e4a156d9454c0f08d1b13c692c41cc480fdefb00000000000000000000000000000000077f4543fadad6f2f8ae8d5d98f64965bf9626971e7efef5221cb4d95d51b8764324cf4a11d0ff5330d58df70cb79d92000000000000000000000000000000000417251cd0c1b32505377e51bb30ac8a8a3c059644b9ddb5a058b3c6e1110e1c71ee19f549b15090144dcf4668d0d50100000000000000000000000000000000052133be345adc562238c4ecbaf76ca4159fc11ff563ab393317b03065ab668e7df401831baf7027f0577f5791b1ca3019e8eed297661c06c92075629e163e80a08835254f7af8c0f179400be114ba7b00000000000000000000000000000000067bd52b7a3193d31a4f1ffb76432c8d4108442616f17056d310fbfee2ffaade9437e2bdb8425cf83233f0c632efc1170000000000000000000000000000000011b045d6eebe1bc8218b696b5e81e78db78eadf1b5d987060c1bdd73aa65666f77e1d6bb6f3d939d64cb3e6bda08994c0000000000000000000000000000000016eb5ea5067413b72632f5300efbe0d01a284b2a59b68d0333c269da9302bf0f0cdc923acb27e51bbbbc1d4086e6b06a000000000000000000000000000000000ff37b8812963d9efaa1e6deb5cfd34eec70620fdb65808739295a819e03ebcc8f501b8194d0b3c72717fc922b785194199ca6fb7f6df8a2e72971c5738ad75d84935e922587acf3a6b6debf3c37bb5e00000000000000000000000000000000149b5e0df255281c1b518427094cc0903fe89eac9a6dcdc379b8ca30f3696d89824c201601fc4b0795a3c859a82893170000000000000000000000000000000016ee9e7d957f439d078f3c5da98d114a1b5bc4da9c17e117e1f540dcbf83a349bba94def4b87b63247f190e3b5813cb00000000000000000000000000000000005d4f56bea105be4bf1fcaf4f25df30f85968d59e60b1c438c28ea0f480851f5ab9c05a7ca6677e6f12c7dd3ed67c2e0000000000000000000000000000000000dc0e87ca5a8b339b485ff3da2b9854a07e9663c43344dfb5ecf3ea055eadf67405c43013e15367fbaa55f1bd8e222f98159c6b98bce6ed31c30957280d8f7820e9376093d1ec9ac68ce0777d02b084b000000000000000000000000000000000b0575fe2adc9ad66209cb2191efc2946672e4e81b96d50493d2125d9c83165f0c4d3f714539eecef9de0706cc20da9b000000000000000000000000000000001511649f0cb6b86111d2830812231ad37df5500d7ce1086241591dc3cf40b30f1c53dda3133b2f7fff253c94d5eb98720000000000000000000000000000000005b15e4e32f4f4e46c1560792a9973f6ad63f5176694734f379375f16a08c162a4a820385d3ea6c191bd87fea4f5c8cb00000000000000000000000000000000089218403fef08dcc6e679b49a74557dafed3278d41ff36a9801db091b91de0d46d779a40574fa4a3f2baaa1a14be098ef1bc580e0b52b10b049f07d5115a60ba96d14a39e48ddee3c219f11c3b2a82a0000000000000000000000000000000001c35a3fdea92b28c9ab4bd9ea592b998853a73be844b9dcb500ed6704bbf3ca4ed4216dc24b50254b6ca75c4ca3e7fc000000000000000000000000000000001815292d2a365dd7f41ecf3f9a89e040bab717241cefb3155a097eb9885d64fa55f5de7023f2ecfd33f483ff304666520000000000000000000000000000000013df522c72805b890aef97864ec6769f569504fca2d6a6beae97f80dc92643f8014daf3dafc0040dd7b985c0d9b2c462000000000000000000000000000000001155ad4373a8304fa6301cf48b4ace135d6a0c08cb06d624f42f88073e43612ced3cc37235422171b43af2b4ebbd5662d06f6ed682c56611fd060ed2b3b1dc48974769ed6dc504ca3e0b9f68b77e63c5000000000000000000000000000000000bb9afedf7417ca31beb96486b024af13c06007585d785efd1e78444daa9bc3c03e1d64b560e8d6a18ccf77a8c3c8d05000000000000000000000000000000001652d3adcf1612e487a9ca198801afb9ec30267148502684c2b91c05ebf6c48e2ce33f9c0a986daab81d5359ec1b503c000000000000000000000000000000000baf3d34bf4a78e3b9dfa637c6392c7f4d7ad0ec315d10748784b5b60221bd9da0f4b75c57c139ac2db329e270d559de0000000000000000000000000000000000c30e553fa2324d552bdbc7d2dc86531340c4894495ee9a38b64f5bb6f92314021a2a00c4bcd8837e55a0ae2676a9b761d7b314ae9d9e78f628ec5a207d12e2dcb690688d256fe46e0affdfcc9775ae00000000000000000000000000000000159a1e4e87c35aaaeacdf21efbf8ed99fd6a2ddd7e990c12407b1417edaf185b8f1df9bafbddfaf3d581b5d97d7718300000000000000000000000000000000012239ef7b1e1009c81098aa4aaad8ee9e003530db5afd49867aec47f46d5e29d44b5e62d80d9e832937a299633e863c80000000000000000000000000000000016af6f74392461a9294d9f848508651ca5c0cb50494ee7c6a334bd770580b924a17beb7824b489e7e101ccd50aa0d5cf000000000000000000000000000000001912a0f54ba4fbecaa55c150ae93455e1db6b238c032fa7992bc8456f183c09b6005dd6398a77ab91cf547919ce7485b03a0c47621401fc20d2c78f7e30814de9a6f838d4328a5b5be628b833c31a6fd000000000000000000000000000000000cf1cf7a09a12f51d10059425042ef8e140718ff11d2f17897a0156034f73ed29496d93b8695cdf609280d319c9bb742000000000000000000000000000000000b2c4d26fa1eb72eed1a24f27229d2675e0c6f91e3a4eba7d34b0fc1bf5a9b4eb49c3492d9586669abaf25a656e1f95d0000000000000000000000000000000012c5c83a03087b2449b71e9037591fa265d710ff6d869bfa18ac37cbdcc93024f673128db3dbad9e3517501af12f2540000000000000000000000000000000000ffe5824245e43953e3d0adcd5fdc1a97ffc87f8c5473fdb0fed57000fd126a9925ba7415c698248c51c1f3e12b270d5e4ac6a5e740e073c5ef8af389e70c2cb8ee8c4c04c2ab4c48c579e83e181005b00000000000000000000000000000000036aa888e40882b2d6ac71d66c88543e32b4a0a7c959eec560e3d26114d8aeca63fd87dcbb3171622c989a6c7a204ac60000000000000000000000000000000006a5e552e6d2dc95ab8636a8be16bc79572b47860bb88934bf04c195ec01fd71eb91e45f24c58bc2812ed5fa10c8dd7d0000000000000000000000000000000015fa3ffcbd4e562a4bc29975cf8c1eedf442e37374fc87128e6f68bcdf6e996f6f054e0b8c608e651753de96655b2c100000000000000000000000000000000019bba7c0b170dfc1f8fdbf7a2e09ca0c4027a6aa6930d15dc2772a0f20e5e56f0d11644094dc866595f801ba5552e6c4c1e20d8003fec60f68c03942185fed934ebc197c2863174442d1a1c8d1424d31000000000000000000000000000000000341f46ec06a8def4f044328bcdaa308798469c767d10e5db34b0ffb6f550421c67c6fab7b63cbc7504e55847cee419e0000000000000000000000000000000006952e5f791c37dfebcfe69cdef196dff66563b29e94927e3ab34365773b93e72251a63af4ff294af88d45fe0899a2c3000000000000000000000000000000000874dfe75b31450e99dea063c090e32d24fbff9b681b64a9dca5f967f82003005b003d17eb869bd3b37d4a412bcb28fb0000000000000000000000000000000014203b69e8af4e25232777f503d5e82d6121256fafdff1b037f65d5aaad0f09ce882151d6bb4705328400f00089dcc7a7713ea72a2ee99442232472ab3dea9307a02fa1279129d994af5588af4fe7af4000000000000000000000000000000001403fa3f418107e0bf7f3f4bfcf621812d32b1b744ab5a4c37b5cf946a5e5dabd675c2b70bd355590a9883436c5e32dd00000000000000000000000000000000069e006f168bed4439fb46db9ba4f279f72ed608c12a05eed172608693f42cb1f04aaa54191f4b0b35f967bf03d0e63b0000000000000000000000000000000003f9ce029f6fe605802de64701ccdf52bf4aa299400a6e1c36f5a1f9173bc11a38e7628f123fdcae01d2b260f77c577c0000000000000000000000000000000009c9732809f60635115cb479c80457c6cd8dad092111d663c0cda0da1fa71c9bd6795ad013d2efaa4599c8ac5c88e5f26f128420cf6ab4616a05b287191105f25c7212f2c39c3230fa56bc27cd06ebfd00000000000000000000000000000000115e08d8e4dff7adcfe46a416625be0ac26ea2d7900f5fed497809a6d46e7faa5b47c52ab3bbeb9fb16d82b549707ed6000000000000000000000000000000000dd1b31446e44f64ea5046dca5174ae854f6bb5d95886fb95aa136d432f1a8c03ef1a5f9320f89c82f764049a7f678a40000000000000000000000000000000014879783c07e6986cd393fa1e0ca8a7e23b2c9efa595229fc0b6a11b9c232ba33e92962a1087fe2ba0532d7b541827900000000000000000000000000000000013dc6e2bdb2801333e7f914b99f30b40125fa1ebd49b141d88a8c090b15ec3250a13812a19c3c0751a4e5ed100a6f0ba12bacb3419c34369dbfd1c968334f76bc50885028758a975cc812a04e6feabd6000000000000000000000000000000000a2cceef36ec78dc702b6731dbaf8cea1dc2b41fee1b235673c6941729bc5631e69ff37900479391a4d10b300fbf3eb40000000000000000000000000000000002f4881fd626f4ac434bc1e59716e5e5ee14dcb9adca4d639ebc9d86e323d274ad8ec0a4b1e6ff92e1fe7928d48924b000000000000000000000000000000000174cac80e7bc63989f58759e123513b611e9849b44d43a362f2eb84421ad008f3ae9e9f0f233e49fc8e10c1824ba948200000000000000000000000000000000143641099c8a6c8153dc8ce74debe795dd6c4487e8234f164f9f8dcdea6a53619c04a8fac215421f985557b5b956c20a5b00f26af6f59620c7130a6d12cf2091b5f52a6b638484fc1f242dc1773be256", "Expected": "0000000000000000000000000000000009807ffe8fa881b235b1181d2d3f147dbe21042524fb0c0b4c90fb122d160c7b895034ab32e20324dfca564ca6e3183c0000000000000000000000000000000010f6da88525da3e86ee56cd5514a436e3ce4128e437a876be130a70c42444a05ac269326c84dca532ca2e546860027c00000000000000000000000000000000011396a7317918841ba171ea46bbddc9bb5a08db7c82b90008c6982b4b79a4dafc151081bbdb7b9fb79784e603e15eb9e00000000000000000000000000000000070b8580f303b83c643a484dd031b780ff4ca2ec805d8c538a0b0c791cc7f8163654f5e5a41776a8681500a6690e24a4", "Name": "matter_g2_multiexp_81", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f38906bd058e4d32403fc3d39fa57bf49c0da65ef42fb129332b91c184185de4f9f0bfe8908a44833ff4ac4d65b88180000000000000000000000000000000014ea6fffa6dc462463c15feace841697698bc521f608ed0d16be5097bf42aefcd1f73182f37b6279f989e9668a8076d1000000000000000000000000000000000f56d296323177ce53c6977fb60e445278e59ed1cf92e3f68c570eb7a9e5f8afbec5e2ef64674bbb54d7016c829f72750000000000000000000000000000000001b29012ff3460cbe4a07bdc65885718f217cf177866823a7cbeae18bda67f65913ea20bb69e0ffb31bd82f19862113dacc5a8ec806f2f273120457865582b08697904a2c6510bfe9ea21eaf682fa4fd000000000000000000000000000000000a4126bff91ada057ceb9a75d577120c7ac8c9ba62151602414364cf88a3e12dfac90b5590db3e40c16163177ad4e7520000000000000000000000000000000004a3768d326c4ebcd5ffed89341e8d04f89e674f3f2aded3205a7193e11c20115b3c4d595b959d6e39a03d76f6b5925b0000000000000000000000000000000006e0ae4a9c45bb69c3a1c65e26e4869f2eb18fefe584e4598ba99c0044e8d911145a5db3f57194ceb6201e7eab9a81b20000000000000000000000000000000005be2ba6b147f3f2052c4877c90ca364427c6721ab64dd35e89f14f3179564d8812b9013e3e3db22f69afd739229682b98c15a259b4dbb8c300a39f0af558a9827112f6b4c5eae3d43bbfe057eb113cf0000000000000000000000000000000004c36cf955fc81bdba4ea8d2ecf934adaa57fa4073199f77bd0428d3ef80a7d7102179d4a44ef0de887bcb3ae915408900000000000000000000000000000000138bd3ec7a1b6fb65d1df6bc1d2ada35aa52b06729c10b5d45b9bb7cbbdf41677942b99eb9c2d32e3e73da7d5f9cfed40000000000000000000000000000000000b0291ca10245e2f7a963fa07ec62b15f6bf9e7a5a7839840ebcbe538dfecaf2114c7864a16564a5b3c85c15d97fb7a000000000000000000000000000000000b436e912b8a71cf8050d10d59017eca6e494e5440f02d2816924ac9cc2034bedb1cce6eff5c42f3dc57a74cf1b51cc0a0e68bdc97fd642581f7e62ecf134df2c05570713c96fa733d3db96ace88f0f0000000000000000000000000000000000c105ac7475ed9517a0b07f25a030a5616952d817f3893181e352907c7cf4ec9f5f3006e37b1da97e9cae4a1213584e20000000000000000000000000000000002c112c18268934823d5946d2322d0faec497d8e18736da91d2af744d90f74136c49370a4b43952152c62820d25e52ee000000000000000000000000000000000fe2818a397d70543e752e7022f12bab10f1b1289cee61a0230d545296ec872e34d8df6edf7ce9980f3c153e6e51d96d000000000000000000000000000000000f479e6a52bfaab3a31aa9a461adbec8a390daa8eb6273f9e425eeed764a6dbad44d12778bb888aa5808df272edde401e5512cac411cd103fcd7497fdf47d1221999bcecdba30467f06ec356483484fe00000000000000000000000000000000016106cb42ffc41d5b23bc5b06001473bdfe556d375fac6a0cb0a12494e9c02ca2dd6133356846e1759a2c485faf5e890000000000000000000000000000000003cec25b0f5d1db0ead5319d6dd15517657d1fec442facda4335ae0bbeff606fa9caa6a4c00445001180aaeef895d7fd0000000000000000000000000000000016ce3573fbe27a8d23b3ebd22aec989d61fbd0e41a519c5e2f1d650f2ad73adcfc8c840fb12bce83b722a0cc69164e21000000000000000000000000000000001434d13d44fd8dcf776c2a045734dff7c09ded31c9e3a4b5e765cf26fbfea4cbb4ac15c06599012a7f2cd572bfafd78ba32f6861298bcfd4668653544b4551d7357d64f733365a5f08ebf297a09fd4ca0000000000000000000000000000000019923ffba0d08ebf1bd43393142d61022430356081c18e37804172082c7ace987ece2594f4852e84604a77235c7795e000000000000000000000000000000000123acf9e1a86846ae27d5fc0358afa34fe9d6b68232c9ebf2d47cc169779c4bd24f225ad30886fdf68166adfd9898abf000000000000000000000000000000000a6061d4cef29d1e3535d54a2e36373e2c16f91543f53e1aca94c4abdabc663049673f2327ea8bb574244d7f5c99e981000000000000000000000000000000000b1f3e1d43575a74584ec7a3280f8b7196f9b99b5e911ed33ba6bde1188c82d906f0f8e6fc2b285fefa0ce59116e449524301fc5c3ab842d7f6a278fcd32249f1daf86a31dd254ab9a21941fffca98a1000000000000000000000000000000000373d36dd0fac76a0fc46ba5da279ca3be5a1f8d799570004e429256787110d4fb746f65a8527d0ba681a81b9980bd5c00000000000000000000000000000000057933c2b3e482ae026159211c4742264f7e890efbaeb6e14f3bf66c80923289af095dc97b751a117e181ef917d049b000000000000000000000000000000000068816ad2369bb57b3430c657284858d3736c327284e7410b61ed444786bcb34a66db9c16aca583aa9722aa8d7975b440000000000000000000000000000000007fcd7dbc062d28f6ef906f6a455337e517e1d6e6c02c7c0b2b2685b79f56ca3436c1bfa0ab96e4a5eb0c2e2c321c0dc17a920aef58100de67c482ae1fabf7ec87cf3447bde1e19d9aaff825695706740000000000000000000000000000000007bb0ab060cc12002e043724c0fd0c8bad30e08b65ba9f2fe5d09d18cac4bb2d50e29ee14590ca7bfc505f3ee3d4f93d000000000000000000000000000000000e680653d29eb5d90f21802f543eac3102a1de6d2a5bc943a53dd9b80bdcaa6951ced2eae5e2a25448b40468f1923ebc000000000000000000000000000000000b7494b494019e3ef36d5c620ac56483fc6b1c8fe5c6f67537b19f56ef01db327812095fdf805d3dfe678a3ed8bb6226000000000000000000000000000000000291e5b98ecaf7aef0374647d28fb9f8785a64d9165de407d062403047da14d4ecd19fad8575070b278608e16b71d387d76d5eebc3d099448ce4a8ea6dec047b0f062c6361ddb9e95ec898442423a31800000000000000000000000000000000186536e3ae3edd9cc6bc24fda6589ed26e72e06121e97e1ead65b200fa0578c6e53d1154dc7b14e7eccc3a53237685060000000000000000000000000000000012fefaf6c76ae7197b99571e41a19b14846fc4499e8e964ff750e7c3ffef6ab3dc19eeb42c5f6ba44a573bca7a15166b000000000000000000000000000000000a135db813a44a21174cea3a0b34fb49f273877203ccb66bce44b2b58794818d8bc1df27544ecbf780823467e2e4ee6b0000000000000000000000000000000009b08f70cdf4e349e1a73935de9fb2ad9f4feb8cf5f835be78383fda2af94d81af253ebce08cef825764151d5713ae60cd4cc1453dec7ae335db989886fc0964ee73e12bab69ce1f1458d1416471176a0000000000000000000000000000000007976df2d47c14374e554401c4d3330bbf6f1e6b8fafcea1e1974af61e8ebf493dc0473d34b30b0b1cbee082550d85c200000000000000000000000000000000177cd64db8334dccb17fb207e467e5b09e891b05df7658d9b439e3cb72bf3e0a70e84f96fb5e448f33c003c279cb38d800000000000000000000000000000000094d739a02b8ea6ff8113019597f41df4728b270770edc5e68b1f5c32775f0c706e3f31c0a82059c1ee150b89097376a0000000000000000000000000000000006ed888aa4bdbee94ec67500e30d654071774fe22464dd5b900fdc17b445754293504b10d044aac8fa0c289f0b2d9dce6d207c08e51d64a9a47f5353faac77fbb184e1123d38e39bbada85534cbcd3150000000000000000000000000000000014a16b856b04ac4b687c79f2b4e1dd6d45db25b382e0ba6687afac648c9b6384cdcfa89812f1a726bb4d1c22ebaa6668000000000000000000000000000000000764088e337df6db30ce8aa23aefd91d9e35be911c9e89ac62a1e06c3d06e28efac256490400fac4490f595cd03c127e000000000000000000000000000000000894856fa1c8488fce182a9c7749f7953e6a73879b6e743fdb8c780275447122f512806fa83d5ad528f8f61598ed01d20000000000000000000000000000000002b33bfd09e0ff452c3336bde08df0102162488bc83c27052447a1e5d16c9c68bc529f96ee3787a26d2009f22a1246342e1910b704d39b6a64cc7a44e44ba3e8b7e64ddfa90dfa6b5ef571f9ff7d7f0b00000000000000000000000000000000133e2d092352d3ecef5b67a09c2be268fcd4fe1f7360a8ce3ef5f33bf689242961a140d9c8afcc1e2fab3ad4e3dba49d00000000000000000000000000000000101eb285f0c462a22406846d82ca6a278520b65132d2008b124f6647a642c221b0c3bbd4a0abe8af7417e7aefb81b5b20000000000000000000000000000000010958cbc317f1186aab69ac24be87647b8013b678b0eabc6270167bdc9c0cefbaf4d9a34dc41524b709f1b881e6bfa34000000000000000000000000000000000d92c47257fd0c4d6baa4c81efe65852840479b9bfda5cc06b253f167069ca7367924c0c67d6497a1e9abcce7d0ce9502eda0eb154d5f9b0e25a828c6f77541701004cd0293c61ae4d36aa3038d0f1840000000000000000000000000000000014ad0f935ba129b47ecaad63b9dda44e7ef7933f182a0f5226141c8f0ede026ca2f11db7f4924b5c582461688dad6359000000000000000000000000000000001453716381f13bf6ebf8fff2ed7bcb90f7beb44269008af5880a355dd03de5c84c14f5aaf69fda043b422aab0c694784000000000000000000000000000000000e983c9e9b799eccfdb56444d31948067d46adf275d7f39a70aaa8bfd0fe1b83632c23d87f4e993c8191901e9a607217000000000000000000000000000000000267c8b8c5e09b59277736caad12ec6986f206d1c1f48023356d8bc877a594c8bbd98981cec6382bf9bdb9a5fa38275ecaf6dcd51a851eb200c7f5fc3e106ac5ffc432f756b942b1b9a5dde31cb2a3760000000000000000000000000000000002e28c245e71a7f6206427ee512f3250612785ce29b369682fbf767d06ac08f91de8ac9f82951574cce46cee1aa757720000000000000000000000000000000019b0dc35eacd961e0ca7d54a0e37c4ace37eb0200d5489316f3371412717c57c8f17c1379721f4dd67b3fde24f50d4cd0000000000000000000000000000000013b9741f7a32e5e5b1ae5400e32dd6fcc1fd43b68df54ade57c934720b1289a51deae77b1726e1955b6430f37928e2bf000000000000000000000000000000000693980b347ed7ee6cd93f565c87efb36fb304d7e9ae24e2b9f902bfc962b6c7fbab93287147f5ac892db2a709c9ab42106d4a893a68b7fcb8be96faedef65181c239dc2cd752c85ae7800ca84fc2dfd000000000000000000000000000000000ad6b7cfc6cefa5783093b7d700360b354d0698d27ecefb7d5928ac5bd6c299e4001474d205cf3b85a32c600ddaf1a360000000000000000000000000000000017172c3d5acf59b70b340fc703e9b7801aeb4857ffbe7a9d5daa0f32ad80d1c0ef2f0b3b7d1fd83a757c076872425fc7000000000000000000000000000000001291f55fa7d14b14c578d57178cc707cabcdc4bfb444cecabda271cbfba2ab361947d045ed46d9edbd215fa4c8164e56000000000000000000000000000000000f64ed6c989eec5222239d888d08dfd638a0e35eff2266410dab0498941fcd1683654064107fb7e53b8c02fbe98a25622b9e1cfbf140f4a3b1d06be656ad6ee5169a9cfa7cbe6efbf8173843d406acd30000000000000000000000000000000001d25b5bfcedc6d7ff7e9fcf729f858759936235d23ad45b14dfd0229bf3e50fc68799d19ef019b36728285bf7ecd0b4000000000000000000000000000000000326e300ba07935e0233a03ac891f18dc7b5a9ad9a28264136228e9e23e8f2aa31b7f5e5f3cb3354984f57a868a5d00c000000000000000000000000000000000dc92060e3403df3a92b15ba3e437ef0c403fcfc9c3545e544a78874e5d9b5e63b9ba6060c29022fe2594c2e6fbb6a840000000000000000000000000000000006a01e85f59dc45b1501309a350137d71147c30fb70da6b7637a9b1dd884aeb7e554215474784ecd3bef18d15d2c0524dbc68f77d40330ad5b8cfcda42edf57899454571c6c6465c4107e662a269aeb5", "Expected": "000000000000000000000000000000000b7fc0b44723ff0d1cb7c43e470d4d432fc4bbc7f9d98ddb3d91434a5574956fdf15f898e579236426ea44677998665d00000000000000000000000000000000176586b6f157e408138391e3767d0c1c8457857f4cfae571267ed64ac86ff8a4b61a28b406e1caecffaae6a399f4ec9c000000000000000000000000000000000a420992f850db20d4f7d2ddff33e4dc79bc0c39caee533920c5d03d1c2619d8ced769ac09f664c0921829bd7edb446b0000000000000000000000000000000017e4000f4d03a6707174c3adb74966896bcc0eaabf4ff83cce92a666fbd13b59efa2c767442062b6c8b1a3abd604f0ac", "Name": "matter_g2_multiexp_82", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000016ac5146ffc26d1f0c33645931bddfb84756e1c7b03f4838467d1b6701ee9478ae03c910b6b4f5c14135487bd2c14bf8000000000000000000000000000000000e1d082f16e4d5c5f0b6fbe5178aef6f781a6fb165f775cf0cd4dd55f2b498a79edf373007113dcdf6b977a87e1fded2000000000000000000000000000000000bb94be280df1aed761651c0292f88037d172b675bae1933ec12323b947023b437d080aac9e196fe5e06e5c4137284d200000000000000000000000000000000064190f9725bfd5d56c31aef7fd1590c975e2ce549fa6d5c71b254851149e0a0dab0b9de3acfc2d64231c79bc0ebaa37ebb3c942d3a1a15cee806fdb0fc3635483743a5b0ee9c40a48700bad5da53ae70000000000000000000000000000000012199d02d3f1bd8c4005878c3302e6a731ea69d69accdd690b4667e847b079563d32e18eb7a440b8005ca936da5e73cf00000000000000000000000000000000125b0dbdb0058639513b007a84d3a3e6302f5d846f22f99a55181f097e200981d9013c00d688a11eb976120f1a5da64200000000000000000000000000000000081e723506635433528fe4a40fe4ecb8a9c3d8cd701c043c0418d149951651e21632cd85f03db33b89efadd69e009ebe000000000000000000000000000000000956af2e67f8ae676abc783c4ec9f85c50ea130410cee8216fe036cd0521b8ea38966288afe7d35c28b30f7ca5c6edc0c193d751c4f24f4808621979f07f03b2eabba75f08bb49682b9df2da7a85a7730000000000000000000000000000000003e11a4e9dfe82cb495e9e698b16c257ea3f4ecb24749751e7334e0f31fbd6677545e4bf9ff78a82853560f7e7ba2ae2000000000000000000000000000000000caea2c527cb3aeae427e92fc364365b1f55e7128a544009be2ff7a5236d1cf8ffd5a5cefc87820bff5bdf1c6bfa165d00000000000000000000000000000000064a3186774da8bb5d013debf46ccb0d894592c414f32de6f77da47f4d42b0c8a13a2ba4f14b9883d564fd8ff6a4c90200000000000000000000000000000000072f6c48b6a05039e3a4dfc6b73501d6d4ca7e840b119da9c074bd4cd2adf4f2c6e9e6325ebf6f97c3f0b00e6b9bfac6dee4eef524f133183b4af95e4445f3ee5084b96c32e284ebebc5b87f3d76150b0000000000000000000000000000000019ddf708ab31f6f6f725f0e4f65d11248d3a79af30927a6f2673901fef9819b189502cb952bd4742d2b8e84acebb5196000000000000000000000000000000000d928535c47eafa5da4ce4f91467fc31aff8b86b850e4582a597b334491b14da71763f9aedb15ed32856382069c094ce0000000000000000000000000000000004d6b3545d067aa0768cda9dc3cca0f58eb546345b96f7d6b9355d47770e00286d962a6b3a64ca2ce22fdb4834a4bb6e000000000000000000000000000000000f4ef9366d342b309076299816c1ed9b424b68886a5c69e21e785f97cb0f99ae3a99ff6b5244dab817094449048a7552da514f21c8eab0edb2405e673297bb595edc21027890ad680f1663fd960ce478000000000000000000000000000000000236c5b4c57ee4facec5d4ff37a478c505217af66e029c3382613442c58875c75cb423789f6703ff3c1c0d80991c9e3a0000000000000000000000000000000016c052de3336002f362d9b0cb386b800860527e0fe81a1a6df0ccde31f3265e6246191b3febd1ea48e9391c44593ab0700000000000000000000000000000000078dcb04ca93c676a9a924e59f924d9d3af872849bc30ca633d4025aecd981ba12e626337635ea77886a45f4da84104f00000000000000000000000000000000027df6394b195222bb8357bd684088e3e2a398f0fb0cb812ca5dcdcd1fa1279cfd03db62e0f8b2800d4b8b48238931656aeac9a669c962817c01069cffbd948d9d8ce764e92859f31fdaf85f5aefab77000000000000000000000000000000000485ce58b387083172102145fdb3e26c6ffca8b35af0e1d84ce9cbd89055be083bddd3da56443924049a056fdb2ef092000000000000000000000000000000000d998b234a69d584c78ed054b1322ceb33f73cafb5b23c1703a9fd609edcabd44f1a642802b9c0b6fde6a6828b50c1200000000000000000000000000000000019235ff13567bd007d77e4dfab139cd57dbb309a3cf6a6198a548c4e6915778094ddf2b05a91f5478169757bf5a56cb300000000000000000000000000000000110f6ea19a7f62bc3e78f4c5c1c6d3efdf1a7f563576e758218b2c363fff8ad8fab0e72431619e4ebc93d2d739fc786c40273bda92c9b1b677edd905d76d75875e5b77841befb2bcaf1fca7674dffd5a0000000000000000000000000000000001d45da76e3016c00fe65bb50f7067e4f06364ad8348184831c4932ea0e0f3a170ab5147e4670ee1b16924105b6fdb6f000000000000000000000000000000000b3468206db0613369b2b0750c98da65b660fc07c30cab4e459c311dab683b6b313b99ec0fbe92ba07f8aab43a12a2c9000000000000000000000000000000000f58a57c449a41105837d5e2419a34201cc921ec77408d6c0c7a2eb227be98ec1f6f6eb9fc088daa0d4c78928a1eacda000000000000000000000000000000000ba53b872dcb9fcabf35e673b467523ea77accfc1b38a5f92d7b9d269c28aa00d00b08d70eae6ed4d2e82bdb06008f9ab77e16276f9464fa2063230d6c1a4152553536c610062f18565c030e80b5cb540000000000000000000000000000000002b82e2b582b247271543117b939fd17ba8bdd617a223873296f7bd75de4790f0d5d8fe523792bc7fb4764d3739669d80000000000000000000000000000000006eb554347efc5f2ee79949bafc012e6d9964ce19459b3867865709d903fe3d11bc617f30f6279a9e62ea104565953600000000000000000000000000000000006a543fe5cfbae629fd3256575e3eb4e0b65864aad6c7f359e169038bf090ed9bd92fef32fe1ac20b2a8c90fbb6081690000000000000000000000000000000013ee42b0693b2f3b9b977fbae5c856e9e4c5e70120b5c29e0a9f898f6d04b7fe351e17b02716a44febcf0a00a9cdd9220be15b654ce22ae4e32987babc4863ffe2bd8a459d0f01f68fe84a75326889900000000000000000000000000000000001ae7368f84e354e5758554aa9c72ab4b00a644cfb9a4ecba38dc72227d297749bbc98c8f5d6149143b31442359d8013000000000000000000000000000000000abf087f77c79cb8c69e4289fae87b2ed483442daec3851a5ba32c43e342be29433b2deac6dbfa7a787547a7361ed0a00000000000000000000000000000000000fa01cff7aea64b649951a8d85fef0bd475f31e47c706b96ee2753df9987508b5e5456cc49e88ec3aad720a2535f6940000000000000000000000000000000018874d020e2eec0e286dce324b91f15b2a4f293d32956b27524f478983f0e0c5b43df802b60f4f001753f12d449cd821c8f1fe94bce21966427380b6d357a3599e9db03a7694159335ffba26fe29e4650000000000000000000000000000000018f7d19362e2cba91023455e115cd90f02aeafcb026349393ca4105e270ab1cf589621b40965fdc9795f66ea0f6a053100000000000000000000000000000000170ce0eb304e0e1047617b709c834b67a8989212e5bf1cbd5a33242be94bb141d5366e636c01a229943bead9a7baf43900000000000000000000000000000000077a17356b3b31faf90f709042938b9e901817f7379b7bd486d18e47d22b0430ba70fb3006e9afa67d7dac71ffaf152400000000000000000000000000000000064aca92c41561e195fa8239800c97d5242ff0f8ce76b0d119063e2ffa09c26e01d23d5728765a59bb9587e885450ad1c6d34471ed00035a484f97f4e8123d40ca23b017b94df65540a5551b905e57b3000000000000000000000000000000000876a57dc24ad58416f910ee3ce220630a1297e6bc691c908e6cc16f975b146872d71661bbb869361623c61670627eb0000000000000000000000000000000000760fc65097d215ab9aeb3d5a5153977e1e399e2cc0b0cb9befb0266d98ac13512a0eadaba4e051bf56794621c551ec60000000000000000000000000000000003c8e205e53075a96c14ec26345c75881a0d67c7ce0d62d73c83dc353cd7b555cde52ffc5659ab0db2179a899f0fd694000000000000000000000000000000000d7e8a7fe6b751f7f478698f4f0d30cd0a435a2295a958cabedf4668769819b4cbd4e8b7721eeb5ced3f913156abcaaff3abd467168bf5e57f71017b5779bdd400dbf416f34f105fe747ea2f8cf4a21000000000000000000000000000000000180546f697349adb2918129f4d0a979bb114d1b58e5baa6cc221a09d7083469bfaa61f80f1e3a6ccde0da54b24d59db70000000000000000000000000000000004074338380e3d7c0facbbc71d83e78b53191af9ba13ba0cba6015bf4f28e4b0b52ffb34c7867a335848f57b5ce5ef5200000000000000000000000000000000148a800ec38cfc2386497d9aacb4327d5953a6612cd4067ac13fb977046688e80032125d4b0e7cb49913e489796a50ea00000000000000000000000000000000132438d18d942e6dd3f69d117abf83c2fa18418e5145cc43b3cb8d18c873935e41279a9e13596f2863be7aeae9b73d172809801eb18d38a61ef8a80f13086d6b1f85ba751cdb8d17fbb9ad5f8d0f835c0000000000000000000000000000000018b3102ce91af86cd10162d3a43e488a0d7b7807dfb9624c3cae76f342e86f8ef1200444a57e2ed7f819828357a6dfe80000000000000000000000000000000017137b470f3c8d1a03e7252e18f4466c9ff809408cbb2043d6b226ae2746d890b267ce3255114b2e073eb66e93c55eb200000000000000000000000000000000054dc1c981c9166d0bd3a54064c33f15ab856b240770ed44adaf9f32d4429babcd0baf2c5b8a1ff80728e9c63e806cd3000000000000000000000000000000001897595f836342ab54bc2e1b72f433bfe3b5bc989727de48575abe89386aaad9b1549af3ca55f39feec14355b29dc9e33521c9cf035b094d754db994fce3161842a9509ec8288699680c0ac7761eac68000000000000000000000000000000000467f1a3093c72aba4c2d9e8171057cf88146eb32f38db0761a5ab2027f2213c89e12c67a338b4b342a73384109988d2000000000000000000000000000000000ab26c871d140c9c4e0512afe9fb576409ffdcb95417f8c6cdc0d964011dfb1e745045766bbbc08ff7dbd6935934bba300000000000000000000000000000000183488902b886200e63465098be87a905810b2e8ebe0364316da798e423dbb267743a0d2e3d93303623fb17df0e74ce30000000000000000000000000000000012c7e79f9ba36cc47762139d191e6625c850a03d5b6e0648032d1669575704c91e48a9ae432bb3553ec66e86e082de689c8c2998d141b9cd3a82507b6dd97e8d32e9e759169c575eb484e9a1559427da0000000000000000000000000000000012ef4988956e026a79e5e904ad3d7ca56793321d62cad46de3cbde8570be5f0ac86d386216152b37053741fe342de7c60000000000000000000000000000000014ff7804312754d23b251a42aea65207695d4df65cac4f87fc96cb920843c022f24cd27731224db751cfb621886249540000000000000000000000000000000006ea693105a1b2afc79dbf75504c256c519f927ea0d79ddd1997a49638a67151dc81b84473208e8078cf71d456f2de0c00000000000000000000000000000000122d367c147c91517679432d3c7b56f2d529d70040109f803b89a04fd8540a6c565354ae420e1bd4ad4ff61427332629dc83c1ea9e4f4fc12a7190e6c71c4f35d1a676d39e30fe688a05820dd989664000000000000000000000000000000000156e7f8f1412cec315eb76f10c92143157313b8eda0677a6c0236de5fd27e5660ec3eb7369f1604082c59e1aa5f94dd900000000000000000000000000000000018ca9f505a88ed2bf595fa9b55d2356748770af16b35bd5db448990b7d41c3aac53aa490791f7ac09d2f5a087f938f70000000000000000000000000000000017c76ca9ddfcc26b028928364ee35829c6e57fda40773a6bc0c259a1b3cdea715c664d7bd0340192aaf7dec7ad20a2ed00000000000000000000000000000000082a255966c4f9d0ad6bd3d88b136cb2cfca09ed6ae378c914c28ff3338a2cd466cafd839f3fff4a30b33ee56e684f4e00be1b9098f1873ce155a66899877c7b48ddda363ae1d2353cb3816f1ab15ef0", "Expected": "00000000000000000000000000000000075c71e21ce327a97024c8ab5fcbef4fff76260a4f8c8489167166c4a85d25096c617cceef73097a4bb956be3eae8b780000000000000000000000000000000016270f3ac86c0ec43b9472499c4d845eab488a34ad9e2148c72cbb1db13623c5dbbc8327c47ce596521bd1f54f119a660000000000000000000000000000000007ad4914ceda9fbc161121c818bd05953836a581dcdc78bebcd82ef548671c899581681c908a337618a445f77c6b7cf400000000000000000000000000000000173f401cb78024e844adcc88fcf0e52d32de134f6300216ea0da7747752ae3ddf4d181b8d266b53d1b699921f9871425", "Name": "matter_g2_multiexp_83", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017f40eea638a3d4fec417701c936d61c5b233c9d6b3e94ba9addd0fa0b20adf9f8e07c6b629977445c7750acfd18001c0000000000000000000000000000000005f1ca1ca9cf67c33e3ff174a65adfde2db62e74edf30b5b0156d6b9dc86dd619ad8863c055096685d611ac015ba884f0000000000000000000000000000000001683dc67710880b8af76b464291c17fb0ee4eff3f648ac0772f4a777025c8cda0342d8f5aae3123da7fac57b965685900000000000000000000000000000000143d919ce2cf00838b10fc65374e770bec3db8ecb17d2db08b6a10ac38657bb109f54c1b3040b661c3914ded6f7eb80fa9cbdaa0ddbf854861eac6621255b2102e5343666c735d0384049d5680d105d4000000000000000000000000000000000616299341f2921adf083d1190c212a7941bc0d9fee50b05b265f2e8c339fc3dd9f94607631f485e394f5a7d71ae73d00000000000000000000000000000000006b2f12e22369e8aff45b6c05a2bb72a706dc46a5d1393aaa9e5a7931ccff33a5df2967189114c3fc5dbf69d080e39dc000000000000000000000000000000000981e1b119d04343e075a80dfc189000b4cfb4e321575817aece6009e6b3a6233d1409e8e584f0ac9caaed1f43e40d7d0000000000000000000000000000000001ce4693e8c14032c35497e0f9a586a4541d8a1a68ad014b0850753a04215be2bb60cd7c2fa9be4f4f09a562d7b29f3892073d958260a55b70b580f3ee27c42553b5b858b66f6928fe74b4de91c34bda0000000000000000000000000000000012d634764207dd7a0201703f855365f7750291c810ff292b3e8dee682d7d8eebd6d6f3b3dc8b0c9e25bd2860e031311b0000000000000000000000000000000000eb0859d79fcdef546026fcd380f5c936e64a5665d73f56d92c03dfb50c534a00c857c86ec43275ce69cccc0b53137f000000000000000000000000000000000131bf000fd117ef722b33a1cebd28899fb012e1113f767d0ed46fdad82a32e4327b883fbe29abba1bb7ba3ecc1cbab2000000000000000000000000000000000e24ef1e44029366ae1daf06524d8beacb2b99f60f419cc2ec1a49013b79fb7a4781dbd37785f32ec67c0a28d61a3cea2117f11d78dfead915a94f11fa7e904a96204ddf1835d3501639b83cd5f716f500000000000000000000000000000000067b6eda41cb8da47a424a02a142e2b98b9c69e7023cf616040993f41507798882194229cb6572806e82e9e5eb837b37000000000000000000000000000000000e38693cddf130d3645fd60ade780db84fa700e5bfb74ebea49cc95ab001bde442f363b4e4c61f683b3e67f1ec8c2af80000000000000000000000000000000006d593005cbccc55c5e336e19aded70da65a7fe42b6a85070e491a4ae54e18ac213556a91d5d62786b6d4d1305525a76000000000000000000000000000000000ff86216f5388114dc06deffa7b52a273b22fe0bc8d50804b491fac83e13915c2dd1b8c2779a46b5c313c4e1c05eb2979087caa1e89e48f05bad1d720477199410941a6105f911d589e1f94a851e0715000000000000000000000000000000000262cf4727703fb227bd7fce6cd3f25c1897011ab892e79fa47446711d6867ca82b9b95f129f7ca24dcb60ac75173d4700000000000000000000000000000000136b5a304807e029d0a77b2ed505ee5c920248242f0f95aa07e9bc2e13d35f6f67451d028dc19d26095b55cdc2fae4fc000000000000000000000000000000000b511b2e19da7bfeb183f0aec91bc7db3e7c913f1c282e12d5d2f422a49e7fa78a5f35656dc9c980324717a5ad386dc30000000000000000000000000000000012eae443aae59fdf907bcfe3ee4366e252bb57e268fd569d742456f348429f009f67bf92f9dadd401104ccd2549cecc8255603b470c056b3dfb3acae0dd45bcb3d014765a5181760336deeabff3f00be0000000000000000000000000000000016a827938d8b98e3446445ce23f48a7ba0d634de826dd1ee3c71467eb57bd4c24e0d1b4190f47bd841183baceaa2593e0000000000000000000000000000000011d360e0c18b45ace82eaee902475127d8f18aa4a2ec2081a453f1c85ffe3c59c0f7016f966574a7c51bc14f1935568400000000000000000000000000000000186b5d452c6dcc1ddb4f47b07e01b6d64644f6d01cba8498c3059cc494a68bd25eef35cae05885b9f2689683e65161410000000000000000000000000000000000ff826e5a62affbfd6d2062bd329fcb561f287046870b8be461767759cb0d5f1ac904ecd1f136c5ccd784bc11088233e0eab0e2486316956291feb44de6389b20f8bafe9cc890d86d27a598bab0f3c4000000000000000000000000000000001010e75c52ed0acebe30fc588961c849b7b6298bb8d859f9a9401737c467921c5e3cda101cd4e38e4318233d12b6c7b9000000000000000000000000000000001884db518fbe4d621403ce00521878c0d419d8cf476a1dfda59b7d3c7af2bd91058bbbf54ac0c5cf9a217beb78e3f98e0000000000000000000000000000000001272cf0ad917738bba052e88baf88347d60f63f5b875d604cf0531c1ba7d43e868bc70a682b7274067106f611f08ae60000000000000000000000000000000006e3236f6a66bd37af4be230d4edda6eaaed661f206ca4852d3004b5f358f184d80be6af81c62e5bc8c88e7a1072fe21fb9436456262e5149d02b33a1078e198bbb681699b3f485625784df444bfff670000000000000000000000000000000004fd1e2fd0d28db08224fa7e880abb8c48dfd0e488df4d2ae5f6649f448193acbe943baf22af4b12fd763e3e4ddaa08d0000000000000000000000000000000008df68f276f356ade28500eeae3b755c9af9b5acac5f5f60827b5b2044b2405129b00e5271baf9a80847d3b720026b3a0000000000000000000000000000000005e683d1556f513e6d093704405f312687c3b9e2de3b2840fff32e88186c89b18d1ac558d960b1196594730a9bc107480000000000000000000000000000000018161f8d23c394d10ba576fb0ceee530ebb95a670f2589d84c0646f693086ecb7ed80e556f3ed9434d7fa488430ccf430e2724d3501e3d79b85266fd83a2a6156eeb48e749a61676a1c92ab9bdd6b8990000000000000000000000000000000017860708943449c2227c0f50cf1274652dd32e999d5f9b1a8d672feedde15e9f1af484a7b9462a62dd745bb6d3c7295a00000000000000000000000000000000064f8cb707494f82ffb6374641817a466af65f5c7d83cc2964e6cb8efd021e0c40934a3ffbb0d91bf8a7a616dbe8d220000000000000000000000000000000000eb37cc9d56fa0dbf050b557aaeec76f9f6d0a6c448ea298af78004e41ecd8a1df8fe8640e77cb76b593ee17658326ff00000000000000000000000000000000092ab597967544fda640b145edcb3ae6c3f027c2111dbc282ebdd48eb93287ae4729cb30e45c1c8999b3a45b099dbf0ca49344fe6ea9274a103f323f3d9381e91ae48233dd579944e12afdeaf854000f00000000000000000000000000000000124fa4d48ffc5732fb21d465b559e995891fef98370a1eb73c9264988f75caa93fc134fde7f93c794582ba5cbf6bc685000000000000000000000000000000000b71d012abc1558e49831f053757518643ae04f79234fa92023db9c5483bbd872d24eb87a78960f12930094c4f8fb70e000000000000000000000000000000000651cf0016efea086d98e5bda8e1959e20e4947e302eeb021d196897cffde3e2c28f783521b2a28b8de1ad1a131f5e67000000000000000000000000000000000555ff8a930cc11d320afc3e0635a6f93da1487a5764d56636be4e5803d740a73d84666f6141ed5ee6b778a463823fbeb44aeaf3ba8b03e7ef7201415de7365365b828f2c1a38d09153e51432d35b9a7000000000000000000000000000000000974e769869719f0ee30895df837cff50d47382461c557abc4b8806b04776f401b76a5e630a6ccbd3484980d03ff58d300000000000000000000000000000000098157f0190e6bacbf34c20310f6471166750ea1b235e46a5fae313f90dddc799f21548088322910bb0fd7e41beb23450000000000000000000000000000000007f00d7d18719db9d91e2c32f51083b42c4fcb43c38087f86879ad6bc99600d4c395586187d26d041ff49dbbe517fca2000000000000000000000000000000000510cea4a7463bc5882d0cc25fa967a0b02072627bd57f9a5863fe5255953732846d4907fa301789bf02af9c1b25211c53961d33104649cbfccecc7eaf33b7a2a486c77dca363ffc9fbc9ce4e8c1adff000000000000000000000000000000000bf264c0b7bf68c595b89453ebbd7fe2e64f4ae2c7268ad51f4578c35d48040277f3dac9021997af02e492039348efaa00000000000000000000000000000000083a4fea41cb1e02e5002259f5f7b335c81e15cca93cbc884dc1b08ee981c55f2dd3c0db1a35ac9907435edd7f0ba625000000000000000000000000000000001468e508a02ed7b61f752ac38313345338d2b2d018f719f391c0f3fa1dd1602d9476f3d8829720d17021a459a2732e96000000000000000000000000000000000629edb2530c38ead8717b289c08036c12630cd8c9ae875111749ed893b8cbce40bcaeaf13df4044147bb665ecc2319ea04e97c20b42dc265271740f27f1a833bc5b324bcb843a8f9f8a68231c663d57000000000000000000000000000000001635830ebf227be126e13c634a84f3649d498e0999ad2dc73b9c7360db120dc2216addfe18c00676ed185efa1e789d8c000000000000000000000000000000000471e3cfca449bde0ba2b1e2a5b63d53badcb34da3251313190a35daf694d70ba385976d1f875242386fc74ae0173d18000000000000000000000000000000000986cf3f1eef587bcc70f66f25c60f353e6b15bd105fde9254487e9b522159658d0fc6b6a8a3ea38c27865f1ea4d76490000000000000000000000000000000015a2eccb9c10bc273cb712ee04bef01a11e486bc6a4d220a0f653582af6ba1bac0b5108250626ddf126f16f4015c9d2cb688426bbe9ae054acb6c1fdd4195f8a113727f5617642a5b3c0c65566e22527000000000000000000000000000000001213cbd035615f09189171b3e22630d72df2df93fa8c14427bb00c34f5b55bc8d1b1a59404bed6549b582537a397eaab00000000000000000000000000000000161072d8ebec2841f0f34cb38a3e1b2094a597640a34178ee951e5c993646ecfc3a4c0dd753e7e76f3a6da5a091f9f7100000000000000000000000000000000077e9c95b6c6f726902392c3a16b5cc71cd9d4cec58c00eadca6091e45bc095e53006ce8ac8827565e867531013821950000000000000000000000000000000018cdf909bd9f38e57ee24c0f51a5f9f703eb3d190dfbf75be00969e9e8f8fee331cf32d93c3a956d12f374f8752c2c79cf365a86a8d08db5cd95f239a2f3d22279556975ecc3baae0b774b0323dbb1b6000000000000000000000000000000000cbc27995eaeef2bef14919d48a008a0b0467856f8a6659d6e68e47a2d9d41d217c5913aa1d67911325dbd4fc38e36eb0000000000000000000000000000000010639740654bad5c4ec93f2496f4dc54a7642bc92ed03372ad4edc5fedcdfcf37158d3f02279d4e15078e9d5a7f8b5df000000000000000000000000000000000155ff4d6dfa031b0cc2f57df41c1e1b1c81bf5a5cc1e3aa93920e93c2e2e7a71b56ac410a87855400025badf6dae8e60000000000000000000000000000000018e637da048e7e84b9d1654113978fb148a54d86e1d011d7f5a86cd4f1e5bc15abc5b67d00129f53c0c021cf933f399c528715199c9f47fd6337b6b0e807e230b1397885fded024431c70e453f55f3650000000000000000000000000000000015d8f6e47b8f07b3e07ae0952a7c8f79519ce2828e3e26b284b8f2fae7432b337de17089b5c32f0081ec6c6916f2f53f0000000000000000000000000000000010ecfcdb02cff772db667266cb3f99f1dc28004ffcadca7a9c64b3b5853c09b7793ca0aadb155257bd64fa7bccb390450000000000000000000000000000000011096a52f3272955947304ba037e8b3fce6b2f07f2352c08d5932f4d2306ca511a74dc044d0f0e1e260ff40b0fac5e0e00000000000000000000000000000000130facbe0c1c6d077e9dcab647a44b049a1aba3df500bf27d1c268f71a59635e702c9ee1bdd68fbfcff7ae5b3e6bd83bc32e8643f38f8177b788b8c2bdc25b668308d914fce35c6f9023a769334a51d1", "Expected": "000000000000000000000000000000000b47d58802579e662f34908a4060becd40434e4934ff58790df2a69a759223ca29f42e658ab475cb92bd9c46566811c7000000000000000000000000000000000091d3a4c58a669d3bf0377abfe28d1817168b2a86375928d95df3459c83334669a59aba95ab2b9957d5ded0bd8925910000000000000000000000000000000005aa9c3fe0067338675099ee32f93bc8a5e9ead94b120dfa391651da40cf1ef5ff79d193b0b14b5926f10660aca6c11500000000000000000000000000000000058200992b111461f4d737533301734a5c3731c9f2e7b55e18887ebff4d5b74dbbfd23773606f54cd6a930b85b89aabd", "Name": "matter_g2_multiexp_84", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000bc3eba5594666cec699a47fa13ee74722a80b4e5a1b28553de37c3163f2fdb8b801e35a19f6d99cd207d1642c0d4ad400000000000000000000000000000000104b334afeab36961824611f0fb58bcac55c9d36604ba73e9c8809085c019bd967cae7147c766df6565ddfcc0cd5fc9700000000000000000000000000000000026c3a6a4ace8638bf8ba7434b59c3aebd4bb274cbdcb898ec6a547b215f32d10395f3bb85a9eaecff5ef6d5ef2b50e000000000000000000000000000000000065bc419f9496b5e81ce72a13fc1bdce4738c2e3faacd80676be31db65ba3e7941ea75e370b6d6c0e7b2cdcce80a2fa14f8bfa3d47ed33a05fe3da738797f18ca5d5b8658055de5a9f85bafe6078f7fe000000000000000000000000000000000e7f1f5ead0f212439b4c47599581982712d2e6ba056f36cb04033ff5eebd81b5b41b874a78aeaa98562899418ab04c900000000000000000000000000000000095e45da9a4b2578cedd13af71e289d0067ecca1f09c014a294e0b250d1e8243ff98a9761030ac855a9d897cfe9fafdd00000000000000000000000000000000030b44b150d1337a3ed6a77f7b6332d7c8103da1aef0d445ff7467b4863e4c830fb782a81d01a6bf97e8d52bf333e78d0000000000000000000000000000000013bb76800375a45b847a96ef6edff3fc3c30e3d45bb4afe04230107f6a1802794e1dc23431797bc5e79e0d5ac6357eee4b0d302be94d437b8055586aa77ec1fe616e30552b4d7d3471ea219c148be069000000000000000000000000000000000602e0bd3d34415ddd517a73acaed5750dcfd68b633d51003edf79a169ad7a3ca2541d7a131c317c957a9597a753b5080000000000000000000000000000000007a964539081fff51e0ec24bb71257f6a1c513fb0047aad84b80180b22133246a1f62958ead75e4b2a68f973d17f1230000000000000000000000000000000000f48fe0f5b5a95e48bde4d8be1b2f352d748c1201b064bc88309a709b285f81260d4535d3e1dc7f1d6ee23ead35abd9f00000000000000000000000000000000135b480fc8a72248f7a4898fffc6c18b7f2f5b1af5cc3846610c299c8da252fb71190d9f761e037c6b47595bab6a03e56765d7f1079b142e513e604d577e7caf82cacae59fb98c6f8990522372dc906f0000000000000000000000000000000004773cd2884e52c2551c1ea0abb78fa17caacfffe13f18b75588484b8bfe781e623075bdf827fc82c6ed7e1d4d62081d0000000000000000000000000000000007e6023fc0e409bfc7d0b7ca65fa0e8d88bf1b4c202a8d1f0e1c3479b0963a646d16795fc5a128a54e624357050fed4000000000000000000000000000000000039f6eaaf99bcc9f4d8fb994a040af0d29c37960e9015d4e48466a9e554da30975c5534e76a1f08a55ed8ce7375b70100000000000000000000000000000000003d2b097d4afdde83a01cf2b4f9d12f77c8e92a8cadc225d40f974ccf385ae65bed1972a365d55e24231d58abed4395a2eeee02d9309af8c74c78e21836f4e6a7a6df5406617e2b4e9d300e37d8a2bfa00000000000000000000000000000000047b8c550310ae246e43b513d39e507f1dace7bcb543a49ae0854a397f62c408ae3632c94d172669ef3e013781796ecf000000000000000000000000000000001592914e260afaca80c0a240426c2828239ad5e256a707530f49cd65e9da2e4bb14a7d6d5978f52c04130a0d434cf4ca0000000000000000000000000000000006c0b8448ad87350db130373778d414deb738d3be97fba25c816826f59e3e926f44956c2e2056b7d769278cf56cf6fe0000000000000000000000000000000000a42d716fd83071bfa014a9b7af6c164d494f0347aed953bd2c1c97ade087a8bbea9f53c507fc0b22d520f28cc5d480cf8449caedd55f0a08825cc1a9e985201c8a7a54d1c4dd96f0ac54214743941810000000000000000000000000000000018026c9f6c86219d0be88955ce0afc3cb637b1c3a531aa2722c56816d368688181ef2fedf1525daec6d9b1651b71f27c000000000000000000000000000000000b40b15bb0621209bf9e33ebc27a7502d90fd3af62a1bb8f54a874a14c105df34ae34a43fc3805c1e4817ba30c048ac7000000000000000000000000000000000465262367e30ccc24632d39bf3af9cb160e97049d855176f665a185c138d5c529d11e53e56c65506e3e30be7b48c6730000000000000000000000000000000009485991319a311052d883b45911be12cf7648b5ca104ffe77594472f7047c803b8e9fb753b98645e630b9913bbc947e28ec5f9dc48931da70ba0cfa7251953e24c4c95cd019e00ac6fda095c1302a01000000000000000000000000000000000fcc0aca0d873cb8733ff7e2ea02b3736b737821af2db06ee6508e161f6159f9d944372c513a03cc4c9e30a707dca0930000000000000000000000000000000015c3774f4e0b30c9532beaa2f7f9b777f8d46bfd3888d6835f4a5a046153a98062efb17f78807fa17b3a995ce720c0b900000000000000000000000000000000083d48e01d2fb58244861a74a1261063f7d20b412c8a44f9945fbe373cb4b9a7ffd4c4ba4054ece0abddb6c14c013ceb00000000000000000000000000000000133c4976454b7be427c4c2ed437bc2e882854d2ddce42d2f97cd3fab1fcf60c3272aaa123a0cbecce1a774946bb7a8a0dc6046b43e6982f11f39412cbdef14f8e330d37fbe6dfa9ddf3656b86f4f60e7000000000000000000000000000000000f6ae7de1dba3b3030b208f61d182013231c4666f134b007b52d36bceb6f3cd77577be7b11abc097cf9618d351d61e270000000000000000000000000000000005803904e3e640e51900805f930638ddd8b86cc1bd50cbd32a142e10d85044cc52ff769bf1b40dcfb7269c913d00b01e000000000000000000000000000000000e6997b1f8bb649c56de5c4bf9968d19712abd22fb7dabee19e0aebd1b13adcd3e8b202975b4edc917d93adf087fb539000000000000000000000000000000000a32384fe03280962c5f575b47192e5ef3111fbbb0a01bda2db1e9733471f11eac0a37df8ae1a891de311770c482c06b0adf4625ec80149b7810767c985c2aa0187987b3649cab8c59a892404ff2aeb2000000000000000000000000000000000531fad86551ac6dee15fbd62cb13f38d8d5c89d23a031b9977f110efcf16501534757bc5b93f0250ff02d6cfdf2009a000000000000000000000000000000000e6d78343049a68514271fc785de053ed7f50a7774b87f264c42e03e6f8f86285477f8cc57ae066ef0fde237c8d1ddb30000000000000000000000000000000013e313484da4d6b85634c5306444bdbe45d7db823616d72821eb64a2bb5f352a4f7e4273fb6557039fa563ce1b091bea0000000000000000000000000000000009a40a984be66c3442fc8946cc42eca722187dd819be9ab34a9c3b4b0de7de3d5f126c175fe84c51a6f09e18623214f9345fd17367ecb06b29d764b22dc1e262ba1a339b6f0e0c77384245e3d41cda970000000000000000000000000000000008a76db551280cd43d4608e9fc629a021675bfdf9bc5a021546b92f3734acff1e97928850716b94d15b7dbcc4a1e0aee0000000000000000000000000000000000b2262872c268782e8f27ee8fefe0827d45131555e755c0a65a7c8b4185269bd621412b653348d7c1111d681f38d946000000000000000000000000000000000dabcf0f847045e01ef70ceaa32455f4c962e4657b840f97a1cff7cf5073cbf4ca8ea75a4887076f155e27e8d7406c95000000000000000000000000000000000a9c0ed94170eddfc485d9f1a770a8b493d4a59bd7156d6cd4b95b55bffa1b597ae9d6fbe529dc0833634d75906a4aba5ce5e62dd15958e6298cdf4a4e899e53644a48494d04fa6d1f73f2dbd645817c00000000000000000000000000000000170ac69c2bf9b48715f445524cab902b18ce6dea7b258481cc59986ae61c8fcb6708b1457be299a6e2f6f34dfd936fdb00000000000000000000000000000000107e855593b6f3bd2982a65167ecead47039065c9ae6e1bf963f81d441f0ebb411eec4b3ed1cff73044f68a4c114806a00000000000000000000000000000000063b470d158ebb4828e875c3dd0ca29a4fd2cd2af356233885a871cb5b77402090f29709c6d6a78f612c8ca4df2f4119000000000000000000000000000000000db75a60fa0b425b8cd2c955e21846ce3c407cb3f96c472cb412498143cc60212de0dfd0bf4de53ae3b345232180b4ad853396021d32530351deec5c266a65519471dce2087485781f33a1423755ef38000000000000000000000000000000000389e79154f627463a7966252deab10b5e809b0c2a9e90989c56d4076b834e2081ddae1c02a9e01b71d96b772766fc680000000000000000000000000000000009109473c7aa614334fde410951a69ac45967f7550890e01b05279b6dff394775dac51d583ae0aa82edda18ecc5e66240000000000000000000000000000000019dd51ec6783c1618a7f12298e38cc75d4fa32fc31438f67eb15419a2f0e9d4b5f70ea59b69e531c868475cada519569000000000000000000000000000000001121c7a6cbbb54d5e30a11a73c158237dedac46385aa15d93592a30fb64fcd94a674cc77afd21a611f704734337905596dfc62eb59bb84b3b6599bf3ce7af229096a8fd5925d4743a5ea386a26c9a6d000000000000000000000000000000000178670fb06f5eb8a4f182913f46f66147deb3f9f634d620ed55da2ccc88895e75f76f55b979e1ba3c3db29710050c7bd0000000000000000000000000000000011adec68ef139716ee081db7122e911ec5a6e1fd7f681a96a713dddc2b742b6e7cf7485b8f45e7ebdec8b1174c02eaf100000000000000000000000000000000089dac9a47cbdfead8536d6cfe8b94d316123bd92ddf30091e16711ff4651c4e2d8dcaf6c72bc159d7de9fd832c6f5be000000000000000000000000000000000c40b871930f0c6826a943a229112f8bf9a3b7d7e07139e1a7d99f97601b6ca8cf3638e0265743dd732cee17fadf996721d35ee6d29ee4816b91d1664b5957767b4b8066775b37c3b3d08729c949d6e5000000000000000000000000000000001040c4cd3c28a752295b115fd80c8ef0e538e1a3906e0d326e46585d633140bd6b8231f50d50c8e7a9018a625c4bdc530000000000000000000000000000000008b966d9433bfc3bede4ddb005cd0c256a168437c31b8ecc83e6fefa6f4b1f2bfd057c78f82bb76279b74a2f7de493b5000000000000000000000000000000000c0f75db7a17e4b712666b16c31b10bb935e7127eb9a0e59e35ec54814a9de9012210ff1862aef5f765d4f7f673c4962000000000000000000000000000000001015e63589a8b56aa643a79c5a433dcd8f4933a10edc9921bcaa7098af435f7879a40868e25d1ca6f7852800df29c2eb3d283067bac390f556891a531dfacfc4795358229bc9a651c0aa71d601bdd56d000000000000000000000000000000000fab22ab380043b01d312004057488ffc958168f8fe4d9c86af622030121e14a46c4308d711d5fa9a414b9ef75d51ba300000000000000000000000000000000047c738fe5272e695f421ed463ce0d6308e05c23b6bd0973df9b55ca96d89c0771a45d53b4d17f30d8cf08edbf94490c0000000000000000000000000000000017bcb3ed735e5a302f76002ae82f4ac74889fa0e966f0fb611fa6a6a09440bc923f447eb6aebe47eef917753b7427efe000000000000000000000000000000000b189d5b64578eb53ad850c826082265e506ab620a9ab9684cc2a53718f26befc35e9431af012306a6190f144a9632bf873724ba35e4e8b731db36f5067aeafd33f2e966977bd0962fd57cd5ccbfe87b00000000000000000000000000000000049fff545ac239696c995eacc560580a0328af07376f5ec819902e30d5e7e40d5fe07295c4ccf54d5c06134370373c1b000000000000000000000000000000000bff448d5ab544a8cae0cacd216a6b6d48f0abe1b4bc946d95c1a8c4ae44bf049c3b572675a5e20c1b4188fa27a867a70000000000000000000000000000000011dbc52baa00712f66def2fa8fc77bcb07431d3285774e2517dcca65e611f07aac265856cdef0c1637def44c382230fe00000000000000000000000000000000090af0898dd578123c65d1f818c3f33866e4acea19aeafbb31bd8da029ed1daa2d7ab3b22147eb32a09021f7a78fdf2acc5934c02b63797010cc8474e90fa5dc88d73dbe5f9be605bf335057fba47ea3", "Expected": "000000000000000000000000000000000d52fcbe9f1776477a9d2149ca55e0651fe9d098a67209ce2e7d772d4901ff2c70be432b53dc94886651865a81ba8c620000000000000000000000000000000006b54871379e2be969f86c72cda9acab9bc99f73de987f17ab8b25c63c55ffa2cff61b87e8c30d9f712afb62a2b9cfcb0000000000000000000000000000000005652612b19c38650d1babd4772722ae2c560e2914f2e246725cea86dbe1275a981a592eb55077ee4b7c6090e84d2ed3000000000000000000000000000000000ee37a6d42ce69aa67cdcacb19efc230c6c34969a2e081ac77e8f9d45128a6e8fff923c7647a0f168fee18342bc6d845", "Name": "matter_g2_multiexp_85", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f114e56d10dba7945d125fe1ab7871d9510771548d8388a2aec8a481de92572645b73631f9a60285c3eebcacb3bc0f5000000000000000000000000000000000667d3f31955df11e4e7896a1856fbd4e573f1cfc906b3953b5806a5d01dcdb96009d9f148156a3828e822435f722c5e000000000000000000000000000000000d7740ae776eb4766999f5671315c8965ccc84ff71757e361fbbb55babeefb96265c97df8892acdd6a9166641f656e62000000000000000000000000000000000166529d1a76ad784557384cb971728dba298baacc2f2a39ee36516bc7a761e9a7c29e385cf5784efb9f6e60e998b01e864a1ee754f6b0a86923e5501d54e6f47d7ab9e1483294ce98be13b7db52937100000000000000000000000000000000133e0b08430d9318d98bcf58b3d8f51c7b717fab56fe25f434bf521f830c7d4247d87d3df910490be2ad38adaa8eec26000000000000000000000000000000000e15afaee4f1ce6290ddfbc13cb887e540efc3fd8150dfbf3a5e7c759ccb8f334ba26953c7bbc43b5234b857159f6722000000000000000000000000000000000e4cc685524d42ea5e435afec7b3d7d025e93ea06407a28c246a39dee8ae77514a0bb2d5031f7367d658027299762bea0000000000000000000000000000000001b231237f7b0538d51adfa4ff92bf313507996cf5255f191875970ed4d946cffa8620b44045f4bcfd8f89baadd331fd93064d187f7d21b8b0a7092943de13b96c2e1ac9b578637a6e64331e2d40f53900000000000000000000000000000000084128f1848b2b244e4812eccba01287b9d07e85450459c8c42b01180bdd843058d9926f39e2fb5f610651a00233e31f000000000000000000000000000000000055ee70765f2cccac966dc08abd4bba0d004b379a2c6bf188f300f5d413f84e77ca1d462219bfb820d7f585b914a52f0000000000000000000000000000000002dd8f1d1cd85a5e6ac793f7e1e3cff887204aa4a5fed92f2088c06eae95842ab2c04d30d56f4b0fcfe61379e8e7c6940000000000000000000000000000000013e318f8b6f4165a8096c76ada440154901de42d69c38e66d9df4ffe5476666ecf7068e7163f29f04972682c43f3b0fd5e676b40c09f80be5d9398a9ec20cb811cf6819a130445203d792a4d34fc3e950000000000000000000000000000000003415c8bab713aa18d3f0d54e0101ba36793e6e9dd3471f8eed9a15e00d8312732a9ce88b5f0c30207aed92eb173ac680000000000000000000000000000000008a7e145e9576be8ba2fd980fb1735a2b73d1bf5f3e108878b721b6ed8378b5e0f03ecac179a6d148541096ba483b40200000000000000000000000000000000029e5554752db8bb87d58275268f24ccfcf3e0923744d57473d54a72e2cccb847eaa8f3bf638833a934c43930fbf30990000000000000000000000000000000000e0f2ead2697110a132c4ce1643b97fc652dd0660deadaa4e0c45e7ebfa64cb6a6fbbaac7c4e2b725beeadf6881ae5893f63a87972dd11f5239c35ce269e4b9239e3ae906ab117f1f045d3acfd16ca00000000000000000000000000000000014325fcc087aa108f152b42759cbc02cfa24e7e7cb995c78ccaa9a283ec2029c08cd747d599e0685d365ee99eeafca880000000000000000000000000000000011da603d3a1128329af19e596ebeaa4bad034c59581e9fa2e42a0260032f84654bf5ce22ee32c34eed7515d7fb0fade0000000000000000000000000000000000189cdb5b934cc1ec7ea0cf4b8158a1416712bb59c1650e6d244de33bebfffd3691b499b3ff8255b1b513deba709f7d3000000000000000000000000000000000e7ab2b279d0d5933df25d8fc4faeb8ca907e7bb8588e618b92737fcb6959380abc205118d2e3fc128b89a2ead5ca906145e3456d5ca6aa5910430e5a19567c327b757377aef98c4f46fe9a1f52cdc5e000000000000000000000000000000000895b6777e677732c74cfa82d5348c4c8ddd63ce10347836f5140b9a64dfe631804ea3be8e20bd4438f5e7fa14a121d80000000000000000000000000000000002422cc4781f007f732239ff9eedc126777d6ca0f0365dd90bab6b68c9e3d02ce726726a6d30d7d51a1f0b45aec1854100000000000000000000000000000000048af8a79663aefaff77a934f0af3a09ba02077c13a794ddb88e5c679ce348b3ab0fa217954ce1422f4e212d1383ebdc000000000000000000000000000000001190fec6c510b0b16e1505f737b25dc2401e9fc2c95bca92aa5d6e93b284b766bfed93a80b137e5fcb339983a86acd41ce27de5d3a5ef941d058a458f3ad2a386f1d66945789e51fa330fd65da4cd5080000000000000000000000000000000014fbf4d005f43563fb7408d1f20f672c8983120c66462ba9156b64a287e66960fecb41ca129b6b14466a5a0de91b81c50000000000000000000000000000000004fb283724950174d60f64af7bc8a7d059431332c8f17769df33f6607d72633aae3a8d595cb8d5af3f8909297844b3a0000000000000000000000000000000000e187476a19280ad9f33a55c50f37f765e343f92938e247ec9fe099c7f3df65e24af14885539bfcf3efe3bde9f2700ce000000000000000000000000000000000f086e6b9e845fe3b0c5100f82bc8aeaed166bed9fa4d34bc03ed86342a997101c508a4c096c4f67cb5791cc1a1fdb8187bf5c4624e86aaead712987f313e5db8f2fe6787fc33481ed6e5c4d3e96d5be0000000000000000000000000000000018dbe48c54347635d4b6bc17ff5ba390a73925f1b180d2c516eafc0936aa9bddaf7317cc0c211fb2a7f7bb096369a45d0000000000000000000000000000000015544c177a4b8018ed60c2639b43236957c2d995fb0f32523654584b0bf052e0930366a93406e1ec5c6d2edb955e811d000000000000000000000000000000000802d2cdbc5e15b25c77ded4bdba087f1d5760e6ebf9549a37f3314b1e88d3d6f58da9d8c6e9ef85028a271b83dd6242000000000000000000000000000000001577bfeaf213ca8b0983cb178e9634dd18f74baf02f6ca31b2e3b287d80a32d4cf11afc71df09ca5bb0bc8e60fc7ffa968cfa3fd0692c9ce56538bf70e77e2a47534d9472ac702c53f2dbe68217d53df0000000000000000000000000000000007c059044ce0c15bc527b19ce85cade8b1d5a9cc6dd304ce9a3c461e631e17c4feec52a0ab5cfab6a2270c75f73df86e00000000000000000000000000000000076344286cedc8c180e3bd762f12ac08f0ecc51293b9f9b8e7c0056ceba1bbb6fab4ee39cf559fdbd601db6c3d201199000000000000000000000000000000000bf6e708d0a4fd85c7566804e19f21f7a00bcc3bd7135f6639ad30aafef2ed1e72c84c8995b0e59738c2bf1e4040621b0000000000000000000000000000000018ff3d0ade15b690b6e306adaa5c10796b78ed7f8a984f637271cccfd39fd17c1e8288a11b051ca94de2a9bd04fa96d7a36b13ef742bfe88882a4e635b5fdbd9b079e1adf3423dd4962835c68c9617c500000000000000000000000000000000025cb808922f6deb0bed979b80a675d9324cf25c53de373534d771afd919a182af9aa1dc26a2d0284887121bf4d6b6470000000000000000000000000000000018970aa4f456c1b203817322df2e222516bce67ff9ace069599061c6229596e506c0286171f3551302e45b7d3b69a39f000000000000000000000000000000000a57d0da60f03fd4a5664546f9809c771ab6188aca5102c31f26b09950cadc26b0275417ddd9c4f4cf29794b739733cf0000000000000000000000000000000004ebf2bd93d7921d8bd97ee71cadf91145e064a33651da2604ed6fc8e08b1b8305005f12fd4e6b68b7b6a3b5cf123b1324c54daa7de8446e5a26cdbd6741cc90bfd26c544fdf221d47d509c978723c3b000000000000000000000000000000000c8ff29d0333e3f38fd8af91ecdca49e54ea5dced71b60d693b1bbade99ae668e4f994f7a5417a08a8ddafa410d437f300000000000000000000000000000000078ac1d0898a9e6cae29fe6b50e435e5f543d0ee233346728c46d659c4338295f27b42fc4b2851ad5035feab2bea8871000000000000000000000000000000000b3a566d2ef4467f21c27e4a3dec99a26c304b32ba1fcce8276a8518383a7de44de5b4011ba738dbb8761e67e36115560000000000000000000000000000000015a0aab8c3d51fc3fc8aa35dcd07f8a08188976883f9d3ccc87ee148525f2115ca46726a2e3c550167c169977b216d6217ff7a416011549f144a3a65238d62395f4f76afc09496902c064b27739c6d0a00000000000000000000000000000000115589e8e1440edcfe72c008f6e9cdf13fb7baaf70aee16166e7f32f4651db784f4c5cac15d91ee13001169fa777f0d00000000000000000000000000000000000f86710678b01c8f648bab2289e8f90648d9470cb13d5145ade526696d22508a4a59164290586c2c000dfc55b4a20350000000000000000000000000000000019b300961b40b0d9fe6e292e9357d04f0483ab3a8cc6f8f522153c51d22de8e96a812adf720d13ff7d05d1e68264638a000000000000000000000000000000000a80b61ab051ce413ec838167fce393f88c8a25f403bdf07cb60391fb15306a5271a7042d36f7c46b5978106a7b5293c4615de9bd7aebf1acedd9d40fddda34e4a85bc253c5e92c20d984f6c4cec533c000000000000000000000000000000000567c33d22805319418cb1ea7eca6205a6c44f1f881c03e37bf3c66a1baa5153473cc73b8c25d497b0b0057ceb0395960000000000000000000000000000000014d7a2bfeea6a746e709f6108eb32581ba38a617e4450b3567c77a992988d91f4da31b209286f8e9fd0d7b8628aa6c4e000000000000000000000000000000000ae6c9fbf0e06f2e38e91699cd21596ba90f92f6022a4f3c7c8a6557b7e1331283bd4d7a7d31d77d9d7cf70a2945ea1600000000000000000000000000000000066b8132c73e1da8ae7fec9169770a188b686f223fd0306441356040bc9070f34a47fe1bb8c94de9fd7606c18b1d2b1dd38f1a0417a5a366dd2d8f5ce229afb6f34c1b663ad6eb1d9ff12f38412f00f7000000000000000000000000000000001460040d0a19c37fb0736ebdac0324d8a38c94a73fc5f602b7ea5b7255be9d4b6ffc22fea5043d948420e9ae3476f56a000000000000000000000000000000000b37c0078ab8babcefa8874c6cd1c5184d713b976852d087ed84337073fab3054899859d0fac2f4351bb75ee0e534fa70000000000000000000000000000000004150f3b98e6166d9d6b0388342042dd8eff9b8e1239f479330b64c5b316f98fc7bb401b737efb87e1f6663ca4efa26700000000000000000000000000000000043e6131c1ff621fd6f8caf0939487a927550343e24425ada33cf622de757e6e75c9affff9f04373a954557181641617364da9c6b07aada98107447afbb189626180c5eef31f7f2cf26d5d76ab0c74590000000000000000000000000000000009fa1754bbc957d2a8317a2eed859457073571379cc7c6d65bc6a0b5829f8142db77654eb98a2bb0cfa5223a27d756cd000000000000000000000000000000000cfe8b8fbbff7507d3d74f4f550b4c85e19b8929d3728a462e12b4008c79014103153c69ed8dc6b743e1b6fb4720bad00000000000000000000000000000000017ca0c08c320c12502a1dbc841425694bde68b7806eddbb40702e58ed26c7e112f9a821a6c67afed174f51896ec2287300000000000000000000000000000000014d08df9cf825b07a387642ac9959e8cd15ea8e752231a3047fa30816acb1ecb79f1755484af9a98b993f50128c2bf5031aa8d860e3b598ad0c4e9f93f26d153f8a8d8d0dd614ba868ed055c517532f000000000000000000000000000000000273b64e867a9111e257c9b32484655e4d7e676ec50f174d9ebc9fc4262c037b176ada941dd8c1abf645e275dde04f4a0000000000000000000000000000000008a63b9604e96a5034d92e3790411f3112c2c7cdaa056f9f1bdfc0b164c37fc9f58dbb566337132cd1626f9ca2618f800000000000000000000000000000000006a661167c9fb6c26bfe0a3902f309fa683fd22729bfcb433756182e7e1a406bf44ae1d13ef0228534881daa339394e400000000000000000000000000000000193c6c5ec200d225c43c6e37cfd15e16e49b7d87e5515bb7b4c918903966f4f6ae0d42af6b98f6efdedc9b0301fa1c0f290c467c4827c9252b82ff523633ba116c52d15df9cd4e3121ff0e9f754ced5f", "Expected": "000000000000000000000000000000001403c7e3059135ebcf5e752011fdfaf66e348135314f3f4239b066e1c6192ffcaf89bad4228fcc2be19a64f4f5386f5e000000000000000000000000000000000aadbd8d0e53d5b409f7fa508089337bcf36212a3f613b37a95757793dd6b0ca99d1b3578ad8020d46e29c9c4197ea070000000000000000000000000000000019e43bb32f92ed187fc32d9dbe24a486e38316a3cec0fd7f7c19b313af43a10fd63738b78e609e04a083de6761d53a90000000000000000000000000000000001490da7d36ff16304b27f6e57412975497e9f3a6d35cb162464bcf69fe141d34ae27a33afc75a2802eb120e90d4897bb", "Name": "matter_g2_multiexp_86", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000038ee0c2c409d8832437ea450ed705589c82791b8319fd0ba6fb4d302d3c5b73ea0521a0253716e5810f03fca2e9dc720000000000000000000000000000000018c9d748aa685bf6e11e6e4b6ad2290ceff59c8837a088b41a08983fb2c5ef077adb0730b298c5df9aa02a820a19a4bd00000000000000000000000000000000015d248426e362ad2489c0c6a567d80b22d54d6a79e198198a771fae4c4e97eb317da9feba8eaafc9460ef45b1a5e5690000000000000000000000000000000005a2342412801cb37911a04d7ee3b1e5d3dce2a06e0658d59f2ddcaa9ba32804a1ddbe8f4d00f4436aad1346ed1ea5344aaa57782608de34c6334ce5039c67767f6da7b315dcfc772f03aaf3dd1e67b90000000000000000000000000000000019d49748f05458cb9b316e433b0d341e23bb5aaa724b824bd147596761c11efe8f4940eae09e302e563e14e96b814f4a0000000000000000000000000000000018011e7ee4988da168adbcf81cd14a9232edacc06bbfef0fc78dc0f96b5ac86ea67be8661442b5ef60e3889f3137182200000000000000000000000000000000175a2ae3bdade6551b23656c16884ba0fd4247df4ba7471cf81022d7e224b23490db153c8289f95467ddf9671f8b6cf90000000000000000000000000000000013c58c0f55c46bced98faf3865e3b6a836252f252e97b6d2a799b574dc569f09ce33082880a4d0c3b8a2c7c0d4c30eae22c1cde67b0e8ec7217c6ec72f36d8a1e73794297819de9ef6f1e52acbd3ec4a000000000000000000000000000000000ee45d5689a8ea6132d5ace000699a157c1cea3c0c98b38d504153d64fcaf1702ac7a1cb0889539d6b15489fef415aef000000000000000000000000000000000b320e0cdedbdc1fc5733488e6d2aece6386a030adc36b0a69dc3809827319947049f3861c2edc859797d30a3689322b00000000000000000000000000000000194096079b3a1d6ab1080dc71bf6d5734bc7b5e7f30bbb0f9b95c9495a6bc4adf76e198fc66accbbbaac215a8932d8c5000000000000000000000000000000000ec07be0cfa9b3d3a64c016471d9e6d25228b46dcaca6e197be00b9ca5087162c35f1d6326a3cf83f568cb06da8c5220895341f4363b688c4e9660fb0cd17f6c111a5c92e732205fab0d0da0175f6832000000000000000000000000000000000a7f3a3fcf2e7b0ada6d4fce179bdf229454002f1271a39d5e99daae72da549c6ccfc7c574f35bb9784100675c30b1120000000000000000000000000000000000fad14ab095fa09bea919ada313727e7aa5aa06a1cc7746d006e3eaf70f79c5e4001a8a8de03540b45e0598b22710e00000000000000000000000000000000015345ade62c5691690c181da09d8f39c1ead42046987b8c7c975d40690a286a816f8cca519731d0ca23349c54b30d8570000000000000000000000000000000019f0a32361bb6ecd8b1d87c2e15d31c0e0cf995eac9facd5eca123c0799c465f156b0142d98e0f315e9b3595974a7b824c5718fed7503c5e2a97fd6ab0294d6c42b1d35067e9d5ec1077176a4bd3126f0000000000000000000000000000000017af46e78904915e348734d2450fc6e1938bcf002989f855082e3b4ff3366d81ee8d28293609c3c3b11568668b1305f80000000000000000000000000000000018b0b3859763c2654fc00792a5193b7317fa5051bcfd15ea42be2fda0f43adf322219f34e54b2446ef73a4562151f9a70000000000000000000000000000000015c23509a1b324c649ff878d004ab5f253d041670ef172ec4dabec7a525d5ddb8f9f62f383e3f71b0e9c98532e247d560000000000000000000000000000000003a38564a55fdbe05b047281fa153f736edbf48c901749005473255333590f967171a6fc88751eaf57a5335bbfb6ebe86d055ad484f5054e8bd0d073cd556deba05418ef1235d08ecbf8717b550933fa00000000000000000000000000000000100322c4a92c136437714a6586c82a6842027ee218bf1fdfffaf95ce47c9c8b6c8f61115b092dff81ff2e645d0a7a4340000000000000000000000000000000013a91ed8629acb5e770683015c3c248255d673d4b2e6c96334d1c80326d1a8b4b655c81175e4a914a45fb37c1f178bd10000000000000000000000000000000019075c2eea3f64f42be82fdb8f83f2c68c08e858702a0225d869143c0b017b76a7a40d809116ffbdff6700b288f5ca3b000000000000000000000000000000000598ee9ba9d56400b59c7f5977aef1e179855a37179fbfe97b95f19137b6034568e5c7f616943b4aca804272955d42334cccbb062c27a67ae2783ab65a47ce166330cfced1f11b85f87483e0250b138400000000000000000000000000000000025a526b137aaab5ac1b5f8179a18b06feb7c905b4a843cd55e31b7464c2b6d432b569e9bfc3222511c18255102aba5b00000000000000000000000000000000090c20c9f78a242e52daa339d5cc1c3f35aff7ab802a3e4366597db8b6ca43d30fa0fe8d9484e49fa4fd0bf5509f19e6000000000000000000000000000000000e928b2173e32e5fc9c373a2a6f126e1a3a472c01a5e87677be0d29907022b9a7dbec3340cfc89e67377ce472c2d5d4c00000000000000000000000000000000147b4eaa2dcee39b918b7cdf24483b29466120677e5d42b51353a9b2fa207bd911d9b391142a13a212d0ab38adcbe10796111cb1181f048f51349aa2953bba2af50f7b7b5d2328d435bd63a7df5cfe5c00000000000000000000000000000000007790cde9ff8af2d7597d33909f00963eafa228817de1ebf4233ef0831202700b99641318186aec80ac913a1b1143eb0000000000000000000000000000000009d42ea1386d8b019dcd26068ab156f399c35b7d492722a20da0c915f7abe44ba688d9486f4bbb44268542c5a49168930000000000000000000000000000000010611f233bc1c4af0a14e1d1b945c91c077ec3dda592e2f852e2de41e09331664e1a92f9a0b7416c50327bc943a17b9e00000000000000000000000000000000048614243262dd070a754f40652b96a03326fc51273dddabed85df0654890ff38e0da7abb8190e4ebefdd6f78a5fec509d7f0c0c7e927bed3fb930fe2d0109f58678969ac8e14fabdf4ccdd0823f706d0000000000000000000000000000000008451d24fdc873c61db44e57372d43c35a2a8098255f9aad3a6b244913b86bff6444042e391685b1244f009c5ccde935000000000000000000000000000000001177c2da9972a2b96afaf866f97dc149482fbaaa93e194803c09c8334c2c7025e08cad4f7898959a57b07a545ecf76ad0000000000000000000000000000000016f40426cbd1f0f4ca5ae1dfa4c3960a6fbd51a1b5b24ff5d03fb9911e908406a0ecf4f20a78a280d24dc9bdd1c0799b00000000000000000000000000000000194a8c55f549da1842cc3173f3eb7bfd70df26b43a3059a3590992e34fb19b2caac4149f64d442965e166225b9013e2b11ce517fad2609f2ab8d44ae6263623a7903b2cbec683570949a96fad78fc6d3000000000000000000000000000000000a97664c1d7624cae0e969c728a84130fe260581305435ff8ec701cdc51a73977f58c891ecee637eb6b7c972069ebbb80000000000000000000000000000000003f4ed6a9e9f4229f0fb35394bbc10da9adbf4985d4453da64eb312ec88cb15bdc189a3b5df1af3107a36fc001ec92ad000000000000000000000000000000000ac552c5f6170a70563fcdca8e0c6a7c6135af2f9d5ae6f60a2c459d1be4cf76ebcdf9bcd891db8a1e2fc905a23a97b4000000000000000000000000000000001734a46c99e776d1ed4b807f5b313562e0989ad5c67dbcb961c134f8b7b7601c23308839569dc224bdf7c370c4498303b17d28cbcb9efde6d9cdc4c9cda385ce598ac8468d4fc94cc8e98ca3bfadf440000000000000000000000000000000000a523182c886671435ccc75cbc78293274802c6142465acb31a1809e43b1d656ed9c808068de167b1ab126ed0f73a4490000000000000000000000000000000007c4616080b5a002fea3589d54c7510884a3ece705d27dee315851746b1ee748e8a08d3516d8c6afe1c0482b960a9c62000000000000000000000000000000000dd1bd9b4b9c140aeb97887a0266bfb5696813fea034b78bb7d0cf1cca15b5bb0ed92a97841c8d8cc614f7721b8b7e040000000000000000000000000000000012a41a8941b6f0e4c87f8188718f9bc75305d41d6f4441eb9682473340fce0bbb463e1b922d3af8daea32b8a8ac9c3b4a9516e93416bc7b0f3c5ef5da6112abb73fc285a14093ed19d8eddf241169119000000000000000000000000000000001763ab2b361681955735ae00b69f26e06469391af993c8dc6f2e1dffb52ca01e49d58d6e2249e7433ccfb5ddaf8fead40000000000000000000000000000000003858f3bb01b2393aa4d4d7889bdeb0bb9bcde0dcb9b39c4ffe0fcd0b865baaff75b676c715be275929ff4303c416e0800000000000000000000000000000000086d64bd1302b0b3a620b87ac29cac3d9e606513ec8b47898cd852bf552c1364291aaa842616b92c8936e076e59451bd000000000000000000000000000000000967c9f59c15ed02c9b2da6e76fb0bf3d445ba849010afb7f9c994b1ef6a05ad577570d4adad043796eb90e51537ce5187fed462636eb57506f870ed1c8f66e211758327f4c19bf909a6419312c58945000000000000000000000000000000000e6b0da7b406bcac2dbb90fbf430fda6442cc2860ce633ab84404dfbb426949d55ecd72992da1a2e8e1ce229b599232c000000000000000000000000000000000fbe3a345ffc8fb85cedc4b8dedf9d952c41b4ff6f1c7ff4cf91b2276621969d905aa9aae5fc89bc516f96b9bd1bb3c10000000000000000000000000000000018c2a7fcc35099c41bb851ff66abb047e2af9cf4fa9fc45f030124ea2c7efd26e594abbfc7a7f258c8081a3a80d15105000000000000000000000000000000000a27cd33c2121c9c542e27b52a13275ef7e81dc0c6ece883b65e71d2bc3e7246f95aef7c6b41eace382a1400568cf298c373d64034c78482d6673c6906553151887c8aa28ab2930659671b8cb98a595700000000000000000000000000000000158bd8e6198d22b52efb7f3b945668666e1190a4a8e70307ba5c1b737316a8f8568092f219f683c0f53f56f25745d4e600000000000000000000000000000000097e64e4553371c81a9bf553ddd9719f59b329284eca0d76f023d603c29a034d123ab777cf173c5f2bbc66412d69d4ce000000000000000000000000000000001298cd5501e136a06ad4fcf87a75c0c7b96c73e844863b74bf6aa581a0ea98c2b1f608c668743a3e37ad5ca2074af9340000000000000000000000000000000017ff9f1336d7f2152f17daddde9d3e1679cab8120ed2c0288b0908d4e2099a08c9bc6f79425f004ea3ac4d684abff6dcf29c901f9769a42610958a8cd53eaacd9e5c4656106fab536052518b4989911700000000000000000000000000000000115baaab8f0331894da531ab557bb454e2003010ba1dc1d96e3d983d49b1312585c6d4c43d85dc074b23b2fb28c8a1d6000000000000000000000000000000000db1621b721c8a54ece26a355b190af5f3e1dc1b43e0827a1912ace651cbad4b980e77a4c3566aa809157229b234c808000000000000000000000000000000000c594e0ed3f7ee55886e251deef9732aea3de11f094ec53907a843b755add8fa5d00779a66621e615ba7772ee821c4030000000000000000000000000000000004e80aeff6c4b85188903b4d2dcac4f94f7cb4285a38f94b0becb556d83dce8735d1db5810b409d45a8dd1b9a6dde29c125c12599e84b7e648aab52cd68fcca7f1a5f56c854f3c36e0445ab7e2df2b740000000000000000000000000000000000371a74468ce2ad90e19b7fe3f57159dffb1b0422b32ad693b2fe6c45c5d371b97a90054095da887019d25c1ee8197800000000000000000000000000000000010575e1ec9a3e609ca086ef8bca679c4548482d9e0da2e51878158ac8e5b29d824c31ad7ff642041e748efc50c2514e000000000000000000000000000000000ef36130380f1e84b2f462b5f970abb8535431b79813015261015c6d7e74f038b47504de01794840d93fbbb4b386e17500000000000000000000000000000000018419e85fc2d75f007d1e0e02c1975332e03d42c3b41c50c3538c3625e702161cdcf8913babd2995aea7566ff15abf2bb9a1d051e33a617c25e17b7ca8ae6b02f16c759cae0df7fbd403372eb2407f6", "Expected": "00000000000000000000000000000000125406a942ae0119575453beb4c093d2696d3bea7bc031d7a586439197f848e1d5a82b925b4e96138a3460eecf198ffa000000000000000000000000000000000befcee6bd1412c54674a3d519dd2813b87b18f2ab3375a731197e9f539f8f8fff634f15647e7fea3c65b93594343c2000000000000000000000000000000000011e4d432ee6babd502a9cbbb5cf4839dc6da6176b6bb0ba51d99a3587465f5f3f83f4d4cf2c7e6187de93b859ca61d800000000000000000000000000000000168509010b867aa198fc294a5879ce14a51503c1d0e8fbc02ec08cf62afbd357ceac24b633bd0fa99f83dda92e10724b", "Name": "matter_g2_multiexp_87", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000070a0d060c6e9bad0d1bb15417578daaa8b7a5c984c4947dba10fd874d93fd1e3994337c87799d78a674087678d9168f00000000000000000000000000000000128985b69d5d6ea0ad0b19eba7c2b430f5242a7e89626c66fb83b58ca7cb65a479de4b2fca6886cf55b8cfb52394102a000000000000000000000000000000000bb0bced708571662af042d18956b5b7d797b61aba70823618682287deebe69bf1f9a94ca4059e0570e25a39e60b9a8b00000000000000000000000000000000193f0793324dc78c40f356dde030b632feeb1609a1bd75ce88f0d313a0864dbf1f5e92826870866ab9b3c98cd1c12aa508c35887835bf4497d673936f40ed44145c5d5009fae16eb0f3ee9168831abf7000000000000000000000000000000000a61a310f90a5ffde617b78f784b2e699cd77e7c3e7c483a2ccb768f94d68e59a2a4521410c22ef6f21ba589ec3abdcc000000000000000000000000000000000e6568c83e0f7e459b27a28e5bf954983c5dee478a009c244da16041e710ddc67479cdb3da6f47e7203fedb8f765b2490000000000000000000000000000000001c5cf6b948b85a1c426fe932cd87605f1fbf6c932756eb1bfb43beaf012bec4612d8dd0840efd4cba3f5394beb65112000000000000000000000000000000000e02d5bc20c40d7cc2165a21ab37c6e4eb71322c01a43f2085f93b5b02bcabcd668dab90323db0f9288737d757997631a0154f7f8d52319c9e5cd59052e91b84640efe83ac814d95370e46aff4334cf400000000000000000000000000000000165287d72eca1ecda5fe16a555245b0a34a04beaf9177466bfd88bbc675442d206e70f7a2063b6ed0e15e9406232f5ea0000000000000000000000000000000004c0608bd7e01e65a15716b0c505111a3abb0abac3efb846e05e8db59c063950dcee052f04d1c4e9e492bc6740fafe6d000000000000000000000000000000000de897f7ebaf9089f7e198ee41e1efd7d84fbec7327799b9293a489965cd36159442eb0dc1f79f6b1f122f592b013bb30000000000000000000000000000000009774586dc359e5d20486f00dcea6ff93948c5a8b74058645d1048fe46ae3330dd56d85204d328f43f15e674020f353ec252ac28ea29b5459cd2ae5bce4bf08a102280c093b9962cafb481016a212709000000000000000000000000000000000438ee51a560aa419ad6ae45e1014c38b7c43f1f6a512bccc2d4f10a35838369b71799fab4b6a754fd938c1a1b874fc0000000000000000000000000000000000c1491c85965c0b74d08f5866ca727fd30bf641a6ada0ab8363ff01916c37d10b1b7eccff79b396c587d9beca2c826c0000000000000000000000000000000001452f254ceae9626443265ba31a1a750a425f2a7789e69cde16b70eb319c744a6221e74a9e2881c6bafea161d29638df0000000000000000000000000000000011bd6a1bbded174e9cb95d74492f7b07a755339a6c40f2a1a76debccc0f3a32c7017ca4e6679fb2c038c751f19986f526d3bb5ee3410dfad575b0fbe71ac5df2048f74b52e777fe0955d6e244d434f3b00000000000000000000000000000000139157c34aaf70cbfaa82be655281b085e37d6406df4cf8e291b221394e91d9e3cf04d431f15436064d0bfc8cbe13701000000000000000000000000000000000353fcf6e587e71e59d8f05d4085961d37b1f62694dd5c7f40efb5875b90459dd66c4d2d6c01a40834307ae9e82c2e08000000000000000000000000000000000a4975c9872fd167d0ff4cc80a6ce179b1e6e1eb21c8de80321451b1deffe68d8a13db26218f14935b64af25d63644c10000000000000000000000000000000001e8a2824f21cda745a24844ac0336994fb18e30608ac61201a932c0a5a58f1acd56cbd9353bfab4944efcf2859ad5915c30684c596976bf46384e6afb2bad6f821c4a62338d7a6eb204ed75070b1973000000000000000000000000000000000537d7a9d7d9dc451cba4d50630caed32e182cbbd95212577b8c2855c327530e447a4f3d73c7d63fa3ad5111254c9ed90000000000000000000000000000000006984b32955fac4ad3c0d181c81b98534ebaddc316d51a40baa1028bacd6a93a20d4bd6cad6a0f8cf7ade96bcd4d68dd000000000000000000000000000000000720c392a663884ad4d8daeb7279ac41717ea602108c76519da13a45a77d2acafee842828f5ccfcd786bf7ea88afd01600000000000000000000000000000000081f1d3e37ebaacc11671bfe1670ed65ece2aee0e3b5d746a8d618b44bd4b7dea905eb8e958bc026a092b2bd5a7b87cb11009058bb8e23b0a4294b5cae63aff10265e729d3601d85dd7f1e8063ce260a00000000000000000000000000000000005af33731879a574f39dca99c5c1b9517eda13121221be77a0c1bac82fbf29b37889c15a9d32531a3f6bf9137ce82dc000000000000000000000000000000000c62939f00d70a07a85804cd97fd34b9764565bdba225cdd7549729ceb9735bf4d09a80ec3055c483e1e24b66c41e403000000000000000000000000000000000e415677988c9d4656e59f77c608926c83028f91bf4c0634120b5f774ba07180b98141ffdf727cf9d0fc7a4cb52f4393000000000000000000000000000000000c9c37eaca857151a0c4a49b079f2f061e6a8ebb77e11eb32b29227529562f8dc8e2646e25469491eec5a07b11943f203e5489447bb9a5b661bcff2d9a4153a5aad975abdec380301b6d4ce019bf2cdf00000000000000000000000000000000015113f8f9100cd18427ff48038e1070fd835fce6c0812b7bafa679ac733c80bef56492ec3ca08c1117bd0edf19cb26f000000000000000000000000000000000789cd90c0be1de5d0b359c030d4b9d8aef93951e26870e37c375b9e7879cf277971a05babd319a3a6ac53f00f3254e40000000000000000000000000000000019b1cb91c9a1b1ee49c3837339778806bf0c093f171c92c9931ad43e35fc61cc08dafaf55b7b9e0f49dac28a12bcf92d00000000000000000000000000000000066c7864631333226f191e313436453e59f48f91d42e68874fa4da45eeda1f6f7f6342204e64e124d5ecd861f02ef4f00444d520ee01d87407747a4ac37abb7bd4e4c4f1735ca7458cc2e4dcb1d6297c00000000000000000000000000000000129d887d694be0ef2f84c343a9aebd0a2aaf19a4e78586470351ffaf0b1309593363bd9c6e7fe39a6e59445d935414ef000000000000000000000000000000000596d7061c2399b6a9be7d4d495e58c0377b18db1e45cf3eb431d10cb8b15ae42548a86a26086d57b1a71cb5857d7917000000000000000000000000000000000cce7181fc87dfe1bb493043279a5d93cb2d980eed38dab2ace8c9fb335c2890447434d80df6e7c95729933ada7b9d8f000000000000000000000000000000000f0e1274ff70bc6d3f1d0d5b251ae528ed94aa3a1b9bbdb260892bfaa6213892071b8a6407abe26105b2f81df90569492035cab8f8120ea8e91389707a290db4ee69875d7429c6857e74e8bd40dc7360000000000000000000000000000000001192050735b114c19eb2bb9aa01f04d1fd9bed4df877113a14f7fbc9c31acc10db3ed0e0d15d8433e7408bc237c985b9000000000000000000000000000000000a8a66cda780790311b56836fe69479c7b94dbc6c82ed5886887dbb539a40390ebb2683c04078ed105e639a2ed8732a1000000000000000000000000000000001678ddff677b99011c73e0c9875b5b2ba063170f4d565d261b4c6d3263ccce0334b5bbb7ee08692568037fa96782e48b000000000000000000000000000000000ae15f79ad7f790f8ceaf7709f4b5da71642da0c1f7c442eeaeb165c7dacd8a4892fdfc8447a03a7c56e12513499e43c4bec711286827f0941ffbb451a8eba871239341a60e3aaef23487175c9d2e8260000000000000000000000000000000007fcb5ea5358074d06b64c5f46454e682dd9ac2127374c83f3ac5ad46bc5fd2fff7c5a80ffc669a1c159ee8c9a01bd37000000000000000000000000000000001010ada1bd493d6282ac2d3582480f50074a02fdf412c63e93c5857974626ff464150c20bdf23a87692bfe69a075eeb300000000000000000000000000000000086bb5664a8738f02af5517aec4c6db47653a6d76bd4b5e37ba4d8b27a7819e82e6a4c7ba4f8377e06a5878e7c0bffbc000000000000000000000000000000000be1463ab76e468e47e1711c158dc9bb10d1278f5cc676cff937f60ba457061bacdad7b8d3286f40219963b147cce4bd369d91a4d575d4c142b98a53115a792ec50a290608ad316465487762e83f3a86000000000000000000000000000000000c3329d1e1c76b0bcc7ca3766b2cc5ec8169690f45e0ea3e37b7173bfd6c884921c7523ff25391a85b47d5de395ca63b00000000000000000000000000000000081ff066c008d5a4c893a636d24e9752c6a06666dcbf80082167610e73a32d70aae3e58c88ffaa27f05260b86b11f72a000000000000000000000000000000001178e88c652d257888cda1c0b65ee2c0636184194fef9e6ae3791a85417c43a31fe75893773ff3e7b4d4cda9eafa8de40000000000000000000000000000000019657ec4604ab5e8812237a28e5ff320a0d728c60c541142ffd87fec2c703665638e5eebc33e308d5582cd043d08d788ee472561535a7710db521976cef0c92a4ed89861ecb397cbcfafa477756e8e120000000000000000000000000000000010789200f69d8acc70f108145804b62b521a30a04176c449f52bedff5975ad7b273aaf4a32f8461ced8e92b2229e2cef000000000000000000000000000000001178c36174cdb783b5b09d419ae4a154512bf9ce07368521d1576b2f1bf39f98be29bf533bad16ba9d96aae621612aa70000000000000000000000000000000002580f2115d1814667b6178b6bffca6a4d992eb66e9601c0d21e32a5f3b69e3f85e1205c877b2dc2696a0e872c5bbc6c0000000000000000000000000000000002c94d7ff016d57bd5f589971344c6499577bc2234e18e6c8dfd7d27a205442a4236ac54fe279d1bbca76467530140b42cfdcb8240f183abec526344e8ceca6a007c35b757928803f854225d3a6ca36100000000000000000000000000000000108b6fef7396ef71b46339d421726f83b08320599d66da18234011720d2b524d24075a255d2771f1ae904958c50a9046000000000000000000000000000000000723d5045b65c0887da1bb01d874714ac86d21441119a93a1d5758957215f399f5ef1cbc00558db01b295bf0cc988cab000000000000000000000000000000000994914a3df9d3094dab0c0c41a45315dce5968a99e6171fc609ac9e50bee5ccac771efaa04067467e95709bd924973f000000000000000000000000000000000ac746602f804f52e9a485c30412adf92eb9af3f6daa8f23b974339a0ffa6f5aa1b70a80a9f19cde2a69a4b7251ecf5d60659743dc1977a698371cc302b7579b6d7d13632a31b47df369365fb02aff790000000000000000000000000000000000a2ffeaff148dc5f70fcf53e7e8d7b6100cd6e7df5b3fa4aa33bced243f15b4f77f48d25f74366a693404b6ed7d3075000000000000000000000000000000000f3e1b34ac8fde4caedf3d8c3e24db02de3f91487db300f09c779e7e4e96ae55229288abd946abcc3a8adaf18a0c89e000000000000000000000000000000000166a68c5191dd7f9d44eade2ef1a9b522dc062bba9c55e2ff03aef400e5d2765a12816b4ba51e10bc21e06113c8ddc5100000000000000000000000000000000109c00de20f7e827375c1841348e684fdb248fad116e9643dbda8be2bd06b71db264e9f2c40dec2092e7d518540a6d82652a5d4fdf6d6703c857fc7b10a741b95fbce91fe823d827cc7203be3b3bce0a0000000000000000000000000000000014ddb61173359514226c150a3343576b04fb1b06fabd8fe2f921fb3b90baf5513447c107f6d2f96c8b03274bfe451dca0000000000000000000000000000000001d1064860f6c4d62a282147308e80ceb0c5dd62f39b3232a231b1b287e497df31cbc5a3905a7687eb2f24447e50a395000000000000000000000000000000000859611bb3962955f92bff861e03d07bab7fe1f69e90c6bc7928be8d1758c9194ff7a52b16472d04564607b742543eaf0000000000000000000000000000000008a3e8396901a205a071aad06ba9812207171f33775eb358de4232826a5f0ff50ec3e137b1344b583849e8a5b424b46676a30abda185e7d280804952fc0c074ad907fea2aa54da4c3190895270169b20", "Expected": "0000000000000000000000000000000008c9db83241e7f3ae6c2eac8fdcff5f2d35318e24c3b4130e9bb7048a3b84a52fa3f222a8190121d2a5b8835bf911bb200000000000000000000000000000000002db79cbcbabf41bd8c715e024f4687bc0d058d76b8dbe58ffdb80918212ab6e9b35256fde583c0fe903c34a4c41ba70000000000000000000000000000000019f37d05f5c9e65c6f004e1aef03ff0e1899f0739c9cc4e9038e18f9d45678388454d144495b2cd993eb3691bf3e96f5000000000000000000000000000000000d8e0d7715ed71291729bf480f5fee7ae04264015732677488472bedc0dbacf8b35eef7adcce196e3bba9cac0991be81", "Name": "matter_g2_multiexp_88", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000064a134260b753af73df3764ab662e3b1bd624c8f3248e9bcf7676d8fb0825ab85ea33387d4641c81fb8ba3757e0870a000000000000000000000000000000000d67eff1936a395cd3f808ed7fc89f8b6a227c4849a6941d4bf762af6e41ae41c8114aeccc2565ba01fd902df530df1e000000000000000000000000000000000110ca2339832e7a9468844b94b3ced0c9216654bef1c8a5cf66385a99d5d452f978bbb7fe15fb477f56753488fc909b00000000000000000000000000000000173210b548d1b98b926539049996713f53108cd2911105235c1d5258360d5620d330951db67219ffaa304a67fd6219f39f4db766964c7855daea58d1205fe8da572aef06e0ca64912cec7c87bcb2f51f000000000000000000000000000000000f7c3795ac3d511f93a3d85e65261e4c09cd316787f74ced6e472a3993b7b5b0ce5a7c91d99559a8e0791f712cb4e1700000000000000000000000000000000018eacb2c5fa9221881c6311256a69c7616748deb3235c61cc11412860450151a25e3d6a220bb23e0b3e3325044fba68300000000000000000000000000000000121827286873ad31f58cb3889fd01cb7d0f91ff1c241295f6ef2dd0e8aa8638b63a7e6061efc2e7ca1d3579b4868f0460000000000000000000000000000000003a57315175d70880b2b53c67d61831ab066b08d7ac68637364ab1c1f3efad96d42a3cf5189c45012c1f73a1b97bdb4c1deebc727d98bdec47b5a1fc48916dca1e42345ff5474a5fd6cab0ae99e9f10800000000000000000000000000000000180648e5d0bf727101417f515cb9578bdde3e9f6c4176d516454ea7c32c1712610cc8bbed303bd1afd48f580ec11b77c000000000000000000000000000000000d6ffa9b85d69b67abb77f5c8bd776eae82d1cb055d2dcdea31ac66b1825014ec7f7a2aea320ef9f6897c9aac8c0706900000000000000000000000000000000073214fedbade28cc60ecfa4e1fe2fbc05f3d71528aca315312d50214f680956bb9e0fc12783843b00b3f4f0f52efe2700000000000000000000000000000000128f87e7da7b53f28944aeb26ef0f6c99d84038af51a1d242501ec84b5a6a8593ef1a0f6b523478d9fa12e36c2fdbe694b964d74259c216c1eccd7f2b52ffa5fcf151d47bd69bd2768e6466b32eb4fe50000000000000000000000000000000001443980d7450af1e19949fb328776cb7238a9b26240cddc565aa9d52c5592083b1533e8103dc07eac80e4bd830f209f000000000000000000000000000000000afdbea7f1cec534c03d3269d50017372f7ccbcba9f096fdb2754af4d6b4956decbab2b0afb69f97a03beeb20b4ccc31000000000000000000000000000000000a83dfa3197dc65097601457a97d0df7710e001e90657b150e289515609f13997b454167a7589ef218893309460139f300000000000000000000000000000000029c362244510c342358130f877de947acad5a379295f3149d5c713274316e06a169501f889e4b9cbf86f10b9521c1bb124ceb1dbc8004a4b1f8b422d394b0480bca7c0f38aafd8f06ba090a98a1d3c60000000000000000000000000000000010a83f13a185c70ca3f724dd84efcfa3ec463d7c05360056f8b5304864b20025b0a82c9d542ba08b645e2334f176472d000000000000000000000000000000000848a6a18bcf64d083e118190805d68f7ffea8b5a66e0807b9cd3733d31ffa5cc25dbfa6ada604646dcd8dfa622e08a30000000000000000000000000000000009962205c0ba43e5101fc3d5353f429a57a97bcb84baa0942a7e7facdfb0d032b9307aed8bd2ac9094a2e5b1460db7140000000000000000000000000000000019b1012661a10d31a4a73d0cb31f7eec0e7be729a42baf560c1e90a9124fe8d5fe31ecbb6d4954dba7d943a7af773eaa5a2bf15b2ed08b33056a0733c920741f86730dcda9c06aa0e3c135a844cef916000000000000000000000000000000000e7f02c1d2ceae60f314f51374b338c329f2eaa82553c3fc1643c7f1910ca24e277f3d658f552a47f780d4d9e0ac5e030000000000000000000000000000000014b6b56afc4afed5199191ec13dbeedd797f14ed493c25658a9658f031ac8d43de12e6a8c4b1671c9e5ef78da1a55e2600000000000000000000000000000000194d8a50618ff55ba3fa5602d41cbbeadc01a348ad1484c5e9aee5fb7241fcd9018f436e3c6c6dc64beaa241513a6c8300000000000000000000000000000000052681eac4bd59e160b67ebb27582a6d3ad5286d652787a0e160026607acfbfc5b9f38b9b171375079d052cb242b87fe8c3c919f31d72ab414f91938089430bbbeaa53ad7a73224fd3f204b80fa1ab87000000000000000000000000000000000d96ce83d917204e674ad9f5e5728651f5f23df25236b0fe769be48adf482ed8c36ad9c9abb6efa3719bd35324bd700800000000000000000000000000000000107f55ab0e5b60dbcc0632c345a9e93818014d7657b264031709275744e1c6722ec63aa209e655878a57704ca6cb3bc10000000000000000000000000000000018d97fba324431fa28b8845d94f62fc9eacc0253134b923908f06889d375405b51610ac21a75bdfb27e3533dd4debc22000000000000000000000000000000001667856804a5471238ffd64bf3bf266ce3a2351ebc68265674bc86ce6faa8dd50a3dfa00c647fb4265951b3a9607ab99f749063165c6db0eb038cb9f1a573de25bf377e1fee94f31df5987f7b2450aff000000000000000000000000000000000fde2fd0349e7a47a9b6858014d551aea569ef9802629bd9520e303ef0487c9d2d399682ac16ce6fa03adb6f4b478fa5000000000000000000000000000000001858ae58920dd0abd8ad94d2f9f946c53e050fe89c61f62fccad37e17f8723a4fbecb6b1be1e3cb853f045d0dca8e53e00000000000000000000000000000000093615a7f9d12e92c90706a47abe9620c4db41e95e42e478949745d6b73e021422e40b969e9e34263778c8a4d4907445000000000000000000000000000000001006ae7963b1e1c4d8c2c85175aca958758fb380019825b09ca3f728b5356254ae4fc670aa29812320b921b48a069df622d292cbcb836843acdd5a3fb404024174cd5c1cef632d1b9b6a73f2c5f705a3000000000000000000000000000000000ac407b75ea77789748e7607b5d6edb1d891875aeef2802715ddc393818fc8cbe82cde9f96377e3ac60107ddcda7e6610000000000000000000000000000000006e63e49356c38b816736d1d7c360ceaaba875c53c98ec68cb825962531855dc6410a125b914b0ad99f6f4327f5450890000000000000000000000000000000018ffb4ac95b8ffde112c8bdbf07a1c97b1d30a42dd4a97c82617698617ceb169e8702437ff6082a2ae387b462cd86256000000000000000000000000000000000497c4b3788c4d6c9b4cd8b3d3569ac4b4332b2f76c5f03f112e089bb79d33152b2469f7ad3eadb8b954775aab73f47de816dd1bfe025685f2eff0856f9c162d73a58fdeae0dfbeb5ce076e9f9ec1a700000000000000000000000000000000003e16f2f5a2fe15fa02b6217aed7dc688dd2670c09c02791cafeccfceb7d99ce826bccf213f6a7c6064687519f9283de00000000000000000000000000000000095e6638ac74815dc451b3ec85a6a8cc18643b541e8be99052ff6dad39c971f2e8bee976ab2ed5e1cdacf92816249ded000000000000000000000000000000000f2703c08b1d707fb6de215de80b53ffbf2ac48f3dd059d2a952b1031189248fad27beec5c8591ac93625a08e3420f0200000000000000000000000000000000024ae36412ba6f2fdeb0777b892f1ed7bab0527879d93f7b71b62f437f5c1ad1f04a5a7380ae5990a455f11870c7208304f117d41a011d36f55d0cb53d4f98de3b1a6cb55dc8a76b29d393bc21826ea0000000000000000000000000000000000f7ab1908c6d4b152835f950b604b55fdda7eb55c6b90c05e98626ba7cd014683bd3e219fd0d5983e9dcfaaa5d389e560000000000000000000000000000000010b285c2884dbdd540d6dfeca704e00839337f12d2267f6a3fc731fa0f724cde19e268782b4b9c2e11ec3aef9a72a6ed0000000000000000000000000000000014a40cc55570e8f45369bd9dc622e05f03989bce6a98a0d87f4fa7add67eee3e2ad9a297615dde05e64203e86153ec230000000000000000000000000000000007f2b6a092adc595e4857e821579801301396321d4a20bccb3296a031d74a62bd79ea4ea094d2e545943138d2fc930fb6b6f5ee0549b28a1bb317cb020ae0e031dbc381075772ff582718fa49db486d200000000000000000000000000000000108834a685455dc0be10aaf54607a06100673140b012ef23a16d3df204a81dd8505d62ca3e0278a2581abc59e0fbc421000000000000000000000000000000000bca7130de9896e8d6858022f24308af7ca66fb4c91f38b30f717c5491996ef4cdb01f4d38a730f9ba9ca5af5ad1de7700000000000000000000000000000000007d60ded107a06114afaf741dc8826f9e14bac6014eba26089c4e31a73b0f30c4b6e22533ac0db7e73621cecf753590000000000000000000000000000000000b538213a703f7a0bbcffb4aa8ce25ba2a538bf599d3c0251f5e8acddfd596c9912d4cf9a1bd8d3ec070713328ca992205edf9812adf95c9844b2da06f75d96e742c0620d1cb0d47dfd9b68d0bb76128000000000000000000000000000000000cdf0b9bc829cd8537918d665e5bf344d309678d01ee80c71a6d6efb45ee8a7beca35bb5ee046e0a3fac76e1771520ff00000000000000000000000000000000014e5be9dca2f8ee4da18e5ec9c4caa891dd78acc47f553af584308c72988435b85ad21b14abf8421bdb9e25164d568f000000000000000000000000000000000accdde22a1c479e47a17b8da6f1d2b7f780ac278c68a68090e5402977d897bd734f5af8164118d613f480c1f65e5d8e00000000000000000000000000000000029614458afdf6b572bea02a0af987d178c43650ca1c80a297b1d31e259aabd3e2a2c8e4b2c044466924dd6e5e3483e6f64a71e4e7652860038df67c99d97b1e5a063370e65217531253419bf2e6365b0000000000000000000000000000000004e45cc43d4d10ed878e18df156062c799a687b8e6beedad9fa6f66ad855cd053af6918e234ff9a43561da7e67f3dee10000000000000000000000000000000009c9ae47a76c199c93c38e7213c8d6c030cfca709714c703839b9ae9b65207e83486f9c8c16373e2b37756f3fd4355fd0000000000000000000000000000000001594ce9c2e229491b22317452938115747515ce62a0d49f4dd12667f5b3e7b541b3775c9b1363cc185a539b9f7596330000000000000000000000000000000016bf68e05e32168c69ad67331d7bc88a6d130fe8aed3e42eddfeb1d92add266eb69487b246a3ca961ea6ac0a35f8da78059bebd962501b8381b67c22055ba01667d916932713d7ca427cd80d8f76b41900000000000000000000000000000000080d165c57354f87008eb97610d4a596f180e48ed3190779591a0f7e07278f8d2fa6cd21d1b10e6347f11bd9731fdfed0000000000000000000000000000000008d5a1e66ec76743ca366be80fd1cbd5efc9112dbcfa84ce6c44e8df03140ca5f07d4bafc6c6ce5f2f190ede55fe8718000000000000000000000000000000000d0e1d2e5ef384a4fb314fdce54ab7895f895b3bc669acffd48e92c6320024d4f371f42071fceea550c8cf68615b00960000000000000000000000000000000010beae4ffbb68cf6e5d0683dc0629411ee14563f84788d50b1c8755b0b06092cc0f0ef7b55a39d51945b5178e374f8e047b3448b9b404e184f7ff20466aef3dbd4e08375673ca31fdb303c88243fface00000000000000000000000000000000161486d422462460923bd98834f0cc270982087697747fe40eb9153a7923d48eda191e4e7a75964f18f1df9365901a360000000000000000000000000000000017ab168a4ec81c8db4a74d529670fe6332b3870004f696f3a143cd1a62abd747d94afac9485e5dc19b0f4262dd379c990000000000000000000000000000000001e9cc85f03039ea53253f0fa2420012171fe39ed8696ddfbed57b80b73476171e59631388d75fe43aafde52aa14a64100000000000000000000000000000000109a5d5449002f4bdca44c0bd141175d5ca1cee449302f0314fcb5f282f022a7a3cef77f4e9fb515107e797726ff51d767d9d30b38b252a0661c12dc69127ac380f3f756144801633e99bc2ffa2f463c", "Expected": "000000000000000000000000000000000aaa5de171664fcb45439b17a024806ff7e07d02294e0592ca74752a5b66f3365d1b49d6893b3bac3b8b0d10d026e48d000000000000000000000000000000000418354ce1820ecf848321a07ce22117303e5a15169a9cbfd141fb4797de8871d84d577e86270a9cbfe31c088ceed0250000000000000000000000000000000016884caa03ea641e0660a790975d77c5bb03568f873800d0559b69e3e0afcc10ddf031bb5c25c46f136f0791bbd3cc8f0000000000000000000000000000000002bdf659df76cbaaec030448e8f4bbd6b424037a8dfd7c4b8ccaa2224b0852c168f49c6f45c04f23abc85b8df21953ce", "Name": "matter_g2_multiexp_89", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000062bad6816308f1c8c6941980caf71929a4006083dd29827902ffc92ebd9b14f1ef662f3a0125b1e74dabd039f9106400000000000000000000000000000000118e4ae76e2c321a5b89eb19b58f58f44e80dcbc7bd6d619579da40e1156aab32fe81df8eeb1bd047f96d65aed8b3b6a000000000000000000000000000000000c8c93e1beeb4efe52a96e5d5612338721e3e487c13c18b02475f9ccd8fafc2c95101aed291951f2031bee5216dba26f0000000000000000000000000000000016fba44e9aa39a12ae27e3c36de1f14e3f37ffb0ceaf5fed2a0d9815eab02c5aae91b254812a8f3a2e3654cec01a341caaea75e63204e177d404898aa51555767f813c3f3ed283405ed1ee829b04c85c0000000000000000000000000000000013716488daf8586719c52fcec80d35f17d4c595b66c7f2138244f3c8cea69b819778bfb50e49ca1d092e57c51674fca00000000000000000000000000000000019cee25c4731bf48602ceab23b5fc4f764993443e3622107b4c33b29c23d1b5916380431b7ecd94a0ce99811fe6dadba000000000000000000000000000000000562b28b245b7c1ee531a320fa0f4e12d7c171c7e3932ffda6cfebb123fa7f5993e5ed5e7b7d295405e5031b339994bf00000000000000000000000000000000180c4a8158a26d34123c870bc694382352a8e4de712b650d3e45e6baa16d6950ec15d3a4e032c1d1ae8fea18faa6f3d8db48a90ddcd791e6a9debfabcb1c71c88e7ad98f9e739ee752b381b28d7656f20000000000000000000000000000000008472d40e0505d6b8b92500e8e9711112048611fcdcca2377481ae86a7f6da1571f179183301e2194a42dac3873a3ba5000000000000000000000000000000000e2c5b61c050a8a12298f76b5f15383e72b90b001fa26889b67a24bb374b63c1e00979b05450e44ed63e72042af6d46e000000000000000000000000000000000e8723eace9c7a72b3e6097afc9bcadde61462e2ee03fcd5ad1b1c0dcf39f437f80530c2a1c5e6ecdaac14e8715f02e30000000000000000000000000000000002e21e0f451d035a5257fb09e9ed17b27f0994e6d85ddaf8d33153628adb194c97db17656351c029be4d3125bd29dc22ad1795823d3834496b0a1c2c07431f9d76071db77834005fa1228393ad4ce3f40000000000000000000000000000000000dce49634595869d7858e95a301bcff8112eb73dca8a22042137456d6d4887998a541489ff09f8e006176e6beee4e300000000000000000000000000000000010835f7336dc49e62706da4ef21d8e3173629b16742c317c1b397d4f17ced40a56520ea63557d7ac7f251568f4eb3a220000000000000000000000000000000017446ebe659a4510a362ee3b406b636bea8f381503e51ac21031c7cc92acd23046d62c2f32cda01b680c0f107142ae7d0000000000000000000000000000000006ef82deabd8983ebe4255d8e06f4a1b3585c057b2a1ca3c3e1cf04b582b65792e9980e3a1735a8ad58b053b16ca03d036d56e38fe63e573b02203be04ef9e1a044e1754eb2db50c6f9804abc4a40f46000000000000000000000000000000000cd8e7422ee179a0499178c3848cc4fbc87fc25c8c882f036a03cd9d3f273f7f2bf71bd3c9cf5e30c42b1ee6e90b36fb0000000000000000000000000000000005005a471d77a35e922b6d6a45b13a90947c2b31d8e7a2e4b6388265b039ce23ed958495dbf904186bef60fd547b941c0000000000000000000000000000000006c337380065eb8a5f63cb20fc61a9eec4ccf0e23c4e0f231a5bc4d765271b9c5697bbde692b4828ae22ea12423ad932000000000000000000000000000000000f7a0080cbe72a6e6473f66ed729f58683a80815a1748e52f7b67a6bf2846b7df8e7dd8599f87fe63706e9823bfe00d21a6b36f4674ab19202037d59fd8e14369e5d3d71acc3c76985b813d81ca6e24a000000000000000000000000000000000c94834474ac91547546d7d179b2091e33c8812c1b582ff186e69b63011177283a74b549aa342a7f3882ee82ad8ecc03000000000000000000000000000000000d72c4308e9ae695acedb9413445bf6a40d59ca78bd4f74ddbc1bcd8508cfb521bfcca99c98dad8022d3d1ccdd98bca9000000000000000000000000000000001487d006830d00d84a567c5d031019035443fae4791a05253f91249b32a4b3e7b3ce7eae885b8caeaea411a90b3445e0000000000000000000000000000000000d94f17aa100503f605732a48e4f55c394a8df1421a3d7c78bc85f4cb7a53744eadcf76e1620fc54204b123d6071cd3bad85286877fa7e5a9a61dba9df5ce35083beca7c2f5ecad13d226fa32b9720e900000000000000000000000000000000101cfa8d9c7522277f2bb4bae6c09e8b93a876c749c91c61784feeb105be61c2479375abdaa81deafc2fe754ed6cd9da00000000000000000000000000000000089ebbdd489ff670a70218f5aaca78d4e7ade483c7f20de4a84d39217be8f560fbf7bbe36f3f8b8361ba16d17ce609d200000000000000000000000000000000094f094372b2315fabc219099200e7b9e2f3a2f6fef2ede6f83c82f44792da03aaad06b8cd06dc3f140746bee2a45706000000000000000000000000000000000cde6cf9a3a7018b2b1c0c26b5850820080c7e4b56e615d577a78565431c93de78348d2851d5ad9f120ddaa9ff3da31b8fa5387c5712832b52c9c72e10c6f69e9c1c5b278aa379140e75e404c4f50a2c00000000000000000000000000000000059bb8e5dc5f0cd31cf674ea78b80b67b8a8a753e51284a2ab37d3f29459250d904e70ed00481b73556970a7f5424e5900000000000000000000000000000000043c6a53c413bfa2f4bb14ef296afd97ce801a37fe63d11a842f8d66160794c1a651d70f4c836af2c73cb1bc58c706460000000000000000000000000000000003e7b67da1513656f7b08fc5a77682477349ac57e53687c82b6d98772b5f929a2b06b0c7e14481d522aa94fa3a6e1cde00000000000000000000000000000000109e07928216eaea36fbb20a38711e73fdc26e18a6967b54f308b10116a5c8af0c8411406ef6ab1050b61c23bb746b0a3023298162ebe7f4ae6aee45a8a6ba602c3942a8bd6b35636fc6b85596a582e000000000000000000000000000000000166f26d3d26cd48e498578900a8c830ce9b80f162c4b430749651b945d9f60ae6a26306ad7711a1f9d3428946074912d00000000000000000000000000000000165f1bc59c9c36d12754097ea83e9a63fb4ae5d1b93a1b9239a6f338cddf4a9b30415d58076852288c6a467ce9b6b9eb00000000000000000000000000000000198e73619cb93fa6a2bc700cd400519d11a7d3d6d945ffac9754a6faf37da8596b49b7a3a4f2cd899ec9c84f1e79b7ed000000000000000000000000000000000a4740820d60034d37bb85e3e622783852779d36d6e61f81a7eabcd094993dd7d81900277550bb4299d550d2805466aa8ff2430d2f82c6d5e7424836ecea15af0ba2d0bd6498e65c65b6cd281a7b8f28000000000000000000000000000000001714857b0ee07b94ea928ff57aae9fe003c0c85d8564456955d14fc8d4ae14a7c9bc303983af3e2999c6db2d000ea51d0000000000000000000000000000000016512cb60aa372cf5098ad514291d8168ed31bd755861dbd9ef020252c01379d343a9c058839cdec8d14f2fb9da0db80000000000000000000000000000000000af74d8ac711b6590e7041e80ca40dd4db659e42b950bdd68c56d676de654c1a47867bfe6483dfe1971eb7c1d1a70bd10000000000000000000000000000000019e56ca1ef3fffa9e131fc5bc93100577b062cf9b2acd234c79e5e54aa799a389f30002b4bd683edec5fb100f1800d66415eea22058493dbf6ac248fd2ad8b4734ebe33761f2177089a3feda396001c00000000000000000000000000000000019d1d1e1e2dd4ab86df81a8246c902a573d1fd1598050663342e411a1d1b3c8849473c689afcc8e0ce5e51a9dc9c3b6200000000000000000000000000000000190d7c923bdd6336fe3e0509563b2eb6067354d8807f66e6052e97d5997464b9f07f29f3022f78779a5c4ac155a703ce00000000000000000000000000000000128591bb699c18a7b9e6e4e894654853f6a68233dfe8c744b42e057711b8d0efb3a98bab6aaa40ae7675d9200a8427d600000000000000000000000000000000045e0560e0936b16d1e055d3d3f4e0fb42d129546abddebeb78e871d1442f4796d939929d354b0326b95e50fd5208fa9ff79e3ef5d32a751b713180be37d44ae55c59c5a8121c132c5098ff972d8a97400000000000000000000000000000000092373dfd7d4375d6bcffa415e5b36a31499e881a80be32400105a6d56b34d64f4fed09f12640a43289a710f034b71e6000000000000000000000000000000000fa75d6510b3b58a32635a7a6cb4b9255aa7af46905cafc893f29b7866e12565765bcde498dbe87df3d1dd53ab5628320000000000000000000000000000000010dfd3456cb6a8bc853b390380a13f045ab43abd289fd05e7f98839477dea1fb1fbe38ca4f5bdd6691446ac0219e453000000000000000000000000000000000112567397f3fda84db6042817a99aeccd0c46a11fd3ba44e2600deafaaab7014dba98cdcadf81b97272fb7f275ee8a4e039bc7274a3ab172285d853d368da0950203a48ef61b3c7564644762279c1ff30000000000000000000000000000000007b397f093e69874d2bd3592489d93c80d0191b157e71d08a6ebe73063f77e7c5e084a24b34da2aa6354b1815a694185000000000000000000000000000000000fcede3a39dd5f905d072dafdb6f56d85726f6f362f91f079fcd47a8c1d3bdcf199d64edf17e3db1dfc96a3e59f69bfe0000000000000000000000000000000010cfa13c84e750d8af8bbb88bd6d16adf3bc7b532447c2e6accb359a5576be08c1b25f336047fb8e01a4d7f9080d0392000000000000000000000000000000000ca0e88b5c2035bcd3a65e8bf1aa219cf428b6f80617040ae02a0ed41559804844df373ac61a85899bec83e5a6243ed42c47d0b1fd24c1c66a3cb0deb7d51ea19f0fc492f637ed5d4d03e102cbdd055500000000000000000000000000000000021f3b793680e0e3127fa53034e9fcf286f5279cd167ac1e8ba051c440aa265ec6d28fcc2f6d3bad126180efd4503fe900000000000000000000000000000000182b429f27996ee070ed27e7015bd70191b814bd02ca6558a9be81d6898161aa525197c1672ae75da92729f2fae9fa3c000000000000000000000000000000000a20b3922e07da4ef6696de85754eabf1f58f7f5d37accb6cde4f62066e789bc64bc8ad6ac827b8c955acc858b03d053000000000000000000000000000000000814faebd3b60fa1a8fb86b3cb57d36b9c85d4b28e97a2251e6bc1fed1ccb18f17664321f38f3723cf8b09a2161c6aeaab4aca860ae4bc20d33808533c9a70108b153bc4b2256003ad4bbc11dc92898500000000000000000000000000000000159f9d329f929a65e41c7a0d4c05e11db61ca7d6d82f8b92a780bac66568694656f4c845a730861fde9a313fa49bdf0e000000000000000000000000000000000d556bdc8dc959b00f74209dff27023c5521d387a40bf20ae2a98f3f55318eddd347bf1e9d856f43a4b5fcd26c3567ad0000000000000000000000000000000009b4b0cedf477ef1e0f99627bdd7a7afeb9e29afbac553a516fab479913b23a9be5e0b38994215a9e23849bb664201ee0000000000000000000000000000000010899f4dc55ac5d1f56a7b8d55ce7f6a5e0a8647bf1ef6e9050f00c5fcac9f679f138018b9aa611be73d3bdc0af2056e297500a2747f9a68b2d8d9ca5b0390369d919897c53d422cb76c5a283c38669e000000000000000000000000000000000226c8a6b27437972ce29c2ed7e5cca4b6691e3a5dbbe713b5d309ff2f4cbb95e8f1571314444d65ff5fbc3281f9354f000000000000000000000000000000000282a49d0c560d873676967700c1062013a2d4beee96a09af7e14436fda4e3d2a32ab8ee4e591decec39a811ddff130400000000000000000000000000000000167bfe499f1f4609e67134e12ad91aadc37bdabd0055ecf7f96162c39a02a86e62a7b3d39f514f63edd82d04beb1958a00000000000000000000000000000000191673ea5470e4704e361f5ead1c56371d6aee3035d92d9e1b96fd119c4f877cde6451411e441fb45aa9fcb90fe4c66ba87ca4cf226c212c80f3db5e4e781ad7391fb73b1124d01cf893169d1c50ca99", "Expected": "000000000000000000000000000000001488532d83fddf0bfd69b32f965790b3fe4cd9f64e8d17e78189c346518c91e69db2f0b742cdd5804b3db3777dd931230000000000000000000000000000000016205c470c6371d73b012a14d519bf214ff10de458605097da1b798977bd938727c5be19a10f4f492f301d2ab6c38ed000000000000000000000000000000000142cc08f61d3c9bd4c7bfd0b7a0b8693af6120898fcaff49a7fb5abdaf1d15bf70eb033d6ff09a75995547e6856c595f00000000000000000000000000000000164b2807e19135ca3b66bac9aceb371165c930ae063f3cb5a06efb8985a1e0c39023d8f01df517713796083e8c2cceb7", "Name": "matter_g2_multiexp_90", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000023bec14deefcc20a90e439bc16912e90191dc7142234b1870e4e8d70c56f695d5cd30a68930ff9b007bdcae8ca90d870000000000000000000000000000000000053a6e226f3bd82150e08ec3690f36616d5ab745b36a9990baac7ad3429a41bc60c7f7000ceda4cc9298b10043639e000000000000000000000000000000000b81b331589ac332093928faa60d6819d3b5559d32d37d2cc13c78aafa1cc34e32d317695c1c4b4979baa1865ced90150000000000000000000000000000000010dbac5e52f9a046ab88aa36b3c5f6952720e174bf8f1732e886e66e5803aab63642185aa24ea08c991edaf8375bcadd9abfe7e05e8a210604355a77f64386a01323407d9f25397769cc6dd141bc6643000000000000000000000000000000001875ef3f90df03d49ce6cede2c791b4d8503b75acff2dcb1c7c88026394dfe11481da72de4ff58ee9a98e75577b6398c000000000000000000000000000000000c8ee603d1404e64ea3ff08c70b3dbffd318736ae95f9a96ca07ddaa449818e6c5a17b2970f572f53c90be893e5c323b000000000000000000000000000000000f31af63c68481f527092b261d29d5c2daa95873b68899c28ac7753d95a64f455ebabedfe6e72246e494cc5fa2a9bd040000000000000000000000000000000009fd06bc51d4dc51de9fad6d1eb763809cdb5ccdba8e0427859d878904bdf295983b318f311856728078e7cbbecb0c5b64be08e7c2fd15ac0116ca941b85615c6deb38fe85e2c0fd22997e394b8a67690000000000000000000000000000000003ce75ecf6b605ce73f4e215b1aad4799f91e624daf0deae3a273968490bdbdbd0250686ee91a1c24c2e2f2b6024fa49000000000000000000000000000000000e4d9b65d71b7593310fb5145677d170663c0ca29636f7b7c50ec1988bd2d2f1c41d542d4cd8fa23fad94bd6a84aef5b000000000000000000000000000000000fa4accea53a6362651f6c6ad2a68d20b5f549f8eb961718e0c14cd05249a121e442a6a588eafc83d6a43d8baa66882400000000000000000000000000000000121e325406767852620ddc45677495fe3e0851fd3c70922896a3e92033347d2fe8d07f4db8f26b8127ec39d619d596030c391dff1c0c303c77b2a1fff24f50250dc793338f7d7f8f1d54bf7d87ab37da0000000000000000000000000000000003a0ac3ac37932b71672b9c48bdbd368d64c11f57ccb952f633bcd10ec19134c65fb2cbad655d773a90cbec2d9232b3b0000000000000000000000000000000007553c470bd8f38a48490dadea29df81ad901ecaaf1eab35b1f497bb58acce77b883e03e78702930dda72e2277139a2b00000000000000000000000000000000044973913824b3326b72e62ccbabd8c9f1b5dc81b423d0dca37b6f33972d993a681c326730717036bc6f0286da9177430000000000000000000000000000000017b0407d2864cfb39dbb0a5fa8deb4ed4a690a4042153e829f51c56bd0f2953a440d8305a318e6d6f67970d473753021a2d728e013e5fc3e1ca24c105a0c268cbb4f152a97e318f3aae33186ea6bc93a000000000000000000000000000000000b7478dda7053590ed013b7c23431a21626e748c3843e2332bde0bd3890ecea95b6104bac420a8be5f3dd9b075203616000000000000000000000000000000000e6dea641181cf796f62b196652f952ee2a26ba998cce1cfe9d65ae49198d10badffa561e2bd818eb2a7f350c122fa820000000000000000000000000000000003c79917ad5a9c7f046b34e5491ed015695aecb00760f3009dde4cfbf88ad1c03e44117fcb6cdbd5ecaa8df8760a3da100000000000000000000000000000000034e22ddbdeb9dea46c71ca2144ffcc8356c1a525c5ada69a6d5e5c1786aaaf0cf532e31a2f78371e04a72e8222ed4c7e8da0c8da19dc441f53c54551579fec5d820ce2e3599824b24b7c5bf1847c5890000000000000000000000000000000017964112272360a38d3bddf89da922ab50be076bf71a094fc8afde109d3817cc2db633e6408f5716b76d70e30ae00c0d0000000000000000000000000000000009bed28bbf43846ab97b92aab9ce094b077bbc59db648dbb469f21842058ef20318a1a8c18045b3de555bd8c76132ff0000000000000000000000000000000001297110789c7aecb0fec577f6f4a4de14608d9aa26a8de68289adea7f6b53b766b840d315152ea346f8c10b2d2729e730000000000000000000000000000000002b551c6a7846b96c6895e55ec435397af70eb435dc1c562ac71a44c36936c2c6d3e6a1e3545513516513391aedaf9ca76e90965adfc2fe52e4341895e6b6154fd7a097e052b59e4935c8267a6f0e63800000000000000000000000000000000003d463ee4d177d78849fdecba52b7e83ca90d54177ed39e82b4e80c17994a6a2bfd9c46edc0ddb256f8955428f30eca0000000000000000000000000000000011dd976dfeb8ecb7d7f5cd10c235131709fb16d8a827e83d7084266c2504cd1f5276ae3333bc7fbb4ebab48c0d97a9930000000000000000000000000000000005fd19477fffc246f5991603b48085d95256b273631bcfc16f19c6980a3ba01ac098061faa149b475bfce37d586464b800000000000000000000000000000000103ac3dd682aee109dd7fbf60b50c28cf7e37642f05b424773a06f6cfaf7e9fb01d5074ade97ef6cb0ace2e1fe07d54c7f3f352c7b7a9e2eb6c87edfc99e2df3148966760168f6abb13ee482f223a01d0000000000000000000000000000000003208ce7f51a96dee053cbaa66fbdb921c2c3b42ead78b39b4f1df7ab49f05cb88d0f4ac18de5839749416eba5535d4b0000000000000000000000000000000001ff7f9db52aaa0fddc8e96a67b99353b92d7032f59d200bf69da3b446d08435d2ddaeb93584d3b68a1934566187922b0000000000000000000000000000000005f05ccfa5704652cecfb42979c538823fb9d11a00222a963d00f1a4b9a040a0222dcf45baad40c6574d85e5617dbbea0000000000000000000000000000000018637b8c3ef111f6ad4538464c250d780e7f081802bdf720f4c925154f4667c5d50cdbc4dbb7d0b2747b97d2ba2280bfd35c4286f19a9fe8117e37132ce4ce76e28afee25ecca2f66de3cd5e1c83235f000000000000000000000000000000000eb400becfa5521b824a4288885fe46642c31576238e94f95e9b4bcbf62845ee9d9ee122f87d36fbe668f0e605fa2ce00000000000000000000000000000000003c8cbdeea0d09590e1719ddffa0a116723f0fe85585583f3f271ead66fbc2107873181915cc41eed3ec6e2c5669e9d3000000000000000000000000000000000e61c0768561517405952c6462f1c5df95be272251d8a7060624b62f9be310cef64436eb2c4c04e8352d7b75fea1756200000000000000000000000000000000036cd74a8efa8a1fce7587f07d5c2a6c4b7ef161b0faae037c9bbe63bd0c92b83e514c8c1bae4a5d9866c0889b1b914f3c2b40b7968a39fe8e4f24acc25b6c727887c3c44cc89cf62eb14a78ae47e8680000000000000000000000000000000013019d0fc8b93da2c79e473d713d94af33eaffda65a7a49d0cbae9f5259b8323e6f29b83da9608ba7d6ec004fb0710eb000000000000000000000000000000001505d30bf8f7c51994d896d91e8e2259782e2b49bda834015477f18c29e64da4d31f8b96edd080267b77a9539afca06a000000000000000000000000000000000eba929531615d9c0f59c4b33c1fc34b81e9c77cd8c6887099d850b3e39326d7caee1feeb101222f22bea1e9853d06ea0000000000000000000000000000000019d88f62cae047ddf2cefe497495f890d9ab8499e56f72488af65095e992427bf821f63555a67b0afb00d6fb441080a010325465403dbd4898beb740884cc325923ec3e1d7483540377d8bbd02c11382000000000000000000000000000000000b7c8f3d0c56b3b7d96c0a24fea3394551a186f87acbbbbce41d1313b23762945bae2e911725da4211614b456b508c0500000000000000000000000000000000125316f64bdd0c5bcd26a0e5bcfc3139045b3a44c8a8dd1cebbfaeb83b963c5a5abd4a5961465cff261c0e49189278d800000000000000000000000000000000095a327f488b901fe7dcc9f9ce6f4f25876bb09b053b64e9f4de9506a0fb95fc0cd443473c2cc5436750581d39b8e51f0000000000000000000000000000000015d406b31c791ae2d25ce462304c0bcf341686d7967c9dbb6734bc28b02123b1730d0a673fa8071dd90950d9411a2b3909545b90dbe35b0d5764bc72d45717e0c3aca6aa77c73178fa8a3ee9fec9cdb3000000000000000000000000000000000c7029af9422246d0a30784431d6bf9eca09481589438fe9a6d2fe1d5e526ec3d176a3d550204aadb85353d99bfe3ce50000000000000000000000000000000014a0dcb26c40693ad19a1edccda05055a27ca24544e933d01dfb964571071f94c94233f81e1ead0925d24e6d3df2c21500000000000000000000000000000000147a55ebd83c746128ba9c7ac57be125ca5c95f80f891e2c5893caa779484bdc1f9c3b3ccc4223b2343ba939251f7fdc00000000000000000000000000000000125622a040d8b157432ad81b8a83a9b1f0920b92680bbb65050b4862b89017b3bfaf81a3402ccb383265ba7200ce677feef0f8014102664a300ea9a30fdc7afeae3cc338fd45cd421a1bfea98e304c810000000000000000000000000000000013b394fd7a0f3d94e5fe4cf5cce3627d425ec848912395565b3e61ffe89e56be799c4779d3b9a0222ecc6538ca3346e40000000000000000000000000000000014ac1a87b333caed0f557fa5692d1138a8c1e92d1f9acdc9f357e2a46f27513dea42f367b046d389dc831610be4fbcf40000000000000000000000000000000011fa243a0aa8b0c01c7636387d60021afe6efc223b7deb69d030651c369643188b9dd5e08d6d031d71dd11eca1e825ac0000000000000000000000000000000015bf8fd7fe438407db7f1b0b586b2c285777c5b6dbef9e45b46cc0a50dc831f32a70e7d4316d4869bc769ff6de58ac30c8f1e08cdd72ed200253211e3b9947cb2a5fa24079b6920b4a4d3f1fd78146e80000000000000000000000000000000005ea57c269c9d43d3f17a83df04c95ea7e7bd85aad1dc2dd285ccdbd52bfe707a1d2476417e848ab119e62fea30520af000000000000000000000000000000000b99768ffbe95e315b244bf996cf34f8ac356664adda5aa7f4ff8d513b2eb5934b8ffe0fd9af94bc9b934e0a8bbd51ba0000000000000000000000000000000003b02c259df189370dd2700c5cccfc8b212a4b332a083adf9771503f5bd0c9ef040590320fe4a86c555a4ea87531268100000000000000000000000000000000003ebb1e610bd055d037a410cce3ae06aa654950aee0210ed0ee79f7a332be7342e308347d7b17a146a8b4c623029e08a7e25b1a60b6c6080ccf1bfdc37aabbc2bf92079d9356844f7f12867b3e2b2800000000000000000000000000000000015c4da691b5e6242af870e06b29bcde467b4644f01080eca60a28c7f941590192be30e6a4270a36dc8959b80235600aa00000000000000000000000000000000080f3d3d5c35ee24179f51ad854a37ac4ff867a2736a0e3e8f3312ac98c7016beea6ffe2bad1dd4842d6ec77995ff97600000000000000000000000000000000130c29dc633aaefc831b0bccb13fde1212fdce8cdd17beaaf1d06e74ef5b1b69bcc219c8d63f054690af1b6dc7c0d647000000000000000000000000000000000767290aaa1ed4c1dfa5603d976df0715b417599445ca577ded7d99e685118bbec71443fe1d9a65e0f23436353df152cdcb456eaad2b7c71ca32277206c1a1dbfa7e0e84950cbf14aadd455fb58e398a00000000000000000000000000000000133e997857f47f8d6278b8ad86f4692ba0dec9da336f2726704db593af368dda7aefc0b218ce1674f415e0d9e2dee5c60000000000000000000000000000000018db87da1272bd386f7d8b5245dc2de30e82739723b680dedd36f4ac4cf5042bcbada1e1bb307ba444431d73a4248f9c0000000000000000000000000000000006580be3e67c7a615408aaf9c95c0956678af0e2b1f536f1e69588193387f8a05b03d5e1060ca60c4fec9eaf3e72d39900000000000000000000000000000000050bd9879ef9eea147678f552cedacaee84562e6561b3b7338fa8f9d514099291c3f2a3723fdb22c88f1c9243d411ccba6e7b19245341fdfc5927cdae57f59de5f3fc8c37f8653e5aaca87db682034ce", "Expected": "000000000000000000000000000000000d8f69d90c871c08ae09e7b3e62e36514fd056c41fb596fec2fc9ce8509ab4f6675d7e85aa6b4b3197f5ab781f6f2e490000000000000000000000000000000011c4bd3cd156c34065e408efcaa5e13ad23d114458b71c2a6345f4aaf82af76cd4362db7ba9ee7e1e92ce72e242f570a000000000000000000000000000000000712dbbf20e9b24d20511d01717a3783608386408a258c2261fcdad5fbcab36c6bd21473c3d93ef8518975256c65a945000000000000000000000000000000000d13747be82153aea8076fd7813ecd7f60a214c31e88e25b14dee5cdb9336599e40b136d9ae6deb85606d35406b2675d", "Name": "matter_g2_multiexp_91", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017da08f2faa32570d95b9efd2d2fe358faec1ffe304750dca1dc3a273be3427c70904d58864f76afa19b0fe33ab1535f0000000000000000000000000000000017de677b713202f23baecef2b0618da140af624e56b876f2d7a20cd437c3868ea00ff6cd9c8908c1ef323ad294edd9670000000000000000000000000000000011d50aad957c54868aed6d848b2e67094b129282cc2df56c41d6ffe976d02ee83a592c33370d3715588a074db503b3e8000000000000000000000000000000000b8aeb019d120959b21627c1dcfdfb67ade22a948fe433172994d4a34084ac9e1c11333a9c663c87acf50962e21c728e92898d9cbad829a5346c0925c15b585de18869adfe796e46cbd56828540571b70000000000000000000000000000000001312ebeee36fff8152324a3ed24c37eee50b3099619a33c7a6316470ae722548b4b9e0f0640453caf53f374dba504830000000000000000000000000000000005ea81d2e5d9edeb3ed6c200b75beb731c31ad666e6e37db72ffd0265378bffc2724047c7c0c6e3f1598345fd390e9270000000000000000000000000000000017617a836beb12e637c5bbadd4fbf1ca2f5cc3280814ff5cbb5890b31cf2d2faee9e3ea8134af97ad4feace50aa194140000000000000000000000000000000002606deb5d57dce5b3d2e5f7ccec3ad036992beae238673641ad6042479ec3cf83bcc0fd03b7dacb9b4bb6c181ea9cc8c193fe87634fb0bdaa1700466881b557c470a62464e8521be311a95dff65eca6000000000000000000000000000000001203ef36896bfad2a2841689a964328fe4ce3d83798671630d0c8876e67ceda03d99555aac46d984f1d3bc38ffc134c50000000000000000000000000000000013e7461c256c8ff9144b17f8cc2e270aa94b64be62588280baca2ae6b6efc4d32b3800eb84da62561e0e96d5f0387a3f0000000000000000000000000000000009454b6a810647350cf0b364eb1c2b719670af45bdba9d7d1a534e23d4e810c3ef4d9318532e46fd104a83bb10159a30000000000000000000000000000000001034546c4288f642daeccf5b56beed2ca2d946bb4391d056df9c6fd6771048903fa330ec16d59d05540cd715333c4bc73dd9c99a5aea019436e3c91030d03ebefbf6ea6ac69222f1870fadae32f55ae6000000000000000000000000000000000d7782404dc6721f52648fc6969db33a9aa209f8baf5faa9678437c76c9e1635fa6d22d94aedefc90112223bb81ce33f0000000000000000000000000000000001e442e548d3045d1589817d0b57dfcd66fc64ff978186f784bd576faf57607170d49364a72189328c9837c9a2d8b0a0000000000000000000000000000000000da2b207bb7720aeca2e6ea02b65076770b960d4b7a96ed941a7f409757b952031a472384298acc3948bdc485088501c00000000000000000000000000000000048f85bc05ed78c692138f27c3541ced11b6b0ec158b43d133c3450a905416682fbb8c83dea06a06d294c48289ddb829e74ab390c3f73c62eb1435226e9b4f9b921ea1918a61a614b9bdbe9eebd1cd790000000000000000000000000000000017134f787c920bc15cf2228a186dfa1d10194087f28b6dd8f03e1c86226928f0eb1c27020a5cc74d94b50c4b4e36b8020000000000000000000000000000000012fa1fdcbaa81c4cc1e37447cae51beb29e55bb19b91e2b575afa3754589ee0151cd9e83573edaaefd341f381d34f4f8000000000000000000000000000000000ecafd00cc87a773a13909512466ed11288c842716e1ca5c37a4d9a4cd7585136c86f32140fdf02e2997a6e19e3d76a200000000000000000000000000000000104cf007ea863dbd473d7dbab6f55e74062b18986e9bc09bcfdc9c23e4bff8683f73aa998a5cce59ded10499d18a0ecc4dee3e2bfae3820f611c30df232c1d9c6bf58d40b3530858c79f840720d78d72000000000000000000000000000000000ffffc98e55f4ba9a642c40678d625690464bea39d085dbc9c99b4c36ea8bff5154eae3c315e1dec29aa669840accf290000000000000000000000000000000000a3df9595167048c52b8170596d4127968194aef7fbaea4594a27c6af05c54bb772928a7749d74311038d1c115e91b2000000000000000000000000000000000b317a3abd808e94a7197e0d3b2515a147774f78d0cd7d36e1156da28a26e33bfa76d75c6e3ae346f9ace050c9911cc6000000000000000000000000000000000fb5fbcc2f74fc30ae7e32143f219db7dfe5db6ecb09cedad8f087b6df56bf9693c8b7d78aace064e7c31785f6869541795fc8e20dd30622876a94afce1c1a76e3b689d6848903c21103cfce6a8a95680000000000000000000000000000000011e4b907a72f34af899a6c4de211af5fbe0265e5bf24d406798de53ecea273d5df4f4953d13fd7c9dc3bb0f0c143e3e4000000000000000000000000000000001623de5e87b6e1ee920e1b7d979fb9c431c12abb47b93876f9ddfaf28a7b673c18be634f96b813f7e0574c55b628a8790000000000000000000000000000000018ba994b02dad759ee79301b42ea20d7545844c0ea4bff2f95dc9420194cc4196fff12cc09bc0cef03cb7ba868c273700000000000000000000000000000000004b3527c8d148bd9e6006bd298ff8d7fe320748dd3f6d23449e874fc0c2f58d933c1e038a74f60fb6032cce41a3dbf5725b49f325e76733eb3c1a2cee5467157b2ee80987abae43d2c4b93e5157f083800000000000000000000000000000000129641af11fa92056236ef135843b2189d46d870381261d5781a5fd6f2c5cc1861ebb2e801f19f3adf2216609a9e196f0000000000000000000000000000000007b4007c55e47f6bf3aa420ad75fd191ffe0fe824fd30c3f1961a8168922476fdb3869822704999b044feead470e3b8f00000000000000000000000000000000174209113e2d8c363b04f49487176dc6d9eb4ecc0b22daa7ecaa5548d038b3b7c23ebda4f1b6845425cee13493385302000000000000000000000000000000000a58c80a02b7f93db01d2f8e0005839625e6c4f121f3d69115f435526a7f7cb53177caab4db86273bc2d2f0474235f31df49b30dd6aff459f64906eb1a9c9b2067d4f1b75057874b2fee17923bcb906e000000000000000000000000000000001738a03b46a8ca3f3d1f4f4447497c59f114005400f06813b24ff462ebc6f27c1c3c788b5f83f65958cadb34fddd08f40000000000000000000000000000000004dcfff2bc9ca0282016f38df484655cce7b872b1ff047351ae6b903e05f457d7fefae93104f9dfb549980394dfad2760000000000000000000000000000000017cd89434225dba07be137a73892faf0258b3fb19e6c8cec412fcda912c0613f2a925ad50ae485187020a371ff2dbc59000000000000000000000000000000000f1f9f87d3401e7b3b59331a89d9535adc973f869b81bfd8892a37117d8597ebab2800c966e623469792f4ae2a8eb232959e0a33b1fa12e0ba960761b09921b81746b8df23e808a8de09e7f5cbe2bf41000000000000000000000000000000000bdcb1d2a782541ff7884dde4167ba060fbd4b117944ae69aa2ff685b9bd7d475f45adce0c9f92695b4f4ecdd48cb9b50000000000000000000000000000000012a55432678043888bb9e7e47efb17700b3e702e389d0f58dd454224a02da3f190b2fef4c9d3e2074c7bef813fb56fb0000000000000000000000000000000000efa51ba64f1e7a1a269dc083179a222afac916778a967098582f55a41394bff3747f8d024261959f6d399f44a40d0fe000000000000000000000000000000000845dd0974c5789a85c3cb09ea441f2c433f0606928ee1b177eb851530d6e6b620b4fdcaffb8f75623435dff99b3ad9526ca68383528f6a871c237ae5214b49c18c4f3e2f3ef5dfba39e69eb181143d700000000000000000000000000000000180beba92bdb95c7803fca0407e29929ee64e03d61cad96ea0e6c469c5a888cc5ca5eb20983b3418a8da6596a5f1b2ba000000000000000000000000000000001322f7356eb3069fe20063f4be22c44426162dc8fc117e4e382bc4e33bdf3d971ef662fffc1d58ce187c33a43a4c853e000000000000000000000000000000001601a0aadaba846f11ba5c9f48e13bda1007ffdc1b8bbc9e85e83e569e9ee17a1e9e780a50ce617e6c780b8155675f2100000000000000000000000000000000105b2c213aa43ead42d9cfdf1d6c0559c25b4b86af43d4493bd75b76986d0d4f1d9b3bf9e3922b5c08a37a1629cab7d8f1f95a9d1d4e8e7d0f17a954177253709d988c3a77c77d35b8bf70294bb358c20000000000000000000000000000000017bc70346765b7160a0a5e556805c7944304acbecde06cadba474c51f05f22445c3d943674cc8215f973cdf11b9ea2e9000000000000000000000000000000000bfdbe202619a1d95359941c249b25462d3ecf09fabb878943a8a37cb9eb94abd7e6399f8d82f90ffcf904f4466cc5b1000000000000000000000000000000000f048db8530a288fef10a5ef9bb3cdd9f3d3b0ef4824609efad96bdf52d7c3b10ef628fa04f8b6513485e55f653f4b990000000000000000000000000000000004ec35f59287eadb1738bb50b0e2ad9d280bedfdb0a201e72594bfc4322ade0b7ffd6b532ebc7796cfc71f88a194bef4b481f986998d863c98e55a7661136a8f19d7d4c57f6036cd642ae16c82cdcfb30000000000000000000000000000000014424c77af7ace8ebf66f556cf219919712d96d24438466ad620221ce1ae9b2cd75b9c526e25df7fbf3c9250583757f500000000000000000000000000000000198aa00723781714152b3494b76ea3ee043b363b3fa81806cdf7e440b4cea907f226a3c038fb95c932710dc9aad4c9dd000000000000000000000000000000001360e4c775f6fa5e987231dce25ec67f61429ca9fd8160c3074383c30a8c0d7ff068b1d1215b2c0cc87129d9c9aecbc9000000000000000000000000000000001280ee6160800c4b0f82d5c2775238b4b223d8a0ac9a8f8013f138d554ba31c9fedb30e0eb5c330da17f5785b2717422ad872848d72367467094675a819f9aa6107183aa0c8685d5d84c27b3aaab33c1000000000000000000000000000000000f1f84251204d9f9328f79a45d15b311984df0715579633a82b5a9f680f6645cbe748b0fa64b9ce1e696e20a5645d6d300000000000000000000000000000000156901506e502a09917f76d825614824dfbc34d019ed53c2ec5395b51512da512b27541bc53331444eac2f618ffd5357000000000000000000000000000000000ea8736a97a33112bea9d07b729e973e3a942422f1d2b24c30e96637b535ccfc10cb5930bb59ed90bef604453df8772100000000000000000000000000000000187378477f60e3eaa225e89d8532bd95babd4a5c51729cca800d364b61575704992639dc5035138664e8e074ed0820033c2c60541fe17fa8e71d58184a055fa8b1dd0bfd16ac2baa912b4472c6056122000000000000000000000000000000000e5281c1c9210269a7f5ccd02cd5a7d3648b56d9ca6a4ee50beadf151c2601e0291fe7f1b89b694500e6c636d4e445c4000000000000000000000000000000000d5d5399f49697e46013558dfff544383b25f3b60681ba5fa2c5e6edfd3924267d0992abe65cbd5109ba8a1c6eadc7e30000000000000000000000000000000012a2104aa92871dd8e41ae1ae6dc18ceb7d0f361a5a4fc67936454b8866b8aec1602dd596459cccf6d9e1319ec3299d4000000000000000000000000000000000268795f6f9892f5b476c3a534673538647300203a51a8ff60b530094608b5fdf16297f02ab7ba41d6fe556885f064a4ff07c19ad4f10ab47e73b6698f9febf3f28087614759e082e6e717588c1caff7000000000000000000000000000000000a5585961328c52e0fefff16e66e3367e34339dac1a20cbc5e89b78804b8bc265e6e3fec1da6a62cd8a46be2f08a6d960000000000000000000000000000000016fbbd698784beec5a636332c0b20fdcb68fd3015cc6d18b541346a5e6af76613e6fcb14c888a2b8133c0f4132fc079300000000000000000000000000000000041805e0adf2a32153b89d1131226cf0ebd77cde3116a168e792ae8b88ba2edcb1fe7275658a384251b805d282ee039c00000000000000000000000000000000024213e4a8504cbae4875617b9b78473e7842ff72415ceacfaaf2e8b415f9f7e411989bada8101be72f9295dfbddfa3f240c881fdbfc414d3e85ead1cdf166ed6929d0b2ccbc35f0811473757b6b41af", "Expected": "0000000000000000000000000000000003c4f051d528166f256d9356aa9cb885db5680c51990d9474a948848888fb82a9b86daa7a2273725ac8ec564ebbf15db00000000000000000000000000000000010a6c4c7067f511ca8f1b66bf9ffcbb275c7575540909262f7c4332c3d75b2f6d2f3ad2848c0d455410afb1cd60c835000000000000000000000000000000000ee5e582554b3930c5670d4e3542bf32e8b871849d7859eafc077bb2b533e936d462f614057f9fc09c4010afab501c1f0000000000000000000000000000000017fdbcaa065d301adb94a60dd20dbae71512d369fc82c556ea0dff66843be768be942e060752591c6eb0718985d8e313", "Name": "matter_g2_multiexp_92", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001353960aff58d45691c5378a0676a8e837260f5819cbbac9cd75c8cc4c6f1e17b9dc9843eabc0b1dfb27ff7631e4e52d000000000000000000000000000000000d6279a43d3526c035e88b0b640b04d42ea573ed07323aaac1d9d5570a8be64782682892415ba2be5cbb13f56e3a44db000000000000000000000000000000001250fd14fd003f88eb6e0e80e9f2ebe204475fc6c06cd10fa45608a17b7039afe0326474ff80c357f86c2825cdf7a16d00000000000000000000000000000000186cd91cfc8ae625e302946f2b393ea67e1107c0bfe938f5f36d28879fa0c0780c847aac77d0310d43211152c1d5f5d314d5455ff1717bdd545f4daa37e145121e7bd9636d7a2b65633e5ca5a63f2d98000000000000000000000000000000000e55a98e8b1e59600e86cabb5e8db8ee622009b1618ff0df3e93fb55b80985bf2a8ed060aeaba53773274d4186934f75000000000000000000000000000000000bb7215fc43f465f51fc8265477fc8c79493966f040e02f0eacc4ebcb3414b84fd94ded822bd24dd5ad5720f12bb8313000000000000000000000000000000000b23328e15cda8a576ea352b5dd7ce382ec781deca6c23f646e42f0cf63e28669539579ea51e3c0afebbb58e1e8e3243000000000000000000000000000000001716019236169bdb4af7bf7d7ce0aeee7900b74023acbb16f6965c2abcf28917bf88d0f9d5bc26a81710496f7821fd4682cd8da62bd901355a60b37ca14ce65d427bcf9551203cae7c346a49b4fa8626000000000000000000000000000000001718a4d6f5e78524d8df23d2c589abf04e3567d2176539a30b9f73c6251de573caa60c2881f3da99c48d48e9aacd7402000000000000000000000000000000000ce0e35721379077e6eb3b572f7f7718bbf775b116521c14acbd3ff19549c75d50bf70ce84326cbc3f9e5e53605d8ecd0000000000000000000000000000000007cb3305ef0d2cd7de4dceaf25d2eff44d4f437e065f6b244bf1b0611c891626eafc4b759d55b45d76e94b85852df1de0000000000000000000000000000000011cb56d2ed32a46bd951836f8e0f92d3824a4cddf011eecf1e2d92d81bff407a04abdfcffd60ccecda6e9443b328d51eea2c7fc2050e9c1ebd05d15f197b4b1be61c6820c8d27ade57d85109d7f982490000000000000000000000000000000011ba705da23100f853882dd166d81ee1d7621550d156b14f7c2123e2681887ec3724626061db68b2c63987325b27d6230000000000000000000000000000000014271414fe078a80587269398afd127ce34c8dc2a4851f76613b81dc99d766d75c703949c1093b04d66a301a79d89bc30000000000000000000000000000000011b7935ff284b0f812b5da5b28ed338dc4c21ebbc7fee04db834732b11fd76092db0e8d80368255b0f1205129081e9af00000000000000000000000000000000104ff0ad2e3db08d3b4890b2e54f29e456e627cefc3a4f07c1109b764dae4142480e3e5312ada43fec9ba96ce587e8a4e3bf7e661d54796c71437354d7d3182770f10ab450827512a423d3dc82d5b43d000000000000000000000000000000000c60749ef36d63960022f3127d0ab4e12acf05ba1e1a136dec89be388b9d7144c1d78c04df658727763dbaa9725bd8b90000000000000000000000000000000019932b1c205a765bc9de0cc136999deb153222a9dd9e9ec3660fb6daef56242d08791d440888e69ca0da2bbe0fcb7d79000000000000000000000000000000001764790d12f5ff79ee4f2c9fadd5dfb1cf47db70b9e86018bbdbffd1be18df193c7dfa71533afa381053a77e02719c6400000000000000000000000000000000044b2b0211cbb407281ab2abc4725c2cd791b313bab8779954a2461ce445cdae60d4a9efad9f90f80e66b1438514e0f0d3a364e7b217dfd649d1e08f76393372d8768bb0fc85c79ef4652417ef1637fc00000000000000000000000000000000175cf9e7eead650e7ae4fd657bc288b6b6392773bf1bbea48e17172a5019637fbb2bc0a3d0d1e3b8054564935c908db200000000000000000000000000000000136da2a625cf72403d0861b9cd947cdad12b1f1e6cdefc4aab6756536425285a7953a1b892df40ec12ac3430fec889cd000000000000000000000000000000000c2d10c6d71cff4e1deba1984bfd17166571e64659ac91b64c343cdf587c29d52a2266c00a57c01feddb1df6439d21d1000000000000000000000000000000000384a782fb31278f49c840bb8f0552ac2734ef36bb3d115be7df20333aa747c92db990f7e879399235d122fdba0eed76eef7b05d5c725ed31269ae9c56dc7ae35048af39ab114319680d4af69be7e7c3000000000000000000000000000000000a9a821cc63e7c9857b0f39f7444a1e00a422f7cd5d0575c26bc5c6b98313abfde51e3f6d5f4c817193bdf391344e5ba0000000000000000000000000000000010daa8c7194a75cea757b6ae4eee85006eda459ff2cf155b1b5f19c3ad341972f72e28b781c4878e8919c7e5abe9a1d5000000000000000000000000000000001154d5d5764aa2b8818a9dc5dce30ba2197a86d0bdc7dee3e600462e295cc3a69dfbf8db34acf138e7a1f16b62a45717000000000000000000000000000000000b4243a09b05a958d78ba8ae25fd3fa85d520b95e56f1dff44e556b221a075f8dd3370313886d9dbfc56a75697454d72acecaee3dd4dc11e341b3dd0073842d90f641d4dd467a6596f337a6147bd30a9000000000000000000000000000000001820f953fd22b71ce00bbe9e9b78fcf5fb28bcb925f6b5dbf5711e00470ed7fd2f38d7291d40514ab4258807f29150270000000000000000000000000000000007b737b56a2ba33f76bcf66c0b26fb44d5f79879273f6ab21ecbfe6a5744da289464ca2b46c55edaadfe3210b907f3f7000000000000000000000000000000001735d1b39c5369bbf886c5063a96dd12b85e56fd9d8ff9d84520918e1dfeccb62bbbe1c2ab440ccecd0fe66f6ec55853000000000000000000000000000000000e591b7709bf00bb2a87e9edb95720de19adc41a42378cf9ebb930c6d3f5993a1d7b6320040d5c69908685d978be8f980cba585b847bec40515a257cb839c7e5d677d17b7313c258e83d630e65cfb5d2000000000000000000000000000000001732ac410b2a7d10110bbf7709dc6fdc91ce742f8cb9b2c3ba37ba5f0934f8622c675753a26d04a176e24a630d090d81000000000000000000000000000000001111a52da6aca10cf40127fa8ab7683505305e0d474eed28a5e1735ee6877aa00c1bd598420876f2154b814660f3fe7600000000000000000000000000000000098c6d19c2ff42c2c57a4924693325de1a91135e3474ec699b70439d034469e72e844a5511e23dff3948a66cc2a2165300000000000000000000000000000000175fb79e5e54963cdbb133f38dccea2d1abc3cdf005c17e8f2de6dba9b9dbdeff7719983aa9ddb602f0cf966fdd430e0b8cd305c650d2e1cfa91ef0aca9dd0d785d7570d6fb67e61fb9b6817116a05440000000000000000000000000000000004e88468d35d72dba6b3e4b9ca216b75b5d20c447064a48bee6a6ddf994b1e22fd6ee8abd60c627622daffcda219645a0000000000000000000000000000000015eb2ae16e3310b4c4ff557f0615519c13f29109d9863418fdfbe6309b5bac4463456df8ebb0b6d9022e294cc16265ea000000000000000000000000000000001288ffe0ffdb96708558d914bc412758770d048c4d50523e2b134f8468d11a57da97e42bea303ab7137e2d26c0b3b8f30000000000000000000000000000000003ce563b63c50b09a80b71a1a82995238a9de31aaf189c6d29307924b6f0990854507b7dc1644f689c5abcf931dd5a3c825e5f9d81273f306a065fd064ae24bc2c5ce8dbff6b22128753663a218da8a30000000000000000000000000000000009e39ce653485caf699ae1d1d9cf2b8c5ea85b80ea042279e57f0beb81056159e49f73d67e7b1f9ece9f9ece7dcd2cf50000000000000000000000000000000008d6492cc335660c54e4a34b29b337b5800f1ef992d124524c799c04c852ccd3cfc01bf39515cb8b96151753147e8c49000000000000000000000000000000000ca779d87aaa3a6552f9f1a10b0d2e635be90022326db04e6072f326b919ee55d4124b9268f55751dc0f18172bd327ae00000000000000000000000000000000112eea543d6609d0acfaeb7be98be609f03304f50c3814ee8a010283146e6b5dbf170c7314598cac06efb9ced1ac2930307ff9660ad0c24cbb139486638a2556687f88fb93a290a1d174bf87d780b3fd0000000000000000000000000000000006624dd7f6eb043da41a36a15752f370eeb3cb2e6bd88b337b370fe0660c5ba8fe64f62e112f91d2524e9324f3a049fb000000000000000000000000000000000415b964484c9246385cf95461ab955ed0390e20209ed405d84fa8c8af9fa7ab39ce89049691a63c61b12bbf6aa2a4e80000000000000000000000000000000014411d7b2db7c9ee78ea14c6a315df3d90827b511db2e2423d660176384d8f8afd284879b22f5aeed73afb2eca4be52200000000000000000000000000000000105bfb471340e76f28901edbdbfe2ba246a8824b501ae2d4a73cffd2690181347c1e6530804614e88e2bb13a8edef8f4bfa8ee3b44c70ba2512c00a1aaecede2180b08ac3ac8c550d70407f0c12e027d0000000000000000000000000000000002b17f4b0b0231be229d87f075998435560ce9046a8b0e8f15e3a9f07cd52f3316f6d8c00d6a872362e7066715cf990e0000000000000000000000000000000003110eb232154f8a06834e2ddd33c0207ea552f439a6127b652bc261158209a00654e50341d333cd1b206a915fe0691d0000000000000000000000000000000007940e209c8934c185e4392f12fc0afe3d234dd1ef3f92df18d76be8fc42bdcdd6d1ea8d5bb6f07b3f3caecbeb5ef27f00000000000000000000000000000000012ec903a8442f68c03300ab02ddd08ec935d97bec9050d26a5e276584592df3ab87d596f90768d2c0918099b28963be58aa85b50e5f4ffe375599cbb912f41d35acbb85a324880148f9b9003c4265bd0000000000000000000000000000000010fdc16bff0fea02b325c672fe06297e0669094e2710d0baf3838f3e234c3f776bb3fd41b967c9ebbc72a6bc6eca70850000000000000000000000000000000009d64ce322e39d5b2d0872760a61a831877c450b1cfac6cacec52d4070b0f179dce90afbdefdaa8466f6a6e2e83ee8da000000000000000000000000000000000cddca46f3b24e05b76e61b4584bc716ca7036afdd914731a61347e453a26d07549e9808e553ee056bd47e53c75eac8f000000000000000000000000000000000451cccaebe1a188d3eaadd40090ca594f071c8b6d0e0d82f5b2d43fa784f8437e4226104c4cfdb24ece1ed75375aa616810c6cd59b14ef4f6a4c2702cc53c65b3dc84988372c1195980417c583fd7ff0000000000000000000000000000000005832ad778dca8dfcfbe741dcf311024d76341d5920b6830cb75893a112c9d86719583d1dfa7287281fb73fe21650c3500000000000000000000000000000000044feb86b4816e45ffb98e9a670fcb039fd9d8844a2c7ff9b7752f20e619195fe6ab1148f30afa393936d3605fa4c8da0000000000000000000000000000000018db9365370a8c703364ba6d9c48b3512da46cc603a43c3fb91c0a8ee59777d7cf9ac646c3e4274bd950d7de92ebce840000000000000000000000000000000017bd82310e251701cafbf8c4dc5b9e6c88085b0df287b6dde7887e1f64f2d9487a25b31abe07aec7d99a75baa5983195c5ebc09190ba3df49d8ea55cfd18370b9d443f9d9084cf84f2236ef4723d2d470000000000000000000000000000000002c1df194f01dcb503dcc8a283f059b82d141274c8f37cdb6441aa33f84f16dd288d566752a93ca23d26ef5834c0658c000000000000000000000000000000001700fa4459dd4e609453284f4f7dab479342675a87c1cb42b601908296557f39256f1597ed3b9ec38ad0a40a2c728f0d00000000000000000000000000000000135ed4f475eb99397cf204f971215a0303316a3ed8b62b303b4bf756ff753410b7fe263c4e97fd4c4b399c319ff3ad98000000000000000000000000000000000a487e179bf1b73627af9d7d2b43bc0e43127a8fbfeaea7ce958ddd53ecb27741eda187745e3917f1cbb60adf0286f5413a56b176fc835b7e825c817d432b9ec6d51b0a66483dfbf12166ee979b664cc", "Expected": "000000000000000000000000000000001327c57e16f03fbf652bbacd16cf574113860eb87b8f2f6e498dc5dcc4f2fa63859d922d88ccd6683d503d0962db5336000000000000000000000000000000000cb06948c539cbf686f6936b6a1ebef2e148d98c531da36272e0334afca5c2b16a52da542a0fdbc3bf764eb877f5778a0000000000000000000000000000000003acddfb5bc4fd5579d3f592977365840be4d3cff96434e5ff4f01ea798e4401930a1f5d91f8de3ff98504dce398c2ef000000000000000000000000000000000a5a332805f704613eb085d6639f99667d0d9247cae34eabcfa399eed551f24c5d5cb05d6458530ae270b1be682e71f4", "Name": "matter_g2_multiexp_93", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b1b06a76e5bdcb6c1c2f1952b49e1820a9d8557229fbff8740269a0b819b91cfd0de20db0afd76a2cb0fbc5fac12ec5000000000000000000000000000000000347654df2084082efd32cba2b270f66b0ed30fa8713b27949fc9d270ee8eaa9b9a7896d7a52dfd8faa3e0cd112a24e0000000000000000000000000000000000bf5b7a2c0c8bc223ab334bd1df5d9fd4bc0c635379ed2b32da13f6178e07217bb88a4bc2eae0b975f2e566f657d23aa0000000000000000000000000000000017042f8585a07304995853270b1b03bb08484104f7498a12bc865f2a0e37e662fc4b0331b94ee5690efe74056567000bdedf65658ec3cca48fd48e844337159af090c5d1f5e9d713ac6d0fe1e1f193d2000000000000000000000000000000000fcbc73d0628537eae417f8efc67af0a4c9c375d82406086bdff669911fe1307576333c389f189f49677cbbfe2ee98730000000000000000000000000000000019d552b85b1445660ca49518d202afdc67b0eb5be02c8d3482dc1b12e5d40a4ff95a49ce47809e4d6644d04aeb67b3c2000000000000000000000000000000000ed536c0f19f592180291bbce59a72ce5e516199dcbd4fbba736cae2edbe3cfb860ead0325dcc8f8d9be1ac126dc6cda000000000000000000000000000000000f5d4f0c0ae3e76b1c41edbbebcf1ff17c7cefd41e7ef8f75dfc10170834d05820149d5f721a8c6460cd0181571fca97db65ad6bcd6f485eefebda0badfc64e9e7dfe7e911f3ccf4f4fb9528dfebdae6000000000000000000000000000000000d6207f6684f8d2f083c963551bbf0a674ba40e691a34ebe6164ff80ba9bab2cc23024a896d7b906fb74c95016a9adfb00000000000000000000000000000000145855e7d610b50cde39db8995b127145d68fc9bea3f075f65b7793acbb14bbb313a1a39bd96fbea6641baae02612b000000000000000000000000000000000005b533ee83cf72f0e4d9c9ddcc6b91f4364e50a106becf766987c490d559d0f733839ecc706bbc9c2c75b243814068a3000000000000000000000000000000000cd8fba13b9ba7557c7577da183bf50810fb14eec7380e3b3d4f2fed62bb36f2b5ff288736bed0578fb6f47fb6d22ac86e0fa09884a7ff4c801ea0722cf6bfa58a46fc3d36058e8c395ea8fe56d9fca4000000000000000000000000000000000fd6a466f2eb12f6337ae9f9b847ac1481820013142af1a474229c5f5f5e1c0bb2d9678c19c7a3a1aa22cfc7b5052e0e0000000000000000000000000000000002a0340f5a0caf5c66719f7d546972bb4b89147989280542787d281901ff036b7c69d41418c21c43127c0158593aa5cb000000000000000000000000000000000deeee37ef96f26a4907e1a8a8f3f030dc09102799bd0c6dbeb1d208a0c86a423d0da6313e0be03c026da5614a6a576b0000000000000000000000000000000007220475449add59b3cc6570701528dcbdedacb9a3d39674ad4aef4d94114f24d2bff32f40b25af97ba883905ea6838a27a3377d7b9ff3aee2ce1194a22d7115b09a9fd53fcfa5e7f76bd9fdd35559610000000000000000000000000000000009d7023ebb73df81455f74cb2708c14ccecacd49521a0cf67ecb6edc8756e286ede59eed54d89eee5f77f178ea8fdee900000000000000000000000000000000002ad48fc3192634e7b01604678473e286afb0efe67a4377bb885d38b59ea00202241fb28c93232ce7c9a3dabb136a53000000000000000000000000000000001934664f2bfffb254f0415d6769f4e2ac710ee88cd822bf5da5df3a2541f887e4155dbb7e8056efb2a0370d6f9173e3b0000000000000000000000000000000019df518e1ebafe95adf683279729a3298fc8d7eb39c9a3dfe4b6665153f970e243e50dfb16fb87b3be54192f69766659446a62ef5760c995cb3cd0984d607c232c1eb0df5516a501ce448a189a3134d8000000000000000000000000000000001870048d360f397877321904563d35bfd0817ce464e0078e9605a4744e2723f49f9cb21dd3d6f37f1f9aff5a6a99bc530000000000000000000000000000000000e29dd0da13ac451d013d4a38408827cb0e739772e1f250d31e4192ddc13d651ab576ed6b8f4ee44e928fa663244999000000000000000000000000000000001646183099579322e0115ab0b3bd6c814e216ae6b2b80206354925565b7bcd97bc12668b7f3530a95409456ac99bf01200000000000000000000000000000000092f6f594ad0d92c9c64f78c819c44320e6bb5dc1dc8fbe58acc7ce3c101e49a74ae6d50b1a668a3b7436dc445e3da345f0c1a7c2dd281f7d2f006497f99f65d6a1e22f1d9aacb08724b3576aa19e19f0000000000000000000000000000000000428ff447de18dcc11b2c5c679bc2efd125464f589013c6964ea6cab33d9b7cbcce3a5d6177bf43114ee256f23fefa10000000000000000000000000000000000d1ded695e88dae6dfa702375959831f4bda688fc0faa289dcfb90a07f3a7963f2c9070958561909a2051a852cc15e1000000000000000000000000000000000c39bf1d11fc5693167890246c81133faee93a8639f459429757965e0b62e372153ce53c61f2c539247dbe7747b27d1c000000000000000000000000000000000e84ecb6dd9cbd4133c22350f07a976ae13dcbe4c6ae09ccb023f2118fa2dec68c20ba2266f9b571bbe30dde97480e0a94c1476ae0a62c502aa096a371e30ca885dc13fc417e3dc9bc00bcdf516764100000000000000000000000000000000015e040fc8753f06ed1112cc06e2cb7142a4fc984834f01faae718c17cde782d5953547857ca9aeee1c4a7d91df060d330000000000000000000000000000000006789ac15d719a7159b650b757f7d3cf58fca02d3b8f3685478ad5e5b1dca0508dea7a8203ece97c7c6d32b2f194458d000000000000000000000000000000001824d75634043cac3fd17ff0bb141daf7010f70b5941d8f75f1ae076713afaa7e0a0a25fc71038baf1b1255d64c914c6000000000000000000000000000000000a2f71bf85af6392a8a070596e30225bec9e3dc12c70e8df7c545bd6bbcee56799db2c9a8d2504c4f90ecf6a5e18abc9b677bc9f1f7572f808e969aa50efc519192ab8653c71090e5cf8cdeb1a3544dd0000000000000000000000000000000008bd859ff1f22d682f86e1a0e3bdf3a332ae78d64814720687a3de44c9bdd7506d2696b4daf81a94d33f64983967fdc2000000000000000000000000000000000d7b4b958e0087f8edf18a4370ff98700764c126808d5c52afd3e71ee326c766c1e5712dfa351cf5b3c518e52133ce780000000000000000000000000000000013a145331bdd9c93e63edbabb9f6c541a7c4dccb1705f07eb353a0407074a76022a8e5f5f2535b41ecf6474649e257bf000000000000000000000000000000000a12e461b7439bff0dddb560dba21ec53ce88f71fd3dc10723f3d8742ed63a1ab725f7e9619ca1ccb729564dfbdb1be7f5ca580a25a5c87015f57f7c23cc51a0beb5926c84d44659e45512da51aa0cf4000000000000000000000000000000001430a8184c5055008a06ea22ca9c997d1a24ddce7e374937c32ed1e487c80537b238a589b5e50b86fa194666bd3410e80000000000000000000000000000000005c78c94f457bdda242deab79524bd2beac82bb1cb427dcb2872b56d1f46d11fc9d69ba132004958fabc5da7d6d103fc000000000000000000000000000000000e985e8ca038b5dadc9fcaf22699e75cad9d2effa47fe7d4c579ee056b1e34ccc540372111a665041062fc6c39e05d170000000000000000000000000000000018c865243534fbde740de0ffbdeab0d38ee878c20f5d84c0226d1f2b14ed3359f5b5b909808b6b3789bfcab3be75c4cdfa1cc45c35e266a82899d8ea0c9c1f96f96140eace41a8758a87975b088f0231000000000000000000000000000000000c5b10541ec34dc0a8b8e42d9d6fd6f4f71e1fe56b5afa323f4ade35c0170b5e224a66771326d9edbddf2bd38c6c68ce0000000000000000000000000000000019cf33c19936f7489a1bbc095d0f5c6ddc1f43bccf7e8d1b30fb8e8cd1ef747b483b9a8e9faf21cba7cb17fbee887ad70000000000000000000000000000000010e83916faa7bc9de9feb8a7f34ac6f2aced06a771b662cbce846107245edb9c07632782300e838957788a8d88c8253c00000000000000000000000000000000066127bed5ac9f2871500fdd68a03ade57c35449d4b4186b9fac7c89e91b4ebf2f2a02e94d0b578aaf60b32017f147a493d2908aa9266844eb265c2b1c17f8357a5ff039836ba83c837909f6a9d0bc03000000000000000000000000000000000cb5a734a28b44f04d39ffae049fe8b63b138411661ca6dba00c72cadd47b50ad4b71e858e817561682d6ca378ebbe870000000000000000000000000000000000baf4d689baa09aaf763ae7e142b801223c8ff58f2b541ee4c44ab2460fb8f6dfc1e9f61a8d73aeb92d7d08c281cf410000000000000000000000000000000008a0c736f19bd0005c9d25f88565b1355e53fa3403021577de536712ec986567184f4dd626127ee80dd03cdf9044b2ba00000000000000000000000000000000063ffb7a3b4e057a9ffe233296c11fb462136fc4b187be6f9e36f9e6d335a3d673ef8b9ae6f60c146a075a1789f389cf3b94325aad8a2c80971a781bf6f6bebad63ee37405ab7e903fb7094beef14d06000000000000000000000000000000000c33d89595d039722222b9b9ee7ff1a0dae896a8de97f202d3aca00bd81d0169f14676efc4b051bbd339dce862d8b60b000000000000000000000000000000001109a24dc6f70bea47e040b24df395bf561cf5f1ee79e90c9b0480fff0795677483a85e6f2e9ded4f36ca849ff39d6f60000000000000000000000000000000009c7878f3a4e4e3149b72149a7da91bf527c4d7c94b15ba80b02e0e50b02a2c482ecae9f458a881c87e669986514f6d70000000000000000000000000000000004284448e42187c128578b801f76d421fc508cfee9360a7203a91d6f9cc7ccb6ed3211fc5df9e15f14aea98bc298b2f95143a8e734824840346078aec03d6760564870c5ee2b2dc13f8a39ac452be9f5000000000000000000000000000000000271ec1a3f8e3364ba8e101b49c0bb17e2b7c7f27a4aa4d4db5c07203195050f30c1a05d33c524a84b1a2f0ce31a587200000000000000000000000000000000082ce9d1da5d7f192c537b2bd617b36b65f88b308fe1ff85e47c64b62dc62324458493d1cd1da9f5fe308d27545fb6510000000000000000000000000000000000b30356b59eb04258096d0c3f357fb04471583cfe6a060de5279bf2cff4413678c1716ba87d0b6de6b6e79a96ec26030000000000000000000000000000000003c02470a14211fef14d754f6f71efb33a06a76e099093a5b9512f907ff819e1e0e15f14995febe48852007bb5c380bd0dbee37fea759c2a58cf360c654f85298e8ff44b3f900e8229c3f838345d053b00000000000000000000000000000000172df3290c3c5044d590eea59980d02e02d4fc6fe7948168492362de8f0a85df0c3d09d8cd8b206cc4d1608311ef4c130000000000000000000000000000000010e4d14065315a0d9e48204e47955ee9652b08318251a7836f32e6fc015d4856444172de44b3b88efa1b54dad346e9b1000000000000000000000000000000001549b9c85cb2fc2c7495d7ef6aa1452e58937baf58717037069e6bc6d72ced3a163f800991cd26510e71aa64c44f66170000000000000000000000000000000007814c2f1734fcc8cbf9fcba06b936c86d0452a2370f8c9480b97105e42f9babfe0869cecda7e15500e9d8d868290201b92f9db82d0976f4c379622c4028002ede2ab17f647bca3bbfb159045cdb342b0000000000000000000000000000000014f849e9749a5ff6b7b10daac7f5934be5f783d49c8593367c4243664e01b1d3552e878802d7dfee823e0122e9fd46f90000000000000000000000000000000000d0b32d7904dbf08269ca3c6ae3fe582501f55e32337ae361fe4a58dada560db54205e56a399aed33bce8758a05ebcb000000000000000000000000000000000cb21440baba44c3cc6943c8cfa2fe544a652f06423d3de06c2ff734ebbb544da07ba8982b3009b6c4857b73ceca570100000000000000000000000000000000174ef591975fdaa0e3cb05bbb4140abcb38f685ce4de77c95e2cec1911985557b77d9229940b8c9157ccf9fb553e8e0d98df4ba50cd5cb5a02d5f50b3ba23e5f5b0172a46cc315a0a94fed05551a68af", "Expected": "0000000000000000000000000000000006da1222c7ae02843ff289931fcfcb315f621972f45e4fb4160b8bf48cd8102d50fb53d2c699afd36892d91f5e608784000000000000000000000000000000000523048c5de2d0139965c976d8c3328666e99c249104712719e992334442245e955cd6b14a1e3d666220617d78edcc630000000000000000000000000000000009f669d4e7d89fa8d999d8d5a6323da9445583344276bd6a29494a91174aeeb29132926a893d5a0eeee9c3048ebc0dd200000000000000000000000000000000099ee1c33d6f09a8d063393d2a8debeaba93027e31f7b23c5170b6747f56bd6e6494de966dc280dd67a38d39ae35a336", "Name": "matter_g2_multiexp_94", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b46cd281a09b85d977e88cb2251cc61cf13181522cf1c344b114783c4fa22d08f2d008faea3dfee8ea7c56aa35ee39a0000000000000000000000000000000012b530bd34f5b31161355436c7dc444d41d634b0ac3292c0096558618005fe82d189e4b208a48240dfdb4d50ad44dc620000000000000000000000000000000014d334e7835d4bcee2698ca4f643f9692f28d8090ebb8ed8f67c60639c64eb116067e5e8a6d04a0c88c765c608d57ef1000000000000000000000000000000000578cb4e243b4b20c99afefcdc0e0a9e308ab4bec6d655a8c4981a711515c807067472a6fca30060d776213b8ed98d74e49662df81f6bd455ee554704ff0c7d5a589d91e017d7ab4c500d36378c17c8900000000000000000000000000000000046ad1212696acdbb686543d284d7cf2e1e8e8c10af76c6ba51d55f060c006dbab25d3a789c71c428f5bdde9aafbf6d5000000000000000000000000000000000a6a880d52fed6a45bdc61d9ee78d8fe472e76ccbe155bddd0e2a967f4d116bb9f2dd4c62cc6f7224b835c8060213ecd000000000000000000000000000000000786544589eda15edc433edcbaa46d4953da72473f04169ea64dc114b99f0a58181d41dce1fcaf7f3109f66aef02e53900000000000000000000000000000000030759c3bdeafc94fc8fc0b03ddcd96869459bf54ace74582aa06c179323ef076aef89c09ce8e7bf9109ab2e8c8fb0be79eb26c79d78ab84c4d7e48e56889a601fda17901037a74fd79355e7536f3953000000000000000000000000000000000e6addfe0db96a7377fcab1fb92183fd7d7f13ec003fdfe0740bcc8cf03d8cc602d5d808b4bc874f34944a65b249997a0000000000000000000000000000000014a4337107e716113d8ba0fc7f75e85edd1c132e2b3dadb3f9cdec1440f261513646525314b5c0de6fd372472aafe877000000000000000000000000000000000d472ee0484ed831f8ddf7ad86faef5443df8b943c6fd4c3f94c8d52d9eed6fbb53107170a60f25be52219ca4816788f00000000000000000000000000000000035d06ffc452c65a31f80c3f8a0c1e2d15e32d993ec06c50499bc0fb8f669acd3d2182ba23d942489ea922baf61dd49cd2918ddc2bfb7f7cb3d7e74b43b9a972c5b51ac20ea83f41d5b51034b5714c0b000000000000000000000000000000000ef1f5f6b3041939557368d613279043d1aceaf5fee3ed90b3b756ad409d700fb41e62b3758c8c2d325db7a37f339c610000000000000000000000000000000004d66040a8e055399bacb6a1e762b698afbfabf789caeb957fb7a3dccb01d7dff5414e90f5a14961c4e980b298f834ec0000000000000000000000000000000006efe9e66078000c26d375e87ffaca643aae9cd3f8337f5718e0e268b74f4b7838f7661dc0ce60f557e162a21ff467160000000000000000000000000000000014ab782a3b2c06af7e9c2f28f1604cbfa8a676a874853bf38195780751d306936cefd1cc38c2192cb756e28793d2abb3e9a8159fd7915c15db69355514d9dd26c66fbd14af969ee576401b1b782fc6d300000000000000000000000000000000057270788a199a894b37a526a26bc4d293780d365a6b66247e7417884d543dd752ef7c89f2f4b38f4b51e6f9d86b45ad0000000000000000000000000000000000b59fedd6798487ec09d226a7406b27f04f7983075b4659ca6a78c6bb8aa83828fafdc6488518e2cba6fa4193de938c000000000000000000000000000000001105c18d92b4192833302814ee9b176831e57fb64b703ab3c2d3f440ab302c8fdf7ddc81933d3b1adaad16038dd6dc1f00000000000000000000000000000000020509b08e6ed980df29da649051c7095edcd4eed4ce95cd797da430cd09062a110bae21b6f73daff2053fc0289041fac818ce6e33e581595e83cf8d33a62edc26ed38c22f20c6949a94e2652bb954cc0000000000000000000000000000000007be348ccf6a76827d3b9b33e7a89378c133c9b226e47dcb205ee061423ee6e1b838bc262a7befae7c15aa385ced00bf000000000000000000000000000000000689787c19192ad55b9c6c260a5ec3aa203ef71f0b746eebf10f82526c4fadaa8570936d7049c1a46e7f3cdc455a63a6000000000000000000000000000000000306965b09678d481aa4c754d56a0bb4565f16f7523cd0b404fbd39dfc3b6ed483f5239fa30f13aa3e87918ca039d5ee0000000000000000000000000000000000a2586143f9610a96eb0ef86593988770db5ed49663eab72f8c368b9388bdfbcd02fc6bee09f4fe055813d140ca0fa89ab338e94b31d22947dbeb20fce3150127249d2db6107d95bdd032eb24c49645000000000000000000000000000000000018f46dfdde786a88e582ff6addbecb4f58e12c2625e3d6440f2e5b5781beaa95cad6f63b7d132e84700e7bd344fe3200000000000000000000000000000000185a4fc339a95a50551d53c18bb0dc3b74e9c164729c2b0d919392f7aad2be3ebae3b8f676ab81ea05233b3039918ab50000000000000000000000000000000015395b020a9d0bb336066c1347dd91c557b6ae7b8817cd8a2cba9e5bb149ca3401d661227c26d52a9be234faea894c8a00000000000000000000000000000000103d9d7e33a0767554e13b57dc756981488a3c7dfcc026ea84b35b0af21193e301226cb5a4760962707d19a95841be9296acb797236dbd0316fdd355f07b9b45c9bc626f73105e87c376af4d7dc075d30000000000000000000000000000000018359aad8af59cdda484232b885d1b14956ec04b5584684b13a64d97b8310c283e5d66637dd75de405f5f4bc65a6879a000000000000000000000000000000000849fd55e4f3d4dfc643dfede6356826eef21290b84f7e8e226deabbc84273d95f7be5479e9656dc907ec367a7ebf8f60000000000000000000000000000000006ee01b54eb7834b4de53f821ad46f467cadffce6df09751b728d0952bfe615253d7ad173892a52c6181810a815bd90600000000000000000000000000000000161472d45b56dd9fd276fc607f2eef84c5c843ea05799e732d7eb6dce96c632335949e1b3a06815e410e919f4cdc3fb360bc12a8b34e717b2c410d026660c14182250d7c66f8f88dd4cc94e550421caf00000000000000000000000000000000107ef91cf3a3068c4e5644676f7bc7c5f9ecc361524bf3fe2ebfc606f22f8f83b38c0d4bae89f3cdff6119cc27fedf820000000000000000000000000000000006a7f7cad2fa9db8824e4e30da7158f7737d2536554b904ed835c37add0341c07c5220db0f9801da2587a456300c7b75000000000000000000000000000000000f6dc3adda42dbccb1d1e3fea8918f5572e8b26ba3011429e754edd28559b731853761d33777f4e767094f80e63d417700000000000000000000000000000000107d93537a79173ba9367732fa3a28113ec37e053cdf31ce6970dedfa8a9b4cd55238289be9a6f40319e3dfedd132f95537f0f732fee8b882d254a81704d2310c05dde186232f3cffc05401fa98302150000000000000000000000000000000019dc19a1663bb05ebfc0b7cc23ea9e07376de413f77e15a685a3f11fc19bf0ddf38d5671e2a5e6e31624cbcd47a19cf60000000000000000000000000000000019e78aae57f327fbe8ce794afc22bddde08ff9bc9ad3527601cb1fd5dc0b8ed8fdf3b210f86760954b48bf61d74162220000000000000000000000000000000013954a533bf871e99f4a7d81a8b9931c480ce7fc47260c3708c590ade42e6b7bb887d4d24aa18642d010a8170cf85d34000000000000000000000000000000000a561d3f64ba31a6d45ffcf1bcac95f8f665133a1e962e31351ec78e369042bd3afb0c43d12b3087168c1142107241f31a22bc0bec2501a505cc8e00a24792bb380ed451ab6f56fde07ace8b6c9348a20000000000000000000000000000000007149094366e29537b0ad7239ce04bf49f253e4b746b9fe440dbf9b425bfff21064fce66e286e08c87dd83e22a3b499b00000000000000000000000000000000045ead132e0d03c842656cfc82a45c8b4a3b0cee7a5d071c5f235791ff7b5ead071b2c529b446a15aa8837aafc11222d00000000000000000000000000000000013159458f2123698ad4e7d41da47ad7d5083b928839e346a32f2307ee69f643ca11335d50e47d328b0079f1873cc7e800000000000000000000000000000000167edcf807ee723ba70e352367705448047c6b5223fe703381af6bb103cbb24da739ed005b14fab5699fbae6574505a7c7b10c801fb9d929432cbbe994b404d3baa5633628f396d20d047fe2c2ac2914000000000000000000000000000000000feb6f6f85903b3c8e4d6ec2ff234775f12727fdf7c35eade09c9773b004270f659b00248338f0b749d6715778f1f4d90000000000000000000000000000000003300794df19b9e472e8b869a2762c07a9251cdb96b508dfecdbd62fc3c3843b37118d216a64519bc3bdb71e40f9bd700000000000000000000000000000000005fa144135a5d6cf1c73055750ab6582b4c6d368566172b75902b1fc7a6f5de2a251ca7efc7ac6cc6c0bded14df02b700000000000000000000000000000000004239a7bfdefbe78116a588810328024b1bcebaf8f28f09387dcab66dcf2b02c94002df09d12db369fef9dd960783c0b84f2f3f31d9869799ed8bfc2cb129dbbeeb096d771730ae2863c4ddece66158d00000000000000000000000000000000007c8a24005575a3098c12ffa65095bfe227ee59e5e978a7ccab7a9a72391fea61690648c102ce24af723945bbcafece0000000000000000000000000000000000323d57bec7dfbb4614c8c3b286860fbadbf71901fa006149053ea614dafd56b1f3d6a86fa55bf1cbdfe8af4ff08dec000000000000000000000000000000001180b2b0b9c4c12f6d06eec07bbf6f5a220722015fe5365d1c4ca9e58ac9c8f67964d8230152d7a2220575c756bdf8b0000000000000000000000000000000001969a364c447f07d0820586bade587ccc816e50696aa0c5ea4f1daf6cd577769a890b44caa013d93e7f21f5ea269aa85c62206fadb762c23bf77f69f69bd492674bb92edb39248ad2a432f819304e6ea0000000000000000000000000000000008a51c01c3bbed13d42a4da626a8b89e2811db1d83d7de3332b36881ad14a5c8668ece4f5ed2b71204810457aa3d75cb000000000000000000000000000000000658a56aaf627e3f776d3f03caa2c00425bf197c6fa20c92f563f48260109a8f935d0d1638f5039486ce0c0100834fcd00000000000000000000000000000000126d1964f2d964c290cd7364e175ca4a855149e5c4ba488829a436b09ee5e21f6c964e439739f15317873088726bd51f000000000000000000000000000000001803186f88833393bd853970ca4fe414a43b7a619ded1f9c830444b4d43a94e9146146e2284d690436b395bf1e3fad15a6f950de53d07fda75ab43f73982c2684edb06317568df15b8712dff2ef782830000000000000000000000000000000002dc3756c7f4bb47559cd720a3acf4159290d7413e0498877d1fe321cbcb7cdda90b6c8b4ef8e27b2642b82ab9b3174d000000000000000000000000000000000c7490f1ccfdd91aa37a3044d265cb0612bfd9c065c370adb813b2d96f02d44041e79921d1b8935dcdb8c83ea4460ef30000000000000000000000000000000007beb34bfb9ba9b6fb590c7e830400888095d1958b252d187c184de91f165e12599d66345341292fdcb662deadcded030000000000000000000000000000000001ce203d58bebe1eb5b7cbc6038f75b2f7534bce9f50e7e4c91d6cc5ac1bb68d9fd8ce99206c5ec92bcabb71672c6ac195a373fab5176d124f783a36eb2346dddd5c4eba9e24e4c0cdc4f925e2e24cc9000000000000000000000000000000000765acace3e238e51bdaa08c0f6d737c9de55b5ce9ac3523335f0d35bfab6f4e7e2944b8aa4ee031ae9d39d4db96e9ac000000000000000000000000000000000b0fd488a6f9e92c4bdb5e82b52a0035f9a0aed7f69ec65303632017669f34d11552f849326e4dd204d58f50f3ad124800000000000000000000000000000000033991f66588b5e39eb78c7cbf62a74bbde2fa1b7c96164cb58040f0887c485b372e0ef4def9d38da9c6f5c4df2d59a700000000000000000000000000000000187d41fa7905739078d2c2f8775394f830d20352a9d91e97568c6929412f356009239bc9e1da3a8c766e89d09893b5b5319d855218eee020f9cf8e4c0b6004902f0b16eedba8a1c911476af34f65dd40", "Expected": "000000000000000000000000000000000dedf92894c567ee656051a7f02384edc7206152af6d3c5f662ca02559a3cc349c6b034c6fadceeccf652a396dbec6c900000000000000000000000000000000089deb173bda620678247a7218408594efff7ab0cebbf627b93ed37e553cf944e09232b92afe2f5f31d29bb9ae442c26000000000000000000000000000000000178bc39b2ca8b032d3cde53d2da3f8797026d78c76c51381b377c79992f027cf55ba4e182773c99c99ea6293a948e5c00000000000000000000000000000000195d9cb91537e77e7a4be4370b982b6d36190342ef6ebc2250a9cc8ef6ef45211736ce1f41da899178c1adcc4927a9ba", "Name": "matter_g2_multiexp_95", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004638ececd7f626a069b1bc3ad9d0f7cc71e5f0c1b11711fbfee1f81466b574f7a11de8161e55eb574ab367f56b9d6480000000000000000000000000000000013ef4f403f139771afe7e97815d3b3777818a3054d02125d3a25138e504c8c2c6696061572322aa19ace9ffd8e3ff308000000000000000000000000000000001910f776582f5acbaea626d2378e9da133b63afa087f25c2cfbcd1e7b34f6a237f2e9adccc303f9d5efe22496ee2ab75000000000000000000000000000000001963bd62098614c4ca2fc2a9e2d679c2b74bf9d322d34377cc63c3b8e7f8a4eb7d6d440d081e044606402fb3f51b0cee2a397c2f19a8c4e66df0e062f179be2f45a0c5e104588222a1a78447512f299b000000000000000000000000000000001935ecdf4f21cc6b510321b4ed2663e339954cd7399b9d67f1d9e2ea7fb9bfff8531f83ab59d3f0546393dc289ab2dd7000000000000000000000000000000000f390b86fb4cd4c1a072a83e1d1198a57a650fa6e94b69d983b693c592bc0c8fcd9a46c6883adacc4c7e2546dcd079fe00000000000000000000000000000000136beae11ea54ae26a8d69015ea7793675625b2013dbeb081a5ed877832849d67ac709b81fcc4fb322b262ec3776c0c00000000000000000000000000000000011f1df574f63f679b6464df463b58948fd337a4b3f159229ba0313cc040303345e75a3a2b0ed0dedfbefa89d8331d074f193d5a575c80a3e7599923bf5a8ba8a48e8f98322d1d8eb1da42e446d518c1b0000000000000000000000000000000001510378fdcde4027999edc99d49bfb46423ceb0d740829e310f8a381a7632fd0d6b6aa3533c2702a5ca76d386ac0145000000000000000000000000000000000bae237bfcc061552ca07eb14300cf557c974611885aa6894f7933f7dc7a0a1cc3b5587bbe1ea5fa604e3cee1db5f7c9000000000000000000000000000000001743207a1814990c798dc3de272a02b1b194a485bf09faea382dedd957861dc15cbf981f9906cda50cce2899785b9a6300000000000000000000000000000000106f902004c66c80437392e92cad73bed6b73010bdc7b6a75de4c01f0b6fbe5b8d1f47378279bfa42b3af05120854ced07f2013742ddf2d35448feb80b6b7aaf2925d3975ce28ed2b1ac789886ae26e400000000000000000000000000000000123362e41268f7821fcd2294b032c6a51c6d80506eb052ab6132267fa248a1a60c3e4eb2e75a1674bee1c9d46d82b9180000000000000000000000000000000006296670461ca67081cd76528446867e1a4905f88742d0ed8d1f7baf86e0a5e5ee86c8b0eeef07c14dd821dee0143bea00000000000000000000000000000000058bff9544e4e02c063158a52a68c93c7544e8157d37159dbb99b51b09e3d8f5b307bfe63a10fa409e20a35219ac244a000000000000000000000000000000000b135edfbf53187004d0977db94eeabf426ad7bea84ad76c6ac771fa186a073d430af76d717070e3c4057a7a2da095984e637a80a4eb1b2caba68b6828aa18f956c62baa7c5e9e591a15156c5abb605000000000000000000000000000000000133d3a223112dc5665e78fba8fc8d040d133858d984e66d2382d5e629f9369dd127e93c7a4da77fad98a0520ebedfeba000000000000000000000000000000000e88515db391bcdeeed2a9f64d27387af0391bf832164fba79100b560d8150debbd703c140dae3ba9b1ec35c1f45670600000000000000000000000000000000042583722c69a19f413392c6a2b75c8ca969be85eb951056d7e1d94e046dba49c346d5774009b8463a40b0576ccc1a6e000000000000000000000000000000000ee61a9eb6ad497c57405a44d798868e22b4fd5b8c480e9938cfdd3f1817eaaf331a9988368680158c59c2801add0a7a27671631f9afd9d2e86f263f5c17c3c11c7f6e43efb6d75cb2cb8250094f228900000000000000000000000000000000020352de9b4e8ea1acc8589bb22e23dfd0ae3a80de9e21bdb3f6391dd05a012e635de9e1f5f450bf4aab05728c054f8a000000000000000000000000000000001733593b94ec800bb59ed97dacbefda5ad882a8023346bdff8f471c5613c67247e27d72cb4ed8cdaa0f236018dd2128a0000000000000000000000000000000011f272a3b25bc519fc3e229211b846042031e22fbed22ecd0d1a4ef1d05feacf105772d71157e3d7293575aca257cd5f00000000000000000000000000000000153b4b4d7d65f7bd13d20fee4812f04706c96cd1a0d27b7e139c47299805e0ac86e8941aa38d90331c78a61c2dd56aa3c2decb1f482f3eb48e7f52b89f6452b659812ef79bb42fb25f03aa9969faf9bc00000000000000000000000000000000143e1f6dd9397f0e89a46c6ec995bf6c87ec8a72b309f050dc5b3134e00e2a16327767cb0573ca5ea9776215a5815df500000000000000000000000000000000186cb3af2cdb4562bf2d0c180079547cfb345cc3943fd7f9203fabbdc1547079cb9ed854f9b1a47f513e318cd409df83000000000000000000000000000000000c8c9197fa5a1e66b371a653c5d18c01fed8d17a8aa92d89b2cbd954b9fd2931fa61abb6676e4851dc9481732c6195610000000000000000000000000000000009026b259e840cb5264f6aad6ebbb09661f5b6d980389817309aef99e4e0cb228d3a7a06e6c25bdb1aeafe5acdc44441911eb1de54fa8ccb746336b681504fd08f995c864a8dae2aa866862f81f0e7850000000000000000000000000000000007bceb74ba86c07d0fca20e4febd3b12b1fe9f786c9a5da0531550244f40261d7ce728498fbfcfe16cc235db6ed42e11000000000000000000000000000000000883104ffcc0d040d70bda04dcf67c1197c39e200d4d9daf5f3c185638a13dffe3dcac94fce4175187dad867e8d2b78c000000000000000000000000000000001404e48e86f199486db7d40076cc8dc4e2aa2c1b6d4bed8f027512e2c71817905b26ff4f0551f9c08a2a7a27b2075b6c000000000000000000000000000000000b789a6addb98ea43c0f9e85831a75b8ee1977936c17929fb45d4c06b4f1ec33b9b41e32b52cde542c9e4b64d27c686cfd0a61dbcb0c657e824cbcf4670a31a95ecbd47a9b93812cd5124f3ac9450c1b000000000000000000000000000000000654e7f3985bf90dd1e3169382690fdc0f804eb6384ce407a060f539804fe6e0451094abaa0dad611c15d3ee52f31a92000000000000000000000000000000000deeec957d58a2246ff8f7b7448f5198647576c16c1717369ad155ae36d5a6bdb42c8d6a1f0a095891fb0890b6203f950000000000000000000000000000000013a01a6ca4c296f59cfa4a5f5399d28af76ffcb8b218c861d5e6dc603e140f730f632028c8da46c823d87bff5ca703280000000000000000000000000000000003698f659e86b96613ca74a480c81e749bce4b74324976c1d241a0911d078926fb2adfcc3f901a7a015a02f525ddbb808118e9c70cc5def8e7d258e05273937c514131f39e0cc9fd2a3620dbffc7ce3c0000000000000000000000000000000016ce72e1798ffd84b52ac664a184c6cf5ce1ca2aa263c9d056355cf610517e9c7bf7f057c342f6e3ae801b84c2082c0f0000000000000000000000000000000010992af1438eec10881b5e2e3fa3b1e91b6b5313ea58dcc0cd2159f8ba6ce5912d81b38956929620e04b3596f6835a6f0000000000000000000000000000000014315dbebd532d0c835e8e85a02c0814574cf040a20c18d06573718223c8ea15b7ea69f0cf342dd09037258398ba4bef00000000000000000000000000000000136d13a83e72525b2d4af54d14d5e21d8bd9bed18543836b02ae0a7e51d433c93aa1943e85f978a8a9ff4454d8c5d120c445931b79e2b826aca02d1bfbb00c2dfb6d30ac2ef97a4ded18243b1afce7730000000000000000000000000000000002c1bf7dc75006c2941b89a2de52fdcdd1b4fbda5b14fe3fc165915b90fd9d93cdb8105898ef59d5b374707f0afaccd600000000000000000000000000000000049a16efcf81de84e443666bf990f6aad2145f9c9c2c61a752e256e8f447dfb27b462e4553544971807f909a666af12f0000000000000000000000000000000000aa4702fb69d791ef958826753d3f74f61c7a591ab94bb6c1bd5d82d94c5877121ecfc1e769d0d16ebe491b775ad96e0000000000000000000000000000000008cd7f2562eca6c53a37382fcdb04be53998f45c2241bfebac3d1fb08d8e1d4df3182f2bd63861d0de72d58072356ccc982ae6de98df906922e660d461009ba6c04cc6497f3645a66385c775b21b210b000000000000000000000000000000000a6b30c4ddb692ae33c903693cdba00ba48efa48e90b9cec9dc747004e57a8d5a05b5522634fc0de306d38c28390dbf4000000000000000000000000000000000601341b3c4057767a910bf30dd16324ad7abcb55b7e98e73584f26d7f87d8a8d24ff2113c12ceb3077bf65e0912b2360000000000000000000000000000000019dc9c50f613470abdb5c763c0272e88e34ed38e617d6757f4e70d05b8ec9f67a023b4ec1363e7e60e38cff64e18f0510000000000000000000000000000000013fb1858f7efeec5fd03d9f7f4513e3e9103c340eee7bfe48ed3cd3dd073b96add9450a17f12e161f1d44669b1b2f813000674ac5d09c6c599173bbe9a43726c120c3a60a96d43954727a2f33ac4320d000000000000000000000000000000000d6c135bfe0fc7af93571a69b7c37ba691f051d69582cf159cbeb0bd59b48342172a82a3eec2e3d440805934e1574f2a0000000000000000000000000000000001b04e56cb3bb221caedd3582943f89a33b955f624f9e473941f1dd987f2898339142a654d11d87bf8bd2fd0fe0d4c1a000000000000000000000000000000000f185fd420b761a1e38d542558b0beffba916f369b37296fdd8878a7c3d2ac9d3ab1d8e45ad799f0d81bb439b5e5058100000000000000000000000000000000002d10ce460c414fa1094ef2b7de8f1ce024b6d086d10067be0fed4e45dc25c8e50bef361d39a2743be1e1ea4fb7e2ef773f8e9637886d795b75e7ecaee512005c1780e7ab17b9f20ae9232595478bb2000000000000000000000000000000001972ea36bae504d7047639ce6e0e6c3b16afe89fa3d6c6b33c910c8d4b70782d8165912e5bfbe8bd84f78f9f23f7f956000000000000000000000000000000000ae55c4fc1c01f1bbdb060191e8551a7ba5ebd3dbadd138202090d7dc6765fd1ef5fe8204ae76a8bcfa03ee5985a35280000000000000000000000000000000018ebed295805e0fc14f1c7b0e6ee12ca48cb7177c1d367a613e0d6cfaaac5128fefce0e8f38d4e2f11ae0d327be466a400000000000000000000000000000000157068d89fe48e77e0f62e3b5b0293423f35c5f4ffb9e0577f5aa49e91cea6bd312a0e65ec08af9c1f53de6499409c8d759d0bab12ac790cc3a16e88f1a108e670681f117d4fc7d01f8c5a2d6ca7fe8e00000000000000000000000000000000120e4a8935c08032dbfc19a43e2a770b12b05cf1dc229e12f683f0d7f604bc13666bf318fcc38038b618ef83c9448b870000000000000000000000000000000004e3f851be46bd85f37c8b1d84507f4ed63ea76bc305cc26a6f4cfa2135d5affcd3b319d9f57619e21c964c6246fc3f600000000000000000000000000000000138733f352029373b19e1c40d5958a04257e2b344770e1bbb8f377bcfb1c7225ae7a8b0b0e57795ec06a08e13c90d7de00000000000000000000000000000000093e85783c556a017829e28bc42b607b1035890fb9743bf0e279df4dd8a695c1dd07a76a213087c3a8a7e614b29b7a1ecce865074a8a41f8a3f40228046c5be68bdb50ced10bb73ac8472f0525302938000000000000000000000000000000000be1ae00f9ba0a2e57f94728508e0029b1bafd52c91ce718ba41790a3541117d1a9f846d68440978cdef016c3b9ae422000000000000000000000000000000001947683154204c9fc93e3aeac17b417453a24d01804e8acbf6f67947f5962dce875f49d05e6ae65384602828784f852c000000000000000000000000000000000859dc1c00b49cd1292cdc65c6aa4b11e27637b949c7db508930c557ee3ce00f98f9cd3dd0f6d73a646d176a91d75c070000000000000000000000000000000015a7a6984b5f42aadebba1e1f4682aaf1a2d01c9ce2afab7fed2269373467787bb1361b493dcdd862180e9159ec2ad5785e2f9597c9b687150864e90ab042f4f012a54d92cf9d2ece09e4a081ec9773f", "Expected": "00000000000000000000000000000000047cc33d9decfd059724bbb014fb9cd95de187e2dd29cf4a9bf9ad06d415e2cacb5a4e49266c13e0c38f2563d1a21d6a0000000000000000000000000000000011c79d93fa870d541e79ad4037c20b85d3cec053587f9df60dc11e7dc2727d79059f75bef76474c09fe61ed10b317cad0000000000000000000000000000000003df3f0db20c5ffea4dc9f4d9333d76141447bba50da18e521e89aae1e63750c71b392570d79e597967dfc9952e903c60000000000000000000000000000000014e83ea645b1019ac2dfafe370f616af0c5baeabe217ac1f9ecf78877717475b25911b339557422526a8163434439923", "Name": "matter_g2_multiexp_96", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000cd1d25f285c2073175ecad5bba4987cc52012eadc7b19dbaa20fa82d7a6cfb8a52f33469b6308d921eb4b3b23f7022d000000000000000000000000000000001707b67a23d9212d30c06f26f0040c38389b185057e80236d2c828a8d9ade4f72eee1d6eccd78e4f4d71e2c28ee9539e0000000000000000000000000000000008e5c04effd14d915b9afc2083afa2b6d4008cfa0e47144a41982d8b5a8e77922a2609384e2c5d18c871ae24a7d505b7000000000000000000000000000000000f414acb056fff2cd6d9b408adb6eb7f34c8f66a66ee93945a3381d46c2d181613047ca6d4067614c190da444223cab685431a1df7678e49ee049b75ea968ca255ef456dd58cce57b64edffac1ac223c0000000000000000000000000000000008ea841aced2d0b8dd688947648a8ff18d0f6f03f63ee1c331f126dd4fc0da3d386535156b80902bdc1f65add7769cd70000000000000000000000000000000017a32ad2763d99c38c954f62466e78c0332e48875e15afbbe9c78376f1bab12346c73a573738353e2162d3928091dede0000000000000000000000000000000010ea738884dbfe5bc35d031bde9aa4109b1fca529502e236aebb5ad0bf71dd2f3db250d924415b0bfca56519f8ca5d290000000000000000000000000000000013699e29cc1871f51a469898be8b3c732b5cf7860286e655e65bd8176832804d17b48d0ff85eb023360db78162581297b6ccbc0b600f11f1b89061d94c6fbdc9b1d389244fb29a5d140dab8842d44eaa00000000000000000000000000000000004d504e62b2825651381ae862fd33407309851d5291591cd0f541fd092800d709ede00a9134e65ee752eaceb0a344b50000000000000000000000000000000016481efba290c37aa4ecbf940c76ee5df199b0c1f90fddebd2db28120bb5a14dd9f4a067b6d4889aeb683cca0f6ab337000000000000000000000000000000001400c89942cc63417ca4cb05c9d81dda3251e5611c27fc7727c3e803170672f103bff26f7216a0b646533aac3171488d0000000000000000000000000000000019889641be9db08880543ff476b9d4c72167092548ba49a3f3ace4518d3874f4f7993ae7b8cec90f092f144ec9d66c1a54dfe31190469897c30ac3736ab166220dd3702df5bc897835347713d03a8d04000000000000000000000000000000001927fe80adc6dbb581349c603103ad8831e645d9275af8669939b83829182cc6e2a30df2fdeda6d3aa2e2a6126e00ba3000000000000000000000000000000000b6d7934d5ca1098a85a0c60acca075220105e221b802b1be97c2967820bffc2937fc3278ed0f26905c60d44d5fd8dc000000000000000000000000000000000057acc1379f23c0d1d37427d400eb1b0a89f3736c83d3ffd797ae279e01e2acddd84082f13f3c8b8f1bf7c275702a9c700000000000000000000000000000000038dbcd7e08d34c553850a52336991a7d48968e98057e930790d78b5c6368eb2fe01571b60c4aefb653ec04122953d56eff1ceff9e5184dd9fea44da4f07529823dc9b100f776cef6f6881120f7de11a00000000000000000000000000000000014052031b88af979b7edb06c99c2e46bd9df2c862c7e1b71321754841fad67fc3242b51141e49ad86b61344aec913f40000000000000000000000000000000014806a86d078ee9bdde99257b67f50dc2ddf9bbf01dde931742ee6f739aa986cfdca06cd32d23d86f2c14c3b09033d29000000000000000000000000000000000e0561e795d35ceb8bd9e3b276406ec1f697a38ada25d1dbe08715a28bdd3d6ce6e0aac01f7dfc7c2b403850ab213b4700000000000000000000000000000000146a65209b09487e00e356e3b29952280ebc6a06343c4ce14efa0c6281bc2482698bd02295bc35125275ff5f5bb867dfb273e4c6266c1f5cf022902fe1310d2191af91c47995486342bc61cd361eab8500000000000000000000000000000000021592cd7f4cf9cab3be53561c889c9ee865961aad51339f6393dd6a0b7dcc8a7c48b753c947b15cd3add01abd3d76d8000000000000000000000000000000000f9e1a80bad58055a8577700c177889c4d702de04343c1202eaed9485a76493158547b20bcb552b66c42a0c86df809ed0000000000000000000000000000000013908dcff1945cf06f038e3caac9a7fbb3a6466ca18627e93468a875759a2b5599a96834ff21fcd6bfbba82b79536b9a0000000000000000000000000000000001b6354665109c5a64613c3bd7d805b3a34098708f3d41c7b77db031ac6fa0b2d4e2f2f70c84ac78687b0c0f9bf334771342b5cd4ad3179f406941ef6ea15d0aecdf9f6d96dc334c39b7dca89d256d4f0000000000000000000000000000000019394063202186e141dcebce7b8f0f267ba6057a0f993bb1cbe22a5bc528323823bfd1597a87017d478186a18f09a47800000000000000000000000000000000148437bcc43d432d70b47dadac8e738616c97d38d0f84dc132599626612f7bba74988bb23ae47ac15e6f70c059d607ed00000000000000000000000000000000180851594710f4bb5be7ae0104a383081c50f59e4e048614660ab5a4e2661e171510f5b112d8cf97a6af27d56d137c860000000000000000000000000000000000599f3f82f29b493ffe9ee3a8363b9a599a5ef3c9c5c680d4e003f4ac5a7de0562cba8e2a4c6da7d07cbe86c3f7bfb85b36620f65ed84fc0bb344b4b73f4eba4b1680a47b28b47f6d10f9ee82398125000000000000000000000000000000000cfdce7997601afbe484901893a1b5fc0b83e8d238d41d2f889a58fd4d884df1c667a000b53b587df2c42ad46aa2c3e0000000000000000000000000000000000c50bf3e06400cb10494cd09bd89f3c96ff49c9f74dd5325f9489ed6be13b59bd7b0b2351411ac854d430405b8a2a3de0000000000000000000000000000000001db313a34ca4073e4fa2287e234ac32bc579742de22e5218f7873b922f5804894826e6054925a394f125fce850f33ef000000000000000000000000000000000e0627a66d286e8d4d3654b32fc5f552a7ca12f0bd47eb6dee0dde22ee48165247c067a0f4c3d422bf3562d38a3c0cf1249ca9bcf879a770b0a054422a6ea97ae795118ae45532c1523c842696de6d170000000000000000000000000000000005285ba39f5bd981fce2fdf853706d70992acab2dc6d4c4198144fab397392a60d631056b580d0d98f3f350414ce554e0000000000000000000000000000000013bddbc1180f155872376fcdfaff2fb12d3d9645b81bd1475a5323ea855cea820ed7eb693791caa9bd3fa5c66036439700000000000000000000000000000000125644d32df397def58dff875d7e3f14166e765ed49a3991f45b38d74db3985fc7f5052058d85594c8b97afcf850e11b000000000000000000000000000000000fca4662eb1b39f576ee820385fba88ddd2fc01fcfb9d9f874453ad725cd5defb357be028fae97ce71bc5ac26d11c1bac014a0aa616e809b674390b4553bf2d9bf325e73d3a935eba94488dddee4e8950000000000000000000000000000000015b97d7c74c8ec102083b41d7ce5490466e1c0e261b5ea5c756d3f9ae79dd2d8ec6eb5075cfb76dfcf7bfdd80442f7d10000000000000000000000000000000016812f845faf96b8b69ac7a6af3c8947aa25877199e3c12552527706a17b768bbea259ea61ea82c4624a96cbcdf4040d00000000000000000000000000000000123ad55e5cb5ac5bdd3ca0a5afa7c3f8e4b98ad91a205f073fb546fe799ffc57b3c1c3a6209547ffc6ef05fd24be6f5d00000000000000000000000000000000017719f31946aedabe0e9d88ef3f90eb6ceda884f5e3d2ece368373785b2d8bf0f9677731803b25accfcb6cb716e0aa4ab722a1c20f068b6955a44073914c418a082345796912ca634e79983a24ec4bb0000000000000000000000000000000000497e3480d58027c780f47cc35a121ee0cd76c4e84d9a2f9002c04a1c286be990167a0138049ad70467132818f48ec9000000000000000000000000000000000ec0ddf938553105400f70989140ca322d996f48ffb1b35641ca36a6ba9ac1daac1603c100822f80cf62ec3bfb442158000000000000000000000000000000000a0b6ebee28a792df46d2f727af812c15fc91a471e0d8e34b25b26048f3b9606d8375b5b268c40fb04ef8f098e1d03340000000000000000000000000000000017843dd19bfabbd0cfa41fb58e70a8900397d17ccea783087ece90962560f5cf090e8d9eaa873a6a6ebac45219ea97a68b314f83cc3ad501caa44b4c3ca8cf68c70ff6920f445d3a7ada212b6a19ba3e000000000000000000000000000000000b27c82d71f7e4aab9a68596669596df3f62071e921e131ba4d9e59d8d81d370e077e93a4a6a43e059661227f40b38c800000000000000000000000000000000093004917ceb2fb4a1b33960ff74943d520f86e83aa02b9a6c85e4b9a489e9331863cd30cb6ad6f099d03289b4ada5520000000000000000000000000000000016f04e35186c7deaf730708e1678089bf3e73c1164bca24bf8f70c4f6cccd5bbb34bbb5dc313ee428aec4ac9c638a01a00000000000000000000000000000000011052348cec9dc3e85e01abcca5a652461f08a9f5d72b3fc27140a6a571137f0065ed7ccf9ec8cebe314ad9a214d5ed94ffab83099c69845cc87727d459ae300a5725ec53176424ab0ec8bd3f80eaff0000000000000000000000000000000007083dfb0738d58ba8933a1f60283e5da8bf90af5aae4053ca573ee7223d3b80e4bdc30b4a831ce6af9f52f393e9742600000000000000000000000000000000130c627b7d3a527c94cfeba9f514e75eac047e1b6088c082229a8c95d0765a0898ce1e45694ca2c7935bb8e41e44e8b10000000000000000000000000000000009610645b074e652a08f2b89dbe594afa3009d795ef211f7c036a56274b1e1bd69a035c4f356b6b21f69b9cec2bf7c32000000000000000000000000000000001020f3cdef468af700269aa1e9d928e71b8c521f23586c9b0155314f0073da7de04ca41ececd5edcc052af72c05f0e4bb1d80be637e2abd98d0433150e14b629d98fc0918c7dfc179204669ab465e90300000000000000000000000000000000123540047f0768b0af841aa4aeceaf3dac31ea832daed86c8cbd1d33ed0282c6f697d5881f9022af032e90ff82efb6bc000000000000000000000000000000000113daffbe413075f5f4f6fb42f37b6e9d5e5822aa24d6f865792f63e6078584246bcf8b17117385db1d6233974f6ed9000000000000000000000000000000001067b46fd221b6995d25d4bf0adb088e0554d858d4e5d9d6b59e1ae2a7d57188d559b0208918a8944aedd62b1ebd4f4700000000000000000000000000000000087dae77e483d5c0baa37b9b96dad5ca92b5869fa253bffad24dd8747446f7ce60858b52438e58233210d86f470f765fe670a57ce4dcfa680e60ef33ba99c437e4fdb160ea1012de36f4b59613a6af8500000000000000000000000000000000039d09a094d655c139cb9714aa258d9548473162548048b0f07c9317a41a7e5dbaa5aca156992c8a509d4071d9ae4394000000000000000000000000000000000f0273a38b1b9d006efa43c15a53f026587a676912d0275968608519e97994ea9c6a147e377f68b1738ebeaa178f9c1000000000000000000000000000000000132cd92417578d2e46884f1c1a1080b1916c8c8404d2533a4de02bf8575c80ce7e8097c2ddd1f95737355521c0ec21ce0000000000000000000000000000000019adbf09a268a3ed8eff936d25fbe8af2874e44d2580c7941dc14fb89c5da963b468a7088c4a763eac89f4d15deaaf5e54a999fdf391d3944318c54680e69b58ce3778683b6f2c607d64450ed32c6d89000000000000000000000000000000000756dced467ea32c3c425590b7690a45e250e464ac6927ad3f5d2d8d2826961b8dd7572db609375c8d06cc3b9bc3a157000000000000000000000000000000000b79b4eecbaf1d0f8a89f9ef8fc144b3aff38148ae260da7c20e9dd3866d946585df7ed12c8b7005e7b0e1387c9db41d000000000000000000000000000000000afc403b008b70e19f17b1ef37c9c396577a585b6c34b23d09621b891efc00ef9460c3f4b5f3e851ef63620dc06c824300000000000000000000000000000000024e06f3f3b18c026a166c41f75d7bcf699480f5b6811463c27606c9ec1232fd249a46235b7f5b5a2ed3b53231b333150563ae7b444cca7ebaba36b8d59aaa5c0e6c1454a4a2907866247e752e640a7d", "Expected": "0000000000000000000000000000000004f2480d0b7e84a996965b76055f6879aab5bab26656e4e5ca7220adc17f14b5946047484327bbc5952d9f2ffa5f92af0000000000000000000000000000000002f7260c55c500b54df4391a55eb4adefa7d19bcbec82a107fc0d222c898b97360a679a02ab3023ce2ebdcffd125ddf30000000000000000000000000000000002cddfa94c8f6b3f29c2fe018b1f8679d0e98c8c2656f86f327b9cbcba574cc52643ab423b458994a03347460deef6570000000000000000000000000000000014eb4c84f71ef5935e707a11a92ba34780677ac7eb198e160585ad92aa5c1ea21e3a77be940fe344e7e170680e2a8d53", "Name": "matter_g2_multiexp_97", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c2c4c039047d297049afd0e8f0375bd4294d628d3a22078d93b684b737e8c4b6ad3ee544ecbeaad6b3c75d8d217f3a20000000000000000000000000000000004c77a2c0943c6f997ce2e785461f8ec253c47273ded4e1af43ae882766ef8c168e66d831abc2b3b3a0849bbc210cbd40000000000000000000000000000000004456a6c267a5cc6b7d9a9f573270855186a1b621cfdc465fe71ddb4d614565d9d36b13985b31396587919226843c6230000000000000000000000000000000009487cdd8a0cf7f40e9087fd3121cb480730f4302339d25fa12128033239662ed65579a59b837bf1bc5fa87db15b15335b59d128b5ac47106b4114cf225dceb621d177141ef5783943f40a54ad94e990000000000000000000000000000000000ba43205e8392168824f77bac344d60c1a9a0b14ab55538c3bfea4a64984cf381a2f61c64f1ba1bcfd8a7973e43f6e80000000000000000000000000000000000e95e5ac415c3e3e7c9feb6e7a2af3e8189afca06ae1fe54bbeb31783810860921ab3c76a475fb227b3c8299e3f1caf00000000000000000000000000000000001e3cb2106a23e77a126013087751c4d2a419a51beedc3a33faa6c933bedb3d34ee9c6450c583642426edb352e04da98000000000000000000000000000000000ab5af4c98aca1fc3fa55355351d12f3bc639662bf8b5b772152988d676b00ef39f767237a2fa3be936e83d1dd77da86a057c0405e24b7373f67197b2109b633a02589711b6a92ff49ca024f893d7ecc0000000000000000000000000000000012f3d927316ba638bd6294f7dd2f3f166d20285ee1662ae4dc145835704a17127078343d26042a5c397bfef31754186200000000000000000000000000000000162893d6252361c340057bcac31986458b8b55a8a4283f5a06ce1730098f9838dad1bca264374e7261bb9d08c177c1820000000000000000000000000000000017264aead0ec41a079827296f3d32c12adfca7cb6c674070d54087438d57b6ccca4822b2337263e60075d469b4ce0ccc000000000000000000000000000000000480cae035bd3bf1b4a4a766bcd5f188833e9587e1aff0e1f10e36ebbf2f3ae76bc0946e7c336efc3ee00bf42e7efbb9677b05905180182427efeb848b2ba2eafbabc7519ab33db14de0746afb607191000000000000000000000000000000000d13375356b1518e37a13b43b7d192eb74bd69636f91c570c41a741a8763c03caf8d13c7364f57c867a4a3983e88060f000000000000000000000000000000000f6f78dffb404faab88ac7373e0c765209c0af80514d438e18393bfcfeb60d9a5e13158d399f43162033571ee4a75dbc0000000000000000000000000000000010c379860638ccf3b6cb8479aa38881b0004197e3e367a1d5ef7c7fcf075689d283b87022e2825b5c789ac6a448467320000000000000000000000000000000002dc392872cf2fcd8e196f10c1ded175300070e4e38aa58c89c81e1aa5faa08d770a5ad90a8295a890551f9329a13cee53e7f69582f4c106ee5bfccba1d5f557736c1b75b6e3777cfde47d552e6bdcac0000000000000000000000000000000010383a21acda7c8f3f3be980bff2d57fa0a5b2dc424164dd2ce53c0b20ca399d6227913b7b550462180b01c231e4813200000000000000000000000000000000078aec90354721f0a31e1377b3652bcb1f388ab36f1866c955f3ea8dfe6ac2c25bc4cea14f54aee71595c2c1bd2dc4910000000000000000000000000000000007dfeec77213d952c183452b98ad936e8854608d950c0c1451262cdc7d6de5aed0db07a8d74b3e8f674967cb4839c4d00000000000000000000000000000000015c09e4ed2ea76d10d196f7a733ccc272b94dc436d6bb5fafad2fae4a96372c2c6f1325d1554746814ae292d8e6b1e3634c87bfb629b817e7ab97def7400b0a83e47af8d628787ff814733fdf34ba8d500000000000000000000000000000000138656fa091cc6613b1fcff04a3efb4f9c393985b2c78fa838eecbbbb8b6dafd88d9c72441f9bc735649480b5187acac000000000000000000000000000000000a35cec4819ca3321917cea5aa589db8cf61882fd1135031dc41a8207a8e71d326312799291b160a646148c382ed086b0000000000000000000000000000000005b6e4c02c9c54630c96271073513cac3a42d47a7272f62a21c7ad4c85c19b60b70d04719626cf4273f6c5691719931700000000000000000000000000000000166a20da734a47d7e28cce8f0c2d679fa6c738a7a1ca9089dc67ba2b1c92a83b024b8991f131e7e8802a617153de4554bebb60069acf431e1671e3d00e4da0d70fa11ed4099b21d45a2b811f99dd9cca000000000000000000000000000000000a4432a544deda931b1f62759320ada2963062e722bc1b748c9bd0d026ffae10f228be36ea0ab076358924f4c06b6feb0000000000000000000000000000000000e955b1b1b28d2044b6be371c58bc85097c77145b239e913bb0729757518c465d9e69338066f7496aa6a2038ea604f900000000000000000000000000000000017ca2a7d52c3a82ab8abf9fc1bc187389b6e4904e161541008e5b3ba0981870e01060d1272a6d59bfcfb294c942403f000000000000000000000000000000001870649a50e0978185551f213eefd9305d33e92b3f8c39752b6ebe18ae86ad97f92acef05971dceee3b3729becea18168b1ee2765e762f1b8c2451270cd5a755758fd733d7922a537aa9f1fd7d0c95960000000000000000000000000000000013713effa20d5039ced751ebafe1516f062f11ee05ffad37281cfee9d7a49ab14c065709832f6674bfbf2c9f379bc9c9000000000000000000000000000000000295f7ef148430209b48c292b024474f05036edfdee082c56aea05a62f1fba3ee7a540955423f78614c8385da8ef60040000000000000000000000000000000007408c97321b6d7c27e5e442a9e35b054e743c34d845874aeb1ccf4e903ca7803ed7fb1288327865f9e0ff0a388e92b400000000000000000000000000000000081808d03722a2d48846a693059c2662dee614f181dc406825544d30a6adc0f9d84a712eff80bddd4a27a036e4bf7359d5009fd559714d5692de5500ec8cae9c04ae1ab1c7c6e08c8738ef22da19ceca000000000000000000000000000000000880b646a674723c15b240ff56d2031e5db724251b1402a68df8b26261ffc9fb60a81abf165c6832137dc7a7293142d200000000000000000000000000000000172354b62bfb8d388b5a984411414738302725a508e8abeacdcb46454371d5e9cf762028fb65921d5c3dd8c67d42a981000000000000000000000000000000000a1af459bc3122dcef78359e468f4094d609ae3da09ca5aa6efb71a7494dafa2373a3906bac1f324d98b3eaa982a27d500000000000000000000000000000000092ac3b47253c7f090df076914cdc08a715faf153e8e365392b4859fca1db14d3f7fb998c97de9ad99b7d0b357252f086330c755ef708d8eb129475785f24be9e7836385ac918c60ad36e80e2f3281b80000000000000000000000000000000003b23eff722c078a781771d8b75d519e7a062ca3e4252ecca877845920158fb20d79a9ce449d9087426b113da0091826000000000000000000000000000000000c9026e8d3fee6282492393db504a2c41db19d8fbb83260624b05ba4107d6cb2c90d645a3c16862b27cc3fcce9bf89840000000000000000000000000000000018b8648d0a42285d474f809519696df9e1ad5c35d8e848ad74fbee37425aee8844a8be8cb4d3331670ee294ddb9a290200000000000000000000000000000000068cad37ee8578f4b502ac2ef4371a10e5432e57fe20d0cb074dc427831872113d3514a0b199d813b796b8357fa2a3dbc2431888d05cae840dde4c26911db1893659fdc345d5433556d9bf75e51fe3740000000000000000000000000000000013200f0aea4c60937be47213b6149b0ae76767f3559e0519f774af4a5d9431e2dd7ea74b42cc3ceb28ccf0d2f01116f30000000000000000000000000000000001c5bff08fd16ecb68f21289a3e7b9a2ec5da1357d604710a18e78ab780f8ef0343d5d9ee7f7988a009329b17e498beb00000000000000000000000000000000125453772eb9d1335ce4dbcc8f2ab8426fe89a0e49fec51d4e96718a38570aa82dbef452368141be2df260fb131c50b2000000000000000000000000000000000432cdd445519775b9914a986a0941cc829b4a15cd361df9ae7129547b24f7a6a15cd8fe9393fa1551db2d761a208b8ec9a72369cda74e5c86c6559cbc4f4db1b3ab24c5150c7decea862ede3c02c505000000000000000000000000000000000396cb6d7b44f92b716ed02985d351b4e8cd1bbb95f239e4f29d7379428470be395e2faeb8e3a910007aaa490d3c336d0000000000000000000000000000000000ad0c0623fdf50c2b504777554dbab3cde1b9705e976561873d7c22b81f49c7654a7c76e558fad1518ed73a0d3c3570000000000000000000000000000000001241d5bed68e02a2ddeb3ccbe109a161abe81edd7affb72182c5163851211c4763e6aecf766053b61ce575de893985f800000000000000000000000000000000183696d2a48feef6088f4e9f75a5055e8c54b3813658b593958490ddd4245ac495a8ff966861b20f26047f07fa8609a0c2f50989b04fc29c4c4a0090fb11e860c15f89a66f3bb8281e4678ba63ff3f9a000000000000000000000000000000000fe0ce41aa9e7cb2bcb4e01721b7b1d99fca4e9b7c4df09bec00bd346fc57c25118ba70d5333b7f3eef2659c64520a470000000000000000000000000000000005c932e09c62b7ddaf3f5c420c60740befa7cdff5bb812e0f089c45098d71b57004b7a207f0cdd34daaa3282cf6e9f7e000000000000000000000000000000001874200ead9776c1ecd6a54a57e5d0f9577910a4b3afb9b051622f658fe3ef6cc5070af60e7ef910562720e9716158d6000000000000000000000000000000000c2c657e58e400a67e59deee8c28234ff4688e781a2f6f2f0d0b186a5e4012695a522dfa0770cfd543f55939a05e20b09fc9abf1c76ff11ab538f46ce768ba597eb5f2f63073ec67e8de10aa1d666720000000000000000000000000000000000f0b561e5860321249b9ff434c604d26c3275824fc4ab9c1ce5c5858605ddaafae83ae27e523bf6006932f6c7f33d0a7000000000000000000000000000000000b47aab85bbd909599aa85c5eda363b67790ac6729fd8b1f4f53f66dd796cf2fa3496407b1bfaea4dc8eae53519054e70000000000000000000000000000000000cab1ebd23bc05c53bc9e8481c469eac3ee1b140af545bebed10a8fe50698d2ed883219881929207c0addf2f687198d0000000000000000000000000000000007742de55b799950e6f786f4eef45d0fb67e0475272ad68a183135b70047abab6c2ed51ede16c39be7b986df334e9e75d4167723682bc0e7476797b3be5e14b8de3e4e23b4ca33c50a2096cda8766dd7000000000000000000000000000000000923861332988bc843a65ec5dd4637f9dca8a15e71b82c780fe60d768213d118d8948ab554e30bb9253e900a9b7d87f200000000000000000000000000000000132b1faef49e7966a05783ba526e71134bfb577b13116548352da37e91e617d7c72ed2645e672ebbc517e079247dfb0e00000000000000000000000000000000000a46a8893a194ebfe077afd05fb25d4680f1e4991a3ec29475fa5651d086d20b38136155a65a4c70af31de5a78af59000000000000000000000000000000001344eb957594028b4228cbdb8efb03cc7cf49ec43b2ca5481eae1df6f2df3d5be9a7c4e4e78f8c39be546e29a83c92f49644c3727f78dd12811092190d5d10adcd5b9fc581dd783c97d4e7b5130f309a0000000000000000000000000000000012d7111303563a6358e5ce9155d7a153b5781062c2f6b919efc67ddfb4c61ef03be8828ca6339397b84763a5f8a7e8330000000000000000000000000000000010a2a0ea9973728d3fb1b5906ee84b2635c687c11398ebf605cad30216df3b7b4e3ee1653d4b323a690e6ba614ebec30000000000000000000000000000000000b93d5de37b892d4de9407a820c73ecfd6cd9fa565db82e7e8c14c8406823f705ff0adf6bd6add5ddc5f72c91e52e840000000000000000000000000000000000dcb320ceba5436df8f099c5a77f34376c96d830f5e8ab80667d156d89f6bf8998c148ef9a53847ed395871ab86f6d280df9846c84354ab7f947caca7800e12e38d8e6651527e6831f4d8b1bd66c4f3d", "Expected": "000000000000000000000000000000000ff3e299e6b9fc488d6db991cf9d226d330846e87c4a5cd3e5d4ac955bc2c3c2d1ee5ff230098b48f594d256495f489800000000000000000000000000000000097fdb8fc95d64c7070d8c71e0fd2a933d1e1ad3fefa230f079bc5743828317cd1b0c6d4253ba9c3c6ec6b12d53afa700000000000000000000000000000000002448bbb179d82eaa453cd5452752b9a083b52694cc65c5d9b47f72eff118d7aa06b0fba18eafe93d2937d7399c001af0000000000000000000000000000000009dec4c0aff2a46b07855c87e08832811633709ddfbbc30dbb7e78b3de43bd95e383baa6ff4c58188f0c7643e0ea5a40", "Name": "matter_g2_multiexp_98", - "Gas": 293920, + "Gas": 240480, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008afabec8a9985cbbc6246825785654c1d2eb7da5a01f76c4af4d0096b9baed3c33dbe492d14a6f9e762f06eb3d198f800000000000000000000000000000000027c592315dee4bcc892acc6f41a6eff5219c308253f7cd715d0e4a32c03c6d0d0e8568e146e9e799ac3025486c77fc30000000000000000000000000000000015b4ee27a3aa518a1ec1b447bb8f9128301c85b7176296d68dad3339b1dee78715b2f031a7fb6ba376145c97ceafeef60000000000000000000000000000000004b7e30ec7cc024ced863ce511cef3cabe954a4e5843dd636d776645a44225a36ed7e153ab5bf5d18f23c6444751875c8a71abe11a893fce872f6b8a020b6d84241df03eb934b50cbf3571df4800a83300000000000000000000000000000000119949d36d8d8e2bc1c26ded5f5fb01225a980a28b934ed3862480dc9297a3758e0f08ccaab3a09b5e5c0e4215e3246c0000000000000000000000000000000004a82dc22316ee6af39d937b662d1f1f2dc855c2ca8f33ec3274d833e87d594633fc7fab247911e0f46564397910d6ce00000000000000000000000000000000196900a09d8504ed960d41f4a8a2cde2e5dac61b008d3f6eb47e86d7b2ce6fcdc0f85157e3ab1571094d9fdaa75d0d500000000000000000000000000000000010c52ef9407eb4ec57844aebbcc3ea5000b1940d035dcc2a873327affaaabdd79e3560cbd29c63ce04f6279056d6eed1bbf28e5bca314391550d3a0fce50b1220965860e72c8c3865a2d4c599d31d3f1000000000000000000000000000000000e43655ae05dc6cfa93113dc26cea895d1c5bc73f20454c7b441dbc5ac80035b290514b13b31b41931ea5336d8d9a6a7000000000000000000000000000000001199a873958c63147e6b82625dfea15ce90dd41ceb4e315f67221eb874ef32c6a2953412e7e981659c72239a7a72bfe6000000000000000000000000000000001845af5936b4d7487ffe59137ba2f86daea3770cf37fd560969ee48243389941a1072205e049ddaa06c0ac56b7edc8930000000000000000000000000000000003cc831177f24614f93a118b896434105f05a277051a852fb9973a775fc54f779c2a1f3d64c457e5231dc22d6aef606b58b208a6845aeb2bf31999042c59b7b130a7ce5297e88023953b1aef63616fe400000000000000000000000000000000005e63584bc85ba58615985f6a466afe05268e545e0062cd7214e0b6fc8b87537c745b754cd9a1144948bc88b3c43acd000000000000000000000000000000000635b6a49090ccede3ed2ef203f0ed164783e3df4d9a7d93319515cb9230bd841b61a097f39e30175793b3e934d8e426000000000000000000000000000000001861e65f47a9da1584c45bc79a66045d86bc1709c2d1cf6cd2930a9fcc8c4efaa6536b5015be8d54789e8f574f93f9f70000000000000000000000000000000009290ce63d55eb436794acf11be9d896f03e7608a1bc8528f61ec9473f054bc9fbbda1072440e58e2f6ba080a01180173b53b6cf9e0ce1661c4960283be790abf956c2d6433529b8f3a32b92b227aebe0000000000000000000000000000000018feed9500bff884d2bb58554da2180c68267b6d3a45c2c7cee4c3f8524252d3faaa5eff971bf40123587e669fe66bbb000000000000000000000000000000001441bd3b58b4a4a87c2459f873c0692f5977b775af984bab46dd76cb9f775d2faebcb77b2854c9f1faa33f6c5de61c6a00000000000000000000000000000000123a890c3362c77e5b5cf9846d9c9e43fb3242d5a831e640ad080993fa0547854c8d11cc22f7f7b426528bf1154d2300000000000000000000000000000000000ff4a59ea98d13cfd353ae61e18d3c7018688f755561e6a1da5f09acc4277e8d49645087115acc64f992ea778a11f39bb049228435ade4c4c565e65f39f13a84c747c312afcdaff352560b9fb3cfebcc0000000000000000000000000000000006b019d005141e82393a2ca04469d1f6fd7b9456001ffef4c34eff6b2e91df58e99fd07944f52b108bd41ab6c4d6bbf200000000000000000000000000000000109ae87042029856befff0c916db5437e1e058a96f2970d8816b3becc93a1a50d6d336d5451303715f3e272147a36caa0000000000000000000000000000000000fc381b8dc9dc02d34db13e34732a10d0dfcf676c224a05a3bffd888b0af7c415b38af0b6afe6b464ffca42947c6ee5000000000000000000000000000000000087040d09c39ccd06c9ecc360fa02147a32e8036ad6e4b6bdf5b3883722a4e5a887dd022d53706d2585fe558696be6656197f5ad17062d2ecbdc8887bcdd32e5ed4c48cefd9e14d622a0b800d970330000000000000000000000000000000000e35c27b29df0fa9298bb9ab6a38b3450782223e2115d79152f9baa924d762d583b3ebe88e42f33028814ec78e5b319d00000000000000000000000000000000190c65667627a16f0af0ac7f23af0803bca810f3986b906b7b4f126d98473d52badf45e90e2e45bb390242fa8c40135100000000000000000000000000000000103f0283a5673c16bcc0f74f259c2eb077061947da04e467dfebf62aa005491e32b85cb73418b624a30dbaa01672921e000000000000000000000000000000000465466955c908607191faf15f0768dce42488c488eb4a065977f21ac7484766bc0abf23961ea2ba46dcc04956abf6c7721d9d7fe10104cafcad71307e785321ab87b2b69593535caecbf0e166cfda5b00000000000000000000000000000000082346e352e845a54cd4267f93b85b2c8623d4650e00c1c56082b73ee31f63588d2c117d3cdecc0378fbbf8956b082040000000000000000000000000000000001a7f43c2bb19cb32345c43c950536f8e85815b86364f278f6ec8169eca80917c2b8fc08d59b20cf55f25dc468e7bd7f00000000000000000000000000000000085a5cb020df10f9b4c7afc01b1d11700579dec1e85e766507def2e6cf5b714174f7be9cce3b18533a5ebfeec2b4e481000000000000000000000000000000001836d7506d1cc984fb777b8ee935d6f5b110644f59e96ff44d8329336d59a3e1d2b53a05d35e97f634baa4fdc11a6cd8461531ecb61365908019c1e8074a4c322df2b356eea3f3eea9aa1e0e1fc5525e000000000000000000000000000000000c1c59828ec6257a02679cff0bee0d665d449d2a158bc6d877e84cc0fe2161c297dde09b778d5e1249c515833e483004000000000000000000000000000000000f5e82589bfb7781e4110f1486752b00cbdf96cdf4191d75053c6d6d646e1c989add011361031a11559e156d64139fbf0000000000000000000000000000000015053afa7fb2b4e4b70f3c8a570fef8288fdc22dd951b6ba8a40b6087b9ab04ede21f0ddfa84d6d18914041bcf244c110000000000000000000000000000000003f399800cba51ab35624d866831ab6506392cb3acf549787153ffaf08cc451acea46c7a612821dd96c45f8b75133d88569c1c1ae2d18bbe36ed50db1bf30957802b09a982fbed49d4968815552e010d000000000000000000000000000000000e26242c8f73116079369ef4265f624abd4377e4e3485c28197663de9de9f5618c3b6ee602ff6bebd1c242aef7295b2200000000000000000000000000000000066ceb3ea6067220bd28fa1164237782859d27c1d3087a42b4d09bcc343611e4ed2be014a27f5b394c67643dc00f57cf00000000000000000000000000000000157f9d30de52110ea7a2a35ddfe67d9fad7223c5e3307e797dd0df3621520a421958a2835205e3c4777923f47d47e5310000000000000000000000000000000016ebb41beb85b9489a6d5482f8a3330a5c5c5e5718e8efb8b67362f9d8e9c313e9e563275ba38c207c5bf3d89c406ea62061d33b2f7e786effbd2e93101a56ba1bb62c1a773a08b72ca82f5183bea35b0000000000000000000000000000000005d1c9109b5b7409f94ae3f7dd9e8ae4908a9b378fea4ea284cbd33d1e59b605577b63892aaa8ec14d415f34e22fec520000000000000000000000000000000005afed05e62599f20f7eca019f41d770c630cf6359cb5601464be821691fba5205c16e7b580e6881047214f938e5104b00000000000000000000000000000000105637a2aa4725d8e080dec3b731a111ea4c94b79f898dfd51f645501ef0c8d68ea8e80fde28ff96e927e44306ebbb1d00000000000000000000000000000000080cfeea754474ceb37973234d5dc3269f8ca99bd862d4d2d1a602321fc709945a3209e5ff2cc962cfa6d03017c9a1354129b150752d2d5551a622231ab067931678454aaeb23f76168219406f0d50ee00000000000000000000000000000000137762ea5c80033aaf17570451b15a062feedde810f11ebdbe9a79a3275dc12613e0505835c122bd5f9afea7dba84203000000000000000000000000000000000d89c04e45e60769a63fcd73df2a138c457bb549195f2c4eebb3be1ea46149f286756795be8328b5b886f497d8167b34000000000000000000000000000000000be43d515083c8c10f467618685a43d4d5f6457204bacd278445943a9f44f7189b561a0e1bc59d2757fcfab2e3f93a4a0000000000000000000000000000000011a52583227c6dcdc1784d3633fd584612a9f3bbc1922477396dcd5af84413e5e9382a34a71b3a72491ea09fab2fc6bf366c32d5d3c132f32a6ac3cfe1dabb649c59ae224338f747ad98b193e8346729000000000000000000000000000000000073acefe33525dd2d5204cce72371ed82c7e4b58d1b4e7f4b4994f9c58b02d9d6206fefb3552446b6b355e860ace43c0000000000000000000000000000000007344eaeaae71e17930e769e02bcb4f44ddf3d040ffa0b081f25901cc125a37a58a6a5d13e7b0ba493802ccdaa054e29000000000000000000000000000000000a65fec6ad29ec3eee9ddc7ded2297f49d03ff18a255f1e6d29d2a67c20713f319d79d513af0c58ae3cddfd1f6240ff50000000000000000000000000000000019d5f00d9e2b271f4e9ac779a096386f08ae124f77fb8183405d48ea7f16e685805442dc67a392aefc643ea95b4f1fcfd997516cac28a3968ac6946b5bffaace0856a52e38fdcca11ddfa16cf5a568f50000000000000000000000000000000018230bf1a873aa04855af1426da30f1b3ef4b64eec613b9f660222e3827b325c318baea031b463c7e9f775165d22ec8f00000000000000000000000000000000017faafa1294fac53e1de8cae9601acc62d76a5f01a39ce49d65f3f5d2cd5cca33eb90bb4116b3ea36f912ae2b81b6cf000000000000000000000000000000000fc3ef5ea59849a87fcd45500989f1744cb5570ee88e34a952cec32cea2eb5900b64d8d0d04ef5c51e8fdcccd46412490000000000000000000000000000000001c53aa8aaae8422fa4fddc86cacdefa89c37592c8e67e472a23627514623a90901a619af79e93561a0dc65215837274e881ec65fdc2f58e46d3ee45a06d0c5ac844ee5b62872c7ba21f6b48621a3371000000000000000000000000000000000e3db6885c2db9244548e11b8c49b73f85e4104b413f54308497262fdff1957495859830114528a22c45d39a554ba82700000000000000000000000000000000181b1bfe2d9a1c563e73356d73f4ed3e7061a79c610bc97c911ab1a0213d123c9f83ed6706e862087a796ce14c5cf53d0000000000000000000000000000000013f5fdceddce771588869b945bd6025e5ce485fe78a362356720b474b83998f27e535cfd8d33ee51cfc68e5d514f915c0000000000000000000000000000000007e8fd7ba457a3cefd50c641847425cf2262deb1d6945a0bd740eadf38dcaa616edc48c3912508d663349f089b8b56fadcd9b95e49473277a665ca0f9a8309df9ed6ee4f25d803aa967fb8f688273e650000000000000000000000000000000004b20b0408da7b704694b47607928a655077015f2174fe01bac9a0b3a61dae087b0b593f58d2947d8d84f75bbfb327c900000000000000000000000000000000106d623b2007c5d7128e03e540325ba763e992a651e2e5c78936f82ee2ff72d89a1a914345486cd0a04440c75beb190b000000000000000000000000000000001847348e5ef429cfdf1ba4d265d8c5ebcbec3d5dd4611ba36e2754fbd3d327273bf2eb7b7ba4b3888d059dc87f034739000000000000000000000000000000000bcb0a9dfe5189bc965e9721407b4cb3ed4171510aa4d4e5d5f0823a1c2827643e1278f9c0ee960c54ef8f6c208eee7b334582482a9038ab906880e43a4a9d39e73b6c63604eba0c8f6399eb5c288638", "Expected": "000000000000000000000000000000001205b70b29ee04212589f8a70a71e004f517d3354e714c1b4fe42cf93faf1a8ed40dbc1b5089ddb53bb052c9cb74c0e8000000000000000000000000000000000f619082734dd9de653b61cf2fb927199f228637db70797bd2a21fdd48b6ecd4c4f712097037534024880a436fdd63680000000000000000000000000000000000592eca560be6ae256abe1796f7ec394a8085c127437f6590c8d41501a482c61456392cb320b9e801044dcba7802df9000000000000000000000000000000000a6d20b8009708ca01a274aed6dece732c5eed5aae5e4c2f3793b5fa1f8cb8c95037ce387bda2e7476e9c493507c7fbc", "Name": "matter_g2_multiexp_99", - "Gas": 293920, + "Gas": 240480, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002", + "Name": "bls_g2multiexp_(g2+g2=2*g2)", + "Expected": "000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3", + "Gas": 54000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", + "Name": "bls_g2multiexp_(p2+p2=2*p2)", + "Expected": "000000000000000000000000000000000b76fcbb604082a4f2d19858a7befd6053fa181c5119a612dfec83832537f644e02454f2b70d40985ebb08042d1620d40000000000000000000000000000000019a4a02c0ae51365d964c73be7babb719db1c69e0ddbf9a8a335b5bed3b0a4b070d2d5df01d2da4a3f1e56aae2ec106d000000000000000000000000000000000d18322f821ac72d3ca92f92b000483cf5b7d9e5d06873a44071c4e7e81efd904f210208fe0b9b4824f01c65bc7e62080000000000000000000000000000000004e563d53609a2d1e216aaaee5fbc14ef460160db8d1fdc5e1bd4e8b54cd2f39abf6f925969fa405efb9e700b01c7085", + "Gas": 54000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000001", + "Name": "bls_g2multiexp_(1*g2=g2)", + "Expected": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", + "Gas": 54000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000001", + "Name": "bls_g2multiexp_(1*p2=p2)", + "Expected": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", + "Gas": 54000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000000", + "Name": "bls_g2multiexp_(0*g2=inf)", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Gas": 54000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000000", + "Name": "bls_g2multiexp_(0*p2=inf)", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Gas": 54000, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011", + "Name": "bls_g2multiexp_(x*inf=inf)", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Gas": 54000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002", + "Name": "bls_g2multiexp_(2g2+inf)", + "Expected": "000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3", + "Gas": 79920, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002", + "Name": "bls_g2multiexp_(2p2+inf)", + "Expected": "000000000000000000000000000000000b76fcbb604082a4f2d19858a7befd6053fa181c5119a612dfec83832537f644e02454f2b70d40985ebb08042d1620d40000000000000000000000000000000019a4a02c0ae51365d964c73be7babb719db1c69e0ddbf9a8a335b5bed3b0a4b070d2d5df01d2da4a3f1e56aae2ec106d000000000000000000000000000000000d18322f821ac72d3ca92f92b000483cf5b7d9e5d06873a44071c4e7e81efd904f210208fe0b9b4824f01c65bc7e62080000000000000000000000000000000004e563d53609a2d1e216aaaee5fbc14ef460160db8d1fdc5e1bd4e8b54cd2f39abf6f925969fa405efb9e700b01c7085", + "Gas": 79920, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000000", + "Name": "bls_g1multiexp_(inf+inf)", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Gas": 79920, "NoBenchmark": false } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/blsMapG2.json b/core/vm/testdata/precompiles/blsMapG2.json index f30eef6564e0..0b2ad89ece9c 100644 --- a/core/vm/testdata/precompiles/blsMapG2.json +++ b/core/vm/testdata/precompiles/blsMapG2.json @@ -3,700 +3,700 @@ "Input": "0000000000000000000000000000000014406e5bfb9209256a3820879a29ac2f62d6aca82324bf3ae2aa7d3c54792043bd8c791fccdb080c1a52dc68b8b69350000000000000000000000000000000000e885bb33996e12f07da69073e2c0cc880bc8eff26d2a724299eb12d54f4bcf26f4748bb020e80a7e3794a7b0e47a641", "Expected": "000000000000000000000000000000000d029393d3a13ff5b26fe52bd8953768946c5510f9441f1136f1e938957882db6adbd7504177ee49281ecccba596f2bf000000000000000000000000000000001993f668fb1ae603aefbb1323000033fcb3b65d8ed3bf09c84c61e27704b745f540299a1872cd697ae45a5afd780f1d600000000000000000000000000000000079cb41060ef7a128d286c9ef8638689a49ca19da8672ea5c47b6ba6dbde193ee835d3b87a76a689966037c07159c10d0000000000000000000000000000000017c688ae9a8b59a7069c27f2d58dd2196cb414f4fb89da8510518a1142ab19d158badd1c3bad03408fafb1669903cd6c", "Name": "matter_fp2_to_g2_0", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ba1b6d79150bdc368a14157ebfe8b5f691cf657a6bbe30e79b6654691136577d2ef1b36bfb232e3336e7e4c9352a8ed000000000000000000000000000000000f12847f7787f439575031bcdb1f03cfb79f942f3a9709306e4bd5afc73d3f78fd1c1fef913f503c8cbab58453fb7df2", "Expected": "000000000000000000000000000000000a2bca68ca23f3f03c678140d87465b5b336dbd50926d1219fcc0def162280765fe1093c117d52483d3d8cdc7ab76529000000000000000000000000000000000fe83e3a958d6038569da6132bfa19f0e3dae3bee0d8a60e7cc33e4d7084a9e8c32fe31ec6e617277e2e450699eba1f80000000000000000000000000000000005602683f0ef231cc0b7c8c695765d7933f4efa7503ed9f2aa3c774284eabcdd32fd287b6a3539c9749f2e15b58f5cd50000000000000000000000000000000000b4f17de0db6e9d081723b613b23864c1eeae91b7cbda40ecd24823022aee7fc4068adc41947b97e17009fad9d0d4de", "Name": "matter_fp2_to_g2_1", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001632336631a3c666159b6e5e1fb62ffa21488e571cffb7bc3d75d55a837f242e789a75f0f583ce2b3a969c64c2b46de200000000000000000000000000000000184f1db9ac0fdd6b5ac0307e203d0b4237a50554eb7af37bb1894d9769609c96c8437e9d6d3679ebd5f979eb04035799", "Expected": "00000000000000000000000000000000184af3f8a359dd35dddd3dfcc6f5b55ed327907ed573378289209569244e3c9c02bdf278eb567186f8b64de380c115360000000000000000000000000000000012f5ba8e520c4730ac1fb75dabbfdc0181855e5ba2968a8c0ba36a47ab86ac45d19aa3d55f15a601e120be1f75eefe240000000000000000000000000000000004e313db704b103c2c1e3a58f8e95a470e7199081eb086e9524583131714c4a3db551fd51a3f2314a19a658e7b1765380000000000000000000000000000000004040eab7416a1703b0d103120506f1de2b26b0f48c7a0ea63dca4d9ad1c478ae03b5d7bfd51f4cd6f8cea26212c4edf", "Name": "matter_fp2_to_g2_2", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000732f171d8f6e283dd40a0324dae42ef0209c4caa0bd8ce2b12b206b6a9704f2c6015c918c79f0625fa791051b05c55c000000000000000000000000000000001139e8d932fc0ab10d6d4f6874c757c545b15be27cdb88056ed7c690aa6d924226d83e66b3e2484b2fc3dcd14418ee60", "Expected": "0000000000000000000000000000000017fc341e495bf4ef5da4c159a28320aca97ca28fe3a0441242cf506b0f89bb52f5b5d8c6e038d229ffe67d00151912f00000000000000000000000000000000007666300b7be3d904ae3d19019f7be5cf5ba6161b969c1a78aff639a24387d8fdcc4d0e3cd81ba6f063ebf2d859370f20000000000000000000000000000000007cc705dbfb5c0418beb1cfbd864fa0631bd60eccfdb16b5d55b6ef3558e2ec87dac3b45294dcf04a064d6d1eba5a6eb00000000000000000000000000000000052cb9c982e6b05c1d2ab4eed1d8082f96426b55615ebc6a53bdc320ccad0aad044395ed641b3176b554f19e62d46b73", "Name": "matter_fp2_to_g2_3", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019a9630cce5181fd0ad80677ed5ad8cd8bce3f284cd529175902b78ad4915f0df56f0d8b37c87c9ddb23d0342005f1570000000000000000000000000000000002cdd00b7662569c9f74553a7d0585312a776c8638e54ad016f8d9d25df98651789470b12ce2626fb3ad1373744387ac", "Expected": "0000000000000000000000000000000015ad9155037e03898cb3b706f7105e39d413ff3a5abb65812b8d21d003cab8fbb607d3938ccd6a774bc8debfa30f42760000000000000000000000000000000019d6382bb2d78180a8998a0536d67412d00ec0ef65f4cbce01340b8d6e781c0ff790296f8cada28966b147c69e02f366000000000000000000000000000000001290c2c205b748069d0875a89ca74a3b05ad8218ed46a1570696932302983c090d96e17e0b828a666fdfc3b72cd348bc000000000000000000000000000000000114f2f7ffaa9f90b547e86c863a5d3585819a78b095848dfa39576a10874a905488687b73e613f3d426510f5d1d1ce1", "Name": "matter_fp2_to_g2_4", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e63c4d12a38837354bbcdf4f844e5dfe727ebe292016748007d162e74c1f849787767f7e77fc57a42783fe0b06c24c80000000000000000000000000000000008d879e4891a891f2e7d27eb95aef70d5b785b796620ec43dfbb6ae550b4effb9f24210dc20f401d54420445e21cfdd3", "Expected": "0000000000000000000000000000000012084a53cde353a46af17cd2fb02c477e47b874d8ff58025b5015837759032ff98013dc5bf01253bb964f035183c9071000000000000000000000000000000001659272ab7e3a070a5c7b25a5d3402f7371ed67e58cac8438df41c39c1acd95ac5886b030384bf537d7c4bb8ddb2c538000000000000000000000000000000000852ddcc37a09a0a8f62dfbd1ba5064c1f6afacc9a279a4d998bed643eec5a0d96d6bad95701a04f52c83e8f87f48d5d00000000000000000000000000000000097a399370875398028d42bde8cf4e9641730af7a2971e2f59c95938120603a239c65030ded4323c955f7fd24bebf31b", "Name": "matter_fp2_to_g2_5", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000028d6de947a3958af5b53578b0ceacc7ef89d36526d8f3b6fbe787af69fed2c85cad3001643b81c575a741c4566e617e00000000000000000000000000000000182b56202f0494bd8baf5c03969288a1288b8ed8e6c7f49ec9f7493ee3369eeb42fa8f5fb7b243fb2bcee6be244f02be", "Expected": "0000000000000000000000000000000006f8191123f1e8f6a05e4e663fa763c8a0ade5de3c7cd38ec1c82e1c85f123ab51fffcebd677afec8e9adecd8d11263d0000000000000000000000000000000004fcd825bc55d044eb70e0bdd5ea2ac58ec1487e903b431c57a640c756265a382581b8450fb15dc649cf22a8539088220000000000000000000000000000000015259f83d76490bb868bb88c2a2c3e07a326bd3e97fc2f552adf85722a360a443d720c328076e35224328e09494746e0000000000000000000000000000000000f76b0b960a1343b4267f5aff44901fd6796a778b1a87666b95b773edd0e7ffb6656d4f0cc3b9b38bc6c0ed20cfce153", "Name": "matter_fp2_to_g2_6", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000016adb5935f32bafcccb81cf4d177dd8826013d85e11a4aad66e3aa596e1183aeb9d68eb8cf5b716a8a9445ea81b40d7a0000000000000000000000000000000018bee24b0c97af8aec210f15bbb6acbb76168dabe16e669d5558d8d32f00fdf5146471922fa98a28f238974d327996a3", "Expected": "0000000000000000000000000000000018bf5f93dbc2c37479b819f8edccd687c4d3c4dd04f8c73762fd89d0c003674e3b2ed749d23e775f925279b3112689f80000000000000000000000000000000008a033b197aa8ea2213dbd7ed478d98c25dc6e9f91b9924f3c14124da26a67bb196926e02da89b746f2a67b14ad226070000000000000000000000000000000006f7824bdc9c53212609512858278f79d9b094165ff178e3da8776e24311bebbd9deb29f366d4c7693a15c34df118403000000000000000000000000000000000edde25fc24b9ec58b3c317aa3ae48dd5fecdf6397ed9636ea042722d264db0b1a89a15a1e16e892755730ef52796527", "Name": "matter_fp2_to_g2_7", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000114285411713eafd395ee43bf1728f52d17ac512b9d0cddd38c904a9a3a1b30283a3918cd2cc3da6a7d6b4ff923cbb6e0000000000000000000000000000000018a067f91f94b2904c5bb6900f427ec4e93374b5079c84707feabeabde20b5e49801f1f3c7504dd27da94d5e754df4ad", "Expected": "0000000000000000000000000000000002d28025f4b798083aec3ca9a91a051ce27a374b115c944932026b4fe0dcf68b335d5e47212f800c241c2d42fd219635000000000000000000000000000000001742fb6ef8e9a5a7572b0d3fa4ae8ae56c9c6f4daa20d0b88212c40511c6f6b5ee98314a2d1cbe4bbbec907495a1ade8000000000000000000000000000000000d700a511a58c1b8f11153669cb21d88512dfdacbabe38e402431b4f7ba374b5f9a88614da2d56799d39324e9d19e27a000000000000000000000000000000000c6068bc7a43d614b8f1132b13e04f66d2fb5ac0c5bc8501b754a0bcf4f382db92b0994c4999e104c9d1111ef91d5edc", "Name": "matter_fp2_to_g2_8", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000dafa9fa843879038fd1566c319c24119989090c5fd34f6514e57f633d3709f0aa9954dfb289843a6990588e337b63e6000000000000000000000000000000001742a98dd7d3671c2c64aa71023a0040e936fd726c062d520626113bed471e53ff3e85737e5abf9ee8821bae53135f20", "Expected": "000000000000000000000000000000001350c68434a9b02392e60540a3985bae8daf9a170b30336ac73afae6f892c7ae8f5f1cadfb2780d6e5961ebf91cd69ee0000000000000000000000000000000000c20bd286fc1886b9b28dfa40d1a27395cf76a8b73946849ea0a7b5e12530de13c16acef8fe2a2c247ea65ca023eed70000000000000000000000000000000002d8ffd0235fb60fa573662034d46260e0c96396537b2a9d486dd03bdd13c5a1efd2d3cb9849ed11c4376b665f378226000000000000000000000000000000000d90ca1b73a6a9566832f9f19d8530a3b12f22bef853fc44088559b923ca108cebf4291e0d7de8f25c7429d455f5ae46", "Name": "matter_fp2_to_g2_9", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019cda532e5d94f3b193b3f286a038637a736c2b87b804efd4779359db5bd95320e06d6d28da3c229ae48ffc02303fab10000000000000000000000000000000018df89e4a545bfb825bcce2f4c25f2416a72e32633b3dead5205c8b7d69c78f119d0e940e5bde9ae1cf91574e5d6c175", "Expected": "0000000000000000000000000000000013f223602e8d12c3bb51cd393f6f59beb5c55fe80c3fc8fb0bc90eca533d9b7981563a30ebd727ab6cf0111fa2d3099d000000000000000000000000000000000962b0585c681894cb701f17ec06c0c240899db574c02d82d85ed4dabd4b8654c29b84c71d2921986fc2abc542a3ed9f0000000000000000000000000000000000f0e79245e645a6e3fb88b9103ede3e6ecdd7e45d61b5755d7a8d100d80719746af58bb23d3068cee7389b2acf17f8b0000000000000000000000000000000017fa0aac84c58283f34b9bf713cde98c175b38e92503c08205350822d778f3dd5bed8051e185c495831a628aa89335c7", "Name": "matter_fp2_to_g2_10", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008ad60829ff001404da40923806e496640a90c5c258a41ef5912f8a1a20eab84ce43b2b5aa4aa7dc4d8b281591d235020000000000000000000000000000000000f13dfef4b3b83aa7f9525eae9913e10502e77c03c55a7aa2de083dc5102c098b6f8e36cb5247b827e30fbcded9e2d3", "Expected": "000000000000000000000000000000001062c97c214b86518660c5e1c33a4e48923ae89ab7d8bc5c798e631de16fc1f104aa957d3e7915aee8551e24aaafc8e6000000000000000000000000000000000e42b785f17f25b87a0dc558a8d57b19d8f41767c3b4fd70c147e95443aff2d9a743003da41d578a2b56d7dc748cf59500000000000000000000000000000000111fd38cd2f5f681bb37f6239a5eea820ce3f01023c685f8e7e244fe9aa9dcbd18f0e50705faa5d8d66b28af9f371c630000000000000000000000000000000004726d3e452f6fcb180ce1d50bbee3a23f7949b635a058f12de1cf5abda19c042168feea53211dbed0bfca489a020930", "Name": "matter_fp2_to_g2_11", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010468e5421a72ec85b63f7f3070a949223105763868111424fd151c8365eb0307dbc9cbc92e5dfb296d06ddfb58d99000000000000000000000000000000000008149ce856d489050ea834452bc66f7f3478c2056969354dca8652f3d0a349e40fae0c4c57ff0f5e022aa93c61f8c844", "Expected": "000000000000000000000000000000001211bb8d3bf65b60efc7237ffecddb4e7e2f0dd36e2a704dfc9f4972897addff1a57182f8e0a0ac08c9af2c98eaa4c560000000000000000000000000000000007e9877280aad45a3b1453b6771ab509e4f53937cc6da73d3add50aff94869b27f49218fb479fe19a6176b9aadd36e35000000000000000000000000000000000ff915801695a281f6642751be77155a813847ae0237d77d2edf836aebac02b659b98d49842d4d10e82d9d146e63a3da000000000000000000000000000000000fae1c8c01a2dd94f17c660353d158ff6f3eed4e6375f1e414ade9d6fd040a48e3ff0d558c882e92e74bd6ef4ab06168", "Name": "matter_fp2_to_g2_12", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006295de7bfec61f06a56fe09afbb74be968329e88ba2e87afffe9ea9bf646ff5b4a03d6088e87644958ced95eceeea08000000000000000000000000000000001443e61dbf14b6c6ed99e1917ecfbe5a4a23ab9bdd3bb089fbba76d795d715d9d2e3c7d8db0b7a9434ad691b68bad3b2", "Expected": "000000000000000000000000000000000dd00d9f31cb5148048125668286c1790cb7294e740df978ac0bdaa6e1c4ba139a04f5770b194c9bcfb123d9b40b6acb00000000000000000000000000000000085d5f4cb831720fa13cef25464a1ba7af33abcc4079d2c5736a219ad9649ebb5dbb8687a2d3952390866587d7088f72000000000000000000000000000000000de377d773e40e1c76e218b969297d15f7819c525ce39aee5114e8405bd7361116682cf9d673574d415a7016b23b567d0000000000000000000000000000000018db26c2097f72b8788ef5aad2d7aa400627e224924afea1ac7c7a6b5cff4a55255e218572614519a536eaaf0f65533c", "Name": "matter_fp2_to_g2_13", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b14b12ecaa94f9656be54772be9b22a2495d4ff873b0bb971c27ab1d8b940c84cabcf921f6f75e93942c38cddeb87500000000000000000000000000000000019eca0daafbfdcd3b56be863dceb21e624b22c0d376fb92ba606456ce3825981713b88e40b7fd801e915f97d5c29ba75", "Expected": "000000000000000000000000000000001853b4c4e6fcdbed29c5d3aa4a9f6d447adc512f66a32fdef06c6ad316c42eb3ca47ffe6f21318ad610d0a68673d7bc300000000000000000000000000000000123d15c37fa8b1a95229e28500c9a767e6286b780138dcff2714bf1f8242f39bebb7d86e2811551914719ca90fb5615f000000000000000000000000000000000537498c2ec64b2ba58aa0a858b69990cac544d5cac29abdf6a42ae9c04061f83580b79c2a6104ebc55939d9a2bc5ae2000000000000000000000000000000000b348c19aad3b67c690512f372d995555ee38bffcdaf33bb827160d6929d2ce598523880f6136f11e1d6482a654cb016", "Name": "matter_fp2_to_g2_14", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000104a452343a4098e9bf07380a8e52050259da95f5fc88f31511a08090bda85f0a08d49cef95bd26c7181aa3eb0be122200000000000000000000000000000000012400aaec3d2f4a1a8cf3f28fd396133c3999c074a565c110354472ae29479b9b62ab67128521c2c6ec4869811ba760", "Expected": "000000000000000000000000000000000994e7b6ccafc996f672c42ab491105ffe1482e65aeb456de2213b531889773ad4d5e6ea1687d6a1f13e74878766f11e000000000000000000000000000000000b89030486a1d622c97970ee7da6189ac341b9cafbb4081463f579ab8b4b049c6e6c8b63157455770a79108424a14f24000000000000000000000000000000000ded43800a991f8c37282d803a39941d3bfbfbdc56dbf7500ef3d16750b27dcb1ad93f89714395fd3dffe318c1771375000000000000000000000000000000001994144b032e1f8c4d688754eef82cdba0018ac47030fcb77e8fd920e0b0336255d2cc8376c03e1074f91269cd2519d1", "Name": "matter_fp2_to_g2_15", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000093e04bfcbd77bc6bafeb77f02d0f794a20b155435ee3af1d667c025e7645d9387abe0ef281386339f461352da93fbe2000000000000000000000000000000000481ffec570d4e155ec10e0cc58effe7a5651795d604cfda6cdbf011676772fdce2c25227e7d5a1a26748d15b1668091", "Expected": "00000000000000000000000000000000195d99406baadc7d8740962cbbf4bc1f22b08eafb52f3cb3c588b6cb3cd89d16cb7b8d388563289f5b5ea466128525c80000000000000000000000000000000004809f70463633595dd763d658354df4f9b409911e1a0328fdaf486d76ffb410d7c6cfcc2d48fd6757d5c2a4834f81fd000000000000000000000000000000000654f8475562098a2cb27ce224674a383283cde35173e1c16b141998b641ac9ee663d766f045451a7f6d600973f0ec520000000000000000000000000000000013bac451a44982c7b1aaac7522dab598cb79b9a3dab77f4d5a4c1c97c154451499979af1f86ced8ce2099bccd400420d", "Name": "matter_fp2_to_g2_16", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000013a3c5dd40f7d7fbba7563331917fe19a093d5d25ae7993200c39460e0c46d839e3958b672b4ed195300f398137faa18000000000000000000000000000000000255bc4d313fbd61a270dce8c851f1fa09e6ac5dff9b9e8dfc8a236a1d44548cb079023ee9b8f0f5756b39e44489c3f1", "Expected": "0000000000000000000000000000000016ea88d0bce32981f489438df1bc14e7ade7a45d449ee1ac1a041c1204460cf53ae5c0e111914d8af9e6b3b7fa394484000000000000000000000000000000000db571ca6a55bc8285421553a373048f7877ecb9683d52acf07d48e1026795993e4e7177490921bc6fe1e63d69c2de3c0000000000000000000000000000000011602919de1df6cc0dd36a59c84ebb8e209056534e336f5074c9ae5323f8a03b123dc6354cf85301d838b16518ab64390000000000000000000000000000000004407d30fbd632fd493055bd4d8cbed337767a2ac534411a3eabec570ba41d2ad28ef37512a7da3611ad60b6536b3f07", "Name": "matter_fp2_to_g2_17", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ab7b4dec955de92224b234c2d8bb2e3881806c2d36a9a21036e9412f0a8d3946027cbb65b5dd9c975e01b3f235b883f000000000000000000000000000000000ffbb55002d9e926b3d8e7d963ece82c14afaca8b4d8415df8f964a39db606ac99f9e442ff69f7ddbbc4ae563b836192", "Expected": "000000000000000000000000000000000c1e7b188697aa9a053f14e2d907f2c61a59e0b0c72f9cce30faf81dc714a50113500ca9bc3af6657a5d214f52c90616000000000000000000000000000000001544c35d712eaf79d8dd5a22fbab72f8a6843728898412a7f305b205f8a50e03c6c462b87b3ac165e9e6428e0a44a74a00000000000000000000000000000000029ebafd90a1a887669fd0ace762a66bca2bf0a216333b0ac97dedb6bff3dda2bca1e3d0ed5fa9081c2887fe6a8e24cf000000000000000000000000000000000e1a01ca93ed268e0291a937483f7f8e252c91f9bd8bde55271b0c97fcbbb9219009514217dd8bd7e0267f44e9927a93", "Name": "matter_fp2_to_g2_18", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000103469c08562f6f72152db58b48811b0098b68af8de00e652bd5a67246459664cc8c54e15705d702d51e3f1d8ff76a7700000000000000000000000000000000059b326dd567fb2f8a6ae87f41fb22b3edc25122138a5f6732edb48ed7fa1949eda6144297f54faf406d873a016a1510", "Expected": "0000000000000000000000000000000004e8ad9838e7e269cddf0ae5c8f0f57e7467e0b6f2b9e37e7c4bcae965e9582dc46c9c50aa01f5dc761bf2f1ad311eec0000000000000000000000000000000011b1438ccc668900914578c3ec6e1334d0823861c892608817498fe2e538deec73e0034a6e8ba9790f63fdd95af3714a0000000000000000000000000000000005b4c88196425d3ecd22bfc0cb1a95488493f85bb74f50315f0ffcdd57ad2de23c137cd6d2f6f6dca8af2e3f7bb0539c0000000000000000000000000000000017066344a0f345ecf6a2ba66c37ccbce26a3f551524f74636d4c4812bf5adfabffb0645b898b10c332e94e5f2ae2d1c2", "Name": "matter_fp2_to_g2_19", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000bd594d2f5e1472f85bfd550df3eb948085781459eb3037fab34186ad9a0204a0767c8fba571af858a054dc231931b8000000000000000000000000000000000087b8398406c1e707fe87a16118e2448d6a5f4fd1d6c9d7174c4d8a4314fc7b2c21f04178533480976dd20e28b278ad5", "Expected": "0000000000000000000000000000000010d393bf893d589c578df58f4d0098ad3cd10d3a1d0f112f51b132a369e68c0284a6b70a5673383ae24a27a9043b16cf0000000000000000000000000000000003402afb77b187b45906d9cce348976ed88c758d75b9962a53352a6c3ee37751a9928097c0d68c6f8a315def4ca875200000000000000000000000000000000019b98631e53a3ffda3fb9165ef7236dad5c0c8d57c3315617cbd3ce77430bd89b9e1d88a019042cae0075594514a5e67000000000000000000000000000000001783bf1c9b0ec44c9191dab01ef5bda0cb2f533dbcd3aeac2b7c6720dbc8e3f770a215ec8ea2035129711ce4b448ba87", "Name": "matter_fp2_to_g2_20", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000673dface7041c3d7503ce4a50af946d344ad48327b515740b45276403d91bf1ef9deba79c8ffa0126be990b62bf3072000000000000000000000000000000000adb42b7eb0f6759a04da7b933bbc2b6aedde47da8571d6fa32268c606dbafcbc810844017eb6377493a12d76ca56c03", "Expected": "00000000000000000000000000000000086ac901098212acd091d9c4d42a1318c3b343480f1130d6e52128d61df9e19fb61ef1ff35de0ef60062cd99202910ff0000000000000000000000000000000019109b7292f1a420f09a56dce9694cb4944808a2ce9f1964cbb6ffd14a710c35abe81300090ffcd9e95f33e0de9f879a0000000000000000000000000000000012660c4e114a215390c6f6eabc4bd6e3d062ee28d0c87e24351c7d43195253cb7b5bcfed2b4abb2fdeb3ac04ee228997000000000000000000000000000000000e56d35a7e40a86ffd2088c81488265ecc4468d6cf02d563c91611cdf8b4333cf66ef50b993fe651b1792d2b242cff94", "Name": "matter_fp2_to_g2_21", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f554e52c4a6c5a94fd09c617f57e8f87af57e73ceaee8997fc62c8ddcb2f875ee805e6594a0fb72738abd3cd4748ddb000000000000000000000000000000001876dd03316ff007a2efb4c5f452d8418edacc2881b20e8340895f6fc768d14fd89bd9db3dcfb53fa98a1e96055fa83e", "Expected": "00000000000000000000000000000000071d3e796fb15d63c2d5cf68f59f11792b0b580b85c8839a02fad96664f14735ede2edfd5ba5b64045b366904f54ab600000000000000000000000000000000013fd1ea38d32772458622731b9e2d9d749f2b747443f7e47ef5e041531b56f86d1775d42a548b2bb201228f49ec9f46800000000000000000000000000000000099c2bd996c8c5ee37de971e8b75a0bdd4f69299778ee3d216973c9dbba97c7a93e40b209d390024bc4b5e82560a1a83000000000000000000000000000000000c4922ed9af845467440b78efa3a53ba904f29adf66e8ac437c8bb6624b5e5ba0772a5639b45fe167b1fb9283747c50f", "Name": "matter_fp2_to_g2_22", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e8b2369fc2c584d78d52037b109aecc87dea0eefc2da46948b5535ad19c9abdb31aee66739f4852a2d3c51f2e7f74e900000000000000000000000000000000168b2d3e4b67390cb8ba5e48a7a823db08edee7d8eff41b88cd653cec1fc0df7a55303d3c91e92a2dc8ebdb327b225fe", "Expected": "000000000000000000000000000000000e413d72fdc3db6fc79ef26ae8b37fe5c4356a80b3598513b5173b3406ffb54708b8794dae158060a1accbe956a39ff30000000000000000000000000000000019ba9dfa74fd241a55a3b47c9f37c6ebd1e8b51f46197881abb64b7f57c0e2d8f18edee35bb9da03702c0dc5cc8749f700000000000000000000000000000000183525156fbc80cc67d6cd15fd2ddf7fb0528656ec1d31b4c275ef101dbb635424abbff1154a3ee04346ac53148fb1f70000000000000000000000000000000011da0dcd666d01180902d8a7fd7d2fbb39f9c7587540451045956108a8579d7c116385a81627dad9d4cb8cfe68927b6d", "Name": "matter_fp2_to_g2_23", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000016cf7b1a9ebafbd20c078948fc974bcca9b8069edc1ca5e8f364f8ca2a52e56e1a424ea6bcc4240f46dc7f262760bf480000000000000000000000000000000011a6a67d4501a8d9b3ab985be59ffc41e79c453bb5548299abff3b83ba9ff951025a68fe6a8ad3eef3c02d39fca8f909", "Expected": "000000000000000000000000000000001932acb1fd0708edf13c293007a035991bdfbfe0089b61c261258e8c5c10d82a5318b2af221b372f0f3f43c391421582000000000000000000000000000000000973650743f0ec8e2acca33f2ef230ee7a05635d14099cdce913ad8678458ec0dde5c5a941097af2ee0c8ffb937d09fd000000000000000000000000000000000bdaf319044101ee9aa27b3accd36a5ecaf8b80deda4548377ddeb97283537be3f7199ad3c190ed23cdb44abb8786a080000000000000000000000000000000006c448827e3fe4f274bfa55a66bc76c5b01e29ac6a8dbebd801855ba4e93bcbd03292ccf804f07f21481260c135b827b", "Name": "matter_fp2_to_g2_24", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010e53fe9fa94ca622cfa370129c1619b2426bd9d50f4b5eb8a3f681479128dbe92adde15477ad8a4463b08f1a02a62d50000000000000000000000000000000014d10a90709789b25369f0376f39b16860aee1ddc3a4340542abff0077a4af8da946cc29fb6afd9930b872ea98749be5", "Expected": "0000000000000000000000000000000004aee050b0ea07118d76f835218b77b39854f5ababc4e2a29d7c8cc7c18a69c30bb22437049a051d049c8a84f7868ad40000000000000000000000000000000003b1b809d5046054924c3814d26fd5fbdc59e03e5505813bab73bc212b0f5bc0d3fc34478311c5e1ac70fd16a01c52800000000000000000000000000000000002249a026af0b49f4659eca2c23dc790fb36a7b2996188828a17d5852003f1420f11699062932835cfe6543d454521e30000000000000000000000000000000008217aea2221f8748cd81cd37777605a95a63aba36a6ddad72c1e1ac57b24d79ff9d9c4ed71a6e3ac8a378129d5475ad", "Name": "matter_fp2_to_g2_25", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000194612afb777e39d0308a290bf823fe706487c3473412d1410dcb2c0016a70706e70e3a009c0bd61e755b1e4c65bcad0000000000000000000000000000000000ade016d06179faa8d44a9ee2542058bb81724d6af2954c0c09a897703d364ec25e62a3a917c5cecce5c96a7cfba924a", "Expected": "000000000000000000000000000000001274f676bcc05e54fa4b0cce234870ba97a0b1626543d6a9f09afebd5a752769000df404e4d434ebfd561f8335f36d0d0000000000000000000000000000000002877c9438fa319dd1a00f381834e8f3d3cdebf4e1f7690cb82559a2e978bedfd2455be020d0353aa56d435c0174b5b10000000000000000000000000000000009487cc9c7a09be901673cb1bd9a51f45e5d2ed30c90cbdd3e2b294c8f866f68da55533b78152e9ef6de30c345fde5b7000000000000000000000000000000000a3a8d4aabdb260203898655745cb695e6dc90c6e7bf0248784f8aa2340390fd5d8f1c6a98eb1990eb97c2a7f103e3fe", "Name": "matter_fp2_to_g2_26", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005aaeba19cb0baff9a8e46b901f15735a0c1f45116fe1f41c22fbe1aba22c0a7678bd4799db5cd9141f3112877e2c5f80000000000000000000000000000000003f54664746a5bc6f64021e2f18d8c175d96b1c8ce895809c0e6fcfbe896b3e8c1ac7f7556b9ef953371bb143bfbdafa", "Expected": "000000000000000000000000000000000ef415dfc1e47f39e9632ed21c9c2bfcc1959299710dcd7935a757e3756a42c8f6c627c720fd62f9c486a8e88a64c76d00000000000000000000000000000000088079108fe7d9ac93590c045be0d41396f3204d83793c4e862c5360ddb3268a63f704a9d14323943fc85874cdadaff1000000000000000000000000000000000cce908e8dbb7ec35820f2db5ae1174e0f675b21ae416fc89a7f242df3ee98764022744842999f65132229156d2627370000000000000000000000000000000011e0e2f8513d0a71b48599139a9a29c8eca090c5b02292baba58e07b1d3898fe158cdeb3bbe8edb4a805e695e896984a", "Name": "matter_fp2_to_g2_27", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010ca243fcabbdb219c5b30092d9d4595a4b8ad1cbed267229eb79a99aef9c5df03d8f24b71db77a5a76917c2fd960ffe00000000000000000000000000000000135d8d92f075c219f8012ce6aebc8e48443b2f33382479a4ca8db0a4f92041d5b6b1e5818b7a3de77a5d30be0e461d13", "Expected": "0000000000000000000000000000000007c6f133647745c312695439f1d8c251e941bad6e988cfe324ec7c959a9e0fb50618984429ff1841d4286922a26873170000000000000000000000000000000008edb220f77ed17fa1f4757a42ec66ad808c1acc25c4b9311be4c09703d547f648d9dd7c8109ffa89d01a35c69ec2685000000000000000000000000000000001595cc05b04f557ed569b19d64c09f4d82e6617437571fddd72a672d07ad94bfbaaed906b3a7e3db519159ec8d0a8c4400000000000000000000000000000000041157d4f40bfcef680af0143ccdd0c4bdd25e598a470dae844d887c398bc498edad715fd7383421fc78758cc9b00326", "Name": "matter_fp2_to_g2_28", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000013e042ccfe0cbb7fa3b045a1fa1a86f199ae91721aaed488b96cc4f6de1899402f81842da2ab55c5bfa63f5b19ddce7300000000000000000000000000000000063cee89d1981f27a4f4d4f23c4d1229fd3333fc8f371ebd85c588e751307ccc75d71d151f7481ecba1ef0cffbfdea5b", "Expected": "000000000000000000000000000000000f983607a6d8a5c3b8a577cbd5d81ad2ae936e714199e3f4095cf280b8fd6d3699acf4d2ef251a571dd1ef4ba6d838bc00000000000000000000000000000000048c12f8b95f9537e56479b1bc43a121e4edfb6477fcb090a5ea60c5f4d01071776dd0264b0250902448f62800f4d2ea000000000000000000000000000000001644ba272d7003d0077991ccb4569638de0dcc48fd2e8e9a41cee1d2200aee1a849f2d620f60beeb06b08c31cd4eeacc0000000000000000000000000000000018892d773f7e48247215484ca0c8d996833c43a5291b0380c97607c86f4ab2784e692673a1da012ac4fec2713d156a49", "Name": "matter_fp2_to_g2_29", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e07265d2762e8e398c83efe1c43452d91b90b7a4271c09ff693c83745a6c01b73561ffe3da9300c8e7e1602dbaab0bc000000000000000000000000000000000375579c16a167fd9f9f61d5177705f157aa0df3451971029a9444432db119fb33b8c07de33fc822eab46ed4ae47cf82", "Expected": "000000000000000000000000000000000a06ea8e644d2d762520ad956d41ac2086a588450bc34f6d070b86fdfd73cd0734341a751d823935a009b7517770f86e00000000000000000000000000000000140ef0d6a0482537da7db8d775ac3c4a93b16c15fbe4602b5b1843ce757aada5f7776a74151d0bcf760f7284d4ffe56c000000000000000000000000000000000873c90f56a2b99da2f0a1528b8e376a5912f9cd81a159379ad70b7c10e6ebb7fea0a90d65543d968a34ebd539372e89000000000000000000000000000000000b05ff57079386e4e18e73cbff5f7b0efa329ef7355f083e8be258922203240dbb8926f7d11c22ab4c16d1df4bcbb600", "Name": "matter_fp2_to_g2_30", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000aaa37576af2101d090139f562edc2a6e7169b0150af831d053a3a87a3a5518889a51871e02deb3ec154ccbe9dda46df00000000000000000000000000000000158edaeb58b99d9442d608bc8e6024365e9a81e0aa23bbbd466c9ccc8d29415352a153e1f852666505ef097122592ecb", "Expected": "000000000000000000000000000000000e9d6f9e83a2584f2cdacc4711085bd251e060f8c87ff7538ce474d663c6f23361c88971c9da589586e754ed69699c820000000000000000000000000000000003fa90cc1dd81b815704e15c0448bd0e8e8d0cd7ad51237a25d4b8a0f78f532b18ec30a108930b7407b7486aad9824de0000000000000000000000000000000000cb97bce1f75b1df5a4b52745014eb632d2d2230e52a9767e3dfd76754e98252ca81ce274b92a2947f6a65fedbaa3e400000000000000000000000000000000090edabb37f411fae1764792083c8c7412fb470833a9f7399fb312c58687d4afbdc622ecf9d74cdfa3ea87382adcdd5f", "Name": "matter_fp2_to_g2_31", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000012bfaf34a8111a01d213f9a9fc90846335cda978b3df23de99cb7b764cf5db1a816f66adad1319aa7e25c0ab89e7de740000000000000000000000000000000000fed118654a128735fd39ffd3b381ad2d71479054b6bccc04dd58fbeed9b255ce2b925e2141a96a12edc3a19188d1f5", "Expected": "000000000000000000000000000000000cd234fcc729a4206233e46875a557027cb52c96322386b56d6e50d95dd9d23b6f8936ddc6f8475b1076a855c1ae23510000000000000000000000000000000010a774120f607bf9ad2d7bc498536cc9d35cefe384f88a2439a75f1a4f6a9e4b4253daff0d2c91b5915ee0e9a99b4582000000000000000000000000000000001496e7181495114abc0314f580c16038a04a8dab43b5564d518dba5f5e48112ce9daca4b16b6ad51c3af54ec9ce915d20000000000000000000000000000000002c61691a96a2120663c726d7fba3ed37524b58c92a024c15fccc659d1d2cdce077ba233a0d4419a6f237ee4e09abf52", "Name": "matter_fp2_to_g2_32", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b693fe53cbcd6f8d8c98900be1f9c85966cc644f0a900c70826c6573ee801ce7863a0b170ce0ef168fb1f0ea484b276000000000000000000000000000000000c6bd688fb883f3097f8b6fd6fd0bc5acef9341f21d62a0706fb3625a70459c45a5200ee36a3802d4bb4912030bfcfc7", "Expected": "00000000000000000000000000000000011cd454f16209b0b7040c744291f2df465ebc786946ce3cde77fe4d4bcc4b60a51573c45b8bb2d209da69107613764b0000000000000000000000000000000018a026f29fc2f81e82015ef8610b4396f2e3514ab1a213356953804d585c5cd6a3c5cffbf70d63d9dfca50129021f0e60000000000000000000000000000000015bdcc8c139e636b05ba7376c1ced4a183eb465df53b1996f4ddc8cbf42cdff4ae2bbc2d24831a8ec8b1134cff4444ee0000000000000000000000000000000017671fc3995babcd2c0a1d2a71c417fea84e29df67fa1096fe6d3ec77c45b64fb8da6ed08a57726ab314fb860899961d", "Name": "matter_fp2_to_g2_33", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ba7f82549ebfdc7f4959dc67cebde4720d76d5d4742af730d45d614133f0a7b0ae7b61ba5b914a997d9dde83b77b031000000000000000000000000000000000b4acd8c203ebd8e3ce12b10cc791b9a4183440309f24bbd60cb2991712c792ecac64d3f878cbe407fa8ca0d09548acb", "Expected": "00000000000000000000000000000000156d8823c37c81d8f03c0b2e61a2342aab6e6c9db36cadc9eb741e085de711e9fda08ca78f21753c4fdd8cec059b6c2800000000000000000000000000000000064d4fc2584c78f1e92f808d4457070b0470eb8de9d558885bba8b03efd8d8e195e4923d8e3382481a0ecee905371ae10000000000000000000000000000000008f1dc4d2ba12e7e3e1b0ef3855df4dbf29468bc99d5cb29fa3058a535af2ba038396bccaa238bba6d538498565c2809000000000000000000000000000000000fc9839b6ee876f7846b5086d487360b8faf133b6f5bd2dbc92a7fe2261b91b15aef8d90c227cd5f8ec05e32d807e022", "Name": "matter_fp2_to_g2_34", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000145f6f774d943a1bb753d5d4876b1a88a4021cb6a6607c0efb07eef2f90ba2a90a6e9dc94586de35f6047332553ce7b5000000000000000000000000000000000b892f1c8d001c8aeddf845c3845c51f2e06c3c77e543e9721d797951b6211a869da97325b569e0de35cf3beda853ac2", "Expected": "000000000000000000000000000000000d40f1c25dd57e36ed305276d4505cb250d2d9da0d5b954fe5e396b2c17a5399613243216586cedb19340e80f898873800000000000000000000000000000000063367c4a622fc925319fc6d119d8592f40f126ae05eed86ee5e4f6707b1d234c747e698c40f292dcb82ac5fe74ea80c00000000000000000000000000000000199ddbb5d4b6cd0fb9225a72c53f4596cf2597de63da56f4a9a18be8321a982de17367b0f3d794fa799657dd8ca10c5f000000000000000000000000000000000f1ed84e4fd958547d40cd2dbf16e2da4cb6d0d02763441067221890ae27ea1f689c26c900b695464ededf083667146d", "Name": "matter_fp2_to_g2_35", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001878e791993186ab76f785b2c6b0fe08588b048007c66fc00c695b55bd17b37bdba71f34ddf75ac441a0c2687711b2990000000000000000000000000000000016598f630f72a0e1f39678e1d0ec6530c4795d7565c5d026fea2389ec0ceb51b434b532466fbb1c92c1c958041283baf", "Expected": "000000000000000000000000000000000ee446310185ce76e31c13e4ca6c43166d971d9b9c539c7d0e8dd8ebbbdd9249922cb674bf6ad6840c203a5e208911fc00000000000000000000000000000000037344752896cff03bc39a9d09757a83c15fbd90f8bc1d8d58dca9b23bc00fa2b0f3f0bd7c9ed857d285825d40afde450000000000000000000000000000000003ef77f0220d1caa7538ecaef1ae2924ac1a180f11004034fc118aeac464fe1ce684b5fc90dae3370e3f79619889f3d7000000000000000000000000000000000fdfa434e7bedec071a1a333088d06299f55735f085a1e907a1c71c312bbb8d27ffa7de7ac69d421ebd675c4afd37594", "Name": "matter_fp2_to_g2_36", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000134725b4d43cb87d2e4d3c43ca98b8df257acfa612ccd61dc0aa1ca749f20bd42c38d933d39f8c3c1a14dd8fec43329200000000000000000000000000000000070ad61a7f5ff9f0b4e7483f5d56b0f315b5f6545b194565ebcf8f0b8d78519ec113af6d70550888be4d661a8403a036", "Expected": "0000000000000000000000000000000000ac465de3832452edcead434729be73be90785158617b5ec3ad53b12653e43721eda7de6742dc51d4d4bb58a291999f00000000000000000000000000000000147c39a5c162afa1f8eef400cfa1bdbe5436bc59d93973f50384022962f828ac934a4f88ab7c3d505b0bc3bb002f5efe00000000000000000000000000000000141bcdad53845a7eb2ec08189a55445059dad24ae5d39fedce869791aa28459f05a6cdf9575676cc6f3dd7d6faf077240000000000000000000000000000000010e9f539a9ced860661472f53147d0347927f065ec09bc32e00c5bc157b07f8b41b05aa4e0eedd1f73c7a287b2d0e5ab", "Name": "matter_fp2_to_g2_37", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000179bc843fecfe713f6e3ccdc8ca0f48759459b675c8b96f5403e1f6da92c2d60449638f564ce179373bce473669965d700000000000000000000000000000000082bd89b49aa62c94ecd4244b3077421569c71efccc62aed3d4bd492bdfe57c0d2cced568df5992a196a7b71bcbe5e3e", "Expected": "0000000000000000000000000000000016479eca30f48bfdaba4c8afca63ddbf59fe3367b2d3c17d15a5869dd2956fc67ebde964530926598cdcb62cfc993d32000000000000000000000000000000000650b4fd24ffbb953ccdb1b112799149d29e2377ee233b9ac97f4db432da63c98b8aad751f6060d04fe1f9262b75fca50000000000000000000000000000000004568dc0b9b430596f2fa59291ea6f923d552683ab9ab93000788145cd7c468c5576efd981c9ecee2ee0c16eca1ecdbe00000000000000000000000000000000154af1490463930d6b8261aa1d066eeda6d65b742cb53c65348e5cd766d86982a1489ad191d1b126233f193d24823b9c", "Name": "matter_fp2_to_g2_38", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000fb118c86e974734fc434c3bcb783e4a7f9251d9fcfb9f4419529354c8a7a3d9f2215de2d1b9f0927b185c5b4db838b60000000000000000000000000000000004da0ce78f3068bebd0a59bc2e41e7ade737375f07d6c9ce962be022856c569a33e8bd6ae60c4bb1b53b3ffc2dcc2aee", "Expected": "0000000000000000000000000000000000df692ca763a74877352af3609c8cdbc184eb71bd35fd86334cb88543637b40b3adbb5802dcd7b88f4d722b566aba7700000000000000000000000000000000181495e709d1617f2d912f43487ad3920ac5f8e47395ec4b58bcf0b2d986c674a0c7838830a039bfb5bb59cd2fee2f5c000000000000000000000000000000000d20b482dd8aad583bd5d08ba9c61b3e954f022d48f9f4f62ddc9f5015ac71dab7d206b1d8b885d5e605519bd33d93a20000000000000000000000000000000010d3deccb9364ee386eb35c7117bab373a76d024627b8a031f96465d5f75b029fa992e29ad4a170c4473cd1df585429b", "Name": "matter_fp2_to_g2_39", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001f43b86ec24ad40552dc4874a632b4ff4663eeefe1a8c613a19a798a0ebe321a3d543e2df28277944a941b4586ac770000000000000000000000000000000000baaca6bc34feac790807b5eb5fd173c86c12803b76b50be59b2707df765bd10eb467effe34f8dc3e1e79df8a54fde38", "Expected": "000000000000000000000000000000000a007c914ed40c7f2719fc70def0d4752cbaa775cedae9365c5afb61a5e1a2854f9e1ce19af9fc85bfbfd2c33f5bf095000000000000000000000000000000000d85b0d173c25c2915fee429d2468a9eae01ba43c0f1a661f2ef83c1acd726865c00c40ccbc3aae306f93074e5e7858e000000000000000000000000000000000b3df302ec532c8100c121c9a3455392c713ec60de1f9572b040b0966f8ffb888e8cd768dcf6d63d4835a52d13a730c0000000000000000000000000000000001123c43dda8717d03fbc02fa53c4b1c9a931db6b274162cfb02ef5eec602bd8161dedc37c7f6217c8e82236f06e49e2e", "Name": "matter_fp2_to_g2_40", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005e4751707f3ea7bc7a74d80eff27a0d65cea0c3d2e793425e79cdb0c41e6ad0cfcdbb4de604637c41dbaf30a1e816e60000000000000000000000000000000008f69021794d93826f8207b96d49214b46dfb1778603634a9f5194e92481465702a8be1bc49a7bb57527fe6f963ae04d", "Expected": "0000000000000000000000000000000016d8d9b1b59a22fd830f88b9850576488f75672a87ccb766e52da77f187a8e66071130c7e71f86675f8379b2a8802c4b000000000000000000000000000000000aa4ca84aa23f01ec536ffa25c4b7a6c822f588bc75a4a72ed9237c0588ab892c8474a0f23afc7ff0dbc3b08f8e35b60000000000000000000000000000000001425e759e2537d9e5f0f356ff1d38128eff3a771fa661a839f7a8d0f548347438574ef7d592cd4273ef9b7269c9c5d7f0000000000000000000000000000000012cf1c67d1ce244ae22eec0bf4a400a0f356b9dd075d87a6e61941933872d7c0e42c1d238b2c1704d2cdb2df75169f39", "Name": "matter_fp2_to_g2_41", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000116988a869cf552b2440e16569d8b6e30c6b15430855c4d6bbf80683c5497291bac7999c1f8f08f494fcb4a989451c3b000000000000000000000000000000000e26058d72875fd3d852aa4139f71d35e1edb58242a4939da7986645117d027d20baf85770fc909d537524244da59ce7", "Expected": "0000000000000000000000000000000017f6e2743cb30fb93816d0dc802c24509315363c3652b0244e1395cb9200efb4d7b9fa7642e8d165d28a00740f1a83be000000000000000000000000000000001483644fffd3989ac98cea71843e87b8e446a3d497630419afe99b3f1729a831fa6a49bf763b0c410cfc5390ac4ac1db0000000000000000000000000000000018ad20ae5012266d771b2c86f891f498c2e90a7df19561be240319edc1fbfb316948fb3f8a6b0e3720676b076eb372e10000000000000000000000000000000012f404211899d8fc1221ab5b82db9042ad37e63348871e5ac6cdbddacda0a564888f89d22712069b6096b58c5935edd2", "Name": "matter_fp2_to_g2_42", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000078c6cf89561533810b583a88149586b29da5228ced10a75257b2587904217f63499d8b9ad2d536617247e12f8d1657d0000000000000000000000000000000005b016ede9d892fbd7aea4e8ed0f1eab70713557311481735a91308fabf76fe71e44a06dc23ea66ac5d831e982f401b1", "Expected": "000000000000000000000000000000000d4d78f992f12aefb0e3a6b18fbe2411108327a9befe4a822618fecca4def3169972b4f1fb254cc4656a676529d554ad00000000000000000000000000000000145ef33250240a5c9434d4b2cf2404d9e7cc51b55e482ebc6a8aed85caa21ed00623b3cb2d76ce2d96b2f346d395dfc40000000000000000000000000000000011af2ee2514c58078da335c0273cd18b98d1ac6f0e67890677403f71b0e06863fc72611c0cfba39ac894ae500edbdbae00000000000000000000000000000000186863e7c24cbeb45f7a66b5dddc9b57c7e22c5139aa6bdb82e77cd8182bb8d2fb7bddd7d3516b5422f92e08d02606b5", "Name": "matter_fp2_to_g2_43", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000007160f36f0e5c4ccbcc7900c6504cd86fd6fd700bfa79af69841e4a6127eaad467ccc93c66baf7d767c3fdb1f31c527a00000000000000000000000000000000043fe62b0b9be76a375f3be0d6ec891d5bf5f2982cb2390125ff8d5db57b6b18c5616c526102e4f615963d601d13f122", "Expected": "0000000000000000000000000000000002af4a301e90c71eb375110e7fe23f8f05e2ede86b1a9b240e8d1d4d70e96f1dc3640fca7ebbcde9918deb91f3592de600000000000000000000000000000000058b5f36cfb6b0adb14b397dee4c3769c7446426eb5719aef4965cde2dcb70e6f2fa60101a5f03517c0040093453d092000000000000000000000000000000000f77b560469cd42c5cf3458ae13020c6678af3cddf9bc559372d12bc5d6b930795e1eb09f27cfdb8215f39fb2a11b30c0000000000000000000000000000000003308985946c742af7bd7d29abc2517ff1d225607b5f11fc66695cefabd8f25e294ebdb7339949d6bc4d98db19533966", "Name": "matter_fp2_to_g2_44", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b9590b1d0d292d9967d759060a551f4e8e4c1c0066a9a3c0be515085847fa26b77462e3bae9e2621f28e01f897df0be0000000000000000000000000000000006ee7c459bb4da96e87eb1d39bd7368de5f60104f85b7b4bcdd7761ce08d48babe1bf5e765282779803bfa972d0e668f", "Expected": "00000000000000000000000000000000093c936d57135b25900bd5dd55cd579aa8b85b9c1b5e8dac6196c4450b624734d9bfc3fda499cedf2e877d79f2da650b000000000000000000000000000000001832306d3ac1c1c61bdaa73c9b6e9c2ccb484c3baa1de6a217a2884c72b72618e864f75fcc2dfaca358181ecbd3347980000000000000000000000000000000002b2e5ff1ee02657fa88c7d6f23cd4c0465152a9daad8479b4b68c97930acb22e4e2eb0011ec4062b8ec46991a7cc630000000000000000000000000000000000712543547e9d24cc78d1c2e3fbe0b51222185f4c6e513256d1ee066ba50beee20321bfd60462e2587c375a0e9395715", "Name": "matter_fp2_to_g2_45", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000044612b42a2baa9d3e1d187b2a4e048773b4851bbd7d4025e0f7f61abee703b5a563397da4515c7379397dcde698228a00000000000000000000000000000000014cbff1000bc0f9b394b18e81124dc81f80e291e841dae6e96e0c86a6f618b9f6aa6103e0e7582e5136319a4dac92fb", "Expected": "000000000000000000000000000000000f52e2f8dff9a93b2985d5c2b8b980e4869af53ce55aa48bc1c9295e557e3b5ff78896e5e6342c2d535d18b11950bf390000000000000000000000000000000013d36cf2805d350c5b748e639d20e592deb4c5bcde99a94fb539dc56d48a862151b925314f21dce4c9130b32e44f54060000000000000000000000000000000017728f485d881b861f626c9de8b3df7d807b266de6cf8dfcba262f40a6248fb5e6506d11e88f460f0b5f1a1907ae5f3e000000000000000000000000000000000c0ab998f63f861c82106dc3ed5ea11a16e98139e8686f8442047a1cf9ac48c3d34b5129263767830144e9a13d4a1f44", "Name": "matter_fp2_to_g2_46", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000013da827dd718d3736cfcec53f034d34bce253bc91f7cfd6cd2666819bdebbfc43a9363f82bf4b580a7739b5dda9c94360000000000000000000000000000000010e94039f37d218ad393e88a226dd324a37e8d5352dedf6d84fa2ed2cab2f874ccc5ce94599950f91b8dd6d6c8b84aba", "Expected": "0000000000000000000000000000000003463d887c4d0aaa21acaa308d77f2c7e13d10157efa9ec3fb1586a8db5ff1a9e807c91c86afc4df34c9fcf06e8561d700000000000000000000000000000000128a81efb9f30ed811ea3163c71b6a46ba2cbdbd3a9f93cb8d0f518747cc860431c6e93bdcdf36d00f83838965da4b50000000000000000000000000000000001777802b7c41111b38da3fd8092c280b4925827b2c1592f779a4ddca71f8268858855c413fd5c0057a652155261d75ba000000000000000000000000000000000c88b522d6dc2000cfbb7052e141ddfe15c6cd7fddc970edc4afc36fc59e7f8e31415706a8121e8e84348be0b50d0d88", "Name": "matter_fp2_to_g2_47", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000010416da7cfbed2768c77b80957053030d49d535b21a8a3297ab257dee0463c91b87a9e571b86bd874522149d9af0c2900000000000000000000000000000000197ef97f6d02a51b80e6f5629e88a3c60399bcc4a358ab103dac3a55a5877482558abed922585a1ce3228ffb507679b4", "Expected": "0000000000000000000000000000000014be96cfc0dbe09155ac8d8233b71ed584153e279b2b2be88471eb653aa4913fd2c33947547c61f7fd8bedbb552a8b1b00000000000000000000000000000000146b9a0011260e2646920894cf405bdebb101db12da7849b30868655fb5f972113cdf2fc322cc246d3dbd9f20b98fe2f00000000000000000000000000000000104bc20e104da5173dcff3e195f80960819a0d64e922bb484c2739c4b7c22535f7faeb1c85188aa853277740b389eac90000000000000000000000000000000019f5aec599f9ec286aefe48eedca3f929ac6c758c231182b92dc965d6ac1f3db53d93f57d733ca8425a5dde070b0dfa8", "Name": "matter_fp2_to_g2_48", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000025f1ac90f5b0748d57d8f7a928be875c5712801f70af0d057546228c1bf83d3a207884c0d66d0b5dbcaa736bfe0aa10000000000000000000000000000000017f66b472b36717ee0902d685c808bb5f190bbcb2c51d067f1cbec64669f10199a5868d7181dcec0498fcc71f5acaf79", "Expected": "0000000000000000000000000000000004ca0149527817b4df0f08acabd4e8c6329c0d1bd9f2e8211cbea25d69b84009ef158c770f948fd67e4609ccadc938680000000000000000000000000000000004101b351e2a9d34042291f38a289d8575872104bcf76f60bf888c60cca5101c34c247da30f7a8db4f0cf2f32abd302c00000000000000000000000000000000167e668de3207ddc60b8a5d5d246bf2f63ceae3bcbc4309e73eebf4d4234c2785bb13e4d5d8fff9c5f205e4fb942a2f6000000000000000000000000000000000491b965ed005065abdac53e3065781f2fd23f6159debc64f01c9f62073c651da33c05ed84617efcb5ffe08ce05e3b2c", "Name": "matter_fp2_to_g2_49", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003f2dd27e3f0ab503a8752c0802ee14c655271e8cfbc734905b4331fb4e70cdfe291ff71053fbaf91680b1dd108f458f000000000000000000000000000000000c62014b7694a3e81370761e0adcc32430547a1bbe33746637e7762dc24f8d04b4bb955f17ca901659482c622d777642", "Expected": "000000000000000000000000000000001541320fb6f8a8c3c67278a7ad05ae7927d3555ad562bc8addb54c6693c51fb1c7355d2e74ff10f6bc3eb182d8f5b88b00000000000000000000000000000000172b65b110935b116ee683c8680ef0a660afdee43b9b8fce08ef3a70b352f8710c06b820348c338fb903a165cc5376da000000000000000000000000000000000df529b0e274e2e8993dd89ffef487aff23d31f502a19dd7d383de08fc77f1308a59ac5bf7cc899e81d377b2422187850000000000000000000000000000000010b40c9063d174b358637ab710d15c80d9230a1b3a056cfac4d583ad8c5b79c3d9bf22a1b0a4e0f629cd09ff7586f886", "Name": "matter_fp2_to_g2_50", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000014d1491a45b4b0914a6cb2e4dc7de9d0962f5c175cd571057cae1e17d2c943954d119690ea14f5815f858d277a9ad828000000000000000000000000000000001650771e0f7b33d235f229b7d49a7a5a0f00f78e5f4abaa70f39ec452370198a8532b5873e41f17c449f9c565e6adea5", "Expected": "000000000000000000000000000000000978ff68d94d33703488298658cf2c1b6034d3d8d21c175d71a0545bc2f99eaaf131f061f3e4f55622668e686e691f53000000000000000000000000000000001124804b252f8187178435761897d00c43cf67b588ca69f97c20b0ffad3ed94acc2c0f85f900713dd6ee9f38e5ca94490000000000000000000000000000000010ca2a8ce71b9a096c132c4a060a17365475b6556d4fc6284266ae787e217b3ceaa3a32bdf751375eaf6ab49800132fd000000000000000000000000000000000a43b435b116d9480497f6b2e1bb377550cb1a7ad59e4214bffacd517afc6b7bf91112fe57b17a02a86876ea07361bca", "Name": "matter_fp2_to_g2_51", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000aeb244909654b3e1df7cbeccf297223be57c2f514474edf0740dff48dcd5898b6e49eb65c787aa56ef79778249f4e07000000000000000000000000000000001007c89a66dab07f54313db8682f9e829baea229b030b4514d9c93686747207939c50a198e83ac2cf50315e02642a24f", "Expected": "000000000000000000000000000000000c3d87b1b78fab65cfc853304c682b39b6ec2b4ed005e9108f69daee5aecbd586c9818c37cdee865ba53eab9302320ce00000000000000000000000000000000062a7203cd2fd04a957cac8b6b6bb51e635ed7165c547ace10f93a32b7f37747a2e63d5767d966684409a6c748d4ee6c000000000000000000000000000000000526b44af8157dd68725aa8743684e020c1e385af7413c9dcebb320568663d18b6f29edea26f2628358852b794ffcc8e00000000000000000000000000000000098126f486ff55c21f64421e85b09a1b54f42d3499dc0e198db6f3bf7dd8476cad97c02b5b366e5ea20d8f83cc223f7c", "Name": "matter_fp2_to_g2_52", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000398d86b5206bae4ceef0bcc6335b1f6bf5d17863ef3a5e8463aaa69d9f73f8227263964659d4b770d6d9813f9399b9d00000000000000000000000000000000096bd18be1176e16a0d80e60f7d7ec9d3b6162f683440e3cde70082a73605da3783c8a058bf76d7e25056f5cd95c31ed", "Expected": "000000000000000000000000000000000f3e76e7d1cadfaad08d16457b02d89c40c157225eec7916d306faca8dbda008f41792888c647dff1acb4d4ba3b43c4900000000000000000000000000000000132bf730456e2afe745a58cdee689e37223292bf682d5b7dafa7df99e40d385559d0b3161bdda0bf5173c43ee46412dd00000000000000000000000000000000141b36ff6890e35db0054358bc0731b3aa0efac1a247a51daeff3515746456216975f44769174a4be41c109d35e4be33000000000000000000000000000000000ca401ee1addff8fe87b600e057ae34ba297886f92c5be8a8c00b360ada71831e31bc4ea1c309c7da31cb28d1011ecad", "Name": "matter_fp2_to_g2_53", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004ca5cb60c32edfa385baa911ccb7fd1f383824c22b945944b0f3f7011db8c123efd8fa70e4fe699d40c6716021f0151000000000000000000000000000000001339adb0dd8d83574c2008f0a7ed001b0808d2fb639b5e57e1d293884247d5c66c948ecc60caeea7bf440a3a44ed296d", "Expected": "0000000000000000000000000000000009d0af77517b654ad97de3ee1dbf69ec1eee901facd0f8c39b4af393d0e63957292a7529b461f7fa58909acad32ba3a2000000000000000000000000000000000fda17cd878ec0f8c294daec1bd1d56c63e875b002a81c9c41146dbb564bab6e4eae2717c9fd718af1ba816a1526e8fa0000000000000000000000000000000017563b7ff22b50b6d9e24b1e0d89ca5c72e68d4d3cc24cce36856191111d087c3dfb392070462dc7850ef5a1422931c600000000000000000000000000000000020001fcff638504055ba35230b360e6d3cb5777b959c194d6f9b038b58d3ead0b82b28bb215378abd85d357b85ea260", "Name": "matter_fp2_to_g2_54", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000089211892a61202b1ad3a85aab9f08f8d028f3e3deb16c1de4d62c1a403fa63c6dbbdf8cec37f0a9d6f346b1c7ee179d0000000000000000000000000000000012a9fc2070b326f4d7e64804b3a2e977f4bb36b6a4afcf27252af757d8535e8172a99dc909fad5a3ff8df23d6d6c5948", "Expected": "0000000000000000000000000000000000d51c77c2443f00d965c0d7ec9b5a8a8003c2a77b0ffce3e47bcb55420e8690a9c2ba9235b62a4b351d79d216a3aad40000000000000000000000000000000013cd46e3ee6cbb3bfb771ee30b5f5faf0a64a9efa1f8fc57024c83ad07a9b25e513f211ea604cfdf319dc42bf4c067d300000000000000000000000000000000009fbe1fffc67220067c948e0c80de23795e045fbe8031c9010eaa69356ffd8e5741cfe12731ec13aa236630f1b1dab4000000000000000000000000000000000e5ecdf808d10d47f041e4b078e79b32520ce9623b50059a3bd8b59daebf9103c31425659ecbaebfb2384d1c2f1b400d", "Name": "matter_fp2_to_g2_55", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b37365748fdb21fcb46f94edf86c586f17d0e042c4683e68c6cb83e7c0ed2c30ed260c15af2c9dce77bb705debfa7590000000000000000000000000000000010d7c02c6c1ba3cf6ac09a05dfe043905e1a7eb32b67f2e8a5dfe82eaca66ef46cce43aaadeff58ca85345dd0d3bf3cb", "Expected": "000000000000000000000000000000000f3e4d2559261829c0f4816f8b571170de1f74d75d74997cba56fdad42932db73504691f9e001f5b4604705a8c1a38e40000000000000000000000000000000018c72136bc7d3050ee693270668e706ebf70f990e447ecc6153a10625cccc9deaf5ae82d2a656b1376bf33b1c1fdc2c9000000000000000000000000000000001754f2725bfa76e92a74ad5b520ec2aa82a1f86e8623a054ebba489adfc9e71d1f14d4692ff9fdd8acc3d768b67e1b7000000000000000000000000000000000096f1373434a8822569cba0679dbd2abf619bd9a8c73e54e078688d4e2615d45431ac8cf3da5e15a83fe77d14b339e49", "Name": "matter_fp2_to_g2_56", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000aeee59421c8ee65f8070b9d036e6bacb39dd2537d02960a3a57da4f0985cc7b27784d60fc1613f5a83c34d2250395c1000000000000000000000000000000001715ddcbaed0a05b38b1c820724405a713cc0215a4c497892f00746c0f9af28b440a3686178d9bfcd41944a224311306", "Expected": "0000000000000000000000000000000018d515b8c99f541c7dd448c3564c1909b84517b662d6a2d1176d3bf5e70abc0a2995c73ae3f1614bfed2f64229e173e80000000000000000000000000000000012126ab671420933cc4fa9206311200cc5241ca3eec54f5d97a426a72642bdde32a65c79735446779cd1744d112d544100000000000000000000000000000000190d836312ffb0d6bf493f4c942263922659abec46ac4de639efc311753148b445509f808c2fd813729b1bd96e0e663f0000000000000000000000000000000006494f9a451460ac658ec17710bef79d59b6e0fca049804c0954c5fc472bbef520f75d34408ccc62cf2da3deeb79acc2", "Name": "matter_fp2_to_g2_57", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ca4b3e1a8351057ba4a2ffaf0cdf1c3c0717ccfe26433f6c40e2cc29e32ed884f63d25979580fb555a5a86c9147bcb00000000000000000000000000000000010c1db593af38aa14ca9dd588f54b219ff1fc9edd25b3d16c595662ffa7939879244326b14d978e0dfdd25e37776964c", "Expected": "00000000000000000000000000000000173fa567aa952bfaa9a60b8232a185475cbb36761ebef49ea5fce900a06043d0e2c1b6024e40eadc9f4bf04b077201450000000000000000000000000000000010fdc32ff84f79fe39351cee1ed6b67dbcf2956020e2518d5bb5b367b61f86f1bce36f75516d9551d74cc3a567e6c2be0000000000000000000000000000000007abdff8a8967eccc4de6b4ce142173841c0e8399f5a67dcf0f7b5e5b4133391b44bf4d41d3ae3426839b19aa4c5d40c000000000000000000000000000000000c99f160062566418c09f10eb80f005f2c8c12825435f354f1d65bec0322e9b8ee968c009a84ba792a7ee7334b32bb3d", "Name": "matter_fp2_to_g2_58", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017cd94e7e672f0dba9a3c1db742d87cb18b9401e8311c4badc24f811a8f40c27942da6485807701c1a12da58076c756b0000000000000000000000000000000012f6de4ac9883e78f9d658cede4c70b44bac6b4c9734cbf24298ddf0df0cf54164aca245d8e313be4aca66ba3cab5d70", "Expected": "0000000000000000000000000000000019dc92f1da66d0855ebc8e7a2ddec623a2f843a97c7385364a631671be7ee3387a0f98940b5a51c8d9e23eb27e3133b00000000000000000000000000000000008493903c5c68b2847869b8c3b0fa9b8ba15bf1f11a40a29e6e82942e2910901044254cc8e8c3c3bf56e1f1b6dab7e86000000000000000000000000000000000bd3c1e302a191094059a6493e59a11ab05a49faf333f36f7680ec9b1043e59dfd7f0fabe9f334b97cd638dbb8bb664b00000000000000000000000000000000141c9b07ff33b6ab55b320dda6be54320082f0057c446236cf3d3a51e674c26a5241f2c702d9989adbae9045942eeab6", "Name": "matter_fp2_to_g2_59", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001b2843d9852feae3145b242cd0999877c07785bc72cc2626f388dca32edfb112bb90f9aefd6953eb15a0babe748573d000000000000000000000000000000000a69bfe809a67ee853cb96b5a7a72798748cda56936e5664d509001544539730f57a7541ecd2396c9225818b9dbfa3c6", "Expected": "000000000000000000000000000000000d0922466c358cfd756727e134b5e64d211244587e4eea036f0959e78570dce3ee264c703cc356cde20637c7560369340000000000000000000000000000000011a66d618f79fb662ac2b2d3b50750a5567e36d7092dfcc72d8f340c04df75ecc0ce4a01b410ea775dc548b8dc66c3d8000000000000000000000000000000000cc49cf4be5e2df6b43054092afa2d6acd66f5a43ef0667f6a2d660beb7fec70558ce02d7acbcd090df91fe833326718000000000000000000000000000000001270b0519db083f903a3dbe0b1b1bd5ce0b0059ea2c2c50335dd80b4bf154fc23a3de1ea753b0e279145254d8e5bd045", "Name": "matter_fp2_to_g2_60", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000002479a989dbf27141bd9f467447218dfa6ef60781a7231f089d5f1f1d8dca2ce9606a75c09f63f37f9cc1ee61dceb32500000000000000000000000000000000037c2f1b96170f6847138232bac663e4940bca602717c877f58ff7f5259778246085d499ec6bbeaade18f738df333cc7", "Expected": "0000000000000000000000000000000007826398b4ec35ab58ba9fda5c15ada2a41d3854677172ef6a4a54087b64d0f73fc875ad62236eb7fdcbd94f14c8895b0000000000000000000000000000000016b14fa92de5f6e43988829ea2f851746efd6680b0ea1283264f803c8ffbe85a343bdd42225caefd1b94b8b311d2f4950000000000000000000000000000000018797093ff82bc10e6db60b1da50b9a60da01d67673e9bee8c7af2bfa2d57f409f7b06f53944938e5c73b049c2d3c6500000000000000000000000000000000000c66dcc3d30f35c21b8a9369c8f6de28af404e8b30d3c9a7f09c461b0272ba6d5a29e716012536dbeac1d9672af8427", "Name": "matter_fp2_to_g2_61", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e6fcc48312831b910e52aebbf19869b3b32f05db8310b68905bb244ab784df5732db2e72183de5d231d803d92aacff9000000000000000000000000000000000f61f9e52fe3afc2a6bf12e420cebf83bc55a449d6a167779e5b6ba3281c51d790a045643aa75f2516eaf6ae2a816ac4", "Expected": "00000000000000000000000000000000191aacce60a1a83f2c453fe196bbe5839a3a1178b147580435f7de8a2b0b4f65b3e280ac7a67570aba0fdbce6c11ad9700000000000000000000000000000000075ddd6b256f53a6ae6758a5158508540aa99b78ca069378f0ae3f5621ec24b9acff1f9b61d378334a63682a33fb0561000000000000000000000000000000000b06e11c9f858446fcc90c69d05cc26c33bafed0feda19adbd838c9c24bbf567b673110a1b248d0ee97fc682e561298e0000000000000000000000000000000018c75dc203493e12e1523af50f85ed648130ce5d3e9757f713850c867cc95c7acbb66c9733dc4f53d6a0e64bfaad5832", "Name": "matter_fp2_to_g2_62", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018efc6d366d79a09b7d56c81c17c2eec2ef7395fdb5991f41273329cdcf4537d342bddd83c3994a40d5c18f6afa054c600000000000000000000000000000000127021ce28627a9d6a492720f728acef3b38c12b951f70a932c7fc0ce3f5b6c80783351cec55d7d1bc4ab964bb4913b2", "Expected": "0000000000000000000000000000000012931f51430bea6e96f8ec456ce6b3c9e058b0bd3bbfbfe8b6e84fd6110c3bbbe0001018064e8981797f9c93713a0e4400000000000000000000000000000000196b6093dd2276098853ef2bfac84f0cad06b67a12484e98915dcc756310b818d8136954de1b602eb825ab29a143cf4b0000000000000000000000000000000008284beaa877b25374571dccb218c401cd905b351dd96700853f01920e409d11c4e440e90dc175cdf0fa807cb9d1e93a00000000000000000000000000000000063c6c238485c291fbb60bd2824154a9e23dea374292966d271ae94875391b7ceeee813e3fb9504223bb86f0ea3b6cb4", "Name": "matter_fp2_to_g2_63", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000a0277228ab4e880c12f957a6fcdfe49e2155083f3f93d3f00c68622415cd1f5bae183b7df9e08328a8139392772cdc6000000000000000000000000000000000de0ab426e56029790a5ff72f34da97e11c028dc5d31e448c49ede004102804d2bcc36d509640247a4c8bfdf5104a781", "Expected": "0000000000000000000000000000000000f7bd0705cc4ea96ca38314cb85963044164b83a506ffeaea6e5eb8f7c4967cab1f1658f33b5435191427aaf9605bbb0000000000000000000000000000000007a93e2a5c118aff6ceaf2370ddad52a82854946ae595d384ee0b2b4935a574ba758736d84b0ae792f998ec6a707dfbe00000000000000000000000000000000090936add00fe5c7556610b28ecb4466ffc37b95b5cab43e072a585920b3cbe70faad01ef75d1dcb4f7d00d900bd99600000000000000000000000000000000006ae82539c68b7af3143e23229fe320924472c2b3e15a2e27e94cba674d30f083dce94706da094435c53285a43f89e56", "Name": "matter_fp2_to_g2_64", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000170b243c5aa49a0134bf3d6494cc1e55a1c6ebefc6117eca3b343a48ef0a2b077c443ec5b9201b198df015a38e66b7910000000000000000000000000000000019a8ac8a3be1d45318801bb0a654963b312540d24aafec46bb7661cebeec27b0b345275fd53c041d02b1ebfa27fc3854", "Expected": "00000000000000000000000000000000024c1b869fc13191b71d7159a07e869f1b13c11c73231b82e9bd0a7b4c32d7b376fb73d54f7231dd4974713179f235140000000000000000000000000000000012b9f95af661e8452aa5026302a7c28695307f75e9e4e32365caf378ed394fcecc831a3c47b443172188f4d18338fa75000000000000000000000000000000000f52675fb4d112d1d39ff953a253b22dfa0b73d972e756ea7fb673bf87aa992883c5baf32be6f50f880b03dcb740f06c0000000000000000000000000000000008b57726e17c873e12834dc291cff6bd95307f50e7b1d0caebd8c1eeb6eff4acc0520b135bc8e35a257133b7dc640db2", "Name": "matter_fp2_to_g2_65", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000fbbd5a10eeb2f358f2b167f1985d4084c4b12accb1520d780ef1c52f6fa80e97aaf190e7a7b241ef96fe8289fc0a9600000000000000000000000000000000155687114e7aa786ba27aeada830fc705aed069c4e3a07e88d7f33923319f416ff3caf6533cbb36e5bbb1b93a191bfd0", "Expected": "00000000000000000000000000000000061938df3365bf910884ccbd74d3cea7c30416bddc1a9b65e7723c15d89aa657da36a45fe10ed50bfa0c2769bb98aa2b0000000000000000000000000000000007b3981054255715826cf8f247210521ac681305aad3928b69804117fc143c5101383eab7017127c8452a79003a857d60000000000000000000000000000000004c745113480fd87212ed3ff30ba43c8716b32e62c1f0091bde53bd4a8fa8fe6bbcf0904144f4791ed1bf12dffa1f17a000000000000000000000000000000001237ba297c7f69e5e240846a12d86c8276a9a6ceb4af977edadc7ebfba3ad3f4ecc0b875da0ea578c83fc3b91f9f31a5", "Name": "matter_fp2_to_g2_66", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000115edef357ccc3432226d9bad796a42b1a278d9c8adfdddc5a0f8a36d32ea1787183877f8b7dfab71424cdd10b63441a0000000000000000000000000000000014b369ce61abe60d942346e049644b95a0fda96316446b2fe7ee427641af52fdd2a654bf125ff6c8c7f3dec98f6cbfb9", "Expected": "000000000000000000000000000000000a0cc3e328b4cfd01afe53dbf971ad78fc74d951050d76210e4c84438109622f0531747e762e185e3d7ecb9faa7c3255000000000000000000000000000000000622ad6092caa727d069b8921f4124d5996f3019705a908ef95d23092c5bb148873a22c227aa25ebee361d4184cc38a10000000000000000000000000000000002938d2ff50cffaab8c056c2844c50013f5bcdbb4f91b3f823836edabb39ba17ed1b8b5862301efad04bd2f5d5bf599b00000000000000000000000000000000072e96136afebbf8c06a37cf9b20c85ef8cb3f7f99d5c71b05a187c193711e5b76f52863c7ef080a1b64b2120ab2ed84", "Name": "matter_fp2_to_g2_67", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d22b7b36ac66b10adb4570f8e7521ed76de2df2a7b94b2d0b9ee4514cdff6fa7c74854d16e7e70f054a91df93c7ebaf0000000000000000000000000000000016867c9cba66dd9f1d0332d31c4e46f8e393eeeeb19af7e6e01effb29ad999b3086b599ee4b371de557d4fafd5da3794", "Expected": "00000000000000000000000000000000142ceeefa9fceb903b25d4dc68f6755833d7529752db0f125f7f65f2b7aeea8c90e599ac409576e82f7b9d6f83c43aa0000000000000000000000000000000001664acd89b482aed04ef40bd4d1ff9f39c80d7738771e2b3ca731af01aa230d865869cb05d83992e94ad99549fd0b8550000000000000000000000000000000013d6ace9b492c014d9a7504b5abe442e3bba13b1ada454aa53177990ec44f616e091f1382d36db87b7e794c11570a9bf00000000000000000000000000000000081b7a8a2906435f8a9242f573225ea62c5429e903bebda9fe9973a18ed2682185d72aaa6584b9848d1cc45ac907dd27", "Name": "matter_fp2_to_g2_68", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000db9258e1257e659e60bf8569ea90c8247a53a1d1eb958481623447a38d0f1f1686c3e40c8f15bd06cf5be9c02485452000000000000000000000000000000000517c87f3df032ff08d960f524939e66f7fa69b4168b0f2507baf7d7231a70dc5690a02d317b26f219365ac3255bee78", "Expected": "000000000000000000000000000000001182e4230f0c360c07913349f89f8436c01841c9615348a0d7057336c7483342024b0369ae52f39d4582f9885f552b5d000000000000000000000000000000000d15433ed130163a85f8ba87468c906aba88ef8610fcc1a8d6b3308cda29907acca351fd7fb19799184f1ad91c751b5e00000000000000000000000000000000111089005c4c5370863b0ea6b629197a865f978f71becb741f50f9b4e49b13162ca63c29aa26287faa9c923f57f4ad4c000000000000000000000000000000000dce405ed2a79ad433123105ad01a26ee85d1ba4e5f3b4e0339fea787058c06e9a6b10f5ec8f6eeb85b211e18b6ea076", "Name": "matter_fp2_to_g2_69", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000b6573c743989fc8613d4ea09c2e500ce965b50cf0c8975ff703116464082efff4b42828c8337809f6938d7cdd3f66e000000000000000000000000000000000896d316629c80ce6e5f240535863b9e064728665c0815f39b21675c236f6995e7dfff1e4aec9ad05861e2122469ea56", "Expected": "000000000000000000000000000000001694cb615d2994a903a13645ad44a63395320f286503902b6009e7c795dc8f024260e0c45bedd864edc9fcb9d1ca6bc1000000000000000000000000000000000f20538af015bd6d213f90fb1a1ebde4d9e2ab2defaf80d791a1f70af2ca7ea1598d43e9eef1cc982f468cf15d223c9d00000000000000000000000000000000046c62bec4c6876a67f5fe68107d677db8fa4d59ac0cb7afe6e706864c6e94744bedac6b34a68e8ebf89c231307b86d3000000000000000000000000000000001839f3b8a6dd8fe8028247670fe5b491bb43ea8fda53116dca87f97da96573a5e701a703fb5fa7bca457ef88a827e061", "Name": "matter_fp2_to_g2_70", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000011fd2ccf6883b78fe19cfe7beded503cdbe1cd5dc9ee452aa6b329d2237c2529df6774334b132cfeaa616f20335f88680000000000000000000000000000000009eacceef036ec500e7676f54af703016fac93d69ed19c8943b64ffed2db498b19cd255a0a3437b568eade0f497c7b17", "Expected": "0000000000000000000000000000000009d8725eb8757828a94969ebf40545a62835686897d4504a66484a3078b2f15e39fe918d8dc01bc7560dcb005a7a0dbb000000000000000000000000000000000954a6cc9b2dedca1cf280f72fd0625184b8f83b78ee1ffcaf0f9178ce97900d759e4a74b914c3ddc32f84c3f4c3a8d60000000000000000000000000000000014121b83d2a06390ce7359e570e1593d5ff097cb0e44c38bc74171fbd8a8da0dfffcc2bcb95fb2d80a55933f696a86cb0000000000000000000000000000000016f71d24256de70618a02b0f016c6f31a21d2cc42855886ba30176584a028c2e12367be19b834bf41356cdab21223314", "Name": "matter_fp2_to_g2_71", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004a851380536054f6b69ef7581b57dfd753d1e6201069bd1218ae5766aada087b4b08f65d43b3ce0215640e8d34633310000000000000000000000000000000013579671b64f2d9a2c3ac2737cf95c2148acce3dcecb3db6d019730010c50d1c0504ba4ed42d93771ba296b0b07487d7", "Expected": "000000000000000000000000000000000cd47f0982904ccaf4f3cdaa37091a08e67a5f04af09033b864631300bb6c2aacbad105eca6ddf68a643976fb555d3d80000000000000000000000000000000012332ddb0e91f0ef9e085f21634c6d69576e60d3d24732a0c91a560906791f60f79d09ac0ebf448bd39f047b1dd428450000000000000000000000000000000000a756a869b3cbc5624f0e08019170beda35fd2642a79108b284a503942f8267b75868636302e5a12b4f1505331b15f9000000000000000000000000000000000f60724f6c8200edff41f3299ca003e9ea03b97b01a3e8c63763bdf67b9f7677331a7144915312458c40d041be97b3c8", "Name": "matter_fp2_to_g2_72", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000021dc1dedded9b0dd90afa9ab7fa8f9c33930fe4ae68185ea4cce9ed97ce4cc9ff93f96377b11f8d42b02e759a10b06200000000000000000000000000000000034c963fda3bb80043d6d7887661ad59b3c31c88c958b451a8e11684770c132205db6655ad7cbd604ecc3225b0c128b0", "Expected": "00000000000000000000000000000000095cd509e53f10b1ee18b2120e2d18f0905a202a992a9c62480beb6588275fc8b5b151e6abf17a12b6d9cd03a8b37a59000000000000000000000000000000001723bf1a3d79935eb4b39f7feaa1e05cd8f3e7a32e2c406625053d8d8fde33eefec231ee00adb00b0acac16a83dc77fb0000000000000000000000000000000004af528e886dad3f9fa7232605936bc22a6a22622828367791920ec9d31cdb2f290e37f5fc79efaeaf96c86b3f6e39220000000000000000000000000000000015bada14a84fdb09b77397cd2e27836f9f88854924af0cafc6f9125d32be848c8325a3eee1a26de8be8eb80b601f1ad5", "Name": "matter_fp2_to_g2_73", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003e8d1be04f8dbe5c7e1c7553cde8355ae16d26c819dea92fb543cbd9fe9e726359e1e4be0483a7720343f34c6a3fb9200000000000000000000000000000000062bc5fdae812802bdea09e4130c3d9bf80c7518138b116a4b6a302c155b97226a6ccc8a3ace18744e7adece08781f72", "Expected": "000000000000000000000000000000000d8f14042f36bb377655b63dbc37c50e0eb5775d4e4399972a6758cdfa9751cb4b733745ed1a47fe5f2cc434efc5af81000000000000000000000000000000001384016829d028f823e6d062898c042a461bca13ae4627c983d9b5c9e8b4ffff7eb25daa1c52b39e309b9c1e7e4f2e920000000000000000000000000000000004f7904d491a0c2018b1361a9cfec4fc829e607402859fd9b9ded60adcee51e9b522d302f9064130a4eed1327f49bb4f000000000000000000000000000000000ef4fe949fca569b31fc57ae7d0166ea53318c5712311076e052c2967144116f5490fdf56f26adf64aa01beb4f6cd214", "Name": "matter_fp2_to_g2_74", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000014b922157b19ed9debd9ae95cd9435f7980b8d4ea33fd29f99d5e7fb1a96f6d99ae13f7f86239c4bc286c3927d3522a000000000000000000000000000000000f6d4badf78d9115d93783a59ec9576fcfd87a2c29e1c506b6f7e313e71723811a36d64b37650fb6f7b460105a7e13f1", "Expected": "000000000000000000000000000000000f20b3a6505784681331208b573d3a241706692db71b5daf4e9c80adb1fa9bb87023d7ba7f9c65158653c735dee9dfdd000000000000000000000000000000000f7f357407ca6cc5c5fae4b84509d71b2f4de9af226cb4038b4820c0541d4999b7396608efd2f322a00a768129f9800400000000000000000000000000000000138dcc1b9d978adb5eee6356980cec5d18cfbfbf18cf6fd14f4119a563f473f5027af06342e84ea858223ed63d1a16af00000000000000000000000000000000012b63f0d2e8ea361d55aa617a99e066b5feef3af1930b83d2a48b527e0ef304ceadf7cba1415db80c54fdcbbcf66d14", "Name": "matter_fp2_to_g2_75", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000005a54ee5e3dc05c38ade7a42c71baf5a1467938f97c0cdf0742441cd339f22542b1ca6cd215d385b3fd6ba74ec996a4d00000000000000000000000000000000051c6f0ce621e8e27e5017628690fb68f0fea27d67726a0a77b0caf9f524936e123ff096168ff2079b9990c07fa80354", "Expected": "0000000000000000000000000000000015ff2aa94f802d8f9c60ddcb43aee598239cf3ab7f90f8289a487b673f6065f8d9bc92bd4cd28df4a7b0d3bb78fad243000000000000000000000000000000000884b5d4ca3c8abea737cfca05878528890b6cee9bbac0bf027df5d4e0add431829caddf4c1e001818581ce08686eeed0000000000000000000000000000000019b91a7738fde9760240b335457955e963030848e85717858f22dc33ba5a4721156cfdd7341aa86d10d268e2fc9a1d26000000000000000000000000000000000af85e60161795906f3cf705f5e8cb8c15083a90836eac78445c6bc27ffbfc8c2df3009b436989b46b271dd8d1dbc282", "Name": "matter_fp2_to_g2_76", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000094e958d9b7dac39fa4f0143a333b2ccee09046cd23e6a1c0712470a3c2e61d2f8b85aeca37350f71d7ec75aea2b3b6b00000000000000000000000000000000080743cdb5e359e8b8ad3485d53ea286669ad66d841945296edf80dde77b20a158e2c1529dfc33a1fbecf177d75a0c69", "Expected": "0000000000000000000000000000000001bd1fe6a6c373cfdc2bfd488b0c942492b77d55b2560824edef3a91c711ee336bc1366690be40949d04edd39ad48a7500000000000000000000000000000000161476946a5687113c74a34284f49b0658e323fae57aba88b039eae584d6ef28adca669fb083a2fe8f0ef664eb5b957d0000000000000000000000000000000007aead870ae09a04cf9c9fa49d0888f7010782cdc5a0ade4c1340ff15d99cb39b7412d66d4147b95601fcf5a39c39bca00000000000000000000000000000000095cce83dbfec12973e27627bfb2d93fa9a027a2c2af4259a0879d6bda055d74559fc93fb3b4f6b0088f702af29a7643", "Name": "matter_fp2_to_g2_77", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000dec04526dbf7666d2c29db5de1ef0b3da85380a171d871a57ae3df364d2754fceabf9d4d2a3da1ecd94e377abc78430000000000000000000000000000000000d19875fe988ffbd0cf1e9bfefc7019579962ffa3a585ee232615e4a5fce0a07bce0537b203ea00010a90ec05d5b8de7", "Expected": "00000000000000000000000000000000133cdf684c3ff1cdaf07ff787b57a66c215eef06acc2aec4d726a086480e7b2a5dead2cb357d99e298df32d4c6f5029b0000000000000000000000000000000019cd65b830fb17880f40e104ed63a7d49b0fbad8eead7502f18f1b9f85f3f6ba6c275b8a242effc61a7a5d770a4fdaa700000000000000000000000000000000039aeacd163862e476b17a22c76042d7896a04f158489ae71afdd35d27106a3ec276baf5c08e3eed4b3f0a79c3c458d200000000000000000000000000000000125a9bd770c1fea2155a581211bd71d55eb1966645cc892a05d32cf1e4e5b23278ea2fb1336bba7f2c887debe4a93b52", "Name": "matter_fp2_to_g2_78", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000016dd03f0df71b183e42cc29c665f18d57637b65f05df85aed9a0f7b8aa37f7913f6606c10f24a7a8c570f485905583a00000000000000000000000000000000161e62d8be678a114fd4a99a6caeb9481f5eaef145571152fe8a6ed77a34c06a1b6ff66044102d19a94abcaaeb254e73", "Expected": "0000000000000000000000000000000007843268081f61ad2b3f6653336a99086381bb4da4c23b7d59b9c7827f2d4c196d136508c8a1f3d2f939e8c9799b95e10000000000000000000000000000000000e2c57ad95f762115d8230320810a4ea9978e26ca17decd6af4c112789608967a92fafe3fb3e79539d75d1c0bae97740000000000000000000000000000000010951c9839db9dd6ca5ef95bd1b1b9cf60bfd97cf88129fca23b24f19c9d5c71486dffb762e92f23d2a9e9d462556f620000000000000000000000000000000013d35c17b3763fc5db46ac8c44aef996f3f876c49f5278b7c97e844f23ac49f2d50b3af080322d30ead873af7b4257e1", "Name": "matter_fp2_to_g2_79", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000036efffcb0c6f42109bf9b8b7421e32fa3f855373345341e6000eccaca135ef3b2e1c0151bddbd46ae92185acb847d74000000000000000000000000000000000edbd7a40f3e688eaff5e29800159b8d799df07e81f65d59011e84329b4689a28a15ce11537fb560df705be26bf14b1e", "Expected": "0000000000000000000000000000000001aa1919a50b5bad62b839d672d5a11ad345fcc61f75eccc42990e113deb8a486423d1b27e7c81536d8a5799986b9408000000000000000000000000000000001879295d2f7bb3923ec61c063ee4f96d7d7cf7786259e2f4cbc3ccffe7e114af264b3527a5e06dcfad50ec1e2a9c1ae0000000000000000000000000000000001042632662e406c95f3fd44a6d956e526907147e7e6d4219c1c4b28a31e479974d00d4ad6e683f6a834d3d4a20830f4b000000000000000000000000000000000a29ea98ec25e7827bcb349ccdb2a57926809f3cce44d5ff6cd636460278c8103b0db78fa580e9edd4ecd0bdb21018ff", "Name": "matter_fp2_to_g2_80", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000974c7d17cbf91947ad435b30ad2b639671a43d67da6a4edc7f8bdc11fe817d4d42f687dd642a2be89c81bc36e8df592000000000000000000000000000000000efeeb85860877abdabae35672a77ca9d2cf0ed18ed209fb905b591a841c900ed06d2c32c56bed5f7efd469d369b05b8", "Expected": "000000000000000000000000000000000c67498c6751cc27d871b8711c4739398c501a5bfb688d7e1a73dc7db5c47c3e28b633078cb83745bf5b0d5d2dde3ce2000000000000000000000000000000000c205c03305422bd44082715b90e0a0ec178003d6f5e14a0d13bb0f2c38f2270816b884b4870b75db44ab080f88a35e2000000000000000000000000000000000257f378935772d326710ec6efeb22f8c9b6b549c8a4c0205b75740047d750d73da4e71aaa8ff33b9bd8ab7621b08e62000000000000000000000000000000000c386a15f09c849be9f449a59e1332a1e7f16a9394c8de198c01399a05b0f963921c4c57d49916407ae0d202af8da32a", "Name": "matter_fp2_to_g2_81", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000015333364f4d0d173ef35e447fc189b9d65ef71b9fc4ecba25fb6c8c1bfe8467f26bb9c55ef10bb34125d714b94aa1df1000000000000000000000000000000000cbba9d8ac191032f03c0746f13108962130c9e2c01d47f01174a4c4d3daa7631268f7dcc08dfda317bd249fb6e73e8a", "Expected": "000000000000000000000000000000000864da537fd94a9ff1bdae733f01e145dc97a894733d0811cd67c2648ba61d0b187241f9ec69d8c011f514894a05a608000000000000000000000000000000000a53ea4ff9c0ff71541ee21127a33daff2b39e74301946a86e51dc7834717e7d8784cf92fa5845bc0613b6b869003f58000000000000000000000000000000000582f5a1fcef3067dfcdfabc6af33871114538abcb02fcad761cb496020c7b423fc52f0075916f160fbe03574df97ea4000000000000000000000000000000001244ede8ba0dc09aacdc5d9f886e59bf963a25885dbbe2c3d1f611bfae82debc556ec4c94f0606492c7b8c7bf976ec34", "Name": "matter_fp2_to_g2_82", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000781e980c167c982c2fc8d0baa3907bc5499eafca675ae20a10b25063c9088fd06f6769df505e5900bcaf99e266c052c00000000000000000000000000000000183c12798438ea92db75d5bf76cf29d320fab3653e4131989205f2817aebcb1b13f161864c084fd13a11459d7d5ccd92", "Expected": "0000000000000000000000000000000016c334aec0e19934665596f0ae37eb398f1d6f0d0c9f08189f1ccc219230395124a9da03858bdba13ec5366da54228af000000000000000000000000000000000b156ea34ae7b5c252dd90997f1c693773a463c26935a69bcc0599b95bde9e6aa31649c48b6ee4ec1f0a56b19273a5170000000000000000000000000000000014b2d69e02418844effcbc0d564b2721deae2872cd1f27f61d544fc0ebd5cadc77c6777ec944ef0500db181a5443618e0000000000000000000000000000000004f0d48a25c1eb81233f385af17ab6abf554e1285b669eeb5e884c64d5815fd5fa1350bb361997cf2e317f7c5e9cd19a", "Name": "matter_fp2_to_g2_83", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000879133a3c0e50c90abf1a6ac75bbeca1121c865ef39e9224ddb160eb725e0850a34aaf9014e42174966773e40e4c99a0000000000000000000000000000000004c66f8f5bd462cb27e9f5e1d93e322bd97582b9e81d07b2877103420262e4cfe6d0e3bc07f9f160701fd754793eae33", "Expected": "0000000000000000000000000000000003c0d6b721cee4e5fdc6a02095674a58075f81b1d28163f81d5b258c82634297009e6bfc8193969e23e196cf7a99ad6c0000000000000000000000000000000013229818411c8e55e50a63df6983150c1d5ead828711131d9c81841850ed76e4712954d3225eb6d7fffd3cb9924f7497000000000000000000000000000000000f42d6e4d5a28dbfda87c806cb0b1bbabb745e63e655c3c6be50411da4dcdc745ae50f71d56e88db8454d40375e325810000000000000000000000000000000000f663ab791b48f76d358e66e8cd8fa40848dff2bbec758ce1d7b3fe02d1f6b3f123cef644d4fd86d6a77b8155feae58", "Name": "matter_fp2_to_g2_84", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000a7e855324ef471b8fefb31967cec84d57953407ba555b672fa59364b303030cb02b6c77933cc63fcd1b8c107b263554000000000000000000000000000000000b50c3f7cebdcf538820113acdb017fcd5d41a4fd679af8dfde7b0c330e3576ca79d09eedc724a93a3f5c90d141e7524", "Expected": "00000000000000000000000000000000197865f685e78a8842fa79ddc728d507e9f31b31666d1952a46f6422c97c83fba3087be70e3bb588260556014523f74000000000000000000000000000000000131f5d85ad3beaabd129d5a5675d90ea911ebd02cddb5ddc7a8be28c33061430d684d123d5c516785d21ebf756c99195000000000000000000000000000000000c7a14948f3aa29f845e5ca9877db9f0477af376eaeb45324c21e6f99e738aeec96b89af4df942bffbabbf50172d8e5b000000000000000000000000000000000ed4aea3cb585b0d36972f9ad6943172ca7375b44d1d6e80e0bf97a0b25d74deca4d35ce865c8747f1c7a2771a37c667", "Name": "matter_fp2_to_g2_85", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001706830efca18d3e75ea0f1ca8af23a816017ceeb045694cdbad6d3d9aa5a9ddb123f5097a226a217166de3a82038393000000000000000000000000000000000402132ac383a2fcb17fe73398273ef0c2f2d0d6edabc78f31080d3ecbf7c249ffeef28bb8b37a6ef2a7d726c070dc41", "Expected": "000000000000000000000000000000000a795c2affaaecab6cd2cfd6c8fab6e35cdd646e9cfa7b5e02400ef4abf839a69924ea80152eca7810a5041d1bf58ee800000000000000000000000000000000121426bb945d6f6b385c98a5247b7dadaebd3375dd8b2bff7aa77fddfbe603de89e77baf0e8f36a924c707c53d29a1450000000000000000000000000000000007a6fcb486634186f001c8b99874f0a07a37f1ff4b30599d2f570f1bb4ff290b816547f6ce8b3c1ed33e57630a1d57ab000000000000000000000000000000000fa65924a8f17414eb7dcc54f2a4134568484e91533dd21fd33cbcc37a920f2804516a64f1986e9d887ca189179d07c8", "Name": "matter_fp2_to_g2_86", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024beda2b950efcee233435f0c748e33aa928f54ff29d3db217d7e32b1aac5f4ed11705da4fb8fd38481382486e4aef7000000000000000000000000000000000c85283ad6e35a72d07b74775df1a4660113d50b51426451f454a575adf9cbf9d7be3f521649f6c367c4f4c74b67ff6b", "Expected": "00000000000000000000000000000000049d9ac43e31faa3d02f8255d207b82e4b27e8a9a61ba45fc4f9ad8048e5f89b58d25d98253aabe29334e0dc09d1cd6b000000000000000000000000000000001544f90a0baea38b48d89bcb337cf5a80faaa79334733b7e6126f55358a7e498aeb61419065b9434cab9d10fe8e7fd9f00000000000000000000000000000000139bdd668462a1b5d3ef1299d47aa91ed141ccbeba5b08a8ee31b023aa78c16514a97ba08abf5c8bb1abbd85b3fe87350000000000000000000000000000000005c7dbb8a22403a96aee634cfc67ee6f1069cd61a1e1831e8faa9d7e1aa5e4f7623f51f2e5b739f7fcf3b4ba77c82ff1", "Name": "matter_fp2_to_g2_87", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000cb18f477abe58af92116101c3f52ad4f6074ed92a08c3adcc6660b555df9cff09dd8b34e032ed81e868a62bda50378d0000000000000000000000000000000013c4ab1558dc250c3b5d0f0fae3db62b8df969bb41e9ecc24c10e1e51cb399f1368bed7375a9b9ad9c7653c868eecfe3", "Expected": "000000000000000000000000000000000b8b8bf2b25c2386e5f3be4bdb387d8005cf055e68ab9a5606f17dbedc4fbd7a11314fd646d08bbd6e394485d4f56f5f00000000000000000000000000000000173a45d766682f82ec2d69aed1d80ede2477c276ddaa8fb97f5f4d0515b2c2e370c615cd81c1e361f95db855c9b1b6e200000000000000000000000000000000115868a9187a0465a9309054e865ef224ec3c88a5eafbcc25f9a912ee3b19084757a90b72a4038ba71b10f59fe2f93100000000000000000000000000000000006c5476eb8aa1a471d289af52c7d1df55f6bb1ad53d7eaba6bdc2a97fcb24ec480f9d8e12079d366f2213194c861f016", "Name": "matter_fp2_to_g2_88", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000188f650fdc51b970d16c0637ad5e97aade93c7f1398751439484ec6cc56613814908e51cfa7f68da9d980bb9dac47a400000000000000000000000000000000081834f86f1310135a2cb03265f37d9b7c9459bb149bc54b5a61319a7cde36c6a2a0fb49f8f1fb9d80f07b84f799119f", "Expected": "0000000000000000000000000000000016e8fea4d09831146fc35bcad28e441f2c02e4d17838e04dc7cf909b2133297a13f07ee927722f3d78e36721d6848e3400000000000000000000000000000000114dee8b3a47269e9ada05ee015a874d1cbdfff4acdf5310642f829efd08f78dd6110e1c7a514e7d76aff52046f4ed140000000000000000000000000000000017b9d23f7a865a3ca61197d841fd9195805a9e883d79dc7d36e82f504e6689ade0e84c70a5c5c516fac3e3c643942e160000000000000000000000000000000001ab82b2a0986dec3211507b8adca351829b0a13f25e281f98f54d9e0e32280ea4c638dcb74280eb747a0d9af43b6b74", "Name": "matter_fp2_to_g2_89", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006f66eb49f95f51ec90df86254580f0ae57862bdd8b5f2759ace63c5f14f8c5a762207f744bb82a8962f8c4fa410dfdb0000000000000000000000000000000004e02a80628c30ce336eab890fa37a227f77357a60be72cb87cc2b7442d2163d395fdc59350624ca1322bfe8619a2efd", "Expected": "0000000000000000000000000000000006bc2ae646a603a1f4524b445cdeb99914e4ed19cd0676d511764b828bfe126e81cad2cb566655f04de1a302c14d70bc00000000000000000000000000000000023bd509aabfa41385e90cd4b1cbbfa45d066c4defab56993aaa386dc5b7707b1a3a7d444b8bd295a30d0b8f4bdc572e0000000000000000000000000000000006f82e60e18cc958375cce6f465db461ff46ed9d15cfcc01a3aff455d54c77ebba5a654c2ec788b6ed8ac53c39defdd3000000000000000000000000000000000896fbe6492c4c297f8b6d60295a7f2565734d69eea67b2675211a203fec043f0d181b1348bea425a068b7bc12676ed0", "Name": "matter_fp2_to_g2_90", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001451bcd19495cea3a19393b77760f688fbf17b107dc131c88cbb503eee2a804e2978d6e8a4720d144083d28be73371d70000000000000000000000000000000017db715e8680a0e82e18b513f2c9c7ea136cefe8add71aac6baba146e3e33a498d025c7e0808ced306c915eb02900c61", "Expected": "0000000000000000000000000000000008604a06a198c3e11458de920176842221667d024f9c155892485a37ff56252be1dc629a6fd580fa41f5e598a23f3651000000000000000000000000000000000e008eed25eafeaa67f27e89e1f81b469724a4b00f08dc4ae672aa1587b19dc615330e3fce0fbd98d7526bc2c4afe69e0000000000000000000000000000000015bc1e4ea5ae2a7fde6d5e5c3e58f6ff5df5bcb125ab402f10edd09087bde39fa27dfcdce7d04fd18ce399729e155fae0000000000000000000000000000000006684e9be8bf9fa4badda842a1d8840f0820d9a797e482c64f4004a18cd63986f19abfc93f6bf068d38eb1e491cabbe6", "Name": "matter_fp2_to_g2_91", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000013a6e129d4dd4aa93cff5489ee879763e2a2231939e609d2d72f07e630b37d09f3057a36fd5cdfc9c81675c996f8ba0f000000000000000000000000000000000e8d7ad082e8f9a718fc2ea712853ed9ab4e8b1a8ca9988f77c70fc759f1fe2d4bd73696e539f130be13b2862efbdf77", "Expected": "000000000000000000000000000000000f15c3d0b40735babb2e38a2471773faa16b2fa307c3a573ef4cfa5a5559574b2d26cf88b19dee204b77f6e11a1b927c000000000000000000000000000000000d224445f3d31d381bb29c4fdc8130174f5bcb957f451c92f4a652cc3d2b5df985017133a944849b5228a88f99bec771000000000000000000000000000000001338b48bc1fa229f251bcd4828654baec9d149f090b19596ad3b444eacc7bc583f97d9cfc40d5611fdcf89cc9a88e33b000000000000000000000000000000000c30dd2aa51f6577d57175edb3ccc1b324717bc195eb0073c1dff4e5b0d77cf5e41ec233527b3936994e86303f91b172", "Name": "matter_fp2_to_g2_92", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003379bc10acda5ed1014e2bba1e30cf83b72fe69259eb35476a031b8a898e0183bc32ee853a85fb3d738424208fc880900000000000000000000000000000000175a2e5a44ed62744fbbab9581ea7283470bff12436dfc414ad80b4070f895de3786022cbaed55bdbbc4f68db7460548", "Expected": "000000000000000000000000000000001735e1f2fe905839fd6534c95b95322f8cc86a4c482f1ad7691b9b9bb8f55015b4faaa1f243786aa33b5874817cd09c80000000000000000000000000000000013f1a27931ac513145f2601e009cf637ba4bdb18a7604f89534fa3ec8488f5b6eab9963c5d753fdd34cbe7d2f8eb8a5900000000000000000000000000000000092d8f800e7a4bf6f9a25ddd7f64fc403db53b1695ae59c15f229458f347a8e7c2ebc415af2d3849282b670c5cf6f8600000000000000000000000000000000019d22d694e559c55db63521e7b60a1a2342c3cce868d70951e5ed32ec0f5efaeab0e78b21359110f6e769776b745938a", "Name": "matter_fp2_to_g2_93", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b384a9db472c38a5d246da56059b7630f002b5f4663abce7c5f6e896222a1ca1ac02883a1ec95a4ef09bcfab7d0652a000000000000000000000000000000000de09ef45aafa56936e446e18ef9ff97ca8b81c295d35cf7b72416ebd80586d0fc479d86c23295ac54a23489af045ebc", "Expected": "000000000000000000000000000000000d7dc499e5213120b3ccc173c83d3c15dde9e13ef57238cad84889243b35c8e69eea2ac7ef7560051dcd7402b46b733e00000000000000000000000000000000063ad31c17eb17d39cb4b33e45a0b0e951becc11b685b10cb45cff268b6dca40b780f7e1532be91903372c413a11b5be00000000000000000000000000000000140da959456cbd34e041409350d6106ff65ce6dd2ac3149f04959b16eb83dd0456ca11e5990daf4a1e5c23d3f30a6c4b00000000000000000000000000000000195d07ab127d49baf89fcf5eea1f5e4cffea1a577a5c864c0e637fbdfa10182adc1d5d4ebb871949300193e45ae0fbdd", "Name": "matter_fp2_to_g2_94", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000014df33e7d3ef2c339b958fee667097ccf146556261f7db4b0b0a3c29897b73a0ca249866cff1461488012bc16df43b0d00000000000000000000000000000000099dda253a43b8cfac580306267d9dfeb2c129ac1818fee43c6df5e582f5fa726ba73e1a2ef6a9e011a387c393529678", "Expected": "0000000000000000000000000000000013ec1ef25b303fe2f10a0bbe9bd77a4b2a055e176c2870c99e63b4baf2b313a835459263351dfbc25c22ea32946d8956000000000000000000000000000000000cb1c3292a2e0c9b1c1ff43cbf7595f39c00fd413b54782681fe75a6f5f231d13912f8d598dd8aaae8159de083dccd8e0000000000000000000000000000000005385f2d4bb6d94d67b2a3bacd3aae31da282707672252c0ab1a12fc85d8e9b9eb75454eb145937542099b860f9d6dce000000000000000000000000000000000e59506f7733a38a7e1da4ea5958de4755b52a9307ba2e5813131b33b86f0e401f97594d9674ff1667068a1ec3c9b145", "Name": "matter_fp2_to_g2_95", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000011c89c8d7e83155a308b2e517a23f05a4a55353332292b44b0a891b6f730fd126bd0b97eb87f0fbdb6c82779791d022f000000000000000000000000000000000da6f02450955bf26e236ec63aaf80a018ac34fd8784bb24a22a1fc5e8bd686244a923009a10cb38b1422534d0997afd", "Expected": "000000000000000000000000000000000f4392a41fb3e58dea97b97fd22e2fe6436c3f9bbcd944585a76a5f1a8f98ea4ee21639208d765b6c3a7d08f8cd3f3f00000000000000000000000000000000002c3d62794996dbb881b665eece98926f41a42c21539125fda6070d9f69e29e0557c886b42e4bcd97b14134d6e9d1d710000000000000000000000000000000004b93f315822aa1be8250c2e736727d390ae3a862c4c7dda452817f70f01c73e6f344df1b0f05f03bd574edecc70902e000000000000000000000000000000000731403981fd6243d00c23d0a42a759016f7907548847743f18421f51b1e72cea92f0c5580328babd4ae3e15bc9c56de", "Name": "matter_fp2_to_g2_96", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000015bb227b5c9ccfb8390edcd158b04a69a88a3b99a10ae90e548182751a16448df25493061afde2c9790a0e75e6f409a20000000000000000000000000000000001d7b609155bf3939192eee9642032e6fb10f57d53916674c60211a37b4a7662759899a9569e2dc730febd23f747a7a3", "Expected": "000000000000000000000000000000000b35c6294b70336217eb9334ff1f1bde9d892d109e947de7f4f5681b3830ed00ad1b89ccd7cbad88ce1586449140697d00000000000000000000000000000000032691e5f4597c06496e9e37907041ddcadd18ca8ce64a8b400b1e2e8d63acce5533231edb66b69807fa2dc026c1d2be000000000000000000000000000000000773ccd132cb215cd98aa17d7fc432e0577b08d8faaa35199000d46fdeeb954e8652566384fa0cc5bcd1724942f7075b00000000000000000000000000000000112e951db3694944fc82fb980547cd8b7f2e5ec6fd2051b6aff2573797bd6a28437848ea0627054af1960ad1de0981e5", "Name": "matter_fp2_to_g2_97", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000017599d71686e817cf58b78dd7586d5b359999b32b0dec2d67e33fb6388411418ecfaa2670a2cc9dce3dadaed0fb3364000000000000000000000000000000001773995b540be9ffbfd276a92c0494e4eae296d094f9f7eca975cf4f73ae05e92bd64ea71ac47bba534044f4072a6591", "Expected": "0000000000000000000000000000000018f2eace212eacabd44ff01d886543410ef72b4d27f8d25cb080dbe4b1d4b2b4e57e4dd40723d15789d9b5104b088d9b00000000000000000000000000000000098e9e9b302876ce85ba486609fd028f357314149ce8b530778e6de586ab057fe59648d8c8ae80fe619c4c605b90784a0000000000000000000000000000000016d20a8ca43d37518c8a0f47566ba61a7aade9ea2cdd4a0907ff0ed862c6b7c64815d50397eebec262a05c6010cfaa790000000000000000000000000000000005a70c2fce25acdc4a95fc2bdedb007d71f24b0b5714fa14910ef590215d25442e91a66b6bfea5f7777f0c6d202eff32", "Name": "matter_fp2_to_g2_98", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f470603a402bc134db1b389fd187460f9eb2dd001a2e99f730af386508c62f0e911d831a2562da84bce11d39f2ff13f000000000000000000000000000000000d8c45f4ab20642d0cba9764126e0818b7d731a6ba29ed234d9d6309a5e8ddfbd85193f1fa8b7cfeed3d31b23b904ee9", "Expected": "0000000000000000000000000000000012e74d5a0c005a86ca148e9eff8e34a00bfa8b6e6aadf633d65cd09bb29917e0ceb0d5c9d9650c162d7fe4aa274526850000000000000000000000000000000005f09101a2088712619f9c096403b66855a12f9016c55aef6047372fba933f02d9d59db1a86df7be57978021e245782100000000000000000000000000000000136975b37fe400d1d217a2b496c1552b39be4e9e71dd7ad482f5f0836d271d02959fdb698dda3d0530587fb86e0db1dd0000000000000000000000000000000000bad0aabd9309e92e2dd752f4dd73be07c0de2c5ddd57916b9ffa065d7440d03d44e7c042075cda694414a9fb639bb7", "Name": "matter_fp2_to_g2_99", - "Gas": 110000, + "Gas": 75000, "NoBenchmark": false } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/blsPairing.json b/core/vm/testdata/precompiles/blsPairing.json index 138b13944ab8..f41d375943df 100644 --- a/core/vm/testdata/precompiles/blsPairing.json +++ b/core/vm/testdata/precompiles/blsPairing.json @@ -3,700 +3,700 @@ "Input": "000000000000000000000000000000000572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e00000000000000000000000000000000166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d2800000000000000000000000000000000122915c824a0857e2ee414a3dccb23ae691ae54329781315a0c75df1c04d6d7a50a030fc866f09d516020ef82324afae0000000000000000000000000000000009380275bbc8e5dcea7dc4dd7e0550ff2ac480905396eda55062650f8d251c96eb480673937cc6d9d6a44aaa56ca66dc000000000000000000000000000000000b21da7955969e61010c7a1abc1a6f0136961d1e3b20b1a7326ac738fef5c721479dfd948b52fdf2455e44813ecfd8920000000000000000000000000000000008f239ba329b3967fe48d718a36cfe5f62a7e42e0bf1c1ed714150a166bfbd6bcf6b3b58b975b9edea56d53f23a0e8490000000000000000000000000000000006e82f6da4520f85c5d27d8f329eccfa05944fd1096b20734c894966d12a9e2a9a9744529d7212d33883113a0cadb9090000000000000000000000000000000017d81038f7d60bee9110d9c0d6d1102fe2d998c957f28e31ec284cc04134df8e47e8f82ff3af2e60a6d9688a4563477c00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "bls_pairing_e(2*G1,3*G2)=e(6*G1,G2)", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e00000000000000000000000000000000166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d2800000000000000000000000000000000122915c824a0857e2ee414a3dccb23ae691ae54329781315a0c75df1c04d6d7a50a030fc866f09d516020ef82324afae0000000000000000000000000000000009380275bbc8e5dcea7dc4dd7e0550ff2ac480905396eda55062650f8d251c96eb480673937cc6d9d6a44aaa56ca66dc000000000000000000000000000000000b21da7955969e61010c7a1abc1a6f0136961d1e3b20b1a7326ac738fef5c721479dfd948b52fdf2455e44813ecfd8920000000000000000000000000000000008f239ba329b3967fe48d718a36cfe5f62a7e42e0bf1c1ed714150a166bfbd6bcf6b3b58b975b9edea56d53f23a0e8490000000000000000000000000000000010e7791fb972fe014159aa33a98622da3cdc98ff707965e536d8636b5fcc5ac7a91a8c46e59a00dca575af0f18fb13dc0000000000000000000000000000000016ba437edcc6551e30c10512367494bfb6b01cc6681e8a4c3cd2501832ab5c4abc40b4578b85cbaffbf0bcd70d67c6e200000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "bls_pairing_e(2*G1,3*G2)=e(5*G1,G2)", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000fd75ebcc0a21649e3177bcce15426da0e4f25d6828fbf4038d4d7ed3bd4421de3ef61d70f794687b12b2d571971a550000000000000000000000000000000004523f5a3915fc57ee889cdb057e3e76109112d125217546ccfe26810c99b130d1b27820595ad61c7527dc5bbb132a9000000000000000000000000000000000186a1da343cacf1815b9c8b6c807f536249dbfdb59d77bf4920ad2198a0d83ada21f7c39de6f06a5599f22571cab288d000000000000000000000000000000000ba1ec44f95121bd622932b84bbb4b3d279f69c494ee44db68e3165c86b627ba5e397ee197313fb5b775972798997332000000000000000000000000000000000783e7493e9fb106fa0d085e7c03eb816468d12c65d9b77643ed07c02583d491f4db5db44e565d50d8ccaa9ad8f7f8e80000000000000000000000000000000010a6a5fd90cd5f4fb6545814f5df065b001074bb3f29f649dd2612815df3a19a320f7754dd3d458e48e7fb1b4953978f000000000000000000000000000000000345dd80ffef0eaec8920e39ebb7f5e9ae9c1d6179e9129b705923df7830c67f3690cbc48649d4079eadf5397339580c00000000000000000000000000000000083d3baf25e42f2845d8fa594dda2e0f40a4d670dda40f30da0aff0d81c87ac3d687fe84eca72f34c7c755a045668cf100000000000000000000000000000000129c4945fe62538d2806fff056adac24f3bba8e17e42d82122affe6ad2123d68784348a79755f194fde3b3d448924032000000000000000000000000000000000528590e82f409ea8ce953f0c59d15080185dc6e3219b69fcaa3a2c8fc9d0b9e0bc1e75ec6c52638e6eaa4584005b5380000000000000000000000000000000018dc3e893f74729d27dd44f45a5a4f433dcd09a3b485e9d1c2bd0eb5e0e4c9024d928ddc426fdecae931e89885ee4db4000000000000000000000000000000000d6ee02e1fc7e52a8e1ef17e753065882c6fcc14da61da7ffe955fe84a9d2af9ba57562c69db3088652931bf124b0d5300000000000000000000000000000000051f8a0b82a6d86202a61cbc3b0f3db7d19650b914587bde4715ccd372e1e40cab95517779d840416e1679c84a6db24e000000000000000000000000000000000b6a63ac48b7d7666ccfcf1e7de0097c5e6e1aacd03507d23fb975d8daec42857b3a471bf3fc471425b63864e045f4df00000000000000000000000000000000131747485cce9a5c32837a964b8c0689ff70cb4702c6520f2220ab95192d73ae9508c5b998ffb0be40520926846ce3f100000000000000000000000000000000101e147f8bd7682b47b3a6cc0c552c26ce90b9ce0daef21f7f634b3360483afa14a11e6745e7de01a35c65b396a1a12700000000000000000000000000000000090ca61ed16c4c1e80acfef736eea2db0d7425d9110cb53e6c4a2aa3f8a59ee6c60bdce8df5825011066d44bef84d29600000000000000000000000000000000028207394adcbf30250ac21a8f1db6283580bc5e39159930552e5edb25e6215c66b6450296edc80dbc3a2acd125dab160000000000000000000000000000000019bef05aaba1ea467fcbc9c420f5e3153c9d2b5f9bf2c7e2e7f6946f854043627b45b008607b9a9108bb96f3c1c089d3000000000000000000000000000000000adb3250ba142db6a748a85e4e401fa0490dd10f27068d161bd47cb562cc189b3194ab53a998e48a48c65e071bb541170000000000000000000000000000000016cfabbe60d1e55723a0ff72cf802f2d1cf13ed131e17729adc88522a657f320a336078a9399c8e61a3bbde3d52fd3640000000000000000000000000000000009aa9a3c2a6d49d286aa593c6ff644f1786fa9ae471bdb3fe70b150a9ed7584eaa886ac057c30005c3642f65ad5581cc0000000000000000000000000000000001d417894c0cce924955a795b188b27951f8438a5485404b921a42fa79dea03c10e29d0390df2f34d7be13f360a7fada00000000000000000000000000000000189b0b3a04e6c613899d51231dbf0cba6a8a8f507ebed99d24fba7ebac6c97a8859ffde88e6d95c1a9d6b4f0a8f3c417000000000000000000000000000000000d9e19b3f4c7c233a6112e5397309f9812a4f61f754f11dd3dcb8b07d55a7b1dfea65f19a1488a14fef9a414950835820000000000000000000000000000000009d0d1f706f1a85a98f3efaf5c35a41c9182afc129285cf2db3212f6ea0da586ca539bc66181f2ccb228485dd8aff0a70000000000000000000000000000000016cad7807d761f2c0c6ff11e786a9ed296442de8acc50f72a87139b9f1eb7c168e1c2f0b2a1ad7f9579e1e922d0eb309000000000000000000000000000000000d3577c713fcbc0648ca8fbdda0a0bf83c726a6205ee04d2d34cacff92b58725ca3c9766206e22d0791cb232fa8a9bc3000000000000000000000000000000000f5ea1957be1b9ca8956ba5f6b1c37ea72e2529f80d7a1c61df01afcc2df6f99ced81ac0052bd0e1e83f09d76ad8d33b000000000000000000000000000000000aabced4e2b9e4a473e72bf2b1cc0ce7ab13de533107df2205ed9e2bb50fa0217e6a13abcd12fce1bda1ccf84dac237a00000000000000000000000000000000073eb991aa22cdb794da6fcde55a427f0a4df5a4a70de23a988b5e5fc8c4d844f66d990273267a54dd21579b7ba6a086000000000000000000000000000000001825bacd18f695351f843521ebeada20352c3c3965626f98bc4c68e6ff7c4eed38b48f328204bbb9cd461511d24ebfb3000000000000000000000000000000000029ea93c2f1eb48b195815571ea0148198ff1b19462618cab08d037646b592ecab5a66b4bc660ffd02d1b996ca377da000000000000000000000000000000000bb319a4550c981ee89e3c7e6dcc434283454847792807940f72fd2dbf3625b092e0a0c03e581fd9bd9cf74f95ccef15000000000000000000000000000000000abb072b8d9011e81c9f5b23ba86fdb6399c878aa4eadee45fb2486afe594dffc53be643598a23e5428894a36f5ac3ce0000000000000000000000000000000005d04aa0b644faae17d4c76a14aa680c69fdfc6b59fee3ef45641f566165fced60cbbda4ca096e132bb6f58ab4516686000000000000000000000000000000001098f178f84fc753a76bb63709e9be91eec3ff5f7f3a5f4836f34fe8a1a6d6c5578d8fd820573cef3a01e2bfef3eaf3a000000000000000000000000000000000ea923110b733b531006075f796cc9368f2477fe26020f465468efbb380ce1f8eebaf5c770f31d320f9bd378dc758436000000000000000000000000000000001065f2a2d29a997343765f239c99a018490eced40ac42fc93217dfe20d8b43ee2215f65166aff483b3dc042c5a43b196000000000000000000000000000000000766e4c66f4a442ff1f61a7a4d197d2b47dd226d0e7822a9b065108cfc643cd3f3d5ae59ed2ce4cde13fd9260bb5b7cc0000000000000000000000000000000012251cc6abbabeb7bbe1fdd63eaee10832a748fff24f7e3fdccaea87facb6e99f2e0407a38f27f90450a471b873104620000000000000000000000000000000011181e08c8fba91271adfee9d31681f8412ab7a3f754f7ba4709024c0ad2287e32dd455d71a296b4838072a8ab9d96f2000000000000000000000000000000001252a4ac3529f8b2b6e8189b95a60b8865f07f9a9b73f98d5df708511d3f68632c4c7d1e2b03e6b1d1e2c01839752ada0000000000000000000000000000000002a1bc189e36902d1a49b9965eca3cb818ab5c26dffca63ca9af032870f7bbc615ac65f21bed27bd77dd65f2e90f53580000000000000000000000000000000005a7445f55add1ed5c143424ceef3d594280e316c9441a8e68c3ad97377141d015bf878bdfcf0df9fbcd0529f4e8100800000000000000000000000000000000192b52ba08ed509fc84d5775a7182498fd1ff80941d673c53470c9c9f1192f9c0057d68a1dfee0c68fe5df3625cc43bf000000000000000000000000000000000d3fcaf2f727e0eb32c65da9b910dc681b948dda874d0db6f6ed3f063430fbf073385a9a14c2dd78568726124e2b3ea8000000000000000000000000000000001943ce22cdb2387bd5796950dc95d1ace4012ab9bb4afb46223760230c1709e075f1ae76d6b3f2e947ba6b16d458ccd1000000000000000000000000000000001271205227c7aa27f45f20b3ba380dfea8b51efae91fd32e552774c99e2a1237aa59c0c43f52aad99bba3783ea2f36a4000000000000000000000000000000001407ffc2c1a2fe3b00d1f91e1f4febcda31004f7c301075c9031c55dd3dfa8104b156a6a3b7017fccd27f81c2af222ef000000000000000000000000000000000a29e38da2d42fd4712052800c7c8dd6e94fd9f506e946068aaac799d60b94c2d7515769ffdd32ea95d3910330ec47de000000000000000000000000000000000c60dae92451206390e30b5daa7151d63624dee496753c87dd54eadc92dc9602081fae02a1a53bac97e984a571923a5d00000000000000000000000000000000085f4fda4c72328895f20c683cb49603a37ff2c43d62f66602506dad5b8d1daebfbac7a7db3f50ccf4dfff277deb105c0000000000000000000000000000000005674d005457e0fe1f0fd978d63996c5f3d29f9149ee4eb04c464742dd329ccaef5e5f6b896d986ddfc9f1b2a3aec13100000000000000000000000000000000071bc66d6e2d244afc4a5ce4da1dce3d0c22c303ba61310fdf57843bbd97763ef496833dfa99d14be084bb1a039bb2da0000000000000000000000000000000012c22e047b0af8e2f4bf3bd3633ef0f8264004ca8ea5677a468857a1762f815235a479e53f4ad4741ffda3fb855021c900000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "bls_pairing_10paircheckstrue", - "Gas": 345000, + "Gas": 495000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000fd75ebcc0a21649e3177bcce15426da0e4f25d6828fbf4038d4d7ed3bd4421de3ef61d70f794687b12b2d571971a550000000000000000000000000000000004523f5a3915fc57ee889cdb057e3e76109112d125217546ccfe26810c99b130d1b27820595ad61c7527dc5bbb132a9000000000000000000000000000000000186a1da343cacf1815b9c8b6c807f536249dbfdb59d77bf4920ad2198a0d83ada21f7c39de6f06a5599f22571cab288d000000000000000000000000000000000ba1ec44f95121bd622932b84bbb4b3d279f69c494ee44db68e3165c86b627ba5e397ee197313fb5b775972798997332000000000000000000000000000000000783e7493e9fb106fa0d085e7c03eb816468d12c65d9b77643ed07c02583d491f4db5db44e565d50d8ccaa9ad8f7f8e80000000000000000000000000000000010a6a5fd90cd5f4fb6545814f5df065b001074bb3f29f649dd2612815df3a19a320f7754dd3d458e48e7fb1b4953978f000000000000000000000000000000000345dd80ffef0eaec8920e39ebb7f5e9ae9c1d6179e9129b705923df7830c67f3690cbc48649d4079eadf5397339580c00000000000000000000000000000000083d3baf25e42f2845d8fa594dda2e0f40a4d670dda40f30da0aff0d81c87ac3d687fe84eca72f34c7c755a045668cf100000000000000000000000000000000129c4945fe62538d2806fff056adac24f3bba8e17e42d82122affe6ad2123d68784348a79755f194fde3b3d448924032000000000000000000000000000000000528590e82f409ea8ce953f0c59d15080185dc6e3219b69fcaa3a2c8fc9d0b9e0bc1e75ec6c52638e6eaa4584005b5380000000000000000000000000000000018dc3e893f74729d27dd44f45a5a4f433dcd09a3b485e9d1c2bd0eb5e0e4c9024d928ddc426fdecae931e89885ee4db4000000000000000000000000000000000d6ee02e1fc7e52a8e1ef17e753065882c6fcc14da61da7ffe955fe84a9d2af9ba57562c69db3088652931bf124b0d5300000000000000000000000000000000051f8a0b82a6d86202a61cbc3b0f3db7d19650b914587bde4715ccd372e1e40cab95517779d840416e1679c84a6db24e000000000000000000000000000000000b6a63ac48b7d7666ccfcf1e7de0097c5e6e1aacd03507d23fb975d8daec42857b3a471bf3fc471425b63864e045f4df00000000000000000000000000000000131747485cce9a5c32837a964b8c0689ff70cb4702c6520f2220ab95192d73ae9508c5b998ffb0be40520926846ce3f100000000000000000000000000000000101e147f8bd7682b47b3a6cc0c552c26ce90b9ce0daef21f7f634b3360483afa14a11e6745e7de01a35c65b396a1a12700000000000000000000000000000000090ca61ed16c4c1e80acfef736eea2db0d7425d9110cb53e6c4a2aa3f8a59ee6c60bdce8df5825011066d44bef84d29600000000000000000000000000000000028207394adcbf30250ac21a8f1db6283580bc5e39159930552e5edb25e6215c66b6450296edc80dbc3a2acd125dab160000000000000000000000000000000019bef05aaba1ea467fcbc9c420f5e3153c9d2b5f9bf2c7e2e7f6946f854043627b45b008607b9a9108bb96f3c1c089d3000000000000000000000000000000000adb3250ba142db6a748a85e4e401fa0490dd10f27068d161bd47cb562cc189b3194ab53a998e48a48c65e071bb541170000000000000000000000000000000016cfabbe60d1e55723a0ff72cf802f2d1cf13ed131e17729adc88522a657f320a336078a9399c8e61a3bbde3d52fd3640000000000000000000000000000000009aa9a3c2a6d49d286aa593c6ff644f1786fa9ae471bdb3fe70b150a9ed7584eaa886ac057c30005c3642f65ad5581cc0000000000000000000000000000000001d417894c0cce924955a795b188b27951f8438a5485404b921a42fa79dea03c10e29d0390df2f34d7be13f360a7fada00000000000000000000000000000000189b0b3a04e6c613899d51231dbf0cba6a8a8f507ebed99d24fba7ebac6c97a8859ffde88e6d95c1a9d6b4f0a8f3c417000000000000000000000000000000000d9e19b3f4c7c233a6112e5397309f9812a4f61f754f11dd3dcb8b07d55a7b1dfea65f19a1488a14fef9a414950835820000000000000000000000000000000009d0d1f706f1a85a98f3efaf5c35a41c9182afc129285cf2db3212f6ea0da586ca539bc66181f2ccb228485dd8aff0a70000000000000000000000000000000016cad7807d761f2c0c6ff11e786a9ed296442de8acc50f72a87139b9f1eb7c168e1c2f0b2a1ad7f9579e1e922d0eb309000000000000000000000000000000000d3577c713fcbc0648ca8fbdda0a0bf83c726a6205ee04d2d34cacff92b58725ca3c9766206e22d0791cb232fa8a9bc3000000000000000000000000000000000f5ea1957be1b9ca8956ba5f6b1c37ea72e2529f80d7a1c61df01afcc2df6f99ced81ac0052bd0e1e83f09d76ad8d33b000000000000000000000000000000000aabced4e2b9e4a473e72bf2b1cc0ce7ab13de533107df2205ed9e2bb50fa0217e6a13abcd12fce1bda1ccf84dac237a00000000000000000000000000000000073eb991aa22cdb794da6fcde55a427f0a4df5a4a70de23a988b5e5fc8c4d844f66d990273267a54dd21579b7ba6a086000000000000000000000000000000001825bacd18f695351f843521ebeada20352c3c3965626f98bc4c68e6ff7c4eed38b48f328204bbb9cd461511d24ebfb3000000000000000000000000000000000029ea93c2f1eb48b195815571ea0148198ff1b19462618cab08d037646b592ecab5a66b4bc660ffd02d1b996ca377da000000000000000000000000000000000bb319a4550c981ee89e3c7e6dcc434283454847792807940f72fd2dbf3625b092e0a0c03e581fd9bd9cf74f95ccef15000000000000000000000000000000000abb072b8d9011e81c9f5b23ba86fdb6399c878aa4eadee45fb2486afe594dffc53be643598a23e5428894a36f5ac3ce0000000000000000000000000000000005d04aa0b644faae17d4c76a14aa680c69fdfc6b59fee3ef45641f566165fced60cbbda4ca096e132bb6f58ab4516686000000000000000000000000000000001098f178f84fc753a76bb63709e9be91eec3ff5f7f3a5f4836f34fe8a1a6d6c5578d8fd820573cef3a01e2bfef3eaf3a000000000000000000000000000000000ea923110b733b531006075f796cc9368f2477fe26020f465468efbb380ce1f8eebaf5c770f31d320f9bd378dc758436000000000000000000000000000000001065f2a2d29a997343765f239c99a018490eced40ac42fc93217dfe20d8b43ee2215f65166aff483b3dc042c5a43b196000000000000000000000000000000000766e4c66f4a442ff1f61a7a4d197d2b47dd226d0e7822a9b065108cfc643cd3f3d5ae59ed2ce4cde13fd9260bb5b7cc0000000000000000000000000000000012251cc6abbabeb7bbe1fdd63eaee10832a748fff24f7e3fdccaea87facb6e99f2e0407a38f27f90450a471b873104620000000000000000000000000000000011181e08c8fba91271adfee9d31681f8412ab7a3f754f7ba4709024c0ad2287e32dd455d71a296b4838072a8ab9d96f2000000000000000000000000000000001252a4ac3529f8b2b6e8189b95a60b8865f07f9a9b73f98d5df708511d3f68632c4c7d1e2b03e6b1d1e2c01839752ada0000000000000000000000000000000002a1bc189e36902d1a49b9965eca3cb818ab5c26dffca63ca9af032870f7bbc615ac65f21bed27bd77dd65f2e90f53580000000000000000000000000000000005a7445f55add1ed5c143424ceef3d594280e316c9441a8e68c3ad97377141d015bf878bdfcf0df9fbcd0529f4e8100800000000000000000000000000000000192b52ba08ed509fc84d5775a7182498fd1ff80941d673c53470c9c9f1192f9c0057d68a1dfee0c68fe5df3625cc43bf000000000000000000000000000000000d3fcaf2f727e0eb32c65da9b910dc681b948dda874d0db6f6ed3f063430fbf073385a9a14c2dd78568726124e2b3ea8000000000000000000000000000000001943ce22cdb2387bd5796950dc95d1ace4012ab9bb4afb46223760230c1709e075f1ae76d6b3f2e947ba6b16d458ccd1000000000000000000000000000000001271205227c7aa27f45f20b3ba380dfea8b51efae91fd32e552774c99e2a1237aa59c0c43f52aad99bba3783ea2f36a4000000000000000000000000000000001407ffc2c1a2fe3b00d1f91e1f4febcda31004f7c301075c9031c55dd3dfa8104b156a6a3b7017fccd27f81c2af222ef000000000000000000000000000000000a29e38da2d42fd4712052800c7c8dd6e94fd9f506e946068aaac799d60b94c2d7515769ffdd32ea95d3910330ec47de000000000000000000000000000000000c60dae92451206390e30b5daa7151d63624dee496753c87dd54eadc92dc9602081fae02a1a53bac97e984a571923a5d00000000000000000000000000000000085f4fda4c72328895f20c683cb49603a37ff2c43d62f66602506dad5b8d1daebfbac7a7db3f50ccf4dfff277deb105c0000000000000000000000000000000005674d005457e0fe1f0fd978d63996c5f3d29f9149ee4eb04c464742dd329ccaef5e5f6b896d986ddfc9f1b2a3aec13100000000000000000000000000000000071bc66d6e2d244afc4a5ce4da1dce3d0c22c303ba61310fdf57843bbd97763ef496833dfa99d14be084bb1a039bb2da0000000000000000000000000000000012c22e047b0af8e2f4bf3bd3633ef0f8264004ca8ea5677a468857a1762f815235a479e53f4ad4741ffda3fb855021c900000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "bls_pairing_10pairchecksfalse", - "Gas": 345000, + "Gas": 495000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000012196c5a43d69224d8713389285f26b98f86ee910ab3dd668e413738282003cc5b7357af9a7af54bb713d62255e80f560000000000000000000000000000000006ba8102bfbeea4416b710c73e8cce3032c31c6269c44906f8ac4f7874ce99fb17559992486528963884ce429a992fee0000000000000000000000000000000017c9fcf0504e62d3553b2f089b64574150aa5117bd3d2e89a8c1ed59bb7f70fb83215975ef31976e757abf60a75a1d9f0000000000000000000000000000000008f5a53d704298fe0cfc955e020442874fe87d5c729c7126abbdcbed355eef6c8f07277bee6d49d56c4ebaf334848624000000000000000000000000000000001302dcc50c6ce4c28086f8e1b43f9f65543cf598be440123816765ab6bc93f62bceda80045fbcad8598d4f32d03ee8fa000000000000000000000000000000000bbb4eb37628d60b035a3e0c45c0ea8c4abef5a6ddc5625e0560097ef9caab208221062e81cd77ef72162923a1906a40", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_0", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000117dbe419018f67844f6a5e1b78a1e597283ad7b8ee7ac5e58846f5a5fd68d0da99ce235a91db3ec1cf340fe6b7afcdb0000000000000000000000000000000013316f23de032d25e912ae8dc9b54c8dba1be7cecdbb9d2228d7e8f652011d46be79089dd0a6080a73c82256ce5e4ed200000000000000000000000000000000192fa5d8732ff9f38e0b1cf12eadfd2608f0c7a39aced7746837833ae253bb57ef9c0d98a4b69eeb2950901917e99d1e0000000000000000000000000000000009aeb10c372b5ef1010675c6a4762fda33636489c23b581c75220589afbc0cc46249f921eea02dd1b761e036ffdbae220000000000000000000000000000000002d225447600d49f932b9dd3ca1e6959697aa603e74d8666681a2dca8160c3857668ae074440366619eb8920256c4e4a00000000000000000000000000000000174882cdd3551e0ce6178861ff83e195fecbcffd53a67b6f10b4431e423e28a480327febe70276036f60bb9c99cf7633", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_1", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008ab7b556c672db7883ec47efa6d98bb08cec7902ebb421aac1c31506b177ac444ffa2d9b400a6f1cbdc6240c607ee110000000000000000000000000000000016b7fa9adf4addc2192271ce7ad3c8d8f902d061c43b7d2e8e26922009b777855bffabe7ed1a09155819eabfa87f276f000000000000000000000000000000000a69d6d9f79e19b38e6bf5a245dc820bddbdfe038d50932f76d0e4629d759f8ca6d573fcfc39256305daedf452f9fdf40000000000000000000000000000000015f5949369e58487afcecf8018775d1b0a73e913bf77e13d2e5a843bbbeba7d1978ca27ae8bfc87d30f567dd396b980e00000000000000000000000000000000182198bb38a0353b8db25389e56ab0d8679a1bda008a65dad77e4c95bc6804f6311eb16c761e1a5e2a5f87cfada49fa4000000000000000000000000000000000eb5483959e98c30e71db52615f63521378b156f142d46f3bb285b94aef39d80feacec335b797c5a68dc17ba89d43e0f", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_2", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000015ff9a232d9b5a8020a85d5fe08a1dcfb73ece434258fe0e2fddf10ddef0906c42dcb5f5d62fc97f934ba900f17beb330000000000000000000000000000000009cfe4ee2241d9413c616462d7bac035a6766aeaab69c81e094d75b840df45d7e0dfac0265608b93efefb9a8728b98e4000000000000000000000000000000000286f09f931c07507ba4aafb7d43befe0b1d25b27ecc9199b19a9dc20bc7ec0329479ef224e00dece67ec0d61f1ca5ae0000000000000000000000000000000014e6ed154b5552be5c463b730b2134f83e0071dcdadfaa68e6c7c7f6e17dabb7daf06e409177bc4b38cfdb8248157618000000000000000000000000000000000f145e998dc6eb0c2b2be87db62949c7bfa63e8b01c8634248010fd623cfaec5d6c6c193331440957d333bf0c988b7b10000000000000000000000000000000002a1ab3eea343cfdea5779f64b3bddbf0769aded60e54a7507338f044310ba239430663394f110e560594d6042a99f1c", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_3", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017a17b82e3bfadf3250210d8ef572c02c3610d65ab4d7366e0b748768a28ee6a1b51f77ed686a64f087f36f641e7dca900000000000000000000000000000000077ea73d233ccea51dc4d5acecf6d9332bf17ae51598f4b394a5f62fb387e9c9aa1d6823b64a074f5873422ca57545d3000000000000000000000000000000000d1007ca90451229d3780d66d3aed7c9d8fc82e9d45549e8586600e38eb6763f3c466e2f6ba6ba1dafd8f00cc452dda20000000000000000000000000000000001d017d920a262b6d6597bab532f83270f41526409510e80278d1c3595ceabb9ceba8ae32b1817297ff78ea7a0d252e8000000000000000000000000000000000935b7a59d2e51bbb2f9b54ccb06ebee9d189fa82f0e97d10c8020badb3de7fe15731b5895faed8cad92ae76e2e1b649000000000000000000000000000000000792dadd48a20040ad43facedc109747411895180813349d41d0e5b389176bfb15895d41665be8d1afa80835ef818eca", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_4", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c1243478f4fbdc21ea9b241655947a28accd058d0cdb4f9f0576d32f09dddaf0850464550ff07cab5927b3e4c863ce90000000000000000000000000000000015fb54db10ffac0b6cd374eb7168a8cb3df0a7d5f872d8e98c1f623deb66df5dd08ff4c3658f2905ec8bd02598bd4f9000000000000000000000000000000000095353ad699b89ac82ca7ef631775b2b3a6e3ed8dd320440cdb929baa428e63cb902a83857cc0e2621470544c69e84aa000000000000000000000000000000000892559ade1060b0eef2cbc1c74de62a7ff076a3621e5f0f159672a549f1201f2ffb3ac12c8b12cb86ae3e386c33e219000000000000000000000000000000000750df4632a7126ddb08658a4001f949b9764d9cc43a9393cc55d8fdbb15d4a1186dd87a6433d111888a7804540ad9fc0000000000000000000000000000000017554bd444665df044b91b0b2614017bbfcd7acc7f8c5a16cea2861235578ce2b27dcced9fba234999fa478cd3f6e42d", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_5", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000328f09584b6d6c98a709fc22e184123994613aca95a28ac53df8523b92273eb6f4e2d9b2a7dcebb474604d54a210719000000000000000000000000000000001220ebde579911fe2e707446aaad8d3789fae96ae2e23670a4fd856ed82daaab704779eb4224027c1ed9460f39951a1b00000000000000000000000000000000175dadb6ee656ec6aebf8d0e5edaee3f119c74e0ea64e374be9e8ab9fd3d085fceeedf4ed8de676ebe9065d83b0542ad0000000000000000000000000000000005cd6a875329c23e4918976cf997e93e403957acfc999f8159a630d21ab6f1762925c063784237262bedc82402ad81bb0000000000000000000000000000000003274bcb8db35e50164d136c2a98b5a6d2fb5f9767d0ee11c1358bf7ca5ed96d9122f8c1051ba3c658cc89777d03dfa5000000000000000000000000000000000380a240443dff85b6542f75db28b87c39e278cdb8d9627efbbc63b229e6ce783f6fb0114c8e91c2fd6ea71c95bb99a4", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_6", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000002ebfa98aa92c32a29ebe17fcb1819ba82e686abd9371fcee8ea793b4c72b6464085044f818f1f5902396df0122830cb00000000000000000000000000000000001184715b8432ed190b459113977289a890f68f6085ea111466af15103c9c02467da33e01d6bff87fd57db6ccba442a000000000000000000000000000000000834cf1b4149d100c41b1bca0495e455002eb6596bddcb94ae48d0c65957e8b313372f8e0d6e57504664b266f38293150000000000000000000000000000000000de2875fbd14760bac4c2cc7d3f239177efe9f7f61f767be420d44f24c9fb863efd60dcd732986db8c5b72470617ea60000000000000000000000000000000000bc9535ebf11c2dcc8c7d3bcd09d7d14035635fccb5fddb7df29ce8855e79f99809781d6ffbbcb33d1227314609abee00000000000000000000000000000000039bbfb4d969d702255e3be7f255a97529a19687ce38cb70637c37894d4102591feef428b0afe8c9ef50310ae3b83091", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_7", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009d6424e002439998e91cd509f85751ad25e574830c564e7568347d19e3f38add0cab067c0b4b0801785a78bcbeaf246000000000000000000000000000000000ef6d7db03ee654503b46ff0dbc3297536a422e963bda9871a8da8f4eeb98dedebd6071c4880b4636198f4c2375dc795000000000000000000000000000000000fc09c241899fa6e8cc3b31830e9c9f2777d2bc6758260c9f6af5fce56c9dc1a8daedb5bcb7d7669005ccf6bfacf71050000000000000000000000000000000018e95921a76bc37308e2f10afb36a812b622afe19c8db84465ab8b3293c7d371948ee0578dbb025eed7ed60686109aa0000000000000000000000000000000001558cdfbac6ea2c4c1f4b9a2e809b19e9f4ba47b78d2b18185ed8c97c2f9c2990beadc78b85c123b4c3c08d5c5b3bbef000000000000000000000000000000000ea4dfdd12b9a4b9a3172671a6eafed7508af296813ec5700b697d9239ae484bcf7ab630e5b6830d6d95675be5174bb2", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_8", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000002d1cdb93191d1f9f0308c2c55d0208a071f5520faca7c52ab0311dbc9ba563bd33b5dd6baa77bf45ac2c3269e945f4800000000000000000000000000000000072a52106e6d7b92c594c4dacd20ef5fab7141e45c231457cd7e71463b2254ee6e72689e516fa6a8f29f2a173ce0a1900000000000000000000000000000000000b36d8fb9bd156f618ab8049d41dfe0698218764c0abb10e12fae43c8810b8e2a5201364e2778f6f433b199bb8f9a6800000000000000000000000000000000000707eb15411b63722b4308c0ed4288320078d2463ae659ad4fb3f9ef8124f379df92d64e077403e50727388adb59ac00000000000000000000000000000000158e1249d5b91614924acb23899c6bae408697dec0982c10d0459746499f4e6739afb9d5129568106ed1a1caefeaa9640000000000000000000000000000000019e841562e4aa75321143f8ce1e5ec6158fa5cb8b98c839a486188260c18ee8a7600930f23aa39eac2eb520d6a0fba90", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_9", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000641642f6801d39a09a536f506056f72a619c50d043673d6d39aa4af11d8e3ded38b9c3bbc970dbc1bd55d68f94b50d0000000000000000000000000000000009ab050de356a24aea90007c6b319614ba2f2ed67223b972767117769e3c8e31ee4056494628fb2892d3d37afb6ac94300000000000000000000000000000000186a9661d6fb539e8687ac214301b2d7623caedd76f4055089befba6ef2c96263d810921ad7783d229f82783c9def424000000000000000000000000000000000447f3e20caa1f99fbaccab7bde2bd37fe77cea691ebf2b9499f95bbbb77afe72b7039eb0c05970b61360fcf8ade73730000000000000000000000000000000005e11f828eda86c10a1d7929def547ac06885da278afae59c5d95453caf0a2d8ed186fa7c6d0a7ab6e9142cfa4b338190000000000000000000000000000000003d954e61b6ab71042b19e804efccd4956b56662f27f70a9255cec0c464b86c0e83721ad3785dec62dd4a9dd3d6d5d53", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_10", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000fd4893addbd58fb1bf30b8e62bef068da386edbab9541d198e8719b2de5beb9223d87387af82e8b55bd521ff3e47e2d000000000000000000000000000000000f3a923b76473d5b5a53501790cb02597bb778bdacb3805a9002b152d22241ad131d0f0d6a260739cbab2c2fe602870e0000000000000000000000000000000002b94534aa0ba923bda34cbe92b3cd7a3e263741b120240ff5bdb8b718f094d3867e3fcabeab4a7be39c8f8c4fdd10d900000000000000000000000000000000048711cf6a82534d64d072355cb8fe647808e7e8b2d9ac9ed52eb7fe121647a721dd1234c71ecd163d91701eb7331cac00000000000000000000000000000000141ef2e23a1ecc7ef2ed3ea915492e79cfffe60b5e0de8441e878bd0653843d79c724e3c5ebe2321361df99f8932ddc200000000000000000000000000000000085513b4009f29b3e00a91c2c4be418368560802ba4194cbd2f4fa3d72a55fcae547014434514a8b2a8fe3e0b28d2773", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_11", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000002cb4b24c8aa799fd7cb1e4ab1aab1372113200343d8526ea7bc64dfaf926baf5d90756a40e35617854a2079cd07fba40000000000000000000000000000000003327ca22bd64ebd673cc6d5b02b2a8804d5353c9d251637c4273ad08d581cc0d58da9bea27c37a0b3f4961dbafd276b0000000000000000000000000000000009143507a24313ee33401955fc46562c9b20c9917df3b40ccbd7ed43b1349d4551cfd98a4976d6fec5fc289460c8d89900000000000000000000000000000000060566b79df5cc975e669da8ca3a7fa91bf3f5c9fb871c3d62f4a3e79dbc341b89d38b588e5414bc385d5e3cbf3ab9310000000000000000000000000000000016bf40b8cc4c01a87aafae0c4439b623a51ba9a383756a550b69d627d6f45209f0d87e4f9be9edff35c986f7b9c49e3f000000000000000000000000000000001842d9172bce51a164fbdbdb108d0faae07e4642f21c80e40ac31e737657472ae3dfe552b65349629c210a068c4afc0e", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_12", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024ad70f2b2105ca37112858e84c6f5e3ffd4a8b064522faae1ecba38fabd52a6274cb46b00075deb87472f11f2e67d90000000000000000000000000000000010a502c8b2a68aa30d2cb719273550b9a3c283c35b2e18a01b0b765344ffaaa5cb30a1e3e6ecd3a53ab67658a5787681000000000000000000000000000000000ab19bbddd661e9db8fe4cb307ecebdc5e03efbb95c5b44716c7075bd60efcfc67de0bfd7c46ad989a613946c90a4c1000000000000000000000000000000000120800e7f344cda816299fa37f603ade06beb3b10907f5af896d6b4e42f7f865b756f14164db84411c56cb2ea81f60be000000000000000000000000000000000f688ddd257e66362af1437b6922d3397a7c3dd6dea6bca8ebd6375e75bf2de40bc287cbf3434388191e56b92949c83b0000000000000000000000000000000005252465784aff8c1c707da58b5808c69583bf852d68f96912bc53f8dae4536b09ccbbd25a49d9e744118992b92b6792", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_13", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000000704cc57c8e0944326ddc7c747d9e7347a7f6918977132eea269f161461eb64066f773352f293a3ac458dc3ccd5026a000000000000000000000000000000001099d3c2bb2d082f2fdcbed013f7ac69e8624f4fcf6dfab3ee9dcf7fbbdb8c49ee79de40e887c0b6828d2496e3a6f768000000000000000000000000000000000e3165efe00f69aee84ac56d2161f07c017abfaadeaad34f8c96799d68bae0e6f9b557bbf9137e7826f49f29c58d1ef9000000000000000000000000000000000de0dce7ea371ad60f21f2cb61cb582b5072408a7efc91edf05b36a1a3b58fd9e6cf808d75157eedccc8f1c93a8ae07d0000000000000000000000000000000016d911943d80427385ebac1d1b293914a9e4dd9db06c1d6a758192d63c8fc9368e02eae7fb0e3a7859408f215cfa76ca0000000000000000000000000000000007bfdc6afb8acec625e50ecbc08a5cdb7862b795866323679885ba5cba3fd51f181078e03fe35e96e6383c077eed1bf5", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_14", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000130535a29392c77f045ac90e47f2e7b3cffff94494fe605aad345b41043f6663ada8e2e7ecd3d06f3b8854ef92212f42000000000000000000000000000000001699a3cc1f10cd2ed0dc68eb916b4402e4f12bf4746893bf70e26e209e605ea89e3d53e7ac52bd07713d3c8fc671931d000000000000000000000000000000000a68dccbe3452731f075580fe6102b8ee5265007ee19c56d95bcb096a3a6ac444f4145b980f41afcb0a865853b279bc600000000000000000000000000000000164767ea55a9038ac2dd254d8c8a4970dba93dacdf5416aecaa407914719cab165e7a32784b2c41652a86358737d831f000000000000000000000000000000000da9441fbc6578c85fdeca49082c9ebbf183de894d67c65158380ee56132d3cdb44b100d72b6d3b82688defb75d2aa390000000000000000000000000000000017d570e4f6e46550679d5d12c347414da207060f594620e2f8db66df8e0b06c912290b207a268e782d4b45db19a199db", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_15", - "Gas": 138000, + "Gas": 108000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd80000000000000000000000000000000000874389c02d4cf1c61bc54c4c24def11dfbe7880bc998a95e70063009451ee8226fec4b278aade3a7cea55659459f1d500000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e000000000000000000000000000000000af1a3f6396f0c983e7c2d42d489a3ae5a3ff0a553d93154f73ac770cd0af7467aa0cef79f10bbd34621b3ec9583a834000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd8000000000000000000000000000000000118cd94e36ab177de95f52f180fdbdc584b8d30436eb882980306fa0625f07a1f7ad3b4c38a921c53d14aa9a6ba5b8d600000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e000000000000000000000000000000000af1a3f6396f0c983e7c2d42d489a3ae5a3ff0a553d93154f73ac770cd0af7467aa0cef79f10bbd34621b3ec9583a834000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_16", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000043c4ff154778330b4d5457b7811b551dbbf9701b402230411c527282fb5d2ba12cb445709718d5999e79fdd74c0a67000000000000000000000000000000000013a80ede40df002b72f6b33b1f0e3862d505efbe0721dce495d18920d542c98cdd2daf5164dbd1a2fee917ba943debe0000000000000000000000000000000001c2d8d353d5983f22a5313ddd58fdc0d9c994b2915dbc87a9b65b7b98ff00b62e140a27dc322d42b3ad190c1b3728dd0000000000000000000000000000000010412f3625947b38bb380a6ed059f1677b7a7afcb91517837c563dadd0e285b95740a200ddff6570d4d92bb636b625bb0000000000000000000000000000000015f4f9a480a57bd1b2388532ab045a1ba93d2f6589a3022c585fe06a1d611165c99d70be06251812405c9c37d6e9f7730000000000000000000000000000000001a78e6c5062a6634a56e9853ff5afacb2e7cf31fd0ea5f0d8c8ac6174c88133cf2f63450ec4590544c9a0e37daac1f900000000000000000000000000000000043c4ff154778330b4d5457b7811b551dbbf9701b402230411c527282fb5d2ba12cb445709718d5999e79fdd74c0a6700000000000000000000000000000000018c690fc5571f69793ec3c82915ac9513726ec891312f4f11dd3ba0ee95cc98b50d925099b0642e58a106e8456bbcbed0000000000000000000000000000000001c2d8d353d5983f22a5313ddd58fdc0d9c994b2915dbc87a9b65b7b98ff00b62e140a27dc322d42b3ad190c1b3728dd0000000000000000000000000000000010412f3625947b38bb380a6ed059f1677b7a7afcb91517837c563dadd0e285b95740a200ddff6570d4d92bb636b625bb0000000000000000000000000000000015f4f9a480a57bd1b2388532ab045a1ba93d2f6589a3022c585fe06a1d611165c99d70be06251812405c9c37d6e9f7730000000000000000000000000000000001a78e6c5062a6634a56e9853ff5afacb2e7cf31fd0ea5f0d8c8ac6174c88133cf2f63450ec4590544c9a0e37daac1f9", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_17", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009f9a78a70b9973c43182ba54bb6e363c6984d5f7920c1d347c5ff82e6093e73f4fb5e3cd985c9ddf9af936b16200e880000000000000000000000000000000008d7489c2d78f17b2b9b1d535f21588d8761b8fb323b08fa9af8a60f39b26e98af76aa883522f21e083c8a14c2e7edb6000000000000000000000000000000000818e567aea83eaf3142984bb736b443743659626c407987b604a30c79756081fa6ae6beeb2e6c652dbfe9cf62d44e3900000000000000000000000000000000193f0317305fde1046acda2c9491e376aa67244f68ef6495845d049e1293082af91f880be935d9d8ad0e25ad918caae200000000000000000000000000000000109224b8178be58ea4e4a194ca66bef9d14f6fc2c625d25feaa4f32e0f4d72d91024d96839bc96e6a624c5ad6221bd94000000000000000000000000000000000e42decf8a987efaeb4ede37236b637e61249bf6245679be7fd4d633e2d814ed4748b73890ad3c4fcbcfb4960cb67ae70000000000000000000000000000000009f9a78a70b9973c43182ba54bb6e363c6984d5f7920c1d347c5ff82e6093e73f4fb5e3cd985c9ddf9af936b16200e88000000000000000000000000000000001129c94e0c06f51f1f808a62e42a5449dd159289c14a09c4cc382c91bcfe878b6f3555767c310de1b1c275eb3d17bcf5000000000000000000000000000000000818e567aea83eaf3142984bb736b443743659626c407987b604a30c79756081fa6ae6beeb2e6c652dbfe9cf62d44e3900000000000000000000000000000000193f0317305fde1046acda2c9491e376aa67244f68ef6495845d049e1293082af91f880be935d9d8ad0e25ad918caae200000000000000000000000000000000109224b8178be58ea4e4a194ca66bef9d14f6fc2c625d25feaa4f32e0f4d72d91024d96839bc96e6a624c5ad6221bd94000000000000000000000000000000000e42decf8a987efaeb4ede37236b637e61249bf6245679be7fd4d633e2d814ed4748b73890ad3c4fcbcfb4960cb67ae7", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_18", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010fcfe8af8403a52400bf79e1bd0058f66b9cab583afe554aa1d82a3e794fffad5f0e19d385263b2dd9ef69d1154f10a000000000000000000000000000000000aba6a0b58b49f7c6c2802afd2a5ed1320bf062c7b93135f3c0ed7a1d7b1ee27b2b986cde732a60fa585ca6ab7cc154b000000000000000000000000000000000ca0d865f8c8ce0a476f7a6edb3ce4bd5e6c3a8d905d8fb5a10e66542f4325a9963c2f8d96f804f4d295f8993b5204df0000000000000000000000000000000005a966f6254f0ef4f93f082a97abe07db56f00c2ade047d2f0027edef6f00a0dfecaa24d50faa778fa29087302211f7e00000000000000000000000000000000121c51da366557c09af1bbd927521da88dfab3e2e9a95b6effb0a968795486f281f0c887e37f51837557b9e3808987130000000000000000000000000000000001a5524975400b1e88f3fff8dd34dadf5d75564cfc0026df31ee9c2c1d48b0f69a48e1e4a48cc4b7db61f023a79157800000000000000000000000000000000010fcfe8af8403a52400bf79e1bd0058f66b9cab583afe554aa1d82a3e794fffad5f0e19d385263b2dd9ef69d1154f10a000000000000000000000000000000000f46a7dee0cb471ddef3a50670a5bfc443b8455877f1ff602b21faff1eff07fc6bf27930ca2159f01479359548339560000000000000000000000000000000000ca0d865f8c8ce0a476f7a6edb3ce4bd5e6c3a8d905d8fb5a10e66542f4325a9963c2f8d96f804f4d295f8993b5204df0000000000000000000000000000000005a966f6254f0ef4f93f082a97abe07db56f00c2ade047d2f0027edef6f00a0dfecaa24d50faa778fa29087302211f7e00000000000000000000000000000000121c51da366557c09af1bbd927521da88dfab3e2e9a95b6effb0a968795486f281f0c887e37f51837557b9e3808987130000000000000000000000000000000001a5524975400b1e88f3fff8dd34dadf5d75564cfc0026df31ee9c2c1d48b0f69a48e1e4a48cc4b7db61f023a7915780", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_19", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000013c5ebfb853f0c8741f12057b6b845c4cdbf72aecbeafc8f5b5978f186eead8685f2f3f125e536c465ade1a00f212b0900000000000000000000000000000000082543b58a13354d0cce5dc3fb1d91d1de6d5927290b2ff51e4e48f40cdf2d490730843b53a92865140153888d73d4af0000000000000000000000000000000002b51851ef3b44481d13f42e5111fa4fec04be0bf6acc7e59dec3a8c8113e5bb7b604c6dbdc5e8eddc2a1ffb81bc2baf0000000000000000000000000000000018ddb483ae75402852b7f285277ff7308ff78a3364cca8b0e0e1fa9182de275fd55c1e8ec3dbde180379c4280787ba8000000000000000000000000000000000170539890c89a4f91acd59efd413b5d1059f0c8fd8718e8f722e865dd106a4eb02e6fb0cd71b34ebc4b94375b52e4dd60000000000000000000000000000000001c2e9392f5d4b75efc5ff10fe97f37e2671cad7e4710765866e92aec99b0130e6ff1314502d069fb7b5f86bfce4300e0000000000000000000000000000000013c5ebfb853f0c8741f12057b6b845c4cdbf72aecbeafc8f5b5978f186eead8685f2f3f125e536c465ade1a00f212b090000000000000000000000000000000011dbce34af6cb14d3e4d49f2482e1b058609f25dca79e2ca48e289ace9d1c8db177b7bc35daad79aa5fdac77728bd5fc0000000000000000000000000000000002b51851ef3b44481d13f42e5111fa4fec04be0bf6acc7e59dec3a8c8113e5bb7b604c6dbdc5e8eddc2a1ffb81bc2baf0000000000000000000000000000000018ddb483ae75402852b7f285277ff7308ff78a3364cca8b0e0e1fa9182de275fd55c1e8ec3dbde180379c4280787ba8000000000000000000000000000000000170539890c89a4f91acd59efd413b5d1059f0c8fd8718e8f722e865dd106a4eb02e6fb0cd71b34ebc4b94375b52e4dd60000000000000000000000000000000001c2e9392f5d4b75efc5ff10fe97f37e2671cad7e4710765866e92aec99b0130e6ff1314502d069fb7b5f86bfce4300e", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_20", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000053a12f6a1cb64272c34e042b7922fabe879275b837ba3b116adfe1eb2a6dc1c1fa6df40c779a7cdb8ed8689b8bc5ba800000000000000000000000000000000097ec91c728ae2d290489909bbee1a30048a7fa90bcfd96fe1d9297545867cbfee0939f20f1791329460a4fe1ac719290000000000000000000000000000000011bbc566a10eadf16009c1d2655cfae6adfb0f56f5e55b31dc000414be1b4cee9a0b9f7d9eab4c6829037c327914d5640000000000000000000000000000000009b28329096d8644dfcba6e92477eafff29f7477da4581ce76d1493f03034d7f5d3acaadbe42c76a83ca51db79d456d10000000000000000000000000000000019f75a303fdede5d97f3e521b03ef6b9d7c008d770b59ce3ac38900b340895e008342701ad1b41830b9c010936f4ff1700000000000000000000000000000000161aa1853edbb56fa3bd685c9c6b88e466dfa3c4f194f6774b4d9b1f30b016993bd0d65e8e9d6dea6caa196ff735bd6700000000000000000000000000000000053a12f6a1cb64272c34e042b7922fabe879275b837ba3b116adfe1eb2a6dc1c1fa6df40c779a7cdb8ed8689b8bc5ba800000000000000000000000000000000108248cdc6f503c7bad30eac875d92a75feccbdbe7b5394f8557a92bb12a796430a2c60ca23c6ecd259e5b01e53891820000000000000000000000000000000011bbc566a10eadf16009c1d2655cfae6adfb0f56f5e55b31dc000414be1b4cee9a0b9f7d9eab4c6829037c327914d5640000000000000000000000000000000009b28329096d8644dfcba6e92477eafff29f7477da4581ce76d1493f03034d7f5d3acaadbe42c76a83ca51db79d456d10000000000000000000000000000000019f75a303fdede5d97f3e521b03ef6b9d7c008d770b59ce3ac38900b340895e008342701ad1b41830b9c010936f4ff1700000000000000000000000000000000161aa1853edbb56fa3bd685c9c6b88e466dfa3c4f194f6774b4d9b1f30b016993bd0d65e8e9d6dea6caa196ff735bd67", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_21", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001354dd8a230fde7c983dcf06fa9ac075b3ab8f56cdd9f15bf870afce2ae6e7c65ba91a1df6255b6f640bb51d7fed302500000000000000000000000000000000130f139ca118869de846d1d938521647b7d27a95b127bbc53578c7b66d88d541adb525e7028a147bf332607bd760deac000000000000000000000000000000000ae7289aa9bf20c4a9c807f2b3ac32f0db24e9a0a360c92e5ce4f8253f0e3e7853f771597c8141d705062bef12d4fea80000000000000000000000000000000001d2f610d79110f93145faad2e34f3408316b1dc3a72852e811b324577d9037035e24af25002ddd100cd9283b70ddcad0000000000000000000000000000000012947315d5c0ec670619125eed0de3dd259a008baee4379b82accf2391e70a2bdad264cda04c3bc1b5394a62559fa0ef000000000000000000000000000000001239e687c4d3417c3c9b655035f8d8a649c255f9a8e6f03b785eed0d416a1cd6ef7c8b45563acb4616af24f64dbccac4000000000000000000000000000000001354dd8a230fde7c983dcf06fa9ac075b3ab8f56cdd9f15bf870afce2ae6e7c65ba91a1df6255b6f640bb51d7fed30250000000000000000000000000000000006f1fe4d98675ffc62d4d5dd0af9968faca4d0ef425d56fa31b80aea892820e270f6da17aec9eb83c6cc9f84289ecbff000000000000000000000000000000000ae7289aa9bf20c4a9c807f2b3ac32f0db24e9a0a360c92e5ce4f8253f0e3e7853f771597c8141d705062bef12d4fea80000000000000000000000000000000001d2f610d79110f93145faad2e34f3408316b1dc3a72852e811b324577d9037035e24af25002ddd100cd9283b70ddcad0000000000000000000000000000000012947315d5c0ec670619125eed0de3dd259a008baee4379b82accf2391e70a2bdad264cda04c3bc1b5394a62559fa0ef000000000000000000000000000000001239e687c4d3417c3c9b655035f8d8a649c255f9a8e6f03b785eed0d416a1cd6ef7c8b45563acb4616af24f64dbccac4", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_22", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003f76a6dc6da31a399b93f4431bfabb3e48d86745eaa4b24d6337305006e3c7fc7bfcc85c85e2f3514cd389fec4e70580000000000000000000000000000000010e4280374c532ed0df44ac0bac82572f839afcfb8b696eea617d5bd1261288dfa90a7190200687d470992fb4827ff32000000000000000000000000000000001179ee329771b5913d07818e70f6ce5a58d74ea0b573eaa1bd3d97e45d3eeb27fcc7d37dba127af7a38354cb6ff48f7c000000000000000000000000000000000c898abe6eb76ef99f5143cfb8d840a918bcc9096ce25caa45d0bf5d20814cb01b024f1fd2cbecb6bef65d9456070dd90000000000000000000000000000000008e2a4fd746e86f90484f9b9b7b47b6afe5833762e515ccb276c554f00df88dd9aa0fb792c5f419dda0465cfed838e7c0000000000000000000000000000000012b5e6f7070c0045ade96f548ed6428c5030fa20c6f6f37a42fde9dbb5cd01def0fd8585bf8aeef913e7d42b9ef22efa0000000000000000000000000000000003f76a6dc6da31a399b93f4431bfabb3e48d86745eaa4b24d6337305006e3c7fc7bfcc85c85e2f3514cd389fec4e705800000000000000000000000000000000091ce9e6c4bab3ad3d275cf5888387646c3d9bb53ace7bd0c118fce3e44fcd96241b58e5af53978272f56d04b7d7ab79000000000000000000000000000000001179ee329771b5913d07818e70f6ce5a58d74ea0b573eaa1bd3d97e45d3eeb27fcc7d37dba127af7a38354cb6ff48f7c000000000000000000000000000000000c898abe6eb76ef99f5143cfb8d840a918bcc9096ce25caa45d0bf5d20814cb01b024f1fd2cbecb6bef65d9456070dd90000000000000000000000000000000008e2a4fd746e86f90484f9b9b7b47b6afe5833762e515ccb276c554f00df88dd9aa0fb792c5f419dda0465cfed838e7c0000000000000000000000000000000012b5e6f7070c0045ade96f548ed6428c5030fa20c6f6f37a42fde9dbb5cd01def0fd8585bf8aeef913e7d42b9ef22efa", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_23", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009439f061c7d5fada6e5431c77fd093222285c98449951f6a6c4c8f225b316144875bc764be5ca51c7895773a9f1a640000000000000000000000000000000000ebdef273e2288c784c061bef6a45cd49b0306ac1e9faab263c6ff73dea4627189c8f10a823253d86a8752769cc4f8f2000000000000000000000000000000000fe2e61bc8e9085d2b472a6791d4851762d6401fd3e7d3f3ba61620dc70b773f2102df1c9d6f1462144662fb2f15359700000000000000000000000000000000031f160cde626ca11f67613884a977fb5d3248d78ddbf23e50e52c3ba4090268c1f6cd8156fa41d848a482a0ca39eb04000000000000000000000000000000000eb61ba51124be7f3ee9be1488aa83cbd2333aa7e09ae67fef63c890534cb37ca7de3d16046b984e72db21e1f5c57a8a0000000000000000000000000000000006bf6f5d65aa7d19613141018ac8bf5d1e6fe494a9f30da215a2313a0241779006bce33a776aeedae5de5ea6ee5a9b9e0000000000000000000000000000000009439f061c7d5fada6e5431c77fd093222285c98449951f6a6c4c8f225b316144875bc764be5ca51c7895773a9f1a640000000000000000000000000000000000b4322c2fb5d5dd2c65b45f74ca75002c97444d8d4e5680d0369d32d180c93b294e30ef42f21ac274f77ad89633ab1b9000000000000000000000000000000000fe2e61bc8e9085d2b472a6791d4851762d6401fd3e7d3f3ba61620dc70b773f2102df1c9d6f1462144662fb2f15359700000000000000000000000000000000031f160cde626ca11f67613884a977fb5d3248d78ddbf23e50e52c3ba4090268c1f6cd8156fa41d848a482a0ca39eb04000000000000000000000000000000000eb61ba51124be7f3ee9be1488aa83cbd2333aa7e09ae67fef63c890534cb37ca7de3d16046b984e72db21e1f5c57a8a0000000000000000000000000000000006bf6f5d65aa7d19613141018ac8bf5d1e6fe494a9f30da215a2313a0241779006bce33a776aeedae5de5ea6ee5a9b9e", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_24", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001478ee0ffebf22708a6ab88855081daba5ee2f279b5a2ee5f5f8aec8f97649c8d5634fec3f8b28ad60981e6f29a091b10000000000000000000000000000000011efaeec0b1a4057b1e0053263afe40158790229c5bfb08062c90a252f59eca36085ab35e4cbc70483d29880c5c2f8c200000000000000000000000000000000196044a5cdbc5300ee837dca745a44379070e9297697f5db28df4a37307cc740abed45cc778a3f4e3b8c9890ab6c3c70000000000000000000000000000000001176f5de6a3577ad67863bd3d9152ab9e8184964c6ac276e95946788f5a76394047580077c0971d874a40d510eb0443e00000000000000000000000000000000147dd55dff69213c5760e8d22b700dd7a9c7c33c434a3be95bd5281b97b464fb934a3dff7c23f3e59c5d8d26faa426bf0000000000000000000000000000000019efcf03ddb0934b0f0dba3569809d5b48b863d50d3be4973b504244414e1e1db56adff51d33265ce102b320c552781f000000000000000000000000000000001478ee0ffebf22708a6ab88855081daba5ee2f279b5a2ee5f5f8aec8f97649c8d5634fec3f8b28ad60981e6f29a091b100000000000000000000000000000000081162fe2e65a642993ba283df9bc8d60bfe495b2dc5623f0467c87bc7570980be2654c8cc8838fb362c677f3a3cb1e900000000000000000000000000000000196044a5cdbc5300ee837dca745a44379070e9297697f5db28df4a37307cc740abed45cc778a3f4e3b8c9890ab6c3c70000000000000000000000000000000001176f5de6a3577ad67863bd3d9152ab9e8184964c6ac276e95946788f5a76394047580077c0971d874a40d510eb0443e00000000000000000000000000000000147dd55dff69213c5760e8d22b700dd7a9c7c33c434a3be95bd5281b97b464fb934a3dff7c23f3e59c5d8d26faa426bf0000000000000000000000000000000019efcf03ddb0934b0f0dba3569809d5b48b863d50d3be4973b504244414e1e1db56adff51d33265ce102b320c552781f", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_25", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000150d43c64cb1dbb7b981f455e90b740918e2d63453ca17d8eeecb68e662d2581f8aa1aea5b095cd8fc2a941d6e2728390000000000000000000000000000000006dc2ccb10213d3f6c3f10856888cb2bf6f1c7fcb2a17d6e63596c29281682cafd4c72696ecd6af3cce31c440144ebd10000000000000000000000000000000005d8edbabf37a47a539d84393bb2747d0a35a52b80a7c99616c910479306e204e5db1f0fa3fe69f35af3164c7e5726b50000000000000000000000000000000005015082d6975649fbc172035da04f8aeb6d0dd88fdfac3fbd68ec925dc199413ed670488dc6588f9bd34c4ff527f149000000000000000000000000000000001312d53088ca58dfc325772b8dc0e1b20cebf7b2d5b6b4c560759987b44060bf4a59a68d1a5623bbb3cc5b0bc3986b810000000000000000000000000000000012110cd462c6fabf04f67d652639d19640c46f51aadd6c4f9a6dd7806cffb6192d95c198f4c8284151feaa2e2a0dbc1f00000000000000000000000000000000150d43c64cb1dbb7b981f455e90b740918e2d63453ca17d8eeecb68e662d2581f8aa1aea5b095cd8fc2a941d6e272839000000000000000000000000000000001324e51f295ea95adedc9730dac2e1ab6d85838840e3955103d76677ce9a7359215f8d954286950bed1be3bbfebabeda0000000000000000000000000000000005d8edbabf37a47a539d84393bb2747d0a35a52b80a7c99616c910479306e204e5db1f0fa3fe69f35af3164c7e5726b50000000000000000000000000000000005015082d6975649fbc172035da04f8aeb6d0dd88fdfac3fbd68ec925dc199413ed670488dc6588f9bd34c4ff527f149000000000000000000000000000000001312d53088ca58dfc325772b8dc0e1b20cebf7b2d5b6b4c560759987b44060bf4a59a68d1a5623bbb3cc5b0bc3986b810000000000000000000000000000000012110cd462c6fabf04f67d652639d19640c46f51aadd6c4f9a6dd7806cffb6192d95c198f4c8284151feaa2e2a0dbc1f", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_26", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f46bb86e827aa9c0c570d93f4d7d6986668c0099e4853927571199e1ce9e756d9db951f5b0325acafb2bf6e8fec2a1b0000000000000000000000000000000006d38cc6cc1a950a18e92e16287f201af4c014aba1a17929dd407d0440924ce5f08fad8fe0c50f7f733b285bf282acfc00000000000000000000000000000000117fd5016ddb779a6979d2bffe18032d9a5cdc5a6c7feeaa412381983d49ab894cb067f671163ccbe6225c3d85219db6000000000000000000000000000000000dcf01077dcce35c283bea662f4e4d16f871717eb78e630d9f95a200cc104fe67b0d69d95f6704d9812b46c92b1bc9de00000000000000000000000000000000121f212cd7251697ef6a7e3aa93eb0d7d0157cf1247d4411430c36c7277bf8acfccc4ed8590b5e8d0f760e0e4ed7e95a0000000000000000000000000000000007d22d78b486f575e01e21e1239cbedc4628ba7e01ecf4a3459bd78a9716e2969f26ea3f2449685f60397e1ab2aa7352000000000000000000000000000000000f46bb86e827aa9c0c570d93f4d7d6986668c0099e4853927571199e1ce9e756d9db951f5b0325acafb2bf6e8fec2a1b00000000000000000000000000000000132d85236d655190323279a01acc8cbc6fb736d951e3999589f0559cb61ea93e2e1c526ed08ef08046c3d7a40d7cfdaf00000000000000000000000000000000117fd5016ddb779a6979d2bffe18032d9a5cdc5a6c7feeaa412381983d49ab894cb067f671163ccbe6225c3d85219db6000000000000000000000000000000000dcf01077dcce35c283bea662f4e4d16f871717eb78e630d9f95a200cc104fe67b0d69d95f6704d9812b46c92b1bc9de00000000000000000000000000000000121f212cd7251697ef6a7e3aa93eb0d7d0157cf1247d4411430c36c7277bf8acfccc4ed8590b5e8d0f760e0e4ed7e95a0000000000000000000000000000000007d22d78b486f575e01e21e1239cbedc4628ba7e01ecf4a3459bd78a9716e2969f26ea3f2449685f60397e1ab2aa7352", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_27", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010cde0dbf4e18009c94ba648477624bbfb3732481d21663dd13cea914d6c54ec060557010ebe333d5e4b266e1563c631000000000000000000000000000000000fb24d3d4063fd054cd5b7288498f107114ff323226aca58d3336444fc79c010db15094ceda6eb99770c168d459f0da0000000000000000000000000000000000224cbea61c5136987d8dbc8deafa78ae002255c031bb54335bcf99e56a57768aa127506fca1761e8b835e67e88bb4dd0000000000000000000000000000000018cbf072b544df760c051d394ff68ad2dd5a8c731377fa2a5f61e61481ad5b42645704a2d083c7d45ed4774e5448141e000000000000000000000000000000000740b8b7d7bce78a51809713656c94cf98de72887676050f65f74c57cbe574278dd3634c44e057ea95babcc3d230e3c40000000000000000000000000000000006696058a191c7012a4ee7c973c2005ac51af02a85cbb60e3164809a583b4431dda2b59e1c9ceeb652b3ac7021d116a60000000000000000000000000000000010cde0dbf4e18009c94ba648477624bbfb3732481d21663dd13cea914d6c54ec060557010ebe333d5e4b266e1563c631000000000000000000000000000000000a4ec4acf91be994fe45f08dbeb2bbd053275861d11a486693fd6e5bfa3736134396f6b1c3ad146642f2e972ba609d0b000000000000000000000000000000000224cbea61c5136987d8dbc8deafa78ae002255c031bb54335bcf99e56a57768aa127506fca1761e8b835e67e88bb4dd0000000000000000000000000000000018cbf072b544df760c051d394ff68ad2dd5a8c731377fa2a5f61e61481ad5b42645704a2d083c7d45ed4774e5448141e000000000000000000000000000000000740b8b7d7bce78a51809713656c94cf98de72887676050f65f74c57cbe574278dd3634c44e057ea95babcc3d230e3c40000000000000000000000000000000006696058a191c7012a4ee7c973c2005ac51af02a85cbb60e3164809a583b4431dda2b59e1c9ceeb652b3ac7021d116a6", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_28", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008c0a4c543b7506e9718658902982b4ab7926cd90d4986eceb17b149d8f5122334903300ad419b90c2cb56dc6d2fe976000000000000000000000000000000000824e1631f054b666893784b1e7edb44b9a53596f718a6e5ba606dc1020cb6e269e9edf828de1768df0dd8ab8440e053000000000000000000000000000000001522e0a4ccd607f117fc6fc8f9abcd704e9850d96adb95d9bfaab210b76bfb2c5dc75163b922bd7a886541250bc1d8630000000000000000000000000000000018a6e4327d633108a292a51abed43e95230e951e4476dc385ceea9c72ed528bf3e06c42d10cefbd4aa75b134936e4747000000000000000000000000000000001198587188e793ad2ec2fa0fa1d0da9b61ed48444fe6722e523aeac270f17f73f56b1e726ab811bb54a6e42e506d70a20000000000000000000000000000000004bedd94182e0f16c71223ac3d68ab327d28ee0ccdcd2c2db07faf69e1babe3fbf3ba09c28b146eca7ab047b592947030000000000000000000000000000000008c0a4c543b7506e9718658902982b4ab7926cd90d4986eceb17b149d8f5122334903300ad419b90c2cb56dc6d2fe9760000000000000000000000000000000011dc30871a7a9b33e2882f6b24ccd192aad215edfc6c6bd9acd064dff4a43f41b4c212068875e896daf127547bbeca58000000000000000000000000000000001522e0a4ccd607f117fc6fc8f9abcd704e9850d96adb95d9bfaab210b76bfb2c5dc75163b922bd7a886541250bc1d8630000000000000000000000000000000018a6e4327d633108a292a51abed43e95230e951e4476dc385ceea9c72ed528bf3e06c42d10cefbd4aa75b134936e4747000000000000000000000000000000001198587188e793ad2ec2fa0fa1d0da9b61ed48444fe6722e523aeac270f17f73f56b1e726ab811bb54a6e42e506d70a20000000000000000000000000000000004bedd94182e0f16c71223ac3d68ab327d28ee0ccdcd2c2db07faf69e1babe3fbf3ba09c28b146eca7ab047b59294703", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_29", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000159d94fb0cf6f4e3e26bdeb536d1ee9c511a29d32944da43420e86c3b5818e0f482a7a8af72880d4825a50fee6bc8cd8000000000000000000000000000000000c2ffe6be05eccd9170b6c181966bb8c1c3ed10e763613112238cabb41370e2a5bb5fef967f4f8f2af944dbef09d265e00000000000000000000000000000000148b7dfc21521d79ff817c7a0305f1048851e283be13c07d5c04d28b571d48172838399ba539529e8d037ffd1f7295580000000000000000000000000000000003015abea326c15098f5205a8b2d3cd74d72dac59d60671ca6ef8c9c714ea61ffdacd46d1024b5b4f7e6b3b569fabaf20000000000000000000000000000000011f0c512fe7dc2dd8abdc1d22c2ecd2e7d1b84f8950ab90fc93bf54badf7bb9a9bad8c355d52a5efb110dca891e4cc3d0000000000000000000000000000000019774010814d1d94caf3ecda3ef4f5c5986e966eaf187c32a8a5a4a59452af0849690cf71338193f2d8435819160bcfb00000000000000000000000000000000159d94fb0cf6f4e3e26bdeb536d1ee9c511a29d32944da43420e86c3b5818e0f482a7a8af72880d4825a50fee6bc8cd8000000000000000000000000000000000dd1137e592119c134103b9e29e4f14b48387a767d4effae44f807e5b579e7f9c2f60105495f070d0a6ab2410f62844d00000000000000000000000000000000148b7dfc21521d79ff817c7a0305f1048851e283be13c07d5c04d28b571d48172838399ba539529e8d037ffd1f7295580000000000000000000000000000000003015abea326c15098f5205a8b2d3cd74d72dac59d60671ca6ef8c9c714ea61ffdacd46d1024b5b4f7e6b3b569fabaf20000000000000000000000000000000011f0c512fe7dc2dd8abdc1d22c2ecd2e7d1b84f8950ab90fc93bf54badf7bb9a9bad8c355d52a5efb110dca891e4cc3d0000000000000000000000000000000019774010814d1d94caf3ecda3ef4f5c5986e966eaf187c32a8a5a4a59452af0849690cf71338193f2d8435819160bcfb", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_30", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000019c822a4d44ac22f6fbaef356c37ceff93c1d6933e8c8f3b55784cfe62e5705930be48607c3f7a4a2ca146945cad6242000000000000000000000000000000000353d6521a17474856ad69582ce225f27d60f5a8319bea8cefded2c3f6b862d76fe633c77ed8ccdf99d2b10430253fc8000000000000000000000000000000000805892f21889cab3cfe62226eaff6a8d3586d4396692b379efc7e90b0eaad4c9afbdf0f56b30f0c07ae0bc4013343b30000000000000000000000000000000007853f0e75c8dee034c2444299da58c98f22de367a90550dbc635fb52c9a8f61ccc100f70f10208944e48d09507fdce100000000000000000000000000000000064afd6b3ef7ff7ec34f1fa330877b42958a46a7698c6d21adf73bfdfcab7793b312e21e5988652e655f2d42edb8a673000000000000000000000000000000000ea8a2217c3dbcc0f6e562de9cb2f334c896577d0b3a7108d96b1aba2d705dbf531e870d4023cec2c0533455013242330000000000000000000000000000000019c822a4d44ac22f6fbaef356c37ceff93c1d6933e8c8f3b55784cfe62e5705930be48607c3f7a4a2ca146945cad62420000000000000000000000000000000016ad3b981f689f51f46e3e5e166986e4e71655dcc1e928327751ffdcfff8934caec5cc37327b3320202c4efbcfda6ae3000000000000000000000000000000000805892f21889cab3cfe62226eaff6a8d3586d4396692b379efc7e90b0eaad4c9afbdf0f56b30f0c07ae0bc4013343b30000000000000000000000000000000007853f0e75c8dee034c2444299da58c98f22de367a90550dbc635fb52c9a8f61ccc100f70f10208944e48d09507fdce100000000000000000000000000000000064afd6b3ef7ff7ec34f1fa330877b42958a46a7698c6d21adf73bfdfcab7793b312e21e5988652e655f2d42edb8a673000000000000000000000000000000000ea8a2217c3dbcc0f6e562de9cb2f334c896577d0b3a7108d96b1aba2d705dbf531e870d4023cec2c053345501324233", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_31", - "Gas": 161000, + "Gas": 151000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000189bf269a72de2872706983835afcbd09f6f4dfcabe0241b4e9fe1965a250d230d6f793ab17ce7cac456af7be4376be6000000000000000000000000000000000d4441801d287ba8de0e2fb6b77f766dbff07b4027098ce463cab80e01eb31d9f5dbd7ac935703d68c7032fa5128ff170000000000000000000000000000000011798ea9c137acf6ef9483b489c0273d4f69296959922a352b079857953263372b8d339115f0576cfabedc185abf2086000000000000000000000000000000001498b1412f52b07a0e4f91cbf5e1852ea38fc111613523f1e61b97ebf1fd7fd2cdf36d7f73f1e33719c0b63d7bf66b8f0000000000000000000000000000000004c56d3ee9931f7582d7eebeb598d1be208e3b333ab976dc7bb271969fa1d6caf8f467eb7cbee4af5d30e5c66d00a4e2000000000000000000000000000000000de29857dae126c0acbe966da6f50342837ef5dd9994ad929d75814f6f33f77e5b33690945bf6e980031ddd90ebc76ce00000000000000000000000000000000189bf269a72de2872706983835afcbd09f6f4dfcabe0241b4e9fe1965a250d230d6f793ab17ce7cac456af7be4376be6000000000000000000000000000000000cbcd06a1c576af16d0d77ff8bcc3669a486d044cc7b85db03661a92f4c5c44a28d028521dfcfc292d8ecd05aed6ab940000000000000000000000000000000011798ea9c137acf6ef9483b489c0273d4f69296959922a352b079857953263372b8d339115f0576cfabedc185abf2086000000000000000000000000000000001498b1412f52b07a0e4f91cbf5e1852ea38fc111613523f1e61b97ebf1fd7fd2cdf36d7f73f1e33719c0b63d7bf66b8f0000000000000000000000000000000004c56d3ee9931f7582d7eebeb598d1be208e3b333ab976dc7bb271969fa1d6caf8f467eb7cbee4af5d30e5c66d00a4e2000000000000000000000000000000000de29857dae126c0acbe966da6f50342837ef5dd9994ad929d75814f6f33f77e5b33690945bf6e980031ddd90ebc76ce00000000000000000000000000000000189bf269a72de2872706983835afcbd09f6f4dfcabe0241b4e9fe1965a250d230d6f793ab17ce7cac456af7be4376be6000000000000000000000000000000000d4441801d287ba8de0e2fb6b77f766dbff07b4027098ce463cab80e01eb31d9f5dbd7ac935703d68c7032fa5128ff170000000000000000000000000000000011798ea9c137acf6ef9483b489c0273d4f69296959922a352b079857953263372b8d339115f0576cfabedc185abf2086000000000000000000000000000000001498b1412f52b07a0e4f91cbf5e1852ea38fc111613523f1e61b97ebf1fd7fd2cdf36d7f73f1e33719c0b63d7bf66b8f00000000000000000000000000000000153ba4ab4fecc724c843b8f78db2db1943e91051b8cb9be2eb7e610a570f1f5925b7981334951b505cce1a3992ff05c9000000000000000000000000000000000c1e79925e9ebfd99e5d11489c56a994e0f855a759f0652cc9bb5151877cfea5c37896f56b949167b9cd2226f14333dd", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_32", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000003299542a0c40efbb55d169a92ad11b4d6d7a6ed949cb0d6477803fbedcf74e4bd74de854c4c8b7f200c85c8129292540000000000000000000000000000000013a3d49e58274c2b4a534b95b7071b6d2f42b17b887bf128627c0f8894c19d3d69c1a419373ca4bd1bb6d4efc78e1d3f000000000000000000000000000000001755d8a095e087ca66f8a118e0d2c7d5e4d8427dda8fe3049080f4aff12a8746f8c2679c310f4be0d94c5bef0414a7a600000000000000000000000000000000069c84c6419ed5c0441975ee8410065a56c65f07a4b545ff596b657dc4620c7405fd4d092b281e272773d2281a6359a8000000000000000000000000000000000e751ccbd475fe7eda1c62df626c1d37e8ae6853cc9b2109beef3e8c6f26d41a5e4e0a91bbc3371c7ab6ba780b5db41600000000000000000000000000000000184097644c9b44d543ebc0934825610590cc9f8b17ed08e9c06592bf85591d2702b18cf48a70b378926057e541eb8ac50000000000000000000000000000000003299542a0c40efbb55d169a92ad11b4d6d7a6ed949cb0d6477803fbedcf74e4bd74de854c4c8b7f200c85c81292925400000000000000000000000000000000065d3d4be1589a6f00c85c208c44916a35349a096b09219704b4c31861ef58e6b4ea5be57a175b429e482b1038718d6c000000000000000000000000000000001755d8a095e087ca66f8a118e0d2c7d5e4d8427dda8fe3049080f4aff12a8746f8c2679c310f4be0d94c5bef0414a7a600000000000000000000000000000000069c84c6419ed5c0441975ee8410065a56c65f07a4b545ff596b657dc4620c7405fd4d092b281e272773d2281a6359a8000000000000000000000000000000000e751ccbd475fe7eda1c62df626c1d37e8ae6853cc9b2109beef3e8c6f26d41a5e4e0a91bbc3371c7ab6ba780b5db41600000000000000000000000000000000184097644c9b44d543ebc0934825610590cc9f8b17ed08e9c06592bf85591d2702b18cf48a70b378926057e541eb8ac50000000000000000000000000000000003299542a0c40efbb55d169a92ad11b4d6d7a6ed949cb0d6477803fbedcf74e4bd74de854c4c8b7f200c85c8129292540000000000000000000000000000000013a3d49e58274c2b4a534b95b7071b6d2f42b17b887bf128627c0f8894c19d3d69c1a419373ca4bd1bb6d4efc78e1d3f000000000000000000000000000000001755d8a095e087ca66f8a118e0d2c7d5e4d8427dda8fe3049080f4aff12a8746f8c2679c310f4be0d94c5bef0414a7a600000000000000000000000000000000069c84c6419ed5c0441975ee8410065a56c65f07a4b545ff596b657dc4620c7405fd4d092b281e272773d2281a6359a8000000000000000000000000000000000b8bf51e6509e81b70ff44d6e0df8f9f7bc8e33126e9f1b5a8419414878a2209c05df56cf590c8e33f484587f4a1f6950000000000000000000000000000000001c07a85ece4a1c5072fe722fb264bd1d3aaabf9db9809d5a6cb3fe17157d8fd1bfa730a26e34c87279ea81abe141fe6", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_33", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000121b540a0465b39f2f093112c20a9822fc82497105778937c9d5cdcfe039d62998d47d4f41c76482c31f39a79352beda0000000000000000000000000000000014a461f829e0a76ba89f42eb57dffb4f5544df2008163bd0ea1af824f7ff910b27418a0e4f86cb8046dc1f3139cab9af000000000000000000000000000000000213e5d2d46523203ae07f36fdeb6c304fb86f552fb9adb566711c31262629efb0b1561585f85d2ac7be174682229bd8000000000000000000000000000000000b3336b5a4f7c0d16db9615e77bcdd55b7cb5b5c1591d835f34f5c1f1468e3cef954608667fb97a32e4595f43b845612000000000000000000000000000000001869606dde1688e5ae9f1c466c5897fce7794f3735234b5af1ad3617f0688529499bbdc9f0b911840a3d99fd9c49150d00000000000000000000000000000000001bfd33df4a6059608ada794e03d7456e78317145eb4d5677c00d482ac4cf470053d33583cf602feb67b6f972c9973900000000000000000000000000000000121b540a0465b39f2f093112c20a9822fc82497105778937c9d5cdcfe039d62998d47d4f41c76482c31f39a79352beda00000000000000000000000000000000055caff20f9f3f2ea27c64caeb6bb1880f326c64eb6ed6ee7d15da7bfeb16518f76a75f061cd347f7322e0cec634f0fc000000000000000000000000000000000213e5d2d46523203ae07f36fdeb6c304fb86f552fb9adb566711c31262629efb0b1561585f85d2ac7be174682229bd8000000000000000000000000000000000b3336b5a4f7c0d16db9615e77bcdd55b7cb5b5c1591d835f34f5c1f1468e3cef954608667fb97a32e4595f43b845612000000000000000000000000000000001869606dde1688e5ae9f1c466c5897fce7794f3735234b5af1ad3617f0688529499bbdc9f0b911840a3d99fd9c49150d00000000000000000000000000000000001bfd33df4a6059608ada794e03d7456e78317145eb4d5677c00d482ac4cf470053d33583cf602feb67b6f972c9973900000000000000000000000000000000121b540a0465b39f2f093112c20a9822fc82497105778937c9d5cdcfe039d62998d47d4f41c76482c31f39a79352beda0000000000000000000000000000000014a461f829e0a76ba89f42eb57dffb4f5544df2008163bd0ea1af824f7ff910b27418a0e4f86cb8046dc1f3139cab9af000000000000000000000000000000000213e5d2d46523203ae07f36fdeb6c304fb86f552fb9adb566711c31262629efb0b1561585f85d2ac7be174682229bd8000000000000000000000000000000000b3336b5a4f7c0d16db9615e77bcdd55b7cb5b5c1591d835f34f5c1f1468e3cef954608667fb97a32e4595f43b845612000000000000000000000000000000000197b17c5b695db49c7c8b6fd6f314da7cfdfc4dbe61c76475839c89064870fad5104234c09aee7bafc1660263b6959e0000000000000000000000000000000019e514b65a358640ea90cd3cf547d591f5ff1a13ad99c568ef70c558cbec26dd1e582cc92d849fcfce9749068d361372", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_34", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001383bc4d6c748d5c76ab4ba04f8fcd4c0fed9a49ea080c548893440819833ad72a8249f77391d5fbff78329eb319d3830000000000000000000000000000000016404bd07b6c6480af2d23301940e61817ee2e61fc625c100b31e1b324c369a583b61048dd57ab97b80b1fe6cd64c5c30000000000000000000000000000000004ac6e6077d4eddd0e23f30cfd64b7aa1525c85424224e70c15d7535e02aea7a312ef24ba2dcf70b926acb851da2530c0000000000000000000000000000000006ad07d3e8f45cedfb4279913bf0a29e37604810463d6020b4fa8c8c4977d69cffaa33e1149706f04eb237194dcafa520000000000000000000000000000000002c536dd2f05f4a7eaa33fd884262b22a2ab2a88e7b63cb08ebb67fc0f143da7d6b18dd394c424161f7cf703acdc82f50000000000000000000000000000000002d1d9ff74e20ea9b03c478784f57e7a58a21ca2b1e552319f33305f367f5ae4daf8138505f953db4f86c0ec1d96d5f0000000000000000000000000000000001383bc4d6c748d5c76ab4ba04f8fcd4c0fed9a49ea080c548893440819833ad72a8249f77391d5fbff78329eb319d3830000000000000000000000000000000003c0c619be1382199bee84862a0ac6bf4c891d22f722b6af5bfef0edd1ed8c7e9af5efb5d3fc546801f3e019329ae4e80000000000000000000000000000000004ac6e6077d4eddd0e23f30cfd64b7aa1525c85424224e70c15d7535e02aea7a312ef24ba2dcf70b926acb851da2530c0000000000000000000000000000000006ad07d3e8f45cedfb4279913bf0a29e37604810463d6020b4fa8c8c4977d69cffaa33e1149706f04eb237194dcafa520000000000000000000000000000000002c536dd2f05f4a7eaa33fd884262b22a2ab2a88e7b63cb08ebb67fc0f143da7d6b18dd394c424161f7cf703acdc82f50000000000000000000000000000000002d1d9ff74e20ea9b03c478784f57e7a58a21ca2b1e552319f33305f367f5ae4daf8138505f953db4f86c0ec1d96d5f0000000000000000000000000000000001383bc4d6c748d5c76ab4ba04f8fcd4c0fed9a49ea080c548893440819833ad72a8249f77391d5fbff78329eb319d3830000000000000000000000000000000016404bd07b6c6480af2d23301940e61817ee2e61fc625c100b31e1b324c369a583b61048dd57ab97b80b1fe6cd64c5c30000000000000000000000000000000004ac6e6077d4eddd0e23f30cfd64b7aa1525c85424224e70c15d7535e02aea7a312ef24ba2dcf70b926acb851da2530c0000000000000000000000000000000006ad07d3e8f45cedfb4279913bf0a29e37604810463d6020b4fa8c8c4977d69cffaa33e1149706f04eb237194dcafa5200000000000000000000000000000000173bdb0d0a79f1f2607867ddbf2581b4c1cc20fc0bced60ed8756aa4e79cb87c47fa722b1c8fdbe99a8208fc532327b600000000000000000000000000000000172f37eac49dd7f09adf602ebe562e5d0bd52ee2419fc08dc7fda241c0319b3f43b3ec79ab5aac246a783f13e268d4bb", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_35", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006bc68c6510c15a5d7bc6eebce04f7c5fce3bb02f9f89ea14ab0dfb43645b6346af7e25a8e044e842b7a3d06fe9b1a0300000000000000000000000000000000053ee41f6a51c49b069f12de32e3e6b0b355cd2c3ba87a149c7de86136a5d9c5b7b59f2d1237964e548d1b62ec36c8db000000000000000000000000000000001913ce14bcd1d7bbb47f8efd92d7ffd155ed1990a1dbf1ee7d5e6d592a92bcbec6e865199362950afd6c8fc49b3e10a400000000000000000000000000000000020df729079e76cf06f84e3355e683e093dafad38c2ba92cf7a9faa0515f2f44d814f971046ea20116cc4b0014d7ec350000000000000000000000000000000018db123e05404eea8707f9356f417c3966312b9e41765a6fd8449879ddc4c9850c38434481b235a5bc35db1b8ee86d43000000000000000000000000000000000b4162715717e9065a3849a9294cfe39b351e57ab5a6790f3e725ad9fbf0e4b9d6a3554e872af9c37df33bb896dada5c0000000000000000000000000000000006bc68c6510c15a5d7bc6eebce04f7c5fce3bb02f9f89ea14ab0dfb43645b6346af7e25a8e044e842b7a3d06fe9b1a030000000000000000000000000000000014c22dcacf2e21ff447c94d81067c626b1217e58b7dc98aacab2ea3fc00b1c5e66f660d19f1c69b16571e49d13c8e1d0000000000000000000000000000000001913ce14bcd1d7bbb47f8efd92d7ffd155ed1990a1dbf1ee7d5e6d592a92bcbec6e865199362950afd6c8fc49b3e10a400000000000000000000000000000000020df729079e76cf06f84e3355e683e093dafad38c2ba92cf7a9faa0515f2f44d814f971046ea20116cc4b0014d7ec350000000000000000000000000000000018db123e05404eea8707f9356f417c3966312b9e41765a6fd8449879ddc4c9850c38434481b235a5bc35db1b8ee86d43000000000000000000000000000000000b4162715717e9065a3849a9294cfe39b351e57ab5a6790f3e725ad9fbf0e4b9d6a3554e872af9c37df33bb896dada5c0000000000000000000000000000000006bc68c6510c15a5d7bc6eebce04f7c5fce3bb02f9f89ea14ab0dfb43645b6346af7e25a8e044e842b7a3d06fe9b1a0300000000000000000000000000000000053ee41f6a51c49b069f12de32e3e6b0b355cd2c3ba87a149c7de86136a5d9c5b7b59f2d1237964e548d1b62ec36c8db000000000000000000000000000000001913ce14bcd1d7bbb47f8efd92d7ffd155ed1990a1dbf1ee7d5e6d592a92bcbec6e865199362950afd6c8fc49b3e10a400000000000000000000000000000000020df729079e76cf06f84e3355e683e093dafad38c2ba92cf7a9faa0515f2f44d814f971046ea20116cc4b0014d7ec35000000000000000000000000000000000125ffac343f97afc413ae80d40a309dfe461fe6b20eb84f8eec3a2718ec2c9f1273bcba2fa1ca59fdc924e471173d68000000000000000000000000000000000ebfaf78e267fd93f0e35e0d19feae9db125660a3dde99b028be77c6fac0116a4808aab02a29063c3c0bc4476924d04f", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_36", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000024ca57c2dc2a7deec3082f2f2110b6788c57a8cdc43515044d275fe7d6f20540055bde823b7b091134fb811d23468ce0000000000000000000000000000000009cd91a281b96a881b20946fda164a987243c052378fcd8fee3926b75576dfa1d29a0aaca4b653da4e61da82577218080000000000000000000000000000000008be924b49e05c45419e328340f1cbcdd3350bacf832a372417d8331c942df200493a3f7f2e46ad2cdaf3544cfd8cd8600000000000000000000000000000000028cd100457f4e930fc0f55996a6b588c5361816bb853d1f522806e5ec1c455eb200343476feeb07ca77e961fc2adc1f000000000000000000000000000000000f6adad0a3bab3610165be2fadb1b020f25488a0af3d418b7d7cf1165812e17aefcbc23308ebcd31d22ba4ca5773dd87000000000000000000000000000000001657ff792e3d89d5d35767bd0cc788411b0420665a5e0704f4d2399b9d9a5ad3c027ee030fdf495e5a6e2a4c69d0571200000000000000000000000000000000024ca57c2dc2a7deec3082f2f2110b6788c57a8cdc43515044d275fe7d6f20540055bde823b7b091134fb811d23468ce0000000000000000000000000000000010338047b7c67c122ffb13466935623ef2338b32bbf5452f78f7abe9a13a16824c11f5520c9dac256b9d257da88d92a30000000000000000000000000000000008be924b49e05c45419e328340f1cbcdd3350bacf832a372417d8331c942df200493a3f7f2e46ad2cdaf3544cfd8cd8600000000000000000000000000000000028cd100457f4e930fc0f55996a6b588c5361816bb853d1f522806e5ec1c455eb200343476feeb07ca77e961fc2adc1f000000000000000000000000000000000f6adad0a3bab3610165be2fadb1b020f25488a0af3d418b7d7cf1165812e17aefcbc23308ebcd31d22ba4ca5773dd87000000000000000000000000000000001657ff792e3d89d5d35767bd0cc788411b0420665a5e0704f4d2399b9d9a5ad3c027ee030fdf495e5a6e2a4c69d0571200000000000000000000000000000000024ca57c2dc2a7deec3082f2f2110b6788c57a8cdc43515044d275fe7d6f20540055bde823b7b091134fb811d23468ce0000000000000000000000000000000009cd91a281b96a881b20946fda164a987243c052378fcd8fee3926b75576dfa1d29a0aaca4b653da4e61da82577218080000000000000000000000000000000008be924b49e05c45419e328340f1cbcdd3350bacf832a372417d8331c942df200493a3f7f2e46ad2cdaf3544cfd8cd8600000000000000000000000000000000028cd100457f4e930fc0f55996a6b588c5361816bb853d1f522806e5ec1c455eb200343476feeb07ca77e961fc2adc1f000000000000000000000000000000000a96371995c5333949b5e9869599fcb67222c2e44447d133e9b3e18a9e9e14a92ee03dcba86832cde7d35b35a88bcd240000000000000000000000000000000003a912710b425cc477c43ff93684249649732b1e99270bba725e990559169b505e8411fba174b6a15f90d5b3962f5399", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_37", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001305e1b9706c7fc132aea63f0926146557d4dd081b7a2913dae02bab75b0409a515d0f25ffa3eda81cf4764de15741f60000000000000000000000000000000011bf87b12734a6360d3dda4b452deede34470fba8e62a68f79153cc288a8e7fed98c74af862883b9861d2195a58262e0000000000000000000000000000000000a5048d860b997a9fb352e58284ebbc026622d9be73de79b2807a0c9b431f41f379c255a2db0dd67413c18217cb21b7200000000000000000000000000000000045a701a3f46ca801c02a5419c836b2ab3d74ebd6f4fd1e7dddb1965b49c9a278f6e89950e7c35ebc6724569d34e364c0000000000000000000000000000000004cb55008ccb5b2b8ece69fac7283f5a9ef9e622e2a0e42bed5bdd77faa550882643afc1759b1a327c4f2277e13a3d4f000000000000000000000000000000001690dee40c6c824dc2588fc47dbf93f68ac250b9357e1112db72ded905ed7b101b5f877bdc42d56afb5b6202403a91c4000000000000000000000000000000001305e1b9706c7fc132aea63f0926146557d4dd081b7a2913dae02bab75b0409a515d0f25ffa3eda81cf4764de15741f60000000000000000000000000000000008418a39124b40643dddcd6afe1dbdf930303bca65226c2fee1b95de6e080e25451f8b4f2b2b7c4633e1de6a5a7d47cb000000000000000000000000000000000a5048d860b997a9fb352e58284ebbc026622d9be73de79b2807a0c9b431f41f379c255a2db0dd67413c18217cb21b7200000000000000000000000000000000045a701a3f46ca801c02a5419c836b2ab3d74ebd6f4fd1e7dddb1965b49c9a278f6e89950e7c35ebc6724569d34e364c0000000000000000000000000000000004cb55008ccb5b2b8ece69fac7283f5a9ef9e622e2a0e42bed5bdd77faa550882643afc1759b1a327c4f2277e13a3d4f000000000000000000000000000000001690dee40c6c824dc2588fc47dbf93f68ac250b9357e1112db72ded905ed7b101b5f877bdc42d56afb5b6202403a91c4000000000000000000000000000000001305e1b9706c7fc132aea63f0926146557d4dd081b7a2913dae02bab75b0409a515d0f25ffa3eda81cf4764de15741f60000000000000000000000000000000011bf87b12734a6360d3dda4b452deede34470fba8e62a68f79153cc288a8e7fed98c74af862883b9861d2195a58262e0000000000000000000000000000000000a5048d860b997a9fb352e58284ebbc026622d9be73de79b2807a0c9b431f41f379c255a2db0dd67413c18217cb21b7200000000000000000000000000000000045a701a3f46ca801c02a5419c836b2ab3d74ebd6f4fd1e7dddb1965b49c9a278f6e89950e7c35ebc6724569d34e364c000000000000000000000000000000001535bce9acb48b6ebc4d3dbb7c236d7cc57d656210e42e9379d4f528fc0ba59bf868503d3bb8e5cd3dafdd881ec56d5c00000000000000000000000000000000037033062d13644c88c317f1c58c18e0d9b4facbbe0701ac8bbdf3c7f0c37b14034c7882d5112a94bea39dfdbfc518e7", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_38", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000012662b26f03fc8179f090f29894e86155cff4ec2def43393e054f417bbf375edd79f5032a5333ab4eba4418306ed0153000000000000000000000000000000000f26fdf1af1b8ad442ef4494627c815ca01ae84510944788b87f4aa2c8600ed310b9579318bc617a689b916bb7731dcb00000000000000000000000000000000153cec9690a6420a10e5a5a8ca46fd9d9f90e2a139886a07b375eeecce9083a5f5418e6baf64ef0f34176e432bc5343a000000000000000000000000000000000d87c1f37f83ae78a51af9c420e2584a64337d2d2dd8dc3b64f252c521901924e5eec1d9899594db5e64c93c7a01ef020000000000000000000000000000000017078538092ace26cc88b94360871fc9a6bb9992172158ef3a16467919955083accf8d55d48c7ec462a743dbbca7b448000000000000000000000000000000000289b703157a02fc1d687a5aa595495be8bbb3eb0d70554728255a44b7820e0ee82d984d5493c800f1d9d8ca0c9381dc0000000000000000000000000000000012662b26f03fc8179f090f29894e86155cff4ec2def43393e054f417bbf375edd79f5032a5333ab4eba4418306ed0153000000000000000000000000000000000ada13f88a645bc6082c6321e0cf2b7ac45c633fe2f0cb36aeb187fe2e50e7510df2a86b98979e8551636e94488c8ce000000000000000000000000000000000153cec9690a6420a10e5a5a8ca46fd9d9f90e2a139886a07b375eeecce9083a5f5418e6baf64ef0f34176e432bc5343a000000000000000000000000000000000d87c1f37f83ae78a51af9c420e2584a64337d2d2dd8dc3b64f252c521901924e5eec1d9899594db5e64c93c7a01ef020000000000000000000000000000000017078538092ace26cc88b94360871fc9a6bb9992172158ef3a16467919955083accf8d55d48c7ec462a743dbbca7b448000000000000000000000000000000000289b703157a02fc1d687a5aa595495be8bbb3eb0d70554728255a44b7820e0ee82d984d5493c800f1d9d8ca0c9381dc0000000000000000000000000000000012662b26f03fc8179f090f29894e86155cff4ec2def43393e054f417bbf375edd79f5032a5333ab4eba4418306ed0153000000000000000000000000000000000f26fdf1af1b8ad442ef4494627c815ca01ae84510944788b87f4aa2c8600ed310b9579318bc617a689b916bb7731dcb00000000000000000000000000000000153cec9690a6420a10e5a5a8ca46fd9d9f90e2a139886a07b375eeecce9083a5f5418e6baf64ef0f34176e432bc5343a000000000000000000000000000000000d87c1f37f83ae78a51af9c420e2584a64337d2d2dd8dc3b64f252c521901924e5eec1d9899594db5e64c93c7a01ef020000000000000000000000000000000002f98cb2305518737e92ee72e2c48d0dbdbbb1f2dc63b9d02d1a8c27dd1ba5a071dc72a8dcc7813b5757bc244357f6630000000000000000000000000000000017775ae72405e39e2db32d5b9db6637b7bbb9799e614bd783f0b785c3f2ee815367e67b15cc037fec8252735f36c28cf", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_39", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001837f0f18bed66841b4ff0b0411da3d5929e59b957a0872bce1c898a4ef0e13350bf4c7c8bcff4e61f24feca1acd5a370000000000000000000000000000000003d2c7fe67cada2213e842ac5ec0dec8ec205b762f2a9c05fa12fa120c80eba30676834f0560d11ce9939fe210ad6c6300000000000000000000000000000000057f975064a29ba6ad20d6e6d97a15bd314d6cd419948d974a16923d52b38b9203f95937a0a0493a693099e4fa17ea540000000000000000000000000000000014396ce4abfc32945a6b2b0eb4896a6b19a041d4eae320ba18507ec3828964e56719fffaa47e57ea4a2e3bd1a149b6b600000000000000000000000000000000048b3e4ba3e2d1e0dbf5955101cf038dc22e87b0855a57b631ef119d1bd19d56c38a1d72376284c8598e866b6dba37530000000000000000000000000000000007c0b98cda33be53cf4ef29d0500ff5e7a3c2df6f83dfc1c36211d7f9c696b77dfa6571169cf7935d2fb5a6463cceac6000000000000000000000000000000001837f0f18bed66841b4ff0b0411da3d5929e59b957a0872bce1c898a4ef0e13350bf4c7c8bcff4e61f24feca1acd5a3700000000000000000000000000000000162e49ebd1b50c7837336509e48ace0e7856f00ec45a76b96d1dd88eea300a8118357cafabf32ee2d06b601def523e4800000000000000000000000000000000057f975064a29ba6ad20d6e6d97a15bd314d6cd419948d974a16923d52b38b9203f95937a0a0493a693099e4fa17ea540000000000000000000000000000000014396ce4abfc32945a6b2b0eb4896a6b19a041d4eae320ba18507ec3828964e56719fffaa47e57ea4a2e3bd1a149b6b600000000000000000000000000000000048b3e4ba3e2d1e0dbf5955101cf038dc22e87b0855a57b631ef119d1bd19d56c38a1d72376284c8598e866b6dba37530000000000000000000000000000000007c0b98cda33be53cf4ef29d0500ff5e7a3c2df6f83dfc1c36211d7f9c696b77dfa6571169cf7935d2fb5a6463cceac6000000000000000000000000000000001837f0f18bed66841b4ff0b0411da3d5929e59b957a0872bce1c898a4ef0e13350bf4c7c8bcff4e61f24feca1acd5a370000000000000000000000000000000003d2c7fe67cada2213e842ac5ec0dec8ec205b762f2a9c05fa12fa120c80eba30676834f0560d11ce9939fe210ad6c6300000000000000000000000000000000057f975064a29ba6ad20d6e6d97a15bd314d6cd419948d974a16923d52b38b9203f95937a0a0493a693099e4fa17ea540000000000000000000000000000000014396ce4abfc32945a6b2b0eb4896a6b19a041d4eae320ba18507ec3828964e56719fffaa47e57ea4a2e3bd1a149b6b6000000000000000000000000000000001575d39e959d14b96f261265417ca949a248c3d46e2abb093541c103dadf58cd5b21e28c79f17b376070799492457358000000000000000000000000000000001240585d5f4c28467bccb5193e4aad78ea3b1d8dfb4716a3310fb5215a478aac3f05a8ed478486c9e703a59b9c32bfe5", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_40", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000181dc6fd3668d036a37d60b214d68f1a6ffe1949ec6b22f923e69fb373b9c70e8bcc5cdace068024c631c27f28d994e5000000000000000000000000000000000b02ca2b0e6e0989ea917719b89caf1aa84b959e45b6238813bf02f40db95fbb3bf43d3017c3f9c57eab1be617f18032000000000000000000000000000000000b6069a2c375471d34029d2a776e56b86b0210c35d3eb530bf116205b70995e4929fc90349a7db057168dbe6c39857970000000000000000000000000000000014251a0a154731f73513b99d830f70b6fc4bcf05d11f52d2cbe9795ee8ffc5a5f717ad25770b8ecad6d0e9f8066e0cba000000000000000000000000000000001172684b21c4dfe02a55e13b57bbf105c954daec849d4c6df5276b02872c004fdf09d24f4eef366bc82eb72fe91bf70d000000000000000000000000000000001151aeb9441c5a8fabe80867b5c791420645241eae1400bbcc064d75bedd39de2ef585138fe9f65725efa1b1e5888d0300000000000000000000000000000000181dc6fd3668d036a37d60b214d68f1a6ffe1949ec6b22f923e69fb373b9c70e8bcc5cdace068024c631c27f28d994e5000000000000000000000000000000000efe47bf2b11dd10608a309c8aaefdbcbc2bb5e6adceef375371cface8f79668e2b7c2ce9990063a3b53e419e80e2a79000000000000000000000000000000000b6069a2c375471d34029d2a776e56b86b0210c35d3eb530bf116205b70995e4929fc90349a7db057168dbe6c39857970000000000000000000000000000000014251a0a154731f73513b99d830f70b6fc4bcf05d11f52d2cbe9795ee8ffc5a5f717ad25770b8ecad6d0e9f8066e0cba000000000000000000000000000000001172684b21c4dfe02a55e13b57bbf105c954daec849d4c6df5276b02872c004fdf09d24f4eef366bc82eb72fe91bf70d000000000000000000000000000000001151aeb9441c5a8fabe80867b5c791420645241eae1400bbcc064d75bedd39de2ef585138fe9f65725efa1b1e5888d0300000000000000000000000000000000181dc6fd3668d036a37d60b214d68f1a6ffe1949ec6b22f923e69fb373b9c70e8bcc5cdace068024c631c27f28d994e5000000000000000000000000000000000b02ca2b0e6e0989ea917719b89caf1aa84b959e45b6238813bf02f40db95fbb3bf43d3017c3f9c57eab1be617f18032000000000000000000000000000000000b6069a2c375471d34029d2a776e56b86b0210c35d3eb530bf116205b70995e4929fc90349a7db057168dbe6c39857970000000000000000000000000000000014251a0a154731f73513b99d830f70b6fc4bcf05d11f52d2cbe9795ee8ffc5a5f717ad25770b8ecad6d0e9f8066e0cba00000000000000000000000000000000088ea99f17bb06ba20c5c67aeb8fbbd19b2270986ee7c6517209679e6f84f5d43fa22daf6264c993f1d048d016e3b39e0000000000000000000000000000000008af6330f5638c0a9f339f4e8d841b955e322766457112039b2a852b37d3bc45efb67aeb216a09a8940f5e4e1a771da8", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_41", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001329a75975b714c861064d743092866d61c4467e0c0316b78142e6db7e74538a376a09487cb09ee89583d547c187229000000000000000000000000000000000096713619bf088bd9e12752cab83e9cdd58296ada8d338c86a749f00ba014087a3836ce10adaaf2e815f431235bff4f000000000000000000000000000000000161b70d0f384e589d8117938602f3d696f941c24e3c1ca5a9be090b670456c9df315d6fde52daed55c9d8335928a7a3c00000000000000000000000000000000186bb9e6f5ba70dd2c66a641d3b711844977939904c59946d4e9f49ac2d8c00890a43ccb20d4a62bfff63ce4a0a44e8e000000000000000000000000000000001995b9d697bded656236430e78726f0f6ef963db9a5a24d455c12db38aeab0f8629e5dc2d04920156f2a057d69613096000000000000000000000000000000001119b13caf82c18fadcb65c9c166914bfd822534bb9def3feae6c9e572c97c84e97fab3b345cf59358436a404075493d000000000000000000000000000000001329a75975b714c861064d743092866d61c4467e0c0316b78142e6db7e74538a376a09487cb09ee89583d547c1872290000000000000000000000000000000001099fe889d8f5ddcad09328997c7c3098ef4b4d74ab1d9f6fcbc33a03cafb59c7b28931da67950d1389fbcedca3fb5bb00000000000000000000000000000000161b70d0f384e589d8117938602f3d696f941c24e3c1ca5a9be090b670456c9df315d6fde52daed55c9d8335928a7a3c00000000000000000000000000000000186bb9e6f5ba70dd2c66a641d3b711844977939904c59946d4e9f49ac2d8c00890a43ccb20d4a62bfff63ce4a0a44e8e000000000000000000000000000000001995b9d697bded656236430e78726f0f6ef963db9a5a24d455c12db38aeab0f8629e5dc2d04920156f2a057d69613096000000000000000000000000000000001119b13caf82c18fadcb65c9c166914bfd822534bb9def3feae6c9e572c97c84e97fab3b345cf59358436a404075493d000000000000000000000000000000001329a75975b714c861064d743092866d61c4467e0c0316b78142e6db7e74538a376a09487cb09ee89583d547c187229000000000000000000000000000000000096713619bf088bd9e12752cab83e9cdd58296ada8d338c86a749f00ba014087a3836ce10adaaf2e815f431235bff4f000000000000000000000000000000000161b70d0f384e589d8117938602f3d696f941c24e3c1ca5a9be090b670456c9df315d6fde52daed55c9d8335928a7a3c00000000000000000000000000000000186bb9e6f5ba70dd2c66a641d3b711844977939904c59946d4e9f49ac2d8c00890a43ccb20d4a62bfff63ce4a0a44e8e00000000000000000000000000000000006b5813a1c1f934e8e564a7cad93dc7f57de7a9592aedeb116fa4ed6bc6452bbc0da23be10adfea4ad4fa82969e7a150000000000000000000000000000000008e760ad89fd250a9d5041ec81e51b8b66f5265037e7237f7c4a08bb83e7799f352c54c37cf70a6c61bb95bfbf8a616e", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_42", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001195502bc48c44b37e3f8f4e6f40295c1156f58dbc00b04b3018d237b574a20512599d18af01c50192db37cb8eb2c8a90000000000000000000000000000000002b03f02b45aa15b39e030c4b88c89a285dff5c4bbfe16f643f3f87d91db774f8ab7019285fda0b236ff7eec16496e5e0000000000000000000000000000000017d1ffcad218efd8b09c68eba34dbbc30b0a62ae250368ee37e5f6fd40479b8580563416afdbd92c0622c341331e20a30000000000000000000000000000000009f0eb3805ed78aa3952a0a437966258ed38cb72912756253a7a2f9113f0dd9a4e187062b0423e0587d93e904d88f50d0000000000000000000000000000000001bca57e985906695e14882f2aaeef75de5009e8717eb59962e978aa11e9d0a4d9a9e203df774cb1e993b1c6ecd6048c000000000000000000000000000000000695b11cc32740c91546eb7d554ca8b1f3afc942ad977345031be8b94b78b57a87ab049ca2d3676e039efccbf24d0c47000000000000000000000000000000001195502bc48c44b37e3f8f4e6f40295c1156f58dbc00b04b3018d237b574a20512599d18af01c50192db37cb8eb2c8a9000000000000000000000000000000001750d2e78525453f113b76f18abf2334de9755c03786fbc9233cda2364d57ed493f4fe6c2b565f4d82ff8113e9b63c4d0000000000000000000000000000000017d1ffcad218efd8b09c68eba34dbbc30b0a62ae250368ee37e5f6fd40479b8580563416afdbd92c0622c341331e20a30000000000000000000000000000000009f0eb3805ed78aa3952a0a437966258ed38cb72912756253a7a2f9113f0dd9a4e187062b0423e0587d93e904d88f50d0000000000000000000000000000000001bca57e985906695e14882f2aaeef75de5009e8717eb59962e978aa11e9d0a4d9a9e203df774cb1e993b1c6ecd6048c000000000000000000000000000000000695b11cc32740c91546eb7d554ca8b1f3afc942ad977345031be8b94b78b57a87ab049ca2d3676e039efccbf24d0c47000000000000000000000000000000001195502bc48c44b37e3f8f4e6f40295c1156f58dbc00b04b3018d237b574a20512599d18af01c50192db37cb8eb2c8a90000000000000000000000000000000002b03f02b45aa15b39e030c4b88c89a285dff5c4bbfe16f643f3f87d91db774f8ab7019285fda0b236ff7eec16496e5e0000000000000000000000000000000017d1ffcad218efd8b09c68eba34dbbc30b0a62ae250368ee37e5f6fd40479b8580563416afdbd92c0622c341331e20a30000000000000000000000000000000009f0eb3805ed78aa3952a0a437966258ed38cb72912756253a7a2f9113f0dd9a4e187062b0423e0587d93e904d88f50d0000000000000000000000000000000018446c6ba126e030ed071f87189cbd618627419c82065d26044759f6e4c7257f45021dfad1dcb34dd06b4e391329a61f00000000000000000000000000000000136b60cd7658a5d135d4bc38edff042570c7824245ed9f7a6414e9e7ab3840a99700fb620e809891b66003340db29e64", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_43", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d7e1651f3e172dcca8774a7a0d58ab47178d3e759933289e1d3eb0da414160ff9e890a608bf8ccdf2820c4aea6e11cb00000000000000000000000000000000185e8671e2ddb8e36380e39fe4eafefbac9769935603c28caac7d3f7f0f3e8ad14e925024b55aeb67d68b219875c9d79000000000000000000000000000000000546a0cb9d9f1ef9ec4a1e576fa0047557a56c0217baed8691c4085b88c84a0e12d44043aab8671393d02c4a764407ee00000000000000000000000000000000131884c1386980a181353548da9602db70ab495a661e76235c4b0a32b54acb0dfd8846e17bebd731e8041c4aebb8776600000000000000000000000000000000135b3db43511dbd8b3bd5a91880d6da1a2bd1383000e0d6f0a521bf88a5836a3b5f7cb9c0c02aa861a1c2d339f3c11f20000000000000000000000000000000000e1337271bd3302a1cab762161ccfbf2a18b7800e6efe58cf897d4adbfe4cb3bf14f4b59307fffc548179bda70c18bf000000000000000000000000000000000d7e1651f3e172dcca8774a7a0d58ab47178d3e759933289e1d3eb0da414160ff9e890a608bf8ccdf2820c4aea6e11cb0000000000000000000000000000000001a28b7856a22db6e79ac4165e60addbb7dfe1f19d815032bc68fea905bd0d7709c2dafc65fe51493c964de678a30d32000000000000000000000000000000000546a0cb9d9f1ef9ec4a1e576fa0047557a56c0217baed8691c4085b88c84a0e12d44043aab8671393d02c4a764407ee00000000000000000000000000000000131884c1386980a181353548da9602db70ab495a661e76235c4b0a32b54acb0dfd8846e17bebd731e8041c4aebb8776600000000000000000000000000000000135b3db43511dbd8b3bd5a91880d6da1a2bd1383000e0d6f0a521bf88a5836a3b5f7cb9c0c02aa861a1c2d339f3c11f20000000000000000000000000000000000e1337271bd3302a1cab762161ccfbf2a18b7800e6efe58cf897d4adbfe4cb3bf14f4b59307fffc548179bda70c18bf000000000000000000000000000000000d7e1651f3e172dcca8774a7a0d58ab47178d3e759933289e1d3eb0da414160ff9e890a608bf8ccdf2820c4aea6e11cb00000000000000000000000000000000185e8671e2ddb8e36380e39fe4eafefbac9769935603c28caac7d3f7f0f3e8ad14e925024b55aeb67d68b219875c9d79000000000000000000000000000000000546a0cb9d9f1ef9ec4a1e576fa0047557a56c0217baed8691c4085b88c84a0e12d44043aab8671393d02c4a764407ee00000000000000000000000000000000131884c1386980a181353548da9602db70ab495a661e76235c4b0a32b54acb0dfd8846e17bebd731e8041c4aebb877660000000000000000000000000000000006a5d436046e0ac1975e4d24bb3e3f35c1ba3801f37705505cdeb6a86c58bf8068b43462a55155799fe2d2cc60c398b900000000000000000000000000000000191fde77c7c2b397a950f0542d2edd183a5e9404e516146697a755561ab2a9705f970b491e4c0003657d864258f391ec", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_44", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001454d4a82163a155446467164904cefd7e1e3c67ae99bf65c581a75c72716fb011e2fd030eaf3d36977fbb0ff5156e2700000000000000000000000000000000123f973ab6bd3c2e5b0512a0c77ea0ac3003fd891e1262137f9444cd07b927b564e618205ba09220320ea1aa4564e82000000000000000000000000000000000113dc3354146ca79eb103b31b61fe8bc6f33dcb9c59a7c39d989bd9411c1afce4239034f84e6b00a084be061c73e69c0000000000000000000000000000000000ae33bf68f24978c7ea9fc58d8d76047ec45d01fdbc880e6a5ba02a22a49a3a8253afe0678ecfa6013f4849da3401df70000000000000000000000000000000012c5b00376a1dd31378ec44f2dc8e321e17185d903cfc5c15345a01c33f2f151b21b938d31816550594a7a1e7216c5b00000000000000000000000000000000013d79f825c44775c68e90932d0496a5cae53f04a1edb19f8abeb5948a3dd325dfec4a8b6f58c7fbca9cf3c09b909d8b2000000000000000000000000000000001454d4a82163a155446467164904cefd7e1e3c67ae99bf65c581a75c72716fb011e2fd030eaf3d36977fbb0ff5156e270000000000000000000000000000000007c17aaf82c2aa6bf01695157bcd0c2b34734dfbd572b0abe79c8dd3eef7ce6eb9c5e7de55b36ddf87f05e55ba9ac28b00000000000000000000000000000000113dc3354146ca79eb103b31b61fe8bc6f33dcb9c59a7c39d989bd9411c1afce4239034f84e6b00a084be061c73e69c0000000000000000000000000000000000ae33bf68f24978c7ea9fc58d8d76047ec45d01fdbc880e6a5ba02a22a49a3a8253afe0678ecfa6013f4849da3401df70000000000000000000000000000000012c5b00376a1dd31378ec44f2dc8e321e17185d903cfc5c15345a01c33f2f151b21b938d31816550594a7a1e7216c5b00000000000000000000000000000000013d79f825c44775c68e90932d0496a5cae53f04a1edb19f8abeb5948a3dd325dfec4a8b6f58c7fbca9cf3c09b909d8b2000000000000000000000000000000001454d4a82163a155446467164904cefd7e1e3c67ae99bf65c581a75c72716fb011e2fd030eaf3d36977fbb0ff5156e2700000000000000000000000000000000123f973ab6bd3c2e5b0512a0c77ea0ac3003fd891e1262137f9444cd07b927b564e618205ba09220320ea1aa4564e82000000000000000000000000000000000113dc3354146ca79eb103b31b61fe8bc6f33dcb9c59a7c39d989bd9411c1afce4239034f84e6b00a084be061c73e69c0000000000000000000000000000000000ae33bf68f24978c7ea9fc58d8d76047ec45d01fdbc880e6a5ba02a22a49a3a8253afe0678ecfa6013f4849da3401df700000000000000000000000000000000073b61e6c2de0969138ce3671582c9b58305c5abefb54cfe13eb3284c2be04d26c906c717fd29aaf60b485e18de8e4fb0000000000000000000000000000000006297267dd3b6f3de2329e837302427ab6235b3ad4a9f8c6bb45795852d3c3c61fe75747bbc78043102fc3f646f5d1f9", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_45", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000178e6828261ee6855b38234ed15c27551bb1648ac6ec9a9e70744643cd1f134b2309dd0c34b1e59ddfe3f831ab814c90000000000000000000000000000000002ec930fb58c898ede931384c5a5f9edd2f5c70b8c3794edb83a12f23be5400949f95e81c96c666c1a72dffb50b811580000000000000000000000000000000006ccaf6c08f831be9c99a97714f5257a985cc2a29b5f5c81bc8d794dd0d8d1a41eb5413bed654c0140dbacfd0dda9e1800000000000000000000000000000000144e9cf91580800dfaa47c98ff7d002a576be76d9e44ae1f8335a3f733e1162af0636372e143174d872c7ea89f4c743900000000000000000000000000000000101e143b838c8a3f5f80fb1412081091b875230f1e2f9cf374d4bcd595392f6daa9552dbb6d5834e27b1b3dafe061ed300000000000000000000000000000000072463400b3e875395a1cdd31d73d51396e34347cd86d9f6f43f42253b3cdb24b89ed7434b1522af95ba1ee2d29ed1bb000000000000000000000000000000000178e6828261ee6855b38234ed15c27551bb1648ac6ec9a9e70744643cd1f134b2309dd0c34b1e59ddfe3f831ab814c90000000000000000000000000000000017147eda83f35d0b6c8894317da5b2e991818479674d7dd1aef6bfaebacbb61ad4b2a17ce7e799939f8c2004af4799530000000000000000000000000000000006ccaf6c08f831be9c99a97714f5257a985cc2a29b5f5c81bc8d794dd0d8d1a41eb5413bed654c0140dbacfd0dda9e1800000000000000000000000000000000144e9cf91580800dfaa47c98ff7d002a576be76d9e44ae1f8335a3f733e1162af0636372e143174d872c7ea89f4c743900000000000000000000000000000000101e143b838c8a3f5f80fb1412081091b875230f1e2f9cf374d4bcd595392f6daa9552dbb6d5834e27b1b3dafe061ed300000000000000000000000000000000072463400b3e875395a1cdd31d73d51396e34347cd86d9f6f43f42253b3cdb24b89ed7434b1522af95ba1ee2d29ed1bb000000000000000000000000000000000178e6828261ee6855b38234ed15c27551bb1648ac6ec9a9e70744643cd1f134b2309dd0c34b1e59ddfe3f831ab814c90000000000000000000000000000000002ec930fb58c898ede931384c5a5f9edd2f5c70b8c3794edb83a12f23be5400949f95e81c96c666c1a72dffb50b811580000000000000000000000000000000006ccaf6c08f831be9c99a97714f5257a985cc2a29b5f5c81bc8d794dd0d8d1a41eb5413bed654c0140dbacfd0dda9e1800000000000000000000000000000000144e9cf91580800dfaa47c98ff7d002a576be76d9e44ae1f8335a3f733e1162af0636372e143174d872c7ea89f4c74390000000000000000000000000000000009e2fdaeb5f35c5aeb9aaca231439c45ac022875d55575cbf25c15cb6177c6b67416ad22fa7e7cb1924d4c2501f98bd80000000000000000000000000000000012dcaeaa2e415f46b579d9e325d7d7c3cd94083d25fe38c872f1907bbb741aff660d28bb663edd502444e11d2d60d8f0", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_46", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001ea88d0f329135df49893406b4f9aee0abfd74b62e7eb5576d3ddb329fc4b1649b7c228ec39c6577a069c0811c952f100000000000000000000000000000000033f481fc62ab0a249561d180da39ff641a540c9c109cde41946a0e85d18c9d60b41dbcdec370c5c9f22a9ee9de00ccd000000000000000000000000000000001354146aa546754e10ada6e0fe98f04f5f3a3f8a8350d0295e02b8e9c80735b04c3061412e08ddb13c80ac36e5638e540000000000000000000000000000000012ab26513534b4dc1b71eec46b73199c4157ba9369e66fbe4d2d8f62237fc7c6fad31854ebd878f989b8c5cf35c7cfe0000000000000000000000000000000000eb731bc99cdadf7f2280385c7e17d72d34bcbdbdc725d5bc94e841036115e8cb95df08084221696f9be479821fbdd7400000000000000000000000000000000143ba7d3f66445249d9a81a6949f24ff40e7c4d270fa044a8b80200a4369b07806c5497a0ef9e9dbb87b9e63694623ee0000000000000000000000000000000001ea88d0f329135df49893406b4f9aee0abfd74b62e7eb5576d3ddb329fc4b1649b7c228ec39c6577a069c0811c952f10000000000000000000000000000000016c1c9ca735535f801c58a9e35a80ce122d20abb327b44db4dea31b899982c4e136a2430c51cf3a31adc5611621f9dde000000000000000000000000000000001354146aa546754e10ada6e0fe98f04f5f3a3f8a8350d0295e02b8e9c80735b04c3061412e08ddb13c80ac36e5638e540000000000000000000000000000000012ab26513534b4dc1b71eec46b73199c4157ba9369e66fbe4d2d8f62237fc7c6fad31854ebd878f989b8c5cf35c7cfe0000000000000000000000000000000000eb731bc99cdadf7f2280385c7e17d72d34bcbdbdc725d5bc94e841036115e8cb95df08084221696f9be479821fbdd7400000000000000000000000000000000143ba7d3f66445249d9a81a6949f24ff40e7c4d270fa044a8b80200a4369b07806c5497a0ef9e9dbb87b9e63694623ee0000000000000000000000000000000001ea88d0f329135df49893406b4f9aee0abfd74b62e7eb5576d3ddb329fc4b1649b7c228ec39c6577a069c0811c952f100000000000000000000000000000000033f481fc62ab0a249561d180da39ff641a540c9c109cde41946a0e85d18c9d60b41dbcdec370c5c9f22a9ee9de00ccd000000000000000000000000000000001354146aa546754e10ada6e0fe98f04f5f3a3f8a8350d0295e02b8e9c80735b04c3061412e08ddb13c80ac36e5638e540000000000000000000000000000000012ab26513534b4dc1b71eec46b73199c4157ba9369e66fbe4d2d8f62237fc7c6fad31854ebd878f989b8c5cf35c7cfe0000000000000000000000000000000000b49e02d9fb238a258f3a4307b6a2f64912b7fa91712b5639de24e90c09f9797654e0f7e2d31e968c040b867de03cd370000000000000000000000000000000005c56a16431ba175ad81260faeac87d8238f86b2828b0e74dbb0b296b34745ac17e6b684a25a16240183619c96b986bd", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_47", - "Gas": 184000, + "Gas": 194000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008d8c4a16fb9d8800cce987c0eadbb6b3b005c213d44ecb5adeed713bae79d606041406df26169c35df63cf972c94be10000000000000000000000000000000011bc8afe71676e6730702a46ef817060249cd06cd82e6981085012ff6d013aa4470ba3a2c71e13ef653e1e223d1ccfe90000000000000000000000000000000013a3de1d25380c44ca06321151e89ca22210926c1cd4e3c1a9c3aa6c709ab5fdd00f8df19243ce058bc753ccf03424ed000000000000000000000000000000001657dbebf712cbda6f15d1d387c87b3fb9b386d5d754135049728a2a856ba2944c741024131a93c78655fdb7bfe3c80300000000000000000000000000000000068edef3169c58920509ed4e7069229bd8038a45d2ce5773451cc18b396d2838c9539ecb52298a27eebd714afacb907c0000000000000000000000000000000004c5346765a62f2d2e700aadccf747acb3322c250435ce2cf358c08f1e286427cabace052327c4b30135c8482c5c0eb90000000000000000000000000000000008d8c4a16fb9d8800cce987c0eadbb6b3b005c213d44ecb5adeed713bae79d606041406df26169c35df63cf972c94be100000000000000000000000000000000084486ebc81878331aab7d6f53ca3c773fda7b181b56a93e5ee0bfa189afbb7fd7a05c5bea35ec1054c0e1ddc2e2dac20000000000000000000000000000000013a3de1d25380c44ca06321151e89ca22210926c1cd4e3c1a9c3aa6c709ab5fdd00f8df19243ce058bc753ccf03424ed000000000000000000000000000000001657dbebf712cbda6f15d1d387c87b3fb9b386d5d754135049728a2a856ba2944c741024131a93c78655fdb7bfe3c80300000000000000000000000000000000068edef3169c58920509ed4e7069229bd8038a45d2ce5773451cc18b396d2838c9539ecb52298a27eebd714afacb907c0000000000000000000000000000000004c5346765a62f2d2e700aadccf747acb3322c250435ce2cf358c08f1e286427cabace052327c4b30135c8482c5c0eb90000000000000000000000000000000008d8c4a16fb9d8800cce987c0eadbb6b3b005c213d44ecb5adeed713bae79d606041406df26169c35df63cf972c94be10000000000000000000000000000000011bc8afe71676e6730702a46ef817060249cd06cd82e6981085012ff6d013aa4470ba3a2c71e13ef653e1e223d1ccfe90000000000000000000000000000000013a3de1d25380c44ca06321151e89ca22210926c1cd4e3c1a9c3aa6c709ab5fdd00f8df19243ce058bc753ccf03424ed000000000000000000000000000000001657dbebf712cbda6f15d1d387c87b3fb9b386d5d754135049728a2a856ba2944c741024131a93c78655fdb7bfe3c80300000000000000000000000000000000137232f722e38e084611ba67d2e28a3b8c73c13f20b6bb4c22141115bd43cdeb555861335f2a75d7cb418eb505341a2f00000000000000000000000000000000153bdd82d3d9b76d1cab9d087654652ab1451f5fef4f449273d81211d88891fc53f131f98e2c3b4cb8c937b7d3a39bf20000000000000000000000000000000008d8c4a16fb9d8800cce987c0eadbb6b3b005c213d44ecb5adeed713bae79d606041406df26169c35df63cf972c94be100000000000000000000000000000000084486ebc81878331aab7d6f53ca3c773fda7b181b56a93e5ee0bfa189afbb7fd7a05c5bea35ec1054c0e1ddc2e2dac20000000000000000000000000000000013a3de1d25380c44ca06321151e89ca22210926c1cd4e3c1a9c3aa6c709ab5fdd00f8df19243ce058bc753ccf03424ed000000000000000000000000000000001657dbebf712cbda6f15d1d387c87b3fb9b386d5d754135049728a2a856ba2944c741024131a93c78655fdb7bfe3c80300000000000000000000000000000000137232f722e38e084611ba67d2e28a3b8c73c13f20b6bb4c22141115bd43cdeb555861335f2a75d7cb418eb505341a2f00000000000000000000000000000000153bdd82d3d9b76d1cab9d087654652ab1451f5fef4f449273d81211d88891fc53f131f98e2c3b4cb8c937b7d3a39bf2", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_48", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000120ddc1cd9e3a7b298673b1036d162c31dbb35d6e83b39b2564b3be16e446a836c96907e8a6af1e677e906bf5ed73159000000000000000000000000000000000fa57c1436615442bbb049d08ac46e501c07736cd239298752bb94d1904bd38cc687759987cadd99bd3c4d45ba07193a000000000000000000000000000000000dd75b4aebed3bd6bd020c3af671aaed67bf1582aceb6c8b5a476968c0c500753e4d0f3276341b79d87af38850893d92000000000000000000000000000000000e9b3be06afd6157eb6df52be4f2db2bcccd650f720661f8d6fcff3f71d69e152e17100ce60b7b90a7f798c4cdd02209000000000000000000000000000000000f6fdc4e5dceb555c9eb4c912fedbfb3cb1b842345f73ded02cfaf8d397c4378809721094aa4a4113a368e0787effeb500000000000000000000000000000000143ac06258c579c11c05569669a2a10babc63ecc86f85c91791d8ea48af700a2067c5f13d2700b8d5cf59bcca8fbf7c600000000000000000000000000000000120ddc1cd9e3a7b298673b1036d162c31dbb35d6e83b39b2564b3be16e446a836c96907e8a6af1e677e906bf5ed73159000000000000000000000000000000000a5b95d6031e92578f6b5de5b8873e87486fd818214be93814753dcf6665229758248a6529892265fcc2b2ba45f89171000000000000000000000000000000000dd75b4aebed3bd6bd020c3af671aaed67bf1582aceb6c8b5a476968c0c500753e4d0f3276341b79d87af38850893d92000000000000000000000000000000000e9b3be06afd6157eb6df52be4f2db2bcccd650f720661f8d6fcff3f71d69e152e17100ce60b7b90a7f798c4cdd02209000000000000000000000000000000000f6fdc4e5dceb555c9eb4c912fedbfb3cb1b842345f73ded02cfaf8d397c4378809721094aa4a4113a368e0787effeb500000000000000000000000000000000143ac06258c579c11c05569669a2a10babc63ecc86f85c91791d8ea48af700a2067c5f13d2700b8d5cf59bcca8fbf7c600000000000000000000000000000000120ddc1cd9e3a7b298673b1036d162c31dbb35d6e83b39b2564b3be16e446a836c96907e8a6af1e677e906bf5ed73159000000000000000000000000000000000fa57c1436615442bbb049d08ac46e501c07736cd239298752bb94d1904bd38cc687759987cadd99bd3c4d45ba07193a000000000000000000000000000000000dd75b4aebed3bd6bd020c3af671aaed67bf1582aceb6c8b5a476968c0c500753e4d0f3276341b79d87af38850893d92000000000000000000000000000000000e9b3be06afd6157eb6df52be4f2db2bcccd650f720661f8d6fcff3f71d69e152e17100ce60b7b90a7f798c4cdd02209000000000000000000000000000000000a91359bdbb1314481305b25135ded23995bc761ad8dd4d264612313bd34b2ab9e14def566af5bee7fc871f8780fabf60000000000000000000000000000000005c65187e0ba6cd92f16511fd9a90bcbb8b10cb86c8cb62dee1343fc6bb9f582182fa0eadee3f4725d0964335703b2e500000000000000000000000000000000120ddc1cd9e3a7b298673b1036d162c31dbb35d6e83b39b2564b3be16e446a836c96907e8a6af1e677e906bf5ed73159000000000000000000000000000000000a5b95d6031e92578f6b5de5b8873e87486fd818214be93814753dcf6665229758248a6529892265fcc2b2ba45f89171000000000000000000000000000000000dd75b4aebed3bd6bd020c3af671aaed67bf1582aceb6c8b5a476968c0c500753e4d0f3276341b79d87af38850893d92000000000000000000000000000000000e9b3be06afd6157eb6df52be4f2db2bcccd650f720661f8d6fcff3f71d69e152e17100ce60b7b90a7f798c4cdd02209000000000000000000000000000000000a91359bdbb1314481305b25135ded23995bc761ad8dd4d264612313bd34b2ab9e14def566af5bee7fc871f8780fabf60000000000000000000000000000000005c65187e0ba6cd92f16511fd9a90bcbb8b10cb86c8cb62dee1343fc6bb9f582182fa0eadee3f4725d0964335703b2e5", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_49", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e3ccaa4fa358a5a885094cbb0b8baa106fbcca66edbe31511ac2f6f3d14edbd8701979d6e4690853555c625091392b600000000000000000000000000000000175bdd42583cbbf733242510c152380525aff7649273acef1ec20569804ffba7f029ca06878dbafde84540cece173822000000000000000000000000000000000057bbf62cdf3c56e146f60f8ce6b6bdebe7aae7d9410c6902c7a505b589ae26ce3ab67d9b8da047185f9d37ab27595e000000000000000000000000000000000843e55c07bba3573592d3f649938654a5c51f9ced0f92bcb3e4f431141fe91a1de3695324b21e31dd2ae0a328055cc500000000000000000000000000000000192f3e8ae2588f9223de77f5e872115f1edec96d6a0f403a47879410c2562e79853c9a706e423b83fbf3154234edb6f80000000000000000000000000000000015084258d58fd1a07bbdb2e90df5a56ae15a787037eff4fe55f660e45f04820c6fc8982303b5e82074cf0cdcbde61307000000000000000000000000000000000e3ccaa4fa358a5a885094cbb0b8baa106fbcca66edbe31511ac2f6f3d14edbd8701979d6e4690853555c625091392b60000000000000000000000000000000002a534a7e1432aa317f782a581f974d23ec75420611165d0486ecd377660fa7c2e8235f829c64501d1b9bf3131e87289000000000000000000000000000000000057bbf62cdf3c56e146f60f8ce6b6bdebe7aae7d9410c6902c7a505b589ae26ce3ab67d9b8da047185f9d37ab27595e000000000000000000000000000000000843e55c07bba3573592d3f649938654a5c51f9ced0f92bcb3e4f431141fe91a1de3695324b21e31dd2ae0a328055cc500000000000000000000000000000000192f3e8ae2588f9223de77f5e872115f1edec96d6a0f403a47879410c2562e79853c9a706e423b83fbf3154234edb6f80000000000000000000000000000000015084258d58fd1a07bbdb2e90df5a56ae15a787037eff4fe55f660e45f04820c6fc8982303b5e82074cf0cdcbde61307000000000000000000000000000000000e3ccaa4fa358a5a885094cbb0b8baa106fbcca66edbe31511ac2f6f3d14edbd8701979d6e4690853555c625091392b600000000000000000000000000000000175bdd42583cbbf733242510c152380525aff7649273acef1ec20569804ffba7f029ca06878dbafde84540cece173822000000000000000000000000000000000057bbf62cdf3c56e146f60f8ce6b6bdebe7aae7d9410c6902c7a505b589ae26ce3ab67d9b8da047185f9d37ab27595e000000000000000000000000000000000843e55c07bba3573592d3f649938654a5c51f9ced0f92bcb3e4f431141fe91a1de3695324b21e31dd2ae0a328055cc50000000000000000000000000000000000d1d35f57275708273d2fc05ad99b78459882178975d2851fa93e90345ac7aa996f658e4311c47bbe0beabdcb11f3b30000000000000000000000000000000004f8cf9163f014f9cf5df4cd3556076c831cd314bb951dc1113a71bc97ac7417aee367dbad9e17df452ff323421997a4000000000000000000000000000000000e3ccaa4fa358a5a885094cbb0b8baa106fbcca66edbe31511ac2f6f3d14edbd8701979d6e4690853555c625091392b60000000000000000000000000000000002a534a7e1432aa317f782a581f974d23ec75420611165d0486ecd377660fa7c2e8235f829c64501d1b9bf3131e87289000000000000000000000000000000000057bbf62cdf3c56e146f60f8ce6b6bdebe7aae7d9410c6902c7a505b589ae26ce3ab67d9b8da047185f9d37ab27595e000000000000000000000000000000000843e55c07bba3573592d3f649938654a5c51f9ced0f92bcb3e4f431141fe91a1de3695324b21e31dd2ae0a328055cc50000000000000000000000000000000000d1d35f57275708273d2fc05ad99b78459882178975d2851fa93e90345ac7aa996f658e4311c47bbe0beabdcb11f3b30000000000000000000000000000000004f8cf9163f014f9cf5df4cd3556076c831cd314bb951dc1113a71bc97ac7417aee367dbad9e17df452ff323421997a4", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_50", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001bc359baeac07a93aca770174ea6444aac9f04affdaa77c8a47b30c60ee2b527c061a4344139264e541d4134f42bfd0000000000000000000000000000000000cbf7a31e6fef4f4664bca4bc87ec7c0b12ced7224300aa4e1a6a7cbdedfcef07482b5d20fa607e3f03fdd6dd03fd10c000000000000000000000000000000000bcec23e092111b38a2f7dc957cf455312ffd33528d084204314492440d29248cb5719346a4f7a490d17ba149e30de5200000000000000000000000000000000194605e5680cc80bd2685949efa3cce90d345b9151ba72f3adf226dd299c23464c4344a42b8834131a51a4156038585f000000000000000000000000000000000477b55bd7fff14e0d1807bfc21edb9481be01c12abb1460d78b1aafe42953730167e32e694c2ddfb0d442e8cea57d460000000000000000000000000000000004b884c6ea36f189dbc3c0e9cf88f08baf5d868579998f63b752e61fcce3cf2c901bb9b51959d3597c4ef53cff41fc260000000000000000000000000000000001bc359baeac07a93aca770174ea6444aac9f04affdaa77c8a47b30c60ee2b527c061a4344139264e541d4134f42bfd0000000000000000000000000000000000d4197b85280f1a5e4cfdd6a7acce516b34a5e12cf55081a858a2ad517d12733aa294a2ca1adf81bc9bf22922fbfd99f000000000000000000000000000000000bcec23e092111b38a2f7dc957cf455312ffd33528d084204314492440d29248cb5719346a4f7a490d17ba149e30de5200000000000000000000000000000000194605e5680cc80bd2685949efa3cce90d345b9151ba72f3adf226dd299c23464c4344a42b8834131a51a4156038585f000000000000000000000000000000000477b55bd7fff14e0d1807bfc21edb9481be01c12abb1460d78b1aafe42953730167e32e694c2ddfb0d442e8cea57d460000000000000000000000000000000004b884c6ea36f189dbc3c0e9cf88f08baf5d868579998f63b752e61fcce3cf2c901bb9b51959d3597c4ef53cff41fc260000000000000000000000000000000001bc359baeac07a93aca770174ea6444aac9f04affdaa77c8a47b30c60ee2b527c061a4344139264e541d4134f42bfd0000000000000000000000000000000000cbf7a31e6fef4f4664bca4bc87ec7c0b12ced7224300aa4e1a6a7cbdedfcef07482b5d20fa607e3f03fdd6dd03fd10c000000000000000000000000000000000bcec23e092111b38a2f7dc957cf455312ffd33528d084204314492440d29248cb5719346a4f7a490d17ba149e30de5200000000000000000000000000000000194605e5680cc80bd2685949efa3cce90d345b9151ba72f3adf226dd299c23464c4344a42b8834131a51a4156038585f0000000000000000000000000000000015895c8e617ff54c3e039ff6812cd142e2b949c3c8c9fe5e8fa5b7f11287a2b11d441cd04807d220092abd17315a2d650000000000000000000000000000000015488d234f48f5106f57e6cc73c2bc4bb519c4ff79eb835bafddec8129cd26f78e90464997fa2ca63db00ac300bdae850000000000000000000000000000000001bc359baeac07a93aca770174ea6444aac9f04affdaa77c8a47b30c60ee2b527c061a4344139264e541d4134f42bfd0000000000000000000000000000000000d4197b85280f1a5e4cfdd6a7acce516b34a5e12cf55081a858a2ad517d12733aa294a2ca1adf81bc9bf22922fbfd99f000000000000000000000000000000000bcec23e092111b38a2f7dc957cf455312ffd33528d084204314492440d29248cb5719346a4f7a490d17ba149e30de5200000000000000000000000000000000194605e5680cc80bd2685949efa3cce90d345b9151ba72f3adf226dd299c23464c4344a42b8834131a51a4156038585f0000000000000000000000000000000015895c8e617ff54c3e039ff6812cd142e2b949c3c8c9fe5e8fa5b7f11287a2b11d441cd04807d220092abd17315a2d650000000000000000000000000000000015488d234f48f5106f57e6cc73c2bc4bb519c4ff79eb835bafddec8129cd26f78e90464997fa2ca63db00ac300bdae85", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_51", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000006b06ae8cb0981bf5167ad51e19d132db77548c4376697f855c8397b835743c42771096ed7b0a4b18af9494e42ee89aa0000000000000000000000000000000005aa892b0a056ff61706430f1daa3f0263dc01337eadabd8a7fd58152affd9aaa329e8c11ea98692134d9718cb4119bf00000000000000000000000000000000073341309b6fbabb18f3cf0842817905e9248db98b582dc0efb2b741a80cdbb13d0df4bce920f257996b95029891a36f0000000000000000000000000000000012d19e09dc254bd1e84afce75aa215c96dd38bcac3f6d4cf08d9e2e8d20345b7c534a0b14ffcdfd4fa3600730e2eeac800000000000000000000000000000000183b7b917aaaa94f0ea9959273ed4701102346be2a9d72531bd18fef908ecb0579a6ac10ed42a91f1147fc3a05b2e81900000000000000000000000000000000070983b1582a97d9797782e4f960a298aaa8ec509720495acdbf176d8ecb9ec9e041c2b5ed6b7dfb46fdeaae3fb341500000000000000000000000000000000006b06ae8cb0981bf5167ad51e19d132db77548c4376697f855c8397b835743c42771096ed7b0a4b18af9494e42ee89aa00000000000000000000000000000000145688bf2f7a76a4341564a725a16dd5009b4a5174d766e6bf337a8bcbb11c797b82173d92aa796da6b168e734be90ec00000000000000000000000000000000073341309b6fbabb18f3cf0842817905e9248db98b582dc0efb2b741a80cdbb13d0df4bce920f257996b95029891a36f0000000000000000000000000000000012d19e09dc254bd1e84afce75aa215c96dd38bcac3f6d4cf08d9e2e8d20345b7c534a0b14ffcdfd4fa3600730e2eeac800000000000000000000000000000000183b7b917aaaa94f0ea9959273ed4701102346be2a9d72531bd18fef908ecb0579a6ac10ed42a91f1147fc3a05b2e81900000000000000000000000000000000070983b1582a97d9797782e4f960a298aaa8ec509720495acdbf176d8ecb9ec9e041c2b5ed6b7dfb46fdeaae3fb341500000000000000000000000000000000006b06ae8cb0981bf5167ad51e19d132db77548c4376697f855c8397b835743c42771096ed7b0a4b18af9494e42ee89aa0000000000000000000000000000000005aa892b0a056ff61706430f1daa3f0263dc01337eadabd8a7fd58152affd9aaa329e8c11ea98692134d9718cb4119bf00000000000000000000000000000000073341309b6fbabb18f3cf0842817905e9248db98b582dc0efb2b741a80cdbb13d0df4bce920f257996b95029891a36f0000000000000000000000000000000012d19e09dc254bd1e84afce75aa215c96dd38bcac3f6d4cf08d9e2e8d20345b7c534a0b14ffcdfd4fa3600730e2eeac80000000000000000000000000000000001c59658bed53d4b3c721223cf5e65d6545404c6c8e7a06c4b5f42b166222b1ea50553edc41156e0a8b703c5fa4cc2920000000000000000000000000000000012f78e38e1554ec0d1a424d149eb0a3eb9ce5f345c64c9649971bb3367e5575a3e6a3d48c3e8820473011551c04c695b0000000000000000000000000000000006b06ae8cb0981bf5167ad51e19d132db77548c4376697f855c8397b835743c42771096ed7b0a4b18af9494e42ee89aa00000000000000000000000000000000145688bf2f7a76a4341564a725a16dd5009b4a5174d766e6bf337a8bcbb11c797b82173d92aa796da6b168e734be90ec00000000000000000000000000000000073341309b6fbabb18f3cf0842817905e9248db98b582dc0efb2b741a80cdbb13d0df4bce920f257996b95029891a36f0000000000000000000000000000000012d19e09dc254bd1e84afce75aa215c96dd38bcac3f6d4cf08d9e2e8d20345b7c534a0b14ffcdfd4fa3600730e2eeac80000000000000000000000000000000001c59658bed53d4b3c721223cf5e65d6545404c6c8e7a06c4b5f42b166222b1ea50553edc41156e0a8b703c5fa4cc2920000000000000000000000000000000012f78e38e1554ec0d1a424d149eb0a3eb9ce5f345c64c9649971bb3367e5575a3e6a3d48c3e8820473011551c04c695b", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_52", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000015dc9f87213e4781863ad43f6bbccd547967d9bcf6a35d95d530cbfbf0d7307981aee5bc4ccd41254841651717393a0300000000000000000000000000000000166ce33c0482b5957c6e746c16908ba579d6402b230bc977d3ff29ac2a4a800748d9c14608f2519e2ac4d1fe4daf29b2000000000000000000000000000000000dca3b392f75583b5266a8def02bd66bf44f26b8a0a27aced57299756cffaf9e1af3538beb08b2a5939b745c8f016fee000000000000000000000000000000000d7feafc9ec0935d5b7be7cd5e2a3c57b667aba9fcc87fd5b8a585010be6958c4e7538a6d2a1f46c9641ff7b8598d74b0000000000000000000000000000000010f7bf9f6711ba723bb71a004a90109ee22be6643d56d410da18103ef44a1b3d50f10c4b94222c7f05fd3c28acbdc8ee00000000000000000000000000000000007af41f09e6d0adcb1935d6a93ea1f6156fa0157a63f265a3a7ceffe82f6635b8511e7e8f21e8f3be7a73513ff597b10000000000000000000000000000000015dc9f87213e4781863ad43f6bbccd547967d9bcf6a35d95d530cbfbf0d7307981aee5bc4ccd41254841651717393a030000000000000000000000000000000003942eae34fd3104cead334a2cbb2131eaa10b59d07949479331a8f4cc66761cd5d23eb8a861ae618f3a2e01b25080f9000000000000000000000000000000000dca3b392f75583b5266a8def02bd66bf44f26b8a0a27aced57299756cffaf9e1af3538beb08b2a5939b745c8f016fee000000000000000000000000000000000d7feafc9ec0935d5b7be7cd5e2a3c57b667aba9fcc87fd5b8a585010be6958c4e7538a6d2a1f46c9641ff7b8598d74b0000000000000000000000000000000010f7bf9f6711ba723bb71a004a90109ee22be6643d56d410da18103ef44a1b3d50f10c4b94222c7f05fd3c28acbdc8ee00000000000000000000000000000000007af41f09e6d0adcb1935d6a93ea1f6156fa0157a63f265a3a7ceffe82f6635b8511e7e8f21e8f3be7a73513ff597b10000000000000000000000000000000015dc9f87213e4781863ad43f6bbccd547967d9bcf6a35d95d530cbfbf0d7307981aee5bc4ccd41254841651717393a0300000000000000000000000000000000166ce33c0482b5957c6e746c16908ba579d6402b230bc977d3ff29ac2a4a800748d9c14608f2519e2ac4d1fe4daf29b2000000000000000000000000000000000dca3b392f75583b5266a8def02bd66bf44f26b8a0a27aced57299756cffaf9e1af3538beb08b2a5939b745c8f016fee000000000000000000000000000000000d7feafc9ec0935d5b7be7cd5e2a3c57b667aba9fcc87fd5b8a585010be6958c4e7538a6d2a1f46c9641ff7b8598d74b000000000000000000000000000000000909524ad26e2c280f648db5f8bb9c38824b6520b62e3eae8d18c2620266dae6cdbaf3b31d31d380b401c3d75341e1bd0000000000000000000000000000000019861dcb2f9915ec800271df9a0d0ae14f07ab6f79212059c38903a10e818fee665ae1802232170bfb848caec00a12fa0000000000000000000000000000000015dc9f87213e4781863ad43f6bbccd547967d9bcf6a35d95d530cbfbf0d7307981aee5bc4ccd41254841651717393a030000000000000000000000000000000003942eae34fd3104cead334a2cbb2131eaa10b59d07949479331a8f4cc66761cd5d23eb8a861ae618f3a2e01b25080f9000000000000000000000000000000000dca3b392f75583b5266a8def02bd66bf44f26b8a0a27aced57299756cffaf9e1af3538beb08b2a5939b745c8f016fee000000000000000000000000000000000d7feafc9ec0935d5b7be7cd5e2a3c57b667aba9fcc87fd5b8a585010be6958c4e7538a6d2a1f46c9641ff7b8598d74b000000000000000000000000000000000909524ad26e2c280f648db5f8bb9c38824b6520b62e3eae8d18c2620266dae6cdbaf3b31d31d380b401c3d75341e1bd0000000000000000000000000000000019861dcb2f9915ec800271df9a0d0ae14f07ab6f79212059c38903a10e818fee665ae1802232170bfb848caec00a12fa", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_53", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000171fbc9cec717964c4324aa0d7dcf56a59b947c24a9092157f4f8c78ae43b8e4222fd1e8acdbf5989d0d17ea10f6046300000000000000000000000000000000148b5454f9b9868aefd2accc3318ddabfe618c5026e8c04f8a6bce76cd88e350bebcd779f2021fe7ceda3e8b4d438a0b0000000000000000000000000000000019e05ccf064f7cdad9748d328170b3e4bcfa6787dbfa93011d16f6d031648faa10dbfb7cc4d7c884d75480c4c864bb75000000000000000000000000000000001999d5f54ee66b3c0dedf9f46450e0ed463fa9c6cd9e0db317a35ec6ce78efae9bea9b64e3b2aaf7f70fbcace71b075a0000000000000000000000000000000003a6cc74cc398f38d535b4341faa37c968daf2009c3f05ace1f938b33bbe4002d81d18d30c2c856b21afe7a22b83c37a000000000000000000000000000000000452d1b2da6392f9df1bfd35e4575c565333703b2f83f56e0a88a0c8195968c5321296b07f6750584e23597304a5472e00000000000000000000000000000000171fbc9cec717964c4324aa0d7dcf56a59b947c24a9092157f4f8c78ae43b8e4222fd1e8acdbf5989d0d17ea10f60463000000000000000000000000000000000575bd953fc6600f5b48faea1032cf2b6615bf34cc9c526fdcc5042a292812d35fef2884bf51e017eb24c174b2bc20a00000000000000000000000000000000019e05ccf064f7cdad9748d328170b3e4bcfa6787dbfa93011d16f6d031648faa10dbfb7cc4d7c884d75480c4c864bb75000000000000000000000000000000001999d5f54ee66b3c0dedf9f46450e0ed463fa9c6cd9e0db317a35ec6ce78efae9bea9b64e3b2aaf7f70fbcace71b075a0000000000000000000000000000000003a6cc74cc398f38d535b4341faa37c968daf2009c3f05ace1f938b33bbe4002d81d18d30c2c856b21afe7a22b83c37a000000000000000000000000000000000452d1b2da6392f9df1bfd35e4575c565333703b2f83f56e0a88a0c8195968c5321296b07f6750584e23597304a5472e00000000000000000000000000000000171fbc9cec717964c4324aa0d7dcf56a59b947c24a9092157f4f8c78ae43b8e4222fd1e8acdbf5989d0d17ea10f6046300000000000000000000000000000000148b5454f9b9868aefd2accc3318ddabfe618c5026e8c04f8a6bce76cd88e350bebcd779f2021fe7ceda3e8b4d438a0b0000000000000000000000000000000019e05ccf064f7cdad9748d328170b3e4bcfa6787dbfa93011d16f6d031648faa10dbfb7cc4d7c884d75480c4c864bb75000000000000000000000000000000001999d5f54ee66b3c0dedf9f46450e0ed463fa9c6cd9e0db317a35ec6ce78efae9bea9b64e3b2aaf7f70fbcace71b075a00000000000000000000000000000000165a45756d46576175e5f38223a1750dfb9c598457460d12853799edbaf2b621468ee72ba5277a94984f185dd47be7310000000000000000000000000000000015ae40375f1c53a06bffaa805ef450811143db49c4011d515ca831d8dd578d5eec99694e31ecafa76bdba68cfb5a637d00000000000000000000000000000000171fbc9cec717964c4324aa0d7dcf56a59b947c24a9092157f4f8c78ae43b8e4222fd1e8acdbf5989d0d17ea10f60463000000000000000000000000000000000575bd953fc6600f5b48faea1032cf2b6615bf34cc9c526fdcc5042a292812d35fef2884bf51e017eb24c174b2bc20a00000000000000000000000000000000019e05ccf064f7cdad9748d328170b3e4bcfa6787dbfa93011d16f6d031648faa10dbfb7cc4d7c884d75480c4c864bb75000000000000000000000000000000001999d5f54ee66b3c0dedf9f46450e0ed463fa9c6cd9e0db317a35ec6ce78efae9bea9b64e3b2aaf7f70fbcace71b075a00000000000000000000000000000000165a45756d46576175e5f38223a1750dfb9c598457460d12853799edbaf2b621468ee72ba5277a94984f185dd47be7310000000000000000000000000000000015ae40375f1c53a06bffaa805ef450811143db49c4011d515ca831d8dd578d5eec99694e31ecafa76bdba68cfb5a637d", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_54", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018724e2b9a2f383329207ee85577805f35d5c5bb9f6903e3c962e57ab7eb9d1639d1e9adbde53499863b299f576325a00000000000000000000000000000000016d2c22eabd4a06a5ae67b890a25fbede7d0e96c625b80329b19be6aa861f44b6e85778130d0bdf69f2abd491ee9751a0000000000000000000000000000000004506802747afd8777904c46ad9bf0b06859a1b395ca3474a93ca4151ca158d2fd41b3a21e0ce0bc950b3241256e10d800000000000000000000000000000000115f41d2c173c3c2c7ecdff1a4aaa3c2e67c803db7a588d6143fe913961eef743d8b1f9d32e3ef1fc0475f41572faf780000000000000000000000000000000007a9cf48dbe005c5c59b2c731cf4117e5fadc9cb2cd8f486f1ed58b2909092ee8f36d88b8f719db94715641b418ab4240000000000000000000000000000000004ba40d4766b91bf8da1cc2526f62791a1b5f6fc24ffc54b522dd30cde2d29a6a6f81e8429d518710843d43705f3b4e60000000000000000000000000000000018724e2b9a2f383329207ee85577805f35d5c5bb9f6903e3c962e57ab7eb9d1639d1e9adbde53499863b299f576325a000000000000000000000000000000000032e4fbb8dab462ff0352c2d3925b0e97ca662189129928ccc1714364e4f01d8b026887d808342091ad442b6e11635910000000000000000000000000000000004506802747afd8777904c46ad9bf0b06859a1b395ca3474a93ca4151ca158d2fd41b3a21e0ce0bc950b3241256e10d800000000000000000000000000000000115f41d2c173c3c2c7ecdff1a4aaa3c2e67c803db7a588d6143fe913961eef743d8b1f9d32e3ef1fc0475f41572faf780000000000000000000000000000000007a9cf48dbe005c5c59b2c731cf4117e5fadc9cb2cd8f486f1ed58b2909092ee8f36d88b8f719db94715641b418ab4240000000000000000000000000000000004ba40d4766b91bf8da1cc2526f62791a1b5f6fc24ffc54b522dd30cde2d29a6a6f81e8429d518710843d43705f3b4e60000000000000000000000000000000018724e2b9a2f383329207ee85577805f35d5c5bb9f6903e3c962e57ab7eb9d1639d1e9adbde53499863b299f576325a00000000000000000000000000000000016d2c22eabd4a06a5ae67b890a25fbede7d0e96c625b80329b19be6aa861f44b6e85778130d0bdf69f2abd491ee9751a0000000000000000000000000000000004506802747afd8777904c46ad9bf0b06859a1b395ca3474a93ca4151ca158d2fd41b3a21e0ce0bc950b3241256e10d800000000000000000000000000000000115f41d2c173c3c2c7ecdff1a4aaa3c2e67c803db7a588d6143fe913961eef743d8b1f9d32e3ef1fc0475f41572faf7800000000000000000000000000000000125742a15d9fe0d485807b4326579b5904c981b9c6ac1e38754379ee662063358f75277321e2624672e99be4be74f687000000000000000000000000000000001546d115c31454dabd79db911c558545c2c15488ce854d741502ff941883cc7d77b3e17a877ee78eb1bb2bc8fa0bf5c50000000000000000000000000000000018724e2b9a2f383329207ee85577805f35d5c5bb9f6903e3c962e57ab7eb9d1639d1e9adbde53499863b299f576325a000000000000000000000000000000000032e4fbb8dab462ff0352c2d3925b0e97ca662189129928ccc1714364e4f01d8b026887d808342091ad442b6e11635910000000000000000000000000000000004506802747afd8777904c46ad9bf0b06859a1b395ca3474a93ca4151ca158d2fd41b3a21e0ce0bc950b3241256e10d800000000000000000000000000000000115f41d2c173c3c2c7ecdff1a4aaa3c2e67c803db7a588d6143fe913961eef743d8b1f9d32e3ef1fc0475f41572faf7800000000000000000000000000000000125742a15d9fe0d485807b4326579b5904c981b9c6ac1e38754379ee662063358f75277321e2624672e99be4be74f687000000000000000000000000000000001546d115c31454dabd79db911c558545c2c15488ce854d741502ff941883cc7d77b3e17a877ee78eb1bb2bc8fa0bf5c5", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_55", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000010fcf5e5e478ac6442b218ce261878d8f61b405c0b9549512e23ead1f26a2240771993f8c039fbce4008a1707aeaaf25000000000000000000000000000000000f1afe9b199362f51cc84edb1d3cf2faf8e5bc0a734a646851ab83e213f73a3734114f255b611ec18db75694dcb0df910000000000000000000000000000000019cc0ec24da141f27b38a53aef0b3d93c4c2b981c1b248014be277002d39d7bde66f6957a659a89adcd3477dfe4f897a000000000000000000000000000000000e4c01d7425e35be84e3cf806aa76a079cf4557732980f7e8f8ce9a879483e28f223694ed8dd45706e12272f4c7952820000000000000000000000000000000008ceb842a17953578013ceee519a28ef1b37f73e13564def5ffe08a64dc53aa680784e26138176c89269477ee003d16700000000000000000000000000000000159791b6f2c26ed611ca40bfbd2059c15cfec9d073a84254ad9b509ef786d62d17fdc67ab13092cf0b7b3482866f4c320000000000000000000000000000000010fcf5e5e478ac6442b218ce261878d8f61b405c0b9549512e23ead1f26a2240771993f8c039fbce4008a1707aeaaf25000000000000000000000000000000000ae6134f1fec83a52e5358db260eb9dc6b918f7a803aae5715854ebee2b9bbecea9ab0d955f2e13e2c47a96b234ecb1a0000000000000000000000000000000019cc0ec24da141f27b38a53aef0b3d93c4c2b981c1b248014be277002d39d7bde66f6957a659a89adcd3477dfe4f897a000000000000000000000000000000000e4c01d7425e35be84e3cf806aa76a079cf4557732980f7e8f8ce9a879483e28f223694ed8dd45706e12272f4c7952820000000000000000000000000000000008ceb842a17953578013ceee519a28ef1b37f73e13564def5ffe08a64dc53aa680784e26138176c89269477ee003d16700000000000000000000000000000000159791b6f2c26ed611ca40bfbd2059c15cfec9d073a84254ad9b509ef786d62d17fdc67ab13092cf0b7b3482866f4c320000000000000000000000000000000010fcf5e5e478ac6442b218ce261878d8f61b405c0b9549512e23ead1f26a2240771993f8c039fbce4008a1707aeaaf25000000000000000000000000000000000f1afe9b199362f51cc84edb1d3cf2faf8e5bc0a734a646851ab83e213f73a3734114f255b611ec18db75694dcb0df910000000000000000000000000000000019cc0ec24da141f27b38a53aef0b3d93c4c2b981c1b248014be277002d39d7bde66f6957a659a89adcd3477dfe4f897a000000000000000000000000000000000e4c01d7425e35be84e3cf806aa76a079cf4557732980f7e8f8ce9a879483e28f223694ed8dd45706e12272f4c79528200000000000000000000000000000000113259a798069342cb07d8c7f1b183e8493f5446e02ec4d00732c9faa8ebbb7d9e33b1d89dd289372795b8811ffbd944000000000000000000000000000000000469803346bd77c4395166f6862b5316077881b47fdcd06ab9958201ff2a1ff706ae398400236d30ae83cb7d79905e790000000000000000000000000000000010fcf5e5e478ac6442b218ce261878d8f61b405c0b9549512e23ead1f26a2240771993f8c039fbce4008a1707aeaaf25000000000000000000000000000000000ae6134f1fec83a52e5358db260eb9dc6b918f7a803aae5715854ebee2b9bbecea9ab0d955f2e13e2c47a96b234ecb1a0000000000000000000000000000000019cc0ec24da141f27b38a53aef0b3d93c4c2b981c1b248014be277002d39d7bde66f6957a659a89adcd3477dfe4f897a000000000000000000000000000000000e4c01d7425e35be84e3cf806aa76a079cf4557732980f7e8f8ce9a879483e28f223694ed8dd45706e12272f4c79528200000000000000000000000000000000113259a798069342cb07d8c7f1b183e8493f5446e02ec4d00732c9faa8ebbb7d9e33b1d89dd289372795b8811ffbd944000000000000000000000000000000000469803346bd77c4395166f6862b5316077881b47fdcd06ab9958201ff2a1ff706ae398400236d30ae83cb7d79905e79", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_56", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000f75bc9feb74110697c9f353686910c6246e587dd71d744aab99917f1aea7165b41deb333e6bd14843f28b2232f799830000000000000000000000000000000019275491a51599736722295659dd5589f4e3f558e3d45137a66b4c8066c7514ae66ec35c862cd00bce809db528040c04000000000000000000000000000000000040d03956c821010969a67c91a6546800c5aa7ac392b16a9895136c941f4ca9f378c55446161562feace3b5b65f3c4f000000000000000000000000000000000e4b299f9fb25caec655d21c390bdad3c1256ca29faa33466a13aaa6d86310106d95fc8d8a0409fbd228fd3be7965cdf000000000000000000000000000000001272c63693873e1dabe2c2739310f627d3d9b5bcaa615402c3849ffd8dfe72b40fea4a068064655f2c8f46f074e6518d0000000000000000000000000000000000161a8e5e1de10938e5bce241ae73d76173022127822d744b23e656095c28f2f8d142ceb48b72a1dbc36b6143f8af95000000000000000000000000000000000f75bc9feb74110697c9f353686910c6246e587dd71d744aab99917f1aea7165b41deb333e6bd14843f28b2232f799830000000000000000000000000000000000d9bd58946a4d26e3f97e5fe96e574d6f93562c0fb0c187c0c586208fe9a4d9383d3ca22b272ff3eb7e624ad7fb9ea7000000000000000000000000000000000040d03956c821010969a67c91a6546800c5aa7ac392b16a9895136c941f4ca9f378c55446161562feace3b5b65f3c4f000000000000000000000000000000000e4b299f9fb25caec655d21c390bdad3c1256ca29faa33466a13aaa6d86310106d95fc8d8a0409fbd228fd3be7965cdf000000000000000000000000000000001272c63693873e1dabe2c2739310f627d3d9b5bcaa615402c3849ffd8dfe72b40fea4a068064655f2c8f46f074e6518d0000000000000000000000000000000000161a8e5e1de10938e5bce241ae73d76173022127822d744b23e656095c28f2f8d142ceb48b72a1dbc36b6143f8af95000000000000000000000000000000000f75bc9feb74110697c9f353686910c6246e587dd71d744aab99917f1aea7165b41deb333e6bd14843f28b2232f799830000000000000000000000000000000019275491a51599736722295659dd5589f4e3f558e3d45137a66b4c8066c7514ae66ec35c862cd00bce809db528040c04000000000000000000000000000000000040d03956c821010969a67c91a6546800c5aa7ac392b16a9895136c941f4ca9f378c55446161562feace3b5b65f3c4f000000000000000000000000000000000e4b299f9fb25caec655d21c390bdad3c1256ca29faa33466a13aaa6d86310106d95fc8d8a0409fbd228fd3be7965cdf00000000000000000000000000000000078e4bb3a5f8a87c9f38e542b03ab6af909d95c84923bebca3ac32a368b283700ec1b5f830ef9aa08d6fb90f8b19591e0000000000000000000000000000000019eaf75bdb6205911235ead4019d390003044963cc02e54b1c0cec4aed54cd3125dabd2ffcc88d5dde3b949ebc06fb16000000000000000000000000000000000f75bc9feb74110697c9f353686910c6246e587dd71d744aab99917f1aea7165b41deb333e6bd14843f28b2232f799830000000000000000000000000000000000d9bd58946a4d26e3f97e5fe96e574d6f93562c0fb0c187c0c586208fe9a4d9383d3ca22b272ff3eb7e624ad7fb9ea7000000000000000000000000000000000040d03956c821010969a67c91a6546800c5aa7ac392b16a9895136c941f4ca9f378c55446161562feace3b5b65f3c4f000000000000000000000000000000000e4b299f9fb25caec655d21c390bdad3c1256ca29faa33466a13aaa6d86310106d95fc8d8a0409fbd228fd3be7965cdf00000000000000000000000000000000078e4bb3a5f8a87c9f38e542b03ab6af909d95c84923bebca3ac32a368b283700ec1b5f830ef9aa08d6fb90f8b19591e0000000000000000000000000000000019eaf75bdb6205911235ead4019d390003044963cc02e54b1c0cec4aed54cd3125dabd2ffcc88d5dde3b949ebc06fb16", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_57", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000a87d0ccfb9c01148703d48993de04059d22a4cc48c5dabd2571ad4f7e60d6abfbcc5fb3bf363fd311fec675486c2a20000000000000000000000000000000000a896c5a84cbd03e52ae77000eb0285f5704993664a744a89ff6b346efd2efec1a519b67229a3b87e1f80e6aa17e2946000000000000000000000000000000000b50dc0957eccf5ad941b148a3824e82464bb7345a05125a0aa64f6ba34e34e767d4f679e9916faaacf82b3c79c9bddc00000000000000000000000000000000087152b3cb0db88776a7144fbafc1b210d150b637ca7148e3df600989231bce613fcf8e310fcc53aa2dc934bcbf86a220000000000000000000000000000000018a236ea02b1971d6e193a6eb92e1298956679d86864042fb6a0c36dd91c0e385944d779dedd0149fa8a1b3d6a07949d00000000000000000000000000000000048eac7d116b5a7906bce070e2b51ee7c4c493f1415abdb6fd2d35676036d3b741d14b7135419645a6906018e9d3f150000000000000000000000000000000000a87d0ccfb9c01148703d48993de04059d22a4cc48c5dabd2571ad4f7e60d6abfbcc5fb3bf363fd311fec675486c2a20000000000000000000000000000000000f77a58fb4b4165bf86d30b6349b84780d72b24e8eddce16c73a1f5a06de0638045a64978eb9c477d806f1955e818165000000000000000000000000000000000b50dc0957eccf5ad941b148a3824e82464bb7345a05125a0aa64f6ba34e34e767d4f679e9916faaacf82b3c79c9bddc00000000000000000000000000000000087152b3cb0db88776a7144fbafc1b210d150b637ca7148e3df600989231bce613fcf8e310fcc53aa2dc934bcbf86a220000000000000000000000000000000018a236ea02b1971d6e193a6eb92e1298956679d86864042fb6a0c36dd91c0e385944d779dedd0149fa8a1b3d6a07949d00000000000000000000000000000000048eac7d116b5a7906bce070e2b51ee7c4c493f1415abdb6fd2d35676036d3b741d14b7135419645a6906018e9d3f150000000000000000000000000000000000a87d0ccfb9c01148703d48993de04059d22a4cc48c5dabd2571ad4f7e60d6abfbcc5fb3bf363fd311fec675486c2a20000000000000000000000000000000000a896c5a84cbd03e52ae77000eb0285f5704993664a744a89ff6b346efd2efec1a519b67229a3b87e1f80e6aa17e2946000000000000000000000000000000000b50dc0957eccf5ad941b148a3824e82464bb7345a05125a0aa64f6ba34e34e767d4f679e9916faaacf82b3c79c9bddc00000000000000000000000000000000087152b3cb0db88776a7144fbafc1b210d150b637ca7148e3df600989231bce613fcf8e310fcc53aa2dc934bcbf86a2200000000000000000000000000000000015edb0036ce4f7cdd026d478a1d9a3ecf10d1ac8b210e8fb0900f331d94e7ebc5672884d276feb5bf74e4c295f8160e000000000000000000000000000000001572656d28148c21445ec74560968def9fb2b793b22a55086a039d39967a226cdcdab48d7c1269ba136e9fe7162bb95b000000000000000000000000000000000a87d0ccfb9c01148703d48993de04059d22a4cc48c5dabd2571ad4f7e60d6abfbcc5fb3bf363fd311fec675486c2a20000000000000000000000000000000000f77a58fb4b4165bf86d30b6349b84780d72b24e8eddce16c73a1f5a06de0638045a64978eb9c477d806f1955e818165000000000000000000000000000000000b50dc0957eccf5ad941b148a3824e82464bb7345a05125a0aa64f6ba34e34e767d4f679e9916faaacf82b3c79c9bddc00000000000000000000000000000000087152b3cb0db88776a7144fbafc1b210d150b637ca7148e3df600989231bce613fcf8e310fcc53aa2dc934bcbf86a2200000000000000000000000000000000015edb0036ce4f7cdd026d478a1d9a3ecf10d1ac8b210e8fb0900f331d94e7ebc5672884d276feb5bf74e4c295f8160e000000000000000000000000000000001572656d28148c21445ec74560968def9fb2b793b22a55086a039d39967a226cdcdab48d7c1269ba136e9fe7162bb95b", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_58", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000d35ffa284655a94c3050213f4f14e927c162818bbfd0480bad2e07000dd3081274056715c96408f243589d83365c9f20000000000000000000000000000000001450bddfa14033ed8cdb94386715013ed9b2c4f9d65944e9d32c0b3545a085113e173e5afcfccb78878414a464d318400000000000000000000000000000000094fdcc2119b4f674b5639653dfabcac59c2adb1ee2ec06c55c3f148c9361351ff0acb2519e4638cb2cde98efaec8f4400000000000000000000000000000000051d5edcbd6eadac808222f0423bada165fcb98f98a89f335c981262b0ca7ea1c536d41aa41b49b25f0c43f53c95384000000000000000000000000000000000003c96c6f20d7ac31ee7ca77d11e8d25ea78cdf13e5f4d317752320e059e19196f14c15b5a18ca712f3a7cc6f09be6d4000000000000000000000000000000000ebd71f61fcddf1652675f577bbaeec26b892dd954965b057ffb431d6e37cc5425a2a42a0059482c2bd75adb2a120b0b000000000000000000000000000000000d35ffa284655a94c3050213f4f14e927c162818bbfd0480bad2e07000dd3081274056715c96408f243589d83365c9f20000000000000000000000000000000018bc060c3f6be35b724dee72bcda5cc376dc1f35561f7e70c9fe11eda256edd30aca8c19018433483186beb5b9b2792700000000000000000000000000000000094fdcc2119b4f674b5639653dfabcac59c2adb1ee2ec06c55c3f148c9361351ff0acb2519e4638cb2cde98efaec8f4400000000000000000000000000000000051d5edcbd6eadac808222f0423bada165fcb98f98a89f335c981262b0ca7ea1c536d41aa41b49b25f0c43f53c95384000000000000000000000000000000000003c96c6f20d7ac31ee7ca77d11e8d25ea78cdf13e5f4d317752320e059e19196f14c15b5a18ca712f3a7cc6f09be6d4000000000000000000000000000000000ebd71f61fcddf1652675f577bbaeec26b892dd954965b057ffb431d6e37cc5425a2a42a0059482c2bd75adb2a120b0b000000000000000000000000000000000d35ffa284655a94c3050213f4f14e927c162818bbfd0480bad2e07000dd3081274056715c96408f243589d83365c9f20000000000000000000000000000000001450bddfa14033ed8cdb94386715013ed9b2c4f9d65944e9d32c0b3545a085113e173e5afcfccb78878414a464d318400000000000000000000000000000000094fdcc2119b4f674b5639653dfabcac59c2adb1ee2ec06c55c3f148c9361351ff0acb2519e4638cb2cde98efaec8f4400000000000000000000000000000000051d5edcbd6eadac808222f0423bada165fcb98f98a89f335c981262b0ca7ea1c536d41aa41b49b25f0c43f53c9538400000000000000000000000000000000019c47b2347726bd72c33dd3e722d1fb179fe7d93b525c58defdea092f112dd0aaf973ea3573b358e8ac483390f63c3d7000000000000000000000000000000000b439ff419b20783f8b4485ec790be14f8ee1dab9eeeb7b9e7358f83887929cff9095bd4b0fab7d38e27a524d5ed9fa0000000000000000000000000000000000d35ffa284655a94c3050213f4f14e927c162818bbfd0480bad2e07000dd3081274056715c96408f243589d83365c9f20000000000000000000000000000000018bc060c3f6be35b724dee72bcda5cc376dc1f35561f7e70c9fe11eda256edd30aca8c19018433483186beb5b9b2792700000000000000000000000000000000094fdcc2119b4f674b5639653dfabcac59c2adb1ee2ec06c55c3f148c9361351ff0acb2519e4638cb2cde98efaec8f4400000000000000000000000000000000051d5edcbd6eadac808222f0423bada165fcb98f98a89f335c981262b0ca7ea1c536d41aa41b49b25f0c43f53c9538400000000000000000000000000000000019c47b2347726bd72c33dd3e722d1fb179fe7d93b525c58defdea092f112dd0aaf973ea3573b358e8ac483390f63c3d7000000000000000000000000000000000b439ff419b20783f8b4485ec790be14f8ee1dab9eeeb7b9e7358f83887929cff9095bd4b0fab7d38e27a524d5ed9fa0", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_59", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000344cafaca754db423544657de1b77025164ccc702f8d45697fb73602302a3cb4511c38f0a76a37415d683398f35556500000000000000000000000000000000120935947070451885bf0c328bd83def193831ab9353844a01130074f16a1ff4d20df8459b5ad6a57d5f1959d37aae920000000000000000000000000000000014b0862ac988a169342a4abacfebc5e7e7e8f8ff1166c6ca8fa53613c5fc28fd8b02d9c8d5e7a264b2fa59cd33a0f33c000000000000000000000000000000000f0f79631e7790192c18187144388373d52653cf11dd076688877fa9b5cf58e65fe4332874c301563089b9b3fa2322e4000000000000000000000000000000000174ffb89d7715866562d9882acb81ce40758644ca3e0decd546c8f5c349b24fce88214956e7540fac36bcfc105cf34a0000000000000000000000000000000003e06c5f607ccf1e2991828034fcdf91106295e7174b4dca21926169451ee58e737d535af45073e2378206e03c81c421000000000000000000000000000000000344cafaca754db423544657de1b77025164ccc702f8d45697fb73602302a3cb4511c38f0a76a37415d683398f3555650000000000000000000000000000000007f7dc55c90fa181c55c9b83b7736ee84b3f19d960318e75661dd22c0546d62f4c9e07b915f9295a3c9fe6a62c84fc190000000000000000000000000000000014b0862ac988a169342a4abacfebc5e7e7e8f8ff1166c6ca8fa53613c5fc28fd8b02d9c8d5e7a264b2fa59cd33a0f33c000000000000000000000000000000000f0f79631e7790192c18187144388373d52653cf11dd076688877fa9b5cf58e65fe4332874c301563089b9b3fa2322e4000000000000000000000000000000000174ffb89d7715866562d9882acb81ce40758644ca3e0decd546c8f5c349b24fce88214956e7540fac36bcfc105cf34a0000000000000000000000000000000003e06c5f607ccf1e2991828034fcdf91106295e7174b4dca21926169451ee58e737d535af45073e2378206e03c81c421000000000000000000000000000000000344cafaca754db423544657de1b77025164ccc702f8d45697fb73602302a3cb4511c38f0a76a37415d683398f35556500000000000000000000000000000000120935947070451885bf0c328bd83def193831ab9353844a01130074f16a1ff4d20df8459b5ad6a57d5f1959d37aae920000000000000000000000000000000014b0862ac988a169342a4abacfebc5e7e7e8f8ff1166c6ca8fa53613c5fc28fd8b02d9c8d5e7a264b2fa59cd33a0f33c000000000000000000000000000000000f0f79631e7790192c18187144388373d52653cf11dd076688877fa9b5cf58e65fe4332874c301563089b9b3fa2322e400000000000000000000000000000000188c12319c08d113e5b8ce2e18802b092401c540294704d291ea09ab336743d45023deb55a6cabf00dc84303efa2b761000000000000000000000000000000001620a58ad903177c218a25360e4ecd465414b59ddc39c4f5459e7137b1921095ab2eaca3bd038c1d827cf91fc37de68a000000000000000000000000000000000344cafaca754db423544657de1b77025164ccc702f8d45697fb73602302a3cb4511c38f0a76a37415d683398f3555650000000000000000000000000000000007f7dc55c90fa181c55c9b83b7736ee84b3f19d960318e75661dd22c0546d62f4c9e07b915f9295a3c9fe6a62c84fc190000000000000000000000000000000014b0862ac988a169342a4abacfebc5e7e7e8f8ff1166c6ca8fa53613c5fc28fd8b02d9c8d5e7a264b2fa59cd33a0f33c000000000000000000000000000000000f0f79631e7790192c18187144388373d52653cf11dd076688877fa9b5cf58e65fe4332874c301563089b9b3fa2322e400000000000000000000000000000000188c12319c08d113e5b8ce2e18802b092401c540294704d291ea09ab336743d45023deb55a6cabf00dc84303efa2b761000000000000000000000000000000001620a58ad903177c218a25360e4ecd465414b59ddc39c4f5459e7137b1921095ab2eaca3bd038c1d827cf91fc37de68a", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_60", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008797f704442e133d3b77a5f0020aa304d36ce326ea75ca47e041e4d8a721754e0579ce82b96a69142cb7185998d18ce00000000000000000000000000000000144f438d86d1d808d528ea60c5d343b427124af6e43d4d9652368ddc508daab32fd9c9425cba44fba72e3449e366b1700000000000000000000000000000000006a3a773638c0b4a13e7ea399ac319f5ea55ed533aca32a933d69d8198ae997a66d1e32a02683e7fc5c1ec597106848f00000000000000000000000000000000155ef036f60a5b11697581265293cc4c6eebd3fdf500540529b6997c27a3be31212aee5cdfea6cd95d6d5bf83a8ce5aa000000000000000000000000000000000b15d92f2301075ab0e3215aa72cf9b130bc8e1bcd9fa36375c4b9d7da430ae3e2b24f417336d8729f44542ee7f561d300000000000000000000000000000000197d90090501e8cdea28eb7963231f1a7b5f716cc3a086acb6e7626600d6544132cac943e8d5cefb5daf0a2f8d4006290000000000000000000000000000000008797f704442e133d3b77a5f0020aa304d36ce326ea75ca47e041e4d8a721754e0579ce82b96a69142cb7185998d18ce0000000000000000000000000000000005b1ce5cb2ae0e9175f2bd557d7869233d65008e0f47c52914fa44c4a6234b70eed236bc5499bb0412d0cbb61c98f93b0000000000000000000000000000000006a3a773638c0b4a13e7ea399ac319f5ea55ed533aca32a933d69d8198ae997a66d1e32a02683e7fc5c1ec597106848f00000000000000000000000000000000155ef036f60a5b11697581265293cc4c6eebd3fdf500540529b6997c27a3be31212aee5cdfea6cd95d6d5bf83a8ce5aa000000000000000000000000000000000b15d92f2301075ab0e3215aa72cf9b130bc8e1bcd9fa36375c4b9d7da430ae3e2b24f417336d8729f44542ee7f561d300000000000000000000000000000000197d90090501e8cdea28eb7963231f1a7b5f716cc3a086acb6e7626600d6544132cac943e8d5cefb5daf0a2f8d4006290000000000000000000000000000000008797f704442e133d3b77a5f0020aa304d36ce326ea75ca47e041e4d8a721754e0579ce82b96a69142cb7185998d18ce00000000000000000000000000000000144f438d86d1d808d528ea60c5d343b427124af6e43d4d9652368ddc508daab32fd9c9425cba44fba72e3449e366b1700000000000000000000000000000000006a3a773638c0b4a13e7ea399ac319f5ea55ed533aca32a933d69d8198ae997a66d1e32a02683e7fc5c1ec597106848f00000000000000000000000000000000155ef036f60a5b11697581265293cc4c6eebd3fdf500540529b6997c27a3be31212aee5cdfea6cd95d6d5bf83a8ce5aa000000000000000000000000000000000eeb38bb167edf3f9a38865b9c1eb32633babd6925e56f5bf16c18c91c6deb403bf9b0bd3e1d278d1abaabd1180a48d800000000000000000000000000000000008381e1347dfdcc60f2bc3ce0288dbce917da182fe48c12b049703af5daa1e2ebe136bac87e31045c4ff5d072bfa4820000000000000000000000000000000008797f704442e133d3b77a5f0020aa304d36ce326ea75ca47e041e4d8a721754e0579ce82b96a69142cb7185998d18ce0000000000000000000000000000000005b1ce5cb2ae0e9175f2bd557d7869233d65008e0f47c52914fa44c4a6234b70eed236bc5499bb0412d0cbb61c98f93b0000000000000000000000000000000006a3a773638c0b4a13e7ea399ac319f5ea55ed533aca32a933d69d8198ae997a66d1e32a02683e7fc5c1ec597106848f00000000000000000000000000000000155ef036f60a5b11697581265293cc4c6eebd3fdf500540529b6997c27a3be31212aee5cdfea6cd95d6d5bf83a8ce5aa000000000000000000000000000000000eeb38bb167edf3f9a38865b9c1eb32633babd6925e56f5bf16c18c91c6deb403bf9b0bd3e1d278d1abaabd1180a48d800000000000000000000000000000000008381e1347dfdcc60f2bc3ce0288dbce917da182fe48c12b049703af5daa1e2ebe136bac87e31045c4ff5d072bfa482", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_61", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000000707c711f77bb425cddc71ecf96a18b6eb0bed7f012c4f6cc9431003f2e1ac17f7c1f68c4965a4fcc273a3db93451d000000000000000000000000000000001211464c91c7e78b00fe156da874407e4eeb7f422dbd698effb9a83357bf226d3f189f2db541eb17db3ed555084e91ec0000000000000000000000000000000006a90568fa25b401756e3f86b5300c4d3b626dc6274f4685e8a9f56ec5ca2afce36a1fdc6d3414edc8780c4e650f10dc0000000000000000000000000000000012e41e8e0dd10b3ee31fa866753aa5d9db7669153b141114cdb2ef7fa6df5db27aef0cc70e76a741eae504b038ecf2300000000000000000000000000000000005c35f3372f1ec9845bd04ea722fbed2be1388abf59e622dd3dafb4b3af49bc5fba9e20235e7e58973fedf4b8b720691000000000000000000000000000000001111d18d621070509805d306a31c109701288fd55d4c0644349deb080c6591b6e852b4f7e009b80019513de7f2fce17d00000000000000000000000000000000000707c711f77bb425cddc71ecf96a18b6eb0bed7f012c4f6cc9431003f2e1ac17f7c1f68c4965a4fcc273a3db93451d0000000000000000000000000000000007efcb9da7b7ff0f4a1d92489ad76c59158bcc42c5c7a93067772a6d9ef1d3b6df9360d0fc1214e7dec02aaaf7b118bf0000000000000000000000000000000006a90568fa25b401756e3f86b5300c4d3b626dc6274f4685e8a9f56ec5ca2afce36a1fdc6d3414edc8780c4e650f10dc0000000000000000000000000000000012e41e8e0dd10b3ee31fa866753aa5d9db7669153b141114cdb2ef7fa6df5db27aef0cc70e76a741eae504b038ecf2300000000000000000000000000000000005c35f3372f1ec9845bd04ea722fbed2be1388abf59e622dd3dafb4b3af49bc5fba9e20235e7e58973fedf4b8b720691000000000000000000000000000000001111d18d621070509805d306a31c109701288fd55d4c0644349deb080c6591b6e852b4f7e009b80019513de7f2fce17d00000000000000000000000000000000000707c711f77bb425cddc71ecf96a18b6eb0bed7f012c4f6cc9431003f2e1ac17f7c1f68c4965a4fcc273a3db93451d000000000000000000000000000000001211464c91c7e78b00fe156da874407e4eeb7f422dbd698effb9a83357bf226d3f189f2db541eb17db3ed555084e91ec0000000000000000000000000000000006a90568fa25b401756e3f86b5300c4d3b626dc6274f4685e8a9f56ec5ca2afce36a1fdc6d3414edc8780c4e650f10dc0000000000000000000000000000000012e41e8e0dd10b3ee31fa866753aa5d9db7669153b141114cdb2ef7fa6df5db27aef0cc70e76a741eae504b038ecf23000000000000000000000000000000000143db2b6c68dfa02055ea2cbd11bee04a663c2d8fde6b0919355d755bbbc5a5e23021dfc7b6c1a76460020b4748da41a0000000000000000000000000000000008ef405cd76f7649b315d4afa02f9c40634ebbaf96390c7b3292e798ea4b646d36594b06d14a47ffa0adc2180d02c92e00000000000000000000000000000000000707c711f77bb425cddc71ecf96a18b6eb0bed7f012c4f6cc9431003f2e1ac17f7c1f68c4965a4fcc273a3db93451d0000000000000000000000000000000007efcb9da7b7ff0f4a1d92489ad76c59158bcc42c5c7a93067772a6d9ef1d3b6df9360d0fc1214e7dec02aaaf7b118bf0000000000000000000000000000000006a90568fa25b401756e3f86b5300c4d3b626dc6274f4685e8a9f56ec5ca2afce36a1fdc6d3414edc8780c4e650f10dc0000000000000000000000000000000012e41e8e0dd10b3ee31fa866753aa5d9db7669153b141114cdb2ef7fa6df5db27aef0cc70e76a741eae504b038ecf23000000000000000000000000000000000143db2b6c68dfa02055ea2cbd11bee04a663c2d8fde6b0919355d755bbbc5a5e23021dfc7b6c1a76460020b4748da41a0000000000000000000000000000000008ef405cd76f7649b315d4afa02f9c40634ebbaf96390c7b3292e798ea4b646d36594b06d14a47ffa0adc2180d02c92e", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_62", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000004b3c0e8b240b79c55f02833c2c20fa158e35c941e9e8e48247b96cb1d4923641b97e766637a3ced9fbef275ca9bd1ea000000000000000000000000000000000b4e7355aea3488234552d3dddfa2d1ad3164056407770e6c54f764193c9dc044cb7f2b157a1c4153b2045867d6f99c5000000000000000000000000000000001310a8cebed1491bb6399abe3a08fb25ad6ca00feb5db62069bc5bd45a57c167aaf06a628a3f18aa990bb389173855b100000000000000000000000000000000134655489380a9ae9cfbc3f4c6a1aa5b6dbe0a994e681915602c1d197c54bf3da6fb2df54eec3634ea87bf3fa92a69740000000000000000000000000000000000e7e532ee4b892af39f8a3db7a05cc77a6eb0b3d977c17076bac4a52d5ba003a0ac1f902a4257791a45370eb88426a70000000000000000000000000000000016a556050e4905fa74b5061e3874f05cc7a6c5b049bd3bb7c34adef5a77c393239a600542a4401c3e61978ee6515a30e0000000000000000000000000000000004b3c0e8b240b79c55f02833c2c20fa158e35c941e9e8e48247b96cb1d4923641b97e766637a3ced9fbef275ca9bd1ea000000000000000000000000000000000eb29e948adc9e1816c67a7865517fbc91610b2eb30da1d8a1e15c5f62e71a1fd1f40d4d59b23bea7edeba79829010e6000000000000000000000000000000001310a8cebed1491bb6399abe3a08fb25ad6ca00feb5db62069bc5bd45a57c167aaf06a628a3f18aa990bb389173855b100000000000000000000000000000000134655489380a9ae9cfbc3f4c6a1aa5b6dbe0a994e681915602c1d197c54bf3da6fb2df54eec3634ea87bf3fa92a69740000000000000000000000000000000000e7e532ee4b892af39f8a3db7a05cc77a6eb0b3d977c17076bac4a52d5ba003a0ac1f902a4257791a45370eb88426a70000000000000000000000000000000016a556050e4905fa74b5061e3874f05cc7a6c5b049bd3bb7c34adef5a77c393239a600542a4401c3e61978ee6515a30e0000000000000000000000000000000004b3c0e8b240b79c55f02833c2c20fa158e35c941e9e8e48247b96cb1d4923641b97e766637a3ced9fbef275ca9bd1ea000000000000000000000000000000000b4e7355aea3488234552d3dddfa2d1ad3164056407770e6c54f764193c9dc044cb7f2b157a1c4153b2045867d6f99c5000000000000000000000000000000001310a8cebed1491bb6399abe3a08fb25ad6ca00feb5db62069bc5bd45a57c167aaf06a628a3f18aa990bb389173855b100000000000000000000000000000000134655489380a9ae9cfbc3f4c6a1aa5b6dbe0a994e681915602c1d197c54bf3da6fb2df54eec3634ea87bf3fa92a69740000000000000000000000000000000019192cb74b345d6f577c1d788bab500fea089ad11a0d514ef0760dfbc95556207dffe06e8711a8869fb9c8f1477b840400000000000000000000000000000000035bbbe52b36e09fd666a1980ad6bc7a9cd085d4a9c7d707a3e5f3ab4f34bcf1e505ffaa870ffe3bd3e587119aea079d0000000000000000000000000000000004b3c0e8b240b79c55f02833c2c20fa158e35c941e9e8e48247b96cb1d4923641b97e766637a3ced9fbef275ca9bd1ea000000000000000000000000000000000eb29e948adc9e1816c67a7865517fbc91610b2eb30da1d8a1e15c5f62e71a1fd1f40d4d59b23bea7edeba79829010e6000000000000000000000000000000001310a8cebed1491bb6399abe3a08fb25ad6ca00feb5db62069bc5bd45a57c167aaf06a628a3f18aa990bb389173855b100000000000000000000000000000000134655489380a9ae9cfbc3f4c6a1aa5b6dbe0a994e681915602c1d197c54bf3da6fb2df54eec3634ea87bf3fa92a69740000000000000000000000000000000019192cb74b345d6f577c1d788bab500fea089ad11a0d514ef0760dfbc95556207dffe06e8711a8869fb9c8f1477b840400000000000000000000000000000000035bbbe52b36e09fd666a1980ad6bc7a9cd085d4a9c7d707a3e5f3ab4f34bcf1e505ffaa870ffe3bd3e587119aea079d", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_63", - "Gas": 207000, + "Gas": 237000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001465358836eb5c6e173e425f675aa231f9c62e9b122584078f2ab9af7440a4ce4ac2cd21ce35a0017b01e4913b40f73d00000000000000000000000000000000170e2da3bca3d0a8659e31df4d8a3a73e681c22beb21577bea6bbc3de1cabff8a1db28b51fdd46ba906767b69db2f679000000000000000000000000000000001360612f80227a2fc50a2dbdb3a49db16bd9f0ae401e2fb69408d990284cec05a1c29696f98b16d83a3dab6eac8678310000000000000000000000000000000001223232338ce1ac91e28b4c00ef4e3561f21f34fc405e479599cced3a86b7c36f541370bfd0176f785326f741699d2900000000000000000000000000000000179c34ba9578d5ff90272a2c7f756794670a047f79a53215da69937152bad0f86576945b12176d3e13cac38d26335c51000000000000000000000000000000000dcc715907e4e17824e24c1f513c09597965941e3ed0aaad6d0c59029b54fb039d716a998c9c418110bd49c5e365507f000000000000000000000000000000001465358836eb5c6e173e425f675aa231f9c62e9b122584078f2ab9af7440a4ce4ac2cd21ce35a0017b01e4913b40f73d0000000000000000000000000000000002f2e4467cdc15f1e57d75d6f5c172637df589590863bb437cc5166314e6362b7cd0d7499176b94529979849624cb432000000000000000000000000000000001360612f80227a2fc50a2dbdb3a49db16bd9f0ae401e2fb69408d990284cec05a1c29696f98b16d83a3dab6eac8678310000000000000000000000000000000001223232338ce1ac91e28b4c00ef4e3561f21f34fc405e479599cced3a86b7c36f541370bfd0176f785326f741699d2900000000000000000000000000000000179c34ba9578d5ff90272a2c7f756794670a047f79a53215da69937152bad0f86576945b12176d3e13cac38d26335c51000000000000000000000000000000000dcc715907e4e17824e24c1f513c09597965941e3ed0aaad6d0c59029b54fb039d716a998c9c418110bd49c5e365507f000000000000000000000000000000001465358836eb5c6e173e425f675aa231f9c62e9b122584078f2ab9af7440a4ce4ac2cd21ce35a0017b01e4913b40f73d00000000000000000000000000000000170e2da3bca3d0a8659e31df4d8a3a73e681c22beb21577bea6bbc3de1cabff8a1db28b51fdd46ba906767b69db2f679000000000000000000000000000000001360612f80227a2fc50a2dbdb3a49db16bd9f0ae401e2fb69408d990284cec05a1c29696f98b16d83a3dab6eac8678310000000000000000000000000000000001223232338ce1ac91e28b4c00ef4e3561f21f34fc405e479599cced3a86b7c36f541370bfd0176f785326f741699d29000000000000000000000000000000000264dd2fa407109abaf47d89c3d64542fd6d470579dfe0a98cc73f2fa3f6252bb9356ba39f3c92c1a6343c72d9cc4e5a000000000000000000000000000000000c34a091319b052226395b96f20fa37deb11b766b4b46811fa24799e5b5bfb20813a956524b7be7ea941b63a1c9a5a2c000000000000000000000000000000001465358836eb5c6e173e425f675aa231f9c62e9b122584078f2ab9af7440a4ce4ac2cd21ce35a0017b01e4913b40f73d0000000000000000000000000000000002f2e4467cdc15f1e57d75d6f5c172637df589590863bb437cc5166314e6362b7cd0d7499176b94529979849624cb432000000000000000000000000000000001360612f80227a2fc50a2dbdb3a49db16bd9f0ae401e2fb69408d990284cec05a1c29696f98b16d83a3dab6eac8678310000000000000000000000000000000001223232338ce1ac91e28b4c00ef4e3561f21f34fc405e479599cced3a86b7c36f541370bfd0176f785326f741699d29000000000000000000000000000000000264dd2fa407109abaf47d89c3d64542fd6d470579dfe0a98cc73f2fa3f6252bb9356ba39f3c92c1a6343c72d9cc4e5a000000000000000000000000000000000c34a091319b052226395b96f20fa37deb11b766b4b46811fa24799e5b5bfb20813a956524b7be7ea941b63a1c9a5a2c000000000000000000000000000000001465358836eb5c6e173e425f675aa231f9c62e9b122584078f2ab9af7440a4ce4ac2cd21ce35a0017b01e4913b40f73d00000000000000000000000000000000170e2da3bca3d0a8659e31df4d8a3a73e681c22beb21577bea6bbc3de1cabff8a1db28b51fdd46ba906767b69db2f679000000000000000000000000000000001360612f80227a2fc50a2dbdb3a49db16bd9f0ae401e2fb69408d990284cec05a1c29696f98b16d83a3dab6eac8678310000000000000000000000000000000001223232338ce1ac91e28b4c00ef4e3561f21f34fc405e479599cced3a86b7c36f541370bfd0176f785326f741699d2900000000000000000000000000000000179c34ba9578d5ff90272a2c7f756794670a047f79a53215da69937152bad0f86576945b12176d3e13cac38d26335c51000000000000000000000000000000000dcc715907e4e17824e24c1f513c09597965941e3ed0aaad6d0c59029b54fb039d716a998c9c418110bd49c5e365507f", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_64", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000ab6e2a649ed97be4574603b3b4a210f0748d8cddf132079e0543ec776ceb63902e48598b7698cf79fd5130cebaf0250000000000000000000000000000000000d55b3115d2bfcd1b93c631a71b2356c887b32452aae53ffd01a719121d58834be1e0fa4f22a01bbde0d40f55ad38f2c0000000000000000000000000000000002fec3b2e25d9300b9757cbe77857d7220d91a53fc29f3b7a0da5c4e0815882d1cc51a40a60fa8e1ae01296c209eda0a00000000000000000000000000000000041ff1a77aca41f7aaeec13fb5238c24d038e2e566b611203c430d7ac6251d545ed4a60e9e0087d6baa36272c7b1c853000000000000000000000000000000001643567a0f22b90fefee96c8e2f5851623384c2c68bce9589cdf64c933d494a8d805edce2fd18a6db80f4819391dd1f9000000000000000000000000000000000e4e40ab1969bf9f00ee3b984947ae95bf7b9579bdaeeee926638f9566f8ab26debb4c8d4009535cb6422b2c2ab7282d000000000000000000000000000000000ab6e2a649ed97be4574603b3b4a210f0748d8cddf132079e0543ec776ceb63902e48598b7698cf79fd5130cebaf0250000000000000000000000000000000000cab5ed8dc53e9c891df449bd199776adbfc193fc8d6bebf9716610fd4db6def608df059bf29fe43dbf1bf0aa52c1b7f0000000000000000000000000000000002fec3b2e25d9300b9757cbe77857d7220d91a53fc29f3b7a0da5c4e0815882d1cc51a40a60fa8e1ae01296c209eda0a00000000000000000000000000000000041ff1a77aca41f7aaeec13fb5238c24d038e2e566b611203c430d7ac6251d545ed4a60e9e0087d6baa36272c7b1c853000000000000000000000000000000001643567a0f22b90fefee96c8e2f5851623384c2c68bce9589cdf64c933d494a8d805edce2fd18a6db80f4819391dd1f9000000000000000000000000000000000e4e40ab1969bf9f00ee3b984947ae95bf7b9579bdaeeee926638f9566f8ab26debb4c8d4009535cb6422b2c2ab7282d000000000000000000000000000000000ab6e2a649ed97be4574603b3b4a210f0748d8cddf132079e0543ec776ceb63902e48598b7698cf79fd5130cebaf0250000000000000000000000000000000000d55b3115d2bfcd1b93c631a71b2356c887b32452aae53ffd01a719121d58834be1e0fa4f22a01bbde0d40f55ad38f2c0000000000000000000000000000000002fec3b2e25d9300b9757cbe77857d7220d91a53fc29f3b7a0da5c4e0815882d1cc51a40a60fa8e1ae01296c209eda0a00000000000000000000000000000000041ff1a77aca41f7aaeec13fb5238c24d038e2e566b611203c430d7ac6251d545ed4a60e9e0087d6baa36272c7b1c8530000000000000000000000000000000003bdbb702a5d2d8a5b2d10ed605627c1413eff588ac82966ca516dd7c2dc617b46a612308182759201efb7e6c6e1d8b2000000000000000000000000000000000bb2d13f201626fb4a2d6c1dfa03fe41a4fbb60b35d623d640cd430b8fb84afd3ff0b371714aaca303bcd4d3d548827e000000000000000000000000000000000ab6e2a649ed97be4574603b3b4a210f0748d8cddf132079e0543ec776ceb63902e48598b7698cf79fd5130cebaf0250000000000000000000000000000000000cab5ed8dc53e9c891df449bd199776adbfc193fc8d6bebf9716610fd4db6def608df059bf29fe43dbf1bf0aa52c1b7f0000000000000000000000000000000002fec3b2e25d9300b9757cbe77857d7220d91a53fc29f3b7a0da5c4e0815882d1cc51a40a60fa8e1ae01296c209eda0a00000000000000000000000000000000041ff1a77aca41f7aaeec13fb5238c24d038e2e566b611203c430d7ac6251d545ed4a60e9e0087d6baa36272c7b1c8530000000000000000000000000000000003bdbb702a5d2d8a5b2d10ed605627c1413eff588ac82966ca516dd7c2dc617b46a612308182759201efb7e6c6e1d8b2000000000000000000000000000000000bb2d13f201626fb4a2d6c1dfa03fe41a4fbb60b35d623d640cd430b8fb84afd3ff0b371714aaca303bcd4d3d548827e000000000000000000000000000000000ab6e2a649ed97be4574603b3b4a210f0748d8cddf132079e0543ec776ceb63902e48598b7698cf79fd5130cebaf0250000000000000000000000000000000000d55b3115d2bfcd1b93c631a71b2356c887b32452aae53ffd01a719121d58834be1e0fa4f22a01bbde0d40f55ad38f2c0000000000000000000000000000000002fec3b2e25d9300b9757cbe77857d7220d91a53fc29f3b7a0da5c4e0815882d1cc51a40a60fa8e1ae01296c209eda0a00000000000000000000000000000000041ff1a77aca41f7aaeec13fb5238c24d038e2e566b611203c430d7ac6251d545ed4a60e9e0087d6baa36272c7b1c853000000000000000000000000000000001643567a0f22b90fefee96c8e2f5851623384c2c68bce9589cdf64c933d494a8d805edce2fd18a6db80f4819391dd1f9000000000000000000000000000000000e4e40ab1969bf9f00ee3b984947ae95bf7b9579bdaeeee926638f9566f8ab26debb4c8d4009535cb6422b2c2ab7282d", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_65", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001654e99ebd103ed5709ae412a6df1751add90d4d56025667a4640c1d51435e7cad5464ff2c8b08cca56e34517b05acf10000000000000000000000000000000004d8353f55fdfb2407e80e881a5e57672fbcf7712dcec4cb583dbd93cf3f1052511fdee20f338a387690da7d69f4f6f700000000000000000000000000000000123a19e1427bac55eabdaec2aeeefadfca6e2b7581a5726c393bede2efd78af04e6cb986aa8d8d5c845bbbc28d62e7a00000000000000000000000000000000018026687f43591dac03a16fce0c4b8020469ec309bdbf9f0f270cf75e262abf4ae55d46f0b4ff130b7bbe2430bd0c9f4000000000000000000000000000000000a27fe0a29c761ce29a731ead969b1db3ae9ef4c05493cc370a128d97ef956c55d9a500991b3e7bf9600383633778ebb000000000000000000000000000000000dbb997ef4970a472bfcf03e959acb90bb13671a3d27c91698975a407856505e93837f46afc965363f21c35a3d194ec0000000000000000000000000000000001654e99ebd103ed5709ae412a6df1751add90d4d56025667a4640c1d51435e7cad5464ff2c8b08cca56e34517b05acf1000000000000000000000000000000001528dcaae381eb764333992e28ed557034ba5413c5b64df40ef3150d2771e5d1cd8c211ca22075c7436e2582960ab3b400000000000000000000000000000000123a19e1427bac55eabdaec2aeeefadfca6e2b7581a5726c393bede2efd78af04e6cb986aa8d8d5c845bbbc28d62e7a00000000000000000000000000000000018026687f43591dac03a16fce0c4b8020469ec309bdbf9f0f270cf75e262abf4ae55d46f0b4ff130b7bbe2430bd0c9f4000000000000000000000000000000000a27fe0a29c761ce29a731ead969b1db3ae9ef4c05493cc370a128d97ef956c55d9a500991b3e7bf9600383633778ebb000000000000000000000000000000000dbb997ef4970a472bfcf03e959acb90bb13671a3d27c91698975a407856505e93837f46afc965363f21c35a3d194ec0000000000000000000000000000000001654e99ebd103ed5709ae412a6df1751add90d4d56025667a4640c1d51435e7cad5464ff2c8b08cca56e34517b05acf10000000000000000000000000000000004d8353f55fdfb2407e80e881a5e57672fbcf7712dcec4cb583dbd93cf3f1052511fdee20f338a387690da7d69f4f6f700000000000000000000000000000000123a19e1427bac55eabdaec2aeeefadfca6e2b7581a5726c393bede2efd78af04e6cb986aa8d8d5c845bbbc28d62e7a00000000000000000000000000000000018026687f43591dac03a16fce0c4b8020469ec309bdbf9f0f270cf75e262abf4ae55d46f0b4ff130b7bbe2430bd0c9f4000000000000000000000000000000000fd913e00fb884cc217475cb69e1fafc298d5c38ee3bd5fbf68fa9c777b79f5ec111aff51fa0184023fec7c9cc881bf0000000000000000000000000000000000c45786b44e8dc531f1eb777adb0e146a963e46ab65d49a8ce9978607e5aa5c58b2880b8018a9ac97add3ca5c2e65beb000000000000000000000000000000001654e99ebd103ed5709ae412a6df1751add90d4d56025667a4640c1d51435e7cad5464ff2c8b08cca56e34517b05acf1000000000000000000000000000000001528dcaae381eb764333992e28ed557034ba5413c5b64df40ef3150d2771e5d1cd8c211ca22075c7436e2582960ab3b400000000000000000000000000000000123a19e1427bac55eabdaec2aeeefadfca6e2b7581a5726c393bede2efd78af04e6cb986aa8d8d5c845bbbc28d62e7a00000000000000000000000000000000018026687f43591dac03a16fce0c4b8020469ec309bdbf9f0f270cf75e262abf4ae55d46f0b4ff130b7bbe2430bd0c9f4000000000000000000000000000000000fd913e00fb884cc217475cb69e1fafc298d5c38ee3bd5fbf68fa9c777b79f5ec111aff51fa0184023fec7c9cc881bf0000000000000000000000000000000000c45786b44e8dc531f1eb777adb0e146a963e46ab65d49a8ce9978607e5aa5c58b2880b8018a9ac97add3ca5c2e65beb000000000000000000000000000000001654e99ebd103ed5709ae412a6df1751add90d4d56025667a4640c1d51435e7cad5464ff2c8b08cca56e34517b05acf10000000000000000000000000000000004d8353f55fdfb2407e80e881a5e57672fbcf7712dcec4cb583dbd93cf3f1052511fdee20f338a387690da7d69f4f6f700000000000000000000000000000000123a19e1427bac55eabdaec2aeeefadfca6e2b7581a5726c393bede2efd78af04e6cb986aa8d8d5c845bbbc28d62e7a00000000000000000000000000000000018026687f43591dac03a16fce0c4b8020469ec309bdbf9f0f270cf75e262abf4ae55d46f0b4ff130b7bbe2430bd0c9f4000000000000000000000000000000000a27fe0a29c761ce29a731ead969b1db3ae9ef4c05493cc370a128d97ef956c55d9a500991b3e7bf9600383633778ebb000000000000000000000000000000000dbb997ef4970a472bfcf03e959acb90bb13671a3d27c91698975a407856505e93837f46afc965363f21c35a3d194ec0", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_66", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000001bb1e11a1ccc0b70ce46114caca7ac1aba2a607fea8c6a0e01785e17559b271a0e8b5afbfa8705ecb77420473e81c510000000000000000000000000000000018f2289ba50f703f87f0516d517e2f6309fe0dc7aca87cc534554c0e57c4bdc5cde0ca896033b7f3d96995d5cbd563d200000000000000000000000000000000000353798691ffba215b6458a47823d149e4e2e48c9e5f65df61d6b995889f3b0e2b34824e4ffa73296d03148c607c26000000000000000000000000000000001190ba585a928413dc3cef3d77b2cff99b053cadcb13b2529c74171a094d479a259678dd43a3ef2a2e597223eb7fd35c000000000000000000000000000000000eb3f5d24d1a4f520032534f6f81a6806c54df33cbd10c30203423aa4f33620b474cda321e924802b636daaeb34400470000000000000000000000000000000016f004f1dfbf140de042e4f57303928a576d9064f2da5b3ad392331f5c43327c7d2a6fd57456d5ef58b54a3e5ec275080000000000000000000000000000000001bb1e11a1ccc0b70ce46114caca7ac1aba2a607fea8c6a0e01785e17559b271a0e8b5afbfa8705ecb77420473e81c5100000000000000000000000000000000010ee94e9470765ac32b5648f1cd7d745a793dbd46dc95fa32db86929eec385e50cb35755120480be0956a2a342a46d900000000000000000000000000000000000353798691ffba215b6458a47823d149e4e2e48c9e5f65df61d6b995889f3b0e2b34824e4ffa73296d03148c607c26000000000000000000000000000000001190ba585a928413dc3cef3d77b2cff99b053cadcb13b2529c74171a094d479a259678dd43a3ef2a2e597223eb7fd35c000000000000000000000000000000000eb3f5d24d1a4f520032534f6f81a6806c54df33cbd10c30203423aa4f33620b474cda321e924802b636daaeb34400470000000000000000000000000000000016f004f1dfbf140de042e4f57303928a576d9064f2da5b3ad392331f5c43327c7d2a6fd57456d5ef58b54a3e5ec275080000000000000000000000000000000001bb1e11a1ccc0b70ce46114caca7ac1aba2a607fea8c6a0e01785e17559b271a0e8b5afbfa8705ecb77420473e81c510000000000000000000000000000000018f2289ba50f703f87f0516d517e2f6309fe0dc7aca87cc534554c0e57c4bdc5cde0ca896033b7f3d96995d5cbd563d200000000000000000000000000000000000353798691ffba215b6458a47823d149e4e2e48c9e5f65df61d6b995889f3b0e2b34824e4ffa73296d03148c607c26000000000000000000000000000000001190ba585a928413dc3cef3d77b2cff99b053cadcb13b2529c74171a094d479a259678dd43a3ef2a2e597223eb7fd35c000000000000000000000000000000000b4d1c17ec6597484ae95466d3ca0656f8226c5127b4068f46fcaef6a77d9418d75f25cc92c1b7fd03c825514cbbaa640000000000000000000000000000000003110cf859c0d28c6ad8c2c0d0481a4d0d09bb2000aab784939e9f819a6dc3a7a18190293cfd2a106149b5c1a13d35a30000000000000000000000000000000001bb1e11a1ccc0b70ce46114caca7ac1aba2a607fea8c6a0e01785e17559b271a0e8b5afbfa8705ecb77420473e81c5100000000000000000000000000000000010ee94e9470765ac32b5648f1cd7d745a793dbd46dc95fa32db86929eec385e50cb35755120480be0956a2a342a46d900000000000000000000000000000000000353798691ffba215b6458a47823d149e4e2e48c9e5f65df61d6b995889f3b0e2b34824e4ffa73296d03148c607c26000000000000000000000000000000001190ba585a928413dc3cef3d77b2cff99b053cadcb13b2529c74171a094d479a259678dd43a3ef2a2e597223eb7fd35c000000000000000000000000000000000b4d1c17ec6597484ae95466d3ca0656f8226c5127b4068f46fcaef6a77d9418d75f25cc92c1b7fd03c825514cbbaa640000000000000000000000000000000003110cf859c0d28c6ad8c2c0d0481a4d0d09bb2000aab784939e9f819a6dc3a7a18190293cfd2a106149b5c1a13d35a30000000000000000000000000000000001bb1e11a1ccc0b70ce46114caca7ac1aba2a607fea8c6a0e01785e17559b271a0e8b5afbfa8705ecb77420473e81c510000000000000000000000000000000018f2289ba50f703f87f0516d517e2f6309fe0dc7aca87cc534554c0e57c4bdc5cde0ca896033b7f3d96995d5cbd563d200000000000000000000000000000000000353798691ffba215b6458a47823d149e4e2e48c9e5f65df61d6b995889f3b0e2b34824e4ffa73296d03148c607c26000000000000000000000000000000001190ba585a928413dc3cef3d77b2cff99b053cadcb13b2529c74171a094d479a259678dd43a3ef2a2e597223eb7fd35c000000000000000000000000000000000eb3f5d24d1a4f520032534f6f81a6806c54df33cbd10c30203423aa4f33620b474cda321e924802b636daaeb34400470000000000000000000000000000000016f004f1dfbf140de042e4f57303928a576d9064f2da5b3ad392331f5c43327c7d2a6fd57456d5ef58b54a3e5ec27508", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_67", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000012ecb4c2f259efb4416025e236108eff7862e54f796605cc7eb12f3e5275c80ef42aadd2acfbf84d5206f6884d8e3eab000000000000000000000000000000001554412fc407e6b6cf3cbcc0c240524d1a0bf9c1335926715ac1c5a5a79ecdf2fdd97c3d828881b3d2f8c0104c85531f0000000000000000000000000000000018b0cd0360c5d5bf8254725c19976345cd84d32d0d770286444fe29dfdbc495dd58407ee8d48ec1004971f249453b8460000000000000000000000000000000009a6ea13f5a5a279ec3bb86cc028a1685d84135ed5fe99cd6b6fb380a42c3af5497e3ba5ea558618487cf953172a376d0000000000000000000000000000000002a36d5efd3381c35ff4f361cd813a96c3e5185141c5985073b45d1319c5f392442b7aa6a253b7eb22d1b5052812be00000000000000000000000000000000000f745dd17966b6befa7f740ea360241162505d6269226ffda90546863d0fff124d8fea13c763cfb69c2f8f12b81d431f0000000000000000000000000000000012ecb4c2f259efb4416025e236108eff7862e54f796605cc7eb12f3e5275c80ef42aadd2acfbf84d5206f6884d8e3eab0000000000000000000000000000000004acd0ba7577ffe37bdeeaf5810b5a8a4a6b51c3c02bec4e0c6f0cfb4f12283120d283c12ecb7e4be7063fefb37a578c0000000000000000000000000000000018b0cd0360c5d5bf8254725c19976345cd84d32d0d770286444fe29dfdbc495dd58407ee8d48ec1004971f249453b8460000000000000000000000000000000009a6ea13f5a5a279ec3bb86cc028a1685d84135ed5fe99cd6b6fb380a42c3af5497e3ba5ea558618487cf953172a376d0000000000000000000000000000000002a36d5efd3381c35ff4f361cd813a96c3e5185141c5985073b45d1319c5f392442b7aa6a253b7eb22d1b5052812be00000000000000000000000000000000000f745dd17966b6befa7f740ea360241162505d6269226ffda90546863d0fff124d8fea13c763cfb69c2f8f12b81d431f0000000000000000000000000000000012ecb4c2f259efb4416025e236108eff7862e54f796605cc7eb12f3e5275c80ef42aadd2acfbf84d5206f6884d8e3eab000000000000000000000000000000001554412fc407e6b6cf3cbcc0c240524d1a0bf9c1335926715ac1c5a5a79ecdf2fdd97c3d828881b3d2f8c0104c85531f0000000000000000000000000000000018b0cd0360c5d5bf8254725c19976345cd84d32d0d770286444fe29dfdbc495dd58407ee8d48ec1004971f249453b8460000000000000000000000000000000009a6ea13f5a5a279ec3bb86cc028a1685d84135ed5fe99cd6b6fb380a42c3af5497e3ba5ea558618487cf953172a376d00000000000000000000000000000000175da48b3c4c64d6eb26b45475ca7240a0923333b1bf7a6ef37c758ddceb0291da8085580f004814972d4afad7ececab000000000000000000000000000000000a8cb418c0192fdb509c33a79feb88c60226ee228a62a2c1be2b8c1ab9a0f711d11c15eae9f030491dcf70ed47e2678c0000000000000000000000000000000012ecb4c2f259efb4416025e236108eff7862e54f796605cc7eb12f3e5275c80ef42aadd2acfbf84d5206f6884d8e3eab0000000000000000000000000000000004acd0ba7577ffe37bdeeaf5810b5a8a4a6b51c3c02bec4e0c6f0cfb4f12283120d283c12ecb7e4be7063fefb37a578c0000000000000000000000000000000018b0cd0360c5d5bf8254725c19976345cd84d32d0d770286444fe29dfdbc495dd58407ee8d48ec1004971f249453b8460000000000000000000000000000000009a6ea13f5a5a279ec3bb86cc028a1685d84135ed5fe99cd6b6fb380a42c3af5497e3ba5ea558618487cf953172a376d00000000000000000000000000000000175da48b3c4c64d6eb26b45475ca7240a0923333b1bf7a6ef37c758ddceb0291da8085580f004814972d4afad7ececab000000000000000000000000000000000a8cb418c0192fdb509c33a79feb88c60226ee228a62a2c1be2b8c1ab9a0f711d11c15eae9f030491dcf70ed47e2678c0000000000000000000000000000000012ecb4c2f259efb4416025e236108eff7862e54f796605cc7eb12f3e5275c80ef42aadd2acfbf84d5206f6884d8e3eab000000000000000000000000000000001554412fc407e6b6cf3cbcc0c240524d1a0bf9c1335926715ac1c5a5a79ecdf2fdd97c3d828881b3d2f8c0104c85531f0000000000000000000000000000000018b0cd0360c5d5bf8254725c19976345cd84d32d0d770286444fe29dfdbc495dd58407ee8d48ec1004971f249453b8460000000000000000000000000000000009a6ea13f5a5a279ec3bb86cc028a1685d84135ed5fe99cd6b6fb380a42c3af5497e3ba5ea558618487cf953172a376d0000000000000000000000000000000002a36d5efd3381c35ff4f361cd813a96c3e5185141c5985073b45d1319c5f392442b7aa6a253b7eb22d1b5052812be00000000000000000000000000000000000f745dd17966b6befa7f740ea360241162505d6269226ffda90546863d0fff124d8fea13c763cfb69c2f8f12b81d431f", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_68", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000010dac3e5885cc55f3e53b3fdd5d28b2d78ceeea2b669757a187de0ce3f28b586e451b119cdb7dc8b97d603f2bb700e2000000000000000000000000000000000712a9656fa95abf8c8c5d0d18a599c4cae3a0ae4bda12c0759ea60fe9f3b698d3c357edebb9f461d95762b1a24e7879000000000000000000000000000000001431c5161fc51024c5708496a1f9545c3d4c05ef9e2c91154e22ebfe251017fc61ba54c679ba2ad6b8314bfd8d6272c900000000000000000000000000000000098f2e8b6d3fcf9fb27e912af57b45d3d35a7c5471b9ea2c85262c0efb44c435cd949f23d7d40f14b6b6d4d92cb8412e000000000000000000000000000000000397dbdcc3edf976e8c507f5e70299da8c7765772115bf8edf7dc9024050c2ed98746c2bf7dd4400ab1fb89af991e43f00000000000000000000000000000000139bd5f917f59e2cb6c41c59024c12cdaf95285f3947b80267f36e3bd2701f9548b561c49003fc5ddeee3fe7bc8f5b5b00000000000000000000000000000000010dac3e5885cc55f3e53b3fdd5d28b2d78ceeea2b669757a187de0ce3f28b586e451b119cdb7dc8b97d603f2bb700e20000000000000000000000000000000012ee6884c9d68bdabe8f4aa92aa613129993aad6a7aafffef1922c910cbd3f8b4ae8a810c59a0b9de0a79d4e5db13232000000000000000000000000000000001431c5161fc51024c5708496a1f9545c3d4c05ef9e2c91154e22ebfe251017fc61ba54c679ba2ad6b8314bfd8d6272c900000000000000000000000000000000098f2e8b6d3fcf9fb27e912af57b45d3d35a7c5471b9ea2c85262c0efb44c435cd949f23d7d40f14b6b6d4d92cb8412e000000000000000000000000000000000397dbdcc3edf976e8c507f5e70299da8c7765772115bf8edf7dc9024050c2ed98746c2bf7dd4400ab1fb89af991e43f00000000000000000000000000000000139bd5f917f59e2cb6c41c59024c12cdaf95285f3947b80267f36e3bd2701f9548b561c49003fc5ddeee3fe7bc8f5b5b00000000000000000000000000000000010dac3e5885cc55f3e53b3fdd5d28b2d78ceeea2b669757a187de0ce3f28b586e451b119cdb7dc8b97d603f2bb700e2000000000000000000000000000000000712a9656fa95abf8c8c5d0d18a599c4cae3a0ae4bda12c0759ea60fe9f3b698d3c357edebb9f461d95762b1a24e7879000000000000000000000000000000001431c5161fc51024c5708496a1f9545c3d4c05ef9e2c91154e22ebfe251017fc61ba54c679ba2ad6b8314bfd8d6272c900000000000000000000000000000000098f2e8b6d3fcf9fb27e912af57b45d3d35a7c5471b9ea2c85262c0efb44c435cd949f23d7d40f14b6b6d4d92cb8412e000000000000000000000000000000001669360d7591ed2362569fc05c4912fcd7ffe60dd26f533087b3099eb6603336863793d2b976bbff0edf4765066dc66c0000000000000000000000000000000006653bf1218a486d94578b5d40ff9a09b4e22325ba3d5abcff3d64652440d68ed5f69e3a215003a1db10c01843704f5000000000000000000000000000000000010dac3e5885cc55f3e53b3fdd5d28b2d78ceeea2b669757a187de0ce3f28b586e451b119cdb7dc8b97d603f2bb700e20000000000000000000000000000000012ee6884c9d68bdabe8f4aa92aa613129993aad6a7aafffef1922c910cbd3f8b4ae8a810c59a0b9de0a79d4e5db13232000000000000000000000000000000001431c5161fc51024c5708496a1f9545c3d4c05ef9e2c91154e22ebfe251017fc61ba54c679ba2ad6b8314bfd8d6272c900000000000000000000000000000000098f2e8b6d3fcf9fb27e912af57b45d3d35a7c5471b9ea2c85262c0efb44c435cd949f23d7d40f14b6b6d4d92cb8412e000000000000000000000000000000001669360d7591ed2362569fc05c4912fcd7ffe60dd26f533087b3099eb6603336863793d2b976bbff0edf4765066dc66c0000000000000000000000000000000006653bf1218a486d94578b5d40ff9a09b4e22325ba3d5abcff3d64652440d68ed5f69e3a215003a1db10c01843704f5000000000000000000000000000000000010dac3e5885cc55f3e53b3fdd5d28b2d78ceeea2b669757a187de0ce3f28b586e451b119cdb7dc8b97d603f2bb700e2000000000000000000000000000000000712a9656fa95abf8c8c5d0d18a599c4cae3a0ae4bda12c0759ea60fe9f3b698d3c357edebb9f461d95762b1a24e7879000000000000000000000000000000001431c5161fc51024c5708496a1f9545c3d4c05ef9e2c91154e22ebfe251017fc61ba54c679ba2ad6b8314bfd8d6272c900000000000000000000000000000000098f2e8b6d3fcf9fb27e912af57b45d3d35a7c5471b9ea2c85262c0efb44c435cd949f23d7d40f14b6b6d4d92cb8412e000000000000000000000000000000000397dbdcc3edf976e8c507f5e70299da8c7765772115bf8edf7dc9024050c2ed98746c2bf7dd4400ab1fb89af991e43f00000000000000000000000000000000139bd5f917f59e2cb6c41c59024c12cdaf95285f3947b80267f36e3bd2701f9548b561c49003fc5ddeee3fe7bc8f5b5b", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_69", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001889ef0e20d5ddbeeb4380b97ed7d4be97ef0def051d232598b2459a72845d97fa5c1264802ab18d76b15d8fbd25e55900000000000000000000000000000000135519fb1c21b215b1f982009db41b30d7af69a3fada207e0c915d01c8b1a22df3bf0dc0ad10020c3e4b88a41609e12a000000000000000000000000000000000caecf650a12bb629ebd3b978ef9c2d4486f8ce21d515451ecdf01d27740f41b719d5a952e737c83641953a8c8b3a1bb000000000000000000000000000000001641ca29ff6016af335499dfc7167b3d961a25b7f61008c27b3cb13d3cb28fb5096413b1c7f1ca18e5d3b5017d6fed1b00000000000000000000000000000000197ed996d62fc0628d8ea4adee487df31c794e05e7c327aaa140c6be0109031bb763c5f84bc35a0597dc61e93d23a9bf000000000000000000000000000000001056c1f3c6ae36be26430d142d34b0e807685c79935496414e004cb85900d85a18454bde9c0f2650f19db35eb3dd468d000000000000000000000000000000001889ef0e20d5ddbeeb4380b97ed7d4be97ef0def051d232598b2459a72845d97fa5c1264802ab18d76b15d8fbd25e5590000000000000000000000000000000006abf7ef1d5e3484992225b5a59791a68cc7e1e0f8aaf2415a9f759f2dff53f62aecf23e0443fdf37bb3775be9f5c981000000000000000000000000000000000caecf650a12bb629ebd3b978ef9c2d4486f8ce21d515451ecdf01d27740f41b719d5a952e737c83641953a8c8b3a1bb000000000000000000000000000000001641ca29ff6016af335499dfc7167b3d961a25b7f61008c27b3cb13d3cb28fb5096413b1c7f1ca18e5d3b5017d6fed1b00000000000000000000000000000000197ed996d62fc0628d8ea4adee487df31c794e05e7c327aaa140c6be0109031bb763c5f84bc35a0597dc61e93d23a9bf000000000000000000000000000000001056c1f3c6ae36be26430d142d34b0e807685c79935496414e004cb85900d85a18454bde9c0f2650f19db35eb3dd468d000000000000000000000000000000001889ef0e20d5ddbeeb4380b97ed7d4be97ef0def051d232598b2459a72845d97fa5c1264802ab18d76b15d8fbd25e55900000000000000000000000000000000135519fb1c21b215b1f982009db41b30d7af69a3fada207e0c915d01c8b1a22df3bf0dc0ad10020c3e4b88a41609e12a000000000000000000000000000000000caecf650a12bb629ebd3b978ef9c2d4486f8ce21d515451ecdf01d27740f41b719d5a952e737c83641953a8c8b3a1bb000000000000000000000000000000001641ca29ff6016af335499dfc7167b3d961a25b7f61008c27b3cb13d3cb28fb5096413b1c7f1ca18e5d3b5017d6fed1b000000000000000000000000000000000082385363502637bd8d030855032ee447fdfd7f0bc1eb14c5f00be2f5a7f30867483a066590a5fa22229e16c2dc00ec0000000000000000000000000000000009aa4ff672d1afdc24d89aa21616fbef5d0eef0b60307c7e193085e89db01dca0666b4201544d9aec8614ca14c22641e000000000000000000000000000000001889ef0e20d5ddbeeb4380b97ed7d4be97ef0def051d232598b2459a72845d97fa5c1264802ab18d76b15d8fbd25e5590000000000000000000000000000000006abf7ef1d5e3484992225b5a59791a68cc7e1e0f8aaf2415a9f759f2dff53f62aecf23e0443fdf37bb3775be9f5c981000000000000000000000000000000000caecf650a12bb629ebd3b978ef9c2d4486f8ce21d515451ecdf01d27740f41b719d5a952e737c83641953a8c8b3a1bb000000000000000000000000000000001641ca29ff6016af335499dfc7167b3d961a25b7f61008c27b3cb13d3cb28fb5096413b1c7f1ca18e5d3b5017d6fed1b000000000000000000000000000000000082385363502637bd8d030855032ee447fdfd7f0bc1eb14c5f00be2f5a7f30867483a066590a5fa22229e16c2dc00ec0000000000000000000000000000000009aa4ff672d1afdc24d89aa21616fbef5d0eef0b60307c7e193085e89db01dca0666b4201544d9aec8614ca14c22641e000000000000000000000000000000001889ef0e20d5ddbeeb4380b97ed7d4be97ef0def051d232598b2459a72845d97fa5c1264802ab18d76b15d8fbd25e55900000000000000000000000000000000135519fb1c21b215b1f982009db41b30d7af69a3fada207e0c915d01c8b1a22df3bf0dc0ad10020c3e4b88a41609e12a000000000000000000000000000000000caecf650a12bb629ebd3b978ef9c2d4486f8ce21d515451ecdf01d27740f41b719d5a952e737c83641953a8c8b3a1bb000000000000000000000000000000001641ca29ff6016af335499dfc7167b3d961a25b7f61008c27b3cb13d3cb28fb5096413b1c7f1ca18e5d3b5017d6fed1b00000000000000000000000000000000197ed996d62fc0628d8ea4adee487df31c794e05e7c327aaa140c6be0109031bb763c5f84bc35a0597dc61e93d23a9bf000000000000000000000000000000001056c1f3c6ae36be26430d142d34b0e807685c79935496414e004cb85900d85a18454bde9c0f2650f19db35eb3dd468d", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_70", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000008726a32d489a5ea1c1b314dc4d400d995d0eb8b49d47e65a6ac8fd0e6ec0cda1c637ee314c0c5d1ad72cd3588ebf925000000000000000000000000000000001849697df83d625fc5cdd722c76faf542a42506fc3479d8127eee7af57611c7d6f33a7f9dba5d3c420fab33ec19305f50000000000000000000000000000000009c7164f8d40c7e9ca571c46f8edf1c4a961779e55f6b10ffc44d76da78adadb83195d757949be39631c6a53d2d67fae0000000000000000000000000000000012cd5149125e7cc21bb5349be7fe03d5854ee73ba515021b6dc87e81ce1e1fa3e386fcb0de80977b9329e72ad54f929f0000000000000000000000000000000008789ffe0a8676c6a56742a30a48e5e65b88aafd71859d704fb9f69e5e274ccb6942bc51ad36c5671406052aacf19df9000000000000000000000000000000000c7607f4fc69a25aff00a54369f213c4587404644358da4abf26d151dfa4905ba9731dcfb12e2a3f2c551cacd0f4e47f0000000000000000000000000000000008726a32d489a5ea1c1b314dc4d400d995d0eb8b49d47e65a6ac8fd0e6ec0cda1c637ee314c0c5d1ad72cd3588ebf9250000000000000000000000000000000001b7a86c4142843a854dd0937bdbfd833a34fb15303d753e3f41eaf19f4fd9a6af785804d5ae2c3b99044cc13e6ca4b60000000000000000000000000000000009c7164f8d40c7e9ca571c46f8edf1c4a961779e55f6b10ffc44d76da78adadb83195d757949be39631c6a53d2d67fae0000000000000000000000000000000012cd5149125e7cc21bb5349be7fe03d5854ee73ba515021b6dc87e81ce1e1fa3e386fcb0de80977b9329e72ad54f929f0000000000000000000000000000000008789ffe0a8676c6a56742a30a48e5e65b88aafd71859d704fb9f69e5e274ccb6942bc51ad36c5671406052aacf19df9000000000000000000000000000000000c7607f4fc69a25aff00a54369f213c4587404644358da4abf26d151dfa4905ba9731dcfb12e2a3f2c551cacd0f4e47f0000000000000000000000000000000008726a32d489a5ea1c1b314dc4d400d995d0eb8b49d47e65a6ac8fd0e6ec0cda1c637ee314c0c5d1ad72cd3588ebf925000000000000000000000000000000001849697df83d625fc5cdd722c76faf542a42506fc3479d8127eee7af57611c7d6f33a7f9dba5d3c420fab33ec19305f50000000000000000000000000000000009c7164f8d40c7e9ca571c46f8edf1c4a961779e55f6b10ffc44d76da78adadb83195d757949be39631c6a53d2d67fae0000000000000000000000000000000012cd5149125e7cc21bb5349be7fe03d5854ee73ba515021b6dc87e81ce1e1fa3e386fcb0de80977b9329e72ad54f929f00000000000000000000000000000000118871ec2ef96fd3a5b465133902c6f108eea08781ff754f1776dc029889a958b56943ad041d3a98a5f8fad5530e0cb2000000000000000000000000000000000d8b09f53d16443f4c1b0272d95999130c034720b02c3874a80a014f170c65c87538e22f0025d5c08da9e3532f0ac62c0000000000000000000000000000000008726a32d489a5ea1c1b314dc4d400d995d0eb8b49d47e65a6ac8fd0e6ec0cda1c637ee314c0c5d1ad72cd3588ebf9250000000000000000000000000000000001b7a86c4142843a854dd0937bdbfd833a34fb15303d753e3f41eaf19f4fd9a6af785804d5ae2c3b99044cc13e6ca4b60000000000000000000000000000000009c7164f8d40c7e9ca571c46f8edf1c4a961779e55f6b10ffc44d76da78adadb83195d757949be39631c6a53d2d67fae0000000000000000000000000000000012cd5149125e7cc21bb5349be7fe03d5854ee73ba515021b6dc87e81ce1e1fa3e386fcb0de80977b9329e72ad54f929f00000000000000000000000000000000118871ec2ef96fd3a5b465133902c6f108eea08781ff754f1776dc029889a958b56943ad041d3a98a5f8fad5530e0cb2000000000000000000000000000000000d8b09f53d16443f4c1b0272d95999130c034720b02c3874a80a014f170c65c87538e22f0025d5c08da9e3532f0ac62c0000000000000000000000000000000008726a32d489a5ea1c1b314dc4d400d995d0eb8b49d47e65a6ac8fd0e6ec0cda1c637ee314c0c5d1ad72cd3588ebf925000000000000000000000000000000001849697df83d625fc5cdd722c76faf542a42506fc3479d8127eee7af57611c7d6f33a7f9dba5d3c420fab33ec19305f50000000000000000000000000000000009c7164f8d40c7e9ca571c46f8edf1c4a961779e55f6b10ffc44d76da78adadb83195d757949be39631c6a53d2d67fae0000000000000000000000000000000012cd5149125e7cc21bb5349be7fe03d5854ee73ba515021b6dc87e81ce1e1fa3e386fcb0de80977b9329e72ad54f929f0000000000000000000000000000000008789ffe0a8676c6a56742a30a48e5e65b88aafd71859d704fb9f69e5e274ccb6942bc51ad36c5671406052aacf19df9000000000000000000000000000000000c7607f4fc69a25aff00a54369f213c4587404644358da4abf26d151dfa4905ba9731dcfb12e2a3f2c551cacd0f4e47f", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_71", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001688c63e325569855bc2e51d668cef112b2479efa33519fe7f45eab89e275e2c4652cf8c2814f179935ccf1d24d8bd0f0000000000000000000000000000000011ebf7d4984237ac0173807f31be64575e7cccb36ce94e666e8149b9c292ebdb68d30ed4ba68f8e00982ee7780b2567300000000000000000000000000000000093c423917d10edc429acd927def56ab4f07254b3892762aa7056f24224528aa0f528fe8538ca996ca63506c84af73270000000000000000000000000000000003fd3ba68878485e25ccaa2539eed0a97743ae9f5b848e9d83c8ea60f7ad0f1cc6d94a59498f79dcab2bfcc2fdbacfed000000000000000000000000000000000b060965391bfd4afe3271c6ddb91eecb8c7a60451c469d63bb178b1361617000f589c33c35b5deda2f072c6edf2eb370000000000000000000000000000000011c8c988379cd2b82cb8ebd81c3e14d2c01c09dde5690b97623c0876c7554f52ccbaa33d17fb0f0cf331cc85749340cd000000000000000000000000000000001688c63e325569855bc2e51d668cef112b2479efa33519fe7f45eab89e275e2c4652cf8c2814f179935ccf1d24d8bd0f0000000000000000000000000000000008151a15a13daeee49a82737118d488005fa7ed1869bc458f8af88e7341e0a48b5d8f129f6eb071fb07c11887f4d543800000000000000000000000000000000093c423917d10edc429acd927def56ab4f07254b3892762aa7056f24224528aa0f528fe8538ca996ca63506c84af73270000000000000000000000000000000003fd3ba68878485e25ccaa2539eed0a97743ae9f5b848e9d83c8ea60f7ad0f1cc6d94a59498f79dcab2bfcc2fdbacfed000000000000000000000000000000000b060965391bfd4afe3271c6ddb91eecb8c7a60451c469d63bb178b1361617000f589c33c35b5deda2f072c6edf2eb370000000000000000000000000000000011c8c988379cd2b82cb8ebd81c3e14d2c01c09dde5690b97623c0876c7554f52ccbaa33d17fb0f0cf331cc85749340cd000000000000000000000000000000001688c63e325569855bc2e51d668cef112b2479efa33519fe7f45eab89e275e2c4652cf8c2814f179935ccf1d24d8bd0f0000000000000000000000000000000011ebf7d4984237ac0173807f31be64575e7cccb36ce94e666e8149b9c292ebdb68d30ed4ba68f8e00982ee7780b2567300000000000000000000000000000000093c423917d10edc429acd927def56ab4f07254b3892762aa7056f24224528aa0f528fe8538ca996ca63506c84af73270000000000000000000000000000000003fd3ba68878485e25ccaa2539eed0a97743ae9f5b848e9d83c8ea60f7ad0f1cc6d94a59498f79dcab2bfcc2fdbacfed000000000000000000000000000000000efb08850063e94f4ce935ef65928deaabafa580a1c0a8e92b7f59efc09adf240f5363caedf8a212170e8d39120cbf74000000000000000000000000000000000838486201e313e21e62bbde270d9804a45b41a70e1c072804f4ca2a2f5ba6d151f15cc19958f0f2c6cd337a8b6c69de000000000000000000000000000000001688c63e325569855bc2e51d668cef112b2479efa33519fe7f45eab89e275e2c4652cf8c2814f179935ccf1d24d8bd0f0000000000000000000000000000000008151a15a13daeee49a82737118d488005fa7ed1869bc458f8af88e7341e0a48b5d8f129f6eb071fb07c11887f4d543800000000000000000000000000000000093c423917d10edc429acd927def56ab4f07254b3892762aa7056f24224528aa0f528fe8538ca996ca63506c84af73270000000000000000000000000000000003fd3ba68878485e25ccaa2539eed0a97743ae9f5b848e9d83c8ea60f7ad0f1cc6d94a59498f79dcab2bfcc2fdbacfed000000000000000000000000000000000efb08850063e94f4ce935ef65928deaabafa580a1c0a8e92b7f59efc09adf240f5363caedf8a212170e8d39120cbf74000000000000000000000000000000000838486201e313e21e62bbde270d9804a45b41a70e1c072804f4ca2a2f5ba6d151f15cc19958f0f2c6cd337a8b6c69de000000000000000000000000000000001688c63e325569855bc2e51d668cef112b2479efa33519fe7f45eab89e275e2c4652cf8c2814f179935ccf1d24d8bd0f0000000000000000000000000000000011ebf7d4984237ac0173807f31be64575e7cccb36ce94e666e8149b9c292ebdb68d30ed4ba68f8e00982ee7780b2567300000000000000000000000000000000093c423917d10edc429acd927def56ab4f07254b3892762aa7056f24224528aa0f528fe8538ca996ca63506c84af73270000000000000000000000000000000003fd3ba68878485e25ccaa2539eed0a97743ae9f5b848e9d83c8ea60f7ad0f1cc6d94a59498f79dcab2bfcc2fdbacfed000000000000000000000000000000000b060965391bfd4afe3271c6ddb91eecb8c7a60451c469d63bb178b1361617000f589c33c35b5deda2f072c6edf2eb370000000000000000000000000000000011c8c988379cd2b82cb8ebd81c3e14d2c01c09dde5690b97623c0876c7554f52ccbaa33d17fb0f0cf331cc85749340cd", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_72", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000bb6f731b345bb1319b9acab09c186449a51dad8b6526251bc58e958cfd933137067e6f778b019f131cc7b23e08a0706000000000000000000000000000000001979a4f3e444c5950d0e2d71f97e99578b3058a6e414dfca313b898c4e02787e6eed89a2d1b05f31cff4af1e12bbedc300000000000000000000000000000000039d8e90425810a0b2fb5c915905863eb2da363ad4188e42cedce678bdd0f51eca0a96b78ab9e082d59dcd10e3c3c97a000000000000000000000000000000001973250dc31d16f658323d021dddc5439ef4396b6ed735f108cd7b27feb1b508daf863ab6431a77ec0b10cf7e001244f000000000000000000000000000000000f05a111b41a54e0ca78c3a1fff3b80bee7c1505a06b9a4faf36a73b87121d2952cc4f4c4e0dcb6633cad12b0caffc620000000000000000000000000000000018daa0f9a2bb347517eee63463b9d6a5e850446e8a94d0986f2921bf81a9f7541e8fee9d7bbb6d9181021af945fce3e3000000000000000000000000000000000bb6f731b345bb1319b9acab09c186449a51dad8b6526251bc58e958cfd933137067e6f778b019f131cc7b23e08a07060000000000000000000000000000000000876cf6553b21053e0d7a4449cd137fd946f2de0f7032f535f54914a8ae7da5afbe765bdfa3a0cdea0a50e1ed43bce800000000000000000000000000000000039d8e90425810a0b2fb5c915905863eb2da363ad4188e42cedce678bdd0f51eca0a96b78ab9e082d59dcd10e3c3c97a000000000000000000000000000000001973250dc31d16f658323d021dddc5439ef4396b6ed735f108cd7b27feb1b508daf863ab6431a77ec0b10cf7e001244f000000000000000000000000000000000f05a111b41a54e0ca78c3a1fff3b80bee7c1505a06b9a4faf36a73b87121d2952cc4f4c4e0dcb6633cad12b0caffc620000000000000000000000000000000018daa0f9a2bb347517eee63463b9d6a5e850446e8a94d0986f2921bf81a9f7541e8fee9d7bbb6d9181021af945fce3e3000000000000000000000000000000000bb6f731b345bb1319b9acab09c186449a51dad8b6526251bc58e958cfd933137067e6f778b019f131cc7b23e08a0706000000000000000000000000000000001979a4f3e444c5950d0e2d71f97e99578b3058a6e414dfca313b898c4e02787e6eed89a2d1b05f31cff4af1e12bbedc300000000000000000000000000000000039d8e90425810a0b2fb5c915905863eb2da363ad4188e42cedce678bdd0f51eca0a96b78ab9e082d59dcd10e3c3c97a000000000000000000000000000000001973250dc31d16f658323d021dddc5439ef4396b6ed735f108cd7b27feb1b508daf863ab6431a77ec0b10cf7e001244f000000000000000000000000000000000afb70d8856591b980a2e4144357f4cb75fb367f5319786fb7fa2b656f9ed8facbdfb0b26346349986342ed4f34fae4900000000000000000000000000000000012670f096c4b225332cc181df91d6317c27071668f04226f807b0e17506fed0001c11613598926e38fce506ba02c6c8000000000000000000000000000000000bb6f731b345bb1319b9acab09c186449a51dad8b6526251bc58e958cfd933137067e6f778b019f131cc7b23e08a07060000000000000000000000000000000000876cf6553b21053e0d7a4449cd137fd946f2de0f7032f535f54914a8ae7da5afbe765bdfa3a0cdea0a50e1ed43bce800000000000000000000000000000000039d8e90425810a0b2fb5c915905863eb2da363ad4188e42cedce678bdd0f51eca0a96b78ab9e082d59dcd10e3c3c97a000000000000000000000000000000001973250dc31d16f658323d021dddc5439ef4396b6ed735f108cd7b27feb1b508daf863ab6431a77ec0b10cf7e001244f000000000000000000000000000000000afb70d8856591b980a2e4144357f4cb75fb367f5319786fb7fa2b656f9ed8facbdfb0b26346349986342ed4f34fae4900000000000000000000000000000000012670f096c4b225332cc181df91d6317c27071668f04226f807b0e17506fed0001c11613598926e38fce506ba02c6c8000000000000000000000000000000000bb6f731b345bb1319b9acab09c186449a51dad8b6526251bc58e958cfd933137067e6f778b019f131cc7b23e08a0706000000000000000000000000000000001979a4f3e444c5950d0e2d71f97e99578b3058a6e414dfca313b898c4e02787e6eed89a2d1b05f31cff4af1e12bbedc300000000000000000000000000000000039d8e90425810a0b2fb5c915905863eb2da363ad4188e42cedce678bdd0f51eca0a96b78ab9e082d59dcd10e3c3c97a000000000000000000000000000000001973250dc31d16f658323d021dddc5439ef4396b6ed735f108cd7b27feb1b508daf863ab6431a77ec0b10cf7e001244f000000000000000000000000000000000f05a111b41a54e0ca78c3a1fff3b80bee7c1505a06b9a4faf36a73b87121d2952cc4f4c4e0dcb6633cad12b0caffc620000000000000000000000000000000018daa0f9a2bb347517eee63463b9d6a5e850446e8a94d0986f2921bf81a9f7541e8fee9d7bbb6d9181021af945fce3e3", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_73", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000078cca0bfd6957f9aff9731b45fdbdbeca6691f6fe6bf0b7847859c77478037e14864b202b235953ac7da231367324c200000000000000000000000000000000096ddc8631aff282d14d1878ef6bc537159abe9dda5732d0b2fe3668e184049cc19e05fec4666a0df204182edb9b0b8a000000000000000000000000000000000eff44a5e3b9fc8ffe31771fbcabea6efbd68384c5931216a2b7465aaa2566ee116b7daeea632677f35379107f7334f0000000000000000000000000000000000c3c942373f69c2c9631cef1c6bbb1a4567d5b95500409d4f2c6bf4a66ee263e6f167e22790badea0eac4a541a9035050000000000000000000000000000000017d9e9e2008501981068cb0403e73c270d99defd468cc9dc2d5bbc57750a4a58236f8f7a8df4f8b607095b6a80e7de49000000000000000000000000000000000ebddf4fc74f25be3c358b72a20d1c093f980adfc943b898266592f691e11413c60151a0085d6c9aec8c2d329abbac0d00000000000000000000000000000000078cca0bfd6957f9aff9731b45fdbdbeca6691f6fe6bf0b7847859c77478037e14864b202b235953ac7da231367324c2000000000000000000000000000000001093356407cff41779ce8f3d53dfe7a04edc8ce7192ddfeeb4329c38152cf1875d0df9ffeced95f1c7fae7d124649f21000000000000000000000000000000000eff44a5e3b9fc8ffe31771fbcabea6efbd68384c5931216a2b7465aaa2566ee116b7daeea632677f35379107f7334f0000000000000000000000000000000000c3c942373f69c2c9631cef1c6bbb1a4567d5b95500409d4f2c6bf4a66ee263e6f167e22790badea0eac4a541a9035050000000000000000000000000000000017d9e9e2008501981068cb0403e73c270d99defd468cc9dc2d5bbc57750a4a58236f8f7a8df4f8b607095b6a80e7de49000000000000000000000000000000000ebddf4fc74f25be3c358b72a20d1c093f980adfc943b898266592f691e11413c60151a0085d6c9aec8c2d329abbac0d00000000000000000000000000000000078cca0bfd6957f9aff9731b45fdbdbeca6691f6fe6bf0b7847859c77478037e14864b202b235953ac7da231367324c200000000000000000000000000000000096ddc8631aff282d14d1878ef6bc537159abe9dda5732d0b2fe3668e184049cc19e05fec4666a0df204182edb9b0b8a000000000000000000000000000000000eff44a5e3b9fc8ffe31771fbcabea6efbd68384c5931216a2b7465aaa2566ee116b7daeea632677f35379107f7334f0000000000000000000000000000000000c3c942373f69c2c9631cef1c6bbb1a4567d5b95500409d4f2c6bf4a66ee263e6f167e22790badea0eac4a541a903505000000000000000000000000000000000227280838fae5023ab2dcb23f6470b056dd6c87acf848e339d5164981a6abcbfb3c7084235f0749b2f5a4957f17cc62000000000000000000000000000000000b43329a7230c0dc0ee61c43a13e90ce24df40a52a415a2740cb3faa64cfe21058aaae5ea8f69364cd72d2cd6543fe9e00000000000000000000000000000000078cca0bfd6957f9aff9731b45fdbdbeca6691f6fe6bf0b7847859c77478037e14864b202b235953ac7da231367324c2000000000000000000000000000000001093356407cff41779ce8f3d53dfe7a04edc8ce7192ddfeeb4329c38152cf1875d0df9ffeced95f1c7fae7d124649f21000000000000000000000000000000000eff44a5e3b9fc8ffe31771fbcabea6efbd68384c5931216a2b7465aaa2566ee116b7daeea632677f35379107f7334f0000000000000000000000000000000000c3c942373f69c2c9631cef1c6bbb1a4567d5b95500409d4f2c6bf4a66ee263e6f167e22790badea0eac4a541a903505000000000000000000000000000000000227280838fae5023ab2dcb23f6470b056dd6c87acf848e339d5164981a6abcbfb3c7084235f0749b2f5a4957f17cc62000000000000000000000000000000000b43329a7230c0dc0ee61c43a13e90ce24df40a52a415a2740cb3faa64cfe21058aaae5ea8f69364cd72d2cd6543fe9e00000000000000000000000000000000078cca0bfd6957f9aff9731b45fdbdbeca6691f6fe6bf0b7847859c77478037e14864b202b235953ac7da231367324c200000000000000000000000000000000096ddc8631aff282d14d1878ef6bc537159abe9dda5732d0b2fe3668e184049cc19e05fec4666a0df204182edb9b0b8a000000000000000000000000000000000eff44a5e3b9fc8ffe31771fbcabea6efbd68384c5931216a2b7465aaa2566ee116b7daeea632677f35379107f7334f0000000000000000000000000000000000c3c942373f69c2c9631cef1c6bbb1a4567d5b95500409d4f2c6bf4a66ee263e6f167e22790badea0eac4a541a9035050000000000000000000000000000000017d9e9e2008501981068cb0403e73c270d99defd468cc9dc2d5bbc57750a4a58236f8f7a8df4f8b607095b6a80e7de49000000000000000000000000000000000ebddf4fc74f25be3c358b72a20d1c093f980adfc943b898266592f691e11413c60151a0085d6c9aec8c2d329abbac0d", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_74", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000b3a1dfe2d1b62538ed49648cb2a8a1d66bdc4f7a492eee59942ab810a306876a7d49e5ac4c6bb1613866c158ded993e000000000000000000000000000000001300956110f47ca8e2aacb30c948dfd046bf33f69bf54007d76373c5a66019454da45e3cf14ce2b9d53a50c9b4366aa300000000000000000000000000000000081da74d812a6718e351c062e93f9edb24eff830be5c44c3f21cca606f5b1287de8ba65a60d42cbf9740c9522fcdc9eb000000000000000000000000000000000eb1d38fd394b7e78dfaeb3b3b97d3d928c16472ee74ae0be1ec3efa510b9bb64cec369793219ceab55a0ed0ece23de80000000000000000000000000000000001fdc4256cc997934a65c68ab9767b09c7aad14b5765dbeedb72ab2429231cb333ab9f9143414359376d76857e8972d9000000000000000000000000000000001362f417875259b47cfd9e4c5feda52b949dcbf5b8178318428fd3e70c384020e58f515b9a24af5597cfa037d42491c6000000000000000000000000000000000b3a1dfe2d1b62538ed49648cb2a8a1d66bdc4f7a492eee59942ab810a306876a7d49e5ac4c6bb1613866c158ded993e0000000000000000000000000000000007007c89288b69f16870dc857a02cd071db8178e578fd2b78fcd5edb5050dcded107a1c1c0071d45e4c4af364bc9400800000000000000000000000000000000081da74d812a6718e351c062e93f9edb24eff830be5c44c3f21cca606f5b1287de8ba65a60d42cbf9740c9522fcdc9eb000000000000000000000000000000000eb1d38fd394b7e78dfaeb3b3b97d3d928c16472ee74ae0be1ec3efa510b9bb64cec369793219ceab55a0ed0ece23de80000000000000000000000000000000001fdc4256cc997934a65c68ab9767b09c7aad14b5765dbeedb72ab2429231cb333ab9f9143414359376d76857e8972d9000000000000000000000000000000001362f417875259b47cfd9e4c5feda52b949dcbf5b8178318428fd3e70c384020e58f515b9a24af5597cfa037d42491c6000000000000000000000000000000000b3a1dfe2d1b62538ed49648cb2a8a1d66bdc4f7a492eee59942ab810a306876a7d49e5ac4c6bb1613866c158ded993e000000000000000000000000000000001300956110f47ca8e2aacb30c948dfd046bf33f69bf54007d76373c5a66019454da45e3cf14ce2b9d53a50c9b4366aa300000000000000000000000000000000081da74d812a6718e351c062e93f9edb24eff830be5c44c3f21cca606f5b1287de8ba65a60d42cbf9740c9522fcdc9eb000000000000000000000000000000000eb1d38fd394b7e78dfaeb3b3b97d3d928c16472ee74ae0be1ec3efa510b9bb64cec369793219ceab55a0ed0ece23de80000000000000000000000000000000018034dc4ccb64f0700b5e12b89d531cd9ccc7a399c1f36d08bbe277ccd8dd970eb00606d6e12bca68291897a817637d200000000000000000000000000000000069e1dd2b22d8ce5ce1e0969e35e07abcfd97f8f3b6d8fa724a0feb9ea78b603391caea3172f50aa222f5fc82bdb18e5000000000000000000000000000000000b3a1dfe2d1b62538ed49648cb2a8a1d66bdc4f7a492eee59942ab810a306876a7d49e5ac4c6bb1613866c158ded993e0000000000000000000000000000000007007c89288b69f16870dc857a02cd071db8178e578fd2b78fcd5edb5050dcded107a1c1c0071d45e4c4af364bc9400800000000000000000000000000000000081da74d812a6718e351c062e93f9edb24eff830be5c44c3f21cca606f5b1287de8ba65a60d42cbf9740c9522fcdc9eb000000000000000000000000000000000eb1d38fd394b7e78dfaeb3b3b97d3d928c16472ee74ae0be1ec3efa510b9bb64cec369793219ceab55a0ed0ece23de80000000000000000000000000000000018034dc4ccb64f0700b5e12b89d531cd9ccc7a399c1f36d08bbe277ccd8dd970eb00606d6e12bca68291897a817637d200000000000000000000000000000000069e1dd2b22d8ce5ce1e0969e35e07abcfd97f8f3b6d8fa724a0feb9ea78b603391caea3172f50aa222f5fc82bdb18e5000000000000000000000000000000000b3a1dfe2d1b62538ed49648cb2a8a1d66bdc4f7a492eee59942ab810a306876a7d49e5ac4c6bb1613866c158ded993e000000000000000000000000000000001300956110f47ca8e2aacb30c948dfd046bf33f69bf54007d76373c5a66019454da45e3cf14ce2b9d53a50c9b4366aa300000000000000000000000000000000081da74d812a6718e351c062e93f9edb24eff830be5c44c3f21cca606f5b1287de8ba65a60d42cbf9740c9522fcdc9eb000000000000000000000000000000000eb1d38fd394b7e78dfaeb3b3b97d3d928c16472ee74ae0be1ec3efa510b9bb64cec369793219ceab55a0ed0ece23de80000000000000000000000000000000001fdc4256cc997934a65c68ab9767b09c7aad14b5765dbeedb72ab2429231cb333ab9f9143414359376d76857e8972d9000000000000000000000000000000001362f417875259b47cfd9e4c5feda52b949dcbf5b8178318428fd3e70c384020e58f515b9a24af5597cfa037d42491c6", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_75", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000007c00b3e7e50a860e99cdc92235f45a555c343304a067a71b6aaade016ef99bc50e3b2c5e3335d4bdacb816d3c765630000000000000000000000000000000000f8a45100cd8afcbb7c05c2d62bfedbf250d68d0fde0a1593cd2ed2f5f4278e1baa9e24625c263764e4347ed78cce6c8000000000000000000000000000000000b8e764aa5afa4a6e8227d1bc720eeffd72d963458a4963a3bbe697d3da11186a30d90f7a4eda5630f6967095816913300000000000000000000000000000000085d05b570cd58def6ac2f7e80dc18658dc5d0e6a1f5a5cf4d18745e03494654eb1a6d5399ec2c5288890ade446317d00000000000000000000000000000000010fb029e35b3f6e156b8751415f180ee3960cd3bb6ba9b8e456715ec70b1ba1410b8bfb77998f744d3f462533b59e26c000000000000000000000000000000001472654d9aa210a41d74e3661e05a9eb6b292719b46aa65f94b6abd514bf05f679dae89d21008245d79a381b0d7f51be0000000000000000000000000000000007c00b3e7e50a860e99cdc92235f45a555c343304a067a71b6aaade016ef99bc50e3b2c5e3335d4bdacb816d3c765630000000000000000000000000000000000a76ccda2ca736ce935b4b88e08bbf183f69e2b3f5a471662a5de571976e7d4264021db88b919c896bbbb8128732c3e3000000000000000000000000000000000b8e764aa5afa4a6e8227d1bc720eeffd72d963458a4963a3bbe697d3da11186a30d90f7a4eda5630f6967095816913300000000000000000000000000000000085d05b570cd58def6ac2f7e80dc18658dc5d0e6a1f5a5cf4d18745e03494654eb1a6d5399ec2c5288890ade446317d00000000000000000000000000000000010fb029e35b3f6e156b8751415f180ee3960cd3bb6ba9b8e456715ec70b1ba1410b8bfb77998f744d3f462533b59e26c000000000000000000000000000000001472654d9aa210a41d74e3661e05a9eb6b292719b46aa65f94b6abd514bf05f679dae89d21008245d79a381b0d7f51be0000000000000000000000000000000007c00b3e7e50a860e99cdc92235f45a555c343304a067a71b6aaade016ef99bc50e3b2c5e3335d4bdacb816d3c765630000000000000000000000000000000000f8a45100cd8afcbb7c05c2d62bfedbf250d68d0fde0a1593cd2ed2f5f4278e1baa9e24625c263764e4347ed78cce6c8000000000000000000000000000000000b8e764aa5afa4a6e8227d1bc720eeffd72d963458a4963a3bbe697d3da11186a30d90f7a4eda5630f6967095816913300000000000000000000000000000000085d05b570cd58def6ac2f7e80dc18658dc5d0e6a1f5a5cf4d18745e03494654eb1a6d5399ec2c5288890ade446317d00000000000000000000000000000000009060f4c03cbefb8f46332a22d5a2be92b167e493cca773121c9bcb485ff3c100df3404737bb08bae60a9dacc4a5c83f00000000000000000000000000000000058eac9c9eddd5f62da6c450254602ebf94e246b3f1a6c5fd27a26cbe1f1f02da4d1176190537db9e264c7e4f28058ed0000000000000000000000000000000007c00b3e7e50a860e99cdc92235f45a555c343304a067a71b6aaade016ef99bc50e3b2c5e3335d4bdacb816d3c765630000000000000000000000000000000000a76ccda2ca736ce935b4b88e08bbf183f69e2b3f5a471662a5de571976e7d4264021db88b919c896bbbb8128732c3e3000000000000000000000000000000000b8e764aa5afa4a6e8227d1bc720eeffd72d963458a4963a3bbe697d3da11186a30d90f7a4eda5630f6967095816913300000000000000000000000000000000085d05b570cd58def6ac2f7e80dc18658dc5d0e6a1f5a5cf4d18745e03494654eb1a6d5399ec2c5288890ade446317d00000000000000000000000000000000009060f4c03cbefb8f46332a22d5a2be92b167e493cca773121c9bcb485ff3c100df3404737bb08bae60a9dacc4a5c83f00000000000000000000000000000000058eac9c9eddd5f62da6c450254602ebf94e246b3f1a6c5fd27a26cbe1f1f02da4d1176190537db9e264c7e4f28058ed0000000000000000000000000000000007c00b3e7e50a860e99cdc92235f45a555c343304a067a71b6aaade016ef99bc50e3b2c5e3335d4bdacb816d3c765630000000000000000000000000000000000f8a45100cd8afcbb7c05c2d62bfedbf250d68d0fde0a1593cd2ed2f5f4278e1baa9e24625c263764e4347ed78cce6c8000000000000000000000000000000000b8e764aa5afa4a6e8227d1bc720eeffd72d963458a4963a3bbe697d3da11186a30d90f7a4eda5630f6967095816913300000000000000000000000000000000085d05b570cd58def6ac2f7e80dc18658dc5d0e6a1f5a5cf4d18745e03494654eb1a6d5399ec2c5288890ade446317d00000000000000000000000000000000010fb029e35b3f6e156b8751415f180ee3960cd3bb6ba9b8e456715ec70b1ba1410b8bfb77998f744d3f462533b59e26c000000000000000000000000000000001472654d9aa210a41d74e3661e05a9eb6b292719b46aa65f94b6abd514bf05f679dae89d21008245d79a381b0d7f51be", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_76", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001517dd04b165c50d2b1ef2f470c821c080f604fe1a23f2fa5481f3a63e0f56e05c89c7403d4067a5f6e59d4a338d0b5c0000000000000000000000000000000007b6b1d032aadd51052f228d7e062e336bacda83bbce657678b5f9634174f0c3c4d0374e83b520a192783a8a5f3fb21100000000000000000000000000000000042280b112fdbbd94f647e5b1f4b51d864f85063a5b66e1f1fe5b1a8d280f9bf1db81ad3588f93f8801ff1a3f66b96330000000000000000000000000000000001e0887904228790d03d8b6d17bebdd8659deafa2ebd9b07069ce89fe228824a39966953d14dda1bd6ccce5faf16e4d7000000000000000000000000000000000520cfc8c536a1d4e685c4eacbc2000d70abd72e1bf8ce3839d79f5cfa069ed31aafb15542f23b8d1af678bab05a2d410000000000000000000000000000000017cfffda12d21c98b79ac31c5bb696783afb7d69c2bedf0fb070cf7714959db14957a4763564b65b7ed214d7b48d399c000000000000000000000000000000001517dd04b165c50d2b1ef2f470c821c080f604fe1a23f2fa5481f3a63e0f56e05c89c7403d4067a5f6e59d4a338d0b5c00000000000000000000000000000000124a601a06d5094945ec8528c5457ea3f8ca710137b6ad48ee7ad93db53c056059dbc8b02d9edf5e2786c575a0bff89a00000000000000000000000000000000042280b112fdbbd94f647e5b1f4b51d864f85063a5b66e1f1fe5b1a8d280f9bf1db81ad3588f93f8801ff1a3f66b96330000000000000000000000000000000001e0887904228790d03d8b6d17bebdd8659deafa2ebd9b07069ce89fe228824a39966953d14dda1bd6ccce5faf16e4d7000000000000000000000000000000000520cfc8c536a1d4e685c4eacbc2000d70abd72e1bf8ce3839d79f5cfa069ed31aafb15542f23b8d1af678bab05a2d410000000000000000000000000000000017cfffda12d21c98b79ac31c5bb696783afb7d69c2bedf0fb070cf7714959db14957a4763564b65b7ed214d7b48d399c000000000000000000000000000000001517dd04b165c50d2b1ef2f470c821c080f604fe1a23f2fa5481f3a63e0f56e05c89c7403d4067a5f6e59d4a338d0b5c0000000000000000000000000000000007b6b1d032aadd51052f228d7e062e336bacda83bbce657678b5f9634174f0c3c4d0374e83b520a192783a8a5f3fb21100000000000000000000000000000000042280b112fdbbd94f647e5b1f4b51d864f85063a5b66e1f1fe5b1a8d280f9bf1db81ad3588f93f8801ff1a3f66b96330000000000000000000000000000000001e0887904228790d03d8b6d17bebdd8659deafa2ebd9b07069ce89fe228824a39966953d14dda1bd6ccce5faf16e4d70000000000000000000000000000000014e04221744944c56495e2cb7789acc9f3cb7456d78c44872d593343fcaa575103fc4ea96e61c4729f0887454fa57d6a000000000000000000000000000000000231121026adca019380e499e795165f297bce1b30c633afb6c00329e21b5872d5545b887bef49a43b2ceb284b72710f000000000000000000000000000000001517dd04b165c50d2b1ef2f470c821c080f604fe1a23f2fa5481f3a63e0f56e05c89c7403d4067a5f6e59d4a338d0b5c00000000000000000000000000000000124a601a06d5094945ec8528c5457ea3f8ca710137b6ad48ee7ad93db53c056059dbc8b02d9edf5e2786c575a0bff89a00000000000000000000000000000000042280b112fdbbd94f647e5b1f4b51d864f85063a5b66e1f1fe5b1a8d280f9bf1db81ad3588f93f8801ff1a3f66b96330000000000000000000000000000000001e0887904228790d03d8b6d17bebdd8659deafa2ebd9b07069ce89fe228824a39966953d14dda1bd6ccce5faf16e4d70000000000000000000000000000000014e04221744944c56495e2cb7789acc9f3cb7456d78c44872d593343fcaa575103fc4ea96e61c4729f0887454fa57d6a000000000000000000000000000000000231121026adca019380e499e795165f297bce1b30c633afb6c00329e21b5872d5545b887bef49a43b2ceb284b72710f000000000000000000000000000000001517dd04b165c50d2b1ef2f470c821c080f604fe1a23f2fa5481f3a63e0f56e05c89c7403d4067a5f6e59d4a338d0b5c0000000000000000000000000000000007b6b1d032aadd51052f228d7e062e336bacda83bbce657678b5f9634174f0c3c4d0374e83b520a192783a8a5f3fb21100000000000000000000000000000000042280b112fdbbd94f647e5b1f4b51d864f85063a5b66e1f1fe5b1a8d280f9bf1db81ad3588f93f8801ff1a3f66b96330000000000000000000000000000000001e0887904228790d03d8b6d17bebdd8659deafa2ebd9b07069ce89fe228824a39966953d14dda1bd6ccce5faf16e4d7000000000000000000000000000000000520cfc8c536a1d4e685c4eacbc2000d70abd72e1bf8ce3839d79f5cfa069ed31aafb15542f23b8d1af678bab05a2d410000000000000000000000000000000017cfffda12d21c98b79ac31c5bb696783afb7d69c2bedf0fb070cf7714959db14957a4763564b65b7ed214d7b48d399c", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_77", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000475e66c9e4e434c4872b8537e0ab930165b39f41e04b208d74d3033e1d69dfb4b134ae3a9dc46347d30a6805508c0420000000000000000000000000000000019e585e1d9adf34a98a7cd38de35aa243d7853c19bc21747213c11240d5fa41ff3b21ae033dd664aaac8fa45354a470a00000000000000000000000000000000137e91115129cbaa1ae2bbb79abe5505436bb51ddceeb011d56dc5c3c396b6b00067d6e6108bafca40fc717737487b27000000000000000000000000000000001592fec7d33bffa7f3eebf038e3194513736cc41a143471fb8c55a44c7521c07e4d8368e5c6ee21ed0478f949f3e224e0000000000000000000000000000000007f786ea1cc7cd69ae1061d6b914278dfc7ebe8a714aa8cd04323860314c3b4b36054169dd5c6c60e67bfa3902d216f50000000000000000000000000000000019675b09a4de34af3c6e79452b57b31b6d499200e996008a9e7d1c910ca0ad2a352dc39cb3fd7333182476095b7aeec3000000000000000000000000000000000475e66c9e4e434c4872b8537e0ab930165b39f41e04b208d74d3033e1d69dfb4b134ae3a9dc46347d30a6805508c04200000000000000000000000000000000001b8c085fd1f34fb273da7d651602b326fef7c357c2fb7845f4c17ce95152042af9e51e7d7699b50f3605bacab563a100000000000000000000000000000000137e91115129cbaa1ae2bbb79abe5505436bb51ddceeb011d56dc5c3c396b6b00067d6e6108bafca40fc717737487b27000000000000000000000000000000001592fec7d33bffa7f3eebf038e3194513736cc41a143471fb8c55a44c7521c07e4d8368e5c6ee21ed0478f949f3e224e0000000000000000000000000000000007f786ea1cc7cd69ae1061d6b914278dfc7ebe8a714aa8cd04323860314c3b4b36054169dd5c6c60e67bfa3902d216f50000000000000000000000000000000019675b09a4de34af3c6e79452b57b31b6d499200e996008a9e7d1c910ca0ad2a352dc39cb3fd7333182476095b7aeec3000000000000000000000000000000000475e66c9e4e434c4872b8537e0ab930165b39f41e04b208d74d3033e1d69dfb4b134ae3a9dc46347d30a6805508c0420000000000000000000000000000000019e585e1d9adf34a98a7cd38de35aa243d7853c19bc21747213c11240d5fa41ff3b21ae033dd664aaac8fa45354a470a00000000000000000000000000000000137e91115129cbaa1ae2bbb79abe5505436bb51ddceeb011d56dc5c3c396b6b00067d6e6108bafca40fc717737487b27000000000000000000000000000000001592fec7d33bffa7f3eebf038e3194513736cc41a143471fb8c55a44c7521c07e4d8368e5c6ee21ed0478f949f3e224e0000000000000000000000000000000012098b001cb819309d0b45df8a37854967f88cfa823a69f262fe9a40c564bad8e8a6be94d3f7939ed38305c6fd2d93b6000000000000000000000000000000000099b6e094a1b1eb0ead2e7117f3f9bbf72db98409ef1234c8b3b60fea1048f9e97e3c61fd568ccca1da89f6a484bbe8000000000000000000000000000000000475e66c9e4e434c4872b8537e0ab930165b39f41e04b208d74d3033e1d69dfb4b134ae3a9dc46347d30a6805508c04200000000000000000000000000000000001b8c085fd1f34fb273da7d651602b326fef7c357c2fb7845f4c17ce95152042af9e51e7d7699b50f3605bacab563a100000000000000000000000000000000137e91115129cbaa1ae2bbb79abe5505436bb51ddceeb011d56dc5c3c396b6b00067d6e6108bafca40fc717737487b27000000000000000000000000000000001592fec7d33bffa7f3eebf038e3194513736cc41a143471fb8c55a44c7521c07e4d8368e5c6ee21ed0478f949f3e224e0000000000000000000000000000000012098b001cb819309d0b45df8a37854967f88cfa823a69f262fe9a40c564bad8e8a6be94d3f7939ed38305c6fd2d93b6000000000000000000000000000000000099b6e094a1b1eb0ead2e7117f3f9bbf72db98409ef1234c8b3b60fea1048f9e97e3c61fd568ccca1da89f6a484bbe8000000000000000000000000000000000475e66c9e4e434c4872b8537e0ab930165b39f41e04b208d74d3033e1d69dfb4b134ae3a9dc46347d30a6805508c0420000000000000000000000000000000019e585e1d9adf34a98a7cd38de35aa243d7853c19bc21747213c11240d5fa41ff3b21ae033dd664aaac8fa45354a470a00000000000000000000000000000000137e91115129cbaa1ae2bbb79abe5505436bb51ddceeb011d56dc5c3c396b6b00067d6e6108bafca40fc717737487b27000000000000000000000000000000001592fec7d33bffa7f3eebf038e3194513736cc41a143471fb8c55a44c7521c07e4d8368e5c6ee21ed0478f949f3e224e0000000000000000000000000000000007f786ea1cc7cd69ae1061d6b914278dfc7ebe8a714aa8cd04323860314c3b4b36054169dd5c6c60e67bfa3902d216f50000000000000000000000000000000019675b09a4de34af3c6e79452b57b31b6d499200e996008a9e7d1c910ca0ad2a352dc39cb3fd7333182476095b7aeec3", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_78", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000002291ff240598e2c129ea12292e4a2fc86e03da9bd9fbbb8bddd6f25797003a4688ba2ed3bafd8dfcf0ddd44c3288c1e000000000000000000000000000000000d7541c9c54a95f3789ca7637348378f8956fd451c3266c8f1a34906bf1cf8e7499fcf8ad1f1a73dafcf71b86833ff3b0000000000000000000000000000000016aed55f56416b8f450283c4afea4c606100eed9bf7b8fea9ab4d04797a7bfe3bf0f10cf229f8ce3156869d75beabe6b0000000000000000000000000000000007e5c03e51a513c6f77179bcb5f7d147dcee32426b4365b1c95f434be7f83a5883d1ee5b0e01a636b3e5377542314b75000000000000000000000000000000000fbe421858e4109c51de57b77da4f9c4c1f950099532d9e30e2f7a8b8b4fb9f708cde1a497050d0944e089978b15321e0000000000000000000000000000000019f48a0bf0f27df65ba766a65e831a0801a4ebcd1995a6002a803f88aead1503b7c39fde8ef5c4672020307241958a880000000000000000000000000000000002291ff240598e2c129ea12292e4a2fc86e03da9bd9fbbb8bddd6f25797003a4688ba2ed3bafd8dfcf0ddd44c3288c1e000000000000000000000000000000000c8bd020743550a6d27f0052d0037547db204e3fd752abf6758d899a3793fd3cd50c3073df6258c20a2f8e4797cbab700000000000000000000000000000000016aed55f56416b8f450283c4afea4c606100eed9bf7b8fea9ab4d04797a7bfe3bf0f10cf229f8ce3156869d75beabe6b0000000000000000000000000000000007e5c03e51a513c6f77179bcb5f7d147dcee32426b4365b1c95f434be7f83a5883d1ee5b0e01a636b3e5377542314b75000000000000000000000000000000000fbe421858e4109c51de57b77da4f9c4c1f950099532d9e30e2f7a8b8b4fb9f708cde1a497050d0944e089978b15321e0000000000000000000000000000000019f48a0bf0f27df65ba766a65e831a0801a4ebcd1995a6002a803f88aead1503b7c39fde8ef5c4672020307241958a880000000000000000000000000000000002291ff240598e2c129ea12292e4a2fc86e03da9bd9fbbb8bddd6f25797003a4688ba2ed3bafd8dfcf0ddd44c3288c1e000000000000000000000000000000000d7541c9c54a95f3789ca7637348378f8956fd451c3266c8f1a34906bf1cf8e7499fcf8ad1f1a73dafcf71b86833ff3b0000000000000000000000000000000016aed55f56416b8f450283c4afea4c606100eed9bf7b8fea9ab4d04797a7bfe3bf0f10cf229f8ce3156869d75beabe6b0000000000000000000000000000000007e5c03e51a513c6f77179bcb5f7d147dcee32426b4365b1c95f434be7f83a5883d1ee5b0e01a636b3e5377542314b75000000000000000000000000000000000a42cfd1e09bd5fdf93d4ffec5a6b312a27dfb7b5e5238dc590158156b613c2d15de1e5a1a4ef2f6751e766874ea788d00000000000000000000000000000000000c87de488d68a3ef74410fe4c892cf62d25fb7d9ef6cbf3cb093184803e12066e86020225e3b9899decf8dbe6a20230000000000000000000000000000000002291ff240598e2c129ea12292e4a2fc86e03da9bd9fbbb8bddd6f25797003a4688ba2ed3bafd8dfcf0ddd44c3288c1e000000000000000000000000000000000c8bd020743550a6d27f0052d0037547db204e3fd752abf6758d899a3793fd3cd50c3073df6258c20a2f8e4797cbab700000000000000000000000000000000016aed55f56416b8f450283c4afea4c606100eed9bf7b8fea9ab4d04797a7bfe3bf0f10cf229f8ce3156869d75beabe6b0000000000000000000000000000000007e5c03e51a513c6f77179bcb5f7d147dcee32426b4365b1c95f434be7f83a5883d1ee5b0e01a636b3e5377542314b75000000000000000000000000000000000a42cfd1e09bd5fdf93d4ffec5a6b312a27dfb7b5e5238dc590158156b613c2d15de1e5a1a4ef2f6751e766874ea788d00000000000000000000000000000000000c87de488d68a3ef74410fe4c892cf62d25fb7d9ef6cbf3cb093184803e12066e86020225e3b9899decf8dbe6a20230000000000000000000000000000000002291ff240598e2c129ea12292e4a2fc86e03da9bd9fbbb8bddd6f25797003a4688ba2ed3bafd8dfcf0ddd44c3288c1e000000000000000000000000000000000d7541c9c54a95f3789ca7637348378f8956fd451c3266c8f1a34906bf1cf8e7499fcf8ad1f1a73dafcf71b86833ff3b0000000000000000000000000000000016aed55f56416b8f450283c4afea4c606100eed9bf7b8fea9ab4d04797a7bfe3bf0f10cf229f8ce3156869d75beabe6b0000000000000000000000000000000007e5c03e51a513c6f77179bcb5f7d147dcee32426b4365b1c95f434be7f83a5883d1ee5b0e01a636b3e5377542314b75000000000000000000000000000000000fbe421858e4109c51de57b77da4f9c4c1f950099532d9e30e2f7a8b8b4fb9f708cde1a497050d0944e089978b15321e0000000000000000000000000000000019f48a0bf0f27df65ba766a65e831a0801a4ebcd1995a6002a803f88aead1503b7c39fde8ef5c4672020307241958a88", "Expected": "0000000000000000000000000000000000000000000000000000000000000000", "Name": "matter_pairing_79", - "Gas": 230000, + "Gas": 280000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018d31bd5a7e94ceb18d803969a2001c6eb3bfbcf82c27e88ca60d4c46807d12f116ca71c67d27270c2332205a4ea11bb0000000000000000000000000000000010b6db11d4fc3a2b449b8fd189d2e4ed4591bf4258d7b92b3eb152048cb3a3eecb87782691e9b954377fd1f34b38cb0d0000000000000000000000000000000016114be17b400ba35875d9009b4d8974023a57d32508c9f658a0d82a8efc6b379ce4a3dbf5ca7130c5581f5008806934000000000000000000000000000000000c68cd7b9d3c3d6c559fa3d52da48ebe68e40a44863c332bb90dd151d1281dd3faa34e6c7b07c277affbdbc1b0a43cfa000000000000000000000000000000001233421a38d77c59bbe1b83992a7a6c964ede5ef83c5a72bd1ba2c0a81b4205ce9a6925718cabcaf4a72ca3d216fbffc0000000000000000000000000000000016b8c22b35af7d925b5c68b6b7b63442e051fdc45542f233f2d97106c4b960eeb47f204c659d16a3a0d3b65ee38ff1480000000000000000000000000000000018d31bd5a7e94ceb18d803969a2001c6eb3bfbcf82c27e88ca60d4c46807d12f116ca71c67d27270c2332205a4ea11bb00000000000000000000000000000000094a36d86483ac6f068017e4b978c7ea1ee58c429aad5994287f809c69fd5235532487d81f6a46ab827f2e0cb4c6df9e0000000000000000000000000000000016114be17b400ba35875d9009b4d8974023a57d32508c9f658a0d82a8efc6b379ce4a3dbf5ca7130c5581f5008806934000000000000000000000000000000000c68cd7b9d3c3d6c559fa3d52da48ebe68e40a44863c332bb90dd151d1281dd3faa34e6c7b07c277affbdbc1b0a43cfa000000000000000000000000000000001233421a38d77c59bbe1b83992a7a6c964ede5ef83c5a72bd1ba2c0a81b4205ce9a6925718cabcaf4a72ca3d216fbffc0000000000000000000000000000000016b8c22b35af7d925b5c68b6b7b63442e051fdc45542f233f2d97106c4b960eeb47f204c659d16a3a0d3b65ee38ff1480000000000000000000000000000000018d31bd5a7e94ceb18d803969a2001c6eb3bfbcf82c27e88ca60d4c46807d12f116ca71c67d27270c2332205a4ea11bb0000000000000000000000000000000010b6db11d4fc3a2b449b8fd189d2e4ed4591bf4258d7b92b3eb152048cb3a3eecb87782691e9b954377fd1f34b38cb0d0000000000000000000000000000000016114be17b400ba35875d9009b4d8974023a57d32508c9f658a0d82a8efc6b379ce4a3dbf5ca7130c5581f5008806934000000000000000000000000000000000c68cd7b9d3c3d6c559fa3d52da48ebe68e40a44863c332bb90dd151d1281dd3faa34e6c7b07c277affbdbc1b0a43cfa0000000000000000000000000000000007cdcfd000a86a408f39ef7cb0a4060dff8965956fbf6b939576a69674fcd5c735056da7988943506f8c35c2de8feaaf0000000000000000000000000000000003484fbf03d06907efbf3eff8b95789484254dc09e42208b7457619a31f795356a2cdfb24bb6e95c192b49a11c6fb9630000000000000000000000000000000018d31bd5a7e94ceb18d803969a2001c6eb3bfbcf82c27e88ca60d4c46807d12f116ca71c67d27270c2332205a4ea11bb00000000000000000000000000000000094a36d86483ac6f068017e4b978c7ea1ee58c429aad5994287f809c69fd5235532487d81f6a46ab827f2e0cb4c6df9e0000000000000000000000000000000016114be17b400ba35875d9009b4d8974023a57d32508c9f658a0d82a8efc6b379ce4a3dbf5ca7130c5581f5008806934000000000000000000000000000000000c68cd7b9d3c3d6c559fa3d52da48ebe68e40a44863c332bb90dd151d1281dd3faa34e6c7b07c277affbdbc1b0a43cfa0000000000000000000000000000000007cdcfd000a86a408f39ef7cb0a4060dff8965956fbf6b939576a69674fcd5c735056da7988943506f8c35c2de8feaaf0000000000000000000000000000000003484fbf03d06907efbf3eff8b95789484254dc09e42208b7457619a31f795356a2cdfb24bb6e95c192b49a11c6fb9630000000000000000000000000000000018d31bd5a7e94ceb18d803969a2001c6eb3bfbcf82c27e88ca60d4c46807d12f116ca71c67d27270c2332205a4ea11bb0000000000000000000000000000000010b6db11d4fc3a2b449b8fd189d2e4ed4591bf4258d7b92b3eb152048cb3a3eecb87782691e9b954377fd1f34b38cb0d0000000000000000000000000000000016114be17b400ba35875d9009b4d8974023a57d32508c9f658a0d82a8efc6b379ce4a3dbf5ca7130c5581f5008806934000000000000000000000000000000000c68cd7b9d3c3d6c559fa3d52da48ebe68e40a44863c332bb90dd151d1281dd3faa34e6c7b07c277affbdbc1b0a43cfa000000000000000000000000000000001233421a38d77c59bbe1b83992a7a6c964ede5ef83c5a72bd1ba2c0a81b4205ce9a6925718cabcaf4a72ca3d216fbffc0000000000000000000000000000000016b8c22b35af7d925b5c68b6b7b63442e051fdc45542f233f2d97106c4b960eeb47f204c659d16a3a0d3b65ee38ff1480000000000000000000000000000000018d31bd5a7e94ceb18d803969a2001c6eb3bfbcf82c27e88ca60d4c46807d12f116ca71c67d27270c2332205a4ea11bb00000000000000000000000000000000094a36d86483ac6f068017e4b978c7ea1ee58c429aad5994287f809c69fd5235532487d81f6a46ab827f2e0cb4c6df9e0000000000000000000000000000000016114be17b400ba35875d9009b4d8974023a57d32508c9f658a0d82a8efc6b379ce4a3dbf5ca7130c5581f5008806934000000000000000000000000000000000c68cd7b9d3c3d6c559fa3d52da48ebe68e40a44863c332bb90dd151d1281dd3faa34e6c7b07c277affbdbc1b0a43cfa000000000000000000000000000000001233421a38d77c59bbe1b83992a7a6c964ede5ef83c5a72bd1ba2c0a81b4205ce9a6925718cabcaf4a72ca3d216fbffc0000000000000000000000000000000016b8c22b35af7d925b5c68b6b7b63442e051fdc45542f233f2d97106c4b960eeb47f204c659d16a3a0d3b65ee38ff1480000000000000000000000000000000018d31bd5a7e94ceb18d803969a2001c6eb3bfbcf82c27e88ca60d4c46807d12f116ca71c67d27270c2332205a4ea11bb0000000000000000000000000000000010b6db11d4fc3a2b449b8fd189d2e4ed4591bf4258d7b92b3eb152048cb3a3eecb87782691e9b954377fd1f34b38cb0d0000000000000000000000000000000016114be17b400ba35875d9009b4d8974023a57d32508c9f658a0d82a8efc6b379ce4a3dbf5ca7130c5581f5008806934000000000000000000000000000000000c68cd7b9d3c3d6c559fa3d52da48ebe68e40a44863c332bb90dd151d1281dd3faa34e6c7b07c277affbdbc1b0a43cfa0000000000000000000000000000000007cdcfd000a86a408f39ef7cb0a4060dff8965956fbf6b939576a69674fcd5c735056da7988943506f8c35c2de8feaaf0000000000000000000000000000000003484fbf03d06907efbf3eff8b95789484254dc09e42208b7457619a31f795356a2cdfb24bb6e95c192b49a11c6fb9630000000000000000000000000000000018d31bd5a7e94ceb18d803969a2001c6eb3bfbcf82c27e88ca60d4c46807d12f116ca71c67d27270c2332205a4ea11bb00000000000000000000000000000000094a36d86483ac6f068017e4b978c7ea1ee58c429aad5994287f809c69fd5235532487d81f6a46ab827f2e0cb4c6df9e0000000000000000000000000000000016114be17b400ba35875d9009b4d8974023a57d32508c9f658a0d82a8efc6b379ce4a3dbf5ca7130c5581f5008806934000000000000000000000000000000000c68cd7b9d3c3d6c559fa3d52da48ebe68e40a44863c332bb90dd151d1281dd3faa34e6c7b07c277affbdbc1b0a43cfa0000000000000000000000000000000007cdcfd000a86a408f39ef7cb0a4060dff8965956fbf6b939576a69674fcd5c735056da7988943506f8c35c2de8feaaf0000000000000000000000000000000003484fbf03d06907efbf3eff8b95789484254dc09e42208b7457619a31f795356a2cdfb24bb6e95c192b49a11c6fb963", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_80", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000190f4dc14439eccc46d46c5c9b15eeba0bbf2dbca11af4183408afdb15c7bfa26f107cf5fda0c1e0236aab95728eac2e000000000000000000000000000000000c47feeb1a1d2891d986b1660810859c1bba427d43a69b4e5ddeaf77116418138bfc2b7b4aa4c0cc6df10bd116721d5000000000000000000000000000000000135b96feb4f1e712661ce0d13842de1198c589f335141ab1fd7ffc6b9d58de82c300e9fe6dacdefe8e68b6db9298da5100000000000000000000000000000000046a3563d167d8b0a9f74e0c6514fdabd795110cf48caa014947ca90a9eeda3d07dd7dce58d3f2b7b86fab1143946b560000000000000000000000000000000016c917abe637da21e60378ea7c2682306aded4ff17ccfea742e9ba63590be1b0fd5432ff0d3b72cdcb15943763cbb6bb00000000000000000000000000000000153bdddfe73f21c3593b128d3885f621935585ba1715e1d989e87cf7271897eea3917b81f0f342790f0f7a330ca0c68f00000000000000000000000000000000190f4dc14439eccc46d46c5c9b15eeba0bbf2dbca11af4183408afdb15c7bfa26f107cf5fda0c1e0236aab95728eac2e000000000000000000000000000000000db912ff1f62be087194f6503b3b273b48bd0907afde777109522329e54cde1092afd48366af3f334c0df42ee98d8d5b00000000000000000000000000000000135b96feb4f1e712661ce0d13842de1198c589f335141ab1fd7ffc6b9d58de82c300e9fe6dacdefe8e68b6db9298da5100000000000000000000000000000000046a3563d167d8b0a9f74e0c6514fdabd795110cf48caa014947ca90a9eeda3d07dd7dce58d3f2b7b86fab1143946b560000000000000000000000000000000016c917abe637da21e60378ea7c2682306aded4ff17ccfea742e9ba63590be1b0fd5432ff0d3b72cdcb15943763cbb6bb00000000000000000000000000000000153bdddfe73f21c3593b128d3885f621935585ba1715e1d989e87cf7271897eea3917b81f0f342790f0f7a330ca0c68f00000000000000000000000000000000190f4dc14439eccc46d46c5c9b15eeba0bbf2dbca11af4183408afdb15c7bfa26f107cf5fda0c1e0236aab95728eac2e000000000000000000000000000000000c47feeb1a1d2891d986b1660810859c1bba427d43a69b4e5ddeaf77116418138bfc2b7b4aa4c0cc6df10bd116721d5000000000000000000000000000000000135b96feb4f1e712661ce0d13842de1198c589f335141ab1fd7ffc6b9d58de82c300e9fe6dacdefe8e68b6db9298da5100000000000000000000000000000000046a3563d167d8b0a9f74e0c6514fdabd795110cf48caa014947ca90a9eeda3d07dd7dce58d3f2b7b86fab1143946b56000000000000000000000000000000000337fa3e53480c7865182ecbc7252aa6f9987685dbb814182447183d9da514732157ccffa4188d31eee96bc89c33f3f00000000000000000000000000000000004c5340a5240c4d6f1e095290ac5b6b5d121c5cadc6f30e5dd4855a9cf985e357b1a847cc060bd86aaef85ccf35ee41c00000000000000000000000000000000190f4dc14439eccc46d46c5c9b15eeba0bbf2dbca11af4183408afdb15c7bfa26f107cf5fda0c1e0236aab95728eac2e000000000000000000000000000000000db912ff1f62be087194f6503b3b273b48bd0907afde777109522329e54cde1092afd48366af3f334c0df42ee98d8d5b00000000000000000000000000000000135b96feb4f1e712661ce0d13842de1198c589f335141ab1fd7ffc6b9d58de82c300e9fe6dacdefe8e68b6db9298da5100000000000000000000000000000000046a3563d167d8b0a9f74e0c6514fdabd795110cf48caa014947ca90a9eeda3d07dd7dce58d3f2b7b86fab1143946b56000000000000000000000000000000000337fa3e53480c7865182ecbc7252aa6f9987685dbb814182447183d9da514732157ccffa4188d31eee96bc89c33f3f00000000000000000000000000000000004c5340a5240c4d6f1e095290ac5b6b5d121c5cadc6f30e5dd4855a9cf985e357b1a847cc060bd86aaef85ccf35ee41c00000000000000000000000000000000190f4dc14439eccc46d46c5c9b15eeba0bbf2dbca11af4183408afdb15c7bfa26f107cf5fda0c1e0236aab95728eac2e000000000000000000000000000000000c47feeb1a1d2891d986b1660810859c1bba427d43a69b4e5ddeaf77116418138bfc2b7b4aa4c0cc6df10bd116721d5000000000000000000000000000000000135b96feb4f1e712661ce0d13842de1198c589f335141ab1fd7ffc6b9d58de82c300e9fe6dacdefe8e68b6db9298da5100000000000000000000000000000000046a3563d167d8b0a9f74e0c6514fdabd795110cf48caa014947ca90a9eeda3d07dd7dce58d3f2b7b86fab1143946b560000000000000000000000000000000016c917abe637da21e60378ea7c2682306aded4ff17ccfea742e9ba63590be1b0fd5432ff0d3b72cdcb15943763cbb6bb00000000000000000000000000000000153bdddfe73f21c3593b128d3885f621935585ba1715e1d989e87cf7271897eea3917b81f0f342790f0f7a330ca0c68f00000000000000000000000000000000190f4dc14439eccc46d46c5c9b15eeba0bbf2dbca11af4183408afdb15c7bfa26f107cf5fda0c1e0236aab95728eac2e000000000000000000000000000000000db912ff1f62be087194f6503b3b273b48bd0907afde777109522329e54cde1092afd48366af3f334c0df42ee98d8d5b00000000000000000000000000000000135b96feb4f1e712661ce0d13842de1198c589f335141ab1fd7ffc6b9d58de82c300e9fe6dacdefe8e68b6db9298da5100000000000000000000000000000000046a3563d167d8b0a9f74e0c6514fdabd795110cf48caa014947ca90a9eeda3d07dd7dce58d3f2b7b86fab1143946b560000000000000000000000000000000016c917abe637da21e60378ea7c2682306aded4ff17ccfea742e9ba63590be1b0fd5432ff0d3b72cdcb15943763cbb6bb00000000000000000000000000000000153bdddfe73f21c3593b128d3885f621935585ba1715e1d989e87cf7271897eea3917b81f0f342790f0f7a330ca0c68f00000000000000000000000000000000190f4dc14439eccc46d46c5c9b15eeba0bbf2dbca11af4183408afdb15c7bfa26f107cf5fda0c1e0236aab95728eac2e000000000000000000000000000000000c47feeb1a1d2891d986b1660810859c1bba427d43a69b4e5ddeaf77116418138bfc2b7b4aa4c0cc6df10bd116721d5000000000000000000000000000000000135b96feb4f1e712661ce0d13842de1198c589f335141ab1fd7ffc6b9d58de82c300e9fe6dacdefe8e68b6db9298da5100000000000000000000000000000000046a3563d167d8b0a9f74e0c6514fdabd795110cf48caa014947ca90a9eeda3d07dd7dce58d3f2b7b86fab1143946b56000000000000000000000000000000000337fa3e53480c7865182ecbc7252aa6f9987685dbb814182447183d9da514732157ccffa4188d31eee96bc89c33f3f00000000000000000000000000000000004c5340a5240c4d6f1e095290ac5b6b5d121c5cadc6f30e5dd4855a9cf985e357b1a847cc060bd86aaef85ccf35ee41c00000000000000000000000000000000190f4dc14439eccc46d46c5c9b15eeba0bbf2dbca11af4183408afdb15c7bfa26f107cf5fda0c1e0236aab95728eac2e000000000000000000000000000000000db912ff1f62be087194f6503b3b273b48bd0907afde777109522329e54cde1092afd48366af3f334c0df42ee98d8d5b00000000000000000000000000000000135b96feb4f1e712661ce0d13842de1198c589f335141ab1fd7ffc6b9d58de82c300e9fe6dacdefe8e68b6db9298da5100000000000000000000000000000000046a3563d167d8b0a9f74e0c6514fdabd795110cf48caa014947ca90a9eeda3d07dd7dce58d3f2b7b86fab1143946b56000000000000000000000000000000000337fa3e53480c7865182ecbc7252aa6f9987685dbb814182447183d9da514732157ccffa4188d31eee96bc89c33f3f00000000000000000000000000000000004c5340a5240c4d6f1e095290ac5b6b5d121c5cadc6f30e5dd4855a9cf985e357b1a847cc060bd86aaef85ccf35ee41c", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_81", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d8000000000000000000000000000000000062783335b87300c97b38e03e5b1318d15a499b29a473c187f930bf34bc1214b4d822725678cbde978c7b5ae6d4bad5100000000000000000000000000000000117821e6c87bb0e04882e95d36dce18ca33a2c8bd0efd5532b33d597804c08ff1799b2d64a95cc84bd31ba45c3b1e822000000000000000000000000000000000887c07c8a9ebe3154950746a4506ff192bb4a05dccb0f4a1a8ac2b8ca0da07190129ba44d9bc8e6c2666027c67d2ddc000000000000000000000000000000000a9e191c9775f57810a511c8bd3dca14b3328e20f0983ca72e42e561b5dd1693209b42a11f2faeecd6307dd34cc01d60000000000000000000000000000000000146061b13546754c74a705776656100a9577f1ff939a82ba990d6b885b27c450f824555829bbb19f9b1f636991799cf00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d800000000000000000000000000000000013d98eb6ddf8b68db36819b25d9a7b4a4ed2b1d2593dd6a6e79dc6adaaefd4d8d129d8d949c7421641374a5192b3fd5a00000000000000000000000000000000117821e6c87bb0e04882e95d36dce18ca33a2c8bd0efd5532b33d597804c08ff1799b2d64a95cc84bd31ba45c3b1e822000000000000000000000000000000000887c07c8a9ebe3154950746a4506ff192bb4a05dccb0f4a1a8ac2b8ca0da07190129ba44d9bc8e6c2666027c67d2ddc000000000000000000000000000000000a9e191c9775f57810a511c8bd3dca14b3328e20f0983ca72e42e561b5dd1693209b42a11f2faeecd6307dd34cc01d60000000000000000000000000000000000146061b13546754c74a705776656100a9577f1ff939a82ba990d6b885b27c450f824555829bbb19f9b1f636991799cf00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d8000000000000000000000000000000000062783335b87300c97b38e03e5b1318d15a499b29a473c187f930bf34bc1214b4d822725678cbde978c7b5ae6d4bad5100000000000000000000000000000000117821e6c87bb0e04882e95d36dce18ca33a2c8bd0efd5532b33d597804c08ff1799b2d64a95cc84bd31ba45c3b1e822000000000000000000000000000000000887c07c8a9ebe3154950746a4506ff192bb4a05dccb0f4a1a8ac2b8ca0da07190129ba44d9bc8e6c2666027c67d2ddc000000000000000000000000000000000f62f8cda209f1223a7695ed860de2c2b144bd6402ecd61838eded3f40d3df90fe10bd5d92245112e3ce822cb33f8d4b0000000000000000000000000000000018bb0bcf262b7f4583d1375ecce64bd6bb1fcc64fa4b6a93bd9ffbe870fe79df0f29baa92eb844e5c04d09c966e810dc00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d800000000000000000000000000000000013d98eb6ddf8b68db36819b25d9a7b4a4ed2b1d2593dd6a6e79dc6adaaefd4d8d129d8d949c7421641374a5192b3fd5a00000000000000000000000000000000117821e6c87bb0e04882e95d36dce18ca33a2c8bd0efd5532b33d597804c08ff1799b2d64a95cc84bd31ba45c3b1e822000000000000000000000000000000000887c07c8a9ebe3154950746a4506ff192bb4a05dccb0f4a1a8ac2b8ca0da07190129ba44d9bc8e6c2666027c67d2ddc000000000000000000000000000000000f62f8cda209f1223a7695ed860de2c2b144bd6402ecd61838eded3f40d3df90fe10bd5d92245112e3ce822cb33f8d4b0000000000000000000000000000000018bb0bcf262b7f4583d1375ecce64bd6bb1fcc64fa4b6a93bd9ffbe870fe79df0f29baa92eb844e5c04d09c966e810dc00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d8000000000000000000000000000000000062783335b87300c97b38e03e5b1318d15a499b29a473c187f930bf34bc1214b4d822725678cbde978c7b5ae6d4bad5100000000000000000000000000000000117821e6c87bb0e04882e95d36dce18ca33a2c8bd0efd5532b33d597804c08ff1799b2d64a95cc84bd31ba45c3b1e822000000000000000000000000000000000887c07c8a9ebe3154950746a4506ff192bb4a05dccb0f4a1a8ac2b8ca0da07190129ba44d9bc8e6c2666027c67d2ddc000000000000000000000000000000000a9e191c9775f57810a511c8bd3dca14b3328e20f0983ca72e42e561b5dd1693209b42a11f2faeecd6307dd34cc01d60000000000000000000000000000000000146061b13546754c74a705776656100a9577f1ff939a82ba990d6b885b27c450f824555829bbb19f9b1f636991799cf00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d800000000000000000000000000000000013d98eb6ddf8b68db36819b25d9a7b4a4ed2b1d2593dd6a6e79dc6adaaefd4d8d129d8d949c7421641374a5192b3fd5a00000000000000000000000000000000117821e6c87bb0e04882e95d36dce18ca33a2c8bd0efd5532b33d597804c08ff1799b2d64a95cc84bd31ba45c3b1e822000000000000000000000000000000000887c07c8a9ebe3154950746a4506ff192bb4a05dccb0f4a1a8ac2b8ca0da07190129ba44d9bc8e6c2666027c67d2ddc000000000000000000000000000000000a9e191c9775f57810a511c8bd3dca14b3328e20f0983ca72e42e561b5dd1693209b42a11f2faeecd6307dd34cc01d60000000000000000000000000000000000146061b13546754c74a705776656100a9577f1ff939a82ba990d6b885b27c450f824555829bbb19f9b1f636991799cf00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d8000000000000000000000000000000000062783335b87300c97b38e03e5b1318d15a499b29a473c187f930bf34bc1214b4d822725678cbde978c7b5ae6d4bad5100000000000000000000000000000000117821e6c87bb0e04882e95d36dce18ca33a2c8bd0efd5532b33d597804c08ff1799b2d64a95cc84bd31ba45c3b1e822000000000000000000000000000000000887c07c8a9ebe3154950746a4506ff192bb4a05dccb0f4a1a8ac2b8ca0da07190129ba44d9bc8e6c2666027c67d2ddc000000000000000000000000000000000f62f8cda209f1223a7695ed860de2c2b144bd6402ecd61838eded3f40d3df90fe10bd5d92245112e3ce822cb33f8d4b0000000000000000000000000000000018bb0bcf262b7f4583d1375ecce64bd6bb1fcc64fa4b6a93bd9ffbe870fe79df0f29baa92eb844e5c04d09c966e810dc00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d800000000000000000000000000000000013d98eb6ddf8b68db36819b25d9a7b4a4ed2b1d2593dd6a6e79dc6adaaefd4d8d129d8d949c7421641374a5192b3fd5a00000000000000000000000000000000117821e6c87bb0e04882e95d36dce18ca33a2c8bd0efd5532b33d597804c08ff1799b2d64a95cc84bd31ba45c3b1e822000000000000000000000000000000000887c07c8a9ebe3154950746a4506ff192bb4a05dccb0f4a1a8ac2b8ca0da07190129ba44d9bc8e6c2666027c67d2ddc000000000000000000000000000000000f62f8cda209f1223a7695ed860de2c2b144bd6402ecd61838eded3f40d3df90fe10bd5d92245112e3ce822cb33f8d4b0000000000000000000000000000000018bb0bcf262b7f4583d1375ecce64bd6bb1fcc64fa4b6a93bd9ffbe870fe79df0f29baa92eb844e5c04d09c966e810dc", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_82", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000e4979375cd880e26d00461de629bac880c12e24ede4a7c702f151c34a728a69a021e37b6a1af520a5f47d3a33f8c8a80000000000000000000000000000000013b5317e3ff7540048b19ceebd47c15538d7eb3bf402823b9c348c464afb1000ce0f7ea4c1cb668af5c8cbf77e6a92510000000000000000000000000000000011f9a369401d2c376c77b4b414e345e6108b11594b26521b51afe6318648af232bf9f1455a99dc2f9b0207cc78339510000000000000000000000000000000000863492499f4791e71bd8d58dd2444a34e66dd3e3ca1cb3669f4182fafc9ef080a1d8111b3dd754f2405032350732b32000000000000000000000000000000000e96f685e6f87677cda23177f9fe7fd15726ab31e4d85a5725e93d558bdf61437dbc2c9ebcfc6a94705fa70de88a81bd00000000000000000000000000000000157ce060a46912c992587fde3db4c64a705ab7115717031778176f6ea311cb352f3a76f4839be4658470e4b0b9854f77000000000000000000000000000000000e4979375cd880e26d00461de629bac880c12e24ede4a7c702f151c34a728a69a021e37b6a1af520a5f47d3a33f8c8a800000000000000000000000000000000064be06bf988929a026a0ac78603eb822b9f6048ff829083cafc465aabb5e623509c8159ef889974c43634088195185a0000000000000000000000000000000011f9a369401d2c376c77b4b414e345e6108b11594b26521b51afe6318648af232bf9f1455a99dc2f9b0207cc78339510000000000000000000000000000000000863492499f4791e71bd8d58dd2444a34e66dd3e3ca1cb3669f4182fafc9ef080a1d8111b3dd754f2405032350732b32000000000000000000000000000000000e96f685e6f87677cda23177f9fe7fd15726ab31e4d85a5725e93d558bdf61437dbc2c9ebcfc6a94705fa70de88a81bd00000000000000000000000000000000157ce060a46912c992587fde3db4c64a705ab7115717031778176f6ea311cb352f3a76f4839be4658470e4b0b9854f77000000000000000000000000000000000e4979375cd880e26d00461de629bac880c12e24ede4a7c702f151c34a728a69a021e37b6a1af520a5f47d3a33f8c8a80000000000000000000000000000000013b5317e3ff7540048b19ceebd47c15538d7eb3bf402823b9c348c464afb1000ce0f7ea4c1cb668af5c8cbf77e6a92510000000000000000000000000000000011f9a369401d2c376c77b4b414e345e6108b11594b26521b51afe6318648af232bf9f1455a99dc2f9b0207cc78339510000000000000000000000000000000000863492499f4791e71bd8d58dd2444a34e66dd3e3ca1cb3669f4182fafc9ef080a1d8111b3dd754f2405032350732b32000000000000000000000000000000000b6a1b64528770227d79763e494d2d060d50a0530eacb8684147954b6ad194e0a0efd35ff457956b499f58f2177528ee00000000000000000000000000000000048431899516d3d0b8c327d80596e68cf41c94739c6e0fa7ef196332539f2aeeef71890a2db81b9a358e1b4f467a5b34000000000000000000000000000000000e4979375cd880e26d00461de629bac880c12e24ede4a7c702f151c34a728a69a021e37b6a1af520a5f47d3a33f8c8a800000000000000000000000000000000064be06bf988929a026a0ac78603eb822b9f6048ff829083cafc465aabb5e623509c8159ef889974c43634088195185a0000000000000000000000000000000011f9a369401d2c376c77b4b414e345e6108b11594b26521b51afe6318648af232bf9f1455a99dc2f9b0207cc78339510000000000000000000000000000000000863492499f4791e71bd8d58dd2444a34e66dd3e3ca1cb3669f4182fafc9ef080a1d8111b3dd754f2405032350732b32000000000000000000000000000000000b6a1b64528770227d79763e494d2d060d50a0530eacb8684147954b6ad194e0a0efd35ff457956b499f58f2177528ee00000000000000000000000000000000048431899516d3d0b8c327d80596e68cf41c94739c6e0fa7ef196332539f2aeeef71890a2db81b9a358e1b4f467a5b34000000000000000000000000000000000e4979375cd880e26d00461de629bac880c12e24ede4a7c702f151c34a728a69a021e37b6a1af520a5f47d3a33f8c8a80000000000000000000000000000000013b5317e3ff7540048b19ceebd47c15538d7eb3bf402823b9c348c464afb1000ce0f7ea4c1cb668af5c8cbf77e6a92510000000000000000000000000000000011f9a369401d2c376c77b4b414e345e6108b11594b26521b51afe6318648af232bf9f1455a99dc2f9b0207cc78339510000000000000000000000000000000000863492499f4791e71bd8d58dd2444a34e66dd3e3ca1cb3669f4182fafc9ef080a1d8111b3dd754f2405032350732b32000000000000000000000000000000000e96f685e6f87677cda23177f9fe7fd15726ab31e4d85a5725e93d558bdf61437dbc2c9ebcfc6a94705fa70de88a81bd00000000000000000000000000000000157ce060a46912c992587fde3db4c64a705ab7115717031778176f6ea311cb352f3a76f4839be4658470e4b0b9854f77000000000000000000000000000000000e4979375cd880e26d00461de629bac880c12e24ede4a7c702f151c34a728a69a021e37b6a1af520a5f47d3a33f8c8a800000000000000000000000000000000064be06bf988929a026a0ac78603eb822b9f6048ff829083cafc465aabb5e623509c8159ef889974c43634088195185a0000000000000000000000000000000011f9a369401d2c376c77b4b414e345e6108b11594b26521b51afe6318648af232bf9f1455a99dc2f9b0207cc78339510000000000000000000000000000000000863492499f4791e71bd8d58dd2444a34e66dd3e3ca1cb3669f4182fafc9ef080a1d8111b3dd754f2405032350732b32000000000000000000000000000000000e96f685e6f87677cda23177f9fe7fd15726ab31e4d85a5725e93d558bdf61437dbc2c9ebcfc6a94705fa70de88a81bd00000000000000000000000000000000157ce060a46912c992587fde3db4c64a705ab7115717031778176f6ea311cb352f3a76f4839be4658470e4b0b9854f77000000000000000000000000000000000e4979375cd880e26d00461de629bac880c12e24ede4a7c702f151c34a728a69a021e37b6a1af520a5f47d3a33f8c8a80000000000000000000000000000000013b5317e3ff7540048b19ceebd47c15538d7eb3bf402823b9c348c464afb1000ce0f7ea4c1cb668af5c8cbf77e6a92510000000000000000000000000000000011f9a369401d2c376c77b4b414e345e6108b11594b26521b51afe6318648af232bf9f1455a99dc2f9b0207cc78339510000000000000000000000000000000000863492499f4791e71bd8d58dd2444a34e66dd3e3ca1cb3669f4182fafc9ef080a1d8111b3dd754f2405032350732b32000000000000000000000000000000000b6a1b64528770227d79763e494d2d060d50a0530eacb8684147954b6ad194e0a0efd35ff457956b499f58f2177528ee00000000000000000000000000000000048431899516d3d0b8c327d80596e68cf41c94739c6e0fa7ef196332539f2aeeef71890a2db81b9a358e1b4f467a5b34000000000000000000000000000000000e4979375cd880e26d00461de629bac880c12e24ede4a7c702f151c34a728a69a021e37b6a1af520a5f47d3a33f8c8a800000000000000000000000000000000064be06bf988929a026a0ac78603eb822b9f6048ff829083cafc465aabb5e623509c8159ef889974c43634088195185a0000000000000000000000000000000011f9a369401d2c376c77b4b414e345e6108b11594b26521b51afe6318648af232bf9f1455a99dc2f9b0207cc78339510000000000000000000000000000000000863492499f4791e71bd8d58dd2444a34e66dd3e3ca1cb3669f4182fafc9ef080a1d8111b3dd754f2405032350732b32000000000000000000000000000000000b6a1b64528770227d79763e494d2d060d50a0530eacb8684147954b6ad194e0a0efd35ff457956b499f58f2177528ee00000000000000000000000000000000048431899516d3d0b8c327d80596e68cf41c94739c6e0fa7ef196332539f2aeeef71890a2db81b9a358e1b4f467a5b34", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_83", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000017f16cffb737dadd52b3c5be258733dc47301474b7351c8dcb8ddb4c519018be08b64efea3336f2b6cfa78e0669dccf9000000000000000000000000000000000ae10eb4f791aa31e5bd7b6c4d68b04c6744262d8f5e9469b3987b101ff5a3066794e05694a9167b7050c3944b6d84f60000000000000000000000000000000000a8382a5f73a7d15c3ee35e5fcaf7142e6d91d71ef30ce7da9c8db2f80c95441dc93674bed244096b71aea40d43c318000000000000000000000000000000000733e9a022695ed6908caf6ec7e67211c6d5ac16ba3fb8e244227f5da787e69e7311fac1e8d102a2d84e6ba98903ff6e0000000000000000000000000000000016002a054bdf3cd916b5f8aca47d97feb170e8864da2eff8bbbf19a5b25ac857dbe6daab97dfe15a4e82455d154652e2000000000000000000000000000000000efc6f6c595368288f5687e710e2faebf12bd63a0ca34a527c05f1d925fcedd23c5e2b6708194069a36f858fa510ee410000000000000000000000000000000017f16cffb737dadd52b3c5be258733dc47301474b7351c8dcb8ddb4c519018be08b64efea3336f2b6cfa78e0669dccf9000000000000000000000000000000000f20033541ee3c68655e2c49f5e2fc8afd33255764267e55b3985790d6bb531db7171fa81caae98449ae3c6bb49225b50000000000000000000000000000000000a8382a5f73a7d15c3ee35e5fcaf7142e6d91d71ef30ce7da9c8db2f80c95441dc93674bed244096b71aea40d43c318000000000000000000000000000000000733e9a022695ed6908caf6ec7e67211c6d5ac16ba3fb8e244227f5da787e69e7311fac1e8d102a2d84e6ba98903ff6e0000000000000000000000000000000016002a054bdf3cd916b5f8aca47d97feb170e8864da2eff8bbbf19a5b25ac857dbe6daab97dfe15a4e82455d154652e2000000000000000000000000000000000efc6f6c595368288f5687e710e2faebf12bd63a0ca34a527c05f1d925fcedd23c5e2b6708194069a36f858fa510ee410000000000000000000000000000000017f16cffb737dadd52b3c5be258733dc47301474b7351c8dcb8ddb4c519018be08b64efea3336f2b6cfa78e0669dccf9000000000000000000000000000000000ae10eb4f791aa31e5bd7b6c4d68b04c6744262d8f5e9469b3987b101ff5a3066794e05694a9167b7050c3944b6d84f60000000000000000000000000000000000a8382a5f73a7d15c3ee35e5fcaf7142e6d91d71ef30ce7da9c8db2f80c95441dc93674bed244096b71aea40d43c318000000000000000000000000000000000733e9a022695ed6908caf6ec7e67211c6d5ac16ba3fb8e244227f5da787e69e7311fac1e8d102a2d84e6ba98903ff6e000000000000000000000000000000000400e7e4eda0a9c13465af099ece14d8b30662fea5e222c6ab71b8fb44562dcc42c5255319741ea56b7cbaa2eab957c9000000000000000000000000000000000b04a27de02c7e71bbc51fcf3268b1eb734b754ae6e1c86ceb2ae0c7d0b40851e24dd497a93abf96168f7a705aeebc6a0000000000000000000000000000000017f16cffb737dadd52b3c5be258733dc47301474b7351c8dcb8ddb4c519018be08b64efea3336f2b6cfa78e0669dccf9000000000000000000000000000000000f20033541ee3c68655e2c49f5e2fc8afd33255764267e55b3985790d6bb531db7171fa81caae98449ae3c6bb49225b50000000000000000000000000000000000a8382a5f73a7d15c3ee35e5fcaf7142e6d91d71ef30ce7da9c8db2f80c95441dc93674bed244096b71aea40d43c318000000000000000000000000000000000733e9a022695ed6908caf6ec7e67211c6d5ac16ba3fb8e244227f5da787e69e7311fac1e8d102a2d84e6ba98903ff6e000000000000000000000000000000000400e7e4eda0a9c13465af099ece14d8b30662fea5e222c6ab71b8fb44562dcc42c5255319741ea56b7cbaa2eab957c9000000000000000000000000000000000b04a27de02c7e71bbc51fcf3268b1eb734b754ae6e1c86ceb2ae0c7d0b40851e24dd497a93abf96168f7a705aeebc6a0000000000000000000000000000000017f16cffb737dadd52b3c5be258733dc47301474b7351c8dcb8ddb4c519018be08b64efea3336f2b6cfa78e0669dccf9000000000000000000000000000000000ae10eb4f791aa31e5bd7b6c4d68b04c6744262d8f5e9469b3987b101ff5a3066794e05694a9167b7050c3944b6d84f60000000000000000000000000000000000a8382a5f73a7d15c3ee35e5fcaf7142e6d91d71ef30ce7da9c8db2f80c95441dc93674bed244096b71aea40d43c318000000000000000000000000000000000733e9a022695ed6908caf6ec7e67211c6d5ac16ba3fb8e244227f5da787e69e7311fac1e8d102a2d84e6ba98903ff6e0000000000000000000000000000000016002a054bdf3cd916b5f8aca47d97feb170e8864da2eff8bbbf19a5b25ac857dbe6daab97dfe15a4e82455d154652e2000000000000000000000000000000000efc6f6c595368288f5687e710e2faebf12bd63a0ca34a527c05f1d925fcedd23c5e2b6708194069a36f858fa510ee410000000000000000000000000000000017f16cffb737dadd52b3c5be258733dc47301474b7351c8dcb8ddb4c519018be08b64efea3336f2b6cfa78e0669dccf9000000000000000000000000000000000f20033541ee3c68655e2c49f5e2fc8afd33255764267e55b3985790d6bb531db7171fa81caae98449ae3c6bb49225b50000000000000000000000000000000000a8382a5f73a7d15c3ee35e5fcaf7142e6d91d71ef30ce7da9c8db2f80c95441dc93674bed244096b71aea40d43c318000000000000000000000000000000000733e9a022695ed6908caf6ec7e67211c6d5ac16ba3fb8e244227f5da787e69e7311fac1e8d102a2d84e6ba98903ff6e0000000000000000000000000000000016002a054bdf3cd916b5f8aca47d97feb170e8864da2eff8bbbf19a5b25ac857dbe6daab97dfe15a4e82455d154652e2000000000000000000000000000000000efc6f6c595368288f5687e710e2faebf12bd63a0ca34a527c05f1d925fcedd23c5e2b6708194069a36f858fa510ee410000000000000000000000000000000017f16cffb737dadd52b3c5be258733dc47301474b7351c8dcb8ddb4c519018be08b64efea3336f2b6cfa78e0669dccf9000000000000000000000000000000000ae10eb4f791aa31e5bd7b6c4d68b04c6744262d8f5e9469b3987b101ff5a3066794e05694a9167b7050c3944b6d84f60000000000000000000000000000000000a8382a5f73a7d15c3ee35e5fcaf7142e6d91d71ef30ce7da9c8db2f80c95441dc93674bed244096b71aea40d43c318000000000000000000000000000000000733e9a022695ed6908caf6ec7e67211c6d5ac16ba3fb8e244227f5da787e69e7311fac1e8d102a2d84e6ba98903ff6e000000000000000000000000000000000400e7e4eda0a9c13465af099ece14d8b30662fea5e222c6ab71b8fb44562dcc42c5255319741ea56b7cbaa2eab957c9000000000000000000000000000000000b04a27de02c7e71bbc51fcf3268b1eb734b754ae6e1c86ceb2ae0c7d0b40851e24dd497a93abf96168f7a705aeebc6a0000000000000000000000000000000017f16cffb737dadd52b3c5be258733dc47301474b7351c8dcb8ddb4c519018be08b64efea3336f2b6cfa78e0669dccf9000000000000000000000000000000000f20033541ee3c68655e2c49f5e2fc8afd33255764267e55b3985790d6bb531db7171fa81caae98449ae3c6bb49225b50000000000000000000000000000000000a8382a5f73a7d15c3ee35e5fcaf7142e6d91d71ef30ce7da9c8db2f80c95441dc93674bed244096b71aea40d43c318000000000000000000000000000000000733e9a022695ed6908caf6ec7e67211c6d5ac16ba3fb8e244227f5da787e69e7311fac1e8d102a2d84e6ba98903ff6e000000000000000000000000000000000400e7e4eda0a9c13465af099ece14d8b30662fea5e222c6ab71b8fb44562dcc42c5255319741ea56b7cbaa2eab957c9000000000000000000000000000000000b04a27de02c7e71bbc51fcf3268b1eb734b754ae6e1c86ceb2ae0c7d0b40851e24dd497a93abf96168f7a705aeebc6a", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_84", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "00000000000000000000000000000000062168f0bfd29c44074430158708a1e3b6808bae633ce9506b32eb9124db1a0668d83f2076adffb568ccf289a61685420000000000000000000000000000000016aead8bd8c4d5ddc444e15bc83e8f14d377d5e8d756a0255f1387506b9a9add69592241dbd9cab95474d55ac473886200000000000000000000000000000000050b449c2425926d961af37c4c88e671eac676a1f828def54b76dc04960d0222fb5832ed44c45d5fbb59549d9d24c236000000000000000000000000000000000c6e811987b30ed77c804e647f867186d425411e514e9bf31099cc0f695195729ae970766b2738a928e776511a44f8a1000000000000000000000000000000001408beb1c3951d79fa43477c5af6894ee3c2ea9605f8ae64a78b51ee7e16ae9641134a9a75735972dbd7b53dd4c9f3bf000000000000000000000000000000000e6c6c9405ff001faa8d8c06bcbd75ee91140f477ef8283d3c5eb3039f16543ca9e7e4162177a7499edb6f3fdb01643f00000000000000000000000000000000062168f0bfd29c44074430158708a1e3b6808bae633ce9506b32eb9124db1a0668d83f2076adffb568ccf289a6168542000000000000000000000000000000000352645e60bb10bc86d6c65a7b0d1dc290ff759c1c2e729a081d4b508b165b46b552ddbcd57a3546658a2aa53b8c224900000000000000000000000000000000050b449c2425926d961af37c4c88e671eac676a1f828def54b76dc04960d0222fb5832ed44c45d5fbb59549d9d24c236000000000000000000000000000000000c6e811987b30ed77c804e647f867186d425411e514e9bf31099cc0f695195729ae970766b2738a928e776511a44f8a1000000000000000000000000000000001408beb1c3951d79fa43477c5af6894ee3c2ea9605f8ae64a78b51ee7e16ae9641134a9a75735972dbd7b53dd4c9f3bf000000000000000000000000000000000e6c6c9405ff001faa8d8c06bcbd75ee91140f477ef8283d3c5eb3039f16543ca9e7e4162177a7499edb6f3fdb01643f00000000000000000000000000000000062168f0bfd29c44074430158708a1e3b6808bae633ce9506b32eb9124db1a0668d83f2076adffb568ccf289a61685420000000000000000000000000000000016aead8bd8c4d5ddc444e15bc83e8f14d377d5e8d756a0255f1387506b9a9add69592241dbd9cab95474d55ac473886200000000000000000000000000000000050b449c2425926d961af37c4c88e671eac676a1f828def54b76dc04960d0222fb5832ed44c45d5fbb59549d9d24c236000000000000000000000000000000000c6e811987b30ed77c804e647f867186d425411e514e9bf31099cc0f695195729ae970766b2738a928e776511a44f8a10000000000000000000000000000000005f8533875eac92050d86039e855238880b460eeed8c645abfa580b2789a478ddd98b5643be0a68cde274ac22b35b6ec000000000000000000000000000000000b94a5563380e67aa08e1baf868e36e8d3633c3d748cea822ad21f9d579aa1e774c41be88fdc58b61b2390c024fe466c00000000000000000000000000000000062168f0bfd29c44074430158708a1e3b6808bae633ce9506b32eb9124db1a0668d83f2076adffb568ccf289a6168542000000000000000000000000000000000352645e60bb10bc86d6c65a7b0d1dc290ff759c1c2e729a081d4b508b165b46b552ddbcd57a3546658a2aa53b8c224900000000000000000000000000000000050b449c2425926d961af37c4c88e671eac676a1f828def54b76dc04960d0222fb5832ed44c45d5fbb59549d9d24c236000000000000000000000000000000000c6e811987b30ed77c804e647f867186d425411e514e9bf31099cc0f695195729ae970766b2738a928e776511a44f8a10000000000000000000000000000000005f8533875eac92050d86039e855238880b460eeed8c645abfa580b2789a478ddd98b5643be0a68cde274ac22b35b6ec000000000000000000000000000000000b94a5563380e67aa08e1baf868e36e8d3633c3d748cea822ad21f9d579aa1e774c41be88fdc58b61b2390c024fe466c00000000000000000000000000000000062168f0bfd29c44074430158708a1e3b6808bae633ce9506b32eb9124db1a0668d83f2076adffb568ccf289a61685420000000000000000000000000000000016aead8bd8c4d5ddc444e15bc83e8f14d377d5e8d756a0255f1387506b9a9add69592241dbd9cab95474d55ac473886200000000000000000000000000000000050b449c2425926d961af37c4c88e671eac676a1f828def54b76dc04960d0222fb5832ed44c45d5fbb59549d9d24c236000000000000000000000000000000000c6e811987b30ed77c804e647f867186d425411e514e9bf31099cc0f695195729ae970766b2738a928e776511a44f8a1000000000000000000000000000000001408beb1c3951d79fa43477c5af6894ee3c2ea9605f8ae64a78b51ee7e16ae9641134a9a75735972dbd7b53dd4c9f3bf000000000000000000000000000000000e6c6c9405ff001faa8d8c06bcbd75ee91140f477ef8283d3c5eb3039f16543ca9e7e4162177a7499edb6f3fdb01643f00000000000000000000000000000000062168f0bfd29c44074430158708a1e3b6808bae633ce9506b32eb9124db1a0668d83f2076adffb568ccf289a6168542000000000000000000000000000000000352645e60bb10bc86d6c65a7b0d1dc290ff759c1c2e729a081d4b508b165b46b552ddbcd57a3546658a2aa53b8c224900000000000000000000000000000000050b449c2425926d961af37c4c88e671eac676a1f828def54b76dc04960d0222fb5832ed44c45d5fbb59549d9d24c236000000000000000000000000000000000c6e811987b30ed77c804e647f867186d425411e514e9bf31099cc0f695195729ae970766b2738a928e776511a44f8a1000000000000000000000000000000001408beb1c3951d79fa43477c5af6894ee3c2ea9605f8ae64a78b51ee7e16ae9641134a9a75735972dbd7b53dd4c9f3bf000000000000000000000000000000000e6c6c9405ff001faa8d8c06bcbd75ee91140f477ef8283d3c5eb3039f16543ca9e7e4162177a7499edb6f3fdb01643f00000000000000000000000000000000062168f0bfd29c44074430158708a1e3b6808bae633ce9506b32eb9124db1a0668d83f2076adffb568ccf289a61685420000000000000000000000000000000016aead8bd8c4d5ddc444e15bc83e8f14d377d5e8d756a0255f1387506b9a9add69592241dbd9cab95474d55ac473886200000000000000000000000000000000050b449c2425926d961af37c4c88e671eac676a1f828def54b76dc04960d0222fb5832ed44c45d5fbb59549d9d24c236000000000000000000000000000000000c6e811987b30ed77c804e647f867186d425411e514e9bf31099cc0f695195729ae970766b2738a928e776511a44f8a10000000000000000000000000000000005f8533875eac92050d86039e855238880b460eeed8c645abfa580b2789a478ddd98b5643be0a68cde274ac22b35b6ec000000000000000000000000000000000b94a5563380e67aa08e1baf868e36e8d3633c3d748cea822ad21f9d579aa1e774c41be88fdc58b61b2390c024fe466c00000000000000000000000000000000062168f0bfd29c44074430158708a1e3b6808bae633ce9506b32eb9124db1a0668d83f2076adffb568ccf289a6168542000000000000000000000000000000000352645e60bb10bc86d6c65a7b0d1dc290ff759c1c2e729a081d4b508b165b46b552ddbcd57a3546658a2aa53b8c224900000000000000000000000000000000050b449c2425926d961af37c4c88e671eac676a1f828def54b76dc04960d0222fb5832ed44c45d5fbb59549d9d24c236000000000000000000000000000000000c6e811987b30ed77c804e647f867186d425411e514e9bf31099cc0f695195729ae970766b2738a928e776511a44f8a10000000000000000000000000000000005f8533875eac92050d86039e855238880b460eeed8c645abfa580b2789a478ddd98b5643be0a68cde274ac22b35b6ec000000000000000000000000000000000b94a5563380e67aa08e1baf868e36e8d3633c3d748cea822ad21f9d579aa1e774c41be88fdc58b61b2390c024fe466c", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_85", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c60b948942652a8214d8776b77a6c559ca77eb3a537b0a9abadc3058eac8c1d7840f091acd6c0056d5a71468a2b1ceb0000000000000000000000000000000019049c394e547b9b714b5969adcf068b381def6af2b27d1d361d06e9576273a8febb5bf94b5061ccec7afdb5642c0ae8000000000000000000000000000000000a8679f08643ff1c4db54e58de15a4828fc80e3f9d80a932b26b49d5c13831b1dc5dc29af2e080eb08e71938e5010fc400000000000000000000000000000000110957f7e9f8e0806bb3d2a811b91c926feab046ef983495f3f768a6cc6e4a6d95bb92facb77d989e53ce5489aa64b3c0000000000000000000000000000000018a8b48aabc6c003a58593a40b55e54b122994f9ab58cc229d1a0e6a3670244cfe73854f07117dc77dd5c2c81314a17e00000000000000000000000000000000062f6a0a8b9dd56001f0f57f82bb7468d709fb8f33e6729369b015685995ef27abebff9dda55c38b0d9e88a1e0b9fc6c000000000000000000000000000000000c60b948942652a8214d8776b77a6c559ca77eb3a537b0a9abadc3058eac8c1d7840f091acd6c0056d5a71468a2b1ceb0000000000000000000000000000000000fc75b0eb2b6afed9d04e4c957ca64c2c595c1a00d295a23113cbb79f4e827b1ff0a40566039e32cd84024a9bd39fc3000000000000000000000000000000000a8679f08643ff1c4db54e58de15a4828fc80e3f9d80a932b26b49d5c13831b1dc5dc29af2e080eb08e71938e5010fc400000000000000000000000000000000110957f7e9f8e0806bb3d2a811b91c926feab046ef983495f3f768a6cc6e4a6d95bb92facb77d989e53ce5489aa64b3c0000000000000000000000000000000018a8b48aabc6c003a58593a40b55e54b122994f9ab58cc229d1a0e6a3670244cfe73854f07117dc77dd5c2c81314a17e00000000000000000000000000000000062f6a0a8b9dd56001f0f57f82bb7468d709fb8f33e6729369b015685995ef27abebff9dda55c38b0d9e88a1e0b9fc6c000000000000000000000000000000000c60b948942652a8214d8776b77a6c559ca77eb3a537b0a9abadc3058eac8c1d7840f091acd6c0056d5a71468a2b1ceb0000000000000000000000000000000019049c394e547b9b714b5969adcf068b381def6af2b27d1d361d06e9576273a8febb5bf94b5061ccec7afdb5642c0ae8000000000000000000000000000000000a8679f08643ff1c4db54e58de15a4828fc80e3f9d80a932b26b49d5c13831b1dc5dc29af2e080eb08e71938e5010fc400000000000000000000000000000000110957f7e9f8e0806bb3d2a811b91c926feab046ef983495f3f768a6cc6e4a6d95bb92facb77d989e53ce5489aa64b3c0000000000000000000000000000000001585d5f8db92696a596141237f5c78c524db68b482c469cca16c436c040d1d720387aafaa4282383c293d37eceb092d0000000000000000000000000000000013d1a7dfade2113a492ab236c090386e8d6d4ff5bf9ea02bfd80bd389d1b06fc72c00060d6fe3c74ac60775e1f45ae3f000000000000000000000000000000000c60b948942652a8214d8776b77a6c559ca77eb3a537b0a9abadc3058eac8c1d7840f091acd6c0056d5a71468a2b1ceb0000000000000000000000000000000000fc75b0eb2b6afed9d04e4c957ca64c2c595c1a00d295a23113cbb79f4e827b1ff0a40566039e32cd84024a9bd39fc3000000000000000000000000000000000a8679f08643ff1c4db54e58de15a4828fc80e3f9d80a932b26b49d5c13831b1dc5dc29af2e080eb08e71938e5010fc400000000000000000000000000000000110957f7e9f8e0806bb3d2a811b91c926feab046ef983495f3f768a6cc6e4a6d95bb92facb77d989e53ce5489aa64b3c0000000000000000000000000000000001585d5f8db92696a596141237f5c78c524db68b482c469cca16c436c040d1d720387aafaa4282383c293d37eceb092d0000000000000000000000000000000013d1a7dfade2113a492ab236c090386e8d6d4ff5bf9ea02bfd80bd389d1b06fc72c00060d6fe3c74ac60775e1f45ae3f000000000000000000000000000000000c60b948942652a8214d8776b77a6c559ca77eb3a537b0a9abadc3058eac8c1d7840f091acd6c0056d5a71468a2b1ceb0000000000000000000000000000000019049c394e547b9b714b5969adcf068b381def6af2b27d1d361d06e9576273a8febb5bf94b5061ccec7afdb5642c0ae8000000000000000000000000000000000a8679f08643ff1c4db54e58de15a4828fc80e3f9d80a932b26b49d5c13831b1dc5dc29af2e080eb08e71938e5010fc400000000000000000000000000000000110957f7e9f8e0806bb3d2a811b91c926feab046ef983495f3f768a6cc6e4a6d95bb92facb77d989e53ce5489aa64b3c0000000000000000000000000000000018a8b48aabc6c003a58593a40b55e54b122994f9ab58cc229d1a0e6a3670244cfe73854f07117dc77dd5c2c81314a17e00000000000000000000000000000000062f6a0a8b9dd56001f0f57f82bb7468d709fb8f33e6729369b015685995ef27abebff9dda55c38b0d9e88a1e0b9fc6c000000000000000000000000000000000c60b948942652a8214d8776b77a6c559ca77eb3a537b0a9abadc3058eac8c1d7840f091acd6c0056d5a71468a2b1ceb0000000000000000000000000000000000fc75b0eb2b6afed9d04e4c957ca64c2c595c1a00d295a23113cbb79f4e827b1ff0a40566039e32cd84024a9bd39fc3000000000000000000000000000000000a8679f08643ff1c4db54e58de15a4828fc80e3f9d80a932b26b49d5c13831b1dc5dc29af2e080eb08e71938e5010fc400000000000000000000000000000000110957f7e9f8e0806bb3d2a811b91c926feab046ef983495f3f768a6cc6e4a6d95bb92facb77d989e53ce5489aa64b3c0000000000000000000000000000000018a8b48aabc6c003a58593a40b55e54b122994f9ab58cc229d1a0e6a3670244cfe73854f07117dc77dd5c2c81314a17e00000000000000000000000000000000062f6a0a8b9dd56001f0f57f82bb7468d709fb8f33e6729369b015685995ef27abebff9dda55c38b0d9e88a1e0b9fc6c000000000000000000000000000000000c60b948942652a8214d8776b77a6c559ca77eb3a537b0a9abadc3058eac8c1d7840f091acd6c0056d5a71468a2b1ceb0000000000000000000000000000000019049c394e547b9b714b5969adcf068b381def6af2b27d1d361d06e9576273a8febb5bf94b5061ccec7afdb5642c0ae8000000000000000000000000000000000a8679f08643ff1c4db54e58de15a4828fc80e3f9d80a932b26b49d5c13831b1dc5dc29af2e080eb08e71938e5010fc400000000000000000000000000000000110957f7e9f8e0806bb3d2a811b91c926feab046ef983495f3f768a6cc6e4a6d95bb92facb77d989e53ce5489aa64b3c0000000000000000000000000000000001585d5f8db92696a596141237f5c78c524db68b482c469cca16c436c040d1d720387aafaa4282383c293d37eceb092d0000000000000000000000000000000013d1a7dfade2113a492ab236c090386e8d6d4ff5bf9ea02bfd80bd389d1b06fc72c00060d6fe3c74ac60775e1f45ae3f000000000000000000000000000000000c60b948942652a8214d8776b77a6c559ca77eb3a537b0a9abadc3058eac8c1d7840f091acd6c0056d5a71468a2b1ceb0000000000000000000000000000000000fc75b0eb2b6afed9d04e4c957ca64c2c595c1a00d295a23113cbb79f4e827b1ff0a40566039e32cd84024a9bd39fc3000000000000000000000000000000000a8679f08643ff1c4db54e58de15a4828fc80e3f9d80a932b26b49d5c13831b1dc5dc29af2e080eb08e71938e5010fc400000000000000000000000000000000110957f7e9f8e0806bb3d2a811b91c926feab046ef983495f3f768a6cc6e4a6d95bb92facb77d989e53ce5489aa64b3c0000000000000000000000000000000001585d5f8db92696a596141237f5c78c524db68b482c469cca16c436c040d1d720387aafaa4282383c293d37eceb092d0000000000000000000000000000000013d1a7dfade2113a492ab236c090386e8d6d4ff5bf9ea02bfd80bd389d1b06fc72c00060d6fe3c74ac60775e1f45ae3f", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_86", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000013fe38343072af8ef1d8247c3d46b4fd190086ceddfeb767787031368da6a6a6ae849cfc26a24ead499338e37fa337e30000000000000000000000000000000009f7d7b21882455e9f1f24ea120f3eb69f739c1320c37eb2b17e0a271cb03ac6e2b0c55d3518548a005f28b5748b7f59000000000000000000000000000000000ba48cbd776dd03a5b69aed3a31b7d151a8d98cd9adc3b9987cf2ac94644a364ebf3d30cf31742e2152aeba0eebc9ceb0000000000000000000000000000000008793a44c730949a9e50e9439d579ff0991dfc49a67a29b1701989ab065e6e937b14ac1bbca5a3dbf79a61837ad18394000000000000000000000000000000000d81a0809479694fde24e5a3ee7d32deacc25e77f241024666bc3372e80379a722863ea8105f345f1d09e462fc5a8c6c0000000000000000000000000000000001a5be923f1ca5ee876d660fbca5896f1634ef6a83ff8c64dca4ed76d1db2ba4875099fa5a39a09f839731278b307fb10000000000000000000000000000000013fe38343072af8ef1d8247c3d46b4fd190086ceddfeb767787031368da6a6a6ae849cfc26a24ead499338e37fa337e30000000000000000000000000000000010093a3820fda13babfc82cc313c6e20c503af71d2c1940cb5b2c879da00bb5d3bfb3aa17c3bab75b99fd74a8b742b52000000000000000000000000000000000ba48cbd776dd03a5b69aed3a31b7d151a8d98cd9adc3b9987cf2ac94644a364ebf3d30cf31742e2152aeba0eebc9ceb0000000000000000000000000000000008793a44c730949a9e50e9439d579ff0991dfc49a67a29b1701989ab065e6e937b14ac1bbca5a3dbf79a61837ad18394000000000000000000000000000000000d81a0809479694fde24e5a3ee7d32deacc25e77f241024666bc3372e80379a722863ea8105f345f1d09e462fc5a8c6c0000000000000000000000000000000001a5be923f1ca5ee876d660fbca5896f1634ef6a83ff8c64dca4ed76d1db2ba4875099fa5a39a09f839731278b307fb10000000000000000000000000000000013fe38343072af8ef1d8247c3d46b4fd190086ceddfeb767787031368da6a6a6ae849cfc26a24ead499338e37fa337e30000000000000000000000000000000009f7d7b21882455e9f1f24ea120f3eb69f739c1320c37eb2b17e0a271cb03ac6e2b0c55d3518548a005f28b5748b7f59000000000000000000000000000000000ba48cbd776dd03a5b69aed3a31b7d151a8d98cd9adc3b9987cf2ac94644a364ebf3d30cf31742e2152aeba0eebc9ceb0000000000000000000000000000000008793a44c730949a9e50e9439d579ff0991dfc49a67a29b1701989ab065e6e937b14ac1bbca5a3dbf79a61837ad18394000000000000000000000000000000000c7f7169a5067d4a6cf6c21254ce79f8b7b4ed0d0144107900749f2e0ead7c7cfc25c156a0f4cba09cf51b9d03a51e3f00000000000000000000000000000000185b5357fa6340abc3ae41a686a623684e425c1a6f85865a8a8be52a24d5ca7f975b6604571a5f603667ced874cf2afa0000000000000000000000000000000013fe38343072af8ef1d8247c3d46b4fd190086ceddfeb767787031368da6a6a6ae849cfc26a24ead499338e37fa337e30000000000000000000000000000000010093a3820fda13babfc82cc313c6e20c503af71d2c1940cb5b2c879da00bb5d3bfb3aa17c3bab75b99fd74a8b742b52000000000000000000000000000000000ba48cbd776dd03a5b69aed3a31b7d151a8d98cd9adc3b9987cf2ac94644a364ebf3d30cf31742e2152aeba0eebc9ceb0000000000000000000000000000000008793a44c730949a9e50e9439d579ff0991dfc49a67a29b1701989ab065e6e937b14ac1bbca5a3dbf79a61837ad18394000000000000000000000000000000000c7f7169a5067d4a6cf6c21254ce79f8b7b4ed0d0144107900749f2e0ead7c7cfc25c156a0f4cba09cf51b9d03a51e3f00000000000000000000000000000000185b5357fa6340abc3ae41a686a623684e425c1a6f85865a8a8be52a24d5ca7f975b6604571a5f603667ced874cf2afa0000000000000000000000000000000013fe38343072af8ef1d8247c3d46b4fd190086ceddfeb767787031368da6a6a6ae849cfc26a24ead499338e37fa337e30000000000000000000000000000000009f7d7b21882455e9f1f24ea120f3eb69f739c1320c37eb2b17e0a271cb03ac6e2b0c55d3518548a005f28b5748b7f59000000000000000000000000000000000ba48cbd776dd03a5b69aed3a31b7d151a8d98cd9adc3b9987cf2ac94644a364ebf3d30cf31742e2152aeba0eebc9ceb0000000000000000000000000000000008793a44c730949a9e50e9439d579ff0991dfc49a67a29b1701989ab065e6e937b14ac1bbca5a3dbf79a61837ad18394000000000000000000000000000000000d81a0809479694fde24e5a3ee7d32deacc25e77f241024666bc3372e80379a722863ea8105f345f1d09e462fc5a8c6c0000000000000000000000000000000001a5be923f1ca5ee876d660fbca5896f1634ef6a83ff8c64dca4ed76d1db2ba4875099fa5a39a09f839731278b307fb10000000000000000000000000000000013fe38343072af8ef1d8247c3d46b4fd190086ceddfeb767787031368da6a6a6ae849cfc26a24ead499338e37fa337e30000000000000000000000000000000010093a3820fda13babfc82cc313c6e20c503af71d2c1940cb5b2c879da00bb5d3bfb3aa17c3bab75b99fd74a8b742b52000000000000000000000000000000000ba48cbd776dd03a5b69aed3a31b7d151a8d98cd9adc3b9987cf2ac94644a364ebf3d30cf31742e2152aeba0eebc9ceb0000000000000000000000000000000008793a44c730949a9e50e9439d579ff0991dfc49a67a29b1701989ab065e6e937b14ac1bbca5a3dbf79a61837ad18394000000000000000000000000000000000d81a0809479694fde24e5a3ee7d32deacc25e77f241024666bc3372e80379a722863ea8105f345f1d09e462fc5a8c6c0000000000000000000000000000000001a5be923f1ca5ee876d660fbca5896f1634ef6a83ff8c64dca4ed76d1db2ba4875099fa5a39a09f839731278b307fb10000000000000000000000000000000013fe38343072af8ef1d8247c3d46b4fd190086ceddfeb767787031368da6a6a6ae849cfc26a24ead499338e37fa337e30000000000000000000000000000000009f7d7b21882455e9f1f24ea120f3eb69f739c1320c37eb2b17e0a271cb03ac6e2b0c55d3518548a005f28b5748b7f59000000000000000000000000000000000ba48cbd776dd03a5b69aed3a31b7d151a8d98cd9adc3b9987cf2ac94644a364ebf3d30cf31742e2152aeba0eebc9ceb0000000000000000000000000000000008793a44c730949a9e50e9439d579ff0991dfc49a67a29b1701989ab065e6e937b14ac1bbca5a3dbf79a61837ad18394000000000000000000000000000000000c7f7169a5067d4a6cf6c21254ce79f8b7b4ed0d0144107900749f2e0ead7c7cfc25c156a0f4cba09cf51b9d03a51e3f00000000000000000000000000000000185b5357fa6340abc3ae41a686a623684e425c1a6f85865a8a8be52a24d5ca7f975b6604571a5f603667ced874cf2afa0000000000000000000000000000000013fe38343072af8ef1d8247c3d46b4fd190086ceddfeb767787031368da6a6a6ae849cfc26a24ead499338e37fa337e30000000000000000000000000000000010093a3820fda13babfc82cc313c6e20c503af71d2c1940cb5b2c879da00bb5d3bfb3aa17c3bab75b99fd74a8b742b52000000000000000000000000000000000ba48cbd776dd03a5b69aed3a31b7d151a8d98cd9adc3b9987cf2ac94644a364ebf3d30cf31742e2152aeba0eebc9ceb0000000000000000000000000000000008793a44c730949a9e50e9439d579ff0991dfc49a67a29b1701989ab065e6e937b14ac1bbca5a3dbf79a61837ad18394000000000000000000000000000000000c7f7169a5067d4a6cf6c21254ce79f8b7b4ed0d0144107900749f2e0ead7c7cfc25c156a0f4cba09cf51b9d03a51e3f00000000000000000000000000000000185b5357fa6340abc3ae41a686a623684e425c1a6f85865a8a8be52a24d5ca7f975b6604571a5f603667ced874cf2afa", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_87", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018c6df81d810deaac0b143edf79956c92af7941f7b279db345f838bd583177912fc2eb367616ae165e261014a4d7b1b900000000000000000000000000000000146696840e8e988d0eab90ea935dd8b5f1272bbb81eb524e523c57d34ad7c5f0f3b721566f51dac4774826b84cc1c82f0000000000000000000000000000000008691df5b245399f24118badfbef3e01a4acd53dc9ab149e407c733df6122fa91f5cbe2f9d247cdbac18b266d3d8f18300000000000000000000000000000000053e6eef4ffdbe239c8bbade8cfc90461d54f281ee6180c271412bf2d64e005d3f0291d3401c324e41067f4dfcc4b2720000000000000000000000000000000000b76cdde0e1205c918e6e6d324ac3f35d42ebe9bb101f1cd8955acdfa8836f22f1497bced2c93495022b0c335bcaaae0000000000000000000000000000000018340c2a8b079b88595aa50e93251d12e3a5aead2d2add3b72ce82e03a26525aa45fe9b379504392edb0a2a26d7e99dc0000000000000000000000000000000018c6df81d810deaac0b143edf79956c92af7941f7b279db345f838bd583177912fc2eb367616ae165e261014a4d7b1b900000000000000000000000000000000059a7b662af14e0d3c7016cbafedd42173501fc97199c07114f47acdabd930332af4dea84202253b42b6d947b33de27c0000000000000000000000000000000008691df5b245399f24118badfbef3e01a4acd53dc9ab149e407c733df6122fa91f5cbe2f9d247cdbac18b266d3d8f18300000000000000000000000000000000053e6eef4ffdbe239c8bbade8cfc90461d54f281ee6180c271412bf2d64e005d3f0291d3401c324e41067f4dfcc4b2720000000000000000000000000000000000b76cdde0e1205c918e6e6d324ac3f35d42ebe9bb101f1cd8955acdfa8836f22f1497bced2c93495022b0c335bcaaae0000000000000000000000000000000018340c2a8b079b88595aa50e93251d12e3a5aead2d2add3b72ce82e03a26525aa45fe9b379504392edb0a2a26d7e99dc0000000000000000000000000000000018c6df81d810deaac0b143edf79956c92af7941f7b279db345f838bd583177912fc2eb367616ae165e261014a4d7b1b900000000000000000000000000000000146696840e8e988d0eab90ea935dd8b5f1272bbb81eb524e523c57d34ad7c5f0f3b721566f51dac4774826b84cc1c82f0000000000000000000000000000000008691df5b245399f24118badfbef3e01a4acd53dc9ab149e407c733df6122fa91f5cbe2f9d247cdbac18b266d3d8f18300000000000000000000000000000000053e6eef4ffdbe239c8bbade8cfc90461d54f281ee6180c271412bf2d64e005d3f0291d3401c324e41067f4dfcc4b272000000000000000000000000000000001949a50c589ec63db98d39491100e8e407345f9b3874f3a28e9b77d2fc28bf31ef976841c4276cb669dc4f3cca42fffd0000000000000000000000000000000001cd05bfae784b11f1c102a7b0268fc480d19cd7c65a3583f4624fc0bc8aa3c97a4c164b3803bc6ccc4e5d5d928110cf0000000000000000000000000000000018c6df81d810deaac0b143edf79956c92af7941f7b279db345f838bd583177912fc2eb367616ae165e261014a4d7b1b900000000000000000000000000000000059a7b662af14e0d3c7016cbafedd42173501fc97199c07114f47acdabd930332af4dea84202253b42b6d947b33de27c0000000000000000000000000000000008691df5b245399f24118badfbef3e01a4acd53dc9ab149e407c733df6122fa91f5cbe2f9d247cdbac18b266d3d8f18300000000000000000000000000000000053e6eef4ffdbe239c8bbade8cfc90461d54f281ee6180c271412bf2d64e005d3f0291d3401c324e41067f4dfcc4b272000000000000000000000000000000001949a50c589ec63db98d39491100e8e407345f9b3874f3a28e9b77d2fc28bf31ef976841c4276cb669dc4f3cca42fffd0000000000000000000000000000000001cd05bfae784b11f1c102a7b0268fc480d19cd7c65a3583f4624fc0bc8aa3c97a4c164b3803bc6ccc4e5d5d928110cf0000000000000000000000000000000018c6df81d810deaac0b143edf79956c92af7941f7b279db345f838bd583177912fc2eb367616ae165e261014a4d7b1b900000000000000000000000000000000146696840e8e988d0eab90ea935dd8b5f1272bbb81eb524e523c57d34ad7c5f0f3b721566f51dac4774826b84cc1c82f0000000000000000000000000000000008691df5b245399f24118badfbef3e01a4acd53dc9ab149e407c733df6122fa91f5cbe2f9d247cdbac18b266d3d8f18300000000000000000000000000000000053e6eef4ffdbe239c8bbade8cfc90461d54f281ee6180c271412bf2d64e005d3f0291d3401c324e41067f4dfcc4b2720000000000000000000000000000000000b76cdde0e1205c918e6e6d324ac3f35d42ebe9bb101f1cd8955acdfa8836f22f1497bced2c93495022b0c335bcaaae0000000000000000000000000000000018340c2a8b079b88595aa50e93251d12e3a5aead2d2add3b72ce82e03a26525aa45fe9b379504392edb0a2a26d7e99dc0000000000000000000000000000000018c6df81d810deaac0b143edf79956c92af7941f7b279db345f838bd583177912fc2eb367616ae165e261014a4d7b1b900000000000000000000000000000000059a7b662af14e0d3c7016cbafedd42173501fc97199c07114f47acdabd930332af4dea84202253b42b6d947b33de27c0000000000000000000000000000000008691df5b245399f24118badfbef3e01a4acd53dc9ab149e407c733df6122fa91f5cbe2f9d247cdbac18b266d3d8f18300000000000000000000000000000000053e6eef4ffdbe239c8bbade8cfc90461d54f281ee6180c271412bf2d64e005d3f0291d3401c324e41067f4dfcc4b2720000000000000000000000000000000000b76cdde0e1205c918e6e6d324ac3f35d42ebe9bb101f1cd8955acdfa8836f22f1497bced2c93495022b0c335bcaaae0000000000000000000000000000000018340c2a8b079b88595aa50e93251d12e3a5aead2d2add3b72ce82e03a26525aa45fe9b379504392edb0a2a26d7e99dc0000000000000000000000000000000018c6df81d810deaac0b143edf79956c92af7941f7b279db345f838bd583177912fc2eb367616ae165e261014a4d7b1b900000000000000000000000000000000146696840e8e988d0eab90ea935dd8b5f1272bbb81eb524e523c57d34ad7c5f0f3b721566f51dac4774826b84cc1c82f0000000000000000000000000000000008691df5b245399f24118badfbef3e01a4acd53dc9ab149e407c733df6122fa91f5cbe2f9d247cdbac18b266d3d8f18300000000000000000000000000000000053e6eef4ffdbe239c8bbade8cfc90461d54f281ee6180c271412bf2d64e005d3f0291d3401c324e41067f4dfcc4b272000000000000000000000000000000001949a50c589ec63db98d39491100e8e407345f9b3874f3a28e9b77d2fc28bf31ef976841c4276cb669dc4f3cca42fffd0000000000000000000000000000000001cd05bfae784b11f1c102a7b0268fc480d19cd7c65a3583f4624fc0bc8aa3c97a4c164b3803bc6ccc4e5d5d928110cf0000000000000000000000000000000018c6df81d810deaac0b143edf79956c92af7941f7b279db345f838bd583177912fc2eb367616ae165e261014a4d7b1b900000000000000000000000000000000059a7b662af14e0d3c7016cbafedd42173501fc97199c07114f47acdabd930332af4dea84202253b42b6d947b33de27c0000000000000000000000000000000008691df5b245399f24118badfbef3e01a4acd53dc9ab149e407c733df6122fa91f5cbe2f9d247cdbac18b266d3d8f18300000000000000000000000000000000053e6eef4ffdbe239c8bbade8cfc90461d54f281ee6180c271412bf2d64e005d3f0291d3401c324e41067f4dfcc4b272000000000000000000000000000000001949a50c589ec63db98d39491100e8e407345f9b3874f3a28e9b77d2fc28bf31ef976841c4276cb669dc4f3cca42fffd0000000000000000000000000000000001cd05bfae784b11f1c102a7b0268fc480d19cd7c65a3583f4624fc0bc8aa3c97a4c164b3803bc6ccc4e5d5d928110cf", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_88", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000c6b634d90c2664b9fa4ccbca35913d23696825350e21f0a6dd5e9abb17497a0a499e1b7b928a57ba8c730158f63b75d0000000000000000000000000000000009d569f05e69a38231d0f636e1ef040af059a00db4ff09bd2ad82b7e04cc041a33603c2eb9b148e3b1412bdef9740ab400000000000000000000000000000000042120affcefe4735ae25e192d1cf34e40afdc6d2ebdacde2e23d30709fecfb71960bc9131e3702b27b6fcd5c7a98d170000000000000000000000000000000001998caf5163b0dccec7c8423c4c56a7d0f0b26d9034f707ed07f636f42dac590a2674c1667d70be385c4e626815c6640000000000000000000000000000000011d7aff6c4512f68031aeb94ce3733ac43659f9fc58fc94c05d99ae80a7656f66b3e3e86843387d1c10f51b4284755150000000000000000000000000000000012a9e7f3804c6b5b25410a82758cd5b6ea1eb150c696b0d67d92cf9eb1f8e17752184d94a4ad2645b1520d6aee1094ed000000000000000000000000000000000c6b634d90c2664b9fa4ccbca35913d23696825350e21f0a6dd5e9abb17497a0a499e1b7b928a57ba8c730158f63b75d00000000000000000000000000000000102ba7f9db164318194ab17f615ca8cc741dab773e8609023c58a722f1e4f209eb4bc3cff7a2b71c08bdd421068b9ff700000000000000000000000000000000042120affcefe4735ae25e192d1cf34e40afdc6d2ebdacde2e23d30709fecfb71960bc9131e3702b27b6fcd5c7a98d170000000000000000000000000000000001998caf5163b0dccec7c8423c4c56a7d0f0b26d9034f707ed07f636f42dac590a2674c1667d70be385c4e626815c6640000000000000000000000000000000011d7aff6c4512f68031aeb94ce3733ac43659f9fc58fc94c05d99ae80a7656f66b3e3e86843387d1c10f51b4284755150000000000000000000000000000000012a9e7f3804c6b5b25410a82758cd5b6ea1eb150c696b0d67d92cf9eb1f8e17752184d94a4ad2645b1520d6aee1094ed000000000000000000000000000000000c6b634d90c2664b9fa4ccbca35913d23696825350e21f0a6dd5e9abb17497a0a499e1b7b928a57ba8c730158f63b75d0000000000000000000000000000000009d569f05e69a38231d0f636e1ef040af059a00db4ff09bd2ad82b7e04cc041a33603c2eb9b148e3b1412bdef9740ab400000000000000000000000000000000042120affcefe4735ae25e192d1cf34e40afdc6d2ebdacde2e23d30709fecfb71960bc9131e3702b27b6fcd5c7a98d170000000000000000000000000000000001998caf5163b0dccec7c8423c4c56a7d0f0b26d9034f707ed07f636f42dac590a2674c1667d70be385c4e626815c66400000000000000000000000000000000082961f3752eb7324800bc217514792b2111abe52df54973615737b8ec3a9f2db36dc1782d20782df8efae4bd7b8559600000000000000000000000000000000075729f6b9337b3f25da9d33cdbed7207a589a342cee61e8e99e030244b814accc93b26a0ca6d9ba08acf29511ef15be000000000000000000000000000000000c6b634d90c2664b9fa4ccbca35913d23696825350e21f0a6dd5e9abb17497a0a499e1b7b928a57ba8c730158f63b75d00000000000000000000000000000000102ba7f9db164318194ab17f615ca8cc741dab773e8609023c58a722f1e4f209eb4bc3cff7a2b71c08bdd421068b9ff700000000000000000000000000000000042120affcefe4735ae25e192d1cf34e40afdc6d2ebdacde2e23d30709fecfb71960bc9131e3702b27b6fcd5c7a98d170000000000000000000000000000000001998caf5163b0dccec7c8423c4c56a7d0f0b26d9034f707ed07f636f42dac590a2674c1667d70be385c4e626815c66400000000000000000000000000000000082961f3752eb7324800bc217514792b2111abe52df54973615737b8ec3a9f2db36dc1782d20782df8efae4bd7b8559600000000000000000000000000000000075729f6b9337b3f25da9d33cdbed7207a589a342cee61e8e99e030244b814accc93b26a0ca6d9ba08acf29511ef15be000000000000000000000000000000000c6b634d90c2664b9fa4ccbca35913d23696825350e21f0a6dd5e9abb17497a0a499e1b7b928a57ba8c730158f63b75d0000000000000000000000000000000009d569f05e69a38231d0f636e1ef040af059a00db4ff09bd2ad82b7e04cc041a33603c2eb9b148e3b1412bdef9740ab400000000000000000000000000000000042120affcefe4735ae25e192d1cf34e40afdc6d2ebdacde2e23d30709fecfb71960bc9131e3702b27b6fcd5c7a98d170000000000000000000000000000000001998caf5163b0dccec7c8423c4c56a7d0f0b26d9034f707ed07f636f42dac590a2674c1667d70be385c4e626815c6640000000000000000000000000000000011d7aff6c4512f68031aeb94ce3733ac43659f9fc58fc94c05d99ae80a7656f66b3e3e86843387d1c10f51b4284755150000000000000000000000000000000012a9e7f3804c6b5b25410a82758cd5b6ea1eb150c696b0d67d92cf9eb1f8e17752184d94a4ad2645b1520d6aee1094ed000000000000000000000000000000000c6b634d90c2664b9fa4ccbca35913d23696825350e21f0a6dd5e9abb17497a0a499e1b7b928a57ba8c730158f63b75d00000000000000000000000000000000102ba7f9db164318194ab17f615ca8cc741dab773e8609023c58a722f1e4f209eb4bc3cff7a2b71c08bdd421068b9ff700000000000000000000000000000000042120affcefe4735ae25e192d1cf34e40afdc6d2ebdacde2e23d30709fecfb71960bc9131e3702b27b6fcd5c7a98d170000000000000000000000000000000001998caf5163b0dccec7c8423c4c56a7d0f0b26d9034f707ed07f636f42dac590a2674c1667d70be385c4e626815c6640000000000000000000000000000000011d7aff6c4512f68031aeb94ce3733ac43659f9fc58fc94c05d99ae80a7656f66b3e3e86843387d1c10f51b4284755150000000000000000000000000000000012a9e7f3804c6b5b25410a82758cd5b6ea1eb150c696b0d67d92cf9eb1f8e17752184d94a4ad2645b1520d6aee1094ed000000000000000000000000000000000c6b634d90c2664b9fa4ccbca35913d23696825350e21f0a6dd5e9abb17497a0a499e1b7b928a57ba8c730158f63b75d0000000000000000000000000000000009d569f05e69a38231d0f636e1ef040af059a00db4ff09bd2ad82b7e04cc041a33603c2eb9b148e3b1412bdef9740ab400000000000000000000000000000000042120affcefe4735ae25e192d1cf34e40afdc6d2ebdacde2e23d30709fecfb71960bc9131e3702b27b6fcd5c7a98d170000000000000000000000000000000001998caf5163b0dccec7c8423c4c56a7d0f0b26d9034f707ed07f636f42dac590a2674c1667d70be385c4e626815c66400000000000000000000000000000000082961f3752eb7324800bc217514792b2111abe52df54973615737b8ec3a9f2db36dc1782d20782df8efae4bd7b8559600000000000000000000000000000000075729f6b9337b3f25da9d33cdbed7207a589a342cee61e8e99e030244b814accc93b26a0ca6d9ba08acf29511ef15be000000000000000000000000000000000c6b634d90c2664b9fa4ccbca35913d23696825350e21f0a6dd5e9abb17497a0a499e1b7b928a57ba8c730158f63b75d00000000000000000000000000000000102ba7f9db164318194ab17f615ca8cc741dab773e8609023c58a722f1e4f209eb4bc3cff7a2b71c08bdd421068b9ff700000000000000000000000000000000042120affcefe4735ae25e192d1cf34e40afdc6d2ebdacde2e23d30709fecfb71960bc9131e3702b27b6fcd5c7a98d170000000000000000000000000000000001998caf5163b0dccec7c8423c4c56a7d0f0b26d9034f707ed07f636f42dac590a2674c1667d70be385c4e626815c66400000000000000000000000000000000082961f3752eb7324800bc217514792b2111abe52df54973615737b8ec3a9f2db36dc1782d20782df8efae4bd7b8559600000000000000000000000000000000075729f6b9337b3f25da9d33cdbed7207a589a342cee61e8e99e030244b814accc93b26a0ca6d9ba08acf29511ef15be", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_89", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000018129b2f00be24717c906d215beaaa136758aa1730bd0bbe9c0de9b3cbb3c0ea47911817fa322b907cc6fc720cabde05000000000000000000000000000000000e8b0f968ccb230517ef8980be559f410a2c4035a1101e6796d4f7a5ee5c93a19c111d38930bd5bca69405fc35fea7c20000000000000000000000000000000001462f8080d9b51235a8aa652445f509e3e13e3073769e9a047e8b2bfa5b227f4354bef017d18bf06f7ec98c169abf1e000000000000000000000000000000000070fdbc18112b49bd83f4347922797f2bbd68bf2592ad59041c97948ba7a091bdb3622c804803ad605604ba364dbdca0000000000000000000000000000000018bc90cd83e1271bf0e39b0c80989f0ddcffc960ae466c64ad340cc32607dbdc73eac5b9145e1339fa02a0c3fafcc1df00000000000000000000000000000000124c4bf66a5e015f142e9e4b26421414a60e54ed76c6d4acc0f20b24a25ddf5ec7ef1f561fac9d470a94bcfb2f2698c50000000000000000000000000000000018129b2f00be24717c906d215beaaa136758aa1730bd0bbe9c0de9b3cbb3c0ea47911817fa322b907cc6fc720cabde05000000000000000000000000000000000b760253acb4c395332c1e3584f60d965a4b0b4f5274f457d05bdafb08546282829ae2c61e482a43136afa03ca0102e90000000000000000000000000000000001462f8080d9b51235a8aa652445f509e3e13e3073769e9a047e8b2bfa5b227f4354bef017d18bf06f7ec98c169abf1e000000000000000000000000000000000070fdbc18112b49bd83f4347922797f2bbd68bf2592ad59041c97948ba7a091bdb3622c804803ad605604ba364dbdca0000000000000000000000000000000018bc90cd83e1271bf0e39b0c80989f0ddcffc960ae466c64ad340cc32607dbdc73eac5b9145e1339fa02a0c3fafcc1df00000000000000000000000000000000124c4bf66a5e015f142e9e4b26421414a60e54ed76c6d4acc0f20b24a25ddf5ec7ef1f561fac9d470a94bcfb2f2698c50000000000000000000000000000000018129b2f00be24717c906d215beaaa136758aa1730bd0bbe9c0de9b3cbb3c0ea47911817fa322b907cc6fc720cabde05000000000000000000000000000000000e8b0f968ccb230517ef8980be559f410a2c4035a1101e6796d4f7a5ee5c93a19c111d38930bd5bca69405fc35fea7c20000000000000000000000000000000001462f8080d9b51235a8aa652445f509e3e13e3073769e9a047e8b2bfa5b227f4354bef017d18bf06f7ec98c169abf1e000000000000000000000000000000000070fdbc18112b49bd83f4347922797f2bbd68bf2592ad59041c97948ba7a091bdb3622c804803ad605604ba364dbdca000000000000000000000000000000000144811cb59ebf7e5a380ca9c2b30dc987778224453ea65ab9fcc5ddd0a91a47aac13a459cf5ecc5bffc5f3c0502e8cc0000000000000000000000000000000007b4c5f3cf21e53b36ed096b1d0998c2be68f6977cbe3e12a63ec77c545316c556bce0a891a762b8af6a4304d0d911e60000000000000000000000000000000018129b2f00be24717c906d215beaaa136758aa1730bd0bbe9c0de9b3cbb3c0ea47911817fa322b907cc6fc720cabde05000000000000000000000000000000000b760253acb4c395332c1e3584f60d965a4b0b4f5274f457d05bdafb08546282829ae2c61e482a43136afa03ca0102e90000000000000000000000000000000001462f8080d9b51235a8aa652445f509e3e13e3073769e9a047e8b2bfa5b227f4354bef017d18bf06f7ec98c169abf1e000000000000000000000000000000000070fdbc18112b49bd83f4347922797f2bbd68bf2592ad59041c97948ba7a091bdb3622c804803ad605604ba364dbdca000000000000000000000000000000000144811cb59ebf7e5a380ca9c2b30dc987778224453ea65ab9fcc5ddd0a91a47aac13a459cf5ecc5bffc5f3c0502e8cc0000000000000000000000000000000007b4c5f3cf21e53b36ed096b1d0998c2be68f6977cbe3e12a63ec77c545316c556bce0a891a762b8af6a4304d0d911e60000000000000000000000000000000018129b2f00be24717c906d215beaaa136758aa1730bd0bbe9c0de9b3cbb3c0ea47911817fa322b907cc6fc720cabde05000000000000000000000000000000000e8b0f968ccb230517ef8980be559f410a2c4035a1101e6796d4f7a5ee5c93a19c111d38930bd5bca69405fc35fea7c20000000000000000000000000000000001462f8080d9b51235a8aa652445f509e3e13e3073769e9a047e8b2bfa5b227f4354bef017d18bf06f7ec98c169abf1e000000000000000000000000000000000070fdbc18112b49bd83f4347922797f2bbd68bf2592ad59041c97948ba7a091bdb3622c804803ad605604ba364dbdca0000000000000000000000000000000018bc90cd83e1271bf0e39b0c80989f0ddcffc960ae466c64ad340cc32607dbdc73eac5b9145e1339fa02a0c3fafcc1df00000000000000000000000000000000124c4bf66a5e015f142e9e4b26421414a60e54ed76c6d4acc0f20b24a25ddf5ec7ef1f561fac9d470a94bcfb2f2698c50000000000000000000000000000000018129b2f00be24717c906d215beaaa136758aa1730bd0bbe9c0de9b3cbb3c0ea47911817fa322b907cc6fc720cabde05000000000000000000000000000000000b760253acb4c395332c1e3584f60d965a4b0b4f5274f457d05bdafb08546282829ae2c61e482a43136afa03ca0102e90000000000000000000000000000000001462f8080d9b51235a8aa652445f509e3e13e3073769e9a047e8b2bfa5b227f4354bef017d18bf06f7ec98c169abf1e000000000000000000000000000000000070fdbc18112b49bd83f4347922797f2bbd68bf2592ad59041c97948ba7a091bdb3622c804803ad605604ba364dbdca0000000000000000000000000000000018bc90cd83e1271bf0e39b0c80989f0ddcffc960ae466c64ad340cc32607dbdc73eac5b9145e1339fa02a0c3fafcc1df00000000000000000000000000000000124c4bf66a5e015f142e9e4b26421414a60e54ed76c6d4acc0f20b24a25ddf5ec7ef1f561fac9d470a94bcfb2f2698c50000000000000000000000000000000018129b2f00be24717c906d215beaaa136758aa1730bd0bbe9c0de9b3cbb3c0ea47911817fa322b907cc6fc720cabde05000000000000000000000000000000000e8b0f968ccb230517ef8980be559f410a2c4035a1101e6796d4f7a5ee5c93a19c111d38930bd5bca69405fc35fea7c20000000000000000000000000000000001462f8080d9b51235a8aa652445f509e3e13e3073769e9a047e8b2bfa5b227f4354bef017d18bf06f7ec98c169abf1e000000000000000000000000000000000070fdbc18112b49bd83f4347922797f2bbd68bf2592ad59041c97948ba7a091bdb3622c804803ad605604ba364dbdca000000000000000000000000000000000144811cb59ebf7e5a380ca9c2b30dc987778224453ea65ab9fcc5ddd0a91a47aac13a459cf5ecc5bffc5f3c0502e8cc0000000000000000000000000000000007b4c5f3cf21e53b36ed096b1d0998c2be68f6977cbe3e12a63ec77c545316c556bce0a891a762b8af6a4304d0d911e60000000000000000000000000000000018129b2f00be24717c906d215beaaa136758aa1730bd0bbe9c0de9b3cbb3c0ea47911817fa322b907cc6fc720cabde05000000000000000000000000000000000b760253acb4c395332c1e3584f60d965a4b0b4f5274f457d05bdafb08546282829ae2c61e482a43136afa03ca0102e90000000000000000000000000000000001462f8080d9b51235a8aa652445f509e3e13e3073769e9a047e8b2bfa5b227f4354bef017d18bf06f7ec98c169abf1e000000000000000000000000000000000070fdbc18112b49bd83f4347922797f2bbd68bf2592ad59041c97948ba7a091bdb3622c804803ad605604ba364dbdca000000000000000000000000000000000144811cb59ebf7e5a380ca9c2b30dc987778224453ea65ab9fcc5ddd0a91a47aac13a459cf5ecc5bffc5f3c0502e8cc0000000000000000000000000000000007b4c5f3cf21e53b36ed096b1d0998c2be68f6977cbe3e12a63ec77c545316c556bce0a891a762b8af6a4304d0d911e6", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_90", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a4700000000000000000000000000000000193118d1f237c68a8a0961fb220c0fd6a08853908a039dd57f8ed334063e5316bf83e8c3c3f44420734abbd7ddda31a600000000000000000000000000000000156901359e5b399168e90ccad27a054d147aa9c4a731294180e395e8e2d458f5537fdac591cdc82fd8bffa4c9fa126ed00000000000000000000000000000000143872757c0a25d85e95a86c5e09175fdbeaf59bae3d1e8a367902d59c662cc3a293ae252443b3201671ad1dbaed8ca20000000000000000000000000000000017f93d49ec5c34cdc31931cbe2d5b3ad7a6dcd3ea864862aa7b41d5b2f4618c9c92da01e246ff8f34240bcf1de4c1c450000000000000000000000000000000002180a95dbe57c43171e2607593dd3b54344bdbf409dcd0c5706a9a72ad0e26ed60b9e4cb17ea4e7b460adc5a6f6d2de000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a470000000000000000000000000000000000cff9184748200fc11245bb213f9d00c3eef7f4698174e9e7a1ff6cf072a30d5f28173aed5fbbdf46b444282225790500000000000000000000000000000000156901359e5b399168e90ccad27a054d147aa9c4a731294180e395e8e2d458f5537fdac591cdc82fd8bffa4c9fa126ed00000000000000000000000000000000143872757c0a25d85e95a86c5e09175fdbeaf59bae3d1e8a367902d59c662cc3a293ae252443b3201671ad1dbaed8ca20000000000000000000000000000000017f93d49ec5c34cdc31931cbe2d5b3ad7a6dcd3ea864862aa7b41d5b2f4618c9c92da01e246ff8f34240bcf1de4c1c450000000000000000000000000000000002180a95dbe57c43171e2607593dd3b54344bdbf409dcd0c5706a9a72ad0e26ed60b9e4cb17ea4e7b460adc5a6f6d2de000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a4700000000000000000000000000000000193118d1f237c68a8a0961fb220c0fd6a08853908a039dd57f8ed334063e5316bf83e8c3c3f44420734abbd7ddda31a600000000000000000000000000000000156901359e5b399168e90ccad27a054d147aa9c4a731294180e395e8e2d458f5537fdac591cdc82fd8bffa4c9fa126ed00000000000000000000000000000000143872757c0a25d85e95a86c5e09175fdbeaf59bae3d1e8a367902d59c662cc3a293ae252443b3201671ad1dbaed8ca2000000000000000000000000000000000207d4a04d23b1cc880275ea6075f929ea097e464b208c94bf7cb545c76add5a557e5fe08ce4070c77be430e21b38e660000000000000000000000000000000017e907545d9a6a5733fd81aeea0dd92221328dc5b2e745b3102a28f9cbe013b548a061b1ffd55b18059e523a5908d7cd000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a470000000000000000000000000000000000cff9184748200fc11245bb213f9d00c3eef7f4698174e9e7a1ff6cf072a30d5f28173aed5fbbdf46b444282225790500000000000000000000000000000000156901359e5b399168e90ccad27a054d147aa9c4a731294180e395e8e2d458f5537fdac591cdc82fd8bffa4c9fa126ed00000000000000000000000000000000143872757c0a25d85e95a86c5e09175fdbeaf59bae3d1e8a367902d59c662cc3a293ae252443b3201671ad1dbaed8ca2000000000000000000000000000000000207d4a04d23b1cc880275ea6075f929ea097e464b208c94bf7cb545c76add5a557e5fe08ce4070c77be430e21b38e660000000000000000000000000000000017e907545d9a6a5733fd81aeea0dd92221328dc5b2e745b3102a28f9cbe013b548a061b1ffd55b18059e523a5908d7cd000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a4700000000000000000000000000000000193118d1f237c68a8a0961fb220c0fd6a08853908a039dd57f8ed334063e5316bf83e8c3c3f44420734abbd7ddda31a600000000000000000000000000000000156901359e5b399168e90ccad27a054d147aa9c4a731294180e395e8e2d458f5537fdac591cdc82fd8bffa4c9fa126ed00000000000000000000000000000000143872757c0a25d85e95a86c5e09175fdbeaf59bae3d1e8a367902d59c662cc3a293ae252443b3201671ad1dbaed8ca20000000000000000000000000000000017f93d49ec5c34cdc31931cbe2d5b3ad7a6dcd3ea864862aa7b41d5b2f4618c9c92da01e246ff8f34240bcf1de4c1c450000000000000000000000000000000002180a95dbe57c43171e2607593dd3b54344bdbf409dcd0c5706a9a72ad0e26ed60b9e4cb17ea4e7b460adc5a6f6d2de000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a470000000000000000000000000000000000cff9184748200fc11245bb213f9d00c3eef7f4698174e9e7a1ff6cf072a30d5f28173aed5fbbdf46b444282225790500000000000000000000000000000000156901359e5b399168e90ccad27a054d147aa9c4a731294180e395e8e2d458f5537fdac591cdc82fd8bffa4c9fa126ed00000000000000000000000000000000143872757c0a25d85e95a86c5e09175fdbeaf59bae3d1e8a367902d59c662cc3a293ae252443b3201671ad1dbaed8ca20000000000000000000000000000000017f93d49ec5c34cdc31931cbe2d5b3ad7a6dcd3ea864862aa7b41d5b2f4618c9c92da01e246ff8f34240bcf1de4c1c450000000000000000000000000000000002180a95dbe57c43171e2607593dd3b54344bdbf409dcd0c5706a9a72ad0e26ed60b9e4cb17ea4e7b460adc5a6f6d2de000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a4700000000000000000000000000000000193118d1f237c68a8a0961fb220c0fd6a08853908a039dd57f8ed334063e5316bf83e8c3c3f44420734abbd7ddda31a600000000000000000000000000000000156901359e5b399168e90ccad27a054d147aa9c4a731294180e395e8e2d458f5537fdac591cdc82fd8bffa4c9fa126ed00000000000000000000000000000000143872757c0a25d85e95a86c5e09175fdbeaf59bae3d1e8a367902d59c662cc3a293ae252443b3201671ad1dbaed8ca2000000000000000000000000000000000207d4a04d23b1cc880275ea6075f929ea097e464b208c94bf7cb545c76add5a557e5fe08ce4070c77be430e21b38e660000000000000000000000000000000017e907545d9a6a5733fd81aeea0dd92221328dc5b2e745b3102a28f9cbe013b548a061b1ffd55b18059e523a5908d7cd000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a470000000000000000000000000000000000cff9184748200fc11245bb213f9d00c3eef7f4698174e9e7a1ff6cf072a30d5f28173aed5fbbdf46b444282225790500000000000000000000000000000000156901359e5b399168e90ccad27a054d147aa9c4a731294180e395e8e2d458f5537fdac591cdc82fd8bffa4c9fa126ed00000000000000000000000000000000143872757c0a25d85e95a86c5e09175fdbeaf59bae3d1e8a367902d59c662cc3a293ae252443b3201671ad1dbaed8ca2000000000000000000000000000000000207d4a04d23b1cc880275ea6075f929ea097e464b208c94bf7cb545c76add5a557e5fe08ce4070c77be430e21b38e660000000000000000000000000000000017e907545d9a6a5733fd81aeea0dd92221328dc5b2e745b3102a28f9cbe013b548a061b1ffd55b18059e523a5908d7cd", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_91", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000000217a4c563d730ef545e452038813301933ccc6638321ee5e217dad0be2e3ddc855a14054d0d72b6bcc692a5fb1ac7300000000000000000000000000000000007025f1c4a5f85a9c1587d4d4a2e620d83d60568343940ffd85e6b1e4fb0f0f53bb08c4f48bf6f45a7dbc3722ecc951e00000000000000000000000000000000162ea8f985c83d59361ee6beb49cf2a797d8c909e2eccfc61fdc5359d5ac9b10fbaeef2eebea1667b5b9bf8f5d603d6e0000000000000000000000000000000018344ca9d4913e817264ed8119fe4d136f2041b0a99d4b5fe7f2b7f268256eec9fceb27fa61c4225f47babd17759c01300000000000000000000000000000000034f7418d96bdbe4f1ed5996fc9e9e99233a5cb3aad717b3717e91ff94fecaa67250ba5b27dcf59c6e36aae08d22983a00000000000000000000000000000000100cd7ea3c342aa2c15e9c6121a1cfecf611235add08290cf9cb8ea54e8ff523e17a0b5dc41e6d07992e5927e3ff6157000000000000000000000000000000000217a4c563d730ef545e452038813301933ccc6638321ee5e217dad0be2e3ddc855a14054d0d72b6bcc692a5fb1ac7300000000000000000000000000000000012feb2cdef2060f089c32a68f91d4ac9e0a1461cbf4bd1bf8ed26782a700052ee2fb73af689490ba12233c8dd133158d00000000000000000000000000000000162ea8f985c83d59361ee6beb49cf2a797d8c909e2eccfc61fdc5359d5ac9b10fbaeef2eebea1667b5b9bf8f5d603d6e0000000000000000000000000000000018344ca9d4913e817264ed8119fe4d136f2041b0a99d4b5fe7f2b7f268256eec9fceb27fa61c4225f47babd17759c01300000000000000000000000000000000034f7418d96bdbe4f1ed5996fc9e9e99233a5cb3aad717b3717e91ff94fecaa67250ba5b27dcf59c6e36aae08d22983a00000000000000000000000000000000100cd7ea3c342aa2c15e9c6121a1cfecf611235add08290cf9cb8ea54e8ff523e17a0b5dc41e6d07992e5927e3ff6157000000000000000000000000000000000217a4c563d730ef545e452038813301933ccc6638321ee5e217dad0be2e3ddc855a14054d0d72b6bcc692a5fb1ac7300000000000000000000000000000000007025f1c4a5f85a9c1587d4d4a2e620d83d60568343940ffd85e6b1e4fb0f0f53bb08c4f48bf6f45a7dbc3722ecc951e00000000000000000000000000000000162ea8f985c83d59361ee6beb49cf2a797d8c909e2eccfc61fdc5359d5ac9b10fbaeef2eebea1667b5b9bf8f5d603d6e0000000000000000000000000000000018344ca9d4913e817264ed8119fe4d136f2041b0a99d4b5fe7f2b7f268256eec9fceb27fa61c4225f47babd17759c0130000000000000000000000000000000016b19dd160140ab5592e4e1f46ad0e3e413ceed148adfb0bf5b240a161b22b7dac5b45a389770a634bc8551f72dd12710000000000000000000000000000000009f439fffd4bbbf789bd0b5521a9dcea6e66282a167ce9b26d6543fba82101003d31f4a0ed3592f820d0a6d81c004954000000000000000000000000000000000217a4c563d730ef545e452038813301933ccc6638321ee5e217dad0be2e3ddc855a14054d0d72b6bcc692a5fb1ac7300000000000000000000000000000000012feb2cdef2060f089c32a68f91d4ac9e0a1461cbf4bd1bf8ed26782a700052ee2fb73af689490ba12233c8dd133158d00000000000000000000000000000000162ea8f985c83d59361ee6beb49cf2a797d8c909e2eccfc61fdc5359d5ac9b10fbaeef2eebea1667b5b9bf8f5d603d6e0000000000000000000000000000000018344ca9d4913e817264ed8119fe4d136f2041b0a99d4b5fe7f2b7f268256eec9fceb27fa61c4225f47babd17759c0130000000000000000000000000000000016b19dd160140ab5592e4e1f46ad0e3e413ceed148adfb0bf5b240a161b22b7dac5b45a389770a634bc8551f72dd12710000000000000000000000000000000009f439fffd4bbbf789bd0b5521a9dcea6e66282a167ce9b26d6543fba82101003d31f4a0ed3592f820d0a6d81c004954000000000000000000000000000000000217a4c563d730ef545e452038813301933ccc6638321ee5e217dad0be2e3ddc855a14054d0d72b6bcc692a5fb1ac7300000000000000000000000000000000007025f1c4a5f85a9c1587d4d4a2e620d83d60568343940ffd85e6b1e4fb0f0f53bb08c4f48bf6f45a7dbc3722ecc951e00000000000000000000000000000000162ea8f985c83d59361ee6beb49cf2a797d8c909e2eccfc61fdc5359d5ac9b10fbaeef2eebea1667b5b9bf8f5d603d6e0000000000000000000000000000000018344ca9d4913e817264ed8119fe4d136f2041b0a99d4b5fe7f2b7f268256eec9fceb27fa61c4225f47babd17759c01300000000000000000000000000000000034f7418d96bdbe4f1ed5996fc9e9e99233a5cb3aad717b3717e91ff94fecaa67250ba5b27dcf59c6e36aae08d22983a00000000000000000000000000000000100cd7ea3c342aa2c15e9c6121a1cfecf611235add08290cf9cb8ea54e8ff523e17a0b5dc41e6d07992e5927e3ff6157000000000000000000000000000000000217a4c563d730ef545e452038813301933ccc6638321ee5e217dad0be2e3ddc855a14054d0d72b6bcc692a5fb1ac7300000000000000000000000000000000012feb2cdef2060f089c32a68f91d4ac9e0a1461cbf4bd1bf8ed26782a700052ee2fb73af689490ba12233c8dd133158d00000000000000000000000000000000162ea8f985c83d59361ee6beb49cf2a797d8c909e2eccfc61fdc5359d5ac9b10fbaeef2eebea1667b5b9bf8f5d603d6e0000000000000000000000000000000018344ca9d4913e817264ed8119fe4d136f2041b0a99d4b5fe7f2b7f268256eec9fceb27fa61c4225f47babd17759c01300000000000000000000000000000000034f7418d96bdbe4f1ed5996fc9e9e99233a5cb3aad717b3717e91ff94fecaa67250ba5b27dcf59c6e36aae08d22983a00000000000000000000000000000000100cd7ea3c342aa2c15e9c6121a1cfecf611235add08290cf9cb8ea54e8ff523e17a0b5dc41e6d07992e5927e3ff6157000000000000000000000000000000000217a4c563d730ef545e452038813301933ccc6638321ee5e217dad0be2e3ddc855a14054d0d72b6bcc692a5fb1ac7300000000000000000000000000000000007025f1c4a5f85a9c1587d4d4a2e620d83d60568343940ffd85e6b1e4fb0f0f53bb08c4f48bf6f45a7dbc3722ecc951e00000000000000000000000000000000162ea8f985c83d59361ee6beb49cf2a797d8c909e2eccfc61fdc5359d5ac9b10fbaeef2eebea1667b5b9bf8f5d603d6e0000000000000000000000000000000018344ca9d4913e817264ed8119fe4d136f2041b0a99d4b5fe7f2b7f268256eec9fceb27fa61c4225f47babd17759c0130000000000000000000000000000000016b19dd160140ab5592e4e1f46ad0e3e413ceed148adfb0bf5b240a161b22b7dac5b45a389770a634bc8551f72dd12710000000000000000000000000000000009f439fffd4bbbf789bd0b5521a9dcea6e66282a167ce9b26d6543fba82101003d31f4a0ed3592f820d0a6d81c004954000000000000000000000000000000000217a4c563d730ef545e452038813301933ccc6638321ee5e217dad0be2e3ddc855a14054d0d72b6bcc692a5fb1ac7300000000000000000000000000000000012feb2cdef2060f089c32a68f91d4ac9e0a1461cbf4bd1bf8ed26782a700052ee2fb73af689490ba12233c8dd133158d00000000000000000000000000000000162ea8f985c83d59361ee6beb49cf2a797d8c909e2eccfc61fdc5359d5ac9b10fbaeef2eebea1667b5b9bf8f5d603d6e0000000000000000000000000000000018344ca9d4913e817264ed8119fe4d136f2041b0a99d4b5fe7f2b7f268256eec9fceb27fa61c4225f47babd17759c0130000000000000000000000000000000016b19dd160140ab5592e4e1f46ad0e3e413ceed148adfb0bf5b240a161b22b7dac5b45a389770a634bc8551f72dd12710000000000000000000000000000000009f439fffd4bbbf789bd0b5521a9dcea6e66282a167ce9b26d6543fba82101003d31f4a0ed3592f820d0a6d81c004954", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_92", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000009ec00ea2da59d937d3154d86dbed2957667253401bce9de80e0ffe6df32f36b06404b9e3af08e912a0b4ef091f93efb000000000000000000000000000000000dd8d1bd66f4accbc9d0c7dabef7af72f51c67a0d61384647533ad92bba44a312f0be0fa52163176f1aff4e64c00aefb0000000000000000000000000000000001cdfae9234096578b9413f926ef8c6831f2c0f700e25d7553a746aef44238e493f8032e09f67f2fed9676c9611f60e70000000000000000000000000000000019c8bae08d3926997146f7827f00cde863684dd4050ea5da64f6798e7a930d3c1f34046bea0f44232594f5469db566280000000000000000000000000000000013574b997ee8988aa81db0e2ddb98be2e7005603076fac5cb246f65c869aa7bb3f148c8dde970e34e5e5efce023e633c000000000000000000000000000000000998bc9d41c5d527360fc4e68ba067d3778cf5cf00e5959b5ec52c1595aabe6e2e92d40cb34faa84513d150568c8cfc00000000000000000000000000000000009ec00ea2da59d937d3154d86dbed2957667253401bce9de80e0ffe6df32f36b06404b9e3af08e912a0b4ef091f93efb000000000000000000000000000000000c28402cd28b39ce814adfdb8453fd646f5ae3e41d718e5af1fd250e3b0cabf2efa01f045f3dce88c84f0b19b3fefbb00000000000000000000000000000000001cdfae9234096578b9413f926ef8c6831f2c0f700e25d7553a746aef44238e493f8032e09f67f2fed9676c9611f60e70000000000000000000000000000000019c8bae08d3926997146f7827f00cde863684dd4050ea5da64f6798e7a930d3c1f34046bea0f44232594f5469db566280000000000000000000000000000000013574b997ee8988aa81db0e2ddb98be2e7005603076fac5cb246f65c869aa7bb3f148c8dde970e34e5e5efce023e633c000000000000000000000000000000000998bc9d41c5d527360fc4e68ba067d3778cf5cf00e5959b5ec52c1595aabe6e2e92d40cb34faa84513d150568c8cfc00000000000000000000000000000000009ec00ea2da59d937d3154d86dbed2957667253401bce9de80e0ffe6df32f36b06404b9e3af08e912a0b4ef091f93efb000000000000000000000000000000000dd8d1bd66f4accbc9d0c7dabef7af72f51c67a0d61384647533ad92bba44a312f0be0fa52163176f1aff4e64c00aefb0000000000000000000000000000000001cdfae9234096578b9413f926ef8c6831f2c0f700e25d7553a746aef44238e493f8032e09f67f2fed9676c9611f60e70000000000000000000000000000000019c8bae08d3926997146f7827f00cde863684dd4050ea5da64f6798e7a930d3c1f34046bea0f44232594f5469db566280000000000000000000000000000000006a9c650ba974e0fa2fdf6d3659220f47d76f581ec156662b4e9dc4470164e68df977370d2bcf1cad4191031fdc1476f000000000000000000000000000000001068554cf7ba1173150be2cfb7ab4503ecea55b5f29f7d24086ba68b610637b5f0192bf1fe04557b68c1eafa9736daeb0000000000000000000000000000000009ec00ea2da59d937d3154d86dbed2957667253401bce9de80e0ffe6df32f36b06404b9e3af08e912a0b4ef091f93efb000000000000000000000000000000000c28402cd28b39ce814adfdb8453fd646f5ae3e41d718e5af1fd250e3b0cabf2efa01f045f3dce88c84f0b19b3fefbb00000000000000000000000000000000001cdfae9234096578b9413f926ef8c6831f2c0f700e25d7553a746aef44238e493f8032e09f67f2fed9676c9611f60e70000000000000000000000000000000019c8bae08d3926997146f7827f00cde863684dd4050ea5da64f6798e7a930d3c1f34046bea0f44232594f5469db566280000000000000000000000000000000006a9c650ba974e0fa2fdf6d3659220f47d76f581ec156662b4e9dc4470164e68df977370d2bcf1cad4191031fdc1476f000000000000000000000000000000001068554cf7ba1173150be2cfb7ab4503ecea55b5f29f7d24086ba68b610637b5f0192bf1fe04557b68c1eafa9736daeb0000000000000000000000000000000009ec00ea2da59d937d3154d86dbed2957667253401bce9de80e0ffe6df32f36b06404b9e3af08e912a0b4ef091f93efb000000000000000000000000000000000dd8d1bd66f4accbc9d0c7dabef7af72f51c67a0d61384647533ad92bba44a312f0be0fa52163176f1aff4e64c00aefb0000000000000000000000000000000001cdfae9234096578b9413f926ef8c6831f2c0f700e25d7553a746aef44238e493f8032e09f67f2fed9676c9611f60e70000000000000000000000000000000019c8bae08d3926997146f7827f00cde863684dd4050ea5da64f6798e7a930d3c1f34046bea0f44232594f5469db566280000000000000000000000000000000013574b997ee8988aa81db0e2ddb98be2e7005603076fac5cb246f65c869aa7bb3f148c8dde970e34e5e5efce023e633c000000000000000000000000000000000998bc9d41c5d527360fc4e68ba067d3778cf5cf00e5959b5ec52c1595aabe6e2e92d40cb34faa84513d150568c8cfc00000000000000000000000000000000009ec00ea2da59d937d3154d86dbed2957667253401bce9de80e0ffe6df32f36b06404b9e3af08e912a0b4ef091f93efb000000000000000000000000000000000c28402cd28b39ce814adfdb8453fd646f5ae3e41d718e5af1fd250e3b0cabf2efa01f045f3dce88c84f0b19b3fefbb00000000000000000000000000000000001cdfae9234096578b9413f926ef8c6831f2c0f700e25d7553a746aef44238e493f8032e09f67f2fed9676c9611f60e70000000000000000000000000000000019c8bae08d3926997146f7827f00cde863684dd4050ea5da64f6798e7a930d3c1f34046bea0f44232594f5469db566280000000000000000000000000000000013574b997ee8988aa81db0e2ddb98be2e7005603076fac5cb246f65c869aa7bb3f148c8dde970e34e5e5efce023e633c000000000000000000000000000000000998bc9d41c5d527360fc4e68ba067d3778cf5cf00e5959b5ec52c1595aabe6e2e92d40cb34faa84513d150568c8cfc00000000000000000000000000000000009ec00ea2da59d937d3154d86dbed2957667253401bce9de80e0ffe6df32f36b06404b9e3af08e912a0b4ef091f93efb000000000000000000000000000000000dd8d1bd66f4accbc9d0c7dabef7af72f51c67a0d61384647533ad92bba44a312f0be0fa52163176f1aff4e64c00aefb0000000000000000000000000000000001cdfae9234096578b9413f926ef8c6831f2c0f700e25d7553a746aef44238e493f8032e09f67f2fed9676c9611f60e70000000000000000000000000000000019c8bae08d3926997146f7827f00cde863684dd4050ea5da64f6798e7a930d3c1f34046bea0f44232594f5469db566280000000000000000000000000000000006a9c650ba974e0fa2fdf6d3659220f47d76f581ec156662b4e9dc4470164e68df977370d2bcf1cad4191031fdc1476f000000000000000000000000000000001068554cf7ba1173150be2cfb7ab4503ecea55b5f29f7d24086ba68b610637b5f0192bf1fe04557b68c1eafa9736daeb0000000000000000000000000000000009ec00ea2da59d937d3154d86dbed2957667253401bce9de80e0ffe6df32f36b06404b9e3af08e912a0b4ef091f93efb000000000000000000000000000000000c28402cd28b39ce814adfdb8453fd646f5ae3e41d718e5af1fd250e3b0cabf2efa01f045f3dce88c84f0b19b3fefbb00000000000000000000000000000000001cdfae9234096578b9413f926ef8c6831f2c0f700e25d7553a746aef44238e493f8032e09f67f2fed9676c9611f60e70000000000000000000000000000000019c8bae08d3926997146f7827f00cde863684dd4050ea5da64f6798e7a930d3c1f34046bea0f44232594f5469db566280000000000000000000000000000000006a9c650ba974e0fa2fdf6d3659220f47d76f581ec156662b4e9dc4470164e68df977370d2bcf1cad4191031fdc1476f000000000000000000000000000000001068554cf7ba1173150be2cfb7ab4503ecea55b5f29f7d24086ba68b610637b5f0192bf1fe04557b68c1eafa9736daeb", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_93", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "0000000000000000000000000000000014153e01c9e495c5c01c82b3cad9eaf20cf78369ccbabf57fb160ded309cbd1caea3d3df38a7ea5490c67f168e9acec0000000000000000000000000000000001648030be79658c134e016a211d311841988065957b35e9bc1580fb6e05e291e747b7a960a50e26a2a3c0cd1634c3585000000000000000000000000000000000c78d84157dc0b102c3843e4c8e88f244cc1b2a27043e07b2fab694a58f93d47e4cf9ca1158a8e30e3d43f94a20d33b50000000000000000000000000000000004842fe0df312f735a9d8af0c2ff7c561ed9cf4add5e3e9402bcff1190f3f36ca91de8edc9472b3ebd27ee2d9afdf8770000000000000000000000000000000008c7a67b89960da4309888bc6ce31e7efe74867165a8aceda7c7290f8a92687100ccbcd39d4d5a67f21f4b63ecc638320000000000000000000000000000000001cd7978ce28629ed1a9c5433c555b1ebb584f80909599282467e7b2471f591bea1d73e7b0a247aed7de4f1fecc012040000000000000000000000000000000014153e01c9e495c5c01c82b3cad9eaf20cf78369ccbabf57fb160ded309cbd1caea3d3df38a7ea5490c67f168e9acec00000000000000000000000000000000003b90ede51e98dd9163b911431789b534aef452b9bd1b423a5d8c2ea1652cd05aa308568a7031d958fc2f32e9cb37526000000000000000000000000000000000c78d84157dc0b102c3843e4c8e88f244cc1b2a27043e07b2fab694a58f93d47e4cf9ca1158a8e30e3d43f94a20d33b50000000000000000000000000000000004842fe0df312f735a9d8af0c2ff7c561ed9cf4add5e3e9402bcff1190f3f36ca91de8edc9472b3ebd27ee2d9afdf8770000000000000000000000000000000008c7a67b89960da4309888bc6ce31e7efe74867165a8aceda7c7290f8a92687100ccbcd39d4d5a67f21f4b63ecc638320000000000000000000000000000000001cd7978ce28629ed1a9c5433c555b1ebb584f80909599282467e7b2471f591bea1d73e7b0a247aed7de4f1fecc012040000000000000000000000000000000014153e01c9e495c5c01c82b3cad9eaf20cf78369ccbabf57fb160ded309cbd1caea3d3df38a7ea5490c67f168e9acec0000000000000000000000000000000001648030be79658c134e016a211d311841988065957b35e9bc1580fb6e05e291e747b7a960a50e26a2a3c0cd1634c3585000000000000000000000000000000000c78d84157dc0b102c3843e4c8e88f244cc1b2a27043e07b2fab694a58f93d47e4cf9ca1158a8e30e3d43f94a20d33b50000000000000000000000000000000004842fe0df312f735a9d8af0c2ff7c561ed9cf4add5e3e9402bcff1190f3f36ca91de8edc9472b3ebd27ee2d9afdf8770000000000000000000000000000000011396b6eafe9d8f61a831ef9d6688e586602c5138ddc65d1bf69a9916c1e8db31ddf432b1406a597c7dfb49c1339727900000000000000000000000000000000183398716b5783fb7971e27306f651b8a91efc0462ef799742c8eaeeaf919d08348e8c1700b1b850e220b0e0133f98a70000000000000000000000000000000014153e01c9e495c5c01c82b3cad9eaf20cf78369ccbabf57fb160ded309cbd1caea3d3df38a7ea5490c67f168e9acec00000000000000000000000000000000003b90ede51e98dd9163b911431789b534aef452b9bd1b423a5d8c2ea1652cd05aa308568a7031d958fc2f32e9cb37526000000000000000000000000000000000c78d84157dc0b102c3843e4c8e88f244cc1b2a27043e07b2fab694a58f93d47e4cf9ca1158a8e30e3d43f94a20d33b50000000000000000000000000000000004842fe0df312f735a9d8af0c2ff7c561ed9cf4add5e3e9402bcff1190f3f36ca91de8edc9472b3ebd27ee2d9afdf8770000000000000000000000000000000011396b6eafe9d8f61a831ef9d6688e586602c5138ddc65d1bf69a9916c1e8db31ddf432b1406a597c7dfb49c1339727900000000000000000000000000000000183398716b5783fb7971e27306f651b8a91efc0462ef799742c8eaeeaf919d08348e8c1700b1b850e220b0e0133f98a70000000000000000000000000000000014153e01c9e495c5c01c82b3cad9eaf20cf78369ccbabf57fb160ded309cbd1caea3d3df38a7ea5490c67f168e9acec0000000000000000000000000000000001648030be79658c134e016a211d311841988065957b35e9bc1580fb6e05e291e747b7a960a50e26a2a3c0cd1634c3585000000000000000000000000000000000c78d84157dc0b102c3843e4c8e88f244cc1b2a27043e07b2fab694a58f93d47e4cf9ca1158a8e30e3d43f94a20d33b50000000000000000000000000000000004842fe0df312f735a9d8af0c2ff7c561ed9cf4add5e3e9402bcff1190f3f36ca91de8edc9472b3ebd27ee2d9afdf8770000000000000000000000000000000008c7a67b89960da4309888bc6ce31e7efe74867165a8aceda7c7290f8a92687100ccbcd39d4d5a67f21f4b63ecc638320000000000000000000000000000000001cd7978ce28629ed1a9c5433c555b1ebb584f80909599282467e7b2471f591bea1d73e7b0a247aed7de4f1fecc012040000000000000000000000000000000014153e01c9e495c5c01c82b3cad9eaf20cf78369ccbabf57fb160ded309cbd1caea3d3df38a7ea5490c67f168e9acec00000000000000000000000000000000003b90ede51e98dd9163b911431789b534aef452b9bd1b423a5d8c2ea1652cd05aa308568a7031d958fc2f32e9cb37526000000000000000000000000000000000c78d84157dc0b102c3843e4c8e88f244cc1b2a27043e07b2fab694a58f93d47e4cf9ca1158a8e30e3d43f94a20d33b50000000000000000000000000000000004842fe0df312f735a9d8af0c2ff7c561ed9cf4add5e3e9402bcff1190f3f36ca91de8edc9472b3ebd27ee2d9afdf8770000000000000000000000000000000008c7a67b89960da4309888bc6ce31e7efe74867165a8aceda7c7290f8a92687100ccbcd39d4d5a67f21f4b63ecc638320000000000000000000000000000000001cd7978ce28629ed1a9c5433c555b1ebb584f80909599282467e7b2471f591bea1d73e7b0a247aed7de4f1fecc012040000000000000000000000000000000014153e01c9e495c5c01c82b3cad9eaf20cf78369ccbabf57fb160ded309cbd1caea3d3df38a7ea5490c67f168e9acec0000000000000000000000000000000001648030be79658c134e016a211d311841988065957b35e9bc1580fb6e05e291e747b7a960a50e26a2a3c0cd1634c3585000000000000000000000000000000000c78d84157dc0b102c3843e4c8e88f244cc1b2a27043e07b2fab694a58f93d47e4cf9ca1158a8e30e3d43f94a20d33b50000000000000000000000000000000004842fe0df312f735a9d8af0c2ff7c561ed9cf4add5e3e9402bcff1190f3f36ca91de8edc9472b3ebd27ee2d9afdf8770000000000000000000000000000000011396b6eafe9d8f61a831ef9d6688e586602c5138ddc65d1bf69a9916c1e8db31ddf432b1406a597c7dfb49c1339727900000000000000000000000000000000183398716b5783fb7971e27306f651b8a91efc0462ef799742c8eaeeaf919d08348e8c1700b1b850e220b0e0133f98a70000000000000000000000000000000014153e01c9e495c5c01c82b3cad9eaf20cf78369ccbabf57fb160ded309cbd1caea3d3df38a7ea5490c67f168e9acec00000000000000000000000000000000003b90ede51e98dd9163b911431789b534aef452b9bd1b423a5d8c2ea1652cd05aa308568a7031d958fc2f32e9cb37526000000000000000000000000000000000c78d84157dc0b102c3843e4c8e88f244cc1b2a27043e07b2fab694a58f93d47e4cf9ca1158a8e30e3d43f94a20d33b50000000000000000000000000000000004842fe0df312f735a9d8af0c2ff7c561ed9cf4add5e3e9402bcff1190f3f36ca91de8edc9472b3ebd27ee2d9afdf8770000000000000000000000000000000011396b6eafe9d8f61a831ef9d6688e586602c5138ddc65d1bf69a9916c1e8db31ddf432b1406a597c7dfb49c1339727900000000000000000000000000000000183398716b5783fb7971e27306f651b8a91efc0462ef799742c8eaeeaf919d08348e8c1700b1b850e220b0e0133f98a7", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_94", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false }, { "Input": "000000000000000000000000000000001555535228eb9a24f460df9894d59aa06fc848a8bf8d6c3b51653b1d85734b3c5a2bece161309bd478d356fa198d579500000000000000000000000000000000144401f7eb69f6321eae8dad39dbe2cf4ae58e455474701dd9f1b62c85c7536813e84eb4f9def511eb62e5194288728b000000000000000000000000000000000e619d79792ac685030311a31a21203e5172d2e5d20ecf69a1e64158e7fe903b3695fd15432d3ca35562b5a8bd9cbdc20000000000000000000000000000000012394a621a503d1d92df3306649a6c6979816cabeb8f8d27450ec883c4e75f6f7411f3bfd068dc8dee58cdb8ebbd91bd0000000000000000000000000000000001652a688dbfd63a1c89452335bdaf248c97c9c6e5a3ad5a126577a6b9ab57075b22987ea8697b459611a5ab164f328400000000000000000000000000000000058a37347c5637808632ae6e8f264e8bde14ebb0ae69828f962f51b728321fea57c5a97ab694f7db175efe7a17d36cb6000000000000000000000000000000001555535228eb9a24f460df9894d59aa06fc848a8bf8d6c3b51653b1d85734b3c5a2bece161309bd478d356fa198d57950000000000000000000000000000000005bd0ff24e15f0682c6d1a09096fca081991bd3f9f10a2a18d3f1c7470e9a2bc0ac3b149b7750aedce9c1ae6bd773820000000000000000000000000000000000e619d79792ac685030311a31a21203e5172d2e5d20ecf69a1e64158e7fe903b3695fd15432d3ca35562b5a8bd9cbdc20000000000000000000000000000000012394a621a503d1d92df3306649a6c6979816cabeb8f8d27450ec883c4e75f6f7411f3bfd068dc8dee58cdb8ebbd91bd0000000000000000000000000000000001652a688dbfd63a1c89452335bdaf248c97c9c6e5a3ad5a126577a6b9ab57075b22987ea8697b459611a5ab164f328400000000000000000000000000000000058a37347c5637808632ae6e8f264e8bde14ebb0ae69828f962f51b728321fea57c5a97ab694f7db175efe7a17d36cb6000000000000000000000000000000001555535228eb9a24f460df9894d59aa06fc848a8bf8d6c3b51653b1d85734b3c5a2bece161309bd478d356fa198d579500000000000000000000000000000000144401f7eb69f6321eae8dad39dbe2cf4ae58e455474701dd9f1b62c85c7536813e84eb4f9def511eb62e5194288728b000000000000000000000000000000000e619d79792ac685030311a31a21203e5172d2e5d20ecf69a1e64158e7fe903b3695fd15432d3ca35562b5a8bd9cbdc20000000000000000000000000000000012394a621a503d1d92df3306649a6c6979816cabeb8f8d27450ec883c4e75f6f7411f3bfd068dc8dee58cdb8ebbd91bd00000000000000000000000000000000189be781abc010602e9262930d8dfdb2d7df81be0de1656554cb5afa3d059f1cc389678008ea84ba23ed5a54e9b07827000000000000000000000000000000001476dab5bd29af19c4e8f947b4255e4b86625fd4451b902fd10180e9ce7ed639c6e65683fabf0824a2a00185e82c3df5000000000000000000000000000000001555535228eb9a24f460df9894d59aa06fc848a8bf8d6c3b51653b1d85734b3c5a2bece161309bd478d356fa198d57950000000000000000000000000000000005bd0ff24e15f0682c6d1a09096fca081991bd3f9f10a2a18d3f1c7470e9a2bc0ac3b149b7750aedce9c1ae6bd773820000000000000000000000000000000000e619d79792ac685030311a31a21203e5172d2e5d20ecf69a1e64158e7fe903b3695fd15432d3ca35562b5a8bd9cbdc20000000000000000000000000000000012394a621a503d1d92df3306649a6c6979816cabeb8f8d27450ec883c4e75f6f7411f3bfd068dc8dee58cdb8ebbd91bd00000000000000000000000000000000189be781abc010602e9262930d8dfdb2d7df81be0de1656554cb5afa3d059f1cc389678008ea84ba23ed5a54e9b07827000000000000000000000000000000001476dab5bd29af19c4e8f947b4255e4b86625fd4451b902fd10180e9ce7ed639c6e65683fabf0824a2a00185e82c3df5000000000000000000000000000000001555535228eb9a24f460df9894d59aa06fc848a8bf8d6c3b51653b1d85734b3c5a2bece161309bd478d356fa198d579500000000000000000000000000000000144401f7eb69f6321eae8dad39dbe2cf4ae58e455474701dd9f1b62c85c7536813e84eb4f9def511eb62e5194288728b000000000000000000000000000000000e619d79792ac685030311a31a21203e5172d2e5d20ecf69a1e64158e7fe903b3695fd15432d3ca35562b5a8bd9cbdc20000000000000000000000000000000012394a621a503d1d92df3306649a6c6979816cabeb8f8d27450ec883c4e75f6f7411f3bfd068dc8dee58cdb8ebbd91bd0000000000000000000000000000000001652a688dbfd63a1c89452335bdaf248c97c9c6e5a3ad5a126577a6b9ab57075b22987ea8697b459611a5ab164f328400000000000000000000000000000000058a37347c5637808632ae6e8f264e8bde14ebb0ae69828f962f51b728321fea57c5a97ab694f7db175efe7a17d36cb6000000000000000000000000000000001555535228eb9a24f460df9894d59aa06fc848a8bf8d6c3b51653b1d85734b3c5a2bece161309bd478d356fa198d57950000000000000000000000000000000005bd0ff24e15f0682c6d1a09096fca081991bd3f9f10a2a18d3f1c7470e9a2bc0ac3b149b7750aedce9c1ae6bd773820000000000000000000000000000000000e619d79792ac685030311a31a21203e5172d2e5d20ecf69a1e64158e7fe903b3695fd15432d3ca35562b5a8bd9cbdc20000000000000000000000000000000012394a621a503d1d92df3306649a6c6979816cabeb8f8d27450ec883c4e75f6f7411f3bfd068dc8dee58cdb8ebbd91bd0000000000000000000000000000000001652a688dbfd63a1c89452335bdaf248c97c9c6e5a3ad5a126577a6b9ab57075b22987ea8697b459611a5ab164f328400000000000000000000000000000000058a37347c5637808632ae6e8f264e8bde14ebb0ae69828f962f51b728321fea57c5a97ab694f7db175efe7a17d36cb6000000000000000000000000000000001555535228eb9a24f460df9894d59aa06fc848a8bf8d6c3b51653b1d85734b3c5a2bece161309bd478d356fa198d579500000000000000000000000000000000144401f7eb69f6321eae8dad39dbe2cf4ae58e455474701dd9f1b62c85c7536813e84eb4f9def511eb62e5194288728b000000000000000000000000000000000e619d79792ac685030311a31a21203e5172d2e5d20ecf69a1e64158e7fe903b3695fd15432d3ca35562b5a8bd9cbdc20000000000000000000000000000000012394a621a503d1d92df3306649a6c6979816cabeb8f8d27450ec883c4e75f6f7411f3bfd068dc8dee58cdb8ebbd91bd00000000000000000000000000000000189be781abc010602e9262930d8dfdb2d7df81be0de1656554cb5afa3d059f1cc389678008ea84ba23ed5a54e9b07827000000000000000000000000000000001476dab5bd29af19c4e8f947b4255e4b86625fd4451b902fd10180e9ce7ed639c6e65683fabf0824a2a00185e82c3df5000000000000000000000000000000001555535228eb9a24f460df9894d59aa06fc848a8bf8d6c3b51653b1d85734b3c5a2bece161309bd478d356fa198d57950000000000000000000000000000000005bd0ff24e15f0682c6d1a09096fca081991bd3f9f10a2a18d3f1c7470e9a2bc0ac3b149b7750aedce9c1ae6bd773820000000000000000000000000000000000e619d79792ac685030311a31a21203e5172d2e5d20ecf69a1e64158e7fe903b3695fd15432d3ca35562b5a8bd9cbdc20000000000000000000000000000000012394a621a503d1d92df3306649a6c6979816cabeb8f8d27450ec883c4e75f6f7411f3bfd068dc8dee58cdb8ebbd91bd00000000000000000000000000000000189be781abc010602e9262930d8dfdb2d7df81be0de1656554cb5afa3d059f1cc389678008ea84ba23ed5a54e9b07827000000000000000000000000000000001476dab5bd29af19c4e8f947b4255e4b86625fd4451b902fd10180e9ce7ed639c6e65683fabf0824a2a00185e82c3df5", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "matter_pairing_95", - "Gas": 299000, + "Gas": 409000, "NoBenchmark": false } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/fail-blsG1Add.json b/core/vm/testdata/precompiles/fail-blsG1Add.json index e58ec0e90ec8..86bd3d660f61 100644 --- a/core/vm/testdata/precompiles/fail-blsG1Add.json +++ b/core/vm/testdata/precompiles/fail-blsG1Add.json @@ -21,12 +21,12 @@ }, { "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", - "ExpectedError": "must be less than modulus", + "ExpectedError": "invalid fp.Element encoding", "Name": "bls_g1add_invalid_field_element" }, { "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", - "ExpectedError": "point is not on curve", + "ExpectedError": "invalid point: not on curve", "Name": "bls_g1add_point_not_on_curve" } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/fail-blsG1Mul.json b/core/vm/testdata/precompiles/fail-blsG1Mul.json index acb8228aaaf3..7473d4d35cab 100644 --- a/core/vm/testdata/precompiles/fail-blsG1Mul.json +++ b/core/vm/testdata/precompiles/fail-blsG1Mul.json @@ -21,12 +21,12 @@ }, { "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac0000000000000000000000000000000000000000000000000000000000000007", - "ExpectedError": "must be less than modulus", + "ExpectedError": "invalid fp.Element encoding", "Name": "bls_g1mul_invalid_field_element" }, { "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", - "ExpectedError": "point is not on curve", + "ExpectedError": "invalid point: not on curve", "Name": "bls_g1mul_point_not_on_curve" } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/fail-blsG1MultiExp.json b/core/vm/testdata/precompiles/fail-blsG1MultiExp.json index 2cd28bd3b5c6..24a46cc0d098 100644 --- a/core/vm/testdata/precompiles/fail-blsG1MultiExp.json +++ b/core/vm/testdata/precompiles/fail-blsG1MultiExp.json @@ -16,7 +16,7 @@ }, { "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac0000000000000000000000000000000000000000000000000000000000000007", - "ExpectedError": "must be less than modulus", + "ExpectedError": "invalid fp.Element encoding", "Name": "bls_g1multiexp_invalid_field_element" }, { @@ -26,7 +26,7 @@ }, { "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", - "ExpectedError": "point is not on curve", + "ExpectedError": "invalid point: not on curve", "Name": "bls_g1multiexp_point_not_on_curve" } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/fail-blsG2Add.json b/core/vm/testdata/precompiles/fail-blsG2Add.json index b1fe9d5b8d53..b28a052b25c7 100644 --- a/core/vm/testdata/precompiles/fail-blsG2Add.json +++ b/core/vm/testdata/precompiles/fail-blsG2Add.json @@ -21,12 +21,12 @@ }, { "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "ExpectedError": "must be less than modulus", + "ExpectedError": "invalid fp.Element encoding", "Name": "bls_g2add_invalid_field_element" }, { "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "ExpectedError": "point is not on curve", + "ExpectedError": "invalid point: not on curve", "Name": "bls_g2add_point_not_on_curve" } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/fail-blsG2Mul.json b/core/vm/testdata/precompiles/fail-blsG2Mul.json index c2f0b89c8a7b..54a13c7f959e 100644 --- a/core/vm/testdata/precompiles/fail-blsG2Mul.json +++ b/core/vm/testdata/precompiles/fail-blsG2Mul.json @@ -21,12 +21,12 @@ }, { "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac0000000000000000000000000000000000000000000000000000000000000007", - "ExpectedError": "must be less than modulus", + "ExpectedError": "invalid fp.Element encoding", "Name": "bls_g2mul_invalid_field_element" }, { "Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", - "ExpectedError": "point is not on curve", + "ExpectedError": "invalid point: not on curve", "Name": "bls_g2mul_point_not_on_curve" } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/fail-blsG2MultiExp.json b/core/vm/testdata/precompiles/fail-blsG2MultiExp.json index 437f8dfca5c5..1679f17b3053 100644 --- a/core/vm/testdata/precompiles/fail-blsG2MultiExp.json +++ b/core/vm/testdata/precompiles/fail-blsG2MultiExp.json @@ -21,12 +21,12 @@ }, { "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac0000000000000000000000000000000000000000000000000000000000000007", - "ExpectedError": "must be less than modulus", + "ExpectedError": "invalid fp.Element encoding", "Name": "bls_g2multiexp_invalid_field_element" }, { "Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", - "ExpectedError": "point is not on curve", + "ExpectedError": "invalid point: not on curve", "Name": "bls_g2multiexp_point_not_on_curve" } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/fail-blsMapG1.json b/core/vm/testdata/precompiles/fail-blsMapG1.json index 8550269f1294..8eacca486550 100644 --- a/core/vm/testdata/precompiles/fail-blsMapG1.json +++ b/core/vm/testdata/precompiles/fail-blsMapG1.json @@ -16,7 +16,7 @@ }, { "Input": "000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac", - "ExpectedError": "must be less than modulus", + "ExpectedError": "invalid fp.Element encoding", "Name": "bls_mapg1_invalid_fq_element" } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/fail-blsMapG2.json b/core/vm/testdata/precompiles/fail-blsMapG2.json index 397a608b0a23..184d3ecbaa4a 100644 --- a/core/vm/testdata/precompiles/fail-blsMapG2.json +++ b/core/vm/testdata/precompiles/fail-blsMapG2.json @@ -16,7 +16,7 @@ }, { "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac", - "ExpectedError": "must be less than modulus", + "ExpectedError": "invalid fp.Element encoding", "Name": "bls_mapg2_invalid_fq_element" } ] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/fail-blsPairing.json b/core/vm/testdata/precompiles/fail-blsPairing.json index 084e55635c5c..4314d7335d2c 100644 --- a/core/vm/testdata/precompiles/fail-blsPairing.json +++ b/core/vm/testdata/precompiles/fail-blsPairing.json @@ -11,7 +11,7 @@ }, { "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac", - "ExpectedError": "must be less than modulus", + "ExpectedError": "invalid fp.Element encoding", "Name": "bls_pairing_invalid_field_element" }, { @@ -21,12 +21,12 @@ }, { "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "ExpectedError": "point is not on curve", + "ExpectedError": "invalid point: not on curve", "Name": "bls_pairing_g1_not_on_curve" }, { "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", - "ExpectedError": "point is not on curve", + "ExpectedError": "invalid point: not on curve", "Name": "bls_pairing_g2_not_on_curve" }, { diff --git a/crypto/bls12381/arithmetic_decl.go b/crypto/bls12381/arithmetic_decl.go deleted file mode 100644 index f6d232d658be..000000000000 --- a/crypto/bls12381/arithmetic_decl.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2020 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 . - -//go:build (amd64 && blsasm) || (amd64 && blsadx) -// +build amd64,blsasm amd64,blsadx - -package bls12381 - -import ( - "golang.org/x/sys/cpu" -) - -func init() { - if !enableADX || !cpu.X86.HasADX || !cpu.X86.HasBMI2 { - mul = mulNoADX - } -} - -// Use ADX backend for default -var mul func(c, a, b *fe) = mulADX - -func square(c, a *fe) { - mul(c, a, a) -} - -func neg(c, a *fe) { - if a.isZero() { - c.set(a) - } else { - _neg(c, a) - } -} - -//go:noescape -func add(c, a, b *fe) - -//go:noescape -func addAssign(a, b *fe) - -//go:noescape -func ladd(c, a, b *fe) - -//go:noescape -func laddAssign(a, b *fe) - -//go:noescape -func double(c, a *fe) - -//go:noescape -func doubleAssign(a *fe) - -//go:noescape -func ldouble(c, a *fe) - -//go:noescape -func sub(c, a, b *fe) - -//go:noescape -func subAssign(a, b *fe) - -//go:noescape -func lsubAssign(a, b *fe) - -//go:noescape -func _neg(c, a *fe) - -//go:noescape -func mulNoADX(c, a, b *fe) - -//go:noescape -func mulADX(c, a, b *fe) diff --git a/crypto/bls12381/arithmetic_fallback.go b/crypto/bls12381/arithmetic_fallback.go deleted file mode 100644 index c09ae0d91c72..000000000000 --- a/crypto/bls12381/arithmetic_fallback.go +++ /dev/null @@ -1,567 +0,0 @@ -// Native go field arithmetic code is generated with 'goff' -// https://github.com/ConsenSys/goff -// Many function signature of field operations are renamed. - -// Copyright 2020 ConsenSys AG -// -// 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. - -// field modulus q = -// -// 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 -// Code generated by goff DO NOT EDIT -// goff version: v0.1.0 - build: 790f1f56eac432441e043abff8819eacddd1d668 -// fe are assumed to be in Montgomery form in all methods - -// /!\ WARNING /!\ -// this code has not been audited and is provided as-is. In particular, -// there is no security guarantees such as constant time implementation -// or side-channel attack resistance -// /!\ WARNING /!\ - -// Package bls (generated by goff) contains field arithmetics operations - -//go:build !amd64 || (!blsasm && !blsadx) -// +build !amd64 !blsasm,!blsadx - -package bls12381 - -import ( - "math/bits" -) - -func add(z, x, y *fe) { - var carry uint64 - - z[0], carry = bits.Add64(x[0], y[0], 0) - z[1], carry = bits.Add64(x[1], y[1], carry) - z[2], carry = bits.Add64(x[2], y[2], carry) - z[3], carry = bits.Add64(x[3], y[3], carry) - z[4], carry = bits.Add64(x[4], y[4], carry) - z[5], _ = bits.Add64(x[5], y[5], carry) - - // if z > q --> z -= q - // note: this is NOT constant time - if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) - z[1], b = bits.Sub64(z[1], 2210141511517208575, b) - z[2], b = bits.Sub64(z[2], 7435674573564081700, b) - z[3], b = bits.Sub64(z[3], 7239337960414712511, b) - z[4], b = bits.Sub64(z[4], 5412103778470702295, b) - z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) - } -} - -func addAssign(x, y *fe) { - var carry uint64 - - x[0], carry = bits.Add64(x[0], y[0], 0) - x[1], carry = bits.Add64(x[1], y[1], carry) - x[2], carry = bits.Add64(x[2], y[2], carry) - x[3], carry = bits.Add64(x[3], y[3], carry) - x[4], carry = bits.Add64(x[4], y[4], carry) - x[5], _ = bits.Add64(x[5], y[5], carry) - - // if z > q --> z -= q - // note: this is NOT constant time - if !(x[5] < 1873798617647539866 || (x[5] == 1873798617647539866 && (x[4] < 5412103778470702295 || (x[4] == 5412103778470702295 && (x[3] < 7239337960414712511 || (x[3] == 7239337960414712511 && (x[2] < 7435674573564081700 || (x[2] == 7435674573564081700 && (x[1] < 2210141511517208575 || (x[1] == 2210141511517208575 && (x[0] < 13402431016077863595))))))))))) { - var b uint64 - x[0], b = bits.Sub64(x[0], 13402431016077863595, 0) - x[1], b = bits.Sub64(x[1], 2210141511517208575, b) - x[2], b = bits.Sub64(x[2], 7435674573564081700, b) - x[3], b = bits.Sub64(x[3], 7239337960414712511, b) - x[4], b = bits.Sub64(x[4], 5412103778470702295, b) - x[5], _ = bits.Sub64(x[5], 1873798617647539866, b) - } -} - -func ladd(z, x, y *fe) { - var carry uint64 - z[0], carry = bits.Add64(x[0], y[0], 0) - z[1], carry = bits.Add64(x[1], y[1], carry) - z[2], carry = bits.Add64(x[2], y[2], carry) - z[3], carry = bits.Add64(x[3], y[3], carry) - z[4], carry = bits.Add64(x[4], y[4], carry) - z[5], _ = bits.Add64(x[5], y[5], carry) -} - -func laddAssign(x, y *fe) { - var carry uint64 - x[0], carry = bits.Add64(x[0], y[0], 0) - x[1], carry = bits.Add64(x[1], y[1], carry) - x[2], carry = bits.Add64(x[2], y[2], carry) - x[3], carry = bits.Add64(x[3], y[3], carry) - x[4], carry = bits.Add64(x[4], y[4], carry) - x[5], _ = bits.Add64(x[5], y[5], carry) -} - -func double(z, x *fe) { - var carry uint64 - - z[0], carry = bits.Add64(x[0], x[0], 0) - z[1], carry = bits.Add64(x[1], x[1], carry) - z[2], carry = bits.Add64(x[2], x[2], carry) - z[3], carry = bits.Add64(x[3], x[3], carry) - z[4], carry = bits.Add64(x[4], x[4], carry) - z[5], _ = bits.Add64(x[5], x[5], carry) - - // if z > q --> z -= q - // note: this is NOT constant time - if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) - z[1], b = bits.Sub64(z[1], 2210141511517208575, b) - z[2], b = bits.Sub64(z[2], 7435674573564081700, b) - z[3], b = bits.Sub64(z[3], 7239337960414712511, b) - z[4], b = bits.Sub64(z[4], 5412103778470702295, b) - z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) - } -} - -func doubleAssign(z *fe) { - var carry uint64 - - z[0], carry = bits.Add64(z[0], z[0], 0) - z[1], carry = bits.Add64(z[1], z[1], carry) - z[2], carry = bits.Add64(z[2], z[2], carry) - z[3], carry = bits.Add64(z[3], z[3], carry) - z[4], carry = bits.Add64(z[4], z[4], carry) - z[5], _ = bits.Add64(z[5], z[5], carry) - - // if z > q --> z -= q - // note: this is NOT constant time - if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) - z[1], b = bits.Sub64(z[1], 2210141511517208575, b) - z[2], b = bits.Sub64(z[2], 7435674573564081700, b) - z[3], b = bits.Sub64(z[3], 7239337960414712511, b) - z[4], b = bits.Sub64(z[4], 5412103778470702295, b) - z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) - } -} - -func ldouble(z, x *fe) { - var carry uint64 - - z[0], carry = bits.Add64(x[0], x[0], 0) - z[1], carry = bits.Add64(x[1], x[1], carry) - z[2], carry = bits.Add64(x[2], x[2], carry) - z[3], carry = bits.Add64(x[3], x[3], carry) - z[4], carry = bits.Add64(x[4], x[4], carry) - z[5], _ = bits.Add64(x[5], x[5], carry) -} - -func sub(z, x, y *fe) { - var b uint64 - z[0], b = bits.Sub64(x[0], y[0], 0) - z[1], b = bits.Sub64(x[1], y[1], b) - z[2], b = bits.Sub64(x[2], y[2], b) - z[3], b = bits.Sub64(x[3], y[3], b) - z[4], b = bits.Sub64(x[4], y[4], b) - z[5], b = bits.Sub64(x[5], y[5], b) - if b != 0 { - var c uint64 - z[0], c = bits.Add64(z[0], 13402431016077863595, 0) - z[1], c = bits.Add64(z[1], 2210141511517208575, c) - z[2], c = bits.Add64(z[2], 7435674573564081700, c) - z[3], c = bits.Add64(z[3], 7239337960414712511, c) - z[4], c = bits.Add64(z[4], 5412103778470702295, c) - z[5], _ = bits.Add64(z[5], 1873798617647539866, c) - } -} - -func subAssign(z, x *fe) { - var b uint64 - z[0], b = bits.Sub64(z[0], x[0], 0) - z[1], b = bits.Sub64(z[1], x[1], b) - z[2], b = bits.Sub64(z[2], x[2], b) - z[3], b = bits.Sub64(z[3], x[3], b) - z[4], b = bits.Sub64(z[4], x[4], b) - z[5], b = bits.Sub64(z[5], x[5], b) - if b != 0 { - var c uint64 - z[0], c = bits.Add64(z[0], 13402431016077863595, 0) - z[1], c = bits.Add64(z[1], 2210141511517208575, c) - z[2], c = bits.Add64(z[2], 7435674573564081700, c) - z[3], c = bits.Add64(z[3], 7239337960414712511, c) - z[4], c = bits.Add64(z[4], 5412103778470702295, c) - z[5], _ = bits.Add64(z[5], 1873798617647539866, c) - } -} - -func lsubAssign(z, x *fe) { - var b uint64 - z[0], b = bits.Sub64(z[0], x[0], 0) - z[1], b = bits.Sub64(z[1], x[1], b) - z[2], b = bits.Sub64(z[2], x[2], b) - z[3], b = bits.Sub64(z[3], x[3], b) - z[4], b = bits.Sub64(z[4], x[4], b) - z[5], _ = bits.Sub64(z[5], x[5], b) -} - -func neg(z *fe, x *fe) { - if x.isZero() { - z.zero() - return - } - var borrow uint64 - z[0], borrow = bits.Sub64(13402431016077863595, x[0], 0) - z[1], borrow = bits.Sub64(2210141511517208575, x[1], borrow) - z[2], borrow = bits.Sub64(7435674573564081700, x[2], borrow) - z[3], borrow = bits.Sub64(7239337960414712511, x[3], borrow) - z[4], borrow = bits.Sub64(5412103778470702295, x[4], borrow) - z[5], _ = bits.Sub64(1873798617647539866, x[5], borrow) -} - -func mul(z, x, y *fe) { - var t [6]uint64 - var c [3]uint64 - { - // round 0 - v := x[0] - c[1], c[0] = bits.Mul64(v, y[0]) - m := c[0] * 9940570264628428797 - c[2] = madd0(m, 13402431016077863595, c[0]) - c[1], c[0] = madd1(v, y[1], c[1]) - c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) - c[1], c[0] = madd1(v, y[2], c[1]) - c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) - c[1], c[0] = madd1(v, y[3], c[1]) - c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) - c[1], c[0] = madd1(v, y[4], c[1]) - c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) - c[1], c[0] = madd1(v, y[5], c[1]) - t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) - } - { - // round 1 - v := x[1] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 9940570264628428797 - c[2] = madd0(m, 13402431016077863595, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) - c[1], c[0] = madd2(v, y[4], c[1], t[4]) - c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) - c[1], c[0] = madd2(v, y[5], c[1], t[5]) - t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) - } - { - // round 2 - v := x[2] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 9940570264628428797 - c[2] = madd0(m, 13402431016077863595, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) - c[1], c[0] = madd2(v, y[4], c[1], t[4]) - c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) - c[1], c[0] = madd2(v, y[5], c[1], t[5]) - t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) - } - { - // round 3 - v := x[3] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 9940570264628428797 - c[2] = madd0(m, 13402431016077863595, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) - c[1], c[0] = madd2(v, y[4], c[1], t[4]) - c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) - c[1], c[0] = madd2(v, y[5], c[1], t[5]) - t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) - } - { - // round 4 - v := x[4] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 9940570264628428797 - c[2] = madd0(m, 13402431016077863595, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) - c[1], c[0] = madd2(v, y[4], c[1], t[4]) - c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) - c[1], c[0] = madd2(v, y[5], c[1], t[5]) - t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) - } - { - // round 5 - v := x[5] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 9940570264628428797 - c[2] = madd0(m, 13402431016077863595, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], z[0] = madd2(m, 2210141511517208575, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], z[1] = madd2(m, 7435674573564081700, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - c[2], z[2] = madd2(m, 7239337960414712511, c[2], c[0]) - c[1], c[0] = madd2(v, y[4], c[1], t[4]) - c[2], z[3] = madd2(m, 5412103778470702295, c[2], c[0]) - c[1], c[0] = madd2(v, y[5], c[1], t[5]) - z[5], z[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) - } - - // if z > q --> z -= q - // note: this is NOT constant time - if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) - z[1], b = bits.Sub64(z[1], 2210141511517208575, b) - z[2], b = bits.Sub64(z[2], 7435674573564081700, b) - z[3], b = bits.Sub64(z[3], 7239337960414712511, b) - z[4], b = bits.Sub64(z[4], 5412103778470702295, b) - z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) - } -} - -func square(z, x *fe) { - - var p [6]uint64 - - var u, v uint64 - { - // round 0 - u, p[0] = bits.Mul64(x[0], x[0]) - m := p[0] * 9940570264628428797 - C := madd0(m, 13402431016077863595, p[0]) - var t uint64 - t, u, v = madd1sb(x[0], x[1], u) - C, p[0] = madd2(m, 2210141511517208575, v, C) - t, u, v = madd1s(x[0], x[2], t, u) - C, p[1] = madd2(m, 7435674573564081700, v, C) - t, u, v = madd1s(x[0], x[3], t, u) - C, p[2] = madd2(m, 7239337960414712511, v, C) - t, u, v = madd1s(x[0], x[4], t, u) - C, p[3] = madd2(m, 5412103778470702295, v, C) - _, u, v = madd1s(x[0], x[5], t, u) - p[5], p[4] = madd3(m, 1873798617647539866, v, C, u) - } - { - // round 1 - m := p[0] * 9940570264628428797 - C := madd0(m, 13402431016077863595, p[0]) - u, v = madd1(x[1], x[1], p[1]) - C, p[0] = madd2(m, 2210141511517208575, v, C) - var t uint64 - t, u, v = madd2sb(x[1], x[2], p[2], u) - C, p[1] = madd2(m, 7435674573564081700, v, C) - t, u, v = madd2s(x[1], x[3], p[3], t, u) - C, p[2] = madd2(m, 7239337960414712511, v, C) - t, u, v = madd2s(x[1], x[4], p[4], t, u) - C, p[3] = madd2(m, 5412103778470702295, v, C) - _, u, v = madd2s(x[1], x[5], p[5], t, u) - p[5], p[4] = madd3(m, 1873798617647539866, v, C, u) - } - { - // round 2 - m := p[0] * 9940570264628428797 - C := madd0(m, 13402431016077863595, p[0]) - C, p[0] = madd2(m, 2210141511517208575, p[1], C) - u, v = madd1(x[2], x[2], p[2]) - C, p[1] = madd2(m, 7435674573564081700, v, C) - var t uint64 - t, u, v = madd2sb(x[2], x[3], p[3], u) - C, p[2] = madd2(m, 7239337960414712511, v, C) - t, u, v = madd2s(x[2], x[4], p[4], t, u) - C, p[3] = madd2(m, 5412103778470702295, v, C) - _, u, v = madd2s(x[2], x[5], p[5], t, u) - p[5], p[4] = madd3(m, 1873798617647539866, v, C, u) - } - { - // round 3 - m := p[0] * 9940570264628428797 - C := madd0(m, 13402431016077863595, p[0]) - C, p[0] = madd2(m, 2210141511517208575, p[1], C) - C, p[1] = madd2(m, 7435674573564081700, p[2], C) - u, v = madd1(x[3], x[3], p[3]) - C, p[2] = madd2(m, 7239337960414712511, v, C) - var t uint64 - t, u, v = madd2sb(x[3], x[4], p[4], u) - C, p[3] = madd2(m, 5412103778470702295, v, C) - _, u, v = madd2s(x[3], x[5], p[5], t, u) - p[5], p[4] = madd3(m, 1873798617647539866, v, C, u) - } - { - // round 4 - m := p[0] * 9940570264628428797 - C := madd0(m, 13402431016077863595, p[0]) - C, p[0] = madd2(m, 2210141511517208575, p[1], C) - C, p[1] = madd2(m, 7435674573564081700, p[2], C) - C, p[2] = madd2(m, 7239337960414712511, p[3], C) - u, v = madd1(x[4], x[4], p[4]) - C, p[3] = madd2(m, 5412103778470702295, v, C) - _, u, v = madd2sb(x[4], x[5], p[5], u) - p[5], p[4] = madd3(m, 1873798617647539866, v, C, u) - } - { - // round 5 - m := p[0] * 9940570264628428797 - C := madd0(m, 13402431016077863595, p[0]) - C, z[0] = madd2(m, 2210141511517208575, p[1], C) - C, z[1] = madd2(m, 7435674573564081700, p[2], C) - C, z[2] = madd2(m, 7239337960414712511, p[3], C) - C, z[3] = madd2(m, 5412103778470702295, p[4], C) - u, v = madd1(x[5], x[5], p[5]) - z[5], z[4] = madd3(m, 1873798617647539866, v, C, u) - } - - // if z > q --> z -= q - // note: this is NOT constant time - if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) - z[1], b = bits.Sub64(z[1], 2210141511517208575, b) - z[2], b = bits.Sub64(z[2], 7435674573564081700, b) - z[3], b = bits.Sub64(z[3], 7239337960414712511, b) - z[4], b = bits.Sub64(z[4], 5412103778470702295, b) - z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) - } -} - -// arith.go -// Copyright 2020 ConsenSys AG -// -// 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. - -// Code generated by goff DO NOT EDIT - -func madd(a, b, t, u, v uint64) (uint64, uint64, uint64) { - var carry uint64 - hi, lo := bits.Mul64(a, b) - v, carry = bits.Add64(lo, v, 0) - u, carry = bits.Add64(hi, u, carry) - t, _ = bits.Add64(t, 0, carry) - return t, u, v -} - -// madd0 hi = a*b + c (discards lo bits) -func madd0(a, b, c uint64) (hi uint64) { - var carry, lo uint64 - hi, lo = bits.Mul64(a, b) - _, carry = bits.Add64(lo, c, 0) - hi, _ = bits.Add64(hi, 0, carry) - return -} - -// madd1 hi, lo = a*b + c -func madd1(a, b, c uint64) (hi uint64, lo uint64) { - var carry uint64 - hi, lo = bits.Mul64(a, b) - lo, carry = bits.Add64(lo, c, 0) - hi, _ = bits.Add64(hi, 0, carry) - return -} - -// madd2 hi, lo = a*b + c + d -func madd2(a, b, c, d uint64) (hi uint64, lo uint64) { - var carry uint64 - hi, lo = bits.Mul64(a, b) - c, carry = bits.Add64(c, d, 0) - hi, _ = bits.Add64(hi, 0, carry) - lo, carry = bits.Add64(lo, c, 0) - hi, _ = bits.Add64(hi, 0, carry) - return -} - -// madd2s superhi, hi, lo = 2*a*b + c + d + e -func madd2s(a, b, c, d, e uint64) (superhi, hi, lo uint64) { - var carry, sum uint64 - - hi, lo = bits.Mul64(a, b) - lo, carry = bits.Add64(lo, lo, 0) - hi, superhi = bits.Add64(hi, hi, carry) - - sum, carry = bits.Add64(c, e, 0) - hi, _ = bits.Add64(hi, 0, carry) - lo, carry = bits.Add64(lo, sum, 0) - hi, _ = bits.Add64(hi, 0, carry) - hi, _ = bits.Add64(hi, 0, d) - return -} - -func madd1s(a, b, d, e uint64) (superhi, hi, lo uint64) { - var carry uint64 - - hi, lo = bits.Mul64(a, b) - lo, carry = bits.Add64(lo, lo, 0) - hi, superhi = bits.Add64(hi, hi, carry) - lo, carry = bits.Add64(lo, e, 0) - hi, _ = bits.Add64(hi, 0, carry) - hi, _ = bits.Add64(hi, 0, d) - return -} - -func madd2sb(a, b, c, e uint64) (superhi, hi, lo uint64) { - var carry, sum uint64 - - hi, lo = bits.Mul64(a, b) - lo, carry = bits.Add64(lo, lo, 0) - hi, superhi = bits.Add64(hi, hi, carry) - - sum, carry = bits.Add64(c, e, 0) - hi, _ = bits.Add64(hi, 0, carry) - lo, carry = bits.Add64(lo, sum, 0) - hi, _ = bits.Add64(hi, 0, carry) - return -} - -func madd1sb(a, b, e uint64) (superhi, hi, lo uint64) { - var carry uint64 - - hi, lo = bits.Mul64(a, b) - lo, carry = bits.Add64(lo, lo, 0) - hi, superhi = bits.Add64(hi, hi, carry) - lo, carry = bits.Add64(lo, e, 0) - hi, _ = bits.Add64(hi, 0, carry) - return -} - -func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { - var carry uint64 - hi, lo = bits.Mul64(a, b) - c, carry = bits.Add64(c, d, 0) - hi, _ = bits.Add64(hi, 0, carry) - lo, carry = bits.Add64(lo, c, 0) - hi, _ = bits.Add64(hi, e, carry) - return -} diff --git a/crypto/bls12381/arithmetic_x86.s b/crypto/bls12381/arithmetic_x86.s deleted file mode 100644 index 2cebbc46f796..000000000000 --- a/crypto/bls12381/arithmetic_x86.s +++ /dev/null @@ -1,2150 +0,0 @@ -// +build amd64,blsasm amd64,blsadx - -#include "textflag.h" - -// addition w/ modular reduction -// a = (a + b) % p -TEXT ·addAssign(SB), NOSPLIT, $0-16 - // | - MOVQ a+0(FP), DI - MOVQ b+8(FP), SI - - // | - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - - // | - ADDQ (SI), R8 - ADCQ 8(SI), R9 - ADCQ 16(SI), R10 - ADCQ 24(SI), R11 - ADCQ 32(SI), R12 - ADCQ 40(SI), R13 - - // | - MOVQ R8, R14 - MOVQ R9, R15 - MOVQ R10, CX - MOVQ R11, DX - MOVQ R12, SI - MOVQ R13, BX - MOVQ $0xb9feffffffffaaab, AX - SUBQ AX, R14 - MOVQ $0x1eabfffeb153ffff, AX - SBBQ AX, R15 - MOVQ $0x6730d2a0f6b0f624, AX - SBBQ AX, CX - MOVQ $0x64774b84f38512bf, AX - SBBQ AX, DX - MOVQ $0x4b1ba7b6434bacd7, AX - SBBQ AX, SI - MOVQ $0x1a0111ea397fe69a, AX - SBBQ AX, BX - CMOVQCC R14, R8 - CMOVQCC R15, R9 - CMOVQCC CX, R10 - CMOVQCC DX, R11 - CMOVQCC SI, R12 - CMOVQCC BX, R13 - - // | - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET - -/* | end */ - - -// addition w/ modular reduction -// c = (a + b) % p -TEXT ·add(SB), NOSPLIT, $0-24 - // | - MOVQ a+8(FP), DI - MOVQ b+16(FP), SI - - // | - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - - // | - ADDQ (SI), R8 - ADCQ 8(SI), R9 - ADCQ 16(SI), R10 - ADCQ 24(SI), R11 - ADCQ 32(SI), R12 - ADCQ 40(SI), R13 - - // | - MOVQ R8, R14 - MOVQ R9, R15 - MOVQ R10, CX - MOVQ R11, DX - MOVQ R12, SI - MOVQ R13, BX - MOVQ $0xb9feffffffffaaab, DI - SUBQ DI, R14 - MOVQ $0x1eabfffeb153ffff, DI - SBBQ DI, R15 - MOVQ $0x6730d2a0f6b0f624, DI - SBBQ DI, CX - MOVQ $0x64774b84f38512bf, DI - SBBQ DI, DX - MOVQ $0x4b1ba7b6434bacd7, DI - SBBQ DI, SI - MOVQ $0x1a0111ea397fe69a, DI - SBBQ DI, BX - CMOVQCC R14, R8 - CMOVQCC R15, R9 - CMOVQCC CX, R10 - CMOVQCC DX, R11 - CMOVQCC SI, R12 - CMOVQCC BX, R13 - - // | - MOVQ c+0(FP), DI - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET -/* | end */ - - -// addition w/o reduction check -// c = (a + b) -TEXT ·ladd(SB), NOSPLIT, $0-24 - // | - MOVQ a+8(FP), DI - MOVQ b+16(FP), SI - - // | - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - - // | - ADDQ (SI), R8 - ADCQ 8(SI), R9 - ADCQ 16(SI), R10 - ADCQ 24(SI), R11 - ADCQ 32(SI), R12 - ADCQ 40(SI), R13 - - // | - MOVQ c+0(FP), DI - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET -/* | end */ - - -// addition w/o reduction check -// a = a + b -TEXT ·laddAssign(SB), NOSPLIT, $0-16 - // | - MOVQ a+0(FP), DI - MOVQ b+8(FP), SI - - // | - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - - // | - ADDQ (SI), R8 - ADCQ 8(SI), R9 - ADCQ 16(SI), R10 - ADCQ 24(SI), R11 - ADCQ 32(SI), R12 - ADCQ 40(SI), R13 - - // | - MOVQ a+0(FP), DI - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET -/* | end */ - - -// subtraction w/ modular reduction -// c = (a - b) % p -TEXT ·sub(SB), NOSPLIT, $0-24 - // | - MOVQ a+8(FP), DI - MOVQ b+16(FP), SI - XORQ AX, AX - - // | - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - SUBQ (SI), R8 - SBBQ 8(SI), R9 - SBBQ 16(SI), R10 - SBBQ 24(SI), R11 - SBBQ 32(SI), R12 - SBBQ 40(SI), R13 - - // | - MOVQ $0xb9feffffffffaaab, R14 - MOVQ $0x1eabfffeb153ffff, R15 - MOVQ $0x6730d2a0f6b0f624, CX - MOVQ $0x64774b84f38512bf, DX - MOVQ $0x4b1ba7b6434bacd7, SI - MOVQ $0x1a0111ea397fe69a, BX - CMOVQCC AX, R14 - CMOVQCC AX, R15 - CMOVQCC AX, CX - CMOVQCC AX, DX - CMOVQCC AX, SI - CMOVQCC AX, BX - ADDQ R14, R8 - ADCQ R15, R9 - ADCQ CX, R10 - ADCQ DX, R11 - ADCQ SI, R12 - ADCQ BX, R13 - - // | - MOVQ c+0(FP), DI - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET -/* | end */ - - -// subtraction w/ modular reduction -// a = (a - b) % p -TEXT ·subAssign(SB), NOSPLIT, $0-16 - // | - MOVQ a+0(FP), DI - MOVQ b+8(FP), SI - XORQ AX, AX - - // | - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - SUBQ (SI), R8 - SBBQ 8(SI), R9 - SBBQ 16(SI), R10 - SBBQ 24(SI), R11 - SBBQ 32(SI), R12 - SBBQ 40(SI), R13 - - // | - MOVQ $0xb9feffffffffaaab, R14 - MOVQ $0x1eabfffeb153ffff, R15 - MOVQ $0x6730d2a0f6b0f624, CX - MOVQ $0x64774b84f38512bf, DX - MOVQ $0x4b1ba7b6434bacd7, SI - MOVQ $0x1a0111ea397fe69a, BX - CMOVQCC AX, R14 - CMOVQCC AX, R15 - CMOVQCC AX, CX - CMOVQCC AX, DX - CMOVQCC AX, SI - CMOVQCC AX, BX - ADDQ R14, R8 - ADCQ R15, R9 - ADCQ CX, R10 - ADCQ DX, R11 - ADCQ SI, R12 - ADCQ BX, R13 - - // | - MOVQ a+0(FP), DI - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET -/* | end */ - - -// subtraction w/o reduction check -// a = (a - b) -TEXT ·lsubAssign(SB), NOSPLIT, $0-16 - // | - MOVQ a+0(FP), DI - MOVQ b+8(FP), SI - - // | - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - SUBQ (SI), R8 - SBBQ 8(SI), R9 - SBBQ 16(SI), R10 - SBBQ 24(SI), R11 - SBBQ 32(SI), R12 - SBBQ 40(SI), R13 - - // | - MOVQ a+0(FP), DI - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET -/* | end */ - -// doubling w/ reduction -// c = (2 * a) % p -TEXT ·double(SB), NOSPLIT, $0-16 - // | - MOVQ a+8(FP), DI - - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - ADDQ R8, R8 - ADCQ R9, R9 - ADCQ R10, R10 - ADCQ R11, R11 - ADCQ R12, R12 - ADCQ R13, R13 - - // | - MOVQ R8, R14 - MOVQ R9, R15 - MOVQ R10, CX - MOVQ R11, DX - MOVQ R12, SI - MOVQ R13, BX - MOVQ $0xb9feffffffffaaab, DI - SUBQ DI, R14 - MOVQ $0x1eabfffeb153ffff, DI - SBBQ DI, R15 - MOVQ $0x6730d2a0f6b0f624, DI - SBBQ DI, CX - MOVQ $0x64774b84f38512bf, DI - SBBQ DI, DX - MOVQ $0x4b1ba7b6434bacd7, DI - SBBQ DI, SI - MOVQ $0x1a0111ea397fe69a, DI - SBBQ DI, BX - CMOVQCC R14, R8 - CMOVQCC R15, R9 - CMOVQCC CX, R10 - CMOVQCC DX, R11 - CMOVQCC SI, R12 - CMOVQCC BX, R13 - - // | - MOVQ c+0(FP), DI - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET -/* | end */ - - -// doubling w/ reduction -// a = (2 * a) % p -TEXT ·doubleAssign(SB), NOSPLIT, $0-8 - // | - MOVQ a+0(FP), DI - - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - ADDQ R8, R8 - ADCQ R9, R9 - ADCQ R10, R10 - ADCQ R11, R11 - ADCQ R12, R12 - ADCQ R13, R13 - - // | - MOVQ R8, R14 - MOVQ R9, R15 - MOVQ R10, CX - MOVQ R11, DX - MOVQ R12, SI - MOVQ R13, BX - MOVQ $0xb9feffffffffaaab, AX - SUBQ AX, R14 - MOVQ $0x1eabfffeb153ffff, AX - SBBQ AX, R15 - MOVQ $0x6730d2a0f6b0f624, AX - SBBQ AX, CX - MOVQ $0x64774b84f38512bf, AX - SBBQ AX, DX - MOVQ $0x4b1ba7b6434bacd7, AX - SBBQ AX, SI - MOVQ $0x1a0111ea397fe69a, AX - SBBQ AX, BX - CMOVQCC R14, R8 - CMOVQCC R15, R9 - CMOVQCC CX, R10 - CMOVQCC DX, R11 - CMOVQCC SI, R12 - CMOVQCC BX, R13 - - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET -/* | end */ - - -// doubling w/o reduction -// c = 2 * a -TEXT ·ldouble(SB), NOSPLIT, $0-16 - // | - MOVQ a+8(FP), DI - - MOVQ (DI), R8 - MOVQ 8(DI), R9 - MOVQ 16(DI), R10 - MOVQ 24(DI), R11 - MOVQ 32(DI), R12 - MOVQ 40(DI), R13 - - // | - ADDQ R8, R8 - ADCQ R9, R9 - ADCQ R10, R10 - ADCQ R11, R11 - ADCQ R12, R12 - ADCQ R13, R13 - - // | - MOVQ c+0(FP), DI - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - - RET -/* | end */ - - -TEXT ·_neg(SB), NOSPLIT, $0-16 - // | - MOVQ a+8(FP), DI - - // | - MOVQ $0xb9feffffffffaaab, R8 - MOVQ $0x1eabfffeb153ffff, R9 - MOVQ $0x6730d2a0f6b0f624, R10 - MOVQ $0x64774b84f38512bf, R11 - MOVQ $0x4b1ba7b6434bacd7, R12 - MOVQ $0x1a0111ea397fe69a, R13 - SUBQ (DI), R8 - SBBQ 8(DI), R9 - SBBQ 16(DI), R10 - SBBQ 24(DI), R11 - SBBQ 32(DI), R12 - SBBQ 40(DI), R13 - - // | - MOVQ c+0(FP), DI - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ R12, 32(DI) - MOVQ R13, 40(DI) - RET -/* | end */ - - -// multiplication without using MULX/ADX -// c = a * b % p -TEXT ·mulNoADX(SB), NOSPLIT, $24-24 - // | - -/* inputs */ - - MOVQ a+8(FP), DI - MOVQ b+16(FP), SI - MOVQ $0x00, R9 - MOVQ $0x00, R10 - MOVQ $0x00, R11 - MOVQ $0x00, R12 - MOVQ $0x00, R13 - MOVQ $0x00, R14 - MOVQ $0x00, R15 - - // | - -/* i0 */ - - // | a0 @ CX - MOVQ (DI), CX - - // | a0 * b0 - MOVQ (SI), AX - MULQ CX - MOVQ AX, (SP) - MOVQ DX, R8 - - // | a0 * b1 - MOVQ 8(SI), AX - MULQ CX - ADDQ AX, R8 - ADCQ DX, R9 - - // | a0 * b2 - MOVQ 16(SI), AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - - // | a0 * b3 - MOVQ 24(SI), AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R11 - - // | a0 * b4 - MOVQ 32(SI), AX - MULQ CX - ADDQ AX, R11 - ADCQ DX, R12 - - // | a0 * b5 - MOVQ 40(SI), AX - MULQ CX - ADDQ AX, R12 - ADCQ DX, R13 - - // | - -/* i1 */ - - // | a1 @ CX - MOVQ 8(DI), CX - MOVQ $0x00, BX - - // | a1 * b0 - MOVQ (SI), AX - MULQ CX - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0x00, R10 - ADCQ $0x00, BX - MOVQ R8, 8(SP) - MOVQ $0x00, R8 - - // | a1 * b1 - MOVQ 8(SI), AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ BX, R11 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a1 * b2 - MOVQ 16(SI), AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R11 - ADCQ BX, R12 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a1 * b3 - MOVQ 24(SI), AX - MULQ CX - ADDQ AX, R11 - ADCQ DX, R12 - ADCQ BX, R13 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a1 * b4 - MOVQ 32(SI), AX - MULQ CX - ADDQ AX, R12 - ADCQ DX, R13 - ADCQ BX, R14 - - // | a1 * b5 - MOVQ 40(SI), AX - MULQ CX - ADDQ AX, R13 - ADCQ DX, R14 - - // | - -/* i2 */ - - // | a2 @ CX - MOVQ 16(DI), CX - MOVQ $0x00, BX - - // | a2 * b0 - MOVQ (SI), AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0x00, R11 - ADCQ $0x00, BX - MOVQ R9, 16(SP) - MOVQ $0x00, R9 - - // | a2 * b1 - MOVQ 8(SI), AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R11 - ADCQ BX, R12 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a2 * b2 - MOVQ 16(SI), AX - MULQ CX - ADDQ AX, R11 - ADCQ DX, R12 - ADCQ BX, R13 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a2 * b3 - MOVQ 24(SI), AX - MULQ CX - ADDQ AX, R12 - ADCQ DX, R13 - ADCQ BX, R14 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a2 * b4 - MOVQ 32(SI), AX - MULQ CX - ADDQ AX, R13 - ADCQ DX, R14 - ADCQ BX, R15 - - // | a2 * b5 - MOVQ 40(SI), AX - MULQ CX - ADDQ AX, R14 - ADCQ DX, R15 - - // | - -/* i3 */ - - // | a3 @ CX - MOVQ 24(DI), CX - MOVQ $0x00, BX - - // | a3 * b0 - MOVQ (SI), AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R11 - ADCQ $0x00, R12 - ADCQ $0x00, BX - - // | a3 * b1 - MOVQ 8(SI), AX - MULQ CX - ADDQ AX, R11 - ADCQ DX, R12 - ADCQ BX, R13 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a3 * b2 - MOVQ 16(SI), AX - MULQ CX - ADDQ AX, R12 - ADCQ DX, R13 - ADCQ BX, R14 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a3 * b3 - MOVQ 24(SI), AX - MULQ CX - ADDQ AX, R13 - ADCQ DX, R14 - ADCQ BX, R15 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a3 * b4 - MOVQ 32(SI), AX - MULQ CX - ADDQ AX, R14 - ADCQ DX, R15 - ADCQ BX, R8 - - // | a3 * b5 - MOVQ 40(SI), AX - MULQ CX - ADDQ AX, R15 - ADCQ DX, R8 - - // | - -/* i4 */ - - // | a4 @ CX - MOVQ 32(DI), CX - MOVQ $0x00, BX - - // | a4 * b0 - MOVQ (SI), AX - MULQ CX - ADDQ AX, R11 - ADCQ DX, R12 - ADCQ $0x00, R13 - ADCQ $0x00, BX - - // | a4 * b1 - MOVQ 8(SI), AX - MULQ CX - ADDQ AX, R12 - ADCQ DX, R13 - ADCQ BX, R14 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a4 * b2 - MOVQ 16(SI), AX - MULQ CX - ADDQ AX, R13 - ADCQ DX, R14 - ADCQ BX, R15 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a4 * b3 - MOVQ 24(SI), AX - MULQ CX - ADDQ AX, R14 - ADCQ DX, R15 - ADCQ BX, R8 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a4 * b4 - MOVQ 32(SI), AX - MULQ CX - ADDQ AX, R15 - ADCQ DX, R8 - ADCQ BX, R9 - - // | a4 * b5 - MOVQ 40(SI), AX - MULQ CX - ADDQ AX, R8 - ADCQ DX, R9 - - // | - -/* i5 */ - - // | a5 @ CX - MOVQ 40(DI), CX - MOVQ $0x00, BX - - // | a5 * b0 - MOVQ (SI), AX - MULQ CX - ADDQ AX, R12 - ADCQ DX, R13 - ADCQ $0x00, R14 - ADCQ $0x00, BX - - // | a5 * b1 - MOVQ 8(SI), AX - MULQ CX - ADDQ AX, R13 - ADCQ DX, R14 - ADCQ BX, R15 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a5 * b2 - MOVQ 16(SI), AX - MULQ CX - ADDQ AX, R14 - ADCQ DX, R15 - ADCQ BX, R8 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a5 * b3 - MOVQ 24(SI), AX - MULQ CX - ADDQ AX, R15 - ADCQ DX, R8 - ADCQ BX, R9 - MOVQ $0x00, BX - ADCQ $0x00, BX - - // | a5 * b4 - MOVQ 32(SI), AX - MULQ CX - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0x00, BX - - // | a5 * b5 - MOVQ 40(SI), AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, BX - - // | - -/* */ - - // | - // | W - // | 0 (SP) | 1 8(SP) | 2 16(SP) | 3 R10 | 4 R11 | 5 R12 - // | 6 R13 | 7 R14 | 8 R15 | 9 R8 | 10 R9 | 11 BX - - - MOVQ (SP), CX - MOVQ 8(SP), DI - MOVQ 16(SP), SI - MOVQ BX, (SP) - MOVQ R9, 8(SP) - - // | - -/* montgomery reduction */ - - // | - -/* i0 */ - - // | - // | W - // | 0 CX | 1 DI | 2 SI | 3 R10 | 4 R11 | 5 R12 - // | 6 R13 | 7 R14 | 8 R15 | 9 R8 | 10 8(SP) | 11 (SP) - - - // | | u0 = w0 * inp - MOVQ CX, AX - MULQ ·inp+0(SB) - MOVQ AX, R9 - MOVQ $0x00, BX - - // | - -/* */ - - // | j0 - - // | w0 @ CX - MOVQ ·modulus+0(SB), AX - MULQ R9 - ADDQ AX, CX - ADCQ DX, BX - - // | j1 - - // | w1 @ DI - MOVQ ·modulus+8(SB), AX - MULQ R9 - ADDQ AX, DI - ADCQ $0x00, DX - ADDQ BX, DI - MOVQ $0x00, BX - ADCQ DX, BX - - // | j2 - - // | w2 @ SI - MOVQ ·modulus+16(SB), AX - MULQ R9 - ADDQ AX, SI - ADCQ $0x00, DX - ADDQ BX, SI - MOVQ $0x00, BX - ADCQ DX, BX - - // | j3 - - // | w3 @ R10 - MOVQ ·modulus+24(SB), AX - MULQ R9 - ADDQ AX, R10 - ADCQ $0x00, DX - ADDQ BX, R10 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j4 - - // | w4 @ R11 - MOVQ ·modulus+32(SB), AX - MULQ R9 - ADDQ AX, R11 - ADCQ $0x00, DX - ADDQ BX, R11 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j5 - - // | w5 @ R12 - MOVQ ·modulus+40(SB), AX - MULQ R9 - ADDQ AX, R12 - ADCQ $0x00, DX - ADDQ BX, R12 - - // | w6 @ R13 - ADCQ DX, R13 - ADCQ $0x00, CX - - // | - -/* i1 */ - - // | - // | W - // | 0 - | 1 DI | 2 SI | 3 R10 | 4 R11 | 5 R12 - // | 6 R13 | 7 R14 | 8 R15 | 9 R8 | 10 8(SP) | 11 (SP) - - - // | | u1 = w1 * inp - MOVQ DI, AX - MULQ ·inp+0(SB) - MOVQ AX, R9 - MOVQ $0x00, BX - - // | - -/* */ - - // | j0 - - // | w1 @ DI - MOVQ ·modulus+0(SB), AX - MULQ R9 - ADDQ AX, DI - ADCQ DX, BX - - // | j1 - - // | w2 @ SI - MOVQ ·modulus+8(SB), AX - MULQ R9 - ADDQ AX, SI - ADCQ $0x00, DX - ADDQ BX, SI - MOVQ $0x00, BX - ADCQ DX, BX - - // | j2 - - // | w3 @ R10 - MOVQ ·modulus+16(SB), AX - MULQ R9 - ADDQ AX, R10 - ADCQ $0x00, DX - ADDQ BX, R10 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j3 - - // | w4 @ R11 - MOVQ ·modulus+24(SB), AX - MULQ R9 - ADDQ AX, R11 - ADCQ $0x00, DX - ADDQ BX, R11 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j4 - - // | w5 @ R12 - MOVQ ·modulus+32(SB), AX - MULQ R9 - ADDQ AX, R12 - ADCQ $0x00, DX - ADDQ BX, R12 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j5 - - // | w6 @ R13 - MOVQ ·modulus+40(SB), AX - MULQ R9 - ADDQ AX, R13 - ADCQ DX, CX - ADDQ BX, R13 - - // | w7 @ R14 - ADCQ CX, R14 - MOVQ $0x00, CX - ADCQ $0x00, CX - - // | - -/* i2 */ - - // | - // | W - // | 0 - | 1 - | 2 SI | 3 R10 | 4 R11 | 5 R12 - // | 6 R13 | 7 R14 | 8 R15 | 9 R8 | 10 8(SP) | 11 (SP) - - - // | | u2 = w2 * inp - MOVQ SI, AX - MULQ ·inp+0(SB) - MOVQ AX, R9 - MOVQ $0x00, BX - - // | - -/* */ - - // | j0 - - // | w2 @ SI - MOVQ ·modulus+0(SB), AX - MULQ R9 - ADDQ AX, SI - ADCQ DX, BX - - // | j1 - - // | w3 @ R10 - MOVQ ·modulus+8(SB), AX - MULQ R9 - ADDQ AX, R10 - ADCQ $0x00, DX - ADDQ BX, R10 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j2 - - // | w4 @ R11 - MOVQ ·modulus+16(SB), AX - MULQ R9 - ADDQ AX, R11 - ADCQ $0x00, DX - ADDQ BX, R11 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j3 - - // | w5 @ R12 - MOVQ ·modulus+24(SB), AX - MULQ R9 - ADDQ AX, R12 - ADCQ $0x00, DX - ADDQ BX, R12 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j4 - - // | w6 @ R13 - MOVQ ·modulus+32(SB), AX - MULQ R9 - ADDQ AX, R13 - ADCQ $0x00, DX - ADDQ BX, R13 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j5 - - // | w7 @ R14 - MOVQ ·modulus+40(SB), AX - MULQ R9 - ADDQ AX, R14 - ADCQ DX, CX - ADDQ BX, R14 - - // | w8 @ R15 - ADCQ CX, R15 - MOVQ $0x00, CX - ADCQ $0x00, CX - - // | - -/* i3 */ - - // | - // | W - // | 0 - | 1 - | 2 - | 3 R10 | 4 R11 | 5 R12 - // | 6 R13 | 7 R14 | 8 R15 | 9 R8 | 10 8(SP) | 11 (SP) - - - // | | u3 = w3 * inp - MOVQ R10, AX - MULQ ·inp+0(SB) - MOVQ AX, R9 - MOVQ $0x00, BX - - // | - -/* */ - - // | j0 - - // | w3 @ R10 - MOVQ ·modulus+0(SB), AX - MULQ R9 - ADDQ AX, R10 - ADCQ DX, BX - - // | j1 - - // | w4 @ R11 - MOVQ ·modulus+8(SB), AX - MULQ R9 - ADDQ AX, R11 - ADCQ $0x00, DX - ADDQ BX, R11 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j2 - - // | w5 @ R12 - MOVQ ·modulus+16(SB), AX - MULQ R9 - ADDQ AX, R12 - ADCQ $0x00, DX - ADDQ BX, R12 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j3 - - // | w6 @ R13 - MOVQ ·modulus+24(SB), AX - MULQ R9 - ADDQ AX, R13 - ADCQ $0x00, DX - ADDQ BX, R13 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j4 - - // | w7 @ R14 - MOVQ ·modulus+32(SB), AX - MULQ R9 - ADDQ AX, R14 - ADCQ $0x00, DX - ADDQ BX, R14 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j5 - - // | w8 @ R15 - MOVQ ·modulus+40(SB), AX - MULQ R9 - ADDQ AX, R15 - ADCQ DX, CX - ADDQ BX, R15 - - // | w9 @ R8 - ADCQ CX, R8 - MOVQ $0x00, CX - ADCQ $0x00, CX - - // | - -/* i4 */ - - // | - // | W - // | 0 - | 1 - | 2 - | 3 - | 4 R11 | 5 R12 - // | 6 R13 | 7 R14 | 8 R15 | 9 R8 | 10 8(SP) | 11 (SP) - - - // | | u4 = w4 * inp - MOVQ R11, AX - MULQ ·inp+0(SB) - MOVQ AX, R9 - MOVQ $0x00, BX - - // | - -/* */ - - // | j0 - - // | w4 @ R11 - MOVQ ·modulus+0(SB), AX - MULQ R9 - ADDQ AX, R11 - ADCQ DX, BX - - // | j1 - - // | w5 @ R12 - MOVQ ·modulus+8(SB), AX - MULQ R9 - ADDQ AX, R12 - ADCQ $0x00, DX - ADDQ BX, R12 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j2 - - // | w6 @ R13 - MOVQ ·modulus+16(SB), AX - MULQ R9 - ADDQ AX, R13 - ADCQ $0x00, DX - ADDQ BX, R13 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j3 - - // | w7 @ R14 - MOVQ ·modulus+24(SB), AX - MULQ R9 - ADDQ AX, R14 - ADCQ $0x00, DX - ADDQ BX, R14 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j4 - - // | w8 @ R15 - MOVQ ·modulus+32(SB), AX - MULQ R9 - ADDQ AX, R15 - ADCQ $0x00, DX - ADDQ BX, R15 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j5 - - // | w9 @ R8 - MOVQ ·modulus+40(SB), AX - MULQ R9 - ADDQ AX, R8 - ADCQ DX, CX - ADDQ BX, R8 - - // | move to idle register - MOVQ 8(SP), DI - - // | w10 @ DI - ADCQ CX, DI - MOVQ $0x00, CX - ADCQ $0x00, CX - - // | - -/* i5 */ - - // | - // | W - // | 0 - | 1 - | 2 - | 3 - | 4 - | 5 R12 - // | 6 R13 | 7 R14 | 8 R15 | 9 R8 | 10 DI | 11 (SP) - - - // | | u5 = w5 * inp - MOVQ R12, AX - MULQ ·inp+0(SB) - MOVQ AX, R9 - MOVQ $0x00, BX - - // | - -/* */ - - // | j0 - - // | w5 @ R12 - MOVQ ·modulus+0(SB), AX - MULQ R9 - ADDQ AX, R12 - ADCQ DX, BX - - // | j1 - - // | w6 @ R13 - MOVQ ·modulus+8(SB), AX - MULQ R9 - ADDQ AX, R13 - ADCQ $0x00, DX - ADDQ BX, R13 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j2 - - // | w7 @ R14 - MOVQ ·modulus+16(SB), AX - MULQ R9 - ADDQ AX, R14 - ADCQ $0x00, DX - ADDQ BX, R14 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j3 - - // | w8 @ R15 - MOVQ ·modulus+24(SB), AX - MULQ R9 - ADDQ AX, R15 - ADCQ $0x00, DX - ADDQ BX, R15 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j4 - - // | w9 @ R8 - MOVQ ·modulus+32(SB), AX - MULQ R9 - ADDQ AX, R8 - ADCQ $0x00, DX - ADDQ BX, R8 - MOVQ $0x00, BX - ADCQ DX, BX - - // | j5 - - // | w10 @ DI - MOVQ ·modulus+40(SB), AX - MULQ R9 - ADDQ AX, DI - ADCQ DX, CX - ADDQ BX, DI - - // | w11 @ CX - ADCQ (SP), CX - - // | - // | W montgomerry reduction ends - // | 0 - | 1 - | 2 - | 3 - | 4 - | 5 - - // | 6 R13 | 7 R14 | 8 R15 | 9 R8 | 10 DI | 11 CX - - - // | - - -/* modular reduction */ - - MOVQ R13, R10 - SUBQ ·modulus+0(SB), R10 - MOVQ R14, R11 - SBBQ ·modulus+8(SB), R11 - MOVQ R15, R12 - SBBQ ·modulus+16(SB), R12 - MOVQ R8, AX - SBBQ ·modulus+24(SB), AX - MOVQ DI, BX - SBBQ ·modulus+32(SB), BX - MOVQ CX, R9 - SBBQ ·modulus+40(SB), R9 - // | - -/* out */ - - MOVQ c+0(FP), SI - CMOVQCC R10, R13 - MOVQ R13, (SI) - CMOVQCC R11, R14 - MOVQ R14, 8(SI) - CMOVQCC R12, R15 - MOVQ R15, 16(SI) - CMOVQCC AX, R8 - MOVQ R8, 24(SI) - CMOVQCC BX, DI - MOVQ DI, 32(SI) - CMOVQCC R9, CX - MOVQ CX, 40(SI) - RET - - // | - -/* end */ - - -// multiplication -// c = a * b % p -TEXT ·mulADX(SB), NOSPLIT, $16-24 - // | - -/* inputs */ - - MOVQ a+8(FP), DI - MOVQ b+16(FP), SI - XORQ AX, AX - - // | - -/* i0 */ - - // | a0 @ DX - MOVQ (DI), DX - - // | a0 * b0 - MULXQ (SI), AX, CX - MOVQ AX, (SP) - - // | a0 * b1 - MULXQ 8(SI), AX, R8 - ADCXQ AX, CX - - // | a0 * b2 - MULXQ 16(SI), AX, R9 - ADCXQ AX, R8 - - // | a0 * b3 - MULXQ 24(SI), AX, R10 - ADCXQ AX, R9 - - // | a0 * b4 - MULXQ 32(SI), AX, R11 - ADCXQ AX, R10 - - // | a0 * b5 - MULXQ 40(SI), AX, R12 - ADCXQ AX, R11 - ADCQ $0x00, R12 - - // | - -/* i1 */ - - // | a1 @ DX - MOVQ 8(DI), DX - XORQ R13, R13 - - // | a1 * b0 - MULXQ (SI), AX, BX - ADOXQ AX, CX - ADCXQ BX, R8 - MOVQ CX, 8(SP) - - // | a1 * b1 - MULXQ 8(SI), AX, BX - ADOXQ AX, R8 - ADCXQ BX, R9 - - // | a1 * b2 - MULXQ 16(SI), AX, BX - ADOXQ AX, R9 - ADCXQ BX, R10 - - // | a1 * b3 - MULXQ 24(SI), AX, BX - ADOXQ AX, R10 - ADCXQ BX, R11 - - // | a1 * b4 - MULXQ 32(SI), AX, BX - ADOXQ AX, R11 - ADCXQ BX, R12 - - // | a1 * b5 - MULXQ 40(SI), AX, BX - ADOXQ AX, R12 - ADOXQ R13, R13 - ADCXQ BX, R13 - - // | - -/* i2 */ - - // | a2 @ DX - MOVQ 16(DI), DX - XORQ R14, R14 - - // | a2 * b0 - MULXQ (SI), AX, BX - ADOXQ AX, R8 - ADCXQ BX, R9 - - // | a2 * b1 - MULXQ 8(SI), AX, BX - ADOXQ AX, R9 - ADCXQ BX, R10 - - // | a2 * b2 - MULXQ 16(SI), AX, BX - ADOXQ AX, R10 - ADCXQ BX, R11 - - // | a2 * b3 - MULXQ 24(SI), AX, BX - ADOXQ AX, R11 - ADCXQ BX, R12 - - // | a2 * b4 - MULXQ 32(SI), AX, BX - ADOXQ AX, R12 - ADCXQ BX, R13 - - // | a2 * b5 - MULXQ 40(SI), AX, BX - ADOXQ AX, R13 - ADOXQ R14, R14 - ADCXQ BX, R14 - - // | - -/* i3 */ - - // | a3 @ DX - MOVQ 24(DI), DX - XORQ R15, R15 - - // | a3 * b0 - MULXQ (SI), AX, BX - ADOXQ AX, R9 - ADCXQ BX, R10 - - // | a3 * b1 - MULXQ 8(SI), AX, BX - ADOXQ AX, R10 - ADCXQ BX, R11 - - // | a3 * b2 - MULXQ 16(SI), AX, BX - ADOXQ AX, R11 - ADCXQ BX, R12 - - // | a3 * b3 - MULXQ 24(SI), AX, BX - ADOXQ AX, R12 - ADCXQ BX, R13 - - // | a3 * b4 - MULXQ 32(SI), AX, BX - ADOXQ AX, R13 - ADCXQ BX, R14 - - // | a3 * b5 - MULXQ 40(SI), AX, BX - ADOXQ AX, R14 - ADOXQ R15, R15 - ADCXQ BX, R15 - - // | - -/* i4 */ - - // | a4 @ DX - MOVQ 32(DI), DX - XORQ CX, CX - - // | a4 * b0 - MULXQ (SI), AX, BX - ADOXQ AX, R10 - ADCXQ BX, R11 - - // | a4 * b1 - MULXQ 8(SI), AX, BX - ADOXQ AX, R11 - ADCXQ BX, R12 - - // | a4 * b2 - MULXQ 16(SI), AX, BX - ADOXQ AX, R12 - ADCXQ BX, R13 - - // | a4 * b3 - MULXQ 24(SI), AX, BX - ADOXQ AX, R13 - ADCXQ BX, R14 - - // | a4 * b4 - MULXQ 32(SI), AX, BX - ADOXQ AX, R14 - ADCXQ BX, R15 - - // | a4 * b5 - MULXQ 40(SI), AX, BX - ADOXQ AX, R15 - ADOXQ CX, CX - ADCXQ BX, CX - - // | - -/* i5 */ - - // | a5 @ DX - MOVQ 40(DI), DX - XORQ DI, DI - - // | a5 * b0 - MULXQ (SI), AX, BX - ADOXQ AX, R11 - ADCXQ BX, R12 - - // | a5 * b1 - MULXQ 8(SI), AX, BX - ADOXQ AX, R12 - ADCXQ BX, R13 - - // | a5 * b2 - MULXQ 16(SI), AX, BX - ADOXQ AX, R13 - ADCXQ BX, R14 - - // | a5 * b3 - MULXQ 24(SI), AX, BX - ADOXQ AX, R14 - ADCXQ BX, R15 - - // | a5 * b4 - MULXQ 32(SI), AX, BX - ADOXQ AX, R15 - ADCXQ BX, CX - - // | a5 * b5 - MULXQ 40(SI), AX, BX - ADOXQ AX, CX - ADOXQ BX, DI - ADCQ $0x00, DI - - // | - -/* */ - - // | - // | W - // | 0 (SP) | 1 8(SP) | 2 R8 | 3 R9 | 4 R10 | 5 R11 - // | 6 R12 | 7 R13 | 8 R14 | 9 R15 | 10 CX | 11 DI - - - MOVQ (SP), BX - MOVQ 8(SP), SI - MOVQ DI, (SP) - - // | - // | W ready to mont - // | 0 BX | 1 SI | 2 R8 | 3 R9 | 4 R10 | 5 R11 - // | 6 R12 | 7 R13 | 8 R14 | 9 R15 | 10 CX | 11 (SP) - - - // | - -/* montgomery reduction */ - - // | clear flags - XORQ AX, AX - - // | - -/* i0 */ - - // | - // | W - // | 0 BX | 1 SI | 2 R8 | 3 R9 | 4 R10 | 5 R11 - // | 6 R12 | 7 R13 | 8 R14 | 9 R15 | 10 CX | 11 (SP) - - - // | | u0 = w0 * inp - MOVQ BX, DX - MULXQ ·inp+0(SB), DX, DI - - // | - -/* */ - - // | j0 - - // | w0 @ BX - MULXQ ·modulus+0(SB), AX, DI - ADOXQ AX, BX - ADCXQ DI, SI - - // | j1 - - // | w1 @ SI - MULXQ ·modulus+8(SB), AX, DI - ADOXQ AX, SI - ADCXQ DI, R8 - - // | j2 - - // | w2 @ R8 - MULXQ ·modulus+16(SB), AX, DI - ADOXQ AX, R8 - ADCXQ DI, R9 - - // | j3 - - // | w3 @ R9 - MULXQ ·modulus+24(SB), AX, DI - ADOXQ AX, R9 - ADCXQ DI, R10 - - // | j4 - - // | w4 @ R10 - MULXQ ·modulus+32(SB), AX, DI - ADOXQ AX, R10 - ADCXQ DI, R11 - - // | j5 - - // | w5 @ R11 - MULXQ ·modulus+40(SB), AX, DI - ADOXQ AX, R11 - ADCXQ DI, R12 - ADOXQ BX, R12 - ADCXQ BX, BX - MOVQ $0x00, AX - ADOXQ AX, BX - - // | clear flags - XORQ AX, AX - - // | - -/* i1 */ - - // | - // | W - // | 0 - | 1 SI | 2 R8 | 3 R9 | 4 R10 | 5 R11 - // | 6 R12 | 7 R13 | 8 R14 | 9 R15 | 10 CX | 11 (SP) - - - // | | u1 = w1 * inp - MOVQ SI, DX - MULXQ ·inp+0(SB), DX, DI - - // | - -/* */ - - // | j0 - - // | w1 @ SI - MULXQ ·modulus+0(SB), AX, DI - ADOXQ AX, SI - ADCXQ DI, R8 - - // | j1 - - // | w2 @ R8 - MULXQ ·modulus+8(SB), AX, DI - ADOXQ AX, R8 - ADCXQ DI, R9 - - // | j2 - - // | w3 @ R9 - MULXQ ·modulus+16(SB), AX, DI - ADOXQ AX, R9 - ADCXQ DI, R10 - - // | j3 - - // | w4 @ R10 - MULXQ ·modulus+24(SB), AX, DI - ADOXQ AX, R10 - ADCXQ DI, R11 - - // | j4 - - // | w5 @ R11 - MULXQ ·modulus+32(SB), AX, DI - ADOXQ AX, R11 - ADCXQ DI, R12 - - // | j5 - - // | w6 @ R12 - MULXQ ·modulus+40(SB), AX, DI - ADOXQ AX, R12 - ADCXQ DI, R13 - ADOXQ BX, R13 - ADCXQ SI, SI - MOVQ $0x00, AX - ADOXQ AX, SI - - // | clear flags - XORQ AX, AX - - // | - -/* i2 */ - - // | - // | W - // | 0 - | 1 - | 2 R8 | 3 R9 | 4 R10 | 5 R11 - // | 6 R12 | 7 R13 | 8 R14 | 9 R15 | 10 CX | 11 (SP) - - - // | | u2 = w2 * inp - MOVQ R8, DX - MULXQ ·inp+0(SB), DX, DI - - // | - -/* */ - - // | j0 - - // | w2 @ R8 - MULXQ ·modulus+0(SB), AX, DI - ADOXQ AX, R8 - ADCXQ DI, R9 - - // | j1 - - // | w3 @ R9 - MULXQ ·modulus+8(SB), AX, DI - ADOXQ AX, R9 - ADCXQ DI, R10 - - // | j2 - - // | w4 @ R10 - MULXQ ·modulus+16(SB), AX, DI - ADOXQ AX, R10 - ADCXQ DI, R11 - - // | j3 - - // | w5 @ R11 - MULXQ ·modulus+24(SB), AX, DI - ADOXQ AX, R11 - ADCXQ DI, R12 - - // | j4 - - // | w6 @ R12 - MULXQ ·modulus+32(SB), AX, DI - ADOXQ AX, R12 - ADCXQ DI, R13 - - // | j5 - - // | w7 @ R13 - MULXQ ·modulus+40(SB), AX, DI - ADOXQ AX, R13 - ADCXQ DI, R14 - ADOXQ SI, R14 - ADCXQ R8, R8 - MOVQ $0x00, AX - ADOXQ AX, R8 - - // | clear flags - XORQ AX, AX - - // | - -/* i3 */ - - // | - // | W - // | 0 - | 1 - | 2 - | 3 R9 | 4 R10 | 5 R11 - // | 6 R12 | 7 R13 | 8 R14 | 9 R15 | 10 CX | 11 (SP) - - - // | | u3 = w3 * inp - MOVQ R9, DX - MULXQ ·inp+0(SB), DX, DI - - // | - -/* */ - - // | j0 - - // | w3 @ R9 - MULXQ ·modulus+0(SB), AX, DI - ADOXQ AX, R9 - ADCXQ DI, R10 - - // | j1 - - // | w4 @ R10 - MULXQ ·modulus+8(SB), AX, DI - ADOXQ AX, R10 - ADCXQ DI, R11 - - // | j2 - - // | w5 @ R11 - MULXQ ·modulus+16(SB), AX, DI - ADOXQ AX, R11 - ADCXQ DI, R12 - - // | j3 - - // | w6 @ R12 - MULXQ ·modulus+24(SB), AX, DI - ADOXQ AX, R12 - ADCXQ DI, R13 - - // | j4 - - // | w7 @ R13 - MULXQ ·modulus+32(SB), AX, DI - ADOXQ AX, R13 - ADCXQ DI, R14 - - // | j5 - - // | w8 @ R14 - MULXQ ·modulus+40(SB), AX, DI - ADOXQ AX, R14 - ADCXQ DI, R15 - ADOXQ R8, R15 - ADCXQ R9, R9 - MOVQ $0x00, AX - ADOXQ AX, R9 - - // | clear flags - XORQ AX, AX - - // | - -/* i4 */ - - // | - // | W - // | 0 - | 1 - | 2 - | 3 - | 4 R10 | 5 R11 - // | 6 R12 | 7 R13 | 8 R14 | 9 R15 | 10 CX | 11 (SP) - - - // | | u4 = w4 * inp - MOVQ R10, DX - MULXQ ·inp+0(SB), DX, DI - - // | - -/* */ - - // | j0 - - // | w4 @ R10 - MULXQ ·modulus+0(SB), AX, DI - ADOXQ AX, R10 - ADCXQ DI, R11 - - // | j1 - - // | w5 @ R11 - MULXQ ·modulus+8(SB), AX, DI - ADOXQ AX, R11 - ADCXQ DI, R12 - - // | j2 - - // | w6 @ R12 - MULXQ ·modulus+16(SB), AX, DI - ADOXQ AX, R12 - ADCXQ DI, R13 - - // | j3 - - // | w7 @ R13 - MULXQ ·modulus+24(SB), AX, DI - ADOXQ AX, R13 - ADCXQ DI, R14 - - // | j4 - - // | w8 @ R14 - MULXQ ·modulus+32(SB), AX, DI - ADOXQ AX, R14 - ADCXQ DI, R15 - - // | j5 - - // | w9 @ R15 - MULXQ ·modulus+40(SB), AX, DI - ADOXQ AX, R15 - ADCXQ DI, CX - ADOXQ R9, CX - ADCXQ R10, R10 - MOVQ $0x00, AX - ADOXQ AX, R10 - - // | clear flags - XORQ AX, AX - - // | - -/* i5 */ - - // | - // | W - // | 0 - | 1 - | 2 - | 3 - | 4 - | 5 R11 - // | 6 R12 | 7 R13 | 8 R14 | 9 R15 | 10 CX | 11 (SP) - - - // | | u5 = w5 * inp - MOVQ R11, DX - MULXQ ·inp+0(SB), DX, DI - - // | - -/* */ - - // | j0 - - // | w5 @ R11 - MULXQ ·modulus+0(SB), AX, DI - ADOXQ AX, R11 - ADCXQ DI, R12 - - // | j1 - - // | w6 @ R12 - MULXQ ·modulus+8(SB), AX, DI - ADOXQ AX, R12 - ADCXQ DI, R13 - - // | j2 - - // | w7 @ R13 - MULXQ ·modulus+16(SB), AX, DI - ADOXQ AX, R13 - ADCXQ DI, R14 - - // | j3 - - // | w8 @ R14 - MULXQ ·modulus+24(SB), AX, DI - ADOXQ AX, R14 - ADCXQ DI, R15 - - // | j4 - - // | w9 @ R15 - MULXQ ·modulus+32(SB), AX, DI - ADOXQ AX, R15 - ADCXQ DI, CX - - // | j5 - - // | w10 @ CX - MULXQ ·modulus+40(SB), AX, DI - ADOXQ AX, CX - - // | w11 @ (SP) - // | move to an idle register - MOVQ (SP), BX - ADCXQ DI, BX - ADOXQ R10, BX - - // | - // | W montgomery reduction ends - // | 0 - | 1 - | 2 - | 3 - | 4 - | 5 - - // | 6 R12 | 7 R13 | 8 R14 | 9 R15 | 10 CX | 11 BX - - - // | - -/* modular reduction */ - - MOVQ R12, AX - SUBQ ·modulus+0(SB), AX - MOVQ R13, DI - SBBQ ·modulus+8(SB), DI - MOVQ R14, SI - SBBQ ·modulus+16(SB), SI - MOVQ R15, R8 - SBBQ ·modulus+24(SB), R8 - MOVQ CX, R9 - SBBQ ·modulus+32(SB), R9 - MOVQ BX, R10 - SBBQ ·modulus+40(SB), R10 - - // | - -/* out */ - - MOVQ c+0(FP), R11 - CMOVQCC AX, R12 - MOVQ R12, (R11) - CMOVQCC DI, R13 - MOVQ R13, 8(R11) - CMOVQCC SI, R14 - MOVQ R14, 16(R11) - CMOVQCC R8, R15 - MOVQ R15, 24(R11) - CMOVQCC R9, CX - MOVQ CX, 32(R11) - CMOVQCC R10, BX - MOVQ BX, 40(R11) - RET - - // | - -/* end */ diff --git a/crypto/bls12381/arithmetic_x86_adx.go b/crypto/bls12381/arithmetic_x86_adx.go deleted file mode 100644 index a40c7384eb57..000000000000 --- a/crypto/bls12381/arithmetic_x86_adx.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2020 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 . - -//go:build amd64 && blsadx -// +build amd64,blsadx - -package bls12381 - -// enableADX is true if the ADX/BMI2 instruction set was requested for the BLS -// implementation. The system may still fall back to plain ASM if the necessary -// instructions are unavailable on the CPU. -const enableADX = true diff --git a/crypto/bls12381/arithmetic_x86_noadx.go b/crypto/bls12381/arithmetic_x86_noadx.go deleted file mode 100644 index 679b30ec8c3a..000000000000 --- a/crypto/bls12381/arithmetic_x86_noadx.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2020 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 . - -//go:build amd64 && blsasm -// +build amd64,blsasm - -package bls12381 - -// enableADX is true if the ADX/BMI2 instruction set was requested for the BLS -// implementation. The system may still fall back to plain ASM if the necessary -// instructions are unavailable on the CPU. -const enableADX = false diff --git a/crypto/bls12381/bls12_381.go b/crypto/bls12381/bls12_381.go deleted file mode 100644 index 1c1c97765f47..000000000000 --- a/crypto/bls12381/bls12_381.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2020 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 bls12381 - -/* - Field Constants -*/ - -// Base field modulus -// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab - -// Size of six words -// r = 2 ^ 384 - -// modulus = p -var modulus = fe{0xb9feffffffffaaab, 0x1eabfffeb153ffff, 0x6730d2a0f6b0f624, 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a} - -var ( - // -p^(-1) mod 2^64 - inp uint64 = 0x89f3fffcfffcfffd - // This value is used in assembly code - _ = inp -) - -// r mod p -var r1 = &fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493} - -// r^2 mod p -var r2 = &fe{ - 0xf4df1f341c341746, 0x0a76e6a609d104f1, 0x8de5476c4c95b6d5, 0x67eb88a9939d83c0, 0x9a793e85b519952d, 0x11988fe592cae3aa, -} - -// -1 + 0 * u -var negativeOne2 = &fe2{ - fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, -} - -// 2 ^ (-1) -var twoInv = &fe{0x1804000000015554, 0x855000053ab00001, 0x633cb57c253c276f, 0x6e22d1ec31ebb502, 0xd3916126f2d14ca2, 0x17fbb8571a006596} - -// (p - 3) / 4 -var pMinus3Over4 = bigFromHex("0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaaa") - -// (p + 1) / 4 -var pPlus1Over4 = bigFromHex("0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaab") - -// (p - 1) / 2 -var pMinus1Over2 = bigFromHex("0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd555") - -// -1 -var nonResidue1 = &fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206} - -// (1 + 1 * u) -var nonResidue2 = &fe2{ - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, -} - -/* - Curve Constants -*/ - -// b coefficient for G1 -var b = &fe{0xaa270000000cfff3, 0x53cc0032fc34000a, 0x478fe97a6b0a807f, 0xb1d37ebee6ba24d7, 0x8ec9733bbf78ab2f, 0x09d645513d83de7e} - -// b coefficient for G2 -var b2 = &fe2{ - fe{0xaa270000000cfff3, 0x53cc0032fc34000a, 0x478fe97a6b0a807f, 0xb1d37ebee6ba24d7, 0x8ec9733bbf78ab2f, 0x09d645513d83de7e}, - fe{0xaa270000000cfff3, 0x53cc0032fc34000a, 0x478fe97a6b0a807f, 0xb1d37ebee6ba24d7, 0x8ec9733bbf78ab2f, 0x09d645513d83de7e}, -} - -// Curve order -var q = bigFromHex("0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001") - -// Efficient cofactor of G1 -var cofactorEFFG1 = bigFromHex("0xd201000000010001") - -// Efficient cofactor of G2 -var cofactorEFFG2 = bigFromHex("0x0bc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551") - -var g1One = PointG1{ - fe{0x5cb38790fd530c16, 0x7817fc679976fff5, 0x154f95c7143ba1c1, 0xf0ae6acdf3d0e747, 0xedce6ecc21dbf440, 0x120177419e0bfb75}, - fe{0xbaac93d50ce72271, 0x8c22631a7918fd8e, 0xdd595f13570725ce, 0x51ac582950405194, 0x0e1c8c3fad0059c0, 0x0bbc3efc5008a26a}, - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, -} - -var g2One = PointG2{ - fe2{ - fe{0xf5f28fa202940a10, 0xb3f5fb2687b4961a, 0xa1a893b53e2ae580, 0x9894999d1a3caee9, 0x6f67b7631863366b, 0x058191924350bcd7}, - fe{0xa5a9c0759e23f606, 0xaaa0c59dbccd60c3, 0x3bb17e18e2867806, 0x1b1ab6cc8541b367, 0xc2b6ed0ef2158547, 0x11922a097360edf3}, - }, - fe2{ - fe{0x4c730af860494c4a, 0x597cfa1f5e369c5a, 0xe7e6856caa0a635a, 0xbbefb5e96e0d495f, 0x07d3a975f0ef25a2, 0x083fd8e7e80dae5}, - fe{0xadc0fc92df64b05d, 0x18aa270a2b1461dc, 0x86adac6a3be4eba0, 0x79495c4ec93da33a, 0xe7175850a43ccaed, 0xb2bc2a163de1bf2}, - }, - fe2{ - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, -} - -/* - Frobenious Coeffs -*/ - -var frobeniusCoeffs61 = [6]fe2{ - { - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741}, - }, - { - fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - }, - { - fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160}, - }, -} - -var frobeniusCoeffs62 = [6]fe2{ - { - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x890dc9e4867545c3, 0x2af322533285a5d5, 0x50880866309b7e2c, 0xa20d1b8c7e881024, 0x14e4f04fe2db9068, 0x14e56d3f1564853a}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0xecfb361b798dba3a, 0xc100ddb891865a2c, 0x0ec08ff1232bda8e, 0xd5c13cc6f1ca4721, 0x47222a47bf7b5c04, 0x0110f184e51c5f59}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, -} - -var frobeniusCoeffs12 = [12]fe2{ - { - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x07089552b319d465, 0xc6695f92b50a8313, 0x97e83cccd117228f, 0xa35baecab2dc29ee, 0x1ce393ea5daace4d, 0x08f2220fb0fb66eb}, - fe{0xb2f66aad4ce5d646, 0x5842a06bfc497cec, 0xcf4895d42599d394, 0xc11b9cba40a8e8d0, 0x2e3813cbe5a0de89, 0x110eefda88847faf}, - }, - { - fe{0xecfb361b798dba3a, 0xc100ddb891865a2c, 0x0ec08ff1232bda8e, 0xd5c13cc6f1ca4721, 0x47222a47bf7b5c04, 0x0110f184e51c5f59}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0x0bd592fc7d825ec8}, - fe{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2}, - }, - { - fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x3726c30af242c66c, 0x7c2ac1aad1b6fe70, 0xa04007fbba4b14a2, 0xef517c3266341429, 0x0095ba654ed2226b, 0x02e370eccc86f7dd}, - fe{0x82d83cf50dbce43f, 0xa2813e53df9d018f, 0xc6f0caa53c65e181, 0x7525cf528d50fe95, 0x4a85ed50f4798a6b, 0x171da0fd6cf8eebd}, - }, - { - fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0xb2f66aad4ce5d646, 0x5842a06bfc497cec, 0xcf4895d42599d394, 0xc11b9cba40a8e8d0, 0x2e3813cbe5a0de89, 0x110eefda88847faf}, - fe{0x07089552b319d465, 0xc6695f92b50a8313, 0x97e83cccd117228f, 0xa35baecab2dc29ee, 0x1ce393ea5daace4d, 0x08f2220fb0fb66eb}, - }, - { - fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2}, - fe{0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0x0bd592fc7d825ec8}, - }, - { - fe{0x890dc9e4867545c3, 0x2af322533285a5d5, 0x50880866309b7e2c, 0xa20d1b8c7e881024, 0x14e4f04fe2db9068, 0x14e56d3f1564853a}, - fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, - }, - { - fe{0x82d83cf50dbce43f, 0xa2813e53df9d018f, 0xc6f0caa53c65e181, 0x7525cf528d50fe95, 0x4a85ed50f4798a6b, 0x171da0fd6cf8eebd}, - fe{0x3726c30af242c66c, 0x7c2ac1aad1b6fe70, 0xa04007fbba4b14a2, 0xef517c3266341429, 0x0095ba654ed2226b, 0x02e370eccc86f7dd}, - }, -} - -/* - x -*/ - -var x = bigFromHex("0xd201000000010000") diff --git a/crypto/bls12381/bls12_381_test.go b/crypto/bls12381/bls12_381_test.go deleted file mode 100644 index 6bf583410594..000000000000 --- a/crypto/bls12381/bls12_381_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package bls12381 - -import ( - "crypto/rand" - "math/big" -) - -var fuz = 10 - -func randScalar(max *big.Int) *big.Int { - a, _ := rand.Int(rand.Reader, max) - return a -} diff --git a/crypto/bls12381/field_element.go b/crypto/bls12381/field_element.go deleted file mode 100644 index 9fdddc618435..000000000000 --- a/crypto/bls12381/field_element.go +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright 2020 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 bls12381 - -import ( - "crypto/rand" - "encoding/hex" - "fmt" - "io" - "math/big" -) - -// fe is base field element representation -type fe [6]uint64 - -// fe2 is element representation of 'fp2' which is quadratic extension of base field 'fp' -// Representation follows c[0] + c[1] * u encoding order. -type fe2 [2]fe - -// fe6 is element representation of 'fp6' field which is cubic extension of 'fp2' -// Representation follows c[0] + c[1] * v + c[2] * v^2 encoding order. -type fe6 [3]fe2 - -// fe12 is element representation of 'fp12' field which is quadratic extension of 'fp6' -// Representation follows c[0] + c[1] * w encoding order. -type fe12 [2]fe6 - -func (fe *fe) setBytes(in []byte) *fe { - size := 48 - l := len(in) - if l >= size { - l = size - } - padded := make([]byte, size) - copy(padded[size-l:], in[:]) - var a int - for i := 0; i < 6; i++ { - a = size - i*8 - fe[i] = uint64(padded[a-1]) | uint64(padded[a-2])<<8 | - uint64(padded[a-3])<<16 | uint64(padded[a-4])<<24 | - uint64(padded[a-5])<<32 | uint64(padded[a-6])<<40 | - uint64(padded[a-7])<<48 | uint64(padded[a-8])<<56 - } - return fe -} - -func (fe *fe) setBig(a *big.Int) *fe { - return fe.setBytes(a.Bytes()) -} - -func (fe *fe) setString(s string) (*fe, error) { - if s[:2] == "0x" { - s = s[2:] - } - bytes, err := hex.DecodeString(s) - if err != nil { - return nil, err - } - return fe.setBytes(bytes), nil -} - -func (fe *fe) set(fe2 *fe) *fe { - fe[0] = fe2[0] - fe[1] = fe2[1] - fe[2] = fe2[2] - fe[3] = fe2[3] - fe[4] = fe2[4] - fe[5] = fe2[5] - return fe -} - -func (fe *fe) bytes() []byte { - out := make([]byte, 48) - var a int - for i := 0; i < 6; i++ { - a = 48 - i*8 - out[a-1] = byte(fe[i]) - out[a-2] = byte(fe[i] >> 8) - out[a-3] = byte(fe[i] >> 16) - out[a-4] = byte(fe[i] >> 24) - out[a-5] = byte(fe[i] >> 32) - out[a-6] = byte(fe[i] >> 40) - out[a-7] = byte(fe[i] >> 48) - out[a-8] = byte(fe[i] >> 56) - } - return out -} - -func (fe *fe) big() *big.Int { - return new(big.Int).SetBytes(fe.bytes()) -} - -func (fe *fe) string() (s string) { - for i := 5; i >= 0; i-- { - s = fmt.Sprintf("%s%16.16x", s, fe[i]) - } - return "0x" + s -} - -func (fe *fe) zero() *fe { - fe[0] = 0 - fe[1] = 0 - fe[2] = 0 - fe[3] = 0 - fe[4] = 0 - fe[5] = 0 - return fe -} - -func (fe *fe) one() *fe { - return fe.set(r1) -} - -func (fe *fe) rand(r io.Reader) (*fe, error) { - bi, err := rand.Int(r, modulus.big()) - if err != nil { - return nil, err - } - return fe.setBig(bi), nil -} - -func (fe *fe) isValid() bool { - return fe.cmp(&modulus) < 0 -} - -func (fe *fe) isOdd() bool { - var mask uint64 = 1 - return fe[0]&mask != 0 -} - -func (fe *fe) isEven() bool { - var mask uint64 = 1 - return fe[0]&mask == 0 -} - -func (fe *fe) isZero() bool { - return (fe[5] | fe[4] | fe[3] | fe[2] | fe[1] | fe[0]) == 0 -} - -func (fe *fe) isOne() bool { - return fe.equal(r1) -} - -func (fe *fe) cmp(fe2 *fe) int { - for i := 5; i >= 0; i-- { - if fe[i] > fe2[i] { - return 1 - } else if fe[i] < fe2[i] { - return -1 - } - } - return 0 -} - -func (fe *fe) equal(fe2 *fe) bool { - return fe2[0] == fe[0] && fe2[1] == fe[1] && fe2[2] == fe[2] && fe2[3] == fe[3] && fe2[4] == fe[4] && fe2[5] == fe[5] -} - -func (e *fe) sign() bool { - r := new(fe) - fromMont(r, e) - return r[0]&1 == 0 -} - -func (fe *fe) div2(e uint64) { - fe[0] = fe[0]>>1 | fe[1]<<63 - fe[1] = fe[1]>>1 | fe[2]<<63 - fe[2] = fe[2]>>1 | fe[3]<<63 - fe[3] = fe[3]>>1 | fe[4]<<63 - fe[4] = fe[4]>>1 | fe[5]<<63 - fe[5] = fe[5]>>1 | e<<63 -} - -func (fe *fe) mul2() uint64 { - e := fe[5] >> 63 - fe[5] = fe[5]<<1 | fe[4]>>63 - fe[4] = fe[4]<<1 | fe[3]>>63 - fe[3] = fe[3]<<1 | fe[2]>>63 - fe[2] = fe[2]<<1 | fe[1]>>63 - fe[1] = fe[1]<<1 | fe[0]>>63 - fe[0] = fe[0] << 1 - return e -} - -func (e *fe2) zero() *fe2 { - e[0].zero() - e[1].zero() - return e -} - -func (e *fe2) one() *fe2 { - e[0].one() - e[1].zero() - return e -} - -func (e *fe2) set(e2 *fe2) *fe2 { - e[0].set(&e2[0]) - e[1].set(&e2[1]) - return e -} - -func (e *fe2) rand(r io.Reader) (*fe2, error) { - a0, err := new(fe).rand(r) - if err != nil { - return nil, err - } - a1, err := new(fe).rand(r) - if err != nil { - return nil, err - } - return &fe2{*a0, *a1}, nil -} - -func (e *fe2) isOne() bool { - return e[0].isOne() && e[1].isZero() -} - -func (e *fe2) isZero() bool { - return e[0].isZero() && e[1].isZero() -} - -func (e *fe2) equal(e2 *fe2) bool { - return e[0].equal(&e2[0]) && e[1].equal(&e2[1]) -} - -func (e *fe2) sign() bool { - r := new(fe) - if !e[0].isZero() { - fromMont(r, &e[0]) - return r[0]&1 == 0 - } - fromMont(r, &e[1]) - return r[0]&1 == 0 -} - -func (e *fe6) zero() *fe6 { - e[0].zero() - e[1].zero() - e[2].zero() - return e -} - -func (e *fe6) one() *fe6 { - e[0].one() - e[1].zero() - e[2].zero() - return e -} - -func (e *fe6) set(e2 *fe6) *fe6 { - e[0].set(&e2[0]) - e[1].set(&e2[1]) - e[2].set(&e2[2]) - return e -} - -func (e *fe6) rand(r io.Reader) (*fe6, error) { - a0, err := new(fe2).rand(r) - if err != nil { - return nil, err - } - a1, err := new(fe2).rand(r) - if err != nil { - return nil, err - } - a2, err := new(fe2).rand(r) - if err != nil { - return nil, err - } - return &fe6{*a0, *a1, *a2}, nil -} - -func (e *fe6) isOne() bool { - return e[0].isOne() && e[1].isZero() && e[2].isZero() -} - -func (e *fe6) isZero() bool { - return e[0].isZero() && e[1].isZero() && e[2].isZero() -} - -func (e *fe6) equal(e2 *fe6) bool { - return e[0].equal(&e2[0]) && e[1].equal(&e2[1]) && e[2].equal(&e2[2]) -} - -func (e *fe12) zero() *fe12 { - e[0].zero() - e[1].zero() - return e -} - -func (e *fe12) one() *fe12 { - e[0].one() - e[1].zero() - return e -} - -func (e *fe12) set(e2 *fe12) *fe12 { - e[0].set(&e2[0]) - e[1].set(&e2[1]) - return e -} - -func (e *fe12) rand(r io.Reader) (*fe12, error) { - a0, err := new(fe6).rand(r) - if err != nil { - return nil, err - } - a1, err := new(fe6).rand(r) - if err != nil { - return nil, err - } - return &fe12{*a0, *a1}, nil -} - -func (e *fe12) isOne() bool { - return e[0].isOne() && e[1].isZero() -} - -func (e *fe12) isZero() bool { - return e[0].isZero() && e[1].isZero() -} - -func (e *fe12) equal(e2 *fe12) bool { - return e[0].equal(&e2[0]) && e[1].equal(&e2[1]) -} diff --git a/crypto/bls12381/field_element_test.go b/crypto/bls12381/field_element_test.go deleted file mode 100644 index 70bbe5cfe5e7..000000000000 --- a/crypto/bls12381/field_element_test.go +++ /dev/null @@ -1,250 +0,0 @@ -package bls12381 - -import ( - "bytes" - "crypto/rand" - "math/big" - "testing" -) - -func TestFieldElementValidation(t *testing.T) { - zero := new(fe).zero() - if !zero.isValid() { - t.Fatal("zero must be valid") - } - one := new(fe).one() - if !one.isValid() { - t.Fatal("one must be valid") - } - if modulus.isValid() { - t.Fatal("modulus must be invalid") - } - n := modulus.big() - n.Add(n, big.NewInt(1)) - if new(fe).setBig(n).isValid() { - t.Fatal("number greater than modulus must be invalid") - } -} - -func TestFieldElementEquality(t *testing.T) { - // fe - zero := new(fe).zero() - if !zero.equal(zero) { - t.Fatal("0 == 0") - } - one := new(fe).one() - if !one.equal(one) { - t.Fatal("1 == 1") - } - a, _ := new(fe).rand(rand.Reader) - if !a.equal(a) { - t.Fatal("a == a") - } - b := new(fe) - add(b, a, one) - if a.equal(b) { - t.Fatal("a != a + 1") - } - // fe2 - zero2 := new(fe2).zero() - if !zero2.equal(zero2) { - t.Fatal("0 == 0") - } - one2 := new(fe2).one() - if !one2.equal(one2) { - t.Fatal("1 == 1") - } - a2, _ := new(fe2).rand(rand.Reader) - if !a2.equal(a2) { - t.Fatal("a == a") - } - b2 := new(fe2) - fp2 := newFp2() - fp2.add(b2, a2, one2) - if a2.equal(b2) { - t.Fatal("a != a + 1") - } - // fe6 - zero6 := new(fe6).zero() - if !zero6.equal(zero6) { - t.Fatal("0 == 0") - } - one6 := new(fe6).one() - if !one6.equal(one6) { - t.Fatal("1 == 1") - } - a6, _ := new(fe6).rand(rand.Reader) - if !a6.equal(a6) { - t.Fatal("a == a") - } - b6 := new(fe6) - fp6 := newFp6(fp2) - fp6.add(b6, a6, one6) - if a6.equal(b6) { - t.Fatal("a != a + 1") - } - // fe12 - zero12 := new(fe12).zero() - if !zero12.equal(zero12) { - t.Fatal("0 == 0") - } - one12 := new(fe12).one() - if !one12.equal(one12) { - t.Fatal("1 == 1") - } - a12, _ := new(fe12).rand(rand.Reader) - if !a12.equal(a12) { - t.Fatal("a == a") - } - b12 := new(fe12) - fp12 := newFp12(fp6) - fp12.add(b12, a12, one12) - if a12.equal(b12) { - t.Fatal("a != a + 1") - } -} - -func TestFieldElementHelpers(t *testing.T) { - // fe - zero := new(fe).zero() - if !zero.isZero() { - t.Fatal("'zero' is not zero") - } - one := new(fe).one() - if !one.isOne() { - t.Fatal("'one' is not one") - } - odd := new(fe).setBig(big.NewInt(1)) - if !odd.isOdd() { - t.Fatal("1 must be odd") - } - if odd.isEven() { - t.Fatal("1 must not be even") - } - even := new(fe).setBig(big.NewInt(2)) - if !even.isEven() { - t.Fatal("2 must be even") - } - if even.isOdd() { - t.Fatal("2 must not be odd") - } - // fe2 - zero2 := new(fe2).zero() - if !zero2.isZero() { - t.Fatal("'zero' is not zero, 2") - } - one2 := new(fe2).one() - if !one2.isOne() { - t.Fatal("'one' is not one, 2") - } - // fe6 - zero6 := new(fe6).zero() - if !zero6.isZero() { - t.Fatal("'zero' is not zero, 6") - } - one6 := new(fe6).one() - if !one6.isOne() { - t.Fatal("'one' is not one, 6") - } - // fe12 - zero12 := new(fe12).zero() - if !zero12.isZero() { - t.Fatal("'zero' is not zero, 12") - } - one12 := new(fe12).one() - if !one12.isOne() { - t.Fatal("'one' is not one, 12") - } -} - -func TestFieldElementSerialization(t *testing.T) { - t.Run("zero", func(t *testing.T) { - in := make([]byte, 48) - fe := new(fe).setBytes(in) - if !fe.isZero() { - t.Fatal("bad serialization") - } - if !bytes.Equal(in, fe.bytes()) { - t.Fatal("bad serialization") - } - }) - t.Run("bytes", func(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b := new(fe).setBytes(a.bytes()) - if !a.equal(b) { - t.Fatal("bad serialization") - } - } - }) - t.Run("big", func(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b := new(fe).setBig(a.big()) - if !a.equal(b) { - t.Fatal("bad encoding or decoding") - } - } - }) - t.Run("string", func(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b, err := new(fe).setString(a.string()) - if err != nil { - t.Fatal(err) - } - if !a.equal(b) { - t.Fatal("bad encoding or decoding") - } - } - }) -} - -func TestFieldElementByteInputs(t *testing.T) { - zero := new(fe).zero() - in := make([]byte, 0) - a := new(fe).setBytes(in) - if !a.equal(zero) { - t.Fatal("bad serialization") - } - in = make([]byte, 48) - a = new(fe).setBytes(in) - if !a.equal(zero) { - t.Fatal("bad serialization") - } - in = make([]byte, 64) - a = new(fe).setBytes(in) - if !a.equal(zero) { - t.Fatal("bad serialization") - } - in = make([]byte, 49) - in[47] = 1 - normalOne := &fe{1, 0, 0, 0, 0, 0} - a = new(fe).setBytes(in) - if !a.equal(normalOne) { - t.Fatal("bad serialization") - } -} - -func TestFieldElementCopy(t *testing.T) { - a, _ := new(fe).rand(rand.Reader) - b := new(fe).set(a) - if !a.equal(b) { - t.Fatal("bad copy, 1") - } - a2, _ := new(fe2).rand(rand.Reader) - b2 := new(fe2).set(a2) - if !a2.equal(b2) { - t.Fatal("bad copy, 2") - } - a6, _ := new(fe6).rand(rand.Reader) - b6 := new(fe6).set(a6) - if !a6.equal(b6) { - t.Fatal("bad copy, 6") - } - a12, _ := new(fe12).rand(rand.Reader) - b12 := new(fe12).set(a12) - if !a12.equal(b12) { - t.Fatal("bad copy, 12") - } -} diff --git a/crypto/bls12381/fp.go b/crypto/bls12381/fp.go deleted file mode 100644 index 09f6f49bc011..000000000000 --- a/crypto/bls12381/fp.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2020 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 bls12381 - -import ( - "errors" - "math/big" -) - -func fromBytes(in []byte) (*fe, error) { - fe := &fe{} - if len(in) != 48 { - return nil, errors.New("input string should be equal 48 bytes") - } - fe.setBytes(in) - if !fe.isValid() { - return nil, errors.New("must be less than modulus") - } - toMont(fe, fe) - return fe, nil -} - -func fromBig(in *big.Int) (*fe, error) { - fe := new(fe).setBig(in) - if !fe.isValid() { - return nil, errors.New("invalid input string") - } - toMont(fe, fe) - return fe, nil -} - -func fromString(in string) (*fe, error) { - fe, err := new(fe).setString(in) - if err != nil { - return nil, err - } - if !fe.isValid() { - return nil, errors.New("invalid input string") - } - toMont(fe, fe) - return fe, nil -} - -func toBytes(e *fe) []byte { - e2 := new(fe) - fromMont(e2, e) - return e2.bytes() -} - -func toBig(e *fe) *big.Int { - e2 := new(fe) - fromMont(e2, e) - return e2.big() -} - -func toString(e *fe) (s string) { - e2 := new(fe) - fromMont(e2, e) - return e2.string() -} - -func toMont(c, a *fe) { - mul(c, a, r2) -} - -func fromMont(c, a *fe) { - mul(c, a, &fe{1}) -} - -func exp(c, a *fe, e *big.Int) { - z := new(fe).set(r1) - for i := e.BitLen(); i >= 0; i-- { - mul(z, z, z) - if e.Bit(i) == 1 { - mul(z, z, a) - } - } - c.set(z) -} - -func inverse(inv, e *fe) { - if e.isZero() { - inv.zero() - return - } - u := new(fe).set(&modulus) - v := new(fe).set(e) - s := &fe{1} - r := &fe{0} - var k int - var z uint64 - var found = false - // Phase 1 - for i := 0; i < 768; i++ { - if v.isZero() { - found = true - break - } - if u.isEven() { - u.div2(0) - s.mul2() - } else if v.isEven() { - v.div2(0) - z += r.mul2() - } else if u.cmp(v) == 1 { - lsubAssign(u, v) - u.div2(0) - laddAssign(r, s) - s.mul2() - } else { - lsubAssign(v, u) - v.div2(0) - laddAssign(s, r) - z += r.mul2() - } - k += 1 - } - - if !found { - inv.zero() - return - } - - if k < 381 || k > 381+384 { - inv.zero() - return - } - - if r.cmp(&modulus) != -1 || z > 0 { - lsubAssign(r, &modulus) - } - u.set(&modulus) - lsubAssign(u, r) - - // Phase 2 - for i := k; i < 384*2; i++ { - double(u, u) - } - inv.set(u) -} - -func sqrt(c, a *fe) bool { - u, v := new(fe).set(a), new(fe) - exp(c, a, pPlus1Over4) - square(v, c) - return u.equal(v) -} - -func isQuadraticNonResidue(elem *fe) bool { - result := new(fe) - exp(result, elem, pMinus1Over2) - return !result.isOne() -} diff --git a/crypto/bls12381/fp12.go b/crypto/bls12381/fp12.go deleted file mode 100644 index 51e949fe5f04..000000000000 --- a/crypto/bls12381/fp12.go +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2020 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 bls12381 - -import ( - "errors" - "math/big" -) - -type fp12 struct { - fp12temp - fp6 *fp6 -} - -type fp12temp struct { - t2 [9]*fe2 - t6 [5]*fe6 - t12 *fe12 -} - -func newFp12Temp() fp12temp { - t2 := [9]*fe2{} - t6 := [5]*fe6{} - for i := 0; i < len(t2); i++ { - t2[i] = &fe2{} - } - for i := 0; i < len(t6); i++ { - t6[i] = &fe6{} - } - return fp12temp{t2, t6, &fe12{}} -} - -func newFp12(fp6 *fp6) *fp12 { - t := newFp12Temp() - if fp6 == nil { - return &fp12{t, newFp6(nil)} - } - return &fp12{t, fp6} -} - -func (e *fp12) fp2() *fp2 { - return e.fp6.fp2 -} - -func (e *fp12) fromBytes(in []byte) (*fe12, error) { - if len(in) != 576 { - return nil, errors.New("input string should be larger than 96 bytes") - } - fp6 := e.fp6 - c1, err := fp6.fromBytes(in[:288]) - if err != nil { - return nil, err - } - c0, err := fp6.fromBytes(in[288:]) - if err != nil { - return nil, err - } - return &fe12{*c0, *c1}, nil -} - -func (e *fp12) toBytes(a *fe12) []byte { - fp6 := e.fp6 - out := make([]byte, 576) - copy(out[:288], fp6.toBytes(&a[1])) - copy(out[288:], fp6.toBytes(&a[0])) - return out -} - -func (e *fp12) new() *fe12 { - return new(fe12) -} - -func (e *fp12) zero() *fe12 { - return new(fe12) -} - -func (e *fp12) one() *fe12 { - return new(fe12).one() -} - -func (e *fp12) add(c, a, b *fe12) { - fp6 := e.fp6 - fp6.add(&c[0], &a[0], &b[0]) - fp6.add(&c[1], &a[1], &b[1]) -} - -func (e *fp12) double(c, a *fe12) { - fp6 := e.fp6 - fp6.double(&c[0], &a[0]) - fp6.double(&c[1], &a[1]) -} - -func (e *fp12) sub(c, a, b *fe12) { - fp6 := e.fp6 - fp6.sub(&c[0], &a[0], &b[0]) - fp6.sub(&c[1], &a[1], &b[1]) -} - -func (e *fp12) neg(c, a *fe12) { - fp6 := e.fp6 - fp6.neg(&c[0], &a[0]) - fp6.neg(&c[1], &a[1]) -} - -func (e *fp12) conjugate(c, a *fe12) { - fp6 := e.fp6 - c[0].set(&a[0]) - fp6.neg(&c[1], &a[1]) -} - -func (e *fp12) square(c, a *fe12) { - fp6, t := e.fp6, e.t6 - fp6.add(t[0], &a[0], &a[1]) - fp6.mul(t[2], &a[0], &a[1]) - fp6.mulByNonResidue(t[1], &a[1]) - fp6.addAssign(t[1], &a[0]) - fp6.mulByNonResidue(t[3], t[2]) - fp6.mulAssign(t[0], t[1]) - fp6.subAssign(t[0], t[2]) - fp6.sub(&c[0], t[0], t[3]) - fp6.double(&c[1], t[2]) -} - -func (e *fp12) cyclotomicSquare(c, a *fe12) { - t, fp2 := e.t2, e.fp2() - e.fp4Square(t[3], t[4], &a[0][0], &a[1][1]) - fp2.sub(t[2], t[3], &a[0][0]) - fp2.doubleAssign(t[2]) - fp2.add(&c[0][0], t[2], t[3]) - fp2.add(t[2], t[4], &a[1][1]) - fp2.doubleAssign(t[2]) - fp2.add(&c[1][1], t[2], t[4]) - e.fp4Square(t[3], t[4], &a[1][0], &a[0][2]) - e.fp4Square(t[5], t[6], &a[0][1], &a[1][2]) - fp2.sub(t[2], t[3], &a[0][1]) - fp2.doubleAssign(t[2]) - fp2.add(&c[0][1], t[2], t[3]) - fp2.add(t[2], t[4], &a[1][2]) - fp2.doubleAssign(t[2]) - fp2.add(&c[1][2], t[2], t[4]) - fp2.mulByNonResidue(t[3], t[6]) - fp2.add(t[2], t[3], &a[1][0]) - fp2.doubleAssign(t[2]) - fp2.add(&c[1][0], t[2], t[3]) - fp2.sub(t[2], t[5], &a[0][2]) - fp2.doubleAssign(t[2]) - fp2.add(&c[0][2], t[2], t[5]) -} - -func (e *fp12) mul(c, a, b *fe12) { - t, fp6 := e.t6, e.fp6 - fp6.mul(t[1], &a[0], &b[0]) - fp6.mul(t[2], &a[1], &b[1]) - fp6.add(t[0], t[1], t[2]) - fp6.mulByNonResidue(t[2], t[2]) - fp6.add(t[3], t[1], t[2]) - fp6.add(t[1], &a[0], &a[1]) - fp6.add(t[2], &b[0], &b[1]) - fp6.mulAssign(t[1], t[2]) - c[0].set(t[3]) - fp6.sub(&c[1], t[1], t[0]) -} - -func (e *fp12) mulAssign(a, b *fe12) { - t, fp6 := e.t6, e.fp6 - fp6.mul(t[1], &a[0], &b[0]) - fp6.mul(t[2], &a[1], &b[1]) - fp6.add(t[0], t[1], t[2]) - fp6.mulByNonResidue(t[2], t[2]) - fp6.add(t[3], t[1], t[2]) - fp6.add(t[1], &a[0], &a[1]) - fp6.add(t[2], &b[0], &b[1]) - fp6.mulAssign(t[1], t[2]) - a[0].set(t[3]) - fp6.sub(&a[1], t[1], t[0]) -} - -func (e *fp12) fp4Square(c0, c1, a0, a1 *fe2) { - t, fp2 := e.t2, e.fp2() - fp2.square(t[0], a0) - fp2.square(t[1], a1) - fp2.mulByNonResidue(t[2], t[1]) - fp2.add(c0, t[2], t[0]) - fp2.add(t[2], a0, a1) - fp2.squareAssign(t[2]) - fp2.subAssign(t[2], t[0]) - fp2.sub(c1, t[2], t[1]) -} - -func (e *fp12) inverse(c, a *fe12) { - fp6, t := e.fp6, e.t6 - fp6.square(t[0], &a[0]) - fp6.square(t[1], &a[1]) - fp6.mulByNonResidue(t[1], t[1]) - fp6.sub(t[1], t[0], t[1]) - fp6.inverse(t[0], t[1]) - fp6.mul(&c[0], &a[0], t[0]) - fp6.mulAssign(t[0], &a[1]) - fp6.neg(&c[1], t[0]) -} - -func (e *fp12) mulBy014Assign(a *fe12, c0, c1, c4 *fe2) { - fp2, fp6, t, t2 := e.fp2(), e.fp6, e.t6, e.t2[0] - fp6.mulBy01(t[0], &a[0], c0, c1) - fp6.mulBy1(t[1], &a[1], c4) - fp2.add(t2, c1, c4) - fp6.add(t[2], &a[1], &a[0]) - fp6.mulBy01Assign(t[2], c0, t2) - fp6.subAssign(t[2], t[0]) - fp6.sub(&a[1], t[2], t[1]) - fp6.mulByNonResidue(t[1], t[1]) - fp6.add(&a[0], t[1], t[0]) -} - -func (e *fp12) exp(c, a *fe12, s *big.Int) { - z := e.one() - for i := s.BitLen() - 1; i >= 0; i-- { - e.square(z, z) - if s.Bit(i) == 1 { - e.mul(z, z, a) - } - } - c.set(z) -} - -func (e *fp12) cyclotomicExp(c, a *fe12, s *big.Int) { - z := e.one() - for i := s.BitLen() - 1; i >= 0; i-- { - e.cyclotomicSquare(z, z) - if s.Bit(i) == 1 { - e.mul(z, z, a) - } - } - c.set(z) -} - -func (e *fp12) frobeniusMap(c, a *fe12, power uint) { - fp6 := e.fp6 - fp6.frobeniusMap(&c[0], &a[0], power) - fp6.frobeniusMap(&c[1], &a[1], power) - switch power { - case 0: - return - case 6: - fp6.neg(&c[1], &c[1]) - default: - fp6.mulByBaseField(&c[1], &c[1], &frobeniusCoeffs12[power]) - } -} - -func (e *fp12) frobeniusMapAssign(a *fe12, power uint) { - fp6 := e.fp6 - fp6.frobeniusMapAssign(&a[0], power) - fp6.frobeniusMapAssign(&a[1], power) - switch power { - case 0: - return - case 6: - fp6.neg(&a[1], &a[1]) - default: - fp6.mulByBaseField(&a[1], &a[1], &frobeniusCoeffs12[power]) - } -} diff --git a/crypto/bls12381/fp2.go b/crypto/bls12381/fp2.go deleted file mode 100644 index 0f1c5a23ac5f..000000000000 --- a/crypto/bls12381/fp2.go +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2020 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 bls12381 - -import ( - "errors" - "math/big" -) - -type fp2Temp struct { - t [4]*fe -} - -type fp2 struct { - fp2Temp -} - -func newFp2Temp() fp2Temp { - t := [4]*fe{} - for i := 0; i < len(t); i++ { - t[i] = &fe{} - } - return fp2Temp{t} -} - -func newFp2() *fp2 { - t := newFp2Temp() - return &fp2{t} -} - -func (e *fp2) fromBytes(in []byte) (*fe2, error) { - if len(in) != 96 { - return nil, errors.New("length of input string should be 96 bytes") - } - c1, err := fromBytes(in[:48]) - if err != nil { - return nil, err - } - c0, err := fromBytes(in[48:]) - if err != nil { - return nil, err - } - return &fe2{*c0, *c1}, nil -} - -func (e *fp2) toBytes(a *fe2) []byte { - out := make([]byte, 96) - copy(out[:48], toBytes(&a[1])) - copy(out[48:], toBytes(&a[0])) - return out -} - -func (e *fp2) new() *fe2 { - return new(fe2).zero() -} - -func (e *fp2) zero() *fe2 { - return new(fe2).zero() -} - -func (e *fp2) one() *fe2 { - return new(fe2).one() -} - -func (e *fp2) add(c, a, b *fe2) { - add(&c[0], &a[0], &b[0]) - add(&c[1], &a[1], &b[1]) -} - -func (e *fp2) addAssign(a, b *fe2) { - addAssign(&a[0], &b[0]) - addAssign(&a[1], &b[1]) -} - -func (e *fp2) ladd(c, a, b *fe2) { - ladd(&c[0], &a[0], &b[0]) - ladd(&c[1], &a[1], &b[1]) -} - -func (e *fp2) double(c, a *fe2) { - double(&c[0], &a[0]) - double(&c[1], &a[1]) -} - -func (e *fp2) doubleAssign(a *fe2) { - doubleAssign(&a[0]) - doubleAssign(&a[1]) -} - -func (e *fp2) ldouble(c, a *fe2) { - ldouble(&c[0], &a[0]) - ldouble(&c[1], &a[1]) -} - -func (e *fp2) sub(c, a, b *fe2) { - sub(&c[0], &a[0], &b[0]) - sub(&c[1], &a[1], &b[1]) -} - -func (e *fp2) subAssign(c, a *fe2) { - subAssign(&c[0], &a[0]) - subAssign(&c[1], &a[1]) -} - -func (e *fp2) neg(c, a *fe2) { - neg(&c[0], &a[0]) - neg(&c[1], &a[1]) -} - -func (e *fp2) mul(c, a, b *fe2) { - t := e.t - mul(t[1], &a[0], &b[0]) - mul(t[2], &a[1], &b[1]) - add(t[0], &a[0], &a[1]) - add(t[3], &b[0], &b[1]) - sub(&c[0], t[1], t[2]) - addAssign(t[1], t[2]) - mul(t[0], t[0], t[3]) - sub(&c[1], t[0], t[1]) -} - -func (e *fp2) mulAssign(a, b *fe2) { - t := e.t - mul(t[1], &a[0], &b[0]) - mul(t[2], &a[1], &b[1]) - add(t[0], &a[0], &a[1]) - add(t[3], &b[0], &b[1]) - sub(&a[0], t[1], t[2]) - addAssign(t[1], t[2]) - mul(t[0], t[0], t[3]) - sub(&a[1], t[0], t[1]) -} - -func (e *fp2) square(c, a *fe2) { - t := e.t - ladd(t[0], &a[0], &a[1]) - sub(t[1], &a[0], &a[1]) - ldouble(t[2], &a[0]) - mul(&c[0], t[0], t[1]) - mul(&c[1], t[2], &a[1]) -} - -func (e *fp2) squareAssign(a *fe2) { - t := e.t - ladd(t[0], &a[0], &a[1]) - sub(t[1], &a[0], &a[1]) - ldouble(t[2], &a[0]) - mul(&a[0], t[0], t[1]) - mul(&a[1], t[2], &a[1]) -} - -func (e *fp2) mulByNonResidue(c, a *fe2) { - t := e.t - sub(t[0], &a[0], &a[1]) - add(&c[1], &a[0], &a[1]) - c[0].set(t[0]) -} - -func (e *fp2) mulByB(c, a *fe2) { - t := e.t - double(t[0], &a[0]) - double(t[1], &a[1]) - doubleAssign(t[0]) - doubleAssign(t[1]) - sub(&c[0], t[0], t[1]) - add(&c[1], t[0], t[1]) -} - -func (e *fp2) inverse(c, a *fe2) { - t := e.t - square(t[0], &a[0]) - square(t[1], &a[1]) - addAssign(t[0], t[1]) - inverse(t[0], t[0]) - mul(&c[0], &a[0], t[0]) - mul(t[0], t[0], &a[1]) - neg(&c[1], t[0]) -} - -func (e *fp2) mulByFq(c, a *fe2, b *fe) { - mul(&c[0], &a[0], b) - mul(&c[1], &a[1], b) -} - -func (e *fp2) exp(c, a *fe2, s *big.Int) { - z := e.one() - for i := s.BitLen() - 1; i >= 0; i-- { - e.square(z, z) - if s.Bit(i) == 1 { - e.mul(z, z, a) - } - } - c.set(z) -} - -func (e *fp2) frobeniusMap(c, a *fe2, power uint) { - c[0].set(&a[0]) - if power%2 == 1 { - neg(&c[1], &a[1]) - return - } - c[1].set(&a[1]) -} - -func (e *fp2) frobeniusMapAssign(a *fe2, power uint) { - if power%2 == 1 { - neg(&a[1], &a[1]) - return - } -} - -func (e *fp2) sqrt(c, a *fe2) bool { - u, x0, a1, alpha := &fe2{}, &fe2{}, &fe2{}, &fe2{} - u.set(a) - e.exp(a1, a, pMinus3Over4) - e.square(alpha, a1) - e.mul(alpha, alpha, a) - e.mul(x0, a1, a) - if alpha.equal(negativeOne2) { - neg(&c[0], &x0[1]) - c[1].set(&x0[0]) - return true - } - e.add(alpha, alpha, e.one()) - e.exp(alpha, alpha, pMinus1Over2) - e.mul(c, alpha, x0) - e.square(alpha, c) - return alpha.equal(u) -} - -func (e *fp2) isQuadraticNonResidue(a *fe2) bool { - // https://github.com/leovt/constructible/wiki/Taking-Square-Roots-in-quadratic-extension-Fields - c0, c1 := new(fe), new(fe) - square(c0, &a[0]) - square(c1, &a[1]) - add(c1, c1, c0) - return isQuadraticNonResidue(c1) -} diff --git a/crypto/bls12381/fp6.go b/crypto/bls12381/fp6.go deleted file mode 100644 index 304173baa3f7..000000000000 --- a/crypto/bls12381/fp6.go +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright 2020 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 bls12381 - -import ( - "errors" - "math/big" -) - -type fp6Temp struct { - t [6]*fe2 -} - -type fp6 struct { - fp2 *fp2 - fp6Temp -} - -func newFp6Temp() fp6Temp { - t := [6]*fe2{} - for i := 0; i < len(t); i++ { - t[i] = &fe2{} - } - return fp6Temp{t} -} - -func newFp6(f *fp2) *fp6 { - t := newFp6Temp() - if f == nil { - return &fp6{newFp2(), t} - } - return &fp6{f, t} -} - -func (e *fp6) fromBytes(b []byte) (*fe6, error) { - if len(b) < 288 { - return nil, errors.New("input string should be larger than 288 bytes") - } - fp2 := e.fp2 - u2, err := fp2.fromBytes(b[:96]) - if err != nil { - return nil, err - } - u1, err := fp2.fromBytes(b[96:192]) - if err != nil { - return nil, err - } - u0, err := fp2.fromBytes(b[192:]) - if err != nil { - return nil, err - } - return &fe6{*u0, *u1, *u2}, nil -} - -func (e *fp6) toBytes(a *fe6) []byte { - fp2 := e.fp2 - out := make([]byte, 288) - copy(out[:96], fp2.toBytes(&a[2])) - copy(out[96:192], fp2.toBytes(&a[1])) - copy(out[192:], fp2.toBytes(&a[0])) - return out -} - -func (e *fp6) new() *fe6 { - return new(fe6) -} - -func (e *fp6) zero() *fe6 { - return new(fe6) -} - -func (e *fp6) one() *fe6 { - return new(fe6).one() -} - -func (e *fp6) add(c, a, b *fe6) { - fp2 := e.fp2 - fp2.add(&c[0], &a[0], &b[0]) - fp2.add(&c[1], &a[1], &b[1]) - fp2.add(&c[2], &a[2], &b[2]) -} - -func (e *fp6) addAssign(a, b *fe6) { - fp2 := e.fp2 - fp2.addAssign(&a[0], &b[0]) - fp2.addAssign(&a[1], &b[1]) - fp2.addAssign(&a[2], &b[2]) -} - -func (e *fp6) double(c, a *fe6) { - fp2 := e.fp2 - fp2.double(&c[0], &a[0]) - fp2.double(&c[1], &a[1]) - fp2.double(&c[2], &a[2]) -} - -func (e *fp6) doubleAssign(a *fe6) { - fp2 := e.fp2 - fp2.doubleAssign(&a[0]) - fp2.doubleAssign(&a[1]) - fp2.doubleAssign(&a[2]) -} - -func (e *fp6) sub(c, a, b *fe6) { - fp2 := e.fp2 - fp2.sub(&c[0], &a[0], &b[0]) - fp2.sub(&c[1], &a[1], &b[1]) - fp2.sub(&c[2], &a[2], &b[2]) -} - -func (e *fp6) subAssign(a, b *fe6) { - fp2 := e.fp2 - fp2.subAssign(&a[0], &b[0]) - fp2.subAssign(&a[1], &b[1]) - fp2.subAssign(&a[2], &b[2]) -} - -func (e *fp6) neg(c, a *fe6) { - fp2 := e.fp2 - fp2.neg(&c[0], &a[0]) - fp2.neg(&c[1], &a[1]) - fp2.neg(&c[2], &a[2]) -} - -func (e *fp6) mul(c, a, b *fe6) { - fp2, t := e.fp2, e.t - fp2.mul(t[0], &a[0], &b[0]) - fp2.mul(t[1], &a[1], &b[1]) - fp2.mul(t[2], &a[2], &b[2]) - fp2.add(t[3], &a[1], &a[2]) - fp2.add(t[4], &b[1], &b[2]) - fp2.mulAssign(t[3], t[4]) - fp2.add(t[4], t[1], t[2]) - fp2.subAssign(t[3], t[4]) - fp2.mulByNonResidue(t[3], t[3]) - fp2.add(t[5], t[0], t[3]) - fp2.add(t[3], &a[0], &a[1]) - fp2.add(t[4], &b[0], &b[1]) - fp2.mulAssign(t[3], t[4]) - fp2.add(t[4], t[0], t[1]) - fp2.subAssign(t[3], t[4]) - fp2.mulByNonResidue(t[4], t[2]) - fp2.add(&c[1], t[3], t[4]) - fp2.add(t[3], &a[0], &a[2]) - fp2.add(t[4], &b[0], &b[2]) - fp2.mulAssign(t[3], t[4]) - fp2.add(t[4], t[0], t[2]) - fp2.subAssign(t[3], t[4]) - fp2.add(&c[2], t[1], t[3]) - c[0].set(t[5]) -} - -func (e *fp6) mulAssign(a, b *fe6) { - fp2, t := e.fp2, e.t - fp2.mul(t[0], &a[0], &b[0]) - fp2.mul(t[1], &a[1], &b[1]) - fp2.mul(t[2], &a[2], &b[2]) - fp2.add(t[3], &a[1], &a[2]) - fp2.add(t[4], &b[1], &b[2]) - fp2.mulAssign(t[3], t[4]) - fp2.add(t[4], t[1], t[2]) - fp2.subAssign(t[3], t[4]) - fp2.mulByNonResidue(t[3], t[3]) - fp2.add(t[5], t[0], t[3]) - fp2.add(t[3], &a[0], &a[1]) - fp2.add(t[4], &b[0], &b[1]) - fp2.mulAssign(t[3], t[4]) - fp2.add(t[4], t[0], t[1]) - fp2.subAssign(t[3], t[4]) - fp2.mulByNonResidue(t[4], t[2]) - fp2.add(&a[1], t[3], t[4]) - fp2.add(t[3], &a[0], &a[2]) - fp2.add(t[4], &b[0], &b[2]) - fp2.mulAssign(t[3], t[4]) - fp2.add(t[4], t[0], t[2]) - fp2.subAssign(t[3], t[4]) - fp2.add(&a[2], t[1], t[3]) - a[0].set(t[5]) -} - -func (e *fp6) square(c, a *fe6) { - fp2, t := e.fp2, e.t - fp2.square(t[0], &a[0]) - fp2.mul(t[1], &a[0], &a[1]) - fp2.doubleAssign(t[1]) - fp2.sub(t[2], &a[0], &a[1]) - fp2.addAssign(t[2], &a[2]) - fp2.squareAssign(t[2]) - fp2.mul(t[3], &a[1], &a[2]) - fp2.doubleAssign(t[3]) - fp2.square(t[4], &a[2]) - fp2.mulByNonResidue(t[5], t[3]) - fp2.add(&c[0], t[0], t[5]) - fp2.mulByNonResidue(t[5], t[4]) - fp2.add(&c[1], t[1], t[5]) - fp2.addAssign(t[1], t[2]) - fp2.addAssign(t[1], t[3]) - fp2.addAssign(t[0], t[4]) - fp2.sub(&c[2], t[1], t[0]) -} - -func (e *fp6) mulBy01Assign(a *fe6, b0, b1 *fe2) { - fp2, t := e.fp2, e.t - fp2.mul(t[0], &a[0], b0) - fp2.mul(t[1], &a[1], b1) - fp2.add(t[5], &a[1], &a[2]) - fp2.mul(t[2], b1, t[5]) - fp2.subAssign(t[2], t[1]) - fp2.mulByNonResidue(t[2], t[2]) - fp2.add(t[5], &a[0], &a[2]) - fp2.mul(t[3], b0, t[5]) - fp2.subAssign(t[3], t[0]) - fp2.add(&a[2], t[3], t[1]) - fp2.add(t[4], b0, b1) - fp2.add(t[5], &a[0], &a[1]) - fp2.mulAssign(t[4], t[5]) - fp2.subAssign(t[4], t[0]) - fp2.sub(&a[1], t[4], t[1]) - fp2.add(&a[0], t[2], t[0]) -} - -func (e *fp6) mulBy01(c, a *fe6, b0, b1 *fe2) { - fp2, t := e.fp2, e.t - fp2.mul(t[0], &a[0], b0) - fp2.mul(t[1], &a[1], b1) - fp2.add(t[2], &a[1], &a[2]) - fp2.mulAssign(t[2], b1) - fp2.subAssign(t[2], t[1]) - fp2.mulByNonResidue(t[2], t[2]) - fp2.add(t[3], &a[0], &a[2]) - fp2.mulAssign(t[3], b0) - fp2.subAssign(t[3], t[0]) - fp2.add(&c[2], t[3], t[1]) - fp2.add(t[4], b0, b1) - fp2.add(t[3], &a[0], &a[1]) - fp2.mulAssign(t[4], t[3]) - fp2.subAssign(t[4], t[0]) - fp2.sub(&c[1], t[4], t[1]) - fp2.add(&c[0], t[2], t[0]) -} - -func (e *fp6) mulBy1(c, a *fe6, b1 *fe2) { - fp2, t := e.fp2, e.t - fp2.mul(t[0], &a[2], b1) - fp2.mul(&c[2], &a[1], b1) - fp2.mul(&c[1], &a[0], b1) - fp2.mulByNonResidue(&c[0], t[0]) -} - -func (e *fp6) mulByNonResidue(c, a *fe6) { - fp2, t := e.fp2, e.t - t[0].set(&a[0]) - fp2.mulByNonResidue(&c[0], &a[2]) - c[2].set(&a[1]) - c[1].set(t[0]) -} - -func (e *fp6) mulByBaseField(c, a *fe6, b *fe2) { - fp2 := e.fp2 - fp2.mul(&c[0], &a[0], b) - fp2.mul(&c[1], &a[1], b) - fp2.mul(&c[2], &a[2], b) -} - -func (e *fp6) exp(c, a *fe6, s *big.Int) { - z := e.one() - for i := s.BitLen() - 1; i >= 0; i-- { - e.square(z, z) - if s.Bit(i) == 1 { - e.mul(z, z, a) - } - } - c.set(z) -} - -func (e *fp6) inverse(c, a *fe6) { - fp2, t := e.fp2, e.t - fp2.square(t[0], &a[0]) - fp2.mul(t[1], &a[1], &a[2]) - fp2.mulByNonResidue(t[1], t[1]) - fp2.subAssign(t[0], t[1]) - fp2.square(t[1], &a[1]) - fp2.mul(t[2], &a[0], &a[2]) - fp2.subAssign(t[1], t[2]) - fp2.square(t[2], &a[2]) - fp2.mulByNonResidue(t[2], t[2]) - fp2.mul(t[3], &a[0], &a[1]) - fp2.subAssign(t[2], t[3]) - fp2.mul(t[3], &a[2], t[2]) - fp2.mul(t[4], &a[1], t[1]) - fp2.addAssign(t[3], t[4]) - fp2.mulByNonResidue(t[3], t[3]) - fp2.mul(t[4], &a[0], t[0]) - fp2.addAssign(t[3], t[4]) - fp2.inverse(t[3], t[3]) - fp2.mul(&c[0], t[0], t[3]) - fp2.mul(&c[1], t[2], t[3]) - fp2.mul(&c[2], t[1], t[3]) -} - -func (e *fp6) frobeniusMap(c, a *fe6, power uint) { - fp2 := e.fp2 - fp2.frobeniusMap(&c[0], &a[0], power) - fp2.frobeniusMap(&c[1], &a[1], power) - fp2.frobeniusMap(&c[2], &a[2], power) - switch power % 6 { - case 0: - return - case 3: - neg(&c[0][0], &a[1][1]) - c[1][1].set(&a[1][0]) - fp2.neg(&a[2], &a[2]) - default: - fp2.mul(&c[1], &c[1], &frobeniusCoeffs61[power%6]) - fp2.mul(&c[2], &c[2], &frobeniusCoeffs62[power%6]) - } -} - -func (e *fp6) frobeniusMapAssign(a *fe6, power uint) { - fp2 := e.fp2 - fp2.frobeniusMapAssign(&a[0], power) - fp2.frobeniusMapAssign(&a[1], power) - fp2.frobeniusMapAssign(&a[2], power) - t := e.t - switch power % 6 { - case 0: - return - case 3: - neg(&t[0][0], &a[1][1]) - a[1][1].set(&a[1][0]) - a[1][0].set(&t[0][0]) - fp2.neg(&a[2], &a[2]) - default: - fp2.mulAssign(&a[1], &frobeniusCoeffs61[power%6]) - fp2.mulAssign(&a[2], &frobeniusCoeffs62[power%6]) - } -} diff --git a/crypto/bls12381/fp_test.go b/crypto/bls12381/fp_test.go deleted file mode 100644 index 0bad35de1630..000000000000 --- a/crypto/bls12381/fp_test.go +++ /dev/null @@ -1,1411 +0,0 @@ -package bls12381 - -import ( - "bytes" - "crypto/rand" - "math/big" - "testing" -) - -func TestFpSerialization(t *testing.T) { - t.Run("zero", func(t *testing.T) { - in := make([]byte, 48) - fe, err := fromBytes(in) - if err != nil { - t.Fatal(err) - } - if !fe.isZero() { - t.Fatal("bad serialization") - } - if !bytes.Equal(in, toBytes(fe)) { - t.Fatal("bad serialization") - } - }) - t.Run("bytes", func(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b, err := fromBytes(toBytes(a)) - if err != nil { - t.Fatal(err) - } - if !a.equal(b) { - t.Fatal("bad serialization") - } - } - }) - t.Run("string", func(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b, err := fromString(toString(a)) - if err != nil { - t.Fatal(err) - } - if !a.equal(b) { - t.Fatal("bad encoding or decoding") - } - } - }) - t.Run("big", func(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b, err := fromBig(toBig(a)) - if err != nil { - t.Fatal(err) - } - if !a.equal(b) { - t.Fatal("bad encoding or decoding") - } - } - }) -} - -func TestFpAdditionCrossAgainstBigInt(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b, _ := new(fe).rand(rand.Reader) - c := new(fe) - big_a := toBig(a) - big_b := toBig(b) - big_c := new(big.Int) - add(c, a, b) - out_1 := toBytes(c) - out_2 := padBytes(big_c.Add(big_a, big_b).Mod(big_c, modulus.big()).Bytes(), 48) - if !bytes.Equal(out_1, out_2) { - t.Fatal("cross test against big.Int is not satisfied A") - } - double(c, a) - out_1 = toBytes(c) - out_2 = padBytes(big_c.Add(big_a, big_a).Mod(big_c, modulus.big()).Bytes(), 48) - if !bytes.Equal(out_1, out_2) { - t.Fatal("cross test against big.Int is not satisfied B") - } - sub(c, a, b) - out_1 = toBytes(c) - out_2 = padBytes(big_c.Sub(big_a, big_b).Mod(big_c, modulus.big()).Bytes(), 48) - if !bytes.Equal(out_1, out_2) { - t.Fatal("cross test against big.Int is not satisfied C") - } - neg(c, a) - out_1 = toBytes(c) - out_2 = padBytes(big_c.Neg(big_a).Mod(big_c, modulus.big()).Bytes(), 48) - if !bytes.Equal(out_1, out_2) { - t.Fatal("cross test against big.Int is not satisfied D") - } - } -} - -func TestFpAdditionCrossAgainstBigIntAssigned(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b, _ := new(fe).rand(rand.Reader) - big_a, big_b := toBig(a), toBig(b) - addAssign(a, b) - out_1 := toBytes(a) - out_2 := padBytes(big_a.Add(big_a, big_b).Mod(big_a, modulus.big()).Bytes(), 48) - if !bytes.Equal(out_1, out_2) { - t.Fatal("cross test against big.Int is not satisfied A") - } - a, _ = new(fe).rand(rand.Reader) - big_a = toBig(a) - doubleAssign(a) - out_1 = toBytes(a) - out_2 = padBytes(big_a.Add(big_a, big_a).Mod(big_a, modulus.big()).Bytes(), 48) - if !bytes.Equal(out_1, out_2) { - t.Fatal("cross test against big.Int is not satisfied B") - } - a, _ = new(fe).rand(rand.Reader) - b, _ = new(fe).rand(rand.Reader) - big_a, big_b = toBig(a), toBig(b) - subAssign(a, b) - out_1 = toBytes(a) - out_2 = padBytes(big_a.Sub(big_a, big_b).Mod(big_a, modulus.big()).Bytes(), 48) - if !bytes.Equal(out_1, out_2) { - t.Fatal("cross test against big.Int is not satisfied A") - } - } -} - -func TestFpAdditionProperties(t *testing.T) { - for i := 0; i < fuz; i++ { - zero := new(fe).zero() - a, _ := new(fe).rand(rand.Reader) - b, _ := new(fe).rand(rand.Reader) - c_1, c_2 := new(fe), new(fe) - add(c_1, a, zero) - if !c_1.equal(a) { - t.Fatal("a + 0 == a") - } - sub(c_1, a, zero) - if !c_1.equal(a) { - t.Fatal("a - 0 == a") - } - double(c_1, zero) - if !c_1.equal(zero) { - t.Fatal("2 * 0 == 0") - } - neg(c_1, zero) - if !c_1.equal(zero) { - t.Fatal("-0 == 0") - } - sub(c_1, zero, a) - neg(c_2, a) - if !c_1.equal(c_2) { - t.Fatal("0-a == -a") - } - double(c_1, a) - add(c_2, a, a) - if !c_1.equal(c_2) { - t.Fatal("2 * a == a + a") - } - add(c_1, a, b) - add(c_2, b, a) - if !c_1.equal(c_2) { - t.Fatal("a + b = b + a") - } - sub(c_1, a, b) - sub(c_2, b, a) - neg(c_2, c_2) - if !c_1.equal(c_2) { - t.Fatal("a - b = - ( b - a )") - } - c_x, _ := new(fe).rand(rand.Reader) - add(c_1, a, b) - add(c_1, c_1, c_x) - add(c_2, a, c_x) - add(c_2, c_2, b) - if !c_1.equal(c_2) { - t.Fatal("(a + b) + c == (a + c ) + b") - } - sub(c_1, a, b) - sub(c_1, c_1, c_x) - sub(c_2, a, c_x) - sub(c_2, c_2, b) - if !c_1.equal(c_2) { - t.Fatal("(a - b) - c == (a - c ) -b") - } - } -} - -func TestFpAdditionPropertiesAssigned(t *testing.T) { - for i := 0; i < fuz; i++ { - zero := new(fe).zero() - a, b := new(fe), new(fe) - _, _ = a.rand(rand.Reader) - b.set(a) - addAssign(a, zero) - if !a.equal(b) { - t.Fatal("a + 0 == a") - } - subAssign(a, zero) - if !a.equal(b) { - t.Fatal("a - 0 == a") - } - a.set(zero) - doubleAssign(a) - if !a.equal(zero) { - t.Fatal("2 * 0 == 0") - } - a.set(zero) - subAssign(a, b) - neg(b, b) - if !a.equal(b) { - t.Fatal("0-a == -a") - } - _, _ = a.rand(rand.Reader) - b.set(a) - doubleAssign(a) - addAssign(b, b) - if !a.equal(b) { - t.Fatal("2 * a == a + a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - c_1, c_2 := new(fe).set(a), new(fe).set(b) - addAssign(c_1, b) - addAssign(c_2, a) - if !c_1.equal(c_2) { - t.Fatal("a + b = b + a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - c_1.set(a) - c_2.set(b) - subAssign(c_1, b) - subAssign(c_2, a) - neg(c_2, c_2) - if !c_1.equal(c_2) { - t.Fatal("a - b = - ( b - a )") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - c, _ := new(fe).rand(rand.Reader) - a0 := new(fe).set(a) - addAssign(a, b) - addAssign(a, c) - addAssign(b, c) - addAssign(b, a0) - if !a.equal(b) { - t.Fatal("(a + b) + c == (b + c) + a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - _, _ = c.rand(rand.Reader) - a0.set(a) - subAssign(a, b) - subAssign(a, c) - subAssign(a0, c) - subAssign(a0, b) - if !a.equal(a0) { - t.Fatal("(a - b) - c == (a - c) -b") - } - } -} - -func TestFpLazyOperations(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b, _ := new(fe).rand(rand.Reader) - c, _ := new(fe).rand(rand.Reader) - c0 := new(fe) - c1 := new(fe) - ladd(c0, a, b) - add(c1, a, b) - mul(c0, c0, c) - mul(c1, c1, c) - if !c0.equal(c1) { - // l+ operator stands for lazy addition - t.Fatal("(a + b) * c == (a l+ b) * c") - } - _, _ = a.rand(rand.Reader) - b.set(a) - ldouble(a, a) - ladd(b, b, b) - if !a.equal(b) { - t.Fatal("2 l* a = a l+ a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - _, _ = c.rand(rand.Reader) - a0 := new(fe).set(a) - lsubAssign(a, b) - laddAssign(a, &modulus) - mul(a, a, c) - subAssign(a0, b) - mul(a0, a0, c) - if !a.equal(a0) { - t.Fatal("((a l- b) + p) * c = (a-b) * c") - } - } -} - -func TestFpMultiplicationCrossAgainstBigInt(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b, _ := new(fe).rand(rand.Reader) - c := new(fe) - big_a := toBig(a) - big_b := toBig(b) - big_c := new(big.Int) - mul(c, a, b) - out_1 := toBytes(c) - out_2 := padBytes(big_c.Mul(big_a, big_b).Mod(big_c, modulus.big()).Bytes(), 48) - if !bytes.Equal(out_1, out_2) { - t.Fatal("cross test against big.Int is not satisfied") - } - } -} - -func TestFpMultiplicationProperties(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - b, _ := new(fe).rand(rand.Reader) - zero, one := new(fe).zero(), new(fe).one() - c_1, c_2 := new(fe), new(fe) - mul(c_1, a, zero) - if !c_1.equal(zero) { - t.Fatal("a * 0 == 0") - } - mul(c_1, a, one) - if !c_1.equal(a) { - t.Fatal("a * 1 == a") - } - mul(c_1, a, b) - mul(c_2, b, a) - if !c_1.equal(c_2) { - t.Fatal("a * b == b * a") - } - c_x, _ := new(fe).rand(rand.Reader) - mul(c_1, a, b) - mul(c_1, c_1, c_x) - mul(c_2, c_x, b) - mul(c_2, c_2, a) - if !c_1.equal(c_2) { - t.Fatal("(a * b) * c == (a * c) * b") - } - square(a, zero) - if !a.equal(zero) { - t.Fatal("0^2 == 0") - } - square(a, one) - if !a.equal(one) { - t.Fatal("1^2 == 1") - } - _, _ = a.rand(rand.Reader) - square(c_1, a) - mul(c_2, a, a) - if !c_1.equal(c_1) { - t.Fatal("a^2 == a*a") - } - } -} - -func TestFpExponentiation(t *testing.T) { - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - u := new(fe) - exp(u, a, big.NewInt(0)) - if !u.isOne() { - t.Fatal("a^0 == 1") - } - exp(u, a, big.NewInt(1)) - if !u.equal(a) { - t.Fatal("a^1 == a") - } - v := new(fe) - mul(u, a, a) - mul(u, u, u) - mul(u, u, u) - exp(v, a, big.NewInt(8)) - if !u.equal(v) { - t.Fatal("((a^2)^2)^2 == a^8") - } - p := modulus.big() - exp(u, a, p) - if !u.equal(a) { - t.Fatal("a^p == a") - } - exp(u, a, p.Sub(p, big.NewInt(1))) - if !u.isOne() { - t.Fatal("a^(p-1) == 1") - } - } -} - -func TestFpInversion(t *testing.T) { - for i := 0; i < fuz; i++ { - u := new(fe) - zero, one := new(fe).zero(), new(fe).one() - inverse(u, zero) - if !u.equal(zero) { - t.Fatal("(0^-1) == 0)") - } - inverse(u, one) - if !u.equal(one) { - t.Fatal("(1^-1) == 1)") - } - a, _ := new(fe).rand(rand.Reader) - inverse(u, a) - mul(u, u, a) - if !u.equal(one) { - t.Fatal("(r*a) * r*(a^-1) == r)") - } - v := new(fe) - p := modulus.big() - exp(u, a, p.Sub(p, big.NewInt(2))) - inverse(v, a) - if !v.equal(u) { - t.Fatal("a^(p-2) == a^-1") - } - } -} - -func TestFpSquareRoot(t *testing.T) { - r := new(fe) - if sqrt(r, nonResidue1) { - t.Fatal("non residue cannot have a sqrt") - } - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - aa, rr, r := &fe{}, &fe{}, &fe{} - square(aa, a) - if !sqrt(r, aa) { - t.Fatal("bad sqrt 1") - } - square(rr, r) - if !rr.equal(aa) { - t.Fatal("bad sqrt 2") - } - } -} - -func TestFpNonResidue(t *testing.T) { - if !isQuadraticNonResidue(nonResidue1) { - t.Fatal("element is quadratic non residue, 1") - } - if isQuadraticNonResidue(new(fe).one()) { - t.Fatal("one is not quadratic non residue") - } - if !isQuadraticNonResidue(new(fe).zero()) { - t.Fatal("should accept zero as quadratic non residue") - } - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - square(a, a) - if isQuadraticNonResidue(new(fe).one()) { - t.Fatal("element is not quadratic non residue") - } - } - for i := 0; i < fuz; i++ { - a, _ := new(fe).rand(rand.Reader) - if !sqrt(new(fe), a) { - if !isQuadraticNonResidue(a) { - t.Fatal("element is quadratic non residue, 2", i) - } - } else { - i -= 1 - } - } -} - -func TestFp2Serialization(t *testing.T) { - field := newFp2() - for i := 0; i < fuz; i++ { - a, _ := new(fe2).rand(rand.Reader) - b, err := field.fromBytes(field.toBytes(a)) - if err != nil { - t.Fatal(err) - } - if !a.equal(b) { - t.Fatal("bad serialization") - } - } -} - -func TestFp2AdditionProperties(t *testing.T) { - field := newFp2() - for i := 0; i < fuz; i++ { - zero := field.zero() - a, _ := new(fe2).rand(rand.Reader) - b, _ := new(fe2).rand(rand.Reader) - c_1 := field.new() - c_2 := field.new() - field.add(c_1, a, zero) - if !c_1.equal(a) { - t.Fatal("a + 0 == a") - } - field.sub(c_1, a, zero) - if !c_1.equal(a) { - t.Fatal("a - 0 == a") - } - field.double(c_1, zero) - if !c_1.equal(zero) { - t.Fatal("2 * 0 == 0") - } - field.neg(c_1, zero) - if !c_1.equal(zero) { - t.Fatal("-0 == 0") - } - field.sub(c_1, zero, a) - field.neg(c_2, a) - if !c_1.equal(c_2) { - t.Fatal("0-a == -a") - } - field.double(c_1, a) - field.add(c_2, a, a) - if !c_1.equal(c_2) { - t.Fatal("2 * a == a + a") - } - field.add(c_1, a, b) - field.add(c_2, b, a) - if !c_1.equal(c_2) { - t.Fatal("a + b = b + a") - } - field.sub(c_1, a, b) - field.sub(c_2, b, a) - field.neg(c_2, c_2) - if !c_1.equal(c_2) { - t.Fatal("a - b = - ( b - a )") - } - c_x, _ := new(fe2).rand(rand.Reader) - field.add(c_1, a, b) - field.add(c_1, c_1, c_x) - field.add(c_2, a, c_x) - field.add(c_2, c_2, b) - if !c_1.equal(c_2) { - t.Fatal("(a + b) + c == (a + c ) + b") - } - field.sub(c_1, a, b) - field.sub(c_1, c_1, c_x) - field.sub(c_2, a, c_x) - field.sub(c_2, c_2, b) - if !c_1.equal(c_2) { - t.Fatal("(a - b) - c == (a - c ) -b") - } - } -} - -func TestFp2AdditionPropertiesAssigned(t *testing.T) { - field := newFp2() - for i := 0; i < fuz; i++ { - zero := new(fe2).zero() - a, b := new(fe2), new(fe2) - _, _ = a.rand(rand.Reader) - b.set(a) - field.addAssign(a, zero) - if !a.equal(b) { - t.Fatal("a + 0 == a") - } - field.subAssign(a, zero) - if !a.equal(b) { - t.Fatal("a - 0 == a") - } - a.set(zero) - field.doubleAssign(a) - if !a.equal(zero) { - t.Fatal("2 * 0 == 0") - } - a.set(zero) - field.subAssign(a, b) - field.neg(b, b) - if !a.equal(b) { - t.Fatal("0-a == -a") - } - _, _ = a.rand(rand.Reader) - b.set(a) - field.doubleAssign(a) - field.addAssign(b, b) - if !a.equal(b) { - t.Fatal("2 * a == a + a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - c_1, c_2 := new(fe2).set(a), new(fe2).set(b) - field.addAssign(c_1, b) - field.addAssign(c_2, a) - if !c_1.equal(c_2) { - t.Fatal("a + b = b + a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - c_1.set(a) - c_2.set(b) - field.subAssign(c_1, b) - field.subAssign(c_2, a) - field.neg(c_2, c_2) - if !c_1.equal(c_2) { - t.Fatal("a - b = - ( b - a )") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - c, _ := new(fe2).rand(rand.Reader) - a0 := new(fe2).set(a) - field.addAssign(a, b) - field.addAssign(a, c) - field.addAssign(b, c) - field.addAssign(b, a0) - if !a.equal(b) { - t.Fatal("(a + b) + c == (b + c) + a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - _, _ = c.rand(rand.Reader) - a0.set(a) - field.subAssign(a, b) - field.subAssign(a, c) - field.subAssign(a0, c) - field.subAssign(a0, b) - if !a.equal(a0) { - t.Fatal("(a - b) - c == (a - c) -b") - } - } -} - -func TestFp2LazyOperations(t *testing.T) { - field := newFp2() - for i := 0; i < fuz; i++ { - a, _ := new(fe2).rand(rand.Reader) - b, _ := new(fe2).rand(rand.Reader) - c, _ := new(fe2).rand(rand.Reader) - c0 := new(fe2) - c1 := new(fe2) - field.ladd(c0, a, b) - field.add(c1, a, b) - field.mulAssign(c0, c) - field.mulAssign(c1, c) - if !c0.equal(c1) { - // l+ operator stands for lazy addition - t.Fatal("(a + b) * c == (a l+ b) * c") - } - _, _ = a.rand(rand.Reader) - b.set(a) - field.ldouble(a, a) - field.ladd(b, b, b) - if !a.equal(b) { - t.Fatal("2 l* a = a l+ a") - } - } -} - -func TestFp2MultiplicationProperties(t *testing.T) { - field := newFp2() - for i := 0; i < fuz; i++ { - a, _ := new(fe2).rand(rand.Reader) - b, _ := new(fe2).rand(rand.Reader) - zero := field.zero() - one := field.one() - c_1, c_2 := field.new(), field.new() - field.mul(c_1, a, zero) - if !c_1.equal(zero) { - t.Fatal("a * 0 == 0") - } - field.mul(c_1, a, one) - if !c_1.equal(a) { - t.Fatal("a * 1 == a") - } - field.mul(c_1, a, b) - field.mul(c_2, b, a) - if !c_1.equal(c_2) { - t.Fatal("a * b == b * a") - } - c_x, _ := new(fe2).rand(rand.Reader) - field.mul(c_1, a, b) - field.mul(c_1, c_1, c_x) - field.mul(c_2, c_x, b) - field.mul(c_2, c_2, a) - if !c_1.equal(c_2) { - t.Fatal("(a * b) * c == (a * c) * b") - } - field.square(a, zero) - if !a.equal(zero) { - t.Fatal("0^2 == 0") - } - field.square(a, one) - if !a.equal(one) { - t.Fatal("1^2 == 1") - } - _, _ = a.rand(rand.Reader) - field.square(c_1, a) - field.mul(c_2, a, a) - if !c_2.equal(c_1) { - t.Fatal("a^2 == a*a") - } - } -} - -func TestFp2MultiplicationPropertiesAssigned(t *testing.T) { - field := newFp2() - for i := 0; i < fuz; i++ { - a, _ := new(fe2).rand(rand.Reader) - zero, one := new(fe2).zero(), new(fe2).one() - field.mulAssign(a, zero) - if !a.equal(zero) { - t.Fatal("a * 0 == 0") - } - _, _ = a.rand(rand.Reader) - a0 := new(fe2).set(a) - field.mulAssign(a, one) - if !a.equal(a0) { - t.Fatal("a * 1 == a") - } - _, _ = a.rand(rand.Reader) - b, _ := new(fe2).rand(rand.Reader) - a0.set(a) - field.mulAssign(a, b) - field.mulAssign(b, a0) - if !a.equal(b) { - t.Fatal("a * b == b * a") - } - c, _ := new(fe2).rand(rand.Reader) - a0.set(a) - field.mulAssign(a, b) - field.mulAssign(a, c) - field.mulAssign(a0, c) - field.mulAssign(a0, b) - if !a.equal(a0) { - t.Fatal("(a * b) * c == (a * c) * b") - } - a0.set(a) - field.squareAssign(a) - field.mulAssign(a0, a0) - if !a.equal(a0) { - t.Fatal("a^2 == a*a") - } - } -} - -func TestFp2Exponentiation(t *testing.T) { - field := newFp2() - for i := 0; i < fuz; i++ { - a, _ := new(fe2).rand(rand.Reader) - u := field.new() - field.exp(u, a, big.NewInt(0)) - if !u.equal(field.one()) { - t.Fatal("a^0 == 1") - } - field.exp(u, a, big.NewInt(1)) - if !u.equal(a) { - t.Fatal("a^1 == a") - } - v := field.new() - field.mul(u, a, a) - field.mul(u, u, u) - field.mul(u, u, u) - field.exp(v, a, big.NewInt(8)) - if !u.equal(v) { - t.Fatal("((a^2)^2)^2 == a^8") - } - } -} - -func TestFp2Inversion(t *testing.T) { - field := newFp2() - u := field.new() - zero := field.zero() - one := field.one() - field.inverse(u, zero) - if !u.equal(zero) { - t.Fatal("(0 ^ -1) == 0)") - } - field.inverse(u, one) - if !u.equal(one) { - t.Fatal("(1 ^ -1) == 1)") - } - for i := 0; i < fuz; i++ { - a, _ := new(fe2).rand(rand.Reader) - field.inverse(u, a) - field.mul(u, u, a) - if !u.equal(one) { - t.Fatal("(r * a) * r * (a ^ -1) == r)") - } - } -} - -func TestFp2SquareRoot(t *testing.T) { - field := newFp2() - for z := 0; z < 1000; z++ { - zi := new(fe) - sub(zi, &modulus, &fe{uint64(z * z)}) - // r = (-z*z, 0) - r := &fe2{*zi, fe{0}} - toMont(&r[0], &r[0]) - toMont(&r[1], &r[1]) - c := field.new() - // sqrt((-z*z, 0)) = (0, z) - if !field.sqrt(c, r) { - t.Fatal("z*z does have a square root") - } - e := &fe2{fe{uint64(0)}, fe{uint64(z)}} - toMont(&e[0], &e[0]) - toMont(&e[1], &e[1]) - field.square(e, e) - field.square(c, c) - if !e.equal(c) { - t.Fatal("square root failed") - } - } - if field.sqrt(field.new(), nonResidue2) { - t.Fatal("non residue cannot have a sqrt") - } - for i := 0; i < fuz; i++ { - a, _ := new(fe2).rand(rand.Reader) - aa, rr, r := field.new(), field.new(), field.new() - field.square(aa, a) - if !field.sqrt(r, aa) { - t.Fatal("bad sqrt 1") - } - field.square(rr, r) - if !rr.equal(aa) { - t.Fatal("bad sqrt 2") - } - } -} - -func TestFp2NonResidue(t *testing.T) { - field := newFp2() - if !field.isQuadraticNonResidue(nonResidue2) { - t.Fatal("element is quadratic non residue, 1") - } - if field.isQuadraticNonResidue(new(fe2).one()) { - t.Fatal("one is not quadratic non residue") - } - if !field.isQuadraticNonResidue(new(fe2).zero()) { - t.Fatal("should accept zero as quadratic non residue") - } - for i := 0; i < fuz; i++ { - a, _ := new(fe2).rand(rand.Reader) - field.squareAssign(a) - if field.isQuadraticNonResidue(new(fe2).one()) { - t.Fatal("element is not quadratic non residue") - } - } - for i := 0; i < fuz; i++ { - a, _ := new(fe2).rand(rand.Reader) - if !field.sqrt(new(fe2), a) { - if !field.isQuadraticNonResidue(a) { - t.Fatal("element is quadratic non residue, 2", i) - } - } else { - i -= 1 - } - } -} - -func TestFp6Serialization(t *testing.T) { - field := newFp6(nil) - for i := 0; i < fuz; i++ { - a, _ := new(fe6).rand(rand.Reader) - b, err := field.fromBytes(field.toBytes(a)) - if err != nil { - t.Fatal(err) - } - if !a.equal(b) { - t.Fatal("bad serialization") - } - } -} - -func TestFp6AdditionProperties(t *testing.T) { - field := newFp6(nil) - for i := 0; i < fuz; i++ { - zero := field.zero() - a, _ := new(fe6).rand(rand.Reader) - b, _ := new(fe6).rand(rand.Reader) - c_1 := field.new() - c_2 := field.new() - field.add(c_1, a, zero) - if !c_1.equal(a) { - t.Fatal("a + 0 == a") - } - field.sub(c_1, a, zero) - if !c_1.equal(a) { - t.Fatal("a - 0 == a") - } - field.double(c_1, zero) - if !c_1.equal(zero) { - t.Fatal("2 * 0 == 0") - } - field.neg(c_1, zero) - if !c_1.equal(zero) { - t.Fatal("-0 == 0") - } - field.sub(c_1, zero, a) - field.neg(c_2, a) - if !c_1.equal(c_2) { - t.Fatal("0-a == -a") - } - field.double(c_1, a) - field.add(c_2, a, a) - if !c_1.equal(c_2) { - t.Fatal("2 * a == a + a") - } - field.add(c_1, a, b) - field.add(c_2, b, a) - if !c_1.equal(c_2) { - t.Fatal("a + b = b + a") - } - field.sub(c_1, a, b) - field.sub(c_2, b, a) - field.neg(c_2, c_2) - if !c_1.equal(c_2) { - t.Fatal("a - b = - ( b - a )") - } - c_x, _ := new(fe6).rand(rand.Reader) - field.add(c_1, a, b) - field.add(c_1, c_1, c_x) - field.add(c_2, a, c_x) - field.add(c_2, c_2, b) - if !c_1.equal(c_2) { - t.Fatal("(a + b) + c == (a + c ) + b") - } - field.sub(c_1, a, b) - field.sub(c_1, c_1, c_x) - field.sub(c_2, a, c_x) - field.sub(c_2, c_2, b) - if !c_1.equal(c_2) { - t.Fatal("(a - b) - c == (a - c ) -b") - } - } -} - -func TestFp6AdditionPropertiesAssigned(t *testing.T) { - field := newFp6(nil) - for i := 0; i < fuz; i++ { - zero := new(fe6).zero() - a, b := new(fe6), new(fe6) - _, _ = a.rand(rand.Reader) - b.set(a) - field.addAssign(a, zero) - if !a.equal(b) { - t.Fatal("a + 0 == a") - } - field.subAssign(a, zero) - if !a.equal(b) { - t.Fatal("a - 0 == a") - } - a.set(zero) - field.doubleAssign(a) - if !a.equal(zero) { - t.Fatal("2 * 0 == 0") - } - a.set(zero) - field.subAssign(a, b) - field.neg(b, b) - if !a.equal(b) { - t.Fatal("0-a == -a") - } - _, _ = a.rand(rand.Reader) - b.set(a) - field.doubleAssign(a) - field.addAssign(b, b) - if !a.equal(b) { - t.Fatal("2 * a == a + a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - c_1, c_2 := new(fe6).set(a), new(fe6).set(b) - field.addAssign(c_1, b) - field.addAssign(c_2, a) - if !c_1.equal(c_2) { - t.Fatal("a + b = b + a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - c_1.set(a) - c_2.set(b) - field.subAssign(c_1, b) - field.subAssign(c_2, a) - field.neg(c_2, c_2) - if !c_1.equal(c_2) { - t.Fatal("a - b = - ( b - a )") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - c, _ := new(fe6).rand(rand.Reader) - a0 := new(fe6).set(a) - field.addAssign(a, b) - field.addAssign(a, c) - field.addAssign(b, c) - field.addAssign(b, a0) - if !a.equal(b) { - t.Fatal("(a + b) + c == (b + c) + a") - } - _, _ = a.rand(rand.Reader) - _, _ = b.rand(rand.Reader) - _, _ = c.rand(rand.Reader) - a0.set(a) - field.subAssign(a, b) - field.subAssign(a, c) - field.subAssign(a0, c) - field.subAssign(a0, b) - if !a.equal(a0) { - t.Fatal("(a - b) - c == (a - c) -b") - } - } -} - -func TestFp6SparseMultiplication(t *testing.T) { - fp6 := newFp6(nil) - var a, b, u *fe6 - for j := 0; j < fuz; j++ { - a, _ = new(fe6).rand(rand.Reader) - b, _ = new(fe6).rand(rand.Reader) - u, _ = new(fe6).rand(rand.Reader) - b[2].zero() - fp6.mul(u, a, b) - fp6.mulBy01(a, a, &b[0], &b[1]) - if !a.equal(u) { - t.Fatal("bad mul by 01") - } - } - for j := 0; j < fuz; j++ { - a, _ = new(fe6).rand(rand.Reader) - b, _ = new(fe6).rand(rand.Reader) - u, _ = new(fe6).rand(rand.Reader) - b[2].zero() - b[0].zero() - fp6.mul(u, a, b) - fp6.mulBy1(a, a, &b[1]) - if !a.equal(u) { - t.Fatal("bad mul by 1") - } - } -} - -func TestFp6MultiplicationProperties(t *testing.T) { - field := newFp6(nil) - for i := 0; i < fuz; i++ { - a, _ := new(fe6).rand(rand.Reader) - b, _ := new(fe6).rand(rand.Reader) - zero := field.zero() - one := field.one() - c_1, c_2 := field.new(), field.new() - field.mul(c_1, a, zero) - if !c_1.equal(zero) { - t.Fatal("a * 0 == 0") - } - field.mul(c_1, a, one) - if !c_1.equal(a) { - t.Fatal("a * 1 == a") - } - field.mul(c_1, a, b) - field.mul(c_2, b, a) - if !c_1.equal(c_2) { - t.Fatal("a * b == b * a") - } - c_x, _ := new(fe6).rand(rand.Reader) - field.mul(c_1, a, b) - field.mul(c_1, c_1, c_x) - field.mul(c_2, c_x, b) - field.mul(c_2, c_2, a) - if !c_1.equal(c_2) { - t.Fatal("(a * b) * c == (a * c) * b") - } - field.square(a, zero) - if !a.equal(zero) { - t.Fatal("0^2 == 0") - } - field.square(a, one) - if !a.equal(one) { - t.Fatal("1^2 == 1") - } - _, _ = a.rand(rand.Reader) - field.square(c_1, a) - field.mul(c_2, a, a) - if !c_2.equal(c_1) { - t.Fatal("a^2 == a*a") - } - } -} - -func TestFp6MultiplicationPropertiesAssigned(t *testing.T) { - field := newFp6(nil) - for i := 0; i < fuz; i++ { - a, _ := new(fe6).rand(rand.Reader) - zero, one := new(fe6).zero(), new(fe6).one() - field.mulAssign(a, zero) - if !a.equal(zero) { - t.Fatal("a * 0 == 0") - } - _, _ = a.rand(rand.Reader) - a0 := new(fe6).set(a) - field.mulAssign(a, one) - if !a.equal(a0) { - t.Fatal("a * 1 == a") - } - _, _ = a.rand(rand.Reader) - b, _ := new(fe6).rand(rand.Reader) - a0.set(a) - field.mulAssign(a, b) - field.mulAssign(b, a0) - if !a.equal(b) { - t.Fatal("a * b == b * a") - } - c, _ := new(fe6).rand(rand.Reader) - a0.set(a) - field.mulAssign(a, b) - field.mulAssign(a, c) - field.mulAssign(a0, c) - field.mulAssign(a0, b) - if !a.equal(a0) { - t.Fatal("(a * b) * c == (a * c) * b") - } - } -} - -func TestFp6Exponentiation(t *testing.T) { - field := newFp6(nil) - for i := 0; i < fuz; i++ { - a, _ := new(fe6).rand(rand.Reader) - u := field.new() - field.exp(u, a, big.NewInt(0)) - if !u.equal(field.one()) { - t.Fatal("a^0 == 1") - } - field.exp(u, a, big.NewInt(1)) - if !u.equal(a) { - t.Fatal("a^1 == a") - } - v := field.new() - field.mul(u, a, a) - field.mul(u, u, u) - field.mul(u, u, u) - field.exp(v, a, big.NewInt(8)) - if !u.equal(v) { - t.Fatal("((a^2)^2)^2 == a^8") - } - } -} - -func TestFp6Inversion(t *testing.T) { - field := newFp6(nil) - for i := 0; i < fuz; i++ { - u := field.new() - zero := field.zero() - one := field.one() - field.inverse(u, zero) - if !u.equal(zero) { - t.Fatal("(0^-1) == 0)") - } - field.inverse(u, one) - if !u.equal(one) { - t.Fatal("(1^-1) == 1)") - } - a, _ := new(fe6).rand(rand.Reader) - field.inverse(u, a) - field.mul(u, u, a) - if !u.equal(one) { - t.Fatal("(r*a) * r*(a^-1) == r)") - } - } -} - -func TestFp12Serialization(t *testing.T) { - field := newFp12(nil) - for i := 0; i < fuz; i++ { - a, _ := new(fe12).rand(rand.Reader) - b, err := field.fromBytes(field.toBytes(a)) - if err != nil { - t.Fatal(err) - } - if !a.equal(b) { - t.Fatal("bad serialization") - } - } -} - -func TestFp12AdditionProperties(t *testing.T) { - field := newFp12(nil) - for i := 0; i < fuz; i++ { - zero := field.zero() - a, _ := new(fe12).rand(rand.Reader) - b, _ := new(fe12).rand(rand.Reader) - c_1 := field.new() - c_2 := field.new() - field.add(c_1, a, zero) - if !c_1.equal(a) { - t.Fatal("a + 0 == a") - } - field.sub(c_1, a, zero) - if !c_1.equal(a) { - t.Fatal("a - 0 == a") - } - field.double(c_1, zero) - if !c_1.equal(zero) { - t.Fatal("2 * 0 == 0") - } - field.neg(c_1, zero) - if !c_1.equal(zero) { - t.Fatal("-0 == 0") - } - field.sub(c_1, zero, a) - field.neg(c_2, a) - if !c_1.equal(c_2) { - t.Fatal("0-a == -a") - } - field.double(c_1, a) - field.add(c_2, a, a) - if !c_1.equal(c_2) { - t.Fatal("2 * a == a + a") - } - field.add(c_1, a, b) - field.add(c_2, b, a) - if !c_1.equal(c_2) { - t.Fatal("a + b = b + a") - } - field.sub(c_1, a, b) - field.sub(c_2, b, a) - field.neg(c_2, c_2) - if !c_1.equal(c_2) { - t.Fatal("a - b = - ( b - a )") - } - c_x, _ := new(fe12).rand(rand.Reader) - field.add(c_1, a, b) - field.add(c_1, c_1, c_x) - field.add(c_2, a, c_x) - field.add(c_2, c_2, b) - if !c_1.equal(c_2) { - t.Fatal("(a + b) + c == (a + c ) + b") - } - field.sub(c_1, a, b) - field.sub(c_1, c_1, c_x) - field.sub(c_2, a, c_x) - field.sub(c_2, c_2, b) - if !c_1.equal(c_2) { - t.Fatal("(a - b) - c == (a - c ) -b") - } - } -} - -func TestFp12MultiplicationProperties(t *testing.T) { - field := newFp12(nil) - for i := 0; i < fuz; i++ { - a, _ := new(fe12).rand(rand.Reader) - b, _ := new(fe12).rand(rand.Reader) - zero := field.zero() - one := field.one() - c_1, c_2 := field.new(), field.new() - field.mul(c_1, a, zero) - if !c_1.equal(zero) { - t.Fatal("a * 0 == 0") - } - field.mul(c_1, a, one) - if !c_1.equal(a) { - t.Fatal("a * 1 == a") - } - field.mul(c_1, a, b) - field.mul(c_2, b, a) - if !c_1.equal(c_2) { - t.Fatal("a * b == b * a") - } - c_x, _ := new(fe12).rand(rand.Reader) - field.mul(c_1, a, b) - field.mul(c_1, c_1, c_x) - field.mul(c_2, c_x, b) - field.mul(c_2, c_2, a) - if !c_1.equal(c_2) { - t.Fatal("(a * b) * c == (a * c) * b") - } - field.square(a, zero) - if !a.equal(zero) { - t.Fatal("0^2 == 0") - } - field.square(a, one) - if !a.equal(one) { - t.Fatal("1^2 == 1") - } - _, _ = a.rand(rand.Reader) - field.square(c_1, a) - field.mul(c_2, a, a) - if !c_2.equal(c_1) { - t.Fatal("a^2 == a*a") - } - } -} - -func TestFp12MultiplicationPropertiesAssigned(t *testing.T) { - field := newFp12(nil) - for i := 0; i < fuz; i++ { - a, _ := new(fe12).rand(rand.Reader) - zero, one := new(fe12).zero(), new(fe12).one() - field.mulAssign(a, zero) - if !a.equal(zero) { - t.Fatal("a * 0 == 0") - } - _, _ = a.rand(rand.Reader) - a0 := new(fe12).set(a) - field.mulAssign(a, one) - if !a.equal(a0) { - t.Fatal("a * 1 == a") - } - _, _ = a.rand(rand.Reader) - b, _ := new(fe12).rand(rand.Reader) - a0.set(a) - field.mulAssign(a, b) - field.mulAssign(b, a0) - if !a.equal(b) { - t.Fatal("a * b == b * a") - } - c, _ := new(fe12).rand(rand.Reader) - a0.set(a) - field.mulAssign(a, b) - field.mulAssign(a, c) - field.mulAssign(a0, c) - field.mulAssign(a0, b) - if !a.equal(a0) { - t.Fatal("(a * b) * c == (a * c) * b") - } - } -} - -func TestFp12SparseMultiplication(t *testing.T) { - fp12 := newFp12(nil) - var a, b, u *fe12 - for j := 0; j < fuz; j++ { - a, _ = new(fe12).rand(rand.Reader) - b, _ = new(fe12).rand(rand.Reader) - u, _ = new(fe12).rand(rand.Reader) - b[0][2].zero() - b[1][0].zero() - b[1][2].zero() - fp12.mul(u, a, b) - fp12.mulBy014Assign(a, &b[0][0], &b[0][1], &b[1][1]) - if !a.equal(u) { - t.Fatal("bad mul by 01") - } - } -} - -func TestFp12Exponentiation(t *testing.T) { - field := newFp12(nil) - for i := 0; i < fuz; i++ { - a, _ := new(fe12).rand(rand.Reader) - u := field.new() - field.exp(u, a, big.NewInt(0)) - if !u.equal(field.one()) { - t.Fatal("a^0 == 1") - } - field.exp(u, a, big.NewInt(1)) - if !u.equal(a) { - t.Fatal("a^1 == a") - } - v := field.new() - field.mul(u, a, a) - field.mul(u, u, u) - field.mul(u, u, u) - field.exp(v, a, big.NewInt(8)) - if !u.equal(v) { - t.Fatal("((a^2)^2)^2 == a^8") - } - } -} - -func TestFp12Inversion(t *testing.T) { - field := newFp12(nil) - for i := 0; i < fuz; i++ { - u := field.new() - zero := field.zero() - one := field.one() - field.inverse(u, zero) - if !u.equal(zero) { - t.Fatal("(0^-1) == 0)") - } - field.inverse(u, one) - if !u.equal(one) { - t.Fatal("(1^-1) == 1)") - } - a, _ := new(fe12).rand(rand.Reader) - field.inverse(u, a) - field.mul(u, u, a) - if !u.equal(one) { - t.Fatal("(r*a) * r*(a^-1) == r)") - } - } -} - -func BenchmarkMultiplication(t *testing.B) { - a, _ := new(fe).rand(rand.Reader) - b, _ := new(fe).rand(rand.Reader) - c, _ := new(fe).rand(rand.Reader) - t.ResetTimer() - for i := 0; i < t.N; i++ { - mul(c, a, b) - } -} - -func BenchmarkInverse(t *testing.B) { - a, _ := new(fe).rand(rand.Reader) - b, _ := new(fe).rand(rand.Reader) - t.ResetTimer() - for i := 0; i < t.N; i++ { - inverse(a, b) - } -} - -func padBytes(in []byte, size int) []byte { - out := make([]byte, size) - if len(in) > size { - panic("bad input for padding") - } - copy(out[size-len(in):], in) - return out -} diff --git a/crypto/bls12381/g1.go b/crypto/bls12381/g1.go deleted file mode 100644 index bcb898027ad8..000000000000 --- a/crypto/bls12381/g1.go +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright 2020 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 bls12381 - -import ( - "errors" - "math" - "math/big" -) - -// PointG1 is type for point in G1. -// PointG1 is both used for Affine and Jacobian point representation. -// If z is equal to one the point is considered as in affine form. -type PointG1 [3]fe - -func (p *PointG1) Set(p2 *PointG1) *PointG1 { - p[0].set(&p2[0]) - p[1].set(&p2[1]) - p[2].set(&p2[2]) - return p -} - -// Zero returns G1 point in point at infinity representation -func (p *PointG1) Zero() *PointG1 { - p[0].zero() - p[1].one() - p[2].zero() - return p -} - -type tempG1 struct { - t [9]*fe -} - -// G1 is struct for G1 group. -type G1 struct { - tempG1 -} - -// NewG1 constructs a new G1 instance. -func NewG1() *G1 { - t := newTempG1() - return &G1{t} -} - -func newTempG1() tempG1 { - t := [9]*fe{} - for i := 0; i < 9; i++ { - t[i] = &fe{} - } - return tempG1{t} -} - -// Q returns group order in big.Int. -func (g *G1) Q() *big.Int { - return new(big.Int).Set(q) -} - -func (g *G1) fromBytesUnchecked(in []byte) (*PointG1, error) { - p0, err := fromBytes(in[:48]) - if err != nil { - return nil, err - } - p1, err := fromBytes(in[48:]) - if err != nil { - return nil, err - } - p2 := new(fe).one() - return &PointG1{*p0, *p1, *p2}, nil -} - -// FromBytes constructs a new point given uncompressed byte input. -// FromBytes does not take zcash flags into account. -// Byte input expected to be larger than 96 bytes. -// First 96 bytes should be concatenation of x and y values. -// Point (0, 0) is considered as infinity. -func (g *G1) FromBytes(in []byte) (*PointG1, error) { - if len(in) != 96 { - return nil, errors.New("input string should be equal or larger than 96") - } - p0, err := fromBytes(in[:48]) - if err != nil { - return nil, err - } - p1, err := fromBytes(in[48:]) - if err != nil { - return nil, err - } - // check if given input points to infinity - if p0.isZero() && p1.isZero() { - return g.Zero(), nil - } - p2 := new(fe).one() - p := &PointG1{*p0, *p1, *p2} - if !g.IsOnCurve(p) { - return nil, errors.New("point is not on curve") - } - return p, nil -} - -// DecodePoint given encoded (x, y) coordinates in 128 bytes returns a valid G1 Point. -func (g *G1) DecodePoint(in []byte) (*PointG1, error) { - if len(in) != 128 { - return nil, errors.New("invalid g1 point length") - } - pointBytes := make([]byte, 96) - // decode x - xBytes, err := decodeFieldElement(in[:64]) - if err != nil { - return nil, err - } - // decode y - yBytes, err := decodeFieldElement(in[64:]) - if err != nil { - return nil, err - } - copy(pointBytes[:48], xBytes) - copy(pointBytes[48:], yBytes) - return g.FromBytes(pointBytes) -} - -// ToBytes serializes a point into bytes in uncompressed form. -// ToBytes does not take zcash flags into account. -// ToBytes returns (0, 0) if point is infinity. -func (g *G1) ToBytes(p *PointG1) []byte { - out := make([]byte, 96) - if g.IsZero(p) { - return out - } - g.Affine(p) - copy(out[:48], toBytes(&p[0])) - copy(out[48:], toBytes(&p[1])) - return out -} - -// EncodePoint encodes a point into 128 bytes. -func (g *G1) EncodePoint(p *PointG1) []byte { - outRaw := g.ToBytes(p) - out := make([]byte, 128) - // encode x - copy(out[16:], outRaw[:48]) - // encode y - copy(out[64+16:], outRaw[48:]) - return out -} - -// New creates a new G1 Point which is equal to zero in other words point at infinity. -func (g *G1) New() *PointG1 { - return g.Zero() -} - -// Zero returns a new G1 Point which is equal to point at infinity. -func (g *G1) Zero() *PointG1 { - return new(PointG1).Zero() -} - -// One returns a new G1 Point which is equal to generator point. -func (g *G1) One() *PointG1 { - p := &PointG1{} - return p.Set(&g1One) -} - -// IsZero returns true if given point is equal to zero. -func (g *G1) IsZero(p *PointG1) bool { - return p[2].isZero() -} - -// Equal checks if given two G1 point is equal in their affine form. -func (g *G1) Equal(p1, p2 *PointG1) bool { - if g.IsZero(p1) { - return g.IsZero(p2) - } - if g.IsZero(p2) { - return g.IsZero(p1) - } - t := g.t - square(t[0], &p1[2]) - square(t[1], &p2[2]) - mul(t[2], t[0], &p2[0]) - mul(t[3], t[1], &p1[0]) - mul(t[0], t[0], &p1[2]) - mul(t[1], t[1], &p2[2]) - mul(t[1], t[1], &p1[1]) - mul(t[0], t[0], &p2[1]) - return t[0].equal(t[1]) && t[2].equal(t[3]) -} - -// InCorrectSubgroup checks whether given point is in correct subgroup. -func (g *G1) InCorrectSubgroup(p *PointG1) bool { - tmp := &PointG1{} - g.MulScalar(tmp, p, q) - return g.IsZero(tmp) -} - -// IsOnCurve checks a G1 point is on curve. -func (g *G1) IsOnCurve(p *PointG1) bool { - if g.IsZero(p) { - return true - } - t := g.t - square(t[0], &p[1]) - square(t[1], &p[0]) - mul(t[1], t[1], &p[0]) - square(t[2], &p[2]) - square(t[3], t[2]) - mul(t[2], t[2], t[3]) - mul(t[2], b, t[2]) - add(t[1], t[1], t[2]) - return t[0].equal(t[1]) -} - -// IsAffine checks a G1 point whether it is in affine form. -func (g *G1) IsAffine(p *PointG1) bool { - return p[2].isOne() -} - -// Affine calculates affine form of given G1 point. -func (g *G1) Affine(p *PointG1) *PointG1 { - if g.IsZero(p) { - return p - } - if !g.IsAffine(p) { - t := g.t - inverse(t[0], &p[2]) - square(t[1], t[0]) - mul(&p[0], &p[0], t[1]) - mul(t[0], t[0], t[1]) - mul(&p[1], &p[1], t[0]) - p[2].one() - } - return p -} - -// Add adds two G1 points p1, p2 and assigns the result to point at first argument. -func (g *G1) Add(r, p1, p2 *PointG1) *PointG1 { - // www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl - if g.IsZero(p1) { - return r.Set(p2) - } - if g.IsZero(p2) { - return r.Set(p1) - } - t := g.t - square(t[7], &p1[2]) - mul(t[1], &p2[0], t[7]) - mul(t[2], &p1[2], t[7]) - mul(t[0], &p2[1], t[2]) - square(t[8], &p2[2]) - mul(t[3], &p1[0], t[8]) - mul(t[4], &p2[2], t[8]) - mul(t[2], &p1[1], t[4]) - if t[1].equal(t[3]) { - if t[0].equal(t[2]) { - return g.Double(r, p1) - } - return r.Zero() - } - sub(t[1], t[1], t[3]) - double(t[4], t[1]) - square(t[4], t[4]) - mul(t[5], t[1], t[4]) - sub(t[0], t[0], t[2]) - double(t[0], t[0]) - square(t[6], t[0]) - sub(t[6], t[6], t[5]) - mul(t[3], t[3], t[4]) - double(t[4], t[3]) - sub(&r[0], t[6], t[4]) - sub(t[4], t[3], &r[0]) - mul(t[6], t[2], t[5]) - double(t[6], t[6]) - mul(t[0], t[0], t[4]) - sub(&r[1], t[0], t[6]) - add(t[0], &p1[2], &p2[2]) - square(t[0], t[0]) - sub(t[0], t[0], t[7]) - sub(t[0], t[0], t[8]) - mul(&r[2], t[0], t[1]) - return r -} - -// Double doubles a G1 point p and assigns the result to the point at first argument. -func (g *G1) Double(r, p *PointG1) *PointG1 { - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l - if g.IsZero(p) { - return r.Set(p) - } - t := g.t - square(t[0], &p[0]) - square(t[1], &p[1]) - square(t[2], t[1]) - add(t[1], &p[0], t[1]) - square(t[1], t[1]) - sub(t[1], t[1], t[0]) - sub(t[1], t[1], t[2]) - double(t[1], t[1]) - double(t[3], t[0]) - add(t[0], t[3], t[0]) - square(t[4], t[0]) - double(t[3], t[1]) - sub(&r[0], t[4], t[3]) - sub(t[1], t[1], &r[0]) - double(t[2], t[2]) - double(t[2], t[2]) - double(t[2], t[2]) - mul(t[0], t[0], t[1]) - sub(t[1], t[0], t[2]) - mul(t[0], &p[1], &p[2]) - r[1].set(t[1]) - double(&r[2], t[0]) - return r -} - -// Neg negates a G1 point p and assigns the result to the point at first argument. -func (g *G1) Neg(r, p *PointG1) *PointG1 { - r[0].set(&p[0]) - r[2].set(&p[2]) - neg(&r[1], &p[1]) - return r -} - -// Sub subtracts two G1 points p1, p2 and assigns the result to point at first argument. -func (g *G1) Sub(c, a, b *PointG1) *PointG1 { - d := &PointG1{} - g.Neg(d, b) - g.Add(c, a, d) - return c -} - -// MulScalar multiplies a point by given scalar value in big.Int and assigns the result to point at first argument. -func (g *G1) MulScalar(c, p *PointG1, e *big.Int) *PointG1 { - q, n := &PointG1{}, &PointG1{} - n.Set(p) - l := e.BitLen() - for i := 0; i < l; i++ { - if e.Bit(i) == 1 { - g.Add(q, q, n) - } - g.Double(n, n) - } - return c.Set(q) -} - -// ClearCofactor maps given a G1 point to correct subgroup -func (g *G1) ClearCofactor(p *PointG1) { - g.MulScalar(p, p, cofactorEFFG1) -} - -// MultiExp calculates multi exponentiation. Given pairs of G1 point and scalar values -// (P_0, e_0), (P_1, e_1), ... (P_n, e_n) calculates r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n -// Length of points and scalars are expected to be equal, otherwise an error is returned. -// Result is assigned to point at first argument. -func (g *G1) MultiExp(r *PointG1, points []*PointG1, powers []*big.Int) (*PointG1, error) { - if len(points) != len(powers) { - return nil, errors.New("point and scalar vectors should be in same length") - } - var c uint32 = 3 - if len(powers) >= 32 { - c = uint32(math.Ceil(math.Log10(float64(len(powers))))) - } - bucketSize, numBits := (1<= 0; i-- { - g.Add(sum, sum, bucket[i]) - g.Add(acc, acc, sum) - } - windows[j] = g.New() - windows[j].Set(acc) - j++ - cur += c - } - acc.Zero() - for i := len(windows) - 1; i >= 0; i-- { - for j := uint32(0); j < c; j++ { - g.Double(acc, acc) - } - g.Add(acc, acc, windows[i]) - } - return r.Set(acc), nil -} - -// MapToCurve given a byte slice returns a valid G1 point. -// This mapping function implements the Simplified Shallue-van de Woestijne-Ulas method. -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06 -// Input byte slice should be a valid field element, otherwise an error is returned. -func (g *G1) MapToCurve(in []byte) (*PointG1, error) { - u, err := fromBytes(in) - if err != nil { - return nil, err - } - x, y := swuMapG1(u) - isogenyMapG1(x, y) - one := new(fe).one() - p := &PointG1{*x, *y, *one} - g.ClearCofactor(p) - return g.Affine(p), nil -} diff --git a/crypto/bls12381/g1_test.go b/crypto/bls12381/g1_test.go deleted file mode 100644 index 87140459fbc5..000000000000 --- a/crypto/bls12381/g1_test.go +++ /dev/null @@ -1,284 +0,0 @@ -package bls12381 - -import ( - "bytes" - "crypto/rand" - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -func (g *G1) one() *PointG1 { - one, _ := g.fromBytesUnchecked( - common.FromHex("" + - "17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" + - "08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", - ), - ) - return one -} - -func (g *G1) rand() *PointG1 { - k, err := rand.Int(rand.Reader, q) - if err != nil { - panic(err) - } - return g.MulScalar(&PointG1{}, g.one(), k) -} - -func TestG1Serialization(t *testing.T) { - g1 := NewG1() - for i := 0; i < fuz; i++ { - a := g1.rand() - buf := g1.ToBytes(a) - b, err := g1.FromBytes(buf) - if err != nil { - t.Fatal(err) - } - if !g1.Equal(a, b) { - t.Fatal("bad serialization from/to") - } - } - for i := 0; i < fuz; i++ { - a := g1.rand() - encoded := g1.EncodePoint(a) - b, err := g1.DecodePoint(encoded) - if err != nil { - t.Fatal(err) - } - if !g1.Equal(a, b) { - t.Fatal("bad serialization encode/decode") - } - } -} - -func TestG1IsOnCurve(t *testing.T) { - g := NewG1() - zero := g.Zero() - if !g.IsOnCurve(zero) { - t.Fatal("zero must be on curve") - } - one := new(fe).one() - p := &PointG1{*one, *one, *one} - if g.IsOnCurve(p) { - t.Fatal("(1, 1) is not on curve") - } -} - -func TestG1AdditiveProperties(t *testing.T) { - g := NewG1() - t0, t1 := g.New(), g.New() - zero := g.Zero() - for i := 0; i < fuz; i++ { - a, b := g.rand(), g.rand() - g.Add(t0, a, zero) - if !g.Equal(t0, a) { - t.Fatal("a + 0 == a") - } - g.Add(t0, zero, zero) - if !g.Equal(t0, zero) { - t.Fatal("0 + 0 == 0") - } - g.Sub(t0, a, zero) - if !g.Equal(t0, a) { - t.Fatal("a - 0 == a") - } - g.Sub(t0, zero, zero) - if !g.Equal(t0, zero) { - t.Fatal("0 - 0 == 0") - } - g.Neg(t0, zero) - if !g.Equal(t0, zero) { - t.Fatal("- 0 == 0") - } - g.Sub(t0, zero, a) - g.Neg(t0, t0) - if !g.Equal(t0, a) { - t.Fatal(" - (0 - a) == a") - } - g.Double(t0, zero) - if !g.Equal(t0, zero) { - t.Fatal("2 * 0 == 0") - } - g.Double(t0, a) - g.Sub(t0, t0, a) - if !g.Equal(t0, a) || !g.IsOnCurve(t0) { - t.Fatal(" (2 * a) - a == a") - } - g.Add(t0, a, b) - g.Add(t1, b, a) - if !g.Equal(t0, t1) { - t.Fatal("a + b == b + a") - } - g.Sub(t0, a, b) - g.Sub(t1, b, a) - g.Neg(t1, t1) - if !g.Equal(t0, t1) { - t.Fatal("a - b == - ( b - a )") - } - c := g.rand() - g.Add(t0, a, b) - g.Add(t0, t0, c) - g.Add(t1, a, c) - g.Add(t1, t1, b) - if !g.Equal(t0, t1) { - t.Fatal("(a + b) + c == (a + c ) + b") - } - g.Sub(t0, a, b) - g.Sub(t0, t0, c) - g.Sub(t1, a, c) - g.Sub(t1, t1, b) - if !g.Equal(t0, t1) { - t.Fatal("(a - b) - c == (a - c) -b") - } - } -} - -func TestG1MultiplicativeProperties(t *testing.T) { - g := NewG1() - t0, t1 := g.New(), g.New() - zero := g.Zero() - for i := 0; i < fuz; i++ { - a := g.rand() - s1, s2, s3 := randScalar(q), randScalar(q), randScalar(q) - sone := big.NewInt(1) - g.MulScalar(t0, zero, s1) - if !g.Equal(t0, zero) { - t.Fatal(" 0 ^ s == 0") - } - g.MulScalar(t0, a, sone) - if !g.Equal(t0, a) { - t.Fatal(" a ^ 1 == a") - } - g.MulScalar(t0, zero, s1) - if !g.Equal(t0, zero) { - t.Fatal(" 0 ^ s == a") - } - g.MulScalar(t0, a, s1) - g.MulScalar(t0, t0, s2) - s3.Mul(s1, s2) - g.MulScalar(t1, a, s3) - if !g.Equal(t0, t1) { - t.Errorf(" (a ^ s1) ^ s2 == a ^ (s1 * s2)") - } - g.MulScalar(t0, a, s1) - g.MulScalar(t1, a, s2) - g.Add(t0, t0, t1) - s3.Add(s1, s2) - g.MulScalar(t1, a, s3) - if !g.Equal(t0, t1) { - t.Errorf(" (a ^ s1) + (a ^ s2) == a ^ (s1 + s2)") - } - } -} - -func TestG1MultiExpExpected(t *testing.T) { - g := NewG1() - one := g.one() - var scalars [2]*big.Int - var bases [2]*PointG1 - scalars[0] = big.NewInt(2) - scalars[1] = big.NewInt(3) - bases[0], bases[1] = new(PointG1).Set(one), new(PointG1).Set(one) - expected, result := g.New(), g.New() - g.MulScalar(expected, one, big.NewInt(5)) - _, _ = g.MultiExp(result, bases[:], scalars[:]) - if !g.Equal(expected, result) { - t.Fatal("bad multi-exponentiation") - } -} - -func TestG1MultiExpBatch(t *testing.T) { - g := NewG1() - one := g.one() - n := 1000 - bases := make([]*PointG1, n) - scalars := make([]*big.Int, n) - // scalars: [s0,s1 ... s(n-1)] - // bases: [P0,P1,..P(n-1)] = [s(n-1)*G, s(n-2)*G ... s0*G] - for i, j := 0, n-1; i < n; i, j = i+1, j-1 { - scalars[j], _ = rand.Int(rand.Reader, big.NewInt(100000)) - bases[i] = g.New() - g.MulScalar(bases[i], one, scalars[j]) - } - // expected: s(n-1)*P0 + s(n-2)*P1 + s0*P(n-1) - expected, tmp := g.New(), g.New() - for i := 0; i < n; i++ { - g.MulScalar(tmp, bases[i], scalars[i]) - g.Add(expected, expected, tmp) - } - result := g.New() - _, _ = g.MultiExp(result, bases, scalars) - if !g.Equal(expected, result) { - t.Fatal("bad multi-exponentiation") - } -} - -func TestG1MapToCurve(t *testing.T) { - for i, v := range []struct { - u []byte - expected []byte - }{ - { - u: make([]byte, 48), - expected: common.FromHex("11a9a0372b8f332d5c30de9ad14e50372a73fa4c45d5f2fa5097f2d6fb93bcac592f2e1711ac43db0519870c7d0ea415" + "092c0f994164a0719f51c24ba3788de240ff926b55f58c445116e8bc6a47cd63392fd4e8e22bdf9feaa96ee773222133"), - }, - { - u: common.FromHex("07fdf49ea58e96015d61f6b5c9d1c8f277146a533ae7fbca2a8ef4c41055cd961fbc6e26979b5554e4b4f22330c0e16d"), - expected: common.FromHex("1223effdbb2d38152495a864d78eee14cb0992d89a241707abb03819a91a6d2fd65854ab9a69e9aacb0cbebfd490732c" + "0f925d61e0b235ecd945cbf0309291878df0d06e5d80d6b84aa4ff3e00633b26f9a7cb3523ef737d90e6d71e8b98b2d5"), - }, - { - u: common.FromHex("1275ab3adbf824a169ed4b1fd669b49cf406d822f7fe90d6b2f8c601b5348436f89761bb1ad89a6fb1137cd91810e5d2"), - expected: common.FromHex("179d3fd0b4fb1da43aad06cea1fb3f828806ddb1b1fa9424b1e3944dfdbab6e763c42636404017da03099af0dcca0fd6" + "0d037cb1c6d495c0f5f22b061d23f1be3d7fe64d3c6820cfcd99b6b36fa69f7b4c1f4addba2ae7aa46fb25901ab483e4"), - }, - { - u: common.FromHex("0e93d11d30de6d84b8578827856f5c05feef36083eef0b7b263e35ecb9b56e86299614a042e57d467fa20948e8564909"), - expected: common.FromHex("15aa66c77eded1209db694e8b1ba49daf8b686733afaa7b68c683d0b01788dfb0617a2e2d04c0856db4981921d3004af" + "0952bb2f61739dd1d201dd0a79d74cda3285403d47655ee886afe860593a8a4e51c5b77a22d2133e3a4280eaaaa8b788"), - }, - { - u: common.FromHex("015a41481155d17074d20be6d8ec4d46632a51521cd9c916e265bd9b47343b3689979b50708c8546cbc2916b86cb1a3a"), - expected: common.FromHex("06328ce5106e837935e8da84bd9af473422e62492930aa5f460369baad9545defa468d9399854c23a75495d2a80487ee" + "094bfdfe3e552447433b5a00967498a3f1314b86ce7a7164c8a8f4131f99333b30a574607e301d5f774172c627fd0bca"), - }, - } { - g := NewG1() - p0, err := g.MapToCurve(v.u) - if err != nil { - t.Fatal("map to curve fails", i, err) - } - if !bytes.Equal(g.ToBytes(p0), v.expected) { - t.Fatal("map to curve fails", i) - } - } -} - -func BenchmarkG1Add(t *testing.B) { - g1 := NewG1() - a, b, c := g1.rand(), g1.rand(), PointG1{} - t.ResetTimer() - for i := 0; i < t.N; i++ { - g1.Add(&c, a, b) - } -} - -func BenchmarkG1Mul(t *testing.B) { - worstCaseScalar, _ := new(big.Int).SetString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16) - g1 := NewG1() - a, e, c := g1.rand(), worstCaseScalar, PointG1{} - t.ResetTimer() - for i := 0; i < t.N; i++ { - g1.MulScalar(&c, a, e) - } -} - -func BenchmarkG1MapToCurve(t *testing.B) { - a := make([]byte, 48) - g1 := NewG1() - t.ResetTimer() - for i := 0; i < t.N; i++ { - _, err := g1.MapToCurve(a) - if err != nil { - t.Fatal(err) - } - } -} diff --git a/crypto/bls12381/g2.go b/crypto/bls12381/g2.go deleted file mode 100644 index b942bf94fddf..000000000000 --- a/crypto/bls12381/g2.go +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright 2020 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 bls12381 - -import ( - "errors" - "math" - "math/big" -) - -// PointG2 is type for point in G2. -// PointG2 is both used for Affine and Jacobian point representation. -// If z is equal to one the point is considered as in affine form. -type PointG2 [3]fe2 - -// Set copies values of one point to another. -func (p *PointG2) Set(p2 *PointG2) *PointG2 { - p[0].set(&p2[0]) - p[1].set(&p2[1]) - p[2].set(&p2[2]) - return p -} - -// Zero returns G2 point in point at infinity representation -func (p *PointG2) Zero() *PointG2 { - p[0].zero() - p[1].one() - p[2].zero() - return p -} - -type tempG2 struct { - t [9]*fe2 -} - -// G2 is struct for G2 group. -type G2 struct { - f *fp2 - tempG2 -} - -// NewG2 constructs a new G2 instance. -func NewG2() *G2 { - return newG2(nil) -} - -func newG2(f *fp2) *G2 { - if f == nil { - f = newFp2() - } - t := newTempG2() - return &G2{f, t} -} - -func newTempG2() tempG2 { - t := [9]*fe2{} - for i := 0; i < 9; i++ { - t[i] = &fe2{} - } - return tempG2{t} -} - -// Q returns group order in big.Int. -func (g *G2) Q() *big.Int { - return new(big.Int).Set(q) -} - -func (g *G2) fromBytesUnchecked(in []byte) (*PointG2, error) { - p0, err := g.f.fromBytes(in[:96]) - if err != nil { - return nil, err - } - p1, err := g.f.fromBytes(in[96:]) - if err != nil { - return nil, err - } - p2 := new(fe2).one() - return &PointG2{*p0, *p1, *p2}, nil -} - -// FromBytes constructs a new point given uncompressed byte input. -// FromBytes does not take zcash flags into account. -// Byte input expected to be larger than 96 bytes. -// First 192 bytes should be concatenation of x and y values -// Point (0, 0) is considered as infinity. -func (g *G2) FromBytes(in []byte) (*PointG2, error) { - if len(in) != 192 { - return nil, errors.New("input string should be equal or larger than 192") - } - p0, err := g.f.fromBytes(in[:96]) - if err != nil { - return nil, err - } - p1, err := g.f.fromBytes(in[96:]) - if err != nil { - return nil, err - } - // check if given input points to infinity - if p0.isZero() && p1.isZero() { - return g.Zero(), nil - } - p2 := new(fe2).one() - p := &PointG2{*p0, *p1, *p2} - if !g.IsOnCurve(p) { - return nil, errors.New("point is not on curve") - } - return p, nil -} - -// DecodePoint given encoded (x, y) coordinates in 256 bytes returns a valid G2 Point. -func (g *G2) DecodePoint(in []byte) (*PointG2, error) { - if len(in) != 256 { - return nil, errors.New("invalid g2 point length") - } - pointBytes := make([]byte, 192) - x0Bytes, err := decodeFieldElement(in[:64]) - if err != nil { - return nil, err - } - x1Bytes, err := decodeFieldElement(in[64:128]) - if err != nil { - return nil, err - } - y0Bytes, err := decodeFieldElement(in[128:192]) - if err != nil { - return nil, err - } - y1Bytes, err := decodeFieldElement(in[192:]) - if err != nil { - return nil, err - } - copy(pointBytes[:48], x1Bytes) - copy(pointBytes[48:96], x0Bytes) - copy(pointBytes[96:144], y1Bytes) - copy(pointBytes[144:192], y0Bytes) - return g.FromBytes(pointBytes) -} - -// ToBytes serializes a point into bytes in uncompressed form, -// does not take zcash flags into account, -// returns (0, 0) if point is infinity. -func (g *G2) ToBytes(p *PointG2) []byte { - out := make([]byte, 192) - if g.IsZero(p) { - return out - } - g.Affine(p) - copy(out[:96], g.f.toBytes(&p[0])) - copy(out[96:], g.f.toBytes(&p[1])) - return out -} - -// EncodePoint encodes a point into 256 bytes. -func (g *G2) EncodePoint(p *PointG2) []byte { - // outRaw is 96 bytes - outRaw := g.ToBytes(p) - out := make([]byte, 256) - // encode x - copy(out[16:16+48], outRaw[48:96]) - copy(out[80:80+48], outRaw[:48]) - // encode y - copy(out[144:144+48], outRaw[144:]) - copy(out[208:208+48], outRaw[96:144]) - return out -} - -// New creates a new G2 Point which is equal to zero in other words point at infinity. -func (g *G2) New() *PointG2 { - return new(PointG2).Zero() -} - -// Zero returns a new G2 Point which is equal to point at infinity. -func (g *G2) Zero() *PointG2 { - return new(PointG2).Zero() -} - -// One returns a new G2 Point which is equal to generator point. -func (g *G2) One() *PointG2 { - p := &PointG2{} - return p.Set(&g2One) -} - -// IsZero returns true if given point is equal to zero. -func (g *G2) IsZero(p *PointG2) bool { - return p[2].isZero() -} - -// Equal checks if given two G2 point is equal in their affine form. -func (g *G2) Equal(p1, p2 *PointG2) bool { - if g.IsZero(p1) { - return g.IsZero(p2) - } - if g.IsZero(p2) { - return g.IsZero(p1) - } - t := g.t - g.f.square(t[0], &p1[2]) - g.f.square(t[1], &p2[2]) - g.f.mul(t[2], t[0], &p2[0]) - g.f.mul(t[3], t[1], &p1[0]) - g.f.mul(t[0], t[0], &p1[2]) - g.f.mul(t[1], t[1], &p2[2]) - g.f.mul(t[1], t[1], &p1[1]) - g.f.mul(t[0], t[0], &p2[1]) - return t[0].equal(t[1]) && t[2].equal(t[3]) -} - -// InCorrectSubgroup checks whether given point is in correct subgroup. -func (g *G2) InCorrectSubgroup(p *PointG2) bool { - tmp := &PointG2{} - g.MulScalar(tmp, p, q) - return g.IsZero(tmp) -} - -// IsOnCurve checks a G2 point is on curve. -func (g *G2) IsOnCurve(p *PointG2) bool { - if g.IsZero(p) { - return true - } - t := g.t - g.f.square(t[0], &p[1]) - g.f.square(t[1], &p[0]) - g.f.mul(t[1], t[1], &p[0]) - g.f.square(t[2], &p[2]) - g.f.square(t[3], t[2]) - g.f.mul(t[2], t[2], t[3]) - g.f.mul(t[2], b2, t[2]) - g.f.add(t[1], t[1], t[2]) - return t[0].equal(t[1]) -} - -// IsAffine checks a G2 point whether it is in affine form. -func (g *G2) IsAffine(p *PointG2) bool { - return p[2].isOne() -} - -// Affine calculates affine form of given G2 point. -func (g *G2) Affine(p *PointG2) *PointG2 { - if g.IsZero(p) { - return p - } - if !g.IsAffine(p) { - t := g.t - g.f.inverse(t[0], &p[2]) - g.f.square(t[1], t[0]) - g.f.mul(&p[0], &p[0], t[1]) - g.f.mul(t[0], t[0], t[1]) - g.f.mul(&p[1], &p[1], t[0]) - p[2].one() - } - return p -} - -// Add adds two G2 points p1, p2 and assigns the result to point at first argument. -func (g *G2) Add(r, p1, p2 *PointG2) *PointG2 { - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl - if g.IsZero(p1) { - return r.Set(p2) - } - if g.IsZero(p2) { - return r.Set(p1) - } - t := g.t - g.f.square(t[7], &p1[2]) - g.f.mul(t[1], &p2[0], t[7]) - g.f.mul(t[2], &p1[2], t[7]) - g.f.mul(t[0], &p2[1], t[2]) - g.f.square(t[8], &p2[2]) - g.f.mul(t[3], &p1[0], t[8]) - g.f.mul(t[4], &p2[2], t[8]) - g.f.mul(t[2], &p1[1], t[4]) - if t[1].equal(t[3]) { - if t[0].equal(t[2]) { - return g.Double(r, p1) - } - return r.Zero() - } - g.f.sub(t[1], t[1], t[3]) - g.f.double(t[4], t[1]) - g.f.square(t[4], t[4]) - g.f.mul(t[5], t[1], t[4]) - g.f.sub(t[0], t[0], t[2]) - g.f.double(t[0], t[0]) - g.f.square(t[6], t[0]) - g.f.sub(t[6], t[6], t[5]) - g.f.mul(t[3], t[3], t[4]) - g.f.double(t[4], t[3]) - g.f.sub(&r[0], t[6], t[4]) - g.f.sub(t[4], t[3], &r[0]) - g.f.mul(t[6], t[2], t[5]) - g.f.double(t[6], t[6]) - g.f.mul(t[0], t[0], t[4]) - g.f.sub(&r[1], t[0], t[6]) - g.f.add(t[0], &p1[2], &p2[2]) - g.f.square(t[0], t[0]) - g.f.sub(t[0], t[0], t[7]) - g.f.sub(t[0], t[0], t[8]) - g.f.mul(&r[2], t[0], t[1]) - return r -} - -// Double doubles a G2 point p and assigns the result to the point at first argument. -func (g *G2) Double(r, p *PointG2) *PointG2 { - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l - if g.IsZero(p) { - return r.Set(p) - } - t := g.t - g.f.square(t[0], &p[0]) - g.f.square(t[1], &p[1]) - g.f.square(t[2], t[1]) - g.f.add(t[1], &p[0], t[1]) - g.f.square(t[1], t[1]) - g.f.sub(t[1], t[1], t[0]) - g.f.sub(t[1], t[1], t[2]) - g.f.double(t[1], t[1]) - g.f.double(t[3], t[0]) - g.f.add(t[0], t[3], t[0]) - g.f.square(t[4], t[0]) - g.f.double(t[3], t[1]) - g.f.sub(&r[0], t[4], t[3]) - g.f.sub(t[1], t[1], &r[0]) - g.f.double(t[2], t[2]) - g.f.double(t[2], t[2]) - g.f.double(t[2], t[2]) - g.f.mul(t[0], t[0], t[1]) - g.f.sub(t[1], t[0], t[2]) - g.f.mul(t[0], &p[1], &p[2]) - r[1].set(t[1]) - g.f.double(&r[2], t[0]) - return r -} - -// Neg negates a G2 point p and assigns the result to the point at first argument. -func (g *G2) Neg(r, p *PointG2) *PointG2 { - r[0].set(&p[0]) - g.f.neg(&r[1], &p[1]) - r[2].set(&p[2]) - return r -} - -// Sub subtracts two G2 points p1, p2 and assigns the result to point at first argument. -func (g *G2) Sub(c, a, b *PointG2) *PointG2 { - d := &PointG2{} - g.Neg(d, b) - g.Add(c, a, d) - return c -} - -// MulScalar multiplies a point by given scalar value in big.Int and assigns the result to point at first argument. -func (g *G2) MulScalar(c, p *PointG2, e *big.Int) *PointG2 { - q, n := &PointG2{}, &PointG2{} - n.Set(p) - l := e.BitLen() - for i := 0; i < l; i++ { - if e.Bit(i) == 1 { - g.Add(q, q, n) - } - g.Double(n, n) - } - return c.Set(q) -} - -// ClearCofactor maps given a G2 point to correct subgroup -func (g *G2) ClearCofactor(p *PointG2) { - g.MulScalar(p, p, cofactorEFFG2) -} - -// MultiExp calculates multi exponentiation. Given pairs of G2 point and scalar values -// (P_0, e_0), (P_1, e_1), ... (P_n, e_n) calculates r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n -// Length of points and scalars are expected to be equal, otherwise an error is returned. -// Result is assigned to point at first argument. -func (g *G2) MultiExp(r *PointG2, points []*PointG2, powers []*big.Int) (*PointG2, error) { - if len(points) != len(powers) { - return nil, errors.New("point and scalar vectors should be in same length") - } - var c uint32 = 3 - if len(powers) >= 32 { - c = uint32(math.Ceil(math.Log10(float64(len(powers))))) - } - bucketSize, numBits := (1<= 0; i-- { - g.Add(sum, sum, bucket[i]) - g.Add(acc, acc, sum) - } - windows[j] = g.New() - windows[j].Set(acc) - j++ - cur += c - } - acc.Zero() - for i := len(windows) - 1; i >= 0; i-- { - for j := uint32(0); j < c; j++ { - g.Double(acc, acc) - } - g.Add(acc, acc, windows[i]) - } - return r.Set(acc), nil -} - -// MapToCurve given a byte slice returns a valid G2 point. -// This mapping function implements the Simplified Shallue-van de Woestijne-Ulas method. -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-6.6.2 -// Input byte slice should be a valid field element, otherwise an error is returned. -func (g *G2) MapToCurve(in []byte) (*PointG2, error) { - fp2 := g.f - u, err := fp2.fromBytes(in) - if err != nil { - return nil, err - } - x, y := swuMapG2(fp2, u) - isogenyMapG2(fp2, x, y) - z := new(fe2).one() - q := &PointG2{*x, *y, *z} - g.ClearCofactor(q) - return g.Affine(q), nil -} diff --git a/crypto/bls12381/g2_test.go b/crypto/bls12381/g2_test.go deleted file mode 100644 index 4d1f3a19ac67..000000000000 --- a/crypto/bls12381/g2_test.go +++ /dev/null @@ -1,287 +0,0 @@ -package bls12381 - -import ( - "bytes" - "crypto/rand" - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -func (g *G2) one() *PointG2 { - one, _ := g.fromBytesUnchecked( - common.FromHex("" + - "13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e" + - "024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8" + - "0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be" + - "0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801", - ), - ) - return one -} - -func (g *G2) rand() *PointG2 { - k, err := rand.Int(rand.Reader, q) - if err != nil { - panic(err) - } - return g.MulScalar(&PointG2{}, g.one(), k) -} - -func TestG2Serialization(t *testing.T) { - g2 := NewG2() - for i := 0; i < fuz; i++ { - a := g2.rand() - buf := g2.ToBytes(a) - b, err := g2.FromBytes(buf) - if err != nil { - t.Fatal(err) - } - if !g2.Equal(a, b) { - t.Fatal("bad serialization from/to") - } - } - for i := 0; i < fuz; i++ { - a := g2.rand() - encoded := g2.EncodePoint(a) - b, err := g2.DecodePoint(encoded) - if err != nil { - t.Fatal(err) - } - if !g2.Equal(a, b) { - t.Fatal("bad serialization encode/decode") - } - } -} - -func TestG2IsOnCurve(t *testing.T) { - g := NewG2() - zero := g.Zero() - if !g.IsOnCurve(zero) { - t.Fatal("zero must be on curve") - } - one := new(fe2).one() - p := &PointG2{*one, *one, *one} - if g.IsOnCurve(p) { - t.Fatal("(1, 1) is not on curve") - } -} - -func TestG2AdditiveProperties(t *testing.T) { - g := NewG2() - t0, t1 := g.New(), g.New() - zero := g.Zero() - for i := 0; i < fuz; i++ { - a, b := g.rand(), g.rand() - _, _, _ = b, t1, zero - g.Add(t0, a, zero) - if !g.Equal(t0, a) { - t.Fatal("a + 0 == a") - } - g.Add(t0, zero, zero) - if !g.Equal(t0, zero) { - t.Fatal("0 + 0 == 0") - } - g.Sub(t0, a, zero) - if !g.Equal(t0, a) { - t.Fatal("a - 0 == a") - } - g.Sub(t0, zero, zero) - if !g.Equal(t0, zero) { - t.Fatal("0 - 0 == 0") - } - g.Neg(t0, zero) - if !g.Equal(t0, zero) { - t.Fatal("- 0 == 0") - } - g.Sub(t0, zero, a) - g.Neg(t0, t0) - if !g.Equal(t0, a) { - t.Fatal(" - (0 - a) == a") - } - g.Double(t0, zero) - if !g.Equal(t0, zero) { - t.Fatal("2 * 0 == 0") - } - g.Double(t0, a) - g.Sub(t0, t0, a) - if !g.Equal(t0, a) || !g.IsOnCurve(t0) { - t.Fatal(" (2 * a) - a == a") - } - g.Add(t0, a, b) - g.Add(t1, b, a) - if !g.Equal(t0, t1) { - t.Fatal("a + b == b + a") - } - g.Sub(t0, a, b) - g.Sub(t1, b, a) - g.Neg(t1, t1) - if !g.Equal(t0, t1) { - t.Fatal("a - b == - ( b - a )") - } - c := g.rand() - g.Add(t0, a, b) - g.Add(t0, t0, c) - g.Add(t1, a, c) - g.Add(t1, t1, b) - if !g.Equal(t0, t1) { - t.Fatal("(a + b) + c == (a + c ) + b") - } - g.Sub(t0, a, b) - g.Sub(t0, t0, c) - g.Sub(t1, a, c) - g.Sub(t1, t1, b) - if !g.Equal(t0, t1) { - t.Fatal("(a - b) - c == (a - c) -b") - } - } -} - -func TestG2MultiplicativeProperties(t *testing.T) { - g := NewG2() - t0, t1 := g.New(), g.New() - zero := g.Zero() - for i := 0; i < fuz; i++ { - a := g.rand() - s1, s2, s3 := randScalar(q), randScalar(q), randScalar(q) - sone := big.NewInt(1) - g.MulScalar(t0, zero, s1) - if !g.Equal(t0, zero) { - t.Fatal(" 0 ^ s == 0") - } - g.MulScalar(t0, a, sone) - if !g.Equal(t0, a) { - t.Fatal(" a ^ 1 == a") - } - g.MulScalar(t0, zero, s1) - if !g.Equal(t0, zero) { - t.Fatal(" 0 ^ s == a") - } - g.MulScalar(t0, a, s1) - g.MulScalar(t0, t0, s2) - s3.Mul(s1, s2) - g.MulScalar(t1, a, s3) - if !g.Equal(t0, t1) { - t.Errorf(" (a ^ s1) ^ s2 == a ^ (s1 * s2)") - } - g.MulScalar(t0, a, s1) - g.MulScalar(t1, a, s2) - g.Add(t0, t0, t1) - s3.Add(s1, s2) - g.MulScalar(t1, a, s3) - if !g.Equal(t0, t1) { - t.Errorf(" (a ^ s1) + (a ^ s2) == a ^ (s1 + s2)") - } - } -} - -func TestG2MultiExpExpected(t *testing.T) { - g := NewG2() - one := g.one() - var scalars [2]*big.Int - var bases [2]*PointG2 - scalars[0] = big.NewInt(2) - scalars[1] = big.NewInt(3) - bases[0], bases[1] = new(PointG2).Set(one), new(PointG2).Set(one) - expected, result := g.New(), g.New() - g.MulScalar(expected, one, big.NewInt(5)) - _, _ = g.MultiExp(result, bases[:], scalars[:]) - if !g.Equal(expected, result) { - t.Fatal("bad multi-exponentiation") - } -} - -func TestG2MultiExpBatch(t *testing.T) { - g := NewG2() - one := g.one() - n := 1000 - bases := make([]*PointG2, n) - scalars := make([]*big.Int, n) - // scalars: [s0,s1 ... s(n-1)] - // bases: [P0,P1,..P(n-1)] = [s(n-1)*G, s(n-2)*G ... s0*G] - for i, j := 0, n-1; i < n; i, j = i+1, j-1 { - scalars[j], _ = rand.Int(rand.Reader, big.NewInt(100000)) - bases[i] = g.New() - g.MulScalar(bases[i], one, scalars[j]) - } - // expected: s(n-1)*P0 + s(n-2)*P1 + s0*P(n-1) - expected, tmp := g.New(), g.New() - for i := 0; i < n; i++ { - g.MulScalar(tmp, bases[i], scalars[i]) - g.Add(expected, expected, tmp) - } - result := g.New() - _, _ = g.MultiExp(result, bases, scalars) - if !g.Equal(expected, result) { - t.Fatal("bad multi-exponentiation") - } -} - -func TestG2MapToCurve(t *testing.T) { - for i, v := range []struct { - u []byte - expected []byte - }{ - { - u: make([]byte, 96), - expected: common.FromHex("0a67d12118b5a35bb02d2e86b3ebfa7e23410db93de39fb06d7025fa95e96ffa428a7a27c3ae4dd4b40bd251ac658892" + "018320896ec9eef9d5e619848dc29ce266f413d02dd31d9b9d44ec0c79cd61f18b075ddba6d7bd20b7ff27a4b324bfce" + "04c69777a43f0bda07679d5805e63f18cf4e0e7c6112ac7f70266d199b4f76ae27c6269a3ceebdae30806e9a76aadf5c" + "0260e03644d1a2c321256b3246bad2b895cad13890cbe6f85df55106a0d334604fb143c7a042d878006271865bc35941"), - }, - { - u: common.FromHex("025fbc07711ba267b7e70c82caa70a16fbb1d470ae24ceef307f5e2000751677820b7013ad4e25492dcf30052d3e5eca" + "0e775d7827adf385b83e20e4445bd3fab21d7b4498426daf3c1d608b9d41e9edb5eda0df022e753b8bb4bc3bb7db4914"), - expected: common.FromHex("0d4333b77becbf9f9dfa3ca928002233d1ecc854b1447e5a71f751c9042d000f42db91c1d6649a5e0ad22bd7bf7398b8" + "027e4bfada0b47f9f07e04aec463c7371e68f2fd0c738cd517932ea3801a35acf09db018deda57387b0f270f7a219e4d" + "0cc76dc777ea0d447e02a41004f37a0a7b1fafb6746884e8d9fc276716ccf47e4e0899548a2ec71c2bdf1a2a50e876db" + "053674cba9ef516ddc218fedb37324e6c47de27f88ab7ef123b006127d738293c0277187f7e2f80a299a24d84ed03da7"), - }, - { - u: common.FromHex("1870a7dbfd2a1deb74015a3546b20f598041bf5d5202997956a94a368d30d3f70f18cdaa1d33ce970a4e16af961cbdcb" + "045ab31ce4b5a8ba7c4b2851b64f063a66cd1223d3c85005b78e1beee65e33c90ceef0244e45fc45a5e1d6eab6644fdb"), - expected: common.FromHex("18f0f87b40af67c056915dbaf48534c592524e82c1c2b50c3734d02c0172c80df780a60b5683759298a3303c5d942778" + "09349f1cb5b2e55489dcd45a38545343451cc30a1681c57acd4fb0a6db125f8352c09f4a67eb7d1d8242cb7d3405f97b" + "10a2ba341bc689ab947b7941ce6ef39be17acaab067bd32bd652b471ab0792c53a2bd03bdac47f96aaafe96e441f63c0" + "02f2d9deb2c7742512f5b8230bf0fd83ea42279d7d39779543c1a43b61c885982b611f6a7a24b514995e8a098496b811"), - }, - { - u: common.FromHex("088fe329b054db8a6474f21a7fbfdf17b4c18044db299d9007af582c3d5f17d00e56d99921d4b5640fce44b05219b5de" + "0b6e6135a4cd31ba980ddbd115ac48abef7ec60e226f264d7befe002c165f3a496f36f76dd524efd75d17422558d10b4"), - expected: common.FromHex("19808ec5930a53c7cf5912ccce1cc33f1b3dcff24a53ce1cc4cba41fd6996dbed4843ccdd2eaf6a0cd801e562718d163" + "149fe43777d34f0d25430dea463889bd9393bdfb4932946db23671727081c629ebb98a89604f3433fba1c67d356a4af7" + "04783e391c30c83f805ca271e353582fdf19d159f6a4c39b73acbb637a9b8ac820cfbe2738d683368a7c07ad020e3e33" + "04c0d6793a766233b2982087b5f4a254f261003ccb3262ea7c50903eecef3e871d1502c293f9e063d7d293f6384f4551"), - }, - { - u: common.FromHex("03df16a66a05e4c1188c234788f43896e0565bfb64ac49b9639e6b284cc47dad73c47bb4ea7e677db8d496beb907fbb6" + "0f45b50647d67485295aa9eb2d91a877b44813677c67c8d35b2173ff3ba95f7bd0806f9ca8a1436b8b9d14ee81da4d7e"), - expected: common.FromHex("0b8e0094c886487870372eb6264613a6a087c7eb9804fab789be4e47a57b29eb19b1983a51165a1b5eb025865e9fc63a" + "0804152cbf8474669ad7d1796ab92d7ca21f32d8bed70898a748ed4e4e0ec557069003732fc86866d938538a2ae95552" + "14c80f068ece15a3936bb00c3c883966f75b4e8d9ddde809c11f781ab92d23a2d1d103ad48f6f3bb158bf3e3a4063449" + "09e5c8242dd7281ad32c03fe4af3f19167770016255fb25ad9b67ec51d62fade31a1af101e8f6172ec2ee8857662be3a"), - }, - } { - g := NewG2() - p0, err := g.MapToCurve(v.u) - if err != nil { - t.Fatal("map to curve fails", i, err) - } - if !bytes.Equal(g.ToBytes(p0), v.expected) { - t.Fatal("map to curve fails", i) - } - } -} - -func BenchmarkG2Add(t *testing.B) { - g2 := NewG2() - a, b, c := g2.rand(), g2.rand(), PointG2{} - t.ResetTimer() - for i := 0; i < t.N; i++ { - g2.Add(&c, a, b) - } -} - -func BenchmarkG2Mul(t *testing.B) { - worstCaseScalar, _ := new(big.Int).SetString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16) - g2 := NewG2() - a, e, c := g2.rand(), worstCaseScalar, PointG2{} - t.ResetTimer() - for i := 0; i < t.N; i++ { - g2.MulScalar(&c, a, e) - } -} - -func BenchmarkG2SWUMap(t *testing.B) { - a := make([]byte, 96) - g2 := NewG2() - t.ResetTimer() - for i := 0; i < t.N; i++ { - _, err := g2.MapToCurve(a) - if err != nil { - t.Fatal(err) - } - } -} diff --git a/crypto/bls12381/gt.go b/crypto/bls12381/gt.go deleted file mode 100644 index 2ac265e9568b..000000000000 --- a/crypto/bls12381/gt.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2020 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 bls12381 - -import ( - "errors" - "math/big" -) - -// E is type for target group element -type E = fe12 - -// GT is type for target multiplicative group GT. -type GT struct { - fp12 *fp12 -} - -func (e *E) Set(e2 *E) *E { - return e.set(e2) -} - -// One sets a new target group element to one -func (e *E) One() *E { - e = new(fe12).one() - return e -} - -// IsOne returns true if given element equals to one -func (e *E) IsOne() bool { - return e.isOne() -} - -// Equal returns true if given two element is equal, otherwise returns false -func (g *E) Equal(g2 *E) bool { - return g.equal(g2) -} - -// NewGT constructs new target group instance. -func NewGT() *GT { - fp12 := newFp12(nil) - return >{fp12} -} - -// Q returns group order in big.Int. -func (g *GT) Q() *big.Int { - return new(big.Int).Set(q) -} - -// FromBytes expects 576 byte input and returns target group element -// FromBytes returns error if given element is not on correct subgroup. -func (g *GT) FromBytes(in []byte) (*E, error) { - e, err := g.fp12.fromBytes(in) - if err != nil { - return nil, err - } - if !g.IsValid(e) { - return e, errors.New("invalid element") - } - return e, nil -} - -// ToBytes serializes target group element. -func (g *GT) ToBytes(e *E) []byte { - return g.fp12.toBytes(e) -} - -// IsValid checks whether given target group element is in correct subgroup. -func (g *GT) IsValid(e *E) bool { - r := g.New() - g.fp12.exp(r, e, q) - return r.isOne() -} - -// New initializes a new target group element which is equal to one -func (g *GT) New() *E { - return new(E).One() -} - -// Add adds two field element `a` and `b` and assigns the result to the element in first argument. -func (g *GT) Add(c, a, b *E) { - g.fp12.add(c, a, b) -} - -// Sub subtracts two field element `a` and `b`, and assigns the result to the element in first argument. -func (g *GT) Sub(c, a, b *E) { - g.fp12.sub(c, a, b) -} - -// Mul multiplies two field element `a` and `b` and assigns the result to the element in first argument. -func (g *GT) Mul(c, a, b *E) { - g.fp12.mul(c, a, b) -} - -// Square squares an element `a` and assigns the result to the element in first argument. -func (g *GT) Square(c, a *E) { - g.fp12.cyclotomicSquare(c, a) -} - -// Exp exponents an element `a` by a scalar `s` and assigns the result to the element in first argument. -func (g *GT) Exp(c, a *E, s *big.Int) { - g.fp12.cyclotomicExp(c, a, s) -} - -// Inverse inverses an element `a` and assigns the result to the element in first argument. -func (g *GT) Inverse(c, a *E) { - g.fp12.inverse(c, a) -} diff --git a/crypto/bls12381/isogeny.go b/crypto/bls12381/isogeny.go deleted file mode 100644 index a63f585dd00a..000000000000 --- a/crypto/bls12381/isogeny.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2020 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 bls12381 - -// isogenyMapG1 applies 11-isogeny map for BLS12-381 G1 defined at draft-irtf-cfrg-hash-to-curve-06. -func isogenyMapG1(x, y *fe) { - // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-C.2 - params := isogenyConstantsG1 - degree := 15 - xNum, xDen, yNum, yDen := new(fe), new(fe), new(fe), new(fe) - xNum.set(params[0][degree]) - xDen.set(params[1][degree]) - yNum.set(params[2][degree]) - yDen.set(params[3][degree]) - for i := degree - 1; i >= 0; i-- { - mul(xNum, xNum, x) - mul(xDen, xDen, x) - mul(yNum, yNum, x) - mul(yDen, yDen, x) - add(xNum, xNum, params[0][i]) - add(xDen, xDen, params[1][i]) - add(yNum, yNum, params[2][i]) - add(yDen, yDen, params[3][i]) - } - inverse(xDen, xDen) - inverse(yDen, yDen) - mul(xNum, xNum, xDen) - mul(yNum, yNum, yDen) - mul(yNum, yNum, y) - x.set(xNum) - y.set(yNum) -} - -// isogenyMapG2 applies 11-isogeny map for BLS12-381 G1 defined at draft-irtf-cfrg-hash-to-curve-06. -func isogenyMapG2(e *fp2, x, y *fe2) { - if e == nil { - e = newFp2() - } - // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-C.2 - params := isogenyConstantsG2 - degree := 3 - xNum := new(fe2).set(params[0][degree]) - xDen := new(fe2).set(params[1][degree]) - yNum := new(fe2).set(params[2][degree]) - yDen := new(fe2).set(params[3][degree]) - for i := degree - 1; i >= 0; i-- { - e.mul(xNum, xNum, x) - e.mul(xDen, xDen, x) - e.mul(yNum, yNum, x) - e.mul(yDen, yDen, x) - e.add(xNum, xNum, params[0][i]) - e.add(xDen, xDen, params[1][i]) - e.add(yNum, yNum, params[2][i]) - e.add(yDen, yDen, params[3][i]) - } - e.inverse(xDen, xDen) - e.inverse(yDen, yDen) - e.mul(xNum, xNum, xDen) - e.mul(yNum, yNum, yDen) - e.mul(yNum, yNum, y) - x.set(xNum) - y.set(yNum) -} - -var isogenyConstantsG1 = [4][16]*fe{ - { - {0x4d18b6f3af00131c, 0x19fa219793fee28c, 0x3f2885f1467f19ae, 0x23dcea34f2ffb304, 0xd15b58d2ffc00054, 0x0913be200a20bef4}, - {0x898985385cdbbd8b, 0x3c79e43cc7d966aa, 0x1597e193f4cd233a, 0x8637ef1e4d6623ad, 0x11b22deed20d827b, 0x07097bc5998784ad}, - {0xa542583a480b664b, 0xfc7169c026e568c6, 0x5ba2ef314ed8b5a6, 0x5b5491c05102f0e7, 0xdf6e99707d2a0079, 0x0784151ed7605524}, - {0x494e212870f72741, 0xab9be52fbda43021, 0x26f5577994e34c3d, 0x049dfee82aefbd60, 0x65dadd7828505289, 0x0e93d431ea011aeb}, - {0x90ee774bd6a74d45, 0x7ada1c8a41bfb185, 0x0f1a8953b325f464, 0x104c24211be4805c, 0x169139d319ea7a8f, 0x09f20ead8e532bf6}, - {0x6ddd93e2f43626b7, 0xa5482c9aa1ccd7bd, 0x143245631883f4bd, 0x2e0a94ccf77ec0db, 0xb0282d480e56489f, 0x18f4bfcbb4368929}, - {0x23c5f0c953402dfd, 0x7a43ff6958ce4fe9, 0x2c390d3d2da5df63, 0xd0df5c98e1f9d70f, 0xffd89869a572b297, 0x1277ffc72f25e8fe}, - {0x79f4f0490f06a8a6, 0x85f894a88030fd81, 0x12da3054b18b6410, 0xe2a57f6505880d65, 0xbba074f260e400f1, 0x08b76279f621d028}, - {0xe67245ba78d5b00b, 0x8456ba9a1f186475, 0x7888bff6e6b33bb4, 0xe21585b9a30f86cb, 0x05a69cdcef55feee, 0x09e699dd9adfa5ac}, - {0x0de5c357bff57107, 0x0a0db4ae6b1a10b2, 0xe256bb67b3b3cd8d, 0x8ad456574e9db24f, 0x0443915f50fd4179, 0x098c4bf7de8b6375}, - {0xe6b0617e7dd929c7, 0xfe6e37d442537375, 0x1dafdeda137a489e, 0xe4efd1ad3f767ceb, 0x4a51d8667f0fe1cf, 0x054fdf4bbf1d821c}, - {0x72db2a50658d767b, 0x8abf91faa257b3d5, 0xe969d6833764ab47, 0x464170142a1009eb, 0xb14f01aadb30be2f, 0x18ae6a856f40715d}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - }, - { - {0xb962a077fdb0f945, 0xa6a9740fefda13a0, 0xc14d568c3ed6c544, 0xb43fc37b908b133e, 0x9c0b3ac929599016, 0x0165aa6c93ad115f}, - {0x23279a3ba506c1d9, 0x92cfca0a9465176a, 0x3b294ab13755f0ff, 0x116dda1c5070ae93, 0xed4530924cec2045, 0x083383d6ed81f1ce}, - {0x9885c2a6449fecfc, 0x4a2b54ccd37733f0, 0x17da9ffd8738c142, 0xa0fba72732b3fafd, 0xff364f36e54b6812, 0x0f29c13c660523e2}, - {0xe349cc118278f041, 0xd487228f2f3204fb, 0xc9d325849ade5150, 0x43a92bd69c15c2df, 0x1c2c7844bc417be4, 0x12025184f407440c}, - {0x587f65ae6acb057b, 0x1444ef325140201f, 0xfbf995e71270da49, 0xccda066072436a42, 0x7408904f0f186bb2, 0x13b93c63edf6c015}, - {0xfb918622cd141920, 0x4a4c64423ecaddb4, 0x0beb232927f7fb26, 0x30f94df6f83a3dc2, 0xaeedd424d780f388, 0x06cc402dd594bbeb}, - {0xd41f761151b23f8f, 0x32a92465435719b3, 0x64f436e888c62cb9, 0xdf70a9a1f757c6e4, 0x6933a38d5b594c81, 0x0c6f7f7237b46606}, - {0x693c08747876c8f7, 0x22c9850bf9cf80f0, 0x8e9071dab950c124, 0x89bc62d61c7baf23, 0xbc6be2d8dad57c23, 0x17916987aa14a122}, - {0x1be3ff439c1316fd, 0x9965243a7571dfa7, 0xc7f7f62962f5cd81, 0x32c6aa9af394361c, 0xbbc2ee18e1c227f4, 0x0c102cbac531bb34}, - {0x997614c97bacbf07, 0x61f86372b99192c0, 0x5b8c95fc14353fc3, 0xca2b066c2a87492f, 0x16178f5bbf698711, 0x12a6dcd7f0f4e0e8}, - {0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - }, - { - {0x2b567ff3e2837267, 0x1d4d9e57b958a767, 0xce028fea04bd7373, 0xcc31a30a0b6cd3df, 0x7d7b18a682692693, 0x0d300744d42a0310}, - {0x99c2555fa542493f, 0xfe7f53cc4874f878, 0x5df0608b8f97608a, 0x14e03832052b49c8, 0x706326a6957dd5a4, 0x0a8dadd9c2414555}, - {0x13d942922a5cf63a, 0x357e33e36e261e7d, 0xcf05a27c8456088d, 0x0000bd1de7ba50f0, 0x83d0c7532f8c1fde, 0x13f70bf38bbf2905}, - {0x5c57fd95bfafbdbb, 0x28a359a65e541707, 0x3983ceb4f6360b6d, 0xafe19ff6f97e6d53, 0xb3468f4550192bf7, 0x0bb6cde49d8ba257}, - {0x590b62c7ff8a513f, 0x314b4ce372cacefd, 0x6bef32ce94b8a800, 0x6ddf84a095713d5f, 0x64eace4cb0982191, 0x0386213c651b888d}, - {0xa5310a31111bbcdd, 0xa14ac0f5da148982, 0xf9ad9cc95423d2e9, 0xaa6ec095283ee4a7, 0xcf5b1f022e1c9107, 0x01fddf5aed881793}, - {0x65a572b0d7a7d950, 0xe25c2d8183473a19, 0xc2fcebe7cb877dbd, 0x05b2d36c769a89b0, 0xba12961be86e9efb, 0x07eb1b29c1dfde1f}, - {0x93e09572f7c4cd24, 0x364e929076795091, 0x8569467e68af51b5, 0xa47da89439f5340f, 0xf4fa918082e44d64, 0x0ad52ba3e6695a79}, - {0x911429844e0d5f54, 0xd03f51a3516bb233, 0x3d587e5640536e66, 0xfa86d2a3a9a73482, 0xa90ed5adf1ed5537, 0x149c9c326a5e7393}, - {0x462bbeb03c12921a, 0xdc9af5fa0a274a17, 0x9a558ebde836ebed, 0x649ef8f11a4fae46, 0x8100e1652b3cdc62, 0x1862bd62c291dacb}, - {0x05c9b8ca89f12c26, 0x0194160fa9b9ac4f, 0x6a643d5a6879fa2c, 0x14665bdd8846e19d, 0xbb1d0d53af3ff6bf, 0x12c7e1c3b28962e5}, - {0xb55ebf900b8a3e17, 0xfedc77ec1a9201c4, 0x1f07db10ea1a4df4, 0x0dfbd15dc41a594d, 0x389547f2334a5391, 0x02419f98165871a4}, - {0xb416af000745fc20, 0x8e563e9d1ea6d0f5, 0x7c763e17763a0652, 0x01458ef0159ebbef, 0x8346fe421f96bb13, 0x0d2d7b829ce324d2}, - {0x93096bb538d64615, 0x6f2a2619951d823a, 0x8f66b3ea59514fa4, 0xf563e63704f7092f, 0x724b136c4cf2d9fa, 0x046959cfcfd0bf49}, - {0xea748d4b6e405346, 0x91e9079c2c02d58f, 0x41064965946d9b59, 0xa06731f1d2bbe1ee, 0x07f897e267a33f1b, 0x1017290919210e5f}, - {0x872aa6c17d985097, 0xeecc53161264562a, 0x07afe37afff55002, 0x54759078e5be6838, 0xc4b92d15db8acca8, 0x106d87d1b51d13b9}, - }, - { - {0xeb6c359d47e52b1c, 0x18ef5f8a10634d60, 0xddfa71a0889d5b7e, 0x723e71dcc5fc1323, 0x52f45700b70d5c69, 0x0a8b981ee47691f1}, - {0x616a3c4f5535b9fb, 0x6f5f037395dbd911, 0xf25f4cc5e35c65da, 0x3e50dffea3c62658, 0x6a33dca523560776, 0x0fadeff77b6bfe3e}, - {0x2be9b66df470059c, 0x24a2c159a3d36742, 0x115dbe7ad10c2a37, 0xb6634a652ee5884d, 0x04fe8bb2b8d81af4, 0x01c2a7a256fe9c41}, - {0xf27bf8ef3b75a386, 0x898b367476c9073f, 0x24482e6b8c2f4e5f, 0xc8e0bbd6fe110806, 0x59b0c17f7631448a, 0x11037cd58b3dbfbd}, - {0x31c7912ea267eec6, 0x1dbf6f1c5fcdb700, 0xd30d4fe3ba86fdb1, 0x3cae528fbee9a2a4, 0xb1cce69b6aa9ad9a, 0x044393bb632d94fb}, - {0xc66ef6efeeb5c7e8, 0x9824c289dd72bb55, 0x71b1a4d2f119981d, 0x104fc1aafb0919cc, 0x0e49df01d942a628, 0x096c3a09773272d4}, - {0x9abc11eb5fadeff4, 0x32dca50a885728f0, 0xfb1fa3721569734c, 0xc4b76271ea6506b3, 0xd466a75599ce728e, 0x0c81d4645f4cb6ed}, - {0x4199f10e5b8be45b, 0xda64e495b1e87930, 0xcb353efe9b33e4ff, 0x9e9efb24aa6424c6, 0xf08d33680a237465, 0x0d3378023e4c7406}, - {0x7eb4ae92ec74d3a5, 0xc341b4aa9fac3497, 0x5be603899e907687, 0x03bfd9cca75cbdeb, 0x564c2935a96bfa93, 0x0ef3c33371e2fdb5}, - {0x7ee91fd449f6ac2e, 0xe5d5bd5cb9357a30, 0x773a8ca5196b1380, 0xd0fda172174ed023, 0x6cb95e0fa776aead, 0x0d22d5a40cec7cff}, - {0xf727e09285fd8519, 0xdc9d55a83017897b, 0x7549d8bd057894ae, 0x178419613d90d8f8, 0xfce95ebdeb5b490a, 0x0467ffaef23fc49e}, - {0xc1769e6a7c385f1b, 0x79bc930deac01c03, 0x5461c75a23ede3b5, 0x6e20829e5c230c45, 0x828e0f1e772a53cd, 0x116aefa749127bff}, - {0x101c10bf2744c10a, 0xbbf18d053a6a3154, 0xa0ecf39ef026f602, 0xfc009d4996dc5153, 0xb9000209d5bd08d3, 0x189e5fe4470cd73c}, - {0x7ebd546ca1575ed2, 0xe47d5a981d081b55, 0x57b2b625b6d4ca21, 0xb0a1ba04228520cc, 0x98738983c2107ff3, 0x13dddbc4799d81d6}, - {0x09319f2e39834935, 0x039e952cbdb05c21, 0x55ba77a9a2f76493, 0xfd04e3dfc6086467, 0xfb95832e7d78742e, 0x0ef9c24eccaf5e0e}, - {0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - }, -} - -var isogenyConstantsG2 = [4][4]*fe2{ - { - { - fe{0x47f671c71ce05e62, 0x06dd57071206393e, 0x7c80cd2af3fd71a2, 0x048103ea9e6cd062, 0xc54516acc8d037f6, 0x13808f550920ea41}, - fe{0x47f671c71ce05e62, 0x06dd57071206393e, 0x7c80cd2af3fd71a2, 0x048103ea9e6cd062, 0xc54516acc8d037f6, 0x13808f550920ea41}, - }, - { - fe{0, 0, 0, 0, 0, 0}, - fe{0x5fe55555554c71d0, 0x873fffdd236aaaa3, 0x6a6b4619b26ef918, 0x21c2888408874945, 0x2836cda7028cabc5, 0x0ac73310a7fd5abd}, - }, - { - fe{0x0a0c5555555971c3, 0xdb0c00101f9eaaae, 0xb1fb2f941d797997, 0xd3960742ef416e1c, 0xb70040e2c20556f4, 0x149d7861e581393b}, - fe{0xaff2aaaaaaa638e8, 0x439fffee91b55551, 0xb535a30cd9377c8c, 0x90e144420443a4a2, 0x941b66d3814655e2, 0x0563998853fead5e}, - }, - { - fe{0x40aac71c71c725ed, 0x190955557a84e38e, 0xd817050a8f41abc3, 0xd86485d4c87f6fb1, 0x696eb479f885d059, 0x198e1a74328002d2}, - fe{0, 0, 0, 0, 0, 0}, - }, - }, - { - { - fe{0, 0, 0, 0, 0, 0}, - fe{0x1f3affffff13ab97, 0xf25bfc611da3ff3e, 0xca3757cb3819b208, 0x3e6427366f8cec18, 0x03977bc86095b089, 0x04f69db13f39a952}, - }, - { - fe{0x447600000027552e, 0xdcb8009a43480020, 0x6f7ee9ce4a6e8b59, 0xb10330b7c0a95bc6, 0x6140b1fcfb1e54b7, 0x0381be097f0bb4e1}, - fe{0x7588ffffffd8557d, 0x41f3ff646e0bffdf, 0xf7b1e8d2ac426aca, 0xb3741acd32dbb6f8, 0xe9daf5b9482d581f, 0x167f53e0ba7431b8}, - }, - { - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - fe{0, 0, 0, 0, 0, 0}, - }, - { - fe{0, 0, 0, 0, 0, 0}, - fe{0, 0, 0, 0, 0, 0}, - }, - }, - { - { - fe{0x96d8f684bdfc77be, 0xb530e4f43b66d0e2, 0x184a88ff379652fd, 0x57cb23ecfae804e1, 0x0fd2e39eada3eba9, 0x08c8055e31c5d5c3}, - fe{0x96d8f684bdfc77be, 0xb530e4f43b66d0e2, 0x184a88ff379652fd, 0x57cb23ecfae804e1, 0x0fd2e39eada3eba9, 0x08c8055e31c5d5c3}, - }, - { - fe{0, 0, 0, 0, 0, 0}, - fe{0xbf0a71c71c91b406, 0x4d6d55d28b7638fd, 0x9d82f98e5f205aee, 0xa27aa27b1d1a18d5, 0x02c3b2b2d2938e86, 0x0c7d13420b09807f}, - }, - { - fe{0xd7f9555555531c74, 0x21cffff748daaaa8, 0x5a9ad1866c9bbe46, 0x4870a2210221d251, 0x4a0db369c0a32af1, 0x02b1ccc429ff56af}, - fe{0xe205aaaaaaac8e37, 0xfcdc000768795556, 0x0c96011a8a1537dd, 0x1c06a963f163406e, 0x010df44c82a881e6, 0x174f45260f808feb}, - }, - { - fe{0xa470bda12f67f35c, 0xc0fe38e23327b425, 0xc9d3d0f2c6f0678d, 0x1c55c9935b5a982e, 0x27f6c0e2f0746764, 0x117c5e6e28aa9054}, - fe{0, 0, 0, 0, 0, 0}, - }, - }, - { - { - fe{0x0162fffffa765adf, 0x8f7bea480083fb75, 0x561b3c2259e93611, 0x11e19fc1a9c875d5, 0xca713efc00367660, 0x03c6a03d41da1151}, - fe{0x0162fffffa765adf, 0x8f7bea480083fb75, 0x561b3c2259e93611, 0x11e19fc1a9c875d5, 0xca713efc00367660, 0x03c6a03d41da1151}, - }, - { - fe{0, 0, 0, 0, 0, 0}, - fe{0x5db0fffffd3b02c5, 0xd713f52358ebfdba, 0x5ea60761a84d161a, 0xbb2c75a34ea6c44a, 0x0ac6735921c1119b, 0x0ee3d913bdacfbf6}, - }, - { - fe{0x66b10000003affc5, 0xcb1400e764ec0030, 0xa73e5eb56fa5d106, 0x8984c913a0fe09a9, 0x11e10afb78ad7f13, 0x05429d0e3e918f52}, - fe{0x534dffffffc4aae6, 0x5397ff174c67ffcf, 0xbff273eb870b251d, 0xdaf2827152870915, 0x393a9cbaca9e2dc3, 0x14be74dbfaee5748}, - }, - { - fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, - fe{0, 0, 0, 0, 0, 0}, - }, - }, -} diff --git a/crypto/bls12381/pairing.go b/crypto/bls12381/pairing.go deleted file mode 100644 index d292d7c3a5f6..000000000000 --- a/crypto/bls12381/pairing.go +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2020 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 bls12381 - -type pair struct { - g1 *PointG1 - g2 *PointG2 -} - -func newPair(g1 *PointG1, g2 *PointG2) pair { - return pair{g1, g2} -} - -// Engine is BLS12-381 elliptic curve pairing engine -type Engine struct { - G1 *G1 - G2 *G2 - fp12 *fp12 - fp2 *fp2 - pairingEngineTemp - pairs []pair -} - -// NewPairingEngine creates new pairing engine instance. -func NewPairingEngine() *Engine { - fp2 := newFp2() - fp6 := newFp6(fp2) - fp12 := newFp12(fp6) - g1 := NewG1() - g2 := newG2(fp2) - return &Engine{ - fp2: fp2, - fp12: fp12, - G1: g1, - G2: g2, - pairingEngineTemp: newEngineTemp(), - } -} - -type pairingEngineTemp struct { - t2 [10]*fe2 - t12 [9]fe12 -} - -func newEngineTemp() pairingEngineTemp { - t2 := [10]*fe2{} - for i := 0; i < 10; i++ { - t2[i] = &fe2{} - } - t12 := [9]fe12{} - return pairingEngineTemp{t2, t12} -} - -// AddPair adds a g1, g2 point pair to pairing engine -func (e *Engine) AddPair(g1 *PointG1, g2 *PointG2) *Engine { - p := newPair(g1, g2) - if !e.isZero(p) { - e.affine(p) - e.pairs = append(e.pairs, p) - } - return e -} - -// AddPairInv adds a G1, G2 point pair to pairing engine. G1 point is negated. -func (e *Engine) AddPairInv(g1 *PointG1, g2 *PointG2) *Engine { - e.G1.Neg(g1, g1) - e.AddPair(g1, g2) - return e -} - -// Reset deletes added pairs. -func (e *Engine) Reset() *Engine { - e.pairs = []pair{} - return e -} - -func (e *Engine) isZero(p pair) bool { - return e.G1.IsZero(p.g1) || e.G2.IsZero(p.g2) -} - -func (e *Engine) affine(p pair) { - e.G1.Affine(p.g1) - e.G2.Affine(p.g2) -} - -func (e *Engine) doublingStep(coeff *[3]fe2, r *PointG2) { - // Adaptation of Formula 3 in https://eprint.iacr.org/2010/526.pdf - fp2 := e.fp2 - t := e.t2 - fp2.mul(t[0], &r[0], &r[1]) - fp2.mulByFq(t[0], t[0], twoInv) - fp2.square(t[1], &r[1]) - fp2.square(t[2], &r[2]) - fp2.double(t[7], t[2]) - fp2.add(t[7], t[7], t[2]) - fp2.mulByB(t[3], t[7]) - fp2.double(t[4], t[3]) - fp2.add(t[4], t[4], t[3]) - fp2.add(t[5], t[1], t[4]) - fp2.mulByFq(t[5], t[5], twoInv) - fp2.add(t[6], &r[1], &r[2]) - fp2.square(t[6], t[6]) - fp2.add(t[7], t[2], t[1]) - fp2.sub(t[6], t[6], t[7]) - fp2.sub(&coeff[0], t[3], t[1]) - fp2.square(t[7], &r[0]) - fp2.sub(t[4], t[1], t[4]) - fp2.mul(&r[0], t[4], t[0]) - fp2.square(t[2], t[3]) - fp2.double(t[3], t[2]) - fp2.add(t[3], t[3], t[2]) - fp2.square(t[5], t[5]) - fp2.sub(&r[1], t[5], t[3]) - fp2.mul(&r[2], t[1], t[6]) - fp2.double(t[0], t[7]) - fp2.add(&coeff[1], t[0], t[7]) - fp2.neg(&coeff[2], t[6]) -} - -func (e *Engine) additionStep(coeff *[3]fe2, r, q *PointG2) { - // Algorithm 12 in https://eprint.iacr.org/2010/526.pdf - fp2 := e.fp2 - t := e.t2 - fp2.mul(t[0], &q[1], &r[2]) - fp2.neg(t[0], t[0]) - fp2.add(t[0], t[0], &r[1]) - fp2.mul(t[1], &q[0], &r[2]) - fp2.neg(t[1], t[1]) - fp2.add(t[1], t[1], &r[0]) - fp2.square(t[2], t[0]) - fp2.square(t[3], t[1]) - fp2.mul(t[4], t[1], t[3]) - fp2.mul(t[2], &r[2], t[2]) - fp2.mul(t[3], &r[0], t[3]) - fp2.double(t[5], t[3]) - fp2.sub(t[5], t[4], t[5]) - fp2.add(t[5], t[5], t[2]) - fp2.mul(&r[0], t[1], t[5]) - fp2.sub(t[2], t[3], t[5]) - fp2.mul(t[2], t[2], t[0]) - fp2.mul(t[3], &r[1], t[4]) - fp2.sub(&r[1], t[2], t[3]) - fp2.mul(&r[2], &r[2], t[4]) - fp2.mul(t[2], t[1], &q[1]) - fp2.mul(t[3], t[0], &q[0]) - fp2.sub(&coeff[0], t[3], t[2]) - fp2.neg(&coeff[1], t[0]) - coeff[2].set(t[1]) -} - -func (e *Engine) preCompute(ellCoeffs *[68][3]fe2, twistPoint *PointG2) { - // Algorithm 5 in https://eprint.iacr.org/2019/077.pdf - if e.G2.IsZero(twistPoint) { - return - } - r := new(PointG2).Set(twistPoint) - j := 0 - for i := x.BitLen() - 2; i >= 0; i-- { - e.doublingStep(&ellCoeffs[j], r) - if x.Bit(i) != 0 { - j++ - ellCoeffs[j] = fe6{} - e.additionStep(&ellCoeffs[j], r, twistPoint) - } - j++ - } -} - -func (e *Engine) millerLoop(f *fe12) { - pairs := e.pairs - ellCoeffs := make([][68][3]fe2, len(pairs)) - for i := 0; i < len(pairs); i++ { - e.preCompute(&ellCoeffs[i], pairs[i].g2) - } - fp12, fp2 := e.fp12, e.fp2 - t := e.t2 - f.one() - j := 0 - for i := 62; /* x.BitLen() - 2 */ i >= 0; i-- { - if i != 62 { - fp12.square(f, f) - } - for i := 0; i <= len(pairs)-1; i++ { - fp2.mulByFq(t[0], &ellCoeffs[i][j][2], &pairs[i].g1[1]) - fp2.mulByFq(t[1], &ellCoeffs[i][j][1], &pairs[i].g1[0]) - fp12.mulBy014Assign(f, &ellCoeffs[i][j][0], t[1], t[0]) - } - if x.Bit(i) != 0 { - j++ - for i := 0; i <= len(pairs)-1; i++ { - fp2.mulByFq(t[0], &ellCoeffs[i][j][2], &pairs[i].g1[1]) - fp2.mulByFq(t[1], &ellCoeffs[i][j][1], &pairs[i].g1[0]) - fp12.mulBy014Assign(f, &ellCoeffs[i][j][0], t[1], t[0]) - } - } - j++ - } - fp12.conjugate(f, f) -} - -func (e *Engine) exp(c, a *fe12) { - fp12 := e.fp12 - fp12.cyclotomicExp(c, a, x) - fp12.conjugate(c, c) -} - -func (e *Engine) finalExp(f *fe12) { - fp12 := e.fp12 - t := e.t12 - // easy part - fp12.frobeniusMap(&t[0], f, 6) - fp12.inverse(&t[1], f) - fp12.mul(&t[2], &t[0], &t[1]) - t[1].set(&t[2]) - fp12.frobeniusMapAssign(&t[2], 2) - fp12.mulAssign(&t[2], &t[1]) - fp12.cyclotomicSquare(&t[1], &t[2]) - fp12.conjugate(&t[1], &t[1]) - // hard part - e.exp(&t[3], &t[2]) - fp12.cyclotomicSquare(&t[4], &t[3]) - fp12.mul(&t[5], &t[1], &t[3]) - e.exp(&t[1], &t[5]) - e.exp(&t[0], &t[1]) - e.exp(&t[6], &t[0]) - fp12.mulAssign(&t[6], &t[4]) - e.exp(&t[4], &t[6]) - fp12.conjugate(&t[5], &t[5]) - fp12.mulAssign(&t[4], &t[5]) - fp12.mulAssign(&t[4], &t[2]) - fp12.conjugate(&t[5], &t[2]) - fp12.mulAssign(&t[1], &t[2]) - fp12.frobeniusMapAssign(&t[1], 3) - fp12.mulAssign(&t[6], &t[5]) - fp12.frobeniusMapAssign(&t[6], 1) - fp12.mulAssign(&t[3], &t[0]) - fp12.frobeniusMapAssign(&t[3], 2) - fp12.mulAssign(&t[3], &t[1]) - fp12.mulAssign(&t[3], &t[6]) - fp12.mul(f, &t[3], &t[4]) -} - -func (e *Engine) calculate() *fe12 { - f := e.fp12.one() - if len(e.pairs) == 0 { - return f - } - e.millerLoop(f) - e.finalExp(f) - return f -} - -// Check computes pairing and checks if result is equal to one -func (e *Engine) Check() bool { - return e.calculate().isOne() -} - -// Result computes pairing and returns target group element as result. -func (e *Engine) Result() *E { - r := e.calculate() - e.Reset() - return r -} - -// GT returns target group instance. -func (e *Engine) GT() *GT { - return NewGT() -} diff --git a/crypto/bls12381/pairing_test.go b/crypto/bls12381/pairing_test.go deleted file mode 100644 index 77676fe9b1f3..000000000000 --- a/crypto/bls12381/pairing_test.go +++ /dev/null @@ -1,230 +0,0 @@ -package bls12381 - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -func TestPairingExpected(t *testing.T) { - bls := NewPairingEngine() - G1, G2 := bls.G1, bls.G2 - GT := bls.GT() - expected, err := GT.FromBytes( - common.FromHex("" + - "0f41e58663bf08cf068672cbd01a7ec73baca4d72ca93544deff686bfd6df543d48eaa24afe47e1efde449383b676631" + - "04c581234d086a9902249b64728ffd21a189e87935a954051c7cdba7b3872629a4fafc05066245cb9108f0242d0fe3ef" + - "03350f55a7aefcd3c31b4fcb6ce5771cc6a0e9786ab5973320c806ad360829107ba810c5a09ffdd9be2291a0c25a99a2" + - "11b8b424cd48bf38fcef68083b0b0ec5c81a93b330ee1a677d0d15ff7b984e8978ef48881e32fac91b93b47333e2ba57" + - "06fba23eb7c5af0d9f80940ca771b6ffd5857baaf222eb95a7d2809d61bfe02e1bfd1b68ff02f0b8102ae1c2d5d5ab1a" + - "19f26337d205fb469cd6bd15c3d5a04dc88784fbb3d0b2dbdea54d43b2b73f2cbb12d58386a8703e0f948226e47ee89d" + - "018107154f25a764bd3c79937a45b84546da634b8f6be14a8061e55cceba478b23f7dacaa35c8ca78beae9624045b4b6" + - "01b2f522473d171391125ba84dc4007cfbf2f8da752f7c74185203fcca589ac719c34dffbbaad8431dad1c1fb597aaa5" + - "193502b86edb8857c273fa075a50512937e0794e1e65a7617c90d8bd66065b1fffe51d7a579973b1315021ec3c19934f" + - "1368bb445c7c2d209703f239689ce34c0378a68e72a6b3b216da0e22a5031b54ddff57309396b38c881c4c849ec23e87" + - "089a1c5b46e5110b86750ec6a532348868a84045483c92b7af5af689452eafabf1a8943e50439f1d59882a98eaa0170f" + - "1250ebd871fc0a92a7b2d83168d0d727272d441befa15c503dd8e90ce98db3e7b6d194f60839c508a84305aaca1789b6", - ), - ) - if err != nil { - t.Fatal(err) - } - r := bls.AddPair(G1.One(), G2.One()).Result() - if !r.Equal(expected) { - t.Fatal("bad pairing") - } - if !GT.IsValid(r) { - t.Fatal("element is not in correct subgroup") - } -} - -func TestPairingNonDegeneracy(t *testing.T) { - bls := NewPairingEngine() - G1, G2 := bls.G1, bls.G2 - g1Zero, g2Zero, g1One, g2One := G1.Zero(), G2.Zero(), G1.One(), G2.One() - GT := bls.GT() - // e(g1^a, g2^b) != 1 - bls.Reset() - { - bls.AddPair(g1One, g2One) - e := bls.Result() - if e.IsOne() { - t.Fatal("pairing result is not expected to be one") - } - if !GT.IsValid(e) { - t.Fatal("pairing result is not valid") - } - } - // e(g1^a, 0) == 1 - bls.Reset() - { - bls.AddPair(g1One, g2Zero) - e := bls.Result() - if !e.IsOne() { - t.Fatal("pairing result is expected to be one") - } - } - // e(0, g2^b) == 1 - bls.Reset() - { - bls.AddPair(g1Zero, g2One) - e := bls.Result() - if !e.IsOne() { - t.Fatal("pairing result is expected to be one") - } - } - // - bls.Reset() - { - bls.AddPair(g1Zero, g2One) - bls.AddPair(g1One, g2Zero) - bls.AddPair(g1Zero, g2Zero) - e := bls.Result() - if !e.IsOne() { - t.Fatal("pairing result is expected to be one") - } - } - // - bls.Reset() - { - expected, err := GT.FromBytes( - common.FromHex("" + - "0f41e58663bf08cf068672cbd01a7ec73baca4d72ca93544deff686bfd6df543d48eaa24afe47e1efde449383b676631" + - "04c581234d086a9902249b64728ffd21a189e87935a954051c7cdba7b3872629a4fafc05066245cb9108f0242d0fe3ef" + - "03350f55a7aefcd3c31b4fcb6ce5771cc6a0e9786ab5973320c806ad360829107ba810c5a09ffdd9be2291a0c25a99a2" + - "11b8b424cd48bf38fcef68083b0b0ec5c81a93b330ee1a677d0d15ff7b984e8978ef48881e32fac91b93b47333e2ba57" + - "06fba23eb7c5af0d9f80940ca771b6ffd5857baaf222eb95a7d2809d61bfe02e1bfd1b68ff02f0b8102ae1c2d5d5ab1a" + - "19f26337d205fb469cd6bd15c3d5a04dc88784fbb3d0b2dbdea54d43b2b73f2cbb12d58386a8703e0f948226e47ee89d" + - "018107154f25a764bd3c79937a45b84546da634b8f6be14a8061e55cceba478b23f7dacaa35c8ca78beae9624045b4b6" + - "01b2f522473d171391125ba84dc4007cfbf2f8da752f7c74185203fcca589ac719c34dffbbaad8431dad1c1fb597aaa5" + - "193502b86edb8857c273fa075a50512937e0794e1e65a7617c90d8bd66065b1fffe51d7a579973b1315021ec3c19934f" + - "1368bb445c7c2d209703f239689ce34c0378a68e72a6b3b216da0e22a5031b54ddff57309396b38c881c4c849ec23e87" + - "089a1c5b46e5110b86750ec6a532348868a84045483c92b7af5af689452eafabf1a8943e50439f1d59882a98eaa0170f" + - "1250ebd871fc0a92a7b2d83168d0d727272d441befa15c503dd8e90ce98db3e7b6d194f60839c508a84305aaca1789b6", - ), - ) - if err != nil { - t.Fatal(err) - } - bls.AddPair(g1Zero, g2One) - bls.AddPair(g1One, g2Zero) - bls.AddPair(g1Zero, g2Zero) - bls.AddPair(g1One, g2One) - e := bls.Result() - if !e.Equal(expected) { - t.Fatal("bad pairing") - } - } -} - -func TestPairingBilinearity(t *testing.T) { - bls := NewPairingEngine() - g1, g2 := bls.G1, bls.G2 - gt := bls.GT() - // e(a*G1, b*G2) = e(G1, G2)^c - { - a, b := big.NewInt(17), big.NewInt(117) - c := new(big.Int).Mul(a, b) - G1, G2 := g1.One(), g2.One() - e0 := bls.AddPair(G1, G2).Result() - P1, P2 := g1.New(), g2.New() - g1.MulScalar(P1, G1, a) - g2.MulScalar(P2, G2, b) - e1 := bls.AddPair(P1, P2).Result() - gt.Exp(e0, e0, c) - if !e0.Equal(e1) { - t.Fatal("bad pairing, 1") - } - } - // e(a * G1, b * G2) = e((a + b) * G1, G2) - { - // scalars - a, b := big.NewInt(17), big.NewInt(117) - c := new(big.Int).Mul(a, b) - // LHS - G1, G2 := g1.One(), g2.One() - g1.MulScalar(G1, G1, c) - bls.AddPair(G1, G2) - // RHS - P1, P2 := g1.One(), g2.One() - g1.MulScalar(P1, P1, a) - g2.MulScalar(P2, P2, b) - bls.AddPairInv(P1, P2) - // should be one - if !bls.Check() { - t.Fatal("bad pairing, 2") - } - } - // e(a * G1, b * G2) = e((a + b) * G1, G2) - { - // scalars - a, b := big.NewInt(17), big.NewInt(117) - c := new(big.Int).Mul(a, b) - // LHS - G1, G2 := g1.One(), g2.One() - g2.MulScalar(G2, G2, c) - bls.AddPair(G1, G2) - // RHS - H1, H2 := g1.One(), g2.One() - g1.MulScalar(H1, H1, a) - g2.MulScalar(H2, H2, b) - bls.AddPairInv(H1, H2) - // should be one - if !bls.Check() { - t.Fatal("bad pairing, 3") - } - } -} - -func TestPairingMulti(t *testing.T) { - // e(G1, G2) ^ t == e(a01 * G1, a02 * G2) * e(a11 * G1, a12 * G2) * ... * e(an1 * G1, an2 * G2) - // where t = sum(ai1 * ai2) - bls := NewPairingEngine() - g1, g2 := bls.G1, bls.G2 - numOfPair := 100 - targetExp := new(big.Int) - // RHS - for i := 0; i < numOfPair; i++ { - // (ai1 * G1, ai2 * G2) - a1, a2 := randScalar(q), randScalar(q) - P1, P2 := g1.One(), g2.One() - g1.MulScalar(P1, P1, a1) - g2.MulScalar(P2, P2, a2) - bls.AddPair(P1, P2) - // accumulate targetExp - // t += (ai1 * ai2) - a1.Mul(a1, a2) - targetExp.Add(targetExp, a1) - } - // LHS - // e(t * G1, G2) - T1, T2 := g1.One(), g2.One() - g1.MulScalar(T1, T1, targetExp) - bls.AddPairInv(T1, T2) - if !bls.Check() { - t.Fatal("fail multi pairing") - } -} - -func TestPairingEmpty(t *testing.T) { - bls := NewPairingEngine() - if !bls.Check() { - t.Fatal("empty check should be accepted") - } - if !bls.Result().IsOne() { - t.Fatal("empty pairing result should be one") - } -} - -func BenchmarkPairing(t *testing.B) { - bls := NewPairingEngine() - g1, g2, gt := bls.G1, bls.G2, bls.GT() - bls.AddPair(g1.One(), g2.One()) - e := gt.New() - t.ResetTimer() - for i := 0; i < t.N; i++ { - e = bls.calculate() - } - _ = e -} diff --git a/crypto/bls12381/swu.go b/crypto/bls12381/swu.go deleted file mode 100644 index e78753b2403a..000000000000 --- a/crypto/bls12381/swu.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2020 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 bls12381 - -// swuMapG1 is implementation of Simplified Shallue-van de Woestijne-Ulas Method -// follows the implementation at draft-irtf-cfrg-hash-to-curve-06. -func swuMapG1(u *fe) (*fe, *fe) { - var params = swuParamsForG1 - var tv [4]*fe - for i := 0; i < 4; i++ { - tv[i] = new(fe) - } - square(tv[0], u) - mul(tv[0], tv[0], params.z) - square(tv[1], tv[0]) - x1 := new(fe) - add(x1, tv[0], tv[1]) - inverse(x1, x1) - e1 := x1.isZero() - one := new(fe).one() - add(x1, x1, one) - if e1 { - x1.set(params.zInv) - } - mul(x1, x1, params.minusBOverA) - gx1 := new(fe) - square(gx1, x1) - add(gx1, gx1, params.a) - mul(gx1, gx1, x1) - add(gx1, gx1, params.b) - x2 := new(fe) - mul(x2, tv[0], x1) - mul(tv[1], tv[0], tv[1]) - gx2 := new(fe) - mul(gx2, gx1, tv[1]) - e2 := !isQuadraticNonResidue(gx1) - x, y2 := new(fe), new(fe) - if e2 { - x.set(x1) - y2.set(gx1) - } else { - x.set(x2) - y2.set(gx2) - } - y := new(fe) - sqrt(y, y2) - if y.sign() != u.sign() { - neg(y, y) - } - return x, y -} - -// swuMapG2 is implementation of Simplified Shallue-van de Woestijne-Ulas Method -// defined at draft-irtf-cfrg-hash-to-curve-06. -func swuMapG2(e *fp2, u *fe2) (*fe2, *fe2) { - if e == nil { - e = newFp2() - } - params := swuParamsForG2 - var tv [4]*fe2 - for i := 0; i < 4; i++ { - tv[i] = e.new() - } - e.square(tv[0], u) - e.mul(tv[0], tv[0], params.z) - e.square(tv[1], tv[0]) - x1 := e.new() - e.add(x1, tv[0], tv[1]) - e.inverse(x1, x1) - e1 := x1.isZero() - e.add(x1, x1, e.one()) - if e1 { - x1.set(params.zInv) - } - e.mul(x1, x1, params.minusBOverA) - gx1 := e.new() - e.square(gx1, x1) - e.add(gx1, gx1, params.a) - e.mul(gx1, gx1, x1) - e.add(gx1, gx1, params.b) - x2 := e.new() - e.mul(x2, tv[0], x1) - e.mul(tv[1], tv[0], tv[1]) - gx2 := e.new() - e.mul(gx2, gx1, tv[1]) - e2 := !e.isQuadraticNonResidue(gx1) - x, y2 := e.new(), e.new() - if e2 { - x.set(x1) - y2.set(gx1) - } else { - x.set(x2) - y2.set(gx2) - } - y := e.new() - e.sqrt(y, y2) - if y.sign() != u.sign() { - e.neg(y, y) - } - return x, y -} - -var swuParamsForG1 = struct { - z *fe - zInv *fe - a *fe - b *fe - minusBOverA *fe -}{ - a: &fe{0x2f65aa0e9af5aa51, 0x86464c2d1e8416c3, 0xb85ce591b7bd31e2, 0x27e11c91b5f24e7c, 0x28376eda6bfc1835, 0x155455c3e5071d85}, - b: &fe{0xfb996971fe22a1e0, 0x9aa93eb35b742d6f, 0x8c476013de99c5c4, 0x873e27c3a221e571, 0xca72b5e45a52d888, 0x06824061418a386b}, - z: &fe{0x886c00000023ffdc, 0x0f70008d3090001d, 0x77672417ed5828c3, 0x9dac23e943dc1740, 0x50553f1b9c131521, 0x078c712fbe0ab6e8}, - zInv: &fe{0x0e8a2e8ba2e83e10, 0x5b28ba2ca4d745d1, 0x678cd5473847377a, 0x4c506dd8a8076116, 0x9bcb227d79284139, 0x0e8d3154b0ba099a}, - minusBOverA: &fe{0x052583c93555a7fe, 0x3b40d72430f93c82, 0x1b75faa0105ec983, 0x2527e7dc63851767, 0x99fffd1f34fc181d, 0x097cab54770ca0d3}, -} - -var swuParamsForG2 = struct { - z *fe2 - zInv *fe2 - a *fe2 - b *fe2 - minusBOverA *fe2 -}{ - a: &fe2{ - fe{0, 0, 0, 0, 0, 0}, - fe{0xe53a000003135242, 0x01080c0fdef80285, 0xe7889edbe340f6bd, 0x0b51375126310601, 0x02d6985717c744ab, 0x1220b4e979ea5467}, - }, - b: &fe2{ - fe{0x22ea00000cf89db2, 0x6ec832df71380aa4, 0x6e1b94403db5a66e, 0x75bf3c53a79473ba, 0x3dd3a569412c0a34, 0x125cdb5e74dc4fd1}, - fe{0x22ea00000cf89db2, 0x6ec832df71380aa4, 0x6e1b94403db5a66e, 0x75bf3c53a79473ba, 0x3dd3a569412c0a34, 0x125cdb5e74dc4fd1}, - }, - z: &fe2{ - fe{0x87ebfffffff9555c, 0x656fffe5da8ffffa, 0x0fd0749345d33ad2, 0xd951e663066576f4, 0xde291a3d41e980d3, 0x0815664c7dfe040d}, - fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206}, - }, - zInv: &fe2{ - fe{0xacd0000000011110, 0x9dd9999dc88ccccd, 0xb5ca2ac9b76352bf, 0xf1b574bcf4bc90ce, 0x42dab41f28a77081, 0x132fc6ac14cd1e12}, - fe{0xe396ffffffff2223, 0x4fbf332fcd0d9998, 0x0c4bbd3c1aff4cc4, 0x6b9c91267926ca58, 0x29ae4da6aef7f496, 0x10692e942f195791}, - }, - minusBOverA: &fe2{ - fe{0x903c555555474fb3, 0x5f98cc95ce451105, 0x9f8e582eefe0fade, 0xc68946b6aebbd062, 0x467a4ad10ee6de53, 0x0e7146f483e23a05}, - fe{0x29c2aaaaaab85af8, 0xbf133368e30eeefa, 0xc7a27a7206cffb45, 0x9dee04ce44c9425c, 0x04a15ce53464ce83, 0x0b8fcaf5b59dac95}, - }, -} diff --git a/crypto/bls12381/utils.go b/crypto/bls12381/utils.go deleted file mode 100644 index de8bf495fe7d..000000000000 --- a/crypto/bls12381/utils.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2020 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 bls12381 - -import ( - "errors" - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -func bigFromHex(hex string) *big.Int { - return new(big.Int).SetBytes(common.FromHex(hex)) -} - -// decodeFieldElement expects 64 byte input with zero top 16 bytes, -// returns lower 48 bytes. -func decodeFieldElement(in []byte) ([]byte, error) { - if len(in) != 64 { - return nil, errors.New("invalid field element length") - } - // check top bytes - for i := 0; i < 16; i++ { - if in[i] != byte(0x00) { - return nil, errors.New("invalid field element top bytes") - } - } - out := make([]byte, 48) - copy(out[:], in[16:]) - return out, nil -} diff --git a/oss-fuzz.sh b/oss-fuzz.sh index 8978de70dde9..7993dc9c6451 100644 --- a/oss-fuzz.sh +++ b/oss-fuzz.sh @@ -208,6 +208,14 @@ compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ FuzzCrossPairing fuzz_cross_pairing\ $repo/tests/fuzzers/bls12381/bls12381_test.go +compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ + FuzzG1SubgroupChecks fuzz_g1_subgroup_checks\ + $repo/tests/fuzzers/bls12381/bls12381_test.go + +compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ + FuzzG2SubgroupChecks fuzz_g2_subgroup_checks\ + $repo/tests/fuzzers/bls12381/bls12381_test.go + compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/secp256k1 \ Fuzz fuzzSecp256k1\ $repo/tests/fuzzers/secp256k1/secp_test.go diff --git a/params/protocol_params.go b/params/protocol_params.go index 4e01b80970f1..863cf58ece46 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -150,14 +150,14 @@ const ( Bn256PairingPerPointGasByzantium uint64 = 80000 // Byzantium per-point price for an elliptic curve pairing check Bn256PairingPerPointGasIstanbul uint64 = 34000 // Per-point price for an elliptic curve pairing check - Bls12381G1AddGas uint64 = 600 // Price for BLS12-381 elliptic curve G1 point addition - Bls12381G1MulGas uint64 = 12000 // Price for BLS12-381 elliptic curve G1 point scalar multiplication - Bls12381G2AddGas uint64 = 4500 // Price for BLS12-381 elliptic curve G2 point addition - Bls12381G2MulGas uint64 = 55000 // Price for BLS12-381 elliptic curve G2 point scalar multiplication - Bls12381PairingBaseGas uint64 = 115000 // Base gas price for BLS12-381 elliptic curve pairing check - Bls12381PairingPerPairGas uint64 = 23000 // Per-point pair gas price for BLS12-381 elliptic curve pairing check - Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation - Bls12381MapG2Gas uint64 = 110000 // Gas price for BLS12-381 mapping field element to G2 operation + Bls12381G1AddGas uint64 = 500 // Price for BLS12-381 elliptic curve G1 point addition + Bls12381G1MulGas uint64 = 12000 // Price for BLS12-381 elliptic curve G1 point scalar multiplication + Bls12381G2AddGas uint64 = 800 // Price for BLS12-381 elliptic curve G2 point addition + Bls12381G2MulGas uint64 = 45000 // Price for BLS12-381 elliptic curve G2 point scalar multiplication + Bls12381PairingBaseGas uint64 = 65000 // Base gas price for BLS12-381 elliptic curve pairing check + Bls12381PairingPerPairGas uint64 = 43000 // Per-point pair gas price for BLS12-381 elliptic curve pairing check + Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation + Bls12381MapG2Gas uint64 = 75000 // Gas price for BLS12-381 mapping field element to G2 operation // The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529, // up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529 diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go index 9a5c566540f7..4efc749b6fc7 100644 --- a/tests/fuzzers/bls12381/bls12381_fuzz.go +++ b/tests/fuzzers/bls12381/bls12381_fuzz.go @@ -31,10 +31,46 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto/bls12381" + bls12381 "github.com/kilic/bls12-381" blst "github.com/supranational/blst/bindings/go" ) +func fuzzG1SubgroupChecks(data []byte) int { + input := bytes.NewReader(data) + kpG1, cpG1, blG1, err := getG1Points(input) + if err != nil { + return 0 + } + inSubGroupKilic := bls12381.NewG1().InCorrectSubgroup(kpG1) + inSubGroupGnark := cpG1.IsInSubGroup() + inSubGroupBLST := blG1.InG1() + if inSubGroupKilic != inSubGroupGnark { + panic(fmt.Sprintf("differing subgroup check, kilic %v, gnark %v", inSubGroupKilic, inSubGroupGnark)) + } + if inSubGroupKilic != inSubGroupBLST { + panic(fmt.Sprintf("differing subgroup check, kilic %v, blst %v", inSubGroupKilic, inSubGroupBLST)) + } + return 1 +} + +func fuzzG2SubgroupChecks(data []byte) int { + input := bytes.NewReader(data) + kpG2, cpG2, blG2, err := getG2Points(input) + if err != nil { + return 0 + } + inSubGroupKilic := bls12381.NewG2().InCorrectSubgroup(kpG2) + inSubGroupGnark := cpG2.IsInSubGroup() + inSubGroupBLST := blG2.InG2() + if inSubGroupKilic != inSubGroupGnark { + panic(fmt.Sprintf("differing subgroup check, kilic %v, gnark %v", inSubGroupKilic, inSubGroupGnark)) + } + if inSubGroupKilic != inSubGroupBLST { + panic(fmt.Sprintf("differing subgroup check, kilic %v, blst %v", inSubGroupKilic, inSubGroupBLST)) + } + return 1 +} + func fuzzCrossPairing(data []byte) int { input := bytes.NewReader(data) @@ -51,7 +87,7 @@ func fuzzCrossPairing(data []byte) int { } // compute pairing using geth - engine := bls12381.NewPairingEngine() + engine := bls12381.NewEngine() engine.AddPair(kpG1, kpG2) kResult := engine.Result() @@ -180,7 +216,7 @@ func fuzzCrossG2Add(data []byte) int { func fuzzCrossG1MultiExp(data []byte) int { var ( input = bytes.NewReader(data) - gethScalars []*big.Int + gethScalars []*bls12381.Fr gnarkScalars []fr.Element gethPoints []*bls12381.PointG1 gnarkPoints []gnark.G1Affine @@ -197,7 +233,7 @@ func fuzzCrossG1MultiExp(data []byte) int { if err != nil { break } - gethScalars = append(gethScalars, s) + gethScalars = append(gethScalars, bls12381.NewFr().FromBytes(s.Bytes())) var gnarkScalar = &fr.Element{} gnarkScalar = gnarkScalar.SetBigInt(s) gnarkScalars = append(gnarkScalars, *gnarkScalar) diff --git a/tests/fuzzers/bls12381/bls12381_test.go b/tests/fuzzers/bls12381/bls12381_test.go index 3e88979d1607..fd782f7813f0 100644 --- a/tests/fuzzers/bls12381/bls12381_test.go +++ b/tests/fuzzers/bls12381/bls12381_test.go @@ -98,3 +98,15 @@ func FuzzMapG2(f *testing.F) { fuzz(blsMapG2, data) }) } + +func FuzzG1SubgroupChecks(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzG1SubgroupChecks(data) + }) +} + +func FuzzG2SubgroupChecks(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzG2SubgroupChecks(data) + }) +} From fadd9d8b81324b0d4405de2837ac9939b2cef6c5 Mon Sep 17 00:00:00 2001 From: law wang <915337710@qq.com> Date: Tue, 16 Apr 2024 17:21:20 +0800 Subject: [PATCH 175/571] eth/catalyst: fix log (#29549) log:output the correct variable Co-authored-by: steven --- eth/catalyst/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index d154d794be1d..e279d168fe19 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -627,7 +627,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe log.Warn("State not available, ignoring new payload") return engine.PayloadStatusV1{Status: engine.ACCEPTED}, nil } - log.Trace("Inserting block without sethead", "hash", block.Hash(), "number", block.Number) + log.Trace("Inserting block without sethead", "hash", block.Hash(), "number", block.Number()) if err := api.eth.BlockChain().InsertBlockWithoutSetHead(block); err != nil { log.Warn("NewPayloadV1: inserting block failed", "error", err) From 72f69366de1d09fbe4738982fec9948ed5a69892 Mon Sep 17 00:00:00 2001 From: Chris Ziogas Date: Tue, 16 Apr 2024 15:31:19 +0300 Subject: [PATCH 176/571] c.d/utils: rename vmtrace.config to vmtrace.jsonconfig (#29554) rename vmtrace.config to vmtrace.jsonconfig for consinstency with t8ntool trace.jsonconfig --- 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 1265864e4426..05bf649d38b6 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -545,7 +545,7 @@ var ( Category: flags.VMCategory, } VMTraceConfigFlag = &cli.StringFlag{ - Name: "vmtrace.config", + Name: "vmtrace.jsonconfig", Usage: "Tracer configuration (JSON)", Category: flags.VMCategory, } From 65e32d47ea336b56d6c4bcfe212c11e8f38032bf Mon Sep 17 00:00:00 2001 From: ucwong Date: Tue, 16 Apr 2024 13:32:50 +0100 Subject: [PATCH 177/571] go.mod: clean up indirection (#29553) --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index ab268da0685b..bbf0137f4fc3 100644 --- a/go.mod +++ b/go.mod @@ -48,6 +48,7 @@ require ( github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 + github.com/kilic/bls12-381 v0.1.0 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.17 @@ -114,7 +115,6 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/kr/pretty v0.3.1 // indirect From 5ffd940b7e67ba7bb3810a9ed234b5dc45c23cdb Mon Sep 17 00:00:00 2001 From: ucwong Date: Tue, 16 Apr 2024 13:42:16 +0100 Subject: [PATCH 178/571] core: go fmt (#29544) --- core/gen_genesis.go | 56 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/core/gen_genesis.go b/core/gen_genesis.go index b8acf9df7c91..2028f98edc06 100644 --- a/core/gen_genesis.go +++ b/core/gen_genesis.go @@ -19,21 +19,21 @@ var _ = (*genesisSpecMarshaling)(nil) // MarshalJSON marshals as JSON. func (g Genesis) MarshalJSON() ([]byte, error) { type Genesis struct { - Config *params.ChainConfig `json:"config"` - Nonce math.HexOrDecimal64 `json:"nonce"` - Timestamp math.HexOrDecimal64 `json:"timestamp"` - ExtraData hexutil.Bytes `json:"extraData"` - GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` - Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"` - Mixhash common.Hash `json:"mixHash"` - Coinbase common.Address `json:"coinbase"` + Config *params.ChainConfig `json:"config"` + Nonce math.HexOrDecimal64 `json:"nonce"` + Timestamp math.HexOrDecimal64 `json:"timestamp"` + ExtraData hexutil.Bytes `json:"extraData"` + GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` + Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"` + Mixhash common.Hash `json:"mixHash"` + Coinbase common.Address `json:"coinbase"` Alloc map[common.UnprefixedAddress]types.Account `json:"alloc" gencodec:"required"` - Number math.HexOrDecimal64 `json:"number"` - GasUsed math.HexOrDecimal64 `json:"gasUsed"` - ParentHash common.Hash `json:"parentHash"` - BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` - ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"` - BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"` + Number math.HexOrDecimal64 `json:"number"` + GasUsed math.HexOrDecimal64 `json:"gasUsed"` + ParentHash common.Hash `json:"parentHash"` + BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` + ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"` + BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"` } var enc Genesis enc.Config = g.Config @@ -62,21 +62,21 @@ func (g Genesis) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (g *Genesis) UnmarshalJSON(input []byte) error { type Genesis struct { - Config *params.ChainConfig `json:"config"` - Nonce *math.HexOrDecimal64 `json:"nonce"` - Timestamp *math.HexOrDecimal64 `json:"timestamp"` - ExtraData *hexutil.Bytes `json:"extraData"` - GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` - Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"` - Mixhash *common.Hash `json:"mixHash"` - Coinbase *common.Address `json:"coinbase"` + Config *params.ChainConfig `json:"config"` + Nonce *math.HexOrDecimal64 `json:"nonce"` + Timestamp *math.HexOrDecimal64 `json:"timestamp"` + ExtraData *hexutil.Bytes `json:"extraData"` + GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` + Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"` + Mixhash *common.Hash `json:"mixHash"` + Coinbase *common.Address `json:"coinbase"` Alloc map[common.UnprefixedAddress]types.Account `json:"alloc" gencodec:"required"` - Number *math.HexOrDecimal64 `json:"number"` - GasUsed *math.HexOrDecimal64 `json:"gasUsed"` - ParentHash *common.Hash `json:"parentHash"` - BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` - ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"` - BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"` + Number *math.HexOrDecimal64 `json:"number"` + GasUsed *math.HexOrDecimal64 `json:"gasUsed"` + ParentHash *common.Hash `json:"parentHash"` + BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` + ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"` + BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"` } var dec Genesis if err := json.Unmarshal(input, &dec); err != nil { From 0a5102881975120b5d321e40c325edba778314d8 Mon Sep 17 00:00:00 2001 From: persmor <166146971+persmor@users.noreply.github.com> Date: Tue, 16 Apr 2024 21:44:00 +0900 Subject: [PATCH 179/571] all: fix various typos (#29542) * core/rawdb: fix typos * accounts/abi: fix typos * metrics: fix typo * beacon: fix typo * crypto: fix typo * rpc: fix typo * rpc: fix typo --- accounts/abi/reflect.go | 4 ++-- beacon/light/request/scheduler.go | 2 +- core/rawdb/accessors_snapshot.go | 6 +++--- crypto/secp256k1/secp256_test.go | 2 +- metrics/sample.go | 2 +- rpc/server.go | 2 +- rpc/service.go | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 1863e5bb7d73..729ca93c54a2 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -24,7 +24,7 @@ import ( "strings" ) -// ConvertType converts an interface of a runtime type into a interface of the +// ConvertType converts an interface of a runtime type into an interface of the // given type, e.g. turn this code: // // var fields []reflect.StructField @@ -33,7 +33,7 @@ import ( // Name: "X", // Type: reflect.TypeOf(new(big.Int)), // Tag: reflect.StructTag("json:\"" + "x" + "\""), -// } +// }) // // into: // diff --git a/beacon/light/request/scheduler.go b/beacon/light/request/scheduler.go index 20f811900ecf..4b8f6ce5703a 100644 --- a/beacon/light/request/scheduler.go +++ b/beacon/light/request/scheduler.go @@ -65,7 +65,7 @@ type Requester interface { // allow new operations. type Scheduler struct { lock sync.Mutex - modules []Module // first has highest priority + modules []Module // first has the highest priority names map[Module]string servers map[server]struct{} targets map[targetData]uint64 diff --git a/core/rawdb/accessors_snapshot.go b/core/rawdb/accessors_snapshot.go index 3c82b3f73141..5cea581fcda3 100644 --- a/core/rawdb/accessors_snapshot.go +++ b/core/rawdb/accessors_snapshot.go @@ -92,20 +92,20 @@ func DeleteAccountSnapshot(db ethdb.KeyValueWriter, hash common.Hash) { } } -// ReadStorageSnapshot retrieves the snapshot entry of an storage trie leaf. +// ReadStorageSnapshot retrieves the snapshot entry of a storage trie leaf. func ReadStorageSnapshot(db ethdb.KeyValueReader, accountHash, storageHash common.Hash) []byte { data, _ := db.Get(storageSnapshotKey(accountHash, storageHash)) return data } -// WriteStorageSnapshot stores the snapshot entry of an storage trie leaf. +// WriteStorageSnapshot stores the snapshot entry of a storage trie leaf. func WriteStorageSnapshot(db ethdb.KeyValueWriter, accountHash, storageHash common.Hash, entry []byte) { if err := db.Put(storageSnapshotKey(accountHash, storageHash), entry); err != nil { log.Crit("Failed to store storage snapshot", "err", err) } } -// DeleteStorageSnapshot removes the snapshot entry of an storage trie leaf. +// DeleteStorageSnapshot removes the snapshot entry of a storage trie leaf. func DeleteStorageSnapshot(db ethdb.KeyValueWriter, accountHash, storageHash common.Hash) { if err := db.Delete(storageSnapshotKey(accountHash, storageHash)); err != nil { log.Crit("Failed to delete storage snapshot", "err", err) diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index 8bb870fa18bc..4827cc5b255c 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -48,7 +48,7 @@ func randSig() []byte { } // tests for malleability -// highest bit of signature ECDSA s value must be 0, in the 33th byte +// the highest bit of signature ECDSA s value must be 0, in the 33th byte func compactSigCheck(t *testing.T, sig []byte) { var b = int(sig[32]) if b < 0 { diff --git a/metrics/sample.go b/metrics/sample.go index e4735fb6fffa..17b2bee28f10 100644 --- a/metrics/sample.go +++ b/metrics/sample.go @@ -153,7 +153,7 @@ func SamplePercentile(values []int64, p float64) float64 { } // CalculatePercentiles returns a slice of arbitrary percentiles of the slice of -// int64. This method returns interpolated results, so e.g if there are only two +// int64. This method returns interpolated results, so e.g. if there are only two // values, [0, 10], a 50% percentile will land between them. // // Note: As a side-effect, this method will also sort the slice of values. diff --git a/rpc/server.go b/rpc/server.go index e2f9120aa2bc..52866004f826 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -88,7 +88,7 @@ func (s *Server) SetHTTPBodyLimit(limit int) { } // RegisterName creates a service for the given receiver type under the given name. When no -// methods on the given receiver match the criteria to be either a RPC method or a +// methods on the given receiver match the criteria to be either an RPC method or a // subscription an error is returned. Otherwise a new service is created and added to the // service collection this server provides to clients. func (s *Server) RegisterName(name string, receiver interface{}) error { diff --git a/rpc/service.go b/rpc/service.go index c13b3c0af046..d50090e9fbc9 100644 --- a/rpc/service.go +++ b/rpc/service.go @@ -110,7 +110,7 @@ func (r *serviceRegistry) subscription(service, name string) *callback { } // suitableCallbacks iterates over the methods of the given type. It determines if a method -// satisfies the criteria for a RPC callback or a subscription callback and adds it to the +// satisfies the criteria for an RPC callback or a subscription callback and adds it to the // collection of callbacks. See server documentation for a summary of these criteria. func suitableCallbacks(receiver reflect.Value) map[string]*callback { typ := receiver.Type() From 92da96b7d5400f006774e15d154f5fa8ea1ebd9f Mon Sep 17 00:00:00 2001 From: Devon Bear Date: Tue, 16 Apr 2024 08:57:57 -0400 Subject: [PATCH 180/571] core/vm: refactor push-functions to use `min` builtin (#29515) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * optimize-push * revert push1 change * Update instructions.go * core/vm: go format * core/vm: fix nit --------- Co-authored-by: Felix Lange Co-authored-by: Martin Holst Swende Co-authored-by: Péter Szilágyi --- core/vm/instructions.go | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 990bdbf925ad..a062bb15ff5c 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -889,22 +889,17 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - codeLen := len(scope.Contract.Code) - - startMin := codeLen - if int(*pc+1) < startMin { - startMin = int(*pc + 1) - } - - endMin := codeLen - if startMin+pushByteSize < endMin { - endMin = startMin + pushByteSize - } - - integer := new(uint256.Int) - scope.Stack.push(integer.SetBytes(common.RightPadBytes( - scope.Contract.Code[startMin:endMin], pushByteSize))) - + var ( + codeLen = len(scope.Contract.Code) + start = min(codeLen, int(*pc+1)) + end = min(codeLen, start+pushByteSize) + ) + scope.Stack.push(new(uint256.Int).SetBytes( + common.RightPadBytes( + scope.Contract.Code[start:end], + pushByteSize, + )), + ) *pc += size return nil, nil } From 27de7dec658839722c8d84963d0a9b0c09a25d25 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 17 Apr 2024 13:52:08 +0800 Subject: [PATCH 181/571] ethdb/pebble: print warning log if pebble performance degrades (#29478) --- ethdb/pebble/pebble.go | 44 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 57689ab04b9b..01bfb4be3d1d 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -45,6 +45,10 @@ const ( // metricsGatheringInterval specifies the interval to retrieve pebble database // compaction, io and pause stats to report to the user. metricsGatheringInterval = 3 * time.Second + + // degradationWarnInterval specifies how often warning should be printed if the + // leveldb database cannot keep up with requested writes. + degradationWarnInterval = time.Minute ) // Database is a persistent key-value store based on the pebble storage engine. @@ -76,14 +80,16 @@ type Database struct { log log.Logger // Contextual logger tracking the database path - activeComp int // Current number of active compactions - compStartTime time.Time // The start time of the earliest currently-active compaction - compTime atomic.Int64 // Total time spent in compaction in ns - level0Comp atomic.Uint32 // Total number of level-zero compactions - nonLevel0Comp atomic.Uint32 // Total number of non level-zero compactions - writeDelayStartTime time.Time // The start time of the latest write stall - writeDelayCount atomic.Int64 // Total number of write stall counts - writeDelayTime atomic.Int64 // Total time spent in write stalls + activeComp int // Current number of active compactions + compStartTime time.Time // The start time of the earliest currently-active compaction + compTime atomic.Int64 // Total time spent in compaction in ns + level0Comp atomic.Uint32 // Total number of level-zero compactions + nonLevel0Comp atomic.Uint32 // Total number of non level-zero compactions + + writeStalled atomic.Bool // Flag whether the write is stalled + writeDelayStartTime time.Time // The start time of the latest write stall + writeDelayCount atomic.Int64 // Total number of write stall counts + writeDelayTime atomic.Int64 // Total time spent in write stalls writeOptions *pebble.WriteOptions } @@ -112,10 +118,13 @@ func (d *Database) onCompactionEnd(info pebble.CompactionInfo) { func (d *Database) onWriteStallBegin(b pebble.WriteStallBeginInfo) { d.writeDelayStartTime = time.Now() + d.writeDelayCount.Add(1) + d.writeStalled.Store(true) } func (d *Database) onWriteStallEnd() { d.writeDelayTime.Add(int64(time.Since(d.writeDelayStartTime))) + d.writeStalled.Store(false) } // panicLogger is just a noop logger to disable Pebble's internal logger. @@ -450,13 +459,15 @@ func (d *Database) meter(refresh time.Duration, namespace string) { // Create storage and warning log tracer for write delay. var ( - compTimes [2]int64 - writeDelayTimes [2]int64 - writeDelayCounts [2]int64 - compWrites [2]int64 - compReads [2]int64 + compTimes [2]int64 + compWrites [2]int64 + compReads [2]int64 nWrites [2]int64 + + writeDelayTimes [2]int64 + writeDelayCounts [2]int64 + lastWriteStallReport time.Time ) // Iterate ad infinitum and collect the stats @@ -496,6 +507,13 @@ func (d *Database) meter(refresh time.Duration, namespace string) { if d.writeDelayMeter != nil { d.writeDelayMeter.Mark(writeDelayTimes[i%2] - writeDelayTimes[(i-1)%2]) } + // Print a warning log if writing has been stalled for a while. The log will + // be printed per minute to avoid overwhelming users. + if d.writeStalled.Load() && writeDelayCounts[i%2] == writeDelayCounts[(i-1)%2] && + time.Now().After(lastWriteStallReport.Add(degradationWarnInterval)) { + d.log.Warn("Database compacting, degraded performance") + lastWriteStallReport = time.Now() + } if d.compTimeMeter != nil { d.compTimeMeter.Mark(compTimes[i%2] - compTimes[(i-1)%2]) } From 74e8d2da97aacc2589d39584f6af74cb9d62ee3f Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Wed, 17 Apr 2024 14:24:30 +0800 Subject: [PATCH 182/571] trie/utils: simplify codeChunkIndex (#29480) minor simplification to the code --- trie/utils/verkle.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index 52e41f524352..328b2d252761 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -209,11 +209,7 @@ func codeChunkIndex(chunk *uint256.Int) (*uint256.Int, byte) { chunkOffset = new(uint256.Int).Add(codeOffset, chunk) treeIndex, subIndexMod = new(uint256.Int).DivMod(chunkOffset, verkleNodeWidth, new(uint256.Int)) ) - var subIndex byte - if len(subIndexMod) != 0 { - subIndex = byte(subIndexMod[0]) - } - return treeIndex, subIndex + return treeIndex, byte(subIndexMod.Uint64()) } // CodeChunkKey returns the verkle tree key of the code chunk for the From 1e9bf2a09ed3d82ac1aa69750a556f3ce127721d Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Wed, 17 Apr 2024 19:55:31 +0800 Subject: [PATCH 183/571] core/state: fix bug in statedb.Copy and remove unnecessary preallocation (#29563) This change removes an unnecessary preallocation and fixes a flaw with no-op copies of some parts of the statedb --- core/state/statedb.go | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index d3d383389c23..ab152dd18d66 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -696,18 +696,18 @@ func (s *StateDB) Copy() *StateDB { db: s.db, trie: s.db.CopyTrie(s.trie), originalRoot: s.originalRoot, - accounts: make(map[common.Hash][]byte), - storages: make(map[common.Hash]map[common.Hash][]byte), - accountsOrigin: make(map[common.Address][]byte), - storagesOrigin: make(map[common.Address]map[common.Hash][]byte), + accounts: copySet(s.accounts), + storages: copy2DSet(s.storages), + accountsOrigin: copySet(s.accountsOrigin), + storagesOrigin: copy2DSet(s.storagesOrigin), stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)), stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)), stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)), - stateObjectsDestruct: make(map[common.Address]*types.StateAccount, len(s.stateObjectsDestruct)), + stateObjectsDestruct: maps.Clone(s.stateObjectsDestruct), refund: s.refund, logs: make(map[common.Hash][]*types.Log, len(s.logs)), logSize: s.logSize, - preimages: make(map[common.Hash][]byte, len(s.preimages)), + preimages: maps.Clone(s.preimages), journal: newJournal(), hasher: crypto.NewKeccakState(), @@ -750,15 +750,6 @@ func (s *StateDB) Copy() *StateDB { } state.stateObjectsDirty[addr] = struct{}{} } - // Deep copy the destruction markers. - state.stateObjectsDestruct = maps.Clone(s.stateObjectsDestruct) - - // Deep copy the state changes made in the scope of block - // along with their original values. - state.accounts = copySet(s.accounts) - state.storages = copy2DSet(s.storages) - state.accountsOrigin = copySet(state.accountsOrigin) - state.storagesOrigin = copy2DSet(state.storagesOrigin) // Deep copy the logs occurred in the scope of block for hash, logs := range s.logs { @@ -769,8 +760,7 @@ func (s *StateDB) Copy() *StateDB { } state.logs[hash] = cpy } - // Deep copy the preimages occurred in the scope of block - state.preimages = maps.Clone(s.preimages) + // Do we need to copy the access list and transient storage? // In practice: No. At the start of a transaction, these two lists are empty. // In practice, we only ever copy state _between_ transactions/blocks, never From 0da69e84c0d481e42f60cecc1562c208525117eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Wed, 17 Apr 2024 17:07:28 +0200 Subject: [PATCH 184/571] beacon/blsync: proceed with empty finalized hash if proof is not expected soon (#29449) * beacon/blsync: proceed with empty finalized hash if proof is not expected soon * Update beacon/blsync/block_sync.go Co-authored-by: Felix Lange * beacon/blsync: fixed linter warning * Update beacon/blsync/block_sync.go Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --------- Co-authored-by: Felix Lange Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- beacon/blsync/block_sync.go | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/beacon/blsync/block_sync.go b/beacon/blsync/block_sync.go index ef852dfe996f..3ab156354dca 100755 --- a/beacon/blsync/block_sync.go +++ b/beacon/blsync/block_sync.go @@ -19,6 +19,7 @@ package blsync import ( "github.com/ethereum/go-ethereum/beacon/light/request" "github.com/ethereum/go-ethereum/beacon/light/sync" + "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" @@ -117,15 +118,31 @@ func (s *beaconBlockSync) updateEventFeed() { if !ok { return } - finality, ok := s.headTracker.ValidatedFinality() //TODO fetch directly if subscription does not deliver - if !ok || head.Header.Epoch() != finality.Attested.Header.Epoch() { - return - } + validatedHead := head.Header.Hash() headBlock, ok := s.recentBlocks.Get(validatedHead) if !ok { return } + + var finalizedHash common.Hash + if finality, ok := s.headTracker.ValidatedFinality(); ok { + he := head.Header.Epoch() + fe := finality.Attested.Header.Epoch() + switch { + case he == fe: + finalizedHash = finality.Finalized.PayloadHeader.BlockHash() + case he < fe: + return + case he == fe+1: + parent, ok := s.recentBlocks.Get(head.Header.ParentRoot) + if !ok || parent.Slot()/params.EpochLength == fe { + return // head is at first slot of next epoch, wait for finality update + //TODO: try to fetch finality update directly if subscription does not deliver + } + } + } + headInfo := blockHeadInfo(headBlock) if headInfo == s.lastHeadInfo { return @@ -141,6 +158,6 @@ func (s *beaconBlockSync) updateEventFeed() { s.chainHeadFeed.Send(types.ChainHeadEvent{ BeaconHead: head.Header, Block: execBlock, - Finalized: finality.Finalized.PayloadHeader.BlockHash(), + Finalized: finalizedHash, }) } From 5f9514530818c4436238d4740111bd699470f0f1 Mon Sep 17 00:00:00 2001 From: ucwong Date: Thu, 18 Apr 2024 07:21:23 +0100 Subject: [PATCH 185/571] eth/ethconfig: regenerate autogen files (#29559) eth/ethconfig/gen_config.go : go generate fix --- eth/ethconfig/gen_config.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 2abddc9e0d38..cda62bc9dd5d 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -50,6 +50,8 @@ func (c Config) MarshalTOML() (interface{}, error) { BlobPool blobpool.Config GPO gasprice.Config EnablePreimageRecording bool + VMTrace string + VMTraceConfig string DocRoot string `toml:"-"` RPCGasCap uint64 RPCEVMTimeout time.Duration @@ -91,6 +93,8 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.BlobPool = c.BlobPool enc.GPO = c.GPO enc.EnablePreimageRecording = c.EnablePreimageRecording + enc.VMTrace = c.VMTrace + enc.VMTraceConfig = c.VMTraceConfig enc.DocRoot = c.DocRoot enc.RPCGasCap = c.RPCGasCap enc.RPCEVMTimeout = c.RPCEVMTimeout @@ -136,6 +140,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { BlobPool *blobpool.Config GPO *gasprice.Config EnablePreimageRecording *bool + VMTrace *string + VMTraceConfig *string DocRoot *string `toml:"-"` RPCGasCap *uint64 RPCEVMTimeout *time.Duration @@ -246,6 +252,12 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.EnablePreimageRecording != nil { c.EnablePreimageRecording = *dec.EnablePreimageRecording } + if dec.VMTrace != nil { + c.VMTrace = *dec.VMTrace + } + if dec.VMTraceConfig != nil { + c.VMTraceConfig = *dec.VMTraceConfig + } if dec.DocRoot != nil { c.DocRoot = *dec.DocRoot } From b5902cf595b3d83f6fa96b5a501213daec169f15 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 18 Apr 2024 14:48:50 +0800 Subject: [PATCH 186/571] core: remove unused fields (#29569) --- core/headerchain.go | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/core/headerchain.go b/core/headerchain.go index 519a32ab80aa..dc28bed3c60b 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -17,12 +17,9 @@ package core import ( - crand "crypto/rand" "errors" "fmt" - "math" "math/big" - mrand "math/rand" "sync/atomic" "time" @@ -43,45 +40,41 @@ const ( numberCacheLimit = 2048 ) -// HeaderChain implements the basic block header chain logic that is shared by -// core.BlockChain and light.LightChain. It is not usable in itself, only as -// a part of either structure. +// HeaderChain implements the basic block header chain logic. It is not usable +// in itself, but rather an internal structure of core.Blockchain. // // HeaderChain is responsible for maintaining the header chain including the // header query and updating. // -// The components maintained by headerchain includes: (1) total difficulty -// (2) header (3) block hash -> number mapping (4) canonical number -> hash mapping -// and (5) head header flag. +// The data components maintained by HeaderChain include: // -// It is not thread safe either, the encapsulating chain structures should do -// the necessary mutex locking/unlocking. +// - total difficulty +// - header +// - block hash -> number mapping +// - canonical number -> hash mapping +// - head header flag. +// +// It is not thread safe, the encapsulating chain structures should do the +// necessary mutex locking/unlocking. type HeaderChain struct { config *params.ChainConfig chainDb ethdb.Database genesisHeader *types.Header - currentHeader atomic.Value // Current head of the header chain (may be above the block chain!) - currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time) + currentHeader atomic.Pointer[types.Header] // Current head of the header chain (maybe above the block chain!) + currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time) headerCache *lru.Cache[common.Hash, *types.Header] tdCache *lru.Cache[common.Hash, *big.Int] // most recent total difficulties numberCache *lru.Cache[common.Hash, uint64] // most recent block numbers procInterrupt func() bool - - rand *mrand.Rand - engine consensus.Engine + engine consensus.Engine } // NewHeaderChain creates a new HeaderChain structure. ProcInterrupt points // to the parent's interrupt semaphore. func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) { - // Seed a fast but crypto originating random generator - seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) - if err != nil { - return nil, err - } hc := &HeaderChain{ config: config, chainDb: chainDb, @@ -89,7 +82,6 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c tdCache: lru.NewCache[common.Hash, *big.Int](tdCacheLimit), numberCache: lru.NewCache[common.Hash, uint64](numberCacheLimit), procInterrupt: procInterrupt, - rand: mrand.New(mrand.NewSource(seed.Int64())), engine: engine, } hc.genesisHeader = hc.GetHeaderByNumber(0) @@ -525,7 +517,7 @@ func (hc *HeaderChain) GetCanonicalHash(number uint64) common.Hash { // CurrentHeader retrieves the current head header of the canonical chain. The // header is retrieved from the HeaderChain's internal cache. func (hc *HeaderChain) CurrentHeader() *types.Header { - return hc.currentHeader.Load().(*types.Header) + return hc.currentHeader.Load() } // SetCurrentHeader sets the in-memory head header marker of the canonical chan From 823719b9e1b72174cd8245ae9e6f6f7d7072a8d6 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 18 Apr 2024 09:08:25 +0200 Subject: [PATCH 187/571] core/vm: enable bls-precompiles for Prague (#29552) enables the bls-contracts on the "Prague" config, so that the testing-team can activate them to make tests. --- core/vm/contracts.go | 118 +++++++++++++++++++++++-------------------- core/vm/evm.go | 2 + tests/init.go | 20 ++++++++ 3 files changed, 85 insertions(+), 55 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 4ca151c3656f..3d4819a74b48 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -49,83 +49,86 @@ type PrecompiledContract interface { // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum // contracts used in the Frontier and Homestead releases. var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{1}): &ecrecover{}, - common.BytesToAddress([]byte{2}): &sha256hash{}, - common.BytesToAddress([]byte{3}): &ripemd160hash{}, - common.BytesToAddress([]byte{4}): &dataCopy{}, + common.BytesToAddress([]byte{0x1}): &ecrecover{}, + common.BytesToAddress([]byte{0x2}): &sha256hash{}, + common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x4}): &dataCopy{}, } // PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum // contracts used in the Byzantium release. var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{1}): &ecrecover{}, - common.BytesToAddress([]byte{2}): &sha256hash{}, - common.BytesToAddress([]byte{3}): &ripemd160hash{}, - common.BytesToAddress([]byte{4}): &dataCopy{}, - common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false}, - common.BytesToAddress([]byte{6}): &bn256AddByzantium{}, - common.BytesToAddress([]byte{7}): &bn256ScalarMulByzantium{}, - common.BytesToAddress([]byte{8}): &bn256PairingByzantium{}, + common.BytesToAddress([]byte{0x1}): &ecrecover{}, + common.BytesToAddress([]byte{0x2}): &sha256hash{}, + common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x4}): &dataCopy{}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false}, + common.BytesToAddress([]byte{0x6}): &bn256AddByzantium{}, + common.BytesToAddress([]byte{0x7}): &bn256ScalarMulByzantium{}, + common.BytesToAddress([]byte{0x8}): &bn256PairingByzantium{}, } // PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum // contracts used in the Istanbul release. var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{1}): &ecrecover{}, - common.BytesToAddress([]byte{2}): &sha256hash{}, - common.BytesToAddress([]byte{3}): &ripemd160hash{}, - common.BytesToAddress([]byte{4}): &dataCopy{}, - common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false}, - common.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, - common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, - common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, - common.BytesToAddress([]byte{9}): &blake2F{}, + common.BytesToAddress([]byte{0x1}): &ecrecover{}, + common.BytesToAddress([]byte{0x2}): &sha256hash{}, + common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x4}): &dataCopy{}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false}, + common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{}, + common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{}, + common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, + common.BytesToAddress([]byte{0x9}): &blake2F{}, } // PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum // contracts used in the Berlin release. var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{1}): &ecrecover{}, - common.BytesToAddress([]byte{2}): &sha256hash{}, - common.BytesToAddress([]byte{3}): &ripemd160hash{}, - common.BytesToAddress([]byte{4}): &dataCopy{}, - common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true}, - common.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, - common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, - common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, - common.BytesToAddress([]byte{9}): &blake2F{}, + common.BytesToAddress([]byte{0x1}): &ecrecover{}, + common.BytesToAddress([]byte{0x2}): &sha256hash{}, + common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x4}): &dataCopy{}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true}, + common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{}, + common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{}, + common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, + common.BytesToAddress([]byte{0x9}): &blake2F{}, } // PrecompiledContractsCancun contains the default set of pre-compiled Ethereum // contracts used in the Cancun release. var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{1}): &ecrecover{}, - common.BytesToAddress([]byte{2}): &sha256hash{}, - common.BytesToAddress([]byte{3}): &ripemd160hash{}, - common.BytesToAddress([]byte{4}): &dataCopy{}, - common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true}, - common.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, - common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, - common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, - common.BytesToAddress([]byte{9}): &blake2F{}, - common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{}, -} - -// PrecompiledContractsBLS contains the set of pre-compiled Ethereum -// contracts specified in EIP-2537. These are exported for testing purposes. -var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{11}): &bls12381G1Add{}, - common.BytesToAddress([]byte{12}): &bls12381G1Mul{}, - common.BytesToAddress([]byte{13}): &bls12381G1MultiExp{}, - common.BytesToAddress([]byte{14}): &bls12381G2Add{}, - common.BytesToAddress([]byte{15}): &bls12381G2Mul{}, - common.BytesToAddress([]byte{16}): &bls12381G2MultiExp{}, - common.BytesToAddress([]byte{17}): &bls12381Pairing{}, - common.BytesToAddress([]byte{18}): &bls12381MapG1{}, - common.BytesToAddress([]byte{19}): &bls12381MapG2{}, -} + common.BytesToAddress([]byte{0x1}): &ecrecover{}, + common.BytesToAddress([]byte{0x2}): &sha256hash{}, + common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x4}): &dataCopy{}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true}, + common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{}, + common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{}, + common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, + common.BytesToAddress([]byte{0x9}): &blake2F{}, + common.BytesToAddress([]byte{0xa}): &kzgPointEvaluation{}, +} + +// PrecompiledContractsPrague contains the set of pre-compiled Ethereum +// contracts used in the Prague release. +var PrecompiledContractsPrague = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{}, + common.BytesToAddress([]byte{0x0c}): &bls12381G1Mul{}, + common.BytesToAddress([]byte{0x0d}): &bls12381G1MultiExp{}, + common.BytesToAddress([]byte{0x0e}): &bls12381G2Add{}, + common.BytesToAddress([]byte{0x0f}): &bls12381G2Mul{}, + common.BytesToAddress([]byte{0x10}): &bls12381G2MultiExp{}, + common.BytesToAddress([]byte{0x11}): &bls12381Pairing{}, + common.BytesToAddress([]byte{0x12}): &bls12381MapG1{}, + common.BytesToAddress([]byte{0x13}): &bls12381MapG2{}, +} + +var PrecompiledContractsBLS = PrecompiledContractsPrague var ( + PrecompiledAddressesPrague []common.Address PrecompiledAddressesCancun []common.Address PrecompiledAddressesBerlin []common.Address PrecompiledAddressesIstanbul []common.Address @@ -149,11 +152,16 @@ func init() { for k := range PrecompiledContractsCancun { PrecompiledAddressesCancun = append(PrecompiledAddressesCancun, k) } + for k := range PrecompiledContractsPrague { + PrecompiledAddressesPrague = append(PrecompiledAddressesPrague, k) + } } // ActivePrecompiles returns the precompiles enabled with the current configuration. func ActivePrecompiles(rules params.Rules) []common.Address { switch { + case rules.IsPrague: + return PrecompiledAddressesPrague case rules.IsCancun: return PrecompiledAddressesCancun case rules.IsBerlin: diff --git a/core/vm/evm.go b/core/vm/evm.go index 36bbf0d3da67..045506a1fd32 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -42,6 +42,8 @@ type ( func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { var precompiles map[common.Address]PrecompiledContract switch { + case evm.chainRules.IsPrague: + precompiles = PrecompiledContractsPrague case evm.chainRules.IsCancun: precompiles = PrecompiledContractsCancun case evm.chainRules.IsBerlin: diff --git a/tests/init.go b/tests/init.go index 99b7e4d33310..8d97b4de63bb 100644 --- a/tests/init.go +++ b/tests/init.go @@ -337,6 +337,26 @@ var Forks = map[string]*params.ChainConfig{ ShanghaiTime: u64(0), CancunTime: u64(15_000), }, + "Prague": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: u64(0), + CancunTime: u64(0), + PragueTime: u64(0), + }, } // AvailableForks returns the set of defined fork names From 81349ff6e53a5bcb7adee210274171c22ae64053 Mon Sep 17 00:00:00 2001 From: ids Date: Fri, 19 Apr 2024 15:58:14 +0800 Subject: [PATCH 188/571] eth/catalyst: fix typo (#29580) --- eth/catalyst/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index e279d168fe19..0efa61587dc9 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -657,7 +657,7 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) engine.PayloadSt api.remoteBlocks.put(block.Hash(), block.Header()) // Although we don't want to trigger a sync, if there is one already in - // progress, try to extend if with the current payload request to relieve + // progress, try to extend it with the current payload request to relieve // some strain from the forkchoice update. err := api.eth.Downloader().BeaconExtend(api.eth.SyncMode(), block.Header()) if err == nil { From cce879b71b772ca9df83ada499127d6ca8e7c8f6 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Fri, 19 Apr 2024 02:07:52 -0600 Subject: [PATCH 189/571] tests: define cancun-to-prague at 15K chainconig (#29557) tests: add cancun->prague config --- tests/init.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/init.go b/tests/init.go index 8d97b4de63bb..e333587a07a7 100644 --- a/tests/init.go +++ b/tests/init.go @@ -357,6 +357,26 @@ var Forks = map[string]*params.ChainConfig{ CancunTime: u64(0), PragueTime: u64(0), }, + "CancunToPragueAtTime15k": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: u64(0), + CancunTime: u64(0), + PragueTime: u64(15_000), + }, } // AvailableForks returns the set of defined fork names From 2e06fbd409d64a400c19d26d7af383f868e34f11 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 19 Apr 2024 13:46:43 +0200 Subject: [PATCH 190/571] core/vm: add KZG benchmark (#29583) --- core/vm/contracts_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 5c4d2ba61aa5..fff5c966f34f 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -316,6 +316,8 @@ func TestPrecompiledBLS12381MapG2(t *testing.T) { testJson("blsMapG2", "f12 func TestPrecompiledPointEvaluation(t *testing.T) { testJson("pointEvaluation", "0a", t) } +func BenchmarkPrecompiledPointEvaluation(b *testing.B) { benchJson("pointEvaluation", "0a", b) } + func BenchmarkPrecompiledBLS12381G1Add(b *testing.B) { benchJson("blsG1Add", "f0a", b) } func BenchmarkPrecompiledBLS12381G1Mul(b *testing.B) { benchJson("blsG1Mul", "f0b", b) } func BenchmarkPrecompiledBLS12381G1MultiExp(b *testing.B) { benchJson("blsG1MultiExp", "f0c", b) } From 98f504f69fad798c03ad43a1fc40f243d2fc8215 Mon Sep 17 00:00:00 2001 From: bugmaker9371 <167614621+bugmaker9371@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:13:36 +0800 Subject: [PATCH 191/571] p2p/discover: fix test error messages (#29592) --- p2p/discover/v4_udp_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 361e37962648..9b80214f7552 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -282,12 +282,12 @@ func TestUDPv4_findnode(t *testing.T) { waitNeighbors := func(want []*node) { test.waitPacketOut(func(p *v4wire.Neighbors, to *net.UDPAddr, hash []byte) { if len(p.Nodes) != len(want) { - t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), bucketSize) + t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), len(want)) return } for i, n := range p.Nodes { if n.ID.ID() != want[i].ID() { - t.Errorf("result mismatch at %d:\n got: %v\n want: %v", i, n, expected.entries[i]) + t.Errorf("result mismatch at %d:\n got: %v\n want: %v", i, n, expected.entries[i]) } if !live[n.ID.ID()] { t.Errorf("result includes dead node %v", n.ID.ID()) From 28ccb2bbf82af487da856d459d4daaa7c0d9b064 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Sun, 21 Apr 2024 17:14:13 +0800 Subject: [PATCH 192/571] build: fix string compare for SortFunc (#29595) --- build/update-license.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/update-license.go b/build/update-license.go index 58e8b16045c6..f548a5995b72 100644 --- a/build/update-license.go +++ b/build/update-license.go @@ -291,8 +291,8 @@ func writeAuthors(files []string) { } } // Write sorted list of authors back to the file. - slices.SortFunc(list, func(a, b string) bool { - return strings.ToLower(a) < strings.ToLower(b) + slices.SortFunc(list, func(a, b string) int { + return strings.Compare(strings.ToLower(a), strings.ToLower(b)) }) content := new(bytes.Buffer) content.WriteString(authorsFileHeader) From ad3d8cb12a368ea901a2b36b0708480065235308 Mon Sep 17 00:00:00 2001 From: xiaodong <81516175+javaandfly@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:13:03 +0800 Subject: [PATCH 193/571] cmd/geth: remove unused parameter (#29602) --- cmd/geth/config.go | 5 ++--- cmd/geth/consolecmd.go | 4 ++-- cmd/geth/main.go | 7 +++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 3f3ed510f355..522e5e22f2a9 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -37,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/log" @@ -169,7 +168,7 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { } // makeFullNode loads geth configuration and creates the Ethereum backend. -func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { +func makeFullNode(ctx *cli.Context) *node.Node { stack, cfg := makeConfigNode(ctx) if ctx.IsSet(utils.OverrideCancun.Name) { v := ctx.Uint64(utils.OverrideCancun.Name) @@ -238,7 +237,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { utils.Fatalf("failed to register catalyst service: %v", err) } } - return stack, backend + return stack } // dumpConfig is the dumpconfig command. diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 526ede96192f..e2d31255596e 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -70,8 +70,8 @@ JavaScript API. See https://geth.ethereum.org/docs/interacting-with-geth/javascr func localConsole(ctx *cli.Context) error { // Create and start the node based on the CLI flags prepare(ctx) - stack, backend := makeFullNode(ctx) - startNode(ctx, stack, backend, true) + stack := makeFullNode(ctx) + startNode(ctx, stack, true) defer stack.Close() // Attach to the newly started node and create the JavaScript console. diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 8ec70aedf93e..37b99a2621b3 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -33,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/internal/debug" - "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -348,10 +347,10 @@ func geth(ctx *cli.Context) error { } prepare(ctx) - stack, backend := makeFullNode(ctx) + stack := makeFullNode(ctx) defer stack.Close() - startNode(ctx, stack, backend, false) + startNode(ctx, stack, false) stack.Wait() return nil } @@ -359,7 +358,7 @@ func geth(ctx *cli.Context) error { // startNode boots up the system node and all registered protocols, after which // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the // miner. -func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isConsole bool) { +func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) { debug.Memsize.Add("node", stack) // Start up the node itself From 82b0dec7135b281c1b03064d50959dc992c2f94f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 22 Apr 2024 10:31:17 +0200 Subject: [PATCH 194/571] eth/filters: remove support for pending logs (#29574) This change removes support for subscribing to pending logs. "Pending logs" were always an odd feature, because it can never be fully reliable. When support for it was added many years ago, the intention was for this to be used by wallet apps to show the 'potential future token balance' of accounts, i.e. as a way of notifying the user of incoming transfers before they were mined. In order to generate the pending logs, the node must pick a subset of all public mempool transactions, execute them in the EVM, and then dispatch the resulting logs to API consumers. --- cmd/utils/flags.go | 2 +- eth/filters/api.go | 15 +- eth/filters/filter.go | 43 +-- eth/filters/filter_system.go | 195 +----------- eth/filters/filter_system_test.go | 387 +----------------------- eth/filters/filter_test.go | 12 +- ethclient/gethclient/gethclient_test.go | 2 +- ethclient/simulated/backend.go | 2 +- 8 files changed, 44 insertions(+), 614 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 05bf649d38b6..8ef9d9e7e836 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1959,7 +1959,7 @@ func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconf }) stack.RegisterAPIs([]rpc.API{{ Namespace: "eth", - Service: filters.NewFilterAPI(filterSystem, false), + Service: filters.NewFilterAPI(filterSystem), }}) return filterSystem } diff --git a/eth/filters/api.go b/eth/filters/api.go index 56a9de1b215f..23fb1faca896 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -34,10 +34,11 @@ import ( ) var ( - errInvalidTopic = errors.New("invalid topic(s)") - errFilterNotFound = errors.New("filter not found") - errInvalidBlockRange = errors.New("invalid block range params") - errExceedMaxTopics = errors.New("exceed max topics") + errInvalidTopic = errors.New("invalid topic(s)") + errFilterNotFound = errors.New("filter not found") + errInvalidBlockRange = errors.New("invalid block range params") + errPendingLogsUnsupported = errors.New("pending logs are not supported") + errExceedMaxTopics = errors.New("exceed max topics") ) // The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0 @@ -70,10 +71,10 @@ type FilterAPI struct { } // NewFilterAPI returns a new FilterAPI instance. -func NewFilterAPI(system *FilterSystem, lightMode bool) *FilterAPI { +func NewFilterAPI(system *FilterSystem) *FilterAPI { api := &FilterAPI{ sys: system, - events: NewEventSystem(system, lightMode), + events: NewEventSystem(system), filters: make(map[rpc.ID]*filter), timeout: system.cfg.Timeout, } @@ -456,7 +457,7 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { f.txs = nil return hashes, nil } - case LogsSubscription, MinedAndPendingLogsSubscription: + case LogsSubscription: logs := f.logs f.logs = nil return returnLogs(logs), nil diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 2f59026b73ed..09ccb939073a 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -108,19 +108,9 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { return f.blockLogs(ctx, header) } - var ( - beginPending = f.begin == rpc.PendingBlockNumber.Int64() - endPending = f.end == rpc.PendingBlockNumber.Int64() - ) - - // special case for pending logs - if beginPending && !endPending { - return nil, errInvalidBlockRange - } - - // Short-cut if all we care about is pending logs - if beginPending && endPending { - return f.pendingLogs(), nil + // Disallow pending logs. + if f.begin == rpc.PendingBlockNumber.Int64() || f.end == rpc.PendingBlockNumber.Int64() { + return nil, errPendingLogsUnsupported } resolveSpecial := func(number int64) (int64, error) { @@ -165,16 +155,7 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { case log := <-logChan: logs = append(logs, log) case err := <-errChan: - if err != nil { - // if an error occurs during extraction, we do return the extracted data - return logs, err - } - // Append the pending ones - if endPending { - pendingLogs := f.pendingLogs() - logs = append(logs, pendingLogs...) - } - return logs, nil + return logs, err } } } @@ -332,22 +313,6 @@ func (f *Filter) checkMatches(ctx context.Context, header *types.Header) ([]*typ return logs, nil } -// pendingLogs returns the logs matching the filter criteria within the pending block. -func (f *Filter) pendingLogs() []*types.Log { - block, receipts, _ := f.sys.backend.Pending() - if block == nil || receipts == nil { - return nil - } - if bloomFilter(block.Bloom(), f.addresses, f.topics) { - var unfiltered []*types.Log - for _, r := range receipts { - unfiltered = append(unfiltered, r.Logs...) - } - return filterLogs(unfiltered, nil, nil, f.addresses, f.topics) - } - return nil -} - // filterLogs creates a slice of logs matching the given criteria. func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*types.Log { var check = func(log *types.Log) bool { diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index d8b41a425973..a3a2787a4144 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -30,8 +30,6 @@ import ( "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" - "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/ethdb" "github.com/ethereum/go-ethereum/event" @@ -63,7 +61,6 @@ type Backend interface { GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) - Pending() (*types.Block, types.Receipts, *state.StateDB) CurrentHeader() *types.Header ChainConfig() *params.ChainConfig @@ -152,10 +149,6 @@ const ( UnknownSubscription Type = iota // LogsSubscription queries for new or removed (chain reorg) logs LogsSubscription - // PendingLogsSubscription queries for logs in pending blocks - PendingLogsSubscription - // MinedAndPendingLogsSubscription queries for logs in mined and pending blocks. - MinedAndPendingLogsSubscription // PendingTransactionsSubscription queries for pending transactions entering // the pending state PendingTransactionsSubscription @@ -192,10 +185,8 @@ type subscription struct { // EventSystem creates subscriptions, processes events and broadcasts them to the // subscription which match the subscription criteria. type EventSystem struct { - backend Backend - sys *FilterSystem - lightMode bool - lastHead *types.Header + backend Backend + sys *FilterSystem // Subscriptions txsSub event.Subscription // Subscription for new transaction event @@ -218,11 +209,10 @@ type EventSystem struct { // // The returned manager has a loop that needs to be stopped with the Stop function // or by stopping the given mux. -func NewEventSystem(sys *FilterSystem, lightMode bool) *EventSystem { +func NewEventSystem(sys *FilterSystem) *EventSystem { m := &EventSystem{ sys: sys, backend: sys.backend, - lightMode: lightMode, install: make(chan *subscription), uninstall: make(chan *subscription), txsCh: make(chan core.NewTxsEvent, txChanSize), @@ -310,10 +300,11 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ to = rpc.BlockNumber(crit.ToBlock.Int64()) } - // only interested in pending logs - if from == rpc.PendingBlockNumber && to == rpc.PendingBlockNumber { - return es.subscribePendingLogs(crit, logs), nil + // Pending logs are not supported anymore. + if from == rpc.PendingBlockNumber || to == rpc.PendingBlockNumber { + return nil, errPendingLogsUnsupported } + // only interested in new mined logs if from == rpc.LatestBlockNumber && to == rpc.LatestBlockNumber { return es.subscribeLogs(crit, logs), nil @@ -322,10 +313,6 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ if from >= 0 && to >= 0 && to >= from { return es.subscribeLogs(crit, logs), nil } - // interested in mined logs from a specific block number, new logs and pending logs - if from >= rpc.LatestBlockNumber && to == rpc.PendingBlockNumber { - return es.subscribeMinedPendingLogs(crit, logs), nil - } // interested in logs from a specific block number to new mined blocks if from >= 0 && to == rpc.LatestBlockNumber { return es.subscribeLogs(crit, logs), nil @@ -333,23 +320,6 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ return nil, errInvalidBlockRange } -// subscribeMinedPendingLogs creates a subscription that returned mined and -// pending logs that match the given criteria. -func (es *EventSystem) subscribeMinedPendingLogs(crit ethereum.FilterQuery, logs chan []*types.Log) *Subscription { - sub := &subscription{ - id: rpc.NewID(), - typ: MinedAndPendingLogsSubscription, - logsCrit: crit, - created: time.Now(), - logs: logs, - txs: make(chan []*types.Transaction), - headers: make(chan *types.Header), - installed: make(chan struct{}), - err: make(chan error), - } - return es.subscribe(sub) -} - // subscribeLogs creates a subscription that will write all logs matching the // given criteria to the given logs channel. func (es *EventSystem) subscribeLogs(crit ethereum.FilterQuery, logs chan []*types.Log) *Subscription { @@ -367,23 +337,6 @@ func (es *EventSystem) subscribeLogs(crit ethereum.FilterQuery, logs chan []*typ return es.subscribe(sub) } -// subscribePendingLogs creates a subscription that writes contract event logs for -// transactions that enter the transaction pool. -func (es *EventSystem) subscribePendingLogs(crit ethereum.FilterQuery, logs chan []*types.Log) *Subscription { - sub := &subscription{ - id: rpc.NewID(), - typ: PendingLogsSubscription, - logsCrit: crit, - created: time.Now(), - logs: logs, - txs: make(chan []*types.Transaction), - headers: make(chan *types.Header), - installed: make(chan struct{}), - err: make(chan error), - } - return es.subscribe(sub) -} - // SubscribeNewHeads creates a subscription that writes the header of a block that is // imported in the chain. func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscription { @@ -430,18 +383,6 @@ func (es *EventSystem) handleLogs(filters filterIndex, ev []*types.Log) { } } -func (es *EventSystem) handlePendingLogs(filters filterIndex, logs []*types.Log) { - if len(logs) == 0 { - return - } - for _, f := range filters[PendingLogsSubscription] { - matchedLogs := filterLogs(logs, nil, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics) - if len(matchedLogs) > 0 { - f.logs <- matchedLogs - } - } -} - func (es *EventSystem) handleTxsEvent(filters filterIndex, ev core.NewTxsEvent) { for _, f := range filters[PendingTransactionsSubscription] { f.txs <- ev.Txs @@ -452,91 +393,6 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) for _, f := range filters[BlocksSubscription] { f.headers <- ev.Block.Header() } - if es.lightMode && len(filters[LogsSubscription]) > 0 { - es.lightFilterNewHead(ev.Block.Header(), func(header *types.Header, remove bool) { - for _, f := range filters[LogsSubscription] { - if f.logsCrit.FromBlock != nil && header.Number.Cmp(f.logsCrit.FromBlock) < 0 { - continue - } - if f.logsCrit.ToBlock != nil && header.Number.Cmp(f.logsCrit.ToBlock) > 0 { - continue - } - if matchedLogs := es.lightFilterLogs(header, f.logsCrit.Addresses, f.logsCrit.Topics, remove); len(matchedLogs) > 0 { - f.logs <- matchedLogs - } - } - }) - } -} - -func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func(*types.Header, bool)) { - oldh := es.lastHead - es.lastHead = newHeader - if oldh == nil { - return - } - newh := newHeader - // find common ancestor, create list of rolled back and new block hashes - var oldHeaders, newHeaders []*types.Header - for oldh.Hash() != newh.Hash() { - if oldh.Number.Uint64() >= newh.Number.Uint64() { - oldHeaders = append(oldHeaders, oldh) - oldh = rawdb.ReadHeader(es.backend.ChainDb(), oldh.ParentHash, oldh.Number.Uint64()-1) - } - if oldh.Number.Uint64() < newh.Number.Uint64() { - newHeaders = append(newHeaders, newh) - newh = rawdb.ReadHeader(es.backend.ChainDb(), newh.ParentHash, newh.Number.Uint64()-1) - if newh == nil { - // happens when CHT syncing, nothing to do - newh = oldh - } - } - } - // roll back old blocks - for _, h := range oldHeaders { - callBack(h, true) - } - // check new blocks (array is in reverse order) - for i := len(newHeaders) - 1; i >= 0; i-- { - callBack(newHeaders[i], false) - } -} - -// filter logs of a single header in light client mode -func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.Address, topics [][]common.Hash, remove bool) []*types.Log { - if !bloomFilter(header.Bloom, addresses, topics) { - return nil - } - // Get the logs of the block - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - cached, err := es.sys.cachedLogElem(ctx, header.Hash(), header.Number.Uint64()) - if err != nil { - return nil - } - unfiltered := append([]*types.Log{}, cached.logs...) - for i, log := range unfiltered { - // Don't modify in-cache elements - logcopy := *log - logcopy.Removed = remove - // Swap copy in-place - unfiltered[i] = &logcopy - } - logs := filterLogs(unfiltered, nil, nil, addresses, topics) - // Txhash is already resolved - if len(logs) > 0 && logs[0].TxHash != (common.Hash{}) { - return logs - } - // Resolve txhash - body, err := es.sys.cachedGetBody(ctx, cached, header.Hash(), header.Number.Uint64()) - if err != nil { - return nil - } - for _, log := range logs { - // logs are already copied, safe to modify - log.TxHash = body.Transactions[log.TxIndex].Hash() - } - return logs } // eventLoop (un)installs filters and processes mux events. @@ -564,46 +420,13 @@ func (es *EventSystem) eventLoop() { es.handleLogs(index, ev.Logs) case ev := <-es.chainCh: es.handleChainEvent(index, ev) - // If we have no pending log subscription, - // we don't need to collect any pending logs. - if len(index[PendingLogsSubscription]) == 0 { - continue - } - - // Pull the pending logs if there is a new chain head. - pendingBlock, pendingReceipts, _ := es.backend.Pending() - if pendingBlock == nil || pendingReceipts == nil { - continue - } - if pendingBlock.ParentHash() != ev.Block.Hash() { - continue - } - var logs []*types.Log - for _, receipt := range pendingReceipts { - if len(receipt.Logs) > 0 { - logs = append(logs, receipt.Logs...) - } - } - es.handlePendingLogs(index, logs) case f := <-es.install: - if f.typ == MinedAndPendingLogsSubscription { - // the type are logs and pending logs subscriptions - index[LogsSubscription][f.id] = f - index[PendingLogsSubscription][f.id] = f - } else { - index[f.typ][f.id] = f - } + index[f.typ][f.id] = f close(f.installed) case f := <-es.uninstall: - if f.typ == MinedAndPendingLogsSubscription { - // the type are logs and pending logs subscriptions - delete(index[LogsSubscription], f.id) - delete(index[PendingLogsSubscription], f.id) - } else { - delete(index[f.typ], f.id) - } + delete(index[f.typ], f.id) close(f.err) // System stopped diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 4a0f40cce934..013b9f7bc26c 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -19,7 +19,6 @@ package filters import ( "context" "errors" - "fmt" "math/big" "math/rand" "reflect" @@ -27,15 +26,12 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "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/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -125,10 +121,6 @@ func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash, number uint return logs, nil } -func (b *testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { - return b.pendingBlock, b.pendingReceipts, nil -} - func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { return b.txFeed.Subscribe(ch) } @@ -181,15 +173,6 @@ func (b *testBackend) setPending(block *types.Block, receipts types.Receipts) { b.pendingReceipts = receipts } -func (b *testBackend) notifyPending(logs []*types.Log) { - genesis := &core.Genesis{ - Config: params.TestChainConfig, - } - _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 2, func(i int, b *core.BlockGen) {}) - b.setPending(blocks[1], []*types.Receipt{{Logs: logs}}) - b.chainFeed.Send(core.ChainEvent{Block: blocks[0]}) -} - func newTestFilterSystem(t testing.TB, db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) { backend := &testBackend{db: db} sys := NewFilterSystem(backend, cfg) @@ -207,7 +190,7 @@ func TestBlockSubscription(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, false) + api = NewFilterAPI(sys) genesis = &core.Genesis{ Config: params.TestChainConfig, BaseFee: big.NewInt(params.InitialBaseFee), @@ -262,7 +245,7 @@ func TestPendingTxFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, false) + api = NewFilterAPI(sys) transactions = []*types.Transaction{ types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), @@ -318,7 +301,7 @@ func TestPendingTxFilterFullTx(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, false) + api = NewFilterAPI(sys) transactions = []*types.Transaction{ types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), @@ -374,7 +357,7 @@ func TestLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() _, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, false) + api = NewFilterAPI(sys) testCases = []struct { crit FilterCriteria @@ -386,8 +369,6 @@ func TestLogFilterCreation(t *testing.T) { {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, true}, // "mined" block range to pending {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, true}, - // new mined and pending blocks - {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, true}, // from block "higher" than to block {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}, false}, // from block "higher" than to block @@ -423,7 +404,7 @@ func TestInvalidLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() _, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, false) + api = NewFilterAPI(sys) ) // different situations where log filter creation should fail. @@ -449,7 +430,7 @@ func TestInvalidGetLogsRequest(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() _, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, false) + api = NewFilterAPI(sys) blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") ) @@ -475,7 +456,7 @@ func TestInvalidGetRangeLogsRequest(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() _, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, false) + api = NewFilterAPI(sys) ) if _, err := api.GetLogs(context.Background(), FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}); err != errInvalidBlockRange { @@ -490,7 +471,7 @@ func TestLogFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, false) + api = NewFilterAPI(sys) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -509,9 +490,6 @@ func TestLogFilter(t *testing.T) { {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}, } - expectedCase7 = []*types.Log{allLogs[3], allLogs[4], allLogs[0], allLogs[1], allLogs[2], allLogs[3], allLogs[4]} - expectedCase11 = []*types.Log{allLogs[1], allLogs[2], allLogs[1], allLogs[2]} - testCases = []struct { crit FilterCriteria expected []*types.Log @@ -529,20 +507,14 @@ func TestLogFilter(t *testing.T) { 4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""}, // match logs based on multiple addresses and "or" topics 5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[2:5], ""}, - // logs in the pending block - 6: {FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, allLogs[:2], ""}, - // mined logs with block num >= 2 or pending logs - 7: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, expectedCase7, ""}, // all "mined" logs with block num >= 2 - 8: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""}, + 6: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""}, // all "mined" logs - 9: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""}, + 7: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""}, // all "mined" logs with 1>= block num <=2 and topic secondTopic - 10: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, - // all "mined" and pending logs with topic firstTopic - 11: {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), Topics: [][]common.Hash{{firstTopic}}}, expectedCase11, ""}, + 8: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, // match all logs due to wildcard topic - 12: {FilterCriteria{Topics: [][]common.Hash{nil}}, allLogs[1:], ""}, + 9: {FilterCriteria{Topics: [][]common.Hash{nil}}, allLogs[1:], ""}, } ) @@ -557,16 +529,13 @@ func TestLogFilter(t *testing.T) { t.Fatal("Logs event not delivered") } - // set pending logs - backend.notifyPending(allLogs) - for i, tt := range testCases { var fetched []*types.Log timeout := time.Now().Add(1 * time.Second) for { // fetch all expected logs results, err := api.GetFilterChanges(tt.id) if err != nil { - t.Fatalf("Unable to fetch logs: %v", err) + t.Fatalf("test %d: unable to fetch logs: %v", i, err) } fetched = append(fetched, results.([]*types.Log)...) @@ -597,326 +566,6 @@ func TestLogFilter(t *testing.T) { } } -// TestPendingLogsSubscription tests if a subscription receives the correct pending logs that are posted to the event feed. -func TestPendingLogsSubscription(t *testing.T) { - t.Parallel() - - var ( - db = rawdb.NewMemoryDatabase() - backend, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, false) - - firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") - secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") - thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") - notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") - firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") - secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") - thirdTopic = common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333") - fourthTopic = common.HexToHash("0x4444444444444444444444444444444444444444444444444444444444444444") - notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") - - allLogs = [][]*types.Log{ - {{Address: firstAddr, Topics: []common.Hash{}, BlockNumber: 0}}, - {{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}}, - {{Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 2}}, - {{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}}, - {{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 4}}, - { - {Address: thirdAddress, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, - {Address: thirdAddress, Topics: []common.Hash{thirdTopic}, BlockNumber: 5}, - {Address: thirdAddress, Topics: []common.Hash{fourthTopic}, BlockNumber: 5}, - {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, - }, - } - - pendingBlockNumber = big.NewInt(rpc.PendingBlockNumber.Int64()) - - testCases = []struct { - crit ethereum.FilterQuery - expected []*types.Log - c chan []*types.Log - sub *Subscription - err chan error - }{ - // match all - { - ethereum.FilterQuery{FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, - flattenLogs(allLogs), - nil, nil, nil, - }, - // match none due to no matching addresses - { - ethereum.FilterQuery{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, - nil, - nil, nil, nil, - }, - // match logs based on addresses, ignore topics - { - ethereum.FilterQuery{Addresses: []common.Address{firstAddr}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, - append(flattenLogs(allLogs[:2]), allLogs[5][3]), - nil, nil, nil, - }, - // match none due to no matching topics (match with address) - { - ethereum.FilterQuery{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, - nil, - nil, nil, nil, - }, - // match logs based on addresses and topics - { - ethereum.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, - append(flattenLogs(allLogs[3:5]), allLogs[5][0]), - nil, nil, nil, - }, - // match logs based on multiple addresses and "or" topics - { - ethereum.FilterQuery{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, - append(flattenLogs(allLogs[2:5]), allLogs[5][0]), - nil, nil, nil, - }, - // multiple pending logs, should match only 2 topics from the logs in block 5 - { - ethereum.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, fourthTopic}}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, - []*types.Log{allLogs[5][0], allLogs[5][2]}, - nil, nil, nil, - }, - // match none due to only matching new mined logs - { - ethereum.FilterQuery{}, - nil, - nil, nil, nil, - }, - // match none due to only matching mined logs within a specific block range - { - ethereum.FilterQuery{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, - nil, - nil, nil, nil, - }, - // match all due to matching mined and pending logs - { - ethereum.FilterQuery{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, - flattenLogs(allLogs), - nil, nil, nil, - }, - // match none due to matching logs from a specific block number to new mined blocks - { - ethereum.FilterQuery{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, - nil, - nil, nil, nil, - }, - } - ) - - // create all subscriptions, this ensures all subscriptions are created before the events are posted. - // on slow machines this could otherwise lead to missing events when the subscription is created after - // (some) events are posted. - for i := range testCases { - testCases[i].c = make(chan []*types.Log) - testCases[i].err = make(chan error, 1) - - var err error - testCases[i].sub, err = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c) - if err != nil { - t.Fatalf("SubscribeLogs %d failed: %v\n", i, err) - } - } - - for n, test := range testCases { - i := n - tt := test - go func() { - defer tt.sub.Unsubscribe() - - var fetched []*types.Log - - timeout := time.After(1 * time.Second) - fetchLoop: - for { - select { - case logs := <-tt.c: - // Do not break early if we've fetched greater, or equal, - // to the number of logs expected. This ensures we do not - // deadlock the filter system because it will do a blocking - // send on this channel if another log arrives. - fetched = append(fetched, logs...) - case <-timeout: - break fetchLoop - } - } - - if len(fetched) != len(tt.expected) { - tt.err <- fmt.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) - return - } - - for l := range fetched { - if fetched[l].Removed { - tt.err <- fmt.Errorf("expected log not to be removed for log %d in case %d", l, i) - return - } - if !reflect.DeepEqual(fetched[l], tt.expected[l]) { - tt.err <- fmt.Errorf("invalid log on index %d for case %d\n", l, i) - return - } - } - tt.err <- nil - }() - } - - // set pending logs - var flattenLogs []*types.Log - for _, logs := range allLogs { - flattenLogs = append(flattenLogs, logs...) - } - backend.notifyPending(flattenLogs) - - for i := range testCases { - err := <-testCases[i].err - if err != nil { - t.Fatalf("test %d failed: %v", i, err) - } - <-testCases[i].sub.Err() - } -} - -func TestLightFilterLogs(t *testing.T) { - t.Parallel() - - var ( - db = rawdb.NewMemoryDatabase() - backend, sys = newTestFilterSystem(t, db, Config{}) - api = NewFilterAPI(sys, true) - signer = types.HomesteadSigner{} - - firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") - secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") - thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") - notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") - firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") - secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") - - // posted twice, once as regular logs and once as pending logs. - allLogs = []*types.Log{ - // Block 1 - {Address: firstAddr, Topics: []common.Hash{}, Data: []byte{}, BlockNumber: 2, Index: 0}, - // Block 2 - {Address: firstAddr, Topics: []common.Hash{firstTopic}, Data: []byte{}, BlockNumber: 3, Index: 0}, - {Address: secondAddr, Topics: []common.Hash{firstTopic}, Data: []byte{}, BlockNumber: 3, Index: 1}, - {Address: thirdAddress, Topics: []common.Hash{secondTopic}, Data: []byte{}, BlockNumber: 3, Index: 2}, - // Block 3 - {Address: thirdAddress, Topics: []common.Hash{secondTopic}, Data: []byte{}, BlockNumber: 4, Index: 0}, - } - - testCases = []struct { - crit FilterCriteria - expected []*types.Log - id rpc.ID - }{ - // match all - 0: {FilterCriteria{}, allLogs, ""}, - // match none due to no matching addresses - 1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, ""}, - // match logs based on addresses, ignore topics - 2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, - // match logs based on addresses and topics - 3: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""}, - // all logs with block num >= 3 - 4: {FilterCriteria{FromBlock: big.NewInt(3), ToBlock: big.NewInt(5)}, allLogs[1:], ""}, - // all logs - 5: {FilterCriteria{FromBlock: big.NewInt(0), ToBlock: big.NewInt(5)}, allLogs, ""}, - // all logs with 1>= block num <=2 and topic secondTopic - 6: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(3), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, - } - - key, _ = crypto.GenerateKey() - addr = crypto.PubkeyToAddress(key.PublicKey) - genesis = &core.Genesis{Config: params.TestChainConfig, - Alloc: types.GenesisAlloc{ - addr: {Balance: big.NewInt(params.Ether)}, - }, - } - receipts = []*types.Receipt{{ - Logs: []*types.Log{allLogs[0]}, - }, { - Logs: []*types.Log{allLogs[1], allLogs[2], allLogs[3]}, - }, { - Logs: []*types.Log{allLogs[4]}, - }} - ) - - _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 4, func(i int, b *core.BlockGen) { - if i == 0 { - return - } - receipts[i-1].Bloom = types.CreateBloom(types.Receipts{receipts[i-1]}) - b.AddUncheckedReceipt(receipts[i-1]) - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i - 1), To: &common.Address{}, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, key) - b.AddTx(tx) - }) - for i, block := range blocks { - rawdb.WriteBlock(db, block) - rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) - rawdb.WriteHeadBlockHash(db, block.Hash()) - if i > 0 { - rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), []*types.Receipt{receipts[i-1]}) - } - } - // create all filters - for i := range testCases { - id, err := api.NewFilter(testCases[i].crit) - if err != nil { - t.Fatal(err) - } - testCases[i].id = id - } - - // raise events - time.Sleep(1 * time.Second) - for _, block := range blocks { - backend.chainFeed.Send(core.ChainEvent{Block: block, Hash: common.Hash{}, Logs: allLogs}) - } - - for i, tt := range testCases { - var fetched []*types.Log - timeout := time.Now().Add(1 * time.Second) - for { // fetch all expected logs - results, err := api.GetFilterChanges(tt.id) - if err != nil { - t.Fatalf("Unable to fetch logs: %v", err) - } - fetched = append(fetched, results.([]*types.Log)...) - if len(fetched) >= len(tt.expected) { - break - } - // check timeout - if time.Now().After(timeout) { - break - } - - time.Sleep(100 * time.Millisecond) - } - - if len(fetched) != len(tt.expected) { - t.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) - return - } - - for l := range fetched { - if fetched[l].Removed { - t.Errorf("expected log not to be removed for log %d in case %d", l, i) - } - expected := *tt.expected[l] - blockNum := expected.BlockNumber - 1 - expected.BlockHash = blocks[blockNum].Hash() - expected.TxHash = blocks[blockNum].Transactions()[0].Hash() - if !reflect.DeepEqual(fetched[l], &expected) { - t.Errorf("invalid log on index %d for case %d", l, i) - } - } - } -} - // TestPendingTxFilterDeadlock tests if the event loop hangs when pending // txes arrive at the same time that one of multiple filters is timing out. // Please refer to #22131 for more details. @@ -927,7 +576,7 @@ func TestPendingTxFilterDeadlock(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend, sys = newTestFilterSystem(t, db, Config{Timeout: timeout}) - api = NewFilterAPI(sys, false) + api = NewFilterAPI(sys) done = make(chan struct{}) ) @@ -979,11 +628,3 @@ func TestPendingTxFilterDeadlock(t *testing.T) { } } } - -func flattenLogs(pl [][]*types.Log) []*types.Log { - var logs []*types.Log - for _, l := range pl { - logs = append(logs, l...) - } - return logs -} diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 48aaa584dbb1..2b3efb51b17f 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -344,16 +344,16 @@ func TestFilters(t *testing.T) { err: "safe header not found", }, { - f: sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), - want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696335"],"data":"0x","blockNumber":"0x3e9","transactionHash":"0x4110587c1b8d86edc85dce929a34127f1cb8809515a9f177c91c866de3eb0638","transactionIndex":"0x0","blockHash":"0xd5e8d4e4eb51a2a2a6ec20ef68a4c2801240743c8deb77a6a1d118ac3eefb725","logIndex":"0x0","removed":false}]`, + f: sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), + err: errPendingLogsUnsupported.Error(), }, { - f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), - want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0xb360bad5265261c075ece02d3bf0e39498a6a76310482cdfd90588748e6c5ee0","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696335"],"data":"0x","blockNumber":"0x3e9","transactionHash":"0x4110587c1b8d86edc85dce929a34127f1cb8809515a9f177c91c866de3eb0638","transactionIndex":"0x0","blockHash":"0xd5e8d4e4eb51a2a2a6ec20ef68a4c2801240743c8deb77a6a1d118ac3eefb725","logIndex":"0x0","removed":false}]`, + f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), + err: errPendingLogsUnsupported.Error(), }, { f: sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), - err: errInvalidBlockRange.Error(), + err: errPendingLogsUnsupported.Error(), }, } { logs, err := tc.f.Logs(context.Background()) @@ -375,7 +375,7 @@ func TestFilters(t *testing.T) { } t.Run("timeout", func(t *testing.T) { - f := sys.NewRangeFilter(0, -1, nil, nil) + f := sys.NewRangeFilter(0, rpc.LatestBlockNumber.Int64(), nil, nil) ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Hour)) defer cancel() _, err := f.Logs(ctx) diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 1cd9c5389b89..59ad370146bb 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -65,7 +65,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { filterSystem := filters.NewFilterSystem(ethservice.APIBackend, filters.Config{}) n.RegisterAPIs([]rpc.API{{ Namespace: "eth", - Service: filters.NewFilterAPI(filterSystem, false), + Service: filters.NewFilterAPI(filterSystem), }}) // Import the test chain. diff --git a/ethclient/simulated/backend.go b/ethclient/simulated/backend.go index d6fb886ad891..6e07aa68d071 100644 --- a/ethclient/simulated/backend.go +++ b/ethclient/simulated/backend.go @@ -114,7 +114,7 @@ func newWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (*Backe filterSystem := filters.NewFilterSystem(backend.APIBackend, filters.Config{}) stack.RegisterAPIs([]rpc.API{{ Namespace: "eth", - Service: filters.NewFilterAPI(filterSystem, false), + Service: filters.NewFilterAPI(filterSystem), }}) // Start the node if err := stack.Start(); err != nil { From c2dfe7a0c7321615e2524f1c677266de26d30d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 22 Apr 2024 12:56:54 +0300 Subject: [PATCH 195/571] go.mod: update golang/x repos (#29604) --- go.mod | 14 +++++++------- go.sum | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index bbf0137f4fc3..3cd0d82bdf7c 100644 --- a/go.mod +++ b/go.mod @@ -67,12 +67,12 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.25.7 go.uber.org/automaxprocs v1.5.2 - golang.org/x/crypto v0.21.0 - golang.org/x/sync v0.5.0 - golang.org/x/sys v0.18.0 + golang.org/x/crypto v0.22.0 + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.19.0 golang.org/x/text v0.14.0 - golang.org/x/time v0.3.0 - golang.org/x/tools v0.15.0 + golang.org/x/time v0.5.0 + golang.org/x/tools v0.20.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -140,8 +140,8 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.21.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.24.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index df357535db3f..a7b4eb1c138a 100644 --- a/go.sum +++ b/go.sum @@ -537,8 +537,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -572,8 +572,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -610,8 +610,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -630,8 +630,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -693,8 +693,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -714,8 +714,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -759,8 +759,8 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 1ec7af261223d6dad9370ee8263f86347b190bab Mon Sep 17 00:00:00 2001 From: Ryan Schneider Date: Mon, 22 Apr 2024 03:17:06 -0700 Subject: [PATCH 196/571] eth: Add eth_blobBaseFee RPC and blob fields to eth_feeHistory (#29140) Co-authored-by: lightclient Co-authored-by: Felix Lange --- eth/api_backend.go | 10 +++- eth/gasprice/feehistory.go | 67 ++++++++++++++++-------- eth/gasprice/feehistory_test.go | 10 +++- eth/gasprice/gasprice_test.go | 63 +++++++++++++++++++--- internal/ethapi/api.go | 31 ++++++++--- internal/ethapi/api_test.go | 26 ++++----- internal/ethapi/backend.go | 3 +- internal/ethapi/transaction_args_test.go | 6 ++- internal/jsre/deps/web3.js | 5 ++ 9 files changed, 167 insertions(+), 54 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index a97942599c97..8a9898b956f3 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" @@ -361,10 +362,17 @@ func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) return b.gpo.SuggestTipCap(ctx) } -func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { +func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, baseFeePerBlobGas []*big.Int, blobGasUsedRatio []float64, err error) { return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles) } +func (b *EthAPIBackend) BlobBaseFee(ctx context.Context) *big.Int { + if excess := b.CurrentHeader().ExcessBlobGas; excess != nil { + return eip4844.CalcBlobFee(*excess) + } + return nil +} + func (b *EthAPIBackend) ChainDb() ethdb.Database { return b.eth.ChainDb() } diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 1c7f8ba42a26..0410ae6b2de3 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -28,8 +28,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -63,9 +65,11 @@ type cacheKey struct { // processedFees contains the results of a processed block. type processedFees struct { - reward []*big.Int - baseFee, nextBaseFee *big.Int - gasUsedRatio float64 + reward []*big.Int + baseFee, nextBaseFee *big.Int + gasUsedRatio float64 + blobGasUsedRatio float64 + blobBaseFee, nextBlobBaseFee *big.Int } // txGasAndReward is sorted in ascending order based on reward @@ -78,16 +82,31 @@ type txGasAndReward struct { // the block field filled in, retrieves the block from the backend if not present yet and // fills in the rest of the fields. func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { - chainconfig := oracle.backend.ChainConfig() + config := oracle.backend.ChainConfig() + + // Fill in base fee and next base fee. if bf.results.baseFee = bf.header.BaseFee; bf.results.baseFee == nil { bf.results.baseFee = new(big.Int) } - if chainconfig.IsLondon(big.NewInt(int64(bf.blockNumber + 1))) { - bf.results.nextBaseFee = eip1559.CalcBaseFee(chainconfig, bf.header) + if config.IsLondon(big.NewInt(int64(bf.blockNumber + 1))) { + bf.results.nextBaseFee = eip1559.CalcBaseFee(config, bf.header) } else { bf.results.nextBaseFee = new(big.Int) } + // Fill in blob base fee and next blob base fee. + if excessBlobGas := bf.header.ExcessBlobGas; excessBlobGas != nil { + bf.results.blobBaseFee = eip4844.CalcBlobFee(*excessBlobGas) + bf.results.nextBlobBaseFee = eip4844.CalcBlobFee(eip4844.CalcExcessBlobGas(*excessBlobGas, *bf.header.BlobGasUsed)) + } else { + bf.results.blobBaseFee = new(big.Int) + bf.results.nextBlobBaseFee = new(big.Int) + } + // Compute gas used ratio for normal and blob gas. bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit) + if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil { + bf.results.blobGasUsedRatio = float64(*blobGasUsed) / params.MaxBlobGasPerBlock + } + if len(percentiles) == 0 { // rewards were not requested, return null return @@ -203,17 +222,19 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNum // or blocks older than a certain age (specified in maxHistory). The first block of the // actually processed range is returned to avoid ambiguity when parts of the requested range // are not available or when the head has changed during processing this request. -// Three arrays are returned based on the processed blocks: +// Five arrays are returned based on the processed blocks: // - reward: the requested percentiles of effective priority fees per gas of transactions in each // block, sorted in ascending order and weighted by gas used. // - baseFee: base fee per gas in the given block // - gasUsedRatio: gasUsed/gasLimit in the given block +// - blobBaseFee: the blob base fee per gas in the given block +// - blobGasUsedRatio: blobGasUsed/blobGasLimit in the given block // -// Note: baseFee includes the next block after the newest of the returned range, because this -// value can be derived from the newest block. -func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedLastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { +// Note: baseFee and blobBaseFee both include the next block after the newest of the returned range, +// because this value can be derived from the newest block. +func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedLastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { if blocks < 1 { - return common.Big0, nil, nil, nil, nil // returning with no data and no error means there are no retrievable blocks + return common.Big0, nil, nil, nil, nil, nil, nil // returning with no data and no error means there are no retrievable blocks } maxFeeHistory := oracle.maxHeaderHistory if len(rewardPercentiles) != 0 { @@ -225,10 +246,10 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL } for i, p := range rewardPercentiles { if p < 0 || p > 100 { - return common.Big0, nil, nil, nil, fmt.Errorf("%w: %f", errInvalidPercentile, p) + return common.Big0, nil, nil, nil, nil, nil, fmt.Errorf("%w: %f", errInvalidPercentile, p) } if i > 0 && p <= rewardPercentiles[i-1] { - return common.Big0, nil, nil, nil, fmt.Errorf("%w: #%d:%f >= #%d:%f", errInvalidPercentile, i-1, rewardPercentiles[i-1], i, p) + return common.Big0, nil, nil, nil, nil, nil, fmt.Errorf("%w: #%d:%f >= #%d:%f", errInvalidPercentile, i-1, rewardPercentiles[i-1], i, p) } } var ( @@ -238,7 +259,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL ) pendingBlock, pendingReceipts, lastBlock, blocks, err := oracle.resolveBlockRange(ctx, unresolvedLastBlock, blocks) if err != nil || blocks == 0 { - return common.Big0, nil, nil, nil, err + return common.Big0, nil, nil, nil, nil, nil, err } oldestBlock := lastBlock + 1 - blocks @@ -295,19 +316,22 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL }() } var ( - reward = make([][]*big.Int, blocks) - baseFee = make([]*big.Int, blocks+1) - gasUsedRatio = make([]float64, blocks) - firstMissing = blocks + reward = make([][]*big.Int, blocks) + baseFee = make([]*big.Int, blocks+1) + gasUsedRatio = make([]float64, blocks) + blobGasUsedRatio = make([]float64, blocks) + blobBaseFee = make([]*big.Int, blocks+1) + firstMissing = blocks ) for ; blocks > 0; blocks-- { fees := <-results if fees.err != nil { - return common.Big0, nil, nil, nil, fees.err + return common.Big0, nil, nil, nil, nil, nil, fees.err } i := fees.blockNumber - oldestBlock if fees.results.baseFee != nil { reward[i], baseFee[i], baseFee[i+1], gasUsedRatio[i] = fees.results.reward, fees.results.baseFee, fees.results.nextBaseFee, fees.results.gasUsedRatio + blobGasUsedRatio[i], blobBaseFee[i], blobBaseFee[i+1] = fees.results.blobGasUsedRatio, fees.results.blobBaseFee, fees.results.nextBlobBaseFee } else { // getting no block and no error means we are requesting into the future (might happen because of a reorg) if i < firstMissing { @@ -316,7 +340,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL } } if firstMissing == 0 { - return common.Big0, nil, nil, nil, nil + return common.Big0, nil, nil, nil, nil, nil, nil } if len(rewardPercentiles) != 0 { reward = reward[:firstMissing] @@ -324,5 +348,6 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL reward = nil } baseFee, gasUsedRatio = baseFee[:firstMissing+1], gasUsedRatio[:firstMissing] - return new(big.Int).SetUint64(oldestBlock), reward, baseFee, gasUsedRatio, nil + blobBaseFee, blobGasUsedRatio = blobBaseFee[:firstMissing+1], blobGasUsedRatio[:firstMissing] + return new(big.Int).SetUint64(oldestBlock), reward, baseFee, gasUsedRatio, blobBaseFee, blobGasUsedRatio, nil } diff --git a/eth/gasprice/feehistory_test.go b/eth/gasprice/feehistory_test.go index 1bcfb287a571..3d426db46fef 100644 --- a/eth/gasprice/feehistory_test.go +++ b/eth/gasprice/feehistory_test.go @@ -58,10 +58,10 @@ func TestFeeHistory(t *testing.T) { MaxHeaderHistory: c.maxHeader, MaxBlockHistory: c.maxBlock, } - backend := newTestBackend(t, big.NewInt(16), c.pending) + backend := newTestBackend(t, big.NewInt(16), big.NewInt(28), c.pending) oracle := NewOracle(backend, config) - first, reward, baseFee, ratio, err := oracle.FeeHistory(context.Background(), c.count, c.last, c.percent) + first, reward, baseFee, ratio, blobBaseFee, blobRatio, err := oracle.FeeHistory(context.Background(), c.count, c.last, c.percent) backend.teardown() expReward := c.expCount if len(c.percent) == 0 { @@ -84,6 +84,12 @@ func TestFeeHistory(t *testing.T) { if len(ratio) != c.expCount { t.Fatalf("Test case %d: gasUsedRatio array length mismatch, want %d, got %d", i, c.expCount, len(ratio)) } + if len(blobRatio) != c.expCount { + t.Fatalf("Test case %d: blobGasUsedRatio array length mismatch, want %d, got %d", i, c.expCount, len(blobRatio)) + } + if len(blobBaseFee) != len(baseFee) { + t.Fatalf("Test case %d: blobBaseFee array length mismatch, want %d, got %d", i, len(baseFee), len(blobBaseFee)) + } if err != c.expErr && !errors.Is(err, c.expErr) { t.Fatalf("Test case %d: error mismatch, want %v, got %v", i, c.expErr, err) } diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 1d2e02cde6e1..b22e75666fb9 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -18,21 +18,26 @@ package gasprice import ( "context" + "crypto/sha256" + "fmt" "math" "math/big" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "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/crypto/kzg4844" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" + "github.com/holiman/uint256" ) const testHead = 32 @@ -121,7 +126,10 @@ func (b *testBackend) teardown() { // newTestBackend creates a test backend. OBS: don't forget to invoke tearDown // after use, otherwise the blockchain instance will mem-leak via goroutines. -func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBackend { +func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pending bool) *testBackend { + if londonBlock != nil && cancunBlock != nil && londonBlock.Cmp(cancunBlock) == 1 { + panic("cannot define test backend with cancun before london") + } var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key.PublicKey) @@ -131,15 +139,27 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke Alloc: types.GenesisAlloc{addr: {Balance: big.NewInt(math.MaxInt64)}}, } signer = types.LatestSigner(gspec.Config) + + // Compute empty blob hash. + emptyBlob = kzg4844.Blob{} + emptyBlobCommit, _ = kzg4844.BlobToCommitment(&emptyBlob) + emptyBlobVHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) ) config.LondonBlock = londonBlock config.ArrowGlacierBlock = londonBlock config.GrayGlacierBlock = londonBlock - config.TerminalTotalDifficulty = common.Big0 - engine := ethash.NewFaker() + var engine consensus.Engine = beacon.New(ethash.NewFaker()) + td := params.GenesisDifficulty.Uint64() + + if cancunBlock != nil { + ts := gspec.Timestamp + cancunBlock.Uint64()*10 // fixed 10 sec block time in blockgen + config.ShanghaiTime = &ts + config.CancunTime = &ts + signer = types.LatestSigner(gspec.Config) + } // Generate testing blocks - _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, testHead+1, func(i int, b *core.BlockGen) { + db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, testHead+1, func(i int, b *core.BlockGen) { b.SetCoinbase(common.Address{1}) var txdata types.TxData @@ -164,15 +184,42 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke } } b.AddTx(types.MustSignNewTx(key, signer, txdata)) + + if cancunBlock != nil && b.Number().Cmp(cancunBlock) >= 0 { + b.SetPoS() + + // put more blobs in each new block + for j := 0; j < i && j < 6; j++ { + blobTx := &types.BlobTx{ + ChainID: uint256.MustFromBig(gspec.Config.ChainID), + Nonce: b.TxNonce(addr), + To: common.Address{}, + Gas: 30000, + GasFeeCap: uint256.NewInt(100 * params.GWei), + GasTipCap: uint256.NewInt(uint64(i+1) * params.GWei), + Data: []byte{}, + BlobFeeCap: uint256.NewInt(1), + BlobHashes: []common.Hash{emptyBlobVHash}, + Value: uint256.NewInt(100), + Sidecar: nil, + } + b.AddTx(types.MustSignNewTx(key, signer, blobTx)) + } + } + td += b.Difficulty().Uint64() }) // Construct testing chain - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil, nil) + gspec.Config.TerminalTotalDifficulty = new(big.Int).SetUint64(td) + chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create local chain, %v", err) } - chain.InsertChain(blocks) + if i, err := chain.InsertChain(blocks); err != nil { + panic(fmt.Errorf("error inserting block %d: %w", i, err)) + } chain.SetFinalized(chain.GetBlockByNumber(25).Header()) chain.SetSafe(chain.GetBlockByNumber(25).Header()) + return &testBackend{chain: chain, pending: pending} } @@ -201,7 +248,7 @@ func TestSuggestTipCap(t *testing.T) { {big.NewInt(33), big.NewInt(params.GWei * int64(30))}, // Fork point in the future } for _, c := range cases { - backend := newTestBackend(t, c.fork, false) + backend := newTestBackend(t, c.fork, nil, false) oracle := NewOracle(backend, config) // The gas price sampled is: 32G, 31G, 30G, 29G, 28G, 27G diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f965c91375a5..8b15d211d1c4 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -26,6 +26,9 @@ import ( "time" "github.com/davecgh/go-spew/spew" + "github.com/holiman/uint256" + "github.com/tyler-smith/go-bip39" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/scwallet" @@ -48,8 +51,6 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" - "github.com/holiman/uint256" - "github.com/tyler-smith/go-bip39" ) // estimateGasErrorRatio is the amount of overestimation eth_estimateGas is @@ -90,15 +91,17 @@ func (s *EthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, e } type feeHistoryResult struct { - OldestBlock *hexutil.Big `json:"oldestBlock"` - Reward [][]*hexutil.Big `json:"reward,omitempty"` - BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"` - GasUsedRatio []float64 `json:"gasUsedRatio"` + OldestBlock *hexutil.Big `json:"oldestBlock"` + Reward [][]*hexutil.Big `json:"reward,omitempty"` + BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"` + GasUsedRatio []float64 `json:"gasUsedRatio"` + BlobBaseFee []*hexutil.Big `json:"baseFeePerBlobGas,omitempty"` + BlobGasUsedRatio []float64 `json:"blobGasUsedRatio,omitempty"` } // FeeHistory returns the fee market history. func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { - oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, uint64(blockCount), lastBlock, rewardPercentiles) + oldest, reward, baseFee, gasUsed, blobBaseFee, blobGasUsed, err := s.b.FeeHistory(ctx, uint64(blockCount), lastBlock, rewardPercentiles) if err != nil { return nil, err } @@ -121,9 +124,23 @@ func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecim results.BaseFee[i] = (*hexutil.Big)(v) } } + if blobBaseFee != nil { + results.BlobBaseFee = make([]*hexutil.Big, len(blobBaseFee)) + for i, v := range blobBaseFee { + results.BlobBaseFee[i] = (*hexutil.Big)(v) + } + } + if blobGasUsed != nil { + results.BlobGasUsedRatio = blobGasUsed + } return results, nil } +// BlobBaseFee returns the base fee for blob gas at the current head. +func (s *EthereumAPI) BlobBaseFee(ctx context.Context) *hexutil.Big { + return (*hexutil.Big)(s.b.BlobBaseFee(ctx)) +} + // Syncing returns false in case the node is currently not syncing with the network. It can be up-to-date or has not // yet received the latest block headers from its pears. In case it is synchronizing: // - startingBlock: block number this node started to synchronize from diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 6aad4097fe84..1f62d0c6bde3 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -32,6 +32,9 @@ import ( "testing" "time" + "github.com/holiman/uint256" + "github.com/stretchr/testify/require" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -53,8 +56,6 @@ import ( "github.com/ethereum/go-ethereum/internal/blocktest" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "github.com/holiman/uint256" - "github.com/stretchr/testify/require" ) func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainConfig) { @@ -468,17 +469,18 @@ func (b testBackend) SyncProgress() ethereum.SyncProgress { return ethereum.Sync func (b testBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { return big.NewInt(0), nil } -func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { - return nil, nil, nil, nil, nil +func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { + return nil, nil, nil, nil, nil, nil, nil } -func (b testBackend) ChainDb() ethdb.Database { return b.db } -func (b testBackend) AccountManager() *accounts.Manager { return b.accman } -func (b testBackend) ExtRPCEnabled() bool { return false } -func (b testBackend) RPCGasCap() uint64 { return 10000000 } -func (b testBackend) RPCEVMTimeout() time.Duration { return time.Second } -func (b testBackend) RPCTxFeeCap() float64 { return 0 } -func (b testBackend) UnprotectedAllowed() bool { return false } -func (b testBackend) SetHead(number uint64) {} +func (b testBackend) BlobBaseFee(ctx context.Context) *big.Int { return new(big.Int) } +func (b testBackend) ChainDb() ethdb.Database { return b.db } +func (b testBackend) AccountManager() *accounts.Manager { return b.accman } +func (b testBackend) ExtRPCEnabled() bool { return false } +func (b testBackend) RPCGasCap() uint64 { return 10000000 } +func (b testBackend) RPCEVMTimeout() time.Duration { return time.Second } +func (b testBackend) RPCTxFeeCap() float64 { return 0 } +func (b testBackend) UnprotectedAllowed() bool { return false } +func (b testBackend) SetHead(number uint64) {} func (b testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { if number == rpc.LatestBlockNumber { return b.chain.CurrentBlock(), nil diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index fd2f5699eabf..2a45ba09210f 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -44,7 +44,8 @@ type Backend interface { SyncProgress() ethereum.SyncProgress SuggestGasTipCap(ctx context.Context) (*big.Int, error) - FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) + FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) + BlobBaseFee(ctx context.Context) *big.Int ChainDb() ethdb.Database AccountManager() *accounts.Manager ExtRPCEnabled() bool diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 24ecb1dee4e7..6750fc07a944 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -314,13 +314,15 @@ func (b *backendMock) setFork(fork string) error { func (b *backendMock) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { return big.NewInt(42), nil } +func (b *backendMock) BlobBaseFee(ctx context.Context) *big.Int { return big.NewInt(42) } + func (b *backendMock) CurrentHeader() *types.Header { return b.current } func (b *backendMock) ChainConfig() *params.ChainConfig { return b.config } // Other methods needed to implement Backend interface. func (b *backendMock) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} } -func (b *backendMock) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { - return nil, nil, nil, nil, nil +func (b *backendMock) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { + return nil, nil, nil, nil, nil, nil, nil } func (b *backendMock) ChainDb() ethdb.Database { return nil } func (b *backendMock) AccountManager() *accounts.Manager { return nil } diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index 4196cb8db0ee..b0fd8fcafc3e 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -5519,6 +5519,11 @@ var properties = function () { getter: 'eth_gasPrice', outputFormatter: formatters.outputBigNumberFormatter }), + new Property({ + name: 'blobBaseFee', + getter: 'eth_blobBaseFee', + outputFormatter: formatters.outputBigNumberFormatter + }), new Property({ name: 'accounts', getter: 'eth_accounts' From e6689fe090cc56cb3f0c1948c5e5356ea1d20c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Mon, 22 Apr 2024 13:19:42 +0200 Subject: [PATCH 197/571] beacon/light/sync: print error log if checkpoint retrieval fails (#29532) Co-authored-by: Felix Lange --- beacon/blsync/block_sync_test.go | 10 +- beacon/light/api/api_server.go | 9 +- beacon/light/api/light_api.go | 17 +-- beacon/light/request/scheduler.go | 4 +- beacon/light/request/scheduler_test.go | 4 + beacon/light/request/server.go | 7 ++ beacon/light/request/server_test.go | 1 + beacon/light/sync/head_sync_test.go | 14 ++- beacon/light/sync/test_helpers.go | 4 +- beacon/light/sync/types.go | 6 +- beacon/light/sync/update_sync.go | 139 +++++++++++++++++++++---- 11 files changed, 175 insertions(+), 40 deletions(-) diff --git a/beacon/blsync/block_sync_test.go b/beacon/blsync/block_sync_test.go index 73ae89ae734f..0525e95a8932 100644 --- a/beacon/blsync/block_sync_test.go +++ b/beacon/blsync/block_sync_test.go @@ -28,8 +28,8 @@ import ( ) var ( - testServer1 = "testServer1" - testServer2 = "testServer2" + testServer1 = testServer("testServer1") + testServer2 = testServer("testServer2") testBlock1 = types.NewBeaconBlock(&deneb.BeaconBlock{ Slot: 123, @@ -51,6 +51,12 @@ var ( }) ) +type testServer string + +func (t testServer) Name() string { + return string(t) +} + func TestBlockSync(t *testing.T) { ht := &testHeadTracker{} blockSync := newBeaconBlockSync(ht) diff --git a/beacon/light/api/api_server.go b/beacon/light/api/api_server.go index da044f4b2d6e..4b885cb8e101 100755 --- a/beacon/light/api/api_server.go +++ b/beacon/light/api/api_server.go @@ -73,8 +73,10 @@ func (s *ApiServer) SendRequest(id request.ID, req request.Request) { r.Updates, r.Committees, err = s.api.GetBestUpdatesAndCommittees(data.FirstPeriod, data.Count) resp = r case sync.ReqHeader: + var r sync.RespHeader log.Debug("Beacon API: requesting header", "reqid", id, "hash", common.Hash(data)) - resp, err = s.api.GetHeader(common.Hash(data)) + r.Header, r.Canonical, r.Finalized, err = s.api.GetHeader(common.Hash(data)) + resp = r case sync.ReqCheckpointData: log.Debug("Beacon API: requesting checkpoint data", "reqid", id, "hash", common.Hash(data)) resp, err = s.api.GetCheckpointData(common.Hash(data)) @@ -101,3 +103,8 @@ func (s *ApiServer) Unsubscribe() { s.unsubscribe = nil } } + +// Name implements request.Server +func (s *ApiServer) Name() string { + return s.api.url +} diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index ceb4261c3c9c..6892407cafd7 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -291,7 +291,9 @@ func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) { // GetHeader fetches and validates the beacon header with the given blockRoot. // If blockRoot is null hash then the latest head header is fetched. -func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, error) { +// The values of the canonical and finalized flags are also returned. Note that +// these flags are not validated. +func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool, bool, error) { var blockId string if blockRoot == (common.Hash{}) { blockId = "head" @@ -300,11 +302,12 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, error } resp, err := api.httpGetf("/eth/v1/beacon/headers/%s", blockId) if err != nil { - return types.Header{}, err + return types.Header{}, false, false, err } var data struct { - Data struct { + Finalized bool `json:"finalized"` + Data struct { Root common.Hash `json:"root"` Canonical bool `json:"canonical"` Header struct { @@ -314,16 +317,16 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, error } `json:"data"` } if err := json.Unmarshal(resp, &data); err != nil { - return types.Header{}, err + return types.Header{}, false, false, err } header := data.Data.Header.Message if blockRoot == (common.Hash{}) { blockRoot = data.Data.Root } if header.Hash() != blockRoot { - return types.Header{}, errors.New("retrieved beacon header root does not match") + return types.Header{}, false, false, errors.New("retrieved beacon header root does not match") } - return header, nil + return header, data.Data.Canonical, data.Finalized, nil } // GetCheckpointData fetches and validates bootstrap data belonging to the given checkpoint. @@ -446,7 +449,7 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() defer wg.Done() // Request initial data. - if head, err := api.GetHeader(common.Hash{}); err == nil { + if head, _, _, err := api.GetHeader(common.Hash{}); err == nil { listener.OnNewHead(head.Slot, head.Hash()) } if signedHead, err := api.GetOptimisticHeadUpdate(); err == nil { diff --git a/beacon/light/request/scheduler.go b/beacon/light/request/scheduler.go index 4b8f6ce5703a..e80daf805e86 100644 --- a/beacon/light/request/scheduler.go +++ b/beacon/light/request/scheduler.go @@ -93,7 +93,9 @@ type ( // the modules that do not interact with them directly. // In order to make module testing easier, Server interface is used in // events and modules. - Server any + Server interface { + Name() string + } Request any Response any ID uint64 diff --git a/beacon/light/request/scheduler_test.go b/beacon/light/request/scheduler_test.go index 7d5a56707864..5cd4965644b4 100644 --- a/beacon/light/request/scheduler_test.go +++ b/beacon/light/request/scheduler_test.go @@ -70,6 +70,10 @@ type testServer struct { canRequest int } +func (s *testServer) Name() string { + return "" +} + func (s *testServer) subscribe(eventCb func(Event)) { s.eventCb = eventCb } diff --git a/beacon/light/request/server.go b/beacon/light/request/server.go index bcb8744b38a4..9f3b09b81e80 100644 --- a/beacon/light/request/server.go +++ b/beacon/light/request/server.go @@ -58,6 +58,7 @@ const ( // EvResponse or EvFail. Additionally, it may also send application-defined // events that the Modules can interpret. type requestServer interface { + Name() string Subscribe(eventCallback func(Event)) SendRequest(ID, Request) Unsubscribe() @@ -69,6 +70,7 @@ type requestServer interface { // limit the number of parallel in-flight requests and temporarily disable // new requests based on timeouts and response failures. type server interface { + Server subscribe(eventCallback func(Event)) canRequestNow() bool sendRequest(Request) ID @@ -138,6 +140,11 @@ type serverWithTimeout struct { lastID ID } +// Name implements request.Server +func (s *serverWithTimeout) Name() string { + return s.parent.Name() +} + // init initializes serverWithTimeout func (s *serverWithTimeout) init(clock mclock.Clock) { s.clock = clock diff --git a/beacon/light/request/server_test.go b/beacon/light/request/server_test.go index b6b9edf9a056..38629cb8c464 100644 --- a/beacon/light/request/server_test.go +++ b/beacon/light/request/server_test.go @@ -153,6 +153,7 @@ type testRequestServer struct { eventCb func(Event) } +func (rs *testRequestServer) Name() string { return "" } func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb } func (rs *testRequestServer) SendRequest(ID, Request) {} func (rs *testRequestServer) Unsubscribe() {} diff --git a/beacon/light/sync/head_sync_test.go b/beacon/light/sync/head_sync_test.go index 2f75487f161c..a2870b2732b2 100644 --- a/beacon/light/sync/head_sync_test.go +++ b/beacon/light/sync/head_sync_test.go @@ -24,10 +24,10 @@ import ( ) var ( - testServer1 = "testServer1" - testServer2 = "testServer2" - testServer3 = "testServer3" - testServer4 = "testServer4" + testServer1 = testServer("testServer1") + testServer2 = testServer("testServer2") + testServer3 = testServer("testServer3") + testServer4 = testServer("testServer4") testHead0 = types.HeadInfo{} testHead1 = types.HeadInfo{Slot: 123, BlockRoot: common.Hash{1}} @@ -42,6 +42,12 @@ var ( testSHead4 = types.SignedHeader{SignatureSlot: 0x6444, Header: types.Header{Slot: 0x6443, StateRoot: common.Hash{4}}} ) +type testServer string + +func (t testServer) Name() string { + return string(t) +} + func TestValidatedHead(t *testing.T) { chain := &TestCommitteeChain{} ht := &TestHeadTracker{} diff --git a/beacon/light/sync/test_helpers.go b/beacon/light/sync/test_helpers.go index a1ca2b590993..9f57ceebe4d8 100644 --- a/beacon/light/sync/test_helpers.go +++ b/beacon/light/sync/test_helpers.go @@ -75,7 +75,7 @@ func (ts *TestScheduler) Run(testIndex int, exp ...any) { if count == 0 { continue } - ts.t.Errorf("Missing %d Server.Fail(s) from server %s in test case #%d", count, server.(string), testIndex) + ts.t.Errorf("Missing %d Server.Fail(s) from server %s in test case #%d", count, server.Name(), testIndex) } if !reflect.DeepEqual(ts.sent[testIndex], expReqs) { @@ -104,7 +104,7 @@ func (ts *TestScheduler) Send(server request.Server, req request.Request) reques func (ts *TestScheduler) Fail(server request.Server, desc string) { if ts.expFail[server] == 0 { - ts.t.Errorf("Unexpected Fail from server %s in test case #%d: %s", server.(string), ts.testIndex, desc) + ts.t.Errorf("Unexpected Fail from server %s in test case #%d: %s", server.Name(), ts.testIndex, desc) return } ts.expFail[server]-- diff --git a/beacon/light/sync/types.go b/beacon/light/sync/types.go index 6449ae842d00..8aa4c95f46ea 100644 --- a/beacon/light/sync/types.go +++ b/beacon/light/sync/types.go @@ -36,7 +36,11 @@ type ( Updates []*types.LightClientUpdate Committees []*types.SerializedSyncCommittee } - ReqHeader common.Hash + ReqHeader common.Hash + RespHeader struct { + Header types.Header + Canonical, Finalized bool + } ReqCheckpointData common.Hash ReqBeaconBlock common.Hash ) diff --git a/beacon/light/sync/update_sync.go b/beacon/light/sync/update_sync.go index 533e470fb022..71801b1b600f 100644 --- a/beacon/light/sync/update_sync.go +++ b/beacon/light/sync/update_sync.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/beacon/light" "github.com/ethereum/go-ethereum/beacon/light/request" + "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" @@ -42,6 +43,31 @@ type CheckpointInit struct { checkpointHash common.Hash locked request.ServerAndID initialized bool + // per-server state is used to track the state of requesting checkpoint header + // info. Part of this info (canonical and finalized state) is not validated + // and therefore it is requested from each server separately after it has + // reported a missing checkpoint (which is also not validated info). + serverState map[request.Server]serverState + // the following fields are used to determine whether the checkpoint is on + // epoch boundary. This information is validated and therefore stored globally. + parentHash common.Hash + hasEpochInfo, epochBoundary bool + cpSlot, parentSlot uint64 +} + +const ( + ssDefault = iota // no action yet or checkpoint requested + ssNeedHeader // checkpoint req failed, need cp header + ssHeaderRequested // cp header requested + ssNeedParent // cp header slot %32 != 0, need parent to check epoch boundary + ssParentRequested // cp parent header requested + ssPrintStatus // has all necessary info, print log message if init still not successful + ssDone // log message printed, no more action required +) + +type serverState struct { + state int + hasHeader, canonical, finalized bool // stored per server because not validated } // NewCheckpointInit creates a new CheckpointInit. @@ -49,40 +75,109 @@ func NewCheckpointInit(chain committeeChain, checkpointHash common.Hash) *Checkp return &CheckpointInit{ chain: chain, checkpointHash: checkpointHash, + serverState: make(map[request.Server]serverState), } } // Process implements request.Module. func (s *CheckpointInit) Process(requester request.Requester, events []request.Event) { + if s.initialized { + return + } for _, event := range events { - if !event.IsRequestEvent() { - continue - } - sid, req, resp := event.RequestInfo() - if s.locked == sid { - s.locked = request.ServerAndID{} - } - if resp != nil { - if checkpoint := resp.(*types.BootstrapData); checkpoint.Header.Hash() == common.Hash(req.(ReqCheckpointData)) { - s.chain.CheckpointInit(*checkpoint) - s.initialized = true - return + switch event.Type { + case request.EvResponse, request.EvFail, request.EvTimeout: + sid, req, resp := event.RequestInfo() + if s.locked == sid { + s.locked = request.ServerAndID{} } - - requester.Fail(event.Server, "invalid checkpoint data") + if event.Type == request.EvTimeout { + continue + } + switch s.serverState[sid.Server].state { + case ssDefault: + if resp != nil { + if checkpoint := resp.(*types.BootstrapData); checkpoint.Header.Hash() == common.Hash(req.(ReqCheckpointData)) { + s.chain.CheckpointInit(*checkpoint) + s.initialized = true + return + } + requester.Fail(event.Server, "invalid checkpoint data") + } + s.serverState[sid.Server] = serverState{state: ssNeedHeader} + case ssHeaderRequested: + if resp == nil { + s.serverState[sid.Server] = serverState{state: ssPrintStatus} + continue + } + newState := serverState{ + hasHeader: true, + canonical: resp.(RespHeader).Canonical, + finalized: resp.(RespHeader).Finalized, + } + s.cpSlot, s.parentHash = resp.(RespHeader).Header.Slot, resp.(RespHeader).Header.ParentRoot + if s.cpSlot%params.EpochLength == 0 { + s.hasEpochInfo, s.epochBoundary = true, true + } + if s.hasEpochInfo { + newState.state = ssPrintStatus + } else { + newState.state = ssNeedParent + } + s.serverState[sid.Server] = newState + case ssParentRequested: + s.parentSlot = resp.(RespHeader).Header.Slot + s.hasEpochInfo, s.epochBoundary = true, s.cpSlot/params.EpochLength > s.parentSlot/params.EpochLength + newState := s.serverState[sid.Server] + newState.state = ssPrintStatus + s.serverState[sid.Server] = newState + } + case request.EvUnregistered: + delete(s.serverState, event.Server) } } // start a request if possible - if s.initialized || s.locked != (request.ServerAndID{}) { - return + for _, server := range requester.CanSendTo() { + switch s.serverState[server].state { + case ssDefault: + if s.locked == (request.ServerAndID{}) { + id := requester.Send(server, ReqCheckpointData(s.checkpointHash)) + s.locked = request.ServerAndID{Server: server, ID: id} + } + case ssNeedHeader: + requester.Send(server, ReqHeader(s.checkpointHash)) + newState := s.serverState[server] + newState.state = ssHeaderRequested + s.serverState[server] = newState + case ssNeedParent: + requester.Send(server, ReqHeader(s.parentHash)) + newState := s.serverState[server] + newState.state = ssParentRequested + s.serverState[server] = newState + } } - cs := requester.CanSendTo() - if len(cs) == 0 { - return + // print log message if necessary + for server, state := range s.serverState { + if state.state != ssPrintStatus { + continue + } + switch { + case !state.hasHeader: + log.Error("blsync: checkpoint block is not available, reported as unknown", "server", server.Name()) + case !state.canonical: + log.Error("blsync: checkpoint block is not available, reported as non-canonical", "server", server.Name()) + case !s.hasEpochInfo: + // should be available if hasHeader is true and state is ssPrintStatus + panic("checkpoint epoch info not available when printing retrieval status") + case !s.epochBoundary: + log.Error("blsync: checkpoint block is not first of epoch", "slot", s.cpSlot, "parent", s.parentSlot, "server", server.Name()) + case !state.finalized: + log.Error("blsync: checkpoint block is reported as non-finalized", "server", server.Name()) + default: + log.Error("blsync: checkpoint not available, but reported as finalized; specified checkpoint hash might be too old", "server", server.Name()) + } + s.serverState[server] = serverState{state: ssDone} } - server := cs[0] - id := requester.Send(server, ReqCheckpointData(s.checkpointHash)) - s.locked = request.ServerAndID{Server: server, ID: id} } // ForwardUpdateSync implements request.Module; it fetches updates between the From acd1eaae2c5006dd7f5ae42455bc7f61e5471013 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 23 Apr 2024 01:00:42 +0800 Subject: [PATCH 198/571] core: remove bad block checks (#29609) --- core/blockchain.go | 24 ---------- core/blockchain_test.go | 101 ---------------------------------------- core/blocks.go | 25 ---------- core/error.go | 3 -- core/headerchain.go | 8 ---- 5 files changed, 161 deletions(-) delete mode 100644 core/blocks.go diff --git a/core/blockchain.go b/core/blockchain.go index 788804b72eaa..8c97740752bc 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -413,37 +413,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // it in advance. bc.engine.VerifyHeader(bc, bc.CurrentHeader()) - // Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain - for hash := range BadHashes { - if header := bc.GetHeaderByHash(hash); header != nil { - // get the canonical block corresponding to the offending header's number - headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64()) - // make sure the headerByNumber (if present) is in our current canonical chain - if headerByNumber != nil && headerByNumber.Hash() == header.Hash() { - log.Error("Found bad hash, rewinding chain", "number", header.Number, "hash", header.ParentHash) - if err := bc.SetHead(header.Number.Uint64() - 1); err != nil { - return nil, err - } - log.Error("Chain rewind was successful, resuming normal operation") - } - } - } - if bc.logger != nil && bc.logger.OnBlockchainInit != nil { bc.logger.OnBlockchainInit(chainConfig) } - if bc.logger != nil && bc.logger.OnGenesisBlock != nil { if block := bc.CurrentBlock(); block.Number.Uint64() == 0 { alloc, err := getGenesisState(bc.db, block.Hash()) if err != nil { return nil, fmt.Errorf("failed to get genesis state: %w", err) } - if alloc == nil { return nil, errors.New("live blockchain tracer requires genesis alloc to be set") } - bc.logger.OnGenesisBlock(bc.genesisBlock, alloc) } } @@ -1762,11 +1743,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) log.Debug("Abort during block processing") break } - // If the header is a banned one, straight out abort - if BadHashes[block.Hash()] { - bc.reportBlock(block, nil, ErrBannedHash) - return it.index, ErrBannedHash - } // If the block is known (in the middle of the chain), it's a special case for // Clique blocks where they can share state among each other, so importing an // older block might complete the state of the subsequent one. In this case, diff --git a/core/blockchain_test.go b/core/blockchain_test.go index f837397a1dd2..f20252da8c2a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -658,107 +658,6 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool, scheme } } -// Tests that the insertion functions detect banned hashes. -func TestBadHeaderHashes(t *testing.T) { - testBadHashes(t, false, rawdb.HashScheme) - testBadHashes(t, false, rawdb.PathScheme) -} -func TestBadBlockHashes(t *testing.T) { - testBadHashes(t, true, rawdb.HashScheme) - testBadHashes(t, true, rawdb.PathScheme) -} - -func testBadHashes(t *testing.T, full bool, scheme string) { - // Create a pristine chain and database - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) - if err != nil { - t.Fatalf("failed to create pristine chain: %v", err) - } - defer blockchain.Stop() - - // Create a chain, ban a hash and try to import - if full { - blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 3, ethash.NewFaker(), genDb, 10) - - BadHashes[blocks[2].Header().Hash()] = true - defer func() { delete(BadHashes, blocks[2].Header().Hash()) }() - - _, err = blockchain.InsertChain(blocks) - } else { - headers := makeHeaderChain(blockchain.chainConfig, blockchain.CurrentHeader(), 3, ethash.NewFaker(), genDb, 10) - - BadHashes[headers[2].Hash()] = true - defer func() { delete(BadHashes, headers[2].Hash()) }() - - _, err = blockchain.InsertHeaderChain(headers) - } - if !errors.Is(err, ErrBannedHash) { - t.Errorf("error mismatch: have: %v, want: %v", err, ErrBannedHash) - } -} - -// Tests that bad hashes are detected on boot, and the chain rolled back to a -// good state prior to the bad hash. -func TestReorgBadHeaderHashes(t *testing.T) { - testReorgBadHashes(t, false, rawdb.HashScheme) - testReorgBadHashes(t, false, rawdb.PathScheme) -} -func TestReorgBadBlockHashes(t *testing.T) { - testReorgBadHashes(t, true, rawdb.HashScheme) - testReorgBadHashes(t, true, rawdb.PathScheme) -} - -func testReorgBadHashes(t *testing.T, full bool, scheme string) { - // Create a pristine chain and database - genDb, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) - if err != nil { - t.Fatalf("failed to create pristine chain: %v", err) - } - // Create a chain, import and ban afterwards - headers := makeHeaderChain(blockchain.chainConfig, blockchain.CurrentHeader(), 4, ethash.NewFaker(), genDb, 10) - blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 4, ethash.NewFaker(), genDb, 10) - - if full { - if _, err = blockchain.InsertChain(blocks); err != nil { - t.Errorf("failed to import blocks: %v", err) - } - if blockchain.CurrentBlock().Hash() != blocks[3].Hash() { - t.Errorf("last block hash mismatch: have: %x, want %x", blockchain.CurrentBlock().Hash(), blocks[3].Header().Hash()) - } - BadHashes[blocks[3].Header().Hash()] = true - defer func() { delete(BadHashes, blocks[3].Header().Hash()) }() - } else { - if _, err = blockchain.InsertHeaderChain(headers); err != nil { - t.Errorf("failed to import headers: %v", err) - } - if blockchain.CurrentHeader().Hash() != headers[3].Hash() { - t.Errorf("last header hash mismatch: have: %x, want %x", blockchain.CurrentHeader().Hash(), headers[3].Hash()) - } - BadHashes[headers[3].Hash()] = true - defer func() { delete(BadHashes, headers[3].Hash()) }() - } - blockchain.Stop() - - // Create a new BlockChain and check that it rolled back the state. - ncm, err := NewBlockChain(blockchain.db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - if err != nil { - t.Fatalf("failed to create new chain manager: %v", err) - } - if full { - if ncm.CurrentBlock().Hash() != blocks[2].Header().Hash() { - t.Errorf("last block hash mismatch: have: %x, want %x", ncm.CurrentBlock().Hash(), blocks[2].Header().Hash()) - } - if blocks[2].Header().GasLimit != ncm.GasLimit() { - t.Errorf("last block gasLimit mismatch: have: %d, want %d", ncm.GasLimit(), blocks[2].Header().GasLimit) - } - } else { - if ncm.CurrentHeader().Hash() != headers[2].Hash() { - t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash()) - } - } - ncm.Stop() -} - // Tests chain insertions in the face of one entity containing an invalid nonce. func TestHeadersInsertNonceError(t *testing.T) { testInsertNonceError(t, false, rawdb.HashScheme) diff --git a/core/blocks.go b/core/blocks.go deleted file mode 100644 index f20ba4aaf295..000000000000 --- a/core/blocks.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015 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 core - -import "github.com/ethereum/go-ethereum/common" - -// BadHashes represent a set of manually tracked bad hashes (usually hard forks) -var BadHashes = map[common.Hash]bool{ - common.HexToHash("05bef30ef572270f654746da22639a7a0c97dd97a7050b9e252391996aaeb689"): true, - common.HexToHash("7d05d08cbc596a2e5e4f13b80a743e53e09221b5323c3a61946b20873e58583f"): true, -} diff --git a/core/error.go b/core/error.go index 72cacf8c78d2..e6e6ba2f90c3 100644 --- a/core/error.go +++ b/core/error.go @@ -26,9 +26,6 @@ var ( // ErrKnownBlock is returned when a block to import is already known locally. ErrKnownBlock = errors.New("block already known") - // ErrBannedHash is returned if a block to import is on the banned list. - ErrBannedHash = errors.New("banned hash") - // ErrNoGenesis is returned when there is no Genesis Block. ErrNoGenesis = errors.New("genesis not found in chain") diff --git a/core/headerchain.go b/core/headerchain.go index dc28bed3c60b..9ce8d11c40a4 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -305,14 +305,6 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header) (int, error) { return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x..], item %d is #%d [%x..] (parent [%x..])", i-1, chain[i-1].Number, parentHash.Bytes()[:4], i, chain[i].Number, hash.Bytes()[:4], chain[i].ParentHash[:4]) } - // If the header is a banned one, straight out abort - if BadHashes[chain[i].ParentHash] { - return i - 1, ErrBannedHash - } - // If it's the last header in the cunk, we need to check it too - if i == len(chain)-1 && BadHashes[chain[i].Hash()] { - return i, ErrBannedHash - } } // Start the parallel verifier abort, results := hc.engine.VerifyHeaders(hc, chain) From 853e0c23f36579423dbac8b4bcb9eeedb53daa9b Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 23 Apr 2024 10:33:36 +0200 Subject: [PATCH 199/571] eth/catalyst, trie/pathdb: fix flaky tests (#29571) This change fixes three flaky tests `TestEth2AssembleBlock`,`TestEth2NewBlock`, `TestEth2PrepareAndGetPayload` and `TestDisable`. --------- Co-authored-by: Gary Rong --- eth/catalyst/api_test.go | 8 ++++---- triedb/pathdb/database.go | 1 + triedb/pathdb/database_test.go | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index ab1d78f90e1b..b8645d6be49b 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -112,7 +112,7 @@ func TestEth2AssembleBlock(t *testing.T) { if err != nil { t.Fatalf("error signing transaction, err=%v", err) } - ethservice.TxPool().Add([]*types.Transaction{tx}, true, false) + ethservice.TxPool().Add([]*types.Transaction{tx}, true, true) blockParams := engine.PayloadAttributes{ Timestamp: blocks[9].Time() + 5, } @@ -189,7 +189,7 @@ func TestEth2PrepareAndGetPayload(t *testing.T) { // Put the 10th block's tx in the pool and produce a new block txs := blocks[9].Transactions() - ethservice.TxPool().Add(txs, true, false) + ethservice.TxPool().Add(txs, true, true) blockParams := engine.PayloadAttributes{ Timestamp: blocks[8].Time() + 5, } @@ -310,13 +310,13 @@ func TestEth2NewBlock(t *testing.T) { statedb, _ := ethservice.BlockChain().StateAt(parent.Root()) nonce := statedb.GetNonce(testAddr) tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) - ethservice.TxPool().Add([]*types.Transaction{tx}, true, false) + ethservice.TxPool().Add([]*types.Transaction{tx}, true, true) execData, err := assembleWithTransactions(api, parent.Hash(), &engine.PayloadAttributes{ Timestamp: parent.Time() + 5, }, 1) if err != nil { - t.Fatalf("Failed to create the executable data %v", err) + t.Fatalf("Failed to create the executable data, block %d: %v", i, err) } block, err := engine.ExecutableDataToBlock(*execData, nil, nil) if err != nil { diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 2e7c66280426..18f2eeef00ce 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -293,6 +293,7 @@ func (db *Database) Enable(root common.Hash) error { // Ensure the provided state root matches the stored one. root = types.TrieRootHash(root) _, stored := rawdb.ReadAccountTrieNode(db.diskdb, nil) + stored = types.TrieRootHash(stored) if stored != root { return fmt.Errorf("state root mismatch: stored %x, synced %x", stored, root) } diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 30edef2760e3..29de534589d2 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -476,13 +476,13 @@ func TestDisable(t *testing.T) { _, stored := rawdb.ReadAccountTrieNode(tester.db.diskdb, nil) if err := tester.db.Disable(); err != nil { - t.Fatal("Failed to deactivate database") + t.Fatalf("Failed to deactivate database: %v", err) } if err := tester.db.Enable(types.EmptyRootHash); err == nil { - t.Fatalf("Invalid activation should be rejected") + t.Fatal("Invalid activation should be rejected") } if err := tester.db.Enable(stored); err != nil { - t.Fatal("Failed to activate database") + t.Fatalf("Failed to activate database: %v", err) } // Ensure journal is deleted from disk From 0e380ddaf7d9ccba87d3a3688a3fb419b562451c Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:06:25 +0800 Subject: [PATCH 200/571] miner: fix typos (#29625) --- miner/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index 4924952478e5..5dc3e2056b81 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -339,7 +339,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran continue } // Error may be ignored here. The error has already been checked - // during transaction acceptance is the transaction pool. + // during transaction acceptance in the transaction pool. from, _ := types.Sender(env.signer, tx) // Check whether the tx is replay protected. If we're not in the EIP155 hf From 709e0b399712f113a907936b9f73da8c33afd3f1 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Tue, 23 Apr 2024 18:08:02 +0800 Subject: [PATCH 201/571] metrics: remove librato (#29624) --- metrics/README.md | 19 --- metrics/librato/client.go | 104 --------------- metrics/librato/librato.go | 254 ------------------------------------- 3 files changed, 377 deletions(-) delete mode 100644 metrics/librato/client.go delete mode 100644 metrics/librato/librato.go diff --git a/metrics/README.md b/metrics/README.md index e2d7945008e6..85b119470a92 100644 --- a/metrics/README.md +++ b/metrics/README.md @@ -100,24 +100,6 @@ go influxdb.InfluxDB(metrics.DefaultRegistry, ) ``` -Periodically upload every metric to Librato using the [Librato client](https://github.com/mihasya/go-metrics-librato): - -**Note**: the client included with this repository under the `librato` package -has been deprecated and moved to the repository linked above. - -```go -import "github.com/mihasya/go-metrics-librato" - -go librato.Librato(metrics.DefaultRegistry, - 10e9, // interval - "example@example.com", // account owner email address - "token", // Librato API token - "hostname", // source - []float64{0.95}, // percentiles to send - time.Millisecond, // time unit -) -``` - Periodically emit every metric to StatHat: ```go @@ -157,7 +139,6 @@ Publishing Metrics Clients are available for the following destinations: -* Librato - https://github.com/mihasya/go-metrics-librato * Graphite - https://github.com/cyberdelia/go-metrics-graphite * InfluxDB - https://github.com/vrischmann/go-metrics-influxdb * Ganglia - https://github.com/appscode/metlia diff --git a/metrics/librato/client.go b/metrics/librato/client.go deleted file mode 100644 index f1b9e1e91669..000000000000 --- a/metrics/librato/client.go +++ /dev/null @@ -1,104 +0,0 @@ -package librato - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" -) - -const Operations = "operations" -const OperationsShort = "ops" - -type LibratoClient struct { - Email, Token string -} - -// property strings -const ( - // display attributes - Color = "color" - DisplayMax = "display_max" - DisplayMin = "display_min" - DisplayUnitsLong = "display_units_long" - DisplayUnitsShort = "display_units_short" - DisplayStacked = "display_stacked" - DisplayTransform = "display_transform" - // special gauge display attributes - SummarizeFunction = "summarize_function" - Aggregate = "aggregate" - - // metric keys - Name = "name" - Period = "period" - Description = "description" - DisplayName = "display_name" - Attributes = "attributes" - - // measurement keys - MeasureTime = "measure_time" - Source = "source" - Value = "value" - - // special gauge keys - Count = "count" - Sum = "sum" - Max = "max" - Min = "min" - SumSquares = "sum_squares" - - // batch keys - Counters = "counters" - Gauges = "gauges" - - MetricsPostUrl = "https://metrics-api.librato.com/v1/metrics" -) - -type Measurement map[string]interface{} -type Metric map[string]interface{} - -type Batch struct { - Gauges []Measurement `json:"gauges,omitempty"` - Counters []Measurement `json:"counters,omitempty"` - MeasureTime int64 `json:"measure_time"` - Source string `json:"source"` -} - -func (c *LibratoClient) PostMetrics(batch Batch) (err error) { - var ( - js []byte - req *http.Request - resp *http.Response - ) - - if len(batch.Counters) == 0 && len(batch.Gauges) == 0 { - return nil - } - - if js, err = json.Marshal(batch); err != nil { - return - } - - if req, err = http.NewRequest(http.MethodPost, MetricsPostUrl, bytes.NewBuffer(js)); err != nil { - return - } - - req.Header.Set("Content-Type", "application/json") - req.SetBasicAuth(c.Email, c.Token) - - resp, err = http.DefaultClient.Do(req) - if err != nil { - return - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - var body []byte - if body, err = io.ReadAll(resp.Body); err != nil { - body = []byte(fmt.Sprintf("(could not fetch response body for error: %s)", err)) - } - err = fmt.Errorf("unable to post to Librato: %d %s %s", resp.StatusCode, resp.Status, string(body)) - } - return -} diff --git a/metrics/librato/librato.go b/metrics/librato/librato.go deleted file mode 100644 index a86f75863786..000000000000 --- a/metrics/librato/librato.go +++ /dev/null @@ -1,254 +0,0 @@ -package librato - -import ( - "fmt" - "log" - "math" - "regexp" - "time" - - "github.com/ethereum/go-ethereum/metrics" -) - -// a regexp for extracting the unit from time.Duration.String -var unitRegexp = regexp.MustCompile(`[^\\d]+$`) - -// a helper that turns a time.Duration into librato display attributes for timer metrics -func translateTimerAttributes(d time.Duration) (attrs map[string]interface{}) { - attrs = make(map[string]interface{}) - attrs[DisplayTransform] = fmt.Sprintf("x/%d", int64(d)) - attrs[DisplayUnitsShort] = string(unitRegexp.Find([]byte(d.String()))) - return -} - -type Reporter struct { - Email, Token string - Namespace string - Source string - Interval time.Duration - Registry metrics.Registry - Percentiles []float64 // percentiles to report on histogram metrics - TimerAttributes map[string]interface{} // units in which timers will be displayed - intervalSec int64 -} - -func NewReporter(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) *Reporter { - return &Reporter{e, t, "", s, d, r, p, translateTimerAttributes(u), int64(d / time.Second)} -} - -func Librato(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) { - NewReporter(r, d, e, t, s, p, u).Run() -} - -func (rep *Reporter) Run() { - log.Printf("WARNING: This client has been DEPRECATED! It has been moved to https://github.com/mihasya/go-metrics-librato and will be removed from rcrowley/go-metrics on August 5th 2015") - ticker := time.NewTicker(rep.Interval) - defer ticker.Stop() - metricsApi := &LibratoClient{rep.Email, rep.Token} - for now := range ticker.C { - var metrics Batch - var err error - if metrics, err = rep.BuildRequest(now, rep.Registry); err != nil { - log.Printf("ERROR constructing librato request body %s", err) - continue - } - if err := metricsApi.PostMetrics(metrics); err != nil { - log.Printf("ERROR sending metrics to librato %s", err) - continue - } - } -} - -// calculate sum of squares from data provided by metrics.Histogram -// see http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods -func sumSquares(icount int64, mean, stDev float64) float64 { - count := float64(icount) - sumSquared := math.Pow(count*mean, 2) - sumSquares := math.Pow(count*stDev, 2) + sumSquared/count - if math.IsNaN(sumSquares) { - return 0.0 - } - return sumSquares -} -func sumSquaresTimer(t metrics.TimerSnapshot) float64 { - count := float64(t.Count()) - sumSquared := math.Pow(count*t.Mean(), 2) - sumSquares := math.Pow(count*t.StdDev(), 2) + sumSquared/count - if math.IsNaN(sumSquares) { - return 0.0 - } - return sumSquares -} - -func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot Batch, err error) { - snapshot = Batch{ - // coerce timestamps to a stepping fn so that they line up in Librato graphs - MeasureTime: (now.Unix() / rep.intervalSec) * rep.intervalSec, - Source: rep.Source, - } - snapshot.Gauges = make([]Measurement, 0) - snapshot.Counters = make([]Measurement, 0) - histogramGaugeCount := 1 + len(rep.Percentiles) - r.Each(func(name string, metric interface{}) { - if rep.Namespace != "" { - name = fmt.Sprintf("%s.%s", rep.Namespace, name) - } - measurement := Measurement{} - measurement[Period] = rep.Interval.Seconds() - switch m := metric.(type) { - case metrics.Counter: - ms := m.Snapshot() - if ms.Count() > 0 { - measurement[Name] = fmt.Sprintf("%s.%s", name, "count") - measurement[Value] = float64(ms.Count()) - measurement[Attributes] = map[string]interface{}{ - DisplayUnitsLong: Operations, - DisplayUnitsShort: OperationsShort, - DisplayMin: "0", - } - snapshot.Counters = append(snapshot.Counters, measurement) - } - case metrics.CounterFloat64: - if count := m.Snapshot().Count(); count > 0 { - measurement[Name] = fmt.Sprintf("%s.%s", name, "count") - measurement[Value] = count - measurement[Attributes] = map[string]interface{}{ - DisplayUnitsLong: Operations, - DisplayUnitsShort: OperationsShort, - DisplayMin: "0", - } - snapshot.Counters = append(snapshot.Counters, measurement) - } - case metrics.Gauge: - measurement[Name] = name - measurement[Value] = float64(m.Snapshot().Value()) - snapshot.Gauges = append(snapshot.Gauges, measurement) - case metrics.GaugeFloat64: - measurement[Name] = name - measurement[Value] = m.Snapshot().Value() - snapshot.Gauges = append(snapshot.Gauges, measurement) - case metrics.GaugeInfo: - measurement[Name] = name - measurement[Value] = m.Snapshot().Value() - snapshot.Gauges = append(snapshot.Gauges, measurement) - case metrics.Histogram: - ms := m.Snapshot() - if ms.Count() > 0 { - gauges := make([]Measurement, histogramGaugeCount) - measurement[Name] = fmt.Sprintf("%s.%s", name, "hist") - measurement[Count] = uint64(ms.Count()) - measurement[Max] = float64(ms.Max()) - measurement[Min] = float64(ms.Min()) - measurement[Sum] = float64(ms.Sum()) - measurement[SumSquares] = sumSquares(ms.Count(), ms.Mean(), ms.StdDev()) - gauges[0] = measurement - for i, p := range rep.Percentiles { - gauges[i+1] = Measurement{ - Name: fmt.Sprintf("%s.%.2f", measurement[Name], p), - Value: ms.Percentile(p), - Period: measurement[Period], - } - } - snapshot.Gauges = append(snapshot.Gauges, gauges...) - } - case metrics.Meter: - ms := m.Snapshot() - measurement[Name] = name - measurement[Value] = float64(ms.Count()) - snapshot.Counters = append(snapshot.Counters, measurement) - snapshot.Gauges = append(snapshot.Gauges, - Measurement{ - Name: fmt.Sprintf("%s.%s", name, "1min"), - Value: ms.Rate1(), - Period: int64(rep.Interval.Seconds()), - Attributes: map[string]interface{}{ - DisplayUnitsLong: Operations, - DisplayUnitsShort: OperationsShort, - DisplayMin: "0", - }, - }, - Measurement{ - Name: fmt.Sprintf("%s.%s", name, "5min"), - Value: ms.Rate5(), - Period: int64(rep.Interval.Seconds()), - Attributes: map[string]interface{}{ - DisplayUnitsLong: Operations, - DisplayUnitsShort: OperationsShort, - DisplayMin: "0", - }, - }, - Measurement{ - Name: fmt.Sprintf("%s.%s", name, "15min"), - Value: ms.Rate15(), - Period: int64(rep.Interval.Seconds()), - Attributes: map[string]interface{}{ - DisplayUnitsLong: Operations, - DisplayUnitsShort: OperationsShort, - DisplayMin: "0", - }, - }, - ) - case metrics.Timer: - ms := m.Snapshot() - measurement[Name] = name - measurement[Value] = float64(ms.Count()) - snapshot.Counters = append(snapshot.Counters, measurement) - if ms.Count() > 0 { - libratoName := fmt.Sprintf("%s.%s", name, "timer.mean") - gauges := make([]Measurement, histogramGaugeCount) - gauges[0] = Measurement{ - Name: libratoName, - Count: uint64(ms.Count()), - Sum: ms.Mean() * float64(ms.Count()), - Max: float64(ms.Max()), - Min: float64(ms.Min()), - SumSquares: sumSquaresTimer(ms), - Period: int64(rep.Interval.Seconds()), - Attributes: rep.TimerAttributes, - } - for i, p := range rep.Percentiles { - gauges[i+1] = Measurement{ - Name: fmt.Sprintf("%s.timer.%2.0f", name, p*100), - Value: ms.Percentile(p), - Period: int64(rep.Interval.Seconds()), - Attributes: rep.TimerAttributes, - } - } - snapshot.Gauges = append(snapshot.Gauges, gauges...) - snapshot.Gauges = append(snapshot.Gauges, - Measurement{ - Name: fmt.Sprintf("%s.%s", name, "rate.1min"), - Value: ms.Rate1(), - Period: int64(rep.Interval.Seconds()), - Attributes: map[string]interface{}{ - DisplayUnitsLong: Operations, - DisplayUnitsShort: OperationsShort, - DisplayMin: "0", - }, - }, - Measurement{ - Name: fmt.Sprintf("%s.%s", name, "rate.5min"), - Value: ms.Rate5(), - Period: int64(rep.Interval.Seconds()), - Attributes: map[string]interface{}{ - DisplayUnitsLong: Operations, - DisplayUnitsShort: OperationsShort, - DisplayMin: "0", - }, - }, - Measurement{ - Name: fmt.Sprintf("%s.%s", name, "rate.15min"), - Value: ms.Rate15(), - Period: int64(rep.Interval.Seconds()), - Attributes: map[string]interface{}{ - DisplayUnitsLong: Operations, - DisplayUnitsShort: OperationsShort, - DisplayMin: "0", - }, - }, - ) - } - } - }) - return -} From b2b0e1da8cac279bf0466885d1abdc5d93402f41 Mon Sep 17 00:00:00 2001 From: haoran <159284258+hr98w@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:09:42 +0800 Subject: [PATCH 202/571] all: fix various typos (#29600) * core: fix typo * rpc: fix typo * snap: fix typo * trie: fix typo * main: fix typo * abi: fix typo * main: fix field comment for basicOp --- accounts/abi/type_test.go | 2 +- core/blockchain_insert.go | 2 +- core/state/iterator.go | 2 +- core/state/snapshot/context.go | 2 +- core/state/snapshot/iterator_binary.go | 4 ++-- core/state/snapshot/iterator_fast.go | 2 +- core/state/snapshot/snapshot.go | 2 +- core/state/state_object.go | 2 +- eth/protocols/snap/gentrie.go | 2 +- rlp/rlpgen/gen.go | 2 +- rpc/subscription.go | 2 +- rpc/types.go | 2 +- trie/errors.go | 2 +- trie/proof.go | 2 +- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/accounts/abi/type_test.go b/accounts/abi/type_test.go index ae69872ad8e0..95922548c400 100644 --- a/accounts/abi/type_test.go +++ b/accounts/abi/type_test.go @@ -25,7 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// typeWithoutStringer is a alias for the Type type which simply doesn't implement +// typeWithoutStringer is an alias for the Type type which simply doesn't implement // the stringer interface to allow printing type details in the tests below. type typeWithoutStringer Type diff --git a/core/blockchain_insert.go b/core/blockchain_insert.go index c7c4c4bfea8b..49e913aadab3 100644 --- a/core/blockchain_insert.go +++ b/core/blockchain_insert.go @@ -170,7 +170,7 @@ func (it *insertIterator) current() *types.Header { return it.chain[it.index].Header() } -// first returns the first block in the it. +// first returns the first block in it. func (it *insertIterator) first() *types.Block { return it.chain[0] } diff --git a/core/state/iterator.go b/core/state/iterator.go index dc84ce689be7..83c552ca1a66 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -46,7 +46,7 @@ type nodeIterator struct { Error error // Failure set in case of an internal error in the iterator } -// newNodeIterator creates an post-order state node iterator. +// newNodeIterator creates a post-order state node iterator. func newNodeIterator(state *StateDB) *nodeIterator { return &nodeIterator{ state: state, diff --git a/core/state/snapshot/context.go b/core/state/snapshot/context.go index 67d7e41a03ca..8a199605010b 100644 --- a/core/state/snapshot/context.go +++ b/core/state/snapshot/context.go @@ -46,7 +46,7 @@ type generatorStats struct { storage common.StorageSize // Total account and storage slot size(generation or recovery) } -// Log creates an contextual log with the given message and the context pulled +// Log creates a contextual log with the given message and the context pulled // from the internally maintained statistics. func (gs *generatorStats) Log(msg string, root common.Hash, marker []byte) { var ctx []interface{} diff --git a/core/state/snapshot/iterator_binary.go b/core/state/snapshot/iterator_binary.go index 22184b254563..edf471213f4a 100644 --- a/core/state/snapshot/iterator_binary.go +++ b/core/state/snapshot/iterator_binary.go @@ -68,7 +68,7 @@ func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator { parent, ok := dl.parent.(*diffLayer) if !ok { // If the storage in this layer is already destructed, discard all - // deeper layers but still return an valid single-branch iterator. + // deeper layers but still return a valid single-branch iterator. a, destructed := dl.StorageIterator(account, common.Hash{}) if destructed { l := &binaryIterator{ @@ -92,7 +92,7 @@ func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator { return l } // If the storage in this layer is already destructed, discard all - // deeper layers but still return an valid single-branch iterator. + // deeper layers but still return a valid single-branch iterator. a, destructed := dl.StorageIterator(account, common.Hash{}) if destructed { l := &binaryIterator{ diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index 9b018bac568d..fa0daea7bacb 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -25,7 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// weightedIterator is a iterator with an assigned weight. It is used to prioritise +// weightedIterator is an iterator with an assigned weight. It is used to prioritise // which account or storage slot is the correct one if multiple iterators find the // same one (modified in multiple consecutive blocks). type weightedIterator struct { diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 5c38cb7252f1..89a4c16c209d 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -835,7 +835,7 @@ func (t *Tree) disklayer() *diskLayer { } } -// diskRoot is a internal helper function to return the disk layer root. +// diskRoot is an internal helper function to return the disk layer root. // The lock of snapTree is assumed to be held already. func (t *Tree) diskRoot() common.Hash { disklayer := t.disklayer() diff --git a/core/state/state_object.go b/core/state/state_object.go index 1aa7946fd0aa..db3c32f2f26b 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -376,7 +376,7 @@ func (s *stateObject) updateTrie() (Trie, error) { // new storage trie root. func (s *stateObject) updateRoot() { // Flush cached storage mutations into trie, short circuit if any error - // is occurred or there is not change in the trie. + // is occurred or there is no change in the trie. tr, err := s.updateTrie() if err != nil || tr == nil { return diff --git a/eth/protocols/snap/gentrie.go b/eth/protocols/snap/gentrie.go index 8ef1a007530e..81c2640b62f3 100644 --- a/eth/protocols/snap/gentrie.go +++ b/eth/protocols/snap/gentrie.go @@ -132,7 +132,7 @@ func (t *pathTrie) onTrieNode(path []byte, hash common.Hash, blob []byte) { // // The extension node is detected if its path is the prefix of last committed // one and path gap is larger than one. If the path gap is only one byte, - // the current node could either be a full node, or a extension with single + // the current node could either be a full node, or an extension with single // byte key. In either case, no gaps will be left in the path. if t.last != nil && bytes.HasPrefix(t.last, path) && len(t.last)-len(path) > 1 { for i := len(path) + 1; i < len(t.last); i++ { diff --git a/rlp/rlpgen/gen.go b/rlp/rlpgen/gen.go index 0c6586482698..ff3987473770 100644 --- a/rlp/rlpgen/gen.go +++ b/rlp/rlpgen/gen.go @@ -158,7 +158,7 @@ type op interface { // basicOp handles basic types bool, uint*, string. type basicOp struct { typ types.Type - writeMethod string // calle write the value + writeMethod string // EncoderBuffer writer method name writeArgType types.Type // parameter type of writeMethod decMethod string decResultType types.Type // return type of decMethod diff --git a/rpc/subscription.go b/rpc/subscription.go index d3dff32a272e..d77c655bf900 100644 --- a/rpc/subscription.go +++ b/rpc/subscription.go @@ -97,7 +97,7 @@ func NotifierFromContext(ctx context.Context) (*Notifier, bool) { return n, ok } -// Notifier is tied to a RPC connection that supports subscriptions. +// Notifier is tied to an RPC connection that supports subscriptions. // Server callbacks use the notifier to send notifications. type Notifier struct { h *handler diff --git a/rpc/types.go b/rpc/types.go index d12408178615..2e53174b872c 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -38,7 +38,7 @@ type API struct { } // ServerCodec implements reading, parsing and writing RPC messages for the server side of -// a RPC session. Implementations must be go-routine safe since the codec can be called in +// an RPC session. Implementations must be go-routine safe since the codec can be called in // multiple go-routines concurrently. type ServerCodec interface { peerInfo() PeerInfo diff --git a/trie/errors.go b/trie/errors.go index 7be7041c7f09..ce5cb1342304 100644 --- a/trie/errors.go +++ b/trie/errors.go @@ -23,7 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// ErrCommitted is returned when a already committed trie is requested for usage. +// ErrCommitted is returned when an already committed trie is requested for usage. // The potential usages can be `Get`, `Update`, `Delete`, `NodeIterator`, `Prove` // and so on. var ErrCommitted = errors.New("trie is already committed") diff --git a/trie/proof.go b/trie/proof.go index fd892fb4becb..a39d6b4ea3f0 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -372,7 +372,7 @@ func unset(parent node, child node, key []byte, pos int, removeLeft bool) error return unset(cld, cld.Children[key[pos]], key, pos+1, removeLeft) case *shortNode: if len(key[pos:]) < len(cld.Key) || !bytes.Equal(cld.Key, key[pos:pos+len(cld.Key)]) { - // Find the fork point, it's an non-existent branch. + // Find the fork point, it's a non-existent branch. if removeLeft { if bytes.Compare(cld.Key, key[pos:]) < 0 { // The key of fork shortnode is less than the path From 256d4b099cf540ba99181d6e746d4a1eaebef054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Tue, 23 Apr 2024 13:31:32 +0200 Subject: [PATCH 203/571] beacon/light: request finality update explicitly when necessary (#29567) This PR adds an extra mechanism to sync.HeadSync that tries to retrieve the latest finality update from every server each time it sends an optimistic update in a new epoch (unless we already have a validated finality update attested in the same epoch). Note that this is not necessary and does not happen if the new finality update is delivered before the optimistic update. The spec only mandates light_client_finality_update events when a new epoch is finalized. If the chain does not finalize for a while then we might need an explicit request that returns a finality proof that proves the same finality epoch from the latest attested epoch. --- beacon/blsync/block_sync.go | 18 ++--- beacon/blsync/block_sync_test.go | 8 +- beacon/blsync/engineclient.go | 3 + beacon/light/api/api_server.go | 16 ++-- beacon/light/api/light_api.go | 77 ++++++++++++------ beacon/light/head_tracker.go | 51 +++++++----- beacon/light/sync/head_sync.go | 110 ++++++++++++++++---------- beacon/light/sync/head_sync_test.go | 78 ++++++++++++------ beacon/light/sync/test_helpers.go | 27 ++++--- beacon/light/sync/types.go | 7 +- beacon/light/sync/update_sync.go | 10 ++- beacon/light/sync/update_sync_test.go | 12 +-- beacon/types/exec_payload.go | 5 +- beacon/types/light_sync.go | 53 ++++++++++++- 14 files changed, 316 insertions(+), 159 deletions(-) diff --git a/beacon/blsync/block_sync.go b/beacon/blsync/block_sync.go index 3ab156354dca..ff689a922f68 100755 --- a/beacon/blsync/block_sync.go +++ b/beacon/blsync/block_sync.go @@ -41,7 +41,7 @@ type beaconBlockSync struct { type headTracker interface { PrefetchHead() types.HeadInfo - ValidatedHead() (types.SignedHeader, bool) + ValidatedOptimistic() (types.OptimisticUpdate, bool) ValidatedFinality() (types.FinalityUpdate, bool) } @@ -66,6 +66,7 @@ func (s *beaconBlockSync) Process(requester request.Requester, events []request. case request.EvResponse, request.EvFail, request.EvTimeout: sid, req, resp := event.RequestInfo() blockRoot := common.Hash(req.(sync.ReqBeaconBlock)) + log.Debug("Beacon block event", "type", event.Type.Name, "hash", blockRoot) if resp != nil { s.recentBlocks.Add(blockRoot, resp.(*types.BeaconBlock)) } @@ -80,8 +81,8 @@ func (s *beaconBlockSync) Process(requester request.Requester, events []request. } s.updateEventFeed() // request validated head block if unavailable and not yet requested - if vh, ok := s.headTracker.ValidatedHead(); ok { - s.tryRequestBlock(requester, vh.Header.Hash(), false) + if vh, ok := s.headTracker.ValidatedOptimistic(); ok { + s.tryRequestBlock(requester, vh.Attested.Hash(), false) } // request prefetch head if the given server has announced it if prefetchHead := s.headTracker.PrefetchHead().BlockRoot; prefetchHead != (common.Hash{}) { @@ -114,12 +115,12 @@ func blockHeadInfo(block *types.BeaconBlock) types.HeadInfo { } func (s *beaconBlockSync) updateEventFeed() { - head, ok := s.headTracker.ValidatedHead() + optimistic, ok := s.headTracker.ValidatedOptimistic() if !ok { return } - validatedHead := head.Header.Hash() + validatedHead := optimistic.Attested.Hash() headBlock, ok := s.recentBlocks.Get(validatedHead) if !ok { return @@ -127,7 +128,7 @@ func (s *beaconBlockSync) updateEventFeed() { var finalizedHash common.Hash if finality, ok := s.headTracker.ValidatedFinality(); ok { - he := head.Header.Epoch() + he := optimistic.Attested.Epoch() fe := finality.Attested.Header.Epoch() switch { case he == fe: @@ -135,10 +136,9 @@ func (s *beaconBlockSync) updateEventFeed() { case he < fe: return case he == fe+1: - parent, ok := s.recentBlocks.Get(head.Header.ParentRoot) + parent, ok := s.recentBlocks.Get(optimistic.Attested.ParentRoot) if !ok || parent.Slot()/params.EpochLength == fe { return // head is at first slot of next epoch, wait for finality update - //TODO: try to fetch finality update directly if subscription does not deliver } } } @@ -156,7 +156,7 @@ func (s *beaconBlockSync) updateEventFeed() { return } s.chainHeadFeed.Send(types.ChainHeadEvent{ - BeaconHead: head.Header, + BeaconHead: optimistic.Attested.Header, Block: execBlock, Finalized: finalizedHash, }) diff --git a/beacon/blsync/block_sync_test.go b/beacon/blsync/block_sync_test.go index 0525e95a8932..3d3b9e5e8d5b 100644 --- a/beacon/blsync/block_sync_test.go +++ b/beacon/blsync/block_sync_test.go @@ -140,8 +140,12 @@ func (h *testHeadTracker) PrefetchHead() types.HeadInfo { return h.prefetch } -func (h *testHeadTracker) ValidatedHead() (types.SignedHeader, bool) { - return h.validated, h.validated.Header != (types.Header{}) +func (h *testHeadTracker) ValidatedOptimistic() (types.OptimisticUpdate, bool) { + return types.OptimisticUpdate{ + Attested: types.HeaderWithExecProof{Header: h.validated.Header}, + Signature: h.validated.Signature, + SignatureSlot: h.validated.SignatureSlot, + }, h.validated.Header != (types.Header{}) } // TODO add test case for finality diff --git a/beacon/blsync/engineclient.go b/beacon/blsync/engineclient.go index 5a2d292a7d22..97ef6f5cb88e 100644 --- a/beacon/blsync/engineclient.go +++ b/beacon/blsync/engineclient.go @@ -62,6 +62,7 @@ func (ec *engineClient) updateLoop(headCh <-chan types.ChainHeadEvent) { for { select { case <-ec.rootCtx.Done(): + log.Debug("Stopping engine API update loop") return case event := <-headCh: @@ -73,12 +74,14 @@ func (ec *engineClient) updateLoop(headCh <-chan types.ChainHeadEvent) { fork := ec.config.ForkAtEpoch(event.BeaconHead.Epoch()) forkName := strings.ToLower(fork.Name) + log.Debug("Calling NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash()) if status, err := ec.callNewPayload(forkName, event); err == nil { log.Info("Successful NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "status", status) } else { log.Error("Failed NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "error", err) } + log.Debug("Calling ForkchoiceUpdated", "head", event.Block.Hash()) if status, err := ec.callForkchoiceUpdated(forkName, event); err == nil { log.Info("Successful ForkchoiceUpdated", "head", event.Block.Hash(), "status", status) } else { diff --git a/beacon/light/api/api_server.go b/beacon/light/api/api_server.go index 4b885cb8e101..2579854d82c5 100755 --- a/beacon/light/api/api_server.go +++ b/beacon/light/api/api_server.go @@ -46,13 +46,13 @@ func (s *ApiServer) Subscribe(eventCallback func(event request.Event)) { log.Debug("New head received", "slot", slot, "blockRoot", blockRoot) eventCallback(request.Event{Type: sync.EvNewHead, Data: types.HeadInfo{Slot: slot, BlockRoot: blockRoot}}) }, - OnSignedHead: func(head types.SignedHeader) { - log.Debug("New signed head received", "slot", head.Header.Slot, "blockRoot", head.Header.Hash(), "signerCount", head.Signature.SignerCount()) - eventCallback(request.Event{Type: sync.EvNewSignedHead, Data: head}) + OnOptimistic: func(update types.OptimisticUpdate) { + log.Debug("New optimistic update received", "slot", update.Attested.Slot, "blockRoot", update.Attested.Hash(), "signerCount", update.Signature.SignerCount()) + eventCallback(request.Event{Type: sync.EvNewOptimisticUpdate, Data: update}) }, - OnFinality: func(head types.FinalityUpdate) { - log.Debug("New finality update received", "slot", head.Attested.Slot, "blockRoot", head.Attested.Hash(), "signerCount", head.Signature.SignerCount()) - eventCallback(request.Event{Type: sync.EvNewFinalityUpdate, Data: head}) + OnFinality: func(update types.FinalityUpdate) { + log.Debug("New finality update received", "slot", update.Attested.Slot, "blockRoot", update.Attested.Hash(), "signerCount", update.Signature.SignerCount()) + eventCallback(request.Event{Type: sync.EvNewFinalityUpdate, Data: update}) }, OnError: func(err error) { log.Warn("Head event stream error", "err", err) @@ -83,6 +83,9 @@ func (s *ApiServer) SendRequest(id request.ID, req request.Request) { case sync.ReqBeaconBlock: log.Debug("Beacon API: requesting block", "reqid", id, "hash", common.Hash(data)) resp, err = s.api.GetBeaconBlock(common.Hash(data)) + case sync.ReqFinality: + log.Debug("Beacon API: requesting finality update") + resp, err = s.api.GetFinalityUpdate() default: } @@ -90,6 +93,7 @@ func (s *ApiServer) SendRequest(id request.ID, req request.Request) { log.Warn("Beacon API request failed", "type", reflect.TypeOf(req), "reqid", id, "err", err) s.eventCallback(request.Event{Type: request.EvFail, Data: request.RequestResponse{ID: id, Request: req}}) } else { + log.Debug("Beacon API request answered", "type", reflect.TypeOf(req), "reqid", id) s.eventCallback(request.Event{Type: request.EvResponse, Data: request.RequestResponse{ID: id, Request: req, Response: resp}}) } }() diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 6892407cafd7..903db5734455 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/log" ) var ( @@ -184,46 +185,56 @@ func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64 return updates, committees, nil } -// GetOptimisticHeadUpdate fetches a signed header based on the latest available -// optimistic update. Note that the signature should be verified by the caller -// as its validity depends on the update chain. +// GetOptimisticUpdate fetches the latest available optimistic update. +// Note that the signature should be verified by the caller as its validity +// depends on the update chain. // // See data structure definition here: // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate -func (api *BeaconLightApi) GetOptimisticHeadUpdate() (types.SignedHeader, error) { +func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error) { resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update") if err != nil { - return types.SignedHeader{}, err + return types.OptimisticUpdate{}, err } - return decodeOptimisticHeadUpdate(resp) + return decodeOptimisticUpdate(resp) } -func decodeOptimisticHeadUpdate(enc []byte) (types.SignedHeader, error) { +func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) { var data struct { - Data struct { - Header jsonBeaconHeader `json:"attested_header"` - Aggregate types.SyncAggregate `json:"sync_aggregate"` - SignatureSlot common.Decimal `json:"signature_slot"` + Version string + Data struct { + Attested jsonHeaderWithExecProof `json:"attested_header"` + Aggregate types.SyncAggregate `json:"sync_aggregate"` + SignatureSlot common.Decimal `json:"signature_slot"` } `json:"data"` } if err := json.Unmarshal(enc, &data); err != nil { - return types.SignedHeader{}, err + return types.OptimisticUpdate{}, err + } + // Decode the execution payload headers. + attestedExecHeader, err := types.ExecutionHeaderFromJSON(data.Version, data.Data.Attested.Execution) + if err != nil { + return types.OptimisticUpdate{}, fmt.Errorf("invalid attested header: %v", err) } - if data.Data.Header.Beacon.StateRoot == (common.Hash{}) { + if data.Data.Attested.Beacon.StateRoot == (common.Hash{}) { // workaround for different event encoding format in Lodestar if err := json.Unmarshal(enc, &data.Data); err != nil { - return types.SignedHeader{}, err + return types.OptimisticUpdate{}, err } } if len(data.Data.Aggregate.Signers) != params.SyncCommitteeBitmaskSize { - return types.SignedHeader{}, errors.New("invalid sync_committee_bits length") + return types.OptimisticUpdate{}, errors.New("invalid sync_committee_bits length") } if len(data.Data.Aggregate.Signature) != params.BLSSignatureSize { - return types.SignedHeader{}, errors.New("invalid sync_committee_signature length") + return types.OptimisticUpdate{}, errors.New("invalid sync_committee_signature length") } - return types.SignedHeader{ - Header: data.Data.Header.Beacon, + return types.OptimisticUpdate{ + Attested: types.HeaderWithExecProof{ + Header: data.Data.Attested.Beacon, + PayloadHeader: attestedExecHeader, + PayloadBranch: data.Data.Attested.ExecutionBranch, + }, Signature: data.Data.Aggregate, SignatureSlot: uint64(data.Data.SignatureSlot), }, nil @@ -411,7 +422,7 @@ func decodeHeadEvent(enc []byte) (uint64, common.Hash, error) { type HeadEventListener struct { OnNewHead func(slot uint64, blockRoot common.Hash) - OnSignedHead func(head types.SignedHeader) + OnOptimistic func(head types.OptimisticUpdate) OnFinality func(head types.FinalityUpdate) OnError func(err error) } @@ -449,21 +460,35 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() defer wg.Done() // Request initial data. + log.Trace("Requesting initial head header") if head, _, _, err := api.GetHeader(common.Hash{}); err == nil { + log.Trace("Retrieved initial head header", "slot", head.Slot, "hash", head.Hash()) listener.OnNewHead(head.Slot, head.Hash()) + } else { + log.Debug("Failed to retrieve initial head header", "error", err) } - if signedHead, err := api.GetOptimisticHeadUpdate(); err == nil { - listener.OnSignedHead(signedHead) + log.Trace("Requesting initial optimistic update") + if optimisticUpdate, err := api.GetOptimisticUpdate(); err == nil { + log.Trace("Retrieved initial optimistic update", "slot", optimisticUpdate.Attested.Slot, "hash", optimisticUpdate.Attested.Hash()) + listener.OnOptimistic(optimisticUpdate) + } else { + log.Debug("Failed to retrieve initial optimistic update", "error", err) } + log.Trace("Requesting initial finality update") if finalityUpdate, err := api.GetFinalityUpdate(); err == nil { + log.Trace("Retrieved initial finality update", "slot", finalityUpdate.Finalized.Slot, "hash", finalityUpdate.Finalized.Hash()) listener.OnFinality(finalityUpdate) + } else { + log.Debug("Failed to retrieve initial finality update", "error", err) } + log.Trace("Starting event stream processing loop") // Receive the stream. var stream *eventsource.Stream select { case stream = <-streamCh: case <-ctx.Done(): + log.Trace("Stopping event stream processing loop") return } @@ -474,8 +499,10 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() case event, ok := <-stream.Events: if !ok { + log.Trace("Event stream closed") return } + log.Trace("New event received from event stream", "type", event.Event()) switch event.Event() { case "head": slot, blockRoot, err := decodeHeadEvent([]byte(event.Data())) @@ -485,9 +512,9 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() listener.OnError(fmt.Errorf("error decoding head event: %v", err)) } case "light_client_optimistic_update": - signedHead, err := decodeOptimisticHeadUpdate([]byte(event.Data())) + optimisticUpdate, err := decodeOptimisticUpdate([]byte(event.Data())) if err == nil { - listener.OnSignedHead(signedHead) + listener.OnOptimistic(optimisticUpdate) } else { listener.OnError(fmt.Errorf("error decoding optimistic update event: %v", err)) } @@ -521,7 +548,8 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() // established. It can only return nil when the context is canceled. func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream { for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) { - path := "/eth/v1/events?topics=head&topics=light_client_optimistic_update&topics=light_client_finality_update" + path := "/eth/v1/events?topics=head&topics=light_client_finality_update&topics=light_client_optimistic_update" + log.Trace("Sending event subscription request") req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil) if err != nil { listener.OnError(fmt.Errorf("error creating event subscription request: %v", err)) @@ -535,6 +563,7 @@ func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadE listener.OnError(fmt.Errorf("error creating event subscription: %v", err)) continue } + log.Trace("Successfully created event stream") return stream } return nil diff --git a/beacon/light/head_tracker.go b/beacon/light/head_tracker.go index 6036322f014b..7ef93feccedf 100644 --- a/beacon/light/head_tracker.go +++ b/beacon/light/head_tracker.go @@ -29,15 +29,15 @@ import ( // which is the (not necessarily validated) head announced by the majority of // servers. type HeadTracker struct { - lock sync.RWMutex - committeeChain *CommitteeChain - minSignerCount int - signedHead types.SignedHeader - hasSignedHead bool - finalityUpdate types.FinalityUpdate - hasFinalityUpdate bool - prefetchHead types.HeadInfo - changeCounter uint64 + lock sync.RWMutex + committeeChain *CommitteeChain + minSignerCount int + optimisticUpdate types.OptimisticUpdate + hasOptimisticUpdate bool + finalityUpdate types.FinalityUpdate + hasFinalityUpdate bool + prefetchHead types.HeadInfo + changeCounter uint64 } // NewHeadTracker creates a new HeadTracker. @@ -48,15 +48,15 @@ func NewHeadTracker(committeeChain *CommitteeChain, minSignerCount int) *HeadTra } } -// ValidatedHead returns the latest validated head. -func (h *HeadTracker) ValidatedHead() (types.SignedHeader, bool) { +// ValidatedOptimistic returns the latest validated optimistic update. +func (h *HeadTracker) ValidatedOptimistic() (types.OptimisticUpdate, bool) { h.lock.RLock() defer h.lock.RUnlock() - return h.signedHead, h.hasSignedHead + return h.optimisticUpdate, h.hasOptimisticUpdate } -// ValidatedFinality returns the latest validated finality. +// ValidatedFinality returns the latest validated finality update. func (h *HeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { h.lock.RLock() defer h.lock.RUnlock() @@ -64,26 +64,36 @@ func (h *HeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { return h.finalityUpdate, h.hasFinalityUpdate } -// ValidateHead validates the given signed head. If the head is successfully validated -// and it is better than the old validated head (higher slot or same slot and more -// signers) then ValidatedHead is updated. The boolean return flag signals if -// ValidatedHead has been changed. -func (h *HeadTracker) ValidateHead(head types.SignedHeader) (bool, error) { +// ValidateOptimistic validates the given optimistic update. If the update is +// successfully validated and it is better than the old validated update (higher +// slot or same slot and more signers) then ValidatedOptimistic is updated. +// The boolean return flag signals if ValidatedOptimistic has been changed. +func (h *HeadTracker) ValidateOptimistic(update types.OptimisticUpdate) (bool, error) { h.lock.Lock() defer h.lock.Unlock() - replace, err := h.validate(head, h.signedHead) + if err := update.Validate(); err != nil { + return false, err + } + replace, err := h.validate(update.SignedHeader(), h.optimisticUpdate.SignedHeader()) if replace { - h.signedHead, h.hasSignedHead = head, true + h.optimisticUpdate, h.hasOptimisticUpdate = update, true h.changeCounter++ } return replace, err } +// ValidateFinality validates the given finality update. If the update is +// successfully validated and it is better than the old validated update (higher +// slot or same slot and more signers) then ValidatedFinality is updated. +// The boolean return flag signals if ValidatedFinality has been changed. func (h *HeadTracker) ValidateFinality(update types.FinalityUpdate) (bool, error) { h.lock.Lock() defer h.lock.Unlock() + if err := update.Validate(); err != nil { + return false, err + } replace, err := h.validate(update.SignedHeader(), h.finalityUpdate.SignedHeader()) if replace { h.finalityUpdate, h.hasFinalityUpdate = update, true @@ -142,6 +152,7 @@ func (h *HeadTracker) SetPrefetchHead(head types.HeadInfo) { h.changeCounter++ } +// ChangeCounter implements request.targetData func (h *HeadTracker) ChangeCounter() uint64 { h.lock.RLock() defer h.lock.RUnlock() diff --git a/beacon/light/sync/head_sync.go b/beacon/light/sync/head_sync.go index 5ccc2e18a2d6..dd05d3958879 100644 --- a/beacon/light/sync/head_sync.go +++ b/beacon/light/sync/head_sync.go @@ -19,11 +19,13 @@ package sync import ( "github.com/ethereum/go-ethereum/beacon/light/request" "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/log" ) type headTracker interface { - ValidateHead(head types.SignedHeader) (bool, error) + ValidateOptimistic(update types.OptimisticUpdate) (bool, error) ValidateFinality(head types.FinalityUpdate) (bool, error) + ValidatedFinality() (types.FinalityUpdate, bool) SetPrefetchHead(head types.HeadInfo) } @@ -33,16 +35,17 @@ type headTracker interface { // It can also postpone the validation of the latest announced signed head // until the committee chain is synced up to at least the required period. type HeadSync struct { - headTracker headTracker - chain committeeChain - nextSyncPeriod uint64 - chainInit bool - unvalidatedHeads map[request.Server]types.SignedHeader - unvalidatedFinality map[request.Server]types.FinalityUpdate - serverHeads map[request.Server]types.HeadInfo - headServerCount map[types.HeadInfo]headServerCount - headCounter uint64 - prefetchHead types.HeadInfo + headTracker headTracker + chain committeeChain + nextSyncPeriod uint64 + chainInit bool + unvalidatedOptimistic map[request.Server]types.OptimisticUpdate + unvalidatedFinality map[request.Server]types.FinalityUpdate + serverHeads map[request.Server]types.HeadInfo + reqFinalityEpoch map[request.Server]uint64 // next epoch to request finality update + headServerCount map[types.HeadInfo]headServerCount + headCounter uint64 + prefetchHead types.HeadInfo } // headServerCount is associated with most recently seen head infos; it counts @@ -57,75 +60,98 @@ type headServerCount struct { // NewHeadSync creates a new HeadSync. func NewHeadSync(headTracker headTracker, chain committeeChain) *HeadSync { s := &HeadSync{ - headTracker: headTracker, - chain: chain, - unvalidatedHeads: make(map[request.Server]types.SignedHeader), - unvalidatedFinality: make(map[request.Server]types.FinalityUpdate), - serverHeads: make(map[request.Server]types.HeadInfo), - headServerCount: make(map[types.HeadInfo]headServerCount), + headTracker: headTracker, + chain: chain, + unvalidatedOptimistic: make(map[request.Server]types.OptimisticUpdate), + unvalidatedFinality: make(map[request.Server]types.FinalityUpdate), + serverHeads: make(map[request.Server]types.HeadInfo), + headServerCount: make(map[types.HeadInfo]headServerCount), + reqFinalityEpoch: make(map[request.Server]uint64), } return s } // Process implements request.Module. func (s *HeadSync) Process(requester request.Requester, events []request.Event) { + nextPeriod, chainInit := s.chain.NextSyncPeriod() + if nextPeriod != s.nextSyncPeriod || chainInit != s.chainInit { + s.nextSyncPeriod, s.chainInit = nextPeriod, chainInit + s.processUnvalidatedUpdates() + } + for _, event := range events { switch event.Type { case EvNewHead: s.setServerHead(event.Server, event.Data.(types.HeadInfo)) - case EvNewSignedHead: - s.newSignedHead(event.Server, event.Data.(types.SignedHeader)) + case EvNewOptimisticUpdate: + update := event.Data.(types.OptimisticUpdate) + s.newOptimisticUpdate(event.Server, update) + epoch := update.Attested.Epoch() + if epoch < s.reqFinalityEpoch[event.Server] { + continue + } + if finality, ok := s.headTracker.ValidatedFinality(); ok && finality.Attested.Header.Epoch() >= epoch { + continue + } + requester.Send(event.Server, ReqFinality{}) + s.reqFinalityEpoch[event.Server] = epoch + 1 case EvNewFinalityUpdate: s.newFinalityUpdate(event.Server, event.Data.(types.FinalityUpdate)) + case request.EvResponse: + _, _, resp := event.RequestInfo() + s.newFinalityUpdate(event.Server, resp.(types.FinalityUpdate)) case request.EvUnregistered: s.setServerHead(event.Server, types.HeadInfo{}) delete(s.serverHeads, event.Server) - delete(s.unvalidatedHeads, event.Server) + delete(s.unvalidatedOptimistic, event.Server) + delete(s.unvalidatedFinality, event.Server) } } - - nextPeriod, chainInit := s.chain.NextSyncPeriod() - if nextPeriod != s.nextSyncPeriod || chainInit != s.chainInit { - s.nextSyncPeriod, s.chainInit = nextPeriod, chainInit - s.processUnvalidated() - } } -// newSignedHead handles received signed head; either validates it if the chain -// is properly synced or stores it for further validation. -func (s *HeadSync) newSignedHead(server request.Server, signedHead types.SignedHeader) { - if !s.chainInit || types.SyncPeriod(signedHead.SignatureSlot) > s.nextSyncPeriod { - s.unvalidatedHeads[server] = signedHead +// newOptimisticUpdate handles received optimistic update; either validates it if +// the chain is properly synced or stores it for further validation. +func (s *HeadSync) newOptimisticUpdate(server request.Server, optimisticUpdate types.OptimisticUpdate) { + if !s.chainInit || types.SyncPeriod(optimisticUpdate.SignatureSlot) > s.nextSyncPeriod { + s.unvalidatedOptimistic[server] = optimisticUpdate return } - s.headTracker.ValidateHead(signedHead) + if _, err := s.headTracker.ValidateOptimistic(optimisticUpdate); err != nil { + log.Debug("Error validating optimistic update", "error", err) + } } -// newFinalityUpdate handles received finality update; either validates it if the chain -// is properly synced or stores it for further validation. +// newFinalityUpdate handles received finality update; either validates it if +// the chain is properly synced or stores it for further validation. func (s *HeadSync) newFinalityUpdate(server request.Server, finalityUpdate types.FinalityUpdate) { if !s.chainInit || types.SyncPeriod(finalityUpdate.SignatureSlot) > s.nextSyncPeriod { s.unvalidatedFinality[server] = finalityUpdate return } - s.headTracker.ValidateFinality(finalityUpdate) + if _, err := s.headTracker.ValidateFinality(finalityUpdate); err != nil { + log.Debug("Error validating finality update", "error", err) + } } -// processUnvalidated iterates the list of unvalidated heads and validates +// processUnvalidatedUpdates iterates the list of unvalidated updates and validates // those which can be validated. -func (s *HeadSync) processUnvalidated() { +func (s *HeadSync) processUnvalidatedUpdates() { if !s.chainInit { return } - for server, signedHead := range s.unvalidatedHeads { - if types.SyncPeriod(signedHead.SignatureSlot) <= s.nextSyncPeriod { - s.headTracker.ValidateHead(signedHead) - delete(s.unvalidatedHeads, server) + for server, optimisticUpdate := range s.unvalidatedOptimistic { + if types.SyncPeriod(optimisticUpdate.SignatureSlot) <= s.nextSyncPeriod { + if _, err := s.headTracker.ValidateOptimistic(optimisticUpdate); err != nil { + log.Debug("Error validating deferred optimistic update", "error", err) + } + delete(s.unvalidatedOptimistic, server) } } for server, finalityUpdate := range s.unvalidatedFinality { if types.SyncPeriod(finalityUpdate.SignatureSlot) <= s.nextSyncPeriod { - s.headTracker.ValidateFinality(finalityUpdate) + if _, err := s.headTracker.ValidateFinality(finalityUpdate); err != nil { + log.Debug("Error validating deferred finality update", "error", err) + } delete(s.unvalidatedFinality, server) } } diff --git a/beacon/light/sync/head_sync_test.go b/beacon/light/sync/head_sync_test.go index a2870b2732b2..cd7dacf7fe7d 100644 --- a/beacon/light/sync/head_sync_test.go +++ b/beacon/light/sync/head_sync_test.go @@ -19,6 +19,7 @@ package sync import ( "testing" + "github.com/ethereum/go-ethereum/beacon/light/request" "github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/common" ) @@ -28,6 +29,7 @@ var ( testServer2 = testServer("testServer2") testServer3 = testServer("testServer3") testServer4 = testServer("testServer4") + testServer5 = testServer("testServer5") testHead0 = types.HeadInfo{} testHead1 = types.HeadInfo{Slot: 123, BlockRoot: common.Hash{1}} @@ -35,13 +37,21 @@ var ( testHead3 = types.HeadInfo{Slot: 124, BlockRoot: common.Hash{3}} testHead4 = types.HeadInfo{Slot: 125, BlockRoot: common.Hash{4}} - testSHead1 = types.SignedHeader{SignatureSlot: 0x0124, Header: types.Header{Slot: 0x0123, StateRoot: common.Hash{1}}} - testSHead2 = types.SignedHeader{SignatureSlot: 0x2010, Header: types.Header{Slot: 0x200e, StateRoot: common.Hash{2}}} - // testSHead3 is at the end of period 1 but signed in period 2 - testSHead3 = types.SignedHeader{SignatureSlot: 0x4000, Header: types.Header{Slot: 0x3fff, StateRoot: common.Hash{3}}} - testSHead4 = types.SignedHeader{SignatureSlot: 0x6444, Header: types.Header{Slot: 0x6443, StateRoot: common.Hash{4}}} + testOptUpdate1 = types.OptimisticUpdate{SignatureSlot: 0x0124, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x0123, StateRoot: common.Hash{1}}}} + testOptUpdate2 = types.OptimisticUpdate{SignatureSlot: 0x2010, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x200e, StateRoot: common.Hash{2}}}} + // testOptUpdate3 is at the end of period 1 but signed in period 2 + testOptUpdate3 = types.OptimisticUpdate{SignatureSlot: 0x4000, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x3fff, StateRoot: common.Hash{3}}}} + testOptUpdate4 = types.OptimisticUpdate{SignatureSlot: 0x6444, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x6443, StateRoot: common.Hash{4}}}} ) +func finality(opt types.OptimisticUpdate) types.FinalityUpdate { + return types.FinalityUpdate{ + SignatureSlot: opt.SignatureSlot, + Attested: opt.Attested, + Finalized: types.HeaderWithExecProof{Header: types.Header{Slot: (opt.Attested.Header.Slot - 64) & uint64(0xffffffffffffffe0)}}, + } +} + type testServer string func (t testServer) Name() string { @@ -57,50 +67,66 @@ func TestValidatedHead(t *testing.T) { ht.ExpValidated(t, 0, nil) ts.AddServer(testServer1, 1) - ts.ServerEvent(EvNewSignedHead, testServer1, testSHead1) - ts.Run(1) + ts.ServerEvent(EvNewOptimisticUpdate, testServer1, testOptUpdate1) + ts.Run(1, testServer1, ReqFinality{}) // announced head should be queued because of uninitialized chain ht.ExpValidated(t, 1, nil) chain.SetNextSyncPeriod(0) // initialize chain ts.Run(2) // expect previously queued head to be validated - ht.ExpValidated(t, 2, []types.SignedHeader{testSHead1}) + ht.ExpValidated(t, 2, []types.OptimisticUpdate{testOptUpdate1}) chain.SetNextSyncPeriod(1) - ts.ServerEvent(EvNewSignedHead, testServer1, testSHead2) + ts.ServerEvent(EvNewFinalityUpdate, testServer1, finality(testOptUpdate2)) + ts.ServerEvent(EvNewOptimisticUpdate, testServer1, testOptUpdate2) ts.AddServer(testServer2, 1) - ts.ServerEvent(EvNewSignedHead, testServer2, testSHead2) + ts.ServerEvent(EvNewOptimisticUpdate, testServer2, testOptUpdate2) ts.Run(3) // expect both head announcements to be validated instantly - ht.ExpValidated(t, 3, []types.SignedHeader{testSHead2, testSHead2}) + ht.ExpValidated(t, 3, []types.OptimisticUpdate{testOptUpdate2, testOptUpdate2}) - ts.ServerEvent(EvNewSignedHead, testServer1, testSHead3) + ts.ServerEvent(EvNewOptimisticUpdate, testServer1, testOptUpdate3) ts.AddServer(testServer3, 1) - ts.ServerEvent(EvNewSignedHead, testServer3, testSHead4) - ts.Run(4) - // future period announced heads should be queued + ts.ServerEvent(EvNewOptimisticUpdate, testServer3, testOptUpdate4) + // finality should be requested from both servers + ts.Run(4, testServer1, ReqFinality{}, testServer3, ReqFinality{}) + // future period annonced heads should be queued ht.ExpValidated(t, 4, nil) chain.SetNextSyncPeriod(2) ts.Run(5) - // testSHead3 can be validated now but not testSHead4 - ht.ExpValidated(t, 5, []types.SignedHeader{testSHead3}) + // testOptUpdate3 can be validated now but not testOptUpdate4 + ht.ExpValidated(t, 5, []types.OptimisticUpdate{testOptUpdate3}) + + ts.AddServer(testServer4, 1) + ts.ServerEvent(EvNewOptimisticUpdate, testServer4, testOptUpdate3) + // new server joined with recent optimistic update but still no finality; should be requested + ts.Run(6, testServer4, ReqFinality{}) + ht.ExpValidated(t, 6, []types.OptimisticUpdate{testOptUpdate3}) + + ts.AddServer(testServer5, 1) + ts.RequestEvent(request.EvResponse, ts.Request(6, 1), finality(testOptUpdate3)) + ts.ServerEvent(EvNewOptimisticUpdate, testServer5, testOptUpdate3) + // finality update request answered; new server should not be requested + ts.Run(7) + ht.ExpValidated(t, 7, []types.OptimisticUpdate{testOptUpdate3}) // server 3 disconnected without proving period 3, its announced head should be dropped ts.RemoveServer(testServer3) - ts.Run(6) - ht.ExpValidated(t, 6, nil) + ts.Run(8) + ht.ExpValidated(t, 8, nil) chain.SetNextSyncPeriod(3) - ts.Run(7) - // testSHead4 could be validated now but it's not queued by any registered server - ht.ExpValidated(t, 7, nil) + ts.Run(9) + // testOptUpdate4 could be validated now but it's not queued by any registered server + ht.ExpValidated(t, 9, nil) - ts.ServerEvent(EvNewSignedHead, testServer2, testSHead4) - ts.Run(8) - // now testSHead4 should be validated - ht.ExpValidated(t, 8, []types.SignedHeader{testSHead4}) + ts.ServerEvent(EvNewFinalityUpdate, testServer2, finality(testOptUpdate4)) + ts.ServerEvent(EvNewOptimisticUpdate, testServer2, testOptUpdate4) + ts.Run(10) + // now testOptUpdate4 should be validated + ht.ExpValidated(t, 10, []types.OptimisticUpdate{testOptUpdate4}) } func TestPrefetchHead(t *testing.T) { diff --git a/beacon/light/sync/test_helpers.go b/beacon/light/sync/test_helpers.go index 9f57ceebe4d8..cfca8ad8a45f 100644 --- a/beacon/light/sync/test_helpers.go +++ b/beacon/light/sync/test_helpers.go @@ -212,32 +212,37 @@ func (tc *TestCommitteeChain) ExpNextSyncPeriod(t *testing.T, expNsp uint64) { type TestHeadTracker struct { phead types.HeadInfo - validated []types.SignedHeader + validated []types.OptimisticUpdate + finality types.FinalityUpdate } -func (ht *TestHeadTracker) ValidateHead(head types.SignedHeader) (bool, error) { - ht.validated = append(ht.validated, head) +func (ht *TestHeadTracker) ValidateOptimistic(update types.OptimisticUpdate) (bool, error) { + ht.validated = append(ht.validated, update) return true, nil } -// TODO add test case for finality -func (ht *TestHeadTracker) ValidateFinality(head types.FinalityUpdate) (bool, error) { +func (ht *TestHeadTracker) ValidateFinality(update types.FinalityUpdate) (bool, error) { + ht.finality = update return true, nil } -func (ht *TestHeadTracker) ExpValidated(t *testing.T, tci int, expHeads []types.SignedHeader) { +func (ht *TestHeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { + return ht.finality, ht.finality.Attested.Header != (types.Header{}) +} + +func (ht *TestHeadTracker) ExpValidated(t *testing.T, tci int, expHeads []types.OptimisticUpdate) { for i, expHead := range expHeads { if i >= len(ht.validated) { - t.Errorf("Missing validated head in test case #%d index #%d (expected {slot %d blockRoot %x}, got none)", tci, i, expHead.Header.Slot, expHead.Header.Hash()) + t.Errorf("Missing validated head in test case #%d index #%d (expected {slot %d blockRoot %x}, got none)", tci, i, expHead.Attested.Header.Slot, expHead.Attested.Header.Hash()) continue } - if ht.validated[i] != expHead { - vhead := ht.validated[i].Header - t.Errorf("Wrong validated head in test case #%d index #%d (expected {slot %d blockRoot %x}, got {slot %d blockRoot %x})", tci, i, expHead.Header.Slot, expHead.Header.Hash(), vhead.Slot, vhead.Hash()) + if !reflect.DeepEqual(ht.validated[i], expHead) { + vhead := ht.validated[i].Attested.Header + t.Errorf("Wrong validated head in test case #%d index #%d (expected {slot %d blockRoot %x}, got {slot %d blockRoot %x})", tci, i, expHead.Attested.Header.Slot, expHead.Attested.Header.Hash(), vhead.Slot, vhead.Hash()) } } for i := len(expHeads); i < len(ht.validated); i++ { - vhead := ht.validated[i].Header + vhead := ht.validated[i].Attested.Header t.Errorf("Unexpected validated head in test case #%d index #%d (expected none, got {slot %d blockRoot %x})", tci, i, vhead.Slot, vhead.Hash()) } ht.validated = nil diff --git a/beacon/light/sync/types.go b/beacon/light/sync/types.go index 8aa4c95f46ea..97a3fb21114a 100644 --- a/beacon/light/sync/types.go +++ b/beacon/light/sync/types.go @@ -23,9 +23,9 @@ import ( ) var ( - EvNewHead = &request.EventType{Name: "newHead"} // data: types.HeadInfo - EvNewSignedHead = &request.EventType{Name: "newSignedHead"} // data: types.SignedHeader - EvNewFinalityUpdate = &request.EventType{Name: "newFinalityUpdate"} // data: types.FinalityUpdate + EvNewHead = &request.EventType{Name: "newHead"} // data: types.HeadInfo + EvNewOptimisticUpdate = &request.EventType{Name: "newOptimisticUpdate"} // data: types.OptimisticUpdate + EvNewFinalityUpdate = &request.EventType{Name: "newFinalityUpdate"} // data: types.FinalityUpdate ) type ( @@ -43,4 +43,5 @@ type ( } ReqCheckpointData common.Hash ReqBeaconBlock common.Hash + ReqFinality struct{} ) diff --git a/beacon/light/sync/update_sync.go b/beacon/light/sync/update_sync.go index 71801b1b600f..9549ee599219 100644 --- a/beacon/light/sync/update_sync.go +++ b/beacon/light/sync/update_sync.go @@ -84,6 +84,7 @@ func (s *CheckpointInit) Process(requester request.Requester, events []request.E if s.initialized { return } + for _, event := range events { switch event.Type { case request.EvResponse, request.EvFail, request.EvTimeout: @@ -132,10 +133,12 @@ func (s *CheckpointInit) Process(requester request.Requester, events []request.E newState.state = ssPrintStatus s.serverState[sid.Server] = newState } + case request.EvUnregistered: delete(s.serverState, event.Server) } } + // start a request if possible for _, server := range requester.CanSendTo() { switch s.serverState[server].state { @@ -156,6 +159,7 @@ func (s *CheckpointInit) Process(requester request.Requester, events []request.E s.serverState[server] = newState } } + // print log message if necessary for server, state := range s.serverState { if state.state != ssPrintStatus { @@ -316,9 +320,9 @@ func (s *ForwardUpdateSync) Process(requester request.Requester, events []reques if !queued { s.unlockRange(sid, req) } - case EvNewSignedHead: - signedHead := event.Data.(types.SignedHeader) - s.nextSyncPeriod[event.Server] = types.SyncPeriod(signedHead.SignatureSlot + 256) + case EvNewOptimisticUpdate: + update := event.Data.(types.OptimisticUpdate) + s.nextSyncPeriod[event.Server] = types.SyncPeriod(update.SignatureSlot + 256) case request.EvUnregistered: delete(s.nextSyncPeriod, event.Server) } diff --git a/beacon/light/sync/update_sync_test.go b/beacon/light/sync/update_sync_test.go index 1c4b3d6d76fa..8329bf28c9d8 100644 --- a/beacon/light/sync/update_sync_test.go +++ b/beacon/light/sync/update_sync_test.go @@ -68,9 +68,9 @@ func TestUpdateSyncParallel(t *testing.T) { ts := NewTestScheduler(t, updateSync) // add 2 servers, head at period 100; allow 3-3 parallel requests for each ts.AddServer(testServer1, 3) - ts.ServerEvent(EvNewSignedHead, testServer1, types.SignedHeader{SignatureSlot: 0x2000*100 + 0x1000}) + ts.ServerEvent(EvNewOptimisticUpdate, testServer1, types.OptimisticUpdate{SignatureSlot: 0x2000*100 + 0x1000}) ts.AddServer(testServer2, 3) - ts.ServerEvent(EvNewSignedHead, testServer2, types.SignedHeader{SignatureSlot: 0x2000*100 + 0x1000}) + ts.ServerEvent(EvNewOptimisticUpdate, testServer2, types.OptimisticUpdate{SignatureSlot: 0x2000*100 + 0x1000}) // expect 6 requests to be sent ts.Run(1, @@ -150,11 +150,11 @@ func TestUpdateSyncDifferentHeads(t *testing.T) { ts := NewTestScheduler(t, updateSync) // add 3 servers with different announced head periods ts.AddServer(testServer1, 1) - ts.ServerEvent(EvNewSignedHead, testServer1, types.SignedHeader{SignatureSlot: 0x2000*15 + 0x1000}) + ts.ServerEvent(EvNewOptimisticUpdate, testServer1, types.OptimisticUpdate{SignatureSlot: 0x2000*15 + 0x1000}) ts.AddServer(testServer2, 1) - ts.ServerEvent(EvNewSignedHead, testServer2, types.SignedHeader{SignatureSlot: 0x2000*16 + 0x1000}) + ts.ServerEvent(EvNewOptimisticUpdate, testServer2, types.OptimisticUpdate{SignatureSlot: 0x2000*16 + 0x1000}) ts.AddServer(testServer3, 1) - ts.ServerEvent(EvNewSignedHead, testServer3, types.SignedHeader{SignatureSlot: 0x2000*17 + 0x1000}) + ts.ServerEvent(EvNewOptimisticUpdate, testServer3, types.OptimisticUpdate{SignatureSlot: 0x2000*17 + 0x1000}) // expect request to the best announced head ts.Run(1, testServer3, ReqUpdates{FirstPeriod: 10, Count: 7}) @@ -190,7 +190,7 @@ func TestUpdateSyncDifferentHeads(t *testing.T) { // a new server is registered with announced head period 17 ts.AddServer(testServer4, 1) - ts.ServerEvent(EvNewSignedHead, testServer4, types.SignedHeader{SignatureSlot: 0x2000*17 + 0x1000}) + ts.ServerEvent(EvNewOptimisticUpdate, testServer4, types.OptimisticUpdate{SignatureSlot: 0x2000*17 + 0x1000}) // expect request to sync one more period ts.Run(7, testServer4, ReqUpdates{FirstPeriod: 16, Count: 1}) diff --git a/beacon/types/exec_payload.go b/beacon/types/exec_payload.go index 604de288d269..718f98f5292e 100644 --- a/beacon/types/exec_payload.go +++ b/beacon/types/exec_payload.go @@ -66,9 +66,8 @@ func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*typ block := types.NewBlockWithHeader(&header) block = block.WithBody(transactions, nil) block = block.WithWithdrawals(withdrawals) - hash := block.Hash() - if hash != expectedHash { - return block, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash) + if hash := block.Hash(); hash != expectedHash { + return nil, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash) } return block, nil } diff --git a/beacon/types/light_sync.go b/beacon/types/light_sync.go index 62becdb21cfd..3e9b13d0e2d2 100644 --- a/beacon/types/light_sync.go +++ b/beacon/types/light_sync.go @@ -23,7 +23,7 @@ import ( "github.com/ethereum/go-ethereum/beacon/merkle" "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" + ctypes "github.com/ethereum/go-ethereum/core/types" ) // HeadInfo represents an unvalidated new head announcement. @@ -142,17 +142,57 @@ func (u UpdateScore) BetterThan(w UpdateScore) bool { return u.SignerCount > w.SignerCount } +// HeaderWithExecProof contains a beacon header and proves the belonging execution +// payload header with a Merkle proof. type HeaderWithExecProof struct { Header PayloadHeader *ExecutionHeader PayloadBranch merkle.Values } +// Validate verifies the Merkle proof of the execution payload header. func (h *HeaderWithExecProof) Validate() error { - payloadRoot := h.PayloadHeader.PayloadRoot() - return merkle.VerifyProof(h.BodyRoot, params.BodyIndexExecPayload, h.PayloadBranch, payloadRoot) + return merkle.VerifyProof(h.BodyRoot, params.BodyIndexExecPayload, h.PayloadBranch, h.PayloadHeader.PayloadRoot()) } +// OptimisticUpdate proves sync committee commitment on the attested beacon header. +// It also proves the belonging execution payload header with a Merkle proof. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate +type OptimisticUpdate struct { + Attested HeaderWithExecProof + // Sync committee BLS signature aggregate + Signature SyncAggregate + // Slot in which the signature has been created (newer than Header.Slot, + // determines the signing sync committee) + SignatureSlot uint64 +} + +// SignedHeader returns the signed attested header of the update. +func (u *OptimisticUpdate) SignedHeader() SignedHeader { + return SignedHeader{ + Header: u.Attested.Header, + Signature: u.Signature, + SignatureSlot: u.SignatureSlot, + } +} + +// Validate verifies the Merkle proof proving the execution payload header. +// Note that the sync committee signature of the attested header should be +// verified separately by a synced committee chain. +func (u *OptimisticUpdate) Validate() error { + return u.Attested.Validate() +} + +// FinalityUpdate proves a finalized beacon header by a sync committee commitment +// on an attested beacon header, referring to the latest finalized header with a +// Merkle proof. +// It also proves the execution payload header belonging to both the attested and +// the finalized beacon header with Merkle proofs. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate type FinalityUpdate struct { Attested, Finalized HeaderWithExecProof FinalityBranch merkle.Values @@ -163,6 +203,7 @@ type FinalityUpdate struct { SignatureSlot uint64 } +// SignedHeader returns the signed attested header of the update. func (u *FinalityUpdate) SignedHeader() SignedHeader { return SignedHeader{ Header: u.Attested.Header, @@ -171,6 +212,10 @@ func (u *FinalityUpdate) SignedHeader() SignedHeader { } } +// Validate verifies the Merkle proofs proving the finalized beacon header and +// the execution payload headers belonging to the attested and finalized headers. +// Note that the sync committee signature of the attested header should be +// verified separately by a synced committee chain. func (u *FinalityUpdate) Validate() error { if err := u.Attested.Validate(); err != nil { return err @@ -186,6 +231,6 @@ func (u *FinalityUpdate) Validate() error { // finalized execution block. type ChainHeadEvent struct { BeaconHead Header - Block *types.Block + Block *ctypes.Block Finalized common.Hash } From 94579932b18931115f28aa7f87f02450bda084c9 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 23 Apr 2024 07:10:24 -0600 Subject: [PATCH 204/571] core/vm: fix Prague contracts (#29612) core/vm: fix prague contracts --- core/vm/contracts.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 3d4819a74b48..5f7de8007b51 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -114,6 +114,16 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{ // PrecompiledContractsPrague contains the set of pre-compiled Ethereum // contracts used in the Prague release. var PrecompiledContractsPrague = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{0x01}): &ecrecover{}, + common.BytesToAddress([]byte{0x02}): &sha256hash{}, + common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x04}): &dataCopy{}, + common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true}, + common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{}, + common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{}, + common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{}, + common.BytesToAddress([]byte{0x09}): &blake2F{}, + common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{}, common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{}, common.BytesToAddress([]byte{0x0c}): &bls12381G1Mul{}, common.BytesToAddress([]byte{0x0d}): &bls12381G1MultiExp{}, From 882d1e22f66521d62ecdfe4566fb419765d744cf Mon Sep 17 00:00:00 2001 From: Chris Ziogas Date: Wed, 24 Apr 2024 08:53:16 +0300 Subject: [PATCH 205/571] cmd/geth, cmd/utils: rename config and flag to` VMTraceJsonConfig` (#29573) renames the yaml config field VMTraceConfig to VMTraceJsonConfig, in order to be consistent with the renaming of the CLI flag. --- cmd/geth/chaincmd.go | 2 +- cmd/geth/main.go | 2 +- cmd/utils/flags.go | 12 ++++++------ eth/backend.go | 4 ++-- eth/ethconfig/config.go | 4 ++-- eth/ethconfig/gen_config.go | 10 +++++----- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index dc45661eaecb..d787f340a38b 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -100,7 +100,7 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.MetricsInfluxDBOrganizationFlag, utils.TxLookupLimitFlag, utils.VMTraceFlag, - utils.VMTraceConfigFlag, + utils.VMTraceJsonConfigFlag, utils.TransactionHistoryFlag, utils.StateHistoryFlag, }, utils.DatabaseFlags), diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 37b99a2621b3..b7885608bc17 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -137,7 +137,7 @@ var ( utils.DeveloperPeriodFlag, utils.VMEnableDebugFlag, utils.VMTraceFlag, - utils.VMTraceConfigFlag, + utils.VMTraceJsonConfigFlag, utils.NetworkIdFlag, utils.EthStatsURLFlag, utils.NoCompactionFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 8ef9d9e7e836..e1c33678be37 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -544,7 +544,7 @@ var ( Usage: "Name of tracer which should record internal VM operations (costly)", Category: flags.VMCategory, } - VMTraceConfigFlag = &cli.StringFlag{ + VMTraceJsonConfigFlag = &cli.StringFlag{ Name: "vmtrace.jsonconfig", Usage: "Tracer configuration (JSON)", Category: flags.VMCategory, @@ -1903,12 +1903,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.IsSet(VMTraceFlag.Name) { if name := ctx.String(VMTraceFlag.Name); name != "" { var config string - if ctx.IsSet(VMTraceConfigFlag.Name) { - config = ctx.String(VMTraceConfigFlag.Name) + if ctx.IsSet(VMTraceJsonConfigFlag.Name) { + config = ctx.String(VMTraceJsonConfigFlag.Name) } cfg.VMTrace = name - cfg.VMTraceConfig = config + cfg.VMTraceJsonConfig = config } } } @@ -2192,8 +2192,8 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if ctx.IsSet(VMTraceFlag.Name) { if name := ctx.String(VMTraceFlag.Name); name != "" { var config json.RawMessage - if ctx.IsSet(VMTraceConfigFlag.Name) { - config = json.RawMessage(ctx.String(VMTraceConfigFlag.Name)) + if ctx.IsSet(VMTraceJsonConfigFlag.Name) { + config = json.RawMessage(ctx.String(VMTraceJsonConfigFlag.Name)) } t, err := tracers.LiveDirectory.New(name, config) if err != nil { diff --git a/eth/backend.go b/eth/backend.go index 04ee82efeeaa..e616b5f2f195 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -203,8 +203,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { ) if config.VMTrace != "" { var traceConfig json.RawMessage - if config.VMTraceConfig != "" { - traceConfig = json.RawMessage(config.VMTraceConfig) + if config.VMTraceJsonConfig != "" { + traceConfig = json.RawMessage(config.VMTraceJsonConfig) } t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig) if err != nil { diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 91f2c8d33010..f36f212d9c3b 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -142,8 +142,8 @@ type Config struct { EnablePreimageRecording bool // Enables VM tracing - VMTrace string - VMTraceConfig string + VMTrace string + VMTraceJsonConfig string // Miscellaneous options DocRoot string `toml:"-"` diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index cda62bc9dd5d..b8b9eee29423 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -51,7 +51,7 @@ func (c Config) MarshalTOML() (interface{}, error) { GPO gasprice.Config EnablePreimageRecording bool VMTrace string - VMTraceConfig string + VMTraceJsonConfig string DocRoot string `toml:"-"` RPCGasCap uint64 RPCEVMTimeout time.Duration @@ -94,7 +94,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.GPO = c.GPO enc.EnablePreimageRecording = c.EnablePreimageRecording enc.VMTrace = c.VMTrace - enc.VMTraceConfig = c.VMTraceConfig + enc.VMTraceJsonConfig = c.VMTraceJsonConfig enc.DocRoot = c.DocRoot enc.RPCGasCap = c.RPCGasCap enc.RPCEVMTimeout = c.RPCEVMTimeout @@ -141,7 +141,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { GPO *gasprice.Config EnablePreimageRecording *bool VMTrace *string - VMTraceConfig *string + VMTraceJsonConfig *string DocRoot *string `toml:"-"` RPCGasCap *uint64 RPCEVMTimeout *time.Duration @@ -255,8 +255,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.VMTrace != nil { c.VMTrace = *dec.VMTrace } - if dec.VMTraceConfig != nil { - c.VMTraceConfig = *dec.VMTraceConfig + if dec.VMTraceJsonConfig != nil { + c.VMTraceJsonConfig = *dec.VMTraceJsonConfig } if dec.DocRoot != nil { c.DocRoot = *dec.DocRoot From fb08fd334a48e2ad07e0d5205c23368ec9cd2bec Mon Sep 17 00:00:00 2001 From: Chris Ziogas Date: Wed, 24 Apr 2024 08:54:59 +0300 Subject: [PATCH 206/571] core/tracing: Add OnClose Trace Hook (#29629) The OnClose trace hook is being triggered on blockchain Stop, so as tracers can release any resources. --- core/blockchain.go | 4 ++++ core/tracing/hooks.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/core/blockchain.go b/core/blockchain.go index 8c97740752bc..b45cd92e523d 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1153,6 +1153,10 @@ func (bc *BlockChain) Stop() { } } } + // Allow tracers to clean-up and release resources. + if bc.logger != nil && bc.logger.OnClose != nil { + bc.logger.OnClose() + } // Close the trie database, release all the held resources as the last step. if err := bc.triedb.Close(); err != nil { log.Error("Failed to close trie database", "err", err) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 48cb4d20275c..9ca6ee39fbe7 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -107,6 +107,9 @@ type ( // BlockchainInitHook is called when the blockchain is initialized. BlockchainInitHook = func(chainConfig *params.ChainConfig) + // CloseHook is called when the blockchain closes. + CloseHook = func() + // BlockStartHook is called before executing `block`. // `td` is the total difficulty prior to `block`. BlockStartHook = func(event BlockEvent) @@ -153,6 +156,7 @@ type Hooks struct { OnGasChange GasChangeHook // Chain events OnBlockchainInit BlockchainInitHook + OnClose CloseHook OnBlockStart BlockStartHook OnBlockEnd BlockEndHook OnSkippedBlock SkippedBlockHook From ade7515c812e96467dce51da39af346aa27df575 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Wed, 24 Apr 2024 01:58:05 -0400 Subject: [PATCH 207/571] eth, eth/tracers: process beacon root before transactions (#29402) The beacon root when applied in `state_processor.go` is performed right before executing transaction. That means that contract reliying on this value would query the same value found in the block header. In that spirit, it means that any tracing/operation relying on state data which touches transaction must have updated the beacon root before any transaction processing. --- eth/state_accessor.go | 6 ++++++ eth/tracers/api.go | 22 +++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 770532cbfe73..372c76f49692 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -233,6 +233,12 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, if err != nil { return nil, vm.BlockContext{}, nil, nil, err } + // Insert parent beacon block root in the state as per EIP-4788. + if beaconRoot := block.BeaconRoot(); beaconRoot != nil { + context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) + core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + } if txIndex == 0 && len(block.Transactions()) == 0 { return nil, vm.BlockContext{}, statedb, release, nil } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 7a7c5e48d901..d99531d48fc9 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -376,6 +376,13 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed failed = err break } + // Insert block's parent beacon block root in the state + // as per EIP-4788. + if beaconRoot := next.BeaconRoot(); beaconRoot != nil { + context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) + core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + } // Clean out any pending release functions of trace state. Note this // step must be done after constructing tracing state, because the // tracing state of block next depends on the parent state and construction @@ -517,7 +524,6 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config return nil, err } defer release() - var ( roots []common.Hash signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) @@ -525,6 +531,10 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) ) + if beaconRoot := block.BeaconRoot(); beaconRoot != nil { + vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + } for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { return nil, err @@ -584,7 +594,6 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac return nil, err } defer release() - // JS tracers have high overhead. In this case run a parallel // process that generates states in one thread and traces txes // in separate worker threads. @@ -601,6 +610,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) results = make([]*txTraceResult, len(txs)) ) + if beaconRoot := block.BeaconRoot(); beaconRoot != nil { + vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) + core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + } for i, tx := range txs { // Generate the next state snapshot fast without tracing msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) @@ -727,7 +740,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block return nil, err } defer release() - // Retrieve the tracing configurations, or use default values var ( logConfig logger.Config @@ -756,6 +768,10 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Note: This copies the config, to not screw up the main config chainConfig, canon = overrideConfig(chainConfig, config.Overrides) } + if beaconRoot := block.BeaconRoot(); beaconRoot != nil { + vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + } for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution var ( From 5f3c58f1de9ef91dd22b632e6bcb559081d56e1d Mon Sep 17 00:00:00 2001 From: jwasinger Date: Wed, 24 Apr 2024 00:07:39 -0700 Subject: [PATCH 208/571] eth/downloader: fix case where skeleton reorgs below the filled block (#29358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change adds a testcase and fixes a corner-case in the skeleton sync. With this change, when doing the skeleton cleanup, we check if the filled header is acually within the range of what we were meant to backfill. If not, it means the backfill was a noop (possibly because we started and stopped it so quickly that it didn't have time to do any meaningful work). In that case, just don't clean up anything. --------- Co-authored-by: Péter Szilágyi --- eth/downloader/downloader_test.go | 81 +++++++++++++++++++++++++++++++ eth/downloader/skeleton.go | 10 ++++ 2 files changed, 91 insertions(+) diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 0fdc7ead9c3b..c810518d56ae 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -1311,3 +1311,84 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) { }) } } + +// Tests that synchronisation progress (origin block number and highest block +// number) is tracked and updated correctly in case of manual head reversion +func TestBeaconForkedSyncProgress68Full(t *testing.T) { + testBeaconForkedSyncProgress(t, eth.ETH68, FullSync) +} +func TestBeaconForkedSyncProgress68Snap(t *testing.T) { + testBeaconForkedSyncProgress(t, eth.ETH68, SnapSync) +} +func TestBeaconForkedSyncProgress68Light(t *testing.T) { + testBeaconForkedSyncProgress(t, eth.ETH68, LightSync) +} + +func testBeaconForkedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { + success := make(chan struct{}) + tester := newTesterWithNotification(t, func() { + success <- struct{}{} + }) + defer tester.terminate() + + chainA := testChainForkLightA.shorten(len(testChainBase.blocks) + MaxHeaderFetch) + chainB := testChainForkLightB.shorten(len(testChainBase.blocks) + MaxHeaderFetch) + + // Set a sync init hook to catch progress changes + starting := make(chan struct{}) + progress := make(chan struct{}) + + tester.downloader.syncInitHook = func(origin, latest uint64) { + starting <- struct{}{} + <-progress + } + checkProgress(t, tester.downloader, "pristine", ethereum.SyncProgress{}) + + // Synchronise with one of the forks and check progress + tester.newPeer("fork A", protocol, chainA.blocks[1:]) + pending := new(sync.WaitGroup) + pending.Add(1) + go func() { + defer pending.Done() + if err := tester.downloader.BeaconSync(mode, chainA.blocks[len(chainA.blocks)-1].Header(), nil); err != nil { + panic(fmt.Sprintf("failed to beacon sync: %v", err)) + } + }() + + <-starting + progress <- struct{}{} + select { + case <-success: + checkProgress(t, tester.downloader, "initial", ethereum.SyncProgress{ + HighestBlock: uint64(len(chainA.blocks) - 1), + CurrentBlock: uint64(len(chainA.blocks) - 1), + }) + case <-time.NewTimer(time.Second * 3).C: + t.Fatalf("Failed to sync chain in three seconds") + } + + // Set the head to a second fork + tester.newPeer("fork B", protocol, chainB.blocks[1:]) + pending.Add(1) + go func() { + defer pending.Done() + if err := tester.downloader.BeaconSync(mode, chainB.blocks[len(chainB.blocks)-1].Header(), nil); err != nil { + panic(fmt.Sprintf("failed to beacon sync: %v", err)) + } + }() + + <-starting + progress <- struct{}{} + + // reorg below available state causes the state sync to rewind to genesis + select { + case <-success: + checkProgress(t, tester.downloader, "initial", ethereum.SyncProgress{ + HighestBlock: uint64(len(chainB.blocks) - 1), + CurrentBlock: uint64(len(chainB.blocks) - 1), + StartingBlock: 0, + }) + case <-time.NewTimer(time.Second * 3).C: + t.Fatalf("Failed to sync chain in three seconds") + } +} diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index 873ee950b66c..04421a2bf5ca 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -1132,6 +1132,16 @@ func (s *skeleton) cleanStales(filled *types.Header) error { if number+1 == s.progress.Subchains[0].Tail { return nil } + // If the latest fill was on a different subchain, it means the backfiller + // was interrupted before it got to do any meaningful work, no cleanup + header := rawdb.ReadSkeletonHeader(s.db, filled.Number.Uint64()) + if header == nil { + log.Debug("Filled header outside of skeleton range", "number", number, "head", s.progress.Subchains[0].Head, "tail", s.progress.Subchains[0].Tail) + return nil + } else if header.Hash() != filled.Hash() { + log.Debug("Filled header on different sidechain", "number", number, "filled", filled.Hash(), "skeleton", header.Hash()) + return nil + } var ( start uint64 end uint64 From 87246f3cbaf10f83f56bc4d45f0f3e36e83e71e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 24 Apr 2024 11:02:49 +0300 Subject: [PATCH 209/571] params: release Geth v1.14.0 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index a49385da7d56..b3978be046de 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 938734be3ce1e254a0a72e56f8bdfb41b58e8953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 24 Apr 2024 11:05:10 +0300 Subject: [PATCH 210/571] params: begin 1.14.1 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index b3978be046de..319f21b2a8b4 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // 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. From 0d4c38865e9cda492e71221c4c429d9b1bec8ac5 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 24 Apr 2024 11:59:06 +0200 Subject: [PATCH 211/571] core/state: remove account reset operation v2 (#29520) * core/state, tests: remove account reset operation * core/state, core/vm: implement createcontract journal event * core/state: make createcontract not emit dirtied account, unskip tests * core/state: add createcontract to journal fuzzing * core/state: fix journal * core/state: address comments * core/state: remove useless code --------- Co-authored-by: Gary Rong --- core/state/journal.go | 151 ++++++++++++++---- core/state/state_object.go | 54 +++---- core/state/state_test.go | 102 +----------- core/state/statedb.go | 274 ++++++++++++++++---------------- core/state/statedb_fuzz_test.go | 4 +- core/state/statedb_test.go | 173 ++++++++++++++------ core/vm/evm.go | 21 ++- core/vm/interface.go | 1 + tests/block_test.go | 8 - 9 files changed, 428 insertions(+), 360 deletions(-) diff --git a/core/state/journal.go b/core/state/journal.go index 6cdc1fc86808..cfd3782eb01b 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -17,6 +17,8 @@ package state import ( + "maps" + "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" ) @@ -29,6 +31,9 @@ type journalEntry interface { // dirtied returns the Ethereum address modified by this journal entry. dirtied() *common.Address + + // copy returns a deep-copied journal entry. + copy() journalEntry } // journal contains the list of state modifications applied since the last state @@ -83,22 +88,31 @@ func (j *journal) length() int { return len(j.entries) } +// copy returns a deep-copied journal. +func (j *journal) copy() *journal { + entries := make([]journalEntry, 0, j.length()) + for i := 0; i < j.length(); i++ { + entries = append(entries, j.entries[i].copy()) + } + return &journal{ + entries: entries, + dirties: maps.Clone(j.dirties), + } +} + type ( // Changes to the account trie. createObjectChange struct { account *common.Address } - resetObjectChange struct { - account *common.Address - prev *stateObject - prevdestruct bool - prevAccount []byte - prevStorage map[common.Hash][]byte - prevAccountOriginExist bool - prevAccountOrigin []byte - prevStorageOrigin map[common.Hash][]byte + // createContractChange represents an account becoming a contract-account. + // This event happens prior to executing initcode. The journal-event simply + // manages the created-flag, in order to allow same-tx destruction. + createContractChange struct { + account common.Address } + selfDestructChange struct { account *common.Address prev bool // whether account had already self-destructed @@ -136,6 +150,7 @@ type ( touchChange struct { account *common.Address } + // Changes to the access list accessListAddAccountChange struct { address *common.Address @@ -145,6 +160,7 @@ type ( slot *common.Hash } + // Changes to transient storage transientStorageChange struct { account *common.Address key, prevalue common.Hash @@ -153,34 +169,30 @@ type ( func (ch createObjectChange) revert(s *StateDB) { delete(s.stateObjects, *ch.account) - delete(s.stateObjectsDirty, *ch.account) } func (ch createObjectChange) dirtied() *common.Address { return ch.account } -func (ch resetObjectChange) revert(s *StateDB) { - s.setStateObject(ch.prev) - if !ch.prevdestruct { - delete(s.stateObjectsDestruct, ch.prev.address) - } - if ch.prevAccount != nil { - s.accounts[ch.prev.addrHash] = ch.prevAccount - } - if ch.prevStorage != nil { - s.storages[ch.prev.addrHash] = ch.prevStorage - } - if ch.prevAccountOriginExist { - s.accountsOrigin[ch.prev.address] = ch.prevAccountOrigin - } - if ch.prevStorageOrigin != nil { - s.storagesOrigin[ch.prev.address] = ch.prevStorageOrigin +func (ch createObjectChange) copy() journalEntry { + return createObjectChange{ + account: ch.account, } } -func (ch resetObjectChange) dirtied() *common.Address { - return ch.account +func (ch createContractChange) revert(s *StateDB) { + s.getStateObject(ch.account).newContract = false +} + +func (ch createContractChange) dirtied() *common.Address { + return nil +} + +func (ch createContractChange) copy() journalEntry { + return createContractChange{ + account: ch.account, + } } func (ch selfDestructChange) revert(s *StateDB) { @@ -195,6 +207,14 @@ func (ch selfDestructChange) dirtied() *common.Address { return ch.account } +func (ch selfDestructChange) copy() journalEntry { + return selfDestructChange{ + account: ch.account, + prev: ch.prev, + prevbalance: new(uint256.Int).Set(ch.prevbalance), + } +} + var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") func (ch touchChange) revert(s *StateDB) { @@ -204,6 +224,12 @@ func (ch touchChange) dirtied() *common.Address { return ch.account } +func (ch touchChange) copy() journalEntry { + return touchChange{ + account: ch.account, + } +} + func (ch balanceChange) revert(s *StateDB) { s.getStateObject(*ch.account).setBalance(ch.prev) } @@ -212,6 +238,13 @@ func (ch balanceChange) dirtied() *common.Address { return ch.account } +func (ch balanceChange) copy() journalEntry { + return balanceChange{ + account: ch.account, + prev: new(uint256.Int).Set(ch.prev), + } +} + func (ch nonceChange) revert(s *StateDB) { s.getStateObject(*ch.account).setNonce(ch.prev) } @@ -220,6 +253,13 @@ func (ch nonceChange) dirtied() *common.Address { return ch.account } +func (ch nonceChange) copy() journalEntry { + return nonceChange{ + account: ch.account, + prev: ch.prev, + } +} + func (ch codeChange) revert(s *StateDB) { s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) } @@ -228,6 +268,14 @@ func (ch codeChange) dirtied() *common.Address { return ch.account } +func (ch codeChange) copy() journalEntry { + return codeChange{ + account: ch.account, + prevhash: common.CopyBytes(ch.prevhash), + prevcode: common.CopyBytes(ch.prevcode), + } +} + func (ch storageChange) revert(s *StateDB) { s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) } @@ -236,6 +284,14 @@ func (ch storageChange) dirtied() *common.Address { return ch.account } +func (ch storageChange) copy() journalEntry { + return storageChange{ + account: ch.account, + key: ch.key, + prevalue: ch.prevalue, + } +} + func (ch transientStorageChange) revert(s *StateDB) { s.setTransientState(*ch.account, ch.key, ch.prevalue) } @@ -244,6 +300,14 @@ func (ch transientStorageChange) dirtied() *common.Address { return nil } +func (ch transientStorageChange) copy() journalEntry { + return transientStorageChange{ + account: ch.account, + key: ch.key, + prevalue: ch.prevalue, + } +} + func (ch refundChange) revert(s *StateDB) { s.refund = ch.prev } @@ -252,6 +316,12 @@ func (ch refundChange) dirtied() *common.Address { return nil } +func (ch refundChange) copy() journalEntry { + return refundChange{ + prev: ch.prev, + } +} + func (ch addLogChange) revert(s *StateDB) { logs := s.logs[ch.txhash] if len(logs) == 1 { @@ -266,6 +336,12 @@ func (ch addLogChange) dirtied() *common.Address { return nil } +func (ch addLogChange) copy() journalEntry { + return addLogChange{ + txhash: ch.txhash, + } +} + func (ch addPreimageChange) revert(s *StateDB) { delete(s.preimages, ch.hash) } @@ -274,6 +350,12 @@ func (ch addPreimageChange) dirtied() *common.Address { return nil } +func (ch addPreimageChange) copy() journalEntry { + return addPreimageChange{ + hash: ch.hash, + } +} + func (ch accessListAddAccountChange) revert(s *StateDB) { /* One important invariant here, is that whenever a (addr, slot) is added, if the @@ -291,6 +373,12 @@ func (ch accessListAddAccountChange) dirtied() *common.Address { return nil } +func (ch accessListAddAccountChange) copy() journalEntry { + return accessListAddAccountChange{ + address: ch.address, + } +} + func (ch accessListAddSlotChange) revert(s *StateDB) { s.accessList.DeleteSlot(*ch.address, *ch.slot) } @@ -298,3 +386,10 @@ func (ch accessListAddSlotChange) revert(s *StateDB) { func (ch accessListAddSlotChange) dirtied() *common.Address { return nil } + +func (ch accessListAddSlotChange) copy() journalEntry { + return accessListAddSlotChange{ + address: ch.address, + slot: ch.slot, + } +} diff --git a/core/state/state_object.go b/core/state/state_object.go index db3c32f2f26b..8978b3054273 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -32,21 +32,8 @@ import ( "github.com/holiman/uint256" ) -type Code []byte - -func (c Code) String() string { - return string(c) //strings.Join(Disassemble(c), " ") -} - type Storage map[common.Hash]common.Hash -func (s Storage) String() (str string) { - for key, value := range s { - str += fmt.Sprintf("%X : %X\n", key, value) - } - return -} - func (s Storage) Copy() Storage { return maps.Clone(s) } @@ -65,8 +52,8 @@ type stateObject struct { data types.StateAccount // Account data with all mutations applied in the scope of block // Write caches. - trie Trie // storage trie, which becomes non-nil on first access - code Code // contract bytecode, which gets set when code is loaded + trie Trie // storage trie, which becomes non-nil on first access + code []byte // contract bytecode, which gets set when code is loaded originStorage Storage // Storage cache of original entries to dedup rewrites pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block @@ -75,17 +62,16 @@ type stateObject struct { // Cache flags. dirtyCode bool // true if the code was updated - // Flag whether the account was marked as self-destructed. The self-destructed account - // is still accessible in the scope of same transaction. + // Flag whether the account was marked as self-destructed. The self-destructed + // account is still accessible in the scope of same transaction. selfDestructed bool - // Flag whether the account was marked as deleted. A self-destructed account - // or an account that is considered as empty will be marked as deleted at - // the end of transaction and no longer accessible anymore. - deleted bool - - // Flag whether the object was created in the current transaction - created bool + // This is an EIP-6780 flag indicating whether the object is eligible for + // self-destruct according to EIP-6780. The flag could be set either when + // the contract is just created within the current transaction, or when the + // object was previously existent and is being deployed as a contract within + // the current transaction. + newContract bool } // empty returns whether the account is considered empty. @@ -95,10 +81,7 @@ func (s *stateObject) empty() bool { // newObject creates a state object. func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject { - var ( - origin = acct - created = acct == nil // true if the account was not existent - ) + origin := acct if acct == nil { acct = types.NewEmptyStateAccount() } @@ -111,7 +94,6 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s originStorage: make(Storage), pendingStorage: make(Storage), dirtyStorage: make(Storage), - created: created, } } @@ -264,6 +246,10 @@ func (s *stateObject) finalise(prefetch bool) { if len(s.dirtyStorage) > 0 { s.dirtyStorage = make(Storage) } + // Revoke the flag at the end of the transaction. It finalizes the status + // of the newly-created object as it's no longer eligible for self-destruct + // by EIP-6780. For non-newly-created objects, it's a no-op. + s.newContract = false } // updateTrie is responsible for persisting cached storage changes into the @@ -463,12 +449,12 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject { obj.trie = db.db.CopyTrie(s.trie) } obj.code = s.code - obj.dirtyStorage = s.dirtyStorage.Copy() obj.originStorage = s.originStorage.Copy() obj.pendingStorage = s.pendingStorage.Copy() - obj.selfDestructed = s.selfDestructed + obj.dirtyStorage = s.dirtyStorage.Copy() obj.dirtyCode = s.dirtyCode - obj.deleted = s.deleted + obj.selfDestructed = s.selfDestructed + obj.newContract = s.newContract return obj } @@ -483,7 +469,7 @@ func (s *stateObject) Address() common.Address { // Code returns the contract code associated with this object, if any. func (s *stateObject) Code() []byte { - if s.code != nil { + if len(s.code) != 0 { return s.code } if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { @@ -501,7 +487,7 @@ func (s *stateObject) Code() []byte { // or zero if none. This method is an almost mirror of Code, but uses a cache // inside the database to avoid loading codes seen recently. func (s *stateObject) CodeSize() int { - if s.code != nil { + if len(s.code) != 0 { return len(s.code) } if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { diff --git a/core/state/state_test.go b/core/state/state_test.go index c6e6db906e8c..9200e4abe9f9 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -194,106 +194,20 @@ func TestSnapshotEmpty(t *testing.T) { s.state.RevertToSnapshot(s.state.Snapshot()) } -func TestSnapshot2(t *testing.T) { +func TestCreateObjectRevert(t *testing.T) { state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + addr := common.BytesToAddress([]byte("so0")) + snap := state.Snapshot() - stateobjaddr0 := common.BytesToAddress([]byte("so0")) - stateobjaddr1 := common.BytesToAddress([]byte("so1")) - var storageaddr common.Hash - - data0 := common.BytesToHash([]byte{17}) - data1 := common.BytesToHash([]byte{18}) - - state.SetState(stateobjaddr0, storageaddr, data0) - state.SetState(stateobjaddr1, storageaddr, data1) - - // db, trie are already non-empty values - so0 := state.getStateObject(stateobjaddr0) + state.CreateAccount(addr) + so0 := state.getStateObject(addr) so0.SetBalance(uint256.NewInt(42), tracing.BalanceChangeUnspecified) so0.SetNonce(43) so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) - so0.selfDestructed = false - so0.deleted = false state.setStateObject(so0) - root, _ := state.Commit(0, false) - state, _ = New(root, state.db, state.snaps) - - // and one with deleted == true - so1 := state.getStateObject(stateobjaddr1) - so1.SetBalance(uint256.NewInt(52), tracing.BalanceChangeUnspecified) - so1.SetNonce(53) - so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) - so1.selfDestructed = true - so1.deleted = true - state.setStateObject(so1) - - so1 = state.getStateObject(stateobjaddr1) - if so1 != nil { - t.Fatalf("deleted object not nil when getting") - } - - snapshot := state.Snapshot() - state.RevertToSnapshot(snapshot) - - so0Restored := state.getStateObject(stateobjaddr0) - // Update lazily-loaded values before comparing. - so0Restored.GetState(storageaddr) - so0Restored.Code() - // non-deleted is equal (restored) - compareStateObjects(so0Restored, so0, t) - - // deleted should be nil, both before and after restore of state copy - so1Restored := state.getStateObject(stateobjaddr1) - if so1Restored != nil { - t.Fatalf("deleted object not nil after restoring snapshot: %+v", so1Restored) - } -} - -func compareStateObjects(so0, so1 *stateObject, t *testing.T) { - if so0.Address() != so1.Address() { - t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address) - } - if so0.Balance().Cmp(so1.Balance()) != 0 { - t.Fatalf("Balance mismatch: have %v, want %v", so0.Balance(), so1.Balance()) - } - if so0.Nonce() != so1.Nonce() { - t.Fatalf("Nonce mismatch: have %v, want %v", so0.Nonce(), so1.Nonce()) - } - if so0.data.Root != so1.data.Root { - t.Errorf("Root mismatch: have %x, want %x", so0.data.Root[:], so1.data.Root[:]) - } - if !bytes.Equal(so0.CodeHash(), so1.CodeHash()) { - t.Fatalf("CodeHash mismatch: have %v, want %v", so0.CodeHash(), so1.CodeHash()) - } - if !bytes.Equal(so0.code, so1.code) { - t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code) - } - - if len(so1.dirtyStorage) != len(so0.dirtyStorage) { - t.Errorf("Dirty storage size mismatch: have %d, want %d", len(so1.dirtyStorage), len(so0.dirtyStorage)) - } - for k, v := range so1.dirtyStorage { - if so0.dirtyStorage[k] != v { - t.Errorf("Dirty storage key %x mismatch: have %v, want %v", k, so0.dirtyStorage[k], v) - } - } - for k, v := range so0.dirtyStorage { - if so1.dirtyStorage[k] != v { - t.Errorf("Dirty storage key %x mismatch: have %v, want none.", k, v) - } - } - if len(so1.originStorage) != len(so0.originStorage) { - t.Errorf("Origin storage size mismatch: have %d, want %d", len(so1.originStorage), len(so0.originStorage)) - } - for k, v := range so1.originStorage { - if so0.originStorage[k] != v { - t.Errorf("Origin storage key %x mismatch: have %v, want %v", k, so0.originStorage[k], v) - } - } - for k, v := range so0.originStorage { - if so1.originStorage[k] != v { - t.Errorf("Origin storage key %x mismatch: have %v, want none.", k, v) - } + state.RevertToSnapshot(snap) + if state.Exist(addr) { + t.Error("Unexpected account after revert") } } diff --git a/core/state/statedb.go b/core/state/statedb.go index ab152dd18d66..4a934fe82cdf 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -44,6 +44,26 @@ type revision struct { journalIndex int } +type mutationType int + +const ( + update mutationType = iota + deletion +) + +type mutation struct { + typ mutationType + applied bool +} + +func (m *mutation) copy() *mutation { + return &mutation{typ: m.typ, applied: m.applied} +} + +func (m *mutation) isDelete() bool { + return m.typ == deletion +} + // StateDB structs within the ethereum protocol are used to store anything // within the merkle trie. StateDBs take care of caching and storing // nested states. It's the general query interface to retrieve: @@ -75,12 +95,22 @@ type StateDB struct { accountsOrigin map[common.Address][]byte // The original value of mutated accounts in 'slim RLP' encoding storagesOrigin map[common.Address]map[common.Hash][]byte // The original value of mutated slots in prefix-zero trimmed rlp format - // This map holds 'live' objects, which will get modified while processing - // a state transition. - stateObjects map[common.Address]*stateObject - stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie - stateObjectsDirty map[common.Address]struct{} // State objects modified in the current execution - stateObjectsDestruct map[common.Address]*types.StateAccount // State objects destructed in the block along with its previous value + // This map holds 'live' objects, which will get modified while + // processing a state transition. + stateObjects map[common.Address]*stateObject + + // This map holds 'deleted' objects. An object with the same address + // might also occur in the 'stateObjects' map due to account + // resurrection. The account value is tracked as the original value + // before the transition. This map is populated at the transaction + // boundaries. + stateObjectsDestruct map[common.Address]*types.StateAccount + + // This map tracks the account mutations that occurred during the + // transition. Uncommitted mutations belonging to the same account + // can be merged into a single one which is equivalent from database's + // perspective. This map is populated at the transaction boundaries. + mutations map[common.Address]*mutation // DB error. // State objects are used by the consensus core and VM which are @@ -154,9 +184,8 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) accountsOrigin: make(map[common.Address][]byte), storagesOrigin: make(map[common.Address]map[common.Hash][]byte), stateObjects: make(map[common.Address]*stateObject), - stateObjectsPending: make(map[common.Address]struct{}), - stateObjectsDirty: make(map[common.Address]struct{}), stateObjectsDestruct: make(map[common.Address]*types.StateAccount), + mutations: make(map[common.Address]*mutation), logs: make(map[common.Hash][]*types.Log), preimages: make(map[common.Hash][]byte), journal: newJournal(), @@ -472,8 +501,7 @@ func (s *StateDB) Selfdestruct6780(addr common.Address) { if stateObject == nil { return } - - if stateObject.created { + if stateObject.newContract { s.SelfDestruct(addr) } } @@ -552,24 +580,16 @@ func (s *StateDB) deleteStateObject(addr common.Address) { } // getStateObject retrieves a state object given by the address, returning nil if -// the object is not found or was deleted in this execution context. If you need -// to differentiate between non-existent/just-deleted, use getDeletedStateObject. +// the object is not found or was deleted in this execution context. func (s *StateDB) getStateObject(addr common.Address) *stateObject { - if obj := s.getDeletedStateObject(addr); obj != nil && !obj.deleted { - return obj - } - return nil -} - -// getDeletedStateObject is similar to getStateObject, but instead of returning -// nil for a deleted state object, it returns the actual object with the deleted -// flag set. This is needed by the state journal to revert to the correct s- -// destructed object instead of wiping all knowledge about the state object. -func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { // Prefer live objects if any is available if obj := s.stateObjects[addr]; obj != nil { return obj } + // Short circuit if the account is already destructed in this block. + if _, ok := s.stateObjectsDestruct[addr]; ok { + return nil + } // If no live objects are available, attempt to use snapshots var data *types.StateAccount if s.snap != nil { @@ -622,69 +642,40 @@ func (s *StateDB) setStateObject(object *stateObject) { // getOrNewStateObject retrieves a state object or create a new state object if nil. func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { - stateObject := s.getStateObject(addr) - if stateObject == nil { - stateObject, _ = s.createObject(addr) - } - return stateObject -} - -// createObject creates a new state object. If there is an existing account with -// the given address, it is overwritten and returned as the second return value. -func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { - prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that! - newobj = newObject(s, addr, nil) - if prev == nil { - s.journal.append(createObjectChange{account: &addr}) - } else { - // The original account should be marked as destructed and all cached - // account and storage data should be cleared as well. Note, it must - // be done here, otherwise the destruction event of "original account" - // will be lost. - _, prevdestruct := s.stateObjectsDestruct[prev.address] - if !prevdestruct { - s.stateObjectsDestruct[prev.address] = prev.origin - } - // There may be some cached account/storage data already since IntermediateRoot - // will be called for each transaction before byzantium fork which will always - // cache the latest account/storage data. - prevAccount, ok := s.accountsOrigin[prev.address] - s.journal.append(resetObjectChange{ - account: &addr, - prev: prev, - prevdestruct: prevdestruct, - prevAccount: s.accounts[prev.addrHash], - prevStorage: s.storages[prev.addrHash], - prevAccountOriginExist: ok, - prevAccountOrigin: prevAccount, - prevStorageOrigin: s.storagesOrigin[prev.address], - }) - delete(s.accounts, prev.addrHash) - delete(s.storages, prev.addrHash) - delete(s.accountsOrigin, prev.address) - delete(s.storagesOrigin, prev.address) + obj := s.getStateObject(addr) + if obj == nil { + obj = s.createObject(addr) } - s.setStateObject(newobj) - if prev != nil && !prev.deleted { - return newobj, prev - } - return newobj, nil + return obj } -// CreateAccount explicitly creates a state object. If a state object with the address -// already exists the balance is carried over to the new account. -// -// CreateAccount is called during the EVM CREATE operation. The situation might arise that -// a contract does the following: -// -// 1. sends funds to sha(account ++ (nonce + 1)) -// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1) -// -// Carrying over the balance ensures that Ether doesn't disappear. +// createObject creates a new state object. The assumption is held there is no +// existing account with the given address, otherwise it will be silently overwritten. +func (s *StateDB) createObject(addr common.Address) *stateObject { + obj := newObject(s, addr, nil) + s.journal.append(createObjectChange{account: &addr}) + s.setStateObject(obj) + return obj +} + +// CreateAccount explicitly creates a new state object, assuming that the +// account did not previously exist in the state. If the account already +// exists, this function will silently overwrite it which might lead to a +// consensus bug eventually. func (s *StateDB) CreateAccount(addr common.Address) { - newObj, prev := s.createObject(addr) - if prev != nil { - newObj.setBalance(prev.data.Balance) + s.createObject(addr) +} + +// CreateContract is used whenever a contract is created. This may be preceded +// by CreateAccount, but that is not required if it already existed in the +// state due to funds sent beforehand. +// This operation sets the 'newContract'-flag, which is required in order to +// correctly handle EIP-6780 'delete-in-same-transaction' logic. +func (s *StateDB) CreateContract(addr common.Address) { + obj := s.getStateObject(addr) + if !obj.newContract { + obj.newContract = true + s.journal.append(createContractChange{account: addr}) } } @@ -695,21 +686,25 @@ func (s *StateDB) Copy() *StateDB { state := &StateDB{ db: s.db, trie: s.db.CopyTrie(s.trie), + hasher: crypto.NewKeccakState(), originalRoot: s.originalRoot, accounts: copySet(s.accounts), storages: copy2DSet(s.storages), accountsOrigin: copySet(s.accountsOrigin), storagesOrigin: copy2DSet(s.storagesOrigin), - stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)), - stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)), - stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)), + stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)), stateObjectsDestruct: maps.Clone(s.stateObjectsDestruct), + mutations: make(map[common.Address]*mutation, len(s.mutations)), + dbErr: s.dbErr, refund: s.refund, + thash: s.thash, + txIndex: s.txIndex, logs: make(map[common.Hash][]*types.Log, len(s.logs)), logSize: s.logSize, preimages: maps.Clone(s.preimages), - journal: newJournal(), - hasher: crypto.NewKeccakState(), + journal: s.journal.copy(), + validRevisions: slices.Clone(s.validRevisions), + nextRevisionId: s.nextRevisionId, // In order for the block producer to be able to use and make additions // to the snapshot tree, we need to copy that as well. Otherwise, any @@ -718,39 +713,14 @@ func (s *StateDB) Copy() *StateDB { snaps: s.snaps, snap: s.snap, } - // Copy the dirty states, logs, and preimages - for addr := range s.journal.dirties { - // As documented [here](https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527), - // and in the Finalise-method, there is a case where an object is in the journal but not - // in the stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we need to check for - // nil - if object, exist := s.stateObjects[addr]; exist { - // Even though the original object is dirty, we are not copying the journal, - // so we need to make sure that any side-effect the journal would have caused - // during a commit (or similar op) is already applied to the copy. - state.stateObjects[addr] = object.deepCopy(state) - - state.stateObjectsDirty[addr] = struct{}{} // Mark the copy dirty to force internal (code/state) commits - state.stateObjectsPending[addr] = struct{}{} // Mark the copy pending to force external (account) commits - } - } - // Above, we don't copy the actual journal. This means that if the copy - // is copied, the loop above will be a no-op, since the copy's journal - // is empty. Thus, here we iterate over stateObjects, to enable copies - // of copies. - for addr := range s.stateObjectsPending { - if _, exist := state.stateObjects[addr]; !exist { - state.stateObjects[addr] = s.stateObjects[addr].deepCopy(state) - } - state.stateObjectsPending[addr] = struct{}{} + // Deep copy cached state objects. + for addr, obj := range s.stateObjects { + state.stateObjects[addr] = obj.deepCopy(state) } - for addr := range s.stateObjectsDirty { - if _, exist := state.stateObjects[addr]; !exist { - state.stateObjects[addr] = s.stateObjects[addr].deepCopy(state) - } - state.stateObjectsDirty[addr] = struct{}{} + // Deep copy the object state markers. + for addr, op := range s.mutations { + state.mutations[addr] = op.copy() } - // Deep copy the logs occurred in the scope of block for hash, logs := range s.logs { cpy := make([]*types.Log, len(logs)) @@ -760,7 +730,6 @@ func (s *StateDB) Copy() *StateDB { } state.logs[hash] = cpy } - // Do we need to copy the access list and transient storage? // In practice: No. At the start of a transaction, these two lists are empty. // In practice, we only ever copy state _between_ transactions/blocks, never @@ -825,7 +794,8 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { continue } if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) { - obj.deleted = true + delete(s.stateObjects, obj.address) + s.markDelete(addr) // If ether was sent to account post-selfdestruct it is burnt. if bal := obj.Balance(); s.logger != nil && s.logger.OnBalanceChange != nil && obj.selfDestructed && bal.Sign() != 0 { @@ -846,11 +816,8 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { delete(s.storagesOrigin, obj.address) // Clear out any previously updated storage data (may be recreated via a resurrect) } else { obj.finalise(true) // Prefetch slots in the background + s.markUpdate(addr) } - obj.created = false - s.stateObjectsPending[addr] = struct{}{} - s.stateObjectsDirty[addr] = struct{}{} - // At this point, also ship the address off to the precacher. The precacher // will start loading tries, and when the change is eventually committed, // the commit-phase will be a lot faster @@ -889,10 +856,14 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // the account prefetcher. Instead, let's process all the storage updates // first, giving the account prefetches just a few more milliseconds of time // to pull useful data from disk. - for addr := range s.stateObjectsPending { - if obj := s.stateObjects[addr]; !obj.deleted { - obj.updateRoot() + for addr, op := range s.mutations { + if op.applied { + continue + } + if op.isDelete() { + continue } + s.stateObjects[addr].updateRoot() } // Now we're about to start to write changes to the trie. The trie is so far // _untouched_. We can check with the prefetcher, if it can give us a trie @@ -902,7 +873,6 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.trie = trie } } - usedAddrs := make([][]byte, 0, len(s.stateObjectsPending)) // Perform updates before deletions. This prevents resolution of unnecessary trie nodes // in circumstances similar to the following: // @@ -913,13 +883,21 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // If the self-destruct is handled first, then `P` would be left with only one child, thus collapsed // into a shortnode. This requires `B` to be resolved from disk. // Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved. - var deletedAddrs []common.Address - for addr := range s.stateObjectsPending { - if obj := s.stateObjects[addr]; !obj.deleted { - s.updateStateObject(obj) - s.AccountUpdated += 1 + var ( + usedAddrs [][]byte + deletedAddrs []common.Address + ) + for addr, op := range s.mutations { + if op.applied { + continue + } + op.applied = true + + if op.isDelete() { + deletedAddrs = append(deletedAddrs, addr) } else { - deletedAddrs = append(deletedAddrs, obj.address) + s.updateStateObject(s.stateObjects[addr]) + s.AccountUpdated += 1 } usedAddrs = append(usedAddrs, common.CopyBytes(addr[:])) // Copy needed for closure } @@ -930,9 +908,6 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { if prefetcher != nil { prefetcher.used(common.Hash{}, s.originalRoot, usedAddrs) } - if len(s.stateObjectsPending) > 0 { - s.stateObjectsPending = make(map[common.Address]struct{}) - } // Track the amount of time wasted on hashing the account trie defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) @@ -1176,11 +1151,12 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er return common.Hash{}, err } // Handle all state updates afterwards - for addr := range s.stateObjectsDirty { - obj := s.stateObjects[addr] - if obj.deleted { + for addr, op := range s.mutations { + if op.isDelete() { continue } + obj := s.stateObjects[addr] + // Write any contract code associated with the state object if obj.code != nil && obj.dirtyCode { rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) @@ -1280,7 +1256,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er s.storages = make(map[common.Hash]map[common.Hash][]byte) s.accountsOrigin = make(map[common.Address][]byte) s.storagesOrigin = make(map[common.Address]map[common.Hash][]byte) - s.stateObjectsDirty = make(map[common.Address]struct{}) + s.mutations = make(map[common.Address]*mutation) s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) return root, nil } @@ -1395,3 +1371,19 @@ func copy2DSet[k comparable](set map[k]map[common.Hash][]byte) map[k]map[common. } return copied } + +func (s *StateDB) markDelete(addr common.Address) { + if _, ok := s.mutations[addr]; !ok { + s.mutations[addr] = &mutation{} + } + s.mutations[addr].applied = false + s.mutations[addr].typ = deletion +} + +func (s *StateDB) markUpdate(addr common.Address) { + if _, ok := s.mutations[addr]; !ok { + s.mutations[addr] = &mutation{} + } + s.mutations[addr].applied = false + s.mutations[addr].typ = update +} diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 65cf278108f5..6317681a7fba 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -96,7 +96,9 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction { name: "CreateAccount", fn: func(a testAction, s *StateDB) { - s.CreateAccount(addr) + if !s.Exist(addr) { + s.CreateAccount(addr) + } }, }, { diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index edde6e825472..1a3eccfe10b7 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -225,6 +225,78 @@ func TestCopy(t *testing.T) { } } +// TestCopyWithDirtyJournal tests if Copy can correct create a equal copied +// stateDB with dirty journal present. +func TestCopyWithDirtyJournal(t *testing.T) { + db := NewDatabase(rawdb.NewMemoryDatabase()) + orig, _ := New(types.EmptyRootHash, db, nil) + + // Fill up the initial states + for i := byte(0); i < 255; i++ { + obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i})) + obj.AddBalance(uint256.NewInt(uint64(i)), tracing.BalanceChangeUnspecified) + obj.data.Root = common.HexToHash("0xdeadbeef") + orig.updateStateObject(obj) + } + root, _ := orig.Commit(0, true) + orig, _ = New(root, db, nil) + + // modify all in memory without finalizing + for i := byte(0); i < 255; i++ { + obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i})) + obj.SubBalance(uint256.NewInt(uint64(i)), tracing.BalanceChangeUnspecified) + orig.updateStateObject(obj) + } + cpy := orig.Copy() + + orig.Finalise(true) + for i := byte(0); i < 255; i++ { + root := orig.GetStorageRoot(common.BytesToAddress([]byte{i})) + if root != (common.Hash{}) { + t.Errorf("Unexpected storage root %x", root) + } + } + cpy.Finalise(true) + for i := byte(0); i < 255; i++ { + root := cpy.GetStorageRoot(common.BytesToAddress([]byte{i})) + if root != (common.Hash{}) { + t.Errorf("Unexpected storage root %x", root) + } + } + if cpy.IntermediateRoot(true) != orig.IntermediateRoot(true) { + t.Error("State is not equal after copy") + } +} + +// TestCopyObjectState creates an original state, S1, and makes a copy S2. +// It then proceeds to make changes to S1. Those changes are _not_ supposed +// to affect S2. This test checks that the copy properly deep-copies the objectstate +func TestCopyObjectState(t *testing.T) { + db := NewDatabase(rawdb.NewMemoryDatabase()) + orig, _ := New(types.EmptyRootHash, db, nil) + + // Fill up the initial states + for i := byte(0); i < 5; i++ { + obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i})) + obj.AddBalance(uint256.NewInt(uint64(i)), tracing.BalanceChangeUnspecified) + obj.data.Root = common.HexToHash("0xdeadbeef") + orig.updateStateObject(obj) + } + orig.Finalise(true) + cpy := orig.Copy() + for _, op := range cpy.mutations { + if have, want := op.applied, false; have != want { + t.Fatalf("Error in test itself, the 'done' flag should not be set before Commit, have %v want %v", have, want) + } + } + orig.Commit(0, true) + for _, op := range cpy.mutations { + if have, want := op.applied, false; have != want { + t.Fatalf("Error: original state affected copy, have %v want %v", have, want) + } + } +} + func TestSnapshotRandom(t *testing.T) { config := &quick.Config{MaxCount: 1000} err := quick.Check((*snapshotTest).run, config) @@ -308,7 +380,30 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { { name: "CreateAccount", fn: func(a testAction, s *StateDB) { - s.CreateAccount(addr) + if !s.Exist(addr) { + s.CreateAccount(addr) + } + }, + }, + { + name: "CreateContract", + fn: func(a testAction, s *StateDB) { + if !s.Exist(addr) { + s.CreateAccount(addr) + } + contractHash := s.GetCodeHash(addr) + emptyCode := contractHash == (common.Hash{}) || contractHash == types.EmptyCodeHash + storageRoot := s.GetStorageRoot(addr) + emptyStorage := storageRoot == (common.Hash{}) || storageRoot == types.EmptyRootHash + if s.GetNonce(addr) == 0 && emptyCode && emptyStorage { + s.CreateContract(addr) + // We also set some code here, to prevent the + // CreateContract action from being performed twice in a row, + // which would cause a difference in state when unrolling + // the journal. (CreateContact assumes created was false prior to + // invocation, and the journal rollback sets it to false). + s.SetCode(addr, []byte{1}) + } }, }, { @@ -709,18 +804,19 @@ func TestCopyCopyCommitCopy(t *testing.T) { } } -// TestCommitCopy tests the copy from a committed state is not functional. +// TestCommitCopy tests the copy from a committed state is not fully functional. func TestCommitCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + db := NewDatabase(rawdb.NewMemoryDatabase()) + state, _ := New(types.EmptyRootHash, db, nil) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") - skey := common.HexToHash("aaa") - sval := common.HexToHash("bbb") + skey1, skey2 := common.HexToHash("a1"), common.HexToHash("a2") + sval1, sval2 := common.HexToHash("b1"), common.HexToHash("b2") state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetState(addr, skey1, sval1) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -728,25 +824,38 @@ func TestCommitCopy(t *testing.T) { if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) } - if val := state.GetState(addr, skey); val != sval { - t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) + if val := state.GetState(addr, skey1); val != sval1 { + t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval1) } - if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { + if val := state.GetCommittedState(addr, skey1); val != (common.Hash{}) { t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) } - // Copy the committed state database, the copied one is not functional. - state.Commit(0, true) + root, _ := state.Commit(0, true) + + state, _ = New(root, db, nil) + state.SetState(addr, skey2, sval2) + state.Commit(1, true) + + // Copy the committed state database, the copied one is not fully functional. copied := state.Copy() - if balance := copied.GetBalance(addr); balance.Cmp(uint256.NewInt(0)) != 0 { + if balance := copied.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { t.Fatalf("unexpected balance: have %v", balance) } - if code := copied.GetCode(addr); code != nil { + if code := copied.GetCode(addr); !bytes.Equal(code, []byte("hello")) { t.Fatalf("unexpected code: have %x", code) } - if val := copied.GetState(addr, skey); val != (common.Hash{}) { + // Miss slots because of non-functional trie after commit + if val := copied.GetState(addr, skey1); val != (common.Hash{}) { + t.Fatalf("unexpected storage slot: have %x", sval1) + } + if val := copied.GetCommittedState(addr, skey1); val != (common.Hash{}) { t.Fatalf("unexpected storage slot: have %x", val) } - if val := copied.GetCommittedState(addr, skey); val != (common.Hash{}) { + // Slots cached in the stateDB, available after commit + if val := copied.GetState(addr, skey2); val != sval2 { + t.Fatalf("unexpected storage slot: have %x", sval1) + } + if val := copied.GetCommittedState(addr, skey2); val != sval2 { t.Fatalf("unexpected storage slot: have %x", val) } if !errors.Is(copied.Error(), trie.ErrCommitted) { @@ -1103,40 +1212,6 @@ func TestStateDBTransientStorage(t *testing.T) { } } -func TestResetObject(t *testing.T) { - var ( - disk = rawdb.NewMemoryDatabase() - tdb = triedb.NewDatabase(disk, nil) - db = NewDatabaseWithNodeDB(disk, tdb) - snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash) - state, _ = New(types.EmptyRootHash, db, snaps) - addr = common.HexToAddress("0x1") - slotA = common.HexToHash("0x1") - slotB = common.HexToHash("0x2") - ) - // Initialize account with balance and storage in first transaction. - state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) - state.SetState(addr, slotA, common.BytesToHash([]byte{0x1})) - state.IntermediateRoot(true) - - // Reset account and mutate balance and storages - state.CreateAccount(addr) - state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified) - state.SetState(addr, slotB, common.BytesToHash([]byte{0x2})) - root, _ := state.Commit(0, true) - - // Ensure the original account is wiped properly - snap := snaps.Snapshot(root) - slot, _ := snap.Storage(crypto.Keccak256Hash(addr.Bytes()), crypto.Keccak256Hash(slotA.Bytes())) - if len(slot) != 0 { - t.Fatalf("Unexpected storage slot") - } - slot, _ = snap.Storage(crypto.Keccak256Hash(addr.Bytes()), crypto.Keccak256Hash(slotB.Bytes())) - if !bytes.Equal(slot, []byte{0x2}) { - t.Fatalf("Unexpected storage slot value %v", slot) - } -} - func TestDeleteStorage(t *testing.T) { var ( disk = rawdb.NewMemoryDatabase() diff --git a/core/vm/evm.go b/core/vm/evm.go index 045506a1fd32..c18353a97354 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -436,14 +436,15 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, return nil, common.Address{}, gas, ErrNonceUintOverflow } evm.StateDB.SetNonce(caller.Address(), nonce+1) - // We add this to the access list _before_ taking a snapshot. Even if the creation fails, - // the access-list change should not be rolled back + + // We add this to the access list _before_ taking a snapshot. Even if the + // creation fails, the access-list change should not be rolled back. if evm.chainRules.IsBerlin { evm.StateDB.AddAddressToAccessList(address) } // Ensure there's no existing contract already at the designated address. // Account is regarded as existent if any of these three conditions is met: - // - the nonce is nonzero + // - the nonce is non-zero // - the code is non-empty // - the storage is non-empty contractHash := evm.StateDB.GetCodeHash(address) @@ -456,9 +457,19 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } return nil, common.Address{}, 0, ErrContractAddressCollision } - // Create a new account on the state + // Create a new account on the state only if the object was not present. + // It might be possible the contract code is deployed to a pre-existent + // account with non-zero balance. snapshot := evm.StateDB.Snapshot() - evm.StateDB.CreateAccount(address) + if !evm.StateDB.Exist(address) { + evm.StateDB.CreateAccount(address) + } + // CreateContract means that regardless of whether the account previously existed + // in the state trie or not, it _now_ becomes created as a _contract_ account. + // This is performed _prior_ to executing the initcode, since the initcode + // acts inside that account. + evm.StateDB.CreateContract(address) + if evm.chainRules.IsEIP158 { evm.StateDB.SetNonce(address, 1) } diff --git a/core/vm/interface.go b/core/vm/interface.go index 30742e96de2b..774360a08ef9 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -29,6 +29,7 @@ import ( // StateDB is an EVM database for full state querying. type StateDB interface { CreateAccount(common.Address) + CreateContract(common.Address) SubBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason) AddBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason) diff --git a/tests/block_test.go b/tests/block_test.go index 43e3d99b3e8c..1ba84f5f24b6 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -64,14 +64,6 @@ func TestExecutionSpecBlocktests(t *testing.T) { } bt := new(testMatcher) - // These tests fail as of https://github.com/ethereum/go-ethereum/pull/28666, since we - // no longer delete "leftover storage" when deploying a contract. - bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/self_destructing_initcode_create_tx.json`) - bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/self_destructing_initcode.json`) - bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/recreate_self_destructed_contract_different_txs.json`) - bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/delegatecall_from_new_contract_to_pre_existing_contract.json`) - bt.skipLoad(`^cancun/eip6780_selfdestruct/selfdestruct/create_selfdestruct_same_tx.json`) - bt.walk(t, executionSpecBlockchainTestDir, func(t *testing.T, name string, test *BlockTest) { execBlockTest(t, bt, test) }) From ac21f9bfb5154854e241928840b3978d801eac8c Mon Sep 17 00:00:00 2001 From: qcrao Date: Wed, 24 Apr 2024 20:04:20 +0800 Subject: [PATCH 212/571] trie: preallocate capacity for fields slice (#29614) trie: Preallocate capacity for fields slice --- trie/trienode/node.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trie/trienode/node.go b/trie/trienode/node.go index 95315c2e9a4f..055db8822e72 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -78,7 +78,7 @@ func NewNodeSet(owner common.Hash) *NodeSet { // ForEachWithOrder iterates the nodes with the order from bottom to top, // right to left, nodes with the longest path will be iterated first. func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) { - var paths []string + paths := make([]string, 0, len(set.Nodes)) for path := range set.Nodes { paths = append(paths, path) } @@ -133,7 +133,7 @@ func (set *NodeSet) Size() (int, int) { // Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can // we get rid of it? func (set *NodeSet) Hashes() []common.Hash { - var ret []common.Hash + ret := make([]common.Hash, 0, len(set.Nodes)) for _, node := range set.Nodes { ret = append(ret, node.Hash) } From 7362691479df9eb7d76c8b968ed8f440372fab6e Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Wed, 24 Apr 2024 20:27:58 +0800 Subject: [PATCH 213/571] trie, consensus/clique: use maps.Clone (#29616) --- consensus/clique/snapshot.go | 23 ++++++----------------- trie/tracer.go | 18 +++++------------- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go index 8ff0b3a70ff7..d0b15e9489cc 100644 --- a/consensus/clique/snapshot.go +++ b/consensus/clique/snapshot.go @@ -19,6 +19,7 @@ package clique import ( "bytes" "encoding/json" + "maps" "slices" "time" @@ -108,28 +109,16 @@ func (s *Snapshot) store(db ethdb.Database) error { // copy creates a deep copy of the snapshot, though not the individual votes. func (s *Snapshot) copy() *Snapshot { - cpy := &Snapshot{ + return &Snapshot{ config: s.config, sigcache: s.sigcache, Number: s.Number, Hash: s.Hash, - Signers: make(map[common.Address]struct{}), - Recents: make(map[uint64]common.Address), - Votes: make([]*Vote, len(s.Votes)), - Tally: make(map[common.Address]Tally), - } - for signer := range s.Signers { - cpy.Signers[signer] = struct{}{} + Signers: maps.Clone(s.Signers), + Recents: maps.Clone(s.Recents), + Votes: slices.Clone(s.Votes), + Tally: maps.Clone(s.Tally), } - for block, signer := range s.Recents { - cpy.Recents[block] = signer - } - for address, tally := range s.Tally { - cpy.Tally[address] = tally - } - copy(cpy.Votes, s.Votes) - - return cpy } // validVote returns whether it makes sense to cast the specified vote in the diff --git a/trie/tracer.go b/trie/tracer.go index 5786af4d3ec9..90b9666f0bb5 100644 --- a/trie/tracer.go +++ b/trie/tracer.go @@ -17,6 +17,8 @@ package trie import ( + "maps" + "github.com/ethereum/go-ethereum/common" ) @@ -92,23 +94,13 @@ func (t *tracer) reset() { // copy returns a deep copied tracer instance. func (t *tracer) copy() *tracer { - var ( - inserts = make(map[string]struct{}) - deletes = make(map[string]struct{}) - accessList = make(map[string][]byte) - ) - for path := range t.inserts { - inserts[path] = struct{}{} - } - for path := range t.deletes { - deletes[path] = struct{}{} - } + accessList := make(map[string][]byte, len(t.accessList)) for path, blob := range t.accessList { accessList[path] = common.CopyBytes(blob) } return &tracer{ - inserts: inserts, - deletes: deletes, + inserts: maps.Clone(t.inserts), + deletes: maps.Clone(t.deletes), accessList: accessList, } } From 4f4f9d88d3a59e972c9fe3a5e6e6a93dad2e7db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 24 Apr 2024 18:45:24 +0300 Subject: [PATCH 214/571] core/state: storage journal entry should revert dirtyness too (#29641) Currently our state journal tracks each storage update to a contract, having the ability to revert those changes to the previously set value. For the very first modification however, it behaves a bit wonky. Reverting the update doesn't actually remove the dirty-ness of the slot, rather leaves it as "change this slot to it's original value". This can cause issues down the line with for example write witnesses needing to gather an unneeded proof. This PR modifies the storageChange journal entry to not only track the previous value of a slot, but also whether there was any previous value at all set in the current execution context. In essence, the PR changes the semantic of storageChange so it does not simply track storage changes, rather it tracks dirty storage changes, an important distinction for being able to cleanly revert the journal item. --- core/state/journal.go | 13 +++++++------ core/state/state_object.go | 40 ++++++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/core/state/journal.go b/core/state/journal.go index cfd3782eb01b..c0f5615c9815 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -129,8 +129,9 @@ type ( prev uint64 } storageChange struct { - account *common.Address - key, prevalue common.Hash + account *common.Address + key common.Hash + prevvalue *common.Hash } codeChange struct { account *common.Address @@ -277,7 +278,7 @@ func (ch codeChange) copy() journalEntry { } func (ch storageChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) + s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue) } func (ch storageChange) dirtied() *common.Address { @@ -286,9 +287,9 @@ func (ch storageChange) dirtied() *common.Address { func (ch storageChange) copy() journalEntry { return storageChange{ - account: ch.account, - key: ch.key, - prevalue: ch.prevalue, + account: ch.account, + key: ch.key, + prevvalue: ch.prevvalue, } } diff --git a/core/state/state_object.go b/core/state/state_object.go index 8978b3054273..aa748f08ac3c 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -140,13 +140,20 @@ func (s *stateObject) getTrie() (Trie, error) { // GetState retrieves a value from the account storage trie. func (s *stateObject) GetState(key common.Hash) common.Hash { + value, _ := s.getState(key) + return value +} + +// getState retrieves a value from the account storage trie and also returns if +// the slot is already dirty or not. +func (s *stateObject) getState(key common.Hash) (common.Hash, bool) { // If we have a dirty value for this state entry, return it value, dirty := s.dirtyStorage[key] if dirty { - return value + return value, true } // Otherwise return the entry's original value - return s.GetCommittedState(key) + return s.GetCommittedState(key), false } // GetCommittedState retrieves a value from the committed account storage trie. @@ -209,25 +216,38 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { // SetState updates a value in account storage. func (s *stateObject) SetState(key, value common.Hash) { - // If the new value is the same as old, don't set - prev := s.GetState(key) + // If the new value is the same as old, don't set. Otherwise, track only the + // dirty changes, supporting reverting all of it back to no change. + prev, dirty := s.getState(key) if prev == value { return } + var prevvalue *common.Hash + if dirty { + prevvalue = &prev + } // New value is different, update and journal the change s.db.journal.append(storageChange{ - account: &s.address, - key: key, - prevalue: prev, + account: &s.address, + key: key, + prevvalue: prevvalue, }) if s.db.logger != nil && s.db.logger.OnStorageChange != nil { s.db.logger.OnStorageChange(s.address, key, prev, value) } - s.setState(key, value) + s.setState(key, &value) } -func (s *stateObject) setState(key, value common.Hash) { - s.dirtyStorage[key] = value +// setState updates a value in account dirty storage. If the value being set is +// nil (assuming journal revert), the dirtyness is removed. +func (s *stateObject) setState(key common.Hash, value *common.Hash) { + // If the first set is being reverted, undo the dirty marker + if value == nil { + delete(s.dirtyStorage, key) + return + } + // Otherwise restore the previous value + s.dirtyStorage[key] = *value } // finalise moves all dirty storage slots into the pending area to be hashed or From 2f6ff492ae02313c9e45df5222bfd472b2481d76 Mon Sep 17 00:00:00 2001 From: yujinpark Date: Thu, 25 Apr 2024 14:47:29 +0900 Subject: [PATCH 215/571] internal/ethapi: typo (#29636) --- internal/ethapi/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 8b15d211d1c4..4b5145f5deea 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -142,7 +142,7 @@ func (s *EthereumAPI) BlobBaseFee(ctx context.Context) *hexutil.Big { } // Syncing returns false in case the node is currently not syncing with the network. It can be up-to-date or has not -// yet received the latest block headers from its pears. In case it is synchronizing: +// yet received the latest block headers from its peers. In case it is synchronizing: // - startingBlock: block number this node started to synchronize from // - currentBlock: block number this node is currently importing // - highestBlock: block number of the highest block header this node has received from peers From a13b92524d9319424b5e9cdf4f9f1d77bf52849f Mon Sep 17 00:00:00 2001 From: Undefinedor Date: Thu, 25 Apr 2024 14:40:29 +0800 Subject: [PATCH 216/571] eth/protocols/eth,p2p/discover: remove unnecessary checks (#29590) fix useless condition --- eth/protocols/eth/handlers.go | 2 +- p2p/discover/v4_udp.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 96656afb1b20..bdc630a9f467 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -190,7 +190,7 @@ func serviceContiguousBlockHeaderQuery(chain *core.BlockChain, query *GetBlockHe return headers } { // Last mode: deliver ancestors of H - for i := uint64(1); header != nil && i < count; i++ { + for i := uint64(1); i < count; i++ { header = chain.GetHeaderByHash(header.ParentHash) if header == nil { break diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 44b1f5305c45..7a0a0f1c7779 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -548,7 +548,7 @@ func (t *UDPv4) handlePacket(from *net.UDPAddr, buf []byte) error { } packet := t.wrapPacket(rawpacket) fromID := fromKey.ID() - if err == nil && packet.preverify != nil { + if packet.preverify != nil { err = packet.preverify(packet, from, fromID, fromKey) } t.log.Trace("<< "+packet.Name(), "id", fromID, "addr", from, "err", err) From 243cde0f54e407ba52c570295886083d6e7d651e Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 25 Apr 2024 09:56:25 +0200 Subject: [PATCH 217/571] core/state: better randomized testing (postcheck) on journalling (#29627) This PR fixes some flaws with the existing tests. The randomized testing (TestSnapshotRandom) executes a series of steps which modify the state and create journal-events. Later on, we compare the forward-going-states against the backwards-unrolling-journal-states, and check that they are identical. The "identical" check is performed using various accessors. It turned out that we failed to check some things: - the accesslist contents - the transient storage contents - the 'newContract' flag - the dirty storage map This change adds these new checks --- core/state/access_list.go | 35 +++++++++++++++++ core/state/state_object.go | 24 ++++++------ core/state/statedb_test.go | 68 ++++++++++++++++++++++++++++++++- core/state/transient_storage.go | 43 +++++++++++++++++++-- 4 files changed, 153 insertions(+), 17 deletions(-) diff --git a/core/state/access_list.go b/core/state/access_list.go index 718bf17cf742..b0effbeadc49 100644 --- a/core/state/access_list.go +++ b/core/state/access_list.go @@ -17,7 +17,10 @@ package state import ( + "fmt" "maps" + "slices" + "strings" "github.com/ethereum/go-ethereum/common" ) @@ -130,3 +133,35 @@ func (al *accessList) DeleteSlot(address common.Address, slot common.Hash) { func (al *accessList) DeleteAddress(address common.Address) { delete(al.addresses, address) } + +// Equal returns true if the two access lists are identical +func (al *accessList) Equal(other *accessList) bool { + if !maps.Equal(al.addresses, other.addresses) { + return false + } + return slices.EqualFunc(al.slots, other.slots, + func(m map[common.Hash]struct{}, m2 map[common.Hash]struct{}) bool { + return maps.Equal(m, m2) + }) +} + +// PrettyPrint prints the contents of the access list in a human-readable form +func (al *accessList) PrettyPrint() string { + out := new(strings.Builder) + var sortedAddrs []common.Address + for addr := range al.addresses { + sortedAddrs = append(sortedAddrs, addr) + } + slices.SortFunc(sortedAddrs, common.Address.Cmp) + for _, addr := range sortedAddrs { + idx := al.addresses[addr] + fmt.Fprintf(out, "%#x : (idx %d)\n", addr, idx) + if idx >= 0 { + slotmap := al.slots[idx] + for h := range slotmap { + fmt.Fprintf(out, " %#x\n", h) + } + } + } + return out.String() +} diff --git a/core/state/state_object.go b/core/state/state_object.go index aa748f08ac3c..d3d20c3dc481 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -459,22 +459,22 @@ func (s *stateObject) setBalance(amount *uint256.Int) { func (s *stateObject) deepCopy(db *StateDB) *stateObject { obj := &stateObject{ - db: db, - address: s.address, - addrHash: s.addrHash, - origin: s.origin, - data: s.data, + db: db, + address: s.address, + addrHash: s.addrHash, + origin: s.origin, + data: s.data, + code: s.code, + originStorage: s.originStorage.Copy(), + pendingStorage: s.pendingStorage.Copy(), + dirtyStorage: s.dirtyStorage.Copy(), + dirtyCode: s.dirtyCode, + selfDestructed: s.selfDestructed, + newContract: s.newContract, } if s.trie != nil { obj.trie = db.db.CopyTrie(s.trie) } - obj.code = s.code - obj.originStorage = s.originStorage.Copy() - obj.pendingStorage = s.pendingStorage.Copy() - obj.dirtyStorage = s.dirtyStorage.Copy() - obj.dirtyCode = s.dirtyCode - obj.selfDestructed = s.selfDestructed - obj.newContract = s.newContract return obj } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 1a3eccfe10b7..71d64f562898 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -21,9 +21,11 @@ import ( "encoding/binary" "errors" "fmt" + "maps" "math" "math/rand" "reflect" + "slices" "strings" "sync" "testing" @@ -557,10 +559,14 @@ func forEachStorage(s *StateDB, addr common.Address, cb func(key, value common.H if err != nil { return err } - it := trie.NewIterator(trieIt) + var ( + it = trie.NewIterator(trieIt) + visited = make(map[common.Hash]bool) + ) for it.Next() { key := common.BytesToHash(s.trie.GetKey(it.Key)) + visited[key] = true if value, dirty := so.dirtyStorage[key]; dirty { if !cb(key, value) { return nil @@ -600,6 +606,10 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) + // Check newContract-flag + if obj := state.getStateObject(addr); obj != nil { + checkeq("IsNewContract", obj.newContract, checkstate.getStateObject(addr).newContract) + } // Check storage. if obj := state.getStateObject(addr); obj != nil { forEachStorage(state, addr, func(key, value common.Hash) bool { @@ -608,12 +618,49 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { forEachStorage(checkstate, addr, func(key, value common.Hash) bool { return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) }) + other := checkstate.getStateObject(addr) + // Check dirty storage which is not in trie + if !maps.Equal(obj.dirtyStorage, other.dirtyStorage) { + print := func(dirty map[common.Hash]common.Hash) string { + var keys []common.Hash + out := new(strings.Builder) + for key := range dirty { + keys = append(keys, key) + } + slices.SortFunc(keys, common.Hash.Cmp) + for i, key := range keys { + fmt.Fprintf(out, " %d. %v %v\n", i, key, dirty[key]) + } + return out.String() + } + return fmt.Errorf("dirty storage err, have\n%v\nwant\n%v", + print(obj.dirtyStorage), + print(other.dirtyStorage)) + } + } + // Check transient storage. + { + have := state.transientStorage + want := checkstate.transientStorage + eq := maps.EqualFunc(have, want, + func(a Storage, b Storage) bool { + return maps.Equal(a, b) + }) + if !eq { + return fmt.Errorf("transient storage differs ,have\n%v\nwant\n%v", + have.PrettyPrint(), + want.PrettyPrint()) + } } if err != nil { return err } } - + if !checkstate.accessList.Equal(state.accessList) { // Check access lists + return fmt.Errorf("AccessLists are wrong, have \n%v\nwant\n%v", + checkstate.accessList.PrettyPrint(), + state.accessList.PrettyPrint()) + } if state.GetRefund() != checkstate.GetRefund() { return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", state.GetRefund(), checkstate.GetRefund()) @@ -622,6 +669,23 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) } + if !maps.Equal(state.journal.dirties, checkstate.journal.dirties) { + getKeys := func(dirty map[common.Address]int) string { + var keys []common.Address + out := new(strings.Builder) + for key := range dirty { + keys = append(keys, key) + } + slices.SortFunc(keys, common.Address.Cmp) + for i, key := range keys { + fmt.Fprintf(out, " %d. %v\n", i, key) + } + return out.String() + } + have := getKeys(state.journal.dirties) + want := getKeys(checkstate.journal.dirties) + return fmt.Errorf("dirty-journal set mismatch.\nhave:\n%v\nwant:\n%v\n", have, want) + } return nil } diff --git a/core/state/transient_storage.go b/core/state/transient_storage.go index 66e563efa732..e63db39ebab6 100644 --- a/core/state/transient_storage.go +++ b/core/state/transient_storage.go @@ -17,6 +17,10 @@ package state import ( + "fmt" + "slices" + "strings" + "github.com/ethereum/go-ethereum/common" ) @@ -30,10 +34,19 @@ func newTransientStorage() transientStorage { // Set sets the transient-storage `value` for `key` at the given `addr`. func (t transientStorage) Set(addr common.Address, key, value common.Hash) { - if _, ok := t[addr]; !ok { - t[addr] = make(Storage) + if value == (common.Hash{}) { // this is a 'delete' + if _, ok := t[addr]; ok { + delete(t[addr], key) + if len(t[addr]) == 0 { + delete(t, addr) + } + } + } else { + if _, ok := t[addr]; !ok { + t[addr] = make(Storage) + } + t[addr][key] = value } - t[addr][key] = value } // Get gets the transient storage for `key` at the given `addr`. @@ -53,3 +66,27 @@ func (t transientStorage) Copy() transientStorage { } return storage } + +// PrettyPrint prints the contents of the access list in a human-readable form +func (t transientStorage) PrettyPrint() string { + out := new(strings.Builder) + var sortedAddrs []common.Address + for addr := range t { + sortedAddrs = append(sortedAddrs, addr) + slices.SortFunc(sortedAddrs, common.Address.Cmp) + } + + for _, addr := range sortedAddrs { + fmt.Fprintf(out, "%#x:", addr) + var sortedKeys []common.Hash + storage := t[addr] + for key := range storage { + sortedKeys = append(sortedKeys, key) + } + slices.SortFunc(sortedKeys, common.Hash.Cmp) + for _, key := range sortedKeys { + fmt.Fprintf(out, " %X : %X\n", key, storage[key]) + } + } + return out.String() +} From 1f628d842c92cdfc85f260194078afad782fe824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 25 Apr 2024 11:50:25 +0300 Subject: [PATCH 218/571] build: build all the builders to build all the builders (#29647) * build: build all the builders to build all the builders * build: tweak the indexes a bit to make them consistent --- build/checksums.txt | 10 ++++---- build/ci.go | 45 +++++++++++++++++++++--------------- build/deb/ethereum/deb.rules | 5 ++-- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 27577285b821..767fc88ce59f 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -56,10 +56,12 @@ a5e68ae73d38748b5269fad36ac7575e3c162a5dc63ef58abdea03cc5da4522a golangci-lint- # This is the builder on PPA that will build Go itself (inception-y), don't modify! # # This version is fine to be old and full of security holes, we just use it -# to build the latest Go. Don't change it. If it ever becomes insufficient, -# we need to switch over to a recursive builder to jump across supported -# versions. +# to build the latest Go. Don't change it. # -# version:ppa-builder 1.19.6 +# version:ppa-builder-1 1.19.6 # https://go.dev/dl/ d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz + +# version:ppa-builder-2 1.21.9 +# https://go.dev/dl/ +58f0c5ced45a0012bce2ff7a9df03e128abcc8818ebabe5027bb92bafe20e421 go1.21.9.src.tar.gz diff --git a/build/ci.go b/build/ci.go index 4d8dba6ce234..abcc248ac5ff 100644 --- a/build/ci.go +++ b/build/ci.go @@ -694,8 +694,8 @@ func doDebianSource(cmdline []string) { } // Download and verify the Go source packages. var ( - gobootbundle = downloadGoBootstrapSources(*cachedir) - gobundle = downloadGoSources(*cachedir) + gobootbundles = downloadGoBootstrapSources(*cachedir) + gobundle = downloadGoSources(*cachedir) ) // Download all the dependencies needed to build the sources and run the ci script srcdepfetch := tc.Go("mod", "download") @@ -714,11 +714,13 @@ func doDebianSource(cmdline []string) { pkgdir := stageDebianSource(*workdir, meta) // Add bootstrapper Go source code - if err := build.ExtractArchive(gobootbundle, pkgdir); err != nil { - log.Fatalf("Failed to extract bootstrapper Go sources: %v", err) - } - if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, ".goboot")); err != nil { - log.Fatalf("Failed to rename bootstrapper Go source folder: %v", err) + for i, gobootbundle := range gobootbundles { + if err := build.ExtractArchive(gobootbundle, pkgdir); err != nil { + log.Fatalf("Failed to extract bootstrapper Go sources: %v", err) + } + if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, fmt.Sprintf(".goboot-%d", i+1))); err != nil { + log.Fatalf("Failed to rename bootstrapper Go source folder: %v", err) + } } // Add builder Go source code if err := build.ExtractArchive(gobundle, pkgdir); err != nil { @@ -754,21 +756,26 @@ func doDebianSource(cmdline []string) { } } -// downloadGoBootstrapSources downloads the Go source tarball that will be used +// downloadGoBootstrapSources downloads the Go source tarball(s) that will be used // to bootstrap the builder Go. -func downloadGoBootstrapSources(cachedir string) string { +func downloadGoBootstrapSources(cachedir string) []string { csdb := build.MustLoadChecksums("build/checksums.txt") - gobootVersion, err := build.Version(csdb, "ppa-builder") - if err != nil { - log.Fatal(err) - } - file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion) - url := "https://dl.google.com/go/" + file - dst := filepath.Join(cachedir, file) - if err := csdb.DownloadFile(url, dst); err != nil { - log.Fatal(err) + + var bundles []string + for _, booter := range []string{"ppa-builder-1", "ppa-builder-2"} { + gobootVersion, err := build.Version(csdb, booter) + if err != nil { + log.Fatal(err) + } + file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion) + url := "https://dl.google.com/go/" + file + dst := filepath.Join(cachedir, file) + if err := csdb.DownloadFile(url, dst); err != nil { + log.Fatal(err) + } + bundles = append(bundles, dst) } - return dst + return bundles } // downloadGoSources downloads the Go source tarball. diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index daca793e555f..cb48b23a5ef0 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -19,8 +19,9 @@ override_dh_auto_build: # # We're also shipping the bootstrapper as of Go 1.20 as it had minimum version # requirements opposed to older versions of Go. - (mv .goboot ../ && cd ../.goboot/src && ./make.bash) - (mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot ./make.bash) + (mv .goboot-1 ../ && cd ../.goboot-1/src && ./make.bash) + (mv .goboot-2 ../ && cd ../.goboot-2/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-1 ./make.bash) + (mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-2 ./make.bash) # We can't download external go modules within Launchpad, so we're shipping the # entire dependency source cache with go-ethereum. From a0282fc94f0a58f2e9a355c6a22a2ac8966d35ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 25 Apr 2024 12:00:59 +0300 Subject: [PATCH 219/571] travis: temporarilly enable PPA builds for testing (#29648) --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8c0af291a3df..c93ccd42251c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -123,7 +123,6 @@ jobs: # This builder does the Ubuntu PPA nightly uploads - stage: build - if: type = cron || (type = push && tag ~= /^v[0-9]/) os: linux dist: bionic go: 1.22.x From 634d03793787dad138c41a0fc92c2a6aa91a976e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 25 Apr 2024 12:27:36 +0300 Subject: [PATCH 220/571] travis: revert the PPA fix hot-build, it works (#29649) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c93ccd42251c..8c0af291a3df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -123,6 +123,7 @@ jobs: # This builder does the Ubuntu PPA nightly uploads - stage: build + if: type = cron || (type = push && tag ~= /^v[0-9]/) os: linux dist: bionic go: 1.22.x From ad4fb2c7291972a1940dbb276ed1b6f49906767c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 25 Apr 2024 14:07:39 +0300 Subject: [PATCH 221/571] build: drop trusty from PPA builds, EOL and incompatible (#29651) * build: drop trusty from PPA builds, EOL and incompatible * build: add Ubuntu Noble PPA build target --- build/ci.go | 51 +++++++++++++--------------------- build/deb/ethereum/deb.control | 2 +- build/deb/ethereum/deb.rules | 2 +- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/build/ci.go b/build/ci.go index abcc248ac5ff..9a2532f51f31 100644 --- a/build/ci.go +++ b/build/ci.go @@ -117,23 +117,15 @@ var ( debEthereum, } - // Distros for which packages are created. - // Note: vivid is unsupported because there is no golang-1.6 package for it. - // Note: the following Ubuntu releases have been officially deprecated on Launchpad: - // wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite, impish, - // kinetic, lunar - debDistroGoBoots = map[string]string{ - "trusty": "golang-1.11", // 14.04, EOL: 04/2024 - "xenial": "golang-go", // 16.04, EOL: 04/2026 - "bionic": "golang-go", // 18.04, EOL: 04/2028 - "focal": "golang-go", // 20.04, EOL: 04/2030 - "jammy": "golang-go", // 22.04, EOL: 04/2032 - "mantic": "golang-go", // 23.10, EOL: 07/2024 - } + // Distros for which packages are created + debDistros = []string{ + "xenial", // 16.04, EOL: 04/2026 + "bionic", // 18.04, EOL: 04/2028 + "focal", // 20.04, EOL: 04/2030 + "jammy", // 22.04, EOL: 04/2032 + "noble", // 24.04, EOL: 04/2034 - debGoBootPaths = map[string]string{ - "golang-1.11": "/usr/lib/go-1.11", - "golang-go": "/usr/lib/go", + "mantic", // 23.10, EOL: 07/2024 } // This is where the tests should be unpacked. @@ -708,9 +700,9 @@ func doDebianSource(cmdline []string) { // Create Debian packages and upload them. for _, pkg := range debPackages { - for distro, goboot := range debDistroGoBoots { + for _, distro := range debDistros { // Prepare the debian package with the go-ethereum sources. - meta := newDebMetadata(distro, goboot, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables) + meta := newDebMetadata(distro, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables) pkgdir := stageDebianSource(*workdir, meta) // Add bootstrapper Go source code @@ -853,10 +845,7 @@ type debPackage struct { } type debMetadata struct { - Env build.Environment - GoBootPackage string - GoBootPath string - + Env build.Environment PackageName string // go-ethereum version being built. Note that this @@ -884,21 +873,19 @@ func (d debExecutable) Package() string { return d.BinaryName } -func newDebMetadata(distro, goboot, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata { +func newDebMetadata(distro, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata { if author == "" { // No signing key, use default author. author = "Ethereum Builds " } return debMetadata{ - GoBootPackage: goboot, - GoBootPath: debGoBootPaths[goboot], - PackageName: name, - Env: env, - Author: author, - Distro: distro, - Version: version, - Time: t.Format(time.RFC1123Z), - Executables: exes, + PackageName: name, + Env: env, + Author: author, + Distro: distro, + Version: version, + Time: t.Format(time.RFC1123Z), + Executables: exes, } } diff --git a/build/deb/ethereum/deb.control b/build/deb/ethereum/deb.control index 3b759f2d042b..333e954c17db 100644 --- a/build/deb/ethereum/deb.control +++ b/build/deb/ethereum/deb.control @@ -2,7 +2,7 @@ Source: {{.Name}} Section: science Priority: extra Maintainer: {{.Author}} -Build-Depends: debhelper (>= 8.0.0), {{.GoBootPackage}} +Build-Depends: debhelper (>= 8.0.0), golang-go Standards-Version: 3.9.5 Homepage: https://ethereum.org Vcs-Git: https://github.com/ethereum/go-ethereum.git diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index cb48b23a5ef0..3287e15ff0f2 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -7,7 +7,7 @@ # Launchpad rejects Go's access to $HOME, use custom folders export GOCACHE=/tmp/go-build export GOPATH=/tmp/gopath -export GOROOT_BOOTSTRAP={{.GoBootPath}} +export GOROOT_BOOTSTRAP=/usr/lib/go override_dh_auto_clean: # Don't try to be smart Launchpad, we know our build rules better than you From 8d42e115b1cae4f09fd02b71c06ec9c85f22ad4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 26 Apr 2024 15:24:40 +0300 Subject: [PATCH 222/571] core/state: revert pending storage updates if they revert to original (#29661) --- core/state/state_object.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index d3d20c3dc481..14a1bd389f66 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/holiman/uint256" @@ -255,9 +256,16 @@ func (s *stateObject) setState(key common.Hash, value *common.Hash) { func (s *stateObject) finalise(prefetch bool) { slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage)) for key, value := range s.dirtyStorage { - s.pendingStorage[key] = value + // If the slot is different from its original value, move it into the + // pending area to be committed at the end of the block (and prefetch + // the pathways). if value != s.originStorage[key] { + s.pendingStorage[key] = value slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure + } else { + // Otherwise, the slot was reverted to its original value, remove it + // from the pending area to avoid thrashing the data strutures. + delete(s.pendingStorage, key) } } if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { @@ -371,6 +379,11 @@ func (s *stateObject) updateTrie() (Trie, error) { } s.db.StorageDeleted += 1 } + // If no slots were touched, issue a warning as we shouldn't have done all + // the above work in the first place + if len(usedStorage) == 0 { + log.Error("State object update was noop", "addr", s.address, "slots", len(s.pendingStorage)) + } if s.db.prefetcher != nil { s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage) } From 4253030ef67a2af2e59bbd1fd90a4c1e75939b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 26 Apr 2024 18:35:52 +0300 Subject: [PATCH 223/571] core/state: move metrics out of state objects (#29665) --- core/blockchain.go | 4 +--- core/state/state_object.go | 9 --------- core/state/statedb.go | 9 +++++++-- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index b45cd92e523d..e4c89668245f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -68,7 +68,6 @@ var ( accountCommitTimer = metrics.NewRegisteredResettingTimer("chain/account/commits", nil) storageReadTimer = metrics.NewRegisteredResettingTimer("chain/storage/reads", nil) - storageHashTimer = metrics.NewRegisteredResettingTimer("chain/storage/hashes", nil) storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil) storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil) @@ -1937,8 +1936,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) - storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation) - triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing + triehash := statedb.AccountHashes // The time spent on tries hashing trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read diff --git a/core/state/state_object.go b/core/state/state_object.go index 14a1bd389f66..1454f7a459a5 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -294,9 +294,6 @@ func (s *stateObject) updateTrie() (Trie, error) { if len(s.pendingStorage) == 0 { return s.trie, nil } - // Track the amount of time wasted on updating the storage trie - defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) - // The snapshot storage map for the object var ( storage map[common.Hash][]byte @@ -400,9 +397,6 @@ func (s *stateObject) updateRoot() { if err != nil || tr == nil { return } - // Track the amount of time wasted on hashing the storage trie - defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) - s.data.Root = tr.Hash() } @@ -415,9 +409,6 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) { s.origin = s.data.Copy() return nil, nil } - // Track the amount of time wasted on committing the storage trie - defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) - // The trie is currently in an open state and could potentially contain // cached mutations. Call commit to acquire a set of nodes that have been // modified, the set can be nil if nothing to commit. diff --git a/core/state/statedb.go b/core/state/statedb.go index 4a934fe82cdf..6d9cc907e03f 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -151,7 +151,6 @@ type StateDB struct { AccountUpdates time.Duration AccountCommits time.Duration StorageReads time.Duration - StorageHashes time.Duration StorageUpdates time.Duration StorageCommits time.Duration SnapshotAccountReads time.Duration @@ -856,6 +855,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // the account prefetcher. Instead, let's process all the storage updates // first, giving the account prefetches just a few more milliseconds of time // to pull useful data from disk. + start := time.Now() for addr, op := range s.mutations { if op.applied { continue @@ -865,6 +865,8 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } s.stateObjects[addr].updateRoot() } + s.StorageUpdates += time.Since(start) + // Now we're about to start to write changes to the trie. The trie is so far // _untouched_. We can check with the prefetcher, if it can give us a trie // which has the same root, but also has some content loaded into it. @@ -1151,6 +1153,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er return common.Hash{}, err } // Handle all state updates afterwards + start := time.Now() for addr, op := range s.mutations { if op.isDelete() { continue @@ -1179,13 +1182,15 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er storageTrieNodesDeleted += deleted } } + s.StorageCommits += time.Since(start) + if codeWriter.ValueSize() > 0 { if err := codeWriter.Write(); err != nil { log.Crit("Failed to commit dirty codes", "error", err) } } // Write the account trie changes, measuring the amount of wasted time - start := time.Now() + start = time.Now() root, set, err := s.trie.Commit(true) if err != nil { From 4bdbaab471d2566c9f267b8372ed18c2af6646ee Mon Sep 17 00:00:00 2001 From: Roy Crihfield Date: Sun, 28 Apr 2024 19:03:03 +0800 Subject: [PATCH 224/571] params: clarify consensus engine config `String`s (#29643) Define these on a value receiever so that nil is shown differently. --- params/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/params/config.go b/params/config.go index 439e88218924..486cb6d132b1 100644 --- a/params/config.go +++ b/params/config.go @@ -374,7 +374,7 @@ type ChainConfig struct { type EthashConfig struct{} // String implements the stringer interface, returning the consensus engine details. -func (c *EthashConfig) String() string { +func (c EthashConfig) String() string { return "ethash" } @@ -385,8 +385,8 @@ type CliqueConfig struct { } // String implements the stringer interface, returning the consensus engine details. -func (c *CliqueConfig) String() string { - return "clique" +func (c CliqueConfig) String() string { + return fmt.Sprintf("clique(period: %d, epoch: %d)", c.Period, c.Epoch) } // Description returns a human-readable description of ChainConfig. From 8c3fc56d7f980d8e200918c956f2bc424d59d305 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Tue, 30 Apr 2024 01:44:41 +0800 Subject: [PATCH 225/571] p2p/simulations/adapters: use maps.Clone (#29626) --- p2p/simulations/adapters/inproc.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/p2p/simulations/adapters/inproc.go b/p2p/simulations/adapters/inproc.go index 349e496b2f68..0efe9744a5c1 100644 --- a/p2p/simulations/adapters/inproc.go +++ b/p2p/simulations/adapters/inproc.go @@ -20,6 +20,7 @@ import ( "context" "errors" "fmt" + "maps" "math" "net" "sync" @@ -215,10 +216,7 @@ func (sn *SimNode) ServeRPC(conn *websocket.Conn) error { // simulation_snapshot RPC method func (sn *SimNode) Snapshots() (map[string][]byte, error) { sn.lock.RLock() - services := make(map[string]node.Lifecycle, len(sn.running)) - for name, service := range sn.running { - services[name] = service - } + services := maps.Clone(sn.running) sn.lock.RUnlock() if len(services) == 0 { return nil, errors.New("no running services") @@ -315,11 +313,7 @@ func (sn *SimNode) Services() []node.Lifecycle { func (sn *SimNode) ServiceMap() map[string]node.Lifecycle { sn.lock.RLock() defer sn.lock.RUnlock() - services := make(map[string]node.Lifecycle, len(sn.running)) - for name, service := range sn.running { - services[name] = service - } - return services + return maps.Clone(sn.running) } // Server returns the underlying p2p.Server From fecc8a0f4a5b4f42825ccc1628d069e6eceaba49 Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 30 Apr 2024 17:19:59 +0800 Subject: [PATCH 226/571] cmd/evm/internal/t8ntool, core: prealloc map sizes where possible (#29620) set cap for map in a certain scenario --- cmd/evm/internal/t8ntool/transition.go | 2 +- core/blockchain.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 2b5eaa65aae1..9ea94d195e82 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -296,7 +296,7 @@ func (g Alloc) OnAccount(addr *common.Address, dumpAccount state.DumpAccount) { balance, _ := new(big.Int).SetString(dumpAccount.Balance, 0) var storage map[common.Hash]common.Hash if dumpAccount.Storage != nil { - storage = make(map[common.Hash]common.Hash) + storage = make(map[common.Hash]common.Hash, len(dumpAccount.Storage)) for k, v := range dumpAccount.Storage { storage[k] = common.HexToHash(v) } diff --git a/core/blockchain.go b/core/blockchain.go index e4c89668245f..9de4baccca75 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1309,7 +1309,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ // Delete block data from the main database. var ( batch = bc.db.NewBatch() - canonHashes = make(map[common.Hash]struct{}) + canonHashes = make(map[common.Hash]struct{}, len(blockChain)) ) for _, block := range blockChain { canonHashes[block.Hash()] = struct{}{} From 69f815f6f5791e0e48160bdad284773d0ffb1ba9 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 30 Apr 2024 17:22:02 +0800 Subject: [PATCH 227/571] params: print time value instead of pointer in ConfigCompatError (#29514) --- params/config.go | 12 ++++++++++-- params/config_test.go | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/params/config.go b/params/config.go index 486cb6d132b1..62acaddaadd2 100644 --- a/params/config.go +++ b/params/config.go @@ -880,7 +880,7 @@ func newTimestampCompatError(what string, storedtime, newtime *uint64) *ConfigCo NewTime: newtime, RewindToTime: 0, } - if rew != nil { + if rew != nil && *rew != 0 { err.RewindToTime = *rew - 1 } return err @@ -890,7 +890,15 @@ func (err *ConfigCompatError) Error() string { if err.StoredBlock != nil { return fmt.Sprintf("mismatching %s in database (have block %d, want block %d, rewindto block %d)", err.What, err.StoredBlock, err.NewBlock, err.RewindToBlock) } - return fmt.Sprintf("mismatching %s in database (have timestamp %d, want timestamp %d, rewindto timestamp %d)", err.What, err.StoredTime, err.NewTime, err.RewindToTime) + + if err.StoredTime == nil && err.NewTime == nil { + return "" + } else if err.StoredTime == nil && err.NewTime != nil { + return fmt.Sprintf("mismatching %s in database (have timestamp nil, want timestamp %d, rewindto timestamp %d)", err.What, *err.NewTime, err.RewindToTime) + } else if err.StoredTime != nil && err.NewTime == nil { + return fmt.Sprintf("mismatching %s in database (have timestamp %d, want timestamp nil, rewindto timestamp %d)", err.What, *err.StoredTime, err.RewindToTime) + } + return fmt.Sprintf("mismatching %s in database (have timestamp %d, want timestamp %d, rewindto timestamp %d)", err.What, *err.StoredTime, *err.NewTime, err.RewindToTime) } // Rules wraps ChainConfig and is merely syntactic sugar or can be used for functions diff --git a/params/config_test.go b/params/config_test.go index bf8ce2fc5e24..fa444a1d0b76 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common/math" + "github.com/stretchr/testify/require" ) func TestCheckCompatible(t *testing.T) { @@ -137,3 +138,20 @@ func TestConfigRules(t *testing.T) { t.Errorf("expected %v to be shanghai", stamp) } } + +func TestTimestampCompatError(t *testing.T) { + require.Equal(t, new(ConfigCompatError).Error(), "") + + errWhat := "Shanghai fork timestamp" + require.Equal(t, newTimestampCompatError(errWhat, nil, newUint64(1681338455)).Error(), + "mismatching Shanghai fork timestamp in database (have timestamp nil, want timestamp 1681338455, rewindto timestamp 1681338454)") + + require.Equal(t, newTimestampCompatError(errWhat, newUint64(1681338455), nil).Error(), + "mismatching Shanghai fork timestamp in database (have timestamp 1681338455, want timestamp nil, rewindto timestamp 1681338454)") + + require.Equal(t, newTimestampCompatError(errWhat, newUint64(1681338455), newUint64(600624000)).Error(), + "mismatching Shanghai fork timestamp in database (have timestamp 1681338455, want timestamp 600624000, rewindto timestamp 600623999)") + + require.Equal(t, newTimestampCompatError(errWhat, newUint64(0), newUint64(1681338455)).Error(), + "mismatching Shanghai fork timestamp in database (have timestamp 0, want timestamp 1681338455, rewindto timestamp 0)") +} From c04b8e6d74fe6d1c1f9a96e6269d51e47124d6f1 Mon Sep 17 00:00:00 2001 From: felipe Date: Tue, 30 Apr 2024 03:22:57 -0600 Subject: [PATCH 228/571] cmd/utils: require TTD and difficulty to be zero at genesis for dev mode (#29579) --- cmd/utils/flags.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index e1c33678be37..ecf6acc18606 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1872,13 +1872,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { Fatalf("Could not read genesis from database: %v", err) } if !genesis.Config.TerminalTotalDifficultyPassed { - Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficultyPassed must be true in developer mode") + Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficultyPassed must be true") } if genesis.Config.TerminalTotalDifficulty == nil { - Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficulty must be specified.") + Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficulty must be specified") + } else if genesis.Config.TerminalTotalDifficulty.Cmp(big.NewInt(0)) != 0 { + Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficulty must be 0") } - if genesis.Difficulty.Cmp(genesis.Config.TerminalTotalDifficulty) != 1 { - Fatalf("Bad developer-mode genesis configuration: genesis block difficulty must be > terminalTotalDifficulty") + if genesis.Difficulty.Cmp(big.NewInt(0)) != 0 { + Fatalf("Bad developer-mode genesis configuration: difficulty must be 0") } } chaindb.Close() From f46c878441e2e567e8815f1e252a38ad0ffafbc2 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 30 Apr 2024 17:33:22 +0800 Subject: [PATCH 229/571] core/rawdb: implement in-memory freezer (#29135) --- core/rawdb/ancient_scheme.go | 20 +- core/rawdb/ancienttest/testsuite.go | 325 +++++++++++++++++++ core/rawdb/chain_freezer.go | 40 ++- core/rawdb/database.go | 27 +- core/rawdb/freezer.go | 8 +- core/rawdb/freezer_memory.go | 428 ++++++++++++++++++++++++++ core/rawdb/freezer_memory_test.go | 41 +++ core/rawdb/freezer_resettable.go | 38 +-- core/rawdb/freezer_resettable_test.go | 6 +- core/rawdb/freezer_test.go | 20 ++ ethdb/database.go | 30 +- node/node.go | 3 +- triedb/pathdb/database.go | 110 ++++--- triedb/pathdb/history.go | 40 +-- triedb/pathdb/history_inspect.go | 12 +- triedb/pathdb/history_test.go | 17 +- 16 files changed, 1014 insertions(+), 151 deletions(-) create mode 100644 core/rawdb/ancienttest/testsuite.go create mode 100644 core/rawdb/freezer_memory.go create mode 100644 core/rawdb/freezer_memory_test.go diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index e88867af0e64..44867ded04ab 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -16,7 +16,11 @@ package rawdb -import "path/filepath" +import ( + "path/filepath" + + "github.com/ethereum/go-ethereum/ethdb" +) // The list of table names of chain freezer. const ( @@ -75,7 +79,15 @@ var ( // freezers the collections of all builtin freezers. var freezers = []string{ChainFreezerName, StateFreezerName} -// NewStateFreezer initializes the freezer for state history. -func NewStateFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) { - return NewResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy) +// NewStateFreezer initializes the ancient store for state history. +// +// - if the empty directory is given, initializes the pure in-memory +// state freezer (e.g. dev mode). +// - if non-empty directory is given, initializes the regular file-based +// state freezer. +func NewStateFreezer(ancientDir string, readOnly bool) (ethdb.ResettableAncientStore, error) { + if ancientDir == "" { + return NewMemoryFreezer(readOnly, stateFreezerNoSnappy), nil + } + return newResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy) } diff --git a/core/rawdb/ancienttest/testsuite.go b/core/rawdb/ancienttest/testsuite.go new file mode 100644 index 000000000000..70de263c0435 --- /dev/null +++ b/core/rawdb/ancienttest/testsuite.go @@ -0,0 +1,325 @@ +// Copyright 2024 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 ancienttest + +import ( + "bytes" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/testrand" +) + +// TestAncientSuite runs a suite of tests against an ancient database +// implementation. +func TestAncientSuite(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) { + // Test basic read methods + t.Run("BasicRead", func(t *testing.T) { basicRead(t, newFn) }) + + // Test batch read method + t.Run("BatchRead", func(t *testing.T) { batchRead(t, newFn) }) + + // Test basic write methods + t.Run("BasicWrite", func(t *testing.T) { basicWrite(t, newFn) }) + + // Test if data mutation is allowed after db write + t.Run("nonMutable", func(t *testing.T) { nonMutable(t, newFn) }) +} + +func basicRead(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) { + var ( + db = newFn([]string{"a"}) + data = makeDataset(100, 32) + ) + defer db.Close() + + db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for i := 0; i < len(data); i++ { + op.AppendRaw("a", uint64(i), data[i]) + } + return nil + }) + db.TruncateTail(10) + db.TruncateHead(90) + + // Test basic tail and head retrievals + tail, err := db.Tail() + if err != nil || tail != 10 { + t.Fatal("Failed to retrieve tail") + } + ancient, err := db.Ancients() + if err != nil || ancient != 90 { + t.Fatal("Failed to retrieve ancient") + } + + // Test the deleted items shouldn't be reachable + var cases = []struct { + start int + limit int + }{ + {0, 10}, + {90, 100}, + } + for _, c := range cases { + for i := c.start; i < c.limit; i++ { + exist, err := db.HasAncient("a", uint64(i)) + if err != nil { + t.Fatalf("Failed to check presence, %v", err) + } + if exist { + t.Fatalf("Item %d is already truncated", uint64(i)) + } + _, err = db.Ancient("a", uint64(i)) + if err == nil { + t.Fatal("Error is expected for non-existent item") + } + } + } + + // Test the items in range should be reachable + for i := 10; i < 90; i++ { + exist, err := db.HasAncient("a", uint64(i)) + if err != nil { + t.Fatalf("Failed to check presence, %v", err) + } + if !exist { + t.Fatalf("Item %d is missing", uint64(i)) + } + blob, err := db.Ancient("a", uint64(i)) + if err != nil { + t.Fatalf("Failed to retrieve item, %v", err) + } + if !bytes.Equal(blob, data[i]) { + t.Fatalf("Unexpected item content, want: %v, got: %v", data[i], blob) + } + } + + // Test the items in unknown table shouldn't be reachable + exist, err := db.HasAncient("b", uint64(0)) + if err != nil { + t.Fatalf("Failed to check presence, %v", err) + } + if exist { + t.Fatal("Item in unknown table shouldn't be found") + } + _, err = db.Ancient("b", uint64(0)) + if err == nil { + t.Fatal("Error is expected for unknown table") + } +} + +func batchRead(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) { + var ( + db = newFn([]string{"a"}) + data = makeDataset(100, 32) + ) + defer db.Close() + + db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for i := 0; i < 100; i++ { + op.AppendRaw("a", uint64(i), data[i]) + } + return nil + }) + db.TruncateTail(10) + db.TruncateHead(90) + + // Test the items in range should be reachable + var cases = []struct { + start uint64 + count uint64 + maxSize uint64 + expStart int + expLimit int + }{ + // Items in range [10, 90) with no size limitation + { + 10, 80, 0, 10, 90, + }, + // Items in range [10, 90) with 32 size cap, single item is expected + { + 10, 80, 32, 10, 11, + }, + // Items in range [10, 90) with 31 size cap, single item is expected + { + 10, 80, 31, 10, 11, + }, + // Items in range [10, 90) with 32*80 size cap, all items are expected + { + 10, 80, 32 * 80, 10, 90, + }, + // Extra items above the last item are not returned + { + 10, 90, 0, 10, 90, + }, + } + for i, c := range cases { + batch, err := db.AncientRange("a", c.start, c.count, c.maxSize) + if err != nil { + t.Fatalf("Failed to retrieve item in range, %v", err) + } + if !reflect.DeepEqual(batch, data[c.expStart:c.expLimit]) { + t.Fatalf("Case %d, Batch content is not matched", i) + } + } + + // Test out-of-range / zero-size retrieval should be rejected + _, err := db.AncientRange("a", 0, 1, 0) + if err == nil { + t.Fatal("Out-of-range retrieval should be rejected") + } + _, err = db.AncientRange("a", 90, 1, 0) + if err == nil { + t.Fatal("Out-of-range retrieval should be rejected") + } + _, err = db.AncientRange("a", 10, 0, 0) + if err == nil { + t.Fatal("Zero-size retrieval should be rejected") + } + + // Test item in unknown table shouldn't be reachable + _, err = db.AncientRange("b", 10, 1, 0) + if err == nil { + t.Fatal("Item in unknown table shouldn't be found") + } +} + +func basicWrite(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) { + var ( + db = newFn([]string{"a", "b"}) + dataA = makeDataset(100, 32) + dataB = makeDataset(100, 32) + ) + defer db.Close() + + // The ancient write to tables should be aligned + _, err := db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for i := 0; i < 100; i++ { + op.AppendRaw("a", uint64(i), dataA[i]) + } + return nil + }) + if err == nil { + t.Fatal("Unaligned ancient write should be rejected") + } + + // Test normal ancient write + size, err := db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for i := 0; i < 100; i++ { + op.AppendRaw("a", uint64(i), dataA[i]) + op.AppendRaw("b", uint64(i), dataB[i]) + } + return nil + }) + if err != nil { + t.Fatalf("Failed to write ancient data %v", err) + } + wantSize := int64(6400) + if size != wantSize { + t.Fatalf("Ancient write size is not expected, want: %d, got: %d", wantSize, size) + } + + // Write should work after head truncating + db.TruncateHead(90) + _, err = db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for i := 90; i < 100; i++ { + op.AppendRaw("a", uint64(i), dataA[i]) + op.AppendRaw("b", uint64(i), dataB[i]) + } + return nil + }) + if err != nil { + t.Fatalf("Failed to write ancient data %v", err) + } + + // Write should work after truncating everything + db.TruncateTail(0) + _, err = db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for i := 0; i < 100; i++ { + op.AppendRaw("a", uint64(i), dataA[i]) + op.AppendRaw("b", uint64(i), dataB[i]) + } + return nil + }) + if err != nil { + t.Fatalf("Failed to write ancient data %v", err) + } +} + +func nonMutable(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) { + db := newFn([]string{"a"}) + defer db.Close() + + // We write 100 zero-bytes to the freezer and immediately mutate the slice + db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + data := make([]byte, 100) + op.AppendRaw("a", uint64(0), data) + for i := range data { + data[i] = 0xff + } + return nil + }) + // Now read it. + data, err := db.Ancient("a", uint64(0)) + if err != nil { + t.Fatal(err) + } + for k, v := range data { + if v != 0 { + t.Fatalf("byte %d != 0: %x", k, v) + } + } +} + +// TestResettableAncientSuite runs a suite of tests against a resettable ancient +// database implementation. +func TestResettableAncientSuite(t *testing.T, newFn func(kinds []string) ethdb.ResettableAncientStore) { + t.Run("Reset", func(t *testing.T) { + var ( + db = newFn([]string{"a"}) + data = makeDataset(100, 32) + ) + defer db.Close() + + db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for i := 0; i < 100; i++ { + op.AppendRaw("a", uint64(i), data[i]) + } + return nil + }) + db.TruncateTail(10) + db.TruncateHead(90) + + // Ancient write should work after resetting + db.Reset() + db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for i := 0; i < 100; i++ { + op.AppendRaw("a", uint64(i), data[i]) + } + return nil + }) + }) +} + +func makeDataset(size, value int) [][]byte { + var vals [][]byte + for i := 0; i < size; i += 1 { + vals = append(vals, testrand.Bytes(value)) + } + return vals +} diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index d8214874bdb8..7a0b819b6fa0 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -39,26 +39,40 @@ const ( freezerBatchLimit = 30000 ) -// chainFreezer is a wrapper of freezer with additional chain freezing feature. -// The background thread will keep moving ancient chain segments from key-value -// database to flat files for saving space on live database. +// chainFreezer is a wrapper of chain ancient store with additional chain freezing +// feature. The background thread will keep moving ancient chain segments from +// key-value database to flat files for saving space on live database. type chainFreezer struct { - *Freezer + ethdb.AncientStore // Ancient store for storing cold chain segment + quit chan struct{} wg sync.WaitGroup trigger chan chan struct{} // Manual blocking freeze trigger, test determinism } -// newChainFreezer initializes the freezer for ancient chain data. +// newChainFreezer initializes the freezer for ancient chain segment. +// +// - if the empty directory is given, initializes the pure in-memory +// state freezer (e.g. dev mode). +// - if non-empty directory is given, initializes the regular file-based +// state freezer. func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFreezer, error) { - freezer, err := NewChainFreezer(datadir, namespace, readonly) + var ( + err error + freezer ethdb.AncientStore + ) + if datadir == "" { + freezer = NewMemoryFreezer(readonly, chainFreezerNoSnappy) + } else { + freezer, err = NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy) + } if err != nil { return nil, err } return &chainFreezer{ - Freezer: freezer, - quit: make(chan struct{}), - trigger: make(chan chan struct{}), + AncientStore: freezer, + quit: make(chan struct{}), + trigger: make(chan chan struct{}), }, nil } @@ -70,7 +84,7 @@ func (f *chainFreezer) Close() error { close(f.quit) } f.wg.Wait() - return f.Freezer.Close() + return f.AncientStore.Close() } // readHeadNumber returns the number of chain head block. 0 is returned if the @@ -167,7 +181,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { log.Debug("Current full block not old enough to freeze", "err", err) continue } - frozen := f.frozen.Load() + frozen, _ := f.Ancients() // no error will occur, safe to ignore // Short circuit if the blocks below threshold are already frozen. if frozen != 0 && frozen-1 >= threshold { @@ -190,7 +204,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { backoff = true continue } - // Batch of blocks have been frozen, flush them before wiping from leveldb + // Batch of blocks have been frozen, flush them before wiping from key-value store if err := f.Sync(); err != nil { log.Crit("Failed to flush frozen tables", "err", err) } @@ -210,7 +224,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { // Wipe out side chains also and track dangling side chains var dangling []common.Hash - frozen = f.frozen.Load() // Needs reload after during freezeRange + frozen, _ = f.Ancients() // Needs reload after during freezeRange for number := first; number < frozen; number++ { // Always keep the genesis block in active database if number != 0 { diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 7b2c0415cbbf..0a9f6f73c76b 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -34,11 +34,13 @@ import ( "github.com/olekukonko/tablewriter" ) -// freezerdb is a database wrapper that enables freezer data retrievals. +// freezerdb is a database wrapper that enables ancient chain segment freezing. type freezerdb struct { - ancientRoot string ethdb.KeyValueStore - ethdb.AncientStore + *chainFreezer + + readOnly bool + ancientRoot string } // AncientDatadir returns the path of root ancient directory. @@ -50,7 +52,7 @@ func (frdb *freezerdb) AncientDatadir() (string, error) { // the slow ancient tables. func (frdb *freezerdb) Close() error { var errs []error - if err := frdb.AncientStore.Close(); err != nil { + if err := frdb.chainFreezer.Close(); err != nil { errs = append(errs, err) } if err := frdb.KeyValueStore.Close(); err != nil { @@ -66,12 +68,12 @@ func (frdb *freezerdb) Close() error { // a freeze cycle completes, without having to sleep for a minute to trigger the // automatic background run. func (frdb *freezerdb) Freeze() error { - if frdb.AncientStore.(*chainFreezer).readonly { + if frdb.readOnly { return errReadOnly } // Trigger a freeze cycle and block until it's done trigger := make(chan struct{}, 1) - frdb.AncientStore.(*chainFreezer).trigger <- trigger + frdb.chainFreezer.trigger <- trigger <-trigger return nil } @@ -192,8 +194,13 @@ func resolveChainFreezerDir(ancient string) string { // storage. The passed ancient indicates the path of root ancient directory // where the chain freezer can be opened. func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace string, readonly bool) (ethdb.Database, error) { - // Create the idle freezer instance - frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly) + // Create the idle freezer instance. If the given ancient directory is empty, + // in-memory chain freezer is used (e.g. dev mode); otherwise the regular + // file-based freezer is created. + if ancient != "" { + ancient = resolveChainFreezerDir(ancient) + } + frdb, err := newChainFreezer(ancient, namespace, readonly) if err != nil { printChainMetadata(db) return nil, err @@ -277,7 +284,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st } } // Freezer is consistent with the key-value database, permit combining the two - if !frdb.readonly { + if !readonly { frdb.wg.Add(1) go func() { frdb.freeze(db) @@ -287,7 +294,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st return &freezerdb{ ancientRoot: ancient, KeyValueStore: db, - AncientStore: frdb, + chainFreezer: frdb, }, nil } diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index b7824ddc0d2c..0f28782db9ee 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -62,7 +62,7 @@ const freezerTableSize = 2 * 1000 * 1000 * 1000 // reserving it for go-ethereum. This would also reduce the memory requirements // of Geth, and thus also GC overhead. type Freezer struct { - frozen atomic.Uint64 // Number of blocks already frozen + frozen atomic.Uint64 // Number of items already frozen tail atomic.Uint64 // Number of the first stored item in the freezer // This lock synchronizes writers and the truncate operation, as well as @@ -76,12 +76,6 @@ type Freezer struct { closeOnce sync.Once } -// NewChainFreezer is a small utility method around NewFreezer that sets the -// default parameters for the chain storage. -func NewChainFreezer(datadir string, namespace string, readonly bool) (*Freezer, error) { - return NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy) -} - // NewFreezer creates a freezer instance for maintaining immutable ordered // data according to the given parameters. // diff --git a/core/rawdb/freezer_memory.go b/core/rawdb/freezer_memory.go new file mode 100644 index 000000000000..954b58e8747b --- /dev/null +++ b/core/rawdb/freezer_memory.go @@ -0,0 +1,428 @@ +// Copyright 2024 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" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" +) + +// memoryTable is used to store a list of sequential items in memory. +type memoryTable struct { + name string // Table name + items uint64 // Number of stored items in the table, including the deleted ones + offset uint64 // Number of deleted items from the table + data [][]byte // List of rlp-encoded items, sort in order + size uint64 // Total memory size occupied by the table + lock sync.RWMutex +} + +// newMemoryTable initializes the memory table. +func newMemoryTable(name string) *memoryTable { + return &memoryTable{name: name} +} + +// has returns an indicator whether the specified data exists. +func (t *memoryTable) has(number uint64) bool { + t.lock.RLock() + defer t.lock.RUnlock() + + return number >= t.offset && number < t.items +} + +// retrieve retrieves multiple items in sequence, starting from the index 'start'. +// It will return: +// - at most 'count' items, +// - if maxBytes is specified: at least 1 item (even if exceeding the maxByteSize), +// but will otherwise return as many items as fit into maxByteSize. +// - if maxBytes is not specified, 'count' items will be returned if they are present +func (t *memoryTable) retrieve(start uint64, count, maxBytes uint64) ([][]byte, error) { + t.lock.RLock() + defer t.lock.RUnlock() + + var ( + size uint64 + batch [][]byte + ) + // Ensure the start is written, not deleted from the tail, and that the + // caller actually wants something. + if t.items <= start || t.offset > start || count == 0 { + return nil, errOutOfBounds + } + // Cap the item count if the retrieval is out of bound. + if start+count > t.items { + count = t.items - start + } + for n := start; n < start+count; n++ { + index := n - t.offset + if len(batch) != 0 && maxBytes != 0 && size+uint64(len(t.data[index])) > maxBytes { + return batch, nil + } + batch = append(batch, t.data[index]) + size += uint64(len(t.data[index])) + } + return batch, nil +} + +// truncateHead discards any recent data above the provided threshold number. +func (t *memoryTable) truncateHead(items uint64) error { + t.lock.Lock() + defer t.lock.Unlock() + + // Short circuit if nothing to delete. + if t.items <= items { + return nil + } + if items < t.offset { + return errors.New("truncation below tail") + } + t.data = t.data[:items-t.offset] + t.items = items + return nil +} + +// truncateTail discards any recent data before the provided threshold number. +func (t *memoryTable) truncateTail(items uint64) error { + t.lock.Lock() + defer t.lock.Unlock() + + // Short circuit if nothing to delete. + if t.offset >= items { + return nil + } + if t.items < items { + return errors.New("truncation above head") + } + t.data = t.data[items-t.offset:] + t.offset = items + return nil +} + +// commit merges the given item batch into table. It's presumed that the +// batch is ordered and continuous with table. +func (t *memoryTable) commit(batch [][]byte) error { + t.lock.Lock() + defer t.lock.Unlock() + + for _, item := range batch { + t.size += uint64(len(item)) + } + t.data = append(t.data, batch...) + t.items += uint64(len(batch)) + return nil +} + +// memoryBatch is the singleton batch used for ancient write. +type memoryBatch struct { + data map[string][][]byte + next map[string]uint64 + size map[string]int64 +} + +func newMemoryBatch() *memoryBatch { + return &memoryBatch{ + data: make(map[string][][]byte), + next: make(map[string]uint64), + size: make(map[string]int64), + } +} + +func (b *memoryBatch) reset(freezer *MemoryFreezer) { + b.data = make(map[string][][]byte) + b.next = make(map[string]uint64) + b.size = make(map[string]int64) + + for name, table := range freezer.tables { + b.next[name] = table.items + } +} + +// Append adds an RLP-encoded item. +func (b *memoryBatch) Append(kind string, number uint64, item interface{}) error { + if b.next[kind] != number { + return errOutOrderInsertion + } + blob, err := rlp.EncodeToBytes(item) + if err != nil { + return err + } + b.data[kind] = append(b.data[kind], blob) + b.next[kind]++ + b.size[kind] += int64(len(blob)) + return nil +} + +// AppendRaw adds an item without RLP-encoding it. +func (b *memoryBatch) AppendRaw(kind string, number uint64, blob []byte) error { + if b.next[kind] != number { + return errOutOrderInsertion + } + b.data[kind] = append(b.data[kind], common.CopyBytes(blob)) + b.next[kind]++ + b.size[kind] += int64(len(blob)) + return nil +} + +// commit is called at the end of a write operation and writes all remaining +// data to tables. +func (b *memoryBatch) commit(freezer *MemoryFreezer) (items uint64, writeSize int64, err error) { + // Check that count agrees on all batches. + items = math.MaxUint64 + for name, next := range b.next { + if items < math.MaxUint64 && next != items { + return 0, 0, fmt.Errorf("table %s is at item %d, want %d", name, next, items) + } + items = next + } + // Commit all table batches. + for name, batch := range b.data { + table := freezer.tables[name] + if err := table.commit(batch); err != nil { + return 0, 0, err + } + writeSize += b.size[name] + } + return items, writeSize, nil +} + +// MemoryFreezer is an ephemeral ancient store. It implements the ethdb.AncientStore +// interface and can be used along with ephemeral key-value store. +type MemoryFreezer struct { + items uint64 // Number of items stored + tail uint64 // Number of the first stored item in the freezer + readonly bool // Flag if the freezer is only for reading + lock sync.RWMutex // Lock to protect fields + tables map[string]*memoryTable // Tables for storing everything + writeBatch *memoryBatch // Pre-allocated write batch +} + +// NewMemoryFreezer initializes an in-memory freezer instance. +func NewMemoryFreezer(readonly bool, tableName map[string]bool) *MemoryFreezer { + tables := make(map[string]*memoryTable) + for name := range tableName { + tables[name] = newMemoryTable(name) + } + return &MemoryFreezer{ + writeBatch: newMemoryBatch(), + readonly: readonly, + tables: tables, + } +} + +// HasAncient returns an indicator whether the specified data exists. +func (f *MemoryFreezer) HasAncient(kind string, number uint64) (bool, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + if table := f.tables[kind]; table != nil { + return table.has(number), nil + } + return false, nil +} + +// Ancient retrieves an ancient binary blob from the in-memory freezer. +func (f *MemoryFreezer) Ancient(kind string, number uint64) ([]byte, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + t := f.tables[kind] + if t == nil { + return nil, errUnknownTable + } + data, err := t.retrieve(number, 1, 0) + if err != nil { + return nil, err + } + return data[0], nil +} + +// AncientRange retrieves multiple items in sequence, starting from the index 'start'. +// It will return +// - at most 'count' items, +// - if maxBytes is specified: at least 1 item (even if exceeding the maxByteSize), +// but will otherwise return as many items as fit into maxByteSize. +// - if maxBytes is not specified, 'count' items will be returned if they are present +func (f *MemoryFreezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + t := f.tables[kind] + if t == nil { + return nil, errUnknownTable + } + return t.retrieve(start, count, maxBytes) +} + +// Ancients returns the ancient item numbers in the freezer. +func (f *MemoryFreezer) Ancients() (uint64, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.items, nil +} + +// Tail returns the number of first stored item in the freezer. +// This number can also be interpreted as the total deleted item numbers. +func (f *MemoryFreezer) Tail() (uint64, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.tail, nil +} + +// AncientSize returns the ancient size of the specified category. +func (f *MemoryFreezer) AncientSize(kind string) (uint64, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + if table := f.tables[kind]; table != nil { + return table.size, nil + } + return 0, errUnknownTable +} + +// ReadAncients runs the given read operation while ensuring that no writes take place +// on the underlying freezer. +func (f *MemoryFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return fn(f) +} + +// ModifyAncients runs the given write operation. +func (f *MemoryFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize int64, err error) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.readonly { + return 0, errReadOnly + } + // Roll back all tables to the starting position in case of error. + defer func(old uint64) { + if err == nil { + return + } + // The write operation has failed. Go back to the previous item position. + for name, table := range f.tables { + err := table.truncateHead(old) + if err != nil { + log.Error("Freezer table roll-back failed", "table", name, "index", old, "err", err) + } + } + }(f.items) + + // Modify the ancients in batch. + f.writeBatch.reset(f) + if err := fn(f.writeBatch); err != nil { + return 0, err + } + item, writeSize, err := f.writeBatch.commit(f) + if err != nil { + return 0, err + } + f.items = item + return writeSize, nil +} + +// TruncateHead discards any recent data above the provided threshold number. +// It returns the previous head number. +func (f *MemoryFreezer) TruncateHead(items uint64) (uint64, error) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.readonly { + return 0, errReadOnly + } + old := f.items + if old <= items { + return old, nil + } + for _, table := range f.tables { + if err := table.truncateHead(items); err != nil { + return 0, err + } + } + f.items = items + return old, nil +} + +// TruncateTail discards any recent data below the provided threshold number. +func (f *MemoryFreezer) TruncateTail(tail uint64) (uint64, error) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.readonly { + return 0, errReadOnly + } + old := f.tail + if old >= tail { + return old, nil + } + for _, table := range f.tables { + if err := table.truncateTail(tail); err != nil { + return 0, err + } + } + f.tail = tail + return old, nil +} + +// Sync flushes all data tables to disk. +func (f *MemoryFreezer) Sync() error { + return nil +} + +// MigrateTable processes and migrates entries of a given table to a new format. +// The second argument is a function that takes a raw entry and returns it +// in the newest format. +func (f *MemoryFreezer) MigrateTable(string, func([]byte) ([]byte, error)) error { + return errors.New("not implemented") +} + +// Close releases all the sources held by the memory freezer. It will panic if +// any following invocation is made to a closed freezer. +func (f *MemoryFreezer) Close() error { + f.lock.Lock() + defer f.lock.Unlock() + + f.tables = nil + f.writeBatch = nil + return nil +} + +// Reset drops all the data cached in the memory freezer and reset itself +// back to default state. +func (f *MemoryFreezer) Reset() error { + f.lock.Lock() + defer f.lock.Unlock() + + tables := make(map[string]*memoryTable) + for name := range f.tables { + tables[name] = newMemoryTable(name) + } + f.tables = tables + f.items, f.tail = 0, 0 + return nil +} diff --git a/core/rawdb/freezer_memory_test.go b/core/rawdb/freezer_memory_test.go new file mode 100644 index 000000000000..e71de0f62922 --- /dev/null +++ b/core/rawdb/freezer_memory_test.go @@ -0,0 +1,41 @@ +// Copyright 2024 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 ( + "testing" + + "github.com/ethereum/go-ethereum/core/rawdb/ancienttest" + "github.com/ethereum/go-ethereum/ethdb" +) + +func TestMemoryFreezer(t *testing.T) { + ancienttest.TestAncientSuite(t, func(kinds []string) ethdb.AncientStore { + tables := make(map[string]bool) + for _, kind := range kinds { + tables[kind] = true + } + return NewMemoryFreezer(false, tables) + }) + ancienttest.TestResettableAncientSuite(t, func(kinds []string) ethdb.ResettableAncientStore { + tables := make(map[string]bool) + for _, kind := range kinds { + tables[kind] = true + } + return NewMemoryFreezer(false, tables) + }) +} diff --git a/core/rawdb/freezer_resettable.go b/core/rawdb/freezer_resettable.go index 7a8548973819..7fa59b8d2196 100644 --- a/core/rawdb/freezer_resettable.go +++ b/core/rawdb/freezer_resettable.go @@ -30,16 +30,16 @@ const tmpSuffix = ".tmp" // freezerOpenFunc is the function used to open/create a freezer. type freezerOpenFunc = func() (*Freezer, error) -// ResettableFreezer is a wrapper of the freezer which makes the +// resettableFreezer is a wrapper of the freezer which makes the // freezer resettable. -type ResettableFreezer struct { +type resettableFreezer struct { freezer *Freezer opener freezerOpenFunc datadir string lock sync.RWMutex } -// NewResettableFreezer creates a resettable freezer, note freezer is +// newResettableFreezer creates a resettable freezer, note freezer is // only resettable if the passed file directory is exclusively occupied // by the freezer. And also the user-configurable ancient root directory // is **not** supported for reset since it might be a mount and rename @@ -48,7 +48,7 @@ type ResettableFreezer struct { // // The reset function will delete directory atomically and re-create the // freezer from scratch. -func NewResettableFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*ResettableFreezer, error) { +func newResettableFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*resettableFreezer, error) { if err := cleanup(datadir); err != nil { return nil, err } @@ -59,7 +59,7 @@ func NewResettableFreezer(datadir string, namespace string, readonly bool, maxTa if err != nil { return nil, err } - return &ResettableFreezer{ + return &resettableFreezer{ freezer: freezer, opener: opener, datadir: datadir, @@ -70,7 +70,7 @@ func NewResettableFreezer(datadir string, namespace string, readonly bool, maxTa // recreate the freezer from scratch. The atomicity of directory deletion // is guaranteed by the rename operation, the leftover directory will be // cleaned up in next startup in case crash happens after rename. -func (f *ResettableFreezer) Reset() error { +func (f *resettableFreezer) Reset() error { f.lock.Lock() defer f.lock.Unlock() @@ -93,7 +93,7 @@ func (f *ResettableFreezer) Reset() error { } // Close terminates the chain freezer, unmapping all the data files. -func (f *ResettableFreezer) Close() error { +func (f *resettableFreezer) Close() error { f.lock.RLock() defer f.lock.RUnlock() @@ -102,7 +102,7 @@ func (f *ResettableFreezer) Close() error { // HasAncient returns an indicator whether the specified ancient data exists // in the freezer -func (f *ResettableFreezer) HasAncient(kind string, number uint64) (bool, error) { +func (f *resettableFreezer) HasAncient(kind string, number uint64) (bool, error) { f.lock.RLock() defer f.lock.RUnlock() @@ -110,7 +110,7 @@ func (f *ResettableFreezer) HasAncient(kind string, number uint64) (bool, error) } // Ancient retrieves an ancient binary blob from the append-only immutable files. -func (f *ResettableFreezer) Ancient(kind string, number uint64) ([]byte, error) { +func (f *resettableFreezer) Ancient(kind string, number uint64) ([]byte, error) { f.lock.RLock() defer f.lock.RUnlock() @@ -123,7 +123,7 @@ func (f *ResettableFreezer) Ancient(kind string, number uint64) ([]byte, error) // - if maxBytes is specified: at least 1 item (even if exceeding the maxByteSize), // but will otherwise return as many items as fit into maxByteSize. // - if maxBytes is not specified, 'count' items will be returned if they are present. -func (f *ResettableFreezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) { +func (f *resettableFreezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) { f.lock.RLock() defer f.lock.RUnlock() @@ -131,7 +131,7 @@ func (f *ResettableFreezer) AncientRange(kind string, start, count, maxBytes uin } // Ancients returns the length of the frozen items. -func (f *ResettableFreezer) Ancients() (uint64, error) { +func (f *resettableFreezer) Ancients() (uint64, error) { f.lock.RLock() defer f.lock.RUnlock() @@ -139,7 +139,7 @@ func (f *ResettableFreezer) Ancients() (uint64, error) { } // Tail returns the number of first stored item in the freezer. -func (f *ResettableFreezer) Tail() (uint64, error) { +func (f *resettableFreezer) Tail() (uint64, error) { f.lock.RLock() defer f.lock.RUnlock() @@ -147,7 +147,7 @@ func (f *ResettableFreezer) Tail() (uint64, error) { } // AncientSize returns the ancient size of the specified category. -func (f *ResettableFreezer) AncientSize(kind string) (uint64, error) { +func (f *resettableFreezer) AncientSize(kind string) (uint64, error) { f.lock.RLock() defer f.lock.RUnlock() @@ -156,7 +156,7 @@ func (f *ResettableFreezer) AncientSize(kind string) (uint64, error) { // ReadAncients runs the given read operation while ensuring that no writes take place // on the underlying freezer. -func (f *ResettableFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) { +func (f *resettableFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) { f.lock.RLock() defer f.lock.RUnlock() @@ -164,7 +164,7 @@ func (f *ResettableFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) ( } // ModifyAncients runs the given write operation. -func (f *ResettableFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize int64, err error) { +func (f *resettableFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize int64, err error) { f.lock.RLock() defer f.lock.RUnlock() @@ -173,7 +173,7 @@ func (f *ResettableFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) // TruncateHead discards any recent data above the provided threshold number. // It returns the previous head number. -func (f *ResettableFreezer) TruncateHead(items uint64) (uint64, error) { +func (f *resettableFreezer) TruncateHead(items uint64) (uint64, error) { f.lock.RLock() defer f.lock.RUnlock() @@ -182,7 +182,7 @@ func (f *ResettableFreezer) TruncateHead(items uint64) (uint64, error) { // TruncateTail discards any recent data below the provided threshold number. // It returns the previous value -func (f *ResettableFreezer) TruncateTail(tail uint64) (uint64, error) { +func (f *resettableFreezer) TruncateTail(tail uint64) (uint64, error) { f.lock.RLock() defer f.lock.RUnlock() @@ -190,7 +190,7 @@ func (f *ResettableFreezer) TruncateTail(tail uint64) (uint64, error) { } // Sync flushes all data tables to disk. -func (f *ResettableFreezer) Sync() error { +func (f *resettableFreezer) Sync() error { f.lock.RLock() defer f.lock.RUnlock() @@ -199,7 +199,7 @@ func (f *ResettableFreezer) Sync() error { // MigrateTable processes the entries in a given table in sequence // converting them to a new format if they're of an old format. -func (f *ResettableFreezer) MigrateTable(kind string, convert convertLegacyFn) error { +func (f *resettableFreezer) MigrateTable(kind string, convert convertLegacyFn) error { f.lock.RLock() defer f.lock.RUnlock() diff --git a/core/rawdb/freezer_resettable_test.go b/core/rawdb/freezer_resettable_test.go index d741bc14e54f..61dc23d79841 100644 --- a/core/rawdb/freezer_resettable_test.go +++ b/core/rawdb/freezer_resettable_test.go @@ -33,7 +33,7 @@ func TestResetFreezer(t *testing.T) { {1, bytes.Repeat([]byte{1}, 2048)}, {2, bytes.Repeat([]byte{2}, 2048)}, } - f, _ := NewResettableFreezer(t.TempDir(), "", false, 2048, freezerTestTableDef) + f, _ := newResettableFreezer(t.TempDir(), "", false, 2048, freezerTestTableDef) defer f.Close() f.ModifyAncients(func(op ethdb.AncientWriteOp) error { @@ -87,7 +87,7 @@ func TestFreezerCleanup(t *testing.T) { {2, bytes.Repeat([]byte{2}, 2048)}, } datadir := t.TempDir() - f, _ := NewResettableFreezer(datadir, "", false, 2048, freezerTestTableDef) + f, _ := newResettableFreezer(datadir, "", false, 2048, freezerTestTableDef) f.ModifyAncients(func(op ethdb.AncientWriteOp) error { for _, item := range items { op.AppendRaw("test", item.id, item.blob) @@ -98,7 +98,7 @@ func TestFreezerCleanup(t *testing.T) { os.Rename(datadir, tmpName(datadir)) // Open the freezer again, trigger cleanup operation - f, _ = NewResettableFreezer(datadir, "", false, 2048, freezerTestTableDef) + f, _ = newResettableFreezer(datadir, "", false, 2048, freezerTestTableDef) f.Close() if _, err := os.Lstat(tmpName(datadir)); !os.IsNotExist(err) { diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index 93bc2c225442..72d1417200ce 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -27,6 +27,7 @@ import ( "sync" "testing" + "github.com/ethereum/go-ethereum/core/rawdb/ancienttest" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/require" @@ -480,3 +481,22 @@ func TestFreezerCloseSync(t *testing.T) { t.Fatalf("want %v, have %v", have, want) } } + +func TestFreezerSuite(t *testing.T) { + ancienttest.TestAncientSuite(t, func(kinds []string) ethdb.AncientStore { + tables := make(map[string]bool) + for _, kind := range kinds { + tables[kind] = true + } + f, _ := newFreezerForTesting(t, tables) + return f + }) + ancienttest.TestResettableAncientSuite(t, func(kinds []string) ethdb.ResettableAncientStore { + tables := make(map[string]bool) + for _, kind := range kinds { + tables[kind] = true + } + f, _ := newResettableFreezer(t.TempDir(), "", false, 2048, tables) + return f + }) +} diff --git a/ethdb/database.go b/ethdb/database.go index 4d4817daf2e5..3ec1f70e3b60 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -88,8 +88,8 @@ type AncientReaderOp interface { // Ancients returns the ancient item numbers in the ancient store. Ancients() (uint64, error) - // Tail returns the number of first stored item in the freezer. - // This number can also be interpreted as the total deleted item numbers. + // Tail returns the number of first stored item in the ancient store. + // This number can also be interpreted as the total deleted items. Tail() (uint64, error) // AncientSize returns the ancient size of the specified category. @@ -101,7 +101,7 @@ type AncientReader interface { AncientReaderOp // ReadAncients runs the given read operation while ensuring that no writes take place - // on the underlying freezer. + // on the underlying ancient store. ReadAncients(fn func(AncientReaderOp) error) (err error) } @@ -141,11 +141,15 @@ type AncientWriteOp interface { AppendRaw(kind string, number uint64, item []byte) error } -// AncientStater wraps the Stat method of a backing data store. +// AncientStater wraps the Stat method of a backing ancient store. type AncientStater interface { - // AncientDatadir returns the path of root ancient directory. Empty string - // will be returned if ancient store is not enabled at all. The returned - // path can be used to construct the path of other freezers. + // AncientDatadir returns the path of the ancient store directory. + // + // If the ancient store is not activated, an error is returned. + // If an ephemeral ancient store is used, an empty path is returned. + // + // The path returned by AncientDatadir can be used as the root path + // of the ancient store to construct paths for other sub ancient stores. AncientDatadir() (string, error) } @@ -171,15 +175,23 @@ type Stater interface { } // AncientStore contains all the methods required to allow handling different -// ancient data stores backing immutable chain data store. +// ancient data stores backing immutable data store. type AncientStore interface { AncientReader AncientWriter io.Closer } +// ResettableAncientStore extends the AncientStore interface by adding a Reset method. +type ResettableAncientStore interface { + AncientStore + + // Reset is designed to reset the entire ancient store to its default state. + Reset() error +} + // Database contains all the methods required by the high level database to not -// only access the key-value data store but also the chain freezer. +// only access the key-value data store but also the ancient chain store. type Database interface { Reader Writer diff --git a/node/node.go b/node/node.go index 6cbae68591eb..633f88f058a1 100644 --- a/node/node.go +++ b/node/node.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" @@ -752,7 +753,7 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient var db ethdb.Database var err error if n.config.DataDir == "" { - db = rawdb.NewMemoryDatabase() + db, err = rawdb.NewDatabaseWithFreezer(memorydb.New(), "", namespace, readonly) } else { db, err = rawdb.Open(rawdb.OpenOptions{ Type: n.config.DBEngine, diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 18f2eeef00ce..50beebced124 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -131,15 +131,15 @@ type Database struct { // readOnly is the flag whether the mutation is allowed to be applied. // It will be set automatically when the database is journaled during // the shutdown to reject all following unexpected mutations. - readOnly bool // Flag if database is opened in read only mode - waitSync bool // Flag if database is deactivated due to initial state sync - isVerkle bool // Flag if database is used for verkle tree - bufferSize int // Memory allowance (in bytes) for caching dirty nodes - config *Config // Configuration for database - diskdb ethdb.Database // Persistent storage for matured trie nodes - tree *layerTree // The group for all known layers - freezer *rawdb.ResettableFreezer // Freezer for storing trie histories, nil possible in tests - lock sync.RWMutex // Lock to prevent mutations from happening at the same time + readOnly bool // Flag if database is opened in read only mode + waitSync bool // Flag if database is deactivated due to initial state sync + isVerkle bool // Flag if database is used for verkle tree + bufferSize int // Memory allowance (in bytes) for caching dirty nodes + config *Config // Configuration for database + diskdb ethdb.Database // Persistent storage for matured trie nodes + tree *layerTree // The group for all known layers + freezer ethdb.ResettableAncientStore // Freezer for storing trie histories, nil possible in tests + lock sync.RWMutex // Lock to prevent mutations from happening at the same time } // New attempts to load an already existing layer from a persistent key-value @@ -162,45 +162,10 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { // and in-memory layer journal. db.tree = newLayerTree(db.loadLayers()) - // Open the freezer for state history if the passed database contains an - // ancient store. Otherwise, all the relevant functionalities are disabled. - // - // Because the freezer can only be opened once at the same time, this - // mechanism also ensures that at most one **non-readOnly** database - // is opened at the same time to prevent accidental mutation. - if ancient, err := diskdb.AncientDatadir(); err == nil && ancient != "" && !db.readOnly { - freezer, err := rawdb.NewStateFreezer(ancient, false) - if err != nil { - log.Crit("Failed to open state history freezer", "err", err) - } - db.freezer = freezer - - diskLayerID := db.tree.bottom().stateID() - if diskLayerID == 0 { - // Reset the entire state histories in case the trie database is - // not initialized yet, as these state histories are not expected. - frozen, err := db.freezer.Ancients() - if err != nil { - log.Crit("Failed to retrieve head of state history", "err", err) - } - if frozen != 0 { - err := db.freezer.Reset() - if err != nil { - log.Crit("Failed to reset state histories", "err", err) - } - log.Info("Truncated extraneous state history") - } - } else { - // Truncate the extra state histories above in freezer in case - // it's not aligned with the disk layer. - pruned, err := truncateFromHead(db.diskdb, freezer, diskLayerID) - if err != nil { - log.Crit("Failed to truncate extra state histories", "err", err) - } - if pruned != 0 { - log.Warn("Truncated extra state histories", "number", pruned) - } - } + // Repair the state history, which might not be aligned with the state + // in the key-value store due to an unclean shutdown. + if err := db.repairHistory(); err != nil { + log.Crit("Failed to repair pathdb", "err", err) } // Disable database in case node is still in the initial state sync stage. if rawdb.ReadSnapSyncStatusFlag(diskdb) == rawdb.StateSyncRunning && !db.readOnly { @@ -211,6 +176,55 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { return db } +// repairHistory truncates leftover state history objects, which may occur due +// to an unclean shutdown or other unexpected reasons. +func (db *Database) repairHistory() error { + // Open the freezer for state history. This mechanism ensures that + // only one database instance can be opened at a time to prevent + // accidental mutation. + ancient, err := db.diskdb.AncientDatadir() + if err != nil { + // TODO error out if ancient store is disabled. A tons of unit tests + // disable the ancient store thus the error here will immediately fail + // all of them. Fix the tests first. + return nil + } + freezer, err := rawdb.NewStateFreezer(ancient, false) + if err != nil { + log.Crit("Failed to open state history freezer", "err", err) + } + db.freezer = freezer + + // Reset the entire state histories if the trie database is not initialized + // yet. This action is necessary because these state histories are not + // expected to exist without an initialized trie database. + id := db.tree.bottom().stateID() + if id == 0 { + frozen, err := db.freezer.Ancients() + if err != nil { + log.Crit("Failed to retrieve head of state history", "err", err) + } + if frozen != 0 { + err := db.freezer.Reset() + if err != nil { + log.Crit("Failed to reset state histories", "err", err) + } + log.Info("Truncated extraneous state history") + } + return nil + } + // Truncate the extra state histories above in freezer in case it's not + // aligned with the disk layer. It might happen after a unclean shutdown. + pruned, err := truncateFromHead(db.diskdb, db.freezer, id) + if err != nil { + log.Crit("Failed to truncate extra state histories", "err", err) + } + if pruned != 0 { + log.Warn("Truncated extra state histories", "number", pruned) + } + return nil +} + // Update adds a new layer into the tree, if that can be linked to an existing // old parent. It is disallowed to insert a disk layer (the origin of all). Apart // from that this function will flatten the extra diff layers at bottom into disk diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 7099b2b381f2..3663cbbdb9a1 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -472,8 +472,8 @@ func (h *history) decode(accountData, storageData, accountIndexes, storageIndexe } // readHistory reads and decodes the state history object by the given id. -func readHistory(freezer *rawdb.ResettableFreezer, id uint64) (*history, error) { - blob := rawdb.ReadStateHistoryMeta(freezer, id) +func readHistory(reader ethdb.AncientReader, id uint64) (*history, error) { + blob := rawdb.ReadStateHistoryMeta(reader, id) if len(blob) == 0 { return nil, fmt.Errorf("state history not found %d", id) } @@ -483,10 +483,10 @@ func readHistory(freezer *rawdb.ResettableFreezer, id uint64) (*history, error) } var ( dec = history{meta: &m} - accountData = rawdb.ReadStateAccountHistory(freezer, id) - storageData = rawdb.ReadStateStorageHistory(freezer, id) - accountIndexes = rawdb.ReadStateAccountIndex(freezer, id) - storageIndexes = rawdb.ReadStateStorageIndex(freezer, id) + accountData = rawdb.ReadStateAccountHistory(reader, id) + storageData = rawdb.ReadStateStorageHistory(reader, id) + accountIndexes = rawdb.ReadStateAccountIndex(reader, id) + storageIndexes = rawdb.ReadStateStorageIndex(reader, id) ) if err := dec.decode(accountData, storageData, accountIndexes, storageIndexes); err != nil { return nil, err @@ -495,7 +495,7 @@ func readHistory(freezer *rawdb.ResettableFreezer, id uint64) (*history, error) } // writeHistory persists the state history with the provided state set. -func writeHistory(freezer *rawdb.ResettableFreezer, dl *diffLayer) error { +func writeHistory(writer ethdb.AncientWriter, dl *diffLayer) error { // Short circuit if state set is not available. if dl.states == nil { return errors.New("state change set is not available") @@ -509,7 +509,7 @@ func writeHistory(freezer *rawdb.ResettableFreezer, dl *diffLayer) error { indexSize := common.StorageSize(len(accountIndex) + len(storageIndex)) // Write history data into five freezer table respectively. - rawdb.WriteStateHistory(freezer, dl.stateID(), history.meta.encode(), accountIndex, storageIndex, accountData, storageData) + rawdb.WriteStateHistory(writer, dl.stateID(), history.meta.encode(), accountIndex, storageIndex, accountData, storageData) historyDataBytesMeter.Mark(int64(dataSize)) historyIndexBytesMeter.Mark(int64(indexSize)) @@ -521,13 +521,13 @@ func writeHistory(freezer *rawdb.ResettableFreezer, dl *diffLayer) error { // checkHistories retrieves a batch of meta objects with the specified range // and performs the callback on each item. -func checkHistories(freezer *rawdb.ResettableFreezer, start, count uint64, check func(*meta) error) error { +func checkHistories(reader ethdb.AncientReader, start, count uint64, check func(*meta) error) error { for count > 0 { number := count if number > 10000 { number = 10000 // split the big read into small chunks } - blobs, err := rawdb.ReadStateHistoryMetaList(freezer, start, number) + blobs, err := rawdb.ReadStateHistoryMetaList(reader, start, number) if err != nil { return err } @@ -548,12 +548,12 @@ func checkHistories(freezer *rawdb.ResettableFreezer, start, count uint64, check // truncateFromHead removes the extra state histories from the head with the given // parameters. It returns the number of items removed from the head. -func truncateFromHead(db ethdb.Batcher, freezer *rawdb.ResettableFreezer, nhead uint64) (int, error) { - ohead, err := freezer.Ancients() +func truncateFromHead(db ethdb.Batcher, store ethdb.AncientStore, nhead uint64) (int, error) { + ohead, err := store.Ancients() if err != nil { return 0, err } - otail, err := freezer.Tail() + otail, err := store.Tail() if err != nil { return 0, err } @@ -566,7 +566,7 @@ func truncateFromHead(db ethdb.Batcher, freezer *rawdb.ResettableFreezer, nhead return 0, nil } // Load the meta objects in range [nhead+1, ohead] - blobs, err := rawdb.ReadStateHistoryMetaList(freezer, nhead+1, ohead-nhead) + blobs, err := rawdb.ReadStateHistoryMetaList(store, nhead+1, ohead-nhead) if err != nil { return 0, err } @@ -581,7 +581,7 @@ func truncateFromHead(db ethdb.Batcher, freezer *rawdb.ResettableFreezer, nhead if err := batch.Write(); err != nil { return 0, err } - ohead, err = freezer.TruncateHead(nhead) + ohead, err = store.TruncateHead(nhead) if err != nil { return 0, err } @@ -590,12 +590,12 @@ func truncateFromHead(db ethdb.Batcher, freezer *rawdb.ResettableFreezer, nhead // truncateFromTail removes the extra state histories from the tail with the given // parameters. It returns the number of items removed from the tail. -func truncateFromTail(db ethdb.Batcher, freezer *rawdb.ResettableFreezer, ntail uint64) (int, error) { - ohead, err := freezer.Ancients() +func truncateFromTail(db ethdb.Batcher, store ethdb.AncientStore, ntail uint64) (int, error) { + ohead, err := store.Ancients() if err != nil { return 0, err } - otail, err := freezer.Tail() + otail, err := store.Tail() if err != nil { return 0, err } @@ -608,7 +608,7 @@ func truncateFromTail(db ethdb.Batcher, freezer *rawdb.ResettableFreezer, ntail return 0, nil } // Load the meta objects in range [otail+1, ntail] - blobs, err := rawdb.ReadStateHistoryMetaList(freezer, otail+1, ntail-otail) + blobs, err := rawdb.ReadStateHistoryMetaList(store, otail+1, ntail-otail) if err != nil { return 0, err } @@ -623,7 +623,7 @@ func truncateFromTail(db ethdb.Batcher, freezer *rawdb.ResettableFreezer, ntail if err := batch.Write(); err != nil { return 0, err } - otail, err = freezer.TruncateTail(ntail) + otail, err = store.TruncateTail(ntail) if err != nil { return 0, err } diff --git a/triedb/pathdb/history_inspect.go b/triedb/pathdb/history_inspect.go index d8a761b91689..240474da37e4 100644 --- a/triedb/pathdb/history_inspect.go +++ b/triedb/pathdb/history_inspect.go @@ -21,7 +21,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -34,7 +34,7 @@ type HistoryStats struct { } // sanitizeRange limits the given range to fit within the local history store. -func sanitizeRange(start, end uint64, freezer *rawdb.ResettableFreezer) (uint64, uint64, error) { +func sanitizeRange(start, end uint64, freezer ethdb.AncientReader) (uint64, uint64, error) { // Load the id of the first history object in local store. tail, err := freezer.Tail() if err != nil { @@ -60,7 +60,7 @@ func sanitizeRange(start, end uint64, freezer *rawdb.ResettableFreezer) (uint64, return first, last, nil } -func inspectHistory(freezer *rawdb.ResettableFreezer, start, end uint64, onHistory func(*history, *HistoryStats)) (*HistoryStats, error) { +func inspectHistory(freezer ethdb.AncientReader, start, end uint64, onHistory func(*history, *HistoryStats)) (*HistoryStats, error) { var ( stats = &HistoryStats{} init = time.Now() @@ -96,7 +96,7 @@ func inspectHistory(freezer *rawdb.ResettableFreezer, start, end uint64, onHisto } // accountHistory inspects the account history within the range. -func accountHistory(freezer *rawdb.ResettableFreezer, address common.Address, start, end uint64) (*HistoryStats, error) { +func accountHistory(freezer ethdb.AncientReader, address common.Address, start, end uint64) (*HistoryStats, error) { return inspectHistory(freezer, start, end, func(h *history, stats *HistoryStats) { blob, exists := h.accounts[address] if !exists { @@ -108,7 +108,7 @@ func accountHistory(freezer *rawdb.ResettableFreezer, address common.Address, st } // storageHistory inspects the storage history within the range. -func storageHistory(freezer *rawdb.ResettableFreezer, address common.Address, slot common.Hash, start uint64, end uint64) (*HistoryStats, error) { +func storageHistory(freezer ethdb.AncientReader, address common.Address, slot common.Hash, start uint64, end uint64) (*HistoryStats, error) { return inspectHistory(freezer, start, end, func(h *history, stats *HistoryStats) { slots, exists := h.storages[address] if !exists { @@ -124,7 +124,7 @@ func storageHistory(freezer *rawdb.ResettableFreezer, address common.Address, sl } // historyRange returns the block number range of local state histories. -func historyRange(freezer *rawdb.ResettableFreezer) (uint64, uint64, error) { +func historyRange(freezer ethdb.AncientReader) (uint64, uint64, error) { // Load the id of the first history object in local store. tail, err := freezer.Tail() if err != nil { diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_test.go index 81ac768acdc6..4114aa118532 100644 --- a/triedb/pathdb/history_test.go +++ b/triedb/pathdb/history_test.go @@ -102,7 +102,7 @@ func TestEncodeDecodeHistory(t *testing.T) { } } -func checkHistory(t *testing.T, db ethdb.KeyValueReader, freezer *rawdb.ResettableFreezer, id uint64, root common.Hash, exist bool) { +func checkHistory(t *testing.T, db ethdb.KeyValueReader, freezer ethdb.AncientReader, id uint64, root common.Hash, exist bool) { blob := rawdb.ReadStateHistoryMeta(freezer, id) if exist && len(blob) == 0 { t.Fatalf("Failed to load trie history, %d", id) @@ -118,7 +118,7 @@ func checkHistory(t *testing.T, db ethdb.KeyValueReader, freezer *rawdb.Resettab } } -func checkHistoriesInRange(t *testing.T, db ethdb.KeyValueReader, freezer *rawdb.ResettableFreezer, from, to uint64, roots []common.Hash, exist bool) { +func checkHistoriesInRange(t *testing.T, db ethdb.KeyValueReader, freezer ethdb.AncientReader, from, to uint64, roots []common.Hash, exist bool) { for i, j := from, 0; i <= to; i, j = i+1, j+1 { checkHistory(t, db, freezer, i, roots[j], exist) } @@ -129,7 +129,7 @@ func TestTruncateHeadHistory(t *testing.T) { roots []common.Hash hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = openFreezer(t.TempDir(), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) ) defer freezer.Close() @@ -157,7 +157,7 @@ func TestTruncateTailHistory(t *testing.T) { roots []common.Hash hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = openFreezer(t.TempDir(), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) ) defer freezer.Close() @@ -200,7 +200,7 @@ func TestTruncateTailHistories(t *testing.T) { roots []common.Hash hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = openFreezer(t.TempDir()+fmt.Sprintf("%d", i), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir()+fmt.Sprintf("%d", i), false) ) defer freezer.Close() @@ -228,7 +228,7 @@ func TestTruncateOutOfRange(t *testing.T) { var ( hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = openFreezer(t.TempDir(), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) ) defer freezer.Close() @@ -268,11 +268,6 @@ func TestTruncateOutOfRange(t *testing.T) { } } -// openFreezer initializes the freezer instance for storing state histories. -func openFreezer(datadir string, readOnly bool) (*rawdb.ResettableFreezer, error) { - return rawdb.NewStateFreezer(datadir, readOnly) -} - func compareSet[k comparable](a, b map[k][]byte) bool { if len(a) != len(b) { return false From 242b24af9f21cd4b35e2e609b12371f41528da3d Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 30 Apr 2024 13:51:04 +0200 Subject: [PATCH 230/571] trie/trienode: minor speedup in nodeset merging (#29683) --- trie/trienode/node.go | 7 ++++- trie/trienode/node_test.go | 61 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 trie/trienode/node_test.go diff --git a/trie/trienode/node.go b/trie/trienode/node.go index 055db8822e72..bc93e3ca88f0 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -114,7 +114,12 @@ func (set *NodeSet) Merge(owner common.Hash, nodes map[string]*Node) error { set.updates -= 1 } } - set.AddNode([]byte(path), node) + if node.IsDeleted() { + set.deletes += 1 + } else { + set.updates += 1 + } + set.Nodes[path] = node } return nil } diff --git a/trie/trienode/node_test.go b/trie/trienode/node_test.go new file mode 100644 index 000000000000..bcb3a2202b53 --- /dev/null +++ b/trie/trienode/node_test.go @@ -0,0 +1,61 @@ +// Copyright 2023 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 trienode + +import ( + "crypto/rand" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +func BenchmarkMerge(b *testing.B) { + b.Run("1K", func(b *testing.B) { + benchmarkMerge(b, 1000) + }) + b.Run("10K", func(b *testing.B) { + benchmarkMerge(b, 10_000) + }) +} + +func benchmarkMerge(b *testing.B, count int) { + x := NewNodeSet(common.Hash{}) + y := NewNodeSet(common.Hash{}) + addNode := func(s *NodeSet) { + path := make([]byte, 4) + rand.Read(path) + blob := make([]byte, 32) + rand.Read(blob) + hash := crypto.Keccak256Hash(blob) + s.AddNode(path, New(hash, blob)) + } + for i := 0; i < count; i++ { + // Random path of 4 nibbles + addNode(x) + addNode(y) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Store set x into a backup + z := NewNodeSet(common.Hash{}) + z.Merge(common.Hash{}, x.Nodes) + // Merge y into x + x.Merge(common.Hash{}, y.Nodes) + x = z + } +} From ea89f9adf0ace09c46e790bf8c38414f7b90af69 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Tue, 30 Apr 2024 20:08:13 +0800 Subject: [PATCH 231/571] core/vm: remove a redundant zero check in opAddmod (#29672) --- core/vm/instructions.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index a062bb15ff5c..f37ee004dc3a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -173,11 +173,7 @@ func opByte(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek() - if z.IsZero() { - z.Clear() - } else { - z.AddMod(&x, &y, z) - } + z.AddMod(&x, &y, z) return nil, nil } From 7c7e3a77fced21b098841aa3cb3663de0c85f951 Mon Sep 17 00:00:00 2001 From: Dragan Milic Date: Tue, 30 Apr 2024 14:33:22 +0200 Subject: [PATCH 232/571] eth/tracers/native: fix flatCallTracer Stop() bug (#29623) Co-authored-by: Sina Mahmoodi --- eth/tracers/native/call_flat.go | 18 +++++++- eth/tracers/native/call_flat_test.go | 64 ++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 eth/tracers/native/call_flat_test.go diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index f8d38ddd2d5b..ce0fb081143e 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -23,6 +23,7 @@ import ( "math/big" "slices" "strings" + "sync/atomic" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -114,7 +115,7 @@ type flatCallTracer struct { tracer *callTracer config flatCallTracerConfig ctx *tracers.Context // Holds tracer context data - reason error // Textual reason for the interruption + interrupt atomic.Bool // Atomic flag to signal execution interruption activePrecompiles []common.Address // Updated on tx start based on given rules } @@ -154,6 +155,9 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Trac // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). func (t *flatCallTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if t.interrupt.Load() { + return + } t.tracer.OnEnter(depth, typ, from, to, input, gas, value) if depth == 0 { @@ -169,6 +173,9 @@ func (t *flatCallTracer) OnEnter(depth int, typ byte, from common.Address, to co // OnExit is called when EVM exits a scope, even if the scope didn't // execute any code. func (t *flatCallTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if t.interrupt.Load() { + return + } t.tracer.OnExit(depth, output, gasUsed, err, reverted) if depth == 0 { @@ -194,6 +201,9 @@ func (t *flatCallTracer) OnExit(depth int, output []byte, gasUsed uint64, err er } func (t *flatCallTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + if t.interrupt.Load() { + return + } t.tracer.OnTxStart(env, tx, from) // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) @@ -201,6 +211,9 @@ func (t *flatCallTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction } func (t *flatCallTracer) OnTxEnd(receipt *types.Receipt, err error) { + if t.interrupt.Load() { + return + } t.tracer.OnTxEnd(receipt, err) } @@ -219,12 +232,13 @@ func (t *flatCallTracer) GetResult() (json.RawMessage, error) { if err != nil { return nil, err } - return res, t.reason + return res, t.tracer.reason } // Stop terminates execution of the tracer at the first opportune moment. func (t *flatCallTracer) Stop(err error) { t.tracer.Stop(err) + t.interrupt.Store(true) } // isPrecompiled returns whether the addr is a precompile. diff --git a/eth/tracers/native/call_flat_test.go b/eth/tracers/native/call_flat_test.go new file mode 100644 index 000000000000..d5481b868bcc --- /dev/null +++ b/eth/tracers/native/call_flat_test.go @@ -0,0 +1,64 @@ +// Copyright 2024 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 native_test + +import ( + "errors" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/params" + "github.com/stretchr/testify/require" +) + +func TestCallFlatStop(t *testing.T) { + tracer, err := tracers.DefaultDirectory.New("flatCallTracer", &tracers.Context{}, nil) + require.NoError(t, err) + + // this error should be returned by GetResult + stopError := errors.New("stop error") + + // simulate a transaction + tx := types.NewTx(&types.LegacyTx{ + Nonce: 0, + To: &common.Address{}, + Value: big.NewInt(0), + Gas: 0, + GasPrice: big.NewInt(0), + Data: nil, + }) + + tracer.OnTxStart(&tracing.VMContext{ + ChainConfig: params.MainnetChainConfig, + }, tx, common.Address{}) + + tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, nil, 0, big.NewInt(0)) + + // stop before the transaction is finished + tracer.Stop(stopError) + + tracer.OnTxEnd(&types.Receipt{GasUsed: 0}, nil) + + // check that the error is returned by GetResult + _, tracerError := tracer.GetResult() + require.Equal(t, stopError, tracerError) +} From bd6bc37eec15542b8c27004a8018ef27be71931d Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 30 Apr 2024 14:35:48 +0200 Subject: [PATCH 233/571] core/vm: add subgroup checks for mul/mulexp for G1/G2 (#29637) --- core/vm/contracts.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 5f7de8007b51..527d9f4f470b 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -705,6 +705,8 @@ func (c *bls12381G1Add) Run(input []byte) ([]byte, error) { return nil, err } + // No need to check the subgroup here, as specified by EIP-2537 + // Compute r = p_0 + p_1 p0.Add(p0, p1) @@ -734,6 +736,11 @@ func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) { if p0, err = decodePointG1(input[:128]); err != nil { return nil, err } + // 'point is on curve' check already done, + // Here we need to apply subgroup checks. + if !p0.IsInSubGroup() { + return nil, errBLS12381G1PointSubgroup + } // Decode scalar value e := new(big.Int).SetBytes(input[128:]) @@ -787,6 +794,11 @@ func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) { if err != nil { return nil, err } + // 'point is on curve' check already done, + // Here we need to apply subgroup checks. + if !p.IsInSubGroup() { + return nil, errBLS12381G1PointSubgroup + } points[i] = *p // Decode scalar value scalars[i] = *new(fr.Element).SetBytes(input[t1:t2]) @@ -827,6 +839,8 @@ func (c *bls12381G2Add) Run(input []byte) ([]byte, error) { return nil, err } + // No need to check the subgroup here, as specified by EIP-2537 + // Compute r = p_0 + p_1 r := new(bls12381.G2Affine) r.Add(p0, p1) @@ -857,6 +871,11 @@ func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) { if p0, err = decodePointG2(input[:256]); err != nil { return nil, err } + // 'point is on curve' check already done, + // Here we need to apply subgroup checks. + if !p0.IsInSubGroup() { + return nil, errBLS12381G2PointSubgroup + } // Decode scalar value e := new(big.Int).SetBytes(input[256:]) @@ -910,6 +929,11 @@ func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) { if err != nil { return nil, err } + // 'point is on curve' check already done, + // Here we need to apply subgroup checks. + if !p.IsInSubGroup() { + return nil, errBLS12381G2PointSubgroup + } points[i] = *p // Decode scalar value scalars[i] = *new(fr.Element).SetBytes(input[t1:t2]) From 5e070545891961a353694682f9fa3f095e1b7d73 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 30 Apr 2024 14:48:54 +0200 Subject: [PATCH 234/571] internal/ethapi: listen to ctx cancellation in access list (#29686) --- internal/ethapi/api.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4b5145f5deea..d308cead627f 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1524,6 +1524,9 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH prevTracer = logger.NewAccessListTracer(*args.AccessList, args.from(), to, precompiles) } for { + if err := ctx.Err(); err != nil { + return nil, 0, nil, err + } // Retrieve the current access list to expand accessList := prevTracer.AccessList() log.Trace("Creating access list", "input", accessList) From 2e8e35f2ada60e8e90aff8f6374ea7cd7da16116 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 30 Apr 2024 06:55:08 -0600 Subject: [PATCH 235/571] all: refactor so `NewBlock`, `WithBody` take `types.Body` (#29482) * all: refactor so NewBlock(..) and WithBody(..) take a types.Body * core: fixup comments, remove txs != receipts panic * core/types: add empty withdrawls to body if len == 0 --- beacon/engine/types.go | 2 +- beacon/types/exec_payload.go | 4 +- cmd/evm/internal/t8ntool/block.go | 2 +- consensus/beacon/consensus.go | 2 +- consensus/clique/clique.go | 2 +- consensus/ethash/consensus.go | 2 +- core/genesis.go | 2 +- core/rawdb/accessors_chain.go | 14 ++++- core/rawdb/accessors_chain_test.go | 2 +- core/rawdb/accessors_indexes_test.go | 2 +- core/rawdb/chain_iterator_test.go | 8 +-- core/state_processor_test.go | 5 +- core/txpool/legacypool/legacypool_test.go | 2 +- core/types/block.go | 68 +++++++++-------------- core/types/block_test.go | 2 +- eth/catalyst/api_test.go | 6 +- eth/downloader/downloader.go | 6 +- eth/downloader/queue.go | 9 +++ ethclient/ethclient.go | 7 ++- internal/era/era.go | 2 +- internal/era/iterator.go | 2 +- internal/ethapi/api_test.go | 4 +- miner/miner_test.go | 2 +- 23 files changed, 81 insertions(+), 76 deletions(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index fc77c13af707..a73691ca0576 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -250,7 +250,7 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, BlobGasUsed: params.BlobGasUsed, ParentBeaconRoot: beaconRoot, } - block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals) + block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: params.Withdrawals}) if block.Hash() != params.BlockHash { return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash()) } diff --git a/beacon/types/exec_payload.go b/beacon/types/exec_payload.go index 718f98f5292e..4448f854ad12 100644 --- a/beacon/types/exec_payload.go +++ b/beacon/types/exec_payload.go @@ -63,9 +63,7 @@ func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*typ panic("unsupported block type") } - block := types.NewBlockWithHeader(&header) - block = block.WithBody(transactions, nil) - block = block.WithWithdrawals(withdrawals) + block := types.NewBlockWithHeader(&header).WithBody(types.Body{Transactions: transactions, Withdrawals: withdrawals}) if hash := block.Hash(); hash != expectedHash { return nil, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash) } diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go index 62c8593a1d47..37a6db9ffcde 100644 --- a/cmd/evm/internal/t8ntool/block.go +++ b/cmd/evm/internal/t8ntool/block.go @@ -160,7 +160,7 @@ func (i *bbInput) ToBlock() *types.Block { if i.Header.Difficulty != nil { header.Difficulty = i.Header.Difficulty } - return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers).WithWithdrawals(i.Withdrawals) + return types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: i.Txs, Uncles: i.Ommers, Withdrawals: i.Withdrawals}) } // SealBlock seals the given block using the configured engine. diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 4e3fbeb09a7c..b8946e0c7109 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -388,7 +388,7 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea header.Root = state.IntermediateRoot(true) // Assemble and return the final block. - return types.NewBlockWithWithdrawals(header, body.Transactions, body.Uncles, receipts, body.Withdrawals, trie.NewStackTrie(nil)), nil + return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil } // Seal generates a new sealing request for the given input block and pushes diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index b5727fc666d5..c9e94840020a 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -597,7 +597,7 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) // Assemble and return the final block for sealing. - return types.NewBlock(header, body.Transactions, nil, receipts, trie.NewStackTrie(nil)), nil + return types.NewBlock(header, &types.Body{Transactions: body.Transactions}, receipts, trie.NewStackTrie(nil)), nil } // Authorize injects a private key into the consensus engine to mint new blocks diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 9800bf928882..b5e2754c2d94 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -520,7 +520,7 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) // Header seems complete, assemble into a block and return - return types.NewBlock(header, body.Transactions, body.Uncles, receipts, trie.NewStackTrie(nil)), nil + return types.NewBlock(header, &types.Body{Transactions: body.Transactions, Uncles: body.Uncles}, receipts, trie.NewStackTrie(nil)), nil } // SealHash returns the hash of a block prior to it being sealed. diff --git a/core/genesis.go b/core/genesis.go index f05e84199ae4..42836e026993 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -476,7 +476,7 @@ func (g *Genesis) ToBlock() *types.Block { } } } - return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)).WithWithdrawals(withdrawals) + return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil)) } // Commit writes the block and state of a genesis specification to the database. diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 5a4af5bb877b..025be7ade7f4 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -753,7 +753,7 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { if body == nil { return nil } - return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithWithdrawals(body.Withdrawals) + return types.NewBlockWithHeader(header).WithBody(*body) } // WriteBlock serializes a block into the database, header and body separately. @@ -843,7 +843,11 @@ func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block { } for _, bad := range badBlocks { if bad.Header.Hash() == hash { - return types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals) + block := types.NewBlockWithHeader(bad.Header) + if bad.Body != nil { + block = block.WithBody(*bad.Body) + } + return block } } return nil @@ -862,7 +866,11 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block { } var blocks []*types.Block for _, bad := range badBlocks { - blocks = append(blocks, types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals)) + block := types.NewBlockWithHeader(bad.Header) + if bad.Body != nil { + block = block.WithBody(*bad.Body) + } + blocks = append(blocks, block) } return blocks } diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index a7ceb72998a1..fdc940b57e66 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -640,7 +640,7 @@ func makeTestBlocks(nblock int, txsPerBlock int) []*types.Block { Number: big.NewInt(int64(i)), Extra: []byte("test block"), } - blocks[i] = types.NewBlockWithHeader(header).WithBody(txs, nil) + blocks[i] = types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs}) blocks[i].Hash() // pre-cache the block hash } return blocks diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index 124389ba7a13..78dba000fcef 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -76,7 +76,7 @@ func TestLookupStorage(t *testing.T) { tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) txs := []*types.Transaction{tx1, tx2, tx3} - block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil, newTestHasher()) + block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, &types.Body{Transactions: txs}, nil, newTestHasher()) // Check that no transactions entries are in a pristine database for i, tx := range txs { diff --git a/core/rawdb/chain_iterator_test.go b/core/rawdb/chain_iterator_test.go index 78b0a82e10fe..390424f673fc 100644 --- a/core/rawdb/chain_iterator_test.go +++ b/core/rawdb/chain_iterator_test.go @@ -34,7 +34,7 @@ func TestChainIterator(t *testing.T) { var block *types.Block var txs []*types.Transaction to := common.BytesToAddress([]byte{0x11}) - block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, nil, newTestHasher()) // Empty genesis block + block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, newTestHasher()) // Empty genesis block WriteBlock(chainDb, block) WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()) for i := uint64(1); i <= 10; i++ { @@ -60,7 +60,7 @@ func TestChainIterator(t *testing.T) { }) } txs = append(txs, tx) - block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newTestHasher()) + block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, &types.Body{Transactions: types.Transactions{tx}}, nil, newTestHasher()) WriteBlock(chainDb, block) WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()) } @@ -111,7 +111,7 @@ func TestIndexTransactions(t *testing.T) { to := common.BytesToAddress([]byte{0x11}) // Write empty genesis block - block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, nil, newTestHasher()) + block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, newTestHasher()) WriteBlock(chainDb, block) WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()) @@ -138,7 +138,7 @@ func TestIndexTransactions(t *testing.T) { }) } txs = append(txs, tx) - block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newTestHasher()) + block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, &types.Body{Transactions: types.Transactions{tx}}, nil, newTestHasher()) WriteBlock(chainDb, block) WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()) } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index dc9cb203bcec..e98d27eb92d2 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -417,10 +417,11 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr header.ParentBeaconRoot = &beaconRoot } // Assemble and return the final block for sealing + body := &types.Body{Transactions: txs} if config.IsShanghai(header.Number, header.Time) { - return types.NewBlockWithWithdrawals(header, txs, nil, receipts, []*types.Withdrawal{}, trie.NewStackTrie(nil)) + body.Withdrawals = []*types.Withdrawal{} } - return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) + return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)) } var ( diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 68d7b6f411fa..c86991c942da 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -87,7 +87,7 @@ func (bc *testBlockChain) CurrentBlock() *types.Header { } func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { - return types.NewBlock(bc.CurrentBlock(), nil, nil, nil, trie.NewStackTrie(nil)) + return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil)) } func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { diff --git a/core/types/block.go b/core/types/block.go index 53054f52d3b9..4857cd6e50c8 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -23,6 +23,7 @@ import ( "io" "math/big" "reflect" + "slices" "sync/atomic" "time" @@ -217,13 +218,19 @@ type extblock struct { // NewBlock creates a new block. The input data is copied, changes to header and to the // field values will not affect the block. // -// The values of TxHash, UncleHash, ReceiptHash and Bloom in header -// are ignored and set to values derived from the given txs, uncles -// and receipts. -func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher) *Block { - b := &Block{header: CopyHeader(header)} +// The body elements and the receipts are used to recompute and overwrite the +// relevant portions of the header. +func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher) *Block { + if body == nil { + body = &Body{} + } + var ( + b = NewBlockWithHeader(header) + txs = body.Transactions + uncles = body.Uncles + withdrawals = body.Withdrawals + ) - // TODO: panic if len(txs) != len(receipts) if len(txs) == 0 { b.header.TxHash = EmptyTxsHash } else { @@ -249,27 +256,18 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* } } - return b -} - -// NewBlockWithWithdrawals creates a new block with withdrawals. The input data is copied, -// changes to header and to the field values will not affect the block. -// -// The values of TxHash, UncleHash, ReceiptHash and Bloom in header are ignored and set to -// values derived from the given txs, uncles and receipts. -func NewBlockWithWithdrawals(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, withdrawals []*Withdrawal, hasher TrieHasher) *Block { - b := NewBlock(header, txs, uncles, receipts, hasher) - if withdrawals == nil { b.header.WithdrawalsHash = nil } else if len(withdrawals) == 0 { b.header.WithdrawalsHash = &EmptyWithdrawalsHash + b.withdrawals = Withdrawals{} } else { - h := DeriveSha(Withdrawals(withdrawals), hasher) - b.header.WithdrawalsHash = &h + hash := DeriveSha(Withdrawals(withdrawals), hasher) + b.header.WithdrawalsHash = &hash + b.withdrawals = slices.Clone(withdrawals) } - return b.WithWithdrawals(withdrawals) + return b } // CopyHeader creates a deep copy of a block header. @@ -453,31 +451,17 @@ func (b *Block) WithSeal(header *Header) *Block { } } -// WithBody returns a copy of the block with the given transaction and uncle contents. -func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { - block := &Block{ - header: b.header, - transactions: make([]*Transaction, len(transactions)), - uncles: make([]*Header, len(uncles)), - withdrawals: b.withdrawals, - } - copy(block.transactions, transactions) - for i := range uncles { - block.uncles[i] = CopyHeader(uncles[i]) - } - return block -} - -// WithWithdrawals returns a copy of the block containing the given withdrawals. -func (b *Block) WithWithdrawals(withdrawals []*Withdrawal) *Block { +// WithBody returns a new block with the original header and a deep copy of the +// provided body. +func (b *Block) WithBody(body Body) *Block { block := &Block{ header: b.header, - transactions: b.transactions, - uncles: b.uncles, + transactions: slices.Clone(body.Transactions), + uncles: make([]*Header, len(body.Uncles)), + withdrawals: slices.Clone(body.Withdrawals), } - if withdrawals != nil { - block.withdrawals = make([]*Withdrawal, len(withdrawals)) - copy(block.withdrawals, withdrawals) + for i := range body.Uncles { + block.uncles[i] = CopyHeader(body.Uncles[i]) } return block } diff --git a/core/types/block_test.go b/core/types/block_test.go index 982d002242f6..1af5b9d7bf2c 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -254,7 +254,7 @@ func makeBenchBlock() *Block { Extra: []byte("benchmark uncle"), } } - return NewBlock(header, txs, uncles, receipts, blocktest.NewHasher()) + return NewBlock(header, &Body{Transactions: txs, Uncles: uncles}, receipts, blocktest.NewHasher()) } func TestRlpDecodeParentHash(t *testing.T) { diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index b8645d6be49b..0586959f0633 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -779,7 +779,7 @@ func setBlockhash(data *engine.ExecutableData) *engine.ExecutableData { Extra: data.ExtraData, MixDigest: data.Random, } - block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */) + block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs}) data.BlockHash = block.Hash() return data } @@ -935,7 +935,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { Extra: data.ExtraData, MixDigest: data.Random, } - block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */) + block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs}) data.BlockHash = block.Hash() // Send the new payload resp2, err := api.NewPayloadV1(data) @@ -1554,7 +1554,7 @@ func TestBlockToPayloadWithBlobs(t *testing.T) { }, } - block := types.NewBlock(&header, txs, nil, nil, trie.NewStackTrie(nil)) + block := types.NewBlock(&header, &types.Body{Transactions: txs}, nil, trie.NewStackTrie(nil)) envelope := engine.BlockToExecutableData(block, nil, sidecars) var want int for _, tx := range txs { diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 941f575aa898..c5b56e91dda4 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -1504,7 +1504,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { ) blocks := make([]*types.Block, len(results)) for i, result := range results { - blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals) + blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.body()) } // Downloaded blocks are always regarded as trusted after the // transition. Because the downloaded chain is guided by the @@ -1726,7 +1726,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state blocks := make([]*types.Block, len(results)) receipts := make([]types.Receipts, len(results)) for i, result := range results { - blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals) + blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.body()) receipts[i] = result.Receipts } if index, err := d.blockchain.InsertReceiptChain(blocks, receipts, d.ancientLimit); err != nil { @@ -1737,7 +1737,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state } func (d *Downloader) commitPivotBlock(result *fetchResult) error { - block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals) + block := types.NewBlockWithHeader(result.Header).WithBody(result.body()) log.Debug("Committing snap sync pivot as new head", "number", block.Number(), "hash", block.Hash()) // Commit the pivot block as the new head, will require full sync from here on diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 6ff858d7553e..267c23407f43 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -87,6 +87,15 @@ func newFetchResult(header *types.Header, fastSync bool) *fetchResult { return item } +// body returns a representation of the fetch result as a types.Body object. +func (f *fetchResult) body() types.Body { + return types.Body{ + Transactions: f.Transactions, + Uncles: f.Uncles, + Withdrawals: f.Withdrawals, + } +} + // SetBodyDone flags the body as finished. func (f *fetchResult) SetBodyDone() { if v := f.pending.Load(); (v & (1 << bodyType)) != 0 { diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 5c3cb79dd65c..390f08567714 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -191,7 +191,12 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface } txs[i] = tx.tx } - return types.NewBlockWithHeader(head).WithBody(txs, uncles).WithWithdrawals(body.Withdrawals), nil + return types.NewBlockWithHeader(head).WithBody( + types.Body{ + Transactions: txs, + Uncles: uncles, + Withdrawals: body.Withdrawals, + }), nil } // HeaderByHash returns the block header with the given hash. diff --git a/internal/era/era.go b/internal/era/era.go index 2b9e6229018a..6ad7339b36a0 100644 --- a/internal/era/era.go +++ b/internal/era/era.go @@ -151,7 +151,7 @@ func (e *Era) GetBlockByNumber(num uint64) (*types.Block, error) { if err := rlp.Decode(r, &body); err != nil { return nil, err } - return types.NewBlockWithHeader(&header).WithBody(body.Transactions, body.Uncles), nil + return types.NewBlockWithHeader(&header).WithBody(body), nil } // Accumulator reads the accumulator entry in the Era1 file. diff --git a/internal/era/iterator.go b/internal/era/iterator.go index cc4f27c20190..f48aab46b4ec 100644 --- a/internal/era/iterator.go +++ b/internal/era/iterator.go @@ -73,7 +73,7 @@ func (it *Iterator) Block() (*types.Block, error) { if err := rlp.Decode(it.inner.Body, &body); err != nil { return nil, err } - return types.NewBlockWithHeader(&header).WithBody(body.Transactions, body.Uncles), nil + return types.NewBlockWithHeader(&header).WithBody(body), nil } // Receipts returns the receipts for the iterator's current position. diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 1f62d0c6bde3..a717ebdfae01 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -1348,7 +1348,7 @@ func TestRPCMarshalBlock(t *testing.T) { } txs = append(txs, tx) } - block := types.NewBlock(&types.Header{Number: big.NewInt(100)}, txs, nil, nil, blocktest.NewHasher()) + block := types.NewBlock(&types.Header{Number: big.NewInt(100)}, &types.Body{Transactions: txs}, nil, blocktest.NewHasher()) var testSuite = []struct { inclTx bool @@ -1559,7 +1559,7 @@ func TestRPCGetBlockOrHeader(t *testing.T) { Address: common.Address{0x12, 0x34}, Amount: 10, } - pending = types.NewBlockWithWithdrawals(&types.Header{Number: big.NewInt(11), Time: 42}, []*types.Transaction{tx}, nil, nil, []*types.Withdrawal{withdrawal}, blocktest.NewHasher()) + pending = types.NewBlock(&types.Header{Number: big.NewInt(11), Time: 42}, &types.Body{Transactions: types.Transactions{tx}, Withdrawals: types.Withdrawals{withdrawal}}, nil, blocktest.NewHasher()) ) backend := newTestBackend(t, genBlocks, genesis, ethash.NewFaker(), func(i int, b *core.BlockGen) { // Transfer from account[0] to account[1] diff --git a/miner/miner_test.go b/miner/miner_test.go index 7c39564240c1..da133ad8d0b6 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -78,7 +78,7 @@ func (bc *testBlockChain) CurrentBlock() *types.Header { } func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { - return types.NewBlock(bc.CurrentBlock(), nil, nil, nil, trie.NewStackTrie(nil)) + return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil)) } func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { From 45baf21111c03d2954c81fdf828e630a8d7b05c1 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 30 Apr 2024 06:46:53 -0700 Subject: [PATCH 236/571] eth/downloader: purge pre-merge sync code (#29281) This PR removes pre-merge sync logic from the downloader. Now-irrelevant tests are removed and others have been updated. --- eth/downloader/beaconsync.go | 6 +- eth/downloader/downloader.go | 872 ++---------------- eth/downloader/downloader_test.go | 836 +++-------------- eth/downloader/fetchers.go | 45 - eth/downloader/fetchers_concurrent.go | 34 +- eth/downloader/fetchers_concurrent_bodies.go | 1 - eth/downloader/fetchers_concurrent_headers.go | 97 -- eth/downloader/testchain_test.go | 1 - 8 files changed, 182 insertions(+), 1710 deletions(-) delete mode 100644 eth/downloader/fetchers_concurrent_headers.go diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 7dfc419f4e9c..8088f16af918 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -106,7 +106,7 @@ func (b *beaconBackfiller) resume() { }() // If the downloader fails, report an error as in beacon chain mode there // should be no errors as long as the chain we're syncing to is valid. - if err := b.downloader.synchronise("", common.Hash{}, nil, nil, mode, true, b.started); err != nil { + if err := b.downloader.synchronise(mode, b.started); err != nil { log.Error("Beacon backfilling failed", "err", err) return } @@ -268,9 +268,9 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { return start, nil } -// fetchBeaconHeaders feeds skeleton headers to the downloader queue for scheduling +// fetchHeaders feeds skeleton headers to the downloader queue for scheduling // until sync errors or is finished. -func (d *Downloader) fetchBeaconHeaders(from uint64) error { +func (d *Downloader) fetchHeaders(from uint64) error { var head *types.Header _, tail, _, err := d.skeleton.Bounds() if err != nil { diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index c5b56e91dda4..bb083260e459 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -41,17 +41,14 @@ import ( var ( MaxBlockFetch = 128 // Number of blocks to be fetched per retrieval request MaxHeaderFetch = 192 // Number of block headers to be fetched per retrieval request - MaxSkeletonSize = 128 // Number of header fetches needed for a skeleton assembly MaxReceiptFetch = 256 // Number of transaction receipts to allow fetching per request - maxQueuedHeaders = 32 * 1024 // [eth/62] Maximum number of headers to queue for import (DOS protection) - maxHeadersProcess = 2048 // Number of header download results to import at once into the chain - maxResultsProcess = 2048 // Number of content download results to import at once into the chain - fullMaxForkAncestry uint64 = params.FullImmutabilityThreshold // Maximum chain reorganisation (locally redeclared so tests can reduce it) - lightMaxForkAncestry uint64 = params.LightImmutabilityThreshold // Maximum chain reorganisation (locally redeclared so tests can reduce it) + maxQueuedHeaders = 32 * 1024 // [eth/62] Maximum number of headers to queue for import (DOS protection) + maxHeadersProcess = 2048 // Number of header download results to import at once into the chain + maxResultsProcess = 2048 // Number of content download results to import at once into the chain + fullMaxForkAncestry uint64 = params.FullImmutabilityThreshold // Maximum chain reorganisation (locally redeclared so tests can reduce it) - reorgProtThreshold = 48 // Threshold number of recent blocks to disable mini reorg protection - reorgProtHeaderDelay = 2 // Number of headers to delay delivering to cover mini reorgs + reorgProtHeaderDelay = 2 // Number of headers to delay delivering to cover mini reorgs fsHeaderSafetyNet = 2048 // Number of headers to discard in case a chain violation is detected fsHeaderContCheck = 3 * time.Second // Time interval to check for header continuations during state download @@ -59,24 +56,16 @@ var ( ) var ( - errBusy = errors.New("busy") - errUnknownPeer = errors.New("peer is unknown or unhealthy") - errBadPeer = errors.New("action from bad peer ignored") - errStallingPeer = errors.New("peer is stalling") - errUnsyncedPeer = errors.New("unsynced peer") - errNoPeers = errors.New("no peers to keep download active") + errBusy = errors.New("busy") + errBadPeer = errors.New("action from bad peer ignored") + errTimeout = errors.New("timeout") - errEmptyHeaderSet = errors.New("empty header set by peer") - 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") errInvalidBody = errors.New("retrieved block body is invalid") errInvalidReceipt = errors.New("retrieved receipt is invalid") errCancelStateFetch = errors.New("state data download canceled (requested)") errCancelContentProcessing = errors.New("content processing canceled (requested)") errCanceled = errors.New("syncing canceled (requested)") - errTooOld = errors.New("peer's protocol version too old") - errNoAncestorFound = errors.New("no common ancestor found") errNoPivotHeader = errors.New("pivot header is not found") ErrMergeTransition = errors.New("legacy sync reached the merge") ) @@ -99,9 +88,8 @@ type Downloader struct { mode atomic.Uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode mux *event.TypeMux // Event multiplexer to announce sync operation events - genesis uint64 // Genesis block number to limit sync to (e.g. light client CHT) - queue *queue // Scheduler for selecting the hashes to download - peers *peerSet // Set of active peers from which download can proceed + queue *queue // Scheduler for selecting the hashes to download + peers *peerSet // Set of active peers from which download can proceed stateDB ethdb.Database // Database to state sync into (and deduplicate via) @@ -118,11 +106,10 @@ type Downloader struct { badBlock badBlockFn // Reports a block as rejected by the chain // Status - synchroniseMock func(id string, hash common.Hash) error // Replacement for synchronise during testing - synchronising atomic.Bool - notified atomic.Bool - committed atomic.Bool - ancientLimit uint64 // The maximum block number which can be regarded as ancient data. + synchronising atomic.Bool + notified atomic.Bool + committed atomic.Bool + ancientLimit uint64 // The maximum block number which can be regarded as ancient data. // Channels headerProcCh chan *headerTask // Channel to feed the header processor new tasks @@ -138,7 +125,6 @@ type Downloader struct { stateSyncStart chan *stateSync // Cancellation and termination - cancelPeer string // Identifier of the peer currently being used as the master (cancel on drop) cancelCh chan struct{} // Channel to cancel mid-flight syncs cancelLock sync.RWMutex // Lock to protect the cancel channel and peer in delivers cancelWg sync.WaitGroup // Make sure all fetcher goroutines have exited. @@ -147,7 +133,6 @@ type Downloader struct { quitLock sync.Mutex // Lock to prevent double closes // Testing hooks - syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run bodyFetchHook func([]*types.Header) // Method to call upon starting a block body fetch receiptFetchHook func([]*types.Header) // Method to call upon starting a receipt fetch chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations) @@ -326,39 +311,10 @@ func (d *Downloader) UnregisterPeer(id string) error { return nil } -// LegacySync tries to sync up our local block chain with a remote peer, both -// adding various sanity checks as well as wrapping it with various log entries. -func (d *Downloader) LegacySync(id string, head common.Hash, td, ttd *big.Int, mode SyncMode) error { - err := d.synchronise(id, head, td, ttd, mode, false, nil) - - switch err { - case nil, errBusy, errCanceled: - return err - } - if errors.Is(err, errInvalidChain) || errors.Is(err, errBadPeer) || errors.Is(err, errTimeout) || - errors.Is(err, errStallingPeer) || errors.Is(err, errUnsyncedPeer) || errors.Is(err, errEmptyHeaderSet) || - errors.Is(err, errPeersUnavailable) || errors.Is(err, errTooOld) || errors.Is(err, errInvalidAncestor) { - log.Warn("Synchronisation failed, dropping peer", "peer", id, "err", err) - 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 - log.Warn("Downloader wants to drop peer, but peerdrop-function is not set", "peer", id) - } else { - d.dropPeer(id) - } - return err - } - if errors.Is(err, ErrMergeTransition) { - return err // This is an expected fault, don't keep printing it in a spin-loop - } - log.Warn("Synchronisation failed, retrying", "err", err) - return err -} - // synchronise will select the peer and use it for synchronising. If an empty string is given // it will use the best peer possible and synchronize if its TD is higher than our own. If any of the // checks fail an error will be returned. This method is synchronous -func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, mode SyncMode, beaconMode bool, beaconPing chan struct{}) error { +func (d *Downloader) synchronise(mode SyncMode, beaconPing chan struct{}) error { // The beacon header syncer is async. It will start this synchronization and // will continue doing other tasks. However, if synchronization needs to be // cancelled, the syncer needs to know if we reached the startup point (and @@ -373,10 +329,6 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, } }() } - // Mock out the synchronisation if testing - if d.synchroniseMock != nil { - return d.synchroniseMock(id, hash) - } // Make sure only one goroutine is ever allowed past this point at once if !d.synchronising.CompareAndSwap(false, true) { return errBusy @@ -424,7 +376,6 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, // Create cancel channel for aborting mid-flight and mark the master peer d.cancelLock.Lock() d.cancelCh = make(chan struct{}) - d.cancelPeer = id d.cancelLock.Unlock() defer d.Cancel() // No matter what, we can't leave the cancel channel open @@ -432,27 +383,19 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, // Atomically set the requested sync mode d.mode.Store(uint32(mode)) - // Retrieve the origin peer and initiate the downloading process - var p *peerConnection - if !beaconMode { // Beacon mode doesn't need a peer to sync from - p = d.peers.Peer(id) - if p == nil { - return errUnknownPeer - } - } if beaconPing != nil { close(beaconPing) } - return d.syncWithPeer(p, hash, td, ttd, beaconMode) + return d.syncToHead() } func (d *Downloader) getMode() SyncMode { return SyncMode(d.mode.Load()) } -// syncWithPeer starts a block synchronization based on the hash chain from the -// specified peer and head hash. -func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *big.Int, beaconMode bool) (err error) { +// syncToHead starts a block synchronization based on the hash chain from +// the specified head hash. +func (d *Downloader) syncToHead() (err error) { d.mux.Post(StartEvent{}) defer func() { // reset on error @@ -465,52 +408,39 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * }() mode := d.getMode() - if !beaconMode { - log.Debug("Synchronising with the network", "peer", p.id, "eth", p.version, "head", hash, "td", td, "mode", mode) - } else { - log.Debug("Backfilling with the network", "mode", mode) - } + log.Debug("Backfilling with the network", "mode", mode) defer func(start time.Time) { log.Debug("Synchronisation terminated", "elapsed", common.PrettyDuration(time.Since(start))) }(time.Now()) // Look up the sync boundaries: the common ancestor and the target block var latest, pivot, final *types.Header - if !beaconMode { - // In legacy mode, use the master peer to retrieve the headers from - latest, pivot, err = d.fetchHead(p) - if err != nil { - return err - } - } else { - // In beacon mode, use the skeleton chain to retrieve the headers from - latest, _, final, err = d.skeleton.Bounds() - if err != nil { - return err - } - if latest.Number.Uint64() > uint64(fsMinFullBlocks) { - number := latest.Number.Uint64() - uint64(fsMinFullBlocks) - - // Retrieve the pivot header from the skeleton chain segment but - // fallback to local chain if it's not found in skeleton space. - if pivot = d.skeleton.Header(number); pivot == nil { - _, oldest, _, _ := d.skeleton.Bounds() // error is already checked - if number < oldest.Number.Uint64() { - count := int(oldest.Number.Uint64() - number) // it's capped by fsMinFullBlocks - headers := d.readHeaderRange(oldest, count) - if len(headers) == count { - pivot = headers[len(headers)-1] - log.Warn("Retrieved pivot header from local", "number", pivot.Number, "hash", pivot.Hash(), "latest", latest.Number, "oldest", oldest.Number) - } + latest, _, final, err = d.skeleton.Bounds() + if err != nil { + return err + } + if latest.Number.Uint64() > uint64(fsMinFullBlocks) { + number := latest.Number.Uint64() - uint64(fsMinFullBlocks) + + // Retrieve the pivot header from the skeleton chain segment but + // fallback to local chain if it's not found in skeleton space. + if pivot = d.skeleton.Header(number); pivot == nil { + _, oldest, _, _ := d.skeleton.Bounds() // error is already checked + if number < oldest.Number.Uint64() { + count := int(oldest.Number.Uint64() - number) // it's capped by fsMinFullBlocks + headers := d.readHeaderRange(oldest, count) + if len(headers) == count { + pivot = headers[len(headers)-1] + log.Warn("Retrieved pivot header from local", "number", pivot.Number, "hash", pivot.Hash(), "latest", latest.Number, "oldest", oldest.Number) } } - // Print an error log and return directly in case the pivot header - // is still not found. It means the skeleton chain is not linked - // correctly with local chain. - if pivot == nil { - log.Error("Pivot header is not found", "number", number) - return errNoPivotHeader - } + } + // Print an error log and return directly in case the pivot header + // is still not found. It means the skeleton chain is not linked + // correctly with local chain. + if pivot == nil { + log.Error("Pivot header is not found", "number", number) + return errNoPivotHeader } } // If no pivot block was returned, the head is below the min full block @@ -522,19 +452,10 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * } height := latest.Number.Uint64() - var origin uint64 - if !beaconMode { - // In legacy mode, reach out to the network and find the ancestor - origin, err = d.findAncestor(p, latest) - if err != nil { - return err - } - } else { - // In beacon mode, use the skeleton chain for the ancestor lookup - origin, err = d.findBeaconAncestor() - if err != nil { - return err - } + // In beacon mode, use the skeleton chain for the ancestor lookup + origin, err := d.findBeaconAncestor() + if err != nil { + return err } d.syncStatsLock.Lock() if d.syncStatsChainHeight <= origin || d.syncStatsChainOrigin > origin { @@ -577,24 +498,15 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * // the ancientLimit through that. Otherwise calculate the ancient limit through // the advertised height of the remote peer. This most is mostly a fallback for // legacy networks, but should eventually be dropped. TODO(karalabe). - if beaconMode { - // Beacon sync, use the latest finalized block as the ancient limit - // or a reasonable height if no finalized block is yet announced. - if final != nil { - d.ancientLimit = final.Number.Uint64() - } else if height > fullMaxForkAncestry+1 { - d.ancientLimit = height - fullMaxForkAncestry - 1 - } else { - d.ancientLimit = 0 - } + // + // Beacon sync, use the latest finalized block as the ancient limit + // or a reasonable height if no finalized block is yet announced. + if final != nil { + d.ancientLimit = final.Number.Uint64() + } else if height > fullMaxForkAncestry+1 { + d.ancientLimit = height - fullMaxForkAncestry - 1 } else { - // Legacy sync, use the best announcement we have from the remote peer. - // TODO(karalabe): Drop this pathway. - if height > fullMaxForkAncestry+1 { - d.ancientLimit = height - fullMaxForkAncestry - 1 - } else { - d.ancientLimit = 0 - } + d.ancientLimit = 0 } frozen, _ := d.stateDB.Ancients() // Ignore the error here since light client can also hit here. @@ -616,22 +528,13 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * } // Initiate the sync using a concurrent header and content retrieval algorithm d.queue.Prepare(origin+1, mode) - if d.syncInitHook != nil { - d.syncInitHook(origin, height) - } - var headerFetcher func() error - if !beaconMode { - // In legacy mode, headers are retrieved from the network - headerFetcher = func() error { return d.fetchHeaders(p, origin+1, latest.Number.Uint64()) } - } else { - // In beacon mode, headers are served by the skeleton syncer - headerFetcher = func() error { return d.fetchBeaconHeaders(origin + 1) } - } + + // In beacon mode, headers are served by the skeleton syncer fetchers := []func() error{ - headerFetcher, // Headers are always retrieved - func() error { return d.fetchBodies(origin+1, beaconMode) }, // Bodies are retrieved during normal and snap sync - func() error { return d.fetchReceipts(origin+1, beaconMode) }, // Receipts are retrieved during snap sync - func() error { return d.processHeaders(origin+1, td, ttd, beaconMode) }, + func() error { return d.fetchHeaders(origin + 1) }, // Headers are always retrieved + func() error { return d.fetchBodies(origin + 1) }, // Bodies are retrieved during normal and snap sync + func() error { return d.fetchReceipts(origin + 1) }, // Receipts are retrieved during snap sync + func() error { return d.processHeaders(origin + 1) }, } if mode == SnapSync { d.pivotLock.Lock() @@ -640,7 +543,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * fetchers = append(fetchers, func() error { return d.processSnapSyncContent() }) } else if mode == FullSync { - fetchers = append(fetchers, func() error { return d.processFullSyncContent(ttd, beaconMode) }) + fetchers = append(fetchers, func() error { return d.processFullSyncContent() }) } return d.spawnSync(fetchers) } @@ -719,540 +622,12 @@ func (d *Downloader) Terminate() { d.Cancel() } -// fetchHead retrieves the head header and prior pivot block (if available) from -// a remote peer. -func (d *Downloader) fetchHead(p *peerConnection) (head *types.Header, pivot *types.Header, err error) { - p.log.Debug("Retrieving remote chain head") - mode := d.getMode() - - // Request the advertised remote head block and wait for the response - latest, _ := p.peer.Head() - fetch := 1 - if mode == SnapSync { - fetch = 2 // head + pivot headers - } - headers, hashes, err := d.fetchHeadersByHash(p, latest, fetch, fsMinFullBlocks-1, true) - if err != nil { - return nil, nil, err - } - // Make sure the peer gave us at least one and at most the requested headers - if len(headers) == 0 || len(headers) > fetch { - return nil, nil, fmt.Errorf("%w: returned headers %d != requested %d", errBadPeer, len(headers), fetch) - } - // The first header needs to be the head, validate against the request. If - // only 1 header was returned, make sure there's no pivot or there was not - // one requested. - head = headers[0] - if len(headers) == 1 { - if mode == SnapSync && head.Number.Uint64() > uint64(fsMinFullBlocks) { - return nil, nil, fmt.Errorf("%w: no pivot included along head header", errBadPeer) - } - p.log.Debug("Remote head identified, no pivot", "number", head.Number, "hash", hashes[0]) - return head, nil, nil - } - // At this point we have 2 headers in total and the first is the - // validated head of the chain. Check the pivot number and return, - pivot = headers[1] - if pivot.Number.Uint64() != head.Number.Uint64()-uint64(fsMinFullBlocks) { - return nil, nil, fmt.Errorf("%w: remote pivot %d != requested %d", errInvalidChain, pivot.Number, head.Number.Uint64()-uint64(fsMinFullBlocks)) - } - return head, pivot, nil -} - -// calculateRequestSpan calculates what headers to request from a peer when trying to determine the -// common ancestor. -// It returns parameters to be used for peer.RequestHeadersByNumber: -// -// from - starting block number -// count - number of headers to request -// skip - number of headers to skip -// -// and also returns 'max', the last block which is expected to be returned by the remote peers, -// given the (from,count,skip) -func calculateRequestSpan(remoteHeight, localHeight uint64) (int64, int, int, uint64) { - var ( - from int - count int - MaxCount = MaxHeaderFetch / 16 - ) - // requestHead is the highest block that we will ask for. If requestHead is not offset, - // the highest block that we will get is 16 blocks back from head, which means we - // will fetch 14 or 15 blocks unnecessarily in the case the height difference - // between us and the peer is 1-2 blocks, which is most common - requestHead := int(remoteHeight) - 1 - if requestHead < 0 { - requestHead = 0 - } - // requestBottom is the lowest block we want included in the query - // Ideally, we want to include the one just below our own head - requestBottom := int(localHeight - 1) - if requestBottom < 0 { - requestBottom = 0 - } - totalSpan := requestHead - requestBottom - span := 1 + totalSpan/MaxCount - if span < 2 { - span = 2 - } - if span > 16 { - span = 16 - } - - count = 1 + totalSpan/span - if count > MaxCount { - count = MaxCount - } - if count < 2 { - count = 2 - } - from = requestHead - (count-1)*span - if from < 0 { - from = 0 - } - max := from + (count-1)*span - return int64(from), count, span - 1, uint64(max) -} - -// findAncestor tries to locate the common ancestor link of the local chain and -// a remote peers blockchain. In the general case when our node was in sync and -// on the correct chain, checking the top N links should already get us a match. -// In the rare scenario when we ended up on a long reorganisation (i.e. none of -// the head links match), we do a binary search to find the common ancestor. -func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) { - // Figure out the valid ancestor range to prevent rewrite attacks - var ( - floor = int64(-1) - localHeight uint64 - remoteHeight = remoteHeader.Number.Uint64() - ) - mode := d.getMode() - switch mode { - case FullSync: - localHeight = d.blockchain.CurrentBlock().Number.Uint64() - case SnapSync: - localHeight = d.blockchain.CurrentSnapBlock().Number.Uint64() - default: - localHeight = d.lightchain.CurrentHeader().Number.Uint64() - } - p.log.Debug("Looking for common ancestor", "local", localHeight, "remote", remoteHeight) - - // Recap floor value for binary search - maxForkAncestry := fullMaxForkAncestry - if d.getMode() == LightSync { - maxForkAncestry = lightMaxForkAncestry - } - if localHeight >= maxForkAncestry { - // We're above the max reorg threshold, find the earliest fork point - floor = int64(localHeight - maxForkAncestry) - } - // If we're doing a light sync, ensure the floor doesn't go below the CHT, as - // all headers before that point will be missing. - if mode == LightSync { - // If we don't know the current CHT position, find it - if d.genesis == 0 { - header := d.lightchain.CurrentHeader() - for header != nil { - d.genesis = header.Number.Uint64() - if floor >= int64(d.genesis)-1 { - break - } - header = d.lightchain.GetHeaderByHash(header.ParentHash) - } - } - // We already know the "genesis" block number, cap floor to that - if floor < int64(d.genesis)-1 { - floor = int64(d.genesis) - 1 - } - } - - ancestor, err := d.findAncestorSpanSearch(p, mode, remoteHeight, localHeight, floor) - if err == nil { - return ancestor, nil - } - // The returned error was not nil. - // If the error returned does not reflect that a common ancestor was not found, return it. - // If the error reflects that a common ancestor was not found, continue to binary search, - // where the error value will be reassigned. - if !errors.Is(err, errNoAncestorFound) { - return 0, err - } - - ancestor, err = d.findAncestorBinarySearch(p, mode, remoteHeight, floor) - if err != nil { - return 0, err - } - return ancestor, nil -} - -func (d *Downloader) findAncestorSpanSearch(p *peerConnection, mode SyncMode, remoteHeight, localHeight uint64, floor int64) (uint64, error) { - from, count, skip, max := calculateRequestSpan(remoteHeight, localHeight) - - p.log.Trace("Span searching for common ancestor", "count", count, "from", from, "skip", skip) - headers, hashes, err := d.fetchHeadersByNumber(p, uint64(from), count, skip, false) - if err != nil { - return 0, err - } - // Wait for the remote response to the head fetch - number, hash := uint64(0), common.Hash{} - - // Make sure the peer actually gave something valid - if len(headers) == 0 { - p.log.Warn("Empty head header set") - return 0, errEmptyHeaderSet - } - // Make sure the peer's reply conforms to the request - for i, header := range headers { - expectNumber := from + int64(i)*int64(skip+1) - if number := header.Number.Int64(); number != expectNumber { - p.log.Warn("Head headers broke chain ordering", "index", i, "requested", expectNumber, "received", number) - return 0, fmt.Errorf("%w: %v", errInvalidChain, errors.New("head headers broke chain ordering")) - } - } - // Check if a common ancestor was found - for i := len(headers) - 1; i >= 0; i-- { - // Skip any headers that underflow/overflow our requested set - if headers[i].Number.Int64() < from || headers[i].Number.Uint64() > max { - continue - } - // Otherwise check if we already know the header or not - h := hashes[i] - n := headers[i].Number.Uint64() - - var known bool - switch mode { - case FullSync: - known = d.blockchain.HasBlock(h, n) - case SnapSync: - known = d.blockchain.HasFastBlock(h, n) - default: - known = d.lightchain.HasHeader(h, n) - } - if known { - number, hash = n, h - break - } - } - // If the head fetch already found an ancestor, return - if hash != (common.Hash{}) { - if int64(number) <= floor { - p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor) - return 0, errInvalidAncestor - } - p.log.Debug("Found common ancestor", "number", number, "hash", hash) - return number, nil - } - return 0, errNoAncestorFound -} - -func (d *Downloader) findAncestorBinarySearch(p *peerConnection, mode SyncMode, remoteHeight uint64, floor int64) (uint64, error) { - hash := common.Hash{} - - // Ancestor not found, we need to binary search over our chain - start, end := uint64(0), remoteHeight - if floor > 0 { - start = uint64(floor) - } - p.log.Trace("Binary searching for common ancestor", "start", start, "end", end) - - for start+1 < end { - // Split our chain interval in two, and request the hash to cross check - check := (start + end) / 2 - - headers, hashes, err := d.fetchHeadersByNumber(p, check, 1, 0, false) - if err != nil { - return 0, err - } - // Make sure the peer actually gave something valid - if len(headers) != 1 { - p.log.Warn("Multiple headers for single request", "headers", len(headers)) - return 0, fmt.Errorf("%w: multiple headers (%d) for single request", errBadPeer, len(headers)) - } - // Modify the search interval based on the response - h := hashes[0] - n := headers[0].Number.Uint64() - - var known bool - switch mode { - case FullSync: - known = d.blockchain.HasBlock(h, n) - case SnapSync: - known = d.blockchain.HasFastBlock(h, n) - default: - known = d.lightchain.HasHeader(h, n) - } - if !known { - end = check - continue - } - header := d.lightchain.GetHeaderByHash(h) // Independent of sync mode, header surely exists - if header.Number.Uint64() != check { - p.log.Warn("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check) - return 0, fmt.Errorf("%w: non-requested header (%d)", errBadPeer, header.Number) - } - start = check - hash = h - } - // Ensure valid ancestry and return - if int64(start) <= floor { - p.log.Warn("Ancestor below allowance", "number", start, "hash", hash, "allowance", floor) - return 0, errInvalidAncestor - } - p.log.Debug("Found common ancestor", "number", start, "hash", hash) - return start, nil -} - -// fetchHeaders keeps retrieving headers concurrently from the number -// requested, until no more are returned, potentially throttling on the way. To -// facilitate concurrency but still protect against malicious nodes sending bad -// headers, we construct a header chain skeleton using the "origin" peer we are -// syncing with, and fill in the missing headers using anyone else. Headers from -// other peers are only accepted if they map cleanly to the skeleton. If no one -// can fill in the skeleton - not even the origin peer - it's assumed invalid and -// the origin is dropped. -func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, head uint64) error { - p.log.Debug("Directing header downloads", "origin", from) - defer p.log.Debug("Header download terminated") - - // Start pulling the header chain skeleton until all is done - var ( - skeleton = true // Skeleton assembly phase or finishing up - pivoting = false // Whether the next request is pivot verification - ancestor = from - mode = d.getMode() - ) - for { - // Pull the next batch of headers, it either: - // - Pivot check to see if the chain moved too far - // - Skeleton retrieval to permit concurrent header fetches - // - Full header retrieval if we're near the chain head - var ( - headers []*types.Header - hashes []common.Hash - err error - ) - switch { - case pivoting: - d.pivotLock.RLock() - pivot := d.pivotHeader.Number.Uint64() - d.pivotLock.RUnlock() - - p.log.Trace("Fetching next pivot header", "number", pivot+uint64(fsMinFullBlocks)) - headers, hashes, err = d.fetchHeadersByNumber(p, pivot+uint64(fsMinFullBlocks), 2, fsMinFullBlocks-9, false) // move +64 when it's 2x64-8 deep - - case skeleton: - p.log.Trace("Fetching skeleton headers", "count", MaxHeaderFetch, "from", from) - headers, hashes, err = d.fetchHeadersByNumber(p, from+uint64(MaxHeaderFetch)-1, MaxSkeletonSize, MaxHeaderFetch-1, false) - - default: - p.log.Trace("Fetching full headers", "count", MaxHeaderFetch, "from", from) - headers, hashes, err = d.fetchHeadersByNumber(p, from, MaxHeaderFetch, 0, false) - } - switch err { - case nil: - // Headers retrieved, continue with processing - - case errCanceled: - // Sync cancelled, no issue, propagate up - return err - - default: - // Header retrieval either timed out, or the peer failed in some strange way - // (e.g. disconnect). Consider the master peer bad and drop - d.dropPeer(p.id) - - // Finish the sync gracefully instead of dumping the gathered data though - for _, ch := range []chan bool{d.queue.blockWakeCh, d.queue.receiptWakeCh} { - select { - case ch <- false: - case <-d.cancelCh: - } - } - select { - case d.headerProcCh <- nil: - case <-d.cancelCh: - } - return fmt.Errorf("%w: header request failed: %v", errBadPeer, err) - } - // If the pivot is being checked, move if it became stale and run the real retrieval - var pivot uint64 - - d.pivotLock.RLock() - if d.pivotHeader != nil { - pivot = d.pivotHeader.Number.Uint64() - } - d.pivotLock.RUnlock() - - if pivoting { - if len(headers) == 2 { - if have, want := headers[0].Number.Uint64(), pivot+uint64(fsMinFullBlocks); have != want { - log.Warn("Peer sent invalid next pivot", "have", have, "want", want) - return fmt.Errorf("%w: next pivot number %d != requested %d", errInvalidChain, have, want) - } - if have, want := headers[1].Number.Uint64(), pivot+2*uint64(fsMinFullBlocks)-8; have != want { - log.Warn("Peer sent invalid pivot confirmer", "have", have, "want", want) - return fmt.Errorf("%w: next pivot confirmer number %d != requested %d", errInvalidChain, have, want) - } - log.Warn("Pivot seemingly stale, moving", "old", pivot, "new", headers[0].Number) - pivot = headers[0].Number.Uint64() - - d.pivotLock.Lock() - d.pivotHeader = headers[0] - d.pivotLock.Unlock() - - // Write out the pivot into the database so a rollback beyond - // it will reenable snap sync and update the state root that - // the state syncer will be downloading. - rawdb.WriteLastPivotNumber(d.stateDB, pivot) - } - // Disable the pivot check and fetch the next batch of headers - pivoting = false - continue - } - // If the skeleton's finished, pull any remaining head headers directly from the origin - if skeleton && len(headers) == 0 { - // A malicious node might withhold advertised headers indefinitely - if from+uint64(MaxHeaderFetch)-1 <= head { - p.log.Warn("Peer withheld skeleton headers", "advertised", head, "withheld", from+uint64(MaxHeaderFetch)-1) - return fmt.Errorf("%w: withheld skeleton headers: advertised %d, withheld #%d", errStallingPeer, head, from+uint64(MaxHeaderFetch)-1) - } - p.log.Debug("No skeleton, fetching headers directly") - skeleton = false - continue - } - // If no more headers are inbound, notify the content fetchers and return - if len(headers) == 0 { - // Don't abort header fetches while the pivot is downloading - if !d.committed.Load() && pivot <= from { - p.log.Debug("No headers, waiting for pivot commit") - select { - case <-time.After(fsHeaderContCheck): - continue - case <-d.cancelCh: - return errCanceled - } - } - // Pivot done (or not in snap sync) and no more headers, terminate the process - p.log.Debug("No more headers available") - select { - case d.headerProcCh <- nil: - return nil - case <-d.cancelCh: - return errCanceled - } - } - // If we received a skeleton batch, resolve internals concurrently - var progressed bool - if skeleton { - filled, hashset, proced, err := d.fillHeaderSkeleton(from, headers) - if err != nil { - p.log.Debug("Skeleton chain invalid", "err", err) - return fmt.Errorf("%w: %v", errInvalidChain, err) - } - headers = filled[proced:] - hashes = hashset[proced:] - - progressed = proced > 0 - from += uint64(proced) - } else { - // A malicious node might withhold advertised headers indefinitely - if n := len(headers); n < MaxHeaderFetch && headers[n-1].Number.Uint64() < head { - p.log.Warn("Peer withheld headers", "advertised", head, "delivered", headers[n-1].Number.Uint64()) - return fmt.Errorf("%w: withheld headers: advertised %d, delivered %d", errStallingPeer, head, headers[n-1].Number.Uint64()) - } - // If we're closing in on the chain head, but haven't yet reached it, delay - // the last few headers so mini reorgs on the head don't cause invalid hash - // chain errors. - if n := len(headers); n > 0 { - // Retrieve the current head we're at - var head uint64 - if mode == LightSync { - head = d.lightchain.CurrentHeader().Number.Uint64() - } else { - head = d.blockchain.CurrentSnapBlock().Number.Uint64() - if full := d.blockchain.CurrentBlock().Number.Uint64(); head < full { - head = full - } - } - // If the head is below the common ancestor, we're actually deduplicating - // already existing chain segments, so use the ancestor as the fake head. - // Otherwise, we might end up delaying header deliveries pointlessly. - if head < ancestor { - head = ancestor - } - // If the head is way older than this batch, delay the last few headers - if head+uint64(reorgProtThreshold) < headers[n-1].Number.Uint64() { - delay := reorgProtHeaderDelay - if delay > n { - delay = n - } - headers = headers[:n-delay] - hashes = hashes[:n-delay] - } - } - } - // If no headers have been delivered, or all of them have been delayed, - // sleep a bit and retry. Take care with headers already consumed during - // skeleton filling - if len(headers) == 0 && !progressed { - p.log.Trace("All headers delayed, waiting") - select { - case <-time.After(fsHeaderContCheck): - continue - case <-d.cancelCh: - return errCanceled - } - } - // Insert any remaining new headers and fetch the next batch - if len(headers) > 0 { - p.log.Trace("Scheduling new headers", "count", len(headers), "from", from) - select { - case d.headerProcCh <- &headerTask{ - headers: headers, - hashes: hashes, - }: - case <-d.cancelCh: - return errCanceled - } - from += uint64(len(headers)) - } - // If we're still skeleton filling snap sync, check pivot staleness - // before continuing to the next skeleton filling - if skeleton && pivot > 0 { - pivoting = true - } - } -} - -// fillHeaderSkeleton concurrently retrieves headers from all our available peers -// and maps them to the provided skeleton header chain. -// -// Any partial results from the beginning of the skeleton is (if possible) forwarded -// immediately to the header processor to keep the rest of the pipeline full even -// in the case of header stalls. -// -// The method returns the entire filled skeleton and also the number of headers -// already forwarded for processing. -func (d *Downloader) fillHeaderSkeleton(from uint64, skeleton []*types.Header) ([]*types.Header, []common.Hash, int, error) { - log.Debug("Filling up skeleton", "from", from) - d.queue.ScheduleSkeleton(from, skeleton) - - err := d.concurrentFetch((*headerQueue)(d), false) - if err != nil { - log.Debug("Skeleton fill failed", "err", err) - } - filled, hashes, proced := d.queue.RetrieveHeaders() - if err == nil { - log.Debug("Skeleton fill succeeded", "filled", len(filled), "processed", proced) - } - return filled, hashes, proced, err -} - // fetchBodies iteratively downloads the scheduled block bodies, taking any // available peers, reserving a chunk of blocks for each, waiting for delivery // and also periodically checking for timeouts. -func (d *Downloader) fetchBodies(from uint64, beaconMode bool) error { +func (d *Downloader) fetchBodies(from uint64) error { log.Debug("Downloading block bodies", "origin", from) - err := d.concurrentFetch((*bodyQueue)(d), beaconMode) + err := d.concurrentFetch((*bodyQueue)(d)) log.Debug("Block body download terminated", "err", err) return err @@ -1261,9 +636,9 @@ func (d *Downloader) fetchBodies(from uint64, beaconMode bool) error { // fetchReceipts iteratively downloads the scheduled block receipts, taking any // available peers, reserving a chunk of receipts for each, waiting for delivery // and also periodically checking for timeouts. -func (d *Downloader) fetchReceipts(from uint64, beaconMode bool) error { +func (d *Downloader) fetchReceipts(from uint64) error { log.Debug("Downloading receipts", "origin", from) - err := d.concurrentFetch((*receiptQueue)(d), beaconMode) + err := d.concurrentFetch((*receiptQueue)(d)) log.Debug("Receipt download terminated", "err", err) return err @@ -1272,11 +647,10 @@ func (d *Downloader) fetchReceipts(from uint64, beaconMode bool) error { // processHeaders takes batches of retrieved headers from an input channel and // keeps processing and scheduling them into the header chain and downloader's // queue until the stream ends or a failure occurs. -func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode bool) error { +func (d *Downloader) processHeaders(origin uint64) error { var ( - mode = d.getMode() - gotHeaders = false // Wait for batches of headers to process - timer = time.NewTimer(time.Second) + mode = d.getMode() + timer = time.NewTimer(time.Second) ) defer timer.Stop() @@ -1295,48 +669,11 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode case <-d.cancelCh: } } - // If we're in legacy sync mode, we need to check total difficulty - // violations from malicious peers. That is not needed in beacon - // mode and we can skip to terminating sync. - if !beaconMode { - // If no headers were retrieved at all, the peer violated its TD promise that it had a - // better chain compared to ours. The only exception is if its promised blocks were - // already imported by other means (e.g. fetcher): - // - // R , L : Both at block 10 - // R: Mine block 11, and propagate it to L - // L: Queue block 11 for import - // L: Notice that R's head and TD increased compared to ours, start sync - // L: Import of block 11 finishes - // L: Sync begins, and finds common ancestor at 11 - // L: Request new headers up from 11 (R's TD was higher, it must have something) - // R: Nothing to give - if mode != LightSync { - head := d.blockchain.CurrentBlock() - if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.Number.Uint64())) > 0 { - return errStallingPeer - } - } - // If snap or light syncing, ensure promised headers are indeed delivered. This is - // needed to detect scenarios where an attacker feeds a bad pivot and then bails out - // of delivering the post-pivot blocks that would flag the invalid content. - // - // This check cannot be executed "as is" for full imports, since blocks may still be - // queued for processing when the header download completes. However, as long as the - // peer gave us something useful, we're already happy/progressed (above check). - if mode == SnapSync || mode == LightSync { - head := d.lightchain.CurrentHeader() - if td.Cmp(d.lightchain.GetTd(head.Hash(), head.Number.Uint64())) > 0 { - return errStallingPeer - } - } - } return nil } // Otherwise split the chunk of headers into batches and process them headers, hashes := task.headers, task.hashes - gotHeaders = true for len(headers) > 0 { // Terminate if something failed in between processing chunks select { @@ -1357,44 +694,12 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode // Although the received headers might be all valid, a legacy // PoW/PoA sync must not accept post-merge headers. Make sure // that any transition is rejected at this point. - var ( - rejected []*types.Header - td *big.Int - ) - if !beaconMode && ttd != nil { - td = d.blockchain.GetTd(chunkHeaders[0].ParentHash, chunkHeaders[0].Number.Uint64()-1) - if td == nil { - // This should never really happen, but handle gracefully for now - log.Error("Failed to retrieve parent header TD", "number", chunkHeaders[0].Number.Uint64()-1, "hash", chunkHeaders[0].ParentHash) - return fmt.Errorf("%w: parent TD missing", errInvalidChain) - } - for i, header := range chunkHeaders { - td = new(big.Int).Add(td, header.Difficulty) - if td.Cmp(ttd) >= 0 { - // Terminal total difficulty reached, allow the last header in - if new(big.Int).Sub(td, header.Difficulty).Cmp(ttd) < 0 { - chunkHeaders, rejected = chunkHeaders[:i+1], chunkHeaders[i+1:] - if len(rejected) > 0 { - // Make a nicer user log as to the first TD truly rejected - td = new(big.Int).Add(td, rejected[0].Difficulty) - } - } else { - chunkHeaders, rejected = chunkHeaders[:i], chunkHeaders[i:] - } - break - } - } - } if len(chunkHeaders) > 0 { if n, err := d.lightchain.InsertHeaderChain(chunkHeaders); err != nil { log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err) return fmt.Errorf("%w: %v", errInvalidChain, err) } } - if len(rejected) != 0 { - log.Info("Legacy sync reached merge threshold", "number", rejected[0].Number, "hash", rejected[0].Hash(), "td", td, "ttd", ttd) - return ErrMergeTransition - } } // Unless we're doing light chains, schedule the headers for associated content retrieval if mode == FullSync || mode == SnapSync { @@ -1436,7 +741,7 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode } // processFullSyncContent takes fetch results from the queue and imports them into the chain. -func (d *Downloader) processFullSyncContent(ttd *big.Int, beaconMode bool) error { +func (d *Downloader) processFullSyncContent() error { for { results := d.queue.Results(true) if len(results) == 0 { @@ -1445,44 +750,9 @@ func (d *Downloader) processFullSyncContent(ttd *big.Int, beaconMode bool) error if d.chainInsertHook != nil { d.chainInsertHook(results) } - // Although the received blocks might be all valid, a legacy PoW/PoA sync - // must not accept post-merge blocks. Make sure that pre-merge blocks are - // imported, but post-merge ones are rejected. - var ( - rejected []*fetchResult - td *big.Int - ) - if !beaconMode && ttd != nil { - td = d.blockchain.GetTd(results[0].Header.ParentHash, results[0].Header.Number.Uint64()-1) - if td == nil { - // This should never really happen, but handle gracefully for now - log.Error("Failed to retrieve parent block TD", "number", results[0].Header.Number.Uint64()-1, "hash", results[0].Header.ParentHash) - return fmt.Errorf("%w: parent TD missing", errInvalidChain) - } - for i, result := range results { - td = new(big.Int).Add(td, result.Header.Difficulty) - if td.Cmp(ttd) >= 0 { - // Terminal total difficulty reached, allow the last block in - if new(big.Int).Sub(td, result.Header.Difficulty).Cmp(ttd) < 0 { - results, rejected = results[:i+1], results[i+1:] - if len(rejected) > 0 { - // Make a nicer user log as to the first TD truly rejected - td = new(big.Int).Add(td, rejected[0].Header.Difficulty) - } - } else { - results, rejected = results[:i], results[i:] - } - break - } - } - } if err := d.importBlockResults(results); err != nil { return err } - if len(rejected) != 0 { - log.Info("Legacy sync reached merge threshold", "number", rejected[0].Header.Number, "hash", rejected[0].Header.Hash(), "td", td, "ttd", ttd) - return ErrMergeTransition - } } } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index c810518d56ae..92403277fd5f 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -20,7 +20,6 @@ import ( "fmt" "math/big" "os" - "strings" "sync" "sync/atomic" "testing" @@ -94,35 +93,16 @@ func (dl *downloadTester) terminate() { os.RemoveAll(dl.freezer) } -// sync starts synchronizing with a remote peer, blocking until it completes. -func (dl *downloadTester) sync(id string, td *big.Int, mode SyncMode) error { - head := dl.peers[id].chain.CurrentBlock() - if td == nil { - // If no particular TD was requested, load from the peer's blockchain - td = dl.peers[id].chain.GetTd(head.Hash(), head.Number.Uint64()) - } - // Synchronise with the chosen peer and ensure proper cleanup afterwards - err := dl.downloader.synchronise(id, head.Hash(), td, nil, mode, false, nil) - select { - case <-dl.downloader.cancelCh: - // Ok, downloader fully cancelled after sync cycle - default: - // Downloader is still accepting packets, can block a peer up - panic("downloader active post sync cycle") // panic will be caught by tester - } - return err -} - // newPeer registers a new block download source into the downloader. func (dl *downloadTester) newPeer(id string, version uint, blocks []*types.Block) *downloadTesterPeer { dl.lock.Lock() defer dl.lock.Unlock() peer := &downloadTesterPeer{ - dl: dl, - id: id, - chain: newTestBlockchain(blocks), - withholdHeaders: make(map[common.Hash]struct{}), + dl: dl, + id: id, + chain: newTestBlockchain(blocks), + withholdBodies: make(map[common.Hash]struct{}), } dl.peers[id] = peer @@ -146,11 +126,10 @@ func (dl *downloadTester) dropPeer(id string) { } type downloadTesterPeer struct { - dl *downloadTester - id string - chain *core.BlockChain - - withholdHeaders map[common.Hash]struct{} + dl *downloadTester + withholdBodies map[common.Hash]struct{} + id string + chain *core.BlockChain } // Head constructs a function to retrieve a peer's current head hash @@ -186,15 +165,6 @@ func (dlp *downloadTesterPeer) RequestHeadersByHash(origin common.Hash, amount i Reverse: reverse, }, nil) headers := unmarshalRlpHeaders(rlpHeaders) - // If a malicious peer is simulated withholding headers, delete them - for hash := range dlp.withholdHeaders { - for i, header := range headers { - if header.Hash() == hash { - headers = append(headers[:i], headers[i+1:]...) - break - } - } - } hashes := make([]common.Hash, len(headers)) for i, header := range headers { hashes[i] = header.Hash() @@ -230,15 +200,6 @@ func (dlp *downloadTesterPeer) RequestHeadersByNumber(origin uint64, amount int, Reverse: reverse, }, nil) headers := unmarshalRlpHeaders(rlpHeaders) - // If a malicious peer is simulated withholding headers, delete them - for hash := range dlp.withholdHeaders { - for i, header := range headers { - if header.Hash() == hash { - headers = append(headers[:i], headers[i+1:]...) - break - } - } - } hashes := make([]common.Hash, len(headers)) for i, header := range headers { hashes[i] = header.Hash() @@ -278,7 +239,13 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et ) hasher := trie.NewStackTrie(nil) for i, body := range bodies { - txsHashes[i] = types.DeriveSha(types.Transactions(body.Transactions), hasher) + hash := types.DeriveSha(types.Transactions(body.Transactions), hasher) + if _, ok := dlp.withholdBodies[hash]; ok { + txsHashes = append(txsHashes[:i], txsHashes[i+1:]...) + uncleHashes = append(uncleHashes[:i], uncleHashes[i+1:]...) + continue + } + txsHashes[i] = hash uncleHashes[i] = types.CalcUncleHash(body.Uncles) } req := ð.Request{ @@ -442,7 +409,10 @@ func TestCanonicalSynchronisation68Snap(t *testing.T) { testCanonSync(t, eth.ET func TestCanonicalSynchronisation68Light(t *testing.T) { testCanonSync(t, eth.ETH68, LightSync) } func testCanonSync(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) + success := make(chan struct{}) + tester := newTesterWithNotification(t, func() { + close(success) + }) defer tester.terminate() // Create a small enough block chain to download @@ -450,10 +420,15 @@ func testCanonSync(t *testing.T, protocol uint, mode SyncMode) { tester.newPeer("peer", protocol, chain.blocks[1:]) // Synchronise with the peer and make sure all relevant data was retrieved - if err := tester.sync("peer", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) + if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil { + t.Fatalf("failed to beacon-sync chain: %v", err) + } + select { + case <-success: + assertOwnChain(t, tester, len(chain.blocks)) + case <-time.NewTimer(time.Second * 3).C: + t.Fatalf("Failed to sync chain in three seconds") } - assertOwnChain(t, tester, len(chain.blocks)) } // Tests that if a large batch of blocks are being downloaded, it is throttled @@ -479,7 +454,7 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { // Start a synchronisation concurrently errc := make(chan error, 1) go func() { - errc <- tester.sync("peer", nil, mode) + errc <- tester.downloader.BeaconSync(mode, testChainBase.blocks[len(testChainBase.blocks)-1].Header(), nil) }() // Iteratively take some blocks, always checking the retrieval count for { @@ -535,132 +510,17 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { } } -// Tests that simple synchronization against a forked chain works correctly. In -// this test common ancestor lookup should *not* be short circuited, and a full -// binary search should be executed. -func TestForkedSync68Full(t *testing.T) { testForkedSync(t, eth.ETH68, FullSync) } -func TestForkedSync68Snap(t *testing.T) { testForkedSync(t, eth.ETH68, SnapSync) } -func TestForkedSync68Light(t *testing.T) { testForkedSync(t, eth.ETH68, LightSync) } - -func testForkedSync(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chainA := testChainForkLightA.shorten(len(testChainBase.blocks) + 80) - chainB := testChainForkLightB.shorten(len(testChainBase.blocks) + 81) - tester.newPeer("fork A", protocol, chainA.blocks[1:]) - tester.newPeer("fork B", protocol, chainB.blocks[1:]) - // Synchronise with the peer and make sure all blocks were retrieved - if err := tester.sync("fork A", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } - assertOwnChain(t, tester, len(chainA.blocks)) - - // Synchronise with the second peer and make sure that fork is pulled too - if err := tester.sync("fork B", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } - assertOwnChain(t, tester, len(chainB.blocks)) -} - -// Tests that synchronising against a much shorter but much heavier fork works -// currently and is not dropped. -func TestHeavyForkedSync68Full(t *testing.T) { testHeavyForkedSync(t, eth.ETH68, FullSync) } -func TestHeavyForkedSync68Snap(t *testing.T) { testHeavyForkedSync(t, eth.ETH68, SnapSync) } -func TestHeavyForkedSync68Light(t *testing.T) { testHeavyForkedSync(t, eth.ETH68, LightSync) } - -func testHeavyForkedSync(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chainA := testChainForkLightA.shorten(len(testChainBase.blocks) + 80) - chainB := testChainForkHeavy.shorten(len(testChainBase.blocks) + 79) - tester.newPeer("light", protocol, chainA.blocks[1:]) - tester.newPeer("heavy", protocol, chainB.blocks[1:]) - - // Synchronise with the peer and make sure all blocks were retrieved - if err := tester.sync("light", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } - assertOwnChain(t, tester, len(chainA.blocks)) - - // Synchronise with the second peer and make sure that fork is pulled too - if err := tester.sync("heavy", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } - assertOwnChain(t, tester, len(chainB.blocks)) -} - -// Tests that chain forks are contained within a certain interval of the current -// chain head, ensuring that malicious peers cannot waste resources by feeding -// long dead chains. -func TestBoundedForkedSync68Full(t *testing.T) { testBoundedForkedSync(t, eth.ETH68, FullSync) } -func TestBoundedForkedSync68Snap(t *testing.T) { testBoundedForkedSync(t, eth.ETH68, SnapSync) } -func TestBoundedForkedSync68Light(t *testing.T) { testBoundedForkedSync(t, eth.ETH68, LightSync) } - -func testBoundedForkedSync(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chainA := testChainForkLightA - chainB := testChainForkLightB - tester.newPeer("original", protocol, chainA.blocks[1:]) - tester.newPeer("rewriter", protocol, chainB.blocks[1:]) - - // Synchronise with the peer and make sure all blocks were retrieved - if err := tester.sync("original", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } - assertOwnChain(t, tester, len(chainA.blocks)) - - // Synchronise with the second peer and ensure that the fork is rejected to being too old - if err := tester.sync("rewriter", nil, mode); err != errInvalidAncestor { - t.Fatalf("sync failure mismatch: have %v, want %v", err, errInvalidAncestor) - } -} - -// Tests that chain forks are contained within a certain interval of the current -// chain head for short but heavy forks too. These are a bit special because they -// take different ancestor lookup paths. -func TestBoundedHeavyForkedSync68Full(t *testing.T) { - testBoundedHeavyForkedSync(t, eth.ETH68, FullSync) -} -func TestBoundedHeavyForkedSync68Snap(t *testing.T) { - testBoundedHeavyForkedSync(t, eth.ETH68, SnapSync) -} -func TestBoundedHeavyForkedSync68Light(t *testing.T) { - testBoundedHeavyForkedSync(t, eth.ETH68, LightSync) -} - -func testBoundedHeavyForkedSync(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - // Create a long enough forked chain - chainA := testChainForkLightA - chainB := testChainForkHeavy - tester.newPeer("original", protocol, chainA.blocks[1:]) - - // Synchronise with the peer and make sure all blocks were retrieved - if err := tester.sync("original", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } - assertOwnChain(t, tester, len(chainA.blocks)) - - tester.newPeer("heavy-rewriter", protocol, chainB.blocks[1:]) - // Synchronise with the second peer and ensure that the fork is rejected to being too old - if err := tester.sync("heavy-rewriter", nil, mode); err != errInvalidAncestor { - t.Fatalf("sync failure mismatch: have %v, want %v", err, errInvalidAncestor) - } -} - // Tests that a canceled download wipes all previously accumulated state. func TestCancel68Full(t *testing.T) { testCancel(t, eth.ETH68, FullSync) } func TestCancel68Snap(t *testing.T) { testCancel(t, eth.ETH68, SnapSync) } func TestCancel68Light(t *testing.T) { testCancel(t, eth.ETH68, LightSync) } func testCancel(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) + complete := make(chan struct{}) + success := func() { + close(complete) + } + tester := newTesterWithNotification(t, success) defer tester.terminate() chain := testChainBase.shorten(MaxHeaderFetch) @@ -672,38 +532,16 @@ func testCancel(t *testing.T, protocol uint, mode SyncMode) { t.Errorf("download queue not idle") } // Synchronise with the peer, but cancel afterwards - if err := tester.sync("peer", nil, mode); err != nil { + if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil { t.Fatalf("failed to synchronise blocks: %v", err) } + <-complete tester.downloader.Cancel() if !tester.downloader.queue.Idle() { t.Errorf("download queue not idle") } } -// Tests that synchronisation from multiple peers works as intended (multi thread sanity test). -func TestMultiSynchronisation68Full(t *testing.T) { testMultiSynchronisation(t, eth.ETH68, FullSync) } -func TestMultiSynchronisation68Snap(t *testing.T) { testMultiSynchronisation(t, eth.ETH68, SnapSync) } -func TestMultiSynchronisation68Light(t *testing.T) { testMultiSynchronisation(t, eth.ETH68, LightSync) } - -func testMultiSynchronisation(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - // Create various peers with various parts of the chain - targetPeers := 8 - chain := testChainBase.shorten(targetPeers * 100) - - for i := 0; i < targetPeers; i++ { - id := fmt.Sprintf("peer #%d", i) - tester.newPeer(id, protocol, chain.shorten(len(chain.blocks) / (i + 1)).blocks[1:]) - } - if err := tester.sync("peer #0", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } - assertOwnChain(t, tester, len(chain.blocks)) -} - // Tests that synchronisations behave well in multi-version protocol environments // and not wreak havoc on other nodes in the network. func TestMultiProtoSynchronisation68Full(t *testing.T) { testMultiProtoSync(t, eth.ETH68, FullSync) } @@ -711,7 +549,11 @@ func TestMultiProtoSynchronisation68Snap(t *testing.T) { testMultiProtoSync(t, func TestMultiProtoSynchronisation68Light(t *testing.T) { testMultiProtoSync(t, eth.ETH68, LightSync) } func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) + complete := make(chan struct{}) + success := func() { + close(complete) + } + tester := newTesterWithNotification(t, success) defer tester.terminate() // Create a small enough block chain to download @@ -720,9 +562,14 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { // Create peers of every type tester.newPeer("peer 68", eth.ETH68, chain.blocks[1:]) - // Synchronise with the requested peer and make sure all blocks were retrieved - if err := tester.sync(fmt.Sprintf("peer %d", protocol), nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) + if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil { + t.Fatalf("failed to start beacon sync: #{err}") + } + select { + case <-complete: + break + case <-time.NewTimer(time.Second * 3).C: + t.Fatalf("Failed to sync chain in three seconds") } assertOwnChain(t, tester, len(chain.blocks)) @@ -742,7 +589,10 @@ func TestEmptyShortCircuit68Snap(t *testing.T) { testEmptyShortCircuit(t, eth.E func TestEmptyShortCircuit68Light(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, LightSync) } func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) + success := make(chan struct{}) + tester := newTesterWithNotification(t, func() { + close(success) + }) defer tester.terminate() // Create a block chain to download @@ -757,10 +607,19 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { tester.downloader.receiptFetchHook = func(headers []*types.Header) { receiptsHave.Add(int32(len(headers))) } - // Synchronise with the peer and make sure all blocks were retrieved - if err := tester.sync("peer", nil, mode); err != nil { + + if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil { t.Fatalf("failed to synchronise blocks: %v", err) } + select { + case <-success: + checkProgress(t, tester.downloader, "initial", ethereum.SyncProgress{ + HighestBlock: uint64(len(chain.blocks) - 1), + CurrentBlock: uint64(len(chain.blocks) - 1), + }) + case <-time.NewTimer(time.Second * 3).C: + t.Fatalf("Failed to sync chain in three seconds") + } assertOwnChain(t, tester, len(chain.blocks)) // Validate the number of block bodies that should have been requested @@ -783,195 +642,6 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { } } -// Tests that headers are enqueued continuously, preventing malicious nodes from -// stalling the downloader by feeding gapped header chains. -func TestMissingHeaderAttack68Full(t *testing.T) { testMissingHeaderAttack(t, eth.ETH68, FullSync) } -func TestMissingHeaderAttack68Snap(t *testing.T) { testMissingHeaderAttack(t, eth.ETH68, SnapSync) } -func TestMissingHeaderAttack68Light(t *testing.T) { testMissingHeaderAttack(t, eth.ETH68, LightSync) } - -func testMissingHeaderAttack(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chain := testChainBase.shorten(blockCacheMaxItems - 15) - - attacker := tester.newPeer("attack", protocol, chain.blocks[1:]) - attacker.withholdHeaders[chain.blocks[len(chain.blocks)/2-1].Hash()] = struct{}{} - - if err := tester.sync("attack", nil, mode); err == nil { - t.Fatalf("succeeded attacker synchronisation") - } - // Synchronise with the valid peer and make sure sync succeeds - tester.newPeer("valid", protocol, chain.blocks[1:]) - if err := tester.sync("valid", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } - assertOwnChain(t, tester, len(chain.blocks)) -} - -// Tests that if requested headers are shifted (i.e. first is missing), the queue -// detects the invalid numbering. -func TestShiftedHeaderAttack68Full(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH68, FullSync) } -func TestShiftedHeaderAttack68Snap(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH68, SnapSync) } -func TestShiftedHeaderAttack68Light(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH68, LightSync) } - -func testShiftedHeaderAttack(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chain := testChainBase.shorten(blockCacheMaxItems - 15) - - // Attempt a full sync with an attacker feeding shifted headers - attacker := tester.newPeer("attack", protocol, chain.blocks[1:]) - attacker.withholdHeaders[chain.blocks[1].Hash()] = struct{}{} - - if err := tester.sync("attack", nil, mode); err == nil { - t.Fatalf("succeeded attacker synchronisation") - } - // Synchronise with the valid peer and make sure sync succeeds - tester.newPeer("valid", protocol, chain.blocks[1:]) - if err := tester.sync("valid", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } - assertOwnChain(t, tester, len(chain.blocks)) -} - -// Tests that a peer advertising a high TD doesn't get to stall the downloader -// afterwards by not sending any useful hashes. -func TestHighTDStarvationAttack68Full(t *testing.T) { - testHighTDStarvationAttack(t, eth.ETH68, FullSync) -} -func TestHighTDStarvationAttack68Snap(t *testing.T) { - testHighTDStarvationAttack(t, eth.ETH68, SnapSync) -} -func TestHighTDStarvationAttack68Light(t *testing.T) { - testHighTDStarvationAttack(t, eth.ETH68, LightSync) -} - -func testHighTDStarvationAttack(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chain := testChainBase.shorten(1) - tester.newPeer("attack", protocol, chain.blocks[1:]) - if err := tester.sync("attack", big.NewInt(1000000), mode); err != errStallingPeer { - t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errStallingPeer) - } -} - -// Tests that misbehaving peers are disconnected, whilst behaving ones are not. -func TestBlockHeaderAttackerDropping68(t *testing.T) { testBlockHeaderAttackerDropping(t, eth.ETH68) } - -func testBlockHeaderAttackerDropping(t *testing.T, protocol uint) { - // Define the disconnection requirement for individual hash fetch errors - tests := []struct { - result error - drop bool - }{ - {nil, false}, // Sync succeeded, all is well - {errBusy, false}, // Sync is already in progress, no problem - {errUnknownPeer, false}, // Peer is unknown, was already dropped, don't double drop - {errBadPeer, true}, // Peer was deemed bad for some reason, drop it - {errStallingPeer, true}, // Peer was detected to be stalling, drop it - {errUnsyncedPeer, true}, // Peer was detected to be unsynced, drop it - {errNoPeers, false}, // No peers to download from, soft race, no issue - {errTimeout, true}, // No hashes received in due time, drop the peer - {errEmptyHeaderSet, true}, // No headers were returned as a response, drop as it's a dead end - {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 - {errInvalidBody, false}, // A bad peer was detected, but not the sync origin - {errInvalidReceipt, false}, // A bad peer was detected, but not the sync origin - {errCancelContentProcessing, false}, // Synchronisation was canceled, origin may be innocent, don't drop - } - // Run the tests and check disconnection status - tester := newTester(t) - defer tester.terminate() - chain := testChainBase.shorten(1) - - for i, tt := range tests { - // Register a new peer and ensure its presence - id := fmt.Sprintf("test %d", i) - tester.newPeer(id, protocol, chain.blocks[1:]) - if _, ok := tester.peers[id]; !ok { - t.Fatalf("test %d: registered peer not found", i) - } - // Simulate a synchronisation and check the required result - tester.downloader.synchroniseMock = func(string, common.Hash) error { return tt.result } - - tester.downloader.LegacySync(id, tester.chain.Genesis().Hash(), big.NewInt(1000), nil, FullSync) - if _, ok := tester.peers[id]; !ok != tt.drop { - t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.result, !ok, tt.drop) - } - } -} - -// Tests that synchronisation progress (origin block number, current block number -// and highest block number) is tracked and updated correctly. -func TestSyncProgress68Full(t *testing.T) { testSyncProgress(t, eth.ETH68, FullSync) } -func TestSyncProgress68Snap(t *testing.T) { testSyncProgress(t, eth.ETH68, SnapSync) } -func TestSyncProgress68Light(t *testing.T) { testSyncProgress(t, eth.ETH68, LightSync) } - -func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chain := testChainBase.shorten(blockCacheMaxItems - 15) - - // Set a sync init hook to catch progress changes - starting := make(chan struct{}) - progress := make(chan struct{}) - - tester.downloader.syncInitHook = func(origin, latest uint64) { - starting <- struct{}{} - <-progress - } - checkProgress(t, tester.downloader, "pristine", ethereum.SyncProgress{}) - - // Synchronise half the blocks and check initial progress - tester.newPeer("peer-half", protocol, chain.shorten(len(chain.blocks) / 2).blocks[1:]) - pending := new(sync.WaitGroup) - pending.Add(1) - - go func() { - defer pending.Done() - if err := tester.sync("peer-half", nil, mode); err != nil { - panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) - } - }() - <-starting - checkProgress(t, tester.downloader, "initial", ethereum.SyncProgress{ - HighestBlock: uint64(len(chain.blocks)/2 - 1), - }) - progress <- struct{}{} - pending.Wait() - - // Synchronise all the blocks and check continuation progress - tester.newPeer("peer-full", protocol, chain.blocks[1:]) - pending.Add(1) - go func() { - defer pending.Done() - if err := tester.sync("peer-full", nil, mode); err != nil { - panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) - } - }() - <-starting - checkProgress(t, tester.downloader, "completing", ethereum.SyncProgress{ - StartingBlock: uint64(len(chain.blocks)/2 - 1), - CurrentBlock: uint64(len(chain.blocks)/2 - 1), - HighestBlock: uint64(len(chain.blocks) - 1), - }) - - // Check final progress after successful sync - progress <- struct{}{} - pending.Wait() - checkProgress(t, tester.downloader, "final", ethereum.SyncProgress{ - StartingBlock: uint64(len(chain.blocks)/2 - 1), - CurrentBlock: uint64(len(chain.blocks) - 1), - HighestBlock: uint64(len(chain.blocks) - 1), - }) -} - func checkProgress(t *testing.T, d *Downloader, stage string, want ethereum.SyncProgress) { // Mark this method as a helper to report errors at callsite, not in here t.Helper() @@ -982,296 +652,12 @@ func checkProgress(t *testing.T, d *Downloader, stage string, want ethereum.Sync } } -// Tests that synchronisation progress (origin block number and highest block -// number) is tracked and updated correctly in case of a fork (or manual head -// revertal). -func TestForkedSyncProgress68Full(t *testing.T) { testForkedSyncProgress(t, eth.ETH68, FullSync) } -func TestForkedSyncProgress68Snap(t *testing.T) { testForkedSyncProgress(t, eth.ETH68, SnapSync) } -func TestForkedSyncProgress68Light(t *testing.T) { testForkedSyncProgress(t, eth.ETH68, LightSync) } - -func testForkedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chainA := testChainForkLightA.shorten(len(testChainBase.blocks) + MaxHeaderFetch) - chainB := testChainForkLightB.shorten(len(testChainBase.blocks) + MaxHeaderFetch) - - // Set a sync init hook to catch progress changes - starting := make(chan struct{}) - progress := make(chan struct{}) - - tester.downloader.syncInitHook = func(origin, latest uint64) { - starting <- struct{}{} - <-progress - } - checkProgress(t, tester.downloader, "pristine", ethereum.SyncProgress{}) - - // Synchronise with one of the forks and check progress - tester.newPeer("fork A", protocol, chainA.blocks[1:]) - pending := new(sync.WaitGroup) - pending.Add(1) - go func() { - defer pending.Done() - if err := tester.sync("fork A", nil, mode); err != nil { - panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) - } - }() - <-starting - - checkProgress(t, tester.downloader, "initial", ethereum.SyncProgress{ - HighestBlock: uint64(len(chainA.blocks) - 1), - }) - progress <- struct{}{} - pending.Wait() - - // Simulate a successful sync above the fork - tester.downloader.syncStatsChainOrigin = tester.downloader.syncStatsChainHeight - - // Synchronise with the second fork and check progress resets - tester.newPeer("fork B", protocol, chainB.blocks[1:]) - pending.Add(1) - go func() { - defer pending.Done() - if err := tester.sync("fork B", nil, mode); err != nil { - panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) - } - }() - <-starting - checkProgress(t, tester.downloader, "forking", ethereum.SyncProgress{ - StartingBlock: uint64(len(testChainBase.blocks)) - 1, - CurrentBlock: uint64(len(chainA.blocks) - 1), - HighestBlock: uint64(len(chainB.blocks) - 1), - }) - - // Check final progress after successful sync - progress <- struct{}{} - pending.Wait() - checkProgress(t, tester.downloader, "final", ethereum.SyncProgress{ - StartingBlock: uint64(len(testChainBase.blocks)) - 1, - CurrentBlock: uint64(len(chainB.blocks) - 1), - HighestBlock: uint64(len(chainB.blocks) - 1), - }) -} - -// Tests that if synchronisation is aborted due to some failure, then the progress -// origin is not updated in the next sync cycle, as it should be considered the -// continuation of the previous sync and not a new instance. -func TestFailedSyncProgress68Full(t *testing.T) { testFailedSyncProgress(t, eth.ETH68, FullSync) } -func TestFailedSyncProgress68Snap(t *testing.T) { testFailedSyncProgress(t, eth.ETH68, SnapSync) } -func TestFailedSyncProgress68Light(t *testing.T) { testFailedSyncProgress(t, eth.ETH68, LightSync) } - -func testFailedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chain := testChainBase.shorten(blockCacheMaxItems - 15) - - // Set a sync init hook to catch progress changes - starting := make(chan struct{}) - progress := make(chan struct{}) - - tester.downloader.syncInitHook = func(origin, latest uint64) { - starting <- struct{}{} - <-progress - } - checkProgress(t, tester.downloader, "pristine", ethereum.SyncProgress{}) - - // Attempt a full sync with a faulty peer - missing := len(chain.blocks)/2 - 1 - - faulter := tester.newPeer("faulty", protocol, chain.blocks[1:]) - faulter.withholdHeaders[chain.blocks[missing].Hash()] = struct{}{} - - pending := new(sync.WaitGroup) - pending.Add(1) - go func() { - defer pending.Done() - if err := tester.sync("faulty", nil, mode); err == nil { - panic("succeeded faulty synchronisation") - } - }() - <-starting - checkProgress(t, tester.downloader, "initial", ethereum.SyncProgress{ - HighestBlock: uint64(len(chain.blocks) - 1), - }) - progress <- struct{}{} - pending.Wait() - afterFailedSync := tester.downloader.Progress() - - // Synchronise with a good peer and check that the progress origin remind the same - // after a failure - tester.newPeer("valid", protocol, chain.blocks[1:]) - pending.Add(1) - go func() { - defer pending.Done() - if err := tester.sync("valid", nil, mode); err != nil { - panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) - } - }() - <-starting - checkProgress(t, tester.downloader, "completing", afterFailedSync) - - // Check final progress after successful sync - progress <- struct{}{} - pending.Wait() - checkProgress(t, tester.downloader, "final", ethereum.SyncProgress{ - CurrentBlock: uint64(len(chain.blocks) - 1), - HighestBlock: uint64(len(chain.blocks) - 1), - }) -} - -// Tests that if an attacker fakes a chain height, after the attack is detected, -// the progress height is successfully reduced at the next sync invocation. -func TestFakedSyncProgress68Full(t *testing.T) { testFakedSyncProgress(t, eth.ETH68, FullSync) } -func TestFakedSyncProgress68Snap(t *testing.T) { testFakedSyncProgress(t, eth.ETH68, SnapSync) } -func TestFakedSyncProgress68Light(t *testing.T) { testFakedSyncProgress(t, eth.ETH68, LightSync) } - -func testFakedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { - tester := newTester(t) - defer tester.terminate() - - chain := testChainBase.shorten(blockCacheMaxItems - 15) - - // Set a sync init hook to catch progress changes - starting := make(chan struct{}) - progress := make(chan struct{}) - tester.downloader.syncInitHook = func(origin, latest uint64) { - starting <- struct{}{} - <-progress - } - checkProgress(t, tester.downloader, "pristine", ethereum.SyncProgress{}) - - // Create and sync with an attacker that promises a higher chain than available. - attacker := tester.newPeer("attack", protocol, chain.blocks[1:]) - numMissing := 5 - for i := len(chain.blocks) - 2; i > len(chain.blocks)-numMissing; i-- { - attacker.withholdHeaders[chain.blocks[i].Hash()] = struct{}{} - } - pending := new(sync.WaitGroup) - pending.Add(1) - go func() { - defer pending.Done() - if err := tester.sync("attack", nil, mode); err == nil { - panic("succeeded attacker synchronisation") - } - }() - <-starting - checkProgress(t, tester.downloader, "initial", ethereum.SyncProgress{ - HighestBlock: uint64(len(chain.blocks) - 1), - }) - progress <- struct{}{} - pending.Wait() - afterFailedSync := tester.downloader.Progress() - - // Synchronise with a good peer and check that the progress height has been reduced to - // the true value. - validChain := chain.shorten(len(chain.blocks) - numMissing) - tester.newPeer("valid", protocol, validChain.blocks[1:]) - pending.Add(1) - - go func() { - defer pending.Done() - if err := tester.sync("valid", nil, mode); err != nil { - panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) - } - }() - <-starting - checkProgress(t, tester.downloader, "completing", ethereum.SyncProgress{ - CurrentBlock: afterFailedSync.CurrentBlock, - HighestBlock: uint64(len(validChain.blocks) - 1), - }) - // Check final progress after successful sync. - progress <- struct{}{} - pending.Wait() - checkProgress(t, tester.downloader, "final", ethereum.SyncProgress{ - CurrentBlock: uint64(len(validChain.blocks) - 1), - HighestBlock: uint64(len(validChain.blocks) - 1), - }) -} - -func TestRemoteHeaderRequestSpan(t *testing.T) { - testCases := []struct { - remoteHeight uint64 - localHeight uint64 - expected []int - }{ - // Remote is way higher. We should ask for the remote head and go backwards - {1500, 1000, - []int{1323, 1339, 1355, 1371, 1387, 1403, 1419, 1435, 1451, 1467, 1483, 1499}, - }, - {15000, 13006, - []int{14823, 14839, 14855, 14871, 14887, 14903, 14919, 14935, 14951, 14967, 14983, 14999}, - }, - // Remote is pretty close to us. We don't have to fetch as many - {1200, 1150, - []int{1149, 1154, 1159, 1164, 1169, 1174, 1179, 1184, 1189, 1194, 1199}, - }, - // Remote is equal to us (so on a fork with higher td) - // We should get the closest couple of ancestors - {1500, 1500, - []int{1497, 1499}, - }, - // We're higher than the remote! Odd - {1000, 1500, - []int{997, 999}, - }, - // Check some weird edgecases that it behaves somewhat rationally - {0, 1500, - []int{0, 2}, - }, - {6000000, 0, - []int{5999823, 5999839, 5999855, 5999871, 5999887, 5999903, 5999919, 5999935, 5999951, 5999967, 5999983, 5999999}, - }, - {0, 0, - []int{0, 2}, - }, - } - reqs := func(from, count, span int) []int { - var r []int - num := from - for len(r) < count { - r = append(r, num) - num += span + 1 - } - return r - } - for i, tt := range testCases { - from, count, span, max := calculateRequestSpan(tt.remoteHeight, tt.localHeight) - data := reqs(int(from), count, span) - - if max != uint64(data[len(data)-1]) { - t.Errorf("test %d: wrong last value %d != %d", i, data[len(data)-1], max) - } - failed := false - if len(data) != len(tt.expected) { - failed = true - t.Errorf("test %d: length wrong, expected %d got %d", i, len(tt.expected), len(data)) - } else { - for j, n := range data { - if n != tt.expected[j] { - failed = true - break - } - } - } - if failed { - res := strings.ReplaceAll(fmt.Sprint(data), " ", ",") - exp := strings.ReplaceAll(fmt.Sprint(tt.expected), " ", ",") - t.Logf("got: %v\n", res) - t.Logf("exp: %v\n", exp) - t.Errorf("test %d: wrong values", i) - } - } -} - // Tests that peers below a pre-configured checkpoint block are prevented from // being fast-synced from, avoiding potential cheap eclipse attacks. func TestBeaconSync68Full(t *testing.T) { testBeaconSync(t, eth.ETH68, FullSync) } func TestBeaconSync68Snap(t *testing.T) { testBeaconSync(t, eth.ETH68, SnapSync) } func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) { - //log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - var cases = []struct { name string // The name of testing scenario local int // The length of local chain(canonical chain assumed), 0 means genesis is the head @@ -1312,81 +698,67 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) { } } -// Tests that synchronisation progress (origin block number and highest block -// number) is tracked and updated correctly in case of manual head reversion -func TestBeaconForkedSyncProgress68Full(t *testing.T) { - testBeaconForkedSyncProgress(t, eth.ETH68, FullSync) -} -func TestBeaconForkedSyncProgress68Snap(t *testing.T) { - testBeaconForkedSyncProgress(t, eth.ETH68, SnapSync) -} -func TestBeaconForkedSyncProgress68Light(t *testing.T) { - testBeaconForkedSyncProgress(t, eth.ETH68, LightSync) -} +// Tests that synchronisation progress (origin block number, current block number +// and highest block number) is tracked and updated correctly. +func TestSyncProgress68Full(t *testing.T) { testSyncProgress(t, eth.ETH68, FullSync) } +func TestSyncProgress68Snap(t *testing.T) { testSyncProgress(t, eth.ETH68, SnapSync) } +func TestSyncProgress68Light(t *testing.T) { testSyncProgress(t, eth.ETH68, LightSync) } -func testBeaconForkedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { +func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) { success := make(chan struct{}) tester := newTesterWithNotification(t, func() { success <- struct{}{} }) defer tester.terminate() + checkProgress(t, tester.downloader, "pristine", ethereum.SyncProgress{}) - chainA := testChainForkLightA.shorten(len(testChainBase.blocks) + MaxHeaderFetch) - chainB := testChainForkLightB.shorten(len(testChainBase.blocks) + MaxHeaderFetch) - - // Set a sync init hook to catch progress changes - starting := make(chan struct{}) - progress := make(chan struct{}) + chain := testChainBase.shorten(blockCacheMaxItems - 15) + shortChain := chain.shorten(len(chain.blocks) / 2).blocks[1:] - tester.downloader.syncInitHook = func(origin, latest uint64) { - starting <- struct{}{} - <-progress + // Connect to peer that provides all headers and part of the bodies + faultyPeer := tester.newPeer("peer-half", protocol, shortChain) + for _, header := range shortChain { + faultyPeer.withholdBodies[header.Hash()] = struct{}{} } - checkProgress(t, tester.downloader, "pristine", ethereum.SyncProgress{}) - - // Synchronise with one of the forks and check progress - tester.newPeer("fork A", protocol, chainA.blocks[1:]) - pending := new(sync.WaitGroup) - pending.Add(1) - go func() { - defer pending.Done() - if err := tester.downloader.BeaconSync(mode, chainA.blocks[len(chainA.blocks)-1].Header(), nil); err != nil { - panic(fmt.Sprintf("failed to beacon sync: %v", err)) - } - }() - <-starting - progress <- struct{}{} + if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)/2-1].Header(), nil); err != nil { + t.Fatalf("failed to beacon-sync chain: %v", err) + } select { case <-success: - checkProgress(t, tester.downloader, "initial", ethereum.SyncProgress{ - HighestBlock: uint64(len(chainA.blocks) - 1), - CurrentBlock: uint64(len(chainA.blocks) - 1), + // Ok, downloader fully cancelled after sync cycle + checkProgress(t, tester.downloader, "peer-half", ethereum.SyncProgress{ + CurrentBlock: uint64(len(chain.blocks)/2 - 1), + HighestBlock: uint64(len(chain.blocks)/2 - 1), }) case <-time.NewTimer(time.Second * 3).C: t.Fatalf("Failed to sync chain in three seconds") } - // Set the head to a second fork - tester.newPeer("fork B", protocol, chainB.blocks[1:]) - pending.Add(1) - go func() { - defer pending.Done() - if err := tester.downloader.BeaconSync(mode, chainB.blocks[len(chainB.blocks)-1].Header(), nil); err != nil { - panic(fmt.Sprintf("failed to beacon sync: %v", err)) - } - }() - - <-starting - progress <- struct{}{} + // Synchronise all the blocks and check continuation progress + tester.newPeer("peer-full", protocol, chain.blocks[1:]) + if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil { + t.Fatalf("failed to beacon-sync chain: %v", err) + } + var startingBlock uint64 + if mode == LightSync { + // in light-sync mode: + // * the starting block is 0 on the second sync cycle because blocks + // are never downloaded. + // * The current/highest blocks reported in the progress reflect the + // current/highest header. + startingBlock = 0 + } else { + startingBlock = uint64(len(chain.blocks)/2 - 1) + } - // reorg below available state causes the state sync to rewind to genesis select { case <-success: - checkProgress(t, tester.downloader, "initial", ethereum.SyncProgress{ - HighestBlock: uint64(len(chainB.blocks) - 1), - CurrentBlock: uint64(len(chainB.blocks) - 1), - StartingBlock: 0, + // Ok, downloader fully cancelled after sync cycle + checkProgress(t, tester.downloader, "peer-full", ethereum.SyncProgress{ + StartingBlock: startingBlock, + CurrentBlock: uint64(len(chain.blocks) - 1), + HighestBlock: uint64(len(chain.blocks) - 1), }) case <-time.NewTimer(time.Second * 3).C: t.Fatalf("Failed to sync chain in three seconds") diff --git a/eth/downloader/fetchers.go b/eth/downloader/fetchers.go index cc4279b0da7a..4ebb9bbc98a4 100644 --- a/eth/downloader/fetchers.go +++ b/eth/downloader/fetchers.go @@ -68,48 +68,3 @@ func (d *Downloader) fetchHeadersByHash(p *peerConnection, hash common.Hash, amo return *res.Res.(*eth.BlockHeadersRequest), res.Meta.([]common.Hash), nil } } - -// fetchHeadersByNumber is a blocking version of Peer.RequestHeadersByNumber which -// handles all the cancellation, interruption and timeout mechanisms of a data -// retrieval to allow blocking API calls. -func (d *Downloader) fetchHeadersByNumber(p *peerConnection, number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error) { - // Create the response sink and send the network request - start := time.Now() - resCh := make(chan *eth.Response) - - req, err := p.peer.RequestHeadersByNumber(number, amount, skip, reverse, resCh) - if err != nil { - return nil, nil, err - } - defer req.Close() - - // Wait until the response arrives, the request is cancelled or times out - ttl := d.peers.rates.TargetTimeout() - - timeoutTimer := time.NewTimer(ttl) - defer timeoutTimer.Stop() - - select { - case <-d.cancelCh: - return nil, nil, errCanceled - - case <-timeoutTimer.C: - // Header retrieval timed out, update the metrics - p.log.Debug("Header request timed out", "elapsed", ttl) - headerTimeoutMeter.Mark(1) - - return nil, nil, errTimeout - - case res := <-resCh: - // Headers successfully retrieved, update the metrics - headerReqTimer.Update(time.Since(start)) - headerInMeter.Mark(int64(len(*res.Res.(*eth.BlockHeadersRequest)))) - - // Don't reject the packet even if it turns out to be bad, downloader will - // disconnect the peer on its own terms. Simply delivery the headers to - // be processed by the caller - res.Done <- nil - - return *res.Res.(*eth.BlockHeadersRequest), res.Meta.([]common.Hash), nil - } -} diff --git a/eth/downloader/fetchers_concurrent.go b/eth/downloader/fetchers_concurrent.go index 649aa2761596..9d8cd114c12a 100644 --- a/eth/downloader/fetchers_concurrent.go +++ b/eth/downloader/fetchers_concurrent.go @@ -76,7 +76,7 @@ type typedQueue interface { // concurrentFetch iteratively downloads scheduled block parts, taking available // peers, reserving a chunk of fetch requests for each and waiting for delivery // or timeouts. -func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { +func (d *Downloader) concurrentFetch(queue typedQueue) error { // Create a delivery channel to accept responses from all peers responses := make(chan *eth.Response) @@ -126,10 +126,6 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { // Prepare the queue and fetch block parts until the block header fetcher's done finished := false for { - // Short circuit if we lost all our peers - if d.peers.Len() == 0 && !beaconMode { - return errNoPeers - } // If there's nothing more to fetch, wait or terminate if queue.pending() == 0 { if len(pending) == 0 && finished { @@ -158,27 +154,20 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { } sort.Sort(&peerCapacitySort{idles, caps}) - var ( - progressed bool - throttled bool - queued = queue.pending() - ) + var throttled bool for _, peer := range idles { // Short circuit if throttling activated or there are no more // queued tasks to be retrieved if throttled { break } - if queued = queue.pending(); queued == 0 { + if queued := queue.pending(); queued == 0 { break } // Reserve a chunk of fetches for a peer. A nil can mean either that // no more headers are available, or that the peer is known not to // have them. - request, progress, throttle := queue.reserve(peer, queue.capacity(peer, d.peers.rates.TargetRoundTrip())) - if progress { - progressed = true - } + request, _, throttle := queue.reserve(peer, queue.capacity(peer, d.peers.rates.TargetRoundTrip())) if throttle { throttled = true throttleCounter.Inc(1) @@ -207,11 +196,6 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { timeout.Reset(ttl) } } - // Make sure that we have peers available for fetching. If all peers have been tried - // and all failed throw an error - if !progressed && !throttled && len(pending) == 0 && len(idles) == d.peers.Len() && queued > 0 && !beaconMode { - return errPeersUnavailable - } } // Wait for something to happen select { @@ -315,16 +299,6 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { queue.updateCapacity(peer, 0, 0) } else { d.dropPeer(peer.id) - - // If this peer was the master peer, abort sync immediately - d.cancelLock.RLock() - master := peer.id == d.cancelPeer - d.cancelLock.RUnlock() - - if master { - d.cancel() - return errTimeout - } } case res := <-responses: diff --git a/eth/downloader/fetchers_concurrent_bodies.go b/eth/downloader/fetchers_concurrent_bodies.go index 5105fda66b3a..56359b33c94e 100644 --- a/eth/downloader/fetchers_concurrent_bodies.go +++ b/eth/downloader/fetchers_concurrent_bodies.go @@ -78,7 +78,6 @@ func (q *bodyQueue) request(peer *peerConnection, req *fetchRequest, resCh chan if q.bodyFetchHook != nil { q.bodyFetchHook(req.Headers) } - hashes := make([]common.Hash, 0, len(req.Headers)) for _, header := range req.Headers { hashes = append(hashes, header.Hash()) diff --git a/eth/downloader/fetchers_concurrent_headers.go b/eth/downloader/fetchers_concurrent_headers.go deleted file mode 100644 index 8201f4ca7423..000000000000 --- a/eth/downloader/fetchers_concurrent_headers.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2021 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 downloader - -import ( - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/eth/protocols/eth" - "github.com/ethereum/go-ethereum/log" -) - -// headerQueue implements typedQueue and is a type adapter between the generic -// concurrent fetcher and the downloader. -type headerQueue Downloader - -// waker returns a notification channel that gets pinged in case more header -// fetches have been queued up, so the fetcher might assign it to idle peers. -func (q *headerQueue) waker() chan bool { - return q.queue.headerContCh -} - -// pending returns the number of headers that are currently queued for fetching -// by the concurrent downloader. -func (q *headerQueue) pending() int { - return q.queue.PendingHeaders() -} - -// capacity is responsible for calculating how many headers a particular peer is -// estimated to be able to retrieve within the allotted round trip time. -func (q *headerQueue) capacity(peer *peerConnection, rtt time.Duration) int { - return peer.HeaderCapacity(rtt) -} - -// updateCapacity is responsible for updating how many headers a particular peer -// is estimated to be able to retrieve in a unit time. -func (q *headerQueue) updateCapacity(peer *peerConnection, items int, span time.Duration) { - peer.UpdateHeaderRate(items, span) -} - -// reserve is responsible for allocating a requested number of pending headers -// from the download queue to the specified peer. -func (q *headerQueue) reserve(peer *peerConnection, items int) (*fetchRequest, bool, bool) { - return q.queue.ReserveHeaders(peer, items), false, false -} - -// unreserve is responsible for removing the current header retrieval allocation -// assigned to a specific peer and placing it back into the pool to allow -// reassigning to some other peer. -func (q *headerQueue) unreserve(peer string) int { - fails := q.queue.ExpireHeaders(peer) - if fails > 2 { - log.Trace("Header delivery timed out", "peer", peer) - } else { - log.Debug("Header delivery stalling", "peer", peer) - } - return fails -} - -// request is responsible for converting a generic fetch request into a header -// one and sending it to the remote peer for fulfillment. -func (q *headerQueue) request(peer *peerConnection, req *fetchRequest, resCh chan *eth.Response) (*eth.Request, error) { - peer.log.Trace("Requesting new batch of headers", "from", req.From) - return peer.peer.RequestHeadersByNumber(req.From, MaxHeaderFetch, 0, false, resCh) -} - -// deliver is responsible for taking a generic response packet from the concurrent -// fetcher, unpacking the header data and delivering it to the downloader's queue. -func (q *headerQueue) deliver(peer *peerConnection, packet *eth.Response) (int, error) { - headers := *packet.Res.(*eth.BlockHeadersRequest) - hashes := packet.Meta.([]common.Hash) - - accepted, err := q.queue.DeliverHeaders(peer.id, headers, hashes, q.headerProcCh) - switch { - case err == nil && len(headers) == 0: - peer.log.Trace("Requested headers delivered") - case err == nil: - peer.log.Trace("Delivered new batch of headers", "count", len(headers), "accepted", accepted) - default: - peer.log.Debug("Failed to deliver retrieved headers", "err", err) - } - return accepted, err -} diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 46f3febd8ba8..6043f5137231 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -58,7 +58,6 @@ var pregenerated bool func init() { // Reduce some of the parameters to make the tester faster fullMaxForkAncestry = 10000 - lightMaxForkAncestry = 10000 blockCacheMaxItems = 1024 fsHeaderSafetyNet = 256 fsHeaderContCheck = 500 * time.Millisecond From f8820f170cba2744198a781fd92ddb1f91f1440f Mon Sep 17 00:00:00 2001 From: Bin <49082129+songzhibin97@users.noreply.github.com> Date: Tue, 30 Apr 2024 21:47:21 +0800 Subject: [PATCH 237/571] accounts, cmd/geth, core: close opened files (#29598) * fix: open file used up but not closed * feat: more same case * feat: accept conversation --- accounts/keystore/keystore.go | 7 +++---- accounts/scwallet/hub.go | 1 + cmd/geth/logging_test.go | 2 ++ core/mkalloc.go | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 5c978cf0b422..df3dda60b656 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -312,11 +312,10 @@ func (ks *KeyStore) Unlock(a accounts.Account, passphrase string) error { // Lock removes the private key with the given address from memory. func (ks *KeyStore) Lock(addr common.Address) error { ks.mu.Lock() - if unl, found := ks.unlocked[addr]; found { - ks.mu.Unlock() + unl, found := ks.unlocked[addr] + ks.mu.Unlock() + if found { ks.expire(addr, unl, time.Duration(0)*time.Nanosecond) - } else { - ks.mu.Unlock() } return nil } diff --git a/accounts/scwallet/hub.go b/accounts/scwallet/hub.go index 5f1f369ca2a0..1b1899dc8e8e 100644 --- a/accounts/scwallet/hub.go +++ b/accounts/scwallet/hub.go @@ -95,6 +95,7 @@ func (hub *Hub) readPairings() error { } return err } + defer pairingFile.Close() pairingData, err := io.ReadAll(pairingFile) if err != nil { diff --git a/cmd/geth/logging_test.go b/cmd/geth/logging_test.go index b5ce03f4b8db..f426b138bb67 100644 --- a/cmd/geth/logging_test.go +++ b/cmd/geth/logging_test.go @@ -73,6 +73,7 @@ func testConsoleLogging(t *testing.T, format string, tStart, tEnd int) { if err != nil { t.Fatal(err) } + defer readFile.Close() wantLines := split(readFile) haveLines := split(bytes.NewBuffer(haveB)) for i, want := range wantLines { @@ -109,6 +110,7 @@ func TestJsonLogging(t *testing.T) { if err != nil { t.Fatal(err) } + defer readFile.Close() wantLines := split(readFile) haveLines := split(bytes.NewBuffer(haveB)) for i, wantLine := range wantLines { diff --git a/core/mkalloc.go b/core/mkalloc.go index 201c2fe7de8d..cc4955f0383c 100644 --- a/core/mkalloc.go +++ b/core/mkalloc.go @@ -101,6 +101,7 @@ func main() { if err != nil { panic(err) } + defer file.Close() if err := json.NewDecoder(file).Decode(g); err != nil { panic(err) } From 9f96e07c1cf87fdd4d044f95de9c1b5e0b85b47f Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 30 Apr 2024 22:25:35 +0800 Subject: [PATCH 238/571] core/rawdb, trie: improve db APIs for accessing trie nodes (#29362) * core/rawdb, trie: improve db APIs for accessing trie nodes * triedb/pathdb: fix --- cmd/devp2p/internal/ethtest/snap.go | 5 +- cmd/geth/dbcmd.go | 10 ++- core/genesis_test.go | 2 +- core/rawdb/accessors_trie.go | 125 +++++++++------------------- core/rawdb/ancient_utils.go | 7 +- eth/handler.go | 3 +- eth/protocols/snap/gentrie.go | 4 +- eth/protocols/snap/sync.go | 7 +- eth/protocols/snap/sync_test.go | 4 +- trie/hasher.go | 3 +- trie/stacktrie_fuzzer_test.go | 5 +- trie/sync.go | 34 ++++++-- trie/trie_test.go | 4 +- trie/trienode/node.go | 10 --- trie/triestate/state.go | 3 +- triedb/database.go | 9 +- triedb/database/database.go | 3 + triedb/hashdb/database.go | 5 -- triedb/pathdb/database.go | 12 ++- triedb/pathdb/database_test.go | 4 +- triedb/pathdb/difflayer_test.go | 8 +- triedb/pathdb/disklayer.go | 27 +++--- triedb/pathdb/journal.go | 18 ++-- triedb/pathdb/nodebuffer.go | 9 +- 24 files changed, 141 insertions(+), 180 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index 8ff3f1f71a6e..4f1b6f86562a 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -32,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/internal/utesting" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" - "golang.org/x/crypto/sha3" ) func (c *Conn) snapRequest(code uint64, msg any) (any, error) { @@ -905,7 +904,7 @@ func (s *Suite) snapGetByteCodes(t *utesting.T, tc *byteCodesTest) error { // that the serving node is missing var ( bytecodes = res.Codes - hasher = sha3.NewLegacyKeccak256().(crypto.KeccakState) + hasher = crypto.NewKeccakState() hash = make([]byte, 32) codes = make([][]byte, len(req.Hashes)) ) @@ -964,7 +963,7 @@ func (s *Suite) snapGetTrieNodes(t *utesting.T, tc *trieNodesTest) error { // Cross reference the requested trienodes with the response to find gaps // that the serving node is missing - hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + hasher := crypto.NewKeccakState() hash := make([]byte, 32) trienodes := res.Nodes if got, want := len(trienodes), len(tc.expHashes); got != want { diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 4e91a4ff25ed..742eadd5f368 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -246,11 +246,17 @@ func removeDB(ctx *cli.Context) error { ancientDir = config.Node.ResolvePath(ancientDir) } // Delete state data - statePaths := []string{rootDir, filepath.Join(ancientDir, rawdb.StateFreezerName)} + statePaths := []string{ + rootDir, + filepath.Join(ancientDir, rawdb.StateFreezerName), + } confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name) // Delete ancient chain - chainPaths := []string{filepath.Join(ancientDir, rawdb.ChainFreezerName)} + chainPaths := []string{filepath.Join( + ancientDir, + rawdb.ChainFreezerName, + )} confirmAndRemoveDB(chainPaths, "ancient chain", ctx, removeChainDataFlag.Name) return nil } diff --git a/core/genesis_test.go b/core/genesis_test.go index 61be0bd252c6..31401e214cb1 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -322,7 +322,7 @@ func TestVerkleGenesisCommit(t *testing.T) { t.Fatalf("expected trie to be verkle") } - if !rawdb.ExistsAccountTrieNode(db, nil) { + if !rawdb.HasAccountTrieNode(db, nil) { t.Fatal("could not find node") } } diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index e34b24fd7661..44eb715d04e2 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" - "golang.org/x/crypto/sha3" ) // HashScheme is the legacy hash-based state scheme with which trie nodes are @@ -50,7 +49,7 @@ const PathScheme = "path" type hasher struct{ sha crypto.KeccakState } var hasherPool = sync.Pool{ - New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} }, + New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} }, } func newHasher() *hasher { @@ -65,33 +64,15 @@ func (h *hasher) release() { hasherPool.Put(h) } -// ReadAccountTrieNode retrieves the account trie node and the associated node -// hash with the specified node path. -func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.Hash) { - data, err := db.Get(accountTrieNodeKey(path)) - if err != nil { - return nil, common.Hash{} - } - h := newHasher() - defer h.release() - return data, h.hash(data) -} - -// HasAccountTrieNode checks the account trie node presence with the specified -// node path and the associated node hash. -func HasAccountTrieNode(db ethdb.KeyValueReader, path []byte, hash common.Hash) bool { - data, err := db.Get(accountTrieNodeKey(path)) - if err != nil { - return false - } - h := newHasher() - defer h.release() - return h.hash(data) == hash +// ReadAccountTrieNode retrieves the account trie node with the specified node path. +func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) []byte { + data, _ := db.Get(accountTrieNodeKey(path)) + return data } -// ExistsAccountTrieNode checks the presence of the account trie node with the +// HasAccountTrieNode checks the presence of the account trie node with the // specified node path, regardless of the node hash. -func ExistsAccountTrieNode(db ethdb.KeyValueReader, path []byte) bool { +func HasAccountTrieNode(db ethdb.KeyValueReader, path []byte) bool { has, err := db.Has(accountTrieNodeKey(path)) if err != nil { return false @@ -113,33 +94,15 @@ func DeleteAccountTrieNode(db ethdb.KeyValueWriter, path []byte) { } } -// ReadStorageTrieNode retrieves the storage trie node and the associated node -// hash with the specified node path. -func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) { - data, err := db.Get(storageTrieNodeKey(accountHash, path)) - if err != nil { - return nil, common.Hash{} - } - h := newHasher() - defer h.release() - return data, h.hash(data) -} - -// HasStorageTrieNode checks the storage trie node presence with the provided -// node path and the associated node hash. -func HasStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte, hash common.Hash) bool { - data, err := db.Get(storageTrieNodeKey(accountHash, path)) - if err != nil { - return false - } - h := newHasher() - defer h.release() - return h.hash(data) == hash +// ReadStorageTrieNode retrieves the storage trie node with the specified node path. +func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) []byte { + data, _ := db.Get(storageTrieNodeKey(accountHash, path)) + return data } -// ExistsStorageTrieNode checks the presence of the storage trie node with the +// HasStorageTrieNode checks the presence of the storage trie node with the // specified account hash and node path, regardless of the node hash. -func ExistsStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) bool { +func HasStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) bool { has, err := db.Has(storageTrieNodeKey(accountHash, path)) if err != nil { return false @@ -198,10 +161,18 @@ func HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash c case HashScheme: return HasLegacyTrieNode(db, hash) case PathScheme: + var blob []byte if owner == (common.Hash{}) { - return HasAccountTrieNode(db, path, hash) + blob = ReadAccountTrieNode(db, path) + } else { + blob = ReadStorageTrieNode(db, owner, path) } - return HasStorageTrieNode(db, owner, path, hash) + if len(blob) == 0 { + return false + } + h := newHasher() + defer h.release() + return h.hash(blob) == hash // exists but not match default: panic(fmt.Sprintf("Unknown scheme %v", scheme)) } @@ -209,43 +180,35 @@ func HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash c // ReadTrieNode retrieves the trie node from database with the provided node info // and associated node hash. -// hashScheme-based lookup requires the following: -// - hash -// -// pathScheme-based lookup requires the following: -// - owner -// - path func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) []byte { switch scheme { case HashScheme: return ReadLegacyTrieNode(db, hash) case PathScheme: - var ( - blob []byte - nHash common.Hash - ) + var blob []byte if owner == (common.Hash{}) { - blob, nHash = ReadAccountTrieNode(db, path) + blob = ReadAccountTrieNode(db, path) } else { - blob, nHash = ReadStorageTrieNode(db, owner, path) + blob = ReadStorageTrieNode(db, owner, path) } - if nHash != hash { + if len(blob) == 0 { return nil } + h := newHasher() + defer h.release() + if h.hash(blob) != hash { + return nil // exists but not match + } return blob default: panic(fmt.Sprintf("Unknown scheme %v", scheme)) } } -// WriteTrieNode writes the trie node into database with the provided node info -// and associated node hash. -// hashScheme-based lookup requires the following: -// - hash +// WriteTrieNode writes the trie node into database with the provided node info. // -// pathScheme-based lookup requires the following: -// - owner -// - path +// hash-scheme requires the node hash as the identifier. +// path-scheme requires the node owner and path as the identifier. func WriteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, node []byte, scheme string) { switch scheme { case HashScheme: @@ -261,14 +224,10 @@ func WriteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash } } -// DeleteTrieNode deletes the trie node from database with the provided node info -// and associated node hash. -// hashScheme-based lookup requires the following: -// - hash +// DeleteTrieNode deletes the trie node from database with the provided node info. // -// pathScheme-based lookup requires the following: -// - owner -// - path +// hash-scheme requires the node hash as the identifier. +// path-scheme requires the node owner and path as the identifier. func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, scheme string) { switch scheme { case HashScheme: @@ -287,9 +246,8 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has // ReadStateScheme reads the state scheme of persistent state, or none // if the state is not present in database. func ReadStateScheme(db ethdb.Reader) string { - // Check if state in path-based scheme is present - blob, _ := ReadAccountTrieNode(db, nil) - if len(blob) != 0 { + // Check if state in path-based scheme is present. + if HasAccountTrieNode(db, nil) { return PathScheme } // The root node might be deleted during the initial snap sync, check @@ -304,8 +262,7 @@ func ReadStateScheme(db ethdb.Reader) string { if header == nil { return "" // empty datadir } - blob = ReadLegacyTrieNode(db, header.Root) - if len(blob) == 0 { + if !HasLegacyTrieNode(db, header.Root) { return "" // no state in disk } return HashScheme diff --git a/core/rawdb/ancient_utils.go b/core/rawdb/ancient_utils.go index 428cda544b03..1c69639c9d04 100644 --- a/core/rawdb/ancient_utils.go +++ b/core/rawdb/ancient_utils.go @@ -89,20 +89,17 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { infos = append(infos, info) case StateFreezerName: - if ReadStateScheme(db) != PathScheme { - continue - } datadir, err := db.AncientDatadir() if err != nil { return nil, err } f, err := NewStateFreezer(datadir, true) if err != nil { - return nil, err + continue // might be possible the state freezer is not existent } defer f.Close() - info, err := inspect(StateFreezerName, stateFreezerNoSnappy, f) + info, err := inspect(freezer, stateFreezerNoSnappy, f) if err != nil { return nil, err } diff --git a/eth/handler.go b/eth/handler.go index c7c582af407b..143ac2a8a57b 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -42,7 +42,6 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/triedb/pathdb" - "golang.org/x/crypto/sha3" ) const ( @@ -480,7 +479,7 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { var ( signer = types.LatestSignerForChainID(h.chain.Config().ChainID) // Don't care about chain status, we just need *a* sender - hasher = sha3.NewLegacyKeccak256().(crypto.KeccakState) + hasher = crypto.NewKeccakState() hash = make([]byte, 32) ) for _, tx := range txs { diff --git a/eth/protocols/snap/gentrie.go b/eth/protocols/snap/gentrie.go index 81c2640b62f3..6255fb221db1 100644 --- a/eth/protocols/snap/gentrie.go +++ b/eth/protocols/snap/gentrie.go @@ -164,7 +164,7 @@ func (t *pathTrie) deleteAccountNode(path []byte, inner bool) { } else { accountOuterLookupGauge.Inc(1) } - if !rawdb.ExistsAccountTrieNode(t.db, path) { + if !rawdb.HasAccountTrieNode(t.db, path) { return } if inner { @@ -181,7 +181,7 @@ func (t *pathTrie) deleteStorageNode(path []byte, inner bool) { } else { storageOuterLookupGauge.Inc(1) } - if !rawdb.ExistsStorageTrieNode(t.db, t.owner, path) { + if !rawdb.HasStorageTrieNode(t.db, t.owner, path) { return } if inner { diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index b0ddb8e403f7..ffda718700f4 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -42,7 +42,6 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" - "golang.org/x/crypto/sha3" ) const ( @@ -2653,7 +2652,7 @@ func (s *Syncer) onByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) error // Cross reference the requested bytecodes with the response to find gaps // that the serving node is missing - hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + hasher := crypto.NewKeccakState() hash := make([]byte, 32) codes := make([][]byte, len(req.hashes)) @@ -2901,7 +2900,7 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error // Cross reference the requested trienodes with the response to find gaps // that the serving node is missing var ( - hasher = sha3.NewLegacyKeccak256().(crypto.KeccakState) + hasher = crypto.NewKeccakState() hash = make([]byte, 32) nodes = make([][]byte, len(req.hashes)) fills uint64 @@ -3007,7 +3006,7 @@ func (s *Syncer) onHealByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) e // Cross reference the requested bytecodes with the response to find gaps // that the serving node is missing - hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + hasher := crypto.NewKeccakState() hash := make([]byte, 32) codes := make([][]byte, len(req.hashes)) diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index f35babb73109..5f6826373a90 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -64,7 +64,7 @@ func TestHashing(t *testing.T) { } } var new = func() { - hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + hasher := crypto.NewKeccakState() var hash = make([]byte, 32) for i := 0; i < len(bytecodes); i++ { hasher.Reset() @@ -96,7 +96,7 @@ func BenchmarkHashing(b *testing.B) { } } var new = func() { - hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + hasher := crypto.NewKeccakState() var hash = make([]byte, 32) for i := 0; i < len(bytecodes); i++ { hasher.Reset() diff --git a/trie/hasher.go b/trie/hasher.go index 1e063d8020b9..abf654c709cf 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -21,7 +21,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/crypto/sha3" ) // hasher is a type used for the trie Hash operation. A hasher has some @@ -38,7 +37,7 @@ var hasherPool = sync.Pool{ New: func() interface{} { return &hasher{ tmp: make([]byte, 0, 550), // cap is as large as a full fullNode. - sha: sha3.NewLegacyKeccak256().(crypto.KeccakState), + sha: crypto.NewKeccakState(), encbuf: rlp.NewEncoderBuffer(nil), } }, diff --git a/trie/stacktrie_fuzzer_test.go b/trie/stacktrie_fuzzer_test.go index 5126e0bd07ce..418b941d94e1 100644 --- a/trie/stacktrie_fuzzer_test.go +++ b/trie/stacktrie_fuzzer_test.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie/trienode" - "golang.org/x/crypto/sha3" ) func FuzzStackTrie(f *testing.F) { @@ -41,10 +40,10 @@ func fuzz(data []byte, debugging bool) { // This spongeDb is used to check the sequence of disk-db-writes var ( input = bytes.NewReader(data) - spongeA = &spongeDb{sponge: sha3.NewLegacyKeccak256()} + spongeA = &spongeDb{sponge: crypto.NewKeccakState()} dbA = newTestDatabase(rawdb.NewDatabase(spongeA), rawdb.HashScheme) trieA = NewEmpty(dbA) - spongeB = &spongeDb{sponge: sha3.NewLegacyKeccak256()} + spongeB = &spongeDb{sponge: crypto.NewKeccakState()} dbB = newTestDatabase(rawdb.NewDatabase(spongeB), rawdb.HashScheme) trieB = NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { rawdb.WriteTrieNode(spongeB, common.Hash{}, path, hash, blob, dbB.Scheme()) diff --git a/trie/sync.go b/trie/sync.go index 589d28364b87..f6b20b224025 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -546,9 +547,9 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { // the performance impact negligible. var exists bool if owner == (common.Hash{}) { - exists = rawdb.ExistsAccountTrieNode(s.database, append(inner, key[:i]...)) + exists = rawdb.HasAccountTrieNode(s.database, append(inner, key[:i]...)) } else { - exists = rawdb.ExistsStorageTrieNode(s.database, owner, append(inner, key[:i]...)) + exists = rawdb.HasStorageTrieNode(s.database, owner, append(inner, key[:i]...)) } if exists { s.membatch.delNode(owner, append(inner, key[:i]...)) @@ -691,13 +692,14 @@ func (s *Sync) hasNode(owner common.Hash, path []byte, hash common.Hash) (exists } // If node is running with path scheme, check the presence with node path. var blob []byte - var dbHash common.Hash if owner == (common.Hash{}) { - blob, dbHash = rawdb.ReadAccountTrieNode(s.database, path) + blob = rawdb.ReadAccountTrieNode(s.database, path) } else { - blob, dbHash = rawdb.ReadStorageTrieNode(s.database, owner, path) + blob = rawdb.ReadStorageTrieNode(s.database, owner, path) } - exists = hash == dbHash + h := newBlobHasher() + defer h.release() + exists = hash == h.hash(blob) inconsistent = !exists && len(blob) != 0 return exists, inconsistent } @@ -712,3 +714,23 @@ func ResolvePath(path []byte) (common.Hash, []byte) { } return owner, path } + +// blobHasher is used to compute the sha256 hash of the provided data. +type blobHasher struct{ state crypto.KeccakState } + +// blobHasherPool is the pool for reusing pre-allocated hash state. +var blobHasherPool = sync.Pool{ + New: func() interface{} { return &blobHasher{state: crypto.NewKeccakState()} }, +} + +func newBlobHasher() *blobHasher { + return blobHasherPool.Get().(*blobHasher) +} + +func (h *blobHasher) hash(data []byte) common.Hash { + return crypto.HashData(h.state, data) +} + +func (h *blobHasher) release() { + blobHasherPool.Put(h) +} diff --git a/trie/trie_test.go b/trie/trie_test.go index 6ecd20c21894..da60a7423dff 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -886,7 +886,7 @@ func TestCommitSequence(t *testing.T) { } { addresses, accounts := makeAccounts(tc.count) // This spongeDb is used to check the sequence of disk-db-writes - s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} + s := &spongeDb{sponge: crypto.NewKeccakState()} db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme) trie := NewEmpty(db) // Fill the trie with elements @@ -917,7 +917,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { } { prng := rand.New(rand.NewSource(int64(i))) // This spongeDb is used to check the sequence of disk-db-writes - s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} + s := &spongeDb{sponge: crypto.NewKeccakState()} db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme) trie := NewEmpty(db) // Fill the trie with elements diff --git a/trie/trienode/node.go b/trie/trienode/node.go index bc93e3ca88f0..aa8a0f6d99b6 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -135,16 +135,6 @@ func (set *NodeSet) Size() (int, int) { return set.updates, set.deletes } -// Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can -// we get rid of it? -func (set *NodeSet) Hashes() []common.Hash { - ret := make([]common.Hash, 0, len(set.Nodes)) - for _, node := range set.Nodes { - ret = append(ret, node.Hash) - } - return ret -} - // Summary returns a string-representation of the NodeSet. func (set *NodeSet) Summary() string { var out = new(strings.Builder) diff --git a/trie/triestate/state.go b/trie/triestate/state.go index aa4d32f852f9..9db9211e8c87 100644 --- a/trie/triestate/state.go +++ b/trie/triestate/state.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" - "golang.org/x/crypto/sha3" ) // Trie is an Ethereum state trie, can be implemented by Ethereum Merkle Patricia @@ -257,7 +256,7 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error { type hasher struct{ sha crypto.KeccakState } var hasherPool = sync.Pool{ - New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} }, + New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} }, } func newHasher() *hasher { diff --git a/triedb/database.go b/triedb/database.go index 261a47dcc2c7..10f77982f336 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -20,6 +20,7 @@ import ( "errors" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie" @@ -48,9 +49,6 @@ var HashDefaults = &Config{ // backend defines the methods needed to access/update trie nodes in different // state scheme. type backend interface { - // Scheme returns the identifier of used storage scheme. - Scheme() string - // Initialized returns an indicator if the state data is already initialized // according to the state scheme. Initialized(genesisRoot common.Hash) bool @@ -181,7 +179,10 @@ func (db *Database) Initialized(genesisRoot common.Hash) bool { // Scheme returns the node scheme used in the database. func (db *Database) Scheme() string { - return db.backend.Scheme() + if db.config.PathDB != nil { + return rawdb.PathScheme + } + return rawdb.HashScheme } // Close flushes the dangling preimages to disk and closes the trie database. diff --git a/triedb/database/database.go b/triedb/database/database.go index 18a8f454e2f4..f11c7e9bbd3e 100644 --- a/triedb/database/database.go +++ b/triedb/database/database.go @@ -25,6 +25,9 @@ type Reader interface { // Node retrieves the trie node blob with the provided trie identifier, // node path and the corresponding node hash. No error will be returned // if the node is not found. + // + // Don't modify the returned byte slice since it's not deep-copied and + // still be referenced by database. Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) } diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index 7d5499eb693a..ebb5d7205712 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -623,11 +623,6 @@ func (db *Database) Close() error { return nil } -// Scheme returns the node scheme used in the database. -func (db *Database) Scheme() string { - return rawdb.HashScheme -} - // Reader retrieves a node reader belonging to the given state root. // An error will be returned if the requested state is not available. func (db *Database) Reader(root common.Hash) (*reader, error) { diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 50beebced124..05a28aa1efa6 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -306,8 +307,10 @@ func (db *Database) Enable(root common.Hash) error { } // Ensure the provided state root matches the stored one. root = types.TrieRootHash(root) - _, stored := rawdb.ReadAccountTrieNode(db.diskdb, nil) - stored = types.TrieRootHash(stored) + stored := types.EmptyRootHash + if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 { + stored = crypto.Keccak256Hash(blob) + } if stored != root { return fmt.Errorf("state root mismatch: stored %x, synced %x", stored, root) } @@ -480,11 +483,6 @@ func (db *Database) SetBufferSize(size int) error { return db.tree.bottom().setBufferSize(db.bufferSize) } -// Scheme returns the node scheme used in the database. -func (db *Database) Scheme() string { - return rawdb.PathScheme -} - // modifyAllowed returns the indicator if mutation is allowed. This function // assumes the db.lock is already held. func (db *Database) modifyAllowed() error { diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 29de534589d2..7b240823154d 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -474,7 +474,7 @@ func TestDisable(t *testing.T) { tester := newTester(t, 0) defer tester.release() - _, stored := rawdb.ReadAccountTrieNode(tester.db.diskdb, nil) + stored := crypto.Keccak256Hash(rawdb.ReadAccountTrieNode(tester.db.diskdb, nil)) if err := tester.db.Disable(); err != nil { t.Fatalf("Failed to deactivate database: %v", err) } @@ -580,7 +580,7 @@ func TestCorruptedJournal(t *testing.T) { t.Errorf("Failed to journal, err: %v", err) } tester.db.Close() - _, root := rawdb.ReadAccountTrieNode(tester.db.diskdb, nil) + root := crypto.Keccak256Hash(rawdb.ReadAccountTrieNode(tester.db.diskdb, nil)) // Mutate the journal in disk, it should be regarded as invalid blob := rawdb.ReadTrieJournal(tester.db.diskdb) diff --git a/triedb/pathdb/difflayer_test.go b/triedb/pathdb/difflayer_test.go index bf4c6502efbd..1e93a3f89214 100644 --- a/triedb/pathdb/difflayer_test.go +++ b/triedb/pathdb/difflayer_test.go @@ -70,10 +70,10 @@ func benchmarkSearch(b *testing.B, depth int, total int) { blob = testrand.Bytes(100) node = trienode.New(crypto.Keccak256Hash(blob), blob) ) - nodes[common.Hash{}][string(path)] = trienode.New(node.Hash, node.Blob) + nodes[common.Hash{}][string(path)] = node if npath == nil && depth == index { npath = common.CopyBytes(path) - nblob = common.CopyBytes(node.Blob) + nblob = common.CopyBytes(blob) } } return newDiffLayer(parent, common.Hash{}, 0, 0, nodes, nil) @@ -116,7 +116,7 @@ func BenchmarkPersist(b *testing.B) { blob = testrand.Bytes(100) node = trienode.New(crypto.Keccak256Hash(blob), blob) ) - nodes[common.Hash{}][string(path)] = trienode.New(node.Hash, node.Blob) + nodes[common.Hash{}][string(path)] = node } return newDiffLayer(parent, common.Hash{}, 0, 0, nodes, nil) } @@ -154,7 +154,7 @@ func BenchmarkJournal(b *testing.B) { blob = testrand.Bytes(100) node = trienode.New(crypto.Keccak256Hash(blob), blob) ) - nodes[common.Hash{}][string(path)] = trienode.New(node.Hash, node.Blob) + nodes[common.Hash{}][string(path)] = node } // TODO(rjl493456442) a non-nil state set is expected. return newDiffLayer(parent, common.Hash{}, 0, 0, nodes, nil) diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index ec7c91bcacfd..964ad2ef777d 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -27,7 +27,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" - "golang.org/x/crypto/sha3" ) // diskLayer is a low level persistent layer built on top of a key-value store. @@ -117,12 +116,12 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co dirtyMissMeter.Mark(1) // Try to retrieve the trie node from the clean memory cache + h := newHasher() + defer h.release() + key := cacheKey(owner, path) if dl.cleans != nil { if blob := dl.cleans.Get(nil, key); len(blob) > 0 { - h := newHasher() - defer h.release() - cleanHitMeter.Mark(1) cleanReadMeter.Mark(int64(len(blob))) return blob, h.hash(blob), &nodeLoc{loc: locCleanCache, depth: depth}, nil @@ -130,20 +129,18 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co cleanMissMeter.Mark(1) } // Try to retrieve the trie node from the disk. - var ( - nBlob []byte - nHash common.Hash - ) + var blob []byte if owner == (common.Hash{}) { - nBlob, nHash = rawdb.ReadAccountTrieNode(dl.db.diskdb, path) + blob = rawdb.ReadAccountTrieNode(dl.db.diskdb, path) } else { - nBlob, nHash = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path) + blob = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path) } - if dl.cleans != nil && len(nBlob) > 0 { - dl.cleans.Set(key, nBlob) - cleanWriteMeter.Mark(int64(len(nBlob))) + if dl.cleans != nil && len(blob) > 0 { + dl.cleans.Set(key, blob) + cleanWriteMeter.Mark(int64(len(blob))) } - return nBlob, nHash, &nodeLoc{loc: locDiskLayer, depth: depth}, nil + + return blob, h.hash(blob), &nodeLoc{loc: locDiskLayer, depth: depth}, nil } // update implements the layer interface, returning a new diff layer on top @@ -303,7 +300,7 @@ func (dl *diskLayer) resetCache() { type hasher struct{ sha crypto.KeccakState } var hasherPool = sync.Pool{ - New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} }, + New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} }, } func newHasher() *hasher { diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index 3a0b7ebae273..1740ec593511 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -120,9 +120,10 @@ func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) { // loadLayers loads a pre-existing state layer backed by a key-value store. func (db *Database) loadLayers() layer { // Retrieve the root node of persistent state. - _, root := rawdb.ReadAccountTrieNode(db.diskdb, nil) - root = types.TrieRootHash(root) - + var root = types.EmptyRootHash + if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 { + root = crypto.Keccak256Hash(blob) + } // Load the layers by resolving the journal head, err := db.loadJournal(root) if err == nil { @@ -361,14 +362,13 @@ func (db *Database) Journal(root common.Hash) error { if err := rlp.Encode(journal, journalVersion); err != nil { return err } - // The stored state in disk might be empty, convert the - // root to emptyRoot in this case. - _, diskroot := rawdb.ReadAccountTrieNode(db.diskdb, nil) - diskroot = types.TrieRootHash(diskroot) - // Secondly write out the state root in disk, ensure all layers // on top are continuous with disk. - if err := rlp.Encode(journal, diskroot); err != nil { + diskRoot := types.EmptyRootHash + if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 { + diskRoot = crypto.Keccak256Hash(blob) + } + if err := rlp.Encode(journal, diskRoot); err != nil { return err } // Finally write out the journal of each layer in reverse order. diff --git a/triedb/pathdb/nodebuffer.go b/triedb/pathdb/nodebuffer.go index 4a13fcc44e8c..5675f141232b 100644 --- a/triedb/pathdb/nodebuffer.go +++ b/triedb/pathdb/nodebuffer.go @@ -17,6 +17,7 @@ package pathdb import ( + "bytes" "fmt" "time" @@ -148,14 +149,14 @@ func (b *nodebuffer) revert(db ethdb.KeyValueReader, nodes map[common.Hash]map[s // // In case of database rollback, don't panic if this "clean" // node occurs which is not present in buffer. - var nhash common.Hash + var blob []byte if owner == (common.Hash{}) { - _, nhash = rawdb.ReadAccountTrieNode(db, []byte(path)) + blob = rawdb.ReadAccountTrieNode(db, []byte(path)) } else { - _, nhash = rawdb.ReadStorageTrieNode(db, owner, []byte(path)) + blob = rawdb.ReadStorageTrieNode(db, owner, []byte(path)) } // Ignore the clean node in the case described above. - if nhash == n.Hash { + if bytes.Equal(blob, n.Blob) { continue } panic(fmt.Sprintf("non-existent node (%x %v) blob: %v", owner, path, crypto.Keccak256Hash(n.Blob).Hex())) From 682ee820fa116b8a081d269c9d155ec19411959b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 2 May 2024 11:18:27 +0300 Subject: [PATCH 239/571] core/state: parallelise parts of state commit (#29681) * core/state, internal/workerpool: parallelize parts of state commit * core, internal: move workerpool into syncx * core/state: use errgroups, commit accounts concurrently * core: resurrect detailed commit timers to almost-accuracy --- core/blockchain.go | 2 +- core/state/state_object.go | 3 + core/state/statedb.go | 126 +++++++++++++++++++++++++------------ 3 files changed, 89 insertions(+), 42 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 9de4baccca75..654b4fbdcac2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1963,7 +1963,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them - blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) + blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits) blockInsertTimer.UpdateSince(start) return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil diff --git a/core/state/state_object.go b/core/state/state_object.go index 1454f7a459a5..d75ba01376bd 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -403,6 +403,9 @@ func (s *stateObject) updateRoot() { // commit obtains a set of dirty storage trie nodes and updates the account data. // The returned set can be nil if nothing to commit. This function assumes all // storage mutations have already been flushed into trie by updateRoot. +// +// Note, commit may run concurrently across all the state objects. Do not assume +// thread-safe access to the statedb. func (s *stateObject) commit() (*trienode.NodeSet, error) { // Short circuit if trie is not even loaded, don't bother with committing anything if s.trie == nil { diff --git a/core/state/statedb.go b/core/state/statedb.go index 6d9cc907e03f..66cfc8f05a32 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -23,6 +23,7 @@ import ( "math/big" "slices" "sort" + "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -37,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" "github.com/holiman/uint256" + "golang.org/x/sync/errgroup" ) type revision struct { @@ -1146,66 +1148,108 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er storageTrieNodesUpdated int storageTrieNodesDeleted int nodes = trienode.NewMergedNodeSet() - codeWriter = s.db.DiskDB().NewBatch() ) // Handle all state deletions first if err := s.handleDestruction(nodes); err != nil { return common.Hash{}, err } - // Handle all state updates afterwards + // Handle all state updates afterwards, concurrently to one another to shave + // off some milliseconds from the commit operation. Also accumulate the code + // writes to run in parallel with the computations. start := time.Now() + var ( + code = s.db.DiskDB().NewBatch() + lock sync.Mutex + root common.Hash + workers errgroup.Group + ) + // Schedule the account trie first since that will be the biggest, so give + // it the most time to crunch. + // + // TODO(karalabe): This account trie commit is *very* heavy. 5-6ms at chain + // heads, which seems excessive given that it doesn't do hashing, it just + // shuffles some data. For comparison, the *hashing* at chain head is 2-3ms. + // We need to investigate what's happening as it seems something's wonky. + // Obviously it's not an end of the world issue, just something the original + // code didn't anticipate for. + workers.Go(func() error { + // Write the account trie changes, measuring the amount of wasted time + newroot, set, err := s.trie.Commit(true) + if err != nil { + return err + } + root = newroot + + // Merge the dirty nodes of account trie into global set + lock.Lock() + defer lock.Unlock() + + if set != nil { + if err = nodes.Merge(set); err != nil { + return err + } + accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() + } + s.AccountCommits = time.Since(start) + return nil + }) + // Schedule each of the storage tries that need to be updated, so they can + // run concurrently to one another. + // + // TODO(karalabe): Experimentally, the account commit takes approximately the + // same time as all the storage commits combined, so we could maybe only have + // 2 threads in total. But that kind of depends on the account commit being + // more expensive than it should be, so let's fix that and revisit this todo. for addr, op := range s.mutations { if op.isDelete() { continue } - obj := s.stateObjects[addr] - // Write any contract code associated with the state object + obj := s.stateObjects[addr] if obj.code != nil && obj.dirtyCode { - rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) + rawdb.WriteCode(code, common.BytesToHash(obj.CodeHash()), obj.code) obj.dirtyCode = false } - // Write any storage changes in the state object to its storage trie - set, err := obj.commit() - if err != nil { - return common.Hash{}, err - } - // Merge the dirty nodes of storage trie into global set. It is possible - // that the account was destructed and then resurrected in the same block. - // In this case, the node set is shared by both accounts. - if set != nil { - if err := nodes.Merge(set); err != nil { - return common.Hash{}, err + // Run the storage updates concurrently to one another + workers.Go(func() error { + // Write any storage changes in the state object to its storage trie + set, err := obj.commit() + if err != nil { + return err } - updates, deleted := set.Size() - storageTrieNodesUpdated += updates - storageTrieNodesDeleted += deleted - } + // Merge the dirty nodes of storage trie into global set. It is possible + // that the account was destructed and then resurrected in the same block. + // In this case, the node set is shared by both accounts. + lock.Lock() + defer lock.Unlock() + + if set != nil { + if err = nodes.Merge(set); err != nil { + return err + } + updates, deleted := set.Size() + storageTrieNodesUpdated += updates + storageTrieNodesDeleted += deleted + } + s.StorageCommits = time.Since(start) // overwrite with the longest storage commit runtime + return nil + }) } - s.StorageCommits += time.Since(start) - - if codeWriter.ValueSize() > 0 { - if err := codeWriter.Write(); err != nil { - log.Crit("Failed to commit dirty codes", "error", err) + // Schedule the code commits to run concurrently too. This shouldn't really + // take much since we don't often commit code, but since it's disk access, + // it's always yolo. + workers.Go(func() error { + if code.ValueSize() > 0 { + if err := code.Write(); err != nil { + log.Crit("Failed to commit dirty codes", "error", err) + } } - } - // Write the account trie changes, measuring the amount of wasted time - start = time.Now() - - root, set, err := s.trie.Commit(true) - if err != nil { + return nil + }) + // Wait for everything to finish and update the metrics + if err := workers.Wait(); err != nil { return common.Hash{}, err } - // Merge the dirty nodes of account trie into global set - if set != nil { - if err := nodes.Merge(set); err != nil { - return common.Hash{}, err - } - accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() - } - // Report the commit metrics - s.AccountCommits += time.Since(start) - accountUpdatedMeter.Mark(int64(s.AccountUpdated)) storageUpdatedMeter.Mark(int64(s.StorageUpdated)) accountDeletedMeter.Mark(int64(s.AccountDeleted)) From bc609e852afd1c10b0dc9e677d8c37cfde17fc04 Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Thu, 2 May 2024 16:18:59 +0800 Subject: [PATCH 240/571] core/vm: remove redundant error checks (#29692) --- core/vm/contracts.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 527d9f4f470b..8b648062e993 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -1123,9 +1123,6 @@ func (c *bls12381MapG1) Run(input []byte) ([]byte, error) { // Compute mapping r := bls12381.MapToG1(fe) - if err != nil { - return nil, err - } // Encode the G1 point to 128 bytes return encodePointG1(&r), nil @@ -1159,9 +1156,6 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { // Compute mapping r := bls12381.MapToG2(bls12381.E2{A0: c0, A1: c1}) - if err != nil { - return nil, err - } // Encode the G2 point to 256 bytes return encodePointG2(&r), nil From fbf6238ae9c4ee61d1a5f60b523763e75e11d07b Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 2 May 2024 16:21:11 +0800 Subject: [PATCH 241/571] params: fix misleading comments (#29684) --- params/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/params/config.go b/params/config.go index 62acaddaadd2..534e57831add 100644 --- a/params/config.go +++ b/params/config.go @@ -566,17 +566,17 @@ func (c *ChainConfig) IsShanghai(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.ShanghaiTime, time) } -// IsCancun returns whether num is either equal to the Cancun fork time or greater. +// IsCancun returns whether time is either equal to the Cancun fork time or greater. func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.CancunTime, time) } -// IsPrague returns whether num is either equal to the Prague fork time or greater. +// IsPrague returns whether time is either equal to the Prague fork time or greater. func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) } -// IsVerkle returns whether num is either equal to the Verkle fork time or greater. +// IsVerkle returns whether time is either equal to the Verkle fork time or greater. func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) } From 2c67fab0d7cb95319c111e150a7ac857819e2a74 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 2 May 2024 17:35:45 +0800 Subject: [PATCH 242/571] trie/pathdb: preallocate map capacity (#29690) * preallocated capacity for map's certain usege of memory * preallocated capacity for map's certain usege of memory --- triedb/pathdb/nodebuffer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triedb/pathdb/nodebuffer.go b/triedb/pathdb/nodebuffer.go index 5675f141232b..ff0948410059 100644 --- a/triedb/pathdb/nodebuffer.go +++ b/triedb/pathdb/nodebuffer.go @@ -90,7 +90,7 @@ func (b *nodebuffer) commit(nodes map[common.Hash]map[string]*trienode.Node) *no // The nodes belong to original diff layer are still accessible even // after merging, thus the ownership of nodes map should still belong // to original layer and any mutation on it should be prevented. - current = make(map[string]*trienode.Node) + current = make(map[string]*trienode.Node, len(subset)) for path, n := range subset { current[path] = n delta += int64(len(n.Blob) + len(path)) From 86a1f0c39494c8f5caddf6bd9fbddd4bdfa944fd Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 2 May 2024 18:26:07 +0800 Subject: [PATCH 243/571] core/rawdb: fix ancient root folder (#29697) --- core/rawdb/database.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 0a9f6f73c76b..3436958de735 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -197,10 +197,11 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st // Create the idle freezer instance. If the given ancient directory is empty, // in-memory chain freezer is used (e.g. dev mode); otherwise the regular // file-based freezer is created. - if ancient != "" { - ancient = resolveChainFreezerDir(ancient) + chainFreezerDir := ancient + if chainFreezerDir != "" { + chainFreezerDir = resolveChainFreezerDir(chainFreezerDir) } - frdb, err := newChainFreezer(ancient, namespace, readonly) + frdb, err := newChainFreezer(chainFreezerDir, namespace, readonly) if err != nil { printChainMetadata(db) return nil, err From 905e325cd85c55d6408373f7bf20ea7c525f6900 Mon Sep 17 00:00:00 2001 From: Kiarash Hajian <133909368+kiarash8112@users.noreply.github.com> Date: Mon, 6 May 2024 07:17:19 -0400 Subject: [PATCH 244/571] p2p/discover/v5wire: add tests for invalid handshake and auth data size (#29708) --- p2p/discover/v5wire/encoding_test.go | 36 +++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index a5387311a5d0..27966f2afc6b 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -30,6 +30,7 @@ import ( "testing" "github.com/davecgh/go-spew/spew" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/crypto" @@ -283,9 +284,38 @@ func TestDecodeErrorsV5(t *testing.T) { b = make([]byte, 63) net.nodeA.expectDecodeErr(t, errInvalidHeader, b) - // TODO some more tests would be nice :) - // - check invalid authdata sizes - // - check invalid handshake data sizes + t.Run("invalid-handshake-datasize", func(t *testing.T) { + requiredNumber := 108 + + testDataFile := filepath.Join("testdata", "v5.1-ping-handshake"+".txt") + enc := hexFile(testDataFile) + //delete some byte from handshake to make it invalid + enc = enc[:len(enc)-requiredNumber] + net.nodeB.expectDecodeErr(t, errMsgTooShort, enc) + }) + + t.Run("invalid-auth-datasize", func(t *testing.T) { + testPacket := []byte{} + testDataFiles := []string{"v5.1-whoareyou", "v5.1-ping-handshake"} + for counter, name := range testDataFiles { + file := filepath.Join("testdata", name+".txt") + enc := hexFile(file) + if counter == 0 { + //make whoareyou header + testPacket = enc[:sizeofStaticPacketData-1] + testPacket = append(testPacket, 255) + } + if counter == 1 { + //append invalid auth size + testPacket = append(testPacket, enc[sizeofStaticPacketData:]...) + } + } + + wantErr := "invalid auth size" + if _, err := net.nodeB.decode(testPacket); strings.HasSuffix(err.Error(), wantErr) { + t.Fatal(fmt.Errorf("(%s) got err %q, want %q", net.nodeB.ln.ID().TerminalString(), err, wantErr)) + } + }) } // This test checks that all test vectors can be decoded. From a09a6103846544a20dfccbe16532d2843f277c5f Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Mon, 6 May 2024 07:21:55 -0400 Subject: [PATCH 245/571] core/tracing: add system call callback when performing `ProcessBeaconBlockRoot` (#29355) Added a start/end system where tracer can be notified that processing of some Ethereum system calls is starting processing and also notifies it when the processing has completed. Doing a start/end for system call will enable tracers to "route" incoming next tracing events to go to a separate bucket than other EVM calls. Those not interested by this fact can simply avoid registering the hooks. The EVM call is going to be traced normally afterward between the signals provided by those 2 new hooks but outside of a transaction context OnTxStart/End. That something implementors of live tracers will need to be aware of (since only "trx tracers" are not concerned by ProcessBeaconRoot). --------- Co-authored-by: Sina Mahmoodi --- core/state_processor.go | 7 +++++++ core/tracing/CHANGELOG.md | 12 +++++++++++- core/tracing/hooks.go | 38 ++++++++++++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index b1a8938f677a..7166ed8bd872 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -186,6 +186,13 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // contract. This method is exported to be used in tests. func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { + if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil { + vmenv.Config.Tracer.OnSystemCallStart() + } + if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil { + defer vmenv.Config.Tracer.OnSystemCallEnd() + } + // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with // the new root msg := &Message{ diff --git a/core/tracing/CHANGELOG.md b/core/tracing/CHANGELOG.md index 77eda4ad7627..93b91cf479b5 100644 --- a/core/tracing/CHANGELOG.md +++ b/core/tracing/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to the tracing interface will be documented in this file. ## [Unreleased] +There have been minor backwards-compatible changes to the tracing interface to explicitly mark the execution of **system** contracts. As of now the only system call updates the parent beacon block root as per [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). Other system calls are being considered for the future hardfork. + +### New methods + +- `OnSystemCallStart()`: This hook is called when EVM starts processing a system call. Note system calls happen outside the scope of a transaction. This event will be followed by normal EVM execution events. +- `OnSystemCallEnd()`: This hook is called when EVM finishes processing a system call. + +## [v1.14.0] + There has been a major breaking change in the tracing interface for custom native tracers. JS and built-in tracers are not affected by this change and tracing API methods may be used as before. This overhaul has been done as part of the new live tracing feature ([#29189](https://github.com/ethereum/go-ethereum/pull/29189)). To learn more about live tracing please refer to the [docs](https://geth.ethereum.org/docs/developers/evm-tracing/live-tracing). **The `EVMLogger` interface which the tracers implemented has been removed.** It has been replaced by a new struct `tracing.Hooks`. `Hooks` keeps pointers to event listening functions. Internally the EVM will use these function pointers to emit events and can skip an event if the tracer has opted not to implement it. In fact this is the main reason for this change of approach. Another benefit is the ease of adding new hooks in future, and dynamically assigning event receivers. @@ -66,4 +75,5 @@ The hooks `CaptureStart` and `CaptureEnd` have been removed. These hooks signale - `CaptureState` -> `OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error)`. `op` is of type `byte` which can be cast to `vm.OpCode` when necessary. A `*vm.ScopeContext` is not passed anymore. It is replaced by `tracing.OpContext` which offers access to the memory, stack and current contract. - `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above. -[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.13.14...master \ No newline at end of file +[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.0...master +[v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0 \ No newline at end of file diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 9ca6ee39fbe7..41bae63d9fa2 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -81,6 +81,10 @@ type ( TxEndHook = func(receipt *types.Receipt, err error) // EnterHook is invoked when the processing of a message starts. + // + // Take note that EnterHook, when in the context of a live tracer, can be invoked + // outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls, + // see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information. EnterHook = func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) // ExitHook is invoked when the processing of a message ends. @@ -89,6 +93,10 @@ type ( // ran out of gas when attempting to persist the code to database did not // count as a call failure and did not cause a revert of the call. This will // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. + // + // Take note that ExitHook, when in the context of a live tracer, can be invoked + // outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls, + // see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information. ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool) // OpcodeHook is invoked just prior to the execution of an opcode. @@ -125,6 +133,22 @@ type ( // GenesisBlockHook is called when the genesis block is being processed. GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc) + // OnSystemCallStartHook is called when a system call is about to be executed. Today, + // this hook is invoked when the EIP-4788 system call is about to be executed to set the + // beacon block root. + // + // After this hook, the EVM call tracing will happened as usual so you will receive a `OnEnter/OnExit` + // as well as state hooks between this hook and the `OnSystemCallEndHook`. + // + // Note that system call happens outside normal transaction execution, so the `OnTxStart/OnTxEnd` hooks + // will not be invoked. + OnSystemCallStartHook = func() + + // OnSystemCallEndHook is called when a system call has finished executing. Today, + // this hook is invoked when the EIP-4788 system call is about to be executed to set the + // beacon block root. + OnSystemCallEndHook = func() + /* - State events - */ @@ -155,12 +179,14 @@ type Hooks struct { OnFault FaultHook OnGasChange GasChangeHook // Chain events - OnBlockchainInit BlockchainInitHook - OnClose CloseHook - OnBlockStart BlockStartHook - OnBlockEnd BlockEndHook - OnSkippedBlock SkippedBlockHook - OnGenesisBlock GenesisBlockHook + OnBlockchainInit BlockchainInitHook + OnClose CloseHook + OnBlockStart BlockStartHook + OnBlockEnd BlockEndHook + OnSkippedBlock SkippedBlockHook + OnGenesisBlock GenesisBlockHook + OnSystemCallStart OnSystemCallStartHook + OnSystemCallEnd OnSystemCallEndHook // State events OnBalanceChange BalanceChangeHook OnNonceChange NonceChangeHook From 43cbcd78ea78a690cf8604cfa3035a3d1e67a794 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 6 May 2024 13:28:53 +0200 Subject: [PATCH 246/571] core, core/state: move TriesInMemory to state package (#29701) --- core/blockchain.go | 17 ++++++++--------- core/blockchain_test.go | 36 ++++++++++++++++++------------------ core/state/statedb.go | 9 ++++++--- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 654b4fbdcac2..56e00e85b615 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -100,7 +100,6 @@ const ( blockCacheLimit = 256 receiptsCacheLimit = 32 txLookupCacheLimit = 1024 - TriesInMemory = 128 // BlockChainVersion ensures that an incompatible database forces a resync from scratch. // @@ -1128,7 +1127,7 @@ func (bc *BlockChain) Stop() { if !bc.cacheConfig.TrieDirtyDisabled { triedb := bc.triedb - for _, offset := range []uint64{0, 1, TriesInMemory - 1} { + for _, offset := range []uint64{0, 1, state.TriesInMemory - 1} { if number := bc.CurrentBlock().Number.Uint64(); number > offset { recent := bc.GetBlockByNumber(number - offset) @@ -1452,7 +1451,7 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error { // writeBlockWithState writes block, metadata and corresponding state data to the // database. -func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error { +func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, statedb *state.StateDB) error { // Calculate the total difficulty of the block ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1) if ptd == nil { @@ -1469,12 +1468,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) rawdb.WriteBlock(blockBatch, block) rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) - rawdb.WritePreimages(blockBatch, state.Preimages()) + rawdb.WritePreimages(blockBatch, statedb.Preimages()) if err := blockBatch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) } // Commit all cached state changes into underlying memory database. - root, err := state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number())) + root, err := statedb.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number())) if err != nil { return err } @@ -1493,7 +1492,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. // Flush limits are not considered for the first TriesInMemory blocks. current := block.NumberU64() - if current <= TriesInMemory { + if current <= state.TriesInMemory { return nil } // If we exceeded our memory allowance, flush matured singleton nodes to disk @@ -1505,7 +1504,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. bc.triedb.Cap(limit - ethdb.IdealBatchSize) } // Find the next state trie we need to commit - chosen := current - TriesInMemory + chosen := current - state.TriesInMemory flushInterval := time.Duration(bc.flushInterval.Load()) // If we exceeded time allowance, flush an entire trie to disk if bc.gcproc > flushInterval { @@ -1517,8 +1516,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 < bc.lastWrite+TriesInMemory && bc.gcproc >= 2*flushInterval { - log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/TriesInMemory) + if chosen < bc.lastWrite+state.TriesInMemory && bc.gcproc >= 2*flushInterval { + log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/state.TriesInMemory) } // Flush an entire trie and restart the counters bc.triedb.Commit(header.Root, true) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index f20252da8c2a..ea8ea7e2421d 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1712,7 +1712,7 @@ func TestTrieForkGC(t *testing.T) { Config: params.TestChainConfig, BaseFee: big.NewInt(params.InitialBaseFee), } - genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.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)) @@ -1740,7 +1740,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 < state.TriesInMemory; i++ { chain.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) chain.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) } @@ -1764,8 +1764,8 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { BaseFee: big.NewInt(params.InitialBaseFee), } genDb, shared, _ := GenerateChainWithGenesis(genesis, engine, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - original, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) - competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) + original, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*state.TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) @@ -1804,7 +1804,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { } // In path-based trie database implementation, it will keep 128 diff + 1 disk // layers, totally 129 latest states available. In hash-based it's 128. - states := TriesInMemory + states := state.TriesInMemory if scheme == rawdb.PathScheme { states = states + 1 } @@ -1972,7 +1972,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) { } // We must use a pretty long chain to ensure that the fork doesn't overtake us // until after at least 128 blocks post tip - genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*TriesInMemory, func(i int, b *BlockGen) { + genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) b.OffsetTime(-9) }) @@ -1992,7 +1992,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) { } // Generate fork chain, starting from an early block parent := blocks[10] - fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*TriesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) @@ -2055,7 +2055,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Set the terminal total difficulty in the config gspec.Config.TerminalTotalDifficulty = big.NewInt(0) } - genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { + genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key) if err != nil { t.Fatalf("failed to create tx: %v", err) @@ -2070,9 +2070,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) - state.TriesInMemory - 1 lastPrunedBlock := blocks[lastPrunedIndex] - firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] + firstNonPrunedBlock := blocks[len(blocks)-state.TriesInMemory] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { @@ -2099,7 +2099,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Generate fork chain, make it longer than canon parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock parent := blocks[parentIndex] - fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) if int(b.header.Number.Uint64()) >= mergeBlock { b.SetPoS() @@ -2742,7 +2742,7 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { BaseFee: big.NewInt(params.InitialBaseFee), } // Generate and import the canonical chain - _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, nil) + _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { @@ -2755,9 +2755,9 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { } // In path-based trie database implementation, it will keep 128 diff + 1 disk // layers, totally 129 latest states available. In hash-based it's 128. - states := TriesInMemory + states := state.TriesInMemory if scheme == rawdb.PathScheme { - states = TriesInMemory + 1 + states = state.TriesInMemory + 1 } lastPrunedIndex := len(blocks) - states - 1 lastPrunedBlock := blocks[lastPrunedIndex] @@ -3638,7 +3638,7 @@ func testSetCanonical(t *testing.T, scheme string) { engine = ethash.NewFaker() ) // Generate and import the canonical chain - _, canon, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { + _, canon, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key) if err != nil { panic(err) @@ -3659,7 +3659,7 @@ func testSetCanonical(t *testing.T, scheme string) { } // Generate the side chain and import them - _, side, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { + _, side, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.header.BaseFee, nil), signer, key) if err != nil { panic(err) @@ -3698,8 +3698,8 @@ func testSetCanonical(t *testing.T, scheme string) { verify(side[len(side)-1]) // Reset the chain head to original chain - chain.SetCanonical(canon[TriesInMemory-1]) - verify(canon[TriesInMemory-1]) + chain.SetCanonical(canon[state.TriesInMemory-1]) + verify(canon[state.TriesInMemory-1]) } // TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted diff --git a/core/state/statedb.go b/core/state/statedb.go index 66cfc8f05a32..ac37d4ceeb9a 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -41,6 +41,9 @@ import ( "golang.org/x/sync/errgroup" ) +// TriesInMemory represents the number of layers that are kept in RAM. +const TriesInMemory = 128 + type revision struct { id int journalIndex int @@ -1269,12 +1272,12 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil { log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) } - // Keep 128 diff layers in the memory, persistent layer is 129th. + // Keep TriesInMemory diff layers in the memory, persistent layer is 129th. // - head layer is paired with HEAD state // - head-1 layer is paired with HEAD-1 state // - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state - if err := s.snaps.Cap(root, 128); err != nil { - log.Warn("Failed to cap snapshot tree", "root", root, "layers", 128, "err", err) + if err := s.snaps.Cap(root, TriesInMemory); err != nil { + log.Warn("Failed to cap snapshot tree", "root", root, "layers", TriesInMemory, "err", err) } } s.SnapshotCommits += time.Since(start) From 3e896c875a372b4d09dc82f986b4fb4bf7fe1041 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik <10907694+magicxyyz@users.noreply.github.com> Date: Mon, 6 May 2024 13:42:22 +0200 Subject: [PATCH 247/571] ethdb/pebble: fix pebble metrics registration (#29699) ethdb/pebble: use GetOrRegister instead of NewRegistered when creating metrics --- ethdb/pebble/pebble.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 01bfb4be3d1d..ee4e5dd75a56 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -240,19 +240,19 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e } db.db = innerDB - db.compTimeMeter = metrics.NewRegisteredMeter(namespace+"compact/time", nil) - db.compReadMeter = metrics.NewRegisteredMeter(namespace+"compact/input", nil) - db.compWriteMeter = metrics.NewRegisteredMeter(namespace+"compact/output", nil) - db.diskSizeGauge = metrics.NewRegisteredGauge(namespace+"disk/size", nil) - db.diskReadMeter = metrics.NewRegisteredMeter(namespace+"disk/read", nil) - db.diskWriteMeter = metrics.NewRegisteredMeter(namespace+"disk/write", nil) - db.writeDelayMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/duration", nil) - db.writeDelayNMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/counter", nil) - db.memCompGauge = metrics.NewRegisteredGauge(namespace+"compact/memory", nil) - db.level0CompGauge = metrics.NewRegisteredGauge(namespace+"compact/level0", nil) - db.nonlevel0CompGauge = metrics.NewRegisteredGauge(namespace+"compact/nonlevel0", nil) - db.seekCompGauge = metrics.NewRegisteredGauge(namespace+"compact/seek", nil) - db.manualMemAllocGauge = metrics.NewRegisteredGauge(namespace+"memory/manualalloc", nil) + db.compTimeMeter = metrics.GetOrRegisterMeter(namespace+"compact/time", nil) + db.compReadMeter = metrics.GetOrRegisterMeter(namespace+"compact/input", nil) + db.compWriteMeter = metrics.GetOrRegisterMeter(namespace+"compact/output", nil) + db.diskSizeGauge = metrics.GetOrRegisterGauge(namespace+"disk/size", nil) + db.diskReadMeter = metrics.GetOrRegisterMeter(namespace+"disk/read", nil) + db.diskWriteMeter = metrics.GetOrRegisterMeter(namespace+"disk/write", nil) + db.writeDelayMeter = metrics.GetOrRegisterMeter(namespace+"compact/writedelay/duration", nil) + db.writeDelayNMeter = metrics.GetOrRegisterMeter(namespace+"compact/writedelay/counter", nil) + db.memCompGauge = metrics.GetOrRegisterGauge(namespace+"compact/memory", nil) + db.level0CompGauge = metrics.GetOrRegisterGauge(namespace+"compact/level0", nil) + db.nonlevel0CompGauge = metrics.GetOrRegisterGauge(namespace+"compact/nonlevel0", nil) + db.seekCompGauge = metrics.GetOrRegisterGauge(namespace+"compact/seek", nil) + db.manualMemAllocGauge = metrics.GetOrRegisterGauge(namespace+"memory/manualalloc", nil) // Start up the metrics gathering and return go db.meter(metricsGatheringInterval, namespace) @@ -543,7 +543,7 @@ func (d *Database) meter(refresh time.Duration, namespace string) { for i, level := range stats.Levels { // Append metrics for additional layers if i >= len(d.levelsGauge) { - d.levelsGauge = append(d.levelsGauge, metrics.NewRegisteredGauge(namespace+fmt.Sprintf("tables/level%v", i), nil)) + d.levelsGauge = append(d.levelsGauge, metrics.GetOrRegisterGauge(namespace+fmt.Sprintf("tables/level%v", i), nil)) } d.levelsGauge[i].Update(level.NumFiles) } From e4b8058d5a5832cdebdac7da385cf6d829c0d433 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 7 May 2024 15:25:15 +0800 Subject: [PATCH 248/571] eth/gasprice: add query limit for FeeHistory to defend DDOS attack (#29644) * eth/gasprice: add query limit for FeeHistory to defend DDOS attack * fix return values after cherry-pick --------- Co-authored-by: Eric <45141191+zlacfzy@users.noreply.github.com> --- eth/gasprice/feehistory.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 0410ae6b2de3..d039bcb40118 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -44,6 +44,7 @@ const ( // maxBlockFetchers is the max number of goroutines to spin up to pull blocks // for the fee history calculation (mostly relevant for LES). maxBlockFetchers = 4 + maxQueryLimit = 100 ) // blockFees represents a single block for processing @@ -240,6 +241,9 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL if len(rewardPercentiles) != 0 { maxFeeHistory = oracle.maxBlockHistory } + if len(rewardPercentiles) > maxQueryLimit { + return common.Big0, nil, nil, nil, nil, nil, fmt.Errorf("%w: over the query limit %d", errInvalidPercentile, maxQueryLimit) + } if blocks > maxFeeHistory { log.Warn("Sanitizing fee history length", "requested", blocks, "truncated", maxFeeHistory) blocks = maxFeeHistory From d6e91e2e05f52271e4d5e2bd6eeddf7a8426b86d Mon Sep 17 00:00:00 2001 From: nand2 Date: Tue, 7 May 2024 14:27:14 +0200 Subject: [PATCH 249/571] eth/gasestimator: include blobs in virtual balance computation (#29703) Fixes #29702 Co-authored-by: Felix Lange --- eth/gasestimator/gasestimator.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index f07f98956e3c..ac3b59e97e8b 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -80,6 +80,16 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin } available.Sub(available, call.Value) } + if opts.Config.IsCancun(opts.Header.Number, opts.Header.Time) && len(call.BlobHashes) > 0 { + blobGasPerBlob := new(big.Int).SetInt64(params.BlobTxBlobGasPerBlob) + blobBalanceUsage := new(big.Int).SetInt64(int64(len(call.BlobHashes))) + blobBalanceUsage.Mul(blobBalanceUsage, blobGasPerBlob) + blobBalanceUsage.Mul(blobBalanceUsage, call.BlobGasFeeCap) + if blobBalanceUsage.Cmp(available) >= 0 { + return 0, nil, core.ErrInsufficientFunds + } + available.Sub(available, blobBalanceUsage) + } allowance := new(big.Int).Div(available, feeCap) // If the allowance is larger than maximum uint64, skip checking From 71aa15c98f88ee03097e5b30ccbb564734180ca3 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 7 May 2024 21:24:58 +0200 Subject: [PATCH 250/571] travis: use ubuntu noble (24.04) instead of bionic (18.04) (#29723) --- .travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8c0af291a3df..722a3a925638 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ jobs: if: type = push os: linux arch: amd64 - dist: bionic + dist: noble go: 1.22.x env: - docker @@ -32,7 +32,7 @@ jobs: if: type = push os: linux arch: arm64 - dist: bionic + dist: noble go: 1.22.x env: - docker @@ -49,7 +49,7 @@ jobs: - stage: build if: type = push os: linux - dist: bionic + dist: noble sudo: required go: 1.22.x env: @@ -100,7 +100,7 @@ jobs: - stage: build os: linux arch: amd64 - dist: bionic + dist: noble go: 1.22.x script: - travis_wait 30 go run build/ci.go test $TEST_PACKAGES @@ -109,14 +109,14 @@ jobs: if: type = pull_request os: linux arch: arm64 - dist: bionic + dist: noble go: 1.21.x script: - travis_wait 30 go run build/ci.go test $TEST_PACKAGES - stage: build os: linux - dist: bionic + dist: noble go: 1.21.x script: - travis_wait 30 go run build/ci.go test $TEST_PACKAGES @@ -125,7 +125,7 @@ jobs: - stage: build if: type = cron || (type = push && tag ~= /^v[0-9]/) os: linux - dist: bionic + dist: noble go: 1.22.x env: - ubuntu-ppa @@ -148,7 +148,7 @@ jobs: - stage: build if: type = cron os: linux - dist: bionic + dist: noble go: 1.22.x env: - azure-purge @@ -161,7 +161,7 @@ jobs: - stage: build if: type = cron os: linux - dist: bionic + dist: noble go: 1.22.x script: - travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES From e96de6489cfa7431592fe14cbfd4eb563331362b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 7 May 2024 22:08:29 +0200 Subject: [PATCH 251/571] build: upgrade to go 1.22.3 (#29725) --- build/checksums.txt | 56 +++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 767fc88ce59f..da2988452a58 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,22 +5,48 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.22.2 +# version:golang 1.22.3 # https://go.dev/dl/ -374ea82b289ec738e968267cac59c7d5ff180f9492250254784b2044e90df5a9 go1.22.2.src.tar.gz -33e7f63077b1c5bce4f1ecadd4d990cf229667c40bfb00686990c950911b7ab7 go1.22.2.darwin-amd64.tar.gz -660298be38648723e783ba0398e90431de1cb288c637880cdb124f39bd977f0d go1.22.2.darwin-arm64.tar.gz -efc7162b0cad2f918ac566a923d4701feb29dc9c0ab625157d49b1cbcbba39da go1.22.2.freebsd-386.tar.gz -d753428296e6709527e291fd204700a587ffef2c0a472b21aebea11618245929 go1.22.2.freebsd-amd64.tar.gz -586d9eb7fe0489ab297ad80dd06414997df487c5cf536c490ffeaa8d8f1807a7 go1.22.2.linux-386.tar.gz -5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17 go1.22.2.linux-amd64.tar.gz -36e720b2d564980c162a48c7e97da2e407dfcc4239e1e58d98082dfa2486a0c1 go1.22.2.linux-arm64.tar.gz -9243dfafde06e1efe24d59df6701818e6786b4adfdf1191098050d6d023c5369 go1.22.2.linux-armv6l.tar.gz -251a8886c5113be6490bdbb955ddee98763b49c9b1bf4c8364c02d3b482dab00 go1.22.2.linux-ppc64le.tar.gz -2b39019481c28c560d65e9811a478ae10e3ef765e0f59af362031d386a71bfef go1.22.2.linux-s390x.tar.gz -651753c06df037020ef4d162c5b273452e9ba976ed17ae39e66ef7ee89d8147e go1.22.2.windows-386.zip -8e581cf330f49d3266e936521a2d8263679ef7e2fc2cbbceb85659122d883596 go1.22.2.windows-amd64.zip -ddfca5beb9a0c62254266c3090c2555d899bf3e7aa26243e7de3621108f06875 go1.22.2.windows-arm64.zip +80648ef34f903193d72a59c0dff019f5f98ae0c9aa13ade0b0ecbff991a76f68 go1.22.3.src.tar.gz +adc9f5fee89cd53d907eb542d3b269d9d8a08a66bf1ab42175450ffbb58733fb go1.22.3.aix-ppc64.tar.gz +610e48c1df4d2f852de8bc2e7fd2dc1521aac216f0c0026625db12f67f192024 go1.22.3.darwin-amd64.tar.gz +02abeab3f4b8981232237ebd88f0a9bad933bc9621791cd7720a9ca29eacbe9d go1.22.3.darwin-arm64.tar.gz +a5b3d54905f17af2ceaf7fcfe92edee67a5bd4eccd962dd89df719ace3e0894d go1.22.3.dragonfly-amd64.tar.gz +b9989ca87695ae93bacde6f3aa7b13cde5f3825515eb9ed9bbef014273739889 go1.22.3.freebsd-386.tar.gz +7483961fae29d7d768afd5c9c0f229354ca3263ab7119c20bc182761f87cbc74 go1.22.3.freebsd-amd64.tar.gz +edf1f0b8ecf68b14faeedb4f5d868a58c4777a0282bd85e5115c39c010cd0130 go1.22.3.freebsd-arm.tar.gz +572eb70e5e835fbff7d53ebf473f611d7eb458c428f8dbd98a49196883c3309e go1.22.3.freebsd-arm64.tar.gz +ef94eb2b74402e436dce970584222c4e454eb3093908591149bd2ded6862b8af go1.22.3.freebsd-riscv64.tar.gz +3c3f498c68334cbd11f72aadfb6bcb507eb8436cebc50f437a0523cd4c5e03d1 go1.22.3.illumos-amd64.tar.gz +fefba30bb0d3dd1909823ee38c9f1930c3dc5337a2ac4701c2277a329a386b57 go1.22.3.linux-386.tar.gz +8920ea521bad8f6b7bc377b4824982e011c19af27df88a815e3586ea895f1b36 go1.22.3.linux-amd64.tar.gz +6c33e52a5b26e7aa021b94475587fce80043a727a54ceb0eee2f9fc160646434 go1.22.3.linux-arm64.tar.gz +f2bacad20cd2b96f23a86d4826525d42b229fd431cc6d0dec61ff3bc448ef46e go1.22.3.linux-armv6l.tar.gz +41e9328340544893482b2928ae18a9a88ba18b2fdd29ac77f4d33cf1815bbdc2 go1.22.3.linux-loong64.tar.gz +cf4d5faff52e642492729eaf396968f43af179518be769075b90bc1bf650abf6 go1.22.3.linux-mips.tar.gz +3bd009fe2e3d2bfd52433a11cb210d1dfa50b11b4c347a293951efd9e36de945 go1.22.3.linux-mips64.tar.gz +5913b82a042188ef698f7f2dfd0cd0c71f0508a4739de9e41fceff3f4dc769b4 go1.22.3.linux-mips64le.tar.gz +441afebca555be5313867b4577f237c7b5c0fff4386e22e47875b9f805abbec5 go1.22.3.linux-mipsle.tar.gz +f3b53190a76f4a35283501ba6d94cbb72093be0c62ff735c6f9e586a1c983381 go1.22.3.linux-ppc64.tar.gz +04b7b05283de30dd2da20bf3114b2e22cc727938aed3148babaf35cc951051ac go1.22.3.linux-ppc64le.tar.gz +d4992d4a85696e3f1de06cefbfc2fd840c9c6695d77a0f35cfdc4e28b2121c20 go1.22.3.linux-riscv64.tar.gz +2aba796417a69be5f3ed489076bac79c1c02b36e29422712f9f3bf51da9cf2d4 go1.22.3.linux-s390x.tar.gz +d6e6113542dd9f23db899e177fe23772bac114a5ea5e8ee436b9da68628335a8 go1.22.3.netbsd-386.tar.gz +c33cee3075bd18ceefddd75bafa8efb51fbdc17b5ee74275122e7a927a237a4c go1.22.3.netbsd-amd64.tar.gz +1ab251df3c85f3b391a09565ca52fb6e1306527d72852d553e9ab74eabb4ecf8 go1.22.3.netbsd-arm.tar.gz +1d194fe53f5d82f9a612f848950d8af8cab7cb40ccc03f10c4eb1c9808ff1a0c go1.22.3.netbsd-arm64.tar.gz +91d6601727f08506e938640885d3ded784925045e3a4444fd9b4b936efe1b1e0 go1.22.3.openbsd-386.tar.gz +09d0c91ae35a4eea92615426992062ca236cc2f66444fb0b0a24cd3b13bd5297 go1.22.3.openbsd-amd64.tar.gz +338da30cc2c97b9458e0b4caa2509f67bba55d3de16fb7d31775baca82d2e3dc go1.22.3.openbsd-arm.tar.gz +53eadfabd2b7dd09a64941421afee2a2888e2a4f94f353b27919b1dad1171a21 go1.22.3.openbsd-arm64.tar.gz +8a1a2842ae8dcf2374bb05dff58074b368bb698dc9c211c794c1ff119cd9fdc7 go1.22.3.plan9-386.tar.gz +f9816d3dd9e730cad55085ea08c1f0c925720728f9c945fff59cd24d2ac2db7b go1.22.3.plan9-amd64.tar.gz +f4d3d7b17c9e1b1635fcb287b5b5ab5b60acc9db3ba6a27f2b2f5d6537a2ef95 go1.22.3.plan9-arm.tar.gz +46b7999ee94d91b21ad6940b5a3131ff6fe53ef97be9a34e582e2a3ad7263e95 go1.22.3.solaris-amd64.tar.gz +f60f63b8a0885e0d924f39fd284aee5438fe87d8c3d8545a312adf43e0d9edac go1.22.3.windows-386.zip +cab2af6951a6e2115824263f6df13ff069c47270f5788714fa1d776f7f60cb39 go1.22.3.windows-amd64.zip +40b37f4b068fc759f3a0dd61176a0f7570a4ba48bed8561c31d3967a3583981a go1.22.3.windows-arm.zip +59b76ee22b9b1c3afbf7f50e3cb4edb954d6c0d25e5e029ab5483a6804d61e71 go1.22.3.windows-arm64.zip # version:golangci 1.55.2 # https://github.com/golangci/golangci-lint/releases/ From 9ec50080eb26d0cea6c5cea3ec4049a5dfb48ae8 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 8 May 2024 14:43:33 +0800 Subject: [PATCH 252/571] core: use in-memory freezer for tests (#29720) * core: simplify chain tests * core, eth, cmd: use in-memory freezer for tests * core: restore tests --- cmd/utils/history_test.go | 3 +-- core/block_validator_test.go | 2 -- core/blockchain_test.go | 33 ++++++++++++++++--------------- core/txindexer_test.go | 5 +---- eth/downloader/downloader_test.go | 12 +++-------- 5 files changed, 22 insertions(+), 33 deletions(-) diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go index b6703c59ed32..a631eaf49036 100644 --- a/cmd/utils/history_test.go +++ b/cmd/utils/history_test.go @@ -162,8 +162,7 @@ func TestHistoryImportAndExport(t *testing.T) { } // Now import Era. - freezer := t.TempDir() - db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false) + db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) if err != nil { panic(err) } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 2f86b2d751b8..c573ef91faca 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -154,12 +154,10 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { preHeaders := make([]*types.Header, len(preBlocks)) for i, block := range preBlocks { preHeaders[i] = block.Header() - t.Logf("Pre-merge header: %d", block.NumberU64()) } postHeaders := make([]*types.Header, len(postBlocks)) for i, block := range postBlocks { postHeaders[i] = block.Header() - t.Logf("Post-merge header: %d", block.NumberU64()) } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index ea8ea7e2421d..e4bc3e09a657 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -785,7 +785,7 @@ func testFastVsFullChains(t *testing.T, scheme string) { t.Fatalf("failed to insert receipt %d: %v", n, err) } // Freezer style fast import the chain. - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -875,12 +875,12 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { BaseFee: big.NewInt(params.InitialBaseFee), } ) - height := uint64(1024) + height := uint64(64) _, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil) // makeDb creates a db instance for testing. makeDb := func() ethdb.Database { - db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -1768,7 +1768,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*state.TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one - db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) defer db.Close() chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) @@ -1833,7 +1833,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) { funds = big.NewInt(1000000000) gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{address: {Balance: funds}}} ) - height := uint64(1024) + height := uint64(64) _, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil) // Import the chain as a ancient-first node and ensure all pointers are updated @@ -1908,7 +1908,7 @@ func testInsertReceiptChainRollback(t *testing.T, scheme string) { } // Set up a BlockChain that uses the ancient store. - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -1978,7 +1978,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) { }) // Import the canonical chain - diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) defer diskdb.Close() chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) @@ -2190,7 +2190,7 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) { b.OffsetTime(-9) // A higher difficulty }) // Import the shared chain and the original canonical one - chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -2361,7 +2361,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } }) // Import the shared chain and the original canonical one - chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -3634,18 +3634,19 @@ func testSetCanonical(t *testing.T, scheme string) { Alloc: types.GenesisAlloc{address: {Balance: funds}}, BaseFee: big.NewInt(params.InitialBaseFee), } - signer = types.LatestSigner(gspec.Config) - engine = ethash.NewFaker() + signer = types.LatestSigner(gspec.Config) + engine = ethash.NewFaker() + chainLength = 10 ) // Generate and import the canonical chain - _, canon, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) { + _, canon, _ := GenerateChainWithGenesis(gspec, engine, chainLength, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key) if err != nil { panic(err) } gen.AddTx(tx) }) - diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) defer diskdb.Close() chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) @@ -3659,7 +3660,7 @@ func testSetCanonical(t *testing.T, scheme string) { } // Generate the side chain and import them - _, side, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) { + _, side, _ := GenerateChainWithGenesis(gspec, engine, chainLength, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.header.BaseFee, nil), signer, key) if err != nil { panic(err) @@ -3698,8 +3699,8 @@ func testSetCanonical(t *testing.T, scheme string) { verify(side[len(side)-1]) // Reset the chain head to original chain - chain.SetCanonical(canon[state.TriesInMemory-1]) - verify(canon[state.TriesInMemory-1]) + chain.SetCanonical(canon[chainLength-1]) + verify(canon[chainLength-1]) } // TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted diff --git a/core/txindexer_test.go b/core/txindexer_test.go index 7b5ff1f206b2..0a606ed8fa6f 100644 --- a/core/txindexer_test.go +++ b/core/txindexer_test.go @@ -18,7 +18,6 @@ package core import ( "math/big" - "os" "testing" "github.com/ethereum/go-ethereum/common" @@ -211,8 +210,7 @@ func TestTxIndexer(t *testing.T) { }, } for _, c := range cases { - frdir := t.TempDir() - db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0)) // Index the initial blocks from ancient store @@ -238,6 +236,5 @@ func TestTxIndexer(t *testing.T) { verify(db, 0, indexer) db.Close() - os.RemoveAll(frdir) } } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 92403277fd5f..e5329b7b3965 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -19,7 +19,6 @@ package downloader import ( "fmt" "math/big" - "os" "sync" "sync/atomic" "testing" @@ -43,7 +42,6 @@ import ( // downloadTester is a test simulator for mocking out local block chain. type downloadTester struct { - freezer string chain *core.BlockChain downloader *Downloader @@ -58,8 +56,7 @@ func newTester(t *testing.T) *downloadTester { // newTesterWithNotification creates a new downloader test mocker. func newTesterWithNotification(t *testing.T, success func()) *downloadTester { - freezer := t.TempDir() - db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false) + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) if err != nil { panic(err) } @@ -76,9 +73,8 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { panic(err) } tester := &downloadTester{ - freezer: freezer, - chain: chain, - peers: make(map[string]*downloadTesterPeer), + chain: chain, + peers: make(map[string]*downloadTesterPeer), } tester.downloader = New(db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success) return tester @@ -89,8 +85,6 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { func (dl *downloadTester) terminate() { dl.downloader.Terminate() dl.chain.Stop() - - os.RemoveAll(dl.freezer) } // newPeer registers a new block download source into the downloader. From dd4afb9fecb266ae4317406ad5b14b177e5cd8a9 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 May 2024 11:08:55 +0200 Subject: [PATCH 253/571] .travis.yml: fix install of gcc-multilib (#29733) --- .travis.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 722a3a925638..9d54ab82f315 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,14 +56,13 @@ jobs: - azure-linux git: submodules: false # avoid cloning ethereum/tests - addons: - apt: - packages: - - gcc-multilib script: - # Build for the primary platforms that Trusty can manage + # build amd64 - go run build/ci.go install -dlgo - go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds + + # build 386 + - sudo -E apt-get install -yq --no-install-suggests --no-install-recommends --force-yes install gcc-multilib - go run build/ci.go install -dlgo -arch 386 - go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds @@ -165,4 +164,3 @@ jobs: go: 1.22.x script: - travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES - From 6154f87c33303698ad962427f619c6f129640c1e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 May 2024 11:33:07 +0200 Subject: [PATCH 254/571] .travis.yml: fix apt-get options (#29734) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9d54ab82f315..11ea43ef5174 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,7 +62,7 @@ jobs: - go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds # build 386 - - sudo -E apt-get install -yq --no-install-suggests --no-install-recommends --force-yes install gcc-multilib + - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib - go run build/ci.go install -dlgo -arch 386 - go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds From dd09f7e3facd973cdaa17b7403f82c8bbff28de3 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 May 2024 14:28:40 +0200 Subject: [PATCH 255/571] params: release go-ethereum v1.14.1 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 319f21b2a8b4..9e7e20b2918a 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // 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 + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 1 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 14f4228472662c5da2b8fd4a11f5f8a3ac4f2aff Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 May 2024 14:30:18 +0200 Subject: [PATCH 256/571] params: begin v1.14.2 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 9e7e20b2918a..02ab76354407 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 1 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 2 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From eeb22089fd24ee1377a6a1f52deb41673c38419c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 May 2024 14:34:58 +0200 Subject: [PATCH 257/571] .travis.yml: fix package install on PPA builder --- .travis.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 11ea43ef5174..29c6d6b52163 100644 --- a/.travis.yml +++ b/.travis.yml @@ -130,15 +130,8 @@ jobs: - ubuntu-ppa git: submodules: false # avoid cloning ethereum/tests - addons: - apt: - packages: - - devscripts - - debhelper - - dput - - fakeroot - - python-bzrlib - - python-paramiko + before_install: + - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot python-bzrlib python-paramiko script: - echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts - go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder " From 35b2d07f4bf735958b41cd141a5feda5e61be73e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 May 2024 16:26:01 +0200 Subject: [PATCH 258/571] params: release go-ethereum v1.14.2 stable --- params/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/version.go b/params/version.go index 02ab76354407..fb40a0dd71e3 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 14 // Minor version component of the current release VersionPatch = 2 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 1a79f8fe58f9c42db1dcfd8599f386c8158069e8 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 May 2024 16:27:44 +0200 Subject: [PATCH 259/571] params: begin v1.14.3 release cycle --- params/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/params/version.go b/params/version.go index fb40a0dd71e3..2eccf9338450 100644 --- a/params/version.go +++ b/params/version.go @@ -23,8 +23,8 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 14 // Minor version component of the current release - VersionPatch = 2 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionPatch = 3 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From faff03c40329be2aa87017dc90ffebf0b7285388 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 May 2024 20:28:05 +0200 Subject: [PATCH 260/571] .travis.yml: enable PPA upload on push and fix apt-get command (#29741) --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 29c6d6b52163..6dca0ea5f685 100644 --- a/.travis.yml +++ b/.travis.yml @@ -122,7 +122,8 @@ jobs: # This builder does the Ubuntu PPA nightly uploads - stage: build - if: type = cron || (type = push && tag ~= /^v[0-9]/) + # if: type = cron || (type = push && tag ~= /^v[0-9]/) + if: type = push os: linux dist: noble go: 1.22.x @@ -131,7 +132,7 @@ jobs: git: submodules: false # avoid cloning ethereum/tests before_install: - - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot python-bzrlib python-paramiko + - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot script: - echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts - go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder " From 804afb8faa0e3796fb8e6f39beabce356bc98298 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 May 2024 20:46:54 +0200 Subject: [PATCH 261/571] .travis.yml: restore PPA condition and bump timeouts (#29742) --- .travis.yml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6dca0ea5f685..488ec1e7d20e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -102,28 +102,18 @@ jobs: dist: noble go: 1.22.x script: - - travis_wait 30 go run build/ci.go test $TEST_PACKAGES - - - stage: build - if: type = pull_request - os: linux - arch: arm64 - dist: noble - go: 1.21.x - script: - - travis_wait 30 go run build/ci.go test $TEST_PACKAGES + - travis_wait 45 go run build/ci.go test $TEST_PACKAGES - stage: build os: linux dist: noble go: 1.21.x script: - - travis_wait 30 go run build/ci.go test $TEST_PACKAGES + - travis_wait 45 go run build/ci.go test $TEST_PACKAGES # This builder does the Ubuntu PPA nightly uploads - stage: build - # if: type = cron || (type = push && tag ~= /^v[0-9]/) - if: type = push + if: type = cron || (type = push && tag ~= /^v[0-9]/) os: linux dist: noble go: 1.22.x @@ -157,4 +147,4 @@ jobs: dist: noble go: 1.22.x script: - - travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES + - travis_wait 50 go run build/ci.go test -race $TEST_PACKAGES From ab48ba42f4f34873d65fd1737fabac5c680baff6 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 9 May 2024 12:34:54 +0200 Subject: [PATCH 262/571] params: release go-ethereum v1.14.3 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 2eccf9338450..0220cb6a6b24 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 3 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 3 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 6d51c1f5f4ac39ba70a9b38c574f55a089302a84 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 9 May 2024 12:40:37 +0200 Subject: [PATCH 263/571] params: begin v1.14.4 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 0220cb6a6b24..88bcc1d13c04 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 3 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 4 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 0e456d9eeb739de1c5de7fc7eb0bee81b35a96dd Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 9 May 2024 16:05:42 +0200 Subject: [PATCH 264/571] .travis.yml: disable normal unit tests in cron job (#29746) --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 488ec1e7d20e..2dc80f85edf9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -97,6 +97,7 @@ jobs: # These builders run the tests - stage: build + if: type = push os: linux arch: amd64 dist: noble @@ -105,6 +106,7 @@ jobs: - travis_wait 45 go run build/ci.go test $TEST_PACKAGES - stage: build + if: type = push os: linux dist: noble go: 1.21.x @@ -146,5 +148,7 @@ jobs: os: linux dist: noble go: 1.22.x + env: + - racetests script: - - travis_wait 50 go run build/ci.go test -race $TEST_PACKAGES + - travis_wait 60 go run build/ci.go test -race $TEST_PACKAGES From 74edc9386495f0ff44d68bf6e237a69f27021144 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 9 May 2024 16:07:32 +0200 Subject: [PATCH 265/571] params: gofmt --- params/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/version.go b/params/version.go index 88bcc1d13c04..a0e2de5a4941 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 14 // Minor version component of the current release - VersionPatch = 4 // Patch version component of the current release + VersionPatch = 4 // Patch version component of the current release VersionMeta = "unstable" // Version metadata to append to the version string ) From e5f5eaebc4c7810e640ec0f95195e76eaf67095c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 10 May 2024 15:57:38 +0800 Subject: [PATCH 266/571] core/state: remove slot dirtyness if it's set back to origin value (#29731) * core/state: remove slot dirtiness if it's set back to origin value * core/state: suggestion from martin --- core/state/journal.go | 5 +++-- core/state/state_object.go | 39 +++++++++++++++------------------ core/state/statedb_test.go | 44 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/core/state/journal.go b/core/state/journal.go index c0f5615c9815..ad4a654fc6a2 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -131,7 +131,8 @@ type ( storageChange struct { account *common.Address key common.Hash - prevvalue *common.Hash + prevvalue common.Hash + origvalue common.Hash } codeChange struct { account *common.Address @@ -278,7 +279,7 @@ func (ch codeChange) copy() journalEntry { } func (ch storageChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue) + s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue, ch.origvalue) } func (ch storageChange) dirtied() *common.Address { diff --git a/core/state/state_object.go b/core/state/state_object.go index d75ba01376bd..da7c51f0a140 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -145,16 +145,15 @@ func (s *stateObject) GetState(key common.Hash) common.Hash { return value } -// getState retrieves a value from the account storage trie and also returns if -// the slot is already dirty or not. -func (s *stateObject) getState(key common.Hash) (common.Hash, bool) { - // If we have a dirty value for this state entry, return it +// getState retrieves a value associated with the given storage key, along with +// it's original value. +func (s *stateObject) getState(key common.Hash) (common.Hash, common.Hash) { + origin := s.GetCommittedState(key) value, dirty := s.dirtyStorage[key] if dirty { - return value, true + return value, origin } - // Otherwise return the entry's original value - return s.GetCommittedState(key), false + return origin, origin } // GetCommittedState retrieves a value from the committed account storage trie. @@ -219,36 +218,32 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { func (s *stateObject) SetState(key, value common.Hash) { // If the new value is the same as old, don't set. Otherwise, track only the // dirty changes, supporting reverting all of it back to no change. - prev, dirty := s.getState(key) + prev, origin := s.getState(key) if prev == value { return } - var prevvalue *common.Hash - if dirty { - prevvalue = &prev - } // New value is different, update and journal the change s.db.journal.append(storageChange{ account: &s.address, key: key, - prevvalue: prevvalue, + prevvalue: prev, + origvalue: origin, }) if s.db.logger != nil && s.db.logger.OnStorageChange != nil { s.db.logger.OnStorageChange(s.address, key, prev, value) } - s.setState(key, &value) + s.setState(key, value, origin) } -// setState updates a value in account dirty storage. If the value being set is -// nil (assuming journal revert), the dirtyness is removed. -func (s *stateObject) setState(key common.Hash, value *common.Hash) { - // If the first set is being reverted, undo the dirty marker - if value == nil { +// setState updates a value in account dirty storage. The dirtiness will be +// removed if the value being set equals to the original value. +func (s *stateObject) setState(key common.Hash, value common.Hash, origin common.Hash) { + // Storage slot is set back to its original value, undo the dirty marker + if value == origin { delete(s.dirtyStorage, key) return } - // Otherwise restore the previous value - s.dirtyStorage[key] = *value + s.dirtyStorage[key] = value } // finalise moves all dirty storage slots into the pending area to be hashed or @@ -264,7 +259,7 @@ func (s *stateObject) finalise(prefetch bool) { slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure } else { // Otherwise, the slot was reverted to its original value, remove it - // from the pending area to avoid thrashing the data strutures. + // from the pending area to avoid thrashing the data structure. delete(s.pendingStorage, key) } } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 71d64f562898..2ce2b868faa9 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -1329,3 +1329,47 @@ func TestDeleteStorage(t *testing.T) { t.Fatalf("difference found:\nfast: %v\nslow: %v\n", fastRes, slowRes) } } + +func TestStorageDirtiness(t *testing.T) { + var ( + disk = rawdb.NewMemoryDatabase() + tdb = triedb.NewDatabase(disk, nil) + db = NewDatabaseWithNodeDB(disk, tdb) + state, _ = New(types.EmptyRootHash, db, nil) + addr = common.HexToAddress("0x1") + checkDirty = func(key common.Hash, value common.Hash, dirty bool) { + obj := state.getStateObject(addr) + v, exist := obj.dirtyStorage[key] + if exist != dirty { + t.Fatalf("Unexpected dirty marker, want: %t, got: %t", dirty, exist) + } + if v != value { + t.Fatalf("Unexpected storage slot, want: %t, got: %t", value, v) + } + } + ) + state.CreateAccount(addr) + + // the storage change is noop, no dirty marker + state.SetState(addr, common.Hash{0x1}, common.Hash{}) + checkDirty(common.Hash{0x1}, common.Hash{}, false) + + // the storage change is valid, dirty marker is expected + snap := state.Snapshot() + state.SetState(addr, common.Hash{0x1}, common.Hash{0x1}) + checkDirty(common.Hash{0x1}, common.Hash{0x1}, true) + + // the storage change is reverted, dirtiness should be revoked + state.RevertToSnapshot(snap) + checkDirty(common.Hash{0x1}, common.Hash{}, false) + + // the storage is reset back to its original value, dirtiness should be revoked + state.SetState(addr, common.Hash{0x1}, common.Hash{0x1}) + snap = state.Snapshot() + state.SetState(addr, common.Hash{0x1}, common.Hash{}) + checkDirty(common.Hash{0x1}, common.Hash{}, false) + + // the storage change is reverted, dirty value should be set back + state.RevertToSnapshot(snap) + checkDirty(common.Hash{0x1}, common.Hash{0x1}, true) +} From 603fd898d443233dadd7871d2fb9400de507424f Mon Sep 17 00:00:00 2001 From: cocoyeal <150209682+cocoyeal@users.noreply.github.com> Date: Sat, 11 May 2024 01:44:07 +0800 Subject: [PATCH 267/571] event: fix typo (#29749) typo: of -> or --- event/multisub.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/event/multisub.go b/event/multisub.go index 5c8d2df48cc4..1f0af2a29249 100644 --- a/event/multisub.go +++ b/event/multisub.go @@ -17,7 +17,7 @@ package event // JoinSubscriptions joins multiple subscriptions to be able to track them as -// one entity and collectively cancel them of consume any errors from them. +// one entity and collectively cancel them or consume any errors from them. func JoinSubscriptions(subs ...Subscription) Subscription { return NewSubscription(func(unsubbed <-chan struct{}) error { // Unsubscribe all subscriptions before returning From 47af69c2bc7ac28c838c5f289de23e65627c2024 Mon Sep 17 00:00:00 2001 From: Hteev Oli Date: Sat, 11 May 2024 01:48:14 +0800 Subject: [PATCH 268/571] core, beacon, ethdb: fix typos (#29748) * core, beacon, ethdb: fix typos * revert file that can't be changed --- beacon/light/sync/head_sync_test.go | 2 +- core/state/state_object.go | 2 +- core/vm/instructions_test.go | 2 +- ethdb/dbtest/testsuite.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/beacon/light/sync/head_sync_test.go b/beacon/light/sync/head_sync_test.go index cd7dacf7fe7d..d095d6a4466e 100644 --- a/beacon/light/sync/head_sync_test.go +++ b/beacon/light/sync/head_sync_test.go @@ -91,7 +91,7 @@ func TestValidatedHead(t *testing.T) { ts.ServerEvent(EvNewOptimisticUpdate, testServer3, testOptUpdate4) // finality should be requested from both servers ts.Run(4, testServer1, ReqFinality{}, testServer3, ReqFinality{}) - // future period annonced heads should be queued + // future period announced heads should be queued ht.ExpValidated(t, 4, nil) chain.SetNextSyncPeriod(2) diff --git a/core/state/state_object.go b/core/state/state_object.go index da7c51f0a140..cc42d0687965 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -146,7 +146,7 @@ func (s *stateObject) GetState(key common.Hash) common.Hash { } // getState retrieves a value associated with the given storage key, along with -// it's original value. +// its original value. func (s *stateObject) getState(key common.Hash) (common.Hash, common.Hash) { origin := s.GetCommittedState(key) value, dirty := s.dirtyStorage[key] diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 8653864d11e4..e17e913aa3ce 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -643,7 +643,7 @@ func BenchmarkOpKeccak256(bench *testing.B) { } } -func TestCreate2Addreses(t *testing.T) { +func TestCreate2Addresses(t *testing.T) { type testcase struct { origin string salt string diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 83a13c8cff64..7137d29396ce 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -381,7 +381,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { } }) - t.Run("OperatonsAfterClose", func(t *testing.T) { + t.Run("OperationsAfterClose", func(t *testing.T) { db := New() db.Put([]byte("key"), []byte("value")) db.Close() From 44a50c9f96386f44a8682d51cf7500044f6cbaea Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Fri, 10 May 2024 20:13:11 +0200 Subject: [PATCH 269/571] cmd, core, params, trie: add verkle access witness gas charging (#29338) Implements some of the changes required to charge and do gas accounting in verkle testnet. --- cmd/geth/consolecmd_test.go | 6 +- cmd/geth/verkle.go | 2 +- core/chain_makers.go | 2 +- core/error.go | 5 + core/state/access_events.go | 320 +++++++++++++++++++++++++++++++ core/state/access_events_test.go | 153 +++++++++++++++ core/state/database.go | 24 ++- core/state/statedb.go | 10 +- core/state_processor_test.go | 2 +- core/state_transition.go | 15 +- core/tracing/hooks.go | 6 + core/vm/common.go | 12 ++ core/vm/contract.go | 3 + core/vm/contracts.go | 2 + core/vm/eips.go | 214 +++++++++++++++++++++ core/vm/evm.go | 60 +++++- core/vm/gas_table.go | 24 ++- core/vm/instructions.go | 7 +- core/vm/interface.go | 5 + core/vm/interpreter.go | 11 ++ core/vm/jump_table.go | 7 + core/vm/operations_verkle.go | 159 +++++++++++++++ go.mod | 4 +- go.sum | 8 +- params/config.go | 11 +- params/protocol_params.go | 1 + params/verkle_params.go | 36 ++++ trie/secure_trie.go | 4 + trie/utils/verkle.go | 8 +- trie/utils/verkle_test.go | 2 +- trie/verkle.go | 2 +- 31 files changed, 1082 insertions(+), 43 deletions(-) create mode 100644 core/state/access_events.go create mode 100644 core/state/access_events_test.go create mode 100644 core/vm/operations_verkle.go create mode 100644 params/verkle_params.go diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index 4d6220641703..33d6d4bbc421 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -103,17 +103,17 @@ func TestAttachWelcome(t *testing.T) { "--http", "--http.port", httpPort, "--ws", "--ws.port", wsPort) t.Run("ipc", func(t *testing.T) { - waitForEndpoint(t, ipc, 3*time.Second) + waitForEndpoint(t, ipc, 4*time.Second) testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs) }) t.Run("http", func(t *testing.T) { endpoint := "http://127.0.0.1:" + httpPort - waitForEndpoint(t, endpoint, 3*time.Second) + waitForEndpoint(t, endpoint, 4*time.Second) testAttachWelcome(t, geth, endpoint, httpAPIs) }) t.Run("ws", func(t *testing.T) { endpoint := "ws://127.0.0.1:" + wsPort - waitForEndpoint(t, endpoint, 3*time.Second) + waitForEndpoint(t, endpoint, 4*time.Second) testAttachWelcome(t, geth, endpoint, httpAPIs) }) geth.Kill() diff --git a/cmd/geth/verkle.go b/cmd/geth/verkle.go index ff3931356e8f..9eb37fb5a875 100644 --- a/cmd/geth/verkle.go +++ b/cmd/geth/verkle.go @@ -28,7 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" - "github.com/gballet/go-verkle" + "github.com/ethereum/go-verkle" "github.com/urfave/cli/v2" ) diff --git a/core/chain_makers.go b/core/chain_makers.go index 13d7cb86c043..58985347bb31 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -32,7 +32,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" - "github.com/gballet/go-verkle" + "github.com/ethereum/go-verkle" "github.com/holiman/uint256" ) diff --git a/core/error.go b/core/error.go index e6e6ba2f90c3..161538fe4323 100644 --- a/core/error.go +++ b/core/error.go @@ -64,6 +64,11 @@ var ( // than init code size limit. ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded") + // ErrInsufficientBalanceWitness is returned if the transaction sender has enough + // funds to cover the transfer, but not enough to pay for witness access/modification + // costs for the transaction + ErrInsufficientBalanceWitness = errors.New("insufficient funds to cover witness access costs for transaction") + // ErrInsufficientFunds is returned if the total cost of executing a transaction // is higher than the balance of the user's account. ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value") diff --git a/core/state/access_events.go b/core/state/access_events.go new file mode 100644 index 000000000000..4b6c7c7e69bb --- /dev/null +++ b/core/state/access_events.go @@ -0,0 +1,320 @@ +// Copyright 2021 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 ( + "maps" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie/utils" + "github.com/holiman/uint256" +) + +// mode specifies how a tree location has been accessed +// for the byte value: +// * the first bit is set if the branch has been edited +// * the second bit is set if the branch has been read +type mode byte + +const ( + AccessWitnessReadFlag = mode(1) + AccessWitnessWriteFlag = mode(2) +) + +var zeroTreeIndex uint256.Int + +// AccessEvents lists the locations of the state that are being accessed +// during the production of a block. +type AccessEvents struct { + branches map[branchAccessKey]mode + chunks map[chunkAccessKey]mode + + pointCache *utils.PointCache +} + +func NewAccessEvents(pointCache *utils.PointCache) *AccessEvents { + return &AccessEvents{ + branches: make(map[branchAccessKey]mode), + chunks: make(map[chunkAccessKey]mode), + pointCache: pointCache, + } +} + +// Merge is used to merge the access events that were generated during the +// execution of a tx, with the accumulation of all access events that were +// generated during the execution of all txs preceding this one in a block. +func (ae *AccessEvents) Merge(other *AccessEvents) { + for k := range other.branches { + ae.branches[k] |= other.branches[k] + } + for k, chunk := range other.chunks { + ae.chunks[k] |= chunk + } +} + +// Keys returns, predictably, the list of keys that were touched during the +// buildup of the access witness. +func (ae *AccessEvents) Keys() [][]byte { + // TODO: consider if parallelizing this is worth it, probably depending on len(ae.chunks). + keys := make([][]byte, 0, len(ae.chunks)) + for chunk := range ae.chunks { + basePoint := ae.pointCache.Get(chunk.addr[:]) + key := utils.GetTreeKeyWithEvaluatedAddress(basePoint, &chunk.treeIndex, chunk.leafKey) + keys = append(keys, key) + } + return keys +} + +func (ae *AccessEvents) Copy() *AccessEvents { + cpy := &AccessEvents{ + branches: maps.Clone(ae.branches), + chunks: maps.Clone(ae.chunks), + pointCache: ae.pointCache, + } + return cpy +} + +// AddAccount returns the gas to be charged for each of the currently cold +// member fields of an account. +func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 { + var gas uint64 + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite) + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite) + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite) + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite) + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite) + return gas +} + +// MessageCallGas returns the gas to be charged for each of the currently +// cold member fields of an account, that need to be touched when making a message +// call to that account. +func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 { + var gas uint64 + gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false) + gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false) + return gas +} + +// ValueTransferGas returns the gas to be charged for each of the currently +// cold balance member fields of the caller and the callee accounts. +func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 { + var gas uint64 + gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true) + gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true) + return gas +} + +// ContractCreateInitGas returns the access gas costs for the initialization of +// a contract creation. +func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 { + var gas uint64 + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true) + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true) + if createSendsValue { + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true) + } + return gas +} + +// AddTxOrigin adds the member fields of the sender account to the access event list, +// so that cold accesses are not charged, since they are covered by the 21000 gas. +func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) { + ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey, false) + ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey, true) + ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey, true) + ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey, false) + ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false) +} + +// AddTxDestination adds the member fields of the sender account to the access event list, +// so that cold accesses are not charged, since they are covered by the 21000 gas. +func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) { + ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false) + ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, sendsValue) + ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, false) + ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, false) + ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false) +} + +// SlotGas returns the amount of gas to be charged for a cold storage access. +func (ae *AccessEvents) SlotGas(addr common.Address, slot common.Hash, isWrite bool) uint64 { + treeIndex, subIndex := utils.StorageIndex(slot.Bytes()) + return ae.touchAddressAndChargeGas(addr, *treeIndex, subIndex, isWrite) +} + +// touchAddressAndChargeGas adds any missing access event to the access event list, and returns the cold +// access cost to be charged, if need be. +func (ae *AccessEvents) touchAddressAndChargeGas(addr common.Address, treeIndex uint256.Int, subIndex byte, isWrite bool) uint64 { + stemRead, selectorRead, stemWrite, selectorWrite, selectorFill := ae.touchAddress(addr, treeIndex, subIndex, isWrite) + + var gas uint64 + if stemRead { + gas += params.WitnessBranchReadCost + } + if selectorRead { + gas += params.WitnessChunkReadCost + } + if stemWrite { + gas += params.WitnessBranchWriteCost + } + if selectorWrite { + gas += params.WitnessChunkWriteCost + } + if selectorFill { + gas += params.WitnessChunkFillCost + } + return gas +} + +// touchAddress adds any missing access event to the access event list. +func (ae *AccessEvents) touchAddress(addr common.Address, treeIndex uint256.Int, subIndex byte, isWrite bool) (bool, bool, bool, bool, bool) { + branchKey := newBranchAccessKey(addr, treeIndex) + chunkKey := newChunkAccessKey(branchKey, subIndex) + + // Read access. + var branchRead, chunkRead bool + if _, hasStem := ae.branches[branchKey]; !hasStem { + branchRead = true + ae.branches[branchKey] = AccessWitnessReadFlag + } + if _, hasSelector := ae.chunks[chunkKey]; !hasSelector { + chunkRead = true + ae.chunks[chunkKey] = AccessWitnessReadFlag + } + + // Write access. + var branchWrite, chunkWrite, chunkFill bool + if isWrite { + if (ae.branches[branchKey] & AccessWitnessWriteFlag) == 0 { + branchWrite = true + ae.branches[branchKey] |= AccessWitnessWriteFlag + } + + chunkValue := ae.chunks[chunkKey] + if (chunkValue & AccessWitnessWriteFlag) == 0 { + chunkWrite = true + ae.chunks[chunkKey] |= AccessWitnessWriteFlag + } + // TODO: charge chunk filling costs if the leaf was previously empty in the state + } + return branchRead, chunkRead, branchWrite, chunkWrite, chunkFill +} + +type branchAccessKey struct { + addr common.Address + treeIndex uint256.Int +} + +func newBranchAccessKey(addr common.Address, treeIndex uint256.Int) branchAccessKey { + var sk branchAccessKey + sk.addr = addr + sk.treeIndex = treeIndex + return sk +} + +type chunkAccessKey struct { + branchAccessKey + leafKey byte +} + +func newChunkAccessKey(branchKey branchAccessKey, leafKey byte) chunkAccessKey { + var lk chunkAccessKey + lk.branchAccessKey = branchKey + lk.leafKey = leafKey + return lk +} + +// CodeChunksRangeGas is a helper function to touch every chunk in a code range and charge witness gas costs +func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC, size uint64, codeLen uint64, isWrite bool) uint64 { + // note that in the case where the copied code is outside the range of the + // contract code but touches the last leaf with contract code in it, + // we don't include the last leaf of code in the AccessWitness. The + // reason that we do not need the last leaf is the account's code size + // is already in the AccessWitness so a stateless verifier can see that + // the code from the last leaf is not needed. + if (codeLen == 0 && size == 0) || startPC > codeLen { + return 0 + } + + endPC := startPC + size + if endPC > codeLen { + endPC = codeLen + } + if endPC > 0 { + endPC -= 1 // endPC is the last bytecode that will be touched. + } + + var statelessGasCharged uint64 + for chunkNumber := startPC / 31; chunkNumber <= endPC/31; chunkNumber++ { + treeIndex := *uint256.NewInt((chunkNumber + 128) / 256) + subIndex := byte((chunkNumber + 128) % 256) + gas := ae.touchAddressAndChargeGas(contractAddr, treeIndex, subIndex, isWrite) + var overflow bool + statelessGasCharged, overflow = math.SafeAdd(statelessGasCharged, gas) + if overflow { + panic("overflow when adding gas") + } + } + return statelessGasCharged +} + +// VersionGas adds the account's version to the accessed data, and returns the +// amount of gas that it costs. +// Note that an access in write mode implies an access in read mode, whereas an +// access in read mode does not imply an access in write mode. +func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 { + return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite) +} + +// BalanceGas adds the account's balance to the accessed data, and returns the +// amount of gas that it costs. +// in write mode. If false, the charged gas corresponds to an access in read mode. +// Note that an access in write mode implies an access in read mode, whereas an access in +// read mode does not imply an access in write mode. +func (ae *AccessEvents) BalanceGas(addr common.Address, isWrite bool) uint64 { + return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite) +} + +// NonceGas adds the account's nonce to the accessed data, and returns the +// amount of gas that it costs. +// in write mode. If false, the charged gas corresponds to an access in read mode. +// Note that an access in write mode implies an access in read mode, whereas an access in +// read mode does not imply an access in write mode. +func (ae *AccessEvents) NonceGas(addr common.Address, isWrite bool) uint64 { + return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite) +} + +// CodeSizeGas adds the account's code size to the accessed data, and returns the +// amount of gas that it costs. +// in write mode. If false, the charged gas corresponds to an access in read mode. +// Note that an access in write mode implies an access in read mode, whereas an access in +// read mode does not imply an access in write mode. +func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 { + return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite) +} + +// CodeHashGas adds the account's code hash to the accessed data, and returns the +// amount of gas that it costs. +// in write mode. If false, the charged gas corresponds to an access in read mode. +// Note that an access in write mode implies an access in read mode, whereas an access in +// read mode does not imply an access in write mode. +func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 { + return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite) +} diff --git a/core/state/access_events_test.go b/core/state/access_events_test.go new file mode 100644 index 000000000000..705033fe0be3 --- /dev/null +++ b/core/state/access_events_test.go @@ -0,0 +1,153 @@ +// Copyright 2021 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 ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie/utils" +) + +var ( + testAddr [20]byte + testAddr2 [20]byte +) + +func init() { + for i := byte(0); i < 20; i++ { + testAddr[i] = i + testAddr[2] = 2 * i + } +} + +func TestAccountHeaderGas(t *testing.T) { + ae := NewAccessEvents(utils.NewPointCache(1024)) + + // Check cold read cost + gas := ae.VersionGas(testAddr, false) + if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost) + } + + // Check warm read cost + gas = ae.VersionGas(testAddr, false) + if gas != 0 { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) + } + + // Check cold read costs in the same group no longer incur the branch read cost + gas = ae.BalanceGas(testAddr, false) + if gas != params.WitnessChunkReadCost { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) + } + gas = ae.NonceGas(testAddr, false) + if gas != params.WitnessChunkReadCost { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) + } + gas = ae.CodeSizeGas(testAddr, false) + if gas != params.WitnessChunkReadCost { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) + } + gas = ae.CodeHashGas(testAddr, false) + if gas != params.WitnessChunkReadCost { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) + } + + // Check cold write cost + gas = ae.VersionGas(testAddr, true) + if gas != params.WitnessBranchWriteCost+params.WitnessChunkWriteCost { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost) + } + + // Check warm write cost + gas = ae.VersionGas(testAddr, true) + if gas != 0 { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) + } + + // Check a write without a read charges both read and write costs + gas = ae.BalanceGas(testAddr2, true) + if gas != params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost) + } + + // Check that a write followed by a read charges nothing + gas = ae.BalanceGas(testAddr2, false) + if gas != 0 { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) + } + + // Check that reading a slot from the account header only charges the + // chunk read cost. + gas = ae.SlotGas(testAddr, common.Hash{}, false) + if gas != params.WitnessChunkReadCost { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) + } +} + +// TestContractCreateInitGas checks that the gas cost of contract creation is correctly +// calculated. +func TestContractCreateInitGas(t *testing.T) { + ae := NewAccessEvents(utils.NewPointCache(1024)) + + var testAddr [20]byte + for i := byte(0); i < 20; i++ { + testAddr[i] = i + } + + // Check cold read cost, without a value + gas := ae.ContractCreateInitGas(testAddr, false) + if gas != params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*2+params.WitnessChunkReadCost*2 { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*3) + } + + // Check warm read cost + gas = ae.ContractCreateInitGas(testAddr, false) + if gas != 0 { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) + } +} + +// TestMessageCallGas checks that the gas cost of message calls is correctly +// calculated. +func TestMessageCallGas(t *testing.T) { + ae := NewAccessEvents(utils.NewPointCache(1024)) + + // Check cold read cost, without a value + gas := ae.MessageCallGas(testAddr) + if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost*2 { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost*2) + } + + // Check that reading the version and code size of the same account does not incur the branch read cost + gas = ae.VersionGas(testAddr, false) + if gas != 0 { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) + } + gas = ae.CodeSizeGas(testAddr, false) + if gas != 0 { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) + } + + // Check warm read cost + gas = ae.MessageCallGas(testAddr) + if gas != 0 { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) + } +} diff --git a/core/state/database.go b/core/state/database.go index 188ecf0c86a5..04d7c06687c0 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -20,7 +20,6 @@ import ( "errors" "fmt" - "github.com/crate-crypto/go-ipa/banderwagon" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core/rawdb" @@ -40,11 +39,8 @@ const ( // Cache size granted for caching clean code. codeCacheSize = 64 * 1024 * 1024 - // commitmentSize is the size of commitment stored in cache. - commitmentSize = banderwagon.UncompressedSize - - // Cache item granted for caching commitment results. - commitmentCacheItems = 64 * 1024 * 1024 / (commitmentSize + common.AddressLength) + // Number of address->curve point associations to keep. + pointCacheSize = 4096 ) // Database wraps access to tries and contract code. @@ -67,6 +63,9 @@ type Database interface { // DiskDB returns the underlying key-value disk database. DiskDB() ethdb.KeyValueStore + // PointCache returns the cache holding points used in verkle tree key computation + PointCache() *utils.PointCache + // TrieDB returns the underlying trie database for managing trie nodes. TrieDB() *triedb.Database } @@ -139,6 +138,9 @@ type Trie interface { // nodes of the longest existing prefix of the key (at least the root), ending // with the node that proves the absence of the key. Prove(key []byte, proofDb ethdb.KeyValueWriter) error + + // IsVerkle returns true if the trie is verkle-tree based + IsVerkle() bool } // NewDatabase creates a backing store for state. The returned database is safe for @@ -157,6 +159,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database { codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), triedb: triedb.NewDatabase(db, config), + pointCache: utils.NewPointCache(pointCacheSize), } } @@ -167,6 +170,7 @@ func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), triedb: triedb, + pointCache: utils.NewPointCache(pointCacheSize), } } @@ -175,12 +179,13 @@ type cachingDB struct { codeSizeCache *lru.Cache[common.Hash, int] codeCache *lru.SizeConstrainedCache[common.Hash, []byte] triedb *triedb.Database + pointCache *utils.PointCache } // OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { if db.triedb.IsVerkle() { - return trie.NewVerkleTrie(root, db.triedb, utils.NewPointCache(commitmentCacheItems)) + return trie.NewVerkleTrie(root, db.triedb, db.pointCache) } tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) if err != nil { @@ -266,3 +271,8 @@ func (db *cachingDB) DiskDB() ethdb.KeyValueStore { func (db *cachingDB) TrieDB() *triedb.Database { return db.triedb } + +// PointCache returns the cache of evaluated curve points. +func (db *cachingDB) PointCache() *utils.PointCache { + return db.pointCache +} diff --git a/core/state/statedb.go b/core/state/statedb.go index ac37d4ceeb9a..1b028a284492 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" + "github.com/ethereum/go-ethereum/trie/utils" "github.com/holiman/uint256" "golang.org/x/sync/errgroup" ) @@ -1327,7 +1328,10 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er // - Add coinbase to access list (EIP-3651) // - Reset transient storage (EIP-1153) func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { - if rules.IsBerlin { + if rules.IsEIP2929 && rules.IsEIP4762 { + panic("eip2929 and eip4762 are both activated") + } + if rules.IsEIP2929 { // Clear out any leftover from previous executions al := newAccessList() s.accessList = al @@ -1439,3 +1443,7 @@ func (s *StateDB) markUpdate(addr common.Address) { s.mutations[addr].applied = false s.mutations[addr].typ = update } + +func (s *StateDB) PointCache() *utils.PointCache { + return s.db.PointCache() +} diff --git a/core/state_processor_test.go b/core/state_processor_test.go index e98d27eb92d2..af4d29b604da 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -482,7 +482,7 @@ func TestProcessVerkle(t *testing.T) { txCost1 := params.TxGas txCost2 := params.TxGas contractCreationCost := intrinsicContractCreationGas + uint64(2039 /* execution costs */) - codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + uint64(293644 /* execution costs */) + codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + uint64(57444 /* execution costs */) blockGasUsagesExpected := []uint64{ txCost1*2 + txCost2, txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas, diff --git a/core/state_transition.go b/core/state_transition.go index a52e24dc4395..3b6a887fff52 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -68,7 +68,7 @@ func (result *ExecutionResult) Revert() []byte { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { +func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { // Set the starting gas for the raw transaction var gas uint64 if isContractCreation && isHomestead { @@ -405,6 +405,14 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } st.gasRemaining -= gas + if rules.IsEIP4762 { + st.evm.AccessEvents.AddTxOrigin(msg.From) + + if targetAddr := msg.To; targetAddr != nil { + st.evm.AccessEvents.AddTxDestination(*targetAddr, msg.Value.Sign() != 0) + } + } + // Check clause 6 value, overflow := uint256.FromBig(msg.Value) if overflow { @@ -458,6 +466,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { fee := new(uint256.Int).SetUint64(st.gasUsed()) fee.Mul(fee, effectiveTipU256) st.state.AddBalance(st.evm.Context.Coinbase, fee, tracing.BalanceIncreaseRewardTransactionFee) + + // add the coinbase to the witness iff the fee is greater than 0 + if rules.IsEIP4762 && fee.Sign() != 0 { + st.evm.AccessEvents.BalanceGas(st.evm.Context.Coinbase, true) + } } return &ExecutionResult{ diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 41bae63d9fa2..9b08cffd4526 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -298,6 +298,12 @@ const ( GasChangeCallStorageColdAccess GasChangeReason = 13 // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert. GasChangeCallFailedExecution GasChangeReason = 14 + // GasChangeWitnessContractInit is the amount charged for adding to the witness during the contract creation initialization step + GasChangeWitnessContractInit GasChangeReason = 15 + // GasChangeWitnessContractCreation is the amount charged for adding to the witness during the contract creation finalization step + GasChangeWitnessContractCreation GasChangeReason = 16 + // GasChangeWitnessCodeChunk is the amount charged for touching one or more contract code chunks + GasChangeWitnessCodeChunk GasChangeReason = 17 // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as // it will be "manually" tracked by a direct emit of the gas change event. diff --git a/core/vm/common.go b/core/vm/common.go index 90ba4a4ad15b..ba75950e370b 100644 --- a/core/vm/common.go +++ b/core/vm/common.go @@ -63,6 +63,18 @@ func getData(data []byte, start uint64, size uint64) []byte { return common.RightPadBytes(data[start:end], int(size)) } +func getDataAndAdjustedBounds(data []byte, start uint64, size uint64) (codeCopyPadded []byte, actualStart uint64, sizeNonPadded uint64) { + length := uint64(len(data)) + if start > length { + start = length + } + end := start + size + if end > length { + end = length + } + return common.RightPadBytes(data[start:end], int(size)), start, end - start +} + // toWordSize returns the ceiled word size required for memory expansion. func toWordSize(size uint64) uint64 { if size > math.MaxUint64-31 { diff --git a/core/vm/contract.go b/core/vm/contract.go index 4e28260a67b7..cfda75b27e11 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -57,6 +57,9 @@ type Contract struct { CodeAddr *common.Address Input []byte + // is the execution frame represented by this object a contract deployment + IsDeployment bool + Gas uint64 value *uint256.Int } diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 8b648062e993..8e0f8467752e 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -137,6 +137,8 @@ var PrecompiledContractsPrague = map[common.Address]PrecompiledContract{ var PrecompiledContractsBLS = PrecompiledContractsPrague +var PrecompiledContractsVerkle = PrecompiledContractsPrague + var ( PrecompiledAddressesPrague []common.Address PrecompiledAddressesCancun []common.Address diff --git a/core/vm/eips.go b/core/vm/eips.go index 9f06b2818fee..edd6ec8d0a2c 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -18,9 +18,11 @@ package vm import ( "fmt" + "math" "sort" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -37,6 +39,7 @@ var activators = map[int]func(*JumpTable){ 1884: enable1884, 1344: enable1344, 1153: enable1153, + 4762: enable4762, } // EnableEIP enables the given EIP on the config. @@ -319,3 +322,214 @@ func enable6780(jt *JumpTable) { maxStack: maxStack(1, 0), } } + +func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + var ( + stack = scope.Stack + a = stack.pop() + memOffset = stack.pop() + codeOffset = stack.pop() + length = stack.pop() + ) + uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() + if overflow { + uint64CodeOffset = math.MaxUint64 + } + addr := common.Address(a.Bytes20()) + code := interpreter.evm.StateDB.GetCode(addr) + contract := &Contract{ + Code: code, + self: AccountRef(addr), + } + paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) + statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false) + if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { + scope.Contract.Gas = 0 + return nil, ErrOutOfGas + } + scope.Memory.Set(memOffset.Uint64(), length.Uint64(), paddedCodeCopy) + + return nil, nil +} + +// opPush1EIP4762 handles the special case of PUSH1 opcode for EIP-4762, which +// need not worry about the adjusted bound logic when adding the PUSHDATA to +// the list of access events. +func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + var ( + codeLen = uint64(len(scope.Contract.Code)) + integer = new(uint256.Int) + ) + *pc += 1 + if *pc < codeLen { + scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc]))) + + if !scope.Contract.IsDeployment && *pc%31 == 0 { + // touch next chunk if PUSH1 is at the boundary. if so, *pc has + // advanced past this boundary. + contractAddr := scope.Contract.Address() + statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false) + if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { + scope.Contract.Gas = 0 + return nil, ErrOutOfGas + } + } + } else { + scope.Stack.push(integer.Clear()) + } + return nil, nil +} + +func makePushEIP4762(size uint64, pushByteSize int) executionFunc { + return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + var ( + codeLen = len(scope.Contract.Code) + start = min(codeLen, int(*pc+1)) + end = min(codeLen, start+pushByteSize) + ) + scope.Stack.push(new(uint256.Int).SetBytes( + common.RightPadBytes( + scope.Contract.Code[start:end], + pushByteSize, + )), + ) + + if !scope.Contract.IsDeployment { + contractAddr := scope.Contract.Address() + statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false) + if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { + scope.Contract.Gas = 0 + return nil, ErrOutOfGas + } + } + + *pc += size + return nil, nil + } +} + +func enable4762(jt *JumpTable) { + jt[SSTORE] = &operation{ + dynamicGas: gasSStore4762, + execute: opSstore, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + } + jt[SLOAD] = &operation{ + dynamicGas: gasSLoad4762, + execute: opSload, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + } + + jt[BALANCE] = &operation{ + execute: opBalance, + dynamicGas: gasBalance4762, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + } + + jt[EXTCODESIZE] = &operation{ + execute: opExtCodeSize, + dynamicGas: gasExtCodeSize4762, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + } + + jt[EXTCODEHASH] = &operation{ + execute: opExtCodeHash, + dynamicGas: gasExtCodeHash4762, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + } + + jt[EXTCODECOPY] = &operation{ + execute: opExtCodeCopyEIP4762, + dynamicGas: gasExtCodeCopyEIP4762, + minStack: minStack(4, 0), + maxStack: maxStack(4, 0), + memorySize: memoryExtCodeCopy, + } + + jt[CODECOPY] = &operation{ + execute: opCodeCopy, + constantGas: GasFastestStep, + dynamicGas: gasCodeCopyEip4762, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryCodeCopy, + } + + jt[SELFDESTRUCT] = &operation{ + execute: opSelfdestruct6780, + dynamicGas: gasSelfdestructEIP4762, + constantGas: params.SelfdestructGasEIP150, + minStack: minStack(1, 0), + maxStack: maxStack(1, 0), + } + + jt[CREATE] = &operation{ + execute: opCreate, + constantGas: params.CreateNGasEip4762, + dynamicGas: gasCreateEip3860, + minStack: minStack(3, 1), + maxStack: maxStack(3, 1), + memorySize: memoryCreate, + } + + jt[CREATE2] = &operation{ + execute: opCreate2, + constantGas: params.CreateNGasEip4762, + dynamicGas: gasCreate2Eip3860, + minStack: minStack(4, 1), + maxStack: maxStack(4, 1), + memorySize: memoryCreate2, + } + + jt[CALL] = &operation{ + execute: opCall, + dynamicGas: gasCallEIP4762, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + } + + jt[CALLCODE] = &operation{ + execute: opCallCode, + dynamicGas: gasCallCodeEIP4762, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + } + + jt[STATICCALL] = &operation{ + execute: opStaticCall, + dynamicGas: gasStaticCallEIP4762, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryStaticCall, + } + + jt[DELEGATECALL] = &operation{ + execute: opDelegateCall, + dynamicGas: gasDelegateCallEIP4762, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryDelegateCall, + } + + jt[PUSH1] = &operation{ + execute: opPush1EIP4762, + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + } + for i := 1; i < 32; i++ { + jt[PUSH1+OpCode(i)] = &operation{ + execute: makePushEIP4762(uint64(i+1), i+1), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + } + } +} diff --git a/core/vm/evm.go b/core/vm/evm.go index c18353a97354..26af0ea041b8 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -22,6 +22,7 @@ import ( "sync/atomic" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -42,6 +43,8 @@ type ( func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { var precompiles map[common.Address]PrecompiledContract switch { + case evm.chainRules.IsVerkle: + precompiles = PrecompiledContractsVerkle case evm.chainRules.IsPrague: precompiles = PrecompiledContractsPrague case evm.chainRules.IsCancun: @@ -85,10 +88,11 @@ type BlockContext struct { // All fields can change between transactions. type TxContext struct { // Message information - Origin common.Address // Provides information for ORIGIN - GasPrice *big.Int // Provides information for GASPRICE (and is used to zero the basefee if NoBaseFee is set) - BlobHashes []common.Hash // Provides information for BLOBHASH - BlobFeeCap *big.Int // Is used to zero the blobbasefee if NoBaseFee is set + Origin common.Address // Provides information for ORIGIN + GasPrice *big.Int // Provides information for GASPRICE (and is used to zero the basefee if NoBaseFee is set) + BlobHashes []common.Hash // Provides information for BLOBHASH + BlobFeeCap *big.Int // Is used to zero the blobbasefee if NoBaseFee is set + AccessEvents *state.AccessEvents // Capture all state accesses for this tx } // EVM is the Ethereum Virtual Machine base object and provides @@ -156,6 +160,9 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig // Reset resets the EVM with a new transaction context.Reset // This is not threadsafe and should only be done very cautiously. func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { + if evm.chainRules.IsEIP4762 { + txCtx.AccessEvents = state.NewAccessEvents(statedb.PointCache()) + } evm.TxContext = txCtx evm.StateDB = statedb } @@ -200,6 +207,16 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas p, isPrecompile := evm.precompile(addr) if !evm.StateDB.Exist(addr) { + if !isPrecompile && evm.chainRules.IsEIP4762 { + // add proof of absence to witness + wgas := evm.AccessEvents.AddAccount(addr, false) + if gas < wgas { + evm.StateDB.RevertToSnapshot(snapshot) + return nil, 0, ErrOutOfGas + } + gas -= wgas + } + if !isPrecompile && evm.chainRules.IsEIP158 && value.IsZero() { // Calling a non-existing account, don't do anything. return nil, gas, nil @@ -439,7 +456,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // We add this to the access list _before_ taking a snapshot. Even if the // creation fails, the access-list change should not be rolled back. - if evm.chainRules.IsBerlin { + if evm.chainRules.IsEIP2929 { evm.StateDB.AddAddressToAccessList(address) } // Ensure there's no existing contract already at the designated address. @@ -479,8 +496,18 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) + contract.IsDeployment = true - ret, err = evm.interpreter.Run(contract, nil, false) + // Charge the contract creation init gas in verkle mode + if evm.chainRules.IsEIP4762 { + if !contract.UseGas(evm.AccessEvents.ContractCreateInitGas(address, value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) { + err = ErrOutOfGas + } + } + + if err == nil { + ret, err = evm.interpreter.Run(contract, nil, false) + } // Check whether the max code size has been exceeded, assign err if the case. if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize { @@ -497,11 +524,24 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // be stored due to not enough gas set an error and let it be handled // by the error checking condition below. if err == nil { - createDataGas := uint64(len(ret)) * params.CreateDataGas - if contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { - evm.StateDB.SetCode(address, ret) + if !evm.chainRules.IsEIP4762 { + createDataGas := uint64(len(ret)) * params.CreateDataGas + if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { + err = ErrCodeStoreOutOfGas + } } else { - err = ErrCodeStoreOutOfGas + // Contract creation completed, touch the missing fields in the contract + if !contract.UseGas(evm.AccessEvents.AddAccount(address, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) { + err = ErrCodeStoreOutOfGas + } + + if err == nil && len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) { + err = ErrCodeStoreOutOfGas + } + } + + if err == nil { + evm.StateDB.SetCode(address, ret) } } diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index fd5fa14cf5d7..d294324b08c2 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -383,7 +383,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize } else if !evm.StateDB.Exist(address) { gas += params.CallNewAccountGas } - if transfersValue { + if transfersValue && !evm.chainRules.IsEIP4762 { gas += params.CallValueTransferGas } memoryGas, err := memoryGasCost(mem, memorySize) @@ -394,7 +394,14 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { return 0, ErrGasUintOverflow } - + if evm.chainRules.IsEIP4762 { + if transfersValue { + gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address)) + if overflow { + return 0, ErrGasUintOverflow + } + } + } evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err @@ -402,6 +409,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, ErrGasUintOverflow } + return gas, nil } @@ -414,12 +422,22 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory gas uint64 overflow bool ) - if stack.Back(2).Sign() != 0 { + if stack.Back(2).Sign() != 0 && !evm.chainRules.IsEIP4762 { gas += params.CallValueTransferGas } if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { return 0, ErrGasUintOverflow } + if evm.chainRules.IsEIP4762 { + address := common.Address(stack.Back(1).Bytes20()) + transfersValue := !stack.Back(2).IsZero() + if transfersValue { + gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address)) + if overflow { + return 0, ErrGasUintOverflow + } + } + } evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err diff --git a/core/vm/instructions.go b/core/vm/instructions.go index f37ee004dc3a..10cdd72e0c57 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -359,9 +359,9 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ if overflow { uint64CodeOffset = math.MaxUint64 } + codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64()) scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - return nil, nil } @@ -434,6 +434,7 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( num.Clear() return nil, nil } + var upper, lower uint64 upper = interpreter.evm.Context.BlockNumber.Uint64() if upper < 257 { @@ -583,6 +584,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b if interpreter.evm.chainRules.IsEIP150 { gas -= gas / 64 } + // reuse size int for stackvalue stackvalue := size @@ -623,6 +625,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) gas = scope.Contract.Gas ) + // Apply EIP150 gas -= gas / 64 scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2) @@ -637,7 +640,6 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] stackvalue.SetBytes(addr.Bytes()) } scope.Stack.push(&stackvalue) - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { @@ -896,6 +898,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { pushByteSize, )), ) + *pc += size return nil, nil } diff --git a/core/vm/interface.go b/core/vm/interface.go index 774360a08ef9..8b2c58898ec6 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie/utils" "github.com/holiman/uint256" ) @@ -75,6 +76,10 @@ type StateDB interface { // AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform // even if the feature/fork is not active yet AddSlotToAccessList(addr common.Address, slot common.Hash) + + // PointCache returns the point cache used in computations + PointCache() *utils.PointCache + Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) RevertToSnapshot(int) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 406927e32158..66a20f434e85 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -99,6 +99,9 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter { // If jump table was not initialised we set the default one. var table *JumpTable switch { + case evm.chainRules.IsVerkle: + // TODO replace with proper instruction set when fork is specified + table = &verkleInstructionSet case evm.chainRules.IsCancun: table = &cancunInstructionSet case evm.chainRules.IsShanghai: @@ -219,6 +222,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // Capture pre-execution values for tracing. logged, pcCopy, gasCopy = false, pc, contract.Gas } + + if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment { + // if the PC ends up in a new "chunk" of verkleized code, charge the + // associated costs. + contractAddr := contract.Address() + contract.Gas -= in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false) + } + // Get the operation from the jump table and validate the stack to ensure there are // enough stack items available to perform the operation. op = contract.GetOp(pc) diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 65716f9442af..5624f47ba72c 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -57,6 +57,7 @@ var ( mergeInstructionSet = newMergeInstructionSet() shanghaiInstructionSet = newShanghaiInstructionSet() cancunInstructionSet = newCancunInstructionSet() + verkleInstructionSet = newVerkleInstructionSet() ) // JumpTable contains the EVM opcodes supported at a given fork. @@ -80,6 +81,12 @@ func validate(jt JumpTable) JumpTable { return jt } +func newVerkleInstructionSet() JumpTable { + instructionSet := newCancunInstructionSet() + enable4762(&instructionSet) + return validate(instructionSet) +} + func newCancunInstructionSet() JumpTable { instructionSet := newShanghaiInstructionSet() enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode) diff --git a/core/vm/operations_verkle.go b/core/vm/operations_verkle.go new file mode 100644 index 000000000000..73eb05974dc0 --- /dev/null +++ b/core/vm/operations_verkle.go @@ -0,0 +1,159 @@ +// Copyright 2024 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 vm + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/params" +) + +func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas := evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), true) + if gas == 0 { + gas = params.WarmStorageReadCostEIP2929 + } + return gas, nil +} + +func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas := evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), false) + if gas == 0 { + gas = params.WarmStorageReadCostEIP2929 + } + return gas, nil +} + +func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + address := stack.peek().Bytes20() + gas := evm.AccessEvents.BalanceGas(address, false) + if gas == 0 { + gas = params.WarmStorageReadCostEIP2929 + } + return gas, nil +} + +func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + address := stack.peek().Bytes20() + if _, isPrecompile := evm.precompile(address); isPrecompile { + return 0, nil + } + gas := evm.AccessEvents.VersionGas(address, false) + gas += evm.AccessEvents.CodeSizeGas(address, false) + if gas == 0 { + gas = params.WarmStorageReadCostEIP2929 + } + return gas, nil +} + +func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + address := stack.peek().Bytes20() + if _, isPrecompile := evm.precompile(address); isPrecompile { + return 0, nil + } + gas := evm.AccessEvents.CodeHashGas(address, false) + if gas == 0 { + gas = params.WarmStorageReadCostEIP2929 + } + return gas, nil +} + +func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := oldCalculator(evm, contract, stack, mem, memorySize) + if err != nil { + return 0, err + } + if _, isPrecompile := evm.precompile(contract.Address()); isPrecompile { + return gas, nil + } + witnessGas := evm.AccessEvents.MessageCallGas(contract.Address()) + if witnessGas == 0 { + witnessGas = params.WarmStorageReadCostEIP2929 + } + return witnessGas + gas, nil + } +} + +var ( + gasCallEIP4762 = makeCallVariantGasEIP4762(gasCall) + gasCallCodeEIP4762 = makeCallVariantGasEIP4762(gasCallCode) + gasStaticCallEIP4762 = makeCallVariantGasEIP4762(gasStaticCall) + gasDelegateCallEIP4762 = makeCallVariantGasEIP4762(gasDelegateCall) +) + +func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + beneficiaryAddr := common.Address(stack.peek().Bytes20()) + if _, isPrecompile := evm.precompile(beneficiaryAddr); isPrecompile { + return 0, nil + } + contractAddr := contract.Address() + statelessGas := evm.AccessEvents.VersionGas(contractAddr, false) + statelessGas += evm.AccessEvents.CodeSizeGas(contractAddr, false) + statelessGas += evm.AccessEvents.BalanceGas(contractAddr, false) + if contractAddr != beneficiaryAddr { + statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr, false) + } + // Charge write costs if it transfers value + if evm.StateDB.GetBalance(contractAddr).Sign() != 0 { + statelessGas += evm.AccessEvents.BalanceGas(contractAddr, true) + if contractAddr != beneficiaryAddr { + statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr, true) + } + } + return statelessGas, nil +} + +func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := gasCodeCopy(evm, contract, stack, mem, memorySize) + if err != nil { + return 0, err + } + var ( + codeOffset = stack.Back(1) + length = stack.Back(2) + ) + uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() + if overflow { + uint64CodeOffset = math.MaxUint64 + } + _, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(contract.Code, uint64CodeOffset, length.Uint64()) + if !contract.IsDeployment { + gas += evm.AccessEvents.CodeChunksRangeGas(contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false) + } + return gas, nil +} + +func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + // memory expansion first (dynamic part of pre-2929 implementation) + gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize) + if err != nil { + return 0, err + } + addr := common.Address(stack.peek().Bytes20()) + wgas := evm.AccessEvents.VersionGas(addr, false) + wgas += evm.AccessEvents.CodeSizeGas(addr, false) + if wgas == 0 { + wgas = params.WarmStorageReadCostEIP2929 + } + var overflow bool + // We charge (cold-warm), since 'warm' is already charged as constantGas + if gas, overflow = math.SafeAdd(gas, wgas); overflow { + return 0, ErrGasUintOverflow + } + return gas, nil +} diff --git a/go.mod b/go.mod index 3cd0d82bdf7c..cf76ae35eb05 100644 --- a/go.mod +++ b/go.mod @@ -15,20 +15,20 @@ require ( github.com/cloudflare/cloudflare-go v0.79.0 github.com/cockroachdb/pebble v1.1.0 github.com/consensys/gnark-crypto v0.12.1 - github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 + github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c github.com/crate-crypto/go-kzg-4844 v1.0.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 github.com/ethereum/c-kzg-4844 v1.0.0 + github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 github.com/fatih/color v1.13.0 github.com/ferranbt/fastssz v0.1.2 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/memsize v0.0.2 github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff - github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/protobuf v1.5.4 diff --git a/go.sum b/go.sum index a7b4eb1c138a..76e6feccdb13 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJ github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I= +github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -169,6 +169,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= +github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= @@ -185,8 +187,6 @@ github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgx github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= diff --git a/params/config.go b/params/config.go index 534e57831add..871782399d14 100644 --- a/params/config.go +++ b/params/config.go @@ -581,6 +581,11 @@ func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) } +// IsEIP4762 returns whether eip 4762 has been activated at given block. +func (c *ChainConfig) IsEIP4762(num *big.Int, time uint64) bool { + return c.IsVerkle(num, time) +} + // CheckCompatible checks whether scheduled fork transitions have been imported // with a mismatching chain configuration. func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError { @@ -909,6 +914,7 @@ func (err *ConfigCompatError) Error() string { type Rules struct { ChainID *big.Int IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool + IsEIP2929, IsEIP4762 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool IsMerge, IsShanghai, IsCancun, IsPrague bool @@ -923,6 +929,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules } // disallow setting Merge out of order isMerge = isMerge && c.IsLondon(num) + isVerkle := isMerge && c.IsVerkle(num, timestamp) return Rules{ ChainID: new(big.Int).Set(chainID), IsHomestead: c.IsHomestead(num), @@ -934,11 +941,13 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsPetersburg: c.IsPetersburg(num), IsIstanbul: c.IsIstanbul(num), IsBerlin: c.IsBerlin(num), + IsEIP2929: c.IsBerlin(num) && !isVerkle, IsLondon: c.IsLondon(num), IsMerge: isMerge, IsShanghai: isMerge && c.IsShanghai(num, timestamp), IsCancun: isMerge && c.IsCancun(num, timestamp), IsPrague: isMerge && c.IsPrague(num, timestamp), - IsVerkle: isMerge && c.IsVerkle(num, timestamp), + IsVerkle: isVerkle, + IsEIP4762: isVerkle, } } diff --git a/params/protocol_params.go b/params/protocol_params.go index 863cf58ece46..d375a9664273 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -86,6 +86,7 @@ const ( LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction. Create2Gas uint64 = 32000 // Once per CREATE2 operation + CreateNGasEip4762 uint64 = 1000 // Once per CREATEn operations post-verkle SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation. MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. diff --git a/params/verkle_params.go b/params/verkle_params.go new file mode 100644 index 000000000000..93d4f7cd6476 --- /dev/null +++ b/params/verkle_params.go @@ -0,0 +1,36 @@ +// Copyright 2023 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 params + +// Verkle tree EIP: costs associated to witness accesses +var ( + WitnessBranchReadCost uint64 = 1900 + WitnessChunkReadCost uint64 = 200 + WitnessBranchWriteCost uint64 = 3000 + WitnessChunkWriteCost uint64 = 500 + WitnessChunkFillCost uint64 = 6200 +) + +// ClearVerkleWitnessCosts sets all witness costs to 0, which is necessary +// for historical block replay simulations. +func ClearVerkleWitnessCosts() { + WitnessBranchReadCost = 0 + WitnessChunkReadCost = 0 + WitnessBranchWriteCost = 0 + WitnessChunkWriteCost = 0 + WitnessChunkFillCost = 0 +} diff --git a/trie/secure_trie.go b/trie/secure_trie.go index efd4dfb5d33f..e38d5ac4dc36 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -284,3 +284,7 @@ func (t *StateTrie) getSecKeyCache() map[string][]byte { } return t.secKeyCache } + +func (t *StateTrie) IsVerkle() bool { + return false +} diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index 328b2d252761..2a4a632d4926 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -23,7 +23,7 @@ import ( "github.com/crate-crypto/go-ipa/bandersnatch/fr" "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/metrics" - "github.com/gballet/go-verkle" + "github.com/ethereum/go-verkle" "github.com/holiman/uint256" ) @@ -219,7 +219,7 @@ func CodeChunkKey(address []byte, chunk *uint256.Int) []byte { return GetTreeKey(address, treeIndex, subIndex) } -func storageIndex(bytes []byte) (*uint256.Int, byte) { +func StorageIndex(bytes []byte) (*uint256.Int, byte) { // If the storage slot is in the header, we need to add the header offset. var key uint256.Int key.SetBytes(bytes) @@ -245,7 +245,7 @@ func storageIndex(bytes []byte) (*uint256.Int, byte) { // StorageSlotKey returns the verkle tree key of the storage slot for the // specified account. func StorageSlotKey(address []byte, storageKey []byte) []byte { - treeIndex, subIndex := storageIndex(storageKey) + treeIndex, subIndex := StorageIndex(storageKey) return GetTreeKey(address, treeIndex, subIndex) } @@ -296,7 +296,7 @@ func CodeChunkKeyWithEvaluatedAddress(addressPoint *verkle.Point, chunk *uint256 // slot for the specified account. The difference between StorageSlotKey is the // address evaluation is already computed to minimize the computational overhead. func StorageSlotKeyWithEvaluatedAddress(evaluated *verkle.Point, storageKey []byte) []byte { - treeIndex, subIndex := storageIndex(storageKey) + treeIndex, subIndex := StorageIndex(storageKey) return GetTreeKeyWithEvaluatedAddress(evaluated, treeIndex, subIndex) } diff --git a/trie/utils/verkle_test.go b/trie/utils/verkle_test.go index 28b059c3794e..c29504a6d0cb 100644 --- a/trie/utils/verkle_test.go +++ b/trie/utils/verkle_test.go @@ -20,7 +20,7 @@ import ( "bytes" "testing" - "github.com/gballet/go-verkle" + "github.com/ethereum/go-verkle" "github.com/holiman/uint256" ) diff --git a/trie/verkle.go b/trie/verkle.go index 01d813d9ec9b..bb0c54857f6d 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -27,7 +27,7 @@ import ( "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/utils" "github.com/ethereum/go-ethereum/triedb/database" - "github.com/gballet/go-verkle" + "github.com/ethereum/go-verkle" "github.com/holiman/uint256" ) From 2ac83e197bc6417231d6faa2027486cf3e00b6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 13 May 2024 15:47:45 +0300 Subject: [PATCH 270/571] core/state: blocking prefetcher on term signal, parallel updates (#29519) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * core/state: trie prefetcher change: calling trie() doesn't stop the associated subfetcher Co-authored-by: Martin HS Co-authored-by: Péter Szilágyi * core/state: improve prefetcher * core/state: restore async prefetcher stask scheduling * core/state: finish prefetching async and process storage updates async * core/state: don't use the prefetcher for missing snapshot items * core/state: remove update concurrency for Verkle tries * core/state: add some termination checks to prefetcher async shutdowns * core/state: differentiate db tries and prefetched tries * core/state: teh teh teh --------- Co-authored-by: Jared Wasinger Co-authored-by: Martin HS Co-authored-by: Gary Rong --- core/blockchain.go | 8 +- core/state/state_object.go | 97 +++++++--- core/state/statedb.go | 106 ++++++----- core/state/trie_prefetcher.go | 292 +++++++++++++---------------- core/state/trie_prefetcher_test.go | 65 +------ 5 files changed, 271 insertions(+), 297 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 56e00e85b615..7c8ab3abc44a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1805,8 +1805,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } statedb.SetLogger(bc.logger) - // Enable prefetching to pull in trie node paths while processing transactions - statedb.StartPrefetcher("chain") + // If we are past Byzantium, enable prefetching to pull in trie node paths + // while processing transactions. Before Byzantium the prefetcher is mostly + // useless due to the intermediate root hashing after each transaction. + if bc.chainConfig.IsByzantium(block.Number()) { + statedb.StartPrefetcher("chain") + } activeState = statedb // If we have a followup block, run that against the current state to pre-cache diff --git a/core/state/state_object.go b/core/state/state_object.go index cc42d0687965..3239be368cb2 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "maps" + "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -33,6 +34,14 @@ import ( "github.com/holiman/uint256" ) +// hasherPool holds a pool of hashers used by state objects during concurrent +// trie updates. +var hasherPool = sync.Pool{ + New: func() interface{} { + return crypto.NewKeccakState() + }, +} + type Storage map[common.Hash]common.Hash func (s Storage) Copy() Storage { @@ -118,27 +127,39 @@ func (s *stateObject) touch() { } } -// getTrie returns the associated storage trie. The trie will be opened -// if it's not loaded previously. An error will be returned if trie can't -// be loaded. +// getTrie returns the associated storage trie. The trie will be opened if it' +// not loaded previously. An error will be returned if trie can't be loaded. +// +// If a new trie is opened, it will be cached within the state object to allow +// subsequent reads to expand the same trie instead of reloading from disk. func (s *stateObject) getTrie() (Trie, error) { if s.trie == nil { - // Try fetching from prefetcher first - if s.data.Root != types.EmptyRootHash && s.db.prefetcher != nil { - // When the miner is creating the pending state, there is no prefetcher - s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root) - } - if s.trie == nil { - tr, err := s.db.db.OpenStorageTrie(s.db.originalRoot, s.address, s.data.Root, s.db.trie) - if err != nil { - return nil, err - } - s.trie = tr + tr, err := s.db.db.OpenStorageTrie(s.db.originalRoot, s.address, s.data.Root, s.db.trie) + if err != nil { + return nil, err } + s.trie = tr } return s.trie, nil } +// getPrefetchedTrie returns the associated trie, as populated by the prefetcher +// if it's available. +// +// Note, opposed to getTrie, this method will *NOT* blindly cache the resulting +// trie in the state object. The caller might want to do that, but it's cleaner +// to break the hidden interdependency between retrieving tries from the db or +// from the prefetcher. +func (s *stateObject) getPrefetchedTrie() (Trie, error) { + // If there's nothing to meaningfully return, let the user figure it out by + // pulling the trie from disk. + if s.data.Root == types.EmptyRootHash || s.db.prefetcher == nil { + return nil, nil + } + // Attempt to retrieve the trie from the pretecher + return s.db.prefetcher.trie(s.addrHash, s.data.Root) +} + // GetState retrieves a value from the account storage trie. func (s *stateObject) GetState(key common.Hash) common.Hash { value, _ := s.getState(key) @@ -248,7 +269,7 @@ func (s *stateObject) setState(key common.Hash, value common.Hash, origin common // finalise moves all dirty storage slots into the pending area to be hashed or // committed later. It is invoked at the end of every transaction. -func (s *stateObject) finalise(prefetch bool) { +func (s *stateObject) finalise() { slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage)) for key, value := range s.dirtyStorage { // If the slot is different from its original value, move it into the @@ -263,8 +284,10 @@ func (s *stateObject) finalise(prefetch bool) { delete(s.pendingStorage, key) } } - if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { - s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch) + if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { + if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch); err != nil { + log.Error("Failed to prefetch slots", "addr", s.address, "slots", len(slotsToPrefetch), "err", err) + } } if len(s.dirtyStorage) > 0 { s.dirtyStorage = make(Storage) @@ -283,25 +306,43 @@ func (s *stateObject) finalise(prefetch bool) { // storage change at all. func (s *stateObject) updateTrie() (Trie, error) { // Make sure all dirty slots are finalized into the pending storage area - s.finalise(false) + s.finalise() // Short circuit if nothing changed, don't bother with hashing anything if len(s.pendingStorage) == 0 { return s.trie, nil } + // Retrieve a pretecher populated trie, or fall back to the database + tr, err := s.getPrefetchedTrie() + switch { + case err != nil: + // Fetcher retrieval failed, something's very wrong, abort + s.db.setError(err) + return nil, err + + case tr == nil: + // Fetcher not running or empty trie, fallback to the database trie + tr, err = s.getTrie() + if err != nil { + s.db.setError(err) + return nil, err + } + + default: + // Prefetcher returned a live trie, swap it out for the current one + s.trie = tr + } // The snapshot storage map for the object var ( storage map[common.Hash][]byte origin map[common.Hash][]byte ) - tr, err := s.getTrie() - if err != nil { - s.db.setError(err) - return nil, err - } // Insert all the pending storage updates into the trie usedStorage := make([][]byte, 0, len(s.pendingStorage)) + hasher := hasherPool.Get().(crypto.KeccakState) + defer hasherPool.Put(hasher) + // Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes // in circumstances similar to the following: // @@ -330,26 +371,30 @@ func (s *stateObject) updateTrie() (Trie, error) { s.db.setError(err) return nil, err } - s.db.StorageUpdated += 1 + s.db.StorageUpdated.Add(1) } else { deletions = append(deletions, key) } // Cache the mutated storage slots until commit if storage == nil { + s.db.storagesLock.Lock() if storage = s.db.storages[s.addrHash]; storage == nil { storage = make(map[common.Hash][]byte) s.db.storages[s.addrHash] = storage } + s.db.storagesLock.Unlock() } - khash := crypto.HashData(s.db.hasher, key[:]) + khash := crypto.HashData(hasher, key[:]) storage[khash] = encoded // encoded will be nil if it's deleted // Cache the original value of mutated storage slots if origin == nil { + s.db.storagesLock.Lock() if origin = s.db.storagesOrigin[s.address]; origin == nil { origin = make(map[common.Hash][]byte) s.db.storagesOrigin[s.address] = origin } + s.db.storagesLock.Unlock() } // Track the original value of slot only if it's mutated first time if _, ok := origin[khash]; !ok { @@ -369,7 +414,7 @@ func (s *stateObject) updateTrie() (Trie, error) { s.db.setError(err) return nil, err } - s.db.StorageDeleted += 1 + s.db.StorageDeleted.Add(1) } // If no slots were touched, issue a warning as we shouldn't have done all // the above work in the first place diff --git a/core/state/statedb.go b/core/state/statedb.go index 1b028a284492..0ef52a88f6ea 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -24,6 +24,7 @@ import ( "slices" "sort" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -96,10 +97,12 @@ type StateDB struct { // These maps hold the state changes (including the corresponding // original value) that occurred in this **block**. - accounts map[common.Hash][]byte // The mutated accounts in 'slim RLP' encoding + accounts map[common.Hash][]byte // The mutated accounts in 'slim RLP' encoding + accountsOrigin map[common.Address][]byte // The original value of mutated accounts in 'slim RLP' encoding + storages map[common.Hash]map[common.Hash][]byte // The mutated slots in prefix-zero trimmed rlp format - accountsOrigin map[common.Address][]byte // The original value of mutated accounts in 'slim RLP' encoding storagesOrigin map[common.Address]map[common.Hash][]byte // The original value of mutated slots in prefix-zero trimmed rlp format + storagesLock sync.Mutex // Mutex protecting the maps during concurrent updates/commits // This map holds 'live' objects, which will get modified while // processing a state transition. @@ -165,9 +168,9 @@ type StateDB struct { TrieDBCommits time.Duration AccountUpdated int - StorageUpdated int + StorageUpdated atomic.Int64 AccountDeleted int - StorageDeleted int + StorageDeleted atomic.Int64 // Testing hooks onCommit func(states *triestate.Set) // Hook invoked when commit is performed @@ -214,7 +217,8 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) { // commit phase, most of the needed data is already hot. func (s *StateDB) StartPrefetcher(namespace string) { if s.prefetcher != nil { - s.prefetcher.close() + s.prefetcher.terminate(false) + s.prefetcher.report() s.prefetcher = nil } if s.snap != nil { @@ -226,7 +230,8 @@ func (s *StateDB) StartPrefetcher(namespace string) { // from the gathered metrics. func (s *StateDB) StopPrefetcher() { if s.prefetcher != nil { - s.prefetcher.close() + s.prefetcher.terminate(false) + s.prefetcher.report() s.prefetcher = nil } } @@ -544,9 +549,6 @@ func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common // updateStateObject writes the given object to the trie. func (s *StateDB) updateStateObject(obj *stateObject) { - // Track the amount of time wasted on updating the account from the trie - defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) - // Encode the account and update the account trie addr := obj.Address() if err := s.trie.UpdateAccount(addr, &obj.data); err != nil { @@ -575,10 +577,6 @@ func (s *StateDB) updateStateObject(obj *stateObject) { // deleteStateObject removes the given object from the state trie. func (s *StateDB) deleteStateObject(addr common.Address) { - // Track the amount of time wasted on deleting the account from the trie - defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) - - // Delete the account from the trie if err := s.trie.DeleteAccount(addr); err != nil { s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err)) } @@ -743,13 +741,6 @@ func (s *StateDB) Copy() *StateDB { // in the middle of a transaction. state.accessList = s.accessList.Copy() state.transientStorage = s.transientStorage.Copy() - - // If there's a prefetcher running, make an inactive copy of it that can - // only access data but does not actively preload (since the user will not - // know that they need to explicitly terminate an active copy). - if s.prefetcher != nil { - state.prefetcher = s.prefetcher.copy() - } return state } @@ -820,7 +811,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { delete(s.accountsOrigin, obj.address) // Clear out any previously updated account data (may be recreated via a resurrect) delete(s.storagesOrigin, obj.address) // Clear out any previously updated storage data (may be recreated via a resurrect) } else { - obj.finalise(true) // Prefetch slots in the background + obj.finalise() s.markUpdate(addr) } // At this point, also ship the address off to the precacher. The precacher @@ -829,7 +820,9 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure } if s.prefetcher != nil && len(addressesToPrefetch) > 0 { - s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch) + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch); err != nil { + log.Error("Failed to prefetch addresses", "addresses", len(addressesToPrefetch), "err", err) + } } // Invalidate journal because reverting across transactions is not allowed. s.clearJournalAndRefund() @@ -842,42 +835,52 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // Finalise all the dirty storage states and write them into the tries s.Finalise(deleteEmptyObjects) - // If there was a trie prefetcher operating, it gets aborted and irrevocably - // modified after we start retrieving tries. Remove it from the statedb after - // this round of use. - // - // This is weird pre-byzantium since the first tx runs with a prefetcher and - // the remainder without, but pre-byzantium even the initial prefetcher is - // useless, so no sleep lost. - prefetcher := s.prefetcher + // If there was a trie prefetcher operating, terminate it async so that the + // individual storage tries can be updated as soon as the disk load finishes. if s.prefetcher != nil { + s.prefetcher.terminate(true) defer func() { - s.prefetcher.close() - s.prefetcher = nil + s.prefetcher.report() + s.prefetcher = nil // Pre-byzantium, unset any used up prefetcher }() } - // Although naively it makes sense to retrieve the account trie and then do - // the contract storage and account updates sequentially, that short circuits - // the account prefetcher. Instead, let's process all the storage updates - // first, giving the account prefetches just a few more milliseconds of time - // to pull useful data from disk. - start := time.Now() + // Process all storage updates concurrently. The state object update root + // method will internally call a blocking trie fetch from the prefetcher, + // so there's no need to explicitly wait for the prefetchers to finish. + var ( + start = time.Now() + workers errgroup.Group + ) + if s.db.TrieDB().IsVerkle() { + // Whilst MPT storage tries are independent, Verkle has one single trie + // for all the accounts and all the storage slots merged together. The + // former can thus be simply parallelized, but updating the latter will + // need concurrency support within the trie itself. That's a TODO for a + // later time. + workers.SetLimit(1) + } for addr, op := range s.mutations { - if op.applied { - continue - } - if op.isDelete() { + if op.applied || op.isDelete() { continue } - s.stateObjects[addr].updateRoot() + obj := s.stateObjects[addr] // closure for the task runner below + workers.Go(func() error { + obj.updateRoot() + return nil + }) } + workers.Wait() s.StorageUpdates += time.Since(start) // Now we're about to start to write changes to the trie. The trie is so far // _untouched_. We can check with the prefetcher, if it can give us a trie // which has the same root, but also has some content loaded into it. - if prefetcher != nil { - if trie := prefetcher.trie(common.Hash{}, s.originalRoot); trie != nil { + start = time.Now() + + if s.prefetcher != nil { + if trie, err := s.prefetcher.trie(common.Hash{}, s.originalRoot); err != nil { + log.Error("Failed to retrieve account pre-fetcher trie", "err", err) + } else if trie != nil { s.trie = trie } } @@ -913,8 +916,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.deleteStateObject(deletedAddr) s.AccountDeleted += 1 } - if prefetcher != nil { - prefetcher.used(common.Hash{}, s.originalRoot, usedAddrs) + s.AccountUpdates += time.Since(start) + + if s.prefetcher != nil { + s.prefetcher.used(common.Hash{}, s.originalRoot, usedAddrs) } // Track the amount of time wasted on hashing the account trie defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) @@ -1255,15 +1260,16 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er return common.Hash{}, err } accountUpdatedMeter.Mark(int64(s.AccountUpdated)) - storageUpdatedMeter.Mark(int64(s.StorageUpdated)) + storageUpdatedMeter.Mark(s.StorageUpdated.Load()) accountDeletedMeter.Mark(int64(s.AccountDeleted)) - storageDeletedMeter.Mark(int64(s.StorageDeleted)) + storageDeletedMeter.Mark(s.StorageDeleted.Load()) accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated)) accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated)) storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted)) s.AccountUpdated, s.AccountDeleted = 0, 0 - s.StorageUpdated, s.StorageDeleted = 0, 0 + s.StorageUpdated.Store(0) + s.StorageDeleted.Store(0) // If snapshotting is enabled, update the snapshot tree with this new version if s.snap != nil { diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index c2a49417d458..7e08964e41bf 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -17,6 +17,7 @@ package state import ( + "errors" "sync" "github.com/ethereum/go-ethereum/common" @@ -27,6 +28,10 @@ import ( var ( // triePrefetchMetricsPrefix is the prefix under which to publish the metrics. triePrefetchMetricsPrefix = "trie/prefetch/" + + // errTerminated is returned if a fetcher is attempted to be operated after it + // has already terminated. + errTerminated = errors.New("fetcher is already terminated") ) // triePrefetcher is an active prefetcher, which receives accounts or storage @@ -37,160 +42,126 @@ var ( type triePrefetcher struct { db Database // Database to fetch trie nodes through root common.Hash // Root hash of the account trie for metrics - fetches map[string]Trie // Partially or fully fetched tries. Only populated for inactive copies. fetchers map[string]*subfetcher // Subfetchers for each trie + term chan struct{} // Channel to signal interruption deliveryMissMeter metrics.Meter accountLoadMeter metrics.Meter accountDupMeter metrics.Meter - accountSkipMeter metrics.Meter accountWasteMeter metrics.Meter storageLoadMeter metrics.Meter storageDupMeter metrics.Meter - storageSkipMeter metrics.Meter storageWasteMeter metrics.Meter } func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePrefetcher { prefix := triePrefetchMetricsPrefix + namespace - p := &triePrefetcher{ + return &triePrefetcher{ db: db, root: root, fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map + term: make(chan struct{}), deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil), accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil), accountDupMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup", nil), - accountSkipMeter: metrics.GetOrRegisterMeter(prefix+"/account/skip", nil), accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil), storageLoadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load", nil), storageDupMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup", nil), - storageSkipMeter: metrics.GetOrRegisterMeter(prefix+"/storage/skip", nil), storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil), } - return p } -// close iterates over all the subfetchers, aborts any that were left spinning -// and reports the stats to the metrics subsystem. -func (p *triePrefetcher) close() { +// terminate iterates over all the subfetchers and issues a terminateion request +// to all of them. Depending on the async parameter, the method will either block +// until all subfetchers spin down, or return immediately. +func (p *triePrefetcher) terminate(async bool) { + // Short circuit if the fetcher is already closed + select { + case <-p.term: + return + default: + } + // Termiante all sub-fetchers, sync or async, depending on the request for _, fetcher := range p.fetchers { - fetcher.abort() // safe to do multiple times - - if metrics.Enabled { - if fetcher.root == p.root { - p.accountLoadMeter.Mark(int64(len(fetcher.seen))) - p.accountDupMeter.Mark(int64(fetcher.dups)) - p.accountSkipMeter.Mark(int64(len(fetcher.tasks))) - - for _, key := range fetcher.used { - delete(fetcher.seen, string(key)) - } - p.accountWasteMeter.Mark(int64(len(fetcher.seen))) - } else { - p.storageLoadMeter.Mark(int64(len(fetcher.seen))) - p.storageDupMeter.Mark(int64(fetcher.dups)) - p.storageSkipMeter.Mark(int64(len(fetcher.tasks))) - - for _, key := range fetcher.used { - delete(fetcher.seen, string(key)) - } - p.storageWasteMeter.Mark(int64(len(fetcher.seen))) - } - } + fetcher.terminate(async) } - // Clear out all fetchers (will crash on a second call, deliberate) - p.fetchers = nil + close(p.term) } -// copy creates a deep-but-inactive copy of the trie prefetcher. Any trie data -// already loaded will be copied over, but no goroutines will be started. This -// is mostly used in the miner which creates a copy of it's actively mutated -// state to be sealed while it may further mutate the state. -func (p *triePrefetcher) copy() *triePrefetcher { - copy := &triePrefetcher{ - db: p.db, - root: p.root, - fetches: make(map[string]Trie), // Active prefetchers use the fetches map - - deliveryMissMeter: p.deliveryMissMeter, - accountLoadMeter: p.accountLoadMeter, - accountDupMeter: p.accountDupMeter, - accountSkipMeter: p.accountSkipMeter, - accountWasteMeter: p.accountWasteMeter, - storageLoadMeter: p.storageLoadMeter, - storageDupMeter: p.storageDupMeter, - storageSkipMeter: p.storageSkipMeter, - storageWasteMeter: p.storageWasteMeter, +// report aggregates the pre-fetching and usage metrics and reports them. +func (p *triePrefetcher) report() { + if !metrics.Enabled { + return } - // If the prefetcher is already a copy, duplicate the data - if p.fetches != nil { - for root, fetch := range p.fetches { - if fetch == nil { - continue + for _, fetcher := range p.fetchers { + fetcher.wait() // ensure the fetcher's idle before poking in its internals + + if fetcher.root == p.root { + p.accountLoadMeter.Mark(int64(len(fetcher.seen))) + p.accountDupMeter.Mark(int64(fetcher.dups)) + for _, key := range fetcher.used { + delete(fetcher.seen, string(key)) } - copy.fetches[root] = p.db.CopyTrie(fetch) + p.accountWasteMeter.Mark(int64(len(fetcher.seen))) + } else { + p.storageLoadMeter.Mark(int64(len(fetcher.seen))) + p.storageDupMeter.Mark(int64(fetcher.dups)) + for _, key := range fetcher.used { + delete(fetcher.seen, string(key)) + } + p.storageWasteMeter.Mark(int64(len(fetcher.seen))) } - return copy - } - // Otherwise we're copying an active fetcher, retrieve the current states - for id, fetcher := range p.fetchers { - copy.fetches[id] = fetcher.peek() } - return copy } -// prefetch schedules a batch of trie items to prefetch. -func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) { - // If the prefetcher is an inactive one, bail out - if p.fetches != nil { - return +// prefetch schedules a batch of trie items to prefetch. After the prefetcher is +// closed, all the following tasks scheduled will not be executed and an error +// will be returned. +// +// prefetch is called from two locations: +// +// 1. Finalize of the state-objects storage roots. This happens at the end +// of every transaction, meaning that if several transactions touches +// upon the same contract, the parameters invoking this method may be +// repeated. +// 2. Finalize of the main account trie. This happens only once per block. +func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) error { + // Ensure the subfetcher is still alive + select { + case <-p.term: + return errTerminated + default: } - // Active fetcher, schedule the retrievals id := p.trieID(owner, root) fetcher := p.fetchers[id] if fetcher == nil { fetcher = newSubfetcher(p.db, p.root, owner, root, addr) p.fetchers[id] = fetcher } - fetcher.schedule(keys) + return fetcher.schedule(keys) } -// trie returns the trie matching the root hash, or nil if the prefetcher doesn't -// have it. -func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie { - // If the prefetcher is inactive, return from existing deep copies - id := p.trieID(owner, root) - if p.fetches != nil { - trie := p.fetches[id] - if trie == nil { - p.deliveryMissMeter.Mark(1) - return nil - } - return p.db.CopyTrie(trie) - } - // Otherwise the prefetcher is active, bail if no trie was prefetched for this root - fetcher := p.fetchers[id] +// trie returns the trie matching the root hash, blocking until the fetcher of +// the given trie terminates. If no fetcher exists for the request, nil will be +// returned. +func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) (Trie, error) { + // Bail if no trie was prefetched for this root + fetcher := p.fetchers[p.trieID(owner, root)] if fetcher == nil { + log.Error("Prefetcher missed to load trie", "owner", owner, "root", root) p.deliveryMissMeter.Mark(1) - return nil + return nil, nil } - // Interrupt the prefetcher if it's by any chance still running and return - // a copy of any pre-loaded trie. - fetcher.abort() // safe to do multiple times - - trie := fetcher.peek() - if trie == nil { - p.deliveryMissMeter.Mark(1) - return nil - } - return trie + // Subfetcher exists, retrieve its trie + return fetcher.peek(), nil } // used marks a batch of state items used to allow creating statistics as to -// how useful or wasteful the prefetcher is. +// how useful or wasteful the fetcher is. func (p *triePrefetcher) used(owner common.Hash, root common.Hash, used [][]byte) { if fetcher := p.fetchers[p.trieID(owner, root)]; fetcher != nil { + fetcher.wait() // ensure the fetcher's idle before poking in its internals fetcher.used = used } } @@ -218,10 +189,9 @@ type subfetcher struct { tasks [][]byte // Items queued up for retrieval lock sync.Mutex // Lock protecting the task queue - wake chan struct{} // Wake channel if a new task is scheduled - stop chan struct{} // Channel to interrupt processing - term chan struct{} // Channel to signal interruption - copy chan chan Trie // Channel to request a copy of the current trie + wake chan struct{} // Wake channel if a new task is scheduled + stop chan struct{} // Channel to interrupt processing + term chan struct{} // Channel to signal interruption seen map[string]struct{} // Tracks the entries already loaded dups int // Number of duplicate preload tasks @@ -240,7 +210,6 @@ func newSubfetcher(db Database, state common.Hash, owner common.Hash, root commo wake: make(chan struct{}, 1), stop: make(chan struct{}), term: make(chan struct{}), - copy: make(chan chan Trie), seen: make(map[string]struct{}), } go sf.loop() @@ -248,50 +217,61 @@ func newSubfetcher(db Database, state common.Hash, owner common.Hash, root commo } // schedule adds a batch of trie keys to the queue to prefetch. -func (sf *subfetcher) schedule(keys [][]byte) { +func (sf *subfetcher) schedule(keys [][]byte) error { + // Ensure the subfetcher is still alive + select { + case <-sf.term: + return errTerminated + default: + } // Append the tasks to the current queue sf.lock.Lock() sf.tasks = append(sf.tasks, keys...) sf.lock.Unlock() - // Notify the prefetcher, it's fine if it's already terminated + // Notify the background thread to execute scheduled tasks select { case sf.wake <- struct{}{}: + // Wake signal sent default: + // Wake signal not sent as a previous is already queued } + return nil } -// peek tries to retrieve a deep copy of the fetcher's trie in whatever form it -// is currently. -func (sf *subfetcher) peek() Trie { - ch := make(chan Trie) - select { - case sf.copy <- ch: - // Subfetcher still alive, return copy from it - return <-ch +// wait blocks until the subfetcher terminates. This method is used to block on +// an async termination before accessing internal fields from the fetcher. +func (sf *subfetcher) wait() { + <-sf.term +} - case <-sf.term: - // Subfetcher already terminated, return a copy directly - if sf.trie == nil { - return nil - } - return sf.db.CopyTrie(sf.trie) - } +// peek retrieves the fetcher's trie, populated with any pre-fetched data. The +// returned trie will be a shallow copy, so modifying it will break subsequent +// peeks for the original data. The method will block until all the scheduled +// data has been loaded and the fethcer terminated. +func (sf *subfetcher) peek() Trie { + // Block until the fertcher terminates, then retrieve the trie + sf.wait() + return sf.trie } -// abort interrupts the subfetcher immediately. It is safe to call abort multiple -// times but it is not thread safe. -func (sf *subfetcher) abort() { +// terminate requests the subfetcher to stop accepting new tasks and spin down +// as soon as everything is loaded. Depending on the async parameter, the method +// will either block until all disk loads finish or return immediately. +func (sf *subfetcher) terminate(async bool) { select { case <-sf.stop: default: close(sf.stop) } + if async { + return + } <-sf.term } -// loop waits for new tasks to be scheduled and keeps loading them until it runs -// out of tasks or its underlying trie is retrieved for committing. +// loop loads newly-scheduled trie tasks as they are received and loads them, stopping +// when requested. func (sf *subfetcher) loop() { // No matter how the loop stops, signal anyone waiting that it's terminated defer close(sf.term) @@ -305,8 +285,6 @@ func (sf *subfetcher) loop() { } sf.trie = trie } else { - // The trie argument can be nil as verkle doesn't support prefetching - // yet. TODO FIX IT(rjl493456442), otherwise code will panic here. trie, err := sf.db.OpenStorageTrie(sf.state, sf.addr, sf.root, nil) if err != nil { log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) @@ -318,48 +296,38 @@ func (sf *subfetcher) loop() { for { select { case <-sf.wake: - // Subfetcher was woken up, retrieve any tasks to avoid spinning the lock + // Execute all remaining tasks in single run sf.lock.Lock() tasks := sf.tasks sf.tasks = nil sf.lock.Unlock() - // Prefetch any tasks until the loop is interrupted - for i, task := range tasks { - select { - case <-sf.stop: - // If termination is requested, add any leftover back and return - sf.lock.Lock() - sf.tasks = append(sf.tasks, tasks[i:]...) - sf.lock.Unlock() - return - - case ch := <-sf.copy: - // Somebody wants a copy of the current trie, grant them - ch <- sf.db.CopyTrie(sf.trie) - - default: - // No termination request yet, prefetch the next entry - if _, ok := sf.seen[string(task)]; ok { - sf.dups++ - } else { - if len(task) == common.AddressLength { - sf.trie.GetAccount(common.BytesToAddress(task)) - } else { - sf.trie.GetStorage(sf.addr, task) - } - sf.seen[string(task)] = struct{}{} - } + for _, task := range tasks { + if _, ok := sf.seen[string(task)]; ok { + sf.dups++ + continue + } + if len(task) == common.AddressLength { + sf.trie.GetAccount(common.BytesToAddress(task)) + } else { + sf.trie.GetStorage(sf.addr, task) } + sf.seen[string(task)] = struct{}{} } - case ch := <-sf.copy: - // Somebody wants a copy of the current trie, grant them - ch <- sf.db.CopyTrie(sf.trie) - case <-sf.stop: - // Termination is requested, abort and leave remaining tasks - return + // Termination is requested, abort if no more tasks are pending. If + // there are some, exhaust them first. + sf.lock.Lock() + done := sf.tasks == nil + sf.lock.Unlock() + + if done { + return + } + // Some tasks are pending, loop and pick them up (that wake branch + // will be selected eventually, whilst stop remains closed to this + // branch will also run afterwards). } } } diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index a616adf98f3a..d6788fad9936 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -19,7 +19,6 @@ package state import ( "math/big" "testing" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -46,68 +45,20 @@ func filledStateDB() *StateDB { return state } -func TestCopyAndClose(t *testing.T) { +func TestUseAfterTerminate(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - time.Sleep(1 * time.Second) - a := prefetcher.trie(common.Hash{}, db.originalRoot) - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - b := prefetcher.trie(common.Hash{}, db.originalRoot) - cpy := prefetcher.copy() - cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - c := cpy.trie(common.Hash{}, db.originalRoot) - prefetcher.close() - cpy2 := cpy.copy() - cpy2.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - d := cpy2.trie(common.Hash{}, db.originalRoot) - cpy.close() - cpy2.close() - if a.Hash() != b.Hash() || a.Hash() != c.Hash() || a.Hash() != d.Hash() { - t.Fatalf("Invalid trie, hashes should be equal: %v %v %v %v", a.Hash(), b.Hash(), c.Hash(), d.Hash()) - } -} -func TestUseAfterClose(t *testing.T) { - db := filledStateDB() - prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") - skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - a := prefetcher.trie(common.Hash{}, db.originalRoot) - prefetcher.close() - b := prefetcher.trie(common.Hash{}, db.originalRoot) - if a == nil { - t.Fatal("Prefetching before close should not return nil") - } - if b != nil { - t.Fatal("Trie after close should return nil") + if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err != nil { + t.Errorf("Prefetch failed before terminate: %v", err) } -} + prefetcher.terminate(false) -func TestCopyClose(t *testing.T) { - db := filledStateDB() - prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") - skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - cpy := prefetcher.copy() - a := prefetcher.trie(common.Hash{}, db.originalRoot) - b := cpy.trie(common.Hash{}, db.originalRoot) - prefetcher.close() - c := prefetcher.trie(common.Hash{}, db.originalRoot) - d := cpy.trie(common.Hash{}, db.originalRoot) - if a == nil { - t.Fatal("Prefetching before close should not return nil") - } - if b == nil { - t.Fatal("Copy trie should return nil") - } - if c != nil { - t.Fatal("Trie after close should return nil") + if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err == nil { + t.Errorf("Prefetch succeeded after terminate: %v", err) } - if d == nil { - t.Fatal("Copy trie should not return nil") + if _, err := prefetcher.trie(common.Hash{}, db.originalRoot); err != nil { + t.Errorf("Trie retrieval failed after terminate: %v", err) } } From 5b3e3cd2bee284db7d7deaa5986544d356410dcb Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 13 May 2024 21:34:29 +0800 Subject: [PATCH 271/571] tests: update tests (#29730) --- cmd/evm/t8n_test.go | 8 ++++---- tests/init.go | 21 +++++++++++++++++++-- tests/state_test.go | 8 -------- tests/testdata | 2 +- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 5a74491c3b2d..76ebc420ec6c 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -234,7 +234,7 @@ func TestT8n(t *testing.T) { { // Test post-merge transition base: "./testdata/24", input: t8nInput{ - "alloc.json", "txs.json", "env.json", "Merge", "", + "alloc.json", "txs.json", "env.json", "Paris", "", }, output: t8nOutput{alloc: true, result: true}, expOut: "exp.json", @@ -242,7 +242,7 @@ func TestT8n(t *testing.T) { { // Test post-merge transition where input is missing random base: "./testdata/24", input: t8nInput{ - "alloc.json", "txs.json", "env-missingrandom.json", "Merge", "", + "alloc.json", "txs.json", "env-missingrandom.json", "Paris", "", }, output: t8nOutput{alloc: false, result: false}, expExitCode: 3, @@ -250,7 +250,7 @@ func TestT8n(t *testing.T) { { // Test base fee calculation base: "./testdata/25", input: t8nInput{ - "alloc.json", "txs.json", "env.json", "Merge", "", + "alloc.json", "txs.json", "env.json", "Paris", "", }, output: t8nOutput{alloc: true, result: true}, expOut: "exp.json", @@ -378,7 +378,7 @@ func TestT8nTracing(t *testing.T) { { base: "./testdata/32", input: t8nInput{ - "alloc.json", "txs.json", "env.json", "Merge", "", + "alloc.json", "txs.json", "env.json", "Paris", "", }, extraArgs: []string{"--trace", "--trace.callframes"}, expectedTraces: []string{"trace-0-0x47806361c0fa084be3caa18afe8c48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl"}, diff --git a/tests/init.go b/tests/init.go index e333587a07a7..c85e714c0023 100644 --- a/tests/init.go +++ b/tests/init.go @@ -212,7 +212,7 @@ var Forks = map[string]*params.ChainConfig{ LondonBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0), }, - "ArrowGlacierToMergeAtDiffC0000": { + "ArrowGlacierToParisAtDiffC0000": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), @@ -246,6 +246,23 @@ var Forks = map[string]*params.ChainConfig{ ArrowGlacierBlock: big.NewInt(0), GrayGlacierBlock: big.NewInt(0), }, + "Paris": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + }, "Merge": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), @@ -281,7 +298,7 @@ var Forks = map[string]*params.ChainConfig{ TerminalTotalDifficulty: big.NewInt(0), ShanghaiTime: u64(0), }, - "MergeToShanghaiAtTime15k": { + "ParisToShanghaiAtTime15k": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), diff --git a/tests/state_test.go b/tests/state_test.go index 6f53b88722d6..76fec97de0ee 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -54,14 +54,6 @@ func initMatcher(st *testMatcher) { // Uses 1GB RAM per tested fork st.skipLoad(`^stStaticCall/static_Call1MB`) - // These tests fail as of https://github.com/ethereum/go-ethereum/pull/28666, since we - // no longer delete "leftover storage" when deploying a contract. - st.skipLoad(`^stSStoreTest/InitCollision\.json`) - st.skipLoad(`^stRevertTest/RevertInCreateInInit\.json`) - st.skipLoad(`^stExtCodeHash/dynamicAccountOverwriteEmpty\.json`) - st.skipLoad(`^stCreate2/create2collisionStorage\.json`) - st.skipLoad(`^stCreate2/RevertInCreateInInitCreate2\.json`) - // Broken tests: // EOF is not part of cancun st.skipLoad(`^stEOF/`) diff --git a/tests/testdata b/tests/testdata index fa51c5c164f7..faf33b471465 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit fa51c5c164f79140730ccb8fe26a46c3d3994338 +Subproject commit faf33b471465d3c6cdc3d04fbd690895f78d33f2 From be3284373f0761b35c38416f7e7aba5dee163e91 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 14 May 2024 20:54:49 +0800 Subject: [PATCH 272/571] core/state: remove useless operation (#29769) --- core/state/state_object.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 3239be368cb2..85cb8b44de35 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -304,10 +304,9 @@ func (s *stateObject) finalise() { // loading or updating of the trie, an error will be returned. Furthermore, // this function will return the mutated storage trie, or nil if there is no // storage change at all. +// +// It assumes all the dirty storage slots have been finalized before. func (s *stateObject) updateTrie() (Trie, error) { - // Make sure all dirty slots are finalized into the pending storage area - s.finalise() - // Short circuit if nothing changed, don't bother with hashing anything if len(s.pendingStorage) == 0 { return s.trie, nil From 8919c5c0fc9d1c8e528e4b05e11644b6515bf45a Mon Sep 17 00:00:00 2001 From: 0xbeny <55846654+0xbeny@users.noreply.github.com> Date: Tue, 14 May 2024 17:04:32 +0400 Subject: [PATCH 273/571] core: deploy EIP-4788 contract in dev mode genesis (#29655) Co-authored-by: Felix Lange --- core/chain_makers_test.go | 3 +-- core/genesis.go | 2 ++ params/protocol_params.go | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index a2ec9e6507d4..6241f3fb6960 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -43,12 +43,11 @@ func TestGeneratePOSChain(t *testing.T) { bb = common.Address{0xbb} funds = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether)) config = *params.AllEthashProtocolChanges - asm4788 = common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500") gspec = &Genesis{ Config: &config, Alloc: types.GenesisAlloc{ address: {Balance: funds}, - params.BeaconRootsAddress: {Balance: common.Big0, Code: asm4788}, + params.BeaconRootsAddress: {Code: params.BeaconRootsCode}, }, BaseFee: big.NewInt(params.InitialBaseFee), Difficulty: common.Big1, diff --git a/core/genesis.go b/core/genesis.go index 42836e026993..042071c531eb 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -593,6 +593,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b + // Pre-deploy EIP-4788 system contract + params.BeaconRootsAddress: types.Account{Nonce: 1, Code: params.BeaconRootsCode}, }, } if faucet != nil { diff --git a/params/protocol_params.go b/params/protocol_params.go index d375a9664273..8ffe8ee75db1 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -187,6 +187,10 @@ var ( // BeaconRootsAddress is the address where historical beacon roots are stored as per EIP-4788 BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02") + + // BeaconRootsCode is the code where historical beacon roots are stored as per EIP-4788 + BeaconRootsCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500") + // SystemAddress is where the system-transaction is sent from as per EIP-4788 SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe") ) From d2f00cb54edc4486314c25d9e6c5b739009c2201 Mon Sep 17 00:00:00 2001 From: cario-dev <152556479+cario-dev@users.noreply.github.com> Date: Tue, 14 May 2024 15:46:11 +0200 Subject: [PATCH 274/571] .github: upgrade to action versions with node20 (#29776) * github: upgrade checkout action to version with node20 * Update go.yml --------- Co-authored-by: Felix Lange --- .github/workflows/go.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 0c673d15f168..41e9631f1571 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,9 +11,9 @@ jobs: build: runs-on: self-hosted steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v5 with: go-version: 1.21.4 - name: Run tests From 7ed52c949e66ca7874ba39e8d69b451615382edc Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Wed, 15 May 2024 20:23:24 +0800 Subject: [PATCH 275/571] core: move balanceCheck addition in buyGas (#29762) It's a bit confusing to add msg.value into the balanceCheck within the conditional. No impact on block validation since GasFeeCap is always set when processing transactions. --- core/state_transition.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/state_transition.go b/core/state_transition.go index 3b6a887fff52..1a6a66a2fc14 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -240,8 +240,9 @@ func (st *StateTransition) buyGas() error { if st.msg.GasFeeCap != nil { balanceCheck.SetUint64(st.msg.GasLimit) balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) - balanceCheck.Add(balanceCheck, st.msg.Value) } + balanceCheck.Add(balanceCheck, st.msg.Value) + if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) { if blobGas := st.blobGasUsed(); blobGas > 0 { // Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap From 473ee8fc07a3f89cf3978e164a6fad218de9a6b5 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 16 May 2024 17:58:35 +0800 Subject: [PATCH 276/571] trie, eth/protocols/snap: sanitize the committed node data (#29485) --- eth/protocols/snap/sync.go | 2 +- trie/sync.go | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index ffda718700f4..8671aebc9081 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -2358,7 +2358,7 @@ func (s *Syncer) commitHealer(force bool) { } batch := s.db.NewBatch() if err := s.healer.scheduler.Commit(batch); err != nil { - log.Error("Failed to commit healing data", "err", err) + log.Crit("Failed to commit healing data", "err", err) } if err := batch.Write(); err != nil { log.Crit("Failed to persist healing data", "err", err) diff --git a/trie/sync.go b/trie/sync.go index f6b20b224025..e609f69e2bb6 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -22,6 +22,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -149,6 +150,7 @@ type CodeSyncResult struct { // nodeOp represents an operation upon the trie node. It can either represent a // deletion to the specific node or a node write for persisting retrieved node. type nodeOp struct { + del bool // flag if op stands for a delete operation owner common.Hash // identifier of the trie (empty for account trie) path []byte // path from the root to the specified node. blob []byte // the content of the node (nil for deletion) @@ -156,8 +158,34 @@ type nodeOp struct { } // isDelete indicates if the operation is a database deletion. -func (op *nodeOp) isDelete() bool { - return len(op.blob) == 0 +func (op *nodeOp) valid() bool { + if op.del && len(op.blob) != 0 { + return false + } + if !op.del && len(op.blob) == 0 { + return false + } + return true +} + +// string returns the node operation in string representation. +func (op *nodeOp) string() string { + var node string + if op.owner == (common.Hash{}) { + node = fmt.Sprintf("node: (%v)", op.path) + } else { + node = fmt.Sprintf("node: (%x-%v)", op.owner, op.path) + } + var blobHex string + if len(op.blob) == 0 { + blobHex = "nil" + } else { + blobHex = hexutil.Encode(op.blob) + } + if op.del { + return fmt.Sprintf("del %s %s %s", node, blobHex, op.hash.Hex()) + } + return fmt.Sprintf("write %s %s %s", node, blobHex, op.hash.Hex()) } // syncMemBatch is an in-memory buffer of successfully downloaded but not yet @@ -220,6 +248,7 @@ func (batch *syncMemBatch) delNode(owner common.Hash, path []byte) { batch.size += common.HashLength + uint64(len(path)) } batch.nodes = append(batch.nodes, nodeOp{ + del: true, owner: owner, path: path, }) @@ -428,7 +457,10 @@ func (s *Sync) Commit(dbw ethdb.Batch) error { storage int ) for _, op := range s.membatch.nodes { - if op.isDelete() { + if !op.valid() { + return fmt.Errorf("invalid op, %s", op.string()) + } + if op.del { // node deletion is only supported in path mode. if op.owner == (common.Hash{}) { rawdb.DeleteAccountTrieNode(dbw, op.path) From be5df74ed57fdb415a8823ec6d8611ab8a336743 Mon Sep 17 00:00:00 2001 From: cocoyeal <150209682+cocoyeal@users.noreply.github.com> Date: Tue, 21 May 2024 19:53:34 +0800 Subject: [PATCH 277/571] trie: update the `valid` function comments (#29809) --- trie/sync.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trie/sync.go b/trie/sync.go index e609f69e2bb6..3b7caae5b103 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -157,7 +157,7 @@ type nodeOp struct { hash common.Hash // hash of the node content (empty for node deletion) } -// isDelete indicates if the operation is a database deletion. +// valid checks whether the node operation is valid. func (op *nodeOp) valid() bool { if op.del && len(op.blob) != 0 { return false From 7fd7c1f7dd9ba8d90399df2f080e4101ae37a255 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 21 May 2024 18:27:36 +0200 Subject: [PATCH 278/571] eth/tracers: fix basefee context for traceBlock (#29811) This fixes an issue for `debug_traceBlock*` methods where the BASEFEE opcode was returning always 0. This caused the method return invalid results. Co-authored-by: Sina Mahmoodi --- eth/tracers/api.go | 4 +- eth/tracers/api_test.go | 88 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index d99531d48fc9..30648c475367 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -22,7 +22,6 @@ import ( "encoding/json" "errors" "fmt" - "math/big" "os" "runtime" "sync" @@ -982,7 +981,8 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor return nil, err } } - vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: big.NewInt(0)}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) + // The actual TxContext will be created as part of ApplyTransactionWithEVM. + vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: message.GasPrice, BlobFeeCap: message.BlobGasFeeCap}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) statedb.SetLogger(tracer.Hooks) // Define a meaningful timeout of a single transaction trace diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 36caee0dda45..120cb585c711 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -994,3 +995,90 @@ func TestTraceChain(t *testing.T) { } } } + +// newTestMergedBackend creates a post-merge chain +func newTestMergedBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { + backend := &testBackend{ + chainConfig: gspec.Config, + engine: beacon.NewFaker(), + chaindb: rawdb.NewMemoryDatabase(), + } + // Generate blocks for testing + _, blocks, _ := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator) + + // Import the canonical chain + cacheConfig := &core.CacheConfig{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + SnapshotLimit: 0, + TrieDirtyDisabled: true, // Archive mode + } + chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + backend.chain = chain + return backend +} + +func TestTraceBlockWithBasefee(t *testing.T) { + t.Parallel() + accounts := newAccounts(1) + target := common.HexToAddress("0x1111111111111111111111111111111111111111") + genesis := &core.Genesis{ + Config: params.AllDevChainProtocolChanges, + Alloc: types.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(1 * params.Ether)}, + target: {Nonce: 1, Code: []byte{ + byte(vm.BASEFEE), byte(vm.STOP), + }}, + }, + } + genBlocks := 1 + signer := types.HomesteadSigner{} + var txHash common.Hash + var baseFee = new(big.Int) + backend := newTestMergedBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: uint64(i), + To: &target, + Value: big.NewInt(0), + Gas: 5 * params.TxGas, + GasPrice: b.BaseFee(), + Data: nil}), + signer, accounts[0].key) + b.AddTx(tx) + txHash = tx.Hash() + baseFee.Set(b.BaseFee()) + }) + defer backend.chain.Stop() + api := NewAPI(backend) + + var testSuite = []struct { + blockNumber rpc.BlockNumber + config *TraceConfig + want string + }{ + // Trace head block + { + blockNumber: rpc.BlockNumber(genBlocks), + want: fmt.Sprintf(`[{"txHash":"%#x","result":{"gas":21002,"failed":false,"returnValue":"","structLogs":[{"pc":0,"op":"BASEFEE","gas":84000,"gasCost":2,"depth":1,"stack":[]},{"pc":1,"op":"STOP","gas":83998,"gasCost":0,"depth":1,"stack":["%#x"]}]}}]`, txHash, baseFee), + }, + } + for i, tc := range testSuite { + result, err := api.TraceBlockByNumber(context.Background(), tc.blockNumber, tc.config) + if err != nil { + t.Errorf("test %d, want no error, have %v", i, err) + continue + } + have, _ := json.Marshal(result) + want := tc.want + if string(have) != want { + t.Errorf("test %d, result mismatch\nhave: %v\nwant: %v\n", i, string(have), want) + } + } +} From 0d4cdb3dbed9c0183110db65270bd5725bf392ec Mon Sep 17 00:00:00 2001 From: Karl Bartel Date: Thu, 23 May 2024 10:41:51 +0200 Subject: [PATCH 279/571] internal/ethapi: fix typos (#29784) Fix typos in api.go --- internal/ethapi/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index d308cead627f..8866a5b8706d 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -966,7 +966,7 @@ func (s *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc. // of a message call. // Note, state and stateDiff can't be specified at the same time. If state is // set, message execution will only use the data in the given state. Otherwise -// if statDiff is set, all diff will be applied first and then execute the call +// if stateDiff is set, all diff will be applied first and then execute the call // message. type OverrideAccount struct { Nonce *hexutil.Uint64 `json:"nonce"` @@ -1203,7 +1203,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr return 0, err } call := args.ToMessage(header.BaseFee) - // Run the gas estimation andwrap any revertals into a custom return + // Run the gas estimation and wrap any revertals into a custom return estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) if err != nil { if len(revert) > 0 { From fa581766f5b14f6fad9f2c7a4aa7e7ac826a8de2 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 23 May 2024 10:55:54 +0200 Subject: [PATCH 280/571] eth/tracers: fix json logger for evm blocktest (#29795) --- eth/tracers/api.go | 8 +++++-- eth/tracers/logger/logger_json.go | 37 ++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 30648c475367..51b55ffdbb1b 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -804,9 +804,13 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) statedb.SetTxContext(tx.Hash(), i) - vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.From) + if vmConf.Tracer.OnTxStart != nil { + vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.From) + } vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) - vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) + if vmConf.Tracer.OnTxEnd != nil { + vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) + } if writer != nil { writer.Flush() } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index d66b8c4b8ad0..797f7ac65821 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -58,6 +58,7 @@ type jsonLogger struct { encoder *json.Encoder cfg *Config env *tracing.VMContext + hooks *tracing.Hooks } // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects @@ -67,12 +68,14 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { if l.cfg == nil { l.cfg = &Config{} } - return &tracing.Hooks{ - OnTxStart: l.OnTxStart, - OnExit: l.OnExit, - OnOpcode: l.OnOpcode, - OnFault: l.OnFault, + l.hooks = &tracing.Hooks{ + OnTxStart: l.OnTxStart, + OnSystemCallStart: l.onSystemCallStart, + OnExit: l.OnEnd, + OnOpcode: l.OnOpcode, + OnFault: l.OnFault, } + return l.hooks } // NewJSONLoggerWithCallFrames creates a new EVM tracer that prints execution steps as JSON objects @@ -82,13 +85,15 @@ func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) *tracing.Hooks { if l.cfg == nil { l.cfg = &Config{} } - return &tracing.Hooks{ - OnTxStart: l.OnTxStart, - OnEnter: l.OnEnter, - OnExit: l.OnExit, - OnOpcode: l.OnOpcode, - OnFault: l.OnFault, + l.hooks = &tracing.Hooks{ + OnTxStart: l.OnTxStart, + OnSystemCallStart: l.onSystemCallStart, + OnEnter: l.OnEnter, + OnExit: l.OnExit, + OnOpcode: l.OnOpcode, + OnFault: l.OnFault, } + return l.hooks } func (l *jsonLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { @@ -122,6 +127,16 @@ func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracin l.encoder.Encode(log) } +func (l *jsonLogger) onSystemCallStart() { + // Process no events while in system call. + hooks := *l.hooks + *l.hooks = tracing.Hooks{ + OnSystemCallEnd: func() { + *l.hooks = hooks + }, + } +} + // OnEnter is not enabled by default. func (l *jsonLogger) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { frame := callFrame{ From b779e469daf17d02ade66667c7adbfb8f51083a1 Mon Sep 17 00:00:00 2001 From: Mobin Mohanan <47410557+tr1sm0s1n@users.noreply.github.com> Date: Thu, 23 May 2024 15:26:32 +0530 Subject: [PATCH 281/571] Makefile: add fmt, update help (#29777) --- Makefile | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 278ae63120f6..857cb8c97899 100644 --- a/Makefile +++ b/Makefile @@ -2,31 +2,35 @@ # with Go source code. If you know what GOPATH is then you probably # don't need to bother with make. -.PHONY: geth all test lint clean devtools help +.PHONY: geth all test lint fmt clean devtools help GOBIN = ./build/bin GO ?= latest GORUN = go run -#? geth: Build geth +#? geth: Build geth. geth: $(GORUN) build/ci.go install ./cmd/geth @echo "Done building." @echo "Run \"$(GOBIN)/geth\" to launch geth." -#? all: Build all packages and executables +#? all: Build all packages and executables. all: $(GORUN) build/ci.go install -#? test: Run the tests +#? test: Run the tests. test: all $(GORUN) build/ci.go test -#? lint: Run certain pre-selected linters +#? lint: Run certain pre-selected linters. lint: ## Run linters. $(GORUN) build/ci.go lint -#? clean: Clean go cache, built executables, and the auto generated folder +#? fmt: Ensure consistent code formatting. +fmt: + gofmt -s -w $(shell find . -name "*.go") + +#? clean: Clean go cache, built executables, and the auto generated folder. clean: go clean -cache rm -fr build/_workspace/pkg/ $(GOBIN)/* @@ -34,7 +38,7 @@ clean: # The devtools target installs tools required for 'go generate'. # You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'. -#? devtools: Install recommended developer tools +#? devtools: Install recommended developer tools. devtools: env GOBIN= go install golang.org/x/tools/cmd/stringer@latest env GOBIN= go install github.com/fjl/gencodec@latest @@ -45,5 +49,9 @@ devtools: #? help: Get more info on make commands. help: Makefile - @echo " Choose a command run in go-ethereum:" + @echo '' + @echo 'Usage:' + @echo ' make [target]' + @echo '' + @echo 'Targets:' @sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /' From 70bee977d6b6099972b2c240f182b61829cf182f Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Thu, 23 May 2024 18:34:34 +0800 Subject: [PATCH 282/571] metrics: fix out of range error message (#29821) --- metrics/sample_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metrics/sample_test.go b/metrics/sample_test.go index 9835ec1c3003..92806c65b2c7 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -114,7 +114,7 @@ func TestExpDecaySample(t *testing.T) { } for _, v := range values { if v > int64(tc.updates) || v < 0 { - t.Errorf("out of range [0, %d): %v", tc.updates, v) + t.Errorf("out of range [0, %d]: %v", tc.updates, v) } } } @@ -195,7 +195,7 @@ func TestUniformSample(t *testing.T) { } for _, v := range values { if v > 1000 || v < 0 { - t.Errorf("out of range [0, 100): %v\n", v) + t.Errorf("out of range [0, 1000]: %v\n", v) } } } From 6a9158bb1bea9feda96489f1d02e15f0a9f93b82 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 23 May 2024 14:26:09 +0200 Subject: [PATCH 283/571] p2p/discover: improved node revalidation (#29572) Node discovery periodically revalidates the nodes in its table by sending PING, checking if they are still alive. I recently noticed some issues with the implementation of this process, which can cause strange results such as nodes dropping unexpectedly, certain nodes not getting revalidated often enough, and bad results being returned to incoming FINDNODE queries. In this change, the revalidation process is improved with the following logic: - We maintain two 'revalidation lists' containing the table nodes, named 'fast' and 'slow'. - The process chooses random nodes from each list on a randomized interval, the interval being faster for the 'fast' list, and performs revalidation for the chosen node. - Whenever a node is newly inserted into the table, it goes into the 'fast' list. Once validation passes, it transfers to the 'slow' list. If a request fails, or the node changes endpoint, it transfers back into 'fast'. - livenessChecks is incremented by one for successful checks. Unlike the old implementation, we will not drop the node on the first failing check. We instead quickly decay the livenessChecks give it another chance. - Order of nodes in bucket doesn't matter anymore. I am also adding a debug API endpoint to dump the node table content. Co-authored-by: Martin HS --- cmd/devp2p/discv4cmd.go | 57 +++ internal/testlog/testlog.go | 2 +- node/api.go | 17 + p2p/discover/common.go | 47 ++- p2p/discover/lookup.go | 29 +- p2p/discover/node.go | 20 +- p2p/discover/table.go | 707 +++++++++++++++----------------- p2p/discover/table_reval.go | 223 ++++++++++ p2p/discover/table_test.go | 181 ++++---- p2p/discover/table_util_test.go | 118 +++++- p2p/discover/v4_udp.go | 10 +- p2p/discover/v4_udp_test.go | 2 +- p2p/discover/v5_udp.go | 4 +- p2p/discover/v5_udp_test.go | 2 +- p2p/server.go | 36 +- 15 files changed, 931 insertions(+), 524 deletions(-) create mode 100644 p2p/discover/table_reval.go diff --git a/cmd/devp2p/discv4cmd.go b/cmd/devp2p/discv4cmd.go index 45bcdcd3674b..3b5400ca3a83 100644 --- a/cmd/devp2p/discv4cmd.go +++ b/cmd/devp2p/discv4cmd.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "net" + "net/http" "strconv" "strings" "time" @@ -28,9 +29,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" "github.com/urfave/cli/v2" ) @@ -45,6 +48,7 @@ var ( discv4ResolveJSONCommand, discv4CrawlCommand, discv4TestCommand, + discv4ListenCommand, }, } discv4PingCommand = &cli.Command{ @@ -75,6 +79,14 @@ var ( Flags: discoveryNodeFlags, ArgsUsage: "", } + discv4ListenCommand = &cli.Command{ + Name: "listen", + Usage: "Runs a discovery node", + Action: discv4Listen, + Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{ + httpAddrFlag, + }), + } discv4CrawlCommand = &cli.Command{ Name: "crawl", Usage: "Updates a nodes.json file with random nodes found in the DHT", @@ -131,6 +143,10 @@ var ( Usage: "Enode of the remote node under test", EnvVars: []string{"REMOTE_ENODE"}, } + httpAddrFlag = &cli.StringFlag{ + Name: "rpc", + Usage: "HTTP server listening address", + } ) var discoveryNodeFlags = []cli.Flag{ @@ -154,6 +170,27 @@ func discv4Ping(ctx *cli.Context) error { return nil } +func discv4Listen(ctx *cli.Context) error { + disc, _ := startV4(ctx) + defer disc.Close() + + fmt.Println(disc.Self()) + + httpAddr := ctx.String(httpAddrFlag.Name) + if httpAddr == "" { + // Non-HTTP mode. + select {} + } + + api := &discv4API{disc} + log.Info("Starting RPC API server", "addr", httpAddr) + srv := rpc.NewServer() + srv.RegisterName("discv4", api) + http.DefaultServeMux.Handle("/", srv) + httpsrv := http.Server{Addr: httpAddr, Handler: http.DefaultServeMux} + return httpsrv.ListenAndServe() +} + func discv4RequestRecord(ctx *cli.Context) error { n := getNodeArg(ctx) disc, _ := startV4(ctx) @@ -362,3 +399,23 @@ func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) { } return nodes, nil } + +type discv4API struct { + host *discover.UDPv4 +} + +func (api *discv4API) LookupRandom(n int) (ns []*enode.Node) { + it := api.host.RandomNodes() + for len(ns) < n && it.Next() { + ns = append(ns, it.Node()) + } + return ns +} + +func (api *discv4API) Buckets() [][]discover.BucketNode { + return api.host.TableBuckets() +} + +func (api *discv4API) Self() *enode.Node { + return api.host.Self() +} diff --git a/internal/testlog/testlog.go b/internal/testlog/testlog.go index 3740dd1f242c..ad61af9eac20 100644 --- a/internal/testlog/testlog.go +++ b/internal/testlog/testlog.go @@ -58,7 +58,7 @@ func (h *bufHandler) Handle(_ context.Context, r slog.Record) error { } func (h *bufHandler) Enabled(_ context.Context, lvl slog.Level) bool { - return lvl <= h.level + return lvl >= h.level } func (h *bufHandler) WithAttrs(attrs []slog.Attr) slog.Handler { diff --git a/node/api.go b/node/api.go index a71ae6aa2954..33dfb3a1cc4d 100644 --- a/node/api.go +++ b/node/api.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" ) @@ -39,6 +40,9 @@ func (n *Node) apis() []rpc.API { }, { Namespace: "debug", Service: debug.Handler, + }, { + Namespace: "debug", + Service: &p2pDebugAPI{n}, }, { Namespace: "web3", Service: &web3API{n}, @@ -333,3 +337,16 @@ func (s *web3API) ClientVersion() string { func (s *web3API) Sha3(input hexutil.Bytes) hexutil.Bytes { return crypto.Keccak256(input) } + +// p2pDebugAPI provides access to p2p internals for debugging. +type p2pDebugAPI struct { + stack *Node +} + +func (s *p2pDebugAPI) DiscoveryV4Table() [][]discover.BucketNode { + disc := s.stack.server.DiscoveryV4() + if disc != nil { + return disc.TableBuckets() + } + return nil +} diff --git a/p2p/discover/common.go b/p2p/discover/common.go index 1f763904bb1f..bebea8cc3846 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -18,7 +18,11 @@ package discover import ( "crypto/ecdsa" + crand "crypto/rand" + "encoding/binary" + "math/rand" "net" + "sync" "time" "github.com/ethereum/go-ethereum/common/mclock" @@ -62,7 +66,7 @@ type Config struct { func (cfg Config) withDefaults() Config { // Node table configuration: if cfg.PingInterval == 0 { - cfg.PingInterval = 10 * time.Second + cfg.PingInterval = 3 * time.Second } if cfg.RefreshInterval == 0 { cfg.RefreshInterval = 30 * time.Minute @@ -92,3 +96,44 @@ type ReadPacket struct { Data []byte Addr *net.UDPAddr } + +type randomSource interface { + Intn(int) int + Int63n(int64) int64 + Shuffle(int, func(int, int)) +} + +// reseedingRandom is a random number generator that tracks when it was last re-seeded. +type reseedingRandom struct { + mu sync.Mutex + cur *rand.Rand +} + +func (r *reseedingRandom) seed() { + var b [8]byte + crand.Read(b[:]) + seed := binary.BigEndian.Uint64(b[:]) + new := rand.New(rand.NewSource(int64(seed))) + + r.mu.Lock() + r.cur = new + r.mu.Unlock() +} + +func (r *reseedingRandom) Intn(n int) int { + r.mu.Lock() + defer r.mu.Unlock() + return r.cur.Intn(n) +} + +func (r *reseedingRandom) Int63n(n int64) int64 { + r.mu.Lock() + defer r.mu.Unlock() + return r.cur.Int63n(n) +} + +func (r *reseedingRandom) Shuffle(n int, swap func(i, j int)) { + r.mu.Lock() + defer r.mu.Unlock() + r.cur.Shuffle(n, swap) +} diff --git a/p2p/discover/lookup.go b/p2p/discover/lookup.go index b8d97b44e1cc..5c3d90d6c90f 100644 --- a/p2p/discover/lookup.go +++ b/p2p/discover/lookup.go @@ -140,32 +140,13 @@ func (it *lookup) slowdown() { } func (it *lookup) query(n *node, reply chan<- []*node) { - fails := it.tab.db.FindFails(n.ID(), n.IP()) r, err := it.queryfunc(n) - if errors.Is(err, errClosed) { - // Avoid recording failures on shutdown. - reply <- nil - return - } else if len(r) == 0 { - fails++ - it.tab.db.UpdateFindFails(n.ID(), n.IP(), fails) - // Remove the node from the local table if it fails to return anything useful too - // many times, but only if there are enough other nodes in the bucket. - dropped := false - if fails >= maxFindnodeFailures && it.tab.bucketLen(n.ID()) >= bucketSize/2 { - dropped = true - it.tab.delete(n) + if !errors.Is(err, errClosed) { // avoid recording failures on shutdown. + success := len(r) > 0 + it.tab.trackRequest(n, success, r) + if err != nil { + it.tab.log.Trace("FINDNODE failed", "id", n.ID(), "err", err) } - it.tab.log.Trace("FINDNODE failed", "id", n.ID(), "failcount", fails, "dropped", dropped, "err", err) - } else if fails > 0 { - // Reset failure counter because it counts _consecutive_ failures. - it.tab.db.UpdateFindFails(n.ID(), n.IP(), 0) - } - - // Grab as many nodes as possible. Some of them might not be alive anymore, but we'll - // just remove those again during revalidation. - for _, n := range r { - it.tab.addSeenNode(n) } reply <- r } diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 9ffe101ccff8..47df09e883da 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -29,12 +29,22 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" ) +type BucketNode struct { + Node *enode.Node `json:"node"` + AddedToTable time.Time `json:"addedToTable"` + AddedToBucket time.Time `json:"addedToBucket"` + Checks int `json:"checks"` + Live bool `json:"live"` +} + // node represents a host on the network. // The fields of Node may not be modified. type node struct { - enode.Node - addedAt time.Time // time when the node was added to the table - livenessChecks uint // how often liveness was checked + *enode.Node + addedToTable time.Time // first time node was added to bucket or replacement list + addedToBucket time.Time // time it was added in the actual bucket + livenessChecks uint // how often liveness was checked + isValidatedLive bool // true if existence of node is considered validated right now } type encPubkey [64]byte @@ -65,7 +75,7 @@ func (e encPubkey) id() enode.ID { } func wrapNode(n *enode.Node) *node { - return &node{Node: *n} + return &node{Node: n} } func wrapNodes(ns []*enode.Node) []*node { @@ -77,7 +87,7 @@ func wrapNodes(ns []*enode.Node) []*node { } func unwrapNode(n *node) *enode.Node { - return &n.Node + return n.Node } func unwrapNodes(ns []*node) []*enode.Node { diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 2b7a28708b8d..74c0e930e4af 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -24,16 +24,15 @@ package discover import ( "context" - crand "crypto/rand" - "encoding/binary" "fmt" - mrand "math/rand" "net" + "slices" "sort" "sync" "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p/enode" @@ -55,21 +54,21 @@ const ( bucketIPLimit, bucketSubnet = 2, 24 // at most 2 addresses from the same /24 tableIPLimit, tableSubnet = 10, 24 - copyNodesInterval = 30 * time.Second - seedMinTableTime = 5 * time.Minute - seedCount = 30 - seedMaxAge = 5 * 24 * time.Hour + seedMinTableTime = 5 * time.Minute + seedCount = 30 + seedMaxAge = 5 * 24 * time.Hour ) // Table is the 'node table', a Kademlia-like index of neighbor nodes. The table keeps // itself up-to-date by verifying the liveness of neighbors and requesting their node // records when announcements of a new record version are received. type Table struct { - mutex sync.Mutex // protects buckets, bucket content, nursery, rand - buckets [nBuckets]*bucket // index of known nodes by distance - nursery []*node // bootstrap nodes - rand *mrand.Rand // source of randomness, periodically reseeded - ips netutil.DistinctNetSet + mutex sync.Mutex // protects buckets, bucket content, nursery, rand + buckets [nBuckets]*bucket // index of known nodes by distance + nursery []*node // bootstrap nodes + rand reseedingRandom // source of randomness, periodically reseeded + ips netutil.DistinctNetSet + revalidation tableRevalidation db *enode.DB // database of known nodes net transport @@ -77,10 +76,14 @@ type Table struct { log log.Logger // loop channels - refreshReq chan chan struct{} - initDone chan struct{} - closeReq chan struct{} - closed chan struct{} + refreshReq chan chan struct{} + revalResponseCh chan revalidationResponse + addNodeCh chan addNodeOp + addNodeHandled chan bool + trackRequestCh chan trackRequestOp + initDone chan struct{} + closeReq chan struct{} + closed chan struct{} nodeAddedHook func(*bucket, *node) nodeRemovedHook func(*bucket, *node) @@ -104,22 +107,33 @@ type bucket struct { index int } +type addNodeOp struct { + node *node + isInbound bool +} + +type trackRequestOp struct { + node *node + foundNodes []*node + success bool +} + func newTable(t transport, db *enode.DB, cfg Config) (*Table, error) { cfg = cfg.withDefaults() tab := &Table{ - net: t, - db: db, - cfg: cfg, - log: cfg.Log, - refreshReq: make(chan chan struct{}), - initDone: make(chan struct{}), - closeReq: make(chan struct{}), - closed: make(chan struct{}), - rand: mrand.New(mrand.NewSource(0)), - ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit}, - } - if err := tab.setFallbackNodes(cfg.Bootnodes); err != nil { - return nil, err + net: t, + db: db, + cfg: cfg, + log: cfg.Log, + refreshReq: make(chan chan struct{}), + revalResponseCh: make(chan revalidationResponse), + addNodeCh: make(chan addNodeOp), + addNodeHandled: make(chan bool), + trackRequestCh: make(chan trackRequestOp), + initDone: make(chan struct{}), + closeReq: make(chan struct{}), + closed: make(chan struct{}), + ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit}, } for i := range tab.buckets { tab.buckets[i] = &bucket{ @@ -127,41 +141,34 @@ func newTable(t transport, db *enode.DB, cfg Config) (*Table, error) { ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit}, } } - tab.seedRand() - tab.loadSeedNodes() - - return tab, nil -} + tab.rand.seed() + tab.revalidation.init(&cfg) -func newMeteredTable(t transport, db *enode.DB, cfg Config) (*Table, error) { - tab, err := newTable(t, db, cfg) - if err != nil { + // initial table content + if err := tab.setFallbackNodes(cfg.Bootnodes); err != nil { return nil, err } - if metrics.Enabled { - tab.nodeAddedHook = func(b *bucket, n *node) { - bucketsCounter[b.index].Inc(1) - } - tab.nodeRemovedHook = func(b *bucket, n *node) { - bucketsCounter[b.index].Dec(1) - } - } + tab.loadSeedNodes() + return tab, nil } // Nodes returns all nodes contained in the table. -func (tab *Table) Nodes() []*enode.Node { - if !tab.isInitDone() { - return nil - } - +func (tab *Table) Nodes() [][]BucketNode { tab.mutex.Lock() defer tab.mutex.Unlock() - var nodes []*enode.Node - for _, b := range &tab.buckets { - for _, n := range b.entries { - nodes = append(nodes, unwrapNode(n)) + nodes := make([][]BucketNode, len(tab.buckets)) + for i, b := range &tab.buckets { + nodes[i] = make([]BucketNode, len(b.entries)) + for j, n := range b.entries { + nodes[i][j] = BucketNode{ + Node: n.Node, + Checks: int(n.livenessChecks), + Live: n.isValidatedLive, + AddedToTable: n.addedToTable, + AddedToBucket: n.addedToBucket, + } } } return nodes @@ -171,15 +178,6 @@ func (tab *Table) self() *enode.Node { return tab.net.Self() } -func (tab *Table) seedRand() { - var b [8]byte - crand.Read(b[:]) - - tab.mutex.Lock() - tab.rand.Seed(int64(binary.BigEndian.Uint64(b[:]))) - tab.mutex.Unlock() -} - // getNode returns the node with the given ID or nil if it isn't in the table. func (tab *Table) getNode(id enode.ID) *enode.Node { tab.mutex.Lock() @@ -239,52 +237,173 @@ func (tab *Table) refresh() <-chan struct{} { return done } -// loop schedules runs of doRefresh, doRevalidate and copyLiveNodes. +// findnodeByID returns the n nodes in the table that are closest to the given id. +// This is used by the FINDNODE/v4 handler. +// +// The preferLive parameter says whether the caller wants liveness-checked results. If +// preferLive is true and the table contains any verified nodes, the result will not +// contain unverified nodes. However, if there are no verified nodes at all, the result +// will contain unverified nodes. +func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) *nodesByDistance { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + // Scan all buckets. There might be a better way to do this, but there aren't that many + // buckets, so this solution should be fine. The worst-case complexity of this loop + // is O(tab.len() * nresults). + nodes := &nodesByDistance{target: target} + liveNodes := &nodesByDistance{target: target} + for _, b := range &tab.buckets { + for _, n := range b.entries { + nodes.push(n, nresults) + if preferLive && n.isValidatedLive { + liveNodes.push(n, nresults) + } + } + } + + if preferLive && len(liveNodes.entries) > 0 { + return liveNodes + } + return nodes +} + +// appendLiveNodes adds nodes at the given distance to the result slice. +// This is used by the FINDNODE/v5 handler. +func (tab *Table) appendLiveNodes(dist uint, result []*enode.Node) []*enode.Node { + if dist > 256 { + return result + } + if dist == 0 { + return append(result, tab.self()) + } + + tab.mutex.Lock() + for _, n := range tab.bucketAtDistance(int(dist)).entries { + if n.isValidatedLive { + result = append(result, n.Node) + } + } + tab.mutex.Unlock() + + // Shuffle result to avoid always returning same nodes in FINDNODE/v5. + tab.rand.Shuffle(len(result), func(i, j int) { + result[i], result[j] = result[j], result[i] + }) + return result +} + +// len returns the number of nodes in the table. +func (tab *Table) len() (n int) { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + for _, b := range &tab.buckets { + n += len(b.entries) + } + return n +} + +// addFoundNode adds a node which may not be live. If the bucket has space available, +// adding the node succeeds immediately. Otherwise, the node is added to the replacements +// list. +// +// The caller must not hold tab.mutex. +func (tab *Table) addFoundNode(n *node) bool { + op := addNodeOp{node: n, isInbound: false} + select { + case tab.addNodeCh <- op: + return <-tab.addNodeHandled + case <-tab.closeReq: + return false + } +} + +// addInboundNode adds a node from an inbound contact. If the bucket has no space, the +// node is added to the replacements list. +// +// There is an additional safety measure: if the table is still initializing the node is +// not added. This prevents an attack where the table could be filled by just sending ping +// repeatedly. +// +// The caller must not hold tab.mutex. +func (tab *Table) addInboundNode(n *node) bool { + op := addNodeOp{node: n, isInbound: true} + select { + case tab.addNodeCh <- op: + return <-tab.addNodeHandled + case <-tab.closeReq: + return false + } +} + +func (tab *Table) trackRequest(n *node, success bool, foundNodes []*node) { + op := trackRequestOp{n, foundNodes, success} + select { + case tab.trackRequestCh <- op: + case <-tab.closeReq: + } +} + +// loop is the main loop of Table. func (tab *Table) loop() { var ( - revalidate = time.NewTimer(tab.nextRevalidateTime()) - refresh = time.NewTimer(tab.nextRefreshTime()) - copyNodes = time.NewTicker(copyNodesInterval) - refreshDone = make(chan struct{}) // where doRefresh reports completion - revalidateDone chan struct{} // where doRevalidate reports completion - waiting = []chan struct{}{tab.initDone} // holds waiting callers while doRefresh runs + refresh = time.NewTimer(tab.nextRefreshTime()) + refreshDone = make(chan struct{}) // where doRefresh reports completion + waiting = []chan struct{}{tab.initDone} // holds waiting callers while doRefresh runs + revalTimer = mclock.NewAlarm(tab.cfg.Clock) + reseedRandTimer = time.NewTicker(10 * time.Minute) ) defer refresh.Stop() - defer revalidate.Stop() - defer copyNodes.Stop() + defer revalTimer.Stop() + defer reseedRandTimer.Stop() // Start initial refresh. go tab.doRefresh(refreshDone) loop: for { + nextTime := tab.revalidation.run(tab, tab.cfg.Clock.Now()) + revalTimer.Schedule(nextTime) + select { + case <-reseedRandTimer.C: + tab.rand.seed() + + case <-revalTimer.C(): + + case r := <-tab.revalResponseCh: + tab.revalidation.handleResponse(tab, r) + + case op := <-tab.addNodeCh: + tab.mutex.Lock() + ok := tab.handleAddNode(op) + tab.mutex.Unlock() + tab.addNodeHandled <- ok + + case op := <-tab.trackRequestCh: + tab.handleTrackRequest(op) + case <-refresh.C: - tab.seedRand() if refreshDone == nil { refreshDone = make(chan struct{}) go tab.doRefresh(refreshDone) } + case req := <-tab.refreshReq: waiting = append(waiting, req) if refreshDone == nil { refreshDone = make(chan struct{}) go tab.doRefresh(refreshDone) } + case <-refreshDone: for _, ch := range waiting { close(ch) } waiting, refreshDone = nil, nil refresh.Reset(tab.nextRefreshTime()) - case <-revalidate.C: - revalidateDone = make(chan struct{}) - go tab.doRevalidate(revalidateDone) - case <-revalidateDone: - revalidate.Reset(tab.nextRevalidateTime()) - revalidateDone = nil - case <-copyNodes.C: - go tab.copyLiveNodes() + case <-tab.closeReq: break loop } @@ -296,9 +415,6 @@ loop: for _, ch := range waiting { close(ch) } - if revalidateDone != nil { - <-revalidateDone - } close(tab.closed) } @@ -335,169 +451,15 @@ func (tab *Table) loadSeedNodes() { age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age) } - tab.addSeenNode(seed) + tab.handleAddNode(addNodeOp{node: seed, isInbound: false}) } } -// doRevalidate checks that the last node in a random bucket is still live and replaces or -// deletes the node if it isn't. -func (tab *Table) doRevalidate(done chan<- struct{}) { - defer func() { done <- struct{}{} }() - - last, bi := tab.nodeToRevalidate() - if last == nil { - // No non-empty bucket found. - return - } - - // Ping the selected node and wait for a pong. - remoteSeq, err := tab.net.ping(unwrapNode(last)) - - // Also fetch record if the node replied and returned a higher sequence number. - if last.Seq() < remoteSeq { - 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 { - last = &node{Node: *n, addedAt: last.addedAt, livenessChecks: last.livenessChecks} - } - } - - tab.mutex.Lock() - defer tab.mutex.Unlock() - b := tab.buckets[bi] - if err == nil { - // The node responded, move it to the front. - last.livenessChecks++ - tab.log.Debug("Revalidated node", "b", bi, "id", last.ID(), "checks", last.livenessChecks) - tab.bumpInBucket(b, last) - return - } - // No reply received, pick a replacement or delete the node if there aren't - // any replacements. - if r := tab.replace(b, last); r != nil { - tab.log.Debug("Replaced dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks, "r", r.ID(), "rip", r.IP()) - } else { - tab.log.Debug("Removed dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks) - } -} - -// nodeToRevalidate returns the last node in a random, non-empty bucket. -func (tab *Table) nodeToRevalidate() (n *node, bi int) { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - for _, bi = range tab.rand.Perm(len(tab.buckets)) { - b := tab.buckets[bi] - if len(b.entries) > 0 { - last := b.entries[len(b.entries)-1] - return last, bi - } - } - return nil, 0 -} - -func (tab *Table) nextRevalidateTime() time.Duration { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - return time.Duration(tab.rand.Int63n(int64(tab.cfg.PingInterval))) -} - func (tab *Table) nextRefreshTime() time.Duration { - tab.mutex.Lock() - defer tab.mutex.Unlock() - half := tab.cfg.RefreshInterval / 2 return half + time.Duration(tab.rand.Int63n(int64(half))) } -// copyLiveNodes adds nodes from the table to the database if they have been in the table -// longer than seedMinTableTime. -func (tab *Table) copyLiveNodes() { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - now := time.Now() - for _, b := range &tab.buckets { - for _, n := range b.entries { - if n.livenessChecks > 0 && now.Sub(n.addedAt) >= seedMinTableTime { - tab.db.UpdateNode(unwrapNode(n)) - } - } - } -} - -// findnodeByID returns the n nodes in the table that are closest to the given id. -// This is used by the FINDNODE/v4 handler. -// -// The preferLive parameter says whether the caller wants liveness-checked results. If -// preferLive is true and the table contains any verified nodes, the result will not -// contain unverified nodes. However, if there are no verified nodes at all, the result -// will contain unverified nodes. -func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) *nodesByDistance { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - // Scan all buckets. There might be a better way to do this, but there aren't that many - // buckets, so this solution should be fine. The worst-case complexity of this loop - // is O(tab.len() * nresults). - nodes := &nodesByDistance{target: target} - liveNodes := &nodesByDistance{target: target} - for _, b := range &tab.buckets { - for _, n := range b.entries { - nodes.push(n, nresults) - if preferLive && n.livenessChecks > 0 { - liveNodes.push(n, nresults) - } - } - } - - if preferLive && len(liveNodes.entries) > 0 { - return liveNodes - } - return nodes -} - -// appendLiveNodes adds nodes at the given distance to the result slice. -func (tab *Table) appendLiveNodes(dist uint, result []*enode.Node) []*enode.Node { - if dist > 256 { - return result - } - if dist == 0 { - return append(result, tab.self()) - } - - tab.mutex.Lock() - defer tab.mutex.Unlock() - for _, n := range tab.bucketAtDistance(int(dist)).entries { - if n.livenessChecks >= 1 { - node := n.Node // avoid handing out pointer to struct field - result = append(result, &node) - } - } - return result -} - -// len returns the number of nodes in the table. -func (tab *Table) len() (n int) { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - for _, b := range &tab.buckets { - n += len(b.entries) - } - return n -} - -// bucketLen returns the number of nodes in the bucket for the given ID. -func (tab *Table) bucketLen(id enode.ID) int { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - return len(tab.bucket(id).entries) -} - // bucket returns the bucket for the given node ID hash. func (tab *Table) bucket(id enode.ID) *bucket { d := enode.LogDist(tab.self().ID(), id) @@ -511,95 +473,6 @@ func (tab *Table) bucketAtDistance(d int) *bucket { return tab.buckets[d-bucketMinDistance-1] } -// addSeenNode adds a node which may or may not be live to the end of a bucket. If the -// bucket has space available, adding the node succeeds immediately. Otherwise, the node is -// added to the replacements list. -// -// The caller must not hold tab.mutex. -func (tab *Table) addSeenNode(n *node) { - if n.ID() == tab.self().ID() { - return - } - - tab.mutex.Lock() - defer tab.mutex.Unlock() - b := tab.bucket(n.ID()) - if contains(b.entries, n.ID()) { - // Already in bucket, don't add. - return - } - if len(b.entries) >= bucketSize { - // Bucket full, maybe add as replacement. - tab.addReplacement(b, n) - return - } - if !tab.addIP(b, n.IP()) { - // Can't add: IP limit reached. - return - } - - // Add to end of bucket: - b.entries = append(b.entries, n) - b.replacements = deleteNode(b.replacements, n) - n.addedAt = time.Now() - - if tab.nodeAddedHook != nil { - tab.nodeAddedHook(b, n) - } -} - -// addVerifiedNode adds a node whose existence has been verified recently to the front of a -// bucket. If the node is already in the bucket, it is moved to the front. If the bucket -// has no space, the node is added to the replacements list. -// -// There is an additional safety measure: if the table is still initializing the node -// is not added. This prevents an attack where the table could be filled by just sending -// ping repeatedly. -// -// The caller must not hold tab.mutex. -func (tab *Table) addVerifiedNode(n *node) { - if !tab.isInitDone() { - return - } - if n.ID() == tab.self().ID() { - return - } - - tab.mutex.Lock() - defer tab.mutex.Unlock() - b := tab.bucket(n.ID()) - if tab.bumpInBucket(b, n) { - // Already in bucket, moved to front. - return - } - if len(b.entries) >= bucketSize { - // Bucket full, maybe add as replacement. - tab.addReplacement(b, n) - return - } - if !tab.addIP(b, n.IP()) { - // Can't add: IP limit reached. - return - } - - // Add to front of bucket. - b.entries, _ = pushNode(b.entries, n, bucketSize) - b.replacements = deleteNode(b.replacements, n) - n.addedAt = time.Now() - - if tab.nodeAddedHook != nil { - tab.nodeAddedHook(b, n) - } -} - -// delete removes an entry from the node table. It is used to evacuate dead nodes. -func (tab *Table) delete(node *node) { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - tab.deleteInBucket(tab.bucket(node.ID()), node) -} - func (tab *Table) addIP(b *bucket, ip net.IP) bool { if len(ip) == 0 { return false // Nodes without IP cannot be added. @@ -627,15 +500,51 @@ func (tab *Table) removeIP(b *bucket, ip net.IP) { b.ips.Remove(ip) } +// handleAddNode adds the node in the request to the table, if there is space. +// The caller must hold tab.mutex. +func (tab *Table) handleAddNode(req addNodeOp) bool { + if req.node.ID() == tab.self().ID() { + return false + } + // For nodes from inbound contact, there is an additional safety measure: if the table + // is still initializing the node is not added. + if req.isInbound && !tab.isInitDone() { + return false + } + + b := tab.bucket(req.node.ID()) + if tab.bumpInBucket(b, req.node.Node) { + // Already in bucket, update record. + return false + } + if len(b.entries) >= bucketSize { + // Bucket full, maybe add as replacement. + tab.addReplacement(b, req.node) + return false + } + if !tab.addIP(b, req.node.IP()) { + // Can't add: IP limit reached. + return false + } + + // Add to bucket. + b.entries = append(b.entries, req.node) + b.replacements = deleteNode(b.replacements, req.node) + tab.nodeAdded(b, req.node) + return true +} + +// addReplacement adds n to the replacement cache of bucket b. func (tab *Table) addReplacement(b *bucket, n *node) { - for _, e := range b.replacements { - if e.ID() == n.ID() { - return // already in list - } + if contains(b.replacements, n.ID()) { + // TODO: update ENR + return } if !tab.addIP(b, n.IP()) { return } + + n.addedToTable = time.Now() var removed *node b.replacements, removed = pushNode(b.replacements, n, maxReplacements) if removed != nil { @@ -643,59 +552,107 @@ func (tab *Table) addReplacement(b *bucket, n *node) { } } -// replace removes n from the replacement list and replaces 'last' with it if it is the -// last entry in the bucket. If 'last' isn't the last entry, it has either been replaced -// with someone else or became active. -func (tab *Table) replace(b *bucket, last *node) *node { - if len(b.entries) == 0 || b.entries[len(b.entries)-1].ID() != last.ID() { - // Entry has moved, don't replace it. +func (tab *Table) nodeAdded(b *bucket, n *node) { + if n.addedToTable == (time.Time{}) { + n.addedToTable = time.Now() + } + n.addedToBucket = time.Now() + tab.revalidation.nodeAdded(tab, n) + if tab.nodeAddedHook != nil { + tab.nodeAddedHook(b, n) + } + if metrics.Enabled { + bucketsCounter[b.index].Inc(1) + } +} + +func (tab *Table) nodeRemoved(b *bucket, n *node) { + tab.revalidation.nodeRemoved(n) + if tab.nodeRemovedHook != nil { + tab.nodeRemovedHook(b, n) + } + if metrics.Enabled { + bucketsCounter[b.index].Dec(1) + } +} + +// deleteInBucket removes node n from the table. +// If there are replacement nodes in the bucket, the node is replaced. +func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *node { + index := slices.IndexFunc(b.entries, func(e *node) bool { return e.ID() == id }) + if index == -1 { + // Entry has been removed already. return nil } - // Still the last entry. + + // Remove the node. + n := b.entries[index] + b.entries = slices.Delete(b.entries, index, index+1) + tab.removeIP(b, n.IP()) + tab.nodeRemoved(b, n) + + // Add replacement. if len(b.replacements) == 0 { - tab.deleteInBucket(b, last) + tab.log.Debug("Removed dead node", "b", b.index, "id", n.ID(), "ip", n.IP()) return nil } - r := b.replacements[tab.rand.Intn(len(b.replacements))] - b.replacements = deleteNode(b.replacements, r) - b.entries[len(b.entries)-1] = r - tab.removeIP(b, last.IP()) - return r -} - -// bumpInBucket moves the given node to the front of the bucket entry list -// if it is contained in that list. -func (tab *Table) bumpInBucket(b *bucket, n *node) bool { - for i := range b.entries { - if b.entries[i].ID() == n.ID() { - if !n.IP().Equal(b.entries[i].IP()) { - // Endpoint has changed, ensure that the new IP fits into table limits. - tab.removeIP(b, b.entries[i].IP()) - if !tab.addIP(b, n.IP()) { - // It doesn't, put the previous one back. - tab.addIP(b, b.entries[i].IP()) - return false - } - } - // Move it to the front. - copy(b.entries[1:], b.entries[:i]) - b.entries[0] = n - return true + rindex := tab.rand.Intn(len(b.replacements)) + rep := b.replacements[rindex] + b.replacements = slices.Delete(b.replacements, rindex, rindex+1) + b.entries = append(b.entries, rep) + tab.nodeAdded(b, rep) + tab.log.Debug("Replaced dead node", "b", b.index, "id", n.ID(), "ip", n.IP(), "r", rep.ID(), "rip", rep.IP()) + return rep +} + +// bumpInBucket updates the node record of n in the bucket. +func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node) bool { + i := slices.IndexFunc(b.entries, func(elem *node) bool { + return elem.ID() == newRecord.ID() + }) + if i == -1 { + return false + } + + if !newRecord.IP().Equal(b.entries[i].IP()) { + // Endpoint has changed, ensure that the new IP fits into table limits. + tab.removeIP(b, b.entries[i].IP()) + if !tab.addIP(b, newRecord.IP()) { + // It doesn't, put the previous one back. + tab.addIP(b, b.entries[i].IP()) + return false } } - return false + b.entries[i].Node = newRecord + return true } -func (tab *Table) deleteInBucket(b *bucket, n *node) { - // Check if the node is actually in the bucket so the removed hook - // isn't called multiple times for the same node. - if !contains(b.entries, n.ID()) { - return +func (tab *Table) handleTrackRequest(op trackRequestOp) { + var fails int + if op.success { + // Reset failure counter because it counts _consecutive_ failures. + tab.db.UpdateFindFails(op.node.ID(), op.node.IP(), 0) + } else { + fails = tab.db.FindFails(op.node.ID(), op.node.IP()) + fails++ + tab.db.UpdateFindFails(op.node.ID(), op.node.IP(), fails) } - b.entries = deleteNode(b.entries, n) - tab.removeIP(b, n.IP()) - if tab.nodeRemovedHook != nil { - tab.nodeRemovedHook(b, n) + + tab.mutex.Lock() + defer tab.mutex.Unlock() + + b := tab.bucket(op.node.ID()) + // Remove the node from the local table if it fails to return anything useful too + // many times, but only if there are enough other nodes in the bucket. This latter + // condition specifically exists to make bootstrapping in smaller test networks more + // reliable. + if fails >= maxFindnodeFailures && len(b.entries) >= bucketSize/4 { + tab.deleteInBucket(b, op.node.ID()) + } + + // Add found nodes. + for _, n := range op.foundNodes { + tab.handleAddNode(addNodeOp{n, false}) } } diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go new file mode 100644 index 000000000000..9a13900ebca4 --- /dev/null +++ b/p2p/discover/table_reval.go @@ -0,0 +1,223 @@ +// Copyright 2024 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 discover + +import ( + "fmt" + "math" + "slices" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +const never = mclock.AbsTime(math.MaxInt64) + +// tableRevalidation implements the node revalidation process. +// It tracks all nodes contained in Table, and schedules sending PING to them. +type tableRevalidation struct { + fast revalidationList + slow revalidationList + activeReq map[enode.ID]struct{} +} + +type revalidationResponse struct { + n *node + newRecord *enode.Node + list *revalidationList + didRespond bool +} + +func (tr *tableRevalidation) init(cfg *Config) { + tr.activeReq = make(map[enode.ID]struct{}) + tr.fast.nextTime = never + tr.fast.interval = cfg.PingInterval + tr.fast.name = "fast" + tr.slow.nextTime = never + tr.slow.interval = cfg.PingInterval * 3 + tr.slow.name = "slow" +} + +// nodeAdded is called when the table receives a new node. +func (tr *tableRevalidation) nodeAdded(tab *Table, n *node) { + tr.fast.push(n, tab.cfg.Clock.Now(), &tab.rand) +} + +// nodeRemoved is called when a node was removed from the table. +func (tr *tableRevalidation) nodeRemoved(n *node) { + if !tr.fast.remove(n) { + tr.slow.remove(n) + } +} + +// run performs node revalidation. +// It returns the next time it should be invoked, which is used in the Table main loop +// to schedule a timer. However, run can be called at any time. +func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mclock.AbsTime) { + if n := tr.fast.get(now, &tab.rand, tr.activeReq); n != nil { + tr.startRequest(tab, &tr.fast, n) + tr.fast.schedule(now, &tab.rand) + } + if n := tr.slow.get(now, &tab.rand, tr.activeReq); n != nil { + tr.startRequest(tab, &tr.slow, n) + tr.slow.schedule(now, &tab.rand) + } + + return min(tr.fast.nextTime, tr.slow.nextTime) +} + +// startRequest spawns a revalidation request for node n. +func (tr *tableRevalidation) startRequest(tab *Table, list *revalidationList, n *node) { + if _, ok := tr.activeReq[n.ID()]; ok { + panic(fmt.Errorf("duplicate startRequest (list %q, node %v)", list.name, n.ID())) + } + tr.activeReq[n.ID()] = struct{}{} + resp := revalidationResponse{n: n, list: list} + + // Fetch the node while holding lock. + tab.mutex.Lock() + node := n.Node + tab.mutex.Unlock() + + go tab.doRevalidate(resp, node) +} + +func (tab *Table) doRevalidate(resp revalidationResponse, node *enode.Node) { + // Ping the selected node and wait for a pong response. + remoteSeq, err := tab.net.ping(node) + resp.didRespond = err == nil + + // Also fetch record if the node replied and returned a higher sequence number. + if remoteSeq > node.Seq() { + newrec, err := tab.net.RequestENR(node) + if err != nil { + tab.log.Debug("ENR request failed", "id", node.ID(), "err", err) + } else { + resp.newRecord = newrec + } + } + + select { + case tab.revalResponseCh <- resp: + case <-tab.closed: + } +} + +// handleResponse processes the result of a revalidation request. +func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationResponse) { + now := tab.cfg.Clock.Now() + n := resp.n + b := tab.bucket(n.ID()) + delete(tr.activeReq, n.ID()) + + tab.mutex.Lock() + defer tab.mutex.Unlock() + + if !resp.didRespond { + // Revalidation failed. + n.livenessChecks /= 3 + if n.livenessChecks <= 0 { + tab.deleteInBucket(b, n.ID()) + } else { + tr.moveToList(&tr.fast, resp.list, n, now, &tab.rand) + } + return + } + + // The node responded. + n.livenessChecks++ + n.isValidatedLive = true + var endpointChanged bool + if resp.newRecord != nil { + endpointChanged = tab.bumpInBucket(b, resp.newRecord) + if endpointChanged { + // If the node changed its advertised endpoint, the updated ENR is not served + // until it has been revalidated. + n.isValidatedLive = false + } + } + tab.log.Debug("Revalidated node", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", resp.list.name) + + // Move node over to slow queue after first validation. + if !endpointChanged { + tr.moveToList(&tr.slow, resp.list, n, now, &tab.rand) + } else { + tr.moveToList(&tr.fast, resp.list, n, now, &tab.rand) + } + + // Store potential seeds in database. + if n.isValidatedLive && n.livenessChecks > 5 { + tab.db.UpdateNode(resp.n.Node) + } +} + +func (tr *tableRevalidation) moveToList(dest, source *revalidationList, n *node, now mclock.AbsTime, rand randomSource) { + if source == dest { + return + } + if !source.remove(n) { + panic(fmt.Errorf("moveToList(%q -> %q): node %v not in source list", source.name, dest.name, n.ID())) + } + dest.push(n, now, rand) +} + +// revalidationList holds a list nodes and the next revalidation time. +type revalidationList struct { + nodes []*node + nextTime mclock.AbsTime + interval time.Duration + name string +} + +// get returns a random node from the queue. Nodes in the 'exclude' map are not returned. +func (list *revalidationList) get(now mclock.AbsTime, rand randomSource, exclude map[enode.ID]struct{}) *node { + if now < list.nextTime || len(list.nodes) == 0 { + return nil + } + for i := 0; i < len(list.nodes)*3; i++ { + n := list.nodes[rand.Intn(len(list.nodes))] + _, excluded := exclude[n.ID()] + if !excluded { + return n + } + } + return nil +} + +func (list *revalidationList) schedule(now mclock.AbsTime, rand randomSource) { + list.nextTime = now.Add(time.Duration(rand.Int63n(int64(list.interval)))) +} + +func (list *revalidationList) push(n *node, now mclock.AbsTime, rand randomSource) { + list.nodes = append(list.nodes, n) + if list.nextTime == never { + list.schedule(now, rand) + } +} + +func (list *revalidationList) remove(n *node) bool { + i := slices.Index(list.nodes, n) + if i == -1 { + return false + } + list.nodes = slices.Delete(list.nodes, i, i+1) + if len(list.nodes) == 0 { + list.nextTime = never + } + return true +} diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 3ba342225133..f72ecd94c989 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -20,14 +20,16 @@ import ( "crypto/ecdsa" "fmt" "math/rand" - "net" "reflect" "testing" "testing/quick" "time" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/testlog" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/netutil" @@ -49,106 +51,109 @@ func TestTable_pingReplace(t *testing.T) { } func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding bool) { + simclock := new(mclock.Simulated) transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{ + Clock: simclock, + Log: testlog.Logger(t, log.LevelTrace), + }) defer db.Close() defer tab.close() <-tab.initDone // Fill up the sender's bucket. - pingKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") - pingSender := wrapNode(enode.NewV4(&pingKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99)) - last := fillBucket(tab, pingSender) + replacementNodeKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") + replacementNode := wrapNode(enode.NewV4(&replacementNodeKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99)) + last := fillBucket(tab, replacementNode.ID()) + tab.mutex.Lock() + nodeEvents := newNodeEventRecorder(128) + tab.nodeAddedHook = nodeEvents.nodeAdded + tab.nodeRemovedHook = nodeEvents.nodeRemoved + tab.mutex.Unlock() - // Add the sender as if it just pinged us. Revalidate should replace the last node in - // its bucket if it is unresponsive. Revalidate again to ensure that + // The revalidation process should replace + // this node in the bucket if it is unresponsive. transport.dead[last.ID()] = !lastInBucketIsResponding - transport.dead[pingSender.ID()] = !newNodeIsResponding - tab.addSeenNode(pingSender) - tab.doRevalidate(make(chan struct{}, 1)) - tab.doRevalidate(make(chan struct{}, 1)) - - if !transport.pinged[last.ID()] { - // Oldest node in bucket is pinged to see whether it is still alive. - t.Error("table did not ping last node in bucket") + transport.dead[replacementNode.ID()] = !newNodeIsResponding + + // Add replacement node to table. + tab.addFoundNode(replacementNode) + + t.Log("last:", last.ID()) + t.Log("replacement:", replacementNode.ID()) + + // Wait until the last node was pinged. + waitForRevalidationPing(t, transport, tab, last.ID()) + + if !lastInBucketIsResponding { + if !nodeEvents.waitNodeAbsent(last.ID(), 2*time.Second) { + t.Error("last node was not removed") + } + if !nodeEvents.waitNodePresent(replacementNode.ID(), 2*time.Second) { + t.Error("replacement node was not added") + } + + // If a replacement is expected, we also need to wait until the replacement node + // was pinged and added/removed. + waitForRevalidationPing(t, transport, tab, replacementNode.ID()) + if !newNodeIsResponding { + if !nodeEvents.waitNodeAbsent(replacementNode.ID(), 2*time.Second) { + t.Error("replacement node was not removed") + } + } } + // Check bucket content. tab.mutex.Lock() defer tab.mutex.Unlock() wantSize := bucketSize if !lastInBucketIsResponding && !newNodeIsResponding { wantSize-- } - if l := len(tab.bucket(pingSender.ID()).entries); l != wantSize { - t.Errorf("wrong bucket size after bond: got %d, want %d", l, wantSize) + bucket := tab.bucket(replacementNode.ID()) + if l := len(bucket.entries); l != wantSize { + t.Errorf("wrong bucket size after revalidation: got %d, want %d", l, wantSize) } - if found := contains(tab.bucket(pingSender.ID()).entries, last.ID()); found != lastInBucketIsResponding { - t.Errorf("last entry found: %t, want: %t", found, lastInBucketIsResponding) + if ok := contains(bucket.entries, last.ID()); ok != lastInBucketIsResponding { + t.Errorf("revalidated node found: %t, want: %t", ok, lastInBucketIsResponding) } wantNewEntry := newNodeIsResponding && !lastInBucketIsResponding - if found := contains(tab.bucket(pingSender.ID()).entries, pingSender.ID()); found != wantNewEntry { - t.Errorf("new entry found: %t, want: %t", found, wantNewEntry) + if ok := contains(bucket.entries, replacementNode.ID()); ok != wantNewEntry { + t.Errorf("replacement node found: %t, want: %t", ok, wantNewEntry) } } -func TestBucket_bumpNoDuplicates(t *testing.T) { - t.Parallel() - cfg := &quick.Config{ - MaxCount: 1000, - Rand: rand.New(rand.NewSource(time.Now().Unix())), - Values: func(args []reflect.Value, rand *rand.Rand) { - // generate a random list of nodes. this will be the content of the bucket. - n := rand.Intn(bucketSize-1) + 1 - nodes := make([]*node, n) - for i := range nodes { - nodes[i] = nodeAtDistance(enode.ID{}, 200, intIP(200)) - } - args[0] = reflect.ValueOf(nodes) - // generate random bump positions. - bumps := make([]int, rand.Intn(100)) - for i := range bumps { - bumps[i] = rand.Intn(len(nodes)) - } - args[1] = reflect.ValueOf(bumps) - }, - } - - prop := func(nodes []*node, bumps []int) (ok bool) { - tab, db := newTestTable(newPingRecorder()) - defer db.Close() - defer tab.close() +// waitForRevalidationPing waits until a PING message is sent to a node with the given id. +func waitForRevalidationPing(t *testing.T, transport *pingRecorder, tab *Table, id enode.ID) *enode.Node { + t.Helper() - b := &bucket{entries: make([]*node, len(nodes))} - copy(b.entries, nodes) - for i, pos := range bumps { - tab.bumpInBucket(b, b.entries[pos]) - if hasDuplicates(b.entries) { - t.Logf("bucket has duplicates after %d/%d bumps:", i+1, len(bumps)) - for _, n := range b.entries { - t.Logf(" %p", n) - } - return false - } + simclock := tab.cfg.Clock.(*mclock.Simulated) + maxAttempts := tab.len() * 8 + for i := 0; i < maxAttempts; i++ { + simclock.Run(tab.cfg.PingInterval) + p := transport.waitPing(2 * time.Second) + if p == nil { + t.Fatal("Table did not send revalidation ping") + } + if id == (enode.ID{}) || p.ID() == id { + return p } - checkIPLimitInvariant(t, tab) - return true - } - if err := quick.Check(prop, cfg); err != nil { - t.Error(err) } + t.Fatalf("Table did not ping node %v (%d attempts)", id, maxAttempts) + return nil } // This checks that the table-wide IP limit is applied correctly. func TestTable_IPLimit(t *testing.T) { transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{}) defer db.Close() defer tab.close() for i := 0; i < tableIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), i, net.IP{172, 0, 1, byte(i)}) - tab.addSeenNode(n) + tab.addFoundNode(n) } if tab.len() > tableIPLimit { t.Errorf("too many nodes in table") @@ -159,14 +164,14 @@ func TestTable_IPLimit(t *testing.T) { // This checks that the per-bucket IP limit is applied correctly. func TestTable_BucketIPLimit(t *testing.T) { transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{}) defer db.Close() defer tab.close() d := 3 for i := 0; i < bucketIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), d, net.IP{172, 0, 1, byte(i)}) - tab.addSeenNode(n) + tab.addFoundNode(n) } if tab.len() > bucketIPLimit { t.Errorf("too many nodes in table") @@ -196,7 +201,7 @@ func TestTable_findnodeByID(t *testing.T) { test := func(test *closeTest) bool { // for any node table, Target and N transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{}) defer db.Close() defer tab.close() fillTable(tab, test.All, true) @@ -271,7 +276,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { } func TestTable_addVerifiedNode(t *testing.T) { - tab, db := newTestTable(newPingRecorder()) + tab, db := newTestTable(newPingRecorder(), Config{}) <-tab.initDone defer db.Close() defer tab.close() @@ -279,31 +284,32 @@ func TestTable_addVerifiedNode(t *testing.T) { // Insert two nodes. n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) - tab.addSeenNode(n1) - tab.addSeenNode(n2) + tab.addFoundNode(n1) + tab.addFoundNode(n2) + bucket := tab.bucket(n1.ID()) // Verify bucket content: bcontent := []*node{n1, n2} - if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { - t.Fatalf("wrong bucket content: %v", tab.bucket(n1.ID()).entries) + if !reflect.DeepEqual(unwrapNodes(bucket.entries), unwrapNodes(bcontent)) { + t.Fatalf("wrong bucket content: %v", bucket.entries) } // Add a changed version of n2. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) - tab.addVerifiedNode(newn2) + tab.addInboundNode(newn2) // Check that bucket is updated correctly. - newBcontent := []*node{newn2, n1} - if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, newBcontent) { - t.Fatalf("wrong bucket content after update: %v", tab.bucket(n1.ID()).entries) + newBcontent := []*node{n1, newn2} + if !reflect.DeepEqual(unwrapNodes(bucket.entries), unwrapNodes(newBcontent)) { + t.Fatalf("wrong bucket content after update: %v", bucket.entries) } checkIPLimitInvariant(t, tab) } func TestTable_addSeenNode(t *testing.T) { - tab, db := newTestTable(newPingRecorder()) + tab, db := newTestTable(newPingRecorder(), Config{}) <-tab.initDone defer db.Close() defer tab.close() @@ -311,8 +317,8 @@ func TestTable_addSeenNode(t *testing.T) { // Insert two nodes. n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) - tab.addSeenNode(n1) - tab.addSeenNode(n2) + tab.addFoundNode(n1) + tab.addFoundNode(n2) // Verify bucket content: bcontent := []*node{n1, n2} @@ -324,7 +330,7 @@ func TestTable_addSeenNode(t *testing.T) { newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) - tab.addSeenNode(newn2) + tab.addFoundNode(newn2) // Check that bucket content is unchanged. if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { @@ -337,7 +343,10 @@ func TestTable_addSeenNode(t *testing.T) { // announces a new sequence number, the new record should be pulled. func TestTable_revalidateSyncRecord(t *testing.T) { transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{ + Clock: new(mclock.Simulated), + Log: testlog.Logger(t, log.LevelTrace), + }) <-tab.initDone defer db.Close() defer tab.close() @@ -347,14 +356,18 @@ func TestTable_revalidateSyncRecord(t *testing.T) { r.Set(enr.IP(net.IP{127, 0, 0, 1})) id := enode.ID{1} n1 := wrapNode(enode.SignNull(&r, id)) - tab.addSeenNode(n1) + tab.addFoundNode(n1) // Update the node record. r.Set(enr.WithEntry("foo", "bar")) n2 := enode.SignNull(&r, id) transport.updateRecord(n2) - tab.doRevalidate(make(chan struct{}, 1)) + // Wait for revalidation. We wait for the node to be revalidated two times + // in order to synchronize with the update in the able. + waitForRevalidationPing(t, transport, tab, n2.ID()) + waitForRevalidationPing(t, transport, tab, n2.ID()) + intable := tab.getNode(id) if !reflect.DeepEqual(intable, n2) { t.Fatalf("table contains old record with seq %d, want seq %d", intable.Seq(), n2.Seq()) diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index f5d4d39bdbb7..86c60480948a 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -26,6 +26,8 @@ import ( "net" "slices" "sync" + "sync/atomic" + "time" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" @@ -40,8 +42,7 @@ func init() { nullNode = enode.SignNull(&r, enode.ID{}) } -func newTestTable(t transport) (*Table, *enode.DB) { - cfg := Config{} +func newTestTable(t transport, cfg Config) (*Table, *enode.DB) { db, _ := enode.OpenDB("") tab, _ := newTable(t, db, cfg) go tab.loop() @@ -98,11 +99,14 @@ func intIP(i int) net.IP { } // fillBucket inserts nodes into the given bucket until it is full. -func fillBucket(tab *Table, n *node) (last *node) { - ld := enode.LogDist(tab.self().ID(), n.ID()) - b := tab.bucket(n.ID()) +func fillBucket(tab *Table, id enode.ID) (last *node) { + ld := enode.LogDist(tab.self().ID(), id) + b := tab.bucket(id) for len(b.entries) < bucketSize { - b.entries = append(b.entries, nodeAtDistance(tab.self().ID(), ld, intIP(ld))) + node := nodeAtDistance(tab.self().ID(), ld, intIP(ld)) + if !tab.addFoundNode(node) { + panic("node not added") + } } return b.entries[bucketSize-1] } @@ -113,16 +117,19 @@ func fillTable(tab *Table, nodes []*node, setLive bool) { for _, n := range nodes { if setLive { n.livenessChecks = 1 + n.isValidatedLive = true } - tab.addSeenNode(n) + tab.addFoundNode(n) } } type pingRecorder struct { - mu sync.Mutex - dead, pinged map[enode.ID]bool - records map[enode.ID]*enode.Node - n *enode.Node + mu sync.Mutex + cond *sync.Cond + dead map[enode.ID]bool + records map[enode.ID]*enode.Node + pinged []*enode.Node + n *enode.Node } func newPingRecorder() *pingRecorder { @@ -130,12 +137,13 @@ func newPingRecorder() *pingRecorder { r.Set(enr.IP{0, 0, 0, 0}) n := enode.SignNull(&r, enode.ID{}) - return &pingRecorder{ + t := &pingRecorder{ dead: make(map[enode.ID]bool), - pinged: make(map[enode.ID]bool), records: make(map[enode.ID]*enode.Node), n: n, } + t.cond = sync.NewCond(&t.mu) + return t } // updateRecord updates a node record. Future calls to ping and @@ -151,12 +159,40 @@ func (t *pingRecorder) Self() *enode.Node { return nullNode } func (t *pingRecorder) lookupSelf() []*enode.Node { return nil } func (t *pingRecorder) lookupRandom() []*enode.Node { return nil } +func (t *pingRecorder) waitPing(timeout time.Duration) *enode.Node { + t.mu.Lock() + defer t.mu.Unlock() + + // Wake up the loop on timeout. + var timedout atomic.Bool + timer := time.AfterFunc(timeout, func() { + timedout.Store(true) + t.cond.Broadcast() + }) + defer timer.Stop() + + // Wait for a ping. + for { + if timedout.Load() { + return nil + } + if len(t.pinged) > 0 { + n := t.pinged[0] + t.pinged = append(t.pinged[:0], t.pinged[1:]...) + return n + } + t.cond.Wait() + } +} + // ping simulates a ping request. func (t *pingRecorder) ping(n *enode.Node) (seq uint64, err error) { t.mu.Lock() defer t.mu.Unlock() - t.pinged[n.ID()] = true + t.pinged = append(t.pinged, n) + t.cond.Broadcast() + if t.dead[n.ID()] { return 0, errTimeout } @@ -256,3 +292,57 @@ func hexEncPubkey(h string) (ret encPubkey) { copy(ret[:], b) return ret } + +type nodeEventRecorder struct { + evc chan recordedNodeEvent +} + +type recordedNodeEvent struct { + node *node + added bool +} + +func newNodeEventRecorder(buffer int) *nodeEventRecorder { + return &nodeEventRecorder{ + evc: make(chan recordedNodeEvent, buffer), + } +} + +func (set *nodeEventRecorder) nodeAdded(b *bucket, n *node) { + select { + case set.evc <- recordedNodeEvent{n, true}: + default: + panic("no space in event buffer") + } +} + +func (set *nodeEventRecorder) nodeRemoved(b *bucket, n *node) { + select { + case set.evc <- recordedNodeEvent{n, false}: + default: + panic("no space in event buffer") + } +} + +func (set *nodeEventRecorder) waitNodePresent(id enode.ID, timeout time.Duration) bool { + return set.waitNodeEvent(id, timeout, true) +} + +func (set *nodeEventRecorder) waitNodeAbsent(id enode.ID, timeout time.Duration) bool { + return set.waitNodeEvent(id, timeout, false) +} + +func (set *nodeEventRecorder) waitNodeEvent(id enode.ID, timeout time.Duration, added bool) bool { + timer := time.NewTimer(timeout) + defer timer.Stop() + for { + select { + case ev := <-set.evc: + if ev.node.ID() == id && ev.added == added { + return true + } + case <-timer.C: + return false + } + } +} diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 7a0a0f1c7779..be6058ec5000 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -142,7 +142,7 @@ func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { log: cfg.Log, } - tab, err := newMeteredTable(t, ln.Database(), cfg) + tab, err := newTable(t, ln.Database(), cfg) if err != nil { return nil, err } @@ -375,6 +375,10 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { return respN, nil } +func (t *UDPv4) TableBuckets() [][]BucketNode { + return t.tab.Nodes() +} + // pending adds a reply matcher to the pending reply queue. // see the documentation of type replyMatcher for a detailed explanation. func (t *UDPv4) pending(id enode.ID, ip net.IP, ptype byte, callback replyMatchFunc) *replyMatcher { @@ -669,10 +673,10 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I n := wrapNode(enode.NewV4(h.senderKey, from.IP, int(req.From.TCP), from.Port)) if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration { t.sendPing(fromID, from, func() { - t.tab.addVerifiedNode(n) + t.tab.addInboundNode(n) }) } else { - t.tab.addVerifiedNode(n) + t.tab.addInboundNode(n) } // Update node database and endpoint predictor. diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 9b80214f7552..9c454d98e3e0 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -264,7 +264,7 @@ func TestUDPv4_findnode(t *testing.T) { n := wrapNode(enode.NewV4(&key.PublicKey, ip, 0, 2000)) // Ensure half of table content isn't verified live yet. if i > numCandidates/2 { - n.livenessChecks = 1 + n.isValidatedLive = true live[n.ID()] = true } nodes.push(n, numCandidates) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 20a8bccd058e..8cdc9dfbce3d 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -175,7 +175,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { cancelCloseCtx: cancelCloseCtx, } t.talk = newTalkSystem(t) - tab, err := newMeteredTable(t, t.db, cfg) + tab, err := newTable(t, t.db, cfg) if err != nil { return nil, err } @@ -699,7 +699,7 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { } if fromNode != nil { // Handshake succeeded, add to table. - t.tab.addSeenNode(wrapNode(fromNode)) + t.tab.addInboundNode(wrapNode(fromNode)) } if packet.Kind() != v5wire.WhoareyouPacket { // WHOAREYOU logged separately to report errors. diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 4373ea81847f..0015f7cc7062 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -141,7 +141,7 @@ func TestUDPv5_unknownPacket(t *testing.T) { // Make node known. n := test.getNode(test.remotekey, test.remoteaddr).Node() - test.table.addSeenNode(wrapNode(n)) + test.table.addFoundNode(wrapNode(n)) test.packetIn(&v5wire.Unknown{Nonce: nonce}) test.waitPacketOut(func(p *v5wire.Whoareyou, addr *net.UDPAddr, _ v5wire.Nonce) { diff --git a/p2p/server.go b/p2p/server.go index 5b9a4aa71fdc..79c5fc76b69f 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -190,8 +190,8 @@ type Server struct { nodedb *enode.DB localnode *enode.LocalNode - ntab *discover.UDPv4 - DiscV5 *discover.UDPv5 + discv4 *discover.UDPv4 + discv5 *discover.UDPv5 discmix *enode.FairMix dialsched *dialScheduler @@ -400,6 +400,16 @@ func (srv *Server) Self() *enode.Node { return ln.Node() } +// DiscoveryV4 returns the discovery v4 instance, if configured. +func (srv *Server) DiscoveryV4() *discover.UDPv4 { + return srv.discv4 +} + +// DiscoveryV4 returns the discovery v5 instance, if configured. +func (srv *Server) DiscoveryV5() *discover.UDPv5 { + return srv.discv5 +} + // Stop terminates the server and all active peer connections. // It blocks until all active connections have been closed. func (srv *Server) Stop() { @@ -547,13 +557,13 @@ func (srv *Server) setupDiscovery() error { ) // If both versions of discovery are running, setup a shared // connection, so v5 can read unhandled messages from v4. - if srv.DiscoveryV4 && srv.DiscoveryV5 { + if srv.Config.DiscoveryV4 && srv.Config.DiscoveryV5 { unhandled = make(chan discover.ReadPacket, 100) sconn = &sharedUDPConn{conn, unhandled} } // Start discovery services. - if srv.DiscoveryV4 { + if srv.Config.DiscoveryV4 { cfg := discover.Config{ PrivateKey: srv.PrivateKey, NetRestrict: srv.NetRestrict, @@ -565,17 +575,17 @@ func (srv *Server) setupDiscovery() error { if err != nil { return err } - srv.ntab = ntab + srv.discv4 = ntab srv.discmix.AddSource(ntab.RandomNodes()) } - if srv.DiscoveryV5 { + if srv.Config.DiscoveryV5 { cfg := discover.Config{ PrivateKey: srv.PrivateKey, NetRestrict: srv.NetRestrict, Bootnodes: srv.BootstrapNodesV5, Log: srv.log, } - srv.DiscV5, err = discover.ListenV5(sconn, srv.localnode, cfg) + srv.discv5, err = discover.ListenV5(sconn, srv.localnode, cfg) if err != nil { return err } @@ -602,8 +612,8 @@ func (srv *Server) setupDialScheduler() { dialer: srv.Dialer, clock: srv.clock, } - if srv.ntab != nil { - config.resolver = srv.ntab + if srv.discv4 != nil { + config.resolver = srv.discv4 } if config.dialer == nil { config.dialer = tcpDialer{&net.Dialer{Timeout: defaultDialTimeout}} @@ -799,11 +809,11 @@ running: srv.log.Trace("P2P networking is spinning down") // Terminate discovery. If there is a running lookup it will terminate soon. - if srv.ntab != nil { - srv.ntab.Close() + if srv.discv4 != nil { + srv.discv4.Close() } - if srv.DiscV5 != nil { - srv.DiscV5.Close() + if srv.discv5 != nil { + srv.discv5.Close() } // Disconnect all peers. for _, p := range peers { From cc9e2bd9ddd538811612156965ce008efd919264 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 23 May 2024 14:27:03 +0200 Subject: [PATCH 284/571] p2p/enode: fix endpoint determination for IPv6 (#29801) enode.Node has separate accessor functions for getting the IP, UDP port and TCP port. These methods performed separate checks for attributes set in the ENR. With this PR, the accessor methods will now return cached information, and the endpoint is determined when the node is created. The logic to determine the preferred endpoint is now more correct, and considers how 'global' each address is when both IPv4 and IPv6 addresses are present in the ENR. --- p2p/enode/idscheme.go | 2 +- p2p/enode/node.go | 137 +++++++++++++++++++++++++--------- p2p/enode/node_test.go | 162 +++++++++++++++++++++++++++++++++++++++++ p2p/enode/nodedb.go | 12 +-- p2p/enode/urlv4.go | 2 +- p2p/enr/entries.go | 55 ++++++++++++++ 6 files changed, 330 insertions(+), 40 deletions(-) diff --git a/p2p/enode/idscheme.go b/p2p/enode/idscheme.go index 6ad7f809a71d..db7841c047a1 100644 --- a/p2p/enode/idscheme.go +++ b/p2p/enode/idscheme.go @@ -157,5 +157,5 @@ func SignNull(r *enr.Record, id ID) *Node { if err := r.SetSig(NullID{}, []byte{}); err != nil { panic(err) } - return &Node{r: *r, id: id} + return newNodeWithID(r, id) } diff --git a/p2p/enode/node.go b/p2p/enode/node.go index d7a1a9a1561c..e7fe0e0ace0f 100644 --- a/p2p/enode/node.go +++ b/p2p/enode/node.go @@ -24,6 +24,7 @@ import ( "fmt" "math/bits" "net" + "net/netip" "strings" "github.com/ethereum/go-ethereum/p2p/enr" @@ -36,6 +37,10 @@ var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded reco type Node struct { r enr.Record id ID + // endpoint information + ip netip.Addr + udp uint16 + tcp uint16 } // New wraps a node record. The record must be valid according to the given @@ -44,11 +49,76 @@ func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { if err := r.VerifySignature(validSchemes); err != nil { return nil, err } - node := &Node{r: *r} - if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) { - return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{})) + var id ID + if n := copy(id[:], validSchemes.NodeAddr(r)); n != len(id) { + return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(id)) + } + return newNodeWithID(r, id), nil +} + +func newNodeWithID(r *enr.Record, id ID) *Node { + n := &Node{r: *r, id: id} + // Set the preferred endpoint. + // Here we decide between IPv4 and IPv6, choosing the 'most global' address. + var ip4 netip.Addr + var ip6 netip.Addr + n.Load((*enr.IPv4Addr)(&ip4)) + n.Load((*enr.IPv6Addr)(&ip6)) + valid4 := validIP(ip4) + valid6 := validIP(ip6) + switch { + case valid4 && valid6: + if localityScore(ip4) >= localityScore(ip6) { + n.setIP4(ip4) + } else { + n.setIP6(ip6) + } + case valid4: + n.setIP4(ip4) + case valid6: + n.setIP6(ip6) + } + return n +} + +// validIP reports whether 'ip' is a valid node endpoint IP address. +func validIP(ip netip.Addr) bool { + return ip.IsValid() && !ip.IsMulticast() +} + +func localityScore(ip netip.Addr) int { + switch { + case ip.IsUnspecified(): + return 0 + case ip.IsLoopback(): + return 1 + case ip.IsLinkLocalUnicast(): + return 2 + case ip.IsPrivate(): + return 3 + default: + return 4 + } +} + +func (n *Node) setIP4(ip netip.Addr) { + n.ip = ip + n.Load((*enr.UDP)(&n.udp)) + n.Load((*enr.TCP)(&n.tcp)) +} + +func (n *Node) setIP6(ip netip.Addr) { + if ip.Is4In6() { + n.setIP4(ip) + return + } + n.ip = ip + if err := n.Load((*enr.UDP6)(&n.udp)); err != nil { + n.Load((*enr.UDP)(&n.udp)) + } + if err := n.Load((*enr.TCP6)(&n.tcp)); err != nil { + n.Load((*enr.TCP)(&n.tcp)) } - return node, nil } // MustParse parses a node record or enode:// URL. It panics if the input is invalid. @@ -89,43 +159,45 @@ func (n *Node) Seq() uint64 { return n.r.Seq() } -// Incomplete returns true for nodes with no IP address. -func (n *Node) Incomplete() bool { - return n.IP() == nil -} - // Load retrieves an entry from the underlying record. func (n *Node) Load(k enr.Entry) error { return n.r.Load(k) } -// IP returns the IP address of the node. This prefers IPv4 addresses. +// IP returns the IP address of the node. func (n *Node) IP() net.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 + return net.IP(n.ip.AsSlice()) +} + +// IPAddr returns the IP address of the node. +func (n *Node) IPAddr() netip.Addr { + return n.ip } // UDP returns the UDP port of the node. func (n *Node) UDP() int { - var port enr.UDP - n.Load(&port) - return int(port) + return int(n.udp) } // TCP returns the TCP port of the node. func (n *Node) TCP() int { - var port enr.TCP - n.Load(&port) - return int(port) + return int(n.tcp) +} + +// UDPEndpoint returns the announced TCP endpoint. +func (n *Node) UDPEndpoint() (netip.AddrPort, bool) { + if !n.ip.IsValid() || n.ip.IsUnspecified() || n.udp == 0 { + return netip.AddrPort{}, false + } + return netip.AddrPortFrom(n.ip, n.udp), true +} + +// TCPEndpoint returns the announced TCP endpoint. +func (n *Node) TCPEndpoint() (netip.AddrPort, bool) { + if !n.ip.IsValid() || n.ip.IsUnspecified() || n.tcp == 0 { + return netip.AddrPort{}, false + } + return netip.AddrPortFrom(n.ip, n.udp), true } // Pubkey returns the secp256k1 public key of the node, if present. @@ -147,16 +219,15 @@ func (n *Node) Record() *enr.Record { // 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() { + if !n.ip.IsValid() { return errors.New("missing IP address") } - if n.UDP() == 0 { - return errors.New("missing UDP port") - } - ip := n.IP() - if ip.IsMulticast() || ip.IsUnspecified() { + if n.ip.IsMulticast() || n.ip.IsUnspecified() { return errors.New("invalid IP (multicast/unspecified)") } + if n.udp == 0 { + return errors.New("missing UDP port") + } // Validate the node key (on curve, etc.). var key Secp256k1 return n.Load(&key) diff --git a/p2p/enode/node_test.go b/p2p/enode/node_test.go index d15859c477a5..56e196e82e2d 100644 --- a/p2p/enode/node_test.go +++ b/p2p/enode/node_test.go @@ -21,6 +21,7 @@ import ( "encoding/hex" "fmt" "math/big" + "net/netip" "testing" "testing/quick" @@ -64,6 +65,167 @@ func TestPythonInterop(t *testing.T) { } } +func TestNodeEndpoints(t *testing.T) { + id := HexID("00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") + type endpointTest struct { + name string + node *Node + wantIP netip.Addr + wantUDP int + wantTCP int + } + tests := []endpointTest{ + { + name: "no-addr", + node: func() *Node { + var r enr.Record + return SignNull(&r, id) + }(), + }, + { + name: "udp-only", + node: func() *Node { + var r enr.Record + r.Set(enr.UDP(9000)) + return SignNull(&r, id) + }(), + }, + { + name: "tcp-only", + node: func() *Node { + var r enr.Record + r.Set(enr.TCP(9000)) + return SignNull(&r, id) + }(), + }, + { + name: "ipv4-only-loopback", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("127.0.0.1"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("127.0.0.1"), + }, + { + name: "ipv4-only-unspecified", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("0.0.0.0"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("0.0.0.0"), + }, + { + name: "ipv4-only", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("99.22.33.1"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("99.22.33.1"), + }, + { + name: "ipv6-only", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + }, + { + name: "ipv4-loopback-and-ipv6-global", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("127.0.0.1"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + wantUDP: 30306, + }, + { + name: "ipv4-unspecified-and-ipv6-loopback", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("0.0.0.0"))) + r.Set(enr.IPv6Addr(netip.MustParseAddr("::1"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("::1"), + }, + { + name: "ipv4-private-and-ipv6-global", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("192.168.2.2"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + wantUDP: 30306, + }, + { + name: "ipv4-local-and-ipv6-global", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("169.254.2.6"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + wantUDP: 30306, + }, + { + name: "ipv4-private-and-ipv6-private", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("192.168.2.2"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("fd00::abcd:1"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("192.168.2.2"), + wantUDP: 30304, + }, + { + name: "ipv4-private-and-ipv6-link-local", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("192.168.2.2"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("fe80::1"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("192.168.2.2"), + wantUDP: 30304, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.wantIP != test.node.IPAddr() { + t.Errorf("node has wrong IP %v, want %v", test.node.IPAddr(), test.wantIP) + } + if test.wantUDP != test.node.UDP() { + t.Errorf("node has wrong UDP port %d, want %d", test.node.UDP(), test.wantUDP) + } + if test.wantTCP != test.node.TCP() { + t.Errorf("node has wrong TCP port %d, want %d", test.node.TCP(), test.wantTCP) + } + }) + } +} + 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") diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go index 6d55ce17f130..654d71d47b6a 100644 --- a/p2p/enode/nodedb.go +++ b/p2p/enode/nodedb.go @@ -26,6 +26,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/errors" @@ -242,13 +243,14 @@ func (db *DB) Node(id ID) *Node { } func mustDecodeNode(id, data []byte) *Node { - node := new(Node) - if err := rlp.DecodeBytes(data, &node.r); err != nil { + var r enr.Record + if err := rlp.DecodeBytes(data, &r); err != nil { panic(fmt.Errorf("p2p/enode: can't decode node %x in DB: %v", id, err)) } - // Restore node id cache. - copy(node.id[:], id) - return node + if len(id) != len(ID{}) { + panic(fmt.Errorf("invalid id length %d", len(id))) + } + return newNodeWithID(&r, ID(id)) } // UpdateNode inserts - potentially overwriting - a node into the peer database. diff --git a/p2p/enode/urlv4.go b/p2p/enode/urlv4.go index 0272eee98725..a55dfa6632b3 100644 --- a/p2p/enode/urlv4.go +++ b/p2p/enode/urlv4.go @@ -181,7 +181,7 @@ func (n *Node) URLv4() string { nodeid = fmt.Sprintf("%s.%x", scheme, n.id[:]) } u := url.URL{Scheme: "enode"} - if n.Incomplete() { + if !n.ip.IsValid() { u.Host = nodeid } else { addr := net.TCPAddr{IP: n.IP(), Port: n.TCP()} diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index 9945a436c9f8..917e1becbaac 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "net" + "net/netip" "github.com/ethereum/go-ethereum/rlp" ) @@ -167,6 +168,60 @@ func (v *IPv6) DecodeRLP(s *rlp.Stream) error { return nil } +// IPv4Addr is the "ip" key, which holds the IP address of the node. +type IPv4Addr netip.Addr + +func (v IPv4Addr) ENRKey() string { return "ip" } + +// EncodeRLP implements rlp.Encoder. +func (v IPv4Addr) EncodeRLP(w io.Writer) error { + addr := netip.Addr(v) + if !addr.Is4() { + return fmt.Errorf("address is not IPv4") + } + enc := rlp.NewEncoderBuffer(w) + bytes := addr.As4() + enc.WriteBytes(bytes[:]) + return enc.Flush() +} + +// DecodeRLP implements rlp.Decoder. +func (v *IPv4Addr) DecodeRLP(s *rlp.Stream) error { + var bytes [4]byte + if err := s.ReadBytes(bytes[:]); err != nil { + return err + } + *v = IPv4Addr(netip.AddrFrom4(bytes)) + return nil +} + +// IPv6Addr is the "ip6" key, which holds the IP address of the node. +type IPv6Addr netip.Addr + +func (v IPv6Addr) ENRKey() string { return "ip6" } + +// EncodeRLP implements rlp.Encoder. +func (v IPv6Addr) EncodeRLP(w io.Writer) error { + addr := netip.Addr(v) + if !addr.Is6() { + return fmt.Errorf("address is not IPv6") + } + enc := rlp.NewEncoderBuffer(w) + bytes := addr.As16() + enc.WriteBytes(bytes[:]) + return enc.Flush() +} + +// DecodeRLP implements rlp.Decoder. +func (v *IPv6Addr) DecodeRLP(s *rlp.Stream) error { + var bytes [16]byte + if err := s.ReadBytes(bytes[:]); err != nil { + return err + } + *v = IPv6Addr(netip.AddrFrom16(bytes)) + return nil +} + // KeyError is an error related to a key. type KeyError struct { Key string From 61b3d93bb02322054a00a9236658e6ac70ab0b6e Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Fri, 24 May 2024 05:17:51 +0800 Subject: [PATCH 285/571] p2p/enode: fix TCPEndpoint (#29827) --- p2p/enode/node.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/enode/node.go b/p2p/enode/node.go index e7fe0e0ace0f..cb4ac8d1726c 100644 --- a/p2p/enode/node.go +++ b/p2p/enode/node.go @@ -184,7 +184,7 @@ func (n *Node) TCP() int { return int(n.tcp) } -// UDPEndpoint returns the announced TCP endpoint. +// UDPEndpoint returns the announced UDP endpoint. func (n *Node) UDPEndpoint() (netip.AddrPort, bool) { if !n.ip.IsValid() || n.ip.IsUnspecified() || n.udp == 0 { return netip.AddrPort{}, false @@ -197,7 +197,7 @@ func (n *Node) TCPEndpoint() (netip.AddrPort, bool) { if !n.ip.IsValid() || n.ip.IsUnspecified() || n.tcp == 0 { return netip.AddrPort{}, false } - return netip.AddrPortFrom(n.ip, n.udp), true + return netip.AddrPortFrom(n.ip, n.tcp), true } // Pubkey returns the secp256k1 public key of the node, if present. From 08fe6a86141861609758978a9d968072968379b6 Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Fri, 24 May 2024 15:20:05 +0800 Subject: [PATCH 286/571] metrics: fix flaky test`TestExpDecaySampleNanosecondRegression` (#29832) --- metrics/sample_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/metrics/sample_test.go b/metrics/sample_test.go index 92806c65b2c7..87f085c70454 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -125,12 +125,12 @@ func TestExpDecaySample(t *testing.T) { // The priority becomes +Inf quickly after starting if this is done, // effectively freezing the set of samples until a rescale step happens. func TestExpDecaySampleNanosecondRegression(t *testing.T) { - sw := NewExpDecaySample(100, 0.99) - for i := 0; i < 100; i++ { + sw := NewExpDecaySample(1000, 0.99) + for i := 0; i < 1000; i++ { sw.Update(10) } time.Sleep(1 * time.Millisecond) - for i := 0; i < 100; i++ { + for i := 0; i < 1000; i++ { sw.Update(20) } s := sw.Snapshot() From 64b1cd8aafd25a110087a47da2043d043de0ac79 Mon Sep 17 00:00:00 2001 From: gitglorythegreat Date: Fri, 24 May 2024 17:33:19 +0800 Subject: [PATCH 287/571] p2p: fix typos (#29828) --- p2p/discover/table_test.go | 2 +- p2p/server.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index f72ecd94c989..945b1a294e9c 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -364,7 +364,7 @@ func TestTable_revalidateSyncRecord(t *testing.T) { transport.updateRecord(n2) // Wait for revalidation. We wait for the node to be revalidated two times - // in order to synchronize with the update in the able. + // in order to synchronize with the update in the table. waitForRevalidationPing(t, transport, tab, n2.ID()) waitForRevalidationPing(t, transport, tab, n2.ID()) diff --git a/p2p/server.go b/p2p/server.go index 79c5fc76b69f..a3c53b07813a 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -405,7 +405,7 @@ func (srv *Server) DiscoveryV4() *discover.UDPv4 { return srv.discv4 } -// DiscoveryV4 returns the discovery v5 instance, if configured. +// DiscoveryV5 returns the discovery v5 instance, if configured. func (srv *Server) DiscoveryV5() *discover.UDPv5 { return srv.discv5 } From b6474e9f90c88003de7d7eb993ddb5f60133172e Mon Sep 17 00:00:00 2001 From: levisyin Date: Fri, 24 May 2024 17:34:30 +0800 Subject: [PATCH 288/571] metrics: add test for `SampleSnapshot.Sum` (#29831) --- metrics/sample_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/metrics/sample_test.go b/metrics/sample_test.go index 87f085c70454..4227b43ef775 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -103,14 +103,14 @@ func TestExpDecaySample(t *testing.T) { } snap := sample.Snapshot() if have, want := int(snap.Count()), tc.updates; have != want { - t.Errorf("have %d want %d", have, want) + t.Errorf("unexpected count: have %d want %d", have, want) } if have, want := snap.Size(), min(tc.updates, tc.reservoirSize); have != want { - t.Errorf("have %d want %d", have, want) + t.Errorf("unexpected size: have %d want %d", have, want) } values := snap.(*sampleSnapshot).values if have, want := len(values), min(tc.updates, tc.reservoirSize); have != want { - t.Errorf("have %d want %d", have, want) + t.Errorf("unexpected values length: have %d want %d", have, want) } for _, v := range values { if v > int64(tc.updates) || v < 0 { @@ -251,6 +251,9 @@ func benchmarkSample(b *testing.B, s Sample) { } func testExpDecaySampleStatistics(t *testing.T, s SampleSnapshot) { + if sum := s.Sum(); sum != 496598 { + t.Errorf("s.Sum(): 496598 != %v\n", sum) + } if count := s.Count(); count != 10000 { t.Errorf("s.Count(): 10000 != %v\n", count) } From d1d9f34e519c25ac9d7366e760969ed2065e9426 Mon Sep 17 00:00:00 2001 From: winterjihwan <113398351+winterjihwan@users.noreply.github.com> Date: Sun, 26 May 2024 18:54:37 +0900 Subject: [PATCH 289/571] core/types: clarify set inclusion in comments (#29839) --- core/types/transaction.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/types/transaction.go b/core/types/transaction.go index 6a27ecbfecee..4ac9187bdbfe 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -556,7 +556,7 @@ func (s Transactions) EncodeIndex(i int, w *bytes.Buffer) { } } -// TxDifference returns a new set which is the difference between a and b. +// TxDifference returns a new set of transactions that are present in a but not in b. func TxDifference(a, b Transactions) Transactions { keep := make(Transactions, 0, len(a)) @@ -574,7 +574,7 @@ func TxDifference(a, b Transactions) Transactions { return keep } -// HashDifference returns a new set which is the difference between a and b. +// HashDifference returns a new set of hashes that are present in a but not in b. func HashDifference(a, b []common.Hash) []common.Hash { keep := make([]common.Hash, 0, len(a)) From 7f5cc02a99c5191079c9ece225778e5747013672 Mon Sep 17 00:00:00 2001 From: Wukingbow <40993922+Wukingbow@users.noreply.github.com> Date: Mon, 27 May 2024 14:34:53 +0800 Subject: [PATCH 290/571] metrics: fix function comment (#29843) --- metrics/debug.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/metrics/debug.go b/metrics/debug.go index de4a2739fe08..9dfee1a86698 100644 --- a/metrics/debug.go +++ b/metrics/debug.go @@ -19,18 +19,18 @@ var ( gcStats debug.GCStats ) -// Capture new values for the Go garbage collector statistics exported in -// debug.GCStats. This is designed to be called as a goroutine. +// CaptureDebugGCStats captures new values for the Go garbage collector statistics +// exported in debug.GCStats. This is designed to be called as a goroutine. func CaptureDebugGCStats(r Registry, d time.Duration) { for range time.Tick(d) { CaptureDebugGCStatsOnce(r) } } -// Capture new values for the Go garbage collector statistics exported in -// debug.GCStats. This is designed to be called in a background goroutine. -// Giving a registry which has not been given to RegisterDebugGCStats will -// panic. +// CaptureDebugGCStatsOnce captures new values for the Go garbage collector +// statistics exported in debug.GCStats. This is designed to be called in +// a background goroutine. Giving a registry which has not been given to +// RegisterDebugGCStats will panic. // // Be careful (but much less so) with this because debug.ReadGCStats calls // the C function runtime·lock(runtime·mheap) which, while not a stop-the-world @@ -50,9 +50,9 @@ func CaptureDebugGCStatsOnce(r Registry) { debugMetrics.GCStats.PauseTotal.Update(int64(gcStats.PauseTotal)) } -// Register metrics for the Go garbage collector statistics exported in -// debug.GCStats. The metrics are named by their fully-qualified Go symbols, -// i.e. debug.GCStats.PauseTotal. +// RegisterDebugGCStats registers metrics for the Go garbage collector statistics +// exported in debug.GCStats. The metrics are named by their fully-qualified Go +// symbols, i.e. debug.GCStats.PauseTotal. func RegisterDebugGCStats(r Registry) { debugMetrics.GCStats.LastGC = NewGauge() debugMetrics.GCStats.NumGC = NewGauge() From 7224576fba63d30e0ddfca538b133048634281ca Mon Sep 17 00:00:00 2001 From: Mobin Mohanan <47410557+tr1sm0s1n@users.noreply.github.com> Date: Mon, 27 May 2024 12:09:39 +0530 Subject: [PATCH 291/571] core, eth/protocols/snap, internal/ethapi: remove redundant types (#29841) --- core/genesis.go | 2 +- eth/protocols/snap/progress_test.go | 2 +- internal/ethapi/api_test.go | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 042071c531eb..f1b4490f2e22 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -594,7 +594,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b // Pre-deploy EIP-4788 system contract - params.BeaconRootsAddress: types.Account{Nonce: 1, Code: params.BeaconRootsCode}, + params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode}, }, } if faucet != nil { diff --git a/eth/protocols/snap/progress_test.go b/eth/protocols/snap/progress_test.go index 9d923bd2f507..1d9a6b8474f8 100644 --- a/eth/protocols/snap/progress_test.go +++ b/eth/protocols/snap/progress_test.go @@ -80,7 +80,7 @@ func makeLegacyProgress() legacyProgress { Next: common.Hash{}, Last: common.Hash{0x77}, SubTasks: map[common.Hash][]*legacyStorageTask{ - common.Hash{0x1}: { + {0x1}: { { Next: common.Hash{}, Last: common.Hash{0xff}, diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index a717ebdfae01..cf5160caf778 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -751,7 +751,7 @@ func TestEstimateGas(t *testing.T) { From: &accounts[0].addr, To: &accounts[1].addr, Value: (*hexutil.Big)(big.NewInt(1)), - BlobHashes: []common.Hash{common.Hash{0x01, 0x22}}, + BlobHashes: []common.Hash{{0x01, 0x22}}, BlobFeeCap: (*hexutil.Big)(big.NewInt(1)), }, want: 21000, @@ -939,7 +939,7 @@ func TestCall(t *testing.T) { call: TransactionArgs{ From: &accounts[1].addr, To: &randomAccounts[2].addr, - BlobHashes: []common.Hash{common.Hash{0x01, 0x22}}, + BlobHashes: []common.Hash{{0x01, 0x22}}, BlobFeeCap: (*hexutil.Big)(big.NewInt(1)), }, overrides: StateOverride{ @@ -1063,7 +1063,7 @@ func TestSendBlobTransaction(t *testing.T) { From: &b.acc.Address, To: &to, Value: (*hexutil.Big)(big.NewInt(1)), - BlobHashes: []common.Hash{common.Hash{0x01, 0x22}}, + BlobHashes: []common.Hash{{0x01, 0x22}}, }) if err != nil { t.Fatalf("failed to fill tx defaults: %v\n", err) From 1a4e4a4fe1286b5dc583ba18acdd39891d98953b Mon Sep 17 00:00:00 2001 From: Steven Wang <915337710@qq.com> Date: Mon, 27 May 2024 19:42:07 +0800 Subject: [PATCH 292/571] miner: fix TestBuildPayload sporadic failure (#29853) miner: fix TestBuildPayload sporadic failure Co-authored-by: steven --- miner/payload_building_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index 1728b9e5bd59..ac9b2ab704ba 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -141,7 +141,7 @@ func (b *testWorkerBackend) TxPool() *txpool.TxPool { return b.txPool } func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*Miner, *testWorkerBackend) { backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) - backend.txPool.Add(pendingTxs, true, false) + backend.txPool.Add(pendingTxs, true, true) w := New(backend, testConfig, engine) return w, backend } From 513276864bb223bf30a3497ba08ae3d15a696903 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 27 May 2024 22:26:55 +0800 Subject: [PATCH 293/571] eth/downloader: fix flaky test (#29852) This pull request fixes the flay test TestSkeletonSyncRetrievals. In this test, we first trigger a sync cycle and wait for it to meet certain expectations. We then inject a new head and potentially also a new peer, then perform another final sync. The test now performs the newPeer addition before launching the final sync, and waits a bit for that peer to get registered. This fixes the logic race that made the test fail sometimes. Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> --- eth/downloader/skeleton_test.go | 389 ++++++++++++++++---------------- 1 file changed, 192 insertions(+), 197 deletions(-) diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index 3693ab095ff6..4aa97cf1f797 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/protocols/eth" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -376,20 +377,9 @@ func TestSkeletonSyncInit(t *testing.T) { skeleton.Terminate() // Ensure the correct resulting sync status - var progress skeletonProgress - json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) - - if len(progress.Subchains) != len(tt.newstate) { - t.Errorf("test %d: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.newstate)) - continue - } - for j := 0; j < len(progress.Subchains); j++ { - if progress.Subchains[j].Head != tt.newstate[j].Head { - t.Errorf("test %d: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.newstate[j].Head) - } - if progress.Subchains[j].Tail != tt.newstate[j].Tail { - t.Errorf("test %d: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.newstate[j].Tail) - } + expect := skeletonExpect{state: tt.newstate} + if err := checkSkeletonProgress(db, false, nil, expect); err != nil { + t.Errorf("test %d: %v", i, err) } } } @@ -493,28 +483,36 @@ func TestSkeletonSyncExtend(t *testing.T) { skeleton.Terminate() // Ensure the correct resulting sync status - var progress skeletonProgress - json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) - - if len(progress.Subchains) != len(tt.newstate) { - t.Errorf("test %d: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.newstate)) - continue - } - for j := 0; j < len(progress.Subchains); j++ { - if progress.Subchains[j].Head != tt.newstate[j].Head { - t.Errorf("test %d: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.newstate[j].Head) - } - if progress.Subchains[j].Tail != tt.newstate[j].Tail { - t.Errorf("test %d: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.newstate[j].Tail) - } + expect := skeletonExpect{state: tt.newstate} + if err := checkSkeletonProgress(db, false, nil, expect); err != nil { + t.Errorf("test %d: %v", i, err) } } } +type skeletonExpect struct { + state []*subchain // Expected sync state after the post-init event + serve uint64 // Expected number of header retrievals after initial cycle + drop uint64 // Expected number of peers dropped after initial cycle +} + +type skeletonTest struct { + fill bool // Whether to run a real backfiller in this test case + unpredictable bool // Whether to ignore drops/serves due to uncertain packet assignments + + head *types.Header // New head header to announce to reorg to + peers []*skeletonTestPeer // Initial peer set to start the sync with + mid skeletonExpect + + newHead *types.Header // New header to anoint on top of the old one + newPeer *skeletonTestPeer // New peer to join the skeleton syncer + end skeletonExpect +} + // Tests that the skeleton sync correctly retrieves headers from one or more // peers without duplicates or other strange side effects. func TestSkeletonSyncRetrievals(t *testing.T) { - //log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + //log.SetDefault(log.NewLogger(log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false)))) // Since skeleton headers don't need to be meaningful, beyond a parent hash // progression, create a long fake chain to test with. @@ -537,22 +535,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) { Extra: []byte("B"), // force a different hash }) } - tests := []struct { - fill bool // Whether to run a real backfiller in this test case - unpredictable bool // Whether to ignore drops/serves due to uncertain packet assignments - - head *types.Header // New head header to announce to reorg to - peers []*skeletonTestPeer // Initial peer set to start the sync with - midstate []*subchain // Expected sync state after initial cycle - midserve uint64 // Expected number of header retrievals after initial cycle - middrop uint64 // Expected number of peers dropped after initial cycle - - newHead *types.Header // New header to anoint on top of the old one - newPeer *skeletonTestPeer // New peer to join the skeleton syncer - endstate []*subchain // Expected sync state after the post-init event - endserve uint64 // Expected number of header retrievals after the post-init event - enddrop uint64 // Expected number of peers dropped after the post-init event - }{ + tests := []skeletonTest{ // Completely empty database with only the genesis set. The sync is expected // to create a single subchain with the requested head. No peers however, so // the sync should be stuck without any progression. @@ -560,12 +543,16 @@ func TestSkeletonSyncRetrievals(t *testing.T) { // When a new peer is added, it should detect the join and fill the headers // to the genesis block. { - head: chain[len(chain)-1], - midstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: uint64(len(chain) - 1)}}, + head: chain[len(chain)-1], + mid: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: uint64(len(chain) - 1)}}, + }, - newPeer: newSkeletonTestPeer("test-peer", chain), - endstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - endserve: uint64(len(chain) - 2), // len - head - genesis + newPeer: newSkeletonTestPeer("test-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, }, // Completely empty database with only the genesis set. The sync is expected // to create a single subchain with the requested head. With one valid peer, @@ -573,14 +560,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { // // Adding a second peer should not have any effect. { - head: chain[len(chain)-1], - peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-1", chain)}, - midstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - midserve: uint64(len(chain) - 2), // len - head - genesis - - newPeer: newSkeletonTestPeer("test-peer-2", chain), - endstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - endserve: uint64(len(chain) - 2), // len - head - genesis + head: chain[len(chain)-1], + peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-1", chain)}, + mid: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, + + newPeer: newSkeletonTestPeer("test-peer-2", chain), + end: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, }, // Completely empty database with only the genesis set. The sync is expected // to create a single subchain with the requested head. With many valid peers, @@ -594,12 +585,16 @@ func TestSkeletonSyncRetrievals(t *testing.T) { newSkeletonTestPeer("test-peer-2", chain), newSkeletonTestPeer("test-peer-3", chain), }, - midstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - midserve: uint64(len(chain) - 2), // len - head - genesis + mid: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, - newPeer: newSkeletonTestPeer("test-peer-4", chain), - endstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - endserve: uint64(len(chain) - 2), // len - head - genesis + newPeer: newSkeletonTestPeer("test-peer-4", chain), + end: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, }, // This test checks if a peer tries to withhold a header - *on* the sync // boundary - instead of sending the requested amount. The malicious short @@ -611,14 +606,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peers: []*skeletonTestPeer{ newSkeletonTestPeer("header-skipper", append(append(append([]*types.Header{}, chain[:99]...), nil), chain[100:]...)), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 3, // len - head - genesis - missing - middrop: 1, // penalize shortened header deliveries + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 3, // len - head - genesis - missing + drop: 1, // penalize shortened header deliveries + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to withhold a header - *off* the sync // boundary - instead of sending the requested amount. The malicious short @@ -630,14 +629,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peers: []*skeletonTestPeer{ newSkeletonTestPeer("header-skipper", append(append(append([]*types.Header{}, chain[:50]...), nil), chain[51:]...)), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 3, // len - head - genesis - missing - middrop: 1, // penalize shortened header deliveries + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 3, // len - head - genesis - missing + drop: 1, // penalize shortened header deliveries + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to duplicate a header - *on* the sync // boundary - instead of sending the correct sequence. The malicious duped @@ -649,14 +652,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peers: []*skeletonTestPeer{ newSkeletonTestPeer("header-duper", append(append(append([]*types.Header{}, chain[:99]...), chain[98]), chain[100:]...)), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 2, // len - head - genesis - middrop: 1, // penalize invalid header sequences + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 2, // len - head - genesis + drop: 1, // penalize invalid header sequences + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to duplicate a header - *off* the sync // boundary - instead of sending the correct sequence. The malicious duped @@ -668,14 +675,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peers: []*skeletonTestPeer{ newSkeletonTestPeer("header-duper", append(append(append([]*types.Header{}, chain[:50]...), chain[49]), chain[51:]...)), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 2, // len - head - genesis - middrop: 1, // penalize invalid header sequences + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 2, // len - head - genesis + drop: 1, // penalize invalid header sequences + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to inject a different header - *on* // the sync boundary - instead of sending the correct sequence. The bad @@ -698,14 +709,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { ), ), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 2, // len - head - genesis - middrop: 1, // different set of headers, drop // TODO(karalabe): maybe just diff sync? + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 2, // len - head - genesis + drop: 1, // different set of headers, drop // TODO(karalabe): maybe just diff sync? + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to inject a different header - *off* // the sync boundary - instead of sending the correct sequence. The bad @@ -728,14 +743,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { ), ), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 2, // len - head - genesis - middrop: 1, // different set of headers, drop + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 2, // len - head - genesis + drop: 1, // different set of headers, drop + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test reproduces a bug caught during review (kudos to @holiman) // where a subchain is merged with a previously interrupted one, causing @@ -765,12 +784,16 @@ func TestSkeletonSyncRetrievals(t *testing.T) { return nil // Fallback to default behavior, just delayed }), }, - midstate: []*subchain{{Head: 2 * requestHeaders, Tail: 1}}, - midserve: 2*requestHeaders - 1, // len - head - genesis + mid: skeletonExpect{ + state: []*subchain{{Head: 2 * requestHeaders, Tail: 1}}, + serve: 2*requestHeaders - 1, // len - head - genesis + }, - newHead: chain[2*requestHeaders+2], - endstate: []*subchain{{Head: 2*requestHeaders + 2, Tail: 1}}, - endserve: 4 * requestHeaders, + newHead: chain[2*requestHeaders+2], + end: skeletonExpect{ + state: []*subchain{{Head: 2*requestHeaders + 2, Tail: 1}}, + serve: 4 * requestHeaders, + }, }, // This test reproduces a bug caught by (@rjl493456442) where a skeleton // header goes missing, causing the sync to get stuck and/or panic. @@ -792,13 +815,17 @@ func TestSkeletonSyncRetrievals(t *testing.T) { fill: true, unpredictable: true, // We have good and bad peer too, bad may be dropped, test too short for certainty - head: chain[len(chain)/2+1], // Sync up until the sidechain common ancestor + 2 - peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-oldchain", chain)}, - midstate: []*subchain{{Head: uint64(len(chain)/2 + 1), Tail: 1}}, + head: chain[len(chain)/2+1], // Sync up until the sidechain common ancestor + 2 + peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-oldchain", chain)}, + mid: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain)/2 + 1), Tail: 1}}, + }, - newHead: sidechain[len(sidechain)/2+3], // Sync up until the sidechain common ancestor + 4 - newPeer: newSkeletonTestPeer("test-peer-newchain", sidechain), - endstate: []*subchain{{Head: uint64(len(sidechain)/2 + 3), Tail: uint64(len(chain) / 2)}}, + newHead: sidechain[len(sidechain)/2+3], // Sync up until the sidechain common ancestor + 4 + newPeer: newSkeletonTestPeer("test-peer-newchain", sidechain), + end: skeletonExpect{ + state: []*subchain{{Head: uint64(len(sidechain)/2 + 3), Tail: uint64(len(chain) / 2)}}, + }, }, } for i, tt := range tests { @@ -861,115 +888,83 @@ func TestSkeletonSyncRetrievals(t *testing.T) { skeleton := newSkeleton(db, peerset, drop, filler) skeleton.Sync(tt.head, nil, true) - var progress skeletonProgress // Wait a bit (bleah) for the initial sync loop to go to idle. This might // be either a finish or a never-start hence why there's no event to hook. - check := func() error { - if len(progress.Subchains) != len(tt.midstate) { - return fmt.Errorf("test %d, mid state: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.midstate)) - } - for j := 0; j < len(progress.Subchains); j++ { - if progress.Subchains[j].Head != tt.midstate[j].Head { - return fmt.Errorf("test %d, mid state: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.midstate[j].Head) - } - if progress.Subchains[j].Tail != tt.midstate[j].Tail { - return fmt.Errorf("test %d, mid state: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.midstate[j].Tail) - } - } - return nil - } - waitStart := time.Now() for waitTime := 20 * time.Millisecond; time.Since(waitStart) < 2*time.Second; waitTime = waitTime * 2 { time.Sleep(waitTime) - // Check the post-init end state if it matches the required results - json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) - if err := check(); err == nil { + if err := checkSkeletonProgress(db, tt.unpredictable, tt.peers, tt.mid); err == nil { break } } - if err := check(); err != nil { - t.Error(err) + if err := checkSkeletonProgress(db, tt.unpredictable, tt.peers, tt.mid); err != nil { + t.Errorf("test %d, mid: %v", i, err) continue } - if !tt.unpredictable { - var served uint64 - for _, peer := range tt.peers { - served += peer.served.Load() - } - if served != tt.midserve { - t.Errorf("test %d, mid state: served headers mismatch: have %d, want %d", i, served, tt.midserve) - } - var drops uint64 - for _, peer := range tt.peers { - drops += peer.dropped.Load() - } - if drops != tt.middrop { - t.Errorf("test %d, mid state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) - } - } + // Apply the post-init events if there's any - if tt.newHead != nil { - skeleton.Sync(tt.newHead, nil, true) - } + endpeers := tt.peers if tt.newPeer != nil { if err := peerset.Register(newPeerConnection(tt.newPeer.id, eth.ETH68, tt.newPeer, log.New("id", tt.newPeer.id))); err != nil { t.Errorf("test %d: failed to register new peer: %v", i, err) } + time.Sleep(time.Millisecond * 50) // given time for peer registration + endpeers = append(tt.peers, tt.newPeer) + } + if tt.newHead != nil { + skeleton.Sync(tt.newHead, nil, true) } + // Wait a bit (bleah) for the second sync loop to go to idle. This might // be either a finish or a never-start hence why there's no event to hook. - check = func() error { - if len(progress.Subchains) != len(tt.endstate) { - return fmt.Errorf("test %d, end state: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.endstate)) - } - for j := 0; j < len(progress.Subchains); j++ { - if progress.Subchains[j].Head != tt.endstate[j].Head { - return fmt.Errorf("test %d, end state: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.endstate[j].Head) - } - if progress.Subchains[j].Tail != tt.endstate[j].Tail { - return fmt.Errorf("test %d, end state: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.endstate[j].Tail) - } - } - return nil - } waitStart = time.Now() for waitTime := 20 * time.Millisecond; time.Since(waitStart) < 2*time.Second; waitTime = waitTime * 2 { time.Sleep(waitTime) - // Check the post-init end state if it matches the required results - json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) - if err := check(); err == nil { + if err := checkSkeletonProgress(db, tt.unpredictable, endpeers, tt.end); err == nil { break } } - if err := check(); err != nil { - t.Error(err) + if err := checkSkeletonProgress(db, tt.unpredictable, endpeers, tt.end); err != nil { + t.Errorf("test %d, end: %v", i, err) continue } // Check that the peers served no more headers than we actually needed - if !tt.unpredictable { - served := uint64(0) - for _, peer := range tt.peers { - served += peer.served.Load() - } - if tt.newPeer != nil { - served += tt.newPeer.served.Load() - } - if served != tt.endserve { - t.Errorf("test %d, end state: served headers mismatch: have %d, want %d", i, served, tt.endserve) - } - drops := uint64(0) - for _, peer := range tt.peers { - drops += peer.dropped.Load() - } - if tt.newPeer != nil { - drops += tt.newPeer.dropped.Load() - } - if drops != tt.enddrop { - t.Errorf("test %d, end state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) - } - } // Clean up any leftover skeleton sync resources skeleton.Terminate() } } + +func checkSkeletonProgress(db ethdb.KeyValueReader, unpredictable bool, peers []*skeletonTestPeer, expected skeletonExpect) error { + var progress skeletonProgress + // Check the post-init end state if it matches the required results + json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) + + if len(progress.Subchains) != len(expected.state) { + return fmt.Errorf("subchain count mismatch: have %d, want %d", len(progress.Subchains), len(expected.state)) + } + for j := 0; j < len(progress.Subchains); j++ { + if progress.Subchains[j].Head != expected.state[j].Head { + return fmt.Errorf("subchain %d head mismatch: have %d, want %d", j, progress.Subchains[j].Head, expected.state[j].Head) + } + if progress.Subchains[j].Tail != expected.state[j].Tail { + return fmt.Errorf("subchain %d tail mismatch: have %d, want %d", j, progress.Subchains[j].Tail, expected.state[j].Tail) + } + } + if !unpredictable { + var served uint64 + for _, peer := range peers { + served += peer.served.Load() + } + if served != expected.serve { + return fmt.Errorf("served headers mismatch: have %d, want %d", served, expected.serve) + } + var drops uint64 + for _, peer := range peers { + drops += peer.dropped.Load() + } + if drops != expected.drop { + return fmt.Errorf("dropped peers mismatch: have %d, want %d", drops, expected.drop) + } + } + return nil +} From ea6c16007c30468ad92c45a13ba1d74514f2d9cf Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 28 May 2024 13:12:46 +0200 Subject: [PATCH 294/571] eth/tracers: clear error for non-reverting pre-homestead fail (#29824) --- .../call_tracer_withLog/frontier_create_outofstorage.json | 3 ++- eth/tracers/native/call.go | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json index c46fe080f7f2..a9092bbcf02a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json @@ -80,8 +80,9 @@ "from": "0x0047a8033cc6d6ca2ed5044674fd421f44884de8", "gas": "0x1b7740", "gasUsed": "0x9274f", + "to": "0xc24431c1a1147456414355b1f1769de450e524da", "input": "0x606060405260018054600160a060020a0319163317905561036f600360609081527f55524c0000000000000000000000000000000000000000000000000000000000608052610120604052604c60a09081527f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707560c0527f626c69632f5469636b65723f706169723d455448584254292e726573756c742e60e0527f58455448585842542e632e3000000000000000000000000000000000000000006101005261037d919062030d417f38cc483100000000000000000000000000000000000000000000000000000000610120908152600090731d11e5eae3112dbd44f99266872ff1d07c77dce89081906338cc4831906101249060209060048188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc8887604051837c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156102255780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f11561000257505060405180517f385928320000000000000000000000000000000000000000000000000000000082526004828101888152606484018a90526080602485018181528d5160848701528d519496508a958e958e958e9594604484019360a40192909181908490829085908e906020601f850104600302600f01f150905090810190601f1680156102e65780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561033f5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151979650505050505050565b611af2806103806000396000f35b5056606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b5056", - "error": "contract creation code storage out of gas", + "output": "0x606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b5056", "calls": [ { "from": "0xc24431c1a1147456414355b1f1769de450e524da", diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 3b6350658038..2b84ecaf4057 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -74,6 +74,11 @@ func (f callFrame) failed() bool { func (f *callFrame) processOutput(output []byte, err error, reverted bool) { output = common.CopyBytes(output) + // Clear error if tx wasn't reverted. This happened + // for pre-homestead contract storage OOG. + if err != nil && !reverted { + err = nil + } if err == nil { f.Output = output return From caafa93598927303d8dbe0aa53bf43ca08632805 Mon Sep 17 00:00:00 2001 From: trillo Date: Tue, 28 May 2024 20:44:40 +0900 Subject: [PATCH 295/571] all: improve some error strings (#29842) --- beacon/types/exec_payload.go | 2 +- cmd/clef/main.go | 2 +- core/chain_indexer_test.go | 2 +- core/types/transaction_test.go | 2 +- eth/backend.go | 2 +- eth/catalyst/api_test.go | 6 +++--- log/logger_test.go | 6 +++--- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/beacon/types/exec_payload.go b/beacon/types/exec_payload.go index 4448f854ad12..b159687dfcc5 100644 --- a/beacon/types/exec_payload.go +++ b/beacon/types/exec_payload.go @@ -65,7 +65,7 @@ func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*typ block := types.NewBlockWithHeader(&header).WithBody(types.Body{Transactions: transactions, Withdrawals: withdrawals}) if hash := block.Hash(); hash != expectedHash { - return nil, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash) + return nil, fmt.Errorf("sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash) } return block, nil } diff --git a/cmd/clef/main.go b/cmd/clef/main.go index f9b00e4a12a0..88d4c99e785a 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -552,7 +552,7 @@ func listWallets(c *cli.Context) error { // accountImport imports a raw hexadecimal private key via CLI. func accountImport(c *cli.Context) error { if c.Args().Len() != 1 { - return errors.New(" must be given as first argument.") + return errors.New(" must be given as first argument") } internalApi, ui, err := initInternalApi(c) if err != nil { diff --git a/core/chain_indexer_test.go b/core/chain_indexer_test.go index f09960901558..bf3bde756cb9 100644 --- a/core/chain_indexer_test.go +++ b/core/chain_indexer_test.go @@ -228,7 +228,7 @@ func (b *testChainIndexBackend) Process(ctx context.Context, header *types.Heade b.t.Error("Unexpected call to Process") // Can't use Fatal since this is not the test's goroutine. // Returning error stops the chainIndexer's updateLoop - return errors.New("Unexpected call to Process") + return errors.New("unexpected call to Process") case b.processCh <- header.Number.Uint64(): } return nil diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 361b977611c2..5dbf367073b5 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -379,7 +379,7 @@ func assertEqual(orig *Transaction, cpy *Transaction) error { } if orig.AccessList() != nil { if !reflect.DeepEqual(orig.AccessList(), cpy.AccessList()) { - return errors.New("access list wrong!") + return errors.New("access list wrong") } } return nil diff --git a/eth/backend.go b/eth/backend.go index e616b5f2f195..97e68b8cf01c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -208,7 +208,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig) if err != nil { - return nil, fmt.Errorf("Failed to create tracer %s: %v", config.VMTrace, err) + return nil, fmt.Errorf("failed to create tracer %s: %v", config.VMTrace, err) } vmConfig.Tracer = t } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 0586959f0633..64e6684be155 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -979,11 +979,11 @@ func TestSimultaneousNewBlock(t *testing.T) { defer wg.Done() if newResp, err := api.NewPayloadV1(*execData); err != nil { errMu.Lock() - testErr = fmt.Errorf("Failed to insert block: %w", err) + testErr = fmt.Errorf("failed to insert block: %w", err) errMu.Unlock() } else if newResp.Status != "VALID" { errMu.Lock() - testErr = fmt.Errorf("Failed to insert block: %v", newResp.Status) + testErr = fmt.Errorf("failed to insert block: %v", newResp.Status) errMu.Unlock() } }() @@ -1018,7 +1018,7 @@ func TestSimultaneousNewBlock(t *testing.T) { defer wg.Done() if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { errMu.Lock() - testErr = fmt.Errorf("Failed to insert block: %w", err) + testErr = fmt.Errorf("failed to insert block: %w", err) errMu.Unlock() } }() diff --git a/log/logger_test.go b/log/logger_test.go index 2ea08585475d..6f415eb471d2 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -97,7 +97,7 @@ func benchmarkLogger(b *testing.B, l Logger) { tt = time.Now() bigint = big.NewInt(100) nilbig *big.Int - err = errors.New("Oh nooes it's crap") + err = errors.New("oh nooes it's crap") ) b.ReportAllocs() b.ResetTimer() @@ -126,7 +126,7 @@ func TestLoggerOutput(t *testing.T) { tt = time.Time{} bigint = big.NewInt(100) nilbig *big.Int - err = errors.New("Oh nooes it's crap") + err = errors.New("oh nooes it's crap") smallUint = uint256.NewInt(500_000) bigUint = &uint256.Int{0xff, 0xff, 0xff, 0xff} ) @@ -150,7 +150,7 @@ func TestLoggerOutput(t *testing.T) { have := out.String() t.Logf("output %v", out.String()) - want := `INFO [11-07|19:14:33.821] This is a message foo=123 bytes="[0 0 0 0 0 0 0 0 0 0]" bonk="a string with text" time=0001-01-01T00:00:00+0000 bigint=100 nilbig= err="Oh nooes it's crap" struct="{A:Foo B:12}" struct="{A:Foo\nLinebreak B:122}" ptrstruct="&{A:Foo B:12}" smalluint=500,000 bigUint=1,600,660,942,523,603,594,864,898,306,482,794,244,293,965,082,972,225,630,372,095 + want := `INFO [11-07|19:14:33.821] This is a message foo=123 bytes="[0 0 0 0 0 0 0 0 0 0]" bonk="a string with text" time=0001-01-01T00:00:00+0000 bigint=100 nilbig= err="oh nooes it's crap" struct="{A:Foo B:12}" struct="{A:Foo\nLinebreak B:122}" ptrstruct="&{A:Foo B:12}" smalluint=500,000 bigUint=1,600,660,942,523,603,594,864,898,306,482,794,244,293,965,082,972,225,630,372,095 ` if !bytes.Equal([]byte(have)[25:], []byte(want)[25:]) { t.Errorf("Error\nhave: %q\nwant: %q", have, want) From 42471d7a3e78296ed99b3d9ac804385931f80ec5 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 28 May 2024 13:45:16 +0200 Subject: [PATCH 296/571] core/vm/runtime: set random to enable merge-opcodes (#29799) --- core/vm/runtime/runtime.go | 45 +++++++++++++++++++++------------ core/vm/runtime/runtime_test.go | 6 ++--- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index b587d6d5a044..1181e5fccdc3 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -57,24 +57,33 @@ type Config struct { // sets defaults on the config func setDefaults(cfg *Config) { if cfg.ChainConfig == nil { + var ( + shanghaiTime = uint64(0) + cancunTime = uint64(0) + ) cfg.ChainConfig = ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: new(big.Int), - DAOForkBlock: new(big.Int), - DAOForkSupport: false, - EIP150Block: new(big.Int), - EIP155Block: new(big.Int), - EIP158Block: new(big.Int), - ByzantiumBlock: new(big.Int), - ConstantinopleBlock: new(big.Int), - PetersburgBlock: new(big.Int), - IstanbulBlock: new(big.Int), - MuirGlacierBlock: new(big.Int), - BerlinBlock: new(big.Int), - LondonBlock: new(big.Int), - } + ChainID: big.NewInt(1), + HomesteadBlock: new(big.Int), + DAOForkBlock: new(big.Int), + DAOForkSupport: false, + EIP150Block: new(big.Int), + EIP155Block: new(big.Int), + EIP158Block: new(big.Int), + ByzantiumBlock: new(big.Int), + ConstantinopleBlock: new(big.Int), + PetersburgBlock: new(big.Int), + IstanbulBlock: new(big.Int), + MuirGlacierBlock: new(big.Int), + BerlinBlock: new(big.Int), + LondonBlock: new(big.Int), + ArrowGlacierBlock: nil, + GrayGlacierBlock: nil, + TerminalTotalDifficulty: big.NewInt(0), + TerminalTotalDifficultyPassed: true, + MergeNetsplitBlock: nil, + ShanghaiTime: &shanghaiTime, + CancunTime: &cancunTime} } - if cfg.Difficulty == nil { cfg.Difficulty = new(big.Int) } @@ -101,6 +110,10 @@ func setDefaults(cfg *Config) { if cfg.BlobBaseFee == nil { cfg.BlobBaseFee = big.NewInt(params.BlobTxMinBlobGasprice) } + // Merge indicators + if t := cfg.ChainConfig.ShanghaiTime; cfg.ChainConfig.TerminalTotalDifficultyPassed || (t != nil && *t == 0) { + cfg.Random = &(common.Hash{}) + } } // Execute executes the code using the input as call data during the execution. diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 45228e78c41a..04abc5480eac 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -105,7 +105,7 @@ func TestExecute(t *testing.T) { func TestCall(t *testing.T) { state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - address := common.HexToAddress("0x0a") + address := common.HexToAddress("0xaa") state.SetCode(address, []byte{ byte(vm.PUSH1), 10, byte(vm.PUSH1), 0, @@ -725,7 +725,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.CREATE), byte(vm.POP), }, - results: []string{`"1,1,952855,6,12"`, `"1,1,952855,6,0"`}, + results: []string{`"1,1,952853,6,12"`, `"1,1,952853,6,0"`}, }, { // CREATE2 @@ -741,7 +741,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.CREATE2), byte(vm.POP), }, - results: []string{`"1,1,952846,6,13"`, `"1,1,952846,6,0"`}, + results: []string{`"1,1,952844,6,13"`, `"1,1,952844,6,0"`}, }, { // CALL From 871e55d93e8b0aeb85c71eff4adf1460547b01d0 Mon Sep 17 00:00:00 2001 From: gitglorythegreat Date: Tue, 28 May 2024 20:10:27 +0800 Subject: [PATCH 297/571] core/state: fix typos in comments (#29767) --- core/state/state_object.go | 6 +++--- core/state/trie_prefetcher.go | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 85cb8b44de35..4011425c2a8d 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -127,7 +127,7 @@ func (s *stateObject) touch() { } } -// getTrie returns the associated storage trie. The trie will be opened if it' +// getTrie returns the associated storage trie. The trie will be opened if it's // not loaded previously. An error will be returned if trie can't be loaded. // // If a new trie is opened, it will be cached within the state object to allow @@ -156,7 +156,7 @@ func (s *stateObject) getPrefetchedTrie() (Trie, error) { if s.data.Root == types.EmptyRootHash || s.db.prefetcher == nil { return nil, nil } - // Attempt to retrieve the trie from the pretecher + // Attempt to retrieve the trie from the prefetcher return s.db.prefetcher.trie(s.addrHash, s.data.Root) } @@ -311,7 +311,7 @@ func (s *stateObject) updateTrie() (Trie, error) { if len(s.pendingStorage) == 0 { return s.trie, nil } - // Retrieve a pretecher populated trie, or fall back to the database + // Retrieve a prefetcher populated trie, or fall back to the database tr, err := s.getPrefetchedTrie() switch { case err != nil: diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 7e08964e41bf..0b45660ac146 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -72,7 +72,7 @@ func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePre } } -// terminate iterates over all the subfetchers and issues a terminateion request +// terminate iterates over all the subfetchers and issues a termination request // to all of them. Depending on the async parameter, the method will either block // until all subfetchers spin down, or return immediately. func (p *triePrefetcher) terminate(async bool) { @@ -234,7 +234,7 @@ func (sf *subfetcher) schedule(keys [][]byte) error { case sf.wake <- struct{}{}: // Wake signal sent default: - // Wake signal not sent as a previous is already queued + // Wake signal not sent as a previous one is already queued } return nil } @@ -250,7 +250,7 @@ func (sf *subfetcher) wait() { // peeks for the original data. The method will block until all the scheduled // data has been loaded and the fethcer terminated. func (sf *subfetcher) peek() Trie { - // Block until the fertcher terminates, then retrieve the trie + // Block until the fetcher terminates, then retrieve the trie sf.wait() return sf.trie } @@ -296,7 +296,7 @@ func (sf *subfetcher) loop() { for { select { case <-sf.wake: - // Execute all remaining tasks in single run + // Execute all remaining tasks in a single run sf.lock.Lock() tasks := sf.tasks sf.tasks = nil From 61932e47106168a4eeb93ee68211752a25e031c5 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 28 May 2024 14:16:45 +0200 Subject: [PATCH 298/571] cmd/geth: update testdata (vulncheck) (#29714) --- cmd/geth/testdata/vcheck/vulnerabilities.json | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/cmd/geth/testdata/vcheck/vulnerabilities.json b/cmd/geth/testdata/vcheck/vulnerabilities.json index bee0e66dd8e5..31a34de6beb2 100644 --- a/cmd/geth/testdata/vcheck/vulnerabilities.json +++ b/cmd/geth/testdata/vcheck/vulnerabilities.json @@ -166,5 +166,37 @@ "severity": "Low", "CVE": "CVE-2022-29177", "check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16)-.*)$" + }, + { + "name": "DoS via malicious p2p message", + "uid": "GETH-2023-01", + "summary": "A vulnerable node can be made to consume unbounded amounts of memory when handling specially crafted p2p messages sent from an attacker node.", + "description": "The p2p handler spawned a new goroutine to respond to ping requests. By flooding a node with ping requests, an unbounded number of goroutines can be created, leading to resource exhaustion and potentially crash due to OOM.", + "links": [ + "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-ppjg-v974-84cm", + "https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities" + ], + "introduced": "v1.10.0", + "fixed": "v1.12.1", + "published": "2023-09-06", + "severity": "High", + "CVE": "CVE-2023-40591", + "check": "(Geth\\/v1\\.(10|11)\\..*)|(Geth\\/v1\\.12\\.0-.*)$" + }, + { + "name": "DoS via malicious p2p message", + "uid": "GETH-2024-01", + "summary": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node.", + "description": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node. Full details will be available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652)", + "links": [ + "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652", + "https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities" + ], + "introduced": "v1.10.0", + "fixed": "v1.13.15", + "published": "2024-05-06", + "severity": "High", + "CVE": "CVE-2024-32972", + "check": "(Geth\\/v1\\.(10|11|12)\\..*)|(Geth\\/v1\\.13\\.\\d-.*)|(Geth\\/v1\\.13\\.1(0|1|2|3|4)-.*)$" } ] From b88051ec83bba7882b59ab9cee573a9c111063e9 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 28 May 2024 20:41:11 +0800 Subject: [PATCH 299/571] core/rawdb, triedb/pathdb: fix freezer read-only option (#29823) --- core/rawdb/freezer_resettable.go | 19 ++++++++++++------- triedb/pathdb/database.go | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/core/rawdb/freezer_resettable.go b/core/rawdb/freezer_resettable.go index 7fa59b8d2196..6f8541f43bfc 100644 --- a/core/rawdb/freezer_resettable.go +++ b/core/rawdb/freezer_resettable.go @@ -33,10 +33,11 @@ type freezerOpenFunc = func() (*Freezer, error) // resettableFreezer is a wrapper of the freezer which makes the // freezer resettable. type resettableFreezer struct { - freezer *Freezer - opener freezerOpenFunc - datadir string - lock sync.RWMutex + readOnly bool + freezer *Freezer + opener freezerOpenFunc + datadir string + lock sync.RWMutex } // newResettableFreezer creates a resettable freezer, note freezer is @@ -60,9 +61,10 @@ func newResettableFreezer(datadir string, namespace string, readonly bool, maxTa return nil, err } return &resettableFreezer{ - freezer: freezer, - opener: opener, - datadir: datadir, + readOnly: readonly, + freezer: freezer, + opener: opener, + datadir: datadir, }, nil } @@ -74,6 +76,9 @@ func (f *resettableFreezer) Reset() error { f.lock.Lock() defer f.lock.Unlock() + if f.readOnly { + return errReadOnly + } if err := f.freezer.Close(); err != nil { return err } diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 05a28aa1efa6..bd6aeaa6abe4 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -190,7 +190,7 @@ func (db *Database) repairHistory() error { // all of them. Fix the tests first. return nil } - freezer, err := rawdb.NewStateFreezer(ancient, false) + freezer, err := rawdb.NewStateFreezer(ancient, db.readOnly) if err != nil { log.Crit("Failed to open state history freezer", "err", err) } From af0a3274be0f948f4816142394559f2d02475980 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 28 May 2024 18:13:03 +0200 Subject: [PATCH 300/571] p2p/discover: fix crash when revalidated node is removed (#29864) In #29572, I assumed the revalidation list that the node is contained in could only ever be changed by the outcome of a revalidation request. But turns out that's not true: if the node gets removed due to FINDNODE failure, it will also be removed from the list it is in. This causes a crash. The invariant is: while node is in table, it is always in exactly one of the two lists. So it seems best to store a pointer to the current list within the node itself. --- p2p/discover/node.go | 1 + p2p/discover/table_reval.go | 74 ++++++++++++++++++++------------ p2p/discover/table_reval_test.go | 70 ++++++++++++++++++++++++++++++ p2p/discover/table_util_test.go | 8 +++- 4 files changed, 125 insertions(+), 28 deletions(-) create mode 100644 p2p/discover/table_reval_test.go diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 47df09e883da..47788248f438 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -41,6 +41,7 @@ type BucketNode struct { // The fields of Node may not be modified. type node struct { *enode.Node + revalList *revalidationList addedToTable time.Time // first time node was added to bucket or replacement list addedToBucket time.Time // time it was added in the actual bucket livenessChecks uint // how often liveness was checked diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index 9a13900ebca4..01a5bdb6fa52 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -39,7 +39,6 @@ type tableRevalidation struct { type revalidationResponse struct { n *node newRecord *enode.Node - list *revalidationList didRespond bool } @@ -60,9 +59,10 @@ func (tr *tableRevalidation) nodeAdded(tab *Table, n *node) { // nodeRemoved is called when a node was removed from the table. func (tr *tableRevalidation) nodeRemoved(n *node) { - if !tr.fast.remove(n) { - tr.slow.remove(n) + if n.revalList == nil { + panic(fmt.Errorf("removed node %v has nil revalList", n.ID())) } + n.revalList.remove(n) } // run performs node revalidation. @@ -70,11 +70,11 @@ func (tr *tableRevalidation) nodeRemoved(n *node) { // to schedule a timer. However, run can be called at any time. func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mclock.AbsTime) { if n := tr.fast.get(now, &tab.rand, tr.activeReq); n != nil { - tr.startRequest(tab, &tr.fast, n) + tr.startRequest(tab, n) tr.fast.schedule(now, &tab.rand) } if n := tr.slow.get(now, &tab.rand, tr.activeReq); n != nil { - tr.startRequest(tab, &tr.slow, n) + tr.startRequest(tab, n) tr.slow.schedule(now, &tab.rand) } @@ -82,12 +82,12 @@ func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mcloc } // startRequest spawns a revalidation request for node n. -func (tr *tableRevalidation) startRequest(tab *Table, list *revalidationList, n *node) { +func (tr *tableRevalidation) startRequest(tab *Table, n *node) { if _, ok := tr.activeReq[n.ID()]; ok { - panic(fmt.Errorf("duplicate startRequest (list %q, node %v)", list.name, n.ID())) + panic(fmt.Errorf("duplicate startRequest (node %v)", n.ID())) } tr.activeReq[n.ID()] = struct{}{} - resp := revalidationResponse{n: n, list: list} + resp := revalidationResponse{n: n} // Fetch the node while holding lock. tab.mutex.Lock() @@ -120,11 +120,28 @@ func (tab *Table) doRevalidate(resp revalidationResponse, node *enode.Node) { // handleResponse processes the result of a revalidation request. func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationResponse) { - now := tab.cfg.Clock.Now() - n := resp.n - b := tab.bucket(n.ID()) + var ( + now = tab.cfg.Clock.Now() + n = resp.n + b = tab.bucket(n.ID()) + ) delete(tr.activeReq, n.ID()) + // If the node was removed from the table while getting checked, we need to stop + // processing here to avoid re-adding it. + if n.revalList == nil { + return + } + + // Store potential seeds in database. + // This is done via defer to avoid holding Table lock while writing to DB. + defer func() { + if n.isValidatedLive && n.livenessChecks > 5 { + tab.db.UpdateNode(resp.n.Node) + } + }() + + // Remaining logic needs access to Table internals. tab.mutex.Lock() defer tab.mutex.Unlock() @@ -134,7 +151,7 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons if n.livenessChecks <= 0 { tab.deleteInBucket(b, n.ID()) } else { - tr.moveToList(&tr.fast, resp.list, n, now, &tab.rand) + tr.moveToList(&tr.fast, n, now, &tab.rand) } return } @@ -151,27 +168,23 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons n.isValidatedLive = false } } - tab.log.Debug("Revalidated node", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", resp.list.name) + tab.log.Debug("Revalidated node", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList) // Move node over to slow queue after first validation. if !endpointChanged { - tr.moveToList(&tr.slow, resp.list, n, now, &tab.rand) + tr.moveToList(&tr.slow, n, now, &tab.rand) } else { - tr.moveToList(&tr.fast, resp.list, n, now, &tab.rand) - } - - // Store potential seeds in database. - if n.isValidatedLive && n.livenessChecks > 5 { - tab.db.UpdateNode(resp.n.Node) + tr.moveToList(&tr.fast, n, now, &tab.rand) } } -func (tr *tableRevalidation) moveToList(dest, source *revalidationList, n *node, now mclock.AbsTime, rand randomSource) { - if source == dest { +// moveToList ensures n is in the 'dest' list. +func (tr *tableRevalidation) moveToList(dest *revalidationList, n *node, now mclock.AbsTime, rand randomSource) { + if n.revalList == dest { return } - if !source.remove(n) { - panic(fmt.Errorf("moveToList(%q -> %q): node %v not in source list", source.name, dest.name, n.ID())) + if n.revalList != nil { + n.revalList.remove(n) } dest.push(n, now, rand) } @@ -208,16 +221,23 @@ func (list *revalidationList) push(n *node, now mclock.AbsTime, rand randomSourc if list.nextTime == never { list.schedule(now, rand) } + n.revalList = list } -func (list *revalidationList) remove(n *node) bool { +func (list *revalidationList) remove(n *node) { i := slices.Index(list.nodes, n) if i == -1 { - return false + panic(fmt.Errorf("node %v not found in list", n.ID())) } list.nodes = slices.Delete(list.nodes, i, i+1) if len(list.nodes) == 0 { list.nextTime = never } - return true + n.revalList = nil +} + +func (list *revalidationList) contains(id enode.ID) bool { + return slices.ContainsFunc(list.nodes, func(n *node) bool { + return n.ID() == id + }) } diff --git a/p2p/discover/table_reval_test.go b/p2p/discover/table_reval_test.go new file mode 100644 index 000000000000..3adf577ae444 --- /dev/null +++ b/p2p/discover/table_reval_test.go @@ -0,0 +1,70 @@ +// Copyright 2024 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 discover + +import ( + "net" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" +) + +// This test checks that revalidation can handle a node disappearing while +// a request is active. +func TestRevalidationNodeRemoved(t *testing.T) { + var ( + clock mclock.Simulated + transport = newPingRecorder() + tab, db = newInactiveTestTable(transport, Config{Clock: &clock}) + tr = &tab.revalidation + ) + defer db.Close() + + // Fill a bucket. + node := nodeAtDistance(tab.self().ID(), 255, net.IP{77, 88, 99, 1}) + tab.handleAddNode(addNodeOp{node: node}) + + // Start a revalidation request. Schedule once to get the next start time, + // then advance the clock to that point and schedule again to start. + next := tr.run(tab, clock.Now()) + clock.Run(time.Duration(next + 1)) + tr.run(tab, clock.Now()) + if len(tr.activeReq) != 1 { + t.Fatal("revalidation request did not start:", tr.activeReq) + } + + // Delete the node. + tab.deleteInBucket(tab.bucket(node.ID()), node.ID()) + + // Now finish the revalidation request. + var resp revalidationResponse + select { + case resp = <-tab.revalResponseCh: + case <-time.After(1 * time.Second): + t.Fatal("timed out waiting for revalidation") + } + tr.handleResponse(tab, resp) + + // Ensure the node was not re-added to the table. + if tab.getNode(node.ID()) != nil { + t.Fatal("node was re-added to Table") + } + if tr.fast.contains(node.ID()) || tr.slow.contains(node.ID()) { + t.Fatal("removed node contained in revalidation list") + } +} diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 86c60480948a..59045bf2a84d 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -43,9 +43,15 @@ func init() { } func newTestTable(t transport, cfg Config) (*Table, *enode.DB) { + tab, db := newInactiveTestTable(t, cfg) + go tab.loop() + return tab, db +} + +// newInactiveTestTable creates a Table without running the main loop. +func newInactiveTestTable(t transport, cfg Config) (*Table, *enode.DB) { db, _ := enode.OpenDB("") tab, _ := newTable(t, db, cfg) - go tab.loop() return tab, db } From e517183719dab4214aa74a9a19ff005ab77c36e1 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 28 May 2024 10:52:08 -0700 Subject: [PATCH 301/571] eth, eth/downloader: remove references to LightChain, LightSync (#29711) Co-authored-by: Gary Rong --- eth/backend.go | 4 -- eth/downloader/beaconsync.go | 6 +-- eth/downloader/downloader.go | 65 ++++++++++++------------------- eth/downloader/downloader_test.go | 44 +++++++-------------- eth/downloader/modes.go | 15 ++----- eth/handler.go | 2 +- 6 files changed, 46 insertions(+), 90 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 97e68b8cf01c..798ffa600b47 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -19,7 +19,6 @@ package eth import ( "encoding/json" - "errors" "fmt" "math/big" "runtime" @@ -105,9 +104,6 @@ type Ethereum struct { // whose lifecycle will be managed by the provided node. func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // Ensure configuration values are compatible and sane - if config.SyncMode == downloader.LightSync { - return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated") - } if !config.SyncMode.IsValid() { return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) } diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 8088f16af918..57c6eee40a0b 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -202,7 +202,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { case SnapSync: chainHead = d.blockchain.CurrentSnapBlock() default: - chainHead = d.lightchain.CurrentHeader() + panic("unknown sync mode") } number := chainHead.Number.Uint64() @@ -222,7 +222,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { case SnapSync: linked = d.blockchain.HasFastBlock(beaconTail.ParentHash, beaconTail.Number.Uint64()-1) default: - linked = d.blockchain.HasHeader(beaconTail.ParentHash, beaconTail.Number.Uint64()-1) + panic("unknown sync mode") } if !linked { // This is a programming error. The chain backfiller was called with a @@ -257,7 +257,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { case SnapSync: known = d.blockchain.HasFastBlock(h.Hash(), n) default: - known = d.lightchain.HasHeader(h.Hash(), n) + panic("unknown sync mode") } if !known { end = check diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index bb083260e459..d147414859f2 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -67,7 +67,6 @@ var ( errCancelContentProcessing = errors.New("content processing canceled (requested)") errCanceled = errors.New("syncing canceled (requested)") errNoPivotHeader = errors.New("pivot header is not found") - ErrMergeTransition = errors.New("legacy sync reached the merge") ) // peerDropFn is a callback type for dropping a peer detected as malicious. @@ -98,7 +97,6 @@ type Downloader struct { syncStatsChainHeight uint64 // Highest block number known when syncing started syncStatsLock sync.RWMutex // Lock protecting the sync stats fields - lightchain LightChain blockchain BlockChain // Callbacks @@ -143,8 +141,8 @@ type Downloader struct { syncLogTime time.Time // Time instance when status was last reported } -// LightChain encapsulates functions required to synchronise a light chain. -type LightChain interface { +// BlockChain encapsulates functions required to sync a (full or snap) blockchain. +type BlockChain interface { // HasHeader verifies a header's presence in the local chain. HasHeader(common.Hash, uint64) bool @@ -162,11 +160,6 @@ type LightChain interface { // SetHead rewinds the local chain to a new head. SetHead(uint64) error -} - -// BlockChain encapsulates functions required to sync a (full or snap) blockchain. -type BlockChain interface { - LightChain // HasBlock verifies a block's presence in the local chain. HasBlock(common.Hash, uint64) bool @@ -201,17 +194,13 @@ type BlockChain interface { } // New creates a new downloader to fetch hashes and blocks from remote peers. -func New(stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func()) *Downloader { - if lightchain == nil { - lightchain = chain - } +func New(stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, dropPeer peerDropFn, success func()) *Downloader { dl := &Downloader{ stateDB: stateDb, mux: mux, queue: newQueue(blockCacheMaxItems, blockCacheInitialItems), peers: newPeerSet(), blockchain: chain, - lightchain: lightchain, dropPeer: dropPeer, headerProcCh: make(chan *headerTask, 1), quitCh: make(chan struct{}), @@ -240,15 +229,13 @@ func (d *Downloader) Progress() ethereum.SyncProgress { current := uint64(0) mode := d.getMode() - switch { - case d.blockchain != nil && mode == FullSync: + switch mode { + case FullSync: current = d.blockchain.CurrentBlock().Number.Uint64() - case d.blockchain != nil && mode == SnapSync: + case SnapSync: current = d.blockchain.CurrentSnapBlock().Number.Uint64() - case d.lightchain != nil: - current = d.lightchain.CurrentHeader().Number.Uint64() default: - log.Error("Unknown downloader chain/mode combo", "light", d.lightchain != nil, "full", d.blockchain != nil, "mode", mode) + log.Error("Unknown downloader mode", "mode", mode) } progress, pending := d.SnapSyncer.Progress() @@ -402,7 +389,7 @@ func (d *Downloader) syncToHead() (err error) { if err != nil { d.mux.Post(FailedEvent{err}) } else { - latest := d.lightchain.CurrentHeader() + latest := d.blockchain.CurrentHeader() d.mux.Post(DoneEvent{latest}) } }() @@ -520,7 +507,7 @@ func (d *Downloader) syncToHead() (err error) { } // Rewind the ancient store and blockchain if reorg happens. if origin+1 < frozen { - if err := d.lightchain.SetHead(origin); err != nil { + if err := d.blockchain.SetHead(origin); err != nil { return err } log.Info("Truncated excess ancient chain segment", "oldhead", frozen-1, "newhead", origin) @@ -690,34 +677,32 @@ func (d *Downloader) processHeaders(origin uint64) error { chunkHashes := hashes[:limit] // In case of header only syncing, validate the chunk immediately - if mode == SnapSync || mode == LightSync { + if mode == SnapSync { // Although the received headers might be all valid, a legacy // PoW/PoA sync must not accept post-merge headers. Make sure // that any transition is rejected at this point. if len(chunkHeaders) > 0 { - if n, err := d.lightchain.InsertHeaderChain(chunkHeaders); err != nil { + if n, err := d.blockchain.InsertHeaderChain(chunkHeaders); err != nil { log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err) return fmt.Errorf("%w: %v", errInvalidChain, err) } } } - // Unless we're doing light chains, schedule the headers for associated content retrieval - if mode == FullSync || mode == SnapSync { - // If we've reached the allowed number of pending headers, stall a bit - for d.queue.PendingBodies() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders { - timer.Reset(time.Second) - select { - case <-d.cancelCh: - return errCanceled - case <-timer.C: - } - } - // Otherwise insert the headers for content retrieval - inserts := d.queue.Schedule(chunkHeaders, chunkHashes, origin) - if len(inserts) != len(chunkHeaders) { - return fmt.Errorf("%w: stale headers", errBadPeer) + // If we've reached the allowed number of pending headers, stall a bit + for d.queue.PendingBodies() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders { + timer.Reset(time.Second) + select { + case <-d.cancelCh: + return errCanceled + case <-timer.C: } } + // Otherwise insert the headers for content retrieval + inserts := d.queue.Schedule(chunkHeaders, chunkHashes, origin) + if len(inserts) != len(chunkHeaders) { + return fmt.Errorf("%w: stale headers", errBadPeer) + } + headers = headers[limit:] hashes = hashes[limit:] origin += uint64(limit) @@ -1056,7 +1041,7 @@ func (d *Downloader) readHeaderRange(last *types.Header, count int) []*types.Hea headers []*types.Header ) for { - parent := d.lightchain.GetHeaderByHash(current.ParentHash) + parent := d.blockchain.GetHeaderByHash(current.ParentHash) if parent == nil { break // The chain is not continuous, or the chain is exhausted } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index e5329b7b3965..0cbddee6bf7a 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -76,7 +76,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { chain: chain, peers: make(map[string]*downloadTesterPeer), } - tester.downloader = New(db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success) + tester.downloader = New(db, new(event.TypeMux), tester.chain, tester.dropPeer, success) return tester } @@ -384,9 +384,6 @@ func assertOwnChain(t *testing.T, tester *downloadTester, length int) { t.Helper() headers, blocks, receipts := length, length, length - if tester.downloader.getMode() == LightSync { - blocks, receipts = 1, 1 - } if hs := int(tester.chain.CurrentHeader().Number.Uint64()) + 1; hs != headers { t.Fatalf("synchronised headers mismatch: have %v, want %v", hs, headers) } @@ -398,9 +395,8 @@ func assertOwnChain(t *testing.T, tester *downloadTester, length int) { } } -func TestCanonicalSynchronisation68Full(t *testing.T) { testCanonSync(t, eth.ETH68, FullSync) } -func TestCanonicalSynchronisation68Snap(t *testing.T) { testCanonSync(t, eth.ETH68, SnapSync) } -func TestCanonicalSynchronisation68Light(t *testing.T) { testCanonSync(t, eth.ETH68, LightSync) } +func TestCanonicalSynchronisation68Full(t *testing.T) { testCanonSync(t, eth.ETH68, FullSync) } +func TestCanonicalSynchronisation68Snap(t *testing.T) { testCanonSync(t, eth.ETH68, SnapSync) } func testCanonSync(t *testing.T, protocol uint, mode SyncMode) { success := make(chan struct{}) @@ -505,9 +501,8 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { } // Tests that a canceled download wipes all previously accumulated state. -func TestCancel68Full(t *testing.T) { testCancel(t, eth.ETH68, FullSync) } -func TestCancel68Snap(t *testing.T) { testCancel(t, eth.ETH68, SnapSync) } -func TestCancel68Light(t *testing.T) { testCancel(t, eth.ETH68, LightSync) } +func TestCancel68Full(t *testing.T) { testCancel(t, eth.ETH68, FullSync) } +func TestCancel68Snap(t *testing.T) { testCancel(t, eth.ETH68, SnapSync) } func testCancel(t *testing.T, protocol uint, mode SyncMode) { complete := make(chan struct{}) @@ -538,9 +533,8 @@ func testCancel(t *testing.T, protocol uint, mode SyncMode) { // Tests that synchronisations behave well in multi-version protocol environments // and not wreak havoc on other nodes in the network. -func TestMultiProtoSynchronisation68Full(t *testing.T) { testMultiProtoSync(t, eth.ETH68, FullSync) } -func TestMultiProtoSynchronisation68Snap(t *testing.T) { testMultiProtoSync(t, eth.ETH68, SnapSync) } -func TestMultiProtoSynchronisation68Light(t *testing.T) { testMultiProtoSync(t, eth.ETH68, LightSync) } +func TestMultiProtoSynchronisation68Full(t *testing.T) { testMultiProtoSync(t, eth.ETH68, FullSync) } +func TestMultiProtoSynchronisation68Snap(t *testing.T) { testMultiProtoSync(t, eth.ETH68, SnapSync) } func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { complete := make(chan struct{}) @@ -578,9 +572,8 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { // Tests that if a block is empty (e.g. header only), no body request should be // made, and instead the header should be assembled into a whole block in itself. -func TestEmptyShortCircuit68Full(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, FullSync) } -func TestEmptyShortCircuit68Snap(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, SnapSync) } -func TestEmptyShortCircuit68Light(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, LightSync) } +func TestEmptyShortCircuit68Full(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, FullSync) } +func TestEmptyShortCircuit68Snap(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, SnapSync) } func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { success := make(chan struct{}) @@ -619,7 +612,7 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { // Validate the number of block bodies that should have been requested bodiesNeeded, receiptsNeeded := 0, 0 for _, block := range chain.blocks[1:] { - if mode != LightSync && (len(block.Transactions()) > 0 || len(block.Uncles()) > 0) { + if len(block.Transactions()) > 0 || len(block.Uncles()) > 0 { bodiesNeeded++ } } @@ -694,9 +687,8 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) { // Tests that synchronisation progress (origin block number, current block number // and highest block number) is tracked and updated correctly. -func TestSyncProgress68Full(t *testing.T) { testSyncProgress(t, eth.ETH68, FullSync) } -func TestSyncProgress68Snap(t *testing.T) { testSyncProgress(t, eth.ETH68, SnapSync) } -func TestSyncProgress68Light(t *testing.T) { testSyncProgress(t, eth.ETH68, LightSync) } +func TestSyncProgress68Full(t *testing.T) { testSyncProgress(t, eth.ETH68, FullSync) } +func TestSyncProgress68Snap(t *testing.T) { testSyncProgress(t, eth.ETH68, SnapSync) } func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) { success := make(chan struct{}) @@ -734,17 +726,7 @@ func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) { if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil { t.Fatalf("failed to beacon-sync chain: %v", err) } - var startingBlock uint64 - if mode == LightSync { - // in light-sync mode: - // * the starting block is 0 on the second sync cycle because blocks - // are never downloaded. - // * The current/highest blocks reported in the progress reflect the - // current/highest header. - startingBlock = 0 - } else { - startingBlock = uint64(len(chain.blocks)/2 - 1) - } + startingBlock := uint64(len(chain.blocks)/2 - 1) select { case <-success: diff --git a/eth/downloader/modes.go b/eth/downloader/modes.go index d388b9ee4d46..9d8e1f313c24 100644 --- a/eth/downloader/modes.go +++ b/eth/downloader/modes.go @@ -23,13 +23,12 @@ import "fmt" type SyncMode uint32 const ( - FullSync SyncMode = iota // Synchronise the entire blockchain history from full blocks - SnapSync // Download the chain and the state via compact snapshots - LightSync // Download only the headers and terminate afterwards + FullSync SyncMode = iota // Synchronise the entire blockchain history from full blocks + SnapSync // Download the chain and the state via compact snapshots ) func (mode SyncMode) IsValid() bool { - return mode >= FullSync && mode <= LightSync + return mode == FullSync || mode == SnapSync } // String implements the stringer interface. @@ -39,8 +38,6 @@ func (mode SyncMode) String() string { return "full" case SnapSync: return "snap" - case LightSync: - return "light" default: return "unknown" } @@ -52,8 +49,6 @@ func (mode SyncMode) MarshalText() ([]byte, error) { return []byte("full"), nil case SnapSync: return []byte("snap"), nil - case LightSync: - return []byte("light"), nil default: return nil, fmt.Errorf("unknown sync mode %d", mode) } @@ -65,10 +60,8 @@ func (mode *SyncMode) UnmarshalText(text []byte) error { *mode = FullSync case "snap": *mode = SnapSync - case "light": - *mode = LightSync default: - return fmt.Errorf(`unknown sync mode %q, want "full", "snap" or "light"`, text) + return fmt.Errorf(`unknown sync mode %q, want "full" or "snap"`, text) } return nil } diff --git a/eth/handler.go b/eth/handler.go index 143ac2a8a57b..d5117584c001 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -180,7 +180,7 @@ func newHandler(config *handlerConfig) (*handler, error) { return nil, errors.New("snap sync not supported with snapshots disabled") } // Construct the downloader (long sync) - h.downloader = downloader.New(config.Database, h.eventMux, h.chain, nil, h.removePeer, h.enableSyncedFeatures) + h.downloader = downloader.New(config.Database, h.eventMux, h.chain, h.removePeer, h.enableSyncedFeatures) fetchTx := func(peer string, hashes []common.Hash) error { p := h.peers.peer(peer) From 171430c3f5d474327bc1721c7c36ad83ad21b4b2 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 28 May 2024 10:54:55 -0700 Subject: [PATCH 302/571] core/state: remove unused error from prefetcher trie method (#29768) Co-authored-by: Gary Rong Co-authored-by: Felix Lange --- core/state/state_object.go | 25 ++++++++++--------------- core/state/statedb.go | 6 +++--- core/state/trie_prefetcher.go | 6 +++--- core/state/trie_prefetcher_test.go | 4 ++-- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 4011425c2a8d..252dcdf2b0d3 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -150,11 +150,11 @@ func (s *stateObject) getTrie() (Trie, error) { // trie in the state object. The caller might want to do that, but it's cleaner // to break the hidden interdependency between retrieving tries from the db or // from the prefetcher. -func (s *stateObject) getPrefetchedTrie() (Trie, error) { +func (s *stateObject) getPrefetchedTrie() Trie { // If there's nothing to meaningfully return, let the user figure it out by // pulling the trie from disk. if s.data.Root == types.EmptyRootHash || s.db.prefetcher == nil { - return nil, nil + return nil } // Attempt to retrieve the trie from the prefetcher return s.db.prefetcher.trie(s.addrHash, s.data.Root) @@ -311,26 +311,21 @@ func (s *stateObject) updateTrie() (Trie, error) { if len(s.pendingStorage) == 0 { return s.trie, nil } - // Retrieve a prefetcher populated trie, or fall back to the database - tr, err := s.getPrefetchedTrie() - switch { - case err != nil: - // Fetcher retrieval failed, something's very wrong, abort - s.db.setError(err) - return nil, err - - case tr == nil: + // Retrieve a pretecher populated trie, or fall back to the database + tr := s.getPrefetchedTrie() + if tr != nil { + // Prefetcher returned a live trie, swap it out for the current one + s.trie = tr + } else { // Fetcher not running or empty trie, fallback to the database trie + var err error tr, err = s.getTrie() if err != nil { s.db.setError(err) return nil, err } - - default: - // Prefetcher returned a live trie, swap it out for the current one - s.trie = tr } + // The snapshot storage map for the object var ( storage map[common.Hash][]byte diff --git a/core/state/statedb.go b/core/state/statedb.go index 0ef52a88f6ea..ccc7ca4ba236 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -878,9 +878,9 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { start = time.Now() if s.prefetcher != nil { - if trie, err := s.prefetcher.trie(common.Hash{}, s.originalRoot); err != nil { - log.Error("Failed to retrieve account pre-fetcher trie", "err", err) - } else if trie != nil { + if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil { + log.Error("Failed to retrieve account pre-fetcher trie") + } else { s.trie = trie } } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 0b45660ac146..ce94ab51396c 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -145,16 +145,16 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm // trie returns the trie matching the root hash, blocking until the fetcher of // the given trie terminates. If no fetcher exists for the request, nil will be // returned. -func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) (Trie, error) { +func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie { // Bail if no trie was prefetched for this root fetcher := p.fetchers[p.trieID(owner, root)] if fetcher == nil { log.Error("Prefetcher missed to load trie", "owner", owner, "root", root) p.deliveryMissMeter.Mark(1) - return nil, nil + return nil } // Subfetcher exists, retrieve its trie - return fetcher.peek(), nil + return fetcher.peek() } // used marks a batch of state items used to allow creating statistics as to diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index d6788fad9936..478407dfbb04 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -58,7 +58,7 @@ func TestUseAfterTerminate(t *testing.T) { if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err == nil { t.Errorf("Prefetch succeeded after terminate: %v", err) } - if _, err := prefetcher.trie(common.Hash{}, db.originalRoot); err != nil { - t.Errorf("Trie retrieval failed after terminate: %v", err) + if tr := prefetcher.trie(common.Hash{}, db.originalRoot); tr == nil { + t.Errorf("Prefetcher returned nil trie after terminate") } } From cc22e0cdf0468947265883921b0c29119ca0327a Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 28 May 2024 13:30:17 -0600 Subject: [PATCH 303/571] p2p/discover: fix update logic in handleAddNode (#29836) It seems the semantic differences between addFoundNode and addInboundNode were lost in #29572. My understanding is addFoundNode is for a node you have not contacted directly (and are unsure if is available) whereas addInboundNode is for adding nodes that have contacted the local node and we can verify they are active. handleAddNode seems to be the consolidation of those two methods, yet it bumps the node in the bucket (updating it's IP addr) even if the node was not an inbound. This PR fixes this. It wasn't originally caught in tests like TestTable_addSeenNode because the manipulation of the node object actually modified the node value used by the test. New logic is added to reject non-inbound updates unless the sequence number of the (signed) ENR increases. Inbound updates, which are published by the updated node itself, are always accepted. If an inbound update changes the endpoint, the node will be revalidated on an expedited schedule. Co-authored-by: Felix Lange --- p2p/discover/table.go | 46 ++++++++---- p2p/discover/table_reval.go | 25 ++++--- p2p/discover/table_reval_test.go | 53 +++++++++++++- p2p/discover/table_test.go | 122 +++++++++++++++++++++++-------- 4 files changed, 187 insertions(+), 59 deletions(-) diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 74c0e930e4af..2b4ba7f5d813 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -513,8 +513,9 @@ func (tab *Table) handleAddNode(req addNodeOp) bool { } b := tab.bucket(req.node.ID()) - if tab.bumpInBucket(b, req.node.Node) { - // Already in bucket, update record. + n, _ := tab.bumpInBucket(b, req.node.Node, req.isInbound) + if n != nil { + // Already in bucket. return false } if len(b.entries) >= bucketSize { @@ -605,26 +606,45 @@ func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *node { return rep } -// bumpInBucket updates the node record of n in the bucket. -func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node) bool { +// bumpInBucket updates a node record if it exists in the bucket. +// The second return value reports whether the node's endpoint (IP/port) was updated. +func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) (n *node, endpointChanged bool) { i := slices.IndexFunc(b.entries, func(elem *node) bool { return elem.ID() == newRecord.ID() }) if i == -1 { - return false + return nil, false // not in bucket + } + n = b.entries[i] + + // For inbound updates (from the node itself) we accept any change, even if it sets + // back the sequence number. For found nodes (!isInbound), seq has to advance. Note + // this check also ensures found discv4 nodes (which always have seq=0) can't be + // updated. + if newRecord.Seq() <= n.Seq() && !isInbound { + return n, false } - if !newRecord.IP().Equal(b.entries[i].IP()) { - // Endpoint has changed, ensure that the new IP fits into table limits. - tab.removeIP(b, b.entries[i].IP()) + // Check endpoint update against IP limits. + ipchanged := newRecord.IPAddr() != n.IPAddr() + portchanged := newRecord.UDP() != n.UDP() + if ipchanged { + tab.removeIP(b, n.IP()) if !tab.addIP(b, newRecord.IP()) { - // It doesn't, put the previous one back. - tab.addIP(b, b.entries[i].IP()) - return false + // It doesn't fit with the limit, put the previous record back. + tab.addIP(b, n.IP()) + return n, false } } - b.entries[i].Node = newRecord - return true + + // Apply update. + n.Node = newRecord + if ipchanged || portchanged { + // Ensure node is revalidated quickly for endpoint changes. + tab.revalidation.nodeEndpointChanged(tab, n) + return n, true + } + return n, false } func (tab *Table) handleTrackRequest(op trackRequestOp) { diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index 01a5bdb6fa52..5d185aa8b428 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -28,6 +28,8 @@ import ( const never = mclock.AbsTime(math.MaxInt64) +const slowRevalidationFactor = 3 + // tableRevalidation implements the node revalidation process. // It tracks all nodes contained in Table, and schedules sending PING to them. type tableRevalidation struct { @@ -48,7 +50,7 @@ func (tr *tableRevalidation) init(cfg *Config) { tr.fast.interval = cfg.PingInterval tr.fast.name = "fast" tr.slow.nextTime = never - tr.slow.interval = cfg.PingInterval * 3 + tr.slow.interval = cfg.PingInterval * slowRevalidationFactor tr.slow.name = "slow" } @@ -65,6 +67,12 @@ func (tr *tableRevalidation) nodeRemoved(n *node) { n.revalList.remove(n) } +// nodeEndpointChanged is called when a change in IP or port is detected. +func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *node) { + n.isValidatedLive = false + tr.moveToList(&tr.fast, n, tab.cfg.Clock.Now(), &tab.rand) +} + // run performs node revalidation. // It returns the next time it should be invoked, which is used in the Table main loop // to schedule a timer. However, run can be called at any time. @@ -146,11 +154,11 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons defer tab.mutex.Unlock() if !resp.didRespond { - // Revalidation failed. n.livenessChecks /= 3 if n.livenessChecks <= 0 { tab.deleteInBucket(b, n.ID()) } else { + tab.log.Debug("Node revalidation failed", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList.name) tr.moveToList(&tr.fast, n, now, &tab.rand) } return @@ -159,22 +167,15 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons // The node responded. n.livenessChecks++ n.isValidatedLive = true + tab.log.Debug("Node revalidated", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList.name) var endpointChanged bool if resp.newRecord != nil { - endpointChanged = tab.bumpInBucket(b, resp.newRecord) - if endpointChanged { - // If the node changed its advertised endpoint, the updated ENR is not served - // until it has been revalidated. - n.isValidatedLive = false - } + _, endpointChanged = tab.bumpInBucket(b, resp.newRecord, false) } - tab.log.Debug("Revalidated node", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList) - // Move node over to slow queue after first validation. + // Node moves to slow list if it passed and hasn't changed. if !endpointChanged { tr.moveToList(&tr.slow, n, now, &tab.rand) - } else { - tr.moveToList(&tr.fast, n, now, &tab.rand) } } diff --git a/p2p/discover/table_reval_test.go b/p2p/discover/table_reval_test.go index 3adf577ae444..d168767e0dd8 100644 --- a/p2p/discover/table_reval_test.go +++ b/p2p/discover/table_reval_test.go @@ -22,11 +22,13 @@ import ( "time" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" ) // This test checks that revalidation can handle a node disappearing while // a request is active. -func TestRevalidationNodeRemoved(t *testing.T) { +func TestRevalidation_nodeRemoved(t *testing.T) { var ( clock mclock.Simulated transport = newPingRecorder() @@ -35,7 +37,7 @@ func TestRevalidationNodeRemoved(t *testing.T) { ) defer db.Close() - // Fill a bucket. + // Add a node to the table. node := nodeAtDistance(tab.self().ID(), 255, net.IP{77, 88, 99, 1}) tab.handleAddNode(addNodeOp{node: node}) @@ -68,3 +70,50 @@ func TestRevalidationNodeRemoved(t *testing.T) { t.Fatal("removed node contained in revalidation list") } } + +// This test checks that nodes with an updated endpoint remain in the fast revalidation list. +func TestRevalidation_endpointUpdate(t *testing.T) { + var ( + clock mclock.Simulated + transport = newPingRecorder() + tab, db = newInactiveTestTable(transport, Config{Clock: &clock}) + tr = &tab.revalidation + ) + defer db.Close() + + // Add node to table. + node := nodeAtDistance(tab.self().ID(), 255, net.IP{77, 88, 99, 1}) + tab.handleAddNode(addNodeOp{node: node}) + + // Update the record in transport, including endpoint update. + record := node.Record() + record.Set(enr.IP{100, 100, 100, 100}) + record.Set(enr.UDP(9999)) + nodev2 := enode.SignNull(record, node.ID()) + transport.updateRecord(nodev2) + + // Start a revalidation request. Schedule once to get the next start time, + // then advance the clock to that point and schedule again to start. + next := tr.run(tab, clock.Now()) + clock.Run(time.Duration(next + 1)) + tr.run(tab, clock.Now()) + if len(tr.activeReq) != 1 { + t.Fatal("revalidation request did not start:", tr.activeReq) + } + + // Now finish the revalidation request. + var resp revalidationResponse + select { + case resp = <-tab.revalResponseCh: + case <-time.After(1 * time.Second): + t.Fatal("timed out waiting for revalidation") + } + tr.handleResponse(tab, resp) + + if !tr.fast.contains(node.ID()) { + t.Fatal("node not contained in fast revalidation list") + } + if node.isValidatedLive { + t.Fatal("node is marked live after endpoint change") + } +} diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 945b1a294e9c..b0be2a94c5b9 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -131,7 +131,7 @@ func waitForRevalidationPing(t *testing.T, transport *pingRecorder, tab *Table, simclock := tab.cfg.Clock.(*mclock.Simulated) maxAttempts := tab.len() * 8 for i := 0; i < maxAttempts; i++ { - simclock.Run(tab.cfg.PingInterval) + simclock.Run(tab.cfg.PingInterval * slowRevalidationFactor) p := transport.waitPing(2 * time.Second) if p == nil { t.Fatal("Table did not send revalidation ping") @@ -275,7 +275,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { return reflect.ValueOf(t) } -func TestTable_addVerifiedNode(t *testing.T) { +func TestTable_addInboundNode(t *testing.T) { tab, db := newTestTable(newPingRecorder(), Config{}) <-tab.initDone defer db.Close() @@ -286,29 +286,26 @@ func TestTable_addVerifiedNode(t *testing.T) { n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) tab.addFoundNode(n1) tab.addFoundNode(n2) - bucket := tab.bucket(n1.ID()) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node}) - // Verify bucket content: - bcontent := []*node{n1, n2} - if !reflect.DeepEqual(unwrapNodes(bucket.entries), unwrapNodes(bcontent)) { - t.Fatalf("wrong bucket content: %v", bucket.entries) - } - - // Add a changed version of n2. + // Add a changed version of n2. The bucket should be updated. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) - newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) - tab.addInboundNode(newn2) - - // Check that bucket is updated correctly. - newBcontent := []*node{n1, newn2} - if !reflect.DeepEqual(unwrapNodes(bucket.entries), unwrapNodes(newBcontent)) { - t.Fatalf("wrong bucket content after update: %v", bucket.entries) - } - checkIPLimitInvariant(t, tab) + n2v2 := enode.SignNull(newrec, n2.ID()) + tab.addInboundNode(wrapNode(n2v2)) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) + + // Try updating n2 without sequence number change. The update is accepted + // because it's inbound. + newrec = n2.Record() + newrec.Set(enr.IP{100, 100, 100, 100}) + newrec.SetSeq(n2.Seq()) + n2v3 := enode.SignNull(newrec, n2.ID()) + tab.addInboundNode(wrapNode(n2v3)) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v3}) } -func TestTable_addSeenNode(t *testing.T) { +func TestTable_addFoundNode(t *testing.T) { tab, db := newTestTable(newPingRecorder(), Config{}) <-tab.initDone defer db.Close() @@ -319,23 +316,84 @@ func TestTable_addSeenNode(t *testing.T) { n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) tab.addFoundNode(n1) tab.addFoundNode(n2) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node}) - // Verify bucket content: - bcontent := []*node{n1, n2} - if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { - t.Fatalf("wrong bucket content: %v", tab.bucket(n1.ID()).entries) - } - - // Add a changed version of n2. + // Add a changed version of n2. The bucket should be updated. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) - newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) - tab.addFoundNode(newn2) + n2v2 := enode.SignNull(newrec, n2.ID()) + tab.addFoundNode(wrapNode(n2v2)) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) + + // Try updating n2 without a sequence number change. + // The update should not be accepted. + newrec = n2.Record() + newrec.Set(enr.IP{100, 100, 100, 100}) + newrec.SetSeq(n2.Seq()) + n2v3 := enode.SignNull(newrec, n2.ID()) + tab.addFoundNode(wrapNode(n2v3)) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) +} - // Check that bucket content is unchanged. - if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { - t.Fatalf("wrong bucket content after update: %v", tab.bucket(n1.ID()).entries) +// This test checks that discv4 nodes can update their own endpoint via PING. +func TestTable_addInboundNodeUpdateV4Accept(t *testing.T) { + tab, db := newTestTable(newPingRecorder(), Config{}) + <-tab.initDone + defer db.Close() + defer tab.close() + + // Add a v4 node. + key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3") + n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000) + tab.addInboundNode(wrapNode(n1)) + checkBucketContent(t, tab, []*enode.Node{n1}) + + // Add an updated version with changed IP. + // The update will be accepted because it is inbound. + n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000) + tab.addInboundNode(wrapNode(n1v2)) + checkBucketContent(t, tab, []*enode.Node{n1v2}) +} + +// This test checks that discv4 node entries will NOT be updated when a +// changed record is found. +func TestTable_addFoundNodeV4UpdateReject(t *testing.T) { + tab, db := newTestTable(newPingRecorder(), Config{}) + <-tab.initDone + defer db.Close() + defer tab.close() + + // Add a v4 node. + key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3") + n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000) + tab.addFoundNode(wrapNode(n1)) + checkBucketContent(t, tab, []*enode.Node{n1}) + + // Add an updated version with changed IP. + // The update won't be accepted because it isn't inbound. + n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000) + tab.addFoundNode(wrapNode(n1v2)) + checkBucketContent(t, tab, []*enode.Node{n1}) +} + +func checkBucketContent(t *testing.T, tab *Table, nodes []*enode.Node) { + t.Helper() + + b := tab.bucket(nodes[0].ID()) + if reflect.DeepEqual(unwrapNodes(b.entries), nodes) { + return } + t.Log("wrong bucket content. have nodes:") + for _, n := range b.entries { + t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IP()) + } + t.Log("want nodes:") + for _, n := range nodes { + t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IP()) + } + t.FailNow() + + // Also check IP limits. checkIPLimitInvariant(t, tab) } From 5534c849b6f426604a572d54d65a209df42a047a Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 29 May 2024 10:30:25 +0200 Subject: [PATCH 304/571] go.mod: update a number of dependencies (#29763) * deps: update go-winio * deps: update fastcache * deps: update golang-set * update fatih/color * update natefinch/lumberjack.v2 --- go.mod | 16 ++++++++-------- go.sum | 39 ++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index cf76ae35eb05..8968140fbf19 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.21 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 - github.com/Microsoft/go-winio v0.6.1 - github.com/VictoriaMetrics/fastcache v1.12.1 + github.com/Microsoft/go-winio v0.6.2 + github.com/VictoriaMetrics/fastcache v1.12.2 github.com/aws/aws-sdk-go-v2 v1.21.2 github.com/aws/aws-sdk-go-v2/config v1.18.45 github.com/aws/aws-sdk-go-v2/credentials v1.13.43 @@ -18,12 +18,12 @@ require ( github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c github.com/crate-crypto/go-kzg-4844 v1.0.0 github.com/davecgh/go-spew v1.1.1 - github.com/deckarep/golang-set/v2 v2.1.0 + github.com/deckarep/golang-set/v2 v2.6.0 github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 github.com/ethereum/c-kzg-4844 v1.0.0 github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 - github.com/fatih/color v1.13.0 + github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.2 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/memsize v0.0.2 @@ -51,7 +51,7 @@ require ( github.com/kilic/bls12-381 v0.1.0 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 - github.com/mattn/go-isatty v0.0.17 + github.com/mattn/go-isatty v0.0.20 github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 @@ -69,11 +69,11 @@ require ( go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.22.0 golang.org/x/sync v0.7.0 - golang.org/x/sys v0.19.0 + golang.org/x/sys v0.20.0 golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.20.0 - gopkg.in/natefinch/lumberjack.v2 v2.0.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -93,7 +93,7 @@ require ( github.com/aws/smithy-go v1.15.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cockroachdb/errors v1.11.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect diff --git a/go.sum b/go.sum index 76e6feccdb13..5e4b38e9a6bc 100644 --- a/go.sum +++ b/go.sum @@ -44,17 +44,15 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgx github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= -github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= +github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -103,8 +101,9 @@ github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -142,8 +141,8 @@ github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= -github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= @@ -171,8 +170,8 @@ github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHE github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY= @@ -377,16 +376,14 @@ github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIG github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= @@ -682,7 +679,6 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -690,11 +686,12 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -851,8 +848,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From daf4f720770d7f7e99fee02f26eb08607d8ddc79 Mon Sep 17 00:00:00 2001 From: bugmaker9371 <167614621+bugmaker9371@users.noreply.github.com> Date: Wed, 29 May 2024 18:09:58 +0800 Subject: [PATCH 305/571] p2p/simulations: remove stale information about docker adapter (#29874) --- p2p/simulations/adapters/types.go | 1 - p2p/simulations/examples/ping-pong.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go index f34315f17097..e18aaacc334a 100644 --- a/p2p/simulations/adapters/types.go +++ b/p2p/simulations/adapters/types.go @@ -42,7 +42,6 @@ import ( // // - SimNode, an in-memory node in the same process // - ExecNode, a child process node -// - DockerNode, a node running in a Docker container type Node interface { // Addr returns the node's address (e.g. an Enode URL) Addr() []byte diff --git a/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go index 70b35ad77742..b0b8f22fdb72 100644 --- a/p2p/simulations/examples/ping-pong.go +++ b/p2p/simulations/examples/ping-pong.go @@ -33,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/simulations/adapters" ) -var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim", "exec" or "docker")`) +var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim" or "exec")`) // main() starts a simulation network which contains nodes running a simple // ping-pong protocol From 153f8da8875930d2a7634939595b38c7bf7a6b10 Mon Sep 17 00:00:00 2001 From: lilasxie Date: Wed, 29 May 2024 18:11:18 +0800 Subject: [PATCH 306/571] p2p/nodestate: remove unused package (#29872) --- p2p/nodestate/nodestate.go | 1023 ------------------------------- p2p/nodestate/nodestate_test.go | 407 ------------ 2 files changed, 1430 deletions(-) delete mode 100644 p2p/nodestate/nodestate.go delete mode 100644 p2p/nodestate/nodestate_test.go diff --git a/p2p/nodestate/nodestate.go b/p2p/nodestate/nodestate.go deleted file mode 100644 index 8052144465a5..000000000000 --- a/p2p/nodestate/nodestate.go +++ /dev/null @@ -1,1023 +0,0 @@ -// Copyright 2020 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 nodestate - -import ( - "errors" - "reflect" - "sync" - "time" - "unsafe" - - "github.com/ethereum/go-ethereum/common/mclock" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/ethereum/go-ethereum/rlp" -) - -var ( - ErrInvalidField = errors.New("invalid field type") - ErrClosed = errors.New("already closed") -) - -type ( - // NodeStateMachine implements a network node-related event subscription system. - // It can assign binary state flags and fields of arbitrary type to each node and allows - // subscriptions to flag/field changes which can also modify further flags and fields, - // potentially triggering further subscriptions. An operation includes an initial change - // and all resulting subsequent changes and always ends in a consistent global state. - // It is initiated by a "top level" SetState/SetField call that blocks (also blocking other - // top-level functions) until the operation is finished. Callbacks making further changes - // should use the non-blocking SetStateSub/SetFieldSub functions. The tree of events - // resulting from the initial changes is traversed in a breadth-first order, ensuring for - // each subscription callback that all other callbacks caused by the same change triggering - // the current callback are processed before anything is triggered by the changes made in the - // current callback. In practice this logic ensures that all subscriptions "see" events in - // the logical order, callbacks are never called concurrently and "back and forth" effects - // are also possible. The state machine design should ensure that infinite event cycles - // cannot happen. - // The caller can also add timeouts assigned to a certain node and a subset of state flags. - // If the timeout elapses, the flags are reset. If all relevant flags are reset then the timer - // is dropped. State flags with no timeout are persisted in the database if the flag - // descriptor enables saving. If a node has no state flags set at any moment then it is discarded. - // Note: in order to avoid mutex deadlocks the callbacks should never lock a mutex that - // might be locked when the top level SetState/SetField functions are called. If a function - // potentially performs state/field changes then it is recommended to mention this fact in the - // function description, along with whether it should run inside an operation callback. - NodeStateMachine struct { - started, closed bool - lock sync.Mutex - clock mclock.Clock - db ethdb.KeyValueStore - dbNodeKey []byte - nodes map[enode.ID]*nodeInfo - offlineCallbackList []offlineCallback - opFlag bool // an operation has started - opWait *sync.Cond // signaled when the operation ends - opPending []func() // pending callback list of the current operation - - // Registered state flags or fields. Modifications are allowed - // only when the node state machine has not been started. - setup *Setup - fields []*fieldInfo - saveFlags bitMask - - // Installed callbacks. Modifications are allowed only when the - // node state machine has not been started. - stateSubs []stateSub - - // Testing hooks, only for testing purposes. - saveNodeHook func(*nodeInfo) - } - - // Flags represents a set of flags from a certain setup - Flags struct { - mask bitMask - setup *Setup - } - - // Field represents a field from a certain setup - Field struct { - index int - setup *Setup - } - - // flagDefinition describes a node state flag. Each registered instance is automatically - // mapped to a bit of the 64 bit node states. - // If persistent is true then the node is saved when state machine is shutdown. - flagDefinition struct { - name string - persistent bool - } - - // fieldDefinition describes an optional node field of the given type. The contents - // of the field are only retained for each node as long as at least one of the - // state flags is set. - fieldDefinition struct { - name string - ftype reflect.Type - encode func(interface{}) ([]byte, error) - decode func([]byte) (interface{}, error) - } - - // Setup contains the list of flags and fields used by the application - Setup struct { - Version uint - flags []flagDefinition - fields []fieldDefinition - } - - // bitMask describes a node state or state mask. It represents a subset - // of node flags with each bit assigned to a flag index (LSB represents flag 0). - bitMask uint64 - - // StateCallback is a subscription callback which is called when one of the - // state flags that is included in the subscription state mask is changed. - // Note: oldState and newState are also masked with the subscription mask so only - // the relevant bits are included. - StateCallback func(n *enode.Node, oldState, newState Flags) - - // FieldCallback is a subscription callback which is called when the value of - // a specific field is changed. - FieldCallback func(n *enode.Node, state Flags, oldValue, newValue interface{}) - - // nodeInfo contains node state, fields and state timeouts - nodeInfo struct { - node *enode.Node - state bitMask - timeouts []*nodeStateTimeout - fields []interface{} - fieldCount int - db, dirty bool - } - - nodeInfoEnc struct { - Enr enr.Record - Version uint - State bitMask - Fields [][]byte - } - - stateSub struct { - mask bitMask - callback StateCallback - } - - nodeStateTimeout struct { - mask bitMask - timer mclock.Timer - } - - fieldInfo struct { - fieldDefinition - subs []FieldCallback - } - - offlineCallback struct { - node *nodeInfo - state bitMask - fields []interface{} - } -) - -// offlineState is a special state that is assumed to be set before a node is loaded from -// the database and after it is shut down. -const offlineState = bitMask(1) - -// NewFlag creates a new node state flag -func (s *Setup) NewFlag(name string) Flags { - if s.flags == nil { - s.flags = []flagDefinition{{name: "offline"}} - } - f := Flags{mask: bitMask(1) << uint(len(s.flags)), setup: s} - s.flags = append(s.flags, flagDefinition{name: name}) - return f -} - -// NewPersistentFlag creates a new persistent node state flag -func (s *Setup) NewPersistentFlag(name string) Flags { - if s.flags == nil { - s.flags = []flagDefinition{{name: "offline"}} - } - f := Flags{mask: bitMask(1) << uint(len(s.flags)), setup: s} - s.flags = append(s.flags, flagDefinition{name: name, persistent: true}) - return f -} - -// OfflineFlag returns the system-defined offline flag belonging to the given setup -func (s *Setup) OfflineFlag() Flags { - return Flags{mask: offlineState, setup: s} -} - -// NewField creates a new node state field -func (s *Setup) NewField(name string, ftype reflect.Type) Field { - f := Field{index: len(s.fields), setup: s} - s.fields = append(s.fields, fieldDefinition{ - name: name, - ftype: ftype, - }) - return f -} - -// NewPersistentField creates a new persistent node field -func (s *Setup) NewPersistentField(name string, ftype reflect.Type, encode func(interface{}) ([]byte, error), decode func([]byte) (interface{}, error)) Field { - f := Field{index: len(s.fields), setup: s} - s.fields = append(s.fields, fieldDefinition{ - name: name, - ftype: ftype, - encode: encode, - decode: decode, - }) - return f -} - -// flagOp implements binary flag operations and also checks whether the operands belong to the same setup -func flagOp(a, b Flags, trueIfA, trueIfB, trueIfBoth bool) Flags { - if a.setup == nil { - if a.mask != 0 { - panic("Node state flags have no setup reference") - } - a.setup = b.setup - } - if b.setup == nil { - if b.mask != 0 { - panic("Node state flags have no setup reference") - } - b.setup = a.setup - } - if a.setup != b.setup { - panic("Node state flags belong to a different setup") - } - res := Flags{setup: a.setup} - if trueIfA { - res.mask |= a.mask & ^b.mask - } - if trueIfB { - res.mask |= b.mask & ^a.mask - } - if trueIfBoth { - res.mask |= a.mask & b.mask - } - return res -} - -// And returns the set of flags present in both a and b -func (a Flags) And(b Flags) Flags { return flagOp(a, b, false, false, true) } - -// AndNot returns the set of flags present in a but not in b -func (a Flags) AndNot(b Flags) Flags { return flagOp(a, b, true, false, false) } - -// Or returns the set of flags present in either a or b -func (a Flags) Or(b Flags) Flags { return flagOp(a, b, true, true, true) } - -// Xor returns the set of flags present in either a or b but not both -func (a Flags) Xor(b Flags) Flags { return flagOp(a, b, true, true, false) } - -// HasAll returns true if b is a subset of a -func (a Flags) HasAll(b Flags) bool { return flagOp(a, b, false, true, false).mask == 0 } - -// HasNone returns true if a and b have no shared flags -func (a Flags) HasNone(b Flags) bool { return flagOp(a, b, false, false, true).mask == 0 } - -// Equals returns true if a and b have the same flags set -func (a Flags) Equals(b Flags) bool { return flagOp(a, b, true, true, false).mask == 0 } - -// IsEmpty returns true if a has no flags set -func (a Flags) IsEmpty() bool { return a.mask == 0 } - -// MergeFlags merges multiple sets of state flags -func MergeFlags(list ...Flags) Flags { - if len(list) == 0 { - return Flags{} - } - res := list[0] - for i := 1; i < len(list); i++ { - res = res.Or(list[i]) - } - return res -} - -// String returns a list of the names of the flags specified in the bit mask -func (f Flags) String() string { - if f.mask == 0 { - return "[]" - } - s := "[" - comma := false - for index, flag := range f.setup.flags { - if f.mask&(bitMask(1)< 8*int(unsafe.Sizeof(bitMask(0))) { - panic("Too many node state flags") - } - ns := &NodeStateMachine{ - db: db, - dbNodeKey: dbKey, - clock: clock, - setup: setup, - nodes: make(map[enode.ID]*nodeInfo), - fields: make([]*fieldInfo, len(setup.fields)), - } - ns.opWait = sync.NewCond(&ns.lock) - stateNameMap := make(map[string]int, len(setup.flags)) - for index, flag := range setup.flags { - if _, ok := stateNameMap[flag.name]; ok { - panic("Node state flag name collision: " + flag.name) - } - stateNameMap[flag.name] = index - if flag.persistent { - ns.saveFlags |= bitMask(1) << uint(index) - } - } - fieldNameMap := make(map[string]int, len(setup.fields)) - for index, field := range setup.fields { - if _, ok := fieldNameMap[field.name]; ok { - panic("Node field name collision: " + field.name) - } - ns.fields[index] = &fieldInfo{fieldDefinition: field} - fieldNameMap[field.name] = index - } - return ns -} - -// stateMask checks whether the set of flags belongs to the same setup and returns its internal bit mask -func (ns *NodeStateMachine) stateMask(flags Flags) bitMask { - if flags.setup != ns.setup && flags.mask != 0 { - panic("Node state flags belong to a different setup") - } - return flags.mask -} - -// fieldIndex checks whether the field belongs to the same setup and returns its internal index -func (ns *NodeStateMachine) fieldIndex(field Field) int { - if field.setup != ns.setup { - panic("Node field belongs to a different setup") - } - return field.index -} - -// SubscribeState adds a node state subscription. The callback is called while the state -// machine mutex is not held and it is allowed to make further state updates using the -// non-blocking SetStateSub/SetFieldSub functions. All callbacks of an operation are running -// from the thread/goroutine of the initial caller and parallel operations are not permitted. -// Therefore the callback is never called concurrently. It is the responsibility of the -// implemented state logic to avoid deadlocks and to reach a stable state in a finite amount -// of steps. -// State subscriptions should be installed before loading the node database or making the -// first state update. -func (ns *NodeStateMachine) SubscribeState(flags Flags, callback StateCallback) { - ns.lock.Lock() - defer ns.lock.Unlock() - - if ns.started { - panic("state machine already started") - } - ns.stateSubs = append(ns.stateSubs, stateSub{ns.stateMask(flags), callback}) -} - -// SubscribeField adds a node field subscription. Same rules apply as for SubscribeState. -func (ns *NodeStateMachine) SubscribeField(field Field, callback FieldCallback) { - ns.lock.Lock() - defer ns.lock.Unlock() - - if ns.started { - panic("state machine already started") - } - f := ns.fields[ns.fieldIndex(field)] - f.subs = append(f.subs, callback) -} - -// newNode creates a new nodeInfo -func (ns *NodeStateMachine) newNode(n *enode.Node) *nodeInfo { - return &nodeInfo{node: n, fields: make([]interface{}, len(ns.fields))} -} - -// checkStarted checks whether the state machine has already been started and panics otherwise. -func (ns *NodeStateMachine) checkStarted() { - if !ns.started { - panic("state machine not started yet") - } -} - -// Start starts the state machine, enabling state and field operations and disabling -// further subscriptions. -func (ns *NodeStateMachine) Start() { - ns.lock.Lock() - if ns.started { - panic("state machine already started") - } - ns.started = true - if ns.db != nil { - ns.loadFromDb() - } - - ns.opStart() - ns.offlineCallbacks(true) - ns.opFinish() - ns.lock.Unlock() -} - -// Stop stops the state machine and saves its state if a database was supplied -func (ns *NodeStateMachine) Stop() { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if !ns.opStart() { - panic("already closed") - } - for _, node := range ns.nodes { - fields := make([]interface{}, len(node.fields)) - copy(fields, node.fields) - ns.offlineCallbackList = append(ns.offlineCallbackList, offlineCallback{node, node.state, fields}) - } - if ns.db != nil { - ns.saveToDb() - } - ns.offlineCallbacks(false) - ns.closed = true - ns.opFinish() -} - -// loadFromDb loads persisted node states from the database -func (ns *NodeStateMachine) loadFromDb() { - it := ns.db.NewIterator(ns.dbNodeKey, nil) - for it.Next() { - var id enode.ID - if len(it.Key()) != len(ns.dbNodeKey)+len(id) { - log.Error("Node state db entry with invalid length", "found", len(it.Key()), "expected", len(ns.dbNodeKey)+len(id)) - continue - } - copy(id[:], it.Key()[len(ns.dbNodeKey):]) - ns.decodeNode(id, it.Value()) - } -} - -type dummyIdentity enode.ID - -func (id dummyIdentity) Verify(r *enr.Record, sig []byte) error { return nil } -func (id dummyIdentity) NodeAddr(r *enr.Record) []byte { return id[:] } - -// decodeNode decodes a node database entry and adds it to the node set if successful -func (ns *NodeStateMachine) decodeNode(id enode.ID, data []byte) { - var enc nodeInfoEnc - if err := rlp.DecodeBytes(data, &enc); err != nil { - log.Error("Failed to decode node info", "id", id, "error", err) - return - } - n, _ := enode.New(dummyIdentity(id), &enc.Enr) - node := ns.newNode(n) - node.db = true - - if enc.Version != ns.setup.Version { - log.Debug("Removing stored node with unknown version", "current", ns.setup.Version, "stored", enc.Version) - ns.deleteNode(id) - return - } - if len(enc.Fields) > len(ns.setup.fields) { - log.Error("Invalid node field count", "id", id, "stored", len(enc.Fields)) - return - } - // Resolve persisted node fields - for i, encField := range enc.Fields { - if len(encField) == 0 { - continue - } - if decode := ns.fields[i].decode; decode != nil { - if field, err := decode(encField); err == nil { - node.fields[i] = field - node.fieldCount++ - } else { - log.Error("Failed to decode node field", "id", id, "field name", ns.fields[i].name, "error", err) - return - } - } else { - log.Error("Cannot decode node field", "id", id, "field name", ns.fields[i].name) - return - } - } - // It's a compatible node record, add it to set. - ns.nodes[id] = node - node.state = enc.State - fields := make([]interface{}, len(node.fields)) - copy(fields, node.fields) - ns.offlineCallbackList = append(ns.offlineCallbackList, offlineCallback{node, node.state, fields}) - log.Debug("Loaded node state", "id", id, "state", Flags{mask: enc.State, setup: ns.setup}) -} - -// saveNode saves the given node info to the database -func (ns *NodeStateMachine) saveNode(id enode.ID, node *nodeInfo) error { - if ns.db == nil { - return nil - } - - storedState := node.state & ns.saveFlags - for _, t := range node.timeouts { - storedState &= ^t.mask - } - enc := nodeInfoEnc{ - Enr: *node.node.Record(), - Version: ns.setup.Version, - State: storedState, - Fields: make([][]byte, len(ns.fields)), - } - log.Debug("Saved node state", "id", id, "state", Flags{mask: enc.State, setup: ns.setup}) - lastIndex := -1 - for i, f := range node.fields { - if f == nil { - continue - } - encode := ns.fields[i].encode - if encode == nil { - continue - } - blob, err := encode(f) - if err != nil { - return err - } - enc.Fields[i] = blob - lastIndex = i - } - if storedState == 0 && lastIndex == -1 { - if node.db { - node.db = false - ns.deleteNode(id) - } - node.dirty = false - return nil - } - enc.Fields = enc.Fields[:lastIndex+1] - data, err := rlp.EncodeToBytes(&enc) - if err != nil { - return err - } - if err := ns.db.Put(append(ns.dbNodeKey, id[:]...), data); err != nil { - return err - } - node.dirty, node.db = false, true - - if ns.saveNodeHook != nil { - ns.saveNodeHook(node) - } - return nil -} - -// deleteNode removes a node info from the database -func (ns *NodeStateMachine) deleteNode(id enode.ID) { - ns.db.Delete(append(ns.dbNodeKey, id[:]...)) -} - -// saveToDb saves the persistent flags and fields of all nodes that have been changed -func (ns *NodeStateMachine) saveToDb() { - for id, node := range ns.nodes { - if node.dirty { - err := ns.saveNode(id, node) - if err != nil { - log.Error("Failed to save node", "id", id, "error", err) - } - } - } -} - -// updateEnode updates the enode entry belonging to the given node if it already exists -func (ns *NodeStateMachine) updateEnode(n *enode.Node) (enode.ID, *nodeInfo) { - id := n.ID() - node := ns.nodes[id] - if node != nil && n.Seq() > node.node.Seq() { - node.node = n - node.dirty = true - } - return id, node -} - -// Persist saves the persistent state and fields of the given node immediately -func (ns *NodeStateMachine) Persist(n *enode.Node) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if id, node := ns.updateEnode(n); node != nil && node.dirty { - err := ns.saveNode(id, node) - if err != nil { - log.Error("Failed to save node", "id", id, "error", err) - } - return err - } - return nil -} - -// SetState updates the given node state flags and blocks until the operation is finished. -// If a flag with a timeout is set again, the operation removes or replaces the existing timeout. -func (ns *NodeStateMachine) SetState(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - if !ns.opStart() { - return ErrClosed - } - ns.setState(n, setFlags, resetFlags, timeout) - ns.opFinish() - return nil -} - -// SetStateSub updates the given node state flags without blocking (should be called -// from a subscription/operation callback). -func (ns *NodeStateMachine) SetStateSub(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.opCheck() - ns.setState(n, setFlags, resetFlags, timeout) -} - -func (ns *NodeStateMachine) setState(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) { - ns.checkStarted() - set, reset := ns.stateMask(setFlags), ns.stateMask(resetFlags) - id, node := ns.updateEnode(n) - if node == nil { - if set == 0 { - return - } - node = ns.newNode(n) - ns.nodes[id] = node - } - oldState := node.state - newState := (node.state & (^reset)) | set - changed := oldState ^ newState - node.state = newState - - // Remove the timeout callbacks for all reset and set flags, - // even they are not existent(it's noop). - ns.removeTimeouts(node, set|reset) - - // Register the timeout callback if required - if timeout != 0 && set != 0 { - ns.addTimeout(n, set, timeout) - } - if newState == oldState { - return - } - if newState == 0 && node.fieldCount == 0 { - delete(ns.nodes, id) - if node.db { - ns.deleteNode(id) - } - } else { - if changed&ns.saveFlags != 0 { - node.dirty = true - } - } - callback := func() { - for _, sub := range ns.stateSubs { - if changed&sub.mask != 0 { - sub.callback(n, Flags{mask: oldState & sub.mask, setup: ns.setup}, Flags{mask: newState & sub.mask, setup: ns.setup}) - } - } - } - ns.opPending = append(ns.opPending, callback) -} - -// opCheck checks whether an operation is active -func (ns *NodeStateMachine) opCheck() { - if !ns.opFlag { - panic("Operation has not started") - } -} - -// opStart waits until other operations are finished and starts a new one -func (ns *NodeStateMachine) opStart() bool { - for ns.opFlag { - ns.opWait.Wait() - } - if ns.closed { - return false - } - ns.opFlag = true - return true -} - -// opFinish finishes the current operation by running all pending callbacks. -// Callbacks resulting from a state/field change performed in a previous callback are always -// put at the end of the pending list and therefore processed after all callbacks resulting -// from the previous state/field change. -func (ns *NodeStateMachine) opFinish() { - for len(ns.opPending) != 0 { - list := ns.opPending - ns.lock.Unlock() - for _, cb := range list { - cb() - } - ns.lock.Lock() - ns.opPending = ns.opPending[len(list):] - } - ns.opPending = nil - ns.opFlag = false - ns.opWait.Broadcast() -} - -// Operation calls the given function as an operation callback. This allows the caller -// to start an operation with multiple initial changes. The same rules apply as for -// subscription callbacks. -func (ns *NodeStateMachine) Operation(fn func()) error { - ns.lock.Lock() - started := ns.opStart() - ns.lock.Unlock() - if !started { - return ErrClosed - } - fn() - ns.lock.Lock() - ns.opFinish() - ns.lock.Unlock() - return nil -} - -// offlineCallbacks calls state update callbacks at startup or shutdown -func (ns *NodeStateMachine) offlineCallbacks(start bool) { - for _, cb := range ns.offlineCallbackList { - cb := cb - callback := func() { - for _, sub := range ns.stateSubs { - offState := offlineState & sub.mask - onState := cb.state & sub.mask - if offState == onState { - continue - } - if start { - sub.callback(cb.node.node, Flags{mask: offState, setup: ns.setup}, Flags{mask: onState, setup: ns.setup}) - } else { - sub.callback(cb.node.node, Flags{mask: onState, setup: ns.setup}, Flags{mask: offState, setup: ns.setup}) - } - } - for i, f := range cb.fields { - if f == nil || ns.fields[i].subs == nil { - continue - } - for _, fsub := range ns.fields[i].subs { - if start { - fsub(cb.node.node, Flags{mask: offlineState, setup: ns.setup}, nil, f) - } else { - fsub(cb.node.node, Flags{mask: offlineState, setup: ns.setup}, f, nil) - } - } - } - } - ns.opPending = append(ns.opPending, callback) - } - ns.offlineCallbackList = nil -} - -// AddTimeout adds a node state timeout associated to the given state flag(s). -// After the specified time interval, the relevant states will be reset. -func (ns *NodeStateMachine) AddTimeout(n *enode.Node, flags Flags, timeout time.Duration) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if ns.closed { - return ErrClosed - } - ns.addTimeout(n, ns.stateMask(flags), timeout) - return nil -} - -// addTimeout adds a node state timeout associated to the given state flag(s). -func (ns *NodeStateMachine) addTimeout(n *enode.Node, mask bitMask, timeout time.Duration) { - _, node := ns.updateEnode(n) - if node == nil { - return - } - mask &= node.state - if mask == 0 { - return - } - ns.removeTimeouts(node, mask) - t := &nodeStateTimeout{mask: mask} - t.timer = ns.clock.AfterFunc(timeout, func() { - ns.lock.Lock() - defer ns.lock.Unlock() - - if !ns.opStart() { - return - } - ns.setState(n, Flags{}, Flags{mask: t.mask, setup: ns.setup}, 0) - ns.opFinish() - }) - node.timeouts = append(node.timeouts, t) - if mask&ns.saveFlags != 0 { - node.dirty = true - } -} - -// removeTimeouts removes node state timeouts associated to the given state flag(s). -// If a timeout was associated to multiple flags which are not all included in the -// specified remove mask then only the included flags are de-associated and the timer -// stays active. -func (ns *NodeStateMachine) removeTimeouts(node *nodeInfo, mask bitMask) { - for i := 0; i < len(node.timeouts); i++ { - t := node.timeouts[i] - match := t.mask & mask - if match == 0 { - continue - } - t.mask -= match - if t.mask != 0 { - continue - } - t.timer.Stop() - node.timeouts[i] = node.timeouts[len(node.timeouts)-1] - node.timeouts = node.timeouts[:len(node.timeouts)-1] - i-- - if match&ns.saveFlags != 0 { - node.dirty = true - } - } -} - -// GetField retrieves the given field of the given node. Note that when used in a -// subscription callback the result can be out of sync with the state change represented -// by the callback parameters so extra safety checks might be necessary. -func (ns *NodeStateMachine) GetField(n *enode.Node, field Field) interface{} { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if ns.closed { - return nil - } - if _, node := ns.updateEnode(n); node != nil { - return node.fields[ns.fieldIndex(field)] - } - return nil -} - -// GetState retrieves the current state of the given node. Note that when used in a -// subscription callback the result can be out of sync with the state change represented -// by the callback parameters so extra safety checks might be necessary. -func (ns *NodeStateMachine) GetState(n *enode.Node) Flags { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if ns.closed { - return Flags{} - } - if _, node := ns.updateEnode(n); node != nil { - return Flags{mask: node.state, setup: ns.setup} - } - return Flags{} -} - -// SetField sets the given field of the given node and blocks until the operation is finished -func (ns *NodeStateMachine) SetField(n *enode.Node, field Field, value interface{}) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - if !ns.opStart() { - return ErrClosed - } - err := ns.setField(n, field, value) - ns.opFinish() - return err -} - -// SetFieldSub sets the given field of the given node without blocking (should be called -// from a subscription/operation callback). -func (ns *NodeStateMachine) SetFieldSub(n *enode.Node, field Field, value interface{}) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.opCheck() - return ns.setField(n, field, value) -} - -func (ns *NodeStateMachine) setField(n *enode.Node, field Field, value interface{}) error { - ns.checkStarted() - id, node := ns.updateEnode(n) - if node == nil { - if value == nil { - return nil - } - node = ns.newNode(n) - ns.nodes[id] = node - } - fieldIndex := ns.fieldIndex(field) - f := ns.fields[fieldIndex] - if value != nil && reflect.TypeOf(value) != f.ftype { - log.Error("Invalid field type", "type", reflect.TypeOf(value), "required", f.ftype) - return ErrInvalidField - } - oldValue := node.fields[fieldIndex] - if value == oldValue { - return nil - } - if oldValue != nil { - node.fieldCount-- - } - if value != nil { - node.fieldCount++ - } - node.fields[fieldIndex] = value - if node.state == 0 && node.fieldCount == 0 { - delete(ns.nodes, id) - if node.db { - ns.deleteNode(id) - } - } else { - if f.encode != nil { - node.dirty = true - } - } - state := node.state - callback := func() { - for _, cb := range f.subs { - cb(n, Flags{mask: state, setup: ns.setup}, oldValue, value) - } - } - ns.opPending = append(ns.opPending, callback) - return nil -} - -// ForEach calls the callback for each node having all of the required and none of the -// disabled flags set. -// Note that this callback is not an operation callback but ForEach can be called from an -// Operation callback or Operation can also be called from a ForEach callback if necessary. -func (ns *NodeStateMachine) ForEach(requireFlags, disableFlags Flags, cb func(n *enode.Node, state Flags)) { - ns.lock.Lock() - ns.checkStarted() - type callback struct { - node *enode.Node - state bitMask - } - require, disable := ns.stateMask(requireFlags), ns.stateMask(disableFlags) - var callbacks []callback - for _, node := range ns.nodes { - if node.state&require == require && node.state&disable == 0 { - callbacks = append(callbacks, callback{node.node, node.state & (require | disable)}) - } - } - ns.lock.Unlock() - for _, c := range callbacks { - cb(c.node, Flags{mask: c.state, setup: ns.setup}) - } -} - -// GetNode returns the enode currently associated with the given ID -func (ns *NodeStateMachine) GetNode(id enode.ID) *enode.Node { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if node := ns.nodes[id]; node != nil { - return node.node - } - return nil -} - -// AddLogMetrics adds logging and/or metrics for nodes entering, exiting and currently -// being in a given set specified by required and disabled state flags -func (ns *NodeStateMachine) AddLogMetrics(requireFlags, disableFlags Flags, name string, inMeter, outMeter metrics.Meter, gauge metrics.Gauge) { - var count int64 - ns.SubscribeState(requireFlags.Or(disableFlags), func(n *enode.Node, oldState, newState Flags) { - oldMatch := oldState.HasAll(requireFlags) && oldState.HasNone(disableFlags) - newMatch := newState.HasAll(requireFlags) && newState.HasNone(disableFlags) - if newMatch == oldMatch { - return - } - - if newMatch { - count++ - if name != "" { - log.Debug("Node entered", "set", name, "id", n.ID(), "count", count) - } - if inMeter != nil { - inMeter.Mark(1) - } - } else { - count-- - if name != "" { - log.Debug("Node left", "set", name, "id", n.ID(), "count", count) - } - if outMeter != nil { - outMeter.Mark(1) - } - } - if gauge != nil { - gauge.Update(count) - } - }) -} diff --git a/p2p/nodestate/nodestate_test.go b/p2p/nodestate/nodestate_test.go deleted file mode 100644 index d06ad755e22e..000000000000 --- a/p2p/nodestate/nodestate_test.go +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright 2020 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 nodestate - -import ( - "errors" - "fmt" - "reflect" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common/mclock" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/ethereum/go-ethereum/rlp" -) - -func testSetup(flagPersist []bool, fieldType []reflect.Type) (*Setup, []Flags, []Field) { - setup := &Setup{} - flags := make([]Flags, len(flagPersist)) - for i, persist := range flagPersist { - if persist { - flags[i] = setup.NewPersistentFlag(fmt.Sprintf("flag-%d", i)) - } else { - flags[i] = setup.NewFlag(fmt.Sprintf("flag-%d", i)) - } - } - fields := make([]Field, len(fieldType)) - for i, ftype := range fieldType { - switch ftype { - case reflect.TypeOf(uint64(0)): - fields[i] = setup.NewPersistentField(fmt.Sprintf("field-%d", i), ftype, uint64FieldEnc, uint64FieldDec) - case reflect.TypeOf(""): - fields[i] = setup.NewPersistentField(fmt.Sprintf("field-%d", i), ftype, stringFieldEnc, stringFieldDec) - default: - fields[i] = setup.NewField(fmt.Sprintf("field-%d", i), ftype) - } - } - return setup, flags, fields -} - -func testNode(b byte) *enode.Node { - r := &enr.Record{} - r.SetSig(dummyIdentity{b}, []byte{42}) - n, _ := enode.New(dummyIdentity{b}, r) - return n -} - -func TestCallback(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{false, false, false}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - set0 := make(chan struct{}, 1) - set1 := make(chan struct{}, 1) - set2 := make(chan struct{}, 1) - ns.SubscribeState(flags[0], func(n *enode.Node, oldState, newState Flags) { set0 <- struct{}{} }) - ns.SubscribeState(flags[1], func(n *enode.Node, oldState, newState Flags) { set1 <- struct{}{} }) - ns.SubscribeState(flags[2], func(n *enode.Node, oldState, newState Flags) { set2 <- struct{}{} }) - - ns.Start() - - ns.SetState(testNode(1), flags[0], Flags{}, 0) - ns.SetState(testNode(1), flags[1], Flags{}, time.Second) - ns.SetState(testNode(1), flags[2], Flags{}, 2*time.Second) - - for i := 0; i < 3; i++ { - select { - case <-set0: - case <-set1: - case <-set2: - case <-time.After(time.Second): - t.Fatalf("failed to invoke callback") - } - } -} - -func TestPersistentFlags(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{true, true, true, false}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - saveNode := make(chan *nodeInfo, 5) - ns.saveNodeHook = func(node *nodeInfo) { - saveNode <- node - } - - ns.Start() - - ns.SetState(testNode(1), flags[0], Flags{}, time.Second) // state with timeout should not be saved - ns.SetState(testNode(2), flags[1], Flags{}, 0) - ns.SetState(testNode(3), flags[2], Flags{}, 0) - ns.SetState(testNode(4), flags[3], Flags{}, 0) - ns.SetState(testNode(5), flags[0], Flags{}, 0) - ns.Persist(testNode(5)) - select { - case <-saveNode: - case <-time.After(time.Second): - t.Fatalf("Timeout") - } - ns.Stop() - - for i := 0; i < 2; i++ { - select { - case <-saveNode: - case <-time.After(time.Second): - t.Fatalf("Timeout") - } - } - select { - case <-saveNode: - t.Fatalf("Unexpected saveNode") - case <-time.After(time.Millisecond * 100): - } -} - -func TestSetField(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, fields := testSetup([]bool{true}, []reflect.Type{reflect.TypeOf("")}) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - saveNode := make(chan *nodeInfo, 1) - ns.saveNodeHook = func(node *nodeInfo) { - saveNode <- node - } - - ns.Start() - - // Set field before setting state - ns.SetField(testNode(1), fields[0], "hello world") - field := ns.GetField(testNode(1), fields[0]) - if field == nil { - t.Fatalf("Field should be set before setting states") - } - ns.SetField(testNode(1), fields[0], nil) - field = ns.GetField(testNode(1), fields[0]) - if field != nil { - t.Fatalf("Field should be unset") - } - // Set field after setting state - ns.SetState(testNode(1), flags[0], Flags{}, 0) - ns.SetField(testNode(1), fields[0], "hello world") - field = ns.GetField(testNode(1), fields[0]) - if field == nil { - t.Fatalf("Field should be set after setting states") - } - if err := ns.SetField(testNode(1), fields[0], 123); err == nil { - t.Fatalf("Invalid field should be rejected") - } - // Dirty node should be written back - ns.Stop() - select { - case <-saveNode: - case <-time.After(time.Second): - t.Fatalf("Timeout") - } -} - -func TestSetState(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{false, false, false}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - type change struct{ old, new Flags } - set := make(chan change, 1) - ns.SubscribeState(flags[0].Or(flags[1]), func(n *enode.Node, oldState, newState Flags) { - set <- change{ - old: oldState, - new: newState, - } - }) - - ns.Start() - - check := func(expectOld, expectNew Flags, expectChange bool) { - if expectChange { - select { - case c := <-set: - if !c.old.Equals(expectOld) { - t.Fatalf("Old state mismatch") - } - if !c.new.Equals(expectNew) { - t.Fatalf("New state mismatch") - } - case <-time.After(time.Second): - } - return - } - select { - case <-set: - t.Fatalf("Unexpected change") - case <-time.After(time.Millisecond * 100): - return - } - } - ns.SetState(testNode(1), flags[0], Flags{}, 0) - check(Flags{}, flags[0], true) - - ns.SetState(testNode(1), flags[1], Flags{}, 0) - check(flags[0], flags[0].Or(flags[1]), true) - - ns.SetState(testNode(1), flags[2], Flags{}, 0) - check(Flags{}, Flags{}, false) - - ns.SetState(testNode(1), Flags{}, flags[0], 0) - check(flags[0].Or(flags[1]), flags[1], true) - - ns.SetState(testNode(1), Flags{}, flags[1], 0) - check(flags[1], Flags{}, true) - - ns.SetState(testNode(1), Flags{}, flags[2], 0) - check(Flags{}, Flags{}, false) - - ns.SetState(testNode(1), flags[0].Or(flags[1]), Flags{}, time.Second) - check(Flags{}, flags[0].Or(flags[1]), true) - clock.Run(time.Second) - check(flags[0].Or(flags[1]), Flags{}, true) -} - -func uint64FieldEnc(field interface{}) ([]byte, error) { - if u, ok := field.(uint64); ok { - enc, err := rlp.EncodeToBytes(&u) - return enc, err - } - return nil, errors.New("invalid field type") -} - -func uint64FieldDec(enc []byte) (interface{}, error) { - var u uint64 - err := rlp.DecodeBytes(enc, &u) - return u, err -} - -func stringFieldEnc(field interface{}) ([]byte, error) { - if s, ok := field.(string); ok { - return []byte(s), nil - } - return nil, errors.New("invalid field type") -} - -func stringFieldDec(enc []byte) (interface{}, error) { - return string(enc), nil -} - -func TestPersistentFields(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, fields := testSetup([]bool{true}, []reflect.Type{reflect.TypeOf(uint64(0)), reflect.TypeOf("")}) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - ns.Start() - ns.SetState(testNode(1), flags[0], Flags{}, 0) - ns.SetField(testNode(1), fields[0], uint64(100)) - ns.SetField(testNode(1), fields[1], "hello world") - ns.Stop() - - ns2 := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - ns2.Start() - field0 := ns2.GetField(testNode(1), fields[0]) - if !reflect.DeepEqual(field0, uint64(100)) { - t.Fatalf("Field changed") - } - field1 := ns2.GetField(testNode(1), fields[1]) - if !reflect.DeepEqual(field1, "hello world") { - t.Fatalf("Field changed") - } - - s.Version++ - ns3 := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - ns3.Start() - if ns3.GetField(testNode(1), fields[0]) != nil { - t.Fatalf("Old field version should have been discarded") - } -} - -func TestFieldSub(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, fields := testSetup([]bool{true}, []reflect.Type{reflect.TypeOf(uint64(0))}) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - var ( - lastState Flags - lastOldValue, lastNewValue interface{} - ) - ns.SubscribeField(fields[0], func(n *enode.Node, state Flags, oldValue, newValue interface{}) { - lastState, lastOldValue, lastNewValue = state, oldValue, newValue - }) - check := func(state Flags, oldValue, newValue interface{}) { - if !lastState.Equals(state) || lastOldValue != oldValue || lastNewValue != newValue { - t.Fatalf("Incorrect field sub callback (expected [%v %v %v], got [%v %v %v])", state, oldValue, newValue, lastState, lastOldValue, lastNewValue) - } - } - ns.Start() - ns.SetState(testNode(1), flags[0], Flags{}, 0) - ns.SetField(testNode(1), fields[0], uint64(100)) - check(flags[0], nil, uint64(100)) - ns.Stop() - check(s.OfflineFlag(), uint64(100), nil) - - ns2 := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - ns2.SubscribeField(fields[0], func(n *enode.Node, state Flags, oldValue, newValue interface{}) { - lastState, lastOldValue, lastNewValue = state, oldValue, newValue - }) - ns2.Start() - check(s.OfflineFlag(), nil, uint64(100)) - ns2.SetState(testNode(1), Flags{}, flags[0], 0) - ns2.SetField(testNode(1), fields[0], nil) - check(Flags{}, uint64(100), nil) - ns2.Stop() -} - -func TestDuplicatedFlags(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{true}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - type change struct{ old, new Flags } - set := make(chan change, 1) - ns.SubscribeState(flags[0], func(n *enode.Node, oldState, newState Flags) { - set <- change{oldState, newState} - }) - - ns.Start() - defer ns.Stop() - - check := func(expectOld, expectNew Flags, expectChange bool) { - if expectChange { - select { - case c := <-set: - if !c.old.Equals(expectOld) { - t.Fatalf("Old state mismatch") - } - if !c.new.Equals(expectNew) { - t.Fatalf("New state mismatch") - } - case <-time.After(time.Second): - } - return - } - select { - case <-set: - t.Fatalf("Unexpected change") - case <-time.After(time.Millisecond * 100): - return - } - } - ns.SetState(testNode(1), flags[0], Flags{}, time.Second) - check(Flags{}, flags[0], true) - ns.SetState(testNode(1), flags[0], Flags{}, 2*time.Second) // extend the timeout to 2s - check(Flags{}, flags[0], false) - - clock.Run(2 * time.Second) - check(flags[0], Flags{}, true) -} - -func TestCallbackOrder(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{false, false, false, false}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - ns.SubscribeState(flags[0], func(n *enode.Node, oldState, newState Flags) { - if newState.Equals(flags[0]) { - ns.SetStateSub(n, flags[1], Flags{}, 0) - ns.SetStateSub(n, flags[2], Flags{}, 0) - } - }) - ns.SubscribeState(flags[1], func(n *enode.Node, oldState, newState Flags) { - if newState.Equals(flags[1]) { - ns.SetStateSub(n, flags[3], Flags{}, 0) - } - }) - lastState := Flags{} - ns.SubscribeState(MergeFlags(flags[1], flags[2], flags[3]), func(n *enode.Node, oldState, newState Flags) { - if !oldState.Equals(lastState) { - t.Fatalf("Wrong callback order") - } - lastState = newState - }) - - ns.Start() - defer ns.Stop() - - ns.SetState(testNode(1), flags[0], Flags{}, 0) -} From b8cf1636d4af9bf1eaea51294ad78885c4474091 Mon Sep 17 00:00:00 2001 From: Steven Wang <915337710@qq.com> Date: Wed, 29 May 2024 18:12:57 +0800 Subject: [PATCH 307/571] accounts: fix TestUpdateKeyfileContents (#29867) Create the directory before NewKeyStore. This ensures the watcher successfully starts on the first attempt, and waitWatcherStart functions as intended. --- accounts/keystore/account_cache_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index 1a9f9a4714cc..6bc14f5bb6d1 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -326,6 +326,11 @@ func TestUpdatedKeyfileContents(t *testing.T) { // Create a temporary keystore to test with dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int())) + + // Create the directory + os.MkdirAll(dir, 0700) + defer os.RemoveAll(dir) + ks := NewKeyStore(dir, LightScryptN, LightScryptP) list := ks.Accounts() @@ -335,9 +340,7 @@ func TestUpdatedKeyfileContents(t *testing.T) { if !waitWatcherStart(ks) { t.Fatal("keystore watcher didn't start in time") } - // Create the directory and copy a key file into it. - os.MkdirAll(dir, 0700) - defer os.RemoveAll(dir) + // Copy a key file into it file := filepath.Join(dir, "aaa") // Place one of our testfiles in there From 06263b1b356dde3e2509aef4efef295744e4f6c3 Mon Sep 17 00:00:00 2001 From: PolyMa <151764357+polymaer@users.noreply.github.com> Date: Wed, 29 May 2024 18:24:10 +0800 Subject: [PATCH 308/571] all: fix typos in comments (#29873) fix using `a` & `the` simutaneously --- cmd/geth/snapshot.go | 2 +- core/bloombits/scheduler.go | 2 +- eth/protocols/snap/sync.go | 2 +- ethdb/leveldb/leveldb.go | 2 +- ethdb/memorydb/memorydb.go | 2 +- ethdb/pebble/pebble.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 192c850868c8..cf7093e60560 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -91,7 +91,7 @@ data, and verifies that all snapshot storage data has a corresponding account. }, { Name: "inspect-account", - Usage: "Check all snapshot layers for the a specific account", + Usage: "Check all snapshot layers for the specific account", ArgsUsage: "
", Action: checkAccount, Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), diff --git a/core/bloombits/scheduler.go b/core/bloombits/scheduler.go index 6449c7465a17..a523bc55ab49 100644 --- a/core/bloombits/scheduler.go +++ b/core/bloombits/scheduler.go @@ -23,7 +23,7 @@ import ( // request represents a bloom retrieval task to prioritize and pull from the local // database or remotely from the network. type request struct { - section uint64 // Section index to retrieve the a bit-vector from + section uint64 // Section index to retrieve the bit-vector from bit uint // Bit index within the section to retrieve the vector of } diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 8671aebc9081..53cba5d11528 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -103,7 +103,7 @@ var ( // to allow concurrent retrievals. accountConcurrency = 16 - // storageConcurrency is the number of chunks to split the a large contract + // storageConcurrency is the number of chunks to split a large contract // storage trie into to allow concurrent retrievals. storageConcurrency = 16 ) diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index e58efbddbe80..64f51cf21701 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -400,7 +400,7 @@ func (b *batch) Put(key, value []byte) error { return nil } -// Delete inserts the a key removal into the batch for later committing. +// Delete inserts the key removal into the batch for later committing. func (b *batch) Delete(key []byte) error { b.b.Delete(key) b.size += len(key) diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index 2a939f9a1850..d1233acb2198 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -227,7 +227,7 @@ func (b *batch) Put(key, value []byte) error { return nil } -// Delete inserts the a key removal into the batch for later committing. +// Delete inserts the key removal into the batch for later committing. func (b *batch) Delete(key []byte) error { b.writes = append(b.writes, keyvalue{string(key), nil, true}) b.size += len(key) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index ee4e5dd75a56..dda084ae3b4e 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -575,7 +575,7 @@ func (b *batch) Put(key, value []byte) error { return nil } -// Delete inserts the a key removal into the batch for later committing. +// Delete inserts the key removal into the batch for later committing. func (b *batch) Delete(key []byte) error { b.b.Delete(key, nil) b.size += len(key) From 2f0e63e5ac6e1c1c85b5831a19bf7bbd6a63ca1d Mon Sep 17 00:00:00 2001 From: trillo Date: Wed, 29 May 2024 21:43:07 +0900 Subject: [PATCH 309/571] eth/downloader, eth/tracer: fix typos in comments (#29707) --- eth/downloader/api.go | 2 +- eth/tracers/api_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/downloader/api.go b/eth/downloader/api.go index 90c36afbb5ba..ac175672a0ce 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -129,7 +129,7 @@ func (api *DownloaderAPI) eventLoop() { } } -// Syncing provides information when this nodes starts synchronising with the Ethereum network and when it's finished. +// Syncing provides information when this node starts synchronising with the Ethereum network and when it's finished. func (api *DownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 120cb585c711..6fbb50848d63 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -312,7 +312,7 @@ func TestTraceCall(t *testing.T) { config: &TraceCallConfig{TxIndex: uintPtr(1)}, expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr), }, - // After the target transaction, should be succeed + // After the target transaction, should be succeeded { blockNumber: rpc.BlockNumber(genBlocks - 1), call: ethapi.TransactionArgs{ From e26fa9e40ebddc39247ca11cae28c7f6bd8337e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=9B=E6=99=93=E5=A9=95?= <30611384+niuxiaojie81@users.noreply.github.com> Date: Wed, 29 May 2024 20:44:14 +0800 Subject: [PATCH 310/571] core/state: fix typo in comment (#29639) --- core/state/statedb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index ccc7ca4ba236..fe262d4695df 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -351,7 +351,7 @@ func (s *StateDB) GetStorageRoot(addr common.Address) common.Hash { return common.Hash{} } -// TxIndex returns the current transaction index set by Prepare. +// TxIndex returns the current transaction index set by SetTxContext. func (s *StateDB) TxIndex() int { return s.txIndex } From 94a8b296e4c0abb90e31f35d0fc433869740207d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 29 May 2024 15:02:26 +0200 Subject: [PATCH 311/571] p2p/discover: refactor node and endpoint representation (#29844) Here we clean up internal uses of type discover.node, converting most code to use enode.Node instead. The discover.node type used to be the canonical representation of network hosts before ENR was introduced. Most code worked with *node to avoid conversions when interacting with Table methods. Since *node also contains internal state of Table and is a mutable type, using *node outside of Table code is prone to data races. It's also cleaner not having to wrap/unwrap *enode.Node all the time. discover.node has been renamed to tableNode to clarify its purpose. While here, we also change most uses of net.UDPAddr into netip.AddrPort. While this is technically a separate refactoring from the *node -> *enode.Node change, it is more convenient because *enode.Node handles IP addresses as netip.Addr. The switch to package netip in discovery would've happened very soon anyway. The change to netip.AddrPort stops at certain interface points. For example, since package p2p/netutil has not been converted to use netip.Addr yet, we still have to convert to net.IP/net.UDPAddr in a few places. --- cmd/devp2p/internal/v4test/framework.go | 2 +- p2p/discover/common.go | 7 +- p2p/discover/lookup.go | 18 +-- p2p/discover/metrics.go | 14 +-- p2p/discover/node.go | 69 +++++++---- p2p/discover/table.go | 125 +++++++------------- p2p/discover/table_reval.go | 22 ++-- p2p/discover/table_reval_test.go | 4 +- p2p/discover/table_test.go | 80 ++++++------- p2p/discover/table_util_test.go | 34 +++--- p2p/discover/v4_lookup_test.go | 27 ++--- p2p/discover/v4_udp.go | 146 ++++++++++++++---------- p2p/discover/v4_udp_test.go | 107 +++++++++-------- p2p/discover/v4wire/v4wire.go | 16 +-- p2p/discover/v5_talk.go | 6 +- p2p/discover/v5_udp.go | 80 +++++++------ p2p/discover/v5_udp_test.go | 93 ++++++++------- p2p/server.go | 7 +- 18 files changed, 429 insertions(+), 428 deletions(-) diff --git a/cmd/devp2p/internal/v4test/framework.go b/cmd/devp2p/internal/v4test/framework.go index 92865941810b..e8f4c021b81e 100644 --- a/cmd/devp2p/internal/v4test/framework.go +++ b/cmd/devp2p/internal/v4test/framework.go @@ -110,7 +110,7 @@ func (te *testenv) localEndpoint(c net.PacketConn) v4wire.Endpoint { } func (te *testenv) remoteEndpoint() v4wire.Endpoint { - return v4wire.NewEndpoint(te.remoteAddr, 0) + return v4wire.NewEndpoint(te.remoteAddr.AddrPort(), 0) } func contains(ns []v4wire.Node, key v4wire.Pubkey) bool { diff --git a/p2p/discover/common.go b/p2p/discover/common.go index bebea8cc3846..0716f7472fce 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -22,6 +22,7 @@ import ( "encoding/binary" "math/rand" "net" + "net/netip" "sync" "time" @@ -34,8 +35,8 @@ import ( // UDPConn is a network connection on which discovery can operate. type UDPConn interface { - ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) - WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) + ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) + WriteToUDPAddrPort(b []byte, addr netip.AddrPort) (n int, err error) Close() error LocalAddr() net.Addr } @@ -94,7 +95,7 @@ func ListenUDP(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { // channel if configured. type ReadPacket struct { Data []byte - Addr *net.UDPAddr + Addr netip.AddrPort } type randomSource interface { diff --git a/p2p/discover/lookup.go b/p2p/discover/lookup.go index 5c3d90d6c90f..09808b71e079 100644 --- a/p2p/discover/lookup.go +++ b/p2p/discover/lookup.go @@ -29,16 +29,16 @@ import ( // not need to be an actual node identifier. type lookup struct { tab *Table - queryfunc func(*node) ([]*node, error) - replyCh chan []*node + queryfunc queryFunc + replyCh chan []*enode.Node cancelCh <-chan struct{} asked, seen map[enode.ID]bool result nodesByDistance - replyBuffer []*node + replyBuffer []*enode.Node queries int } -type queryFunc func(*node) ([]*node, error) +type queryFunc func(*enode.Node) ([]*enode.Node, error) func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *lookup { it := &lookup{ @@ -47,7 +47,7 @@ func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *l asked: make(map[enode.ID]bool), seen: make(map[enode.ID]bool), result: nodesByDistance{target: target}, - replyCh: make(chan []*node, alpha), + replyCh: make(chan []*enode.Node, alpha), cancelCh: ctx.Done(), queries: -1, } @@ -61,7 +61,7 @@ func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *l func (it *lookup) run() []*enode.Node { for it.advance() { } - return unwrapNodes(it.result.entries) + return it.result.entries } // advance advances the lookup until any new nodes have been found. @@ -139,7 +139,7 @@ func (it *lookup) slowdown() { } } -func (it *lookup) query(n *node, reply chan<- []*node) { +func (it *lookup) query(n *enode.Node, reply chan<- []*enode.Node) { r, err := it.queryfunc(n) if !errors.Is(err, errClosed) { // avoid recording failures on shutdown. success := len(r) > 0 @@ -154,7 +154,7 @@ func (it *lookup) query(n *node, reply chan<- []*node) { // lookupIterator performs lookup operations and iterates over all seen nodes. // When a lookup finishes, a new one is created through nextLookup. type lookupIterator struct { - buffer []*node + buffer []*enode.Node nextLookup lookupFunc ctx context.Context cancel func() @@ -173,7 +173,7 @@ func (it *lookupIterator) Node() *enode.Node { if len(it.buffer) == 0 { return nil } - return unwrapNode(it.buffer[0]) + return it.buffer[0] } // Next moves to the next node. diff --git a/p2p/discover/metrics.go b/p2p/discover/metrics.go index 3cd0ab041403..8deafbbce47b 100644 --- a/p2p/discover/metrics.go +++ b/p2p/discover/metrics.go @@ -18,7 +18,7 @@ package discover import ( "fmt" - "net" + "net/netip" "github.com/ethereum/go-ethereum/metrics" ) @@ -58,16 +58,16 @@ func newMeteredConn(conn UDPConn) UDPConn { return &meteredUdpConn{UDPConn: conn} } -// ReadFromUDP delegates a network read to the underlying connection, bumping the udp ingress traffic meter along the way. -func (c *meteredUdpConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) { - n, addr, err = c.UDPConn.ReadFromUDP(b) +// ReadFromUDPAddrPort delegates a network read to the underlying connection, bumping the udp ingress traffic meter along the way. +func (c *meteredUdpConn) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) { + n, addr, err = c.UDPConn.ReadFromUDPAddrPort(b) ingressTrafficMeter.Mark(int64(n)) return n, addr, err } -// Write delegates a network write to the underlying connection, bumping the udp egress traffic meter along the way. -func (c *meteredUdpConn) WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) { - n, err = c.UDPConn.WriteToUDP(b, addr) +// WriteToUDP delegates a network write to the underlying connection, bumping the udp egress traffic meter along the way. +func (c *meteredUdpConn) WriteToUDP(b []byte, addr netip.AddrPort) (n int, err error) { + n, err = c.UDPConn.WriteToUDPAddrPort(b, addr) egressTrafficMeter.Mark(int64(n)) return n, err } diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 47788248f438..042619221bde 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -21,7 +21,8 @@ import ( "crypto/elliptic" "errors" "math/big" - "net" + "slices" + "sort" "time" "github.com/ethereum/go-ethereum/common/math" @@ -37,9 +38,8 @@ type BucketNode struct { Live bool `json:"live"` } -// node represents a host on the network. -// The fields of Node may not be modified. -type node struct { +// tableNode is an entry in Table. +type tableNode struct { *enode.Node revalList *revalidationList addedToTable time.Time // first time node was added to bucket or replacement list @@ -75,34 +75,59 @@ func (e encPubkey) id() enode.ID { return enode.ID(crypto.Keccak256Hash(e[:])) } -func wrapNode(n *enode.Node) *node { - return &node{Node: n} -} - -func wrapNodes(ns []*enode.Node) []*node { - result := make([]*node, len(ns)) +func unwrapNodes(ns []*tableNode) []*enode.Node { + result := make([]*enode.Node, len(ns)) for i, n := range ns { - result[i] = wrapNode(n) + result[i] = n.Node } return result } -func unwrapNode(n *node) *enode.Node { - return n.Node +func (n *tableNode) String() string { + return n.Node.String() +} + +// nodesByDistance is a list of nodes, ordered by distance to target. +type nodesByDistance struct { + entries []*enode.Node + target enode.ID } -func unwrapNodes(ns []*node) []*enode.Node { - result := make([]*enode.Node, len(ns)) - for i, n := range ns { - result[i] = unwrapNode(n) +// push adds the given node to the list, keeping the total size below maxElems. +func (h *nodesByDistance) push(n *enode.Node, maxElems int) { + ix := sort.Search(len(h.entries), func(i int) bool { + return enode.DistCmp(h.target, h.entries[i].ID(), n.ID()) > 0 + }) + + end := len(h.entries) + if len(h.entries) < maxElems { + h.entries = append(h.entries, n) + } + if ix < end { + // Slide existing entries down to make room. + // This will overwrite the entry we just appended. + copy(h.entries[ix+1:], h.entries[ix:]) + h.entries[ix] = n } - return result } -func (n *node) addr() *net.UDPAddr { - return &net.UDPAddr{IP: n.IP(), Port: n.UDP()} +type nodeType interface { + ID() enode.ID } -func (n *node) String() string { - return n.Node.String() +// containsID reports whether ns contains a node with the given ID. +func containsID[N nodeType](ns []N, id enode.ID) bool { + for _, n := range ns { + if n.ID() == id { + return true + } + } + return false +} + +// deleteNode removes a node from the list. +func deleteNode[N nodeType](list []N, id enode.ID) []N { + return slices.DeleteFunc(list, func(n N) bool { + return n.ID() == id + }) } diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 2b4ba7f5d813..bd3c9b4143f0 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -27,7 +27,6 @@ import ( "fmt" "net" "slices" - "sort" "sync" "time" @@ -65,7 +64,7 @@ const ( type Table struct { mutex sync.Mutex // protects buckets, bucket content, nursery, rand buckets [nBuckets]*bucket // index of known nodes by distance - nursery []*node // bootstrap nodes + nursery []*enode.Node // bootstrap nodes rand reseedingRandom // source of randomness, periodically reseeded ips netutil.DistinctNetSet revalidation tableRevalidation @@ -85,8 +84,8 @@ type Table struct { closeReq chan struct{} closed chan struct{} - nodeAddedHook func(*bucket, *node) - nodeRemovedHook func(*bucket, *node) + nodeAddedHook func(*bucket, *tableNode) + nodeRemovedHook func(*bucket, *tableNode) } // transport is implemented by the UDP transports. @@ -101,20 +100,21 @@ type transport interface { // bucket contains nodes, ordered by their last activity. the entry // that was most recently active is the first element in entries. type bucket struct { - entries []*node // live entries, sorted by time of last contact - replacements []*node // recently seen nodes to be used if revalidation fails + entries []*tableNode // live entries, sorted by time of last contact + replacements []*tableNode // recently seen nodes to be used if revalidation fails ips netutil.DistinctNetSet index int } type addNodeOp struct { - node *node - isInbound bool + node *enode.Node + isInbound bool + forceSetLive bool // for tests } type trackRequestOp struct { - node *node - foundNodes []*node + node *enode.Node + foundNodes []*enode.Node success bool } @@ -186,7 +186,7 @@ func (tab *Table) getNode(id enode.ID) *enode.Node { b := tab.bucket(id) for _, e := range b.entries { if e.ID() == id { - return unwrapNode(e) + return e.Node } } return nil @@ -202,7 +202,7 @@ func (tab *Table) close() { // are used to connect to the network if the table is empty and there // are no known nodes in the database. func (tab *Table) setFallbackNodes(nodes []*enode.Node) error { - nursery := make([]*node, 0, len(nodes)) + nursery := make([]*enode.Node, 0, len(nodes)) for _, n := range nodes { if err := n.ValidateComplete(); err != nil { return fmt.Errorf("bad bootstrap node %q: %v", n, err) @@ -211,7 +211,7 @@ func (tab *Table) setFallbackNodes(nodes []*enode.Node) error { tab.log.Error("Bootstrap node filtered by netrestrict", "id", n.ID(), "ip", n.IP()) continue } - nursery = append(nursery, wrapNode(n)) + nursery = append(nursery, n) } tab.nursery = nursery return nil @@ -255,9 +255,9 @@ func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) * liveNodes := &nodesByDistance{target: target} for _, b := range &tab.buckets { for _, n := range b.entries { - nodes.push(n, nresults) + nodes.push(n.Node, nresults) if preferLive && n.isValidatedLive { - liveNodes.push(n, nresults) + liveNodes.push(n.Node, nresults) } } } @@ -309,8 +309,8 @@ func (tab *Table) len() (n int) { // list. // // The caller must not hold tab.mutex. -func (tab *Table) addFoundNode(n *node) bool { - op := addNodeOp{node: n, isInbound: false} +func (tab *Table) addFoundNode(n *enode.Node, forceSetLive bool) bool { + op := addNodeOp{node: n, isInbound: false, forceSetLive: forceSetLive} select { case tab.addNodeCh <- op: return <-tab.addNodeHandled @@ -327,7 +327,7 @@ func (tab *Table) addFoundNode(n *node) bool { // repeatedly. // // The caller must not hold tab.mutex. -func (tab *Table) addInboundNode(n *node) bool { +func (tab *Table) addInboundNode(n *enode.Node) bool { op := addNodeOp{node: n, isInbound: true} select { case tab.addNodeCh <- op: @@ -337,7 +337,7 @@ func (tab *Table) addInboundNode(n *node) bool { } } -func (tab *Table) trackRequest(n *node, success bool, foundNodes []*node) { +func (tab *Table) trackRequest(n *enode.Node, success bool, foundNodes []*enode.Node) { op := trackRequestOp{n, foundNodes, success} select { case tab.trackRequestCh <- op: @@ -443,13 +443,14 @@ func (tab *Table) doRefresh(done chan struct{}) { } func (tab *Table) loadSeedNodes() { - seeds := wrapNodes(tab.db.QuerySeeds(seedCount, seedMaxAge)) + seeds := tab.db.QuerySeeds(seedCount, seedMaxAge) seeds = append(seeds, tab.nursery...) for i := range seeds { seed := seeds[i] if tab.log.Enabled(context.Background(), log.LevelTrace) { age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) - tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age) + addr, _ := seed.UDPEndpoint() + tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", addr, "age", age) } tab.handleAddNode(addNodeOp{node: seed, isInbound: false}) } @@ -513,7 +514,7 @@ func (tab *Table) handleAddNode(req addNodeOp) bool { } b := tab.bucket(req.node.ID()) - n, _ := tab.bumpInBucket(b, req.node.Node, req.isInbound) + n, _ := tab.bumpInBucket(b, req.node, req.isInbound) if n != nil { // Already in bucket. return false @@ -529,15 +530,20 @@ func (tab *Table) handleAddNode(req addNodeOp) bool { } // Add to bucket. - b.entries = append(b.entries, req.node) - b.replacements = deleteNode(b.replacements, req.node) - tab.nodeAdded(b, req.node) + wn := &tableNode{Node: req.node} + if req.forceSetLive { + wn.livenessChecks = 1 + wn.isValidatedLive = true + } + b.entries = append(b.entries, wn) + b.replacements = deleteNode(b.replacements, wn.ID()) + tab.nodeAdded(b, wn) return true } // addReplacement adds n to the replacement cache of bucket b. -func (tab *Table) addReplacement(b *bucket, n *node) { - if contains(b.replacements, n.ID()) { +func (tab *Table) addReplacement(b *bucket, n *enode.Node) { + if containsID(b.replacements, n.ID()) { // TODO: update ENR return } @@ -545,15 +551,15 @@ func (tab *Table) addReplacement(b *bucket, n *node) { return } - n.addedToTable = time.Now() - var removed *node - b.replacements, removed = pushNode(b.replacements, n, maxReplacements) + wn := &tableNode{Node: n, addedToTable: time.Now()} + var removed *tableNode + b.replacements, removed = pushNode(b.replacements, wn, maxReplacements) if removed != nil { tab.removeIP(b, removed.IP()) } } -func (tab *Table) nodeAdded(b *bucket, n *node) { +func (tab *Table) nodeAdded(b *bucket, n *tableNode) { if n.addedToTable == (time.Time{}) { n.addedToTable = time.Now() } @@ -567,7 +573,7 @@ func (tab *Table) nodeAdded(b *bucket, n *node) { } } -func (tab *Table) nodeRemoved(b *bucket, n *node) { +func (tab *Table) nodeRemoved(b *bucket, n *tableNode) { tab.revalidation.nodeRemoved(n) if tab.nodeRemovedHook != nil { tab.nodeRemovedHook(b, n) @@ -579,8 +585,8 @@ func (tab *Table) nodeRemoved(b *bucket, n *node) { // deleteInBucket removes node n from the table. // If there are replacement nodes in the bucket, the node is replaced. -func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *node { - index := slices.IndexFunc(b.entries, func(e *node) bool { return e.ID() == id }) +func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *tableNode { + index := slices.IndexFunc(b.entries, func(e *tableNode) bool { return e.ID() == id }) if index == -1 { // Entry has been removed already. return nil @@ -608,8 +614,8 @@ func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *node { // bumpInBucket updates a node record if it exists in the bucket. // The second return value reports whether the node's endpoint (IP/port) was updated. -func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) (n *node, endpointChanged bool) { - i := slices.IndexFunc(b.entries, func(elem *node) bool { +func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) (n *tableNode, endpointChanged bool) { + i := slices.IndexFunc(b.entries, func(elem *tableNode) bool { return elem.ID() == newRecord.ID() }) if i == -1 { @@ -672,21 +678,12 @@ func (tab *Table) handleTrackRequest(op trackRequestOp) { // Add found nodes. for _, n := range op.foundNodes { - tab.handleAddNode(addNodeOp{n, false}) + tab.handleAddNode(addNodeOp{n, false, false}) } } -func contains(ns []*node, id enode.ID) bool { - for _, n := range ns { - if n.ID() == id { - return true - } - } - return false -} - // pushNode adds n to the front of list, keeping at most max items. -func pushNode(list []*node, n *node, max int) ([]*node, *node) { +func pushNode(list []*tableNode, n *tableNode, max int) ([]*tableNode, *tableNode) { if len(list) < max { list = append(list, nil) } @@ -695,37 +692,3 @@ func pushNode(list []*node, n *node, max int) ([]*node, *node) { list[0] = n return list, removed } - -// deleteNode removes n from list. -func deleteNode(list []*node, n *node) []*node { - for i := range list { - if list[i].ID() == n.ID() { - return append(list[:i], list[i+1:]...) - } - } - return list -} - -// nodesByDistance is a list of nodes, ordered by distance to target. -type nodesByDistance struct { - entries []*node - target enode.ID -} - -// push adds the given node to the list, keeping the total size below maxElems. -func (h *nodesByDistance) push(n *node, maxElems int) { - ix := sort.Search(len(h.entries), func(i int) bool { - return enode.DistCmp(h.target, h.entries[i].ID(), n.ID()) > 0 - }) - - end := len(h.entries) - if len(h.entries) < maxElems { - h.entries = append(h.entries, n) - } - if ix < end { - // Slide existing entries down to make room. - // This will overwrite the entry we just appended. - copy(h.entries[ix+1:], h.entries[ix:]) - h.entries[ix] = n - } -} diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index 5d185aa8b428..f2ea8b34fa3e 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -39,7 +39,7 @@ type tableRevalidation struct { } type revalidationResponse struct { - n *node + n *tableNode newRecord *enode.Node didRespond bool } @@ -55,12 +55,12 @@ func (tr *tableRevalidation) init(cfg *Config) { } // nodeAdded is called when the table receives a new node. -func (tr *tableRevalidation) nodeAdded(tab *Table, n *node) { +func (tr *tableRevalidation) nodeAdded(tab *Table, n *tableNode) { tr.fast.push(n, tab.cfg.Clock.Now(), &tab.rand) } // nodeRemoved is called when a node was removed from the table. -func (tr *tableRevalidation) nodeRemoved(n *node) { +func (tr *tableRevalidation) nodeRemoved(n *tableNode) { if n.revalList == nil { panic(fmt.Errorf("removed node %v has nil revalList", n.ID())) } @@ -68,7 +68,7 @@ func (tr *tableRevalidation) nodeRemoved(n *node) { } // nodeEndpointChanged is called when a change in IP or port is detected. -func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *node) { +func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *tableNode) { n.isValidatedLive = false tr.moveToList(&tr.fast, n, tab.cfg.Clock.Now(), &tab.rand) } @@ -90,7 +90,7 @@ func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mcloc } // startRequest spawns a revalidation request for node n. -func (tr *tableRevalidation) startRequest(tab *Table, n *node) { +func (tr *tableRevalidation) startRequest(tab *Table, n *tableNode) { if _, ok := tr.activeReq[n.ID()]; ok { panic(fmt.Errorf("duplicate startRequest (node %v)", n.ID())) } @@ -180,7 +180,7 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons } // moveToList ensures n is in the 'dest' list. -func (tr *tableRevalidation) moveToList(dest *revalidationList, n *node, now mclock.AbsTime, rand randomSource) { +func (tr *tableRevalidation) moveToList(dest *revalidationList, n *tableNode, now mclock.AbsTime, rand randomSource) { if n.revalList == dest { return } @@ -192,14 +192,14 @@ func (tr *tableRevalidation) moveToList(dest *revalidationList, n *node, now mcl // revalidationList holds a list nodes and the next revalidation time. type revalidationList struct { - nodes []*node + nodes []*tableNode nextTime mclock.AbsTime interval time.Duration name string } // get returns a random node from the queue. Nodes in the 'exclude' map are not returned. -func (list *revalidationList) get(now mclock.AbsTime, rand randomSource, exclude map[enode.ID]struct{}) *node { +func (list *revalidationList) get(now mclock.AbsTime, rand randomSource, exclude map[enode.ID]struct{}) *tableNode { if now < list.nextTime || len(list.nodes) == 0 { return nil } @@ -217,7 +217,7 @@ func (list *revalidationList) schedule(now mclock.AbsTime, rand randomSource) { list.nextTime = now.Add(time.Duration(rand.Int63n(int64(list.interval)))) } -func (list *revalidationList) push(n *node, now mclock.AbsTime, rand randomSource) { +func (list *revalidationList) push(n *tableNode, now mclock.AbsTime, rand randomSource) { list.nodes = append(list.nodes, n) if list.nextTime == never { list.schedule(now, rand) @@ -225,7 +225,7 @@ func (list *revalidationList) push(n *node, now mclock.AbsTime, rand randomSourc n.revalList = list } -func (list *revalidationList) remove(n *node) { +func (list *revalidationList) remove(n *tableNode) { i := slices.Index(list.nodes, n) if i == -1 { panic(fmt.Errorf("node %v not found in list", n.ID())) @@ -238,7 +238,7 @@ func (list *revalidationList) remove(n *node) { } func (list *revalidationList) contains(id enode.ID) bool { - return slices.ContainsFunc(list.nodes, func(n *node) bool { + return slices.ContainsFunc(list.nodes, func(n *tableNode) bool { return n.ID() == id }) } diff --git a/p2p/discover/table_reval_test.go b/p2p/discover/table_reval_test.go index d168767e0dd8..360544393439 100644 --- a/p2p/discover/table_reval_test.go +++ b/p2p/discover/table_reval_test.go @@ -110,10 +110,10 @@ func TestRevalidation_endpointUpdate(t *testing.T) { } tr.handleResponse(tab, resp) - if !tr.fast.contains(node.ID()) { + if tr.fast.nodes[0].ID() != node.ID() { t.Fatal("node not contained in fast revalidation list") } - if node.isValidatedLive { + if tr.fast.nodes[0].isValidatedLive { t.Fatal("node is marked live after endpoint change") } } diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index b0be2a94c5b9..30e7d56f4afd 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -22,6 +22,7 @@ import ( "math/rand" "net" "reflect" + "slices" "testing" "testing/quick" "time" @@ -64,7 +65,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding // Fill up the sender's bucket. replacementNodeKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") - replacementNode := wrapNode(enode.NewV4(&replacementNodeKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99)) + replacementNode := enode.NewV4(&replacementNodeKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99) last := fillBucket(tab, replacementNode.ID()) tab.mutex.Lock() nodeEvents := newNodeEventRecorder(128) @@ -78,7 +79,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding transport.dead[replacementNode.ID()] = !newNodeIsResponding // Add replacement node to table. - tab.addFoundNode(replacementNode) + tab.addFoundNode(replacementNode, false) t.Log("last:", last.ID()) t.Log("replacement:", replacementNode.ID()) @@ -115,11 +116,11 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding if l := len(bucket.entries); l != wantSize { t.Errorf("wrong bucket size after revalidation: got %d, want %d", l, wantSize) } - if ok := contains(bucket.entries, last.ID()); ok != lastInBucketIsResponding { + if ok := containsID(bucket.entries, last.ID()); ok != lastInBucketIsResponding { t.Errorf("revalidated node found: %t, want: %t", ok, lastInBucketIsResponding) } wantNewEntry := newNodeIsResponding && !lastInBucketIsResponding - if ok := contains(bucket.entries, replacementNode.ID()); ok != wantNewEntry { + if ok := containsID(bucket.entries, replacementNode.ID()); ok != wantNewEntry { t.Errorf("replacement node found: %t, want: %t", ok, wantNewEntry) } } @@ -153,7 +154,7 @@ func TestTable_IPLimit(t *testing.T) { for i := 0; i < tableIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), i, net.IP{172, 0, 1, byte(i)}) - tab.addFoundNode(n) + tab.addFoundNode(n, false) } if tab.len() > tableIPLimit { t.Errorf("too many nodes in table") @@ -171,7 +172,7 @@ func TestTable_BucketIPLimit(t *testing.T) { d := 3 for i := 0; i < bucketIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), d, net.IP{172, 0, 1, byte(i)}) - tab.addFoundNode(n) + tab.addFoundNode(n, false) } if tab.len() > bucketIPLimit { t.Errorf("too many nodes in table") @@ -232,7 +233,7 @@ func TestTable_findnodeByID(t *testing.T) { // check that the result nodes have minimum distance to target. for _, b := range tab.buckets { for _, n := range b.entries { - if contains(result, n.ID()) { + if containsID(result, n.ID()) { continue // don't run the check below for nodes in result } farthestResult := result[len(result)-1].ID() @@ -255,7 +256,7 @@ func TestTable_findnodeByID(t *testing.T) { type closeTest struct { Self enode.ID Target enode.ID - All []*node + All []*enode.Node N int } @@ -268,8 +269,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { for _, id := range gen([]enode.ID{}, rand).([]enode.ID) { r := new(enr.Record) r.Set(enr.IP(genIP(rand))) - n := wrapNode(enode.SignNull(r, id)) - n.livenessChecks = 1 + n := enode.SignNull(r, id) t.All = append(t.All, n) } return reflect.ValueOf(t) @@ -284,16 +284,16 @@ func TestTable_addInboundNode(t *testing.T) { // Insert two nodes. n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) - tab.addFoundNode(n1) - tab.addFoundNode(n2) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node}) + tab.addFoundNode(n1, false) + tab.addFoundNode(n2, false) + checkBucketContent(t, tab, []*enode.Node{n1, n2}) // Add a changed version of n2. The bucket should be updated. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) n2v2 := enode.SignNull(newrec, n2.ID()) - tab.addInboundNode(wrapNode(n2v2)) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) + tab.addInboundNode(n2v2) + checkBucketContent(t, tab, []*enode.Node{n1, n2v2}) // Try updating n2 without sequence number change. The update is accepted // because it's inbound. @@ -301,8 +301,8 @@ func TestTable_addInboundNode(t *testing.T) { newrec.Set(enr.IP{100, 100, 100, 100}) newrec.SetSeq(n2.Seq()) n2v3 := enode.SignNull(newrec, n2.ID()) - tab.addInboundNode(wrapNode(n2v3)) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v3}) + tab.addInboundNode(n2v3) + checkBucketContent(t, tab, []*enode.Node{n1, n2v3}) } func TestTable_addFoundNode(t *testing.T) { @@ -314,16 +314,16 @@ func TestTable_addFoundNode(t *testing.T) { // Insert two nodes. n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) - tab.addFoundNode(n1) - tab.addFoundNode(n2) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node}) + tab.addFoundNode(n1, false) + tab.addFoundNode(n2, false) + checkBucketContent(t, tab, []*enode.Node{n1, n2}) // Add a changed version of n2. The bucket should be updated. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) n2v2 := enode.SignNull(newrec, n2.ID()) - tab.addFoundNode(wrapNode(n2v2)) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) + tab.addFoundNode(n2v2, false) + checkBucketContent(t, tab, []*enode.Node{n1, n2v2}) // Try updating n2 without a sequence number change. // The update should not be accepted. @@ -331,8 +331,8 @@ func TestTable_addFoundNode(t *testing.T) { newrec.Set(enr.IP{100, 100, 100, 100}) newrec.SetSeq(n2.Seq()) n2v3 := enode.SignNull(newrec, n2.ID()) - tab.addFoundNode(wrapNode(n2v3)) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) + tab.addFoundNode(n2v3, false) + checkBucketContent(t, tab, []*enode.Node{n1, n2v2}) } // This test checks that discv4 nodes can update their own endpoint via PING. @@ -345,13 +345,13 @@ func TestTable_addInboundNodeUpdateV4Accept(t *testing.T) { // Add a v4 node. key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3") n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000) - tab.addInboundNode(wrapNode(n1)) + tab.addInboundNode(n1) checkBucketContent(t, tab, []*enode.Node{n1}) // Add an updated version with changed IP. // The update will be accepted because it is inbound. n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000) - tab.addInboundNode(wrapNode(n1v2)) + tab.addInboundNode(n1v2) checkBucketContent(t, tab, []*enode.Node{n1v2}) } @@ -366,13 +366,13 @@ func TestTable_addFoundNodeV4UpdateReject(t *testing.T) { // Add a v4 node. key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3") n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000) - tab.addFoundNode(wrapNode(n1)) + tab.addFoundNode(n1, false) checkBucketContent(t, tab, []*enode.Node{n1}) // Add an updated version with changed IP. // The update won't be accepted because it isn't inbound. n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000) - tab.addFoundNode(wrapNode(n1v2)) + tab.addFoundNode(n1v2, false) checkBucketContent(t, tab, []*enode.Node{n1}) } @@ -413,8 +413,8 @@ func TestTable_revalidateSyncRecord(t *testing.T) { var r enr.Record r.Set(enr.IP(net.IP{127, 0, 0, 1})) id := enode.ID{1} - n1 := wrapNode(enode.SignNull(&r, id)) - tab.addFoundNode(n1) + n1 := enode.SignNull(&r, id) + tab.addFoundNode(n1, false) // Update the node record. r.Set(enr.WithEntry("foo", "bar")) @@ -437,7 +437,7 @@ func TestNodesPush(t *testing.T) { n1 := nodeAtDistance(target, 255, intIP(1)) n2 := nodeAtDistance(target, 254, intIP(2)) n3 := nodeAtDistance(target, 253, intIP(3)) - perm := [][]*node{ + perm := [][]*enode.Node{ {n3, n2, n1}, {n3, n1, n2}, {n2, n3, n1}, @@ -452,7 +452,7 @@ func TestNodesPush(t *testing.T) { for _, n := range nodes { list.push(n, 3) } - if !slicesEqual(list.entries, perm[0], nodeIDEqual) { + if !slices.EqualFunc(list.entries, perm[0], nodeIDEqual) { t.Fatal("not equal") } } @@ -463,28 +463,16 @@ func TestNodesPush(t *testing.T) { for _, n := range nodes { list.push(n, 2) } - if !slicesEqual(list.entries, perm[0][:2], nodeIDEqual) { + if !slices.EqualFunc(list.entries, perm[0][:2], nodeIDEqual) { t.Fatal("not equal") } } } -func nodeIDEqual(n1, n2 *node) bool { +func nodeIDEqual[N nodeType](n1, n2 N) bool { return n1.ID() == n2.ID() } -func slicesEqual[T any](s1, s2 []T, check func(e1, e2 T) bool) bool { - if len(s1) != len(s2) { - return false - } - for i := range s1 { - if !check(s1[i], s2[i]) { - return false - } - } - return true -} - // gen wraps quick.Value so it's easier to use. // it generates a random value of the given value's type. func gen(typ interface{}, rand *rand.Rand) interface{} { diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 59045bf2a84d..997ac3779994 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -56,18 +56,18 @@ func newInactiveTestTable(t transport, cfg Config) (*Table, *enode.DB) { } // nodeAtDistance creates a node for which enode.LogDist(base, n.id) == ld. -func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node { +func nodeAtDistance(base enode.ID, ld int, ip net.IP) *enode.Node { var r enr.Record r.Set(enr.IP(ip)) r.Set(enr.UDP(30303)) - return wrapNode(enode.SignNull(&r, idAtDistance(base, ld))) + return enode.SignNull(&r, idAtDistance(base, ld)) } // nodesAtDistance creates n nodes for which enode.LogDist(base, node.ID()) == ld. func nodesAtDistance(base enode.ID, ld int, n int) []*enode.Node { results := make([]*enode.Node, n) for i := range results { - results[i] = unwrapNode(nodeAtDistance(base, ld, intIP(i))) + results[i] = nodeAtDistance(base, ld, intIP(i)) } return results } @@ -105,12 +105,12 @@ func intIP(i int) net.IP { } // fillBucket inserts nodes into the given bucket until it is full. -func fillBucket(tab *Table, id enode.ID) (last *node) { +func fillBucket(tab *Table, id enode.ID) (last *tableNode) { ld := enode.LogDist(tab.self().ID(), id) b := tab.bucket(id) for len(b.entries) < bucketSize { node := nodeAtDistance(tab.self().ID(), ld, intIP(ld)) - if !tab.addFoundNode(node) { + if !tab.addFoundNode(node, false) { panic("node not added") } } @@ -119,13 +119,9 @@ func fillBucket(tab *Table, id enode.ID) (last *node) { // fillTable adds nodes the table to the end of their corresponding bucket // if the bucket is not full. The caller must not hold tab.mutex. -func fillTable(tab *Table, nodes []*node, setLive bool) { +func fillTable(tab *Table, nodes []*enode.Node, setLive bool) { for _, n := range nodes { - if setLive { - n.livenessChecks = 1 - n.isValidatedLive = true - } - tab.addFoundNode(n) + tab.addFoundNode(n, setLive) } } @@ -219,7 +215,7 @@ func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) { return t.records[n.ID()], nil } -func hasDuplicates(slice []*node) bool { +func hasDuplicates(slice []*enode.Node) bool { seen := make(map[enode.ID]bool, len(slice)) for i, e := range slice { if e == nil { @@ -261,14 +257,14 @@ func nodeEqual(n1 *enode.Node, n2 *enode.Node) bool { return n1.ID() == n2.ID() && n1.IP().Equal(n2.IP()) } -func sortByID(nodes []*enode.Node) { - slices.SortFunc(nodes, func(a, b *enode.Node) int { +func sortByID[N nodeType](nodes []N) { + slices.SortFunc(nodes, func(a, b N) int { return bytes.Compare(a.ID().Bytes(), b.ID().Bytes()) }) } -func sortedByDistanceTo(distbase enode.ID, slice []*node) bool { - return slices.IsSortedFunc(slice, func(a, b *node) int { +func sortedByDistanceTo(distbase enode.ID, slice []*enode.Node) bool { + return slices.IsSortedFunc(slice, func(a, b *enode.Node) int { return enode.DistCmp(distbase, a.ID(), b.ID()) }) } @@ -304,7 +300,7 @@ type nodeEventRecorder struct { } type recordedNodeEvent struct { - node *node + node *tableNode added bool } @@ -314,7 +310,7 @@ func newNodeEventRecorder(buffer int) *nodeEventRecorder { } } -func (set *nodeEventRecorder) nodeAdded(b *bucket, n *node) { +func (set *nodeEventRecorder) nodeAdded(b *bucket, n *tableNode) { select { case set.evc <- recordedNodeEvent{n, true}: default: @@ -322,7 +318,7 @@ func (set *nodeEventRecorder) nodeAdded(b *bucket, n *node) { } } -func (set *nodeEventRecorder) nodeRemoved(b *bucket, n *node) { +func (set *nodeEventRecorder) nodeRemoved(b *bucket, n *tableNode) { select { case set.evc <- recordedNodeEvent{n, false}: default: diff --git a/p2p/discover/v4_lookup_test.go b/p2p/discover/v4_lookup_test.go index 5682f262be76..bc9475a8b369 100644 --- a/p2p/discover/v4_lookup_test.go +++ b/p2p/discover/v4_lookup_test.go @@ -19,7 +19,7 @@ package discover import ( "crypto/ecdsa" "fmt" - "net" + "net/netip" "slices" "testing" @@ -40,7 +40,7 @@ func TestUDPv4_Lookup(t *testing.T) { } // Seed table with initial node. - fillTable(test.table, []*node{wrapNode(lookupTestnet.node(256, 0))}, true) + fillTable(test.table, []*enode.Node{lookupTestnet.node(256, 0)}, true) // Start the lookup. resultC := make(chan []*enode.Node, 1) @@ -70,9 +70,9 @@ func TestUDPv4_LookupIterator(t *testing.T) { defer test.close() // Seed table with initial nodes. - bootnodes := make([]*node, len(lookupTestnet.dists[256])) + bootnodes := make([]*enode.Node, len(lookupTestnet.dists[256])) for i := range lookupTestnet.dists[256] { - bootnodes[i] = wrapNode(lookupTestnet.node(256, i)) + bootnodes[i] = lookupTestnet.node(256, i) } fillTable(test.table, bootnodes, true) go serveTestnet(test, lookupTestnet) @@ -105,9 +105,9 @@ func TestUDPv4_LookupIteratorClose(t *testing.T) { defer test.close() // Seed table with initial nodes. - bootnodes := make([]*node, len(lookupTestnet.dists[256])) + bootnodes := make([]*enode.Node, len(lookupTestnet.dists[256])) for i := range lookupTestnet.dists[256] { - bootnodes[i] = wrapNode(lookupTestnet.node(256, i)) + bootnodes[i] = lookupTestnet.node(256, i) } fillTable(test.table, bootnodes, true) go serveTestnet(test, lookupTestnet) @@ -136,7 +136,7 @@ func TestUDPv4_LookupIteratorClose(t *testing.T) { func serveTestnet(test *udpTest, testnet *preminedTestnet) { for done := false; !done; { - done = test.waitPacketOut(func(p v4wire.Packet, to *net.UDPAddr, hash []byte) { + done = test.waitPacketOut(func(p v4wire.Packet, to netip.AddrPort, hash []byte) { n, key := testnet.nodeByAddr(to) switch p.(type) { case *v4wire.Ping: @@ -158,10 +158,10 @@ func checkLookupResults(t *testing.T, tn *preminedTestnet, results []*enode.Node for _, e := range results { t.Logf(" ld=%d, %x", enode.LogDist(tn.target.id(), e.ID()), e.ID().Bytes()) } - if hasDuplicates(wrapNodes(results)) { + if hasDuplicates(results) { t.Errorf("result set contains duplicate entries") } - if !sortedByDistanceTo(tn.target.id(), wrapNodes(results)) { + if !sortedByDistanceTo(tn.target.id(), results) { t.Errorf("result set not sorted by distance to target") } wantNodes := tn.closest(len(results)) @@ -264,9 +264,10 @@ func (tn *preminedTestnet) node(dist, index int) *enode.Node { return n } -func (tn *preminedTestnet) nodeByAddr(addr *net.UDPAddr) (*enode.Node, *ecdsa.PrivateKey) { - dist := int(addr.IP[1])<<8 + int(addr.IP[2]) - index := int(addr.IP[3]) +func (tn *preminedTestnet) nodeByAddr(addr netip.AddrPort) (*enode.Node, *ecdsa.PrivateKey) { + ip := addr.Addr().As4() + dist := int(ip[1])<<8 + int(ip[2]) + index := int(ip[3]) key := tn.dists[dist][index] return tn.node(dist, index), key } @@ -274,7 +275,7 @@ func (tn *preminedTestnet) nodeByAddr(addr *net.UDPAddr) (*enode.Node, *ecdsa.Pr func (tn *preminedTestnet) nodesAtDistance(dist int) []v4wire.Node { result := make([]v4wire.Node, len(tn.dists[dist])) for i := range result { - result[i] = nodeToRPC(wrapNode(tn.node(dist, i))) + result[i] = nodeToRPC(tn.node(dist, i)) } return result } diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index be6058ec5000..3880ca34a708 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -26,6 +26,7 @@ import ( "fmt" "io" "net" + "net/netip" "sync" "time" @@ -45,6 +46,7 @@ var ( errClockWarp = errors.New("reply deadline too far in the future") errClosed = errors.New("socket closed") errLowPort = errors.New("low port") + errNoUDPEndpoint = errors.New("node has no UDP endpoint") ) const ( @@ -93,7 +95,7 @@ type UDPv4 struct { type replyMatcher struct { // these fields must match in the reply. from enode.ID - ip net.IP + ip netip.Addr ptype byte // time when the request must complete @@ -119,7 +121,7 @@ type replyMatchFunc func(v4wire.Packet) (matched bool, requestDone bool) // reply is a reply packet from a certain node. type reply struct { from enode.ID - ip net.IP + ip netip.Addr data v4wire.Packet // loop indicates whether there was // a matching request by sending on this channel. @@ -201,9 +203,12 @@ func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { } func (t *UDPv4) ourEndpoint() v4wire.Endpoint { - n := t.Self() - a := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} - return v4wire.NewEndpoint(a, uint16(n.TCP())) + node := t.Self() + addr, ok := node.UDPEndpoint() + if !ok { + return v4wire.Endpoint{} + } + return v4wire.NewEndpoint(addr, uint16(node.TCP())) } // Ping sends a ping message to the given node. @@ -214,7 +219,11 @@ func (t *UDPv4) Ping(n *enode.Node) error { // 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) + addr, ok := n.UDPEndpoint() + if !ok { + return 0, errNoUDPEndpoint + } + rm := t.sendPing(n.ID(), addr, nil) if err = <-rm.errc; err == nil { seq = rm.reply.(*v4wire.Pong).ENRSeq } @@ -223,7 +232,7 @@ func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { // sendPing sends a ping message to the given node and invokes the callback // when the reply arrives. -func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *replyMatcher { +func (t *UDPv4) sendPing(toid enode.ID, toaddr netip.AddrPort, callback func()) *replyMatcher { req := t.makePing(toaddr) packet, hash, err := v4wire.Encode(t.priv, req) if err != nil { @@ -233,7 +242,7 @@ func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *r } // Add a matcher for the reply to the pending reply queue. Pongs are matched if they // reference the ping we're about to send. - rm := t.pending(toid, toaddr.IP, v4wire.PongPacket, func(p v4wire.Packet) (matched bool, requestDone bool) { + rm := t.pending(toid, toaddr.Addr(), v4wire.PongPacket, func(p v4wire.Packet) (matched bool, requestDone bool) { matched = bytes.Equal(p.(*v4wire.Pong).ReplyTok, hash) if matched && callback != nil { callback() @@ -241,12 +250,13 @@ func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *r return matched, matched }) // Send the packet. - t.localNode.UDPContact(toaddr) + toUDPAddr := &net.UDPAddr{IP: toaddr.Addr().AsSlice()} + t.localNode.UDPContact(toUDPAddr) t.write(toaddr, toid, req.Name(), packet) return rm } -func (t *UDPv4) makePing(toaddr *net.UDPAddr) *v4wire.Ping { +func (t *UDPv4) makePing(toaddr netip.AddrPort) *v4wire.Ping { return &v4wire.Ping{ Version: 4, From: t.ourEndpoint(), @@ -290,35 +300,39 @@ func (t *UDPv4) newRandomLookup(ctx context.Context) *lookup { func (t *UDPv4) newLookup(ctx context.Context, targetKey encPubkey) *lookup { target := enode.ID(crypto.Keccak256Hash(targetKey[:])) ekey := v4wire.Pubkey(targetKey) - it := newLookup(ctx, t.tab, target, func(n *node) ([]*node, error) { - return t.findnode(n.ID(), n.addr(), ekey) + it := newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) { + addr, ok := n.UDPEndpoint() + if !ok { + return nil, errNoUDPEndpoint + } + return t.findnode(n.ID(), addr, ekey) }) return it } // findnode sends a findnode request to the given node and waits until // the node has sent up to k neighbors. -func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubkey) ([]*node, error) { - t.ensureBond(toid, toaddr) +func (t *UDPv4) findnode(toid enode.ID, toAddrPort netip.AddrPort, target v4wire.Pubkey) ([]*enode.Node, error) { + t.ensureBond(toid, toAddrPort) // Add a matcher for 'neighbours' replies to the pending reply queue. The matcher is // active until enough nodes have been received. - nodes := make([]*node, 0, bucketSize) + nodes := make([]*enode.Node, 0, bucketSize) nreceived := 0 - rm := t.pending(toid, toaddr.IP, v4wire.NeighborsPacket, func(r v4wire.Packet) (matched bool, requestDone bool) { + rm := t.pending(toid, toAddrPort.Addr(), v4wire.NeighborsPacket, func(r v4wire.Packet) (matched bool, requestDone bool) { reply := r.(*v4wire.Neighbors) for _, rn := range reply.Nodes { nreceived++ - n, err := t.nodeFromRPC(toaddr, rn) + n, err := t.nodeFromRPC(toAddrPort, rn) if err != nil { - t.log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err) + t.log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toAddrPort, "err", err) continue } nodes = append(nodes, n) } return true, nreceived >= bucketSize }) - t.send(toaddr, toid, &v4wire.Findnode{ + t.send(toAddrPort, toid, &v4wire.Findnode{ Target: target, Expiration: uint64(time.Now().Add(expiration).Unix()), }) @@ -336,7 +350,7 @@ func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubke // 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()} + addr, _ := n.UDPEndpoint() t.ensureBond(n.ID(), addr) req := &v4wire.ENRRequest{ @@ -349,7 +363,7 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { // Add a matcher for the reply to the pending reply queue. Responses are matched if // they reference the request we're about to send. - rm := t.pending(n.ID(), addr.IP, v4wire.ENRResponsePacket, func(r v4wire.Packet) (matched bool, requestDone bool) { + rm := t.pending(n.ID(), addr.Addr(), v4wire.ENRResponsePacket, func(r v4wire.Packet) (matched bool, requestDone bool) { matched = bytes.Equal(r.(*v4wire.ENRResponse).ReplyTok, hash) return matched, matched }) @@ -369,7 +383,7 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { if respN.Seq() < n.Seq() { return n, nil // response record is older } - if err := netutil.CheckRelayIP(addr.IP, respN.IP()); err != nil { + if err := netutil.CheckRelayIP(addr.Addr().AsSlice(), respN.IP()); err != nil { return nil, fmt.Errorf("invalid IP in response record: %v", err) } return respN, nil @@ -381,7 +395,7 @@ func (t *UDPv4) TableBuckets() [][]BucketNode { // pending adds a reply matcher to the pending reply queue. // see the documentation of type replyMatcher for a detailed explanation. -func (t *UDPv4) pending(id enode.ID, ip net.IP, ptype byte, callback replyMatchFunc) *replyMatcher { +func (t *UDPv4) pending(id enode.ID, ip netip.Addr, ptype byte, callback replyMatchFunc) *replyMatcher { ch := make(chan error, 1) p := &replyMatcher{from: id, ip: ip, ptype: ptype, callback: callback, errc: ch} select { @@ -395,7 +409,7 @@ func (t *UDPv4) pending(id enode.ID, ip net.IP, ptype byte, callback replyMatchF // handleReply dispatches a reply packet, invoking reply matchers. It returns // whether any matcher considered the packet acceptable. -func (t *UDPv4) handleReply(from enode.ID, fromIP net.IP, req v4wire.Packet) bool { +func (t *UDPv4) handleReply(from enode.ID, fromIP netip.Addr, req v4wire.Packet) bool { matched := make(chan bool, 1) select { case t.gotreply <- reply{from, fromIP, req, matched}: @@ -461,7 +475,7 @@ func (t *UDPv4) loop() { var matched bool // whether any replyMatcher considered the reply acceptable. for el := plist.Front(); el != nil; el = el.Next() { p := el.Value.(*replyMatcher) - if p.from == r.from && p.ptype == r.data.Kind() && p.ip.Equal(r.ip) { + if p.from == r.from && p.ptype == r.data.Kind() && p.ip == r.ip { ok, requestDone := p.callback(r.data) matched = matched || ok p.reply = r.data @@ -500,7 +514,7 @@ func (t *UDPv4) loop() { } } -func (t *UDPv4) send(toaddr *net.UDPAddr, toid enode.ID, req v4wire.Packet) ([]byte, error) { +func (t *UDPv4) send(toaddr netip.AddrPort, toid enode.ID, req v4wire.Packet) ([]byte, error) { packet, hash, err := v4wire.Encode(t.priv, req) if err != nil { return hash, err @@ -508,8 +522,8 @@ func (t *UDPv4) send(toaddr *net.UDPAddr, toid enode.ID, req v4wire.Packet) ([]b return hash, t.write(toaddr, toid, req.Name(), packet) } -func (t *UDPv4) write(toaddr *net.UDPAddr, toid enode.ID, what string, packet []byte) error { - _, err := t.conn.WriteToUDP(packet, toaddr) +func (t *UDPv4) write(toaddr netip.AddrPort, toid enode.ID, what string, packet []byte) error { + _, err := t.conn.WriteToUDPAddrPort(packet, toaddr) t.log.Trace(">> "+what, "id", toid, "addr", toaddr, "err", err) return err } @@ -523,7 +537,7 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { buf := make([]byte, maxPacketSize) for { - nbytes, from, err := t.conn.ReadFromUDP(buf) + nbytes, from, err := t.conn.ReadFromUDPAddrPort(buf) if netutil.IsTemporaryError(err) { // Ignore temporary read errors. t.log.Debug("Temporary UDP read error", "err", err) @@ -544,7 +558,7 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { } } -func (t *UDPv4) handlePacket(from *net.UDPAddr, buf []byte) error { +func (t *UDPv4) handlePacket(from netip.AddrPort, buf []byte) error { rawpacket, fromKey, hash, err := v4wire.Decode(buf) if err != nil { t.log.Debug("Bad discv4 packet", "addr", from, "err", err) @@ -563,15 +577,16 @@ func (t *UDPv4) handlePacket(from *net.UDPAddr, buf []byte) error { } // checkBond checks if the given node has a recent enough endpoint proof. -func (t *UDPv4) checkBond(id enode.ID, ip net.IP) bool { - return time.Since(t.db.LastPongReceived(id, ip)) < bondExpiration +func (t *UDPv4) checkBond(id enode.ID, ip netip.AddrPort) bool { + return time.Since(t.db.LastPongReceived(id, ip.Addr().AsSlice())) < bondExpiration } // ensureBond solicits a ping from a node if we haven't seen a ping from it for a while. // This ensures there is a valid endpoint proof on the remote end. -func (t *UDPv4) ensureBond(toid enode.ID, toaddr *net.UDPAddr) { - tooOld := time.Since(t.db.LastPingReceived(toid, toaddr.IP)) > bondExpiration - if tooOld || t.db.FindFails(toid, toaddr.IP) > maxFindnodeFailures { +func (t *UDPv4) ensureBond(toid enode.ID, toaddr netip.AddrPort) { + ip := toaddr.Addr().AsSlice() + tooOld := time.Since(t.db.LastPingReceived(toid, ip)) > bondExpiration + if tooOld || t.db.FindFails(toid, ip) > maxFindnodeFailures { rm := t.sendPing(toid, toaddr, nil) <-rm.errc // Wait for them to ping back and process our pong. @@ -579,11 +594,11 @@ func (t *UDPv4) ensureBond(toid enode.ID, toaddr *net.UDPAddr) { } } -func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*node, error) { +func (t *UDPv4) nodeFromRPC(sender netip.AddrPort, rn v4wire.Node) (*enode.Node, error) { if rn.UDP <= 1024 { return nil, errLowPort } - if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil { + if err := netutil.CheckRelayIP(sender.Addr().AsSlice(), rn.IP); err != nil { return nil, err } if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) { @@ -593,12 +608,12 @@ func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*node, error) if err != nil { return nil, err } - n := wrapNode(enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP))) + n := enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP)) err = n.ValidateComplete() return n, err } -func nodeToRPC(n *node) v4wire.Node { +func nodeToRPC(n *enode.Node) v4wire.Node { var key ecdsa.PublicKey var ekey v4wire.Pubkey if err := n.Load((*enode.Secp256k1)(&key)); err == nil { @@ -637,14 +652,14 @@ type packetHandlerV4 struct { senderKey *ecdsa.PublicKey // used for ping // preverify checks whether the packet is valid and should be handled at all. - preverify func(p *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error + preverify func(p *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error // handle handles the packet. - handle func(req *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) + handle func(req *packetHandlerV4, from netip.AddrPort, fromID enode.ID, mac []byte) } // PING/v4 -func (t *UDPv4) verifyPing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyPing(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.Ping) if v4wire.Expired(req.Expiration) { @@ -658,7 +673,7 @@ func (t *UDPv4) verifyPing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I return nil } -func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { +func (t *UDPv4) handlePing(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, mac []byte) { req := h.Packet.(*v4wire.Ping) // Reply. @@ -670,8 +685,9 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I }) // Ping back if our last pong on file is too far in the past. - n := wrapNode(enode.NewV4(h.senderKey, from.IP, int(req.From.TCP), from.Port)) - if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration { + fromIP := from.Addr().AsSlice() + n := enode.NewV4(h.senderKey, fromIP, int(req.From.TCP), int(from.Port())) + if time.Since(t.db.LastPongReceived(n.ID(), fromIP)) > bondExpiration { t.sendPing(fromID, from, func() { t.tab.addInboundNode(n) }) @@ -680,35 +696,40 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I } // Update node database and endpoint predictor. - t.db.UpdateLastPingReceived(n.ID(), from.IP, time.Now()) - t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) + t.db.UpdateLastPingReceived(n.ID(), fromIP, time.Now()) + fromUDPAddr := &net.UDPAddr{IP: fromIP, Port: int(from.Port())} + toUDPAddr := &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)} + t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) } // PONG/v4 -func (t *UDPv4) verifyPong(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyPong(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.Pong) if v4wire.Expired(req.Expiration) { return errExpired } - if !t.handleReply(fromID, from.IP, req) { + if !t.handleReply(fromID, from.Addr(), req) { return errUnsolicitedReply } - t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) - t.db.UpdateLastPongReceived(fromID, from.IP, time.Now()) + fromIP := from.Addr().AsSlice() + fromUDPAddr := &net.UDPAddr{IP: fromIP, Port: int(from.Port())} + toUDPAddr := &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)} + t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) + t.db.UpdateLastPongReceived(fromID, fromIP, time.Now()) return nil } // FINDNODE/v4 -func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.Findnode) if v4wire.Expired(req.Expiration) { return errExpired } - if !t.checkBond(fromID, from.IP) { + if !t.checkBond(fromID, from) { // No endpoint proof pong exists, we don't process the packet. This prevents an // attack vector where the discovery protocol could be used to amplify traffic in a // DDOS attack. A malicious actor would send a findnode request with the IP address @@ -720,7 +741,7 @@ func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno return nil } -func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { +func (t *UDPv4) handleFindnode(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, mac []byte) { req := h.Packet.(*v4wire.Findnode) // Determine closest nodes. @@ -732,7 +753,8 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno p := v4wire.Neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} var sent bool for _, n := range closest { - if netutil.CheckRelayIP(from.IP, n.IP()) == nil { + fromIP := from.Addr().AsSlice() + if netutil.CheckRelayIP(fromIP, n.IP()) == nil { p.Nodes = append(p.Nodes, nodeToRPC(n)) } if len(p.Nodes) == v4wire.MaxNeighbors { @@ -748,13 +770,13 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno // NEIGHBORS/v4 -func (t *UDPv4) verifyNeighbors(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyNeighbors(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.Neighbors) if v4wire.Expired(req.Expiration) { return errExpired } - if !t.handleReply(fromID, from.IP, h.Packet) { + if !t.handleReply(fromID, from.Addr(), h.Packet) { return errUnsolicitedReply } return nil @@ -762,19 +784,19 @@ func (t *UDPv4) verifyNeighbors(h *packetHandlerV4, from *net.UDPAddr, fromID en // ENRREQUEST/v4 -func (t *UDPv4) verifyENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyENRRequest(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.ENRRequest) if v4wire.Expired(req.Expiration) { return errExpired } - if !t.checkBond(fromID, from.IP) { + if !t.checkBond(fromID, from) { return errUnknownNode } return nil } -func (t *UDPv4) handleENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { +func (t *UDPv4) handleENRRequest(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, mac []byte) { t.send(from, fromID, &v4wire.ENRResponse{ ReplyTok: mac, Record: *t.localNode.Node().Record(), @@ -783,8 +805,8 @@ func (t *UDPv4) handleENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID e // ENRRESPONSE/v4 -func (t *UDPv4) verifyENRResponse(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { - if !t.handleReply(fromID, from.IP, h.Packet) { +func (t *UDPv4) verifyENRResponse(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { + if !t.handleReply(fromID, from.Addr(), h.Packet) { return errUnsolicitedReply } return nil diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 9c454d98e3e0..28a6fb867596 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -26,6 +26,7 @@ import ( "io" "math/rand" "net" + "net/netip" "reflect" "sync" "testing" @@ -55,7 +56,7 @@ type udpTest struct { udp *UDPv4 sent [][]byte localkey, remotekey *ecdsa.PrivateKey - remoteaddr *net.UDPAddr + remoteaddr netip.AddrPort } func newUDPTest(t *testing.T) *udpTest { @@ -64,7 +65,7 @@ func newUDPTest(t *testing.T) *udpTest { pipe: newpipe(), localkey: newkey(), remotekey: newkey(), - remoteaddr: &net.UDPAddr{IP: net.IP{10, 0, 1, 99}, Port: 30303}, + remoteaddr: netip.MustParseAddrPort("10.0.1.99:30303"), } test.db, _ = enode.OpenDB("") @@ -92,7 +93,7 @@ func (test *udpTest) packetIn(wantError error, data v4wire.Packet) { } // handles a packet as if it had been sent to the transport by the key/endpoint. -func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr *net.UDPAddr, data v4wire.Packet) { +func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr netip.AddrPort, data v4wire.Packet) { test.t.Helper() enc, _, err := v4wire.Encode(key, data) @@ -106,7 +107,7 @@ func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr * } // waits for a packet to be sent by the transport. -// validate should have type func(X, *net.UDPAddr, []byte), where X is a packet type. +// validate should have type func(X, netip.AddrPort, []byte), where X is a packet type. func (test *udpTest) waitPacketOut(validate interface{}) (closed bool) { test.t.Helper() @@ -128,7 +129,7 @@ func (test *udpTest) waitPacketOut(validate interface{}) (closed bool) { test.t.Errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype) return false } - fn.Call([]reflect.Value{reflect.ValueOf(p), reflect.ValueOf(&dgram.to), reflect.ValueOf(hash)}) + fn.Call([]reflect.Value{reflect.ValueOf(p), reflect.ValueOf(dgram.to), reflect.ValueOf(hash)}) return false } @@ -236,7 +237,7 @@ func TestUDPv4_findnodeTimeout(t *testing.T) { test := newUDPTest(t) defer test.close() - toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222} + toaddr := netip.AddrPortFrom(netip.MustParseAddr("1.2.3.4"), 2222) toid := enode.ID{1, 2, 3, 4} target := v4wire.Pubkey{4, 5, 6, 7} result, err := test.udp.findnode(toid, toaddr, target) @@ -261,26 +262,25 @@ func TestUDPv4_findnode(t *testing.T) { for i := 0; i < numCandidates; i++ { key := newkey() ip := net.IP{10, 13, 0, byte(i)} - n := wrapNode(enode.NewV4(&key.PublicKey, ip, 0, 2000)) + n := enode.NewV4(&key.PublicKey, ip, 0, 2000) // Ensure half of table content isn't verified live yet. if i > numCandidates/2 { - n.isValidatedLive = true live[n.ID()] = true } + test.table.addFoundNode(n, live[n.ID()]) nodes.push(n, numCandidates) } - fillTable(test.table, nodes.entries, false) // ensure there's a bond with the test node, // findnode won't be accepted otherwise. remoteID := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID() - test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.IP, time.Now()) + test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.Addr().AsSlice(), time.Now()) // check that closest neighbors are returned. expected := test.table.findnodeByID(testTarget.ID(), bucketSize, true) test.packetIn(nil, &v4wire.Findnode{Target: testTarget, Expiration: futureExp}) - waitNeighbors := func(want []*node) { - test.waitPacketOut(func(p *v4wire.Neighbors, to *net.UDPAddr, hash []byte) { + waitNeighbors := func(want []*enode.Node) { + test.waitPacketOut(func(p *v4wire.Neighbors, to netip.AddrPort, hash []byte) { if len(p.Nodes) != len(want) { t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), len(want)) return @@ -309,10 +309,10 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { defer test.close() rid := enode.PubkeyToIDV4(&test.remotekey.PublicKey) - test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.IP, time.Now()) + test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.Addr().AsSlice(), time.Now()) // queue a pending findnode request - resultc, errc := make(chan []*node, 1), make(chan error, 1) + resultc, errc := make(chan []*enode.Node, 1), make(chan error, 1) go func() { rid := encodePubkey(&test.remotekey.PublicKey).id() ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget) @@ -325,18 +325,18 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { // wait for the findnode to be sent. // after it is sent, the transport is waiting for a reply - test.waitPacketOut(func(p *v4wire.Findnode, to *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.Findnode, to netip.AddrPort, hash []byte) { if p.Target != testTarget { t.Errorf("wrong target: got %v, want %v", p.Target, testTarget) } }) // send the reply as two packets. - list := []*node{ - 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")), + list := []*enode.Node{ + enode.MustParse("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304"), + enode.MustParse("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303"), + enode.MustParse("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17"), + enode.MustParse("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303"), } rpclist := make([]v4wire.Node, len(list)) for i := range list { @@ -368,8 +368,8 @@ func TestUDPv4_pingMatch(t *testing.T) { crand.Read(randToken) test.packetIn(nil, &v4wire.Ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) - test.waitPacketOut(func(*v4wire.Pong, *net.UDPAddr, []byte) {}) - test.waitPacketOut(func(*v4wire.Ping, *net.UDPAddr, []byte) {}) + test.waitPacketOut(func(*v4wire.Pong, netip.AddrPort, []byte) {}) + test.waitPacketOut(func(*v4wire.Ping, netip.AddrPort, []byte) {}) test.packetIn(errUnsolicitedReply, &v4wire.Pong{ReplyTok: randToken, To: testLocalAnnounced, Expiration: futureExp}) } @@ -379,10 +379,10 @@ func TestUDPv4_pingMatchIP(t *testing.T) { defer test.close() test.packetIn(nil, &v4wire.Ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) - test.waitPacketOut(func(*v4wire.Pong, *net.UDPAddr, []byte) {}) + test.waitPacketOut(func(*v4wire.Pong, netip.AddrPort, []byte) {}) - test.waitPacketOut(func(p *v4wire.Ping, to *net.UDPAddr, hash []byte) { - wrongAddr := &net.UDPAddr{IP: net.IP{33, 44, 1, 2}, Port: 30000} + test.waitPacketOut(func(p *v4wire.Ping, to netip.AddrPort, hash []byte) { + wrongAddr := netip.MustParseAddrPort("33.44.1.2:30000") test.packetInFrom(errUnsolicitedReply, test.remotekey, wrongAddr, &v4wire.Pong{ ReplyTok: hash, To: testLocalAnnounced, @@ -393,41 +393,36 @@ func TestUDPv4_pingMatchIP(t *testing.T) { func TestUDPv4_successfulPing(t *testing.T) { test := newUDPTest(t) - added := make(chan *node, 1) - test.table.nodeAddedHook = func(b *bucket, n *node) { added <- n } + added := make(chan *tableNode, 1) + test.table.nodeAddedHook = func(b *bucket, n *tableNode) { added <- n } defer test.close() // The remote side sends a ping packet to initiate the exchange. go test.packetIn(nil, &v4wire.Ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) // The ping is replied to. - test.waitPacketOut(func(p *v4wire.Pong, to *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.Pong, to netip.AddrPort, hash []byte) { pinghash := test.sent[0][:32] if !bytes.Equal(p.ReplyTok, pinghash) { t.Errorf("got pong.ReplyTok %x, want %x", p.ReplyTok, pinghash) } - wantTo := v4wire.Endpoint{ - // The mirrored UDP address is the UDP packet sender - IP: test.remoteaddr.IP, UDP: uint16(test.remoteaddr.Port), - // The mirrored TCP port is the one from the ping packet - TCP: testRemote.TCP, - } + // The mirrored UDP address is the UDP packet sender. + // The mirrored TCP port is the one from the ping packet. + wantTo := v4wire.NewEndpoint(test.remoteaddr, testRemote.TCP) if !reflect.DeepEqual(p.To, wantTo) { t.Errorf("got pong.To %v, want %v", p.To, wantTo) } }) // Remote is unknown, the table pings back. - test.waitPacketOut(func(p *v4wire.Ping, to *net.UDPAddr, hash []byte) { - if !reflect.DeepEqual(p.From, test.udp.ourEndpoint()) { + test.waitPacketOut(func(p *v4wire.Ping, to netip.AddrPort, hash []byte) { + wantFrom := test.udp.ourEndpoint() + wantFrom.IP = net.IP{} + if !reflect.DeepEqual(p.From, wantFrom) { t.Errorf("got ping.From %#v, want %#v", p.From, test.udp.ourEndpoint()) } - wantTo := v4wire.Endpoint{ - // The mirrored UDP address is the UDP packet sender. - IP: test.remoteaddr.IP, - UDP: uint16(test.remoteaddr.Port), - TCP: 0, - } + // The mirrored UDP address is the UDP packet sender. + wantTo := v4wire.NewEndpoint(test.remoteaddr, 0) if !reflect.DeepEqual(p.To, wantTo) { t.Errorf("got ping.To %v, want %v", p.To, wantTo) } @@ -442,11 +437,11 @@ func TestUDPv4_successfulPing(t *testing.T) { if n.ID() != rid { t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid) } - if !n.IP().Equal(test.remoteaddr.IP) { - t.Errorf("node has wrong IP: got %v, want: %v", n.IP(), test.remoteaddr.IP) + if !n.IP().Equal(test.remoteaddr.Addr().AsSlice()) { + t.Errorf("node has wrong IP: got %v, want: %v", n.IP(), test.remoteaddr.Addr()) } - if n.UDP() != test.remoteaddr.Port { - t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP(), test.remoteaddr.Port) + if n.UDP() != int(test.remoteaddr.Port()) { + t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP(), test.remoteaddr.Port()) } if n.TCP() != int(testRemote.TCP) { t.Errorf("node has wrong TCP port: got %v, want: %v", n.TCP(), testRemote.TCP) @@ -469,12 +464,12 @@ func TestUDPv4_EIP868(t *testing.T) { // Perform endpoint proof and check for sequence number in packet tail. test.packetIn(nil, &v4wire.Ping{Expiration: futureExp}) - test.waitPacketOut(func(p *v4wire.Pong, addr *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.Pong, addr netip.AddrPort, hash []byte) { if p.ENRSeq != wantNode.Seq() { t.Errorf("wrong sequence number in pong: %d, want %d", p.ENRSeq, wantNode.Seq()) } }) - test.waitPacketOut(func(p *v4wire.Ping, addr *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.Ping, addr netip.AddrPort, hash []byte) { if p.ENRSeq != wantNode.Seq() { t.Errorf("wrong sequence number in ping: %d, want %d", p.ENRSeq, wantNode.Seq()) } @@ -483,7 +478,7 @@ func TestUDPv4_EIP868(t *testing.T) { // Request should work now. test.packetIn(nil, &v4wire.ENRRequest{Expiration: futureExp}) - test.waitPacketOut(func(p *v4wire.ENRResponse, addr *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.ENRResponse, addr netip.AddrPort, hash []byte) { n, err := enode.New(enode.ValidSchemes, &p.Record) if err != nil { t.Fatalf("invalid record: %v", err) @@ -584,7 +579,7 @@ type dgramPipe struct { } type dgram struct { - to net.UDPAddr + to netip.AddrPort data []byte } @@ -597,8 +592,8 @@ func newpipe() *dgramPipe { } } -// WriteToUDP queues a datagram. -func (c *dgramPipe) WriteToUDP(b []byte, to *net.UDPAddr) (n int, err error) { +// WriteToUDPAddrPort queues a datagram. +func (c *dgramPipe) WriteToUDPAddrPort(b []byte, to netip.AddrPort) (n int, err error) { msg := make([]byte, len(b)) copy(msg, b) c.mu.Lock() @@ -606,15 +601,15 @@ func (c *dgramPipe) WriteToUDP(b []byte, to *net.UDPAddr) (n int, err error) { if c.closed { return 0, errors.New("closed") } - c.queue = append(c.queue, dgram{*to, b}) + c.queue = append(c.queue, dgram{to, b}) c.cond.Signal() return len(b), nil } -// ReadFromUDP just hangs until the pipe is closed. -func (c *dgramPipe) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) { +// ReadFromUDPAddrPort just hangs until the pipe is closed. +func (c *dgramPipe) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) { <-c.closing - return 0, nil, io.EOF + return 0, netip.AddrPort{}, io.EOF } func (c *dgramPipe) Close() error { diff --git a/p2p/discover/v4wire/v4wire.go b/p2p/discover/v4wire/v4wire.go index 9c59359fb2c2..958cca324d64 100644 --- a/p2p/discover/v4wire/v4wire.go +++ b/p2p/discover/v4wire/v4wire.go @@ -25,6 +25,7 @@ import ( "fmt" "math/big" "net" + "net/netip" "time" "github.com/ethereum/go-ethereum/common/math" @@ -150,14 +151,15 @@ type Endpoint struct { } // NewEndpoint creates an endpoint. -func NewEndpoint(addr *net.UDPAddr, tcpPort uint16) Endpoint { - ip := net.IP{} - if ip4 := addr.IP.To4(); ip4 != nil { - ip = ip4 - } else if ip6 := addr.IP.To16(); ip6 != nil { - ip = ip6 +func NewEndpoint(addr netip.AddrPort, tcpPort uint16) Endpoint { + var ip net.IP + if addr.Addr().Is4() || addr.Addr().Is4In6() { + ip4 := addr.Addr().As4() + ip = ip4[:] + } else { + ip = addr.Addr().AsSlice() } - return Endpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} + return Endpoint{IP: ip, UDP: addr.Port(), TCP: tcpPort} } type Packet interface { diff --git a/p2p/discover/v5_talk.go b/p2p/discover/v5_talk.go index c1f67879402c..2246b47141c0 100644 --- a/p2p/discover/v5_talk.go +++ b/p2p/discover/v5_talk.go @@ -18,6 +18,7 @@ package discover import ( "net" + "net/netip" "sync" "time" @@ -70,7 +71,7 @@ func (t *talkSystem) register(protocol string, handler TalkRequestHandler) { } // handleRequest handles a talk request. -func (t *talkSystem) handleRequest(id enode.ID, addr *net.UDPAddr, req *v5wire.TalkRequest) { +func (t *talkSystem) handleRequest(id enode.ID, addr netip.AddrPort, req *v5wire.TalkRequest) { t.mutex.Lock() handler, ok := t.handlers[req.Protocol] t.mutex.Unlock() @@ -88,7 +89,8 @@ func (t *talkSystem) handleRequest(id enode.ID, addr *net.UDPAddr, req *v5wire.T case <-t.slots: go func() { defer func() { t.slots <- struct{}{} }() - respMessage := handler(id, addr, req.Message) + udpAddr := &net.UDPAddr{IP: addr.Addr().AsSlice(), Port: int(addr.Port())} + respMessage := handler(id, udpAddr, req.Message) resp := &v5wire.TalkResponse{ReqID: req.ReqID, Message: respMessage} t.transport.sendFromAnotherThread(id, addr, resp) }() diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 8cdc9dfbce3d..9ba54b3d400a 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -25,6 +25,7 @@ import ( "fmt" "io" "net" + "net/netip" "slices" "sync" "time" @@ -101,14 +102,14 @@ type UDPv5 struct { type sendRequest struct { destID enode.ID - destAddr *net.UDPAddr + destAddr netip.AddrPort msg v5wire.Packet } // callV5 represents a remote procedure call against another node. type callV5 struct { id enode.ID - addr *net.UDPAddr + addr netip.AddrPort node *enode.Node // This is required to perform handshakes. packet v5wire.Packet @@ -233,7 +234,7 @@ func (t *UDPv5) AllNodes() []*enode.Node { for _, b := range &t.tab.buckets { for _, n := range b.entries { - nodes = append(nodes, unwrapNode(n)) + nodes = append(nodes, n.Node) } } return nodes @@ -266,7 +267,7 @@ func (t *UDPv5) TalkRequest(n *enode.Node, protocol string, request []byte) ([]b } // TalkRequestToID sends a talk request to a node and waits for a response. -func (t *UDPv5) TalkRequestToID(id enode.ID, addr *net.UDPAddr, protocol string, request []byte) ([]byte, error) { +func (t *UDPv5) TalkRequestToID(id enode.ID, addr netip.AddrPort, protocol string, request []byte) ([]byte, error) { req := &v5wire.TalkRequest{Protocol: protocol, Message: request} resp := t.callToID(id, addr, v5wire.TalkResponseMsg, req) defer t.callDone(resp) @@ -314,26 +315,26 @@ func (t *UDPv5) newRandomLookup(ctx context.Context) *lookup { } func (t *UDPv5) newLookup(ctx context.Context, target enode.ID) *lookup { - return newLookup(ctx, t.tab, target, func(n *node) ([]*node, error) { + return newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) { return t.lookupWorker(n, target) }) } // lookupWorker performs FINDNODE calls against a single node during lookup. -func (t *UDPv5) lookupWorker(destNode *node, target enode.ID) ([]*node, error) { +func (t *UDPv5) lookupWorker(destNode *enode.Node, target enode.ID) ([]*enode.Node, error) { var ( dists = lookupDistances(target, destNode.ID()) nodes = nodesByDistance{target: target} err error ) var r []*enode.Node - r, err = t.findnode(unwrapNode(destNode), dists) + r, err = t.findnode(destNode, dists) if errors.Is(err, errClosed) { return nil, err } for _, n := range r { if n.ID() != t.Self().ID() { - nodes.push(wrapNode(n), findnodeResultLimit) + nodes.push(n, findnodeResultLimit) } } return nodes.entries, err @@ -427,7 +428,7 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s if err != nil { return nil, err } - if err := netutil.CheckRelayIP(c.addr.IP, node.IP()); err != nil { + if err := netutil.CheckRelayIP(c.addr.Addr().AsSlice(), node.IP()); err != nil { return nil, err } if t.netrestrict != nil && !t.netrestrict.Contains(node.IP()) { @@ -452,14 +453,14 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s // callToNode sends the given call and sets up a handler for response packets (of message // type responseType). Responses are dispatched to the call's response channel. func (t *UDPv5) callToNode(n *enode.Node, responseType byte, req v5wire.Packet) *callV5 { - addr := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} + addr, _ := n.UDPEndpoint() c := &callV5{id: n.ID(), addr: addr, node: n} t.initCall(c, responseType, req) return c } // callToID is like callToNode, but for cases where the node record is not available. -func (t *UDPv5) callToID(id enode.ID, addr *net.UDPAddr, responseType byte, req v5wire.Packet) *callV5 { +func (t *UDPv5) callToID(id enode.ID, addr netip.AddrPort, responseType byte, req v5wire.Packet) *callV5 { c := &callV5{id: id, addr: addr} t.initCall(c, responseType, req) return c @@ -619,12 +620,12 @@ func (t *UDPv5) sendCall(c *callV5) { // sendResponse sends a response packet to the given node. // This doesn't trigger a handshake even if no keys are available. -func (t *UDPv5) sendResponse(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet) error { +func (t *UDPv5) sendResponse(toID enode.ID, toAddr netip.AddrPort, packet v5wire.Packet) error { _, err := t.send(toID, toAddr, packet, nil) return err } -func (t *UDPv5) sendFromAnotherThread(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet) { +func (t *UDPv5) sendFromAnotherThread(toID enode.ID, toAddr netip.AddrPort, packet v5wire.Packet) { select { case t.sendCh <- sendRequest{toID, toAddr, packet}: case <-t.closeCtx.Done(): @@ -632,7 +633,7 @@ func (t *UDPv5) sendFromAnotherThread(toID enode.ID, toAddr *net.UDPAddr, packet } // send sends a packet to the given node. -func (t *UDPv5) send(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet, c *v5wire.Whoareyou) (v5wire.Nonce, error) { +func (t *UDPv5) send(toID enode.ID, toAddr netip.AddrPort, packet v5wire.Packet, c *v5wire.Whoareyou) (v5wire.Nonce, error) { addr := toAddr.String() t.logcontext = append(t.logcontext[:0], "id", toID, "addr", addr) t.logcontext = packet.AppendLogInfo(t.logcontext) @@ -644,7 +645,7 @@ func (t *UDPv5) send(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet, c return nonce, err } - _, err = t.conn.WriteToUDP(enc, toAddr) + _, err = t.conn.WriteToUDPAddrPort(enc, toAddr) t.log.Trace(">> "+packet.Name(), t.logcontext...) return nonce, err } @@ -655,7 +656,7 @@ func (t *UDPv5) readLoop() { buf := make([]byte, maxPacketSize) for range t.readNextCh { - nbytes, from, err := t.conn.ReadFromUDP(buf) + nbytes, from, err := t.conn.ReadFromUDPAddrPort(buf) if netutil.IsTemporaryError(err) { // Ignore temporary read errors. t.log.Debug("Temporary UDP read error", "err", err) @@ -672,7 +673,7 @@ func (t *UDPv5) readLoop() { } // dispatchReadPacket sends a packet into the dispatch loop. -func (t *UDPv5) dispatchReadPacket(from *net.UDPAddr, content []byte) bool { +func (t *UDPv5) dispatchReadPacket(from netip.AddrPort, content []byte) bool { select { case t.packetInCh <- ReadPacket{content, from}: return true @@ -682,7 +683,7 @@ func (t *UDPv5) dispatchReadPacket(from *net.UDPAddr, content []byte) bool { } // handlePacket decodes and processes an incoming packet from the network. -func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { +func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr netip.AddrPort) error { addr := fromAddr.String() fromID, fromNode, packet, err := t.codec.Decode(rawpacket, addr) if err != nil { @@ -699,7 +700,7 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { } if fromNode != nil { // Handshake succeeded, add to table. - t.tab.addInboundNode(wrapNode(fromNode)) + t.tab.addInboundNode(fromNode) } if packet.Kind() != v5wire.WhoareyouPacket { // WHOAREYOU logged separately to report errors. @@ -712,13 +713,13 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { } // handleCallResponse dispatches a response packet to the call waiting for it. -func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr *net.UDPAddr, p v5wire.Packet) bool { +func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr netip.AddrPort, p v5wire.Packet) bool { ac := t.activeCallByNode[fromID] if ac == nil || !bytes.Equal(p.RequestID(), ac.reqid) { t.log.Debug(fmt.Sprintf("Unsolicited/late %s response", p.Name()), "id", fromID, "addr", fromAddr) return false } - if !fromAddr.IP.Equal(ac.addr.IP) || fromAddr.Port != ac.addr.Port { + if fromAddr != ac.addr { t.log.Debug(fmt.Sprintf("%s from wrong endpoint", p.Name()), "id", fromID, "addr", fromAddr) return false } @@ -743,7 +744,7 @@ func (t *UDPv5) getNode(id enode.ID) *enode.Node { } // handle processes incoming packets according to their message type. -func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) { +func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr netip.AddrPort) { switch p := p.(type) { case *v5wire.Unknown: t.handleUnknown(p, fromID, fromAddr) @@ -753,7 +754,9 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) t.handlePing(p, fromID, fromAddr) case *v5wire.Pong: if t.handleCallResponse(fromID, fromAddr, p) { - t.localNode.UDPEndpointStatement(fromAddr, &net.UDPAddr{IP: p.ToIP, Port: int(p.ToPort)}) + fromUDPAddr := &net.UDPAddr{IP: fromAddr.Addr().AsSlice(), Port: int(fromAddr.Port())} + toUDPAddr := &net.UDPAddr{IP: p.ToIP, Port: int(p.ToPort)} + t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) } case *v5wire.Findnode: t.handleFindnode(p, fromID, fromAddr) @@ -767,7 +770,7 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) } // handleUnknown initiates a handshake by responding with WHOAREYOU. -func (t *UDPv5) handleUnknown(p *v5wire.Unknown, fromID enode.ID, fromAddr *net.UDPAddr) { +func (t *UDPv5) handleUnknown(p *v5wire.Unknown, fromID enode.ID, fromAddr netip.AddrPort) { challenge := &v5wire.Whoareyou{Nonce: p.Nonce} crand.Read(challenge.IDNonce[:]) if n := t.getNode(fromID); n != nil { @@ -783,7 +786,7 @@ var ( ) // handleWhoareyou resends the active call as a handshake packet. -func (t *UDPv5) handleWhoareyou(p *v5wire.Whoareyou, fromID enode.ID, fromAddr *net.UDPAddr) { +func (t *UDPv5) handleWhoareyou(p *v5wire.Whoareyou, fromID enode.ID, fromAddr netip.AddrPort) { c, err := t.matchWithCall(fromID, p.Nonce) if err != nil { t.log.Debug("Invalid "+p.Name(), "addr", fromAddr, "err", err) @@ -817,32 +820,35 @@ func (t *UDPv5) matchWithCall(fromID enode.ID, nonce v5wire.Nonce) (*callV5, err } // handlePing sends a PONG response. -func (t *UDPv5) handlePing(p *v5wire.Ping, fromID enode.ID, fromAddr *net.UDPAddr) { - remoteIP := fromAddr.IP - // Handle IPv4 mapped IPv6 addresses in the - // event the local node is binded to an - // ipv6 interface. - if remoteIP.To4() != nil { - remoteIP = remoteIP.To4() +func (t *UDPv5) handlePing(p *v5wire.Ping, fromID enode.ID, fromAddr netip.AddrPort) { + var remoteIP net.IP + // Handle IPv4 mapped IPv6 addresses in the event the local node is binded + // to an ipv6 interface. + if fromAddr.Addr().Is4() || fromAddr.Addr().Is4In6() { + ip4 := fromAddr.Addr().As4() + remoteIP = ip4[:] + } else { + remoteIP = fromAddr.Addr().AsSlice() } t.sendResponse(fromID, fromAddr, &v5wire.Pong{ ReqID: p.ReqID, ToIP: remoteIP, - ToPort: uint16(fromAddr.Port), + ToPort: fromAddr.Port(), ENRSeq: t.localNode.Node().Seq(), }) } // handleFindnode returns nodes to the requester. -func (t *UDPv5) handleFindnode(p *v5wire.Findnode, fromID enode.ID, fromAddr *net.UDPAddr) { - nodes := t.collectTableNodes(fromAddr.IP, p.Distances, findnodeResultLimit) +func (t *UDPv5) handleFindnode(p *v5wire.Findnode, fromID enode.ID, fromAddr netip.AddrPort) { + nodes := t.collectTableNodes(fromAddr.Addr(), p.Distances, findnodeResultLimit) for _, resp := range packNodes(p.ReqID, nodes) { t.sendResponse(fromID, fromAddr, resp) } } // collectTableNodes creates a FINDNODE result set for the given distances. -func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*enode.Node { +func (t *UDPv5) collectTableNodes(rip netip.Addr, distances []uint, limit int) []*enode.Node { + ripSlice := rip.AsSlice() var bn []*enode.Node var nodes []*enode.Node var processed = make(map[uint]struct{}) @@ -857,7 +863,7 @@ func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*en for _, n := range t.tab.appendLiveNodes(dist, bn[:0]) { // Apply some pre-checks to avoid sending invalid nodes. // Note liveness is checked by appendLiveNodes. - if netutil.CheckRelayIP(rip, n.IP()) != nil { + if netutil.CheckRelayIP(ripSlice, n.IP()) != nil { continue } nodes = append(nodes, n) diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 0015f7cc7062..1f8e972200ae 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -23,6 +23,7 @@ import ( "fmt" "math/rand" "net" + "net/netip" "reflect" "slices" "testing" @@ -103,7 +104,7 @@ func TestUDPv5_pingHandling(t *testing.T) { defer test.close() test.packetIn(&v5wire.Ping{ReqID: []byte("foo")}) - test.waitPacketOut(func(p *v5wire.Pong, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Pong, addr netip.AddrPort, _ v5wire.Nonce) { if !bytes.Equal(p.ReqID, []byte("foo")) { t.Error("wrong request ID in response:", p.ReqID) } @@ -135,16 +136,16 @@ func TestUDPv5_unknownPacket(t *testing.T) { // Unknown packet from unknown node. test.packetIn(&v5wire.Unknown{Nonce: nonce}) - test.waitPacketOut(func(p *v5wire.Whoareyou, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { check(p, 0) }) // Make node known. n := test.getNode(test.remotekey, test.remoteaddr).Node() - test.table.addFoundNode(wrapNode(n)) + test.table.addFoundNode(n, false) test.packetIn(&v5wire.Unknown{Nonce: nonce}) - test.waitPacketOut(func(p *v5wire.Whoareyou, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { check(p, n.Seq()) }) } @@ -159,9 +160,9 @@ func TestUDPv5_findnodeHandling(t *testing.T) { nodes253 := nodesAtDistance(test.table.self().ID(), 253, 16) nodes249 := nodesAtDistance(test.table.self().ID(), 249, 4) nodes248 := nodesAtDistance(test.table.self().ID(), 248, 10) - fillTable(test.table, wrapNodes(nodes253), true) - fillTable(test.table, wrapNodes(nodes249), true) - fillTable(test.table, wrapNodes(nodes248), true) + fillTable(test.table, nodes253, true) + fillTable(test.table, nodes249, true) + fillTable(test.table, nodes248, true) // Requesting with distance zero should return the node's own record. test.packetIn(&v5wire.Findnode{ReqID: []byte{0}, Distances: []uint{0}}) @@ -199,7 +200,7 @@ func (test *udpV5Test) expectNodes(wantReqID []byte, wantTotal uint8, wantNodes } for { - test.waitPacketOut(func(p *v5wire.Nodes, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Nodes, addr netip.AddrPort, _ v5wire.Nonce) { if !bytes.Equal(p.ReqID, wantReqID) { test.t.Fatalf("wrong request ID %v in response, want %v", p.ReqID, wantReqID) } @@ -238,7 +239,7 @@ func TestUDPv5_pingCall(t *testing.T) { _, err := test.udp.ping(remote) done <- err }() - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) {}) + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) {}) if err := <-done; err != errTimeout { t.Fatalf("want errTimeout, got %q", err) } @@ -248,7 +249,7 @@ func TestUDPv5_pingCall(t *testing.T) { _, err := test.udp.ping(remote) done <- err }() - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) { test.packetInFrom(test.remotekey, test.remoteaddr, &v5wire.Pong{ReqID: p.ReqID}) }) if err := <-done; err != nil { @@ -260,8 +261,8 @@ func TestUDPv5_pingCall(t *testing.T) { _, err := test.udp.ping(remote) done <- err }() - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) { - wrongAddr := &net.UDPAddr{IP: net.IP{33, 44, 55, 22}, Port: 10101} + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) { + wrongAddr := netip.MustParseAddrPort("33.44.55.22:10101") test.packetInFrom(test.remotekey, wrongAddr, &v5wire.Pong{ReqID: p.ReqID}) }) if err := <-done; err != errTimeout { @@ -291,7 +292,7 @@ func TestUDPv5_findnodeCall(t *testing.T) { }() // Serve the responses: - test.waitPacketOut(func(p *v5wire.Findnode, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Findnode, addr netip.AddrPort, _ v5wire.Nonce) { if !reflect.DeepEqual(p.Distances, distances) { t.Fatalf("wrong distances in request: %v", p.Distances) } @@ -337,15 +338,15 @@ func TestUDPv5_callResend(t *testing.T) { }() // Ping answered by WHOAREYOU. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, nonce v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, nonce v5wire.Nonce) { test.packetIn(&v5wire.Whoareyou{Nonce: nonce}) }) // Ping should be re-sent. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) { test.packetIn(&v5wire.Pong{ReqID: p.ReqID}) }) // Answer the other ping. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) { test.packetIn(&v5wire.Pong{ReqID: p.ReqID}) }) if err := <-done; err != nil { @@ -370,11 +371,11 @@ func TestUDPv5_multipleHandshakeRounds(t *testing.T) { }() // Ping answered by WHOAREYOU. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, nonce v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, nonce v5wire.Nonce) { test.packetIn(&v5wire.Whoareyou{Nonce: nonce}) }) // Ping answered by WHOAREYOU again. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, nonce v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, nonce v5wire.Nonce) { test.packetIn(&v5wire.Whoareyou{Nonce: nonce}) }) if err := <-done; err != errTimeout { @@ -401,7 +402,7 @@ func TestUDPv5_callTimeoutReset(t *testing.T) { }() // Serve two responses, slowly. - test.waitPacketOut(func(p *v5wire.Findnode, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Findnode, addr netip.AddrPort, _ v5wire.Nonce) { time.Sleep(respTimeout - 50*time.Millisecond) test.packetIn(&v5wire.Nodes{ ReqID: p.ReqID, @@ -439,7 +440,7 @@ func TestUDPv5_talkHandling(t *testing.T) { Protocol: "test", Message: []byte("test request"), }) - test.waitPacketOut(func(p *v5wire.TalkResponse, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.TalkResponse, addr netip.AddrPort, _ v5wire.Nonce) { if !bytes.Equal(p.ReqID, []byte("foo")) { t.Error("wrong request ID in response:", p.ReqID) } @@ -458,7 +459,7 @@ func TestUDPv5_talkHandling(t *testing.T) { Protocol: "wrong", Message: []byte("test request"), }) - test.waitPacketOut(func(p *v5wire.TalkResponse, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.TalkResponse, addr netip.AddrPort, _ v5wire.Nonce) { if !bytes.Equal(p.ReqID, []byte("2")) { t.Error("wrong request ID in response:", p.ReqID) } @@ -485,7 +486,7 @@ func TestUDPv5_talkRequest(t *testing.T) { _, err := test.udp.TalkRequest(remote, "test", []byte("test request")) done <- err }() - test.waitPacketOut(func(p *v5wire.TalkRequest, addr *net.UDPAddr, _ v5wire.Nonce) {}) + test.waitPacketOut(func(p *v5wire.TalkRequest, addr netip.AddrPort, _ v5wire.Nonce) {}) if err := <-done; err != errTimeout { t.Fatalf("want errTimeout, got %q", err) } @@ -495,7 +496,7 @@ func TestUDPv5_talkRequest(t *testing.T) { _, err := test.udp.TalkRequest(remote, "test", []byte("test request")) done <- err }() - test.waitPacketOut(func(p *v5wire.TalkRequest, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.TalkRequest, addr netip.AddrPort, _ v5wire.Nonce) { if p.Protocol != "test" { t.Errorf("wrong protocol ID in talk request: %q", p.Protocol) } @@ -516,7 +517,7 @@ func TestUDPv5_talkRequest(t *testing.T) { _, err := test.udp.TalkRequestToID(remote.ID(), test.remoteaddr, "test", []byte("test request 2")) done <- err }() - test.waitPacketOut(func(p *v5wire.TalkRequest, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.TalkRequest, addr netip.AddrPort, _ v5wire.Nonce) { if p.Protocol != "test" { t.Errorf("wrong protocol ID in talk request: %q", p.Protocol) } @@ -583,13 +584,14 @@ func TestUDPv5_lookup(t *testing.T) { for d, nn := range lookupTestnet.dists { for i, key := range nn { n := lookupTestnet.node(d, i) - test.getNode(key, &net.UDPAddr{IP: n.IP(), Port: n.UDP()}) + addr, _ := n.UDPEndpoint() + test.getNode(key, addr) } } // Seed table with initial node. initialNode := lookupTestnet.node(256, 0) - fillTable(test.table, []*node{wrapNode(initialNode)}, true) + fillTable(test.table, []*enode.Node{initialNode}, true) // Start the lookup. resultC := make(chan []*enode.Node, 1) @@ -601,7 +603,7 @@ func TestUDPv5_lookup(t *testing.T) { // Answer lookup packets. asked := make(map[enode.ID]bool) for done := false; !done; { - done = test.waitPacketOut(func(p v5wire.Packet, to *net.UDPAddr, _ v5wire.Nonce) { + done = test.waitPacketOut(func(p v5wire.Packet, to netip.AddrPort, _ v5wire.Nonce) { recipient, key := lookupTestnet.nodeByAddr(to) switch p := p.(type) { case *v5wire.Ping: @@ -652,11 +654,8 @@ func TestUDPv5_PingWithIPV4MappedAddress(t *testing.T) { test := newUDPV5Test(t) defer test.close() - rawIP := net.IPv4(0xFF, 0x12, 0x33, 0xE5) - test.remoteaddr = &net.UDPAddr{ - IP: rawIP.To16(), - Port: 0, - } + rawIP := netip.AddrFrom4([4]byte{0xFF, 0x12, 0x33, 0xE5}) + test.remoteaddr = netip.AddrPortFrom(netip.AddrFrom16(rawIP.As16()), 0) remote := test.getNode(test.remotekey, test.remoteaddr).Node() done := make(chan struct{}, 1) @@ -665,14 +664,14 @@ func TestUDPv5_PingWithIPV4MappedAddress(t *testing.T) { test.udp.handlePing(&v5wire.Ping{ENRSeq: 1}, remote.ID(), test.remoteaddr) done <- struct{}{} }() - test.waitPacketOut(func(p *v5wire.Pong, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Pong, addr netip.AddrPort, _ v5wire.Nonce) { if len(p.ToIP) == net.IPv6len { t.Error("Received untruncated ip address") } if len(p.ToIP) != net.IPv4len { t.Errorf("Received ip address with incorrect length: %d", len(p.ToIP)) } - if !p.ToIP.Equal(rawIP) { + if !p.ToIP.Equal(rawIP.AsSlice()) { t.Errorf("Received incorrect ip address: wanted %s but received %s", rawIP.String(), p.ToIP.String()) } }) @@ -688,9 +687,9 @@ type udpV5Test struct { db *enode.DB udp *UDPv5 localkey, remotekey *ecdsa.PrivateKey - remoteaddr *net.UDPAddr + remoteaddr netip.AddrPort nodesByID map[enode.ID]*enode.LocalNode - nodesByIP map[string]*enode.LocalNode + nodesByIP map[netip.Addr]*enode.LocalNode } // testCodec is the packet encoding used by protocol tests. This codec does not perform encryption. @@ -750,9 +749,9 @@ func newUDPV5Test(t *testing.T) *udpV5Test { pipe: newpipe(), localkey: newkey(), remotekey: newkey(), - remoteaddr: &net.UDPAddr{IP: net.IP{10, 0, 1, 99}, Port: 30303}, + remoteaddr: netip.MustParseAddrPort("10.0.1.99:30303"), nodesByID: make(map[enode.ID]*enode.LocalNode), - nodesByIP: make(map[string]*enode.LocalNode), + nodesByIP: make(map[netip.Addr]*enode.LocalNode), } test.db, _ = enode.OpenDB("") ln := enode.NewLocalNode(test.db, test.localkey) @@ -777,8 +776,8 @@ func (test *udpV5Test) packetIn(packet v5wire.Packet) { test.packetInFrom(test.remotekey, test.remoteaddr, packet) } -// handles a packet as if it had been sent to the transport by the key/endpoint. -func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr *net.UDPAddr, packet v5wire.Packet) { +// packetInFrom handles a packet as if it had been sent to the transport by the key/endpoint. +func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr netip.AddrPort, packet v5wire.Packet) { test.t.Helper() ln := test.getNode(key, addr) @@ -793,22 +792,22 @@ func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr *net.UDPAddr, pa } // getNode ensures the test knows about a node at the given endpoint. -func (test *udpV5Test) getNode(key *ecdsa.PrivateKey, addr *net.UDPAddr) *enode.LocalNode { +func (test *udpV5Test) getNode(key *ecdsa.PrivateKey, addr netip.AddrPort) *enode.LocalNode { id := encodePubkey(&key.PublicKey).id() ln := test.nodesByID[id] if ln == nil { db, _ := enode.OpenDB("") ln = enode.NewLocalNode(db, key) - ln.SetStaticIP(addr.IP) - ln.Set(enr.UDP(addr.Port)) + ln.SetStaticIP(addr.Addr().AsSlice()) + ln.Set(enr.UDP(addr.Port())) test.nodesByID[id] = ln } - test.nodesByIP[string(addr.IP)] = ln + test.nodesByIP[addr.Addr()] = ln return ln } // waitPacketOut waits for the next output packet and handles it using the given 'validate' -// function. The function must be of type func (X, *net.UDPAddr, v5wire.Nonce) where X is +// function. The function must be of type func (X, netip.AddrPort, v5wire.Nonce) where X is // assignable to packetV5. func (test *udpV5Test) waitPacketOut(validate interface{}) (closed bool) { test.t.Helper() @@ -824,7 +823,7 @@ func (test *udpV5Test) waitPacketOut(validate interface{}) (closed bool) { test.t.Fatalf("timed out waiting for %v", exptype) return false } - ln := test.nodesByIP[string(dgram.to.IP)] + ln := test.nodesByIP[dgram.to.Addr()] if ln == nil { test.t.Fatalf("attempt to send to non-existing node %v", &dgram.to) return false @@ -839,7 +838,7 @@ func (test *udpV5Test) waitPacketOut(validate interface{}) (closed bool) { test.t.Errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype) return false } - fn.Call([]reflect.Value{reflect.ValueOf(p), reflect.ValueOf(&dgram.to), reflect.ValueOf(frame.AuthTag)}) + fn.Call([]reflect.Value{reflect.ValueOf(p), reflect.ValueOf(dgram.to), reflect.ValueOf(frame.AuthTag)}) return false } diff --git a/p2p/server.go b/p2p/server.go index a3c53b07813a..13eebed3f4f1 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "net" + "net/netip" "slices" "sync" "sync/atomic" @@ -435,11 +436,11 @@ type sharedUDPConn struct { unhandled chan discover.ReadPacket } -// ReadFromUDP implements discover.UDPConn -func (s *sharedUDPConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) { +// ReadFromUDPAddrPort implements discover.UDPConn +func (s *sharedUDPConn) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) { packet, ok := <-s.unhandled if !ok { - return 0, nil, errors.New("connection was closed") + return 0, netip.AddrPort{}, errors.New("connection was closed") } l := len(packet.Data) if l > len(b) { From 3fef53447f39878e5ebca1938db90e79a363f535 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 29 May 2024 15:31:27 +0200 Subject: [PATCH 312/571] build: upgrade to golangci-lint v1.59.0 (#29875) --- .golangci.yml | 6 +++-- build/checksums.txt | 59 +++++++++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 0343c4b4ebf2..46844d1e90b9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,8 +6,6 @@ run: # default is true. Enables skipping of directories: # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ skip-dirs-use-default: true - skip-files: - - core/genesis_alloc.go linters: disable-all: true @@ -26,6 +24,8 @@ linters: - exportloopref - whitespace + ### linters we tried and will not be using: + ### # - structcheck # lots of false positives # - errcheck #lot of false positives # - contextcheck @@ -40,6 +40,8 @@ linters-settings: simplify: true issues: + exclude-files: + - core/genesis_alloc.go exclude-rules: - path: crypto/bn256/cloudflare/optate.go linters: diff --git a/build/checksums.txt b/build/checksums.txt index da2988452a58..94cac9738c1e 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -48,36 +48,37 @@ cab2af6951a6e2115824263f6df13ff069c47270f5788714fa1d776f7f60cb39 go1.22.3.windo 40b37f4b068fc759f3a0dd61176a0f7570a4ba48bed8561c31d3967a3583981a go1.22.3.windows-arm.zip 59b76ee22b9b1c3afbf7f50e3cb4edb954d6c0d25e5e029ab5483a6804d61e71 go1.22.3.windows-arm64.zip -# version:golangci 1.55.2 +# version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ -# https://github.com/golangci/golangci-lint/releases/download/v1.55.2/ -632e96e6d5294fbbe7b2c410a49c8fa01c60712a0af85a567de85bcc1623ea21 golangci-lint-1.55.2-darwin-amd64.tar.gz -234463f059249f82045824afdcdd5db5682d0593052f58f6a3039a0a1c3899f6 golangci-lint-1.55.2-darwin-arm64.tar.gz -2bdd105e2d4e003a9058c33a22bb191a1e0f30fa0790acca0d8fbffac1d6247c golangci-lint-1.55.2-freebsd-386.tar.gz -e75056e8b082386676ce23eba455cf893931a792c0d87e1e3743c0aec33c7fb5 golangci-lint-1.55.2-freebsd-amd64.tar.gz -5789b933facaf6136bd23f1d50add67b79bbcf8dfdfc9069a37f729395940a66 golangci-lint-1.55.2-freebsd-armv6.tar.gz -7f21ab1008d05f32c954f99470fc86a83a059e530fe2add1d0b7d8ed4d8992a7 golangci-lint-1.55.2-freebsd-armv7.tar.gz -33ab06139b9219a28251f10821da94423db30285cc2af97494cbb2a281927de9 golangci-lint-1.55.2-illumos-amd64.tar.gz -57ce6f8ce3ad6ee45d7cc3d9a047545a851c2547637834a3fcb086c7b40b1e6b golangci-lint-1.55.2-linux-386.tar.gz -ca21c961a33be3bc15e4292dc40c98c8dcc5463a7b6768a3afc123761630c09c golangci-lint-1.55.2-linux-amd64.tar.gz -8eb0cee9b1dbf0eaa49871798c7f8a5b35f2960c52d776a5f31eb7d886b92746 golangci-lint-1.55.2-linux-arm64.tar.gz -3195f3e0f37d353fd5bd415cabcd4e263f5c29d3d0ffb176c26ff3d2c75eb3bb golangci-lint-1.55.2-linux-armv6.tar.gz -c823ee36eb1a719e171de1f2f5ca3068033dce8d9817232fd10ed71fd6650406 golangci-lint-1.55.2-linux-armv7.tar.gz -758a5d2a356dc494bd13ed4c0d4bf5a54a4dc91267ea5ecdd87b86c7ca0624e7 golangci-lint-1.55.2-linux-loong64.tar.gz -2c7b9abdce7cae802a67d583cd7c6dca520bff6d0e17c8535a918e2f2b437aa0 golangci-lint-1.55.2-linux-mips64.tar.gz -024e0a15b85352cc27271285526e16a4ab66d3e67afbbe446c9808c06cb8dbed golangci-lint-1.55.2-linux-mips64le.tar.gz -6b00f89ba5506c1de1efdd9fa17c54093013a294fefd8b9b31534db626a672ee golangci-lint-1.55.2-linux-ppc64le.tar.gz -0faa0d047d9bf7b703ed3ea65b6117043c93504f9ca1de25ae929d3901c73d4a golangci-lint-1.55.2-linux-riscv64.tar.gz -30dec9b22e7d5bb4e9d5ccea96da20f71cd7db3c8cf30b8ddc7cb9174c4d742a golangci-lint-1.55.2-linux-s390x.tar.gz -5a0ede48f79ad707902fdb29be8cd2abd8302dc122b65ebae3fdfc86751c7698 golangci-lint-1.55.2-netbsd-386.tar.gz -95af20a2e617126dd5b08122ece7819101070e1582a961067ce8c41172f901ad golangci-lint-1.55.2-netbsd-amd64.tar.gz -94fb7dacb7527847cc95d7120904e19a2a0a81a0d50d61766c9e0251da72ab9d golangci-lint-1.55.2-netbsd-armv6.tar.gz -ca906bce5fee9619400e4a321c56476fe4a4efb6ac4fc989d340eb5563348873 golangci-lint-1.55.2-netbsd-armv7.tar.gz -45b442f69fc8915c4500201c0247b7f3f69544dbc9165403a61f9095f2c57355 golangci-lint-1.55.2-windows-386.zip -f57d434d231d43417dfa631587522f8c1991220b43c8ffadb9c7bd279508bf81 golangci-lint-1.55.2-windows-amd64.zip -fd7dc8f4c6829ee6fafb252a4d81d2155cd35da7833665cbb25d53ce7cecd990 golangci-lint-1.55.2-windows-arm64.zip -1892c3c24f9e7ef44b02f6750c703864b6dc350129f3ec39510300007b2376f1 golangci-lint-1.55.2-windows-armv6.zip -a5e68ae73d38748b5269fad36ac7575e3c162a5dc63ef58abdea03cc5da4522a golangci-lint-1.55.2-windows-armv7.zip +# https://github.com/golangci/golangci-lint/releases/download/v1.59.0/ +418acf7e255ddc0783e97129c9b03d9311b77826a5311d425a01c708a86417e7 golangci-lint-1.59.0-darwin-amd64.tar.gz +5f6a1d95a6dd69f6e328eb56dd311a38e04cfab79a1305fbf4957f4e203f47b6 golangci-lint-1.59.0-darwin-arm64.tar.gz +8899bf589185d49f747f3e5db9f0bde8a47245a100c64a3dd4d65e8e92cfc4f2 golangci-lint-1.59.0-freebsd-386.tar.gz +658212f138d9df2ac89427e22115af34bf387c0871d70f2a25101718946a014f golangci-lint-1.59.0-freebsd-amd64.tar.gz +4c6395ea40f314d3b6fa17d8997baab93464d5d1deeaab513155e625473bd03a golangci-lint-1.59.0-freebsd-armv6.tar.gz +ff37da4fbaacdb6bbae70fdbdbb1ba932a859956f788c82822fa06bef5b7c6b3 golangci-lint-1.59.0-freebsd-armv7.tar.gz +439739469ed2bda182b1ec276d40c40e02f195537f78e3672996741ad223d6b6 golangci-lint-1.59.0-illumos-amd64.tar.gz +940801d46790e40d0a097d8fee34e2606f0ef148cd039654029b0b8750a15ed6 golangci-lint-1.59.0-linux-386.tar.gz +3b14a439f33c4fff83dbe0349950d984042b9a1feb6c62f82787b598fc3ab5f4 golangci-lint-1.59.0-linux-amd64.tar.gz +c57e6c0b0fa03089a2611dceddd5bc5d206716cccdff8b149da8baac598719a1 golangci-lint-1.59.0-linux-arm64.tar.gz +93149e2d3b25ac754df9a23172403d8aa6d021a7e0d9c090a12f51897f68c9a0 golangci-lint-1.59.0-linux-armv6.tar.gz +d10ac38239d9efee3ee87b55c96cdf3fa09e1a525babe3ffdaaf65ccc48cf3dc golangci-lint-1.59.0-linux-armv7.tar.gz +047338114b4f0d5f08f0fb9a397b03cc171916ed0960be7dfb355c2320cd5e9c golangci-lint-1.59.0-linux-loong64.tar.gz +5632df0f7f8fc03a80a266130faef0b5902d280cf60621f1b2bdc1aef6d97ee9 golangci-lint-1.59.0-linux-mips64.tar.gz +71dd638c82fa4439171e7126d2c7a32b5d103bfdef282cea40c83632cb3d1f4b golangci-lint-1.59.0-linux-mips64le.tar.gz +6cf9ea0d34e91669948483f9ae7f07da319a879344373a1981099fbd890cde00 golangci-lint-1.59.0-linux-ppc64le.tar.gz +af0205fa6fbab197cee613c359947711231739095d21b5c837086233b36ad971 golangci-lint-1.59.0-linux-riscv64.tar.gz +a9d2fb93f3c688ebccef94f5dc96c0b07c4d20bf6556cddebd8442159b0c80f6 golangci-lint-1.59.0-linux-s390x.tar.gz +68ab4c57a847b8ace9679887f2f8b2b6760e57ee29dcde8c3f40dd8bb2654fa2 golangci-lint-1.59.0-netbsd-386.tar.gz +d277b8b435c19406d00de4d509eadf5a024a5782878332e9a1b7c02bb76e87a7 golangci-lint-1.59.0-netbsd-amd64.tar.gz +83211656be8dcfa1545af4f92894409f412d1f37566798cb9460a526593ad62c golangci-lint-1.59.0-netbsd-arm64.tar.gz +6c6866d28bf79fa9817a0f7d2b050890ed109cae80bdb4dfa39536a7226da237 golangci-lint-1.59.0-netbsd-armv6.tar.gz +11587566363bd03ca586b7df9776ccaed569fcd1f3489930ac02f9375b307503 golangci-lint-1.59.0-netbsd-armv7.tar.gz +466181a8967bafa495e41494f93a0bec829c2cf715de874583b0460b3b8ae2b8 golangci-lint-1.59.0-windows-386.zip +3317d8a87a99a49a0a1321d295c010790e6dbf43ee96b318f4b8bb23eae7a565 golangci-lint-1.59.0-windows-amd64.zip +b3af955c7fceac8220a36fc799e1b3f19d3b247d32f422caac5f9845df8f7316 golangci-lint-1.59.0-windows-arm64.zip +6f083c7d0c764e5a0e5bde46ee3e91ae357d80c194190fe1d9754392e9064c7e golangci-lint-1.59.0-windows-armv6.zip +3709b4dd425deadab27748778d08e03c0f804d7748f7dd5b6bb488d98aa031c7 golangci-lint-1.59.0-windows-armv7.zip # This is the builder on PPA that will build Go itself (inception-y), don't modify! # From 2f06c1e854de1d916547a539679649e359dad476 Mon Sep 17 00:00:00 2001 From: hattizai Date: Wed, 29 May 2024 21:55:51 +0800 Subject: [PATCH 313/571] cmd/devp2p: fix node.TCP -> node.UDP (#29879) --- cmd/devp2p/internal/v4test/framework.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/devp2p/internal/v4test/framework.go b/cmd/devp2p/internal/v4test/framework.go index e8f4c021b81e..df1f1f8abaca 100644 --- a/cmd/devp2p/internal/v4test/framework.go +++ b/cmd/devp2p/internal/v4test/framework.go @@ -62,7 +62,7 @@ func newTestEnv(remote string, listen1, listen2 string) *testenv { if tcpPort = node.TCP(); tcpPort == 0 { tcpPort = 30303 } - if udpPort = node.TCP(); udpPort == 0 { + if udpPort = node.UDP(); udpPort == 0 { udpPort = 30303 } node = enode.NewV4(node.Pubkey(), ip, tcpPort, udpPort) From 6bb13e8e2be3aa8c41460eb11837baba514e19be Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 29 May 2024 15:56:52 +0200 Subject: [PATCH 314/571] eth/catalyst: ensure TxPool is synced in Fork (#29876) This should fix an occasional test failure in ethclient/simulated.TestForkResendTx. Inspection of logs revealed the cause of the failure to be that the txpool was not done reorganizing by the time Fork is called. --- eth/catalyst/simulated_beacon.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index fecd83f2762c..2d6569e42218 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -279,9 +279,12 @@ func (c *SimulatedBeacon) Rollback() { // Fork sets the head to the provided hash. func (c *SimulatedBeacon) Fork(parentHash common.Hash) error { + // Ensure no pending transactions. + c.eth.TxPool().Sync() if len(c.eth.TxPool().Pending(txpool.PendingFilter{})) != 0 { return errors.New("pending block dirty") } + parent := c.eth.BlockChain().GetBlockByHash(parentHash) if parent == nil { return errors.New("parent not found") From e015c1116f2c78a5b140d3fdc368f5d1abcd2eaf Mon Sep 17 00:00:00 2001 From: SuiYuan <165623542+suiyuan1314@users.noreply.github.com> Date: Thu, 30 May 2024 21:23:04 +0800 Subject: [PATCH 315/571] ethdb: remove unnecessary function wrapper (#29888) --- ethdb/dbtest/testsuite.go | 2 +- ethdb/pebble/pebble.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 7137d29396ce..29a773ced407 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -530,7 +530,7 @@ func makeDataset(size, ksize, vsize int, order bool) ([][]byte, [][]byte) { vals = append(vals, randBytes(vsize)) } if order { - slices.SortFunc(keys, func(a, b []byte) int { return bytes.Compare(a, b) }) + slices.SortFunc(keys, bytes.Compare) } return keys, vals } diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index dda084ae3b4e..0fac07c9604e 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -207,7 +207,7 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e // The default compaction concurrency(1 thread), // Here use all available CPUs for faster compaction. - MaxConcurrentCompactions: func() int { return runtime.NumCPU() }, + MaxConcurrentCompactions: runtime.NumCPU, // Per-level options. Options for at least one level must be specified. The // options for the last level are used for all subsequent levels. From 2262bf34158e184a2440f325ad355a45fa15ba9d Mon Sep 17 00:00:00 2001 From: SuiYuan <165623542+suiyuan1314@users.noreply.github.com> Date: Thu, 30 May 2024 22:24:16 +0800 Subject: [PATCH 316/571] crypto/secp256k1: change receiver variable name to lowercase (#29889) --- crypto/secp256k1/curve.go | 88 +++++++++++++-------------- crypto/secp256k1/scalar_mult_cgo.go | 2 +- crypto/secp256k1/scalar_mult_nocgo.go | 2 +- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go index 9b26ab292859..85ba885d6f5f 100644 --- a/crypto/secp256k1/curve.go +++ b/crypto/secp256k1/curve.go @@ -79,52 +79,52 @@ type BitCurve struct { BitSize int // the size of the underlying field } -func (BitCurve *BitCurve) Params() *elliptic.CurveParams { +func (bitCurve *BitCurve) Params() *elliptic.CurveParams { return &elliptic.CurveParams{ - P: BitCurve.P, - N: BitCurve.N, - B: BitCurve.B, - Gx: BitCurve.Gx, - Gy: BitCurve.Gy, - BitSize: BitCurve.BitSize, + P: bitCurve.P, + N: bitCurve.N, + B: bitCurve.B, + Gx: bitCurve.Gx, + Gy: bitCurve.Gy, + BitSize: bitCurve.BitSize, } } // IsOnCurve returns true if the given (x,y) lies on the BitCurve. -func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { +func (bitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { // y² = x³ + b y2 := new(big.Int).Mul(y, y) //y² - y2.Mod(y2, BitCurve.P) //y²%P + y2.Mod(y2, bitCurve.P) //y²%P x3 := new(big.Int).Mul(x, x) //x² x3.Mul(x3, x) //x³ - x3.Add(x3, BitCurve.B) //x³+B - x3.Mod(x3, BitCurve.P) //(x³+B)%P + x3.Add(x3, bitCurve.B) //x³+B + x3.Mod(x3, bitCurve.P) //(x³+B)%P return x3.Cmp(y2) == 0 } // affineFromJacobian reverses the Jacobian transform. See the comment at the // top of the file. -func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { +func (bitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { if z.Sign() == 0 { return new(big.Int), new(big.Int) } - zinv := new(big.Int).ModInverse(z, BitCurve.P) + zinv := new(big.Int).ModInverse(z, bitCurve.P) zinvsq := new(big.Int).Mul(zinv, zinv) xOut = new(big.Int).Mul(x, zinvsq) - xOut.Mod(xOut, BitCurve.P) + xOut.Mod(xOut, bitCurve.P) zinvsq.Mul(zinvsq, zinv) yOut = new(big.Int).Mul(y, zinvsq) - yOut.Mod(yOut, BitCurve.P) + yOut.Mod(yOut, bitCurve.P) return } // Add returns the sum of (x1,y1) and (x2,y2) -func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { // If one point is at infinity, return the other point. // Adding the point at infinity to any point will preserve the other point. if x1.Sign() == 0 && y1.Sign() == 0 { @@ -135,27 +135,27 @@ func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { } z := new(big.Int).SetInt64(1) if x1.Cmp(x2) == 0 && y1.Cmp(y2) == 0 { - return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z)) + return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z)) } - return BitCurve.affineFromJacobian(BitCurve.addJacobian(x1, y1, z, x2, y2, z)) + return bitCurve.affineFromJacobian(bitCurve.addJacobian(x1, y1, z, x2, y2, z)) } // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and // (x2, y2, z2) and returns their sum, also in Jacobian form. -func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { +func (bitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl z1z1 := new(big.Int).Mul(z1, z1) - z1z1.Mod(z1z1, BitCurve.P) + z1z1.Mod(z1z1, bitCurve.P) z2z2 := new(big.Int).Mul(z2, z2) - z2z2.Mod(z2z2, BitCurve.P) + z2z2.Mod(z2z2, bitCurve.P) u1 := new(big.Int).Mul(x1, z2z2) - u1.Mod(u1, BitCurve.P) + u1.Mod(u1, bitCurve.P) u2 := new(big.Int).Mul(x2, z1z1) - u2.Mod(u2, BitCurve.P) + u2.Mod(u2, bitCurve.P) h := new(big.Int).Sub(u2, u1) if h.Sign() == -1 { - h.Add(h, BitCurve.P) + h.Add(h, bitCurve.P) } i := new(big.Int).Lsh(h, 1) i.Mul(i, i) @@ -163,13 +163,13 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int s1 := new(big.Int).Mul(y1, z2) s1.Mul(s1, z2z2) - s1.Mod(s1, BitCurve.P) + s1.Mod(s1, bitCurve.P) s2 := new(big.Int).Mul(y2, z1) s2.Mul(s2, z1z1) - s2.Mod(s2, BitCurve.P) + s2.Mod(s2, bitCurve.P) r := new(big.Int).Sub(s2, s1) if r.Sign() == -1 { - r.Add(r, BitCurve.P) + r.Add(r, bitCurve.P) } r.Lsh(r, 1) v := new(big.Int).Mul(u1, i) @@ -179,7 +179,7 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int x3.Sub(x3, j) x3.Sub(x3, v) x3.Sub(x3, v) - x3.Mod(x3, BitCurve.P) + x3.Mod(x3, bitCurve.P) y3 := new(big.Int).Set(r) v.Sub(v, x3) @@ -187,33 +187,33 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int s1.Mul(s1, j) s1.Lsh(s1, 1) y3.Sub(y3, s1) - y3.Mod(y3, BitCurve.P) + y3.Mod(y3, bitCurve.P) z3 := new(big.Int).Add(z1, z2) z3.Mul(z3, z3) z3.Sub(z3, z1z1) if z3.Sign() == -1 { - z3.Add(z3, BitCurve.P) + z3.Add(z3, bitCurve.P) } z3.Sub(z3, z2z2) if z3.Sign() == -1 { - z3.Add(z3, BitCurve.P) + z3.Add(z3, bitCurve.P) } z3.Mul(z3, h) - z3.Mod(z3, BitCurve.P) + z3.Mod(z3, bitCurve.P) return x3, y3, z3 } // Double returns 2*(x,y) -func (BitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { z1 := new(big.Int).SetInt64(1) - return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z1)) + return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z1)) } // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and // returns its double, also in Jacobian form. -func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { +func (bitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l a := new(big.Int).Mul(x, x) //X1² @@ -231,30 +231,30 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, x3 := new(big.Int).Mul(big.NewInt(2), d) //2*D x3.Sub(f, x3) //F-2*D - x3.Mod(x3, BitCurve.P) + x3.Mod(x3, bitCurve.P) y3 := new(big.Int).Sub(d, x3) //D-X3 y3.Mul(e, y3) //E*(D-X3) y3.Sub(y3, new(big.Int).Mul(big.NewInt(8), c)) //E*(D-X3)-8*C - y3.Mod(y3, BitCurve.P) + y3.Mod(y3, bitCurve.P) z3 := new(big.Int).Mul(y, z) //Y1*Z1 z3.Mul(big.NewInt(2), z3) //3*Y1*Z1 - z3.Mod(z3, BitCurve.P) + z3.Mod(z3, bitCurve.P) return x3, y3, z3 } // ScalarBaseMult returns k*G, where G is the base point of the group and k is // an integer in big-endian form. -func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { - return BitCurve.ScalarMult(BitCurve.Gx, BitCurve.Gy, k) +func (bitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + return bitCurve.ScalarMult(bitCurve.Gx, bitCurve.Gy, k) } // Marshal converts a point into the form specified in section 4.3.6 of ANSI // X9.62. -func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { - byteLen := (BitCurve.BitSize + 7) >> 3 +func (bitCurve *BitCurve) Marshal(x, y *big.Int) []byte { + byteLen := (bitCurve.BitSize + 7) >> 3 ret := make([]byte, 1+2*byteLen) ret[0] = 4 // uncompressed point flag readBits(x, ret[1:1+byteLen]) @@ -264,8 +264,8 @@ func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { // Unmarshal converts a point, serialised by Marshal, into an x, y pair. On // error, x = nil. -func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) { - byteLen := (BitCurve.BitSize + 7) >> 3 +func (bitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) { + byteLen := (bitCurve.BitSize + 7) >> 3 if len(data) != 1+2*byteLen { return } diff --git a/crypto/secp256k1/scalar_mult_cgo.go b/crypto/secp256k1/scalar_mult_cgo.go index bdf8eeede7df..d11c11faf85b 100644 --- a/crypto/secp256k1/scalar_mult_cgo.go +++ b/crypto/secp256k1/scalar_mult_cgo.go @@ -21,7 +21,7 @@ extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned */ import "C" -func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { // Ensure scalar is exactly 32 bytes. We pad always, even if // scalar is 32 bytes long, to avoid a timing side channel. if len(scalar) > 32 { diff --git a/crypto/secp256k1/scalar_mult_nocgo.go b/crypto/secp256k1/scalar_mult_nocgo.go index 22f53ac6ae65..feb13a8dfd0e 100644 --- a/crypto/secp256k1/scalar_mult_nocgo.go +++ b/crypto/secp256k1/scalar_mult_nocgo.go @@ -9,6 +9,6 @@ package secp256k1 import "math/big" -func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { panic("ScalarMult is not available when secp256k1 is built without cgo") } From 5d7d48fc3e862237f97a9a27ba737816ab641a55 Mon Sep 17 00:00:00 2001 From: yujinpark Date: Fri, 31 May 2024 01:22:23 +0900 Subject: [PATCH 317/571] eth/gasprice: add comment to constant (#29892) Co-authored-by: Felix Lange --- eth/gasprice/feehistory.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index d039bcb40118..1e625e21c029 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -44,7 +44,8 @@ const ( // maxBlockFetchers is the max number of goroutines to spin up to pull blocks // for the fee history calculation (mostly relevant for LES). maxBlockFetchers = 4 - maxQueryLimit = 100 + // maxQueryLimit is the max number of requested percentiles. + maxQueryLimit = 100 ) // blockFees represents a single block for processing From bdc62f9bebc6f0762b77568a421a35125fa7db61 Mon Sep 17 00:00:00 2001 From: tianyeyouyou <150894831+tianyeyouyou@users.noreply.github.com> Date: Fri, 31 May 2024 15:25:49 +0800 Subject: [PATCH 318/571] common/math: rename variable name `int` to `n` (#29890) * chore: rename variable name `int` to `in` * chore: rename variable name `int` to `n` --- common/math/big_test.go | 4 ++-- common/math/integer.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/math/big_test.go b/common/math/big_test.go index 803b5e1cc617..ee8f09e7b45f 100644 --- a/common/math/big_test.go +++ b/common/math/big_test.go @@ -180,9 +180,9 @@ func BenchmarkByteAtOld(b *testing.B) { func TestReadBits(t *testing.T) { check := func(input string) { want, _ := hex.DecodeString(input) - int, _ := new(big.Int).SetString(input, 16) + n, _ := new(big.Int).SetString(input, 16) buf := make([]byte, len(want)) - ReadBits(int, buf) + ReadBits(n, buf) if !bytes.Equal(buf, want) { t.Errorf("have: %x\nwant: %x", buf, want) } diff --git a/common/math/integer.go b/common/math/integer.go index da01c0a08e00..080fba8fea89 100644 --- a/common/math/integer.go +++ b/common/math/integer.go @@ -54,11 +54,11 @@ func (i *HexOrDecimal64) UnmarshalJSON(input []byte) error { // UnmarshalText implements encoding.TextUnmarshaler. func (i *HexOrDecimal64) UnmarshalText(input []byte) error { - int, ok := ParseUint64(string(input)) + n, ok := ParseUint64(string(input)) if !ok { return fmt.Errorf("invalid hex or decimal integer %q", input) } - *i = HexOrDecimal64(int) + *i = HexOrDecimal64(n) return nil } From 2613523cb510a2e3ab956214c447e95c8a3d2d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 31 May 2024 10:39:40 +0300 Subject: [PATCH 319/571] miner: lower default min miner tip from 1 gwei to 0.001 gwei (#29895) --- miner/miner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/miner.go b/miner/miner.go index 430efcb2fcf1..ff81d0e8f5c8 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -53,7 +53,7 @@ type Config struct { // DefaultConfig contains default settings for miner. var DefaultConfig = Config{ GasCeil: 30_000_000, - GasPrice: big.NewInt(params.GWei), + GasPrice: big.NewInt(params.GWei / 1000), // The default recommit time is chosen as two seconds since // consensus-layer usually will wait a half slot of time(6s) From d4b81f0e087a660cffcbc6c660b43b46115e62ee Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 31 May 2024 18:40:09 +0200 Subject: [PATCH 320/571] CODEOWNERS: @s1na owns core/tracing (#29899) Update CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index faf922df0161..0dabaf4df5cf 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,6 +10,7 @@ core/ @karalabe @holiman @rjl493456442 eth/ @karalabe @holiman @rjl493456442 eth/catalyst/ @gballet eth/tracers/ @s1na +core/tracing/ @s1na graphql/ @s1na les/ @zsfelfoldi @rjl493456442 light/ @zsfelfoldi @rjl493456442 From c9e0b3105baa68e58780340cbaf146b1f0b46636 Mon Sep 17 00:00:00 2001 From: Chris Ziogas Date: Mon, 3 Jun 2024 13:30:27 +0300 Subject: [PATCH 321/571] Supply delta live tracer (#29347) Introduces the first built-in live tracer. The supply tracer tracks ETH supply changes across blocks and writes the output to disk. This will need to be enabled through CLI using the `--vmtrace supply` flag. Co-authored-by: Sina Mahmoodi --- .../gen_balance_change_reason_stringer.go | 37 ++ core/tracing/hooks.go | 2 + eth/tracers/internal/tracetest/supply_test.go | 613 ++++++++++++++++++ eth/tracers/live/gen_supplyinfoburn.go | 49 ++ eth/tracers/live/gen_supplyinfoissuance.go | 49 ++ eth/tracers/live/supply.go | 310 +++++++++ 6 files changed, 1060 insertions(+) create mode 100644 core/tracing/gen_balance_change_reason_stringer.go create mode 100644 eth/tracers/internal/tracetest/supply_test.go create mode 100644 eth/tracers/live/gen_supplyinfoburn.go create mode 100644 eth/tracers/live/gen_supplyinfoissuance.go create mode 100644 eth/tracers/live/supply.go diff --git a/core/tracing/gen_balance_change_reason_stringer.go b/core/tracing/gen_balance_change_reason_stringer.go new file mode 100644 index 000000000000..d3a515a12d37 --- /dev/null +++ b/core/tracing/gen_balance_change_reason_stringer.go @@ -0,0 +1,37 @@ +// Code generated by "stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go"; DO NOT EDIT. + +package tracing + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[BalanceChangeUnspecified-0] + _ = x[BalanceIncreaseRewardMineUncle-1] + _ = x[BalanceIncreaseRewardMineBlock-2] + _ = x[BalanceIncreaseWithdrawal-3] + _ = x[BalanceIncreaseGenesisBalance-4] + _ = x[BalanceIncreaseRewardTransactionFee-5] + _ = x[BalanceDecreaseGasBuy-6] + _ = x[BalanceIncreaseGasReturn-7] + _ = x[BalanceIncreaseDaoContract-8] + _ = x[BalanceDecreaseDaoAccount-9] + _ = x[BalanceChangeTransfer-10] + _ = x[BalanceChangeTouchAccount-11] + _ = x[BalanceIncreaseSelfdestruct-12] + _ = x[BalanceDecreaseSelfdestruct-13] + _ = x[BalanceDecreaseSelfdestructBurn-14] +} + +const _BalanceChangeReason_name = "BalanceChangeUnspecifiedBalanceIncreaseRewardMineUncleBalanceIncreaseRewardMineBlockBalanceIncreaseWithdrawalBalanceIncreaseGenesisBalanceBalanceIncreaseRewardTransactionFeeBalanceDecreaseGasBuyBalanceIncreaseGasReturnBalanceIncreaseDaoContractBalanceDecreaseDaoAccountBalanceChangeTransferBalanceChangeTouchAccountBalanceIncreaseSelfdestructBalanceDecreaseSelfdestructBalanceDecreaseSelfdestructBurn" + +var _BalanceChangeReason_index = [...]uint16{0, 24, 54, 84, 109, 138, 173, 194, 218, 244, 269, 290, 315, 342, 369, 400} + +func (i BalanceChangeReason) String() string { + if i >= BalanceChangeReason(len(_BalanceChangeReason_index)-1) { + return "BalanceChangeReason(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _BalanceChangeReason_name[_BalanceChangeReason_index[i]:_BalanceChangeReason_index[i+1]] +} diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 9b08cffd4526..db058e847c0d 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -199,6 +199,8 @@ type Hooks struct { // for tracing and reporting. type BalanceChangeReason byte +//go:generate stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go + const ( BalanceChangeUnspecified BalanceChangeReason = 0 diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go new file mode 100644 index 000000000000..2d4f1b089006 --- /dev/null +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -0,0 +1,613 @@ +// Copyright 2021 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 tracetest + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "math/big" + "os" + "path" + "path/filepath" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "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/eth/tracers" + "github.com/ethereum/go-ethereum/params" + + // Force-load live packages, to trigger registration + _ "github.com/ethereum/go-ethereum/eth/tracers/live" +) + +type supplyInfoIssuance struct { + GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"` + Reward *hexutil.Big `json:"reward,omitempty"` + Withdrawals *hexutil.Big `json:"withdrawals,omitempty"` +} + +type supplyInfoBurn struct { + EIP1559 *hexutil.Big `json:"1559,omitempty"` + Blob *hexutil.Big `json:"blob,omitempty"` + Misc *hexutil.Big `json:"misc,omitempty"` +} + +type supplyInfo struct { + Issuance *supplyInfoIssuance `json:"issuance,omitempty"` + Burn *supplyInfoBurn `json:"burn,omitempty"` + + // Block info + Number uint64 `json:"blockNumber"` + Hash common.Hash `json:"hash"` + ParentHash common.Hash `json:"parentHash"` +} + +func emptyBlockGenerationFunc(b *core.BlockGen) {} + +func TestSupplyOmittedFields(t *testing.T) { + var ( + config = *params.MergedTestChainConfig + gspec = &core.Genesis{ + Config: &config, + } + ) + + gspec.Config.TerminalTotalDifficulty = big.NewInt(0) + + out, _, err := testSupplyTracer(t, gspec, func(b *core.BlockGen) { + b.SetPoS() + }) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + expected := supplyInfo{ + Number: 0, + Hash: common.HexToHash("0x52f276d96f0afaaf2c3cb358868bdc2779c4b0cb8de3e7e5302e247c0b66a703"), + ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + } + actual := out[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func TestSupplyGenesisAlloc(t *testing.T) { + var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + + config = *params.AllEthashProtocolChanges + + gspec = &core.Genesis{ + Config: &config, + Alloc: types.GenesisAlloc{ + addr1: {Balance: eth1}, + addr2: {Balance: eth1}, + }, + } + ) + + expected := supplyInfo{ + Issuance: &supplyInfoIssuance{ + GenesisAlloc: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))), + }, + Number: 0, + Hash: common.HexToHash("0xbcc9466e9fc6a8b56f4b29ca353a421ff8b51a0c1a58ca4743b427605b08f2ca"), + ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + } + + out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + actual := out[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func TestSupplyRewards(t *testing.T) { + var ( + config = *params.AllEthashProtocolChanges + + gspec = &core.Genesis{ + Config: &config, + } + ) + + expected := supplyInfo{ + Issuance: &supplyInfoIssuance{ + Reward: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))), + }, + Number: 1, + Hash: common.HexToHash("0xcbb08370505be503dafedc4e96d139ea27aba3cbc580148568b8a307b3f51052"), + ParentHash: common.HexToHash("0xadeda0a83e337b6c073e3f0e9a17531a04009b397a9588c093b628f21b8bc5a3"), + } + + out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + actual := out[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func TestSupplyEip1559Burn(t *testing.T) { + var ( + config = *params.AllEthashProtocolChanges + + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") + // A sender who makes transactions, has some eth1 + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei)) + eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + + gspec = &core.Genesis{ + Config: &config, + BaseFee: big.NewInt(params.InitialBaseFee), + Alloc: types.GenesisAlloc{ + addr1: {Balance: eth1}, + }, + } + ) + + signer := types.LatestSigner(gspec.Config) + + eip1559BlockGenerationFunc := func(b *core.BlockGen) { + txdata := &types.DynamicFeeTx{ + ChainID: gspec.Config.ChainID, + Nonce: 0, + To: &aa, + Gas: 21000, + GasFeeCap: gwei5, + GasTipCap: big.NewInt(2), + } + tx := types.NewTx(txdata) + tx, _ = types.SignTx(tx, signer, key1) + + b.AddTx(tx) + } + + out, chain, err := testSupplyTracer(t, gspec, eip1559BlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + var ( + head = chain.CurrentBlock() + reward = new(big.Int).Mul(common.Big2, big.NewInt(params.Ether)) + burn = new(big.Int).Mul(big.NewInt(21000), head.BaseFee) + expected = supplyInfo{ + Issuance: &supplyInfoIssuance{ + Reward: (*hexutil.Big)(reward), + }, + Burn: &supplyInfoBurn{ + EIP1559: (*hexutil.Big)(burn), + }, + Number: 1, + Hash: head.Hash(), + ParentHash: head.ParentHash, + } + ) + + actual := out[expected.Number] + compareAsJSON(t, expected, actual) +} + +func TestSupplyWithdrawals(t *testing.T) { + var ( + config = *params.MergedTestChainConfig + gspec = &core.Genesis{ + Config: &config, + } + ) + + withdrawalsBlockGenerationFunc := func(b *core.BlockGen) { + b.SetPoS() + + b.AddWithdrawal(&types.Withdrawal{ + Validator: 42, + Address: common.Address{0xee}, + Amount: 1337, + }) + } + + out, chain, err := testSupplyTracer(t, gspec, withdrawalsBlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + var ( + head = chain.CurrentBlock() + expected = supplyInfo{ + Issuance: &supplyInfoIssuance{ + Withdrawals: (*hexutil.Big)(big.NewInt(1337000000000)), + }, + Number: 1, + Hash: head.Hash(), + ParentHash: head.ParentHash, + } + actual = out[expected.Number] + ) + + compareAsJSON(t, expected, actual) +} + +// Tests fund retrieval after contract's selfdestruct. +// Contract A calls contract B which selfdestructs, but B receives eth1 +// after the selfdestruct opcode executes from Contract A. +// Because Contract B is removed only at the end of the transaction +// the ether sent in between is burnt before Cancun hard fork. +func TestSupplySelfdestruct(t *testing.T) { + var ( + config = *params.TestChainConfig + + aa = common.HexToAddress("0x1111111111111111111111111111111111111111") + bb = common.HexToAddress("0x2222222222222222222222222222222222222222") + dad = common.HexToAddress("0x0000000000000000000000000000000000000dad") + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei)) + eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + + gspec = &core.Genesis{ + Config: &config, + BaseFee: big.NewInt(params.InitialBaseFee), + Alloc: types.GenesisAlloc{ + addr1: {Balance: eth1}, + aa: { + Code: common.FromHex("0x61face60f01b6000527322222222222222222222222222222222222222226000806002600080855af160008103603457600080fd5b60008060008034865af1905060008103604c57600080fd5b5050"), + // Nonce: 0, + Balance: big.NewInt(0), + }, + bb: { + Code: common.FromHex("0x6000357fface000000000000000000000000000000000000000000000000000000000000808203602f57610dad80ff5b5050"), + Nonce: 0, + Balance: eth1, + }, + }, + } + ) + + gspec.Config.TerminalTotalDifficulty = big.NewInt(0) + + signer := types.LatestSigner(gspec.Config) + + testBlockGenerationFunc := func(b *core.BlockGen) { + b.SetPoS() + + txdata := &types.LegacyTx{ + Nonce: 0, + To: &aa, + Value: gwei5, + Gas: 150000, + GasPrice: gwei5, + Data: []byte{}, + } + + tx := types.NewTx(txdata) + tx, _ = types.SignTx(tx, signer, key1) + + b.AddTx(tx) + } + + // 1. Test pre Cancun + preCancunOutput, preCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + if err != nil { + t.Fatalf("Pre-cancun failed to test supply tracer: %v", err) + } + + // Check balance at state: + // 1. 0x0000...000dad has 1 ether + // 2. A has 0 ether + // 3. B has 0 ether + statedb, _ := preCancunChain.State() + if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 { + t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", dad, got, exp) + } + if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 { + t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", aa, got, exp) + } + if got, exp := statedb.GetBalance(bb), big.NewInt(0); got.CmpBig(exp) != 0 { + t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + + head := preCancunChain.CurrentBlock() + // Check live trace output + expected := supplyInfo{ + Burn: &supplyInfoBurn{ + EIP1559: (*hexutil.Big)(big.NewInt(55289500000000)), + Misc: (*hexutil.Big)(big.NewInt(5000000000)), + }, + Number: 1, + Hash: head.Hash(), + ParentHash: head.ParentHash, + } + + actual := preCancunOutput[expected.Number] + + compareAsJSON(t, expected, actual) + + // 2. Test post Cancun + cancunTime := uint64(0) + gspec.Config.ShanghaiTime = &cancunTime + gspec.Config.CancunTime = &cancunTime + + postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + if err != nil { + t.Fatalf("Post-cancun failed to test supply tracer: %v", err) + } + + // Check balance at state: + // 1. 0x0000...000dad has 1 ether + // 3. A has 0 ether + // 3. B has 5 gwei + statedb, _ = postCancunChain.State() + if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 { + t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", dad, got, exp) + } + if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 { + t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", aa, got, exp) + } + if got, exp := statedb.GetBalance(bb), gwei5; got.CmpBig(exp) != 0 { + t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + + // Check live trace output + head = postCancunChain.CurrentBlock() + expected = supplyInfo{ + Burn: &supplyInfoBurn{ + EIP1559: (*hexutil.Big)(big.NewInt(55289500000000)), + }, + Number: 1, + Hash: head.Hash(), + ParentHash: head.ParentHash, + } + + actual = postCancunOutput[expected.Number] + + compareAsJSON(t, expected, actual) +} + +// Tests selfdestructing contract to send its balance to itself (burn). +// It tests both cases of selfdestructing succeding and being reverted. +// - Contract A calls B and D. +// - Contract B selfdestructs and sends the eth1 to itself (Burn amount to be counted). +// - Contract C selfdestructs and sends the eth1 to itself. +// - Contract D calls C and reverts (Burn amount of C +// has to be reverted as well). +func TestSupplySelfdestructItselfAndRevert(t *testing.T) { + var ( + config = *params.TestChainConfig + + aa = common.HexToAddress("0x1111111111111111111111111111111111111111") + bb = common.HexToAddress("0x2222222222222222222222222222222222222222") + cc = common.HexToAddress("0x3333333333333333333333333333333333333333") + dd = common.HexToAddress("0x4444444444444444444444444444444444444444") + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei)) + eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + eth2 = new(big.Int).Mul(common.Big2, big.NewInt(params.Ether)) + eth5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.Ether)) + + gspec = &core.Genesis{ + Config: &config, + // BaseFee: big.NewInt(params.InitialBaseFee), + Alloc: types.GenesisAlloc{ + addr1: {Balance: eth1}, + aa: { + // Contract code in YUL: + // + // object "ContractA" { + // code { + // let B := 0x2222222222222222222222222222222222222222 + // let D := 0x4444444444444444444444444444444444444444 + + // // Call to Contract B + // let resB:= call(gas(), B, 0, 0x0, 0x0, 0, 0) + + // // Call to Contract D + // let resD := call(gas(), D, 0, 0x0, 0x0, 0, 0) + // } + // } + Code: common.FromHex("0x73222222222222222222222222222222222222222273444444444444444444444444444444444444444460006000600060006000865af160006000600060006000865af150505050"), + Balance: common.Big0, + }, + bb: { + // Contract code in YUL: + // + // object "ContractB" { + // code { + // let self := address() + // selfdestruct(self) + // } + // } + Code: common.FromHex("0x3080ff50"), + Balance: eth5, + }, + cc: { + Code: common.FromHex("0x3080ff50"), + Balance: eth1, + }, + dd: { + // Contract code in YUL: + // + // object "ContractD" { + // code { + // let C := 0x3333333333333333333333333333333333333333 + + // // Call to Contract C + // let resC := call(gas(), C, 0, 0x0, 0x0, 0, 0) + + // // Revert + // revert(0, 0) + // } + // } + Code: common.FromHex("0x73333333333333333333333333333333333333333360006000600060006000855af160006000fd5050"), + Balance: eth2, + }, + }, + } + ) + + gspec.Config.TerminalTotalDifficulty = big.NewInt(0) + + signer := types.LatestSigner(gspec.Config) + + testBlockGenerationFunc := func(b *core.BlockGen) { + b.SetPoS() + + txdata := &types.LegacyTx{ + Nonce: 0, + To: &aa, + Value: common.Big0, + Gas: 150000, + GasPrice: gwei5, + Data: []byte{}, + } + + tx := types.NewTx(txdata) + tx, _ = types.SignTx(tx, signer, key1) + + b.AddTx(tx) + } + + output, chain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + // Check balance at state: + // 1. A has 0 ether + // 2. B has 0 ether, burned + // 3. C has 2 ether, selfdestructed but parent D reverted + // 4. D has 1 ether, reverted + statedb, _ := chain.State() + if got, exp := statedb.GetBalance(aa), common.Big0; got.CmpBig(exp) != 0 { + t.Fatalf("address \"%v\" balance, got %v exp %v\n", aa, got, exp) + } + if got, exp := statedb.GetBalance(bb), common.Big0; got.CmpBig(exp) != 0 { + t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + if got, exp := statedb.GetBalance(cc), eth1; got.CmpBig(exp) != 0 { + t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + if got, exp := statedb.GetBalance(dd), eth2; got.CmpBig(exp) != 0 { + t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + + // Check live trace output + block := chain.GetBlockByNumber(1) + + expected := supplyInfo{ + Burn: &supplyInfoBurn{ + EIP1559: (*hexutil.Big)(new(big.Int).Mul(block.BaseFee(), big.NewInt(int64(block.GasUsed())))), + Misc: (*hexutil.Big)(eth5), // 5ETH burned from contract B + }, + Number: 1, + Hash: block.Hash(), + ParentHash: block.ParentHash(), + } + + actual := output[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, *core.BlockChain, error) { + var ( + engine = beacon.New(ethash.NewFaker()) + ) + + traceOutputPath := filepath.ToSlash(t.TempDir()) + traceOutputFilename := path.Join(traceOutputPath, "supply.jsonl") + + // Load supply tracer + tracer, err := tracers.LiveDirectory.New("supply", json.RawMessage(fmt.Sprintf(`{"path":"%s"}`, traceOutputPath))) + if err != nil { + return nil, nil, fmt.Errorf("failed to create call tracer: %v", err) + } + + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), core.DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, engine, vm.Config{Tracer: tracer}, nil, nil) + if err != nil { + return nil, nil, fmt.Errorf("failed to create tester chain: %v", err) + } + defer chain.Stop() + + _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, 1, func(i int, b *core.BlockGen) { + b.SetCoinbase(common.Address{1}) + gen(b) + }) + + if n, err := chain.InsertChain(blocks); err != nil { + return nil, chain, fmt.Errorf("block %d: failed to insert into chain: %v", n, err) + } + + // Check and compare the results + file, err := os.OpenFile(traceOutputFilename, os.O_RDONLY, 0666) + if err != nil { + return nil, chain, fmt.Errorf("failed to open output file: %v", err) + } + defer file.Close() + + var output []supplyInfo + scanner := bufio.NewScanner(file) + + for scanner.Scan() { + blockBytes := scanner.Bytes() + + var info supplyInfo + if err := json.Unmarshal(blockBytes, &info); err != nil { + return nil, chain, fmt.Errorf("failed to unmarshal result: %v", err) + } + + output = append(output, info) + } + + return output, chain, nil +} + +func compareAsJSON(t *testing.T, expected interface{}, actual interface{}) { + want, err := json.Marshal(expected) + if err != nil { + t.Fatalf("failed to marshal expected value to JSON: %v", err) + } + + have, err := json.Marshal(actual) + if err != nil { + t.Fatalf("failed to marshal actual value to JSON: %v", err) + } + + if !bytes.Equal(want, have) { + t.Fatalf("incorrect supply info: expected %s, got %s", string(want), string(have)) + } +} diff --git a/eth/tracers/live/gen_supplyinfoburn.go b/eth/tracers/live/gen_supplyinfoburn.go new file mode 100644 index 000000000000..d01eda3975da --- /dev/null +++ b/eth/tracers/live/gen_supplyinfoburn.go @@ -0,0 +1,49 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package live + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*supplyInfoBurnMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (s supplyInfoBurn) MarshalJSON() ([]byte, error) { + type supplyInfoBurn struct { + EIP1559 *hexutil.Big `json:"1559,omitempty"` + Blob *hexutil.Big `json:"blob,omitempty"` + Misc *hexutil.Big `json:"misc,omitempty"` + } + var enc supplyInfoBurn + enc.EIP1559 = (*hexutil.Big)(s.EIP1559) + enc.Blob = (*hexutil.Big)(s.Blob) + enc.Misc = (*hexutil.Big)(s.Misc) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (s *supplyInfoBurn) UnmarshalJSON(input []byte) error { + type supplyInfoBurn struct { + EIP1559 *hexutil.Big `json:"1559,omitempty"` + Blob *hexutil.Big `json:"blob,omitempty"` + Misc *hexutil.Big `json:"misc,omitempty"` + } + var dec supplyInfoBurn + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.EIP1559 != nil { + s.EIP1559 = (*big.Int)(dec.EIP1559) + } + if dec.Blob != nil { + s.Blob = (*big.Int)(dec.Blob) + } + if dec.Misc != nil { + s.Misc = (*big.Int)(dec.Misc) + } + return nil +} diff --git a/eth/tracers/live/gen_supplyinfoissuance.go b/eth/tracers/live/gen_supplyinfoissuance.go new file mode 100644 index 000000000000..e2536ee3252d --- /dev/null +++ b/eth/tracers/live/gen_supplyinfoissuance.go @@ -0,0 +1,49 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package live + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*supplyInfoIssuanceMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (s supplyInfoIssuance) MarshalJSON() ([]byte, error) { + type supplyInfoIssuance struct { + GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"` + Reward *hexutil.Big `json:"reward,omitempty"` + Withdrawals *hexutil.Big `json:"withdrawals,omitempty"` + } + var enc supplyInfoIssuance + enc.GenesisAlloc = (*hexutil.Big)(s.GenesisAlloc) + enc.Reward = (*hexutil.Big)(s.Reward) + enc.Withdrawals = (*hexutil.Big)(s.Withdrawals) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (s *supplyInfoIssuance) UnmarshalJSON(input []byte) error { + type supplyInfoIssuance struct { + GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"` + Reward *hexutil.Big `json:"reward,omitempty"` + Withdrawals *hexutil.Big `json:"withdrawals,omitempty"` + } + var dec supplyInfoIssuance + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.GenesisAlloc != nil { + s.GenesisAlloc = (*big.Int)(dec.GenesisAlloc) + } + if dec.Reward != nil { + s.Reward = (*big.Int)(dec.Reward) + } + if dec.Withdrawals != nil { + s.Withdrawals = (*big.Int)(dec.Withdrawals) + } + return nil +} diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go new file mode 100644 index 000000000000..0c9141e99d9f --- /dev/null +++ b/eth/tracers/live/supply.go @@ -0,0 +1,310 @@ +package live + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + "path/filepath" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/log" + "gopkg.in/natefinch/lumberjack.v2" +) + +func init() { + tracers.LiveDirectory.Register("supply", newSupply) +} + +type supplyInfoIssuance struct { + GenesisAlloc *big.Int `json:"genesisAlloc,omitempty"` + Reward *big.Int `json:"reward,omitempty"` + Withdrawals *big.Int `json:"withdrawals,omitempty"` +} + +//go:generate go run github.com/fjl/gencodec -type supplyInfoIssuance -field-override supplyInfoIssuanceMarshaling -out gen_supplyinfoissuance.go +type supplyInfoIssuanceMarshaling struct { + GenesisAlloc *hexutil.Big + Reward *hexutil.Big + Withdrawals *hexutil.Big +} + +type supplyInfoBurn struct { + EIP1559 *big.Int `json:"1559,omitempty"` + Blob *big.Int `json:"blob,omitempty"` + Misc *big.Int `json:"misc,omitempty"` +} + +//go:generate go run github.com/fjl/gencodec -type supplyInfoBurn -field-override supplyInfoBurnMarshaling -out gen_supplyinfoburn.go +type supplyInfoBurnMarshaling struct { + EIP1559 *hexutil.Big + Blob *hexutil.Big + Misc *hexutil.Big +} + +type supplyInfo struct { + Issuance *supplyInfoIssuance `json:"issuance,omitempty"` + Burn *supplyInfoBurn `json:"burn,omitempty"` + + // Block info + Number uint64 `json:"blockNumber"` + Hash common.Hash `json:"hash"` + ParentHash common.Hash `json:"parentHash"` +} + +type supplyTxCallstack struct { + calls []supplyTxCallstack + burn *big.Int +} + +type supply struct { + delta supplyInfo + txCallstack []supplyTxCallstack // Callstack for current transaction + logger *lumberjack.Logger +} + +type supplyTracerConfig struct { + Path string `json:"path"` // Path to the directory where the tracer logs will be stored + MaxSize int `json:"maxSize"` // MaxSize is the maximum size in megabytes of the tracer log file before it gets rotated. It defaults to 100 megabytes. +} + +func newSupply(cfg json.RawMessage) (*tracing.Hooks, error) { + var config supplyTracerConfig + if cfg != nil { + if err := json.Unmarshal(cfg, &config); err != nil { + return nil, fmt.Errorf("failed to parse config: %v", err) + } + } + if config.Path == "" { + return nil, errors.New("supply tracer output path is required") + } + + // Store traces in a rotating file + logger := &lumberjack.Logger{ + Filename: filepath.Join(config.Path, "supply.jsonl"), + } + if config.MaxSize > 0 { + logger.MaxSize = config.MaxSize + } + + t := &supply{ + delta: newSupplyInfo(), + logger: logger, + } + return &tracing.Hooks{ + OnBlockStart: t.OnBlockStart, + OnBlockEnd: t.OnBlockEnd, + OnGenesisBlock: t.OnGenesisBlock, + OnTxStart: t.OnTxStart, + OnBalanceChange: t.OnBalanceChange, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnClose: t.OnClose, + }, nil +} + +func newSupplyInfo() supplyInfo { + return supplyInfo{ + Issuance: &supplyInfoIssuance{ + GenesisAlloc: big.NewInt(0), + Reward: big.NewInt(0), + Withdrawals: big.NewInt(0), + }, + Burn: &supplyInfoBurn{ + EIP1559: big.NewInt(0), + Blob: big.NewInt(0), + Misc: big.NewInt(0), + }, + + Number: 0, + Hash: common.Hash{}, + ParentHash: common.Hash{}, + } +} + +func (s *supply) resetDelta() { + s.delta = newSupplyInfo() +} + +func (s *supply) OnBlockStart(ev tracing.BlockEvent) { + s.resetDelta() + + s.delta.Number = ev.Block.NumberU64() + s.delta.Hash = ev.Block.Hash() + s.delta.ParentHash = ev.Block.ParentHash() + + // Calculate Burn for this block + if ev.Block.BaseFee() != nil { + burn := new(big.Int).Mul(new(big.Int).SetUint64(ev.Block.GasUsed()), ev.Block.BaseFee()) + s.delta.Burn.EIP1559 = burn + } + // Blob burnt gas + if blobGas := ev.Block.BlobGasUsed(); blobGas != nil && *blobGas > 0 && ev.Block.ExcessBlobGas() != nil { + var ( + excess = *ev.Block.ExcessBlobGas() + baseFee = eip4844.CalcBlobFee(excess) + burn = new(big.Int).Mul(new(big.Int).SetUint64(*blobGas), baseFee) + ) + s.delta.Burn.Blob = burn + } +} + +func (s *supply) OnBlockEnd(err error) { + s.write(s.delta) +} + +func (s *supply) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) { + s.resetDelta() + + s.delta.Number = b.NumberU64() + s.delta.Hash = b.Hash() + s.delta.ParentHash = b.ParentHash() + + // Initialize supply with total allocation in genesis block + for _, account := range alloc { + s.delta.Issuance.GenesisAlloc.Add(s.delta.Issuance.GenesisAlloc, account.Balance) + } + + s.write(s.delta) +} + +func (s *supply) OnBalanceChange(a common.Address, prevBalance, newBalance *big.Int, reason tracing.BalanceChangeReason) { + diff := new(big.Int).Sub(newBalance, prevBalance) + + // NOTE: don't handle "BalanceIncreaseGenesisBalance" because it is handled in OnGenesisBlock + switch reason { + case tracing.BalanceIncreaseRewardMineUncle: + case tracing.BalanceIncreaseRewardMineBlock: + s.delta.Issuance.Reward.Add(s.delta.Issuance.Reward, diff) + case tracing.BalanceIncreaseWithdrawal: + s.delta.Issuance.Withdrawals.Add(s.delta.Issuance.Withdrawals, diff) + case tracing.BalanceDecreaseSelfdestructBurn: + // BalanceDecreaseSelfdestructBurn is non-reversible as it happens + // at the end of the transaction. + s.delta.Burn.Misc.Sub(s.delta.Burn.Misc, diff) + default: + return + } +} + +func (s *supply) OnTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) { + s.txCallstack = make([]supplyTxCallstack, 0, 1) +} + +// internalTxsHandler handles internal transactions burned amount +func (s *supply) internalTxsHandler(call *supplyTxCallstack) { + // Handle Burned amount + if call.burn != nil { + s.delta.Burn.Misc.Add(s.delta.Burn.Misc, call.burn) + } + + if len(call.calls) > 0 { + // Recursivelly handle internal calls + for _, call := range call.calls { + callCopy := call + s.internalTxsHandler(&callCopy) + } + } +} + +func (s *supply) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + call := supplyTxCallstack{ + calls: make([]supplyTxCallstack, 0), + } + + // This is a special case of burned amount which has to be handled here + // which happens when type == selfdestruct and from == to. + if vm.OpCode(typ) == vm.SELFDESTRUCT && from == to && value.Cmp(common.Big0) == 1 { + call.burn = value + } + + // Append call to the callstack, so we can fill the details in CaptureExit + s.txCallstack = append(s.txCallstack, call) +} + +func (s *supply) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth == 0 { + // No need to handle Burned amount if transaction is reverted + if !reverted { + s.internalTxsHandler(&s.txCallstack[0]) + } + return + } + + size := len(s.txCallstack) + if size <= 1 { + return + } + // Pop call + call := s.txCallstack[size-1] + s.txCallstack = s.txCallstack[:size-1] + size -= 1 + + // In case of a revert, we can drop the call and all its subcalls. + // Caution, that this has to happen after popping the call from the stack. + if reverted { + return + } + s.txCallstack[size-1].calls = append(s.txCallstack[size-1].calls, call) +} + +func (s *supply) OnClose() { + if err := s.logger.Close(); err != nil { + log.Warn("failed to close supply tracer log file", "error", err) + } +} + +func (s *supply) write(data any) { + supply, ok := data.(supplyInfo) + if !ok { + log.Warn("failed to cast supply tracer data on write to log file") + return + } + + // Remove empty fields + if supply.Issuance.GenesisAlloc.Sign() == 0 { + supply.Issuance.GenesisAlloc = nil + } + + if supply.Issuance.Reward.Sign() == 0 { + supply.Issuance.Reward = nil + } + + if supply.Issuance.Withdrawals.Sign() == 0 { + supply.Issuance.Withdrawals = nil + } + + if supply.Issuance.GenesisAlloc == nil && supply.Issuance.Reward == nil && supply.Issuance.Withdrawals == nil { + supply.Issuance = nil + } + + if supply.Burn.EIP1559.Sign() == 0 { + supply.Burn.EIP1559 = nil + } + + if supply.Burn.Blob.Sign() == 0 { + supply.Burn.Blob = nil + } + + if supply.Burn.Misc.Sign() == 0 { + supply.Burn.Misc = nil + } + + if supply.Burn.EIP1559 == nil && supply.Burn.Blob == nil && supply.Burn.Misc == nil { + supply.Burn = nil + } + + out, _ := json.Marshal(supply) + if _, err := s.logger.Write(out); err != nil { + log.Warn("failed to write to supply tracer log file", "error", err) + } + if _, err := s.logger.Write([]byte{'\n'}); err != nil { + log.Warn("failed to write to supply tracer log file", "error", err) + } +} From d38b88a5a10800e1632833e284c6500c240c012e Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 3 Jun 2024 19:17:12 +0800 Subject: [PATCH 322/571] core/state: introduce stateupdate structure (#29530) * core/state: introduce stateUpate structure * core/state: remove outdated function description * core/state: address comments --- core/genesis_test.go | 4 +- core/state/state_object.go | 268 +++++++++++----------- core/state/statedb.go | 391 ++++++++++++++------------------ core/state/statedb_fuzz_test.go | 30 ++- core/state/stateupdate.go | 133 +++++++++++ 5 files changed, 461 insertions(+), 365 deletions(-) create mode 100644 core/state/stateupdate.go diff --git a/core/genesis_test.go b/core/genesis_test.go index 31401e214cb1..ab408327d4e6 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -304,7 +304,7 @@ func TestVerkleGenesisCommit(t *testing.T) { }, } - expected := common.Hex2Bytes("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b") + expected := common.FromHex("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b") got := genesis.ToBlock().Root().Bytes() if !bytes.Equal(got, expected) { t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got) @@ -314,7 +314,7 @@ func TestVerkleGenesisCommit(t *testing.T) { triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults}) block := genesis.MustCommit(db, triedb) if !bytes.Equal(block.Root().Bytes(), expected) { - t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got) + t.Fatalf("invalid genesis state root, expected %x, got %x", expected, block.Root()) } // Test that the trie is verkle diff --git a/core/state/state_object.go b/core/state/state_object.go index 252dcdf2b0d3..b7a215bd1753 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -19,9 +19,7 @@ package state import ( "bytes" "fmt" - "io" "maps" - "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -34,14 +32,6 @@ import ( "github.com/holiman/uint256" ) -// hasherPool holds a pool of hashers used by state objects during concurrent -// trie updates. -var hasherPool = sync.Pool{ - New: func() interface{} { - return crypto.NewKeccakState() - }, -} - type Storage map[common.Hash]common.Hash func (s Storage) Copy() Storage { @@ -65,9 +55,20 @@ type stateObject struct { trie Trie // storage trie, which becomes non-nil on first access code []byte // contract bytecode, which gets set when code is loaded - originStorage Storage // Storage cache of original entries to dedup rewrites - pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block - dirtyStorage Storage // Storage entries that have been modified in the current transaction execution, reset for every transaction + originStorage Storage // Storage entries that have been accessed within the current block + dirtyStorage Storage // Storage entries that have been modified within the current transaction + pendingStorage Storage // Storage entries that have been modified within the current block + + // uncommittedStorage tracks a set of storage entries that have been modified + // but not yet committed since the "last commit operation", along with their + // original values before mutation. + // + // Specifically, the commit will be performed after each transaction before + // the byzantium fork, therefore the map is already reset at the transaction + // boundary; however post the byzantium fork, the commit will only be performed + // at the end of block, this set essentially tracks all the modifications + // made within the block. + uncommittedStorage Storage // Cache flags. dirtyCode bool // true if the code was updated @@ -96,22 +97,18 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s acct = types.NewEmptyStateAccount() } return &stateObject{ - db: db, - address: address, - addrHash: crypto.Keccak256Hash(address[:]), - origin: origin, - data: *acct, - originStorage: make(Storage), - pendingStorage: make(Storage), - dirtyStorage: make(Storage), + db: db, + address: address, + addrHash: crypto.Keccak256Hash(address[:]), + origin: origin, + data: *acct, + originStorage: make(Storage), + dirtyStorage: make(Storage), + pendingStorage: make(Storage), + uncommittedStorage: make(Storage), } } -// EncodeRLP implements rlp.Encoder. -func (s *stateObject) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, &s.data) -} - func (s *stateObject) markSelfdestructed() { s.selfDestructed = true } @@ -160,7 +157,7 @@ func (s *stateObject) getPrefetchedTrie() Trie { return s.db.prefetcher.trie(s.addrHash, s.data.Root) } -// GetState retrieves a value from the account storage trie. +// GetState retrieves a value associated with the given storage key. func (s *stateObject) GetState(key common.Hash) common.Hash { value, _ := s.getState(key) return value @@ -177,7 +174,8 @@ func (s *stateObject) getState(key common.Hash) (common.Hash, common.Hash) { return origin, origin } -// GetCommittedState retrieves a value from the committed account storage trie. +// GetCommittedState retrieves the value associated with the specific key +// without any mutations caused in the current execution. func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { // If we have a pending write or clean cached, return that if value, pending := s.pendingStorage[key]; pending { @@ -193,6 +191,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { // have been handles via pendingStorage above. // 2) we don't have new values, and can deliver empty response back if _, destructed := s.db.stateObjectsDestruct[s.address]; destructed { + s.originStorage[key] = common.Hash{} // track the empty slot as origin value return common.Hash{} } // If no live objects are available, attempt to use snapshots @@ -272,17 +271,26 @@ func (s *stateObject) setState(key common.Hash, value common.Hash, origin common func (s *stateObject) finalise() { slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage)) for key, value := range s.dirtyStorage { - // If the slot is different from its original value, move it into the - // pending area to be committed at the end of the block (and prefetch - // the pathways). - if value != s.originStorage[key] { - s.pendingStorage[key] = value - slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure + if origin, exist := s.uncommittedStorage[key]; exist && origin == value { + // The slot is reverted to its original value, delete the entry + // to avoid thrashing the data structures. + delete(s.uncommittedStorage, key) + } else if exist { + // The slot is modified to another value and the slot has been + // tracked for commit, do nothing here. } else { - // Otherwise, the slot was reverted to its original value, remove it - // from the pending area to avoid thrashing the data structure. - delete(s.pendingStorage, key) + // The slot is different from its original value and hasn't been + // tracked for commit yet. + s.uncommittedStorage[key] = s.GetCommittedState(key) + slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure } + // Aggregate the dirty storage slots into the pending area. It might + // be possible that the value of tracked slot here is same with the + // one in originStorage (e.g. the slot was modified in tx_a and then + // modified back in tx_b). We can't blindly remove it from pending + // map as the dirty slot might have been committed already (before the + // byzantium fork) and entry is necessary to modify the value back. + s.pendingStorage[key] = value } if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch); err != nil { @@ -308,7 +316,7 @@ func (s *stateObject) finalise() { // It assumes all the dirty storage slots have been finalized before. func (s *stateObject) updateTrie() (Trie, error) { // Short circuit if nothing changed, don't bother with hashing anything - if len(s.pendingStorage) == 0 { + if len(s.uncommittedStorage) == 0 { return s.trie, nil } // Retrieve a pretecher populated trie, or fall back to the database @@ -325,20 +333,8 @@ func (s *stateObject) updateTrie() (Trie, error) { return nil, err } } - - // The snapshot storage map for the object - var ( - storage map[common.Hash][]byte - origin map[common.Hash][]byte - ) - // Insert all the pending storage updates into the trie - usedStorage := make([][]byte, 0, len(s.pendingStorage)) - - hasher := hasherPool.Get().(crypto.KeccakState) - defer hasherPool.Put(hasher) - - // Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes - // in circumstances similar to the following: + // Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes + // in circumstances similar to the following: // // Consider nodes `A` and `B` who share the same full node parent `P` and have no other siblings. // During the execution of a block: @@ -347,21 +343,23 @@ func (s *stateObject) updateTrie() (Trie, error) { // If the deletion is handled first, then `P` would be left with only one child, thus collapsed // into a shortnode. This requires `B` to be resolved from disk. // Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved. - var deletions []common.Hash - for key, value := range s.pendingStorage { + var ( + deletions []common.Hash + used = make([][]byte, 0, len(s.uncommittedStorage)) + ) + for key, origin := range s.uncommittedStorage { // Skip noop changes, persist actual changes - if value == s.originStorage[key] { + value, exist := s.pendingStorage[key] + if value == origin { + log.Error("Storage update was noop", "address", s.address, "slot", key) + continue + } + if !exist { + log.Error("Storage slot is not found in pending area", s.address, "slot", key) continue } - prev := s.originStorage[key] - s.originStorage[key] = value - - var encoded []byte // rlp-encoded value to be used by the snapshot if (value != common.Hash{}) { - // Encoding []byte cannot fail, ok to ignore the error. - trimmed := common.TrimLeftZeroes(value[:]) - encoded, _ = rlp.EncodeToBytes(trimmed) - if err := tr.UpdateStorage(s.address, key[:], trimmed); err != nil { + if err := tr.UpdateStorage(s.address, key[:], common.TrimLeftZeroes(value[:])); err != nil { s.db.setError(err) return nil, err } @@ -369,39 +367,8 @@ func (s *stateObject) updateTrie() (Trie, error) { } else { deletions = append(deletions, key) } - // Cache the mutated storage slots until commit - if storage == nil { - s.db.storagesLock.Lock() - if storage = s.db.storages[s.addrHash]; storage == nil { - storage = make(map[common.Hash][]byte) - s.db.storages[s.addrHash] = storage - } - s.db.storagesLock.Unlock() - } - khash := crypto.HashData(hasher, key[:]) - storage[khash] = encoded // encoded will be nil if it's deleted - - // Cache the original value of mutated storage slots - if origin == nil { - s.db.storagesLock.Lock() - if origin = s.db.storagesOrigin[s.address]; origin == nil { - origin = make(map[common.Hash][]byte) - s.db.storagesOrigin[s.address] = origin - } - s.db.storagesLock.Unlock() - } - // Track the original value of slot only if it's mutated first time - if _, ok := origin[khash]; !ok { - if prev == (common.Hash{}) { - origin[khash] = nil // nil if it was not present previously - } else { - // Encoding []byte cannot fail, ok to ignore the error. - b, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(prev[:])) - origin[khash] = b - } - } // Cache the items for preloading - usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure + used = append(used, common.CopyBytes(key[:])) // Copy needed for closure } for _, key := range deletions { if err := tr.DeleteStorage(s.address, key[:]); err != nil { @@ -410,15 +377,10 @@ func (s *stateObject) updateTrie() (Trie, error) { } s.db.StorageDeleted.Add(1) } - // If no slots were touched, issue a warning as we shouldn't have done all - // the above work in the first place - if len(usedStorage) == 0 { - log.Error("State object update was noop", "addr", s.address, "slots", len(s.pendingStorage)) - } if s.db.prefetcher != nil { - s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage) + s.db.prefetcher.used(s.addrHash, s.data.Root, used) } - s.pendingStorage = make(Storage) // reset pending map + s.uncommittedStorage = make(Storage) // empties the commit markers return tr, nil } @@ -434,30 +396,79 @@ func (s *stateObject) updateRoot() { s.data.Root = tr.Hash() } -// commit obtains a set of dirty storage trie nodes and updates the account data. -// The returned set can be nil if nothing to commit. This function assumes all -// storage mutations have already been flushed into trie by updateRoot. +// commitStorage overwrites the clean storage with the storage changes and +// fulfills the storage diffs into the given accountUpdate struct. +func (s *stateObject) commitStorage(op *accountUpdate) { + var ( + buf = crypto.NewKeccakState() + encode = func(val common.Hash) []byte { + if val == (common.Hash{}) { + return nil + } + blob, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(val[:])) + return blob + } + ) + for key, val := range s.pendingStorage { + // Skip the noop storage changes, it might be possible the value + // of tracked slot is same in originStorage and pendingStorage + // map, e.g. the storage slot is modified in tx_a and then reset + // back in tx_b. + if val == s.originStorage[key] { + continue + } + hash := crypto.HashData(buf, key[:]) + if op.storages == nil { + op.storages = make(map[common.Hash][]byte) + } + op.storages[hash] = encode(val) + if op.storagesOrigin == nil { + op.storagesOrigin = make(map[common.Hash][]byte) + } + op.storagesOrigin[hash] = encode(s.originStorage[key]) + + // Overwrite the clean value of storage slots + s.originStorage[key] = val + } + s.pendingStorage = make(Storage) +} + +// commit obtains the account changes (metadata, storage slots, code) caused by +// state execution along with the dirty storage trie nodes. // // Note, commit may run concurrently across all the state objects. Do not assume // thread-safe access to the statedb. -func (s *stateObject) commit() (*trienode.NodeSet, error) { - // Short circuit if trie is not even loaded, don't bother with committing anything - if s.trie == nil { +func (s *stateObject) commit() (*accountUpdate, *trienode.NodeSet, error) { + // commit the account metadata changes + op := &accountUpdate{ + address: s.address, + data: types.SlimAccountRLP(s.data), + } + if s.origin != nil { + op.origin = types.SlimAccountRLP(*s.origin) + } + // commit the contract code if it's modified + if s.dirtyCode { + op.code = &contractCode{ + hash: common.BytesToHash(s.CodeHash()), + blob: s.code, + } + s.dirtyCode = false // reset the dirty flag + } + // Commit storage changes and the associated storage trie + s.commitStorage(op) + if len(op.storages) == 0 { + // nothing changed, don't bother to commit the trie s.origin = s.data.Copy() - return nil, nil + return op, nil, nil } - // The trie is currently in an open state and could potentially contain - // cached mutations. Call commit to acquire a set of nodes that have been - // modified, the set can be nil if nothing to commit. root, nodes, err := s.trie.Commit(false) if err != nil { - return nil, err + return nil, nil, err } s.data.Root = root - - // Update original account data after commit s.origin = s.data.Copy() - return nodes, nil + return op, nodes, nil } // AddBalance adds amount to s's balance. @@ -500,18 +511,19 @@ func (s *stateObject) setBalance(amount *uint256.Int) { func (s *stateObject) deepCopy(db *StateDB) *stateObject { obj := &stateObject{ - db: db, - address: s.address, - addrHash: s.addrHash, - origin: s.origin, - data: s.data, - code: s.code, - originStorage: s.originStorage.Copy(), - pendingStorage: s.pendingStorage.Copy(), - dirtyStorage: s.dirtyStorage.Copy(), - dirtyCode: s.dirtyCode, - selfDestructed: s.selfDestructed, - newContract: s.newContract, + db: db, + address: s.address, + addrHash: s.addrHash, + origin: s.origin, + data: s.data, + code: s.code, + originStorage: s.originStorage.Copy(), + pendingStorage: s.pendingStorage.Copy(), + dirtyStorage: s.dirtyStorage.Copy(), + uncommittedStorage: s.uncommittedStorage.Copy(), + dirtyCode: s.dirtyCode, + selfDestructed: s.selfDestructed, + newContract: s.newContract, } if s.trie != nil { obj.trie = db.db.CopyTrie(s.trie) diff --git a/core/state/statedb.go b/core/state/statedb.go index fe262d4695df..659c500c3bf1 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -18,6 +18,7 @@ package state import ( + "errors" "fmt" "maps" "math/big" @@ -95,15 +96,6 @@ type StateDB struct { // It will be updated when the Commit is called. originalRoot common.Hash - // These maps hold the state changes (including the corresponding - // original value) that occurred in this **block**. - accounts map[common.Hash][]byte // The mutated accounts in 'slim RLP' encoding - accountsOrigin map[common.Address][]byte // The original value of mutated accounts in 'slim RLP' encoding - - storages map[common.Hash]map[common.Hash][]byte // The mutated slots in prefix-zero trimmed rlp format - storagesOrigin map[common.Address]map[common.Hash][]byte // The original value of mutated slots in prefix-zero trimmed rlp format - storagesLock sync.Mutex // Mutex protecting the maps during concurrent updates/commits - // This map holds 'live' objects, which will get modified while // processing a state transition. stateObjects map[common.Address]*stateObject @@ -171,9 +163,6 @@ type StateDB struct { StorageUpdated atomic.Int64 AccountDeleted int StorageDeleted atomic.Int64 - - // Testing hooks - onCommit func(states *triestate.Set) // Hook invoked when commit is performed } // New creates a new state from a given trie. @@ -187,10 +176,6 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) trie: tr, originalRoot: root, snaps: snaps, - accounts: make(map[common.Hash][]byte), - storages: make(map[common.Hash]map[common.Hash][]byte), - accountsOrigin: make(map[common.Address][]byte), - storagesOrigin: make(map[common.Address]map[common.Hash][]byte), stateObjects: make(map[common.Address]*stateObject), stateObjectsDestruct: make(map[common.Address]*types.StateAccount), mutations: make(map[common.Address]*mutation), @@ -380,7 +365,7 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { return common.Hash{} } -// GetState retrieves a value from the given account's storage trie. +// GetState retrieves the value associated with the specific key. func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { stateObject := s.getStateObject(addr) if stateObject != nil { @@ -389,7 +374,8 @@ func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { return common.Hash{} } -// GetCommittedState retrieves a value from the given account's committed storage trie. +// GetCommittedState retrieves the value associated with the specific key +// without any mutations caused in the current execution. func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash { stateObject := s.getStateObject(addr) if stateObject != nil { @@ -557,22 +543,6 @@ func (s *StateDB) updateStateObject(obj *stateObject) { if obj.dirtyCode { s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code) } - // Cache the data until commit. Note, this update mechanism is not symmetric - // to the deletion, because whereas it is enough to track account updates - // at commit time, deletions need tracking at transaction boundary level to - // ensure we capture state clearing. - s.accounts[obj.addrHash] = types.SlimAccountRLP(obj.data) - - // Track the original value of mutated account, nil means it was not present. - // Skip if it has been tracked (because updateStateObject may be called - // multiple times in a block). - if _, ok := s.accountsOrigin[obj.address]; !ok { - if obj.origin == nil { - s.accountsOrigin[obj.address] = nil - } else { - s.accountsOrigin[obj.address] = types.SlimAccountRLP(*obj.origin) - } - } } // deleteStateObject removes the given object from the state trie. @@ -691,10 +661,6 @@ func (s *StateDB) Copy() *StateDB { trie: s.db.CopyTrie(s.trie), hasher: crypto.NewKeccakState(), originalRoot: s.originalRoot, - accounts: copySet(s.accounts), - storages: copy2DSet(s.storages), - accountsOrigin: copySet(s.accountsOrigin), - storagesOrigin: copy2DSet(s.storagesOrigin), stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)), stateObjectsDestruct: maps.Clone(s.stateObjectsDestruct), mutations: make(map[common.Address]*mutation, len(s.mutations)), @@ -803,13 +769,6 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { if _, ok := s.stateObjectsDestruct[obj.address]; !ok { s.stateObjectsDestruct[obj.address] = obj.origin } - // Note, we can't do this only at the end of a block because multiple - // transactions within the same block might self destruct and then - // resurrect an account; but the snapshotter needs both events. - delete(s.accounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a resurrect) - delete(s.storages, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a resurrect) - delete(s.accountsOrigin, obj.address) // Clear out any previously updated account data (may be recreated via a resurrect) - delete(s.storagesOrigin, obj.address) // Clear out any previously updated storage data (may be recreated via a resurrect) } else { obj.finalise() s.markUpdate(addr) @@ -1020,10 +979,9 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r } // deleteStorage is designed to delete the storage trie of a designated account. -// It could potentially be terminated if the storage size is excessively large, -// potentially leading to an out-of-memory panic. The function will make an attempt -// to utilize an efficient strategy if the associated state snapshot is reachable; -// otherwise, it will resort to a less-efficient approach. +// The function will make an attempt to utilize an efficient strategy if the +// associated state snapshot is reachable; otherwise, it will resort to a less +// efficient approach. func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { var ( start = time.Now() @@ -1058,75 +1016,61 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root } // handleDestruction processes all destruction markers and deletes the account -// and associated storage slots if necessary. There are four possible situations -// here: -// -// - the account was not existent and be marked as destructed -// -// - the account was not existent and be marked as destructed, -// however, it's resurrected later in the same block. +// and associated storage slots if necessary. There are four potential scenarios +// as following: // -// - the account was existent and be marked as destructed -// -// - the account was existent and be marked as destructed, -// however it's resurrected later in the same block. +// (a) the account was not existent and be marked as destructed +// (b) the account was not existent and be marked as destructed, +// however, it's resurrected later in the same block. +// (c) the account was existent and be marked as destructed +// (d) the account was existent and be marked as destructed, +// however it's resurrected later in the same block. // // In case (a), nothing needs be deleted, nil to nil transition can be ignored. -// // In case (b), nothing needs be deleted, nil is used as the original value for // newly created account and storages -// // In case (c), **original** account along with its storages should be deleted, // with their values be tracked as original value. -// // In case (d), **original** account along with its storages should be deleted, // with their values be tracked as original value. -func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) error { - // Short circuit if geth is running with hash mode. This procedure can consume - // considerable time and storage deletion isn't supported in hash mode, thus - // preemptively avoiding unnecessary expenses. - if s.db.TrieDB().Scheme() == rawdb.HashScheme { - return nil - } +func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trienode.NodeSet, error) { + var ( + nodes []*trienode.NodeSet + buf = crypto.NewKeccakState() + deletes = make(map[common.Hash]*accountDelete) + ) for addr, prev := range s.stateObjectsDestruct { - // The original account was non-existing, and it's marked as destructed - // in the scope of block. It can be case (a) or (b). - // - for (a), skip it without doing anything. - // - for (b), track account's original value as nil. It may overwrite - // the data cached in s.accountsOrigin set by 'updateStateObject'. - addrHash := crypto.Keccak256Hash(addr[:]) + // The account was non-existent, and it's marked as destructed in the scope + // of block. It can be either case (a) or (b) and will be interpreted as + // null->null state transition. + // - for (a), skip it without doing anything + // - for (b), the resurrected account with nil as original will be handled afterwards if prev == nil { - if _, ok := s.accounts[addrHash]; ok { - s.accountsOrigin[addr] = nil // case (b) - } continue } - // It can overwrite the data in s.accountsOrigin set by 'updateStateObject'. - s.accountsOrigin[addr] = types.SlimAccountRLP(*prev) // case (c) or (d) + // The account was existent, it can be either case (c) or (d). + addrHash := crypto.HashData(buf, addr.Bytes()) + op := &accountDelete{ + address: addr, + origin: types.SlimAccountRLP(*prev), + } + deletes[addrHash] = op - // Short circuit if the storage was empty. + // Short circuit if the origin storage was empty. if prev.Root == types.EmptyRootHash { continue } - // Remove storage slots belong to the account. + // Remove storage slots belonging to the account. slots, set, err := s.deleteStorage(addr, addrHash, prev.Root) if err != nil { - return fmt.Errorf("failed to delete storage, err: %w", err) - } - if s.storagesOrigin[addr] == nil { - s.storagesOrigin[addr] = slots - } else { - // It can overwrite the data in s.storagesOrigin[addrHash] set by - // 'object.updateTrie'. - for key, val := range slots { - s.storagesOrigin[addr][key] = val - } - } - if err := nodes.Merge(set); err != nil { - return err + return nil, nil, fmt.Errorf("failed to delete storage, err: %w", err) } + op.storagesOrigin = slots + + // Aggregate the associated trie node changes. + nodes = append(nodes, set) } - return nil + return deletes, nodes, nil } // GetTrie returns the account trie. @@ -1134,18 +1078,12 @@ func (s *StateDB) GetTrie() Trie { return s.trie } -// Commit writes the state to the underlying in-memory trie database. -// Once the state is committed, tries cached in stateDB (including account -// trie, storage tries) will no longer be functional. A new state instance -// must be created with new root and updated database for accessing post- -// commit states. -// -// The associated block number of the state transition is also provided -// for more chain context. -func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) { +// commit gathers the state mutations accumulated along with the associated +// trie changes, resetting all internal flags with the new state as the base. +func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { // Short circuit in case any database failure occurred earlier. if s.dbErr != nil { - return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) + return nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) } // Finalize any pending changes and merge everything into the tries s.IntermediateRoot(deleteEmptyObjects) @@ -1156,19 +1094,56 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er accountTrieNodesDeleted int storageTrieNodesUpdated int storageTrieNodesDeleted int - nodes = trienode.NewMergedNodeSet() + + lock sync.Mutex // protect two maps below + nodes = trienode.NewMergedNodeSet() // aggregated trie nodes + updates = make(map[common.Hash]*accountUpdate, len(s.mutations)) // aggregated account updates + + // merge aggregates the dirty trie nodes into the global set. + // + // Given that some accounts may be destroyed and then recreated within + // the same block, it's possible that a node set with the same owner + // may already exists. In such cases, these two sets are combined, with + // the later one overwriting the previous one if any nodes are modified + // or deleted in both sets. + // + // merge run concurrently across all the state objects and account trie. + merge = func(set *trienode.NodeSet) error { + if set == nil { + return nil + } + lock.Lock() + defer lock.Unlock() + + updates, deletes := set.Size() + if set.Owner == (common.Hash{}) { + accountTrieNodesUpdated += updates + accountTrieNodesDeleted += deletes + } else { + storageTrieNodesUpdated += updates + storageTrieNodesDeleted += deletes + } + return nodes.Merge(set) + } ) - // Handle all state deletions first - if err := s.handleDestruction(nodes); err != nil { - return common.Hash{}, err + // Given that some accounts could be destroyed and then recreated within + // the same block, account deletions must be processed first. This ensures + // that the storage trie nodes deleted during destruction and recreated + // during subsequent resurrection can be combined correctly. + deletes, delNodes, err := s.handleDestruction() + if err != nil { + return nil, err + } + for _, set := range delNodes { + if err := merge(set); err != nil { + return nil, err + } } // Handle all state updates afterwards, concurrently to one another to shave // off some milliseconds from the commit operation. Also accumulate the code // writes to run in parallel with the computations. - start := time.Now() var ( - code = s.db.DiskDB().NewBatch() - lock sync.Mutex + start = time.Now() root common.Hash workers errgroup.Group ) @@ -1189,15 +1164,8 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er } root = newroot - // Merge the dirty nodes of account trie into global set - lock.Lock() - defer lock.Unlock() - - if set != nil { - if err = nodes.Merge(set); err != nil { - return err - } - accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() + if err := merge(set); err != nil { + return err } s.AccountCommits = time.Since(start) return nil @@ -1215,49 +1183,29 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er } // Write any contract code associated with the state object obj := s.stateObjects[addr] - if obj.code != nil && obj.dirtyCode { - rawdb.WriteCode(code, common.BytesToHash(obj.CodeHash()), obj.code) - obj.dirtyCode = false + if obj == nil { + return nil, errors.New("missing state object") } // Run the storage updates concurrently to one another workers.Go(func() error { // Write any storage changes in the state object to its storage trie - set, err := obj.commit() + update, set, err := obj.commit() if err != nil { return err } - // Merge the dirty nodes of storage trie into global set. It is possible - // that the account was destructed and then resurrected in the same block. - // In this case, the node set is shared by both accounts. - lock.Lock() - defer lock.Unlock() - - if set != nil { - if err = nodes.Merge(set); err != nil { - return err - } - updates, deleted := set.Size() - storageTrieNodesUpdated += updates - storageTrieNodesDeleted += deleted + if err := merge(set); err != nil { + return err } + lock.Lock() + updates[obj.addrHash] = update + lock.Unlock() s.StorageCommits = time.Since(start) // overwrite with the longest storage commit runtime return nil }) } - // Schedule the code commits to run concurrently too. This shouldn't really - // take much since we don't often commit code, but since it's disk access, - // it's always yolo. - workers.Go(func() error { - if code.ValueSize() > 0 { - if err := code.Write(); err != nil { - log.Crit("Failed to commit dirty codes", "error", err) - } - } - return nil - }) // Wait for everything to finish and update the metrics if err := workers.Wait(); err != nil { - return common.Hash{}, err + return nil, err } accountUpdatedMeter.Mark(int64(s.AccountUpdated)) storageUpdatedMeter.Mark(s.StorageUpdated.Load()) @@ -1271,53 +1219,78 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er s.StorageUpdated.Store(0) s.StorageDeleted.Store(0) - // If snapshotting is enabled, update the snapshot tree with this new version - if s.snap != nil { - start = time.Now() - // Only update if there's a state transition (skip empty Clique blocks) - if parent := s.snap.Root(); parent != root { - if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil { - log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) + // Clear all internal flags and update state root at the end. + s.mutations = make(map[common.Address]*mutation) + s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) + + origin := s.originalRoot + s.originalRoot = root + return newStateUpdate(origin, root, deletes, updates, nodes), nil +} + +// commitAndFlush is a wrapper of commit which also commits the state mutations +// to the configured data stores. +func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateUpdate, error) { + ret, err := s.commit(deleteEmptyObjects) + if err != nil { + return nil, err + } + // Commit dirty contract code if any exists + if db := s.db.DiskDB(); db != nil && len(ret.codes) > 0 { + batch := db.NewBatch() + for _, code := range ret.codes { + rawdb.WriteCode(batch, code.hash, code.blob) + } + if err := batch.Write(); err != nil { + return nil, err + } + } + if !ret.empty() { + // If snapshotting is enabled, update the snapshot tree with this new version + if s.snap != nil { + s.snap = nil + + start := time.Now() + if err := s.snaps.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil { + log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err) } - // Keep TriesInMemory diff layers in the memory, persistent layer is 129th. + // Keep 128 diff layers in the memory, persistent layer is 129th. // - head layer is paired with HEAD state // - head-1 layer is paired with HEAD-1 state // - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state - if err := s.snaps.Cap(root, TriesInMemory); err != nil { - log.Warn("Failed to cap snapshot tree", "root", root, "layers", TriesInMemory, "err", err) + if err := s.snaps.Cap(ret.root, TriesInMemory); err != nil { + log.Warn("Failed to cap snapshot tree", "root", ret.root, "layers", TriesInMemory, "err", err) } + s.SnapshotCommits += time.Since(start) } - s.SnapshotCommits += time.Since(start) - s.snap = nil - } - if root == (common.Hash{}) { - root = types.EmptyRootHash - } - origin := s.originalRoot - if origin == (common.Hash{}) { - origin = types.EmptyRootHash - } - if root != origin { - start = time.Now() - set := triestate.New(s.accountsOrigin, s.storagesOrigin) - if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil { - return common.Hash{}, err + // If trie database is enabled, commit the state update as a new layer + if db := s.db.TrieDB(); db != nil { + start := time.Now() + set := triestate.New(ret.accountsOrigin, ret.storagesOrigin) + if err := db.Update(ret.root, ret.originRoot, block, ret.nodes, set); err != nil { + return nil, err + } + s.TrieDBCommits += time.Since(start) } - s.originalRoot = root - s.TrieDBCommits += time.Since(start) + } + return ret, err +} - if s.onCommit != nil { - s.onCommit(set) - } +// Commit writes the state mutations into the configured data stores. +// +// Once the state is committed, tries cached in stateDB (including account +// trie, storage tries) will no longer be functional. A new state instance +// must be created with new root and updated database for accessing post- +// commit states. +// +// The associated block number of the state transition is also provided +// for more chain context. +func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) { + ret, err := s.commitAndFlush(block, deleteEmptyObjects) + if err != nil { + return common.Hash{}, err } - // Clear all internal flags at the end of commit operation. - s.accounts = make(map[common.Hash][]byte) - s.storages = make(map[common.Hash]map[common.Hash][]byte) - s.accountsOrigin = make(map[common.Address][]byte) - s.storagesOrigin = make(map[common.Address]map[common.Hash][]byte) - s.mutations = make(map[common.Address]*mutation) - s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) - return root, nil + return ret.root, nil } // Prepare handles the preparatory steps for executing a state transition with. @@ -1399,41 +1372,9 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre return s.accessList.Contains(addr, slot) } -// convertAccountSet converts a provided account set from address keyed to hash keyed. -func (s *StateDB) convertAccountSet(set map[common.Address]*types.StateAccount) map[common.Hash]struct{} { - ret := make(map[common.Hash]struct{}, len(set)) - for addr := range set { - obj, exist := s.stateObjects[addr] - if !exist { - ret[crypto.Keccak256Hash(addr[:])] = struct{}{} - } else { - ret[obj.addrHash] = struct{}{} - } - } - return ret -} - -// copySet returns a deep-copied set. -func copySet[k comparable](set map[k][]byte) map[k][]byte { - copied := make(map[k][]byte, len(set)) - for key, val := range set { - copied[key] = common.CopyBytes(val) - } - return copied -} - -// copy2DSet returns a two-dimensional deep-copied set. -func copy2DSet[k comparable](set map[k]map[common.Hash][]byte) map[k]map[common.Hash][]byte { - copied := make(map[k]map[common.Hash][]byte, len(set)) - for addr, subset := range set { - copied[addr] = make(map[common.Hash][]byte, len(subset)) - for key, val := range subset { - copied[addr][key] = common.CopyBytes(val) - } - } - return copied -} - +// markDelete is invoked when an account is deleted but the deletion is +// not yet committed. The pending mutation is cached and will be applied +// all together func (s *StateDB) markDelete(addr common.Address) { if _, ok := s.mutations[addr]; !ok { s.mutations[addr] = &mutation{} diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 6317681a7fba..40b079cd8a43 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -36,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/pathdb" "github.com/holiman/uint256" @@ -180,9 +179,21 @@ func (test *stateTest) run() bool { roots []common.Hash accountList []map[common.Address][]byte storageList []map[common.Address]map[common.Hash][]byte - onCommit = func(states *triestate.Set) { - accountList = append(accountList, copySet(states.Accounts)) - storageList = append(storageList, copy2DSet(states.Storages)) + copyUpdate = func(update *stateUpdate) { + accounts := make(map[common.Address][]byte, len(update.accountsOrigin)) + for key, val := range update.accountsOrigin { + accounts[key] = common.CopyBytes(val) + } + accountList = append(accountList, accounts) + + storages := make(map[common.Address]map[common.Hash][]byte, len(update.storagesOrigin)) + for addr, subset := range update.storagesOrigin { + storages[addr] = make(map[common.Hash][]byte, len(subset)) + for key, val := range subset { + storages[addr][key] = common.CopyBytes(val) + } + } + storageList = append(storageList, storages) } disk = rawdb.NewMemoryDatabase() tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults}) @@ -210,8 +221,6 @@ func (test *stateTest) run() bool { if err != nil { panic(err) } - state.onCommit = onCommit - for i, action := range actions { if i%test.chunk == 0 && i != 0 { if byzantium { @@ -227,14 +236,15 @@ func (test *stateTest) run() bool { } else { state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary } - nroot, err := state.Commit(0, true) // call commit at the block boundary + ret, err := state.commitAndFlush(0, true) // call commit at the block boundary if err != nil { panic(err) } - if nroot == root { - return true // filter out non-change state transition + if ret.empty() { + return true } - roots = append(roots, nroot) + copyUpdate(ret) + roots = append(roots, ret.root) } for i := 0; i < len(test.actions); i++ { root := types.EmptyRootHash diff --git a/core/state/stateupdate.go b/core/state/stateupdate.go new file mode 100644 index 000000000000..f3e6af997e44 --- /dev/null +++ b/core/state/stateupdate.go @@ -0,0 +1,133 @@ +// Copyright 2024 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 ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/trie/trienode" +) + +// contractCode represents a contract code with associated metadata. +type contractCode struct { + hash common.Hash // hash is the cryptographic hash of the contract code. + blob []byte // blob is the binary representation of the contract code. +} + +// accountDelete represents an operation for deleting an Ethereum account. +type accountDelete struct { + address common.Address // address is the unique account identifier + origin []byte // origin is the original value of account data in slim-RLP encoding. + storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format. +} + +// accountUpdate represents an operation for updating an Ethereum account. +type accountUpdate struct { + address common.Address // address is the unique account identifier + data []byte // data is the slim-RLP encoded account data. + origin []byte // origin is the original value of account data in slim-RLP encoding. + code *contractCode // code represents mutated contract code; nil means it's not modified. + storages map[common.Hash][]byte // storages stores mutated slots in prefix-zero-trimmed RLP format. + storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format. +} + +// stateUpdate represents the difference between two states resulting from state +// execution. It contains information about mutated contract codes, accounts, +// and storage slots, along with their original values. +type stateUpdate struct { + originRoot common.Hash // hash of the state before applying mutation + root common.Hash // hash of the state after applying mutation + destructs map[common.Hash]struct{} // destructs contains the list of destructed accounts + accounts map[common.Hash][]byte // accounts stores mutated accounts in 'slim RLP' encoding + accountsOrigin map[common.Address][]byte // accountsOrigin stores the original values of mutated accounts in 'slim RLP' encoding + storages map[common.Hash]map[common.Hash][]byte // storages stores mutated slots in 'prefix-zero-trimmed' RLP format + storagesOrigin map[common.Address]map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in 'prefix-zero-trimmed' RLP format + codes map[common.Address]contractCode // codes contains the set of dirty codes + nodes *trienode.MergedNodeSet // Aggregated dirty nodes caused by state changes +} + +// empty returns a flag indicating the state transition is empty or not. +func (sc *stateUpdate) empty() bool { + return sc.originRoot == sc.root +} + +// newStateUpdate constructs a state update object, representing the differences +// between two states by performing state execution. It aggregates the given +// account deletions and account updates to form a comprehensive state update. +func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common.Hash]*accountDelete, updates map[common.Hash]*accountUpdate, nodes *trienode.MergedNodeSet) *stateUpdate { + var ( + destructs = make(map[common.Hash]struct{}) + accounts = make(map[common.Hash][]byte) + accountsOrigin = make(map[common.Address][]byte) + storages = make(map[common.Hash]map[common.Hash][]byte) + storagesOrigin = make(map[common.Address]map[common.Hash][]byte) + codes = make(map[common.Address]contractCode) + ) + // Due to the fact that some accounts could be destructed and resurrected + // within the same block, the deletions must be aggregated first. + for addrHash, op := range deletes { + addr := op.address + destructs[addrHash] = struct{}{} + accountsOrigin[addr] = op.origin + if len(op.storagesOrigin) > 0 { + storagesOrigin[addr] = op.storagesOrigin + } + } + // Aggregate account updates then. + for addrHash, op := range updates { + // Aggregate dirty contract codes if they are available. + addr := op.address + if op.code != nil { + codes[addr] = *op.code + } + // Aggregate the account changes. The original account value will only + // be tracked if it's not present yet. + accounts[addrHash] = op.data + if _, found := accountsOrigin[addr]; !found { + accountsOrigin[addr] = op.origin + } + // Aggregate the storage changes. The original storage slot value will + // only be tracked if it's not present yet. + if len(op.storages) > 0 { + storages[addrHash] = op.storages + } + if len(op.storagesOrigin) > 0 { + origin := storagesOrigin[addr] + if origin == nil { + storagesOrigin[addr] = op.storagesOrigin + continue + } + for key, slot := range op.storagesOrigin { + if _, found := origin[key]; !found { + origin[key] = slot + } + } + storagesOrigin[addr] = origin + } + } + return &stateUpdate{ + originRoot: types.TrieRootHash(originRoot), + root: types.TrieRootHash(root), + destructs: destructs, + accounts: accounts, + accountsOrigin: accountsOrigin, + storages: storages, + storagesOrigin: storagesOrigin, + codes: codes, + nodes: nodes, + } +} From 50405e29b73140f80cf2008be7827752a430a199 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:31:23 +0800 Subject: [PATCH 323/571] cmd/evm/internal/t8ntool: fix a typo (#29887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * i8ntool: fix a typo * cmd/evm/internal/t8ntool: fix typo typo --------- Co-authored-by: Péter Szilágyi --- cmd/evm/internal/t8ntool/transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 9ea94d195e82..8fd068b2ea14 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -217,7 +217,7 @@ func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error { return nil } if env.ParentBaseFee == nil || env.Number == 0 { - return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) + return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'parentBaseFee' in env section")) } env.BaseFee = eip1559.CalcBaseFee(chainConfig, &types.Header{ Number: new(big.Int).SetUint64(env.Number - 1), From b36c73813c6101c2cd5dfa227dc8e40b417e23ba Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 3 Jun 2024 19:38:08 +0700 Subject: [PATCH 324/571] beacon/engine: prealloc capacity for map and slice (#29903) * prealloc capacity for map and slice * revert unnecessary change --- beacon/engine/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index a73691ca0576..1dfcf5b71a0e 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -209,7 +209,7 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) { return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas) } - var blobHashes []common.Hash + var blobHashes = make([]common.Hash, 0, len(txs)) for _, tx := range txs { blobHashes = append(blobHashes, tx.BlobHashes()...) } From 7270cba25c71d72447a535d0aafcd39892cf8112 Mon Sep 17 00:00:00 2001 From: miles <66052478+miles-six@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:50:24 +0800 Subject: [PATCH 325/571] log: fix a typo (#29883) logger --- log/logger_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log/logger_test.go b/log/logger_test.go index 6f415eb471d2..f1a9a93bce7a 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -26,7 +26,7 @@ func TestLoggingWithVmodule(t *testing.T) { logger.Trace("a message", "foo", "bar") have := out.String() // The timestamp is locale-dependent, so we want to trim that off - // "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..." + // "INFO [01-01|00:00:00.000] a message ..." -> "a message..." have = strings.Split(have, "]")[1] want := " a message foo=bar\n" if have != want { @@ -42,7 +42,7 @@ func TestTerminalHandlerWithAttrs(t *testing.T) { logger.Trace("a message", "foo", "bar") have := out.String() // The timestamp is locale-dependent, so we want to trim that off - // "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..." + // "INFO [01-01|00:00:00.000] a message ..." -> "a message..." have = strings.Split(have, "]")[1] want := " a message baz=bat foo=bar\n" if have != want { From a6751d6fc830b9a1edc963df2c05908f4392e39c Mon Sep 17 00:00:00 2001 From: tianyeyouyou <150894831+tianyeyouyou@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:51:04 +0800 Subject: [PATCH 326/571] core/rawdb,eth/protocols,p2p: prealloc slice size (#29893) chore: prealloc slice size --- eth/protocols/snap/sync.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 53cba5d11528..88d7d34dcc66 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -3250,9 +3250,9 @@ func (t *healRequestSort) Merge() []TrieNodePathSet { // sortByAccountPath takes hashes and paths, and sorts them. After that, it generates // the TrieNodePaths and merges paths which belongs to the same account path. func sortByAccountPath(paths []string, hashes []common.Hash) ([]string, []common.Hash, []trie.SyncPath, []TrieNodePathSet) { - var syncPaths []trie.SyncPath - for _, path := range paths { - syncPaths = append(syncPaths, trie.NewSyncPath([]byte(path))) + syncPaths := make([]trie.SyncPath, len(paths)) + for i, path := range paths { + syncPaths[i] = trie.NewSyncPath([]byte(path)) } n := &healRequestSort{paths, hashes, syncPaths} sort.Sort(n) From adbbd8cd7b3c0d3e5a8475c3e3557f11ca38a3d1 Mon Sep 17 00:00:00 2001 From: Steven Wang <915337710@qq.com> Date: Tue, 4 Jun 2024 11:12:24 +0800 Subject: [PATCH 327/571] core/state: prefetch account trie while starting a prefetcher (#29919) Always prefetch the account trie while starting the prefetcher. Co-authored-by: steven Co-authored-by: rjl493456442 --- core/state/statedb.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/state/statedb.go b/core/state/statedb.go index 659c500c3bf1..bb2a87b17294 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -208,6 +208,19 @@ func (s *StateDB) StartPrefetcher(namespace string) { } if s.snap != nil { s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace) + + // With the switch to the Proof-of-Stake consensus algorithm, block production + // rewards are now handled at the consensus layer. Consequently, a block may + // have no state transitions if it contains no transactions and no withdrawals. + // In such cases, the account trie won't be scheduled for prefetching, leading + // to unnecessary error logs. + // + // To prevent this, the account trie is always scheduled for prefetching once + // the prefetcher is constructed. For more details, see: + // https://github.com/ethereum/go-ethereum/issues/29880 + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil); err != nil { + log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err) + } } } From 68c0ec08158c2e61a40baa4489fd4377f6d1a223 Mon Sep 17 00:00:00 2001 From: Roy Crihfield Date: Tue, 4 Jun 2024 11:17:26 +0800 Subject: [PATCH 328/571] trie: iterate values pre-order and fix seek behavior (#27838) This pull request fixes the pre-order trie traversal by defining a more accurate iterator order and path comparison rule. Co-authored-by: Gary Rong --- trie/iterator.go | 81 ++++++++++++++++++++++++++++++++++--------- trie/iterator_test.go | 18 ++++++---- 2 files changed, 76 insertions(+), 23 deletions(-) diff --git a/trie/iterator.go b/trie/iterator.go index 83ccc0740f3a..fa016110636a 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -135,7 +135,7 @@ type nodeIteratorState struct { node node // Trie node being iterated parent common.Hash // Hash of the first full ancestor node (nil if current is the root) index int // Child to be processed next - pathlen int // Length of the path to this node + pathlen int // Length of the path to the parent node } type nodeIterator struct { @@ -145,7 +145,7 @@ type nodeIterator struct { err error // Failure set in case of an internal error in the iterator resolver NodeResolver // optional node resolver for avoiding disk hits - pool []*nodeIteratorState // local pool for iteratorstates + pool []*nodeIteratorState // local pool for iterator states } // errIteratorEnd is stored in nodeIterator.err when iteration is done. @@ -304,6 +304,7 @@ func (it *nodeIterator) seek(prefix []byte) error { // The path we're looking for is the hex encoded key without terminator. key := keybytesToHex(prefix) key = key[:len(key)-1] + // Move forward until we're just before the closest match to key. for { state, parentIndex, path, err := it.peekSeek(key) @@ -311,7 +312,7 @@ func (it *nodeIterator) seek(prefix []byte) error { return errIteratorEnd } else if err != nil { return seekError{prefix, err} - } else if bytes.Compare(path, key) >= 0 { + } else if reachedPath(path, key) { return nil } it.push(state, parentIndex, path) @@ -339,7 +340,6 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er // If we're skipping children, pop the current node first it.pop() } - // Continue iteration to the next child for len(it.stack) > 0 { parent := it.stack[len(it.stack)-1] @@ -372,7 +372,6 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by // If we're skipping children, pop the current node first it.pop() } - // Continue iteration to the next child for len(it.stack) > 0 { parent := it.stack[len(it.stack)-1] @@ -449,16 +448,18 @@ func (it *nodeIterator) findChild(n *fullNode, index int, ancestor common.Hash) state *nodeIteratorState childPath []byte ) - for ; index < len(n.Children); index++ { + for ; index < len(n.Children); index = nextChildIndex(index) { if n.Children[index] != nil { child = n.Children[index] hash, _ := child.cache() + state = it.getFromPool() state.hash = common.BytesToHash(hash) state.node = child state.parent = ancestor state.index = -1 state.pathlen = len(path) + childPath = append(childPath, path...) childPath = append(childPath, byte(index)) return child, state, childPath, index @@ -471,8 +472,8 @@ func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Has switch node := parent.node.(type) { case *fullNode: // Full node, move to the first non-nil child. - if child, state, path, index := it.findChild(node, parent.index+1, ancestor); child != nil { - parent.index = index - 1 + if child, state, path, index := it.findChild(node, nextChildIndex(parent.index), ancestor); child != nil { + parent.index = prevChildIndex(index) return state, path, true } case *shortNode: @@ -498,23 +499,23 @@ func (it *nodeIterator) nextChildAt(parent *nodeIteratorState, ancestor common.H switch n := parent.node.(type) { case *fullNode: // Full node, move to the first non-nil child before the desired key position - child, state, path, index := it.findChild(n, parent.index+1, ancestor) + child, state, path, index := it.findChild(n, nextChildIndex(parent.index), ancestor) if child == nil { // No more children in this fullnode return parent, it.path, false } // If the child we found is already past the seek position, just return it. - if bytes.Compare(path, key) >= 0 { - parent.index = index - 1 + if reachedPath(path, key) { + parent.index = prevChildIndex(index) return state, path, true } // The child is before the seek position. Try advancing for { - nextChild, nextState, nextPath, nextIndex := it.findChild(n, index+1, ancestor) + nextChild, nextState, nextPath, nextIndex := it.findChild(n, nextChildIndex(index), ancestor) // If we run out of children, or skipped past the target, return the // previous one - if nextChild == nil || bytes.Compare(nextPath, key) >= 0 { - parent.index = index - 1 + if nextChild == nil || reachedPath(nextPath, key) { + parent.index = prevChildIndex(index) return state, path, true } // We found a better child closer to the target @@ -541,7 +542,7 @@ func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path [] it.path = path it.stack = append(it.stack, state) if parentIndex != nil { - *parentIndex++ + *parentIndex = nextChildIndex(*parentIndex) } } @@ -550,8 +551,54 @@ func (it *nodeIterator) pop() { it.path = it.path[:last.pathlen] it.stack[len(it.stack)-1] = nil it.stack = it.stack[:len(it.stack)-1] - // last is now unused - it.putInPool(last) + + it.putInPool(last) // last is now unused +} + +// reachedPath normalizes a path by truncating a terminator if present, and +// returns true if it is greater than or equal to the target. Using this, +// the path of a value node embedded a full node will compare less than the +// full node's children. +func reachedPath(path, target []byte) bool { + if hasTerm(path) { + path = path[:len(path)-1] + } + return bytes.Compare(path, target) >= 0 +} + +// A value embedded in a full node occupies the last slot (16) of the array of +// children. In order to produce a pre-order traversal when iterating children, +// we jump to this last slot first, then go back iterate the child nodes (and +// skip the last slot at the end): + +// prevChildIndex returns the index of a child in a full node which precedes +// the given index when performing a pre-order traversal. +func prevChildIndex(index int) int { + switch index { + case 0: // We jumped back to iterate the children, from the value slot + return 16 + case 16: // We jumped to the embedded value slot at the end, from the placeholder index + return -1 + case 17: // We skipped the value slot after iterating all the children + return 15 + default: // We are iterating the children in sequence + return index - 1 + } +} + +// nextChildIndex returns the index of a child in a full node which follows +// the given index when performing a pre-order traversal. +func nextChildIndex(index int) int { + switch index { + case -1: // Jump from the placeholder index to the embedded value slot + return 16 + case 15: // Skip the value slot after iterating the children + return 17 + case 16: // From the embedded value slot, jump back to iterate the children + return 0 + default: // Iterate children in sequence + return index + 1 + } } func compareNodes(a, b NodeIterator) int { diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 41e83f6cb69e..a8f3c4413ea7 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -182,14 +182,14 @@ func testNodeIteratorCoverage(t *testing.T, scheme string) { type kvs struct{ k, v string } var testdata1 = []kvs{ + {"bar", "b"}, {"barb", "ba"}, {"bard", "bc"}, {"bars", "bb"}, - {"bar", "b"}, {"fab", "z"}, + {"foo", "a"}, {"food", "ab"}, {"foos", "aa"}, - {"foo", "a"}, } var testdata2 = []kvs{ @@ -218,7 +218,7 @@ func TestIteratorSeek(t *testing.T) { // Seek to a non-existent key. it = NewIterator(trie.MustNodeIterator([]byte("barc"))) - if err := checkIteratorOrder(testdata1[1:], it); err != nil { + if err := checkIteratorOrder(testdata1[2:], it); err != nil { t.Fatal(err) } @@ -227,6 +227,12 @@ func TestIteratorSeek(t *testing.T) { if err := checkIteratorOrder(nil, it); err != nil { t.Fatal(err) } + + // Seek to a key for which a prefixing key exists. + it = NewIterator(trie.MustNodeIterator([]byte("food"))) + if err := checkIteratorOrder(testdata1[6:], it); err != nil { + t.Fatal(err) + } } func checkIteratorOrder(want []kvs, it *Iterator) error { @@ -311,16 +317,16 @@ func TestUnionIterator(t *testing.T) { all := []struct{ k, v string }{ {"aardvark", "c"}, + {"bar", "b"}, {"barb", "ba"}, {"barb", "bd"}, {"bard", "bc"}, {"bars", "bb"}, {"bars", "be"}, - {"bar", "b"}, {"fab", "z"}, + {"foo", "a"}, {"food", "ab"}, {"foos", "aa"}, - {"foo", "a"}, {"jars", "d"}, } @@ -512,7 +518,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme strin rawdb.WriteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, barNodeBlob, triedb.Scheme()) } // Check that iteration produces the right set of values. - if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil { + if err := checkIteratorOrder(testdata1[3:], NewIterator(it)); err != nil { t.Fatal(err) } } From 682ae838b2312a4ec8e5581069039b567e33c7c2 Mon Sep 17 00:00:00 2001 From: SangIlMo <156392700+SangIlMo@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:59:41 +0900 Subject: [PATCH 329/571] internal/ethapi: recap higher args.Gas with block GasLimit in DoEstimateGas (#29738) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * internal/ethapi: recap higher args.Gas with block GasLimit in DoEstimateGas * internal/ethapi: fix gas estimator capping code * internal/ethapi: fix test * fix goimports lint (remove space) --------- Co-authored-by: Péter Szilágyi --- internal/ethapi/api.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 8866a5b8706d..f211dcc6598b 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1199,10 +1199,16 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr State: state, ErrorRatio: estimateGasErrorRatio, } + // Set any required transaction default, but make sure the gas cap itself is not messed with + // if it was not specified in the original argument list. + if args.Gas == nil { + args.Gas = new(hexutil.Uint64) + } if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil { return 0, err } call := args.ToMessage(header.BaseFee) + // Run the gas estimation and wrap any revertals into a custom return estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) if err != nil { From 125fb1ff5855134b040e295f380eeecff29af375 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 4 Jun 2024 20:51:34 +0800 Subject: [PATCH 330/571] core/state: avoid data race (#29924) --- core/state/statedb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index bb2a87b17294..61e76cdd7788 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1211,8 +1211,8 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { } lock.Lock() updates[obj.addrHash] = update - lock.Unlock() s.StorageCommits = time.Since(start) // overwrite with the longest storage commit runtime + lock.Unlock() return nil }) } From 5550d8399f744aca0f50fc20bcd57bf2abeb13e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 5 Jun 2024 11:06:37 +0300 Subject: [PATCH 331/571] params: release Geth v1.14.4 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index a0e2de5a4941..62140f05c76e 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 4 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 4 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From fc40d68e5bd6ffb1651a75f985114de5eabd4e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 5 Jun 2024 11:20:35 +0300 Subject: [PATCH 332/571] params: begin v1.14.5 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 62140f05c76e..5ae1187b82d5 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 4 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 5 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From e85e21c93267f619c8ce75c0457f4ed52cd9bbf0 Mon Sep 17 00:00:00 2001 From: Hteev Oli Date: Wed, 5 Jun 2024 17:07:37 +0800 Subject: [PATCH 333/571] core/state, eth/tracers: fix typos (#29932) --- core/state/trie_prefetcher.go | 2 +- eth/tracers/internal/tracetest/supply_test.go | 2 +- eth/tracers/live/supply.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index ce94ab51396c..5e5afbbeccfe 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -82,7 +82,7 @@ func (p *triePrefetcher) terminate(async bool) { return default: } - // Termiante all sub-fetchers, sync or async, depending on the request + // Terminate all sub-fetchers, sync or async, depending on the request for _, fetcher := range p.fetchers { fetcher.terminate(async) } diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 2d4f1b089006..d608b1e002af 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -398,7 +398,7 @@ func TestSupplySelfdestruct(t *testing.T) { } // Tests selfdestructing contract to send its balance to itself (burn). -// It tests both cases of selfdestructing succeding and being reverted. +// It tests both cases of selfdestructing succeeding and being reverted. // - Contract A calls B and D. // - Contract B selfdestructs and sends the eth1 to itself (Burn amount to be counted). // - Contract C selfdestructs and sends the eth1 to itself. diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go index 0c9141e99d9f..936ffb94724c 100644 --- a/eth/tracers/live/supply.go +++ b/eth/tracers/live/supply.go @@ -205,7 +205,7 @@ func (s *supply) internalTxsHandler(call *supplyTxCallstack) { } if len(call.calls) > 0 { - // Recursivelly handle internal calls + // Recursively handle internal calls for _, call := range call.calls { callCopy := call s.internalTxsHandler(&callCopy) From d09ddac39950645b95eae94894c322fc19f23acb Mon Sep 17 00:00:00 2001 From: Marquis Shanahan <29431502+9547@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:05:00 +0800 Subject: [PATCH 334/571] core/rawdb: remove unused deriveLogFields (#29913) Co-authored-by: Gary Rong Co-authored-by: Martin HS --- core/rawdb/accessors_chain.go | 22 ---------------------- core/rawdb/accessors_chain_test.go | 6 ++---- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 025be7ade7f4..c4735c850c02 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -19,7 +19,6 @@ package rawdb import ( "bytes" "encoding/binary" - "errors" "fmt" "math/big" "slices" @@ -695,27 +694,6 @@ func (r *receiptLogs) DecodeRLP(s *rlp.Stream) error { return nil } -// deriveLogFields fills the logs in receiptLogs with information such as block number, txhash, etc. -func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, txs types.Transactions) error { - logIndex := uint(0) - if len(txs) != len(receipts) { - return errors.New("transaction and receipt count mismatch") - } - for i := 0; i < len(receipts); i++ { - txHash := txs[i].Hash() - // The derived log fields can simply be set from the block and transaction - for j := 0; j < len(receipts[i].Logs); j++ { - receipts[i].Logs[j].BlockNumber = number - receipts[i].Logs[j].BlockHash = hash - receipts[i].Logs[j].TxHash = txHash - receipts[i].Logs[j].TxIndex = uint(i) - receipts[i].Logs[j].Index = logIndex - logIndex++ - } - } - return nil -} - // ReadLogs retrieves the logs for all transactions in a block. In case // receipts is not found, a nil is returned. // Note: ReadLogs does not derive unstored log fields. diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index fdc940b57e66..2d30af4b3d20 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -794,7 +794,7 @@ func TestDeriveLogFields(t *testing.T) { }), } // Create the corresponding receipts - receipts := []*receiptLogs{ + receipts := []*types.Receipt{ { Logs: []*types.Log{ {Address: common.BytesToAddress([]byte{0x11})}, @@ -818,9 +818,7 @@ func TestDeriveLogFields(t *testing.T) { // Derive log metadata fields number := big.NewInt(1) hash := common.BytesToHash([]byte{0x03, 0x14}) - if err := deriveLogFields(receipts, hash, number.Uint64(), txs); err != nil { - t.Fatal(err) - } + types.Receipts(receipts).DeriveFields(params.TestChainConfig, hash, number.Uint64(), 0, big.NewInt(0), big.NewInt(0), txs) // Iterate over all the computed fields and check that they're correct logIndex := uint(0) From bc6569462dfd78394599c93fd9e2a21908aca662 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 5 Jun 2024 19:31:04 +0200 Subject: [PATCH 335/571] p2p: use netip.Addr where possible (#29891) enode.Node was recently changed to store a cache of endpoint information. The IP address in the cache is a netip.Addr. I chose that type over net.IP because it is just better. netip.Addr is meant to be used as a value type. Copying it does not allocate, it can be compared with ==, and can be used as a map key. This PR changes most uses of Node.IP() into Node.IPAddr(), which returns the cached value directly without allocating. While there are still some public APIs left where net.IP is used, I have converted all code used internally by p2p/discover to the new types. So this does change some public Go API, but hopefully not APIs any external code actually uses. There weren't supposed to be any semantic differences resulting from this refactoring, however it does introduce one: In package p2p/netutil we treated the 0.0.0.0/8 network (addresses 0.x.y.z) as LAN, but netip.Addr.IsPrivate() doesn't. The treatment of this particular IP address range is controversial, with some software supporting it and others not. IANA lists it as special-purpose and invalid as a destination for a long time, so I don't know why I put it into the LAN list. It has now been marked as special in p2p/netutil as well. --- cmd/devp2p/internal/ethtest/conn.go | 3 +- cmd/devp2p/internal/v4test/framework.go | 6 +- cmd/devp2p/nodesetcmd.go | 6 +- cmd/devp2p/rlpxcmd.go | 6 +- p2p/dial.go | 27 ++-- p2p/discover/table.go | 52 ++++---- p2p/discover/table_test.go | 14 +-- p2p/discover/table_util_test.go | 5 +- p2p/discover/v4_udp.go | 33 ++--- p2p/discover/v4_udp_test.go | 8 +- p2p/discover/v5_udp.go | 12 +- p2p/discover/v5wire/encoding_test.go | 2 +- p2p/enode/localnode.go | 42 ++----- p2p/enode/localnode_test.go | 16 ++- p2p/enode/nodedb.go | 62 +++++---- p2p/enode/nodedb_test.go | 35 +++--- p2p/netutil/addrutil.go | 49 ++++++-- p2p/netutil/iptrack.go | 24 ++-- p2p/netutil/iptrack_test.go | 59 +++++---- p2p/netutil/net.go | 160 +++++++++++++----------- p2p/netutil/net_test.go | 64 +++++++--- p2p/server.go | 15 +-- p2p/server_nat_test.go | 5 +- 23 files changed, 392 insertions(+), 313 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/conn.go b/cmd/devp2p/internal/ethtest/conn.go index ba3c0585fde9..757b137aa12d 100644 --- a/cmd/devp2p/internal/ethtest/conn.go +++ b/cmd/devp2p/internal/ethtest/conn.go @@ -53,7 +53,8 @@ func (s *Suite) dial() (*Conn, error) { // dialAs attempts to dial a given node and perform a handshake using the given // private key. func (s *Suite) dialAs(key *ecdsa.PrivateKey) (*Conn, error) { - fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", s.Dest.IP(), s.Dest.TCP())) + tcpEndpoint, _ := s.Dest.TCPEndpoint() + fd, err := net.Dial("tcp", tcpEndpoint.String()) if err != nil { return nil, err } diff --git a/cmd/devp2p/internal/v4test/framework.go b/cmd/devp2p/internal/v4test/framework.go index df1f1f8abaca..958fb711798f 100644 --- a/cmd/devp2p/internal/v4test/framework.go +++ b/cmd/devp2p/internal/v4test/framework.go @@ -53,10 +53,12 @@ func newTestEnv(remote string, listen1, listen2 string) *testenv { if err != nil { panic(err) } - if node.IP() == nil || node.UDP() == 0 { + if !node.IPAddr().IsValid() || node.UDP() == 0 { var ip net.IP var tcpPort, udpPort int - if ip = node.IP(); ip == nil { + if node.IPAddr().IsValid() { + ip = node.IPAddr().AsSlice() + } else { ip = net.ParseIP("127.0.0.1") } if tcpPort = node.TCP(); tcpPort == 0 { diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go index 6fbc185ad8ad..f0773edfb81f 100644 --- a/cmd/devp2p/nodesetcmd.go +++ b/cmd/devp2p/nodesetcmd.go @@ -19,7 +19,7 @@ package main import ( "errors" "fmt" - "net" + "net/netip" "sort" "strconv" "strings" @@ -205,11 +205,11 @@ func trueFilter(args []string) (nodeFilter, error) { } func ipFilter(args []string) (nodeFilter, error) { - _, cidr, err := net.ParseCIDR(args[0]) + prefix, err := netip.ParsePrefix(args[0]) if err != nil { return nil, err } - f := func(n nodeJSON) bool { return cidr.Contains(n.N.IP()) } + f := func(n nodeJSON) bool { return prefix.Contains(n.N.IPAddr()) } return f, nil } diff --git a/cmd/devp2p/rlpxcmd.go b/cmd/devp2p/rlpxcmd.go index aa7d065818d9..fb8066ee1a1d 100644 --- a/cmd/devp2p/rlpxcmd.go +++ b/cmd/devp2p/rlpxcmd.go @@ -77,7 +77,11 @@ var ( func rlpxPing(ctx *cli.Context) error { n := getNodeArg(ctx) - fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", n.IP(), n.TCP())) + tcpEndpoint, ok := n.TCPEndpoint() + if !ok { + return fmt.Errorf("node has no TCP endpoint") + } + fd, err := net.Dial("tcp", tcpEndpoint.String()) if err != nil { return err } diff --git a/p2p/dial.go b/p2p/dial.go index 08e1db28771e..24d4dc2e8936 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -65,11 +65,8 @@ type tcpDialer struct { } func (t tcpDialer) Dial(ctx context.Context, dest *enode.Node) (net.Conn, error) { - return t.d.DialContext(ctx, "tcp", nodeAddr(dest).String()) -} - -func nodeAddr(n *enode.Node) net.Addr { - return &net.TCPAddr{IP: n.IP(), Port: n.TCP()} + addr, _ := dest.TCPEndpoint() + return t.d.DialContext(ctx, "tcp", addr.String()) } // checkDial errors: @@ -243,7 +240,7 @@ loop: select { case node := <-nodesCh: if err := d.checkDial(node); err != nil { - d.log.Trace("Discarding dial candidate", "id", node.ID(), "ip", node.IP(), "reason", err) + d.log.Trace("Discarding dial candidate", "id", node.ID(), "ip", node.IPAddr(), "reason", err) } else { d.startDial(newDialTask(node, dynDialedConn)) } @@ -277,7 +274,7 @@ loop: case node := <-d.addStaticCh: id := node.ID() _, exists := d.static[id] - d.log.Trace("Adding static node", "id", id, "ip", node.IP(), "added", !exists) + d.log.Trace("Adding static node", "id", id, "ip", node.IPAddr(), "added", !exists) if exists { continue loop } @@ -376,7 +373,7 @@ func (d *dialScheduler) checkDial(n *enode.Node) error { if n.ID() == d.self { return errSelf } - if n.IP() != nil && n.TCP() == 0 { + if n.IPAddr().IsValid() && n.TCP() == 0 { // This check can trigger if a non-TCP node is found // by discovery. If there is no IP, the node is a static // node and the actual endpoint will be resolved later in dialTask. @@ -388,7 +385,7 @@ func (d *dialScheduler) checkDial(n *enode.Node) error { if _, ok := d.peers[n.ID()]; ok { return errAlreadyConnected } - if d.netRestrict != nil && !d.netRestrict.Contains(n.IP()) { + if d.netRestrict != nil && !d.netRestrict.ContainsAddr(n.IPAddr()) { return errNetRestrict } if d.history.contains(string(n.ID().Bytes())) { @@ -439,7 +436,7 @@ func (d *dialScheduler) removeFromStaticPool(idx int) { // startDial runs the given dial task in a separate goroutine. func (d *dialScheduler) startDial(task *dialTask) { node := task.dest() - d.log.Trace("Starting p2p dial", "id", node.ID(), "ip", node.IP(), "flag", task.flags) + d.log.Trace("Starting p2p dial", "id", node.ID(), "ip", node.IPAddr(), "flag", task.flags) hkey := string(node.ID().Bytes()) d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration)) d.dialing[node.ID()] = task @@ -492,7 +489,7 @@ func (t *dialTask) run(d *dialScheduler) { } func (t *dialTask) needResolve() bool { - return t.flags&staticDialedConn != 0 && t.dest().IP() == nil + return t.flags&staticDialedConn != 0 && !t.dest().IPAddr().IsValid() } // resolve attempts to find the current endpoint for the destination @@ -526,7 +523,8 @@ func (t *dialTask) resolve(d *dialScheduler) bool { // The node was found. t.resolveDelay = initialResolveDelay t.destPtr.Store(resolved) - d.log.Debug("Resolved node", "id", resolved.ID(), "addr", &net.TCPAddr{IP: resolved.IP(), Port: resolved.TCP()}) + resAddr, _ := resolved.TCPEndpoint() + d.log.Debug("Resolved node", "id", resolved.ID(), "addr", resAddr) return true } @@ -535,7 +533,8 @@ func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error { dialMeter.Mark(1) fd, err := d.dialer.Dial(d.ctx, dest) if err != nil { - d.log.Trace("Dial error", "id", dest.ID(), "addr", nodeAddr(dest), "conn", t.flags, "err", cleanupDialErr(err)) + addr, _ := dest.TCPEndpoint() + d.log.Trace("Dial error", "id", dest.ID(), "addr", addr, "conn", t.flags, "err", cleanupDialErr(err)) dialConnectionError.Mark(1) return &dialError{err} } @@ -545,7 +544,7 @@ func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error { func (t *dialTask) String() string { node := t.dest() id := node.ID() - return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], node.IP(), node.TCP()) + return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], node.IPAddr(), node.TCP()) } func cleanupDialErr(err error) error { diff --git a/p2p/discover/table.go b/p2p/discover/table.go index bd3c9b4143f0..bb5ab4f3fcd9 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -25,7 +25,7 @@ package discover import ( "context" "fmt" - "net" + "net/netip" "slices" "sync" "time" @@ -207,8 +207,8 @@ func (tab *Table) setFallbackNodes(nodes []*enode.Node) error { if err := n.ValidateComplete(); err != nil { return fmt.Errorf("bad bootstrap node %q: %v", n, err) } - if tab.cfg.NetRestrict != nil && !tab.cfg.NetRestrict.Contains(n.IP()) { - tab.log.Error("Bootstrap node filtered by netrestrict", "id", n.ID(), "ip", n.IP()) + if tab.cfg.NetRestrict != nil && !tab.cfg.NetRestrict.ContainsAddr(n.IPAddr()) { + tab.log.Error("Bootstrap node filtered by netrestrict", "id", n.ID(), "ip", n.IPAddr()) continue } nursery = append(nursery, n) @@ -448,7 +448,7 @@ func (tab *Table) loadSeedNodes() { for i := range seeds { seed := seeds[i] if tab.log.Enabled(context.Background(), log.LevelTrace) { - age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) + age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IPAddr())) addr, _ := seed.UDPEndpoint() tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", addr, "age", age) } @@ -474,31 +474,31 @@ func (tab *Table) bucketAtDistance(d int) *bucket { return tab.buckets[d-bucketMinDistance-1] } -func (tab *Table) addIP(b *bucket, ip net.IP) bool { - if len(ip) == 0 { +func (tab *Table) addIP(b *bucket, ip netip.Addr) bool { + if !ip.IsValid() || ip.IsUnspecified() { return false // Nodes without IP cannot be added. } - if netutil.IsLAN(ip) { + if netutil.AddrIsLAN(ip) { return true } - if !tab.ips.Add(ip) { + if !tab.ips.AddAddr(ip) { tab.log.Debug("IP exceeds table limit", "ip", ip) return false } - if !b.ips.Add(ip) { + if !b.ips.AddAddr(ip) { tab.log.Debug("IP exceeds bucket limit", "ip", ip) - tab.ips.Remove(ip) + tab.ips.RemoveAddr(ip) return false } return true } -func (tab *Table) removeIP(b *bucket, ip net.IP) { - if netutil.IsLAN(ip) { +func (tab *Table) removeIP(b *bucket, ip netip.Addr) { + if netutil.AddrIsLAN(ip) { return } - tab.ips.Remove(ip) - b.ips.Remove(ip) + tab.ips.RemoveAddr(ip) + b.ips.RemoveAddr(ip) } // handleAddNode adds the node in the request to the table, if there is space. @@ -524,7 +524,7 @@ func (tab *Table) handleAddNode(req addNodeOp) bool { tab.addReplacement(b, req.node) return false } - if !tab.addIP(b, req.node.IP()) { + if !tab.addIP(b, req.node.IPAddr()) { // Can't add: IP limit reached. return false } @@ -547,7 +547,7 @@ func (tab *Table) addReplacement(b *bucket, n *enode.Node) { // TODO: update ENR return } - if !tab.addIP(b, n.IP()) { + if !tab.addIP(b, n.IPAddr()) { return } @@ -555,7 +555,7 @@ func (tab *Table) addReplacement(b *bucket, n *enode.Node) { var removed *tableNode b.replacements, removed = pushNode(b.replacements, wn, maxReplacements) if removed != nil { - tab.removeIP(b, removed.IP()) + tab.removeIP(b, removed.IPAddr()) } } @@ -595,12 +595,12 @@ func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *tableNode { // Remove the node. n := b.entries[index] b.entries = slices.Delete(b.entries, index, index+1) - tab.removeIP(b, n.IP()) + tab.removeIP(b, n.IPAddr()) tab.nodeRemoved(b, n) // Add replacement. if len(b.replacements) == 0 { - tab.log.Debug("Removed dead node", "b", b.index, "id", n.ID(), "ip", n.IP()) + tab.log.Debug("Removed dead node", "b", b.index, "id", n.ID(), "ip", n.IPAddr()) return nil } rindex := tab.rand.Intn(len(b.replacements)) @@ -608,7 +608,7 @@ func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *tableNode { b.replacements = slices.Delete(b.replacements, rindex, rindex+1) b.entries = append(b.entries, rep) tab.nodeAdded(b, rep) - tab.log.Debug("Replaced dead node", "b", b.index, "id", n.ID(), "ip", n.IP(), "r", rep.ID(), "rip", rep.IP()) + tab.log.Debug("Replaced dead node", "b", b.index, "id", n.ID(), "ip", n.IPAddr(), "r", rep.ID(), "rip", rep.IPAddr()) return rep } @@ -635,10 +635,10 @@ func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) ipchanged := newRecord.IPAddr() != n.IPAddr() portchanged := newRecord.UDP() != n.UDP() if ipchanged { - tab.removeIP(b, n.IP()) - if !tab.addIP(b, newRecord.IP()) { + tab.removeIP(b, n.IPAddr()) + if !tab.addIP(b, newRecord.IPAddr()) { // It doesn't fit with the limit, put the previous record back. - tab.addIP(b, n.IP()) + tab.addIP(b, n.IPAddr()) return n, false } } @@ -657,11 +657,11 @@ func (tab *Table) handleTrackRequest(op trackRequestOp) { var fails int if op.success { // Reset failure counter because it counts _consecutive_ failures. - tab.db.UpdateFindFails(op.node.ID(), op.node.IP(), 0) + tab.db.UpdateFindFails(op.node.ID(), op.node.IPAddr(), 0) } else { - fails = tab.db.FindFails(op.node.ID(), op.node.IP()) + fails = tab.db.FindFails(op.node.ID(), op.node.IPAddr()) fails++ - tab.db.UpdateFindFails(op.node.ID(), op.node.IP(), fails) + tab.db.UpdateFindFails(op.node.ID(), op.node.IPAddr(), fails) } tab.mutex.Lock() diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 30e7d56f4afd..2f1797d1e239 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -188,7 +188,7 @@ func checkIPLimitInvariant(t *testing.T, tab *Table) { tabset := netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit} for _, b := range tab.buckets { for _, n := range b.entries { - tabset.Add(n.IP()) + tabset.AddAddr(n.IPAddr()) } } if tabset.String() != tab.ips.String() { @@ -268,7 +268,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { } for _, id := range gen([]enode.ID{}, rand).([]enode.ID) { r := new(enr.Record) - r.Set(enr.IP(genIP(rand))) + r.Set(enr.IPv4Addr(netutil.RandomAddr(rand, true))) n := enode.SignNull(r, id) t.All = append(t.All, n) } @@ -385,11 +385,11 @@ func checkBucketContent(t *testing.T, tab *Table, nodes []*enode.Node) { } t.Log("wrong bucket content. have nodes:") for _, n := range b.entries { - t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IP()) + t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IPAddr()) } t.Log("want nodes:") for _, n := range nodes { - t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IP()) + t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IPAddr()) } t.FailNow() @@ -483,12 +483,6 @@ func gen(typ interface{}, rand *rand.Rand) interface{} { return v.Interface() } -func genIP(rand *rand.Rand) net.IP { - ip := make(net.IP, 4) - rand.Read(ip) - return ip -} - func quickcfg() *quick.Config { return &quick.Config{ MaxCount: 5000, diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 997ac3779994..5b2699d460cc 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -100,8 +100,9 @@ func idAtDistance(a enode.ID, n int) (b enode.ID) { return b } +// intIP returns a LAN IP address based on i. func intIP(i int) net.IP { - return net.IP{byte(i), 0, 2, byte(i)} + return net.IP{10, 0, byte(i >> 8), byte(i & 0xFF)} } // fillBucket inserts nodes into the given bucket until it is full. @@ -254,7 +255,7 @@ NotEqual: } func nodeEqual(n1 *enode.Node, n2 *enode.Node) bool { - return n1.ID() == n2.ID() && n1.IP().Equal(n2.IP()) + return n1.ID() == n2.ID() && n1.IPAddr() == n2.IPAddr() } func sortByID[N nodeType](nodes []N) { diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 3880ca34a708..6234fd93ca5f 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -25,7 +25,6 @@ import ( "errors" "fmt" "io" - "net" "net/netip" "sync" "time" @@ -250,8 +249,7 @@ func (t *UDPv4) sendPing(toid enode.ID, toaddr netip.AddrPort, callback func()) return matched, matched }) // Send the packet. - toUDPAddr := &net.UDPAddr{IP: toaddr.Addr().AsSlice()} - t.localNode.UDPContact(toUDPAddr) + t.localNode.UDPContact(toaddr) t.write(toaddr, toid, req.Name(), packet) return rm } @@ -383,7 +381,7 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { if respN.Seq() < n.Seq() { return n, nil // response record is older } - if err := netutil.CheckRelayIP(addr.Addr().AsSlice(), respN.IP()); err != nil { + if err := netutil.CheckRelayAddr(addr.Addr(), respN.IPAddr()); err != nil { return nil, fmt.Errorf("invalid IP in response record: %v", err) } return respN, nil @@ -578,15 +576,14 @@ func (t *UDPv4) handlePacket(from netip.AddrPort, buf []byte) error { // checkBond checks if the given node has a recent enough endpoint proof. func (t *UDPv4) checkBond(id enode.ID, ip netip.AddrPort) bool { - return time.Since(t.db.LastPongReceived(id, ip.Addr().AsSlice())) < bondExpiration + return time.Since(t.db.LastPongReceived(id, ip.Addr())) < bondExpiration } // ensureBond solicits a ping from a node if we haven't seen a ping from it for a while. // This ensures there is a valid endpoint proof on the remote end. func (t *UDPv4) ensureBond(toid enode.ID, toaddr netip.AddrPort) { - ip := toaddr.Addr().AsSlice() - tooOld := time.Since(t.db.LastPingReceived(toid, ip)) > bondExpiration - if tooOld || t.db.FindFails(toid, ip) > maxFindnodeFailures { + tooOld := time.Since(t.db.LastPingReceived(toid, toaddr.Addr())) > bondExpiration + if tooOld || t.db.FindFails(toid, toaddr.Addr()) > maxFindnodeFailures { rm := t.sendPing(toid, toaddr, nil) <-rm.errc // Wait for them to ping back and process our pong. @@ -687,7 +684,7 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from netip.AddrPort, fromID enode // Ping back if our last pong on file is too far in the past. fromIP := from.Addr().AsSlice() n := enode.NewV4(h.senderKey, fromIP, int(req.From.TCP), int(from.Port())) - if time.Since(t.db.LastPongReceived(n.ID(), fromIP)) > bondExpiration { + if time.Since(t.db.LastPongReceived(n.ID(), from.Addr())) > bondExpiration { t.sendPing(fromID, from, func() { t.tab.addInboundNode(n) }) @@ -696,10 +693,9 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from netip.AddrPort, fromID enode } // Update node database and endpoint predictor. - t.db.UpdateLastPingReceived(n.ID(), fromIP, time.Now()) - fromUDPAddr := &net.UDPAddr{IP: fromIP, Port: int(from.Port())} - toUDPAddr := &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)} - t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) + t.db.UpdateLastPingReceived(n.ID(), from.Addr(), time.Now()) + toaddr := netip.AddrPortFrom(netutil.IPToAddr(req.To.IP), req.To.UDP) + t.localNode.UDPEndpointStatement(from, toaddr) } // PONG/v4 @@ -713,11 +709,9 @@ func (t *UDPv4) verifyPong(h *packetHandlerV4, from netip.AddrPort, fromID enode if !t.handleReply(fromID, from.Addr(), req) { return errUnsolicitedReply } - fromIP := from.Addr().AsSlice() - fromUDPAddr := &net.UDPAddr{IP: fromIP, Port: int(from.Port())} - toUDPAddr := &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)} - t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) - t.db.UpdateLastPongReceived(fromID, fromIP, time.Now()) + toaddr := netip.AddrPortFrom(netutil.IPToAddr(req.To.IP), req.To.UDP) + t.localNode.UDPEndpointStatement(from, toaddr) + t.db.UpdateLastPongReceived(fromID, from.Addr(), time.Now()) return nil } @@ -753,8 +747,7 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from netip.AddrPort, fromID e p := v4wire.Neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} var sent bool for _, n := range closest { - fromIP := from.Addr().AsSlice() - if netutil.CheckRelayIP(fromIP, n.IP()) == nil { + if netutil.CheckRelayAddr(from.Addr(), n.IPAddr()) == nil { p.Nodes = append(p.Nodes, nodeToRPC(n)) } if len(p.Nodes) == v4wire.MaxNeighbors { diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 28a6fb867596..9d6df08ead7f 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -274,7 +274,7 @@ func TestUDPv4_findnode(t *testing.T) { // ensure there's a bond with the test node, // findnode won't be accepted otherwise. remoteID := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID() - test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.Addr().AsSlice(), time.Now()) + test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.Addr(), time.Now()) // check that closest neighbors are returned. expected := test.table.findnodeByID(testTarget.ID(), bucketSize, true) @@ -309,7 +309,7 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { defer test.close() rid := enode.PubkeyToIDV4(&test.remotekey.PublicKey) - test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.Addr().AsSlice(), time.Now()) + test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.Addr(), time.Now()) // queue a pending findnode request resultc, errc := make(chan []*enode.Node, 1), make(chan error, 1) @@ -437,8 +437,8 @@ func TestUDPv4_successfulPing(t *testing.T) { if n.ID() != rid { t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid) } - if !n.IP().Equal(test.remoteaddr.Addr().AsSlice()) { - t.Errorf("node has wrong IP: got %v, want: %v", n.IP(), test.remoteaddr.Addr()) + if n.IPAddr() != test.remoteaddr.Addr() { + t.Errorf("node has wrong IP: got %v, want: %v", n.IPAddr(), test.remoteaddr.Addr()) } if n.UDP() != int(test.remoteaddr.Port()) { t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP(), test.remoteaddr.Port()) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 9ba54b3d400a..4cc21cd9c584 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -428,10 +428,10 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s if err != nil { return nil, err } - if err := netutil.CheckRelayIP(c.addr.Addr().AsSlice(), node.IP()); err != nil { + if err := netutil.CheckRelayAddr(c.addr.Addr(), node.IPAddr()); err != nil { return nil, err } - if t.netrestrict != nil && !t.netrestrict.Contains(node.IP()) { + if t.netrestrict != nil && !t.netrestrict.ContainsAddr(node.IPAddr()) { return nil, errors.New("not contained in netrestrict list") } if node.UDP() <= 1024 { @@ -754,9 +754,8 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr netip.AddrPort t.handlePing(p, fromID, fromAddr) case *v5wire.Pong: if t.handleCallResponse(fromID, fromAddr, p) { - fromUDPAddr := &net.UDPAddr{IP: fromAddr.Addr().AsSlice(), Port: int(fromAddr.Port())} - toUDPAddr := &net.UDPAddr{IP: p.ToIP, Port: int(p.ToPort)} - t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) + toAddr := netip.AddrPortFrom(netutil.IPToAddr(p.ToIP), p.ToPort) + t.localNode.UDPEndpointStatement(fromAddr, toAddr) } case *v5wire.Findnode: t.handleFindnode(p, fromID, fromAddr) @@ -848,7 +847,6 @@ func (t *UDPv5) handleFindnode(p *v5wire.Findnode, fromID enode.ID, fromAddr net // collectTableNodes creates a FINDNODE result set for the given distances. func (t *UDPv5) collectTableNodes(rip netip.Addr, distances []uint, limit int) []*enode.Node { - ripSlice := rip.AsSlice() var bn []*enode.Node var nodes []*enode.Node var processed = make(map[uint]struct{}) @@ -863,7 +861,7 @@ func (t *UDPv5) collectTableNodes(rip netip.Addr, distances []uint, limit int) [ for _, n := range t.tab.appendLiveNodes(dist, bn[:0]) { // Apply some pre-checks to avoid sending invalid nodes. // Note liveness is checked by appendLiveNodes. - if netutil.CheckRelayIP(ripSlice, n.IP()) != nil { + if netutil.CheckRelayAddr(rip, n.IPAddr()) != nil { continue } nodes = append(nodes, n) diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index 27966f2afc6b..8dd02620eba7 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -606,7 +606,7 @@ func (n *handshakeTestNode) n() *enode.Node { } func (n *handshakeTestNode) addr() string { - return n.ln.Node().IP().String() + return n.ln.Node().IPAddr().String() } func (n *handshakeTestNode) id() enode.ID { diff --git a/p2p/enode/localnode.go b/p2p/enode/localnode.go index a18204e752ce..6e79c9cbdc74 100644 --- a/p2p/enode/localnode.go +++ b/p2p/enode/localnode.go @@ -20,8 +20,8 @@ import ( "crypto/ecdsa" "fmt" "net" + "net/netip" "reflect" - "strconv" "sync" "sync/atomic" "time" @@ -175,8 +175,8 @@ func (ln *LocalNode) delete(e enr.Entry) { } } -func (ln *LocalNode) endpointForIP(ip net.IP) *lnEndpoint { - if ip.To4() != nil { +func (ln *LocalNode) endpointForIP(ip netip.Addr) *lnEndpoint { + if ip.Is4() { return &ln.endpoint4 } return &ln.endpoint6 @@ -188,7 +188,7 @@ func (ln *LocalNode) SetStaticIP(ip net.IP) { ln.mu.Lock() defer ln.mu.Unlock() - ln.endpointForIP(ip).staticIP = ip + ln.endpointForIP(netutil.IPToAddr(ip)).staticIP = ip ln.updateEndpoints() } @@ -198,7 +198,7 @@ func (ln *LocalNode) SetFallbackIP(ip net.IP) { ln.mu.Lock() defer ln.mu.Unlock() - ln.endpointForIP(ip).fallbackIP = ip + ln.endpointForIP(netutil.IPToAddr(ip)).fallbackIP = ip ln.updateEndpoints() } @@ -215,21 +215,21 @@ func (ln *LocalNode) SetFallbackUDP(port int) { // UDPEndpointStatement should be called whenever a statement about the local node's // UDP endpoint is received. It feeds the local endpoint predictor. -func (ln *LocalNode) UDPEndpointStatement(fromaddr, endpoint *net.UDPAddr) { +func (ln *LocalNode) UDPEndpointStatement(fromaddr, endpoint netip.AddrPort) { ln.mu.Lock() defer ln.mu.Unlock() - ln.endpointForIP(endpoint.IP).track.AddStatement(fromaddr.String(), endpoint.String()) + ln.endpointForIP(endpoint.Addr()).track.AddStatement(fromaddr.Addr(), endpoint) ln.updateEndpoints() } // UDPContact should be called whenever the local node has announced itself to another node // via UDP. It feeds the local endpoint predictor. -func (ln *LocalNode) UDPContact(toaddr *net.UDPAddr) { +func (ln *LocalNode) UDPContact(toaddr netip.AddrPort) { ln.mu.Lock() defer ln.mu.Unlock() - ln.endpointForIP(toaddr.IP).track.AddContact(toaddr.String()) + ln.endpointForIP(toaddr.Addr()).track.AddContact(toaddr.Addr()) ln.updateEndpoints() } @@ -268,29 +268,13 @@ func (e *lnEndpoint) get() (newIP net.IP, newPort uint16) { } if e.staticIP != nil { newIP = e.staticIP - } else if ip, port := predictAddr(e.track); ip != nil { - newIP = ip - newPort = port + } else if ap := e.track.PredictEndpoint(); ap.IsValid() { + newIP = ap.Addr().AsSlice() + newPort = ap.Port() } return newIP, newPort } -// predictAddr wraps IPTracker.PredictEndpoint, converting from its string-based -// endpoint representation to IP and port types. -func predictAddr(t *netutil.IPTracker) (net.IP, uint16) { - ep := t.PredictEndpoint() - if ep == "" { - return nil, 0 - } - ipString, portString, _ := net.SplitHostPort(ep) - ip := net.ParseIP(ipString) - port, err := strconv.ParseUint(portString, 10, 16) - if err != nil { - return nil, 0 - } - return ip, uint16(port) -} - func (ln *LocalNode) invalidate() { ln.cur.Store((*Node)(nil)) } @@ -314,7 +298,7 @@ func (ln *LocalNode) sign() { panic(fmt.Errorf("enode: can't verify local record: %v", err)) } ln.cur.Store(n) - log.Info("New local node record", "seq", ln.seq, "id", n.ID(), "ip", n.IP(), "udp", n.UDP(), "tcp", n.TCP()) + log.Info("New local node record", "seq", ln.seq, "id", n.ID(), "ip", n.IPAddr(), "udp", n.UDP(), "tcp", n.TCP()) } func (ln *LocalNode) bumpSeq() { diff --git a/p2p/enode/localnode_test.go b/p2p/enode/localnode_test.go index 7f97ad392f27..86b962a74eed 100644 --- a/p2p/enode/localnode_test.go +++ b/p2p/enode/localnode_test.go @@ -17,12 +17,14 @@ package enode import ( - "crypto/rand" + "math/rand" "net" + "net/netip" "testing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/stretchr/testify/assert" ) @@ -88,6 +90,7 @@ func TestLocalNodeSeqPersist(t *testing.T) { // This test checks behavior of the endpoint predictor. func TestLocalNodeEndpoint(t *testing.T) { var ( + rng = rand.New(rand.NewSource(4)) 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} @@ -96,6 +99,7 @@ func TestLocalNodeEndpoint(t *testing.T) { defer db.Close() // Nothing is set initially. + assert.Equal(t, netip.Addr{}, ln.Node().IPAddr()) assert.Equal(t, net.IP(nil), ln.Node().IP()) assert.Equal(t, 0, ln.Node().UDP()) initialSeq := ln.Node().Seq() @@ -103,26 +107,30 @@ func TestLocalNodeEndpoint(t *testing.T) { // Set up fallback address. ln.SetFallbackIP(fallback.IP) ln.SetFallbackUDP(fallback.Port) + assert.Equal(t, netutil.IPToAddr(fallback.IP), ln.Node().IPAddr()) assert.Equal(t, fallback.IP, ln.Node().IP()) assert.Equal(t, fallback.Port, ln.Node().UDP()) assert.Equal(t, initialSeq+1, ln.Node().Seq()) // Add endpoint statements from random hosts. for i := 0; i < iptrackMinStatements; i++ { + assert.Equal(t, netutil.IPToAddr(fallback.IP), ln.Node().IPAddr()) assert.Equal(t, fallback.IP, ln.Node().IP()) assert.Equal(t, fallback.Port, ln.Node().UDP()) assert.Equal(t, initialSeq+1, ln.Node().Seq()) - from := &net.UDPAddr{IP: make(net.IP, 4), Port: 90} - rand.Read(from.IP) - ln.UDPEndpointStatement(from, predicted) + from := netip.AddrPortFrom(netutil.RandomAddr(rng, true), 9000) + endpoint := netip.AddrPortFrom(netutil.IPToAddr(predicted.IP), uint16(predicted.Port)) + ln.UDPEndpointStatement(from, endpoint) } + assert.Equal(t, netutil.IPToAddr(predicted.IP), ln.Node().IPAddr()) assert.Equal(t, predicted.IP, ln.Node().IP()) assert.Equal(t, predicted.Port, ln.Node().UDP()) assert.Equal(t, initialSeq+2, ln.Node().Seq()) // Static IP overrides prediction. ln.SetStaticIP(staticIP) + assert.Equal(t, netutil.IPToAddr(staticIP), ln.Node().IPAddr()) assert.Equal(t, staticIP, ln.Node().IP()) assert.Equal(t, fallback.Port, ln.Node().UDP()) assert.Equal(t, initialSeq+3, ln.Node().Seq()) diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go index 654d71d47b6a..1f31c98d2256 100644 --- a/p2p/enode/nodedb.go +++ b/p2p/enode/nodedb.go @@ -21,7 +21,7 @@ import ( "crypto/rand" "encoding/binary" "fmt" - "net" + "net/netip" "os" "sync" "time" @@ -66,7 +66,7 @@ var ( errInvalidIP = errors.New("invalid IP") ) -var zeroIP = make(net.IP, 16) +var zeroIP = netip.IPv6Unspecified() // DB is the node database, storing previously seen nodes and any collected metadata about // them for QoS purposes. @@ -151,39 +151,37 @@ func splitNodeKey(key []byte) (id ID, rest []byte) { } // nodeItemKey returns the database key for a node metadata field. -func nodeItemKey(id ID, ip net.IP, field string) []byte { - ip16 := ip.To16() - if ip16 == nil { - panic(fmt.Errorf("invalid IP (length %d)", len(ip))) +func nodeItemKey(id ID, ip netip.Addr, field string) []byte { + if !ip.IsValid() { + panic("invalid IP") } - return bytes.Join([][]byte{nodeKey(id), ip16, []byte(field)}, []byte{':'}) + ip16 := ip.As16() + return bytes.Join([][]byte{nodeKey(id), ip16[:], []byte(field)}, []byte{':'}) } // splitNodeItemKey returns the components of a key created by nodeItemKey. -func splitNodeItemKey(key []byte) (id ID, ip net.IP, field string) { +func splitNodeItemKey(key []byte) (id ID, ip netip.Addr, field string) { id, key = splitNodeKey(key) // Skip discover root. if string(key) == dbDiscoverRoot { - return id, nil, "" + return id, netip.Addr{}, "" } key = key[len(dbDiscoverRoot)+1:] // Split out the IP. - ip = key[:16] - if ip4 := ip.To4(); ip4 != nil { - ip = ip4 - } + ip, _ = netip.AddrFromSlice(key[:16]) key = key[16+1:] // Field is the remainder of key. field = string(key) return id, ip, field } -func v5Key(id ID, ip net.IP, field string) []byte { +func v5Key(id ID, ip netip.Addr, field string) []byte { + ip16 := ip.As16() return bytes.Join([][]byte{ []byte(dbNodePrefix), id[:], []byte(dbDiscv5Root), - ip.To16(), + ip16[:], []byte(field), }, []byte{':'}) } @@ -364,24 +362,24 @@ func (db *DB) expireNodes() { // LastPingReceived retrieves the time of the last ping packet received from // a remote node. -func (db *DB) LastPingReceived(id ID, ip net.IP) time.Time { - if ip = ip.To16(); ip == nil { +func (db *DB) LastPingReceived(id ID, ip netip.Addr) time.Time { + if !ip.IsValid() { return time.Time{} } return time.Unix(db.fetchInt64(nodeItemKey(id, ip, dbNodePing)), 0) } // UpdateLastPingReceived updates the last time we tried contacting a remote node. -func (db *DB) UpdateLastPingReceived(id ID, ip net.IP, instance time.Time) error { - if ip = ip.To16(); ip == nil { +func (db *DB) UpdateLastPingReceived(id ID, ip netip.Addr, instance time.Time) error { + if !ip.IsValid() { return errInvalidIP } return db.storeInt64(nodeItemKey(id, ip, dbNodePing), instance.Unix()) } // LastPongReceived retrieves the time of the last successful pong from remote node. -func (db *DB) LastPongReceived(id ID, ip net.IP) time.Time { - if ip = ip.To16(); ip == nil { +func (db *DB) LastPongReceived(id ID, ip netip.Addr) time.Time { + if !ip.IsValid() { return time.Time{} } // Launch expirer @@ -390,40 +388,40 @@ func (db *DB) LastPongReceived(id ID, ip net.IP) time.Time { } // UpdateLastPongReceived updates the last pong time of a node. -func (db *DB) UpdateLastPongReceived(id ID, ip net.IP, instance time.Time) error { - if ip = ip.To16(); ip == nil { +func (db *DB) UpdateLastPongReceived(id ID, ip netip.Addr, instance time.Time) error { + if !ip.IsValid() { return errInvalidIP } return db.storeInt64(nodeItemKey(id, ip, dbNodePong), instance.Unix()) } // FindFails retrieves the number of findnode failures since bonding. -func (db *DB) FindFails(id ID, ip net.IP) int { - if ip = ip.To16(); ip == nil { +func (db *DB) FindFails(id ID, ip netip.Addr) int { + if !ip.IsValid() { return 0 } return int(db.fetchInt64(nodeItemKey(id, ip, dbNodeFindFails))) } // UpdateFindFails updates the number of findnode failures since bonding. -func (db *DB) UpdateFindFails(id ID, ip net.IP, fails int) error { - if ip = ip.To16(); ip == nil { +func (db *DB) UpdateFindFails(id ID, ip netip.Addr, fails int) error { + if !ip.IsValid() { return errInvalidIP } return db.storeInt64(nodeItemKey(id, ip, dbNodeFindFails), int64(fails)) } // FindFailsV5 retrieves the discv5 findnode failure counter. -func (db *DB) FindFailsV5(id ID, ip net.IP) int { - if ip = ip.To16(); ip == nil { +func (db *DB) FindFailsV5(id ID, ip netip.Addr) int { + if !ip.IsValid() { return 0 } return int(db.fetchInt64(v5Key(id, ip, dbNodeFindFails))) } // UpdateFindFailsV5 stores the discv5 findnode failure counter. -func (db *DB) UpdateFindFailsV5(id ID, ip net.IP, fails int) error { - if ip = ip.To16(); ip == nil { +func (db *DB) UpdateFindFailsV5(id ID, ip netip.Addr, fails int) error { + if !ip.IsValid() { return errInvalidIP } return db.storeInt64(v5Key(id, ip, dbNodeFindFails), int64(fails)) @@ -470,7 +468,7 @@ seek: id[0] = 0 continue seek // iterator exhausted } - if now.Sub(db.LastPongReceived(n.ID(), n.IP())) > maxAge { + if now.Sub(db.LastPongReceived(n.ID(), n.IPAddr())) > maxAge { continue seek } for i := range nodes { diff --git a/p2p/enode/nodedb_test.go b/p2p/enode/nodedb_test.go index 38764f31b124..bc0291665d06 100644 --- a/p2p/enode/nodedb_test.go +++ b/p2p/enode/nodedb_test.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "net" + "net/netip" "path/filepath" "reflect" "testing" @@ -48,8 +49,10 @@ func TestDBNodeKey(t *testing.T) { } func TestDBNodeItemKey(t *testing.T) { - wantIP := net.IP{127, 0, 0, 3} + wantIP := netip.MustParseAddr("127.0.0.3") + wantIP4in6 := netip.AddrFrom16(wantIP.As16()) wantField := "foobar" + enc := nodeItemKey(keytestID, wantIP, wantField) want := []byte{ 'n', ':', @@ -69,7 +72,7 @@ func TestDBNodeItemKey(t *testing.T) { if id != keytestID { t.Errorf("splitNodeItemKey returned wrong ID: %v", id) } - if !ip.Equal(wantIP) { + if ip != wantIP4in6 { t.Errorf("splitNodeItemKey returned wrong IP: %v", ip) } if field != wantField { @@ -123,33 +126,33 @@ func TestDBFetchStore(t *testing.T) { defer db.Close() // Check fetch/store operations on a node ping object - if stored := db.LastPingReceived(node.ID(), node.IP()); stored.Unix() != 0 { + if stored := db.LastPingReceived(node.ID(), node.IPAddr()); stored.Unix() != 0 { t.Errorf("ping: non-existing object: %v", stored) } - if err := db.UpdateLastPingReceived(node.ID(), node.IP(), inst); err != nil { + if err := db.UpdateLastPingReceived(node.ID(), node.IPAddr(), inst); err != nil { t.Errorf("ping: failed to update: %v", err) } - if stored := db.LastPingReceived(node.ID(), node.IP()); stored.Unix() != inst.Unix() { + if stored := db.LastPingReceived(node.ID(), node.IPAddr()); stored.Unix() != inst.Unix() { t.Errorf("ping: value mismatch: have %v, want %v", stored, inst) } // Check fetch/store operations on a node pong object - if stored := db.LastPongReceived(node.ID(), node.IP()); stored.Unix() != 0 { + if stored := db.LastPongReceived(node.ID(), node.IPAddr()); stored.Unix() != 0 { t.Errorf("pong: non-existing object: %v", stored) } - if err := db.UpdateLastPongReceived(node.ID(), node.IP(), inst); err != nil { + if err := db.UpdateLastPongReceived(node.ID(), node.IPAddr(), inst); err != nil { t.Errorf("pong: failed to update: %v", err) } - if stored := db.LastPongReceived(node.ID(), node.IP()); stored.Unix() != inst.Unix() { + if stored := db.LastPongReceived(node.ID(), node.IPAddr()); stored.Unix() != inst.Unix() { t.Errorf("pong: value mismatch: have %v, want %v", stored, inst) } // Check fetch/store operations on a node findnode-failure object - if stored := db.FindFails(node.ID(), node.IP()); stored != 0 { + if stored := db.FindFails(node.ID(), node.IPAddr()); stored != 0 { t.Errorf("find-node fails: non-existing object: %v", stored) } - if err := db.UpdateFindFails(node.ID(), node.IP(), num); err != nil { + if err := db.UpdateFindFails(node.ID(), node.IPAddr(), num); err != nil { t.Errorf("find-node fails: failed to update: %v", err) } - if stored := db.FindFails(node.ID(), node.IP()); stored != num { + if stored := db.FindFails(node.ID(), node.IPAddr()); stored != num { t.Errorf("find-node fails: value mismatch: have %v, want %v", stored, num) } // Check fetch/store operations on an actual node object @@ -266,7 +269,7 @@ func testSeedQuery() error { if err := db.UpdateNode(seed.node); err != nil { return fmt.Errorf("node %d: failed to insert: %v", i, err) } - if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IP(), seed.pong); err != nil { + if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IPAddr(), seed.pong); err != nil { return fmt.Errorf("node %d: failed to insert bondTime: %v", i, err) } } @@ -427,7 +430,7 @@ func TestDBExpiration(t *testing.T) { t.Fatalf("node %d: failed to insert: %v", i, err) } } - if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IP(), seed.pong); err != nil { + if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IPAddr(), seed.pong); err != nil { t.Fatalf("node %d: failed to update bondTime: %v", i, err) } } @@ -438,13 +441,13 @@ func TestDBExpiration(t *testing.T) { unixZeroTime := time.Unix(0, 0) for i, seed := range nodeDBExpirationNodes { node := db.Node(seed.node.ID()) - pong := db.LastPongReceived(seed.node.ID(), seed.node.IP()) + pong := db.LastPongReceived(seed.node.ID(), seed.node.IPAddr()) if seed.exp { if seed.storeNode && node != nil { t.Errorf("node %d (%s) shouldn't be present after expiration", i, seed.node.ID().TerminalString()) } if !pong.Equal(unixZeroTime) { - t.Errorf("pong time %d (%s %v) shouldn't be present after expiration", i, seed.node.ID().TerminalString(), seed.node.IP()) + t.Errorf("pong time %d (%s %v) shouldn't be present after expiration", i, seed.node.ID().TerminalString(), seed.node.IPAddr()) } } else { if seed.storeNode && node == nil { @@ -463,7 +466,7 @@ func TestDBExpireV5(t *testing.T) { db, _ := OpenDB("") defer db.Close() - ip := net.IP{127, 0, 0, 1} + ip := netip.MustParseAddr("127.0.0.1") db.UpdateFindFailsV5(ID{}, ip, 4) db.expireNodes() } diff --git a/p2p/netutil/addrutil.go b/p2p/netutil/addrutil.go index fb6d8d27318d..b8b318571beb 100644 --- a/p2p/netutil/addrutil.go +++ b/p2p/netutil/addrutil.go @@ -16,18 +16,53 @@ package netutil -import "net" +import ( + "fmt" + "math/rand" + "net" + "net/netip" +) -// AddrIP gets the IP address contained in addr. It returns nil if no address is present. -func AddrIP(addr net.Addr) net.IP { +// AddrAddr gets the IP address contained in addr. The result will be invalid if the +// address type is unsupported. +func AddrAddr(addr net.Addr) netip.Addr { switch a := addr.(type) { case *net.IPAddr: - return a.IP + return IPToAddr(a.IP) case *net.TCPAddr: - return a.IP + return IPToAddr(a.IP) case *net.UDPAddr: - return a.IP + return IPToAddr(a.IP) default: - return nil + return netip.Addr{} } } + +// IPToAddr converts net.IP to netip.Addr. Note that unlike netip.AddrFromSlice, this +// function will always ensure that the resulting Addr is IPv4 when the input is. +func IPToAddr(ip net.IP) netip.Addr { + if ip4 := ip.To4(); ip4 != nil { + addr, _ := netip.AddrFromSlice(ip4) + return addr + } else if ip6 := ip.To16(); ip6 != nil { + addr, _ := netip.AddrFromSlice(ip6) + return addr + } + return netip.Addr{} +} + +// RandomAddr creates a random IP address. +func RandomAddr(rng *rand.Rand, ipv4 bool) netip.Addr { + var bytes []byte + if ipv4 || rng.Intn(2) == 0 { + bytes = make([]byte, 4) + } else { + bytes = make([]byte, 16) + } + rng.Read(bytes) + addr, ok := netip.AddrFromSlice(bytes) + if !ok { + panic(fmt.Errorf("BUG! invalid IP %v", bytes)) + } + return addr +} diff --git a/p2p/netutil/iptrack.go b/p2p/netutil/iptrack.go index a070499e19dc..5140ac7539aa 100644 --- a/p2p/netutil/iptrack.go +++ b/p2p/netutil/iptrack.go @@ -17,6 +17,7 @@ package netutil import ( + "net/netip" "time" "github.com/ethereum/go-ethereum/common/mclock" @@ -29,14 +30,14 @@ type IPTracker struct { contactWindow time.Duration minStatements int clock mclock.Clock - statements map[string]ipStatement - contact map[string]mclock.AbsTime + statements map[netip.Addr]ipStatement + contact map[netip.Addr]mclock.AbsTime lastStatementGC mclock.AbsTime lastContactGC mclock.AbsTime } type ipStatement struct { - endpoint string + endpoint netip.AddrPort time mclock.AbsTime } @@ -51,9 +52,9 @@ func NewIPTracker(window, contactWindow time.Duration, minStatements int) *IPTra return &IPTracker{ window: window, contactWindow: contactWindow, - statements: make(map[string]ipStatement), + statements: make(map[netip.Addr]ipStatement), minStatements: minStatements, - contact: make(map[string]mclock.AbsTime), + contact: make(map[netip.Addr]mclock.AbsTime), clock: mclock.System{}, } } @@ -74,12 +75,15 @@ func (it *IPTracker) PredictFullConeNAT() bool { } // PredictEndpoint returns the current prediction of the external endpoint. -func (it *IPTracker) PredictEndpoint() string { +func (it *IPTracker) PredictEndpoint() netip.AddrPort { it.gcStatements(it.clock.Now()) // The current strategy is simple: find the endpoint with most statements. - counts := make(map[string]int, len(it.statements)) - maxcount, max := 0, "" + var ( + counts = make(map[netip.AddrPort]int, len(it.statements)) + maxcount int + max netip.AddrPort + ) for _, s := range it.statements { c := counts[s.endpoint] + 1 counts[s.endpoint] = c @@ -91,7 +95,7 @@ func (it *IPTracker) PredictEndpoint() string { } // AddStatement records that a certain host thinks our external endpoint is the one given. -func (it *IPTracker) AddStatement(host, endpoint string) { +func (it *IPTracker) AddStatement(host netip.Addr, endpoint netip.AddrPort) { now := it.clock.Now() it.statements[host] = ipStatement{endpoint, now} if time.Duration(now-it.lastStatementGC) >= it.window { @@ -101,7 +105,7 @@ func (it *IPTracker) AddStatement(host, endpoint string) { // AddContact records that a packet containing our endpoint information has been sent to a // certain host. -func (it *IPTracker) AddContact(host string) { +func (it *IPTracker) AddContact(host netip.Addr) { now := it.clock.Now() it.contact[host] = now if time.Duration(now-it.lastContactGC) >= it.contactWindow { diff --git a/p2p/netutil/iptrack_test.go b/p2p/netutil/iptrack_test.go index ee3bba861e25..81653a273307 100644 --- a/p2p/netutil/iptrack_test.go +++ b/p2p/netutil/iptrack_test.go @@ -19,6 +19,7 @@ package netutil import ( crand "crypto/rand" "fmt" + "net/netip" "testing" "time" @@ -42,37 +43,37 @@ func TestIPTracker(t *testing.T) { tests := map[string][]iptrackTestEvent{ "minStatements": { {opPredict, 0, "", ""}, - {opStatement, 0, "127.0.0.1", "127.0.0.2"}, + {opStatement, 0, "127.0.0.1:8000", "127.0.0.2"}, {opPredict, 1000, "", ""}, - {opStatement, 1000, "127.0.0.1", "127.0.0.3"}, + {opStatement, 1000, "127.0.0.1:8000", "127.0.0.3"}, {opPredict, 1000, "", ""}, - {opStatement, 1000, "127.0.0.1", "127.0.0.4"}, - {opPredict, 1000, "127.0.0.1", ""}, + {opStatement, 1000, "127.0.0.1:8000", "127.0.0.4"}, + {opPredict, 1000, "127.0.0.1:8000", ""}, }, "window": { - {opStatement, 0, "127.0.0.1", "127.0.0.2"}, - {opStatement, 2000, "127.0.0.1", "127.0.0.3"}, - {opStatement, 3000, "127.0.0.1", "127.0.0.4"}, - {opPredict, 10000, "127.0.0.1", ""}, + {opStatement, 0, "127.0.0.1:8000", "127.0.0.2"}, + {opStatement, 2000, "127.0.0.1:8000", "127.0.0.3"}, + {opStatement, 3000, "127.0.0.1:8000", "127.0.0.4"}, + {opPredict, 10000, "127.0.0.1:8000", ""}, {opPredict, 10001, "", ""}, // first statement expired - {opStatement, 10100, "127.0.0.1", "127.0.0.2"}, - {opPredict, 10200, "127.0.0.1", ""}, + {opStatement, 10100, "127.0.0.1:8000", "127.0.0.2"}, + {opPredict, 10200, "127.0.0.1:8000", ""}, }, "fullcone": { {opContact, 0, "", "127.0.0.2"}, - {opStatement, 10, "127.0.0.1", "127.0.0.2"}, + {opStatement, 10, "127.0.0.1:8000", "127.0.0.2"}, {opContact, 2000, "", "127.0.0.3"}, - {opStatement, 2010, "127.0.0.1", "127.0.0.3"}, + {opStatement, 2010, "127.0.0.1:8000", "127.0.0.3"}, {opContact, 3000, "", "127.0.0.4"}, - {opStatement, 3010, "127.0.0.1", "127.0.0.4"}, + {opStatement, 3010, "127.0.0.1:8000", "127.0.0.4"}, {opCheckFullCone, 3500, "false", ""}, }, "fullcone_2": { {opContact, 0, "", "127.0.0.2"}, - {opStatement, 10, "127.0.0.1", "127.0.0.2"}, + {opStatement, 10, "127.0.0.1:8000", "127.0.0.2"}, {opContact, 2000, "", "127.0.0.3"}, - {opStatement, 2010, "127.0.0.1", "127.0.0.3"}, - {opStatement, 3000, "127.0.0.1", "127.0.0.4"}, + {opStatement, 2010, "127.0.0.1:8000", "127.0.0.3"}, + {opStatement, 3000, "127.0.0.1:8000", "127.0.0.4"}, {opContact, 3010, "", "127.0.0.4"}, {opCheckFullCone, 3500, "true", ""}, }, @@ -93,12 +94,19 @@ func runIPTrackerTest(t *testing.T, evs []iptrackTestEvent) { clock.Run(evtime - time.Duration(clock.Now())) switch ev.op { case opStatement: - it.AddStatement(ev.from, ev.ip) + it.AddStatement(netip.MustParseAddr(ev.from), netip.MustParseAddrPort(ev.ip)) case opContact: - it.AddContact(ev.from) + it.AddContact(netip.MustParseAddr(ev.from)) case opPredict: - if pred := it.PredictEndpoint(); pred != ev.ip { - t.Errorf("op %d: wrong prediction %q, want %q", i, pred, ev.ip) + pred := it.PredictEndpoint() + if ev.ip == "" { + if pred.IsValid() { + t.Errorf("op %d: wrong prediction %v, expected invalid", i, pred) + } + } else { + if pred != netip.MustParseAddrPort(ev.ip) { + t.Errorf("op %d: wrong prediction %v, want %q", i, pred, ev.ip) + } } case opCheckFullCone: pred := fmt.Sprintf("%t", it.PredictFullConeNAT()) @@ -121,12 +129,11 @@ func TestIPTrackerForceGC(t *testing.T) { it.clock = &clock for i := 0; i < 5*max; i++ { - e1 := make([]byte, 4) - e2 := make([]byte, 4) - crand.Read(e1) - crand.Read(e2) - it.AddStatement(string(e1), string(e2)) - it.AddContact(string(e1)) + var e1, e2 [4]byte + crand.Read(e1[:]) + crand.Read(e2[:]) + it.AddStatement(netip.AddrFrom4(e1), netip.AddrPortFrom(netip.AddrFrom4(e2), 9000)) + it.AddContact(netip.AddrFrom4(e1)) clock.Run(rate) } if len(it.contact) > 2*max { diff --git a/p2p/netutil/net.go b/p2p/netutil/net.go index d5da3c694f8e..474912978e62 100644 --- a/p2p/netutil/net.go +++ b/p2p/netutil/net.go @@ -22,21 +22,19 @@ import ( "errors" "fmt" "net" - "sort" + "net/netip" + "slices" "strings" + + "golang.org/x/exp/maps" ) -var lan4, lan6, special4, special6 Netlist +var special4, special6 Netlist func init() { // Lists from RFC 5735, RFC 5156, // https://www.iana.org/assignments/iana-ipv4-special-registry/ - lan4.Add("0.0.0.0/8") // "This" network - lan4.Add("10.0.0.0/8") // Private Use - lan4.Add("172.16.0.0/12") // Private Use - lan4.Add("192.168.0.0/16") // Private Use - lan6.Add("fe80::/10") // Link-Local - lan6.Add("fc00::/7") // Unique-Local + special4.Add("0.0.0.0/8") // "This" network. special4.Add("192.0.0.0/29") // IPv4 Service Continuity special4.Add("192.0.0.9/32") // PCP Anycast special4.Add("192.0.0.170/32") // NAT64/DNS64 Discovery @@ -66,7 +64,7 @@ func init() { } // Netlist is a list of IP networks. -type Netlist []net.IPNet +type Netlist []netip.Prefix // ParseNetlist parses a comma-separated list of CIDR masks. // Whitespace and extra commas are ignored. @@ -78,11 +76,11 @@ func ParseNetlist(s string) (*Netlist, error) { if mask == "" { continue } - _, n, err := net.ParseCIDR(mask) + prefix, err := netip.ParsePrefix(mask) if err != nil { return nil, err } - l = append(l, *n) + l = append(l, prefix) } return &l, nil } @@ -103,11 +101,11 @@ func (l *Netlist) UnmarshalTOML(fn func(interface{}) error) error { return err } for _, mask := range masks { - _, n, err := net.ParseCIDR(mask) + prefix, err := netip.ParsePrefix(mask) if err != nil { return err } - *l = append(*l, *n) + *l = append(*l, prefix) } return nil } @@ -115,15 +113,20 @@ func (l *Netlist) UnmarshalTOML(fn func(interface{}) error) error { // Add parses a CIDR mask and appends it to the list. It panics for invalid masks and is // intended to be used for setting up static lists. func (l *Netlist) Add(cidr string) { - _, n, err := net.ParseCIDR(cidr) + prefix, err := netip.ParsePrefix(cidr) if err != nil { panic(err) } - *l = append(*l, *n) + *l = append(*l, prefix) } // Contains reports whether the given IP is contained in the list. func (l *Netlist) Contains(ip net.IP) bool { + return l.ContainsAddr(IPToAddr(ip)) +} + +// ContainsAddr reports whether the given IP is contained in the list. +func (l *Netlist) ContainsAddr(ip netip.Addr) bool { if l == nil { return false } @@ -137,25 +140,39 @@ func (l *Netlist) Contains(ip net.IP) bool { // IsLAN reports whether an IP is a local network address. func IsLAN(ip net.IP) bool { + return AddrIsLAN(IPToAddr(ip)) +} + +// AddrIsLAN reports whether an IP is a local network address. +func AddrIsLAN(ip netip.Addr) bool { + if ip.Is4In6() { + ip = netip.AddrFrom4(ip.As4()) + } if ip.IsLoopback() { return true } - if v4 := ip.To4(); v4 != nil { - return lan4.Contains(v4) - } - return lan6.Contains(ip) + return ip.IsPrivate() || ip.IsLinkLocalUnicast() } // IsSpecialNetwork reports whether an IP is located in a special-use network range // This includes broadcast, multicast and documentation addresses. func IsSpecialNetwork(ip net.IP) bool { + return AddrIsSpecialNetwork(IPToAddr(ip)) +} + +// AddrIsSpecialNetwork reports whether an IP is located in a special-use network range +// This includes broadcast, multicast and documentation addresses. +func AddrIsSpecialNetwork(ip netip.Addr) bool { + if ip.Is4In6() { + ip = netip.AddrFrom4(ip.As4()) + } if ip.IsMulticast() { return true } - if v4 := ip.To4(); v4 != nil { - return special4.Contains(v4) + if ip.Is4() { + return special4.ContainsAddr(ip) } - return special6.Contains(ip) + return special6.ContainsAddr(ip) } var ( @@ -175,19 +192,31 @@ var ( // - LAN addresses are OK if relayed by a LAN host. // - All other addresses are always acceptable. func CheckRelayIP(sender, addr net.IP) error { - if len(addr) != net.IPv4len && len(addr) != net.IPv6len { + return CheckRelayAddr(IPToAddr(sender), IPToAddr(addr)) +} + +// CheckRelayAddr reports whether an IP relayed from the given sender IP +// is a valid connection target. +// +// There are four rules: +// - Special network addresses are never valid. +// - Loopback addresses are OK if relayed by a loopback host. +// - LAN addresses are OK if relayed by a LAN host. +// - All other addresses are always acceptable. +func CheckRelayAddr(sender, addr netip.Addr) error { + if !addr.IsValid() { return errInvalid } if addr.IsUnspecified() { return errUnspecified } - if IsSpecialNetwork(addr) { + if AddrIsSpecialNetwork(addr) { return errSpecial } if addr.IsLoopback() && !sender.IsLoopback() { return errLoopback } - if IsLAN(addr) && !IsLAN(sender) { + if AddrIsLAN(addr) && !AddrIsLAN(sender) { return errLAN } return nil @@ -221,17 +250,22 @@ type DistinctNetSet struct { Subnet uint // number of common prefix bits Limit uint // maximum number of IPs in each subnet - members map[string]uint - buf net.IP + members map[netip.Prefix]uint } // Add adds an IP address to the set. It returns false (and doesn't add the IP) if the // number of existing IPs in the defined range exceeds the limit. func (s *DistinctNetSet) Add(ip net.IP) bool { + return s.AddAddr(IPToAddr(ip)) +} + +// AddAddr adds an IP address to the set. It returns false (and doesn't add the IP) if the +// number of existing IPs in the defined range exceeds the limit. +func (s *DistinctNetSet) AddAddr(ip netip.Addr) bool { key := s.key(ip) - n := s.members[string(key)] + n := s.members[key] if n < s.Limit { - s.members[string(key)] = n + 1 + s.members[key] = n + 1 return true } return false @@ -239,20 +273,30 @@ func (s *DistinctNetSet) Add(ip net.IP) bool { // Remove removes an IP from the set. func (s *DistinctNetSet) Remove(ip net.IP) { + s.RemoveAddr(IPToAddr(ip)) +} + +// RemoveAddr removes an IP from the set. +func (s *DistinctNetSet) RemoveAddr(ip netip.Addr) { key := s.key(ip) - if n, ok := s.members[string(key)]; ok { + if n, ok := s.members[key]; ok { if n == 1 { - delete(s.members, string(key)) + delete(s.members, key) } else { - s.members[string(key)] = n - 1 + s.members[key] = n - 1 } } } // Contains whether the given IP is contained in the set. func (s DistinctNetSet) Contains(ip net.IP) bool { + return s.ContainsAddr(IPToAddr(ip)) +} + +// ContainsAddr whether the given IP is contained in the set. +func (s DistinctNetSet) ContainsAddr(ip netip.Addr) bool { key := s.key(ip) - _, ok := s.members[string(key)] + _, ok := s.members[key] return ok } @@ -265,54 +309,30 @@ func (s DistinctNetSet) Len() int { return int(n) } -// key encodes the map key for an address into a temporary buffer. -// -// The first byte of key is '4' or '6' to distinguish IPv4/IPv6 address types. -// The remainder of the key is the IP, truncated to the number of bits. -func (s *DistinctNetSet) key(ip net.IP) net.IP { +// key returns the map key for ip. +func (s *DistinctNetSet) key(ip netip.Addr) netip.Prefix { // Lazily initialize storage. if s.members == nil { - s.members = make(map[string]uint) - s.buf = make(net.IP, 17) - } - // Canonicalize ip and bits. - typ := byte('6') - if ip4 := ip.To4(); ip4 != nil { - typ, ip = '4', ip4 + s.members = make(map[netip.Prefix]uint) } - bits := s.Subnet - if bits > uint(len(ip)*8) { - bits = uint(len(ip) * 8) - } - // Encode the prefix into s.buf. - nb := int(bits / 8) - mask := ^byte(0xFF >> (bits % 8)) - s.buf[0] = typ - buf := append(s.buf[:1], ip[:nb]...) - if nb < len(ip) && mask != 0 { - buf = append(buf, ip[nb]&mask) + p, err := ip.Prefix(int(s.Subnet)) + if err != nil { + panic(err) } - return buf + return p } // String implements fmt.Stringer func (s DistinctNetSet) String() string { + keys := maps.Keys(s.members) + slices.SortFunc(keys, func(a, b netip.Prefix) int { + return strings.Compare(a.String(), b.String()) + }) + var buf bytes.Buffer buf.WriteString("{") - keys := make([]string, 0, len(s.members)) - for k := range s.members { - keys = append(keys, k) - } - sort.Strings(keys) for i, k := range keys { - var ip net.IP - if k[0] == '4' { - ip = make(net.IP, 4) - } else { - ip = make(net.IP, 16) - } - copy(ip, k[1:]) - fmt.Fprintf(&buf, "%v×%d", ip, s.members[k]) + fmt.Fprintf(&buf, "%v×%d", k, s.members[k]) if i != len(keys)-1 { buf.WriteString(" ") } diff --git a/p2p/netutil/net_test.go b/p2p/netutil/net_test.go index 3a6aa081f2c2..569c7ac45428 100644 --- a/p2p/netutil/net_test.go +++ b/p2p/netutil/net_test.go @@ -18,7 +18,9 @@ package netutil import ( "fmt" + "math/rand" "net" + "net/netip" "reflect" "testing" "testing/quick" @@ -29,7 +31,7 @@ import ( func TestParseNetlist(t *testing.T) { var tests = []struct { input string - wantErr error + wantErr string wantList *Netlist }{ { @@ -38,25 +40,27 @@ func TestParseNetlist(t *testing.T) { }, { input: "127.0.0.0/8", - wantErr: nil, - wantList: &Netlist{{IP: net.IP{127, 0, 0, 0}, Mask: net.CIDRMask(8, 32)}}, + wantList: &Netlist{netip.MustParsePrefix("127.0.0.0/8")}, }, { input: "127.0.0.0/44", - wantErr: &net.ParseError{Type: "CIDR address", Text: "127.0.0.0/44"}, + wantErr: `netip.ParsePrefix("127.0.0.0/44"): prefix length out of range`, }, { input: "127.0.0.0/16, 23.23.23.23/24,", wantList: &Netlist{ - {IP: net.IP{127, 0, 0, 0}, Mask: net.CIDRMask(16, 32)}, - {IP: net.IP{23, 23, 23, 0}, Mask: net.CIDRMask(24, 32)}, + netip.MustParsePrefix("127.0.0.0/16"), + netip.MustParsePrefix("23.23.23.23/24"), }, }, } for _, test := range tests { l, err := ParseNetlist(test.input) - if !reflect.DeepEqual(err, test.wantErr) { + if err == nil && test.wantErr != "" { + t.Errorf("%q: got no error, expected %q", test.input, test.wantErr) + continue + } else if err != nil && err.Error() != test.wantErr { t.Errorf("%q: got error %q, want %q", test.input, err, test.wantErr) continue } @@ -70,14 +74,12 @@ func TestParseNetlist(t *testing.T) { func TestNilNetListContains(t *testing.T) { var list *Netlist - checkContains(t, list.Contains, nil, []string{"1.2.3.4"}) + checkContains(t, list.Contains, list.ContainsAddr, nil, []string{"1.2.3.4"}) } func TestIsLAN(t *testing.T) { - checkContains(t, IsLAN, + checkContains(t, IsLAN, AddrIsLAN, []string{ // included - "0.0.0.0", - "0.2.0.8", "127.0.0.1", "10.0.1.1", "10.22.0.3", @@ -86,25 +88,35 @@ func TestIsLAN(t *testing.T) { "fe80::f4a1:8eff:fec5:9d9d", "febf::ab32:2233", "fc00::4", + // 4-in-6 + "::ffff:127.0.0.1", + "::ffff:10.10.0.2", }, []string{ // excluded "192.0.2.1", "1.0.0.0", "172.32.0.1", "fec0::2233", + // 4-in-6 + "::ffff:88.99.100.2", }, ) } func TestIsSpecialNetwork(t *testing.T) { - checkContains(t, IsSpecialNetwork, + checkContains(t, IsSpecialNetwork, AddrIsSpecialNetwork, []string{ // included + "0.0.0.0", + "0.2.0.8", "192.0.2.1", "192.0.2.44", "2001:db8:85a3:8d3:1319:8a2e:370:7348", "255.255.255.255", "224.0.0.22", // IPv4 multicast "ff05::1:3", // IPv6 multicast + // 4-in-6 + "::ffff:255.255.255.255", + "::ffff:192.0.2.1", }, []string{ // excluded "192.0.3.1", @@ -115,15 +127,21 @@ func TestIsSpecialNetwork(t *testing.T) { ) } -func checkContains(t *testing.T, fn func(net.IP) bool, inc, exc []string) { +func checkContains(t *testing.T, fn func(net.IP) bool, fn2 func(netip.Addr) bool, inc, exc []string) { for _, s := range inc { if !fn(parseIP(s)) { - t.Error("returned false for included address", s) + t.Error("returned false for included net.IP", s) + } + if !fn2(netip.MustParseAddr(s)) { + t.Error("returned false for included netip.Addr", s) } } for _, s := range exc { if fn(parseIP(s)) { - t.Error("returned true for excluded address", s) + t.Error("returned true for excluded net.IP", s) + } + if fn2(netip.MustParseAddr(s)) { + t.Error("returned true for excluded netip.Addr", s) } } } @@ -244,14 +262,22 @@ func TestDistinctNetSet(t *testing.T) { } func TestDistinctNetSetAddRemove(t *testing.T) { - cfg := &quick.Config{} - fn := func(ips []net.IP) bool { + cfg := &quick.Config{ + Values: func(s []reflect.Value, rng *rand.Rand) { + slice := make([]netip.Addr, rng.Intn(20)+1) + for i := range slice { + slice[i] = RandomAddr(rng, false) + } + s[0] = reflect.ValueOf(slice) + }, + } + fn := func(ips []netip.Addr) bool { s := DistinctNetSet{Limit: 3, Subnet: 2} for _, ip := range ips { - s.Add(ip) + s.AddAddr(ip) } for _, ip := range ips { - s.Remove(ip) + s.RemoveAddr(ip) } return s.Len() == 0 } diff --git a/p2p/server.go b/p2p/server.go index 13eebed3f4f1..22e5f6cb9444 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -905,14 +905,14 @@ func (srv *Server) listenLoop() { break } - remoteIP := netutil.AddrIP(fd.RemoteAddr()) + remoteIP := netutil.AddrAddr(fd.RemoteAddr()) if err := srv.checkInboundConn(remoteIP); err != nil { srv.log.Debug("Rejected inbound connection", "addr", fd.RemoteAddr(), "err", err) fd.Close() slots <- struct{}{} continue } - if remoteIP != nil { + if remoteIP.IsValid() { fd = newMeteredConn(fd) serveMeter.Mark(1) srv.log.Trace("Accepted connection", "addr", fd.RemoteAddr()) @@ -924,18 +924,19 @@ func (srv *Server) listenLoop() { } } -func (srv *Server) checkInboundConn(remoteIP net.IP) error { - if remoteIP == nil { +func (srv *Server) checkInboundConn(remoteIP netip.Addr) error { + if !remoteIP.IsValid() { + // This case happens for internal test connections without remote address. return nil } // Reject connections that do not match NetRestrict. - if srv.NetRestrict != nil && !srv.NetRestrict.Contains(remoteIP) { + if srv.NetRestrict != nil && !srv.NetRestrict.ContainsAddr(remoteIP) { return errors.New("not in netrestrict list") } // Reject Internet peers that try too often. now := srv.clock.Now() srv.inboundHistory.expire(now, nil) - if !netutil.IsLAN(remoteIP) && srv.inboundHistory.contains(remoteIP.String()) { + if !netutil.AddrIsLAN(remoteIP) && srv.inboundHistory.contains(remoteIP.String()) { return errors.New("too many attempts") } srv.inboundHistory.add(remoteIP.String(), now.Add(inboundThrottleTime)) @@ -1108,7 +1109,7 @@ func (srv *Server) NodeInfo() *NodeInfo { Name: srv.Name, Enode: node.URLv4(), ID: node.ID().String(), - IP: node.IP().String(), + IP: node.IPAddr().String(), ListenAddr: srv.ListenAddr, Protocols: make(map[string]interface{}), } diff --git a/p2p/server_nat_test.go b/p2p/server_nat_test.go index de935fcfc56d..cbb1f37e0a6a 100644 --- a/p2p/server_nat_test.go +++ b/p2p/server_nat_test.go @@ -18,6 +18,7 @@ package p2p import ( "net" + "net/netip" "sync/atomic" "testing" "time" @@ -64,8 +65,8 @@ func TestServerPortMapping(t *testing.T) { t.Error("wrong request count:", reqCount) } enr := srv.LocalNode().Node() - if enr.IP().String() != "192.0.2.0" { - t.Error("wrong IP in ENR:", enr.IP()) + if enr.IPAddr() != netip.MustParseAddr("192.0.2.0") { + t.Error("wrong IP in ENR:", enr.IPAddr()) } if enr.TCP() != 30000 { t.Error("wrong TCP port in ENR:", enr.TCP()) From 6c518fe6068726679016123d574a0523b2855168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Thu, 6 Jun 2024 09:52:57 +0200 Subject: [PATCH 336/571] build: upgrade -dlgo version to Go 1.22.4 (#29938) --- build/checksums.txt | 89 ++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 94cac9738c1e..d099e53156e6 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,48 +5,55 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.22.3 +# version:golang 1.22.4 # https://go.dev/dl/ -80648ef34f903193d72a59c0dff019f5f98ae0c9aa13ade0b0ecbff991a76f68 go1.22.3.src.tar.gz -adc9f5fee89cd53d907eb542d3b269d9d8a08a66bf1ab42175450ffbb58733fb go1.22.3.aix-ppc64.tar.gz -610e48c1df4d2f852de8bc2e7fd2dc1521aac216f0c0026625db12f67f192024 go1.22.3.darwin-amd64.tar.gz -02abeab3f4b8981232237ebd88f0a9bad933bc9621791cd7720a9ca29eacbe9d go1.22.3.darwin-arm64.tar.gz -a5b3d54905f17af2ceaf7fcfe92edee67a5bd4eccd962dd89df719ace3e0894d go1.22.3.dragonfly-amd64.tar.gz -b9989ca87695ae93bacde6f3aa7b13cde5f3825515eb9ed9bbef014273739889 go1.22.3.freebsd-386.tar.gz -7483961fae29d7d768afd5c9c0f229354ca3263ab7119c20bc182761f87cbc74 go1.22.3.freebsd-amd64.tar.gz -edf1f0b8ecf68b14faeedb4f5d868a58c4777a0282bd85e5115c39c010cd0130 go1.22.3.freebsd-arm.tar.gz -572eb70e5e835fbff7d53ebf473f611d7eb458c428f8dbd98a49196883c3309e go1.22.3.freebsd-arm64.tar.gz -ef94eb2b74402e436dce970584222c4e454eb3093908591149bd2ded6862b8af go1.22.3.freebsd-riscv64.tar.gz -3c3f498c68334cbd11f72aadfb6bcb507eb8436cebc50f437a0523cd4c5e03d1 go1.22.3.illumos-amd64.tar.gz -fefba30bb0d3dd1909823ee38c9f1930c3dc5337a2ac4701c2277a329a386b57 go1.22.3.linux-386.tar.gz -8920ea521bad8f6b7bc377b4824982e011c19af27df88a815e3586ea895f1b36 go1.22.3.linux-amd64.tar.gz -6c33e52a5b26e7aa021b94475587fce80043a727a54ceb0eee2f9fc160646434 go1.22.3.linux-arm64.tar.gz -f2bacad20cd2b96f23a86d4826525d42b229fd431cc6d0dec61ff3bc448ef46e go1.22.3.linux-armv6l.tar.gz -41e9328340544893482b2928ae18a9a88ba18b2fdd29ac77f4d33cf1815bbdc2 go1.22.3.linux-loong64.tar.gz -cf4d5faff52e642492729eaf396968f43af179518be769075b90bc1bf650abf6 go1.22.3.linux-mips.tar.gz -3bd009fe2e3d2bfd52433a11cb210d1dfa50b11b4c347a293951efd9e36de945 go1.22.3.linux-mips64.tar.gz -5913b82a042188ef698f7f2dfd0cd0c71f0508a4739de9e41fceff3f4dc769b4 go1.22.3.linux-mips64le.tar.gz -441afebca555be5313867b4577f237c7b5c0fff4386e22e47875b9f805abbec5 go1.22.3.linux-mipsle.tar.gz -f3b53190a76f4a35283501ba6d94cbb72093be0c62ff735c6f9e586a1c983381 go1.22.3.linux-ppc64.tar.gz -04b7b05283de30dd2da20bf3114b2e22cc727938aed3148babaf35cc951051ac go1.22.3.linux-ppc64le.tar.gz -d4992d4a85696e3f1de06cefbfc2fd840c9c6695d77a0f35cfdc4e28b2121c20 go1.22.3.linux-riscv64.tar.gz -2aba796417a69be5f3ed489076bac79c1c02b36e29422712f9f3bf51da9cf2d4 go1.22.3.linux-s390x.tar.gz -d6e6113542dd9f23db899e177fe23772bac114a5ea5e8ee436b9da68628335a8 go1.22.3.netbsd-386.tar.gz -c33cee3075bd18ceefddd75bafa8efb51fbdc17b5ee74275122e7a927a237a4c go1.22.3.netbsd-amd64.tar.gz -1ab251df3c85f3b391a09565ca52fb6e1306527d72852d553e9ab74eabb4ecf8 go1.22.3.netbsd-arm.tar.gz -1d194fe53f5d82f9a612f848950d8af8cab7cb40ccc03f10c4eb1c9808ff1a0c go1.22.3.netbsd-arm64.tar.gz -91d6601727f08506e938640885d3ded784925045e3a4444fd9b4b936efe1b1e0 go1.22.3.openbsd-386.tar.gz -09d0c91ae35a4eea92615426992062ca236cc2f66444fb0b0a24cd3b13bd5297 go1.22.3.openbsd-amd64.tar.gz -338da30cc2c97b9458e0b4caa2509f67bba55d3de16fb7d31775baca82d2e3dc go1.22.3.openbsd-arm.tar.gz -53eadfabd2b7dd09a64941421afee2a2888e2a4f94f353b27919b1dad1171a21 go1.22.3.openbsd-arm64.tar.gz -8a1a2842ae8dcf2374bb05dff58074b368bb698dc9c211c794c1ff119cd9fdc7 go1.22.3.plan9-386.tar.gz -f9816d3dd9e730cad55085ea08c1f0c925720728f9c945fff59cd24d2ac2db7b go1.22.3.plan9-amd64.tar.gz -f4d3d7b17c9e1b1635fcb287b5b5ab5b60acc9db3ba6a27f2b2f5d6537a2ef95 go1.22.3.plan9-arm.tar.gz -46b7999ee94d91b21ad6940b5a3131ff6fe53ef97be9a34e582e2a3ad7263e95 go1.22.3.solaris-amd64.tar.gz -f60f63b8a0885e0d924f39fd284aee5438fe87d8c3d8545a312adf43e0d9edac go1.22.3.windows-386.zip -cab2af6951a6e2115824263f6df13ff069c47270f5788714fa1d776f7f60cb39 go1.22.3.windows-amd64.zip -40b37f4b068fc759f3a0dd61176a0f7570a4ba48bed8561c31d3967a3583981a go1.22.3.windows-arm.zip -59b76ee22b9b1c3afbf7f50e3cb4edb954d6c0d25e5e029ab5483a6804d61e71 go1.22.3.windows-arm64.zip +fed720678e728a7ca30ba8d1ded1caafe27d16028fab0232b8ba8e22008fb784 go1.22.4.src.tar.gz +b9647fa9fc83a0cc5d4f092a19eaeaecf45f063a5aa7d4962fde65aeb7ae6ce1 go1.22.4.aix-ppc64.tar.gz +7788f40f3a46f201df1dc46ca640403eb535d5513fc33449164a90dbd229b761 go1.22.4.darwin-amd64.pkg +c95967f50aa4ace34af0c236cbdb49a9a3e80ee2ad09d85775cb4462a5c19ed3 go1.22.4.darwin-amd64.tar.gz +4036c88faf57a6b096916f1827edcdbf5290a47cc5f59956e88cdd9b1b71088c go1.22.4.darwin-arm64.pkg +242b78dc4c8f3d5435d28a0d2cec9b4c1aa999b601fb8aa59fb4e5a1364bf827 go1.22.4.darwin-arm64.tar.gz +f2fbb51af4719d3616efb482d6ed2b96579b474156f85a7ddc6f126764feec4b go1.22.4.dragonfly-amd64.tar.gz +7c54884bb9f274884651d41e61d1bc12738863ad1497e97ea19ad0e9aa6bf7b5 go1.22.4.freebsd-386.tar.gz +88d44500e1701dd35797619774d6dd51bf60f45a8338b0a82ddc018e4e63fb78 go1.22.4.freebsd-amd64.tar.gz +3d9efe47db142a22679aba46b1772e3900b0d87ae13bd2b3bc80dbf2ac0b2cd6 go1.22.4.freebsd-arm.tar.gz +726dc093cf020277be45debf03c3b02b43c2efb3e2a5d4fba8f52579d65327dc go1.22.4.freebsd-arm64.tar.gz +5f6b67e5e32f1d6ccb2d4dcb44934a5e2e870a877ba7443d86ec43cfc28afa71 go1.22.4.freebsd-riscv64.tar.gz +d56ecc2f85b6418a21ef83879594d0c42ab4f65391a676bb12254870e6690d63 go1.22.4.illumos-amd64.tar.gz +47a2a8d249a91eb8605c33bceec63aedda0441a43eac47b4721e3975ff916cec go1.22.4.linux-386.tar.gz +ba79d4526102575196273416239cca418a651e049c2b099f3159db85e7bade7d go1.22.4.linux-amd64.tar.gz +a8e177c354d2e4a1b61020aca3562e27ea3e8f8247eca3170e3fa1e0c2f9e771 go1.22.4.linux-arm64.tar.gz +e2b143fbacbc9cbd448e9ef41ac3981f0488ce849af1cf37e2341d09670661de go1.22.4.linux-armv6l.tar.gz +e2ff9436e4b34bf6926b06d97916e26d67a909a2effec17967245900f0816f1d go1.22.4.linux-loong64.tar.gz +73f0dcc60458c4770593b05a7bc01cc0d31fc98f948c0c2334812c7a1f2fc3f1 go1.22.4.linux-mips.tar.gz +417af97fc2630a647052375768be4c38adcc5af946352ea5b28613ea81ca5d45 go1.22.4.linux-mips64.tar.gz +7486e2d7dd8c98eb44df815ace35a7fe7f30b7c02326e3741bd934077508139b go1.22.4.linux-mips64le.tar.gz +69479c8aad301e459a8365b40cad1074a0dbba5defb9291669f94809c4c4be6e go1.22.4.linux-mipsle.tar.gz +dd238847e65bc3e2745caca475a5db6522a2fcf85cf6c38fc36a06642b19efd7 go1.22.4.linux-ppc64.tar.gz +a3e5834657ef92523f570f798fed42f1f87bc18222a16815ec76b84169649ec4 go1.22.4.linux-ppc64le.tar.gz +56a827ff7dc6245bcd7a1e9288dffaa1d8b0fd7468562264c1523daf3b4f1b4a go1.22.4.linux-riscv64.tar.gz +7590c3e278e2dc6040aae0a39da3ca1eb2e3921673a7304cc34d588c45889eec go1.22.4.linux-s390x.tar.gz +ddd2eebe34471a2502de6c5dad04ab27c9fc80cbde7a9ad5b3c66ecec4504e1d go1.22.4.netbsd-386.tar.gz +33af79f6f935f6fbacc5d23876450b3567b79348fc065beef8e64081127dd234 go1.22.4.netbsd-amd64.tar.gz +fa3550ebd5375a70b3bcd342b5a71f4bd271dcbbfaf4eabefa2144ab5d8924b6 go1.22.4.netbsd-arm.tar.gz +c9a2971dec9f6d320c6f2b049b2353c6d0a2d35e87b8a4b2d78a2f0d62545f8e go1.22.4.netbsd-arm64.tar.gz +d21af022331bfdc2b5b161d616c3a1a4573d33cf7a30416ee509a8f3641deb47 go1.22.4.openbsd-386.tar.gz +72c0094c43f7e5722ec49c2a3e9dfa7a1123ac43a5f3a63eecf3e3795d3ff0ae go1.22.4.openbsd-amd64.tar.gz +1096831ea3c5ea3ca57d14251d9eda3786889531eb40d7d6775dcaa324d4b065 go1.22.4.openbsd-arm.tar.gz +a7ab8d4e0b02bf06ed144ba42c61c0e93ee00f2b433415dfd4ad4b6e79f31650 go1.22.4.openbsd-arm64.tar.gz +9716327c8a628358798898dc5148c49dbbeb5196bf2cbf088e550721a6e4f60b go1.22.4.openbsd-ppc64.tar.gz +a8dd4503c95c32a502a616ab78870a19889c9325fe9bd31eb16dd69346e4bfa8 go1.22.4.plan9-386.tar.gz +5423a25808d76fe5aca8607a2e5ac5673abf45446b168cb5e9d8519ee9fe39a1 go1.22.4.plan9-amd64.tar.gz +6af939ad583f5c85c09c53728ab7d38c3cc2b39167562d6c18a07c5c6608b370 go1.22.4.plan9-arm.tar.gz +e8cabe69c03085725afdb32a6f9998191a3e55a747b270d835fd05000d56abba go1.22.4.solaris-amd64.tar.gz +5c6446e2ea80bc6a971d2b34446f16e6517e638b0ff8d3ea229228d1931790b0 go1.22.4.windows-386.msi +aca4e2c37278a10f1c70dd0df142f7d66b50334fcee48978d409202d308d6d25 go1.22.4.windows-386.zip +3c21105d7b584759b6e266383b777caf6e87142d304a10b539dbc66ab482bb5f go1.22.4.windows-amd64.msi +26321c4d945a0035d8a5bc4a1965b0df401ff8ceac66ce2daadabf9030419a98 go1.22.4.windows-amd64.zip +c4303f02b864304eb83dd1db0b4ebf9d2ec9d216e7ef44a7657b166a52889c7f go1.22.4.windows-arm.msi +5fcd0671a49cecf39b41021621ee1b6e7aa1370f37122b72e80d4fd4185833b6 go1.22.4.windows-arm.zip +553cc6c460f4e3eb4fad5b897c0bb22cd8bbeb20929f0e3eeb939420320292ce go1.22.4.windows-arm64.msi +8a2daa9ea28cbdafddc6171aefed384f4e5b6e714fb52116fe9ed25a132f37ed go1.22.4.windows-arm64.zip # version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ From cbbfa3eac05b816a704ef2e50ab0a7ac8a9c4dcc Mon Sep 17 00:00:00 2001 From: Marquis Shanahan <29431502+9547@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:55:38 +0800 Subject: [PATCH 337/571] rlp: no need to repeat called len method (#29936) rlp: no need to repeat calling len --- rlp/raw.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/rlp/raw.go b/rlp/raw.go index 773aa7e614e8..879e3bfe5d49 100644 --- a/rlp/raw.go +++ b/rlp/raw.go @@ -30,33 +30,33 @@ var rawValueType = reflect.TypeOf(RawValue{}) // StringSize returns the encoded size of a string. func StringSize(s string) uint64 { - switch { - case len(s) == 0: + switch n := len(s); n { + case 0: return 1 - case len(s) == 1: + case 1: if s[0] <= 0x7f { return 1 } else { return 2 } default: - return uint64(headsize(uint64(len(s))) + len(s)) + return uint64(headsize(uint64(n)) + n) } } // BytesSize returns the encoded size of a byte slice. func BytesSize(b []byte) uint64 { - switch { - case len(b) == 0: + switch n := len(b); n { + case 0: return 1 - case len(b) == 1: + case 1: if b[0] <= 0x7f { return 1 } else { return 2 } default: - return uint64(headsize(uint64(len(b))) + len(b)) + return uint64(headsize(uint64(n)) + n) } } @@ -105,18 +105,20 @@ func SplitUint64(b []byte) (x uint64, rest []byte, err error) { if err != nil { return 0, b, err } - switch { - case len(content) == 0: + switch n := len(content); n { + case 0: return 0, rest, nil - case len(content) == 1: + case 1: if content[0] == 0 { return 0, b, ErrCanonInt } return uint64(content[0]), rest, nil - case len(content) > 8: - return 0, b, errUintOverflow default: - x, err = readSize(content, byte(len(content))) + if n > 8 { + return 0, b, errUintOverflow + } + + x, err = readSize(content, byte(n)) if err != nil { return 0, b, ErrCanonInt } From 0750cb0c8f384ade3213ac3eb18dde214fcc1864 Mon Sep 17 00:00:00 2001 From: Hteev Oli Date: Thu, 6 Jun 2024 15:56:41 +0800 Subject: [PATCH 338/571] p2p/netutil: fix comments (#29942) --- p2p/netutil/net.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/netutil/net.go b/p2p/netutil/net.go index 474912978e62..7d8da886704b 100644 --- a/p2p/netutil/net.go +++ b/p2p/netutil/net.go @@ -288,12 +288,12 @@ func (s *DistinctNetSet) RemoveAddr(ip netip.Addr) { } } -// Contains whether the given IP is contained in the set. +// Contains reports whether the given IP is contained in the set. func (s DistinctNetSet) Contains(ip net.IP) bool { return s.ContainsAddr(IPToAddr(ip)) } -// ContainsAddr whether the given IP is contained in the set. +// ContainsAddr reports whether the given IP is contained in the set. func (s DistinctNetSet) ContainsAddr(ip netip.Addr) bool { key := s.key(ip) _, ok := s.members[key] From 85459e14395dcd083076ee356358aec961aa35cc Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 6 Jun 2024 15:15:22 +0200 Subject: [PATCH 339/571] p2p/discover: unwrap 4-in-6 UDP source addresses (#29944) Fixes an issue where discovery responses were not recognized. --- p2p/discover/v4_udp.go | 5 +++++ p2p/discover/v5_udp.go | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 6234fd93ca5f..cca01bd3ce79 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -557,6 +557,11 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { } func (t *UDPv4) handlePacket(from netip.AddrPort, buf []byte) error { + // Unwrap IPv4-in-6 source address. + if from.Addr().Is4In6() { + from = netip.AddrPortFrom(netip.AddrFrom4(from.Addr().As4()), from.Port()) + } + rawpacket, fromKey, hash, err := v4wire.Decode(buf) if err != nil { t.log.Debug("Bad discv4 packet", "addr", from, "err", err) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 4cc21cd9c584..81d94812aab4 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -674,6 +674,10 @@ func (t *UDPv5) readLoop() { // dispatchReadPacket sends a packet into the dispatch loop. func (t *UDPv5) dispatchReadPacket(from netip.AddrPort, content []byte) bool { + // Unwrap IPv4-in-6 source address. + if from.Addr().Is4In6() { + from = netip.AddrPortFrom(netip.AddrFrom4(from.Addr().As4()), from.Port()) + } select { case t.packetInCh <- ReadPacket{content, from}: return true From 0dd173a727dd2d2409b8e401b22e85d20c25b71f Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Thu, 6 Jun 2024 21:17:53 +0800 Subject: [PATCH 340/571] params: release Geth v1.14.5 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 5ae1187b82d5..f812cc0c1b11 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 5 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 4461c1fc17c489f1df86dea1ebde4247c6305ea4 Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Thu, 6 Jun 2024 21:23:44 +0800 Subject: [PATCH 341/571] params: begin v1.14.6 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index f812cc0c1b11..48bca3c5b2fe 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 6 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 4405f1851953ff75758d4bd570244a6f6c49d32a Mon Sep 17 00:00:00 2001 From: Gealber Morales <48373523+Gealber@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:04:18 +0200 Subject: [PATCH 342/571] cmd/evm/internal/t8ntool: remove unused parameter (#29930) --- cmd/evm/internal/t8ntool/transition.go | 2 +- cmd/evm/internal/t8ntool/tx_iterator.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 8fd068b2ea14..fa052f59549b 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -181,7 +181,7 @@ func Transition(ctx *cli.Context) error { // Set the chain id chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) - if txIt, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil { + if txIt, err = loadTransactions(txStr, inputData, chainConfig); err != nil { return err } if err := applyLondonChecks(&prestate.Env, chainConfig); err != nil { diff --git a/cmd/evm/internal/t8ntool/tx_iterator.go b/cmd/evm/internal/t8ntool/tx_iterator.go index 046f62314dae..d4ebb4b399ea 100644 --- a/cmd/evm/internal/t8ntool/tx_iterator.go +++ b/cmd/evm/internal/t8ntool/tx_iterator.go @@ -112,7 +112,7 @@ func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Tran return signedTxs, nil } -func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *params.ChainConfig) (txIterator, error) { +func loadTransactions(txStr string, inputData *input, chainConfig *params.ChainConfig) (txIterator, error) { var txsWithKeys []*txWithKey if txStr != stdinSelector { data, err := os.ReadFile(txStr) From 6a49d13c13d967dd9fb2190fd110ef6d90fc09cd Mon Sep 17 00:00:00 2001 From: ucwong Date: Thu, 6 Jun 2024 01:48:22 +0800 Subject: [PATCH 343/571] go.mod : tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 8968140fbf19..9947df31f32a 100644 --- a/go.mod +++ b/go.mod @@ -68,6 +68,7 @@ require ( github.com/urfave/cli/v2 v2.25.7 go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.22.0 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.7.0 golang.org/x/sys v0.20.0 golang.org/x/text v0.14.0 @@ -139,7 +140,6 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.24.0 // indirect google.golang.org/protobuf v1.33.0 // indirect From deaf10982cc1a6e02c133a8d70982a25b4ae3084 Mon Sep 17 00:00:00 2001 From: kukuru909 Date: Sat, 8 Jun 2024 20:00:53 +0900 Subject: [PATCH 344/571] cmd/clef, cmd/evm: fix markdown issues in README (#29954) --- cmd/clef/README.md | 4 ++-- cmd/evm/README.md | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/clef/README.md b/cmd/clef/README.md index cf0926513603..b7018a5f41ed 100644 --- a/cmd/clef/README.md +++ b/cmd/clef/README.md @@ -225,8 +225,8 @@ Response - `value` [number:optional]: amount of Wei to send with the transaction - `data` [data:optional]: input data - `nonce` [number]: account nonce - 1. method signature [string:optional] - - The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected. + 2. method signature [string:optional] + - The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected. #### Result diff --git a/cmd/evm/README.md b/cmd/evm/README.md index 25647c18a9ac..f95b6b4d7b3b 100644 --- a/cmd/evm/README.md +++ b/cmd/evm/README.md @@ -14,15 +14,15 @@ The `evm t8n` tool is a stateless state transition utility. It is a utility which can 1. Take a prestate, including - - Accounts, - - Block context information, - - Previous blockshashes (*optional) + - Accounts, + - Block context information, + - Previous blockshashes (*optional) 2. Apply a set of transactions, 3. Apply a mining-reward (*optional), 4. And generate a post-state, including - - State root, transaction root, receipt root, - - Information about rejected transactions, - - Optionally: a full or partial post-state dump + - State root, transaction root, receipt root, + - Information about rejected transactions, + - Optionally: a full or partial post-state dump ### Specification From 1098d148a51c929fd9829328fe60ca1214f3c7b5 Mon Sep 17 00:00:00 2001 From: Ha DANG Date: Sat, 8 Jun 2024 18:04:16 +0700 Subject: [PATCH 345/571] cmd/geth: remove unused param (#29952) --- cmd/geth/chaincmd.go | 5 ++--- cmd/geth/snapshot.go | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index d787f340a38b..2965b99d94f9 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) @@ -516,7 +515,7 @@ func importPreimages(ctx *cli.Context) error { return nil } -func parseDumpConfig(ctx *cli.Context, stack *node.Node, db ethdb.Database) (*state.DumpConfig, common.Hash, error) { +func parseDumpConfig(ctx *cli.Context, db ethdb.Database) (*state.DumpConfig, common.Hash, error) { var header *types.Header if ctx.NArg() > 1 { return nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg()) @@ -580,7 +579,7 @@ func dump(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() - conf, root, err := parseDumpConfig(ctx, stack, db) + conf, root, err := parseDumpConfig(ctx, db) if err != nil { return err } diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index cf7093e60560..7d713ad1109a 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -544,7 +544,7 @@ func dumpState(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() - conf, root, err := parseDumpConfig(ctx, stack, db) + conf, root, err := parseDumpConfig(ctx, db) if err != nil { return err } From 349fcdd22d672fedc59a893e6ebb65349c3dfcdf Mon Sep 17 00:00:00 2001 From: Gealber Morales <48373523+Gealber@users.noreply.github.com> Date: Sun, 9 Jun 2024 22:47:51 +0200 Subject: [PATCH 346/571] p2p/discover: add missing lock when calling tab.handleAddNode (#29960) --- p2p/discover/table.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/p2p/discover/table.go b/p2p/discover/table.go index bb5ab4f3fcd9..8045f1389e86 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -452,7 +452,9 @@ func (tab *Table) loadSeedNodes() { addr, _ := seed.UDPEndpoint() tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", addr, "age", age) } + tab.mutex.Lock() tab.handleAddNode(addNodeOp{node: seed, isInbound: false}) + tab.mutex.Unlock() } } From 8bda6429637c6219be5e0965fab15810fed3dced Mon Sep 17 00:00:00 2001 From: Gealber Morales <48373523+Gealber@users.noreply.github.com> Date: Sun, 9 Jun 2024 22:50:22 +0200 Subject: [PATCH 347/571] p2p: use package slices to sort in PeersInfo (#29957) --- p2p/server.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/p2p/server.go b/p2p/server.go index 22e5f6cb9444..172f0667eb13 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -19,6 +19,7 @@ package p2p import ( "bytes" + "cmp" "crypto/ecdsa" "encoding/hex" "errors" @@ -1140,12 +1141,9 @@ func (srv *Server) PeersInfo() []*PeerInfo { } } // Sort the result array alphabetically by node identifier - for i := 0; i < len(infos); i++ { - for j := i + 1; j < len(infos); j++ { - if infos[i].ID > infos[j].ID { - infos[i], infos[j] = infos[j], infos[i] - } - } - } + slices.SortFunc(infos, func(a, b *PeerInfo) int { + return cmp.Compare(a.ID, b.ID) + }) + return infos } From db273c8733309d415b0c1296aa8630e67930d16d Mon Sep 17 00:00:00 2001 From: jwasinger Date: Sun, 9 Jun 2024 22:58:50 -0700 Subject: [PATCH 348/571] core: initialize developer genesis beacon root contract with 0 balance (#29963) --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index f1b4490f2e22..4ca24807fccd 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -594,7 +594,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b // Pre-deploy EIP-4788 system contract - params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode}, + params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, }, } if faucet != nil { From 2eb185c92b2655ceee91b730fc5904379fe0ff6f Mon Sep 17 00:00:00 2001 From: TinyFoxy Date: Mon, 10 Jun 2024 20:55:47 +0800 Subject: [PATCH 349/571] core, rlp: remove duplicated words (#29964) --- core/state/snapshot/iterator_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/snapshot/iterator_test.go b/core/state/snapshot/iterator_test.go index 54614427a5cf..daa8cdcc543a 100644 --- a/core/state/snapshot/iterator_test.go +++ b/core/state/snapshot/iterator_test.go @@ -815,7 +815,7 @@ func TestStorageIteratorDeletions(t *testing.T) { verifyIterator(t, 2, snaps.Snapshot(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage) } -// BenchmarkAccountIteratorTraversal is a bit a bit notorious -- all layers contain the +// BenchmarkAccountIteratorTraversal is a bit notorious -- all layers contain the // exact same 200 accounts. That means that we need to process 2000 items, but // only spit out 200 values eventually. // From 85587d5ef2da92edc009b85146200e4012f9f6ed Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 11 Jun 2024 01:10:07 -0700 Subject: [PATCH 350/571] cmd, core: prefetch reads too from tries if requested (#29807) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * cmd/utils, consensus/beacon, core/state: when configured via stub flag: prefetch all reads from account/storage tries, terminate prefetcher synchronously. * cmd, core/state: fix nil panic, fix error handling, prefetch nosnap too * core/state: expand prefetcher metrics for reads and writes separately * cmd/utils, eth: fix noop collect witness flag --------- Co-authored-by: Péter Szilágyi --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 13 ++- core/blockchain.go | 2 +- core/state/state_object.go | 10 +- core/state/statedb.go | 16 ++- core/state/trie_prefetcher.go | 162 +++++++++++++++++++++-------- core/state/trie_prefetcher_test.go | 6 +- core/vm/interpreter.go | 1 + eth/backend.go | 1 + eth/ethconfig/config.go | 3 + 10 files changed, 159 insertions(+), 56 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b7885608bc17..f6bb09ee54a5 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -156,6 +156,7 @@ var ( utils.BeaconGenesisRootFlag, utils.BeaconGenesisTimeFlag, utils.BeaconCheckpointFlag, + utils.CollectWitnessFlag, }, utils.NetworkFlags, utils.DatabaseFlags) rpcFlags = []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ecf6acc18606..46d380b98499 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -604,6 +604,11 @@ var ( Usage: "Disables db compaction after import", Category: flags.LoggingCategory, } + CollectWitnessFlag = &cli.BoolFlag{ + Name: "collectwitness", + Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.", + Category: flags.MiscCategory, + } // MISC settings SyncTargetFlag = &cli.StringFlag{ @@ -1760,6 +1765,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // TODO(fjl): force-enable this in --dev mode cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name) } + if ctx.IsSet(CollectWitnessFlag.Name) { + cfg.EnableWitnessCollection = ctx.Bool(CollectWitnessFlag.Name) + } if ctx.IsSet(RPCGlobalGasCapFlag.Name) { cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name) @@ -2190,7 +2198,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) { cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 } - vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} + vmcfg := vm.Config{ + EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name), + EnableWitnessCollection: ctx.Bool(CollectWitnessFlag.Name), + } if ctx.IsSet(VMTraceFlag.Name) { if name := ctx.String(VMTraceFlag.Name); name != "" { var config json.RawMessage diff --git a/core/blockchain.go b/core/blockchain.go index 7c8ab3abc44a..ac4eb1c47e1c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1809,7 +1809,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // while processing transactions. Before Byzantium the prefetcher is mostly // useless due to the intermediate root hashing after each transaction. if bc.chainConfig.IsByzantium(block.Number()) { - statedb.StartPrefetcher("chain") + statedb.StartPrefetcher("chain", !bc.vmConfig.EnableWitnessCollection) } activeState = statedb diff --git a/core/state/state_object.go b/core/state/state_object.go index b7a215bd1753..16a5f3e5e211 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -230,6 +230,14 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { } value.SetBytes(val) } + // Independent of where we loaded the data from, add it to the prefetcher. + // Whilst this would be a bit weird if snapshots are disabled, but we still + // want the trie nodes to end up in the prefetcher too, so just push through. + if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash { + if err = s.db.prefetcher.prefetch(s.addrHash, s.origin.Root, s.address, [][]byte{key[:]}, true); err != nil { + log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err) + } + } s.originStorage[key] = value return value } @@ -293,7 +301,7 @@ func (s *stateObject) finalise() { s.pendingStorage[key] = value } if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { - if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch); err != nil { + if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch, false); err != nil { log.Error("Failed to prefetch slots", "addr", s.address, "slots", len(slotsToPrefetch), "err", err) } } diff --git a/core/state/statedb.go b/core/state/statedb.go index 61e76cdd7788..b4ef0a6e47bc 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -200,14 +200,14 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) { // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. -func (s *StateDB) StartPrefetcher(namespace string) { +func (s *StateDB) StartPrefetcher(namespace string, noreads bool) { if s.prefetcher != nil { s.prefetcher.terminate(false) s.prefetcher.report() s.prefetcher = nil } if s.snap != nil { - s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace) + s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, noreads) // With the switch to the Proof-of-Stake consensus algorithm, block production // rewards are now handled at the consensus layer. Consequently, a block may @@ -218,7 +218,7 @@ func (s *StateDB) StartPrefetcher(namespace string) { // To prevent this, the account trie is always scheduled for prefetching once // the prefetcher is constructed. For more details, see: // https://github.com/ethereum/go-ethereum/issues/29880 - if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil); err != nil { + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil, false); err != nil { log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err) } } @@ -616,6 +616,14 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { return nil } } + // Independent of where we loaded the data from, add it to the prefetcher. + // Whilst this would be a bit weird if snapshots are disabled, but we still + // want the trie nodes to end up in the prefetcher too, so just push through. + if s.prefetcher != nil { + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]}, true); err != nil { + log.Error("Failed to prefetch account", "addr", addr, "err", err) + } + } // Insert into the live set obj := newObject(s, addr, data) s.setStateObject(obj) @@ -792,7 +800,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure } if s.prefetcher != nil && len(addressesToPrefetch) > 0 { - if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch); err != nil { + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch, false); err != nil { log.Error("Failed to prefetch addresses", "addresses", len(addressesToPrefetch), "err", err) } } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 5e5afbbeccfe..491b3807c8d3 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -44,31 +44,49 @@ type triePrefetcher struct { root common.Hash // Root hash of the account trie for metrics fetchers map[string]*subfetcher // Subfetchers for each trie term chan struct{} // Channel to signal interruption + noreads bool // Whether to ignore state-read-only prefetch requests deliveryMissMeter metrics.Meter - accountLoadMeter metrics.Meter - accountDupMeter metrics.Meter - accountWasteMeter metrics.Meter - storageLoadMeter metrics.Meter - storageDupMeter metrics.Meter - storageWasteMeter metrics.Meter + + accountLoadReadMeter metrics.Meter + accountLoadWriteMeter metrics.Meter + accountDupReadMeter metrics.Meter + accountDupWriteMeter metrics.Meter + accountDupCrossMeter metrics.Meter + accountWasteMeter metrics.Meter + + storageLoadReadMeter metrics.Meter + storageLoadWriteMeter metrics.Meter + storageDupReadMeter metrics.Meter + storageDupWriteMeter metrics.Meter + storageDupCrossMeter metrics.Meter + storageWasteMeter metrics.Meter } -func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePrefetcher { +func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher { prefix := triePrefetchMetricsPrefix + namespace return &triePrefetcher{ db: db, root: root, fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map term: make(chan struct{}), + noreads: noreads, deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil), - accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil), - accountDupMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup", nil), - accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil), - storageLoadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load", nil), - storageDupMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup", nil), - storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil), + + accountLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/read", nil), + accountLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/write", nil), + accountDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/read", nil), + accountDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/write", nil), + accountDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/cross", nil), + accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil), + + storageLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/read", nil), + storageLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/write", nil), + storageDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/read", nil), + storageDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/write", nil), + storageDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/cross", nil), + storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil), } } @@ -98,19 +116,31 @@ func (p *triePrefetcher) report() { fetcher.wait() // ensure the fetcher's idle before poking in its internals if fetcher.root == p.root { - p.accountLoadMeter.Mark(int64(len(fetcher.seen))) - p.accountDupMeter.Mark(int64(fetcher.dups)) + p.accountLoadReadMeter.Mark(int64(len(fetcher.seenRead))) + p.accountLoadWriteMeter.Mark(int64(len(fetcher.seenWrite))) + + p.accountDupReadMeter.Mark(int64(fetcher.dupsRead)) + p.accountDupWriteMeter.Mark(int64(fetcher.dupsWrite)) + p.accountDupCrossMeter.Mark(int64(fetcher.dupsCross)) + for _, key := range fetcher.used { - delete(fetcher.seen, string(key)) + delete(fetcher.seenRead, string(key)) + delete(fetcher.seenWrite, string(key)) } - p.accountWasteMeter.Mark(int64(len(fetcher.seen))) + p.accountWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite))) } else { - p.storageLoadMeter.Mark(int64(len(fetcher.seen))) - p.storageDupMeter.Mark(int64(fetcher.dups)) + p.storageLoadReadMeter.Mark(int64(len(fetcher.seenRead))) + p.storageLoadWriteMeter.Mark(int64(len(fetcher.seenWrite))) + + p.storageDupReadMeter.Mark(int64(fetcher.dupsRead)) + p.storageDupWriteMeter.Mark(int64(fetcher.dupsWrite)) + p.storageDupCrossMeter.Mark(int64(fetcher.dupsCross)) + for _, key := range fetcher.used { - delete(fetcher.seen, string(key)) + delete(fetcher.seenRead, string(key)) + delete(fetcher.seenWrite, string(key)) } - p.storageWasteMeter.Mark(int64(len(fetcher.seen))) + p.storageWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite))) } } } @@ -126,7 +156,11 @@ func (p *triePrefetcher) report() { // upon the same contract, the parameters invoking this method may be // repeated. // 2. Finalize of the main account trie. This happens only once per block. -func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) error { +func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte, read bool) error { + // If the state item is only being read, but reads are disabled, return + if read && p.noreads { + return nil + } // Ensure the subfetcher is still alive select { case <-p.term: @@ -139,7 +173,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm fetcher = newSubfetcher(p.db, p.root, owner, root, addr) p.fetchers[id] = fetcher } - return fetcher.schedule(keys) + return fetcher.schedule(keys, read) } // trie returns the trie matching the root hash, blocking until the fetcher of @@ -186,38 +220,51 @@ type subfetcher struct { addr common.Address // Address of the account that the trie belongs to trie Trie // Trie being populated with nodes - tasks [][]byte // Items queued up for retrieval - lock sync.Mutex // Lock protecting the task queue + tasks []*subfetcherTask // Items queued up for retrieval + lock sync.Mutex // Lock protecting the task queue wake chan struct{} // Wake channel if a new task is scheduled stop chan struct{} // Channel to interrupt processing term chan struct{} // Channel to signal interruption - seen map[string]struct{} // Tracks the entries already loaded - dups int // Number of duplicate preload tasks - used [][]byte // Tracks the entries used in the end + seenRead map[string]struct{} // Tracks the entries already loaded via read operations + seenWrite map[string]struct{} // Tracks the entries already loaded via write operations + + dupsRead int // Number of duplicate preload tasks via reads only + dupsWrite int // Number of duplicate preload tasks via writes only + dupsCross int // Number of duplicate preload tasks via read-write-crosses + + used [][]byte // Tracks the entries used in the end +} + +// subfetcherTask is a trie path to prefetch, tagged with whether it originates +// from a read or a write request. +type subfetcherTask struct { + read bool + key []byte } // newSubfetcher creates a goroutine to prefetch state items belonging to a // particular root hash. func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher { sf := &subfetcher{ - db: db, - state: state, - owner: owner, - root: root, - addr: addr, - wake: make(chan struct{}, 1), - stop: make(chan struct{}), - term: make(chan struct{}), - seen: make(map[string]struct{}), + db: db, + state: state, + owner: owner, + root: root, + addr: addr, + wake: make(chan struct{}, 1), + stop: make(chan struct{}), + term: make(chan struct{}), + seenRead: make(map[string]struct{}), + seenWrite: make(map[string]struct{}), } go sf.loop() return sf } // schedule adds a batch of trie keys to the queue to prefetch. -func (sf *subfetcher) schedule(keys [][]byte) error { +func (sf *subfetcher) schedule(keys [][]byte, read bool) error { // Ensure the subfetcher is still alive select { case <-sf.term: @@ -226,7 +273,10 @@ func (sf *subfetcher) schedule(keys [][]byte) error { } // Append the tasks to the current queue sf.lock.Lock() - sf.tasks = append(sf.tasks, keys...) + for _, key := range keys { + key := key // closure for the append below + sf.tasks = append(sf.tasks, &subfetcherTask{read: read, key: key}) + } sf.lock.Unlock() // Notify the background thread to execute scheduled tasks @@ -303,16 +353,36 @@ func (sf *subfetcher) loop() { sf.lock.Unlock() for _, task := range tasks { - if _, ok := sf.seen[string(task)]; ok { - sf.dups++ - continue + key := string(task.key) + if task.read { + if _, ok := sf.seenRead[key]; ok { + sf.dupsRead++ + continue + } + if _, ok := sf.seenWrite[key]; ok { + sf.dupsCross++ + continue + } + } else { + if _, ok := sf.seenRead[key]; ok { + sf.dupsCross++ + continue + } + if _, ok := sf.seenWrite[key]; ok { + sf.dupsWrite++ + continue + } + } + if len(task.key) == common.AddressLength { + sf.trie.GetAccount(common.BytesToAddress(task.key)) + } else { + sf.trie.GetStorage(sf.addr, task.key) } - if len(task) == common.AddressLength { - sf.trie.GetAccount(common.BytesToAddress(task)) + if task.read { + sf.seenRead[key] = struct{}{} } else { - sf.trie.GetStorage(sf.addr, task) + sf.seenWrite[key] = struct{}{} } - sf.seen[string(task)] = struct{}{} } case <-sf.stop: diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index 478407dfbb04..8f01acd2214d 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -47,15 +47,15 @@ func filledStateDB() *StateDB { func TestUseAfterTerminate(t *testing.T) { db := filledStateDB() - prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") + prefetcher := newTriePrefetcher(db.db, db.originalRoot, "", true) skey := common.HexToHash("aaa") - if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err != nil { + if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err != nil { t.Errorf("Prefetch failed before terminate: %v", err) } prefetcher.terminate(false) - if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err == nil { + if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err == nil { t.Errorf("Prefetch succeeded after terminate: %v", err) } if tr := prefetcher.trie(common.Hash{}, db.originalRoot); tr == nil { diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 66a20f434e85..2b1ea3848352 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -33,6 +33,7 @@ type Config struct { NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled + EnableWitnessCollection bool // true if witness collection is enabled } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/eth/backend.go b/eth/backend.go index 798ffa600b47..91a07811f038 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -184,6 +184,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { var ( vmConfig = vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, + EnableWitnessCollection: config.EnableWitnessCollection, } cacheConfig = &core.CacheConfig{ TrieCleanLimit: config.TrieCleanCache, diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index f36f212d9c3b..7453fb1efdd3 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -141,6 +141,9 @@ type Config struct { // Enables tracking of SHA3 preimages in the VM EnablePreimageRecording bool + // Enables prefetching trie nodes for read operations too + EnableWitnessCollection bool `toml:"-"` + // Enables VM tracing VMTrace string VMTraceJsonConfig string From 3aa874bed22a82e74fad0d679412d4fb6d9375f2 Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 11 Jun 2024 16:24:44 +0800 Subject: [PATCH 351/571] core/state: rename all the AccessList receivers to 'al' (#29921) rename all the receivers to 'al' --- core/state/access_list.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/state/access_list.go b/core/state/access_list.go index b0effbeadc49..90e5590748cf 100644 --- a/core/state/access_list.go +++ b/core/state/access_list.go @@ -60,11 +60,11 @@ func newAccessList() *accessList { } // Copy creates an independent copy of an accessList. -func (a *accessList) Copy() *accessList { +func (al *accessList) Copy() *accessList { cp := newAccessList() - cp.addresses = maps.Clone(a.addresses) - cp.slots = make([]map[common.Hash]struct{}, len(a.slots)) - for i, slotMap := range a.slots { + cp.addresses = maps.Clone(al.addresses) + cp.slots = make([]map[common.Hash]struct{}, len(al.slots)) + for i, slotMap := range al.slots { cp.slots[i] = maps.Clone(slotMap) } return cp From ffb29be7d4b32256f6becb603feced0dec661c89 Mon Sep 17 00:00:00 2001 From: ucwong Date: Tue, 11 Jun 2024 13:34:56 +0100 Subject: [PATCH 352/571] ethconfig: regenerate config (#29970) --- eth/ethconfig/gen_config.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index b8b9eee29423..147a5599848b 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -50,6 +50,7 @@ func (c Config) MarshalTOML() (interface{}, error) { BlobPool blobpool.Config GPO gasprice.Config EnablePreimageRecording bool + EnableWitnessCollection bool `toml:"-"` VMTrace string VMTraceJsonConfig string DocRoot string `toml:"-"` @@ -93,6 +94,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.BlobPool = c.BlobPool enc.GPO = c.GPO enc.EnablePreimageRecording = c.EnablePreimageRecording + enc.EnableWitnessCollection = c.EnableWitnessCollection enc.VMTrace = c.VMTrace enc.VMTraceJsonConfig = c.VMTraceJsonConfig enc.DocRoot = c.DocRoot @@ -140,6 +142,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { BlobPool *blobpool.Config GPO *gasprice.Config EnablePreimageRecording *bool + EnableWitnessCollection *bool `toml:"-"` VMTrace *string VMTraceJsonConfig *string DocRoot *string `toml:"-"` @@ -252,6 +255,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.EnablePreimageRecording != nil { c.EnablePreimageRecording = *dec.EnablePreimageRecording } + if dec.EnableWitnessCollection != nil { + c.EnableWitnessCollection = *dec.EnableWitnessCollection + } if dec.VMTrace != nil { c.VMTrace = *dec.VMTrace } From caa066dcb0dcb250d32f0861f996fefd1373082c Mon Sep 17 00:00:00 2001 From: bugmaker9371 <167614621+bugmaker9371@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:27:35 +0800 Subject: [PATCH 353/571] cmd/devp2p: fix log output (#29972) --- cmd/devp2p/rlpxcmd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/devp2p/rlpxcmd.go b/cmd/devp2p/rlpxcmd.go index fb8066ee1a1d..77f09e6b85af 100644 --- a/cmd/devp2p/rlpxcmd.go +++ b/cmd/devp2p/rlpxcmd.go @@ -109,7 +109,7 @@ func rlpxPing(ctx *cli.Context) error { } return fmt.Errorf("received disconnect message: %v", msg[0]) default: - return fmt.Errorf("invalid message code %d, expected handshake (code zero)", code) + return fmt.Errorf("invalid message code %d, expected handshake (code zero) or disconnect (code one)", code) } return nil } From c732039a3442c6724054b0d9f4ec96a8639cce47 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 11 Jun 2024 15:57:41 +0200 Subject: [PATCH 354/571] .github: disable cache in actions run (#29926) --- .github/workflows/go.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 41e9631f1571..844cfb5d242a 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,6 +16,7 @@ jobs: uses: actions/setup-go@v5 with: go-version: 1.21.4 + cache: false - name: Run tests run: go test -short ./... env: From b6f2bbd4172cbb56cf879358b1d378564dd09d93 Mon Sep 17 00:00:00 2001 From: bugmaker9371 <167614621+bugmaker9371@users.noreply.github.com> Date: Wed, 12 Jun 2024 01:41:17 +0800 Subject: [PATCH 355/571] p2p/simulations: update doc of HTTP endpoints (#29894) --- p2p/simulations/README.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/p2p/simulations/README.md b/p2p/simulations/README.md index 023f73a098a2..1f9f72dcdacf 100644 --- a/p2p/simulations/README.md +++ b/p2p/simulations/README.md @@ -123,20 +123,25 @@ The API is initialised with a particular node adapter and has the following endpoints: ``` -GET / Get network information -POST /start Start all nodes in the network -POST /stop Stop all nodes in the network -GET /events Stream network events -GET /snapshot Take a network snapshot -POST /snapshot Load a network snapshot -POST /nodes Create a node -GET /nodes Get all nodes in the network -GET /nodes/:nodeid Get node information -POST /nodes/:nodeid/start Start a node -POST /nodes/:nodeid/stop Stop a node -POST /nodes/:nodeid/conn/:peerid Connect two nodes -DELETE /nodes/:nodeid/conn/:peerid Disconnect two nodes -GET /nodes/:nodeid/rpc Make RPC requests to a node via WebSocket +OPTIONS / Response 200 with "Access-Control-Allow-Headers"" header set to "Content-Type"" +GET / Get network information +POST /start Start all nodes in the network +POST /stop Stop all nodes in the network +POST /mocker/start Start the mocker node simulation +POST /mocker/stop Stop the mocker node simulation +GET /mocker Get a list of available mockers +POST /reset Reset all properties of a network to initial (empty) state +GET /events Stream network events +GET /snapshot Take a network snapshot +POST /snapshot Load a network snapshot +POST /nodes Create a node +GET /nodes Get all nodes in the network +GET /nodes/:nodeid Get node information +POST /nodes/:nodeid/start Start a node +POST /nodes/:nodeid/stop Stop a node +POST /nodes/:nodeid/conn/:peerid Connect two nodes +DELETE /nodes/:nodeid/conn/:peerid Disconnect two nodes +GET /nodes/:nodeid/rpc Make RPC requests to a node via WebSocket ``` For convenience, `nodeid` in the URL can be the name of a node rather than its From 1e97148249e027b68c2ff71fe14db4b1d36cf216 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 12 Jun 2024 09:45:42 +0200 Subject: [PATCH 356/571] all: fix inconsistent receiver name and add lint rule for it (#29974) * .golangci.yml: enable check for consistent receiver name * beacon/light/sync: fix receiver name * core/txpool/blobpool: fix receiver name * core/types: fix receiver name * internal/ethapi: use consistent receiver name 'api' for handler object * signer/core/apitypes: fix receiver name * signer/core: use consistent receiver name 'api' for handler object * log: fix receiver name --- .golangci.yml | 13 + beacon/light/sync/test_helpers.go | 20 +- core/txpool/blobpool/blobpool_test.go | 2 +- core/types/transaction_signing.go | 8 +- internal/ethapi/api.go | 373 +++++++++++++------------- log/handler.go | 8 +- signer/core/apitypes/types.go | 4 +- signer/core/uiapi.go | 34 +-- 8 files changed, 237 insertions(+), 225 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 46844d1e90b9..2132f5403ab7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -23,6 +23,7 @@ linters: - durationcheck - exportloopref - whitespace + - revive # only certain checks enabled ### linters we tried and will not be using: ### @@ -38,6 +39,15 @@ linters: linters-settings: gofmt: simplify: true + revive: + enable-all-rules: false + # here we enable specific useful rules + # see https://golangci-lint.run/usage/linters/#revive for supported rules + rules: + - name: receiver-naming + severity: warning + disabled: false + exclude: [""] issues: exclude-files: @@ -47,6 +57,9 @@ issues: linters: - deadcode - staticcheck + - path: crypto/bn256/ + linters: + - revive - path: internal/build/pgp.go text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - path: core/vm/contracts.go diff --git a/beacon/light/sync/test_helpers.go b/beacon/light/sync/test_helpers.go index cfca8ad8a45f..b331bf711097 100644 --- a/beacon/light/sync/test_helpers.go +++ b/beacon/light/sync/test_helpers.go @@ -173,24 +173,24 @@ type TestCommitteeChain struct { init bool } -func (t *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error { - t.fsp, t.nsp, t.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true +func (tc *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error { + tc.fsp, tc.nsp, tc.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true return nil } -func (t *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error { +func (tc *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error { period := update.AttestedHeader.Header.SyncPeriod() - if period < t.fsp || period > t.nsp || !t.init { + if period < tc.fsp || period > tc.nsp || !tc.init { return light.ErrInvalidPeriod } - if period == t.nsp { - t.nsp++ + if period == tc.nsp { + tc.nsp++ } return nil } -func (t *TestCommitteeChain) NextSyncPeriod() (uint64, bool) { - return t.nsp, t.init +func (tc *TestCommitteeChain) NextSyncPeriod() (uint64, bool) { + return tc.nsp, tc.init } func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) { @@ -199,8 +199,8 @@ func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) { } } -func (t *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) { - t.init, t.nsp = true, nsp +func (tc *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) { + tc.init, tc.nsp = true, nsp } func (tc *TestCommitteeChain) ExpNextSyncPeriod(t *testing.T, expNsp uint64) { diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 85e13980bee6..d658a6daf44a 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -143,7 +143,7 @@ func (bc *testBlockChain) CurrentFinalBlock() *types.Header { } } -func (bt *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { +func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { return nil } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 6e5f6712f81b..2ae38661f31e 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -459,11 +459,11 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash { // homestead rules. type HomesteadSigner struct{ FrontierSigner } -func (s HomesteadSigner) ChainID() *big.Int { +func (hs HomesteadSigner) ChainID() *big.Int { return nil } -func (s HomesteadSigner) Equal(s2 Signer) bool { +func (hs HomesteadSigner) Equal(s2 Signer) bool { _, ok := s2.(HomesteadSigner) return ok } @@ -486,11 +486,11 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) { // frontier rules. type FrontierSigner struct{} -func (s FrontierSigner) ChainID() *big.Int { +func (fs FrontierSigner) ChainID() *big.Int { return nil } -func (s FrontierSigner) Equal(s2 Signer) bool { +func (fs FrontierSigner) Equal(s2 Signer) bool { _, ok := s2.(FrontierSigner) return ok } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f211dcc6598b..1c209fb5a490 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -26,9 +26,6 @@ import ( "time" "github.com/davecgh/go-spew/spew" - "github.com/holiman/uint256" - "github.com/tyler-smith/go-bip39" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/scwallet" @@ -51,6 +48,8 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" + "github.com/holiman/uint256" + "github.com/tyler-smith/go-bip39" ) // estimateGasErrorRatio is the amount of overestimation eth_estimateGas is @@ -70,20 +69,20 @@ func NewEthereumAPI(b Backend) *EthereumAPI { } // GasPrice returns a suggestion for a gas price for legacy transactions. -func (s *EthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { - tipcap, err := s.b.SuggestGasTipCap(ctx) +func (api *EthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { + tipcap, err := api.b.SuggestGasTipCap(ctx) if err != nil { return nil, err } - if head := s.b.CurrentHeader(); head.BaseFee != nil { + if head := api.b.CurrentHeader(); head.BaseFee != nil { tipcap.Add(tipcap, head.BaseFee) } return (*hexutil.Big)(tipcap), err } // MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions. -func (s *EthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { - tipcap, err := s.b.SuggestGasTipCap(ctx) +func (api *EthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { + tipcap, err := api.b.SuggestGasTipCap(ctx) if err != nil { return nil, err } @@ -100,8 +99,8 @@ type feeHistoryResult struct { } // FeeHistory returns the fee market history. -func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { - oldest, reward, baseFee, gasUsed, blobBaseFee, blobGasUsed, err := s.b.FeeHistory(ctx, uint64(blockCount), lastBlock, rewardPercentiles) +func (api *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { + oldest, reward, baseFee, gasUsed, blobBaseFee, blobGasUsed, err := api.b.FeeHistory(ctx, uint64(blockCount), lastBlock, rewardPercentiles) if err != nil { return nil, err } @@ -137,8 +136,8 @@ func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecim } // BlobBaseFee returns the base fee for blob gas at the current head. -func (s *EthereumAPI) BlobBaseFee(ctx context.Context) *hexutil.Big { - return (*hexutil.Big)(s.b.BlobBaseFee(ctx)) +func (api *EthereumAPI) BlobBaseFee(ctx context.Context) *hexutil.Big { + return (*hexutil.Big)(api.b.BlobBaseFee(ctx)) } // Syncing returns false in case the node is currently not syncing with the network. It can be up-to-date or has not @@ -148,8 +147,8 @@ func (s *EthereumAPI) BlobBaseFee(ctx context.Context) *hexutil.Big { // - highestBlock: block number of the highest block header this node has received from peers // - pulledStates: number of state entries processed until now // - knownStates: number of known state entries that still need to be pulled -func (s *EthereumAPI) Syncing() (interface{}, error) { - progress := s.b.SyncProgress() +func (api *EthereumAPI) Syncing() (interface{}, error) { + progress := api.b.SyncProgress() // Return not syncing if the synchronisation already completed if progress.Done() { @@ -188,18 +187,18 @@ func NewTxPoolAPI(b Backend) *TxPoolAPI { } // Content returns the transactions contained within the transaction pool. -func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { +func (api *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { content := map[string]map[string]map[string]*RPCTransaction{ "pending": make(map[string]map[string]*RPCTransaction), "queued": make(map[string]map[string]*RPCTransaction), } - pending, queue := s.b.TxPoolContent() - curHeader := s.b.CurrentHeader() + pending, queue := api.b.TxPoolContent() + curHeader := api.b.CurrentHeader() // Flatten the pending transactions for account, txs := range pending { dump := make(map[string]*RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig()) } content["pending"][account.Hex()] = dump } @@ -207,7 +206,7 @@ func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { for account, txs := range queue { dump := make(map[string]*RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig()) } content["queued"][account.Hex()] = dump } @@ -215,22 +214,22 @@ func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { } // ContentFrom returns the transactions contained within the transaction pool. -func (s *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCTransaction { +func (api *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCTransaction { content := make(map[string]map[string]*RPCTransaction, 2) - pending, queue := s.b.TxPoolContentFrom(addr) - curHeader := s.b.CurrentHeader() + pending, queue := api.b.TxPoolContentFrom(addr) + curHeader := api.b.CurrentHeader() // Build the pending transactions dump := make(map[string]*RPCTransaction, len(pending)) for _, tx := range pending { - dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig()) } content["pending"] = dump // Build the queued transactions dump = make(map[string]*RPCTransaction, len(queue)) for _, tx := range queue { - dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig()) } content["queued"] = dump @@ -238,8 +237,8 @@ func (s *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCT } // Status returns the number of pending and queued transaction in the pool. -func (s *TxPoolAPI) Status() map[string]hexutil.Uint { - pending, queue := s.b.Stats() +func (api *TxPoolAPI) Status() map[string]hexutil.Uint { + pending, queue := api.b.Stats() return map[string]hexutil.Uint{ "pending": hexutil.Uint(pending), "queued": hexutil.Uint(queue), @@ -248,12 +247,12 @@ func (s *TxPoolAPI) Status() map[string]hexutil.Uint { // Inspect retrieves the content of the transaction pool and flattens it into an // easily inspectable list. -func (s *TxPoolAPI) Inspect() map[string]map[string]map[string]string { +func (api *TxPoolAPI) Inspect() map[string]map[string]map[string]string { content := map[string]map[string]map[string]string{ "pending": make(map[string]map[string]string), "queued": make(map[string]map[string]string), } - pending, queue := s.b.TxPoolContent() + pending, queue := api.b.TxPoolContent() // Define a formatter to flatten a transaction into a string var format = func(tx *types.Transaction) string { @@ -293,8 +292,8 @@ func NewEthereumAccountAPI(am *accounts.Manager) *EthereumAccountAPI { } // Accounts returns the collection of accounts this node manages. -func (s *EthereumAccountAPI) Accounts() []common.Address { - return s.am.Accounts() +func (api *EthereumAccountAPI) Accounts() []common.Address { + return api.am.Accounts() } // PersonalAccountAPI provides an API to access accounts managed by this node. @@ -316,8 +315,8 @@ func NewPersonalAccountAPI(b Backend, nonceLock *AddrLocker) *PersonalAccountAPI } // ListAccounts will return a list of addresses for accounts this node manages. -func (s *PersonalAccountAPI) ListAccounts() []common.Address { - return s.am.Accounts() +func (api *PersonalAccountAPI) ListAccounts() []common.Address { + return api.am.Accounts() } // rawWallet is a JSON representation of an accounts.Wallet interface, with its @@ -330,9 +329,9 @@ type rawWallet struct { } // ListWallets will return a list of wallets this node manages. -func (s *PersonalAccountAPI) ListWallets() []rawWallet { +func (api *PersonalAccountAPI) ListWallets() []rawWallet { wallets := make([]rawWallet, 0) // return [] instead of nil if empty - for _, wallet := range s.am.Wallets() { + for _, wallet := range api.am.Wallets() { status, failure := wallet.Status() raw := rawWallet{ @@ -352,8 +351,8 @@ func (s *PersonalAccountAPI) ListWallets() []rawWallet { // connection and attempting to authenticate via the provided passphrase. Note, // the method may return an extra challenge requiring a second open (e.g. the // Trezor PIN matrix challenge). -func (s *PersonalAccountAPI) OpenWallet(url string, passphrase *string) error { - wallet, err := s.am.Wallet(url) +func (api *PersonalAccountAPI) OpenWallet(url string, passphrase *string) error { + wallet, err := api.am.Wallet(url) if err != nil { return err } @@ -366,8 +365,8 @@ func (s *PersonalAccountAPI) OpenWallet(url string, passphrase *string) error { // DeriveAccount requests an HD wallet to derive a new account, optionally pinning // it for later reuse. -func (s *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { - wallet, err := s.am.Wallet(url) +func (api *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { + wallet, err := api.am.Wallet(url) if err != nil { return accounts.Account{}, err } @@ -382,8 +381,8 @@ func (s *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) ( } // NewAccount will create a new account and returns the address for the new account. -func (s *PersonalAccountAPI) NewAccount(password string) (common.AddressEIP55, error) { - ks, err := fetchKeystore(s.am) +func (api *PersonalAccountAPI) NewAccount(password string) (common.AddressEIP55, error) { + ks, err := fetchKeystore(api.am) if err != nil { return common.AddressEIP55{}, err } @@ -408,12 +407,12 @@ func fetchKeystore(am *accounts.Manager) (*keystore.KeyStore, error) { // ImportRawKey stores the given hex encoded ECDSA key into the key directory, // encrypting it with the passphrase. -func (s *PersonalAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) { +func (api *PersonalAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) { key, err := crypto.HexToECDSA(privkey) if err != nil { return common.Address{}, err } - ks, err := fetchKeystore(s.am) + ks, err := fetchKeystore(api.am) if err != nil { return common.Address{}, err } @@ -424,11 +423,11 @@ func (s *PersonalAccountAPI) ImportRawKey(privkey string, password string) (comm // UnlockAccount will unlock the account associated with the given address with // the given password for duration seconds. If duration is nil it will use a // default of 300 seconds. It returns an indication if the account was unlocked. -func (s *PersonalAccountAPI) UnlockAccount(ctx context.Context, addr common.Address, password string, duration *uint64) (bool, error) { +func (api *PersonalAccountAPI) UnlockAccount(ctx context.Context, addr common.Address, password string, duration *uint64) (bool, error) { // When the API is exposed by external RPC(http, ws etc), unless the user // explicitly specifies to allow the insecure account unlocking, otherwise // it is disabled. - if s.b.ExtRPCEnabled() && !s.b.AccountManager().Config().InsecureUnlockAllowed { + if api.b.ExtRPCEnabled() && !api.b.AccountManager().Config().InsecureUnlockAllowed { return false, errors.New("account unlock with HTTP access is forbidden") } @@ -441,7 +440,7 @@ func (s *PersonalAccountAPI) UnlockAccount(ctx context.Context, addr common.Addr } else { d = time.Duration(*duration) * time.Second } - ks, err := fetchKeystore(s.am) + ks, err := fetchKeystore(api.am) if err != nil { return false, err } @@ -453,8 +452,8 @@ func (s *PersonalAccountAPI) UnlockAccount(ctx context.Context, addr common.Addr } // LockAccount will lock the account associated with the given address when it's unlocked. -func (s *PersonalAccountAPI) LockAccount(addr common.Address) bool { - if ks, err := fetchKeystore(s.am); err == nil { +func (api *PersonalAccountAPI) LockAccount(addr common.Address) bool { + if ks, err := fetchKeystore(api.am); err == nil { return ks.Lock(addr) == nil } return false @@ -463,49 +462,49 @@ func (s *PersonalAccountAPI) LockAccount(addr common.Address) bool { // signTransaction sets defaults and signs the given transaction // NOTE: the caller needs to ensure that the nonceLock is held, if applicable, // and release it after the transaction has been submitted to the tx pool -func (s *PersonalAccountAPI) signTransaction(ctx context.Context, args *TransactionArgs, passwd string) (*types.Transaction, error) { +func (api *PersonalAccountAPI) signTransaction(ctx context.Context, args *TransactionArgs, passwd string) (*types.Transaction, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: args.from()} - wallet, err := s.am.Find(account) + wallet, err := api.am.Find(account) if err != nil { return nil, err } // Set some sanity defaults and terminate on failure - if err := args.setDefaults(ctx, s.b, false); err != nil { + if err := args.setDefaults(ctx, api.b, false); err != nil { return nil, err } // Assemble the transaction and sign with the wallet tx := args.ToTransaction() - return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID) + return wallet.SignTxWithPassphrase(account, passwd, tx, api.b.ChainConfig().ChainID) } // SendTransaction will create a transaction from the given arguments and // tries to sign it with the key associated with args.From. If the given // passwd isn't able to decrypt the key it fails. -func (s *PersonalAccountAPI) SendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { +func (api *PersonalAccountAPI) SendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { if args.Nonce == nil { // Hold the mutex around signing to prevent concurrent assignment of // the same nonce to multiple accounts. - s.nonceLock.LockAddr(args.from()) - defer s.nonceLock.UnlockAddr(args.from()) + api.nonceLock.LockAddr(args.from()) + defer api.nonceLock.UnlockAddr(args.from()) } if args.IsEIP4844() { return common.Hash{}, errBlobTxNotSupported } - signed, err := s.signTransaction(ctx, &args, passwd) + signed, err := api.signTransaction(ctx, &args, passwd) if err != nil { log.Warn("Failed transaction send attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err) return common.Hash{}, err } - return SubmitTransaction(ctx, s.b, signed) + return SubmitTransaction(ctx, api.b, signed) } // SignTransaction will create a transaction from the given arguments and // tries to sign it with the key associated with args.From. If the given passwd isn't // able to decrypt the key it fails. The transaction is returned in RLP-form, not broadcast // to other nodes -func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args TransactionArgs, passwd string) (*SignTransactionResult, error) { +func (api *PersonalAccountAPI) SignTransaction(ctx context.Context, args TransactionArgs, passwd string) (*SignTransactionResult, error) { // No need to obtain the noncelock mutex, since we won't be sending this // tx into the transaction pool, but right back to the user if args.From == nil { @@ -525,10 +524,10 @@ func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transacti } // Before actually signing the transaction, ensure the transaction fee is reasonable. tx := args.ToTransaction() - if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil { + if err := checkTxFee(tx.GasPrice(), tx.Gas(), api.b.RPCTxFeeCap()); err != nil { return nil, err } - signed, err := s.signTransaction(ctx, &args, passwd) + signed, err := api.signTransaction(ctx, &args, passwd) if err != nil { log.Warn("Failed transaction sign attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err) return nil, err @@ -549,11 +548,11 @@ func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transacti // The key used to calculate the signature is decrypted with the given password. // // https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-personal#personal-sign -func (s *PersonalAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) { +func (api *PersonalAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} - wallet, err := s.b.AccountManager().Find(account) + wallet, err := api.b.AccountManager().Find(account) if err != nil { return nil, err } @@ -577,7 +576,7 @@ func (s *PersonalAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr // the V value must be 27 or 28 for legacy reasons. // // https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-personal#personal-ecrecover -func (s *PersonalAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) { +func (api *PersonalAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) { if len(sig) != crypto.SignatureLength { return common.Address{}, fmt.Errorf("signature must be %d bytes long", crypto.SignatureLength) } @@ -594,8 +593,8 @@ func (s *PersonalAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.By } // InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key. -func (s *PersonalAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) { - wallet, err := s.am.Wallet(url) +func (api *PersonalAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) { + wallet, err := api.am.Wallet(url) if err != nil { return "", err } @@ -621,8 +620,8 @@ func (s *PersonalAccountAPI) InitializeWallet(ctx context.Context, url string) ( } // Unpair deletes a pairing between wallet and geth. -func (s *PersonalAccountAPI) Unpair(ctx context.Context, url string, pin string) error { - wallet, err := s.am.Wallet(url) +func (api *PersonalAccountAPI) Unpair(ctx context.Context, url string, pin string) error { + wallet, err := api.am.Wallet(url) if err != nil { return err } @@ -656,16 +655,16 @@ func (api *BlockChainAPI) ChainId() *hexutil.Big { } // BlockNumber returns the block number of the chain head. -func (s *BlockChainAPI) BlockNumber() hexutil.Uint64 { - header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available +func (api *BlockChainAPI) BlockNumber() hexutil.Uint64 { + header, _ := api.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available return hexutil.Uint64(header.Number.Uint64()) } // GetBalance returns the amount of wei for the given address in the state of the // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta // block numbers are also allowed. -func (s *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { - state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) +func (api *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { + state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } @@ -704,7 +703,7 @@ func (n *proofList) Delete(key []byte) error { } // GetProof returns the Merkle-proof for a given account and optionally some storage keys. -func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { +func (api *BlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { var ( keys = make([]common.Hash, len(storageKeys)) keyLengths = make([]int, len(storageKeys)) @@ -718,7 +717,7 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st return nil, err } } - statedb, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + statedb, header, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if statedb == nil || err != nil { return nil, err } @@ -804,10 +803,10 @@ func decodeHash(s string) (h common.Hash, inputLength int, err error) { // - When blockNr is -2 the chain latest header is returned. // - When blockNr is -3 the chain finalized header is returned. // - When blockNr is -4 the chain safe header is returned. -func (s *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) { - header, err := s.b.HeaderByNumber(ctx, number) +func (api *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) { + header, err := api.b.HeaderByNumber(ctx, number) if header != nil && err == nil { - response := s.rpcMarshalHeader(ctx, header) + response := api.rpcMarshalHeader(ctx, header) if number == rpc.PendingBlockNumber { // Pending header need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -820,10 +819,10 @@ func (s *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockN } // GetHeaderByHash returns the requested header by hash. -func (s *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} { - header, _ := s.b.HeaderByHash(ctx, hash) +func (api *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} { + header, _ := api.b.HeaderByHash(ctx, hash) if header != nil { - return s.rpcMarshalHeader(ctx, header) + return api.rpcMarshalHeader(ctx, header) } return nil } @@ -835,10 +834,10 @@ func (s *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) m // - When blockNr is -4 the chain safe block is returned. // - When fullTx is true all transactions in the block are returned, otherwise // only the transaction hash is returned. -func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { - block, err := s.b.BlockByNumber(ctx, number) +func (api *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { + block, err := api.b.BlockByNumber(ctx, number) if block != nil && err == nil { - response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) + response, err := api.rpcMarshalBlock(ctx, block, true, fullTx) if err == nil && number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -852,17 +851,17 @@ func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNu // GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full // detail, otherwise only the transaction hash is returned. -func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { - block, err := s.b.BlockByHash(ctx, hash) +func (api *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { + block, err := api.b.BlockByHash(ctx, hash) if block != nil { - return s.rpcMarshalBlock(ctx, block, true, fullTx) + return api.rpcMarshalBlock(ctx, block, true, fullTx) } return nil, err } // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. -func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { - block, err := s.b.BlockByNumber(ctx, blockNr) +func (api *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { + block, err := api.b.BlockByNumber(ctx, blockNr) if block != nil { uncles := block.Uncles() if index >= hexutil.Uint(len(uncles)) { @@ -870,14 +869,14 @@ func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, block return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return s.rpcMarshalBlock(ctx, block, false, false) + return api.rpcMarshalBlock(ctx, block, false, false) } return nil, err } // GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. -func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { - block, err := s.b.BlockByHash(ctx, blockHash) +func (api *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { + block, err := api.b.BlockByHash(ctx, blockHash) if block != nil { uncles := block.Uncles() if index >= hexutil.Uint(len(uncles)) { @@ -885,14 +884,14 @@ func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHa return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return s.rpcMarshalBlock(ctx, block, false, false) + return api.rpcMarshalBlock(ctx, block, false, false) } return nil, err } // GetUncleCountByBlockNumber returns number of uncles in the block for the given block number -func (s *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { +func (api *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { + if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n } @@ -900,8 +899,8 @@ func (s *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr } // GetUncleCountByBlockHash returns number of uncles in the block for the given block hash -func (s *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { +func (api *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { + if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n } @@ -909,8 +908,8 @@ func (s *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash } // GetCode returns the code stored at the given address in the state for the given block number. -func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { - state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) +func (api *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } @@ -921,8 +920,8 @@ func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blo // GetStorageAt returns the storage from the state at the given address, key and // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block // numbers are also allowed. -func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { - state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) +func (api *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } @@ -935,14 +934,14 @@ func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address } // GetBlockReceipts returns the block receipts for the given block hash or number or tag. -func (s *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) { - block, err := s.b.BlockByNumberOrHash(ctx, blockNrOrHash) +func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) { + block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) if block == nil || err != nil { // When the block doesn't exist, the RPC method should return JSON null // as per specification. return nil, nil } - receipts, err := s.b.GetReceipts(ctx, block.Hash()) + receipts, err := api.b.GetReceipts(ctx, block.Hash()) if err != nil { return nil, err } @@ -952,7 +951,7 @@ func (s *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc. } // Derive the sender. - signer := types.MakeSigner(s.b.ChainConfig(), block.Number(), block.Time()) + signer := types.MakeSigner(api.b.ChainConfig(), block.Number(), block.Time()) result := make([]map[string]interface{}, len(receipts)) for i, receipt := range receipts { @@ -1162,12 +1161,12 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash // // Note, this function doesn't make and changes in the state/blockchain and is // useful to execute and retrieve values. -func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Bytes, error) { +func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Bytes, error) { if blockNrOrHash == nil { latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) blockNrOrHash = &latest } - result, err := DoCall(ctx, s.b, args, *blockNrOrHash, overrides, blockOverrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap()) + result, err := DoCall(ctx, api.b, args, *blockNrOrHash, overrides, blockOverrides, api.b.RPCEVMTimeout(), api.b.RPCGasCap()) if err != nil { return nil, err } @@ -1226,12 +1225,12 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr // value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap // configuration (if non-zero). // Note: Required blob gas is not computed in this method. -func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) { +func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) { bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } - return DoEstimateGas(ctx, s.b, args, bNrOrHash, overrides, s.b.RPCGasCap()) + return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, api.b.RPCGasCap()) } // RPCMarshalHeader converts the given header to the RPC output . @@ -1309,18 +1308,18 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param // rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires // a `BlockchainAPI`. -func (s *BlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { +func (api *BlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { fields := RPCMarshalHeader(header) - fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, header.Hash())) + fields["totalDifficulty"] = (*hexutil.Big)(api.b.GetTd(ctx, header.Hash())) return fields } // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires // a `BlockchainAPI`. -func (s *BlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig()) +func (api *BlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + fields := RPCMarshalBlock(b, inclTx, fullTx, api.b.ChainConfig()) if inclTx { - fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, b.Hash())) + fields["totalDifficulty"] = (*hexutil.Big)(api.b.GetTd(ctx, b.Hash())) } return fields, nil } @@ -1484,12 +1483,12 @@ type accessListResult struct { // CreateAccessList creates an EIP-2930 type AccessList for the given transaction. // Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state. -func (s *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) { +func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) { bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } - acl, gasUsed, vmerr, err := AccessList(ctx, s.b, bNrOrHash, args) + acl, gasUsed, vmerr, err := AccessList(ctx, api.b, bNrOrHash, args) if err != nil { return nil, err } @@ -1574,8 +1573,8 @@ func NewTransactionAPI(b Backend, nonceLock *AddrLocker) *TransactionAPI { } // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. -func (s *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { +func (api *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { + if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { n := hexutil.Uint(len(block.Transactions())) return &n } @@ -1583,8 +1582,8 @@ func (s *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, b } // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. -func (s *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { +func (api *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { + if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { n := hexutil.Uint(len(block.Transactions())) return &n } @@ -1592,49 +1591,49 @@ func (s *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blo } // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. -func (s *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) +func (api *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { + if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { + return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()) } return nil } // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. -func (s *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) +func (api *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { + if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { + return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()) } return nil } // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. -func (s *TransactionAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { +func (api *TransactionAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { + if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil } // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. -func (s *TransactionAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { +func (api *TransactionAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { + if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil } // GetTransactionCount returns the number of transactions the given address has sent for the given block number -func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { +func (api *TransactionAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { // Ask transaction pool for the nonce which includes pending transactions if blockNr, ok := blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber { - nonce, err := s.b.GetPoolNonce(ctx, address) + nonce, err := api.b.GetPoolNonce(ctx, address) if err != nil { return nil, err } return (*hexutil.Uint64)(&nonce), nil } // Resolve block number and use its state to ask for the nonce - state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } @@ -1643,32 +1642,32 @@ func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common } // GetTransactionByHash returns the transaction for the given hash -func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { +func (api *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { // Try to return an already finalized transaction - found, tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) + found, tx, blockHash, blockNumber, index, err := api.b.GetTransaction(ctx, hash) if !found { // No finalized transaction, try to retrieve it from the pool - if tx := s.b.GetPoolTransaction(hash); tx != nil { - return NewRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil + if tx := api.b.GetPoolTransaction(hash); tx != nil { + return NewRPCPendingTransaction(tx, api.b.CurrentHeader(), api.b.ChainConfig()), nil } if err == nil { return nil, nil } return nil, NewTxIndexingError() } - header, err := s.b.HeaderByHash(ctx, blockHash) + header, err := api.b.HeaderByHash(ctx, blockHash) if err != nil { return nil, err } - return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, s.b.ChainConfig()), nil + return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, api.b.ChainConfig()), nil } // GetRawTransactionByHash returns the bytes of the transaction for the given hash. -func (s *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { +func (api *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { // Retrieve a finalized transaction, or a pooled otherwise - found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash) + found, tx, _, _, _, err := api.b.GetTransaction(ctx, hash) if !found { - if tx = s.b.GetPoolTransaction(hash); tx != nil { + if tx = api.b.GetPoolTransaction(hash); tx != nil { return tx.MarshalBinary() } if err == nil { @@ -1680,19 +1679,19 @@ func (s *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash commo } // GetTransactionReceipt returns the transaction receipt for the given transaction hash. -func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { - found, tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) +func (api *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { + found, tx, blockHash, blockNumber, index, err := api.b.GetTransaction(ctx, hash) if err != nil { return nil, NewTxIndexingError() // transaction is not fully indexed } if !found { return nil, nil // transaction is not existent or reachable } - header, err := s.b.HeaderByHash(ctx, blockHash) + header, err := api.b.HeaderByHash(ctx, blockHash) if err != nil { return nil, err } - receipts, err := s.b.GetReceipts(ctx, blockHash) + receipts, err := api.b.GetReceipts(ctx, blockHash) if err != nil { return nil, err } @@ -1702,7 +1701,7 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. receipt := receipts[index] // Derive the sender. - signer := types.MakeSigner(s.b.ChainConfig(), header.Number, header.Time) + signer := types.MakeSigner(api.b.ChainConfig(), header.Number, header.Time) return marshalReceipt(receipt, blockHash, blockNumber, signer, tx, int(index)), nil } @@ -1749,16 +1748,16 @@ func marshalReceipt(receipt *types.Receipt, blockHash common.Hash, blockNumber u } // sign is a helper function that signs a transaction with the private key of the given address. -func (s *TransactionAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { +func (api *TransactionAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} - wallet, err := s.b.AccountManager().Find(account) + wallet, err := api.b.AccountManager().Find(account) if err != nil { return nil, err } // Request the wallet to sign the transaction - return wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) + return wallet.SignTx(account, tx, api.b.ChainConfig().ChainID) } // SubmitTransaction is a helper function that submits tx to txPool and logs a message. @@ -1794,11 +1793,11 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c // SendTransaction creates a transaction for the given argument, sign it and submit it to the // transaction pool. -func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionArgs) (common.Hash, error) { +func (api *TransactionAPI) SendTransaction(ctx context.Context, args TransactionArgs) (common.Hash, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: args.from()} - wallet, err := s.b.AccountManager().Find(account) + wallet, err := api.b.AccountManager().Find(account) if err != nil { return common.Hash{}, err } @@ -1806,35 +1805,35 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr if args.Nonce == nil { // Hold the mutex around signing to prevent concurrent assignment of // the same nonce to multiple accounts. - s.nonceLock.LockAddr(args.from()) - defer s.nonceLock.UnlockAddr(args.from()) + api.nonceLock.LockAddr(args.from()) + defer api.nonceLock.UnlockAddr(args.from()) } if args.IsEIP4844() { return common.Hash{}, errBlobTxNotSupported } // Set some sanity defaults and terminate on failure - if err := args.setDefaults(ctx, s.b, false); err != nil { + if err := args.setDefaults(ctx, api.b, false); err != nil { return common.Hash{}, err } // Assemble the transaction and sign with the wallet tx := args.ToTransaction() - signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) + signed, err := wallet.SignTx(account, tx, api.b.ChainConfig().ChainID) if err != nil { return common.Hash{}, err } - return SubmitTransaction(ctx, s.b, signed) + return SubmitTransaction(ctx, api.b, signed) } // FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields) // on a given unsigned transaction, and returns it to the caller for further // processing (signing + broadcast). -func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { +func (api *TransactionAPI) FillTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { args.blobSidecarAllowed = true // Set some sanity defaults and terminate on failure - if err := args.setDefaults(ctx, s.b, false); err != nil { + if err := args.setDefaults(ctx, api.b, false); err != nil { return nil, err } // Assemble the transaction and obtain rlp @@ -1848,12 +1847,12 @@ func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionAr // SendRawTransaction will add the signed transaction to the transaction pool. // The sender is responsible for signing the transaction and using the correct nonce. -func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { +func (api *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { tx := new(types.Transaction) if err := tx.UnmarshalBinary(input); err != nil { return common.Hash{}, err } - return SubmitTransaction(ctx, s.b, tx) + return SubmitTransaction(ctx, api.b, tx) } // Sign calculates an ECDSA signature for: @@ -1865,11 +1864,11 @@ func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.B // The account associated with addr must be unlocked. // // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign -func (s *TransactionAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { +func (api *TransactionAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} - wallet, err := s.b.AccountManager().Find(account) + wallet, err := api.b.AccountManager().Find(account) if err != nil { return nil, err } @@ -1890,7 +1889,7 @@ type SignTransactionResult struct { // SignTransaction will sign the given transaction with the from account. // The node needs to have the private key of the account corresponding with // the given from address and it needs to be unlocked. -func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { +func (api *TransactionAPI) SignTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { args.blobSidecarAllowed = true if args.Gas == nil { @@ -1902,15 +1901,15 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr if args.Nonce == nil { return nil, errors.New("nonce not specified") } - if err := args.setDefaults(ctx, s.b, false); err != nil { + if err := args.setDefaults(ctx, api.b, false); err != nil { return nil, err } // Before actually sign the transaction, ensure the transaction fee is reasonable. tx := args.ToTransaction() - if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil { + if err := checkTxFee(tx.GasPrice(), tx.Gas(), api.b.RPCTxFeeCap()); err != nil { return nil, err } - signed, err := s.sign(args.from(), tx) + signed, err := api.sign(args.from(), tx) if err != nil { return nil, err } @@ -1933,23 +1932,23 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr // PendingTransactions returns the transactions that are in the transaction pool // and have a from address that is one of the accounts this node manages. -func (s *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) { - pending, err := s.b.GetPoolTransactions() +func (api *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) { + pending, err := api.b.GetPoolTransactions() if err != nil { return nil, err } accounts := make(map[common.Address]struct{}) - for _, wallet := range s.b.AccountManager().Wallets() { + for _, wallet := range api.b.AccountManager().Wallets() { for _, account := range wallet.Accounts() { accounts[account.Address] = struct{}{} } } - curHeader := s.b.CurrentHeader() + curHeader := api.b.CurrentHeader() transactions := make([]*RPCTransaction, 0, len(pending)) for _, tx := range pending { - from, _ := types.Sender(s.signer, tx) + from, _ := types.Sender(api.signer, tx) if _, exists := accounts[from]; exists { - transactions = append(transactions, NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())) + transactions = append(transactions, NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig())) } } return transactions, nil @@ -1957,11 +1956,11 @@ func (s *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) { // Resend accepts an existing transaction and a new gas price and limit. It will remove // the given transaction from the pool and reinsert it with the new gas price and limit. -func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { +func (api *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { if sendArgs.Nonce == nil { return common.Hash{}, errors.New("missing transaction nonce in transaction spec") } - if err := sendArgs.setDefaults(ctx, s.b, false); err != nil { + if err := sendArgs.setDefaults(ctx, api.b, false); err != nil { return common.Hash{}, err } matchTx := sendArgs.ToTransaction() @@ -1975,18 +1974,18 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g if gasLimit != nil { gas = uint64(*gasLimit) } - if err := checkTxFee(price, gas, s.b.RPCTxFeeCap()); err != nil { + if err := checkTxFee(price, gas, api.b.RPCTxFeeCap()); err != nil { return common.Hash{}, err } // Iterate the pending list for replacement - pending, err := s.b.GetPoolTransactions() + pending, err := api.b.GetPoolTransactions() if err != nil { return common.Hash{}, err } for _, p := range pending { - wantSigHash := s.signer.Hash(matchTx) - pFrom, err := types.Sender(s.signer, p) - if err == nil && pFrom == sendArgs.from() && s.signer.Hash(p) == wantSigHash { + wantSigHash := api.signer.Hash(matchTx) + pFrom, err := types.Sender(api.signer, p) + if err == nil && pFrom == sendArgs.from() && api.signer.Hash(p) == wantSigHash { // Match. Re-sign and send the transaction. if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 { sendArgs.GasPrice = gasPrice @@ -1994,11 +1993,11 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g if gasLimit != nil && *gasLimit != 0 { sendArgs.Gas = gasLimit } - signedTx, err := s.sign(sendArgs.from(), sendArgs.ToTransaction()) + signedTx, err := api.sign(sendArgs.from(), sendArgs.ToTransaction()) if err != nil { return common.Hash{}, err } - if err = s.b.SendTx(ctx, signedTx); err != nil { + if err = api.b.SendTx(ctx, signedTx); err != nil { return common.Hash{}, err } return signedTx.Hash(), nil @@ -2084,11 +2083,11 @@ func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.Block } // GetRawTransaction returns the bytes of the transaction for the given hash. -func (s *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { +func (api *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { // Retrieve a finalized transaction, or a pooled otherwise - found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash) + found, tx, _, _, _, err := api.b.GetTransaction(ctx, hash) if !found { - if tx = s.b.GetPoolTransaction(hash); tx != nil { + if tx = api.b.GetPoolTransaction(hash); tx != nil { return tx.MarshalBinary() } if err == nil { @@ -2151,18 +2150,18 @@ func NewNetAPI(net *p2p.Server, networkVersion uint64) *NetAPI { } // Listening returns an indication if the node is listening for network connections. -func (s *NetAPI) Listening() bool { +func (api *NetAPI) Listening() bool { return true // always listening } // PeerCount returns the number of connected peers -func (s *NetAPI) PeerCount() hexutil.Uint { - return hexutil.Uint(s.net.PeerCount()) +func (api *NetAPI) PeerCount() hexutil.Uint { + return hexutil.Uint(api.net.PeerCount()) } // Version returns the current ethereum protocol version. -func (s *NetAPI) Version() string { - return fmt.Sprintf("%d", s.networkVersion) +func (api *NetAPI) Version() string { + return fmt.Sprintf("%d", api.networkVersion) } // checkTxFee is an internal function used to check whether the fee of diff --git a/log/handler.go b/log/handler.go index c604a6230188..56eff6671f1b 100644 --- a/log/handler.go +++ b/log/handler.go @@ -101,10 +101,10 @@ func (h *TerminalHandler) WithAttrs(attrs []slog.Attr) slog.Handler { } // ResetFieldPadding zeroes the field-padding for all attribute pairs. -func (t *TerminalHandler) ResetFieldPadding() { - t.mu.Lock() - t.fieldPadding = make(map[string]int) - t.mu.Unlock() +func (h *TerminalHandler) ResetFieldPadding() { + h.mu.Lock() + h.fieldPadding = make(map[string]int) + h.mu.Unlock() } type leveler struct{ minLevel slog.Level } diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 9113c091c5c7..73243b16a14b 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -67,9 +67,9 @@ func (vs *ValidationMessages) Info(msg string) { } // GetWarnings returns an error with all messages of type WARN of above, or nil if no warnings were present -func (v *ValidationMessages) GetWarnings() error { +func (vs *ValidationMessages) GetWarnings() error { var messages []string - for _, msg := range v.Messages { + for _, msg := range vs.Messages { if msg.Typ == WARN || msg.Typ == CRIT { messages = append(messages, msg.Message) } diff --git a/signer/core/uiapi.go b/signer/core/uiapi.go index b8c3acfb4d31..43edfe7d9746 100644 --- a/signer/core/uiapi.go +++ b/signer/core/uiapi.go @@ -52,9 +52,9 @@ func NewUIServerAPI(extapi *SignerAPI) *UIServerAPI { // the full Account object and not only Address. // Example call // {"jsonrpc":"2.0","method":"clef_listAccounts","params":[], "id":4} -func (s *UIServerAPI) ListAccounts(ctx context.Context) ([]accounts.Account, error) { +func (api *UIServerAPI) ListAccounts(ctx context.Context) ([]accounts.Account, error) { var accs []accounts.Account - for _, wallet := range s.am.Wallets() { + for _, wallet := range api.am.Wallets() { accs = append(accs, wallet.Accounts()...) } return accs, nil @@ -72,9 +72,9 @@ type rawWallet struct { // ListWallets will return a list of wallets that clef manages // Example call // {"jsonrpc":"2.0","method":"clef_listWallets","params":[], "id":5} -func (s *UIServerAPI) ListWallets() []rawWallet { +func (api *UIServerAPI) ListWallets() []rawWallet { wallets := make([]rawWallet, 0) // return [] instead of nil if empty - for _, wallet := range s.am.Wallets() { + for _, wallet := range api.am.Wallets() { status, failure := wallet.Status() raw := rawWallet{ @@ -94,8 +94,8 @@ func (s *UIServerAPI) ListWallets() []rawWallet { // it for later reuse. // Example call // {"jsonrpc":"2.0","method":"clef_deriveAccount","params":["ledger://","m/44'/60'/0'", false], "id":6} -func (s *UIServerAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { - wallet, err := s.am.Wallet(url) +func (api *UIServerAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { + wallet, err := api.am.Wallet(url) if err != nil { return accounts.Account{}, err } @@ -122,7 +122,7 @@ func fetchKeystore(am *accounts.Manager) *keystore.KeyStore { // encrypting it with the passphrase. // Example call (should fail on password too short) // {"jsonrpc":"2.0","method":"clef_importRawKey","params":["1111111111111111111111111111111111111111111111111111111111111111","test"], "id":6} -func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Account, error) { +func (api *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Account, error) { key, err := crypto.HexToECDSA(privkey) if err != nil { return accounts.Account{}, err @@ -131,7 +131,7 @@ func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Ac return accounts.Account{}, fmt.Errorf("password requirements not met: %v", err) } // No error - return fetchKeystore(s.am).ImportECDSA(key, password) + return fetchKeystore(api.am).ImportECDSA(key, password) } // OpenWallet initiates a hardware wallet opening procedure, establishing a USB @@ -140,8 +140,8 @@ func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Ac // Trezor PIN matrix challenge). // Example // {"jsonrpc":"2.0","method":"clef_openWallet","params":["ledger://",""], "id":6} -func (s *UIServerAPI) OpenWallet(url string, passphrase *string) error { - wallet, err := s.am.Wallet(url) +func (api *UIServerAPI) OpenWallet(url string, passphrase *string) error { + wallet, err := api.am.Wallet(url) if err != nil { return err } @@ -155,24 +155,24 @@ func (s *UIServerAPI) OpenWallet(url string, passphrase *string) error { // ChainId returns the chainid in use for Eip-155 replay protection // Example call // {"jsonrpc":"2.0","method":"clef_chainId","params":[], "id":8} -func (s *UIServerAPI) ChainId() math.HexOrDecimal64 { - return (math.HexOrDecimal64)(s.extApi.chainID.Uint64()) +func (api *UIServerAPI) ChainId() math.HexOrDecimal64 { + return (math.HexOrDecimal64)(api.extApi.chainID.Uint64()) } // SetChainId sets the chain id to use when signing transactions. // Example call to set Ropsten: // {"jsonrpc":"2.0","method":"clef_setChainId","params":["3"], "id":8} -func (s *UIServerAPI) SetChainId(id math.HexOrDecimal64) math.HexOrDecimal64 { - s.extApi.chainID = new(big.Int).SetUint64(uint64(id)) - return s.ChainId() +func (api *UIServerAPI) SetChainId(id math.HexOrDecimal64) math.HexOrDecimal64 { + api.extApi.chainID = new(big.Int).SetUint64(uint64(id)) + return api.ChainId() } // Export returns encrypted private key associated with the given address in web3 keystore format. // Example // {"jsonrpc":"2.0","method":"clef_export","params":["0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a"], "id":4} -func (s *UIServerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) { +func (api *UIServerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) { // Look up the wallet containing the requested signer - wallet, err := s.am.Find(accounts.Account{Address: addr}) + wallet, err := api.am.Find(accounts.Account{Address: addr}) if err != nil { return nil, err } From 3687c34cfc9eba1b2c29209d27d272a72c4de3af Mon Sep 17 00:00:00 2001 From: jackyin <648588267@qq.com> Date: Wed, 12 Jun 2024 15:46:36 +0800 Subject: [PATCH 357/571] accounts: avoid duplicate regex compilation (#29943) * fix: Optimize regular initialization * modify var name * variable change to private types --- accounts/abi/type.go | 6 ++++-- accounts/scwallet/wallet.go | 12 ++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 383982663331..d57fa3d4e667 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -64,6 +64,9 @@ type Type struct { var ( // typeRegex parses the abi sub types typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") + + // sliceSizeRegex grab the slice size + sliceSizeRegex = regexp.MustCompile("[0-9]+") ) // NewType creates a new reflection type of abi type given in t. @@ -91,8 +94,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty // grab the last cell and create a type from there sliced := t[i:] // grab the slice size with regexp - re := regexp.MustCompile("[0-9]+") - intz := re.FindAllString(sliced, -1) + intz := sliceSizeRegex.FindAllString(sliced, -1) if len(intz) == 0 { // is a slice diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index f0ca9085b680..58cfc8830163 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -73,6 +73,14 @@ var ( DerivationSignatureHash = sha256.Sum256(common.Hash{}.Bytes()) ) +var ( + // PinRegexp is the regular expression used to validate PIN codes. + pinRegexp = regexp.MustCompile(`^[0-9]{6,}$`) + + // PukRegexp is the regular expression used to validate PUK codes. + pukRegexp = regexp.MustCompile(`^[0-9]{12,}$`) +) + // List of APDU command-related constants const ( claISO7816 = 0 @@ -380,7 +388,7 @@ func (w *Wallet) Open(passphrase string) error { case passphrase == "": return ErrPINUnblockNeeded case status.PinRetryCount > 0: - if !regexp.MustCompile(`^[0-9]{6,}$`).MatchString(passphrase) { + if !pinRegexp.MatchString(passphrase) { w.log.Error("PIN needs to be at least 6 digits") return ErrPINNeeded } @@ -388,7 +396,7 @@ func (w *Wallet) Open(passphrase string) error { return err } default: - if !regexp.MustCompile(`^[0-9]{12,}$`).MatchString(passphrase) { + if !pukRegexp.MatchString(passphrase) { w.log.Error("PUK needs to be at least 12 digits") return ErrPINUnblockNeeded } From 69351e8b0fcbcfb5b7dd8f3dc85d4c7d0217c848 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Wed, 12 Jun 2024 02:23:16 -0700 Subject: [PATCH 358/571] core/state, eth/protocols, trie, triedb/pathdb: remove unused error from trie Commit (#29869) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * core/state, eth/protocols, trie, triedb/pathdb: remove unused error return from trie Commit * move set back to account-trie-update block scoping for easier readability * address review * undo tests submodule change * trie: panic if BatchSerialize returns an error in Verkle trie Commit * trie: verkle comment nitpicks --------- Co-authored-by: Péter Szilágyi --- core/state/database.go | 2 +- core/state/snapshot/generate.go | 5 +---- core/state/snapshot/generate_test.go | 4 ++-- core/state/state_object.go | 5 +---- core/state/statedb.go | 5 +---- eth/protocols/snap/sync_test.go | 14 +++++++------- trie/iterator_test.go | 16 ++++++++-------- trie/secure_trie.go | 2 +- trie/secure_trie_test.go | 2 +- trie/stacktrie_fuzzer_test.go | 5 +---- trie/sync_test.go | 18 +++++++++--------- trie/tracer_test.go | 18 +++++++++--------- trie/trie.go | 10 +++++----- trie/trie_test.go | 22 +++++++++++----------- trie/triestate/state.go | 17 ++++------------- trie/verkle.go | 15 +++++++-------- triedb/pathdb/database_test.go | 6 +----- triedb/pathdb/testutils.go | 4 ++-- 18 files changed, 72 insertions(+), 98 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 04d7c06687c0..d71f8f34b6f6 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -123,7 +123,7 @@ type Trie interface { // The returned nodeset can be nil if the trie is clean(nothing to commit). // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) + Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) // NodeIterator returns an iterator that returns nodes of the trie. Iteration // starts at the key after the given start key. And error will be returned diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 8de4b134d38c..d81a628c91fa 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -360,10 +360,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi for i, key := range result.keys { snapTrie.Update(key, result.vals[i]) } - root, nodes, err := snapTrie.Commit(false) - if err != nil { - return false, nil, err - } + root, nodes := snapTrie.Commit(false) if nodes != nil { tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) tdb.Commit(root, false) diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index da93ebc87506..891111973a5e 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -210,7 +210,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st if !commit { return stTrie.Hash() } - root, nodes, _ := stTrie.Commit(false) + root, nodes := stTrie.Commit(false) if nodes != nil { t.nodes.Merge(nodes) } @@ -218,7 +218,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st } func (t *testHelper) Commit() common.Hash { - root, nodes, _ := t.accTrie.Commit(true) + root, nodes := t.accTrie.Commit(true) if nodes != nil { t.nodes.Merge(nodes) } diff --git a/core/state/state_object.go b/core/state/state_object.go index 16a5f3e5e211..5c1dab53dc4e 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -470,10 +470,7 @@ func (s *stateObject) commit() (*accountUpdate, *trienode.NodeSet, error) { s.origin = s.data.Copy() return op, nil, nil } - root, nodes, err := s.trie.Commit(false) - if err != nil { - return nil, nil, err - } + root, nodes := s.trie.Commit(false) s.data.Root = root s.origin = s.data.Copy() return op, nodes, nil diff --git a/core/state/statedb.go b/core/state/statedb.go index b4ef0a6e47bc..4f84d93d63c3 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1179,10 +1179,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { // code didn't anticipate for. workers.Go(func() error { // Write the account trie changes, measuring the amount of wasted time - newroot, set, err := s.trie.Commit(true) - if err != nil { - return err - } + newroot, set := s.trie.Commit(true) root = newroot if err := merge(set); err != nil { diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 5f6826373a90..82360ae0e30b 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1525,7 +1525,7 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv) // Commit the state changes into db and re-create the trie // for accessing later. - root, nodes, _ := accTrie.Commit(false) + root, nodes := accTrie.Commit(false) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) accTrie, _ = trie.New(trie.StateTrieID(root), db) @@ -1587,7 +1587,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) { // Commit the state changes into db and re-create the trie // for accessing later. - root, nodes, _ := accTrie.Commit(false) + root, nodes := accTrie.Commit(false) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) accTrie, _ = trie.New(trie.StateTrieID(root), db) @@ -1633,7 +1633,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots slices.SortFunc(entries, (*kv).cmp) // Commit account trie - root, set, _ := accTrie.Commit(true) + root, set := accTrie.Commit(true) nodes.Merge(set) // Commit gathered dirty nodes into database @@ -1700,7 +1700,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda slices.SortFunc(entries, (*kv).cmp) // Commit account trie - root, set, _ := accTrie.Commit(true) + root, set := accTrie.Commit(true) nodes.Merge(set) // Commit gathered dirty nodes into database @@ -1742,7 +1742,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *triedb.Datab entries = append(entries, elem) } slices.SortFunc(entries, (*kv).cmp) - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) return root, nodes, entries } @@ -1793,7 +1793,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *triedb.Database) (com entries = append(entries, elem) } slices.SortFunc(entries, (*kv).cmp) - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) return root, nodes, entries } @@ -1825,7 +1825,7 @@ func makeUnevenStorageTrie(owner common.Hash, slots int, db *triedb.Database) (c } } slices.SortFunc(entries, (*kv).cmp) - root, nodes, _ := tr.Commit(false) + root, nodes := tr.Commit(false) return root, nodes, entries } diff --git a/trie/iterator_test.go b/trie/iterator_test.go index a8f3c4413ea7..b463294b09dd 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -59,7 +59,7 @@ func TestIterator(t *testing.T) { all[val.k] = val.v trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -257,7 +257,7 @@ func TestDifferenceIterator(t *testing.T) { for _, val := range testdata1 { triea.MustUpdate([]byte(val.k), []byte(val.v)) } - rootA, nodesA, _ := triea.Commit(false) + rootA, nodesA := triea.Commit(false) dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) triea, _ = New(TrieID(rootA), dba) @@ -266,7 +266,7 @@ func TestDifferenceIterator(t *testing.T) { for _, val := range testdata2 { trieb.MustUpdate([]byte(val.k), []byte(val.v)) } - rootB, nodesB, _ := trieb.Commit(false) + rootB, nodesB := trieb.Commit(false) dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) trieb, _ = New(TrieID(rootB), dbb) @@ -299,7 +299,7 @@ func TestUnionIterator(t *testing.T) { for _, val := range testdata1 { triea.MustUpdate([]byte(val.k), []byte(val.v)) } - rootA, nodesA, _ := triea.Commit(false) + rootA, nodesA := triea.Commit(false) dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) triea, _ = New(TrieID(rootA), dba) @@ -308,7 +308,7 @@ func TestUnionIterator(t *testing.T) { for _, val := range testdata2 { trieb.MustUpdate([]byte(val.k), []byte(val.v)) } - rootB, nodesB, _ := trieb.Commit(false) + rootB, nodesB := trieb.Commit(false) dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) trieb, _ = New(TrieID(rootB), dbb) @@ -371,7 +371,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) { for _, val := range testdata1 { tr.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := tr.Commit(false) + root, nodes := tr.Commit(false) tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) if !memonly { tdb.Commit(root) @@ -481,7 +481,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme strin for _, val := range testdata1 { ctr.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := ctr.Commit(false) + root, nodes := ctr.Commit(false) for path, n := range nodes.Nodes { if n.Hash == barNodeHash { barNodePath = []byte(path) @@ -561,7 +561,7 @@ func testIteratorNodeBlob(t *testing.T, scheme string) { all[val.k] = val.v trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) triedb.Commit(root) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index e38d5ac4dc36..fb39a80609f3 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -221,7 +221,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { // All cached preimages will be also flushed if preimages recording is enabled. // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage -func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { +func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { preimages := make(map[common.Hash][]byte) diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index 0a6fd688b7ea..59958d33f4cf 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -60,7 +60,7 @@ func makeTestStateTrie() (*testDb, *StateTrie, map[string][]byte) { trie.MustUpdate(key, val) } } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { panic(fmt.Errorf("failed to commit db %v", err)) } diff --git a/trie/stacktrie_fuzzer_test.go b/trie/stacktrie_fuzzer_test.go index 418b941d94e1..df487d16bf46 100644 --- a/trie/stacktrie_fuzzer_test.go +++ b/trie/stacktrie_fuzzer_test.go @@ -79,10 +79,7 @@ func fuzz(data []byte, debugging bool) { return } // Flush trie -> database - rootA, nodes, err := trieA.Commit(false) - if err != nil { - panic(err) - } + rootA, nodes := trieA.Commit(false) if nodes != nil { dbA.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) } diff --git a/trie/sync_test.go b/trie/sync_test.go index 7221b06f59c0..ccdee7d01400 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -58,7 +58,7 @@ func makeTestTrie(scheme string) (ethdb.Database, *testDb, *StateTrie, map[strin trie.MustUpdate(key, val) } } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { panic(fmt.Errorf("failed to commit db %v", err)) } @@ -771,7 +771,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) { srcTrie.MustUpdate(key, val) diff[string(key)] = val } - root, nodes, _ := srcTrie.Commit(false) + root, nodes := srcTrie.Commit(false) if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { panic(err) } @@ -796,7 +796,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) { srcTrie.MustUpdate([]byte(k), val) reverted[k] = val } - root, nodes, _ = srcTrie.Commit(false) + root, nodes = srcTrie.Commit(false) if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { panic(err) } @@ -847,7 +847,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) { writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA) writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateA) - rootA, nodesA, _ := srcTrie.Commit(false) + rootA, nodesA := srcTrie.Commit(false) if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil { panic(err) } @@ -866,7 +866,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) { deleteFn([]byte{0x13, 0x44}, srcTrie, stateB) writeFn([]byte{0x01, 0x24}, nil, srcTrie, stateB) - rootB, nodesB, _ := srcTrie.Commit(false) + rootB, nodesB := srcTrie.Commit(false) if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil { panic(err) } @@ -884,7 +884,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) { writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC) writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateC) - rootC, nodesC, _ := srcTrie.Commit(false) + rootC, nodesC := srcTrie.Commit(false) if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil { panic(err) } @@ -946,7 +946,7 @@ func testSyncAbort(t *testing.T, scheme string) { } writeFn(key, val, srcTrie, stateA) - rootA, nodesA, _ := srcTrie.Commit(false) + rootA, nodesA := srcTrie.Commit(false) if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil { panic(err) } @@ -963,7 +963,7 @@ func testSyncAbort(t *testing.T, scheme string) { srcTrie, _ = New(TrieID(rootA), srcTrieDB) deleteFn(key, srcTrie, stateB) - rootB, nodesB, _ := srcTrie.Commit(false) + rootB, nodesB := srcTrie.Commit(false) if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil { panic(err) } @@ -990,7 +990,7 @@ func testSyncAbort(t *testing.T, scheme string) { srcTrie, _ = New(TrieID(rootB), srcTrieDB) writeFn(key, val, srcTrie, stateC) - rootC, nodesC, _ := srcTrie.Commit(false) + rootC, nodesC := srcTrie.Commit(false) if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil { panic(err) } diff --git a/trie/tracer_test.go b/trie/tracer_test.go index 27e42d497af0..852a706021b0 100644 --- a/trie/tracer_test.go +++ b/trie/tracer_test.go @@ -70,7 +70,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { } insertSet := copySet(trie.tracer.inserts) // copy before commit deleteSet := copySet(trie.tracer.deletes) // copy before commit - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) seen := setKeys(iterNodes(db, root)) @@ -137,7 +137,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for _, val := range vals { trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -152,7 +152,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for _, val := range vals { trie.MustUpdate([]byte(val.k), randBytes(32)) } - root, nodes, _ = trie.Commit(false) + root, nodes = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -170,7 +170,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { keys = append(keys, string(key)) trie.MustUpdate(key, randBytes(32)) } - root, nodes, _ = trie.Commit(false) + root, nodes = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -185,7 +185,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for _, key := range keys { trie.MustUpdate([]byte(key), nil) } - root, nodes, _ = trie.Commit(false) + root, nodes = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -200,7 +200,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for _, val := range vals { trie.MustUpdate([]byte(val.k), nil) } - root, nodes, _ = trie.Commit(false) + root, nodes = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -219,7 +219,7 @@ func TestAccessListLeak(t *testing.T) { for _, val := range standard { trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) var cases = []struct { @@ -269,7 +269,7 @@ func TestTinyTree(t *testing.T) { for _, val := range tiny { trie.MustUpdate([]byte(val.k), randBytes(32)) } - root, set, _ := trie.Commit(false) + root, set := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(set)) parent := root @@ -278,7 +278,7 @@ func TestTinyTree(t *testing.T) { for _, val := range tiny { trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, set, _ = trie.Commit(false) + root, set = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(set)) trie, _ = New(TrieID(root), db) diff --git a/trie/trie.go b/trie/trie.go index 12764e18d1b0..935f81fc7d1d 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -608,7 +608,7 @@ func (t *Trie) Hash() common.Hash { // The returned nodeset can be nil if the trie is clean (nothing to commit). // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage -func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { +func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { defer t.tracer.reset() defer func() { t.committed = true @@ -620,13 +620,13 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) if t.root == nil { paths := t.tracer.deletedNodes() if len(paths) == 0 { - return types.EmptyRootHash, nil, nil // case (a) + return types.EmptyRootHash, nil // case (a) } nodes := trienode.NewNodeSet(t.owner) for _, path := range paths { nodes.AddNode([]byte(path), trienode.NewDeleted()) } - return types.EmptyRootHash, nodes, nil // case (b) + return types.EmptyRootHash, nodes // case (b) } // Derive the hash for all dirty nodes first. We hold the assumption // in the following procedure that all nodes are hashed. @@ -638,14 +638,14 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) // Replace the root node with the origin hash in order to // ensure all resolved nodes are dropped after the commit. t.root = hashedNode - return rootHash, nil, nil + return rootHash, nil } nodes := trienode.NewNodeSet(t.owner) for _, path := range t.tracer.deletedNodes() { nodes.AddNode([]byte(path), trienode.NewDeleted()) } t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root) - return rootHash, nodes, nil + return rootHash, nodes } // hashRoot calculates the root hash of the given trie diff --git a/trie/trie_test.go b/trie/trie_test.go index da60a7423dff..f31fd393f501 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -95,7 +95,7 @@ func testMissingNode(t *testing.T, memonly bool, scheme string) { trie := NewEmpty(triedb) updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) if !memonly { @@ -184,7 +184,7 @@ func TestInsert(t *testing.T) { updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") - root, _, _ = trie.Commit(false) + root, _ = trie.Commit(false) if root != exp { t.Errorf("case 2: exp %x got %x", exp, root) } @@ -209,7 +209,7 @@ func TestGet(t *testing.T) { if i == 1 { return } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) } @@ -282,7 +282,7 @@ func TestReplication(t *testing.T) { for _, val := range vals { updateString(trie, val.k, val.v) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // create a new trie on top of the database and check that lookups work. @@ -295,7 +295,7 @@ func TestReplication(t *testing.T) { t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) } } - hash, nodes, _ := trie2.Commit(false) + hash, nodes := trie2.Commit(false) if hash != root { t.Errorf("root failure. expected %x got %x", root, hash) } @@ -531,7 +531,7 @@ func runRandTest(rt randTest) error { case opHash: tr.Hash() case opCommit: - root, nodes, _ := tr.Commit(true) + root, nodes := tr.Commit(true) if nodes != nil { triedb.Update(root, origin, trienode.NewWithNodeSet(nodes)) } @@ -768,7 +768,7 @@ func TestCommitAfterHash(t *testing.T) { if exp != root { t.Errorf("got %x, exp %x", root, exp) } - root, _, _ = trie.Commit(false) + root, _ = trie.Commit(false) if exp != root { t.Errorf("got %x, exp %x", root, exp) } @@ -894,7 +894,7 @@ func TestCommitSequence(t *testing.T) { trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root) @@ -935,7 +935,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { trie.MustUpdate(key, val) } // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root) @@ -984,7 +984,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { stTrie.Update(key, val) } // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Commit(root) @@ -1042,7 +1042,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) { stTrie.Update(key, []byte{0x1}) // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Commit(root) diff --git a/trie/triestate/state.go b/trie/triestate/state.go index 9db9211e8c87..7508da5d60cd 100644 --- a/trie/triestate/state.go +++ b/trie/triestate/state.go @@ -42,7 +42,7 @@ type Trie interface { // Commit the trie and returns a set of dirty nodes generated along with // the new root hash. - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) + Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) } // TrieLoader wraps functions to load tries. @@ -125,10 +125,7 @@ func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Addre return nil, fmt.Errorf("failed to revert state, err: %w", err) } } - root, result, err := tr.Commit(false) - if err != nil { - return nil, err - } + root, result := tr.Commit(false) if root != prevRoot { return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) } @@ -180,10 +177,7 @@ func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error { return err } } - root, result, err := st.Commit(false) - if err != nil { - return err - } + root, result := st.Commit(false) if root != prev.Root { return errors.New("failed to reset storage trie") } @@ -234,10 +228,7 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error { return err } } - root, result, err := st.Commit(false) - if err != nil { - return err - } + root, result := st.Commit(false) if root != types.EmptyRootHash { return errors.New("failed to clear storage trie") } diff --git a/trie/verkle.go b/trie/verkle.go index bb0c54857f6d..1ea23186f92b 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -217,22 +217,21 @@ func (t *VerkleTrie) Hash() common.Hash { } // Commit writes all nodes to the tree's memory database. -func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) { - root, ok := t.root.(*verkle.InternalNode) - if !ok { - return common.Hash{}, nil, errors.New("unexpected root node type") - } +func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet) { + root := t.root.(*verkle.InternalNode) nodes, err := root.BatchSerialize() if err != nil { - return common.Hash{}, nil, fmt.Errorf("serializing tree nodes: %s", err) + // Error return from this function indicates error in the code logic + // of BatchSerialize, and we fail catastrophically if this is the case. + panic(fmt.Errorf("BatchSerialize failed: %v", err)) } nodeset := trienode.NewNodeSet(common.Hash{}) for _, node := range nodes { - // hash parameter is not used in pathdb + // Hash parameter is not used in pathdb nodeset.AddNode(node.Path, trienode.New(common.Hash{}, node.SerializedBytes)) } // Serialize root commitment form - return t.Hash(), nodeset, nil + return t.Hash(), nodeset } // NodeIterator implements state.Trie, returning an iterator that returns diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 7b240823154d..04c8af415f6f 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -46,11 +46,7 @@ func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[comm h.Update(key.Bytes(), val) } } - root, nodes, err := h.Commit(false) - if err != nil { - panic(fmt.Errorf("failed to commit hasher, err: %w", err)) - } - return root, nodes + return h.Commit(false) } func generateAccount(storageRoot common.Hash) types.StateAccount { diff --git a/triedb/pathdb/testutils.go b/triedb/pathdb/testutils.go index 0c99565b8e28..af832bc59c44 100644 --- a/triedb/pathdb/testutils.go +++ b/triedb/pathdb/testutils.go @@ -80,7 +80,7 @@ func (h *testHasher) Delete(key []byte) error { // Commit computes the new hash of the states and returns the set with all // state changes. -func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { +func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { var ( nodes = make(map[common.Hash][]byte) set = trienode.NewNodeSet(h.owner) @@ -111,7 +111,7 @@ func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, e if root == types.EmptyRootHash && h.root != types.EmptyRootHash { set.AddNode(nil, trienode.NewDeleted()) } - return root, set, nil + return root, set } // hash performs the hash computation upon the provided states. From 86150af2e5deb33130660a5a5d62ed819a2b0e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Wed, 12 Jun 2024 16:38:19 +0200 Subject: [PATCH 359/571] beacon/light: fix shutdown issues (#29946) * beacon/light/request: add server test for event after unsubscribe * beacon/light/api: fixed double stream.Close() * beacon/light/request: add checks for nil event callback function * beacon/light/request: unlock server mutex while unsubscribing from parent --- beacon/light/api/light_api.go | 3 --- beacon/light/request/server.go | 31 +++++++++++++++++------------ beacon/light/request/server_test.go | 31 +++++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 903db5734455..6f60fc0cc655 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -494,9 +494,6 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() for { select { - case <-ctx.Done(): - stream.Close() - case event, ok := <-stream.Events: if !ok { log.Trace("Event stream closed") diff --git a/beacon/light/request/server.go b/beacon/light/request/server.go index 9f3b09b81e80..a06dec99ae75 100644 --- a/beacon/light/request/server.go +++ b/beacon/light/request/server.go @@ -186,10 +186,14 @@ func (s *serverWithTimeout) eventCallback(event Event) { // call will just do nothing timer.Stop() delete(s.timeouts, id) - s.childEventCb(event) + if s.childEventCb != nil { + s.childEventCb(event) + } } default: - s.childEventCb(event) + if s.childEventCb != nil { + s.childEventCb(event) + } } } @@ -211,25 +215,27 @@ func (s *serverWithTimeout) startTimeout(reqData RequestResponse) { delete(s.timeouts, id) childEventCb := s.childEventCb s.lock.Unlock() - childEventCb(Event{Type: EvFail, Data: reqData}) + if childEventCb != nil { + childEventCb(Event{Type: EvFail, Data: reqData}) + } }) childEventCb := s.childEventCb s.lock.Unlock() - childEventCb(Event{Type: EvTimeout, Data: reqData}) + if childEventCb != nil { + childEventCb(Event{Type: EvTimeout, Data: reqData}) + } }) } // unsubscribe stops all goroutines associated with the server. func (s *serverWithTimeout) unsubscribe() { s.lock.Lock() - defer s.lock.Unlock() - for _, timer := range s.timeouts { if timer != nil { timer.Stop() } } - s.childEventCb = nil + s.lock.Unlock() s.parent.Unsubscribe() } @@ -328,10 +334,10 @@ func (s *serverWithLimits) eventCallback(event Event) { } childEventCb := s.childEventCb s.lock.Unlock() - if passEvent { + if passEvent && childEventCb != nil { childEventCb(event) } - if sendCanRequestAgain { + if sendCanRequestAgain && childEventCb != nil { childEventCb(Event{Type: EvCanRequestAgain}) } } @@ -347,13 +353,12 @@ func (s *serverWithLimits) sendRequest(request Request) (reqId ID) { // unsubscribe stops all goroutines associated with the server. func (s *serverWithLimits) unsubscribe() { s.lock.Lock() - defer s.lock.Unlock() - if s.delayTimer != nil { s.delayTimer.Stop() s.delayTimer = nil } s.childEventCb = nil + s.lock.Unlock() s.serverWithTimeout.unsubscribe() } @@ -383,7 +388,7 @@ func (s *serverWithLimits) canRequestNow() bool { } childEventCb := s.childEventCb s.lock.Unlock() - if sendCanRequestAgain { + if sendCanRequestAgain && childEventCb != nil { childEventCb(Event{Type: EvCanRequestAgain}) } return canRequest @@ -415,7 +420,7 @@ func (s *serverWithLimits) delay(delay time.Duration) { } childEventCb := s.childEventCb s.lock.Unlock() - if sendCanRequestAgain { + if sendCanRequestAgain && childEventCb != nil { childEventCb(Event{Type: EvCanRequestAgain}) } }) diff --git a/beacon/light/request/server_test.go b/beacon/light/request/server_test.go index 38629cb8c464..fef5d062ea2c 100644 --- a/beacon/light/request/server_test.go +++ b/beacon/light/request/server_test.go @@ -51,6 +51,7 @@ func TestServerEvents(t *testing.T) { expEvent(EvFail) rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}}) expEvent(nil) + srv.unsubscribe() } func TestServerParallel(t *testing.T) { @@ -129,9 +130,7 @@ func TestServerEventRateLimit(t *testing.T) { srv := NewServer(rs, clock) var eventCount int srv.subscribe(func(event Event) { - if !event.IsRequestEvent() { - eventCount++ - } + eventCount++ }) expEvents := func(send, expAllowed int) { eventCount = 0 @@ -147,6 +146,30 @@ func TestServerEventRateLimit(t *testing.T) { expEvents(5, 1) clock.Run(maxServerEventRate * maxServerEventBuffer * 2) expEvents(maxServerEventBuffer+5, maxServerEventBuffer) + srv.unsubscribe() +} + +func TestServerUnsubscribe(t *testing.T) { + rs := &testRequestServer{} + clock := &mclock.Simulated{} + srv := NewServer(rs, clock) + var eventCount int + srv.subscribe(func(event Event) { + eventCount++ + }) + eventCb := rs.eventCb + eventCb(Event{Type: testEventType}) + if eventCount != 1 { + t.Errorf("Server event callback not called before unsubscribe") + } + srv.unsubscribe() + if rs.eventCb != nil { + t.Errorf("Server event callback not removed after unsubscribe") + } + eventCb(Event{Type: testEventType}) + if eventCount != 1 { + t.Errorf("Server event callback called after unsubscribe") + } } type testRequestServer struct { @@ -156,4 +179,4 @@ type testRequestServer struct { func (rs *testRequestServer) Name() string { return "" } func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb } func (rs *testRequestServer) SendRequest(ID, Request) {} -func (rs *testRequestServer) Unsubscribe() {} +func (rs *testRequestServer) Unsubscribe() { rs.eventCb = nil } From fd5078c779f2aab50ea759bd3dcd3c5d4f2556f8 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Thu, 13 Jun 2024 23:52:46 -0700 Subject: [PATCH 360/571] trie/triedb: add Reader to backend interface (#29988) --- triedb/database.go | 12 +++++------- triedb/hashdb/database.go | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/triedb/database.go b/triedb/database.go index 10f77982f336..ef757e7f5bc3 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -74,6 +74,10 @@ type backend interface { // Close closes the trie database backend and releases all held resources. Close() error + + // Reader returns a reader for accessing all trie nodes with provided state + // root. An error will be returned if the requested state is not available. + Reader(root common.Hash) (database.Reader, error) } // Database is the wrapper of the underlying backend which is shared by different @@ -123,13 +127,7 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { // Reader returns a reader for accessing all trie nodes with provided state root. // An error will be returned if the requested state is not available. func (db *Database) Reader(blockRoot common.Hash) (database.Reader, error) { - switch b := db.backend.(type) { - case *hashdb.Database: - return b.Reader(blockRoot) - case *pathdb.Database: - return b.Reader(blockRoot) - } - return nil, errors.New("unknown backend") + return db.backend.Reader(blockRoot) } // Update performs a state transition by committing dirty nodes contained in the diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index ebb5d7205712..bb0deca9a713 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" + "github.com/ethereum/go-ethereum/triedb/database" ) var ( @@ -625,7 +626,7 @@ func (db *Database) Close() error { // Reader retrieves a node reader belonging to the given state root. // An error will be returned if the requested state is not available. -func (db *Database) Reader(root common.Hash) (*reader, error) { +func (db *Database) Reader(root common.Hash) (database.Reader, error) { if _, err := db.node(root); err != nil { return nil, fmt.Errorf("state %#x is not available, %v", root, err) } From 34b46a2f756da71595ac84eb7f25441f2a5b6ebb Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 17 Jun 2024 15:42:39 +0800 Subject: [PATCH 361/571] core/state/snapshot: add a missing lock (#30001) * upgrade lock usage * revert unnecessary change --- core/state/snapshot/snapshot.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 89a4c16c209d..7c76765417aa 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -829,6 +829,8 @@ func (t *Tree) disklayer() *diskLayer { case *diskLayer: return layer case *diffLayer: + layer.lock.RLock() + defer layer.lock.RUnlock() return layer.origin default: panic(fmt.Sprintf("%T: undefined layer", snap)) @@ -860,7 +862,7 @@ func (t *Tree) generating() (bool, error) { return layer.genMarker != nil, nil } -// DiskRoot is a external helper function to return the disk layer root. +// DiskRoot is an external helper function to return the disk layer root. func (t *Tree) DiskRoot() common.Hash { t.lock.Lock() defer t.lock.Unlock() From a58e4f06747b287af6d5befaddaae66c4494f431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 17 Jun 2024 11:15:27 +0300 Subject: [PATCH 362/571] go.mod: update Pebble to sort out a deleted upstream dependency (#30010) --- go.mod | 11 ++++++----- go.sum | 22 ++++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 9947df31f32a..b578ec07b556 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.79.0 - github.com/cockroachdb/pebble v1.1.0 + github.com/cockroachdb/pebble v1.1.1 github.com/consensys/gnark-crypto v0.12.1 github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c github.com/crate-crypto/go-kzg-4844 v1.0.0 @@ -61,7 +61,7 @@ require ( github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/supranational/blst v0.3.11 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.1.0 @@ -95,7 +95,8 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cockroachdb/errors v1.11.1 // indirect + github.com/cockroachdb/errors v1.11.3 // indirect + github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect @@ -105,7 +106,7 @@ require ( github.com/deepmap/oapi-codegen v1.6.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect - github.com/getsentry/sentry-go v0.18.0 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/goccy/go-json v0.10.2 // indirect @@ -116,7 +117,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/klauspost/compress v1.15.15 // indirect + github.com/klauspost/compress v1.16.0 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect diff --git a/go.sum b/go.sum index 5e4b38e9a6bc..168637b0ad5f 100644 --- a/go.sum +++ b/go.sum @@ -116,12 +116,14 @@ github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= -github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4= -github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= +github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= +github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= @@ -187,8 +189,8 @@ github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILD github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= -github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -347,8 +349,8 @@ github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4 github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= -github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -494,8 +496,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= From b78d2352ef55b727ed57d1abe612af09c67be29a Mon Sep 17 00:00:00 2001 From: Zoro <40222601+BabyHalimao@users.noreply.github.com> Date: Mon, 17 Jun 2024 17:03:27 +0800 Subject: [PATCH 363/571] log: fix some functions comments (#29907) updates some docstrings --------- Co-authored-by: rjl493456442 --- log/handler_glog.go | 12 ++++++++++-- log/logger.go | 6 +++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/log/handler_glog.go b/log/handler_glog.go index 625a03640381..739f8c5b427d 100644 --- a/log/handler_glog.go +++ b/log/handler_glog.go @@ -139,11 +139,15 @@ func (h *GlogHandler) Vmodule(ruleset string) error { return nil } +// Enabled implements slog.Handler, reporting whether the handler handles records +// at the given level. func (h *GlogHandler) Enabled(ctx context.Context, lvl slog.Level) bool { // fast-track skipping logging if override not enabled and the provided verbosity is above configured return h.override.Load() || slog.Level(h.level.Load()) <= lvl } +// WithAttrs implements slog.Handler, returning a new Handler whose attributes +// consist of both the receiver's attributes and the arguments. func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { h.lock.RLock() siteCache := maps.Clone(h.siteCache) @@ -164,12 +168,16 @@ func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { return &res } +// WithGroup implements slog.Handler, returning a new Handler with the given +// group appended to the receiver's existing groups. +// +// Note, this function is not implemented. func (h *GlogHandler) WithGroup(name string) slog.Handler { panic("not implemented") } -// Log implements Handler.Log, filtering a log record through the global, local -// and backtrace filters, finally emitting it if either allow it through. +// Handle implements slog.Handler, filtering a log record through the global, +// local and backtrace filters, finally emitting it if either allow it through. func (h *GlogHandler) Handle(_ context.Context, r slog.Record) error { // If the global log level allows, fast track logging if slog.Level(h.level.Load()) <= r.Level { diff --git a/log/logger.go b/log/logger.go index 8b03b68fc86e..016856c8348d 100644 --- a/log/logger.go +++ b/log/logger.go @@ -35,7 +35,7 @@ const ( LvlDebug = LevelDebug ) -// convert from old Geth verbosity level constants +// FromLegacyLevel converts from old Geth verbosity level constants // to levels defined by slog func FromLegacyLevel(lvl int) slog.Level { switch lvl { @@ -107,7 +107,7 @@ type Logger interface { // With returns a new Logger that has this logger's attributes plus the given attributes With(ctx ...interface{}) Logger - // With returns a new Logger that has this logger's attributes plus the given attributes. Identical to 'With'. + // New returns a new Logger that has this logger's attributes plus the given attributes. Identical to 'With'. New(ctx ...interface{}) Logger // Log logs a message at the specified level with context key/value pairs @@ -156,7 +156,7 @@ func (l *logger) Handler() slog.Handler { return l.inner.Handler() } -// Write logs a message at the specified level: +// Write logs a message at the specified level. func (l *logger) Write(level slog.Level, msg string, attrs ...any) { if !l.inner.Enabled(context.Background(), level) { return From 115d154392dc47eedbdfe9e598f2f4d9ae421976 Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 17 Jun 2024 17:42:41 +0800 Subject: [PATCH 364/571] trie, triedb/pathdb: prealloc capacity for map and slice (#29986) --- trie/secure_trie.go | 2 +- trie/trienode/node.go | 2 +- triedb/pathdb/history.go | 14 ++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index fb39a80609f3..cfa7f0bddb0b 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -224,7 +224,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { - preimages := make(map[common.Hash][]byte) + preimages := make(map[common.Hash][]byte, len(t.secKeyCache)) for hk, key := range t.secKeyCache { preimages[common.BytesToHash([]byte(hk))] = key } diff --git a/trie/trienode/node.go b/trie/trienode/node.go index aa8a0f6d99b6..fa7bebe4f98f 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -186,7 +186,7 @@ func (set *MergedNodeSet) Merge(other *NodeSet) error { // Flatten returns a two-dimensional map for internal nodes. func (set *MergedNodeSet) Flatten() map[common.Hash]map[string]*Node { - nodes := make(map[common.Hash]map[string]*Node) + nodes := make(map[common.Hash]map[string]*Node, len(set.Sets)) for owner, set := range set.Sets { nodes[owner] = set.Nodes } diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 3663cbbdb9a1..60ce3dc2bc61 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -384,10 +384,11 @@ func (r *decoder) readAccount(pos int) (accountIndex, []byte, error) { func (r *decoder) readStorage(accIndex accountIndex) ([]common.Hash, map[common.Hash][]byte, error) { var ( last common.Hash - list []common.Hash - storage = make(map[common.Hash][]byte) + count = int(accIndex.storageSlots) + list = make([]common.Hash, 0, count) + storage = make(map[common.Hash][]byte, count) ) - for j := 0; j < int(accIndex.storageSlots); j++ { + for j := 0; j < count; j++ { var ( index slotIndex start = (accIndex.storageOffset + uint32(j)) * uint32(slotIndexSize) @@ -430,9 +431,10 @@ func (r *decoder) readStorage(accIndex accountIndex) ([]common.Hash, map[common. // decode deserializes the account and storage data from the provided byte stream. func (h *history) decode(accountData, storageData, accountIndexes, storageIndexes []byte) error { var ( - accounts = make(map[common.Address][]byte) + count = len(accountIndexes) / accountIndexSize + accounts = make(map[common.Address][]byte, count) storages = make(map[common.Address]map[common.Hash][]byte) - accountList []common.Address + accountList = make([]common.Address, 0, count) storageList = make(map[common.Address][]common.Hash) r = &decoder{ @@ -445,7 +447,7 @@ func (h *history) decode(accountData, storageData, accountIndexes, storageIndexe if err := r.verify(); err != nil { return err } - for i := 0; i < len(accountIndexes)/accountIndexSize; i++ { + for i := 0; i < count; i++ { // Resolve account first accIndex, accData, err := r.readAccount(i) if err != nil { From c736b04d9b3bec8d9281146490b05075a91e7eea Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 17 Jun 2024 23:09:29 +0800 Subject: [PATCH 365/571] triedb/pathdb: use maps.Clone and maps.Keys (#29985) --- triedb/pathdb/history.go | 11 +++-------- triedb/pathdb/nodebuffer.go | 5 ++--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 60ce3dc2bc61..d77f7aa04d07 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie/triestate" + "golang.org/x/exp/maps" ) // State history records the state changes involved in executing a block. The @@ -244,19 +245,13 @@ type history struct { // newHistory constructs the state history object with provided state change set. func newHistory(root common.Hash, parent common.Hash, block uint64, states *triestate.Set) *history { var ( - accountList []common.Address + accountList = maps.Keys(states.Accounts) storageList = make(map[common.Address][]common.Hash) ) - for addr := range states.Accounts { - accountList = append(accountList, addr) - } slices.SortFunc(accountList, common.Address.Cmp) for addr, slots := range states.Storages { - slist := make([]common.Hash, 0, len(slots)) - for slotHash := range slots { - slist = append(slist, slotHash) - } + slist := maps.Keys(slots) slices.SortFunc(slist, common.Hash.Cmp) storageList[addr] = slist } diff --git a/triedb/pathdb/nodebuffer.go b/triedb/pathdb/nodebuffer.go index ff0948410059..d3492602c8b7 100644 --- a/triedb/pathdb/nodebuffer.go +++ b/triedb/pathdb/nodebuffer.go @@ -19,6 +19,7 @@ package pathdb import ( "bytes" "fmt" + "maps" "time" "github.com/VictoriaMetrics/fastcache" @@ -90,12 +91,10 @@ func (b *nodebuffer) commit(nodes map[common.Hash]map[string]*trienode.Node) *no // The nodes belong to original diff layer are still accessible even // after merging, thus the ownership of nodes map should still belong // to original layer and any mutation on it should be prevented. - current = make(map[string]*trienode.Node, len(subset)) for path, n := range subset { - current[path] = n delta += int64(len(n.Blob) + len(path)) } - b.nodes[owner] = current + b.nodes[owner] = maps.Clone(subset) continue } for path, n := range subset { From d8664490da47bfff1854869826268c486e6487d7 Mon Sep 17 00:00:00 2001 From: Dean Eigenmann <7621705+decanus@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:53:00 +0200 Subject: [PATCH 366/571] common/math: fix out of bounds access in json unmarshalling (#30014) Co-authored-by: Martin Holst Swende --- common/math/big.go | 2 +- common/math/integer.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/math/big.go b/common/math/big.go index 721b297c9c4d..d9748d01a39b 100644 --- a/common/math/big.go +++ b/common/math/big.go @@ -54,7 +54,7 @@ func NewHexOrDecimal256(x int64) *HexOrDecimal256 { // It is similar to UnmarshalText, but allows parsing real decimals too, not just // quoted decimal strings. func (i *HexOrDecimal256) UnmarshalJSON(input []byte) error { - if len(input) > 0 && input[0] == '"' { + if len(input) > 1 && input[0] == '"' { input = input[1 : len(input)-1] } return i.UnmarshalText(input) diff --git a/common/math/integer.go b/common/math/integer.go index 080fba8fea89..82de96f9272f 100644 --- a/common/math/integer.go +++ b/common/math/integer.go @@ -46,7 +46,7 @@ type HexOrDecimal64 uint64 // It is similar to UnmarshalText, but allows parsing real decimals too, not just // quoted decimal strings. func (i *HexOrDecimal64) UnmarshalJSON(input []byte) error { - if len(input) > 0 && input[0] == '"' { + if len(input) > 1 && input[0] == '"' { input = input[1 : len(input)-1] } return i.UnmarshalText(input) From 7cf6a63687da2d9300fec495ff4bc978c4b70b65 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 18 Jun 2024 04:52:49 +0200 Subject: [PATCH 367/571] core/state/snapshot: acquire the lock on Release (#30011) * core/state/snapshot: acquire the lock on release * core/state/snapshot: only acquire read-lock when iterating --- core/state/snapshot/snapshot.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 7c76765417aa..752f4359fb85 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -666,6 +666,9 @@ func diffToDisk(bottom *diffLayer) *diskLayer { // Release releases resources func (t *Tree) Release() { + t.lock.RLock() + defer t.lock.RUnlock() + if dl := t.disklayer(); dl != nil { dl.Release() } @@ -850,8 +853,8 @@ func (t *Tree) diskRoot() common.Hash { // generating is an internal helper function which reports whether the snapshot // is still under the construction. func (t *Tree) generating() (bool, error) { - t.lock.Lock() - defer t.lock.Unlock() + t.lock.RLock() + defer t.lock.RUnlock() layer := t.disklayer() if layer == nil { @@ -864,8 +867,8 @@ func (t *Tree) generating() (bool, error) { // DiskRoot is an external helper function to return the disk layer root. func (t *Tree) DiskRoot() common.Hash { - t.lock.Lock() - defer t.lock.Unlock() + t.lock.RLock() + defer t.lock.RUnlock() return t.diskRoot() } From 67a862db9de372cd9c53fb3d7f44252d6b535c28 Mon Sep 17 00:00:00 2001 From: Ha DANG Date: Wed, 19 Jun 2024 13:47:17 +0700 Subject: [PATCH 368/571] cmd/geth, ethdb/pebble: improve database statistic (#29948) * cmd/geth, ethdb/pebble: polish method naming and code comment * implement db stat for pebble * cmd, core, ethdb, internal, trie: remove db property selector * cmd, core, ethdb: fix function description --------- Co-authored-by: prpeh Co-authored-by: Gary Rong --- cmd/geth/chaincmd.go | 4 +-- cmd/geth/dbcmd.go | 20 ++++++-------- core/rawdb/table.go | 6 ++--- ethdb/database.go | 4 +-- ethdb/leveldb/leveldb.go | 54 +++++++++++++++++++++++++++++++------ ethdb/memorydb/memorydb.go | 6 ++--- ethdb/pebble/pebble.go | 6 ++--- ethdb/remotedb/remotedb.go | 4 +-- internal/ethapi/api.go | 4 +-- internal/web3ext/web3ext.go | 1 - trie/trie_test.go | 2 +- 11 files changed, 71 insertions(+), 40 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 2965b99d94f9..9450c09e7e2b 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -336,7 +336,7 @@ func importChain(ctx *cli.Context) error { fmt.Printf("Import done in %v.\n\n", time.Since(start)) // Output pre-compaction stats mostly to see the import trashing - showLeveldbStats(db) + showDBStats(db) // Print the memory statistics used by the importing mem := new(runtime.MemStats) @@ -359,7 +359,7 @@ func importChain(ctx *cli.Context) error { } fmt.Printf("Compaction done in %v.\n\n", time.Since(start)) - showLeveldbStats(db) + showDBStats(db) return importErr } diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 742eadd5f368..4b683569a45e 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -407,17 +407,13 @@ func checkStateContent(ctx *cli.Context) error { return nil } -func showLeveldbStats(db ethdb.KeyValueStater) { - if stats, err := db.Stat("leveldb.stats"); err != nil { +func showDBStats(db ethdb.KeyValueStater) { + stats, err := db.Stat() + if err != nil { log.Warn("Failed to read database stats", "error", err) - } else { - fmt.Println(stats) - } - if ioStats, err := db.Stat("leveldb.iostats"); err != nil { - log.Warn("Failed to read database iostats", "error", err) - } else { - fmt.Println(ioStats) + return } + fmt.Println(stats) } func dbStats(ctx *cli.Context) error { @@ -427,7 +423,7 @@ func dbStats(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() - showLeveldbStats(db) + showDBStats(db) return nil } @@ -439,7 +435,7 @@ func dbCompact(ctx *cli.Context) error { defer db.Close() log.Info("Stats before compaction") - showLeveldbStats(db) + showDBStats(db) log.Info("Triggering compaction") if err := db.Compact(nil, nil); err != nil { @@ -447,7 +443,7 @@ func dbCompact(ctx *cli.Context) error { return err } log.Info("Stats after compaction") - showLeveldbStats(db) + showDBStats(db) return nil } diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 19e4ed5b5c4b..90849fe9d93e 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -147,9 +147,9 @@ func (t *table) NewIterator(prefix []byte, start []byte) ethdb.Iterator { } } -// Stat returns a particular internal stat of the database. -func (t *table) Stat(property string) (string, error) { - return t.db.Stat(property) +// Stat returns the statistic data of the database. +func (t *table) Stat() (string, error) { + return t.db.Stat() } // Compact flattens the underlying data store for the given key range. In essence, diff --git a/ethdb/database.go b/ethdb/database.go index 3ec1f70e3b60..9ef5942a136b 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -39,8 +39,8 @@ type KeyValueWriter interface { // KeyValueStater wraps the Stat method of a backing data store. type KeyValueStater interface { - // Stat returns a particular internal stat of the database. - Stat(property string) (string, error) + // Stat returns the statistic data of the database. + Stat() (string, error) } // Compacter wraps the Compact method of a backing data store. diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 64f51cf21701..92838ad7ab85 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -22,7 +22,6 @@ package leveldb import ( "fmt" - "strings" "sync" "time" @@ -244,14 +243,53 @@ func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { return &snapshot{db: snap}, nil } -// Stat returns a particular internal stat of the database. -func (db *Database) Stat(property string) (string, error) { - if property == "" { - property = "leveldb.stats" - } else if !strings.HasPrefix(property, "leveldb.") { - property = "leveldb." + property +// Stat returns the statistic data of the database. +func (db *Database) Stat() (string, error) { + var stats leveldb.DBStats + if err := db.db.Stats(&stats); err != nil { + return "", err } - return db.db.GetProperty(property) + var ( + message string + totalRead int64 + totalWrite int64 + totalSize int64 + totalTables int + totalDuration time.Duration + ) + if len(stats.LevelSizes) > 0 { + message += " Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" + + "-------+------------+---------------+---------------+---------------+---------------\n" + for level, size := range stats.LevelSizes { + read := stats.LevelRead[level] + write := stats.LevelWrite[level] + duration := stats.LevelDurations[level] + tables := stats.LevelTablesCounts[level] + + if tables == 0 && duration == 0 { + continue + } + totalTables += tables + totalSize += size + totalRead += read + totalWrite += write + totalDuration += duration + message += fmt.Sprintf(" %3d | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", + level, tables, float64(size)/1048576.0, duration.Seconds(), + float64(read)/1048576.0, float64(write)/1048576.0) + } + message += "-------+------------+---------------+---------------+---------------+---------------\n" + message += fmt.Sprintf(" Total | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", + totalTables, float64(totalSize)/1048576.0, totalDuration.Seconds(), + float64(totalRead)/1048576.0, float64(totalWrite)/1048576.0) + message += "-------+------------+---------------+---------------+---------------+---------------\n\n" + } + message += fmt.Sprintf("Read(MB):%.5f Write(MB):%.5f\n", float64(stats.IORead)/1048576.0, float64(stats.IOWrite)/1048576.0) + message += fmt.Sprintf("BlockCache(MB):%.5f FileCache:%d\n", float64(stats.BlockCacheSize)/1048576.0, stats.OpenedTablesCount) + message += fmt.Sprintf("MemoryCompaction:%d Level0Compaction:%d NonLevel0Compaction:%d SeekCompaction:%d\n", stats.MemComp, stats.Level0Comp, stats.NonLevel0Comp, stats.SeekComp) + message += fmt.Sprintf("WriteDelayCount:%d WriteDelayDuration:%s Paused:%t\n", stats.WriteDelayCount, common.PrettyDuration(stats.WriteDelayDuration), stats.WritePaused) + message += fmt.Sprintf("Snapshots:%d Iterators:%d\n", stats.AliveSnapshots, stats.AliveIterators) + return message, nil } // Compact flattens the underlying data store for the given key range. In essence, diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index d1233acb2198..9b0872f89a33 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -182,9 +182,9 @@ func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { return newSnapshot(db), nil } -// Stat returns a particular internal stat of the database. -func (db *Database) Stat(property string) (string, error) { - return "", errors.New("unknown property") +// Stat returns the statistic data of the database. +func (db *Database) Stat() (string, error) { + return "", nil } // Compact is not supported on a memory database, but there's no need either as diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 0fac07c9604e..130d6617b5ba 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -416,10 +416,8 @@ func upperBound(prefix []byte) (limit []byte) { } // Stat returns the internal metrics of Pebble in a text format. It's a developer -// method to read everything there is to read independent of Pebble version. -// -// The property is unused in Pebble as there's only one thing to retrieve. -func (d *Database) Stat(property string) (string, error) { +// method to read everything there is to read, independent of Pebble version. +func (d *Database) Stat() (string, error) { return d.db.Metrics().String(), nil } diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index c1c803caf2b9..bfecde4a3263 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -126,8 +126,8 @@ func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { panic("not supported") } -func (db *Database) Stat(property string) (string, error) { - panic("not supported") +func (db *Database) Stat() (string, error) { + return "", nil } func (db *Database) AncientDatadir() (string, error) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1c209fb5a490..0ecedf113038 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -2108,8 +2108,8 @@ func (api *DebugAPI) PrintBlock(ctx context.Context, number uint64) (string, err } // ChaindbProperty returns leveldb properties of the key-value database. -func (api *DebugAPI) ChaindbProperty(property string) (string, error) { - return api.b.ChainDb().Stat(property) +func (api *DebugAPI) ChaindbProperty() (string, error) { + return api.b.ChainDb().Stat() } // ChaindbCompact flattens the entire key-value database into a single level, diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 1da7d737dd94..4a1a37d722d6 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -263,7 +263,6 @@ web3._extend({ new web3._extend.Method({ name: 'chaindbProperty', call: 'debug_chaindbProperty', - params: 1, outputFormatter: console.log }), new web3._extend.Method({ diff --git a/trie/trie_test.go b/trie/trie_test.go index f31fd393f501..5f706a28befc 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -820,7 +820,7 @@ func (s *spongeDb) Delete(key []byte) error { panic("implement func (s *spongeDb) NewBatch() ethdb.Batch { return &spongeBatch{s} } func (s *spongeDb) NewBatchWithSize(size int) ethdb.Batch { return &spongeBatch{s} } func (s *spongeDb) NewSnapshot() (ethdb.Snapshot, error) { panic("implement me") } -func (s *spongeDb) Stat(property string) (string, error) { panic("implement me") } +func (s *spongeDb) Stat() (string, error) { panic("implement me") } func (s *spongeDb) Compact(start []byte, limit []byte) error { panic("implement me") } func (s *spongeDb) Close() error { return nil } func (s *spongeDb) Put(key []byte, value []byte) error { From 0e3a0a693ce99cca1f928c913108237d4be8c233 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Wed, 19 Jun 2024 00:58:22 -0700 Subject: [PATCH 369/571] trie: don't reset tracer at the end of Commit (#30024) * trie: don't reset tracer at the end of Commit * Update trie.go --------- Co-authored-by: rjl493456442 --- trie/trie.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/trie/trie.go b/trie/trie.go index 935f81fc7d1d..e1a92011084d 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -53,7 +53,6 @@ type Trie struct { reader *trieReader // tracer is the tool to track the trie changes. - // It will be reset after each commit operation. tracer *tracer } @@ -609,7 +608,6 @@ func (t *Trie) Hash() common.Hash { // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { - defer t.tracer.reset() defer func() { t.committed = true }() From c11aac249ddca275a12a1da0e66d1f4c6c21f4f6 Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Wed, 19 Jun 2024 17:06:52 +0800 Subject: [PATCH 370/571] common: using `ParseUint` instead of `ParseInt` (#30020) Since Decimal is defined as unsiged `uint64`, we should use `strconv.ParseUint` instead of `strconv.ParseInt` during unmarshalling. --------- Co-authored-by: Martin Holst Swende --- common/types.go | 2 +- common/types_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/common/types.go b/common/types.go index b914787d1347..fdb25f1b34d1 100644 --- a/common/types.go +++ b/common/types.go @@ -468,7 +468,7 @@ func (d *Decimal) UnmarshalJSON(input []byte) error { if !isString(input) { return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeOf(uint64(0))} } - if i, err := strconv.ParseInt(string(input[1:len(input)-1]), 10, 64); err == nil { + if i, err := strconv.ParseUint(string(input[1:len(input)-1]), 10, 64); err == nil { *d = Decimal(i) return nil } else { diff --git a/common/types_test.go b/common/types_test.go index cec689ea39f7..11247b117bad 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -21,6 +21,7 @@ import ( "database/sql/driver" "encoding/json" "fmt" + "math" "math/big" "reflect" "strings" @@ -595,3 +596,29 @@ func BenchmarkPrettyDuration(b *testing.B) { } b.Logf("Post %s", a) } + +func TestDecimalUnmarshalJSON(t *testing.T) { + // These should error + for _, tc := range []string{``, `"`, `""`, `"-1"`} { + if err := new(Decimal).UnmarshalJSON([]byte(tc)); err == nil { + t.Errorf("input %s should cause error", tc) + } + } + // These should succeed + for _, tc := range []struct { + input string + want uint64 + }{ + {`"0"`, 0}, + {`"9223372036854775807"`, math.MaxInt64}, + {`"18446744073709551615"`, math.MaxUint64}, + } { + have := new(Decimal) + if err := have.UnmarshalJSON([]byte(tc.input)); err != nil { + t.Errorf("input %q triggered error: %v", tc.input, err) + } + if uint64(*have) != tc.want { + t.Errorf("input %q, have %d want %d", tc.input, *have, tc.want) + } + } +} From 27008408a57c77e55d3630adb50c72b0a36abb32 Mon Sep 17 00:00:00 2001 From: psogv0308 Date: Wed, 19 Jun 2024 21:46:57 +0900 Subject: [PATCH 371/571] core/txpool/blobpool: change rw-lock to r-lock (#29989) --- core/txpool/blobpool/blobpool.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index f1c2c10fc965..69423731ee19 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1598,8 +1598,8 @@ func (p *BlobPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool // Nonce returns the next nonce of an account, with all transactions executable // by the pool already applied on top. func (p *BlobPool) Nonce(addr common.Address) uint64 { - p.lock.Lock() - defer p.lock.Unlock() + p.lock.RLock() + defer p.lock.RUnlock() if txs, ok := p.index[addr]; ok { return txs[len(txs)-1].nonce + 1 @@ -1610,8 +1610,8 @@ func (p *BlobPool) Nonce(addr common.Address) uint64 { // Stats retrieves the current pool stats, namely the number of pending and the // number of queued (non-executable) transactions. func (p *BlobPool) Stats() (int, int) { - p.lock.Lock() - defer p.lock.Unlock() + p.lock.RLock() + defer p.lock.RUnlock() var pending int for _, txs := range p.index { From 00675c5876d84bffd44f3b18db9db7892fa3f87e Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 20 Jun 2024 11:47:29 +0800 Subject: [PATCH 372/571] trie/trienode: avoid unnecessary copy (#30019) * avoid unnecessary copy * delete the never used function ProofList * eth/protocols/snap, trie/trienode: polish the code --------- Co-authored-by: Gary Rong --- eth/protocols/snap/handler.go | 10 ++-------- eth/protocols/snap/sync_test.go | 23 ++++++----------------- trie/trienode/proof.go | 10 +++++----- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index bd7ce9e71543..5cbe9d127056 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -332,11 +332,7 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac return nil, nil } } - var proofs [][]byte - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } - return accounts, proofs + return accounts, proof.List() } func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesPacket) ([][]*StorageData, [][]byte) { @@ -438,9 +434,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP return nil, nil } } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } + proofs = append(proofs, proof.List()...) // Proof terminates the reply as proofs are only added if a node // refuses to serve more data (exception when a contract fetch is // finishing, but that's that). diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 82360ae0e30b..c97c3b99b353 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -286,10 +286,7 @@ func createAccountRequestResponse(t *testPeer, root common.Hash, origin common.H t.logger.Error("Could not prove last item", "error", err) } } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } - return keys, vals, proofs + return keys, vals, proof.List() } // defaultStorageRequestHandler is a well-behaving storage request handler @@ -371,9 +368,7 @@ func createStorageRequestResponse(t *testPeer, root common.Hash, accounts []comm t.logger.Error("Could not prove last item", "error", err) } } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } + proofs = append(proofs, proof.List()...) break } } @@ -430,9 +425,7 @@ func createStorageRequestResponseAlwaysProve(t *testPeer, root common.Hash, acco t.logger.Error("Could not prove last item", "error", err) } } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } + proofs = append(proofs, proof.List()...) break } } @@ -586,9 +579,8 @@ func testSyncBloatedProof(t *testing.T, scheme string) { source.accountRequestHandler = func(t *testPeer, requestId uint64, root common.Hash, origin common.Hash, limit common.Hash, cap uint64) error { var ( - proofs [][]byte - keys []common.Hash - vals [][]byte + keys []common.Hash + vals [][]byte ) // The values for _, entry := range t.accountValues { @@ -618,10 +610,7 @@ func testSyncBloatedProof(t *testing.T, scheme string) { keys = append(keys[:1], keys[2:]...) vals = append(vals[:1], vals[2:]...) } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } - if err := t.remote.OnAccounts(t, requestId, keys, vals, proofs); err != nil { + if err := t.remote.OnAccounts(t, requestId, keys, vals, proof.List()); err != nil { t.logger.Info("remote error on delivery (as expected)", "error", err) t.term() // This is actually correct, signal to exit the test successfully diff --git a/trie/trienode/proof.go b/trie/trienode/proof.go index 012f0087dded..d3075ecccf12 100644 --- a/trie/trienode/proof.go +++ b/trie/trienode/proof.go @@ -102,14 +102,14 @@ func (db *ProofSet) DataSize() int { return db.dataSize } -// List converts the node set to a ProofList -func (db *ProofSet) List() ProofList { +// List converts the node set to a slice of bytes. +func (db *ProofSet) List() [][]byte { db.lock.RLock() defer db.lock.RUnlock() - var values ProofList - for _, key := range db.order { - values = append(values, db.nodes[key]) + values := make([][]byte, len(db.order)) + for i, key := range db.order { + values[i] = db.nodes[key] } return values } From 27654d30228f9de2c15e351948103ae619364f36 Mon Sep 17 00:00:00 2001 From: David Theodore <29786815+infosecual@users.noreply.github.com> Date: Thu, 20 Jun 2024 07:08:54 -0500 Subject: [PATCH 373/571] p2p/rlpx: 2KB maximum size for handshake messages (#30029) Co-authored-by: Felix Lange --- p2p/rlpx/rlpx.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/p2p/rlpx/rlpx.go b/p2p/rlpx/rlpx.go index a338490e62b3..dd14822dee76 100644 --- a/p2p/rlpx/rlpx.go +++ b/p2p/rlpx/rlpx.go @@ -604,6 +604,11 @@ func (h *handshakeState) readMsg(msg interface{}, prv *ecdsa.PrivateKey, r io.Re } size := binary.BigEndian.Uint16(prefix) + // baseProtocolMaxMsgSize = 2 * 1024 + if size > 2048 { + return nil, errors.New("message too big") + } + // Read the handshake packet. packet, err := h.rbuf.read(r, int(size)) if err != nil { From e0e45dbc32501d7917edb07083aa1c34ab7b0fb4 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 21 Jun 2024 09:51:03 +0800 Subject: [PATCH 374/571] core/state/snapshot: tiny fixes (#29995) --- core/state/snapshot/generate.go | 9 +-------- core/state/snapshot/snapshot.go | 10 ++-------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index d81a628c91fa..6d9e16307516 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -631,16 +631,10 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er accMarker = nil return nil } - // Always reset the initial account range as 1 whenever recover from the - // interruption. TODO(rjl493456442) can we remove it? - var accountRange = accountCheckRange - if len(accMarker) > 0 { - accountRange = 1 - } origin := common.CopyBytes(accMarker) for { id := trie.StateTrieID(dl.root) - exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, types.FullAccountRLP) + exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountCheckRange, onAccount, types.FullAccountRLP) if err != nil { return err // The procedure it aborted, either by external signal or internal error. } @@ -652,7 +646,6 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er ctx.removeStorageLeft() break } - accountRange = accountCheckRange } return nil } diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 752f4359fb85..e319c8e4e040 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -258,14 +258,6 @@ func (t *Tree) Disable() { for _, layer := range t.layers { switch layer := layer.(type) { case *diskLayer: - - layer.lock.RLock() - generating := layer.genMarker != nil - layer.lock.RUnlock() - if !generating { - // Generator is already aborted or finished - break - } // If the base layer is generating, abort it if layer.genAbort != nil { abort := make(chan *generatorStats) @@ -276,6 +268,7 @@ func (t *Tree) Disable() { layer.lock.Lock() layer.stale = true layer.lock.Unlock() + layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale @@ -740,6 +733,7 @@ func (t *Tree) Rebuild(root common.Hash) { layer.lock.Lock() layer.stale = true layer.lock.Unlock() + layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale From c10ac4f48fb9c985390be0f46115aaa40a4ef16d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 21 Jun 2024 15:42:43 +0800 Subject: [PATCH 375/571] Revert "core/state/snapshot: tiny fixes" (#30039) Revert "core/state/snapshot: tiny fixes (#29995)" This reverts commit e0e45dbc32501d7917edb07083aa1c34ab7b0fb4. --- core/state/snapshot/generate.go | 9 ++++++++- core/state/snapshot/snapshot.go | 10 ++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 6d9e16307516..d81a628c91fa 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -631,10 +631,16 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er accMarker = nil return nil } + // Always reset the initial account range as 1 whenever recover from the + // interruption. TODO(rjl493456442) can we remove it? + var accountRange = accountCheckRange + if len(accMarker) > 0 { + accountRange = 1 + } origin := common.CopyBytes(accMarker) for { id := trie.StateTrieID(dl.root) - exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountCheckRange, onAccount, types.FullAccountRLP) + exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, types.FullAccountRLP) if err != nil { return err // The procedure it aborted, either by external signal or internal error. } @@ -646,6 +652,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er ctx.removeStorageLeft() break } + accountRange = accountCheckRange } return nil } diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index e319c8e4e040..752f4359fb85 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -258,6 +258,14 @@ func (t *Tree) Disable() { for _, layer := range t.layers { switch layer := layer.(type) { case *diskLayer: + + layer.lock.RLock() + generating := layer.genMarker != nil + layer.lock.RUnlock() + if !generating { + // Generator is already aborted or finished + break + } // If the base layer is generating, abort it if layer.genAbort != nil { abort := make(chan *generatorStats) @@ -268,7 +276,6 @@ func (t *Tree) Disable() { layer.lock.Lock() layer.stale = true layer.lock.Unlock() - layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale @@ -733,7 +740,6 @@ func (t *Tree) Rebuild(root common.Hash) { layer.lock.Lock() layer.stale = true layer.lock.Unlock() - layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale From a71f6f91fdb2fcccdd0c1e336267951d45932f26 Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Fri, 21 Jun 2024 21:29:07 +0800 Subject: [PATCH 376/571] p2p/discover: improve flaky revalidation tests (#30023) --- p2p/discover/table_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 2f1797d1e239..8cc4ae33b2eb 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -135,7 +135,7 @@ func waitForRevalidationPing(t *testing.T, transport *pingRecorder, tab *Table, simclock.Run(tab.cfg.PingInterval * slowRevalidationFactor) p := transport.waitPing(2 * time.Second) if p == nil { - t.Fatal("Table did not send revalidation ping") + continue } if id == (enode.ID{}) || p.ID() == id { return p From d8ea7ac2b056f94ed77e18493d5d17f90f1c7747 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 25 Jun 2024 03:14:12 -0600 Subject: [PATCH 377/571] cmd/blsync: use debug.Setup for logging configuration (#30065) --- cmd/blsync/main.go | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go index 2aa3d9a24ed7..854c99703c5c 100644 --- a/cmd/blsync/main.go +++ b/cmd/blsync/main.go @@ -19,39 +19,21 @@ package main import ( "context" "fmt" - "io" "os" "github.com/ethereum/go-ethereum/beacon/blsync" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" - "github.com/mattn/go-colorable" - "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" ) -var ( - verbosityFlag = &cli.IntFlag{ - Name: "verbosity", - Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", - Value: 3, - Category: flags.LoggingCategory, - } - vmoduleFlag = &cli.StringFlag{ - Name: "vmodule", - Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", - Value: "", - Hidden: true, - Category: flags.LoggingCategory, - } -) - func main() { app := flags.NewApp("beacon light syncer tool") - app.Flags = []cli.Flag{ + app.Flags = flags.Merge([]cli.Flag{ utils.BeaconApiFlag, utils.BeaconApiHeaderFlag, utils.BeaconThresholdFlag, @@ -66,8 +48,16 @@ func main() { utils.GoerliFlag, utils.BlsyncApiFlag, utils.BlsyncJWTSecretFlag, - verbosityFlag, - vmoduleFlag, + }, + debug.Flags, + ) + app.Before = func(ctx *cli.Context) error { + flags.MigrateGlobalFlags(ctx) + return debug.Setup(ctx) + } + app.After = func(ctx *cli.Context) error { + debug.Exit() + return nil } app.Action = sync @@ -78,14 +68,6 @@ func main() { } func sync(ctx *cli.Context) error { - usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" - output := io.Writer(os.Stderr) - if usecolor { - output = colorable.NewColorable(os.Stderr) - } - verbosity := log.FromLegacyLevel(ctx.Int(verbosityFlag.Name)) - log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor))) - // set up blsync client := blsync.NewClient(ctx) client.SetEngineRPC(makeRPCClient(ctx)) From 0a651f8972392943b22120d2444adcfe8a480d14 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 25 Jun 2024 03:16:27 -0600 Subject: [PATCH 378/571] .github: add lightclient as codeowner to relevant packages (#30062) --- .github/CODEOWNERS | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0dabaf4df5cf..ec2efb10e354 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,14 +4,18 @@ accounts/usbwallet @karalabe accounts/scwallet @gballet accounts/abi @gballet @MariusVanDerWijden +beacon/engine @lightclient cmd/clef @holiman +cmd/evm @holiman @MariusVanDerWijden @lightclient consensus @karalabe core/ @karalabe @holiman @rjl493456442 eth/ @karalabe @holiman @rjl493456442 -eth/catalyst/ @gballet +eth/catalyst/ @gballet @lightclient eth/tracers/ @s1na core/tracing/ @s1na graphql/ @s1na +internal/ethapi @lightclient +internal/era @lightclient les/ @zsfelfoldi @rjl493456442 light/ @zsfelfoldi @rjl493456442 node/ @fjl From fe0c0b04fee6d7fbaad77540ceaed4df84939ba7 Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Tue, 25 Jun 2024 17:24:33 +0800 Subject: [PATCH 379/571] accounts/keystore: use t.TempDir in test (#30052) --- accounts/keystore/account_cache_test.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index 6bc14f5bb6d1..41a300224842 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -325,11 +325,7 @@ func TestUpdatedKeyfileContents(t *testing.T) { t.Parallel() // Create a temporary keystore to test with - dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int())) - - // Create the directory - os.MkdirAll(dir, 0700) - defer os.RemoveAll(dir) + dir := t.TempDir() ks := NewKeyStore(dir, LightScryptN, LightScryptP) From 73f7e7c0878b61eceb11923187a34660a7218f47 Mon Sep 17 00:00:00 2001 From: AMIR <31338382+amiremohamadi@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:00:58 +0330 Subject: [PATCH 380/571] internal/debug: remove unnecessary log level assignment (#30044) Log level is specified in L259 so it's unnecessary to specify it for handlers (L234, L236). --- internal/debug/flags.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 361dc6fcca6a..19222c8325f9 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -231,9 +231,9 @@ func Setup(ctx *cli.Context) error { case ctx.Bool(logjsonFlag.Name): // Retain backwards compatibility with `--log.json` flag if `--log.format` not set defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead") - handler = log.JSONHandlerWithLevel(output, log.LevelInfo) + handler = log.JSONHandler(output) case logFmtFlag == "json": - handler = log.JSONHandlerWithLevel(output, log.LevelInfo) + handler = log.JSONHandler(output) case logFmtFlag == "logfmt": handler = log.LogfmtHandler(output) case logFmtFlag == "", logFmtFlag == "terminal": From ed8fd0ac0919ee954cfa621d16a5d0cfbf30c96d Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 25 Jun 2024 04:48:08 -0700 Subject: [PATCH 381/571] all: stateless witness builder and (self-)cross validator (#29719) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * all: add stateless verifications * all: simplify witness and integrate it into live geth --------- Co-authored-by: Péter Szilágyi --- cmd/evm/blockrunner.go | 2 +- core/block_validator.go | 37 ++++++- core/blockchain.go | 33 ++++-- core/blockchain_test.go | 3 +- core/state/database.go | 4 + core/state/state_object.go | 16 ++- core/state/statedb.go | 85 +++++++++++++-- core/state_prefetcher.go | 11 +- core/state_processor.go | 16 ++- core/stateless.go | 73 +++++++++++++ core/stateless/database.go | 60 +++++++++++ core/stateless/encoding.go | 129 ++++++++++++++++++++++ core/stateless/gen_encoding_json.go | 74 +++++++++++++ core/stateless/witness.go | 159 ++++++++++++++++++++++++++++ core/types.go | 7 +- core/vm/evm.go | 12 +++ core/vm/instructions.go | 16 ++- core/vm/interface.go | 3 + tests/block_test.go | 52 ++++----- tests/block_test_util.go | 5 +- trie/secure_trie.go | 5 + trie/trie.go | 12 +++ trie/verkle.go | 5 + 23 files changed, 738 insertions(+), 81 deletions(-) create mode 100644 core/stateless.go create mode 100644 core/stateless/database.go create mode 100644 core/stateless/encoding.go create mode 100644 core/stateless/gen_encoding_json.go create mode 100644 core/stateless/witness.go diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 0275c019bc61..d5cd8d8e3de2 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -86,7 +86,7 @@ func blockTestCmd(ctx *cli.Context) error { continue } test := tests[name] - if err := test.Run(false, rawdb.HashScheme, tracer, func(res error, chain *core.BlockChain) { + if err := test.Run(false, rawdb.HashScheme, false, tracer, func(res error, chain *core.BlockChain) { if ctx.Bool(DumpFlag.Name) { if state, _ := chain.State(); state != nil { fmt.Println(string(state.Dump(nil))) diff --git a/core/block_validator.go b/core/block_validator.go index 3d49f4e6a3df..75f7f8a94b68 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -20,8 +20,10 @@ import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" @@ -34,14 +36,12 @@ import ( type BlockValidator struct { config *params.ChainConfig // Chain configuration options bc *BlockChain // Canonical block chain - engine consensus.Engine // Consensus engine used for validating } // NewBlockValidator returns a new block validator which is safe for re-use -func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator { +func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *BlockValidator { validator := &BlockValidator{ config: config, - engine: engine, bc: blockchain, } return validator @@ -59,7 +59,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // Header validity is known at this point. Here we verify that uncles, transactions // and withdrawals given in the block body match the header. header := block.Header() - if err := v.engine.VerifyUncles(v.bc, block); err != nil { + if err := v.bc.engine.VerifyUncles(v.bc, block); err != nil { return err } if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash { @@ -121,7 +121,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // ValidateState validates the various changes that happen after a state transition, // such as amount of used gas, the receipt roots and the state root itself. -func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { +func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error { header := block.Header() if block.GasUsed() != usedGas { return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) @@ -132,6 +132,11 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD if rbloom != header.Bloom { return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) } + // In stateless mode, return early because the receipt and state root are not + // provided through the witness, rather the cross validator needs to return it. + if stateless { + return nil + } // The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) if receiptSha != header.ReceiptHash { @@ -145,6 +150,28 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD return nil } +// ValidateWitness cross validates a block execution with stateless remote clients. +// +// Normally we'd distribute the block witness to remote cross validators, wait +// for them to respond and then merge the results. For now, however, it's only +// Geth, so do an internal stateless run. +func (v *BlockValidator) ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error { + // Run the cross client stateless execution + // TODO(karalabe): Self-stateless for now, swap with other clients + crossReceiptRoot, crossStateRoot, err := ExecuteStateless(v.config, witness) + if err != nil { + return fmt.Errorf("stateless execution failed: %v", err) + } + // Stateless cross execution suceeeded, validate the withheld computed fields + if crossReceiptRoot != receiptRoot { + return fmt.Errorf("cross validator receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, receiptRoot) + } + if crossStateRoot != stateRoot { + return fmt.Errorf("cross validator state root mismatch (cross: %x local: %x)", crossStateRoot, stateRoot) + } + return nil +} + // CalcGasLimit computes the gas limit of the next block after parent. It aims // to keep the baseline gas close to the provided target, and increase it towards // the target if the baseline gas is lower. diff --git a/core/blockchain.go b/core/blockchain.go index ac4eb1c47e1c..05ebfd18b830 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -302,18 +303,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis vmConfig: vmConfig, logger: vmConfig.Tracer, } - bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) - bc.forker = NewForkChoice(bc, shouldPreserve) - bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) - bc.validator = NewBlockValidator(chainConfig, bc, engine) - bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine) - bc.processor = NewStateProcessor(chainConfig, bc, engine) - var err error bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped) if err != nil { return nil, err } + bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) + bc.forker = NewForkChoice(bc, shouldPreserve) + bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) + bc.validator = NewBlockValidator(chainConfig, bc) + bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc) + bc.processor = NewStateProcessor(chainConfig, bc.hc) + bc.genesisBlock = bc.GetBlockByNumber(0) if bc.genesisBlock == nil { return nil, ErrNoGenesis @@ -1809,7 +1810,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // while processing transactions. Before Byzantium the prefetcher is mostly // useless due to the intermediate root hashing after each transaction. if bc.chainConfig.IsByzantium(block.Number()) { - statedb.StartPrefetcher("chain", !bc.vmConfig.EnableWitnessCollection) + var witness *stateless.Witness + if bc.vmConfig.EnableWitnessCollection { + witness, err = stateless.NewWitness(bc, block) + if err != nil { + return it.index, err + } + } + statedb.StartPrefetcher("chain", witness) } activeState = statedb @@ -1924,11 +1932,18 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s ptime := time.Since(pstart) vstart := time.Now() - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { bc.reportBlock(block, receipts, err) return nil, err } vtime := time.Since(vstart) + + if witness := statedb.Witness(); witness != nil { + if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil { + bc.reportBlock(block, receipts, err) + return nil, fmt.Errorf("cross verification failed: %v", err) + } + } proctime := time.Since(start) // processing + validation // Update the metrics touched during block processing and validation diff --git a/core/blockchain_test.go b/core/blockchain_test.go index e4bc3e09a657..4f28c6f5e681 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -168,8 +168,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.reportBlock(block, receipts, err) return err } - err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas) - if err != nil { + if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { blockchain.reportBlock(block, receipts, err) return err } diff --git a/core/state/database.go b/core/state/database.go index d71f8f34b6f6..d54417d2f91e 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -125,6 +125,10 @@ type Trie interface { // be created with new root and updated trie database for following usage Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) + // Witness returns a set containing all trie nodes that have been accessed. + // The returned map could be nil if the witness is empty. + Witness() map[string]struct{} + // NodeIterator returns an iterator that returns nodes of the trie. Iteration // starts at the key after the given start key. And error will be returned // if fails to create node iterator. diff --git a/core/state/state_object.go b/core/state/state_object.go index 5c1dab53dc4e..880b715b4b37 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -323,11 +323,17 @@ func (s *stateObject) finalise() { // // It assumes all the dirty storage slots have been finalized before. func (s *stateObject) updateTrie() (Trie, error) { - // Short circuit if nothing changed, don't bother with hashing anything + // Short circuit if nothing was accessed, don't trigger a prefetcher warning if len(s.uncommittedStorage) == 0 { - return s.trie, nil + // Nothing was written, so we could stop early. Unless we have both reads + // and witness collection enabled, in which case we need to fetch the trie. + if s.db.witness == nil || len(s.originStorage) == 0 { + return s.trie, nil + } } - // Retrieve a pretecher populated trie, or fall back to the database + // Retrieve a pretecher populated trie, or fall back to the database. This will + // block until all prefetch tasks are done, which are needed for witnesses even + // for unmodified state objects. tr := s.getPrefetchedTrie() if tr != nil { // Prefetcher returned a live trie, swap it out for the current one @@ -341,6 +347,10 @@ func (s *stateObject) updateTrie() (Trie, error) { return nil, err } } + // Short circuit if nothing changed, don't bother with hashing anything + if len(s.uncommittedStorage) == 0 { + return s.trie, nil + } // Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes // in circumstances similar to the following: // diff --git a/core/state/statedb.go b/core/state/statedb.go index 4f84d93d63c3..ac82a8e3e3ab 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -105,7 +106,7 @@ type StateDB struct { // resurrection. The account value is tracked as the original value // before the transition. This map is populated at the transaction // boundaries. - stateObjectsDestruct map[common.Address]*types.StateAccount + stateObjectsDestruct map[common.Address]*stateObject // This map tracks the account mutations that occurred during the // transition. Uncommitted mutations belonging to the same account @@ -146,6 +147,9 @@ type StateDB struct { validRevisions []revision nextRevisionId int + // State witness if cross validation is needed + witness *stateless.Witness + // Measurements gathered during execution for debugging purposes AccountReads time.Duration AccountHashes time.Duration @@ -177,7 +181,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) originalRoot: root, snaps: snaps, stateObjects: make(map[common.Address]*stateObject), - stateObjectsDestruct: make(map[common.Address]*types.StateAccount), + stateObjectsDestruct: make(map[common.Address]*stateObject), mutations: make(map[common.Address]*mutation), logs: make(map[common.Hash][]*types.Log), preimages: make(map[common.Hash][]byte), @@ -200,14 +204,19 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) { // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. -func (s *StateDB) StartPrefetcher(namespace string, noreads bool) { +func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) { + // Terminate any previously running prefetcher if s.prefetcher != nil { s.prefetcher.terminate(false) s.prefetcher.report() s.prefetcher = nil } + // Enable witness collection if requested + s.witness = witness + + // If snapshots are enabled, start prefethers explicitly if s.snap != nil { - s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, noreads) + s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, witness == nil) // With the switch to the Proof-of-Stake consensus algorithm, block production // rewards are now handled at the consensus layer. Consequently, a block may @@ -582,7 +591,6 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { start := time.Now() acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes())) s.SnapshotAccountReads += time.Since(start) - if err == nil { if acc == nil { return nil @@ -683,7 +691,7 @@ func (s *StateDB) Copy() *StateDB { hasher: crypto.NewKeccakState(), originalRoot: s.originalRoot, stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)), - stateObjectsDestruct: maps.Clone(s.stateObjectsDestruct), + stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)), mutations: make(map[common.Address]*mutation, len(s.mutations)), dbErr: s.dbErr, refund: s.refund, @@ -703,10 +711,17 @@ func (s *StateDB) Copy() *StateDB { snaps: s.snaps, snap: s.snap, } + if s.witness != nil { + state.witness = s.witness.Copy() + } // Deep copy cached state objects. for addr, obj := range s.stateObjects { state.stateObjects[addr] = obj.deepCopy(state) } + // Deep copy destructed state objects. + for addr, obj := range s.stateObjectsDestruct { + state.stateObjectsDestruct[addr] = obj.deepCopy(state) + } // Deep copy the object state markers. for addr, op := range s.mutations { state.mutations[addr] = op.copy() @@ -788,7 +803,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // set indefinitely). Note only the first occurred self-destruct // event is tracked. if _, ok := s.stateObjectsDestruct[obj.address]; !ok { - s.stateObjectsDestruct[obj.address] = obj.origin + s.stateObjectsDestruct[obj.address] = obj } } else { obj.finalise() @@ -846,9 +861,46 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { obj := s.stateObjects[addr] // closure for the task runner below workers.Go(func() error { obj.updateRoot() + + // If witness building is enabled and the state object has a trie, + // gather the witnesses for its specific storage trie + if s.witness != nil && obj.trie != nil { + s.witness.AddState(obj.trie.Witness()) + } return nil }) } + // If witness building is enabled, gather all the read-only accesses + if s.witness != nil { + // Pull in anything that has been accessed before destruction + for _, obj := range s.stateObjectsDestruct { + // Skip any objects that haven't touched their storage + if len(obj.originStorage) == 0 { + continue + } + if trie := obj.getPrefetchedTrie(); trie != nil { + s.witness.AddState(trie.Witness()) + } else if obj.trie != nil { + s.witness.AddState(obj.trie.Witness()) + } + } + // Pull in only-read and non-destructed trie witnesses + for _, obj := range s.stateObjects { + // Skip any objects that have been updated + if _, ok := s.mutations[obj.address]; ok { + continue + } + // Skip any objects that haven't touched their storage + if len(obj.originStorage) == 0 { + continue + } + if trie := obj.getPrefetchedTrie(); trie != nil { + s.witness.AddState(trie.Witness()) + } else if obj.trie != nil { + s.witness.AddState(obj.trie.Witness()) + } + } + } workers.Wait() s.StorageUpdates += time.Since(start) @@ -904,7 +956,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // Track the amount of time wasted on hashing the account trie defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) - return s.trie.Hash() + hash := s.trie.Hash() + + // If witness building is enabled, gather the account trie witness + if s.witness != nil { + s.witness.AddState(s.trie.Witness()) + } + return hash } // SetTxContext sets the current transaction hash and index which are @@ -1060,7 +1118,9 @@ func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trieno buf = crypto.NewKeccakState() deletes = make(map[common.Hash]*accountDelete) ) - for addr, prev := range s.stateObjectsDestruct { + for addr, prevObj := range s.stateObjectsDestruct { + prev := prevObj.origin + // The account was non-existent, and it's marked as destructed in the scope // of block. It can be either case (a) or (b) and will be interpreted as // null->null state transition. @@ -1239,7 +1299,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { // Clear all internal flags and update state root at the end. s.mutations = make(map[common.Address]*mutation) - s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) + s.stateObjectsDestruct = make(map[common.Address]*stateObject) origin := s.originalRoot s.originalRoot = root @@ -1412,3 +1472,8 @@ func (s *StateDB) markUpdate(addr common.Address) { func (s *StateDB) PointCache() *utils.PointCache { return s.db.PointCache() } + +// Witness retrieves the current state witness being collected. +func (s *StateDB) Witness() *stateless.Witness { + return s.witness +} diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index ff867309de30..31405fa078bb 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -19,7 +19,6 @@ package core import ( "sync/atomic" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -31,16 +30,14 @@ import ( // data from disk before the main block processor start executing. type statePrefetcher struct { config *params.ChainConfig // Chain configuration options - bc *BlockChain // Canonical block chain - engine consensus.Engine // Consensus engine used for block rewards + chain *HeaderChain // Canonical block chain } // newStatePrefetcher initialises a new statePrefetcher. -func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *statePrefetcher { +func newStatePrefetcher(config *params.ChainConfig, chain *HeaderChain) *statePrefetcher { return &statePrefetcher{ config: config, - bc: bc, - engine: engine, + chain: chain, } } @@ -51,7 +48,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c var ( header = block.Header() gaspool = new(GasPool).AddGas(block.GasLimit()) - blockContext = NewEVMBlockContext(header, p.bc, nil) + blockContext = NewEVMBlockContext(header, p.chain, nil) evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) signer = types.MakeSigner(p.config, header.Number, header.Time) ) diff --git a/core/state_processor.go b/core/state_processor.go index 7166ed8bd872..c21f644f9851 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -22,7 +22,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -37,16 +36,14 @@ import ( // StateProcessor implements Processor. type StateProcessor struct { config *params.ChainConfig // Chain configuration options - bc *BlockChain // Canonical block chain - engine consensus.Engine // Consensus engine used for block rewards + chain *HeaderChain // Canonical header chain } // NewStateProcessor initialises a new StateProcessor. -func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor { +func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StateProcessor { return &StateProcessor{ config: config, - bc: bc, - engine: engine, + chain: chain, } } @@ -73,10 +70,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg misc.ApplyDAOHardFork(statedb) } var ( - context = NewEVMBlockContext(header, p.bc, nil) - vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) + context vm.BlockContext signer = types.MakeSigner(p.config, header.Number, header.Time) ) + context = NewEVMBlockContext(header, p.chain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } @@ -101,7 +99,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, nil, 0, errors.New("withdrawals before shanghai") } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - p.engine.Finalize(p.bc, header, statedb, block.Body()) + p.chain.engine.Finalize(p.chain, header, statedb, block.Body()) return receipts, allLogs, *usedGas, nil } diff --git a/core/stateless.go b/core/stateless.go new file mode 100644 index 000000000000..4c7e6f31027f --- /dev/null +++ b/core/stateless.go @@ -0,0 +1,73 @@ +// Copyright 2024 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 core + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/stateless" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/triedb" +) + +// ExecuteStateless runs a stateless execution based on a witness, verifies +// everything it can locally and returns the two computed fields that need the +// other side to explicitly check. +// +// This method is a bit of a sore thumb here, but: +// - It cannot be placed in core/stateless, because state.New prodces a circular dep +// - It cannot be placed outside of core, because it needs to construct a dud headerchain +// +// TODO(karalabe): Would be nice to resolve both issues above somehow and move it. +func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (common.Hash, common.Hash, error) { + // Create and populate the state database to serve as the stateless backend + memdb := witness.MakeHashDB() + + db, err := state.New(witness.Root(), state.NewDatabaseWithConfig(memdb, triedb.HashDefaults), nil) + if err != nil { + return common.Hash{}, common.Hash{}, err + } + // Create a blockchain that is idle, but can be used to access headers through + chain := &HeaderChain{ + config: config, + chainDb: memdb, + headerCache: lru.NewCache[common.Hash, *types.Header](256), + engine: beacon.New(ethash.NewFaker()), + } + processor := NewStateProcessor(config, chain) + validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block + + // Run the stateless blocks processing and self-validate certain fields + receipts, _, usedGas, err := processor.Process(witness.Block, db, vm.Config{}) + if err != nil { + return common.Hash{}, common.Hash{}, err + } + if err = validator.ValidateState(witness.Block, db, receipts, usedGas, true); err != nil { + return common.Hash{}, common.Hash{}, err + } + // Almost everything validated, but receipt and state root needs to be returned + receiptRoot := types.DeriveSha(receipts, trie.NewStackTrie(nil)) + stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number())) + + return receiptRoot, stateRoot, nil +} diff --git a/core/stateless/database.go b/core/stateless/database.go new file mode 100644 index 000000000000..135da621934c --- /dev/null +++ b/core/stateless/database.go @@ -0,0 +1,60 @@ +// Copyright 2024 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 stateless + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" +) + +// MakeHashDB imports tries, codes and block hashes from a witness into a new +// hash-based memory db. We could eventually rewrite this into a pathdb, but +// simple is better for now. +func (w *Witness) MakeHashDB() ethdb.Database { + var ( + memdb = rawdb.NewMemoryDatabase() + hasher = crypto.NewKeccakState() + hash = make([]byte, 32) + ) + // Inject all the "block hashes" (i.e. headers) into the ephemeral database + for _, header := range w.Headers { + rawdb.WriteHeader(memdb, header) + } + // Inject all the bytecodes into the ephemeral database + for code := range w.Codes { + blob := []byte(code) + + hasher.Reset() + hasher.Write(blob) + hasher.Read(hash) + + rawdb.WriteCode(memdb, common.BytesToHash(hash), blob) + } + // Inject all the MPT trie nodes into the ephemeral database + for node := range w.State { + blob := []byte(node) + + hasher.Reset() + hasher.Write(blob) + hasher.Read(hash) + + rawdb.WriteLegacyTrieNode(memdb, common.BytesToHash(hash), blob) + } + return memdb +} diff --git a/core/stateless/encoding.go b/core/stateless/encoding.go new file mode 100644 index 000000000000..2b7245d377e3 --- /dev/null +++ b/core/stateless/encoding.go @@ -0,0 +1,129 @@ +// Copyright 2024 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 stateless + +import ( + "bytes" + "errors" + "fmt" + "io" + "slices" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +//go:generate go run github.com/fjl/gencodec -type extWitness -field-override extWitnessMarshalling -out gen_encoding_json.go + +// toExtWitness converts our internal witness representation to the consensus one. +func (w *Witness) toExtWitness() *extWitness { + ext := &extWitness{ + Block: w.Block, + Headers: w.Headers, + } + ext.Codes = make([][]byte, 0, len(w.Codes)) + for code := range w.Codes { + ext.Codes = append(ext.Codes, []byte(code)) + } + slices.SortFunc(ext.Codes, bytes.Compare) + + ext.State = make([][]byte, 0, len(w.State)) + for node := range w.State { + ext.State = append(ext.State, []byte(node)) + } + slices.SortFunc(ext.State, bytes.Compare) + return ext +} + +// fromExtWitness converts the consensus witness format into our internal one. +func (w *Witness) fromExtWitness(ext *extWitness) error { + w.Block, w.Headers = ext.Block, ext.Headers + + w.Codes = make(map[string]struct{}, len(ext.Codes)) + for _, code := range ext.Codes { + w.Codes[string(code)] = struct{}{} + } + w.State = make(map[string]struct{}, len(ext.State)) + for _, node := range ext.State { + w.State[string(node)] = struct{}{} + } + return w.sanitize() +} + +// MarshalJSON marshals a witness as JSON. +func (w *Witness) MarshalJSON() ([]byte, error) { + return w.toExtWitness().MarshalJSON() +} + +// EncodeRLP serializes a witness as RLP. +func (w *Witness) EncodeRLP(wr io.Writer) error { + return rlp.Encode(wr, w.toExtWitness()) +} + +// UnmarshalJSON unmarshals from JSON. +func (w *Witness) UnmarshalJSON(input []byte) error { + var ext extWitness + if err := ext.UnmarshalJSON(input); err != nil { + return err + } + return w.fromExtWitness(&ext) +} + +// DecodeRLP decodes a witness from RLP. +func (w *Witness) DecodeRLP(s *rlp.Stream) error { + var ext extWitness + if err := s.Decode(&ext); err != nil { + return err + } + return w.fromExtWitness(&ext) +} + +// sanitize checks for some mandatory fields in the witness after decoding so +// the rest of the code can assume invariants and doesn't have to deal with +// corrupted data. +func (w *Witness) sanitize() error { + // Verify that the "parent" header (i.e. index 0) is available, and is the + // true parent of the block-to-be executed, since we use that to link the + // current block to the pre-state. + if len(w.Headers) == 0 { + return errors.New("parent header (for pre-root hash) missing") + } + for i, header := range w.Headers { + if header == nil { + return fmt.Errorf("witness header nil at position %d", i) + } + } + if w.Headers[0].Hash() != w.Block.ParentHash() { + return fmt.Errorf("parent hash different: witness %v, block parent %v", w.Headers[0].Hash(), w.Block.ParentHash()) + } + return nil +} + +// extWitness is a witness RLP encoding for transferring across clients. +type extWitness struct { + Block *types.Block `json:"block" gencodec:"required"` + Headers []*types.Header `json:"headers" gencodec:"required"` + Codes [][]byte `json:"codes"` + State [][]byte `json:"state"` +} + +// extWitnessMarshalling defines the hex marshalling types for a witness. +type extWitnessMarshalling struct { + Codes []hexutil.Bytes + State []hexutil.Bytes +} diff --git a/core/stateless/gen_encoding_json.go b/core/stateless/gen_encoding_json.go new file mode 100644 index 000000000000..1d0497976e34 --- /dev/null +++ b/core/stateless/gen_encoding_json.go @@ -0,0 +1,74 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package stateless + +import ( + "encoding/json" + "errors" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" +) + +var _ = (*extWitnessMarshalling)(nil) + +// MarshalJSON marshals as JSON. +func (e extWitness) MarshalJSON() ([]byte, error) { + type extWitness struct { + Block *types.Block `json:"block" gencodec:"required"` + Headers []*types.Header `json:"headers" gencodec:"required"` + Codes []hexutil.Bytes `json:"codes"` + State []hexutil.Bytes `json:"state"` + } + var enc extWitness + enc.Block = e.Block + enc.Headers = e.Headers + if e.Codes != nil { + enc.Codes = make([]hexutil.Bytes, len(e.Codes)) + for k, v := range e.Codes { + enc.Codes[k] = v + } + } + if e.State != nil { + enc.State = make([]hexutil.Bytes, len(e.State)) + for k, v := range e.State { + enc.State[k] = v + } + } + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (e *extWitness) UnmarshalJSON(input []byte) error { + type extWitness struct { + Block *types.Block `json:"block" gencodec:"required"` + Headers []*types.Header `json:"headers" gencodec:"required"` + Codes []hexutil.Bytes `json:"codes"` + State []hexutil.Bytes `json:"state"` + } + var dec extWitness + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Block == nil { + return errors.New("missing required field 'block' for extWitness") + } + e.Block = dec.Block + if dec.Headers == nil { + return errors.New("missing required field 'headers' for extWitness") + } + e.Headers = dec.Headers + if dec.Codes != nil { + e.Codes = make([][]byte, len(dec.Codes)) + for k, v := range dec.Codes { + e.Codes[k] = v + } + } + if dec.State != nil { + e.State = make([][]byte, len(dec.State)) + for k, v := range dec.State { + e.State[k] = v + } + } + return nil +} diff --git a/core/stateless/witness.go b/core/stateless/witness.go new file mode 100644 index 000000000000..7622c5eb610d --- /dev/null +++ b/core/stateless/witness.go @@ -0,0 +1,159 @@ +// Copyright 2024 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 stateless + +import ( + "bytes" + "errors" + "fmt" + "maps" + "slices" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +// HeaderReader is an interface to pull in headers in place of block hashes for +// the witness. +type HeaderReader interface { + // GetHeader retrieves a block header from the database by hash and number, + GetHeader(hash common.Hash, number uint64) *types.Header +} + +// Witness encompasses a block, state and any other chain data required to apply +// a set of transactions and derive a post state/receipt root. +type Witness struct { + Block *types.Block // Current block with rootHash and receiptHash zeroed out + Headers []*types.Header // Past headers in reverse order (0=parent, 1=parent's-parent, etc). First *must* be set. + Codes map[string]struct{} // Set of bytecodes ran or accessed + State map[string]struct{} // Set of MPT state trie nodes (account and storage together) + + chain HeaderReader // Chain reader to convert block hash ops to header proofs + lock sync.Mutex // Lock to allow concurrent state insertions +} + +// NewWitness creates an empty witness ready for population. +func NewWitness(chain HeaderReader, block *types.Block) (*Witness, error) { + // Zero out the result fields to avoid accidentally sending them to the verifier + header := block.Header() + header.Root = common.Hash{} + header.ReceiptHash = common.Hash{} + + // Retrieve the parent header, which will *always* be included to act as a + // trustless pre-root hash container + parent := chain.GetHeader(block.ParentHash(), block.NumberU64()-1) + if parent == nil { + return nil, errors.New("failed to retrieve parent header") + } + // Create the wtness with a reconstructed gutted out block + return &Witness{ + Block: types.NewBlockWithHeader(header).WithBody(*block.Body()), + Codes: make(map[string]struct{}), + State: make(map[string]struct{}), + Headers: []*types.Header{parent}, + chain: chain, + }, nil +} + +// AddBlockHash adds a "blockhash" to the witness with the designated offset from +// chain head. Under the hood, this method actually pulls in enough headers from +// the chain to cover the block being added. +func (w *Witness) AddBlockHash(number uint64) { + // Keep pulling in headers until this hash is populated + for int(w.Block.NumberU64()-number) > len(w.Headers) { + tail := w.Block.Header() + if len(w.Headers) > 0 { + tail = w.Headers[len(w.Headers)-1] + } + w.Headers = append(w.Headers, w.chain.GetHeader(tail.ParentHash, tail.Number.Uint64()-1)) + } +} + +// AddCode adds a bytecode blob to the witness. +func (w *Witness) AddCode(code []byte) { + if len(code) == 0 { + return + } + w.Codes[string(code)] = struct{}{} +} + +// AddState inserts a batch of MPT trie nodes into the witness. +func (w *Witness) AddState(nodes map[string]struct{}) { + if len(nodes) == 0 { + return + } + w.lock.Lock() + defer w.lock.Unlock() + + for node := range nodes { + w.State[node] = struct{}{} + } +} + +// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it +// is never mutated by Witness +func (w *Witness) Copy() *Witness { + return &Witness{ + Block: w.Block, + Headers: slices.Clone(w.Headers), + Codes: maps.Clone(w.Codes), + State: maps.Clone(w.State), + } +} + +// String prints a human-readable summary containing the total size of the +// witness and the sizes of the underlying components +func (w *Witness) String() string { + blob, _ := rlp.EncodeToBytes(w) + bytesTotal := len(blob) + + blob, _ = rlp.EncodeToBytes(w.Block) + bytesBlock := len(blob) + + bytesHeaders := 0 + for _, header := range w.Headers { + blob, _ = rlp.EncodeToBytes(header) + bytesHeaders += len(blob) + } + bytesCodes := 0 + for code := range w.Codes { + bytesCodes += len(code) + } + bytesState := 0 + for node := range w.State { + bytesState += len(node) + } + buf := new(bytes.Buffer) + + fmt.Fprintf(buf, "Witness #%d: %v\n", w.Block.Number(), common.StorageSize(bytesTotal)) + fmt.Fprintf(buf, " block (%4d txs): %10v\n", len(w.Block.Transactions()), common.StorageSize(bytesBlock)) + fmt.Fprintf(buf, "%4d headers: %10v\n", len(w.Headers), common.StorageSize(bytesHeaders)) + fmt.Fprintf(buf, "%4d trie nodes: %10v\n", len(w.State), common.StorageSize(bytesState)) + fmt.Fprintf(buf, "%4d codes: %10v\n", len(w.Codes), common.StorageSize(bytesCodes)) + + return buf.String() +} + +// Root returns the pre-state root from the first header. +// +// Note, this method will panic in case of a bad witness (but RLP decoding will +// sanitize it and fail before that). +func (w *Witness) Root() common.Hash { + return w.Headers[0].Root +} diff --git a/core/types.go b/core/types.go index 36eb0d1dedbe..dc13de52ce2b 100644 --- a/core/types.go +++ b/core/types.go @@ -19,7 +19,9 @@ package core import ( "sync/atomic" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" ) @@ -33,7 +35,10 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. - ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error + ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error + + // ValidateWitness cross validates a block execution with stateless remote clients. + ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error } // Prefetcher is an interface for pre-caching transaction signatures and state. diff --git a/core/vm/evm.go b/core/vm/evm.go index 26af0ea041b8..1944189b5da2 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -231,6 +231,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. code := evm.StateDB.GetCode(addr) + if witness := evm.StateDB.Witness(); witness != nil { + witness.AddCode(code) + } if len(code) == 0 { ret, err = nil, nil // gas is unchanged } else { @@ -298,6 +301,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(caller.Address()), value, gas) + if witness := evm.StateDB.Witness(); witness != nil { + witness.AddCode(evm.StateDB.GetCode(addrCopy)) + } contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas @@ -345,6 +351,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by addrCopy := addr // Initialise a new contract and make initialise the delegate values contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate() + if witness := evm.StateDB.Witness(); witness != nil { + witness.AddCode(evm.StateDB.GetCode(addrCopy)) + } contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas @@ -400,6 +409,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(addrCopy), new(uint256.Int), gas) + if witness := evm.StateDB.Witness(); witness != nil { + witness.AddCode(evm.StateDB.GetCode(addrCopy)) + } contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 10cdd72e0c57..9ec454464363 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -340,6 +340,10 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() + address := slot.Bytes20() + if witness := interpreter.evm.StateDB.Witness(); witness != nil { + witness.AddCode(interpreter.evm.StateDB.GetCode(address)) + } slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20()))) return nil, nil } @@ -378,7 +382,11 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) uint64CodeOffset = math.MaxUint64 } addr := common.Address(a.Bytes20()) - codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64()) + code := interpreter.evm.StateDB.GetCode(addr) + if witness := interpreter.evm.StateDB.Witness(); witness != nil { + witness.AddCode(code) + } + codeCopy := getData(code, uint64CodeOffset, length.Uint64()) scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) return nil, nil @@ -443,7 +451,11 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( lower = upper - 256 } if num64 >= lower && num64 < upper { - num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes()) + res := interpreter.evm.Context.GetHash(num64) + if witness := interpreter.evm.StateDB.Witness(); witness != nil { + witness.AddBlockHash(num64) + } + num.SetBytes(res[:]) } else { num.Clear() } diff --git a/core/vm/interface.go b/core/vm/interface.go index 8b2c58898ec6..5f426435650d 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" @@ -87,6 +88,8 @@ type StateDB interface { AddLog(*types.Log) AddPreimage(common.Hash, []byte) + + Witness() *stateless.Witness } // CallContext provides a basic interface for the EVM calling conventions. The EVM diff --git a/tests/block_test.go b/tests/block_test.go index 1ba84f5f24b6..52184eb27432 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -26,11 +26,11 @@ import ( func TestBlockchain(t *testing.T) { bt := new(testMatcher) - // General state tests are 'exported' as blockchain tests, but we can run them natively. - // For speedier CI-runs, the line below can be uncommented, so those are skipped. - // For now, in hardfork-times (Berlin), we run the tests both as StateTests and - // as blockchain tests, since the latter also covers things like receipt root - bt.skipLoad(`^GeneralStateTests/`) + + // We are running most of GeneralStatetests to tests witness support, even + // though they are ran as state tests too. Still, the performance tests are + // less about state andmore about EVM number crunching, so skip those. + bt.skipLoad(`^GeneralStateTests/VMTests/vmPerformance`) // Skip random failures due to selfish mining test bt.skipLoad(`.*bcForgedTest/bcForkUncle\.json`) @@ -70,33 +70,25 @@ func TestExecutionSpecBlocktests(t *testing.T) { } func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) { - // If -short flag is used, we don't execute all four permutations, only one. - executionMask := 0xf + // Define all the different flag combinations we should run the tests with, + // picking only one for short tests. + // + // Note, witness building and self-testing is always enabled as it's a very + // good test to ensure that we don't break it. + var ( + snapshotConf = []bool{false, true} + dbschemeConf = []string{rawdb.HashScheme, rawdb.PathScheme} + ) if testing.Short() { - executionMask = (1 << (rand.Int63() & 4)) - } - if executionMask&0x1 != 0 { - if err := bt.checkFailure(t, test.Run(false, rawdb.HashScheme, nil, nil)); err != nil { - t.Errorf("test in hash mode without snapshotter failed: %v", err) - return - } - } - if executionMask&0x2 != 0 { - if err := bt.checkFailure(t, test.Run(true, rawdb.HashScheme, nil, nil)); err != nil { - t.Errorf("test in hash mode with snapshotter failed: %v", err) - return - } - } - if executionMask&0x4 != 0 { - if err := bt.checkFailure(t, test.Run(false, rawdb.PathScheme, nil, nil)); err != nil { - t.Errorf("test in path mode without snapshotter failed: %v", err) - return - } + snapshotConf = []bool{snapshotConf[rand.Int()%2]} + dbschemeConf = []string{dbschemeConf[rand.Int()%2]} } - if executionMask&0x8 != 0 { - if err := bt.checkFailure(t, test.Run(true, rawdb.PathScheme, nil, nil)); err != nil { - t.Errorf("test in path mode with snapshotter failed: %v", err) - return + for _, snapshot := range snapshotConf { + for _, dbscheme := range dbschemeConf { + if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, true, nil, nil)); err != nil { + t.Errorf("test with config {snapshotter:%v, scheme:%v} failed: %v", snapshot, dbscheme, err) + return + } } } } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 04a04fdc288c..62aa582c828e 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -110,7 +110,7 @@ type btHeaderMarshaling struct { ExcessBlobGas *math.HexOrDecimal64 } -func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { +func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { config, ok := Forks[t.json.Network] if !ok { return UnsupportedForkError{t.json.Network} @@ -151,7 +151,8 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.Hooks, cache.SnapshotWait = true } chain, err := core.NewBlockChain(db, cache, gspec, nil, engine, vm.Config{ - Tracer: tracer, + Tracer: tracer, + EnableWitnessCollection: witness, }, nil, nil) if err != nil { return err diff --git a/trie/secure_trie.go b/trie/secure_trie.go index cfa7f0bddb0b..3572117e034d 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -214,6 +214,11 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { return t.db.Preimage(common.BytesToHash(shaKey)) } +// Witness returns a set containing all trie nodes that have been accessed. +func (t *StateTrie) Witness() map[string]struct{} { + return t.trie.Witness() +} + // Commit collects all dirty nodes in the trie and replaces them with the // corresponding node hash. All collected nodes (including dirty leaves if // collectLeaf is true) will be encapsulated into a nodeset for return. diff --git a/trie/trie.go b/trie/trie.go index e1a92011084d..f44e10b918d4 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -661,6 +661,18 @@ func (t *Trie) hashRoot() (node, node) { return hashed, cached } +// Witness returns a set containing all trie nodes that have been accessed. +func (t *Trie) Witness() map[string]struct{} { + if len(t.tracer.accessList) == 0 { + return nil + } + witness := make(map[string]struct{}) + for _, node := range t.tracer.accessList { + witness[string(node)] = struct{}{} + } + return witness +} + // Reset drops the referenced root node and cleans all internal state. func (t *Trie) Reset() { t.root = nil diff --git a/trie/verkle.go b/trie/verkle.go index 1ea23186f92b..94a5ca9a2c5f 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -369,3 +369,8 @@ func (t *VerkleTrie) ToDot() string { func (t *VerkleTrie) nodeResolver(path []byte) ([]byte, error) { return t.reader.node(path, common.Hash{}) } + +// Witness returns a set containing all trie nodes that have been accessed. +func (t *VerkleTrie) Witness() map[string]struct{} { + panic("not implemented") +} From 98b5930d2d780fe13895633ffcc6b84c9beb4450 Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 25 Jun 2024 20:19:04 +0800 Subject: [PATCH 382/571] core/txpool/blobpool: avoid use *map as parameter. (#30048) --- core/txpool/blobpool/blobpool.go | 2 +- core/txpool/blobpool/evictheap.go | 12 ++++++------ core/txpool/blobpool/evictheap_test.go | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 69423731ee19..2fca5c7b3edf 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -407,7 +407,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres if p.head.ExcessBlobGas != nil { blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*p.head.ExcessBlobGas)) } - p.evict = newPriceHeap(basefee, blobfee, &p.index) + p.evict = newPriceHeap(basefee, blobfee, p.index) // Pool initialized, attach the blob limbo to it to track blobs included // recently but not yet finalized diff --git a/core/txpool/blobpool/evictheap.go b/core/txpool/blobpool/evictheap.go index bc4543a352e2..701eb405cfc0 100644 --- a/core/txpool/blobpool/evictheap.go +++ b/core/txpool/blobpool/evictheap.go @@ -35,7 +35,7 @@ import ( // The goal of the heap is to decide which account has the worst bottleneck to // evict transactions from. type evictHeap struct { - metas *map[common.Address][]*blobTxMeta // Pointer to the blob pool's index for price retrievals + metas map[common.Address][]*blobTxMeta // Pointer to the blob pool's index for price retrievals basefeeJumps float64 // Pre-calculated absolute dynamic fee jumps for the base fee blobfeeJumps float64 // Pre-calculated absolute dynamic fee jumps for the blob fee @@ -46,7 +46,7 @@ type evictHeap struct { // newPriceHeap creates a new heap of cheapest accounts in the blob pool to evict // from in case of over saturation. -func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index *map[common.Address][]*blobTxMeta) *evictHeap { +func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index map[common.Address][]*blobTxMeta) *evictHeap { heap := &evictHeap{ metas: index, index: make(map[common.Address]int), @@ -54,8 +54,8 @@ func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index *map[common. // Populate the heap in account sort order. Not really needed in practice, // but it makes the heap initialization deterministic and less annoying to // test in unit tests. - addrs := make([]common.Address, 0, len(*index)) - for addr := range *index { + addrs := make([]common.Address, 0, len(index)) + for addr := range index { addrs = append(addrs, addr) } sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i][:], addrs[j][:]) < 0 }) @@ -94,8 +94,8 @@ func (h *evictHeap) Len() int { // Less implements sort.Interface as part of heap.Interface, returning which of // the two requested accounts has a cheaper bottleneck. func (h *evictHeap) Less(i, j int) bool { - txsI := (*(h.metas))[h.addrs[i]] - txsJ := (*(h.metas))[h.addrs[j]] + txsI := h.metas[h.addrs[i]] + txsJ := h.metas[h.addrs[j]] lastI := txsI[len(txsI)-1] lastJ := txsJ[len(txsJ)-1] diff --git a/core/txpool/blobpool/evictheap_test.go b/core/txpool/blobpool/evictheap_test.go index 01b136551cf2..1cf577cb0000 100644 --- a/core/txpool/blobpool/evictheap_test.go +++ b/core/txpool/blobpool/evictheap_test.go @@ -37,17 +37,17 @@ func verifyHeapInternals(t *testing.T, evict *evictHeap) { seen := make(map[common.Address]struct{}) for i, addr := range evict.addrs { seen[addr] = struct{}{} - if _, ok := (*evict.metas)[addr]; !ok { + if _, ok := evict.metas[addr]; !ok { t.Errorf("heap contains unexpected address at slot %d: %v", i, addr) } } - for addr := range *evict.metas { + for addr := range evict.metas { if _, ok := seen[addr]; !ok { t.Errorf("heap is missing required address %v", addr) } } - if len(evict.addrs) != len(*evict.metas) { - t.Errorf("heap size %d mismatches metadata size %d", len(evict.addrs), len(*evict.metas)) + if len(evict.addrs) != len(evict.metas) { + t.Errorf("heap size %d mismatches metadata size %d", len(evict.addrs), len(evict.metas)) } // Ensure that all accounts are present in the heap order index and no extras have := make([]common.Address, len(evict.index)) @@ -159,7 +159,7 @@ func TestPriceHeapSorting(t *testing.T) { }} } // Create a price heap and check the pop order - priceheap := newPriceHeap(uint256.NewInt(tt.basefee), uint256.NewInt(tt.blobfee), &index) + priceheap := newPriceHeap(uint256.NewInt(tt.basefee), uint256.NewInt(tt.blobfee), index) verifyHeapInternals(t, priceheap) for j := 0; j < len(tt.order); j++ { @@ -218,7 +218,7 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) { }} } // Create a price heap and reinit it over and over - heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), &index) + heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index) basefees := make([]*uint256.Int, b.N) blobfees := make([]*uint256.Int, b.N) @@ -278,7 +278,7 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) { }} } // Create a price heap and overflow it over and over - evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), &index) + evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index) var ( addrs = make([]common.Address, b.N) metas = make([]*blobTxMeta, b.N) From 9298d2db884c4e3f9474880e3dcfd080ef9eacfa Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 25 Jun 2024 21:45:33 +0800 Subject: [PATCH 383/571] trie/trienode: remove unnecessary check in Summary (#30047) --- trie/trienode/node.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/trie/trienode/node.go b/trie/trienode/node.go index fa7bebe4f98f..09f355f3b590 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -139,16 +139,14 @@ func (set *NodeSet) Size() (int, int) { func (set *NodeSet) Summary() string { var out = new(strings.Builder) fmt.Fprintf(out, "nodeset owner: %v\n", set.Owner) - if set.Nodes != nil { - for path, n := range set.Nodes { - // Deletion - if n.IsDeleted() { - fmt.Fprintf(out, " [-]: %x\n", path) - continue - } - // Insertion or update - fmt.Fprintf(out, " [+/*]: %x -> %v \n", path, n.Hash) + for path, n := range set.Nodes { + // Deletion + if n.IsDeleted() { + fmt.Fprintf(out, " [-]: %x\n", path) + continue } + // Insertion or update + fmt.Fprintf(out, " [+/*]: %x -> %v \n", path, n.Hash) } for _, n := range set.Leaves { fmt.Fprintf(out, "[leaf]: %v\n", n) From 269e80b07ed8b8300372c44ebb5d7ac2328bf84c Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Thu, 27 Jun 2024 17:29:50 +0800 Subject: [PATCH 384/571] eth/tracers,trie: remove unnecessary check (#30071) --- eth/tracers/live/supply.go | 10 ++++------ eth/tracers/native/call_flat.go | 16 +++++++--------- trie/verkle.go | 6 ++---- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go index 936ffb94724c..96f70594548c 100644 --- a/eth/tracers/live/supply.go +++ b/eth/tracers/live/supply.go @@ -204,12 +204,10 @@ func (s *supply) internalTxsHandler(call *supplyTxCallstack) { s.delta.Burn.Misc.Add(s.delta.Burn.Misc, call.burn) } - if len(call.calls) > 0 { - // Recursively handle internal calls - for _, call := range call.calls { - callCopy := call - s.internalTxsHandler(&callCopy) - } + // Recursively handle internal calls + for _, call := range call.calls { + callCopy := call + s.internalTxsHandler(&callCopy) } } diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index ce0fb081143e..a47b79f8df26 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -274,16 +274,14 @@ func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx } output = append(output, *frame) - if len(input.Calls) > 0 { - for i, childCall := range input.Calls { - childAddr := childTraceAddress(traceAddress, i) - childCallCopy := childCall - flat, err := flatFromNested(&childCallCopy, childAddr, convertErrs, ctx) - if err != nil { - return nil, err - } - output = append(output, flat...) + for i, childCall := range input.Calls { + childAddr := childTraceAddress(traceAddress, i) + childCallCopy := childCall + flat, err := flatFromNested(&childCallCopy, childAddr, convertErrs, ctx) + if err != nil { + return nil, err } + output = append(output, flat...) } return output, nil diff --git a/trie/verkle.go b/trie/verkle.go index 94a5ca9a2c5f..a457097e9585 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -144,10 +144,8 @@ func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount) // Encode balance in little-endian bytes := acc.Balance.Bytes() - if len(bytes) > 0 { - for i, b := range bytes { - balance[len(bytes)-i-1] = b - } + for i, b := range bytes { + balance[len(bytes)-i-1] = b } values[utils.BalanceLeafKey] = balance[:] From 045b9718d512d24af71331cbe4d8e3e1a7afba12 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 27 Jun 2024 20:30:39 +0800 Subject: [PATCH 385/571] trie: relocate state execution logic into pathdb package (#29861) --- trie/secure_trie.go | 29 ++++- trie/trie_reader.go | 21 ---- trie/triestate/state.go | 212 +-------------------------------- triedb/database.go | 9 +- triedb/database/database.go | 16 +-- triedb/pathdb/database.go | 4 +- triedb/pathdb/database_test.go | 64 ++++++---- triedb/pathdb/disklayer.go | 4 +- triedb/pathdb/execute.go | 186 +++++++++++++++++++++++++++++ triedb/pathdb/testutils.go | 159 ------------------------- 10 files changed, 259 insertions(+), 445 deletions(-) create mode 100644 triedb/pathdb/execute.go delete mode 100644 triedb/pathdb/testutils.go diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 3572117e034d..6eb6defa45eb 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -24,6 +24,16 @@ import ( "github.com/ethereum/go-ethereum/triedb/database" ) +// preimageStore wraps the methods of a backing store for reading and writing +// trie node preimages. +type preimageStore interface { + // Preimage retrieves the preimage of the specified hash. + Preimage(hash common.Hash) []byte + + // InsertPreimage commits a set of preimages along with their hashes. + InsertPreimage(preimages map[common.Hash][]byte) +} + // SecureTrie is the old name of StateTrie. // Deprecated: use StateTrie. type SecureTrie = StateTrie @@ -52,6 +62,7 @@ func NewSecure(stateRoot common.Hash, owner common.Hash, root common.Hash, db da type StateTrie struct { trie Trie db database.Database + preimages preimageStore hashKeyBuf [common.HashLength]byte secKeyCache map[string][]byte secKeyCacheOwner *StateTrie // Pointer to self, replace the key cache on mismatch @@ -70,7 +81,14 @@ func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) { if err != nil { return nil, err } - return &StateTrie{trie: *trie, db: db}, nil + tr := &StateTrie{trie: *trie, db: db} + + // link the preimage store if it's supported + preimages, ok := db.(preimageStore) + if ok { + tr.preimages = preimages + } + return tr, nil } // MustGet returns the value for key stored in the trie. @@ -211,7 +229,10 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { return key } - return t.db.Preimage(common.BytesToHash(shaKey)) + if t.preimages == nil { + return nil + } + return t.preimages.Preimage(common.BytesToHash(shaKey)) } // Witness returns a set containing all trie nodes that have been accessed. @@ -233,7 +254,9 @@ func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { for hk, key := range t.secKeyCache { preimages[common.BytesToHash([]byte(hk))] = key } - t.db.InsertPreimage(preimages) + if t.preimages != nil { + t.preimages.InsertPreimage(preimages) + } t.secKeyCache = make(map[string][]byte) } // Commit the trie and return its modified nodeset. diff --git a/trie/trie_reader.go b/trie/trie_reader.go index 42bc4316fe63..adbf43d287ca 100644 --- a/trie/trie_reader.go +++ b/trie/trie_reader.go @@ -20,7 +20,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/triedb/database" ) @@ -72,23 +71,3 @@ func (r *trieReader) node(path []byte, hash common.Hash) ([]byte, error) { } return blob, nil } - -// MerkleLoader implements triestate.TrieLoader for constructing tries. -type MerkleLoader struct { - db database.Database -} - -// NewMerkleLoader creates the merkle trie loader. -func NewMerkleLoader(db database.Database) *MerkleLoader { - return &MerkleLoader{db: db} -} - -// OpenTrie opens the main account trie. -func (l *MerkleLoader) OpenTrie(root common.Hash) (triestate.Trie, error) { - return New(TrieID(root), l.db) -} - -// OpenStorageTrie opens the storage trie of an account. -func (l *MerkleLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) { - return New(StorageTrieID(stateRoot, addrHash, root), l.db) -} diff --git a/trie/triestate/state.go b/trie/triestate/state.go index 7508da5d60cd..62a904387353 100644 --- a/trie/triestate/state.go +++ b/trie/triestate/state.go @@ -16,43 +16,7 @@ package triestate -import ( - "errors" - "fmt" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie/trienode" -) - -// Trie is an Ethereum state trie, can be implemented by Ethereum Merkle Patricia -// tree or Verkle tree. -type Trie interface { - // Get returns the value for key stored in the trie. - Get(key []byte) ([]byte, error) - - // Update associates key with value in the trie. - Update(key, value []byte) error - - // Delete removes any existing value for key from the trie. - Delete(key []byte) error - - // Commit the trie and returns a set of dirty nodes generated along with - // the new root hash. - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) -} - -// TrieLoader wraps functions to load tries. -type TrieLoader interface { - // OpenTrie opens the main account trie. - OpenTrie(root common.Hash) (Trie, error) - - // OpenStorageTrie opens the storage trie of an account. - OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) -} +import "github.com/ethereum/go-ethereum/common" // Set represents a collection of mutated states during a state transition. // The value refers to the original content of state before the transition @@ -87,177 +51,3 @@ func (s *Set) Size() common.StorageSize { } return s.size } - -// context wraps all fields for executing state diffs. -type context struct { - prevRoot common.Hash - postRoot common.Hash - accounts map[common.Address][]byte - storages map[common.Address]map[common.Hash][]byte - accountTrie Trie - nodes *trienode.MergedNodeSet -} - -// Apply traverses the provided state diffs, apply them in the associated -// post-state and return the generated dirty trie nodes. The state can be -// loaded via the provided trie loader. -func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, loader TrieLoader) (map[common.Hash]map[string]*trienode.Node, error) { - tr, err := loader.OpenTrie(postRoot) - if err != nil { - return nil, err - } - ctx := &context{ - prevRoot: prevRoot, - postRoot: postRoot, - accounts: accounts, - storages: storages, - accountTrie: tr, - nodes: trienode.NewMergedNodeSet(), - } - for addr, account := range accounts { - var err error - if len(account) == 0 { - err = deleteAccount(ctx, loader, addr) - } else { - err = updateAccount(ctx, loader, addr) - } - if err != nil { - return nil, fmt.Errorf("failed to revert state, err: %w", err) - } - } - root, result := tr.Commit(false) - if root != prevRoot { - return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) - } - if err := ctx.nodes.Merge(result); err != nil { - return nil, err - } - return ctx.nodes.Flatten(), nil -} - -// updateAccount the account was present in prev-state, and may or may not -// existent in post-state. Apply the reverse diff and verify if the storage -// root matches the one in prev-state account. -func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error { - // The account was present in prev-state, decode it from the - // 'slim-rlp' format bytes. - h := newHasher() - defer h.release() - - addrHash := h.hash(addr.Bytes()) - prev, err := types.FullAccount(ctx.accounts[addr]) - if err != nil { - return err - } - // The account may or may not existent in post-state, try to - // load it and decode if it's found. - blob, err := ctx.accountTrie.Get(addrHash.Bytes()) - if err != nil { - return err - } - post := types.NewEmptyStateAccount() - if len(blob) != 0 { - if err := rlp.DecodeBytes(blob, &post); err != nil { - return err - } - } - // Apply all storage changes into the post-state storage trie. - st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) - if err != nil { - return err - } - for key, val := range ctx.storages[addr] { - var err error - if len(val) == 0 { - err = st.Delete(key.Bytes()) - } else { - err = st.Update(key.Bytes(), val) - } - if err != nil { - return err - } - } - root, result := st.Commit(false) - if root != prev.Root { - return errors.New("failed to reset storage trie") - } - // The returned set can be nil if storage trie is not changed - // at all. - if result != nil { - if err := ctx.nodes.Merge(result); err != nil { - return err - } - } - // Write the prev-state account into the main trie - full, err := rlp.EncodeToBytes(prev) - if err != nil { - return err - } - return ctx.accountTrie.Update(addrHash.Bytes(), full) -} - -// deleteAccount the account was not present in prev-state, and is expected -// to be existent in post-state. Apply the reverse diff and verify if the -// account and storage is wiped out correctly. -func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error { - // The account must be existent in post-state, load the account. - h := newHasher() - defer h.release() - - addrHash := h.hash(addr.Bytes()) - blob, err := ctx.accountTrie.Get(addrHash.Bytes()) - if err != nil { - return err - } - if len(blob) == 0 { - return fmt.Errorf("account is non-existent %#x", addrHash) - } - var post types.StateAccount - if err := rlp.DecodeBytes(blob, &post); err != nil { - return err - } - st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) - if err != nil { - return err - } - for key, val := range ctx.storages[addr] { - if len(val) != 0 { - return errors.New("expect storage deletion") - } - if err := st.Delete(key.Bytes()); err != nil { - return err - } - } - root, result := st.Commit(false) - if root != types.EmptyRootHash { - return errors.New("failed to clear storage trie") - } - // The returned set can be nil if storage trie is not changed - // at all. - if result != nil { - if err := ctx.nodes.Merge(result); err != nil { - return err - } - } - // Delete the post-state account from the main trie. - return ctx.accountTrie.Delete(addrHash.Bytes()) -} - -// hasher is used to compute the sha256 hash of the provided data. -type hasher struct{ sha crypto.KeccakState } - -var hasherPool = sync.Pool{ - New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} }, -} - -func newHasher() *hasher { - return hasherPool.Get().(*hasher) -} - -func (h *hasher) hash(data []byte) common.Hash { - return crypto.HashData(h.sha, data) -} - -func (h *hasher) release() { - hasherPool.Put(h) -} diff --git a/triedb/database.go b/triedb/database.go index ef757e7f5bc3..91386a9dbcf5 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -264,14 +264,7 @@ func (db *Database) Recover(target common.Hash) error { if !ok { return errors.New("not supported") } - var loader triestate.TrieLoader - if db.config.IsVerkle { - // TODO define verkle loader - log.Crit("Verkle loader is not defined") - } else { - loader = trie.NewMerkleLoader(db) - } - return pdb.Recover(target, loader) + return pdb.Recover(target) } // Recoverable returns the indicator if the specified state is enabled to be diff --git a/triedb/database/database.go b/triedb/database/database.go index f11c7e9bbd3e..9bd5da08d109 100644 --- a/triedb/database/database.go +++ b/triedb/database/database.go @@ -16,9 +16,7 @@ package database -import ( - "github.com/ethereum/go-ethereum/common" -) +import "github.com/ethereum/go-ethereum/common" // Reader wraps the Node method of a backing trie reader. type Reader interface { @@ -31,20 +29,8 @@ type Reader interface { Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) } -// PreimageStore wraps the methods of a backing store for reading and writing -// trie node preimages. -type PreimageStore interface { - // Preimage retrieves the preimage of the specified hash. - Preimage(hash common.Hash) []byte - - // InsertPreimage commits a set of preimages along with their hashes. - InsertPreimage(preimages map[common.Hash][]byte) -} - // Database wraps the methods of a backing trie store. type Database interface { - PreimageStore - // Reader returns a node reader associated with the specific state. // An error will be returned if the specified state is not available. Reader(stateRoot common.Hash) (Reader, error) diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index bd6aeaa6abe4..450c3a8f4f38 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -345,7 +345,7 @@ func (db *Database) Enable(root common.Hash) error { // Recover rollbacks the database to a specified historical point. // The state is supported as the rollback destination only if it's // canonical state and the corresponding trie histories are existent. -func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error { +func (db *Database) Recover(root common.Hash) error { db.lock.Lock() defer db.lock.Unlock() @@ -371,7 +371,7 @@ func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error if err != nil { return err } - dl, err = dl.revert(h, loader) + dl, err = dl.revert(h) if err != nil { return err } diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 04c8af415f6f..8870bfe95b21 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -29,24 +29,31 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" "github.com/holiman/uint256" ) -func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[common.Hash][]byte) (common.Hash, *trienode.NodeSet) { - h, err := newTestHasher(addrHash, root, cleans) +func updateTrie(db *Database, stateRoot common.Hash, addrHash common.Hash, root common.Hash, dirties map[common.Hash][]byte) (common.Hash, *trienode.NodeSet) { + var id *trie.ID + if addrHash == (common.Hash{}) { + id = trie.StateTrieID(stateRoot) + } else { + id = trie.StorageTrieID(stateRoot, addrHash, root) + } + tr, err := trie.New(id, db) if err != nil { - panic(fmt.Errorf("failed to create hasher, err: %w", err)) + panic(fmt.Errorf("failed to load trie, err: %w", err)) } for key, val := range dirties { if len(val) == 0 { - h.Delete(key.Bytes()) + tr.Delete(key.Bytes()) } else { - h.Update(key.Bytes(), val) + tr.Update(key.Bytes(), val) } } - return h.Commit(false) + return tr.Commit(false) } func generateAccount(storageRoot common.Hash) types.StateAccount { @@ -66,6 +73,7 @@ const ( ) type genctx struct { + stateRoot common.Hash accounts map[common.Hash][]byte storages map[common.Hash]map[common.Hash][]byte accountOrigin map[common.Address][]byte @@ -73,8 +81,9 @@ type genctx struct { nodes *trienode.MergedNodeSet } -func newCtx() *genctx { +func newCtx(stateRoot common.Hash) *genctx { return &genctx{ + stateRoot: stateRoot, accounts: make(map[common.Hash][]byte), storages: make(map[common.Hash]map[common.Hash][]byte), accountOrigin: make(map[common.Address][]byte), @@ -151,7 +160,7 @@ func (t *tester) generateStorage(ctx *genctx, addr common.Address) common.Hash { storage[hash] = v origin[hash] = nil } - root, set := updateTrie(addrHash, types.EmptyRootHash, storage, nil) + root, set := updateTrie(t.db, ctx.stateRoot, addrHash, types.EmptyRootHash, storage) ctx.storages[addrHash] = storage ctx.storageOrigin[addr] = origin @@ -180,7 +189,7 @@ func (t *tester) mutateStorage(ctx *genctx, addr common.Address, root common.Has storage[hash] = v origin[hash] = nil } - root, set := updateTrie(crypto.Keccak256Hash(addr.Bytes()), root, storage, t.storages[addrHash]) + root, set := updateTrie(t.db, ctx.stateRoot, crypto.Keccak256Hash(addr.Bytes()), root, storage) ctx.storages[addrHash] = storage ctx.storageOrigin[addr] = origin @@ -198,7 +207,7 @@ func (t *tester) clearStorage(ctx *genctx, addr common.Address, root common.Hash origin[hash] = val storage[hash] = nil } - root, set := updateTrie(addrHash, root, storage, t.storages[addrHash]) + root, set := updateTrie(t.db, ctx.stateRoot, addrHash, root, storage) if root != types.EmptyRootHash { panic("failed to clear storage trie") } @@ -210,7 +219,7 @@ func (t *tester) clearStorage(ctx *genctx, addr common.Address, root common.Hash func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNodeSet, *triestate.Set) { var ( - ctx = newCtx() + ctx = newCtx(parent) dirties = make(map[common.Hash]struct{}) ) for i := 0; i < 20; i++ { @@ -271,7 +280,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode ctx.accountOrigin[addr] = account } } - root, set := updateTrie(common.Hash{}, parent, ctx.accounts, t.accounts) + root, set := updateTrie(t.db, parent, common.Hash{}, parent, ctx.accounts) ctx.nodes.Merge(set) // Save state snapshot before commit @@ -297,6 +306,9 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode t.storages[addrHash][sHash] = slot } } + if len(t.storages[addrHash]) == 0 { + delete(t.storages, addrHash) + } } return root, ctx.nodes, triestate.New(ctx.accountOrigin, ctx.storageOrigin) } @@ -310,25 +322,31 @@ func (t *tester) lastHash() common.Hash { } func (t *tester) verifyState(root common.Hash) error { - reader, err := t.db.Reader(root) + tr, err := trie.New(trie.StateTrieID(root), t.db) if err != nil { return err } - _, err = reader.Node(common.Hash{}, nil, root) - if err != nil { - return errors.New("root node is not available") - } for addrHash, account := range t.snapAccounts[root] { - path := crypto.Keccak256(addrHash.Bytes()) - blob, err := reader.Node(common.Hash{}, path, crypto.Keccak256Hash(account)) + blob, err := tr.Get(addrHash.Bytes()) if err != nil || !bytes.Equal(blob, account) { return fmt.Errorf("account is mismatched: %w", err) } } for addrHash, slots := range t.snapStorages[root] { + blob := t.snapAccounts[root][addrHash] + if len(blob) == 0 { + return fmt.Errorf("account %x is missing", addrHash) + } + account := new(types.StateAccount) + if err := rlp.DecodeBytes(blob, account); err != nil { + return err + } + storageIt, err := trie.New(trie.StorageTrieID(root, addrHash, account.Root), t.db) + if err != nil { + return err + } for hash, slot := range slots { - path := crypto.Keccak256(hash.Bytes()) - blob, err := reader.Node(addrHash, path, crypto.Keccak256Hash(slot)) + blob, err := storageIt.Get(hash.Bytes()) if err != nil || !bytes.Equal(blob, slot) { return fmt.Errorf("slot is mismatched: %w", err) } @@ -395,13 +413,11 @@ func TestDatabaseRollback(t *testing.T) { } // Revert database from top to bottom for i := tester.bottomIndex(); i >= 0; i-- { - root := tester.roots[i] parent := types.EmptyRootHash if i > 0 { parent = tester.roots[i-1] } - loader := newHashLoader(tester.snapAccounts[root], tester.snapStorages[root]) - if err := tester.db.Recover(parent, loader); err != nil { + if err := tester.db.Recover(parent); err != nil { t.Fatalf("Failed to revert db, err: %v", err) } if i > 0 { diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index 964ad2ef777d..e538a7928055 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -219,7 +219,7 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { } // revert applies the given state history and return a reverted disk layer. -func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) (*diskLayer, error) { +func (dl *diskLayer) revert(h *history) (*diskLayer, error) { if h.meta.root != dl.rootHash() { return nil, errUnexpectedHistory } @@ -229,7 +229,7 @@ func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) (*diskLayer // Apply the reverse state changes upon the current state. This must // be done before holding the lock in order to access state in "this" // layer. - nodes, err := triestate.Apply(h.meta.parent, h.meta.root, h.accounts, h.storages, loader) + nodes, err := apply(dl.db, h.meta.parent, h.meta.root, h.accounts, h.storages) if err != nil { return nil, err } diff --git a/triedb/pathdb/execute.go b/triedb/pathdb/execute.go new file mode 100644 index 000000000000..9074e4debf26 --- /dev/null +++ b/triedb/pathdb/execute.go @@ -0,0 +1,186 @@ +// Copyright 2024 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 pathdb + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" + "github.com/ethereum/go-ethereum/triedb/database" +) + +// context wraps all fields for executing state diffs. +type context struct { + prevRoot common.Hash + postRoot common.Hash + accounts map[common.Address][]byte + storages map[common.Address]map[common.Hash][]byte + nodes *trienode.MergedNodeSet + + // TODO (rjl493456442) abstract out the state hasher + // for supporting verkle tree. + accountTrie *trie.Trie +} + +// apply processes the given state diffs, updates the corresponding post-state +// and returns the trie nodes that have been modified. +func apply(db database.Database, prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) (map[common.Hash]map[string]*trienode.Node, error) { + tr, err := trie.New(trie.TrieID(postRoot), db) + if err != nil { + return nil, err + } + ctx := &context{ + prevRoot: prevRoot, + postRoot: postRoot, + accounts: accounts, + storages: storages, + accountTrie: tr, + nodes: trienode.NewMergedNodeSet(), + } + for addr, account := range accounts { + var err error + if len(account) == 0 { + err = deleteAccount(ctx, db, addr) + } else { + err = updateAccount(ctx, db, addr) + } + if err != nil { + return nil, fmt.Errorf("failed to revert state, err: %w", err) + } + } + root, result := tr.Commit(false) + if root != prevRoot { + return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) + } + if err := ctx.nodes.Merge(result); err != nil { + return nil, err + } + return ctx.nodes.Flatten(), nil +} + +// updateAccount the account was present in prev-state, and may or may not +// existent in post-state. Apply the reverse diff and verify if the storage +// root matches the one in prev-state account. +func updateAccount(ctx *context, db database.Database, addr common.Address) error { + // The account was present in prev-state, decode it from the + // 'slim-rlp' format bytes. + h := newHasher() + defer h.release() + + addrHash := h.hash(addr.Bytes()) + prev, err := types.FullAccount(ctx.accounts[addr]) + if err != nil { + return err + } + // The account may or may not existent in post-state, try to + // load it and decode if it's found. + blob, err := ctx.accountTrie.Get(addrHash.Bytes()) + if err != nil { + return err + } + post := types.NewEmptyStateAccount() + if len(blob) != 0 { + if err := rlp.DecodeBytes(blob, &post); err != nil { + return err + } + } + // Apply all storage changes into the post-state storage trie. + st, err := trie.New(trie.StorageTrieID(ctx.postRoot, addrHash, post.Root), db) + if err != nil { + return err + } + for key, val := range ctx.storages[addr] { + var err error + if len(val) == 0 { + err = st.Delete(key.Bytes()) + } else { + err = st.Update(key.Bytes(), val) + } + if err != nil { + return err + } + } + root, result := st.Commit(false) + if root != prev.Root { + return errors.New("failed to reset storage trie") + } + // The returned set can be nil if storage trie is not changed + // at all. + if result != nil { + if err := ctx.nodes.Merge(result); err != nil { + return err + } + } + // Write the prev-state account into the main trie + full, err := rlp.EncodeToBytes(prev) + if err != nil { + return err + } + return ctx.accountTrie.Update(addrHash.Bytes(), full) +} + +// deleteAccount the account was not present in prev-state, and is expected +// to be existent in post-state. Apply the reverse diff and verify if the +// account and storage is wiped out correctly. +func deleteAccount(ctx *context, db database.Database, addr common.Address) error { + // The account must be existent in post-state, load the account. + h := newHasher() + defer h.release() + + addrHash := h.hash(addr.Bytes()) + blob, err := ctx.accountTrie.Get(addrHash.Bytes()) + if err != nil { + return err + } + if len(blob) == 0 { + return fmt.Errorf("account is non-existent %#x", addrHash) + } + var post types.StateAccount + if err := rlp.DecodeBytes(blob, &post); err != nil { + return err + } + st, err := trie.New(trie.StorageTrieID(ctx.postRoot, addrHash, post.Root), db) + if err != nil { + return err + } + for key, val := range ctx.storages[addr] { + if len(val) != 0 { + return errors.New("expect storage deletion") + } + if err := st.Delete(key.Bytes()); err != nil { + return err + } + } + root, result := st.Commit(false) + if root != types.EmptyRootHash { + return errors.New("failed to clear storage trie") + } + // The returned set can be nil if storage trie is not changed + // at all. + if result != nil { + if err := ctx.nodes.Merge(result); err != nil { + return err + } + } + // Delete the post-state account from the main trie. + return ctx.accountTrie.Delete(addrHash.Bytes()) +} diff --git a/triedb/pathdb/testutils.go b/triedb/pathdb/testutils.go deleted file mode 100644 index af832bc59c44..000000000000 --- a/triedb/pathdb/testutils.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2023 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 pathdb - -import ( - "bytes" - "fmt" - "slices" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/trie/trienode" - "github.com/ethereum/go-ethereum/trie/triestate" -) - -// testHasher is a test utility for computing root hash of a batch of state -// elements. The hash algorithm is to sort all the elements in lexicographical -// order, concat the key and value in turn, and perform hash calculation on -// the concatenated bytes. Except the root hash, a nodeset will be returned -// once Commit is called, which contains all the changes made to hasher. -type testHasher struct { - owner common.Hash // owner identifier - root common.Hash // original root - dirties map[common.Hash][]byte // dirty states - cleans map[common.Hash][]byte // clean states -} - -// newTestHasher constructs a hasher object with provided states. -func newTestHasher(owner common.Hash, root common.Hash, cleans map[common.Hash][]byte) (*testHasher, error) { - if cleans == nil { - cleans = make(map[common.Hash][]byte) - } - if got, _ := hash(cleans); got != root { - return nil, fmt.Errorf("state root mismatched, want: %x, got: %x", root, got) - } - return &testHasher{ - owner: owner, - root: root, - dirties: make(map[common.Hash][]byte), - cleans: cleans, - }, nil -} - -// Get returns the value for key stored in the trie. -func (h *testHasher) Get(key []byte) ([]byte, error) { - hash := common.BytesToHash(key) - val, ok := h.dirties[hash] - if ok { - return val, nil - } - return h.cleans[hash], nil -} - -// Update associates key with value in the trie. -func (h *testHasher) Update(key, value []byte) error { - h.dirties[common.BytesToHash(key)] = common.CopyBytes(value) - return nil -} - -// Delete removes any existing value for key from the trie. -func (h *testHasher) Delete(key []byte) error { - h.dirties[common.BytesToHash(key)] = nil - return nil -} - -// Commit computes the new hash of the states and returns the set with all -// state changes. -func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { - var ( - nodes = make(map[common.Hash][]byte) - set = trienode.NewNodeSet(h.owner) - ) - for hash, val := range h.cleans { - nodes[hash] = val - } - for hash, val := range h.dirties { - nodes[hash] = val - if bytes.Equal(val, h.cleans[hash]) { - continue - } - // Utilize the hash of the state key as the node path to mitigate - // potential collisions within the path. - path := crypto.Keccak256(hash.Bytes()) - if len(val) == 0 { - set.AddNode(path, trienode.NewDeleted()) - } else { - set.AddNode(path, trienode.New(crypto.Keccak256Hash(val), val)) - } - } - root, blob := hash(nodes) - - // Include the dirty root node as well. - if root != types.EmptyRootHash && root != h.root { - set.AddNode(nil, trienode.New(root, blob)) - } - if root == types.EmptyRootHash && h.root != types.EmptyRootHash { - set.AddNode(nil, trienode.NewDeleted()) - } - return root, set -} - -// hash performs the hash computation upon the provided states. -func hash(states map[common.Hash][]byte) (common.Hash, []byte) { - var hs []common.Hash - for hash := range states { - hs = append(hs, hash) - } - slices.SortFunc(hs, common.Hash.Cmp) - - var input []byte - for _, hash := range hs { - if len(states[hash]) == 0 { - continue - } - input = append(input, hash.Bytes()...) - input = append(input, states[hash]...) - } - if len(input) == 0 { - return types.EmptyRootHash, nil - } - return crypto.Keccak256Hash(input), input -} - -type hashLoader struct { - accounts map[common.Hash][]byte - storages map[common.Hash]map[common.Hash][]byte -} - -func newHashLoader(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) *hashLoader { - return &hashLoader{ - accounts: accounts, - storages: storages, - } -} - -// OpenTrie opens the main account trie. -func (l *hashLoader) OpenTrie(root common.Hash) (triestate.Trie, error) { - return newTestHasher(common.Hash{}, root, l.accounts) -} - -// OpenStorageTrie opens the storage trie of an account. -func (l *hashLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) { - return newTestHasher(addrHash, root, l.storages[addrHash]) -} From 19c3c1e20560ff85205dbad9c5c0c698d1854bf6 Mon Sep 17 00:00:00 2001 From: lilasxie Date: Fri, 28 Jun 2024 21:15:54 +0800 Subject: [PATCH 386/571] triedb/pathdb: fix flaky test in pathdb (#29901) --- triedb/pathdb/database_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 8870bfe95b21..f667944784bf 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -121,7 +121,7 @@ func newTester(t *testing.T, historyLimit uint64) *tester { snapStorages: make(map[common.Hash]map[common.Hash]map[common.Hash][]byte), } ) - for i := 0; i < 8; i++ { + for i := 0; i < 12; i++ { var parent = types.EmptyRootHash if len(obj.roots) != 0 { parent = obj.roots[len(obj.roots)-1] From 36d67be41be59fc92118a6a8cdebdf52e1037eb3 Mon Sep 17 00:00:00 2001 From: maskpp Date: Fri, 28 Jun 2024 21:51:27 +0800 Subject: [PATCH 387/571] core/txpool/blobpool: improve newPriceHeap function (#30050) Co-authored-by: Felix Lange --- core/txpool/blobpool/evictheap.go | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/core/txpool/blobpool/evictheap.go b/core/txpool/blobpool/evictheap.go index 701eb405cfc0..5e285e6c534e 100644 --- a/core/txpool/blobpool/evictheap.go +++ b/core/txpool/blobpool/evictheap.go @@ -17,13 +17,13 @@ package blobpool import ( - "bytes" "container/heap" "math" - "sort" + "slices" "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" + "golang.org/x/exp/maps" ) // evictHeap is a helper data structure to keep track of the cheapest bottleneck @@ -49,20 +49,15 @@ type evictHeap struct { func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index map[common.Address][]*blobTxMeta) *evictHeap { heap := &evictHeap{ metas: index, - index: make(map[common.Address]int), + index: make(map[common.Address]int, len(index)), } // Populate the heap in account sort order. Not really needed in practice, // but it makes the heap initialization deterministic and less annoying to // test in unit tests. - addrs := make([]common.Address, 0, len(index)) - for addr := range index { - addrs = append(addrs, addr) - } - sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i][:], addrs[j][:]) < 0 }) - - for _, addr := range addrs { - heap.index[addr] = len(heap.addrs) - heap.addrs = append(heap.addrs, addr) + heap.addrs = maps.Keys(index) + slices.SortFunc(heap.addrs, common.Address.Cmp) + for i, addr := range heap.addrs { + heap.index[addr] = i } heap.reinit(basefee, blobfee, true) return heap From 4939c253411c3a02fff84df6f9506f998b9762de Mon Sep 17 00:00:00 2001 From: maskpp Date: Sat, 29 Jun 2024 00:05:57 +0800 Subject: [PATCH 388/571] cmd/evm/internal/t8ntool: log writeTraceResult error message (#30038) --- cmd/evm/internal/t8ntool/execution.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 3c09229e1c5c..9537d6d97434 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -306,7 +306,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, if tracer.Hooks.OnTxEnd != nil { tracer.Hooks.OnTxEnd(receipt, nil) } - writeTraceResult(tracer, traceOutput) + if err = writeTraceResult(tracer, traceOutput); err != nil { + log.Warn("Error writing tracer output", "err", err) + } } } From 06f1d077d382b457ba28497d1a7bcfb3d0ea5645 Mon Sep 17 00:00:00 2001 From: gitglorythegreat Date: Sat, 29 Jun 2024 00:08:31 +0800 Subject: [PATCH 389/571] all: replace division with right shift if possible (#29911) --- cmd/evm/internal/t8ntool/execution.go | 4 ++-- consensus/ethash/consensus.go | 10 ++-------- core/types/transaction_signing.go | 4 ++-- core/vm/contracts.go | 13 +++++-------- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 9537d6d97434..a4c5f6efcb0a 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -325,7 +325,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, var ( blockReward = big.NewInt(miningReward) minerReward = new(big.Int).Set(blockReward) - perOmmer = new(big.Int).Div(blockReward, big.NewInt(32)) + perOmmer = new(big.Int).Rsh(blockReward, 5) ) for _, ommer := range pre.Env.Ommers { // Add 1/32th for each ommer included @@ -334,7 +334,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, reward := big.NewInt(8) reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Mul(reward, blockReward) - reward.Div(reward, big.NewInt(8)) + reward.Rsh(reward, 3) statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward), tracing.BalanceIncreaseRewardMineUncle) } statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward), tracing.BalanceIncreaseRewardMineBlock) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index b5e2754c2d94..0bd1a56bce19 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -562,12 +562,6 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { return hash } -// Some weird constants to avoid constant memory allocs for them. -var ( - u256_8 = uint256.NewInt(8) - u256_32 = uint256.NewInt(32) -) - // accumulateRewards credits the coinbase of the given block with the mining // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. @@ -589,10 +583,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade r.AddUint64(uNum, 8) r.Sub(r, hNum) r.Mul(r, blockReward) - r.Div(r, u256_8) + r.Rsh(r, 3) stateDB.AddBalance(uncle.Coinbase, r, tracing.BalanceIncreaseRewardMineUncle) - r.Div(blockReward, u256_32) + r.Rsh(blockReward, 5) reward.Add(reward, r) } stateDB.AddBalance(header.Coinbase, reward, tracing.BalanceIncreaseRewardMineBlock) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 2ae38661f31e..339fee6f9737 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -572,6 +572,6 @@ func deriveChainId(v *big.Int) *big.Int { } return new(big.Int).SetUint64((v - 35) / 2) } - v = new(big.Int).Sub(v, big.NewInt(35)) - return v.Div(v, big.NewInt(2)) + v.Sub(v, big.NewInt(35)) + return v.Rsh(v, 1) } diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 8e0f8467752e..dd71a9729f34 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -296,10 +296,7 @@ type bigModExp struct { var ( big1 = big.NewInt(1) big3 = big.NewInt(3) - big4 = big.NewInt(4) big7 = big.NewInt(7) - big8 = big.NewInt(8) - big16 = big.NewInt(16) big20 = big.NewInt(20) big32 = big.NewInt(32) big64 = big.NewInt(64) @@ -325,13 +322,13 @@ func modexpMultComplexity(x *big.Int) *big.Int { case x.Cmp(big1024) <= 0: // (x ** 2 // 4 ) + ( 96 * x - 3072) x = new(big.Int).Add( - new(big.Int).Div(new(big.Int).Mul(x, x), big4), + new(big.Int).Rsh(new(big.Int).Mul(x, x), 2), new(big.Int).Sub(new(big.Int).Mul(big96, x), big3072), ) default: // (x ** 2 // 16) + (480 * x - 199680) x = new(big.Int).Add( - new(big.Int).Div(new(big.Int).Mul(x, x), big16), + new(big.Int).Rsh(new(big.Int).Mul(x, x), 4), new(big.Int).Sub(new(big.Int).Mul(big480, x), big199680), ) } @@ -369,7 +366,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { adjExpLen := new(big.Int) if expLen.Cmp(big32) > 0 { adjExpLen.Sub(expLen, big32) - adjExpLen.Mul(big8, adjExpLen) + adjExpLen.Lsh(adjExpLen, 3) } adjExpLen.Add(adjExpLen, big.NewInt(int64(msb))) // Calculate the gas cost of the operation @@ -383,8 +380,8 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { // ceiling(x/8)^2 // //where is x is max(length_of_MODULUS, length_of_BASE) - gas = gas.Add(gas, big7) - gas = gas.Div(gas, big8) + gas.Add(gas, big7) + gas.Rsh(gas, 3) gas.Mul(gas, gas) gas.Mul(gas, math.BigMax(adjExpLen, big1)) From 7cfff30ba3a67de767a9b2a7405b91f120873d10 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 28 Jun 2024 21:37:58 +0300 Subject: [PATCH 390/571] rpc: truncate call error data logs (#30028) Co-authored-by: Felix Lange --- rpc/handler.go | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/rpc/handler.go b/rpc/handler.go index 7b8f64aa7be8..f23b544b5869 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -17,8 +17,11 @@ package rpc import ( + "bytes" "context" "encoding/json" + "errors" + "fmt" "reflect" "strconv" "strings" @@ -468,16 +471,16 @@ func (h *handler) handleCallMsg(ctx *callProc, msg *jsonrpcMessage) *jsonrpcMess case msg.isCall(): resp := h.handleCall(ctx, msg) - var ctx []interface{} - ctx = append(ctx, "reqid", idForLog{msg.ID}, "duration", time.Since(start)) + var logctx []any + logctx = append(logctx, "reqid", idForLog{msg.ID}, "duration", time.Since(start)) if resp.Error != nil { - ctx = append(ctx, "err", resp.Error.Message) + logctx = append(logctx, "err", resp.Error.Message) if resp.Error.Data != nil { - ctx = append(ctx, "errdata", resp.Error.Data) + logctx = append(logctx, "errdata", formatErrorData(resp.Error.Data)) } - h.log.Warn("Served "+msg.Method, ctx...) + h.log.Warn("Served "+msg.Method, logctx...) } else { - h.log.Debug("Served "+msg.Method, ctx...) + h.log.Debug("Served "+msg.Method, logctx...) } return resp @@ -591,3 +594,33 @@ func (id idForLog) String() string { } return string(id.RawMessage) } + +var errTruncatedOutput = errors.New("truncated output") + +type limitedBuffer struct { + output []byte + limit int +} + +func (buf *limitedBuffer) Write(data []byte) (int, error) { + avail := max(buf.limit, len(buf.output)) + if len(data) < avail { + buf.output = append(buf.output, data...) + return len(data), nil + } + buf.output = append(buf.output, data[:avail]...) + return avail, errTruncatedOutput +} + +func formatErrorData(v any) string { + buf := limitedBuffer{limit: 1024} + err := json.NewEncoder(&buf).Encode(v) + switch { + case err == nil: + return string(bytes.TrimRight(buf.output, "\n")) + case errors.Is(err, errTruncatedOutput): + return fmt.Sprintf("%s... (truncated)", buf.output) + default: + return fmt.Sprintf("bad error data (err=%v)", err) + } +} From a4e338f05e1e38b752a50c0fb2d66d93501a4a3f Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 1 Jul 2024 07:18:38 -0700 Subject: [PATCH 391/571] accounts/usbwallet/trezor: upgrade to generate with protoc 27.1 (#30058) --- .../usbwallet/trezor/messages-common.pb.go | 1371 +++++---- .../usbwallet/trezor/messages-common.proto | 2 + .../usbwallet/trezor/messages-ethereum.pb.go | 1152 +++++--- .../usbwallet/trezor/messages-ethereum.proto | 2 + .../trezor/messages-management.pb.go | 2567 +++++++++++------ .../trezor/messages-management.proto | 2 + accounts/usbwallet/trezor/messages.pb.go | 1735 +++++++---- accounts/usbwallet/trezor/messages.proto | 3 + accounts/usbwallet/trezor/trezor.go | 2 +- 9 files changed, 4334 insertions(+), 2502 deletions(-) diff --git a/accounts/usbwallet/trezor/messages-common.pb.go b/accounts/usbwallet/trezor/messages-common.pb.go index b396c6d8b554..c5e305960bcb 100644 --- a/accounts/usbwallet/trezor/messages-common.pb.go +++ b/accounts/usbwallet/trezor/messages-common.pb.go @@ -1,25 +1,28 @@ +// 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. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v5.27.1 // source: messages-common.proto package trezor import ( - fmt "fmt" - math "math" - - proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// 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 +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) type Failure_FailureType int32 @@ -39,37 +42,39 @@ const ( 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, -} +// Enum value maps for Failure_FailureType. +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", + } + 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) @@ -78,20 +83,34 @@ func (x Failure_FailureType) Enum() *Failure_FailureType { } func (x Failure_FailureType) String() string { - return proto.EnumName(Failure_FailureType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Failure_FailureType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_common_proto_enumTypes[0].Descriptor() +} + +func (Failure_FailureType) Type() protoreflect.EnumType { + return &file_messages_common_proto_enumTypes[0] +} + +func (x Failure_FailureType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } -func (x *Failure_FailureType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(Failure_FailureType_value, data, "Failure_FailureType") +// Deprecated: Do not use. +func (x *Failure_FailureType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = Failure_FailureType(value) + *x = Failure_FailureType(num) return nil } +// Deprecated: Use Failure_FailureType.Descriptor instead. func (Failure_FailureType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{1, 0} + return file_messages_common_proto_rawDescGZIP(), []int{1, 0} } // * @@ -116,41 +135,43 @@ const ( 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, -} +// Enum value maps for ButtonRequest_ButtonRequestType. +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", + } + 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) @@ -159,20 +180,34 @@ func (x ButtonRequest_ButtonRequestType) Enum() *ButtonRequest_ButtonRequestType } func (x ButtonRequest_ButtonRequestType) String() string { - return proto.EnumName(ButtonRequest_ButtonRequestType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ButtonRequest_ButtonRequestType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_common_proto_enumTypes[1].Descriptor() +} + +func (ButtonRequest_ButtonRequestType) Type() protoreflect.EnumType { + return &file_messages_common_proto_enumTypes[1] +} + +func (x ButtonRequest_ButtonRequestType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } -func (x *ButtonRequest_ButtonRequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(ButtonRequest_ButtonRequestType_value, data, "ButtonRequest_ButtonRequestType") +// Deprecated: Do not use. +func (x *ButtonRequest_ButtonRequestType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = ButtonRequest_ButtonRequestType(value) + *x = ButtonRequest_ButtonRequestType(num) return nil } +// Deprecated: Use ButtonRequest_ButtonRequestType.Descriptor instead. func (ButtonRequest_ButtonRequestType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{2, 0} + return file_messages_common_proto_rawDescGZIP(), []int{2, 0} } // * @@ -185,17 +220,19 @@ const ( 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, -} +// Enum value maps for PinMatrixRequest_PinMatrixRequestType. +var ( + PinMatrixRequest_PinMatrixRequestType_name = map[int32]string{ + 1: "PinMatrixRequestType_Current", + 2: "PinMatrixRequestType_NewFirst", + 3: "PinMatrixRequestType_NewSecond", + } + 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) @@ -204,60 +241,82 @@ func (x PinMatrixRequest_PinMatrixRequestType) Enum() *PinMatrixRequest_PinMatri } func (x PinMatrixRequest_PinMatrixRequestType) String() string { - return proto.EnumName(PinMatrixRequest_PinMatrixRequestType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PinMatrixRequest_PinMatrixRequestType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_common_proto_enumTypes[2].Descriptor() +} + +func (PinMatrixRequest_PinMatrixRequestType) Type() protoreflect.EnumType { + return &file_messages_common_proto_enumTypes[2] } -func (x *PinMatrixRequest_PinMatrixRequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(PinMatrixRequest_PinMatrixRequestType_value, data, "PinMatrixRequest_PinMatrixRequestType") +func (x PinMatrixRequest_PinMatrixRequestType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *PinMatrixRequest_PinMatrixRequestType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = PinMatrixRequest_PinMatrixRequestType(value) + *x = PinMatrixRequest_PinMatrixRequestType(num) return nil } +// Deprecated: Use PinMatrixRequest_PinMatrixRequestType.Descriptor instead. func (PinMatrixRequest_PinMatrixRequestType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{4, 0} + return file_messages_common_proto_rawDescGZIP(), []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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` // human readable description of action or request-specific payload } -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 (x *Success) Reset() { + *x = Success{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Success) XXX_Size() int { - return xxx_messageInfo_Success.Size(m) + +func (x *Success) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Success) XXX_DiscardUnknown() { - xxx_messageInfo_Success.DiscardUnknown(m) + +func (*Success) ProtoMessage() {} + +func (x *Success) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Success proto.InternalMessageInfo +// Deprecated: Use Success.ProtoReflect.Descriptor instead. +func (*Success) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{0} +} -func (m *Success) GetMessage() string { - if m != nil && m.Message != nil { - return *m.Message +func (x *Success) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message } return "" } @@ -266,48 +325,56 @@ func (m *Success) GetMessage() string { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Code *Failure_FailureType `protobuf:"varint,1,opt,name=code,enum=hw.trezor.messages.common.Failure_FailureType" json:"code,omitempty"` // computer-readable definition of the error state + Message *string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` // human-readable message of the error state } -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 (x *Failure) Reset() { + *x = Failure{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Failure) XXX_Size() int { - return xxx_messageInfo_Failure.Size(m) + +func (x *Failure) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Failure) XXX_DiscardUnknown() { - xxx_messageInfo_Failure.DiscardUnknown(m) + +func (*Failure) ProtoMessage() {} + +func (x *Failure) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Failure proto.InternalMessageInfo +// Deprecated: Use Failure.ProtoReflect.Descriptor instead. +func (*Failure) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{1} +} -func (m *Failure) GetCode() Failure_FailureType { - if m != nil && m.Code != nil { - return *m.Code +func (x *Failure) GetCode() Failure_FailureType { + if x != nil && x.Code != nil { + return *x.Code } return Failure_Failure_UnexpectedMessage } -func (m *Failure) GetMessage() string { - if m != nil && m.Message != nil { - return *m.Message +func (x *Failure) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message } return "" } @@ -317,48 +384,56 @@ func (m *Failure) GetMessage() string { // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + 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"` } -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 (x *ButtonRequest) Reset() { + *x = ButtonRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ButtonRequest) XXX_Size() int { - return xxx_messageInfo_ButtonRequest.Size(m) + +func (x *ButtonRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ButtonRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ButtonRequest.DiscardUnknown(m) + +func (*ButtonRequest) ProtoMessage() {} + +func (x *ButtonRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ButtonRequest proto.InternalMessageInfo +// Deprecated: Use ButtonRequest.ProtoReflect.Descriptor instead. +func (*ButtonRequest) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{2} +} -func (m *ButtonRequest) GetCode() ButtonRequest_ButtonRequestType { - if m != nil && m.Code != nil { - return *m.Code +func (x *ButtonRequest) GetCode() ButtonRequest_ButtonRequestType { + if x != nil && x.Code != nil { + return *x.Code } return ButtonRequest_ButtonRequest_Other } -func (m *ButtonRequest) GetData() string { - if m != nil && m.Data != nil { - return *m.Data +func (x *ButtonRequest) GetData() string { + if x != nil && x.Data != nil { + return *x.Data } return "" } @@ -367,75 +442,90 @@ func (m *ButtonRequest) GetData() string { // 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:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -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 (x *ButtonAck) Reset() { + *x = ButtonAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -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 (x *ButtonAck) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ButtonAck) XXX_DiscardUnknown() { - xxx_messageInfo_ButtonAck.DiscardUnknown(m) + +func (*ButtonAck) ProtoMessage() {} + +func (x *ButtonAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ButtonAck proto.InternalMessageInfo +// Deprecated: Use ButtonAck.ProtoReflect.Descriptor instead. +func (*ButtonAck) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{3} +} // * // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Type *PinMatrixRequest_PinMatrixRequestType `protobuf:"varint,1,opt,name=type,enum=hw.trezor.messages.common.PinMatrixRequest_PinMatrixRequestType" json:"type,omitempty"` } -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 (x *PinMatrixRequest) Reset() { + *x = PinMatrixRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *PinMatrixRequest) XXX_Size() int { - return xxx_messageInfo_PinMatrixRequest.Size(m) + +func (x *PinMatrixRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *PinMatrixRequest) XXX_DiscardUnknown() { - xxx_messageInfo_PinMatrixRequest.DiscardUnknown(m) + +func (*PinMatrixRequest) ProtoMessage() {} + +func (x *PinMatrixRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_PinMatrixRequest proto.InternalMessageInfo +// Deprecated: Use PinMatrixRequest.ProtoReflect.Descriptor instead. +func (*PinMatrixRequest) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{4} +} -func (m *PinMatrixRequest) GetType() PinMatrixRequest_PinMatrixRequestType { - if m != nil && m.Type != nil { - return *m.Type +func (x *PinMatrixRequest) GetType() PinMatrixRequest_PinMatrixRequestType { + if x != nil && x.Type != nil { + return *x.Type } return PinMatrixRequest_PinMatrixRequestType_Current } @@ -444,40 +534,48 @@ func (m *PinMatrixRequest) GetType() PinMatrixRequest_PinMatrixRequestType { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Pin *string `protobuf:"bytes,1,req,name=pin" json:"pin,omitempty"` // matrix encoded PIN entered by user } -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 (x *PinMatrixAck) Reset() { + *x = PinMatrixAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *PinMatrixAck) XXX_Size() int { - return xxx_messageInfo_PinMatrixAck.Size(m) + +func (x *PinMatrixAck) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *PinMatrixAck) XXX_DiscardUnknown() { - xxx_messageInfo_PinMatrixAck.DiscardUnknown(m) + +func (*PinMatrixAck) ProtoMessage() {} + +func (x *PinMatrixAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_PinMatrixAck proto.InternalMessageInfo +// Deprecated: Use PinMatrixAck.ProtoReflect.Descriptor instead. +func (*PinMatrixAck) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{5} +} -func (m *PinMatrixAck) GetPin() string { - if m != nil && m.Pin != nil { - return *m.Pin +func (x *PinMatrixAck) GetPin() string { + if x != nil && x.Pin != nil { + return *x.Pin } return "" } @@ -487,40 +585,48 @@ func (m *PinMatrixAck) GetPin() string { // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + OnDevice *bool `protobuf:"varint,1,opt,name=on_device,json=onDevice" json:"on_device,omitempty"` // passphrase is being entered on the device } -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 (x *PassphraseRequest) Reset() { + *x = PassphraseRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *PassphraseRequest) XXX_Size() int { - return xxx_messageInfo_PassphraseRequest.Size(m) + +func (x *PassphraseRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *PassphraseRequest) XXX_DiscardUnknown() { - xxx_messageInfo_PassphraseRequest.DiscardUnknown(m) + +func (*PassphraseRequest) ProtoMessage() {} + +func (x *PassphraseRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_PassphraseRequest proto.InternalMessageInfo +// Deprecated: Use PassphraseRequest.ProtoReflect.Descriptor instead. +func (*PassphraseRequest) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{6} +} -func (m *PassphraseRequest) GetOnDevice() bool { - if m != nil && m.OnDevice != nil { - return *m.OnDevice +func (x *PassphraseRequest) GetOnDevice() bool { + if x != nil && x.OnDevice != nil { + return *x.OnDevice } return false } @@ -529,48 +635,56 @@ func (m *PassphraseRequest) GetOnDevice() bool { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Passphrase *string `protobuf:"bytes,1,opt,name=passphrase" json:"passphrase,omitempty"` + State []byte `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"` // expected device state } -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 (x *PassphraseAck) Reset() { + *x = PassphraseAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *PassphraseAck) XXX_Size() int { - return xxx_messageInfo_PassphraseAck.Size(m) + +func (x *PassphraseAck) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *PassphraseAck) XXX_DiscardUnknown() { - xxx_messageInfo_PassphraseAck.DiscardUnknown(m) + +func (*PassphraseAck) ProtoMessage() {} + +func (x *PassphraseAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_PassphraseAck proto.InternalMessageInfo +// Deprecated: Use PassphraseAck.ProtoReflect.Descriptor instead. +func (*PassphraseAck) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{7} +} -func (m *PassphraseAck) GetPassphrase() string { - if m != nil && m.Passphrase != nil { - return *m.Passphrase +func (x *PassphraseAck) GetPassphrase() string { + if x != nil && x.Passphrase != nil { + return *x.Passphrase } return "" } -func (m *PassphraseAck) GetState() []byte { - if m != nil { - return m.State +func (x *PassphraseAck) GetState() []byte { + if x != nil { + return x.State } return nil } @@ -579,40 +693,48 @@ func (m *PassphraseAck) GetState() []byte { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + State []byte `protobuf:"bytes,1,opt,name=state" json:"state,omitempty"` // actual device state } -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 (x *PassphraseStateRequest) Reset() { + *x = PassphraseStateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *PassphraseStateRequest) XXX_Size() int { - return xxx_messageInfo_PassphraseStateRequest.Size(m) + +func (x *PassphraseStateRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *PassphraseStateRequest) XXX_DiscardUnknown() { - xxx_messageInfo_PassphraseStateRequest.DiscardUnknown(m) + +func (*PassphraseStateRequest) ProtoMessage() {} + +func (x *PassphraseStateRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_PassphraseStateRequest proto.InternalMessageInfo +// Deprecated: Use PassphraseStateRequest.ProtoReflect.Descriptor instead. +func (*PassphraseStateRequest) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{8} +} -func (m *PassphraseStateRequest) GetState() []byte { - if m != nil { - return m.State +func (x *PassphraseStateRequest) GetState() []byte { + if x != nil { + return x.State } return nil } @@ -621,191 +743,456 @@ func (m *PassphraseStateRequest) GetState() []byte { // Request: Send passphrase state back // @auxend type PassphraseStateAck struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -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 (x *PassphraseStateAck) Reset() { + *x = PassphraseStateAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -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 (x *PassphraseStateAck) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *PassphraseStateAck) XXX_DiscardUnknown() { - xxx_messageInfo_PassphraseStateAck.DiscardUnknown(m) + +func (*PassphraseStateAck) ProtoMessage() {} + +func (x *PassphraseStateAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_PassphraseStateAck proto.InternalMessageInfo +// Deprecated: Use PassphraseStateAck.ProtoReflect.Descriptor instead. +func (*PassphraseStateAck) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{9} +} // * // 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} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + 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"` +} + +func (x *HDNodeType) Reset() { + *x = HDNodeType{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -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 (x *HDNodeType) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *HDNodeType) XXX_DiscardUnknown() { - xxx_messageInfo_HDNodeType.DiscardUnknown(m) + +func (*HDNodeType) ProtoMessage() {} + +func (x *HDNodeType) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_HDNodeType proto.InternalMessageInfo +// Deprecated: Use HDNodeType.ProtoReflect.Descriptor instead. +func (*HDNodeType) Descriptor() ([]byte, []int) { + return file_messages_common_proto_rawDescGZIP(), []int{10} +} -func (m *HDNodeType) GetDepth() uint32 { - if m != nil && m.Depth != nil { - return *m.Depth +func (x *HDNodeType) GetDepth() uint32 { + if x != nil && x.Depth != nil { + return *x.Depth } return 0 } -func (m *HDNodeType) GetFingerprint() uint32 { - if m != nil && m.Fingerprint != nil { - return *m.Fingerprint +func (x *HDNodeType) GetFingerprint() uint32 { + if x != nil && x.Fingerprint != nil { + return *x.Fingerprint } return 0 } -func (m *HDNodeType) GetChildNum() uint32 { - if m != nil && m.ChildNum != nil { - return *m.ChildNum +func (x *HDNodeType) GetChildNum() uint32 { + if x != nil && x.ChildNum != nil { + return *x.ChildNum } return 0 } -func (m *HDNodeType) GetChainCode() []byte { - if m != nil { - return m.ChainCode +func (x *HDNodeType) GetChainCode() []byte { + if x != nil { + return x.ChainCode } return nil } -func (m *HDNodeType) GetPrivateKey() []byte { - if m != nil { - return m.PrivateKey +func (x *HDNodeType) GetPrivateKey() []byte { + if x != nil { + return x.PrivateKey } return nil } -func (m *HDNodeType) GetPublicKey() []byte { - if m != nil { - return m.PublicKey +func (x *HDNodeType) GetPublicKey() []byte { + if x != nil { + return x.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, +var File_messages_common_proto protoreflect.FileDescriptor + +var file_messages_common_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, + 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x22, 0x23, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd5, 0x03, 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, + 0x75, 0x72, 0x65, 0x12, 0x42, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x2e, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, 0x61, + 0x69, 0x6c, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0xeb, 0x02, 0x0a, 0x0b, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x55, 0x6e, 0x65, + 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x01, + 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, + 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x44, 0x61, 0x74, 0x61, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x10, 0x03, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x10, 0x04, + 0x12, 0x17, 0x0a, 0x13, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x45, + 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x61, 0x69, + 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, + 0x64, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, + 0x69, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 0x07, 0x12, 0x1c, 0x0a, 0x18, 0x46, + 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x08, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x61, 0x69, + 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x10, 0x09, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x4e, + 0x6f, 0x74, 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x46, 0x75, 0x6e, 0x64, 0x73, 0x10, 0x0a, 0x12, + 0x1a, 0x0a, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x4e, 0x6f, 0x74, 0x49, 0x6e, + 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x10, 0x0b, 0x12, 0x17, 0x0a, 0x13, 0x46, + 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x4d, 0x69, 0x73, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, + 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x63, 0x22, + 0xe6, 0x04, 0x0a, 0x0d, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x4e, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x3a, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf0, 0x03, 0x0a, 0x11, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x42, + 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x4f, 0x74, 0x68, + 0x65, 0x72, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x46, 0x65, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x54, 0x68, 0x72, + 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, + 0x6d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x75, 0x74, + 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x52, 0x65, 0x73, 0x65, 0x74, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x10, 0x04, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, + 0x6d, 0x57, 0x6f, 0x72, 0x64, 0x10, 0x05, 0x12, 0x1c, 0x0a, 0x18, 0x42, 0x75, 0x74, 0x74, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x57, 0x69, 0x70, 0x65, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x10, 0x06, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x43, 0x61, + 0x6c, 0x6c, 0x10, 0x07, 0x12, 0x18, 0x0a, 0x14, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0x08, 0x12, 0x1f, + 0x0a, 0x1b, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x10, 0x09, 0x12, + 0x19, 0x0a, 0x15, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x0a, 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x75, + 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0x0b, 0x12, 0x23, 0x0a, 0x1f, 0x42, 0x75, 0x74, 0x74, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, + 0x63, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0x0c, 0x12, 0x1f, 0x0a, 0x1b, + 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x4d, 0x6e, + 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x10, 0x0d, 0x12, 0x20, 0x0a, + 0x1c, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x50, + 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0x0e, 0x12, + 0x27, 0x0a, 0x23, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x44, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x10, 0x0f, 0x22, 0x0b, 0x0a, 0x09, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x41, 0x63, 0x6b, 0x22, 0xe9, 0x01, 0x0a, 0x10, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, + 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x40, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x7f, 0x0a, 0x14, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x69, 0x6e, 0x4d, + 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x69, + 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x4e, 0x65, 0x77, 0x46, 0x69, 0x72, 0x73, 0x74, 0x10, 0x02, 0x12, 0x22, 0x0a, + 0x1e, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x65, 0x77, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x10, + 0x03, 0x22, 0x20, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x41, 0x63, + 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, + 0x70, 0x69, 0x6e, 0x22, 0x30, 0x0a, 0x11, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x6e, 0x5f, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6f, 0x6e, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x45, 0x0a, 0x0d, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, + 0x61, 0x73, 0x65, 0x41, 0x63, 0x6b, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, + 0x72, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x73, 0x73, + 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x2e, 0x0a, 0x16, + 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x14, 0x0a, 0x12, + 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, + 0x63, 0x6b, 0x22, 0xc0, 0x01, 0x0a, 0x0a, 0x48, 0x44, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0d, + 0x52, 0x05, 0x64, 0x65, 0x70, 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x02, 0x28, 0x0d, 0x52, 0x0b, 0x66, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x68, 0x69, + 0x6c, 0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x02, 0x28, 0x0d, 0x52, 0x08, 0x63, 0x68, + 0x69, 0x6c, 0x64, 0x4e, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, + 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x02, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x2f, 0x75, 0x73, 0x62, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x74, 0x72, 0x65, 0x7a, + 0x6f, 0x72, +} + +var ( + file_messages_common_proto_rawDescOnce sync.Once + file_messages_common_proto_rawDescData = file_messages_common_proto_rawDesc +) + +func file_messages_common_proto_rawDescGZIP() []byte { + file_messages_common_proto_rawDescOnce.Do(func() { + file_messages_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_common_proto_rawDescData) + }) + return file_messages_common_proto_rawDescData +} + +var file_messages_common_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_messages_common_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_messages_common_proto_goTypes = []interface{}{ + (Failure_FailureType)(0), // 0: hw.trezor.messages.common.Failure.FailureType + (ButtonRequest_ButtonRequestType)(0), // 1: hw.trezor.messages.common.ButtonRequest.ButtonRequestType + (PinMatrixRequest_PinMatrixRequestType)(0), // 2: hw.trezor.messages.common.PinMatrixRequest.PinMatrixRequestType + (*Success)(nil), // 3: hw.trezor.messages.common.Success + (*Failure)(nil), // 4: hw.trezor.messages.common.Failure + (*ButtonRequest)(nil), // 5: hw.trezor.messages.common.ButtonRequest + (*ButtonAck)(nil), // 6: hw.trezor.messages.common.ButtonAck + (*PinMatrixRequest)(nil), // 7: hw.trezor.messages.common.PinMatrixRequest + (*PinMatrixAck)(nil), // 8: hw.trezor.messages.common.PinMatrixAck + (*PassphraseRequest)(nil), // 9: hw.trezor.messages.common.PassphraseRequest + (*PassphraseAck)(nil), // 10: hw.trezor.messages.common.PassphraseAck + (*PassphraseStateRequest)(nil), // 11: hw.trezor.messages.common.PassphraseStateRequest + (*PassphraseStateAck)(nil), // 12: hw.trezor.messages.common.PassphraseStateAck + (*HDNodeType)(nil), // 13: hw.trezor.messages.common.HDNodeType +} +var file_messages_common_proto_depIdxs = []int32{ + 0, // 0: hw.trezor.messages.common.Failure.code:type_name -> hw.trezor.messages.common.Failure.FailureType + 1, // 1: hw.trezor.messages.common.ButtonRequest.code:type_name -> hw.trezor.messages.common.ButtonRequest.ButtonRequestType + 2, // 2: hw.trezor.messages.common.PinMatrixRequest.type:type_name -> hw.trezor.messages.common.PinMatrixRequest.PinMatrixRequestType + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_messages_common_proto_init() } +func file_messages_common_proto_init() { + if File_messages_common_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_messages_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Success); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Failure); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ButtonRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ButtonAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PinMatrixRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PinMatrixAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PassphraseRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PassphraseAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PassphraseStateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PassphraseStateAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HDNodeType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_messages_common_proto_rawDesc, + NumEnums: 3, + NumMessages: 11, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_messages_common_proto_goTypes, + DependencyIndexes: file_messages_common_proto_depIdxs, + EnumInfos: file_messages_common_proto_enumTypes, + MessageInfos: file_messages_common_proto_msgTypes, + }.Build() + File_messages_common_proto = out.File + file_messages_common_proto_rawDesc = nil + file_messages_common_proto_goTypes = nil + file_messages_common_proto_depIdxs = nil } diff --git a/accounts/usbwallet/trezor/messages-common.proto b/accounts/usbwallet/trezor/messages-common.proto index 75a983b0a3e5..1f524e25d7bf 100644 --- a/accounts/usbwallet/trezor/messages-common.proto +++ b/accounts/usbwallet/trezor/messages-common.proto @@ -5,6 +5,8 @@ syntax = "proto2"; package hw.trezor.messages.common; +option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"; + /** * Response: Success of the previous request * @end diff --git a/accounts/usbwallet/trezor/messages-ethereum.pb.go b/accounts/usbwallet/trezor/messages-ethereum.pb.go index 230a48279d48..a080a1c3fe8d 100644 --- a/accounts/usbwallet/trezor/messages-ethereum.pb.go +++ b/accounts/usbwallet/trezor/messages-ethereum.pb.go @@ -1,25 +1,28 @@ +// 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. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v5.27.1 // source: messages-ethereum.proto package trezor import ( - fmt "fmt" - math "math" - - proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// 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 +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) // * // Request: Ask device for public key corresponding to address_n path @@ -27,48 +30,56 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` // BIP-32 path to derive the key from master node + ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` // optionally show on display before sending the result } -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 (x *EthereumGetPublicKey) Reset() { + *x = EthereumGetPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumGetPublicKey) XXX_Size() int { - return xxx_messageInfo_EthereumGetPublicKey.Size(m) + +func (x *EthereumGetPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumGetPublicKey) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumGetPublicKey.DiscardUnknown(m) + +func (*EthereumGetPublicKey) ProtoMessage() {} + +func (x *EthereumGetPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumGetPublicKey proto.InternalMessageInfo +// Deprecated: Use EthereumGetPublicKey.ProtoReflect.Descriptor instead. +func (*EthereumGetPublicKey) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{0} +} -func (m *EthereumGetPublicKey) GetAddressN() []uint32 { - if m != nil { - return m.AddressN +func (x *EthereumGetPublicKey) GetAddressN() []uint32 { + if x != nil { + return x.AddressN } return nil } -func (m *EthereumGetPublicKey) GetShowDisplay() bool { - if m != nil && m.ShowDisplay != nil { - return *m.ShowDisplay +func (x *EthereumGetPublicKey) GetShowDisplay() bool { + if x != nil && x.ShowDisplay != nil { + return *x.ShowDisplay } return false } @@ -77,48 +88,56 @@ func (m *EthereumGetPublicKey) GetShowDisplay() bool { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Node *HDNodeType `protobuf:"bytes,1,opt,name=node" json:"node,omitempty"` // BIP32 public node + Xpub *string `protobuf:"bytes,2,opt,name=xpub" json:"xpub,omitempty"` // serialized form of public node } -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 (x *EthereumPublicKey) Reset() { + *x = EthereumPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumPublicKey) XXX_Size() int { - return xxx_messageInfo_EthereumPublicKey.Size(m) + +func (x *EthereumPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumPublicKey) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumPublicKey.DiscardUnknown(m) + +func (*EthereumPublicKey) ProtoMessage() {} + +func (x *EthereumPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumPublicKey proto.InternalMessageInfo +// Deprecated: Use EthereumPublicKey.ProtoReflect.Descriptor instead. +func (*EthereumPublicKey) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{1} +} -func (m *EthereumPublicKey) GetNode() *HDNodeType { - if m != nil { - return m.Node +func (x *EthereumPublicKey) GetNode() *HDNodeType { + if x != nil { + return x.Node } return nil } -func (m *EthereumPublicKey) GetXpub() string { - if m != nil && m.Xpub != nil { - return *m.Xpub +func (x *EthereumPublicKey) GetXpub() string { + if x != nil && x.Xpub != nil { + return *x.Xpub } return "" } @@ -129,48 +148,56 @@ func (m *EthereumPublicKey) GetXpub() string { // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` // BIP-32 path to derive the key from master node + ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` // optionally show on display before sending the result } -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 (x *EthereumGetAddress) Reset() { + *x = EthereumGetAddress{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumGetAddress) XXX_Size() int { - return xxx_messageInfo_EthereumGetAddress.Size(m) + +func (x *EthereumGetAddress) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumGetAddress) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumGetAddress.DiscardUnknown(m) + +func (*EthereumGetAddress) ProtoMessage() {} + +func (x *EthereumGetAddress) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumGetAddress proto.InternalMessageInfo +// Deprecated: Use EthereumGetAddress.ProtoReflect.Descriptor instead. +func (*EthereumGetAddress) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{2} +} -func (m *EthereumGetAddress) GetAddressN() []uint32 { - if m != nil { - return m.AddressN +func (x *EthereumGetAddress) GetAddressN() []uint32 { + if x != nil { + return x.AddressN } return nil } -func (m *EthereumGetAddress) GetShowDisplay() bool { - if m != nil && m.ShowDisplay != nil { - return *m.ShowDisplay +func (x *EthereumGetAddress) GetShowDisplay() bool { + if x != nil && x.ShowDisplay != nil { + return *x.ShowDisplay } return false } @@ -179,48 +206,56 @@ func (m *EthereumGetAddress) GetShowDisplay() bool { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` // Ethereum address as 20 bytes (legacy firmwares) + AddressHex *string `protobuf:"bytes,2,opt,name=addressHex" json:"addressHex,omitempty"` // Ethereum address as hex string (newer firmwares) } -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 (x *EthereumAddress) Reset() { + *x = EthereumAddress{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumAddress) XXX_Size() int { - return xxx_messageInfo_EthereumAddress.Size(m) + +func (x *EthereumAddress) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumAddress) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumAddress.DiscardUnknown(m) + +func (*EthereumAddress) ProtoMessage() {} + +func (x *EthereumAddress) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumAddress proto.InternalMessageInfo +// Deprecated: Use EthereumAddress.ProtoReflect.Descriptor instead. +func (*EthereumAddress) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{3} +} -func (m *EthereumAddress) GetAddressBin() []byte { - if m != nil { - return m.AddressBin +func (x *EthereumAddress) GetAddressBin() []byte { + if x != nil { + return x.AddressBin } return nil } -func (m *EthereumAddress) GetAddressHex() string { - if m != nil && m.AddressHex != nil { - return *m.AddressHex +func (x *EthereumAddress) GetAddressHex() string { + if x != nil && x.AddressHex != nil { + return *x.AddressHex } return "" } @@ -233,120 +268,128 @@ func (m *EthereumAddress) GetAddressHex() string { // @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} -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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) + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` // BIP-32 path to derive the key from master node + Nonce []byte `protobuf:"bytes,2,opt,name=nonce" json:"nonce,omitempty"` // <=256 bit unsigned big endian + GasPrice []byte `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice" json:"gas_price,omitempty"` // <=256 bit unsigned big endian (in wei) + GasLimit []byte `protobuf:"bytes,4,opt,name=gas_limit,json=gasLimit" json:"gas_limit,omitempty"` // <=256 bit unsigned big endian + ToBin []byte `protobuf:"bytes,5,opt,name=toBin" json:"toBin,omitempty"` // recipient address (20 bytes, legacy firmware) + ToHex *string `protobuf:"bytes,11,opt,name=toHex" json:"toHex,omitempty"` // recipient address (hex string, newer firmware) + Value []byte `protobuf:"bytes,6,opt,name=value" json:"value,omitempty"` // <=256 bit unsigned big endian (in wei) + DataInitialChunk []byte `protobuf:"bytes,7,opt,name=data_initial_chunk,json=dataInitialChunk" json:"data_initial_chunk,omitempty"` // The initial data chunk (<= 1024 bytes) + DataLength *uint32 `protobuf:"varint,8,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` // Length of transaction payload + ChainId *uint32 `protobuf:"varint,9,opt,name=chain_id,json=chainId" json:"chain_id,omitempty"` // Chain Id for EIP 155 + TxType *uint32 `protobuf:"varint,10,opt,name=tx_type,json=txType" json:"tx_type,omitempty"` // (only for Wanchain) } -func (m *EthereumSignTx) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumSignTx.Merge(m, src) + +func (x *EthereumSignTx) Reset() { + *x = EthereumSignTx{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumSignTx) XXX_Size() int { - return xxx_messageInfo_EthereumSignTx.Size(m) + +func (x *EthereumSignTx) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumSignTx) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumSignTx.DiscardUnknown(m) + +func (*EthereumSignTx) ProtoMessage() {} + +func (x *EthereumSignTx) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumSignTx proto.InternalMessageInfo +// Deprecated: Use EthereumSignTx.ProtoReflect.Descriptor instead. +func (*EthereumSignTx) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{4} +} -func (m *EthereumSignTx) GetAddressN() []uint32 { - if m != nil { - return m.AddressN +func (x *EthereumSignTx) GetAddressN() []uint32 { + if x != nil { + return x.AddressN } return nil } -func (m *EthereumSignTx) GetNonce() []byte { - if m != nil { - return m.Nonce +func (x *EthereumSignTx) GetNonce() []byte { + if x != nil { + return x.Nonce } return nil } -func (m *EthereumSignTx) GetGasPrice() []byte { - if m != nil { - return m.GasPrice +func (x *EthereumSignTx) GetGasPrice() []byte { + if x != nil { + return x.GasPrice } return nil } -func (m *EthereumSignTx) GetGasLimit() []byte { - if m != nil { - return m.GasLimit +func (x *EthereumSignTx) GetGasLimit() []byte { + if x != nil { + return x.GasLimit } return nil } -func (m *EthereumSignTx) GetToBin() []byte { - if m != nil { - return m.ToBin +func (x *EthereumSignTx) GetToBin() []byte { + if x != nil { + return x.ToBin } return nil } -func (m *EthereumSignTx) GetToHex() string { - if m != nil && m.ToHex != nil { - return *m.ToHex +func (x *EthereumSignTx) GetToHex() string { + if x != nil && x.ToHex != nil { + return *x.ToHex } return "" } -func (m *EthereumSignTx) GetValue() []byte { - if m != nil { - return m.Value +func (x *EthereumSignTx) GetValue() []byte { + if x != nil { + return x.Value } return nil } -func (m *EthereumSignTx) GetDataInitialChunk() []byte { - if m != nil { - return m.DataInitialChunk +func (x *EthereumSignTx) GetDataInitialChunk() []byte { + if x != nil { + return x.DataInitialChunk } return nil } -func (m *EthereumSignTx) GetDataLength() uint32 { - if m != nil && m.DataLength != nil { - return *m.DataLength +func (x *EthereumSignTx) GetDataLength() uint32 { + if x != nil && x.DataLength != nil { + return *x.DataLength } return 0 } -func (m *EthereumSignTx) GetChainId() uint32 { - if m != nil && m.ChainId != nil { - return *m.ChainId +func (x *EthereumSignTx) GetChainId() uint32 { + if x != nil && x.ChainId != nil { + return *x.ChainId } return 0 } -func (m *EthereumSignTx) GetTxType() uint32 { - if m != nil && m.TxType != nil { - return *m.TxType +func (x *EthereumSignTx) GetTxType() uint32 { + if x != nil && x.TxType != nil { + return *x.TxType } return 0 } @@ -358,64 +401,72 @@ func (m *EthereumSignTx) GetTxType() uint32 { // @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} -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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) + DataLength *uint32 `protobuf:"varint,1,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` // Number of bytes being requested (<= 1024) + SignatureV *uint32 `protobuf:"varint,2,opt,name=signature_v,json=signatureV" json:"signature_v,omitempty"` // Computed signature (recovery parameter, limited to 27 or 28) + SignatureR []byte `protobuf:"bytes,3,opt,name=signature_r,json=signatureR" json:"signature_r,omitempty"` // Computed signature R component (256 bit) + SignatureS []byte `protobuf:"bytes,4,opt,name=signature_s,json=signatureS" json:"signature_s,omitempty"` // Computed signature S component (256 bit) } -func (m *EthereumTxRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumTxRequest.Merge(m, src) + +func (x *EthereumTxRequest) Reset() { + *x = EthereumTxRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumTxRequest) XXX_Size() int { - return xxx_messageInfo_EthereumTxRequest.Size(m) + +func (x *EthereumTxRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumTxRequest) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumTxRequest.DiscardUnknown(m) + +func (*EthereumTxRequest) ProtoMessage() {} + +func (x *EthereumTxRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumTxRequest proto.InternalMessageInfo +// Deprecated: Use EthereumTxRequest.ProtoReflect.Descriptor instead. +func (*EthereumTxRequest) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{5} +} -func (m *EthereumTxRequest) GetDataLength() uint32 { - if m != nil && m.DataLength != nil { - return *m.DataLength +func (x *EthereumTxRequest) GetDataLength() uint32 { + if x != nil && x.DataLength != nil { + return *x.DataLength } return 0 } -func (m *EthereumTxRequest) GetSignatureV() uint32 { - if m != nil && m.SignatureV != nil { - return *m.SignatureV +func (x *EthereumTxRequest) GetSignatureV() uint32 { + if x != nil && x.SignatureV != nil { + return *x.SignatureV } return 0 } -func (m *EthereumTxRequest) GetSignatureR() []byte { - if m != nil { - return m.SignatureR +func (x *EthereumTxRequest) GetSignatureR() []byte { + if x != nil { + return x.SignatureR } return nil } -func (m *EthereumTxRequest) GetSignatureS() []byte { - if m != nil { - return m.SignatureS +func (x *EthereumTxRequest) GetSignatureS() []byte { + if x != nil { + return x.SignatureS } return nil } @@ -424,40 +475,48 @@ func (m *EthereumTxRequest) GetSignatureS() []byte { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + DataChunk []byte `protobuf:"bytes,1,opt,name=data_chunk,json=dataChunk" json:"data_chunk,omitempty"` // Bytes from transaction payload (<= 1024 bytes) } -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 (x *EthereumTxAck) Reset() { + *x = EthereumTxAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumTxAck) XXX_Size() int { - return xxx_messageInfo_EthereumTxAck.Size(m) + +func (x *EthereumTxAck) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumTxAck) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumTxAck.DiscardUnknown(m) + +func (*EthereumTxAck) ProtoMessage() {} + +func (x *EthereumTxAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumTxAck proto.InternalMessageInfo +// Deprecated: Use EthereumTxAck.ProtoReflect.Descriptor instead. +func (*EthereumTxAck) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{6} +} -func (m *EthereumTxAck) GetDataChunk() []byte { - if m != nil { - return m.DataChunk +func (x *EthereumTxAck) GetDataChunk() []byte { + if x != nil { + return x.DataChunk } return nil } @@ -468,48 +527,56 @@ func (m *EthereumTxAck) GetDataChunk() []byte { // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` // BIP-32 path to derive the key from master node + Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` // message to be signed } -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 (x *EthereumSignMessage) Reset() { + *x = EthereumSignMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumSignMessage) XXX_Size() int { - return xxx_messageInfo_EthereumSignMessage.Size(m) + +func (x *EthereumSignMessage) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumSignMessage) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumSignMessage.DiscardUnknown(m) + +func (*EthereumSignMessage) ProtoMessage() {} + +func (x *EthereumSignMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumSignMessage proto.InternalMessageInfo +// Deprecated: Use EthereumSignMessage.ProtoReflect.Descriptor instead. +func (*EthereumSignMessage) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{7} +} -func (m *EthereumSignMessage) GetAddressN() []uint32 { - if m != nil { - return m.AddressN +func (x *EthereumSignMessage) GetAddressN() []uint32 { + if x != nil { + return x.AddressN } return nil } -func (m *EthereumSignMessage) GetMessage() []byte { - if m != nil { - return m.Message +func (x *EthereumSignMessage) GetMessage() []byte { + if x != nil { + return x.Message } return nil } @@ -518,56 +585,64 @@ func (m *EthereumSignMessage) GetMessage() []byte { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` // address used to sign the message (20 bytes, legacy firmware) + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` // signature of the message + AddressHex *string `protobuf:"bytes,3,opt,name=addressHex" json:"addressHex,omitempty"` // address used to sign the message (hex string, newer firmware) } -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 (x *EthereumMessageSignature) Reset() { + *x = EthereumMessageSignature{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumMessageSignature) XXX_Size() int { - return xxx_messageInfo_EthereumMessageSignature.Size(m) + +func (x *EthereumMessageSignature) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumMessageSignature) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumMessageSignature.DiscardUnknown(m) + +func (*EthereumMessageSignature) ProtoMessage() {} + +func (x *EthereumMessageSignature) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumMessageSignature proto.InternalMessageInfo +// Deprecated: Use EthereumMessageSignature.ProtoReflect.Descriptor instead. +func (*EthereumMessageSignature) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{8} +} -func (m *EthereumMessageSignature) GetAddressBin() []byte { - if m != nil { - return m.AddressBin +func (x *EthereumMessageSignature) GetAddressBin() []byte { + if x != nil { + return x.AddressBin } return nil } -func (m *EthereumMessageSignature) GetSignature() []byte { - if m != nil { - return m.Signature +func (x *EthereumMessageSignature) GetSignature() []byte { + if x != nil { + return x.Signature } return nil } -func (m *EthereumMessageSignature) GetAddressHex() string { - if m != nil && m.AddressHex != nil { - return *m.AddressHex +func (x *EthereumMessageSignature) GetAddressHex() string { + if x != nil && x.AddressHex != nil { + return *x.AddressHex } return "" } @@ -578,121 +653,350 @@ func (m *EthereumMessageSignature) GetAddressHex() string { // @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} -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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) + AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` // address to verify (20 bytes, legacy firmware) + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` // signature to verify + Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` // message to verify + AddressHex *string `protobuf:"bytes,4,opt,name=addressHex" json:"addressHex,omitempty"` // address to verify (hex string, newer firmware) } -func (m *EthereumVerifyMessage) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumVerifyMessage.Merge(m, src) + +func (x *EthereumVerifyMessage) Reset() { + *x = EthereumVerifyMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EthereumVerifyMessage) XXX_Size() int { - return xxx_messageInfo_EthereumVerifyMessage.Size(m) + +func (x *EthereumVerifyMessage) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EthereumVerifyMessage) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumVerifyMessage.DiscardUnknown(m) + +func (*EthereumVerifyMessage) ProtoMessage() {} + +func (x *EthereumVerifyMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EthereumVerifyMessage proto.InternalMessageInfo +// Deprecated: Use EthereumVerifyMessage.ProtoReflect.Descriptor instead. +func (*EthereumVerifyMessage) Descriptor() ([]byte, []int) { + return file_messages_ethereum_proto_rawDescGZIP(), []int{9} +} -func (m *EthereumVerifyMessage) GetAddressBin() []byte { - if m != nil { - return m.AddressBin +func (x *EthereumVerifyMessage) GetAddressBin() []byte { + if x != nil { + return x.AddressBin } return nil } -func (m *EthereumVerifyMessage) GetSignature() []byte { - if m != nil { - return m.Signature +func (x *EthereumVerifyMessage) GetSignature() []byte { + if x != nil { + return x.Signature } return nil } -func (m *EthereumVerifyMessage) GetMessage() []byte { - if m != nil { - return m.Message +func (x *EthereumVerifyMessage) GetMessage() []byte { + if x != nil { + return x.Message } return nil } -func (m *EthereumVerifyMessage) GetAddressHex() string { - if m != nil && m.AddressHex != nil { - return *m.AddressHex +func (x *EthereumVerifyMessage) GetAddressHex() string { + if x != nil && x.AddressHex != nil { + return *x.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, +var File_messages_ethereum_proto protoreflect.FileDescriptor + +var file_messages_ethereum_proto_rawDesc = []byte{ + 0x0a, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2d, 0x65, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x75, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x68, 0x77, 0x2e, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x65, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x1a, 0x15, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, + 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x56, 0x0a, + 0x14, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x4e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, + 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x68, 0x6f, 0x77, 0x44, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x22, 0x62, 0x0a, 0x11, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, + 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x04, 0x6e, 0x6f, + 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x48, 0x44, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x70, 0x75, 0x62, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x78, 0x70, 0x75, 0x62, 0x22, 0x54, 0x0a, 0x12, 0x45, 0x74, 0x68, + 0x65, 0x72, 0x65, 0x75, 0x6d, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0d, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4e, 0x12, 0x21, 0x0a, 0x0c, + 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0b, 0x73, 0x68, 0x6f, 0x77, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x22, + 0x51, 0x0a, 0x0f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x69, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, + 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, + 0x65, 0x78, 0x22, 0xc2, 0x02, 0x0a, 0x0e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x53, + 0x69, 0x67, 0x6e, 0x54, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x4e, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, + 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x61, 0x73, + 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x42, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x74, 0x6f, 0x42, 0x69, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x48, 0x65, + 0x78, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x48, 0x65, 0x78, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x10, 0x64, 0x61, 0x74, 0x61, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x68, 0x75, + 0x6e, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x17, + 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x06, 0x74, 0x78, 0x54, 0x79, 0x70, 0x65, 0x22, 0x97, 0x01, 0x0a, 0x11, 0x45, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, + 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1f, + 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x76, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x56, 0x12, + 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, + 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x53, 0x22, 0x2e, 0x0a, 0x0d, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x41, + 0x63, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x22, 0x4c, 0x0a, 0x13, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x53, 0x69, 0x67, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x4e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x78, 0x0a, 0x18, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x69, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, 0x22, 0x8f, 0x01, 0x0a, 0x15, 0x45, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x69, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x42, 0x69, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, 0x42, 0x77, 0x0a, 0x23, 0x63, + 0x6f, 0x6d, 0x2e, 0x73, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69, 0x6c, 0x61, 0x62, 0x73, 0x2e, 0x74, + 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x42, 0x15, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, + 0x6f, 0x2d, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x73, 0x2f, 0x75, 0x73, 0x62, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, +} + +var ( + file_messages_ethereum_proto_rawDescOnce sync.Once + file_messages_ethereum_proto_rawDescData = file_messages_ethereum_proto_rawDesc +) + +func file_messages_ethereum_proto_rawDescGZIP() []byte { + file_messages_ethereum_proto_rawDescOnce.Do(func() { + file_messages_ethereum_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_ethereum_proto_rawDescData) + }) + return file_messages_ethereum_proto_rawDescData +} + +var file_messages_ethereum_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_messages_ethereum_proto_goTypes = []interface{}{ + (*EthereumGetPublicKey)(nil), // 0: hw.trezor.messages.ethereum.EthereumGetPublicKey + (*EthereumPublicKey)(nil), // 1: hw.trezor.messages.ethereum.EthereumPublicKey + (*EthereumGetAddress)(nil), // 2: hw.trezor.messages.ethereum.EthereumGetAddress + (*EthereumAddress)(nil), // 3: hw.trezor.messages.ethereum.EthereumAddress + (*EthereumSignTx)(nil), // 4: hw.trezor.messages.ethereum.EthereumSignTx + (*EthereumTxRequest)(nil), // 5: hw.trezor.messages.ethereum.EthereumTxRequest + (*EthereumTxAck)(nil), // 6: hw.trezor.messages.ethereum.EthereumTxAck + (*EthereumSignMessage)(nil), // 7: hw.trezor.messages.ethereum.EthereumSignMessage + (*EthereumMessageSignature)(nil), // 8: hw.trezor.messages.ethereum.EthereumMessageSignature + (*EthereumVerifyMessage)(nil), // 9: hw.trezor.messages.ethereum.EthereumVerifyMessage + (*HDNodeType)(nil), // 10: hw.trezor.messages.common.HDNodeType +} +var file_messages_ethereum_proto_depIdxs = []int32{ + 10, // 0: hw.trezor.messages.ethereum.EthereumPublicKey.node:type_name -> hw.trezor.messages.common.HDNodeType + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_messages_ethereum_proto_init() } +func file_messages_ethereum_proto_init() { + if File_messages_ethereum_proto != nil { + return + } + file_messages_common_proto_init() + if !protoimpl.UnsafeEnabled { + file_messages_ethereum_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumGetPublicKey); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumPublicKey); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumGetAddress); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumAddress); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumSignTx); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumTxRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumTxAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumSignMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumMessageSignature); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumVerifyMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_messages_ethereum_proto_rawDesc, + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_messages_ethereum_proto_goTypes, + DependencyIndexes: file_messages_ethereum_proto_depIdxs, + MessageInfos: file_messages_ethereum_proto_msgTypes, + }.Build() + File_messages_ethereum_proto = out.File + file_messages_ethereum_proto_rawDesc = nil + file_messages_ethereum_proto_goTypes = nil + file_messages_ethereum_proto_depIdxs = nil } diff --git a/accounts/usbwallet/trezor/messages-ethereum.proto b/accounts/usbwallet/trezor/messages-ethereum.proto index 096bed2e4ae1..8e1150abb6b6 100644 --- a/accounts/usbwallet/trezor/messages-ethereum.proto +++ b/accounts/usbwallet/trezor/messages-ethereum.proto @@ -5,6 +5,8 @@ syntax = "proto2"; package hw.trezor.messages.ethereum; +option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"; + // Sugar for easier handling in Java option java_package = "com.satoshilabs.trezor.lib.protobuf"; option java_outer_classname = "TrezorMessageEthereum"; diff --git a/accounts/usbwallet/trezor/messages-management.pb.go b/accounts/usbwallet/trezor/messages-management.pb.go index 91bfca1e3f08..6df4cbdc29da 100644 --- a/accounts/usbwallet/trezor/messages-management.pb.go +++ b/accounts/usbwallet/trezor/messages-management.pb.go @@ -1,25 +1,28 @@ +// 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. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v5.27.1 // source: messages-management.proto package trezor import ( - fmt "fmt" - math "math" - - proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// 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 +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) // * // Structure representing passphrase source @@ -31,17 +34,19 @@ const ( 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, -} +// Enum value maps for ApplySettings_PassphraseSourceType. +var ( + ApplySettings_PassphraseSourceType_name = map[int32]string{ + 0: "ASK", + 1: "DEVICE", + 2: "HOST", + } + ApplySettings_PassphraseSourceType_value = map[string]int32{ + "ASK": 0, + "DEVICE": 1, + "HOST": 2, + } +) func (x ApplySettings_PassphraseSourceType) Enum() *ApplySettings_PassphraseSourceType { p := new(ApplySettings_PassphraseSourceType) @@ -50,20 +55,34 @@ func (x ApplySettings_PassphraseSourceType) Enum() *ApplySettings_PassphraseSour } func (x ApplySettings_PassphraseSourceType) String() string { - return proto.EnumName(ApplySettings_PassphraseSourceType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *ApplySettings_PassphraseSourceType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(ApplySettings_PassphraseSourceType_value, data, "ApplySettings_PassphraseSourceType") +func (ApplySettings_PassphraseSourceType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_management_proto_enumTypes[0].Descriptor() +} + +func (ApplySettings_PassphraseSourceType) Type() protoreflect.EnumType { + return &file_messages_management_proto_enumTypes[0] +} + +func (x ApplySettings_PassphraseSourceType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *ApplySettings_PassphraseSourceType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = ApplySettings_PassphraseSourceType(value) + *x = ApplySettings_PassphraseSourceType(num) return nil } +// Deprecated: Use ApplySettings_PassphraseSourceType.Descriptor instead. func (ApplySettings_PassphraseSourceType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{4, 0} + return file_messages_management_proto_rawDescGZIP(), []int{4, 0} } // * @@ -77,19 +96,21 @@ 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 + RecoveryDevice_RecoveryDeviceType_ScrambledWords RecoveryDevice_RecoveryDeviceType = 0 // words in scrambled order + RecoveryDevice_RecoveryDeviceType_Matrix RecoveryDevice_RecoveryDeviceType = 1 // matrix recovery type ) -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, -} +// Enum value maps for RecoveryDevice_RecoveryDeviceType. +var ( + RecoveryDevice_RecoveryDeviceType_name = map[int32]string{ + 0: "RecoveryDeviceType_ScrambledWords", + 1: "RecoveryDeviceType_Matrix", + } + RecoveryDevice_RecoveryDeviceType_value = map[string]int32{ + "RecoveryDeviceType_ScrambledWords": 0, + "RecoveryDeviceType_Matrix": 1, + } +) func (x RecoveryDevice_RecoveryDeviceType) Enum() *RecoveryDevice_RecoveryDeviceType { p := new(RecoveryDevice_RecoveryDeviceType) @@ -98,20 +119,34 @@ func (x RecoveryDevice_RecoveryDeviceType) Enum() *RecoveryDevice_RecoveryDevice } func (x RecoveryDevice_RecoveryDeviceType) String() string { - return proto.EnumName(RecoveryDevice_RecoveryDeviceType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RecoveryDevice_RecoveryDeviceType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_management_proto_enumTypes[1].Descriptor() +} + +func (RecoveryDevice_RecoveryDeviceType) Type() protoreflect.EnumType { + return &file_messages_management_proto_enumTypes[1] } -func (x *RecoveryDevice_RecoveryDeviceType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(RecoveryDevice_RecoveryDeviceType_value, data, "RecoveryDevice_RecoveryDeviceType") +func (x RecoveryDevice_RecoveryDeviceType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *RecoveryDevice_RecoveryDeviceType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = RecoveryDevice_RecoveryDeviceType(value) + *x = RecoveryDevice_RecoveryDeviceType(num) return nil } +// Deprecated: Use RecoveryDevice_RecoveryDeviceType.Descriptor instead. func (RecoveryDevice_RecoveryDeviceType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{17, 0} + return file_messages_management_proto_rawDescGZIP(), []int{17, 0} } // * @@ -124,17 +159,19 @@ const ( 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, -} +// Enum value maps for WordRequest_WordRequestType. +var ( + WordRequest_WordRequestType_name = map[int32]string{ + 0: "WordRequestType_Plain", + 1: "WordRequestType_Matrix9", + 2: "WordRequestType_Matrix6", + } + 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) @@ -143,20 +180,34 @@ func (x WordRequest_WordRequestType) Enum() *WordRequest_WordRequestType { } func (x WordRequest_WordRequestType) String() string { - return proto.EnumName(WordRequest_WordRequestType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *WordRequest_WordRequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(WordRequest_WordRequestType_value, data, "WordRequest_WordRequestType") +func (WordRequest_WordRequestType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_management_proto_enumTypes[2].Descriptor() +} + +func (WordRequest_WordRequestType) Type() protoreflect.EnumType { + return &file_messages_management_proto_enumTypes[2] +} + +func (x WordRequest_WordRequestType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *WordRequest_WordRequestType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = WordRequest_WordRequestType(value) + *x = WordRequest_WordRequestType(num) return nil } +// Deprecated: Use WordRequest_WordRequestType.Descriptor instead. func (WordRequest_WordRequestType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{18, 0} + return file_messages_management_proto_rawDescGZIP(), []int{18, 0} } // * @@ -164,48 +215,56 @@ func (WordRequest_WordRequestType) EnumDescriptor() ([]byte, []int) { // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + State []byte `protobuf:"bytes,1,opt,name=state" json:"state,omitempty"` // assumed device state, clear session if set and different + SkipPassphrase *bool `protobuf:"varint,2,opt,name=skip_passphrase,json=skipPassphrase" json:"skip_passphrase,omitempty"` // this session should always assume empty passphrase } -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 (x *Initialize) Reset() { + *x = Initialize{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Initialize) XXX_Size() int { - return xxx_messageInfo_Initialize.Size(m) + +func (x *Initialize) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Initialize) XXX_DiscardUnknown() { - xxx_messageInfo_Initialize.DiscardUnknown(m) + +func (*Initialize) ProtoMessage() {} + +func (x *Initialize) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Initialize proto.InternalMessageInfo +// Deprecated: Use Initialize.ProtoReflect.Descriptor instead. +func (*Initialize) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{0} +} -func (m *Initialize) GetState() []byte { - if m != nil { - return m.State +func (x *Initialize) GetState() []byte { + if x != nil { + return x.State } return nil } -func (m *Initialize) GetSkipPassphrase() bool { - if m != nil && m.SkipPassphrase != nil { - return *m.SkipPassphrase +func (x *Initialize) GetSkipPassphrase() bool { + if x != nil && x.SkipPassphrase != nil { + return *x.SkipPassphrase } return false } @@ -215,282 +274,297 @@ func (m *Initialize) GetSkipPassphrase() bool { // @start // @next Features type GetFeatures struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -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 (x *GetFeatures) Reset() { + *x = GetFeatures{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -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 (x *GetFeatures) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *GetFeatures) XXX_DiscardUnknown() { - xxx_messageInfo_GetFeatures.DiscardUnknown(m) + +func (*GetFeatures) ProtoMessage() {} + +func (x *GetFeatures) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_GetFeatures proto.InternalMessageInfo +// Deprecated: Use GetFeatures.ProtoReflect.Descriptor instead. +func (*GetFeatures) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{1} +} // * // 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() {} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Vendor *string `protobuf:"bytes,1,opt,name=vendor" json:"vendor,omitempty"` // name of the manufacturer, e.g. "trezor.io" + MajorVersion *uint32 `protobuf:"varint,2,opt,name=major_version,json=majorVersion" json:"major_version,omitempty"` // major version of the firmware/bootloader, e.g. 1 + MinorVersion *uint32 `protobuf:"varint,3,opt,name=minor_version,json=minorVersion" json:"minor_version,omitempty"` // minor version of the firmware/bootloader, e.g. 0 + PatchVersion *uint32 `protobuf:"varint,4,opt,name=patch_version,json=patchVersion" json:"patch_version,omitempty"` // patch version of the firmware/bootloader, e.g. 0 + BootloaderMode *bool `protobuf:"varint,5,opt,name=bootloader_mode,json=bootloaderMode" json:"bootloader_mode,omitempty"` // is device in bootloader mode? + DeviceId *string `protobuf:"bytes,6,opt,name=device_id,json=deviceId" json:"device_id,omitempty"` // device's unique identifier + PinProtection *bool `protobuf:"varint,7,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` // is device protected by PIN? + PassphraseProtection *bool `protobuf:"varint,8,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // is node/mnemonic encrypted using passphrase? + Language *string `protobuf:"bytes,9,opt,name=language" json:"language,omitempty"` // device language + Label *string `protobuf:"bytes,10,opt,name=label" json:"label,omitempty"` // device description label + Initialized *bool `protobuf:"varint,12,opt,name=initialized" json:"initialized,omitempty"` // does device contain seed? + Revision []byte `protobuf:"bytes,13,opt,name=revision" json:"revision,omitempty"` // SCM revision of firmware + BootloaderHash []byte `protobuf:"bytes,14,opt,name=bootloader_hash,json=bootloaderHash" json:"bootloader_hash,omitempty"` // hash of the bootloader + Imported *bool `protobuf:"varint,15,opt,name=imported" json:"imported,omitempty"` // was storage imported from an external source? + PinCached *bool `protobuf:"varint,16,opt,name=pin_cached,json=pinCached" json:"pin_cached,omitempty"` // is PIN already cached in session? + PassphraseCached *bool `protobuf:"varint,17,opt,name=passphrase_cached,json=passphraseCached" json:"passphrase_cached,omitempty"` // is passphrase already cached in session? + FirmwarePresent *bool `protobuf:"varint,18,opt,name=firmware_present,json=firmwarePresent" json:"firmware_present,omitempty"` // is valid firmware loaded? + NeedsBackup *bool `protobuf:"varint,19,opt,name=needs_backup,json=needsBackup" json:"needs_backup,omitempty"` // does storage need backup? (equals to Storage.needs_backup) + Flags *uint32 `protobuf:"varint,20,opt,name=flags" json:"flags,omitempty"` // device flags (equals to Storage.flags) + Model *string `protobuf:"bytes,21,opt,name=model" json:"model,omitempty"` // device hardware model + FwMajor *uint32 `protobuf:"varint,22,opt,name=fw_major,json=fwMajor" json:"fw_major,omitempty"` // reported firmware version if in bootloader mode + FwMinor *uint32 `protobuf:"varint,23,opt,name=fw_minor,json=fwMinor" json:"fw_minor,omitempty"` // reported firmware version if in bootloader mode + FwPatch *uint32 `protobuf:"varint,24,opt,name=fw_patch,json=fwPatch" json:"fw_patch,omitempty"` // reported firmware version if in bootloader mode + FwVendor *string `protobuf:"bytes,25,opt,name=fw_vendor,json=fwVendor" json:"fw_vendor,omitempty"` // reported firmware vendor if in bootloader mode + FwVendorKeys []byte `protobuf:"bytes,26,opt,name=fw_vendor_keys,json=fwVendorKeys" json:"fw_vendor_keys,omitempty"` // reported firmware vendor keys (their hash) + UnfinishedBackup *bool `protobuf:"varint,27,opt,name=unfinished_backup,json=unfinishedBackup" json:"unfinished_backup,omitempty"` // report unfinished backup (equals to Storage.unfinished_backup) + NoBackup *bool `protobuf:"varint,28,opt,name=no_backup,json=noBackup" json:"no_backup,omitempty"` // report no backup (equals to Storage.no_backup) +} + +func (x *Features) Reset() { + *x = Features{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Features) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Features) ProtoMessage() {} + +func (x *Features) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Features.ProtoReflect.Descriptor instead. 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) + return file_messages_management_proto_rawDescGZIP(), []int{2} } -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 +func (x *Features) GetVendor() string { + if x != nil && x.Vendor != nil { + return *x.Vendor } return "" } -func (m *Features) GetMajorVersion() uint32 { - if m != nil && m.MajorVersion != nil { - return *m.MajorVersion +func (x *Features) GetMajorVersion() uint32 { + if x != nil && x.MajorVersion != nil { + return *x.MajorVersion } return 0 } -func (m *Features) GetMinorVersion() uint32 { - if m != nil && m.MinorVersion != nil { - return *m.MinorVersion +func (x *Features) GetMinorVersion() uint32 { + if x != nil && x.MinorVersion != nil { + return *x.MinorVersion } return 0 } -func (m *Features) GetPatchVersion() uint32 { - if m != nil && m.PatchVersion != nil { - return *m.PatchVersion +func (x *Features) GetPatchVersion() uint32 { + if x != nil && x.PatchVersion != nil { + return *x.PatchVersion } return 0 } -func (m *Features) GetBootloaderMode() bool { - if m != nil && m.BootloaderMode != nil { - return *m.BootloaderMode +func (x *Features) GetBootloaderMode() bool { + if x != nil && x.BootloaderMode != nil { + return *x.BootloaderMode } return false } -func (m *Features) GetDeviceId() string { - if m != nil && m.DeviceId != nil { - return *m.DeviceId +func (x *Features) GetDeviceId() string { + if x != nil && x.DeviceId != nil { + return *x.DeviceId } return "" } -func (m *Features) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection +func (x *Features) GetPinProtection() bool { + if x != nil && x.PinProtection != nil { + return *x.PinProtection } return false } -func (m *Features) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *Features) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } -func (m *Features) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *Features) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return "" } -func (m *Features) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *Features) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *Features) GetInitialized() bool { - if m != nil && m.Initialized != nil { - return *m.Initialized +func (x *Features) GetInitialized() bool { + if x != nil && x.Initialized != nil { + return *x.Initialized } return false } -func (m *Features) GetRevision() []byte { - if m != nil { - return m.Revision +func (x *Features) GetRevision() []byte { + if x != nil { + return x.Revision } return nil } -func (m *Features) GetBootloaderHash() []byte { - if m != nil { - return m.BootloaderHash +func (x *Features) GetBootloaderHash() []byte { + if x != nil { + return x.BootloaderHash } return nil } -func (m *Features) GetImported() bool { - if m != nil && m.Imported != nil { - return *m.Imported +func (x *Features) GetImported() bool { + if x != nil && x.Imported != nil { + return *x.Imported } return false } -func (m *Features) GetPinCached() bool { - if m != nil && m.PinCached != nil { - return *m.PinCached +func (x *Features) GetPinCached() bool { + if x != nil && x.PinCached != nil { + return *x.PinCached } return false } -func (m *Features) GetPassphraseCached() bool { - if m != nil && m.PassphraseCached != nil { - return *m.PassphraseCached +func (x *Features) GetPassphraseCached() bool { + if x != nil && x.PassphraseCached != nil { + return *x.PassphraseCached } return false } -func (m *Features) GetFirmwarePresent() bool { - if m != nil && m.FirmwarePresent != nil { - return *m.FirmwarePresent +func (x *Features) GetFirmwarePresent() bool { + if x != nil && x.FirmwarePresent != nil { + return *x.FirmwarePresent } return false } -func (m *Features) GetNeedsBackup() bool { - if m != nil && m.NeedsBackup != nil { - return *m.NeedsBackup +func (x *Features) GetNeedsBackup() bool { + if x != nil && x.NeedsBackup != nil { + return *x.NeedsBackup } return false } -func (m *Features) GetFlags() uint32 { - if m != nil && m.Flags != nil { - return *m.Flags +func (x *Features) GetFlags() uint32 { + if x != nil && x.Flags != nil { + return *x.Flags } return 0 } -func (m *Features) GetModel() string { - if m != nil && m.Model != nil { - return *m.Model +func (x *Features) GetModel() string { + if x != nil && x.Model != nil { + return *x.Model } return "" } -func (m *Features) GetFwMajor() uint32 { - if m != nil && m.FwMajor != nil { - return *m.FwMajor +func (x *Features) GetFwMajor() uint32 { + if x != nil && x.FwMajor != nil { + return *x.FwMajor } return 0 } -func (m *Features) GetFwMinor() uint32 { - if m != nil && m.FwMinor != nil { - return *m.FwMinor +func (x *Features) GetFwMinor() uint32 { + if x != nil && x.FwMinor != nil { + return *x.FwMinor } return 0 } -func (m *Features) GetFwPatch() uint32 { - if m != nil && m.FwPatch != nil { - return *m.FwPatch +func (x *Features) GetFwPatch() uint32 { + if x != nil && x.FwPatch != nil { + return *x.FwPatch } return 0 } -func (m *Features) GetFwVendor() string { - if m != nil && m.FwVendor != nil { - return *m.FwVendor +func (x *Features) GetFwVendor() string { + if x != nil && x.FwVendor != nil { + return *x.FwVendor } return "" } -func (m *Features) GetFwVendorKeys() []byte { - if m != nil { - return m.FwVendorKeys +func (x *Features) GetFwVendorKeys() []byte { + if x != nil { + return x.FwVendorKeys } return nil } -func (m *Features) GetUnfinishedBackup() bool { - if m != nil && m.UnfinishedBackup != nil { - return *m.UnfinishedBackup +func (x *Features) GetUnfinishedBackup() bool { + if x != nil && x.UnfinishedBackup != nil { + return *x.UnfinishedBackup } return false } -func (m *Features) GetNoBackup() bool { - if m != nil && m.NoBackup != nil { - return *m.NoBackup +func (x *Features) GetNoBackup() bool { + if x != nil && x.NoBackup != nil { + return *x.NoBackup } return false } @@ -500,35 +574,42 @@ func (m *Features) GetNoBackup() bool { // @start // @next Success type ClearSession struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -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 (x *ClearSession) Reset() { + *x = ClearSession{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -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 (x *ClearSession) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ClearSession) XXX_DiscardUnknown() { - xxx_messageInfo_ClearSession.DiscardUnknown(m) + +func (*ClearSession) ProtoMessage() {} + +func (x *ClearSession) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ClearSession proto.InternalMessageInfo +// Deprecated: Use ClearSession.ProtoReflect.Descriptor instead. +func (*ClearSession) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{3} +} // * // Request: change language and/or label of the device @@ -536,88 +617,96 @@ var xxx_messageInfo_ClearSession proto.InternalMessageInfo // @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} -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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) + 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"` // in degrees from North } -func (m *ApplySettings) XXX_Merge(src proto.Message) { - xxx_messageInfo_ApplySettings.Merge(m, src) + +func (x *ApplySettings) Reset() { + *x = ApplySettings{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ApplySettings) XXX_Size() int { - return xxx_messageInfo_ApplySettings.Size(m) + +func (x *ApplySettings) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ApplySettings) XXX_DiscardUnknown() { - xxx_messageInfo_ApplySettings.DiscardUnknown(m) + +func (*ApplySettings) ProtoMessage() {} + +func (x *ApplySettings) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ApplySettings proto.InternalMessageInfo +// Deprecated: Use ApplySettings.ProtoReflect.Descriptor instead. +func (*ApplySettings) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{4} +} -func (m *ApplySettings) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *ApplySettings) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return "" } -func (m *ApplySettings) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *ApplySettings) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *ApplySettings) GetUsePassphrase() bool { - if m != nil && m.UsePassphrase != nil { - return *m.UsePassphrase +func (x *ApplySettings) GetUsePassphrase() bool { + if x != nil && x.UsePassphrase != nil { + return *x.UsePassphrase } return false } -func (m *ApplySettings) GetHomescreen() []byte { - if m != nil { - return m.Homescreen +func (x *ApplySettings) GetHomescreen() []byte { + if x != nil { + return x.Homescreen } return nil } -func (m *ApplySettings) GetPassphraseSource() ApplySettings_PassphraseSourceType { - if m != nil && m.PassphraseSource != nil { - return *m.PassphraseSource +func (x *ApplySettings) GetPassphraseSource() ApplySettings_PassphraseSourceType { + if x != nil && x.PassphraseSource != nil { + return *x.PassphraseSource } return ApplySettings_ASK } -func (m *ApplySettings) GetAutoLockDelayMs() uint32 { - if m != nil && m.AutoLockDelayMs != nil { - return *m.AutoLockDelayMs +func (x *ApplySettings) GetAutoLockDelayMs() uint32 { + if x != nil && x.AutoLockDelayMs != nil { + return *x.AutoLockDelayMs } return 0 } -func (m *ApplySettings) GetDisplayRotation() uint32 { - if m != nil && m.DisplayRotation != nil { - return *m.DisplayRotation +func (x *ApplySettings) GetDisplayRotation() uint32 { + if x != nil && x.DisplayRotation != nil { + return *x.DisplayRotation } return 0 } @@ -628,40 +717,48 @@ func (m *ApplySettings) GetDisplayRotation() uint32 { // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Flags *uint32 `protobuf:"varint,1,opt,name=flags" json:"flags,omitempty"` // bitmask, can only set bits, not unset } -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 (x *ApplyFlags) Reset() { + *x = ApplyFlags{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ApplyFlags) XXX_Size() int { - return xxx_messageInfo_ApplyFlags.Size(m) + +func (x *ApplyFlags) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ApplyFlags) XXX_DiscardUnknown() { - xxx_messageInfo_ApplyFlags.DiscardUnknown(m) + +func (*ApplyFlags) ProtoMessage() {} + +func (x *ApplyFlags) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ApplyFlags proto.InternalMessageInfo +// Deprecated: Use ApplyFlags.ProtoReflect.Descriptor instead. +func (*ApplyFlags) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{5} +} -func (m *ApplyFlags) GetFlags() uint32 { - if m != nil && m.Flags != nil { - return *m.Flags +func (x *ApplyFlags) GetFlags() uint32 { + if x != nil && x.Flags != nil { + return *x.Flags } return 0 } @@ -672,40 +769,48 @@ func (m *ApplyFlags) GetFlags() uint32 { // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Remove *bool `protobuf:"varint,1,opt,name=remove" json:"remove,omitempty"` // is PIN removal requested? } -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 (x *ChangePin) Reset() { + *x = ChangePin{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ChangePin) XXX_Size() int { - return xxx_messageInfo_ChangePin.Size(m) + +func (x *ChangePin) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ChangePin) XXX_DiscardUnknown() { - xxx_messageInfo_ChangePin.DiscardUnknown(m) + +func (*ChangePin) ProtoMessage() {} + +func (x *ChangePin) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ChangePin proto.InternalMessageInfo +// Deprecated: Use ChangePin.ProtoReflect.Descriptor instead. +func (*ChangePin) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{6} +} -func (m *ChangePin) GetRemove() bool { - if m != nil && m.Remove != nil { - return *m.Remove +func (x *ChangePin) GetRemove() bool { + if x != nil && x.Remove != nil { + return *x.Remove } return false } @@ -715,64 +820,72 @@ func (m *ChangePin) GetRemove() bool { // @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} -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *Ping) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Ping.Unmarshal(m, b) + Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` // message to send back in Success message + ButtonProtection *bool `protobuf:"varint,2,opt,name=button_protection,json=buttonProtection" json:"button_protection,omitempty"` // ask for button press + PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` // ask for PIN if set in device + PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // ask for passphrase if set in device } -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 (x *Ping) Reset() { + *x = Ping{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Ping) XXX_Size() int { - return xxx_messageInfo_Ping.Size(m) + +func (x *Ping) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Ping) XXX_DiscardUnknown() { - xxx_messageInfo_Ping.DiscardUnknown(m) + +func (*Ping) ProtoMessage() {} + +func (x *Ping) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Ping proto.InternalMessageInfo +// Deprecated: Use Ping.ProtoReflect.Descriptor instead. +func (*Ping) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{7} +} -func (m *Ping) GetMessage() string { - if m != nil && m.Message != nil { - return *m.Message +func (x *Ping) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message } return "" } -func (m *Ping) GetButtonProtection() bool { - if m != nil && m.ButtonProtection != nil { - return *m.ButtonProtection +func (x *Ping) GetButtonProtection() bool { + if x != nil && x.ButtonProtection != nil { + return *x.ButtonProtection } return false } -func (m *Ping) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection +func (x *Ping) GetPinProtection() bool { + if x != nil && x.PinProtection != nil { + return *x.PinProtection } return false } -func (m *Ping) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *Ping) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } @@ -782,35 +895,42 @@ func (m *Ping) GetPassphraseProtection() bool { // @start // @next Failure type Cancel struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -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 (x *Cancel) Reset() { + *x = Cancel{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Cancel) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Cancel.Unmarshal(m, b) +func (x *Cancel) String() string { + return protoimpl.X.MessageStringOf(x) } -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) + +func (*Cancel) ProtoMessage() {} + +func (x *Cancel) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Cancel proto.InternalMessageInfo +// Deprecated: Use Cancel.ProtoReflect.Descriptor instead. +func (*Cancel) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{8} +} // * // Request: Request a sample of random data generated by hardware RNG. May be used for testing. @@ -818,40 +938,48 @@ var xxx_messageInfo_Cancel proto.InternalMessageInfo // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Size *uint32 `protobuf:"varint,1,req,name=size" json:"size,omitempty"` // size of requested entropy } -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 (x *GetEntropy) Reset() { + *x = GetEntropy{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *GetEntropy) XXX_Size() int { - return xxx_messageInfo_GetEntropy.Size(m) + +func (x *GetEntropy) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *GetEntropy) XXX_DiscardUnknown() { - xxx_messageInfo_GetEntropy.DiscardUnknown(m) + +func (*GetEntropy) ProtoMessage() {} + +func (x *GetEntropy) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_GetEntropy proto.InternalMessageInfo +// Deprecated: Use GetEntropy.ProtoReflect.Descriptor instead. +func (*GetEntropy) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{9} +} -func (m *GetEntropy) GetSize() uint32 { - if m != nil && m.Size != nil { - return *m.Size +func (x *GetEntropy) GetSize() uint32 { + if x != nil && x.Size != nil { + return *x.Size } return 0 } @@ -860,40 +988,48 @@ func (m *GetEntropy) GetSize() uint32 { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Entropy []byte `protobuf:"bytes,1,req,name=entropy" json:"entropy,omitempty"` // chunk of random generated bytes } -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 (x *Entropy) Reset() { + *x = Entropy{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Entropy) XXX_Size() int { - return xxx_messageInfo_Entropy.Size(m) + +func (x *Entropy) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Entropy) XXX_DiscardUnknown() { - xxx_messageInfo_Entropy.DiscardUnknown(m) + +func (*Entropy) ProtoMessage() {} + +func (x *Entropy) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Entropy proto.InternalMessageInfo +// Deprecated: Use Entropy.ProtoReflect.Descriptor instead. +func (*Entropy) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{10} +} -func (m *Entropy) GetEntropy() []byte { - if m != nil { - return m.Entropy +func (x *Entropy) GetEntropy() []byte { + if x != nil { + return x.Entropy } return nil } @@ -904,35 +1040,42 @@ func (m *Entropy) GetEntropy() []byte { // @next Success // @next Failure type WipeDevice struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -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 (x *WipeDevice) Reset() { + *x = WipeDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -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 (x *WipeDevice) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *WipeDevice) XXX_DiscardUnknown() { - xxx_messageInfo_WipeDevice.DiscardUnknown(m) + +func (*WipeDevice) ProtoMessage() {} + +func (x *WipeDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_WipeDevice proto.InternalMessageInfo +// Deprecated: Use WipeDevice.ProtoReflect.Descriptor instead. +func (*WipeDevice) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{11} +} // * // Request: Load seed and related internal settings from the computer @@ -940,98 +1083,109 @@ var xxx_messageInfo_WipeDevice proto.InternalMessageInfo // @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} -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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) + Mnemonic *string `protobuf:"bytes,1,opt,name=mnemonic" json:"mnemonic,omitempty"` // seed encoded as BIP-39 mnemonic (12, 18 or 24 words) + Node *HDNodeType `protobuf:"bytes,2,opt,name=node" json:"node,omitempty"` // BIP-32 node + Pin *string `protobuf:"bytes,3,opt,name=pin" json:"pin,omitempty"` // set PIN protection + PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // enable master node encryption using passphrase + Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` // device language + Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` // device label + SkipChecksum *bool `protobuf:"varint,7,opt,name=skip_checksum,json=skipChecksum" json:"skip_checksum,omitempty"` // do not test mnemonic for valid BIP-39 checksum + U2FCounter *uint32 `protobuf:"varint,8,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` // U2F counter } -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) + +// Default values for LoadDevice fields. +const ( + Default_LoadDevice_Language = string("english") +) + +func (x *LoadDevice) Reset() { + *x = LoadDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *LoadDevice) XXX_DiscardUnknown() { - xxx_messageInfo_LoadDevice.DiscardUnknown(m) + +func (x *LoadDevice) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_LoadDevice proto.InternalMessageInfo +func (*LoadDevice) ProtoMessage() {} -const Default_LoadDevice_Language string = "english" +func (x *LoadDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} -func (m *LoadDevice) GetMnemonic() string { - if m != nil && m.Mnemonic != nil { - return *m.Mnemonic +// Deprecated: Use LoadDevice.ProtoReflect.Descriptor instead. +func (*LoadDevice) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{12} +} + +func (x *LoadDevice) GetMnemonic() string { + if x != nil && x.Mnemonic != nil { + return *x.Mnemonic } return "" } -func (m *LoadDevice) GetNode() *HDNodeType { - if m != nil { - return m.Node +func (x *LoadDevice) GetNode() *HDNodeType { + if x != nil { + return x.Node } return nil } -func (m *LoadDevice) GetPin() string { - if m != nil && m.Pin != nil { - return *m.Pin +func (x *LoadDevice) GetPin() string { + if x != nil && x.Pin != nil { + return *x.Pin } return "" } -func (m *LoadDevice) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *LoadDevice) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } -func (m *LoadDevice) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *LoadDevice) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return Default_LoadDevice_Language } -func (m *LoadDevice) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *LoadDevice) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *LoadDevice) GetSkipChecksum() bool { - if m != nil && m.SkipChecksum != nil { - return *m.SkipChecksum +func (x *LoadDevice) GetSkipChecksum() bool { + if x != nil && x.SkipChecksum != nil { + return *x.SkipChecksum } return false } -func (m *LoadDevice) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter +func (x *LoadDevice) GetU2FCounter() uint32 { + if x != nil && x.U2FCounter != nil { + return *x.U2FCounter } return 0 } @@ -1042,107 +1196,118 @@ func (m *LoadDevice) GetU2FCounter() uint32 { // @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} -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DisplayRandom *bool `protobuf:"varint,1,opt,name=display_random,json=displayRandom" json:"display_random,omitempty"` // display entropy generated by the device before asking for additional entropy + Strength *uint32 `protobuf:"varint,2,opt,name=strength,def=256" json:"strength,omitempty"` // strength of seed in bits + PassphraseProtection *bool `protobuf:"varint,3,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // enable master node encryption using passphrase + PinProtection *bool `protobuf:"varint,4,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` // enable PIN protection + Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` // device language + Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` // device label + U2FCounter *uint32 `protobuf:"varint,7,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` // U2F counter + SkipBackup *bool `protobuf:"varint,8,opt,name=skip_backup,json=skipBackup" json:"skip_backup,omitempty"` // postpone seed backup to BackupDevice workflow + NoBackup *bool `protobuf:"varint,9,opt,name=no_backup,json=noBackup" json:"no_backup,omitempty"` // indicate that no backup is going to be made +} + +// Default values for ResetDevice fields. +const ( + Default_ResetDevice_Strength = uint32(256) + Default_ResetDevice_Language = string("english") +) -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 (x *ResetDevice) Reset() { + *x = ResetDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ResetDevice) XXX_DiscardUnknown() { - xxx_messageInfo_ResetDevice.DiscardUnknown(m) + +func (x *ResetDevice) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_ResetDevice proto.InternalMessageInfo +func (*ResetDevice) ProtoMessage() {} -const Default_ResetDevice_Strength uint32 = 256 -const Default_ResetDevice_Language string = "english" +func (x *ResetDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResetDevice.ProtoReflect.Descriptor instead. +func (*ResetDevice) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{13} +} -func (m *ResetDevice) GetDisplayRandom() bool { - if m != nil && m.DisplayRandom != nil { - return *m.DisplayRandom +func (x *ResetDevice) GetDisplayRandom() bool { + if x != nil && x.DisplayRandom != nil { + return *x.DisplayRandom } return false } -func (m *ResetDevice) GetStrength() uint32 { - if m != nil && m.Strength != nil { - return *m.Strength +func (x *ResetDevice) GetStrength() uint32 { + if x != nil && x.Strength != nil { + return *x.Strength } return Default_ResetDevice_Strength } -func (m *ResetDevice) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *ResetDevice) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } -func (m *ResetDevice) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection +func (x *ResetDevice) GetPinProtection() bool { + if x != nil && x.PinProtection != nil { + return *x.PinProtection } return false } -func (m *ResetDevice) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *ResetDevice) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return Default_ResetDevice_Language } -func (m *ResetDevice) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *ResetDevice) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *ResetDevice) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter +func (x *ResetDevice) GetU2FCounter() uint32 { + if x != nil && x.U2FCounter != nil { + return *x.U2FCounter } return 0 } -func (m *ResetDevice) GetSkipBackup() bool { - if m != nil && m.SkipBackup != nil { - return *m.SkipBackup +func (x *ResetDevice) GetSkipBackup() bool { + if x != nil && x.SkipBackup != nil { + return *x.SkipBackup } return false } -func (m *ResetDevice) GetNoBackup() bool { - if m != nil && m.NoBackup != nil { - return *m.NoBackup +func (x *ResetDevice) GetNoBackup() bool { + if x != nil && x.NoBackup != nil { + return *x.NoBackup } return false } @@ -1152,108 +1317,130 @@ func (m *ResetDevice) GetNoBackup() bool { // @start // @next Success type BackupDevice struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -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 (x *BackupDevice) Reset() { + *x = BackupDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -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 (x *BackupDevice) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *BackupDevice) XXX_Size() int { - return xxx_messageInfo_BackupDevice.Size(m) -} -func (m *BackupDevice) XXX_DiscardUnknown() { - xxx_messageInfo_BackupDevice.DiscardUnknown(m) + +func (*BackupDevice) ProtoMessage() {} + +func (x *BackupDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_BackupDevice proto.InternalMessageInfo +// Deprecated: Use BackupDevice.ProtoReflect.Descriptor instead. +func (*BackupDevice) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{14} +} // * // 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:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -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 (x *EntropyRequest) Reset() { + *x = EntropyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EntropyRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EntropyRequest.Unmarshal(m, b) +func (x *EntropyRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -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) + +func (*EntropyRequest) ProtoMessage() {} + +func (x *EntropyRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EntropyRequest proto.InternalMessageInfo +// Deprecated: Use EntropyRequest.ProtoReflect.Descriptor instead. +func (*EntropyRequest) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{15} +} // * // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Entropy []byte `protobuf:"bytes,1,opt,name=entropy" json:"entropy,omitempty"` // 256 bits (32 bytes) of random data } -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 (x *EntropyAck) Reset() { + *x = EntropyAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EntropyAck) XXX_Size() int { - return xxx_messageInfo_EntropyAck.Size(m) + +func (x *EntropyAck) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EntropyAck) XXX_DiscardUnknown() { - xxx_messageInfo_EntropyAck.DiscardUnknown(m) + +func (*EntropyAck) ProtoMessage() {} + +func (x *EntropyAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EntropyAck proto.InternalMessageInfo +// Deprecated: Use EntropyAck.ProtoReflect.Descriptor instead. +func (*EntropyAck) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{16} +} -func (m *EntropyAck) GetEntropy() []byte { - if m != nil { - return m.Entropy +func (x *EntropyAck) GetEntropy() []byte { + if x != nil { + return x.Entropy } return nil } @@ -1264,107 +1451,118 @@ func (m *EntropyAck) GetEntropy() []byte { // @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"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WordCount *uint32 `protobuf:"varint,1,opt,name=word_count,json=wordCount" json:"word_count,omitempty"` // number of words in BIP-39 mnemonic + PassphraseProtection *bool `protobuf:"varint,2,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // enable master node encryption using passphrase + PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` // enable PIN protection + Language *string `protobuf:"bytes,4,opt,name=language,def=english" json:"language,omitempty"` // device language + Label *string `protobuf:"bytes,5,opt,name=label" json:"label,omitempty"` // device label + EnforceWordlist *bool `protobuf:"varint,6,opt,name=enforce_wordlist,json=enforceWordlist" json:"enforce_wordlist,omitempty"` // enforce BIP-39 wordlist during the process // 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:"-"` + Type *RecoveryDevice_RecoveryDeviceType `protobuf:"varint,8,opt,name=type,enum=hw.trezor.messages.management.RecoveryDevice_RecoveryDeviceType" json:"type,omitempty"` // supported recovery type + U2FCounter *uint32 `protobuf:"varint,9,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` // U2F counter + DryRun *bool `protobuf:"varint,10,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"` // perform dry-run recovery workflow (for safe mnemonic validation) } -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} -} +// Default values for RecoveryDevice fields. +const ( + Default_RecoveryDevice_Language = string("english") +) -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 (x *RecoveryDevice) Reset() { + *x = RecoveryDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *RecoveryDevice) XXX_DiscardUnknown() { - xxx_messageInfo_RecoveryDevice.DiscardUnknown(m) + +func (x *RecoveryDevice) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_RecoveryDevice proto.InternalMessageInfo +func (*RecoveryDevice) ProtoMessage() {} + +func (x *RecoveryDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} -const Default_RecoveryDevice_Language string = "english" +// Deprecated: Use RecoveryDevice.ProtoReflect.Descriptor instead. +func (*RecoveryDevice) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{17} +} -func (m *RecoveryDevice) GetWordCount() uint32 { - if m != nil && m.WordCount != nil { - return *m.WordCount +func (x *RecoveryDevice) GetWordCount() uint32 { + if x != nil && x.WordCount != nil { + return *x.WordCount } return 0 } -func (m *RecoveryDevice) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *RecoveryDevice) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } -func (m *RecoveryDevice) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection +func (x *RecoveryDevice) GetPinProtection() bool { + if x != nil && x.PinProtection != nil { + return *x.PinProtection } return false } -func (m *RecoveryDevice) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *RecoveryDevice) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return Default_RecoveryDevice_Language } -func (m *RecoveryDevice) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *RecoveryDevice) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *RecoveryDevice) GetEnforceWordlist() bool { - if m != nil && m.EnforceWordlist != nil { - return *m.EnforceWordlist +func (x *RecoveryDevice) GetEnforceWordlist() bool { + if x != nil && x.EnforceWordlist != nil { + return *x.EnforceWordlist } return false } -func (m *RecoveryDevice) GetType() RecoveryDevice_RecoveryDeviceType { - if m != nil && m.Type != nil { - return *m.Type +func (x *RecoveryDevice) GetType() RecoveryDevice_RecoveryDeviceType { + if x != nil && x.Type != nil { + return *x.Type } return RecoveryDevice_RecoveryDeviceType_ScrambledWords } -func (m *RecoveryDevice) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter +func (x *RecoveryDevice) GetU2FCounter() uint32 { + if x != nil && x.U2FCounter != nil { + return *x.U2FCounter } return 0 } -func (m *RecoveryDevice) GetDryRun() bool { - if m != nil && m.DryRun != nil { - return *m.DryRun +func (x *RecoveryDevice) GetDryRun() bool { + if x != nil && x.DryRun != nil { + return *x.DryRun } return false } @@ -1374,40 +1572,48 @@ func (m *RecoveryDevice) GetDryRun() bool { // 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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Type *WordRequest_WordRequestType `protobuf:"varint,1,opt,name=type,enum=hw.trezor.messages.management.WordRequest_WordRequestType" json:"type,omitempty"` } -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 (x *WordRequest) Reset() { + *x = WordRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *WordRequest) XXX_Size() int { - return xxx_messageInfo_WordRequest.Size(m) + +func (x *WordRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *WordRequest) XXX_DiscardUnknown() { - xxx_messageInfo_WordRequest.DiscardUnknown(m) + +func (*WordRequest) ProtoMessage() {} + +func (x *WordRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_WordRequest proto.InternalMessageInfo +// Deprecated: Use WordRequest.ProtoReflect.Descriptor instead. +func (*WordRequest) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{18} +} -func (m *WordRequest) GetType() WordRequest_WordRequestType { - if m != nil && m.Type != nil { - return *m.Type +func (x *WordRequest) GetType() WordRequest_WordRequestType { + if x != nil && x.Type != nil { + return *x.Type } return WordRequest_WordRequestType_Plain } @@ -1418,40 +1624,48 @@ func (m *WordRequest) GetType() WordRequest_WordRequestType { // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + Word *string `protobuf:"bytes,1,req,name=word" json:"word,omitempty"` // one word of mnemonic on asked position } -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 (x *WordAck) Reset() { + *x = WordAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *WordAck) XXX_Size() int { - return xxx_messageInfo_WordAck.Size(m) + +func (x *WordAck) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *WordAck) XXX_DiscardUnknown() { - xxx_messageInfo_WordAck.DiscardUnknown(m) + +func (*WordAck) ProtoMessage() {} + +func (x *WordAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_WordAck proto.InternalMessageInfo +// Deprecated: Use WordAck.ProtoReflect.Descriptor instead. +func (*WordAck) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{19} +} -func (m *WordAck) GetWord() string { - if m != nil && m.Word != nil { - return *m.Word +func (x *WordAck) GetWord() string { + if x != nil && x.Word != nil { + return *x.Word } return "" } @@ -1461,161 +1675,602 @@ func (m *WordAck) GetWord() string { // @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:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -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} + U2FCounter *uint32 `protobuf:"varint,1,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` // counter } -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 (x *SetU2FCounter) Reset() { + *x = SetU2FCounter{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *SetU2FCounter) XXX_Size() int { - return xxx_messageInfo_SetU2FCounter.Size(m) + +func (x *SetU2FCounter) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *SetU2FCounter) XXX_DiscardUnknown() { - xxx_messageInfo_SetU2FCounter.DiscardUnknown(m) + +func (*SetU2FCounter) ProtoMessage() {} + +func (x *SetU2FCounter) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_SetU2FCounter proto.InternalMessageInfo +// Deprecated: Use SetU2FCounter.ProtoReflect.Descriptor instead. +func (*SetU2FCounter) Descriptor() ([]byte, []int) { + return file_messages_management_proto_rawDescGZIP(), []int{20} +} -func (m *SetU2FCounter) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter +func (x *SetU2FCounter) GetU2FCounter() uint32 { + if x != nil && x.U2FCounter != nil { + return *x.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, +var File_messages_management_proto protoreflect.FileDescriptor + +var file_messages_management_proto_rawDesc = []byte{ + 0x0a, 0x19, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x68, 0x77, 0x2e, + 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x15, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x4b, 0x0a, 0x0a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x70, 0x61, + 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, + 0x73, 0x6b, 0x69, 0x70, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x22, 0x0d, + 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x8c, 0x07, + 0x0a, 0x08, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, + 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x61, 0x6a, 0x6f, 0x72, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x6f, 0x72, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, + 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, + 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x70, 0x61, 0x74, 0x63, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x5f, + 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x62, 0x6f, 0x6f, 0x74, + 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x69, 0x6e, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0d, 0x70, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, + 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, + 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, + 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x62, 0x6f, + 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1a, 0x0a, 0x08, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x69, 0x6e, 0x5f, + 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x70, 0x69, + 0x6e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x61, 0x73, 0x73, 0x70, + 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x10, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x43, 0x61, + 0x63, 0x68, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, + 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, + 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, + 0x21, 0x0a, 0x0c, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, + 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x19, + 0x0a, 0x08, 0x66, 0x77, 0x5f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x66, 0x77, 0x4d, 0x61, 0x6a, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x77, 0x5f, + 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x66, 0x77, 0x4d, + 0x69, 0x6e, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x77, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, + 0x18, 0x18, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x66, 0x77, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, + 0x1b, 0x0a, 0x09, 0x66, 0x77, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x19, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x66, 0x77, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x24, 0x0a, 0x0e, + 0x66, 0x77, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x1a, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x66, 0x77, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x4b, 0x65, + 0x79, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x75, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x75, + 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, + 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x1c, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x0e, 0x0a, 0x0c, + 0x43, 0x6c, 0x65, 0x61, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x87, 0x03, 0x0a, + 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, + 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x50, 0x61, 0x73, + 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x6f, 0x6d, 0x65, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x68, 0x6f, 0x6d, + 0x65, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x12, 0x6e, 0x0a, 0x11, 0x70, 0x61, 0x73, 0x73, 0x70, + 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x41, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x2e, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, + 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x5f, + 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x61, 0x75, 0x74, 0x6f, 0x4c, 0x6f, 0x63, 0x6b, 0x44, 0x65, 0x6c, + 0x61, 0x79, 0x4d, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, + 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x35, 0x0a, 0x14, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x53, 0x4b, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, + 0x48, 0x4f, 0x53, 0x54, 0x10, 0x02, 0x22, 0x22, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x46, + 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x23, 0x0a, 0x09, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x50, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, + 0xa9, 0x01, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x62, + 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x25, 0x0a, 0x0e, 0x70, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x70, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, + 0x72, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, + 0x65, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x08, 0x0a, 0x06, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x22, 0x20, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, + 0x6f, 0x70, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x23, 0x0a, 0x07, 0x45, 0x6e, 0x74, 0x72, 0x6f, + 0x70, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x01, 0x20, + 0x02, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x22, 0x0c, 0x0a, 0x0a, + 0x57, 0x69, 0x70, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0xab, 0x02, 0x0a, 0x0a, 0x4c, + 0x6f, 0x61, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6e, 0x65, + 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6e, 0x65, + 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x12, 0x39, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x48, 0x44, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, + 0x69, 0x6e, 0x12, 0x33, 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x14, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x50, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, + 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x3a, 0x07, 0x65, 0x6e, 0x67, 0x6c, 0x69, + 0x73, 0x68, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, + 0x73, 0x75, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x32, 0x66, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x75, 0x32, + 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, 0xcb, 0x02, 0x0a, 0x0b, 0x52, 0x65, 0x73, + 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x70, + 0x6c, 0x61, 0x79, 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0d, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, + 0x1f, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x3a, 0x03, 0x32, 0x35, 0x36, 0x52, 0x08, 0x73, 0x74, 0x72, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x12, 0x33, 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x14, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x70, + 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x08, + 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x3a, 0x07, + 0x65, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x32, 0x66, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x75, 0x32, + 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6b, 0x69, 0x70, + 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, + 0x6b, 0x69, 0x70, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x5f, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x0e, 0x0a, 0x0c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x72, 0x6f, 0x70, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x26, 0x0a, 0x0a, 0x45, 0x6e, 0x74, 0x72, + 0x6f, 0x70, 0x79, 0x41, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, + 0x22, 0xdd, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x33, 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x14, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x50, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x69, 0x6e, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0d, 0x70, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, + 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x3a, 0x07, 0x65, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, + 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x6e, 0x66, + 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x6c, 0x69, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x40, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x32, + 0x66, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0a, 0x75, 0x32, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x64, + 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, + 0x79, 0x52, 0x75, 0x6e, 0x22, 0x5a, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x21, 0x52, 0x65, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x53, 0x63, 0x72, 0x61, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x10, + 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x10, 0x01, + 0x22, 0xc5, 0x01, 0x0a, 0x0b, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x4e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3a, + 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x57, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x57, 0x6f, 0x72, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x66, 0x0a, 0x0f, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x1b, + 0x0a, 0x17, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x39, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x57, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, + 0x61, 0x74, 0x72, 0x69, 0x78, 0x36, 0x10, 0x02, 0x22, 0x1d, 0x0a, 0x07, 0x57, 0x6f, 0x72, 0x64, + 0x41, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x09, 0x52, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x30, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x55, 0x32, + 0x46, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x32, 0x66, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x75, + 0x32, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x42, 0x79, 0x0a, 0x23, 0x63, 0x6f, 0x6d, + 0x2e, 0x73, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69, 0x6c, 0x61, 0x62, 0x73, 0x2e, 0x74, 0x72, 0x65, + 0x7a, 0x6f, 0x72, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x42, 0x17, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, + 0x6f, 0x2d, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x73, 0x2f, 0x75, 0x73, 0x62, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, +} + +var ( + file_messages_management_proto_rawDescOnce sync.Once + file_messages_management_proto_rawDescData = file_messages_management_proto_rawDesc +) + +func file_messages_management_proto_rawDescGZIP() []byte { + file_messages_management_proto_rawDescOnce.Do(func() { + file_messages_management_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_management_proto_rawDescData) + }) + return file_messages_management_proto_rawDescData +} + +var file_messages_management_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_messages_management_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_messages_management_proto_goTypes = []interface{}{ + (ApplySettings_PassphraseSourceType)(0), // 0: hw.trezor.messages.management.ApplySettings.PassphraseSourceType + (RecoveryDevice_RecoveryDeviceType)(0), // 1: hw.trezor.messages.management.RecoveryDevice.RecoveryDeviceType + (WordRequest_WordRequestType)(0), // 2: hw.trezor.messages.management.WordRequest.WordRequestType + (*Initialize)(nil), // 3: hw.trezor.messages.management.Initialize + (*GetFeatures)(nil), // 4: hw.trezor.messages.management.GetFeatures + (*Features)(nil), // 5: hw.trezor.messages.management.Features + (*ClearSession)(nil), // 6: hw.trezor.messages.management.ClearSession + (*ApplySettings)(nil), // 7: hw.trezor.messages.management.ApplySettings + (*ApplyFlags)(nil), // 8: hw.trezor.messages.management.ApplyFlags + (*ChangePin)(nil), // 9: hw.trezor.messages.management.ChangePin + (*Ping)(nil), // 10: hw.trezor.messages.management.Ping + (*Cancel)(nil), // 11: hw.trezor.messages.management.Cancel + (*GetEntropy)(nil), // 12: hw.trezor.messages.management.GetEntropy + (*Entropy)(nil), // 13: hw.trezor.messages.management.Entropy + (*WipeDevice)(nil), // 14: hw.trezor.messages.management.WipeDevice + (*LoadDevice)(nil), // 15: hw.trezor.messages.management.LoadDevice + (*ResetDevice)(nil), // 16: hw.trezor.messages.management.ResetDevice + (*BackupDevice)(nil), // 17: hw.trezor.messages.management.BackupDevice + (*EntropyRequest)(nil), // 18: hw.trezor.messages.management.EntropyRequest + (*EntropyAck)(nil), // 19: hw.trezor.messages.management.EntropyAck + (*RecoveryDevice)(nil), // 20: hw.trezor.messages.management.RecoveryDevice + (*WordRequest)(nil), // 21: hw.trezor.messages.management.WordRequest + (*WordAck)(nil), // 22: hw.trezor.messages.management.WordAck + (*SetU2FCounter)(nil), // 23: hw.trezor.messages.management.SetU2FCounter + (*HDNodeType)(nil), // 24: hw.trezor.messages.common.HDNodeType +} +var file_messages_management_proto_depIdxs = []int32{ + 0, // 0: hw.trezor.messages.management.ApplySettings.passphrase_source:type_name -> hw.trezor.messages.management.ApplySettings.PassphraseSourceType + 24, // 1: hw.trezor.messages.management.LoadDevice.node:type_name -> hw.trezor.messages.common.HDNodeType + 1, // 2: hw.trezor.messages.management.RecoveryDevice.type:type_name -> hw.trezor.messages.management.RecoveryDevice.RecoveryDeviceType + 2, // 3: hw.trezor.messages.management.WordRequest.type:type_name -> hw.trezor.messages.management.WordRequest.WordRequestType + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_messages_management_proto_init() } +func file_messages_management_proto_init() { + if File_messages_management_proto != nil { + return + } + file_messages_common_proto_init() + if !protoimpl.UnsafeEnabled { + file_messages_management_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Initialize); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFeatures); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Features); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClearSession); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplySettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyFlags); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangePin); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Ping); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Cancel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetEntropy); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Entropy); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WipeDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoadDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResetDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BackupDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EntropyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EntropyAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RecoveryDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WordRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WordAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetU2FCounter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_messages_management_proto_rawDesc, + NumEnums: 3, + NumMessages: 21, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_messages_management_proto_goTypes, + DependencyIndexes: file_messages_management_proto_depIdxs, + EnumInfos: file_messages_management_proto_enumTypes, + MessageInfos: file_messages_management_proto_msgTypes, + }.Build() + File_messages_management_proto = out.File + file_messages_management_proto_rawDesc = nil + file_messages_management_proto_goTypes = nil + file_messages_management_proto_depIdxs = nil } diff --git a/accounts/usbwallet/trezor/messages-management.proto b/accounts/usbwallet/trezor/messages-management.proto index 0ab825a1bcca..55eb58983edc 100644 --- a/accounts/usbwallet/trezor/messages-management.proto +++ b/accounts/usbwallet/trezor/messages-management.proto @@ -5,6 +5,8 @@ syntax = "proto2"; package hw.trezor.messages.management; +option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"; + // Sugar for easier handling in Java option java_package = "com.satoshilabs.trezor.lib.protobuf"; option java_outer_classname = "TrezorMessageManagement"; diff --git a/accounts/usbwallet/trezor/messages.pb.go b/accounts/usbwallet/trezor/messages.pb.go index af0c957144d2..3e80d7c9c39d 100644 --- a/accounts/usbwallet/trezor/messages.pb.go +++ b/accounts/usbwallet/trezor/messages.pb.go @@ -1,26 +1,29 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/messages.proto +// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v5.27.1 // source: messages.proto package trezor import ( - fmt "fmt" - math "math" - - proto "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" + sync "sync" ) -// 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 +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) // * // Mapping between TREZOR wire identifier (uint) and a protobuf message @@ -241,397 +244,399 @@ const ( MessageType_MessageType_BinanceSignedTx MessageType = 709 ) -var MessageType_name = map[int32]string{ - 0: "MessageType_Initialize", - 1: "MessageType_Ping", - 2: "MessageType_Success", - 3: "MessageType_Failure", - 4: "MessageType_ChangePin", - 5: "MessageType_WipeDevice", - 9: "MessageType_GetEntropy", - 10: "MessageType_Entropy", - 13: "MessageType_LoadDevice", - 14: "MessageType_ResetDevice", - 17: "MessageType_Features", - 18: "MessageType_PinMatrixRequest", - 19: "MessageType_PinMatrixAck", - 20: "MessageType_Cancel", - 24: "MessageType_ClearSession", - 25: "MessageType_ApplySettings", - 26: "MessageType_ButtonRequest", - 27: "MessageType_ButtonAck", - 28: "MessageType_ApplyFlags", - 34: "MessageType_BackupDevice", - 35: "MessageType_EntropyRequest", - 36: "MessageType_EntropyAck", - 41: "MessageType_PassphraseRequest", - 42: "MessageType_PassphraseAck", - 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", - 53: "MessageType_SignIdentity", - 54: "MessageType_SignedIdentity", - 61: "MessageType_GetECDHSessionKey", - 62: "MessageType_ECDHSessionKey", - 71: "MessageType_CosiCommit", - 72: "MessageType_CosiCommitment", - 73: "MessageType_CosiSign", - 74: "MessageType_CosiSignature", - 100: "MessageType_DebugLinkDecision", - 101: "MessageType_DebugLinkGetState", - 102: "MessageType_DebugLinkState", - 103: "MessageType_DebugLinkStop", - 104: "MessageType_DebugLinkLog", - 110: "MessageType_DebugLinkMemoryRead", - 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_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, -} +// Enum value maps for MessageType. +var ( + MessageType_name = map[int32]string{ + 0: "MessageType_Initialize", + 1: "MessageType_Ping", + 2: "MessageType_Success", + 3: "MessageType_Failure", + 4: "MessageType_ChangePin", + 5: "MessageType_WipeDevice", + 9: "MessageType_GetEntropy", + 10: "MessageType_Entropy", + 13: "MessageType_LoadDevice", + 14: "MessageType_ResetDevice", + 17: "MessageType_Features", + 18: "MessageType_PinMatrixRequest", + 19: "MessageType_PinMatrixAck", + 20: "MessageType_Cancel", + 24: "MessageType_ClearSession", + 25: "MessageType_ApplySettings", + 26: "MessageType_ButtonRequest", + 27: "MessageType_ButtonAck", + 28: "MessageType_ApplyFlags", + 34: "MessageType_BackupDevice", + 35: "MessageType_EntropyRequest", + 36: "MessageType_EntropyAck", + 41: "MessageType_PassphraseRequest", + 42: "MessageType_PassphraseAck", + 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", + 53: "MessageType_SignIdentity", + 54: "MessageType_SignedIdentity", + 61: "MessageType_GetECDHSessionKey", + 62: "MessageType_ECDHSessionKey", + 71: "MessageType_CosiCommit", + 72: "MessageType_CosiCommitment", + 73: "MessageType_CosiSign", + 74: "MessageType_CosiSignature", + 100: "MessageType_DebugLinkDecision", + 101: "MessageType_DebugLinkGetState", + 102: "MessageType_DebugLinkState", + 103: "MessageType_DebugLinkStop", + 104: "MessageType_DebugLinkLog", + 110: "MessageType_DebugLinkMemoryRead", + 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", + } + MessageType_value = map[string]int32{ + "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 { p := new(MessageType) @@ -640,250 +645,722 @@ func (x MessageType) Enum() *MessageType { } func (x MessageType) String() string { - return proto.EnumName(MessageType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (MessageType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_proto_enumTypes[0].Descriptor() } -func (x *MessageType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(MessageType_value, data, "MessageType") +func (MessageType) Type() protoreflect.EnumType { + return &file_messages_proto_enumTypes[0] +} + +func (x MessageType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *MessageType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = MessageType(value) + *x = MessageType(num) return nil } +// Deprecated: Use MessageType.Descriptor instead. func (MessageType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_4dc296cbfe5ffcd5, []int{0} + return file_messages_proto_rawDescGZIP(), []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 file_messages_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50002, + Name: "hw.trezor.messages.wire_in", + Tag: "varint,50002,opt,name=wire_in", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50003, + Name: "hw.trezor.messages.wire_out", + Tag: "varint,50003,opt,name=wire_out", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.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", + }, + { + ExtendedType: (*descriptorpb.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", + }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50006, + Name: "hw.trezor.messages.wire_tiny", + Tag: "varint,50006,opt,name=wire_tiny", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50007, + Name: "hw.trezor.messages.wire_bootloader", + Tag: "varint,50007,opt,name=wire_bootloader", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.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", + }, } -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", -} +// Extension fields to descriptorpb.EnumValueOptions. +var ( + // optional bool wire_in = 50002; + E_WireIn = &file_messages_proto_extTypes[0] // message can be transmitted via wire from PC to TREZOR + // optional bool wire_out = 50003; + E_WireOut = &file_messages_proto_extTypes[1] // message can be transmitted via wire from TREZOR to PC + // optional bool wire_debug_in = 50004; + E_WireDebugIn = &file_messages_proto_extTypes[2] // message can be transmitted via debug wire from PC to TREZOR + // optional bool wire_debug_out = 50005; + E_WireDebugOut = &file_messages_proto_extTypes[3] // message can be transmitted via debug wire from TREZOR to PC + // optional bool wire_tiny = 50006; + E_WireTiny = &file_messages_proto_extTypes[4] // message is handled by TREZOR when the USB stack is in tiny mode + // optional bool wire_bootloader = 50007; + E_WireBootloader = &file_messages_proto_extTypes[5] // message is only handled by TREZOR Bootloader + // optional bool wire_no_fsm = 50008; + E_WireNoFsm = &file_messages_proto_extTypes[6] // message is not handled by TREZOR unless the USB stack is in tiny mode +) -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 File_messages_proto protoreflect.FileDescriptor -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 file_messages_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x12, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2a, 0xb9, 0x3f, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, + 0x10, 0x00, 0x1a, 0x08, 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0x12, 0x1a, 0x0a, 0x10, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x67, + 0x10, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x10, + 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x10, 0x03, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1f, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x69, 0x6e, 0x10, + 0x04, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x57, 0x69, 0x70, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x10, 0x05, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, + 0x6f, 0x70, 0x79, 0x10, 0x09, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6e, 0x74, 0x72, 0x6f, + 0x70, 0x79, 0x10, 0x0a, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x6f, 0x61, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x10, 0x0d, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x52, 0x65, 0x73, 0x65, + 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x10, 0x0e, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, + 0x1e, 0x0a, 0x14, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x46, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x10, 0x11, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, + 0x26, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, + 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, + 0x12, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, + 0x41, 0x63, 0x6b, 0x10, 0x13, 0x1a, 0x0c, 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, + 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x10, 0x14, 0x1a, 0x08, 0x90, 0xb5, 0x18, + 0x01, 0xb0, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x10, 0x18, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x10, 0x19, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, + 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x75, + 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x1a, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x41, 0x63, 0x6b, 0x10, 0x1b, 0x1a, 0x0c, + 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x41, 0x70, 0x70, 0x6c, + 0x79, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x10, 0x1c, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x22, + 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x10, 0x22, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x45, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x10, 0x23, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x41, + 0x63, 0x6b, 0x10, 0x24, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1d, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, + 0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x29, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x41, 0x63, 0x6b, + 0x10, 0x2a, 0x1a, 0x0c, 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, 0xb5, 0x18, 0x01, + 0x12, 0x2c, 0x0a, 0x22, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x4d, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x30, + 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x61, + 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x63, 0x6b, + 0x10, 0x4e, 0x1a, 0x0c, 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, 0xb5, 0x18, 0x01, + 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x10, 0x2d, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x10, 0x2e, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x57, 0x6f, 0x72, 0x64, 0x41, 0x63, 0x6b, + 0x10, 0x2f, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x47, 0x65, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x10, 0x37, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x65, 0x74, 0x55, 0x32, + 0x46, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x10, 0x3f, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, + 0x12, 0x27, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x45, 0x72, 0x61, 0x73, 0x65, 0x10, 0x06, 0x1a, + 0x08, 0x90, 0xb5, 0x18, 0x01, 0xb8, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1a, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, + 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x10, 0x07, 0x1a, 0x08, 0x90, 0xb5, 0x18, 0x01, 0xb8, + 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x10, 0x08, 0x1a, 0x08, 0x98, 0xb5, 0x18, 0x01, 0xb8, 0xb5, 0x18, 0x01, 0x12, 0x22, + 0x0a, 0x14, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x65, + 0x6c, 0x66, 0x54, 0x65, 0x73, 0x74, 0x10, 0x20, 0x1a, 0x08, 0x90, 0xb5, 0x18, 0x01, 0xb8, 0xb5, + 0x18, 0x01, 0x12, 0x22, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0x0b, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1f, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, + 0x0c, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1c, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0x0f, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1f, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x15, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1b, 0x0a, 0x11, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x78, 0x41, 0x63, 0x6b, 0x10, 0x16, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x1d, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x1e, 0x1a, 0x04, + 0x98, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, + 0x26, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x10, 0x27, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x28, 0x1a, 0x04, + 0x98, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x10, 0x17, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1c, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, + 0x65, 0x64, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x10, 0x30, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x22, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x10, 0x35, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x10, 0x36, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1d, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x47, 0x65, 0x74, 0x45, + 0x43, 0x44, 0x48, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0x3d, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x4b, 0x65, 0x79, 0x10, 0x3e, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x6f, 0x73, 0x69, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x10, 0x47, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, + 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x6f, 0x73, + 0x69, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0x48, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x1e, 0x0a, 0x14, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x43, 0x6f, 0x73, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x10, 0x49, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x43, 0x6f, 0x73, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x10, 0x4a, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2f, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, + 0x6b, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x10, 0x64, 0x1a, 0x0c, 0xa0, 0xb5, 0x18, + 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x1d, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, + 0x6e, 0x6b, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x10, 0x65, 0x1a, 0x08, 0xa0, 0xb5, + 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x10, 0x66, 0x1a, 0x04, 0xa8, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, + 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x6f, 0x70, 0x10, 0x67, 0x1a, 0x04, 0xa0, 0xb5, 0x18, + 0x01, 0x12, 0x22, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x4c, 0x6f, 0x67, 0x10, 0x68, 0x1a, + 0x04, 0xa8, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, 0x10, 0x6e, 0x1a, 0x04, 0xa0, 0xb5, 0x18, 0x01, + 0x12, 0x25, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x10, + 0x6f, 0x1a, 0x04, 0xa8, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, + 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x10, 0x70, 0x1a, 0x04, 0xa0, + 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x46, 0x6c, 0x61, 0x73, + 0x68, 0x45, 0x72, 0x61, 0x73, 0x65, 0x10, 0x71, 0x1a, 0x04, 0xa0, 0xb5, 0x18, 0x01, 0x12, 0x2b, + 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x10, 0xc2, 0x03, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x75, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xc3, 0x03, 0x1a, + 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x47, 0x65, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x38, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, + 0x25, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, + 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x39, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x53, 0x69, + 0x67, 0x6e, 0x54, 0x78, 0x10, 0x3a, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1d, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x3b, 0x1a, + 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x41, + 0x63, 0x6b, 0x10, 0x3c, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1f, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x75, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x40, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x21, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x41, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x2e, 0x0a, 0x24, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x42, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, + 0x43, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x10, 0x44, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1f, 0x0a, 0x15, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x53, 0x69, 0x67, 0x6e, + 0x54, 0x78, 0x10, 0x45, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x53, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0x46, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, + 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, + 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x4b, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x4c, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, + 0x72, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x10, 0x73, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x53, 0x69, + 0x67, 0x6e, 0x54, 0x78, 0x10, 0x74, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x18, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0x75, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x25, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4c, 0x69, 0x73, 0x6b, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, + 0x76, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x77, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x10, 0x78, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, + 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0x79, 0x1a, 0x04, + 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x10, 0x7a, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x47, 0x65, + 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x96, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, + 0x01, 0x12, 0x23, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x97, 0x01, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x54, + 0x78, 0x10, 0x98, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x53, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0x99, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x10, 0x9a, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0x9b, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0xca, + 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x54, 0x78, + 0x4f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xcb, 0x01, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x10, 0xcf, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, + 0x6c, 0x61, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xd0, 0x01, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x2d, 0x0a, 0x22, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x70, 0x10, 0xd2, 0x01, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x4f, 0x70, 0x10, 0xd3, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x20, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, + 0x61, 0x72, 0x50, 0x61, 0x74, 0x68, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4f, 0x70, 0x10, + 0xd4, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x4d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x4f, 0x70, 0x10, 0xd5, 0x01, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x32, 0x0a, 0x27, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x4f, 0x70, + 0x10, 0xd6, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x1f, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, + 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4f, 0x70, 0x10, 0xd7, 0x01, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x4f, 0x70, 0x10, 0xd8, 0x01, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x4f, 0x70, 0x10, 0xd9, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2c, + 0x0a, 0x21, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, + 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x65, 0x72, 0x67, + 0x65, 0x4f, 0x70, 0x10, 0xda, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x1f, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, + 0x6c, 0x61, 0x72, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4f, 0x70, 0x10, + 0xdc, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2c, 0x0a, 0x21, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x42, + 0x75, 0x6d, 0x70, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x4f, 0x70, 0x10, 0xdd, 0x01, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x53, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0xe6, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x25, + 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x72, + 0x6f, 0x6e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xfa, 0x01, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x72, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x10, 0xfb, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x16, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x72, 0x6f, 0x6e, 0x53, 0x69, 0x67, + 0x6e, 0x54, 0x78, 0x10, 0xfc, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x18, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x72, 0x6f, 0x6e, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0xfd, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0xaf, + 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x54, 0x78, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xb0, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x2a, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x10, 0xb1, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, + 0x61, 0x6e, 0x6f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xb2, 0x02, 0x1a, + 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x47, 0x65, 0x74, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xb3, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, + 0x25, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, + 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xb4, 0x02, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x54, 0x78, 0x41, + 0x63, 0x6b, 0x10, 0xb5, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, + 0x6e, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0xb6, 0x02, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x47, 0x65, 0x74, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xde, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, + 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, + 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xdf, 0x02, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x47, 0x65, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xe0, 0x02, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x10, 0xe1, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, + 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, + 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, + 0x72, 0x10, 0xe2, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2d, 0x0a, 0x22, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, + 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, + 0x10, 0xe3, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2e, 0x0a, 0x23, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, + 0x79, 0x53, 0x69, 0x67, 0x6e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x4f, 0x6e, 0x67, + 0x10, 0xe4, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, + 0x79, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x4f, + 0x6e, 0x67, 0x10, 0xe5, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, + 0x6f, 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x6e, 0x74, 0x49, 0x64, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x10, 0xe6, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x32, 0x0a, + 0x27, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, + 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x6e, 0x74, 0x49, 0x64, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0xe7, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x35, 0x0a, 0x2a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x6e, 0x74, + 0x49, 0x64, 0x41, 0x64, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x10, + 0xe8, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x37, 0x0a, 0x2c, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x6e, 0x74, 0x49, 0x64, 0x41, 0x64, 0x64, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x10, 0xe9, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x52, 0x69, 0x70, 0x70, 0x6c, 0x65, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x10, 0x90, 0x03, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x52, 0x69, 0x70, 0x70, 0x6c, 0x65, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x91, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x23, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x52, 0x69, 0x70, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0x92, 0x03, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x52, 0x69, 0x70, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x54, 0x78, 0x10, 0x93, 0x03, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x33, 0x0a, 0x28, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, + 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x69, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xf5, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x2f, 0x0a, 0x24, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x6e, 0x69, 0x74, 0x41, 0x63, 0x6b, 0x10, 0xf6, 0x03, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x37, 0x0a, 0x2c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x10, 0xf7, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x33, 0x0a, 0x28, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, + 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x49, + 0x6e, 0x70, 0x75, 0x74, 0x41, 0x63, 0x6b, 0x10, 0xf8, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x40, 0x0a, 0x35, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xf9, 0x03, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x3c, 0x0a, 0x31, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x75, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x6b, 0x10, 0xfa, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x38, 0x0a, 0x2d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x56, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x10, 0xfb, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x56, 0x69, 0x6e, 0x69, 0x41, 0x63, 0x6b, 0x10, 0xfc, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x3b, 0x0a, 0x30, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x41, 0x6c, 0x6c, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x10, 0xfd, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x37, 0x0a, + 0x2c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, + 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, + 0x6c, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x53, 0x65, 0x74, 0x41, 0x63, 0x6b, 0x10, 0xfe, 0x03, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x38, 0x0a, 0x2d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xff, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x63, 0x6b, 0x10, 0x80, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x38, 0x0a, 0x2d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, 0x6c, 0x4f, 0x75, 0x74, 0x53, 0x65, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x81, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x41, 0x6c, 0x6c, 0x4f, 0x75, 0x74, 0x53, 0x65, 0x74, 0x41, 0x63, 0x6b, 0x10, 0x82, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x38, 0x0a, 0x2d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x83, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x41, 0x63, 0x6b, 0x10, 0x84, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x10, 0x85, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, + 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6e, + 0x61, 0x6c, 0x41, 0x63, 0x6b, 0x10, 0x86, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x36, + 0x0a, 0x2b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, + 0x6e, 0x65, 0x72, 0x6f, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x45, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x92, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x32, 0x0a, 0x27, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4b, 0x65, 0x79, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x69, 0x74, 0x41, 0x63, + 0x6b, 0x10, 0x93, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, + 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x65, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x94, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x30, 0x0a, 0x25, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x79, + 0x6e, 0x63, 0x53, 0x74, 0x65, 0x70, 0x41, 0x63, 0x6b, 0x10, 0x95, 0x04, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x35, 0x0a, 0x2a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x53, 0x79, 0x6e, 0x63, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x10, 0x96, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x31, 0x0a, 0x26, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4b, + 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x69, 0x6e, 0x61, 0x6c, + 0x41, 0x63, 0x6b, 0x10, 0x97, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, + 0x72, 0x6f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x9c, 0x04, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x10, 0x9d, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, + 0x6f, 0x47, 0x65, 0x74, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x10, 0x9e, 0x04, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x57, 0x61, 0x74, 0x63, 0x68, + 0x4b, 0x65, 0x79, 0x10, 0x9f, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2d, 0x0a, 0x22, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, + 0x67, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x44, 0x69, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x10, 0xa2, 0x04, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x44, 0x69, 0x61, 0x67, 0x41, 0x63, 0x6b, 0x10, 0xa3, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2c, 0x0a, 0x21, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x47, 0x65, 0x74, 0x54, + 0x78, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xa6, 0x04, 0x1a, 0x04, + 0x90, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x47, 0x65, 0x74, 0x54, 0x78, 0x4b, + 0x65, 0x79, 0x41, 0x63, 0x6b, 0x10, 0xa7, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, + 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, + 0x6e, 0x65, 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xa8, 0x04, 0x1a, 0x04, + 0x90, 0xb5, 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x63, 0x6b, 0x10, 0xa9, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x33, 0x0a, 0x28, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, + 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x65, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x10, 0xaa, 0x04, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2f, 0x0a, 0x24, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, + 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x65, 0x70, + 0x41, 0x63, 0x6b, 0x10, 0xab, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, 0x0a, 0x29, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, + 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x46, 0x69, 0x6e, + 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xac, 0x04, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x66, 0x72, + 0x65, 0x73, 0x68, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x6b, 0x10, 0xad, 0x04, 0x1a, 0x04, + 0x98, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6f, 0x73, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x10, 0xd8, 0x04, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x18, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6f, 0x73, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xd9, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x20, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x45, 0x6f, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0xda, 0x04, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x45, 0x6f, 0x73, 0x54, 0x78, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xdb, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x25, + 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6f, + 0x73, 0x54, 0x78, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x6b, 0x10, 0xdc, 0x04, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6f, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, + 0x10, 0xdd, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, + 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xbc, 0x05, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x10, 0xbd, 0x05, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x1f, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xbe, 0x05, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xbf, 0x05, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, + 0x24, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, + 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0xc0, 0x05, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x78, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xc1, 0x05, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x29, + 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4d, 0x73, 0x67, + 0x10, 0xc2, 0x05, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, + 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x10, 0xc3, 0x05, 0x1a, 0x04, 0x90, 0xb5, 0x18, + 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4d, 0x73, + 0x67, 0x10, 0xc4, 0x05, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0xc5, 0x05, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x3a, 0x3c, 0x0a, 0x07, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x69, 0x6e, 0x12, 0x21, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0xd2, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x77, 0x69, 0x72, 0x65, 0x49, 0x6e, + 0x3a, 0x3e, 0x0a, 0x08, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x12, 0x21, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0xd3, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x77, 0x69, 0x72, 0x65, 0x4f, 0x75, 0x74, + 0x3a, 0x47, 0x0a, 0x0d, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x69, + 0x6e, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd4, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x69, + 0x72, 0x65, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x3a, 0x49, 0x0a, 0x0e, 0x77, 0x69, 0x72, + 0x65, 0x5f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6f, 0x75, 0x74, 0x12, 0x21, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, + 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd5, + 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x77, 0x69, 0x72, 0x65, 0x44, 0x65, 0x62, 0x75, + 0x67, 0x4f, 0x75, 0x74, 0x3a, 0x40, 0x0a, 0x09, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6e, + 0x79, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd6, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x69, + 0x72, 0x65, 0x54, 0x69, 0x6e, 0x79, 0x3a, 0x4c, 0x0a, 0x0f, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x62, + 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd7, 0x86, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x77, 0x69, 0x72, 0x65, 0x42, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, + 0x61, 0x64, 0x65, 0x72, 0x3a, 0x43, 0x0a, 0x0b, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x6e, 0x6f, 0x5f, + 0x66, 0x73, 0x6d, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd8, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x77, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x46, 0x73, 0x6d, 0x42, 0x6f, 0x0a, 0x23, 0x63, 0x6f, 0x6d, + 0x2e, 0x73, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69, 0x6c, 0x61, 0x62, 0x73, 0x2e, 0x74, 0x72, 0x65, + 0x7a, 0x6f, 0x72, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x42, 0x0d, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5a, + 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, + 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x75, 0x73, 0x62, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x2f, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, } -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 ( + file_messages_proto_rawDescOnce sync.Once + file_messages_proto_rawDescData = file_messages_proto_rawDesc +) -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", +func file_messages_proto_rawDescGZIP() []byte { + file_messages_proto_rawDescOnce.Do(func() { + file_messages_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_proto_rawDescData) + }) + return file_messages_proto_rawDescData } -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", +var file_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_messages_proto_goTypes = []interface{}{ + (MessageType)(0), // 0: hw.trezor.messages.MessageType + (*descriptorpb.EnumValueOptions)(nil), // 1: google.protobuf.EnumValueOptions } - -func init() { - 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) +var file_messages_proto_depIdxs = []int32{ + 1, // 0: hw.trezor.messages.wire_in:extendee -> google.protobuf.EnumValueOptions + 1, // 1: hw.trezor.messages.wire_out:extendee -> google.protobuf.EnumValueOptions + 1, // 2: hw.trezor.messages.wire_debug_in:extendee -> google.protobuf.EnumValueOptions + 1, // 3: hw.trezor.messages.wire_debug_out:extendee -> google.protobuf.EnumValueOptions + 1, // 4: hw.trezor.messages.wire_tiny:extendee -> google.protobuf.EnumValueOptions + 1, // 5: hw.trezor.messages.wire_bootloader:extendee -> google.protobuf.EnumValueOptions + 1, // 6: hw.trezor.messages.wire_no_fsm:extendee -> google.protobuf.EnumValueOptions + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 0, // [0:7] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } -func init() { proto.RegisterFile("messages.proto", fileDescriptor_4dc296cbfe5ffcd5) } - -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, +func init() { file_messages_proto_init() } +func file_messages_proto_init() { + if File_messages_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_messages_proto_rawDesc, + NumEnums: 1, + NumMessages: 0, + NumExtensions: 7, + NumServices: 0, + }, + GoTypes: file_messages_proto_goTypes, + DependencyIndexes: file_messages_proto_depIdxs, + EnumInfos: file_messages_proto_enumTypes, + ExtensionInfos: file_messages_proto_extTypes, + }.Build() + File_messages_proto = out.File + file_messages_proto_rawDesc = nil + file_messages_proto_goTypes = nil + file_messages_proto_depIdxs = nil } diff --git a/accounts/usbwallet/trezor/messages.proto b/accounts/usbwallet/trezor/messages.proto index 3e0482e3446f..c232bef60d12 100644 --- a/accounts/usbwallet/trezor/messages.proto +++ b/accounts/usbwallet/trezor/messages.proto @@ -9,10 +9,13 @@ package hw.trezor.messages; * Messages for TREZOR communication */ +option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"; + // Sugar for easier handling in Java option java_package = "com.satoshilabs.trezor.lib.protobuf"; option java_outer_classname = "TrezorMessage"; + import "google/protobuf/descriptor.proto"; /** diff --git a/accounts/usbwallet/trezor/trezor.go b/accounts/usbwallet/trezor/trezor.go index cdca6b4e0b3b..432425831437 100644 --- a/accounts/usbwallet/trezor/trezor.go +++ b/accounts/usbwallet/trezor/trezor.go @@ -42,7 +42,7 @@ // - 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 +//go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto // Package trezor contains the wire protocol. package trezor From 41abab9e39323823ddc4549e1930c8932ffd4c00 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 1 Jul 2024 08:16:15 -0700 Subject: [PATCH 392/571] build: add check for stale generated files (#30037) Co-authored-by: Felix Lange --- .../usbwallet/trezor/messages-common.pb.go | 26 +-- .../usbwallet/trezor/messages-ethereum.pb.go | 24 +-- .../trezor/messages-management.pb.go | 46 ++--- accounts/usbwallet/trezor/messages.pb.go | 4 +- appveyor.yml | 1 + build/checksums.txt | 25 +++ build/ci.go | 174 ++++++++++++++++++ core/tracing/hooks.go | 2 +- internal/build/archive.go | 11 +- 9 files changed, 259 insertions(+), 54 deletions(-) diff --git a/accounts/usbwallet/trezor/messages-common.pb.go b/accounts/usbwallet/trezor/messages-common.pb.go index c5e305960bcb..73800802bb30 100644 --- a/accounts/usbwallet/trezor/messages-common.pb.go +++ b/accounts/usbwallet/trezor/messages-common.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.2 // protoc v5.27.1 // source: messages-common.proto @@ -1010,7 +1010,7 @@ func file_messages_common_proto_rawDescGZIP() []byte { var file_messages_common_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_messages_common_proto_msgTypes = make([]protoimpl.MessageInfo, 11) -var file_messages_common_proto_goTypes = []interface{}{ +var file_messages_common_proto_goTypes = []any{ (Failure_FailureType)(0), // 0: hw.trezor.messages.common.Failure.FailureType (ButtonRequest_ButtonRequestType)(0), // 1: hw.trezor.messages.common.ButtonRequest.ButtonRequestType (PinMatrixRequest_PinMatrixRequestType)(0), // 2: hw.trezor.messages.common.PinMatrixRequest.PinMatrixRequestType @@ -1043,7 +1043,7 @@ func file_messages_common_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_messages_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Success); i { case 0: return &v.state @@ -1055,7 +1055,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Failure); i { case 0: return &v.state @@ -1067,7 +1067,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*ButtonRequest); i { case 0: return &v.state @@ -1079,7 +1079,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*ButtonAck); i { case 0: return &v.state @@ -1091,7 +1091,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*PinMatrixRequest); i { case 0: return &v.state @@ -1103,7 +1103,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*PinMatrixAck); i { case 0: return &v.state @@ -1115,7 +1115,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*PassphraseRequest); i { case 0: return &v.state @@ -1127,7 +1127,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*PassphraseAck); i { case 0: return &v.state @@ -1139,7 +1139,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*PassphraseStateRequest); i { case 0: return &v.state @@ -1151,7 +1151,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*PassphraseStateAck); i { case 0: return &v.state @@ -1163,7 +1163,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*HDNodeType); i { case 0: return &v.state diff --git a/accounts/usbwallet/trezor/messages-ethereum.pb.go b/accounts/usbwallet/trezor/messages-ethereum.pb.go index a080a1c3fe8d..a92123efcdda 100644 --- a/accounts/usbwallet/trezor/messages-ethereum.pb.go +++ b/accounts/usbwallet/trezor/messages-ethereum.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.2 // protoc v5.27.1 // source: messages-ethereum.proto @@ -831,7 +831,7 @@ func file_messages_ethereum_proto_rawDescGZIP() []byte { } var file_messages_ethereum_proto_msgTypes = make([]protoimpl.MessageInfo, 10) -var file_messages_ethereum_proto_goTypes = []interface{}{ +var file_messages_ethereum_proto_goTypes = []any{ (*EthereumGetPublicKey)(nil), // 0: hw.trezor.messages.ethereum.EthereumGetPublicKey (*EthereumPublicKey)(nil), // 1: hw.trezor.messages.ethereum.EthereumPublicKey (*EthereumGetAddress)(nil), // 2: hw.trezor.messages.ethereum.EthereumGetAddress @@ -860,7 +860,7 @@ func file_messages_ethereum_proto_init() { } file_messages_common_proto_init() if !protoimpl.UnsafeEnabled { - file_messages_ethereum_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*EthereumGetPublicKey); i { case 0: return &v.state @@ -872,7 +872,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*EthereumPublicKey); i { case 0: return &v.state @@ -884,7 +884,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*EthereumGetAddress); i { case 0: return &v.state @@ -896,7 +896,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*EthereumAddress); i { case 0: return &v.state @@ -908,7 +908,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*EthereumSignTx); i { case 0: return &v.state @@ -920,7 +920,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*EthereumTxRequest); i { case 0: return &v.state @@ -932,7 +932,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*EthereumTxAck); i { case 0: return &v.state @@ -944,7 +944,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*EthereumSignMessage); i { case 0: return &v.state @@ -956,7 +956,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*EthereumMessageSignature); i { case 0: return &v.state @@ -968,7 +968,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*EthereumVerifyMessage); i { case 0: return &v.state diff --git a/accounts/usbwallet/trezor/messages-management.pb.go b/accounts/usbwallet/trezor/messages-management.pb.go index 6df4cbdc29da..983e2d281df3 100644 --- a/accounts/usbwallet/trezor/messages-management.pb.go +++ b/accounts/usbwallet/trezor/messages-management.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.2 // protoc v5.27.1 // source: messages-management.proto @@ -1955,7 +1955,7 @@ func file_messages_management_proto_rawDescGZIP() []byte { var file_messages_management_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_messages_management_proto_msgTypes = make([]protoimpl.MessageInfo, 21) -var file_messages_management_proto_goTypes = []interface{}{ +var file_messages_management_proto_goTypes = []any{ (ApplySettings_PassphraseSourceType)(0), // 0: hw.trezor.messages.management.ApplySettings.PassphraseSourceType (RecoveryDevice_RecoveryDeviceType)(0), // 1: hw.trezor.messages.management.RecoveryDevice.RecoveryDeviceType (WordRequest_WordRequestType)(0), // 2: hw.trezor.messages.management.WordRequest.WordRequestType @@ -2001,7 +2001,7 @@ func file_messages_management_proto_init() { } file_messages_common_proto_init() if !protoimpl.UnsafeEnabled { - file_messages_management_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Initialize); i { case 0: return &v.state @@ -2013,7 +2013,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*GetFeatures); i { case 0: return &v.state @@ -2025,7 +2025,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*Features); i { case 0: return &v.state @@ -2037,7 +2037,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*ClearSession); i { case 0: return &v.state @@ -2049,7 +2049,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*ApplySettings); i { case 0: return &v.state @@ -2061,7 +2061,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*ApplyFlags); i { case 0: return &v.state @@ -2073,7 +2073,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*ChangePin); i { case 0: return &v.state @@ -2085,7 +2085,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*Ping); i { case 0: return &v.state @@ -2097,7 +2097,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*Cancel); i { case 0: return &v.state @@ -2109,7 +2109,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*GetEntropy); i { case 0: return &v.state @@ -2121,7 +2121,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*Entropy); i { case 0: return &v.state @@ -2133,7 +2133,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*WipeDevice); i { case 0: return &v.state @@ -2145,7 +2145,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*LoadDevice); i { case 0: return &v.state @@ -2157,7 +2157,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*ResetDevice); i { case 0: return &v.state @@ -2169,7 +2169,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*BackupDevice); i { case 0: return &v.state @@ -2181,7 +2181,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*EntropyRequest); i { case 0: return &v.state @@ -2193,7 +2193,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*EntropyAck); i { case 0: return &v.state @@ -2205,7 +2205,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[17].Exporter = func(v any, i int) any { switch v := v.(*RecoveryDevice); i { case 0: return &v.state @@ -2217,7 +2217,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[18].Exporter = func(v any, i int) any { switch v := v.(*WordRequest); i { case 0: return &v.state @@ -2229,7 +2229,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[19].Exporter = func(v any, i int) any { switch v := v.(*WordAck); i { case 0: return &v.state @@ -2241,7 +2241,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[20].Exporter = func(v any, i int) any { switch v := v.(*SetU2FCounter); i { case 0: return &v.state diff --git a/accounts/usbwallet/trezor/messages.pb.go b/accounts/usbwallet/trezor/messages.pb.go index 3e80d7c9c39d..4518db679e93 100644 --- a/accounts/usbwallet/trezor/messages.pb.go +++ b/accounts/usbwallet/trezor/messages.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.2 // protoc v5.27.1 // source: messages.proto @@ -1320,7 +1320,7 @@ func file_messages_proto_rawDescGZIP() []byte { } var file_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_messages_proto_goTypes = []interface{}{ +var file_messages_proto_goTypes = []any{ (MessageType)(0), // 0: hw.trezor.messages.MessageType (*descriptorpb.EnumValueOptions)(nil), // 1: google.protobuf.EnumValueOptions } diff --git a/appveyor.yml b/appveyor.yml index 41c70491b4eb..92369537cd0e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,6 +24,7 @@ for: - image: Ubuntu build_script: - go run build/ci.go lint + - go run build/ci.go generate -verify - go run build/ci.go install -dlgo test_script: - go run build/ci.go test -dlgo -short diff --git a/build/checksums.txt b/build/checksums.txt index d099e53156e6..c6c96068657f 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -99,3 +99,28 @@ d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.t # version:ppa-builder-2 1.21.9 # https://go.dev/dl/ 58f0c5ced45a0012bce2ff7a9df03e128abcc8818ebabe5027bb92bafe20e421 go1.21.9.src.tar.gz + +# version:protoc 27.1 +# https://github.com/protocolbuffers/protobuf/releases/ +# https://github.com/protocolbuffers/protobuf/releases/download/v27.1/ +8809c2ec85368c6b6e9af161b6771a153aa92670a24adbe46dd34fa02a04df2f protoc-27.1-linux-aarch_64.zip +5d21979a6d27475e810b76b88863d1e784fa01ffb15e511a3ec5bd1924d89426 protoc-27.1-linux-ppcle_64.zip +84d8852750ed186dc4a057a1a86bcac409be5362d6af04770f42367fee6b7bc1 protoc-27.1-linux-s390_64.zip +2f028796ff5741691650e0eea290e61ff2f1c0d87f8d31fe45ef47fd967cef0c protoc-27.1-linux-x86_32.zip +8970e3d8bbd67d53768fe8c2e3971bdd71e51cfe2001ca06dacad17258a7dae3 protoc-27.1-linux-x86_64.zip +03b7af1bf469e7285dc51976ee5fa99412704dbd1c017105114852a37b165c12 protoc-27.1-osx-aarch_64.zip +f14d3973cf13283d07c520ed6f4c12405ad41b9efd18089a1c74897037d742b5 protoc-27.1-osx-universal_binary.zip +8520d944f3a3890fa296a3b3b0d4bb18337337e2526bbbf1b507eeea3c2a1ec4 protoc-27.1-osx-x86_64.zip +6263718ff96547b8392a079f6fdf02a4156f2e8d13cd51649a0d03fb7afa2de8 protoc-27.1-win32.zip +da531c51ccd1290d8d34821f0ce4e219c7fbaa6f9825f5a3fb092a9d03fe6206 protoc-27.1-win64.zip + +# version:protoc-gen-go 1.34.2 +# https://github.com/protocolbuffers/protobuf-go/releases/ +# https://github.com/protocolbuffers/protobuf-go/releases/download/v1.34.2/ +9b48d8f90add02e8e94e14962fed74e7ce2b2d6bda4dd42f1f4fbccf0f766f1a protoc-gen-go.v1.34.2.darwin.amd64.tar.gz +17aca7f948dbb624049030cf841e35895cf34183ba006e721247fdeb95ff2780 protoc-gen-go.v1.34.2.darwin.arm64.tar.gz +a191849433fd489f1d44f37788d762658f3f5fb225f3a85d4ce6ba32666703ed protoc-gen-go.v1.34.2.linux.386.tar.gz +b87bc134dee55576a842141bf0ed27761c635d746780fce5dee038c6dd16554f protoc-gen-go.v1.34.2.linux.amd64.tar.gz +63d400167e75ab9f6690688f6fdc6a9455aa20bc1faa71e32149dbd322f7f198 protoc-gen-go.v1.34.2.linux.arm64.tar.gz +56e7675816db6e62be4f833a51544d5716b8420c462515579e05ca8444ab06ed protoc-gen-go.v1.34.2.windows.386.zip +abafd39612177dd4e9a65207cadd5374a9352d8611e8e040f8462fcfa3010daf protoc-gen-go.v1.34.2.windows.amd64.zip diff --git a/build/ci.go b/build/ci.go index 9a2532f51f31..db5763370431 100644 --- a/build/ci.go +++ b/build/ci.go @@ -39,9 +39,11 @@ package main import ( "bytes" + "crypto/sha256" "encoding/base64" "flag" "fmt" + "io" "log" "os" "os/exec" @@ -169,6 +171,8 @@ func main() { doPurge(os.Args[2:]) case "sanitycheck": doSanityCheck() + case "generate": + doGenerate() default: log.Fatal("unknown command ", os.Args[1]) } @@ -345,6 +349,86 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string { return filepath.Join(cachedir, base) } +// hashSourceFiles iterates all files under the top-level project directory +// computing the hash of each file (excluding files within the tests +// subrepo) +func hashSourceFiles() (map[string]common.Hash, error) { + res := make(map[string]common.Hash) + err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error { + if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) { + return filepath.SkipDir + } + if !d.Type().IsRegular() { + return nil + } + // open the file and hash it + f, err := os.OpenFile(path, os.O_RDONLY, 0666) + if err != nil { + return err + } + hasher := sha256.New() + if _, err := io.Copy(hasher, f); err != nil { + return err + } + res[path] = common.Hash(hasher.Sum(nil)) + return nil + }) + if err != nil { + return nil, err + } + return res, nil +} + +// doGenerate ensures that re-generating generated files does not cause +// any mutations in the source file tree: i.e. all generated files were +// updated and committed. Any stale generated files are updated. +func doGenerate() { + var ( + tc = new(build.GoToolchain) + cachedir = flag.String("cachedir", "./build/cache", "directory for caching binaries.") + verify = flag.Bool("verify", false, "check whether any files are changed by go generate") + ) + + protocPath := downloadProtoc(*cachedir) + protocGenGoPath := downloadProtocGenGo(*cachedir) + + var preHashes map[string]common.Hash + if *verify { + var err error + preHashes, err = hashSourceFiles() + if err != nil { + log.Fatal("failed to compute map of source hashes", "err", err) + } + } + + c := tc.Go("generate", "./...") + pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")} + c.Env = append(c.Env, "PATH="+strings.Join(pathList, string(os.PathListSeparator))) + build.MustRun(c) + + if !*verify { + return + } + // Check if files were changed. + postHashes, err := hashSourceFiles() + if err != nil { + log.Fatal("error computing source tree file hashes", "err", err) + } + updates := []string{} + for path, postHash := range postHashes { + preHash, ok := preHashes[path] + if !ok || preHash != postHash { + updates = append(updates, path) + } + } + for _, updatedFile := range updates { + fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile) + } + if len(updates) != 0 { + log.Fatal("One or more generated files were updated by running 'go generate ./...'") + } +} + // doLint runs golangci-lint on requested packages. func doLint(cmdline []string) { var ( @@ -390,6 +474,96 @@ func downloadLinter(cachedir string) string { return filepath.Join(cachedir, base, "golangci-lint") } +// protocArchiveBaseName returns the name of the protoc archive file for +// the current system, stripped of version and file suffix. +func protocArchiveBaseName() (string, error) { + switch runtime.GOOS + "-" + runtime.GOARCH { + case "windows-amd64": + return "win64", nil + case "windows-386": + return "win32", nil + case "linux-arm64": + return "linux-aarch_64", nil + case "linux-386": + return "linux-x86_32", nil + case "linux-amd64": + return "linux-x86_64", nil + case "darwin-arm64": + return "osx-aarch_64", nil + case "darwin-amd64": + return "osx-x86_64", nil + default: + return "", fmt.Errorf("no prebuilt release of protoc available for this system (os: %s, arch: %s)", runtime.GOOS, runtime.GOARCH) + } +} + +// downloadProtocGenGo downloads protoc-gen-go, which is used by protoc +// in the generate command. It returns the full path of the directory +// containing the 'protoc-gen-go' executable. +func downloadProtocGenGo(cachedir string) string { + csdb := build.MustLoadChecksums("build/checksums.txt") + version, err := build.Version(csdb, "protoc-gen-go") + if err != nil { + log.Fatal(err) + } + baseName := fmt.Sprintf("protoc-gen-go.v%s.%s.%s", version, runtime.GOOS, runtime.GOARCH) + archiveName := baseName + if runtime.GOOS == "windows" { + archiveName += ".zip" + } else { + archiveName += ".tar.gz" + } + + url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf-go/releases/download/v%s/%s", version, archiveName) + + archivePath := path.Join(cachedir, archiveName) + if err := csdb.DownloadFile(url, archivePath); err != nil { + log.Fatal(err) + } + extractDest := filepath.Join(cachedir, baseName) + if err := build.ExtractArchive(archivePath, extractDest); err != nil { + log.Fatal(err) + } + extractDest, err = filepath.Abs(extractDest) + if err != nil { + log.Fatal("error resolving absolute path for protoc", "err", err) + } + return extractDest +} + +// downloadProtoc downloads the prebuilt protoc binary used to lint generated +// files as a CI step. It returns the full path to the directory containing +// the protoc executable. +func downloadProtoc(cachedir string) string { + csdb := build.MustLoadChecksums("build/checksums.txt") + version, err := build.Version(csdb, "protoc") + if err != nil { + log.Fatal(err) + } + baseName, err := protocArchiveBaseName() + if err != nil { + log.Fatal(err) + } + + fileName := fmt.Sprintf("protoc-%s-%s", version, baseName) + archiveFileName := fileName + ".zip" + url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf/releases/download/v%s/%s", version, archiveFileName) + archivePath := filepath.Join(cachedir, archiveFileName) + + if err := csdb.DownloadFile(url, archivePath); err != nil { + log.Fatal(err) + } + extractDest := filepath.Join(cachedir, fileName) + if err := build.ExtractArchive(archivePath, extractDest); err != nil { + log.Fatal(err) + } + extractDest, err = filepath.Abs(extractDest) + if err != nil { + log.Fatal("error resolving absolute path for protoc", "err", err) + } + return extractDest +} + // Release Packaging func doArchive(cmdline []string) { var ( diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index db058e847c0d..aa66dc49ff09 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -199,7 +199,7 @@ type Hooks struct { // for tracing and reporting. type BalanceChangeReason byte -//go:generate stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go +//go:generate go run golang.org/x/tools/cmd/stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go const ( BalanceChangeUnspecified BalanceChangeReason = 0 diff --git a/internal/build/archive.go b/internal/build/archive.go index 5b37c0edfa13..645921c690a7 100644 --- a/internal/build/archive.go +++ b/internal/build/archive.go @@ -272,17 +272,22 @@ func extractFile(arpath string, armode os.FileMode, data io.Reader, dest string) return fmt.Errorf("path %q escapes archive destination", target) } - // Ensure the destination directory exists. + // Remove the preivously-extracted file if it exists + if err := os.RemoveAll(target); err != nil { + return err + } + + // Recreate the destination directory if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { return err } // Copy file data. - file, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, armode) + file, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY, armode) if err != nil { return err } - if _, err := io.Copy(file, data); err != nil { + if _, err = io.Copy(file, data); err != nil { file.Close() os.Remove(target) return err From 09056601d864d83a46e1020d5d919eaaa626df08 Mon Sep 17 00:00:00 2001 From: Hteev Oli Date: Tue, 2 Jul 2024 03:57:04 +0800 Subject: [PATCH 393/571] core/state: fix inconsistent verkle test error messages (#29753) --- core/state/access_events_test.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/state/access_events_test.go b/core/state/access_events_test.go index 705033fe0be3..c8c93accfdfe 100644 --- a/core/state/access_events_test.go +++ b/core/state/access_events_test.go @@ -41,8 +41,8 @@ func TestAccountHeaderGas(t *testing.T) { // Check cold read cost gas := ae.VersionGas(testAddr, false) - if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost) + if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check warm read cost @@ -71,8 +71,8 @@ func TestAccountHeaderGas(t *testing.T) { // Check cold write cost gas = ae.VersionGas(testAddr, true) - if gas != params.WitnessBranchWriteCost+params.WitnessChunkWriteCost { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost) + if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check warm write cost @@ -83,8 +83,8 @@ func TestAccountHeaderGas(t *testing.T) { // Check a write without a read charges both read and write costs gas = ae.BalanceGas(testAddr2, true) - if gas != params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost) + if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check that a write followed by a read charges nothing @@ -113,8 +113,8 @@ func TestContractCreateInitGas(t *testing.T) { // Check cold read cost, without a value gas := ae.ContractCreateInitGas(testAddr, false) - if gas != params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*2+params.WitnessChunkReadCost*2 { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*3) + if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*2; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check warm read cost @@ -131,8 +131,8 @@ func TestMessageCallGas(t *testing.T) { // Check cold read cost, without a value gas := ae.MessageCallGas(testAddr) - if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost*2 { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost*2) + if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost*2; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check that reading the version and code size of the same account does not incur the branch read cost From de366fd2e2e2ee6b93161a245a91e93fc1b1862f Mon Sep 17 00:00:00 2001 From: winniehere Date: Tue, 2 Jul 2024 20:58:15 +0800 Subject: [PATCH 394/571] accounts/abi: embed Go template instead of string literal (#30098) refactor(accounts/abi): use embed pkg to split default template to file --- accounts/abi/bind/source.go.tpl | 487 +++++++++++++++++++++++++++++++ accounts/abi/bind/template.go | 498 +------------------------------- 2 files changed, 495 insertions(+), 490 deletions(-) create mode 100644 accounts/abi/bind/source.go.tpl diff --git a/accounts/abi/bind/source.go.tpl b/accounts/abi/bind/source.go.tpl new file mode 100644 index 000000000000..c84862d03be6 --- /dev/null +++ b/accounts/abi/bind/source.go.tpl @@ -0,0 +1,487 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package {{.Package}} + +import ( + "math/big" + "strings" + "errors" + + 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 ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +{{$structs := .Structs}} +{{range $structs}} + // {{.Name}} is an auto generated low-level Go binding around an user-defined struct. + type {{.Name}} struct { + {{range $field := .Fields}} + {{$field.Name}} {{$field.Type}}{{end}} + } +{{end}} + +{{range $contract := .Contracts}} + // {{.Type}}MetaData contains all meta data concerning the {{.Type}} contract. + var {{.Type}}MetaData = &bind.MetaData{ + ABI: "{{.InputABI}}", + {{if $contract.FuncSigs -}} + Sigs: map[string]string{ + {{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}", + {{end}} + }, + {{end -}} + {{if .InputBin -}} + Bin: "0x{{.InputBin}}", + {{end}} + } + // {{.Type}}ABI is the input ABI used to generate the binding from. + // Deprecated: Use {{.Type}}MetaData.ABI instead. + var {{.Type}}ABI = {{.Type}}MetaData.ABI + + {{if $contract.FuncSigs}} + // Deprecated: Use {{.Type}}MetaData.Sigs instead. + // {{.Type}}FuncSigs maps the 4-byte function signature to its string representation. + var {{.Type}}FuncSigs = {{.Type}}MetaData.Sigs + {{end}} + + {{if .InputBin}} + // {{.Type}}Bin is the compiled bytecode used for deploying new contracts. + // Deprecated: Use {{.Type}}MetaData.Bin instead. + var {{.Type}}Bin = {{.Type}}MetaData.Bin + + // Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it. + func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) { + parsed, err := {{.Type}}MetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + {{range $pattern, $name := .Libraries}} + {{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend) + {{$contract.Type}}Bin = strings.ReplaceAll({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:]) + {{end}} + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}}) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil + } + {{end}} + + // {{.Type}} is an auto generated Go binding around an Ethereum contract. + type {{.Type}} struct { + {{.Type}}Caller // Read-only binding to the contract + {{.Type}}Transactor // Write-only binding to the contract + {{.Type}}Filterer // Log filterer for contract events + } + + // {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract. + type {{.Type}}Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls + } + + // {{.Type}}Transactor is an auto generated write-only Go binding around an Ethereum contract. + type {{.Type}}Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls + } + + // {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events. + type {{.Type}}Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls + } + + // {{.Type}}Session is an auto generated Go binding around an Ethereum contract, + // with pre-set call and transact options. + type {{.Type}}Session struct { + Contract *{{.Type}} // 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 + } + + // {{.Type}}CallerSession is an auto generated read-only Go binding around an Ethereum contract, + // with pre-set call options. + type {{.Type}}CallerSession struct { + Contract *{{.Type}}Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + } + + // {{.Type}}TransactorSession is an auto generated write-only Go binding around an Ethereum contract, + // with pre-set transact options. + type {{.Type}}TransactorSession struct { + Contract *{{.Type}}Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session + } + + // {{.Type}}Raw is an auto generated low-level Go binding around an Ethereum contract. + type {{.Type}}Raw struct { + Contract *{{.Type}} // Generic contract binding to access the raw methods on + } + + // {{.Type}}CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. + type {{.Type}}CallerRaw struct { + Contract *{{.Type}}Caller // Generic read-only contract binding to access the raw methods on + } + + // {{.Type}}TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. + type {{.Type}}TransactorRaw struct { + Contract *{{.Type}}Transactor // Generic write-only contract binding to access the raw methods on + } + + // New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract. + func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) { + contract, err := bind{{.Type}}(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil + } + + // New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract. + func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) { + contract, err := bind{{.Type}}(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &{{.Type}}Caller{contract: contract}, nil + } + + // New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract. + func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) { + contract, err := bind{{.Type}}(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &{{.Type}}Transactor{contract: contract}, nil + } + + // New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract. + func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) { + contract, err := bind{{.Type}}(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &{{.Type}}Filterer{contract: contract}, nil + } + + // bind{{.Type}} binds a generic wrapper to an already deployed contract. + func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := {{.Type}}MetaData.GetAbi() + 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 (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.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 (_{{$contract.Type}} *{{$contract.Type}}Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transfer(opts) + } + + // Transact invokes the (paid) contract method with params as input values. + func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.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 (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _{{$contract.Type}}.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 (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.contract.Transfer(opts) + } + + // Transact invokes the (paid) contract method with params as input values. + func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...) + } + + {{range .Calls}} + // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) { + var out []interface{} + err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) + {{if .Structured}} + outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} }) + if err != nil { + return *outstruct, err + } + {{range $i, $t := .Normalized.Outputs}} + outstruct.{{.Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}} + + return *outstruct, err + {{else}} + if err != nil { + return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err + } + {{range $i, $t := .Normalized.Outputs}} + out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}} + + return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err + {{end}} + } + + // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { + return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) + } + + // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { + return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) + } + {{end}} + + {{range .Transacts}} + // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { + return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) + } + + // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) + } + + // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) + } + {{end}} + + {{if .Fallback}} + // Fallback is a paid mutator transaction binding the contract fallback function. + // + // Solidity: {{.Fallback.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _{{$contract.Type}}.contract.RawTransact(opts, calldata) + } + + // Fallback is a paid mutator transaction binding the contract fallback function. + // + // Solidity: {{.Fallback.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Session) Fallback(calldata []byte) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) + } + + // Fallback is a paid mutator transaction binding the contract fallback function. + // + // Solidity: {{.Fallback.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) + } + {{end}} + + {{if .Receive}} + // Receive is a paid mutator transaction binding the contract receive function. + // + // Solidity: {{.Receive.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _{{$contract.Type}}.contract.RawTransact(opts, nil) // calldata is disallowed for receive function + } + + // Receive is a paid mutator transaction binding the contract receive function. + // + // Solidity: {{.Receive.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Session) Receive() (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) + } + + // Receive is a paid mutator transaction binding the contract receive function. + // + // Solidity: {{.Receive.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Receive() (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) + } + {{end}} + + {{range .Events}} + // {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract. + type {{$contract.Type}}{{.Normalized.Name}}Iterator struct { + Event *{{$contract.Type}}{{.Normalized.Name}} // 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 *{{$contract.Type}}{{.Normalized.Name}}Iterator) 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({{$contract.Type}}{{.Normalized.Name}}) + 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({{$contract.Type}}{{.Normalized.Name}}) + 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 *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error { + return it.fail + } + // Close terminates the iteration process, releasing any pending underlying + // resources. + func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error { + it.sub.Unsubscribe() + return nil + } + + // {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract. + type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}} + {{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}} + Raw types.Log // Blockchain specific contextual infos + } + + // Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) { + {{range .Normalized.Inputs}} + {{if .Indexed}}var {{.Name}}Rule []interface{} + for _, {{.Name}}Item := range {{.Name}} { + {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) + }{{end}}{{end}} + + logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) + if err != nil { + return nil, err + } + return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil + } + + // Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) { + {{range .Normalized.Inputs}} + {{if .Indexed}}var {{.Name}}Rule []interface{} + for _, {{.Name}}Item := range {{.Name}} { + {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) + }{{end}}{{end}} + + logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) + 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({{$contract.Type}}{{.Normalized.Name}}) + if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", 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 + } + + // Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) { + event := new({{$contract.Type}}{{.Normalized.Name}}) + if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil + } + + {{end}} +{{end}} \ No newline at end of file diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go index 95dc13cc188e..4a0062af0a80 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/bind/template.go @@ -16,7 +16,11 @@ package bind -import "github.com/ethereum/go-ethereum/accounts/abi" +import ( + _ "embed" + + "github.com/ethereum/go-ethereum/accounts/abi" +) // tmplData is the data structure required to fill the binding template. type tmplData struct { @@ -80,492 +84,6 @@ var tmplSource = map[Lang]string{ // tmplSourceGo is the Go source template that the generated Go contract binding // is based on. -const tmplSourceGo = ` -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package {{.Package}} - -import ( - "math/big" - "strings" - "errors" - - 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 ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -{{$structs := .Structs}} -{{range $structs}} - // {{.Name}} is an auto generated low-level Go binding around an user-defined struct. - type {{.Name}} struct { - {{range $field := .Fields}} - {{$field.Name}} {{$field.Type}}{{end}} - } -{{end}} - -{{range $contract := .Contracts}} - // {{.Type}}MetaData contains all meta data concerning the {{.Type}} contract. - var {{.Type}}MetaData = &bind.MetaData{ - ABI: "{{.InputABI}}", - {{if $contract.FuncSigs -}} - Sigs: map[string]string{ - {{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}", - {{end}} - }, - {{end -}} - {{if .InputBin -}} - Bin: "0x{{.InputBin}}", - {{end}} - } - // {{.Type}}ABI is the input ABI used to generate the binding from. - // Deprecated: Use {{.Type}}MetaData.ABI instead. - var {{.Type}}ABI = {{.Type}}MetaData.ABI - - {{if $contract.FuncSigs}} - // Deprecated: Use {{.Type}}MetaData.Sigs instead. - // {{.Type}}FuncSigs maps the 4-byte function signature to its string representation. - var {{.Type}}FuncSigs = {{.Type}}MetaData.Sigs - {{end}} - - {{if .InputBin}} - // {{.Type}}Bin is the compiled bytecode used for deploying new contracts. - // Deprecated: Use {{.Type}}MetaData.Bin instead. - var {{.Type}}Bin = {{.Type}}MetaData.Bin - - // Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it. - func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) { - parsed, err := {{.Type}}MetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - {{range $pattern, $name := .Libraries}} - {{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend) - {{$contract.Type}}Bin = strings.ReplaceAll({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:]) - {{end}} - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}}) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil - } - {{end}} - - // {{.Type}} is an auto generated Go binding around an Ethereum contract. - type {{.Type}} struct { - {{.Type}}Caller // Read-only binding to the contract - {{.Type}}Transactor // Write-only binding to the contract - {{.Type}}Filterer // Log filterer for contract events - } - - // {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract. - type {{.Type}}Caller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls - } - - // {{.Type}}Transactor is an auto generated write-only Go binding around an Ethereum contract. - type {{.Type}}Transactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls - } - - // {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events. - type {{.Type}}Filterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls - } - - // {{.Type}}Session is an auto generated Go binding around an Ethereum contract, - // with pre-set call and transact options. - type {{.Type}}Session struct { - Contract *{{.Type}} // 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 - } - - // {{.Type}}CallerSession is an auto generated read-only Go binding around an Ethereum contract, - // with pre-set call options. - type {{.Type}}CallerSession struct { - Contract *{{.Type}}Caller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - } - - // {{.Type}}TransactorSession is an auto generated write-only Go binding around an Ethereum contract, - // with pre-set transact options. - type {{.Type}}TransactorSession struct { - Contract *{{.Type}}Transactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session - } - - // {{.Type}}Raw is an auto generated low-level Go binding around an Ethereum contract. - type {{.Type}}Raw struct { - Contract *{{.Type}} // Generic contract binding to access the raw methods on - } - - // {{.Type}}CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. - type {{.Type}}CallerRaw struct { - Contract *{{.Type}}Caller // Generic read-only contract binding to access the raw methods on - } - - // {{.Type}}TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. - type {{.Type}}TransactorRaw struct { - Contract *{{.Type}}Transactor // Generic write-only contract binding to access the raw methods on - } - - // New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) { - contract, err := bind{{.Type}}(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil - } - - // New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) { - contract, err := bind{{.Type}}(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &{{.Type}}Caller{contract: contract}, nil - } - - // New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) { - contract, err := bind{{.Type}}(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &{{.Type}}Transactor{contract: contract}, nil - } - - // New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) { - contract, err := bind{{.Type}}(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &{{.Type}}Filterer{contract: contract}, nil - } - - // bind{{.Type}} binds a generic wrapper to an already deployed contract. - func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := {{.Type}}MetaData.GetAbi() - 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 (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.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 (_{{$contract.Type}} *{{$contract.Type}}Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transfer(opts) - } - - // Transact invokes the (paid) contract method with params as input values. - func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.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 (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _{{$contract.Type}}.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 (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.contract.Transfer(opts) - } - - // Transact invokes the (paid) contract method with params as input values. - func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...) - } - - {{range .Calls}} - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) { - var out []interface{} - err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - {{if .Structured}} - outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} }) - if err != nil { - return *outstruct, err - } - {{range $i, $t := .Normalized.Outputs}} - outstruct.{{.Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}} - - return *outstruct, err - {{else}} - if err != nil { - return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err - } - {{range $i, $t := .Normalized.Outputs}} - out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}} - - return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err - {{end}} - } - - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - } - - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - } - {{end}} - - {{range .Transacts}} - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { - return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - } - - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) - } - - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) - } - {{end}} - - {{if .Fallback}} - // Fallback is a paid mutator transaction binding the contract fallback function. - // - // Solidity: {{.Fallback.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { - return _{{$contract.Type}}.contract.RawTransact(opts, calldata) - } - - // Fallback is a paid mutator transaction binding the contract fallback function. - // - // Solidity: {{.Fallback.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) Fallback(calldata []byte) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) - } - - // Fallback is a paid mutator transaction binding the contract fallback function. - // - // Solidity: {{.Fallback.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) - } - {{end}} - - {{if .Receive}} - // Receive is a paid mutator transaction binding the contract receive function. - // - // Solidity: {{.Receive.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { - return _{{$contract.Type}}.contract.RawTransact(opts, nil) // calldata is disallowed for receive function - } - - // Receive is a paid mutator transaction binding the contract receive function. - // - // Solidity: {{.Receive.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) Receive() (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) - } - - // Receive is a paid mutator transaction binding the contract receive function. - // - // Solidity: {{.Receive.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Receive() (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) - } - {{end}} - - {{range .Events}} - // {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract. - type {{$contract.Type}}{{.Normalized.Name}}Iterator struct { - Event *{{$contract.Type}}{{.Normalized.Name}} // 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 *{{$contract.Type}}{{.Normalized.Name}}Iterator) 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({{$contract.Type}}{{.Normalized.Name}}) - 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({{$contract.Type}}{{.Normalized.Name}}) - 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 *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error { - return it.fail - } - // Close terminates the iteration process, releasing any pending underlying - // resources. - func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error { - it.sub.Unsubscribe() - return nil - } - - // {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract. - type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}} - {{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}} - Raw types.Log // Blockchain specific contextual infos - } - - // Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) { - {{range .Normalized.Inputs}} - {{if .Indexed}}var {{.Name}}Rule []interface{} - for _, {{.Name}}Item := range {{.Name}} { - {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) - }{{end}}{{end}} - - logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) - if err != nil { - return nil, err - } - return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil - } - - // Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) { - {{range .Normalized.Inputs}} - {{if .Indexed}}var {{.Name}}Rule []interface{} - for _, {{.Name}}Item := range {{.Name}} { - {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) - }{{end}}{{end}} - - logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) - 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({{$contract.Type}}{{.Normalized.Name}}) - if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", 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 - } - - // Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) { - event := new({{$contract.Type}}{{.Normalized.Name}}) - if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil - } - - {{end}} -{{end}} -` +// +//go:embed source.go.tpl +var tmplSourceGo string From 6f2e1cff47cb24897983b1a2a3fffc1186b58d4a Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:58:42 +0200 Subject: [PATCH 395/571] params: release Geth v1.14.6 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 48bca3c5b2fe..cc607ea29c37 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 6 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 640e0f15fd881e44f58e303fa768e10490541764 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:59:41 +0200 Subject: [PATCH 396/571] params: begin v1.14.7 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index cc607ea29c37..a3e841750e23 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 7 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From aadddf3a6e5e889e96859132f115cc44dd2ecfbd Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:58:42 +0200 Subject: [PATCH 397/571] params: release Geth v1.14.6 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 48bca3c5b2fe..cc607ea29c37 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 6 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 2d9d42376436cd275c28056cffd0eb97cb8daed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Wed, 3 Jul 2024 12:11:43 +0200 Subject: [PATCH 398/571] build: upgrade -dlgo version to Go 1.22.5 (#30112) --- build/checksums.txt | 96 ++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index c6c96068657f..15c74559e6ae 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,55 +5,55 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.22.4 +# version:golang 1.22.5 # https://go.dev/dl/ -fed720678e728a7ca30ba8d1ded1caafe27d16028fab0232b8ba8e22008fb784 go1.22.4.src.tar.gz -b9647fa9fc83a0cc5d4f092a19eaeaecf45f063a5aa7d4962fde65aeb7ae6ce1 go1.22.4.aix-ppc64.tar.gz -7788f40f3a46f201df1dc46ca640403eb535d5513fc33449164a90dbd229b761 go1.22.4.darwin-amd64.pkg -c95967f50aa4ace34af0c236cbdb49a9a3e80ee2ad09d85775cb4462a5c19ed3 go1.22.4.darwin-amd64.tar.gz -4036c88faf57a6b096916f1827edcdbf5290a47cc5f59956e88cdd9b1b71088c go1.22.4.darwin-arm64.pkg -242b78dc4c8f3d5435d28a0d2cec9b4c1aa999b601fb8aa59fb4e5a1364bf827 go1.22.4.darwin-arm64.tar.gz -f2fbb51af4719d3616efb482d6ed2b96579b474156f85a7ddc6f126764feec4b go1.22.4.dragonfly-amd64.tar.gz -7c54884bb9f274884651d41e61d1bc12738863ad1497e97ea19ad0e9aa6bf7b5 go1.22.4.freebsd-386.tar.gz -88d44500e1701dd35797619774d6dd51bf60f45a8338b0a82ddc018e4e63fb78 go1.22.4.freebsd-amd64.tar.gz -3d9efe47db142a22679aba46b1772e3900b0d87ae13bd2b3bc80dbf2ac0b2cd6 go1.22.4.freebsd-arm.tar.gz -726dc093cf020277be45debf03c3b02b43c2efb3e2a5d4fba8f52579d65327dc go1.22.4.freebsd-arm64.tar.gz -5f6b67e5e32f1d6ccb2d4dcb44934a5e2e870a877ba7443d86ec43cfc28afa71 go1.22.4.freebsd-riscv64.tar.gz -d56ecc2f85b6418a21ef83879594d0c42ab4f65391a676bb12254870e6690d63 go1.22.4.illumos-amd64.tar.gz -47a2a8d249a91eb8605c33bceec63aedda0441a43eac47b4721e3975ff916cec go1.22.4.linux-386.tar.gz -ba79d4526102575196273416239cca418a651e049c2b099f3159db85e7bade7d go1.22.4.linux-amd64.tar.gz -a8e177c354d2e4a1b61020aca3562e27ea3e8f8247eca3170e3fa1e0c2f9e771 go1.22.4.linux-arm64.tar.gz -e2b143fbacbc9cbd448e9ef41ac3981f0488ce849af1cf37e2341d09670661de go1.22.4.linux-armv6l.tar.gz -e2ff9436e4b34bf6926b06d97916e26d67a909a2effec17967245900f0816f1d go1.22.4.linux-loong64.tar.gz -73f0dcc60458c4770593b05a7bc01cc0d31fc98f948c0c2334812c7a1f2fc3f1 go1.22.4.linux-mips.tar.gz -417af97fc2630a647052375768be4c38adcc5af946352ea5b28613ea81ca5d45 go1.22.4.linux-mips64.tar.gz -7486e2d7dd8c98eb44df815ace35a7fe7f30b7c02326e3741bd934077508139b go1.22.4.linux-mips64le.tar.gz -69479c8aad301e459a8365b40cad1074a0dbba5defb9291669f94809c4c4be6e go1.22.4.linux-mipsle.tar.gz -dd238847e65bc3e2745caca475a5db6522a2fcf85cf6c38fc36a06642b19efd7 go1.22.4.linux-ppc64.tar.gz -a3e5834657ef92523f570f798fed42f1f87bc18222a16815ec76b84169649ec4 go1.22.4.linux-ppc64le.tar.gz -56a827ff7dc6245bcd7a1e9288dffaa1d8b0fd7468562264c1523daf3b4f1b4a go1.22.4.linux-riscv64.tar.gz -7590c3e278e2dc6040aae0a39da3ca1eb2e3921673a7304cc34d588c45889eec go1.22.4.linux-s390x.tar.gz -ddd2eebe34471a2502de6c5dad04ab27c9fc80cbde7a9ad5b3c66ecec4504e1d go1.22.4.netbsd-386.tar.gz -33af79f6f935f6fbacc5d23876450b3567b79348fc065beef8e64081127dd234 go1.22.4.netbsd-amd64.tar.gz -fa3550ebd5375a70b3bcd342b5a71f4bd271dcbbfaf4eabefa2144ab5d8924b6 go1.22.4.netbsd-arm.tar.gz -c9a2971dec9f6d320c6f2b049b2353c6d0a2d35e87b8a4b2d78a2f0d62545f8e go1.22.4.netbsd-arm64.tar.gz -d21af022331bfdc2b5b161d616c3a1a4573d33cf7a30416ee509a8f3641deb47 go1.22.4.openbsd-386.tar.gz -72c0094c43f7e5722ec49c2a3e9dfa7a1123ac43a5f3a63eecf3e3795d3ff0ae go1.22.4.openbsd-amd64.tar.gz -1096831ea3c5ea3ca57d14251d9eda3786889531eb40d7d6775dcaa324d4b065 go1.22.4.openbsd-arm.tar.gz -a7ab8d4e0b02bf06ed144ba42c61c0e93ee00f2b433415dfd4ad4b6e79f31650 go1.22.4.openbsd-arm64.tar.gz -9716327c8a628358798898dc5148c49dbbeb5196bf2cbf088e550721a6e4f60b go1.22.4.openbsd-ppc64.tar.gz -a8dd4503c95c32a502a616ab78870a19889c9325fe9bd31eb16dd69346e4bfa8 go1.22.4.plan9-386.tar.gz -5423a25808d76fe5aca8607a2e5ac5673abf45446b168cb5e9d8519ee9fe39a1 go1.22.4.plan9-amd64.tar.gz -6af939ad583f5c85c09c53728ab7d38c3cc2b39167562d6c18a07c5c6608b370 go1.22.4.plan9-arm.tar.gz -e8cabe69c03085725afdb32a6f9998191a3e55a747b270d835fd05000d56abba go1.22.4.solaris-amd64.tar.gz -5c6446e2ea80bc6a971d2b34446f16e6517e638b0ff8d3ea229228d1931790b0 go1.22.4.windows-386.msi -aca4e2c37278a10f1c70dd0df142f7d66b50334fcee48978d409202d308d6d25 go1.22.4.windows-386.zip -3c21105d7b584759b6e266383b777caf6e87142d304a10b539dbc66ab482bb5f go1.22.4.windows-amd64.msi -26321c4d945a0035d8a5bc4a1965b0df401ff8ceac66ce2daadabf9030419a98 go1.22.4.windows-amd64.zip -c4303f02b864304eb83dd1db0b4ebf9d2ec9d216e7ef44a7657b166a52889c7f go1.22.4.windows-arm.msi -5fcd0671a49cecf39b41021621ee1b6e7aa1370f37122b72e80d4fd4185833b6 go1.22.4.windows-arm.zip -553cc6c460f4e3eb4fad5b897c0bb22cd8bbeb20929f0e3eeb939420320292ce go1.22.4.windows-arm64.msi -8a2daa9ea28cbdafddc6171aefed384f4e5b6e714fb52116fe9ed25a132f37ed go1.22.4.windows-arm64.zip +ac9c723f224969aee624bc34fd34c9e13f2a212d75c71c807de644bb46e112f6 go1.22.5.src.tar.gz +c82ba3403c45a4aa4b84b08244656a51e55b86fb130dcc500f5291d0f3b12222 go1.22.5.aix-ppc64.tar.gz +8a8872b1bac959b3b76f2e3978c46406d22a54a99c83ca55840ca08b4f2960bc go1.22.5.darwin-amd64.pkg +95d9933cdcf45f211243c42c7705c37353cccd99f27eb4d8e2d1bf2f4165cb50 go1.22.5.darwin-amd64.tar.gz +8c943512d1fa4e849f0078b03721df02aac19d8bb872dd17ab3ee7127ae6b732 go1.22.5.darwin-arm64.pkg +4cd1bcb05be03cecb77bccd765785d5ff69d79adf4dd49790471d00c06b41133 go1.22.5.darwin-arm64.tar.gz +1f1f035e968a877cd8ed62adae6edb2feeee62470660b7587ddcb904a3877a21 go1.22.5.dragonfly-amd64.tar.gz +d660698411465531d475ec1c617fdb415df68740f3511138a8d15506665a06f9 go1.22.5.freebsd-386.tar.gz +75f43ef46c2ad46c534ded25d26fba9bef036fc07074dfa45c0b3b90856a8151 go1.22.5.freebsd-amd64.tar.gz +75614714e7e4a4dd721f0eddd6555b3f6afc4c07e59c1b9b769cf663996165f9 go1.22.5.freebsd-arm.tar.gz +1377d0d7233f1b8f4cb8e3456f2e7ed44aca4a95daab79ae09605d34aa967c6b go1.22.5.freebsd-arm64.tar.gz +07baf198587abc05ea789dbe5810a2d6612ad56a51718bbf74de2c93bdbe676a go1.22.5.freebsd-riscv64.tar.gz +c0bd4f0d44252f3ec93ca850a41b167bb868179c7c283f8af9439e73b2654b17 go1.22.5.illumos-amd64.tar.gz +3ea4c78e6fa52978ae1ed2e5927ad17495da440c9fae7787b1ebc1d0572f7f43 go1.22.5.linux-386.tar.gz +904b924d435eaea086515bc63235b192ea441bd8c9b198c507e85009e6e4c7f0 go1.22.5.linux-amd64.tar.gz +8d21325bfcf431be3660527c1a39d3d9ad71535fabdf5041c826e44e31642b5a go1.22.5.linux-arm64.tar.gz +8c4587cf3e63c9aefbcafa92818c4d9d51683af93ea687bf6c7508d6fa36f85e go1.22.5.linux-armv6l.tar.gz +780e2eeb6376a763c564f776eaac6700f33f95e29302faa54b040b19cb1f6fd2 go1.22.5.linux-loong64.tar.gz +f784aa1adfb605da3bfe8cd534b545bddae3eb893e9302f7c2f5d44656b1cae2 go1.22.5.linux-mips.tar.gz +aaa3756571467768388f2ab641a02ff54f98f1684808cda047a7be3026e4b438 go1.22.5.linux-mips64.tar.gz +b7956d925c9ef5a4dc53017feaed2d78dba5d0a1036bad5ea513f1f15ba08fbc go1.22.5.linux-mips64le.tar.gz +7baf605be9b787acd750b6b48a91818a5590ec9289b14aea5696a46b41853888 go1.22.5.linux-mipsle.tar.gz +f09b2a6c1a409662e8e8fe267e1eabeba0a1fd00eb1422fd88297b013803952e go1.22.5.linux-ppc64.tar.gz +5312bb420ac0b59175a58927e70b4660b14ab7319aab54398b6071fabcbfbb09 go1.22.5.linux-ppc64le.tar.gz +f8d0c7d96b336f4133409ff9da7241cfe91e65723c2e8e7c7f9b58a9f9603476 go1.22.5.linux-riscv64.tar.gz +24c6c5c9d515adea5d58ae78388348c97614a0c21ac4d4f4c0dab75e893b0b5d go1.22.5.linux-s390x.tar.gz +39144c62acbaa85e4f1ab57bad8f5b3dc67d6fa24b711ec1fa593f4a0ea1fe91 go1.22.5.netbsd-386.tar.gz +118f79640588eb878529b46cdf56599012da6575f0ac07069ec1e9a8e78ddd0b go1.22.5.netbsd-amd64.tar.gz +d39c2b94ae3fd0a6399e545cbecb673496293075291bd98ef15f24d21625a490 go1.22.5.netbsd-arm.tar.gz +f7fb617d10c39248996521d72370db82d50724fa894089c76ae4298fbbe1fb0b go1.22.5.netbsd-arm64.tar.gz +e0f778a34746587ae7c18e8a24cfaba1b2eaabce75d0ceb470adf576ad1cd90f go1.22.5.openbsd-386.tar.gz +b417311df26ef7ae8b34fcb991519a5c496010561c12386d9469aea03c1bdf0b go1.22.5.openbsd-amd64.tar.gz +e78e8ad05605d530a4f79e55031c7c65f2020a9d442e05d490bd08f0d947a34f go1.22.5.openbsd-arm.tar.gz +8027898948f17742717786ead2ff2e960ee1fc82995d6edbad0050d551710f59 go1.22.5.openbsd-arm64.tar.gz +99c5b81d75bcc0d83d25dedc9535682c42c0e761276c88bcc4db6340344644fd go1.22.5.openbsd-ppc64.tar.gz +30d5dacdee0481f0b8cabb75b706465e2177c3a4a1d1c46293332f4b90a3d199 go1.22.5.plan9-386.tar.gz +65628650cd7665387cfe6fa386c381f4de1ef7b03a12067ae9ccf06d2feaea2c go1.22.5.plan9-amd64.tar.gz +322541cbfc9ae95b48b9eec4eb45df48299784592e23121084f790cf1082787e go1.22.5.plan9-arm.tar.gz +87c590e3eb81fcffa3dc1524c03c2847f0890e95c2a43586e82b56c262eb03d8 go1.22.5.solaris-amd64.tar.gz +3ec89ed822b38f4483977a90913fbe39d0857f0ed16c4642dec1950ddbe8c943 go1.22.5.windows-386.msi +c44fc421075022add78fbf8db38519dd5520a11832749be2189e64b3cf4f02f9 go1.22.5.windows-386.zip +86b0299ab8cb9c44882a9080dac03f7f4d9546f51ed1ba1015599114bcbc66d0 go1.22.5.windows-amd64.msi +59968438b8d90f108fd240d4d2f95b037e59716995f7409e0a322dcb996e9f42 go1.22.5.windows-amd64.zip +013d3b300e6b8f26482d6dd17b02830b83ee63795498bd8c0c9d80bb2c4d6cf7 go1.22.5.windows-arm.msi +8cc860630a84e2dbff3e84280f46a571741f26f8a1819aa4fbcb3164fdd51312 go1.22.5.windows-arm.zip +8f90519d9f305f2caa05d1d4fb0656b50f1bf89d76e194279f480e5a484c891f go1.22.5.windows-arm64.msi +6717d5841162aa8c05f932eb74a643f1310b8a88f80f0830e86d194289734bbf go1.22.5.windows-arm64.zip # version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ From c4b4d05e695c7926baa8f3776f91349d0ef76daf Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 9 Jul 2024 19:19:25 +0800 Subject: [PATCH 399/571] crypto: remove hardcoded value for secp256k1.N (#30126) --- crypto/crypto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/crypto.go b/crypto/crypto.go index 7f7171f730a0..aaa5cc43a2d0 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -45,7 +45,7 @@ const RecoveryIDOffset = 64 const DigestLength = 32 var ( - secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) + secp256k1N = S256().Params().N secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2)) ) From 10467acc713d6f110a56ade5ceaddf4b4cef7044 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 9 Jul 2024 14:17:43 +0200 Subject: [PATCH 400/571] go.mod: update uint256 to 1.3.0 (#30134) --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index b578ec07b556..a757b6705d23 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/hashicorp/go-bexpr v0.1.10 github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 github.com/holiman/bloomfilter/v2 v2.0.3 - github.com/holiman/uint256 v1.2.4 + github.com/holiman/uint256 v1.3.0 github.com/huin/goupnp v1.3.0 github.com/influxdata/influxdb-client-go/v2 v2.4.0 github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c @@ -74,6 +74,7 @@ require ( golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.20.0 + google.golang.org/protobuf v1.33.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -143,7 +144,6 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.24.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index 168637b0ad5f..826f0f674f5a 100644 --- a/go.sum +++ b/go.sum @@ -312,8 +312,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8 github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= -github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= +github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= From 37590b2c5579c36d846c788c70861685b0ea240e Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 9 Jul 2024 08:19:55 -0400 Subject: [PATCH 401/571] eth/catalyst: fix params in failure log (#30131) --- eth/catalyst/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 0efa61587dc9..00cce259c861 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -335,7 +335,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl log.Warn("Final block not available in database", "hash", update.FinalizedBlockHash) return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not available in database")) } else if rawdb.ReadCanonicalHash(api.eth.ChainDb(), finalBlock.NumberU64()) != update.FinalizedBlockHash { - log.Warn("Final block not in canonical chain", "number", block.NumberU64(), "hash", update.HeadBlockHash) + log.Warn("Final block not in canonical chain", "number", finalBlock.NumberU64(), "hash", update.FinalizedBlockHash) return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not in canonical chain")) } // Set the finalized block From 803dc6b664376df8a69aed113b986b08b2c41784 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 11 Jul 2024 09:28:27 +0200 Subject: [PATCH 402/571] core/txpool/blobpool: revert #29989, WLock on Nonce (#30142) --- core/txpool/blobpool/blobpool.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 2fca5c7b3edf..6ff8847a7662 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1598,8 +1598,9 @@ func (p *BlobPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool // Nonce returns the next nonce of an account, with all transactions executable // by the pool already applied on top. func (p *BlobPool) Nonce(addr common.Address) uint64 { - p.lock.RLock() - defer p.lock.RUnlock() + // We need a write lock here, since state.GetNonce might write the cache. + p.lock.Lock() + defer p.lock.Unlock() if txs, ok := p.index[addr]; ok { return txs[len(txs)-1].nonce + 1 From 0aafbb31ab6836c1a3ab3b2c16f31bd833407ff5 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 11 Jul 2024 14:23:27 +0200 Subject: [PATCH 403/571] params: go-ethereum v1.14.7 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index a3e841750e23..c4e1274ad2da 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 7 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 7 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From bcaf3747f8443c6f8042f4f058f74404bb8c0a22 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 11 Jul 2024 14:24:09 +0200 Subject: [PATCH 404/571] params: begin v1.14.8 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index c4e1274ad2da..852f9fd1e185 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 7 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 8 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From cf0378499f1bcae65c093c58cd6ca8225e91b125 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 11 Jul 2024 22:09:24 +0800 Subject: [PATCH 405/571] core/state: fix prefetcher for verkle (#29760) --- core/state/statedb.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index ac82a8e3e3ab..1664a446f4e2 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -907,9 +907,12 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // Now we're about to start to write changes to the trie. The trie is so far // _untouched_. We can check with the prefetcher, if it can give us a trie // which has the same root, but also has some content loaded into it. + // + // Don't check prefetcher if verkle trie has been used. In the context of verkle, + // only a single trie is used for state hashing. Replacing a non-nil verkle tree + // here could result in losing uncommitted changes from storage. start = time.Now() - - if s.prefetcher != nil { + if s.prefetcher != nil && (s.trie == nil || !s.trie.IsVerkle()) { if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil { log.Error("Failed to retrieve account pre-fetcher trie") } else { From a0631f3ebd228eebd8ef809a09cee89bf630e0df Mon Sep 17 00:00:00 2001 From: minh-bq <97180373+minh-bq@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:28:06 +0700 Subject: [PATCH 406/571] core/txpool/blobpool: use nonce from argument instead of tx.Nonce() (#30148) This does not change the behavior here as the nonce in the argument is tx.Nonce(). This commit helps to make the function easier to read and avoid capturing the tx in the function. --- core/txpool/blobpool/blobpool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 6ff8847a7662..cb266fd10a07 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1116,7 +1116,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error { ExistingCost: func(addr common.Address, nonce uint64) *big.Int { next := p.state.GetNonce(addr) if uint64(len(p.index[addr])) > nonce-next { - return p.index[addr][int(tx.Nonce()-next)].costCap.ToBig() + return p.index[addr][int(nonce-next)].costCap.ToBig() } return nil }, From 79d2327771e5a10e363bdd6542c624b8060bac7b Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:05:59 +0200 Subject: [PATCH 407/571] trie: add RollBackAccount function to verkle trees (#30135) --- trie/verkle.go | 51 ++++++++++++++++++++++++++++ trie/verkle_test.go | 82 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/trie/verkle.go b/trie/verkle.go index a457097e9585..fb4d81281cbd 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -199,6 +199,57 @@ func (t *VerkleTrie) DeleteAccount(addr common.Address) error { return nil } +// RollBackAccount removes the account info + code from the tree, unlike DeleteAccount +// that will overwrite it with 0s. The first 64 storage slots are also removed. +func (t *VerkleTrie) RollBackAccount(addr common.Address) error { + var ( + evaluatedAddr = t.cache.Get(addr.Bytes()) + codeSizeKey = utils.CodeSizeKeyWithEvaluatedAddress(evaluatedAddr) + ) + codeSizeBytes, err := t.root.Get(codeSizeKey, t.nodeResolver) + if err != nil { + return fmt.Errorf("rollback: error finding code size: %w", err) + } + if len(codeSizeBytes) == 0 { + return errors.New("rollback: code size is not existent") + } + codeSize := binary.LittleEndian.Uint64(codeSizeBytes) + + // Delete the account header + first 64 slots + first 128 code chunks + key := common.CopyBytes(codeSizeKey) + for i := 0; i < verkle.NodeWidth; i++ { + key[31] = byte(i) + + // this is a workaround to avoid deleting nil leaves, the lib needs to be + // fixed to be able to handle that + v, err := t.root.Get(key, t.nodeResolver) + if err != nil { + return fmt.Errorf("error rolling back account header: %w", err) + } + if len(v) == 0 { + continue + } + _, err = t.root.Delete(key, t.nodeResolver) + if err != nil { + return fmt.Errorf("error rolling back account header: %w", err) + } + } + // Delete all further code + for i, chunknr := uint64(32*128), uint64(128); i < codeSize; i, chunknr = i+32, chunknr+1 { + // evaluate group key at the start of a new group + groupOffset := (chunknr + 128) % 256 + if groupOffset == 0 { + key = utils.CodeChunkKeyWithEvaluatedAddress(evaluatedAddr, uint256.NewInt(chunknr)) + } + key[31] = byte(groupOffset) + _, err = t.root.Delete(key[:], t.nodeResolver) + if err != nil { + return fmt.Errorf("error deleting code chunk (addr=%x) error: %w", addr[:], err) + } + } + return nil +} + // DeleteStorage implements state.Trie, deleting the specified storage slot from // the trie. If the storage slot was not existent in the trie, no error will be // returned. If the trie is corrupted, an error will be returned. diff --git a/trie/verkle_test.go b/trie/verkle_test.go index 0cbe28bf0192..55438d45e12c 100644 --- a/trie/verkle_test.go +++ b/trie/verkle_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie/utils" "github.com/holiman/uint256" ) @@ -89,3 +90,84 @@ func TestVerkleTreeReadWrite(t *testing.T) { } } } + +func TestVerkleRollBack(t *testing.T) { + db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme) + tr, _ := NewVerkleTrie(types.EmptyVerkleHash, db, utils.NewPointCache(100)) + + for addr, acct := range accounts { + if err := tr.UpdateAccount(addr, acct); err != nil { + t.Fatalf("Failed to update account, %v", err) + } + for key, val := range storages[addr] { + if err := tr.UpdateStorage(addr, key.Bytes(), val); err != nil { + t.Fatalf("Failed to update account, %v", err) + } + } + // create more than 128 chunks of code + code := make([]byte, 129*32) + for i := 0; i < len(code); i += 2 { + code[i] = 0x60 + code[i+1] = byte(i % 256) + } + hash := crypto.Keccak256Hash(code) + if err := tr.UpdateContractCode(addr, hash, code); err != nil { + t.Fatalf("Failed to update contract, %v", err) + } + } + + // Check that things were created + for addr, acct := range accounts { + stored, err := tr.GetAccount(addr) + if err != nil { + t.Fatalf("Failed to get account, %v", err) + } + if !reflect.DeepEqual(stored, acct) { + t.Fatal("account is not matched") + } + for key, val := range storages[addr] { + stored, err := tr.GetStorage(addr, key.Bytes()) + if err != nil { + t.Fatalf("Failed to get storage, %v", err) + } + if !bytes.Equal(stored, val) { + t.Fatal("storage is not matched") + } + } + } + + // ensure there is some code in the 2nd group + keyOf2ndGroup := []byte{141, 124, 185, 236, 50, 22, 185, 39, 244, 47, 97, 209, 96, 235, 22, 13, 205, 38, 18, 201, 128, 223, 0, 59, 146, 199, 222, 119, 133, 13, 91, 0} + chunk, err := tr.root.Get(keyOf2ndGroup, nil) + if err != nil { + t.Fatalf("Failed to get account, %v", err) + } + if len(chunk) == 0 { + t.Fatal("account was not created ") + } + + // Rollback first account and check that it is gone + addr1 := common.Address{1} + err = tr.RollBackAccount(addr1) + if err != nil { + t.Fatalf("error rolling back address 1: %v", err) + } + + // ensure the account is gone + stored, err := tr.GetAccount(addr1) + if err != nil { + t.Fatalf("Failed to get account, %v", err) + } + if stored != nil { + t.Fatal("account was not deleted") + } + + // ensure that the last code chunk is also gone from the tree + chunk, err = tr.root.Get(keyOf2ndGroup, nil) + if err != nil { + t.Fatalf("Failed to get account, %v", err) + } + if len(chunk) != 0 { + t.Fatal("account was not deleted") + } +} From 4bbe993252f0f54f58a09ab32822e09281c25e79 Mon Sep 17 00:00:00 2001 From: Nathan Jo <162083209+qqqeck@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:15:35 +0900 Subject: [PATCH 408/571] p2p: fix ip change log parameter (#30158) --- p2p/server_nat.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/server_nat.go b/p2p/server_nat.go index 299d27549005..933993bc1f49 100644 --- a/p2p/server_nat.go +++ b/p2p/server_nat.go @@ -125,7 +125,7 @@ func (srv *Server) portMappingLoop() { if err != nil { log.Debug("Couldn't get external IP", "err", err, "interface", srv.NAT) } else if !ip.Equal(lastExtIP) { - log.Debug("External IP changed", "ip", extip, "interface", srv.NAT) + log.Debug("External IP changed", "ip", ip, "interface", srv.NAT) } else { continue } From 169aa914497f3dff4dec2fdd68a29e185a4091a6 Mon Sep 17 00:00:00 2001 From: Jeremy Schlatter Date: Mon, 15 Jul 2024 02:36:21 -0700 Subject: [PATCH 409/571] cmd/utils: fix typo in flag description (#30127) --- 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 46d380b98499..96a3cf55bb7d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -291,7 +291,7 @@ var ( } BeaconApiHeaderFlag = &cli.StringSliceFlag{ Name: "beacon.api.header", - Usage: "Pass custom HTTP header fields to the emote beacon node API in \"key:value\" format. This flag can be given multiple times.", + Usage: "Pass custom HTTP header fields to the remote beacon node API in \"key:value\" format. This flag can be given multiple times.", Category: flags.BeaconCategory, } BeaconThresholdFlag = &cli.IntFlag{ From a0d2613ef0814c5cde83909cf48b2c3eea274faf Mon Sep 17 00:00:00 2001 From: Danyal Prout Date: Mon, 15 Jul 2024 05:09:32 -0500 Subject: [PATCH 410/571] core/types: don't modify signature V when reading large chainID (#30157) --- core/types/transaction_signing.go | 4 ++-- core/types/transaction_test.go | 35 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 339fee6f9737..dd25f081f79a 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -572,6 +572,6 @@ func deriveChainId(v *big.Int) *big.Int { } return new(big.Int).SetUint64((v - 35) / 2) } - v.Sub(v, big.NewInt(35)) - return v.Rsh(v, 1) + vCopy := new(big.Int).Sub(v, big.NewInt(35)) + return vCopy.Rsh(vCopy, 1) } diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 5dbf367073b5..eed13ee205bf 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -345,6 +345,41 @@ func TestTransactionCoding(t *testing.T) { } } +func TestLegacyTransaction_ConsistentV_LargeChainIds(t *testing.T) { + chainId := new(big.Int).SetUint64(13317435930671861669) + + txdata := &LegacyTx{ + Nonce: 1, + Gas: 1, + GasPrice: big.NewInt(2), + Data: []byte("abcdef"), + } + + key, err := crypto.GenerateKey() + if err != nil { + t.Fatalf("could not generate key: %v", err) + } + + tx, err := SignNewTx(key, NewEIP2930Signer(chainId), txdata) + if err != nil { + t.Fatalf("could not sign transaction: %v", err) + } + + // Make a copy of the initial V value + preV, _, _ := tx.RawSignatureValues() + preV = new(big.Int).Set(preV) + + if tx.ChainId().Cmp(chainId) != 0 { + t.Fatalf("wrong chain id: %v", tx.ChainId()) + } + + v, _, _ := tx.RawSignatureValues() + + if v.Cmp(preV) != 0 { + t.Fatalf("wrong v value: %v", v) + } +} + func encodeDecodeJSON(tx *Transaction) (*Transaction, error) { data, err := json.Marshal(tx) if err != nil { From 8adce57b411267faac6cf744aee84f5c51445bb9 Mon Sep 17 00:00:00 2001 From: JeukHwang <92910273+JeukHwang@users.noreply.github.com> Date: Mon, 15 Jul 2024 21:29:13 +0900 Subject: [PATCH 411/571] SECURITY.md: correct PGP key block formatting (#30123) --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 41b900d5e984..1c99ab59505a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -171,5 +171,5 @@ i4O1UeWKs9owWttan9+PI47ozBSKOTxmMqLSQ0f56Np9FJsV0ilGxRKfjhzJ4KniOMUBA7mP epy6lH7HmxjjOR7eo0DaSxQGQpThAtFGwkWkFh8yki8j3E42kkrxvEyyYZDXn2YcI3bpqhJx PtwCMZUJ3kc/skOrs6bOI19iBNaEoNX5Dllm7UHjOgWNDQkcCuOCxucKano= =arte ------END PGP PUBLIC KEY BLOCK------ +-----END PGP PUBLIC KEY BLOCK----- ``` From 71210b0630e4f8dd2e7bcc7c39424fb2382e4f00 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Mon, 15 Jul 2024 21:26:58 +0800 Subject: [PATCH 412/571] all: simplify tests using t.TempDir() (#30150) --- accounts/keystore/account_cache_test.go | 3 +-- cmd/clef/consolecmd_test.go | 9 +++----- cmd/devp2p/internal/ethtest/suite_test.go | 8 ++++---- cmd/geth/exportcmd_test.go | 3 +-- cmd/geth/logging_test.go | 6 ++---- cmd/utils/export_test.go | 25 +++++------------------ core/rawdb/freezer_meta_test.go | 6 ++++-- 7 files changed, 20 insertions(+), 40 deletions(-) diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index 41a300224842..c9a8cdfcef3d 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -114,7 +114,7 @@ func TestWatchNewFile(t *testing.T) { func TestWatchNoDir(t *testing.T) { t.Parallel() // Create ks but not the directory that it watches. - dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int())) + dir := filepath.Join(t.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int())) ks := NewKeyStore(dir, LightScryptN, LightScryptP) list := ks.Accounts() if len(list) > 0 { @@ -126,7 +126,6 @@ func TestWatchNoDir(t *testing.T) { } // Create the directory and copy a key file into it. os.MkdirAll(dir, 0700) - defer os.RemoveAll(dir) file := filepath.Join(dir, "aaa") if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil { t.Fatal(err) diff --git a/cmd/clef/consolecmd_test.go b/cmd/clef/consolecmd_test.go index c8b37f5b92ee..a5b324c53f31 100644 --- a/cmd/clef/consolecmd_test.go +++ b/cmd/clef/consolecmd_test.go @@ -27,9 +27,8 @@ import ( // TestImportRaw tests clef --importraw func TestImportRaw(t *testing.T) { t.Parallel() - keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) + keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) - t.Cleanup(func() { os.Remove(keyPath) }) t.Run("happy-path", func(t *testing.T) { t.Parallel() @@ -68,9 +67,8 @@ func TestImportRaw(t *testing.T) { // TestListAccounts tests clef --list-accounts func TestListAccounts(t *testing.T) { t.Parallel() - keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) + keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) - t.Cleanup(func() { os.Remove(keyPath) }) t.Run("no-accounts", func(t *testing.T) { t.Parallel() @@ -97,9 +95,8 @@ func TestListAccounts(t *testing.T) { // TestListWallets tests clef --list-wallets func TestListWallets(t *testing.T) { t.Parallel() - keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) + keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) - t.Cleanup(func() { os.Remove(keyPath) }) t.Run("no-accounts", func(t *testing.T) { t.Parallel() diff --git a/cmd/devp2p/internal/ethtest/suite_test.go b/cmd/devp2p/internal/ethtest/suite_test.go index d70adda51f92..a6fca0e524d0 100644 --- a/cmd/devp2p/internal/ethtest/suite_test.go +++ b/cmd/devp2p/internal/ethtest/suite_test.go @@ -34,12 +34,12 @@ import ( "github.com/ethereum/go-ethereum/p2p" ) -func makeJWTSecret() (string, [32]byte, error) { +func makeJWTSecret(t *testing.T) (string, [32]byte, error) { var secret [32]byte if _, err := crand.Read(secret[:]); err != nil { return "", secret, fmt.Errorf("failed to create jwt secret: %v", err) } - jwtPath := filepath.Join(os.TempDir(), "jwt_secret") + jwtPath := filepath.Join(t.TempDir(), "jwt_secret") if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil { return "", secret, fmt.Errorf("failed to prepare jwt secret file: %v", err) } @@ -47,7 +47,7 @@ func makeJWTSecret() (string, [32]byte, error) { } func TestEthSuite(t *testing.T) { - jwtPath, secret, err := makeJWTSecret() + jwtPath, secret, err := makeJWTSecret(t) if err != nil { t.Fatalf("could not make jwt secret: %v", err) } @@ -75,7 +75,7 @@ func TestEthSuite(t *testing.T) { } func TestSnapSuite(t *testing.T) { - jwtPath, secret, err := makeJWTSecret() + jwtPath, secret, err := makeJWTSecret(t) if err != nil { t.Fatalf("could not make jwt secret: %v", err) } diff --git a/cmd/geth/exportcmd_test.go b/cmd/geth/exportcmd_test.go index 9570b1ffd27a..d08c89073464 100644 --- a/cmd/geth/exportcmd_test.go +++ b/cmd/geth/exportcmd_test.go @@ -28,8 +28,7 @@ import ( // TestExport does a basic test of "geth export", exporting the test-genesis. func TestExport(t *testing.T) { t.Parallel() - outfile := fmt.Sprintf("%v/testExport.out", os.TempDir()) - defer os.Remove(outfile) + outfile := fmt.Sprintf("%v/testExport.out", t.TempDir()) geth := runGeth(t, "--datadir", initGeth(t), "export", outfile) geth.WaitExit() if have, want := geth.ExitStatus(), 0; have != want { diff --git a/cmd/geth/logging_test.go b/cmd/geth/logging_test.go index f426b138bb67..4293a860ec33 100644 --- a/cmd/geth/logging_test.go +++ b/cmd/geth/logging_test.go @@ -201,9 +201,8 @@ func TestFileOut(t *testing.T) { var ( have, want []byte err error - path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63()) + path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63()) ) - t.Cleanup(func() { os.Remove(path) }) if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "logtest"); err != nil { t.Fatal(err) } @@ -222,9 +221,8 @@ func TestRotatingFileOut(t *testing.T) { var ( have, want []byte err error - path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63()) + path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63()) ) - t.Cleanup(func() { os.Remove(path) }) if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "--log.rotate", "logtest"); err != nil { t.Fatal(err) } diff --git a/cmd/utils/export_test.go b/cmd/utils/export_test.go index c22aad64b817..b70d2451c68e 100644 --- a/cmd/utils/export_test.go +++ b/cmd/utils/export_test.go @@ -29,18 +29,12 @@ import ( // TestExport does basic sanity checks on the export/import functionality func TestExport(t *testing.T) { - f := fmt.Sprintf("%v/tempdump", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump", t.TempDir()) testExport(t, f) } func TestExportGzip(t *testing.T) { - f := fmt.Sprintf("%v/tempdump.gz", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump.gz", t.TempDir()) testExport(t, f) } @@ -99,20 +93,14 @@ func testExport(t *testing.T, f string) { // TestDeletionExport tests if the deletion markers can be exported/imported correctly func TestDeletionExport(t *testing.T) { - f := fmt.Sprintf("%v/tempdump", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump", t.TempDir()) testDeletion(t, f) } // TestDeletionExportGzip tests if the deletion markers can be exported/imported // correctly with gz compression. func TestDeletionExportGzip(t *testing.T) { - f := fmt.Sprintf("%v/tempdump.gz", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump.gz", t.TempDir()) testDeletion(t, f) } @@ -171,10 +159,7 @@ func testDeletion(t *testing.T, f string) { // TestImportFutureFormat tests that we reject unsupported future versions. func TestImportFutureFormat(t *testing.T) { t.Parallel() - f := fmt.Sprintf("%v/tempdump-future", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump-future", t.TempDir()) fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) if err != nil { t.Fatal(err) diff --git a/core/rawdb/freezer_meta_test.go b/core/rawdb/freezer_meta_test.go index ba1a95e45317..409e8110262a 100644 --- a/core/rawdb/freezer_meta_test.go +++ b/core/rawdb/freezer_meta_test.go @@ -22,10 +22,11 @@ import ( ) func TestReadWriteFreezerTableMeta(t *testing.T) { - f, err := os.CreateTemp(os.TempDir(), "*") + f, err := os.CreateTemp(t.TempDir(), "*") if err != nil { t.Fatalf("Failed to create file %v", err) } + defer f.Close() err = writeMetadata(f, newMetadata(100)) if err != nil { t.Fatalf("Failed to write metadata %v", err) @@ -43,10 +44,11 @@ func TestReadWriteFreezerTableMeta(t *testing.T) { } func TestInitializeFreezerTableMeta(t *testing.T) { - f, err := os.CreateTemp(os.TempDir(), "*") + f, err := os.CreateTemp(t.TempDir(), "*") if err != nil { t.Fatalf("Failed to create file %v", err) } + defer f.Close() meta, err := loadMetadata(f, uint64(100)) if err != nil { t.Fatalf("Failed to read metadata %v", err) From 0d38b0cd34fd8fef3388feb529bb241b725b7364 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 16 Jul 2024 04:47:11 -0500 Subject: [PATCH 413/571] eth/catalyst: fix (*SimulatedBeacon).AdjustTime() conversion (#30138) --- eth/catalyst/simulated_beacon.go | 2 +- ethclient/simulated/backend_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index 2d6569e42218..8bdf94b80e81 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -302,7 +302,7 @@ func (c *SimulatedBeacon) AdjustTime(adjustment time.Duration) error { return errors.New("parent not found") } withdrawals := c.withdrawals.gatherPending(10) - return c.sealBlock(withdrawals, parent.Time+uint64(adjustment)) + return c.sealBlock(withdrawals, parent.Time+uint64(adjustment/time.Second)) } func RegisterSimulatedBeaconAPIs(stack *node.Node, sim *SimulatedBeacon) { diff --git a/ethclient/simulated/backend_test.go b/ethclient/simulated/backend_test.go index a8fd7913c334..b70086b3854c 100644 --- a/ethclient/simulated/backend_test.go +++ b/ethclient/simulated/backend_test.go @@ -106,7 +106,7 @@ func TestAdjustTime(t *testing.T) { block2, _ := client.BlockByNumber(context.Background(), nil) prevTime := block1.Time() newTime := block2.Time() - if newTime-prevTime != uint64(time.Minute) { + if newTime-prevTime != 60 { t.Errorf("adjusted time not equal to 60 seconds. prev: %v, new: %v", prevTime, newTime) } } From b530d8e4552a583eb89538799b31aa92e281b4ed Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 16 Jul 2024 18:52:19 +0800 Subject: [PATCH 414/571] trie, triedb: remove unnecessary child resolver interface (#30167) --- trie/committer.go | 8 ++------ triedb/database.go | 10 +--------- triedb/hashdb/database.go | 30 +++++++++++------------------- 3 files changed, 14 insertions(+), 34 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index 4e2f7b8bd6a3..863e7bafdc4b 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -154,12 +154,8 @@ func (c *committer) store(path []byte, n node) node { return hash } -// MerkleResolver the children resolver in merkle-patricia-tree. -type MerkleResolver struct{} - -// ForEach implements childResolver, decodes the provided node and -// traverses the children inside. -func (resolver MerkleResolver) ForEach(node []byte, onChild func(common.Hash)) { +// ForGatherChildren decodes the provided node and traverses the children inside. +func ForGatherChildren(node []byte, onChild func(common.Hash)) { forGatherChildren(mustDecodeNodeUnsafe(nil, node), onChild) } diff --git a/triedb/database.go b/triedb/database.go index 91386a9dbcf5..1f9f38388b4d 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -23,7 +23,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/triedb/database" @@ -112,14 +111,7 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { if config.PathDB != nil { db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle) } else { - var resolver hashdb.ChildResolver - if config.IsVerkle { - // TODO define verkle resolver - log.Crit("verkle does not use a hash db") - } else { - resolver = trie.MerkleResolver{} - } - db.backend = hashdb.New(diskdb, config.HashDB, resolver) + db.backend = hashdb.New(diskdb, config.HashDB) } return db } diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index bb0deca9a713..4def10e338b1 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/triedb/database" @@ -60,12 +61,6 @@ var ( memcacheCommitBytesMeter = metrics.NewRegisteredMeter("hashdb/memcache/commit/bytes", nil) ) -// ChildResolver defines the required method to decode the provided -// trie node and iterate the children on top. -type ChildResolver interface { - ForEach(node []byte, onChild func(common.Hash)) -} - // Config contains the settings for database. type Config struct { CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes @@ -84,9 +79,7 @@ var Defaults = &Config{ // the disk database. The aim is to accumulate trie writes in-memory and only // periodically flush a couple tries to disk, garbage collecting the remainder. type Database struct { - diskdb ethdb.Database // Persistent storage for matured trie nodes - resolver ChildResolver // The handler to resolve children of nodes - + diskdb ethdb.Database // Persistent storage for matured trie nodes cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes oldest common.Hash // Oldest tracked node, flush-list head @@ -124,15 +117,15 @@ var cachedNodeSize = int(reflect.TypeOf(cachedNode{}).Size()) // forChildren invokes the callback for all the tracked children of this node, // both the implicit ones from inside the node as well as the explicit ones // from outside the node. -func (n *cachedNode) forChildren(resolver ChildResolver, onChild func(hash common.Hash)) { +func (n *cachedNode) forChildren(onChild func(hash common.Hash)) { for child := range n.external { onChild(child) } - resolver.ForEach(n.node, onChild) + trie.ForGatherChildren(n.node, onChild) } // New initializes the hash-based node database. -func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Database { +func New(diskdb ethdb.Database, config *Config) *Database { if config == nil { config = Defaults } @@ -141,10 +134,9 @@ func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Databas cleans = fastcache.New(config.CleanCacheSize) } return &Database{ - diskdb: diskdb, - resolver: resolver, - cleans: cleans, - dirties: make(map[common.Hash]*cachedNode), + diskdb: diskdb, + cleans: cleans, + dirties: make(map[common.Hash]*cachedNode), } } @@ -163,7 +155,7 @@ func (db *Database) insert(hash common.Hash, node []byte) { node: node, flushPrev: db.newest, } - entry.forChildren(db.resolver, func(child common.Hash) { + entry.forChildren(func(child common.Hash) { if c := db.dirties[child]; c != nil { c.parents++ } @@ -316,7 +308,7 @@ func (db *Database) dereference(hash common.Hash) { db.dirties[node.flushNext].flushPrev = node.flushPrev } // Dereference all children and delete the node - node.forChildren(db.resolver, func(child common.Hash) { + node.forChildren(func(child common.Hash) { db.dereference(child) }) delete(db.dirties, hash) @@ -465,7 +457,7 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane var err error // Dereference all children and delete the node - node.forChildren(db.resolver, func(child common.Hash) { + node.forChildren(func(child common.Hash) { if err == nil { err = db.commit(child, batch, uncacher) } From 15936c64a26d624026ae2df953cc3d5369a8131f Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 16 Jul 2024 19:42:30 +0800 Subject: [PATCH 415/571] core/txpool/legacypool: use maps.Keys and maps.Copy (#30091) --- core/txpool/legacypool/legacypool.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 4e1d26acf405..5506ecc31fc3 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" + "golang.org/x/exp/maps" ) const ( @@ -1717,7 +1718,7 @@ func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } type accountSet struct { accounts map[common.Address]struct{} signer types.Signer - cache *[]common.Address + cache []common.Address } // newAccountSet creates a new address set with an associated signer for sender @@ -1765,20 +1766,14 @@ func (as *accountSet) addTx(tx *types.Transaction) { // reuse. The returned slice should not be changed! func (as *accountSet) flatten() []common.Address { if as.cache == nil { - accounts := make([]common.Address, 0, len(as.accounts)) - for account := range as.accounts { - accounts = append(accounts, account) - } - as.cache = &accounts + as.cache = maps.Keys(as.accounts) } - return *as.cache + return as.cache } // merge adds all addresses from the 'other' set into 'as'. func (as *accountSet) merge(other *accountSet) { - for addr := range other.accounts { - as.accounts[addr] = struct{}{} - } + maps.Copy(as.accounts, other.accounts) as.cache = nil } From c54294bd41fdea30f715d9f0a4f3f9e44dcc9101 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:06:22 +0200 Subject: [PATCH 416/571] core/state: don't compute verkle storage tree roots (#30130) --- core/state/statedb.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 1664a446f4e2..641775b0bdfc 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -860,12 +860,16 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } obj := s.stateObjects[addr] // closure for the task runner below workers.Go(func() error { - obj.updateRoot() + if s.db.TrieDB().IsVerkle() { + obj.updateTrie() + } else { + obj.updateRoot() - // If witness building is enabled and the state object has a trie, - // gather the witnesses for its specific storage trie - if s.witness != nil && obj.trie != nil { - s.witness.AddState(obj.trie.Witness()) + // If witness building is enabled and the state object has a trie, + // gather the witnesses for its specific storage trie + if s.witness != nil && obj.trie != nil { + s.witness.AddState(obj.trie.Witness()) + } } return nil }) From f59d013e4064adbb092b323781104c07550a8bff Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 16 Jul 2024 21:17:58 +0800 Subject: [PATCH 417/571] core/rawdb, triedb, cmd: create an isolated disk namespace for verkle (#30105) * core, triedb/pathdb, cmd: define verkle state ancient store * core/rawdb, triedb: add verkle namespace in pathdb --- cmd/geth/dbcmd.go | 3 ++- core/genesis_test.go | 6 +++--- core/rawdb/accessors_trie.go | 12 +++++++++++- core/rawdb/ancient_scheme.go | 17 ++++++++++++----- core/rawdb/ancient_utils.go | 6 +++--- core/rawdb/database.go | 24 ++++++++++++++++++++++++ core/rawdb/schema.go | 7 +++++++ triedb/database.go | 11 +++++++++-- triedb/pathdb/database.go | 10 +++++++++- triedb/pathdb/history_test.go | 8 ++++---- 10 files changed, 84 insertions(+), 20 deletions(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 4b683569a45e..052ae0eab2d5 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -248,7 +248,8 @@ func removeDB(ctx *cli.Context) error { // Delete state data statePaths := []string{ rootDir, - filepath.Join(ancientDir, rawdb.StateFreezerName), + filepath.Join(ancientDir, rawdb.MerkleStateFreezerName), + filepath.Join(ancientDir, rawdb.VerkleStateFreezerName), } confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name) diff --git a/core/genesis_test.go b/core/genesis_test.go index ab408327d4e6..002e58a961b9 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -311,7 +311,7 @@ func TestVerkleGenesisCommit(t *testing.T) { } db := rawdb.NewMemoryDatabase() - triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults}) + triedb := triedb.NewDatabase(db, triedb.VerkleDefaults) block := genesis.MustCommit(db, triedb) if !bytes.Equal(block.Root().Bytes(), expected) { t.Fatalf("invalid genesis state root, expected %x, got %x", expected, block.Root()) @@ -321,8 +321,8 @@ func TestVerkleGenesisCommit(t *testing.T) { if !triedb.IsVerkle() { t.Fatalf("expected trie to be verkle") } - - if !rawdb.HasAccountTrieNode(db, nil) { + vdb := rawdb.NewTable(db, string(rawdb.VerklePrefix)) + if !rawdb.HasAccountTrieNode(vdb, nil) { t.Fatal("could not find node") } } diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index 44eb715d04e2..0f856d180457 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -245,7 +245,7 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has // ReadStateScheme reads the state scheme of persistent state, or none // if the state is not present in database. -func ReadStateScheme(db ethdb.Reader) string { +func ReadStateScheme(db ethdb.Database) string { // Check if state in path-based scheme is present. if HasAccountTrieNode(db, nil) { return PathScheme @@ -255,6 +255,16 @@ func ReadStateScheme(db ethdb.Reader) string { if id := ReadPersistentStateID(db); id != 0 { return PathScheme } + // Check if verkle state in path-based scheme is present. + vdb := NewTable(db, string(VerklePrefix)) + if HasAccountTrieNode(vdb, nil) { + return PathScheme + } + // The root node of verkle might be deleted during the initial snap sync, + // check the persistent state id then. + if id := ReadPersistentStateID(vdb); id != 0 { + return PathScheme + } // In a hash-based scheme, the genesis state is consistently stored // on the disk. To assess the scheme of the persistent state, it // suffices to inspect the scheme of the genesis state. diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index 44867ded04ab..371fd384ada7 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -72,12 +72,13 @@ var stateFreezerNoSnappy = map[string]bool{ // The list of identifiers of ancient stores. var ( - ChainFreezerName = "chain" // the folder name of chain segment ancient store. - StateFreezerName = "state" // the folder name of reverse diff ancient store. + ChainFreezerName = "chain" // the folder name of chain segment ancient store. + MerkleStateFreezerName = "state" // the folder name of state history ancient store. + VerkleStateFreezerName = "state_verkle" // the folder name of state history ancient store. ) // freezers the collections of all builtin freezers. -var freezers = []string{ChainFreezerName, StateFreezerName} +var freezers = []string{ChainFreezerName, MerkleStateFreezerName, VerkleStateFreezerName} // NewStateFreezer initializes the ancient store for state history. // @@ -85,9 +86,15 @@ var freezers = []string{ChainFreezerName, StateFreezerName} // state freezer (e.g. dev mode). // - if non-empty directory is given, initializes the regular file-based // state freezer. -func NewStateFreezer(ancientDir string, readOnly bool) (ethdb.ResettableAncientStore, error) { +func NewStateFreezer(ancientDir string, verkle bool, readOnly bool) (ethdb.ResettableAncientStore, error) { if ancientDir == "" { return NewMemoryFreezer(readOnly, stateFreezerNoSnappy), nil } - return newResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy) + var name string + if verkle { + name = filepath.Join(ancientDir, VerkleStateFreezerName) + } else { + name = filepath.Join(ancientDir, MerkleStateFreezerName) + } + return newResettableFreezer(name, "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy) } diff --git a/core/rawdb/ancient_utils.go b/core/rawdb/ancient_utils.go index 1c69639c9d04..6804d7a91a2a 100644 --- a/core/rawdb/ancient_utils.go +++ b/core/rawdb/ancient_utils.go @@ -88,12 +88,12 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { } infos = append(infos, info) - case StateFreezerName: + case MerkleStateFreezerName, VerkleStateFreezerName: datadir, err := db.AncientDatadir() if err != nil { return nil, err } - f, err := NewStateFreezer(datadir, true) + f, err := NewStateFreezer(datadir, freezer == VerkleStateFreezerName, true) if err != nil { continue // might be possible the state freezer is not existent } @@ -124,7 +124,7 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s switch freezerName { case ChainFreezerName: path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy - case StateFreezerName: + case MerkleStateFreezerName, VerkleStateFreezerName: path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy default: return fmt.Errorf("unknown freezer, supported ones: %v", freezers) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 3436958de735..831016da15df 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -481,6 +481,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { beaconHeaders stat cliqueSnaps stat + // Verkle statistics + verkleTries stat + verkleStateLookups stat + // Les statistic chtTrieNodes stat bloomTrieNodes stat @@ -550,6 +554,24 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { bytes.HasPrefix(key, BloomTrieIndexPrefix) || bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub bloomTrieNodes.Add(size) + + // Verkle trie data is detected, determine the sub-category + case bytes.HasPrefix(key, VerklePrefix): + remain := key[len(VerklePrefix):] + switch { + case IsAccountTrieNode(remain): + verkleTries.Add(size) + case bytes.HasPrefix(remain, stateIDPrefix) && len(remain) == len(stateIDPrefix)+common.HashLength: + verkleStateLookups.Add(size) + case bytes.Equal(remain, persistentStateIDKey): + metadata.Add(size) + case bytes.Equal(remain, trieJournalKey): + metadata.Add(size) + case bytes.Equal(remain, snapSyncStatusFlagKey): + metadata.Add(size) + default: + unaccounted.Add(size) + } default: var accounted bool for _, meta := range [][]byte{ @@ -590,6 +612,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Path trie state lookups", stateLookups.Size(), stateLookups.Count()}, {"Key-Value store", "Path trie account nodes", accountTries.Size(), accountTries.Count()}, {"Key-Value store", "Path trie storage nodes", storageTries.Size(), storageTries.Count()}, + {"Key-Value store", "Verkle trie nodes", verkleTries.Size(), verkleTries.Count()}, + {"Key-Value store", "Verkle trie state lookups", verkleStateLookups.Size(), verkleStateLookups.Count()}, {"Key-Value store", "Trie preimages", preimages.Size(), preimages.Count()}, {"Key-Value store", "Account snapshot", accountSnaps.Size(), accountSnaps.Count()}, {"Key-Value store", "Storage snapshot", storageSnaps.Size(), storageSnaps.Count()}, diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index dbf010be0ca8..04b5d0d6d2c8 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -117,6 +117,13 @@ var ( TrieNodeStoragePrefix = []byte("O") // TrieNodeStoragePrefix + accountHash + hexPath -> trie node stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id + // VerklePrefix is the database prefix for Verkle trie data, which includes: + // (a) Trie nodes + // (b) In-memory trie node journal + // (c) Persistent state ID + // (d) State ID lookups, etc. + VerklePrefix = []byte("v") + PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage configPrefix = []byte("ethereum-config-") // config prefix for the db genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db diff --git a/triedb/database.go b/triedb/database.go index 1f9f38388b4d..aecb900f31d3 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -42,9 +42,18 @@ type Config struct { // default settings. var HashDefaults = &Config{ Preimages: false, + IsVerkle: false, HashDB: hashdb.Defaults, } +// VerkleDefaults represents a config for holding verkle trie data +// using path-based scheme with default settings. +var VerkleDefaults = &Config{ + Preimages: false, + IsVerkle: true, + PathDB: pathdb.Defaults, +} + // backend defines the methods needed to access/update trie nodes in different // state scheme. type backend interface { @@ -84,7 +93,6 @@ type backend interface { // relevant with trie nodes and node preimages. type Database struct { config *Config // Configuration for trie database - diskdb ethdb.Database // Persistent database to store the snapshot preimages *preimageStore // The store for caching preimages backend backend // The backend for managing trie nodes } @@ -102,7 +110,6 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { } db := &Database{ config: config, - diskdb: diskdb, preimages: preimages, } if config.HashDB != nil && config.PathDB != nil { diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 450c3a8f4f38..31e478117cd5 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -152,6 +152,14 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { } config = config.sanitize() + // Establish a dedicated database namespace tailored for verkle-specific + // data, ensuring the isolation of both verkle and merkle tree data. It's + // important to note that the introduction of a prefix won't lead to + // substantial storage overhead, as the underlying database will efficiently + // compress the shared key prefix. + if isVerkle { + diskdb = rawdb.NewTable(diskdb, string(rawdb.VerklePrefix)) + } db := &Database{ readOnly: config.ReadOnly, isVerkle: isVerkle, @@ -190,7 +198,7 @@ func (db *Database) repairHistory() error { // all of them. Fix the tests first. return nil } - freezer, err := rawdb.NewStateFreezer(ancient, db.readOnly) + freezer, err := rawdb.NewStateFreezer(ancient, db.isVerkle, db.readOnly) if err != nil { log.Crit("Failed to open state history freezer", "err", err) } diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_test.go index 4114aa118532..586f907fe4e0 100644 --- a/triedb/pathdb/history_test.go +++ b/triedb/pathdb/history_test.go @@ -129,7 +129,7 @@ func TestTruncateHeadHistory(t *testing.T) { roots []common.Hash hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false) ) defer freezer.Close() @@ -157,7 +157,7 @@ func TestTruncateTailHistory(t *testing.T) { roots []common.Hash hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false) ) defer freezer.Close() @@ -200,7 +200,7 @@ func TestTruncateTailHistories(t *testing.T) { roots []common.Hash hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = rawdb.NewStateFreezer(t.TempDir()+fmt.Sprintf("%d", i), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir()+fmt.Sprintf("%d", i), false, false) ) defer freezer.Close() @@ -228,7 +228,7 @@ func TestTruncateOutOfRange(t *testing.T) { var ( hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false) ) defer freezer.Close() From ad49c708f5769602e0d7a2d8889616ae13327d3a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 18 Jul 2024 11:09:02 +0200 Subject: [PATCH 418/571] p2p/discover: remove type encPubkey (#30172) The pubkey type was moved to package v4wire a long time ago. Remaining uses of encPubkey were probably left in due to laziness. --- p2p/discover/node.go | 33 --------------------------------- p2p/discover/table_util_test.go | 3 ++- p2p/discover/v4_lookup_test.go | 18 +++++++++--------- p2p/discover/v4_udp.go | 12 ++++++------ p2p/discover/v4_udp_test.go | 4 ++-- p2p/discover/v5_udp_test.go | 7 ++++--- 6 files changed, 23 insertions(+), 54 deletions(-) diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 042619221bde..ac34b7c5b2ea 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -17,16 +17,10 @@ package discover import ( - "crypto/ecdsa" - "crypto/elliptic" - "errors" - "math/big" "slices" "sort" "time" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" ) @@ -48,33 +42,6 @@ type tableNode struct { isValidatedLive bool // true if existence of node is considered validated right now } -type encPubkey [64]byte - -func encodePubkey(key *ecdsa.PublicKey) encPubkey { - var e encPubkey - math.ReadBits(key.X, e[:len(e)/2]) - math.ReadBits(key.Y, e[len(e)/2:]) - return e -} - -func decodePubkey(curve elliptic.Curve, e []byte) (*ecdsa.PublicKey, error) { - if len(e) != len(encPubkey{}) { - return nil, errors.New("wrong size public key data") - } - p := &ecdsa.PublicKey{Curve: curve, X: new(big.Int), Y: new(big.Int)} - half := len(e) / 2 - p.X.SetBytes(e[:half]) - p.Y.SetBytes(e[half:]) - if !p.Curve.IsOnCurve(p.X, p.Y) { - return nil, errors.New("invalid curve point") - } - return p, nil -} - -func (e encPubkey) id() enode.ID { - return enode.ID(crypto.Keccak256Hash(e[:])) -} - func unwrapNodes(ns []*tableNode) []*enode.Node { result := make([]*enode.Node, len(ns)) for i, n := range ns { diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 5b2699d460cc..fe10883fe6e2 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -30,6 +30,7 @@ import ( "time" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/discover/v4wire" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" ) @@ -284,7 +285,7 @@ func hexEncPrivkey(h string) *ecdsa.PrivateKey { } // hexEncPubkey decodes h as a public key. -func hexEncPubkey(h string) (ret encPubkey) { +func hexEncPubkey(h string) (ret v4wire.Pubkey) { b, err := hex.DecodeString(h) if err != nil { panic(err) diff --git a/p2p/discover/v4_lookup_test.go b/p2p/discover/v4_lookup_test.go index bc9475a8b369..70bd7056fba2 100644 --- a/p2p/discover/v4_lookup_test.go +++ b/p2p/discover/v4_lookup_test.go @@ -34,7 +34,7 @@ func TestUDPv4_Lookup(t *testing.T) { test := newUDPTest(t) // Lookup on empty table returns no nodes. - targetKey, _ := decodePubkey(crypto.S256(), lookupTestnet.target[:]) + targetKey, _ := v4wire.DecodePubkey(crypto.S256(), lookupTestnet.target) if results := test.udp.LookupPubkey(targetKey); len(results) > 0 { t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results) } @@ -56,7 +56,7 @@ func TestUDPv4_Lookup(t *testing.T) { results := <-resultC t.Logf("results:") for _, e := range results { - t.Logf(" ld=%d, %x", enode.LogDist(lookupTestnet.target.id(), e.ID()), e.ID().Bytes()) + t.Logf(" ld=%d, %x", enode.LogDist(lookupTestnet.target.ID(), e.ID()), e.ID().Bytes()) } if len(results) != bucketSize { t.Errorf("wrong number of results: got %d, want %d", len(results), bucketSize) @@ -142,7 +142,7 @@ func serveTestnet(test *udpTest, testnet *preminedTestnet) { case *v4wire.Ping: test.packetInFrom(nil, key, to, &v4wire.Pong{Expiration: futureExp, ReplyTok: hash}) case *v4wire.Findnode: - dist := enode.LogDist(n.ID(), testnet.target.id()) + dist := enode.LogDist(n.ID(), testnet.target.ID()) nodes := testnet.nodesAtDistance(dist - 1) test.packetInFrom(nil, key, to, &v4wire.Neighbors{Expiration: futureExp, Nodes: nodes}) } @@ -156,12 +156,12 @@ func checkLookupResults(t *testing.T, tn *preminedTestnet, results []*enode.Node t.Helper() t.Logf("results:") for _, e := range results { - t.Logf(" ld=%d, %x", enode.LogDist(tn.target.id(), e.ID()), e.ID().Bytes()) + t.Logf(" ld=%d, %x", enode.LogDist(tn.target.ID(), e.ID()), e.ID().Bytes()) } if hasDuplicates(results) { t.Errorf("result set contains duplicate entries") } - if !sortedByDistanceTo(tn.target.id(), results) { + if !sortedByDistanceTo(tn.target.ID(), results) { t.Errorf("result set not sorted by distance to target") } wantNodes := tn.closest(len(results)) @@ -231,7 +231,7 @@ var lookupTestnet = &preminedTestnet{ } type preminedTestnet struct { - target encPubkey + target v4wire.Pubkey dists [hashBits + 1][]*ecdsa.PrivateKey } @@ -304,7 +304,7 @@ func (tn *preminedTestnet) closest(n int) (nodes []*enode.Node) { } } slices.SortFunc(nodes, func(a, b *enode.Node) int { - return enode.DistCmp(tn.target.id(), a.ID(), b.ID()) + return enode.DistCmp(tn.target.ID(), a.ID(), b.ID()) }) return nodes[:n] } @@ -319,11 +319,11 @@ func (tn *preminedTestnet) mine() { tn.dists[i] = nil } - targetSha := tn.target.id() + targetSha := tn.target.ID() found, need := 0, 40 for found < need { k := newkey() - ld := enode.LogDist(targetSha, encodePubkey(&k.PublicKey).id()) + ld := enode.LogDist(targetSha, v4wire.EncodePubkey(&k.PublicKey).ID()) if len(tn.dists[ld]) < 8 { tn.dists[ld] = append(tn.dists[ld], k) found++ diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index cca01bd3ce79..321552ddc371 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -271,7 +271,7 @@ func (t *UDPv4) LookupPubkey(key *ecdsa.PublicKey) []*enode.Node { // case and run the bootstrapping logic. <-t.tab.refresh() } - return t.newLookup(t.closeCtx, encodePubkey(key)).run() + return t.newLookup(t.closeCtx, v4wire.EncodePubkey(key)).run() } // RandomNodes is an iterator yielding nodes from a random walk of the DHT. @@ -286,24 +286,24 @@ func (t *UDPv4) lookupRandom() []*enode.Node { // lookupSelf implements transport. func (t *UDPv4) lookupSelf() []*enode.Node { - return t.newLookup(t.closeCtx, encodePubkey(&t.priv.PublicKey)).run() + pubkey := v4wire.EncodePubkey(&t.priv.PublicKey) + return t.newLookup(t.closeCtx, pubkey).run() } func (t *UDPv4) newRandomLookup(ctx context.Context) *lookup { - var target encPubkey + var target v4wire.Pubkey crand.Read(target[:]) return t.newLookup(ctx, target) } -func (t *UDPv4) newLookup(ctx context.Context, targetKey encPubkey) *lookup { +func (t *UDPv4) newLookup(ctx context.Context, targetKey v4wire.Pubkey) *lookup { target := enode.ID(crypto.Keccak256Hash(targetKey[:])) - ekey := v4wire.Pubkey(targetKey) it := newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) { addr, ok := n.UDPEndpoint() if !ok { return nil, errNoUDPEndpoint } - return t.findnode(n.ID(), addr, ekey) + return t.findnode(n.ID(), addr, targetKey) }) return it } diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 9d6df08ead7f..1af31f4f1b9b 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -314,7 +314,7 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { // queue a pending findnode request resultc, errc := make(chan []*enode.Node, 1), make(chan error, 1) go func() { - rid := encodePubkey(&test.remotekey.PublicKey).id() + rid := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID() ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget) if err != nil && len(ns) == 0 { errc <- err @@ -433,7 +433,7 @@ func TestUDPv4_successfulPing(t *testing.T) { // pong packet. select { case n := <-added: - rid := encodePubkey(&test.remotekey.PublicKey).id() + rid := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID() if n.ID() != rid { t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid) } diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 1f8e972200ae..8631b918ff08 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/internal/testlog" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/discover/v4wire" "github.com/ethereum/go-ethereum/p2p/discover/v5wire" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" @@ -576,7 +577,7 @@ func TestUDPv5_lookup(t *testing.T) { test := newUDPV5Test(t) // Lookup on empty table returns no nodes. - if results := test.udp.Lookup(lookupTestnet.target.id()); len(results) > 0 { + if results := test.udp.Lookup(lookupTestnet.target.ID()); len(results) > 0 { t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results) } @@ -596,7 +597,7 @@ func TestUDPv5_lookup(t *testing.T) { // Start the lookup. resultC := make(chan []*enode.Node, 1) go func() { - resultC <- test.udp.Lookup(lookupTestnet.target.id()) + resultC <- test.udp.Lookup(lookupTestnet.target.ID()) test.close() }() @@ -793,7 +794,7 @@ func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr netip.AddrPort, // getNode ensures the test knows about a node at the given endpoint. func (test *udpV5Test) getNode(key *ecdsa.PrivateKey, addr netip.AddrPort) *enode.LocalNode { - id := encodePubkey(&key.PublicKey).id() + id := v4wire.EncodePubkey(&key.PublicKey).ID() ln := test.nodesByID[id] if ln == nil { db, _ := enode.OpenDB("") From df3f0a81a7ef6fd56c90675c32b6d732380a9fd2 Mon Sep 17 00:00:00 2001 From: Alexander Mint Date: Thu, 18 Jul 2024 13:38:42 +0300 Subject: [PATCH 419/571] go.mod: upgrade to btcsuite/btcd/btcec v2.3.4 (#30181) --- crypto/signature_nocgo.go | 5 +---- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index 989057442b6e..5ac3765c7106 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -88,10 +88,7 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { return nil, errors.New("invalid private key") } defer priv.Zero() - sig, err := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey - if err != nil { - return nil, err - } + sig := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey // Convert to Ethereum signature format with 'recovery id' v at the end. v := sig[0] - 27 copy(sig, sig[1:]) diff --git a/go.mod b/go.mod index a757b6705d23..db5c71349864 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.18.45 github.com/aws/aws-sdk-go-v2/credentials v1.13.43 github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2 - github.com/btcsuite/btcd/btcec/v2 v2.2.0 + github.com/btcsuite/btcd/btcec/v2 v2.3.4 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.79.0 github.com/cockroachdb/pebble v1.1.1 diff --git a/go.sum b/go.sum index 826f0f674f5a..e3cf5f3d63b9 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= -github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= From 944718bf165ae8c56528fe5c6dd52831513518e1 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Mon, 22 Jul 2024 05:40:14 +0200 Subject: [PATCH 420/571] ethdb: remove snapshot (#30189) --- core/rawdb/table.go | 7 ---- ethdb/database.go | 2 -- ethdb/dbtest/testsuite.go | 63 ----------------------------------- ethdb/leveldb/leveldb.go | 36 -------------------- ethdb/memorydb/memorydb.go | 67 -------------------------------------- ethdb/pebble/pebble.go | 49 ---------------------------- ethdb/remotedb/remotedb.go | 4 --- ethdb/snapshot.go | 41 ----------------------- trie/trie_test.go | 1 - 9 files changed, 270 deletions(-) delete mode 100644 ethdb/snapshot.go diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 90849fe9d93e..0a25c5bcddc6 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -200,13 +200,6 @@ func (t *table) NewBatchWithSize(size int) ethdb.Batch { return &tableBatch{t.db.NewBatchWithSize(size), t.prefix} } -// NewSnapshot creates a database snapshot based on the current state. -// The created snapshot will not be affected by all following mutations -// happened on the database. -func (t *table) NewSnapshot() (ethdb.Snapshot, error) { - return t.db.NewSnapshot() -} - // tableBatch is a wrapper around a database batch that prefixes each key access // with a pre-configured string. type tableBatch struct { diff --git a/ethdb/database.go b/ethdb/database.go index 9ef5942a136b..89c793d0be66 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -64,7 +64,6 @@ type KeyValueStore interface { Batcher Iteratee Compacter - Snapshotter io.Closer } @@ -199,6 +198,5 @@ type Database interface { Iteratee Stater Compacter - Snapshotter io.Closer } diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 29a773ced407..1af55a0e38af 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -318,69 +318,6 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { } }) - t.Run("Snapshot", func(t *testing.T) { - db := New() - defer db.Close() - - initial := map[string]string{ - "k1": "v1", "k2": "v2", "k3": "", "k4": "", - } - for k, v := range initial { - db.Put([]byte(k), []byte(v)) - } - snapshot, err := db.NewSnapshot() - if err != nil { - t.Fatal(err) - } - for k, v := range initial { - got, err := snapshot.Get([]byte(k)) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(got, []byte(v)) { - t.Fatalf("Unexpected value want: %v, got %v", v, got) - } - } - - // Flush more modifications into the database, ensure the snapshot - // isn't affected. - var ( - update = map[string]string{"k1": "v1-b", "k3": "v3-b"} - insert = map[string]string{"k5": "v5-b"} - delete = map[string]string{"k2": ""} - ) - for k, v := range update { - db.Put([]byte(k), []byte(v)) - } - for k, v := range insert { - db.Put([]byte(k), []byte(v)) - } - for k := range delete { - db.Delete([]byte(k)) - } - for k, v := range initial { - got, err := snapshot.Get([]byte(k)) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(got, []byte(v)) { - t.Fatalf("Unexpected value want: %v, got %v", v, got) - } - } - for k := range insert { - got, err := snapshot.Get([]byte(k)) - if err == nil || len(got) != 0 { - t.Fatal("Unexpected value") - } - } - for k := range delete { - got, err := snapshot.Get([]byte(k)) - if err != nil || len(got) == 0 { - t.Fatal("Unexpected deletion") - } - } - }) - t.Run("OperationsAfterClose", func(t *testing.T) { db := New() db.Put([]byte("key"), []byte("value")) diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 92838ad7ab85..24925a4f0457 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -230,19 +230,6 @@ func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { return db.db.NewIterator(bytesPrefixRange(prefix, start), nil) } -// NewSnapshot creates a database snapshot based on the current state. -// The created snapshot will not be affected by all following mutations -// happened on the database. -// Note don't forget to release the snapshot once it's used up, otherwise -// the stale data will never be cleaned up by the underlying compactor. -func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { - snap, err := db.db.GetSnapshot() - if err != nil { - return nil, err - } - return &snapshot{db: snap}, nil -} - // Stat returns the statistic data of the database. func (db *Database) Stat() (string, error) { var stats leveldb.DBStats @@ -498,26 +485,3 @@ func bytesPrefixRange(prefix, start []byte) *util.Range { r.Start = append(r.Start, start...) return r } - -// snapshot wraps a leveldb snapshot for implementing the Snapshot interface. -type snapshot struct { - db *leveldb.Snapshot -} - -// Has retrieves if a key is present in the snapshot backing by a key-value -// data store. -func (snap *snapshot) Has(key []byte) (bool, error) { - return snap.db.Has(key, nil) -} - -// Get retrieves the given key if it's present in the snapshot backing by -// key-value data store. -func (snap *snapshot) Get(key []byte) ([]byte, error) { - return snap.db.Get(key, nil) -} - -// Release releases associated resources. Release should always succeed and can -// be called multiple times without causing error. -func (snap *snapshot) Release() { - snap.db.Release() -} diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index 9b0872f89a33..532e0dfe3f36 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -35,10 +35,6 @@ var ( // errMemorydbNotFound is returned if a key is requested that is not found in // the provided memory database. errMemorydbNotFound = errors.New("not found") - - // errSnapshotReleased is returned if callers want to retrieve data from a - // released snapshot. - errSnapshotReleased = errors.New("snapshot released") ) // Database is an ephemeral key-value store. Apart from basic data storage @@ -175,13 +171,6 @@ func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { } } -// NewSnapshot creates a database snapshot based on the current state. -// The created snapshot will not be affected by all following mutations -// happened on the database. -func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { - return newSnapshot(db), nil -} - // Stat returns the statistic data of the database. func (db *Database) Stat() (string, error) { return "", nil @@ -332,59 +321,3 @@ func (it *iterator) Value() []byte { func (it *iterator) Release() { it.index, it.keys, it.values = -1, nil, nil } - -// snapshot wraps a batch of key-value entries deep copied from the in-memory -// database for implementing the Snapshot interface. -type snapshot struct { - db map[string][]byte - lock sync.RWMutex -} - -// newSnapshot initializes the snapshot with the given database instance. -func newSnapshot(db *Database) *snapshot { - db.lock.RLock() - defer db.lock.RUnlock() - - copied := make(map[string][]byte, len(db.db)) - for key, val := range db.db { - copied[key] = common.CopyBytes(val) - } - return &snapshot{db: copied} -} - -// Has retrieves if a key is present in the snapshot backing by a key-value -// data store. -func (snap *snapshot) Has(key []byte) (bool, error) { - snap.lock.RLock() - defer snap.lock.RUnlock() - - if snap.db == nil { - return false, errSnapshotReleased - } - _, ok := snap.db[string(key)] - return ok, nil -} - -// Get retrieves the given key if it's present in the snapshot backing by -// key-value data store. -func (snap *snapshot) Get(key []byte) ([]byte, error) { - snap.lock.RLock() - defer snap.lock.RUnlock() - - if snap.db == nil { - return nil, errSnapshotReleased - } - if entry, ok := snap.db[string(key)]; ok { - return common.CopyBytes(entry), nil - } - return nil, errMemorydbNotFound -} - -// Release releases associated resources. Release should always succeed and can -// be called multiple times without causing error. -func (snap *snapshot) Release() { - snap.lock.Lock() - defer snap.lock.Unlock() - - snap.db = nil -} diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 130d6617b5ba..8203dd136dea 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -351,55 +351,6 @@ func (d *Database) NewBatchWithSize(size int) ethdb.Batch { } } -// snapshot wraps a pebble snapshot for implementing the Snapshot interface. -type snapshot struct { - db *pebble.Snapshot -} - -// NewSnapshot creates a database snapshot based on the current state. -// The created snapshot will not be affected by all following mutations -// happened on the database. -// Note don't forget to release the snapshot once it's used up, otherwise -// the stale data will never be cleaned up by the underlying compactor. -func (d *Database) NewSnapshot() (ethdb.Snapshot, error) { - snap := d.db.NewSnapshot() - return &snapshot{db: snap}, nil -} - -// Has retrieves if a key is present in the snapshot backing by a key-value -// data store. -func (snap *snapshot) Has(key []byte) (bool, error) { - _, closer, err := snap.db.Get(key) - if err != nil { - if err != pebble.ErrNotFound { - return false, err - } else { - return false, nil - } - } - closer.Close() - return true, nil -} - -// Get retrieves the given key if it's present in the snapshot backing by -// key-value data store. -func (snap *snapshot) Get(key []byte) ([]byte, error) { - dat, closer, err := snap.db.Get(key) - if err != nil { - return nil, err - } - ret := make([]byte, len(dat)) - copy(ret, dat) - closer.Close() - return ret, nil -} - -// Release releases associated resources. Release should always succeed and can -// be called multiple times without causing error. -func (snap *snapshot) Release() { - snap.db.Close() -} - // upperBound returns the upper bound for the given prefix func upperBound(prefix []byte) (limit []byte) { for i := len(prefix) - 1; i >= 0; i-- { diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index bfecde4a3263..c8b76eab4ac4 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -138,10 +138,6 @@ func (db *Database) Compact(start []byte, limit []byte) error { return nil } -func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { - panic("not supported") -} - func (db *Database) Close() error { db.remote.Close() return nil diff --git a/ethdb/snapshot.go b/ethdb/snapshot.go deleted file mode 100644 index 03b7794a777d..000000000000 --- a/ethdb/snapshot.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2022 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 ethdb - -type Snapshot interface { - // Has retrieves if a key is present in the snapshot backing by a key-value - // data store. - Has(key []byte) (bool, error) - - // Get retrieves the given key if it's present in the snapshot backing by - // key-value data store. - Get(key []byte) ([]byte, error) - - // Release releases associated resources. Release should always succeed and can - // be called multiple times without causing error. - Release() -} - -// Snapshotter wraps the Snapshot method of a backing data store. -type Snapshotter interface { - // NewSnapshot creates a database snapshot based on the current state. - // The created snapshot will not be affected by all following mutations - // happened on the database. - // Note don't forget to release the snapshot once it's used up, otherwise - // the stale data will never be cleaned up by the underlying compactor. - NewSnapshot() (Snapshot, error) -} diff --git a/trie/trie_test.go b/trie/trie_test.go index 5f706a28befc..505b517bc593 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -819,7 +819,6 @@ func (s *spongeDb) Get(key []byte) ([]byte, error) { return nil, error func (s *spongeDb) Delete(key []byte) error { panic("implement me") } func (s *spongeDb) NewBatch() ethdb.Batch { return &spongeBatch{s} } func (s *spongeDb) NewBatchWithSize(size int) ethdb.Batch { return &spongeBatch{s} } -func (s *spongeDb) NewSnapshot() (ethdb.Snapshot, error) { panic("implement me") } func (s *spongeDb) Stat() (string, error) { panic("implement me") } func (s *spongeDb) Compact(start []byte, limit []byte) error { panic("implement me") } func (s *spongeDb) Close() error { return nil } From 380688c636a654becc8f114438c2a5d93d2db032 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 22 Jul 2024 09:58:53 +0200 Subject: [PATCH 421/571] eth/gasprice: remove default from config (#30080) * eth/gasprice: remove default from config * eth/gasprice: sanitize startPrice --- eth/backend.go | 6 +----- eth/gasprice/feehistory_test.go | 2 +- eth/gasprice/gasprice.go | 8 +++++--- eth/gasprice/gasprice_test.go | 3 +-- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 91a07811f038..8679018dabfc 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -264,11 +264,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if eth.APIBackend.allowUnprotectedTxs { log.Info("Unprotected transactions allowed") } - gpoParams := config.GPO - if gpoParams.Default == nil { - gpoParams.Default = config.Miner.GasPrice - } - eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) + eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice) // Setup DNS discovery iterators. dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) diff --git a/eth/gasprice/feehistory_test.go b/eth/gasprice/feehistory_test.go index 3d426db46fef..241b91b81003 100644 --- a/eth/gasprice/feehistory_test.go +++ b/eth/gasprice/feehistory_test.go @@ -59,7 +59,7 @@ func TestFeeHistory(t *testing.T) { MaxBlockHistory: c.maxBlock, } backend := newTestBackend(t, big.NewInt(16), big.NewInt(28), c.pending) - oracle := NewOracle(backend, config) + oracle := NewOracle(backend, config, nil) first, reward, baseFee, ratio, blobBaseFee, blobRatio, err := oracle.FeeHistory(context.Background(), c.count, c.last, c.percent) backend.teardown() diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index c90408e36302..19a6c0010a60 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -45,7 +45,6 @@ type Config struct { Percentile int MaxHeaderHistory uint64 MaxBlockHistory uint64 - Default *big.Int `toml:",omitempty"` MaxPrice *big.Int `toml:",omitempty"` IgnorePrice *big.Int `toml:",omitempty"` } @@ -79,7 +78,7 @@ type Oracle struct { // NewOracle returns a new gasprice oracle which can recommend suitable // gasprice for newly created transaction. -func NewOracle(backend OracleBackend, params Config) *Oracle { +func NewOracle(backend OracleBackend, params Config, startPrice *big.Int) *Oracle { blocks := params.Blocks if blocks < 1 { blocks = 1 @@ -115,6 +114,9 @@ func NewOracle(backend OracleBackend, params Config) *Oracle { maxBlockHistory = 1 log.Warn("Sanitizing invalid gasprice oracle max block history", "provided", params.MaxBlockHistory, "updated", maxBlockHistory) } + if startPrice == nil { + startPrice = new(big.Int) + } cache := lru.NewCache[cacheKey, processedFees](2048) headEvent := make(chan core.ChainHeadEvent, 1) @@ -131,7 +133,7 @@ func NewOracle(backend OracleBackend, params Config) *Oracle { return &Oracle{ backend: backend, - lastPrice: params.Default, + lastPrice: startPrice, maxPrice: maxPrice, ignorePrice: ignorePrice, checkBlocks: blocks, diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index b22e75666fb9..39f3c79b98e4 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -235,7 +235,6 @@ func TestSuggestTipCap(t *testing.T) { config := Config{ Blocks: 3, Percentile: 60, - Default: big.NewInt(params.GWei), } var cases = []struct { fork *big.Int // London fork number @@ -249,7 +248,7 @@ func TestSuggestTipCap(t *testing.T) { } for _, c := range cases { backend := newTestBackend(t, c.fork, nil, false) - oracle := NewOracle(backend, config) + oracle := NewOracle(backend, config, big.NewInt(params.GWei)) // The gas price sampled is: 32G, 31G, 30G, 29G, 28G, 27G got, err := oracle.SuggestTipCap(context.Background()) From 7abe84c8d724c1f92ca6f41ac6da72870c886ba0 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:38:04 -0600 Subject: [PATCH 422/571] rpc: use stable object in notifier test (#30193) This makes the test resilient to changes of types.Header -- otherwise the test needs to be updated each time the header structure is modified. --- rpc/subscription_test.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index a7dac705c959..ab40ab169ff6 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -267,13 +267,9 @@ func TestNotify(t *testing.T) { sub: &Subscription{ID: id}, activated: true, } - msg := &types.Header{ - ParentHash: common.HexToHash("0x01"), - Number: big.NewInt(100), - } - notifier.Notify(id, msg) + notifier.Notify(id, "hello") have := strings.TrimSpace(out.String()) - want := `{"jsonrpc":"2.0","method":"_subscription","params":{"subscription":"test","result":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000001","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":null,"number":"0x64","gasLimit":"0x0","gasUsed":"0x0","timestamp":"0x0","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":null,"withdrawalsRoot":null,"blobGasUsed":null,"excessBlobGas":null,"parentBeaconBlockRoot":null,"hash":"0xe5fb877dde471b45b9742bb4bb4b3d74a761e2fb7cb849a3d2b687eed90fb604"}}}` + want := `{"jsonrpc":"2.0","method":"_subscription","params":{"subscription":"test","result":"hello"}}` if have != want { t.Errorf("have:\n%v\nwant:\n%v\n", have, want) } From ef583e9d18a98dfea8dad9f027c9d8a989591579 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 23 Jul 2024 05:44:31 +0800 Subject: [PATCH 423/571] core/state: remove useless metrics (#30184) Originally, these metrics were added to track the largest storage wiping. Since account self-destruction was deprecated with the Cancun fork, these metrics have become meaningless. --- core/state/metrics.go | 6 ------ core/state/statedb.go | 46 +++++++++++++------------------------------ 2 files changed, 14 insertions(+), 38 deletions(-) diff --git a/core/state/metrics.go b/core/state/metrics.go index 7447e44dfd1e..e702ef3a81a6 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -27,10 +27,4 @@ var ( storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil) accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil) storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil) - - slotDeletionMaxCount = metrics.NewRegisteredGauge("state/delete/storage/max/slot", nil) - slotDeletionMaxSize = metrics.NewRegisteredGauge("state/delete/storage/max/size", nil) - slotDeletionTimer = metrics.NewRegisteredResettingTimer("state/delete/storage/timer", nil) - slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil) - slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil) ) diff --git a/core/state/statedb.go b/core/state/statedb.go index 641775b0bdfc..0bd6b37d04c8 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -992,76 +992,70 @@ func (s *StateDB) clearJournalAndRefund() { // of a specific account. It leverages the associated state snapshot for fast // storage iteration and constructs trie node deletion markers by creating // stack trie with iterated slots. -func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { +func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { iter, err := s.snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{}) if err != nil { - return 0, nil, nil, err + return nil, nil, err } defer iter.Release() var ( - size common.StorageSize nodes = trienode.NewNodeSet(addrHash) slots = make(map[common.Hash][]byte) ) stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { nodes.AddNode(path, trienode.NewDeleted()) - size += common.StorageSize(len(path)) }) for iter.Next() { slot := common.CopyBytes(iter.Slot()) if err := iter.Error(); err != nil { // error might occur after Slot function - return 0, nil, nil, err + return nil, nil, err } - size += common.StorageSize(common.HashLength + len(slot)) slots[iter.Hash()] = slot if err := stack.Update(iter.Hash().Bytes(), slot); err != nil { - return 0, nil, nil, err + return nil, nil, err } } if err := iter.Error(); err != nil { // error might occur during iteration - return 0, nil, nil, err + return nil, nil, err } if stack.Hash() != root { - return 0, nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash()) + return nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash()) } - return size, slots, nodes, nil + return slots, nodes, nil } // slowDeleteStorage serves as a less-efficient alternative to "fastDeleteStorage," // employed when the associated state snapshot is not available. It iterates the // storage slots along with all internal trie nodes via trie directly. -func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { +func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root, s.trie) if err != nil { - return 0, nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err) + return nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err) } it, err := tr.NodeIterator(nil) if err != nil { - return 0, nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err) + return nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err) } var ( - size common.StorageSize nodes = trienode.NewNodeSet(addrHash) slots = make(map[common.Hash][]byte) ) for it.Next(true) { if it.Leaf() { slots[common.BytesToHash(it.LeafKey())] = common.CopyBytes(it.LeafBlob()) - size += common.StorageSize(common.HashLength + len(it.LeafBlob())) continue } if it.Hash() == (common.Hash{}) { continue } - size += common.StorageSize(len(it.Path())) nodes.AddNode(it.Path(), trienode.NewDeleted()) } if err := it.Error(); err != nil { - return 0, nil, nil, err + return nil, nil, err } - return size, slots, nodes, nil + return slots, nodes, nil } // deleteStorage is designed to delete the storage trie of a designated account. @@ -1070,9 +1064,7 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r // efficient approach. func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { var ( - start = time.Now() err error - size common.StorageSize slots map[common.Hash][]byte nodes *trienode.NodeSet ) @@ -1080,24 +1072,14 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root // generated, or it's internally corrupted. Fallback to the slow // one just in case. if s.snap != nil { - size, slots, nodes, err = s.fastDeleteStorage(addrHash, root) + slots, nodes, err = s.fastDeleteStorage(addrHash, root) } if s.snap == nil || err != nil { - size, slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) + slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) } if err != nil { return nil, nil, err } - // Report the metrics - n := int64(len(slots)) - - slotDeletionMaxCount.UpdateIfGt(int64(len(slots))) - slotDeletionMaxSize.UpdateIfGt(int64(size)) - - slotDeletionTimer.UpdateSince(start) - slotDeletionCount.Mark(n) - slotDeletionSize.Mark(int64(size)) - return slots, nodes, nil } From 57e662793287651dcfd36c52fb40a83c54682810 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 23 Jul 2024 17:55:56 +0800 Subject: [PATCH 424/571] rpc: show more error detail for `invalidMessageError` (#30191) Here we add distinct error messages for network timeouts and JSON parsing errors. Note this specifically applies to HTTP connections serving a single RPC request. Co-authored-by: Felix Lange --- rpc/server.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/rpc/server.go b/rpc/server.go index 52866004f826..42b59f8f6f7f 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -18,7 +18,9 @@ package rpc import ( "context" + "errors" "io" + "net" "sync" "sync/atomic" @@ -151,8 +153,8 @@ func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { reqs, batch, err := codec.readBatch() if err != nil { - if err != io.EOF { - resp := errorMessage(&invalidMessageError{"parse error"}) + if msg := messageForReadError(err); msg != "" { + resp := errorMessage(&invalidMessageError{msg}) codec.writeJSON(ctx, resp, true) } return @@ -164,6 +166,20 @@ func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { } } +func messageForReadError(err error) string { + var netErr net.Error + if errors.As(err, &netErr) { + if netErr.Timeout() { + return "read timeout" + } else { + return "read error" + } + } else if err != io.EOF { + return "parse error" + } + return "" +} + // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending // requests to finish, then closes all codecs which will cancel pending requests and // subscriptions. From 7026bae17c8d2fcf0b6ee134528c1a6b6e00c60c Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:05:46 +0200 Subject: [PATCH 425/571] core/tracing: update latest release version (#30211) --- core/tracing/CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/tracing/CHANGELOG.md b/core/tracing/CHANGELOG.md index 93b91cf479b5..cddc728fc0f1 100644 --- a/core/tracing/CHANGELOG.md +++ b/core/tracing/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the tracing interface will be documented in this file. -## [Unreleased] +## [v1.14.3] There have been minor backwards-compatible changes to the tracing interface to explicitly mark the execution of **system** contracts. As of now the only system call updates the parent beacon block root as per [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). Other system calls are being considered for the future hardfork. @@ -76,4 +76,5 @@ The hooks `CaptureStart` and `CaptureEnd` have been removed. These hooks signale - `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above. [unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.0...master -[v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0 \ No newline at end of file +[v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0 +[v1.14.3]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.3 From 6693fe1be277d5c20cc39d82085dad0d5bebaa16 Mon Sep 17 00:00:00 2001 From: minh-bq <97180373+minh-bq@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:07:06 +0700 Subject: [PATCH 426/571] core/txpool: use the cached address in ValidateTransactionWithState (#30208) The address recover is executed and cached in ValidateTransaction already. It's expected that the cached one is returned in ValidateTransaction. However, currently, we use the wrong function signer.Sender instead of types.Sender which will do all the address recover again. --- core/txpool/validation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 555b777505cf..7fd5f8bc79e6 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -201,7 +201,7 @@ type ValidationOptionsWithState struct { // rules without duplicating code and running the risk of missed updates. func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, opts *ValidationOptionsWithState) error { // Ensure the transaction adheres to nonce ordering - from, err := signer.Sender(tx) // already validated (and cached), but cleaner to check + from, err := types.Sender(signer, tx) // already validated (and cached), but cleaner to check if err != nil { log.Error("Transaction sender recovery failed", "err", err) return err From 1939813ece995084e3b7c55b46324d98219494a8 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 23 Jul 2024 20:40:12 +0800 Subject: [PATCH 427/571] core/state: check db error after intermediate call (#30171) This pull request adds an additional error check after statedb.IntermediateRoot, ensuring that no errors occur during this call. This step is essential, as the call might encounter database errors. --- core/state/statedb.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/state/statedb.go b/core/state/statedb.go index 0bd6b37d04c8..f0de73733ab1 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1158,6 +1158,10 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { // Finalize any pending changes and merge everything into the tries s.IntermediateRoot(deleteEmptyObjects) + // Short circuit if any error occurs within the IntermediateRoot. + if s.dbErr != nil { + return nil, fmt.Errorf("commit aborted due to database error: %v", s.dbErr) + } // Commit objects to the trie, measuring the elapsed time var ( accountTrieNodesUpdated int From 35b4183caa59ddd6973606900b100523a090b0c1 Mon Sep 17 00:00:00 2001 From: minh-bq <97180373+minh-bq@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:44:01 +0700 Subject: [PATCH 428/571] cmd/utils: allow configurating blob pool from flags (#30203) Currently, we have 3 flags to configure blob pool. However, we don't read these flags and set the blob pool configuration in eth config accordingly. This commit adds a function to check if these flags are provided and set blob pool configuration based on them. --- cmd/utils/flags.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 96a3cf55bb7d..b9fa3b8b4e5a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -42,6 +42,7 @@ import ( "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -1550,6 +1551,18 @@ func setTxPool(ctx *cli.Context, cfg *legacypool.Config) { } } +func setBlobPool(ctx *cli.Context, cfg *blobpool.Config) { + if ctx.IsSet(BlobPoolDataDirFlag.Name) { + cfg.Datadir = ctx.String(BlobPoolDataDirFlag.Name) + } + if ctx.IsSet(BlobPoolDataCapFlag.Name) { + cfg.Datacap = ctx.Uint64(BlobPoolDataCapFlag.Name) + } + if ctx.IsSet(BlobPoolPriceBumpFlag.Name) { + cfg.PriceBump = ctx.Uint64(BlobPoolPriceBumpFlag.Name) + } +} + func setMiner(ctx *cli.Context, cfg *miner.Config) { if ctx.Bool(MiningEnabledFlag.Name) { log.Warn("The flag --mine is deprecated and will be removed") @@ -1651,6 +1664,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { setEtherbase(ctx, cfg) setGPO(ctx, &cfg.GPO) setTxPool(ctx, &cfg.TxPool) + setBlobPool(ctx, &cfg.BlobPool) setMiner(ctx, &cfg.Miner) setRequiredBlocks(ctx, cfg) setLes(ctx, cfg) From 766ce23032deae2519322b705e87c7a2ea9f1317 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 23 Jul 2024 20:54:35 +0800 Subject: [PATCH 429/571] core/state: fix SetStorage override behavior (#30185) This pull request fixes the broken feature where the entire storage set is overridden. Originally, the storage set override was achieved by marking the associated account as deleted, preventing access to the storage slot on disk. However, since #29520, this flag is also checked when accessing the account, rendering the account unreachable. A fix has been applied in this pull request, which re-creates a new state object with all account metadata inherited. --- core/state/statedb.go | 28 ++++++++++++++++++---------- internal/ethapi/api_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index f0de73733ab1..80a53dbb1772 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -471,20 +471,28 @@ func (s *StateDB) SetState(addr common.Address, key, value common.Hash) { // storage. This function should only be used for debugging and the mutations // must be discarded afterwards. func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) { - // SetStorage needs to wipe existing storage. We achieve this by pretending - // that the account self-destructed earlier in this block, by flagging - // it in stateObjectsDestruct. The effect of doing so is that storage lookups - // will not hit disk, since it is assumed that the disk-data is belonging + // SetStorage needs to wipe the existing storage. We achieve this by marking + // the account as self-destructed in this block. The effect is that storage + // lookups will not hit the disk, as it is assumed that the disk data belongs // to a previous incarnation of the object. // - // TODO(rjl493456442) this function should only be supported by 'unwritable' - // state and all mutations made should all be discarded afterwards. - if _, ok := s.stateObjectsDestruct[addr]; !ok { - s.stateObjectsDestruct[addr] = nil + // TODO (rjl493456442): This function should only be supported by 'unwritable' + // state, and all mutations made should be discarded afterward. + obj := s.getStateObject(addr) + if obj != nil { + if _, ok := s.stateObjectsDestruct[addr]; !ok { + s.stateObjectsDestruct[addr] = obj + } } - stateObject := s.getOrNewStateObject(addr) + newObj := s.createObject(addr) for k, v := range storage { - stateObject.SetState(k, v) + newObj.SetState(k, v) + } + // Inherit the metadata of original object if it was existent + if obj != nil { + newObj.SetCode(common.BytesToHash(obj.CodeHash()), obj.code) + newObj.SetNonce(obj.Nonce()) + newObj.SetBalance(obj.Balance(), tracing.BalanceChangeUnspecified) } } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index cf5160caf778..b4041fc84ce3 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -781,15 +781,24 @@ func TestEstimateGas(t *testing.T) { func TestCall(t *testing.T) { t.Parallel() + // Initialize test accounts var ( accounts = newAccounts(3) + dad = common.HexToAddress("0x0000000000000000000000000000000000000dad") genesis = &core.Genesis{ Config: params.MergedTestChainConfig, Alloc: types.GenesisAlloc{ accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)}, accounts[2].addr: {Balance: big.NewInt(params.Ether)}, + dad: { + Balance: big.NewInt(params.Ether), + Nonce: 1, + Storage: map[common.Hash]common.Hash{ + common.Hash{}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"), + }, + }, }, } genBlocks = 10 @@ -949,6 +958,32 @@ func TestCall(t *testing.T) { }, want: "0x0122000000000000000000000000000000000000000000000000000000000000", }, + // Clear the entire storage set + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[1].addr, + // Yul: + // object "Test" { + // code { + // let dad := 0x0000000000000000000000000000000000000dad + // if eq(balance(dad), 0) { + // revert(0, 0) + // } + // let slot := sload(0) + // mstore(0, slot) + // return(0, 32) + // } + // } + Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"), + }, + overrides: StateOverride{ + dad: OverrideAccount{ + State: &map[common.Hash]common.Hash{}, + }, + }, + want: "0x0000000000000000000000000000000000000000000000000000000000000000", + }, } for i, tc := range testSuite { result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) From 4ad88e9463090a6363be5ed8dca733c890e91b7b Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 24 Jul 2024 20:32:28 +0800 Subject: [PATCH 430/571] triedb/pathdb: print out all trie owner and hash information (#30200) This pull request explicitly prints out the full hash for debugging purpose. --- triedb/pathdb/reader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triedb/pathdb/reader.go b/triedb/pathdb/reader.go index 54dc98a5437d..6a58493ba694 100644 --- a/triedb/pathdb/reader.go +++ b/triedb/pathdb/reader.go @@ -78,7 +78,7 @@ func (r *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, if len(blob) > 0 { blobHex = hexutil.Encode(blob) } - log.Error("Unexpected trie node", "location", loc.loc, "owner", owner, "path", path, "expect", hash, "got", got, "blob", blobHex) + log.Error("Unexpected trie node", "location", loc.loc, "owner", owner.Hex(), "path", path, "expect", hash.Hex(), "got", got.Hex(), "blob", blobHex) return nil, fmt.Errorf("unexpected node: (%x %v), %x!=%x, %s, blob: %s", owner, path, hash, got, loc.string(), blobHex) } return blob, nil From 4dfc75deefd2d68fba682d089d9ae61771c19d66 Mon Sep 17 00:00:00 2001 From: yukionfire Date: Thu, 25 Jul 2024 06:32:58 +0800 Subject: [PATCH 431/571] beacon/types, cmd/devp2p, p2p/enr: clean up uses of fmt.Errorf (#30182) --- beacon/types/beacon_block.go | 2 +- beacon/types/exec_header.go | 2 +- cmd/devp2p/rlpxcmd.go | 2 +- p2p/enr/entries.go | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/beacon/types/beacon_block.go b/beacon/types/beacon_block.go index 370152114a45..e4cd1340e528 100644 --- a/beacon/types/beacon_block.go +++ b/beacon/types/beacon_block.go @@ -48,7 +48,7 @@ func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) { case "capella": obj = new(capella.BeaconBlock) default: - return nil, fmt.Errorf("unsupported fork: " + forkName) + return nil, fmt.Errorf("unsupported fork: %s", forkName) } if err := json.Unmarshal(data, obj); err != nil { return nil, err diff --git a/beacon/types/exec_header.go b/beacon/types/exec_header.go index dce101ba2009..b5f90bae2561 100644 --- a/beacon/types/exec_header.go +++ b/beacon/types/exec_header.go @@ -46,7 +46,7 @@ func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, er case "deneb": obj = new(deneb.ExecutionPayloadHeader) default: - return nil, fmt.Errorf("unsupported fork: " + forkName) + return nil, fmt.Errorf("unsupported fork: %s", forkName) } if err := json.Unmarshal(data, obj); err != nil { return nil, err diff --git a/cmd/devp2p/rlpxcmd.go b/cmd/devp2p/rlpxcmd.go index 77f09e6b85af..118731fd6c54 100644 --- a/cmd/devp2p/rlpxcmd.go +++ b/cmd/devp2p/rlpxcmd.go @@ -79,7 +79,7 @@ func rlpxPing(ctx *cli.Context) error { n := getNodeArg(ctx) tcpEndpoint, ok := n.TCPEndpoint() if !ok { - return fmt.Errorf("node has no TCP endpoint") + return errors.New("node has no TCP endpoint") } fd, err := net.Dial("tcp", tcpEndpoint.String()) if err != nil { diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index 917e1becbaac..155ec4c02320 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -177,7 +177,7 @@ func (v IPv4Addr) ENRKey() string { return "ip" } func (v IPv4Addr) EncodeRLP(w io.Writer) error { addr := netip.Addr(v) if !addr.Is4() { - return fmt.Errorf("address is not IPv4") + return errors.New("address is not IPv4") } enc := rlp.NewEncoderBuffer(w) bytes := addr.As4() @@ -204,7 +204,7 @@ func (v IPv6Addr) ENRKey() string { return "ip6" } func (v IPv6Addr) EncodeRLP(w io.Writer) error { addr := netip.Addr(v) if !addr.Is6() { - return fmt.Errorf("address is not IPv6") + return errors.New("address is not IPv6") } enc := rlp.NewEncoderBuffer(w) bytes := addr.As16() From ac0f220040bd4271a040170bc0b039eb88dee9bd Mon Sep 17 00:00:00 2001 From: caseylove Date: Thu, 25 Jul 2024 07:01:59 +0800 Subject: [PATCH 432/571] eth/tracers, internal/ethapi: remove unnecessary map pointer in state override (#30094) --- eth/tracers/api_test.go | 10 +++++----- internal/ethapi/api.go | 16 ++++++++-------- internal/ethapi/api_test.go | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 6fbb50848d63..e717f5352d7e 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -843,7 +843,7 @@ func TestTracingWithOverrides(t *testing.T) { byte(vm.PUSH1), 00, byte(vm.RETURN), }), - StateDiff: &map[common.Hash]common.Hash{ + StateDiff: map[common.Hash]common.Hash{ common.HexToHash("0x03"): common.HexToHash("0x11"), }, }, @@ -898,9 +898,9 @@ func newAccounts(n int) (accounts []Account) { return accounts } -func newRPCBalance(balance *big.Int) **hexutil.Big { +func newRPCBalance(balance *big.Int) *hexutil.Big { rpcBalance := (*hexutil.Big)(balance) - return &rpcBalance + return rpcBalance } func newRPCBytes(bytes []byte) *hexutil.Bytes { @@ -908,7 +908,7 @@ func newRPCBytes(bytes []byte) *hexutil.Bytes { return &rpcBytes } -func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.Hash { +func newStates(keys []common.Hash, vals []common.Hash) map[common.Hash]common.Hash { if len(keys) != len(vals) { panic("invalid input") } @@ -916,7 +916,7 @@ func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.H for i := 0; i < len(keys); i++ { m[keys[i]] = vals[i] } - return &m + return m } func TestTraceChain(t *testing.T) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 0ecedf113038..1c3cb4adf936 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -968,11 +968,11 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp // if stateDiff is set, all diff will be applied first and then execute the call // message. type OverrideAccount struct { - Nonce *hexutil.Uint64 `json:"nonce"` - Code *hexutil.Bytes `json:"code"` - Balance **hexutil.Big `json:"balance"` - State *map[common.Hash]common.Hash `json:"state"` - StateDiff *map[common.Hash]common.Hash `json:"stateDiff"` + Nonce *hexutil.Uint64 `json:"nonce"` + Code *hexutil.Bytes `json:"code"` + Balance *hexutil.Big `json:"balance"` + State map[common.Hash]common.Hash `json:"state"` + StateDiff map[common.Hash]common.Hash `json:"stateDiff"` } // StateOverride is the collection of overridden accounts. @@ -994,7 +994,7 @@ func (diff *StateOverride) Apply(statedb *state.StateDB) error { } // Override account balance. if account.Balance != nil { - u256Balance, _ := uint256.FromBig((*big.Int)(*account.Balance)) + u256Balance, _ := uint256.FromBig((*big.Int)(account.Balance)) statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified) } if account.State != nil && account.StateDiff != nil { @@ -1002,11 +1002,11 @@ func (diff *StateOverride) Apply(statedb *state.StateDB) error { } // Replace entire state if caller requires. if account.State != nil { - statedb.SetStorage(addr, *account.State) + statedb.SetStorage(addr, account.State) } // Apply state diff into specified accounts. if account.StateDiff != nil { - for key, value := range *account.StateDiff { + for key, value := range account.StateDiff { statedb.SetState(addr, key, value) } } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index b4041fc84ce3..e867f572847a 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -913,7 +913,7 @@ func TestCall(t *testing.T) { overrides: StateOverride{ randomAccounts[2].addr: OverrideAccount{ Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"), - StateDiff: &map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))}, + StateDiff: map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))}, }, }, want: "0x000000000000000000000000000000000000000000000000000000000000007b", @@ -1343,9 +1343,9 @@ func newAccounts(n int) (accounts []account) { return accounts } -func newRPCBalance(balance *big.Int) **hexutil.Big { +func newRPCBalance(balance *big.Int) *hexutil.Big { rpcBalance := (*hexutil.Big)(balance) - return &rpcBalance + return rpcBalance } func hex2Bytes(str string) *hexutil.Bytes { From f94baab238a64895e78034522092e935628c6c74 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:02:37 -0600 Subject: [PATCH 433/571] internal/ethapi: fix state override test (#30228) Looks like #30094 became a bit stale after #30185 was merged and now we have a stale ref to a state override object causing CI to fail on master. --- internal/ethapi/api_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index e867f572847a..7465fb55295f 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -979,7 +979,7 @@ func TestCall(t *testing.T) { }, overrides: StateOverride{ dad: OverrideAccount{ - State: &map[common.Hash]common.Hash{}, + State: map[common.Hash]common.Hash{}, }, }, want: "0x0000000000000000000000000000000000000000000000000000000000000000", From b0f66e34ca2a4ea7ae23475224451c8c9a569826 Mon Sep 17 00:00:00 2001 From: dknopik <107140945+dknopik@users.noreply.github.com> Date: Sat, 27 Jul 2024 10:18:05 +0200 Subject: [PATCH 434/571] p2p/nat: return correct port for ExtIP NAT (#30234) Return the actually requested external port instead of 0 in the AddMapping implementation for `--nat extip:`. --- p2p/nat/nat.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index 2aa1f855852a..c65604426833 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -138,8 +138,10 @@ func (n ExtIP) String() string { return fmt.Sprintf("ExtIP(%v)", ne // These do nothing. -func (ExtIP) AddMapping(string, int, int, string, time.Duration) (uint16, error) { return 0, nil } -func (ExtIP) DeleteMapping(string, int, int) error { return nil } +func (ExtIP) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) { + return uint16(extport), nil +} +func (ExtIP) DeleteMapping(string, int, int) error { return nil } // Any returns a port mapper that tries to discover any supported // mechanism on the local network. From 6e33dbf96a06cb3ad3bdbd5d0539e54de254ce6b Mon Sep 17 00:00:00 2001 From: Marius G <90795310+bearpebble@users.noreply.github.com> Date: Tue, 30 Jul 2024 15:31:27 +0200 Subject: [PATCH 435/571] p2p: fix flaky test TestServerPortMapping (#30241) The test specifies `ListenAddr: ":0"`, which means a random ephemeral port will be chosen for the TCP listener by the OS. Additionally, since no `DiscAddr` was specified, the same port that is chosen automatically by the OS will also be used for the UDP listener in the discovery UDP setup. This sometimes leads to test failures if the TCP listener picks a free TCP port that is already taken for UDP. By specifying `DiscAddr: ":0"`, the UDP port will be chosen independently from the TCP port, fixing the random failure. See issue #29830. Verified using ``` cd p2p go test -c -race stress ./p2p.test -test.run=TestServerPortMapping ... 5m0s: 4556 runs so far, 0 failures ``` The issue described above can technically lead to sporadic failures on systems that specify a listen address via the `--port` flag of 0 while not setting `--discovery.port`. Since the default is using port `30303` and using a random ephemeral port is likely not used much to begin with, not addressing the root cause might be acceptable. --- p2p/server_nat_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/p2p/server_nat_test.go b/p2p/server_nat_test.go index cbb1f37e0a6a..7e193872104a 100644 --- a/p2p/server_nat_test.go +++ b/p2p/server_nat_test.go @@ -36,6 +36,7 @@ func TestServerPortMapping(t *testing.T) { PrivateKey: newkey(), NoDial: true, ListenAddr: ":0", + DiscAddr: ":0", NAT: mockNAT, Logger: testlog.Logger(t, log.LvlTrace), clock: clock, From de6d5976794a9ed3b626d4eba57bf7f0806fb970 Mon Sep 17 00:00:00 2001 From: Daniel Knopik <107140945+dknopik@users.noreply.github.com> Date: Wed, 31 Jul 2024 21:38:23 +0200 Subject: [PATCH 436/571] p2p/discover: schedule revalidation also when all nodes are excluded (#30239) ## Issue If `nextTime` has passed, but all nodes are excluded, `get` would return `nil` and `run` would therefore not invoke `schedule`. Then, we schedule a timer for the past, as neither `nextTime` value has been updated. This creates a busy loop, as the timer immediately returns. ## Fix With this PR, revalidation will be also rescheduled when all nodes are excluded. --------- Co-authored-by: lightclient --- p2p/discover/table_reval.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index f2ea8b34fa3e..2465fee9066f 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -77,14 +77,18 @@ func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *tableNode) { // It returns the next time it should be invoked, which is used in the Table main loop // to schedule a timer. However, run can be called at any time. func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mclock.AbsTime) { - if n := tr.fast.get(now, &tab.rand, tr.activeReq); n != nil { - tr.startRequest(tab, n) - tr.fast.schedule(now, &tab.rand) - } - if n := tr.slow.get(now, &tab.rand, tr.activeReq); n != nil { - tr.startRequest(tab, n) - tr.slow.schedule(now, &tab.rand) + reval := func(list *revalidationList) { + if list.nextTime <= now { + if n := list.get(now, &tab.rand, tr.activeReq); n != nil { + tr.startRequest(tab, n) + } + // Update nextTime regardless if any requests were started because + // current value has passed. + list.schedule(now, &tab.rand) + } } + reval(&tr.fast) + reval(&tr.slow) return min(tr.fast.nextTime, tr.slow.nextTime) } @@ -200,7 +204,7 @@ type revalidationList struct { // get returns a random node from the queue. Nodes in the 'exclude' map are not returned. func (list *revalidationList) get(now mclock.AbsTime, rand randomSource, exclude map[enode.ID]struct{}) *tableNode { - if now < list.nextTime || len(list.nodes) == 0 { + if len(list.nodes) == 0 { return nil } for i := 0; i < len(list.nodes)*3; i++ { From ff6e43e8c4db9f6d8afa7887ae9d2081c2c890d0 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Thu, 1 Aug 2024 07:06:43 -0700 Subject: [PATCH 437/571] miner: remove outdated comment (#30248) --- miner/worker.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 5dc3e2056b81..9aae6e16099d 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -205,8 +205,7 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) // makeEnv creates a new environment for the sealing block. func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address) (*environment, error) { - // Retrieve the parent state to execute on top and start a prefetcher for - // the miner to speed block sealing up a bit. + // Retrieve the parent state to execute on top. state, err := miner.chain.StateAt(parent.Root) if err != nil { return nil, err From dad8f237ffa5da2c2471f2d9f32d2bc5b580f667 Mon Sep 17 00:00:00 2001 From: Seungmin Kim Date: Thu, 1 Aug 2024 23:10:43 +0900 Subject: [PATCH 438/571] eth/downloader: correct sync mode logging to show old mode (#30219) This PR fixes an issue in the setMode method of beaconBackfiller where the log message was not displaying the previous mode correctly. The log message now shows both the old and new sync modes. --- eth/downloader/beaconsync.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 57c6eee40a0b..5ef3f91dc788 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -123,7 +123,8 @@ func (b *beaconBackfiller) resume() { func (b *beaconBackfiller) setMode(mode SyncMode) { // Update the old sync mode and track if it was changed b.lock.Lock() - updated := b.syncMode != mode + oldMode := b.syncMode + updated := oldMode != mode filling := b.filling b.syncMode = mode b.lock.Unlock() @@ -133,8 +134,8 @@ func (b *beaconBackfiller) setMode(mode SyncMode) { if !updated || !filling { return } - log.Error("Downloader sync mode changed mid-run", "old", mode.String(), "new", mode.String()) - b.suspend() + log.Error("Downloader sync mode changed mid-run", "old", oldMode.String(), "new", mode.String()) + b.suspend() b.resume() } From b635089c7c7b4d9ae840e2052cf9f086109242ee Mon Sep 17 00:00:00 2001 From: Icarus Wu Date: Thu, 1 Aug 2024 22:25:55 +0800 Subject: [PATCH 439/571] all: remove deprecated protobuf dependencies (#30232) The package `github.com/golang/protobuf/proto` is deprecated in favor `google.golang.org/protobuf/proto`. We should update the codes to recommended package. Signed-off-by: Icarus Wu --- .golangci.yml | 4 ---- Makefile | 2 +- accounts/usbwallet/trezor.go | 2 +- accounts/usbwallet/trezor/trezor.go | 6 +++--- build/tools/tools.go | 2 +- go.mod | 4 ++-- go.sum | 2 ++ 7 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 2132f5403ab7..75452472d026 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -64,10 +64,6 @@ issues: text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - path: core/vm/contracts.go text: 'SA1019: "golang.org/x/crypto/ripemd160" is deprecated: RIPEMD-160 is a legacy hash and should not be used for new applications.' - - path: accounts/usbwallet/trezor.go - text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.' - - path: accounts/usbwallet/trezor/ - text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.' exclude: - 'SA1019: event.TypeMux is deprecated: use Feed' - 'SA1019: strings.Title is deprecated' diff --git a/Makefile b/Makefile index 857cb8c97899..f4932165a482 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ clean: devtools: env GOBIN= go install golang.org/x/tools/cmd/stringer@latest env GOBIN= go install github.com/fjl/gencodec@latest - env GOBIN= go install github.com/golang/protobuf/protoc-gen-go@latest + env GOBIN= go install google.golang.org/protobuf/cmd/protoc-gen-go@latest env GOBIN= go install ./cmd/abigen @type "solc" 2> /dev/null || echo 'Please install solc' @type "protoc" 2> /dev/null || echo 'Please install protoc' diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index 9644dc4e02c9..1c4270d255c6 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -33,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" - "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/proto" ) // ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In diff --git a/accounts/usbwallet/trezor/trezor.go b/accounts/usbwallet/trezor/trezor.go index 432425831437..93aee3c2899e 100644 --- a/accounts/usbwallet/trezor/trezor.go +++ b/accounts/usbwallet/trezor/trezor.go @@ -39,8 +39,8 @@ // - 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/...` +// - Grab the latest Go plugin `go get -u google.golang.org/protobuf/cmd/protoc-gen-go` +// - Vendor in the latest Go plugin `govendor fetch google.golang.org/protobuf/...` //go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto @@ -50,7 +50,7 @@ package trezor import ( "reflect" - "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/proto" ) // Type returns the protocol buffer type number of a specific message. If the diff --git a/build/tools/tools.go b/build/tools/tools.go index 506e26eeff74..e9e2241d2fe8 100644 --- a/build/tools/tools.go +++ b/build/tools/tools.go @@ -22,6 +22,6 @@ package tools import ( // Tool imports for go:generate. _ "github.com/fjl/gencodec" - _ "github.com/golang/protobuf/protoc-gen-go" _ "golang.org/x/tools/cmd/stringer" + _ "google.golang.org/protobuf/cmd/protoc-gen-go" ) diff --git a/go.mod b/go.mod index db5c71349864..5a0314d635a0 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,6 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.5.0 - github.com/golang/protobuf v1.5.4 github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/google/gofuzz v1.2.0 github.com/google/uuid v1.3.0 @@ -74,7 +73,7 @@ require ( golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.20.0 - google.golang.org/protobuf v1.33.0 + google.golang.org/protobuf v1.34.2 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -112,6 +111,7 @@ require ( github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect diff --git a/go.sum b/go.sum index e3cf5f3d63b9..465e98f337a9 100644 --- a/go.sum +++ b/go.sum @@ -842,6 +842,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 67b81371008d147aa2ccebd3fa9655fe042b0f14 Mon Sep 17 00:00:00 2001 From: ysh0566 Date: Fri, 2 Aug 2024 02:09:04 +0800 Subject: [PATCH 440/571] accounts/abi/bind: add accessList support to base bond contract (#30195) Adding the correct accessList parameter when calling a contract can reduce gas consumption. However, the current version only allows adding the accessList manually when constructing the transaction. This PR can provide convenience for saving gas. --- accounts/abi/bind/base.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index c8972a9dff2a..0504089c7173 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -59,11 +59,12 @@ type TransactOpts struct { Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state) Signer SignerFn // Method to use for signing the transaction (mandatory) - Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds) - GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) - GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle) - GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle) - GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) + Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds) + GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) + GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle) + GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle) + GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) + AccessList types.AccessList // Access list to set for the transaction execution (nil = no access list) Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) @@ -300,20 +301,21 @@ func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Add return nil, err } baseTx := &types.DynamicFeeTx{ - To: contract, - Nonce: nonce, - GasFeeCap: gasFeeCap, - GasTipCap: gasTipCap, - Gas: gasLimit, - Value: value, - Data: input, + To: contract, + Nonce: nonce, + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + Gas: gasLimit, + Value: value, + Data: input, + AccessList: opts.AccessList, } return types.NewTx(baseTx), nil } func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { - if opts.GasFeeCap != nil || opts.GasTipCap != nil { - return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") + if opts.GasFeeCap != nil || opts.GasTipCap != nil || opts.AccessList != nil { + return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas or accessList specified but london is not active yet") } // Normalize value value := opts.Value From e4675771eda550e7eeb63a8884816982c1980644 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 2 Aug 2024 06:44:03 +0200 Subject: [PATCH 441/571] internal/debug: remove memsize (#30253) Removing because memsize will very likely be broken by Go 1.23. See https://github.com/fjl/memsize/issues/4 --- cmd/geth/main.go | 2 -- go.mod | 1 - go.sum | 2 -- internal/debug/flags.go | 4 ---- 4 files changed, 9 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index f6bb09ee54a5..a37bb5f98789 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -360,8 +360,6 @@ func geth(ctx *cli.Context) error { // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the // miner. func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) { - debug.Memsize.Add("node", stack) - // Start up the node itself utils.StartNode(ctx, stack, isConsole) diff --git a/go.mod b/go.mod index 5a0314d635a0..3e9837186d89 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,6 @@ require ( github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.2 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e - github.com/fjl/memsize v0.0.2 github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gofrs/flock v0.8.1 diff --git a/go.sum b/go.sum index 465e98f337a9..d8e7a540c70a 100644 --- a/go.sum +++ b/go.sum @@ -178,8 +178,6 @@ github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNP github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= -github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= -github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 19222c8325f9..0e05975c7e07 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -31,15 +31,12 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics/exp" - "github.com/fjl/memsize/memsizeui" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" "gopkg.in/natefinch/lumberjack.v2" ) -var Memsize memsizeui.Handler - var ( verbosityFlag = &cli.IntFlag{ Name: "verbosity", @@ -313,7 +310,6 @@ func StartPProf(address string, withMetrics bool) { if withMetrics { exp.Exp(metrics.DefaultRegistry) } - http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) go func() { if err := http.ListenAndServe(address, nil); err != nil { From 16cf5c5fed9f8f22ef31fcdb0057aa4ad4ea3a12 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 2 Aug 2024 17:36:28 +0200 Subject: [PATCH 442/571] eth/downloader: gofmt (#30261) Fixes a regression introduced in https://github.com/ethereum/go-ethereum/pull/30219 --- eth/downloader/beaconsync.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 5ef3f91dc788..e682536e075d 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -135,7 +135,7 @@ func (b *beaconBackfiller) setMode(mode SyncMode) { return } log.Error("Downloader sync mode changed mid-run", "old", oldMode.String(), "new", mode.String()) - b.suspend() + b.suspend() b.resume() } From 142c94d62842c7801e8f4d71f080ae156ecd1f2b Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Fri, 2 Aug 2024 09:49:01 -0600 Subject: [PATCH 443/571] cmd/evm: don't overwrite sender account (#30259) Fixes #30254 It seems like the removed CreateAccount call is very old and not needed anymore. After removing it, setting a sender that does not exist in the state doesn't seem to cause an issue. --- cmd/evm/runner.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index f179e733e657..d06f85ed5965 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -162,7 +162,6 @@ func runCmd(ctx *cli.Context) error { if ctx.String(SenderFlag.Name) != "" { sender = common.HexToAddress(ctx.String(SenderFlag.Name)) } - statedb.CreateAccount(sender) if ctx.String(ReceiverFlag.Name) != "" { receiver = common.HexToAddress(ctx.String(ReceiverFlag.Name)) From 10586952dfad6d57ed0b24500f572f7889c8fa97 Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 6 Aug 2024 01:14:22 +0800 Subject: [PATCH 444/571] eth/catalyst: get params.ExcessBlobGas but check with params.BlobGasUsed (#30267) Seems it is checked with the wrong argument Signed-off-by: jsvisa --- eth/catalyst/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 00cce259c861..5a001e1ee836 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -546,7 +546,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe bgu = strconv.Itoa(int(*params.BlobGasUsed)) } ebg := "nil" - if params.BlobGasUsed != nil { + if params.ExcessBlobGas != nil { ebg = strconv.Itoa(int(*params.ExcessBlobGas)) } log.Warn("Invalid NewPayload params", From cf8aa31e3edc6fc652963c5d5dee869cd69f077b Mon Sep 17 00:00:00 2001 From: stevemilk Date: Tue, 6 Aug 2024 19:49:48 +0800 Subject: [PATCH 445/571] params: remove unused les parameters (#30268) --- params/network_params.go | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/params/network_params.go b/params/network_params.go index 9311b5e2d54d..61bd6b2f4229 100644 --- a/params/network_params.go +++ b/params/network_params.go @@ -24,44 +24,13 @@ const ( // contains on the server side. BloomBitsBlocks uint64 = 4096 - // BloomBitsBlocksClient is the number of blocks a single bloom bit section vector - // contains on the light client side - BloomBitsBlocksClient uint64 = 32768 - // BloomConfirms is the number of confirmation blocks before a bloom section is // considered probably final and its rotated bits are calculated. BloomConfirms = 256 - // CHTFrequency is the block frequency for creating CHTs - CHTFrequency = 32768 - - // BloomTrieFrequency is the block frequency for creating BloomTrie on both - // server/client sides. - BloomTrieFrequency = 32768 - - // HelperTrieConfirmations is the number of confirmations before a client is expected - // to have the given HelperTrie available. - HelperTrieConfirmations = 2048 - - // HelperTrieProcessConfirmations is the number of confirmations before a HelperTrie - // is generated - HelperTrieProcessConfirmations = 256 - - // CheckpointFrequency is the block frequency for creating checkpoint - CheckpointFrequency = 32768 - - // CheckpointProcessConfirmations is the number before a checkpoint is generated - CheckpointProcessConfirmations = 256 - // FullImmutabilityThreshold is the number of blocks after which a chain segment is // considered immutable (i.e. soft finality). It is used by the downloader as a // hard limit against deep ancestors, by the blockchain against deep reorgs, by // the freezer as the cutoff threshold and by clique as the snapshot trust limit. FullImmutabilityThreshold = 90000 - - // LightImmutabilityThreshold is the number of blocks after which a header chain - // segment is considered immutable for light client(i.e. soft finality). It is used by - // the downloader as a hard limit against deep ancestors, by the blockchain against deep - // reorgs, by the light pruner as the pruning validity guarantee. - LightImmutabilityThreshold = 30000 ) From dbc1d04f5e4a6e466e32db08ed03678624a93307 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 6 Aug 2024 05:51:48 -0600 Subject: [PATCH 446/571] core/vm/runtime: ensure tracer benchmark calls `OnTxStart` (#30257) The struct-based tracing added in #29189 seems to have caused an issue with the benchmark `BenchmarkTracerStepVsCallFrame`. On master we see the following panic: ```console BenchmarkTracerStepVsCallFrame panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x2 addr=0x40 pc=0x1019782f0] goroutine 37 [running]: github.com/ethereum/go-ethereum/eth/tracers/js.(*jsTracer).OnOpcode(0x140004c4000, 0x0, 0x10?, 0x989680, 0x1, {0x101ea2298, 0x1400000e258}, {0x1400000e258?, 0x14000155928?, 0x10173020c?}, ...) /Users/matt/dev/go-ethereum/eth/tracers/js/goja.go:328 +0x140 github.com/ethereum/go-ethereum/core/vm.(*EVMInterpreter).Run(0x14000307da0, 0x140003cc0d0, {0x0, 0x0, 0x0}, 0x0) ... FAIL github.com/ethereum/go-ethereum/core/vm/runtime 0.420s FAIL ``` The issue seems to be that `OnOpcode` expects that `OnTxStart` has already been called to initialize the `env` value in the tracer. The JS tracer uses it in `OnOpcode` for the `GetRefund()` method. This patch resolves the issue by reusing the `Call` method already defined in `runtime_test.go` which correctly calls `OnTxStart`. --- core/vm/runtime/runtime_test.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 04abc5480eac..a49eca25d3b3 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -38,7 +38,6 @@ import ( // force-load js tracers to trigger registration _ "github.com/ethereum/go-ethereum/eth/tracers/js" - "github.com/holiman/uint256" ) func TestDefaults(t *testing.T) { @@ -339,11 +338,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode Tracer: tracer.Hooks, } } - var ( - destination = common.BytesToAddress([]byte("contract")) - vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) - ) + destination := common.BytesToAddress([]byte("contract")) cfg.State.CreateAccount(destination) eoa := common.HexToAddress("E0") { @@ -363,12 +358,12 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode //cfg.State.CreateAccount(cfg.Origin) // set the receiver's (the executing contract) code for execution. cfg.State.SetCode(destination, code) - vmenv.Call(sender, destination, nil, gas, uint256.MustFromBig(cfg.Value)) + Call(destination, nil, cfg) b.Run(name, func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - vmenv.Call(sender, destination, nil, gas, uint256.MustFromBig(cfg.Value)) + Call(destination, nil, cfg) } }) } From e9981bc6f72229f2bcc87b6721d2c06a195332b9 Mon Sep 17 00:00:00 2001 From: Zhihao Lin <3955922+kkqy@users.noreply.github.com> Date: Tue, 6 Aug 2024 20:14:37 +0800 Subject: [PATCH 447/571] ethclient: support networkID in hex format (#30263) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some chains’ network IDs use hexadecimal such as Optimism ("0xa" instead of "10"), so when converting the string to big.Int, we cannot specify base 10; otherwise, it will encounter errors with hexadecimal network IDs. --- ethclient/ethclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 390f08567714..f769ee847554 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -359,7 +359,7 @@ func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) { if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil { return nil, err } - if _, ok := version.SetString(ver, 10); !ok { + if _, ok := version.SetString(ver, 0); !ok { return nil, fmt.Errorf("invalid net_version result %q", ver) } return version, nil From b37ac5c1027847de2eb65162a7251b37b9466793 Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:38:47 +0200 Subject: [PATCH 448/571] core/vm: improved stack swap performance (#30249) This PR adds the methods `Stack.swap1..16()` that faster than `Stack.swap(1..16)`. Co-authored-by: lmittmann --- core/vm/instructions.go | 90 +++++++++++++++++++++++++++++---- core/vm/jump_table.go | 32 ++++++------ core/vm/runtime/runtime_test.go | 29 +++++++++++ core/vm/stack.go | 51 +++++++++++++++++-- 4 files changed, 173 insertions(+), 29 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 9ec454464363..1e8be295d82a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -583,6 +583,86 @@ func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte return nil, nil } +func opSwap1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap1() + return nil, nil +} + +func opSwap2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap2() + return nil, nil +} + +func opSwap3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap3() + return nil, nil +} + +func opSwap4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap4() + return nil, nil +} + +func opSwap5(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap5() + return nil, nil +} + +func opSwap6(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap6() + return nil, nil +} + +func opSwap7(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap7() + return nil, nil +} + +func opSwap8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap8() + return nil, nil +} + +func opSwap9(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap9() + return nil, nil +} + +func opSwap10(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap10() + return nil, nil +} + +func opSwap11(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap11() + return nil, nil +} + +func opSwap12(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap12() + return nil, nil +} + +func opSwap13(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap13() + return nil, nil +} + +func opSwap14(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap14() + return nil, nil +} + +func opSwap15(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap15() + return nil, nil +} + +func opSwap16(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.swap16() + return nil, nil +} + func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { if interpreter.readOnly { return nil, ErrWriteProtection @@ -923,13 +1003,3 @@ func makeDup(size int64) executionFunc { return nil, nil } } - -// make swap instruction function -func makeSwap(size int64) executionFunc { - // switch n + 1 otherwise n would be swapped with n - size++ - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.swap(int(size)) - return nil, nil - } -} diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 5624f47ba72c..6b2950194d71 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -892,97 +892,97 @@ func newFrontierInstructionSet() JumpTable { maxStack: maxDupStack(16), }, SWAP1: { - execute: makeSwap(1), + execute: opSwap1, constantGas: GasFastestStep, minStack: minSwapStack(2), maxStack: maxSwapStack(2), }, SWAP2: { - execute: makeSwap(2), + execute: opSwap2, constantGas: GasFastestStep, minStack: minSwapStack(3), maxStack: maxSwapStack(3), }, SWAP3: { - execute: makeSwap(3), + execute: opSwap3, constantGas: GasFastestStep, minStack: minSwapStack(4), maxStack: maxSwapStack(4), }, SWAP4: { - execute: makeSwap(4), + execute: opSwap4, constantGas: GasFastestStep, minStack: minSwapStack(5), maxStack: maxSwapStack(5), }, SWAP5: { - execute: makeSwap(5), + execute: opSwap5, constantGas: GasFastestStep, minStack: minSwapStack(6), maxStack: maxSwapStack(6), }, SWAP6: { - execute: makeSwap(6), + execute: opSwap6, constantGas: GasFastestStep, minStack: minSwapStack(7), maxStack: maxSwapStack(7), }, SWAP7: { - execute: makeSwap(7), + execute: opSwap7, constantGas: GasFastestStep, minStack: minSwapStack(8), maxStack: maxSwapStack(8), }, SWAP8: { - execute: makeSwap(8), + execute: opSwap8, constantGas: GasFastestStep, minStack: minSwapStack(9), maxStack: maxSwapStack(9), }, SWAP9: { - execute: makeSwap(9), + execute: opSwap9, constantGas: GasFastestStep, minStack: minSwapStack(10), maxStack: maxSwapStack(10), }, SWAP10: { - execute: makeSwap(10), + execute: opSwap10, constantGas: GasFastestStep, minStack: minSwapStack(11), maxStack: maxSwapStack(11), }, SWAP11: { - execute: makeSwap(11), + execute: opSwap11, constantGas: GasFastestStep, minStack: minSwapStack(12), maxStack: maxSwapStack(12), }, SWAP12: { - execute: makeSwap(12), + execute: opSwap12, constantGas: GasFastestStep, minStack: minSwapStack(13), maxStack: maxSwapStack(13), }, SWAP13: { - execute: makeSwap(13), + execute: opSwap13, constantGas: GasFastestStep, minStack: minSwapStack(14), maxStack: maxSwapStack(14), }, SWAP14: { - execute: makeSwap(14), + execute: opSwap14, constantGas: GasFastestStep, minStack: minSwapStack(15), maxStack: maxSwapStack(15), }, SWAP15: { - execute: makeSwap(15), + execute: opSwap15, constantGas: GasFastestStep, minStack: minSwapStack(16), maxStack: maxSwapStack(16), }, SWAP16: { - execute: makeSwap(16), + execute: opSwap16, constantGas: GasFastestStep, minStack: minSwapStack(17), maxStack: maxSwapStack(17), diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index a49eca25d3b3..f52484606b74 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -212,6 +212,35 @@ func BenchmarkEVM_CREATE2_1200(bench *testing.B) { benchmarkEVM_Create(bench, "5b5862124f80600080f5600152600056") } +func BenchmarkEVM_SWAP1(b *testing.B) { + // returns a contract that does n swaps (SWAP1) + swapContract := func(n uint64) []byte { + contract := []byte{ + byte(vm.PUSH0), // PUSH0 + byte(vm.PUSH0), // PUSH0 + } + for i := uint64(0); i < n; i++ { + contract = append(contract, byte(vm.SWAP1)) + } + return contract + } + + state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + contractAddr := common.BytesToAddress([]byte("contract")) + + b.Run("10k", func(b *testing.B) { + contractCode := swapContract(10_000) + state.SetCode(contractAddr, contractCode) + + for i := 0; i < b.N; i++ { + _, _, err := Call(contractAddr, []byte{}, &Config{State: state}) + if err != nil { + b.Fatal(err) + } + } + }) +} + func fakeHeader(n uint64, parentHash common.Hash) *types.Header { header := types.Header{ Coinbase: common.HexToAddress("0x00000000000000000000000000000000deadbeef"), diff --git a/core/vm/stack.go b/core/vm/stack.go index e1a957e2445a..879dc9aa6d82 100644 --- a/core/vm/stack.go +++ b/core/vm/stack.go @@ -30,7 +30,7 @@ var stackPool = sync.Pool{ // Stack is an object for basic stack operations. Items popped to the stack are // expected to be changed and modified. stack does not take care of adding newly -// initialised objects. +// initialized objects. type Stack struct { data []uint256.Int } @@ -64,8 +64,53 @@ func (st *Stack) len() int { return len(st.data) } -func (st *Stack) swap(n int) { - st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n] +func (st *Stack) swap1() { + st.data[st.len()-2], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-2] +} +func (st *Stack) swap2() { + st.data[st.len()-3], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-3] +} +func (st *Stack) swap3() { + st.data[st.len()-4], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-4] +} +func (st *Stack) swap4() { + st.data[st.len()-5], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-5] +} +func (st *Stack) swap5() { + st.data[st.len()-6], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-6] +} +func (st *Stack) swap6() { + st.data[st.len()-7], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-7] +} +func (st *Stack) swap7() { + st.data[st.len()-8], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-8] +} +func (st *Stack) swap8() { + st.data[st.len()-9], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-9] +} +func (st *Stack) swap9() { + st.data[st.len()-10], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-10] +} +func (st *Stack) swap10() { + st.data[st.len()-11], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-11] +} +func (st *Stack) swap11() { + st.data[st.len()-12], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-12] +} +func (st *Stack) swap12() { + st.data[st.len()-13], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-13] +} +func (st *Stack) swap13() { + st.data[st.len()-14], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-14] +} +func (st *Stack) swap14() { + st.data[st.len()-15], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-15] +} +func (st *Stack) swap15() { + st.data[st.len()-16], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-16] +} +func (st *Stack) swap16() { + st.data[st.len()-17], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-17] } func (st *Stack) dup(n int) { From 978041feeaffc3f91afd98c8495a63bfff4b12f4 Mon Sep 17 00:00:00 2001 From: llkhacquan <3724362+llkhacquan@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:13:18 +0700 Subject: [PATCH 449/571] signer/core: improve performance of isPrimitiveTypeValid function (#30274) (#30277) Precomputes valid primitive types into a map to use for validation, thus removing sprintf. --- signer/core/apitypes/types.go | 48 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 73243b16a14b..e886d7fc443e 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -843,39 +843,35 @@ func (t Types) validate() error { return nil } -// Checks if the primitive value is valid -func isPrimitiveTypeValid(primitiveType string) bool { - if primitiveType == "address" || - primitiveType == "address[]" || - primitiveType == "bool" || - primitiveType == "bool[]" || - primitiveType == "string" || - primitiveType == "string[]" || - primitiveType == "bytes" || - primitiveType == "bytes[]" || - primitiveType == "int" || - primitiveType == "int[]" || - primitiveType == "uint" || - primitiveType == "uint[]" { - return true +var validPrimitiveTypes = map[string]struct{}{} + +// build the set of valid primitive types +func init() { + // Types those are trivially valid + for _, t := range []string{ + "address", "address[]", "bool", "bool[]", "string", "string[]", + "bytes", "bytes[]", "int", "int[]", "uint", "uint[]", + } { + validPrimitiveTypes[t] = struct{}{} } // For 'bytesN', 'bytesN[]', we allow N from 1 to 32 for n := 1; n <= 32; n++ { - // e.g. 'bytes28' or 'bytes28[]' - if primitiveType == fmt.Sprintf("bytes%d", n) || primitiveType == fmt.Sprintf("bytes%d[]", n) { - return true - } + validPrimitiveTypes[fmt.Sprintf("bytes%d", n)] = struct{}{} + validPrimitiveTypes[fmt.Sprintf("bytes%d[]", n)] = struct{}{} } // For 'intN','intN[]' and 'uintN','uintN[]' we allow N in increments of 8, from 8 up to 256 for n := 8; n <= 256; n += 8 { - if primitiveType == fmt.Sprintf("int%d", n) || primitiveType == fmt.Sprintf("int%d[]", n) { - return true - } - if primitiveType == fmt.Sprintf("uint%d", n) || primitiveType == fmt.Sprintf("uint%d[]", n) { - return true - } + validPrimitiveTypes[fmt.Sprintf("int%d", n)] = struct{}{} + validPrimitiveTypes[fmt.Sprintf("int%d[]", n)] = struct{}{} + validPrimitiveTypes[fmt.Sprintf("uint%d", n)] = struct{}{} + validPrimitiveTypes[fmt.Sprintf("uint%d[]", n)] = struct{}{} } - return false +} + +// Checks if the primitive value is valid +func isPrimitiveTypeValid(primitiveType string) bool { + _, ok := validPrimitiveTypes[primitiveType] + return ok } // validate checks if the given domain is valid, i.e. contains at least From 4a3aed380e91fc3e01ccc35e367865de89adb508 Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:27:38 +0200 Subject: [PATCH 450/571] core/vm: use uint64 in memory for indices everywhere (#30252) Consistently use `uint64` for indices in `Memory` and drop lots of type conversions from `uint64` to `int64`. --------- Co-authored-by: lmittmann --- core/vm/instructions.go | 22 +++++++++++----------- core/vm/memory.go | 21 +++++++-------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 1e8be295d82a..2e0f4c40ab1b 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -232,7 +232,7 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.peek() - data := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) + data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) if interpreter.hasher == nil { interpreter.hasher = crypto.NewKeccakState() @@ -502,7 +502,7 @@ func opPop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { v := scope.Stack.peek() - offset := int64(v.Uint64()) + offset := v.Uint64() v.SetBytes(scope.Memory.GetPtr(offset, 32)) return nil, nil } @@ -670,7 +670,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b var ( value = scope.Stack.pop() offset, size = scope.Stack.pop(), scope.Stack.pop() - input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) + input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) gas = scope.Contract.Gas ) if interpreter.evm.chainRules.IsEIP150 { @@ -714,7 +714,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] endowment = scope.Stack.pop() offset, size = scope.Stack.pop(), scope.Stack.pop() salt = scope.Stack.pop() - input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) + input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) gas = scope.Contract.Gas ) @@ -752,7 +752,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get the arguments from the memory. - args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) if interpreter.readOnly && !value.IsZero() { return nil, ErrWriteProtection @@ -788,7 +788,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. - args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) if !value.IsZero() { gas += params.CallStipend @@ -821,7 +821,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. - args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract, toAddr, args, gas) if err != nil { @@ -850,7 +850,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. - args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) ret, returnGas, err := interpreter.evm.StaticCall(scope.Contract, toAddr, args, gas) if err != nil { @@ -871,14 +871,14 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() - ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) + ret := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) return ret, errStopToken } func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() - ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) + ret := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) interpreter.returnData = ret return ret, ErrExecutionReverted @@ -947,7 +947,7 @@ func makeLog(size int) executionFunc { topics[i] = addr.Bytes32() } - d := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64())) + d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64()) interpreter.evm.StateDB.AddLog(&types.Log{ Address: scope.Contract.Address(), Topics: topics, diff --git a/core/vm/memory.go b/core/vm/memory.go index e0202fd7c020..33203879ae50 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -66,32 +66,25 @@ func (m *Memory) Resize(size uint64) { } // GetCopy returns offset + size as a new slice -func (m *Memory) GetCopy(offset, size int64) (cpy []byte) { +func (m *Memory) GetCopy(offset, size uint64) (cpy []byte) { if size == 0 { return nil } - if len(m.store) > int(offset) { - cpy = make([]byte, size) - copy(cpy, m.store[offset:offset+size]) - - return - } - + // memory is always resized before being accessed, no need to check bounds + cpy = make([]byte, size) + copy(cpy, m.store[offset:offset+size]) return } // GetPtr returns the offset + size -func (m *Memory) GetPtr(offset, size int64) []byte { +func (m *Memory) GetPtr(offset, size uint64) []byte { if size == 0 { return nil } - if len(m.store) > int(offset) { - return m.store[offset : offset+size] - } - - return nil + // memory is always resized before being accessed, no need to check bounds + return m.store[offset : offset+size] } // Len returns the length of the backing slice From 9ea766d6e9189e8fbec7dbcacaf4c3f5083276ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Thu, 8 Aug 2024 13:47:43 +0200 Subject: [PATCH 451/571] build: upgrade -dlgo version to Go 1.22.6 (#30273) --- build/checksums.txt | 96 ++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 15c74559e6ae..5a25229885bd 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,55 +5,55 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.22.5 +# version:golang 1.22.6 # https://go.dev/dl/ -ac9c723f224969aee624bc34fd34c9e13f2a212d75c71c807de644bb46e112f6 go1.22.5.src.tar.gz -c82ba3403c45a4aa4b84b08244656a51e55b86fb130dcc500f5291d0f3b12222 go1.22.5.aix-ppc64.tar.gz -8a8872b1bac959b3b76f2e3978c46406d22a54a99c83ca55840ca08b4f2960bc go1.22.5.darwin-amd64.pkg -95d9933cdcf45f211243c42c7705c37353cccd99f27eb4d8e2d1bf2f4165cb50 go1.22.5.darwin-amd64.tar.gz -8c943512d1fa4e849f0078b03721df02aac19d8bb872dd17ab3ee7127ae6b732 go1.22.5.darwin-arm64.pkg -4cd1bcb05be03cecb77bccd765785d5ff69d79adf4dd49790471d00c06b41133 go1.22.5.darwin-arm64.tar.gz -1f1f035e968a877cd8ed62adae6edb2feeee62470660b7587ddcb904a3877a21 go1.22.5.dragonfly-amd64.tar.gz -d660698411465531d475ec1c617fdb415df68740f3511138a8d15506665a06f9 go1.22.5.freebsd-386.tar.gz -75f43ef46c2ad46c534ded25d26fba9bef036fc07074dfa45c0b3b90856a8151 go1.22.5.freebsd-amd64.tar.gz -75614714e7e4a4dd721f0eddd6555b3f6afc4c07e59c1b9b769cf663996165f9 go1.22.5.freebsd-arm.tar.gz -1377d0d7233f1b8f4cb8e3456f2e7ed44aca4a95daab79ae09605d34aa967c6b go1.22.5.freebsd-arm64.tar.gz -07baf198587abc05ea789dbe5810a2d6612ad56a51718bbf74de2c93bdbe676a go1.22.5.freebsd-riscv64.tar.gz -c0bd4f0d44252f3ec93ca850a41b167bb868179c7c283f8af9439e73b2654b17 go1.22.5.illumos-amd64.tar.gz -3ea4c78e6fa52978ae1ed2e5927ad17495da440c9fae7787b1ebc1d0572f7f43 go1.22.5.linux-386.tar.gz -904b924d435eaea086515bc63235b192ea441bd8c9b198c507e85009e6e4c7f0 go1.22.5.linux-amd64.tar.gz -8d21325bfcf431be3660527c1a39d3d9ad71535fabdf5041c826e44e31642b5a go1.22.5.linux-arm64.tar.gz -8c4587cf3e63c9aefbcafa92818c4d9d51683af93ea687bf6c7508d6fa36f85e go1.22.5.linux-armv6l.tar.gz -780e2eeb6376a763c564f776eaac6700f33f95e29302faa54b040b19cb1f6fd2 go1.22.5.linux-loong64.tar.gz -f784aa1adfb605da3bfe8cd534b545bddae3eb893e9302f7c2f5d44656b1cae2 go1.22.5.linux-mips.tar.gz -aaa3756571467768388f2ab641a02ff54f98f1684808cda047a7be3026e4b438 go1.22.5.linux-mips64.tar.gz -b7956d925c9ef5a4dc53017feaed2d78dba5d0a1036bad5ea513f1f15ba08fbc go1.22.5.linux-mips64le.tar.gz -7baf605be9b787acd750b6b48a91818a5590ec9289b14aea5696a46b41853888 go1.22.5.linux-mipsle.tar.gz -f09b2a6c1a409662e8e8fe267e1eabeba0a1fd00eb1422fd88297b013803952e go1.22.5.linux-ppc64.tar.gz -5312bb420ac0b59175a58927e70b4660b14ab7319aab54398b6071fabcbfbb09 go1.22.5.linux-ppc64le.tar.gz -f8d0c7d96b336f4133409ff9da7241cfe91e65723c2e8e7c7f9b58a9f9603476 go1.22.5.linux-riscv64.tar.gz -24c6c5c9d515adea5d58ae78388348c97614a0c21ac4d4f4c0dab75e893b0b5d go1.22.5.linux-s390x.tar.gz -39144c62acbaa85e4f1ab57bad8f5b3dc67d6fa24b711ec1fa593f4a0ea1fe91 go1.22.5.netbsd-386.tar.gz -118f79640588eb878529b46cdf56599012da6575f0ac07069ec1e9a8e78ddd0b go1.22.5.netbsd-amd64.tar.gz -d39c2b94ae3fd0a6399e545cbecb673496293075291bd98ef15f24d21625a490 go1.22.5.netbsd-arm.tar.gz -f7fb617d10c39248996521d72370db82d50724fa894089c76ae4298fbbe1fb0b go1.22.5.netbsd-arm64.tar.gz -e0f778a34746587ae7c18e8a24cfaba1b2eaabce75d0ceb470adf576ad1cd90f go1.22.5.openbsd-386.tar.gz -b417311df26ef7ae8b34fcb991519a5c496010561c12386d9469aea03c1bdf0b go1.22.5.openbsd-amd64.tar.gz -e78e8ad05605d530a4f79e55031c7c65f2020a9d442e05d490bd08f0d947a34f go1.22.5.openbsd-arm.tar.gz -8027898948f17742717786ead2ff2e960ee1fc82995d6edbad0050d551710f59 go1.22.5.openbsd-arm64.tar.gz -99c5b81d75bcc0d83d25dedc9535682c42c0e761276c88bcc4db6340344644fd go1.22.5.openbsd-ppc64.tar.gz -30d5dacdee0481f0b8cabb75b706465e2177c3a4a1d1c46293332f4b90a3d199 go1.22.5.plan9-386.tar.gz -65628650cd7665387cfe6fa386c381f4de1ef7b03a12067ae9ccf06d2feaea2c go1.22.5.plan9-amd64.tar.gz -322541cbfc9ae95b48b9eec4eb45df48299784592e23121084f790cf1082787e go1.22.5.plan9-arm.tar.gz -87c590e3eb81fcffa3dc1524c03c2847f0890e95c2a43586e82b56c262eb03d8 go1.22.5.solaris-amd64.tar.gz -3ec89ed822b38f4483977a90913fbe39d0857f0ed16c4642dec1950ddbe8c943 go1.22.5.windows-386.msi -c44fc421075022add78fbf8db38519dd5520a11832749be2189e64b3cf4f02f9 go1.22.5.windows-386.zip -86b0299ab8cb9c44882a9080dac03f7f4d9546f51ed1ba1015599114bcbc66d0 go1.22.5.windows-amd64.msi -59968438b8d90f108fd240d4d2f95b037e59716995f7409e0a322dcb996e9f42 go1.22.5.windows-amd64.zip -013d3b300e6b8f26482d6dd17b02830b83ee63795498bd8c0c9d80bb2c4d6cf7 go1.22.5.windows-arm.msi -8cc860630a84e2dbff3e84280f46a571741f26f8a1819aa4fbcb3164fdd51312 go1.22.5.windows-arm.zip -8f90519d9f305f2caa05d1d4fb0656b50f1bf89d76e194279f480e5a484c891f go1.22.5.windows-arm64.msi -6717d5841162aa8c05f932eb74a643f1310b8a88f80f0830e86d194289734bbf go1.22.5.windows-arm64.zip +9e48d99d519882579917d8189c17e98c373ce25abaebb98772e2927088992a51 go1.22.6.src.tar.gz +eeb0cc42120cbae6d3695dae2e5420fa0e93a5db957db139b55efdb879dd9856 go1.22.6.aix-ppc64.tar.gz +b47ac340f0b072943fed1f558a26eb260cc23bd21b8af175582e9103141d465b go1.22.6.darwin-amd64.pkg +9c3c0124b01b5365f73a1489649f78f971ecf84844ad9ca58fde133096ddb61b go1.22.6.darwin-amd64.tar.gz +14d0355ec1c0eeb213a16efa8635fac1f16067ef78a8173abf9a8c7b805e551e go1.22.6.darwin-arm64.pkg +ebac39fd44fc22feed1bb519af431c84c55776e39b30f4fd62930da9c0cfd1e3 go1.22.6.darwin-arm64.tar.gz +3695b10c722a4920c8a736284f8820c142e1e752f3a87f797a45c64366f7a173 go1.22.6.dragonfly-amd64.tar.gz +a9b9570c80294a664d50b566d6bd1aa42465997d2d76a57936b32f55f5c69c63 go1.22.6.freebsd-386.tar.gz +424a5618406800365fe3ad96a795fb55ce394bea3ff48eaf56d292bf7a916d1e go1.22.6.freebsd-amd64.tar.gz +e0dce3a6dbe8e7e054d329dd4cb403935c63c0f7e22e693077aa60e12018b883 go1.22.6.freebsd-arm.tar.gz +34930b01f58889c71f7a78c51c6c3bd2ce289ac7862c76dab691303cfa935fd1 go1.22.6.freebsd-arm64.tar.gz +4c9d630e55d4d600a5b4297e59620c3bdfe63a441981682b3638e2fdda228a44 go1.22.6.freebsd-riscv64.tar.gz +9ed63feaf2ef56c56f1cf0d9d3fab4006efd22a38e2f1f5252e95c6ac09332f3 go1.22.6.illumos-amd64.tar.gz +9e680027b058beab10ce5938607660964b6d2c564bf50bdb01aa090dc5beda98 go1.22.6.linux-386.tar.gz +999805bed7d9039ec3da1a53bfbcafc13e367da52aa823cb60b68ba22d44c616 go1.22.6.linux-amd64.tar.gz +c15fa895341b8eaf7f219fada25c36a610eb042985dc1a912410c1c90098eaf2 go1.22.6.linux-arm64.tar.gz +b566484fe89a54c525dd1a4cbfec903c1f6e8f0b7b3dbaf94c79bc9145391083 go1.22.6.linux-armv6l.tar.gz +1ee6e1896aea856142d2af7045cea118995b39404aa61afd12677d023d47ee69 go1.22.6.linux-loong64.tar.gz +fdd0e1a3e178f9bc79adf6ff1e3de4554ce581b4c468fd6e113c43fbbbe1eec6 go1.22.6.linux-mips.tar.gz +d3e5a621fc5a07759e503a971af0b28ded6a7d6f5604ab511f51f930a18dd3e4 go1.22.6.linux-mips64.tar.gz +01547606c5b5c1b0e5587b3afd65172860d2f4755e523785832905759ecce2d7 go1.22.6.linux-mips64le.tar.gz +2cd771416ae03c11240cfdb551d66ab9a941077664f3727b966f94386c23b0fa go1.22.6.linux-mipsle.tar.gz +6ef61d517777925e6bdb0321ea42d5f60acc20c1314dd902b9d0bfa3a5fd4fca go1.22.6.linux-ppc64.tar.gz +9d99fce3f6f72a76630fe91ec0884dfe3db828def4713368424900fa98bb2bd6 go1.22.6.linux-ppc64le.tar.gz +30be9c9b9cc4f044d4da9a33ee601ab7b3aff4246107d323a79e08888710754e go1.22.6.linux-riscv64.tar.gz +82f3bae3ddb4ede45b848db48c5486fadb58551e74507bda45484257e7194a95 go1.22.6.linux-s390x.tar.gz +85b2eb9d40a930bd3e75d0096a6eb5847aac86c5085e6d13a5845e9ef03f8d4b go1.22.6.netbsd-386.tar.gz +6e9acbdc34fb2a942d547c47c9c1989bb6e32b4a37d57fb312499e2bb33b46b7 go1.22.6.netbsd-amd64.tar.gz +e6eff3cf0038f2a9b0c9e01e228577a783bddcd8051222a3d949e24ee392e769 go1.22.6.netbsd-arm.tar.gz +43a7e2ba22da700b844f7561e3dd5434540ed6c9781be2e9c42e8a8cbf558f8e go1.22.6.netbsd-arm64.tar.gz +a90b758ccb45d8a17af8e140fafa1e97607de5a7ecd53a4c55f69258bfb043d0 go1.22.6.openbsd-386.tar.gz +cc13436c4a644e55bedcea65981eb80ca8317b39b129f5563ab3b6da1391bd47 go1.22.6.openbsd-amd64.tar.gz +aee34f61ba2b0a8f2618f5c7065e20da7714ce7651680509eda30728fe01ee88 go1.22.6.openbsd-arm.tar.gz +c67d57daf8baada93c69c8fb02401270cd33159730b1f2d70d9e724ba1a918cf go1.22.6.openbsd-arm64.tar.gz +03e1f96002e94a6b381bcf66a0a62b9d5f63148682a780d727840ad540185c7c go1.22.6.openbsd-ppc64.tar.gz +0ac2b5bbe2c8a293d284512630e629bf0578aaa7b7b1f39ac4ee182c7924aaad go1.22.6.plan9-386.tar.gz +f9afdab8a72a8d874f023f5605482cc94160843ac768dbd840e6f772d16578c7 go1.22.6.plan9-amd64.tar.gz +4b9f01a47e6a29d57cbb3097b6770583336cef9c8f0d51d3d1451e42a851002e go1.22.6.plan9-arm.tar.gz +46c2552ac7b8d6314a52e14e0a0761aaeebdd6aba5f531de386f4cf2b66ec723 go1.22.6.solaris-amd64.tar.gz +a57821dab76af1ef7a6b62db1628f0caa74343e0c7cb829df9ce8ea0713a3e8e go1.22.6.windows-386.msi +eb734bacc9aabca1273b61dd392bb84a9bb33783f5e2fff2cd6ab9885bbefbe6 go1.22.6.windows-386.zip +1238a3e6892eb8a0eb3fe0640e18ab82ca21cc1a933f16897b2ad081f057b5da go1.22.6.windows-amd64.msi +6023083a6e4d3199b44c37e9ba7b25d9674da20fd846a35ee5f9589d81c21a6a go1.22.6.windows-amd64.zip +6791218c568a3d000cb36317506541d7fd67e7cfe613baaf361ca36cad5e2cd5 go1.22.6.windows-arm.msi +ee41ca83bb07c4fd46a1d6b2d083519bb8ca156fcd9db37ee711234d43126e2f go1.22.6.windows-arm.zip +91c6b3376612095315a0aeae4b03e3da34fabe9dfd4532d023e2a70f913cf22a go1.22.6.windows-arm64.msi +7cf55f357ba8116cd3bff992980e20a704ba451b3dab341cf1787b133d900512 go1.22.6.windows-arm64.zip # version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ From d3dae66e594748c2fb608177726bd46715b0a3a6 Mon Sep 17 00:00:00 2001 From: taiking Date: Thu, 8 Aug 2024 20:50:00 +0900 Subject: [PATCH 452/571] tests: fix TransactionTest to actually run (#30272) Due to https://github.com/ethereum/tests/releases/tag/v10.1, the format of the TransactionTest changed, but it was not properly addressed, causing the test to pass unexpectedly. --------- Co-authored-by: Martin Holst Swende --- tests/transaction_test.go | 11 ++++------- tests/transaction_test_util.go | 22 +++++++++++++--------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/tests/transaction_test.go b/tests/transaction_test.go index cb0f2623189c..5179fc9afe8b 100644 --- a/tests/transaction_test.go +++ b/tests/transaction_test.go @@ -26,20 +26,17 @@ func TestTransaction(t *testing.T) { t.Parallel() txt := new(testMatcher) - // 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.*") + // calculating the final cost + txt.skipLoad("^ttGasPrice/TransactionWithGasPriceOverflow.json") - // 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 maximum value of nonce is 2^64 - 1 + txt.skipLoad("^ttNonce/TransactionWithHighNonce64Minus1.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 diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 391aa57584cf..d3dbbd5db294 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -29,7 +29,11 @@ import ( // TransactionTest checks RLP decoding and sender derivation of transactions. type TransactionTest struct { - RLP hexutil.Bytes `json:"rlp"` + Txbytes hexutil.Bytes `json:"txbytes"` + Result ttResult +} + +type ttResult struct { Byzantium ttFork Constantinople ttFork Istanbul ttFork @@ -73,15 +77,15 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { isHomestead bool isIstanbul bool }{ - {"Frontier", types.FrontierSigner{}, tt.Frontier, false, false}, - {"Homestead", types.HomesteadSigner{}, tt.Homestead, true, false}, - {"EIP150", types.HomesteadSigner{}, tt.EIP150, true, false}, - {"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true, false}, - {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true, false}, - {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true, false}, - {"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Istanbul, true, true}, + {"Frontier", types.FrontierSigner{}, tt.Result.Frontier, false, false}, + {"Homestead", types.HomesteadSigner{}, tt.Result.Homestead, true, false}, + {"EIP150", types.HomesteadSigner{}, tt.Result.EIP150, true, false}, + {"EIP158", types.NewEIP155Signer(config.ChainID), tt.Result.EIP158, true, false}, + {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Result.Byzantium, true, false}, + {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Result.Constantinople, true, false}, + {"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Result.Istanbul, true, true}, } { - sender, txhash, err := validateTx(tt.RLP, testcase.signer, testcase.isHomestead, testcase.isIstanbul) + sender, txhash, err := validateTx(tt.Txbytes, testcase.signer, testcase.isHomestead, testcase.isIstanbul) if testcase.fork.Sender == (common.UnprefixedAddress{}) { if err == nil { From ebe31dfd5c8c053c098b65eac2ec3070b7f8e9a8 Mon Sep 17 00:00:00 2001 From: psogv0308 Date: Thu, 8 Aug 2024 22:14:00 +0900 Subject: [PATCH 453/571] eth/downloader, core/types: take withdrawals-size into account in downloader queue (#30276) Fixes a slight miscalculation in the downloader queue, which was not accurately taking block withdrawals into account when calculating the size of the items in the queue --- core/types/withdrawal.go | 7 +++++++ eth/downloader/queue.go | 1 + 2 files changed, 8 insertions(+) diff --git a/core/types/withdrawal.go b/core/types/withdrawal.go index d1ad918f985c..6f99e53b56ad 100644 --- a/core/types/withdrawal.go +++ b/core/types/withdrawal.go @@ -18,6 +18,7 @@ package types import ( "bytes" + "reflect" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -48,6 +49,12 @@ type Withdrawals []*Withdrawal // Len returns the length of s. func (s Withdrawals) Len() int { return len(s) } +var withdrawalSize = int(reflect.TypeOf(Withdrawal{}).Size()) + +func (s Withdrawals) Size() int { + return withdrawalSize * len(s) +} + // EncodeIndex encodes the i'th withdrawal to w. Note that this does not check for errors // because we assume that *Withdrawal will only ever contain valid withdrawals that were either // constructed by decoding or via public API in this package. diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 267c23407f43..5441ad118791 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -385,6 +385,7 @@ func (q *queue) Results(block bool) []*fetchResult { for _, tx := range result.Transactions { size += common.StorageSize(tx.Size()) } + size += common.StorageSize(result.Withdrawals.Size()) q.resultSize = common.StorageSize(blockCacheSizeWeight)*size + (1-common.StorageSize(blockCacheSizeWeight))*q.resultSize } From 83e70aa3d00bbee9713b31768a30a7741eee8945 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 8 Aug 2024 18:58:08 +0200 Subject: [PATCH 454/571] cmd/evm: fix evm basefee (#30281) fixes #30279 -- previously we did not use the basefee from the genesis, and instead the defaults were used from `runtime.go/setDefaults`-function --- cmd/evm/runner.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index d06f85ed5965..c02f9f059085 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -221,6 +221,7 @@ func runCmd(ctx *cli.Context) error { Time: genesisConfig.Timestamp, Coinbase: genesisConfig.Coinbase, BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), + BaseFee: genesisConfig.BaseFee, BlobHashes: blobHashes, BlobBaseFee: blobBaseFee, EVMConfig: vm.Config{ From 811a69cd3cf77fe9b63c7dc260ff92a79c631846 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 9 Aug 2024 22:11:22 +0200 Subject: [PATCH 455/571] go.mod: update uint256 to 1.3.1 (#30280) Release notes: https://github.com/holiman/uint256/releases/tag/v1.3.1 --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 3e9837186d89..763210decd0b 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/hashicorp/go-bexpr v0.1.10 github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 github.com/holiman/bloomfilter/v2 v2.0.3 - github.com/holiman/uint256 v1.3.0 + github.com/holiman/uint256 v1.3.1 github.com/huin/goupnp v1.3.0 github.com/influxdata/influxdb-client-go/v2 v2.4.0 github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c diff --git a/go.sum b/go.sum index d8e7a540c70a..562362dee6fd 100644 --- a/go.sum +++ b/go.sum @@ -310,8 +310,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8 github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= -github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= +github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= @@ -838,8 +838,6 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= From 32a1e0643ca5012bda851d65194fb5eb3d83591b Mon Sep 17 00:00:00 2001 From: Artyom Aminov Date: Sat, 10 Aug 2024 13:44:31 +0300 Subject: [PATCH 456/571] beacon/engine, consensus/beacon: use params.MaximumExtraDataSize instead of hard-coded value (#29721) Co-authored-by: Felix Lange Co-authored-by: Marius van der Wijden Co-authored-by: lightclient --- beacon/engine/types.go | 57 ++++++++++++++++++----------------- consensus/beacon/consensus.go | 2 +- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 1dfcf5b71a0e..d1b3aa22abdf 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" ) @@ -193,21 +194,21 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { // // and that the blockhash of the constructed block matches the parameters. Nil // Withdrawals value will propagate through the returned block. Empty -// Withdrawals value must be passed via non-nil, length 0 value in params. -func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { - txs, err := decodeTransactions(params.Transactions) +// Withdrawals value must be passed via non-nil, length 0 value in data. +func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { + txs, err := decodeTransactions(data.Transactions) if err != nil { return nil, err } - if len(params.ExtraData) > 32 { - return nil, fmt.Errorf("invalid extradata length: %v", len(params.ExtraData)) + if len(data.ExtraData) > int(params.MaximumExtraDataSize) { + return nil, fmt.Errorf("invalid extradata length: %v", len(data.ExtraData)) } - if len(params.LogsBloom) != 256 { - return nil, fmt.Errorf("invalid logsBloom length: %v", len(params.LogsBloom)) + if len(data.LogsBloom) != 256 { + return nil, fmt.Errorf("invalid logsBloom length: %v", len(data.LogsBloom)) } // Check that baseFeePerGas is not negative or too big - if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) { - return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas) + if data.BaseFeePerGas != nil && (data.BaseFeePerGas.Sign() == -1 || data.BaseFeePerGas.BitLen() > 256) { + return nil, fmt.Errorf("invalid baseFeePerGas: %v", data.BaseFeePerGas) } var blobHashes = make([]common.Hash, 0, len(txs)) for _, tx := range txs { @@ -225,34 +226,34 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, // ExecutableData before withdrawals are enabled by marshaling // Withdrawals as the json null value. var withdrawalsRoot *common.Hash - if params.Withdrawals != nil { - h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil)) + if data.Withdrawals != nil { + h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil)) withdrawalsRoot = &h } header := &types.Header{ - ParentHash: params.ParentHash, + ParentHash: data.ParentHash, UncleHash: types.EmptyUncleHash, - Coinbase: params.FeeRecipient, - Root: params.StateRoot, + Coinbase: data.FeeRecipient, + Root: data.StateRoot, TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), - ReceiptHash: params.ReceiptsRoot, - Bloom: types.BytesToBloom(params.LogsBloom), + ReceiptHash: data.ReceiptsRoot, + Bloom: types.BytesToBloom(data.LogsBloom), Difficulty: common.Big0, - Number: new(big.Int).SetUint64(params.Number), - GasLimit: params.GasLimit, - GasUsed: params.GasUsed, - Time: params.Timestamp, - BaseFee: params.BaseFeePerGas, - Extra: params.ExtraData, - MixDigest: params.Random, + Number: new(big.Int).SetUint64(data.Number), + GasLimit: data.GasLimit, + GasUsed: data.GasUsed, + Time: data.Timestamp, + BaseFee: data.BaseFeePerGas, + Extra: data.ExtraData, + MixDigest: data.Random, WithdrawalsHash: withdrawalsRoot, - ExcessBlobGas: params.ExcessBlobGas, - BlobGasUsed: params.BlobGasUsed, + ExcessBlobGas: data.ExcessBlobGas, + BlobGasUsed: data.BlobGasUsed, ParentBeaconRoot: beaconRoot, } - block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: params.Withdrawals}) - if block.Hash() != params.BlockHash { - return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash()) + block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}) + if block.Hash() != data.BlockHash { + return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash()) } return block, nil } diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index b8946e0c7109..19763ed303f1 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -229,7 +229,7 @@ func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Blo // (c) the extradata is limited to 32 bytes func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error { // Ensure that the header's extra-data section is of a reasonable size - if len(header.Extra) > 32 { + if len(header.Extra) > int(params.MaximumExtraDataSize) { return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra)) } // Verify the seal parts. Ensure the nonce and uncle hash are the expected value. From 33a13b6f2110807a15c443ec234580cfce94a194 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 12 Aug 2024 02:36:48 -0600 Subject: [PATCH 457/571] p2p/simulations: remove packages (#30250) Looking at the history of these packages over the past several years, there haven't been any meaningful contributions or usages: https://github.com/ethereum/go-ethereum/commits/master/p2p/simulations?before=de6d5976794a9ed3b626d4eba57bf7f0806fb970+35 Almost all of the commits are part of larger refactors or low-hanging-fruit contributions. Seems like it's not providing much value and taking up team + contributor time. --- .github/CODEOWNERS | 3 - cmd/p2psim/main.go | 443 ------- .../pipes/pipes.go => pipes/pipe.go} | 14 +- p2p/rlpx/rlpx_test.go | 2 +- p2p/simulations/README.md | 174 --- p2p/simulations/adapters/exec.go | 567 --------- p2p/simulations/adapters/inproc.go | 344 ------ p2p/simulations/adapters/inproc_test.go | 202 --- p2p/simulations/adapters/types.go | 325 ----- p2p/simulations/connect.go | 153 --- p2p/simulations/connect_test.go | 172 --- p2p/simulations/events.go | 110 -- p2p/simulations/examples/README.md | 39 - p2p/simulations/examples/ping-pong.go | 173 --- p2p/simulations/examples/ping-pong.sh | 40 - p2p/simulations/http.go | 743 ----------- p2p/simulations/http_test.go | 869 ------------- p2p/simulations/mocker.go | 197 --- p2p/simulations/mocker_test.go | 174 --- p2p/simulations/network.go | 1093 ----------------- p2p/simulations/network_test.go | 872 ------------- p2p/simulations/simulation.go | 157 --- p2p/simulations/test.go | 150 --- p2p/transport_test.go | 2 +- 24 files changed, 5 insertions(+), 7013 deletions(-) delete mode 100644 cmd/p2psim/main.go rename p2p/{simulations/pipes/pipes.go => pipes/pipe.go} (85%) delete mode 100644 p2p/simulations/README.md delete mode 100644 p2p/simulations/adapters/exec.go delete mode 100644 p2p/simulations/adapters/inproc.go delete mode 100644 p2p/simulations/adapters/inproc_test.go delete mode 100644 p2p/simulations/adapters/types.go delete mode 100644 p2p/simulations/connect.go delete mode 100644 p2p/simulations/connect_test.go delete mode 100644 p2p/simulations/events.go delete mode 100644 p2p/simulations/examples/README.md delete mode 100644 p2p/simulations/examples/ping-pong.go delete mode 100755 p2p/simulations/examples/ping-pong.sh delete mode 100644 p2p/simulations/http.go delete mode 100644 p2p/simulations/http_test.go delete mode 100644 p2p/simulations/mocker.go delete mode 100644 p2p/simulations/mocker_test.go delete mode 100644 p2p/simulations/network.go delete mode 100644 p2p/simulations/network_test.go delete mode 100644 p2p/simulations/simulation.go delete mode 100644 p2p/simulations/test.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ec2efb10e354..b50561172fbb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -21,7 +21,4 @@ light/ @zsfelfoldi @rjl493456442 node/ @fjl p2p/ @fjl @zsfelfoldi rpc/ @fjl @holiman -p2p/simulations @fjl -p2p/protocols @fjl -p2p/testing @fjl signer/ @holiman diff --git a/cmd/p2psim/main.go b/cmd/p2psim/main.go deleted file mode 100644 index a0f5f0d2889d..000000000000 --- a/cmd/p2psim/main.go +++ /dev/null @@ -1,443 +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 . - -// p2psim provides a command-line client for a simulation HTTP API. -// -// Here is an example of creating a 2 node network with the first node -// connected to the second: -// -// $ p2psim node create -// Created node01 -// -// $ p2psim node start node01 -// Started node01 -// -// $ p2psim node create -// Created node02 -// -// $ p2psim node start node02 -// Started node02 -// -// $ p2psim node connect node01 node02 -// Connected node01 to node02 -package main - -import ( - "context" - "encoding/json" - "fmt" - "io" - "os" - "strings" - "text/tabwriter" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/internal/flags" - "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/urfave/cli/v2" -) - -var client *simulations.Client - -var ( - // global command flags - apiFlag = &cli.StringFlag{ - Name: "api", - Value: "http://localhost:8888", - Usage: "simulation API URL", - EnvVars: []string{"P2PSIM_API_URL"}, - } - - // events subcommand flags - currentFlag = &cli.BoolFlag{ - Name: "current", - Usage: "get existing nodes and conns first", - } - filterFlag = &cli.StringFlag{ - Name: "filter", - Value: "", - Usage: "message filter", - } - - // node create subcommand flags - nameFlag = &cli.StringFlag{ - Name: "name", - Value: "", - Usage: "node name", - } - servicesFlag = &cli.StringFlag{ - Name: "services", - Value: "", - Usage: "node services (comma separated)", - } - keyFlag = &cli.StringFlag{ - Name: "key", - Value: "", - Usage: "node private key (hex encoded)", - } - - // node rpc subcommand flags - subscribeFlag = &cli.BoolFlag{ - Name: "subscribe", - Usage: "method is a subscription", - } -) - -func main() { - app := flags.NewApp("devp2p simulation command-line client") - app.Flags = []cli.Flag{ - apiFlag, - } - app.Before = func(ctx *cli.Context) error { - client = simulations.NewClient(ctx.String(apiFlag.Name)) - return nil - } - app.Commands = []*cli.Command{ - { - Name: "show", - Usage: "show network information", - Action: showNetwork, - }, - { - Name: "events", - Usage: "stream network events", - Action: streamNetwork, - Flags: []cli.Flag{ - currentFlag, - filterFlag, - }, - }, - { - Name: "snapshot", - Usage: "create a network snapshot to stdout", - Action: createSnapshot, - }, - { - Name: "load", - Usage: "load a network snapshot from stdin", - Action: loadSnapshot, - }, - { - Name: "node", - Usage: "manage simulation nodes", - Action: listNodes, - Subcommands: []*cli.Command{ - { - Name: "list", - Usage: "list nodes", - Action: listNodes, - }, - { - Name: "create", - Usage: "create a node", - Action: createNode, - Flags: []cli.Flag{ - nameFlag, - servicesFlag, - keyFlag, - }, - }, - { - Name: "show", - ArgsUsage: "", - Usage: "show node information", - Action: showNode, - }, - { - Name: "start", - ArgsUsage: "", - Usage: "start a node", - Action: startNode, - }, - { - Name: "stop", - ArgsUsage: "", - Usage: "stop a node", - Action: stopNode, - }, - { - Name: "connect", - ArgsUsage: " ", - Usage: "connect a node to a peer node", - Action: connectNode, - }, - { - Name: "disconnect", - ArgsUsage: " ", - Usage: "disconnect a node from a peer node", - Action: disconnectNode, - }, - { - Name: "rpc", - ArgsUsage: " []", - Usage: "call a node RPC method", - Action: rpcNode, - Flags: []cli.Flag{ - subscribeFlag, - }, - }, - }, - }, - } - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func showNetwork(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - network, err := client.GetNetwork() - if err != nil { - return err - } - w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0) - defer w.Flush() - fmt.Fprintf(w, "NODES\t%d\n", len(network.Nodes)) - fmt.Fprintf(w, "CONNS\t%d\n", len(network.Conns)) - return nil -} - -func streamNetwork(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - events := make(chan *simulations.Event) - sub, err := client.SubscribeNetwork(events, simulations.SubscribeOpts{ - Current: ctx.Bool(currentFlag.Name), - Filter: ctx.String(filterFlag.Name), - }) - if err != nil { - return err - } - defer sub.Unsubscribe() - enc := json.NewEncoder(ctx.App.Writer) - for { - select { - case event := <-events: - if err := enc.Encode(event); err != nil { - return err - } - case err := <-sub.Err(): - return err - } - } -} - -func createSnapshot(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - snap, err := client.CreateSnapshot() - if err != nil { - return err - } - return json.NewEncoder(os.Stdout).Encode(snap) -} - -func loadSnapshot(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - snap := &simulations.Snapshot{} - if err := json.NewDecoder(os.Stdin).Decode(snap); err != nil { - return err - } - return client.LoadSnapshot(snap) -} - -func listNodes(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodes, err := client.GetNodes() - if err != nil { - return err - } - w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0) - defer w.Flush() - fmt.Fprintf(w, "NAME\tPROTOCOLS\tID\n") - for _, node := range nodes { - fmt.Fprintf(w, "%s\t%s\t%s\n", node.Name, strings.Join(protocolList(node), ","), node.ID) - } - return nil -} - -func protocolList(node *p2p.NodeInfo) []string { - protos := make([]string, 0, len(node.Protocols)) - for name := range node.Protocols { - protos = append(protos, name) - } - return protos -} - -func createNode(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - config := adapters.RandomNodeConfig() - config.Name = ctx.String(nameFlag.Name) - if key := ctx.String(keyFlag.Name); key != "" { - privKey, err := crypto.HexToECDSA(key) - if err != nil { - return err - } - config.ID = enode.PubkeyToIDV4(&privKey.PublicKey) - config.PrivateKey = privKey - } - if services := ctx.String(servicesFlag.Name); services != "" { - config.Lifecycles = strings.Split(services, ",") - } - node, err := client.CreateNode(config) - if err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Created", node.Name) - return nil -} - -func showNode(ctx *cli.Context) error { - if ctx.NArg() != 1 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := ctx.Args().First() - node, err := client.GetNode(nodeName) - if err != nil { - return err - } - w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0) - defer w.Flush() - fmt.Fprintf(w, "NAME\t%s\n", node.Name) - fmt.Fprintf(w, "PROTOCOLS\t%s\n", strings.Join(protocolList(node), ",")) - fmt.Fprintf(w, "ID\t%s\n", node.ID) - fmt.Fprintf(w, "ENODE\t%s\n", node.Enode) - for name, proto := range node.Protocols { - fmt.Fprintln(w) - fmt.Fprintf(w, "--- PROTOCOL INFO: %s\n", name) - fmt.Fprintf(w, "%v\n", proto) - fmt.Fprintf(w, "---\n") - } - return nil -} - -func startNode(ctx *cli.Context) error { - if ctx.NArg() != 1 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := ctx.Args().First() - if err := client.StartNode(nodeName); err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Started", nodeName) - return nil -} - -func stopNode(ctx *cli.Context) error { - if ctx.NArg() != 1 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := ctx.Args().First() - if err := client.StopNode(nodeName); err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Stopped", nodeName) - return nil -} - -func connectNode(ctx *cli.Context) error { - if ctx.NArg() != 2 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - args := ctx.Args() - nodeName := args.Get(0) - peerName := args.Get(1) - if err := client.ConnectNode(nodeName, peerName); err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Connected", nodeName, "to", peerName) - return nil -} - -func disconnectNode(ctx *cli.Context) error { - args := ctx.Args() - if args.Len() != 2 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := args.Get(0) - peerName := args.Get(1) - if err := client.DisconnectNode(nodeName, peerName); err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Disconnected", nodeName, "from", peerName) - return nil -} - -func rpcNode(ctx *cli.Context) error { - args := ctx.Args() - if args.Len() < 2 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := args.Get(0) - method := args.Get(1) - rpcClient, err := client.RPCClient(context.Background(), nodeName) - if err != nil { - return err - } - if ctx.Bool(subscribeFlag.Name) { - return rpcSubscribe(rpcClient, ctx.App.Writer, method, args.Slice()[3:]...) - } - var result interface{} - params := make([]interface{}, len(args.Slice()[3:])) - for i, v := range args.Slice()[3:] { - params[i] = v - } - if err := rpcClient.Call(&result, method, params...); err != nil { - return err - } - return json.NewEncoder(ctx.App.Writer).Encode(result) -} - -func rpcSubscribe(client *rpc.Client, out io.Writer, method string, args ...string) error { - namespace, method, _ := strings.Cut(method, "_") - ch := make(chan interface{}) - subArgs := make([]interface{}, len(args)+1) - subArgs[0] = method - for i, v := range args { - subArgs[i+1] = v - } - sub, err := client.Subscribe(context.Background(), namespace, ch, subArgs...) - if err != nil { - return err - } - defer sub.Unsubscribe() - enc := json.NewEncoder(out) - for { - select { - case v := <-ch: - if err := enc.Encode(v); err != nil { - return err - } - case err := <-sub.Err(): - return err - } - } -} diff --git a/p2p/simulations/pipes/pipes.go b/p2p/pipes/pipe.go similarity index 85% rename from p2p/simulations/pipes/pipes.go rename to p2p/pipes/pipe.go index ec277c0d147c..cf1f3e2a80fe 100644 --- a/p2p/simulations/pipes/pipes.go +++ b/p2p/pipes/pipe.go @@ -1,4 +1,4 @@ -// Copyright 2018 The go-ethereum Authors +// Copyright 2024 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,17 +16,9 @@ package pipes -import ( - "net" -) +import "net" -// NetPipe wraps net.Pipe in a signature returning an error -func NetPipe() (net.Conn, net.Conn, error) { - p1, p2 := net.Pipe() - return p1, p2, nil -} - -// TCPPipe creates an in process full duplex pipe based on a localhost TCP socket +// TCPPipe creates an in process full duplex pipe based on a localhost TCP socket. func TCPPipe() (net.Conn, net.Conn, error) { l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { diff --git a/p2p/rlpx/rlpx_test.go b/p2p/rlpx/rlpx_test.go index 136cb1b5bfca..27d51546e79c 100644 --- a/p2p/rlpx/rlpx_test.go +++ b/p2p/rlpx/rlpx_test.go @@ -31,7 +31,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/p2p/simulations/pipes" + "github.com/ethereum/go-ethereum/p2p/pipes" "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" ) diff --git a/p2p/simulations/README.md b/p2p/simulations/README.md deleted file mode 100644 index 1f9f72dcdacf..000000000000 --- a/p2p/simulations/README.md +++ /dev/null @@ -1,174 +0,0 @@ -# devp2p Simulations - -The `p2p/simulations` package implements a simulation framework that supports -creating a collection of devp2p nodes, connecting them to form a -simulation network, performing simulation actions in that network and then -extracting useful information. - -## Nodes - -Each node in a simulation network runs multiple services by wrapping a collection -of objects which implement the `node.Service` interface meaning they: - -* can be started and stopped -* run p2p protocols -* expose RPC APIs - -This means that any object which implements the `node.Service` interface can be -used to run a node in the simulation. - -## Services - -Before running a simulation, a set of service initializers must be registered -which can then be used to run nodes in the network. - -A service initializer is a function with the following signature: - -```go -func(ctx *adapters.ServiceContext) (node.Service, error) -``` - -These initializers should be registered by calling the `adapters.RegisterServices` -function in an `init()` hook: - -```go -func init() { - adapters.RegisterServices(adapters.Services{ - "service1": initService1, - "service2": initService2, - }) -} -``` - -## Node Adapters - -The simulation framework includes multiple "node adapters" which are -responsible for creating an environment in which a node runs. - -### SimAdapter - -The `SimAdapter` runs nodes in-memory, connecting them using an in-memory, -synchronous `net.Pipe` and connecting to their RPC server using an in-memory -`rpc.Client`. - -### ExecAdapter - -The `ExecAdapter` runs nodes as child processes of the running simulation. - -It does this by executing the binary which is running the simulation but -setting `argv[0]` (i.e. the program name) to `p2p-node` which is then -detected by an init hook in the child process which runs the `node.Service` -using the devp2p node stack rather than executing `main()`. - -The nodes listen for devp2p connections and WebSocket RPC clients on random -localhost ports. - -## Network - -A simulation network is created with an ID and default service. The default -service is used if a node is created without an explicit service. The -network has exposed methods for creating, starting, stopping, connecting -and disconnecting nodes. It also emits events when certain actions occur. - -### Events - -A simulation network emits the following events: - -* node event - when nodes are created / started / stopped -* connection event - when nodes are connected / disconnected -* message event - when a protocol message is sent between two nodes - -The events have a "control" flag which when set indicates that the event is the -outcome of a controlled simulation action (e.g. creating a node or explicitly -connecting two nodes). - -This is in contrast to a non-control event, otherwise called a "live" event, -which is the outcome of something happening in the network as a result of a -control event (e.g. a node actually started up or a connection was actually -established between two nodes). - -Live events are detected by the simulation network by subscribing to node peer -events via RPC when the nodes start up. - -## Testing Framework - -The `Simulation` type can be used in tests to perform actions in a simulation -network and then wait for expectations to be met. - -With a running simulation network, the `Simulation.Run` method can be called -with a `Step` which has the following fields: - -* `Action` - a function that performs some action in the network - -* `Expect` - an expectation function which returns whether or not a - given node meets the expectation - -* `Trigger` - a channel that receives node IDs which then trigger a check - of the expectation function to be performed against that node - -As a concrete example, consider a simulated network of Ethereum nodes. An -`Action` could be the sending of a transaction, `Expect` it being included in -a block, and `Trigger` a check for every block that is mined. - -On return, the `Simulation.Run` method returns a `StepResult` which can be used -to determine if all nodes met the expectation, how long it took them to meet -the expectation and what network events were emitted during the step run. - -## HTTP API - -The simulation framework includes a HTTP API that can be used to control the -simulation. - -The API is initialised with a particular node adapter and has the following -endpoints: - -``` -OPTIONS / Response 200 with "Access-Control-Allow-Headers"" header set to "Content-Type"" -GET / Get network information -POST /start Start all nodes in the network -POST /stop Stop all nodes in the network -POST /mocker/start Start the mocker node simulation -POST /mocker/stop Stop the mocker node simulation -GET /mocker Get a list of available mockers -POST /reset Reset all properties of a network to initial (empty) state -GET /events Stream network events -GET /snapshot Take a network snapshot -POST /snapshot Load a network snapshot -POST /nodes Create a node -GET /nodes Get all nodes in the network -GET /nodes/:nodeid Get node information -POST /nodes/:nodeid/start Start a node -POST /nodes/:nodeid/stop Stop a node -POST /nodes/:nodeid/conn/:peerid Connect two nodes -DELETE /nodes/:nodeid/conn/:peerid Disconnect two nodes -GET /nodes/:nodeid/rpc Make RPC requests to a node via WebSocket -``` - -For convenience, `nodeid` in the URL can be the name of a node rather than its -ID. - -## Command line client - -`p2psim` is a command line client for the HTTP API, located in -`cmd/p2psim`. - -It provides the following commands: - -``` -p2psim show -p2psim events [--current] [--filter=FILTER] -p2psim snapshot -p2psim load -p2psim node create [--name=NAME] [--services=SERVICES] [--key=KEY] -p2psim node list -p2psim node show -p2psim node start -p2psim node stop -p2psim node connect -p2psim node disconnect -p2psim node rpc [] [--subscribe] -``` - -## Example - -See [p2p/simulations/examples/README.md](examples/README.md). diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go deleted file mode 100644 index 6307b90bf81c..000000000000 --- a/p2p/simulations/adapters/exec.go +++ /dev/null @@ -1,567 +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 adapters - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "log/slog" - "net" - "net/http" - "os" - "os/exec" - "os/signal" - "path/filepath" - "strings" - "sync" - "syscall" - "time" - - "github.com/ethereum/go-ethereum/internal/reexec" - "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/rpc" - "github.com/gorilla/websocket" -) - -func init() { - // Register a reexec function to start a simulation node when the current binary is - // executed as "p2p-node" (rather than whatever the main() function would normally do). - reexec.Register("p2p-node", execP2PNode) -} - -// ExecAdapter is a NodeAdapter which runs simulation nodes by executing the current binary -// as a child process. -type ExecAdapter struct { - // BaseDir is the directory under which the data directories for each - // simulation node are created. - BaseDir string - - nodes map[enode.ID]*ExecNode -} - -// NewExecAdapter returns an ExecAdapter which stores node data in -// subdirectories of the given base directory -func NewExecAdapter(baseDir string) *ExecAdapter { - return &ExecAdapter{ - BaseDir: baseDir, - nodes: make(map[enode.ID]*ExecNode), - } -} - -// Name returns the name of the adapter for logging purposes -func (e *ExecAdapter) Name() string { - return "exec-adapter" -} - -// NewNode returns a new ExecNode using the given config -func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) { - if len(config.Lifecycles) == 0 { - return nil, errors.New("node must have at least one service lifecycle") - } - for _, service := range config.Lifecycles { - if _, exists := lifecycleConstructorFuncs[service]; !exists { - return nil, fmt.Errorf("unknown node service %q", service) - } - } - - // create the node directory using the first 12 characters of the ID - // as Unix socket paths cannot be longer than 256 characters - dir := filepath.Join(e.BaseDir, config.ID.String()[:12]) - if err := os.Mkdir(dir, 0755); err != nil { - return nil, fmt.Errorf("error creating node directory: %s", err) - } - - err := config.initDummyEnode() - if err != nil { - return nil, err - } - - // generate the config - conf := &execNodeConfig{ - Stack: node.DefaultConfig, - Node: config, - } - if config.DataDir != "" { - conf.Stack.DataDir = config.DataDir - } else { - conf.Stack.DataDir = filepath.Join(dir, "data") - } - - // these parameters are crucial for execadapter node to run correctly - conf.Stack.WSHost = "127.0.0.1" - conf.Stack.WSPort = 0 - conf.Stack.WSOrigins = []string{"*"} - conf.Stack.WSExposeAll = true - conf.Stack.P2P.EnableMsgEvents = config.EnableMsgEvents - conf.Stack.P2P.NoDiscovery = true - conf.Stack.P2P.NAT = nil - - // Listen on a localhost port, which we set when we - // initialise NodeConfig (usually a random port) - conf.Stack.P2P.ListenAddr = fmt.Sprintf(":%d", config.Port) - - node := &ExecNode{ - ID: config.ID, - Dir: dir, - Config: conf, - adapter: e, - } - node.newCmd = node.execCommand - e.nodes[node.ID] = node - return node, nil -} - -// ExecNode starts a simulation node by exec'ing the current binary and -// running the configured services -type ExecNode struct { - ID enode.ID - Dir string - Config *execNodeConfig - Cmd *exec.Cmd - Info *p2p.NodeInfo - - adapter *ExecAdapter - client *rpc.Client - wsAddr string - newCmd func() *exec.Cmd -} - -// Addr returns the node's enode URL -func (n *ExecNode) Addr() []byte { - if n.Info == nil { - return nil - } - return []byte(n.Info.Enode) -} - -// Client returns an rpc.Client which can be used to communicate with the -// underlying services (it is set once the node has started) -func (n *ExecNode) Client() (*rpc.Client, error) { - return n.client, nil -} - -// Start exec's the node passing the ID and service as command line arguments -// and the node config encoded as JSON in an environment variable. -func (n *ExecNode) Start(snapshots map[string][]byte) (err error) { - if n.Cmd != nil { - return errors.New("already started") - } - defer func() { - if err != nil { - n.Stop() - } - }() - - // encode a copy of the config containing the snapshot - confCopy := *n.Config - confCopy.Snapshots = snapshots - confCopy.PeerAddrs = make(map[string]string) - for id, node := range n.adapter.nodes { - confCopy.PeerAddrs[id.String()] = node.wsAddr - } - confData, err := json.Marshal(confCopy) - if err != nil { - return fmt.Errorf("error generating node config: %s", err) - } - // expose the admin namespace via websocket if it's not enabled - exposed := confCopy.Stack.WSExposeAll - if !exposed { - for _, api := range confCopy.Stack.WSModules { - if api == "admin" { - exposed = true - break - } - } - } - if !exposed { - confCopy.Stack.WSModules = append(confCopy.Stack.WSModules, "admin") - } - // start the one-shot server that waits for startup information - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - statusURL, statusC := n.waitForStartupJSON(ctx) - - // start the node - cmd := n.newCmd() - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Env = append(os.Environ(), - envStatusURL+"="+statusURL, - envNodeConfig+"="+string(confData), - ) - if err := cmd.Start(); err != nil { - return fmt.Errorf("error starting node: %s", err) - } - n.Cmd = cmd - - // Wait for the node to start. - status := <-statusC - if status.Err != "" { - return errors.New(status.Err) - } - client, err := rpc.DialWebsocket(ctx, status.WSEndpoint, "") - if err != nil { - return fmt.Errorf("can't connect to RPC server: %v", err) - } - - // Node ready :) - n.client = client - n.wsAddr = status.WSEndpoint - n.Info = status.NodeInfo - return nil -} - -// waitForStartupJSON runs a one-shot HTTP server to receive a startup report. -func (n *ExecNode) waitForStartupJSON(ctx context.Context) (string, chan nodeStartupJSON) { - var ( - ch = make(chan nodeStartupJSON, 1) - quitOnce sync.Once - srv http.Server - ) - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - ch <- nodeStartupJSON{Err: err.Error()} - return "", ch - } - quit := func(status nodeStartupJSON) { - quitOnce.Do(func() { - l.Close() - ch <- status - }) - } - srv.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - var status nodeStartupJSON - if err := json.NewDecoder(r.Body).Decode(&status); err != nil { - status.Err = fmt.Sprintf("can't decode startup report: %v", err) - } - quit(status) - }) - // Run the HTTP server, but don't wait forever and shut it down - // if the context is canceled. - go srv.Serve(l) - go func() { - <-ctx.Done() - quit(nodeStartupJSON{Err: "didn't get startup report"}) - }() - - url := "http://" + l.Addr().String() - return url, ch -} - -// execCommand returns a command which runs the node locally by exec'ing -// the current binary but setting argv[0] to "p2p-node" so that the child -// runs execP2PNode -func (n *ExecNode) execCommand() *exec.Cmd { - return &exec.Cmd{ - Path: reexec.Self(), - Args: []string{"p2p-node", strings.Join(n.Config.Node.Lifecycles, ","), n.ID.String()}, - } -} - -// Stop stops the node by first sending SIGTERM and then SIGKILL if the node -// doesn't stop within 5s -func (n *ExecNode) Stop() error { - if n.Cmd == nil { - return nil - } - defer func() { - n.Cmd = nil - }() - - if n.client != nil { - n.client.Close() - n.client = nil - n.wsAddr = "" - n.Info = nil - } - - if err := n.Cmd.Process.Signal(syscall.SIGTERM); err != nil { - return n.Cmd.Process.Kill() - } - waitErr := make(chan error, 1) - go func() { - waitErr <- n.Cmd.Wait() - }() - timer := time.NewTimer(5 * time.Second) - defer timer.Stop() - - select { - case err := <-waitErr: - return err - case <-timer.C: - return n.Cmd.Process.Kill() - } -} - -// NodeInfo returns information about the node -func (n *ExecNode) NodeInfo() *p2p.NodeInfo { - info := &p2p.NodeInfo{ - ID: n.ID.String(), - } - if n.client != nil { - n.client.Call(&info, "admin_nodeInfo") - } - return info -} - -// ServeRPC serves RPC requests over the given connection by dialling the -// node's WebSocket address and joining the two connections -func (n *ExecNode) ServeRPC(clientConn *websocket.Conn) error { - conn, _, err := websocket.DefaultDialer.Dial(n.wsAddr, nil) - if err != nil { - return err - } - var wg sync.WaitGroup - wg.Add(2) - go wsCopy(&wg, conn, clientConn) - go wsCopy(&wg, clientConn, conn) - wg.Wait() - conn.Close() - return nil -} - -func wsCopy(wg *sync.WaitGroup, src, dst *websocket.Conn) { - defer wg.Done() - for { - msgType, r, err := src.NextReader() - if err != nil { - return - } - w, err := dst.NextWriter(msgType) - if err != nil { - return - } - if _, err = io.Copy(w, r); err != nil { - return - } - } -} - -// Snapshots creates snapshots of the services by calling the -// simulation_snapshot RPC method -func (n *ExecNode) Snapshots() (map[string][]byte, error) { - if n.client == nil { - return nil, errors.New("RPC not started") - } - var snapshots map[string][]byte - return snapshots, n.client.Call(&snapshots, "simulation_snapshot") -} - -// execNodeConfig is used to serialize the node configuration so it can be -// passed to the child process as a JSON encoded environment variable -type execNodeConfig struct { - Stack node.Config `json:"stack"` - Node *NodeConfig `json:"node"` - Snapshots map[string][]byte `json:"snapshots,omitempty"` - PeerAddrs map[string]string `json:"peer_addrs,omitempty"` -} - -func initLogging() { - // Initialize the logging by default first. - var innerHandler slog.Handler - innerHandler = slog.NewTextHandler(os.Stderr, nil) - glogger := log.NewGlogHandler(innerHandler) - glogger.Verbosity(log.LevelInfo) - log.SetDefault(log.NewLogger(glogger)) - - confEnv := os.Getenv(envNodeConfig) - if confEnv == "" { - return - } - var conf execNodeConfig - if err := json.Unmarshal([]byte(confEnv), &conf); err != nil { - return - } - var writer = os.Stderr - if conf.Node.LogFile != "" { - logWriter, err := os.Create(conf.Node.LogFile) - if err != nil { - return - } - writer = logWriter - } - var verbosity = log.LevelInfo - if conf.Node.LogVerbosity <= log.LevelTrace && conf.Node.LogVerbosity >= log.LevelCrit { - verbosity = log.FromLegacyLevel(int(conf.Node.LogVerbosity)) - } - // Reinitialize the logger - innerHandler = log.NewTerminalHandler(writer, true) - glogger = log.NewGlogHandler(innerHandler) - glogger.Verbosity(verbosity) - log.SetDefault(log.NewLogger(glogger)) -} - -// execP2PNode starts a simulation node when the current binary is executed with -// argv[0] being "p2p-node", reading the service / ID from argv[1] / argv[2] -// and the node config from an environment variable. -func execP2PNode() { - initLogging() - - statusURL := os.Getenv(envStatusURL) - if statusURL == "" { - log.Crit("missing " + envStatusURL) - } - - // Start the node and gather startup report. - var status nodeStartupJSON - stack, stackErr := startExecNodeStack() - if stackErr != nil { - status.Err = stackErr.Error() - } else { - status.WSEndpoint = stack.WSEndpoint() - status.NodeInfo = stack.Server().NodeInfo() - } - - // Send status to the host. - statusJSON, _ := json.Marshal(status) - resp, err := http.Post(statusURL, "application/json", bytes.NewReader(statusJSON)) - if err != nil { - log.Crit("Can't post startup info", "url", statusURL, "err", err) - } - resp.Body.Close() - if stackErr != nil { - os.Exit(1) - } - - // Stop the stack if we get a SIGTERM signal. - go func() { - sigc := make(chan os.Signal, 1) - signal.Notify(sigc, syscall.SIGTERM) - defer signal.Stop(sigc) - <-sigc - log.Info("Received SIGTERM, shutting down...") - stack.Close() - }() - stack.Wait() // Wait for the stack to exit. -} - -func startExecNodeStack() (*node.Node, error) { - // read the services from argv - serviceNames := strings.Split(os.Args[1], ",") - - // decode the config - confEnv := os.Getenv(envNodeConfig) - if confEnv == "" { - return nil, errors.New("missing " + envNodeConfig) - } - var conf execNodeConfig - if err := json.Unmarshal([]byte(confEnv), &conf); err != nil { - return nil, fmt.Errorf("error decoding %s: %v", envNodeConfig, err) - } - - // create enode record - nodeTcpConn, _ := net.ResolveTCPAddr("tcp", conf.Stack.P2P.ListenAddr) - if nodeTcpConn.IP == nil { - nodeTcpConn.IP = net.IPv4(127, 0, 0, 1) - } - conf.Node.initEnode(nodeTcpConn.IP, nodeTcpConn.Port, nodeTcpConn.Port) - conf.Stack.P2P.PrivateKey = conf.Node.PrivateKey - conf.Stack.Logger = log.New("node.id", conf.Node.ID.String()) - - // initialize the devp2p stack - stack, err := node.New(&conf.Stack) - if err != nil { - return nil, fmt.Errorf("error creating node stack: %v", err) - } - - // Register the services, collecting them into a map so they can - // be accessed by the snapshot API. - services := make(map[string]node.Lifecycle, len(serviceNames)) - for _, name := range serviceNames { - lifecycleFunc, exists := lifecycleConstructorFuncs[name] - if !exists { - return nil, fmt.Errorf("unknown node service %q", err) - } - ctx := &ServiceContext{ - RPCDialer: &wsRPCDialer{addrs: conf.PeerAddrs}, - Config: conf.Node, - } - if conf.Snapshots != nil { - ctx.Snapshot = conf.Snapshots[name] - } - service, err := lifecycleFunc(ctx, stack) - if err != nil { - return nil, err - } - services[name] = service - } - - // Add the snapshot API. - stack.RegisterAPIs([]rpc.API{{ - Namespace: "simulation", - Service: SnapshotAPI{services}, - }}) - - if err = stack.Start(); err != nil { - err = fmt.Errorf("error starting stack: %v", err) - } - return stack, err -} - -const ( - envStatusURL = "_P2P_STATUS_URL" - envNodeConfig = "_P2P_NODE_CONFIG" -) - -// nodeStartupJSON is sent to the simulation host after startup. -type nodeStartupJSON struct { - Err string - WSEndpoint string - NodeInfo *p2p.NodeInfo -} - -// SnapshotAPI provides an RPC method to create snapshots of services -type SnapshotAPI struct { - services map[string]node.Lifecycle -} - -func (api SnapshotAPI) Snapshot() (map[string][]byte, error) { - snapshots := make(map[string][]byte) - for name, service := range api.services { - if s, ok := service.(interface { - Snapshot() ([]byte, error) - }); ok { - snap, err := s.Snapshot() - if err != nil { - return nil, err - } - snapshots[name] = snap - } - } - return snapshots, nil -} - -type wsRPCDialer struct { - addrs map[string]string -} - -// DialRPC implements the RPCDialer interface by creating a WebSocket RPC -// client of the given node -func (w *wsRPCDialer) DialRPC(id enode.ID) (*rpc.Client, error) { - addr, ok := w.addrs[id.String()] - if !ok { - return nil, fmt.Errorf("unknown node: %s", id) - } - return rpc.DialWebsocket(context.Background(), addr, "http://localhost") -} diff --git a/p2p/simulations/adapters/inproc.go b/p2p/simulations/adapters/inproc.go deleted file mode 100644 index 0efe9744a5c1..000000000000 --- a/p2p/simulations/adapters/inproc.go +++ /dev/null @@ -1,344 +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 adapters - -import ( - "context" - "errors" - "fmt" - "maps" - "math" - "net" - "sync" - - "github.com/ethereum/go-ethereum/event" - "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/pipes" - "github.com/ethereum/go-ethereum/rpc" - "github.com/gorilla/websocket" -) - -// SimAdapter is a NodeAdapter which creates in-memory simulation nodes and -// connects them using net.Pipe -type SimAdapter struct { - pipe func() (net.Conn, net.Conn, error) - mtx sync.RWMutex - nodes map[enode.ID]*SimNode - lifecycles LifecycleConstructors -} - -// NewSimAdapter creates a SimAdapter which is capable of running in-memory -// simulation nodes running any of the given services (the services to run on a -// particular node are passed to the NewNode function in the NodeConfig) -// the adapter uses a net.Pipe for in-memory simulated network connections -func NewSimAdapter(services LifecycleConstructors) *SimAdapter { - return &SimAdapter{ - pipe: pipes.NetPipe, - nodes: make(map[enode.ID]*SimNode), - lifecycles: services, - } -} - -// Name returns the name of the adapter for logging purposes -func (s *SimAdapter) Name() string { - return "sim-adapter" -} - -// NewNode returns a new SimNode using the given config -func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) { - s.mtx.Lock() - defer s.mtx.Unlock() - - id := config.ID - // verify that the node has a private key in the config - if config.PrivateKey == nil { - return nil, fmt.Errorf("node is missing private key: %s", id) - } - - // check a node with the ID doesn't already exist - if _, exists := s.nodes[id]; exists { - return nil, fmt.Errorf("node already exists: %s", id) - } - - // check the services are valid - if len(config.Lifecycles) == 0 { - return nil, errors.New("node must have at least one service") - } - for _, service := range config.Lifecycles { - if _, exists := s.lifecycles[service]; !exists { - return nil, fmt.Errorf("unknown node service %q", service) - } - } - - err := config.initDummyEnode() - if err != nil { - return nil, err - } - - n, err := node.New(&node.Config{ - P2P: p2p.Config{ - PrivateKey: config.PrivateKey, - MaxPeers: math.MaxInt32, - NoDiscovery: true, - Dialer: s, - EnableMsgEvents: config.EnableMsgEvents, - }, - ExternalSigner: config.ExternalSigner, - Logger: log.New("node.id", id.String()), - }) - if err != nil { - return nil, err - } - - simNode := &SimNode{ - ID: id, - config: config, - node: n, - adapter: s, - running: make(map[string]node.Lifecycle), - } - s.nodes[id] = simNode - return simNode, nil -} - -// Dial implements the p2p.NodeDialer interface by connecting to the node using -// an in-memory net.Pipe -func (s *SimAdapter) Dial(ctx context.Context, dest *enode.Node) (conn net.Conn, err error) { - node, ok := s.GetNode(dest.ID()) - if !ok { - return nil, fmt.Errorf("unknown node: %s", dest.ID()) - } - srv := node.Server() - if srv == nil { - return nil, fmt.Errorf("node not running: %s", dest.ID()) - } - // SimAdapter.pipe is net.Pipe (NewSimAdapter) - pipe1, pipe2, err := s.pipe() - if err != nil { - return nil, err - } - // this is simulated 'listening' - // asynchronously call the dialed destination node's p2p server - // to set up connection on the 'listening' side - go srv.SetupConn(pipe1, 0, nil) - return pipe2, nil -} - -// DialRPC implements the RPCDialer interface by creating an in-memory RPC -// client of the given node -func (s *SimAdapter) DialRPC(id enode.ID) (*rpc.Client, error) { - node, ok := s.GetNode(id) - if !ok { - return nil, fmt.Errorf("unknown node: %s", id) - } - return node.node.Attach(), nil -} - -// GetNode returns the node with the given ID if it exists -func (s *SimAdapter) GetNode(id enode.ID) (*SimNode, bool) { - s.mtx.RLock() - defer s.mtx.RUnlock() - node, ok := s.nodes[id] - return node, ok -} - -// SimNode is an in-memory simulation node which connects to other nodes using -// net.Pipe (see SimAdapter.Dial), running devp2p protocols directly over that -// pipe -type SimNode struct { - lock sync.RWMutex - ID enode.ID - config *NodeConfig - adapter *SimAdapter - node *node.Node - running map[string]node.Lifecycle - client *rpc.Client - registerOnce sync.Once -} - -// Close closes the underlying node.Node to release -// acquired resources. -func (sn *SimNode) Close() error { - return sn.node.Close() -} - -// Addr returns the node's discovery address -func (sn *SimNode) Addr() []byte { - return []byte(sn.Node().String()) -} - -// Node returns a node descriptor representing the SimNode -func (sn *SimNode) Node() *enode.Node { - return sn.config.Node() -} - -// Client returns an rpc.Client which can be used to communicate with the -// underlying services (it is set once the node has started) -func (sn *SimNode) Client() (*rpc.Client, error) { - sn.lock.RLock() - defer sn.lock.RUnlock() - if sn.client == nil { - return nil, errors.New("node not started") - } - return sn.client, nil -} - -// ServeRPC serves RPC requests over the given connection by creating an -// in-memory client to the node's RPC server. -func (sn *SimNode) ServeRPC(conn *websocket.Conn) error { - handler, err := sn.node.RPCHandler() - if err != nil { - return err - } - codec := rpc.NewFuncCodec(conn, func(v any, _ bool) error { return conn.WriteJSON(v) }, conn.ReadJSON) - handler.ServeCodec(codec, 0) - return nil -} - -// Snapshots creates snapshots of the services by calling the -// simulation_snapshot RPC method -func (sn *SimNode) Snapshots() (map[string][]byte, error) { - sn.lock.RLock() - services := maps.Clone(sn.running) - sn.lock.RUnlock() - if len(services) == 0 { - return nil, errors.New("no running services") - } - snapshots := make(map[string][]byte) - for name, service := range services { - if s, ok := service.(interface { - Snapshot() ([]byte, error) - }); ok { - snap, err := s.Snapshot() - if err != nil { - return nil, err - } - snapshots[name] = snap - } - } - return snapshots, nil -} - -// Start registers the services and starts the underlying devp2p node -func (sn *SimNode) Start(snapshots map[string][]byte) error { - // ensure we only register the services once in the case of the node - // being stopped and then started again - var regErr error - sn.registerOnce.Do(func() { - for _, name := range sn.config.Lifecycles { - ctx := &ServiceContext{ - RPCDialer: sn.adapter, - Config: sn.config, - } - if snapshots != nil { - ctx.Snapshot = snapshots[name] - } - serviceFunc := sn.adapter.lifecycles[name] - service, err := serviceFunc(ctx, sn.node) - if err != nil { - regErr = err - break - } - // if the service has already been registered, don't register it again. - if _, ok := sn.running[name]; ok { - continue - } - sn.running[name] = service - } - }) - if regErr != nil { - return regErr - } - - if err := sn.node.Start(); err != nil { - return err - } - - // create an in-process RPC client - client := sn.node.Attach() - sn.lock.Lock() - sn.client = client - sn.lock.Unlock() - - return nil -} - -// Stop closes the RPC client and stops the underlying devp2p node -func (sn *SimNode) Stop() error { - sn.lock.Lock() - if sn.client != nil { - sn.client.Close() - sn.client = nil - } - sn.lock.Unlock() - return sn.node.Close() -} - -// Service returns a running service by name -func (sn *SimNode) Service(name string) node.Lifecycle { - sn.lock.RLock() - defer sn.lock.RUnlock() - return sn.running[name] -} - -// Services returns a copy of the underlying services -func (sn *SimNode) Services() []node.Lifecycle { - sn.lock.RLock() - defer sn.lock.RUnlock() - services := make([]node.Lifecycle, 0, len(sn.running)) - for _, service := range sn.running { - services = append(services, service) - } - return services -} - -// ServiceMap returns a map by names of the underlying services -func (sn *SimNode) ServiceMap() map[string]node.Lifecycle { - sn.lock.RLock() - defer sn.lock.RUnlock() - return maps.Clone(sn.running) -} - -// Server returns the underlying p2p.Server -func (sn *SimNode) Server() *p2p.Server { - return sn.node.Server() -} - -// SubscribeEvents subscribes the given channel to peer events from the -// underlying p2p.Server -func (sn *SimNode) SubscribeEvents(ch chan *p2p.PeerEvent) event.Subscription { - srv := sn.Server() - if srv == nil { - panic("node not running") - } - return srv.SubscribeEvents(ch) -} - -// NodeInfo returns information about the node -func (sn *SimNode) NodeInfo() *p2p.NodeInfo { - server := sn.Server() - if server == nil { - return &p2p.NodeInfo{ - ID: sn.ID.String(), - Enode: sn.Node().String(), - } - } - return server.NodeInfo() -} diff --git a/p2p/simulations/adapters/inproc_test.go b/p2p/simulations/adapters/inproc_test.go deleted file mode 100644 index d0539ca86752..000000000000 --- a/p2p/simulations/adapters/inproc_test.go +++ /dev/null @@ -1,202 +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 adapters - -import ( - "bytes" - "encoding/binary" - "fmt" - "sync" - "testing" - - "github.com/ethereum/go-ethereum/p2p/simulations/pipes" -) - -func TestTCPPipe(t *testing.T) { - c1, c2, err := pipes.TCPPipe() - if err != nil { - t.Fatal(err) - } - - msgs := 50 - size := 1024 - for i := 0; i < msgs; i++ { - msg := make([]byte, size) - binary.PutUvarint(msg, uint64(i)) - if _, err := c1.Write(msg); err != nil { - t.Fatal(err) - } - } - - for i := 0; i < msgs; i++ { - msg := make([]byte, size) - binary.PutUvarint(msg, uint64(i)) - out := make([]byte, size) - if _, err := c2.Read(out); err != nil { - t.Fatal(err) - } - if !bytes.Equal(msg, out) { - t.Fatalf("expected %#v, got %#v", msg, out) - } - } -} - -func TestTCPPipeBidirections(t *testing.T) { - c1, c2, err := pipes.TCPPipe() - if err != nil { - t.Fatal(err) - } - - msgs := 50 - size := 7 - for i := 0; i < msgs; i++ { - msg := []byte(fmt.Sprintf("ping %02d", i)) - if _, err := c1.Write(msg); err != nil { - t.Fatal(err) - } - } - - for i := 0; i < msgs; i++ { - expected := []byte(fmt.Sprintf("ping %02d", i)) - out := make([]byte, size) - if _, err := c2.Read(out); err != nil { - t.Fatal(err) - } - - if !bytes.Equal(expected, out) { - t.Fatalf("expected %#v, got %#v", expected, out) - } else { - msg := []byte(fmt.Sprintf("pong %02d", i)) - if _, err := c2.Write(msg); err != nil { - t.Fatal(err) - } - } - } - - for i := 0; i < msgs; i++ { - expected := []byte(fmt.Sprintf("pong %02d", i)) - out := make([]byte, size) - if _, err := c1.Read(out); err != nil { - t.Fatal(err) - } - if !bytes.Equal(expected, out) { - t.Fatalf("expected %#v, got %#v", expected, out) - } - } -} - -func TestNetPipe(t *testing.T) { - c1, c2, err := pipes.NetPipe() - if err != nil { - t.Fatal(err) - } - - msgs := 50 - size := 1024 - var wg sync.WaitGroup - defer wg.Wait() - - // netPipe is blocking, so writes are emitted asynchronously - wg.Add(1) - go func() { - defer wg.Done() - - for i := 0; i < msgs; i++ { - msg := make([]byte, size) - binary.PutUvarint(msg, uint64(i)) - if _, err := c1.Write(msg); err != nil { - t.Error(err) - } - } - }() - - for i := 0; i < msgs; i++ { - msg := make([]byte, size) - binary.PutUvarint(msg, uint64(i)) - out := make([]byte, size) - if _, err := c2.Read(out); err != nil { - t.Error(err) - } - if !bytes.Equal(msg, out) { - t.Errorf("expected %#v, got %#v", msg, out) - } - } -} - -func TestNetPipeBidirections(t *testing.T) { - c1, c2, err := pipes.NetPipe() - if err != nil { - t.Fatal(err) - } - - msgs := 1000 - size := 8 - pingTemplate := "ping %03d" - pongTemplate := "pong %03d" - var wg sync.WaitGroup - defer wg.Wait() - - // netPipe is blocking, so writes are emitted asynchronously - wg.Add(1) - go func() { - defer wg.Done() - - for i := 0; i < msgs; i++ { - msg := []byte(fmt.Sprintf(pingTemplate, i)) - if _, err := c1.Write(msg); err != nil { - t.Error(err) - } - } - }() - - // netPipe is blocking, so reads for pong are emitted asynchronously - wg.Add(1) - go func() { - defer wg.Done() - - for i := 0; i < msgs; i++ { - expected := []byte(fmt.Sprintf(pongTemplate, i)) - out := make([]byte, size) - if _, err := c1.Read(out); err != nil { - t.Error(err) - } - if !bytes.Equal(expected, out) { - t.Errorf("expected %#v, got %#v", expected, out) - } - } - }() - - // expect to read pings, and respond with pongs to the alternate connection - for i := 0; i < msgs; i++ { - expected := []byte(fmt.Sprintf(pingTemplate, i)) - - out := make([]byte, size) - _, err := c2.Read(out) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(expected, out) { - t.Errorf("expected %#v, got %#v", expected, out) - } else { - msg := []byte(fmt.Sprintf(pongTemplate, i)) - if _, err := c2.Write(msg); err != nil { - t.Fatal(err) - } - } - } -} diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go deleted file mode 100644 index e18aaacc334a..000000000000 --- a/p2p/simulations/adapters/types.go +++ /dev/null @@ -1,325 +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 adapters - -import ( - "crypto/ecdsa" - "encoding/hex" - "encoding/json" - "fmt" - "log/slog" - "net" - "os" - "strconv" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/internal/reexec" - "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/enr" - "github.com/ethereum/go-ethereum/rpc" - "github.com/gorilla/websocket" -) - -// Node represents a node in a simulation network which is created by a -// NodeAdapter, for example: -// -// - SimNode, an in-memory node in the same process -// - ExecNode, a child process node -type Node interface { - // Addr returns the node's address (e.g. an Enode URL) - Addr() []byte - - // Client returns the RPC client which is created once the node is - // up and running - Client() (*rpc.Client, error) - - // ServeRPC serves RPC requests over the given connection - ServeRPC(*websocket.Conn) error - - // Start starts the node with the given snapshots - Start(snapshots map[string][]byte) error - - // Stop stops the node - Stop() error - - // NodeInfo returns information about the node - NodeInfo() *p2p.NodeInfo - - // Snapshots creates snapshots of the running services - Snapshots() (map[string][]byte, error) -} - -// NodeAdapter is used to create Nodes in a simulation network -type NodeAdapter interface { - // Name returns the name of the adapter for logging purposes - Name() string - - // NewNode creates a new node with the given configuration - NewNode(config *NodeConfig) (Node, error) -} - -// NodeConfig is the configuration used to start a node in a simulation -// network -type NodeConfig struct { - // ID is the node's ID which is used to identify the node in the - // simulation network - ID enode.ID - - // PrivateKey is the node's private key which is used by the devp2p - // stack to encrypt communications - PrivateKey *ecdsa.PrivateKey - - // Enable peer events for Msgs - EnableMsgEvents bool - - // Name is a human friendly name for the node like "node01" - Name string - - // Use an existing database instead of a temporary one if non-empty - DataDir string - - // Lifecycles are the names of the service lifecycles which should be run when - // starting the node (for SimNodes it should be the names of service lifecycles - // contained in SimAdapter.lifecycles, for other nodes it should be - // service lifecycles registered by calling the RegisterLifecycle function) - Lifecycles []string - - // Properties are the names of the properties this node should hold - // within running services (e.g. "bootnode", "lightnode" or any custom values) - // These values need to be checked and acted upon by node Services - Properties []string - - // ExternalSigner specifies an external URI for a clef-type signer - ExternalSigner string - - // Enode - node *enode.Node - - // ENR Record with entries to overwrite - Record enr.Record - - // function to sanction or prevent suggesting a peer - Reachable func(id enode.ID) bool - - Port uint16 - - // LogFile is the log file name of the p2p node at runtime. - // - // The default value is empty so that the default log writer - // is the system standard output. - LogFile string - - // LogVerbosity is the log verbosity of the p2p node at runtime. - // - // The default verbosity is INFO. - LogVerbosity slog.Level -} - -// nodeConfigJSON is used to encode and decode NodeConfig as JSON by encoding -// all fields as strings -type nodeConfigJSON struct { - ID string `json:"id"` - PrivateKey string `json:"private_key"` - Name string `json:"name"` - Lifecycles []string `json:"lifecycles"` - Properties []string `json:"properties"` - EnableMsgEvents bool `json:"enable_msg_events"` - Port uint16 `json:"port"` - LogFile string `json:"logfile"` - LogVerbosity int `json:"log_verbosity"` -} - -// MarshalJSON implements the json.Marshaler interface by encoding the config -// fields as strings -func (n *NodeConfig) MarshalJSON() ([]byte, error) { - confJSON := nodeConfigJSON{ - ID: n.ID.String(), - Name: n.Name, - Lifecycles: n.Lifecycles, - Properties: n.Properties, - Port: n.Port, - EnableMsgEvents: n.EnableMsgEvents, - LogFile: n.LogFile, - LogVerbosity: int(n.LogVerbosity), - } - if n.PrivateKey != nil { - confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey)) - } - return json.Marshal(confJSON) -} - -// UnmarshalJSON implements the json.Unmarshaler interface by decoding the json -// string values into the config fields -func (n *NodeConfig) UnmarshalJSON(data []byte) error { - var confJSON nodeConfigJSON - if err := json.Unmarshal(data, &confJSON); err != nil { - return err - } - - if confJSON.ID != "" { - if err := n.ID.UnmarshalText([]byte(confJSON.ID)); err != nil { - return err - } - } - - if confJSON.PrivateKey != "" { - key, err := hex.DecodeString(confJSON.PrivateKey) - if err != nil { - return err - } - privKey, err := crypto.ToECDSA(key) - if err != nil { - return err - } - n.PrivateKey = privKey - } - - n.Name = confJSON.Name - n.Lifecycles = confJSON.Lifecycles - n.Properties = confJSON.Properties - n.Port = confJSON.Port - n.EnableMsgEvents = confJSON.EnableMsgEvents - n.LogFile = confJSON.LogFile - n.LogVerbosity = slog.Level(confJSON.LogVerbosity) - - return nil -} - -// Node returns the node descriptor represented by the config. -func (n *NodeConfig) Node() *enode.Node { - return n.node -} - -// RandomNodeConfig returns node configuration with a randomly generated ID and -// PrivateKey -func RandomNodeConfig() *NodeConfig { - prvkey, err := crypto.GenerateKey() - if err != nil { - panic("unable to generate key") - } - - port, err := assignTCPPort() - if err != nil { - panic("unable to assign tcp port") - } - - enodId := enode.PubkeyToIDV4(&prvkey.PublicKey) - return &NodeConfig{ - PrivateKey: prvkey, - ID: enodId, - Name: fmt.Sprintf("node_%s", enodId.String()), - Port: port, - EnableMsgEvents: true, - LogVerbosity: log.LvlInfo, - } -} - -func assignTCPPort() (uint16, error) { - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - return 0, err - } - l.Close() - _, port, err := net.SplitHostPort(l.Addr().String()) - if err != nil { - return 0, err - } - p, err := strconv.ParseUint(port, 10, 16) - if err != nil { - return 0, err - } - return uint16(p), nil -} - -// ServiceContext is a collection of options and methods which can be utilised -// when starting services -type ServiceContext struct { - RPCDialer - - Config *NodeConfig - Snapshot []byte -} - -// RPCDialer is used when initialising services which need to connect to -// other nodes in the network (for example a simulated Swarm node which needs -// to connect to a Geth node to resolve ENS names) -type RPCDialer interface { - DialRPC(id enode.ID) (*rpc.Client, error) -} - -// LifecycleConstructor allows a Lifecycle to be constructed during node start-up. -// While the service-specific package usually takes care of Lifecycle creation and registration, -// for testing purposes, it is useful to be able to construct a Lifecycle on spot. -type LifecycleConstructor func(ctx *ServiceContext, stack *node.Node) (node.Lifecycle, error) - -// LifecycleConstructors stores LifecycleConstructor functions to call during node start-up. -type LifecycleConstructors map[string]LifecycleConstructor - -// lifecycleConstructorFuncs is a map of registered services which are used to boot devp2p -// nodes -var lifecycleConstructorFuncs = make(LifecycleConstructors) - -// RegisterLifecycles registers the given Services which can then be used to -// start devp2p nodes using either the Exec or Docker adapters. -// -// It should be called in an init function so that it has the opportunity to -// execute the services before main() is called. -func RegisterLifecycles(lifecycles LifecycleConstructors) { - for name, f := range lifecycles { - if _, exists := lifecycleConstructorFuncs[name]; exists { - panic(fmt.Sprintf("node service already exists: %q", name)) - } - lifecycleConstructorFuncs[name] = f - } - - // now we have registered the services, run reexec.Init() which will - // potentially start one of the services if the current binary has - // been exec'd with argv[0] set to "p2p-node" - if reexec.Init() { - os.Exit(0) - } -} - -// adds the host part to the configuration's ENR, signs it -// creates and adds the corresponding enode object to the configuration -func (n *NodeConfig) initEnode(ip net.IP, tcpport int, udpport int) error { - enrIp := enr.IP(ip) - n.Record.Set(&enrIp) - enrTcpPort := enr.TCP(tcpport) - n.Record.Set(&enrTcpPort) - enrUdpPort := enr.UDP(udpport) - n.Record.Set(&enrUdpPort) - - err := enode.SignV4(&n.Record, n.PrivateKey) - if err != nil { - return fmt.Errorf("unable to generate ENR: %v", err) - } - nod, err := enode.New(enode.V4ID{}, &n.Record) - if err != nil { - return fmt.Errorf("unable to create enode: %v", err) - } - log.Trace("simnode new", "record", n.Record) - n.node = nod - return nil -} - -func (n *NodeConfig) initDummyEnode() error { - return n.initEnode(net.IPv4(127, 0, 0, 1), int(n.Port), 0) -} diff --git a/p2p/simulations/connect.go b/p2p/simulations/connect.go deleted file mode 100644 index ede96b34c133..000000000000 --- a/p2p/simulations/connect.go +++ /dev/null @@ -1,153 +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 simulations - -import ( - "errors" - "strings" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -var ( - ErrNodeNotFound = errors.New("node not found") -) - -// ConnectToLastNode connects the node with provided NodeID -// to the last node that is up, and avoiding connection to self. -// It is useful when constructing a chain network topology -// when Network adds and removes nodes dynamically. -func (net *Network) ConnectToLastNode(id enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - ids := net.getUpNodeIDs() - l := len(ids) - if l < 2 { - return nil - } - last := ids[l-1] - if last == id { - last = ids[l-2] - } - return net.connectNotConnected(last, id) -} - -// ConnectToRandomNode connects the node with provided NodeID -// to a random node that is up. -func (net *Network) ConnectToRandomNode(id enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - selected := net.getRandomUpNode(id) - if selected == nil { - return ErrNodeNotFound - } - return net.connectNotConnected(selected.ID(), id) -} - -// ConnectNodesFull connects all nodes one to another. -// It provides a complete connectivity in the network -// which should be rarely needed. -func (net *Network) ConnectNodesFull(ids []enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - if ids == nil { - ids = net.getUpNodeIDs() - } - for i, lid := range ids { - for _, rid := range ids[i+1:] { - if err = net.connectNotConnected(lid, rid); err != nil { - return err - } - } - } - return nil -} - -// ConnectNodesChain connects all nodes in a chain topology. -// If ids argument is nil, all nodes that are up will be connected. -func (net *Network) ConnectNodesChain(ids []enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - return net.connectNodesChain(ids) -} - -func (net *Network) connectNodesChain(ids []enode.ID) (err error) { - if ids == nil { - ids = net.getUpNodeIDs() - } - l := len(ids) - for i := 0; i < l-1; i++ { - if err := net.connectNotConnected(ids[i], ids[i+1]); err != nil { - return err - } - } - return nil -} - -// ConnectNodesRing connects all nodes in a ring topology. -// If ids argument is nil, all nodes that are up will be connected. -func (net *Network) ConnectNodesRing(ids []enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - if ids == nil { - ids = net.getUpNodeIDs() - } - l := len(ids) - if l < 2 { - return nil - } - if err := net.connectNodesChain(ids); err != nil { - return err - } - return net.connectNotConnected(ids[l-1], ids[0]) -} - -// ConnectNodesStar connects all nodes into a star topology -// If ids argument is nil, all nodes that are up will be connected. -func (net *Network) ConnectNodesStar(ids []enode.ID, center enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - if ids == nil { - ids = net.getUpNodeIDs() - } - for _, id := range ids { - if center == id { - continue - } - if err := net.connectNotConnected(center, id); err != nil { - return err - } - } - return nil -} - -func (net *Network) connectNotConnected(oneID, otherID enode.ID) error { - return ignoreAlreadyConnectedErr(net.connect(oneID, otherID)) -} - -func ignoreAlreadyConnectedErr(err error) error { - if err == nil || strings.Contains(err.Error(), "already connected") { - return nil - } - return err -} diff --git a/p2p/simulations/connect_test.go b/p2p/simulations/connect_test.go deleted file mode 100644 index 0154a18b030f..000000000000 --- a/p2p/simulations/connect_test.go +++ /dev/null @@ -1,172 +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 simulations - -import ( - "testing" - - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -func newTestNetwork(t *testing.T, nodeCount int) (*Network, []enode.ID) { - t.Helper() - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - return NewNoopService(nil), nil - }, - }) - - // create network - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "noopwoop", - }) - - // create and start nodes - ids := make([]enode.ID, nodeCount) - for i := range ids { - conf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(conf) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := network.Start(node.ID()); err != nil { - t.Fatalf("error starting node: %s", err) - } - ids[i] = node.ID() - } - - if len(network.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - return network, ids -} - -func TestConnectToLastNode(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - first := ids[0] - if err := net.ConnectToLastNode(first); err != nil { - t.Fatal(err) - } - - last := ids[len(ids)-1] - for i, id := range ids { - if id == first || id == last { - continue - } - - if net.GetConn(first, id) != nil { - t.Errorf("connection must not exist with node(ind: %v, id: %v)", i, id) - } - } - - if net.GetConn(first, last) == nil { - t.Error("first and last node must be connected") - } -} - -func TestConnectToRandomNode(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - err := net.ConnectToRandomNode(ids[0]) - if err != nil { - t.Fatal(err) - } - - var cc int - for i, a := range ids { - for _, b := range ids[i:] { - if net.GetConn(a, b) != nil { - cc++ - } - } - } - - if cc != 1 { - t.Errorf("expected one connection, got %v", cc) - } -} - -func TestConnectNodesFull(t *testing.T) { - tests := []struct { - name string - nodeCount int - }{ - {name: "no node", nodeCount: 0}, - {name: "single node", nodeCount: 1}, - {name: "2 nodes", nodeCount: 2}, - {name: "3 nodes", nodeCount: 3}, - {name: "even number of nodes", nodeCount: 12}, - {name: "odd number of nodes", nodeCount: 13}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - net, ids := newTestNetwork(t, test.nodeCount) - defer net.Shutdown() - - err := net.ConnectNodesFull(ids) - if err != nil { - t.Fatal(err) - } - - VerifyFull(t, net, ids) - }) - } -} - -func TestConnectNodesChain(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - err := net.ConnectNodesChain(ids) - if err != nil { - t.Fatal(err) - } - - VerifyChain(t, net, ids) -} - -func TestConnectNodesRing(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - err := net.ConnectNodesRing(ids) - if err != nil { - t.Fatal(err) - } - - VerifyRing(t, net, ids) -} - -func TestConnectNodesStar(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - pivotIndex := 2 - - err := net.ConnectNodesStar(ids, ids[pivotIndex]) - if err != nil { - t.Fatal(err) - } - - VerifyStar(t, net, ids, pivotIndex) -} diff --git a/p2p/simulations/events.go b/p2p/simulations/events.go deleted file mode 100644 index 1131185fb914..000000000000 --- a/p2p/simulations/events.go +++ /dev/null @@ -1,110 +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 simulations - -import ( - "fmt" - "time" -) - -// EventType is the type of event emitted by a simulation network -type EventType string - -const ( - // EventTypeNode is the type of event emitted when a node is either - // created, started or stopped - EventTypeNode EventType = "node" - - // EventTypeConn is the type of event emitted when a connection is - // either established or dropped between two nodes - EventTypeConn EventType = "conn" - - // EventTypeMsg is the type of event emitted when a p2p message it - // sent between two nodes - EventTypeMsg EventType = "msg" -) - -// Event is an event emitted by a simulation network -type Event struct { - // Type is the type of the event - Type EventType `json:"type"` - - // Time is the time the event happened - Time time.Time `json:"time"` - - // Control indicates whether the event is the result of a controlled - // action in the network - Control bool `json:"control"` - - // Node is set if the type is EventTypeNode - Node *Node `json:"node,omitempty"` - - // Conn is set if the type is EventTypeConn - Conn *Conn `json:"conn,omitempty"` - - // Msg is set if the type is EventTypeMsg - Msg *Msg `json:"msg,omitempty"` - - //Optionally provide data (currently for simulation frontends only) - Data interface{} `json:"data"` -} - -// NewEvent creates a new event for the given object which should be either a -// Node, Conn or Msg. -// -// The object is copied so that the event represents the state of the object -// when NewEvent is called. -func NewEvent(v interface{}) *Event { - event := &Event{Time: time.Now()} - switch v := v.(type) { - case *Node: - event.Type = EventTypeNode - event.Node = v.copy() - case *Conn: - event.Type = EventTypeConn - conn := *v - event.Conn = &conn - case *Msg: - event.Type = EventTypeMsg - msg := *v - event.Msg = &msg - default: - panic(fmt.Sprintf("invalid event type: %T", v)) - } - return event -} - -// ControlEvent creates a new control event -func ControlEvent(v interface{}) *Event { - event := NewEvent(v) - event.Control = true - return event -} - -// String returns the string representation of the event -func (e *Event) String() string { - switch e.Type { - case EventTypeNode: - return fmt.Sprintf(" id: %s up: %t", e.Node.ID().TerminalString(), e.Node.Up()) - case EventTypeConn: - return fmt.Sprintf(" nodes: %s->%s up: %t", e.Conn.One.TerminalString(), e.Conn.Other.TerminalString(), e.Conn.Up) - case EventTypeMsg: - return fmt.Sprintf(" nodes: %s->%s proto: %s, code: %d, received: %t", e.Msg.One.TerminalString(), e.Msg.Other.TerminalString(), e.Msg.Protocol, e.Msg.Code, e.Msg.Received) - default: - return "" - } -} diff --git a/p2p/simulations/examples/README.md b/p2p/simulations/examples/README.md deleted file mode 100644 index 822a48dcb6e4..000000000000 --- a/p2p/simulations/examples/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# devp2p simulation examples - -## ping-pong - -`ping-pong.go` implements a simulation network which contains nodes running a -simple "ping-pong" protocol where nodes send a ping message to all their -connected peers every 10s and receive pong messages in return. - -To run the simulation, run `go run ping-pong.go` in one terminal to start the -simulation API and `./ping-pong.sh` in another to start and connect the nodes: - -``` -$ go run ping-pong.go -INFO [08-15|13:53:49] using sim adapter -INFO [08-15|13:53:49] starting simulation server on 0.0.0.0:8888... -``` - -``` -$ ./ping-pong.sh ----> 13:58:12 creating 10 nodes -Created node01 -Started node01 -... -Created node10 -Started node10 ----> 13:58:13 connecting node01 to all other nodes -Connected node01 to node02 -... -Connected node01 to node10 ----> 13:58:14 done -``` - -Use the `--adapter` flag to choose the adapter type: - -``` -$ go run ping-pong.go --adapter exec -INFO [08-15|14:01:14] using exec adapter tmpdir=/var/folders/k6/wpsgfg4n23ddbc6f5cnw5qg00000gn/T/p2p-example992833779 -INFO [08-15|14:01:14] starting simulation server on 0.0.0.0:8888... -``` diff --git a/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go deleted file mode 100644 index b0b8f22fdb72..000000000000 --- a/p2p/simulations/examples/ping-pong.go +++ /dev/null @@ -1,173 +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 main - -import ( - "flag" - "fmt" - "io" - "net/http" - "os" - "sync/atomic" - "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" -) - -var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim" or "exec")`) - -// main() starts a simulation network which contains nodes running a simple -// ping-pong protocol -func main() { - flag.Parse() - - // set the log level to Trace - log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, false))) - - // register a single ping-pong service - services := map[string]adapters.LifecycleConstructor{ - "ping-pong": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - pps := newPingPongService(ctx.Config.ID) - stack.RegisterProtocols(pps.Protocols()) - return pps, nil - }, - } - adapters.RegisterLifecycles(services) - - // create the NodeAdapter - var adapter adapters.NodeAdapter - - switch *adapterType { - - case "sim": - log.Info("using sim adapter") - adapter = adapters.NewSimAdapter(services) - - case "exec": - tmpdir, err := os.MkdirTemp("", "p2p-example") - if err != nil { - log.Crit("error creating temp dir", "err", err) - } - defer os.RemoveAll(tmpdir) - log.Info("using exec adapter", "tmpdir", tmpdir) - adapter = adapters.NewExecAdapter(tmpdir) - - default: - log.Crit(fmt.Sprintf("unknown node adapter %q", *adapterType)) - } - - // start the HTTP API - log.Info("starting simulation server on 0.0.0.0:8888...") - network := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ - DefaultService: "ping-pong", - }) - if err := http.ListenAndServe(":8888", simulations.NewServer(network)); err != nil { - log.Crit("error starting simulation server", "err", err) - } -} - -// pingPongService runs a ping-pong protocol between nodes where each node -// sends a ping to all its connected peers every 10s and receives a pong in -// return -type pingPongService struct { - id enode.ID - log log.Logger - received atomic.Int64 -} - -func newPingPongService(id enode.ID) *pingPongService { - return &pingPongService{ - id: id, - log: log.New("node.id", id), - } -} - -func (p *pingPongService) Protocols() []p2p.Protocol { - return []p2p.Protocol{{ - Name: "ping-pong", - Version: 1, - Length: 2, - Run: p.Run, - NodeInfo: p.Info, - }} -} - -func (p *pingPongService) Start() error { - p.log.Info("ping-pong service starting") - return nil -} - -func (p *pingPongService) Stop() error { - p.log.Info("ping-pong service stopping") - return nil -} - -func (p *pingPongService) Info() interface{} { - return struct { - Received int64 `json:"received"` - }{ - p.received.Load(), - } -} - -const ( - pingMsgCode = iota - pongMsgCode -) - -// Run implements the ping-pong protocol which sends ping messages to the peer -// at 10s intervals, and responds to pings with pong messages. -func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { - log := p.log.New("peer.id", peer.ID()) - - errC := make(chan error, 1) - go func() { - for range time.Tick(10 * time.Second) { - log.Info("sending ping") - if err := p2p.Send(rw, pingMsgCode, "PING"); err != nil { - errC <- err - return - } - } - }() - go func() { - for { - msg, err := rw.ReadMsg() - if err != nil { - errC <- err - return - } - payload, err := io.ReadAll(msg.Payload) - if err != nil { - errC <- err - return - } - log.Info("received message", "msg.code", msg.Code, "msg.payload", string(payload)) - p.received.Add(1) - if msg.Code == pingMsgCode { - log.Info("sending pong") - go p2p.Send(rw, pongMsgCode, "PONG") - } - } - }() - return <-errC -} diff --git a/p2p/simulations/examples/ping-pong.sh b/p2p/simulations/examples/ping-pong.sh deleted file mode 100755 index 47936bd9a071..000000000000 --- a/p2p/simulations/examples/ping-pong.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -# -# Boot a ping-pong network simulation using the HTTP API started by ping-pong.go - -set -e - -main() { - if ! which p2psim &>/dev/null; then - fail "missing p2psim binary (you need to build cmd/p2psim and put it in \$PATH)" - fi - - info "creating 10 nodes" - for i in $(seq 1 10); do - p2psim node create --name "$(node_name $i)" - p2psim node start "$(node_name $i)" - done - - info "connecting node01 to all other nodes" - for i in $(seq 2 10); do - p2psim node connect "node01" "$(node_name $i)" - done - - info "done" -} - -node_name() { - local num=$1 - echo "node$(printf '%02d' $num)" -} - -info() { - echo -e "\033[1;32m---> $(date +%H:%M:%S) ${@}\033[0m" -} - -fail() { - echo -e "\033[1;31mERROR: ${@}\033[0m" >&2 - exit 1 -} - -main "$@" diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go deleted file mode 100644 index 34521b477898..000000000000 --- a/p2p/simulations/http.go +++ /dev/null @@ -1,743 +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 simulations - -import ( - "bufio" - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "html" - "io" - "net/http" - "strconv" - "strings" - "sync" - - "github.com/ethereum/go-ethereum/event" - "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/gorilla/websocket" - "github.com/julienschmidt/httprouter" -) - -// DefaultClient is the default simulation API client which expects the API -// to be running at http://localhost:8888 -var DefaultClient = NewClient("http://localhost:8888") - -// Client is a client for the simulation HTTP API which supports creating -// and managing simulation networks -type Client struct { - URL string - - client *http.Client -} - -// NewClient returns a new simulation API client -func NewClient(url string) *Client { - return &Client{ - URL: url, - client: http.DefaultClient, - } -} - -// GetNetwork returns details of the network -func (c *Client) GetNetwork() (*Network, error) { - network := &Network{} - return network, c.Get("/", network) -} - -// StartNetwork starts all existing nodes in the simulation network -func (c *Client) StartNetwork() error { - return c.Post("/start", nil, nil) -} - -// StopNetwork stops all existing nodes in a simulation network -func (c *Client) StopNetwork() error { - return c.Post("/stop", nil, nil) -} - -// CreateSnapshot creates a network snapshot -func (c *Client) CreateSnapshot() (*Snapshot, error) { - snap := &Snapshot{} - return snap, c.Get("/snapshot", snap) -} - -// LoadSnapshot loads a snapshot into the network -func (c *Client) LoadSnapshot(snap *Snapshot) error { - return c.Post("/snapshot", snap, nil) -} - -// SubscribeOpts is a collection of options to use when subscribing to network -// events -type SubscribeOpts struct { - // Current instructs the server to send events for existing nodes and - // connections first - Current bool - - // Filter instructs the server to only send a subset of message events - Filter string -} - -// SubscribeNetwork subscribes to network events which are sent from the server -// as a server-sent-events stream, optionally receiving events for existing -// nodes and connections and filtering message events -func (c *Client) SubscribeNetwork(events chan *Event, opts SubscribeOpts) (event.Subscription, error) { - url := fmt.Sprintf("%s/events?current=%t&filter=%s", c.URL, opts.Current, opts.Filter) - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - return nil, err - } - req.Header.Set("Accept", "text/event-stream") - res, err := c.client.Do(req) - if err != nil { - return nil, err - } - if res.StatusCode != http.StatusOK { - response, _ := io.ReadAll(res.Body) - res.Body.Close() - return nil, fmt.Errorf("unexpected HTTP status: %s: %s", res.Status, response) - } - - // define a producer function to pass to event.Subscription - // which reads server-sent events from res.Body and sends - // them to the events channel - producer := func(stop <-chan struct{}) error { - defer res.Body.Close() - - // read lines from res.Body in a goroutine so that we are - // always reading from the stop channel - lines := make(chan string) - errC := make(chan error, 1) - go func() { - s := bufio.NewScanner(res.Body) - for s.Scan() { - select { - case lines <- s.Text(): - case <-stop: - return - } - } - errC <- s.Err() - }() - - // detect any lines which start with "data:", decode the data - // into an event and send it to the events channel - for { - select { - case line := <-lines: - if !strings.HasPrefix(line, "data:") { - continue - } - data := strings.TrimSpace(strings.TrimPrefix(line, "data:")) - event := &Event{} - if err := json.Unmarshal([]byte(data), event); err != nil { - return fmt.Errorf("error decoding SSE event: %s", err) - } - select { - case events <- event: - case <-stop: - return nil - } - case err := <-errC: - return err - case <-stop: - return nil - } - } - } - - return event.NewSubscription(producer), nil -} - -// GetNodes returns all nodes which exist in the network -func (c *Client) GetNodes() ([]*p2p.NodeInfo, error) { - var nodes []*p2p.NodeInfo - return nodes, c.Get("/nodes", &nodes) -} - -// CreateNode creates a node in the network using the given configuration -func (c *Client) CreateNode(config *adapters.NodeConfig) (*p2p.NodeInfo, error) { - node := &p2p.NodeInfo{} - return node, c.Post("/nodes", config, node) -} - -// GetNode returns details of a node -func (c *Client) GetNode(nodeID string) (*p2p.NodeInfo, error) { - node := &p2p.NodeInfo{} - return node, c.Get(fmt.Sprintf("/nodes/%s", nodeID), node) -} - -// StartNode starts a node -func (c *Client) StartNode(nodeID string) error { - return c.Post(fmt.Sprintf("/nodes/%s/start", nodeID), nil, nil) -} - -// StopNode stops a node -func (c *Client) StopNode(nodeID string) error { - return c.Post(fmt.Sprintf("/nodes/%s/stop", nodeID), nil, nil) -} - -// ConnectNode connects a node to a peer node -func (c *Client) ConnectNode(nodeID, peerID string) error { - return c.Post(fmt.Sprintf("/nodes/%s/conn/%s", nodeID, peerID), nil, nil) -} - -// DisconnectNode disconnects a node from a peer node -func (c *Client) DisconnectNode(nodeID, peerID string) error { - return c.Delete(fmt.Sprintf("/nodes/%s/conn/%s", nodeID, peerID)) -} - -// RPCClient returns an RPC client connected to a node -func (c *Client) RPCClient(ctx context.Context, nodeID string) (*rpc.Client, error) { - baseURL := strings.Replace(c.URL, "http", "ws", 1) - return rpc.DialWebsocket(ctx, fmt.Sprintf("%s/nodes/%s/rpc", baseURL, nodeID), "") -} - -// Get performs a HTTP GET request decoding the resulting JSON response -// into "out" -func (c *Client) Get(path string, out interface{}) error { - return c.Send(http.MethodGet, path, nil, out) -} - -// Post performs a HTTP POST request sending "in" as the JSON body and -// decoding the resulting JSON response into "out" -func (c *Client) Post(path string, in, out interface{}) error { - return c.Send(http.MethodPost, path, in, out) -} - -// Delete performs a HTTP DELETE request -func (c *Client) Delete(path string) error { - return c.Send(http.MethodDelete, path, nil, nil) -} - -// Send performs a HTTP request, sending "in" as the JSON request body and -// decoding the JSON response into "out" -func (c *Client) Send(method, path string, in, out interface{}) error { - var body []byte - if in != nil { - var err error - body, err = json.Marshal(in) - if err != nil { - return err - } - } - req, err := http.NewRequest(method, c.URL+path, bytes.NewReader(body)) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - res, err := c.client.Do(req) - if err != nil { - return err - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { - response, _ := io.ReadAll(res.Body) - return fmt.Errorf("unexpected HTTP status: %s: %s", res.Status, response) - } - if out != nil { - if err := json.NewDecoder(res.Body).Decode(out); err != nil { - return err - } - } - return nil -} - -// Server is an HTTP server providing an API to manage a simulation network -type Server struct { - router *httprouter.Router - network *Network - mockerStop chan struct{} // when set, stops the current mocker - mockerMtx sync.Mutex // synchronises access to the mockerStop field -} - -// NewServer returns a new simulation API server -func NewServer(network *Network) *Server { - s := &Server{ - router: httprouter.New(), - network: network, - } - - s.OPTIONS("/", s.Options) - s.GET("/", s.GetNetwork) - s.POST("/start", s.StartNetwork) - s.POST("/stop", s.StopNetwork) - s.POST("/mocker/start", s.StartMocker) - s.POST("/mocker/stop", s.StopMocker) - s.GET("/mocker", s.GetMockers) - s.POST("/reset", s.ResetNetwork) - s.GET("/events", s.StreamNetworkEvents) - s.GET("/snapshot", s.CreateSnapshot) - s.POST("/snapshot", s.LoadSnapshot) - s.POST("/nodes", s.CreateNode) - s.GET("/nodes", s.GetNodes) - s.GET("/nodes/:nodeid", s.GetNode) - s.POST("/nodes/:nodeid/start", s.StartNode) - s.POST("/nodes/:nodeid/stop", s.StopNode) - s.POST("/nodes/:nodeid/conn/:peerid", s.ConnectNode) - s.DELETE("/nodes/:nodeid/conn/:peerid", s.DisconnectNode) - s.GET("/nodes/:nodeid/rpc", s.NodeRPC) - - return s -} - -// GetNetwork returns details of the network -func (s *Server) GetNetwork(w http.ResponseWriter, req *http.Request) { - s.JSON(w, http.StatusOK, s.network) -} - -// StartNetwork starts all nodes in the network -func (s *Server) StartNetwork(w http.ResponseWriter, req *http.Request) { - if err := s.network.StartAll(); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusOK) -} - -// StopNetwork stops all nodes in the network -func (s *Server) StopNetwork(w http.ResponseWriter, req *http.Request) { - if err := s.network.StopAll(); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusOK) -} - -// StartMocker starts the mocker node simulation -func (s *Server) StartMocker(w http.ResponseWriter, req *http.Request) { - s.mockerMtx.Lock() - defer s.mockerMtx.Unlock() - if s.mockerStop != nil { - http.Error(w, "mocker already running", http.StatusInternalServerError) - return - } - mockerType := req.FormValue("mocker-type") - mockerFn := LookupMocker(mockerType) - if mockerFn == nil { - http.Error(w, fmt.Sprintf("unknown mocker type %q", html.EscapeString(mockerType)), http.StatusBadRequest) - return - } - nodeCount, err := strconv.Atoi(req.FormValue("node-count")) - if err != nil { - http.Error(w, "invalid node-count provided", http.StatusBadRequest) - return - } - s.mockerStop = make(chan struct{}) - go mockerFn(s.network, s.mockerStop, nodeCount) - - w.WriteHeader(http.StatusOK) -} - -// StopMocker stops the mocker node simulation -func (s *Server) StopMocker(w http.ResponseWriter, req *http.Request) { - s.mockerMtx.Lock() - defer s.mockerMtx.Unlock() - if s.mockerStop == nil { - http.Error(w, "stop channel not initialized", http.StatusInternalServerError) - return - } - close(s.mockerStop) - s.mockerStop = nil - - w.WriteHeader(http.StatusOK) -} - -// GetMockers returns a list of available mockers -func (s *Server) GetMockers(w http.ResponseWriter, req *http.Request) { - list := GetMockerList() - s.JSON(w, http.StatusOK, list) -} - -// ResetNetwork resets all properties of a network to its initial (empty) state -func (s *Server) ResetNetwork(w http.ResponseWriter, req *http.Request) { - s.network.Reset() - - w.WriteHeader(http.StatusOK) -} - -// StreamNetworkEvents streams network events as a server-sent-events stream -func (s *Server) StreamNetworkEvents(w http.ResponseWriter, req *http.Request) { - events := make(chan *Event) - sub := s.network.events.Subscribe(events) - defer sub.Unsubscribe() - - // write writes the given event and data to the stream like: - // - // event: - // data: - // - write := func(event, data string) { - fmt.Fprintf(w, "event: %s\n", event) - fmt.Fprintf(w, "data: %s\n\n", data) - if fw, ok := w.(http.Flusher); ok { - fw.Flush() - } - } - writeEvent := func(event *Event) error { - data, err := json.Marshal(event) - if err != nil { - return err - } - write("network", string(data)) - return nil - } - writeErr := func(err error) { - write("error", err.Error()) - } - - // check if filtering has been requested - var filters MsgFilters - if filterParam := req.URL.Query().Get("filter"); filterParam != "" { - var err error - filters, err = NewMsgFilters(filterParam) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - } - - w.Header().Set("Content-Type", "text/event-stream; charset=utf-8") - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "\n\n") - if fw, ok := w.(http.Flusher); ok { - fw.Flush() - } - - // optionally send the existing nodes and connections - if req.URL.Query().Get("current") == "true" { - snap, err := s.network.Snapshot() - if err != nil { - writeErr(err) - return - } - for _, node := range snap.Nodes { - event := NewEvent(&node.Node) - if err := writeEvent(event); err != nil { - writeErr(err) - return - } - } - for _, conn := range snap.Conns { - conn := conn - event := NewEvent(&conn) - if err := writeEvent(event); err != nil { - writeErr(err) - return - } - } - } - - clientGone := req.Context().Done() - for { - select { - case event := <-events: - // only send message events which match the filters - if event.Msg != nil && !filters.Match(event.Msg) { - continue - } - if err := writeEvent(event); err != nil { - writeErr(err) - return - } - case <-clientGone: - return - } - } -} - -// NewMsgFilters constructs a collection of message filters from a URL query -// parameter. -// -// The parameter is expected to be a dash-separated list of individual filters, -// each having the format ':', where is the name of a -// protocol and is a comma-separated list of message codes. -// -// A message code of '*' or '-1' is considered a wildcard and matches any code. -func NewMsgFilters(filterParam string) (MsgFilters, error) { - filters := make(MsgFilters) - for _, filter := range strings.Split(filterParam, "-") { - proto, codes, found := strings.Cut(filter, ":") - if !found || proto == "" || codes == "" { - return nil, fmt.Errorf("invalid message filter: %s", filter) - } - - for _, code := range strings.Split(codes, ",") { - if code == "*" || code == "-1" { - filters[MsgFilter{Proto: proto, Code: -1}] = struct{}{} - continue - } - n, err := strconv.ParseUint(code, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid message code: %s", code) - } - filters[MsgFilter{Proto: proto, Code: int64(n)}] = struct{}{} - } - } - return filters, nil -} - -// MsgFilters is a collection of filters which are used to filter message -// events -type MsgFilters map[MsgFilter]struct{} - -// Match checks if the given message matches any of the filters -func (m MsgFilters) Match(msg *Msg) bool { - // check if there is a wildcard filter for the message's protocol - if _, ok := m[MsgFilter{Proto: msg.Protocol, Code: -1}]; ok { - return true - } - - // check if there is a filter for the message's protocol and code - if _, ok := m[MsgFilter{Proto: msg.Protocol, Code: int64(msg.Code)}]; ok { - return true - } - - return false -} - -// MsgFilter is used to filter message events based on protocol and message -// code -type MsgFilter struct { - // Proto is matched against a message's protocol - Proto string - - // Code is matched against a message's code, with -1 matching all codes - Code int64 -} - -// CreateSnapshot creates a network snapshot -func (s *Server) CreateSnapshot(w http.ResponseWriter, req *http.Request) { - snap, err := s.network.Snapshot() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, snap) -} - -// LoadSnapshot loads a snapshot into the network -func (s *Server) LoadSnapshot(w http.ResponseWriter, req *http.Request) { - snap := &Snapshot{} - if err := json.NewDecoder(req.Body).Decode(snap); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - if err := s.network.Load(snap); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, s.network) -} - -// CreateNode creates a node in the network using the given configuration -func (s *Server) CreateNode(w http.ResponseWriter, req *http.Request) { - config := &adapters.NodeConfig{} - - err := json.NewDecoder(req.Body).Decode(config) - if err != nil && !errors.Is(err, io.EOF) { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - node, err := s.network.NewNodeWithConfig(config) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusCreated, node.NodeInfo()) -} - -// GetNodes returns all nodes which exist in the network -func (s *Server) GetNodes(w http.ResponseWriter, req *http.Request) { - nodes := s.network.GetNodes() - - infos := make([]*p2p.NodeInfo, len(nodes)) - for i, node := range nodes { - infos[i] = node.NodeInfo() - } - - s.JSON(w, http.StatusOK, infos) -} - -// GetNode returns details of a node -func (s *Server) GetNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// StartNode starts a node -func (s *Server) StartNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - - if err := s.network.Start(node.ID()); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// StopNode stops a node -func (s *Server) StopNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - - if err := s.network.Stop(node.ID()); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// ConnectNode connects a node to a peer node -func (s *Server) ConnectNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - peer := req.Context().Value("peer").(*Node) - - if err := s.network.Connect(node.ID(), peer.ID()); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// DisconnectNode disconnects a node from a peer node -func (s *Server) DisconnectNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - peer := req.Context().Value("peer").(*Node) - - if err := s.network.Disconnect(node.ID(), peer.ID()); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// Options responds to the OPTIONS HTTP method by returning a 200 OK response -// with the "Access-Control-Allow-Headers" header set to "Content-Type" -func (s *Server) Options(w http.ResponseWriter, req *http.Request) { - w.Header().Set("Access-Control-Allow-Headers", "Content-Type") - w.WriteHeader(http.StatusOK) -} - -var wsUpgrade = websocket.Upgrader{ - CheckOrigin: func(*http.Request) bool { return true }, -} - -// NodeRPC forwards RPC requests to a node in the network via a WebSocket -// connection -func (s *Server) NodeRPC(w http.ResponseWriter, req *http.Request) { - conn, err := wsUpgrade.Upgrade(w, req, nil) - if err != nil { - return - } - defer conn.Close() - node := req.Context().Value("node").(*Node) - node.ServeRPC(conn) -} - -// ServeHTTP implements the http.Handler interface by delegating to the -// underlying httprouter.Router -func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { - s.router.ServeHTTP(w, req) -} - -// GET registers a handler for GET requests to a particular path -func (s *Server) GET(path string, handle http.HandlerFunc) { - s.router.GET(path, s.wrapHandler(handle)) -} - -// POST registers a handler for POST requests to a particular path -func (s *Server) POST(path string, handle http.HandlerFunc) { - s.router.POST(path, s.wrapHandler(handle)) -} - -// DELETE registers a handler for DELETE requests to a particular path -func (s *Server) DELETE(path string, handle http.HandlerFunc) { - s.router.DELETE(path, s.wrapHandler(handle)) -} - -// OPTIONS registers a handler for OPTIONS requests to a particular path -func (s *Server) OPTIONS(path string, handle http.HandlerFunc) { - s.router.OPTIONS("/*path", s.wrapHandler(handle)) -} - -// JSON sends "data" as a JSON HTTP response -func (s *Server) JSON(w http.ResponseWriter, status int, data interface{}) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(status) - json.NewEncoder(w).Encode(data) -} - -// wrapHandler returns an httprouter.Handle which wraps an http.HandlerFunc by -// populating request.Context with any objects from the URL params -func (s *Server) wrapHandler(handler http.HandlerFunc) httprouter.Handle { - return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) { - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") - - ctx := req.Context() - - if id := params.ByName("nodeid"); id != "" { - var nodeID enode.ID - var node *Node - if nodeID.UnmarshalText([]byte(id)) == nil { - node = s.network.GetNode(nodeID) - } else { - node = s.network.GetNodeByName(id) - } - if node == nil { - http.NotFound(w, req) - return - } - ctx = context.WithValue(ctx, "node", node) - } - - if id := params.ByName("peerid"); id != "" { - var peerID enode.ID - var peer *Node - if peerID.UnmarshalText([]byte(id)) == nil { - peer = s.network.GetNode(peerID) - } else { - peer = s.network.GetNodeByName(id) - } - if peer == nil { - http.NotFound(w, req) - return - } - ctx = context.WithValue(ctx, "peer", peer) - } - - handler(w, req.WithContext(ctx)) - } -} diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go deleted file mode 100644 index cd03e600f35c..000000000000 --- a/p2p/simulations/http_test.go +++ /dev/null @@ -1,869 +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 simulations - -import ( - "context" - "flag" - "fmt" - "log/slog" - "math/rand" - "net/http/httptest" - "os" - "reflect" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/event" - "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/mattn/go-colorable" -) - -func TestMain(m *testing.M) { - loglevel := flag.Int("loglevel", 2, "verbosity of logs") - - flag.Parse() - log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(colorable.NewColorableStderr(), slog.Level(*loglevel), true))) - os.Exit(m.Run()) -} - -// testService implements the node.Service interface and provides protocols -// and APIs which are useful for testing nodes in a simulation network -type testService struct { - id enode.ID - - // peerCount is incremented once a peer handshake has been performed - peerCount int64 - - peers map[enode.ID]*testPeer - peersMtx sync.Mutex - - // state stores []byte which is used to test creating and loading - // snapshots - state atomic.Value -} - -func newTestService(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - svc := &testService{ - id: ctx.Config.ID, - peers: make(map[enode.ID]*testPeer), - } - svc.state.Store(ctx.Snapshot) - - stack.RegisterProtocols(svc.Protocols()) - stack.RegisterAPIs(svc.APIs()) - return svc, nil -} - -type testPeer struct { - testReady chan struct{} - dumReady chan struct{} -} - -func (t *testService) peer(id enode.ID) *testPeer { - t.peersMtx.Lock() - defer t.peersMtx.Unlock() - if peer, ok := t.peers[id]; ok { - return peer - } - peer := &testPeer{ - testReady: make(chan struct{}), - dumReady: make(chan struct{}), - } - t.peers[id] = peer - return peer -} - -func (t *testService) Protocols() []p2p.Protocol { - return []p2p.Protocol{ - { - Name: "test", - Version: 1, - Length: 3, - Run: t.RunTest, - }, - { - Name: "dum", - Version: 1, - Length: 1, - Run: t.RunDum, - }, - { - Name: "prb", - Version: 1, - Length: 1, - Run: t.RunPrb, - }, - } -} - -func (t *testService) APIs() []rpc.API { - return []rpc.API{{ - Namespace: "test", - Version: "1.0", - Service: &TestAPI{ - state: &t.state, - peerCount: &t.peerCount, - }, - }} -} - -func (t *testService) Start() error { - return nil -} - -func (t *testService) Stop() error { - return nil -} - -// handshake performs a peer handshake by sending and expecting an empty -// message with the given code -func (t *testService) handshake(rw p2p.MsgReadWriter, code uint64) error { - errc := make(chan error, 2) - go func() { errc <- p2p.SendItems(rw, code) }() - go func() { errc <- p2p.ExpectMsg(rw, code, struct{}{}) }() - for i := 0; i < 2; i++ { - if err := <-errc; err != nil { - return err - } - } - return nil -} - -func (t *testService) RunTest(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := t.peer(p.ID()) - - // perform three handshakes with three different message codes, - // used to test message sending and filtering - if err := t.handshake(rw, 2); err != nil { - return err - } - if err := t.handshake(rw, 1); err != nil { - return err - } - if err := t.handshake(rw, 0); err != nil { - return err - } - - // close the testReady channel so that other protocols can run - close(peer.testReady) - - // track the peer - atomic.AddInt64(&t.peerCount, 1) - defer atomic.AddInt64(&t.peerCount, -1) - - // block until the peer is dropped - for { - _, err := rw.ReadMsg() - if err != nil { - return err - } - } -} - -func (t *testService) RunDum(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := t.peer(p.ID()) - - // wait for the test protocol to perform its handshake - <-peer.testReady - - // perform a handshake - if err := t.handshake(rw, 0); err != nil { - return err - } - - // close the dumReady channel so that other protocols can run - close(peer.dumReady) - - // block until the peer is dropped - for { - _, err := rw.ReadMsg() - if err != nil { - return err - } - } -} -func (t *testService) RunPrb(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := t.peer(p.ID()) - - // wait for the dum protocol to perform its handshake - <-peer.dumReady - - // perform a handshake - if err := t.handshake(rw, 0); err != nil { - return err - } - - // block until the peer is dropped - for { - _, err := rw.ReadMsg() - if err != nil { - return err - } - } -} - -func (t *testService) Snapshot() ([]byte, error) { - return t.state.Load().([]byte), nil -} - -// TestAPI provides a test API to: -// * get the peer count -// * get and set an arbitrary state byte slice -// * get and increment a counter -// * subscribe to counter increment events -type TestAPI struct { - state *atomic.Value - peerCount *int64 - counter int64 - feed event.Feed -} - -func (t *TestAPI) PeerCount() int64 { - return atomic.LoadInt64(t.peerCount) -} - -func (t *TestAPI) Get() int64 { - return atomic.LoadInt64(&t.counter) -} - -func (t *TestAPI) Add(delta int64) { - atomic.AddInt64(&t.counter, delta) - t.feed.Send(delta) -} - -func (t *TestAPI) GetState() []byte { - return t.state.Load().([]byte) -} - -func (t *TestAPI) SetState(state []byte) { - t.state.Store(state) -} - -func (t *TestAPI) Events(ctx context.Context) (*rpc.Subscription, error) { - notifier, supported := rpc.NotifierFromContext(ctx) - if !supported { - return nil, rpc.ErrNotificationsUnsupported - } - - rpcSub := notifier.CreateSubscription() - - go func() { - events := make(chan int64) - sub := t.feed.Subscribe(events) - defer sub.Unsubscribe() - - for { - select { - case event := <-events: - notifier.Notify(rpcSub.ID, event) - case <-sub.Err(): - return - case <-rpcSub.Err(): - return - } - } - }() - - return rpcSub, nil -} - -var testServices = adapters.LifecycleConstructors{ - "test": newTestService, -} - -func testHTTPServer(t *testing.T) (*Network, *httptest.Server) { - t.Helper() - adapter := adapters.NewSimAdapter(testServices) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - return network, httptest.NewServer(NewServer(network)) -} - -// TestHTTPNetwork tests interacting with a simulation network using the HTTP -// API -func TestHTTPNetwork(t *testing.T) { - // start the server - network, s := testHTTPServer(t) - defer s.Close() - - // subscribe to events so we can check them later - client := NewClient(s.URL) - events := make(chan *Event, 100) - var opts SubscribeOpts - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // check we can retrieve details about the network - gotNetwork, err := client.GetNetwork() - if err != nil { - t.Fatalf("error getting network: %s", err) - } - if gotNetwork.ID != network.ID { - t.Fatalf("expected network to have ID %q, got %q", network.ID, gotNetwork.ID) - } - - // start a simulation network - nodeIDs := startTestNetwork(t, client) - - // check we got all the events - x := &expectEvents{t, events, sub} - x.expect( - x.nodeEvent(nodeIDs[0], false), - x.nodeEvent(nodeIDs[1], false), - x.nodeEvent(nodeIDs[0], true), - x.nodeEvent(nodeIDs[1], true), - x.connEvent(nodeIDs[0], nodeIDs[1], false), - x.connEvent(nodeIDs[0], nodeIDs[1], true), - ) - - // reconnect the stream and check we get the current nodes and conns - events = make(chan *Event, 100) - opts.Current = true - sub, err = client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - x = &expectEvents{t, events, sub} - x.expect( - x.nodeEvent(nodeIDs[0], true), - x.nodeEvent(nodeIDs[1], true), - x.connEvent(nodeIDs[0], nodeIDs[1], true), - ) -} - -func startTestNetwork(t *testing.T, client *Client) []string { - // create two nodes - nodeCount := 2 - nodeIDs := make([]string, nodeCount) - for i := 0; i < nodeCount; i++ { - config := adapters.RandomNodeConfig() - node, err := client.CreateNode(config) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - nodeIDs[i] = node.ID - } - - // check both nodes exist - nodes, err := client.GetNodes() - if err != nil { - t.Fatalf("error getting nodes: %s", err) - } - if len(nodes) != nodeCount { - t.Fatalf("expected %d nodes, got %d", nodeCount, len(nodes)) - } - for i, nodeID := range nodeIDs { - if nodes[i].ID != nodeID { - t.Fatalf("expected node %d to have ID %q, got %q", i, nodeID, nodes[i].ID) - } - node, err := client.GetNode(nodeID) - if err != nil { - t.Fatalf("error getting node %d: %s", i, err) - } - if node.ID != nodeID { - t.Fatalf("expected node %d to have ID %q, got %q", i, nodeID, node.ID) - } - } - - // start both nodes - for _, nodeID := range nodeIDs { - if err := client.StartNode(nodeID); err != nil { - t.Fatalf("error starting node %q: %s", nodeID, err) - } - } - - // connect the nodes - for i := 0; i < nodeCount-1; i++ { - peerId := i + 1 - if i == nodeCount-1 { - peerId = 0 - } - if err := client.ConnectNode(nodeIDs[i], nodeIDs[peerId]); err != nil { - t.Fatalf("error connecting nodes: %s", err) - } - } - - return nodeIDs -} - -type expectEvents struct { - *testing.T - - events chan *Event - sub event.Subscription -} - -func (t *expectEvents) nodeEvent(id string, up bool) *Event { - config := &adapters.NodeConfig{ID: enode.HexID(id)} - return &Event{Type: EventTypeNode, Node: newNode(nil, config, up)} -} - -func (t *expectEvents) connEvent(one, other string, up bool) *Event { - return &Event{ - Type: EventTypeConn, - Conn: &Conn{ - One: enode.HexID(one), - Other: enode.HexID(other), - Up: up, - }, - } -} - -func (t *expectEvents) expectMsgs(expected map[MsgFilter]int) { - actual := make(map[MsgFilter]int) - timeout := time.After(10 * time.Second) -loop: - for { - select { - case event := <-t.events: - t.Logf("received %s event: %v", event.Type, event) - - if event.Type != EventTypeMsg || event.Msg.Received { - continue loop - } - if event.Msg == nil { - t.Fatal("expected event.Msg to be set") - } - filter := MsgFilter{ - Proto: event.Msg.Protocol, - Code: int64(event.Msg.Code), - } - actual[filter]++ - if actual[filter] > expected[filter] { - t.Fatalf("received too many msgs for filter: %v", filter) - } - if reflect.DeepEqual(actual, expected) { - return - } - - case err := <-t.sub.Err(): - t.Fatalf("network stream closed unexpectedly: %s", err) - - case <-timeout: - t.Fatal("timed out waiting for expected events") - } - } -} - -func (t *expectEvents) expect(events ...*Event) { - t.Helper() - timeout := time.After(10 * time.Second) - i := 0 - for { - select { - case event := <-t.events: - t.Logf("received %s event: %v", event.Type, event) - - expected := events[i] - if event.Type != expected.Type { - t.Fatalf("expected event %d to have type %q, got %q", i, expected.Type, event.Type) - } - - switch expected.Type { - case EventTypeNode: - if event.Node == nil { - t.Fatal("expected event.Node to be set") - } - if event.Node.ID() != expected.Node.ID() { - t.Fatalf("expected node event %d to have id %q, got %q", i, expected.Node.ID().TerminalString(), event.Node.ID().TerminalString()) - } - if event.Node.Up() != expected.Node.Up() { - t.Fatalf("expected node event %d to have up=%t, got up=%t", i, expected.Node.Up(), event.Node.Up()) - } - - case EventTypeConn: - if event.Conn == nil { - t.Fatal("expected event.Conn to be set") - } - if event.Conn.One != expected.Conn.One { - t.Fatalf("expected conn event %d to have one=%q, got one=%q", i, expected.Conn.One.TerminalString(), event.Conn.One.TerminalString()) - } - if event.Conn.Other != expected.Conn.Other { - t.Fatalf("expected conn event %d to have other=%q, got other=%q", i, expected.Conn.Other.TerminalString(), event.Conn.Other.TerminalString()) - } - if event.Conn.Up != expected.Conn.Up { - t.Fatalf("expected conn event %d to have up=%t, got up=%t", i, expected.Conn.Up, event.Conn.Up) - } - } - - i++ - if i == len(events) { - return - } - - case err := <-t.sub.Err(): - t.Fatalf("network stream closed unexpectedly: %s", err) - - case <-timeout: - t.Fatal("timed out waiting for expected events") - } - } -} - -// TestHTTPNodeRPC tests calling RPC methods on nodes via the HTTP API -func TestHTTPNodeRPC(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - // start a node in the network - client := NewClient(s.URL) - - config := adapters.RandomNodeConfig() - node, err := client.CreateNode(config) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := client.StartNode(node.ID); err != nil { - t.Fatalf("error starting node: %s", err) - } - - // create two RPC clients - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - rpcClient1, err := client.RPCClient(ctx, node.ID) - if err != nil { - t.Fatalf("error getting node RPC client: %s", err) - } - rpcClient2, err := client.RPCClient(ctx, node.ID) - if err != nil { - t.Fatalf("error getting node RPC client: %s", err) - } - - // subscribe to events using client 1 - events := make(chan int64, 1) - sub, err := rpcClient1.Subscribe(ctx, "test", events, "events") - if err != nil { - t.Fatalf("error subscribing to events: %s", err) - } - defer sub.Unsubscribe() - - // call some RPC methods using client 2 - if err := rpcClient2.CallContext(ctx, nil, "test_add", 10); err != nil { - t.Fatalf("error calling RPC method: %s", err) - } - var result int64 - if err := rpcClient2.CallContext(ctx, &result, "test_get"); err != nil { - t.Fatalf("error calling RPC method: %s", err) - } - if result != 10 { - t.Fatalf("expected result to be 10, got %d", result) - } - - // check we got an event from client 1 - select { - case event := <-events: - if event != 10 { - t.Fatalf("expected event to be 10, got %d", event) - } - case <-ctx.Done(): - t.Fatal(ctx.Err()) - } -} - -// TestHTTPSnapshot tests creating and loading network snapshots -func TestHTTPSnapshot(t *testing.T) { - // start the server - network, s := testHTTPServer(t) - defer s.Close() - - var eventsDone = make(chan struct{}, 1) - count := 1 - eventsDoneChan := make(chan *Event) - eventSub := network.Events().Subscribe(eventsDoneChan) - go func() { - defer eventSub.Unsubscribe() - for event := range eventsDoneChan { - if event.Type == EventTypeConn && !event.Control { - count-- - if count == 0 { - eventsDone <- struct{}{} - return - } - } - } - }() - - // create a two-node network - client := NewClient(s.URL) - nodeCount := 2 - nodes := make([]*p2p.NodeInfo, nodeCount) - for i := 0; i < nodeCount; i++ { - config := adapters.RandomNodeConfig() - node, err := client.CreateNode(config) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := client.StartNode(node.ID); err != nil { - t.Fatalf("error starting node: %s", err) - } - nodes[i] = node - } - if err := client.ConnectNode(nodes[0].ID, nodes[1].ID); err != nil { - t.Fatalf("error connecting nodes: %s", err) - } - - // store some state in the test services - states := make([]string, nodeCount) - for i, node := range nodes { - rpc, err := client.RPCClient(context.Background(), node.ID) - if err != nil { - t.Fatalf("error getting RPC client: %s", err) - } - defer rpc.Close() - state := fmt.Sprintf("%x", rand.Int()) - if err := rpc.Call(nil, "test_setState", []byte(state)); err != nil { - t.Fatalf("error setting service state: %s", err) - } - states[i] = state - } - <-eventsDone - // create a snapshot - snap, err := client.CreateSnapshot() - if err != nil { - t.Fatalf("error creating snapshot: %s", err) - } - for i, state := range states { - gotState := snap.Nodes[i].Snapshots["test"] - if string(gotState) != state { - t.Fatalf("expected snapshot state %q, got %q", state, gotState) - } - } - - // create another network - network2, s := testHTTPServer(t) - defer s.Close() - client = NewClient(s.URL) - count = 1 - eventSub = network2.Events().Subscribe(eventsDoneChan) - go func() { - defer eventSub.Unsubscribe() - for event := range eventsDoneChan { - if event.Type == EventTypeConn && !event.Control { - count-- - if count == 0 { - eventsDone <- struct{}{} - return - } - } - } - }() - - // subscribe to events so we can check them later - events := make(chan *Event, 100) - var opts SubscribeOpts - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // load the snapshot - if err := client.LoadSnapshot(snap); err != nil { - t.Fatalf("error loading snapshot: %s", err) - } - <-eventsDone - - // check the nodes and connection exists - net, err := client.GetNetwork() - if err != nil { - t.Fatalf("error getting network: %s", err) - } - if len(net.Nodes) != nodeCount { - t.Fatalf("expected network to have %d nodes, got %d", nodeCount, len(net.Nodes)) - } - for i, node := range nodes { - id := net.Nodes[i].ID().String() - if id != node.ID { - t.Fatalf("expected node %d to have ID %s, got %s", i, node.ID, id) - } - } - if len(net.Conns) != 1 { - t.Fatalf("expected network to have 1 connection, got %d", len(net.Conns)) - } - conn := net.Conns[0] - if conn.One.String() != nodes[0].ID { - t.Fatalf("expected connection to have one=%q, got one=%q", nodes[0].ID, conn.One) - } - if conn.Other.String() != nodes[1].ID { - t.Fatalf("expected connection to have other=%q, got other=%q", nodes[1].ID, conn.Other) - } - if !conn.Up { - t.Fatal("should be up") - } - - // check the node states were restored - for i, node := range nodes { - rpc, err := client.RPCClient(context.Background(), node.ID) - if err != nil { - t.Fatalf("error getting RPC client: %s", err) - } - defer rpc.Close() - var state []byte - if err := rpc.Call(&state, "test_getState"); err != nil { - t.Fatalf("error getting service state: %s", err) - } - if string(state) != states[i] { - t.Fatalf("expected snapshot state %q, got %q", states[i], state) - } - } - - // check we got all the events - x := &expectEvents{t, events, sub} - x.expect( - x.nodeEvent(nodes[0].ID, false), - x.nodeEvent(nodes[0].ID, true), - x.nodeEvent(nodes[1].ID, false), - x.nodeEvent(nodes[1].ID, true), - x.connEvent(nodes[0].ID, nodes[1].ID, false), - x.connEvent(nodes[0].ID, nodes[1].ID, true), - ) -} - -// TestMsgFilterPassMultiple tests streaming message events using a filter -// with multiple protocols -func TestMsgFilterPassMultiple(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - // subscribe to events with a message filter - client := NewClient(s.URL) - events := make(chan *Event, 10) - opts := SubscribeOpts{ - Filter: "prb:0-test:0", - } - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // start a simulation network - startTestNetwork(t, client) - - // check we got the expected events - x := &expectEvents{t, events, sub} - x.expectMsgs(map[MsgFilter]int{ - {"test", 0}: 2, - {"prb", 0}: 2, - }) -} - -// TestMsgFilterPassWildcard tests streaming message events using a filter -// with a code wildcard -func TestMsgFilterPassWildcard(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - // subscribe to events with a message filter - client := NewClient(s.URL) - events := make(chan *Event, 10) - opts := SubscribeOpts{ - Filter: "prb:0,2-test:*", - } - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // start a simulation network - startTestNetwork(t, client) - - // check we got the expected events - x := &expectEvents{t, events, sub} - x.expectMsgs(map[MsgFilter]int{ - {"test", 2}: 2, - {"test", 1}: 2, - {"test", 0}: 2, - {"prb", 0}: 2, - }) -} - -// TestMsgFilterPassSingle tests streaming message events using a filter -// with a single protocol and code -func TestMsgFilterPassSingle(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - // subscribe to events with a message filter - client := NewClient(s.URL) - events := make(chan *Event, 10) - opts := SubscribeOpts{ - Filter: "dum:0", - } - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // start a simulation network - startTestNetwork(t, client) - - // check we got the expected events - x := &expectEvents{t, events, sub} - x.expectMsgs(map[MsgFilter]int{ - {"dum", 0}: 2, - }) -} - -// TestMsgFilterFailBadParams tests streaming message events using an invalid -// filter -func TestMsgFilterFailBadParams(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - client := NewClient(s.URL) - events := make(chan *Event, 10) - opts := SubscribeOpts{ - Filter: "foo:", - } - _, err := client.SubscribeNetwork(events, opts) - if err == nil { - t.Fatalf("expected event subscription to fail but succeeded!") - } - - opts.Filter = "bzz:aa" - _, err = client.SubscribeNetwork(events, opts) - if err == nil { - t.Fatalf("expected event subscription to fail but succeeded!") - } - - opts.Filter = "invalid" - _, err = client.SubscribeNetwork(events, opts) - if err == nil { - t.Fatalf("expected event subscription to fail but succeeded!") - } -} diff --git a/p2p/simulations/mocker.go b/p2p/simulations/mocker.go deleted file mode 100644 index 8763df67ef39..000000000000 --- a/p2p/simulations/mocker.go +++ /dev/null @@ -1,197 +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 simulations simulates p2p networks. -// A mocker simulates starting and stopping real nodes in a network. -package simulations - -import ( - "fmt" - "math/rand" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -// a map of mocker names to its function -var mockerList = map[string]func(net *Network, quit chan struct{}, nodeCount int){ - "startStop": startStop, - "probabilistic": probabilistic, - "boot": boot, -} - -// LookupMocker looks a mocker by its name, returns the mockerFn -func LookupMocker(mockerType string) func(net *Network, quit chan struct{}, nodeCount int) { - return mockerList[mockerType] -} - -// GetMockerList returns a list of mockers (keys of the map) -// Useful for frontend to build available mocker selection -func GetMockerList() []string { - list := make([]string, 0, len(mockerList)) - for k := range mockerList { - list = append(list, k) - } - return list -} - -// The boot mockerFn only connects the node in a ring and doesn't do anything else -func boot(net *Network, quit chan struct{}, nodeCount int) { - _, err := connectNodesInRing(net, nodeCount) - if err != nil { - panic("Could not startup node network for mocker") - } -} - -// The startStop mockerFn stops and starts nodes in a defined period (ticker) -func startStop(net *Network, quit chan struct{}, nodeCount int) { - nodes, err := connectNodesInRing(net, nodeCount) - if err != nil { - panic("Could not startup node network for mocker") - } - var ( - tick = time.NewTicker(10 * time.Second) - timer = time.NewTimer(3 * time.Second) - ) - defer tick.Stop() - defer timer.Stop() - - for { - select { - case <-quit: - log.Info("Terminating simulation loop") - return - case <-tick.C: - id := nodes[rand.Intn(len(nodes))] - log.Info("stopping node", "id", id) - if err := net.Stop(id); err != nil { - log.Error("error stopping node", "id", id, "err", err) - return - } - - timer.Reset(3 * time.Second) - select { - case <-quit: - log.Info("Terminating simulation loop") - return - case <-timer.C: - } - - log.Debug("starting node", "id", id) - if err := net.Start(id); err != nil { - log.Error("error starting node", "id", id, "err", err) - return - } - } - } -} - -// The probabilistic mocker func has a more probabilistic pattern -// (the implementation could probably be improved): -// nodes are connected in a ring, then a varying number of random nodes is selected, -// mocker then stops and starts them in random intervals, and continues the loop -func probabilistic(net *Network, quit chan struct{}, nodeCount int) { - nodes, err := connectNodesInRing(net, nodeCount) - if err != nil { - select { - case <-quit: - //error may be due to abortion of mocking; so the quit channel is closed - return - default: - panic("Could not startup node network for mocker") - } - } - for { - select { - case <-quit: - log.Info("Terminating simulation loop") - return - default: - } - var lowid, highid int - var wg sync.WaitGroup - randWait := time.Duration(rand.Intn(5000)+1000) * time.Millisecond - rand1 := rand.Intn(nodeCount - 1) - rand2 := rand.Intn(nodeCount - 1) - if rand1 <= rand2 { - lowid = rand1 - highid = rand2 - } else if rand1 > rand2 { - highid = rand1 - lowid = rand2 - } - var steps = highid - lowid - wg.Add(steps) - for i := lowid; i < highid; i++ { - select { - case <-quit: - log.Info("Terminating simulation loop") - return - case <-time.After(randWait): - } - log.Debug(fmt.Sprintf("node %v shutting down", nodes[i])) - err := net.Stop(nodes[i]) - if err != nil { - log.Error("Error stopping node", "node", nodes[i]) - wg.Done() - continue - } - go func(id enode.ID) { - time.Sleep(randWait) - err := net.Start(id) - if err != nil { - log.Error("Error starting node", "node", id) - } - wg.Done() - }(nodes[i]) - } - wg.Wait() - } -} - -// connect nodeCount number of nodes in a ring -func connectNodesInRing(net *Network, nodeCount int) ([]enode.ID, error) { - ids := make([]enode.ID, nodeCount) - for i := 0; i < nodeCount; i++ { - conf := adapters.RandomNodeConfig() - node, err := net.NewNodeWithConfig(conf) - if err != nil { - log.Error("Error creating a node!", "err", err) - return nil, err - } - ids[i] = node.ID() - } - - for _, id := range ids { - if err := net.Start(id); err != nil { - log.Error("Error starting a node!", "err", err) - return nil, err - } - log.Debug(fmt.Sprintf("node %v starting up", id)) - } - for i, id := range ids { - peerID := ids[(i+1)%len(ids)] - if err := net.Connect(id, peerID); err != nil { - log.Error("Error connecting a node to a peer!", "err", err) - return nil, err - } - } - - return ids, nil -} diff --git a/p2p/simulations/mocker_test.go b/p2p/simulations/mocker_test.go deleted file mode 100644 index 0112ee5cfd6e..000000000000 --- a/p2p/simulations/mocker_test.go +++ /dev/null @@ -1,174 +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 simulations simulates p2p networks. -// A mocker simulates starting and stopping real nodes in a network. -package simulations - -import ( - "encoding/json" - "net/http" - "net/url" - "strconv" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -func TestMocker(t *testing.T) { - //start the simulation HTTP server - _, s := testHTTPServer(t) - defer s.Close() - - //create a client - client := NewClient(s.URL) - - //start the network - err := client.StartNetwork() - if err != nil { - t.Fatalf("Could not start test network: %s", err) - } - //stop the network to terminate - defer func() { - err = client.StopNetwork() - if err != nil { - t.Fatalf("Could not stop test network: %s", err) - } - }() - - //get the list of available mocker types - resp, err := http.Get(s.URL + "/mocker") - if err != nil { - t.Fatalf("Could not get mocker list: %s", err) - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - t.Fatalf("Invalid Status Code received, expected 200, got %d", resp.StatusCode) - } - - //check the list is at least 1 in size - var mockerlist []string - err = json.NewDecoder(resp.Body).Decode(&mockerlist) - if err != nil { - t.Fatalf("Error decoding JSON mockerlist: %s", err) - } - - if len(mockerlist) < 1 { - t.Fatalf("No mockers available") - } - - nodeCount := 10 - var wg sync.WaitGroup - - events := make(chan *Event, 10) - var opts SubscribeOpts - sub, err := client.SubscribeNetwork(events, opts) - defer sub.Unsubscribe() - - // wait until all nodes are started and connected - // store every node up event in a map (value is irrelevant, mimic Set datatype) - nodemap := make(map[enode.ID]bool) - nodesComplete := false - connCount := 0 - wg.Add(1) - go func() { - defer wg.Done() - - for connCount < (nodeCount-1)*2 { - select { - case event := <-events: - if isNodeUp(event) { - //add the correspondent node ID to the map - nodemap[event.Node.Config.ID] = true - //this means all nodes got a nodeUp event, so we can continue the test - if len(nodemap) == nodeCount { - nodesComplete = true - } - } else if event.Conn != nil && nodesComplete { - connCount += 1 - } - case <-time.After(30 * time.Second): - t.Errorf("Timeout waiting for nodes being started up!") - return - } - } - }() - - //take the last element of the mockerlist as the default mocker-type to ensure one is enabled - mockertype := mockerlist[len(mockerlist)-1] - //still, use hardcoded "probabilistic" one if available ;) - for _, m := range mockerlist { - if m == "probabilistic" { - mockertype = m - break - } - } - //start the mocker with nodeCount number of nodes - resp, err = http.PostForm(s.URL+"/mocker/start", url.Values{"mocker-type": {mockertype}, "node-count": {strconv.Itoa(nodeCount)}}) - if err != nil { - t.Fatalf("Could not start mocker: %s", err) - } - resp.Body.Close() - if resp.StatusCode != 200 { - t.Fatalf("Invalid Status Code received for starting mocker, expected 200, got %d", resp.StatusCode) - } - - wg.Wait() - - //check there are nodeCount number of nodes in the network - nodesInfo, err := client.GetNodes() - if err != nil { - t.Fatalf("Could not get nodes list: %s", err) - } - - if len(nodesInfo) != nodeCount { - t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodesInfo)) - } - - //stop the mocker - resp, err = http.Post(s.URL+"/mocker/stop", "", nil) - if err != nil { - t.Fatalf("Could not stop mocker: %s", err) - } - resp.Body.Close() - if resp.StatusCode != 200 { - t.Fatalf("Invalid Status Code received for stopping mocker, expected 200, got %d", resp.StatusCode) - } - - //reset the network - resp, err = http.Post(s.URL+"/reset", "", nil) - if err != nil { - t.Fatalf("Could not reset network: %s", err) - } - resp.Body.Close() - - //now the number of nodes in the network should be zero - nodesInfo, err = client.GetNodes() - if err != nil { - t.Fatalf("Could not get nodes list: %s", err) - } - - if len(nodesInfo) != 0 { - t.Fatalf("Expected empty list of nodes, got: %d", len(nodesInfo)) - } -} - -func isNodeUp(event *Event) bool { - return event.Node != nil && event.Node.Up() -} diff --git a/p2p/simulations/network.go b/p2p/simulations/network.go deleted file mode 100644 index 2eb8333cd600..000000000000 --- a/p2p/simulations/network.go +++ /dev/null @@ -1,1093 +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 simulations - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "math/rand" - "sync" - "time" - - "github.com/ethereum/go-ethereum/event" - "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/simulations/adapters" -) - -var DialBanTimeout = 200 * time.Millisecond - -// NetworkConfig defines configuration options for starting a Network -type NetworkConfig struct { - ID string `json:"id"` - DefaultService string `json:"default_service,omitempty"` -} - -// Network models a p2p simulation network which consists of a collection of -// simulated nodes and the connections which exist between them. -// -// The Network has a single NodeAdapter which is responsible for actually -// starting nodes and connecting them together. -// -// The Network emits events when nodes are started and stopped, when they are -// connected and disconnected, and also when messages are sent between nodes. -type Network struct { - NetworkConfig - - Nodes []*Node `json:"nodes"` - nodeMap map[enode.ID]int - - // Maps a node property string to node indexes of all nodes that hold this property - propertyMap map[string][]int - - Conns []*Conn `json:"conns"` - connMap map[string]int - - nodeAdapter adapters.NodeAdapter - events event.Feed - lock sync.RWMutex - quitc chan struct{} -} - -// NewNetwork returns a Network which uses the given NodeAdapter and NetworkConfig -func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network { - return &Network{ - NetworkConfig: *conf, - nodeAdapter: nodeAdapter, - nodeMap: make(map[enode.ID]int), - propertyMap: make(map[string][]int), - connMap: make(map[string]int), - quitc: make(chan struct{}), - } -} - -// Events returns the output event feed of the Network. -func (net *Network) Events() *event.Feed { - return &net.events -} - -// NewNodeWithConfig adds a new node to the network with the given config, -// returning an error if a node with the same ID or name already exists -func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) { - net.lock.Lock() - defer net.lock.Unlock() - - if conf.Reachable == nil { - conf.Reachable = func(otherID enode.ID) bool { - _, err := net.InitConn(conf.ID, otherID) - if err != nil && bytes.Compare(conf.ID.Bytes(), otherID.Bytes()) < 0 { - return false - } - return true - } - } - - // check the node doesn't already exist - if node := net.getNode(conf.ID); node != nil { - return nil, fmt.Errorf("node with ID %q already exists", conf.ID) - } - if node := net.getNodeByName(conf.Name); node != nil { - return nil, fmt.Errorf("node with name %q already exists", conf.Name) - } - - // if no services are configured, use the default service - if len(conf.Lifecycles) == 0 { - conf.Lifecycles = []string{net.DefaultService} - } - - // use the NodeAdapter to create the node - adapterNode, err := net.nodeAdapter.NewNode(conf) - if err != nil { - return nil, err - } - node := newNode(adapterNode, conf, false) - log.Trace("Node created", "id", conf.ID) - - nodeIndex := len(net.Nodes) - net.nodeMap[conf.ID] = nodeIndex - net.Nodes = append(net.Nodes, node) - - // Register any node properties with the network-level propertyMap - for _, property := range conf.Properties { - net.propertyMap[property] = append(net.propertyMap[property], nodeIndex) - } - - // emit a "control" event - net.events.Send(ControlEvent(node)) - - return node, nil -} - -// Config returns the network configuration -func (net *Network) Config() *NetworkConfig { - return &net.NetworkConfig -} - -// StartAll starts all nodes in the network -func (net *Network) StartAll() error { - for _, node := range net.Nodes { - if node.Up() { - continue - } - if err := net.Start(node.ID()); err != nil { - return err - } - } - return nil -} - -// StopAll stops all nodes in the network -func (net *Network) StopAll() error { - for _, node := range net.Nodes { - if !node.Up() { - continue - } - if err := net.Stop(node.ID()); err != nil { - return err - } - } - return nil -} - -// Start starts the node with the given ID -func (net *Network) Start(id enode.ID) error { - return net.startWithSnapshots(id, nil) -} - -// startWithSnapshots starts the node with the given ID using the give -// snapshots -func (net *Network) startWithSnapshots(id enode.ID, snapshots map[string][]byte) error { - net.lock.Lock() - defer net.lock.Unlock() - - node := net.getNode(id) - if node == nil { - return fmt.Errorf("node %v does not exist", id) - } - if node.Up() { - return fmt.Errorf("node %v already up", id) - } - log.Trace("Starting node", "id", id, "adapter", net.nodeAdapter.Name()) - if err := node.Start(snapshots); err != nil { - log.Warn("Node startup failed", "id", id, "err", err) - return err - } - node.SetUp(true) - log.Info("Started node", "id", id) - ev := NewEvent(node) - net.events.Send(ev) - - // subscribe to peer events - client, err := node.Client() - if err != nil { - return fmt.Errorf("error getting rpc client for node %v: %s", id, 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 net.watchPeerEvents(id, events, sub) - return nil -} - -// watchPeerEvents reads peer events from the given channel and emits -// corresponding network events -func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub event.Subscription) { - defer func() { - sub.Unsubscribe() - - // assume the node is now down - net.lock.Lock() - defer net.lock.Unlock() - - node := net.getNode(id) - if node == nil { - return - } - node.SetUp(false) - ev := NewEvent(node) - net.events.Send(ev) - }() - for { - select { - case event, ok := <-events: - if !ok { - return - } - peer := event.Peer - switch event.Type { - case p2p.PeerEventTypeAdd: - net.DidConnect(id, peer) - - case p2p.PeerEventTypeDrop: - net.DidDisconnect(id, peer) - - case p2p.PeerEventTypeMsgSend: - net.DidSend(id, peer, event.Protocol, *event.MsgCode) - - case p2p.PeerEventTypeMsgRecv: - net.DidReceive(peer, id, event.Protocol, *event.MsgCode) - } - - case err := <-sub.Err(): - if err != nil { - log.Error("Error in peer event subscription", "id", id, "err", err) - } - return - } - } -} - -// Stop stops the node with the given ID -func (net *Network) Stop(id enode.ID) error { - // IMPORTANT: node.Stop() must NOT be called under net.lock as - // node.Reachable() closure has a reference to the network and - // calls net.InitConn() what also locks the network. => DEADLOCK - // That holds until the following ticket is not resolved: - - var err error - - node, err := func() (*Node, error) { - net.lock.Lock() - defer net.lock.Unlock() - - node := net.getNode(id) - if node == nil { - return nil, fmt.Errorf("node %v does not exist", id) - } - if !node.Up() { - return nil, fmt.Errorf("node %v already down", id) - } - node.SetUp(false) - return node, nil - }() - if err != nil { - return err - } - - err = node.Stop() // must be called without net.lock - - net.lock.Lock() - defer net.lock.Unlock() - - if err != nil { - node.SetUp(true) - return err - } - log.Info("Stopped node", "id", id, "err", err) - ev := ControlEvent(node) - net.events.Send(ev) - return nil -} - -// Connect connects two nodes together by calling the "admin_addPeer" RPC -// method on the "one" node so that it connects to the "other" node -func (net *Network) Connect(oneID, otherID enode.ID) error { - net.lock.Lock() - defer net.lock.Unlock() - return net.connect(oneID, otherID) -} - -func (net *Network) connect(oneID, otherID enode.ID) error { - log.Debug("Connecting nodes with addPeer", "id", oneID, "other", otherID) - conn, err := net.initConn(oneID, otherID) - if err != nil { - return err - } - client, err := conn.one.Client() - if err != nil { - return err - } - net.events.Send(ControlEvent(conn)) - return client.Call(nil, "admin_addPeer", string(conn.other.Addr())) -} - -// Disconnect disconnects two nodes by calling the "admin_removePeer" RPC -// method on the "one" node so that it disconnects from the "other" node -func (net *Network) Disconnect(oneID, otherID enode.ID) error { - conn := net.GetConn(oneID, otherID) - if conn == nil { - return fmt.Errorf("connection between %v and %v does not exist", oneID, otherID) - } - if !conn.Up { - return fmt.Errorf("%v and %v already disconnected", oneID, otherID) - } - client, err := conn.one.Client() - if err != nil { - return err - } - net.events.Send(ControlEvent(conn)) - return client.Call(nil, "admin_removePeer", string(conn.other.Addr())) -} - -// DidConnect tracks the fact that the "one" node connected to the "other" node -func (net *Network) DidConnect(one, other enode.ID) error { - net.lock.Lock() - defer net.lock.Unlock() - conn, err := net.getOrCreateConn(one, other) - if err != nil { - return fmt.Errorf("connection between %v and %v does not exist", one, other) - } - if conn.Up { - return fmt.Errorf("%v and %v already connected", one, other) - } - conn.Up = true - net.events.Send(NewEvent(conn)) - return nil -} - -// DidDisconnect tracks the fact that the "one" node disconnected from the -// "other" node -func (net *Network) DidDisconnect(one, other enode.ID) error { - net.lock.Lock() - defer net.lock.Unlock() - conn := net.getConn(one, other) - if conn == nil { - return fmt.Errorf("connection between %v and %v does not exist", one, other) - } - if !conn.Up { - return fmt.Errorf("%v and %v already disconnected", one, other) - } - conn.Up = false - conn.initiated = time.Now().Add(-DialBanTimeout) - net.events.Send(NewEvent(conn)) - return nil -} - -// DidSend tracks the fact that "sender" sent a message to "receiver" -func (net *Network) DidSend(sender, receiver enode.ID, proto string, code uint64) error { - msg := &Msg{ - One: sender, - Other: receiver, - Protocol: proto, - Code: code, - Received: false, - } - net.events.Send(NewEvent(msg)) - return nil -} - -// DidReceive tracks the fact that "receiver" received a message from "sender" -func (net *Network) DidReceive(sender, receiver enode.ID, proto string, code uint64) error { - msg := &Msg{ - One: sender, - Other: receiver, - Protocol: proto, - Code: code, - Received: true, - } - net.events.Send(NewEvent(msg)) - return nil -} - -// GetNode gets the node with the given ID, returning nil if the node does not -// exist -func (net *Network) GetNode(id enode.ID) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getNode(id) -} - -func (net *Network) getNode(id enode.ID) *Node { - i, found := net.nodeMap[id] - if !found { - return nil - } - return net.Nodes[i] -} - -// GetNodeByName gets the node with the given name, returning nil if the node does -// not exist -func (net *Network) GetNodeByName(name string) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getNodeByName(name) -} - -func (net *Network) getNodeByName(name string) *Node { - for _, node := range net.Nodes { - if node.Config.Name == name { - return node - } - } - return nil -} - -// GetNodeIDs returns the IDs of all existing nodes -// Nodes can optionally be excluded by specifying their enode.ID. -func (net *Network) GetNodeIDs(excludeIDs ...enode.ID) []enode.ID { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodeIDs(excludeIDs) -} - -func (net *Network) getNodeIDs(excludeIDs []enode.ID) []enode.ID { - // Get all current nodeIDs - nodeIDs := make([]enode.ID, 0, len(net.nodeMap)) - for id := range net.nodeMap { - nodeIDs = append(nodeIDs, id) - } - - if len(excludeIDs) > 0 { - // Return the difference of nodeIDs and excludeIDs - return filterIDs(nodeIDs, excludeIDs) - } - return nodeIDs -} - -// GetNodes returns the existing nodes. -// Nodes can optionally be excluded by specifying their enode.ID. -func (net *Network) GetNodes(excludeIDs ...enode.ID) []*Node { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodes(excludeIDs) -} - -func (net *Network) getNodes(excludeIDs []enode.ID) []*Node { - if len(excludeIDs) > 0 { - nodeIDs := net.getNodeIDs(excludeIDs) - return net.getNodesByID(nodeIDs) - } - return net.Nodes -} - -// GetNodesByID returns existing nodes with the given enode.IDs. -// If a node doesn't exist with a given enode.ID, it is ignored. -func (net *Network) GetNodesByID(nodeIDs []enode.ID) []*Node { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodesByID(nodeIDs) -} - -func (net *Network) getNodesByID(nodeIDs []enode.ID) []*Node { - nodes := make([]*Node, 0, len(nodeIDs)) - for _, id := range nodeIDs { - node := net.getNode(id) - if node != nil { - nodes = append(nodes, node) - } - } - - return nodes -} - -// GetNodesByProperty returns existing nodes that have the given property string registered in their NodeConfig -func (net *Network) GetNodesByProperty(property string) []*Node { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodesByProperty(property) -} - -func (net *Network) getNodesByProperty(property string) []*Node { - nodes := make([]*Node, 0, len(net.propertyMap[property])) - for _, nodeIndex := range net.propertyMap[property] { - nodes = append(nodes, net.Nodes[nodeIndex]) - } - - return nodes -} - -// GetNodeIDsByProperty returns existing node's enode IDs that have the given property string registered in the NodeConfig -func (net *Network) GetNodeIDsByProperty(property string) []enode.ID { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodeIDsByProperty(property) -} - -func (net *Network) getNodeIDsByProperty(property string) []enode.ID { - nodeIDs := make([]enode.ID, 0, len(net.propertyMap[property])) - for _, nodeIndex := range net.propertyMap[property] { - node := net.Nodes[nodeIndex] - nodeIDs = append(nodeIDs, node.ID()) - } - - return nodeIDs -} - -// GetRandomUpNode returns a random node on the network, which is running. -func (net *Network) GetRandomUpNode(excludeIDs ...enode.ID) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getRandomUpNode(excludeIDs...) -} - -// getRandomUpNode returns a random node on the network, which is running. -func (net *Network) getRandomUpNode(excludeIDs ...enode.ID) *Node { - return net.getRandomNode(net.getUpNodeIDs(), excludeIDs) -} - -func (net *Network) getUpNodeIDs() (ids []enode.ID) { - for _, node := range net.Nodes { - if node.Up() { - ids = append(ids, node.ID()) - } - } - return ids -} - -// GetRandomDownNode returns a random node on the network, which is stopped. -func (net *Network) GetRandomDownNode(excludeIDs ...enode.ID) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getRandomNode(net.getDownNodeIDs(), excludeIDs) -} - -func (net *Network) getDownNodeIDs() (ids []enode.ID) { - for _, node := range net.Nodes { - if !node.Up() { - ids = append(ids, node.ID()) - } - } - return ids -} - -// GetRandomNode returns a random node on the network, regardless of whether it is running or not -func (net *Network) GetRandomNode(excludeIDs ...enode.ID) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getRandomNode(net.getNodeIDs(nil), excludeIDs) // no need to exclude twice -} - -func (net *Network) getRandomNode(ids []enode.ID, excludeIDs []enode.ID) *Node { - filtered := filterIDs(ids, excludeIDs) - - l := len(filtered) - if l == 0 { - return nil - } - return net.getNode(filtered[rand.Intn(l)]) -} - -func filterIDs(ids []enode.ID, excludeIDs []enode.ID) []enode.ID { - exclude := make(map[enode.ID]bool) - for _, id := range excludeIDs { - exclude[id] = true - } - var filtered []enode.ID - for _, id := range ids { - if _, found := exclude[id]; !found { - filtered = append(filtered, id) - } - } - return filtered -} - -// GetConn returns the connection which exists between "one" and "other" -// regardless of which node initiated the connection -func (net *Network) GetConn(oneID, otherID enode.ID) *Conn { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getConn(oneID, otherID) -} - -// GetOrCreateConn is like GetConn but creates the connection if it doesn't -// already exist -func (net *Network) GetOrCreateConn(oneID, otherID enode.ID) (*Conn, error) { - net.lock.Lock() - defer net.lock.Unlock() - return net.getOrCreateConn(oneID, otherID) -} - -func (net *Network) getOrCreateConn(oneID, otherID enode.ID) (*Conn, error) { - if conn := net.getConn(oneID, otherID); conn != nil { - return conn, nil - } - - one := net.getNode(oneID) - if one == nil { - return nil, fmt.Errorf("node %v does not exist", oneID) - } - other := net.getNode(otherID) - if other == nil { - return nil, fmt.Errorf("node %v does not exist", otherID) - } - conn := &Conn{ - One: oneID, - Other: otherID, - one: one, - other: other, - } - label := ConnLabel(oneID, otherID) - net.connMap[label] = len(net.Conns) - net.Conns = append(net.Conns, conn) - return conn, nil -} - -func (net *Network) getConn(oneID, otherID enode.ID) *Conn { - label := ConnLabel(oneID, otherID) - i, found := net.connMap[label] - if !found { - return nil - } - return net.Conns[i] -} - -// InitConn retrieves the connection model for the connection between -// peers 'oneID' and 'otherID', or creates a new one if it does not exist -// the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i) -// it checks if the connection is already up, and if the nodes are running -// NOTE: -// it also checks whether there has been recent attempt to connect the peers -// this is cheating as the simulation is used as an oracle and know about -// remote peers attempt to connect to a node which will then not initiate the connection -func (net *Network) InitConn(oneID, otherID enode.ID) (*Conn, error) { - net.lock.Lock() - defer net.lock.Unlock() - return net.initConn(oneID, otherID) -} - -func (net *Network) initConn(oneID, otherID enode.ID) (*Conn, error) { - if oneID == otherID { - return nil, fmt.Errorf("refusing to connect to self %v", oneID) - } - conn, err := net.getOrCreateConn(oneID, otherID) - if err != nil { - return nil, err - } - if conn.Up { - return nil, fmt.Errorf("%v and %v already connected", oneID, otherID) - } - if time.Since(conn.initiated) < DialBanTimeout { - return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID) - } - - err = conn.nodesUp() - if err != nil { - log.Trace("Nodes not up", "err", err) - return nil, fmt.Errorf("nodes not up: %v", err) - } - log.Debug("Connection initiated", "id", oneID, "other", otherID) - conn.initiated = time.Now() - return conn, nil -} - -// Shutdown stops all nodes in the network and closes the quit channel -func (net *Network) Shutdown() { - for _, node := range net.Nodes { - log.Debug("Stopping node", "id", node.ID()) - if err := node.Stop(); err != nil { - log.Warn("Can't stop node", "id", node.ID(), "err", err) - } - } - close(net.quitc) -} - -// Reset resets all network properties: -// empties the nodes and the connection list -func (net *Network) Reset() { - net.lock.Lock() - defer net.lock.Unlock() - - //re-initialize the maps - net.connMap = make(map[string]int) - net.nodeMap = make(map[enode.ID]int) - net.propertyMap = make(map[string][]int) - - net.Nodes = nil - net.Conns = nil -} - -// Node is a wrapper around adapters.Node which is used to track the status -// of a node in the network -type Node struct { - adapters.Node `json:"-"` - - // Config if the config used to created the node - Config *adapters.NodeConfig `json:"config"` - - // up tracks whether or not the node is running - up bool - upMu *sync.RWMutex -} - -func newNode(an adapters.Node, ac *adapters.NodeConfig, up bool) *Node { - return &Node{Node: an, Config: ac, up: up, upMu: new(sync.RWMutex)} -} - -func (n *Node) copy() *Node { - configCpy := *n.Config - return newNode(n.Node, &configCpy, n.Up()) -} - -// Up returns whether the node is currently up (online) -func (n *Node) Up() bool { - n.upMu.RLock() - defer n.upMu.RUnlock() - return n.up -} - -// SetUp sets the up (online) status of the nodes with the given value -func (n *Node) SetUp(up bool) { - n.upMu.Lock() - defer n.upMu.Unlock() - n.up = up -} - -// ID returns the ID of the node -func (n *Node) ID() enode.ID { - return n.Config.ID -} - -// String returns a log-friendly string -func (n *Node) String() string { - return fmt.Sprintf("Node %v", n.ID().TerminalString()) -} - -// NodeInfo returns information about the node -func (n *Node) NodeInfo() *p2p.NodeInfo { - // avoid a panic if the node is not started yet - if n.Node == nil { - return nil - } - info := n.Node.NodeInfo() - info.Name = n.Config.Name - return info -} - -// MarshalJSON implements the json.Marshaler interface so that the encoded -// JSON includes the NodeInfo -func (n *Node) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Info *p2p.NodeInfo `json:"info,omitempty"` - Config *adapters.NodeConfig `json:"config,omitempty"` - Up bool `json:"up"` - }{ - Info: n.NodeInfo(), - Config: n.Config, - Up: n.Up(), - }) -} - -// UnmarshalJSON implements json.Unmarshaler interface so that we don't lose Node.up -// status. IMPORTANT: The implementation is incomplete; we lose p2p.NodeInfo. -func (n *Node) UnmarshalJSON(raw []byte) error { - // TODO: How should we turn back NodeInfo into n.Node? - // Ticket: https://github.com/ethersphere/go-ethereum/issues/1177 - var node struct { - Config *adapters.NodeConfig `json:"config,omitempty"` - Up bool `json:"up"` - } - if err := json.Unmarshal(raw, &node); err != nil { - return err - } - *n = *newNode(nil, node.Config, node.Up) - return nil -} - -// Conn represents a connection between two nodes in the network -type Conn struct { - // One is the node which initiated the connection - One enode.ID `json:"one"` - - // Other is the node which the connection was made to - Other enode.ID `json:"other"` - - // Up tracks whether or not the connection is active - Up bool `json:"up"` - // Registers when the connection was grabbed to dial - initiated time.Time - - one *Node - other *Node -} - -// nodesUp returns whether both nodes are currently up -func (c *Conn) nodesUp() error { - if !c.one.Up() { - return fmt.Errorf("one %v is not up", c.One) - } - if !c.other.Up() { - return fmt.Errorf("other %v is not up", c.Other) - } - return nil -} - -// String returns a log-friendly string -func (c *Conn) String() string { - return fmt.Sprintf("Conn %v->%v", c.One.TerminalString(), c.Other.TerminalString()) -} - -// Msg represents a p2p message sent between two nodes in the network -type Msg struct { - One enode.ID `json:"one"` - Other enode.ID `json:"other"` - Protocol string `json:"protocol"` - Code uint64 `json:"code"` - Received bool `json:"received"` -} - -// String returns a log-friendly string -func (m *Msg) String() string { - return fmt.Sprintf("Msg(%d) %v->%v", m.Code, m.One.TerminalString(), m.Other.TerminalString()) -} - -// ConnLabel generates a deterministic string which represents a connection -// between two nodes, used to compare if two connections are between the same -// nodes -func ConnLabel(source, target enode.ID) string { - var first, second enode.ID - if bytes.Compare(source.Bytes(), target.Bytes()) > 0 { - first = target - second = source - } else { - first = source - second = target - } - return fmt.Sprintf("%v-%v", first, second) -} - -// Snapshot represents the state of a network at a single point in time and can -// be used to restore the state of a network -type Snapshot struct { - Nodes []NodeSnapshot `json:"nodes,omitempty"` - Conns []Conn `json:"conns,omitempty"` -} - -// NodeSnapshot represents the state of a node in the network -type NodeSnapshot struct { - Node Node `json:"node,omitempty"` - - // Snapshots is arbitrary data gathered from calling node.Snapshots() - Snapshots map[string][]byte `json:"snapshots,omitempty"` -} - -// Snapshot creates a network snapshot -func (net *Network) Snapshot() (*Snapshot, error) { - return net.snapshot(nil, nil) -} - -func (net *Network) SnapshotWithServices(addServices []string, removeServices []string) (*Snapshot, error) { - return net.snapshot(addServices, removeServices) -} - -func (net *Network) snapshot(addServices []string, removeServices []string) (*Snapshot, error) { - net.lock.Lock() - defer net.lock.Unlock() - snap := &Snapshot{ - Nodes: make([]NodeSnapshot, len(net.Nodes)), - } - for i, node := range net.Nodes { - snap.Nodes[i] = NodeSnapshot{Node: *node.copy()} - if !node.Up() { - continue - } - snapshots, err := node.Snapshots() - if err != nil { - return nil, err - } - snap.Nodes[i].Snapshots = snapshots - for _, addSvc := range addServices { - haveSvc := false - for _, svc := range snap.Nodes[i].Node.Config.Lifecycles { - if svc == addSvc { - haveSvc = true - break - } - } - if !haveSvc { - snap.Nodes[i].Node.Config.Lifecycles = append(snap.Nodes[i].Node.Config.Lifecycles, addSvc) - } - } - if len(removeServices) > 0 { - var cleanedServices []string - for _, svc := range snap.Nodes[i].Node.Config.Lifecycles { - haveSvc := false - for _, rmSvc := range removeServices { - if rmSvc == svc { - haveSvc = true - break - } - } - if !haveSvc { - cleanedServices = append(cleanedServices, svc) - } - } - snap.Nodes[i].Node.Config.Lifecycles = cleanedServices - } - } - for _, conn := range net.Conns { - if conn.Up { - snap.Conns = append(snap.Conns, *conn) - } - } - return snap, nil -} - -// longrunning tests may need a longer timeout -var snapshotLoadTimeout = 900 * time.Second - -// Load loads a network snapshot -func (net *Network) Load(snap *Snapshot) error { - // Start nodes. - for _, n := range snap.Nodes { - if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil { - return err - } - if !n.Node.Up() { - continue - } - if err := net.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil { - return err - } - } - - // Prepare connection events counter. - allConnected := make(chan struct{}) // closed when all connections are established - done := make(chan struct{}) // ensures that the event loop goroutine is terminated - defer close(done) - - // Subscribe to event channel. - // It needs to be done outside of the event loop goroutine (created below) - // to ensure that the event channel is blocking before connect calls are made. - events := make(chan *Event) - sub := net.Events().Subscribe(events) - defer sub.Unsubscribe() - - go func() { - // Expected number of connections. - total := len(snap.Conns) - // Set of all established connections from the snapshot, not other connections. - // Key array element 0 is the connection One field value, and element 1 connection Other field. - connections := make(map[[2]enode.ID]struct{}, total) - - for { - select { - case e := <-events: - // Ignore control events as they do not represent - // connect or disconnect (Up) state change. - if e.Control { - continue - } - // Detect only connection events. - if e.Type != EventTypeConn { - continue - } - connection := [2]enode.ID{e.Conn.One, e.Conn.Other} - // Nodes are still not connected or have been disconnected. - if !e.Conn.Up { - // Delete the connection from the set of established connections. - // This will prevent false positive in case disconnections happen. - delete(connections, connection) - log.Warn("load snapshot: unexpected disconnection", "one", e.Conn.One, "other", e.Conn.Other) - continue - } - // Check that the connection is from the snapshot. - for _, conn := range snap.Conns { - if conn.One == e.Conn.One && conn.Other == e.Conn.Other { - // Add the connection to the set of established connections. - connections[connection] = struct{}{} - if len(connections) == total { - // Signal that all nodes are connected. - close(allConnected) - return - } - - break - } - } - case <-done: - // Load function returned, terminate this goroutine. - return - } - } - }() - - // Start connecting. - for _, conn := range snap.Conns { - if !net.GetNode(conn.One).Up() || !net.GetNode(conn.Other).Up() { - //in this case, at least one of the nodes of a connection is not up, - //so it would result in the snapshot `Load` to fail - continue - } - if err := net.Connect(conn.One, conn.Other); err != nil { - return err - } - } - - timeout := time.NewTimer(snapshotLoadTimeout) - defer timeout.Stop() - - select { - // Wait until all connections from the snapshot are established. - case <-allConnected: - // Make sure that we do not wait forever. - case <-timeout.C: - return errors.New("snapshot connections not established") - } - return nil -} - -// Subscribe reads control events from a channel and executes them -func (net *Network) Subscribe(events chan *Event) { - for { - select { - case event, ok := <-events: - if !ok { - return - } - if event.Control { - net.executeControlEvent(event) - } - case <-net.quitc: - return - } - } -} - -func (net *Network) executeControlEvent(event *Event) { - log.Trace("Executing control event", "type", event.Type, "event", event) - switch event.Type { - case EventTypeNode: - if err := net.executeNodeEvent(event); err != nil { - log.Error("Error executing node event", "event", event, "err", err) - } - case EventTypeConn: - if err := net.executeConnEvent(event); err != nil { - log.Error("Error executing conn event", "event", event, "err", err) - } - case EventTypeMsg: - log.Warn("Ignoring control msg event") - } -} - -func (net *Network) executeNodeEvent(e *Event) error { - if !e.Node.Up() { - return net.Stop(e.Node.ID()) - } - - if _, err := net.NewNodeWithConfig(e.Node.Config); err != nil { - return err - } - return net.Start(e.Node.ID()) -} - -func (net *Network) executeConnEvent(e *Event) error { - if e.Conn.Up { - return net.Connect(e.Conn.One, e.Conn.Other) - } - return net.Disconnect(e.Conn.One, e.Conn.Other) -} diff --git a/p2p/simulations/network_test.go b/p2p/simulations/network_test.go deleted file mode 100644 index 4ed1e4e6c33b..000000000000 --- a/p2p/simulations/network_test.go +++ /dev/null @@ -1,872 +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 simulations - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "reflect" - "strconv" - "strings" - "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" -) - -// Tests that a created snapshot with a minimal service only contains the expected connections -// and that a network when loaded with this snapshot only contains those same connections -func TestSnapshot(t *testing.T) { - // PART I - // create snapshot from ring network - - // this is a minimal service, whose protocol will take exactly one message OR close of connection before quitting - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - return NewNoopService(nil), nil - }, - }) - - // create network - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "noopwoop", - }) - // \todo consider making a member of network, set to true threadsafe when shutdown - runningOne := true - defer func() { - if runningOne { - network.Shutdown() - } - }() - - // create and start nodes - nodeCount := 20 - ids := make([]enode.ID, nodeCount) - for i := 0; i < nodeCount; i++ { - conf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(conf) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := network.Start(node.ID()); err != nil { - t.Fatalf("error starting node: %s", err) - } - ids[i] = node.ID() - } - - // subscribe to peer events - evC := make(chan *Event) - sub := network.Events().Subscribe(evC) - defer sub.Unsubscribe() - - // connect nodes in a ring - // spawn separate thread to avoid deadlock in the event listeners - connectErr := make(chan error, 1) - go func() { - for i, id := range ids { - peerID := ids[(i+1)%len(ids)] - if err := network.Connect(id, peerID); err != nil { - connectErr <- err - return - } - } - }() - - // collect connection events up to expected number - ctx, cancel := context.WithTimeout(context.TODO(), time.Second) - defer cancel() - checkIds := make(map[enode.ID][]enode.ID) - connEventCount := nodeCount -OUTER: - for { - select { - case <-ctx.Done(): - t.Fatal(ctx.Err()) - case err := <-connectErr: - t.Fatal(err) - case ev := <-evC: - if ev.Type == EventTypeConn && !ev.Control { - // fail on any disconnect - if !ev.Conn.Up { - t.Fatalf("unexpected disconnect: %v -> %v", ev.Conn.One, ev.Conn.Other) - } - checkIds[ev.Conn.One] = append(checkIds[ev.Conn.One], ev.Conn.Other) - checkIds[ev.Conn.Other] = append(checkIds[ev.Conn.Other], ev.Conn.One) - connEventCount-- - log.Debug("ev", "count", connEventCount) - if connEventCount == 0 { - break OUTER - } - } - } - } - - // create snapshot of current network - snap, err := network.Snapshot() - if err != nil { - t.Fatal(err) - } - j, err := json.Marshal(snap) - if err != nil { - t.Fatal(err) - } - log.Debug("snapshot taken", "nodes", len(snap.Nodes), "conns", len(snap.Conns), "json", string(j)) - - // verify that the snap element numbers check out - if len(checkIds) != len(snap.Conns) || len(checkIds) != len(snap.Nodes) { - t.Fatalf("snapshot wrong node,conn counts %d,%d != %d", len(snap.Nodes), len(snap.Conns), len(checkIds)) - } - - // shut down sim network - runningOne = false - sub.Unsubscribe() - network.Shutdown() - - // check that we have all the expected connections in the snapshot - for nodid, nodConns := range checkIds { - for _, nodConn := range nodConns { - var match bool - for _, snapConn := range snap.Conns { - if snapConn.One == nodid && snapConn.Other == nodConn { - match = true - break - } else if snapConn.Other == nodid && snapConn.One == nodConn { - match = true - break - } - } - if !match { - t.Fatalf("snapshot missing conn %v -> %v", nodid, nodConn) - } - } - } - log.Info("snapshot checked") - - // PART II - // load snapshot and verify that exactly same connections are formed - - adapter = adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - return NewNoopService(nil), nil - }, - }) - network = NewNetwork(adapter, &NetworkConfig{ - DefaultService: "noopwoop", - }) - defer func() { - network.Shutdown() - }() - - // subscribe to peer events - // every node up and conn up event will generate one additional control event - // therefore multiply the count by two - evC = make(chan *Event, (len(snap.Conns)*2)+(len(snap.Nodes)*2)) - sub = network.Events().Subscribe(evC) - defer sub.Unsubscribe() - - // load the snapshot - // spawn separate thread to avoid deadlock in the event listeners - err = network.Load(snap) - if err != nil { - t.Fatal(err) - } - - // collect connection events up to expected number - ctx, cancel = context.WithTimeout(context.TODO(), time.Second*3) - defer cancel() - - connEventCount = nodeCount - -OuterTwo: - for { - select { - case <-ctx.Done(): - t.Fatal(ctx.Err()) - case ev := <-evC: - if ev.Type == EventTypeConn && !ev.Control { - // fail on any disconnect - if !ev.Conn.Up { - t.Fatalf("unexpected disconnect: %v -> %v", ev.Conn.One, ev.Conn.Other) - } - log.Debug("conn", "on", ev.Conn.One, "other", ev.Conn.Other) - checkIds[ev.Conn.One] = append(checkIds[ev.Conn.One], ev.Conn.Other) - checkIds[ev.Conn.Other] = append(checkIds[ev.Conn.Other], ev.Conn.One) - connEventCount-- - log.Debug("ev", "count", connEventCount) - if connEventCount == 0 { - break OuterTwo - } - } - } - } - - // check that we have all expected connections in the network - for _, snapConn := range snap.Conns { - var match bool - for nodid, nodConns := range checkIds { - for _, nodConn := range nodConns { - if snapConn.One == nodid && snapConn.Other == nodConn { - match = true - break - } else if snapConn.Other == nodid && snapConn.One == nodConn { - match = true - break - } - } - } - if !match { - t.Fatalf("network missing conn %v -> %v", snapConn.One, snapConn.Other) - } - } - - // verify that network didn't generate any other additional connection events after the ones we have collected within a reasonable period of time - ctx, cancel = context.WithTimeout(context.TODO(), time.Second) - defer cancel() - select { - case <-ctx.Done(): - case ev := <-evC: - if ev.Type == EventTypeConn { - t.Fatalf("Superfluous conn found %v -> %v", ev.Conn.One, ev.Conn.Other) - } - } - - // This test validates if all connections from the snapshot - // are created in the network. - t.Run("conns after load", func(t *testing.T) { - // Create new network. - n := NewNetwork( - adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - return NewNoopService(nil), nil - }, - }), - &NetworkConfig{ - DefaultService: "noopwoop", - }, - ) - defer n.Shutdown() - - // Load the same snapshot. - err := n.Load(snap) - if err != nil { - t.Fatal(err) - } - - // Check every connection from the snapshot - // if it is in the network, too. - for _, c := range snap.Conns { - if n.GetConn(c.One, c.Other) == nil { - t.Errorf("missing connection: %s -> %s", c.One, c.Other) - } - } - }) -} - -// TestNetworkSimulation creates a multi-node simulation network with each node -// connected in a ring topology, checks that all nodes successfully handshake -// with each other and that a snapshot fully represents the desired topology -func TestNetworkSimulation(t *testing.T) { - // create simulation network with 20 testService nodes - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - nodeCount := 20 - ids := make([]enode.ID, nodeCount) - for i := 0; i < nodeCount; i++ { - conf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(conf) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := network.Start(node.ID()); err != nil { - t.Fatalf("error starting node: %s", err) - } - ids[i] = node.ID() - } - - // perform a check which connects the nodes in a ring (so each node is - // connected to exactly two peers) and then checks that all nodes - // performed two handshakes by checking their peerCount - action := func(_ context.Context) error { - for i, id := range ids { - peerID := ids[(i+1)%len(ids)] - if err := network.Connect(id, peerID); err != nil { - return err - } - } - return nil - } - check := func(ctx context.Context, id enode.ID) (bool, error) { - // check we haven't run out of time - select { - case <-ctx.Done(): - return false, ctx.Err() - default: - } - - // get the node - node := network.GetNode(id) - if node == nil { - return false, fmt.Errorf("unknown node: %s", id) - } - - // check it has exactly two peers - client, err := node.Client() - if err != nil { - return false, err - } - var peerCount int64 - if err := client.CallContext(ctx, &peerCount, "test_peerCount"); err != nil { - return false, err - } - switch { - case peerCount < 2: - return false, nil - case peerCount == 2: - return true, nil - default: - return false, fmt.Errorf("unexpected peerCount: %d", peerCount) - } - } - - timeout := 30 * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - // trigger a check every 100ms - trigger := make(chan enode.ID) - go triggerChecks(ctx, ids, trigger, 100*time.Millisecond) - - result := NewSimulation(network).Run(ctx, &Step{ - Action: action, - Trigger: trigger, - Expect: &Expectation{ - Nodes: ids, - Check: check, - }, - }) - if result.Error != nil { - t.Fatalf("simulation failed: %s", result.Error) - } - - // take a network snapshot and check it contains the correct topology - snap, err := network.Snapshot() - if err != nil { - t.Fatal(err) - } - if len(snap.Nodes) != nodeCount { - t.Fatalf("expected snapshot to contain %d nodes, got %d", nodeCount, len(snap.Nodes)) - } - if len(snap.Conns) != nodeCount { - t.Fatalf("expected snapshot to contain %d connections, got %d", nodeCount, len(snap.Conns)) - } - for i, id := range ids { - conn := snap.Conns[i] - if conn.One != id { - t.Fatalf("expected conn[%d].One to be %s, got %s", i, id, conn.One) - } - peerID := ids[(i+1)%len(ids)] - if conn.Other != peerID { - t.Fatalf("expected conn[%d].Other to be %s, got %s", i, peerID, conn.Other) - } - } -} - -func createTestNodes(count int, network *Network) (nodes []*Node, err error) { - for i := 0; i < count; i++ { - nodeConf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(nodeConf) - if err != nil { - return nil, err - } - if err := network.Start(node.ID()); err != nil { - return nil, err - } - - nodes = append(nodes, node) - } - - return nodes, nil -} - -func createTestNodesWithProperty(property string, count int, network *Network) (propertyNodes []*Node, err error) { - for i := 0; i < count; i++ { - nodeConf := adapters.RandomNodeConfig() - nodeConf.Properties = append(nodeConf.Properties, property) - - node, err := network.NewNodeWithConfig(nodeConf) - if err != nil { - return nil, err - } - if err := network.Start(node.ID()); err != nil { - return nil, err - } - - propertyNodes = append(propertyNodes, node) - } - - return propertyNodes, nil -} - -// TestGetNodeIDs creates a set of nodes and attempts to retrieve their IDs,. -// It then tests again whilst excluding a node ID from being returned. -// If a node ID is not returned, or more node IDs than expected are returned, the test fails. -func TestGetNodeIDs(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 5 - nodes, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Could not create test nodes %v", err) - } - - gotNodeIDs := network.GetNodeIDs() - if len(gotNodeIDs) != numNodes { - t.Fatalf("Expected %d nodes, got %d", numNodes, len(gotNodeIDs)) - } - - for _, node1 := range nodes { - match := false - for _, node2ID := range gotNodeIDs { - if bytes.Equal(node1.ID().Bytes(), node2ID.Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("A created node was not returned by GetNodes(), ID: %s", node1.ID().String()) - } - } - - excludeNodeID := nodes[3].ID() - gotNodeIDsExcl := network.GetNodeIDs(excludeNodeID) - if len(gotNodeIDsExcl) != numNodes-1 { - t.Fatalf("Expected one less node ID to be returned") - } - for _, nodeID := range gotNodeIDsExcl { - if bytes.Equal(excludeNodeID.Bytes(), nodeID.Bytes()) { - t.Fatalf("GetNodeIDs returned the node ID we excluded, ID: %s", nodeID.String()) - } - } -} - -// TestGetNodes creates a set of nodes and attempts to retrieve them again. -// It then tests again whilst excluding a node from being returned. -// If a node is not returned, or more nodes than expected are returned, the test fails. -func TestGetNodes(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 5 - nodes, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Could not create test nodes %v", err) - } - - gotNodes := network.GetNodes() - if len(gotNodes) != numNodes { - t.Fatalf("Expected %d nodes, got %d", numNodes, len(gotNodes)) - } - - for _, node1 := range nodes { - match := false - for _, node2 := range gotNodes { - if bytes.Equal(node1.ID().Bytes(), node2.ID().Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("A created node was not returned by GetNodes(), ID: %s", node1.ID().String()) - } - } - - excludeNodeID := nodes[3].ID() - gotNodesExcl := network.GetNodes(excludeNodeID) - if len(gotNodesExcl) != numNodes-1 { - t.Fatalf("Expected one less node to be returned") - } - for _, node := range gotNodesExcl { - if bytes.Equal(excludeNodeID.Bytes(), node.ID().Bytes()) { - t.Fatalf("GetNodes returned the node we excluded, ID: %s", node.ID().String()) - } - } -} - -// TestGetNodesByID creates a set of nodes and attempts to retrieve a subset of them by ID -// If a node is not returned, or more nodes than expected are returned, the test fails. -func TestGetNodesByID(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 5 - nodes, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Could not create test nodes: %v", err) - } - - numSubsetNodes := 2 - subsetNodes := nodes[0:numSubsetNodes] - var subsetNodeIDs []enode.ID - for _, node := range subsetNodes { - subsetNodeIDs = append(subsetNodeIDs, node.ID()) - } - - gotNodesByID := network.GetNodesByID(subsetNodeIDs) - if len(gotNodesByID) != numSubsetNodes { - t.Fatalf("Expected %d nodes, got %d", numSubsetNodes, len(gotNodesByID)) - } - - for _, node1 := range subsetNodes { - match := false - for _, node2 := range gotNodesByID { - if bytes.Equal(node1.ID().Bytes(), node2.ID().Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("A created node was not returned by GetNodesByID(), ID: %s", node1.ID().String()) - } - } -} - -// TestGetNodesByProperty creates a subset of nodes with a property assigned. -// GetNodesByProperty is then checked for correctness by comparing the nodes returned to those initially created. -// If a node with a property is not found, or more nodes than expected are returned, the test fails. -func TestGetNodesByProperty(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 3 - _, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Failed to create nodes: %v", err) - } - - numPropertyNodes := 3 - propertyTest := "test" - propertyNodes, err := createTestNodesWithProperty(propertyTest, numPropertyNodes, network) - if err != nil { - t.Fatalf("Failed to create nodes with property: %v", err) - } - - gotNodesByProperty := network.GetNodesByProperty(propertyTest) - if len(gotNodesByProperty) != numPropertyNodes { - t.Fatalf("Expected %d nodes with a property, got %d", numPropertyNodes, len(gotNodesByProperty)) - } - - for _, node1 := range propertyNodes { - match := false - for _, node2 := range gotNodesByProperty { - if bytes.Equal(node1.ID().Bytes(), node2.ID().Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("A created node with property was not returned by GetNodesByProperty(), ID: %s", node1.ID().String()) - } - } -} - -// TestGetNodeIDsByProperty creates a subset of nodes with a property assigned. -// GetNodeIDsByProperty is then checked for correctness by comparing the node IDs returned to those initially created. -// If a node ID with a property is not found, or more nodes IDs than expected are returned, the test fails. -func TestGetNodeIDsByProperty(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 3 - _, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Failed to create nodes: %v", err) - } - - numPropertyNodes := 3 - propertyTest := "test" - propertyNodes, err := createTestNodesWithProperty(propertyTest, numPropertyNodes, network) - if err != nil { - t.Fatalf("Failed to created nodes with property: %v", err) - } - - gotNodeIDsByProperty := network.GetNodeIDsByProperty(propertyTest) - if len(gotNodeIDsByProperty) != numPropertyNodes { - t.Fatalf("Expected %d nodes with a property, got %d", numPropertyNodes, len(gotNodeIDsByProperty)) - } - - for _, node1 := range propertyNodes { - match := false - id1 := node1.ID() - for _, id2 := range gotNodeIDsByProperty { - if bytes.Equal(id1.Bytes(), id2.Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("Not all nodes IDs were returned by GetNodeIDsByProperty(), ID: %s", id1.String()) - } - } -} - -func triggerChecks(ctx context.Context, ids []enode.ID, trigger chan enode.ID, interval time.Duration) { - tick := time.NewTicker(interval) - defer tick.Stop() - for { - select { - case <-tick.C: - for _, id := range ids { - select { - case trigger <- id: - case <-ctx.Done(): - return - } - } - case <-ctx.Done(): - return - } - } -} - -// \todo: refactor to implement snapshots -// and connect configuration methods once these are moved from -// swarm/network/simulations/connect.go -func BenchmarkMinimalService(b *testing.B) { - b.Run("ring/32", benchmarkMinimalServiceTmp) -} - -func benchmarkMinimalServiceTmp(b *testing.B) { - // stop timer to discard setup time pollution - args := strings.Split(b.Name(), "/") - nodeCount, err := strconv.ParseInt(args[2], 10, 16) - if err != nil { - b.Fatal(err) - } - - for i := 0; i < b.N; i++ { - // this is a minimal service, whose protocol will close a channel upon run of protocol - // making it possible to bench the time it takes for the service to start and protocol actually to be run - protoCMap := make(map[enode.ID]map[enode.ID]chan struct{}) - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - protoCMap[ctx.Config.ID] = make(map[enode.ID]chan struct{}) - svc := NewNoopService(protoCMap[ctx.Config.ID]) - return svc, nil - }, - }) - - // create network - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "noopwoop", - }) - defer network.Shutdown() - - // create and start nodes - ids := make([]enode.ID, nodeCount) - for i := 0; i < int(nodeCount); i++ { - conf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(conf) - if err != nil { - b.Fatalf("error creating node: %s", err) - } - if err := network.Start(node.ID()); err != nil { - b.Fatalf("error starting node: %s", err) - } - ids[i] = node.ID() - } - - // ready, set, go - b.ResetTimer() - - // connect nodes in a ring - for i, id := range ids { - peerID := ids[(i+1)%len(ids)] - if err := network.Connect(id, peerID); err != nil { - b.Fatal(err) - } - } - - // wait for all protocols to signal to close down - ctx, cancel := context.WithTimeout(context.TODO(), time.Second) - defer cancel() - for nodid, peers := range protoCMap { - for peerid, peerC := range peers { - log.Debug("getting ", "node", nodid, "peer", peerid) - select { - case <-ctx.Done(): - b.Fatal(ctx.Err()) - case <-peerC: - } - } - } - } -} - -func TestNode_UnmarshalJSON(t *testing.T) { - t.Run("up_field", func(t *testing.T) { - runNodeUnmarshalJSON(t, casesNodeUnmarshalJSONUpField()) - }) - t.Run("config_field", func(t *testing.T) { - runNodeUnmarshalJSON(t, casesNodeUnmarshalJSONConfigField()) - }) -} - -func runNodeUnmarshalJSON(t *testing.T, tests []nodeUnmarshalTestCase) { - t.Helper() - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var got *Node - if err := json.Unmarshal([]byte(tt.marshaled), &got); err != nil { - expectErrorMessageToContain(t, err, tt.wantErr) - got = nil - } - expectNodeEquality(t, got, tt.want) - }) - } -} - -type nodeUnmarshalTestCase struct { - name string - marshaled string - want *Node - wantErr string -} - -func expectErrorMessageToContain(t *testing.T, got error, want string) { - t.Helper() - if got == nil && want == "" { - return - } - - if got == nil && want != "" { - t.Errorf("error was expected, got: nil, want: %v", want) - return - } - - if !strings.Contains(got.Error(), want) { - t.Errorf( - "unexpected error message, got %v, want: %v", - want, - got, - ) - } -} - -func expectNodeEquality(t *testing.T, got, want *Node) { - t.Helper() - if !reflect.DeepEqual(got, want) { - t.Errorf("Node.UnmarshalJSON() = %v, want %v", got, want) - } -} - -func casesNodeUnmarshalJSONUpField() []nodeUnmarshalTestCase { - return []nodeUnmarshalTestCase{ - { - name: "empty json", - marshaled: "{}", - want: newNode(nil, nil, false), - }, - { - name: "a stopped node", - marshaled: "{\"up\": false}", - want: newNode(nil, nil, false), - }, - { - name: "a running node", - marshaled: "{\"up\": true}", - want: newNode(nil, nil, true), - }, - { - name: "invalid JSON value on valid key", - marshaled: "{\"up\": foo}", - wantErr: "invalid character", - }, - { - name: "invalid JSON key and value", - marshaled: "{foo: bar}", - wantErr: "invalid character", - }, - { - name: "bool value expected but got something else (string)", - marshaled: "{\"up\": \"true\"}", - wantErr: "cannot unmarshal string into Go struct", - }, - } -} - -func casesNodeUnmarshalJSONConfigField() []nodeUnmarshalTestCase { - // Don't do a big fuss around testing, as adapters.NodeConfig should - // handle it's own serialization. Just do a sanity check. - return []nodeUnmarshalTestCase{ - { - name: "Config field is omitted", - marshaled: "{}", - want: newNode(nil, nil, false), - }, - { - name: "Config field is nil", - marshaled: "{\"config\": null}", - want: newNode(nil, nil, false), - }, - { - name: "a non default Config field", - marshaled: "{\"config\":{\"name\":\"node_ecdd0\",\"port\":44665}}", - want: newNode(nil, &adapters.NodeConfig{Name: "node_ecdd0", Port: 44665}, false), - }, - } -} diff --git a/p2p/simulations/simulation.go b/p2p/simulations/simulation.go deleted file mode 100644 index ae62c42b9c2d..000000000000 --- a/p2p/simulations/simulation.go +++ /dev/null @@ -1,157 +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 simulations - -import ( - "context" - "time" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -// Simulation provides a framework for running actions in a simulated network -// and then waiting for expectations to be met -type Simulation struct { - network *Network -} - -// NewSimulation returns a new simulation which runs in the given network -func NewSimulation(network *Network) *Simulation { - return &Simulation{ - network: network, - } -} - -// Run performs a step of the simulation by performing the step's action and -// then waiting for the step's expectation to be met -func (s *Simulation) Run(ctx context.Context, step *Step) (result *StepResult) { - result = newStepResult() - - result.StartedAt = time.Now() - defer func() { result.FinishedAt = time.Now() }() - - // watch network events for the duration of the step - stop := s.watchNetwork(result) - defer stop() - - // perform the action - if err := step.Action(ctx); err != nil { - result.Error = err - return - } - - // wait for all node expectations to either pass, error or timeout - nodes := make(map[enode.ID]struct{}, len(step.Expect.Nodes)) - for _, id := range step.Expect.Nodes { - nodes[id] = struct{}{} - } - for len(result.Passes) < len(nodes) { - select { - case id := <-step.Trigger: - // skip if we aren't checking the node - if _, ok := nodes[id]; !ok { - continue - } - - // skip if the node has already passed - if _, ok := result.Passes[id]; ok { - continue - } - - // run the node expectation check - pass, err := step.Expect.Check(ctx, id) - if err != nil { - result.Error = err - return - } - if pass { - result.Passes[id] = time.Now() - } - case <-ctx.Done(): - result.Error = ctx.Err() - return - } - } - - return -} - -func (s *Simulation) watchNetwork(result *StepResult) func() { - stop := make(chan struct{}) - done := make(chan struct{}) - events := make(chan *Event) - sub := s.network.Events().Subscribe(events) - go func() { - defer close(done) - defer sub.Unsubscribe() - for { - select { - case event := <-events: - result.NetworkEvents = append(result.NetworkEvents, event) - case <-stop: - return - } - } - }() - return func() { - close(stop) - <-done - } -} - -type Step struct { - // Action is the action to perform for this step - Action func(context.Context) error - - // Trigger is a channel which receives node ids and triggers an - // expectation check for that node - Trigger chan enode.ID - - // Expect is the expectation to wait for when performing this step - Expect *Expectation -} - -type Expectation struct { - // Nodes is a list of nodes to check - Nodes []enode.ID - - // Check checks whether a given node meets the expectation - Check func(context.Context, enode.ID) (bool, error) -} - -func newStepResult() *StepResult { - return &StepResult{ - Passes: make(map[enode.ID]time.Time), - } -} - -type StepResult struct { - // Error is the error encountered whilst running the step - Error error - - // StartedAt is the time the step started - StartedAt time.Time - - // FinishedAt is the time the step finished - FinishedAt time.Time - - // Passes are the timestamps of the successful node expectations - Passes map[enode.ID]time.Time - - // NetworkEvents are the network events which occurred during the step - NetworkEvents []*Event -} diff --git a/p2p/simulations/test.go b/p2p/simulations/test.go deleted file mode 100644 index 0edb07b127f8..000000000000 --- a/p2p/simulations/test.go +++ /dev/null @@ -1,150 +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 simulations - -import ( - "testing" - - "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/rpc" -) - -// NoopService is the service that does not do anything -// but implements node.Service interface. -type NoopService struct { - c map[enode.ID]chan struct{} -} - -func NewNoopService(ackC map[enode.ID]chan struct{}) *NoopService { - return &NoopService{ - c: ackC, - } -} - -func (t *NoopService) Protocols() []p2p.Protocol { - return []p2p.Protocol{ - { - Name: "noop", - Version: 666, - Length: 0, - Run: func(peer *p2p.Peer, rw p2p.MsgReadWriter) error { - if t.c != nil { - t.c[peer.ID()] = make(chan struct{}) - close(t.c[peer.ID()]) - } - rw.ReadMsg() - return nil - }, - NodeInfo: func() interface{} { - return struct{}{} - }, - PeerInfo: func(id enode.ID) interface{} { - return struct{}{} - }, - Attributes: []enr.Entry{}, - }, - } -} - -func (t *NoopService) APIs() []rpc.API { - return []rpc.API{} -} - -func (t *NoopService) Start() error { - return nil -} - -func (t *NoopService) Stop() error { - return nil -} - -func VerifyRing(t *testing.T, net *Network, ids []enode.ID) { - t.Helper() - n := len(ids) - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - c := net.GetConn(ids[i], ids[j]) - if i == j-1 || (i == 0 && j == n-1) { - if c == nil { - t.Errorf("nodes %v and %v are not connected, but they should be", i, j) - } - } else { - if c != nil { - t.Errorf("nodes %v and %v are connected, but they should not be", i, j) - } - } - } - } -} - -func VerifyChain(t *testing.T, net *Network, ids []enode.ID) { - t.Helper() - n := len(ids) - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - c := net.GetConn(ids[i], ids[j]) - if i == j-1 { - if c == nil { - t.Errorf("nodes %v and %v are not connected, but they should be", i, j) - } - } else { - if c != nil { - t.Errorf("nodes %v and %v are connected, but they should not be", i, j) - } - } - } - } -} - -func VerifyFull(t *testing.T, net *Network, ids []enode.ID) { - t.Helper() - n := len(ids) - var connections int - for i, lid := range ids { - for _, rid := range ids[i+1:] { - if net.GetConn(lid, rid) != nil { - connections++ - } - } - } - - want := n * (n - 1) / 2 - if connections != want { - t.Errorf("wrong number of connections, got: %v, want: %v", connections, want) - } -} - -func VerifyStar(t *testing.T, net *Network, ids []enode.ID, centerIndex int) { - t.Helper() - n := len(ids) - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - c := net.GetConn(ids[i], ids[j]) - if i == centerIndex || j == centerIndex { - if c == nil { - t.Errorf("nodes %v and %v are not connected, but they should be", i, j) - } - } else { - if c != nil { - t.Errorf("nodes %v and %v are connected, but they should not be", i, j) - } - } - } - } -} diff --git a/p2p/transport_test.go b/p2p/transport_test.go index 24e06c5a06bc..01695cd3afdb 100644 --- a/p2p/transport_test.go +++ b/p2p/transport_test.go @@ -24,7 +24,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p/simulations/pipes" + "github.com/ethereum/go-ethereum/p2p/pipes" ) func TestProtocolHandshake(t *testing.T) { From 5adf4adc8ec2c497eddd3b1ff20d2d35d65ec5fc Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 12 Aug 2024 16:43:54 +0800 Subject: [PATCH 458/571] eth/protocols/snap: cleanup dangling account trie nodes due to incomplete storage (#30258) This pull request fixes #30229. During snap sync, large storage will be split into several pieces and synchronized concurrently. Unfortunately, the tradeoff is that the respective merkle trie of each storage chunk will be incomplete due to the incomplete boundaries. The trie nodes on these boundaries will be discarded, and any dangling nodes on disk will also be removed if they fall on these paths, ensuring the state healer won't be blocked. However, the dangling account trie nodes on the path from the root to the associated account are left untouched. This means the dangling account trie nodes could potentially stop the state healing and break the assumption that the entire subtrie should exist if the subtrie root exists. We should consider the account trie node as the ancestor of the corresponding storage trie node. In the scenarios described in the above ticket, the state corruption could occur if there is a dangling account trie node while some storage trie nodes are removed due to synchronization redo. The fixing idea is pretty straightforward, the trie nodes on the path from root to account should all be explicitly removed if an incomplete storage trie occurs. Therefore, a `delete` operation has been added into `gentrie` to explicitly clear the account along with all nodes on this path. The special thing is that it's a cross-trie clearing. In theory, there may be a dangling node at any position on this account key and we have to clear all of them. --- eth/protocols/snap/gentrie.go | 44 ++++++++- eth/protocols/snap/gentrie_test.go | 142 +++++++++++++++++++++++++++++ eth/protocols/snap/sync.go | 11 ++- trie/stacktrie.go | 10 +- 4 files changed, 198 insertions(+), 9 deletions(-) diff --git a/eth/protocols/snap/gentrie.go b/eth/protocols/snap/gentrie.go index 6255fb221db1..5126d26777c8 100644 --- a/eth/protocols/snap/gentrie.go +++ b/eth/protocols/snap/gentrie.go @@ -31,6 +31,9 @@ type genTrie interface { // update inserts the state item into generator trie. update(key, value []byte) error + // delete removes the state item from the generator trie. + delete(key []byte) error + // commit flushes the right boundary nodes if complete flag is true. This // function must be called before flushing the associated database batch. commit(complete bool) common.Hash @@ -113,7 +116,7 @@ func (t *pathTrie) onTrieNode(path []byte, hash common.Hash, blob []byte) { // removed because it's a sibling of the nodes we want to commit, not // the parent or ancestor. for i := 0; i < len(path); i++ { - t.delete(path[:i], false) + t.deleteNode(path[:i], false) } } return @@ -136,7 +139,7 @@ func (t *pathTrie) onTrieNode(path []byte, hash common.Hash, blob []byte) { // byte key. In either case, no gaps will be left in the path. if t.last != nil && bytes.HasPrefix(t.last, path) && len(t.last)-len(path) > 1 { for i := len(path) + 1; i < len(t.last); i++ { - t.delete(t.last[:i], true) + t.deleteNode(t.last[:i], true) } } t.write(path, blob) @@ -192,8 +195,8 @@ func (t *pathTrie) deleteStorageNode(path []byte, inner bool) { rawdb.DeleteStorageTrieNode(t.batch, t.owner, path) } -// delete commits the node deletion to provided database batch in path mode. -func (t *pathTrie) delete(path []byte, inner bool) { +// deleteNode commits the node deletion to provided database batch in path mode. +func (t *pathTrie) deleteNode(path []byte, inner bool) { if t.owner == (common.Hash{}) { t.deleteAccountNode(path, inner) } else { @@ -207,6 +210,34 @@ func (t *pathTrie) update(key, value []byte) error { return t.tr.Update(key, value) } +// delete implements genTrie interface, deleting the item from the stack trie. +func (t *pathTrie) delete(key []byte) error { + // Commit the trie since the right boundary is incomplete because + // of the deleted item. This will implicitly discard the last inserted + // item and clean some ancestor trie nodes of the last committed + // item in the database. + t.commit(false) + + // Reset the trie and all the internal trackers + t.first = nil + t.last = nil + t.tr.Reset() + + // Explicitly mark the left boundary as incomplete, as the left-side + // item of the next one has been deleted. Be aware that the next item + // to be inserted will be ignored from committing as well as it's on + // the left boundary. + t.skipLeftBoundary = true + + // Explicitly delete the potential leftover nodes on the specific + // path from the database. + tkey := t.tr.TrieKey(key) + for i := 0; i <= len(tkey); i++ { + t.deleteNode(tkey[:i], false) + } + return nil +} + // commit implements genTrie interface, flushing the right boundary if it's // considered as complete. Otherwise, the nodes on the right boundary are // discarded and cleaned up. @@ -255,7 +286,7 @@ func (t *pathTrie) commit(complete bool) common.Hash { // with no issues as they are actually complete. Also, from a database // perspective, first deleting and then rewriting is a valid data update. for i := 0; i < len(t.last); i++ { - t.delete(t.last[:i], false) + t.deleteNode(t.last[:i], false) } return common.Hash{} // the hash is meaningless for incomplete commit } @@ -278,6 +309,9 @@ func (t *hashTrie) update(key, value []byte) error { return t.tr.Update(key, value) } +// delete implements genTrie interface, ignoring the state item for deleting. +func (t *hashTrie) delete(key []byte) error { return nil } + // commit implements genTrie interface, committing the nodes on right boundary. func (t *hashTrie) commit(complete bool) common.Hash { if !complete { diff --git a/eth/protocols/snap/gentrie_test.go b/eth/protocols/snap/gentrie_test.go index 1fb2dbce7568..2da4f3c866e6 100644 --- a/eth/protocols/snap/gentrie_test.go +++ b/eth/protocols/snap/gentrie_test.go @@ -551,3 +551,145 @@ func TestTinyPartialTree(t *testing.T) { } } } + +func TestTrieDelete(t *testing.T) { + var entries []*kv + for i := 0; i < 1024; i++ { + entries = append(entries, &kv{ + k: testrand.Bytes(32), + v: testrand.Bytes(32), + }) + } + slices.SortFunc(entries, (*kv).cmp) + + nodes := make(map[string]common.Hash) + tr := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { + nodes[string(path)] = hash + }) + for i := 0; i < len(entries); i++ { + tr.Update(entries[i].k, entries[i].v) + } + tr.Hash() + + check := func(index []int) { + var ( + db = rawdb.NewMemoryDatabase() + batch = db.NewBatch() + marks = map[int]struct{}{} + neighbors = map[int]struct{}{} + ) + for _, n := range index { + marks[n] = struct{}{} + } + for _, n := range index { + if n != 0 { + if _, ok := marks[n-1]; !ok { + neighbors[n-1] = struct{}{} + } + } + if n != len(entries)-1 { + if _, ok := neighbors[n+1]; !ok { + neighbors[n+1] = struct{}{} + } + } + } + // Write the junk nodes as the dangling + var injects []string + for _, n := range index { + nibbles := byteToHex(entries[n].k) + for i := 0; i <= len(nibbles); i++ { + injects = append(injects, string(nibbles[:i])) + } + } + for _, path := range injects { + rawdb.WriteAccountTrieNode(db, []byte(path), testrand.Bytes(32)) + } + tr := newPathTrie(common.Hash{}, false, db, batch) + for i := 0; i < len(entries); i++ { + if _, ok := marks[i]; ok { + tr.delete(entries[i].k) + } else { + tr.update(entries[i].k, entries[i].v) + } + } + tr.commit(true) + + r := newBatchReplay() + batch.Replay(r) + batch.Write() + + for _, path := range injects { + if rawdb.HasAccountTrieNode(db, []byte(path)) { + t.Fatalf("Unexpected leftover node %v", []byte(path)) + } + } + + // ensure all the written nodes match with the complete tree + set := make(map[string]common.Hash) + for path, hash := range r.modifies() { + if hash == (common.Hash{}) { + continue + } + n, ok := nodes[path] + if !ok { + t.Fatalf("Unexpected trie node: %v", []byte(path)) + } + if n != hash { + t.Fatalf("Unexpected trie node content: %v, want: %x, got: %x", []byte(path), n, hash) + } + set[path] = hash + } + + // ensure all the missing nodes either on the deleted path, or + // on the neighbor paths. + isMissing := func(path []byte) bool { + for n := range marks { + key := byteToHex(entries[n].k) + if bytes.HasPrefix(key, path) { + return true + } + } + for n := range neighbors { + key := byteToHex(entries[n].k) + if bytes.HasPrefix(key, path) { + return true + } + } + return false + } + for path := range nodes { + if _, ok := set[path]; ok { + continue + } + if !isMissing([]byte(path)) { + t.Fatalf("Missing node %v", []byte(path)) + } + } + } + var cases = []struct { + index []int + }{ + // delete the first + {[]int{0}}, + + // delete the last + {[]int{len(entries) - 1}}, + + // delete the first two + {[]int{0, 1}}, + + // delete the last two + {[]int{len(entries) - 2, len(entries) - 1}}, + + {[]int{ + 0, 2, 4, 6, + len(entries) - 1, + len(entries) - 3, + len(entries) - 5, + len(entries) - 7, + }}, + } + for _, c := range cases { + check(c.index) + } +} diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 88d7d34dcc66..cdd03e6a0c48 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -2424,14 +2424,21 @@ func (s *Syncer) forwardAccountTask(task *accountTask) { slim := types.SlimAccountRLP(*res.accounts[i]) rawdb.WriteAccountSnapshot(batch, hash, slim) - // If the task is complete, drop it into the stack trie to generate - // account trie nodes for it if !task.needHeal[i] { + // If the storage task is complete, drop it into the stack trie + // to generate account trie nodes for it full, err := types.FullAccountRLP(slim) // TODO(karalabe): Slim parsing can be omitted if err != nil { panic(err) // Really shouldn't ever happen } task.genTrie.update(hash[:], full) + } else { + // If the storage task is incomplete, explicitly delete the corresponding + // account item from the account trie to ensure that all nodes along the + // path to the incomplete storage trie are cleaned up. + if err := task.genTrie.delete(hash[:]); err != nil { + panic(err) // Really shouldn't ever happen + } } } // Flush anything written just now and update the stats diff --git a/trie/stacktrie.go b/trie/stacktrie.go index 9c574db0bfa5..d194cbf0aec4 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -64,8 +64,7 @@ func (t *StackTrie) Update(key, value []byte) error { if len(value) == 0 { return errors.New("trying to insert empty (deletion)") } - k := keybytesToHex(key) - k = k[:len(k)-1] // chop the termination flag + k := t.TrieKey(key) if bytes.Compare(t.last, k) >= 0 { return errors.New("non-ascending key order") } @@ -84,6 +83,13 @@ func (t *StackTrie) Reset() { t.last = nil } +// TrieKey returns the internal key representation for the given user key. +func (t *StackTrie) TrieKey(key []byte) []byte { + k := keybytesToHex(key) + k = k[:len(k)-1] // chop the termination flag + return k +} + // stNode represents a node within a StackTrie type stNode struct { typ uint8 // node type (as in branch, ext, leaf) From 880511dc39e5d4788a07313a1289c928c8b7c7b7 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 12 Aug 2024 14:15:30 +0200 Subject: [PATCH 459/571] params: release go-ethereum v1.14.8 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 852f9fd1e185..050b2122f788 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 8 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 8 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 1cf3b5d38ac64921819b8e999d194047c84c4126 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 12 Aug 2024 14:19:35 +0200 Subject: [PATCH 460/571] params: begin v1.14.9 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 050b2122f788..22e59d6838f9 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 8 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 9 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From ab03c5746c040be2336a0efa0e2dcc43871435f0 Mon Sep 17 00:00:00 2001 From: Shude Li Date: Tue, 13 Aug 2024 02:42:36 +0800 Subject: [PATCH 461/571] go.mod: remove github.com/julienschmidt/httprouter (#30290) --- go.mod | 1 - go.sum | 1 - 2 files changed, 2 deletions(-) diff --git a/go.mod b/go.mod index 763210decd0b..ae6b12c0b8e6 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,6 @@ require ( github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 - github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 github.com/kilic/bls12-381 v0.1.0 github.com/kylelemons/godebug v1.1.0 diff --git a/go.sum b/go.sum index 562362dee6fd..4dadd40a75f0 100644 --- a/go.sum +++ b/go.sum @@ -339,7 +339,6 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 h1:msKODTL1m0wigztaqILOtla9HeW1ciscYG4xjLtvk5I= github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8= From bc95452e024b91c238ef3e43f3573eb179a762d2 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 12 Aug 2024 11:46:15 -0700 Subject: [PATCH 462/571] build: run 'go mod tidy' check as part of lint (#30291) --- build/ci.go | 68 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/build/ci.go b/build/ci.go index db5763370431..009d69e6e416 100644 --- a/build/ci.go +++ b/build/ci.go @@ -349,10 +349,10 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string { return filepath.Join(cachedir, base) } -// hashSourceFiles iterates all files under the top-level project directory +// hashAllSourceFiles iterates all files under the top-level project directory // computing the hash of each file (excluding files within the tests // subrepo) -func hashSourceFiles() (map[string]common.Hash, error) { +func hashAllSourceFiles() (map[string]common.Hash, error) { res := make(map[string]common.Hash) err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error { if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) { @@ -379,6 +379,56 @@ func hashSourceFiles() (map[string]common.Hash, error) { return res, nil } +// hashSourceFiles iterates the provided set of filepaths (relative to the top-level geth project directory) +// computing the hash of each file. +func hashSourceFiles(files []string) (map[string]common.Hash, error) { + res := make(map[string]common.Hash) + for _, filePath := range files { + f, err := os.OpenFile(filePath, os.O_RDONLY, 0666) + if err != nil { + return nil, err + } + hasher := sha256.New() + if _, err := io.Copy(hasher, f); err != nil { + return nil, err + } + res[filePath] = common.Hash(hasher.Sum(nil)) + } + return res, nil +} + +// compareHashedFilesets compares two maps (key is relative file path to top-level geth directory, value is its hash) +// and returns the list of file paths whose hashes differed. +func compareHashedFilesets(preHashes map[string]common.Hash, postHashes map[string]common.Hash) []string { + updates := []string{} + for path, postHash := range postHashes { + preHash, ok := preHashes[path] + if !ok || preHash != postHash { + updates = append(updates, path) + } + } + return updates +} + +func doGoModTidy() { + targetFiles := []string{"go.mod", "go.sum"} + preHashes, err := hashSourceFiles(targetFiles) + if err != nil { + log.Fatal("failed to hash go.mod/go.sum", "err", err) + } + tc := new(build.GoToolchain) + c := tc.Go("mod", "tidy") + build.MustRun(c) + postHashes, err := hashSourceFiles(targetFiles) + updates := compareHashedFilesets(preHashes, postHashes) + for _, updatedFile := range updates { + fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile) + } + if len(updates) != 0 { + log.Fatal("go.sum and/or go.mod were updated by running 'go mod tidy'") + } +} + // doGenerate ensures that re-generating generated files does not cause // any mutations in the source file tree: i.e. all generated files were // updated and committed. Any stale generated files are updated. @@ -395,7 +445,7 @@ func doGenerate() { var preHashes map[string]common.Hash if *verify { var err error - preHashes, err = hashSourceFiles() + preHashes, err = hashAllSourceFiles() if err != nil { log.Fatal("failed to compute map of source hashes", "err", err) } @@ -410,17 +460,11 @@ func doGenerate() { return } // Check if files were changed. - postHashes, err := hashSourceFiles() + postHashes, err := hashAllSourceFiles() if err != nil { log.Fatal("error computing source tree file hashes", "err", err) } - updates := []string{} - for path, postHash := range postHashes { - preHash, ok := preHashes[path] - if !ok || preHash != postHash { - updates = append(updates, path) - } - } + updates := compareHashedFilesets(preHashes, postHashes) for _, updatedFile := range updates { fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile) } @@ -443,6 +487,8 @@ func doLint(cmdline []string) { linter := downloadLinter(*cachedir) lflags := []string{"run", "--config", ".golangci.yml"} build.MustRunCommandWithOutput(linter, append(lflags, packages...)...) + + doGoModTidy() fmt.Println("You have achieved perfection.") } From bd57f35f8d1e920ef2b234ea6cd1aa18715b358f Mon Sep 17 00:00:00 2001 From: Zoo Date: Tue, 13 Aug 2024 19:49:31 +0800 Subject: [PATCH 463/571] core/txpool/blobpool: fix error message (#30247) the validation process only checks for 'less than', which is inconsistent with the error output --- core/txpool/blobpool/blobpool.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index cb266fd10a07..d66a08aa17a4 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1155,11 +1155,11 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error { ) switch { case tx.GasFeeCapIntCmp(minGasFeeCap.ToBig()) < 0: - return fmt.Errorf("%w: new tx gas fee cap %v <= %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasFeeCap(), prev.execFeeCap, p.config.PriceBump) + return fmt.Errorf("%w: new tx gas fee cap %v < %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasFeeCap(), prev.execFeeCap, p.config.PriceBump) case tx.GasTipCapIntCmp(minGasTipCap.ToBig()) < 0: - return fmt.Errorf("%w: new tx gas tip cap %v <= %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasTipCap(), prev.execTipCap, p.config.PriceBump) + return fmt.Errorf("%w: new tx gas tip cap %v < %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasTipCap(), prev.execTipCap, p.config.PriceBump) case tx.BlobGasFeeCapIntCmp(minBlobGasFeeCap.ToBig()) < 0: - return fmt.Errorf("%w: new tx blob gas fee cap %v <= %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.BlobGasFeeCap(), prev.blobFeeCap, p.config.PriceBump) + return fmt.Errorf("%w: new tx blob gas fee cap %v < %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.BlobGasFeeCap(), prev.blobFeeCap, p.config.PriceBump) } } return nil From 2b9d19870646140c4dc90645cf7c828cc76860aa Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Wed, 14 Aug 2024 19:45:51 +1000 Subject: [PATCH 464/571] go.mod: upgrade to pebble v1.1.2 (#30297) Includes a fix for MIPS32 support. Pebble release: https://github.com/cockroachdb/pebble/releases/tag/v1.1.2 Key fix for mips32: https://github.com/cockroachdb/pebble/commit/9f3904a705d60b9832febb6c6494183d92c8f556 (also the only change from v1.1.1. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ae6b12c0b8e6..909add8be662 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.3.4 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.79.0 - github.com/cockroachdb/pebble v1.1.1 + github.com/cockroachdb/pebble v1.1.2 github.com/consensys/gnark-crypto v0.12.1 github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c github.com/crate-crypto/go-kzg-4844 v1.0.0 diff --git a/go.sum b/go.sum index 4dadd40a75f0..089c05c2ecb7 100644 --- a/go.sum +++ b/go.sum @@ -122,8 +122,8 @@ github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/e github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= -github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= +github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= +github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= From c686485a062d0addddf40c3808de7fe90793ed18 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 15 Aug 2024 09:16:23 +0200 Subject: [PATCH 465/571] core: only compute state root once (#30299) This PR refactors the genesis initialization a bit, s.th. we only compute the blockhash once instead of twice as before (during hashAlloc and flushAlloc) This will significantly reduce the amount of memory allocated during genesis init --------- Co-authored-by: Gary Rong --- core/genesis.go | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 4ca24807fccd..9e213e5163b0 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -145,13 +145,12 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { return statedb.Commit(0, false) } -// flushAlloc is very similar with hash, but the main difference is all the generated -// states will be persisted into the given database. Also, the genesis state -// specification will be flushed as well. -func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database, blockhash common.Hash) error { +// flushAlloc is very similar with hash, but the main difference is all the +// generated states will be persisted into the given database. +func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database) (common.Hash, error) { statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) if err != nil { - return err + return common.Hash{}, err } for addr, account := range *ga { if account.Balance != nil { @@ -167,21 +166,15 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa } root, err := statedb.Commit(0, false) if err != nil { - return err + return common.Hash{}, err } // Commit newly generated states into disk if it's not empty. if root != types.EmptyRootHash { if err := triedb.Commit(root, true); err != nil { - return err + return common.Hash{}, err } } - // Marshal the genesis state specification and persist. - blob, err := json.Marshal(ga) - if err != nil { - return err - } - rawdb.WriteGenesisStateSpec(db, blockhash, blob) - return nil + return root, nil } func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) { @@ -426,6 +419,11 @@ func (g *Genesis) ToBlock() *types.Block { if err != nil { panic(err) } + return g.toBlockWithRoot(root) +} + +// toBlockWithRoot constructs the genesis block with the given genesis state root. +func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block { head := &types.Header{ Number: new(big.Int).SetUint64(g.Number), Nonce: types.EncodeNonce(g.Nonce), @@ -482,8 +480,7 @@ func (g *Genesis) ToBlock() *types.Block { // Commit writes the block and state of a genesis specification to the database. // The block is committed as the canonical head block. func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) { - block := g.ToBlock() - if block.Number().Sign() != 0 { + if g.Number != 0 { return nil, errors.New("can't commit genesis block with number > 0") } config := g.Config @@ -493,15 +490,22 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo if err := config.CheckConfigForkOrder(); err != nil { return nil, err } - if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength { + if config.Clique != nil && len(g.ExtraData) < 32+crypto.SignatureLength { return nil, errors.New("can't start clique chain without signers") } - // All the checks has passed, flushAlloc the states derived from the genesis - // specification as well as the specification itself into the provided - // database. - if err := flushAlloc(&g.Alloc, db, triedb, block.Hash()); err != nil { + // flush the data to disk and compute the state root + root, err := flushAlloc(&g.Alloc, db, triedb) + if err != nil { + return nil, err + } + block := g.toBlockWithRoot(root) + + // Marshal the genesis state specification and persist. + blob, err := json.Marshal(g.Alloc) + if err != nil { return nil, err } + rawdb.WriteGenesisStateSpec(db, block.Hash(), blob) rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) rawdb.WriteBlock(db, block) rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil) From 2f2e5b088a08ff164fb20f704d04d67ddd6edbf5 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 10:11:03 +0200 Subject: [PATCH 466/571] .golangci.yml: remove lint warning for TxLookupLimit --- .golangci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.golangci.yml b/.golangci.yml index 75452472d026..d3b8535cfb56 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -60,6 +60,8 @@ issues: - path: crypto/bn256/ linters: - revive + - path: cmd/utils/flags.go + text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead." - path: internal/build/pgp.go text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - path: core/vm/contracts.go From c4b01d80b94820abeea52504c661e2a2ca8739d7 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 15 Aug 2024 17:35:16 +0800 Subject: [PATCH 467/571] eth/fetcher: always expect transaction metadata in announcement (#30288) This pull request drops the legacy transaction retrieval support from before eth68, adding the restrictions that transaction metadata must be provided along with the transaction announment. --- eth/fetcher/tx_fetcher.go | 23 +- eth/fetcher/tx_fetcher_test.go | 971 ++++++++++++++++++--------------- 2 files changed, 542 insertions(+), 452 deletions(-) diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 18c5ff007a9f..a113155009e1 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -114,7 +114,7 @@ var errTerminated = errors.New("terminated") type txAnnounce struct { origin string // Identifier of the peer originating the notification hashes []common.Hash // Batch of transaction hashes being announced - metas []*txMetadata // Batch of metadatas associated with the hashes (nil before eth/68) + metas []*txMetadata // Batch of metadata associated with the hashes } // txMetadata is a set of extra data transmitted along the announcement for better @@ -137,7 +137,7 @@ type txRequest struct { type txDelivery struct { origin string // Identifier of the peer originating the notification hashes []common.Hash // Batch of transaction hashes having been delivered - metas []txMetadata // Batch of metadatas associated with the delivered hashes + metas []txMetadata // Batch of metadata associated with the delivered hashes direct bool // Whether this is a direct reply or a broadcast } @@ -260,11 +260,11 @@ func (f *TxFetcher) Notify(peer string, types []byte, sizes []uint32, hashes []c underpriced++ default: unknownHashes = append(unknownHashes, hash) - if types == nil { - unknownMetas = append(unknownMetas, nil) - } else { - unknownMetas = append(unknownMetas, &txMetadata{kind: types[i], size: sizes[i]}) - } + + // Transaction metadata has been available since eth68, and all + // legacy eth protocols (prior to eth68) have been deprecated. + // Therefore, metadata is always expected in the announcement. + unknownMetas = append(unknownMetas, &txMetadata{kind: types[i], size: sizes[i]}) } } txAnnounceKnownMeter.Mark(duplicate) @@ -892,13 +892,8 @@ func (f *TxFetcher) scheduleFetches(timer *mclock.Timer, timeout chan struct{}, if len(hashes) >= maxTxRetrievals { return false // break in the for-each } - if meta != nil { // Only set eth/68 and upwards - bytes += uint64(meta.size) - if bytes >= maxTxRetrievalSize { - return false - } - } - return true // scheduled, try to add more + bytes += uint64(meta.size) + return bytes < maxTxRetrievalSize }) // If any hashes were allocated, request them from the peer if len(hashes) > 0 { diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index 3d3ef81edef6..0b4764666984 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -45,13 +45,10 @@ var ( type announce struct { hash common.Hash - kind *byte - size *uint32 + kind byte + size uint32 } -func typeptr(t byte) *byte { return &t } -func sizeptr(n uint32) *uint32 { return &n } - type doTxNotify struct { peer string hashes []common.Hash @@ -70,16 +67,10 @@ type doWait struct { type doDrop string type doFunc func() -type isWaitingWithMeta map[string][]announce -type isWaiting map[string][]common.Hash +type isWaiting map[string][]announce -type isScheduledWithMeta struct { - tracking map[string][]announce - fetching map[string][]common.Hash - dangling map[string][]common.Hash -} type isScheduled struct { - tracking map[string][]common.Hash + tracking map[string][]announce fetching map[string][]common.Hash dangling map[string][]common.Hash } @@ -92,104 +83,13 @@ type txFetcherTest struct { steps []interface{} } -// Tests that transaction announcements are added to a waitlist, and none -// of them are scheduled for retrieval until the wait expires. -func TestTransactionFetcherWaiting(t *testing.T) { - testTransactionFetcherParallel(t, txFetcherTest{ - init: func() *TxFetcher { - return NewTxFetcher( - func(common.Hash) bool { return false }, - nil, - func(string, []common.Hash) error { return nil }, - nil, - ) - }, - steps: []interface{}{ - // Initial announcement to get something into the waitlist - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - }), - // Announce from a new peer to check that no overwrite happens - doTxNotify{peer: "B", hashes: []common.Hash{{0x03}, {0x04}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - "B": {{0x03}, {0x04}}, - }), - // Announce clashing hashes but unique new peer - doTxNotify{peer: "C", hashes: []common.Hash{{0x01}, {0x04}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}}, - }), - // Announce existing and clashing hashes from existing peer - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x03}, {0x05}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x05}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}}, - }), - isScheduled{tracking: nil, fetching: nil}, - - // Wait for the arrival timeout which should move all expired items - // from the wait list to the scheduler - doWait{time: txArriveTimeout, step: true}, - isWaiting(nil), - isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x05}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}}, - }, - fetching: map[string][]common.Hash{ // Depends on deterministic test randomizer - "A": {{0x02}, {0x03}, {0x05}}, - "C": {{0x01}, {0x04}}, - }, - }, - // Queue up a non-fetchable transaction and then trigger it with a new - // peer (weird case to test 1 line in the fetcher) - doTxNotify{peer: "C", hashes: []common.Hash{{0x06}, {0x07}}}, - isWaiting(map[string][]common.Hash{ - "C": {{0x06}, {0x07}}, - }), - doWait{time: txArriveTimeout, step: true}, - isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x05}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}, {0x06}, {0x07}}, - }, - fetching: map[string][]common.Hash{ - "A": {{0x02}, {0x03}, {0x05}}, - "C": {{0x01}, {0x04}}, - }, - }, - doTxNotify{peer: "D", hashes: []common.Hash{{0x06}, {0x07}}}, - isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x05}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}, {0x06}, {0x07}}, - "D": {{0x06}, {0x07}}, - }, - fetching: map[string][]common.Hash{ - "A": {{0x02}, {0x03}, {0x05}}, - "C": {{0x01}, {0x04}}, - "D": {{0x06}, {0x07}}, - }, - }, - }, - }) -} - // Tests that transaction announcements with associated metadata are added to a // waitlist, and none of them are scheduled for retrieval until the wait expires. // // This test is an extended version of TestTransactionFetcherWaiting. It's mostly // to cover the metadata checks without bloating up the basic behavioral tests // with all the useless extra fields. -func TestTransactionFetcherWaitingWithMeta(t *testing.T) { +func TestTransactionFetcherWaiting(t *testing.T) { testTransactionFetcherParallel(t, txFetcherTest{ init: func() *TxFetcher { return NewTxFetcher( @@ -202,80 +102,80 @@ func TestTransactionFetcherWaitingWithMeta(t *testing.T) { steps: []interface{}{ // Initial announcement to get something into the waitlist doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{111, 222}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, }, }), // Announce from a new peer to check that no overwrite happens doTxNotify{peer: "B", hashes: []common.Hash{{0x03}, {0x04}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{333, 444}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, }), // Announce clashing hashes but unique new peer doTxNotify{peer: "C", hashes: []common.Hash{{0x01}, {0x04}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{111, 444}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, }), // Announce existing and clashing hashes from existing peer. Clashes // should not overwrite previous announcements. doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x03}, {0x05}}, types: []byte{types.LegacyTxType, types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{999, 333, 555}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, }), // Announce clashing hashes with conflicting metadata. Somebody will // be in the wrong, but we don't know yet who. doTxNotify{peer: "D", hashes: []common.Hash{{0x01}, {0x02}}, types: []byte{types.LegacyTxType, types.BlobTxType}, sizes: []uint32{999, 222}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "D": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(999)}, - {common.Hash{0x02}, typeptr(types.BlobTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 999}, + {common.Hash{0x02}, types.BlobTxType, 222}, }, }), isScheduled{tracking: nil, fetching: nil}, @@ -284,25 +184,25 @@ func TestTransactionFetcherWaitingWithMeta(t *testing.T) { // from the wait list to the scheduler doWait{time: txArriveTimeout, step: true}, isWaiting(nil), - isScheduledWithMeta{ + isScheduled{ tracking: map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "D": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(999)}, - {common.Hash{0x02}, typeptr(types.BlobTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 999}, + {common.Hash{0x02}, types.BlobTxType, 222}, }, }, fetching: map[string][]common.Hash{ // Depends on deterministic test randomizer @@ -314,34 +214,34 @@ func TestTransactionFetcherWaitingWithMeta(t *testing.T) { // Queue up a non-fetchable transaction and then trigger it with a new // peer (weird case to test 1 line in the fetcher) doTxNotify{peer: "C", hashes: []common.Hash{{0x06}, {0x07}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{666, 777}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "C": { - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(666)}, - {common.Hash{0x07}, typeptr(types.LegacyTxType), sizeptr(777)}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + {common.Hash{0x07}, types.LegacyTxType, 777}, }, }), doWait{time: txArriveTimeout, step: true}, - isScheduledWithMeta{ + isScheduled{ tracking: map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(666)}, - {common.Hash{0x07}, typeptr(types.LegacyTxType), sizeptr(777)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + {common.Hash{0x07}, types.LegacyTxType, 777}, }, "D": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(999)}, - {common.Hash{0x02}, typeptr(types.BlobTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 999}, + {common.Hash{0x02}, types.BlobTxType, 222}, }, }, fetching: map[string][]common.Hash{ @@ -351,31 +251,31 @@ func TestTransactionFetcherWaitingWithMeta(t *testing.T) { }, }, doTxNotify{peer: "E", hashes: []common.Hash{{0x06}, {0x07}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{666, 777}}, - isScheduledWithMeta{ + isScheduled{ tracking: map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(666)}, - {common.Hash{0x07}, typeptr(types.LegacyTxType), sizeptr(777)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + {common.Hash{0x07}, types.LegacyTxType, 777}, }, "D": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(999)}, - {common.Hash{0x02}, typeptr(types.BlobTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 999}, + {common.Hash{0x02}, types.BlobTxType, 222}, }, "E": { - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(666)}, - {common.Hash{0x07}, typeptr(types.LegacyTxType), sizeptr(777)}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + {common.Hash{0x07}, types.LegacyTxType, 777}, }, }, fetching: map[string][]common.Hash{ @@ -403,17 +303,28 @@ func TestTransactionFetcherSkipWaiting(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{{0x01}, {0x02}}, + types: []byte{types.LegacyTxType, types.LegacyTxType}, + sizes: []uint32{111, 222}, + }, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -421,13 +332,18 @@ func TestTransactionFetcherSkipWaiting(t *testing.T) { }, // Announce overlaps from the same peer, ensure the new ones end up // in stage one, and clashing ones don't get double tracked - doTxNotify{peer: "A", hashes: []common.Hash{{0x02}, {0x03}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x03}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x02}, {0x03}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{222, 333}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -435,15 +351,25 @@ func TestTransactionFetcherSkipWaiting(t *testing.T) { }, // Announce overlaps from a new peer, ensure new transactions end up // in stage one and clashing ones get tracked for the new peer - doTxNotify{peer: "B", hashes: []common.Hash{{0x02}, {0x03}, {0x04}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x03}}, - "B": {{0x03}, {0x04}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x02}, {0x03}, {0x04}}, types: []byte{types.LegacyTxType, types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{222, 333, 444}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + }, + "B": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - "B": {{0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -467,17 +393,23 @@ func TestTransactionFetcherSingletonRequesting(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{111, 222}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -485,13 +417,19 @@ func TestTransactionFetcherSingletonRequesting(t *testing.T) { }, // Announce a new set of transactions from the same peer and ensure // they do not start fetching since the peer is already busy - doTxNotify{peer: "A", hashes: []common.Hash{{0x03}, {0x04}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x03}, {0x04}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x03}, {0x04}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{333, 444}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -500,8 +438,13 @@ func TestTransactionFetcherSingletonRequesting(t *testing.T) { doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x04}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -509,14 +452,25 @@ func TestTransactionFetcherSingletonRequesting(t *testing.T) { }, // Announce a duplicate set of transactions from a new peer and ensure // uniquely new ones start downloading, even if clashing. - doTxNotify{peer: "B", hashes: []common.Hash{{0x02}, {0x03}, {0x05}, {0x06}}}, - isWaiting(map[string][]common.Hash{ - "B": {{0x05}, {0x06}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x02}, {0x03}, {0x05}, {0x06}}, types: []byte{types.LegacyTxType, types.LegacyTxType, types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{222, 333, 555, 666}}, + isWaiting(map[string][]announce{ + "B": { + {common.Hash{0x05}, types.LegacyTxType, 555}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x04}}, - "B": {{0x02}, {0x03}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + }, + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -547,17 +501,23 @@ func TestTransactionFetcherFailedRescheduling(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{111, 222}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -565,12 +525,17 @@ func TestTransactionFetcherFailedRescheduling(t *testing.T) { }, // While the original peer is stuck in the request, push in an second // data source. - doTxNotify{peer: "B", hashes: []common.Hash{{0x02}}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x02}}, types: []byte{types.LegacyTxType}, sizes: []uint32{222}}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - "B": {{0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -584,8 +549,10 @@ func TestTransactionFetcherFailedRescheduling(t *testing.T) { doWait{time: 0, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "B": {{0x02}}, + tracking: map[string][]announce{ + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "B": {{0x02}}, @@ -617,17 +584,21 @@ func TestTransactionFetcherCleanup(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -657,17 +628,21 @@ func TestTransactionFetcherCleanupEmpty(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -696,17 +671,29 @@ func TestTransactionFetcherMissingRescheduling(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, + doTxNotify{peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type(), testTxs[2].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size()), uint32(testTxs[2].Size())}, + }, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, @@ -716,8 +703,10 @@ func TestTransactionFetcherMissingRescheduling(t *testing.T) { // should be dropped and the one after re-requested. doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}, direct: true}, // This depends on the deterministic random isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[2]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[2]}, @@ -743,17 +732,27 @@ func TestTransactionFetcherMissingCleanup(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1]}, + doTxNotify{peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}, + }, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0], testTxsHashes[1]}, @@ -782,18 +781,23 @@ func TestTransactionFetcherBroadcasts(t *testing.T) { }, steps: []interface{}{ // Set up three transactions to be in different stats, waiting, queued and fetching - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}, types: []byte{testTxs[1].Type()}, sizes: []uint32{uint32(testTxs[1].Size())}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[2]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[2]}, types: []byte{testTxs[2].Type()}, sizes: []uint32{uint32(testTxs[2].Size())}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[2]}, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -830,29 +834,40 @@ func TestTransactionFetcherWaitTimerResets(t *testing.T) { ) }, steps: []interface{}{ - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + }, }), isScheduled{nil, nil, nil}, doWait{time: txArriveTimeout / 2, step: false}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + }, }), isScheduled{nil, nil, nil}, - doTxNotify{peer: "A", hashes: []common.Hash{{0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x02}}, types: []byte{types.LegacyTxType}, sizes: []uint32{222}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{nil, nil, nil}, doWait{time: txArriveTimeout / 2, step: true}, - isWaiting(map[string][]common.Hash{ - "A": {{0x02}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -862,8 +877,11 @@ func TestTransactionFetcherWaitTimerResets(t *testing.T) { doWait{time: txArriveTimeout / 2, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -889,17 +907,22 @@ func TestTransactionFetcherTimeoutRescheduling(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{testTxsHashes[0]}, + types: []byte{testTxs[0].Type()}, + sizes: []uint32{uint32(testTxs[0].Size())}, + }, + isWaiting(map[string][]announce{ + "A": {{testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}}, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + tracking: map[string][]announce{ + "A": {{testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}}, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -916,11 +939,16 @@ func TestTransactionFetcherTimeoutRescheduling(t *testing.T) { }, }, // Ensure that followup announcements don't get scheduled - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{testTxsHashes[1]}, + types: []byte{testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[1].Size())}, + }, doWait{time: txArriveTimeout, step: true}, isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": {{testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}}, }, fetching: nil, dangling: map[string][]common.Hash{ @@ -931,8 +959,8 @@ func TestTransactionFetcherTimeoutRescheduling(t *testing.T) { doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}, direct: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": {{testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}}, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[1]}, @@ -954,16 +982,20 @@ func TestTransactionFetcherTimeoutTimerResets(t *testing.T) { ) }, steps: []interface{}{ - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "B", hashes: []common.Hash{{0x02}}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x02}}, types: []byte{types.LegacyTxType}, sizes: []uint32{222}}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}}, - "B": {{0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + }, + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -972,8 +1004,10 @@ func TestTransactionFetcherTimeoutTimerResets(t *testing.T) { }, doWait{time: txFetchTimeout - txArriveTimeout, step: true}, isScheduled{ - tracking: map[string][]common.Hash{ - "B": {{0x02}}, + tracking: map[string][]announce{ + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "B": {{0x02}}, @@ -999,9 +1033,22 @@ func TestTransactionFetcherTimeoutTimerResets(t *testing.T) { // number of them will be requested at a time. func TestTransactionFetcherRateLimiting(t *testing.T) { // Create a slew of transactions and announce them - var hashes []common.Hash + var ( + hashes []common.Hash + ts []byte + sizes []uint32 + announces []announce + ) for i := 0; i < maxTxAnnounces; i++ { - hashes = append(hashes, common.Hash{byte(i / 256), byte(i % 256)}) + hash := common.Hash{byte(i / 256), byte(i % 256)} + hashes = append(hashes, hash) + ts = append(ts, types.LegacyTxType) + sizes = append(sizes, 111) + announces = append(announces, announce{ + hash: hash, + kind: types.LegacyTxType, + size: 111, + }) } testTransactionFetcherParallel(t, txFetcherTest{ init: func() *TxFetcher { @@ -1015,12 +1062,12 @@ func TestTransactionFetcherRateLimiting(t *testing.T) { steps: []interface{}{ // Announce all the transactions, wait a bit and ensure only a small // percentage gets requested - doTxNotify{peer: "A", hashes: hashes}, + doTxNotify{peer: "A", hashes: hashes, types: ts, sizes: sizes}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": hashes, + tracking: map[string][]announce{ + "A": announces, }, fetching: map[string][]common.Hash{ "A": hashes[1643 : 1643+maxTxRetrievals], @@ -1065,21 +1112,21 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) { }, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), - isScheduledWithMeta{ + isScheduled{ tracking: map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, + {common.Hash{0x01}, types.LegacyTxType, 48 * 1024}, + {common.Hash{0x02}, types.LegacyTxType, 48 * 1024}, + {common.Hash{0x03}, types.LegacyTxType, 48 * 1024}, + {common.Hash{0x04}, types.LegacyTxType, 48 * 1024}, }, "B": { - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(maxTxRetrievalSize)}, - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(maxTxRetrievalSize)}, + {common.Hash{0x05}, types.LegacyTxType, maxTxRetrievalSize}, + {common.Hash{0x06}, types.LegacyTxType, maxTxRetrievalSize}, }, "C": { - {common.Hash{0x07}, typeptr(types.BlobTxType), sizeptr(params.MaxBlobGasPerBlock)}, - {common.Hash{0x08}, typeptr(types.BlobTxType), sizeptr(params.MaxBlobGasPerBlock)}, + {common.Hash{0x07}, types.BlobTxType, params.MaxBlobGasPerBlock}, + {common.Hash{0x08}, types.BlobTxType, params.MaxBlobGasPerBlock}, }, }, fetching: map[string][]common.Hash{ @@ -1096,13 +1143,41 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) { // request at the same time is hard capped. func TestTransactionFetcherDoSProtection(t *testing.T) { // Create a slew of transactions and to announce them - var hashesA []common.Hash + var ( + hashesA []common.Hash + typesA []byte + sizesA []uint32 + announceA []announce + ) for i := 0; i < maxTxAnnounces+1; i++ { - hashesA = append(hashesA, common.Hash{0x01, byte(i / 256), byte(i % 256)}) + hash := common.Hash{0x01, byte(i / 256), byte(i % 256)} + hashesA = append(hashesA, hash) + typesA = append(typesA, types.LegacyTxType) + sizesA = append(sizesA, 111) + + announceA = append(announceA, announce{ + hash: hash, + kind: types.LegacyTxType, + size: 111, + }) } - var hashesB []common.Hash + var ( + hashesB []common.Hash + typesB []byte + sizesB []uint32 + announceB []announce + ) for i := 0; i < maxTxAnnounces+1; i++ { - hashesB = append(hashesB, common.Hash{0x02, byte(i / 256), byte(i % 256)}) + hash := common.Hash{0x02, byte(i / 256), byte(i % 256)} + hashesB = append(hashesB, hash) + typesB = append(typesB, types.LegacyTxType) + sizesB = append(sizesB, 111) + + announceB = append(announceB, announce{ + hash: hash, + kind: types.LegacyTxType, + size: 111, + }) } testTransactionFetcherParallel(t, txFetcherTest{ init: func() *TxFetcher { @@ -1115,23 +1190,23 @@ func TestTransactionFetcherDoSProtection(t *testing.T) { }, steps: []interface{}{ // Announce half of the transaction and wait for them to be scheduled - doTxNotify{peer: "A", hashes: hashesA[:maxTxAnnounces/2]}, - doTxNotify{peer: "B", hashes: hashesB[:maxTxAnnounces/2-1]}, + doTxNotify{peer: "A", hashes: hashesA[:maxTxAnnounces/2], types: typesA[:maxTxAnnounces/2], sizes: sizesA[:maxTxAnnounces/2]}, + doTxNotify{peer: "B", hashes: hashesB[:maxTxAnnounces/2-1], types: typesB[:maxTxAnnounces/2-1], sizes: sizesB[:maxTxAnnounces/2-1]}, doWait{time: txArriveTimeout, step: true}, // Announce the second half and keep them in the wait list - doTxNotify{peer: "A", hashes: hashesA[maxTxAnnounces/2 : maxTxAnnounces]}, - doTxNotify{peer: "B", hashes: hashesB[maxTxAnnounces/2-1 : maxTxAnnounces-1]}, + doTxNotify{peer: "A", hashes: hashesA[maxTxAnnounces/2 : maxTxAnnounces], types: typesA[maxTxAnnounces/2 : maxTxAnnounces], sizes: sizesA[maxTxAnnounces/2 : maxTxAnnounces]}, + doTxNotify{peer: "B", hashes: hashesB[maxTxAnnounces/2-1 : maxTxAnnounces-1], types: typesB[maxTxAnnounces/2-1 : maxTxAnnounces-1], sizes: sizesB[maxTxAnnounces/2-1 : maxTxAnnounces-1]}, // Ensure the hashes are split half and half - isWaiting(map[string][]common.Hash{ - "A": hashesA[maxTxAnnounces/2 : maxTxAnnounces], - "B": hashesB[maxTxAnnounces/2-1 : maxTxAnnounces-1], + isWaiting(map[string][]announce{ + "A": announceA[maxTxAnnounces/2 : maxTxAnnounces], + "B": announceB[maxTxAnnounces/2-1 : maxTxAnnounces-1], }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": hashesA[:maxTxAnnounces/2], - "B": hashesB[:maxTxAnnounces/2-1], + tracking: map[string][]announce{ + "A": announceA[:maxTxAnnounces/2], + "B": announceB[:maxTxAnnounces/2-1], }, fetching: map[string][]common.Hash{ "A": hashesA[1643 : 1643+maxTxRetrievals], @@ -1139,17 +1214,17 @@ func TestTransactionFetcherDoSProtection(t *testing.T) { }, }, // Ensure that adding even one more hash results in dropping the hash - doTxNotify{peer: "A", hashes: []common.Hash{hashesA[maxTxAnnounces]}}, - doTxNotify{peer: "B", hashes: hashesB[maxTxAnnounces-1 : maxTxAnnounces+1]}, + doTxNotify{peer: "A", hashes: []common.Hash{hashesA[maxTxAnnounces]}, types: []byte{typesA[maxTxAnnounces]}, sizes: []uint32{sizesA[maxTxAnnounces]}}, + doTxNotify{peer: "B", hashes: hashesB[maxTxAnnounces-1 : maxTxAnnounces+1], types: typesB[maxTxAnnounces-1 : maxTxAnnounces+1], sizes: sizesB[maxTxAnnounces-1 : maxTxAnnounces+1]}, - isWaiting(map[string][]common.Hash{ - "A": hashesA[maxTxAnnounces/2 : maxTxAnnounces], - "B": hashesB[maxTxAnnounces/2-1 : maxTxAnnounces], + isWaiting(map[string][]announce{ + "A": announceA[maxTxAnnounces/2 : maxTxAnnounces], + "B": announceB[maxTxAnnounces/2-1 : maxTxAnnounces], }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": hashesA[:maxTxAnnounces/2], - "B": hashesB[:maxTxAnnounces/2-1], + tracking: map[string][]announce{ + "A": announceA[:maxTxAnnounces/2], + "B": announceB[:maxTxAnnounces/2-1], }, fetching: map[string][]common.Hash{ "A": hashesA[1643 : 1643+maxTxRetrievals], @@ -1183,15 +1258,23 @@ func TestTransactionFetcherUnderpricedDedup(t *testing.T) { }, steps: []interface{}{ // Deliver a transaction through the fetcher, but reject as underpriced - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}}, + doTxNotify{peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}, + }, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0], testTxs[1]}, direct: true}, isScheduled{nil, nil, nil}, // Try to announce the transaction again, ensure it's not scheduled back - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}}, // [2] is needed to force a step in the fetcher - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[2]}, + doTxNotify{peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type(), testTxs[2].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size()), uint32(testTxs[2].Size())}, + }, // [2] is needed to force a step in the fetcher + isWaiting(map[string][]announce{ + "A": {{testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}}, }), isScheduled{nil, nil, nil}, }, @@ -1211,21 +1294,38 @@ func TestTransactionFetcherUnderpricedDoSProtection(t *testing.T) { for i := 0; i < maxTxUnderpricedSetSize+1; i++ { txs = append(txs, types.NewTransaction(rand.Uint64(), common.Address{byte(rand.Intn(256))}, new(big.Int), 0, new(big.Int), nil)) } - hashes := make([]common.Hash, len(txs)) - for i, tx := range txs { - hashes[i] = tx.Hash() + var ( + hashes []common.Hash + ts []byte + sizes []uint32 + annos []announce + ) + for _, tx := range txs { + hashes = append(hashes, tx.Hash()) + ts = append(ts, tx.Type()) + sizes = append(sizes, uint32(tx.Size())) + annos = append(annos, announce{ + hash: tx.Hash(), + kind: tx.Type(), + size: uint32(tx.Size()), + }) } // Generate a set of steps to announce and deliver the entire set of transactions var steps []interface{} for i := 0; i < maxTxUnderpricedSetSize/maxTxRetrievals; i++ { - steps = append(steps, doTxNotify{peer: "A", hashes: hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals]}) - steps = append(steps, isWaiting(map[string][]common.Hash{ - "A": hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + steps = append(steps, doTxNotify{ + peer: "A", + hashes: hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + types: ts[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + sizes: sizes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + }) + steps = append(steps, isWaiting(map[string][]announce{ + "A": annos[i*maxTxRetrievals : (i+1)*maxTxRetrievals], })) steps = append(steps, doWait{time: txArriveTimeout, step: true}) steps = append(steps, isScheduled{ - tracking: map[string][]common.Hash{ - "A": hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + tracking: map[string][]announce{ + "A": annos[i*maxTxRetrievals : (i+1)*maxTxRetrievals], }, fetching: map[string][]common.Hash{ "A": hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], @@ -1253,7 +1353,12 @@ func TestTransactionFetcherUnderpricedDoSProtection(t *testing.T) { }, steps: append(steps, []interface{}{ // The preparation of the test has already been done in `steps`, add the last check - doTxNotify{peer: "A", hashes: []common.Hash{hashes[maxTxUnderpricedSetSize]}}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{hashes[maxTxUnderpricedSetSize]}, + types: []byte{ts[maxTxUnderpricedSetSize]}, + sizes: []uint32{sizes[maxTxUnderpricedSetSize]}, + }, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{txs[maxTxUnderpricedSetSize]}, direct: true}, isUnderpriced(maxTxUnderpricedSetSize), @@ -1283,18 +1388,23 @@ func TestTransactionFetcherOutOfBoundDeliveries(t *testing.T) { isScheduled{nil, nil, nil}, // Set up a few hashes into various stages - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}, types: []byte{testTxs[1].Type()}, sizes: []uint32{uint32(testTxs[1].Size())}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[2]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[2]}, types: []byte{testTxs[2].Type()}, sizes: []uint32{uint32(testTxs[2].Size())}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[2]}, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -1330,18 +1440,23 @@ func TestTransactionFetcherDrop(t *testing.T) { }, steps: []interface{}{ // Set up a few hashes into various stages - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{{0x02}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x02}}, types: []byte{types.LegacyTxType}, sizes: []uint32{222}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{{0x03}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x03}}, types: []byte{types.LegacyTxType}, sizes: []uint32{333}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x03}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -1353,12 +1468,14 @@ func TestTransactionFetcherDrop(t *testing.T) { isScheduled{nil, nil, nil}, // Push the node into a dangling (timeout) state - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -1397,15 +1514,15 @@ func TestTransactionFetcherDropRescheduling(t *testing.T) { }, steps: []interface{}{ // Set up a few hashes into various stages - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "B", hashes: []common.Hash{{0x01}}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}}, - "B": {{0x01}}, + tracking: map[string][]announce{ + "A": {{common.Hash{0x01}, types.LegacyTxType, 111}}, + "B": {{common.Hash{0x01}, types.LegacyTxType, 111}}, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -1415,8 +1532,8 @@ func TestTransactionFetcherDropRescheduling(t *testing.T) { doDrop("A"), isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "B": {{0x01}}, + tracking: map[string][]announce{ + "B": {{common.Hash{0x01}, types.LegacyTxType, 111}}, }, fetching: map[string][]common.Hash{ "B": {{0x01}}, @@ -1443,42 +1560,57 @@ func TestInvalidAnnounceMetadata(t *testing.T) { }, steps: []interface{}{ // Initial announcement to get something into the waitlist - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, types: []byte{testTxs[0].Type(), testTxs[1].Type()}, sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}}, - isWaitingWithMeta(map[string][]announce{ + doTxNotify{ + peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}, + }, + isWaiting(map[string][]announce{ "A": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(uint32(testTxs[0].Size()))}, - {testTxsHashes[1], typeptr(testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, }, }), // Announce from new peers conflicting transactions - doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{1024 + uint32(testTxs[0].Size())}}, - doTxNotify{peer: "C", hashes: []common.Hash{testTxsHashes[1]}, types: []byte{1 + testTxs[1].Type()}, sizes: []uint32{uint32(testTxs[1].Size())}}, - isWaitingWithMeta(map[string][]announce{ + doTxNotify{ + peer: "B", + hashes: []common.Hash{testTxsHashes[0]}, + types: []byte{testTxs[0].Type()}, + sizes: []uint32{1024 + uint32(testTxs[0].Size())}, + }, + doTxNotify{ + peer: "C", + hashes: []common.Hash{testTxsHashes[1]}, + types: []byte{1 + testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[1].Size())}, + }, + isWaiting(map[string][]announce{ "A": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(uint32(testTxs[0].Size()))}, - {testTxsHashes[1], typeptr(testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, }, "B": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(1024 + uint32(testTxs[0].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), 1024 + uint32(testTxs[0].Size())}, }, "C": { - {testTxsHashes[1], typeptr(1 + testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[1], 1 + testTxs[1].Type(), uint32(testTxs[1].Size())}, }, }), // Schedule all the transactions for retrieval doWait{time: txArriveTimeout, step: true}, - isWaitingWithMeta(nil), - isScheduledWithMeta{ + isWaiting(nil), + isScheduled{ tracking: map[string][]announce{ "A": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(uint32(testTxs[0].Size()))}, - {testTxsHashes[1], typeptr(testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, }, "B": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(1024 + uint32(testTxs[0].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), 1024 + uint32(testTxs[0].Size())}, }, "C": { - {testTxsHashes[1], typeptr(1 + testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[1], 1 + testTxs[1].Type(), uint32(testTxs[1].Size())}, }, }, fetching: map[string][]common.Hash{ @@ -1511,12 +1643,12 @@ func TestTransactionFetcherFuzzCrash01(t *testing.T) { }, steps: []interface{}{ // Get a transaction into fetching mode and make it dangling with a broadcast - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}}, // Notify the dangling transaction once more and crash via a timeout - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txFetchTimeout, step: true}, }, }) @@ -1539,12 +1671,12 @@ func TestTransactionFetcherFuzzCrash02(t *testing.T) { }, steps: []interface{}{ // Get a transaction into fetching mode and make it dangling with a broadcast - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}}, // Notify the dangling transaction once more, re-fetch, and crash via a drop and timeout - doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doDrop("A"), doWait{time: txFetchTimeout, step: true}, @@ -1569,12 +1701,17 @@ func TestTransactionFetcherFuzzCrash03(t *testing.T) { }, steps: []interface{}{ // Get a transaction into fetching mode and make it dangling with a broadcast - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}, + }, doWait{time: txFetchTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0], testTxs[1]}}, // Notify the dangling transaction once more, partially deliver, clash&crash with a timeout - doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[1]}, direct: true}, @@ -1606,12 +1743,12 @@ func TestTransactionFetcherFuzzCrash04(t *testing.T) { }, steps: []interface{}{ // Get a transaction into fetching mode and make it dangling with a broadcast - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}}, // Notify the dangling transaction once more, re-fetch, and crash via an in-flight disconnect - doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doFunc(func() { proceed <- struct{}{} // Allow peer A to return the failure @@ -1652,30 +1789,6 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { // Crunch through all the test steps and execute them for i, step := range tt.steps { - // Auto-expand certain steps to ones with metadata - switch old := step.(type) { - case isWaiting: - new := make(isWaitingWithMeta) - for peer, hashes := range old { - for _, hash := range hashes { - new[peer] = append(new[peer], announce{hash, nil, nil}) - } - } - step = new - - case isScheduled: - new := isScheduledWithMeta{ - tracking: make(map[string][]announce), - fetching: old.fetching, - dangling: old.dangling, - } - for peer, hashes := range old.tracking { - for _, hash := range hashes { - new.tracking[peer] = append(new.tracking[peer], announce{hash, nil, nil}) - } - } - step = new - } // Process the original or expanded steps switch step := step.(type) { case doTxNotify: @@ -1710,7 +1823,7 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { case doFunc: step() - case isWaitingWithMeta: + case isWaiting: // We need to check that the waiting list (stage 1) internals // match with the expected set. Check the peer->hash mappings // first. @@ -1724,18 +1837,13 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { if meta, ok := waiting[ann.hash]; !ok { t.Errorf("step %d, peer %s: hash %x missing from waitslots", i, peer, ann.hash) } else { - if (meta == nil && (ann.kind != nil || ann.size != nil)) || - (meta != nil && (ann.kind == nil || ann.size == nil)) || - (meta != nil && (meta.kind != *ann.kind || meta.size != *ann.size)) { - t.Errorf("step %d, peer %s, hash %x: waitslot metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, *ann.kind, *ann.size) + if meta.kind != ann.kind || meta.size != ann.size { + t.Errorf("step %d, peer %s, hash %x: waitslot metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, ann.kind, ann.size) } } } for hash, meta := range waiting { - ann := announce{hash: hash} - if meta != nil { - ann.kind, ann.size = &meta.kind, &meta.size - } + ann := announce{hash: hash, kind: meta.kind, size: meta.size} if !containsAnnounce(announces, ann) { t.Errorf("step %d, peer %s: announce %v extra in waitslots", i, peer, ann) } @@ -1780,7 +1888,7 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { } } - case isScheduledWithMeta: + case isScheduled: // Check that all scheduled announces are accounted for and no // extra ones are present. for peer, announces := range step.tracking { @@ -1793,18 +1901,13 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { if meta, ok := scheduled[ann.hash]; !ok { t.Errorf("step %d, peer %s: hash %x missing from announces", i, peer, ann.hash) } else { - if (meta == nil && (ann.kind != nil || ann.size != nil)) || - (meta != nil && (ann.kind == nil || ann.size == nil)) || - (meta != nil && (meta.kind != *ann.kind || meta.size != *ann.size)) { - t.Errorf("step %d, peer %s, hash %x: announce metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, *ann.kind, *ann.size) + if meta.kind != ann.kind || meta.size != ann.size { + t.Errorf("step %d, peer %s, hash %x: announce metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, ann.kind, ann.size) } } } for hash, meta := range scheduled { - ann := announce{hash: hash} - if meta != nil { - ann.kind, ann.size = &meta.kind, &meta.size - } + ann := announce{hash: hash, kind: meta.kind, size: meta.size} if !containsAnnounce(announces, ann) { t.Errorf("step %d, peer %s: announce %x extra in announces", i, peer, hash) } @@ -1954,18 +2057,10 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { func containsAnnounce(slice []announce, ann announce) bool { for _, have := range slice { if have.hash == ann.hash { - if have.kind == nil || ann.kind == nil { - if have.kind != ann.kind { - return false - } - } else if *have.kind != *ann.kind { + if have.kind != ann.kind { return false } - if have.size == nil || ann.size == nil { - if have.size != ann.size { - return false - } - } else if *have.size != *ann.size { + if have.size != ann.size { return false } return true From c35684709c8c71da78d5abbc6c38a501dd05b58a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 11:42:39 +0200 Subject: [PATCH 468/571] eth/ethconfig: remove LES server config (#30298) --- .golangci.yml | 2 ++ cmd/geth/config.go | 32 +++++++++++++++----------------- cmd/utils/flags_legacy.go | 4 ---- eth/backend.go | 12 ++---------- eth/ethconfig/config.go | 15 ++++----------- eth/ethconfig/gen_config.go | 36 ------------------------------------ 6 files changed, 23 insertions(+), 78 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index d3b8535cfb56..adb59f318f21 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -62,6 +62,8 @@ issues: - revive - path: cmd/utils/flags.go text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead." + - path: cmd/utils/flags.go + text: "SA1019: ethconfig.Defaults.TxLookupLimit is deprecated: use 'TransactionHistory' instead." - path: internal/build/pgp.go text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - path: core/vm/contracts.go diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 522e5e22f2a9..fd57ff40def4 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -75,8 +75,8 @@ var tomlSettings = toml.Config{ }, MissingField: func(rt reflect.Type, field string) error { id := fmt.Sprintf("%s.%s", rt.String(), field) - if deprecated(id) { - log.Warn("Config field is deprecated and won't have an effect", "name", id) + if deprecatedConfigFields[id] { + log.Warn(fmt.Sprintf("Config field '%s' is deprecated and won't have any effect.", id)) return nil } var link string @@ -87,6 +87,19 @@ var tomlSettings = toml.Config{ }, } +var deprecatedConfigFields = map[string]bool{ + "ethconfig.Config.EVMInterpreter": true, + "ethconfig.Config.EWASMInterpreter": true, + "ethconfig.Config.TrieCleanCacheJournal": true, + "ethconfig.Config.TrieCleanCacheRejournal": true, + "ethconfig.Config.LightServ": true, + "ethconfig.Config.LightIngress": true, + "ethconfig.Config.LightEgress": true, + "ethconfig.Config.LightPeers": true, + "ethconfig.Config.LightNoPrune": true, + "ethconfig.Config.LightNoSyncServe": true, +} + type ethstatsConfig struct { URL string `toml:",omitempty"` } @@ -314,21 +327,6 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) { } } -func deprecated(field string) bool { - switch field { - case "ethconfig.Config.EVMInterpreter": - return true - case "ethconfig.Config.EWASMInterpreter": - return true - case "ethconfig.Config.TrieCleanCacheJournal": - return true - case "ethconfig.Config.TrieCleanCacheRejournal": - return true - default: - return false - } -} - func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error { scryptN := keystore.StandardScryptN scryptP := keystore.StandardScryptP diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go index 1dfd1a5f8934..f145f605d6aa 100644 --- a/cmd/utils/flags_legacy.go +++ b/cmd/utils/flags_legacy.go @@ -92,25 +92,21 @@ var ( LightServeFlag = &cli.IntFlag{ Name: "light.serve", Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)", - Value: ethconfig.Defaults.LightServ, Category: flags.DeprecatedCategory, } LightIngressFlag = &cli.IntFlag{ Name: "light.ingress", Usage: "Incoming bandwidth limit for serving light clients (deprecated)", - Value: ethconfig.Defaults.LightIngress, Category: flags.DeprecatedCategory, } LightEgressFlag = &cli.IntFlag{ Name: "light.egress", Usage: "Outgoing bandwidth limit for serving light clients (deprecated)", - Value: ethconfig.Defaults.LightEgress, Category: flags.DeprecatedCategory, } LightMaxPeersFlag = &cli.IntFlag{ Name: "light.maxpeers", Usage: "Maximum number of light clients to serve, or light servers to attach to (deprecated)", - Value: ethconfig.Defaults.LightPeers, Category: flags.DeprecatedCategory, } LightNoPruneFlag = &cli.BoolFlag{ diff --git a/eth/backend.go b/eth/backend.go index 8679018dabfc..442d408bb00d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -377,16 +377,8 @@ func (s *Ethereum) Start() error { // Regularly update shutdown marker s.shutdownTracker.Start() - // Figure out a max peers count based on the server limits - maxPeers := s.p2pServer.MaxPeers - if s.config.LightServ > 0 { - if s.config.LightPeers >= s.p2pServer.MaxPeers { - return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers) - } - maxPeers -= s.config.LightPeers - } - // Start the networking layer and the light server if requested - s.handler.Start(maxPeers) + // Start the networking layer + s.handler.Start(s.p2pServer.MaxPeers) return nil } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 7453fb1efdd3..5a955d9bbfc3 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -53,7 +53,6 @@ var Defaults = Config{ TxLookupLimit: 2350000, TransactionHistory: 2350000, StateHistory: params.FullImmutabilityThreshold, - LightPeers: 100, DatabaseCache: 512, TrieCleanCache: 154, TrieDirtyCache: 256, @@ -87,11 +86,13 @@ type Config struct { EthDiscoveryURLs []string SnapDiscoveryURLs []string + // State options. NoPruning bool // Whether to disable pruning and flush everything to disk NoPrefetch bool // Whether to disable prefetching and only load state on demand - // Deprecated, use 'TransactionHistory' instead. - TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. + // Deprecated: use 'TransactionHistory' instead. + TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. + TransactionHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. StateHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose state histories are reserved. @@ -105,14 +106,6 @@ type Config struct { // presence of these blocks for every new peer connection. RequiredBlocks map[uint64]common.Hash `toml:"-"` - // Light client options - LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests - LightIngress int `toml:",omitempty"` // Incoming bandwidth limit for light servers - LightEgress int `toml:",omitempty"` // Outgoing bandwidth limit for light servers - LightPeers int `toml:",omitempty"` // Maximum number of LES client peers - LightNoPrune bool `toml:",omitempty"` // Whether to disable light chain pruning - LightNoSyncServe bool `toml:",omitempty"` // Whether to serve light clients before syncing - // Database options SkipBcVersionCheck bool `toml:"-"` DatabaseHandles int `toml:"-"` diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 147a5599848b..2854c870975c 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -29,12 +29,6 @@ func (c Config) MarshalTOML() (interface{}, error) { StateHistory uint64 `toml:",omitempty"` StateScheme string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` - LightServ int `toml:",omitempty"` - LightIngress int `toml:",omitempty"` - LightEgress int `toml:",omitempty"` - LightPeers int `toml:",omitempty"` - LightNoPrune bool `toml:",omitempty"` - LightNoSyncServe bool `toml:",omitempty"` SkipBcVersionCheck bool `toml:"-"` DatabaseHandles int `toml:"-"` DatabaseCache int @@ -73,12 +67,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.StateHistory = c.StateHistory enc.StateScheme = c.StateScheme enc.RequiredBlocks = c.RequiredBlocks - enc.LightServ = c.LightServ - enc.LightIngress = c.LightIngress - enc.LightEgress = c.LightEgress - enc.LightPeers = c.LightPeers - enc.LightNoPrune = c.LightNoPrune - enc.LightNoSyncServe = c.LightNoSyncServe enc.SkipBcVersionCheck = c.SkipBcVersionCheck enc.DatabaseHandles = c.DatabaseHandles enc.DatabaseCache = c.DatabaseCache @@ -121,12 +109,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { StateHistory *uint64 `toml:",omitempty"` StateScheme *string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` - LightServ *int `toml:",omitempty"` - LightIngress *int `toml:",omitempty"` - LightEgress *int `toml:",omitempty"` - LightPeers *int `toml:",omitempty"` - LightNoPrune *bool `toml:",omitempty"` - LightNoSyncServe *bool `toml:",omitempty"` SkipBcVersionCheck *bool `toml:"-"` DatabaseHandles *int `toml:"-"` DatabaseCache *int @@ -192,24 +174,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.RequiredBlocks != nil { c.RequiredBlocks = dec.RequiredBlocks } - if dec.LightServ != nil { - c.LightServ = *dec.LightServ - } - if dec.LightIngress != nil { - c.LightIngress = *dec.LightIngress - } - if dec.LightEgress != nil { - c.LightEgress = *dec.LightEgress - } - if dec.LightPeers != nil { - c.LightPeers = *dec.LightPeers - } - if dec.LightNoPrune != nil { - c.LightNoPrune = *dec.LightNoPrune - } - if dec.LightNoSyncServe != nil { - c.LightNoSyncServe = *dec.LightNoSyncServe - } if dec.SkipBcVersionCheck != nil { c.SkipBcVersionCheck = *dec.SkipBcVersionCheck } From 7a149a159a609f5c0a1eb0cc76dc27a944a1007b Mon Sep 17 00:00:00 2001 From: Dylan Vassallo Date: Thu, 15 Aug 2024 16:36:35 +0200 Subject: [PATCH 469/571] eth/tracers/js: add coinbase addr to ctx (#30231) Add coinbase address to javascript tracer context. This PR adds the `coinbase` address to `jsTracer.ctx`, allowing access to the coinbase address (fee receipient) in custom JavaScript tracers. Example usage: ```javascript result: function(ctx) { return toAddress(ctx.coinbase); } ``` This change enables custom tracers to access coinbase address, previously unavailable, enhancing their capabilities to match built-in tracers. --- eth/tracers/js/goja.go | 6 ++++++ eth/tracers/js/tracer_test.go | 3 +++ 2 files changed, 9 insertions(+) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 5290d4f70995..fd8f74fc54c8 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -254,6 +254,12 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from return } t.ctx["gasPrice"] = gasPriceBig + coinbase, err := t.toBuf(t.vm, env.Coinbase.Bytes()) + if err != nil { + t.err = err + return + } + t.ctx["coinbase"] = t.vm.ToValue(coinbase) } // OnTxEnd implements the Tracer interface and is invoked at the end of diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 05adedf265d1..7122b3c90e2c 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -154,6 +154,9 @@ func TestTracer(t *testing.T) { want: "", fail: "reached limit for padding memory slice: 1049568 at step (:1:83(20)) in server-side tracer function 'step'", contract: []byte{byte(vm.PUSH1), byte(0xff), byte(vm.PUSH1), byte(0x00), byte(vm.MSTORE8), byte(vm.STOP)}, + }, { // tests ctx.coinbase + code: "{lengths: [], step: function(log) { }, fault: function() {}, result: function(ctx) { var coinbase = ctx.coinbase; return toAddress(coinbase); }}", + want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0}`, }, } { if have, err := execTracer(tt.code, tt.contract); tt.want != string(have) || tt.fail != err { From 6eb42a6b4f9a07a4a11a9ac706b6a738212de210 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 22:14:42 +0200 Subject: [PATCH 470/571] eth: dial nodes from discv5 (#30302) Here I am adding a discv5 nodes source into the p2p dial iterator. It's an improved version of #29533. Unlike discv4, the discv5 random nodes iterator will always provide full ENRs. This means we can apply filtering to the results and will only try dialing nodes which explictly opt into the eth protocol with a matching chain. I have also removed the dial iterator from snap. We don't have an official DNS list for snap anymore, and I doubt anyone else is running one. While we could potentially filter for snap on discv5, there will be very few nodes announcing it, and the extra iterator would just stall the dialer. --------- Co-authored-by: lightclient --- eth/backend.go | 67 ++++++++++++++++++++++------------ eth/protocols/eth/discovery.go | 14 +++++++ eth/protocols/eth/handler.go | 3 +- eth/protocols/snap/handler.go | 11 +----- 4 files changed, 60 insertions(+), 35 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 442d408bb00d..51011ed0b228 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -64,15 +64,13 @@ type Config = ethconfig.Config // Ethereum implements the Ethereum full node service. type Ethereum struct { - config *ethconfig.Config + // core protocol objects + config *ethconfig.Config + txPool *txpool.TxPool + blockchain *core.BlockChain - // Handlers - txPool *txpool.TxPool - - blockchain *core.BlockChain - handler *handler - ethDialCandidates enode.Iterator - snapDialCandidates enode.Iterator + handler *handler + discmix *enode.FairMix // DB interfaces chainDb ethdb.Database // Block chain database @@ -162,6 +160,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), p2pServer: stack.Server(), + discmix: enode.NewFairMix(0), shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), } bcVersion := rawdb.ReadDatabaseVersion(chainDb) @@ -266,17 +265,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice) - // Setup DNS discovery iterators. - dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) - eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...) - if err != nil { - return nil, err - } - eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...) - if err != nil { - return nil, err - } - // Start the RPC service eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID) @@ -359,9 +347,9 @@ func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } // Protocols returns all the currently configured // network protocols to start. func (s *Ethereum) Protocols() []p2p.Protocol { - protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates) + protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.discmix) if s.config.SnapshotCache > 0 { - protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) + protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler))...) } return protos } @@ -369,7 +357,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol { // Start implements node.Lifecycle, starting all internal goroutines needed by the // Ethereum protocol implementation. func (s *Ethereum) Start() error { - eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) + s.setupDiscovery() // Start the bloom bits servicing goroutines s.startBloomHandlers(params.BloomBitsBlocks) @@ -382,12 +370,43 @@ func (s *Ethereum) Start() error { return nil } +func (s *Ethereum) setupDiscovery() error { + eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) + + // Add eth nodes from DNS. + dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) + if len(s.config.EthDiscoveryURLs) > 0 { + iter, err := dnsclient.NewIterator(s.config.EthDiscoveryURLs...) + if err != nil { + return err + } + s.discmix.AddSource(iter) + } + + // Add snap nodes from DNS. + if len(s.config.SnapDiscoveryURLs) > 0 { + iter, err := dnsclient.NewIterator(s.config.SnapDiscoveryURLs...) + if err != nil { + return err + } + s.discmix.AddSource(iter) + } + + // Add DHT nodes from discv5. + if s.p2pServer.DiscoveryV5() != nil { + filter := eth.NewNodeFilter(s.blockchain) + iter := enode.Filter(s.p2pServer.DiscoveryV5().RandomNodes(), filter) + s.discmix.AddSource(iter) + } + + return nil +} + // Stop implements node.Lifecycle, terminating all internal goroutines used by the // Ethereum protocol. func (s *Ethereum) Stop() error { // Stop all the peer-related stuff first. - s.ethDialCandidates.Close() - s.snapDialCandidates.Close() + s.discmix.Close() s.handler.Stop() // Then stop everything else. diff --git a/eth/protocols/eth/discovery.go b/eth/protocols/eth/discovery.go index a7bdd47daf07..075a85b69cdf 100644 --- a/eth/protocols/eth/discovery.go +++ b/eth/protocols/eth/discovery.go @@ -64,3 +64,17 @@ func currentENREntry(chain *core.BlockChain) *enrEntry { ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time), } } + +// NewNodeFilter returns a filtering function that returns whether the provided +// enode advertises a forkid compatible with the current chain. +func NewNodeFilter(chain *core.BlockChain) func(*enode.Node) bool { + filter := forkid.NewFilter(chain) + return func(n *enode.Node) bool { + var entry enrEntry + if err := n.Load(entry); err != nil { + return false + } + err := filter(entry.ForkID) + return err == nil + } +} diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 2d69ecdc8366..ecf07b6a2cc9 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -113,8 +113,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2 PeerInfo: func(id enode.ID) interface{} { return backend.PeerInfo(id) }, - Attributes: []enr.Entry{currentENREntry(backend.Chain())}, - DialCandidates: dnsdisc, + Attributes: []enr.Entry{currentENREntry(backend.Chain())}, }) } return protocols diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 5cbe9d127056..a6c60bc0757f 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -82,13 +82,7 @@ type Backend interface { } // MakeProtocols constructs the P2P protocol definitions for `snap`. -func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol { - // Filter the discovery iterator for nodes advertising snap support. - dnsdisc = enode.Filter(dnsdisc, func(n *enode.Node) bool { - var snap enrEntry - return n.Load(&snap) == nil - }) - +func MakeProtocols(backend Backend) []p2p.Protocol { protocols := make([]p2p.Protocol, len(ProtocolVersions)) for i, version := range ProtocolVersions { version := version // Closure @@ -108,8 +102,7 @@ func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol { PeerInfo: func(id enode.ID) interface{} { return backend.PeerInfo(id) }, - Attributes: []enr.Entry{&enrEntry{}}, - DialCandidates: dnsdisc, + Attributes: []enr.Entry{&enrEntry{}}, } } return protocols From 43640f12d8576cf5e27a99f34280b3e20fb900d3 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 16 Aug 2024 14:39:57 +0200 Subject: [PATCH 471/571] beacon/light: handle endpoint URL more gracefully (#30306) blsync was failing if the light endpoint it was provided ended with a `/`. This change should handle the joining more gracefully. --- beacon/light/api/light_api.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 6f60fc0cc655..45b425164f91 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -23,6 +23,7 @@ import ( "fmt" "io" "net/http" + "net/url" "sync" "time" @@ -121,7 +122,11 @@ func NewBeaconLightApi(url string, customHeaders map[string]string) *BeaconLight } func (api *BeaconLightApi) httpGet(path string) ([]byte, error) { - req, err := http.NewRequest("GET", api.url+path, nil) + uri, err := api.buildURL(path, nil) + if err != nil { + return nil, err + } + req, err := http.NewRequest("GET", uri, nil) if err != nil { return nil, err } @@ -545,9 +550,13 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() // established. It can only return nil when the context is canceled. func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream { for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) { - path := "/eth/v1/events?topics=head&topics=light_client_finality_update&topics=light_client_optimistic_update" log.Trace("Sending event subscription request") - req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil) + uri, err := api.buildURL("/eth/v1/events", map[string][]string{"topics": {"head", "light_client_finality_update", "light_client_optimistic_update"}}) + if err != nil { + listener.OnError(fmt.Errorf("error creating event subscription URL: %v", err)) + continue + } + req, err := http.NewRequestWithContext(ctx, "GET", uri, nil) if err != nil { listener.OnError(fmt.Errorf("error creating event subscription request: %v", err)) continue @@ -576,3 +585,15 @@ func ctxSleep(ctx context.Context, timeout time.Duration) (ok bool) { return false } } + +func (api *BeaconLightApi) buildURL(path string, params url.Values) (string, error) { + uri, err := url.Parse(api.url) + if err != nil { + return "", err + } + uri = uri.JoinPath(path) + if params != nil { + uri.RawQuery = params.Encode() + } + return uri.String(), nil +} From 09d889d2e3405f3c15d0b92fc0f027bed232a6e1 Mon Sep 17 00:00:00 2001 From: Shude Li Date: Fri, 16 Aug 2024 22:33:41 +0800 Subject: [PATCH 472/571] core: remove withdrawal length check for state processor (#30286) The withdrawal length is already verified by the beacon consensus package, so the check in the state processor is a duplicate. --- core/state_processor.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index c21f644f9851..cc415831659d 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,7 +17,6 @@ package core import ( - "errors" "fmt" "math/big" @@ -93,11 +92,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } - // Fail if Shanghai not enabled and len(withdrawals) is non-zero. - withdrawals := block.Withdrawals() - if len(withdrawals) > 0 && !p.config.IsShanghai(block.Number(), block.Time()) { - return nil, nil, 0, errors.New("withdrawals before shanghai") - } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.chain.engine.Finalize(p.chain, header, statedb, block.Body()) From 710c3f32ac8e4e5829a6a631dcfb1e0e13a49220 Mon Sep 17 00:00:00 2001 From: Arran Schlosberg <519948+ARR4N@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:41:44 +0100 Subject: [PATCH 473/571] vm: simplify error handling in `vm.EVM.create()` (#30292) To allow all error paths in `vm.EVM.create()` to consume the necessary gas, there is currently a pattern of gating code on `if err == nil` instead of returning as soon as the error occurs. The same behaviour can be achieved by abstracting the gated code into a method that returns immediately on error, improving readability and thus making it easier to understand and maintain. --- core/vm/evm.go | 73 +++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 1944189b5da2..7617d843c7f9 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -510,64 +510,59 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, contract.SetCodeOptionalHash(&address, codeAndHash) contract.IsDeployment = true + ret, err = evm.initNewContract(contract, address, value) + if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { + evm.StateDB.RevertToSnapshot(snapshot) + if err != ErrExecutionReverted { + contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution) + } + } + return ret, address, contract.Gas, err +} + +// initNewContract runs a new contract's creation code, performs checks on the +// resulting code that is to be deployed, and consumes necessary gas. +func (evm *EVM) initNewContract(contract *Contract, address common.Address, value *uint256.Int) ([]byte, error) { // Charge the contract creation init gas in verkle mode if evm.chainRules.IsEIP4762 { if !contract.UseGas(evm.AccessEvents.ContractCreateInitGas(address, value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) { - err = ErrOutOfGas + return nil, ErrOutOfGas } } - if err == nil { - ret, err = evm.interpreter.Run(contract, nil, false) + ret, err := evm.interpreter.Run(contract, nil, false) + if err != nil { + return ret, err } // Check whether the max code size has been exceeded, assign err if the case. - if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize { - err = ErrMaxCodeSizeExceeded + if evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize { + return ret, ErrMaxCodeSizeExceeded } // Reject code starting with 0xEF if EIP-3541 is enabled. - if err == nil && len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.IsLondon { - err = ErrInvalidCode - } - - // if the contract creation ran successfully and no errors were returned - // calculate the gas required to store the code. If the code could not - // be stored due to not enough gas set an error and let it be handled - // by the error checking condition below. - if err == nil { - if !evm.chainRules.IsEIP4762 { - createDataGas := uint64(len(ret)) * params.CreateDataGas - if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { - err = ErrCodeStoreOutOfGas - } - } else { - // Contract creation completed, touch the missing fields in the contract - if !contract.UseGas(evm.AccessEvents.AddAccount(address, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) { - err = ErrCodeStoreOutOfGas - } + if len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.IsLondon { + return ret, ErrInvalidCode + } - if err == nil && len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) { - err = ErrCodeStoreOutOfGas - } + if !evm.chainRules.IsEIP4762 { + createDataGas := uint64(len(ret)) * params.CreateDataGas + if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { + return ret, ErrCodeStoreOutOfGas } - - if err == nil { - evm.StateDB.SetCode(address, ret) + } else { + // Contract creation completed, touch the missing fields in the contract + if !contract.UseGas(evm.AccessEvents.AddAccount(address, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) { + return ret, ErrCodeStoreOutOfGas } - } - // When an error was returned by the EVM or when setting the creation code - // above we revert to the snapshot and consume any gas remaining. Additionally, - // when we're in homestead this also counts for code storage gas errors. - if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { - evm.StateDB.RevertToSnapshot(snapshot) - if err != ErrExecutionReverted { - contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution) + if len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) { + return ret, ErrCodeStoreOutOfGas } } - return ret, address, contract.Gas, err + evm.StateDB.SetCode(address, ret) + return ret, nil } // Create creates a new contract using code as deployment code. From 60db6a7b424433246d80609ce323645fc80a9ea8 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 19 Aug 2024 13:35:04 +0200 Subject: [PATCH 474/571] internal/build: include git-date on detached head (#30320) When we are building in detached head, we cannot easily obtain the same information as we can if we're in non-detached head. However, one thing we _can_ obtain is the git-hash and git-date. Currently, we omit to include the git-date into the build-info, which causes problem for reproducable builds which are on a detached head. This change fixes it to include the date-info always. --- internal/build/env.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/build/env.go b/internal/build/env.go index 0854fba2498d..35b2cd6ae7b9 100644 --- a/internal/build/env.go +++ b/internal/build/env.go @@ -111,6 +111,7 @@ func LocalEnv() Environment { commitRe, _ := regexp.Compile("^([0-9a-f]{40})$") if commit := commitRe.FindString(head); commit != "" && env.Commit == "" { env.Commit = commit + env.Date = getDate(env.Commit) } return env } From 8486722dcbf2b989bc1f79f60ed5035c008e7c68 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 19 Aug 2024 13:35:41 +0200 Subject: [PATCH 475/571] build: remove mantic from ppa builds (#30322) removes ppa-build for ubuntu `mantic` --- build/ci.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/build/ci.go b/build/ci.go index 009d69e6e416..ac7060dc2fd7 100644 --- a/build/ci.go +++ b/build/ci.go @@ -126,8 +126,6 @@ var ( "focal", // 20.04, EOL: 04/2030 "jammy", // 22.04, EOL: 04/2032 "noble", // 24.04, EOL: 04/2034 - - "mantic", // 23.10, EOL: 07/2024 } // This is where the tests should be unpacked. From 41b3b30863a86dc560a57043aa72b9efa1002094 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 19 Aug 2024 20:06:57 +0200 Subject: [PATCH 476/571] gitignore: ignore upload-artefacts (#30325) Our `WriteArchive`, used by ci builder, creates files in the repo root,in order to upload. After we've built the amd64-builds, we create the uploads, and cause the repo to be flagged as dirty for the remaining builds. This change fixes it by adding the artefacts to gitignore. Closes #30324 --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3f27cdc00f07..62f3a96e30ef 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ build/_vendor/pkg /build/bin/ /geth*.zip +# used by the build/ci.go archive + upload tool +/geth*.tar.gz + # travis profile.tmp profile.cov From 84565dc899ebad48862a1fcec039594833f83669 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 19 Aug 2024 15:32:15 -0600 Subject: [PATCH 477/571] eth/catalyst: ensure period zero mode leaves no pending txs in pool (#30264) closes #29475, replaces #29657, #30104 Fixes two issues. First is a deadlock where the txpool attempts to reorg, but can't complete because there are no readers left for the new txs subscription. Second, resolves a problem with on demand mode where txs may be left pending when there are more pending txs than block space. Co-authored-by: Martin Holst Swende --- eth/catalyst/api.go | 21 ++----- eth/catalyst/simulated_beacon.go | 87 ++++++++++++++++----------- eth/catalyst/simulated_beacon_api.go | 72 +++++++++++++++++----- eth/catalyst/simulated_beacon_test.go | 68 ++++++++++++++++++++- 4 files changed, 178 insertions(+), 70 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 5a001e1ee836..48bfb021b948 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -184,7 +184,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("forkChoiceUpdateV1 called post-shanghai")) } } - return api.forkchoiceUpdated(update, payloadAttributes, engine.PayloadV1, false) + return api.forkchoiceUpdated(update, payloadAttributes, engine.PayloadV1) } // ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload @@ -207,7 +207,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV2 must only be called with paris and shanghai payloads")) } } - return api.forkchoiceUpdated(update, params, engine.PayloadV2, false) + return api.forkchoiceUpdated(update, params, engine.PayloadV2) } // ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root @@ -228,10 +228,10 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa // hash, even if params are wrong. To do this we need to split up // forkchoiceUpdate into a function that only updates the head and then a // function that kicks off block construction. - return api.forkchoiceUpdated(update, params, engine.PayloadV3, false) + return api.forkchoiceUpdated(update, params, engine.PayloadV3) } -func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes, payloadVersion engine.PayloadVersion, simulatorMode bool) (engine.ForkChoiceResponse, error) { +func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes, payloadVersion engine.PayloadVersion) (engine.ForkChoiceResponse, error) { api.forkchoiceLock.Lock() defer api.forkchoiceLock.Unlock() @@ -374,19 +374,6 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl if api.localBlocks.has(id) { return valid(&id), nil } - // If the beacon chain is ran by a simulator, then transaction insertion, - // block insertion and block production will happen without any timing - // delay between them. This will cause flaky simulator executions due to - // the transaction pool running its internal reset operation on a back- - // ground thread. To avoid the racey behavior - in simulator mode - the - // pool will be explicitly blocked on its reset before continuing to the - // block production below. - if simulatorMode { - if err := api.eth.TxPool().Sync(); err != nil { - log.Error("Failed to sync transaction pool", "err", err) - return valid(nil), engine.InvalidPayloadAttributes.With(err) - } - } payload, err := api.eth.Miner().BuildPayload(args) if err != nil { log.Error("Failed to build payload", "err", err) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index 8bdf94b80e81..86355a153387 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -20,6 +20,7 @@ import ( "crypto/rand" "crypto/sha256" "errors" + "fmt" "math/big" "sync" "time" @@ -30,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" @@ -41,36 +43,46 @@ const devEpochLength = 32 // withdrawalQueue implements a FIFO queue which holds withdrawals that are // pending inclusion. type withdrawalQueue struct { - pending chan *types.Withdrawal + pending types.Withdrawals + mu sync.Mutex + feed event.Feed + subs event.SubscriptionScope } +type newWithdrawalsEvent struct{ Withdrawals types.Withdrawals } + // add queues a withdrawal for future inclusion. func (w *withdrawalQueue) add(withdrawal *types.Withdrawal) error { - select { - case w.pending <- withdrawal: - break - default: - return errors.New("withdrawal queue full") - } + w.mu.Lock() + w.pending = append(w.pending, withdrawal) + w.mu.Unlock() + + w.feed.Send(newWithdrawalsEvent{types.Withdrawals{withdrawal}}) return nil } -// gatherPending returns a number of queued withdrawals up to a maximum count. -func (w *withdrawalQueue) gatherPending(maxCount int) []*types.Withdrawal { - withdrawals := []*types.Withdrawal{} - for { - select { - case withdrawal := <-w.pending: - withdrawals = append(withdrawals, withdrawal) - if len(withdrawals) == maxCount { - return withdrawals - } - default: - return withdrawals - } - } +// pop dequeues the specified number of withdrawals from the queue. +func (w *withdrawalQueue) pop(count int) types.Withdrawals { + w.mu.Lock() + defer w.mu.Unlock() + + count = min(count, len(w.pending)) + popped := w.pending[0:count] + w.pending = w.pending[count:] + + return popped +} + +// subscribe allows a listener to be updated when new withdrawals are added to +// the queue. +func (w *withdrawalQueue) subscribe(ch chan<- newWithdrawalsEvent) event.Subscription { + sub := w.feed.Subscribe(ch) + return w.subs.Track(sub) } +// SimulatedBeacon drives an Ethereum instance as if it were a real beacon +// client. It can run in period mode where it mines a new block every period +// (seconds) or on every transaction via Commit, Fork and AdjustTime. type SimulatedBeacon struct { shutdownCh chan struct{} eth *eth.Ethereum @@ -86,10 +98,6 @@ type SimulatedBeacon struct { } // NewSimulatedBeacon constructs a new simulated beacon chain. -// Period sets the period in which blocks should be produced. -// -// - If period is set to 0, a block is produced on every transaction. -// via Commit, Fork and AdjustTime. func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, error) { block := eth.BlockChain().CurrentBlock() current := engine.ForkchoiceStateV1{ @@ -112,7 +120,6 @@ func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, err engineAPI: engineAPI, lastBlockTime: block.Time, curForkchoiceState: current, - withdrawals: withdrawalQueue{make(chan *types.Withdrawal, 20)}, }, nil } @@ -156,6 +163,16 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u c.setCurrentState(header.Hash(), *finalizedHash) } + // Because transaction insertion, block insertion, and block production will + // happen without any timing delay between them in simulator mode and the + // transaction pool will be running its internal reset operation on a + // background thread, flaky executions can happen. To avoid the racey + // behavior, the pool will be explicitly blocked on its reset before + // continuing to the block production below. + if err := c.eth.APIBackend.TxPool().Sync(); err != nil { + return fmt.Errorf("failed to sync txpool: %w", err) + } + var random [32]byte rand.Read(random[:]) fcResponse, err := c.engineAPI.forkchoiceUpdated(c.curForkchoiceState, &engine.PayloadAttributes{ @@ -164,13 +181,14 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u Withdrawals: withdrawals, Random: random, BeaconRoot: &common.Hash{}, - }, engine.PayloadV3, true) + }, engine.PayloadV3) if err != nil { return err } if fcResponse == engine.STATUS_SYNCING { return errors.New("chain rewind prevented invocation of payload creation") } + envelope, err := c.engineAPI.getPayload(*fcResponse.PayloadID, true) if err != nil { return err @@ -223,8 +241,7 @@ func (c *SimulatedBeacon) loop() { case <-c.shutdownCh: return case <-timer.C: - withdrawals := c.withdrawals.gatherPending(10) - if err := c.sealBlock(withdrawals, uint64(time.Now().Unix())); err != nil { + if err := c.sealBlock(c.withdrawals.pop(10), uint64(time.Now().Unix())); err != nil { log.Warn("Error performing sealing work", "err", err) } else { timer.Reset(time.Second * time.Duration(c.period)) @@ -260,7 +277,7 @@ func (c *SimulatedBeacon) setCurrentState(headHash, finalizedHash common.Hash) { // Commit seals a block on demand. func (c *SimulatedBeacon) Commit() common.Hash { - withdrawals := c.withdrawals.gatherPending(10) + withdrawals := c.withdrawals.pop(10) if err := c.sealBlock(withdrawals, uint64(time.Now().Unix())); err != nil { log.Warn("Error performing sealing work", "err", err) } @@ -301,16 +318,14 @@ func (c *SimulatedBeacon) AdjustTime(adjustment time.Duration) error { if parent == nil { return errors.New("parent not found") } - withdrawals := c.withdrawals.gatherPending(10) + withdrawals := c.withdrawals.pop(10) return c.sealBlock(withdrawals, parent.Time+uint64(adjustment/time.Second)) } +// RegisterSimulatedBeaconAPIs registers the simulated beacon's API with the +// stack. func RegisterSimulatedBeaconAPIs(stack *node.Node, sim *SimulatedBeacon) { - api := &api{sim} - if sim.period == 0 { - // mine on demand if period is set to 0 - go api.loop() - } + api := newSimulatedBeaconAPI(sim) stack.RegisterAPIs([]rpc.API{ { Namespace: "dev", diff --git a/eth/catalyst/simulated_beacon_api.go b/eth/catalyst/simulated_beacon_api.go index 73d0a5921d83..668780531501 100644 --- a/eth/catalyst/simulated_beacon_api.go +++ b/eth/catalyst/simulated_beacon_api.go @@ -18,44 +18,88 @@ package catalyst import ( "context" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" ) -type api struct { +// simulatedBeaconAPI provides a RPC API for SimulatedBeacon. +type simulatedBeaconAPI struct { sim *SimulatedBeacon } -func (a *api) loop() { +// newSimulatedBeaconAPI returns an instance of simulatedBeaconAPI with a +// buffered commit channel. If period is zero, it starts a goroutine to handle +// new tx events. +func newSimulatedBeaconAPI(sim *SimulatedBeacon) *simulatedBeaconAPI { + api := &simulatedBeaconAPI{sim: sim} + if sim.period == 0 { + // mine on demand if period is set to 0 + go api.loop() + } + return api +} + +// loop is the main loop for the API when it's running in period = 0 mode. It +// ensures that block production is triggered as soon as a new withdrawal or +// transaction is received. +func (a *simulatedBeaconAPI) loop() { var ( - newTxs = make(chan core.NewTxsEvent) - sub = a.sim.eth.TxPool().SubscribeTransactions(newTxs, true) + newTxs = make(chan core.NewTxsEvent) + newWxs = make(chan newWithdrawalsEvent) + newTxsSub = a.sim.eth.TxPool().SubscribeTransactions(newTxs, true) + newWxsSub = a.sim.withdrawals.subscribe(newWxs) + doCommit = make(chan struct{}, 1) ) - defer sub.Unsubscribe() + defer newTxsSub.Unsubscribe() + defer newWxsSub.Unsubscribe() + + // A background thread which signals to the simulator when to commit + // based on messages over doCommit. + go func() { + for range doCommit { + a.sim.Commit() + a.sim.eth.TxPool().Sync() + + // It's worth noting that in case a tx ends up in the pool listed as + // "executable", but for whatever reason the miner does not include it in + // a block -- maybe the miner is enforcing a higher tip than the pool -- + // this code will spinloop. + for { + if executable, _ := a.sim.eth.TxPool().Stats(); executable == 0 { + break + } + a.sim.Commit() + } + } + }() for { select { case <-a.sim.shutdownCh: + close(doCommit) return - case w := <-a.sim.withdrawals.pending: - withdrawals := append(a.sim.withdrawals.gatherPending(9), w) - if err := a.sim.sealBlock(withdrawals, uint64(time.Now().Unix())); err != nil { - log.Warn("Error performing sealing work", "err", err) + case <-newWxs: + select { + case doCommit <- struct{}{}: + default: } case <-newTxs: - a.sim.Commit() + select { + case doCommit <- struct{}{}: + default: + } } } } -func (a *api) AddWithdrawal(ctx context.Context, withdrawal *types.Withdrawal) error { +// AddWithdrawal adds a withdrawal to the pending queue. +func (a *simulatedBeaconAPI) AddWithdrawal(ctx context.Context, withdrawal *types.Withdrawal) error { return a.sim.withdrawals.add(withdrawal) } -func (a *api) SetFeeRecipient(ctx context.Context, feeRecipient common.Address) { +// SetFeeRecipient sets the fee recipient for block building purposes. +func (a *simulatedBeaconAPI) SetFeeRecipient(ctx context.Context, feeRecipient common.Address) { a.sim.setFeeRecipient(feeRecipient) } diff --git a/eth/catalyst/simulated_beacon_test.go b/eth/catalyst/simulated_beacon_test.go index bb10938c359d..711e8f1d60f3 100644 --- a/eth/catalyst/simulated_beacon_test.go +++ b/eth/catalyst/simulated_beacon_test.go @@ -35,7 +35,7 @@ import ( "github.com/ethereum/go-ethereum/params" ) -func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis) (*node.Node, *eth.Ethereum, *SimulatedBeacon) { +func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis, period uint64) (*node.Node, *eth.Ethereum, *SimulatedBeacon) { t.Helper() n, err := node.New(&node.Config{ @@ -55,7 +55,7 @@ func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis) (*node. t.Fatal("can't create eth service:", err) } - simBeacon, err := NewSimulatedBeacon(1, ethservice) + simBeacon, err := NewSimulatedBeacon(period, ethservice) if err != nil { t.Fatal("can't create simulated beacon:", err) } @@ -87,7 +87,7 @@ func TestSimulatedBeaconSendWithdrawals(t *testing.T) { // short period (1 second) for testing purposes var gasLimit uint64 = 10_000_000 genesis := core.DeveloperGenesisBlock(gasLimit, &testAddr) - node, ethService, mock := startSimulatedBeaconEthService(t, genesis) + node, ethService, mock := startSimulatedBeaconEthService(t, genesis, 1) _ = mock defer node.Close() @@ -140,3 +140,65 @@ func TestSimulatedBeaconSendWithdrawals(t *testing.T) { } } } + +// Tests that zero-period dev mode can handle a lot of simultaneous +// transactions/withdrawals +func TestOnDemandSpam(t *testing.T) { + var ( + withdrawals []types.Withdrawal + txs = make(map[common.Hash]*types.Transaction) + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testAddr = crypto.PubkeyToAddress(testKey.PublicKey) + gasLimit uint64 = 10_000_000 + genesis = core.DeveloperGenesisBlock(gasLimit, &testAddr) + node, eth, mock = startSimulatedBeaconEthService(t, genesis, 0) + _ = newSimulatedBeaconAPI(mock) + signer = types.LatestSigner(eth.BlockChain().Config()) + chainHeadCh = make(chan core.ChainHeadEvent, 100) + sub = eth.BlockChain().SubscribeChainHeadEvent(chainHeadCh) + ) + defer node.Close() + defer sub.Unsubscribe() + + // generate some withdrawals + for i := 0; i < 20; i++ { + withdrawals = append(withdrawals, types.Withdrawal{Index: uint64(i)}) + if err := mock.withdrawals.add(&withdrawals[i]); err != nil { + t.Fatal("addWithdrawal failed", err) + } + } + + // generate a bunch of transactions + for i := 0; i < 20000; i++ { + tx, err := types.SignTx(types.NewTransaction(uint64(i), common.Address{byte(i), byte(1)}, big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), signer, testKey) + if err != nil { + t.Fatal("error signing transaction", err) + } + txs[tx.Hash()] = tx + if err := eth.APIBackend.SendTx(context.Background(), tx); err != nil { + t.Fatal("error adding txs to pool", err) + } + } + + var ( + includedTxs = make(map[common.Hash]struct{}) + includedWxs []uint64 + ) + for { + select { + case evt := <-chainHeadCh: + for _, itx := range evt.Block.Transactions() { + includedTxs[itx.Hash()] = struct{}{} + } + for _, iwx := range evt.Block.Withdrawals() { + includedWxs = append(includedWxs, iwx.Index) + } + // ensure all withdrawals/txs included. this will take two blocks b/c number of withdrawals > 10 + if len(includedTxs) == len(txs) && len(includedWxs) == len(withdrawals) { + return + } + case <-time.After(10 * time.Second): + t.Fatalf("timed out without including all withdrawals/txs: have txs %d, want %d, have wxs %d, want %d", len(includedTxs), len(txs), len(includedWxs), len(withdrawals)) + } + } +} From 65aaf52f4c92a3a0096bcb86717f5aca3056d97a Mon Sep 17 00:00:00 2001 From: chen4903 <108803001+chen4903@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:26:35 +0800 Subject: [PATCH 478/571] accounts/abi: handle ABIs with contract type parameter (#30315) convert parameter of type contract to the basic `address` type --------- Co-authored-by: Martin HS --- accounts/abi/abi_test.go | 7 +++++++ accounts/abi/type.go | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index bc76df0dc264..dfcd0593937c 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -1218,3 +1218,10 @@ func TestUnpackRevert(t *testing.T) { }) } } + +func TestInternalContractType(t *testing.T) { + jsonData := `[{"inputs":[{"components":[{"internalType":"uint256","name":"dailyLimit","type":"uint256"},{"internalType":"uint256","name":"txLimit","type":"uint256"},{"internalType":"uint256","name":"accountDailyLimit","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"bool","name":"onlyWhitelisted","type":"bool"}],"internalType":"struct IMessagePassingBridge.BridgeLimits","name":"bridgeLimits","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastTransferReset","type":"uint256"},{"internalType":"uint256","name":"bridged24Hours","type":"uint256"}],"internalType":"struct IMessagePassingBridge.AccountLimit","name":"accountDailyLimit","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastTransferReset","type":"uint256"},{"internalType":"uint256","name":"bridged24Hours","type":"uint256"}],"internalType":"struct IMessagePassingBridge.BridgeDailyLimit","name":"bridgeDailyLimit","type":"tuple"},{"internalType":"contract INameService","name":"nameService","type":"INameService"},{"internalType":"bool","name":"isClosed","type":"bool"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"canBridge","outputs":[{"internalType":"bool","name":"isWithinLimit","type":"bool"},{"internalType":"string","name":"error","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"normalizeFrom18ToTokenDecimals","outputs":[{"internalType":"uint256","name":"normalized","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"normalizeFromTokenTo18Decimals","outputs":[{"internalType":"uint256","name":"normalized","type":"uint256"}],"stateMutability":"pure","type":"function"}]` + if _, err := JSON(strings.NewReader(jsonData)); err != nil { + t.Fatal(err) + } +} diff --git a/accounts/abi/type.go b/accounts/abi/type.go index d57fa3d4e667..e59456f15af0 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -219,7 +219,12 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty typ.T = FunctionTy typ.Size = 24 default: - return Type{}, fmt.Errorf("unsupported arg type: %s", t) + if strings.HasPrefix(internalType, "contract ") { + typ.Size = 20 + typ.T = AddressTy + } else { + return Type{}, fmt.Errorf("unsupported arg type: %s", t) + } } return From 3b48b16290cd19e4f87ab90c72dd28b4072dc744 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:06:00 +0200 Subject: [PATCH 479/571] core/rawdb: drop MigrateTable (#30331) These are the leftovers from #24028. --- core/rawdb/database.go | 6 -- core/rawdb/freezer.go | 114 ------------------------------- core/rawdb/freezer_memory.go | 7 -- core/rawdb/freezer_resettable.go | 9 --- core/rawdb/freezer_test.go | 83 ---------------------- core/rawdb/table.go | 6 -- ethdb/database.go | 5 -- ethdb/remotedb/remotedb.go | 4 -- 8 files changed, 234 deletions(-) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 831016da15df..13233406fe6c 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -149,12 +149,6 @@ func (db *nofreezedb) ReadAncients(fn func(reader ethdb.AncientReaderOp) error) return fn(db) } -// MigrateTable processes the entries in a given table in sequence -// converting them to a new format if they're of an old format. -func (db *nofreezedb) MigrateTable(kind string, convert convertLegacyFn) error { - return errNotSupported -} - // AncientDatadir returns an error as we don't have a backing chain freezer. func (db *nofreezedb) AncientDatadir() (string, error) { return "", errNotSupported diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 0f28782db9ee..6c050ee625e5 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -24,9 +24,7 @@ import ( "path/filepath" "sync" "sync/atomic" - "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -389,115 +387,3 @@ func (f *Freezer) repair() error { f.tail.Store(tail) return nil } - -// convertLegacyFn takes a raw freezer entry in an older format and -// returns it in the new format. -type convertLegacyFn = func([]byte) ([]byte, error) - -// MigrateTable processes the entries in a given table in sequence -// converting them to a new format if they're of an old format. -func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { - if f.readonly { - return errReadOnly - } - f.writeLock.Lock() - defer f.writeLock.Unlock() - - table, ok := f.tables[kind] - if !ok { - return errUnknownTable - } - // forEach iterates every entry in the table serially and in order, calling `fn` - // with the item as argument. If `fn` returns an error the iteration stops - // and that error will be returned. - forEach := func(t *freezerTable, offset uint64, fn func(uint64, []byte) error) error { - var ( - items = t.items.Load() - batchSize = uint64(1024) - maxBytes = uint64(1024 * 1024) - ) - for i := offset; i < items; { - if i+batchSize > items { - batchSize = items - i - } - data, err := t.RetrieveItems(i, batchSize, maxBytes) - if err != nil { - return err - } - for j, item := range data { - if err := fn(i+uint64(j), item); err != nil { - return err - } - } - i += uint64(len(data)) - } - return nil - } - // TODO(s1na): This is a sanity-check since as of now no process does tail-deletion. But the migration - // process assumes no deletion at tail and needs to be modified to account for that. - if table.itemOffset.Load() > 0 || table.itemHidden.Load() > 0 { - return errors.New("migration not supported for tail-deleted freezers") - } - ancientsPath := filepath.Dir(table.index.Name()) - // Set up new dir for the migrated table, the content of which - // we'll at the end move over to the ancients dir. - migrationPath := filepath.Join(ancientsPath, "migration") - newTable, err := newFreezerTable(migrationPath, kind, table.noCompression, false) - if err != nil { - return err - } - var ( - batch = newTable.newBatch() - out []byte - start = time.Now() - logged = time.Now() - offset = newTable.items.Load() - ) - if offset > 0 { - log.Info("found previous migration attempt", "migrated", offset) - } - // Iterate through entries and transform them - if err := forEach(table, offset, func(i uint64, blob []byte) error { - if i%10000 == 0 && time.Since(logged) > 16*time.Second { - log.Info("Processing legacy elements", "count", i, "elapsed", common.PrettyDuration(time.Since(start))) - logged = time.Now() - } - out, err = convert(blob) - if err != nil { - return err - } - if err := batch.AppendRaw(i, out); err != nil { - return err - } - return nil - }); err != nil { - return err - } - if err := batch.commit(); err != nil { - return err - } - log.Info("Replacing old table files with migrated ones", "elapsed", common.PrettyDuration(time.Since(start))) - // Release and delete old table files. Note this won't - // delete the index file. - table.releaseFilesAfter(0, true) - - if err := newTable.Close(); err != nil { - return err - } - files, err := os.ReadDir(migrationPath) - if err != nil { - return err - } - // Move migrated files to ancients dir. - for _, f := range files { - // This will replace the old index file as a side-effect. - if err := os.Rename(filepath.Join(migrationPath, f.Name()), filepath.Join(ancientsPath, f.Name())); err != nil { - return err - } - } - // Delete by now empty dir. - if err := os.Remove(migrationPath); err != nil { - return err - } - return nil -} diff --git a/core/rawdb/freezer_memory.go b/core/rawdb/freezer_memory.go index 954b58e8747b..cd3910151486 100644 --- a/core/rawdb/freezer_memory.go +++ b/core/rawdb/freezer_memory.go @@ -394,13 +394,6 @@ func (f *MemoryFreezer) Sync() error { return nil } -// MigrateTable processes and migrates entries of a given table to a new format. -// The second argument is a function that takes a raw entry and returns it -// in the newest format. -func (f *MemoryFreezer) MigrateTable(string, func([]byte) ([]byte, error)) error { - return errors.New("not implemented") -} - // Close releases all the sources held by the memory freezer. It will panic if // any following invocation is made to a closed freezer. func (f *MemoryFreezer) Close() error { diff --git a/core/rawdb/freezer_resettable.go b/core/rawdb/freezer_resettable.go index 6f8541f43bfc..b14799506615 100644 --- a/core/rawdb/freezer_resettable.go +++ b/core/rawdb/freezer_resettable.go @@ -202,15 +202,6 @@ func (f *resettableFreezer) Sync() error { return f.freezer.Sync() } -// MigrateTable processes the entries in a given table in sequence -// converting them to a new format if they're of an old format. -func (f *resettableFreezer) MigrateTable(kind string, convert convertLegacyFn) error { - f.lock.RLock() - defer f.lock.RUnlock() - - return f.freezer.MigrateTable(kind, convert) -} - // cleanup removes the directory located in the specified path // has the name with deletion marker suffix. func cleanup(path string) error { diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index 72d1417200ce..7d82ea305f2c 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -22,8 +22,6 @@ import ( "fmt" "math/big" "math/rand" - "os" - "path/filepath" "sync" "testing" @@ -379,87 +377,6 @@ func checkAncientCount(t *testing.T, f *Freezer, kind string, n uint64) { } } -func TestRenameWindows(t *testing.T) { - var ( - fname = "file.bin" - fname2 = "file2.bin" - data = []byte{1, 2, 3, 4} - data2 = []byte{2, 3, 4, 5} - data3 = []byte{3, 5, 6, 7} - dataLen = 4 - ) - - // Create 2 temp dirs - dir1 := t.TempDir() - dir2 := t.TempDir() - - // Create file in dir1 and fill with data - f, err := os.Create(filepath.Join(dir1, fname)) - if err != nil { - t.Fatal(err) - } - f2, err := os.Create(filepath.Join(dir1, fname2)) - if err != nil { - t.Fatal(err) - } - f3, err := os.Create(filepath.Join(dir2, fname2)) - if err != nil { - t.Fatal(err) - } - if _, err := f.Write(data); err != nil { - t.Fatal(err) - } - if _, err := f2.Write(data2); err != nil { - t.Fatal(err) - } - if _, err := f3.Write(data3); err != nil { - t.Fatal(err) - } - if err := f.Close(); err != nil { - t.Fatal(err) - } - if err := f2.Close(); err != nil { - t.Fatal(err) - } - if err := f3.Close(); err != nil { - t.Fatal(err) - } - if err := os.Rename(f.Name(), filepath.Join(dir2, fname)); err != nil { - t.Fatal(err) - } - if err := os.Rename(f2.Name(), filepath.Join(dir2, fname2)); err != nil { - t.Fatal(err) - } - - // Check file contents - f, err = os.Open(filepath.Join(dir2, fname)) - if err != nil { - t.Fatal(err) - } - defer f.Close() - defer os.Remove(f.Name()) - buf := make([]byte, dataLen) - if _, err := f.Read(buf); err != nil { - t.Fatal(err) - } - if !bytes.Equal(buf, data) { - t.Errorf("unexpected file contents. Got %v\n", buf) - } - - f, err = os.Open(filepath.Join(dir2, fname2)) - if err != nil { - t.Fatal(err) - } - defer f.Close() - defer os.Remove(f.Name()) - if _, err := f.Read(buf); err != nil { - t.Fatal(err) - } - if !bytes.Equal(buf, data2) { - t.Errorf("unexpected file contents. Got %v\n", buf) - } -} - func TestFreezerCloseSync(t *testing.T) { t.Parallel() f, _ := newFreezerForTesting(t, map[string]bool{"a": true, "b": true}) diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 0a25c5bcddc6..bc1d354d106b 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -113,12 +113,6 @@ func (t *table) Sync() error { return t.db.Sync() } -// MigrateTable processes the entries in a given table in sequence -// converting them to a new format if they're of an old format. -func (t *table) MigrateTable(kind string, convert convertLegacyFn) error { - return t.db.MigrateTable(kind, convert) -} - // AncientDatadir returns the ancient datadir of the underlying database. func (t *table) AncientDatadir() (string, error) { return t.db.AncientDatadir() diff --git a/ethdb/database.go b/ethdb/database.go index 89c793d0be66..c6e76fd2fecf 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -124,11 +124,6 @@ type AncientWriter interface { // Sync flushes all in-memory ancient store data to disk. Sync() error - - // MigrateTable processes and migrates entries of a given table to a new format. - // The second argument is a function that takes a raw entry and returns it - // in the newest format. - MigrateTable(string, func([]byte) ([]byte, error)) error } // AncientWriteOp is given to the function argument of ModifyAncients. diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index c8b76eab4ac4..d0f018cb01f2 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -110,10 +110,6 @@ func (db *Database) Sync() error { return nil } -func (db *Database) MigrateTable(s string, f func([]byte) ([]byte, error)) error { - panic("not supported") -} - func (db *Database) NewBatch() ethdb.Batch { panic("not supported") } From fc88cea64864f61ed3ae24d502ade785deb5d077 Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:31:06 +0200 Subject: [PATCH 480/571] core/vm: reuse Memory instances (#30137) This PR adds a sync.Pool to reuse instances of Memory in EVMInterpreter. --- core/vm/instructions.go | 4 ++-- core/vm/interpreter.go | 1 + core/vm/memory.go | 21 ++++++++++++++++++- core/vm/runtime/runtime_test.go | 37 +++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 2e0f4c40ab1b..35d6393fba0e 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -871,14 +871,14 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() - ret := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) + ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) return ret, errStopToken } func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() - ret := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) + ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) interpreter.returnData = ret return ret, ErrExecutionReverted diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 2b1ea3848352..6e7d28a0ce25 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -198,6 +198,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // they are returned to the pools defer func() { returnStack(stack) + mem.Free() }() contract.Input = input diff --git a/core/vm/memory.go b/core/vm/memory.go index 33203879ae50..1ddd8d1ead65 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -17,9 +17,17 @@ package vm import ( + "sync" + "github.com/holiman/uint256" ) +var memoryPool = sync.Pool{ + New: func() any { + return &Memory{} + }, +} + // Memory implements a simple memory model for the ethereum virtual machine. type Memory struct { store []byte @@ -28,7 +36,18 @@ type Memory struct { // NewMemory returns a new memory model. func NewMemory() *Memory { - return &Memory{} + return memoryPool.Get().(*Memory) +} + +// Free returns the memory to the pool. +func (m *Memory) Free() { + // To reduce peak allocation, return only smaller memory instances to the pool. + const maxBufferSize = 16 << 10 + if cap(m.store) <= maxBufferSize { + m.store = m.store[:0] + m.lastGasCost = 0 + memoryPool.Put(m) + } } // Set sets offset + size to value diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index f52484606b74..f56d4a74520f 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -17,9 +17,11 @@ package runtime import ( + "encoding/binary" "fmt" "math/big" "os" + "strconv" "strings" "testing" @@ -241,6 +243,41 @@ func BenchmarkEVM_SWAP1(b *testing.B) { }) } +func BenchmarkEVM_RETURN(b *testing.B) { + // returns a contract that returns a zero-byte slice of len size + returnContract := func(size uint64) []byte { + contract := []byte{ + byte(vm.PUSH8), 0, 0, 0, 0, 0, 0, 0, 0, // PUSH8 0xXXXXXXXXXXXXXXXX + byte(vm.PUSH0), // PUSH0 + byte(vm.RETURN), // RETURN + } + binary.BigEndian.PutUint64(contract[1:], size) + return contract + } + + state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + contractAddr := common.BytesToAddress([]byte("contract")) + + for _, n := range []uint64{1_000, 10_000, 100_000, 1_000_000} { + b.Run(strconv.FormatUint(n, 10), func(b *testing.B) { + b.ReportAllocs() + + contractCode := returnContract(n) + state.SetCode(contractAddr, contractCode) + + for i := 0; i < b.N; i++ { + ret, _, err := Call(contractAddr, []byte{}, &Config{State: state}) + if err != nil { + b.Fatal(err) + } + if uint64(len(ret)) != n { + b.Fatalf("expected return size %d, got %d", n, len(ret)) + } + } + }) + } +} + func fakeHeader(n uint64, parentHash common.Hash) *types.Header { header := types.Header{ Coinbase: common.HexToAddress("0x00000000000000000000000000000000deadbeef"), From 693e40a495fa8af8d12a8e81a90041e66d42603c Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 20 Aug 2024 15:33:28 +0200 Subject: [PATCH 481/571] build: attempt at reproducible builds (#30321) This PR implements the conclusions from https://github.com/ethereum/go-ethereum/issues/28987#issuecomment-2296075028, that is: Building with `--strip-all` as a ld-flag to the cgo linker, to remove symbols. Without that, some spurious reference to a temporary file is included into the kzg-related library. Building with `--build-id=none`, to avoid putting a `build id` into the file. --- build/ci.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build/ci.go b/build/ci.go index ac7060dc2fd7..fe507cf48f94 100644 --- a/build/ci.go +++ b/build/ci.go @@ -249,7 +249,11 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) ( if runtime.GOOS == "linux" { // Enforce the stacksize to 8M, which is the case on most platforms apart from // alpine Linux. - extld := []string{"-Wl,-z,stack-size=0x800000"} + // See https://sourceware.org/binutils/docs-2.23.1/ld/Options.html#Options + // regarding the options --build-id=none and --strip-all. It is needed for + // reproducible builds; removing references to temporary files in C-land, and + // making build-id reproducably absent. + extld := []string{"-Wl,-z,stack-size=0x800000,--build-id=none,--strip-all"} if staticLinking { extld = append(extld, "-static") // Under static linking, use of certain glibc features must be From d0fd1331f16bf4a075338d70548492ae042ee327 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 20 Aug 2024 15:50:07 +0200 Subject: [PATCH 482/571] all: update to go version 1.23.0 (#30323) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates the version of go used in builds and docker to 1.23.0. Release notes: https://go.dev/doc/go1.23 More importantly, following our policy of maintaining the last two versions (which now becomes 1.23 and 1.22), we can now make use of the things that were introduced in 1.22: https://go.dev/doc/go1.22 Go 1.22 makes two changes to “for” loops. - each iteration creates new variables, - for loops may range over integers Other than that, some interesting library changes and other stuff. --- .github/workflows/go.yml | 2 +- .travis.yml | 18 +++---- Dockerfile | 2 +- Dockerfile.alltools | 2 +- README.md | 2 +- build/checksums.txt | 96 +++++++++++++++++++------------------- go.mod | 4 +- internal/build/download.go | 3 +- 8 files changed, 65 insertions(+), 64 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 844cfb5d242a..6406d2fa3db0 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -15,7 +15,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: 1.21.4 + go-version: 1.23.0 cache: false - name: Run tests run: go test -short ./... diff --git a/.travis.yml b/.travis.yml index 2dc80f85edf9..edb16561d556 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ jobs: os: linux arch: amd64 dist: noble - go: 1.22.x + go: 1.23.x env: - docker services: @@ -33,7 +33,7 @@ jobs: os: linux arch: arm64 dist: noble - go: 1.22.x + go: 1.23.x env: - docker services: @@ -51,7 +51,7 @@ jobs: os: linux dist: noble sudo: required - go: 1.22.x + go: 1.23.x env: - azure-linux git: @@ -84,7 +84,7 @@ jobs: if: type = push os: osx osx_image: xcode14.2 - go: 1.22.x + go: 1.23.x env: - azure-osx git: @@ -101,7 +101,7 @@ jobs: os: linux arch: amd64 dist: noble - go: 1.22.x + go: 1.23.x script: - travis_wait 45 go run build/ci.go test $TEST_PACKAGES @@ -109,7 +109,7 @@ jobs: if: type = push os: linux dist: noble - go: 1.21.x + go: 1.22.x script: - travis_wait 45 go run build/ci.go test $TEST_PACKAGES @@ -118,7 +118,7 @@ jobs: if: type = cron || (type = push && tag ~= /^v[0-9]/) os: linux dist: noble - go: 1.22.x + go: 1.23.x env: - ubuntu-ppa git: @@ -134,7 +134,7 @@ jobs: if: type = cron os: linux dist: noble - go: 1.22.x + go: 1.23.x env: - azure-purge git: @@ -147,7 +147,7 @@ jobs: if: type = cron os: linux dist: noble - go: 1.22.x + go: 1.23.x env: - racetests script: diff --git a/Dockerfile b/Dockerfile index 63b92e082529..56c31bad2665 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.22-alpine as builder +FROM golang:1.23-alpine as builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/Dockerfile.alltools b/Dockerfile.alltools index bdefd9540c7d..c7871364ad98 100644 --- a/Dockerfile.alltools +++ b/Dockerfile.alltools @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.22-alpine as builder +FROM golang:1.23-alpine as builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/README.md b/README.md index 0d5b7872124a..a32ebde02df0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ archives are published at https://geth.ethereum.org/downloads/. For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth). -Building `geth` requires both a Go (version 1.21 or later) and a C compiler. You can install +Building `geth` requires both a Go (version 1.22 or later) and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run ```shell diff --git a/build/checksums.txt b/build/checksums.txt index 5a25229885bd..432e36150580 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,55 +5,55 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.22.6 +# version:golang 1.23.0 # https://go.dev/dl/ -9e48d99d519882579917d8189c17e98c373ce25abaebb98772e2927088992a51 go1.22.6.src.tar.gz -eeb0cc42120cbae6d3695dae2e5420fa0e93a5db957db139b55efdb879dd9856 go1.22.6.aix-ppc64.tar.gz -b47ac340f0b072943fed1f558a26eb260cc23bd21b8af175582e9103141d465b go1.22.6.darwin-amd64.pkg -9c3c0124b01b5365f73a1489649f78f971ecf84844ad9ca58fde133096ddb61b go1.22.6.darwin-amd64.tar.gz -14d0355ec1c0eeb213a16efa8635fac1f16067ef78a8173abf9a8c7b805e551e go1.22.6.darwin-arm64.pkg -ebac39fd44fc22feed1bb519af431c84c55776e39b30f4fd62930da9c0cfd1e3 go1.22.6.darwin-arm64.tar.gz -3695b10c722a4920c8a736284f8820c142e1e752f3a87f797a45c64366f7a173 go1.22.6.dragonfly-amd64.tar.gz -a9b9570c80294a664d50b566d6bd1aa42465997d2d76a57936b32f55f5c69c63 go1.22.6.freebsd-386.tar.gz -424a5618406800365fe3ad96a795fb55ce394bea3ff48eaf56d292bf7a916d1e go1.22.6.freebsd-amd64.tar.gz -e0dce3a6dbe8e7e054d329dd4cb403935c63c0f7e22e693077aa60e12018b883 go1.22.6.freebsd-arm.tar.gz -34930b01f58889c71f7a78c51c6c3bd2ce289ac7862c76dab691303cfa935fd1 go1.22.6.freebsd-arm64.tar.gz -4c9d630e55d4d600a5b4297e59620c3bdfe63a441981682b3638e2fdda228a44 go1.22.6.freebsd-riscv64.tar.gz -9ed63feaf2ef56c56f1cf0d9d3fab4006efd22a38e2f1f5252e95c6ac09332f3 go1.22.6.illumos-amd64.tar.gz -9e680027b058beab10ce5938607660964b6d2c564bf50bdb01aa090dc5beda98 go1.22.6.linux-386.tar.gz -999805bed7d9039ec3da1a53bfbcafc13e367da52aa823cb60b68ba22d44c616 go1.22.6.linux-amd64.tar.gz -c15fa895341b8eaf7f219fada25c36a610eb042985dc1a912410c1c90098eaf2 go1.22.6.linux-arm64.tar.gz -b566484fe89a54c525dd1a4cbfec903c1f6e8f0b7b3dbaf94c79bc9145391083 go1.22.6.linux-armv6l.tar.gz -1ee6e1896aea856142d2af7045cea118995b39404aa61afd12677d023d47ee69 go1.22.6.linux-loong64.tar.gz -fdd0e1a3e178f9bc79adf6ff1e3de4554ce581b4c468fd6e113c43fbbbe1eec6 go1.22.6.linux-mips.tar.gz -d3e5a621fc5a07759e503a971af0b28ded6a7d6f5604ab511f51f930a18dd3e4 go1.22.6.linux-mips64.tar.gz -01547606c5b5c1b0e5587b3afd65172860d2f4755e523785832905759ecce2d7 go1.22.6.linux-mips64le.tar.gz -2cd771416ae03c11240cfdb551d66ab9a941077664f3727b966f94386c23b0fa go1.22.6.linux-mipsle.tar.gz -6ef61d517777925e6bdb0321ea42d5f60acc20c1314dd902b9d0bfa3a5fd4fca go1.22.6.linux-ppc64.tar.gz -9d99fce3f6f72a76630fe91ec0884dfe3db828def4713368424900fa98bb2bd6 go1.22.6.linux-ppc64le.tar.gz -30be9c9b9cc4f044d4da9a33ee601ab7b3aff4246107d323a79e08888710754e go1.22.6.linux-riscv64.tar.gz -82f3bae3ddb4ede45b848db48c5486fadb58551e74507bda45484257e7194a95 go1.22.6.linux-s390x.tar.gz -85b2eb9d40a930bd3e75d0096a6eb5847aac86c5085e6d13a5845e9ef03f8d4b go1.22.6.netbsd-386.tar.gz -6e9acbdc34fb2a942d547c47c9c1989bb6e32b4a37d57fb312499e2bb33b46b7 go1.22.6.netbsd-amd64.tar.gz -e6eff3cf0038f2a9b0c9e01e228577a783bddcd8051222a3d949e24ee392e769 go1.22.6.netbsd-arm.tar.gz -43a7e2ba22da700b844f7561e3dd5434540ed6c9781be2e9c42e8a8cbf558f8e go1.22.6.netbsd-arm64.tar.gz -a90b758ccb45d8a17af8e140fafa1e97607de5a7ecd53a4c55f69258bfb043d0 go1.22.6.openbsd-386.tar.gz -cc13436c4a644e55bedcea65981eb80ca8317b39b129f5563ab3b6da1391bd47 go1.22.6.openbsd-amd64.tar.gz -aee34f61ba2b0a8f2618f5c7065e20da7714ce7651680509eda30728fe01ee88 go1.22.6.openbsd-arm.tar.gz -c67d57daf8baada93c69c8fb02401270cd33159730b1f2d70d9e724ba1a918cf go1.22.6.openbsd-arm64.tar.gz -03e1f96002e94a6b381bcf66a0a62b9d5f63148682a780d727840ad540185c7c go1.22.6.openbsd-ppc64.tar.gz -0ac2b5bbe2c8a293d284512630e629bf0578aaa7b7b1f39ac4ee182c7924aaad go1.22.6.plan9-386.tar.gz -f9afdab8a72a8d874f023f5605482cc94160843ac768dbd840e6f772d16578c7 go1.22.6.plan9-amd64.tar.gz -4b9f01a47e6a29d57cbb3097b6770583336cef9c8f0d51d3d1451e42a851002e go1.22.6.plan9-arm.tar.gz -46c2552ac7b8d6314a52e14e0a0761aaeebdd6aba5f531de386f4cf2b66ec723 go1.22.6.solaris-amd64.tar.gz -a57821dab76af1ef7a6b62db1628f0caa74343e0c7cb829df9ce8ea0713a3e8e go1.22.6.windows-386.msi -eb734bacc9aabca1273b61dd392bb84a9bb33783f5e2fff2cd6ab9885bbefbe6 go1.22.6.windows-386.zip -1238a3e6892eb8a0eb3fe0640e18ab82ca21cc1a933f16897b2ad081f057b5da go1.22.6.windows-amd64.msi -6023083a6e4d3199b44c37e9ba7b25d9674da20fd846a35ee5f9589d81c21a6a go1.22.6.windows-amd64.zip -6791218c568a3d000cb36317506541d7fd67e7cfe613baaf361ca36cad5e2cd5 go1.22.6.windows-arm.msi -ee41ca83bb07c4fd46a1d6b2d083519bb8ca156fcd9db37ee711234d43126e2f go1.22.6.windows-arm.zip -91c6b3376612095315a0aeae4b03e3da34fabe9dfd4532d023e2a70f913cf22a go1.22.6.windows-arm64.msi -7cf55f357ba8116cd3bff992980e20a704ba451b3dab341cf1787b133d900512 go1.22.6.windows-arm64.zip +42b7a8e80d805daa03022ed3fde4321d4c3bf2c990a144165d01eeecd6f699c6 go1.23.0.src.tar.gz +257f8560bb4001fb81a5e0ee84f32fecbe18d4450343c9556557d296786847b6 go1.23.0.aix-ppc64.tar.gz +bc91d2573939a01731413fac0884c329606c1c168883692131ce772669caf27b go1.23.0.darwin-amd64.pkg +ffd070acf59f054e8691b838f274d540572db0bd09654af851e4e76ab88403dc go1.23.0.darwin-amd64.tar.gz +d73ae741ed449ea842238f76f4b02935277eb867689f84ace0640965b2caf700 go1.23.0.darwin-arm64.pkg +b770812aef17d7b2ea406588e2b97689e9557aac7e646fe76218b216e2c51406 go1.23.0.darwin-arm64.tar.gz +8fd2ab5ac8629fc97d25a056693e23f332446603dd3c2b764ccb496872004b0c go1.23.0.dragonfly-amd64.tar.gz +2c9b76ead3c44f5b3e40e10b980075addb837f2dd05dafe7c0e4c611fd239753 go1.23.0.freebsd-386.tar.gz +2c2252902b87ba605fdc0b12b4c860fe6553c0c5483c12cc471756ebdd8249fe go1.23.0.freebsd-amd64.tar.gz +8ec48b8d99a515644ae00e79d093ad3b7645dcaf2a19c0a9c0d97916187f4514 go1.23.0.freebsd-arm.tar.gz +f476bbe8efb0db18155671840545370bfb73903fec04ea897d510569dab16d9c go1.23.0.freebsd-arm64.tar.gz +b0e254b2ea5752b4f1c69934ae43a44bbabf98e0c2843af44e1b6d12390eb551 go1.23.0.freebsd-riscv64.tar.gz +09716dcc7a2e19891b3d1e2ea68a1aab22838fc664cdc5f82d5f8eef05db78cf go1.23.0.illumos-amd64.tar.gz +0e8a7340c2632e6fb5088d60f95b52be1f8303143e04cd34e9b2314fafc24edd go1.23.0.linux-386.tar.gz +905a297f19ead44780548933e0ff1a1b86e8327bb459e92f9c0012569f76f5e3 go1.23.0.linux-amd64.tar.gz +62788056693009bcf7020eedc778cdd1781941c6145eab7688bd087bce0f8659 go1.23.0.linux-arm64.tar.gz +0efa1338e644d7f74064fa7f1016b5da7872b2df0070ea3b56e4fef63192e35b go1.23.0.linux-armv6l.tar.gz +dc8f723ce1a236e85c8b56d1e6749e270314e99dd41b80a58355e7ffcf9ea857 go1.23.0.linux-loong64.tar.gz +3332cc76c73c05b3413cdecccffc29aaa3469f87db8ed9f9b784ebb527ca5352 go1.23.0.linux-mips.tar.gz +0ed5cee92433d09fd0816ec5adfbf4b16d712944e833f6342bbe2df18f7826ae go1.23.0.linux-mips64.tar.gz +06a579dd6d1f9a84bc43cab063e7c759a92a6d4dd01fec3d860f22a32df93406 go1.23.0.linux-mips64le.tar.gz +d522770d32d6ee963f61331a695c4f8a730f2445b965d8d56db0a2e75c62af57 go1.23.0.linux-mipsle.tar.gz +8c884cb4f2593d897f58ec1b0f23f303acf5c78fd101e76cb48d6cb1fe5e90e7 go1.23.0.linux-ppc64.tar.gz +8b26e20d4d43a4d7641cddbdc0298d7ba3804d910a9e06cda7672970dbf2829d go1.23.0.linux-ppc64le.tar.gz +87726205f1a283247f877ccae8ce147ff4e77ac802382647ac52256eb5642c7 go1.23.0.linux-riscv64.tar.gz +003722971de02d97131a4dca2496abdab5cb175a6ee0ed9c8227c5ae9b883e69 go1.23.0.linux-s390x.tar.gz +b203fa2354874c66c40d828e96a6cce1f4e4db192414050a600d0a09b16cafd3 go1.23.0.netbsd-386.tar.gz +1502c82c3ba663959df99c2cc3ca5e7a5e1a75a1495fd26bef697d63bf1f291c go1.23.0.netbsd-amd64.tar.gz +dd50c05c7f613522c8d3d74f598bfc1862c0fee9182b738225820c9b458c7be5 go1.23.0.netbsd-arm.tar.gz +728a94a648f9502cd6175adaac2b770acde6b26f5f92dcbd8c5a1a43cc44bb10 go1.23.0.netbsd-arm64.tar.gz +e1ff3584778257778a4e3f0093b09044072423aebedf2015a550537853c46745 go1.23.0.openbsd-386.tar.gz +d2e30cdb0de256360b51a43f5e551587a7369d8c248120010d5e9432f698a6e8 go1.23.0.openbsd-amd64.tar.gz +bd5224c8a5f195f4128c866c0d418f1b61db865a1042913fd07714ed85da28db go1.23.0.openbsd-arm.tar.gz +fc0e0af3a1b4b7168455e8492a5bb6aa96ceaf46321cef1fc04187301c058890 go1.23.0.openbsd-arm64.tar.gz +ce7ea9343c7c2ef2700b55b80c45549ce39d164031e4d7bb98bec7ca593ed93d go1.23.0.openbsd-ppc64.tar.gz +93b970a8a41f6c89113daaea12e39f2580038af155e823550d0a94a5502c5e2c go1.23.0.plan9-386.tar.gz +6231862acbb6c1e02b1455b35446b9789b0b4b3230d249953e6957c393a53011 go1.23.0.plan9-amd64.tar.gz +632bdd3a1f84b2fe691203423dd2c3f536d4ab250bb52a48e9b05ebf327ae594 go1.23.0.plan9-arm.tar.gz +16773f85003d9e610960f9af67e00bc6c02359d7914de7224079538cc9c1e93d go1.23.0.solaris-amd64.tar.gz +803ef1d4f431d37ac8572ad9b0b65a4f945798208cd16b7f0588960e6b0949ba go1.23.0.windows-386.msi +09448fedec0cdf98ad12397222e0c8bfc835b1d0894c0015ced653534b8d7427 go1.23.0.windows-386.zip +93e1cf580893303d0f6ac10647335de9f0768199d7027d8a361639cae6ab3145 go1.23.0.windows-amd64.msi +d4be481ef73079ee0ad46081d278923aa3fd78db1b3cf147172592f73e14c1ac go1.23.0.windows-amd64.zip +2a361c94879258309343e88c5de5df17f6425df4d74bdf7e333b7298b29f6f29 go1.23.0.windows-arm.msi +006d93712246a672bdb57906dd5bffcab62facc36169e51a27d52340cdac661f go1.23.0.windows-arm.zip +a876ed2bb130d9146152aaf391638abd79dcb3a4f2e9cc59b78709dcef29ced3 go1.23.0.windows-arm64.msi +0be62073ef8f5a2d3b9adcefddf18c417dab0a7975c71488ac2694856e2ff976 go1.23.0.windows-arm64.zip # version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ diff --git a/go.mod b/go.mod index 909add8be662..8b18ddfce232 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/ethereum/go-ethereum -go 1.21 +go 1.22 + +toolchain go1.22.0 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 diff --git a/internal/build/download.go b/internal/build/download.go index 206c51dce1e3..50268227a501 100644 --- a/internal/build/download.go +++ b/internal/build/download.go @@ -57,7 +57,7 @@ func (db *ChecksumDB) Verify(path string) error { } fileHash := hex.EncodeToString(h.Sum(nil)) if !db.findHash(filepath.Base(path), fileHash) { - return fmt.Errorf("invalid file hash %s for %s", fileHash, filepath.Base(path)) + return fmt.Errorf("invalid file hash: %s %s", fileHash, filepath.Base(path)) } return nil } @@ -103,7 +103,6 @@ func (db *ChecksumDB) DownloadFile(url, dstPath string) error { if err != nil { return err } - return db.Verify(dstPath) } From 15fb0dcc6732f3b04f8d3b13e309afd723364ba5 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 20 Aug 2024 07:54:28 -0600 Subject: [PATCH 483/571] rpc: add timeout to rpc client Unsubscribe (#30318) Fixes #30156 This adds a repro of the linked issue. I fixed it by adding a timeout when issuing the call to unsubscribe. --- rpc/client.go | 1 + rpc/client_test.go | 64 +++++++++++++++++++++++++++++++++++++++++++++ rpc/subscription.go | 5 +++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/rpc/client.go b/rpc/client.go index 05b87ae96cb7..f9a8f1116b2b 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -45,6 +45,7 @@ var ( const ( defaultDialTimeout = 10 * time.Second // used if context has no deadline subscribeTimeout = 10 * time.Second // overall timeout eth_subscribe, rpc_modules calls + unsubscribeTimeout = 10 * time.Second // timeout for *_unsubscribe calls ) const ( diff --git a/rpc/client_test.go b/rpc/client_test.go index 01c326afb017..b7607adfce9d 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -518,6 +518,70 @@ func TestClientCloseUnsubscribeRace(t *testing.T) { } } +// unsubscribeBlocker will wait for the quit channel to process an unsubscribe +// request. +type unsubscribeBlocker struct { + ServerCodec + quit chan struct{} +} + +func (b *unsubscribeBlocker) readBatch() ([]*jsonrpcMessage, bool, error) { + msgs, batch, err := b.ServerCodec.readBatch() + for _, msg := range msgs { + if msg.isUnsubscribe() { + <-b.quit + } + } + return msgs, batch, err +} + +// TestUnsubscribeTimeout verifies that calling the client's Unsubscribe +// function will eventually timeout and not block forever in case the serve does +// not respond. +// It reproducers the issue https://github.com/ethereum/go-ethereum/issues/30156 +func TestUnsubscribeTimeout(t *testing.T) { + srv := NewServer() + srv.RegisterName("nftest", new(notificationTestService)) + + // Setup middleware to block on unsubscribe. + p1, p2 := net.Pipe() + blocker := &unsubscribeBlocker{ServerCodec: NewCodec(p1), quit: make(chan struct{})} + defer close(blocker.quit) + + // Serve the middleware. + go srv.ServeCodec(blocker, OptionMethodInvocation|OptionSubscriptions) + defer srv.Stop() + + // Create the client on the other end of the pipe. + cfg := new(clientConfig) + client, _ := newClient(context.Background(), cfg, func(context.Context) (ServerCodec, error) { + return NewCodec(p2), nil + }) + defer client.Close() + + // Start subscription. + sub, err := client.Subscribe(context.Background(), "nftest", make(chan int), "someSubscription", 1, 1) + if err != nil { + t.Fatalf("failed to subscribe: %v", err) + } + + // Now on a separate thread, attempt to unsubscribe. Since the middleware + // won't return, the function will only return if it times out on the request. + done := make(chan struct{}) + go func() { + sub.Unsubscribe() + done <- struct{}{} + }() + + // Wait for the timeout. If the expected time for the timeout elapses, the + // test is considered failed. + select { + case <-done: + case <-time.After(unsubscribeTimeout + 3*time.Second): + t.Fatalf("Unsubscribe did not return within %s", unsubscribeTimeout) + } +} + // unsubscribeRecorder collects the subscription IDs of *_unsubscribe calls. type unsubscribeRecorder struct { ServerCodec diff --git a/rpc/subscription.go b/rpc/subscription.go index d77c655bf900..9e400c8b6080 100644 --- a/rpc/subscription.go +++ b/rpc/subscription.go @@ -371,5 +371,8 @@ func (sub *ClientSubscription) unmarshal(result json.RawMessage) (interface{}, e func (sub *ClientSubscription) requestUnsubscribe() error { var result interface{} - return sub.client.Call(&result, sub.namespace+unsubscribeMethodSuffix, sub.subid) + ctx, cancel := context.WithTimeout(context.Background(), unsubscribeTimeout) + defer cancel() + err := sub.client.CallContext(ctx, &result, sub.namespace+unsubscribeMethodSuffix, sub.subid) + return err } From 0fde5067c38dc6c9dcdb4dfe85d5d3421b751520 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Tue, 20 Aug 2024 09:59:16 -0400 Subject: [PATCH 484/571] cmd/devp2p: require dns:read, dns:edit permissions for cloudflare deploy (#30326) This PR adds the `dns:read` and `dns:edit` permissions to the required set of permissions checked before deploying an ENR tree to Cloudflare. These permissions are necessary for a successful publish. **Background**: The current logic for `devp2p dns to-cloudflare` checks for `zone:edit` and `zone:read` permissions. However, when running the command with only these two permissions, the following error occurs: ``` wrong permissions on zone REMOVED-ZONE: map[#zone:edit:false #zone:read:true] ``` Adding `zone:read` and `zone:edit` to the API token led to a different error: ``` INFO [08-19|14:06:16.782] Retrieving existing TXT records on pos-nodes.hardfork.dev Authentication error (10000) ``` This suggested that additional permissions were required. I added `dns:read`, but encountered another error: ``` INFO [08-19|14:11:42.342] Retrieving existing TXT records on pos-nodes.hardfork.dev INFO [08-19|14:11:42.851] Updating DNS entries failed to publish REMOVED.pos-nodes.hardfork.dev: Authentication error (10000) ``` Finally, after adding both `dns:read` and `dns:edit` permissions, the command executed successfully with the following output: ``` INFO [08-19|14:13:07.677] Checking Permissions on zone REMOVED-ZONE INFO [08-19|14:13:08.014] Retrieving existing TXT records on pos-nodes.hardfork.dev INFO [08-19|14:13:08.440] Updating DNS entries INFO [08-19|14:13:08.440] "Updating pos-nodes.hardfork.dev from \"enrtree-root:v1 e=FSED3EDKEKRDDFMCLP746QY6CY l=FDXN3SN67NA5DKA4J2GOK7BVQI seq=1 sig=Glja2c9RviRqOpaaHR0MnHsQwU76nJXadJwFeiXpp8MRTVIhvL0LIireT0yE3ETZArGEmY5Ywz3FVHZ3LR5JTAE\" to \"enrtree-root:v1 e=AB66M4ULYD5OYN4XFFCPVZRLUM l=FDXN3SN67NA5DKA4J2GOK7BVQI seq=1 sig=H8cqDzu0FAzBplK4g3yudhSaNtszIebc2aj4oDm5a5ZE5PAg-xpCnQgVE_53CsgsqQpalD9byafx_FrUT61sagA\"" INFO [08-19|14:13:16.932] Updated DNS entries new=32 updated=1 untouched=100 INFO [08-19|14:13:16.932] Deleting stale DNS entries INFO [08-19|14:13:24.663] Deleted stale DNS entries count=31 ``` With this PR, the required permissions for deploying an ENR tree to Cloudflare now include `zone:read`, `zone:edit`, `dns:read`, and `dns:edit`. The initial check now includes all of the necessary permissions and indicates in the error message which permissions are missing: ``` INFO [08-19|14:17:20.339] Checking Permissions on zone REMOVED-ZONE wrong permissions on zone REMOVED-ZONE: map[#dns_records:edit:false #dns_records:read:false #zone:edit:false #zone:read:true] ``` --- cmd/devp2p/dns_cloudflare.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/devp2p/dns_cloudflare.go b/cmd/devp2p/dns_cloudflare.go index a3cc69cf1925..b8aded7b0d2e 100644 --- a/cmd/devp2p/dns_cloudflare.go +++ b/cmd/devp2p/dns_cloudflare.go @@ -88,7 +88,8 @@ func (c *cloudflareClient) checkZone(name string) error { if !strings.HasSuffix(name, "."+zone.Name) { return fmt.Errorf("CloudFlare zone name %q does not match name %q to be deployed", zone.Name, name) } - needPerms := map[string]bool{"#zone:edit": false, "#zone:read": false} + // Necessary permissions for Cloudlare management - Zone:Read, DNS:Read, Zone:Edit, DNS:Edit + needPerms := map[string]bool{"#zone:edit": false, "#zone:read": false, "#dns_records:read": false, "#dns_records:edit": false} for _, perm := range zone.Permissions { if _, ok := needPerms[perm]; ok { needPerms[perm] = true From 3c37db798995f1f64b69587e2e534b3014613a22 Mon Sep 17 00:00:00 2001 From: stevemilk Date: Tue, 20 Aug 2024 21:59:48 +0800 Subject: [PATCH 485/571] all: clean up goerli flag and config (#30289) Co-authored-by: lightclient --- README.md | 12 ++++++------ beacon/blsync/config.go | 17 +---------------- cmd/blsync/main.go | 1 - cmd/clef/README.md | 2 +- cmd/clef/main.go | 2 +- cmd/devp2p/README.md | 2 +- cmd/devp2p/nodesetcmd.go | 2 -- cmd/geth/chaincmd.go | 2 -- cmd/geth/consolecmd_test.go | 10 +++++----- cmd/geth/main.go | 4 ---- cmd/utils/flags.go | 27 +++------------------------ consensus/clique/clique_test.go | 10 +++++----- core/forkid/forkid_test.go | 19 ------------------- core/genesis.go | 16 ---------------- core/genesis_alloc.go | 1 - core/genesis_test.go | 20 +++++--------------- core/state/pruner/pruner.go | 9 ++++----- eth/protocols/eth/handler.go | 2 +- internal/era/era_test.go | 1 - params/bootnodes.go | 19 ------------------- params/config.go | 28 ---------------------------- 21 files changed, 33 insertions(+), 173 deletions(-) diff --git a/README.md b/README.md index a32ebde02df0..182464c639c5 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ This command will: This tool is optional and if you leave it out you can always attach it to an already running `geth` instance with `geth attach`. -### A Full node on the Görli test network +### A Full node on the Holesky test network Transitioning towards developers, if you'd like to play around with creating Ethereum contracts, you almost certainly would like to do that without any real money involved until @@ -98,23 +98,23 @@ network, you want to join the **test** network with your node, which is fully eq the main network, but with play-Ether only. ```shell -$ geth --goerli console +$ geth --holesky console ``` The `console` subcommand has the same meaning as above and is equally useful on the testnet too. -Specifying the `--goerli` flag, however, will reconfigure your `geth` instance a bit: +Specifying the `--holesky` flag, however, will reconfigure your `geth` instance a bit: - * Instead of connecting to the main Ethereum network, the client will connect to the Görli + * Instead of connecting to the main Ethereum network, the client will connect to the Holesky test network, which uses different P2P bootnodes, different network IDs and genesis states. * Instead of using the default data directory (`~/.ethereum` on Linux for example), `geth` - will nest itself one level deeper into a `goerli` subfolder (`~/.ethereum/goerli` on + will nest itself one level deeper into a `holesky` subfolder (`~/.ethereum/holesky` on Linux). Note, on OSX and Linux this also means that attaching to a running testnet node requires the use of a custom endpoint since `geth attach` will try to attach to a production node endpoint by default, e.g., - `geth attach /goerli/geth.ipc`. Windows users are not affected by + `geth attach /holesky/geth.ipc`. Windows users are not affected by this. *Note: Although some internal protective measures prevent transactions from diff --git a/beacon/blsync/config.go b/beacon/blsync/config.go index 93ed81306c98..efc44b47d1a9 100644 --- a/beacon/blsync/config.go +++ b/beacon/blsync/config.go @@ -56,32 +56,17 @@ var ( AddFork("DENEB", 132608, []byte{144, 0, 0, 115}), Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"), } - - GoerliConfig = lightClientConfig{ - ChainConfig: (&types.ChainConfig{ - GenesisValidatorsRoot: common.HexToHash("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb"), - GenesisTime: 1614588812, - }). - AddFork("GENESIS", 0, []byte{0, 0, 16, 32}). - AddFork("ALTAIR", 36660, []byte{1, 0, 16, 32}). - AddFork("BELLATRIX", 112260, []byte{2, 0, 16, 32}). - AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}). - AddFork("DENEB", 231680, []byte{4, 0, 16, 32}), - Checkpoint: common.HexToHash("0x53a0f4f0a378e2c4ae0a9ee97407eb69d0d737d8d8cd0a5fb1093f42f7b81c49"), - } ) func makeChainConfig(ctx *cli.Context) lightClientConfig { var config lightClientConfig customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name) - utils.CheckExclusive(ctx, utils.MainnetFlag, utils.GoerliFlag, utils.SepoliaFlag, utils.BeaconConfigFlag) + utils.CheckExclusive(ctx, utils.MainnetFlag, utils.SepoliaFlag, utils.BeaconConfigFlag) switch { case ctx.Bool(utils.MainnetFlag.Name): config = MainnetConfig case ctx.Bool(utils.SepoliaFlag.Name): config = SepoliaConfig - case ctx.Bool(utils.GoerliFlag.Name): - config = GoerliConfig default: if !customConfig { config = MainnetConfig diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go index 854c99703c5c..f9b8575edf9c 100644 --- a/cmd/blsync/main.go +++ b/cmd/blsync/main.go @@ -45,7 +45,6 @@ func main() { //TODO datadir for optional permanent database utils.MainnetFlag, utils.SepoliaFlag, - utils.GoerliFlag, utils.BlsyncApiFlag, utils.BlsyncJWTSecretFlag, }, diff --git a/cmd/clef/README.md b/cmd/clef/README.md index b7018a5f41ed..a73ffd5b455a 100644 --- a/cmd/clef/README.md +++ b/cmd/clef/README.md @@ -29,7 +29,7 @@ GLOBAL OPTIONS: --loglevel value log level to emit to the screen (default: 4) --keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore") --configdir value Directory for Clef configuration (default: "$HOME/.clef") - --chainid value Chain id to use for signing (1=mainnet, 5=Goerli) (default: 1) + --chainid value Chain id to use for signing (1=mainnet, 17000=Holesky) (default: 1) --lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength --nousb Disables monitoring for and managing USB hardware wallets --pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm") diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 88d4c99e785a..dde4ae853ff8 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -100,7 +100,7 @@ var ( chainIdFlag = &cli.Int64Flag{ Name: "chainid", Value: params.MainnetChainConfig.ChainID.Int64(), - Usage: "Chain id to use for signing (1=mainnet, 5=Goerli)", + Usage: "Chain id to use for signing (1=mainnet, 17000=Holesky)", } rpcPortFlag = &cli.IntFlag{ Name: "http.port", diff --git a/cmd/devp2p/README.md b/cmd/devp2p/README.md index 284dfe0a454d..ad2985b4b0fb 100644 --- a/cmd/devp2p/README.md +++ b/cmd/devp2p/README.md @@ -44,7 +44,7 @@ set to standard output. The following filters are supported: - `-limit ` limits the output set to N entries, taking the top N nodes by score - `-ip ` filters nodes by IP subnet - `-min-age ` filters nodes by 'first seen' time -- `-eth-network ` filters nodes by "eth" ENR entry +- `-eth-network ` filters nodes by "eth" ENR entry - `-les-server` filters nodes by LES server support - `-snap` filters nodes by snap protocol support diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go index f0773edfb81f..c8177f049d43 100644 --- a/cmd/devp2p/nodesetcmd.go +++ b/cmd/devp2p/nodesetcmd.go @@ -230,8 +230,6 @@ func ethFilter(args []string) (nodeFilter, error) { switch args[0] { case "mainnet": filter = forkid.NewStaticFilter(params.MainnetChainConfig, core.DefaultGenesisBlock().ToBlock()) - case "goerli": - filter = forkid.NewStaticFilter(params.GoerliChainConfig, core.DefaultGoerliGenesisBlock().ToBlock()) case "sepolia": filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock()) case "holesky": diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 9450c09e7e2b..ca2f00512b34 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -425,8 +425,6 @@ func importHistory(ctx *cli.Context) error { network = "mainnet" case ctx.Bool(utils.SepoliaFlag.Name): network = "sepolia" - case ctx.Bool(utils.GoerliFlag.Name): - network = "goerli" } } else { // No network flag set, try to determine network based on files diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index 33d6d4bbc421..ffaf17741fc9 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -30,7 +30,7 @@ import ( ) const ( - ipcAPIs = "admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0" + ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0" httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0" ) @@ -38,10 +38,10 @@ const ( // memory and disk IO. If the args don't set --datadir, the // child g gets a temporary data directory. func runMinimalGeth(t *testing.T, args ...string) *testgeth { - // --goerli to make the 'writing genesis to disk' faster (no accounts) + // --holesky to make the 'writing genesis to disk' faster (no accounts) // --networkid=1337 to avoid cache bump // --syncmode=full to avoid allocating fast sync bloom - allArgs := []string{"--goerli", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0", + allArgs := []string{"--holesky", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0", "--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64", "--datadir.minfreedisk", "0"} return runGeth(t, append(allArgs, args...)...) @@ -62,7 +62,7 @@ func TestConsoleWelcome(t *testing.T) { geth.SetTemplateFunc("gover", runtime.Version) geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") }) geth.SetTemplateFunc("niltime", func() string { - return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") + return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") }) geth.SetTemplateFunc("apis", func() string { return ipcAPIs }) @@ -131,7 +131,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { attach.SetTemplateFunc("gover", runtime.Version) attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") }) attach.SetTemplateFunc("niltime", func() string { - return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") + return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") }) attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") }) attach.SetTemplateFunc("datadir", func() string { return geth.Datadir }) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a37bb5f98789..9354684b718c 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -289,9 +289,6 @@ func main() { func prepare(ctx *cli.Context) { // If we're running a known preset, log it for convenience. switch { - case ctx.IsSet(utils.GoerliFlag.Name): - log.Info("Starting Geth on Görli testnet...") - case ctx.IsSet(utils.SepoliaFlag.Name): log.Info("Starting Geth on Sepolia testnet...") @@ -324,7 +321,6 @@ func prepare(ctx *cli.Context) { // Make sure we're not on any supported preconfigured testnet either if !ctx.IsSet(utils.HoleskyFlag.Name) && !ctx.IsSet(utils.SepoliaFlag.Name) && - !ctx.IsSet(utils.GoerliFlag.Name) && !ctx.IsSet(utils.DeveloperFlag.Name) { // Nope, we're really on mainnet. Bump that cache up! log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b9fa3b8b4e5a..22dd6645de7a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -134,7 +134,7 @@ var ( } NetworkIdFlag = &cli.Uint64Flag{ Name: "networkid", - Usage: "Explicitly set network id (integer)(For testnets: use --goerli, --sepolia, --holesky instead)", + Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky instead)", Value: ethconfig.Defaults.NetworkId, Category: flags.EthCategory, } @@ -143,11 +143,6 @@ var ( Usage: "Ethereum mainnet", Category: flags.EthCategory, } - GoerliFlag = &cli.BoolFlag{ - Name: "goerli", - Usage: "Görli network: pre-configured proof-of-authority test network", - Category: flags.EthCategory, - } SepoliaFlag = &cli.BoolFlag{ Name: "sepolia", Usage: "Sepolia network: pre-configured proof-of-work test network", @@ -965,7 +960,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server. var ( // TestnetFlags is the flag group of all built-in supported testnets. TestnetFlags = []cli.Flag{ - GoerliFlag, SepoliaFlag, HoleskyFlag, } @@ -988,9 +982,6 @@ var ( // then a subdirectory of the specified datadir will be used. func MakeDataDir(ctx *cli.Context) string { if path := ctx.String(DataDirFlag.Name); path != "" { - if ctx.Bool(GoerliFlag.Name) { - return filepath.Join(path, "goerli") - } if ctx.Bool(SepoliaFlag.Name) { return filepath.Join(path, "sepolia") } @@ -1042,7 +1033,7 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { // // 1. --bootnodes flag // 2. Config file -// 3. Network preset flags (e.g. --goerli) +// 3. Network preset flags (e.g. --holesky) // 4. default to mainnet nodes func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls := params.MainnetBootnodes @@ -1057,8 +1048,6 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls = params.HoleskyBootnodes case ctx.Bool(SepoliaFlag.Name): urls = params.SepoliaBootnodes - case ctx.Bool(GoerliFlag.Name): - urls = params.GoerliBootnodes } } cfg.BootstrapNodes = mustParseBootnodes(urls) @@ -1484,8 +1473,6 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) { cfg.DataDir = ctx.String(DataDirFlag.Name) case ctx.Bool(DeveloperFlag.Name): cfg.DataDir = "" // unless explicitly requested, use memory databases - case ctx.Bool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir(): - cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli") case ctx.Bool(SepoliaFlag.Name) && cfg.DataDir == node.DefaultDataDir(): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia") case ctx.Bool(HoleskyFlag.Name) && cfg.DataDir == node.DefaultDataDir(): @@ -1657,7 +1644,7 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) { // SetEthConfig applies eth-related command line flags to the config. func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // Avoid conflicting network flags - CheckExclusive(ctx, MainnetFlag, DeveloperFlag, GoerliFlag, SepoliaFlag, HoleskyFlag) + CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag) CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer // Set configurations from CLI flags @@ -1827,12 +1814,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { } cfg.Genesis = core.DefaultSepoliaGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash) - case ctx.Bool(GoerliFlag.Name): - if !ctx.IsSet(NetworkIdFlag.Name) { - cfg.NetworkId = 5 - } - cfg.Genesis = core.DefaultGoerliGenesisBlock() - SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash) case ctx.Bool(DeveloperFlag.Name): if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 1337 @@ -2154,8 +2135,6 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { genesis = core.DefaultHoleskyGenesisBlock() case ctx.Bool(SepoliaFlag.Name): genesis = core.DefaultSepoliaGenesisBlock() - case ctx.Bool(GoerliFlag.Name): - genesis = core.DefaultGoerliGenesisBlock() case ctx.Bool(DeveloperFlag.Name): Fatalf("Developer chains are ephemeral") } diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index 8ef8dbffa974..f14c8cb5bae3 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -30,11 +30,11 @@ import ( ) // This test case is a repro of an annoying bug that took us forever to catch. -// In Clique PoA networks (Görli, etc), consecutive blocks might have -// the same state root (no block subsidy, empty block). If a node crashes, the -// chain ends up losing the recent state and needs to regenerate it from blocks -// already in the database. The bug was that processing the block *prior* to an -// empty one **also completes** the empty one, ending up in a known-block error. +// In Clique PoA networks, consecutive blocks might have the same state root (no +// block subsidy, empty block). If a node crashes, the chain ends up losing the +// recent state and needs to regenerate it from blocks already in the database. +// The bug was that processing the block *prior* to an empty one **also +// completes** the empty one, ending up in a known-block error. func TestReimportMirroredState(t *testing.T) { // Initialize a Clique chain with a single signer var ( diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index b9d346bd9051..ec6c27b48dbe 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -80,25 +80,6 @@ func TestCreation(t *testing.T) { {50000000, 2000000000, ID{Hash: checksumToBytes(0x9f3d2254), Next: 0}}, // Future Cancun block }, }, - // Goerli test cases - { - params.GoerliChainConfig, - core.DefaultGoerliGenesisBlock().ToBlock(), - []testcase{ - {0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block - {1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block - {1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block - {4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block - {4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block - {5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block - {5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // First London block - {6000000, 1678832735, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // Last London block - {6000001, 1678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // First Shanghai block - {6500002, 1705473119, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // Last Shanghai block - {6500003, 1705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // First Cancun block - {6500003, 2705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // Future Cancun block - }, - }, // Sepolia test cases { params.SepoliaChainConfig, diff --git a/core/genesis.go b/core/genesis.go index 9e213e5163b0..cbd3bcebf79d 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -196,8 +196,6 @@ func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.Gene switch blockhash { case params.MainnetGenesisHash: genesis = DefaultGenesisBlock() - case params.GoerliGenesisHash: - genesis = DefaultGoerliGenesisBlock() case params.SepoliaGenesisHash: genesis = DefaultSepoliaGenesisBlock() case params.HoleskyGenesisHash: @@ -400,8 +398,6 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { return params.HoleskyChainConfig case ghash == params.SepoliaGenesisHash: return params.SepoliaChainConfig - case ghash == params.GoerliGenesisHash: - return params.GoerliChainConfig default: return params.AllEthashProtocolChanges } @@ -539,18 +535,6 @@ func DefaultGenesisBlock() *Genesis { } } -// DefaultGoerliGenesisBlock returns the Görli network genesis block. -func DefaultGoerliGenesisBlock() *Genesis { - return &Genesis{ - Config: params.GoerliChainConfig, - Timestamp: 1548854791, - ExtraData: hexutil.MustDecode("0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - GasLimit: 10485760, - Difficulty: big.NewInt(1), - Alloc: decodePrealloc(goerliAllocData), - } -} - // DefaultSepoliaGenesisBlock returns the Sepolia network genesis block. func DefaultSepoliaGenesisBlock() *Genesis { return &Genesis{ diff --git a/core/genesis_alloc.go b/core/genesis_alloc.go index 94c4ec535889..28bb2d5c108a 100644 --- a/core/genesis_alloc.go +++ b/core/genesis_alloc.go @@ -22,6 +22,5 @@ package core // nolint: misspell const mainnetAllocData = "\xfa\x04]X\u0793\r\x83b\x011\x8e\u0189\x9agT\x06\x908'\x80t2\x80\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0793\x17bC\x0e\xa9\u00e2nWI\xaf\xdbp\xda_x\u077b\x8c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0793\x1d\x14\x80K9\x9cn\xf8\x0edWoev`\x80O\xec\v\x89\u3bb5sr@\xa0\x00\x00\u07932@5\x87\x94{\x9f\x15b*h\xd1\x04\xd5M3\xdb\xd1\u0349\x043\x87Oc,\xc6\x00\x00\u0793I~\x92\xcd\xc0\xe0\xb9c\xd7R\xb2)j\u02c7\u0682\x8b$\x89\n\x8fd\x9f\xe7\xc6\x18\x00\x00\u0793K\xfb\xe1Tk\xc6\xc6[\\~\xaaU0K8\xbb\xfe\xc6\u04c9lk\x93[\x8b\xbd@\x00\x00\u0793Z\x9c\x03\xf6\x9d\x17\xd6l\xbb\x8a\xd7!\x00\x8a\x9e\xbb\xb86\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u0793]\x0e\xe8\x15^\xc0\xa6\xffh\bU,\xa5\xf1k\xb5\xbe2:\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u0793v\"\xd8J#K\xb8\xb0x#\x0f\u03c4\xb6z\u9a2c\xae\x89%\xe1\xccQ\x99R\xf8\x00\x00\u0793{\x9f\xc3\x19\x05\xb4\x99K\x04\xc9\xe2\xcf\xdc^'pP?B\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u0793\u007fJ#\xca\x00\xcd\x04=%\u0088\x8c\x1a\xa5h\x8f\x81\xa3D\x89)\xf0\xa9[\xfb\xf7)\x00\x00\u0793\x869\u06bb\u3bac\x88{]\xc0\xe4>\x13\xbc\u0487\xd7l\x89\x10\xd0\xe3\xc8}n,\x00\x00\u0793\x89P\x86y\xab\xf8\xc7\x1b\xf6x\x16\x87\x12\x0e>j\x84XM\x89a\x94\x04\x9f0\xf7 \x00\x00\u0793\x8f\xc7\u02ed\xff\xbd\r\u007f\xe4O\x8d\xfd`\xa7\x9dr\x1a\x1c\x9c\x8965\u026d\xc5\u07a0\x00\x00\u0793\x95`\xa3\xdebxh\xf9\x1f\xa8\xbf\xe1\xc1\xb7\xaf\xaf\b\x18k\x89\x1cg\xf5\xf7\xba\xa0\xb0\x00\x00\u0793\x96\x97G\xf7\xa5\xb3\x06E\xfe\x00\xe4I\x01CZ\xce$\xcc7\x89\\(=A\x03\x94\x10\x00\x00\u0793\x9am}\xb3&g\x9bw\xc9\x03\x91\xa7Gm#\x8f;\xa3>\x89\n\xdaUGK\x814\x00\x00\u0793\x9e\xef\n\b\x86\x05n?i!\x18S\xb9\xb7E\u007f7\x82\u4262\xa8x\x06\x9b(\xe0\x00\x00\u0793\x9f\xdb\xf4N\x1fJcb\xb7i\u00daG_\x95\xa9l+\u01c9\x1e\x93\x12\x83\xcc\xc8P\x00\x00\u07d3\xa5y\u007fR\xc9\u054f\x18\x9f6\xb1\xd4]\x1b\xf6\x04\x1f/k\x8a\x01'\u0473F\x1a\xcd\x1a\x00\x00\u0793\xaaS\x81\xb2\x13\x8e\xbe\xff\xc1\x91\xd5\xd8\u00d1u;p\x98\u04895\xab\xb0\x9f\xfe\u07b6\x80\x00\u0793\xaa\xda%\xea\"\x86p\x9a\xbbB-A\x92?\u04c0\xcd\x04\u01c9#=\xf3)\x9far\x00\x00\u0793\xac\xbf\xb2\xf2ZT\x85\xc79\xefp\xa4N\xee\xeb|e\xa6o\x89\x05k\xc7^-c\x10\x00\x00\u07d3\xac\xc6\xf0\x82\xa4B\x82\x87d\xd1\x1fX\u0589J\xe4\b\xf0s\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u0793\xb2w\xb0\x99\xa8\xe8f\xca\x0e\xc6[\u02c7(O\xd1B\xa5\x82\x89j\xcb=\xf2~\x1f\x88\x00\x00\u0753\xbd\xd4\x01:\xa3\x1c\x04al+\xc9x_'\x88\xf9\x15g\x9b\x88\xb9\xf6]\x00\xf6<\x00\x00\u0793\xc2}c\xfd\xe2K\x92\xee\x8a\x1e~\xd5\xd2m\x8d\xc5\xc8;\x03\x89lk\x93[\x8b\xbd@\x00\x00\u0553\xc4\x0f\xe2\tT#P\x9b\x9f\u0677T21X\xaf#\x10\xf3\x80\u0793\xd7^\xd6\fwO\x8b:ZQs\xfb\x183\xadq\x05\xa2\u0649l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d3\u05cd\x89\xb3_G'\x16\xec\xea\xfe\xbf`\x05'\u04e1\xf9i\x8a\x05\xe0T\x9c\x962\xe1\xd8\x00\x00\u0793\xda\xe2{5\v\xae \xc5e!$\xaf]\x8b\\\xba\x00\x1e\xc1\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u0793\xdc\x01\xcb\xf4Ix\xa4.\x8d\xe8\xe46\xed\xf9B\x05\u03f6\xec\x89O\x0f\xeb\xbc\u068c\xb4\x00\x00\u07d3\u607c-\x10\xdbb\u0785\x84\x83$I\"P4\x8e\x90\xbf\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d3\xf4c\xe17\xdc\xf6%\xfb\U000fc8de\u0298\u04b9h\xcf\u007f\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\x01\x00\a9K\x8bue\xa1e\x8a\xf8\x8c\xe4cI\x915\u05b7\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x01\r\xf1\xdfK\xed#v\r-\x1c\x03x\x15\x86\xdd\xf7\x91\x8eT\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\x01\x0fJ\x98\u07e1\xd9y\x9b\xf5\u01d6\xfbU\x0e\xfb\xe7\xec\xd8w\x8a\x01\xb2\xf2\x92#b\x92\xc7\x00\x00\u07d4\x01\x15PW\x00/k\r\x18\xac\xb98\x8d;\xc8\x12\x9f\x8fz \x89H\xa4\xa9\x0f\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x01k`\xbbmg\x92\x8c)\xfd\x03\x13\xc6f\u068f\x16\x98\xd9\u0149lk\x93[\x8b\xbd@\x00\x00\u07d4\x01l\x85\xe1a;\x90\x0f\xa3W\xb8(;\x12\x0ee\xae\xfc\xdd\b\x89+]\x97\x84\xa9|\xd5\x00\x00\u07d4\x01\x84\x92H\x8b\xa1\xa2\x924\"G\xb3\x18U\xa5Y\x05\xfe\xf2i\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x01\x8f \xa2{'\xecD\x1a\xf7#\xfd\x90\x99\xf2\u02f7\x9dbc\x89uy*\x8a\xbd\xef|\x00\x00\u07d4\x01\x91\xebT~{\xf6\x97k\x9b\x1bWuFv\x1d\xe6V\"\xe2\x89lkLM\xa6\u077e\x00\x00\u07d4\x01\x9dp\x95y\xffK\xc0\x9f\xdc\xdd\xe41\xdc\x14G\xd2\xc2`\xbc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x01\xa2Z_Z\xf0\x16\x9b0\x86L;\xe4\xd7V<\xcdD\xf0\x9e\x89M\x85<\x8f\x89\b\x98\x00\x00\xe0\x94\x01\xa7\xd9\xfa}\x0e\xb1\x18\\g\xe5M\xa8<.u\xdbi\u37ca\x01\x9dJ\xdd\xd0\u063c\x96\x00\x00\u07d4\x01\xa8\x18\x13ZAB\x10\xc3|b\xb6%\xac\xa1\xa5F\x11\xac6\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\x01\xb1\xca\xe9\x1a;\x95Y\xaf\xb3<\xdcmh\x94B\xfd\xbf\xe07\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x01\xb5\xb5\xbcZ\x11\u007f\xa0\x8b4\xed\x1d\xb9D\x06\bYz\xc5H\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x01\xbb\xc1Og\xaf\x069\xaa\xb1D\x1ej\b\xd4\xceqb\t\x0f\x89F\xfc\xf6\x8f\xf8\xbe\x06\x00\x00\xe0\x94\x01\xd08\x15\xc6\x1fAkq\xa2a\n-\xab\xa5\x9f\xf6\xa6\xde[\x8a\x02\x05\xdf\xe5\v\x81\xc8.\x00\x00\u07d4\x01\u0559\xee\r_\x8c8\xab-9.,e\xb7L<\xe3\x18 \x89\x1b\xa5\xab\xf9\xe7y8\x00\x00\u07d4\x01\xe4\x05!\x12%0\u066c\x91\x11<\x06\xa0\x19\vmc\x85\v\x89Hz\x9a0E9D\x00\x00\u07d4\x01\xe6A]X{\x06T\x90\xf1\xed\u007f!\xd6\xe0\xf3\x86\xeegG\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x01\xe8d\xd3Tt\x1bB>oB\x85\x17$F\x8ct\xf5\xaa\x9c\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x01\xed_\xba\x8d.\xabg:\xec\x04-0\xe4\xe8\xa6\x11\xd8\xc5Z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x01\xfb\x8e\xc1$%\xa0O\x81>F\xc5L\x05t\x8c\xa6\xb2\x9a\xa9\x89\x0e\x15s\x03\x85F|\x00\x00\u07d4\x01\xff\x1e\xb1\u07adP\xa7\xf2\xf9c\x8f\xde\xe6\xec\xcf:{*\u0209 \x86\xac5\x10R`\x00\x00\u07d4\x02\x03b\u00ed\xe8x\u0290\u05b2\u0609\xa4\xccU\x10\xee\xd5\xf3\x898\x88\xe8\xb3\x11\xad\xb3\x80\x00\u07d4\x02\x03\xae\x01\xd4\xc4\x1c\xae\x18e\xe0K\x1f[S\xcd\xfa\xec\xae1\x896\x89\xcd\u03b2\x8c\xd7\x00\x00\u07d4\x02\b\x93a\xa3\xfetQ\xfb\x1f\x87\xf0\x1a-\x86fS\xdc\v\a\x89\x02*\xc7H2\xb5\x04\x00\x00\u07d4\x02\x1fi\x04=\xe8\x8cI\x17\xca\x10\xf1\x84(\x97\xee\xc0X\x9c|\x89kD\u03f8\x14\x87\xf4\x00\x00\u07d4\x02)\x0f\xb5\xf9\xa5\x17\xf8(E\xac\xde\xca\x0f\xc8F\x03\x9b\xe23\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x029\xb4\xf2\x1f\x8e\x05\xcd\x01Q++\xe7\xa0\xe1\x8am\x97F\a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x02Gr\x12\xff\xddu\xe5\x15VQ\xb7e\x06\xb1dfq\xa1\xeb\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x02J\t\x8a\xe7\x02\xbe\xf5@l\x9c\"\xb7\x8b\xd4\xeb,\u01e2\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x02K\xdd,{\xfdP\x0e\xe7@O\u007f\xb3\xe9\xfb1\xdd \xfb\u0449\t\xc2\x00vQ\xb2P\x00\x00\u07d4\x02Sg\x96\x03\x04\xbe\xee4Y\x11\x18\xe9\xac-\x13X\xd8\x02\x1a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x02V\x14\x9f[Pc\xbe\xa1N\x15f\x1f\xfbX\xf9\xb4Y\xa9W\x89&)\xf6n\fS\x00\x00\x00\u07d4\x02`=z;\xb2\x97\xc6|\x87~]4\xfb\u0579\x13\xd4\xc6:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x02a\xad:\x17*\xbf\x13\x15\xf0\xff\xec2p\x98j\x84\t\xcb%\x89\v\b!;\u03cf\xfe\x00\x00\u07d4\x02d2\xaf7\xdcQ\x13\xf1\xf4mH\nM\u0c80R#~\x89\x13I\xb7\x86\xe4\v\xfc\x00\x00\u07d4\x02f\xab\x1ck\x02\x16#\v\x93\x95D=_\xa7^hEh\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x02u\x1d\u018c\xb5\xbdsp'\xab\xf7\u0777s\x90\xcdw\xc1k\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x02w\x8e9\x0f\xa1u\x10\xa3B\x8a\xf2\x87\fBsT}8l\x8a\x03lw\x80\x18\x8b\xf0\xef\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x037|\x0eUkd\x01\x03(\x9aa\x89\u1baecI4g\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03IcM\u00a9\xe8\f?w!\xee+PF\xae\xaa\xed\xfb\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x03U\xbc\xac\xbd!D\x1e\x95\xad\xee\xdc0\xc1r\x18\u0224\b\u0389\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x03n\xef\xf5\xba\x90\xa6\x87\x9a\x14\xdf\xf4\xc5\x04;\x18\xca\x04`\u0249\x05k\xc7^-c\x10\x00\x00\xe0\x94\x03qKA\u04a6\xf7Q\x00\x8e\xf8\xddM+)\xae\u02b8\xf3n\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x03r\xe8RX.\t44J\x0f\xed!x0M\xf2]F(\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03r\xeeU\b\xbf\x81c\xed(N^\xef\x94\xceMsg\xe5\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x03}\xd0V\xe7\xfd\xbdd\x1d\xb5\xb6\xbe\xa2\xa8x\n\x83\xfa\u1009\a\x96\xe3\xea?\x8a\xb0\x00\x00\xe0\x94\x03\x83#\xb1\x84\xcf\xf7\xa8*\xe2\u1f67y?\xe41\x9c\xa0\xbf\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03\x87y\xca-\xbef>c\xdb?\xe7V\x83\xea\x0e\xc6.#\x83\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\x03\x8eE\xea\xdd=\x88\xb8\u007f\xe4\u06b0fh\x05\"\xf0\xdf\xc8\xf9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x03\x92T\x9ar\u007f\x81eT)\u02d2\x8bR\x9f%\xdfM\x13\x85\x89\x01lC\xa0\xee\xa0t\x00\x00\u07d4\x03\x94\xb9\x0f\xad\xb8`O\x86\xf4?\xc1\xe3]1$\xb3*Y\x89\x89)j\xa1@'\x8ep\x00\x00\u0794\x03\x9ezN\xbc(N,\xcdB\xb1\xbd\xd6\v\xd6Q\x1c\x0fw\x06\x88\xf0\x15\xf2W6B\x00\x00\u07d4\x03\x9e\xf1\xceR\xfeyc\xf1f\u0562u\u0131\x06\x9f\xe3\xa82\x89\x15\xaf9\u4ab2t\x00\x00\u07d4\x03\xa2l\xfcL\x181op\u055e\x9e\x1ay\xee>\x8b\x96/L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x03\xaab(\x81#m\xd0\xf4\x94\f$\xc3$\xff\x8b{~!\x86\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4\x03\xafz\xd9\xd5\"<\xf7\xc8\xc1? \xdfg\xeb\xe5\xff\u017bA\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x03\xb0\xf1|\xd4F\x9d\xdc\u03f7\xdai~\x82\xa9\x1a_\x9ewt\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x03\xb4\x1bQ\xf4\x1d\xf2\r\xd2y\xba\xe1\x8c\x12w_w\xadw\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x03\xbe[F)\xae\xfb\xbc\xab\x9d\xe2m9Wl\xb7\xf6\x91\xd7d\x89\n\xdf0\xbap\u0217\x00\x00\u07d4\x03\xc6G\xa9\xf9)\xb0x\x1f\xe9\xae\x01\u02a3\xe1\x83\xe8vw~\x89\x18*\xb7\xc2\f\xe5$\x00\x00\u07d4\x03\xc9\x1d\x92\x946\x03\xe7R >\x054\x0eV`\x13\xb9\x00E\x89+|\xc2\xe9\xc3\"\\\x00\x00\u07d4\x03\xcbLOE\x16\xc4\xffy\xa1\xb6$O\xbfW.\x1c\u007f\xeay\x89\x94\x89#z\u06daP\x00\x00\u07d4\x03\u02d8\u05ec\xd8\x17\u079d\x88m\"\xfa\xb3\xf1\xb5}\x92\xa6\b\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x03\u031d-!\xf8k\x84\xac\x8c\xea\xf9q\u06e7\x8a\x90\xe6%p\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\x03\xd1rO\xd0\x0eT\xaa\xbc\xd2\xde*\x91\xe8F+\x10I\xdd:\x89\x8f\x1d\\\x1c\xae7@\x00\x00\u07d4\x03\xde\xdf\xcd\v<.\x17\xc7\x05\xda$\x87\x90\uf626\xbdWQ\x89Hz\x9a0E9D\x00\x00\u07d4\x03\u8c04SuW\xe7\t\xea\xe2\xe1\u1966\xbc\xe1\xef\x83\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x03\xeam&\u0400\xe5z\xee9&\xb1\x8e\x8e\xd7:N[(&\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x03\xeb<\xb8`\xf6\x02\x8d\xa5T\xd3D\xa2\xbbZP\n\xe8\xb8o\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x03\xeb\xc6?\xdaf`\xa4e\x04^#_\xben\\\xf1\x95s_\x89\a\xb0l\xe8\u007f\xddh\x00\x00\xe0\x94\x03\xefj\xd2\x0f\xf7\xbdO\x00+\xacX\xd4uD\u03c7\x9a\xe7(\x8a\x01u\xc7X\u0439n\\\x00\x00\u07d4\x03\xf7\xb9 \b\x81:\xe0\xa6v\xeb!(\x14\xaf\xab5\"\x10i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\x11p\xf5\x81\u0780\xe5\x8b*\x04\\\x8f|\x14\x93\xb0\x01\xb7\u02c90\xc8\xeca2\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\x04i\xe8\xc4@E\v\x0eQ&&\xfe\x81~gT\xa8\x15(0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04m'K\x1a\xf6\x15\xfbPZvJ\xd8\u0767p\xb1\xdb/=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x04}Z&\u05ed\x8f\x8ep`\x0fp\xa3\x98\u076a\x1c-\xb2o\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x04~\x87\xc8\xf7\xd1\xfc\xe3\xb0\x13S\xa8Xb\xa9H\xac\x04\x9f>\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x04\u007f\x9b\xf1R\x9d\xaf\x87\xd4\a\x17^o\x17\x1b^Y\xe9\xff>\x89#<\x8f\xe4'\x03\xe8\x00\x00\xe0\x94\x04\x85'2\xb4\xc6R\xf6\xc2\u53b3e\x87\xe6\nb\xda\x14\u06ca\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x04\x8a\x89p\xeaAE\xc6MU\x17\xb8\xde[F\xd0YZ\xad\x06\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x04\x9c]K\xc6\xf2]NEli{R\xa0x\x11\xcc\u045f\xb1\x89\x10D\x00\xa2G\x0eh\x00\x00\u07d4\x04\xa1\xca\xda\x1c\xc7Q\b/\xf8\u0692\x8e<\xfa\x00\b \xa9\xe9\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x04\xa8\n\xfa\xd5>\xf1\xf8Ae\xcf\xd8R\xb0\xfd\xf1\xb1\xc2K\xa8\x89\x03$\xe9d\xb3\xec\xa8\x00\x00\u07d4\x04\xaa\xfc\x8a\xe5\xceoI\x03\u021d\u007f\xac\x9c\xb1\x95\x12\"Gw\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x04\xbaK\xb8q@\x02,!Jo\xacB\xdbZ\x16\u0755@E\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x04\xba\x8a?\x03\xf0\x8b\x89P\x95\x99M\xdaa\x9e\u06ac\xee>z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\xc2\xc6K\xb5L>\xcc\xd0U\x85\xe1\x0e\xc6\xf9\x9a\f\xdb\x01\xa3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x04\xceE\xf6\x00\xdb\x18\xa9\u0405\x1b)\xd99>\xbd\xaa\xfe=\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x04\u05b8\xd4\u0686t\a\xbb\x99wI\u07bb\xcd\xc0\xb3XS\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x04\xd78\x96\xcfe\x93\xa6\x91\x97*\x13\xa6\xe4\x87\x1f\xf2\xc4+\x13\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\xd8*\xf9\xe0\x1a\x93m\x97\xf8\xf8Y@\xb9p\xf9\xd4\u06d96\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x04\xe5\xf5\xbc|\x92?\xd1\xe3\x175\xe7.\xf9h\xfdg\x11\fn\x89WU\x1d\xbc\x8ebL\x00\x00\u07d4\x04\xec\xa5\x01c\n\xbc\xe3R\x18\xb1t\x95k\x89\x1b\xa2^\xfb#\x8966\x9e\xd7t}&\x00\x00\u07d4\x05\x05\xa0\x8e\"\xa1\t\x01Z\"\xf6\x850STf*U1\u0549\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\x05\x14\x95L\xe8\x81\xc807\x03d\x00\x89lO\xd1\xee$nx\x00\x00\u07d4\x05\x1dBBv\xb2\x129fQ\x86\x13=e;\xb8\xb1\x86/\x89\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x05!\xbc:\x9f\x87\x11\xfe\xcb\x10\xf5\a\x97\xd7\x10\x83\xe3A\ub749\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x05#mL\x90\xd0e\xf9\u34c3X\xaa\xff\xd7w\xb8j\xecI\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x05*X\xe05\xf1\xfe\x9c\xdd\x16\x9b\xcf \x97\x03E\xd1+\x9cQ\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x05.\xab\x1fa\xb6\xd4U\x17(?A\xd1D\x18$\x87\x87I\u0409\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x053n\x9ar'(\xd9c\xe7\xa1\xcf'Y\xfd\x02tS\x0f\u02891\xa2D?\x88\x8ay\x80\x00\u07d4\x054q\u035aA\x92[9\x04\xa5\xa8\xff\xca6Y\xe04\xbe#\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4\x056\x1d\x8e\xb6\x94\x1dN\x90\xfb~\x14\x18\xa9Z2\xd5%w2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x05B:T\xc8\xd0\xf9p~pAs\xd9#\xb9F\xed\xc8\xe7\x00\x89\x06\xea\x03\u00bf\x8b\xa5\x80\x00\u07d4\x05D\f[\a;R\x9bH) \x9d\xff\x88\t\x0e\a\xc4\xf6\xf5\x89E\u04977\xe2/ \x00\x00\u07d4\x05Z\xb6X\xc6\xf0\xedO\x87^\xd6t.K\xc7)-\x1a\xbb\xf0\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\u07d4\x05[\xd0,\xaf\x19\xd6 +\xbc\u0703m\x18{\xd1\xc0\x1c\xf2a\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x05^\xacO\x1a\xd3\xf5\x8f\v\xd0$\u058e\xa6\r\xbe\x01\u01af\xb3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x05fQU\xccI\xcb\xf6\xaa\xbd\u056e\x92\xcb\xfa\xad\x82\xb8\xc0\xc1\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x05f\x86\a\x8f\xb6\xbc\xf9\xba\n\x8a\x8d\xc6:\x90o_\xea\xc0\xea\x89\x1b\x18\x1eK\xf24<\x00\x00\u07d4\x05iks\x91k\xd3\x03>\x05R\x1e2\x11\xdf\xec\x02n\x98\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x05k\x15F\x89O\x9a\x85\xe2\x03\xfb3m\xb5i\xb1l%\xe0O\x89\t.\xdb\t\xff\b\u0600\x00\u07d4\x05yI\xe1\xca\x05pF\x9eL\xe3\u0190\xaea:k\x01\xc5Y\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x05}\u049f-\x19\xaa=\xa4#'\xeaP\xbc\xe8o\xf5\xc9\x11\u0649\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x05\u007f\u007f\x81\xcdz@o\xc4Y\x94@\x8bPI\x91,Vdc\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x05\x91]N\"Zf\x81b\xae\xe7\xd6\xc2_\xcf\xc6\xed\x18\xdb\x03\x89\x03\x98\xc3ry%\x9e\x00\x00\u07d4\x05\x96\xa2}\xc3\xee\x11_\xce/\x94\xb4\x81\xbc z\x9e&\x15%\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x05\xa80rC\x02\xbc\x0fn\xbd\xaa\x1e\xbe\xee\xb4nl\xe0\v9\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\x05\xae\u007f\u053b\u0300\xca\x11\xa9\n\x1e\u01e3\x01\xf7\xcc\u0303\u06c91T\xc9r\x9d\x05x\x00\x00\u07d4\x05\xbbd\xa9\x16\xbef\xf4`\xf5\xe3\xb6C2\x11\r \x9e\x19\xae\x89\u3bb5sr@\xa0\x00\x00\xe0\x94\x05\xbfO\xcf\xe7r\xe4[\x82dC\x85.l5\x13P\xcer\xa2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\x05\xc6@\x04\xa9\xa8&\xe9N^N\xe2g\xfa*v2\xddNo\x8a\x03m\xc4.\xbf\xf9\v\u007f\x80\x00\xe0\x94\x05\xc76\xd3e\xaa7\xb5\xc0\xbe\x9c\x12\u022d\\\xd9\x03\xc3,\xf9\x8a\x01E^{\x80\n\x86\x88\x00\x00\xe0\x94\x05\xcbl;\x00r\xd3\x11ga\xb52\xb2\x18D;S\xe8\xf6\u014a\x1e\x02\xc3\xd7\xfc\xa9\xb6(\x00\x00\u07d4\x05\xd0\xf4\xd7(\xeb\xe8.\x84\xbfYu\x15\xadA\xb6\v\xf2\x8b9\x89\u3bb5sr@\xa0\x00\x00\u07d4\x05\u058d\xada\u04fb\u07f3\xf7y&\\IGJ\xff?\xcd0\x89\x02\"\xc5]\xc1Q\x9d\x80\x00\u07d4\x05\xe6q\xdeU\xaf\xec\x96K\aM\xe5t\xd5\x15\x8d]!\xb0\xa3\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x05\xe9{\tI,\u058fc\xb1+\x89.\xd1\xd1\x1d\x15,\x0e\u02897\b\xba\xed=h\x90\x00\x00\u07d4\x05\xf3c\x1fVd\xbd\xad]\x012\xc88\x8d6\xd7\u0612\t\x18\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x06\t\xd8:l\xe1\xff\u0276\x90\xf3\xe9\xa8\x1e\x98>\x8b\xdcM\x9d\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\u07d4\x06\x1e\xa4\x87|\u0409D\xebd\u0096n\x9d\xb8\xde\xdc\xfe\xc0k\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x06%\xd0`V\x96\x8b\x00\"\x06\xff\x91\x98\x01@$+\xfa\xa4\x99\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x06(\xbf\xbeU5x/\xb5\x88@k\xc9f`\xa4\x9b\x01\x1a\xf5\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\x061\u044b\xbb\xbd0\xd9\xe1s+\xf3n\xda\xe2\u0389\x01\xab\x80\x89\xa3\xf9\x88U\xec9\x90\x00\x00\u07d4\x061\xdc@\xd7NP\x95\xe3r\x9e\xdd\xf4\x95D\xec\xd49og\x89\b\xacr0H\x9e\x80\x00\x00\xe0\x94\x067Y\xdd\x1cN6.\xb1\x93\x98\x95\x1f\xf9\xf8\xfa\xd1\xd3\x10h\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x06_\xf5u\xfd\x9c\x16\xd3\xcbo\u058f\xfc\x8fH?\xc3.\xc85\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x06a\x8e\x9dWb\xdfb\x02\x86\x01\xa8\x1dD\x87\u05a0\xec\xb8\x0e\x89Hz\x9a0E9D\x00\x00\xe0\x94\x06fG\xcf\xc8]#\xd3v\x05W= \x8c\xa1T\xb2D\xd7l\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x06xeJ\xc6v\x1d\xb9\x04\xa2\xf7\xe8Y^\xc1\xea\xacsC\b\x89/\x98\xb2\x9c(\x18\xf8\x00\x00\u07d4\x06\x86\n\x93RYU\xffbI@\xfa\xdc\xff\xb8\xe1I\xfdY\x9c\x89lh\xcc\u041b\x02,\x00\x00\xe0\x94\x06\x8c\xe8\xbdn\x90*E\u02c3\xb5\x15A\xb4\x0f9\xc4F\x97\x12\x8a\x01\x1c\x0f\x9b\xadJF\xe0\x00\x00\u07d4\x06\x8e)\xb3\xf1\x91\xc8\x12\xa699\x18\xf7\x1a\xb93\xaehG\xf2\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x06\x8eeWf\xb9D\xfb&6\x19e\x87@\xb8P\xc9J\xfa1\x89\x01\xe8\u007f\x85\x80\x9d\xc0\x00\x00\u0794\x06\x96N-\x17\xe9\x18\x9f\x88\xa8 96\xb4\n\xc9nS<\x06\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x06\x99L\xd8:\xa2d\n\x97\xb2`\vA3\x9d\x1e\r>\xdel\x89\r\x8drkqw\xa8\x00\x00\u07d4\x06\x9e\u042bz\xa7}\xe5q\xf1a\x06\x05\x1d\x92\xaf\xe1\x95\xf2\u0409\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x06\xac&\xad\x92\u02c5\x9b\u0550]\xdc\xe4&j\xa0\xecP\xa9\u0149*\x03I\x19\u07ff\xbc\x00\x00\u07d4\x06\xb0\xc1\xe3\u007fZ^\u013b\xf5\b@T\x8f\x9d:\xc0(\x88\x97\x89\xd8\u0602\u148e}\x00\x00\u07d4\x06\xb0\xff\x83@s\xcc\xe1\xcb\xc9\xeaU~\xa8{`Yc\u8d09\x10CV\x1a\x88)0\x00\x00\xe0\x94\x06\xb1\x06d\x9a\xa8\xc4!\xdd\xcd\x1b\x8c2\xcd\x04\x18\xcf0\xda\x1f\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x06\xb5\xed\xe6\xfd\xf1\xd6\xe9\xa3G!7\x9a\xea\xa1|q=\xd8*\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x06\xcb\xfa\b\xcd\xd4\xfb\xa77\xba\xc4\a\xbe\x82$\xf4\xee\xf3X(\x89 +\xe5\xe88.\x8b\x80\x00\u07d4\x06\xd6\xcb0\x84\x81\xc36\xa6\xe1\xa2%\xa9\x12\xf6\xe65Y@\xa1\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x06\xdc\u007f\x18\xce\xe7\xed\xab[yS7\xb1\xdfj\x9e\x8b\u062eY\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x06\xf6\x8d\xe3\xd79\xdbA\x12\x1e\xac\xf7y\xaa\xda=\xe8v!\a\x89\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\x06\xf7\u070d\x1b\x94b\xce\xf6\xfe\xb13h\xa7\xe3\x97K\t\u007f\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\a\x01\xf9\xf1G\xecHhV\xf5\xe1\xb7\x1d\xe9\xf1\x17\xe9\x9e!\x05\x89\te\xdaq\u007f\u0578\x00\x00\u07d4\a\r]6L\xb7\xbb\xf8\"\xfc,\xa9\x1a5\xbd\xd4A\xb2\x15\u0549lk\x93[\x8b\xbd@\x00\x00\xe0\x94\a\x1d\xd9\r\x14\xd4\x1fO\xf7\xc4\x13\xc2B8\xd35\x9c\xd6\x1a\a\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\u07d4\a&\xc4.\x00\xf4T\x04\x83n\xb1\xe2\x80\xd0s\xe7\x05\x96\x87\xf5\x89X\x00>?\xb9G\xa3\x80\x00\xe0\x94\a'\xbe\n*\x00! H\xb5R\x0f\xbe\xfb\x95>\xbc\x9dT\xa0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\a)\xa8\xa4\xa5\xba#\xf5y\xd0\x02[\x1a\xd0\xf8\xa0\xd3\\\xdf\u048a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4\a)\xb4\xb4|\t\xeb\x16\x15\x84d\u022a\u007f\xd9i\vC\x889\x89lh\xcc\u041b\x02,\x00\x00\u0794\a4\xa0\xa8\x1c\x95b\xf4\xd9\xe9\xe1\n\x85\x03\xda\x15\xdbF\xd7n\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\a\xa7\xef[G\x00\x00\xe0\x94\ap\xc6\x1b\xe7\x87r#\f\xb5\xa3\xbb$)\xa7&\x14\xa0\xb36\x8a\x01n\u0899\xb7\x13A\x80\x00\u07d4\ar><0\xe8\xb71\xeeEj)\x1e\xe0\u7630 Jw\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\as\xee\xac\xc0P\xf7G \xb4\xa1\xbdW\x89[\x1c\xce\xebI]\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\a\x80\r/\x80h\xe4H\u01daOi\xb1\xf1^\xf6\x82\xaa\xe5\xf6\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\u07d4\a\xa8\xda\xde\xc1BW\x1a}S\xa4)pQxm\a,\xbaU\x89\x01;m\xa1\x13\x9b\u0680\x00\u07d4\a\xaf\x93\x8c\x127\xa2|\x900\tM\xcf$\aP$n=,\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\a\xb1\xa3\x06\xcbC\x12\xdffH,,\xaer\xd1\xe0a@\x0f\u034a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\a\xb7\xa5p3\xf8\xf1\x130\xe4f^\x18]#N\x83\xec\x14\v\x89\xea~\xe9*\f\x9a\v\x80\x00\u07d4\a\xbc,\xc8\xee\xdc\x01\x97\a\x00\xef\xc9\xc4\xfb6s^\x98\xcdq\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\a\xd4\x12\x17\xba\u0725\xe0\xe6\x03'\xd8E\xa3FO\x0f'\xf8J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\a\xd43N\u00c5\xe8\xaaT\xee\xda\xea\xdb0\x02/\f\u07e4\xab\x89\x8e\x91\xd5 \xf2\xeby\x00\x00\u07d4\a\xda\xe6\"c\r\x1168\x193\u04adk\"\xb89\xd8!\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\a\xdc+\xf8;\u01af\x19\xa8B\xff\xeaf\x1a\xf5\xb4\x1bg\xfd\xa1\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\a\u070c\x8b\x92z\xdb\xed\xfa\x8f]c\x9bCR5\x1f/6\u0489\x11\n\xed;U0\xdb\x00\x00\u07d4\a\xdd\xd0B,\x86\xefe\xbf\f\u007f\xc3E(b\xb1\"\x8b\b\xb8\x89o\xf5\u04aa\x8f\x9f\xcf\x00\x00\u07d4\a\xe1\x16,\xea\xe3\xcf!\xa3\xf6-\x10Y\x900.0\u007fN;\x89R\xf1\x03\xed\xb6k\xa8\x00\x00\u07d4\a\xe2\xb4\xcd\xee\xd9\u0407\xb1.Um\x9ew\f\x13\xc0\x99a_\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\a\xfe\xefT\xc16\x85\b)\xba\xdcKI\xc3\xf2\xa7<\x89\xfb\x9e\x89\x06hZ\xc1\xbf\xe3,\x00\x00\u07d4\b\x05FP\x8a=&\x82\u0239\x88O\x13c{\x88G\xb4M\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\t\bv\xba\xad\xfe\xe6\\=6;\xa5S\x12t\x8c\xfa\x87=\x89\\*\x997\x1c\xff\xe1\x00\x00\u07d4\b\x16o\x021?\xea\u12f0D\xe7\x87|\x80\x8bU\xb5\xbfX\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\b)\xd0\xf7\xbb|Dl\xfb\xb0\u07ad\xb29M\x9d\xb7$\x9a\x87\x89\x02,\xa3X|\xf4\xeb\x00\x00\u07d4\b0m\xe5\x19\x81\u7b21\x85hY\xb7\xc7xijki\xf9\x89\xadx\xeb\u016cb\x00\x00\x00\xe0\x94\b7S\x9b_jR*H,\xdc\u04e9\xbbpC\xaf9\xbd\u048a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\b8\xa7v\x8d\x9c*\u028b\xa2y\xad\xfe\xe4\xb1\xf4\x91\xe3&\xf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\bA\x16R\xc8qq6\t\xaf\x00b\xa8\xa1(\x1b\xf1\xbb\xcf\u0649K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\bM\x102Tu\x9b4<\xb2\xb9\xc2\xd8\xff\x9e\x1a\xc5\xf1E\x96\x8a\x01\x9b\xff/\xf5yh\xc0\x00\x00\u07d4\bPO\x05d?\xabY\x19\xf5\xee\xa5Y%\u05e3\xed}\x80z\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\b[J\xb7]\x83b\xd9\x14C\\\xed\xee\x1d\xaa+\x1e\xe1\xa2;\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\b[\xa6_\xeb\xe2>\xef\xc2\xc8\x02fj\xb1&#\x82\xcf\u0114\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\bt\x98\xc0FFh\xf3\x11P\xf4\xd3\u013c\u0765\"\x1b\xa1\x02\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\bw\uebabx\xd5\xc0\x0e\x83\xc3+-\x98\xfay\xadQH/\x89\x17\xd2-q\xdab&\x00\x00\u0794\b\x93j7\u07c5\xb3\xa1X\xca\xfd\x9d\xe0!\xf5\x817h\x13G\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\b\xa9\xa4N\x1fA\xde=\xbb\xa7\xa3c\xa3\xabA,\x12L\xd1^\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\b\xb7\xbd\u03d4MUp\x83\x8b\xe7\x04`$:\x86\x94HXX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xb8E6\xb7L\x8c\x01T=\xa8\x8b\x84\u05cb\xb9WG\xd8\"\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\b\xc2\xf26\xacJ\xdc\xd3\xfd\xa9\xfb\xc6\xe4S\"S\xf9\xda;\xec\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\b\xc8\x02\xf8wX4\x9f\xa0>k\xc2\xe2\xfd\a\x91\x19~\ua689lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xc9\U0007fd89\xfd\xf8\x04\xd7i\xf8!#6\x02\x15\xaf\xf9;\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\b\xca\u0215&A\xd8\xfcRn\xc1\xabO-\xf8&\xa5\xe7q\x0f\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\b\xcc\xdaP\xe4\xb2j\x0f\xfc\x0e\xf9.\x92\x051\a\x06\xbe\xc2\u01ca\x01Iul8W\xc6\x00\x00\x00\u07d4\b\u0406M\xc3/\x9a\xcb6\xbfN\xa4G\xe8\xddg&\x90j\x15\x89lnY\xe6|xT\x00\x00\u07d4\b\xd4&\u007f\xeb\x15\u0697\x00\xf7\xcc\xc3\xc8J\x89\x18\xbf\x17\xcf\u0789a\t=|,m8\x00\x00\xe0\x94\b\xd41\x1c\x9c\x1b\xba\xf8\u007f\xab\xe1\xa1\xd0\x14c\x82\x8d]\x98\u038a\x13\x0e\xe8\xe7\x17\x90D@\x00\x00\u07d4\b\xd5N\x83\xadHj\x93L\xfa\xea\u20e3>\xfd\"|\x0e\x99\x898S\x05\x83$^\xdc\x00\x00\u07d4\b\xd9~\xad\xfc\xb7\xb0d\xe1\xcc\xd9\u0217\x9f\xbe\xe5\xe7z\x97\x19\x89\x0el]\xa8\xd6z\xc1\x80\x00\u07d4\b\xda:z\x0fE!a\u03fc\xec1\x1b\xb6\x8e\xbf\xde\xe1~\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xe3\x8e\xe0\xceH\xc9\xcad\\\x10\x19\xf7;SUX\x1cV\xe6\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\b\xef?\xa4\xc4<\xcd\xc5{\"\xa4\xb9\xb23\x1a\x82\xe58\x18\xf2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\t\td\x8c\x18\xa3\xce[\xaez\x04~\xc2\xf8h\xd2L\u0768\x1d\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\t\f\xd6{`\xe8\x1dT\xe7\xb5\xf6\a\x8f>\x02\x1b\xa6[\x9a\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\f\xeb\xef),>\xb0\x81\xa0_\u062a\xf7\u04db\xf0{\x89\u0509\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\t\x0f\xa96{\xdaW\xd0\xd3%:\n\x8f\xf7l\xe0\xb8\xe1\x9as\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\x14n\xa3\x88Qv\xf0w\x82\xe1\xfe0\xdc\xe3\xce$\u011e\x1f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\t!`_\x99\x16N;\xcc(\xf3\x1c\xae\xcex\x971\x82V\x1d\x89+\ai*\x90e\xa8\x00\x00\xe0\x94\t&\x1f\x9a\xcbE\x1c7\x88\x84O\f\x14Q\xa3[\xadP\x98\xe3\x8a\x01\u056d'P) `\x00\x00\xe0\x94\t'\"\x04\x92\x19K.\u069f\u013b\xe3\x8f%\u0581\xdf\xd3l\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\t*\xcbbK\b\xc0U\x10\x18\x9b\xbb\xe2\x1ee$\xd6D\u032d\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\t.\x81UX@-g\xf9\rk\xfem\xa0\xb2\xff\xfa\x91EZ\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\tP0\xe4\xb8&\x92\xdc\xf8\xb8\u0411$\x94\xb9\xb3x\xec\x93(\x89H\xa4zu\x80\x00\u07d4\t\x89\xc2\x00D\v\x87\x89\x91\xb6\x9d`\x95\xdf\xe6\x9e3\xa2.p\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\t\x90\xe8\x1c\u05c5Y\x9e\xa26\xbd\x19f\xcfRc\x02\xc3[\x9c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\x98\xd8'1\x15\xb5j\xf4%\xff\xc8>!\x8c\x1e\n\xfe\x89(\u01c8\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\t\xaeI\xe3\u007f\x12\x1d\xf5\xdc\x15\x8c\xfd\xe8\x06\xf1s\xa0k\f\u007f\x89\xd80\x9e&\xab\xa1\xd0\x00\x00\u07d4\t\xaf\xa7;\xc0G\xefF\xb9w\xfd\x97c\xf8r\x86\xa6\xbeh\u0189\x1b/\xb5\xe8\xf0jf\x00\x00\u07d4\t\xb4f\x86\x96\xf8j\b\x0f\x8b\xeb\xb9\x1d\xb8\xe6\xf8p\x15\x91Z\x89#\x8f\xf7\xb3O`\x01\x00\x00\xe0\x94\t\xb5\x9b\x86\x98\xa7\xfb\xd3\xd2\xf8\xc7:\x00\x89\x88\xde>@k+\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94\t\xb7\xa9\x88\xd1?\xf8\x91\x86so\x03\xfd\xf4au\xb5=\x16\xe0\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\t\xc1w\xf1\xaeD$\x11\u076c\xf1\x87\xd4m\xb9V\x14\x83`\xe7\x8a\x01\xe5.3l\xde\"\x18\x00\x00\xe0\x94\t\u020f\x91~Mj\xd4s\xfa\x12\u93a3\xc4G*^\xd6\u068a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\t\u0438\xcd\a|i\xd9\xf3-\x9c\xcaC\xb3\xc2\b\xa2\x1e\u050b\x89\b!\xd2!\xb5)\x1f\x80\x00\xe0\x94\t\xd6\xce\xfdu\xb0\u0133\xf8\xf1\u0587\xa5\"\xc9a#\xf1\xf59\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\t\xe47\xd4H\x86\x12(\xa22\xb6.\xe8\xd3ye\xa9\x04\ud70a\x04\x98\xcf@\x1d\xf8\x84.\x80\x00\u07d4\t\xee\x12\xb1\xb4+\x05\xaf\x9c\xf2\a\xd5\xfc\xac%[.\xc4\x11\xf2\x89\x031\xcd\xddG\xe0\xfe\x80\x00\u07d4\t\xf3\xf6\x01\xf6\x05D\x11@Xl\xe0eo\xa2J\xa5\xb1\u066e\x89Sswo\xe8\xc4T\x00\x00\u07d4\t\xf9W[\xe5}\x00G\x93\u01e4\ub137\x15\x87\xf9|\xbbj\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n\x06P\x86\x1fx^\xd8\xe4\xbf\x10\x05\xc4P\xbb\xd0n\xb4\x8f\xb6\x89\xa6A;y\x14N~\x00\x00\u07d4\n\x06\xfa\xd7\xdc\u05e4\x92\xcb\xc0S\xee\xab\xdei4\xb3\x9d\x867\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\n\a}\xb1?\xfe\xb0\x94\x84\xc2\x17p\x9dX\x86\xb8\xbf\x9cZ\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\n\x0e\u0366cow\x16\xef\x19saF\x87\xfd\x89\xa8 \xa7\x06\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\n)\xa8\xa4\xd5\xfd\x95\x00u\xff\xb3Mw\xaf\xeb-\x82;\u0589\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n*\u0795\xb2\xe8\xc6m\x8a\xe6\xf0\xbad\xcaW\u05c3\xbemD\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\n+O\xc5\xd8\x1a\xceg\xdcK\xba\x03\xf7\xb4UA=F\xfe=\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\n-\xcbzg\x17\x01\u06f8\xf4\x95r\x80\x88&Xs5l\x8e\x89\b?\x16\xce\b\xa0l\x00\x00\u07d4\n=\xe1U\xd5\xec\xd8\xe8\x1c\x1f\xf9\xbb\xf07\x83\x01\xf8\xd4\xc6#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\nG\xad\x90Y\xa2I\xfc\x93k&b5=\xa6\x90_u\u00b9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\nH)ov1p\x8c\x95\u04b7Iu\xbcJ\xb8\x8a\xc19*\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\nJ\x01\x19\x95\u0181\xbc\x99\x9f\xddyuN\x9a2J\xe3\xb3y\x8a\b\xc1\x9a\xb0n\xb8\x9a\xf6\x00\x00\u07d4\nX\xfd\xddq\x89\x8d\xe7s\xa7O\xda\xe4^{\xd8N\xf46F\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\n[y\xd8\xf2;d\x83\xdb\u2f6ab\xb1\x06L\xc7cf\xae\x89j\u0202\x10\tR\u01c0\x00\u07d4\ne.*\x8bw\xbd\x97\xa7\x90\xd0\xe9\x13a\u0248\x90\u06f0N\x8965\u026d\xc5\u07a0\x00\x00\u07d4\nn\xber;n\xd1\xf9\xa8ji\xdd\xdah\xdcGF\\+\x1b\x89@=-\xb5\x99\xd5\xe4\x00\x00\u07d4\nw\xe7\xf7+C{WO\x00\x12\x8b!\xf2\xac&Q3R\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\n\x91\u007f;\\\xb0\xb8\x83\x04\u007f\u0676Y=\xbc\xd5W\xf4S\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\n\x93\x1bD\x9e\xa8\xf1,\xdb\xd5\xe2\xc8\xccv\xba\xd2\xc2|\x069\x89\x01?\x9e\x8cy\xfe\x05\x80\x00\u0794\n\x98\x04\x13x\x03\xbahh\xd9:U\xf9\x98_\xcdT\x04Q\u4239\x8b\xc8)\xa6\xf9\x00\x00\u07d4\n\x9a\xb2c\x8b\x1c\xfdeM%\u06b0\x18\xa0\xae\xbd\u07c5\xfdU\x89\x01.\x8c\xb5\xfeLJ\x80\x00\u07d4\n\xb3f\xe6\xe7\u056b\xbc\xe6\xb4JC\x8di\xa1\u02bb\x90\xd13\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\n\xb4(\x1e\xbb1\x85\x90\xab\xb8\x9a\x81\xdf\a\xfa:\xf9\x04%\x8a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\n\xb5\x9d9\a\x02\xc9\xc0Y\xdb\x14\x8e\xb4\xf3\xfc\xfa}\x04\xc7\xe7\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\n\xbf\xb3\x9b\x11HmyW(f\x19[\xa2lc\vg\x84\u06ca\x19\xba\x877\xf9i(\xf0\x00\x00\u07d4\n\u029aV&\x91;\b\xcf\u0266m@P\x8d\xceR\xb6\x0f\x87\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\n\xd3\xe4M<\x00\x1f\xa2\x90\xb3\x93ap0TA\b\xacn\xb9\x89j\xbd\xa0\xbc0\xb2\u07c0\x00\u07d4\n\xec.Bn\xd6\xcc\f\xf3\xc2I\xc1\x89~\xacG\xa7\xfa\xa9\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n\xf6_\x14xNU\xa6\xf9Vg\xfds%*\x1c\x94\a-*\x89\nv;\x8e\x02\xd4O\x80\x00\u07d4\n\xf6\xc8\xd59\xc9mP%\x9e\x1b\xa6q\x9e\x9c\x80`\xf3\x88\u008965\u026d\xc5\u07a0\x00\x00\u07d4\v\x069\x0f$7\xb2\x0e\u0123\xd3C\x1b2y\xc6X>^\u05c9\n\x84Jt$\xd9\xc8\x00\x00\u07d4\v\v8b\x11*\xee\u00e04\x92\xb1\xb0_D\x0e\xcaT%n\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\v\x0e\x05[(\xcb\xd0=\xc5\xffD\xaad\xf3\xdc\xe0O^c\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\x11\x9d\xf9\x9ck\x8d\xe5\x8a\x1e,?)zgD\xbfU\"w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\x14\x89\x19\x99\xa6\\\x9e\xf73\b\xef\xe3\x10\f\xa1\xb2\x0e\x81\x92\x89+^:\xf1k\x18\x80\x00\x00\u07d4\v!\x13PE4d*\x1d\xaf\x10.\xee\x10\xb9\xeb\xdev\xe2a\x89\x94,\xdd|\x95\xf2\xbd\x80\x00\xe0\x94\v(\x8aZ\x8bu\xf3\xdcA\x91\xeb\x04W\xe1\xc8=\xbd M%\x8a\x01\a\x14\xe7{\xb4:\xb4\x00\x00\u07d4\v6\x9e\x00.\x1bLy\x13\xfc\xf0\x0f-^\x19\u0141eG\x8f\x89\x03\u007fe\x16(\x8c4\x00\x00\u07d4\vC\xbd#\x91\x02U\x81\u0615l\xe4*\a%y\u02ff\xcb\x14\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u07d4\vP|\xf5SV\x8d\xaa\xf6U\x04\xaeN\xaa\x17\xa8\xea<\xdb\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v]f\xb1<\x87\xb3\x92\xe9M\x91\xd5\xf7l\rE\nU(C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v^ \x11\xeb\xc2Z\x00\u007f!6)`I\x8a\xfb\x8a\xf2\x80\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vd\x9d\xa3\xb9j\x10,\xdcm\xb6R\xa0\xc0}e\xb1\xe4C\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vi \xa6K6;\x8d]\x90\x80$\x94\xcfVKT|C\r\x89A\rXj \xa4\xc0\x00\x00\u07d4\vp\x11\x01\xa4\x10\x9f\x9c\xb3`\xdcW\xb7tBg=^Y\x83\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vq\xf5T\x12$i\uf5ce/\x1f\xef\xd7\u02f4\x10\x98'r\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\xe0\x94\v{\xb3B\xf0\x1b\u0248\x8ej\x9a\xf4\xa8\x87\xcb\xf4\xc2\xdd,\xaf\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\v}3\x93q\xe5\xbeg'\xe6\xe31\xb5\x82\x1f\xa2K\u06ddZ\x89.\u007f\x81\x86\x82b\x01\x00\x00\u07d4\v\u007f\xc9\xdd\xf7\x05v\xf63\x06i\xea\xaaq\xb6\xa81\xe9\x95(\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\v\x80\xfcp(,\xbd\xd5\xfd\xe3[\xf7\x89\x84\xdb;\xdb\x12\x01\x88\x8968\x02\x1c\xec\u06b0\x00\x00\u07d4\v\x92M\xf0\a\xe9\xc0\x87\x84\x17\xcf\xe6;\x97n\xa1\xa3\x82\xa8\x97\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\v\x93\xfc\xa4\xa4\xf0\x9c\xac \xdb`\xe0e\xed\xcc\xcc\x11\u0976\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\v\x9d\xf8\x0f\xbe# \t\xda\xcf\n\xa8\xca\u0153v\xe2Gb\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xa6\xe4j\xf2Z\x13\xf5qi%Z4\xa4\xda\xc7\xce\x12\xbe\x04\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\v\xa8p[\xf5\\\xf2\x19\xc0\x95k^?\xc0\x1cDt\xa6\xcd\xc1\x89\x05%\xe0Y]Mk\x80\x00\u07d4\v\xafn\u0379\x1a\xcb6\x06\xa85|\v\xc4\xf4\\\xfd-~o\x8965\u026d\xc5\u07a0\x00\x00\u07d4\v\xb0_r$\xbbX\x04\x85eV\xc0~\xea\xdb\ud1fa\x8f|\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\v\xb0\xc1&\x82\xa2\xf1\\\x9bWA\xb28\\\xbeA\xf04\x06\x8e\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\v\xb2\\\xa7\u0448\xe7\x1eMi={\x17\a\x17\xd6\xf8\xf0\xa7\n\x89\x12C\x02\xa8/\xad\xd7\x00\x00\u07d4\v\xb2e\x0e\xa0\x1a\xcau[\xc0\xc0\x17\xb6K\x1a\xb5\xa6m\x82\xe3\x89Hz\x9a0E9D\x00\x00\u07d4\v\xb5Lr\xfdf\x10\xbf\xa463\x97\xe0 8K\x02+\fI\x89Hz\x9a0E9D\x00\x00\u07d4\v\xb7\x16\n\xba)7b\xf8sO>\x03&\xff\u0264\xca\xc1\x90\x8965\u026d\xc5\u07a0\x00\x00\u07d4\v\xc9\\\xb3-\xbbWL\x83/\xa8\x17J\x815m8\xbc\x92\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xd6}\xbd\xe0z\x85n\xbd\x89;^\xdcO:[\xe4 &\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xdb\xc5L\u023d\xbb\xb4\x02\xa0\x89\x11\xe2#*T`\u0386k\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\v\xddX\xb9n|\x91m\xd2\xfb05o*\xeb\xfa\xaf\x1d\x860\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\v\u1f39\x03C\xfa\xe501s\xf4a\xbd\x91JH9\x05l\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\v\xe1\xfd\xf6&\xeea\x89\x10-p\xd1;1\x01,\x95\xcd\x1c\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xe2\xb9J\xd9P\xa2\xa6&@\xc3[\xfc\xcdlg\xda\xe4P\xf6\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\v\u681eC\a\xfeH\xd4\x12\xb8\u0461\xa8(M\xceHba\x8a\x04\x0f\xbf\xf8\\\x0180\x00\x00\u07d4\v\xef\xb5G\a\xf6\x1b,\x9f\xb0G\x15\xab\x02n\x1b\xb7 B\xbd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\v\xf0dB\x8f\x83bg\"\xa7\xb5\xb2j\x9a\xb2\x04!\xa7r>\x89\a?u\u0460\x85\xba\x00\x00\u07d4\v\xfb\xb6\x92]\xc7^R\xcf&\x84\"K\xbe\x05P\xfe\xa6\x85\u04c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\f\b\x80\x06\xc6K0\xc4\u076f\xbc6\xcb_\x05F\x9e\xb6(4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f s\xbaD\xd3\u077d\xb69\xc0N\x19\x109\xa7\x17\x16#\u007f\x89M\x85<\x8f\x89\b\x98\x00\x00\xe0\x94\f\",|A\u0270H\xef\xcc\xe0\xa22CCb\xe1-g;\x8a\x02\x1e\x83Yivw8\x00\x00\xe0\x94\f(\b\xb9Q\ud787-{2y\x0f\xccY\x94\xaeA\xff\u070a\x15\x99n[<\u05b3\xc0\x00\x00\u07d4\f(\x84~O\t\xdf\xce_\x9b%\xaf|NS\x0fY\u0200\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f-\\\x92\x058\xe9S\u02af$\xf0s\u007fUL\u0192wB\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f0\xca\xcc?r&\x9f\x8bO\x04\xcf\a=+\x05\xa8=\x9a\u0449lyt\x12?d\xa4\x00\x00\u07d4\f29\xe2\xe8A$-\xb9\x89\xa6\x15\x18\xc2\"G\xe8\xc5R\b\x89\x0eJ\xf6G\x174d\x00\x00\xe0\x94\fH\r\xe9\xf7F\x10\x02\x90\x8bI\xf6\x0f\xc6\x1e+b\xd3\x14\v\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\fH\xaeb\xd1S\x97\x88\xeb\xa0\x13\xd7^\xa6\vd\xee\xbaN\x80\x89w\xfb\xdcC\xe00\x99\x80\x00\u07d4\fU\x89\xa7\xa8\x9b\x9a\xd1[\x02u\x190AYH\xa8u\xfb\xef\x89\x06\u0519\xeclc8\x00\x00\u07d4\fg\x03=\xd8\xee\u007f\f\x8a\xe54\xd4*Q\xf7\xd9\xd4\xf7\x97\x8f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\fhE\xbfA\xd5\xee'<>\u6d70\u059fo\xd5\xea\xbb\xf7\x89\xa2\xa1\xb9h.X\t\x00\x00\xe0\x94\f\u007f\x86\x9f\x8e\x90\xd5?\xdc\x03\u8c81\x9b\x01k\x9d\x18\xeb&\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\f\x86\x92\xee\xff*S\xd6\xd1h\x8e\xd5j\x9d\u06fdh\u06bb\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f\x8ff\xc6\x01{\xce[ 4r\x04\xb6\x02\xb7C\xba\u05cd`\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\f\x8f\xd7w^T\xa6\xd9\u0263\xbf\x89\x0ev\x1fewi?\xf0\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\f\x92Z\xd5\xeb5,\x8e\xf7m\f\"-\x11[\a\x91\xb9b\xa1\x89\xacc]\u007f\xa3N0\x00\x00\u07d4\f\x96~0a\xb8zu>\x84P~\xb6\t\x86x,\x8f0\x13\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\f\xa1*\xb0\xb9fl\xf0\xce\xc6g\x1a\x15)/&SGj\xb2\x8a,x'\xc4-\"\xd0|\x00\x00\u07d4\f\xa6p\xeb,\x8b\x96\u02e3y!\u007fY)\u00b8\x92\xf3\x9e\xf6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f\xae\x10\x8em\xb9\x9b\x9ecxv\xb0d\xc60>\u068ae\u0209\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\f\xbd\x92\x1d\xbe\x12\x15c\xb9\x8ahq\xfe\xcb\x14\xf1\xcc~\x88\u05c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\f\xbf\x87p\xf0\xd1\b.\\ \u016e\xad4\xe5\xfc\xa9\xaez\xe2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f\xc6\u007f\x82s\xe1\xba\xe0\x86\u007f\xd4.\x8b\x81\x93\xd7&y\xdb\xf8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\f\u05a1A\x91\x8d\x12k\x10m\x9f.\xbfi\xe1\x02\xdeM2w\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\f\xda\x12\xbfr\xd4a\xbb\xc4y\xeb\x92\xe6I\x1d\x05~kZ\u044a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\f\u0716\v\x99\x8c\x14\x19\x98\x16\r\xc1y\xb3l\x15\u0484p\xed\x89\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\f\xfb\x17#5\xb1l\x87\xd5\x19\xcd\x14uS\r W\u007f^\x0e\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\r\x1f*Wq>\xbcn\x94\xde)\x84n\x88D\xd3vfWc\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\r2e\xd3\u7f79=^\x8e\x8b\x1c\xa4\u007f!\ny>\u030e\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\r5@\x8f\"ef\x11o\xb8\xac\u06a9\xe2\xc9\u055bvh?\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\rU\x1e\xc1\xa2\x13<\x98\x1d_\u01a8\xc8\x17?\x9e|OG\xaf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r]\x98V\\d|\xa5\xf1w\xa2\xad\xb9\xd3\x02/\xac(\u007f!\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\re\x80\x14\xa1\x99\x06\x1c\xf6\xb3\x943\x14\x03\x03\xc2\x0f\xfdNZ\x8a\x01\xbc\x85\xdc*\x89\xbb \x00\x00\u07d4\rg\x87\x06\xd07\x18\u007f>\"\xe6\xf6\x9b\x99\xa5\x92\xd1\x1e\xbcY\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\ri\x10\f9\\\xe6\xc5\xea\xad\xf9]\x05\xd8r\x83~\xde\xdd!\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\rt~\u559b\xf7\x9dW8\x1do\xe3\xa2@l\xd0\xd8\xce'\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\r\x80#\x92\x9d\x91r4\xae@Q+\x1a\xab\xb5\xe8\xa4Q'q\x89\b\x05\xe9\x9f\xdc\xc5\xd0\x00\x00\xe0\x94\r\x8a\xab\x8ft\xea\x86,\xdfvh\x05\x00\x9d?>B\xd8\xd0\v\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\r\x8c@\xa7\x9e\x18\x99O\xf9\x9e\xc2Q\xee\x10\u0408\u00d1.\x80\x89\x066d\xfc\u04bb\xc4\x00\x00\u07d4\r\x8e\xd7\xd0\xd1V83\x0e\xd7\xe4\xea\u032b\x8aE\x8dus~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r\x92X/\u06e0^\xab\xc3\xe5\x158\xc5m\xb8\x817\x85\xb3(\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\r\x94C\xa7\x94h\xa5\xbb\xf7\xc1\xe5\xb9\x15\xb3d\x87\xf9\x16\x1f\x19\x84m\x10\x1431\x8a\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\r\xbdA|7+\x8b\r\x01\xbc\xd9Dpk\xd3.`\xae(\u0449\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\r\xc1\x00\xb1\a\x01\x1c\u007f\xc0\xa13\x96\x12\xa1l\xce\xc3(R\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r\u03dd\x8c\x98\x04E\x9fd|\x14\x13\x8e\xd5\x0f\xadV;AT\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4\r\xcf\xe87\xea\x1c\xf2\x8ce\xfc\xce\u00fe\xf1\xf8NY\xd1P\xc0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\r\xd4\xe6t\xbb\xad\xb1\xb0\u0702D\x98q=\xce;QV\xda)\x89\t79SM(h\x00\x00\u07d4\r\xfb\u0501pP\xd9\x1d\x9db\\\x02\x05<\xf6\x1a>\xe2\x85r\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\x0e\x02N\u007f\x02\x9cj\xaf:\x8b\x91\x0f^\b\bs\xb8W\x95\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0e\tdl\x99\xafC\x8e\x99\xfa'L\xb2\xf9\xc8V\xcbe\xf76\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x0e\f\x9d\x00^\xa0\x16\u0095\xcdy\\\xc9!>\x87\xfe\xbc3\xeb\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\x0e\rf3\xdb\x1e\f\u007f#Jm\xf1c\xa1\x0e\n\xb3\x9c \x0f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x0e\x11\xd7z\x89w\xfa\xc3\r&\x84E\xe51\x14\x9b1T\x1a$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\x12=}\xa6\xd1\xe6\xfa\xc2\u072d\xd2p)$\v\xb3\x90R\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0e\x18\x01\xe7\vbb\x86\x1b\x114\u033c9\x1fV\x8a\xfc\x92\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x0e \x94\xac\x16T\xa4k\xa1\xc4\u04e4\v\xb8\xc1}\xa7\U000d6209\x13h?\u007f<\x15\xd8\x00\x00\u07d4\x0e!\xaf\x1b\x8d\xbf'\xfc\xf6?7\xe0G\xb8z\x82\\\xbe|'\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x0e.PJ-\x11\"\xb5\xa9\xfe\xee\\\xb1E\x1b\xf4\u00ac\xe8{\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x0e/\x8e(\xa6\x81\xf7|X;\xd0\xec\xde\x16cK\xdd~\x00\u0349\x05'8\xf6Y\xbc\xa2\x00\x00\u07d4\x0e2\x02\x19\x83\x8e\x85\x9b/\x9f\x18\xb7.=@s\xcaP\xb3}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e3\xfc\xbb\xc0\x03Q\v\xe3W\x85\xb5*\x9c]!k\xc0\x05\xf4\x89e\xea=\xb7UF`\x00\x00\u07d4\x0e6\x96\xcf\x1fB\x17\xb1c\u047c\x12\xa5\xeas\x0f\x1c2\xa1J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x0e9\x0fD\x05=\xdf\xce\xf0\xd6\b\xb3^M\x9c,\xbe\x98q\xbb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x0e:(\xc1\u07ef\xb0P[\xdc\xe1\x9f\xe0%\xf5\x06\xa6\xd0\x1c\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e=\xd7\xd4\xe4)\xfe90\xa6A@5\xf5+\xdcY\x9dxM\x89\x02,\xa3X|\xf4\xeb\x00\x00\u07d4\x0eGey\x03Rek\xc6Vh,$\xfc^\xf3\xe7j#\u01c9\x02\x86\xd7\xfc\f\xb4\xf5\x00\x00\u07d4\x0eI\x88\x00Dqw\xb8\u022f\xc3\xfd\xfa\u007fi\xf4\x05\x1b\xb6)\x89t\x05\xb6\x9b\x8d\xe5a\x00\x00\u07d4\x0ek\xaa\xa3\u07b9\x89\xf2\x89b\x00vf\x86\x18\xe9\xac3(e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x0el\xd6d\xad\x9c\x1e\xd6K\xf9\x87I\xf4\x06D\xb6&\xe3y,\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\xe0\x94\x0em\xfdU;.\x87=*\xec\x15\xbd_\xbb?\x84r\xd8\u04d4\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\x0en\xc3\x137bq\xdf\xf5T#\xabT\"\xcc:\x8b\x06\xb2+\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x0en\u0399\x11\x1c\xad\x19a\xc7H\xed=\xf5\x1e\xddi\u04a3\xb1\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x0e\x83\xb8PH\x1a\xb4MI\xe0\xa2)\xa2\xe4d\x90,iS\x9b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0e\x89\xed\xdd?\xa0\xd7\x1d\x8a\xb0\xff\x8d\xa5X\x06\x86\xe3\xd4\xf7O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\x90\x96\xd3C\xc0`\xdbX\x1a\x12\x01\x12\xb2x`~\xc6\xe5+\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x0e\x9cQ\x18d\xa1w\xf4\x9b\xe7\x82\x02w?`H\x9f\xe0NR\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x0e\xa2\xa2\x101+>\x86~\xe0\xd1\xcch,\xe1\xd6f\xf1\x8e\u054a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x0e\xb1\x89\xef,-Wb\xa9c\u05b7\xbd\xf9i\x8e\xa8\u7d0a\x89Hz\x9a0E9D\x00\x00\xe0\x94\x0e\xb5\xb6b\xa1\xc7\x18`\x8f\xd5/\f%\xf97\x880\x17\x85\x19\x8a\x01J7(\x1aa.t\x00\x00\xe0\x94\x0e\xc4f\x96\xff\xac\x1fX\x00_\xa8C\x98$\xf0\x8e\xed\x1d\xf8\x9b\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x0e\xc5\n\xa8#\xf4e\xb9FK\v\xc0\u0125w$\xa5U\xf5\u058a\f\x83\xd1Bj\u01f1\xf0\x00\x00\u07d4\x0e\xc50\x8b1(.!\x8f\xc9\xe7Y\xd4\xfe\xc5\xdb7\b\xce\u01096C\xaady\x86\x04\x00\x00\u07d4\x0e\xcc\xf6\x17\x84O\xd6\x1f\xbab\xcb\x0eD[z\u018b\xcc\x1f\xbe\x89\x14\xfeO\xe65e\xc6\x00\x00\u07d4\x0e\u04fb:N\xb5T\xcf\u0297\x94}WU\a\xcd\xfdm!\u0609\x1d\xb3 _\xcc#\u0540\x00\u07d4\x0e\xd7l,;]P\xff\x8f\xb5\v>\xea\xcdh\x15\x90\xbe\x1c-\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0e\u0680\xf4\xed\aJ\xeaiz\xed\xdf(;c\xdb\xca=\xc4\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\xddKX\x0f\xf1\x0f\xe0lJ\x03\x11b9\xef\x96b+\xae5\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x0e\xe3\x91\xf0^\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x0f\x92\x9c\xf8\x95\xdb\x01z\xf7\x9f>\xad\"\x16\xb1\xbdi\xc3}\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x0f\xa0\x10\xce\fs\x1d;b\x8e6\xb9\x1fW\x13\x00\u477e\xab\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\x0f\xa5\xd8\u0173\xf2\x94\xef\u0515\xabi\xd7h\xf8\x18rP\x85H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0f\xa6\u01f0\x97=\v\xae)@T\x0e$}6'\xe3|\xa3G\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0f\xad\x05P|\u070f$\xb2\xbeL\xb7\xfa]\x92}\u06d1\x1b\x88\x89\xa2\xdf\x13\xf4A\xf0\t\x80\x00\u07d4\x0f\xb5\xd2\xc6s\xbf\xb1\xdd\xca\x14\x1b\x98\x94\xfdm?\x05\xdag \x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0f\u0260\xe3AE\xfb\xfd\xd2\xc9\u04a4\x99\xb6\x17\u05e0)i\xb9\x89\t\xc2\x00vQ\xb2P\x00\x00\xe0\x94\x0f\xcf\xc4\x06P\b\xcf\xd3#0_b\x86\xb5zM\xd7\xee\xe2;\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x0f\xdde@#\x95\u07db\u045f\xeeE\a\xefSE\xf7E\x10L\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x0f\xecN\xe0\xd7\xca\x18\x02\x90\xb6\xbd \xf9\x99#B\xf6\x0f\xf6\x8d\x89\x12 \u007f\x0e\xdc\xe9q\x80\x00\u07d4\x0f\ue06c3\x1e\xfd\x8f\x81\x16\x1cW8+\xb4P{\xb9\xeb\xec\x89\x15\xaf\x88\r\x8c\u06c3\x00\x00\u07d4\x0f\xfe\xa0mq\x13\xfbj\xec(i\xf4\xa9\u07f0\x90\a\xfa\xce\xf4\x89\f8F\x81\xb1\xe1t\x00\x00\u07d4\x10\tq\x98\xb4\xe7\xee\x91\xff\x82\xcc/;\xd9_\xeds\xc5@\xc0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x10\vM\tw\xfc\xba\xd4\u07bd^d\xa0Iz\xea\xe5\x16\x8f\xab\x89\x11\f\x90s\xb5$Z\x00\x00\xe0\x94\x10\x1a\nd\xf9\xaf\xccD\x8a\x8a\x13\rM\xfc\xbe\xe8\x957\xd8T\x8a\x037\xfe_\xea\xf2\u0440\x00\x00\u07d4\x10,G}i\xaa\u06e9\xa0\xb0\xf6+tY\xe1\u007f\xbb\x1c\x15a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x101\xe0\xec\xb5I\x85\xae!\xaf\x17\x93\x95\r\xc8\x11\x88\x8f\xde|\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x104d\x14\xbe\xc6\xd3\xdc\xc4NP\xe5MT\u00b8\xc3sN>\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x108\x98X\xb8\x00\xe8\xc0\xec2\xf5\x1e\xd6\x1a5YF\xcc@\x9b\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x10Y\xcb\xc6>6\xc4>\x88\xf3\x00\b\xac\xa7\xce\x05\x8e\ua816\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\x10n\xd5\xc7\x19\xb5&\x14w\x89\x04%\xaeuQ\xdcY\xbd%\\\x8a\x02\x89jX\xc9[\xe5\x88\x00\x00\u07d4\x10q\x1c=\xda21x\x85\xf0\xa2\xfd\x8a\xe9.\x82\x06\x9b\r\v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x10sy\xd4\xc4gFO#[\xc1\x8eU\x93\x8a\xad>h\x8a\u05c9\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x10v!-Ou\x8c\x8e\xc7\x12\x1c\x1c}t%I&E\x92\x84\x8a\ai[Y\xb5\xc1{L\x00\x00\u07d4\x10x\xd7\xf6\x1b\x0eV\xc7N\xe6c[.\x18\x19\xef\x1e=\x87\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x10z\x03\xcf\bB\xdb\u07b0a\x8f\xb5\x87\xcai\x18\x9e\xc9/\xf5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x10\x80\xc1\xd85\x8a\x15\xbc\x84\xda\xc8%\x89\u0392\xb9\x81\x89t\xc1\xfa\xb8\xad\xb4T\x00\x00\u07d4\x10\xe1\xe37x\x85\xc4-}\xf2\x18R.\xe7vh\x87\xc0^j\x89\x10C\xc4<\xde\x1d9\x80\x00\u07d4\x10\u342d+\xa3=\x82\xb3s\x88\u041cED\u01b0\"]\xe5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x10\xf4\xbf\xf0\u02a5\x02|\nj-\xcf\xc9R\x82M\xe2\x94\t\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11\x00\x1b\x89\xed\x87>:\xae\xc1\x15V4\xb4h\x16C\x98c#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x11\x027\u03d1\x17\xe7g\x92/\u0121\xb7\x8dyd\u0682\xdf \x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x11\x11\xe5\xdb\xf4^o\x90mb\x86o\x17\b\x10\x17\x88\xdd\xd5q\x89F{\xe6S>\xc2\xe4\x00\x00\xe0\x94\x11\x17+'\x8d\xddD\xee\xa2\xfd\xf4\xcb\x1d\x16\x96#\x91\xc4S\u064a\xc6/=\x9b\xfdH\x95\xf0\x00\x00\u07d4\x11&4\xb4\xec0\xffxn\x02AY\xf7\x96\xa5y9\xea\x14N\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x110l}WX\x867x\x0f\xc9\xfd\xe8\xe9\x8e\xcb\x00\x8f\x01d\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x116\x12\xbc;\xa0\xeeH\x98\xb4\x9d\xd2\x023\x90_/E\x8fb\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x11A_\xaba\xe0\xdf\u0539\x06v\x14\x1aUz\x86\x9b\xa0\xbd\xe9\x89o\x05\xb5\x9d; \x00\x00\x00\u07d4\x11L\xbb\xbfo\xb5*\xc4\x14\xbe~\xc6\x1f{\xb7\x14\x95\xce\x1d\xfa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x11L\xfe\xfeP\x17\r\xd9z\xe0\x8f\nDTIx\u0159T\x8d\x89.\u0207\xe7\xa1J\x1c\x00\x00\u07d4\x11a\b\xc1 \x84a.\xed\xa7\xa9=\xdc\xf8\xd2`.'\x9e\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11d\u02aa\x8c\u0157z\xfe\x1f\xad\x8a}`(\xce-W)\x9b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x11gZ%UF\a\xa3\xb6\xc9*\x9e\xe8\xf3ou\xed\xd3\xe36\x89\b\xa9\xab\xa5W\xe3l\x00\x00\u07d4\x11j\t\xdff\xcb\x15\x0e\x97W\x8e)\u007f\xb0n\x13\x04\f\x89<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11o\xef^`\x16B\xc9\x18\u02c9\x16\x0f\xc2);\xa7\x1d\xa96\x89+|\xc2\xe9\xc3\"\\\x00\x00\u07d4\x11xP\x1f\xf9J\xdd\x1cX\x81\xfe\x88a6\xf6\xdf\xdb\xe6\x1a\x94\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x11y\xc6\r\xbd\x06\x8b\x15\v\aM\xa4\xbe#\x03; \u0185X\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\x11}\x9a\xa3\xc4\xd1;\xee\x12\xc7P\x0f\t\xf5\xdd\x1cf\xc4e\x04\x89\v*\xd3\x04\x90\xb2x\x00\x00\xe0\x94\x11}\xb867\u007f\xe1TU\xe0,.\xbd\xa4\v\x1c\xebU\x1b\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x11\x8c\x18\xb2\xdc\xe1p\xe8\xf4Eu;\xa5\xd7Q<\xb7cm-\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\x11\x8f\xbdu;\x97\x929Z\xefzMx\xd2c\xcd\u02ab\xd4\xf7\x8963\x03\"\xd5#\x8c\x00\x00\xe0\x94\x11\x92\x83x\xd2}U\xc5 \xce\xed\xf2L\xeb\x1e\x82-\x89\r\xf0\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x11\x9a\xa6M[}\x18\x1d\xae\x9d<\xb4I\x95\\\x89\xc1\xf9c\xfa\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\x11\xc05\x8a\xa6G\x9d\xe2\x18f\xfe!\a\x19$\xb6^p\xf8\xb9\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\xe0\x94\x11\xd2$z\"\x1ep\xc2\xd6m\x17\xee\x13\x8d8\xc5_\xfb\x86@\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x11\u05c4JG\x1e\xf8\x9a\x8d\x87uUX<\xee\xbd\x149\xea&\x8a\x02#i\u6e80\u0188\x00\x00\u07d4\x11\xdda\x85\u0668\xd7=\xdf\u06a7\x1e\x9bwtC\x1cM\xfe\u008965\u026d\xc5\u07a0\x00\x00\u07d4\x11\xe7\x99~\u0750E\x03\xd7}\xa6\x03\x8a\xb0\xa4\xc84\xbb\xd5c\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\x11\xec\x00\xf8I\xb61\x9c\xf5\x1a\xa8\u074ff\xb3U)\xc0\xbew\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11\ufe22\x04Q\x16\x1bdJ\x8c\u03bb\xc1\xd3C\xa3\xbb\xcbR\x89\xadx\xeb\u016cb\x00\x00\x00\xe0\x94\x11\xfe\xfb]\xc1\xa4Y\x8a\xa7\x12d\fQwu\u07e1\xd9\x1f\x8c\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x12\x0f\x9d\xe6\xe0\xaf~\xc0*\a\xc6\t\u0284G\xf1W\xe64L\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x12\x10\xf8\v\u06c2l\x17Tb\xab\a\x16\xe6\x9eF\xc2J\xd0v\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x12\x13N\u007fk\x01{\xf4\x8e\x85Z9\x9c\xa5\x8e.\x89/\xa5\u020965\u026d\xc5\u07a0\x00\x00\u07d4\x12\x170t\x98\x01S\xae\xaaK\r\xcb\xc7\x13.\xad\xce\xc2\x1bd\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4\x12\x1f\x85[p\x14\x9a\xc84s\xb9po\xb4MG\x82\x8b\x98;\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x12'\xe1\nM\xbf\x9c\xac\xa3\x1b\x17\x80#\x9fUv\x15\xfc5\xc1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x12-\xcf\xd8\x1a\u0779}\x1a\x0eI%\u0135I\x80n\x9f;\xeb\x89R 5\xccn\x01!\x00\x00\u07d4\x12/V\x12%I\xd1h\xa5\xc5\xe2g\xf5&b\xe5\xc5\xcc\xe5\u0209\n\ad\a\xd3\xf7D\x00\x00\xe0\x94\x121o\xc7\xf1x\xea\xc2.\xb2\xb2Z\xed\xea\xdf=u\xd0\x01w\x8a\x04<3\xbe\x05\xf6\xbf\xb9\x80\x00\xe0\x94\x127Y\xf33\xe1>0i\xe2\x03KO\x059\x89\x18\x11\x9d6\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x12\\\xc5\xe4\xd5k+\xcc.\xe1\xc7\t\xfb\x9eh\xfb\x17t@\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x12c#\x88\xb2v^\xe4E+P\x16\x1d\x1f\xff\xd9\x1a\xb8\x1fJ\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\u07d4\x12h\x97\xa3\x11\xa1J\xd4;x\xe0\x92\x01\x00\xc4Bk\xfdk\u07494\xc7&\x89?-\x94\x80\x00\u07d4\x12m\x91\xf7\xad\x86\u07bb\x05W\xc6\x12\xca'n\xb7\xf9m\x00\xa1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x12}?\xc5\x00;\xf6<\r\x83\xe99W\x83e\x15\xfd'\x90E\x89\x06\x10\xc9\".nu\x00\x00\xe0\x94\x12}\xb1\xca\xdf\x1bw\x1c\xbdtu\xe1\xb2ri\x0fU\x8c\x85e\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x12\x84\xf0\xce\xe9\xd2\xff)\x89\xb6Ut\xd0o\xfd\x9a\xb0\xf7\xb8\x05\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x12\x8b\x90\x8f\xe7C\xa44 =\xe2\x94\xc4A\xc7\xe2\n\x86\xeag\x89&\xab\x14\xe0\xc0\xe1<\x00\x00\xe0\x94\x12\x93\u01cc}jD;\x9dt\xb0\xba^\xe7\xbbG\xfdA\x85\x88\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\x12\x96\xac\xde\xd1\xe0c\xaf9\xfe\x8b\xa0\xb4\xb6=\xf7\x89\xf7\x05\x17\x89\x05k\xf9\x1b\x1ae\xeb\x00\x00\u07d4\x12\xaa}\x86\xdd\xfb\xad0\x16\x92\xfe\xac\x8a\b\xf8A\xcb!\\7\x89\amA\xc6$\x94\x84\x00\x00\xe0\x94\x12\xaf\xbc\xba\x14'\xa6\xa3\x9e{\xa4\x84\x9fz\xb1\xc45\x8a\xc3\x1b\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x12\xb5\xe2\x89E\xbb)i\xf9\xc6Lc\xcc\x05\xb6\xf1\xf8\xd6\xf4\u054a\x01\xa2\x9e\x86\x91;t\x05\x00\x00\u0794\x12\u03cb\x0eFR\x13!\x1a[S\u07f0\xdd'\x1a(,\x12\u0248\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x12\xd2\a\x90\xb7\xd3\xdb\u060c\x81\xa2y\xb8\x12\x03\x9e\x8a`;\u0409V\xf9\x85\u04c6D\xb8\x00\x00\xe0\x94\x12\xd6\re\xb7\xd9\xfcH\x84\v\xe5\xf8\x91\xc7E\xcev\xeeP\x1e\x8a\x04\x85\xe58\x8d\fv\x84\x00\x00\u0794\x12\xd9\x1a\x92\xd7O\xc8a\xa7)dm\xb1\x92\xa1%\xb7\x9fSt\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\x12\u992d*\xd5t\x84\xddp\x05e\xbd\xdbFB;\u067d1\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x12\xf3,\n\x1f-\xaa\xb6v\xfei\xab\xd9\xe0\x185-L\xcdE\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x12\xf4`\xaedl\xd2x\x0f\xd3\\P\xa6\xafK\x9a\xcc\xfa\x85\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x12\xff\xc1\x12\x86\x05\xcb\f\x13p\x9ar\x90Po&\x90\x97q\x93\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x13\x03$F\xe7\xd6\x10\xaa\x00\xec\x8cV\u0275t\xd3l\xa1\xc0\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\x1cy,\x19}\x18\xbd\x04]p$\x93|\x1f\x84\xb6\x0fD8\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13\x1d\xf8\xd30\xeb|\xc7\x14}\nUWo\x05\u078d&\xa8\xb7\x89\n1\x06+\xee\xedp\x00\x00\u07d4\x13\x1f\xae\xd1%a\xbbz\xee\x04\xe5\x18Z\xf8\x02\xb1\xc3C\x8d\x9b\x89\v\xdf\x0e\u0733\x90\xc9\xc8V\b\xb7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13!\xcc\xf2\x979\xb9t\xe5\xa5\x16\xf1\x8f:\x846q\xe3\x96B\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13'\xd7Y\xd5n\n\xb8z\xf3~\xcfc\xfe\x01\xf3\x10\xbe\x10\n\x89#\xbc<\xdbh\xa1\x80\x00\x00\u07d4\x13)\xdd\x19\xcdK\xaa\x9f\xc6C\x10\xef\xec\xea\xb2!\x17%\x1f\x12\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x137\x1f\x92\xa5n\xa88\x1eC\x05\x9a\x95\x12\x8b\xdcMC\u0166\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x13O\x15\xe1\xe3\x9cSCY0\xaa\xed\xf3\xe0\xfeV\xfd\xe8C\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x13Ac\xbe\x9f\xbb\xe1\xc5in\xe2U\xe9\v\x13%C\x95\xc3\x18\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x13\\\xec\xd9U\xe5y\x83pv\x920\x15\x93\x03\u0671\x83\x9ff\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x13]\x17\x19\xbf\x03\xe3\xf8f1$y\xfe3\x81\x18\xcd8~p\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x13^\xb8\xc0\xe9\xe1\x01\xde\xed\xec\x11\xf2\xec\xdbf\xae\x1a\xae\x88g\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x13`\xe8}\xf2Li\xeemQ\xc7nsv\u007f\xfe\x19\xa2\x13\x1c\x89\x04\xfc\xc1\xa8\x90'\xf0\x00\x00\u07d4\x13l\x83K\xf1\x112m s\x95)[.X>\xa7\xf35r\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x13mKf+\xbd\x10\x80\xcf\xe4D[\x0f\xa2\x13\x86D5\xb7\xf1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13oI\a\u02b4\x1e'\bK\x98E\x06\x9f\xf2\xfd\f\x9a\xdey\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13t\xfa\xcd{?\x8dhd\x9d`\xd4U\x0e\xe6\x9f\xf0HA3\x89\x0e\x9e\xd6\xe1\x11r\xda\x00\x00\u07d4\x13|\xf3A\xe8Ql\x81X\x14\xeb\xcds\xe6V\x9a\xf1L\xf7\xbc\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x13\x84\x8bF\xeau\xbe\xb7\xea\xa8_Y\xd8f\xd7\u007f\xd2L\xf2\x1a\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x13\x9d51\u0252*\xd5bi\xf60\x9a\xa7\x89\xfb$\x85\xf9\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13\x9eG\x97d\xb4\x99\xd6f \x8cJ\x8a\x04z\x97\x041c\u0749 w!*\xffm\xf0\x00\x00\u07d4\x13\xa5\xee\xcb80]\xf9Iq\xef-\x9e\x17\x9a\xe6\u03ba\xb37\x89\x11\u3ac3\x95\xc6\xe8\x00\x00\u07d4\x13\xac\xad\xa8\x98\n\xff\xc7PI!\xbe\x84\xebID\xc8\xfb\xb2\xbd\x89V\u04aa:\\\t\xa0\x00\x00\u07d4\x13\xb9\xb1\a\x15qL\t\xcf\xd6\x10\u03dc\x98F\x05\x1c\xb1\xd5\x13\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x13\xce3-\xffe\xa6\xab\x938\x97X\x8a\xa2>\x00\t\x80\xfa\x82\x89\x0e\x02\x056\xf0(\xf0\x00\x00\u07d4\x13\xd6z~%\xf2\xb1,\u06c5XP\t\xf8\xac\u011b\x96s\x01\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x13\xde\xe0>7\x99\x95-\a8\x84=K\xe8\xfc\n\x80?\xb2\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\xe0/\xb4H\xd6\xc8J\xe1}\xb3\x10\xad(m\x05a`\u0695\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\xe3!r\x8c\x9cWb\x80X\xe9?\xc8f\xa02\xdd\v\u0690\x89&\xbc\xca#\xfe.\xa2\x00\x00\u07d4\x13\xec\x81\"\x84\x02n@\x9b\xc0f\xdf\xeb\xf9\u0564\xa2\xbf\x80\x1e\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\x14\x01)\xea\xa7f\xb5\xa2\x9f[:\xf2WND\t\xf8\xf6\xd3\xf1\x8a\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u07d4\x14\x05\x18\xa3\x19K\xad\x13P\xb8\x94\x9ee\x05e\u07bem\xb3\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x14\x06\x85M\x14\x9e\b\x1a\xc0\x9c\xb4\xcaV\r\xa4c\xf3\x120Y\x89Hz\x9a0E9D\x00\x00\u07d4\x14\f\xa2\x8f\xf3;\x9ff\xd7\xf1\xfc\x00x\xf8\xc1\xee\xf6\x9a\x1b\xc0\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x14\x0f\xbaX\xdb\xc0H\x03\xd8L!0\xf0\x19x\xf9\xe0\xc71)\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\x14\x1a^9\xee/h\n`\x0f\xbfo\xa2\x97\u0790\xf3\"\\\u074a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x14%N\xa1&\xb5-\x01B\xda\n~\x18\x8c\xe2U\xd8\xc4qx\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\x14+\x87\xc5\x04?\xfbZ\x91\xdf\x18\xc2\xe1\t\xce\xd6\xfeJq\u06c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x14\x87\xf5\xa5$\u0288Q^\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4\x14\xa75 f6D\x04\xdbP\xf0\xd0\u05cduJ\"\x19\x8e\xf4\x89e\xea=\xb7UF`\x00\x00\u07d4\x14\xab\x16K;RL\x82\u05ab\xfb\xc0\u0783\x11&\xae\x8d\x13u\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x14\xb1`>\xc6+ \x02 3\xee\xc4\xd6\xd6eZ\xc2J\x01Z\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x14\xc6;\xa2\u0731\xddM\xf3=\u06b1\x1cO\x00\a\xfa\x96\xa6-\x8a\x03HA\xb6\x05z\xfa\xb0\x00\x00\xe0\x94\x14\xcd\u077c\x8b\t\xe6gZ\x9e\x9e\x05\t\x1c\xb9\"8\u00de\x1e\x8a\x01\x14x\xb7\xc3\n\xbc0\x00\x00\u07d4\x14\xd0\n\xad9\xa0\xa7\u045c\xa0SP\xf7\xb07'\xf0\x8d\xd8.\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x14\xee\xc0\x9b\xf0>5+\xd6\xff\x1b\x1e\x87k\xe6d\xce\xff\xd0\u03c9\x01\x16\xdc:\x89\x94\xb3\x00\x00\u07d4\x14\xf2!\x15\x95\x18x;\u0127\x06go\xc4\xf3\xc5\xee@X)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x14\xfc\xd19\x1e}s/Avl\xda\u0344\xfa\x1d\xeb\x9f\xfd\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x0e=\xbc\xbc\xfc\x84\xcc\xf8\x9bsBwc\xa5e\xc2>`\u0409\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\x15\x18b{\x885\x1f\xed\xe7\x96\xd3\xf3\b3d\xfb\u0508{\f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u0794\x15\"J\xd1\xc0\xfa\xceF\xf9\xf5V\xe4wJ0%\xad\x06\xbdR\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x15/+\xd2)\xdd\xf3\xcb\x0f\xda\xf4U\xc1\x83 \x9c\x0e\x1e9\xa2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x15/N\x86\x0e\xf3\xee\x80jP'w\xa1\xb8\xdb\xc9\x1a\x90vh\x89 \x86\xac5\x10R`\x00\x00\u07d4\x15<\b\xaa\x8b\x96\xa6\x11\xefc\xc0%>*C4\x82\x9eW\x9d\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\x15<\xf2\x84,\xb9\u0787l'o\xa6Gg\u0468\xec\xf5s\xbb\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15>\xf5\x8a\x1e.z>\xb6\xb4Y\xa8\n\xb2\xa5G\xc9A\x82\xa2\x8a\x14T+\xa1*3|\x00\x00\x00\u07d4\x15DY\xfa/!1\x8e44D\x97\x89\xd8&\xcd\xc1W\f\xe5\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15G\xb9\xbfz\xd6bt\xf3A8'#\x1b\xa4\x05\ue308\xc1\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\x15H\xb7p\xa5\x11\x8e\u0787\u06e2\xf6\x903\u007fam\u60eb\x89\x1c\x99V\x85\u0fc7\x00\x00\u07d4\x15R\x83P\xe0\xd9g\n.\xa2\u007f{J3\xb9\xc0\xf9b\x1d!\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x15[7y\xbbmV4./\u0681{[-\x81\xc7\xf4\x13'\x89\x02\xb8\xaa:\al\x9c\x00\x00\u07d4\x15e\xaf\x83~\xf3\xb0\xbdN+#V\x8dP#\xcd4\xb1d\x98\x89\x15Q\xe9rJ\u013a\x00\x00\u07d4\x15f\x91\x80\xde\u2558\x86\x9b\b\xa7!\xc7\xd2LL\x0e\xe6?\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x15r\xcd\xfa\xb7*\x01\u0396\x8ex\xf5\xb5D\x8d\xa2\x98S\xfb\u074a\x01\x12blI\x06\x0f\xa6\x00\x00\xe0\x94\x15uY\xad\xc5Wd\xccm\xf7\x93#\t%4\xe3\xd6dZf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x15x\xbd\xbc7\x1bM$8E3\x05V\xff\xf2\xd5\xefM\xffg\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x15~\xb3\xd3\x11;\u04f5\x97qM:\x95N\xdd\x01\x89\x82\xa5\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x84\xa2\xc0f\xb7\xa4U\xdb\u05ae(\a\xa73N\x83\xc3_\xa5\x89\a\f\x1c\xc7;\x00\xc8\x00\x00\u07d4\x15\x87F\x86\xb6s=\x10\xd7\x03\xc9\xf9\xbe\xc6\xc5.\xb8b\x8dg\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x8a\ra\x92S\xbfD2\xb5\xcd\x02\u01f8b\xf7\u00b7V6\x89\a[\xac|[\x12\x18\x80\x00\u07d4\x15\x98\x12y\x82\xf2\xf8\xad;k\x8f\xc3\xcf'\xbfax\x01\xba+\x89\t`\xdbwh\x1e\x94\x00\x00\xe0\x94\x15\x9a\xdc\xe2z\xa1\vG#d)\xa3JZ\xc4,\xad[d\x16\x8a\x06\xbf\x90\xa9n\xdb\xfaq\x80\x00\u07d4\x15\xa0\xae\xc3\u007f\xf9\xff=T\t\xf2\xa4\xf0\xc1!*\xac\xcb\x02\x96\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x15\xaaS\r\xc3iX\xb4\xed\xb3\x8e\xeem\xd9\xe3\xc7}L\x91E\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15\xac\xb6\x15h\xecJ\xf7\xea(\x198a\x81\xb1\x16\xa6\xc5\xeep\x8a\x06\x90\x83l\n\xf5\xf5`\x00\x00\u07d4\x15\xb9o0\xc2;\x86d\xe7I\x06Q\x06k\x00\xc49\x1f\xbf\x84\x89\x16B\xe9\xdfHv)\x00\x00\u07d4\x15\xc7\xed\xb8\x11\x8e\xe2{4\"\x85\xebY&\xb4z\x85[\u01e5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x15\u0654hPz\xa0A?\xb6\r\xca*\xdc\u007fV\x9c\xb3kT\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15\u06f4\x8c\x980\x97d\xf9\x9c\xed6\x92\xdc\xca5\xee0k\xac\x8a\x1f\u00c4+\xd1\xf0q\xc0\x00\x00\xe0\x94\x15\u072f\xcc+\xac\xe7\xb5[T\xc0\x1a\x1cQF&\xbfa\xeb\u060a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x15\u3d44\x05kb\xc9s\xcf^\xb0\x96\xf1s>T\xc1\\\x91\x892\xc7Z\x02#\xdd\xf3\x00\x00\u07d4\x15\xeb\xd1\xc7\xca\u04af\xf1\x92u\xc6W\xc4\xd8\b\xd0\x10\xef\xa0\xf5\x89\n\xdf0\xbap\u0217\x00\x00\u07d4\x15\xee\x0f\xc6>\xbf\x1b\x1f\u011d{\xb3\x8f\x88c\x82:.\x17\u0489g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x15\xf1\xb3R\x11\rh\x90\x1d\x8fg\xaa\xc4jl\xfa\xfe\x03\x14w\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x15\xf2\xb7\xb1d2\xeeP\xa5\xf5[A#/c4\xedX\xbd\xc0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x16\x01\x9aM\xaf\xabC\xf4\u067fAc\xfa\xe0\x84}\x84\x8a\xfc\xa2\x89\x01[\xc7\x019\xf7J\x00\x00\u07d4\x16\x02&\xef\xe7\xb5:\x8a\xf4b\xd1\x17\xa0\x10\x80\x89\xbd\xec\xc2\u0449\n\xdf0\xbap\u0217\x00\x00\u07d4\x16\f\xebo\x98\x0e\x041_S\xc4\xfc\x98\x8b+\xf6\x9e(M}\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\xe0\x94\x16\x1c\xafZ\x97*\u0383y\xa6\u0420J\xe6\xe1c\xfe!\xdf+\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x16\x1d&\xefgY\xba[\x9f \xfd\xcdf\xf1a2\xc3RA^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16!\x10\xf2\x9e\xac_}\x02\xb5C\xd8\xdc\u057bY\xa5\xe3;s\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x16+\xa5\x03'b\x14\xb5\t\xf9u\x86\xbd\x84!\x10\xd1\x03\xd5\x17\x8a\x01\xe7\xff\u0609\\\"h\x00\x00\u07d4\x16-v\xc2\xe6QJ:\xfbo\xe3\xd3\u02d3\xa3\\Z\xe7\x83\xf1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16;\xadJ\x12+E}d\xe8\x15\nA>\xaeM\a\x02>k\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u07d4\x16<\u023e\"vF\xcb\tq\x91Y\xf2\x8e\u041c]\xc0\xdc\xe0\x89Hz\x9a0E9D\x00\x00\u07d4\x16=\xcas\xd7\xd6\xea?>`b2*\x874\x18\f\vx\uf25ft \x03\xcb}\xfc\x00\x00\u07d4\x16Mz\xac>\xec\xba\uc86dQ\x91\xb7S\xf1s\xfe\x12\xec3\x89(VR\xb8\xa4hi\x00\x00\u07d4\x16Rl\x9e\u07d4>\xfaOm\x0f\v\xae\x81\xe1\x8b1\xc5@y\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x16S\x05\xb7\x872.%\xdcj\xd0\xce\xfelo3Fx\xd5i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16e\xab\x179\xd7\x11\x19\xeea2\xab\xbd\x92j'\x9f\xe6yH\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x16k\xf6\u06b2-\x84\x1bHl8\xe7\xbaj\xb3:\x14\x87\ud30a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x16v\x99\xf4\x8ax\xc6\x15Q%\x15s\x99X\x993\x12WO\a\x89\x02\x1d;\xd5^\x80<\x00\x00\u07d4\x16x\xc5\xf2\xa5\"92%\x19ca\x89OS\xccu/\xe2\xf3\x89h\xf3e\xae\xa1\xe4@\x00\x00\u07d4\x16|\xe7\xdee\xe8G\bYZRT\x97\xa3\xeb^ZfPs\x89\x1f1Gsfo\xc4\x00\x00\u07d4\x16~>:\xe2\x003HE\x93\x92\xf7\xdf\xceD\xaf|!\xadY\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x16\x80\xce\xc5\x02\x1e\xe90P\xf8\xae\x12rQ\x83\x9et\xc1\xf1\xfd\x8a\x02\xc6\x14a\xe5\xd7C\u0580\x00\u07d4\x16\x81j\xac\x0e\xde\r-<\xd4B\xday\xe0c\x88\x0f\x0f\x1dg\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x16\x8bP\x19\xb8\x18i\x16D\x83_\xe6\x9b\xf2)\xe1q\x12\xd5,\x8a\x05\xed\xe2\x0f\x01\xa4Y\x80\x00\x00\u07d4\x16\x8b\xde\xc8\x18\xea\xfcm)\x92\xe5\xefT\xaa\x0e\x16\x01\xe3\xc5a\x8967Pz0\xab\xeb\x00\x00\u07d4\x16\x8d0\xe5?\xa6\x81\t+R\xe9\xba\xe1Z\r\xcbA\xa8\u027b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x16\x9b\xbe\xfcA\xcf\xd7\xd7\u02f8\xdf\xc60 \xe9\xfb\x06\u0515F\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xa5\x8e\x98]\xcc\xd7\a\xa5\x94\u0453\xe7\u0327\x8b]\x02xI\x89I\xb9\u029aiC@\x00\x00\u07d4\x16\xa9\xe9\xb7:\u92c6M\x17(y\x8b\x87f\xdb\xc6\xea\x8d\x12\x893\xe7\xb4K\r\xb5\x04\x00\x00\u07d4\x16\xaaR\xcb\vUG#\xe7\x06\x0f!\xf3'\xb0\xa6\x83\x15\xfe\xa3\x89\r\x8drkqw\xa8\x00\x00\u07d4\x16\xab\xb8\xb0!\xa7\x10\xbd\u01ce\xa54\x94\xb2\x06\x14\xffN\xaf\xe8\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x16\xaf\xa7\x87\xfc\x9f\x94\xbd\xffiv\xb1\xa4/C\n\x8b\xf6\xfb\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xba\xe5\xd2N\xff\x91w\x8c\u064bM:\x1c\xc3\x16/D\xaaw\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\x16\xbc@!Z\xbb\u066e](\v\x95\xb8\x01\vE\x14\xff\x12\x92\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x16\xbeu\u9299Z9R\"\xd0\v\u05df\xf4\xb6\xe68\u144a\a\x9f\x90\\o\xd3N\x80\x00\x00\u07d4\x16\xc1\xbf[}\xc9\xc8<\x17\x9e\xfa\xcb\xcf.\xb1t\xe3V\x1c\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x16\u01f3\x1e\x8c7b\x82\xac\"qr\x8c1\xc9^5\xd9R\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xf3\x13\u03ca\xd0\x00\x91J\n\x17m\u01a44+y\xec%8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xff\xac\x84\x03)@\xf0\x12\x1a\tf\x8b\x85\x8a~y\xff\xa3\xbb\x89\xd2J\xdan\x10\x87\x11\x00\x00\xe0\x94\x17\x03\xb4\xb2\x92\xb8\xa9\xde\xdd\xed\xe8\x1b\xb2]\x89\x17\x9fdF\xb6\x8a\x04+e\xa4U\xe8\xb1h\x00\x00\u07d4\x17\x04\x93\x11\x10\x1d\x81~\xfb\x1de\x91\x0ff6b\xa6\x99\u024c\x89lh\xcc\u041b\x02,\x00\x00\u07d4\x17\x04\xce\xfc\xfb\x131\xeczx8\x8b)9>\x85\xc1\xafy\x16\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17\n\x88\xa8\x99\u007f\x92\xd287\x0f\x1a\xff\xde\xe64pP\xb0\x13\x89\xa2\xacw5\x14\x880\x00\x00\u07d4\x17\x10\x8d\xab,P\xf9\x9d\xe1\x10\u1cf3\xb4\u0342\xf5\xdf(\xe7\x895 ;g\xbc\xca\xd0\x00\x00\xe0\x94\x17\x12[Y\xacQ\xce\xe0)\xe4\xbdx\xd7\xf5\x94}\x1e\xa4\x9b\xb2\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4\x17\x1a\u0660K\xed\u0238a\xe8\xedK\xdd\xf5qx\x13\xb1\xbbH\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17\x1c\xa0*\x8bmb\xbfL\xa4~\x90i\x14\a\x98a\x97,\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x17\"\xc4\xcb\xe7\n\x94\xb6U\x9dBP\x84\xca\xee\xd4\xd6\xe6n!\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x17X\vvotSR\\\xa4\u01a8\x8b\x01\xb5\x05p\xea\b\x8c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x17X\x9al\x00jT\xca\xd7\x01\x03\x12:\xae\n\x82\x13_\u07b4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x17Z\x18::#_\xfb\xb0;\xa85gRg\"\x94\x17\xa0\x91\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x17_\xee\xea*\xa4\xe0\xef\xda\x12\xe1X\x8d/H2\x90\xed\xe8\x1a\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x17e6\x1c.\xc2\xf86\x16\u0383c\xaa\xe2\x10%\xf2Vo@\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x17gR\\_Z\"\xed\x80\xe9\xd4\xd7q\x0f\x03b\u049e\xfa3\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17v%`\xe8*\x93\xb3\xf5\"\xe0\xe5$\xad\xb8a,:tp\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x17}\xaex\xbc\x01\x13\xd8\u04dcD\x02\xf2\xa6A\xae*\x10Z\xb8\x89b\x92BV \xb4H\x00\x00\xe0\x94\x17\x84\x94\x8b\xf9\x98H\u021eDV8PM\u0598'\x1bY$\x8a\x01GLA\r\x87\xba\xee\x00\x00\u07d4\x17\x88\u069bW\xfd\x05\xed\xc4\xff\x99\xe7\xfe\xf3\x01Q\x9c\x8a\n\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\x8e\xafk\x85T\xc4]\xfd\xe1kx\xce\f\x15\u007f.\xe3\x13Q\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\x17\x96\x1dc;\xcf \xa7\xb0)\xa7\xd9K}\xf4\xda.\xc5B\u007f\x89\fo\xf0p\U000532c0\x00\u07d4\x17\x96\xbc\xc9{\x8a\xbcq\u007fKJ|k\x106\xea!\x82c\x9f\x89\x13A\xf9\x1c\xd8\xe3Q\x00\x00\u07d4\x17\x99=1*\xa1\x10iW\x86\x8fjU\xa5\xe8\xf1/w\xc8C\x89\x18e\xe8\x14\xf4\x14.\x80\x00\u07d4\x17\x9a\x82^\x0f\x1fn\x98S\tf\x84e\xcf\xfe\xd46\xf6\xae\xa9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x17\xb2\xd6\xcfe\xc6\xf4\xa3G\xdd\xc6W&U5M\x8aA+)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xb8\a\xaf\xa3\xdd\xd6G\xe7#T.{R\xfe\xe3\x95'\xf3\x06\x89\x15\xaf@\xff\xa7\xfc\x01\x00\x00\u07d4\x17\xc0G\x86W\xe1\xd3\xd1z\xaa3\x1d\xd4)\xce\u03d1\xf8\xae]\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\x17\xc0\xfe\xf6\x98l\xfb.@A\xf9\x97\x9d\x99@\xb6\x9d\xff=\xe2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x17\u0511\x8d\xfa\xc1]w\xc4\u007f\x9e\xd4\x00\xa8P\x19\rd\xf1Q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xd5!\xa8\xd9w\x90#\xf7\x16M#<;d \xff\xd2#\xed\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x17\xd91\xd4\xc5b\x94\u073ew\xc8e[\xe4i_\x00mJ<\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xdfIQ\x8ds\xb1)\xf0\xda6\xb1\u0274\f\xb6d \xfd\u01ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x17\xe4\xa0\xe5+\xac>\xe4N\xfe\tT\xe7S\u0538]dN\x05\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xe5\x84\xe8\x10\xe5gp,a\xd5]CK4\u0375\xee0\xf6\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x17\xe8.px\xdcO\xd9\xe8y\xfb\x8aPf\u007fS\xa5\xc5E\x91\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x17\xe8o;[0\xc0\xbaY\xf2\xb2\xe8XB[\xa8\x9f\n\x10\xb0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xee\x9fT\xd4\xdd\xc8Mg\x0e\xff\x11\xe5Je\x9f\xd7/DU\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94\x17\xefJ\xcc\x1b\xf1G\xe3&t\x9d\x10\xe6w\xdc\xff\xd7o\x9e\x06\x8a\bwQ\xf4\xe0\xe1\xb50\x00\x00\u07d4\x17\xf1F2\xa7\xe2\x82\v\xe6\xe8\xf6\u07c25X(=\xad\xab-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xf5#\xf1\x17\xbc\x9f\xe9x\xaaH\x1e\xb4\xf5V\x17\x117\x1b\u0209li\xf7>)\x13N\x00\x00\u07d4\x17\xfd\x9bU\x1a\x98\xcba\xc2\xe0\u007f\xbfA\xd3\xe8\u02650\u02e5\x89\x01v\x8c0\x81\x93\x04\x80\x00\u07d4\x18\x04x\xa6U\u05cd\x0f;\fO +aH[\xc4\x00/\u0549lk\x93[\x8b\xbd@\x00\x00\u07d4\x18\x13l\x9d\xf1g\xaa\x17\xb6\xf1\x8e\"\xa7\x02\u020fK\u0082E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x18\x15'\x9d\xff\x99R\xda;\xe8\xf7rI\xdb\xe2\"C7{\xe7\x8a\x01\x01|\xb7n{&d\x00\x00\u07d4\x18\x1f\xbb\xa8R\xa7\xf5\x01x\xb1\xc7\xf0>\xd9\xe5\x8dT\x16))\x89$\x1a\x9bOaz(\x00\x00\xe0\x94\x18'\x03\x9f\tW\x02\x94\b\x8f\xdd\xf0G\x16\\3\u65a4\x92\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\x18-\xb8R\x93\xf6\x06\u8248\xc3pL\xb3\xf0\xc0\xbb\xbf\xcaZ\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x18H\x00<%\xbf\u052a\x90\xe7\xfc\xb5\u05f1k\xcd\f\xff\xc0\u060965\u026d\xc5\u07a0\x00\x00\xe0\x94\x18JO\v\xebq\xff\xd5X\xa6\xb6\xe8\xf2(\xb7\x87\x96\xc4\xcf>\x8a\x02\x8a\x85t%Fo\x80\x00\x00\xe0\x94\x18M\x86\xf3Fj\xe6h;\x19r\x99\x82\xe7\xa7\u1903G\xb2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x18Q\xa0c\xcc\xdb0T\x90w\xf1\xd19\xe7-\xe7\x97\x11\x97\u0549lk\x93[\x8b\xbd@\x00\x00\u07d4\x18UF\xe8v\x8dPhs\x81\x8a\xc9u\x1c\x1f\x12\x11j;\xef\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x18X\xcf\x11\xae\xa7\x9fS\x98\xad+\xb2\"g\xb5\xa3\xc9R\xeat\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\xe0\x94\x18Z\u007f\u012c\xe3h\xd23\xe6 \xb2\xa4Y5f\x12\x92\xbd\xf2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x18d\xa3\u01f4\x81UD\x8cT\u020cp\x8f\x16g\tsm1\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x18j\xfd\xc0\x85\xf2\xa3\xdc\xe4a^\xdf\xfb\xad\xf7\x1a\x11x\x0fP\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x18k\x95\xf8\xe5\xef\xfd\xdc\xc9O\x1a1[\xf0)];\x1e\xa5\x88\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x18}\x9f\f\a\xf8\xebt\xfa\xaa\xd1^\xbc{\x80Dt\x17\xf7\x82\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x18\x95\xa0\xebJCrr/\xcb\u016f\xe6\x93o(\x9c\x88\xa4\x19\x891T\xc9r\x9d\x05x\x00\x00\u07d4\x18\x99\xf6\x9fe;\x05\xa5\xa6\xe8\x1fH\a\x11\u041b\xbf\x97X\x8c\x89i\xfb\x13=\xf7P\xac\x00\x00\u07d4\x18\xa6\xd2\xfcR\xbes\b@#\xc9\x18\x02\xf0[\xc2JK\xe0\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x18\xb0@|\xda\xd4\xceR`\x06#\xbd^\x1fj\x81\xaba\xf0&\x89\x11Q\xcc\xf0\xc6T\u0180\x00\u07d4\x18\xb8\xbc\xf9\x83!\xdaa\xfbN>\xac\xc1\xecT\x17'-\xc2~\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\x18\xc6r:gS)\x9c\xb9\x14G}\x04\xa3\xbd!\x8d\xf8\xc7u\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x18\xe1\x13\xd8\x17|i\x1aa\xbexXR\xfa[\xb4z\uef6f\x89Hz\x9a0E9D\x00\x00\xe0\x94\x18\xe4\xceGH;S\x04\n\u06eb5\x17,\x01\xefdPn\f\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\xe0\x94\x18\xe52C\x98\x1a\xab\xc8v}\xa1\fsD\x9f\x13\x91V\x0e\xaa\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x18\xfa\x86%\xc9\u0704>\x00\x15\x9e\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94\x193\xe34\xc4\x0f:\u02ed\f\v\x85\x11X i$\xbe\xca:\x8a\x01\x99^\xaf\x01\xb8\x96\x18\x80\x00\xe0\x94\x197\xc5\xc5\x15\x05uS\u033dF\u0546dU\xcef)\x02\x84\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u07d4\x19:\xc6Q\x83e\x18\x00\xe25\x80\xf8\xf0\xea\u04fbY~\xb8\xa4\x89\x02\xb6*\xbc\xfb\x91\n\x00\x00\u07d4\x19=7\xed4}\x1c/N55\r\x9aDK\xc5|\xa4\xdbC\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\x19@\u0713d\xa8R\x16_GAN'\xf5\x00$E\xa4\xf1C\x8a\x02L-\xffj<|H\x00\x00\u07d4\x19E\xfe7\u007f\xe6\u0537\x1e>y\x1fo\x17\xdb$<\x9b\x8b\x0f\x89vy\u7fb9\x886\x00\x00\u07d4\x19Jk\xb3\x02\xb8\xab\xa7\xa5\xb5y\u07d3\xe0\xdf\x15t\x96v%\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x19L\ubd12\x98\x82\xbf;K\xf9\x86L+\x1b\x0fb\u0083\xf9\x89\x1e\xf8aS\x1ft\xaa\x00\x00\u07d4\x19O\xf4J\xef\xc1{\xd2\x0e\xfdz LG\xd1b\f\x86\xdb]\x89\xa2\x99\th\u007fj\xa4\x00\x00\xe0\x94\x19O\xfex\xbb\xf5\xd2\r\u044a\x1f\x01\xdaU.\x00\xb7\xb1\x1d\xb1\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x19S1>*\xd7F#\x9c\xb2'\x0fH\xaf4\u063b\x9cDe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19W\x1a+\x8f\x81\u01bc\xf6j\xb3\xa1\x00\x83)V\x17\x15\x00\x03\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\xe0\x94\x19h}\xaa9\xc3h\x13\x9bn{\xe6\r\xc1u:\x9f\f\xbe\xa3\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x19l\x02!\nE\n\xb0\xb3cpe_qz\xa8{\xd1\xc0\x04\x89\x0e\x10\xac\xe1W\xdb\xc0\x00\x00\u07d4\x19n\x85\xdf~s+J\x8f\x0e\xd06#\xf4\u06dd\xb0\xb8\xfa1\x89\x01%\xb9/\\\xef$\x80\x00\u07d4\x19s+\xf9s\x05]\xbd\x91\xa4S:\u06a2\x14\x9a\x91\u04c3\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19vr\xfd9\xd6\xf2F\xcef\xa7\x90\xd1:\xa9\"\xd7\x0e\xa1\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x19y\x8c\xbd\xa7\x15\ua69b\x9dj\xab\x94,U\x12\x1e\x98\xbf\x91\x89A\rXj \xa4\xc0\x00\x00\u07d4\x19\x8b\xfc\xf1\xb0z\xe3\b\xfa,\x02\x06\x9a\xc9\xda\xfeq5\xfbG\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x19\x8e\xf1\xec2Z\x96\xcc5Lrf\xa08\xbe\x8b\\U\x8fg\x8a\x80\xd1\xe47>\u007f!\xda\x00\x00\xe0\x94\x19\x91\x8a\xa0\x9e}IN\x98\xff\xa5\xdbP5\b\x92\xf7\x15j\u018a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x19\xb3k\f\x87\xeafN\xd8\x03\x18\xdcw\xb6\x88\xdd\xe8}\x95\xa5\x89i\x9fI\x98\x020=\x00\x00\u07d4\x19\u07d4E\xa8\x1c\x1b=\x80J\xea\xebon NB6f?\x89\x02\x06\xd9NjI\x87\x80\x00\u07d4\x19\xe5\u07a37\n,tj\xae4\xa3|S\x1fA\xda&N\x83\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x19\xe7\xf3\xeb{\xf6\u007f5\x99 \x9e\xbe\b\xb6*\xd32\u007f\x8c\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\x19\xe9Nb\x00P\xaa\xd7f\xb9\xe1\xba\xd91#\x83\x12\u053fI\x89\x81\xe3-\xf9r\xab\xf0\x00\x00\u07d4\x19\xec\xf2\xab\xf4\f\x9e\x85{%/\xe1\xdb\xfd=L]\x8f\x81n\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19\xf5\xca\xf4\xc4\x0ei\b\x81<\aE\xb0\xae\xa9Xm\x9d\xd91\x89#\xfe\xd9\xe1\xfa+`\x00\x00\u07d4\x19\xf6C\xe1\xa8\xfa\x04\xae\x16\x00`(\x13\x833\xa5\x9a\x96\u0787\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x19\xf9\x9f,\vF\u0389\x06\x87]\xc9\xf9\n\xe1\x04\xda\xe3U\x94\x89\xf4WZ]M\x16*\x00\x00\u07d4\x19\xff$O\xcf\xe3\xd4\xfa/O\u065f\x87\xe5[\xb3\x15\xb8\x1e\xb6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1a\x04\xce\xc4 \xadC\"\x15$mw\xfe\x17\x8d3\x9e\u0435\x95\x89\x11!a\x85\u009fp\x00\x00\xe0\x94\x1a\x04\xd58\x9e\xb0\x06\xf9\u0388\f0\xd1SS\xf8\xd1\x1cK1\x8a\x03\x9d\x84\xb2\x18m\xc9\x10\x00\x00\u07d4\x1a\bA\xb9*\u007fpuV\x9d\xc4b~kv\u02b0Z\u0791\x89Rf<\u02b1\xe1\xc0\x00\x00\xe0\x94\x1a\b]C\xec\x92AN\xa2{\x91O\xe7g\xb6\xd4k\x1e\xefD\x8a\x06A\xe8\xa15c\xd8\xf8\x00\x00\u07d4\x1a\t\xfd\xc2\u01e2\x0e#WK\x97\u019e\x93\u07bag\xd3r \x89lO\xd1\xee$nx\x00\x00\u07d4\x1a\n\x1d\u07f01\xe5\xc8\xcc\x1dF\xcf\x05\x84-P\xfd\xdcq0\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1a\x1c\x9a&\xe0\xe0$\x18\xa5\xcfh}\xa7Z'\\b,\x94@\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x1a \x1bC'\u03a7\xf3\x99\x04bF\xa3\xc8~n\x03\xa3\u0368\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a$4\xccwD\"\u050dS\u055c]V,\u0384\a\xc9K\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\x1a%\xe1\u017c~_P\xec\x16\xf8\x88_!\x0e\xa1\xb98\x80\x0e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x1a&\x94\xec\a\xcf^Mh\xba@\xf3\xe7\xa1LS\xf3\x03\x8cn\x8966\xcd\x06\xe2\xdb:\x80\x00\u07d4\x1a5 E5\x82\xc7\x18\xa2\x1cB7[\xc5\as%RS\xe1\x89*\xd3s\xcef\x8e\x98\x00\x00\xe0\x94\x1a7n\x1b-/Y\ai\xbb\x85\x8dEu2\rN\x14\x99p\x8a\x01\x06q%v9\x1d\x18\x00\x00\u07d4\x1a:3\x0eO\xcbi\xdb\xef^i\x01x;\xf5\x0f\xd1\xc1SB\x89\u3bb5sr@\xa0\x00\x00\u07d4\x1aN\u01a0\xae\u007fZ\x94'\xd2=\xb9rL\r\f\xff\xb2\xab/\x89\t\xb4\x1f\xbf\x9e\n\xec\x00\x00\u07d4\x1aP^b\xa7N\x87\xe5wG>O:\xfa\x16\xbe\xdd<\xfaR\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x1a^\xe53\xac\xbf\xb3\xa2\xd7m[hRw\xb7\x96\xc5j\x05+\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1adJP\xcb\u00ae\xe8#\xbd+\xf2C\xe8%\xbeMG\xdf\x02\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\x1apD\xe28?\x87\b0[I[\xd1\x17k\x92\xe7\xef\x04:\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1ay\xc7\xf4\x03\x9cg\xa3\x9du\x13\x88L\xdc\x0e,4\"$\x90\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1a\x89\x89\x9c\xbe\xbd\xbbd\xbb&\xa1\x95\xa6<\bI\x1f\u035e\xee\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1a\x8a\\\xe4\x14\u079c\xd1r\x93~7\xf2\u055c\xffq\xceW\xa0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1a\x95\xa8\xa8\b.FR\xe4\x17\r\xf9'\x1c\xb4\xbbC\x05\xf0\xb2\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x1a\x95\u0277Tk]\x17\x86\u00c5\x8f\xb1#dF\xbc\f\xa4\u0389j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1a\x98~?\x83\xdeu\xa4/\x1b\xde|\x99|\x19!{J_$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1a\x9ep/8]\xcd\x10^\x8b\x9f\xa4(\xee\xa2\x1cW\xffR\x8a\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1a\xa1\x02\x1fU\n\xf1X\xc7Gf\x8d\xd1;F1`\xf9Z@\x89O\xb0Y\x1b\x9b08\x00\x00\u07d4\x1a\xa2v\x99\xca\u068d\u00e7oy3\xaaf\xc7\x19\x19\x04\x0e\x88\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x1a\xa4\x02p\xd2\x1e\\\u0786\xb61m\x1a\xc3\xc53IKy\xed\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1a\xb5:\x11\xbc\xc6=\u07ea@\xa0+\x9e\x18d\x96\u037b\x8a\xff\x89l?*\xac\x80\f\x00\x00\x00\u07d4\x1a\xbcN%;\b\n\xebCy\x84\xab\x05\xbc\xa0\x97\x9a\xa4>\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a\xc0\x89\u00fcM\x82\xf0j \x05\x1a\x9ds-\xc0\xe74\xcba\x89%\xf6\x9dc\xa6\xce\x0e\x00\x00\xe0\x94\x1a\xd4V>\xa5xk\xe1\x15\x995\xab\xb0\xf1\u0547\x9c>sr\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1a\xd7- \xa7n\u007f\xcckv@X\xf4\x8dA}Io\xa6\u0349lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1a\xda\xf4\xab\xfa\x86}\xb1\u007f\x99\xafj\xbe\xbfpz<\xf5]\xf6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1a\xf6\x03C6\x0e\v-u%R\x107W \xdf!\xdb\\}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a\xfc\u0145\x89l\xd0\xed\xe1)\xee-\xe5\xc1\x9e\xa8\x11T\vd\x89\xaf*\xba\f\x8e[\xef\x80\x00\u07d4\x1b\x05\xeajj\u022f|\xb6\xa8\xb9\x11\xa8\xcc\xe8\xfe\x1a*\xcf\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\v1\xaf\xffKm\xf3e:\x94\xd7\xc8yx\xae5\xf3J\xae\x89\x139\x10E?\xa9\x84\x00\x00\u07d4\x1b\r\ah\x17\xe8\u058e\xe2\xdfN\x1d\xa1\xc1\x14-\x19\x8cD5\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\x1b\x13\ro\xa5\x1d\\H\xec\x8d\x1dR\u070a\"{\xe8s\\\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b#\u02c6cUHq\xfb\xbe\r\x9e`9~\xfbo\xae\xdc>\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1b&9X\x8bU\xc3D\xb0#\xe8\xde_\xd4\b{\x1f\x04\x03a\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x1b9 \xd0\x01\xc4>r\xb2N|\xa4o\x0f\xd6\xe0\xc2\n_\xf2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1b<\xb8\x1eQ\x01\x1bT\x9dx\xbfr\v\r\x92J\xc7c\xa7\u008av\x95\xa9, \xd6\xfe\x00\x00\x00\u07d4\x1bC#,\xcdH\x80\xd6\xf4o\xa7Q\xa9l\xd8$s1XA\x89\x04V9\x18$O@\x00\x00\u07d4\x1bK\xbc\xb1\x81e!\x1b&[(\a\x16\xcb?\x1f!!v\xe8\x89\x19\x9a\xd3}\x03\xd0`\x80\x00\u07d4\x1bM\a\xac\u04c1\x83\xa6\x1b\xb2x=+{\x17\x8d\xd5\x02\xac\x8d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1bckzIo\x04MsYYn5:\x10F\x16Cok\x89\x13\x88\xea\x95\xc3?\x1d\x00\x00\u07d4\x1bd\x95\x89\x12@\xe6NYD\x93\xc2f!q\xdb^0\xce\x13\x89\tX\x87\u0595\xedX\x00\x00\u07d4\x1bf\x10\xfbh\xba\xd6\xed\x1c\xfa\xa0\xbb\xe3:$\xeb.\x96\xfa\xfb\x89\b=lz\xabc`\x00\x00\u07d4\x1by\x903\xefm\xc7\x12x\"\xf7EB\xbb\"\xdb\xfc\t\xa3\b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x1b~\xd9t\xb6\xe24\u0381$t\x98B\x9a[\u0520\xa2\xd19\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\x82o\xb3\xc0\x12\xb0\xd1Y\u253a[\x8aI\x9f\xf3\xc0\xe0<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\x8a\xa0\x16\f\u05df\x00_\x88Q\nqI\x13\xd7\n\u04fe3\x89\n\xef\xfb\x83\a\x9a\xd0\x00\x00\xe0\x94\x1b\x8b\xd6\xd2\xec\xa2\x01\x85\xa7\x8e}\x98\xe8\xe1\x85g\x8d\xacH0\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\x1b\x9b-\u0096\x0eL\xb9@\x8ft\x05\x82|\x9bY\a\x16\x12\xfd\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1b\xa9\"\x8d8\x87'\xf3\x89\x15\x0e\xa0;s\xc8-\xe8\xeb.\t\x8a\x01\x89t\xfb\xe1w\xc9(\x00\x00\u07d4\x1b\xa9\xf7\x99~S\x87\xb6\xb2\xaa\x015\xac$R\xfe6\xb4\xc2\r\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\x1b\xba\x03\xffkJ\u057f\x18\x18J\xcb!\xb1\x88\xa3\x99\xe9\xebJ\x89a\t=|,m8\x00\x00\u07d4\x1b\xbc\x19\x9eXg\x90\xbe\x87\xaf\xed\xc8I\xc0G&t\\]{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x1b\xbc`\xbc\xc8\x0e\\\xdc5\xc5Aj\x1f\n@\xa8=\xae\x86{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xc4L\x87a#\x1b\xa1\xf1\x1f_\xaa@\xfaf\x9a\x01>\x12\u0389\v\tR\xc4Z\xea\xad\x00\x00\u07d4\x1b\xcf4A\xa8f\xbd\xbe\x960\t\xce3\xc8\x1c\xbb\x02a\xb0,\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\x1b\u048c\xd5\u01ca\xeeQ5|\x95\xc1\xef\x925\xe7\xc1\x8b\xc8T\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xd8\xeb\xaavt\xbb\x18\u1458\xdb$OW\x03\x13\a_C\x89\b!\xab\rD\x14\x98\x00\x00\u07d4\x1b\xd9\t\xac\rJ\x11\x02\xec\x98\xdc\xf2\u0329j\n\xdc\u05e9Q\x89\x01\x16Q\xac>zu\x80\x00\u07d4\x1b\xe3T,6\x13hte\xf1Zp\xae\xeb\x81f+e\u0328\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xeaM\xf5\x12/\xaf\u07b3`~\xdd\xda\x1e\xa4\xff\u06da\xbf*\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d4\x1b\xecM\x02\u0385\xfcH\xfe\xb6$\x89\x84\x1d\x85\xb1pXj\x9b\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\x1b\xf9t\u0650OE\u0381\xa8E\xe1\x1e\xf4\xcb\xcf'\xafq\x9e\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x1c\x04VI\xcdS\xdc#T\x1f\x8e\xd4\xd3A\x81(\b\xd5\u075c\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x1c\x12\x8b\xd6\u0365\xfc\xa2uu\xe4\xb4;2S\xc8\xc4\x17*\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\x13\u04c67\xb9\xa4|\xe7\x9d7\xa8oP\xfb@\x9c\x06\a(\x89Hz\x9a0E9D\x00\x00\u07d4\x1c \x10\xbdf-\xf4\x17\xf2\xa2q\x87\x9a\xfb\x13\xefL\x88\xa3\xae\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x1c%z\u0525Q\x05\xea;X\xed7K\x19\x8d\xa2f\xc8_c\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x1c.6\a\xe1'\xca\xca\x0f\xbd\\YH\xad\xad}\xd80\xb2\x85\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x1c5l\xfd\xb9_\xeb\xb7\x14c;(\xd5\xc12\u0744\xa9\xb46\x89\x01Z\xf1\u05cbX\xc4\x00\x00\u07d4\x1c5\xaa\xb6\x88\xa0\u034e\xf8.vT\x1b\xa7\xac9R\u007ft;\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x1c>\xf0]\xae\x9d\xcb\u0509\xf3\x02D\bf\x9d\xe2D\xc5*\x02\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x1cJ\xf0\xe8c\xd2el\x865\xbco\xfe\xc8\u0759(\x90\x8c\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c`\x19\x93x\x92\a\xf9e\xbb\x86\\\xbbL\xd6W\xcc\xe7o\xc0\x89\x05T\x1ap7P?\x00\x00\u07d4\x1cc\xfa\x9e,\xbb\xf21a\xda3\xa1\xda}\xf7\r\x1b\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1c\xb6\xb2\xd7\xcf\xc5Y\xb7\xf4\x1eoV\xab\x95\xc7\xc9X\xcd\x0eL\x89Hz\x9a0E9D\x00\x00\u07d4\x1c\xc1\xd3\xc1O\x0f\xb8d\x0e6rM\xc42)\xd2\xeaz\x1eH\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x1c\xc9\bv\x00A\t\xcdy\xa3\u07a8f\u02c4\n\xc3d\xba\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xd1\xf0\xa3\x14\u02f2\x00\xde\n\f\xb1\xef\x97\xe9 p\x9d\x97\u0089lk\x93[\x8b\xbd@\x00\x00\u0794\x1c\xdaA\x1b\xd5\x16;\xae\xca\x1eU\x85c`\x1c\xe7 \xe2N\xe1\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1c\xe8\x1d1\xa7\x920\"\xe1%\xbfH\xa3\xe06\x93\xb9\x8d\xc9\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xeb\xf0\x98]\u007fh\n\xaa\x91\\D\xccb\xed\xb4\x9e\xab&\x9e\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1c\xedg\x15\xf8b\xb1\xff\x86\x05\x82\x01\xfc\xceP\x82\xb3nb\xb2\x8a\x01j^`\xbe\xe2s\xb1\x00\x00\u07d4\x1c\xf0L\xb1C\x80\x05\x9e\xfd?#\x8be\u057e\xb8j\xfa\x14\u0609\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1c\xf1\x05\xab#\x02;ULX>\x86\u05d2\x11y\xee\x83\x16\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1c\xf2\xebz\x8c\xca\u00ad\xea\xef\x0e\xe8sG\xd55\u04f9@X\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xfc\xf7Q\u007f\f\bE\x97 \x94+dz\u0452\xaa\x9c\x88(\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\x1d\t\xad$\x12i\x1c\u0141\xc1\xab6\xb6\xf9CL\xd4\xf0\x8bT\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x1d\x15|Xv\xc5\xca\xd5S\xc9\x12\xca\xf6\xce-Rw\xe0\\s\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1d&\x15\xf8\xb6\xcaP\x12\xb6c\xbd\u0414\xb0\xc5\x13|w\x8d\u07ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1d)\u01ea\xb4+ H\u04b2R%\u0518\u06e6z\x03\xfb\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0794\x1d4\x1f\xa5\xa3\xa1\xbd\x05\x1f}\xb8\a\xb6\xdb/\u01faO\x9bE\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1d4N\x96%g\xcb'\xe4M\xb9\xf2\xfa\u01f6\x8d\xf1\xc1\xe6\xf7\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x1d6h0c\xb7\xe9\xeb\x99F-\xab\xd5i\xbd\xdc\xe7\x16\x86\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1d7aky?\x94\x91\x188\xac\x8e\x19\xee\x94I\u07d2\x1e\u0109QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94\x1d9[0\xad\xda\x1c\xf2\x1f\t\x1aOJ{u3q\x18\x94A\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x1dEXn\xb8\x03\xca!\x90e\v\xf7H\xa2\xb1t1+\xb5\a\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1dW.\xdd-\x87\xca'\x1ag\x14\xc1Z;7v\x1d\u0320\x05\x89\x06\xeb\xd5*\x8d\xdd9\x00\x00\u07d4\x1dc0\x97\xa8R%\xa1\xffC!\xb1)\x88\xfd\xd5\\+8D\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x1di\xc8=(\xff\x04t\xce\xeb\xea\xcb:\xd2'\xa1D\xec\u78ca\x01(\xcc\x03\x92\nb\u0480\x00\u07d4\x1d\x96\xbc\u0544W\xbb\xf1\xd3\u00a4o\xfa\xf1m\xbf}\x83hY\x89\tIr\t\xd8F~\x80\x00\u07d4\x1d\x9ej\xaf\x80\x19\xa0_#\x0e]\xef\x05\xaf]\x88\x9b\xd4\xd0\xf2\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x1d\xab\x17.\xff\xa6\xfb\xeeSL\x94\xb1~yN\xda\xc5OU\xf8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1d\xb9\xac\x9a\x9e\xae\xec\nR7W\x05\fq\xf4rx\xc7-P\x89Hz\x9a0E9D\x00\x00\u07d4\x1d\xbe\x8e\x1c+\x8a\x00\x9f\x85\xf1\xad<\xe8\r.\x055\x0e\u3709\aW\rn\x9e\xbb\xe4\x00\x00\u07d4\x1d\xc7\xf7\xda\xd8]\xf5?\x12q\x15$\x03\xf4\xe1\xe4\xfd\xb3\xaf\xa0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1d\u03bc\xb7em\xf5\u072a3h\xa0U\xd2/\x9e\xd6\xcd\xd9@\x89\x1b\x18\x1eK\xf24<\x00\x00\xe0\x94\x1d\xd7tA\x84J\xfe\x9c\xc1\x8f\x15\xd8\xc7{\xcc\xfbe^\xe04\x8a\x01\x06\xebEW\x99D\x88\x00\x00\u07d4\x1d\xde\xfe\xfd5\xab\x8fe\x8b$q\xe5G\x90\xbc\x17\xaf\x98\u07a4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1d\xee\xc0\x1a\xbe\\\r\x95-\xe9\x10l=\xc3\x069\xd8P\x05\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\x1d\xf6\x91\x16rg\x9b\xb0\xef5\t\x03\x8c\f'\xe3\x94\xfd\xfe0\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\x1d\xfa\xee\ar\x12\xf1\xbe\xaf\x0eo/\x18@Sz\xe1T\xad\x86\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1e\x06\r\xc6\xc5\xf1\u02cc\xc7\xe1E.\x02\xee\x16u\b\xb5eB\x8a\x02\xb1O\x02\xc8d\xc7~\x00\x00\xe0\x94\x1e\x13\xecQ\x14,\ubde2`\x83A,<\xe3QD\xbaV\xa1\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x1e\x1aH(\x11\x9b\xe3\t\xbd\x88#nMH+PM\xc5W\x11\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\x1e\x1a\ud178leb\u02cf\xa1\xebo\x8f;\xc9\u072eny\x89\xf4\xd2\u0744%\x9b$\x00\x00\u07d4\x1e\x1ccQwj\xc3\x10\x919~\xcf\x16\x00-\x97\x9a\x1b-Q\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1e\x1dz_$h\xb9N\xa8&\x98-\xbf!%yR*\xb7\xdf\n\u02ac\x9e\xee\xd3Y09\xe5\xacuy\x8a+\x14F\xddj\xef\xe4\x1c\x00\x00\u07d4\x1e{^M\x1fW+\xec\xf2\xc0\x0f\xc9\f\xb4v{Jn3\u0509\x06\x1f\xc6\x10u\x93\xe1\x00\x00\u07d4\x1e\x8eh\x9b\x02\x91|\xdc)$]\f\x9ch\xb0\x94\xb4\x1a\x9e\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xa34\xb5u\b\a\xeat\xaa\u016b\x86\x94\xec_(\xaaw\u03c9\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\x1e\xa4qU\x04\u01af\x10{\x01\x94\xf4\xf7\xb1\xcbo\xcc\xcdoK\x89 \x041\x97\xe0\xb0'\x00\x00\u07d4\x1e\xa4\x92\xbc\xe1\xad\x10~3\u007fK\u0527\xac\x9a{\xab\xcc\u036b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x1e\xa6\xbf/\x15\xae\x9c\x1d\xbcd\u06a7\xf8\xeaM\r\x81\xaa\xd3\xeb\x89\u3bb5sr@\xa0\x00\x00\u07d4\x1e\xb4\xbfs\x15j\x82\xa0\xa6\x82 \x80\xc6\xed\xf4\x9cF\x9a\xf8\xb9\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\x1e\xba\xcbxD\xfd\xc3\"\xf8\x05\x90O\xbf\x19b\x80-\xb1S|\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1e\xc4\xecKw\xbf\x19\u0411\xa8h\xe6\xf4\x91T\x18\x05A\xf9\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xd0n\xe5\x16b\xa8lcE\x88\xfbb\xdcC\xc8\xf2~|\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1e\u063b?\x06w\x8b\x03\x9e\x99a\xd8\x1c\xb7\x1as\xe6x|\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xda\bNye\x00\xba\x14\xc5\x12\x1c\r\x90\x84of\xe4\xbeb\x89\x1c\xfd\xd7F\x82\x16\xe8\x00\x00\u07d4\x1e\xeel\xbe\xe4\xfe\x96\xadaZ\x9c\xf5\x85zdy@\u07ccx\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4\x1e\xf2\u073f\xe0\xa5\x00A\x1d\x95n\xb8\u0213\x9c=l\xfef\x9d\x89*\x11)\u0413g \x00\x00\xe0\x94\x1e\xf5\xc9\xc76P\u03fb\xde\\\x88U1\xd4'\xc7\xc3\xfeUD\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1f\x04\x12\xbf\xed\u0356N\x83}\t,q\xa5\xfc\xba\xf3\x01&\xe2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\x17O@\xa0Dr4\xe6fS\x91Mu\xbc\x00>V\x90\u0709\b\xacr0H\x9e\x80\x00\x00\u07d4\x1f!\x86\xde\xd2>\f\xf9R\x16\x94\xe4\xe1dY>i\n\x96\x85\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x1f*\xfc\n\xed\x11\xbf\xc7\x1ew\xa9\ae{6\xeav\xe3\xfb\x99\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\x1f9Y\xfc)\x11\x10\xe8\x822\xc3kvg\xfcx\xa3ya?\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1f=\xa6\x8f\xe8~\xafC\xa8)\xabm~\u0166\xe0\t\xb2\x04\xfb\x89\x1e\x16\x01u\x8c,~\x00\x00\u07d4\x1fI\xb8m\r9EY\x06\x98\xa6\xaa\xf1g<7u\\\xa8\r\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\x1f_;4\xbd\x13K'\x81\xaf\xe5\xa0BJ\u0144l\xde\xfd\x11\x89\x05]\xe6\xa7y\xbb\xac\x00\x00\u07d4\x1fo\x0004\x97R\x06\x1c\x96\a+\xc3\xd6\xeb5I \x8dk\x89\x01K\x8d\xe1\xeb\x88\u06c0\x00\u07d4\x1f}\x8e\x86\xd6\xee\xb0%E\xaa\xd9\x0e\x912{\xd3i\xd7\xd2\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\x81\x16\xbd\n\xf5W\x0e\xaf\fV\u011cz\xb5\xe3zX\x04X\x89lk\x93[\x8b\xbd@\x00\x00\u0794\x1f\x88\xf8\xa13\x8f\xc7\xc1\tv\xab\xcd?\xb8\u04c5T\xb5\uc708\xb9\xf6]\x00\xf6<\x00\x00\u07d4\x1f\x9c2hE\x8d\xa3\x01\xa2\xbeZ\xb0\x82W\xf7{\xb5\xa9\x8a\xa4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1f\xa21\x9f\xed\x8c-F*\xdf.\x17\xfe\xecjo0Qn\x95\x89\x06\xca\xe3\x06!\xd4r\x00\x00\u07d4\x1f\xb4c\xa08\x99\x83\xdf}Y?{\xddmxI\u007f\xed\x88y\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\xb7\xbd1\r\x95\xf2\xa6\u067a\xaf\x8a\x8aC\n\x9a\x04E:\x8b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x1f\xcc|\xe6\xa8HX\x95\xa3\x19\x9e\x16H\x1fr\xe1\xf7b\xde\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1f\xcf\xd1\xd5\u007f\x87\"\x90V\f\xb6-`\x0e\x1d\xef\xbe\xfc\xcc\x1c\x89P\xc5\xe7a\xa4D\b\x00\x00\u0794\x1f\u0496\xbe\x03\xads|\x92\xf9\u0186\x9e\x8d\x80\xa7\x1cW\x14\xaa\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x1f\xdd\xd8_\u024b\xe9\xc4\x04Ya\xf4\x0f\x93\x80^\xccEI\xe5\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4 \x01\xbe\xf7{f\xf5\x1e\x15\x99\xb0/\xb1\x10\x19J\x00\x99\xb7\x8d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4 \x02d\xa0\x9f\x8ch\xe3\xe6b\x97\x95(\x0fV%O\x86@\u0409\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \x03qy\a\xa7%`\xf40\u007f\x1b\xee\xccT6\xf4=!\xe7\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4 \r\xfc\vq\xe3Y\xb2\xb4eD\n6\xa6\xcd\xc3Rw0\a\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4 \x13L\xbf\xf8\x8b\xfa\xdcFkR\xec\ua9d8W\x89\x1d\x83\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4 \x14&\x1f\x01\b\x9fSyV0\xba\x9d\xd2O\x9a4\xc2\xd9B\x89Hz\x9a0E9D\x00\x00\u07d4 \x16\x89]\xf3,\x8e\xd5G\x82iF\x84#\xae\xa7\xb7\xfb\xceP\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \x18\x1cKA\xf6\xf9r\xb6iX!_\x19\xf5p\xc1]\xdf\xf1\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4 \x18d\xa8\xf7\x84\xc2'{\v|\x9e\xe74\xf7\xb3w\xea\xb6H\x89\xf2(\x14\x00\xd1\xd5\xec\x00\x00\u07d4 \xb8\x1a\xe59&\xac\xe9\xf7\xd7AZ\x05\f\x03\x1dX_ \x89\x12\u007f\x19\xe8>\xb3H\x00\x00\xe0\x94 \x1d\x9e\xc1\xbc\v\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4 \xa1RV\xd5\f\xe0X\xbf\x0e\xacC\xaaS:\xa1n\u0273\x80\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \xa2\x9cPy\xe2k?\x181\x8b\xb2\xe5\x0e\x8e\x8b4n[\xe8\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4 \xa8\x16\x80\xe4e\xf8\x87\x90\xf0\aO`\xb4\xf3_]\x1ej\xa5\x89Ea\x80'\x8f\fw\x80\x00\u07d4 \xb9\xa9\u6f48\x80\u0659J\xe0\r\u0439(*\v\xea\xb8\x16\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4 \u0084\xba\x10\xa2\b0\xfc=i\x9e\xc9}-\xfa'\xe1\xb9^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4 \xd1A\u007f\x99\xc5i\u3fb0\x95\x85e0\xfe\x12\xd0\xfc\uaa89@\x15\xf9K\x11\x83i\x80\x00\u07d4 \u074f\u02f4n\xa4o\u3066\x8b\x8c\xa0\xea[\xe2\x1f\u9949lk\x93[\x8b\xbd@\x00\x00\xe0\x94 \xff>\u078c\xad\xb5\xc3{H\xcb\x14X\x0f\xb6^#\t\n{\x8a\b\xe4\xd3\x16\x82v\x86@\x00\x00\xe0\x94!\x008\x1d`\xa5\xb5J\xdc\t\u0456\x83\xa8\xf6\u057bK\xfb\u02ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94!\x18\xc1\x16\xab\f\xdfo\xd1\x1dT\xa40\x93\a\xb4w\xc3\xfc\x0f\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94!\x1b)\xce\xfcy\xae\x97gD\xfd\xeb\u03bd<\xbb2\xc5\x13\x03\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4! l\xe2.\xa4\x80\xe8Y@\xd3\x13\x14\xe0\xd6ONM:\x04\x8965\u026d\xc5\u07a0\x00\x00\u07d4!2\xc0Qj.\x17\x17J\xc5G\xc4;{\x00 \xd1\xebLY\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94!@\x8bMz,\x0en\xcaAC\xf2\xca\u037b\u033a\x12\x1b\u060a\x04<3\xc1\x93ud\x80\x00\x00\u07d4!Kt9U\xa5\x12\xden\r\x88j\x8c\xbd\x02\x82\xbe\xe6\u04a2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!L\x89\u017d\x8e}\"\xbcWK\xb3^H\x95\x02\x11\xc6\xf7v\x89\x01\x06T\xf2X\xfd5\x80\x00\xe0\x94!Ti\x14\xdf\u04ef*\xddA\xb0\xff>\x83\xff\xdat\x14\xe1\xe0\x8a\x01C\x95\xe78ZP.\x00\x00\u07d4!X.\x99\xe5\x02\xcb\xf3\xd3\xc2;\xdf\xfbv\xe9\x01\xacmV\xb2\x89\x05k\xc7^-c\x10\x00\x00\u07d4!Y$\b\x13\xa70\x95\xa7\xeb\xf7\u00f3t>\x80(\xae_\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!`\xb4\xc0,\xac\n\x81\u0791\b\xdeCE\x90\xa8\xbf\xe6\x875\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94!nA\x86N\xf9\x8f\x06\r\xa0\x8e\xca\xe1\x9a\xd1\x16j\x17\xd06\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4!\x84o/\xdfZA\xed\x8d\xf3n^\xd8TM\xf7Y\x88\xec\xe3\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94!\xa6\xdbe'F{\xc6\xda\xd5K\xc1n\x9f\xe2\x95;g\x94\xed\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4!\xa6\xfe\xb6\xab\x11\xc7f\xfd\xd9w\xf8\xdfA!\x15_G\xa1\xc0\x89\x03\x19\xcf8\xf1\x00X\x00\x00\u07d4!\xb1\x82\xf2\xda+8D\x93\xcf_5\xf8=\x9d\x1e\xe1O*!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!\xbf\xe1\xb4\\\xac\xdebt\xfd\x86\b\u0661x\xbf>\xebn\u0709l\xee\x06\u077e\x15\xec\x00\x00\u07d4!\xc0s\x80HOl\xbc\x87$\xad2\xbc\x86L;Z\xd5\x00\xb7\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94!\u00e8\xbb\xa2g\xc8\u0322{\x1a\x9a\xfa\xba\xd8o`z\xf7\b\x8a\x01\xe4\xa3lI\u06580\x00\x00\u07d4!\xcem[\x90\x18\xce\xc0J\u0596yD\xbe\xa3\x9e\x800\xb6\xb8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4!\xd0'\x05\xf3\xf6I\x05\xd8\x0e\xd9\x14y\x13\xea\x8cs\a\u0595\x89I\xed\xb1\xc0\x98\x876\x00\x00\u07d4!\xd1?\f@$\xe9g\xd9G\a\x91\xb5\x0f\"\xde:\xfe\xcf\x1b\x89\xf1Z\xd3^.1\xe5\x00\x00\xe0\x94!\xdb\u06c1z\r\x84\x04\u01bd\xd6\x15\x047N\x9cC\xc9!\x0e\x8a\x02\x1e\x18\xb9\xe9\xabE\xe4\x80\x00\xe0\x94!\xdf\x1e\xc2KNK\xfey\xb0\xc0\x95\u03ba\xe1\x98\xf2\x91\xfb\u044a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94!\xdf-\u036ft\xb2\xbf\x804\x04\xddM\xe6\xa3^\xab\xec\x1b\xbd\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4!\xe2\x19\u021c\xa8\xac\x14\xaeL\xbaa0\xee\xb7}\x9em9b\x89*\u035f\xaa\xa08\xee\x00\x00\u07d4!\xe5\u04ba\xe9\x95\xcc\xfd\b\xa5\xc1k\xb5$\xe1\xf60D\x8f\x82\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4!\xe5\xd7s 0L \x1c\x1eS\xb2a\xa1#\u0421\x06>\x81\x89\x04\xb6\xfa\x9d3\xddF\x00\x00\xe0\x94!\xea\xe6\xfe\xff\xa9\xfb\xf4\u0347OG9\xac\xe50\u033eY7\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4!\xec\xb2\u07e6Wy\xc7Y-\x04\x1c\xd2\x10Z\x81\xf4\xfdNF\x8965\u026d\xc5\u07a0\x00\x00\u07d4!\uff20\x9b5\x80\xb9\x8es\xf5\xb2\xf7\xf4\xdc\v\xf0,R\x9c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!\xfd\v\xad\xe5\xf4\xeftt\xd0X\xb7\xf3\xd8T\xcb\x13\x00RN\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94!\xfdG\xc5%`\x12\x19\x8f\xa5\xab\xf11\xc0mj\xa1\x96_u\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4!\xfdl]\x97\xf9\xc6\x00\xb7h!\xdd\xd4\xe7v5\x0f\xce+\xe0\x89lj\u04c2\xd4\xfba\x00\x00\u07d4\"\r\u018d\xf0\x19\xb6\xb0\u033f\xfbxKZZ\xb4\xb1]@`\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\"\x0e+\x92\xc0\xf6\xc9\x02\xb5\x13\xd9\xf1\xe6\xfa\xb6\xa8\xb0\xde\xf3\u05c9+^:\xf1k\x18\x80\x00\x00\u07d4\"V\x1cY1\x14560\x9c\x17\xe82X{b\\9\v\x9a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\"W\xfc\xa1jn\\*d|<)\xf3l\xe2)\xab\x93\xb1~\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\"]5\xfa\xed\xb3\x91\u01fc-\xb7\xfa\x90q\x16\x04\x05\x99m\x00\x89\t\x18T\xfc\x18bc\x00\x00\u07d4\"_\x9e\xb3\xfbo\xf3\xe9\xe3\xc8D~\x14\xa6n\x8dO7y\xf6\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\"r\x18n\xf2}\xcb\xe2\xf5\xfc70P\xfd\xae\u007f*\xce#\x16\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4\"s\xba\u05fcNHv\"\xd1u\xefzf\x98\x8bj\x93\xc4\xee\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\"v&K\xec\x85&\xc0\xc0\xf2pgz\xba\xf4\xf0\xe4A\xe1g\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\"\x82B\xf83n\xec\xd8$.\x1f\x00\x0fA\x93~q\xdf\xfb\xbf\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\"\x84*\xb80\xdaP\x99\x13\xf8\x1d\xd1\xf0O\x10\xaf\x9e\xdd\x1cU\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\"\x94O\xbc\xa9\xb5yc\bN\xb8M\xf7\xc8_\xb9\xbc\u07f8V\x89\xfc\x11\x8f\uf43a8\x80\x00\u07d4\"\x9c\xc4q\x1bbu^\xa2\x96DZ\u00f7\u007f\xc63\x82\x1c\xf2\x89\x02#\xe8\xb0R\x192\x80\x00\u0794\"\x9eC\r\xe2\xb7OD&Q\xdd\u0377\x01v\xbc\x05L\xadT\x88\xbb\xf9\x81\xbcJ\xaa\x80\x00\u07d4\"\x9fO\x1a*OT\atP[G\a\xa8\x1d\xe4D\x10%[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\"\x9f\xf8\v\xf5p\x80\t\xa9\xf79\xe0\xf8\xb5`\x91@\x16\u0566\x89\x12\x11\xec\xb5m\x13H\x80\x00\u07d4\"\xa2X\x12\xabV\xdc\xc4#\x17^\xd1\u062d\xac\xce3\xcd\x18\x10\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94\"\xb9j\xb2\xca\xd5]\xb1\x00\xb50\x01\xf9\xe4\xdb7\x81\x04\xc8\a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\"\xbd\xff\xc2@\xa8\x8f\xf7C\x1a\xf3\xbf\xf5\x0e\x14\xda7\xd5\x18>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\"\xce4\x91Y\xee\xb1D\xef\x06\xff&6X\x8a\xefy\xf6(2\x89\n1\x06+\xee\xedp\x00\x00\u07d4\"\xdbU\x9f,<\x14u\xa2\xe6\xff\xe8:YyY\x91\x96\xa7\xfa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\"\xe1QX\xb5\xee>\x86\xeb\x032\xe3\u6a6cl\u0675^\u0349\b\xacr0H\x9e\x80\x00\x00\u07d4\"\xe2H\x8e-\xa2jI\xae\x84\xc0\x1b\xd5K!\xf2\x94x\x91\u0189]\u0212\xaa\x111\xc8\x00\x00\u07d4\"\xe5\x12\x14\x9a\x18\xd3i\xb7\x86\xc9\xed\xab\xaf\x1d\x89N\xe0.g\x14a\\\x00\x00\u07d4\"\xeb}\xb0\xbaV\xb0\xf8\xb8\x16\u0332\x06\xe6\x15\xd9)\x18[\r\x89\x04])s~\"\xf2\x00\x00\u07d4\"\xee\xd3'\xf8\xeb\x1d\x138\xa3\xcb{\x0f\x8aK\xaaY\a\u0355\x89\x01E]_Hw\b\x80\x00\xe0\x94\"\xf0\x04\u07cd\xe9\xe6\xeb\xf5#\u032c\xe4W\xac\xcb&\xf9r\x81\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794\"\xf2\xdc\xffZ\u05cc>\xb6\x85\v\\\xb9Q\x12{e\x95\"\u623e -j\x0e\xda\x00\x00\u07d4\"\xf3\xc7y\xddy\x02>\xa9*x\xb6\\\x1a\x17\x80\xf6-\\J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\"\xfe\x88M\x907)\x1bMR\xe6(Z\xe6\x8d\xea\v\xe9\xff\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\x06\u07d3\x1a\x94\rX\xc0\x16e\xfaM\b\x00\x80,\x02\xed\xfe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94#\t\xd3@\x91D[22Y\v\xd7\x0fO\x10\x02[,\x95\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4#\x12\x00F\xf6\x83!\x02\xa7R\xa7fVi\x1c\x86>\x17\u5709\x11\xe0\xe4\xf8\xa5\v\xd4\x00\x00\u07d4#\x1a\x15\xac\xc1\x99\u021f\xa9\xcb\"D\x1c\xc7\x030\xbd\xcc\xe6\x17\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4#\x1d\x94\x15]\xbc\xfe*\x93\xa3\x19\xb6\x17\x1fc\xb2\v\u04b6\xfa\x89\xcf\x14{\xb9\x06\xe2\xf8\x00\x00\u07d4#(2\xcdYw\xe0\nL0\xd0\x16?.$\xf0\x88\xa6\xcb\t\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4#,m\x03\xb5\xb6\xe6q\x1e\xff\xf1\x90\xe4\x9c(\xee\xf3l\x82\xb0\x89Hz\x9a0E9D\x00\x00\xe0\x94#,\xb1\xcdI\x99<\x14J?\x88\xb3a\x1e#5i\xa8k\u058a\x03L`lB\u042c`\x00\x00\u07d4#,\xe7\x82Pb%\xfd\x98`\xa2\xed\xc1Jz0Gsm\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4#/R]U\x85\x9b}N`\x8d H\u007f\xaa\xdb\x00)15\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94#4\u0150\u01e4\x87i\x100E\u0176SL\x8a4i\xf4J\x8a\x03\xb1\x99\a=\xf7-\xc0\x00\x00\u07d4#7n\u02bftl\xe53!\xcfB\xc8fI\xb9+g\xb2\xff\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#7\x8fB\x92m\x01\x84\xb7\x93\xb0\xc8'\xa6\xdd>=3O\u0349\x03\t'\xf7L\x9d\xe0\x00\x00\u07d4#8B\xb1\xd0i/\xd1\x11@\xcfZ\u0364\xbf\x960\xba\xe5\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#9\xe9I(p\xaf\xea%7\xf3\x89\xac/\x83\x83\x02\xa3<\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#;\xdd\xdd]\xa9HR\xf4\xad\xe8\xd2\x12\x88V\x82\xd9\ak\u0189\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#OF\xba\xb7?\xe4]1\xbf\x87\xf0\xa1\xe0Fa\x99\xf2\ubb09\x1aJ\xba\"\\ t\x00\x00\u07d4#U\x1fV\x97_\xe9+1\xfaF\x9cI\xeaf\xeefb\xf4\x1e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4#V\x95B\xc9}V`\x18\xc9\a\xac\xfc\xf3\x91\xd1@g\xe8~\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94#_\xa6l\x02^\xf5T\x00p\xeb\xcf\r7-\x81w\xc4g\xab\x8a\a\x12\x9e\x1c\xdf7>\xe0\x00\x00\xe0\x94#r\xc4\xc1\u0253\x9fz\xafl\xfa\xc0@\x90\xf0\x04t\x84\n\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4#s\f5z\x91\x02nD\xb1\xd0\xe2\xfc*Q\xd0q\xd8\xd7{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#v\xad\xa9\x033\xb1\u0441\bL\x97\xe6E\xe8\x10\xaa[v\xf1\x89(\xa8WBTf\xf8\x00\x00\u07d4#x\xfdC\x82Q\x1e\x96\x8e\u0452\x10g7\xd3$\xf4T\xb55\x8965\u026d\xc5\u07a0\x00\x00\u07d4#\x82\xa9\u050e\xc8>\xa3e(\x90\xfd\x0e\u7710{[-\xc1\x89\a?u\u0460\x85\xba\x00\x00\u07d4#\x83\xc2\"\xe6~\x96\x91\x90\xd3!\x9e\xf1M\xa3xP\xe2lU\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\x8akv5%/RDHl\n\xf0\xa7: s\x85\xe09\x89JD\x91\xbdm\xcd(\x00\x00\u07d4#\x9as>k\x85Z\u0152\xd6c\x15a\x86\xa8\xa1t\xd2D\x9e\x89X\xbe7X\xb2A\xf6\x00\x00\xe0\x94#\xab\t\xe7?\x87\xaa\x0f;\xe0\x13\x9d\xf0\xc8\xebk\xe5cO\x95\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94#\xab\xd9\xe9>yW\xe5\xb66\xbeey\x05\x1c\x15\xe5\xce\v\x0e\x8a\x03\xa3\xc8\xf7\xcb\xf4,8\x00\x00\u07d4#\xb1\u0111\u007f\xbd\x93\xee=H8\x93\x06\x95s\x84\xa5Il\xbf\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94#\xba8d\xdaX=\xabV\xf4 \x87<7g\x96\x90\xe0/\x00\x8a\x02\x13BR\r_\xec \x00\x00\u07d4#\xc5Z\xebW9\x87o\n\xc8\xd7\xeb\xea\x13\xber\x96\x85\xf0\x00\x89Hz\x9a0E9D\x00\x00\u07d4#\u025b\xa0\x87D\x8e\x19\xc9p\x1d\xf6n\f\xabR6\x831\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xcc\xc3\u01ac\xd8\\.F\fO\xfd\xd8+\xc7]\xc8I\xea\x14\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#\xcd%\x98\xa2\x0e\x14\x9e\xad*\u0593yWn\xce\xdb`\u3389lk\x93[\x8b\xbd@\x00\x00\u07d4#\u07cfH\xee\x00\x92V\xeay~\x1f\xa3i\xbe\xeb\xcfk\xc6c\x89|\xd3\xfa\xc2m\x19\x81\x80\x00\u07d4#\xe2\u01a8\xbe\x8e\n\u03e5\xc4\xdf^6\x05\x8b\xb7\u02ecZ\x81\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xeaf\x9e5d\x81\x9a\x83\xb0\xc2l\x00\xa1m\x9e\x82olF\x89M\x8dl\xa9h\xca\x13\x00\x00\u07d4#\xebo\xd8Vq\xa9\x06:\xb7g\x8e\xbe&Z \xf6\x1a\x02\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xf9\xec\xf3\xe5\xdd\u0723\x88\x15\xd3\xe5\x9e\xd3K[\x90\xb4\xa3S\x89\v\x17\x81\xa3\xf0\xbb \x00\x00\u07d4#\xfa~\xb5\x1aH\"\x95\x98\xf9~v+\xe0\x86\x96R\xdf\xfcf\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94$\x03\x05rs\x13\xd0\x1esT,w_\xf5\x9d\x11\xcd5\xf8\x19\x8a\x01A\x88Vf\x80\u007f\\\x80\x00\u07d4$\x04k\x91\u069ba\xb6)\u02cb\x8e\xc0\xc3Q\xa0~\a\x03\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4$\x0eU\x9e'J\xae\xf0\xc2X\x99\x8c\x97\x9fg\x1d\x11s\xb8\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94$\x13aU\x9f\xee\xf8\x0e\xf170!S\xbd\x9e\xd2\xf2]\xb3\xef\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94$;;\xcaj)\x93Y\xe8\x86\xce3\xa3\x03A\xfa\xfeMW=\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4$<\x84\xd1$ W\f\xc4\xef;\xab\xa1\xc9Y\u0083$\x95 \x89\u007f\x1fi\x93\xa8S\x04\x00\x00\xe0\x94$CJ>2\xe5N\xcf'/\xe3G\v_oQ/gU \x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4$HYo\x91\xc0\x9b\xaa0\xbc\x96\x10j-7\xb5p^](\x89lk\x93[\x8b\xbd@\x00\x00\u0794$Xn\xc5E\x175\xee\xaa\xebG\r\xc8sj\xaeu/\x82\xe5\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4$X\xd6U_\xf9\x8a\x12\x9c\xce@7\x95=\x00 n\xffB\x87\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4$b\x91\x16[Y3-\xf5\xf1\x8c\xe5\u0248V\xfa\xe9X\x97\u0589\\(=A\x03\x94\x10\x00\x00\u07d4$g\u01a5\u0196\xed\xe9\xa1\xe5B\xbf\x1a\xd0k\xccK\x06\xac\xa0\x89\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4$v\xb2\xbbu\x1c\xe7H\xe1\xa4\xc4\xff{#\v\xe0\xc1]\"E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4$z\n\x11\xc5\u007f\x03\x83\xb9I\xdeT\vf\xde\xe6\x86\x04\xb0\xa1\x899\xfb\xae\x8d\x04-\xd0\x00\x00\u07d4$\x87\xc3\u013e\x86\xa2r=\x91|\x06\xb4XU\x01p\xc3\xed\xba\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\x89\xac\x12i4\xd4\u05a9M\xf0\x87C\xda{v\x91\xe9y\x8e\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\x9d\xb2\x9d\xbc\x19\xd1#]\xa7)\x8a\x04\b\x1c1WB\u9b09a\xac\xff\x81\xa7\x8a\xd4\x00\x00\u07d4$\xa4\xeb6\xa7\xe4\x98\xc3o\x99\x97\\\x1a\x8dr\x9f\u05b3\x05\u05c9\r\xfcx!\x0e\xb2\xc8\x00\x00\u07d4$\xa7P\xea\xe5\x87G\x11\x11m\xd7\xd4{q\x86\u0399\r1\x03\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4$\xaa\x11Q\xbbv_\xa3\xa8\x9c\xa5\x0e\xb6\xe1\xb1\xc7\x06A\u007f\u0509\xa8\r$g~\xfe\xf0\x00\x00\u0794$\xac\xa0\x8d[\xe8^\xbb\x9f12\xdf\xc1\xb6 \x82N\xdf\xed\xf9\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4$\xb2\xbe\x11\x8b\x16\u0632\x17Gi\xd1{L\xf8O\a\u0294m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4$\xb8\xb4F\u07bd\x19G\x95]\u0404\xf2\xc5D\x933F\u04ed\x89\xeaim\x90@9\xbd\x80\x00\u07d4$\xb9^\xbe\xf7\x95\x00\xba\xa0\xed\xa7.w\xf8wA]\xf7\\3\x891T\xc9r\x9d\x05x\x00\x00\u07d4$\xb9\xe6dOk\xa4\xcd\xe1&'\r\x81\xf6\xab`\xf2\x86\xdf\xf4\x89\a?u\u0460\x85\xba\x00\x00\u07d4$\xbdY\x04\x05\x90\x91\xd2\xf9\xe1-j&\xa0\x10\xca\"\xab\x14\xe8\x89e\xea=\xb7UF`\x00\x00\u07d4$\xc0\u020bT\xa3TG\t\x82\x8a\xb4\xab\x06\x84\x05Y\xf6\xc5\u2250\xf54`\x8ar\x88\x00\x00\u07d4$\xc1\x17\xd1\u04b3\xa9z\xb1\x1aFy\u025awJ\x9e\xad\xe8\u044965\u026d\xc5\u07a0\x00\x00\u07d4$\xcf\xf0\xe93j\x9f\x80\xf9\xb1\u02d6\x8c\xafk\x1d\x1cI2\xa4\x89\n\xdaUGK\x814\x00\x00\u07d4$\u06aa\xdd\xf7\xb0k\xbc\ua6c0Y\x00\x85\xa8\x85gh+N\x89\x11K \x15\u04bb\xd0\x00\x00\u07d4$\xdc\xc2K\xd9\xc7!\f\xea\u03f3\r\xa9\x8a\xe0JM{\x8a\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\xf7E\r\xdb\xf1\x8b\x02\x0f\xeb\x1a 2\xd9\xd5Kc>\xdf7\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4$\xfcs\xd2\a\x93\t\x8e\t\u076bW\x98Pb$\xfa\x1e\x18P\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4$\xfd\x9al\x87L/\xab?\xf3n\x9a\xfb\xf8\xce\r2\xc7\u0792\x89Hz\x9a0E9D\x00\x00\u07d4%\n@\xce\xf3 #\x97\xf2@F\x95H\xbe\xb5bj\xf4\xf2<\x89\x05\x03\xb2\x03\xe9\xfb\xa2\x00\x00\u07d4%\niC\av\xf64w\x03\xf9R\x97\x83\x95Za\x97\xb6\x82\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4%\x0e\xb7\xc6o\x86\x9d\xdfI\u0685\xf39>\x98\f\x02\x9a\xa44\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%\x10j\xb6u]\xf8mkc\xa1\x87p;\f\xfe\xa0\u5520\x89\x01|@Z\xd4\x1d\xb4\x00\x00\xe0\x94%\x18_2Z\xcf-dP\x06\x98\xf6\\v\x9d\xdfh0\x16\x02\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4%\x1c\x12r,hy\"y\x92\xa3\x04\xeb5v\xcd\x18CN\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\x1eh8\xf7\xce\u0173\x83\xc1\xd9\x01F4\x12t\xda\xf8\xe5\x02\x89\a\xff\x1c\xcbua\xdf\x00\x00\u07d4%%\x9d\x97Z!\xd8:\xe3\x0e3\xf8\x00\xf5?7\u07e0\x198\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4%({\x81_\\\x828\ns\xb0\xb1?\xba\xf9\x82\xbe$\xc4\u04c9\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94%+eU\xaf\u0700\xf2\xd9m\x97-\x17\u06c4\xeaZ\xd5!\xac\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4%8S)6\x81<\x91\xe6S(O\x01|\x80\u00f8\xf8\xa3o\x89l\x87T\xc8\xf3\f\b\x00\x00\xe0\x94%>2\xb7N\xa4I\n\xb9&\x06\xfd\xa0\xaa%{\xf2=\u02cb\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94%?\x1et*,\uc1b0\u05f3\x06\xe5\xea\xcbl\xcb/\x85T\x8a\x04>^\xde\x1f\x87\x8c \x00\x00\u07d4%A1J\v@\x8e\x95\xa6\x94DIwq*Pq5\x91\xab\x89X\x9e\x1a]\xf4\u05f5\x00\x00\u07d4%L\x1e\xccc\f(w\u0780\x95\xf0\xa8\u06e1\xe8\xbf\x1fU\f\x89\\(=A\x03\x94\x10\x00\x00\u07d4%Z\xbc\x8d\b\xa0\x96\xa8\x8f=j\xb5_\xbcsR\xbd\u0739\u0389\x04t6\x821>\u0780\x00\u07d4%[\xdddt\u0302b\xf2j\"\u00cfE\x94\x0e\x1c\ue99b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%`\xb0\x9b\x89\xa4\xaehI\xedZ<\x99XBf1qDf\x89\\(=A\x03\x94\x10\x00\x00\u07d4%a\xa18\xdc\xf8;\xd8\x13\xe0\xe7\xf1\bd+\xe3\xde=o\x05\x8964\xf4\x84\x17@\x1a\x00\x00\u0794%a\xec\x0f7\x92\x18\xfe^\xd4\xe0(\xa3\xf7D\xaaAuLr\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u0794%b\x92\xa1\x91\xbd\xda4\xc4\xdakk\u0591G\xbfu\u2a6b\x88\xc2\xff.\r\xfb\x03\x80\x00\u07d4%i~\xf2\f\u032ap\xd3-7o\x82r\xd9\xc1\a\f=x\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4%o\xa1P\u0307\xb5\x05j\a\xd0\x04\xef\xc8E$s\x9eb\xb5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4%r\x1c\x87\xb0\xdc!7|r\x00\xe5$\xb1J\"\xf0\xafi\xfb\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%\x899\xbb\xf0\f\x9d\xe9\xafS8\xf5\xd7\x14\xab\xf6\xd0\xc1\xc6q\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94%\x90\x12hp\xe0\xbd\xe8\xa6c\xab\x04\nr\xa5W=\x8dA\u008a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4%\x9e\xc4\xd2e\xf3\xabSk|p\xfa\x97\xac\xa1Bi,\x13\xfc\x89\x01\x1b\x1b[\xea\x89\xf8\x00\x00\xe0\x94%\xa5\x00\xee\xeczf*\x84\x15R\xb5\x16\x8bp{\r\xe2\x1e\x9e\x8a\x02\x1f/o\x0f\xc3\xc6\x10\x00\x00\xe0\x94%\xa5\xa4M8\xa2\xf4Lj\x9d\xb9\u037ck\x1e.\x97\xab\xb5\t\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4%\xa7L*\xc7]\u023a\xa8\xb3\x1a\x9c|\xb4\xb7\x82\x9b$V\u0689lk\x93[\x8b\xbd@\x00\x00\xe0\x94%\xad\xb8\xf9o9I,\x9b\xb4|^\u0708bNF\aV\x97\x8a\x05\xa9\x94\v\xc5hyP\x00\x00\u07d4%\xae\xe6\x8d\t\xaf\xb7\x1d\x88\x17\xf3\xf1\x84\xecV/x\x97\xb74\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\xb0S;\x81\xd0*a{\x92)\xc7\xec]o/g.[Z\x8965\u026d\xc5\u07a0\x00\x00\u07d4%\xb7\x8c\x9f\xad\x85\xb43C\xf0\xbf\xcd\x0f\xac\x11\u0254\x9c\xa5\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\xbcI\xef(\x8c\xd1e\xe5%\xc6a\xa8\x12\u03c4\xfb\xec\x8f3\x89\x12Y!\xae\xbd\xa9\xd0\x00\x00\u07d4%\xbd\xfa>\xe2o8Ia{#\x00bX\x8a\x97\xe3\xca\xe7\x01\x8965\xe6\x19\xbb\x04\xd4\x00\x00\u07d4%\xc1\xa3~\xe5\xf0\x82e\xa1\xe1\r=\x90\xd5G)U\xf9x\x06\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4%\xc6\xe7O\xf1\xd9(\u07d8\x13z\xf4\u07c40\xdf$\xf0|\u05c9\x15$VU\xb1\x02X\x00\x00\xe0\x94%\xcf\xc4\xe2\\5\xc1;i\xf7\xe7}\xbf\xb0\x8b\xafXuk\x8d\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94%\xda\u0515\xa1\x1a\x86\xb9\xee\xec\xe1\xee\xec\x80^W\xf1W\xfa\xff\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94%\xe07\xf0\n\x18'\v\xa5\xec4 \"\x9d\xdb\n,\u33e2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4%\xe6a\xc99\x86:\xcc\x04No\x17\xb5i\x8c\xce7\x9e\xc3\u0309JD\x91\xbdm\xcd(\x00\x00\u07d4&\x04\x8f\xe8M\x9b\x01\nb\xe71b~I\xbc.\xb7?@\x8f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4&\x06\u00f3\xb4\xca\x1b\t\x14\x98`,\xb1\x97\x8b\xf3\xb9R!\xc0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4&\n#\x0eDe\a~\v\x14\xeeDB\xa4\x82\u0570\xc9\x14\xbf\x89Z\xf6\x06\xa0k[\x11\x80\x00\u07d4&\r\xf8\x94:\x8c\x9a]\xbayE2\u007f\xd7\xe0\x83|\x11\xad\a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4&\x14\xf4-]\xa8D7ux\xe6\xb4H\xdc$0[\xef+\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\x15\x10\x0e\xa7\xe2[\xba\x9b\xcat`X\xaf\xbb\xb4\xff\xbeBD\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4&\x15u\xe9\xcfY\xc8\"o\xa7\xaa\xf9\x1d\xe8o\xb7\x0fZ\u00ee\x89\x10C\xa4CjR?\x00\x00\xe0\x94&\x1e\x0f\xa6LQ\x13te\xee\xcf[\x90\xf1\x97\xf7\x93\u007f\xdb\x05\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4&*\x8b\xfd}\x9d\xc5\xdd:\u05c1a\xb6\xbbV\b$76U\x89?j\x83\x84\a+v\x00\x00\xe0\x94&*\xedK\xc0\xf4\xa4\xb2\xc6\xfb5y>\x83ZI\x18\x9c\xdf\xec\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94&-\xc16L\xcfm\xf8\\C&\x8e\xe1\x82UM\xaei.)\x8a\x01\v /\xect\xce\xd8\x00\x00\u07d4&8\x140\x9d\xe4\xe65\xcfX^\r6Tw\xfc@\xe6l\xf7\x89\a\xea(2uw\b\x00\x00\u07d4&9\xee\xe9\x87<\xee\xc2o\u0314T\xb5H\xb9\xe7\xc5J\xa6\\\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94&>W\xda\xcb\xe0\x14\x9f\x82\xfee\xa2fH\x98\x86o\xf5\xb4c\x8a\b\v\xfb\xef\xcb_\v\xc0\x00\x00\u07d4>\x19\xc0m_\x14z\xa5\x97$\x8e\xb4l\xf7\xbe\xfad\xa5\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4&L\xc8\bj\x87\x10\xf9\x1b!r\t\x05\x91,\u05d6J\xe8h\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94&S\x83\u058bR\xd04\x16\x1b\xfa\xb0\x1a\xe1\xb0G\x94/\xbc2\x8a\x04rq\xde\xe2\rt\\\x00\x00\u07d4&Y\xfa\xcb\x1e\x83CeS\xb5\xb4)\x89\xad\xb8\a_\x99S\xed\x89\x01\x97evw\x1a^\x00\x00\xe0\x94&o-\xa7\xf0\b^\xf3\xf3\xfa\t\xba\xee#+\x93\xc7D\xdb.\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4&qH\xfdr\xc5Ob\nY/\xb9'\x991\x9c\xc4S+\\\x89\x169\u46fa\x16(\x00\x00\xe0\x94&xJ\u0791\u0228:\x8e9e\x8c\x8d\x82wA<\u0319T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4&z~n\x82\xe1\xb9\x1dQ\xde\u0776D\xf0\xe9m\xbb\x1f\u007f~\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4&\x80q=@\x80\x8e*P\xed\x011P\xa2\xa6\x94\xb9j\u007f\x1d\x89a\t=|,m8\x00\x00\u07d4&\x97\xb39\x81;\f-\x96K$q\xeb\x1c`oN\u02d6\x16\x89>\x8e\xf7\x95\u0610\xc8\x00\x00\u07d4&\xa6\x8e\xab\x90Z\x8b=\xce\x00\xe3\x170\x82%\u06b1\xb9\xf6\xb8\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4&\xb1\x1d\x06e\x88\xcet\xa5r\xa8Zc(s\x92\x12\xaa\x8b@\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xba\xbfB\xb2g\xfd\xcf8a\xfd\xd4#j^GHH\xb3X\x8965\u026d\xc5\u07a0\x00\x00\u07d4&\xc0\x05Kp\r:|-\xcb\xe2uh\x9dOL\xad\x16\xa35\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xc2\xff\xc3\x0e\xfd\xc5'>v\x18:\x16\xc2i\x8dnS\x12\x86\x89*\x11)\u0413g \x00\x00\u07d4&\u025f\x88I\u0240+\x83\xc8a!\u007f\xd0z\x9e\x84\u0377\x9d\x89\x10CV\x1a\x88)0\x00\x00\u07d4&\xcf\xff\xd0R\x15+\xb3\xf9W\xb4x\xd5\xf9\x8b#:|+\x92\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4&\u0521h\x91\xf5)\"x\x92\x17\xfc\u0606\xf7\xfc\xe2\x96\xd4\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xd4\xec\x17\xd5\u03b2\u0214\xbd\u015d\nji]\xad+C\u0309\x9f\x1fxv\x1d4\x1a\x00\x00\u07d4&\xe8\x01\xb6,\x82q\x91\xddh\xd3\x1a\x01\x19\x90\x94\u007f\xd0\xeb\xe0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4&\xe9\xe2\xadr\x97\x02bd\x17\xef%\xde\r\xc8\x00\xf7\xa7y\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4&\xf9\xf7\xce\xfd~9K\x9d9$A+\xf2\u0083\x1f\xaf\x1f\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94&\xfe\x17L\xbfRfP\xe0\xcd\x00\x9b\xd6\x12e\x02\u038ehM\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\xe0\x94&\xff\nQ\xe7\xce\u0384\x00'ix\xdb\xd6#n\xf1b\xc0\xe6\x8a\x15.\x18V'T\nP\x00\x00\u07d4'\x10\x1a\x0fV\u04da\x88\u0168O\x9b2L\xdd\xe3>\\\xb6\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'\x14L\xa9\xa7w\x1a\x83j\xd5\x0f\x80?d\xd8i\xb2\xae+ \x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4'\x14i\x13V:\xa7E\xe2X\x840\xd94\x8e\x86\xea|5\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4'\x1d=H\x1c\xb8\x8evq\xad!iI\xb66^\x060=\xe0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4' \xf9\xcaBn\xf2\xf2\xcb\xd2\xfe\xcd9\x92\fO\x1a\x89\xe1m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'*\x13\x1aZejz:\xca5\u023d \"\"\xa7Y\"X\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4'D\xffgFA!\xe3Z\xfc)\"\x17qd\xfa/\xcb\x02g\x89\x05k\xc7^-c\x10\x00\x00\u07d4'J=w\x1a=p\x97\x96\xfb\xc4\xd5\xf4\x8f\xce/\xe3\x8cy\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4'Mi\x17\x0f\xe7\x14\x14\x01\x88+\x88j\xc4a\x8cj\xe4\x0e\u06c93\xc5I\x901r\f\x00\x00\u07d4'R\x1d\xeb;n\xf1An\xa4\u01c1\xa2\xe5\u05f3n\xe8\x1ca\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'Xu\xffO\xbb\f\xf3\xa40!1'H\u007fv\b\xd0L\xba\x89\x1b\x1c\x01\x0evmX\x00\x00\u07d4'j\x00n0(\xec\xd4L\xdbb\xba\nw\u0394\xeb\xd9\xf1\x0f\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4'k\x05!\xb0\xe6\x8b'}\xf0\xbb2\xf3\xfdH2cP\xbf\xb2\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4'o\xd7\xd2O\x8f\x88?Zz()[\xf1qQ\u01e8K\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'p\xf1N\xfb\x16]\u07bay\xc1\v\xb0\xaf1\xc3\x1eY3L\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4'vw\xab\xa1\xe5,;S\xbf\xa2\a\x1dN\x85\x9a\n\xf7\xe8\xe1\x8965\u026d\xc5\u07a0\x00\x00\u07d4'\x82Ff\xd2x\xd7\x04#\xf0=\xfe\x1d\u01e3\xf0/C\u2d4966\xc2^f\xec\xe7\x00\x00\u07d4'\x83\f_`#\xaf\xaa\xf7\x97Egl J\x0f\xac\u0360\xba\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94'\x84\x90?\x1d|\x1b\\\xd9\x01\xf8\x87]\x14\xa7\x9b<\xbe*V\x8a\x04\xbd\xa7\xe9\xd7J\xd5P\x00\x00\u07d4'\x8c\v\xdec\x0e\u00d3\xb1\xe7&\u007f\xc9\xd7\xd9p\x19\xe4\x14[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'\x98q\x10\"\x1a\x88\b&\xad\xb2\xe7\xab^\xcax\xc6\xe3\x1a\xec\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94'\xac\a;\xe7\x9c\xe6W\xa9:\xa6\x93\xeeC\xbf\x0f\xa4\x1f\xef\x04\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4'\xb1iN\xaf\xa1e\xeb\xd7\xcc{\u025et\x81J\x95\x14\x19\u0709+^:\xf1k\x18\x80\x00\x00\u07d4'\xb6(\x16\xe1\xe3\xb8\u045by\xd1Q=]\xfa\x85[\f:*\x89\x05j\xf5\xc1\xfdiP\x80\x00\u07d4'\xbf\x94<\x163\xfe2\xf8\xbc\xcc\xdbc\x02\xb4\a\xa5rND\x892\xf8Lm\xf4\b\xc0\x80\x00\u07d4'\xbf\x9fD\xba}\x05\xc35@\u00e5;\xb0,\xbb\xff\xe7\xc3\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4'\xc2\xd7\xcaPM\xaa=\x90f\xdc\t\x13}\xc4/:\xaa\xb4R\x89 \x86\xac5\x10R`\x00\x00\u07d4'\xd1X\xac=>\x11\t\xabnW\x0e\x90\xe8]8\x92\xcdv\x80\x89\x05k\xc7^-c\x10\x00\x00\u07d4'\xe69\x89\xca\x1e\x90;\xc6 \xcf\x1b\x9c?g\xb9\xe2\xaee\x81\x89Hz\x9a0E9D\x00\x00\xe0\x94'\xf0<\xf1\xab\xc5\xe1\xb5\x1d\xbcDK(\x9eT,\x9d\u07f0\xe6\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4'\xfc\x85\xa4\x9c\xff\x90\xdb\xcf\xda\u071d\xdd@\u05b9\xa2!\nl\x89\x05k\xc7^-c\x10\x00\x00\u07d4(\x05A^\x1d\u007f\xde\xc6\xde\u07f8\x9eR\x1d\x10Y-t<\x10\x89\x05k\xc7^-c\x10\x00\x00\u07d4(\a>\xfc\x17\xd0\\\xab1\x95\xc2\xdb3+a\x98Gw\xa6\x12\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x12P\xa2\x91!'\nN\xe5\u05cd$\xfe\xaf\xe8,p\xba:\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x13\xd2c\xfc_\xf2G\x9e\x97\x05\x95\u05b6\xb5`\xf8\xd6\xd6\u0449lk\x93[\x8b\xbd@\x00\x00\u07d4(.\x80\xa5T\x87ZVy\x9f\xa0\xa9\u007fU\x10\u7557LN\x8965\u026d\xc5\u07a0\x00\x00\u07d4(3\x96\xce<\xac9\x8b\xcb\xe7\"\u007f2>x\xff\x96\u0407g\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4(4\x9f~\xf9t\xeaU\xfe6\xa1X;4\xce\xc3\xc4Pe\xf0\x89\f\xb63\u051eeY\x00\x00\u07d4(6\x120F\xb2\x84\xe5\xef\x10+\xfd\"\xb1v^P\x81\x16\xad\x89\x16S\xfb\xb5\xc4'\xe4\x00\x00\u07d4(<#\x14(<\x92\u0530d\xf0\xae\xf9\xbbRF\xa7\x00\u007f9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4(>\x11 7I\xb1\xfaO2\xfe\xbbq\xe4\x9d\x13Y\x198*\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94(>bR\xb4\xef\xcfFT9\x1a\xcbu\xf9\x03\u015bx\xc5\xfb\x8a\x02\x8a\x85t%Fo\x80\x00\x00\xe0\x94(Q\x0en\xff\x1f\xc8)\xb6WoC(\xbc98\xecze\x80\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4(X\xac\xac\xaf!\xea\x81\u02b7Y\x8f\xdb\xd8kE.\x9e\x8e\x15\x89$\x1a\x9bOaz(\x00\x00\u07d4(Z\xe5\x1b\x95\x00\u014dT\x13e\xd9ui\xf1K\xb2\xa3p\x9b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(f\xb8\x1d\xec\xb0.\xe7\n\xe2P\xce\xe5\xcd\xc7{Y\u05f6y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(i\x06\xb6\xbdIr\xe3\xc7\x16U\xe0K\xaf6&\f|\xb1S\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4(k\x18ma\xea\x1f\u05cd\x990\xfe\x12\xb0e7\xb0\\=Q\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94(t\xf3\xe2\x98]_{@f'\xe1{\xaaw+\x01\xab\u031e\x8a\x01F\x05\x04\x10v_8\x00\x00\xe0\x94(|\xf9\u0410.\xf8\x19\xa7\xa5\xf1ID[\xf1w^\xe8\xc4|\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4(\x81\x8e\x18\xb6\x10\x00\x13!\xb3\x1d\xf6\xfe}(\x15\u036d\xc9\xf5\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x86\x83$3~\x11\xba\x10l\xb4\x81\u0696/:\x84S\x80\x8d\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94(\x90K\xb7\xc40)C\xb7\t\xb1Myp\xe4+\x83$\u184a\x02\x1f\x97\x84j\a-~\x00\x00\u07d4(\x95\xe8\t\x99\xd4\x06\xadY.+&'7\xd3_}\xb4\xb6\x99\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4(\x96r\x80!N!\x8a\x12\f]\xda7\x04\x1b\x11\x1e\xa3mt\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4(\xa3\xda\t\xa8\x19H\x19\xae\x19\x9f.m\x9d\x13\x04\x81~(\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(\xab\x16_\xfbi\xed\xa0\xc5I\xae8\xe9\x82o_\u007f\x92\xf8S\x89FM\xf6\xd7\xc8DY\x00\x00\u07d4(\xb7u\x85\xcb=U\xa1\x99\xab)\x1d:\x18\u018f\u8684\x8a\x89j@v\xcfy\x95\xa0\x00\x00\xe0\x94(\xd4\xeb\xf4\x1e=\x95\xf9\xbb\x9a\x89u#\\\x1d\x009>\x80\x00\u07d4)\nV\xd4\x1fn\x9e\xfb\xdc\xea\x03B\u0dd2\x9a\x8c\xdf\xcb\x05\x89\x12\xa5\xf5\x81h\xee`\x00\x00\u07d4)\x15bK\xcbg\x917\xb8\xda\xe9\xabW\xd1\x1bI\x05\xea\xeeK\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4)\x1e\xfe\x00\x81\xdc\xe8\xc1G\x99\xf7\xb2\xa46\x19\xc0\u00f3\xfc\x1f\x89A\rXj \xa4\xc0\x00\x00\u07d4)\x1f\x92\x9c\xa5\x9bT\xf8D>=Mu\xd9]\xee$<\xefx\x89\x1b\x1a\b\x927\a=\x00\x00\xe0\x94))\x8c\xcb\xdf\xf6\x89\xf8\u007f\xe4\x1a\xa6\xe9\x8f\u07f5=\xea\xf3z\x8a\x041\\2\xd7\x1a\x9e`\x00\x00\u07d4)/\"\x8b\n\x94t\x8c\x8e\xeca-$o\x98\x93c\xe0\x8f\b\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4)3\x84\xc4+o\x8f)\x05\xceR\xb7 \\\"t7la+\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4)4\xc0\xdf{\xbc\x17+l\x18k\vrTz\u038b\xf7TT\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4)<#\x06\xdf6\x04\xaeO\xda\r z\xbasog\xde\a\x92\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94)I\xfd\x1d\xef\\v\xa2\x86\xb3\x87$$\x80\x9a\a\xdb9f\xf3\x8a\x01\x1b\xd9\x06\u06a0\xc9C\x80\x00\u07d4)OIK?.\x14\xa3\xf8\xab\x00\x00\x00\u07d4)U\xc3W\xfd\x8fu\xd5\x15\x9a=\xfai\u0178z5\x9d\ua309lk\x93[\x8b\xbd@\x00\x00\u07d4)a\xfb9\x1ca\x95|\xb5\xc9\xe4\a\u0762\x938\u04f9,\x80\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4)h\x1d\x99\x12\xdd\xd0~\xaa\xbb\x88\xd0]\x90\xf7f\xe8bA}\x8965\u026d\xc5\u07a0\x00\x00\u07d4)kq\xc0\x01X\x19\xc2B\xa7\x86\x1eo\xf7\xed\xed\x8a_q\xe3\x89lh\xcc\u041b\x02,\x00\x00\u07d4)mf\xb5!W\x1aNA\x03\xa7\xf5b\xc5\x11\xe6\xaas-\x81\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4)o\x00\xde\x1d\u00fb\x01\xd4z\x8c\xcd\x1e]\x1d\u0661\xebw\x91\x8965\u026d\xc5\u07a0\x00\x00\u07d4)s\x85\xe8\x864FV\x85\xc21\xa3\x14\xa0\xd5\xdc\xd1F\xaf\x01\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4)v=\xd6\u069a|\x16\x11s\x88\x83!\ub9b6<\x8f\xb8E\x89\x11\xc7\xea\x16.x \x00\x00\u07d4)yt\x11t\xa8\xc1\xea\v\u007f\x9e\xdfe\x81w\x85\x94\x17\xf5\x12\x89\x19\x01\x96l\x84\x96\x83\x80\x00\u07d4)z\x88\x92\x1b_\xca\x10\u5edd\xed`\x02T7\xae\"\x16\x94\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94)}]\xbe\"//\xb5%1\xac\xbd\v\x01=\xc4F\xacsh\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4)\x82N\x94\xccCH\xbc\x962y\xdc\xdfG9\x17\x152L\u04c9i*\xe8\x89p\x81\xd0\x00\x00\u07d4)\x82\xd7j\x15\xf8G\xddA\xf1\x92*\xf3h\xfeg\x8d\x0eh\x1e\x89\x05k\xc7^-c\x10\x00\x00\u07d4)\x88\x87\xba\xb5|[\xa4\xf0aR)\xd7R_\xa1\x13\xb7\ua249\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94)\x8e\xc7kD\r\x88\a\xb3\xf7\x8b_\x90\x97\x9b\xeeB\xedC\u06ca\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4)\x93h`\x90B\xa8X\xd1\xec\xdf\x1f\xc0\xad\xa5\xea\xce\xca)\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4)\x9e\v\xcaU\xe0i\u0785\x04\xe8\x9a\xcan\xca!\u04ca\x9a]\x89\x03\x027\x9b\xf2\xca.\x00\x00\u07d4)\xac+E\x84T\xa3l~\x96\xc7:\x86g\"*\x12$,q\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94)\xad\u03c3\xb6\xb2\n\u01a44\xab\xb1\x99<\xbd\x05\xc6\x0e\xa2\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94)\xae\xf4\x8d\xe8\xc9\xfb\xadK\x9eL\xa9pyzU3\xebr-\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4)\xb3\xf5a\xeezn%\x94\x1e\x98\xa52[x\xad\u01d7\x85\xf3\x89\x05k\xc7^-c\x10\x00\x00\u07d4)\xbd\xc4\xf2\x8d\xe0\x18\x0fC<&\x94\xebt\xf5PL\xe9C7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4)\u0300M\x92+\xe9\x1fY\t\xf3H\xb0\xaa\xa5\xd2\x1b`x0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94)\xda>5\xb2;\xb1\xf7/\x8e\"X\xcf\u007fU3Y\xd2K\xac\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94)\xe6y\x90\xe1\xb6\xd5.\x10U\xff\xe0I\xc51\x95\xa8\x15B\u03ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4)\uab82v\x17b\xf4\xd2\xdbS\xa9\u018b\x0fk\vmNf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4)\xeb~\xef\xda\xe9\xfe\xb4I\xc6?\xf5\xf2y\xd6u\x10\xeb\x14\"\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4)\xf0\xed\xc6\x038\xe7\x11 \x85\xa1\xd1\x14\u068cB\u038fU\u0589\xa0Z\u007f\x0f\xd8%x\x00\x00\u07d4)\xf8\xfb\xa4\xc3\ar\xb0W\xed\xbb\xe6*\xe7B\f9\x05r\xe1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94)\xf9(l\x0es\x8d\x17!\xa6\x91\u01b9Z\xb3\u0667\x97\xed\xe8\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4*\b^%\xb6Hb\xf5\xe6\x8dv\x8e+\x0fz\x85)\x85\x8e\xee\x89k\x88:\xcdWf\xcd\x00\x00\u07d4**\xb6\xb7Lz\xf1\xd9Gk\xb5\xbc\xb4RG\x97\xbe\xdc5R\x8965\u026d\xc5\u07a0\x00\x00\u07d4*9\x19\nO\u0783\u07f3\xdd\xcbL_\xbb\x83\xaclIu\\\x8965\u026d\xc5\u07a0\x00\x00\u07d4*@\r\xff\x85\x94\xder(\xb4\xfd\x15\xc3#\"\xb7[\xb8}\xa8\x89\x051\xa1\u007f`z-\x00\x00\xe0\x94*D\xa7!\x8f\xe4Me\xa1\xb4\xb7\xa7\u0671\xc2\xc5,\x8c>4\x8a\r-\x06\xc3\x05\xa1\xebW\x80\x00\u07d4*F\xd3Swqv\xff\x8e\x83\xff\xa8\x00\x1fOp\xf9s:\xa5\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4*Y_\x16\xee\xe4\xcb\f\x17\u0662\xd99\xb3\xc1\x0flgrC\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4*Y\xe4~\xa5\xd8\xf0\xe7\xc0(\xa3\xe8\xe0\x93\xa4\x9c\x1bP\xb9\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4*[\xa9\xe3L\u054d\xa5L\x9a'\x12f:;\xe2t\xc8\xe4{\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94*^:@\xd2\xcd\x03%vm\xe7:=g\x18\x96\xb3b\xc7;\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94*cY\x0e\xfe\x99\x86\xc3\xfe\xe0\x9b\n\n3\x8b\x15\xbe\xd9\x1f!\x8a\x01^\x1cN\x05\xee&\xd0\x00\x00\u07d4*gf\n\x13h\xef\xcdbn\xf3k+\x1b`\x19\x80\x94\x1c\x05\x89\a?u\u0460\x85\xba\x00\x00\u07d4*t+\x89\x10\x94\x1e\t2\x83\n\x1d\x96\x92\xcf\u0484\x94\xcf@\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4*tl\xd4@'\xaf>\xbd7\xc3x\xc8^\xf7\xf7T\xab_(\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4*\x81\xd2|\xb6\xd4w\x0f\xf4\xf3\u0123\xba\x18\xe5\xe5\u007f\aQ|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4*\x91\xa9\xfe\xd4\x1b}\x0e\\\xd2\xd81X\xd3\xe8\xa4\x1a\x9a-q\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94*\x9cW\xfe{k\x13\x8a\x92\rgo{\x1a%\x10\x80\xff\xb9\x8a4\xf0\x86\xf3\xb3;h@\x00\x00\u07d4+p\x1d\x16\xc0\xd3\xcc\x1eL\xd8TE\xe6\xad\x02\ue92c\x01-\x89 \x86\xac5\x10R`\x00\x00\xe0\x94+q|\xd42\xa3#\xa4e\x909\x84\x8d;\x87\xde&\xfc\x95F\x8ai\xe1\r\xe7fv\u0400\x00\x00\u07d4+t\xc3s\xd0K\xfb\x0f\xd6\n\x18\xa0\x1a\x88\xfb\xe8Gp\u5309\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4+w\xa4\u060c\rV\xa3\xdb\xe3\xba\xe0J\x05\xf4\xfc\u0477W\xe1\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94+\x84\x88\xbd-<\x19z=&\x15\x18\x15\xb5\xa7\x98\xd2qh\u070a\x01j\x1f\x9f_\xd7\xd9`\x00\x00\u07d4+\x8a\r\xee\\\xb0\xe1\xe9~\x15\xcf\xcan\x19\xad!\xf9\x95\ufb49\x1bUC\x8d\x9a$\x9b\x00\x00\xe0\x94+\x8f\xe4\x16n#\xd1\x19c\xc0\x93+\x8a\u078e\x01E\xea\ap\x8a\t(\x96R\x9b\xad\u0708\x00\x00\xe0\x94+\x99\xb4.OBa\x9e\xe3k\xaa~J\xf2\xd6^\xac\xfc\xba5\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4+\xab\x0f\xbe(\u0544 \xb5 6w\n\x12\xf9\x95*\xeai\x11\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4+\xad\xe9\x1d\x15E\x17b\x0f\u05349\xac\x97\x15zA\x02\xa9\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4+\xaf\x8dn\"\x11t\x12H \xeeI+\x94Y\xecO\xad\xaf\xbb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4+\xaf\xbf\x9e\x9e\xd2\xc2\x19\xf7\xf2y\x13t\xe7\xd0\\\xb0gw\xe7\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\xe0\x94+\xb3f\xb9\xed\xcb\r\xa6\x80\xf0\xe1\v;n(t\x81\x90\xd6\u00ca\x01:b\u05f5v@d\x00\x00\xe0\x94+\xb6\xf5x\xad\xfb\u7ca1\x16\xb3UO\xac\xf9\x96\x98\x13\xc3\x19\x8a\x01\x91'\xa19\x1e\xa2\xa0\x00\x00\u07d4+\xbeb\xea\xc8\f\xa7\xf4\xd6\xfd\xee~}\x8e(\xb6:\xcfw\x0e\x89\x81\xe3-\xf9r\xab\xf0\x00\x00\u07d4+\xbeg*\x18WP\x8fc\x0f*^\xdbV=\x9e\x9d\xe9(\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4+\xc4)\xd6\x18\xa6jL\xf8-\xbb-\x82N\x93V\xef\xfa\x12j\x89lj\xccg\u05f1\xd4\x00\x00\u07d4+\xd2R\xe0\xd72\xff\x1d|x\xf0\xa0.l\xb2T#\xcf\x1b\x1a\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4+\xdd\x03\xbe\xbb\xee';l\xa1\x05\x9b4\x99\x9a[\xbda\xbby\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,\x04\x11\\>R\x96\x1b\r\xc0\xb0\xbf1\xfb\xa4ToYf\xfd\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94,\x06\u0752+aQJ\xaf\xed\xd8D\x88\xc0\u008em\xcf\x0e\x99\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94,\f\xc3\xf9QH,\u0222\x92X\x15hN\xb9\xf9N\x06\x02\x00\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4,\x0e\xe14\u0633aE\xb4{\xee\u7bcd'8\xdb\xda\b\xe8\x89\n\xe5os\x0em\x84\x00\x00\u07d4,\x0f[\x9d\xf46%y\x8e~\x03\xc1\xa5\xfdjm\t\x1a\xf8+\x89\x01\xb0\xfc\xaa\xb2\x000\x00\x00\u07d4,\x12\x8c\x95\xd9W!Q\x01\xf0C\u074f\u0142EmA\x01m\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4,\x18\x00\xf3_\xa0->\xb6\xff[%(_^J\xdd\x13\xb3\x8d\x891\"\u04ed\xaf\xde\x10\x00\x00\u07d4,\x1c\x19\x11N=m\xe2xQHK\x8d'\x15\xe5\x0f\x8a\x10e\x89\x05k\xc7^-c\x10\x00\x00\u07d4,\x1c\xc6\xe1\x8c\x15$\x88\xba\x11\xc2\xcc\x1b\xce\xfa-\xf3\x06\xab\u0449Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94,\x1d\xf8\xa7oH\xf6\xb5K\u03dc\xafV\xf0\xee\x1c\xf5z\xb3=\x8a\x02$\u007fu\x00\x89\xdaX\x00\x00\u07d4,!G\x94z\xe3?\xb0\x98\xb4\x89\xa5\xc1k\xff\xf9\xab\xcdN*\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4,#OP\\\xa8\xdc\xc7}\x9b~\x01\xd2W\xc3\x18\xcc\x199m\x89\x05k\xc7^-c\x10\x00\x00\u07d4,$(\xe4\xa6it\xed\xc8\"\xd5\xdb\xfb$\x1b'(\aQX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,-\x15\xff9V\x1c\x1br\xed\xa1\xcc\x02\u007f\xfe\xf27C\xa1D\x89\u0500\xed\x9e\xf3+@\x00\x00\u07d4,-\xb2\x8c3\t7^\xea1\x82\x1b\x84\xd4\b\x93\x0e\xfa\x1a\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4,Z-\n\xbd\xa0;\xbe!W\x81\xb4\xff)l\x8ca\xbd\xba\xf6\x89\x01\xa8\xe5oH\xc0\"\x80\x00\u07d4,[}{\x19Z7\x1b\xf9\xab\u0774/\xe0O/\x1d\x9a\x99\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4,]\xf8ffj\x19K&\u03bb@~J\x1f\xd7> \x8d^\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94,`?\xf0\xfe\x93alCW>\xf2y\xbf\xea@\x88\x8dj\xe7\x8a\x01\x00\xf4\xb6\xd6gW\x90\x00\x00\xe0\x94,hF\xa1\xaa\x99\x9a\"F\xa2\x87\x05`\x00\xbaM\u02e8\xe6=\x8a\x02\x1f/o\x0f\xc3\xc6\x10\x00\x00\u0794,j\xfc\xd4\x03|\x1e\xd1O\xa7O\xf6u\x8e\tE\xa1\x85\xa8\xe8\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4,ki\x9d\x9e\xad4\x9f\x06\u007fEq\x1a\aJd\x1d\xb6\xa8\x97\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,o\\\x12L\u01c9\xf8\xbb9\x8e?\x88\x97Q\xbcK`-\x9e\x89\x01Y\xf2\v\xed\x00\xf0\x00\x00\u07d4,\x83\xae\xb0/\xcf\x06}e\xa4p\x82\xfd\x97x3\xab\x1c\uc449\b'8#%\x8a\xc0\x00\x00\xe0\x94,\x89\xf5\xfd\xca=\x15T\t\xb68\xb9\x8at.U\xebFR\xb7\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4,\x96HI\xb1\xf6\x9c\xc7\u03a4D%8\xed\x87\xfd\xf1l\xfc\x8f\x89lk\x93[\x8b\xbd@\x00\x00\u0794,\x9f\xa7,\x95\xf3}\b\xe9\xa3`\t\u7930\u007f)\xba\xd4\x1a\x88\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4,\xafk\xf4\xec}Z\x19\xc5\xe0\x89z^\xeb\x01\x1d\xce\xceB\x10\x89\a\x93H5\xa01\x16\x00\x00\u07d4,\xb4\xc3\xc1k\xb1\xc5^|kz\x19\xb1'\xa1\xac\x93\x90\xcc\t\x89\xb8'\x94\xa9$O\f\x80\x00\xe0\x94,\xb5IZPS6\xc2FT\x10\xd1\xca\xe0\x95\xb8\xe1\xba\\\u074a\x04<3\xc1\x93ud\x80\x00\x00\u07d4,\xb6\x15\a:@\xdc\u06d9\xfa\xa8HW.\x98{;\x05n\xfb\x89+X\xad\u06c9\xa2X\x00\x00\u07d4,\xbam]\r\xc2\x04\xea\x8a%\xad\xa2\xe2oVu\xbd_/\u0709H#\xef}\u06da\xf3\x80\x00\u07d4,\xbb\fs\u07d1\xb9\x17@\xb6i;wJ}\x05\x17~\x8eX\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4,\xcbfIM\n\xf6\x89\xab\xf9H=6]x$D\xe7\u07ad\x8965\u026d\xc5\u07a0\x00\x00\u07d4,\xcc\x1f\x1c\xb5\xf4\xa8\x00.\x18k \x88]\x9d\xbc\x03\f\b\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,\u03c0\xe2\x18\x98\x12^\xb4\xe8\a\u0342\xe0\x9b\x9d(Y/n\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,\u0456\x94\u0452j\x0f\xa9\x18\x9e\u07ba\xfcg\x1c\xf1\xb2\u02a5\x8965\u026d\xc5\u07a0\x00\x00\u07d4,\u04d34\xac~\xacyrW\xab\xe3sa\x95\xf5\xb4\xb5\xce\x0f\x89\x05kGx^7&\x00\x00\u07d4,\u05de\xb5 '\xb1,\x18\x82\x8e>\xaa\xb2\x96\x9b\xfc\u0487\xe9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,\xd8xfV\x8d\xd8\x1a\xd4}\x9d:\u0404nZePss\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4,\xdb9De\x06\x16\xe4|\xb1\x82\xe0`2/\xa1Hyx\u0389b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4,\xe1\x1a\x92\xfa\xd0$\xff+>\x87\xe3\xb5B\xe6\xc6\r\xcb\u0656\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4-\x03&\xb2?\x04\t\xc0\xc0\xe9#hc\xa13\aZ\x94\xba\x18\x89\vg\x9b\xe7[\xe6\xae\x00\x00\u07d4-\r\xecQ\xa6\xe8s0\xa6\xa8\xfa*\x0fe\u060dJ\xbc\xdfs\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4-#vkok\x05s}\xad\x80\xa4\x19\xc4\x0e\xdaMw\x10>\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4-+\x03#Y\xb3c\x96O\xc1\x1aQ\x82c\xbf\xd0T1\xe8g\x89\b\x1c\x1d\xf7b\x9ep\x00\x00\u07d4-4\x80\xbf\be\aJr\xc7u\x9e\xe5\x13{Mp\xc5\x1c\xe9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4-5\xa9\xdfbu\u007f\u007f\xfa\xd1\x04\x9a\xfb\x06\xcaJ\xfcFLQ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4-@U\x8b\x06\xf9\n9#\x14U\x92\x12;gt\xe4n1\xf4\x8965\u026d\xc5\u07a0\x00\x00\u07d4-Bi\x12\xd0Y\xfa\xd9t\v.9\n.\xea\xc0To\xf0\x1b\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4-S-\xf4\xc69\x11\xd1\u0391\xf6\xd1\xfc\xbf\xf7\x96\x0fx\xa8\x85\x89Z\x85\x96\x8aXx\u0680\x00\u07d4-S\x91\xe98\xb3HX\u03d6[\x84\x051\xd5\xef\xdaA\v\t\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94-[B\xfcY\xeb\xda\r\xfdf\xae\x91K\u008c\x1b\nn\xf8:\x8a+\u0235\x9f\xdc\xd86c\x80\x00\u07d4-]s5\xac\xb06+G\u07e3\xa8\xa4\xd3\xf5\x94\x95D\u04c0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-a\xbf\xc5hs\x92<+\x00\t]\xc3\xea\xa0\xf5\x90\u062e\x0f\x8a\x04ef\xdf\xf8\xceU`\x00\x00\u07d4-e\x11\xfdz8\x00\xb2hT\xc7\xec9\xc0\u0735\xf4\xc4\xe8\xe8\x89\x15\xad\u077a/\x9ew\x00\x00\u07d4-}\\@\u076f\xc4P\xb0Jt\xa4\u06bc+\xb5\xd6e\x00.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4-\x89\xa8\x00jO\x13z \xdc+\xecF\xfe.\xb3\x12\xea\x96T\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4-\x8cR2\x9f8\u04a2\xfa\x9c\xba\xf5\u0143\xda\xf1I\v\xb1\x1c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4-\x8e\x06\x18\x92\xa5\xdc\xce!\x96j\xe1\xbb\a\x88\xfd>\x8b\xa0Y\x89\r\x8e\\\xe6\x17\xf2\xd5\x00\x00\u07d4-\x8e[\xb8\xd3R\x16\x95\xc7~|\x83N\x02\x91\xbf\xac\xeet\b\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4-\x90\xb4\x15\xa3\x8e.\x19\xcd\xd0/\U000ed069z\xf7\xcb\xf6r\x89\x05\xf3\xc7\xf6A1\xe4\x00\x00\u07d4-\x9b\xado\x1e\xe0*p\xf1\xf1=\xef\\\u0332z\x9a'@1\x89a\t=|,m8\x00\x00\u07d4-\x9c_\xec\u04b4O\xbbj\x1e\xc72\xea\x05\x9fO\x1f\x9d+\\\x896\xca2f\x1d\x1a\xa7\x00\x00\xe0\x94-\xa6\x17iP\t\xccW\xd2j\u0510\xb3*]\xfb\xeb\x93N^\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4-\xa7k|9\xb4 \u323a,\x10 \xb0\x85k\x02pd\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4-\u01ddn\u007fU\xbc\xe2\xe2\xd0\xc0*\xd0|\uca3bR\x93T\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\xe0\x94-\xca\x0eD\x9a\xb6F\xdb\xdf\u04d3\xa9fb\x96\v\u02b5\xae\x1e\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4-\xd3%\xfd\xff\xb9{\x19\x99R\x84\xaf\xa5\xab\xdbWJ\x1d\xf1j\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4-\xd5x\xf7@}\xfb\xd5H\xd0^\x95\xcc\u00dcHT)bj\x89\u3bb5sr@\xa0\x00\x00\u07d4-\xd8\xee\xef\x87\x19J\xbc,\xe7X]\xa1\xe3[|\xeax\f\xb7\x8965\xc6 G9\u0640\x00\u07d4-\xdf@\x90Wi\xbc\xc4&\xcb,)8\xff\xe0w\xe1\u8758\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4-\xe0\x96D\x00\u0082\xbd\u05ca\x91\x9ck\xf7|k_yay\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-\xe3\x1a\xfd\x18\x9a\x13\xa7o\xf6\xfes\xea\xd9\xf7K\xb5\u0126)\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4-\xec\x982\x9d\x1f\x96\u00e5\x9c\xaay\x81uTR\xd4\xdaI\u0549\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-\ue422\x8f\x19-gj\x87s#+V\xf1\x8f#\x9e/\xad\x8a\x03\xef\xa7\xe7G\xb6\u046d\x00\x00\xe0\x94.\b\x80\xa3E\x96#\a \xf0Z\xc8\xf0e\xaf\x86\x81\u0736\u008a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4.\fW\xb4qP\xf9Z\xa6\xa7\xe1j\xb9\xb1\xcb\xf5C(\x97\x9a\x89\x05k\xc7^-c\x10\x00\x00\u07d4.\x10\x91\v\xa6\xe0\xbc\x17\xe0UUf\x14\u02c7\t\x0fM~[\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94.$\xb5\x97\x87;\xb1A\xbd\xb27\xea\x8aZ\xb7Gy\x9a\xf0-\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4.(\x10\xde\xe4J\xe4\xdf\xf3\xd8cB\xab\x12fW\xd6S\xc36\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4.,\xbdz\xd8%G\xb4\xf5\xff\x8b:\xb5o\x94*dE\xa3\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4.-~\xa6k\x9fG\xd8\xccR\xc0\x1cR\xb6\u147c}G\x86\x89\xd8\xd4`,&\xbfl\x00\x00\u07d4.C\x93H\u07caBw\xb2*v\x84W\xd1\x15\x8e\x97\xc4\t\x04\x89*\x1e\x9f\xf2o\xbfA\x00\x00\xe0\x94.F\xfc\xeej;\xb1E\xb5\x94\xa2C\xa3\x91?\xce]\xado\xba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794.G\xf2\x87\xf4\x98#7\x13\x85\r1&\x82<\xc6}\xce\xe2U\x88\u029d\x9e\xa5X\xb4\x00\x00\u07d4.N\u1b99j\xa0\xa1\xd9$(\xd0fR\xa6\xbe\xa6\xd2\xd1]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.R\x91+\xc1\x0e\xa3\x9dT\xe2\x93\xf7\xae\u05b9\x9a\x0fLs\xbe\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4.a\x9fW\xab\xc1\u91ea\x93j\xe3\xa2&Ib\xe7\xeb-\x9a\x89(\xfb\x9b\x8a\x8aSP\x00\x00\u07d4.d\xa8\xd7\x11\x11\xa2/L]\xe1\xe09\xb36\xf6\x8d9\x8a|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.i3T=O,\xc0\vSP\xbd\x80h\xba\x92C\u05be\xb0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94.~\x05\xe2\x9e\u0767\xe4\xae%\xc5\x175C\xef\xd7\x1fm=\x80\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4.\u007fFU \xec5\xcc#\u058eue\x1b\xb6h\x95D\xa1\x96\x898\xec[r\x1a\x1a&\x80\x00\u07d4.\x8e\xb3\nqn_\xe1\\t#>\x03\x9b\xfb\x11\x06\xe8\x1d\x12\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94.\x98$\xb5\xc12\x11\x1b\xca$\xdd\xfb\xa7\xe5u\xa5\xcdr\x96\xc1\x8a\x03\xa4\x84Qnm\u007f\xfe\x00\x00\u07d4.\xa5\xfe\xe6?3z7nK\x91\x8e\xa8!H\xf9MH\xa6&\x89e\x0f\x8e\r\u0493\xc5\x00\x00\u07d4.\xafN*F\xb7\x89\xcc\u0088\xc8\xd1\xd9)N?\xb0\x858\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.\xaf\xf9\xf8\xf8\x110d\u04d5z\xc6\xd6\xe1\x1e\xeeB\xc8\x19]\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4.\xba\fn\xe5\xa1\x14\\\x1cW9\x84\x96:`]\x88\nz \x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4.\xc9X\"\xeb\x88{\xc1\x13\xb4q*M\xfd\u007f\x13\xb0\x97\xb5\xe7\x8965\u026d\xc5\u07a0\x00\x00\u07d4.\xcaj<]\x9fD\x9d\tV\xbdC\xfa{M{\xe8CYX\x89lk\xdaip\x9c\xc2\x00\x00\xe0\x94.\xca\xc5\x04\xb23\x86n\xb5\xa4\xa9\x9e{\u0490\x13Y\xe4;=\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4.\xeb\xf5\x942\xb5(\x92\xf98\v\xd1@\xaa\x99\xdc\xf8\xad\f\x0f\x89\b=lz\xabc`\x00\x00\u07d4.\xee\xd5\x04q\xa1\xa2\xbfS\xee0\xb1#.n\x9d\x80\xef\x86m\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4.\xefk\x14\x17\u05f1\x0e\xcf\xc1\x9b\x12:\x8a\x89\xe7>RlX\x89 \x86\xac5\x10R`\x00\x00\u07d4.\xf8i\xf05\vW\xd54x\xd7\x01\xe3\xfe\xe5)\xbc\x91\x1cu\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4.\xf9\xe4eqj\xca\u03f8\xc8%/\xa8\xe7\xbcyi\xeb\xf6\u4255\x9e\xb1\xc0\xe4\xae \x00\x00\xe0\x94.\xfcLd}\xacj\xca\xc3Uw\xad\"\x17X\xfe\xf6ao\xaa\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4/\x13eu&\xb1w\xca\xd5G\u00d0\x8c\x84\x0e\xffd{E\u0649?v\x84\x9c\xf1\xee,\x80\x00\u07d4/\x18}ZpMZ3\x8c[(v\xa0\x90\xdc\xe9d(N)\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94/%#\u0303O\x00\x86\x05$\x02bb\x96gQ\x86\xa8\u508a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4/(*\xbb\xb6\u0523\xc3\xcd;\\\xa8\x12\xf7d>\x800_\x06\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4/+\xba\x1b\x17\x96\x82\x1avo\xced\xb8O(\xech\xf1Z\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4/1]\x90\x16\xe8\xee_Sf\x81 /\x90\x84\xb02TMM\x898<\xd1+\x9e\x86<\x00\x00\u07d4/M\xa7SC\x0f\xc0\x9es\xac\xbc\xcd\xcd\xe9\xdad\u007f+]7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4/P\x80\xb8?~-\xc0\xa1\xdd\x11\xb0\x92\xad\x04+\xffx\x8fL\x89\xb4\xf8\xfby#\x1d+\x80\x00\u07d4/a\uf941\x9dp_+\x1eN\xe7T\xae\xb8\xa8\x19Pju\x89O%\x91\xf8\x96\xa6P\x00\x00\xe0\x94/f\xbf\xbf\"b\xef\u030d+\xd0DO\u0170ib\x98\xff\x1e\x8a\x02\x1a\xd95\xf7\x9fv\xd0\x00\x00\u07d4/m\xce\x130\u015e\xf9!`!TW-MK\xac\xbd\x04\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4/}2\x90\x85\x1b\xe5\u01b4\xb4?}Et2\x9fa\xa7\x92\u00c9\x05k\xc7^-c\x10\x00\x00\u07d4/\x858\x17\xaf\u04f8\xf3\xb8n\x9f`\xeew\xb5\xd9ws\xc0\xe3\x89N\xae\xeaD\xe3h\xb9\x00\x00\u07d4/\xa4\x91\xfbY \xa6WN\xbd(\x9f9\xc1\xb2C\r-\x9aj\x89lk\x93[\x8b\xbd@\x00\x00\u07d4/\xb5f\xc9K\xbb\xa4\xe3\xcbg\xcd\xda}_\xadq1S\x91\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4/\xbbPJ]\xc5'\xd3\xe3\xeb\x00\x85\xe2\xfc<}\xd58\xcbz\x89C\u00b1\x8a\xec<\n\x80\x00\u07d4/\xbc\x85y\x8aX5\x98\xb5\"\x16mn\x9d\xda\x12\x1db}\xbc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4/\xbc\xef3\x84\xd4 \xe4\xbfa\xa0f\x99\x90\xbcpT\U00065bc9lk\x93[\x8b\xbd@\x00\x00\xe0\x94/\xc8.\xf0v\x93#A&Oaz\f\x80\xddW\x1ej\xe99\x8a\x01\x84$\xf5\xf0\xb1\xb4\xe0\x00\x00\u07d4/\u075by\u07cd\xf50\xadc\xc2\x0eb\xafC\x1a\xe9\x92\x16\xb8\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4/\xe0\x02?W\"e\x0f:\x8a\xc0\x10\t\x12^t\xe3\xf8.\x9b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4/\xe0\xccBKS\xa3\x1f\t\x16\xbe\b\xec\x81\xc5\v\xf8\xea\xb0\xc1\x89 \x86\xac5\x10R`\x00\x00\u07d4/\xe1:\x8d\a\x85\u0787X\xa5\xe4\x18v\xc3n\x91l\xf7Pt\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4/\xea\x1b/\x83O\x02\xfcT3?\x8a\x80\x9f\x048\xe5\x87\n\xa9\x89\x01\x18T\xd0\xf9\xce\xe4\x00\x00\u07d4/\xee6\xa4\x9e\xe5\x0e\xcfqo\x10G\x91VFw\x9f\x8b\xa0?\x899B\"\xc4\u0686\xd7\x00\x00\u07d4/\xef\x81G\x8aK.\x80\x98\xdb_\xf3\x87\xba!S\xf4\xe2+y\x896'\xe8\xf7\x127<\x00\x00\u07d4/\xf1`\xc4Or\xa2\x99\xb5\xec-q\xe2\x8c\xe5Dm/\u02ef\x89\x13\x84\x00\xec\xa3d\xa0\x00\x00\u07d4/\xf1\xcaU\xfd\x9c\xec\x1b\x1f\xe9\U00029af7LQ<\x1e*\xaa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94/\xf5\u02b1,\r\x95\u007f\xd33\xf3\x82\xee\xb7Q\a\xa6L\xb8\xe8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94/\xf80\xcfU\xfb\x00\u0560\xe05\x14\xfe\xcdD1K\xd6\xd9\xf1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4/\xfe\x93\xec\x1aV6\xe9\xee4\xafp\xdf\xf5&\x82\xe6\xffpy\x89lk\x93[\x8b\xbd@\x00\x00\u07d40\x03y\x88p&q\xac\xbe\x89,\x03\xfeW\x88\xaa\x98\xaf(z\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d40$\x8dX\xe4\x14\xb2\x0f\xed:lH+Y\xd9\xd8\xf5\xa4\xb7\xe2\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4019\xbcYd\x03\xd5\u04d3\x1fwLf\u013aFtT\u06c9\\%\xe1J\xea(?\x00\x00\u079408\x00\x87xie\x14\x9e\x81B;\x15\xe3\x13\xba2\xc5\u01c3\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d40:0\xacB\x86\xae\x17\xcfH=\xad{\x87\fk\xd6M{J\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d40?\xba\xeb\xbeF\xb3[n[t\x94j_\x99\xbc\x15\x85\xca\xe7\x89/\x9a\xc0i_[\xba\x00\x00\u07d40ADZ3\xba\x15\x87A\x16\r\x9c4N\xb8\x8e\\0o\x94\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d40H\x01d\xbc\xd8It\xeb\xc0\xd9\f\x9b\x9a\xfa\xb6&\xcd\x1cs\x89+^:\xf1k\x18\x80\x00\x00\u07d40N\u019atTW!\xd71j\xefM\u03f4\x1a\u015e\xe2\xf0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x940Q\x182\x91\x8d\x804\xa7\xbe\xe7.\xf2\xbf\xeeD\x0e\u02fc\xf6\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d40Q?\u029f6\xfdx\x8c\xfe\xa7\xa3@\xe8m\xf9\x82\x94\xa2D\x89\x18;_\x03\xb1G\x9c\x00\x00\u07d40U\xef\xd2`)\xe0\xd1\x1b\x93\r\xf4\xf5;\x16,\x8c?\xd2\u0389\x1b\x1a\b\x927\a=\x00\x00\u07d40]&\xc1\v\xdc\x10?k\x9c!'.\xb7\xcb-\x91\b\xc4~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d40_x\xd6\x18\xb9\x90\xb4)[\xac\x8a-\xfa&(\x84\xf8\x04\xea\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x940d\x89\x9a\x96\x1a>\x1d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d40\x98\xb6]\xb9>\xca\xca\xf75\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d40\uc4d2$J!\b\u0247\xbc\\\xdd\xe0\ud7c3z\x81{\x89T\x99%\xf6\xc9\xc5%\x00\x00\xe0\x940\xed\x11\xb7{\xc1~^f\x94\u023c[nG\x98\xf6\x8d\x9c\xa7\x8a\x1eo\xb3B\x1f\xe0)\x9e\x00\x00\u07d40\xf7\xd0%\xd1o{\xee\x10U\x80Ho\x9fV\x1c{\xae?\xef\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x940\xfb\xe5\x88_\x9f\xcc\xe9\xea^\u06c2\xedJ\x11\x96\xdd%\x9a\xed\x8a\x01\x19\xe4\u007f!8\x1f@\x00\x00\u07d41\x04}p?c\xb94$\xfb\xbdn/\x1f\x9et\xde\x13\xe7\t\x89\x9a\x81f\xf7\u6ca7\x80\x00\u07d411?\xfdc[\xf2\xf32HA\xa8\x8c\a\xed\x14aD\xce\xeb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d41Y\xe9\fH\xa9\x15\x90J\xdf\u24b2/\xa5\xfd^ryk\x896\xaf\xe9\x8f&\x06\x10\x00\x00\u07d41]\xb7C\x9f\xa1\u0574#\xaf\xa7\xddq\x98\xc1\xcft\xc9\x18\xbc\x89 \x86\xac5\x10R`\x00\x00\u07d41^\xf2\xdab\x0f\xd30\xd1.\xe5]\xe5\xf3)\xa6\x96\xe0\xa9h\x89\b!\xab\rD\x14\x98\x00\x00\u07d41n\x92\xa9\x1b\xbd\xa6\x8b\x9e/\x98\xb3\xc0H\x93N<\xc0\xb4\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d41n\xb4\xe4}\xf7\x1bB\xe1mo\xe4h%\xb72{\xaf1$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d41q\x87~\x9d\x82\f\xc6\x18\xfc\t\x19\xb2\x9e\xfd3?\xdaI4\x8965\u026d\xc5\u07a0\x00\x00\u07d41|\xf4\xa2<\xb1\x91\xcd\xc5c\x12\u009d\x15\xe2\x10\xb3\xb9\xb7\x84\x89\a\xcef\xc5\x0e(@\x00\x00\u07d41\x8b.\xa5\xf0\xaa\xa8y\xc4\xd5\xe5H\xac\x9d\x92\xa0\xc6t\x87\xb7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d41\x8cv\xec\xfd\x8a\xf6\x8dpUSR\xe1\xf6\x01\xe3Y\x88\x04-\x89\x1b1\x19.h\xc7\xf0\x00\x00\u07d41\x8f\x1f\x8b\xd2 \xb0U\x8b\x95\xfb3\x10\x0f\xfd\xbbd\r|\xa6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d41\xaa;\x1e\xbe\x8cM\xbc\xb6\xa7\b\xb1\xd7H1\xe6\x0eIv`\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d41\xab\b\x89f\xec\xc7\"\x92X\xf6\t\x8f\xceh\xcf9\xb3\x84\x85\x8965\u026d\xc5\u07a0\x00\x00\xe0\x941\xadM\x99F\xef\t\xd8\xe9\x88\xd9F\xb1\"\u007f\x91A\x90\x176\x8a\x04\xd8S\xc8\xf8\x90\x89\x80\x00\x00\xe0\x941\xb4;\x01]\x00\x81d~h\x00\x00\u07d424\x86\xcad\xb3uGO\xb2\xb7Y\xa9\xe7\xa15\x85\x9b\xd9\xf6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d427I\xa3\xb9q\x95\x9eF\u0234\x82-\xca\xfa\xf7\xaa\xf9\xbdn\x89\x01\x16q\xa5\xb2Ep\x00\x00\u07d42:\xadA\xdfKo\xc8\xfe\u038c\x93\x95\x8a\xa9\x01\xfah\bC\x894\x95tD\xb8@\xe8\x00\x00\xe0\x942;<\xfe>\xe6+\xbd\xe2\xa2a\xe5<\xb3\xec\xc0X\x10\xf2\u018a\x02\ub3b1\xa1r\u0738\x00\x00\u07d42?\xca^\xd7\u007fi\x9f\x9d\x990\xf5\xce\xef\xf8\xe5oY\xf0<\x89Hz\x9a0E9D\x00\x00\u07d42H\\\x81\x87(\xc1\x97\xfe\xa4\x87\xfb\xb6\xe8)\x15\x9e\xba\x83p\x899!\xb4\x13\xbcN\xc0\x80\x00\xe0\x942P\xe3\xe8X\xc2j\xde\u032d\xf3jVc\xc2*\xa8LAp\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x942Y\xbd/\xdd\xfb\xbco\xba\u04f6\xe8t\xf0\xbb\xc0,\xda\x18\xb5\x8a\x02\x84`VI[\r\x18\x80\x00\u07d42uIo\xd4\u07491\xfdi\xfb\n\v\x04\xc4\xd1\xff\x87\x9e\xf5\x89\x18-~L\xfd\xa08\x00\x00\u07d42{\xb4\x9euOo\xb4\xf73\xc6\xe0o9\x89\xb4\xf6]K\xee\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d42\x82y\x1do\xd7\x13\xf1\xe9OK\xfdV^\xaax\xb3\xa0Y\x9d\x89Hz\x9a0E9D\x00\x00\u07d42\x83\xeb\u007f\x917\xdd9\xbe\xd5_\xfek\x8d\xc8E\xf3\xe1\xa0y\x89\x03\x97\n\xe9!Ux\x00\x00\u07d42\x86\t\x97\xd70\xb2\xd8;s$\x1a%\xd3f}Q\xc9\b\xef\x89\x1b\x1a\b\x927\a=\x00\x00\xe0\x942\x86\u047cez1,\x88G\xd9<\xb3\xcbyP\xf2\xb0\xc6\xe3\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x942\xa2\r\x02\x8e,b\x18\xb9\xd9[D\\w\x15$cj\"\xef\x8a\x02\x02\xfe\xfb\xf2\xd7\xc2\xf0\x00\x00\u07d42\xa7\x06\x91%\\\x9f\xc9y\x1aOu\u0238\x1f8\x8e\n%\x03\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d42\xb7\xfe\xeb\xc5\u015b\xf6^\x86\x1cL\v\xe4*v\x11\xa5T\x1a\x89w\u9aa8R\\\x10\x00\x00\xe0\x942\xba\x9a}\x04#\xe0:R_\xe2\xeb\xebf\x1d \x85w\x8b\u060a\x04<3\xc1\x93ud\x80\x00\x00\u07d42\xbb.\x96\x93\xe4\xe0\x854M/\r\xbdF\xa2\x83\u3807\xfd\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x942\xc2\xfd\u2daa\xbb\x80\u5ba2\xb9I\xa2\x17\xf3\xcb\t\"\x83\x8a\x010a`\xaf\xdf 7\x80\x00\u07d42\xd9P\xd5\xe9>\xa1\u0574\x8d\xb4qO\x86{\x03 \xb3\x1c\x0f\x897\b\xba\xed=h\x90\x00\x00\u07d42\u06f6qlT\xe81e\x82\x9aJ\xbb6uxI\xb6\xe4}\x8965\u026d\xc5\u07a0\x00\x00\u07d42\xebd\xbe\x1b]\xed\xe4\b\u01bd\xef\xben@\\\x16\xb7\xed\x02\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d42\xef\\\xdcg\x1d\xf5V*\x90\x1a\xee]\xb7\x16\xb9\xbev\xdc\xf6\x89lk\x93[\x8b\xbd@\x00\x00\u07d42\xf2\x9e\x87'\xa7LkC\x01\xe3\xff\xff\x06\x87\xc1\xb8p\xda\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d42\xfa\x0e\x86\xcd\b}\u058di1\x90\xf3-\x931\t\t\xedS\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d42\xfb\xee\xd6\xf6&\xfc\xdf\xd5\x1a\xca\xfbs\v\x9e\xef\xf6\x12\xf5d\x89lk\x93[\x8b\xbd@\x00\x00\u07943\x00\xfb\x14\x9a\xde\xd6[\u02e6\xc0N\x9c\u05b7\xa0;\x89;\xb1\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x943\x01\xd9\xca/;\xfe\x02by\xcdh\x19\xf7\x9a)=\x98\x15n\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\xe0\x943\b\xb04f\xc2z\x17\xdf\xe1\xaa\xfc\xeb\x81\xe1m)4Vo\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07943\x1a\x1c&\xcci\x94\xcd\xd3\xc1K\xec\xe2v\xff\xffK\x9d\xf7|\x88\xfaz\xed\xdfO\x06\x80\x00\xe0\x943&\xb8\x8d\xe8\x06\x18DT\xc4\v'\xf3\t\xd9\xddm\u03f9x\x8a\x03\xca\\f\u067cD0\x00\x00\xe0\x943)\xeb;\xafCE\xd6\x00\xce\xd4\x0en\x99ueo\x117B\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d432\r\xd9\x0f+\xaa\x11\r\xd34\x87*\x99\x8f\x14\x84&E<\x8965f3\xeb\xd8\xea\x00\x00\u07d436\xc3\xefn\x8bP\xee\x90\xe07\xb1d\xb7\xa8\xea_\xaa\xc6]\x89\x0e\u0223\xa7\x1c\"T\x00\x00\xe0\x9438\fo\xffZ\xcd&Q0\x96)\u06daq\xbf? \u017a\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d43:\xd1Yd\x01\xe0Z\xea-6\xcaG1\x8e\xf4\xcd,\xb3\u07c9\x9d\xc0\\\xce(\u00b8\x00\x00\u07d43C@\xeeK\x9c\u0701\xf8P\xa7Q\x16\xd5\x0e\u9d98%\xbf\x89lk\x93[\x8b\xbd@\x00\x00\u07d43H\x1e\x85n\xbe\u050e\xa7\b\xa2t&\xef(\xe8g\xf5|\u0449\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x943V[\xa9\xda,\x03\xe7x\xce\x12)O\b\x1d\xfe\x81\x06M$\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07943X\x1c\xee#0\x88\xc0\x86\r\x94N\f\xf1\u03ab\xb8&\x1c.\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d43XX\xf7I\xf1i\u02bc\xfeR\xb7\x96\xe3\xc1\x1e\xc4~\xa3\u0089\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x943^\"\x02[zw\u00e0t\u01cb\x8e=\xfe\a\x13A\x94n\x8a\x02'\xcas\n\xb3\xf6\xac\x00\x00\u07d43b\x9b\xd5/\x0e\x10{\xc0q\x17ld\xdf\x10\x8fdw}I\x89\x01\xcf\xddth!n\x80\x00\u07d43{;\u07c6\xd7\x13\xdb\xd0{]\xbf\xcc\x02+z{\x19F\xae\x89\xd7\xc1\x98q\x0ef\xb0\x00\x00\u07d43|\xfe\x11W\xa5\u0191 \x10\xddV\x153y\x17i\u00b6\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d43\xb36\xf5\xba^\xdb{\x1c\xcc~\xb1\xa0\u0644\xc1#\x1d\x0e\u0709lk\x93[\x8b\xbd@\x00\x00\u07d43\xc4\a\x13;\x84\xb3\xcaL=\xed\x1fFX\x90\f8\x10\x16$\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\xe0\x943\xd1r\xab\a\\Q\xdb\x1c\xd4\n\x8c\xa8\xdb\xff\r\x93\xb8C\xbb\x8a\x016x\x05\x10\xd1-\xe3\x80\x00\u07d43\xe9\xb7\x18#\x95.\x1ff\x95\x8c'\x8f\u008b\x11\x96\xa6\u0164\x89\x05k\xc7^-c\x10\x00\x00\u07d43\xeakxU\xe0[\a\xab\x80\u06b1\xe1M\xe9\xb6I\xe9\x9bl\x89\x1c\xd6\xfb\xadW\xdb\xd0\x00\x00\u07d43\xf1R#1\rD\u078bf6h_:L=\x9cVU\xa5\x89\r\x94b\xc6\xcbKZ\x00\x00\u07d43\xf4\xa6G\x1e\xb1\xbc\xa6\xa9\xf8[;Hr\xe1\aU\xc8+\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d43\xfbWzM!O\xe0\x10\xd3,\xca|>\xed\xa6?\x87\xce\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d43\xfdq\x8f\v\x91\xb5\xce\u020a]\xc1^\xec\xf0\xec\xef\xa4\xef=\x89\x17r$\xaa\x84Lr\x00\x00\u07d44\x14\x80\u030c\xb4v\xf8\xd0\x1f\xf3\b\x12\xe7\xc7\x0e\x05\xaf\xaf]\x89lk\x93[\x8b\xbd@\x00\x00\u07d44'-^ut1]\xca\u9afd1{\xac\x90(\x9dGe\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x9440\xa1c\x81\xf8i\xf6\xeaT#\x91XU\xe8\x00\x885%\xa9\x8a\x03\xca\\f\u067cD0\x00\x00\u07d441\x86%\x81\x8e\xc1?\x11\x83Z\xe9sS\xce7}oY\n\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d449<]\x91\xb9\xdeYr\x03\xe7[\xacC\t\xb5\xfa=(\u00c9\n\x84Jt$\xd9\xc8\x00\x00\u07d449\x99\x8b$|\xb4\xbf\x8b\xc8\nm+5'\xf1\xdf\xe9\xa6\u0489\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d44C}\x14ed\v\x13l\xb5\x84\x1c?\x93O\x9b\xa0\xb7\t}\x89\t`\xdbwh\x1e\x94\x00\x00\u07d44J\x8d\xb0\x86\xfa\xedN\xfc7\x13\x1b:\"\xb0x-\xadp\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x944fM\"\x0f\xa7\xf3yX\x02J32\u0584\xbc\xc6\xd4\u023d\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d44f\xf6~9cl\x01\xf4;:!\xa0\xe8R\x93%\xc0\x86$\x89-\xb1\x16vP\xac\xd8\x00\x00\u07d44\x856\x1e\xe6\xbf\x06\xefe\b\xcc\xd2=\x94d\x1f\x81M>/\x89lk\x93[\x8b\xbd@\x00\x00\u07d44\x85\xf6!%d3\xb9\x8aB\x00\xda\xd8W\xef\xe5Y7\uc609lk\x93[\x8b\xbd@\x00\x00\u07d44\x95\x8aF\xd3\x0e0\xb2s\xec\xc6\xe5\xd3X\xa2\x12\xe50~\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d44\x97\xddf\xfd\x11\x80q\xa7\x8c,\xb3n@\xb6e\x1c\xc8%\x98\x89\x05\xf1\x01kPv\xd0\x00\x00\xe0\x944\x9a\x81k\x17\xab='\xbb\xc0\xae\x00Q\xf6\xa0p\xbe\x1f\xf2\x9d\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d44\x9d,\x91\x8f\u041e(\a1\x8ef\xceC)\t\x17k\xd5\v\x89<\xb7\x1fQ\xfcU\x80\x00\x00\u07d44\xa0C\x1f\xff^\xad\x92\u007f\xb6`\f\x1e\xa8\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d44\xff&\xeb`\xa8\u0469ZH\x9f\xae\x13n\xe9\x1dNX\bL\x89 \x86\xac5\x10R`\x00\x00\u07d44\xffX)R\xff$E\x8f{\x13\xd5\x1f\vO\x98p\"\xc1\xfe\x89\x98\x06\xde=\xa6\xe9x\x00\x00\u07d45\x10k\xa9N\x85c\u0533\xcb<\\i,\x10\xe6\x04\xb7\xce\u0609lk\x93[\x8b\xbd@\x00\x00\xe0\x945\x14_b\x03\x97\u019c\xb8\xe0\tb\x96\x1f\x0fH\x86d9\x89\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d45\x14t0\xc3\x10e\x00\u77e2\xf5\x02F.\x94p<#\xb1\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x945\x17\x87\x845\x05\xf8\xe4\xef\xf4ef\xcc\u695fM\x1c_\xe7\x8a\x01\xf5q\x89\x87fKH\x00\x00\xe0\x945\x1f\x16\xe5\xe0sZ\xf5gQ\xb0\xe2%\xb2B\x11q9@\x90\x8a\x02\xd4\xca\x05\xe2\xb4<\xa8\x00\x00\xe0\x945$\xa0\x00#N\xba\xaf\a\x89\xa14\xa2\xa4\x178<\xe5(*\x8a\x011yU\x94}\x8e,\x00\x00\u07d45&\xee\xce\x1ak\xdc>\xe7\xb4\x00\xfe\x93[HF?1\xbe\u05c9\x04w\x87\x9bm\x140\x00\x00\u07d45*x_J\x92\x162PL\xe5\xd0\x15\xf8\xd7FO\xa3\xdb\x14\xe7r\x92\x13\u03aa7\x8c\t^\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d45\xaf\x04\n\f\xc23zv\xaf(\x81T\xc7V\x1e\x1a#3I\x8965\u026d\xc5\u07a0\x00\x00\u07d45\xb0>\xa4$W6\xf5{\x85\xd2\xebyb\x8f\x03m\xdc\xd7\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d45\xbd$he\xfa\xb4\x90\xac\bz\xc1\xf1\xd4\xf2\xc1\r\f\xda\x03\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x945\xbff\x88R/5Fz\u007fu0#\x14\xc0+\xa1v\x80\x0e\x8a\x03\xafA\x82\x02\xd9T\xe0\x00\x00\u07d45\u022d\xc1\x11%C+;w\xac\xd6F%\xfeX\xeb\xee\x9df\x89lk\x93[\x8b\xbd@\x00\x00\u07d45\u0497\x0fI\xdc\xc8\x1e\xa9\xeep~\x9c\x8a\n\xb2\xa8\xbbtc\x89N\x10\x03\xb2\x8d\x92\x80\x00\x00\u07d45\xe0\x96\x12\r\xea\xa5\xc1\xec\xb1d^,\u02cbN\xdb\xd9)\x9a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d45\xea!c\xa3\x8c\u07da\x12?\x82\xa5\xec\x00%\x8d\xae\v\xc7g\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d45\xf1\xda\x12{\x837o\x1b\x88\xc8*3Y\xf6z^g\xddP\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d45\xf2\x94\x9c\xf7\x8b\xc2\x19\xbbO\x01\x90|\xf3\xb4\xb3\u04c6T\x82\x89\x0f\xb5\xc8l\x92\xe44\x00\x00\u07d45\xf5\x86\x01I\xe4\xbb\xc0K\x8a\u0172r\xbeU\xad\x1a\xcaX\xe0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d46\x02E\x8d\xa8omj\x9d\x9e\xb0=\xaf\x97\xfeV\x19\xd4B\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x057-\x93\xa9\x01\t\x88\x01\x8f\x9f1]\x03.\u0448\x0f\xa1\x89\x1b\x1b\xcfQ\x89j}\x00\x00\u07d46\x16\xd4H\x98_]2\xae\xfa\x8b\x93\xa9\x93\xe0\x94\xbd\x85I\x86\x89\v\"\u007fc\xbe\x81<\x00\x00\u07d46\x16\xfbF\xc8\x15x\xc9\xc8\xebM;\xf8\x80E\x1a\x887\x9d}\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d46\x1cu\x93\x16\x96\xbc=B}\x93\xe7lw\xfd\x13\xb2A\xf6\xf4\x89\x1d\xc5\xd8\xfc&m\xd6\x00\x00\u07d46\x1d\x9e\xd8\v[\xd2|\xf9\xf1\"o&u2X\xee_\x9b?\x89\xbfi\x14\xba}r\xc2\x00\x00\u07d46\x1f;\xa9\xed\x95kw\x0f%}6r\xfe\x1f\xf9\xf7\xb0$\f\x89 \x86\xac5\x10R`\x00\x00\u07d46\"|\u07e0\xfd;\x9d~jtF\x85\xf5\xbe\x9a\xa3f\xa7\xf0\x89\n\xc2s\x0e\xe9\xc6\xc1\x80\x00\u07d46/\xbc\xb1\x06b7\n\x06\x8f\xc2e&\x02\xa2Wy7\xcc\xe6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d460\xc5\xe5e\u03aa\x8a\x0f\x0f\xfe2\x87^\xae*l\xe6<\x19\x89\t7r+7t\xd0\x00\x00\u07d463\x9f\x84\xa5\u00b4L\xe5=\xfd\xb6\xd4\xf9}\xf7\x82\x12\xa7\u07c9\x11o\x18\xb8\x17\x15\xa0\x00\x00\u07d464:\xec\xa0{n\u054a\x0eb\xfaN\xcbI\x8a\x12O\xc9q\x89\x10CV\x1a\x88)0\x00\x00\u07d46au@4\x81\xe0\xab\x15\xbbQF\x15\u02f9\x89\xeb\u018f\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d46ro;\x88Z$\xf9)\x96\u0681b^\u022d\x16\xd8\xcb\xe6\x89S\xafu\u0441HW\x80\x00\xe0\x946s\x95C\x99\xf6\u07feg\x18\x18%\x9b\xb2x\xe2\xe9.\xe3\x15\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d46u\x8e\x04\x9c\u064b\u03a1\"w\xa6v\xf9)sb\x89\x00#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d46\u007fY\u0302yS)8NA\xe1(1\x15\xe7\x91\xf2j\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x81\x0f\xf9\xd2\x13\xa2q\xed\xa2\xb8\xaay\x8b\xe6T\xfaK\xbe\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x8cT\x14\xb5k\x84U\x17\x1f\xbf\ab \xc1\u02e4\xb5\xca1\x89\x1e>\xf9\x11\xe8=r\x00\x00\xe0\x946\x90$k\xa3\xc8\x06y\xe2.\xacD\x12\xa1\xae\xfc\xe6\xd7\u0342\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d46\x92\x8bU\xbc\x86\x15\t\xd5\x1c\x8c\xf1\xd5F\xbf\xecn>\x90\xaf\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d46\x98\"\xf5W\x8b@\xdd\x1fDqpk\"\u0357\x13R\xdak\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d46\x9e\xf7a\x19_:7>$\xec\xe6\xcd\"R\x0f\xe0\xb9\xe8n\x89\x1c\xff\xaf\xc9M\xb2\b\x80\x00\u07d46\xa0\x8f\xd6\xfd\x1a\xc1|\xe1^\xd5~\xef\xb1*+\u2048\xbf\x89Hz\x9a0E9D\x00\x00\u07d46\xa0\xe6\x1e\x1b\xe4\u007f\xa8~0\xd3(\x88\xee\x030\x90\x1c\xa9\x91\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x946\xb2\xc8^:\xee\xeb\xb7\rc\u0124s\f\xe2\xe8\xe8\x8a6$\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x946\xbfC\xff5\u07d0\x90\x88$3l\x9b1\xce3\x06~/P\x8aIr\x15\x10\xc1\xc1\xe9H\x00\x00\u07d46\xbf\xe1\xfa;{p\xc1r\xeb\x04/h\x19\xa8\x97%\x95A>\x8965\u026d\xc5\u07a0\x00\x00\xe0\x946\xc5\x10\xbf\x8dnV\x9b\xf2\xf3}G&]\xbc\xb5\x02\xff+\u038a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x946\xd8]\xc3h1V\xe6;\xf8\x80\xa9\xfa\xb7x\x8c\xf8\x14:'\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d46\u07cf\x88<\x12s\xec\x8a\x17\x1fz3\xcf\xd6I\xb1\xfe`u\x89\fRHJ\xc4\x16\x89\x00\x00\xe0\x946\xe1Va\f\xd8\xffd\xe7\x80\u061d\x00T8\\\xa7gU\xaa\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d46\xfe\xc6,,B^!\x9b\x18D\x8a\xd7W\x00\x9d\x8cT\x02o\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d47\x00\xe3\x02t$\xd99\xdb\xde]B\xfbx\xf6\xc4\xdb\xec\x1a\x8f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d47\x02\xe7\x04\xcc!at9\xadN\xa2zW\x14\xf2\xfd\xa1\xe92\x8965\u026d\xc5\u07a0\x00\x00\u07d47\x035\fMo\xe374,\xdd\xc6[\xf1\xe28k\xf3\xf9\xb2\x89m\x81!\xa1\x94\xd1\x10\x00\x00\xe0\x947\b\xe5\x9d\xe6\xb4\x05P\x88x)\x02\xe0W\x9cr\x01\xa8\xbfP\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d47\x126~^U\xa9mZ\x19\x16\x8fn\xb2\xbc~\x99q\xf8i\x8965\u026d\xc5\u07a0\x00\x00\u07d47\x19Zc]\xccb\xf5jq\x80I\xd4~\x8f\x9f\x96\x83(\x91\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d47'4\x1f&\xc1 \x01\xe3x@^\xe3\x8b-\x84d\xecq@\x89lk\x93[\x8b\xbd@\x00\x00\u07d47.E:kb\x9f'g\x8c\u022e\xb5\xe5|\xe8^\xc0\xae\xf9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d474\xcb\x18t\x91\xed\xe7\x13\xae[;-\x12(J\xf4k\x81\x01\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d477!n\xe9\x1f\x17w2\xfbX\xfa@\x97&r\a\xe2\xcfU\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d47M;\xbb\x057Q\xf9\xf6\x8d\xdb\a\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d48r\xf4\x8d\xc5\xe3\xf8\x17\xbck*\xd2\xd00\xfc^\x04q\x19=\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d48~\xea\xfdk@\t\u07af\x8b\u0578Zr\x98:\x8d\xcc4\x87\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d48\x81\xde\xfa\xe1\xc0{<\xe0Lx\xab\xe2k\f\u070ds\xf0\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d48\x83\xbe\xcc\b\xb9\xbeh\xad;\b6\xaa\u00f6 \xdc\x00\x17\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d48\x85\xfe\xe6q\a\xdc:\xa9\x8a\x1d\x99:t\xdf\\\xd7T\xb9\x8dR\x9a\x89a\t=|,m8\x00\x00\u07d48\xe4m\xe4E<8\xe9A\xe7\x93\x0fC0O\x94\xbb{+\xe8\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d48\xe7\u06e8\xfdO\x1f\x85\r\xbc&I\xd8\xe8O\tR\xe3\xeb<\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d48\xe8\xa3\x1a\xf2\xd2e\xe3\x1a\x9f\xff-\x8fF(m\x12E\xa4g\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d48\xeao[Z{\x88AuQ\xb4\x12=\xc1'\xdf\xe94-\xa6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d48\xee\xc6\xe2\x17\xf4\xd4\x1a\xa9 \xe4$\xb9RQ\x97\x04\x1c\xd4\u0189\xf0\r%\xeb\x92.g\x00\x00\xe0\x948\xf3\x87\xe1\xa4\xedJs\x10n\xf2\xb4b\xe4t\xe2\xe3\x14:\u040a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d49\x11a\xb0\xe4<0 f\u898d,\xe7\xe1\x99\xec\xdb\x1dW\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x949\x15\uad6b.Yw\xd0u\xde\xc4}\x96\xb6\x8bK\\\xf5\x15\x8a\r\a\x01\x81\x85\x12\x0f@\x00\x00\u07d49\x1aw@\\\t\xa7+^\x846#z\xaa\xf9]h\xda\x17\t\x89\x02\xa9&J\xf3\u0479\x00\x00\u07d49\x1f \x17m\x126\rrMQG\n\x90p6uYJM\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d49$3\xd2\u0383\xd3\xfbJv\x02\u0323\xfa\xcaN\xc1@\xa4\xb0\x89\x02\xc3\xc4e\xcaX\xec\x00\x00\xe0\x949?x;\\\u06c6\"\x1b\xf0)O\xb7\x14\x95\x9c{E\x89\x9c\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d49?\xf4%^\\e\x8f.\u007f\x10\xec\xbd)%rg\x1b\xc2\u0489lk\x93[\x8b\xbd@\x00\x00\u07d49A2`\x0fAU\xe0\u007fME\xbc>\xb8\xd9\xfbr\xdc\u05c4\x89\x9fn\x92\xed\xea\a\xd4\x00\x00\u07d49Q\xe4\x8e<\x86\x9ekr\xa1C\xb6\xa4Ph\u0379\xd4f\u0409\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x949T\xbd\xfe\v\xf5\x87\u0195\xa3\x05\xd9$L=[\xdd\xda\u027b\x8a\x04\x10'\x83'\xf9\x85`\x80\x00\u07d49]m%U \xa8\xdb)\xab\xc4}\x83\xa5\u06ca\x1a}\xf0\x87\x89\x05k\xc7^-c\x10\x00\x00\u07d49ck%\x81\x1b\x17j\xbf\xcf\xee\xcad\xbc\x87E/\x1f\xdf\xf4\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d49i\xb4\xf7\x1b\xb8u\x1e\xdeC\xc0\x166:zaOv\x11\x8e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x949x/\xfe\x06\xacx\x82*<:\x8a\xfe0^P\xa5a\x88\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d49zn\xf8v:\x18\xf0\x0f\xac!~\x05\\\r0\x94\x10\x10\x11\x89lk\x93[\x8b\xbd@\x00\x00\u07d49|\u06cc\x80\xc6yP\xb1\x8deB)a\x0e\x93\xbf\xa6\xee\x1a\x89?\x95\xc8\xe0\x82\x15!\x00\x00\u07d49\x82O\x8b\xce\xd1v\xfd>\xa2.\u01a4\x93\xd0\xcc\xc3?\xc1G\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d49\x93l'\x19E\v\x94 \xcc%\"\u03d1\xdb\x01\xf2'\xc1\xc1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d49\x95\xe0\x96\xb0\x8aZrh\x00\xfc\xd1}\x9cd\xc6N\b\x8d+\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d49\x9a\xa6\xf5\xd0x\xcb\tp\x88+\u0259 \x06\xf8\xfb\xdf4q\x8965\u026d\xc5\u07a0\x00\x00\u07d49\xaa\x05\xe5m}28T!\u03d36\xe9\r=\x15\xa9\xf8Y\x89\x01h\u048e?\x00(\x00\x00\u07d49\xaa\xf0\x85M\xb6\xeb9\xbc{.C\x84jv\x17\x1c\x04E\u0789dI\xe8NG\xa8\xa8\x00\x00\u07d49\xb1\xc4q\xae\x94\xe1!dE.\x81\x1f\xbb\xe2\xb3\xcdru\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d49\xb2\x992t\x90\xd7/\x9a\x9e\xdf\xf1\x1b\x83\xaf\xd0\xe9\xd3\xc4P\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d49\xba\u018d\x94xY\xf5\x9e\x92&\b\x9c\x96\xd6.\x9f\xbe<\u0789\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x949\xbf\xd9xh\x9b\xec\x04\x8f\xc7v\xaa\x15$\u007f^\x1d|9\xa2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d49\xc7s6|\x88%\xd3YlhoB\xbf\r\x141\x9e?\x84\x89\a?u\u0460\x85\xba\x00\x00\u07d49\u05291@,\fy\xc4W\x18o$\u07c7)\u03d5p1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d49\xd6\xca\xca\"\xbc\xcdjr\xf8~\xe7\u05b5\x9e\v\xde!\xd7\x19\x89l\x87T\xc8\xf3\f\b\x00\x00\u07d49\xe0\xdbM`V\x8c\x80\v\x8cU\x00\x02l%\x94\xf5v\x89`\x8965\u026d\xc5\u07a0\x00\x00\xe0\x949\xeeO\xe0\x0f\xbc\xeddph\xd4\xf5|\x01\xcb\"\xa8\v\xcc\u044a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d49\xf1\x983\x1eK!\xc1\xb7`\xa3\x15_J\xb2\xfe\x00\xa7F\x19\x89lk\x93[\x8b\xbd@\x00\x00\u07d49\xf4Fc\xd9%a\t\x1b\x82\xa7\r\xcfY=u@\x05\x97:\x89\n\u05cb.\xdc!Y\x80\x00\u07d4:\x03U\x94\xc7GGmB\xd1\xee\x96l6\"L\xdd\"I\x93\x89\x13J\xf7Ei\xf9\xc5\x00\x00\u07d4:\x04W(G\xd3\x1e\x81\xf7v\\\xa5\xbf\xc9\xd5W\x15\x9f6\x83\x89\a6-\r\xab\xea\xfd\x80\x00\xe0\x94:\x06\xe3\xbb\x1e\xdc\xfd\fD\xc3\aM\xe0\xbb`k\x04\x98\x94\xa2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794:\x10\x88\x8b~\x14\x9c\xae',\x010,2}\n\xf0\x1a\v$\x88\xeb\xec!\xee\x1d\xa4\x00\x00\u07d4:1\b\xc1\u6023;3l!\x13\x134@\x9d\x97\xe5\xad\xec\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4:6\x8e\xfeJ\u05c6\xe2c\x95\xec\x9f\u01adi\x8c\xae)\xfe\x01\x89\"E\x89\x96u\xf9\xf4\x00\x00\u07d4:=\xd1\x04\xcd~\xb0O!\x93/\xd43\xeaz\xff\u04d3i\xf5\x89\x13aO#\xe2B&\x00\x00\u07d4:B\x97\xda\xc4.\x1eO\xb8\xcb1\xec\xddC\xaew<\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94:\x99`&m\xf6I cS\x8a\x99\xf4\x87\xc9P\xa3\xa5\uc78a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4:\x9b\x11\x10)\xce\x1f \xc9\x10\x9czt\xee\xee\xf3OO.\xb2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4:\x9eTA\xd4K$;\xe5[u\x02z\x1c\ub7ac\xf5\r\xf2\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94:\xa0z4\xa1\xaf\u0216}=\x13\x83\xb9kb\u03d6\xd5\xfa\x90\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94:\xa4,!\xb9\xb3\x1c>'\xcc\xd1~\t\x9a\xf6y\xcd\xf5i\a\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4:\xa9H\xea\x029wU\xef\xfb/\x9d\xc99-\xf1\x05\x8f~3\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4:\xad\xf9\x8ba\xe5\u0216\xe7\xd1\x00\xa39\x1d2P\"]a\u07c9\f\xafg\x007\x01h\x00\x00\u07d4:\xaeHr\xfd\x90\x93\xcb\xca\xd1@o\x1e\x80x\xba\xb5\x03Y\xe2\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4:\xbb\x8a\xdf\xc6\x04\xf4\x8dY\x84\x81\x1d\u007f\x1dR\xfe\xf6u\x82p\x89\xf2\x97\x19\xb6o\x11\f\x00\x00\u07d4:\xc2\xf0\xff\x16\x12\xe4\xa1\xc3F\xd53\x82\xab\xf6\u0622[\xaaS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4:\xc9\xdczCj\xe9\x8f\xd0\x1cz\x96!\xaa\x8e\x9d\v\x8bS\x1d\x89a\t=|,m8\x00\x00\xe0\x94:\xd0aI\xb2\x1cU\xff\x86|\xc3\xfb\x97@\u04bc\xc7\x10\x121\x8a)\xb7d2\xb9DQ \x00\x00\u07d4:\xd7\x02C\u060b\xf0@\x0fW\xc8\xc1\xfdW\x81\x18H\xaf\x16*\x89.\x9e\xe5\u00c6S\xf0\x00\x00\u07d4:\xd9\x15\xd5P\xb7#AV \xf5\xa9\xb5\xb8\x8a\x85\xf3\x82\xf05\x8965\u026d\xc5\u07a0\x00\x00\u07d4:\xe1`\xe3\xcd`\xae1\xb9\xd6t-h\xe1Nv\xbd\x96\xc5\x17\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4:\xe6+\xd2q\xa7`c\u007f\xady\xc3\x1c\x94\xffb\xb4\xcd\x12\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4:\xeaN\x82\xd2@\x02H\xf9\x98q\xa4\x1c\xa2W\x06\r:\"\x1b\x8965\u026d\xc5\u07a0\x00\x00\u07d4:\xf6[>(\x89ZJ\x00\x11S9\x1d\x1ei\xc3\x1f\xb9\xdb9\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4;\a\xdbZ5\u007fZ\xf2HL\xbc\x9dw\xd7;\x1f\xd0Q\x9f\u01c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4;\n\u032fK`|\xfea\xd1s4\xc2\x14\xb7\\\xde\xfd\xbd\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\x13c\x1a\x1b\x89\xcbVeH\x89\x9a\x1d`\x91\\\xdc\xc4 [\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\x15\x90\x99\aR\a\u0180vc\xb1\xf0\xf7\xed\xa5J\xc8\xcc\xe3\x89j\xc4\xe6[i\xf9-\x80\x00\u07d4;\x197\xd5\u74f8\x9bc\xfb\x8e\xb5\xf1\xb1\xc9\xcak\xa0\xfa\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\"\xda*\x02q\xc8\xef\xe1\x02S'scji\xb1\xc1~\t\x89\x1b6\xa6DJ>\x18\x00\x00\u07d4;\"\u07a3\xc2_\x1bY\u01fd'\xbb\x91\u04e3\xea\xec\xef9\x84\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94;#g\xf8IK_\xe1\x8dh<\x05]\x89\x99\x9c\x9f=\x1b4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4;,E\x99\x0e!GDQ\xcfOY\xf0\x19U\xb31\xc7\xd7\u0249lk\x93[\x8b\xbd@\x00\x00\xe0\x94;A\x00\xe3\ns\xb0\xc74\xb1\x8f\xfa\x84&\u045b\x191/\x1a\x8a\v\xb5\u046ap\n\xfd\x90\x00\x00\u07d4;B\xa6m\x97\x9fX(4tz\x8b`B\x8e\x9bN\xec\xcd#\x89!\xa1\u01d0\xfa\xdcX\x00\x00\u07d4;Gh\xfdq\xe2\xdb,\xbe\u007f\xa0PH<'\xb4\xeb\x93\x1d\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;Vj\x8a\xfa\u0456\x82\xdc,\xe8g\x9a<\xe4D\xa5\xb0\xfdO\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94;\\%\x1d\u007f\u05c9;\xa2\t\xfeT\x1c\xec\xd0\xce%:\x99\r\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4;^\x8b\x17w\xca\x18A\x896\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94;\x93\xb1a6\xf1\x1e\xaf\x10\x99l\x95\x99\r;'9\xcc\xea_\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4;\xabK\x01\xa7\xc8K\xa1?\uea70\xbb\x19\x1bw\xa3\xaa\u0723\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4;\xb55\x98\xcc \xe2\x05]\xc5S\xb0I@J\u0277\xdd\x1e\x83\x89!W\x1d\xf7|\x00\xbe\x00\x00\u07d4;\xbc\x13\xd0J\xcc\xc0pz\xeb\u072e\xf0\x87\u0438~\v^\u327e\xd1\xd0&=\x9f\x00\x00\x00\u07d4;\xc6\xe3\xeezV\u038f\x14\xa3u2Y\x0fcqk\x99f\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\xc8]ls[\x9c\xdaK\xba_H\xb2K\x13\xe7\x0600{\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4;\xd6$\xb5H\xcbe\x976\x90~\u062a<\fp^$\xb5u\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\u0660m\x1b\xd3lN\xdd'\xfc\r\x1f[\b\x8d\xda\xe3\xc7*\x89\x1b\x1azB\v\xa0\r\x00\x00\u0794;\u077c\x814\xf7}UY\u007f\xc9|&\xd2f\x98\t\x06\x04\ub23e -j\x0e\xda\x00\x00\xe0\x94;\xf8n\u0623\x15>\xc93xj\x02\xac\t\x03\x01\x85^Wk\x8a_J\x8c\x83u\xd1U@\x00\x00\u07d4;\xfb\u04c4|\x17\xa6\x1c\xf3\xf1{R\xf8\ub879`\xb3\U000df262\xa1]\tQ\x9b\xe0\x00\x00\u07d4<\x03\xbb\xc0#\xe1\xe9?\xa3\xa3\xa6\xe4(\xcf\f\xd8\xf9^\x1e\u0189Rf<\u02b1\xe1\xc0\x00\x00\u07d4<\f=\ufb1c\xeaz\xcc1\x9a\x96\xc3\v\x8e\x1f\xed\xabEt\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4<\x15\xb3Q\x1d\xf6\xf04.sH\u0309\xaf9\xa1h\xb7s\x0f\x8965\u026d\xc5\u07a0\x00\x00\u07d4<\x1f\x91\xf3\x01\xf4\xb5e\xbc\xa2GQ\xaa\x1fv\x13\"p\x9d\u0749a\t=|,m8\x00\x00\xe0\x94<(l\xfb0\x14n_\u05d0\xc2\xc8T\x15RW\x8d\xe34\u060a\x02)\x1b\x11\xaa0n\x8c\x00\x00\u07d4<2.a\x1f\u06c2\rG\xc6\xf8\xfcd\xb6\xfa\xd7L\xa9_^\x89\r%\x8e\xce\x1b\x13\x15\x00\x00\u07d4\xa5\xe5\xbfb\xbb\u0309\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4<\x86\x9c\tie#\xce\xd8$\xa0pAF\x05\xbbv#\x1f\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4<\x92V\x19\u02731DF?\x057\u06165\x87\x06\xc5 \xb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\x98YK\xf6\x8bW5\x1e\x88\x14\xae\x9em\xfd-%J\xa0o\x89\x10CV\x1a\x88)0\x00\x00\u07d4<\xad\xeb=>\xed?b1\x1dRU>p\xdfJ\xfc\xe5o#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94<\xae\xdbS\x19\xfe\x80eC\xc5nP!\xd3r\xf7\x1b\xe9\x06.\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4<\xaf\xaf^bPV\x15\x06\x8a\xf8\xeb\"\xa1:\u0629\xe5Pp\x89lf\x06E\xaaG\x18\x00\x00\u07d4<\xb1y\xcbH\x01\xa9\x9b\x95\u00f0\xc3$\xa2\xbd\xc1\x01\xa6S`\x89\x01h\u048e?\x00(\x00\x00\u07d4<\xb5a\u0386BK5\x98\x91\xe3d\xec\x92_\xfe\xff'}\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xcbq\xaah\x80\xcb\v\x84\x01-\x90\xe6\a@\xec\x06\xac\u05cf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\xce\xf8\x86yW9G\xe9I\x97y\x8a\x1e2~\b`:e\x89+\xc9\x16\u059f;\x02\x00\x00\xe0\x94<\xd1\xd9s\x1b\xd5H\xc1\xddo\u03a6\x1b\xebu\xd9\x17T\xf7\u04ca\x01\x16\x1d\x01\xb2\x15\xca\xe4\x80\x00\u07d4<\u04e6\xe95y\xc5mIAq\xfcS>z\x90\xe6\xf5\x94d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\u05b7Y<\xbe\xe7x0\xa8\xb1\x9d\b\x01\x95\x8f\xcdK\xc5z\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4<\xd7\xf7\xc7\xc257\x80\xcd\xe0\x81\xee\xecE\x82+%\xf2\x86\f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xe1\u0717\xfc\u05f7\xc4\u04e1\x8aI\xd6\xf2\xa5\xc1\xb1\xa9\x06\u05c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xea0*G*\x94\x03y\xdd9\x8a$\xea\xfd\xba\u07c8\xady\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94<\xec\xa9k\xb1\xcd\xc2\x14\x02\x9c\xbc^\x18\x1d9\x8a\xb9M=A\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4<\xf4\x84RO\xbd\xfa\xda\xe2m\xc1\x85\xe3++c\x0f\xd2\xe7&\x89\x18TR\xcb*\x91\xc3\x00\x00\u07d4<\xf9\xa1\xd4e\xe7\x8bp9\xe3iDx\xe2b{6\xfc\xd1A\x89J`S*\xd5\x1b\xf0\x00\x00\u07d4<\xfb\xf0fVYpc\x9e\x13\r\xf2\xa7\xd1k\x0e\x14\xd6\t\x1c\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94=\th\x8d\x93\xad\a\xf3\xab\xe6\x8cr'#\xcdh\t\x90C^\x8a\x06ZL\xe9\x9fv\x9en\x00\x00\u07d4=1X{_\u0546\x98Ex\x87%\xa6c)\nI\xd3g\x8c\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4=?\xadI\xc9\xe5\xd2u\x9c\x8e\x8eZzM`\xa0\xdd\x13V\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4=WO\xcf\x00\xfa\xe1\u064c\u023f\x9d\u07e1\xb3\x95;\x97A\xbc\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4=Z\x8b+\x80\xbe\x8b5\xd8\xec\xf7\x89\xb5\xedz\au\xc5\al\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4=f\xcdK\xd6M\\\x8c\x1b^\xea(\x1e\x10m\x1cZ\xad#s\x89i\xc4\xf3\xa8\xa1\x10\xa6\x00\x00\u0794=j\xe0S\xfc\xbc1\x8do\xd0\xfb\xc3S\xb8\xbfT.h\r'\x88\xc6s\xce<@\x16\x00\x00\u07d4=o\xf8,\x93w\x05\x9f\xb3\r\x92\x15r?`\xc7u\u0211\xfe\x89\r\x8e\\\xe6\x17\xf2\xd5\x00\x00\u07d4=y\xa8S\xd7\x1b\xe0b\x1bD\xe2\x97Yel\xa0u\xfd\xf4\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4=~\xa5\xbf\x03R\x81\x00\xed\x8a\xf8\xae\xd2e>\x92\x1bng%\x8965\u026d\xc5\u07a0\x00\x00\u07d4=\x81?\xf2\xb6\xedW\xb97\u06bf+8\x1d\x14\x8aA\x1f\xa0\x85\x89\x05k\xc7^-c\x10\x00\x00\u07d4=\x88\x143\xf0J}\r'\xf8ID\xe0\x8aQ-\xa3UR\x87\x89A\rXj \xa4\xc0\x00\x00\u07d4=\x89\xe5\x05\xcbF\xe2\x11\xa5?2\xf1g\xa8w\xbe\xc8\u007fK\n\x89\x01[5W\xf1\x93\u007f\x80\x00\xe0\x94=\x8d\a#r\x1es\xa6\xc0\xd8`\xaa\x05W\xab\xd1L\x1e\xe3b\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4=\x8f9\x88\x1b\x9e\xdf\xe9\x12'\xc3?\xa4\xcd\xd9\x1eg\x85D\xb0\x89\x04\xab\a\xbaC\xad\xa9\x80\x00\u07d4=\x9dk\xe5\u007f\xf8>\x06Y\x85fO\x12VD\x83\xf2\xe6\x00\xb2\x89n\xac\xe4?#\xbd\x80\x00\x00\u07d4=\xa3\x9c\xe3\xefJz9f\xb3.\xe7\xeaN\xbc#5\xa8\xf1\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4=\xaa\x01\u03b7\x0e\xaf\x95\x91\xfaR\x1b\xa4\xa2~\xa9\xfb\x8e\xdeJ\x89Zc\xd2\u027cvT\x00\x00\u07d4=\xb5\xfejh\xbd6\x12\xac\x15\xa9\x9aa\xe5U\x92\x8e\xec\xea\xf3\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4=\xb9\xed\u007f\x02L~&7/\xea\xcf+\x05\b\x03D^8\x10\x89E\xb1H\xb4\x99j0\x00\x00\u07d4=\xbf\r\xbf\xd7x\x90\x80\x053\xf0\x9d\xea\x83\x01\xb9\xf0%\u04a6\x8965\u026d\xc5\u07a0\x00\x00\u07d4=\xce\U0005c18b\x15\xd3N\xdaBn\xc7\xe0K\x18\xb6\x01p\x02\x89lh\xcc\u041b\x02,\x00\x00\xe0\x94=\xd1.Uj`76\xfe\xbaJo\xa8\xbdJ\xc4]f*\x04\x8a#u{\x91\x83\xe0x(\x00\x00\u07d4=\u078b\x15\xb3\u033a\xa5x\x01\x12\xc3\xd6t\xf3\x13\xbb\xa6\x80&\x89`\x1dQZ>O\x94\x00\x00\xe0\x94=\xde\xdb\xe4\x89#\xfb\xf9\xe56\xbf\x9f\xfb\aG\xc9\xcd\u04de\xef\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4=\xea\xe43'\x91?b\x80\x8f\xaa\x1bbv\xa2\xbdch\xea\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4=\xf7b\x04\x9e\u068a\u0192}\x90Lz\xf4/\x94\xe5Q\x96\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>\x04\r@\u02c0\xba\x01%\xf3\xb1_\xde\xfc\xc8?0\x05\xda\x1b\x898E$\xccp\xb7x\x00\x00\u07d4>\v\x8e\xd8n\xd6i\xe1'#\xafur\xfb\xac\xfe\x82\x9b\x1e\x16\x89QM\xe7\xf9\xb8\x12\xdc\x00\x00\xe0\x94>\f\xbejm\xcba\xf1\x10\xc4[\xa2\xaa6\x1d\u007f\xca\xd3\xdas\x8a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4>\x19KN\xce\xf8\xbbq\x1e\xa2\xff$\xfe\xc4\xe8{\xd02\xf7\u0449\x8b\x9d\xc1\xbc\x1a\x03j\x80\x00\xe0\x94>\x1b\"0\xaf\xbb\xd3\x10\xb4\x92jLwmZ\u705cf\x1d\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4>\x1cS0\x0eL\x16\x89\x12\x16<~\x99\xb9]\xa2h\xad(\n\x896b2\\\u044f\xe0\x00\x00\u07d4>\x1c\x96 c\xe0\xd5)YA\xf2\x10\u0723\xabS\x1e\xec\x88\t\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4>,\xa0\xd24\xba\xf6\a\xadFj\x1b\x85\xf4\xa6H\x8e\xf0\n\xe7\x89\x04\xda!\xa3H=V\x80\x00\u07d4>/&#^\x13zs$\xe4\xdc\x15K]\xf5\xafF\xea\x1aI\x89\x017\xaa\xd8\x03-\xb9\x00\x00\xe0\x94>1a\xf1\xea/\xbf\x12ny\xda\x18\x01\u0695\x12\xb3y\x88\u024a\nm\xd9\f\xaeQ\x14H\x00\x00\xe0\x94>6\xc1rS\xc1\x1c\xf3\x89t\xed\r\xb1\xb7Y\x16\r\xa67\x83\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4><\u04fe\xc0e\x91\xd64o%Kb\x1e\xb4\x1c\x89\x00\x8d1\x895\u07fe\u069f74\x00\x00\u07d4>E\xbdU\u06d0`\xec\xed\x92;\xb9\xcbs<\xb3W?\xb51\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4>M\x13\xc5Z\x84\xe4n\xd7\xe9\u02d0\xfd5^\x8a\u0651\u33c965\u026d\xc5\u07a0\x00\x00\u07d4>N\x92e\"<\x9782L\xf2\v\xd0`\x06\xd0\a>\u06cc\x89\a?u\u0460\x85\xba\x00\x00\xe0\x94>O\xbdf\x10\x15\xf6F\x1e\xd6s\\\xef\xef\x01\xf3\x14E\xde:\x8a\x03n4)\x98\xb8\xb0 \x00\x00\xe0\x94>S\xff!\a\xa8\u07be3(I:\x92\xa5\x86\xa7\xe1\xf4\x97X\x8a\x04\xe6\x9c*q\xa4\x05\xab\x00\x00\u07d4>Z9\xfd\xdap\xdf\x11&\xab\r\u011asx1\x1aSz\x1f\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\xe0\x94>Z\xbd\t\xceZ\xf7\xba\x84\x87\xc3Y\xe0\xf2\xa9:\x98k\v\x18\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4>\\\xb8\x92\x8cAx%\xc0:;\xfc\xc5!\x83\xe5\xc9\x1eB\u05c9\xe71\xd9\xc5,\x96/\x00\x00\u07d4>^\x93\xfbL\x9c\x9d\x12F\xf8\xf2G5\x8e\"\xc3\xc5\xd1{j\x89\b!\xab\rD\x14\x98\x00\x00\u07d4>a\x83P\xfa\x01ez\xb0\xef>\xba\xc8\xe3p\x12\xf8\xfc+o\x89\x98\x06\xde=\xa6\xe9x\x00\x00\u07d4>c\xce;$\xca(e\xb4\u0166\x87\xb7\xae\xa3Y~\xf6\xe5H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>f\xb8GiVj\xb6yE\xd5\xfa\x8175V\xbc\u00e1\xfa\x89\b=lz\xabc`\x00\x00\xe0\x94>v\xa6-\xb1\x87\xaat\xf68\x17S;0l\xea\xd0\xe8\u03be\x8a\x06\x9bZ\xfa\xc7P\xbb\x80\x00\x00\u07d4>z\x96k]\xc3W\xff\xb0~\x9f\xe0g\xc4W\x91\xfd\x8e0I\x89\x034-`\xdf\xf1\x96\x00\x00\xe0\x94>\x81w!u#~\xb4\xcb\xe0\xfe-\xca\xfd\xad\xff\xebj\x19\x99\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4>\x83I\xb6\u007fWED\x9fe\x93g\u066dG\x12\xdb[\x89Z\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4>\x83TO\x00\x82U%r\u01c2\xbe\xe5\xd2\x18\xf1\xef\x06J\x9d\x89\x05l\xd5_\xc6M\xfe\x00\x00\u07d4>\x84\xb3\\[\"ePpa\xd3\vo\x12\xda\x03?\xe6\xf8\xb9\x89a\t=|,m8\x00\x00\u07d4>\x86A\xd4\x87E\xba2/_\xd6\xcbP\x12N\xc4f\x88\u01e6\x9a\u007f\xae\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4>\x91N0\x18\xac\x00D\x93A\u011d\xa7\x1d\x04\xdf\xee\xedb!\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4>\x94\x10\u04f9\xa8~\xd5\xe4Q\xa6\xb9\x1b\xb8\x92?\xe9\x0f\xb2\xb5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4>\x94\xdfS\x13\xfaR\x05p\xef#+\xc31\x1d_b/\xf1\x83\x89lk\x93[\x8b\xbd@\x00\x00\u0794>\x9b4\xa5\u007f3u\xaeY\xc0\xa7^\x19\u0136A\"\x8d\x97\x00\x88\xf8i\x93)g~\x00\x00\u07d4>\xad\xa8\xc9/V\x06~\x1b\xb7<\xe3x\xdaV\xdc,\xdf\xd3e\x89w\xcd\xe9:\xeb\rH\x00\x00\xe0\x94>\xaf\by\xb5\xb6\xdb\x15\x9bX\x9f\x84W\x8bjt\xf6\xc1\x03W\x8a\x01\x898\xb6q\xfae\xa2\x80\x00\u07d4>\xaf1k\x87a]\x88\xf7\xad\xc7|X\xe7\x12\xedMw\x96k\x89\x05m\xbcL\xee$d\x80\x00\u07d4>\xb8\xb3;!\xd2<\u0686\xd8(\x88\x84\xabG\x0e\x16F\x91\xb5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4>\xb9\xef\x06\xd0\xc2Y\x04\x03\x19\x94~\x8czh\x12\xaa\x02S\u0609\t\r\x97/22<\x00\x00\u07d4>\u030e\x16h\xdd\xe9\x95\xdcW\x0f\xe4\x14\xf4B\x11\xc54\xa6\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>\u03752\xe3\x97W\x96b\xb2\xa4aA\u73c25\x93j_\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4>\xeeo\x1e\x966\vv\x89\xb3\x06\x9a\xda\xf9\xaf\x8e\xb6\f\u404965\u026d\xc5\u07a0\x00\x00\xe0\x94?\b\u066d\x89O\x81>\x8e!H\xc1`\xd2K5:\x8et\xb0\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4?\f\x83\xaa\xc5qybsN\\\xea\xea\xec\u04db(\xad\x06\xbe\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94?\x10\x80\x02\x82\u0477\xdd\u01cf\xa9-\x820\aN\x1b\xf6\xae\xae\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4?\x123qO M\xe9\xdeN\xe9m\a;6\x8d\x81\x97\x98\x9f\x89\x02\x17\xc4\x10t\xe6\xbb\x00\x00\u07d4?\x17:\xa6\xed\xf4i\u0445\xe5\x9b\xd2j\xe4#k\x92\xb4\xd8\xe1\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4?\x1b\xc4 \xc5<\x00,\x9e\x90\x03|D\xfej\x8e\xf4\xdd\xc9b\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4?#a\b\xee\xc7\"\x89\xba\u00e6\\\u0483\xf9^\x04\x1d\x14L\x8964\xbf9\xab\x98x\x80\x00\u07d4?-\xa0\x93\xbb\x16\xeb\x06O\x8b\xfa\x9e0\xb9)\xd1_\x8e\x1cL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?-\xd5]\xb7\xea\xb0\xeb\xeee\xb3>\xd8 ,\x1e\x99.\x95\x8b\x89,s\xc97t,P\x00\x00\u07d4?/8\x14\x91y|\xc5\xc0\u0502\x96\xc1O\xd0\xcd\x00\xcd\xfa-\x89+\x95\xbd\xcc9\xb6\x10\x00\x00\u07d4?0\u04fc\x9f`\"2\xbcrB\x88\xcaF\xcd\v\a\x88\xf7\x15\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4?<\x8ea\xe5`L\xef\x06\x05\xd46\xdd\"\xac\u0346\"\x17\xfc\x89Hz\x9a0E9D\x00\x00\u07d4??F\xb7\\\xab\xe3{\xfa\u0307`(\x1fCA\xca\u007fF=\x89 \xacD\x825\xfa\xe8\x80\x00\u07d4?G)c\x19x\x83\xbb\xdaZ\x9b}\xfc\xb2-\xb1\x14@\xad1\x89\x1a\x19d<\xb1\xef\xf0\x80\x00\u07d4?L\xd19\x9f\x8a4\xed\u06da\x17\xa4q\xfc\x92+Xp\xaa\xfc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4?U\x1b\xa9<\xd5F\x93\xc1\x83\xfb\x9a\xd6\re\xe1`\x96s\u0249lk\x93[\x8b\xbd@\x00\x00\xe0\x94?bzv\x9ej\x95\x0e\xb8p\x17\xa7\u035c\xa2\bq\x13h1\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4?m\xd3e\x0e\xe4(\u0737u\x95S\xb0\x17\xa9j\x94(j\u0249Hz\x9a0E9D\x00\x00\u07d4?tr7\x80o\xed?\x82\x8ahR\xeb\bg\xf7\x90'\xaf\x89\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4?u\xaea\xcc\x1d\x80Be;[\xae\xc4D>\x05\x1c^z\xbd\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4?\xb7\u0457\xb3\xbaO\xe0E\xef\xc2=P\xa1E\x85\xf5X\u0672\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94?\xbc\x1eE\x18\xd74\x00\xc6\xd0F5\x949\xfbh\xea\x1aI\xf4\x8a\x03y\v\xb8U\x13v@\x00\x00\u07d4?\xbe\xd6\xe7\xe0\u029c\x84\xfb\xe9\xeb\u03ddN\xf9\xbbIB\x81e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?\u043bGy\x8c\xf4L\u07feM3=\xe67\xdfJ\x00\xe4\\\x89\x05lUy\xf7\"\x14\x00\x00\xe0\x94?\xe4\x0f\xbd\x91\x9a\xad(\x18\xdf\x01\xeeM\xf4lF\x84*\xc59\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4?\xe8\x01\xe6\x135\xc5\x14\r\xc7\xed\xa2\xefR\x04F\nP\x120\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?\xf86\xb6\xf5{\x90\x1bD\f0\xe4\xdb\xd0e\xcf7\xd3\u050c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4?\xfc\xb8p\xd4\x02=%]Qg\u0625\a\xce\xfc6kh\xba\x89#4^\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4@s\xfaI\xb8q\x17\u02d0\x8c\xf1\xabQ-\xa7T\xa92\xd4w\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4@\x8ai\xa4\a\x15\xe1\xb3\x13\xe15N`\b\x00\xa1\xe6\xdc\x02\xa5\x89\x01\u7e11\u0312T\x00\x00\u07d4@\x9b\xd7P\x85\x82\x1c\x1d\xe7\f\xdc;\x11\xff\xc3\xd9#\xc7@\x10\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4@\x9dZ\x96.\xde\uefa1x\x01\x8c\x0f8\xb9\u0372\x13\xf2\x89\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4@\xa31\x19[\x97s%\u00aa(\xfa/B\xcb%\xec<%<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4@\xa7\xf7(g\xa7\u0706w\v\x16+uW\xa44\xedP\xcc\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d4@\xab\n>\x83\xd0\u022c\x93f\x91\x05 \xea\xb1w+\xac;\x1a\x894\xf1\f-\xc0^|\x00\x00\u07d4@\xabf\xfe!>\xa5l:\xfb\x12\xc7[\xe3?\x8e2\xfd\b]\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94@\xadt\xbc\v\xce*E\xe5/6\xc3\u07bb\x1b:\xda\x1bv\x19\x8a\x01p\x16-\xe1\t\xc6X\x00\x00\u07d4@\u03c9\x05\x91\xea\u484f\x81*)T\xcb)_c3'\xe6\x89\x02\x9b\xf76\xfcY\x1a\x00\x00\u07d4@\u03d0\xef[v\x8c]\xa5\x85\x00,\xcb\xe6avP\xd8\xe87\x8963\x03\"\xd5#\x8c\x00\x00\xe0\x94@\xd4]\x9dv%\xd1QV\xc92\xb7q\xca{\x05'\x13\tX\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4@\xdb\x1b\xa5\x85\xce4S\x1e\xde\xc5IHI9\x13\x81\xe6\xcc\u04c9a\t=|,m8\x00\x00\xe0\x94@\xdfI^\xcf?\x8bL\xef*l\x18\x99W$\x8f\u813c+\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4@\xe0\xdb\xf3\xef\uf404\xea\x1c\xd7\xe5\x03\xf4\v;J\x84C\xf6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4@\xe2D\n\xe1B\u02006j\x12\xc6\xd4\x10/K\x844\xb6*\x8965\u026d\xc5\u07a0\x00\x00\u07d4@\xe3\u0083\xf7\xe2M\xe0A\f\x12\x1b\xee`\xa5`\u007f>)\xa6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94@\xeaPD\xb2\x04\xb20v\xb1\xa5\x80;\xf1\xd3\f\x0f\x88\x87\x1a\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94@\xed\xdbD\x8di\x0e\xd7.\x05\xc2%\xd3O\xc85\x0f\xa1\xe4\u014a\x01{x\x83\xc0i\x16`\x00\x00\xe0\x94@\xf4\xf4\xc0ls,\xd3[\x11\x9b\x89;\x12~}\x9d\aq\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4A\x01\x0f\u023a\xf8C}\x17\xa0Ci\x80\x9a\x16\x8a\x17\xcaV\xfb\x89\x05k\xc7^-c\x10\x00\x00\u07d4A\x03)\x96q\xd4gc\x97\x8f\xa4\xaa\x19\xee4\xb1\xfc\x95'\x84\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4A\x03<\x1bm\x05\xe1\u0289\xb0\x94\x8f\xc6DS\xfb\xe8z\xb2^\x89Hz\x9a0E9D\x00\x00\u07d4A\t\x8a\x81E#\x17\xc1\x9e>\xef\v\xd1#\xbb\xe1x\xe9\xe9\u0289\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4A\x16\x10\xb1x\xd5a}\xfa\xb94\u0493\xf5\x12\xa9>\\\x10\xe1\x89\t79SM(h\x00\x00\u07d4A\x1c\x83\x1c\xc6\xf4O\x19e\xecWW\xabN[<\xa4\xcf\xfd\x1f\x89\x17\n\x0fP@\xe5\x04\x00\x00\xe0\x94A*h\xf6\xc6EU\x9c\xc9w\xfcId\x04z \x1d\x1b\xb0\xe2\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4A?K\x02f\x9c\xcf\xf6\x80k\xc8&\xfc\xb7\xde\xca;\x0e\xa9\xbc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4AE\x99\t.\x87\x9a\xe2Sr\xa8MsZ\xf5\xc4\xe5\x10\xcdm\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4AHV\x12\xd04F\xecL\x05\xe5$NV?\x1c\xba\xe0\xf1\x97\x894\x95tD\xb8@\xe8\x00\x00\u07d4A]\tj\xb0b\x93\x18?<\x03=%\xf6\xcfqx\xac;\u01c9\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4Af\xfc\b\u0285\xf7f\xfd\xe81F\x0e\x9d\xc9<\x0e!\xaal\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Ag\x84\xaf`\x960\xb0p\u051a\x8b\xcd\x12#\\d(\xa4\b\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Ag\xcdH\xe73A\x8e\x8f\x99\xff\xd14\x12\x1cJJ\xb2x\u0109\xc5S%\xcat\x15\xe0\x00\x00\u07d4Al\x86\xb7 \x83\xd1\xf8\x90}\x84\xef\xd2\xd2\u05c3\xdf\xfa>\xfb\x89lj\xccg\u05f1\xd4\x00\x00\u07d4AsA\x9d\\\x9fc)U\x1d\xc4\xd3\xd0\u03ac\x1bp\x1b\x86\x9e\x89\x04\xc5>\xcd\xc1\x8a`\x00\x00\u07d4At\xfa\x1b\xc1*;q\x83\u02eb\xb7z\vYU{\xa5\xf1\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4Axj\x10\xd4G\xf4\x84\xd32D\u0337\xfa\u034bB{[\x8c\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Az<\u0454\x96S\nmB\x04\u00f5\xa1|\xe0\xf2\a\xb1\xa5\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4A~N&\x88\xb1\xfdf\xd8!R\x9eF\xedOB\xf8\xb3\xdb=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94A\x9aq\xa3l\x11\xd1\x05\xe0\xf2\xae\xf5\xa3\xe5\x98\a\x8e\x85\xc8\v\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94A\x9b\xdes\x16\xcc\x1e\u0495\u0205\xac\xe3B\u01db\xf7\xee3\xea\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4A\xa2\xf2\xe6\xec\xb8c\x94\xec\x0e3\x8c\x0f\xc9~\x9cU\x83\xde\u0489l\xee\x06\u077e\x15\xec\x00\x00\u07d4A\xa8\u0083\x00\x81\xb1\x02\xdfn\x011e|\a\xabc[T\u0389lj\xccg\u05f1\xd4\x00\x00\u07d4A\xa8\xe26\xa3\x0emc\xc1\xffdM\x13*\xa2\\\x89S~\x01\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4A\xa9\xa4\x04\xfc\x9f[\xfe\xe4\x8e\xc2e\xb1%#3\x8e)\xa8\xbf\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4A\xad6\x9fu\x8f\xef8\xa1\x9a\xa3\x14\x93y\x83,\x81\x8e\xf2\xa0\x8966\x9e\xd7t}&\x00\x00\u07d4A\xb2\xd3O\xde\v\x10)&+Ar\xc8\x1c\x15\x90@[\x03\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4A\xb2\xdb\u05dd\u069b\x86Ojp0'T\x19\u00dd>\xfd;\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4A\xc3\xc26u4\xd1;\xa2\xb3?\x18\\\xdb\xe6\xacC\xc2\xfa1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4A\u02d8\x96D_p\xa1\n\x14!R\x96\xda\xf6\x14\xe3,\xf4\u0549g\x8a\x93 b\xe4\x18\x00\x00\u07d4A\xcey\x95\t5\xcf\xf5[\xf7\x8eL\xce\xc2\xfec\x17\x85\u06d5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4A\u04f71\xa3&\xe7hX\xba\xa5\xf4\xbd\x89\xb5{6\x93#C\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\xe0\x94A\xe4\xa2\x02u\xe3\x9b\xdc\xef\xebe\\\x03\"tKvQ@\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4A\xed-\x8ep\x81H,\x91\x9f\xc2=\x8f\x00\x91\xb3\xc8,F\x85\x89F:\x1ev[\u05ca\x00\x00\xe0\x94A\xf2~tK\u049d\xe2\xb0Y\x8f\x02\xa0\xbb\x9f\x98\xe6\x81\ua90a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\u07d4A\xf4\x89\xa1\xect{\u009c>_\x9d\x8d\xb9xw\xd4\u0474\xe9\x89\a?u\u0460\x85\xba\x00\x00\u07d4B\x0f\xb8n}+Q@\x1f\xc5\xe8\xc7 \x15\xde\xcbN\xf8\xfc.\x8965\u026d\xc5\u07a0\x00\x00\u07d4B\x16\x84\xba\xa9\xc0\xb4\xb5\xf5S8\xe6\xf6\xe7\xc8\xe1F\xd4\x1c\xb7\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4B9\x96Y\xac\xa6\xa5\xa8c\xea\"E\xc93\xfe\x9a5\xb7\x88\x0e\x89n\xce2\xc2l\x82p\x00\x00\xe0\x94B;\xcaG\xab\xc0\fpW\xe3\xad4\xfc\xa6>7_\xbd\x8bJ\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4B<1\a\xf4\xba\xceANI\x9cd9\nQ\xf7F\x15\xca^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B<\xc4YL\xf4\xab\xb66\x8d\xe5\x9f\u04b1#\a4a!C\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94BD\xf13\x11X\xb9\xce&\xbb\xe0\xb9#k\x92\x03\xca5\x144\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794BQw\xebt\xad\n\x9d\x9aWR\"\x81G\xeemcV\xa6\u6239\x8b\xc8)\xa6\xf9\x00\x00\u07d4BW%\xc0\xf0\x8f\b\x11\xf5\xf0\x06\xee\xc9\x1c\\\\\x12k\x12\xae\x89\b!\xab\rD\x14\x98\x00\x00\xe0\x94BX\xfdf/\xc4\xce2\x95\xf0\xd4\xed\x8f{\xb1D\x96\x00\xa0\xa9\x8a\x01lE.\xd6\b\x8a\xd8\x00\x00\xe0\x94B\\\x18\x16\x86\x8fww\xcc+\xa6\xc6\u048c\x9e\x1eylR\xb3\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4B\\3\x8a\x13%\xe3\xa1W\x8e\xfa)\x9eW\u0646\xebGO\x81\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94BbY\xb0\xa7Vp\x1a\x8bf5(R!V\xc0(\x8f\x0f$\x8a\x02\x18\xae\x19k\x8dO0\x00\x00\u07d4Bm\x15\xf4\a\xa0\x115\xb1:kr\xf8\xf2R\v51\xe3\x02\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Box\xf7\r\xb2Y\xac\x854\x14[)4\xf4\xef\x10\x98\xb5\u0609\x13\x84\x00\xec\xa3d\xa0\x00\x00\u07d4Bs-\x8e\xf4\x9f\xfd\xa0K\x19x\x0f\xd3\xc1\x84i\xfb7A\x06\x89\x17\v\x00\xe5\u4a7e\x00\x00\u07d4Bt\x17\xbd\x16\xb1\xb3\xd2-\xbb\x90-\x8f\x96W\x01o$\xa6\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Btj\xee\xa1O'\xbe\xff\f\r\xa6BS\xf1\xe7\x97\x18\x90\xa0\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4B{F*\xb8NP\x91\xf4\x8aF\xeb\f\u0712\xdd\xcb&\xe0x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B~GQ\u00fa\xbex\xcf\xf8\x83\b\x86\xfe\xbc\x10\xf9\x90\x8dt\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94B~\xc6h\xac\x94\x04\xe8\x95\u0306\x15\x11\xd1b\nI\x12\xbe\x98\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4B\x80\xa5\x8f\x8b\xb1\v\x94@\u0794\xf4+OY! \x82\x01\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B\x8a\x1e\xe0\xed3\x1dyR\u033e\x1cyt\xb2\x85+\u0453\x8a\x89w\xb7JN\x8d\xe5e\x00\x00\u0794B\x9c\x06\xb4\x87\xe8Tj\xbd\xfc\x95\x8a%\xa3\xf0\xfb\xa5?o\x00\x88\xbbdJ\xf5B\x19\x80\x00\xe0\x94B\xa9\x8b\xf1`'\xceX\x9cN\xd2\xc9X1\xe2rB\x05\x06N\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4B\xc6\xed\xc5\x15\xd3UW\x80\x8d\x13\xcdD\xdc\xc4@\v%\x04\xe4\x89\n\xba\x14\u015b\xa72\x00\x00\u07d4B\xce\xcf\u0492\x10y\xc2\xd7\xdf?\b\xb0z\xa3\xbe\xee^!\x9a\x8965\u026d\xc5\u07a0\x00\x00\u07d4B\u04669\x9b0\x16\xa8Y\u007f\x8bd\t'\xb8\xaf\xbc\xe4\xb2\x15\x89\xa1\x8b\xce\xc3H\x88\x10\x00\x00\u07d4B\xd3I@\xed\xd2\xe7\x00]F\xe2\x18\x8eL\xfe\u0383\x11\xd7M\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4B\u04e5\xa9\x01\xf2\xf6\xbd\x93V\xf1\x12\xa7\x01\x80\xe5\xa1U\v`\x892$\xf4'#\xd4T\x00\x00\u07d4B\u05b2c\xd9\xe9\xf4\x11lA\x14$\xfc\x99Ux;\xa1\xc5\x1b\x81\x0f\xc4g\u057aM\xeaB\xf7\xa9\x88^i\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94C>\xb9J3\x90\x86\xed\x12\u067d\xe9\xcd\x1dE\x86\x03\xc9}\u058a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4CI\"Zb\xf7\n\xeaH\n\x02\x99\x15\xa0\x1eSy\xe6O\xa5\x89\x8c\xd6~#4\xc0\xd8\x00\x00\u07d4CT\"\x1eb\xdc\t\xe6@d6\x16:\x18^\xf0m\x11J\x81\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94CTC\xb8\x1d\xfd\xb9\xbd\x8cg\x87\xbc%\x18\xe2\xd4~W\xc1_\x8a\x01C\x8d\x93\x97\x88\x1e\xf2\x00\x00\u07d4Ca\u0504o\xaf\xb3w\xb6\xc0\xeeI\xa5\x96\xa7\x8d\xdf5\x16\xa3\x89\xc2\x12z\xf8X\xdap\x00\x00\xe0\x94Cd0\x9a\x9f\xa0p\x95`\x0fy\xed\xc6Q \xcd\xcd#\xdcd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Cg\xaeK\f\xe9d\xf4\xa5J\xfdK\\6\x84\x96\xdb\x16\x9e\x9a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Ct\x89(\xe8\xc3\xecD6\xa1\u0412\xfb\xe4:\xc7I\xbe\x12Q\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4Cv{\xf7\xfd*\xf9[r\xe91-\xa9D<\xb1h\x8eCC\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94Cy\x838\x8a\xb5\x9aO\xfc!_\x8e\x82iF\x10)\xc3\xf1\xc1\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4C\x89\x8cI\xa3MP\x9b\xfe\xd4\xf7`A\xee\x91\xca\xf3\xaaj\xa5\x89\x10CV\x1a\x88)0\x00\x00\u07d4C\x8c/T\xff\x8eb\x9b\xab6\xb1D+v\v\x12\xa8\x8f\x02\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\x98b\x8e\xa6c-9>\x92\x9c\xbd\x92\x84d\xc5h\xaaJ\f\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4C\x9d//Q\x10\xa4\u054b\x17W\x93P\x15@\x87@\xfe\xc7\xf8\x89\u03e5\xc5\x15\x0fL\x88\x80\x00\u07d4C\x9d\xee?vy\xff\x100s?\x93@\xc0\x96hkI9\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xb0y\xba\xf0ry\x99\xe6k\xf7C\u057c\xbfwl;\t\"\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xbc-M\xdc\xd6X;\xe2\u01fc\tK(\xfbr\xe6+\xa8;\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xc7\xeb\u0173\xe7\xaf\x16\xf4}\xc5az\xb1\x0e\x0f9\xb4\xaf\xbb\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4C\u02d6R\x81\x8coMg\x96\xb0\xe8\x94\t0ly\xdbcI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xcc\b\xd0s*\xa5\x8a\xde\xf7a\x9b\xedFU\x8a\xd7wAs\x89\xf0\xe7\u0730\x12*\x8f\x00\x00\xe0\x94C\u0567\x1c\xe8\xb8\xf8\xae\x02\xb2\xea\xf8\xea\xf2\xca(@\xb9?\xb6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794C\xdb\u007f\xf9Z\bm(\ubff8/\xb8\xfb_#\n^\xbc\u0348\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4C\xe7\xec\x84cX\xd7\xd0\xf97\xad\x1c5\v\xa0i\u05ffr\xbf\x89\x06p\xaeb\x92\x14h\x00\x00\u07d4C\xf1o\x1eu\xc3\xc0j\x94x\xe8\u0157\xa4\n<\xb0\xbf\x04\u0309\x9d\xf7\u07e8\xf7`H\x00\x00\u07d4C\xf4p\xede\x9e)\x91\xc3u\x95~]\xde\u017d\x1d8\"1\x89\x05k\xc7^-c\x10\x00\x00\u07d4C\xf7\xe8n8\x1e\xc5\x1e\u0110m\x14v\u02e9z=\xb5\x84\xe4\x8965\u026d\xc5\u07a0\x00\x00\u07d4C\xff8t>\xd0\xcdC0\x8c\x06e\t\u030e~r\xc8b\xaa\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94C\xff\x88S\xe9\x8e\xd8@k\x95\x00\n\u0684\x83b\u05a09*\x8a\x04\xae\v\x1cM.\x84\xd0\x00\x00\u07d4D\t\x88f\xa6\x9bh\xc0\xb6\xbc\x16\x82)\xb9`5\x87\x05\x89g\x89\n1\x06+\xee\xedp\x00\x00\u07d4D\x19\xaca\x8d]\xea|\xdc`w o\xb0}\xbd\xd7\x1c\x17\x02\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4D\x1aR\x00\x16a\xfa\xc7\x18\xb2\u05f3Q\xb7\xc6\xfbR\x1az\xfd\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94D\x1a\u0282c\x13$\xac\xbf\xa2F\x8b\xda2[\xbdxG{\xbf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4D\x1f7\xe8\xa0)\xfd\x02H/(\x9cI\xb5\xd0m\x00\xe4\b\xa4\x89\x12\x11\xec\xb5m\x13H\x80\x00\u07d4D \xaa5F[\xe6\x17\xad$\x98\xf3p\xde\n<\xc4\xd20\xaf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4D#/\xf6m\xda\xd1\xfd\x84\x12f8\x006\xaf\xd7\xcf}\u007fB\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4D%\rGn\x06$\x84\xe9\b\n9g\xbf:Js*\xd7?\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4D)\xa2\x9f\xee\x19\x84Pg,\f\x1d\a1b%\v\xecdt\x896*\xaf\x82\x02\xf2P\x00\x00\u07d4D5RS\xb2wH\xe3\xf3O\xe9\xca\xe1\xfbq\x8c\x8f$\x95)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4D8\xe8\x80\xcb'f\xb0\xc1\u03ae\xc9\xd2A\x8f\u03b9R\xa0D\x89\a?\xa0s\x90?\b\x00\x00\u07d4DL\xafy\xb7\x138\ue6a7\xc73\xb0*\u02a7\xdc\x02YH\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4D\\\xb8\xde^=\xf5 \xb4\x99\xef\u0240\xf5+\xff@\xf5\\v\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Dj\x809\xce\u03dd\xceHy\xcb\xca\xf3I;\xf5E\xa8\x86\x10\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4Dt)\x9d\x0e\xe0\x90\u0710x\x9a\x14\x86H\x9c=\rd^m\x8965\u026d\xc5\u07a0\x00\x00\u07d4D\x8b\xf4\x10\xad\x9b\xbc/\xec\xc4P\x8d\x87\xa7\xfc.K\x85a\xad\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4D\x90\x1e\r\x0e\b\xac=^\x95\xb8\xec\x9d^\x0f\xf5\xf1.\x03\x93\x89\x16\xa1\xf9\xf5\xfd}\x96\x00\x00\xe0\x94D\x93\x12<\x02\x1e\xce;3\xb1\xa4R\xc9&\x8d\xe1@\a\xf9\u04ca\x01je\x02\xf1Z\x1eT\x00\x00\xe0\x94D\x9a\xc4\xfb\xe3\x83\xe3g8\x85^6JW\xf4q\xb2\xbf\xa11\x8a)\xb7d2\xb9DQ \x00\x00\u07d4D\xa0\x1f\xb0J\xc0\xdb,\xce]\xbe(\x1e\x1cF\xe2\x8b9\xd8x\x89lj\xccg\u05f1\xd4\x00\x00\u07d4D\xa6=\x18BE\x87\xb9\xb3\a\xbf\xc3\xc3d\xae\x10\xcd\x04\xc7\x13\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94D\xa8\x98\x9e20\x81!\xf7$f\x97\x8d\xb3\x95\xd1\xf7l:K\x8a\x01\x88P)\x9fB\xb0j\x00\x00\u07d4D\xc1\x11\v\x18\x87\x0e\xc8\x11x\xd9=!X8\xc5Q\u050ed\x89\n\xd6\xf9\x85\x93\xbd\x8f\x00\x00\u07d4D\xc1Ge\x12|\xde\x11\xfa\xb4l],\xf4\u0532\x89\x00#\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94D\xc5N\xaa\x8a\xc9@\xf9\xe8\x0f\x1et\xe8/\xc1O\x16v\x85j\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4D\xcdwSZ\x89?\xa7\xc4\xd5\xeb:$\x0ey\u0419\xa7--\x89,s\xc97t,P\x00\x00\u07d4D\u07faP\xb8)\xbe\xcc_O\x14\u0470J\xab3 \xa2\x95\xe5\x8965\u026d\xc5\u07a0\x00\x00\u07d4D\xe2\xfd\xc6y\xe6\xbe\xe0\x1e\x93\xefJ:\xb1\xbc\xce\x01*\xbc|\x89\x16=\x19I\x00\xc5E\x80\x00\xe0\x94D\xf6/*\xaa\xbc)\xad:k\x04\xe1\xffo\x9c\xe4R\xd1\xc1@\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4D\xff\xf3{\xe0\x1a8\x88\u04f8\xb8\u1200\xa7\xdd\xef\xee\xea\u04c9\x0e\f[\xfc}\xae\x9a\x80\x00\u07d4E\x06\xfe\x19\xfaK\x00k\xaa9\x84R\x9d\x85\x16\xdb++P\xab\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\x1b6\x99G[\xed]y\x05\xf8\x90Z\xa3Eo\x1e\u05c8\xfc\x89\x8a\xc7#\x04\x89\xe8\x00\x00\x00\u0794E\x1bpp%\x9b\u06e2q\x00\xe3n#B\x8aS\xdf\xe3\x04\u9239\x8b\xc8)\xa6\xf9\x00\x00\u07d4E'+\x8fb\xe9\xf9\xfa\x8c\xe0D \u1ba3\xeb\xa9hn\xac\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94E+d\u06ce\xf7\xd6\u07c7\u01c8c\x9c\"\x90\xbe\x84\x82\xd5u\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4E>5\x9a3\x97\x94LZ'Z\xb1\xa2\xf7\n^Z?i\x89\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4EI\xb1Yy%_~e\xe9\x9b\rV\x04\u06d8\xdf\xca\u023f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4EKa\xb3D\xc0\xef\x96Qy#\x81U\xf2w\u00c2\x9d\v8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94EO\x01A\xd7!\xd3<\xbd\xc4\x10\x18\xbd\x01\x11\x9a\xa4xH\x18\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4ES3\x90\xe3@\xfe\r\xe3\xb3\xcf_\xb9\xfc\x8e\xa5R\xe2\x9eb\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4ES\x96\xa4\xbb\u067a\u8bdf\xb7\xc4\xd6MG\x1d\xb9\xc2E\x05\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4E[\x92\x96\x92\x1at\xd1\xfcAa\u007fC\xb80>o>\xd7l\x89\u3bb5sr@\xa0\x00\x00\u07d4E\\\xb8\xee9\xff\xbcu#1\xe5\xae\xfcX\x8e\xf0\xeeY4T\x8965F:x\r\xef\x80\x00\u07d4Ej\u0b24\x8e\xbc\xfa\xe1f\x06\x02PR_c\x96^v\x0f\x89\x10CV\x1a\x88)0\x00\x00\u07d4Eo\x8dtf\x82\xb2$g\x93I\x06M\x1b6\x8c|\x05\xb1v\x89\u0213\u041c\x8fQP\x00\x00\u07d4Ep)\xc4i\xc4T\x8d\x16\x8c\xec>e\x87.D(\xd4+g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Eq\xdeg+\x99\x04\xba\xd8t6\x92\xc2\x1cO\xdc\xeaL.\x01\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Ex\x1b\xbew\x14\xa1\xc8\xf7;\x1cty!\xdfO\x84'\x8bp\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E{\xce\xf3}\xd3\xd6\v-\xd0\x19\xe3\xfea\xd4k?\x1erR\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94E\x8e<\u025e\x94xD\xa1\x8ejB\x91\x8f\xef~\u007f_^\xb3\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\u07d4E\x93\x93\xd6:\x06>\xf3r\x1e\x16\xbd\x9f\xdeE\ue77dw\xfb\x89j\xba\u05a3\xc1S\x05\x00\x00\u07d4E\xa5p\xdc\xc2\t\f\x86\xa6\xb3\xea)\xa6\bc\xdd\xe4\x1f\x13\xb5\x89\f\x9a\x95\xee)\x86R\x00\x00\u07d4E\xa8 \xa0g/\x17\xdct\xa0\x81\x12\xbcd?\xd1\x16w6\u00c9\n\xd6\xc4;(\x15\xed\x80\x00\u07d4E\xb4q\x05\xfeB\xc4q-\xcen*!\xc0[\xff\xd5\xeaG\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\xbb\x82\x96R\u063f\xb5\x8b\x85'\xf0\xec\xb6!\u009e!.\u00c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\xc0\u045f\v\x8e\x05O\x9e\x8986\xd5\xec\xaey\x01\xaf(\x12\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4E\xc4\xec\xb4\xee\x89\x1e\xa9\x84\xa7\xc5\xce\xfd\x8d\xfb\x001\v(P\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4E\u028d\x95f\b\xf9\xe0\n/\x99t\x02\x86@\x88\x84ef\x8f\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\u0298b\x00;N@\xa3\x17\x1f\xb5\xca\xfa\x90(\xca\xc8\xde\x19\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4E\xd1\xc9\xee\xdf|\xabA\xa7y\x05{y9_T(\xd8\x05(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\u0535M7\xa8\xcfY\x98!#_\x06/\xa9\xd1p\xed\u8909\x11\x90g;_\u0690\x00\x00\xe0\x94E\xdb\x03\xbc\xcf\u05a5\xf4\xd0&k\x82\xa2*6\x87\x92\xc7}\x83\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4E\xe3\xa9>r\x14J\u0686\f\xbcV\xff\x85\x14Z\xda8\xc6\u0689WG=\x05\u06ba\xe8\x00\x00\u07d4E\u6378\u06fa\xba_\xc2\xcb3|b\xbc\xd0\xd6\x1b\x05\x91\x89\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\u6379L}\n\xb7\xacA\x85zq\xd6qG\x87\x0fNq\x8aT\xb4\v\x1f\x85+\xda\x00\x00\x00\u07d4E\xf4\xfc`\xf0\x8e\xac\xa1\x05\x98\xf03c)\x80\x1e<\x92\xcbF\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4F\rSU\xb2\xce\xebnb\x10}\x81\xe5\x12p\xb2k\xf4V \x89l\xb7\xe7Hg\xd5\xe6\x00\x00\xe0\x94F\"O2\xf4\xec\xe5\u0206p\x90\xd4@\x9dU\xe5\v\x18C-\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4F'\xc6\x06\x84&q\xab\u0782\x95\xee]\xd9L\u007fT\x954\xf4\x89\x0f\x89_\xbd\x872\xf4\x00\x00\u07d4F+g\x8bQ\xb5\x84\xf3\xedz\xda\a\v\\\u065c\v\xf7\xb8\u007f\x89\x05k\xc7^-c\x10\x00\x00\u07d4FM\x9c\x89\xcc\xe4\x84\xdf\x00\x02w\x19\x8e\xd8\a_\xa65r\u0449\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4FPNj!Z\xc8;\xcc\xf9V\xbe\xfc\x82\xabZg\x93q\u0209\x1c!(\x05\u00b4\xa5\x00\x00\xe0\x94FQ\xdcB\x0e\b\xc3);'\xd2Ix\x90\xebP\":\xe2\xf4\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4FS\x1e\x8b\x1b\xde\t\u007f\u07c4\x9dm\x11\x98\x85`\x8a\x00\x8d\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4Fb\x92\xf0\xe8\rC\xa7\x87t'u\x90\xa9\xebE\x96\x12\x14\xf4\x894\x95tD\xb8@\xe8\x00\x00\xe0\x94Fb\xa1v^\xe9!\x84-\u0708\x89\x8d\x1d\xc8bu\x97\xbd~\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Fe\xe4s\x96\xc7\u06d7\xeb*\x03\xd9\bc\xd5\u053a1\x9a\x94\x89 \x86\xac5\x10R`\x00\x00\u07d4Fo\xdak\x9bX\xc5S'P0j\x10\xa2\xa8\xc7h\x10;\a\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4Fq$\xae\u007fE/&\xb3\xd5t\xf6\b\x88\x94\xfa]\x1c\xfb;\x89\x92^\x06\xee\xc9r\xb0\x00\x00\u0794Fr*6\xa0\x1e\x84\x1d\x03\xf7\x80\x93^\x91}\x85\u0566z\xbd\x88\xce\xc7o\x0eqR\x00\x00\u07d4Fw\x9aVV\xff\x00\xd7>\xac:\xd0\u00cbl\x850\x94\xfb@\x89\f\x82S\xc9lj\xf0\x00\x00\u07d4Fw\xb0N\x03C\xa3!1\xfdj\xbb9\xb1\xb6\x15k\xba=[\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4F}Y\x88$\x9ahaG\x16e\x98@\xed\n\xe6\xf6\xf4W\xbc\x89\x15\x01\xa4\x8c\xef\xdf\xde\x00\x00\u07d4F~\x0e\xd5O;v\xae\x066\x17n\aB\b\x15\xa0!sn\x89lk\x93[\x8b\xbd@\x00\x00\u07d4F~\xa1\x04E\x82~\xf1\xe5\x02\xda\xf7k\x92\x8a \x9e\r@2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94F\u007f\xbfAD\x16\x00u\u007f\xe1X0\xc8\xcd_O\xfb\xbb\xd5`\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94F\x93Xp\x932\xc8+\x88~ \xbc\xdd\xd0\"\x0f\x8e\u06e7\u040a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4F\x97\xba\xaf\x9c\xcb`?\xd3\x040h\x9dCTE\xe9\u024b\xf5\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4F\xa3\v\x8a\x80\x891!tE\xc3\xf5\xa9>\x88,\x03E\xb4&\x89\r\x8d\xb5\xeb\u05f2c\x80\x00\u07d4F\xa40\xa2\u0528\x94\xa0\u062a?\xea\xc6\x156\x14\x15\xc3\xf8\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4F\xaaP\x18pg~\u007f\nPHv\xb4\xe8\x80\x1a\n\xd0\x1cF\x89+^:\xf1k\x18\x80\x00\x00\u07d4F\xbf\u0172\a\xeb \x13\xe2\xe6\x0fw_\xec\xd7\x18\x10\u0159\f\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4F\xc1\xaa\"D\xb9\u0229W\u028f\xacC\x1b\x05\x95\xa3\xb8h$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4F\xd8\x061(B\x03\xf6(\x8e\xcdNWX\xbb\x9dA\xd0]\xbe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\n\xc5\xd1\xf3\xef\xe2\x8f8\x02\xaf\x92[W\x1ec\x86\x8b9}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\x10\x10\xdaI/@\x18\x83;\b\x8d\x98r\x90\x1e\x06\x12\x91t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4G\x12T\x02e\xcb\xee\u00c4p\"\u015f\x1b1\x8dC@\n\x9e\x89\xbd\xbcA\xe04\x8b0\x00\x00\xe0\x94G\x14\u03e4\xf4k\u05bdps}u\x87\x81\x97\xe0\x8f\x88\xe61\x8a\x02\u007f>\u07f3Nn@\x00\x00\u07d4G H\xcc`\x9a\xeb$!e\uaa87\x05\x85\f\xf3\x12]\xe0\x8965\u026d\xc5\u07a0\x00\x00\u07d4G!\x92)\xe8\xcdVe\x9ae\u00a9C\xe2\u075a\x8fK\xfd\x89\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4G7\xd0B\xdcj\xe7>\xc7:\xe2Qz\u03a2\xfd\xd9d\x87\u014965\u026d\xc5\u07a0\x00\x00\u07d4GAX\xa1\xa9\xdci<\x13?e\xe4{\\:\xe2\xf7s\xa8o\x89\n\xdaUGK\x814\x00\x00\u07d4GE\xab\x18\x1a6\xaa\x8c\xbf\"\x89\xd0\xc4Qe\xbc~\xbe#\x81\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4GPf\xf9\xad&eQ\x96\xd5SS'\xbb\xeb\x9by)\xcb\x04\x89\xa4\xccy\x95c\u00c0\x00\x00\xe0\x94GR!\x8eT\xdeB?\x86\xc0P\x193\x91z\xea\b\xc8\xfe\u054a\x04<3\xc1\x93ud\x80\x00\x00\u07d4GZa\x93W-JNY\u05fe\t\u02d6\r\u074cS\x0e/\x89$,\xf7\x8c\xdf\a\xff\x80\x00\u07d4Gd\x8b\xed\x01\xf3\xcd2I\bNc]\x14\u06a9\xe7\xec<\x8a\x89\n\x84Jt$\xd9\xc8\x00\x00\u07d4Gh\x84\x10\xff%\xd6T\xd7.\xb2\xbc\x06\xe4\xad$\xf83\xb0\x94\x89\b\xb2\x8da\xf3\u04ec\x00\x00\u07d4GkU\x99\b\x9a?\xb6\xf2\x9clr\xe4\x9b.G@\ua00d\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4Gs\x0f_\x8e\xbf\x89\xacr\xef\x80\xe4l\x12\x19P8\xec\xdcI\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94G{$\xee\u80deO\u045d\x12P\xbd\vfEyJa\u028a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4G\x81\xa1\nM\xf5\uef02\xf4\xcf\xe1\a\xba\x1d\x8av@\xbdf\x89a\t=|,m8\x00\x00\u07d4G\x88Z\xba\xbe\xdfM\x92\x8e\x1c\x88\x83\xa6a\x9cl(\x11\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94G\xe2]\xf8\x82%8\xa8Yk(\xc67\x89kM\x14<5\x1d\x8a\x11\v\xe9\xeb$\xb8\x81P\x00\x00\u07d4G\xf4ik\xd4b\xb2\r\xa0\x9f\xb8>\xd2\x03\x98\x18\xd7v%\xb3\x89\b\x13\xcaV\x90m4\x00\x00\u07d4G\xfe\xf5\x85\x84FRH\xa0\x81\r`F>\xe9>Zn\xe8\u04c9\x0fX\xcd>\x12i\x16\x00\x00\u07d4G\xffo\xebC! `\xbb\x15\x03\u05e3\x97\xfc\b\xf4\xe7\x03R\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\xff\xf4,g\x85Q\xd1A\xebu\xa6\xee9\x81\x17\xdf>J\x8d\x89\x05k\xea\xe5\x1f\xd2\xd1\x00\x00\u07d4H\x01\x0e\xf3\xb8\xe9^?0\x8f0\xa8\xcb\u007fN\xb4\xbf`\xd9e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4H\n\xf5 v\x00\x9c\xa77\x81\xb7\x0eC\xb9Y\x16\xa6\"\x03\xab\x892\x19r\xf4\b=\x87\x80\x00\u07d4H\x0f1\xb9\x891\x1eA$\u01a7F_ZD\tM6\xf9\u04097\x90\xbb\x85Q7d\x00\x00\xe0\x94H\x11\x15)j\xb7\xdbRI/\xf7\xb6G\xd63)\xfb\\\xbck\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4H\x1e:\x91\xbf\xdc/\x1c\x84(\xa0\x11\x9d\x03\xa4\x16\x01A~\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4H(\xe4\xcb\xe3N\x15\x10\xaf\xb7,+\ueb0aE\x13\xea\xeb\u0649\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94H)\x82\xac\x1f\x1cm\x17!\xfe\xec\u0679\xc9l\xd9I\x80PU\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4H0,1\x1e\xf8\xe5\xdcfAX\xddX<\x81\x19Mn\rX\x89\xb6gl\xe0\xbc\xcb\\\x00\x00\u07d4H;\xa9\x904\xe9\x00\xe3\xae\xdfaI\x9d;+\xce9\xbe\xb7\xaa\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4HT\x8bK\xa6+\xcb/\r4\xa8\x8d\u019ah\x0eS\x9c\xf0F\x89\x05l\xf1\u02fbt2\x00\x00\u07d4Hc\x84\x979&Zc\xb0\xa2\xbf#jY\x13\xe6\xf9Y\xce\x15\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4He\x9d\x8f\x8c\x9a/\xd4Oh\u06a5]#\xa6\b\xfb\xe5\x00\u0709lk\x93[\x8b\xbd@\x00\x00\xe0\x94Hf\x9e\xb5\xa8\x01\u0637_\xb6\xaaX\xc3E\x1bpX\xc2C\xbf\x8a\x06\x8dB\xc18\u06b9\xf0\x00\x00\u07d4Hjl\x85\x83\xa8D\x84\xe3\xdfC\xa1#\x83\u007f\x8c~#\x17\u0409\x11\x87\xc5q\xab\x80E\x00\x00\u07d4Hz\xdf}p\xa6t\x0f\x8dQ\xcb\xddh\xbb?\x91\u0125\xceh\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4H~\x10\x85\x02\xb0\xb1\x89\uf70cm\xa4\xd0\xdbba\xee\xc6\xc0\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94H\x88\xfb%\xcdP\u06f9\xe0H\xf4\x1c\xa4}x\xb7\x8a'\xc7\u064a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u0794H\x934\u00b6\x95\xc8\xee\a\x94\xbd\x86B\x17\xfb\x9f\xd8\xf8\xb15\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4H\xa3\r\xe1\xc9\x19\xd3\xfd1\x80\xe9}_+*\x9d\xbd\x96M-\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4H\xbf\x14\u05f1\xfc\x84\xeb\xf3\xc9k\xe1/{\xce\x01\xaai\xb0>\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4H\xc2\ue465\aV\xd8\u039a\xbe\xebu\x89\xd2,o\xee]\xfb\x89\xae\x8ez\v\xb5u\xd0\x00\x00\u07d4H\xc5\u0197\v\x91a\xbb\x1c{z\xdf\xed\x9c\xde\u078a\x1b\xa8d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94H\xd2CKz}\xbb\xff\b\";c\x87\xb0]\xa2\xe5\t1&\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4H\xd4\xf2F\x8f\x96?\u05da\x00a\x98\xbbg\x89]-Z\xa4\u04c9K\xe4\xe7&{j\xe0\x00\x00\u07d4H\xe0\xcb\xd6\u007f\x18\xac\xdbzb\x91\xe1%M\xb3.\trs\u007f\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4H\xf6\n5HO\xe7y+\u030a{c\x93\xd0\u0761\xf6\xb7\x17\x89\xc3(\t>a\xee@\x00\x00\u07d4H\xf8\x83\xe5g\xb46\xa2{\xb5\xa3\x12M\xbc\x84\xde\xc7u\xa8\x00\x89)\xd7n\x86\x9d\u0340\x00\x00\xe0\x94I\x01E\xaf\xa8\xb5E\"\xbb!\xf3R\xf0m\xa5\xa7\x88\xfa\x8f\x1d\x8a\x01\xf4lb\x90\x1a\x03\xfb\x00\x00\u07d4I\t\xb3\x19\x98\xea\xd4\x14\xb8\xfb\x0e\x84k\xd5\xcb\xde995\xbe\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4I\x12\xd9\x02\x93\x16v\xff9\xfc4\xfe<<\xc8\xfb!\x82\xfaz\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4I\x13o\xe6\xe2\x8btS\xfc\xb1kk\xbb\u9aac\xba\x837\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94I\x15a\u06cbo\xaf\xb9\x00~b\xd0P\u0082\xe9,Kk\u020a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4I\x18]\xd7\xc262\xf4lu\x94s\ubb96`\b\xcd5\x98\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4I,\xb5\xf8a\xb1\x87\xf9\xdf!\xcdD\x85\xbe\xd9\vP\xff\xe2-\x89\x1b\x19\xe5\vD\x97|\x00\x00\u07d4I-\xe4j\xaf\x8f\x1dp\x8dY\u05da\xf1\xd0:\xd2\xcb`\x90/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I.p\xf0M\x18@\x8c\xb4\x1e%`70Pk5\xa2\x87k\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4I:g\xfe#\xde\xccc\xb1\r\xdau\xf3(v\x95\xa8\x1b\u056b\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4I=H\xbd\xa0\x15\xa9\xbf\xcf\x16\x03\x93n\xabh\x02L\xe5Q\xe0\x89\x018\xa3\x88\xa4<\x00\x00\x00\xe0\x94IBV\xe9\x9b\x0f\x9c\xd6\xe5\xeb\xca8\x99\x862R\x90\x01e\u020a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4IM\xecM^\xe8\x8a'q\xa8\x15\xf1\xeerd\x94/\xb5\x8b(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I[d\x1b\x1c\u07a3b\u00f4\u02fd\x0f\\\xc5\v\x1e\x17k\x9c\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Ih\xa2\xce\xdbEuU\xa19)Z\xea(wnT\x00<\x87\x8a\x02#\x1a\xef\u0266b\x8f\x00\x00\u07d4Im6U4S\n_\xc1W|\nRA\u02c8\xc4\xdapr\x89a\t=|,m8\x00\x00\xe0\x94In1\x95\x92\xb3A\xea\xcc\xd7x\u0767\xc8\x19mT\xca\xc7u\x8a\x01\xf5q\x89\x87fKH\x00\x00\u07d4IoXC\xf6\xd2L\u064d%^L#\xd1\xe1\xf0#\"uE\x89_\x17\x9f\u0526\xee\t\x80\x00\xe0\x94Ip\u04ec\xf7+[\x1f2\xa7\x00<\xf1\x02\xc6N\xe0TyA\x8a\x1d\xa5jK\b5\xbf\x80\x00\x00\u07d4Iw\xa7\x93\x9d\t9h\x94U\xce&9\xd0\xeeZL\xd9\x10\xed\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4Iy\x19N\xc9\xe9}\xb9\xbe\xe84;|w\xd9\xd7\xf3\xf1\u071f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Iy4c\xe1h\x10\x83\u05ab\xd6\xe7%\u057b\xa7E\xdc\xcd\xe8\x89\x1d\x98\xe9LNG\x1f\x00\x00\u07d4I\x81\xc5\xfff\xccN\x96\x80%\x1f\xc4\xcd/\xf9\a\xcb2xe\x89(\xa8WBTf\xf8\x00\x00\u07d4I\x89\u007f\xe92\xbb\xb3\x15L\x95\u04fc\xe6\xd9;ms)\x04\u0749\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4I\x89\xe1\xab^|\xd0\aF\xb3\x93\x8e\xf0\xf0\xd0d\xa2\x02[\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I\x8a\xbd\xeb\x14\xc2k{r4\xd7\x0f\u03ae\xf3a\xa7m\xffr\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4I\xa6E\xe0f}\xfd{2\xd0u\xcc$g\u074ch\t\a\u0109\a\x06\x01\x95\x8f\u02dc\x00\x00\xe0\x94I\xb7N\x16\x92e\xf0\x1a\x89\xecL\x90r\u0164\xcdr\xe4\xe85\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4I\xbd\xbc{\xa5\xab\xeb\xb68\x9e\x91\xa3(R \xd3E\x1b\xd2S\x8965\u026d\xc5\u07a0\x00\x00\u07d4I\xc9A\xe0\xe5\x01\x87&\xb7)\x0f\xc4s\xb4q\xd4\x1d\xae\x80\u0449\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94I\xc9w\x1f\xca\x19\u0579\xd2E\u0211\xf8\x15\x8f\xe4\x9fG\xa0b\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4I\xcf\x1eT\xbe61\x06\xb9 r\x9d-\v\xa4o\bg\x98\x9a\x89\x0e\x87?D\x13<\xb0\x00\x00\u07d4I\xd2\u008e\xe9\xbcT^\xaa\xf7\xfd\x14\xc2|@s\xb4\xbb_\x1a\x89O\xe9\xb8\x06\xb4\r\xaf\x00\x00\u07d4I\xdd\xee\x90.\x1d\f\x99\u0471\x1a\xf3\u030a\x96\xf7\x8eM\xcf\x1a\x89\n\u03a5\xe4\xc1\x8cS\x00\x00\u07d4I\xf0(9[Z\x86\xc9\xe0\u007fwxc\x0eL.=7:w\x89\x06\xa7JP8\u06d1\x80\x00\xe0\x94J\x19 5\xe2a\x9b$\xb0p\x9dVY\x0e\x91\x83\xcc\xf2\xc1\u064a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4J@S\xb3\x1d\x0e\xe5\u06ef\xb1\xd0k\u05ec\u007f\xf3\",G\u0589K\xe4\xe7&{j\xe0\x00\x00\u07d4JC\x01p\x15-\xe5\x17&3\u0742b\xd1\a\xa0\xaf\xd9j\x0f\x89\xabM\xcf9\x9a:`\x00\x00\u07d4JG\xfc>\x17\u007fVz\x1e8\x93\xe0\x00\xe3k\xba#R\n\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4JR\xba\xd2\x03W\"\x8f\xaa\x1e\x99k\xedy\f\x93gK\xa7\u0409Hz\x9a0E9D\x00\x00\u07d4JS\xdc\xdbV\xceL\xdc\xe9\xf8.\xc0\xeb\x13\xd6sR\xe7\u020b\x89\u3bb5sr@\xa0\x00\x00\u07d4J_\xae;\x03r\xc20\xc1%\xd6\xd4p\x14\x037\xab\x91VV\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4Jq\x90a\xf5(T\x95\xb3{\x9d~\xf8\xa5\x1b\a\xd6\u6b2c\x89\n\xd4\xc81j\v\f\x00\x00\u07d4Js8\x92\x98\x03\x1b\x88\x16\u0329FB\x1c\x19\x9e\x18\xb3C\u0589\"8h\xb8y\x14o\x00\x00\u07d4Js]\"G\x927m3\x13g\xc0\x93\xd3\x1c\x87\x944\x15\x82\x89f\xff\xcb\xfd^Z0\x00\x00\u07d4Jt\x94\xcc\xe4HU\u0300X(B\xbe\x95\x8a\r\x1c\x00r\ue242\x1a\xb0\xd4AI\x80\x00\x00\u07d4Ju\xc3\xd4\xfao\u033d]\u0567\x03\xc1Sy\xa1\xe7\x83\u9dc9b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94J\x81\xab\xe4\x98L|k\xefc\u0598 \xe5WC\xc6\x1f \x1c\x8a\x03d\x01\x00N\x9a\xa3G\x00\x00\u07d4J\x82iO\xa2\x9d\x9e!2\x02\xa1\xa2\t(]\xf6\xe7E\xc2\t\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4J\x83\\%\x82LG\xec\xbf\u01d49\xbf?\\4\x81\xaau\u0349K\xe4\xe7&{j\xe0\x00\x00\u07d4J\x91\x802C\x91Y\xbb1[g%\xb6\x83\r\xc86\x97s\x9f\x89\x12\xa3.\xf6x3L\x00\x00\u07d4J\x97\xe8\xfc\xf4c^\xa7\xfc^\x96\xeeQu.\u00c8qk`\x89\x1d\x99E\xab+\x03H\x00\x00\u07d4J\x9a&\xfd\n\x8b\xa1\x0f\x97}\xa4\xf7|1\x90\x8d\xabJ\x80\x16\x89a\t=|,m8\x00\x00\u07d4J\xa1H\xc2\xc34\x01\xe6j+Xnew\u0132\x92\xd3\xf2@\x89\v\xb8`\xb2\x85\xf7t\x00\x00\u07d4J\xa6\x93\xb1\"\xf3\x14H*G\xb1\x1c\xc7|h\xa4\x97\x87ab\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4J\xb2\xd3O\x04\x83O\xbftyd\x9c\xab\x92=,G%\xc5S\x89\xbe\xd1\xd0&=\x9f\x00\x00\x00\u07d4J\xc0vs\xe4/d\xc1\xa2^\xc2\xfa-\x86\xe5\xaa+4\xe09\x89lk\x93[\x8b\xbd@\x00\x00\u07d4J\u016c\xad\x00\v\x88w!L\xb1\xae\x00\xea\u0263}Y\xa0\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4J\u0250ZL\xb6\xab\x1c\xfdbTn\xe5\x91s\x00\xb8|O\u07897\b\xba\xed=h\x90\x00\x00\u07d4J\u03e9\xd9N\xdaf%\xc9\u07e5\xf9\xf4\xf5\xd1\a\xc4\x03\x1f\u07c9\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4J\xd0G\xfa\xe6~\xf1b\xfeh\xfe\xdb\xc2};e\xca\xf1\f6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4J\xd9]\x18\x8dddp\x9a\xdd%U\xfbM\x97\xfe\x1e\xbf1\x1f\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d4J\xdb\xf4\xaa\xe0\xe3\xefD\xf7\xddM\x89\x85\u03ef\tn\u010e\x98\x89\b!\xab\rD\x14\x98\x00\x00\u07d4J\xe2\xa0M9\t\xefENTL\xcf\xd6\x14\xbf\xef\xa7\x10\x89\xae\x89\x18\x01\x15\x9d\xf1\xee\xf8\x00\x00\xe0\x94J\xe90\x82\xe4Q\x87\xc2a`\xe6g\x92\xf5\u007f\xad5Q\xc7:\x8a\x04\x96\x15 \xda\xff\x82(\x00\x00\u07d4J\xf0\xdb\a{\xb9\xba^D>!\xe1H\xe5\x9f7\x91\x05\u0152\x89 \x86\xac5\x10R`\x00\x00\u07d4K\x06\x19\xd9\u062a1:\x951\xac}\xbe\x04\xca\rjZ\u0476\x89lk\x93[\x8b\xbd@\x00\x00\u07d4K\v\u062c\xfc\xbcS\xa6\x01\v@\xd4\u040d\xdd-\x9dib-\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4K\x19\xeb\f5K\xc199`\xeb\x06\x06;\x83\x92o\rg\xb2\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4K)C|\x97\xb4\xa8D\xbeq\u0323\xb6H\xd4\xca\x0f\u075b\xa4\x89\b$q\x984\u03ec\x00\x00\u07d4K1\xbfA\xab\xc7\\\x9a\xe2\u034f\u007f5\x16;n+tPT\x89\x14\xb5P\xa0\x13\xc78\x00\x00\u07d4K:|\u00e7\u05f0\x0e\xd5(\"!\xa6\x02Y\xf2[\xf6S\x8a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94K:\xab3^\xbb\xfa\xa8p\xccM`^}.t\xc6h6\x9f\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4K\xcd\xc1\x8a`\x00\x00\u07d4K`\xa3\xe2S\xbf8\xc8\xd5f \x10\xbb\x93\xa4s\xc9e\xc3\xe5\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4Kt\xf5\xe5\x8e.\xdfv\xda\xf7\x01Q\x96J\v\x8f\x1d\xe0f<\x89\x11\x90\xaeID\xba\x12\x00\x00\u07d4Kv!f\xdd\x11\x18\xe8Ci\xf8\x04\xc7_\x9c\xd6W\xbfs\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Ky.)h>\xb5\x86\u353b3Rl`\x01\xb3\x97\x99\x9e\x89 \x86\xac5\x10R`\x00\x00\u07d4K\x90N\x93K\xd0\u030b p_\x87\x9e\x90[\x93\xea\f\xcc0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94K\x92\x06\xbakT\x9a\x1a\u007f\x96\x9e\x1d]\xba\x86u9\xd1\xfag\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4K\x98N\xf2lWn\x81Z.\xae\xd2\xf5\x17\u007f\a\u06f1\xc4v\x89T\x91YV\xc4\t`\x00\x00\u07d4K\x9e\x06\x8f\xc4h\tv\xe6\x15\x04\x91)\x85\xfd\\\xe9K\xab\r\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4K\xa0\xd9\xe8\x96\x01w+IhG\xa2\xbbC@\x18g\x87\xd2e\x8965\u026d\xc5\u07a0\x00\x00\u07d4K\xa5:\xb5I\xe2\x01m\xfa\"<\x9e\u0563\x8f\xad\x91(\x8d\a\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94K\xa8\xe0\x11\u007f\xc0\xb6\xa3\xe5k$\xa3\xa5\x8f\xe6\xce\xf4B\xff\x98\x8a\x011\xbe\xb9%\xff\xd3 \x00\x00\u07d4K\xac\x84j\xf4\x16\x9f\x1d\x95C\x1b4\x1d\x88\x00\xb2!\x80\xaf\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4K\xb6\xd8k\x83\x14\xc2-\x8d7\xeaQm\x00\x19\xf1V\xaa\xe1-\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94K\xb9e\\\xfb*6\xea|cz{\x85\x9bJ1T\xe2n\xbe\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94K\xbc\xbf8\xb3\xc9\x01c\xa8K\x1c\u04a9;X\xb2\xa34\x8d\x87\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94K\xd6\xdd\f\xff#@\x0e\x170\xba{\x89E\x04W}\x14\xe7J\x8a+\xa0\xcc\xdd\xd0\xdfs\xb0\x00\x00\u07d4K\xe8b\x8a\x81T\x87N\x04\x8d\x80\xc1B\x18\x10\"\xb1\x80\xbc\xc1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4K\xe9\rA!)\u0564\xd0BCa\xd6d\x9dNG\xa6#\x16\x897\b\xba\xed=h\x90\x00\x00\xe0\x94K\xea(\x8e\xeaB\u0115^\xb9\xfa\xad*\x9f\xafG\x83\xcb\u076c\x8a\x06\x18\xbe\x16c\u012fI\x00\x00\u07d4K\xf4G\x97\x99\xef\x82\xee\xa2\tC7OV\xa1\xbfT\x00\x1e^\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4K\xf8\xbf\x1d5\xa211Wd\xfc\x80\x01\x80\x9a\x94\x92\x94\xfcI\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4K\xf8\xe2oL'\x90\xdae3\xa2\xac\x9a\xba\xc3\u019a\x19\x943\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0794L\n\xcaP\x8b<\xaf^\xe0(\xbcp}\xd1\xe8\x00\xb88\xf4S\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94L\v\x15\x15\xdf\xce\u05e1>\x13\xee\x12\xc0\xf5#\xaePO\x03+\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4L\x13\x98\f2\xdc\xf3\x92\vx\xa4\xa7\x903\x12\x90|\x1b\x12?\x89\x03A\x00\x15\xfa\xae\f\x00\x00\u07d4L\x15y\xaf3\x12\xe4\xf8\x8a\xe9\x95\xcc9W\xd2R\xce\v\xf0\xc8}[O\"4g.p\x89\x87\x86x2n\xac\x90\x00\x00\u07d4LB1y\x82i\x1d\x10\x89\x05k\xc7^-c\x10\x00\x00\u07d4LZ\xfe@\xf1\x8f\xfcH\u04e1\xae\xc4\x1f\u009d\xe1y\xf4\u0497\x89lk\x93[\x8b\xbd@\x00\x00\u07d4L[=\xc0\xe2\xb96\x0f\x91(\x9b\x1f\xe1<\xe1,\x0f\xbd\xa3\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Lfk\x86\xf1\xc5\ue324\x12\x85\xf5\xbd\xe4\xf7\x90R\b\x14\x06\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Lik\xe9\x9f:i\x04@\xc3CjY\xa7\xd7\xe97\u05ba\r\x89\xbb\x91%T\"c\x90\x00\x00\u07d4Lj$\x8f\xc9}p]\xefI\\\xa2\aY\x16\x9e\xf0\xd3dq\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4Lj\x9d\xc2\u02b1\n\xbb.|\x13p\x06\xf0\x8f\ucd77y\xe1\x89\x1b\r\x04 /G\xec\x00\x00\u07d4Lk\x93\xa3\xbe\xc1cIT\f\xbf\xca\xe9l\x96!\xd6dP\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Lu\x98\x13\xad\x13\x86\xbe\xd2\u007f\xfa\xe9\xe4\x81^60\u0323\x12\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Lv\f\xd9\xe1\x95\xeeO-k\xce%\x00\xff\x96\xda|C\ue44a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4Lv{e\xfd\x91\x16\x1fO\xbd\xccji\xe2\xf6\xadq\x1b\xb9\x18\x89'\b\x01\xd9F\xc9@\x00\x00\u07d4L~.+w\xad\f\xd6\xf4J\xcb(a\xf0\xfb\x8b(u\x0e\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4L\x85\xed6/$\xf6\xb9\xf0L\xdf\xcc\xd0\"\xaeSQG\u02f9\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4L\x93[\xb2Pw\x8b0\x9b==\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4L\xee\x90\x1bJ\u0231V\xc5\xe2\xf8\xa6\xf1\xbe\xf5r\xa7\xdc\xeb~\x8965\u026d\xc5\u07a0\x00\x00\u07d4L\xef\xbe#\x98\xe4}R\u73743L\x8bivu\U00053b89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4L\xf5S{\x85\x84/\x89\xcf\xee5\x9e\xaeP\x0f\xc4I\xd2\x11\x8f\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94M\bG\x1dh\x00z\xff*\xe2y\xbc^?\xe4\x15o\xbb\xe3\u078a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4M \x01\x10\x12@\b\xd5ov\x98\x12VB\f\x94jo\xf4\\\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4M$\xb7\xacG\xd2\xf2}\xe9\tt\xba=\xe5\xea\xd2\x03TK\u0349\x05k\xc7^-c\x10\x00\x00\u0794M)\xfcR:,\x16)S!!\u0699\x98\u9d6b\x9d\x1bE\x88\xdbD\xe0I\xbb,\x00\x00\u07d4M8\xd9\x0f\x83\xf4Q\\\x03\xccx2j\x15M5\x8b\u0602\xb7\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4ML\xf5\x80t)a^0\xcd\xfa\xce\x1eZ\xaeM\xad0U\xe6\x89 \x86\xac5\x10R`\x00\x00\u07d4MW\xe7\x16\x87l\f\x95\xef^\xae\xbd5\xc8\xf4\x1b\x06\x9bk\xfe\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Mg\U000ab159\xfe\xf5\xfcA9\x99\xaa\x01\xfd\u007f\xcep\xb4=\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Mn\x8f\xe1\t\xcc\xd2\x15\x8eM\xb1\x14\x13/\xe7_\xec\u023e[\x89\x01[5W\xf1\x93\u007f\x80\x00\xe0\x94Mq\xa6\xeb=\u007f2~\x184'\x8e(\v\x03\x9e\xdd\xd3\x1c/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4M|\xfa\xa8L\xb31\x06\x80\n\x8c\x80/\xb8\xaaF8\x96\u0159\x89a\t=|,m8\x00\x00\u07d4M\x80\x10\x93\xc1\x9c\xa9\xb8\xf3B\xe3<\xc9\xc7{\xbdL\x83\x12\u03c9\x12\xb3\xe7\xfb\x95\u0364\x80\x00\u07d4M\x82\x88\x94u/o%\x17]\xaf!w\tD\x87\x95Ko\x9f\x89O!+\xc2\u011c\x83\x80\x00\xe0\x94M\x82\xd7p\f\x12;\xb9\x19A\x9b\xba\xf0Fy\x9ck\x0e,f\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4M\x83m\x9d;\x0e,\xbdM\xe0PYo\xaaI\f\xff\xb6\r]\x89\x10CV\x1a\x88)0\x00\x00\u07d4M\x86\x97\xaf\x0f\xbf,\xa3n\x87h\xf4\xaf\"\x135phZ`\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4M\x92y\x96 )\xa8\xbdEc\x977\xe9\x8bQ\x1e\xff\aL!\x89Hz\x9a0E9D\x00\x00\u07d4M\x93io\xa2HY\xf5\u0493\x9a\xeb\xfaT\xb4\xb5\x1a\xe1\xdc\u0309\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4M\x9cw\xd0u\f^o\xbc$\u007f/\u05d2thl\xb3S\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4M\xa5\xed\u0188\xb0\xcbb\xe1@=\x17\x00\xd9\u0739\x9f\xfe?\u04c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94M\xa8\x03\ai\x84K\xc3A\x86\xb8\\\xd4\xc74\x88I\xffI\xe9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4M\xb1\xc4:\x0f\x83M}\x04x\xb8\x96\ag\xec\x1a\xc4L\x9a\xeb\x89/Q\x810V'7\x00\x00\u07d4M\xb2\x12\x84\xbc\xd4\xf7\x87\xa7Ue\x00\xd6\xd7\xd8\xf3f#\xcf5\x89i(7Ow\xa3c\x00\x00\u07d4M\xc3\xda\x13\xb2\xb4\xaf\xd4O]\r1\x89\xf4D\xd4\xdd\xf9\x1b\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4M\u013f^u\x89\xc4{(7\x8du\x03\u03d6H\x80a\u06fd\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4M\xc9\u057bK\x19\xce\u0354\xf1\x9e\xc2] \x0e\xa7/%\xd7\xed\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94M\xcd\x11\x81X\x18\xae)\xb8]\x016sI\xa8\xa7\xfb\x12\xd0k\x8a\x01\xacB\x86\x10\x01\x91\xf0\x00\x00\u07d4M\xcfb\xa3\xde?\x06\x1d\xb9\x14\x98\xfda\x06\x0f\x1fc\x98\xffs\x89lj\xccg\u05f1\xd4\x00\x00\u07d4M\xd11\xc7J\x06\x8a7\xc9\n\xde\xd4\xf3\t\xc2@\x9fdx\u04c9\x15\xaf9\u4ab2t\x00\x00\xe0\x94M\u0767Xk\"7\xb0S\xa7\xf3(\x9c\xf4`\xdcW\xd3z\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4M\xe3\xfe4\xa6\xfb\xf64\xc0Q\x99\u007fG\xcc\u007fHy\x1fX$\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4M\xf1@\xbaye\x85\xddT\x891[\xcaK\xbah\n\u06f8\x18\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4N\x02\ay\xb5\xdd\xd3\xdf\"\x8a\x00\xcbH\xc2\xfc\x97\x9d\xa6\xae8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4N\v\xd3$s\xc4\xc5\x1b\xf2VT\xde\xf6\x9fy|k)\xa22\x89V\xc9]\xe8\xe8\xca\x1d\x00\x00\u07d4N\"%\xa1\xbbY\xbc\x88\xa21ft\xd33\xb9\xb0\xaf\xcafU\x89\bg\x0e\x9e\xc6Y\x8c\x00\x00\u07d4N#\x10\x19\x1e\xad\x8d;\xc6H\x98s\xa5\xf0\xc2\xeck\x87\u1f8965\u026d\xc5\u07a0\x00\x00\u07d4N#-S\xb3\u6f8f\x89Sa\xd3\x1c4\xd4v+\x12\xc8.\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4N+\xfaJFo\x82g\x1b\x80\x0e\xeeBj\xd0\f\a\x1b\xa1p\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4N>\xda\u0506M\xabd\xca\xe4\xc5Azvw@S\xdcd2\x89 \b\xfbG\x8c\xbf\xa9\x80\x00\u07d4NC\x18\xf5\xe1>\x82JT\xed\xfe0\xa7\xedO&\xcd=\xa5\x04\x89lk\x93[\x8b\xbd@\x00\x00\u07d4N[w\xf9\x06aY\xe6\x15\x93?-\xdatw\xfaNG\xd6H\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94Nf\x00\x80b\x89EJ\u03630\xa2\xa3U`\x10\u07ec\xad\xe6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Ns\xcf#y\xf1$\x86\x0fs\xd6\xd9\x1b\xf5\x9a\xcc\\\xfc\x84[\x89\x02,\xa3X|\xf4\xeb\x00\x00\xe0\x94Nz\xa6~\x12\x18>\xf9\xd7F\x8e\xa2\x8a\xd29\xc2\xee\xf7\x1bv\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\xe0\x94N{TGM\x01\xfe\xfd8\x8d\xfc\xd5;\x9ff&$A\x8a\x05\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94N\x89.\x80\x81\xbf6\xe4\x88\xfd\xdb;&0\xf3\xf1\xe8\xda0\u048a\x02\x8a\xba0u$Q\xfc\x00\x00\xe0\x94N\x8amcH\x9c\xcc\x10\xa5\u007f\x88_\x96\xeb\x04\xec\xbbT`$\x8a\x03\xea\xe3\x13\x0e\u0316\x90\x00\x00\u07d4N\x8eG\xae;\x1e\xf5\f\x9dT\xa3\x8e\x14 \x8c\x1a\xbd6\x03\u0089y(\xdb\x12vf\f\x00\x00\u0794N\x90\u03312X\xac\xaa\x9fO\xeb\xc0\xa3B\x92\xf9Y\x91\xe20\x88\xdbD\xe0I\xbb,\x00\x00\u07d4N\xa5n\x11\x12d\x1c\x03\x8d\x05e\xa9\u0096\xc4c\xaf\xef\xc1~\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\xe0\x94N\xa7\x0f\x041?\xaee\xc3\xff\"J\x05\\=-\xab(\xdd\u07ca\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4N\xb1EKW8\x05\u022c\xa3~\xde\xc7\x14\x9aA\xf6\x12\x02\xf4\x89\x10CV\x1a\x88)0\x00\x00\u07d4N\xb8{\xa8x\x8e\xba\r\xf8~[\x9b\xd5\n\x8eE6\x80\x91\xc1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4N\xbcV)\xf9\xa6\xa6k,\xf36:\u0109\\\x03H\u8fc7\x8967\tlK\xcci\x00\x00\u07d4N\xc7h)^\xea\xba\xfcB\x95\x84\x15\xe2+\xe2\x16\xcd\xe7v\x18\x89\x03;\x1d\xbc9\xc5H\x00\x00\u07d4N\xcc\x19\x94\x8d\xd9\u0347\xb4\xc7 \x1a\xb4\x8eu\x8f(\xe7\xccv\x89\x1b\x1d\xaba\u04ead\x00\x00\u07d4N\xd1M\x81\xb6\v#\xfb%\x05M\x89%\u07e5s\u072eah\x89\x12nr\xa6\x9aP\xd0\x00\x00\xe0\x94N\xe1<\rA \vF\u045d\xee\\K\xce\xc7\x1d\x82\xbb\x8e8\x8a\x01\xab\xee\x13\u033e\ufbc0\x00\u07d4N\xea\xd4\n\xad\x8cs\xef\b\xfc\x84\xbc\n\x92\xc9\t/j6\xbf\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4N\xeb\xe8\f\xb6\xf3\xaeY\x04\xf6\xf4\xb2\x8d\x90\u007f\x90q\x89\xfc\xab\x89lj\xccg\u05f1\xd4\x00\x00\u07d4N\xeb\xf1 ]\f\xc2\f\xeel\u007f\x8f\xf3\x11_V\u050f\xba&\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4N\xf1\xc2\x14c:\xd9\xc0p;N#t\xa2\xe3>>B\x92\x91\x89Hz\x9a0E9D\x00\x00\u07d4N\xfc\xd9\u01df\xb43L\xa6${\n3\xbd\x9c\xc32\b\xe2r\x89Hz\x9a0E9D\x00\x00\xe0\x94O\x06$k\x8dK\u0496a\xf4>\x93v\"\x01\u0486\x93Z\xb1\x8a\x01\x059O\xfcF6\x11\x00\x00\u07d4O\x15+/\xb8e\x9dCwn\xbb\x1e\x81g:\xa8Ai\xbe\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4O\x17\u007f\x9dV\x95=\xedq\xa5a\x1f93\"\xc3\x02y\x89\\\x89\rU\uf422\xda\x18\x00\x00\u07d4O\x1a-\xa5JLm\xa1\x9d\x14$\x12\xe5n\x81WA\xdb#%\x89\x05k\xc7^-c\x10\x00\x00\u07d4O#\xb6\xb8\x17\xff\xa5\xc6d\xac\xda\u05db\xb7\xb7&\xd3\n\xf0\xf9\x89_h\xe8\x13\x1e\u03c0\x00\x00\xe0\x94O&i\f\x99+z1*\xb1.\x13\x85\xd9J\xcdX(\x8e{\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4O+G\xe2wZ\x1f\xa7\x17\x8d\xad\x92\x98Z[\xbeI;\xa6\u0589\n\u05ce\xbcZ\xc6 \x00\x00\u07d4O:HT\x91\x11E\xea\x01\xc6D\x04K\xdb.Z\x96\n\x98/\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4O?,g0i\xac\x97\xc2\x026\a\x15)\x81\xf5\xcd`c\xa0\x89 \x86\xac5\x10R`\x00\x00\xe0\x94OJ\x9b\xe1\f\xd5\xd3\xfb]\xe4\x8c\x17\xbe)o\x89V\x90d[\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4OR\xadap\xd2[*.\x85\x0e\xad\xbbRA?\xf20>\u007f\x89\xa4\xccy\x95c\u00c0\x00\x00\u07d4OX\x01\xb1\xeb0\xb7\x12\u0620WZ\x9aq\xff\x96]O4\xeb\x89\x10CV\x1a\x88)0\x00\x00\u07d4O]\xf5\xb9CW\u0794\x86\x04\xc5\x1bx\x93\xcd\xdf`v\xba\xad\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\u07d4Od\xa8^\x8e\x9a@I\x8c\fu\xfc\xeb\x037\xfbI\b>^\x8965\u026d\xc5\u07a0\x00\x00\u07d4Og9m%S\xf9\x98x_pN\a\xa69\x19}\u0454\x8d\x89\x10DrR\x1b\xa78\x00\x00\u07d4OmG7\u05e9@8$\x87&H\x86i|\xf7c\u007f\x80\x15\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4Os0\toy\xed&N\xe0\x12\u007f]0\xd2\xf7?!\xcb\u007f\x04\x89\x04\x82\xfe&\f\xbc\xa9\x00\x00\u07d4O\xeeP\xc5\xf9\x88 k\t\xa5sF\x9f\xb1\u0434.\xbbm\u0389l\xee\x06\u077e\x15\xec\x00\x00\u07d4O\xf6v\xe2\u007fh\x1a\x98-\x8f\xd9\xd2\x0ed\x8b=\xce\x05\xe9E\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4O\xf6\u007f\xb8\u007fn\xfb\xa9'\x990\u03fd\x1bz4L\u057a\x8bN\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94PFf\u03891\x17^\x11\xa5\xed\x11\xc1\u072a\x06\xe5\u007fNf\x8a\x02\u007f>\u07f3Nn@\x00\x00\u0794PXM\x92\x06\xa4l\xe1\\0\x11\x17\xee(\xf1\\0\xe6\x0eu\x88\xb9\xf6]\x00\xf6<\x00\x00\xe0\x94PZ3\xa1\x864\xddH\x00i)\x13N\x00\x00\u07d4P\u0286\xb5\xeb\x1d\x01\x87M\xf8\xe5\xf3IE\u051cl\x1a\xb8H\x8965\u026d\xc5\u07a0\x00\x00\u07d4P\u0357\xe97\x8b\\\xf1\x8f\x179c#l\x99Q\xeft8\xa5\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4P\u073c'\xbc\xad\x98@\x93\xa2\x12\xa9\xb4\x17\x8e\xab\xe9\x01ua\x89\a\xe3by\v\\\xa4\x00\x00\u07d4P\xe10#\xbd\x9c\xa9j\xd4\xc5?\xdf\xd4\x10\xcbk\x1fB\v\u07c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94P\xe1\xc8\xec\x98A[\xefD&\x18p\x87\x99C{\x86\xe6\xc2\x05\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4P\xf8\xfaK\xb9\xe2g|\x99\nN\xe8\xcep\xdd\x15#%\x1eO\x89\x01i=#\x16Ok\x00\x00\u07d4P\xfb6\xc2q\a\xee,\xa9\xa3#n'F\u0321\x9a\xcekI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4P\xfe\xf2\x96\x95U\x88\u02aet\xc6.\xc3*#\xa4T\xe0\x9a\xb8\x89A\x1d\xff\xab\xc5\a8\x00\x00\u07d4Q\x02\xa4\xa4 w\xe1\x1cX\xdfGs\u3b14F#\xa6m\x9f\x89lp\x15\xfdR\xed@\x80\x00\u07d4Q\x03\x93w\xee\xd0\xc5s\xf9\x86\xc5\xe8\xa9_\xb9\x9aY\xe93\x0f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Q\x03\xbc\t\x93>\x99!\xfdS\xdcSo\x11\xf0]\rG\x10}\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94Q\x04\xec\xc0\xe30\xdd\x1f\x81\xb5\x8a\xc9\u06f1\xa9\xfb\xf8\x8a<\x85\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4Q\r\x81Y\u0314Wh\xc7E\a\x90\xba\a>\xc0\xd9\xf8\x9e0\x89\x8a\xc7#\x04\x89\xe8\x00\x00\x00\u07d4Q\x0e\xdaV\x01I\x9a\r^\x1a\x00k\xff\xfd\x836r\xf2\xe2g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x12dF\xab=\x802U~\x8e\xbaeY}u\xfa\u0701\\\x89\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\xe0\x94Q\x18U}`\r\x05\xc2\xfc\xbf8\x06\xff\xbd\x93\xd0 %\xd70\x8a\x02g\u04ebd#\xf5\x80\x00\x00\u07d4Q\x1e\x0e\xfb\x04\xacN?\xf2\xe6U\x0eI\x82\x95\xbf\xcdV\xff\u0549$=M\x18\"\x9c\xa2\x00\x00\u07d4Q!\x16\x81{\xa9\xaa\xf8C\xd1P|e\xa5\xead\n{\x9e\xec\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4Q&F\ri,q\u026fo\x05WM\x93\x99\x83h\xa27\x99\x89\x02\u0465\x1c~\x00P\x00\x00\u07d4Q'\u007f\xe7\xc8\x1e\xeb\xd2R\xa0=\xf6\x9ak\x9f2n'\"\a\x89\x03@.y\u02b4L\x80\x00\u07d4Q)oPD'\r\x17pvF\x12\x9c\x86\xaa\xd1d^\xad\xc1\x89H|r\xb3\x10\xd4d\x80\x00\xe0\x94Q+\x91\xbb\xfa\xa9\xe5\x81\xefh?\xc9\r\x9d\xb2*\x8fI\xf4\x8b\x8aA\xa5\"8m\x9b\x95\xc0\x00\x00\u07d4Q5\xfb\x87W`\f\xf4tTbR\xf7M\xc0tm\x06&,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4QF2\xef\xbdd,\x04\xdel\xa3B1]@\u0750\xa2\u06e6\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4QKu\x12\u026e^\xa6<\xbf\x11q[c\xf2\x1e\x18\u0496\xc1\x89lj\xccg\u05f1\xd4\x00\x00\u07d4QS\xa0\xc3\u0211(\x81\xbf\x1c5\x01\xbfd\xb4VI\xe4\x82\"\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94QVQ\xd6\xdbO\xaf\x9e\xcd\x10:\x92\x1b\xbb\xbej\xe9p\xfd\u050a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94Q_0\xbc\x90\xcd\xf4W~\xe4}e\u05c5\xfb\xe2\xe87\u01bc\x8a\x02'\x1b^\x01\x8b\xa0X\x00\x00\u07d4Q`\xeda.\x1bH\xe7??\xc1[\xc42\x1b\x8f#\xb8\xa2K\x89\x1e\x82kB(e\xd8\x00\x00\u07d4Qa\xfdI\xe8G\xf6tU\xf1\u023bz\xbb6\xe9\x85&\r\x03\x89A\rXj \xa4\xc0\x00\x00\u07d4QiT\x02_\xca&\b\xf4}\xa8\x1c!^\xed\xfd\x84J\t\xff\x89\x14\xb5P\xa0\x13\xc78\x00\x00\u07d4Qi\xc6\n\xeeL\xee\u0444\x9a\xb3mfL\xff\x97\x06\x1e\x8e\xa8\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4Q|uC\r\xe4\x01\xc3A\x03&\x86\x11'\x90\xf4mM6\x9e\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4Q|\xd7`\x8e]\r\x83\xa2kq\u007f6\x03\xda\xc2'}\u00e4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x86]\xb1H\x88\x19Q\xf5\x12Qq\x0e\x82\xb9\xbe\r~\xad\xb2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x89\x1b,\xcd\xd2\xf5\xa4K*\x8b\u011a]\x9b\xcadw%\x1c\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4Q\x8c\xef'\xb1\x05\x82\xb6\xd1OiH=\u06a0\xdd<\x87\xbb\\\x89 \x86\xac5\x10R`\x00\x00\u07d4Q\xa6\xd6'\xf6j\x89#\u060d`\x94\xc4qS\x80\xd3\x05|\xb6\x89>s\xd2z5\x94\x1e\x00\x00\u07d4Q\xa8\xc2\x166\x02\xa3.\xe2L\xf4\xaa\x97\xfd\x9e\xa4\x14QiA\x89\x03h\xf7\xe6\xb8g,\x00\x00\u07d4Q\xb4u\x8e\x9e\x14P\xe7\xafBh\xc3\u01f1\xe7\xbdo\\uP\x8965\u026d\xc5\u07a0\x00\x00\u07d4Q\u028b\xd4\xdcdO\xacG\xafgUc\u0540J\r\xa2\x1e\xeb\x89*\xb7\xb2`\xff?\xd0\x00\x00\u07d4Q\xd2K\xc3so\x88\xddc\xb7\" &\x88f0\xb6\ub1cd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\u05cb\x17\x8dp~9n\x87\x10\x96\\OA\xb1\xa1\xd9\x17\x9d\x89\x05\xfe\xe2\"\x04\x1e4\x00\x00\u07d4Q\xe3/\x14\xf4\xca^(|\xda\xc0W\xa7y^\xa9\xe0C\x99S\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Q\xe4?\xe0\xd2\\x(`\xaf\x81\xea\x89\xddy<\x13\xf0\u02f1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4Q\xe7\xb5\\/\x98 \xee\xd78\x846\x1bPf\xa5\x9boE\u0189lk\x93[\x8b\xbd@\x00\x00\xe0\x94Q\xea\x1c\t4\xe3\xd0@\"\ud715\xa0\x87\xa1P\xefp^\x81\x8a\x01Tp\x81\xe7\"M \x00\x00\u07d4Q\xee\f\xca;\xcb\x10\xcd>\x987\"\xce\xd8I=\x92l\bf\x8965f3\xeb\xd8\xea\x00\x00\xe0\x94Q\xf4f:\xb4O\xf7\x93E\xf4'\xa0\xf6\xf8\xa6\u0225?\xf24\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Q\xf5^\xf4~dV\xa4\x18\xab2\xb9\"\x1e\xd2}\xbaf\b\xee\x89\u3bb5sr@\xa0\x00\x00\xe0\x94Q\xf9\xc42\xa4\xe5\x9a\xc8b\x82\u05ad\xabL.\xb8\x91\x91`\xeb\x8ap;[\x89\u00e6\xe7@\x00\x00\u07d4R\x0ff\xa0\xe2e\u007f\xf0\xacA\x95\xf2\xf0d\xcf/\xa4\xb2BP\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4R\x10#T\xa6\xac\xa9]\x8a.\x86\xd5\u07bd\xa6\xdei4`v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\x13\xf4Y\xe0x\xad:\xb9Z\t #\x9f\xcf\x163\xdc\x04\u0289\x8c\xf2\x18|*\xfb\x18\x80\x00\u07d4R\x15\x18;\x8f\x80\xa9\xbc\x03\xd2l\xe9\x12\a\x83*\r9\xe6 \x8965\u026d\xc5\u07a0\x00\x00\xe0\x94R!Cx\xb5@\x04\x05j|\xc0\x8c\x89\x13'y\x8a\u01b2H\x8a\x037\xfe_\xea\xf2\u0440\x00\x00\xe0\x94R##\xaa\xd7\x1d\xbc\x96\xd8Z\xf9\x0f\bK\x99\xc3\xf0\x9d\ucdca\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4R>\x14\r\xc8\x11\xb1\x86\xde\xe5\xd6\u020b\xf6\x8e\x90\xb8\xe0\x96\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R?mdi\x0f\xda\u0354(SY\x1b\xb0\xff \xd3em\x95\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4RO\xb2\x10R,^#\xbbg\u07ff\x8c&\xaaam\xa4\x99U\x8965b\xa6m4#\x80\x00\u07d4RU\xdci\x15ZE\xb9p\xc6\x04\xd3\x00G\xe2\xf50i\x0e\u007f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4R`\xdcQ\xee\a\xbd\u06ab\xab\xb9\xeetK9<\u007fG\x93\xa6\x89\x01\xd8f_\xa5\xfaL\x00\x00\u07d4Rg\xf4\xd4\x12\x92\xf3p\x86<\x90\u05d3)i\x03\x846%\u01c9K\xe4\xe7&{j\xe0\x00\x00\u07d4Rk\xb53\xb7n \xc8\xee\x1e\xbf\x12?\x1e\x9f\xf4\x14\x8e@\xbe\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4Rl\xb0\x9c\u3b63g.\xec\x1d\xebF [\xe8\x9aKV>\x89\x85\xcaa[\xf9\xc0\x10\x00\x00\u07d4Rs\x8c\x90\xd8`\xe0L\xb1/I\x8d\x96\xfd\xb5\xbf6\xfc4\x0e\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4Rz\x8c\xa1&\x863\xa6\xc99\xc5\xde\x1b\x92\x9a\ue4ae\xac\x8d\x890\xca\x02O\x98{\x90\x00\x00\u07d4R\x81\x01\xceF\xb7 \xa2!M\u036ef\x18\xa51w\xff\xa3w\x89\x1b\x96\x12\xb9\xdc\x01\xae\x00\x00\xe0\x94R\x81s4s\xe0\r\x87\xf1\x1e\x99U\u5275\x9fJ\u008ez\x8a\x8b\xd6/\xf4\xee\xc5Y \x00\x00\u07d4R\x98\xab\x18*\x195\x9f\xfc\xec\xaf\xd7\u0475\xfa!-\xed\xe6\u0749\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4R\x9a\xa0\x02\u0196*:\x85E\x02\u007f\u0630_\"\xb5\xbf\x95d\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4R\x9e\x82O\xa0rX+@2h:\xc7\xee\xcc\x1c\x04\xb4\xca\xc1\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94R\xa5\xe4\xdeC\x93\xee\xcc\xf0X\x1a\xc1\x1bR\u0183\xc7n\xa1]\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4R\xb4%|\xf4\x1bn(\x87\x8dP\xd5{\x99\x91O\xfa\x89\x87:\x89\xd5\r\u026a,Aw\x00\x00\u07d4R\xb8\xa9Y&4\xf70\v|\\Y\xa34[\x83_\x01\xb9\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\xbd\u066fYx\x85\v\xc2A\x10q\x8b7#u\x9bC~Y\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4R\xcd @;\xa7\xed\xa6\xbc0z=c\xb5\x91\x1b\x81|\x12c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794R\u04c0Q\x1d\xf1\x9d^\u0080{\xbc\xb6vX\x1bg\xfd7\xa3\x88\xb9\xf6]\x00\xf6<\x00\x00\xe0\x94R\xe1s\x13P\xf9\x83\xcc,A\x89\x84/\xde\x06\x13\xfa\xd5\f\xe1\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\u07d4R\xe4g\x832\x9av\x93\x01\xb1u\x00\x9d4gh\xf4\xc8~\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\xf0X\xd4aG\xe9\x00m)\xbf,\t0J\xd1\xcd\xddn\x15\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4R\xf1T#2<$\xf1\x9a\xe2\xabg7\x17\"\x9d?t}\x9b\x897\xa04\xcb\xe8\xe3\xf3\x80\x00\u07d4R\xf8\xb5\t\xfe\xe1\xa8t\xabo\x9d\x876\u007f\xbe\xaf\x15\xac\x13\u007f\x8965\u026d\xc5\u07a0\x00\x00\u07d4R\xfbF\xac]\x00\xc3Q\x8b,:\x1c\x17}D/\x81eU_\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4S\x00w\xc9\xf7\xb9\a\xff\x9c\xec\fw\xa4\x1ap\xe9\x02\x9a\xddJ\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\x03\x19\xdb\n\x8f\x93\xe5\xbb}M\xbfH\x161O\xbe\xd86\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\x04}\u022c\x90\x83\xd9\x06r\xe8\xb3G<\x10\f\xcd'\x83#\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4S\va\xe4/9Bm$\b\xd4\bR\xb9\xe3J\xb5\xeb\xeb\u0149\x0e~\xeb\xa3A\vt\x00\x00\u07d4S\x0f\xfa\u00fc4\x12\xe2\xec\x0e\xa4{y\x81\xc7p\xf5\xbb/5\x89\a?u\u0460\x85\xba\x00\x00\u07d4S\x17\xec\xb0#\x05,\xa7\xf5e+\xe2\xfa\x85L\xfeEc\xdfM\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4S\x19M\x8a\xfa>\x885\x02v~\xdb\xc3\x05\x86\xaf3\xb1\x14\u04c9lk\x93[\x8b\xbd@\x00\x00\u07d4S*}\xa0\xa5\xadt\aF\x8d;\xe8\xe0~i\xc7\xddd\xe8a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4S-2\xb0\x0f0[\xcc$\xdc\xefV\x81}b/4\xfb,$\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4S4DX@\x82\xeb\xa6T\xe1\xad0\xe1Is\\o{\xa9\"\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4S8\xefp\xea\xc9\u075a\xf5\xa0P;^\xfa\xd1\x03\x9eg\xe7%\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94S9oJ&\u00b4`D\x960lTB\xe7\xfc\xba'.6\x8a\x04?/\b\xd4\x0eZ\xfc\x00\x00\xe0\x94S:s\xa4\xa2\"\x8e\xee\x05\xc4\xff\xd7\x18\xbb\xf3\xf9\xc1\xb1)\xa7\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4S<\x06\x92\x8f\x19\u0429V\xcc(\x86k\xf6\xc8\xd8\xf4\x19\x1a\x94\x89\x0f\xd8\xc1C8\xe60\x00\x00\u07d4S@e6\x1c\xb8T\xfa\xc4+\xfb\\\x9f\xcd\xe0`J\xc9\x19\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4SC\u007f\xec\xf3J\xb9\xd45\xf4\u07b8\xca\x18\x15\x19\xe2Y 5\x89\n1\x06+\xee\xedp\x00\x00\u07d4SR\x01\xa0\xa1\xd74\"\x80\x1fU\xde\xd4\u07ee\xe4\xfb\xaan;\x89\x02&!\x1fy\x15B\x80\x00\xe0\x94S`\x81\x05\xceK\x9e\x11\xf8k\xf4\x97\xff\xca;x\x96{_\x96\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4SnM\x80)\xb7?Uy\u0723>p\xb2N\xba\x89\xe1\x1d~\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Sp\rS%MC\x0f\"x\x1aJv\xa4c\x93;]k\b\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94S\u007f\x9dM1\xefp\x83\x9d\x84\xb0\xd9\u0377+\x9a\xfe\xdb\xdf5\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\xe0\x94S\x81D\x85\x03\xc0\xc7\x02T+\x1d\xe7\xcc_\xb5\xf6\xab\x1c\xf6\xa5\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94S\x94.yI\xd6x\x8b\xb7\x80\xa7\xe8\xa0y'\x81\xb1aK\x84\x8a\x03]\xebFhO\x10\xc8\x00\x00\u07d4S\x95\xa4E]\x95\xd1x\xb4S*\xa4r[\x19?\xfeQ)a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94S\x98\x9e\xd30V?\xd5}\xfe\u027d4<7`\xb0y\x93\x90\x8a\x01P\x89N\x84\x9b9\x00\x00\x00\u07d4S\xa2Dg(\x95H\x0fJ+\x1c\xdf}\xa5\xe5\xa2B\xecM\xbc\x8965\u026d\xc5\u07a0\x00\x00\u07d4S\xa7\x14\xf9\x9f\xa0\x0f\xefu\x8e#\xa2\xe7F2m\xad$|\xa7\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4S\xaf2\xc2/\uf640?\x17\x8c\xf9\v\x80/\xb5q\xc6\x1c\xb9\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4S\xc0\xbb\u007f\u020e\xa4\"\xd2\xef~T\x0e-\x8f(\xb1\xbb\x81\x83\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94S\xc5\xfe\x01\x19\xe1\xe8Hd\f\xee0\xad\ua594\x0f*]\x8b\x8a\x04\x9a\xda_\xa8\xc1\f\x88\x00\x00\u07d4S\xc9\xec\xa4\ts\xf6;\xb5\x92{\xe0\xbcj\x8a\x8b\xe1\x95\x1ft\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\u0388\xe6lZ\xf2\U0009bf4fY*V\xa3\xd1_ l2\x89\a\xa2\x8c1\xcc6\x04\x00\x00\u07d4S\xce\xc6\u0200\x92\xf7V\xef\xe5o}\xb1\x12(\xa2\xdbE\xb1\"\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4S\xe3[\x12#\x1f\x19\xc3\xfdwL\x88\xfe\xc8\xcb\xee\xdf\x14\b\xb2\x89\x1b\xc1mgN\xc8\x00\x00\x00\u07d4S\xe4\xd9im\xcb?M{?p\u072aN\xec\xb7\x17\x82\xff\\\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4S\xfa\xf1e\xbe\x03\x1e\xc1\x830\xd9\xfc\xe5\xbd\x12\x81\xa1\xaf\b\u06c9\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4T\n\x18\x19\xbd|5\x86\x1ey\x18\x04\xe5\xfb\xb3\xbc\x97\u026b\xb1\x89N\xd7\xda\xc6B0 \x00\x00\xe0\x94T\f\a(\x02\x01N\xf0\xd5a4Z\xecH\x1e\x8e\x11\xcb5p\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94T\f\xf2=\xd9\\MU\x8a'\x9dw\x8d+75\xb3\x16A\x91\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4T\x10`\xfcX\xc7P\xc4\x05\x12\xf83i\xc0\xa63@\xc1\"\xb6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4T\x13\xc9\u007f\xfaJn*{\xba\x89a\u071f\u03850\xa7\x87\u05c965\u026d\xc5\u07a0\x00\x00\u07d4T\x1d\xb2\n\x80\xcf;\x17\xf1b\x1f\x1b?\xf7\x9b\x88/P\xde\xf3\x8965\u026d\xc5\u07a0\x00\x00\u07d4T.\x80\x96\xba\xfb\x88\x16&\x06\x00.\x8c\x8a>\u0458\x14\xae\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T1\v:\xa8\x87\x03\xa7%\u07e5}\xe6\xe6F\x93Qd\x80,\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4T1\xb1\u0447Q\xb9\x8f\xc9\u220a\xc7u\x9f\x155\xa2\xdbG\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T1\xcaB~ae\xa6D\xba\xe3&\xbd\tu\n\x17\x8ce\r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T5\xc6\xc1y3\x17\xd3,\xe1;\xbaLO\xfe\xb9s\xb7\x8a\u0709\r\x8ek\x1c\x12\x85\xef\x00\x00\xe0\x94T6)\xc9\\\xde\xf4(\xad7\xd4S\u02958\xa9\xf9\t\x00\xac\x8a\t(\x96R\x9b\xad\u0708\x00\x00\u07d4T9\x1bM\x17mGl\xea\x16N_\xb55\u0197\x00\xcb%5\x89\x05l\xd5_\xc6M\xfe\x00\x00\xe0\x94T:\x8c\x0e\xfb\x8b\xcd\x15\xc5C\u29a4\xf8\aYv1\xad\xef\x8a\x01?\x80\xe7\xe1O-D\x00\x00\u07d4T?\x8cgN$b\xd8\xd5\u06a0\xe8\x01\x95\xa8p\x8e\x11\xa2\x9e\x89\x03wX\x83;:z\x00\x00\xe0\x94TK[5\x1d\x1b\xc8.\x92\x97C\x99H\xcfHa\xda\u026e\x11\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4TM\xdaB\x1d\xc1\xebs\xbb$\xe3\xe5j$\x80\x13\xb8|\x0fD\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4TW\\1\x14u\x1e\x14o\xfe\u00c7nE\xf2\x0e\xe8AJ\u07ba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4T\xb4B\x9b\x18/\x03w\xbe~bi9\xc5\xdbd@\xf7]z\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4T\xbc\xb8\xe7\xf7<\xda=s\xf4\u04cb-\bG\xe6\x00\xba\r\xf8\x89:pAX\x82\xdf\x18\x00\x00\u07d4T\xc9>\x03\xa9\xb2\xe8\xe4\xc3g(5\xa9\xeev\xf9a[\xc1N\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4T\u0388'YV\xde\xf5\xf9E\x8e;\x95\xde\xca\xcdH@!\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T\xdb^\x06\xb4\x81]1\xcbV\xa8q\x9b\xa3:\xf2\xd7>rR\x89$R\x1e*0\x17\xb8\x00\x00\xe0\x94T\xe0\x12\x83\u030b8E8\xdddgp\xb3W\xc9`\xd6\xca\u034a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4T\xecs\x00\xb8\x1a\xc8C3\xed\x1b\x03<\xd5\u05e39r\xe24\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4T\xfe\xbc\xce \xfez\x90\x98\xa7U\xbd\x90\x98\x86\x02\xa4\x8c\b\x9e\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4U\n\xad\xae\x12!\xb0z\xfe\xa3\x9f\xba.\xd6.\x05\u5df5\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4U\f0o\x81\xef]\x95\x80\xc0l\xb1\xab \x1b\x95\xc7H\xa6\x91\x89$\x17\xd4\xc4p\xbf\x14\x00\x00\xe0\x94U\x19\x99\xdd\xd2\x05V3'\xb9\xb50xZ\xcf\xf9\xbcs\xa4\xba\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4U\x1ew\x84w\x8e\xf8\xe0H\xe4\x95\xdfI\xf2aO\x84\xa4\xf1\u0709 \x86\xac5\x10R`\x00\x00\xe0\x94U)\x83\na\xc1\xf1<\x19~U\v\xed\xdf\u05bd\x19\\\x9d\x02\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4U)\x87\xf0e\x1b\x91[.\x1eS(\xc1!\x96\rK\xddj\xf4\x89a\t=|,m8\x00\x00\u07d4U;k\x1cW\x05\x0e\x88\xcf\f1\x06{\x8dL\xd1\xff\x80\xcb\t\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4U?7\xd9$fU\x0e\x9f\xd7u\xaet6-\xf00\x17\x912\x89lk\x93[\x8b\xbd@\x00\x00\u07d4UC6\xeeN\xa1U\xf9\xf2O\x87\xbc\xa9\xcar\xe2S\xe1,\u0489\x05k\xc7^-c\x10\x00\x00\u0794UC\xddm\x16\x9e\xec\x8a!;\xbfz\x8a\xf9\xff\xd1]O\xf7Y\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4UG\xfd\xb4\xae\x11\x95>\x01)+x\a\xfa\x92#\xd0\xe4`j\x89\x05]\x11}\xcb\x1d&\x00\x00\u07d4UR\xf4\xb3\xed>\x1d\xa7\x9a/x\xbb\x13\xe8\xaeZh\xa9\xdf;\x8965\u026d\xc5\u07a0\x00\x00\u07d4U\\\xa9\xf0\\\xc14\xabT\xae\x9b\xea\x1c?\xf8z\xa8Q\x98\u0289\x05k\xc7^-c\x10\x00\x00\xe0\x94U]\x8d<\xe1y\x8a\u0290'T\xf1d\xb8\xbe*\x022\x9cl\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4U]\xf1\x93\x90\xc1m\x01)\x87r\xba\xe8\xbc:\x11R\x19\x9c\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4U^\xbe\x84\u06a4+\xa2V\xeax\x91\x05\xce\u0136\x93\xf1/\x18\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94U\u007f^e\xe0\xda3\x99\x82\x19\xadN\x99W\x05E\xb2\xa9\xd5\x11\x8a\x02U\x9c\xbb\x98XB@\x00\x00\u07d4U\x83` h\x83\xdd\x1bmJYc\x9eV)\xd0\xf0\xc6u\u0409lk\x93[\x8b\xbd@\x00\x00\u07d4U\x84B0P\xe3\xc2\x05\x1f\v\xbd\x8fD\xbdm\xbc'\xec\xb6,\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4U\x85)CI)p\xf8\xd6)\xa1Sf\xcd\xda\x06\xa9OE\x13\x89lk\x93[\x8b\xbd@\x00\x00\u0794U\x86d\x86\xec\x16\x8fy\xdb\xe0\u1af1\x88d\u0649\x91\xae,\x88\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4U\x8cTd\x9a\x8an\x94r+\xd6\xd2\x1d\x14qOqx\x054\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\x91\x940O\x14\xb1\xb9:\xfeDO\x06$\xe0S\xc2:\x00\t\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4U\x93\xc9\u0536ds\x0f\xd9<\xa6\x01Q\xc2\\.\xae\xd9<;\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4U\x97\x06\xc32\xd2\ay\xc4_\x8am\x04ji\x91Y\xb7I!\x89\x14\x9bD.\x85\xa3\u03c0\x00\u07d4U\x98\xb3\xa7\x9aH\xf3+\x1f_\xc9\x15\xb8{d]\x80]\x1a\xfe\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4U\xa3\xdfW\xb7\xaa\xec\x16\xa1b\xfdS\x16\xf3[\xec\b(!\u03c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4U\xa4\xca\xc0\u02cbX-\x9f\xef8\xc5\xc9\xff\xf9\xbdS\t=\x1f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4U\xa6\x1b\x10\x94\x80\xb5\xb2\xc4\xfc\xfd\xef\x92\xd9\x05\x84\x16\f\r5\x89\x02lVM+S\xf6\x00\x00\u07d4U\xaa]1>\xbb\bM\xa0\xe7\x80\x10\x91\u2792\xc5\xde\u00ea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\xab\x99\xb0\xe0\xe5]{\xb8t\xb7\xcf\xe84\xdec\x1c\x97\xec#\x897\xe9\x8c\xe3h\x99\xe4\x00\x00\u07d4U\xaf\t/\x94\xbajy\x91\x8b\f\xf99\xea\xb3\xf0\x1b?Q\u01c9\b \xd5\xe3\x95v\x12\x00\x00\u07d4U\xc5dfAf\xa1\xed\xf3\x91>\x01i\xf1\xcdE\x1f\xdb]\f\x89\x82\x17\xeaIP\x8el\x00\x00\xe0\x94U\xcaj\xbey\xea$\x97\xf4o\u06f804`\x10\xfeF\x9c\xbe\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4U\xca\xffK\xba\x04\xd2 \u0265\xd2\x01\x86r\xec\x85\xe3\x1e\xf8>\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\xd0W\xbc\xc0K\xd0\xf4\xaf\x96BQ:\xa5\t\v\xb3\xff\x93\xfe\x89;\xfeE,\x8e\xddL\x00\x00\u07d4U\xd4.\xb4\x95\xbfF\xa64\x99{_.\xa3b\x81I\x18\u2c09\x05\xc0\xd2e\xb5\xb2\xa8\x00\x00\u07d4U\u069d\xcd\xcaa\xcb\xfe\x1f\x13<{\xce\xfc\x86{\x9c\x81\"\xf9\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4U\xe2 \x87bb\xc2\x18\xafOVxG\x98\xc7\xe5]\xa0\x9e\x91\x89\a=\x99\xc1VE\xd3\x00\x00\u07d4U\xfd\b\u0440d\xbd ,\x0e\xc3\xd2\xcc\xe0\xce\v\x9d\x16\x9cM\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4V\x00s\nU\xf6\xb2\x0e\xbd$\x81\x1f\xaa=\xe9m\x16b\xab\xab\x89e\xea=\xb7UF`\x00\x00\u07d4V\x03$\x1e\xb8\xf0\x8fr\x1e4\x8c\x9d\x9a\xd9/H\u342a$\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4V\x056yJ\x9e+\x00I\xd1\x023\xc4\x1a\xdc_A\x8a&J\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\aY\x00Y\xa9\xfe\xc1\x88\x11I\xa4K6\x94\x9a\xef\x85\xd5`\x89lk\x93[\x8b\xbd@\x00\x00\u07d4V\v\xec\xdfR\xb7\x1f=\x88'\xd9'a\x0f\x1a\x98\x0f3qo\x89\x17GMp_V\u0400\x00\xe0\x94V\r\xa3~\x95m\x86/\x81\xa7_\u0540\xa7\x13\\\x1b$cR\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94V\x0f\xc0\x8d\a\x9f\x04~\xd8\xd7\xdfuU\x1a\xa55\x01\xf5p\x13\x8a\x01\x9b\xff/\xf5yh\xc0\x00\x00\u07d4V\x1b\xe9)\x9b>k>c\xb7\x9b\t\x16\x9d\x1a\x94\x8a\xe6\xdb\x01\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94V \xe3\xedy-/\x185\xfe_UA}Q\x11F\fj\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4V \xf4m\x14Q\xc25=bC\xa5\u0534'\x13\v\xe2\xd4\a\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94V!\x05\xe8+\t\x975\xdeI\xf6&\x92\u0307\xcd8\xa8\xed\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94V*\x8d\u02fe\xee\xf7\xb3`h]'0;\u059e\tJ\xcc\xf6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4V+\xce\u04ca\xb2\xabl\b\x0f;\x05A\xb8Enp\x82K?\x89\"\xca5\x87\xcfN\xb0\x00\x00\xe0\x94V+\xe9Z\xba\x17\xc57\x1f\u2e82\x87\x99\xb1\xf5]!w\u058a\b\x16\xd3~\x87\xb9\xd1\xe0\x00\x00\u07d4V/\x16\u05da\xbf\xce\u00d4>4\xb2\x0f\x05\xf9{\xdf\u0366\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4V7=\xaa\xb4c\x16\xfd~\x15v\xc6\x1ej\xff\xcbeY\xdd\u05c9\v\xacq]\x14l\x9e\x00\x00\u07d4V9v8\xbb<\xeb\xf1\xf6 byK^\xb9B\xf9\x16\x17\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4V:\x03\xab\x9cV\xb6\x00\xf6\xd2[f\f!\xe1c5Qzu\x8965\u026d\xc5\u07a0\x00\x00\u07d4V<\xb8\x80<\x1d2\xa2['\xb6A\x14\x85+\xd0M\x9c \u0349\v\x14\x9e\xad\n\xd9\xd8\x00\x00\u07d4VXc\x91\x04\fW\xee\xc6\xf5\xaf\xfd\x8c\u052b\xde\x10\xb5\n\u0309\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Vl\x10\xd68\u8e0bG\xd6\xe6\xa4\x14Iz\xfd\xd0\x06\x00\u0509\x05k9Bc\xa4\f\x00\x00\u07d4Vl(\xe3L8\b\xd9vo\xe8B\x1e\xbfO+\x1cO}w\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4V\x8d\xf3\x18Vi\x9b\xb5\xac\xfc\x1f\xe1\u0580\u07d9`\xcaCY\x89J\xcfUR\xf3\xb2I\x80\x00\u07d4V\x91\xdd/gE\xf2\x0e\"\xd2\xe1\u0479U\xaa)\x03\xd6VV\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4V\xa1\xd6\r@\xf5\u007f0\x8e\xeb\xf0\x87\xde\xe3\xb3\u007f\x1e|,\xba\x89>\u072e\xc8-\x06\xf8\x00\x00\u07d4V\xac \xd6;\xd8\x03Y\\\xec\x03m\xa7\xed\x1d\xc6n\n\x9e\a\x89\x03w*S\xcc\xdce\x80\x00\u07d4V\xb6\xc2=\xd2\uc434r\x8f;\xb2\xe7d\xc3\xc5\f\x85\xf1D\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\xdf\x05\xba\xd4l?\x00\xaeGn\xcf\x01{\xb8\xc8w8?\xf1\x89\n\xb1]\xaa\xefp@\x00\x00\u07d4V\xee\x19\u007fK\xbf\x9f\x1b\x06b\xe4\x1c+\xbd\x9a\xa1\xf7\x99\xe8F\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\xf4\x93\xa3\xd1\b\xaa\xa2\u044d\x98\x92/\x8e\xfe\x16b\u03f7=\x89m\x81!\xa1\x94\xd1\x10\x00\x00\u07d4V\xfc\x1a{\xad@G#|\xe1\x16\x14b\x96#\x8e\a\x8f\x93\xad\x89\t\xa6?\b\xeac\x88\x00\x00\u07d4V\xfe\xbf\x9e\x10\x03\xaf\x15\xb1\xbdI\a\xec\b\x9aJ\x1b\x91\xd2h\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4W\x17\u0313\x01Q\x1dJ\x81\xb9\xf5\x83\x14\x8b\xee\xd3\xd3\u0303\t\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4W\x17\xf2\xd8\xf1\x8f\xfc\xc0\xe5\xfe$}:B\x19\x03|:d\x9c\x89\u063beI\xb0+\xb8\x00\x00\u07d4W\x19P\xea,\x90\xc1B}\x93\x9da\xb4\xf2\xdeL\xf1\u03ff\xb0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4W\x19\xf4\x9br\r\xa6\x88V\xf4\xb9\xe7\b\xf2VE\xbd\xbcKA\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4W*\xc1\xab\xa0\xde#\xaeA\xa7\xca\xe1\xdc\bB\u062b\xfc\x10;\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94W-\xd8\xcd?\xe3\x99\xd1\xd0\xec(\x121\xb7\xce\xfc \xb9\u4eca\x023\xc8\xfeBp>\x80\x00\x00\xe0\x94WI!\x83\x8c\xc7}l\x98\xb1}\x90::\xe0\xee\r\xa9[\u040a\vS(\x17\x8a\xd0\xf2\xa0\x00\x00\u07d4WJ\xd95S\x90\u421e\xf4*\xcd\x13\x8b*'\xe7\x8c\x00\xae\x89Tg\xb72\xa9\x134\x00\x00\u07d4WM\xe1\xb3\xf3\x8d\x91XF\xae7\x18VJZ\xda \xc2\xf3\xed\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94W\\\x00\u0081\x82\x10\u0085U\xa0\xff)\x01\x02\x89\xd3\xf8#\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94Ws\xb6\x02g!\xa1\xdd\x04\xb7\x82\x8c\xd6+Y\x1b\xfb4SL\x8a\x05\xb7\xacES\xdez\xe0\x00\x00\xe0\x94WwD\x1c\x83\xe0?\v\xe8\xdd4\v\xdechP\x84|b\v\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Wx\xff\u071b\x94\u0165\x9e\"N\xb9e\xb6\u0790\xf2\"\xd1p\x89\x12-\u007f\xf3f\x03\xfc\x00\x00\u07d4Wz\xee\xe8\u053c\b\xfc\x97\xab\x15n\xd5\u007f\xb9p\x92Sf\xbe\x89\x12\r\xf1\x14rX\xbf\x00\x00\u07d4W{-\a\xe9\xcfRJ\x18\u04c9\x15Vak\x96\x06g\x00\x00\u07d4W\xd5\xfd\x0e=0I3\x0f\xfc\xdc\xd0 Ei\x17e{\xa2\u0689k\xf2\x01\x95\xf5T\xd4\x00\x00\u07d4W\u0754q\xcb\xfa&'\t\xf5\U00106f37t\xc5\xf5'\xb8\xf8\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4W\xdf#\xbe\xbd\xc6^\xb7_\ub732\xfa\xd1\xc0si++\xaf\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4X\x00\u03410\x83\x9e\x94I]-\x84\x15\xa8\xea,\x90\xe0\xc5\u02c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94X\x03\xe6\x8b4\xda\x12\x1a\xef\b\xb6\x02\xba\u06ef\xb4\xd1$\x81\u028a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\xe0\x94X\x16\xc2hww\xb6\xd7\u04a2C-Y\xa4\x1f\xa0Y\xe3\xa4\x06\x8a\x1cO\xe4:\xdb\n^\x90\x00\x00\u07d4X\x1a:\xf2\x97\xef\xa4Cj)\xaf\x00r\x92\x9a\xbf\x98&\xf5\x8b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\x1b\x9f\xd6\xea\xe3r\xf3P\x1fB\xeb\x96\x19\xee\xc8 \xb7\x8a\x84\x8a\x04+\xe2\xc0\f\xa5;\x8d\x80\x00\u07d4X\x1b\xdf\x1b\xb2v\xdb\u0746\xae\xdc\xdb9z\x01\xef\xc0\xe0\f[\x8965\u026d\xc5\u07a0\x00\x00\u07d4X\x1f4\xb5#\xe5\xb4\x1c\t\xc8|)\x8e)\x9c\xbc\x0e)\xd0f\x89=X3\xaa\xfd9u\x80\x00\xe0\x94X$\xa7\xe2(8'q40\x8c_KP\u06b6^C\xbb1\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4X+pf\x9c\x97\xaa\xb7\u0581H\xd8\xd4\xe9\x04\x11\xe2\x81\rV\x8965f3\xeb\xd8\xea\x00\x00\u07d4X.|\xc4o\x1d{Nn\x9d\x95\x86\x8b\xfd7\x05s\x17\x8fL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4X>\x83\xbaU\xe6~\x13\xe0\xe7o\x83\x92\xd8s\xcd!\xfb\xf7\x98\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Xi\xfb\x86}q\xf18\u007f\x86;i\x8d\t\xfd\xfb\x87\u011b\\\x89\u01bb\xf8X\xb3\x16\b\x00\x00\u07d4X}hI\xb1h\xf6\xc33+z\xba\xe7\xeblB\xc3\u007fH\xbf\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4X\x87\xdcj3\xdf\xedZ\xc1\xed\xef\xe3^\xf9\x1a!b1\xac\x96\x89\r\x8drkqw\xa8\x00\x00\xe0\x94X\x8e\u0650\xa2\xaf\xf4J\x94\x10]X\xc3\x05%w5\xc8h\xac\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4X\xae-\xdc_L\x8a\u0697\xe0l\x00\x86\x17\x17g\xc4#\xf5\u05c9WG=\x05\u06ba\xe8\x00\x00\u07d4X\xae\xd6gJ\xff\xd9\xf6B3'*W\x8d\xd98k\x99\xc2c\x89\xb8Pz\x82\a( \x00\x00\xe0\x94X\xb8\b\xa6[Q\xe63\x89i\xaf\xb9^\xc7\a5\xe4Q\xd5&\x8a\bxK\xc1\xb9\x83z8\x00\x00\u07d4X\xb8\xae\x8fc\xef5\xed\ab\xf0\xb6#=J\xc1Nd\xb6M\x89lk\x93[\x8b\xbd@\x00\x00\u07d4X\xba\x15ie\x0e[\xbb\xb2\x1d5\xd3\xe1u\xc0\u05b0\xc6Q\xa9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4X\xc5U\xbc)<\xdb\x16\xc66.\xd9z\xe9U\v\x92\xea\x18\x0e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4X\xc6P\xce\xd4\v\xb6VA\xb8\xe8\xa9$\xa09\xde\xf4hT\u07c9\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4X\xc9\aT\xd2\xf2\n\x1c\xb1\xdd3\x06%\xe0KE\xfaa\x9d\\\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\xe2\xf1\x12#\xfc\x827\xf6\x9d\x99\xc6(\x9c\x14\x8c\x06\x04\xf7B\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4X\xe5T\xaf=\x87b\x96 \xdaa\xd58\xc7\xf5\xb4\xb5LJ\xfe\x89FP\x9diE4r\x80\x00\u07d4X\xe5\xc9\xe3D\xc8\x06e\r\xac\xfc\x90M3\xed\xbaQ\a\xb0\u0789\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4X\xe6a\u043as\xd6\xcf$\t\x9aUb\xb8\b\xf7\xb3g;h\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\xf0[&%`P<\xa7a\xc6\x18\x90\xa4\x03_Lsr\x80\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4X\xfb\x94sd\xe7iWe6\x1e\xbb\x1e\x80\x1f\xfb\x8b\x95\xe6\u0409\n\u05ce\xbcZ\xc6 \x00\x00\u07d4Y\x01\x81\xd4E\x00{\u0407Z\xaf\x06\x1c\x8dQ\x159\x00\x83j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Y\x02\xe4J\xf7i\xa8rF\xa2\x1e\a\x9c\b\xbf6\xb0n\xfe\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4Y\n\xcb\xda7)\f\r>\xc8O\xc2\x00\rv\x97\xf9\xa4\xb1]\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94Y\f\xcbY\x11\xcfx\xf6\xf6\"\xf55\xc4t7_J\x12\xcf\u03ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y\x10\x10m\xeb\u0491\xa1\u0340\xb0\xfb\xbb\x8d\x8d\x9e\x93\xa7\xcc\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Y\x16\x17I\xfe\xdc\xf1\xc7!\xf2 -\x13\xad\xe2\xab\xcfF\v=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Y\x1b\xef1q\xd1\u0155w\x17\xa4\xe9\x8d\x17\xeb\x14,!NV\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y <\xc3u\x99\xb6H1*|\xc9\xe0m\xac\xb5\x89\xa9\xaej\x89\b\x0fyq\xb6@\x0e\x80\x00\u07d4Y&\x81q\xb83\xe0\xaa\x13\xc5KR\xcc\xc0B.O\xa0:\ub262\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94Y'w&\x1e;\xd8R\u010e\u0295\xb3\xa4L[\u007f-B,\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y0Dg\x0f\xae\xff\x00\xa5[Z\xe0Q\xeb{\xe8p\xb1\x16\x94\x89\a?u\u0460\x85\xba\x00\x00\xe0\x94Y;E\xa1\x86J\xc5\xc7\xe8\xf0\u02ae\xba\r\x87<\xd5\xd1\x13\xb2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Y_^\xdajV\xf1N%\xe0\xc6\xf3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Z\x1a3ib\xd6\xe0\xc601\u0303\u01a5\u01a6\xf4G\x8e\u02c965\u026d\xc5\u07a0\x00\x00\u07d4Z\x1d--\x1dR\x03\x04\xb6 \x88IW\x047\xeb0\x91\xbb\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Z&s1\xfa\xcb&-\xaa\xec\xd9\xddc\xa9p\f_RY\u07c9\x05k\xc7^-c\x10\x00\x00\xe0\x94Z(WU9\x1e\x91NX\x02_\xaaH\xcch_O\xd4\xf5\xb8\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4Z)\x16\xb8\xd2\xe8\xcc\x12\xe2\a\xabFMC>#p\xd8#\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4Z+\x1c\x85:\xeb(\xc4U9\xafv\xa0\n\xc2\u0628$(\x96\x89\x01Z\xf1\u05cbX\xc4\x00\x00\u07d4Z-\xaa\xb2\\1\xa6\x1a\x92\xa4\xc8,\x99%\xa1\xd2\xefXX^\x89\f8\r\xa9\u01d5\f\x00\x00\u07d4Z0\xfe\xac7\xac\x9fr\u05f4\xaf\x0f+\xc79R\xc7O\xd5\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4ZTh\xfa\\\xa2&\xc7S.\xcf\x06\xe1\xbc\x1cE\"]~\u0249g\x8a\x93 b\xe4\x18\x00\x00\u07d4ZVR\x857JI\xee\xddPL\x95}Q\bt\xd0\x04U\xbc\x89\x05k\xc7^-c\x10\x00\x00\u07d4Z^\xe8\xe9\xbb\x0e\x8a\xb2\xfe\xcbK3\u0494x\xbeP\xbb\xd4K\x89*\x11)\u0413g \x00\x00\xe0\x94Z_\x85\b\xda\x0e\xbe\xbb\x90\xbe\x903\xbdM\x9e'A\x05\xae\x00\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4Z`q\xbc\xeb\xfc\xbaJ\xb5\u007fM\xb9o\u01e6\x8b\xec\xe2\xba[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z`\xc9$\x16(s\xfc~\xa4\xda\u007f\x97.5\x01g7`1\x89\x04\x87\xf2w\xa8\x85y\x80\x00\u07d4Zf\x86\xb0\xf1~\a\xed\xfcY\xb7Y\xc7}[\xef\x16M8y\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4Zp\x10o \xd6?\x87Re\xe4\x8e\r5\xf0\x0e\x17\xd0+\u0249\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794Zt\xbab\xe7\xc8\x1a4t\xe2}\x89O\xed3\xdd$\xad\x95\xfe\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94Zw5\x00}p\xb0hD\u0699\x01\xcd\xfa\xdb\x11\xa2X,/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Z\x82\xf9l\u0537\xe2\xd9=\x10\xf3\x18]\xc8\xf4=Ku\xaai\x89lc?\xba\xb9\x8c\x04\x00\x00\u07d4Z\x87\xf04\xe6\xf6\x8fNt\xff\xe6\fd\x81\x946\x03l\xf7\u05c9\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94Z\x89\x11U\xf5\x0eB\aCt\xc79\xba\xad\xf7\xdf&Q\x15:\x8a\x01\x02\xdao\xd0\xf7:<\x00\x00\u07d4Z\x9c\x8bi\xfcaMiVI\x99\xb0\r\xcbB\xdbg\xf9~\x90\x89\xb9\xe6\x15\xab\xad:w\x80\x00\xe0\x94Z\xaf\x1c1%Jn\x00_\xba\u007fZ\xb0\xecy\xd7\xfc+c\x0e\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4Z\xb1\xa5aSH\x00\x1c|w]\xc7WHf\x9b\x8b\xe4\xde\x14\x89%jr\xfb)\xe6\x9c\x00\x00\xe1\x94Z\xbf\xec%\xf7L\u06047c\x1aw1\x90i2wcV\xf9\x8b\t\xd8<\xc0\u07e1\x11w\xff\x80\x00\u07d4Z\u0090\x8b\x0f9\x8c\r\xf5\xba\xc2\xcb\x13\xcas\x14\xfb\xa8\xfa=\x89\n\xd4\xc81j\v\f\x00\x00\xe0\x94Z\u025a\u05c1j\xe9\x02\x0f\xf8\xad\xf7\x9f\xa9\x86\x9b|\xeaf\x01\x8a\x04ri\x8bA;C \x00\x00\u07d4Z\xd1,^\xd4\xfa\x82~!P\u03e0\u058c\n\xa3{\x17i\xb8\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94Z\xd5\xe4 uV\x13\x88o5\xaaV\xac@>\xeb\xdf\xe4\xb0\u040a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4Z\xdew\xfd\x81\xc2\\\n\xf7\x13\xb1\a\x02v\x8c\x1e\xb2\xf9u\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Z\xe6N\x85;\xa0\xa5\x12\x82\u02cd\xb5.Aa^|\x9fs?\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z\xed\x0el\xfe\x95\xf9\u0580\xc7dr\xa8\x1a+h\n\u007f\x93\xe2\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4Z\xef\x16\xa2&\xddh\a\x1f$\x83\xe1\xdaBY\x83\x19\xf6\x9b,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z\xf4j%\xac\t\xcbsakS\xb1O\xb4/\xf0\xa5\x1c\u0772\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Z\xf7\xc0r\xb2\u016c\xd7\x1cv\xad\xdc\xceS\\\xf7\xf8\xf95\x85\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94Z\xfd\xa9@\\\x8e\x976QEt\u0692\x8d\xe6tV\x01\t\x18\x8a\x01E\xb8\xb0#\x9aF\x92\x00\x00\u07d4[\x06\xd1\xe6\x93\f\x10Ti+y\xe3\xdb\xe6\xec\xceS\x96d \x89\v\"\u007fc\xbe\x81<\x00\x00\u07d4[%\xca\xe8m\xca\xfa*`\xe7r61\xfc_\xa4\x9c\x1a\xd8}\x89\x87\fXQ\x0e\x85 \x00\x00\u07d4[(|~sB\x99\xe7'bo\x93\xfb\x11\x87\xa6\rPW\xfe\x89\x05|\xd94\xa9\x14\xcb\x00\x00\u07d4[)\f\x01\x96|\x81.M\xc4\xc9\v\x17L\x1b@\x15\xba\xe7\x1e\x89\b \xeb4\x8dR\xb9\x00\x00\u07d4[+d\xe9\xc0X\u30a8\xb2\x99\"N\xec\xaa\x16\xe0\x9c\x8d\x92\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\xe0\x94[./\x16\x18U.\xab\r\xb9\x8a\xddUc|)Q\xf1\xfb\x19\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4[0`\x8cg\x8e\x1a\xc4d\xa8\x99L;3\xe5\xcd\xf3Iq\x12\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4[36\x96\xe0L\xca\x16\x92\xe7\x19\x86W\x9c\x92\rk)\x16\xf9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94[C\rw\x96\x96\xa3e?\xc6\x0et\xfb\u02ec\xf6\xb9\u00ba\xf1\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4[Cse\xae:\x9a/\xf9|h\xe6\xf9\nv \x18\x8c}\x19\x89l\x87T\xc8\xf3\f\b\x00\x00\u07d4[I\xaf\xcduDx8\xf6\xe7\xce\u068d!w}O\xc1\xc3\xc0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4[L\f`\xf1\x0e\u0489K\xdbB\xd9\xdd\x1d!\x05\x87\x81\n\r\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4[N\xa1m\xb6\x80\x9b\x03R\u0536\xe8\x1c9\x13\xf7jQ\xbb2\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4[[\xe0\xd8\xc6rv\xba\xab\xd8\xed\xb3\rH\xeaud\v\x8b)\x89,\xb1\xf5_\xb7\xbe\x10\x00\x00\u07d4[]Qp)2\x15b\x11\x1bC\bm\v\x045\x91\x10\x9ap\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\xe0\x94[]\x8c\x8e\xedl\x85\xac!Va\xde\x02fv\x82?\xaa\n\f\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4[mU\xf6q)g@\\e\x91)\xf4\xb1\xde\t\xac\xf2\xcb{\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4[p\u011c\u024b=\xf3\xfb\xe2\xb1Y\u007f\\\x1bcG\xa3\x88\xb7\x894\x95tD\xb8@\xe8\x00\x00\u07d4[sn\xb1\x83Sb\x9b\u0796v\xda\xdd\x16P4\xce^\xcch\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4[u\x9f\xa1\x10\xa3\x1c\x88F\x9fT\xd4K\xa3\x03\xd5}\xd3\xe1\x0f\x89[F\xdd/\x0e\xa3\xb8\x00\x00\u07d4[w\x84\xca\xea\x01y\x9c\xa3\x02'\x82vg\xce |\\\xbcv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4[x\xec\xa2\u007f\xbd\xeao&\xbe\xfb\xa8\x97+)^x\x146K\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94[\x80\v\xfd\x1b>\u0525}\x87Z\xed&\xd4/\x1aw\b\xd7*\x8a\x01Z\x82\xd1\u057b\x88\xe0\x00\x00\u07d4[\x85\xe6\x0e*\xf0TO/\x01\xc6N 2\x90\x0e\xbd8\xa3\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4[\xa2\xc6\xc3]\xfa\xec)h&Y\x19\x04\xd5DFJ\xea\xbd^\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94[\xafmt\x96 \x80>\x83H\xaf7\x10\xe5\xc4\xfb\xf2\x0f\u0214\x8a\x01\x0f@\x02a]\xfe\x90\x00\x00\u07d4[\xc1\xf9U\a\xb1\x01\x86B\xe4\\\xd9\xc0\xe2'3\xb9\xb1\xa3&\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94[\xd25GG\u007fm\t\u05f2\xa0\x05\xc5\xeee\fQ\fV\u05ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4[\xd2J\xac6\x12\xb2\f`\x9e\xb4gy\xbf\x95i\x84\a\xc5|\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4[\u0586-Q}M\xe4U\x9dN\xec\n\x06\xca\xd0^/\x94n\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4[\xe0EQ*\x02n?\x1c\xeb\xfdZ~\xc0\xcf\xc3o-\xc1k\x89\x06\x81U\xa46v\xe0\x00\x00\xe0\x94[\xf9\xf2\"nZ\xea\xcf\x1d\x80\xae\nY\xc6\xe3\x808\xbc\x8d\xb5\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4[\xfa\xfe\x97\xb1\xdd\x1dq+\xe8mA\xdfy\x89SE\x87Z\x87\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\\\x0f.Q7\x8fk\r{\xabas1X\vn9\xad<\xa5\x8a\x02\bj\xc3Q\x05&\x00\x00\x00\u07d4\\)\xf9\xe9\xa5#\xc1\xf8f\x94H\xb5\\H\xcb\xd4|%\xe6\x10\x894F\xa0\xda\xd0L\xb0\x00\x00\xe0\x94\\0\x8b\xacHW\xd3;\xae\xa0t\xf3\x95m6!\xd9\xfa(\xe1\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\\1*V\u01c4\xb1\"\t\x9bvM\x05\x9c!\xec\xe9^\x84\u0289\x05&c\u032b\x1e\x1c\x00\x00\u07d4\\1\x99m\xca\xc0\x15\xf9\xbe\x98[a\x1fF\x870\xef$M\x90\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\\24W\xe1\x87v\x1a\x82v\xe3Y\xb7\xb7\xaf?;n=\xf6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\\<\x1cd[\x91uC\x11;>l\x1c\x05M\xa1\xfet+\x9a\x89+^:\xf1k\x18\x80\x00\x00\u0794\\=\x19D\x1d\x19l\xb4Cf \xfc\xad\u007f\xbby\xb2\x9ex\x88\xc6s\xce<@\x16\x00\x00\u07d4\\?V\u007f\xaf\xf7\xba\u0475\x12\x00\"\xe8\xcb\u02a8+I\x17\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\\Ch\x91\x8a\xced\t\u01de\u0280\u036a\xe49\x1d+bN\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\\FA\x97y\x1c\x8a=\xa3\xc9%Co'z\xb1;\xf2\xfa\xa2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\\H\x81\x16\\\xb4+\xb8.\x979l\x8e\xf4J\xdb\xf1s\xfb\x99\x89\x05\xfe\xe2\"\x04\x1e4\x00\x00\xe0\x94\\H\x92\x90z\a \xdfo\xd3A>c\xffv}k9\x80#\x8a\x02\xcb\x00\x9f\u04f5y\x0f\x80\x00\u07d4\\O$\xe9\x94\ud3c5\x0e\xa7\x81\x8fG\x1c\x8f\xac;\xcf\x04R\x89]\x80h\x8d\x9e1\xc0\x00\x00\u07d4\\T\x19V\\:\xadNqN\a92\x8e5!\u024f\x05\u0309\x1c\x9fx\u0489>@\x00\x00\u07d4\\a6\xe2\x18\xde\na\xa17\xb2\xb3\x96-*a\x12\xb8\t\u05c9\x0f\xf3\u06f6_\xf4\x86\x80\x00\xe0\x94\\a\xaby\xb4\b\xdd2)\xf6bY7\x05\xd7/\x1e\x14{\xb8\x8a\x04\xd0$=4\x98\u0344\x00\x00\u07d4\\m\x04\x1d\xa7\xafD\x87\xb9\xdcH\xe8\xe1\xf6\af\u0425m\xbc\x89O\a\n\x00>\x9ct\x00\x00\u07d4\\o6\xaf\x90\xab\x1aeln\xc8\xc7\xd5!Q'b\xbb\xa3\xe1\x89lh\xcc\u041b\x02,\x00\x00\u07d4\\{\x9e\u01e2C\x8d\x1eD*\x86\x0f\x8a\x02\x1e\x18\x99\xf07z\xea\x00\x00\u07d4\\\xcc\xf1P\x8b\xfd5\xc2\x050\xaad%\x00\xc1\r\xeee\xea\xed\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\\\xcer\xd0h\xc7\xc3\xf5[\x1d(\x19T^w1|\xae\x82@\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\\\xd0\xe4u\xb5D!\xbd\xfc\f\x12\xea\x8e\b+\u05e5\xaf\nj\x89\x032\xca\x1bg\x94\f\x00\x00\u07d4\\\u0548\xa1N\xc6H\xcc\xf6G)\xf9\x16z\xa7\xbf\x8b\xe6\xeb=\x8965\u026d\xc5\u07a0\x00\x00\u07d4\\\u062f`\xdee\xf2M\xc3\xceW0\xba\x92e0\"\xdcYc\x89a\t=|,m8\x00\x00\u07d4\\\xdcG\b\xf1O@\xdc\xc1Zy_}\xc8\xcb\v\u007f\xaa\x9en\x89\x1d\x1c_>\xda \xc4\x00\x00\u07d4\\\u0d86,\u0391b\xe8~\bI\xe3\x87\xcb]\xf4\xf9\x11\x8c\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\\\xe2\xe7\u03aa\xa1\x8a\xf0\xf8\xaa\xfa\u007f\xba\xd7L\u021e<\xd46\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\\\xe4@h\xb8\xf4\xa3\xfey\x9ej\x83\x11\xdb\xfd\xed\xa2\x9d\xee\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u0794\\\xeb\xe3\v*\x95\xf4\xae\xfd\xa6ee\x1d\xc0\xcf~\xf5u\x81\x99\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\\\xf1\x8f\xa7\u0227\xc0\xa2\xb3\xd5\xef\u0459\x0fd\xdd\xc5i$,\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\\\xf4N\x10T\reqd#\xb1\xbc\xb5B\xd2\x1f\xf8:\x94\u034a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\\\xf8\xc0>\xb3\xe8r\xe5\x0f|\xfd\f/\x8d;?,\xb5\x18:\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\\\xfa\x8dV\x85ue\x8c\xa4\xc1\xa5\x93\xacL]\x0eD\xc6\aE\x89\x0f\xc6o\xae7F\xac\x00\x00\u07d4\\\xfa\x98w\xf7\x19\u01dd\x9eIJ\b\xd1\xe4\x1c\xf1\x03\xfc\x87\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4]\x1d\xc38{G\xb8E\x1eU\x10l\f\xc6}m\xc7+\u007f\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4]#\x1ap\xc1\xdf\xeb6\n\xbd\x97\xf6\x16\xe2\xd1\r9\xf3\u02b5\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4]$\xbd\xbc\x1cG\xf0\xeb\x83\xd1(\xca\xe4\x8a\xc3\xf4\xb5\x02bt\a\xda'/g\x81Jk\xec\u0509\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4]\x83\xb2\x1b\xd2q#`Ckg\xa5\x97\xee3x\xdb>z\xe4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94]\x87+\x12.\x99N\xf2|q\xd7\u07b4W\xbfeB\x9e\xcal\x8a\x01\xb1\xad\xed\x81\u04d4\x10\x80\x00\xe0\x94]\x8d1\xfa\xa8d\xe2!Y\xcdoQu\xcc\xec\xc5?\xa5Mr\x8a\x05\xb6\x96\xb7\r\xd5g\x10\x00\x00\xe0\x94]\x95\x8a\x9b\u0449\u0098_\x86\u014a\x8ci\xa7\xa7\x88\x06\xe8\u068a\x02(\xf1o\x86\x15x`\x00\x00\u07d4]\xa2\xa9\xa4\xc2\xc0\xa4\xa9$\xcb\xe0\xa5:\xb9\xd0\xc6'\xa1\u03e0\x89'\xbf8\xc6TM\xf5\x00\x00\u07d4]\xa4\u0288\x93\\'\xf5\\1\x10H\x84\x0eX\x9e\x04\xa8\xa0I\x89\x04V9\x18$O@\x00\x00\u07d4]\xa5G\x85\u027d0W\\\x89\u07b5\x9d A\xd2\n9\xe1{\x89j\xa2\t\xf0\xb9\x1de\x80\x00\xe0\x94]\xb6\x9f\xe9>o\xb6\xfb\xd4P\x96k\x97#\x8b\x11\n\xd8'\x9a\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4]\xb7\xbb\xa1\xf9W?$\x11]\x8c\x8cb\xe9\u0388\x95\x06\x8e\x9f\x89\x02\xb5\xaa\xd7,e \x00\x00\xe0\x94]\xb8D\x00W\x00i\xa9W<\xab\x04\xb4\u6d955\xe2\x02\xb8\x8a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4]\xc3m\xe55\x94P\xa1\xec\t\xcb\fD\xcf+\xb4+:\xe45\x89<\x94m\x89;3\x06\x00\x00\u07d4]\xc6\xf4_\xef&\xb0n3\x021?\x88M\xafH\xe2to\xb9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94]\u0376\xb8zP\xa9\xde\x02C\x80\x00\x00\u07d4^Q\xb8\xa3\xbb\t\xd3\x03\xea|\x86\x05\x15\x82\xfd`\x0f\xb3\xdc\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794^X\xe2U\xfc\x19\x87\n\x040_\xf2\xa0F1\xf2\xff)K\xb1\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4^ZD\x19t\xa8=t\u0187\xeb\xdcc?\xb1\xa4\x9e{\x1a\u05c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^eE\x8b\xe9d\xaeD\x9fqw7\x04\x97\x97f\xf8\x89\x87a\x89\x1c\xa7\xccs[o|\x00\x00\u07d4^g\u07c9i\x10\x1a\u06bd\x91\xac\xcdk\xb1\x99\x12t\xaf\x8d\xf2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4^n\x97G\xe1b\xf8\xb4\\en\x0fl\xaez\x84\xba\xc8\x0eN\x89lk\x93[\x8b\xbd@\x00\x00\u07d4^s\x1bU\xce\xd4R\xbb??\xe8q\xdd\xc3\xed~\xe6Q\n\x8f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^t\xed\x80\xe9eW\x88\xe1\xbb&\x97R1\x96g\xfeuNZ\x89\x03\t'\xf7L\x9d\xe0\x00\x00\u07d4^w.'\xf2\x88\x00\xc5\r\u0697;\xb3>\x10v.n\xea \x89a\t=|,m8\x00\x00\u07d4^{\x8cT\xdcW\xb0@ bq\x9d\xee~\xf5\xe3~\xa3]b\x89\x9b\xf9\x81\x0f\xd0\\\x84\x00\x00\u07d4^\u007fp7\x87uX\x9f\xc6j\x81\xd3\xf6S\xe9T\xf5U`\ub243\xf2\x89\x18\x1d\x84\xc8\x00\x00\xe0\x94^\x80n\x84W0\xf8\a>l\xc9\x01\x8e\xe9\x0f\\\x05\xf9\t\xa3\x8a\x02\x01\xe9m\xac\u03af \x00\x00\u07d4^\x8eM\xf1\x8c\xf0\xafw\tx\xa8\u07cd\xac\x90\x93\x15\x10\xa6y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4^\x90\xc8Xw\x19\x87V\xb06l\x0e\x17\xb2\x8eR\xb4FPZ\x89\x14JJ\x18\xef\xebh\x00\x00\u07d4^\x95\xfe_\xfc\xf9\x98\xf9\xf9\xac\x0e\x9a\x81\u06b8>\xadw\x00=\x89\x1dB\xc2\r2y\u007f\x00\x00\u07d4^\xad)\x03z\x12\x89dx\xb1)j\xb7\x14\xe9\u02d5B\x8c\x81\x89\x03\xe0C\a-@n\x00\x00\u07d4^\xb3q\xc4\a@lB{;}\xe2q\xad<\x1e\x04&\x95y\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^\u037a\xea\xb9\x10o\xfe]{Q\x96\x96`\x9a\x05\xba\ub16d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4^\xd0\xd63\x85Y\xefD\xdcza\xed\xeb\x89?\xa5\xd8?\xa1\xb5\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\xe0\x94^\u04fb\xc0R@\xe0\u04d9\xebm\xdf\xe6\x0fb\xdeM\x95\t\xaf\x8a)\x14\xc0$u\xf9\xd6\xd3\x00\x00\u0594^\xd3\xf1\xeb\xe2\xaegV\xb5\xd8\xdc\x19\xca\xd0,A\x9a\xa5w\x8b\x80\u07d4^\xd5a\x15\xbde\x05\xa8\x82s\xdf\\V\x83\x94p\xd2J-\xb7\x89\x03\x8ee\x91\xeeVf\x80\x00\xe0\x94^\xf8\xc9a\x86\xb3y\x84\xcb\xfe\x04\u0158@n;\n\xc3\x17\x1f\x8a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4^\xfb\xdf\xe58\x99\x99c<&`Z[\xfc,\x1b\xb5\x95\x93\x93\x89\x03\xc0W\xc9\\\xd9\b\x00\x00\xe0\x94_\x13\x15F1Fm\xcb\x13S\u0210\x93*|\x97\xe0\x87\x8e\x90\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4_\x16z\xa2B\xbcL\x18\x9a\xde\xcb:\u0127\xc4R\xcf\x19/\u03c9lkLM\xa6\u077e\x00\x00\xe0\x94_\x1c\x8a\x04\xc9\rs[\x8a\x15)\t\xae\xaeco\xb0\xce\x16e\x8a\x01{x'a\x8cZ7\x00\x00\u07d4_#\xba\x1f7\xa9lE\xbcI\x02YS\x8aT\u008b\xa3\xb0\u0549A\rXj \xa4\xc0\x00\x00\u07d4_&\xcf4Y\x9b\xc3n\xa6{\x9ez\x9f\x9bC0\xc9\xd5B\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4_)\xc9\xdev]\xde%\x85*\xf0}3\xf2\xceF\x8f\xd2\t\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_/\a\xd2\u0597\xe8\xc5g\xfc\xfd\xfe\x02\x0fI\xf3`\xbe!9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_2\x1b=\xaa\xa2\x96\xca\xdf)C\x9f\x9d\xab\x06*K\xff\xed\u0589\x04p%\x90>\xa7\xae\x00\x00\u07d4_3:;#\x10vZ\r\x182\xb9\xbeL\n\x03pL\x1c\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4_4K\x01\xc7\x19\x1a2\xd0v*\xc1\x88\xf0\xec-\xd4`\x91\x1d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94_6>\n\xb7G\xe0-\x1b;f\xab\xb6\x9e\xa5<{\xafR:\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\u07d4_7[\x86`\f@\u0328\xb2gkz\x1a\x1d\x16D\xc5\xf5,\x89\x04F\x18\xd7Lb?\x00\x00\u07d4_>\x1eg9\xb0\xc6\"\x00\xe0\n\x006\x91\xd9\xef\xb28\u061f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4_H?\xfb\x8fh\n\xed\xf2\xa3\x8fx3\xaf\xdc\xdeY\xb6\x1eK\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94_J\xceL\x1c\xc13\x91\xe0\x1f\x00\xb1\x98\xe1\xf2\v_\x91\xcb\xf5\x8a\x01\x0f\x0f\xa8\xb9\u04c1\x1a\x00\x00\xe0\x94_R\x12\x82\xe9\xb2x\u070c\x03Lr\xafS\xee)\xe5D=x\x8a\x01as-/\x8f:\xe0\x00\x00\u07d4_h\xa2L~\xb4\x11vgs{39?\xb3\xc2\x14\x8aS\xb6\x89\x02\xce\u0791\x8dE<\x00\x00\u07d4_p\x8e\xaf9\xd8#\x94lQ\xb3\xa3\u9df3\xc0\x03\xe2cA\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4_t.H~:\xb8\x1a\xf2\xf9J\xfd\xbe\x1b\x9b\x8f\\\u0301\xbc\x89u\xc4E\xd4\x11c\xe6\x00\x00\u07d4_t\xed\x0e$\xff\x80\u0672\u0124K\xaa\x99uB\x8c\u05b95\x89\xa1\x8b\xce\xc3H\x88\x10\x00\x00\u07d4_v\xf0\xa3\x06&\x9cx0k=e\r\xc3\xe9\xc3p\x84\xdba\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4_w\xa1\a\xab\x12&\xb3\xf9_\x10\ue0ee\xfcl]\xff>\u0709\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4_{;\xba\xc1m\xab\x83\x1aJ\x0f\xc5;\fT\x9d\xc3l1\u0289i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94_\x93\xff\x83't\xdbQ\x14\xc5[\xb4\xbfD\xcc\U000f53d0?\x8a(\xa9\xc9\x1a&4X)\x00\x00\u07d4_\x96\x16\xc4{Jg\xf4\x06\xb9Z\x14\xfeo\xc2h9o\x17!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4_\x98\x109\xfc\xf5\x02%\xe2\xad\xf7bu!\x12\xd1\xcc&\xb6\xe3\x89\x1b\x1aAj!S\xa5\x00\x00\u07d4_\x99\u070eI\xe6\x1dW\xda\xef`j\xcd\xd9\x1bMp\a2j\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4_\xa6\x1f\x15-\xe6\x125\x16\xc7Q$)y(_yj\u01d1\x89\v\x0f\x11\x97)c\xb0\x00\x00\u07d4_\xa7\xbf\xe0C\x88a'\xd4\x01\x1d\x83V\xa4~\x94yc\xac\xa8\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94_\xa8\xa5Nh\x17lO\xe2\xc0\x1c\xf6q\xc5\x15\xbf\xbd\xd5(\xa8\x8aE\xe1U\xfa\x01\x10\xfa@\x00\x00\u07d4_\xad\x96\x0fk,\x84V\x9c\x9fMG\xbf\x19\x85\xfc\xb2\xc6]\xa6\x8965f3\xeb\xd8\xea\x00\x00\u07d4_\xc6\xc1\x14&\xb4\xa1\xea\xe7\xe5\x1d\xd5\x12\xad\x10\x90\xc6\xf1\xa8[\x89\x93\xfe\\W\xd7\x10h\x00\x00\u07d4_\u0344Th\x96\xdd\b\x1d\xb1\xa3 \xbdM\x8c\x1d\xd1R\x8cL\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4_\u0368G\xaa\xf8\xd7\xfa\x8b\xca\b\x02\x9c\xa2\x84\x91f\xaa\x15\xa3\x89!\u02b8\x12Y\xa3\xbf\x00\x00\u07d4_\xd1\xc3\xe3\x17x'l\xb4.\xa7@\xf5\xea\xe9\xc6A\xdb\xc7\x01\x89\n\x84Jt$\xd9\xc8\x00\x00\u07d4_\xd3\xd6w~\xc2b\n\xe8:\x05R\x8e\xd4%\a-<\xa8\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_\xd9s\xaf6j\xa5\x15|Te\x9b\u03f2|\xbf\xa5\xac\x15\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4_\xe7w\x03\x80\x8f\x82>l9\x93R\x10\x8b\xdb,R|\xb8|\x89j@v\xcfy\x95\xa0\x00\x00\xe0\x94_\xecI\xc6e\xe6N\xe8\x9d\xd4A\xeet\x05n\x1f\x01\xe9(p\x8a\x01V\x9b\x9es4t\xc0\x00\x00\u07d4_\xf3&\xcd`\xfd\x13k$^)\xe9\bzj\u04e6R\u007f\r\x89e\xea=\xb7UF`\x00\x00\u07d4_\xf9=\xe6\xee\x05L\xadE\x9b-^\xb0\xf6\x87\x03\x89\xdf\xcbt\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\u07d4`\x06\xe3m\x92\x9b\xf4]\x8f\x16#\x1b\x12j\x01\x1a\xe2\x83\xd9%\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4`!\xe8Z\x88\x14\xfc\xe1\xe8*A\xab\xd1\u04f2\xda\xd2\xfa\xef\xe0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4`8t\n\xe2\x8df\xba\x93\xb0\xbe\bH+2\x05\xa0\xf7\xa0{\x89\x11!a\x85\u009fp\x00\x00\u07d4`?/\xabz\xfbn\x01{\x94v`i\xa4\xb4;8\x96I#\x89Y\xd2\xdb$\x14\u0699\x00\x00\u07d4`B'm\xf2\x98?\xe2\xbcGY\xdc\x19C\xe1\x8f\xdb\xc3Ow\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4`B\xc6D\xba\xe2\xb9o%\xf9M1\xf6x\xc9\r\xc9f\x90\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4`L\xdf\x18b\x8d\xbf\xa82\x91\x94\xd4x\xddR\x01\xee\xccK\xe7\x89\x01?0j$\t\xfc\x00\x00\u07d4`N\x94w\xeb\xf4r|t[\u02bb\xed\xcbl\xcf)\x99@\"\x8966\x9e\xd7t}&\x00\x00\u07d4`gm\x1f\xa2\x1f\xca\x05\"\x97\xe2K\xf9c\x89\u0171*p\u05c9\r\x17|Zzh\xd6\x00\x00\u07d4`gn\x92\u044b\x00\x05\t\xc6\x1d\xe5@\xe6\xc5\u0776v\xd5\t\x89A\rXj \xa4\xc0\x00\x00\u07d4`o\x17q!\xf7\x85\\!\xa5\x06#0\xc8v\"d\xa9{1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4`\x86B6\x93\r\x04\xd8@+]\xcb\xeb\x80\u007f<\xafa\x1e\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4`\xabq\xcd&\xeamnY\xa7\xa0\xf6'\xee\a\x9c\x88^\xbb\xf6\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4`\xaf\x0e\xe1\x18D<\x9b7\xd2\xfe\xadw\xf5\xe5!\u07be\x15s\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4`\xb3X\xcb=\xbe\xfa7\xf4}\xf2\xd76X@\u068e;\u024c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4`\xb8\u05b7;ySO\xb0\x8b\xb8\xcb\xce\xfa\xc7\xf3\x93\xc5{\xfe\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4`\xbeo\x95?*M%\xb6%o\xfd$#\xac\x148%.N\x89\b!\xab\rD\x14\x98\x00\x00\u0794`\xc3qO\xdd\xdbcFY\u48b1\xeaB\xc4r\x8c\u01f8\xba\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4`\xcc=D^\xbd\xf7j}z\xe5q\u0197\x1d\xffh\u0305\x85\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94`\xd5fq@\xd1&\x14\xb2\x1c\x8e^\x8a3\b.2\xdf\xcf#\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4`\xde\"\xa1Pt2\xa4{\x01\xcch\xc5*\v\xf8\xa2\xe0\u0418\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4`\xe0\xbd\u0422Y\xbb\x9c\xb0\x9d?7\xe5\u034b\x9d\xac\uafca\x89JD\x91\xbdm\xcd(\x00\x00\u07d4`\xe3\xccC\xbc\xdb\x02j\xadu\x9cpf\xf5U\xbb\xf2\xacf\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\x04+\x80\xfd`\x95\u0478{\xe2\xf0\x0f\x10\x9f\xab\xaf\xd1W\xa6\x89\x05k\xc7^-c\x10\x00\x00\u07d4a\a\xd7\x1d\xd6\xd0\xee\xfb\x11\xd4\xc9\x16@L\xb9\x8cu>\x11}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\x0f\xd6\xeeN\xeb\xab\x10\xa8\xc5]\vK\xd2\xe7\xd6\xef\x81qV\x89\x01\x15\x95a\x06]]\x00\x00\u07d4a\x14\xb0\xea\xe5Wi\x03\xf8\v\xfb\x98\x84-$\xed\x92#\u007f\x1e\x89\x05k\xc7^-c\x10\x00\x00\u07d4a!\xaf9\x8a[-\xa6\x9fe\xc68\x1a\xec\x88\u039c\xc6D\x1f\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4a&g\xf1r\x13[\x95\v,\xd1\xde\x10\xaf\xde\xcehW\xb8s\x8965\u026d\xc5\u07a0\x00\x00\u07d4a,\xed\x8d\xc0\u071e\x89\x9e\xe4oyb33\x15\xf3\xf5^D\x89\x12^5\xf9\xcd=\x9b\x00\x00\u07d4a4\xd9B\xf07\xf2\xcc=BJ#\f`=g\xab\xd3\xed\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a:\xc5;\xe5e\xd4e6\xb8 q[\x9b\x8d:\xe6\x8aK\x95\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\u07d4a?\xabD\xb1k\xbeUMD\xaf\xd1x\xab\x1d\x02\xf3z\ua949lk\x93[\x8b\xbd@\x00\x00\u07d4aN\x8b\xef=\xd2\u015bY\xa4\x14Vt@\x10\x185\x18\x84\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4aQ\x84d\xfd\u0637<\x1b\xb6\xacm\xb6\x00eI8\xdb\xf1z\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4aT}7nSi\xbc\xf9x\xfc\x16,1\xc9\b\"3\xb8%\xd0%\xbe?{\x10V\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4a\x91\xdd\u0276J\x8e\b\x90\xb427\t\u05e0|H\xb9*d\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4a\x96\xc3\xd3\xc0\x90\x8d%Cf\xb7\xbc\xa5WE\"-\x9dM\xb1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4a\x9f\x17\x14E\xd4+\x02\xe2\xe0p\x04\xad\x8a\xfeiO\xa5=j\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4a\xad\xf5\x92\x9a^)\x81hN\xa2C\xba\xa0\x1f}\x1f^\x14\x8a\x89\x05\xfa\xbfl\x98O#\x00\x00\u07d4a\xb1\xb8\xc0\x12\xcdLx\xf6\x98\xe4p\xf9\x02V\xe6\xa3\x0fH\u0749\n\u05ce\xbcZ\xc6 \x00\x00\u07d4a\xb3\xdf.\x9e\x9f\xd9h\x13\x1f\x1e\x88\xf0\xa0\xeb[\xd7eFM\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4a\xb9\x02\u0166s\x88X&\x82\r\x1f\xe1EI\xe4\x86_\xbd\u0089\x12$\xef\xed*\u1440\x00\u07d4a\xb9\x05\xdef?\xc1s\x86R;:(\xe2\xf7\xd07\xa6U\u0349\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4a\xba\x87\xc7~\x9bYm\xe7\xba\x0e2o\xdd\xfe\xec!c\xeff\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4a\xbf\x84\u056b\x02oX\xc8s\xf8o\xf0\xdf\u0282\xb5W3\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\xc4\xee|\x86LMk^7\xea\x131\xc2\x03s\x9e\x82k/\x89\x01\xa15;8*\x91\x80\x00\u07d4a\xc80\xf1eG\x18\xf0u\u032b\xa3\x16\xfa\xac\xb8[}\x12\v\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4a\xc8\xf1\xfaC\xbf\x84i\x99\xec\xf4{+2M\xfbkc\xfe:\x89+^:\xf1k\x18\x80\x00\x00\u07d4a\xc9\xdc\u8c98\x1c\xb4\x0e\x98\xb0@+\xc3\xeb(4\x8f\x03\xac\x89\n\xac\xac\u0679\xe2+\x00\x00\u07d4a\u03a7\x1f\xa4d\xd6*\a\x06?\x92\v\f\xc9\x17S\x973\u0609Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4a\xd1\x01\xa03\xee\x0e.\xbb1\x00\xed\xe7f\xdf\x1a\xd0$IT\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4a\xedU\x96\u0197 \u007f=U\xb2\xa5\x1a\xa7\xd5\x0f\a\xfa\t\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\xff\x8eg\xb3M\x9e\xe6\xf7\x8e\xb3o\xfe\xa1\xb9\xf7\xc1W\x87\xaf\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4b\x05\xc2\xd5dtp\x84\x8a8@\xf3\x88~\x9b\x01]4u\\\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4b(\xad\xe9^\x8b\xb1}\x1a\xe2;\xfb\x05\x18AMI~\x0e\xb8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94b)\xdc\xc2\x03\xb1\xed\xcc\xfd\xf0n\x87\x91\fE*\x1fMzr\x8a\x06\xe1\xd4\x1a\x8f\x9e\xc3P\x00\x00\u0794b+\xe4\xb4T\x95\xfc\xd91C\xef\xc4\x12\u0599\xd6\xcd\xc2=\u0148\xf0\x15\xf2W6B\x00\x00\u07d4b3\x1d\xf2\xa3\xcb\xee5 \xe9\x11\u07a9\xf7>\x90_\x89%\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4bVD\xc9Z\x87>\xf8\xc0l\u06de\x9fm\x8dv\x80\x04=b\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4be\xb2\xe7s\x0f6\xb7v\xb5-\f\x9d\x02\xad\xa5]\x8e<\xb6\x8965\u026d\xc5\u07a0\x00\x00\u07d4bh\n\x15\xf8\u0338\xbd\xc0/s`\xc2Z\xd8\u03f5{\x8c\u034965\u026d\xc5\u07a0\x00\x00\u07d4b\x94\xea\xe6\xe4 \xa3\xd5`\n9\xc4\x14\x1f\x83\x8f\xf8\xe7\xccH\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4b\x97\x1b\xf2cL\xee\v\xe3\u0249\x0fQ\xa5`\x99\u06f9Q\x9b\x89#\x8f\xd4,\\\xf0@\x00\x00\u07d4b\x9b\xe7\xab\x12jS\x98\xed\xd6\u069f\x18D~x\u0192\xa4\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4b\xb4\xa9\"nah\a\x1el\xbea\x11\xfe\xf0\xbcc\x8a\x03\xba\x19\x10\xbf4\x1b\x00\x00\x00\xe0\x94c\n\x91:\x901\xc9I*\xbdLA\u06f1PT\xcf\xecD\x16\x8a\x014X\xdbg\xaf5\xe0\x00\x00\xe0\x94c\fRs\x12mQ|\xe6q\x01\x81\x1c\xab\x16\xb8SL\xf9\xa8\x8a\x01\xfe\xcc\xc6%s\xbb\u04c0\x00\u07d4c\x100\xa5\xb2{\a(\x8aEio\x18\x9e\x11\x14\xf1*\x81\xc0\x89\x1b\x1azB\v\xa0\r\x00\x00\u07d4c\x10\xb0 \xfd\x98\x04IW\x99P\x92\t\x0f\x17\xf0NR\xcd\xfd\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4c+\x91I\xd7\x01x\xa7364'^\x82\u0555?'\x96{\x89%\xf2s\x93=\xb5p\x00\x00\u07d4c,\xec\xb1\f\xfc\xf3\x8e\u0246\xb4;\x87p\xad\xec\xe9 \x02!\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4c1\x02\x8c\xbbZ!H[\xc5\x1bVQB\x99;\xdb%\x82\xa9\x89\x1c\xfd\xd7F\x82\x16\xe8\x00\x00\u07d4c3O\xcf\x17E\x84\x0eK\tJ;\xb4\v\xb7o\x96\x04\xc0L\x89\u05e5\xd7\x03\xa7\x17\xe8\x00\x00\u07d4c4\nWqk\xfac\xebl\xd13r\x12\x02W[\xf7\x96\xf0\x89\va\xe0\xa2\f\x12q\x80\x00\u07d4cN\xfc$7\x11\a\xb4\xcb\xf0?y\xa9=\xfd\x93\xe41\xd5\xfd\x89B5\x82\xe0\x8e\xdc\\\x80\x00\xe0\x94c\\\x00\xfd\xf05\xbc\xa1_\xa3a\r\xf38N\x0f\xb7\x90h\xb1\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4ca.xb\xc2{X|\xfbm\xaf\x99\x12\xcb\x05\x1f\x03\n\x9f\x89\x02[\x19\u053f\xe8\xed\x00\x00\u07d4cfgU\xbdA\xb5\x98i\x97x<\x13\x040\b$+<\xb5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4c{\xe7\x1b:\xa8\x15\xffE=VB\xf70tE\vd\xc8*\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94c}g\xd8\u007fXo\nZG\x9e \xee\x13\xea1\n\x10\xb6G\x8a\n:Y&\xaf\xa1\xe70\x00\x00\u07d4c\u007fXi\xd6\xe4i_\x0e\xb9\xe2s\x11\u0107\x8a\xff33\x80\x89j\xc0Nh\xaa\xec\x86\x00\x00\u07d4c\x97|\xad}\r\xcd\xc5+\x9a\xc9\xf2\xff\xa16\xe8d(\x82\xb8\x89\x04\x10\u0546\xa2\nL\x00\x00\u07d4c\xa6\x1d\xc3\n\x8e;0\xa7c\xc4!<\x80\x1c\xbf\x98s\x81x\x8965\u026d\xc5\u07a0\x00\x00\u07d4c\xacT\\\x99\x12C\xfa\x18\xae\xc4\x1dOoY\x8eUP\x15\u0709 \x86\xac5\x10R`\x00\x00\u07d4c\xb9uMu\xd1-8@9\xeci\x06<\v\xe2\x10\xd5\xe0\u3252\v\x86\f\xc8\xec\xfd\x80\x00\u07d4c\xbbfO\x91\x17\x03v(YM\xa7\xe3\xc5\b\x9f\xd6\x18\xb5\xb5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4c\u00a3\xd25\xe5\xee\xab\xd0\u0526\xaf\u06c9\xd9F'9d\x95\x89CN\xf0[\x9d\x84\x82\x00\x00\u07d4c\xc8\xdf\xde\v\x8e\x01\xda\xdc.t\x8c\x82L\xc06\x9d\U00010cc9\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4c\xd5Z\u065b\x917\xfd\x1b \xcc+O\x03\xd4,\xba\xdd\xf34\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4c\xd8\x00H\x87u\x96\xe0\u0084\x89\xe6P\xcdJ\xc1\x80\tjI\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94c\xe4\x14`>\x80\xd4\xe5\xa0\xf5\xc1\x87t FB%\x82\b\xe4\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94c\xe8\x8e.S\x9f\xfbE\x03\x86\xb4\xe4g\x89\xb2#\xf5GlE\x8a\x01U\x17\nw\x8e%\xd0\x00\x00\u07d4c\xef/\xbc=\xaf^\xda\xf4\xa2\x95b\x9c\xcf1\xbc\xdf@8\xe5\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4c\xf0\xe5\xa7R\xf7\x9fg\x12N\xedc:\xd3\xfd'\x05\xa3\x97\u0509\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94c\xf5\xb5=y\xbf.A\x14\x89Re0\"8E\xfa\xc6\xf6\x01\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4c\xfc\x93\x00\x13\x05\xad\xfb\u0278])\xd9)\x1a\x05\xf8\xf1A\v\x8965\u026d\xc5\u07a0\x00\x00\u0794c\xfek\xccK\x8a\x98P\xab\xbeu\x8070\xc92%\x1f\x14[\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4d\x03\xd0bT\x96\x90\xc8\xe8\xb6>\xaeA\xd6\xc1\tGn%\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4d\x04+\xa6\x8b\x12\xd4\xc1Qe\x1c\xa2\x81;sR\xbdV\xf0\x8e\x89 \x86\xac5\x10R`\x00\x00\u0794d\x05\xdd\x13\xe9:\xbc\xff7~p\x0e<\x1a\x00\x86\xec\xa2})\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94d\n\xbam\xe9\x84\xd9E\x177x\x03p^\xae\xa7\t_J\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4d\v\xf8t\x15\xe0\xcf@s\x01\xe5Y\x9ah6m\xa0\x9b\xba\u0209\x1a\xbc\x9fA`\x98\x15\x80\x00\u07d4d \xf8\xbc\xc8\x16JaR\xa9\x9dk\x99i0\x05\xcc\xf7\xe0S\x8965f3\xeb\xd8\xea\x00\x00\u07d4d$\x1axD)\x0e\n\xb8U\xf1\u052au\xb5SE\x03\"$\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4d&J\xed\xd5-\xca\xe9\x18\xa0\x12\xfb\xcd\f\x03\x0e\xe6\xf7\x18!\x8965\u026d\xc5\u07a0\x00\x00\u07d4d7\x0e\x87 &E\x12Z5\xb2\a\xaf\x121\xfb`r\xf9\xa7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4d=\x9a\xee\u0531\x80\x94~\u04b9 |\xceL=\xdcU\xe1\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4dC\xb8\xaec\x9d\xe9\x1c\xf7\xf0p\xa5G\x03\xb7\x18NH'l\\\x00w\xefK4\x89\x11X\xe4`\x91=\x00\x00\x00\xe0\x94d\xe2\xde! \v\x18\x99\u00e0\xc0e;P@\x13m\r\xc8B\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4d\xec\x8a[t?4y\xe7\a\xda\xe9\xee \u076aO@\xf1\u0649\n\u05ce\xbcZ\xc6 \x00\x00\u07d4e\x03\x86\v\x19\x10\b\xc1U\x83\xbf\u0201X\t\x93\x01v((\x8965\u026d\xc5\u07a0\x00\x00\u07d4e\x051\x911\x9e\x06z%\xe66\x1dG\xf3\u007fc\x18\xf84\x19\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4e\t;#\x9b\xbf\xba#\xc7w\\\xa7\xdaZ\x86H\xa9\xf5L\xf7\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4e\t\xee\xb14~\x84/\xfbA>7\x15^,\xbcs\x82s\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94e\vBUU\xe4\xe4\xc5\x17\x18\x14h6\xa2\xc1\xeew\xa5\xb4!\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4e\f\xf6}\xb0`\xcc\xe1uh\xd5\xf2\xa4#h|Idv\t\x89\x05k\xc7^-c\x10\x00\x00\u07d4e\x10\xdfB\xa5\x99\xbc\xb0\xa5\x19\u0329a\xb4\x88u\x9aogw\x89lk\x93[\x8b\xbd@\x00\x00\u07d4e6u\xb8B\xd7\u0634a\xf7\"\xb4\x11|\xb8\x1d\xac\x8ec\x9d\x89\x01\xae6\x1f\xc1E\x1c\x00\x00\u07d4eK~\x80\x87\x99\xa8=r\x87\xc6w\x06\xf2\xab\xf4\x9aId\x04\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94eORHG\xb3\xa6\xac\xc0\xd3\xd5\xf1\xf3b\xb6\x03\xed\xf6_\x96\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4eY4\u068etN\xaa=\xe3M\xbb\xc0\x89LN\xda\va\xf2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4e]\\\xd7H\x96)\xe2ANIb?\xabb\xa1~M6\x11\x89\x05\fL\xb2\xa1\f`\x00\x00\u07d4e\xaf\x8d\x8b[\x1d\x1e\xed\xfaw\xbc\xbc\x96\xc1\xb13\xf83\x06\u07c9\x05P\x05\xf0\xc6\x14H\x00\x00\u07d4e\xaf\x90\x87\xe0QgqT\x97\u0265\xa7I\x18\x94\x89\x00M\xef\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u0794e\xb4/\xae\xcc\x1e\u07f1B\x83\u0297\x9a\xf5E\xf6;0\xe6\f\x88\xfc\x93c\x92\x80\x1c\x00\x00\u0794e\xd3>\xb3\x9c\xdadS\xb1\x9ea\xc1\xfeM\xb91p\xef\x9d4\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4e\xd8\xddN%\x1c\xbc\x02\x1f\x05\xb0\x10\xf2\xd5\xdcR\f8r\xe0\x89-CW\x9a6\xa9\x0e\x00\x00\u07d4e\xea&\xea\xbb\xe2\xf6L\xcc\xcf\xe0h)\xc2]F7R\x02%\x89%\xf2s\x93=\xb5p\x00\x00\u07d4e\xeag\xad?\xb5j\xd5\xfb\x948}\u04ce\xb3\x83\x00\x1d|h\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94e\xeb\xae\xd2~\u06dd\xcc\x19W\xae\xe5\xf4R\xac!\x05\xa6\\\x0e\x8a\t7\u07ed\xae%\u26c0\x00\u07d4e\xee \xb0m\x9a\u0549\xa7\xe7\xce\x04\xb9\xf5\xf7\x95\xf4\x02\xae\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4e\xf544m/\xfbx\u007f\xa9\xcf\x18]t[\xa4)\x86\xbdn\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94e\xf5\x87\x0f&\xbc\xe0\x89g}\xfc#\xb5\x00\x1e\xe4\x92H4(\x8a\x01\x12\xb1\xf1U\xaa2\xa3\x00\x00\u07d4e\xfd\x02\xd7\x04\xa1*M\xac\xe9G\x1b\x06E\xf9b\xa8\x96q\u0209\x01\x8d\x1c\xe6\xe4'\u0340\x00\u07d4e\xff\x87O\xaf\xceM\xa3\x18\xd6\xc9=W\xe2\u00ca\rs\xe8 \x8968\x02\x1c\xec\u06b0\x00\x00\xe0\x94f\x05W\xbbC\xf4\xbe:\x1b\x8b\x85\xe7\xdf{<[\xcdT\x80W\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4f\b,u\xa8\xde1\xa59\x13\xbb\xd4M\xe3\xa07O\u007f\xaaA\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4f\x11\xceY\xa9\x8b\a*\xe9Y\xdcI\xadQ\x1d\xaa\xaa\xa1\x9dk\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4f \x1b\xd2'\xaem\u01bd\xfe\xd5\xfb\u0781\x1f\xec\xfe^\x9d\u0649 >\x9e\x84\x92x\x8c\x00\x00\u07d4f#4\x81G$\x93[y1\xdd\xcaa\x00\xe0\rFw'\u0349\"\x88&\x9d\a\x83\xd4\x00\x00\u07d4f'O\xea\x82\xcd0\xb6\u009b#5\x0eOO=1\nX\x99\x89p7\x05P\xab\x82\x98\x00\x00\u07d4f,\xfa\x03\x8f\xab7\xa0\x17E\xa3d\u1e41'\xc5\x03tm\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4f5\xb4oq\x1d-\xa6\xf0\xe1cp\u034e\xe4>\xfb,-R\x89lk\x93[\x8b\xbd@\x00\x00\u07d4f6\x04\xb0P0F\xe6$\xcd&\xa8\xb6\xfbGB\xdc\xe0*o\x89\x03\x8b\x9by~\xf6\x8c\x00\x00\u07d4f6\u05ecczH\xf6\x1d8\xb1L\xfdHe\xd3m\x14(\x05\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4f@\xcc\xf0SU\\\x13\n\xe2\xb6Vd~\xa6\xe3\x167\xb9\xab\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4fBK\xd8x[\x8c\xb4a\x10*\x90\x02\x83\xc3]\xfa\a\xefj\x89\x02.-\xb2ff\xfc\x80\x00\u07d4fL\xd6}\xcc\u026c\x82(\xb4\\U\u06cdvU\ve\x9c\u0709\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4fNC\x11\x98p\xaf\x10zD\x8d\xb1'\x8b\x04H8\xff\u036f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4fQso\xb5\x9b\x91\xfe\xe9\xc9:\xa0\xbdn\xa2\xf7\xb2Pa\x80\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4f[\x00\x0f\vw'P\xcc\x89k\x91\x8a\xacIK\x16\x80\x00\xe0\x94g]\\\xaa`\x9b\xf7\n\x18\xac\xa5\x80F]\x8f\xb71\r\x1b\xbb\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4gc F\u0732ZT\x93i(\xa9oB?3 \xcb\ud489lk\x93[\x8b\xbd@\x00\x00\u07d4ge\xdf%(\x0e\x8eO8\u0531\xcfDo\xc5\xd7\xebe\x9e4\x89\x05k\xc7^-c\x10\x00\x00\u07d4gv\xe13\xd9\xdc5L\x12\xa9Q\b{c\x96P\xf59\xa43\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4g\x85Q<\xf72\xe4~\x87g\ap\xb5A\x9b\xe1\f\xd1\xfct\x89lk\x93[\x8b\xbd@\x00\x00\u07d4g\x947\xea\xcfCxx\xdc)=H\xa3\x9c\x87\xb7B\x1a!l\x89\x03\u007f\x81\x82\x1d\xb2h\x00\x00\u07d4g\x9b\x9a\x10\x990Q~\x89\x99\t\x9c\xcf*\x91LL\x8d\xd94\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4g\xa8\x0e\x01\x90r\x1f\x949\rh\x02r\x9d\xd1,1\xa8\x95\xad\x89lk\x13u\xbc\x91V\x00\x00\u07d4g\xb8\xa6\xe9\x0f\xdf\n\x1c\xacD\x17\x930\x1e\x87P\xa9\xfayW\x890\x84\x9e\xbe\x166\x9c\x00\x00\u07d4g\xbc\x85\xe8}\xc3LN\x80\xaa\xfa\x06k\xa8\u049d\xbb\x8eC\x8e\x89\x15\xd1\xcfAv\xae\xba\x00\x00\u07d4g\xc9&\t>\x9b\x89'\x938\x10\u0642\"\xd6.+\x82\x06\xbb\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4g\xcf\xdanp\xbfvW\u04d0Y\xb5\x97\x90\xe5\x14Z\xfd\xbea\x89#\x05\r\tXfX\x00\x00\u07d4g\u0582\xa2\x82\xefs\xfb\x8dn\x90q\xe2aOG\xab\x1d\x0f^\x8965\u026d\xc5\u07a0\x00\x00\u07d4g\u05a8\xaa\x1b\xf8\xd6\xea\xf78N\x99=\xfd\xf1\x0f\n\xf6\x8aa\x89\n\xbc\xbbW\x18\x97K\x80\x00\u07d4g\u0692.\xff\xa4r\xa6\xb1$\xe8N\xa8\xf8k$\xe0\xf5\x15\xaa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4g\xdf$-$\r\u0538\a\x1dr\xf8\xfc\xf3[\xb3\x80\x9dq\xe8\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4g\xee@n\xa4\xa7\xaej:8\x1e\xb4\xed\xd2\xf0\x9f\x17KI(\x898)c_\th\xb0\x00\x00\u07d4g\xf2\xbbx\xb8\xd3\xe1\x1f|E\x8a\x10\xb5\xc8\xe0\xa1\xd3tF}\x89a\t=|,m8\x00\x00\u07d4g\xfcR}\xce\x17\x85\xf0\xfb\x8b\xc7\xe5\x18\xb1\xc6i\xf7\xec\u07f5\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4h\x02}\x19U\x8e\xd73\x9a\b\xae\xe8\xde5Y\xbe\x06>\xc2\xea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4h\x06@\x83\x8b\xd0zD{\x16\x8dm\x92;\x90\xcflC\xcd\u0289]\u0212\xaa\x111\xc8\x00\x00\u07d4h\a\xdd\u020d\xb4\x89\xb03\xe6\xb2\xf9\xa8\x15SW\x1a\xb3\xc8\x05\x89\x01\x9f\x8euY\x92L\x00\x00\xe0\x94h\rY\x11\xed\x8d\xd9\xee\xc4\\\x06\f\"?\x89\xa7\xf6 \xbb\u054a\x04<3\xc1\x93ud\x80\x00\x00\u07d4h\x11\xb5L\u0456c\xb1\x1b\x94\xda\x1d\xe2D\x82\x85\u035fh\u0649;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4h\x19\f\xa8\x85\xdaB1\x87L\x1c\xfbB\xb1X\n!s\u007f8\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94h(\x97\xbcO\x8e\x89\x02\x91 \xfc\xff\xb7\x87\xc0\x1a\x93\xe6A\x84\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4h)^\x8e\xa5\xaf\xd9\t?\xc0\xa4e\xd1W\x92+]*\xe24\x89\x01\x15NS!}\xdb\x00\x00\u07d4h.\x96'oQ\x8d1\xd7\xe5n0\u07f0\t\xc1!\x82\x01\xbd\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4h5\xc8\xe8\xb7J,\xa2\xae?J\x8d\x0fk\x95J>*\x83\x92\x89\x03B\x9c3]W\xfe\x00\x00\u07d4h63\x01\n\x88hk\xeaZ\x98\xeaS\xe8y\x97\xcb\xf7>i\x89\x05k9Bc\xa4\f\x00\x00\u07d4h=\xba6\xf7\xe9O@\xeaj\xea\ry\xb8\xf5!\xdeU\an\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4hA\x9cm\xd2\xd3\xceo\u02f3\xc7>/\xa0y\xf0`Q\xbd\xe6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4hG;z}\x96Y\x04\xbe\u06e5V\u07fc\x17\x13l\xd5\xd44\x89\x05k\xc7^-c\x10\x00\x00\u07d4hG\x82[\xde\xe8$\x0e(\x04,\x83\xca\xd6B\U000868fd\u0709QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94hJD\xc0i3\x9d\b\xe1\x9auf\x8b\u06e3\x03\xbe\x85S2\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\u07d4hS\x1fM\u0680\x8fS vz\x03\x114(\xca\f\xe2\xf3\x89\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4hy'\xe3\x04\x8b\xb5\x16*\xe7\xc1\\\xf7k\xd1$\xf9I{\x9e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94h\x80\x9a\xf5\xd52\xa1\x1c\x1aMn2\xaa\xc7\\LR\xb0\x8e\xad\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4h\x86\xad\xa7\xbb\xb0a{\u0684!\x91\u018c\x92.\xa3\xa8\xac\x82\x89>\xe2;\xde\x0e} \x00\x00\xe0\x94h\x88>\x15.V`\xfe\xe5\x96&\xe7\xe3\xb4\xf0Q\x10\xe6\"/\x8a\v\x94c;\xe9u\xa6*\x00\x00\u07d4h\x8aV\x9e\x96U$\xeb\x1d\n\xc3\xd3s>\xab\x90\x9f\xb3\xd6\x1e\x89G\x8e\xae\x0eW\x1b\xa0\x00\x00\xe0\x94h\x8e\xb3\x85;\xbc\xc5\x0e\xcf\xee\x0f\xa8\u007f\n\xb6\x93\u02bd\xef\x02\x8a\x06\xb1\n\x18@\x06G\xc0\x00\x00\u07d4h\xa7B_\xe0\x9e\xb2\x8c\xf8n\xb1y>A\xb2\x11\xe5{\u058d\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4h\xa8l@#\x88\xfd\xdcY\x02\x8f\xecp!\u933f\x83\x0e\xac\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\xe0\x94h\xac\u06a9\xfb\x17\xd3\xc3\t\x91\x1aw\xb0_S\x91\xfa\x03N\xe9\x8a\x01\xe5.3l\xde\"\x18\x00\x00\u07d4h\xad\xdf\x01\x9dk\x9c\xabp\xac\xb1?\v1\x17\x99\x9f\x06.\x12\x89\x02\xb5\x12\x12\xe6\xb7\u0200\x00\u07d4h\xb3\x186\xa3\n\x01j\xda\x15{c\x8a\xc1]\xa7?\x18\xcf\u0789\x01h\u048e?\x00(\x00\x00\xe0\x94h\xb6\x85G\x88\xa7\xc6Il\xdb\xf5\xf8K\x9e\xc5\xef9+x\xbb\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4h\xc0\x84\x90\u021b\xf0\u05b6\xf3 \xb1\xac\xa9\\\x83\x12\xc0\x06\b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4h\xc7\xd1q\x1b\x01\x1a3\xf1o\x1fU\xb5\xc9\x02\xcc\xe9p\xbd\u05c9\b=lz\xabc`\x00\x00\u07d4h\xc8y\x1d\xc3B\xc3sv\x9e\xa6\x1f\xb7\xb5\x10\xf2Q\xd3 \x88\x8965\u026d\xc5\u07a0\x00\x00\u07d4h\u07d4|I[\ubbb8\u8273\xf9S\xd53\x87K\xf1\x06\x89\x1d\x99E\xab+\x03H\x00\x00\u07d4h\xe8\x02'@\xf4\xaf)\xebH\xdb2\xbc\xec\xdd\xfd\x14\x8d=\xe3\x8965\u026d\xc5\u07a0\x00\x00\u07d4h\xecy\u057eqUql@\x94\x1cy\u05cd\x17\u079e\xf8\x03\x89\x1b#8w\xb5 \x8c\x00\x00\u07d4h\xee\xc1\u222c1\xb6\xea\xba~\x1f\xbdO\x04\xadW\x9ak]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4h\xf5%\x92\x1d\xc1\x1c2\x9buO\xbf>R\x9f\xc7#\xc84\u0349WG=\x05\u06ba\xe8\x00\x00\u07d4h\xf7\x19\xae4+\xd7\xfe\xf1\x8a\x05\u02f0/pZ\u04ce\u0572\x898\xeb\xad\\\u0710(\x00\x00\xe0\x94h\xf7W<\xd4W\xe1L\x03\xfe\xa4>0-04|\x10p\\\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4h\xf8\xf4QU\xe9\x8cP)\xa4\xeb\u0175'\xa9.\x9f\xa81 \x89\xf0{D\xb4\a\x93 \x80\x00\u07d4h\xfe\x13W!\x8d\tXI\xcdW\x98B\u012a\x02\xff\x88\x8d\x93\x89lk\x93[\x8b\xbd@\x00\x00\u07d4i\x02(\xe4\xbb\x12\xa8\u0535\u09d7\xb0\xc5\xcf*u\t\x13\x1e\x89e\xea=\xb7UF`\x00\x00\u07d4i\x05\x94\xd3\x06a<\xd3\xe2\xfd$\xbc\xa9\x99J\u064a=s\xf8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94i\a2ir\x9ed\x14\xb2n\xc8\xdc\x0f\xd95\xc7;W\x9f\x1e\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x94i\x19\xdd^]\xfb\x1a\xfa@G\x03\xb9\xfa\xea\x8c\xee5\xd0\rp\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4i4\x92\xa5\xc5\x13\x96\xa4\x82\x88\x16i\xcc\xf6\xd8\xd7y\xf0\tQ\x89\x12\xbfPP:\xe3\x03\x80\x00\u07d4i=\x83\xbe\tE\x9e\xf89\v.0\xd7\xf7\u008d\xe4\xb4(N\x89lk\x93[\x8b\xbd@\x00\x00\u07d4iQp\x83\xe3\x03\xd4\xfb\xb6\xc2\x11E\x14!]i\xbcF\xa2\x99\x89\x05k\xc7^-c\x10\x00\x00\u07d4iUPel\xbf\x90\xb7]\x92\xad\x91\"\xd9\r#\xcah\xcaM\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94iX\xf8;\xb2\xfd\xfb'\xce\x04\t\xcd\x03\xf9\xc5\xed\xbfL\xbe\u074a\x04<3\xc1\x93ud\x80\x00\x00\u0794i[\x0fRBu7\x01\xb2d\xa6pq\xa2\u0708\b6\xb8\u06c8\u3601\x1b\xech\x00\x00\xe0\x94i[L\xce\bXV\xd9\xe1\xf9\xff>y\x94 #5\x9e_\xbc\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94if\x06:\xa5\xde\x1d\xb5\xc6q\xf3\xddi\x9dZ\xbe!>\xe9\x02\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4it\u0224\x14\u03ae\xfd<.M\xfd\xbe\xf40V\x8d\x9a\x96\v\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\xe0\x94iximQP\xa9\xa2cQ?\x8ft\u0196\xf8\xb19|\xab\x8a\x01g\xf4\x82\xd3\u0171\xc0\x00\x00\xe0\x94iy{\xfb\x12\u027e\u0582\xb9\x1f\xbcY5\x91\xd5\xe4\x027(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94i\u007fUSk\xf8Z\xdaQ\x84\x1f\x02\x87b:\x9f\x0e\u041a\x17\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4i\x82\xfe\x8a\x86~\x93\xebJ\v\xd0QX\x93\x99\xf2\xec\x9aR\x92\x89lk\x93[\x8b\xbd@\x00\x00\u07d4i\x8a\x8ao\x01\xf9\xabh/c|yi\xbe\x88_lS\x02\xbf\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4i\x8a\xb9\xa2\xf33\x81\xe0|\fGC=\r!\xd6\xf36\xb1'\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4i\x94\xfb21\xd7\xe4\x1dI\x1a\x9dh\xd1\xfaL\xae,\xc1Y`\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\x9c\x9e\xe4q\x95Q\x1f5\xf8b\xcaL\"\xfd5\xae\x8f\xfb\xf4\x89\x04V9\x18$O@\x00\x00\u07d4i\x9f\xc6\u058aGuW<\x1d\u036e\xc80\xfe\xfdP9|N\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4i\xaf(\xb0tl\xac\r\xa1p\x84\xb99\x8c^6\xbb:\r\xf2\x896w\x03n\xdf\n\xf6\x00\x00\u07d4i\xb8\x0e\xd9\x0f\x84\x83J\xfa?\xf8.\xb9dp;V\tw\u0589\x01s\x17\x90SM\xf2\x00\x00\xe0\x94i\xb8\x1dY\x81\x14\x1e\u01e7\x14\x10`\xdf\u03cf5\x99\xff\xc6>\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4i\xbc\xfc\x1dC\xb4\xba\x19\xde{'K\xdf\xfb5\x13\x94\x12\xd3\u05c95e\x9e\xf9?\x0f\xc4\x00\x00\u07d4i\xbd%\xad\xe1\xa34lY\xc4\xe90\xdb*\x9dq^\xf0\xa2z\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\xc0\x8dtGT\xdep\x9c\xe9n\x15\xae\r\x1d9[:\"c\x8965\u026d\xc5\u07a0\x00\x00\u07d4i\xc2\xd85\xf1>\xe9\x05\x80@\x8ej2\x83\xc8\u0326\xa44\xa2\x89#\x8f\xd4,\\\xf0@\x00\x00\u07d4i\xc9N\a\u0129\xbe3\x84\xd9]\xfa<\xb9)\x00Q\x87;{\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4i\xcb>!S\x99\x8d\x86\xe5\xee \xc1\xfc\u0466\xba\uec86?\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\u04ddQ\b\x89\xe5R\xa3\x96\x13[\xfc\xdb\x06\xe3~8v3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94i\u064f8\xa3\xba=\xbc\x01\xfa\\,\x14'\xd8b\x83//p\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94i\xe2\xe2\xe7\x040|\xcc[\\\xa3\xf1d\xfe\xce.\xa7\xb2\xe5\x12\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4i\xffB\x90t\u02dblc\xbc\x91B\x84\xbc\xe5\xf0\xc8\xfb\xf7\u0409\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4i\xff\x89\x01\xb5Av?\x81|_)\x98\xf0-\xcf\xc1\xdf)\x97\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4j\x02:\xf5}XM\x84^i\x876\xf10\u06dd\xb4\r\xfa\x9a\x89\x05[ \x1c\x89\x00\x98\x00\x00\u07d4j\x04\xf5\xd5?\xc0\xf5\x15\xbe\x94+\x8f\x12\xa9\xcbz\xb0\xf3\x97x\x89\xa9\xaa\xb3E\x9b\xe1\x94\x00\x00\u07d4j\x05\xb2\x1cO\x17\xf9\xd7?_\xb2\xb0\u02c9\xffSV\xa6\xcc~\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94j\x0f\x05`f\xc2\xd5f(\x85\x02s\xd7\xec\xb7\xf8\xe6\xe9\x12\x9e\x8a\x01\x0f\r)<\u01e5\x88\x00\x00\u07d4j\x13\xd5\xe3,\x1f\xd2m~\x91\xffn\x051`\xa8\x9b,\x8a\xad\x89\x02\xe6/ \xa6\x9b\xe4\x00\x00\u07d4j.\x86F\x9a[\xf3|\xee\x82\xe8\x8bL8c\x89](\xfc\xaf\x89\x1c\"\x92f8[\xbc\x00\x00\u07d4j6\x94BL|\u01b8\xbc\u067c\u02baT\f\xc1\xf5\xdf\x18\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94jB\u0297\x1cex\u056d\xe2\x95\xc3\xe7\xf4\xad3\x1d\xd3BN\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4jD\xaf\x96\xb3\xf02\xaed\x1b\xebg\xf4\xb6\xc83B\xd3|]\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4jL\x89\a\xb6\x00$\x80W\xb1\xe4cT\xb1\x9b\u0705\x9c\x99\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4jQNbB\xf6\xb6\x8c\x13~\x97\xfe\xa1\u73b5U\xa7\xe5\xf7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4jS\xd4\x1a\xe4\xa7R\xb2\x1a\xbe\xd57FI\x95:Q=\xe5\xe5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4jaY\aJ\xb5s\xe0\xeeX\x1f\x0f=\xf2\u05a5\x94b\x9bt\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4jc7\x83?\x8fjk\xf1\f\xa7\xec!\xaa\x81\x0e\xd4D\xf4\u02c97\xbd$4\\\xe8\xa4\x00\x00\u07d4jcS\xb9qX\x9f\x18\xf2\x95\\\xba(\xab\xe8\xac\xcejWa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4jc\xfc\x89\xab\xc7\xf3n(-\x80x{{\x04\xaf\xd6U>q\x89\b\xacr0H\x9e\x80\x00\x00\u07d4jg\x9e7\x8f\xdc\xe6\xbf\xd9\u007f\xe6/\x04)Z$\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4j\x8c\xea-\xe8J\x8d\xf9\x97\xfd?\x84\xe3\b=\x93\xdeW\u0369\x89\x05k\xe0<\xa3\xe4}\x80\x00\xe0\x94j\x97Xt;`>\xea:\xa0RKB\x88\x97#\xc4\x159H\x8a\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4j\xa5s/;\x86\xfb\x8c\x81\xef\xbek[G\xb5cs\v\x06\u020965\u026d\xc5\u07a0\x00\x00\u07d4j\xb3#\xaePV\xed\nE0r\u016b\xe2\xe4/\xcf]q9\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4j\xb5\xb4\xc4\x1c\u0778)i\f/\xda\u007f \xc8^b\x9d\xd5\u0549d\u052fqL2\x90\x00\x00\u07d4j\xc4\x0fS-\xfe\xe5\x11\x81\x17\u04ad5-\xa7}Om\xa2\u0209\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4j\xc4\u053e-\xb0\u065d\xa3\xfa\xaa\xf7RZ\xf2\x82\x05\x1dj\x90\x89\x04X\xcaX\xa9b\xb2\x80\x00\u07d4j\xcd\u0723\xcd+I\x90\xe2\\\xd6\\$\x14\x9d\t\x12\t\x9ey\x89\xa2\xa1\xe0|\x9fl\x90\x80\x00\u07d4j\xd9\v\xe2R\xd9\xcdFM\x99\x81%\xfa\xb6\x93\x06\v\xa8\xe4)\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4j\u0753!\x93\xcd8IJ\xa3\xf0:\xec\xccKz\xb7\xfa\xbc\xa2\x89\x04\xdbs%Gc\x00\x00\x00\xe0\x94j\xe5\u007f'\x91|V*\x13*M\x1b\xf7\xec\n\u01c5\x83)&\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4j\xeb\x9ftt.\xa4\x91\x81=\xbb\xf0\xd6\xfc\xde\x1a\x13\x1dM\xb3\x89\x17\xe5T0\x8a\xa00\x00\x00\u07d4j\xf25\u04bb\xe0P\xe6)\x16\x15\xb7\x1c\xa5\x82\x96X\x81\x01B\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4j\xf6\xc7\xee\x99\xdf'\x1b\xa1[\xf3\x84\xc0\xb7d\xad\xcbM\xa1\x82\x8965f3\xeb\xd8\xea\x00\x00\u07d4j\xf8\xe5Yih,q_H\xadO\xc0\xfb\xb6~\xb5\x97\x95\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4j\xf9@\xf6>\u0278\xd8v'*\u0296\xfe\xf6\\\xda\xce\xcd\ua262\xa1]\tQ\x9b\xe0\x00\x00\u07d4j\xf9\xf0\xdf\uebbb_d\xbf\x91\xabw\x16i\xbf\x05)US\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4j\xff\x14f\xc2b6u\xe3\xcb\x0eu\xe4#\xd3z%\xe4B\xeb\x89]\u0212\xaa\x111\xc8\x00\x00\xe0\x94k\r\xa2Z\xf2g\u05c3l\"k\xca\xe8\xd8r\xd2\xceR\xc9A\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4k\x10\xf8\xf8\xb3\xe3\xb6\r\xe9\n\xa1-\x15_\x9f\xf5\xff\xb2,P\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\x17Y\x8a\x8e\xf5Oyz\xe5\x15\u0336Q}\x18Y\xbf\x80\x11\x89\x05k\xc7^-c\x10\x00\x00\u07d4k \xc0\x80`jy\xc7;\xd8\xe7[\x11qzN\x8d\xb3\xf1\u00c9\x10?sX\x03\xf0\x14\x00\x00\u07d4k\"\x84D\x02!\xce\x16\xa88-\xe5\xff\x02)G\"i\xde\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4k0\xf1\x829\x10\xb8m:\xcbZj\xfc\x9d\xef\xb6\xf3\xa3\v\xf8\x89\u3bb5sr@\xa0\x00\x00\u07d4k8\u0784\x1f\xad\u007fS\xfe\x02\xda\x11[\xd8j\xaff$f\xbd\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4kK\x99\xcb?\xa9\xf7\xb7L\u3903\x17\xb1\xcd\x13\t\n\x1az\x89\x03\x1b2~i]\xe2\x00\x00\u07d4kZ\xe7\xbfx\xecu\xe9\f\xb5\x03\xc7x\xcc\u04f2KO\x1a\xaf\x89+^:\xf1k\x18\x80\x00\x00\u07d4kc\xa2\u07f2\xbc\xd0\xca\xec\x00\"\xb8\x8b\xe3\f\x14Q\xeaV\xaa\x89+\xdbk\xf9\x1f\u007fL\x80\x00\u07d4kew\xf3\x90\x9aMm\xe0\xf4\x11R-Ep8d\x004\\\x89e\xea=\xb7UF`\x00\x00\u07d4kr\xa8\xf0a\xcf\xe6\x99j\xd4G\xd3\xc7,(\xc0\xc0\x8a\xb3\xa7\x89\xe7\x8cj\u01d9\x12b\x00\x00\u07d4kv\rHw\xe6\xa6'\xc1\xc9g\xbe\xe4Q\xa8P}\xdd\u06eb\x891T\xc9r\x9d\x05x\x00\x00\u07d4k\x83\xba\xe7\xb5e$EXU[\xcfK\xa8\xda \x11\x89\x1c\x17\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\x92]\xd5\xd8\xeda2\xabm\b`\xb8,D\xe1\xa5\x1f\x1f\xee\x89P; >\x9f\xba \x00\x00\xe0\x94k\x94a]\xb7Pej\u00cc~\x1c\xf2\x9a\x9d\x13g\u007fN\x15\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4k\x95\x1aC'N\xea\xfc\x8a\t\x03\xb0\xaf.\xc9+\xf1\xef\xc89\x89\x05k\xc7^-c\x10\x00\x00\u07d4k\x99%!\xec\x85#p\x84\x8a\u0597\xcc-\xf6Nc\xcc\x06\xff\x8965\u026d\xc5\u07a0\x00\x00\u07d4k\xa8\xf7\xe2_\xc2\xd8qa\x8e$\xe4\x01\x84\x19\x917\xf9\xf6\xaa\x89\x15\xafd\x86\x9ak\xc2\x00\x00\u07d4k\xa9\xb2\x1b5\x10k\xe1Y\xd1\xc1\xc2ez\xc5l\u049f\xfdD\x89\xf2\xdc}G\xf1V\x00\x00\x00\u07d4k\xafz*\x02\xaex\x80\x1e\x89\x04\xadz\xc0Q\b\xfcV\xcf\xf6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94k\xb2\xac\xa2?\xa1bm\x18\xef\xd6w\u007f\xb9}\xb0-\x8e\n\xe4\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4k\xb4\xa6a\xa3:q\xd4$\u051b\xb5\xdf(b.\xd4\xdf\xfc\xf4\x89\",\x8e\xb3\xfff@\x00\x00\u07d4k\xb5\b\x13\x14j\x9a\xddB\xee\"\x03\x8c\x9f\x1fti\xd4\u007fG\x89\n\xdaUGK\x814\x00\x00\u07d4k\xbc?5\x8af\x8d\u0461\x1f\x03\x80\xf3\xf71\bBj\xbdJ\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4k\xbd\x1eq\x93\x90\xe6\xb9\x10C\xf8\xb6\xb9\u07c9\x8e\xa8\x00\x1b4\x89llO\xa6\xc3\xdaX\x80\x00\u07d4k\xc8Z\xcdY(r.\xf5\tS1\xee\x88\xf4\x84\xb8\u03c3W\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4k\xd3\xe5\x9f#\x9f\xaf\xe4wk\xb9\xbd\xddk\ue0fa]\x9d\x9f\x8965\u026d\xc5\u07a0\x00\x00\u07d4k\xd4W\xad\xe0Qy]\xf3\xf2F\\89\xae\xd3\xc5\xde\xe9x\x8964\xbf9\xab\x98x\x80\x00\u07d4k\xe1c\x13d>\xbc\x91\xff\x9b\xb1\xa2\xe1\x16\xb8T\xea\x93:E\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4k\xe7Y^\xa0\xf0hH\x9a'\x01\xecFI\x15\x8d\xdcC\xe1x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\xe9\x03\x0e\xe6\xe2\xfb\u0111\xac\xa3\xde@\"\xd3\x01w+{}\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94k\xec1\x1a\xd0P\b\xb4\xaf5<\x95\x8c@\xbd\x06s\x9a?\xf3\x8a\x03w\xf6*\x0f\nbp\x00\x00\u07d4k\xf7\xb3\xc0e\xf2\xc1\xe7\xc6\xeb\t+\xa0\xd1Pf\xf3\x93\u0478\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4k\xf8o\x1e/+\x802\xa9\\Mw8\xa1\t\xd3\xd0\xed\x81\x04\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4l\x05\xe3N^\xf2\xf4.\u041d\xef\xf1\x02l\xd6k\xcbi`\xbb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4l\b\xa6\xdc\x01s\xc74)U\xd1\xd3\xf2\xc0e\xd6/\x83\xae\u01c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4l\n\xe9\xf0C\xc84\xd4Bq\xf14\x06Y=\xfe\tO8\x9f\x89RD*\xe13\xb6*\x80\x00\u07d4l\f\xc9\x17\xcb\xee}|\t\x97c\xf1Nd\xdf}4\xe2\xbf\t\x89\r\x8drkqw\xa8\x00\x00\xe0\x94l\x0eq/@\\Yr_\xe8)\xe9wK\xf4\xdf\u007fM\xd9e\x8a\f(h\x88\x9c\xa6\x8aD\x00\x00\xe0\x94l\x10\x12\x05\xb3#\xd7uD\xd6\xdcR\xaf7\xac\xa3\xce\xc6\xf7\xf1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4l\x15\xec5 \xbf\x8e\xbb\xc8 \xbd\x0f\xf1\x97x7T\x94\u03dd\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\xe0\x94l\x1d\xdd3\xc8\x19f\u0706!w`q\xa4\x12\x94\x82\xf2\xc6_\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4l%2\u007f\x8d\u02f2\xf4^V\x1e\x86\xe3]\x88P\xe5:\xb0Y\x89;\xcd\xf9\xba\xfe\xf2\xf0\x00\x00\u07d4l.\x9b\xe6\u052bE\x0f\xd1%1\xf3?\x02\x8caFt\xf1\x97\x89\xc2\x12z\xf8X\xdap\x00\x00\u07d4l5\x9eX\xa1=Ex\xa93\x8e3\\g\xe7c\x9f_\xb4\u05c9\v\xd1[\x94\xfc\x8b(\x00\x00\u07d4l=\x18pA&\xaa\x99\xee3B\xce`\xf5\xd4\xc8_\x18g\u0349\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4lGK\xc6jTx\x00f\xaaOQ.\xef\xa7s\xab\xf9\x19\u01c9\x05\x18\x83\x15\xf7v\xb8\x00\x00\u07d4lNBn\x8d\xc0\x05\u07e3Ql\xb8\xa6\x80\xb0.\ua56e\x8e\x89Hz\x9a0E9D\x00\x00\u07d4lR\xcf\b\x95\xbb5\xe6V\x16\x1eM\xc4j\xe0\xe9m\xd3\xe6,\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4lT\"\xfbK\x14\xe6\u064b`\x91\xfd\xecq\xf1\xf0\x86@A\x9d\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4l\\:T\u0367\xc2\xf1\x18\xed\xbaCN\xd8\x1en\xbb\x11\xddz\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4lc\xf8EV\u0490\xbf\u0359\xe44\ue657\xbf\xd7yWz\x89lk\x93[\x8b\xbd@\x00\x00\u07d4lc\xfc\x85\x02\x9a&T\u05db+\xeaM\xe3I\xe4REw\u0149#\xc7W\a+\x8d\xd0\x00\x00\u07d4led\xe5\xc9\xc2N\xaa\xa7D\xc9\xc7\xc9h\xc9\xe2\xc9\xf1\xfb\xae\x89I\x9bB\xa2\x119d\x00\x00\xe0\x94lg\xd6\xdb\x1d\x03Ql\x12\x8b\x8f\xf24\xbf=I\xb2m)A\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4lg\xe0\u05f6.*\bPiE\xa5\xdf\xe3\x82c3\x9f\x1f\"\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4lj\xa0\xd3\vdr\x19\x90\xb9PJ\x86?\xa0\xbf\xb5\xe5}\xa7\x89\x92^\x06\xee\xc9r\xb0\x00\x00\u07d4lqJX\xff\xf6\xe9}\x14\xb8\xa5\xe3\x05\xeb$@eh\x8b\xbd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4l\x80\rKI\xba\a%\x04`\xf9\x93\xb8\xcb\xe0\v&j%S\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4l\x80\x8c\xab\xb8\xff_\xbbc\x12\xd9\xc8\xe8J\xf8\xcf\x12\xef\bu\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94l\x82 )!\x8a\xc8\xe9\x8a&\f\x1e\x06@)4\x889\x87[\x8a\x01\x0f\x97\xb7\x87\xe1\xe3\b\x00\x00\u07d4l\x84\u02e7|m\xb4\xf7\xf9\x0e\xf1=^\xe2\x1e\x8c\xfc\u007f\x83\x14\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94l\x86\x87\xe3Aw\x10\xbb\x8a\x93U\x90!\xa1F\x9ej\x86\xbcw\x8a\x02[-\xa2x\xd9k{\x80\x00\xe0\x94l\x88,'s,\xef\\|\x13\xa6\x86\xf0\xa2\xeawUZ\u0089\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4l\xa5\xde\x00\x81}\xe0\xce\xdc\xe5\xfd\x00\x01(\xde\xde\x12d\x8b<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4l\xa6\xa12\xce\x1c\u0488\xbe\xe3\x0e\xc7\xcf\xef\xfb\x85\xc1\xf5\nT\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94l\xb1\x1e\xcb2\xd3\u0382\x96\x011\x066\xf5\xa1\f\xf7\u03db_\x8a\x04?\u851c8\x01\xf5\x00\x00\u07d4l\xc1\xc8x\xfal\u078a\x9a\v\x83\x11$~t\x1eFB\xfem\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94l\xcb\x03\xac\xf7\xf5<\xe8z\xad\xcc!\xa9\x93-\xe9\x15\xf8\x98\x04\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4l\xd2\x12\xae\xe0N\x01?=*\xba\u04a0#`k\xfb\\j\u01c9lj\xccg\u05f1\xd4\x00\x00\u07d4l\xd2(\xdcq!i0\u007f\xe2|\xebtw\xb4\x8c\xfc\x82r\xe5\x89\x044\xea\x94\u06caP\x00\x00\u07d4l\xe1\xb0\xf6\xad\xc4pQ\xe8\xab8\xb3\x9e\xdbA\x86\xb0;\xab\u0309Ay\x97\x94\xcd$\xcc\x00\x00\u07d4l\xea\xe3s=\x8f\xa4=l\xd8\f\x1a\x96\xe8\xeb\x93\x10\x9c\x83\xb7\x89\x10'\x94\xad \xdah\x00\x00\u07d4m\x05i\xe5U\x8f\xc7\xdf'f\xf2\xba\x15\u070a\xef\xfc[\xebu\x89\xd8\xe6\x00\x1el0+\x00\x00\u07d4m\x12\x0f\f\xaa\xe4O\xd9K\xca\xfeU\xe2\xe2y\uf5ba\\z\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4m\x14V\xff\xf0\x10N\xe8D\xa31G7\x8438\xd2L\xd6l\x89\a\xb0l\xe8\u007f\xddh\x00\x00\u07d4m \xef\x97\x04g\nP\v\xb2i\xb5\x83.\x85\x98\x02\x04\x9f\x01\x89\a\f\x1c\xc7;\x00\xc8\x00\x00\xe0\x94m/\x97g4\xb9\xd0\a\r\x18\x83\xcfz\u02b8\xb3\xe4\x92\x0f\xc1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4m9\xa9\u93c1\xf7i\xd7:\xad,\xea\xd2v\xac\x13\x87\xba\xbe\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4m;x6\xa2\xb9\u0619r\x1aM#{R#\x85\xdc\xe8\xdf\u034966\xc2^f\xec\xe7\x00\x00\u07d4m?+\xa8V\u033b\x027\xfava\x15k\x14\xb0\x13\xf2\x12@\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94m@\b\xb4\xa8\x88\xa8&\xf2H\xeej\v\r\xfd\xe9\xf92\x10\xb9\x8a\x01'\xfc\xb8\xaf\xae \xd0\x00\x00\u07d4m@\xca'\x82m\x97s\x1b>\x86\xef\xfc\u05f9*Aa\xfe\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4mD\x97J1\u0447\xed\xa1m\xddG\xb9\xc7\xecP\x02\xd6\x1f\xbe\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94mK\\\x05\xd0j \x95~\x17H\xabm\xf2\x06\xf3C\xf9/\x01\x8a\x02\x1f6\x06\x99\xbf\x82_\x80\x00\xe0\x94mL\xbf=\x82\x84\x83:\xe9\x93D0>\b\xb4\xd6\x14\xbf\xda;\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4mY\xb2\x1c\xd0\xe2t\x88\x04\u066b\xe0d\xea\u00be\xf0\xc9_'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4mc\u04ce\xe8\xb9\x0e\x0en\xd8\xf1\x92\xed\xa0Q\xb2\u05a5\x8b\xfd\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4mf4\xb5\xb8\xa4\x01\x95\xd9I\x02z\xf4\x82\x88\x02\t,\ued89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94m}\x1c\x94\x95\x11\xf8\x83\x03\x80\x8c`\xc5\xea\x06@\xfc\xc0&\x83\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4m\x84m\xc1&W\xe9\x1a\xf2P\bQ\x9c>\x85\u007fQp}\u0589\xf8\xd3\v\xc9#B\xf8\x00\x00\u07d4m\x91\x93\x99k\x19F\x17!\x11\x06\xd1c^\xb2l\u0136ll\x89\x15\xaa\x1e~\x9d\xd5\x1c\x00\x00\u07d4m\x99\x97P\x98\x82\x02~\xa9G#\x14$\xbe\xde\xde)e\u043a\x89l\x81\u01f3\x11\x95\xe0\x00\x00\u07d4m\xa0\xed\x8f\x1di3\x9f\x05\x9f*\x0e\x02G\x1c\xb4O\xb8\u00fb\x892\xbc8\xbbc\xa8\x16\x00\x00\u07d4m\xb7+\xfdC\xfe\xf4e\xcaV2\xb4Z\xabra@N\x13\xbf\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94m\xbe\x8a\xbf\xa1t(\x06&9\x817\x1b\xf3\xd3U\x90\x80kn\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4m\xc3\xf9+\xaa\x1d!\u06b78+\x892a\xa05o\xa7\xc1\x87\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4m\xc7\x05:q\x86\x16\xcf\u01cb\xeec\x82\xeeQ\xad\xd0\xc7\x030\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94m\xcc~d\xfc\xaf\xcb\xc2\xdcl\x0e^f,\xb3G\xbf\xfc\xd7\x02\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4m\xda_x\x8alh\x8d\u07d2\x1f\xa3\x85.\xb6\xd6\xc6\xc6)f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4m\xdb`\x92w\x9dXB\xea\xd3x\xe2\x1e\x81 \xfdLk\xc12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4m\xdf\xefc\x91U\u06ab\n\\\xb4\x95:\xa8\u016f\xaa\x88\x04S\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4m\xe0/-\xd6~\xfd\xb794\x02\xfa\x9e\xaa\xcb\xcfX\x9d.V\x89@\x13\x8b\x91~\u07f8\x00\x00\u07d4m\u4d418\\\xf7\xfc\x9f\xe8\xc7}\x13\x1f\xe2\xeew$\xc7j\x89})\x97s=\xcc\xe4\x00\x00\u07d4m\xe4\xd1R\x19\x18/\xaf:\xa2\xc5\xd4\xd2Y_\xf20\x91\xa7'\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4m\xed\xf6.t?M,*K\x87\xa7\x87\xf5BJz\xeb9<\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4m\xf2Of\x85\xa6/y\x1b\xa37\xbf?\xf6~\x91\xf3\u053c:\x89ukI\xd4\nH\x18\x00\x00\u07d4m\xf5\xc8O{\x90\x9a\xab>a\xfe\x0e\xcb\x1b;\xf2`\"*\u0489\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4m\xff\x90\xe6\xdc5\x9d%\x90\x88+\x14\x83\xed\xbc\xf8\x87\xc0\xe4#\x8965\u026d\xc5\u07a0\x00\x00\u07d4n\x01\xe4\xadV\x9c\x95\xd0\a\xad\xa3\r^-\xb1(\x88I\"\x94\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\a;f\u0478\xc6gD\u0600\x96\xa8\u0759\xec~\x02(\u0689\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\x0e\xe7\x06\x12\xc9v(}I\x9d\u07e6\xc0\xdc\xc1,\x06\xde\xea\x89\a\v\u0579V!F\x00\x00\xe0\x94n\x12\xb5\x1e\"[JCr\xe5\x9a\u05e2\xa1\xa1>\xa3\u04e17\x8a\x03\x00F\xc8\xccw_\x04\x00\x00\u07d4n\x1a\x04l\xaf[JW\xf4\xfdK\xc1sb!&\xb4\xe2\xfd\x86\x89a\t=|,m8\x00\x00\u07d4n\x1e\xa4\xb1\x83\xe2R\u027bwg\xa0\x06\u05346\x96\u02ca\xe9\x89\x0f\xf3x<\x85\xee\u0400\x00\u07d4n%[p\n\xe7\x13\x8aK\xac\xf2(\x88\xa9\xe2\xc0\n(^\xec\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n'\n\xd5)\xf1\xf0\xb8\xd9\xcbm$'\xec\x1b~-\xc6Jt\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4n.\xab\x85\u0709\xfe)\xdc\n\xa1\x852G\u06b4:R=V\x89\x04V9\x18$O@\x00\x00\u07d4n:Q\xdbt=3M/\xe8\x82$\xb5\xfe|\x00\x8e\x80\xe6$\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4nL*\xb7\xdb\x02i9\xdb\u04fch8J\xf6`\xa6\x18\x16\xb2\x89\t\r\x97/22<\x00\x00\u07d4nM.9\u0203f)\u5d07\xb1\x91\x8af\x9a\xeb\u07556\x8965\u026d\xc5\u07a0\x00\x00\u07d4n\\-\x9b\x1cTj\x86\xee\xfd]\nQ \xc9\xe4\xe70\x19\x0e\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4n`\xae\u19cf\x8e\u068bBLs\xe3S5J\xe6|0B\x89\xbd5\xa4\x8d\x99\x19\xe6\x00\x00\u07d4nd\xe6\x12\x9f\"N7\x8c\x0ensj~z\x06\xc2\x11\xe9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4nm[\xbb\xb9\x05;\x89\xd7D\xa2s\x16\u00a7\xb8\xc0\x9bT}\x891Rq\n\x02>m\x80\x00\u07d4nr\xb2\xa1\x18j\x8e)\x16T;\x1c\xb3jh\x87\x0e\xa5\u0457\x89\n\x15D\xbe\x87\x9e\xa8\x00\x00\u07d4nv\x1e\xaa\x0f4_w{TA\xb7:\x0f\xa5\xb5k\x85\xf2-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4ny\xed\u0504[\anL\u060d\x18\x8bnC-\xd9?5\xaa\x893\xc5I\x901r\f\x00\x00\u07d4n\x82\x12\xb7\"\xaf\xd4\b\xa7\xa7>\xd3\xe29^\xe6EJ\x030\x89\b\x9e\x91y\x94\xf7\x1c\x00\x00\u07d4n\x84\x87m\xbb\x95\xc4\vfV\xe4+\xa9\xae\xa0\x8a\x99;T\u0709;\xbc`\xe3\xb6\u02fe\x00\x00\u07d4n\x84\xc2\xfd\x18\xd8\tW\x14\xa9h\x17\x18\x9c\xa2\x1c\xcab\xba\xb1\x89\x12{lp&!\u0340\x00\u07d4n\x86m\x03-@Z\xbd\xd6\\\xf6QA\x1d\x807\x96\xc2#\x11\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94n\x89\x9eY\xa9\xb4\x1a\xb7\xeaA\xdfu\x17\x86\x0f*\xcbY\xf4\xfd\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4n\x89\xc5\x1e\xa6\xde\x13\xe0l\xdct\x8bg\xc4A\x0f\u9f2b\x03\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\x8a&h\x9fz/\xde\xfd\x00\x9c\xba\xaaS\x10%4P\u06ba\x89o!7\x17\xba\xd8\xd3\x00\x00\u07d4n\x96\xfa\xed\xa3\x05C\x02\xc4_X\xf1a2L\x99\xa3\xee\xbbb\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4n\xb0\xa5\xa9\xae\x96\xd2,\xf0\x1d\x8f\xd6H;\x9f8\xf0\x8c,\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xb3\x81\x96\x17@@X&\x8f\f<\xff5\x96\xbf\xe9\x14\x8c\x1c\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94n\xb5W\x8ak\xb7\xc3!S\x19[\r\x80 \xa6\x91HR\xc0Y\x8a\x8b\u00ab\xf4\x02!\xf4\x80\x00\x00\u07d4n\xbb^iW\xaa\x82\x1e\xf6Y\xb6\x01\x8a9:PL\xaeDP\x89lk\x93[\x8b\xbd@\x00\x00\u07d4n\xbc\xf9\x95\u007f_\xc5\u916d\xd4u\";\x04\xb8\xc1Jz\xed\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4n\xc3e\x95q\xb1\x1f\x88\x9d\xd49\xbc\xd4\xd6u\x10\xa2[\xe5~\x89\x06\xaa\xf7\xc8Qm\f\x00\x00\u07d4n\u021b9\xf9\xf5'jU>\x8d\xa3\x0en\xc1z\xa4~\xef\u01c9\x18BO_\v\x1bN\x00\x00\u07d4n\xc9m\x13\xbd\xb2M\u01e5W)?\x02\x9e\x02\xddt\xb9zU\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xca\xef\xa6\xfc>\xe54bm\xb0,o\x85\xa0\u00d5W\x1ew\x89 \x86\xac5\x10R`\x00\x00\u07d4n\u04a1+\x02\xf8\u0188\u01f5\u04e6\xea\x14\xd66\x87\u06b3\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4n\u0604E\x9f\x80\x9d\xfa\x10\x16\xe7p\xed\xaf>\x9f\xefF\xfa0\x89\xb8R\xd6x \x93\xf1\x00\x00\xe0\x94n\xdf\u007fR\x83r\\\x95>\xe6C\x17\xf6a\x88\xaf\x11\x84\xb03\x8a\x01\xb4d1\x1dE\xa6\x88\x00\x00\u07d4n\xe8\xaa\xd7\xe0\xa0e\u0605-|;\x9an_\xdcK\xf5\f\x00\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4n\xef\u0705\x0e\x87\xb7\x15\xc7'\x91w<\x03\x16\xc3U\x9bX\xa4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xf9\xe8\u0276!}Vv\x9a\xf9}\xbb\x1c\x8e\x1b\x8b\xe7\x99\u0489\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4n\xfb\xa8\xfb*\u0176s\a)\xa9r\xec\"D&\xa2\x87\u00ed\x89\x0fY\x85\xfb\xcb\xe1h\x00\x00\xe0\x94n\xfd\x90\xb55\xe0\v\xbd\x88\x9f\xda~\x9c1\x84\xf8y\xa1Q\u06ca\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4o\x05\x16f\xcbO{\u04b1\x90r!\xb8)\xb5U\u05e3\xdbt\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4o\x0e\xdd#\xbc\xd8_`\x15\xf9(\x9c(\x84\x1f\xe0L\x83\xef\xeb\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4o\x13zq\xa6\xf1\x97\xdf,\xbb\xf0\x10\u073d\x89a\t=|,m8\x00\x00\u07d4p\x10\xbe-\xf5{\u042b\x9a\xe8\x19l\xd5\n\xb0\xc5!\xab\xa9\xf9\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4p#\xc7\tV\xe0J\x92\xd7\x00%\xaa\u0497\xb59\xaf5Xi\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p%\x96]+\x88\xda\x19}DY\xbe=\xc98cD\xcc\x1f1\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d4p(\x02\xf3m\x00%\x0f\xabS\xad\xbc\u0596\xf0\x17oc\x8aI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4pH\x19\xd2\xe4Mn\xd1\xda%\xbf\u0384\u011f\u0322V\x13\xe5\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4pJn\xb4\x1b\xa3O\x13\xad\xdd\xe7\xd2\xdb}\xf0I\x15\u01e2!\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4pJ\xb1\x15\r^\x10\xf5\xe3I\x95\b\xf0\xbfpe\x0f\x02\x8dK\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4pJ\xe2\x1dv-n\x1d\xde(\xc25\xd11\x04Yr6\xdb\x1a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4pM$<)x\xe4l,\x86\xad\xbe\xcd$n;)_\xf63\x89m\x12\x1b\xeb\xf7\x95\xf0\x00\x00\u07d4pM]\xe4\x84m9\xb5<\xd2\x1d\x1cI\xf0\x96\xdb\\\x19\xba)\x89\b=lz\xabc`\x00\x00\u07d4p]\xdd85T\x82\xb8\xc7\u04f5\x15\xbd\xa1P\r\xd7\u05e8\x17\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94pan(\x92\xfa&\x97\x05\xb2\x04k\x8f\xe3\xe7/\xa5X\x16\u04ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4pg\x0f\xbb\x05\xd30\x14DK\x8d\x1e\x8ew\x00%\x8b\x8c\xaam\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\x81\xfak\xaa\xd6\u03f7\xf5\x1b,\xca\x16\xfb\x89p\x99\x1ad\xba\x89\f\xae\xc0\x05\xf6\xc0\xf6\x80\x00\xe0\x94p\x85\xae~~M\x93!\x97\xb5\u01c5\x8c\x00\xa3gF&\xb7\xa5\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4p\x86\xb4\xbd\xe3\xe3]J\xeb$\xb8%\xf1\xa2\x15\xf9\x9d\x85\xf7E\x89lh\xcc\u041b\x02,\x00\x00\u07d4p\x8a*\xf4%\u03b0\x1e\x87\xff\xc1\xbeT\xc0\xf52\xb2\x0e\xac\u0589\aE\u0503\xb1\xf5\xa1\x80\x00\u07d4p\x8e\xa7\a\xba\xe45\u007f\x1e\xbe\xa9Y\u00e2P\xac\u05aa!\xb3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794p\x8f\xa1\x1f\xe3=\x85\xad\x1b\xef\u02ee8\x18\xac\xb7\x1fj}~\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4p\x9101\x16\xd5\xf28\x9b##\x8bMej\x85\x96\u0644\u04c9;N~\x80\xaaX3\x00\x00\u07d4p\x99\xd1/n\xc6V\x89\x9b\x04\x9avW\x06]b\x99h\x92\u0209\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4p\x9f\xe9\xd2\xc1\xf1\xceB |\x95\x85\x04J`\x89\x9f5\x94/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\xa05I\xaaah\xe9~\x88\xa5\b3\nZ\v\xeatq\x1a\x89Hz\x9a0E9D\x00\x00\u07d4p\xa4\x06}D\x8c\xc2]\xc8\xe7\x0ee\x1c\xea|\xf8N\x92\x10\x9e\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4p\xab4\xbc\x17\xb6o\x9c;c\xf1Q'O*r|S\x92c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\xc2\x13H\x8a\x02\f<\xfb9\x01N\xf5\xbad\x04rK\u02a3\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4p\xd2^\xd2\u022d\xa5\x9c\b\x8c\xf7\r\xd2+\xf2\u06d3\xac\xc1\x8a\x899GEE\u4b7c\x00\x00\u07d4p\xe5\xe9\xdas_\xf0w$\x9d\u02da\xaf=\xb2\xa4\x8d\x94\x98\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4p\xfe\xe0\x8b\x00\xc6\xc2\xc0Jp\xc0\xce=\x92\u03ca\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u0794q\v\xe8\xfd^)\x18F\x8b\u2abe\xa8\r\x82\x845\u05d6\x12\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4q\x13]\x8f\x05\x96<\x90ZJ\a\x92)\t#Z\x89jR\ua262\xa1]\tQ\x9b\xe0\x00\x00\u07d4q\x1e\xcfw\xd7\x1b=\x0e\xa9\\\xe4u\x8a\xfe\u0379\xc11\a\x9d\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4q!?\xca14\x04 N\u02e8q\x97t\x1a\xa9\xdf\xe9c8\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94q+vQ\x02\x14\xdcb\x0fl:\x1d\u049a\xa2+\xf6\xd2\x14\xfb\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4q/\xf77\n\x13\xed6\ts\xfe\u071f\xf5\xd2\xc9:P^\x9e\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4q3\x84:x\xd99\u019dD\x86\xe1\x0e\xbc{`*4\x9f\xf7\x89\x11\xd5\xca\xcc\xe2\x1f\x84\x00\x00\u07d4qH\xae\xf32a\xd8\x03\x1f\xac?q\x82\xff5\x92\x8d\xafT\u0649\xdeB\xee\x15D\u0750\x00\x00\u07d4qcu\x8c\xbblLR^\x04\x14\xa4\n\x04\x9d\xcc\xcc\xe9\x19\xbb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4qh\xb3\xbb\x8c\x16s!\u067d\xb0#\xa6\xe9\xfd\x11\xaf\u026f\u0649a\t=|,m8\x00\x00\u07d4qirN\xe7\"q\xc54\xca\xd6B\x0f\xb0N\xe6D\u02c6\xfe\x89\x16<+@\u06e5R\x00\x00\u07d4qj\xd3\xc3:\x9b\x9a\n\x18\x96sW\x96\x9b\x94\xee}*\xbc\x10\x89\x1a!\x17\xfeA*H\x00\x00\xe0\x94qk\xa0\x1e\xad*\x91'\x065\xf9_%\xbf\xaf-\xd6\x10\xca#\x8a\ty\xe7\x01 V\xaax\x00\x00\u07d4qmP\u0320\x1e\x93\x85\x00\xe6B\x1c\xc0p\xc3P|g\u04c7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4qv,cg\x8c\x18\xd1\xc67\x8c\xe0h\xe6f8\x13\x15\x14~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4qxL\x10Q\x17\xc1\xf6\x895y\u007f\xe1Y\xab\xc7NC\xd1j\x89l\x81\u01f3\x11\x95\xe0\x00\x00\xe0\x94qyro\\q\xae\x1bm\x16\xa6\x84(\x17Nk4\xb26F\x8a\x01\x8e\xa2P\t|\xba\xf6\x00\x00\xe0\x94q|\xf9\xbe\xab680\x8d\xed~\x19^\f\x86\x13-\x16?\xed\x8a\x032n\xe6\xf8e\xf4\"\x00\x00\u07d4q\x80\xb8>\xe5WC\x17\xf2\x1c\x80r\xb1\x91\u0615\xd4aS\u00c9\x18\xef\xc8J\xd0\u01f0\x00\x00\u07d4q\x94kq\x17\xfc\x91^\xd1\a8_B\u065d\xda\xc62I\u0089lk\x93[\x8b\xbd@\x00\x00\xe0\x94q\x9e\x89\x1f\xbc\xc0\xa3>\x19\xc1-\xc0\xf0 9\xca\x05\xb8\x01\u07ca\x01OU8F:\x1bT\x00\x00\u07d4q\xc7#\n\x1d5\xbd\u0581\x9e\u0539\xa8\x8e\x94\xa0\xeb\a\x86\u0749\uc80b5=$\x14\x00\x00\u07d4q\xd2\xccm\x02W\x8ce\xf7\r\xf1\x1bH\xbe\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4r\x83\xcdFu\xdaX\u0116UaQ\xda\xfd\x80\xc7\xf9\x95\xd3\x18\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4r\x86\xe8\x9c\xd9\u078fz\x8a\x00\xc8o\xfd\xb59\x92\u0752Q\u0449i*\xe8\x89p\x81\xd0\x00\x00\u07d4r\x8f\x9a\xb0\x80\x15}\xb3\a1V\xdb\xca\x1a\x16\x9e\xf3\x17\x94\a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4r\x94\xc9\x18\xb1\xae\xfbM%\x92~\xf9\u05d9\xe7\x1f\x93\xa2\x8e\x85\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94r\x94\uc763\x10\xbckK\xbd\xf5C\xb0\xefE\xab\xfc>\x1bM\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4r\x9a\xadF'tNS\xf5\xd6c\t\xaatD\x8b:\xcd\xf4o\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xa2\xfc\x86u\xfe\xb9r\xfaA\xb5\r\xff\u06fa\xe7\xfa*\u07f7\x89\x9a\xb4\xfcg\xb5(\xc8\x00\x00\u07d4r\xa8&\b&)G&\xa7[\xf3\x9c\u066a\x9e\a\xa3\xea\x14\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4r\xb0Yb\xfb*\u0549\xd6Z\xd1j\"U\x9e\xba\x14X\xf3\x87\x89\a?u\u0460\x85\xba\x00\x00\u07d4r\xb5c?\xe4w\xfeT.t/\xac\xfdi\f\x13xT\xf2\x16\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4r\xb7\xa0=\xda\x14\u029cf\x1a\x1dF\x9f\xd376\xf6s\xc8\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xb9\x04D\x0e\x90\xe7 \u05ac\x1c*\u05dc2\x1d\xcc\x1c\x1a\x86\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94r\xb9\nM\xc0\x97#\x94\x92\u0179w}\xcd\x1eR\xba+\xe2\u008a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4r\xbb'\u02d9\xf3\xe2\xc2\u03d0\xa9\x8fp}0\xe4\xa2\x01\xa0q\x89X\xe7\x92n\xe8X\xa0\x00\x00\xe0\x94r\xc0\x83\xbe\xad\xbd\xc2'\xc5\xfbC\x88\x15\x97\xe3.\x83\xc2`V\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4r\xcd\x04\x8a\x11\x05tH)\x83I-\xfb\x1b\xd2yB\xa6\x96\xba\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xd0=M\xfa\xb3P\f\xf8\x9b\x86\x86o\x15\xd4R\x8e\x14\xa1\x95\x89\xf3K\x82\xfd\x8e\x91 \x00\x00\u07d4r\u06bb[n\ud799\xbe\x91X\x88\xf6V\x80V8\x16\b\xf8\x89\vL\x96\xc5,\xb4\xfe\x80\x00\u07d4r\xfbI\u009d#\xa1\x89P\u0132\xdc\r\xdfA\x0fS-oS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xfe\xaf\x12EyR9Td[\u007f\xaf\xff\x03x\xd1\xc8$.\x8965\u026d\xc5\u07a0\x00\x00\u07d4s\x01\xdcL\xf2mq\x86\xf2\xa1\x1b\xf8\xb0\x8b\xf2)F?d\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s\x04G\xf9|\xe9\xb2_\"\xba\x1a\xfb6\xdf'\xf9Xk\ub6c9,s\xc97t,P\x00\x00\u07d4s\x06\xde\x0e(\x8bV\xcf\u07d8~\xf0\xd3\xcc)f\a\x93\xf6\u0749\x1b\x8a\xbf\xb6.\xc8\xf6\x00\x00\xe0\x94s\r\x87c\u01a4\xfd\x82J\xb8\xb8Y\x16\x1e\xf7\xe3\xa9j\x12\x00\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4s\x12\x81sH\x95(\x01.v\xb4\x1a^(\u018b\xa4\xe3\xa9\u050965\u026d\xc5\u07a0\x00\x00\u07d4s\x13F\x12\bETUFTE\xa4Y\xb0l7s\xb0\xeb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s/\xea\xd6\x0f{\xfd\u05a9\xde\u0101%\xe3s]\xb1\xb6eO\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4sB#\xd2\u007f\xf2>Y\x06\xca\xed\"YW\x01\xbb4\x83\f\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4sG>r\x11Q\x10\xd0\xc3\xf1\x17\b\xf8nw\xbe+\xb0\x98<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4sRXm\x02\x1a\xd0\xcfw\xe0\xe9(@JY\xf3t\xffE\x82\x89\xb8Pz\x82\a( \x00\x00\u07d4sU\v\xebs+\xa9\u076f\xdaz\xe4\x06\xe1\x8f\u007f\xeb\x0f\x8b\xb2\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4s[\x97\xf2\xfc\x1b\xd2K\x12\an\xfa\xf3\xd1(\x80s\xd2\f\x8c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4s^2\x86f\xedV7\x14+3\x06\xb7|\xccT`\xe7,=\x89j\xb8\xf3xy\u0251\x00\x00\u07d4sc\u0350\xfb\xab[\xb8\u011a\xc2\x0f\xc6,9\x8f\xe6\xfbtL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4skDP=\xd2\xf6\xddTi\xffL[-\xb8\xeaO\xece\u0409\x11\x04\xeeu\x9f!\xe3\x00\x00\xe0\x94sk\xf1@,\x83\x80\x0f\x89>X1\x92X*\x13N\xb52\xe9\x8a\x02\x1e\x19\u0493\xc0\x1f&\x00\x00\xe0\x94s\x8c\xa9M\xb7\u038b\xe1\xc3\x05l\u0598\x8e\xb3v5\x9f3S\x8a\x05f[\x96\xcf5\xac\xf0\x00\x00\u07d4s\x91K\"\xfc/\x13\x15\x84$}\x82\xbeO\ucfd7\x8a\u053a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s\x93'\t\xa9\u007f\x02\u024eQ\xb0\x911(e\x12#\x85\xae\x8e\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4s\x93\xcb\xe7\xf9\xba!e\xe5\xa7U5\x00\xb6\xe7]\xa3\xc3:\xbf\x89\x05k\xc7^-c\x10\x00\x00\u07d4s\xb4\u0519\xde?8\xbf5\xaa\xf7i\xa6\xe3\x18\xbcm\x126\x92\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94s\xbe\xddo\xda{\xa3'!\x85\b{cQ\xfc\x13=HN7\x8a\x01\x12&\xbf\x9d\xceYx\x00\x00\u07d4s\xbf\xe7q\x0f1\u02b9I\xb7\xa2`O\xbfR9\xce\xe7\x90\x15\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94s\u03c0\xae\x96\x88\xe1X\x0eh\xe7\x82\xcd\b\x11\xf7\xaaIM,\x8a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\xe0\x94s\xd7&\x9f\xf0l\x9f\xfd3uL\xe5\x88\xf7J\x96j\xbb\xbb\xba\x8a\x01e\xc9fG\xb3\x8a \x00\x00\u07d4s\xd8\xfe\xe3\u02c6M\xce\"\xbb&\u029c/\bm^\x95\xe6;\x8965\u026d\xc5\u07a0\x00\x00\u07d4s\xdf<>yU\xf4\xf2\xd8Y\x83\x1b\xe3\x80\x00\xb1\ak8\x84\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4s\u48b6\f\U0010e2ef+w~\x17Z[\x1eM\f-\x8f\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94t\n\xf1\xee\xfd3e\u05cb\xa7\xb1,\xb1\xa6s\xe0j\arF\x8a\x04+\xf0kx\xed;P\x00\x00\xe0\x94t\v\xfdR\xe0\x16g\xa3A\x9b\x02\x9a\x1b\x8eEWj\x86\xa2\u06ca\x03\x8e\xba\xd5\xcd\xc9\x02\x80\x00\x00\u07d4t\x0fd\x16\x14w\x9d\u03e8\x8e\xd1\xd4%\xd6\r\xb4*\x06\f\xa6\x896\"\xc6v\b\x10W\x00\x00\u07d4t\x12\u027c0\xb4\xdfC\x9f\x021\x00\xe69$\x06j\xfdS\xaf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4t\x16\x93\xc3\x03vP\x85\x13\b \xcc+c\xe9\xfa\x92\x13\x1b\x89A\rXj \xa4\xc0\x00\x00\u07d4t!\xce[\xe3\x81s\x8d\u0703\xf0&!\x97O\xf0hly\xb8\x89Xx\x8c\xb9K\x1d\x80\x00\x00\u07d4t1j\xdf%7\x8c\x10\xf5v\u0574\x1aoG\xfa\x98\xfc\xe3=\x89\x128\x13\x1e\\z\xd5\x00\x00\u07d4t6Q\xb5^\xf8B\x9d\xf5\f\xf8\x198\xc2P\x8d\xe5\u0207\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t=\xe5\x00&\xcag\xc9M\xf5O\x06b`\xe1\xd1J\xcc\x11\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tE /\ft)z\x00N\xb3rj\xa6\xa8-\xd7\xc0/\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tK\x03\xbb\xa8X*\xe5I\x8e-\xc2-\x19\x94\x94g\xabS\xfc\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4tL\fw\xba\u007f#i \xd1\xe44\xde]\xa3>H\xeb\xf0,\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4tP\xff\u007f\x99\xea\xa9\x11bu\u07ach\xe4(\xdf[\xbc\u0639\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tV\u0172\xc5Cn>W\x10\b\x93?\x18\x05\xcc\xfe4\xe9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4tZ\u04eb\xc6\xee\xeb$qh\x9bS\x9ex\x9c\xe2\xb8&\x83\x06\x89=A\x94\xbe\xa0\x11\x92\x80\x00\xe0\x94tZ\xec\xba\xf9\xbb9\xb7Jg\xea\x1c\xe6#\xde6\x84\x81\xba\xa6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4t\\\xcf-\x81\x9e\u06fd\u07a8\x11{\\I\xed<*\x06n\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4tb\u021c\xaa\x9d\x8dx\x91\xb2T]\xef!otd\u057b!\x89\x05\xea\xedT\xa2\x8b1\x00\x00\u07d4td\x8c\xaa\xc7H\xdd\x13\\\xd9\x1e\xa1L(\xe1\xbdM\u007f\xf6\xae\x89\xa8\r$g~\xfe\xf0\x00\x00\xe0\x94tq\xf7.\xeb0\x06$\xeb(.\xabM\x03r\x00\x00\x00\xe0\x94t\x84\xd2k\xec\xc1\xee\xa8\xc61^\xc3\xee\nE\x01\x17\u0706\xa0\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4t\x86:\xce\xc7]\x03\xd5>\x86\x0ed\x00/,\x16^S\x83w\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\x89\u030a\xbeu\u0364\xef\r\x01\xce\xf2`^G\xed\xa6z\xb1\x89\a?u\u0460\x85\xba\x00\x00\u07d4t\x8c(^\xf1#?\xe4\xd3\x1c\x8f\xb17\x833r\x1c\x12\xe2z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t\x90\x87\xac\x0fZ\x97\xc6\xfa\xd0!S\x8b\xf1\xd6\u0361\x8e\r\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\x95\xaex\xc0\xd9\x02a\xe2\x14\x0e\xf2\x061\x04s\x1a`\xd1\xed\x89\x01\xdbPq\x89%!\x00\x00\u07d4t\x9aJv\x8b_#rH\x93\x8a\x12\xc6#\x84{\xd4\xe6\x88\u0709\x03\xe73b\x87\x14 \x00\x00\u07d4t\x9a\xd6\xf2\xb5pk\xbe/h\x9aD\u0136@\xb5\x8e\x96\xb9\x92\x89\x05k\xc7^-c\x10\x00\x00\u07d4t\xa1\u007f\x06K4N\x84\xdbce\u0695\x91\xff\x16(%vC\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4t\xae\xec\x91]\xe0\x1c\u019b,\xb5\xa65o\xee\xa1FX\xc6\u0149\f\x9a\x95\xee)\x86R\x00\x00\u07d4t\xaf\xe5I\x02\xd6\x15x%v\xf8\xba\xac\x13\xac\x97\f\x05\x0fn\x89\t\xa1\xaa\xa3\xa9\xfb\xa7\x00\x00\u07d4t\xb7\xe0\"\x8b\xae\xd6YW\xae\xbbM\x91m3:\xae\x16O\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t\xbcJ^ E\xf4\xff\x8d\xb1\x84\xcf:\x9b\f\x06Z\xd8\a\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4t\xbc\xe9\xec86-l\x94\u032c&\xd5\xc0\xe1:\x8b;\x1d@\x8965&A\x04B\xf5\x00\x00\u07d4t\xbfzZ\xb5\x92\x93\x14\x9b\\`\xcf6Bc\xe5\xeb\xf1\xaa\r\x89\x06G\f>w\x1e<\x00\x00\xe0\x94t\xc7<\x90R\x8a\x15s6\xf1\xe7\xea b\n\xe5?\xd2G(\x8a\x01\xe6:.S\x8f\x16\xe3\x00\x00\u07d4t\u0464\xd0\xc7RN\x01\x8dN\x06\xed;d\x80\x92\xb5\xb6\xaf,\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94t\xd3f\xb0{/VG}|pw\xaco\xe4\x97\xe0\xebeY\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4t\xd3zQt{\xf8\xb7q\xbf\xbfC\x9493\xd1\x00\xd2\x14\x83\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\xd6q\u065c\xbe\xa1\xabW\x90cu\xb6?\xf4+PE\x1d\x17\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\xeb\xf4BVF\xe6\u03c1\xb1\t\xce{\xf4\xa2\xa6=\x84\x81_\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4t\xed3\xac\xf4?5\xb9\x8c\x920\xb9\xe6d.\xcbS0\x83\x9e\x89$\xf6\xdf\xfbI\x8d(\x00\x00\u07d4t\xef(i\xcb\xe6\b\x85`E\xd8\xc2\x04\x11\x18W\x9f\"6\xea\x89\x03<\xd6E\x91\x95n\x00\x00\u07d4t\xfcZ\x99\xc0\xc5F\x05\x03\xa1;\x05\tE\x9d\xa1\x9c\xe7\u0350\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4u\v\xbb\x8c\x06\xbb\xbf$\bC\xccux.\xe0/\b\xa9tS\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4u\x14\xad\xbd\xc6?H?0M\x8e\x94\xb6\u007f\xf30\x9f\x18\v\x82\x89!\u0120n-\x13Y\x80\x00\u0794u\x17\xf1l(\xd12\xbb@\xe3\xba6\u01ae\xf11\xc4b\xda\x17\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4u\x1a,\xa3Nq\x87\xc1c\u048e6\x18\xdb(\xb1<\x19m&\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94u\x1a\xbc\xb6\xcc\x030Y\x91\x18\x15\xc9o\u04516\n\xb0D-\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4u&\xe4\x82R\x9f\n\x14\xee\u0248q\xdd\xdd\x0er\x1b\f\u0662\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4u)\xf3y{\xb6\xa2\x0f~\xa6I$\x19\xc8L\x86vA\xd8\x1c\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94u*^\xe22a,\xd3\x00_\xb2n[Y}\xe1\x9fwk\xe6\x8a\x01'\xfc\xb8\xaf\xae \xd0\x00\x00\u07d4u,\x9f\xeb\xf4/f\xc4x{\xfa~\xb1|\xf53;\xbaPp\x89j\x99\xf2\xb5O\xddX\x00\x00\u07d4u930F\u07b1\xef\x8e\u07b9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94u\xc1\xad#\xd2?$\xb3\x84\xd0\xc3\x14\x91w\xe8f\x97a\r!\x8a\x01\\[\xcdl(\x8b\xbd\x00\x00\u07d4u\xc2\xff\xa1\xbe\xf5I\x19\xd2\t\u007fz\x14-.\x14\xf9\xb0JX\x89\x90\xf3XP@2\xa1\x00\x00\u07d4u\xd6|\xe1N\x8d)\xe8\xc2\xff\u3051{\x93\v\x1a\xff\x1a\x87\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4u\xde~\x93R\xe9\v\x13\xa5\x9aXx\xff\xec\u01c3\x1c\xacM\x82\x89\x94\x89#z\u06daP\x00\x00\u07d4u\xf7S\x9d0\x9e\x909\x98\x9e\xfe.\x8b-\xbd\x86Z\r\xf0\x88\x89\x85[[\xa6\\\x84\xf0\x00\x00\u07d4v\b\xf47\xb3\x1f\x18\xbc\vd\u04c1\xae\x86\xfd\x97\x8e\u05f3\x1f\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94v\x0f\xf35N\x0f\u0793\x8d\x0f\xb5\xb8,\xef[\xa1\\=)\x16\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4v\x1an6,\x97\xfb\xbd|Yw\xac\xba-\xa7F\x876_I\x89\t\xf7J\xe1\xf9S\xd0\x00\x00\u07d4v\x1el\xae\xc1\x89\xc20\xa1b\xec\x00e0\x19>g\u03dd\x19\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94v\x1f\x8a:*\U00028f7e\x1d\xa0\t2\x1f\xb2\x97d\xebb\xa1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4v)\x98\xe1\xd7R'\xfc\xedzp\xbe\x10\x9aL\vN\xd8d\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4v-o0\u06b9\x915\xe4\xec\xa5\x1dRC\xd6\xc8b\x11\x02\u0549\x0fI\x89A\xe6d(\x00\x00\u07d4v3\x1e0yl\xe6d\xb2p\x0e\rASp\x0e\u0706\x97w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v8\x86\xe33\xc5o\xef\xf8[\xe3\x95\x1a\xb0\xb8\x89\xce&.\x95\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v:|\xba\xb7\rzd\u0427\xe5)\x80\xf6\x81G%\x93I\f\x89 \x86\xac5\x10R`\x00\x00\u07d4v>\xec\u0c0a\u021e2\xbf\xa4\xbe\xcev\x95\x14\xd8\xcb[\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4v@\xa3\u007f\x80R\x98\x15\x15\xbc\xe0x\u0693\xaf\xa4x\x9bW4\x89lk\x93[\x8b\xbd@\x00\x00\u0794vA\xf7\xd2j\x86\xcd\xdb+\xe10\x81\x81\x0e\x01\xc9\xc8E\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94vO\xc4mB\x8bm\xbc\"\x8a\x0f_U\xc9P\x8cw.\xab\x9f\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4vPn\xb4\xa7\x80\xc9Q\xc7J\x06\xb0=;\x83b\xf0\x99\x9dq\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94v[\xe2\xe1/b\x9ecI\xb9}!\xb6*\x17\xb7\xc80\xed\xab\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94vb\x81P\xe2\x99[['\x9f\xc8>\r\xd5\xf1\x02\xa6q\xdd\x1c\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4vk7Y\xe8yN\x92m\xacG=\x91:\x8f\xb6\x1a\xd0\xc2\u0249\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4vp\xb0/,<\xf8\xfdOG0\xf38\x1aq\xeaC\x1c3\u01c9\x0e~\xeb\xa3A\vt\x00\x00\u07d4vz\x03eZ\xf3`\x84\x1e\x81\r\x83\xf5\xe6\x1f\xb4\x0fL\xd1\x13\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4vz\u0190y\x1c.#E\x10\x89\xfelp\x83\xfeU\u07b6+\x89,s\xc97t,P\x00\x00\u07d4v\u007f\xd7y}Qi\xa0_sd2\x1c\x19\x84:\x8c4\x8e\x1e\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u0794v\x84o\r\xe0;Zv\x97\x1e\xad)\x8c\xdd\b\x84:K\xc6\u0188\xd7\x1b\x0f\u088e\x00\x00\xe0\x94v\x84\x98\x93N7\xe9\x05\xf1\xd0\xe7{D\xb5t\xbc\xf3\xecJ\xe8\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4v\x8c\xe0\u06a0)\xb7\xde\xd0\"\xe5\xfcWM\x11\xcd\xe3\xec\xb5\x17\x89\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\xe0\x94v\x93\xbd\xebo\xc8+[\xcar\x13U\"1u\xd4z\bKM\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4v\xaa\xf8\xc1\xac\x01/\x87R\xd4\xc0\x9b\xb4f\a\xb6e\x1d\\\xa8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4v\xab\x87\xddZ\x05\xad\x83\x9aN/\xc8\xc8Z\xa6\xba\x05d\x170\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v\xaf\xc2%\xf4\xfa0}\xe4\x84U+\xbe\x1d\x9d?\x15\aLJ\x89\xa2\x90\xb5\u01ed9h\x00\x00\xe0\x94v\xbe\xca\xe4\xa3\x1d6\xf3\xcbW\u007f*CYO\xb1\xab\xc1\xbb\x96\x8a\x05C\xa9\xce\x0e\x132\xf0\x00\x00\u07d4v\xc2u5\xbc\xb5\x9c\xe1\xfa-\x8c\x91\x9c\xab\xebJk\xba\x01\u0449lk\x93[\x8b\xbd@\x00\x00\u07d4v\xca\"\xbc\xb8y\x9eS'\u012a*}\tI\xa1\xfc\xce_)\x89R\xa0?\"\x8cZ\xe2\x00\x00\u07d4v\xca\u0108\x11\x1aO\u0555\xf5h\xae:\x85\x87p\xfc\x91]_\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94v\u02dc\x8bi\xf48vu\u0102S\xe24\xcb~\rt\xa4&\x8a\x01\x90\xf4H.\xb9\x1d\xae\x00\x00\u07d4v\xf8:\xc3\xda0\xf7\t&(\xc73\x9f \x8b\xfc\x14,\xb1\ue25a\x18\xff\xe7B}d\x00\x00\xe0\x94v\xf9\xad=\x9b\xbd\x04\xae\x05\\\x14w\xc0\xc3^u\x92\xcb* \x8a\b\x83?\x11\xe3E\x8f \x00\x00\u07d4v\xff\xc1W\xadk\xf8\xd5m\x9a\x1a\u007f\u077c\x0f\xea\x01\n\xab\xf4\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\x02\x8e@\x9c\xc4:;\xd3=!\xa9\xfcS\xec`n\x94\x91\x0e\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4w\f/\xb2\u0128\x17S\xac\x01\x82\xeaF\x0e\xc0\x9c\x90\xa5\x16\xf8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4w\r\x98\xd3\x1bCS\xfc\xee\xe8V\fL\u03c0>\x88\xc0\xc4\xe0\x89 \x86\xac5\x10R`\x00\x00\xe0\x94w\x13\xab\x807A\x1c\t\xbah\u007fo\x93d\xf0\xd3#\x9f\xac(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4w\x15\a\xae\xeej%]\xc2\u035d\xf5QT\x06-\b\x97\xb2\x97\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4w\x19\x88\x87\x95\xadtY$\xc7W`\u0771\x82}\xff\xd8\u0368\x89lkLM\xa6\u077e\x00\x00\u07d4w'\xaf\x10\x1f\n\xab\xa4\xd2:\x1c\xaf\xe1|n\xb5\u06b1\xc6\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4w,)\u007f\n\u0454H.\xe8\xc3\xf06\xbd\xeb\x01\xc2\x01\xd5\u0309\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94w0o\xfe.J\x8f<\xa8&\xc1\xa2I\xf7!-\xa4:\xef\xfd\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4w1A\x12}\x8c\xf3\x18\xae\xbf\x886Z\xdd=U'\xd8[j\x8966\u05ef^\u024e\x00\x00\u07d4wF\xb6\xc6i\x9c\x8f4\xca'h\xa8 \xf1\xff\xa4\xc2\a\xfe\x05\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4wQ\xf3c\xa0\xa7\xfd\x053\x19\b\t\u076f\x93@\xd8\xd1\x12\x91\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4wW\xa4\xb9\xcc=\x02G\u032a\xeb\x99\t\xa0\xe5n\x1d\xd6\xdc\u0089\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4w\\\x10\xc9>\r\xb7 [&CE\x823\xc6O\xc3?\xd7[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4wa~\xbcK\xeb\xc5\xf5\xdd\xeb\x1bzp\xcd\xebj\xe2\xff\xa0$\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4wiC\xff\xb2\xef\\\xdd5\xb8<(\xbc\x04k\xd4\xf4gp\x98\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94wp\x1e,I=\xa4|\x1bX\xf4!\xb5I]\xeeE\xbe\xa3\x9b\x8a\x01H\xf6I\xcfaB\xa5\x80\x00\u07d4wy\x8f \x12W\xb9\xc3R\x04\x95pW\xb5Ft\xae\xfaQ\u07c9\b\x13\xcaV\x90m4\x00\x00\u07d4w\x8cC\xd1\x1a\xfe;Xo\xf3t\x19-\x96\xa7\xf2=+\x9b\u007f\x89\x8b\xb4\xfc\xfa;}k\x80\x00\u07d4w\x8cy\xf4\xde\x19S\xeb\u0398\xfe\x80\x06\xd5:\x81\xfbQ@\x12\x8963\x03\"\xd5#\x8c\x00\x00\u07d4w\x92t\xbf\x18\x03\xa36\xe4\u04f0\r\u0753\xf2\xd4\xf5\xf4\xa6.\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\xa1q\"\xfa1\xb9\x8f\x17\x11\xd3*\x99\xf0>\xc3&\xf3=\b\x89\\(=A\x03\x94\x10\x00\x00\u07d4w\xa3I\a\xf3\x05\xa5L\x85\xdb\t\xc3c\xfd\xe3\xc4~j\xe2\x1f\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4w\xa7i\xfa\xfd\xec\xf4\xa68v-[\xa3\x96\x9d\xf61 \xa4\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4w\xbekd\xd7\xc73\xa46\xad\xec^\x14\xbf\x9a\xd7@+\x1bF\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\xbf\xe9<\u0367P\x84~A\xa1\xaf\xfe\xe6\xb2\u0696\xe7!N\x89\x10CV\x1a\x88)0\x00\x00\u07d4w\u0126\x97\xe6\x03\xd4+\x12\x05l\xbb\xa7a\xe7\xf5\x1d\x04C\xf5\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4w\xcc\x02\xf6#\xa9\u03d8S\t\x97\xeag\xd9\\;I\x18Y\xae\x89Is\x03\xc3n\xa0\xc2\x00\x00\u07d4w\xd4?\xa7\xb4\x81\xdb\xf3\xdbS\f\xfb\xf5\xfd\xce\xd0\xe6W\x181\x89lk\x93[\x8b\xbd@\x00\x00\u07d4w\xda^lr\xfb6\xbc\xe1\xd9y\x8f{\xcd\xf1\u044fE\x9c.\x89\x016\x95\xbbl\xf9>\x00\x00\u07d4w\xf4\xe3\xbd\xf0V\x88<\xc8r\x80\xdb\xe6@\xa1\x8a\r\x02\xa2\a\x89\n\x81\x99:+\xfb[\x00\x00\u0794w\xf6\t\u0287 \xa0#&,U\xc4o-&\xfb90\xaci\x88\xf0\x15\xf2W6B\x00\x00\u07d4w\xf8\x1b\x1b&\xfc\x84\xd6\u0797\uf2df\xbdr\xa310\xccJ\x8965\u026d\xc5\u07a0\x00\x00\u07d4x\x19\xb0E\x8e1N+S\xbf\xe0\f8I_\u0539\xfd\xf8\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4x\x1b\x15\x01dz.\x06\xc0\xedC\xff\x19\u007f\xcc\xec5\xe1p\v\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4x/R\xf0\xa6v\xc7w\x16\xd5t\xc8\x1e\xc4hO\x9a\x02\n\x97\x89.\x14\xe2\x06\xb70\xad\x80\x00\u07d4x5]\xf0\xa20\xf8=\x03,p1TAM\xe3\xee\u06b5W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4x6\xf7\xefk\u01fd\x0f\xf3\xac\xafD\x9c\x84\xddk\x1e,\x93\x9f\x89\xe0\x8d\xe7\xa9,\xd9|\x00\x00\u07d4x7\xfc\xb8v\xda\x00\xd1\xeb;\x88\xfe\xb3\xdf?\xa4\x04/\xac\x82\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4x>\uc2a5\xda\xc7{.f#\xedQ\x98\xa41\xab\xba\xee\a\x89\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4x\\\x8e\xa7t\xd70D\xa74\xfay\n\x1b\x1et>w\xed|\x89\f\xf1Rd\f\\\x83\x00\x00\u07d4x`\xa3\xde8\xdf8*\xe4\xa4\xdc\xe1\x8c\f\a\xb9\x8b\xce=\xfa\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94xcCq\xe1s\x04\xcb\xf39\xb1E*L\xe48\xdcvL\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4xd\u0719\x9f\xe4\xf8\xe0\x03\xc0\xf4=\xec\u00da\xae\x15\"\xdc\x0f\x89\x05\x1e\x10+\xd8\xec\xe0\x00\x00\u07d4xtj\x95\x8d\xce\xd4\xc7d\xf8vP\x8cAJh4,\uce49\x02\xbe7O\xe8\xe2\xc4\x00\x00\xe0\x94x}1?\xd3k\x05>\xee\xae\xdb\xcet\xb9\xfb\x06x32\x89\x8a\x05\xc0X\xb7\x84'\x19`\x00\x00\u07d4x\x85\x9c[T\x8bp\r\x92\x84\xce\xe4\xb6c=GJ\x8a\x04{\x92\xc4\x15B$-\n\b\xc7\x0f\x99\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4x\u03c36\xb3(\xdb=\x87\x81:G+\x9e\x89\xb7^\f\xf3\xbc\x8965\u026d\xc5\u07a0\x00\x00\u07d4x\xd4\xf8\xc7\x1c\x1eh\xa6\x9a\x98\xf5/\xcbE\u068a\xf5n\xa1\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4x\xdf&\x81\xd6\xd6\x02\xe2!B\xd5A\x16\u07a1]EIW\xaa\x89\x10'\x94\xad \xdah\x00\x00\u07d4x\xe0\x8b\xc53A<&\u2473\x14?\xfa|\u026f\xb9{x\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4x\xe8?\x80\xb3g\x8cz\nN>\x8c\x84\xdc\xcd\xe0dBbw\x89a\t=|,m8\x00\x00\u07d4x\xf5\xc7G\x85\xc5f\x8a\x83\x80r\x04\x8b\xf8\xb4SYM\u06ab\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4y\x0f\x91\xbd]\x1c\\\xc4s\x9a\xe9\x13\x00\u06c9\xe1\xc10<\x93\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\x17\u5f42\xa9y\x0f\xd6P\xd0C\xcd\xd90\xf7y\x963\u06c9\xd8\xd4`,&\xbfl\x00\x00\u07d4y\x19\xe7b\u007f\x9b}T\xea;\x14\xbbM\xd4d\x9fO9\xde\xe0\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4y\x1f`@\xb4\xe3\xe5\r\xcf5S\xf1\x82\u0357\xa9\x060\xb7]\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4y0\xc2\xd9\xcb\xfa\x87\xf5\x10\xf8\xf9\x87w\xff\x8a\x84H\xcaV)\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4yE)\u041d\x01rq5\x970\x02pu\xb8z\xd8=\xaen\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4yKQ\u00deS\xd9\xe7b\xb0a;\x82\x9aD\xb4r\xf4\xff\xf3\x89$5\xe0dxA\u0300\x00\xe0\x94yU\x1c\xed\xe3v\xf7G\xe3ql\x8dy@\rvm.\x01\x95\x8a\t\xcb7\xaf\xa4\xffxh\x00\x00\u07d4y^\xbc&&\xfc9\xb0\xc8b\x94\xe0\xe87\xdc\xf5#U0\x90\x8965\u026d\xc5\u07a0\x00\x00\u07d4yn\xbb\xf4\x9b>6\xd6v\x94\xady\xf8\xff6vz\xc6\xfa\xb0\x89\x03K\xc4\xfd\xde'\xc0\x00\x00\u07d4yo\x87\xbaaz)0\xb1g\v\xe9.\xd1(\x1f\xb0\xb3F\xe1\x89\x06\xf5\xe8o\xb5((\x00\x00\u07d4yt'\xe3\xdb\xf0\xfe\xaez%\x06\xf1-\xf1\xdc@2n\x85\x05\x8965\u026d\xc5\u07a0\x00\x00\u07d4yu\x10\xe3\x86\xf5c\x93\xce\xd8\xf4w7\x8aDLHO}\xad\x8965\u026d\xc5\u07a0\x00\x00\u07d4y{\xb7\xf1W\xd9\xfe\xaa\x17\xf7m\xa4\xf7\x04\xb7M\xc1\x03\x83A\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4y\x88\x90\x131\xe3\x87\xf7\x13\xfa\u03b9\x00\\\xb9\xb6Q6\xeb\x14\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4y\x89\u041f8&\xc3\u5bccu*\x81\x15r:\x84\xd8\tp\x89\x16\x86\xf8aL\xf0\xad\x00\x00\xe0\x94y\x95\xbd\x8c\xe2\xe0\xc6{\xf1\u01e51\xd4w\xbc\xa1\xb2\xb9ua\x8a\x01BH\xd6\x17\x82\x9e\xce\x00\x00\u07d4y\xae\xb3Ef\xb9t\xc3ZX\x81\xde\xc0 \x92}\xa7\xdf]%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\xb1 \xeb\x88\x06s#!(\x8fgZ'\xa9\"_\x1c\xd2\ub245\xa0\xbf7\xde\xc9\xe4\x00\x00\u07d4y\xb4\x8d-a7\u00c5Ma\x1c\x01\xeaBBz\x0fY{\xb7\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4y\xb8\xaa\xd8y\xdd0V~\x87x\xd2\xd21\xc8\xf3z\xb8sN\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\xbf/{n2\x8a\xaf&\xe0\xbb\t?\xa2-\xa2\x9e\xf2\xf4q\x89a\t=|,m8\x00\x00\u07d4y\xc10\xc7b\xb8v[\x19\u04ab\u0260\x83\xab\x8f:\xady@\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4y\xc1\xbe\x19q\x1fs\xbe\xe4\xe61j\xe7T\x94Y\xaa\u03a2\xe0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4y\xc6\x00/\x84R\xca\x15\u007f\x13\x17\xe8\n/\xaf$GUY\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4y\xca\xc6IO\x11\xef'\x98t\x8c\xb52\x85\xbd\x8e\"\xf9|\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4y\u03e9x\n\xe6\xd8{,1\x88?\t'i\x86\u021ag5\x8965\u026d\xc5\u07a0\x00\x00\u07d4y\u06e2VG-\xb4\xe0X\xf2\xe4\xcd\xc3\xeaN\x8aBw83\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4y\xed\x10\xcf\x1fm\xb4\x82\x06\xb5\t\x19\xb9\xb6\x97\b\x1f\xbd\xaa\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u0794y\xf0\x8e\x01\xce\t\x88\xe6<\u007f\x8f)\b\xfa\xdeC\xc7\xf9\xf5\u0248\xfc\x93c\x92\x80\x1c\x00\x00\u07d4y\xfdmH1Pf\xc2\x04\xf9e\x18i\xc1\tl\x14\xfc\x97\x81\x89lk\x93[\x8b\xbd@\x00\x00\u0794y\xff\xb4\xac\x13\x81*\vx\u0123{\x82u\">\x17k\xfd\xa5\x88\xf0\x15\xf2W6B\x00\x00\u07d4z\x05\x89\xb1C\xa8\xe5\xe1\a\u026cf\xa9\xf9\xf8Yz\xb3\u7ac9Q\xe92\xd7n\x8f{\x00\x00\u07d4z\nx\xa9\xcc9?\x91\xc3\xd9\xe3\x9ak\x8c\x06\x9f\a^k\xf5\x89Hz\x9a0E9D\x00\x00\u07d4z\x13p\xa7B\xec&\x87\xe7a\xa1\x9a\u0167\x942\x9e\xe6t\x04\x89\xa2\xa12ga\xe2\x92\x00\x00\xe0\x94z-\xfcw\x0e$6\x811\xb7\x84w\x95\xf2\x03\xf3\xd5\r[V\x8a\x02i\xfe\xc7\xf06\x1d \x00\x00\u07d4z3\x83N\x85\x83s>-R\xae\xadX\x9b\u046f\xfb\x1d\xd2V\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94z6\xab\xa5\xc3\x1e\xa0\xca~'{\xaa2\xecF\u0393\xcfu\x06\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94z8\x11\"\xba\xday\x1az\xb1\xf6\x03}\xac\x80C'S\xba\xad\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94zH\xd8w\xb6:\x8f\x8f\x93\x83\xe9\xd0\x1eS\xe8\fR\x8e\x95_\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4zO\x9b\x85\x06\x90\xc7\xc9F\x00\xdb\xee\f\xa4\xb0\xa4\x11\xe9\xc2!\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4zc\x86\x9f\xc7g\xa4\u01b1\xcd\x0e\x06I\xf3cL\xb1!\xd2K\x89\x043\x87Oc,\xc6\x00\x00\u07d4zg\xdd\x04:PO\xc2\xf2\xfcq\x94\xe9\xbe\xcfHL\xec\xb1\xfb\x89\r\x8drkqw\xa8\x00\x00\xe0\x94zk&\xf48\u0663RD\x91U\xb8\x87l\xbd\x17\xc9\u065bd\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4zmx\x1cw\u013a\x1f\xca\xdfhsA\xc1\xe3\x17\x99\xe9='\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4zph\xe1\xc37\\\x0eY\x9d\xb1\xfb\xe6\xb2\xea#\xb8\xf4\a\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4zt\xce\xe4\xfa\x0fcp\xa7\x89O\x11l\xd0\f\x11G\xb8>Y\x89+^:\xf1k\x18\x80\x00\x00\u07d4zy\xe3\x0f\xf0W\xf7\n=\x01\x91\xf7\xf5?v\x157\xaf}\xff\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94zzO\x80sW\xa4\xbb\xe6\x8e\x1a\xa8\x0692\x10\xc4\x11\u0333\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4z\x85c\x86y\x01 o?+\xf0\xfa>\x1c\x81\t\u02bc\u0345\x89\amA\xc6$\x94\x84\x00\x00\xe0\x94z\x87\x97i\n\xb7{Tp\xbf|\f\x1b\xbaa%\b\xe1\xac}\x8a\x01\xe0\x92\x96\xc37\x8d\xe4\x00\x00\u07d4z\x8c\x89\xc0\x14P\x9dV\u05f6\x810f\x8f\xf6\xa3\xec\xecsp\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94z\x94\xb1\x99\x92\u03b8\xcec\xbc\x92\xeeKZ\xde\xd1\fM\x97%\x8a\x03\x8d\x1a\x80d\xbbd\xc8\x00\x00\u07d4z\xa7\x9a\xc0C\x16\u030d\b\xf2\x00e\xba\xa6\xd4\x14(\x97\xd5N\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4z\xadM\xbc\u04ec\xf9\x97\u07d3XiV\xf7+d\u062d\x94\xee\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94z\xb2V\xb2\x04\x80\n\xf2\x017\xfa\xbc\xc9\x16\xa22Xu%\x01\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4z\xbaV\xf6:H\xbc\b\x17\u05b9p9\x03\x9az\xd6/\xae.\x89 \x86\xac5\x10R`\x00\x00\xe0\x94z\xbb\x10\xf5\xbd\x9b\xc3;\x8e\xc1\xa8-d\xb5[k\x18wuA\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4z\u010d@\xc6d\u031am\x89\xf1\xc5\xf5\xc8\n\x1cp\xe7D\u6263\x10b\xbe\xee\xd7\x00\x00\x00\u07d4z\u014fo\xfcO\x81\a\xaen07\x8eN\x9f\x99\xc5\u007f\xbb$\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4z\xd3\xf3\aao\x19\u0731C\xe6DM\xab\x9c<3a\x1fR\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4z\xd8,\xae\xa1\xa8\xb4\xed\x051\x9b\x9c\x98p\x17<\x81N\x06\xee\x89!d\xb7\xa0J\u0220\x00\x00\u07d4z\xde]f\xb9D\xbb\x86\f\x0e\xfd\xc8bv\u054fFS\xf7\x11\x89lk\x93[\x8b\xbd@\x00\x00\u07d4z\xdf\xed\xb0m\x91\xf3\xccs\x90E\v\x85U\x02p\x88<{\xb7\x89\x11x\xfa@Q]\xb4\x00\x00\u07d4z\xe1\xc1\x9eS\xc7\x1c\xeeLs\xfa\xe2\xd7\xfcs\xbf\x9a\xb5\u348965\u026d\xc5\u07a0\x00\x00\u07d4z\xe6Y\xeb;\xc4hR\xfa\x86\xfa\xc4\xe2\x1cv\x8dP8\x89E\x89\x0f\x81\f\x1c\xb5\x01\xb8\x00\x00\u07d4z\xea%\xd4+&\x12(n\x99\xc56\x97\u01bcA\x00\xe2\u06ff\x89lk\x93[\x8b\xbd@\x00\x00\u07d4z\xef{U\x1f\v\x9cF\xe7U\xc0\xf3\x8e[:s\xfe\x11\x99\xf5\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4{\v1\xffn$t^\xad\x8e\u067b\x85\xfc\v\xf2\xfe\x1dU\u0509+^:\xf1k\x18\x80\x00\x00\xe0\x94{\x0f\xea\x11v\xd5!Y3:\x14<)IC\xda6\xbb\u0774\x8a\x01\xfc}\xa6N\xa1L\x10\x00\x00\u07d4{\x11g<\xc0\x19bk)\f\xbd\xce&\x04o~m\x14\x1e!\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4{\x12!b\xc9\x13\xe7\x14l\xad\v~\xd3z\xff\xc9*\v\xf2\u007f\x89Q\xaf\tk#\x01\u0440\x00\u07d4{\x1b\xf5:\x9c\xbe\x83\xa7\u07a44W\x9f\xe7*\xac\x8d*\f\u0409\n\xd4\xc81j\v\f\x00\x00\u07d4{\x1d\xaf\x14\x89\x1b\x8a\x1e\x1b\xd4)\u0633k\x9aJ\xa1\u066f\xbf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4{\x1f\xe1\xabM\xfd\x00\x88\xcd\xd7\xf6\x01c\xefY\xec*\xee\x06\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4{%\xbb\x9c\xa8\xe7\x02!~\x933\"RP\xe5<6\x80MH\x89e\xea=\xb7UF`\x00\x00\u07d4{'\xd0\xd1\xf3\xdd<\x14\x02\x94\xd0H\x8bx>\xbf@\x15'}\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94{@\a\xc4^ZW?\u06f6\xf8\xbdtk\xf9J\xd0J<&\x8a\x038!\xf5\x13]%\x9a\x00\x00\u07d4{C\xc7\xee\xa8\xd6#U\xb0\xa8\xa8\x1d\xa0\x81\xc6Dk3\xe9\xe0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4{M*8&\x90i\xc1\x85Ww\rY\x1d$\xc5\x12\x1f^\x83\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94{au\xec\x9b\xef\xc78$\x955\xdd\xde4h\x8c\xd3n\xdf%\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94{f\x12hy\x84M\xfa4\xfee\xc9\xf2\x88\x11\u007f\xef\xb4I\xad\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4{j\x84q\x8d\xd8nc3\x84)\xac\x81\x1d|\x8a\x86\x0f!\xf1\x89a\t=|,m8\x00\x00\xe0\x94{q,z\xf1\x16v\x00jf\xd2\xfc\\\x1a\xb4\xc4y\xce`7\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4{s$-u\u029a\xd5X\xd6P)\r\xf1v\x92\xd5L\u0638\x89lnY\xe6|xT\x00\x00\u07d4{v\x1f\xeb\u007f\u03e7\xde\xd1\xf0\xeb\x05\x8fJ`\v\xf3\xa7\b\u02c9\xf9]\xd2\xec'\xcc\xe0\x00\x00\xe0\x94{\x82|\xae\u007f\xf4t\t\x18\xf2\xe00\xab&\u02d8\xc4\xf4l\xf5\x8a\x01\x94hL\v9\xde\x10\x00\x00\xe0\x94{\x892\x86B~r\xdb!\x9a!\xfcM\xcd_\xbfY(<1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4{\x92&\xd4o\xe7Q\x94\v\xc4\x16\xa7\x98\xb6\x9c\xcf\r\xfa\xb6g\x89\u3bb5sr@\xa0\x00\x00\u07d4{\x98\xe2<\xb9k\xee\xe8\n\x16\x80i\ube8f \xed\xd5\\\u03c9\v\xa0\xc9\x15\x87\xc1J\x00\x00\u07d4{\xb0\xfd\xf5\xa6c\xb5\xfb\xa2\x8d\x9c\x90*\xf0\xc8\x11\xe2R\xf2\x98\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4{\xb9W\x1f9K\v\x1a\x8e\xbaVd\xe9\u0635\xe8@g{\xea\x89\x01\x11du\x9f\xfb2\x00\x00\xe0\x94{\xb9\x84\xc6\u06f9\xe2y\x96j\xfa\xfd\xa5\x9c\x01\xd0&'\xc8\x04\x8a\x01\xb4d1\x1dE\xa6\x88\x00\x00\u07d4{\xbb\xec^p\xbd\xea\u063b2\xb4(\x05\x98\x8e\x96H\xc0\xaa\x97\x8966\u05ef^\u024e\x00\x00\u07d4{\xca\x1d\xa6\xc8\nf\xba\xa5\xdbZ\u0245A\u013e'kD}\x89$\xcf\x04\x96\x80\xfa<\x00\x00\u07d4{\u0772\xee\x98\xde\x19\xeeL\x91\xf6a\xee\x8eg\xa9\x1d\x05K\x97\x8965\u026d\xc5\u07a0\x00\x00\u0794{\xe2\xf7h\f\x80-\xa6\x15L\x92\xc0\x19J\xe72Qzqi\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4{\xe7\xf2Eiq\x88;\x9a\x8d\xbeL\x91\xde\xc0\x8a\xc3N\x88b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4{\xe8\u0334\xf1\x1bf\xcan\x1dW\xc0\xb59b!\xa3\x1b\xa5:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94{\xeb\x81\xfb/^\x91Rk*\xc9y^v\u019b\xcf\xf0K\xc0\x8a\x0e\xb2.yO\n\x8d`\x00\x00\u07d4|\b\x83\x05L-\x02\xbcz\x85+\x1f\x86\xc4'w\xd0\xd5\xc8V\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4|\x0f^\a C\xc9\xeet\x02B\x19~x\xccK\x98\xcd\xf9`\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|\x1d\xf2JO\u007f\xb2\u01f4r\xe0\xbb\x00l\xb2}\xcd\x16AV\x8965\u026d\xc5\u07a0\x00\x00\u07d4|)\xd4}W\xa73\xf5k\x9b!pc\xb5\x13\xdc;1Y#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4|+\x96\x03\x88JO.FN\u03b9}\x17\x93\x8d\x82\x8b\xc0,\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4|8,\x02\x96a.N\x97\xe4@\xe0-8q';U\xf5;\x89\n\xb6@9\x12\x010\x00\x00\u07d4|>\xb7\x13\xc4\xc9\xe08\x1c\xd8\x15L|\x9a}\xb8d\\\xde\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|D\x01\xae\x98\xf1.\xf6\xde9\xae$\u03df\xc5\x1f\x80\xeb\xa1k\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|E\xf0\xf8D*V\xdb\u04dd\xbf\x15\x99\x95A\\R\xedG\x9b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94|S-\xb9\xe0\xc0l&\xfd@\xac\xc5j\xc5\\\x1e\xe9-<:\x8a?\x87\bW\xa3\xe0\xe3\x80\x00\x00\u07d4|`\xa0_zJ_\x8c\xf2xC\x916.uZ\x83A\xefY\x89f\x94\xf0\x18*7\xae\x00\x00\u07d4|`\xe5\x1f\v\xe2(\xe4\xd5o\xdd)\x92\xc8\x14\xdaw@\u01bc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|i$\xd0|>\xf5\x89\x19f\xfe\nxV\xc8{\xef\x9d 4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94|\x8b\xb6Zo\xbbI\xbdA3\x96\xa9\xd7\xe3\x10S\xbb\xb3z\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94|\x9a\x11\f\xb1\x1f%\x98\xb2\xb2\x0e,\xa4\x002^A\xe9\xdb3\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4|\xbc\xa8\x8f\xcaj\x00`\xb9`\x98\\\x9a\xa1\xb0%4\xdc\"\b\x89\x19\x12z\x13\x91\xea*\x00\x00\u07d4|\xbe\xb9\x992\xe9~n\x02\x05\x8c\xfcb\u0432k\xc7\u0325+\x89lk\x93[\x8b\xbd@\x00\x00\u07d4|\xc2Jj\x95\x8c \xc7\xd1$\x96`\xf7Xb&\x95\v\r\x9a\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4|\xd2\x0e\u0335\x18\xb6\f\xab\t[r\x0fW\x15p\u02aaD~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4|\xd5\xd8\x1e\xab7\xe1\x1ebv\xa3\xa1\t\x12Q`~\r~8\x89\x03hM^\xf9\x81\xf4\x00\x00\u07d4|\xdft!9E\x95=\xb3\x9a\xd0\xe8\xa9x\x1a\xddy.M\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4|\xe4hdF\U000547be\xd6r\x15\xeb\rZ\x1d\xd7,\x11\xb8\x89x9\xd3!\xb8\x1a\xb8\x00\x00\u07d4|\xefMC\xaaA\u007f\x9e\xf8\xb7\x87\xf8\xb9\x9dS\xf1\xfe\xa1\ue209g\x8a\x93 b\xe4\x18\x00\x00\u07d4}\x03P\xe4\v3\x8d\xdasfa\x87+\xe3?\x1f\x97R\xd7U\x89\x02\xb4\xf5\xa6\U00051500\x00\xe0\x94}\x04\xd2\xed\xc0X\xa1\xaf\xc7a\xd9\u025a\xe4\xfc\\\x85\xd4\u0226\x8aB\xa9\xc4g\\\x94g\xd0\x00\x00\u07d4}\v%^\xfbW\xe1\x0fp\b\xaa\"\xd4\x0e\x97R\xdf\xcf\x03x\x89\x01\x9f\x8euY\x92L\x00\x00\xe0\x94}\x13\xd6pX\x84\xab!W\u074d\xccpF\xca\xf5\x8e\xe9K\xe4\x8a\x1d\r\xa0|\xbb>\xe9\xc0\x00\x00\u07d4}'>c~\xf1\xea\u0101\x11\x94\x13\xb9\x1c\x98\x9d\xc5\xea\xc1\"\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4}*R\xa7\xcf\f\x846\xa8\xe0\a\x97kl&\xb7\"\x9d\x1e\x15\x89\x17\xbf\x06\xb3*$\x1c\x00\x00\u07d4}4\x805i\xe0\v\u05b5\x9f\xff\b\x1d\xfa\\\n\xb4\x19zb\x89\\\xd8|\xb7\xb9\xfb\x86\x00\x00\u07d4}4\xffY\xae\x84\nt\x13\u01baL[\xb2\xba,u\xea\xb0\x18\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4}9(R\xf3\xab\xd9/\xf4\xbb[\xb2l\xb6\bt\xf2\xbeg\x95\x8966\xc2^f\xec\xe7\x00\x00\u07d4}DRg\u015a\xb8\u04a2\xd9\xe7\t\x99\x0e\th%\x80\u011f\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94}U\x13\x97\xf7\x9a)\x88\xb0d\xaf\xd0\xef\xeb\xee\x80,w!\xbc\x8a\bW\xe0\xd6\xf1\xdav\xa0\x00\x00\u07d4}Z\xa3?\xc1KQ\x84\x1a\x06\x90n\xdb+\xb4\x9c*\x11ri\x89\x10D\x00\xa2G\x0eh\x00\x00\xe0\x94}]/s\x94\x9d\xad\xda\bV\xb2\x06\x98\x9d\xf0\a\x8dQ\xa1\xe5\x8a\x02\xc4:H\x1d\xf0M\x01wb\xed\xcb\\\xaab\x9bZ\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4~\x8f\x96\xcc)\xf5{\tu\x12\f\xb5\x93\xb7\u0743=`kS\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4~\x97*\x8a|*D\xc9;!Cl8\xd2\x1b\x92R\xc3E\xfe\x89a\t=|,m8\x00\x00\u07d4~\x99\u07fe\x98\x9d;\xa5)\u0457Q\xb7\xf41\u007f\x89S\xa3\xe2\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4~\xa0\xf9n\xe0\xa5s\xa30\xb5h\x97v\x1f=L\x010\xa8\xe3\x89Hz\x9a0E9D\x00\x00\u0794~\xa7\x91\xeb\xab\x04E\xa0\x0e\xfd\xfcNJ\x8e\x9a~ue\x13m\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4~\xab\xa05\xe2\xaf7\x93\xfdtgK\x10%@\xcf\x19\n\u0779\x89E\x02l\x83[`D\x00\x00\xe0\x94~\xb4\xb0\x18\\\x92\xb6C\x9a\b\xe72!h\xcb5<\x8awJ\x8a\x02'\x19l\xa0I\x83\xca\x00\x00\xe0\x94~\xbd\x95\xe9\xc4p\xf7(5\x83\xdcn\x9d,M\xce\v\ua3c4\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4~\u0425\xa8G\xbe\xf9\xa9\xda|\xba\x1dd\x11\xf5\xc3\x161&\x19\x89\x02(\xeb7\xe8u\x1d\x00\x00\u07d4~\xda\xfb\xa8\x98K\xafc\x1a\x82\vk\x92\xbb\xc2\xc56U\xf6\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4~\xdb\x02\xc6\x1a\"r\x87a\x1a\xd9Pici\xccNdzh\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4~\xe5\u0280]\xce#\xaf\x89\xc2\xd4D\xe7\xe4\af\xc5Lt\x04\x89\r\v\xd4\x12\xed\xbd\x82\x00\x00\xe0\x94~\xe6\x04\u01e9\xdc)\t\xce2\x1d\u6e72OWgWuU\x8a\x01+\xf9\u01d8\\\xf6-\x80\x00\u07d4~\xf1o\xd8\xd1[7\x8a\x0f\xba0k\x8d\x03\u0758\xfc\x92a\x9f\x89%\xf2s\x93=\xb5p\x00\x00\u07d4~\xf9\x8bR\xbe\xe9S\xbe\xf9\x92\xf3\x05\xfd\xa0'\xf8\x91\x1cXQ\x89\x1b\xe7\" i\x96\xbc\x80\x00\u07d4~\xfc\x90vj\x00\xbcR7,\xac\x97\xfa\xbd\x8a<\x83\x1f\x8e\u0349\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4~\xfe\xc0\xc6%<\xaf9\u007fq(|\x1c\a\xf6\xc9X+[\x86\x89\x1a,\xbc\xb8O0\u0540\x00\u07d4\u007f\x01\xdc|7G\xca`\x8f\x98=\xfc\x8c\x9b9\xe7U\xa3\xb9\x14\x89\v8l\xad_zZ\x00\x00\u07d4\u007f\x06b\xb4\x10)\x8c\x99\xf3\x11\u04e1EJ\x1e\xed\xba/\xeav\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\u007f\x06\u021dY\x80\u007f\xa6\v\xc6\x016\xfc\xf8\x14\u02ef%C\xbd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u007f\v\x90\xa1\xfd\u050f'\xb2h\xfe\xb3\x83\x82\xe5]\xdbP\xef\x0f\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\u007f\x0e\xc3\u06c0F\x92\xd4\xd1\xea2E6Z\xab\x05\x90\a[\u0109\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u007f\x0f\x04\xfc\xf3zS\xa4\xe2N\xden\x93\x10Nx\xbe\x1d<\x9e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u007f\x13\xd7`I\x8dq\x93\xcahY\xbc\x95\xc9\x018d#\xd7l\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\u007f\x15\n\xfb\x1aw\u00b4Y(\xc2h\xc1\u9f74d\x1dG\u0609lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\x16\x19\x98\x8f7\x15\xe9O\xf1\xd2S&-\xc5X\x1d\xb3\xde\x1c\x890\xca\x02O\x98{\x90\x00\x00\u07d4\u007f\x1c\x81\xee\x16\x97\xfc\x14K|\v\xe5I;V\x15\xae\u007f\xdd\u0289\x1b\x1d\xaba\u04ead\x00\x00\u07d4\u007f#\x82\xff\xd8\xf89VFy7\xf9\xbar7F#\xf1\x1b8\x89 \x86\xac5\x10R`\x00\x00\u07d4\u007f7\t9\x1f?\xbe\xba5\x92\xd1u\xc7@\xe8z\tT\x1d\x02\x89\x1a\x05V\x90\xd9\u06c0\x00\x00\u07d4\u007f8\x9c\x12\xf3\xc6\x16OdFVlwf\x95\x03\xc2y%'\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\xe0\x94\u007f:\x1eE\xf6~\x92\u0200\xe5s\xb43y\xd7\x1e\xe0\x89\xdbT\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\u007f=r\x03\u0224G\xf7\xbf6\u060a\xe9\xb6\x06*^\xeex\xae\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\u007fF\xbb%F\r\xd7\xda\xe4!\x1c\xa7\xf1Z\xd3\x12\xfc}\xc7\\\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\u007fI\xe7\xa4&\x98\x82\xbd\x87\"\u0526\xf5f4v)b@y\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u007fI\xf2\a&G\x1a\xc1\u01e8>\xf1\x06\xe9w\\\xebf%f\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\u007fK^'\x85x\xc0F\xcc\xea\xf6W0\xa0\xe0h2\x9e\u0576\x89e\xea=\xb7UF`\x00\x00\u07d4\u007fOY;a\x8c3\v\xa2\xc3\xd5\xf4\x1e\xce\xeb\x92\xe2~Bl\x89\x96n\xdcuk|\xfc\x00\x00\u07d4\u007fT\x14\x91\u04ac\x00\xd2a/\x94\xaa\u007f\v\xcb\x01FQ\xfb\u0509\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\u007fZ\xe0Z\xe0\xf8\xcb\xe5\xdf\xe7!\xf0D\u05e7\xbe\xf4\xc2y\x97\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\u007f`:\xec\x17Y\xea_\a\xc7\xf8\xd4\x1a\x14(\xfb\xba\xf9\xe7b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u007falo\x00\x8a\u07e0\x82\xf3M\xa7\xd0e\x04`6\x80u\xfb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u007fa\xfal\xf5\xf8\x98\xb4@\xda\u016b\xd8`\rmi\x1f\xde\xf9\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94\u007fe\\g\x89\xed\xdfE\\\xb4\xb8\x80\x99r\x0698\x9e\ubb0a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u007fk(\u0204!\xe4\x85~E\x92\x81\u05c4ai$\x89\xd3\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007fn\xfboC\x18\x87m.\xe6$\xe2u\x95\xf4DF\xf6\x8e\x93\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u007fq\x92\xc0\xdf\x1c}\xb6\xd9\xede\xd7\x11\x84\xd8\xe4\x15Z\x17\xba\x89\x04Sr\x8d3\x94,\x00\x00\u07d4\u007fz:!\xb3\xf5\xa6]\x81\xe0\xfc\xb7\xd5-\xd0\n\x1a\xa3m\xba\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u007f\x8d\xbc\xe1\x80\xed\x9cV65\xaa\xd2\xd9{L\xbcB\x89\x06\u0649\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\u007f\x99=\xdb~\x02\u0082\xb8\x98\xf6\x15_h\x0e\xf5\xb9\xaf\xf9\a\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\u007f\x9f\x9bV\xe4(\x9d\xfbX\xe7\x0f\xd5\xf1*\x97\xb5m5\u01a5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u007f\xa3~\xd6x\x87u\x1aG\x1f\x0e\xb3\x06\xbeD\xe0\xdb\xcd`\x89\x899vt\u007f\xe1\x1a\x10\x00\x00\u07d4\u007f\xaa0\xc3\x15\x19\xb5\x84\xe9rP\xed*<\xf38^\xd5\xfdP\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xcf[\xa6fo\x96lTH\xc1{\xf1\xcb\v\xbc\xd8\x01\x9b\x06\x89\x05k\xc3\u042e\xbeI\x80\x00\xe0\x94\u007f\xd6y\xe5\xfb\r\xa2\xa5\xd1\x16\x19M\xcbP\x83\x18\xed\u0140\xf3\x8a\x01c\x9eI\xbb\xa1b\x80\x00\x00\u07d4\u007f\u06e01\u01cf\x9c\tmb\xd0Z6\x9e\uac3c\xccU\u5257\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\u007f\xdb\u00e8D\xe4\r\x96\xb2\xf3\xa652.`e\xf4\xca\x0e\x84\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xdf\u020dx\xbf\x1b(Z\xc6O\x1a\xdb5\xdc\x11\xfc\xb09Q\x89|\x06\xfd\xa0/\xb06\x00\x00\u07d4\u007f\xea\x19b\xe3]b\x05\x97h\xc7I\xbe\u0756\u02b90\xd3x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xef\x8c8w\x9f\xb3\a\xeco\x04K\xeb\xe4\u007f<\xfa\xe7\x96\xf1\x89\t#@\xf8l\xf0\x9e\x80\x00\u07d4\u007f\xf0\xc6?p$\x1b\xec\xe1\x9bs~SA\xb1+\x10\x901\u0609\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\u007f\xfa\xbf\xbc9\f\xbeC\u0389\x18\x8f\bh\xb2}\xcb\x0f\f\xad\x8a\x01YQ\x82\"K&H\x00\x00\xe0\x94\u007f\xfd\x02\xed7\fp`\xb2\xaeS\xc0x\xc8\x01!\x90\u07fbu\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794\x80\x02*\x12\a\xe9\x10\x91\x1f\xc9(I\xb0i\xab\f\xda\xd0C\u04c8\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x80\t\xa7\xcb\u0452\xb3\xae\u052d\xb9\x83\xd5(ER\xc1ltQ\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80\x0e}c\x1cnW:\x903/\x17\xf7\x1f_\u045bR\x8c\xb9\x89\b=lz\xabc`\x00\x00\u07d4\x80\x15m\x10\ufa320\u0254\x10c\r7\xe2i\xd4\t<\xea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\x172\xa4\x81\u00c0\xe5~\xd6-l)\u0799\x8a\xf3\xfa;\x13\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x1de\xc5\x18\xb1\x1d\x0e?OG\x02!Ap\x13\xc8\xe5>\u0149\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80&CZ\xacr\x8dI{\x19\xb3\xe7\xe5|(\xc5c\x95O+\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x80-\xc3\xc4\xff-}\x92^\u215fJ\x06\u05fa`\xf10\x8c\x89\x05P\x94\f\x8f\xd3L\x00\x00\u07d4\x800\xb1\x11\u0198?\x04\x85\u076c\xa7b$\xc6\x18\x064x\x9f\x89\x04V9\x18$O@\x00\x00\u07d4\x805\xbc\xff\xae\xfd\xee\xea5\x83\fI}\x14(\x9d6 #\u0789\x10CV\x1a\x88)0\x00\x00\u07d4\x805\xfeNkj\xf2z\u44a5xQ^\x9d9\xfao\xa6[\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80C\xed\"\xf9\x97\u58a4\xc1n6D\x86\xaed\x97V\x92\u0109=I\x04\xff\xc9\x11.\x80\x00\u07d4\x80C\xfd\u043cL\x97=\x16c\xd5_\xc15P\x8e\xc5\xd4\xf4\xfa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x80L\xa9IrcOc:Q\xf3V\v\x1d\x06\xc0\xb2\x93\xb3\xb1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x80R-\u07d4N\xc5.'\xd7$\xedL\x93\xe1\xf7\xbe`\x83\u0589\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x80Y\x1aB\x17\x9f4\xe6M\x9d\xf7]\xcdF;(hoUt\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x80\\\xe5\x12\x97\xa0y;\x81 g\xf0\x17\xb3\xe7\xb2\u07db\xb1\xf9\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x80]\x84o\xb0\xbc\x02\xa73r&\u0585\xbe\x9e\xe7s\xb9\x19\x8a\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x80c7\x9a{\xf2\u02d2:\x84\xc5\t>h\xda\xc7\xf7T\x81\u0149\x11v\x10.n2\xdf\x00\x00\u07d4\x80hTX\x8e\xcc\xe5AI_\x81\u008a)\x03s\xdf\x02t\xb2\x89\x1f\x8c\xdf\\n\x8dX\x00\x00\u07d4\x80oD\xbd\xebh\x807\x01^\x84\xff!\x80I\xe3\x823*3\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\x80tF\x18\xde9jT1\x97\xeeH\x94\xab\xd0c\x98\xdd|'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80w\xc3\xe4\xc4EXn\tL\xe1\x02\x93\u007f\xa0[s{V\x8c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x90\u007fY1H\xb5|F\xc1w\xe2=%\xab\u012a\xe1\x83a\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x97s\x16\x94NYB\xe7\x9b\x0e:\xba\u04cd\xa7F\be\x19\x89\x02\x1auJm\xc5(\x00\x00\xe0\x94\x80\xa0\xf6\xcc\x18l\xf6 \x14\x00sn\x06Z9\x1fR\xa9\xdfJ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x80\xab\xecZ\xa3n\\\x9d\t\x8f\x1b\x94(\x81\xbdZ\xca\u0196=\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xb2=8\v\x82\\F\xe098\x99\xa8UVF-\xa0\u1309lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xb4-\xe1p\xdb\xd7#\xf4T\xe8\x8fw\x16E-\x92\x98P\x92\x89\x10F#\xc0v-\xd1\x00\x00\u07d4\x80\xb7\x9f3\x83\x90\u047a\x1b77\xa2\x9a\x02W\xe5\xd9\x1e\a1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x80\xbf\x99^\u063a\x92p\x1d\x10\xfe\u011f\x9e}\x01M\xbe\xe0&\x89\x1f\x047\xca\x1a~\x12\x80\x00\u07d4\x80\xc0N\xfd1\x0fD\x04\x83\xc7?tK[\x9edY\x9c\xe3\xec\x89A\rXj \xa4\xc0\x00\x00\u07d4\x80\u00e9\xf6\x95\xb1m\xb1Yr\x86\u0473\xa8\xb7il9\xfa'\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\xc5>\xe7\xe35\u007f\x94\xce\rxh\x00\x9c \x8bJ\x13\x01%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xcc!\xbd\x99\xf3\x90\x05\u014f\xe4\xa4H\x90\x92 !\x8ff\u02c966\xc9yd6t\x00\x00\u07d4\x80\xd5\xc4\fY\xc7\xf5N\xa3\xa5_\xcf\xd1uG\x1e\xa3P\x99\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x80\xda/\u0762\x9a\x9e'\xf9\xe1\x15\x97^i\xae\x9c\xfb\xf3\xf2~\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x80\xe7\xb3 R0\xa5f\xa1\xf0a\xd9\"\x81\x9b\xb4\xd4\u04a0\xe1\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x80\xea\x1a\xcc\x13n\xcaKh\xc8B\xa9Z\xdfk\u007f\xee~\xb8\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80\xf0z\xc0\x9e{,<\n=\x1e\x94\x13\xa5D\xc7:A\xbe\u02c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x81\r\xb2Vu\xf4^\xa4\xc7\xf3\x17\u007f7\xce)\xe2-g\x99\x9c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81\x13\x9b\xfd\u0326V\xc40 ?r\x95\x8cT;e\x80\xd4\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x81\x14a\xa2\xb0\u0290\xba\xda\xc0j\x9e\xa1nx{3\xb1\x96\u0309\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\x81\x16M\xeb\x10\x81J\xe0\x83\x91\xf3,\bf{bH\xc2}z\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\x81\x18i1\x18A7\xd1\x19*\u020c\xd3\xe1\xe5\xd0\xfd\xb8jt\x89\x9d5\x95\xab$8\xd0\x00\x00\u0794\x81*U\xc4<\xae\xdcYr\x187\x90\x00\xceQ\rT\x886\xfd\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x81.\xa7\xa3\xb2\xc8n\xed2\xffO,sQL\xc6;\xac\xfb\u038965\u026d\xc5\u07a0\x00\x00\u07d4\x814\xdd\x1c\x9d\xf0\xd6\u0225\x81$&\xbbU\xc7a\u0283\x1f\b\x89\x06\xa2\x16\v\xb5|\xcc\x00\x00\u07d4\x81A5\u068f\x98\x11\aW\x83\xbf\x1a\xb6pb\xaf\x8d>\x9f@\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x81I\x8c\xa0{\x0f/\x17\xe8\xbb\xc7\xe6\x1a\u007fJ\xe7\xbef\xb7\x8b\x89\x05\x81\xfb\xb5\xb3;\xb0\x00\x00\u07d4\x81Um\xb2sI\xab\x8b'\x00ID\xedP\xa4n\x94\x1a\x0f_\x89\u063beI\xb0+\xb8\x00\x00\u07d4\x81U\xfalQ\xeb1\xd8\bA-t\x8a\xa0\x86\x10P\x18\x12/\x89e\xea=\xb7UF`\x00\x00\xe0\x94\x81V6\v\xbd7\ta\xce\xcakf\x91\xd7P\x06\xad L\xf2\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x81a\xd9@\xc3v\x01\x00\xb9\b\x05)\xf8\xa6\x03%\x03\x0fn\u0709\x10CV\x1a\x88)0\x00\x00\xe0\x94\x81d\xe7\x83\x14\xae\x16\xb2\x89&\xccU=,\xcb\x16\xf3V'\r\x8a\x01\xca\x13N\x95\xfb2\xc8\x00\x00\u07d4\x81e\u02b0\xea\xfbZ2\x8f\xc4\x1a\xc6M\xaeq[.\xef,e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81h\xed\xce\u007f)a\xcf)[\x9f\xcdZE\xc0l\xde\xdan\xf5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81m\x97r\xcf\x119\x91\x16\xcc\x1er\xc2lgt\xc9\xed\xd79\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81s\xc85djg.\x01R\xbe\x10\xff\xe8Ab\xdd%nL\x89\x1a\xab\xdf!E\xb40\x00\x00\u07d4\x81t\x93\u035b\xc6#p*$\xa5o\x9f\x82\xe3\xfdH\xf3\xcd1\x89\x9eK#\xf1-L\xa0\x00\x00\u07d4\x81y\xc8\tp\x18,\u0177\xd8*M\xf0n\xa9M\xb6:%\xf3\x89'o%\x9d\xe6k\xf4\x00\x00\u07d4\x81z\xc3;\xd8\xf8GVsr\x95\x1fJ\x10\u05e9\x1c\xe3\xf40\x89\n\xd7\xc4\x06\xc6m\xc1\x80\x00\xe0\x94\x81\x8f\xfe'\x1f\u00d75e\xc3\x03\xf2\x13\xf6\xd2\u0689\x89~\xbd\x8a\x016\xe0SB\xfe\u1e40\x00\u07d4\x81\x97\x94\x81!s.c\xd9\xc1H\x19N\xca\xd4n0\xb7I\u0209\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x81\x9a\xf9\xa1\xc2s2\xb1\xc3i\xbb\xda\x1b=\xe1\xc6\xe93\xd6@\x89\x11\t\xe6T\xb9\x8fz\x00\x00\xe0\x94\x81\x9c\u06a506x\xef|\xecY\u050c\x82\x16:\xcc`\xb9R\x8a\x03\x13QT_y\x81l\x00\x00\u07d4\x81\x9e\xb4\x99\vZ\xbaUG\t=\xa1+k<\x10\x93\xdfmF\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81\xa8\x81\x96\xfa\xc5\xf2<>\x12\xa6\x9d\xecK\x88\x0e\xb7\xd9s\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x81\xbc\xcb\xff\x8fD4~\xb7\xfc\xa9['\xce|\x95$\x92\xaa\xad\x89\b@\xc1!e\xddx\x00\x00\u07d4\x81\xbdu\xab\xd8e\xe0\xc3\xf0J\vO\xdb\xcbt\xd3@\x82\xfb\xb7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x81\xc1\x8c*#\x8d\xdcL\xba#\n\a-\xd7\xdc\x10\x1eb\x02s\x89Hz\x9a0E9D\x00\x00\u07d4\x81\xc9\xe1\xae\xe2\xd36]S\xbc\xfd\u0356\xc7\xc58\xb0\xfd~\xec\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\x81\u03edv\t\x13\xd3\xc3\"\xfc\xc7{I\u00ae9\a\xe7On\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x81\xd6\x19\xffW&\xf2@_\x12\x90Lr\xeb\x1e$\xa0\xaa\xeeO\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x81\xef\u25aev\xc8`\xd1\xc5\xfb\xd3=G\xe8\u0399\x96\xd1W\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81\xf8\xde,(=_\u052f\xbd\xa8]\xed\xf9v\x0e\xab\xbb\xb5r\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x82\f\x19)\x11\x96P[e\x05\x9d\x99\x14\xb7\t\v\xe1\u06c7\u0789\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x82\x1c\xb5\xcd\x05\xc7\uf41f\xe1\xbe`s=\x89c\xd7`\xdcA\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x82\x1dy\x8a\xf1\x99\x89\u00ee[\x84\xa7\xa7(<\xd7\xfd\xa1\xfa\xbe\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x82\x1e\xb9\t\x94\xa2\xfb\xf9K\xdc23\x91\x02\x96\xf7o\x9b\xf6\xe7\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x82$\x9f\xe7\x0fa\u01b1o\x19\xa3$\x84\x0f\xdc\x02\x021\xbb\x02\x8a\x02\x036\xb0\x8a\x93c[\x00\x00\u07d4\x82(\xeb\xc0\x87H\x0f\xd6EG\xca(\x1f^\xac\xe3\x04\x14S\xb9\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\x82)\u03b9\xf0\xd7\b9I\x8dD\xe6\xab\xed\x93\xc5\xca\x05\x9f]\x8a\x1a\x1c\x1b<\x98\x9a \x10\x00\x00\u07d4\x82.\xdf\xf66V:a\x06\xe5.\x9a%\x98\xf7\xe6\xd0\xef'\x82\x89\x01\xf4\xf9i=B\u04c0\x00\u07d4\x822\x19\xa2Yv\xbb*\xa4\xaf\x8b\xadA\xac5&\xb4\x936\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x822\xd1\xf9t.\u07cd\xd9'\xda5;*\xe7\xb4\xcb\xceu\x92\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\x824\xf4c\u0444\x85P\x1f\x8f\x85\xac\xe4\x97,\x9bc-\xbc\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\x827htg7\xcem\xa3\x12\xd5>TSN\x10o\x96|\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82;\xa7dr8\xd1\x13\xbc\xe9\x96JC\u0420\x98\x11\x8b\xfeM\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x82@t1(\x06\xdaGHCBf\xee\x00!@\u305a\u0089Q\xb1\u04c3\x92a\xac\x00\x00\u07d4\x82C\x8f\u04b3*\x9b\xddgKI\xd8\xcc_\xa2\xef\xf9x\x18G\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82HW(\xd0\xe2\x81V7X\xc7Z\xb2~\xd9\u80a0\x00-\x89\a\xf8\b\xe9)\x1el\x00\x00\u07d4\x82K<\x19)]~\xf6\xfa\xa7\xf3t\xa4y\x84\x86\xa8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82Q5\x8c\xa4\xe0`\u0775Y\xcaX\xbc\v\u077e\xb4\a\x02\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82Q5\xb1\xa7\xfc\x16\x05aL\x8a\xa4\u042cm\xba\u040fH\x0e\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\x82S\t\xa7\xd4]\x18\x12\xf5\x1en\x8d\xf5\xa7\xb9ol\x90\x88\x87\x89\x804\xf7\u0671f\xd4\x00\x00\u07d4\x82Z\u007fN\x10\x94\x9c\xb6\xf8\x96Bh\xf1\xfa_W\xe7\x12\xb4\u0109\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82a\xfa#\f\x90\x1dC\xffW\x9fG\x80\u04d9\xf3\x1e`v\xbc\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82b\x16\x9baXp\x13N\xb4\xacl_G\x1ck\xf2\xf7\x89\xfc\x89\x19\x12z\x13\x91\xea*\x00\x00\u07d4\x82c\xec\xe5\xd7\t\xe0\u05eeq\u0328h\xed7\xcd/\xef\x80{\x895\xab\x02\x8a\xc1T\xb8\x00\x00\xe0\x94\x82l\xe5y\x052\xe0T\x8ca\x02\xa3\r>\xac\x83k\xd68\x8f\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4\x82n\xb7\xcds\x19\xb8-\xd0z\x1f;@\x90q\xd9n9g\u007f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x82u1\xa6\u0141z\xe3_\x82\xb0\v\x97T\xfc\xf7LU\xe22\x89\xc3(\t>a\xee@\x00\x00\u0794\x82u\xcdhL6y\u0548}\x03fN3\x83E\xdc<\xdd\xe1\x88\xdbD\xe0I\xbb,\x00\x00\u07d4\x82\x84\x92;b\u62ff|+\x9f4\x14\xd1>\xf6\xc8\x12\xa9\x04\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\x82\x8b\xa6Q\u02d3\x0e\xd9xqV)\x9a=\xe4L\u040br\x12\x89Hz\x9a0E9D\x00\x00\u07d4\x82\xa1\\\xef\x1dl\x82`\xea\xf1Y\xea?\x01\x80\xd8g}\xce\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82\xa8\xb9kl\x9e\x13\xeb\xec\x1e\x9f\x18\xac\x02\xa6\x0e\xa8\x8aH\xff\x89lk\x8c@\x8es\xb3\x00\x00\u07d4\x82\xa8\u02ff\xdf\xf0+.8\xaeK\xbf\xca\x15\xf1\xf0\xe8;\x1a\xea\x89\x04\x9b\x99\x1c'\xefm\x80\x00\u07d4\x82\xe4F\x1e\xb9\xd8I\xf0\x04\x1c\x14\x04!\x9eBr\u0110\n\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82\xe5w\xb5\x15\xcb+\b`\xaa\xfe\x1c\xe0\x9aY\xe0\x9f\xe7\xd0@\x89 \x86\xac5\x10R`\x00\x00\u07d4\x82\xea\x01\xe3\xbf.\x83\x83nqpN\"\xa2q\x93w\xef\xd9\u00c9\xa4\xccy\x95c\u00c0\x00\x00\u07d4\x82\xf2\xe9\x91\xfd2L_]\x17v\x8e\x9fa3]\xb61\x9dl\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x82\xf3\x9b'X\xaeB'{\x86\u059fu\xe6(\xd9X\xeb\u02b0\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94\x82\xf8T\xc9\xc2\xf0\x87\xdf\xfa\x98Z\xc8 \x1ebl\xa5Fv\x86\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x82\xffqo\xdf\x03>\xc7\xe9B\xc9\t\u0643\x18g\xb8\xb6\xe2\xef\x89a\t=|,m8\x00\x00\u07d4\x83\b\xed\n\xf7\xf8\xa3\xc1u\x1f\xaf\xc8w\xb5\xa4*\xf7\xd3X\x82\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x83\x1cD\xb3\b@G\x18K*\xd2\x18h\x06@\x907P\xc4]\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x83!\x05\x83\xc1jN\x1e\x1d\xac\x84\xeb\xd3~=\x0f|W\ub909lk\x93[\x8b\xbd@\x00\x00\u07d4\x83,T\x17k\xdfC\xd2\u027c\u05f8\b\xb8\x95V\xb8\x9c\xbf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x833\x16\x98]Gt+\xfe\xd4\x10`J\x91\x95<\x05\xfb\x12\xb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x834vK{9zNW\x8fP6M`\xceD\x89\x9b\xff\x94\x89\x05\x03\xb2\x03\xe9\xfb\xa2\x00\x00\xe0\x94\x83;j\x8e\xc8\xda@\x81\x86\xac\x8a}*m\xd6\x15#\xe7\u0384\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x83=?\xaeT*\xd5\xf8\xb5\f\xe1\x9b\xde+\xecW\x91\x80\u020c\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\x83=\xb4,\x14\x16<{\xe4\u02b8j\u0153\xe0bf\u0599\u054a$\xe4\r+iC\xef\x90\x00\x00\xe0\x94\x83V;\xc3d\ud060\xc6\xda;V\xffI\xbb\xf2g\x82z\x9c\x8a\x03\xab\x91\xd1{ \xdeP\x00\x00\u07d4\x83zd]\xc9\\IT\x9f\x89\x9cN\x8b\u03c7S$\xb2\xf5|\x89 \x8c9J\xf1\u0208\x00\x00\u07d4\x83\x8b\xd5e\xf9\x9f\xdeH\x05?y\x17\xfe3<\xf8J\xd5H\xab\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x83\x90\x8a\xa7G\x8am\x1c\x9b\x9b\x02\x81\x14\x8f\x8f\x9f$+\x9f\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\x83\x92\xe57vq5x\x01[\xffI@\xcfC\x84\x9d}\u02e1\x89\bM\xf05]V\x17\x00\x00\xe0\x94\x83\x97\xa1\xbcG\xac\xd6GA\x81Y\xb9\x9c\xeaW\xe1\xe6S-n\x8a\x01\xf1\x0f\xa8'\xb5P\xb4\x00\x00\u07d4\x83\x98\xe0~\xbc\xb4\xf7_\xf2\x11m\xe7|\x1c*\x99\xf3\x03\xa4\u03c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xa3\x14\x883\xd9dI\x84\xf7\xc4u\xa7\x85\a\x16\ufd00\xff\x89\xb8Pz\x82\a( \x00\x00\u07d4\x83\xa4\x02C\x8e\x05\x19w=TH2k\xfba\xf8\xb2\f\xf5-\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\x83\xa9;[\xa4\x1b\xf8\x87 \xe4\x15y\f\xdc\vg\xb4\xaf4\u0109\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x83\xc2=\x8aP!$\xee\x15\x0f\b\xd7\x1d\xc6rt\x10\xa0\xf9\x01\x8a\a3\x1f;\xfef\x1b\x18\x00\x00\u07d4\x83\u0217\xa8Ki^\xeb\xe4fy\xf7\xda\x19\xd7vb\x1c&\x94\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xd52\u04cdm\xee?`\xad\u018b\x93a3\u01e2\xa1\xb0\u0749\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xdb\xf8\xa1(S\xb4\n\xc6\x19\x96\xf8\xbf\x1d\xc8\xfd\xba\xdd\xd3)\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x83\xdb\xfd\x8e\xda\x01\xd0\u078e\x15\x8b\x16\u0413_\xc28\n]\u01c9 \x86\xac5\x10R`\x00\x00\u07d4\x83\xe4\x80U2|(\xb5\x93o\xd9\xf4D~s\xbd\xb2\xdd3v\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\x83\xfeZ\x1b2\x8b\xaeD\a\x11\xbe\xafj\xad`&\xed\xa6\xd2 \x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x84\x00\x8ar\xf8\x03o?\xeb\xa5B\xe3Px\xc0W\xf3*\x88%\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x84\x0e\xc8>\xa96!\xf04\xe7\xbb7b\xbb\x8e)\xde\xd4\xc4y\x89\x87\x86x2n\xac\x90\x00\x00\xe0\x94\x84\x11E\xb4H@\xc9F\xe2\x1d\xbc\x19\x02d\xb8\xe0\xd5\x02\x93i\x8a?\x87\bW\xa3\xe0\xe3\x80\x00\x00\u07d4\x84#!\a\x93+\x12\xe01\x86X5%\xce\x02:p>\xf8\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4\x84$O\xc9ZiW\xed|\x15\x04\xe4\x9f0\xb8\xc3^\xcaKy\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x841'}{\xdd\x10E}\xc0\x17@\x8c\x8d\xbb\xbdAJ\x8d\xf3\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4\x847Z\xfb\xf5\x9b:\x1da\xa1\xbe2\xd0u\xe0\xe1ZO\xbc\xa5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x84;\xd3P/E\xf8\xbcM\xa3p\xb3#\xbd\xac?\xcf_\x19\xa6\x89P\x03\x9dc\xd1\x1c\x90\x00\x00\u07d4\x84P34c\rw\xf7AG\xf6\x8b.\bf\x13\xc8\xf1\xad\xe9\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x84R\x03u\x0fqH\xa9\xaa&)!\xe8mC\xbfd\x19t\xfd\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x84a\xec\u0126\xa4^\xb1\xa5\xb9G\xfb\x86\xb8\x80i\xb9\x1f\xcdo\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84g^\x91wrmE\xea\xa4k9\x92\xa3@\xba\u007fq\f\x95\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x84hl{\xadv,T\xb6g\u055f\x90\x94<\xd1M\x11z&\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\x89\xf6\xad\x1d\x9a\x94\xa2\x97x\x91V\x89\x9d\xb6AT\xf1\u06f5\x89\x13t\a\xc0<\x8c&\x80\x00\u07d4\x84\x8c\x99Jy\x00?\xe7\xb7\xc2l\xc62\x12\xe1\xfc/\x9c\x19\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\x8f\xbd)\xd6|\xf4\xa0\x13\xcb\x02\xa4\xb1v\xef$N\x9e\u6349\x01\x17*ck\xbd\xc2\x00\x00\u07d4\x84\x94\x9d\xbaU\x9ac\xbf\xc8E\xde\xd0n\x9f-\x9b\u007f\x11\xef$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\x9a\xb8\a\x90\xb2\x8f\xf1\xff\u05ba9N\xfctc\x10\\6\xf7\x89\x01\xe0+\xe4\xael\x84\x00\x00\u07d4\x84\x9b\x11oYc\x01\xc5\u063bb\xe0\xe9z\x82H\x12n9\xf3\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x84\xa7L\xee\xcf\xf6\\\xb9;/\x94\x9dw>\xf1\xad\u007f\xb4\xa2E\x89\x05\n\x9bDF\x85\xc7\x00\x00\u07d4\x84\xaa\xc7\xfa\x19\u007f\xf8\\0\xe0;zS\x82\xb9W\xf4\x1f:\xfb\x89\b\x8b#\xac\xff\u0650\x00\x00\u07d4\x84\xaf\x1b\x15sB\xd5Ch&\r\x17\x87b0\xa54\xb5K\x0e\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x84\xb0\xeek\xb87\u04e4\xc4\xc5\x01\x1c:\"\x8c\x0e\u06b4cJ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\xb4\xb7Nf#\xba\x9d\x15\x83\xe0\u03feId?\x168AI\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\xb6\xb6\xad\xbe/[>-h,f\xaf\x1b\u0110S@\xc3\xed\x89!\x92\xf8\xd2\"\x15\x00\x80\x00\xe0\x94\x84\xb9\x1e.)\x02\xd0^+Y\x1bA\b;\u05fe\xb2\xd5,t\x8a\x02\x15\xe5\x12\x8bE\x04d\x80\x00\u07d4\x84\xbc\xbf\"\xc0\x96\a\xac\x844\x1d.\xdb\xc0;\xfb\x179\xd7D\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x84\xbf\xce\xf0I\x1a\n\xe0iK7\u03ac\x02E\x84\xf2\xaa\x04g\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x84\xcb}\xa0P-\xf4\\\xf5a\x81{\xbd#b\xf4Q\xbe\x02\u0689Hz\x9a0E9D\x00\x00\u07d4\x84\xccxx\xda`_\xdb\x01\x9f\xab\x9bL\xcf\xc1Wp\x9c\u0765\x89Hy\x85\x13\xaf\x04\xc9\x00\x00\u07d4\x84\xdb\x14Y\xbb\x00\x81.\xa6~\xcb=\xc1\x89\xb7!\x87\xd9\xc5\x01\x89\b\x11\xb8\xfb\u0685\xab\x80\x00\u07d4\x84\u9516\x80\xbe\xcehA\xb9\xa7\xe5%\r\b\xac\xd8}\x16\u0349\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x84\xe9\u03c1f\xc3j\xbf\xa4\x90S\xb7\xa1\xad@6 &\x81\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\xec\x06\xf2G\x00\xfeBAL\xb9\x89|\x15L\x88\xde/a2\x89Hz\x9a0E9D\x00\x00\xe0\x94\x84\xf5\"\xf0R\x0e\xbaR\xdd\x18\xad!\xfaK\x82\x9f+\x89\u02d7\x8a\x01\fQ\x06\xd5\x13O\x13\x00\x00\u07d4\x85\v\x9d\xb1\x8f\xf8K\xf0\xc7\xdaI\xea7\x81\xd9 \x90\xad~d\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\x85\x10\xee\x93O\f\xbc\x90\x0e\x10\a\xeb8\xa2\x1e*Q\x01\xb8\xb2\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4\x85\x16\xfc\xafw\u0213\x97\x0f\xcd\x1a\x95\x8b\xa9\xa0\x0eI\x04@\x19\x89\n\xa3\xeb\x16\x91\xbc\xe5\x80\x00\u07d4\x85\x1a\xa9\x1c\x82\xf4/\xad]\xd8\xe8\xbb^\xa6\x9c\x8f:Yw\u0449\b\x0eV\x1f%xy\x80\x00\u07d4\x85\x1c\rb\xbeF5\xd4w~\x805\xe3~K\xa8Q|a2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x85\x1d\u00ca\xdbE\x93r\x9av\xf3:\x86\x16\u06b6\xf5\xf5\x9aw\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x852I\b\x97\xbb\xb4\u038b\u007fk\x83~L\xba\x84\x8f\xbe\x99v\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x85>j\xba\xf4Di\xc7/\x15\x1dN\"8\x19\xac\xedN7(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x85F\x91\xceqO2\\\xedU\xceY(\u039b\xa1/\xac\u0478\x89\xedp\xb5\xe9\xc3\xf2\xf0\x00\x00\u07d4\x85L\fF\x9c$k\x83\xb5\u0473\xec\xa4C\xb3\x9a\xf5\xee\x12\x8a\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x85]\x9a\xef,9\xc6#\r\t\u025e\xf6II\x89\xab\u61c5\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\x85c\u0113a\xb6%\xe7hw\x1c\x96\x15\x1d\xbf\xbd\x1c\x90iv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x85fa\t\x01\xaa\xce8\xb82D\xf3\xa9\xc810jg\xb9\u0709\xb0\x82\x13\xbc\xf8\xff\xe0\x00\x00\xe0\x94\x85j\xa2<\x82\xd7![\xec\x8dW\xf6\n\xd7^\xf1O\xa3_D\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x85nZ\xb3\xf6L\x9a\xb5k\x00\x93\x93\xb0\x16d\xfc\x03$\x05\x0e\x89a\t=|,m8\x00\x00\u07d4\x85n\xb2\x04$\x1a\x87\x83\x0f\xb2)\x03\x13C\xdc0\x85OX\x1a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x85s,\x06\\\xbdd\x11\x99A\xae\xd40\xacYg\vlQ\u0109'\xa5sb\xab\n\x0e\x80\x00\xe0\x94\x85x\xe1\x02\x12\xca\x14\xff\a2\xa8$\x1e7F}\xb8V2\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x85y\xda\xdf\x1a9Z4q\xe2\vov=\x9a\x0f\xf1\x9a?o\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x85\u007f\x10\v\x1aY0\"^\xfc~\x90 \u05c3'\xb4\x1c\x02\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x85\x94mV\xa4\xd3q\xa93hS\x96\x90\xb6\x0e\xc8%\x10tT\x89]\u0212\xaa\x111\xc8\x00\x00\xe0\x94\x85\x99\xcb\u0566\xa9\xdc\u0539f\xbe8}iw]\xa5\xe3C'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86$_Yf\x91\t>\xce?=<\xa2&>\xac\xe8\x19A\u0649\n1\x06+\xee\xedp\x00\x00\u07d4\x86%i!\x1e\x8cc'\xb5A^:g\xe5s\x8b\x15\xba\xafn\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x86)}s\x0f\xe0\xf7\xa9\xee$\xe0\x8f\xb1\b{1\xad\xb3\x06\xa7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86D\xcc(\x1b\xe32\xcc\xce\xd3m\xa4\x83\xfb*\aF\u067a.\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x86I\x9a\x12(\xff-~\xe3\au\x93dPo\x8e\x8c\x83\a\xa5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x86K\xecPi\xf8U\xa4\xfdX\x92\xa6\xc4I\x1d\xb0|\x88\xff|\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86W\n\xb2Y\u0271\xc3,\x97) /w\xf5\x90\xc0}\xd6\x12\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86c\xa2A\xa0\xa8\x9ep\xe1\x82\xc8E\xe2\x10\\\x8a\xd7&K\u03ca\x03#\xb1=\x83\x98\xf3#\x80\x00\u07d4\x86g\xfa\x11U\xfe\xd72\u03f8\u0725\xa0\xd7e\xce\r\a\x05\xed\x89\x04n\xc9e\u00d3\xb1\x00\x00\u07d4\x86h\xaf\x86\x8a\x1e\x98\x88_\x93\u007f&\x15\xde\xd6u\x18\x04\xeb-\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x86t\nFd\x8e\x84Z]\x96F\x1b\x18\t\x1f\xf5{\xe8\xa1o\x8a\x14\xc0\x974\x85\xbf9@\x00\x00\xe0\x94\x86~\xbaVt\x8aY\x045\r,\xa2\xa5\u039c\xa0\vg\n\x9b\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x86\x80dt\xc3X\x04}\x94\x06\xe6\xa0\u007f@\x94[\xc82\x8eg\x8a\x01u.\xb0\xf7\x01=\x10\x00\x00\u07d4\x86\x88=T\xcd9\x15\xe5I\tU0\xf9\xab\x18\x05\xe8\xc5C-\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x86\x8c#\xbe\x874f\xd4\xc7L\"\n\x19\xb2E\xd1x~\x80\u007f\x89J\x13\xbb\xbd\x92\u020e\x80\x00\xe0\x94\x86\x92O\xb2\x11\xaa\xd2<\xf5\xce`\x0e\n\xae\x80c\x96D@\x87\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x86\x93\u9e3e\x94B^\xefyi\xbci\xf9\xd4/|\xadg\x1e\x8967\tlK\xcci\x00\x00\xe0\x94\x86\x9f\x1a\xa3\x0eDU\xbe\xb1\x82 \x91\xde\\\xad\xecy\xa8\xf9F\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x86\xa1\xea\xde\xeb0F\x13E\xd9\xefk\xd0R\x16\xfa$|\r\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86\xa5\xf8%\x9e\u0570\x9e\x18\x8c\xe3F\xee\x92\xd3J\xa5\u0753\xfa\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xb7\xbdV<\uad86\xf9bD\xf9\xdd\xc0*\u05f0\xb1K\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x86\u008bVx\xaf7\xd7'\xec\x05\xe4Dw\x90\xf1_q\xf2\xea\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xc4\xce\x06\u066c\x18[\xb1H\xd9o{z\xbes\xf4A\x00m\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x86\xc8\xd0\u0642\xb59\xf4\x8f\x980\xf9\x89\x1f\x9d`z\x94&Y\x8a\x02\xce\xd3wa\x82O\xb0\x00\x00\u07d4\x86\xc94\xe3\x8eS\xbe;3\xf2t\xd0S\x9c\xfc\xa1Y\xa4\xd0\u04494\x95tD\xb8@\xe8\x00\x00\xe0\x94\x86\xca\x01E\x95~k\r\xfe6\x87_\xbez\r\xecU\xe1z(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x86\u02af\xac\xf3*\xa01|\x03*\xc3k\xab\xed\x97G\x91\xdc\x03\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x86\u0377\xe5\x1a\xc4Gr\xbe6\x90\xf6\x1d\x0eYvn\x8b\xfc\x18\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x86\xdfs\xbd7\u007f,\t\xdec\xc4]g\xf2\x83\xea\xef\xa0\xf4\xab\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86\xe3\xfe\x86\xe9=\xa4\x86\xb1Bf\xea\xdf\x05l\xbf\xa4\xd9\x14C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86\xe8g\x0e'Y\x8e\xa0\x9c8\x99\xabw\x11\u04f9\xfe\x90\x1c\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xefd&!\x19I\xcc7\xf4\xc7^xP6\x9d\f\xf5\xf4y\x8a\x02\xd6_2\xea\x04Z\xf6\x00\x00\u07d4\x86\xf0]\x19\x06>\x93i\xc6\x00N\xb3\xf1#\x94:|\xffN\xab\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x86\xf2>\x9c\n\xaf\u01cb\x9c@M\xcd`3\x9a\x92[\xff\xa2f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x86\xf4\xf4\n\u0644\xfb\xb8\t3\xaebn\x0eB\xf93?\xddA\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x86\xf9\\[\x11\xa2\x93\x94\x0e5\xc0\xb8\x98\u0637_\b\xaa\xb0m\x8a\x06D\xe3\xe8u\xfc\xcft\x00\x00\u07d4\x86\xff\xf2 \xe5\x93\x05\xc0\x9fH8`\xd6\xf9N\x96\xfb\xe3/W\x89\x02S[j\xb4\xc0B\x00\x00\u07d4\x87\a\x96\xab\xc0\u06c4\xaf\x82\xdaR\xa0\xedhsM\xe7\xe66\xf5\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x87\x0f\x15\xe5\u07cb\x0e\xab\xd0%iSz\x8e\xf9;Vx\\B\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\x87\x181`\xd1r\xd2\xe0\x84\xd3'\xb8k\xcb|\x1d\x8eg\x84\xef\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94\x87\x1b\x8a\x8bQ\u07a1\x98\x9aY!\xf1>\xc1\xa9U\xa5\x15\xadG\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x87%\xe8\xc7S\xb3\xac\xbf\u0725_I\x13\\3\x91\x99\x10`)\n\xa7\xf6\u0338\xf8Zx\u06c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x87Pa\xee\x12\xe8 \x04\x1a\x01\x94,\xb0\xe6[\xb4'\xb0\x00`\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\x87XJ?a;\xd4\xfa\xc7L\x1ex\v\x86\xd6\xca\xeb\x89\f\xb2\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x87d\xd0'\"\x00\t\x96\xec\xd4u\xb43)\x8e\x9fT\v\x05\xbf\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x87l?!\x8bGv\xdf<\xa9\xdb\xfb'\r\xe1R\xd9N\xd2R\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x87u\xa6\x10\xc5\x02\xb9\xf1\xe6\xadL\xda\u06cc\xe2\x9b\xffu\xf6\xe4\x89 \x86\xac5\x10R`\x00\x00\u07d4\x87vN6w\xee\xf6\x04\xcb\u015a\xed$\xab\xdcVk\t\xfc%\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\x87\x87\xd1&w\xa5\xec)\x1eW\xe3\x1f\xfb\xfa\xd1\x05\xc32K\x87\x8a\x02\xa2N\xb52\b\xf3\x12\x80\x00\u07d4\x87\x94\xbfG\xd5E@\xec\xe5\xc7\"7\xa1\xff\xb5\x11\u0777Gb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x87\xa5>\xa3\x9fY\xa3[\xad\xa85%!dU\x94\xa1\xa7\x14\u02c9g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x87\xa7\xc5\b\xefqX-\u0665Cr\xf8\x9c\xb0\x1f%/\xb1\x80\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x87\xaf%\xd3\xf6\xf8\xee\xa1S\x13\xd5\xfeEW\xe8\x10\xc5$\xc0\x83\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x87\xb1\x0f\x9c(\x00\x98\x17\x9a+v\xe9\u0390\xbea\xfc\x84M\r\x89Hz\x9a0E9D\x00\x00\u07d4\x87\xbf|\xd5\u0629)\xe1\u01c5\xf9\xe5D\x91\x06\xac#$c\u0249\x047\xb1\x1f\xccEd\x00\x00\u07d4\x87\u0118\x17\t4\xb8#=\x1a\xd1\xe7i1}\\G_/@\x897\b\xba\xed=h\x90\x00\x00\u07d4\x87\xcf6\xad\x03\xc9\xea\xe9\x05:\xbbRB\u0791\x17\xbb\x0f*\v\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x87\u05ec\x06S\xcc\xc6z\xa9\xc3F\x9e\xefCR\x19?}\xbb\x86\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\xe0\x94\x87\xe3\x06+#!\xe9\u07f0\x87\\\u311c\x9b.5\"\xd5\n\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x87\xe6\x03N\xcf#\xf8\xb5c\x9d_\x0e\xa7\n\"S\x8a\x92\x04#\x89\x11\xc7\xea\x16.x \x00\x00\u07d4\x87\xefm\x8bj|\xbf\x9b\\\x8c\x97\xf6~\xe2\xad\u00a7;?w\x89\n\xdd\x1b\xd2<\x00L\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x88F\x92\x8dh2\x89\xa2\xd1\x1d\xf8\xdbz\x94t\x98\x8e\xf0\x13H\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x88I\x80\xebEe\xc1\x04\x83\x17\xa8\xf4\u007f\u06f4a\x96[\u4049\xd8\xd6\x11\x9a\x81F\x05\x00\x00\xe0\x94\x88Jz9\u0411n\x05\xf1\xc2B\xdfU`\u007f7\u07cc_\u068a\x04\xf4\x84<\x15|\x8c\xa0\x00\x00\u07d4\x88T\x93\xbd\xa3j\x042\x97eF\xc1\xdd\xceq\xc3\xf4W\x00!\x89\v\xbfQ\r\xdf\xcb&\x00\x00\xe0\x94\x88`\x9e\nF[n\x99\xfc\xe9\a\x16mW\xe9\xda\b\x14\xf5\u020a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x88m\n\x9e\x17\xc9\xc0\x95\xaf.\xa25\x8b\x89\xecpR\x12\ue509\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\x88y~Xg^\xd5\xccL\x19\x98\a\x83\xdb\xd0\xc9V\bQS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x88|\xacA\xcdpo3E\xf2\xd3J\xc3N\x01u*nY\t\x89 F\\\ue7617\x00\x00\u07d4\x88\x88\x8aW\xbd\x96\x87\xcb\xf9P\xae\xea\u03d7@\xdc\xc4\xd1\xefY\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u0794\x88\x89D\x83\x16\xcc\xf1N\xd8m\xf8\xe2\xf4x\xdcc\xc43\x83@\x88\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x88\x8c\x16\x14I3\x19|\xac&PM\xd7n\x06\xfdf\x00\u01c9\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x88\x8e\x94\x91p\x83\xd1R +S\x1699\x86\x9d'\x11u\xb4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x88\x90\x87\xf6o\xf2\x84\xf8\xb5\xef\xbd)I;pg3\xab\x14G\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\x88\x95\xebrb&\xed\xc3\xf7\x8c\u01a5\x15\a{2\x96\xfd\xb9^\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x88\x97Z_\x1e\xf2R\x8c0\v\x83\xc0\xc6\a\xb8\xe8}\u0593\x15\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\u07d4\x88\x9d\xa4\x0f\xb1\xb6\x0f\x9e\xa9\xbdzE>XL\xf7\xb1\xb4\xd9\xf7\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x88\x9d\xa6b\xebJ\n*\x06\x9d+\xc2K\x05\xb4\xee.\x92\xc4\x1b\x89Z,\x8cTV\xc9\xf2\x80\x00\u07d4\x88\xa1\"\xa28,R91\xfbQ\xa0\u032d;\xeb[rY\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x88\xa2\x15D0\xc0\xe4\x11G\xd3\xc1\xfe\u3cf0\x06\xf8Q\xed\xbd\x8965f3\xeb\xd8\xea\x00\x00\u07d4\x88\xb2\x17\u0337\x86\xa2T\xcfM\xc5\u007f]\x9a\xc3\xc4U\xa3\x04\x83\x892$\xf4'#\xd4T\x00\x00\xe0\x94\x88\xbcC\x01.\xdb\x0e\xa9\xf0b\xacCxC%\n9\xb7\x8f\xbb\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x88\xc2Qj|\xdb\t\xa6'mr\x97\xd3\x0fZM\xb1\xe8K\x86\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x88\xc3ad\rki7;\b\x1c\xe0\xc43\xbdY\x02\x87\xd5\xec\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x88\xd5A\xc8@\xceC\xce\xfb\xafm\x19\xafk\x98Y\xb5s\xc1E\x89\t79SM(h\x00\x00\u07d4\x88\xde\x13\xb0\x991\x87|\x91\rY1e\xc3d\u0221d\x1b\u04c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x88\xde\u017d?N\xba-\x18\xb8\xaa\xce\xfa{r\x15H\xc3\x19\xba\x89JD\x91\xbdm\xcd(\x00\x00\u07d4\x88\xe6\xf9\xb2G\xf9\x88\xf6\xc0\xfc\x14\xc5o\x1d\xe5>\u019dC\u0309\x05k\xc7^-c\x10\x00\x00\u07d4\x88\xee\u007f\x0e\xfc\x8fw\x8ckh~\xc3+\xe9\xe7\xd6\xf0 \xb6t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x88\xf1\x04_\x19\xf2\xd3\x19\x18\x16\xb1\xdf\x18\xbbn\x145\xad\x1b8\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x89\x00\x9e\a\xe3\xfahc\xa7x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x89Wr~r\xcfb\x90 \xf4\xe0^\xdfy\x9a\xa7E\x80b\u0409wC\"\x17\xe6\x83`\x00\x00\u07d4\x89]iN\x88\v\x13\xcc\u0404\x8a\x86\xc5\xceA\x1f\x88Gk\xbf\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x89^\xc5TVD\u0dc30\xff\xfa\xb8\xdd\xea\xc9\xe83\x15l\x89 \x86\xac5\x10R`\x00\x00\u07d4\x89`\tRj,{\f\t\xa6\xf6:\x80\xbd\U0009d707\u079c\x89\xbb\xb8k\x82#\xed\xeb\x00\x00\u07d4\x89g\u05f9\xbd\xb7\xb4\xae\xd2.e\xa1]\xc8\x03\xcbz!?\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x89n3\\\xa4z\xf5yb\xfa\x0fM\xbf>E\xe6\x88\u02e5\x84\x89J/\xc0\xab`R\x12\x00\x00\u07d4\x89s\xae\xfd^\xfa\xee\x96\t]\x9e(\x8fj\x04l\x977KC\x89\a\xa4\u0120\xf32\x14\x00\x00\u07d4\x89\x8cr\xddseX\xef\x9eK\xe9\xfd\xc3O\xefT\xd7\xfc~\b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x89\x9b<$\x9f\fK\x81\xdfu\xd2\x12\x00M=m\x95/\xd2#\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x89\xab\x13\xee&mw\x9c5\xe8\xbb\x04\u034a\x90\xcc!\x03\xa9[\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\x89\xc43\xd6\x01\xfa\xd7\x14\xdaci0\x8f\xd2l\x1d\u0254+\xbf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x89\xd7[\x8e\b1\xe4o\x80\xbc\x17A\x88\x18N\x00o\xde\x0e\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x89\u3d5a\x15\x86G7\u0513\xc1\xd2<\xc5=\xbf\x8d\xcb\x13b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x89\xfc\x8eM8k\r\v\xb4\xa7\a\xed\xf3\xbdV\r\xf1\xad\x8fN\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\x89\xfe\xe3\r\x17(\xd9l\xec\xc1\u06b3\xda.w\x1a\xfb\u03eaA\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x8a\x1c\u016c\x11\x1cI\xbf\xcf\xd8H\xf3}\xd7h\xaae\u0208\x02\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x8a \xe5\xb5\xce\xe7\xcd\x1fU\x15\xba\xce;\xf4\xf7\u007f\xfd\xe5\xcc\a\x89\x04V9\x18$O@\x00\x00\xe0\x94\x8a!}\xb3\x8b\xc3_!_\xd9)\x06\xbeBCo\xe7\xe6\xed\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x8a$:\n\x9f\xeaI\xb89TwE\xff-\x11\xaf?K\x05\"\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x8a$}\x18e\x10\x80\x9fq\xcf\xfcEYG\x1c9\x10\x85\x81!\x89a\t=|,m8\x00\x00\u07d4\x8a4p(-^**\xef\u05e7P\x94\xc8\"\xc4\xf5\xae\uf289\r(\xbc`dx\xa5\x80\x00\u07d4\x8a6\x86\x9a\xd4x\x99|\xbfm\x89$\xd2\n<\x80\x18\xe9\x85[\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8aC\x14\xfba\u0353\x8f\xc3>\x15\xe8\x16\xb1\x13\U000ac267\xfb\x89\x17vNz\xede\x10\x00\x00\u07d4\x8aOJ\u007fR\xa3U\xba\x10_\xca r\xd3\x06_\xc8\xf7\x94K\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8aX1(,\xe1Jezs\r\xc1\x88&\xf7\xf9\xb9\x9d\xb9h\x89\uaf8a[A\xc16\x00\x00\u07d4\x8a_\xb7W\x93\xd0C\xf1\xbc\xd48\x85\xe07\xbd0\xa5(\xc9'\x89\x13Snm.\x9a\xc2\x00\x00\u07d4\x8af\xab\xbc-0\xce!\xa83\xb0\u06ceV\x1dQ\x05\xe0\xa7,\x89%\xf1\xde\\v\xac\xdf\x00\x00\u07d4\x8atl]g\x06G\x11\xbf\xcah[\x95\xa4\xfe)\x1a'\x02\x8e\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8ax\n\xb8z\x91E\xfe\x10\xed`\xfaGjt\n\xf4\u02b1\u0489\x12\x1b.^ddx\x00\x00\u07d4\x8az\x06\xbe\x19\x9a:X\x01\x9d\x84j\xc9\xcb\xd4\xd9]\xd7W\u0789\xa2\xa4#\x94BV\xf4\x00\x00\u07d4\x8a\x81\x01\x14\xb2\x02]\xb9\xfb\xb5\x00\x99\xa6\xe0\u02de.\xfak\u0709g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x8a\x86\xe4\xa5\x1c\x01;\x1f\xb4\xc7k\xcf0f|x\xd5.\xed\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\x9e\u029cZ\xba\x8e\x13\x9f\x80\x03\xed\xf1\x16:\xfbp\xaa:\xa9\x89#\xc7W\a+\x8d\xd0\x00\x00\u07d4\x8a\xb89\xae\xaf*\xd3|\xb7\x8b\xac\xbb\xb63\xbc\xc5\xc0\x99\xdcF\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\u021b\u06780\x1ek\x06w\xfa%\xfc\xf0\xf5\x8f\f\u01f6\x11\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x8a\xdcS\xef\x8c\x18\xed0Qx]\x88\xe9\x96\xf3\xe4\xb2\x0e\xcdQ\x8a\b\xe4\xd3\x16\x82v\x86@\x00\x00\u07d4\x8a\xe6\xf8\vp\xe1\xf2<\x91\xfb\u0569f\xb0\xe4\x99\xd9]\xf82\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x8a\xe9\uf30a\x8a\u07e6\xaby\x8a\xb2\xcd\xc4\x05\b*\x1b\xbbp\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\xf6&\xa5\xf3'\xd7Pe\x89\xee\xb7\x01\x0f\xf9\xc9D` \u0489K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\x8b\x01\xda4\xd4p\xc1\xd1\x15\xac\xf4\xd8\x11\xe1\x01\xdb\x1e\x14\xec\xc7\xd3\"\xc7+\x8c\x04s\x89\x18\xb2j1>\x8a\xe9\x00\x00\xe0\x94\x8bH\xe1\x9d9\xdd5\xb6nn\x1b\xb6\xb9\xc6W\xcb,\xf5\x9d\x04\x8a\x03\xc7U\xac\x9c\x02J\x01\x80\x00\xe0\x94\x8bP^(q\xf7\u07b7\xa68\x95 \x8e\x82'\u072a\x1b\xff\x05\x8a\f\xf6\x8e\xfc0\x8dy\xbc\x00\x00\u07d4\x8bW\xb2\xbc\x83\u030dM\xe31 N\x89?/;\x1d\xb1\a\x9a\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8b\\\x91K\x12\x8b\xf1i\\\b\x89#\xfaF~y\x11\xf3Q\xfa\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\xe0\x94\x8b_)\xcc/\xaa&,\xde\xf3\x0e\xf5T\xf5\x0e\xb4\x88\x14n\xac\x8a\x01;hp\\\x97 \x81\x00\x00\u07d4\x8bpV\xf6\xab\xf3\xb1\x18\xd0&\xe9D\xd5\xc0sC<\xa4Q\u05c965\xc6 G9\u0640\x00\u07d4\x8bqE\"\xfa(9b\x04p\xed\xcf\fD\x01\xb7\x13f=\xf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x8bt\xa7\xcb\x1b\xb8\u014f\xce&tf\xa3\x03X\xad\xafR\u007fa\x8a\x02\xe2WxN%\xb4P\x00\x00\u07d4\x8b~\x9fo\x05\xf7\xe3dv\xa1n>q\x00\xc9\x03\x1c\xf4\x04\xaf\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8b\x81\x15ni\x869\x94<\x01\xa7Rr\xad=5\x85\x1a\xb2\x82\x89\x12\xb3\x16_e\xd3\xe5\x00\x00\u07d4\x8b\x95w\x92\x00S\xb1\xa0\x01\x890M\x88\x80\x10\xd9\xef,\xb4\xbf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8b\x98A\x86.w\xfb\xbe\x91\x94p\x93U\x83\xa9<\xf0'\xe4P\x89llS4B\u007f\x1f\x00\x00\u07d4\x8b\x99}\xbc\a\x8a\xd0)a5]\xa0\xa1Y\xf2\x92~\xd4=d\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x8b\x9f\xda}\x98\x1f\xe9\xd6B\x87\xf8\\\x94\xd8?\x90t\x84\x9f\u030a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x8b\xb0!/2\x95\xe0)\u02b1\xd9a\xb0A3\xa1\x80\x9e{\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8b\xbe\xac\xfc)\xcf\xe94\x02\xdb\xd6j\x1a\xcbvv\x85c7\xb9;\xf0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8b\xf3s\xd0v\x81L\xbcW\xe1\xc6\xd1j\x82\u017e\x13\xc7=7\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x8c\x10#\xfd\xe1WM\xb8\xbbT\xf1s\x96p\x15|\xa4}\xa6R\x8a\x01y\u03da\u00e1\xb1w\x00\x00\u07d4\x8c\x1f\xbe_\n\xea5\x9cZ\xa1\xfa\b\u0209T\x12\u028e\x05\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\"B`U\xb7o\x11\xf0\xa2\xde\x1a\u007f\x81\x9aa\x96\x85\xfe`\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4\x8c+}\x8b`\x8d(\xb7\u007f\\\xaa\x9c\xd6E$*\x82>L\u0649b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\x8c/\xbe\ue3ac\xc5\xc5\xd7|\x16\xab\xd4b\ue701E\xf3K\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x8c:\x9e\xe7\x1fr\x9f#l\xba8g\xb4\u05dd\x8c\xee\xe2]\xbc\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8cP\xaa*\x92\x12\xbc\xdeVA\x8a\xe2a\xf0\xb3^z\x9d\xbb\x82\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8cT\xc7\xf8\xb9\x89nu\xd7\xd5\xf5\xc7`%\x86\x99\x95qB\xad\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8c]\x16\xede\xe3\xed~\x8b\x96\u0297+\xc8as\xe3P\v\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8cj\xa8\x82\xee2,\xa8HW\x8c\x06\xcb\x0f\xa9\x11\xd3`\x83\x05\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\x8cj\xe7\xa0Z\x1d\xe5u\x82\xae'h Bv\xc0\xffG\xed\x03\x8a,\v\xb3\xdd0\xc4\xe2\x00\x00\x00\u07d4\x8co\x9fN[z\xe2v\xbfXI{\u05ff*}%$_d\x89\x93\xfe\\W\xd7\x10h\x00\x00\u07d4\x8cu\x95n\x8f\xedP\xf5\xa7\xdd|\xfd'\xda \x0fgF\xae\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c|\xb4\xe4\x8b%\x03\x1a\xa1\xc4\xf9)%\xd61\xa8\xc3\xed\xc7a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\u007f\xa5\xca\xe8/\xed\xb6\x9a\xb1\x89\xd3\xff'\xae \x92\x93\xfb\x93\x89\x15\xaf\x88\r\x8c\u06c3\x00\x00\xe0\x94\x8c\x81A\x0e\xa85L\xc5\xc6\\A\xbe\x8b\xd5\xdes<\v\x11\x1d\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\x8c\x83\xd4$\xa3\xcf$\xd5\x1f\x01\x92=\xd5J\x18\u05b6\xfe\xde{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8c\x90\n\x826\xb0\x8c+e@]9\xd7_ \x06*ua\xfd\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\x8c\x93\xc3\xc6\u06dd7q}\xe1e\u00e1\xb4\xfeQ\x95,\b\u0789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8c\x99\x95\x91\xfdr\xefq\x11\xef\xcaz\x9e\x97\xa25k;\x00\n\x89\xddd\xe2\xaa\ngP\x00\x00\u07d4\x8c\xa6\x98\x97F\xb0n2\xe2Hta\xb1\u0399j':\xcf\u05c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8c\xb3\xaa?\xcd!(T\xd7W\x8f\xcc0\xfd\xed\xe6t*1*\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x8c\xc0\xd7\xc0\x16\xfaz\xa9P\x11J\xa1\xdb\tH\x82\xed\xa2t\xea\x89\b\xa9\xab\xa5W\xe3l\x00\x00\u07d4\x8c\xc6R\xdd\x13\xe7\xfe\x14\u06bb\xb3m]2\r\xb9\xff\xee\x8aT\x89a\t=|,m8\x00\x00\u07d4\x8c\u02bf%\a\u007f:\xa4\x15E4MS\xbe\x1b+\x9c3\x90\x00\x89[\xe8f\xc5b\xc5D\x00\x00\u07d4\x8c\xcf:\xa2\x1a\xb7BWj\xd8\xc4\"\xf7\x1b\xb1\x88Y\x1d\ua28965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\xd0\xcd\"\xe6 \xed\xa7\x9c\x04a\xe8\x96\xc9\xd1b)\x12K_z\xfb\xec\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x8c\xe2/\x9f\xa3rD\x9aB\x06\x10\xb4z\xe0\xc8\xd5eH\x122\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x8c\u451d\x8a\x16T-B<\x17\x98Ng9\xfar\u03b1w\x8a\x05K@Y&\xf4\xa6=\x80\x00\u07d4\x8c\xe5\xe3\xb5\xf5\x91\xd5\uc8ca\xbf\"\x8f.<5\x13K\xda\xc0\x89}\xc3[\x84\x89|8\x00\x00\xe0\x94\x8c\xee8\xd6YW\x88\xa5n?\xb9F4\xb3\xff\xe1\xfb\xdb&\u058a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x8c\xee\xa1^\xec;\xda\xd8\x02?\x98\xec\xf2[+\x8f\xef'\xdb)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8c\xf3To\xd1\u0363=X\x84_\xc8\xfc\xfe\u02bc\xa7\xc5d*\x89\x1f\x1e9\x93,\xb3'\x80\x00\u07d4\x8c\xf6\xda\x02\x04\xdb\u0106\vF\xad\x97?\xc1\x11\x00\x8d\x9e\fF\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x8c\xfe\xde\xf1\x98\xdb\n\x91C\xf0\x91)\xb3\xfdd\u073b\x9bIV\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\x04\xa5\xeb\xfb]\xb4\t\xdb\x06\x17\xc9\xfaV1\xc1\x92\x86\x1fJ\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x8d\x06\xe4d$\\\xadaI9\xe0\xaf\bE\xe6\xd70\xe2\x03t\x89\n\u070a(\xf3\xd8}\x80\x00\u07d4\x8d\a\xd4-\x83\x1c-|\x83\x8a\xa1\x87+:\xd5\xd2w\x17h#\x89\x12\xee\x1f\x9d\xdb\xeeh\x00\x00\u07d4\x8d\v\x9e\xa5?\xd2cA^\xac\x119\x1f|\xe9\x12V\xb9\xfb\x06`\xf6\xf0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8dy\\_JV\x89\xadb\u0696\x16q\xf0(\x06R\x86\xd5T\x89o\x05\xb5\x9d; \x00\x00\x00\u07d4\x8d\u007f>a)\x9c-\xb9\xb9\xc0H|\xf6'Q\x9e\xd0\n\x91#\x89^t\xa8P^\x80\xa0\x00\x00\xe0\x94\x8d\x89\x17\v\x92\xb2\xbe,\b\xd5|H\xa7\xb1\x90\xa2\xf1Fr\x0f\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x8d\x93\xda\u01c5\xf8\x8f\x1a\x84\xbf\x92}Se+E\xa1T\xcc\u0749\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x8d\x99R\u043bN\xbf\xa0\xef\xd0\x1a:\xa9\xe8\xe8\u007f\x05%t.\x89\xbb\x91%T\"c\x90\x00\x00\u07d4\x8d\x9a\fp\xd2& B\xdf\x10\x17\xd6\xc3\x03\x13 $w'\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\x9e\xd7\xf4U0X\xc2ox6\xa3\x80-0d\xeb\x1b6=\x89\x04\xe1\x00;(\xd9(\x00\x00\u07d4\x8d\xa1\x17\x8fU\xd9wr\xbb\x1d$\x11\x1a@JO\x87\x15\xb9]\x89/\x9a\xc3\xf6\xde\x00\x80\x80\x00\u07d4\x8d\xa1\xd3Y\xbal\xb4\xbc\xc5}zCw \xd5]\xb2\xf0\x1cr\x89\x04V9\x18$O@\x00\x00\u07d4\x8d\xab\x94\x8a\xe8\x1d\xa3\x01\xd9r\xe3\xf6\x17\xa9\x12\xe5\xa7Sq.\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8d\xad\xdfR\xef\xbdt\u0695\xb9i\xa5GoO\xbb\xb5c\xbf\u0489-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4\x8d\xb1\x85\xfe\x1bp\xa9Jj\b\x0e~#\xa8\xbe\xdcJ\xcb\xf3K\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x8d\xb5\x8e@n -\xf9\xbcpl\xb43\xe1\x94\xf4\x0f\x82\xb4\x0f\xaa\xdb\x1f\x8b\x85a\x16\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x8d\xc1\xd5\x11\x1d\t\xaf%\xfd\xfc\xacE\\|\xec(>mgu\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\u0504\xff\x8a0sd\xebf\xc5%\xa5q\xaa\xc7\x01\xc5\xc3\x18\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\u05a9\xba\xe5\u007fQ\x85I\xad\xa6wFo\ua2b0O\u0674\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\xde<\xb8\x11\x85h\xefE\x03\xfe\x99\x8c\xcd\xf56\xbf\x19\xa0\x98\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\xde`\xeb\b\xa0\x99\xd7\u06a3V\u06aa\xb2G\r{\x02Zk\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x8d\xf39!Kj\u0472Fc\xceq`4t\x9dn\xf88\u064a\x02TO\xaaw\x80\x90\xe0\x00\x00\xe0\x94\x8d\xf5=\x96\x19\x14q\xe0Y\xdeQ\xc7\x18\xb9\x83\xe4\xa5\x1d*\xfd\x8a\x06\u01b95\xb8\xbb\xd4\x00\x00\x00\u07d4\x8d\xfb\xaf\xbc\x0e[\\\x86\xcd\x1a\u0597\xfe\xea\x04\xf41\x88\u0796\x89\x15%+\u007f_\xa0\xde\x00\x00\u07d4\x8e\a;\xad%\xe4\"\x18a_J\x0ek.\xa8\xf8\xde\"0\xc0\x89\x82=b\x9d\x02k\xfa\x00\x00\u07d4\x8e\x0f\xee8hZ\x94\xaa\xbc\xd7\u0385{k\x14\t\x82Ou\xb8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e#\xfa\xcd\x12\xc7e\xc3j\xb8\x1am\xd3M\x8a\xa9\xe6\x89\x18\xae\x89\t\x11\u418d\xba\x9b\x00\x00\xe0\x94\x8e/\x904\xc9%G\x19\u00ceP\u026ad0^\u0596\xdf\x1e\x8a\x01\x00N.E\xfb~\xe0\x00\x00\u07d4\x8e2@\xb0\x81\x0e\x1c\xf4\a\xa5\x00\x80G@\u03cdad2\xa4\x89\x02/fU\xef\v8\x80\x00\u07d4\x8eHj\x04B\xd1q\xc8`[\xe3H\xfe\xe5~\xb5\b^\xff\r\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8eaV3k\xe2\u037e2\x14\r\xf0\x8a+\xa5_\u0425\x84c\x89\x04\t\x9e\x1dcW\x18\x00\x00\u07d4\x8eg\b\x15\xfbg\xae\xae\xa5{\x86SN\xdc\x00\xcd\xf5d\xfe\u5272\xe4\xb3#\xd9\xc5\x10\x00\x00\u07d4\x8emt\x85\xcb\u942c\xc1\xad\x0e\xe9\xe8\xcc\xf3\x9c\f\x93D\x0e\x893\xc5I\x901r\f\x00\x00\xe0\x94\x8et\xe0\u0477~\xbc\x82:\xca\x03\xf1\x19\x85L\xb1 '\xf6\u05ca\x16\xb3R\xda^\x0e\xd3\x00\x00\x00\u07d4\x8ex\xf3QE}\x01oJ\xd2u^\xc7BN\\!\xbamQ\x89\a\xea(2uw\b\x00\x00\u07d4\x8ey6\u0552\x00\x8f\xdcz\xa0N\xde\xebuZ\xb5\x13\u06f8\x9d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8e\u007f\xd28H\xf4\xdb\a\x90j}\x10\xc0K!\x80;\xb0\x82'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8e\x92\xab\xa3\x8er\xa0\x98\x17\v\x92\x95\x92FSz.UV\xc0\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x8e\x98ve$\xb0\xcf'G\xc5\r\xd4;\x95gYM\x971\u0789lD\xb7\xc2a\x82(\x00\x00\u07d4\x8e\x9b5\xadJ\n\x86\xf7XDo\xff\xde4&\x9d\x94\f\xea\u0349\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8e\x9c\b\xf78f\x1f\x96v#n\xff\x82\xbaba\xdd?H\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8e\x9cB\x92f\xdf\x05~\xfax\xdd\x1d_w\xfc@t*\xd4f\x89\x10D.\u0475l|\x80\x00\u07d4\x8e\xa6V\xe7\x1e\xc6Q\xbf\xa1|ZWY\xd8`1\xcc5\x99w\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8e\xae)CU\x98\xba\x8f\x1c\x93B\x8c\xdb>+M1\a\x8e\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\xb1\xfb\xe4\xe5\xd3\x01\x9c\xd7\xd3\r\xae\x9c\r[Lv\xfbc1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\xb5\x17t\xaf k\x96k\x89\t\xc4Z\xa6r'H\x80,\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e\xb8\xc7\x19\x82\xa0\x0f\xb8Bu)2S\xf8\x04ED\xb6kI\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\x8e\xcb\u03ec\xbf\xaf\xe9\xf0\f9\"\xa2N,\xf0\x02gV\xca \x8a\x011\xbe\xb9%\xff\xd3 \x00\x00\u07d4\x8e\u03b2\xe1$Sl[_\xfcd\x0e\xd1O\xf1^\u0668\xcbq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\u042f\x11\xff(p\xda\x06\x81\x00J\xfe\x18\xb0\x13\xf7\xbd8\x82\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\x8e\xd1Cp\x1f/r(\x0f\xd0J{Ad(\x19y\xea\x87\u0248\xc2I\xfd\xd3'x\x00\x00\u07d4\x8e\xd1R\x8bD~\xd4)y\x02\xf69\xc5\x14\u0414J\x88\xf8\u0209\n\xc6\xe7z\xb6c\xa8\x00\x00\u07d4\x8e\xd4(L\x0fGD\x9c\x15\xb8\u0673$]\u8fb6\u0380\xbf\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\x8e\xde~=\xc5\aI\xc6\xc5\x0e.(\x16\x84x\xc3M\xb8\x19F\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x8e\xe5\x843}\xdb\xc8\x0f\x9e4\x98\xdfU\xf0\xa2\x1e\xac\xb5\u007f\xb1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8e\xeb\xec\x1ab\xc0\x8b\x05\xa7\xd1\u0551\x80\xaf\x9f\xf0\u044e?6\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e\xf4\u0622\xc2o\xf7\x14\xb6u\x89\x19\x80\x1c\x83\xb6\xc7\xc0\x00\x00\u07d4\x8fM\x1dAi>F,\xf9\x82\xfd\x81\u042ap\x1d:St\u0249\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8fM\x1e~Ea(J4\xfe\xf9g<\r4\xe1*\xf4\xaa\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8fO\xb1\xae\xa7\xcd\x0fW\x0e\xa5\xe6\x1b@\xa4\xf4Q\vbd\xe4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8fV\x1bA\xb2\t\xf2H\u0229\x9f\x85\x87\x887bP`\x9c\xf3\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94\x8fX\xd84\x8f\xc1\xdcN\r\xd84;eC\xc8W\x04^\xe9@\x8a\x02\xe3\x03\x8d\xf4s\x03(\x00\x00\u07d4\x8f`\x89_\xbe\xbb\xb5\x01\u007f\xcb\xff<\u0763\x97)+\xf2[\xa6\x89\x17D\x06\xff\x9fo\u0480\x00\u07d4\x8fd\xb9\xc1$m\x85x1d1\a\xd3U\xb5\xc7_\xef]O\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x8ff\x0f\x8b.L|\u00b4\xac\x9cG\xed(P\x8d_\x8f\x86P\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x8fi\xea\xfd\x023\xca\xdb@Y\xabw\x9cF\xed\xf2\xa0PnH\x89`\xf0f \xa8IE\x00\x00\xe0\x94\x8fq~\xc1U/LD\x00\x84\xfb\xa1\x15J\x81\xdc\x00>\xbd\xc0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x8f\x8a\xcb\x10v\a8\x84y\xf6K\xaa\xab\xea\x8f\xf0\a\xad\xa9}\x8a\x05\xc6\xf3\b\n\xd4#\xf4\x00\x00\u07d4\x8f\x8c\xd2n\x82\xe7\xc6\xde\xfd\x02\u07ed\a\x97\x90!\xcb\xf7\x15\f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x8f\x8f7\u042d\x8f3]*q\x01\xb4\x11V\xb6\x88\xa8\x1a\x9c\xbe\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\x8f\x92\x84O(*\x92\x99\x9e\u5d28\xd7s\xd0kiM\xbd\x9f\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x8f\xact\x8fxJ\x0f\xedh\u06e43\x19\xb4*u\xb4d\x9cn\x891T\xc9r\x9d\x05x\x00\x00\u07d4\x8f\u0665\xc3:}\x9e\xdc\xe0\x99{\xdfw\xab0d$\xa1\x1e\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8f\xef\xfa\xdb8z\x15G\xfb(M\xa9\xb8\x14\u007f>|m\xc6\u0689-b{\xe4S\x05\b\x00\x00\u07d4\x8f\xf4`Ehw#\xdc3\xe4\u0419\xa0i\x04\xf1\ubd44\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\x8f\xfa\x06!\"\xac0t\x18\x82\x1a\u06d3\x11\aZ7\x03\xbf\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8f\xfe2)\x97\xb8\xe4\x04B-\x19\xc5J\xad\xb1\x8f[\xc8\u9dc9\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x90\x01\x94\u0131\aC\x05\u045d\xe4\x05\xb0\xacx(\x0e\xca\xf9g\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x90\x03\xd2p\x89\x1b\xa2\xdfd=\xa84\x15\x83\x195E\xe3\xe0\x00\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x90\x05z\xf9\xaaf0~\xc9\xf03\xb2\x97$\u04f2\xf4\x1e\xb6\xf9\x8a\x19\xd1\u05aa\xdb,R\xe8\x00\x00\u07d4\x90\x0f\v\x8e5\xb6h\xf8\x1e\xf2R\xb18U\xaaP\a\xd0\x12\xe7\x89\x17\n\x0fP@\xe5\x04\x00\x00\u07d4\x90\x18\xcc\x1fH\xd20\x8e%*\xb6\b\x9f\xb9\x9a|\x1dV\x94\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x90\x1d\x99\xb6\x99\xe5\u0191\x15\x19\xcb v\xb4\xc7c0\xc5M\"\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x90-t\xa1W\xf7\u04b9\xa37\x8b\x1fVp70\xe0:\x17\x19\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x904\x13\x87\x8a\xea;\xc1\bc\t\xa3\xfev\x8beU\x9e\x8c\xab\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x90If\xcc\"\x13\xb5\xb8\xcb[\xd6\b\x9e\xf9\xcd\xdb\xef~\xdf\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\x90L\xaaB\x9ca\x9d\x94\x0f\x8egA\x82j\r\xb6\x92\xb1\x97(\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x90R\xf2\xe4\xa3\xe3\xc1-\xd1\xc7\x1b\xf7\x8aN\xc3\x04=\u020b~\x89\x0e~\xeb\xa3A\vt\x00\x00\u0794\x90U&V\x8a\xc1#\xaf\xc0\xe8J\xa7\x15\x12O\xeb\xe8=\xc8|\x88\xf8i\x93)g~\x00\x00\u07d4\x90\x92\x91\x87\a\xc6!\xfd\xbd\x1d\x90\xfb\x80\xebx\u007f\xd2osP\x89\x85[[\xa6\\\x84\xf0\x00\x00\u07d4\x90\x9b^v:9\xdc\u01d5\"=s\xa1\u06f7\xd9L\xa7Z\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\x90\xac\xce\xd7\xe4\x8c\b\u01b94dm\xfa\n\xdf)\u0714\aO\x89\x03\vK\x15{\xbdI\x00\x00\u07d4\x90\xb1\xf3p\xf9\xc1\xeb\v\xe0\xfb\x8e+\x8a\xd9jAcq\u074a\x890\xca\x02O\x98{\x90\x00\x00\u07d4\x90\xb6/\x13\x1a_)\xb4UqQ>\xe7\xa7J\x8f\v#\"\x02\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x90\xbdb\xa0P\x84Ra\xfaJ\x9f|\xf2A\xeac\v\x05\ufe09\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x90\xc4\x1e\xba\x00\x8e \xcb\xe9'\xf3F`?\u0206\x98\x12Yi\x89\x02F\xdd\xf9yvh\x00\x00\u07d4\x90\u0480\x9a\xe1\xd1\xff\xd8\xf6>\xda\x01\xdeI\xddU-\xf3\u047c\x89\u063beI\xb0+\xb8\x00\x00\u07d4\x90\xdc\t\xf7\x17\xfc*[i\xfd`\xba\b\xeb\xf4\v\xf4\xe8$l\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x90\xe3\x00\xacqE\x1e@\x1f\x88\u007fnw(\x85\x16G\xa8\x0e\a\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x90\xe3Z\xab\xb2\xde\xef@\x8b\xb9\xb5\xac\xefqDW\xdf\xdebr\x89\x05l\xd5_\xc6M\xfe\x00\x00\u07d4\x90\xe7\a\x0fM\x03?\xe6\x91\f\x9e\xfeZ'\x8e\x1f\xc6#M\xef\x89\x05q8\b\x19\xb3\x04\x00\x00\u07d4\x90\xe9>M\xc1q!HyR36\x14\x00+\xe4#VI\x8e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x90\u9a68.\u06a8\x14\u0084\xd22\xb6\u9e90p\x1dIR\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\x90\xf7t\xc9\x14}\u0790\x85=\xdcC\xf0\x8f\x16\xd4U\x17\x8b\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x90\xfcS{!\x06Xf\n\x83\xba\xa9\xacJ\x84\x02\xf6WF\xa8\x89e\xea=\xb7UF`\x00\x00\u07d4\x91\x05\n\\\xff\xad\xed\xb4\xbbn\xaa\xfb\xc9\xe5\x014(\xe9l\x80\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x91\x05\x17d\xafk\x80\x8eB\x12\xc7~0\xa5W.\xaa1pp\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x91\v}Wz~9\xaa#\xac\xf6*\xd7\xf1\xef4)4\xb9h\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x91\x0e\x99eC4Lh\x15\xfb\x97\u0367\xafK\x86\x98vZ[\x89\x05\x9a\xf6\x98)\xcfd\x00\x00\u07d4\x91\x1f\xee\xa6\x1f\xe0\xedP\u0179\xe5\xa0\xd6`q9\x9d(\xbd\u0189\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x91\x1f\xf23\xe1\xa2\x11\xc0\x17,\x92\xb4l\xf9\x97\x03\x05\x82\xc8:\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x91 \xe7\x11s\xe1\xba\x19\xba\x8f\x9fO\xdb\u072a4\xe1\u05bbx\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91!\x17\x12q\x9f+\bM;8u\xa8Pi\xf4f61A\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x91#\x04\x11\x8b\x80G=\x9e\x9f\xe3\xeeE\x8f\xbea\x0f\xfd\xa2\xbb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x91Tky\xec\xf6\x9f\x93kZV\x15\b\xb0\xd7\xe5\f\u0159/\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x91V\u0440)5\x0eG\x04\b\xf1_\x1a\xa3\xbe\x9f\x04\ng\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x91b\x0f>\xb3\x04\xe8\x13\u048b\x02\x97Ume\xdcN]\u5a89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\x91k\xf7\xe3\xc5E\x92\x1d2\x06\xd9\x00\xc2O\x14\x12|\xbd^p\x8a\x03\xd0\u077c}\xf2\xbb\x10\x00\x00\u0794\x91l\xf1}qA(\x05\xf4\xaf\xc3DJ\v\x8d\xd1\xd93\x9d\x16\x88\xc6s\xce<@\x16\x00\x00\u07d4\x91{\x8f\x9f:\x8d\t\xe9 ,R\u009erA\x96\xb8\x97\xd3^\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\x91\x89g\x91\x8c\u0617\xdd\x00\x05\xe3m\xc6\u0203\xefC\x8f\xc8\u01c9\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x91\x89\x8e\xab\x8c\x05\xc0\"(\x83\xcdM\xb2;w\x95\xe1\xa2J\u05c9lk\x93[\x8b\xbd@\x00\x00\u0794\x91\x91\xf9F\x98!\x05\x16\xcfc!\xa1B\a\x0e Yvt\xed\x88\xee\x9d[\xe6\xfc\x11\x00\x00\u07d4\x91\xa4\x14\x9a,{\x1b:g\xea(\xaf\xf3G%\u0fcdu$\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x91\xa7\x87\xbcQ\x96\xf3HW\xfe\f7/M\xf3v\xaa\xa7f\x13\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91\xa8\xba\xae\xd0\x12\xea.c\x80;Y=\r\f*\xabL[\n\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x91\xac\\\xfeg\xc5J\xa7\xeb\xfb\xa4HflF\x1a;\x1f\xe2\xe1\x89\x15\xc94\x92\xbf\x9d\xfc\x00\x00\u07d4\x91\xbb?y\x02+\xf3\xc4S\xf4\xff%n&\x9b\x15\xcf,\x9c\xbd\x89RX\\\x13\xfe:\\\x00\x00\u07d4\x91\xc7^<\xb4\xaa\x89\xf3F\x19\xa1d\xe2\xa4x\x98\xf5gM\x9c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91\xc8\f\xaa\b\x1b85\x1d*\x0e\x0e\x00\xf8\n4\xe5dt\xc1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x91\xccF\xaa7\x9f\x85jf@\xdc\xcdZd\x8ay\x02\xf8I\u0649\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x91\u04a9\xee\x1am\xb2\x0fS\x17\u0327\xfb\xe218\x95\u06ce\xf8\x8a\x01\xcc\u00e5/0n(\x00\x00\u07d4\x91\xd6n\xa6(\x8f\xaaK=`l*\xa4\\{k\x8a%'9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x91\u06f6\xaa\xad\x14\x95\x85\xbeG7\\]m\xe5\xff\t\x19\x15\x18\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x91\xe8\x81\x06R\xe8\xe6\x16\x15%\xd6;\xb7u\x1d\xc2\x0fg`v\x89'Mej\xc9\x0e4\x00\x00\u07d4\x91\xf5\x16\x14l\xda (\x17\x19\x97\x80`\u01beAI\x06|\x88\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x91\xf6$\xb2J\x1f\xa5\xa0V\xfeW\x12)\xe77\x9d\xb1K\x9a\x1e\x8a\x02\x8a\x85\x17\xc6i\xb3W\x00\x00\xe0\x94\x91\xfe\x8aLad\u07cf\xa6\x06\x99]k\xa7\xad\xca\xf1\u0213\u038a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4\x92\x1fRa\xf4\xf6\x12v\a\x06\x89&%\xc7^{\u0396\xb7\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92!\xc9\xce\x01#&et\x10\x96\xac\a#Y\x03\xad\x1f\xe2\xfc\x89\x06\xdbc3U\"b\x80\x00\u07d4\x92%\x988`\xa1\xcbF#\xc7$\x80\xac\x16'+\f\x95\xe5\xf5\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x92%\xd4jZ\x80\x949$\xa3\x9e[\x84\xb9m\xa0\xacE\x05\x81\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x92* \u01da\x1d:&\xdd8)g{\xf1\xd4\\\x8fg+\xb6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x92C\x8eR\x03\xb64o\xf8\x86\xd7\xc3b\x88\xaa\xcc\xccx\xce\u028965\u026d\xc5\u07a0\x00\x00\u07d4\x92C\xd7v-w({\x12c\x86\x88\xb9\x85N\x88\xa7i\xb2q\x8965\u026d\xc5\u07a0\x00\x00\u0794\x92K\xcez\x85<\x97\v\xb5\xec{\xb7Y\xba\xeb\x9ct\x10\x85{\x88\xbe -j\x0e\xda\x00\x00\u07d4\x92N\xfam\xb5\x95\xb7\x93\x13'~\x881\x96%\akX\n\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92U\x82&\xb3\x84bl\xadH\xe0\x9d\x96k\xf19^\xe7\xea]\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4\x92`\x82\xcb~\xedK\x19\x93\xad$ZGrg\xe1\xc3<\xd5h\x89\x14Jt\xba\u07e4\xb6\x00\x00\u07d4\x92b\t\xb7\xfd\xa5N\x8d\u06dd\x9eM=\x19\xeb\u070e\x88\u009f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92h\xd6&FV6\x11\xdc;\x83*0\xaa#\x94\xc6F\x13\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92i\x8e4Sx\xc6-\x8e\xda\x18M\x946j\x14K\f\x10[\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x92y:\u0173rhwJq0\xde+\xbd3\x04\x05f\x17s\x89\x02,\xa3X|\xf4\xeb\x00\x00\xe0\x94\x92y\xb2\"\x8c\xec\x8f{M\xda?2\x0e\x9a\x04f\xc2\xf5\x85\u028a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x92|\xb7\xdc\x18p6\xb5B{\xc7\xe2\x00\xc5\xecE\f\x1d'\u0509\v\xb5\x9a'\x95<`\x00\x00\u07d4\x92|\u00bf\xda\x0e\b\x8d\x02\xef\xf7\v8\xb0\x8a\xa5<\xc3\tA\x89do`\xa1\xf9\x866\x00\x00\xe0\x94\x92\x84\xf9m\xdbG\xb5\x18n\xe5X\xaa12M\xf56\x1c\x0fs\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x92\x9d6\x8e\xb4j-\x1f\xbd\xc8\xff\xa0`~\xdeK\xa8\x8fY\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xa7\u0166Cb\xe9\xf8B\xa2=\xec\xa2\x105\x85\u007f\x88\x98\x00\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x92\xa8\x98\xd4o\x19q\x9c8\x12j\x8a<'\x86z\xe2\xce\u5589lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xa9q\xa79y\x9f\x8c\xb4\x8e\xa8G]r\xb2\xd2GAr\xe6\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x92\xaa\xe5\x97h\xed\xdf\xf8<\xfe`\xbbQ.s\n\x05\xa1a\u05c9\\\x97xA\fv\u0440\x00\u07d4\x92\xad\x1b=u\xfb\xa6}Tf=\xa9\xfc\x84\x8a\x8a\xde\x10\xfag\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xae[|~\xb4\x92\xff\x1f\xfa\x16\xddB\xad\x9c\xad@\xb7\xf8\u0709.\xe4IU\b\x98\xe4\x00\x00\u07d4\x92\xc0\xf5s\xec\xcfb\xc5H\x10\xeek\xa8\xd1\xf1\x13T+0\x1b\x89\xb7ro\x16\u0331\xe0\x00\x00\u07d4\x92\xc1?\xe0\xd6\u0387\xfdP\xe0=\uf7e6@\x05\t\xbdps\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x92\xc9L( \xdf\xcfqV\xe6\xf10\x88\xec\u754b6v\xfd\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4\x92\xcf\xd6\x01\x88\xef\u07f2\xf8\xc2\xe7\xb1i\x8a\xbb\x95&\xc1Q\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\u062d\x9aMah;\x80\u0526g.\x84\xc2\rbB\x1e\x80\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x92\u0725\xe1\x02\xb3\xb8\x1b`\xf1\xa5\x04cIG\xc3t\xa8\x8c\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xe454\x0e\x9d%<\x00%c\x89\xf5+\x06}U\x97Nv\x89\x0e\x87?D\x13<\xb0\x00\x00\xe0\x94\x92\xe49(\x16\xe5\xf2\xef_\xb6X7\xce\xc2\xc22\\\xc6I\"\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x92\xe6X\x1e\x1d\xa1\xf9\xb8F\xe0\x93G3=\xc8\x18\xe2\u04acf\x89\xc5S%\xcat\x15\xe0\x00\x00\u07d4\x93\x1d\xf3M\x12%\xbc\xd4\"Nch\r\\L\t\xbc\xe75\xa6\x89\x03\xaf\xb0\x87\xb8v\x90\x00\x00\u07d4\x93\x1f\xe7\x12\xf6B\a\xa2\xfdP\"r\x88CT\x8b\xfb\x8c\xbb\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x93#_4\r(c\xe1\x8d/LR\x99e\x16\x13\x8d\"\x02g\x89\x04\x00.D\xfd\xa7\xd4\x00\x00\u07d4\x93%\x82U\xb3|\u007fX\xf4\xb1\x06s\xa92\xdd:\xfd\x90\xf4\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x93(\xd5\\\xcb?\xceS\x1f\x19\x93\x823\x9f\x0eWn\xe8@\xa3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x93)\xff\xdc&\x8b\xab\u0788t\xb3f@l\x81D[\x9b-5\x89\x16\xe6/\x8cs\f\xa1\x80\x00\u07d4\x93+\x9c\x04\xd4\r*\xc80\x83\xd9B\x98\x16\x9d\xae\x81\xab.\u0409lk\x93[\x8b\xbd@\x00\x00\u07d4\x9346\xc8G&U\xf6L:\xfa\xaf|Lb\x1c\x83\xa6+8\x8965\u026d\xc5\u07a0\x00\x00\u0794\x93;\xf3?\x82\x99p+:\x90&B\xc3>\v\xfa\xea\\\x1c\xa3\x88\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x93@4\\\xa6\xa3\uaf77sc\xf2X`C\xf2\x948\xce\v\x89\x1c\xc8\x05\xda\r\xff\xf1\x00\x00\xe0\x94\x93@\xb5\xf6x\xe4^\xe0^\xb7\b\xbbz\xbbn\xc8\xf0\x8f\x1bk\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x93J\xf2\x1b~\xbf\xa4g\xe2\xce\xd6Z\xa3N\xdd:\x0e\xc7\x132\x8a\a\x80\x1f>\x80\xcc\x0f\xf0\x00\x00\xe0\x94\x93PiDJj\x98M\xe2\bNFi*\xb9\x9fg\x1f\xc7'\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\xe0\x94\x93P~\x9e\x81\x19\xcb\xce\u068a\xb0\x87\xe7\xec\xb0q8=i\x81\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x93g\x8a\x00\x00\xe0\x94\x93m\xcf\x00\x01\x94\xe3\xbf\xf5\n\u0174$:;\xa0\x14\xd6a\u060a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x93o8\x13\xf5\xf6\xa1;\x8eO\xfe\xc8?\xe7\xf8&\x18jq\u0349\x1c0s\x1c\xec\x03 \x00\x00\u07d4\x93t\x86\x9dJ\x99\x11\xee\x1e\xafU\x8b\xc4\u00b6>\xc6:\xcf\u074965\u026d\xc5\u07a0\x00\x00\u07d4\x93uc\u0628\x0f\u05657\xb0\xe6m \xa0%%\xd5\u0606`\x89\x87\x86x2n\xac\x90\x00\x00\u07d4\x93v\xdc\xe2\xaf.\xc8\xdc\xdat\x1b~sEfF\x81\xd96h\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x93\x86\x8d\xdb*yM\x02\xeb\xda/\xa4\x80|v\xe3`\x98X\u0709m\xee\x15\xfc|$\xa7\x80\x00\xe0\x94\x93\x9cC\x13\xd2(\x0e\xdf^\a\x1b\xce\xd8F\x06?\n\x97]T\x8a\x19i6\x89t\xc0[\x00\x00\x00\xe0\x94\x93\xa6\xb3\xabB0\x10\xf9\x81\xa7H\x9dJ\xad%\xe2b\\WA\x8a\x04F\x80\xfej\x1e\xdeN\x80\x00\u07d4\x93\xaa\x8f\x92\xeb\xff\xf9\x91\xfc\x05^\x90ne\x1a\xc7h\xd3+\u02092\xf5\x1e\u06ea\xa30\x00\x00\u07d4\x93\xb4\xbf?\xdf\xf6\xde?NV\xbamw\x99\xdcK\x93\xa6T\x8f\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4\x93\xbc}\x9aJ\xbdD\u023b\xb8\xfe\x8b\xa8\x04\xc6\x1a\xd8\xd6Wl\x89\xd8\xd6\x11\x9a\x81F\x05\x00\x00\u07d4\x93\xc2\xe6N]\xe5X\x9e\xd2P\x06\xe8C\x19n\xe9\xb1\xcf\v>\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\x93\u020e-\x88b\x1e0\xf5\x8a\x95\x86\xbe\xd4\t\x89\x99\xebg\u074a\x06\x9bZ\xfa\xc7P\xbb\x80\x00\x00\u07d4\x93\xe0\xf3~\xcd\xfb\x00\x86\xe3\xe8b\xa9p4D{\x1eM\xec\x1a\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\xe0\x94\x93\xe3\x03A\x1a\xfa\xf6\xc1\a\xa4A\x01\u026c[6\xe9\xd6S\x8b\x8a\r\xf9\xdd\xfe\xcd\x03e@\x00\x00\u07d4\x93\xf1\x8c\xd2R`@v\x14\x88\xc5\x13\x17M\x1eycv\x8b,\x89\x82\xff\xac\x9a\u0553r\x00\x00\u07d4\x94\x0fqQ@P\x9f\xfa\xbf\x97EF\xfa\xb3\x90\"\xa4\x19R\u0489K\xe4\xe7&{j\xe0\x00\x00\u07d4\x94,k\x8c\x95[\xc0\u0608\x12g\x8a#g%\xb3'9\xd9G\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\x94=7\x86JJS}5\xc8\u0657#\xcdd\x06\xce%b\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94C\x9c\xa9\xcc\x16\x9ay\u0520\x9c\xae^gvJo\x87\x1a!\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x94D\x9c\x01\xb3*\u007f\xa5Z\xf8\x10OB\xcd\xd8D\xaa\x8c\xbc@\x8a\x03\x81\x11\xa1\xf4\xf0<\x10\x00\x00\xe0\x94\x94E\xba\\0\xe9\x89a\xb8`$a\xd08]@\xfb\xd8\x03\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x94O\a\xb9o\x90\xc5\xf0\xd7\xc0\u0140S1I\xf3\xf5\x85\xa0x\x89\x04\x02\xf4\xcf\xeeb\xe8\x00\x00\u07d4\x94T\xb3\xa8\xbf\xf9p\x9f\xd0\u1407~l\xb6\u0219t\xdb\u0589\x90\xf54`\x8ar\x88\x00\x00\u07d4\x94]\x96\xeaW>\x8d\xf7&+\xbf\xa5r\"\x9bK\x16\x01k\x0f\x89\vX\x9e\xf9\x14\xc1B\x00\x00\u07d4\x94^\x18v\x9d~\xe7'\xc7\x01?\x92\xde$\xd1\x17\x96\u007f\xf3\x17\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94a'\x81\x03;W\xb1F\xeet\xe7S\xc6r\x01\u007fS\x85\xe4\x89\xc3(\t>a\xee@\x00\x00\xe0\x94\x94dJ\xd1\x16\xa4\x1c\xe2\xca\u007f\xbe\xc6\t\xbd\xefs\x8a*\xc7\u01ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x94p\xcc6YE\x86\x82\x18!\xc5\u0256\xb6\xed\xc8;mZ2\x89\x01M\x11 \u05f1`\x00\x00\xe0\x94\x94u\xc5\x10\xec\x9a&\x97\x92GtL=\x8c;\x0e\v_D\u04ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x94~\x11\xe5\xea)\ro\u00f3\x80H\x97\x9e\f\xd4N\xc7\xc1\u007f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94\x83\u064f\x14\xa3?\xdc\x11\x8d@9U\u00995\xed\xfc_p\x89\x18\xea;4\xefQ\x88\x00\x00\u07d4\x94\x911\xf2\x89C\x92\\\xfc\x97\xd4\x1e\f\xea\v&)s\xa70\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\x94\x9f\x84\xf0\xb1\xd7\u0127\xcfI\xee\u007f\x8b,J\x13M\xe3(x\x89%\"H\u07b6\xe6\x94\x00\x00\u07d4\x94\x9f\x8c\x10{\xc7\xf0\xac\xea\xa0\xf1pR\xaa\xdb\xd2\xf9s+.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94\xa7\u0368\xf4\x81\xf9\u061dB\xc3\x03\xae\x162\xb3\xb7\t\xdb\x1d\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x94\xa9\xa7\x16\x911| d'\x1bQ\xc95?\xbd\xed5\x01\xa8\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x94\xadK\xad\x82K\xd0\ub7a4\x9cX\u03bc\xc0\xff^\b4k\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x94\xbb\xc6}\x13\xf8\x9e\xbc\xa5\x94\xbe\x94\xbcQp\x92\f0\xd9\xf3\x89\x04X\xff\xa3\x15\nT\x00\x00\u07d4\x94\xbe:\xe5Ob\xd6c\xb0\xd4\u031e\x1e\xa8\xfe\x95V\ua7bf\x89\x01C\x13,\xa8C\x18\x00\x00\xe0\x94\x94\xc0U\xe8X5z\xaa0\xcf A\xfa\x90Y\xce\x16J\x1f\x91\x8a\x04<%\xe0\xdc\xc1\xbd\x1c\x00\x00\xe0\x94\x94\xc7B\xfdz\x8by\x06\xb3\xbf\xe4\xf8\x90O\xc0\xbe\\v\x803\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x94\xcaV\xdew\u007f\xd4S\x17\u007f^\x06\x94\xc4x\xe6j\xff\x8a\x84\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x94\xd8\x10t\xdbZ\xe1\x97\u04bb\x13s\xab\x80\xa8}\x12\x1cK\u04ca\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x94\u06c0xs\x86\n\xac=Z\xea\x1e\x88^R\xbf\xf2\x86\x99T\x89\xae\x8ez\v\xb5u\xd0\x00\x00\u07d4\x94\xe1\xf5\u02db\x8a\xba\xce\x03\xa1\xa6B\x82VU;i\f#U\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x94\xef\x8b\xe4Pw\xc7\xd4\xc5e'@\u0794jbbOq?\x89\x05l\xf5Y:\x18\xf8\x80\x00\u07d4\x94\xf1?\x9f\b6\xa3\xee$7\xa8I\"\u0498M\xc0\xf7\xd5;\x89\xa2\xa02\x9b\u00ca\xbe\x00\x00\u07d4\x94\xf8\xf0W\xdb~`\xe6u\xad\x94\x0f\x15X\x85\u0464w4\x8e\x89\x15\xbeat\xe1\x91.\x00\x00\xe0\x94\x94\xfc\u03ad\xfe\\\x10\x9c^\xae\xafF-C\x871B\u020e\"\x8a\x01\x045a\xa8\x82\x93\x00\x00\x00\u07d4\x95\x03N\x16!\x86Q7\xcdG9\xb3F\xdc\x17\xda:'\xc3N\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\x95\fh\xa4\t\x88\x15M#\x93\xff\xf8\xda|\u0369\x96\x14\xf7,\x89\xf9AF\xfd\x8d\xcd\xe5\x80\x00\xe0\x94\x95\x0f\xe9\xc6\xca\xd5\f\x18\xf1\x1a\x9e\xd9\xc4W@\xa6\x18\x06\x12\u040a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x95!\x83\xcf\u04ce5.W\x9d6\xde\xce\u0171\x84P\xf7\xfb\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95'\x8b\b\xde\xe7\xc0\xf2\xc8\xc0\xf7\"\xf9\xfc\xbb\xb9\xa5$\x1f\u0689\x82\x93\t\xf6O\r\xb0\x00\x00\u07d4\x95,W\xd2\xfb\x19Q\a\xd4\xcd\\\xa3\x00wA\x19\u07ed/x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x955r\xf0\xeam\xf9\xb1\x97\xca\xe4\x0eK\x8e\xcc\x05lCq\u014965\u026d\xc5\u07a0\x00\x00\u07d4\x95>\xf6R\xe7\xb7i\xf5=nxjX\x95/\xa9>\xe6\xab\u725b\ny\x1f\x12\x110\x00\x00\u07d4\x95DpF1;/:^\x19\xb9H\xfd;\x8b\xed\xc8,q|\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x95]\xb3\xb7C`\xb9\xa2hg~s\u03a8!f\x8a\xf6\xfa\u038a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\x95`\xe8\xacg\x18\xa6\xa1\xcd\xcf\xf1\x89\xd6\x03\xc9\x06>A=\xa6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x95g\xa0\u0781\x1d\xe6\xff\t[~\xe6N\u007f\x1b\x83\xc2a[\x80\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x95h\x1c\xda\xe6\x9b I\xce\x10\x1e2\\u\x98\x92\xca\xc3\xf8\x11\x89\x9a\xe9*\x9b\xc9L@\x00\x00\xe0\x94\x95h\xb7\xdeuV(\xaf5\x9a\x84T=\xe25\x04\xe1^A\xe6\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x95i\xc6:\x92\x84\xa8\x05bm\xb3\xa3.\x9d#c\x93GaQ\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x95\x80\x9e\x8d\xa3\xfb\xe4\xb7\xf2\x81\xf0\xb8\xb1q_B\x0f}}c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95\x9fW\xfd\xedj\xe3y\x13\xd9\x00\xb8\x1e_H\xa7\x93\"\xc6'\x89\r\xdb&\x10GI\x11\x80\x00\u07d4\x95\x9f\xf1\u007f\x1dQ\xb4s\xb4@\x10\x05'U\xa7\xfa\x8cu\xbdT\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x95\xa5w\xdc.\xb3\xael\xb9\xdf\xc7z\xf6\x97\xd7\xef\xdf\xe8\x9a\x01\x89\a_a\x0fp\xed \x00\x00\u07d4\x95\xcbm\x8acy\xf9J\xba\x8b\x88ViV,MD\x8eV\xa7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95\xd5PB{ZQLu\x1ds\xa0\xf6\u049f\xb6]\"\xed\x10\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x95\u064d\f\x10i\x90\x8f\x06zR\xac\xac+\x8bSM\xa3z\xfd\x89oY\xb60\xa9)p\x80\x00\xe0\x94\x95\xdfN4E\xd7f&$\u010e\xbat\u03de\nS\xe9\xf72\x8a\v\xdb\xc4\x1e\x03H\xb3\x00\x00\x00\u07d4\x95\xe6\xa5K-_g\xa2JHu\xafu\x10|\xa7\xea\x9f\xd2\xfa\x89Hz\x9a0E9D\x00\x00\xe0\x94\x95\xe6\xf9=\xac\"\x8b\xc7XZ%sZ\xc2\xd0v\xcc:@\x17\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x95\xe7ad$\xcd\ta\xa7\x17'$t7\xf0\x06\x92r(\x0e\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x95\xe8\n\x82\xc2\f\xbe= `$,\xb9-sX\x10\xd04\xa2\x89\x01\xc3.F?\u0539\x80\x00\u07d4\x95\xf6-\x02C\xed\xe6\x1d\xad\x9a1e\xf59\x05'\rT\xe2B\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\x95\xfbZ\xfb\x14\xc1\uf6b7\xd1y\xc5\xc3\x00P?\xd6j^\xe2\x89\x01\xda\xf7\xa0+\r\xbe\x80\x00\u07d4\x96\x10Y\"\x02\u0082\xab\x9b\u0628\x84Q\x8b>\v\xd4u\x817\x89\x0e\x87?D\x13<\xb0\x00\x00\xe0\x94\x96\x1cY\xad\xc7E\x05\u0446M\x1e\xcf\u02ca\xfa\x04\x12Y<\x93\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x96,\r\xec\x8a=FK\xf3\x9b\x12\x15\xea\xfd&H\n\xe4\x90\u0349l\x82\xe3\xea\xa5\x13\xe8\x00\x00\u07d4\x96,\xd2*\x8e\xdf\x1eONU\xb4\xb1]\xdb\xfb]\x9dT\x19q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x963K\xfe\x04\xff\xfaY\x02\x13\xea\xb3e\x14\xf38\xb8d\xb76\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x967\xdc\x12r=\x9cxX\x85B\uac02fO?\x03\x8d\x9d\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x96N\xabK'kL\u0618>\x15\xcar\xb1\x06\x90\x0f\xe4\x1f\u0389\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x96b\xee\x02\x19&h+1\xc5\xf2\x00\xceEz\xbe\xa7ll\xe9\x89$Y\x0e\x85\x89\xebj\x00\x00\xe0\x94\x96l\x04x\x1c\xb5\xe6}\xde25\xd7\xf8b\x0e\x1a\xb6c\xa9\xa5\x8a\x10\r P\xdacQ`\x00\x00\u07d4\x96pv\xa8w\xb1\x8e\xc1ZA[\xb1\x16\xf0n\xf3&E\u06e3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96{\xfa\xf7bC\u0379@\t\xae<\x8d5\x05\xe9\xc0\x80EK\xe0\xe8\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x96\x92A\x91\xb7\xdfe[3\x19\xdcma7\xf4\x81\xa7:\x0f\xf3\x89\xd9\xec\xb4\xfd \x8eP\x00\x00\u07d4\x96\x96\x05!83\x8cr/\x11@\x81\\\xf7t\x9d\r;:t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x96\xa5_\x00\xdf\xf4\x05\xdcM\xe5\xe5\x8cW\xf6\xf6\xf0\xca\xc5]/\x89jf\x167\x9c\x87\xb5\x80\x00\u07d4\x96\xaaW?\xed/#4\x10\u06eeQ\x80\x14[#\xc3\x1a\x02\xf0\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x96\xadW\x9b\xbf\xa8\u06ce\xbe\xc9\u0486\xa7.Fa\xee\xd8\xe3V\x89:\v\xa4+\xeca\x83\x00\x00\u07d4\x96\xb44\xfe\x06W\xe4*\u0302\x12\xb6\x86Q9\xde\xde\x15\x97\x9c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x96\xb9\x06\xear\x9fFU\xaf\xe3\xe5}5'|\x96}\xfa\x15w\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x96\xd6-\xfdF\b\u007fb@\x9d\x93\xdd`a\x88\xe7\x0e8\x12W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96\xd9\u0328\xf5^\xea\x00@\xecn\xb3H\xa1wK\x95\xd9>\xf4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x96\xe7\xc0\xc9\u057f\x10\x82\x1b\xf1@\xc5X\xa1E\xb7\xca\xc2\x13\x97\x899>\xf1\xa5\x12|\x80\x00\x00\u07d4\x96\xeaj\u021a+\xac\x954{Q\u06e6=\x8b\xd5\xeb\xde\xdc\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96\xea\xfb\xf2\xfboM\xb9\xa46\xa7LE\xb5eDR\xe28\x19\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x96\xebR>\x83/P\n\x01}\xe1>\xc2\u007f]6lV\x0e\xff\x89\x10\xac\u03baC\xee(\x00\x00\u07d4\x96\xf0F*\xe6\xf8\xb9`\x88\xf7\xe9\u018ct\xb9\u062d4\xb3G\x89a\t=|,m8\x00\x00\u07d4\x96\xf8 P\vp\xf4\xa3\xe3#\x9da\x9c\xff\x8f\" u\xb15\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x96\xfeY\xc3\u06f3\xaa|\xc8\xcbbH\fe\xe5nb\x04\xa7\xe2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x96\xffoP\x99h\xf3l\xb4,\xbaH\xdb2\xf2\x1fVv\xab\xf8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x97\t8R*\xfb^\x8f\x99Hs\xc9\xfb\xdc&\xe3\xb3~1L\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x97\n\xbdS\xa5O\xcaJd) |\x18-MW\xbb9\u0520\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97\r\x8b\x8a\x00\x16\xd1C\x05O\x14\x9f\xb3\xb8\xe5P\xdc\a\x97\u01c965\u026d\xc5\u07a0\x00\x00\u07d4\x97,/\x96\xaa\x00\u03ca/ Z\xbc\xf8\x93|\fu\xf5\xd8\u0649\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97?N6\x1f\xe5\xde\u0358\x9dL\x8f}|\xc9y\x908]\xaf\x89\x15\x0f\x85C\xa3\x87B\x00\x00\u07d4\x97M\x05A\xabJG\xec\u007fu6\x9c\x00i\xb6J\x1b\x81w\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u0794\x97M/\x17\x89_)\x02\x04\x9d\xea\xae\xcf\t\xc3\x04e\a@-\x88\xcc\x19\u00947\xab\x80\x00\u07d4\x97R\xd1O^\x10\x93\xf0qq\x1c\x1a\xdb\xc4\xe3\xeb\x1e\\W\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97V\xe1v\xc9\xefi>\xe1\xee\u01b9\xf8\xb1Q\xd3\x13\xbe\xb0\x99\x89A\rXj \xa4\xc0\x00\x00\u07d4\x97_7d\xe9{\xbc\xcfv|\xbd;y[\xa8m\x8b\xa9\x84\x0e\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\x97j\x18Sj\xf4\x18tBc\b\x87\x1b\xcd\x15\x12\xa7u\xc9\xf8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x97n<\xea\xf3\xf1\xafQ\xf8\u009a\xff]\u007f\xa2\x1f\x03\x86\xd8\xee\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x97w\xcca\xcfuk\xe3\xb3\xc2\f\xd4I\x1ci\xd2u\xe7\xa1 \x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x97\x81\v\xaf\xc3~\x840c2\xaa\xcb5\xe9*\xd9\x11\xd2=$\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x97\x8cC\f\xe45\x9b\x06\xbc,\xdf\\)\x85\xfc\x95\x0eP\xd5\u0209\x1a\x05V\x90\xd9\u06c0\x00\x00\u07d4\x97\x95\xf6C\x19\xfc\x17\xdd\x0f\x82a\xf9\xd2\x06\xfbf\xb6L\xd0\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97\x99\xca!\xdb\xcfi\xbf\xa1\xb3\xf7+\xacQ\xb9\xe3\xcaX|\xf9\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x97\x9c\xbf!\xdf\xec\x8a\xce?\x1c\x19m\x82\u07d6%4\xdf9O\x89\x99\x91\xd4x\xddM\x16\x00\x00\u07d4\x97\x9dh\x1ca}\xa1o!\xbc\xac\xa1\x01\xed\x16\xed\x01Z\xb6\x96\x89e\xea=\xb7UF`\x00\x00\u07d4\x97\x9f0\x15\x8bWK\x99\x9a\xab4\x81\a\xb9\xee\xd8[\x1f\xf8\xc1\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x97\xa8o\x01\xce?|\xfdDA3\x0e\x1c\x9b\x19\xe1\xb1\x06\x06\xef\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x97\xb9\x1e\xfesP\xc2\xd5~~@k\xab\x18\xf3a{\xcd\xe1J\x8a\x02\x1e\x19\x99\xbb\xd5\u04be\x00\x00\u07d4\x97\xd0\xd9r^;p\xe6u\x841s\x93\x8e\xd3q\xb6,\u007f\xac\x89\t79SM(h\x00\x00\u07d4\x97\xd9\xe4jv\x04\u05f5\xa4\xeaN\xe6\x1aB\xb3\xd25\x0f\xc3\xed\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97\xdc&\xecg\n1\xe0\"\x1d*u\xbc]\xc9\xf9\f\x1fo\u0509\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x97\xde!\xe4!\xc3\u007f\xe4\xb8\x02_\x9aQ\xb7\xb3\x90\xb5\xdfx\x04\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\x97\xe2\x89s\xb8`\xc5g@(\x00\xfb\xb6<\xe3\x9a\x04\x8a=y\x89\x05B%:\x12l\xe4\x00\x00\u07d4\x97\xe5\xcca'\xc4\xf8\x85\xbe\x02\xf4KB\xd1\u0230\xac\x91\u44c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97\xf1\xfeL\x80\x83\xe5\x96!*\x18w(\xdd\\\xf8\n1\xbe\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x97\xf7v\x06W\xc1\xe2\x02u\x90\x86\x96>\xb4!\x1c_\x819\xb9\x8a\n\x8a\t\u007f\xcb=\x17h\x00\x00\xe0\x94\x97\xf9\x9bk\xa3\x13F\u0358\xa9\xfeL0\x8f\x87\u0165\x8cQQ\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x98\n\x84\xb6\x86\xfc1\xbd\xc8<\"\x10XTjq\xb1\x1f\x83\x8a\x89*AUH\xaf\x86\x81\x80\x00\u07d4\x98\x10\xe3J\x94\xdbn\xd1V\xd08\x9a\x0e+\x80\xf4\xfdk\n\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\x1d\xdf\x04\x04\xe4\xd2-\xdaUj\a&\xf0\v-\x98\xab\x95i\x8965f3\xeb\xd8\xea\x00\x00\xe0\x94\x98\x1fq'u\xc0\xda\xd9u\x18\xff\xed\xcbG\xb9\xad\x1dl'b\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\x984h!\x80\xb9\x82\xd1f\xba\u06dd\x9d\x1d\x9b\xbf\x01m\x87\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x986\xb4\xd3\x04sd\x1a\xb5j\xee\xe1\x92Bv\x1drrQx\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x989sB\xec_=L\xb8w\xe5N\xf5\xd6\xf1\xd3fs\x1b\u050a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\x98Fd\x886\xa3\a\xa0W\x18O\xd5\x1fb\x8a_\x8c\x12B|\x8a\x04\vi\xbfC\xdc\xe8\xf0\x00\x00\xe0\x94\x98Jy\x85\xe3\xcc~\xb5\xc96\x91\xf6\xf8\xcc{\x8f$]\x01\xb2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x98]p\xd2\a\x89+\xed9\x85\x90\x02N$!\xb1\xcc\x11\x93Y\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x98m\xf4~v\xe4\u05e7\x89\xcd\xee\x91<\u0243\x16P\x93l\x9d\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x98t\x80?\xe1\xf3\xa06^y\"\xb1Bp\xea\xeb\x03,\xc1\xb5\x89<\xf5\x92\x88$\xc6\xc2\x00\x00\u07d4\x98ub4\x95\xa4l\xdb\xf2YS\x0f\xf88\xa1y\x9e\u00c9\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98v\x18\xc8VV |{\xac\x15\a\xc0\xff\xef\xa2\xfbd\xb0\x92\x89\x03}\xfeC1\x89\xe3\x80\x00\u07d4\x98|\x9b\xcdn?9\x90\xa5+\xe3\xed\xa4q\f'Q\x8fOr\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x98\x82\x96|\xeeh\u04a89\xfa\u062bJ|=\xdd\xf6\xc0\xad\u0209Hx\xbe\x1f\xfa\xf9]\x00\x00\u07d4\x98\x85\\}\xfb\xee3SD\x90J\x12\xc4\fs\x17\x95\xb1:T\x899\xfb\xae\x8d\x04-\xd0\x00\x00\u07d4\x98\x9c\f\xcf\xf6T\xda\x03\xae\xb1\x1a\xf7\x01\x05Ea\xd6)~\x1d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x98\xa0\xe5Lm\x9d\u023e\x96'l\xeb\xf4\xfe\xc4`\xf6#]\x85\x89j\u0202\x10\tR\u01c0\x00\u07d4\x98\xb7i\xcc0\\\xec\xfbb\x9a\x00\xc9\a\x06\x9d~\xf9\xbc:\x12\x89\x01h\u048e?\x00(\x00\x00\xe0\x94\x98\xbaN\x9c\xa7/\xdd\xc2\fi\xb49ov\xf8\x18?z*N\x8a\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\x00\u07d4\x98\xbeimQ\xe3\x90\xff\x1cP\x1b\x8a\x0fc1\xb6(\xdd\u016d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\xbe\u04e7.\xcc\xfb\xaf\xb9#H\x92\x93\xe4)\xe7\x03\xc7\xe2[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\xbfJ\xf3\x81\v\x84#\x87\xdbp\xc1MF\t\x96&\x00=\x10\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x98\xc1\x0e\xbf,O\x97\u02e5\xa1\xab?*\xaf\xe1\xca\xc4#\xf8\u02c9\x10CV\x1a\x88)0\x00\x00\u07d4\x98\xc1\x9d\xba\x81\v\xa6\x11\xe6\x8f/\x83\xee\x16\xf6\xe7tO\f\x1f\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x98\xc5IJ\x03\xac\x91\xa7h\xdf\xfc\x0e\xa1\xdd\u0b3f\x88\x90\x19\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\x98\xd2\x04\xf9\b_\x8c\x8e}\xe2>X\x9bd\xc6\xef\xf6\x92\xccc\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x98\xd3s\x19\x92\xd1\xd4\x0e\x12\x11\xc7\xf75\xf2\x18\x9a\xfa\a\x02\xe0\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x98\xe2\xb6\xd6\x06\xfd-i\x91\xc9\xd6\xd4\a\u007f\xdf?\xddE\x85\u06890\xdf\x1ao\x8a\xd6(\x00\x00\u07d4\x98\xe3\xe9\v(\xfc\xca\ue087y\xb8\xd4\nUh\xc4\x11n!\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x98\xe6\xf5G\u06c8\xe7_\x1f\x9c\x8a\xc2\xc5\xcf\x16'\xbaX\v>\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x98\xf4\xaf:\xf0\xae\xde_\xaf\xdcB\xa0\x81\xec\xc1\xf8\x9e<\xcf \x8a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x98\xf6\xb8\xe6!=\xbc\x9aU\x81\xf4\xcc\xe6e_\x95%+\xdb\a\x89\x11Xr\xb0\xbc\xa40\x00\x00\u07d4\x99\te\r\u05719{\x8b\x8b\x0e\xb6\x94\x99\xb2\x91\xb0\xad\x12\x13\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x99\x11s`\x19G\xc2\bJb\xd69R~\x96\x15\x12W\x9a\xf9\x89 \x86\xac5\x10R`\x00\x00\u07d4\x99\x12\x9d[<\f\xdeG\xea\r\xefM\xfc\a\r\x1fJY\x95'\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x99\x17\u058dJ\xf3A\xd6Q\xe7\xf0\a\\m\xe6\xd7\x14Nt\t\x8a\x012\xd4Gl\b\xe6\xf0\x00\x00\u07d4\x99\x1a\xc7\xcap\x97\x11_& ^\xee\x0e\xf7\xd4\x1e\xb4\xe3\x11\xae\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\x99#e\xd7d\xc5\xce5@9\xdd\xfc\x91.\x02:u\xb8\xe1h\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x99&F\xac\x1a\u02ab\xf5\u076b\xa8\xf9B\x9a\xa6\xa9Nt\x96\xa7\x8967Pz0\xab\xeb\x00\x00\u07d4\x99&\x83'\xc3s3.\x06\xc3\xf6\x16B\x87\xd4U\xb9\xd5\xfaK\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99(\xffqZ\xfc:+`\xf8\xebL\u013aN\xe8\u06b6\u5749\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4\x992\xef\x1c\x85\xb7Z\x9b*\x80\x05}P\x874\xc5\x10\x85\xbe\u0309\x02\xb8?\xa50\x1dY\x00\x00\xe0\x94\x99?\x14ax`^f\xd5\x17\xbex.\xf0\xb3\xc6\x1aN\x19%\x8a\x01|\x1f\x055\u05e5\x83\x00\x00\xe0\x94\x99A7\x04\xb1\xa3.p\xf3\xbc\ri\u0748\x1c8VkT\u02ca\x05\xcckiF1\xf7\x12\x00\x00\u07d4\x99AR\xfc\x95\xd5\xc1\u028b\x88\x11:\xbb\xadMq\x0e@\xde\xf6\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x99D\xfe\xe9\xd3JJ\x88\x00#\u01c92\xc0\vY\xd5\xc8*\x82\x89(\xa8\xa5k6\x90\a\x00\x00\u07d4\x99L\u00b5\"~\xc3\xcf\x04\x85\x12F|A\xb7\xb7\xb7H\x90\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99q\xdf`\xf0\xaef\xdc\xe9\xe8\xc8N\x17\x14\x9f\t\xf9\xc5/d\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x99v\x94~\xff_j\xe5\xda\b\xddT\x11\x92\xf3x\xb4(\xff\x94\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x99}e\x92\xa3\x15\x89\xac\xc3\x1b\x99\x01\xfb\xeb<\xc3\xd6[2\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\x82\xa5\x89\x0f\xfbT\x06\u04ec\xa8\u04bf\xc1\xddp\xaa\xa8\n\xe0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\x87\x8f\x9dn\n~\u066e\u01c2\x97\xb78y\xa8\x01\x95\xaf\xe0\x89\xd7\xc1\x98q\x0ef\xb0\x00\x00\u07d4\x99\x8c\x1f\x93\xbc\xdbo\xf2<\x10\xd0\u0712G(\xb7;\xe2\xff\x9f\x896[\xf3\xa43\xea\xf3\x00\x00\u07d4\x99\x91aL[\xaaG\xddl\x96\x87FE\xf9z\xdd,=\x83\x80\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x99\x92J\x98\x16\xbb}\xdf?\xec\x18D\x82\x8e\x9a\xd7\xd0k\xf4\xe6\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x99\x99vh\xf7\xc1\xa4\xff\x9e1\xf9\x97z\xe3\"K\u02c8z\x85\x89\x0f\xc969(\x01\xc0\x00\x00\u07d4\x99\x9cI\xc1t\xca\x13\xbc\x83l\x1e\n\x92\xbf\xf4\x8b'\x15C\u0289\xb1\xcf$\xdd\u0431@\x00\x00\u07d4\x99\xa4\xde\x19\xde\u05d0\b\xcf\xdc\xd4]\x01M.XK\x89\x14\xa8\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x99\xa9k\xf2$.\xa1\xb3\x9e\xceo\xcc\r\x18\xae\xd0\f\x01y\xf3\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x99\xb0\x18\x93+\xca\xd3U\xb6y+%]\xb6p-\xec\x8c\xe5\u0749\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x99\xb7C\xd1\xd9\xef\xf9\r\x9a\x194\xb4\xdb!\xd5\x19\u061bJ8\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x99\xb8\xc8$\x86\x9d\xe9\xed$\xf3\xbf\xf6\x85L\xb6\xddE\xcc?\x9f\x89e\xea=\xb7UF`\x00\x00\u07d4\x99\xc0\x17L\xf8N\a\x83\xc2 \xb4\xebj\xe1\x8f\xe7\x03\x85J\u04c9py\xa2W=\fx\x00\x00\u07d4\x99\xc1\xd9\xf4\fj\xb7\xf8\xa9/\xce/\xdc\xe4zT\xa5\x86\xc5?\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x99\xc26\x14\x1d\xae\xc87\xec\xe0O\xda\xee\x1d\x90\u03cb\xbd\xc1\x04\x89ve\x16\xac\xac\r \x00\x00\u07d4\x99\xc3\x1f\xe7HX7\x87\xcd\xd3\xe5%\xb2\x81\xb2\x18\x96\x179\xe3\x897\b\xba\xed=h\x90\x00\x00\u07d4\x99\xc4u\xbf\x02\xe8\xb9!J\xda_\xad\x02\xfd\xfd\x15\xba6\\\f\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\x99\u0203%\x85F\xcc~N\x97\x1fR.8\x99\x18\xda^\xa6:\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x99\xc9\xf9>E\xfe<\x14\x18\xc3S\xe4\u016c8\x94\xee\xf8\x12\x1e\x89\x05\x85\xba\xf1E\x05\v\x00\x00\xe0\x94\x99\xd1W\x9c\xd4&\x82\xb7dN\x1dOq(D\x1e\xef\xfe3\x9d\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x99\u0475\x85\x96_@jB\xa4\x9a\x1c\xa7\x0fv\x9evZ?\x98\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\x99\xdf\xd0PL\x06\xc7C\xe4e4\xfd{U\xf1\xf9\xc7\xec3)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\xf4\x14|\xcck\u02c0\u0304.i\xf6\xd0\x0e0\xfaA3\u0649\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x99\xf7\u007f\x99\x8b \xe0\xbc\xdc\xd9\xfc\x83\x86ARl\xf2Y\x18\xef\x89a\t=|,m8\x00\x00\u07d4\x99\xfa\xd5\x008\xd0\xd9\xd4\xc3\xfb\xb4\xbc\xe0V\x06\xec\xad\xcdQ!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\xfe\r \x12(\xa7S\x14VU\xd4(\xeb\x9f\xd9I\x85\xd3m\x89i \xbf\xf3QZ:\x00\x00\u07d4\x9a\a\x9c\x92\xa6)\xca\x15\xc8\xca\xfa.\xb2\x8d[\xc1z\xf8(\x11\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9a\r<\xee=\x98\x92\xea;7\x00\xa2\u007f\xf8A@\xd9\x02T\x93\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x9a$\u038dH\\\xc4\xc8nI\u07b3\x90\"\xf9,t0\xe6~\x89Fy\x1f\xc8N\a\xd0\x00\x00\u07d4\x9a,\xe4;]\x89\u0593k\x8e\x8c5G\x91\xb8\xaf\xff\x96$%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9a9\x01bS^9\x88w\xe4\x16x}b9\xe0uN\x93|\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9a=\xa6P#\xa10 \xd2!E\xcf\xc1\x8b\xab\x10\xbd\x19\xceN\x89\x18\xbfn\xa3FJ:\x00\x00\xe0\x94\x9a>+\x1b\xf3F\xdd\a\v\x02sW\xfe\xacD\xa4\xb2\xc9}\xb8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9aL\xa8\xb8!\x17\x89NC\xdbr\xb9\xfax\xf0\xb9\xb9:\xce\t\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x9aR.R\xc1\x95\xbf\xb7\xcf_\xfa\xae\u06d1\xa3\xbath\x16\x1d\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9aZ\xf3\x1c~\x063\x9a\u0234b\x8d|M\xb0\xce\x0fE\u0224\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\x9ac?\xcd\x11,\xce\xebv_\xe0A\x81ps*\x97\x05\u7708\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x9ac\u0445\xa7\x91)\xfd\xab\x19\xb5\x8b\xb61\xea6\xa4 TN\x89\x02F\xdd\xf9yvh\x00\x00\u07d4\x9ag\b\u0778\x90<(\x9f\x83\xfe\x88\x9c\x1e\xdc\xd6\x1f\x85D#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9ao\xf5\xf6\xa7\xaf{z\xe0\xed\x9c \xec\xecP#\u0481\xb7\x86\x89\x8a\x12\xb9\xbdjg\xec\x00\x00\xe0\x94\x9a\x82\x82m<)H\x1d\xcc+\u0495\x00G\xe8\xb6\x04\x86\xc38\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9a\x8e\xcaA\x89\xffJ\xa8\xff~\u0536\xb7\x03\x9f\t\x02!\x9b\x15\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9a\x95;[\xccp\x93y\xfc\xb5Y\u05f9\x16\xaf\u06a5\f\xad\u0309\x05k\xc7^-c\x10\x00\x00\u07d4\x9a\x99\v\x8a\xebX\x8d~\xe7\xec.\xd8\xc2\xe6Os\x82\xa9\xfe\xe2\x89\x01\xd1'\xdbi\xfd\x8b\x00\x00\u07d4\x9a\x9d\x1d\xc0\xba\xa7}n \xc3\xd8I\u01c8b\xdd\x1c\x05L\x87\x89/\xb4t\t\x8fg\xc0\x00\x00\xe0\x94\x9a\xa4\x8cf\xe4\xfbJ\u0419\x93N2\x02.\x82t'\xf2w\xba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9a\xa80\x8fB\x91\x0eZ\xde\t\xc1\xa5\xe2\x82\xd6\xd9\x17\x10\xbd\xbf\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9a\xaa\xfa\x00gd~\u0659\x06kzL\xa5\xb4\xb3\xf3\xfe\xaao\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9a\xb9\x88\xb5\x05\xcf\xee\x1d\xbe\x9c\u044e\x9bTs\xb9\xa2\xd4\xf56\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\x9a\xb9\x8dm\xbb\x1e\xaa\xe1mE\xa0EhT\x1a\xd3\xd8\xfe\x06\u0309\x0e\xc5\x04d\xfe#\xf3\x80\x00\xe0\x94\x9a\xba+^'\xffx\xba\xaa\xb5\xcd\u0248\xb7\xbe\x85\\\xeb\xbd\u038a\x02\x1e\f\x00\x13\a\n\xdc\x00\x00\u07d4\x9a\xc4\xdaQ\xd2x\"\xd1\xe2\b\xc9n\xa6J\x1e[U)\x97#\x89\x05lUy\xf7\"\x14\x00\x00\u0794\x9a\xc8S\x97y*i\u05cf(k\x86C*\a\xae\u03b6\x0ed\x88\xc6s\xce<@\x16\x00\x00\xe0\x94\x9a\xc9\a\xee\x85\xe6\xf3\xe2#E\x99\x92\xe2V\xa4?\xa0\x8f\xa8\xb2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9a\xd4\u007f\xdc\xf9\u0354-(\xef\xfd[\x84\x11[1\xa6X\xa1>\x89\xb2Y\xec\x00\xd5;(\x00\x00\u07d4\x9a\xdb\u04fc{\n\xfc\x05\xd1\xd2\xed\xa4\x9f\xf8c\x93\x9cH\xdbF\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x9a\xdfE\x8b\xff5\x99\xee\xe1\xa2c\x98\x85\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x9a\xf9\xdb\xe4t\"\xd1w\xf9E\xbd\xea\xd7\xe6\xd8)05b0\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x9a\xfaSkLf\xbc8\xd8u\u0133\x00\x99\xd9&\x1f\xdb8\xeb\x89\v*\x8f\x84*w\xbc\x80\x00\u07d4\x9b\x06\xad\x84\x1d\xff\xbeL\xcfF\xf1\x03\x9f\u00c6\xf3\xc3!Dn\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\x11h\u078a\xb6KGU/3\x89\x80\n\x9c\xc0\x8bFf\u03c9]\u0212\xaa\x111\xc8\x00\x00\u07d4\x9b\x18\x11\xc3\x05\x1fF\xe6d\xaeK\xc9\xc8$\u0445\x92\xc4WJ\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x9b\x18G\x86U\xa4\x85\x1c\xc9\x06\xe6`\xfe\xaca\xf7\xf4\u023f\xfc\x89\xe2G\x8d8\x90}\x84\x00\x00\u07d4\x9b\"\xa8\r\\{3t\xa0[D`\x81\xf9}\n4\a\x9e\u007f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x9b+\xe7\xf5gT\xf5\x05\xe3D\x1a\x10\xf7\xf0\xe2\x0f\xd3\xdd\xf8I\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\x9b2\xcfOQ\x15\xf4\xb3J\x00\xa6La}\xe0c\x875C#\x89\x05\xb8\x1e\u0608 |\x80\x00\u07d4\x9bC\u0739_\xde1\x80u\xa5g\xf1\xe6\xb5v\x17\x05^\xf9\xe8\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x9bDO\xd37\xe5\xd7R\x93\xad\xcf\xffp\xe1\xea\x01\xdb\x022\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9bH$\xff\x9f\xb2\xab\xdaUM\xeeO\xb8\xcfT\x91eW\x061\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9bL'\x15x\f\xa4\xe9\x9e`\xeb\xf2\x19\xf1Y\f\x8c\xadP\n\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x9bY\xeb!;\x1eue\xe4PG\xe0N\xa07O\x10v-\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\\9\xf7\xe0\xac\x16\x8c\x8e\xd0\xed4\x04w\x11}\x1bh.\xe9\x89\x05P\x05\xf0\xc6\x14H\x00\x00\u07d4\x9b^\xc1\x8e\x83\x13\x88}\xf4a\u0490.\x81\xe6z\x8f\x11;\xb1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9bd\xd3\u034d+s\xf6hA\xb5\xc4k\xb6\x95\xb8\x8a\x9a\xb7]\x89\x01 :Ov\f\x16\x80\x00\u07d4\x9be\x8f\xb3a\xe0F\xd4\xfc\xaa\x8a\xefm\x02\xa9\x91\x11\"6%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9bfA\xb1>\x17/\xc0r\xcaK\x83'\xa3\xbc(\xa1[f\xa9\x89\x06\x81U\xa46v\xe0\x00\x00\xe0\x94\x9bh\xf6t\x16\xa6;\xf4E\x1a1\x16L\x92\xf6r\xa6\x87Y\xe9\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\x9bw6i\xe8}v\x01\x8c\t\x0f\x82U\xe5D\t\xb9\u0728\xb2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9bw\xeb\xce\xd7\xe2\x15\xf0\x92\x0e\x8c+\x87\x00$\xf6\xec\xb2\xff1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9b|\x88\x10\xcc|\u021e\x80Nm>8\x12\x18PG(w\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\xa5=\xc8\xc9^\x9aG/\xeb\xa2\xc4\xe3,\x1d\xc4\xdd{\xabF\x89Hz\x9a0E9D\x00\x00\xe0\x94\x9b\xac\xd3\xd4\x0f;\x82\xac\x91\xa2d\xd9\u060d\x90\x8e\xac\x86d\xb9\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9b\xb7`\xd5\u0089\xa3\xe1\xdb\x18\xdb\tSE\xcaA;\x9aC\u0089\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x9b\xb7b\x04\x18j\xf2\xf6;\xe7\x91h`\x16\x87\xfc\x9b\xadf\x1f\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9b\xb9\xb0*&\xbf\xe1\xcc\xc3\xf0\xc6!\x9e&\x1c9\u007f\xc5\xcax\x89Hz\x9a0E9D\x00\x00\u07d4\x9b\xc5s\xbc\xda#\xb8\xb2o\x90s\xd9\f#\x0e\x8eq\xe0'\v\x896/u\xa40]\f\x00\x00\u07d4\x9b\xd7\u00caB\x100JMe>\xde\xff\x1b<\xe4_\xcexC\x89\x0fI\x89A\xe6d(\x00\x00\xe0\x94\x9b\u0600h\xe10u\xf3\xa8\xca\xc4d\xa5\xf9I\xd6\xd8\x18\xc0\xf6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9b\xd9\x05\xf1q\x9f\u01ec\xd0\x15\x9dM\xc1\xf8\xdb/!G#8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9b\xdb\u071b\x9741\xd1<\x89\xa3\xf9u~\x9b;bu\xbf\u01c9\x1b\x1a}\u03caD\u04c0\x00\u07d4\x9b\xe3\xc3)\xb6*(\xb8\xb0\x88l\xbd\x8b\x99\xf8\xbc\x93\f\xe3\xe6\x89\x04\t\xe5+H6\x9a\x00\x00\xe0\x94\x9b\xf5\x8e\xfb\xea\a\x84\xeb\x06\x8a\xde\u03e0\xbb!P\x84\xc7:5\x8a\x01:k+VHq\xa0\x00\x00\u07d4\x9b\xf6r\xd9y\xb3fR\xfcR\x82Tzjk\xc2\x12\xaeCh\x89#\x8f\xd4,\\\xf0@\x00\x00\xe0\x94\x9b\xf7\x03\xb4\x1c6$\xe1_@T\x96#\x90\xbc\xba0R\xf0\xfd\x8a\x01H>\x01S<.<\x00\x00\u07d4\x9b\xf7\x1f\u007f\xb57\xacT\xf4\xe5\x14\x94\u007f\xa7\xffg(\xf1m/\x89\x01\u03c4\xa3\n\n\f\x00\x00\u07d4\x9b\xf9\xb3\xb2\xf2<\xf4a\xebY\x1f(4\v\xc7\x19\x93\x1c\x83d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x9b\xfce\x9c\x9c`\x1e\xa4*k!\xb8\xf1p\x84\xec\x87\xd7\x02\x12\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9b\xff\xf5\r\xb3jxUU\xf0vR\xa1S\xb0\xc4+\x1b\x8bv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\x05\xe9\xd0\xf0u\x8eyS\x03q~1\xda!<\xa1W\u618965\u026d\xc5\u07a0\x00\x00\u07d4\x9c\x1bw\x1f\t\xaf\x88*\xf0d0\x83\xde*\xa7\x9d\xc0\x97\xc4\x0e\x89\x86p\xe9\xece\x98\xc0\x00\x00\u07d4\x9c(\xa2\xc4\b`\x91\xcb]\xa2&\xa6W\xce2H\xe8\xea{o\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\x9c/\xd5@\x89\xaff]\xf5\x97\x1ds\xb8\x04a`9dsu\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c4@\x98\xbaaZ9\x8f\x11\xd0\t\x90[\x17|D\xa7\xb6\x02\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c=\x06\x92\xce\xee\xf8\n\xa4\x96\\\xee\xd2b\xff\xc7\xf0i\xf2\u0709\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9c@\\\xf6\x97\x95a8\x06^\x11\xc5\xf7U\x9eg$[\u0465\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9cE *%\xf6\xad\x00\x11\xf1\x15\xa5\xa7\"\x04\xf2\xf2\x19\x88f\x8a\x01\x0f\xcf:b\xb0\x80\x98\x00\x00\xe0\x94\x9cI\xde\xffG\b_\xc0\x97\x04\u02a2\u0728\u0087\xa9\xa17\u068a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x9cK\xbc\xd5\xf1dJo\aX$\xdd\xfe\x85\xc5q\u05ab\xf6\x9c\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4\x9cRj\x14\x06\x83\xed\xf1C\x1c\xfa\xa1(\xa95\xe2\xb6\x14\u060b\x89\x06\x04o7\xe5\x94\\\x00\x00\xe0\x94\x9cT\xe4\xedG\x9a\x85h)\u01bbB\u069f\vi*u\xf7(\x8a\x01\x97\xa8\xf6\xddU\x19\x80\x00\x00\xe0\x94\x9cX\x1a`\xb6\x10(\xd94\x16y)\xb2-p\xb3\x13\xc3O\u040a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x9c\\\xc1\x11\t,\x12!\x16\xf1\xa8_N\xe3\x14\bt\x1a}/\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\x9ck\u0264k\x03\xaeT\x04\xf0C\xdf\xcf!\x88>A\x10\xcc3\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9cx\x96?\xbc&<\t\xbdr\xe4\xf8\xde\xf7J\x94u\xf7\x05\\\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4\x9cx\xfb\xb4\xdfv\x9c\xe2\xc1V\x92\f\xfe\xdf\xda\x03:\x0e%J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x9c{m\xc5\x19\x0f\xe2\x91)c\xfc\xd5yh>\xc79Q\x16\xb0\x89*\x11)\u0413g \x00\x00\u07d4\x9c\x80\xbc\x18\xe9\xf8\u0516\x8b\x18]\xa8\u01df\xa6\xe1\x1f\xfc>#\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x9c\x98\xfd\xf1\xfd\u034b\xa8\xf4\u0170L:\xe8X~\xfd\xf0\xf6\xe6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x9c\x99\xa1\u0691\u0552\v\xc1N\f\xb9\x14\xfd\xf6+\x94\u02c3X\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9c\x99\xb6&\x06(\x1b\\\xef\xab\xf3aV\xc8\xfeb\x83\x9e\xf5\xf3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x9c\x9a\a\xa8\xe5|1r\xa9\x19\xefdx\x94tI\x0f\r\x9fQ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9c\x9d\xe4G$\xa4\x05M\xa0\xea\xa6\x05\xab\u0300&hw\x8b\xea\x89\n\xd7\xd5\xca?\xa5\xa2\x00\x00\u07d4\x9c\x9f;\x8a\x81\x1b!\xf3\xff?\xe2\x0f\xe9p\x05\x1c\xe6j\x82O\x89>\xc2\u07bc\a\u053e\x00\x00\xe0\x94\x9c\x9f\x89\xa3\x91\x0fj*\xe8\xa9\x10G\xa1z\xb7\x88\xbd\xde\xc1p\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9c\xa0B\x9f\x87O\x8d\xce\xe2\xe9\xc0b\xa9\x02\n\x84*Xz\xb9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\xa4.\u7838\x98\xf6\xa5\xcc`\xb5\xa5\u05f1\xbf\xa3\xc321\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\xb2\x8a\xc1\xa2\n\x10o\u007f76\x92\xc5\xceLs\xf172\xa1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c\xcd\u0732\xcf\u00b2[\br\x9a\n\x98\xd9\xe6\xf0 .\xa2\xc1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9c\xe2\u007f$^\x02\xd1\xc3\x12\xc1\xd5\x00x\x8c\x9d\xefv\x90E;\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9c\xe56;\x13\xe8#\x8a\xa4\xdd\x15\xac\u0432\xe8\xaf\xe0\x872G\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9c\xf2\x92\x8b\xee\xf0\x9a@\xf9\xbf\xc9S\xbe\x06\xa2Q\x11a\x82\xfb\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9d\x06\x91\x97\xd1\xdeP\x04Z\x18o^\xc7D\xac@\u8bd1\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\x9d\x0e}\x92\xfb0XS\u05d8&;\xf1^\x97\xc7+\xf9\xd7\xe0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9d\x0f4~\x82k}\u03aa\xd2y\x06\n5\xc0\x06\x1e\xcf3K\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d u\x17B,\xc0\xd6\r\xe7\xc27\tzMO\xce \x94\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x9d%\n\xe4\xf1\x10\xd7\x1c\xaf\u01f0\xad\xb5.\x8d\x9a\xcbfy\xb8\x8a\x02\x15mn\x99r\x13\xc0\x00\x00\xe0\x94\x9d+\xfc6\x10o\x03\x82P\xc0\x18\x01hW\x85\xb1l\x86\xc6\r\x8aPw\xd7]\xf1\xb6u\x80\x00\x00\xe0\x94\x9d0\xcb#{\xc0\x96\xf1p6\xfc\x80\xdd!\xcah\x99,\xa2\u064a\x06n\xe71\x8f\u070f0\x00\x00\u07d4\x9d2\x96.\xa9\x97\x00\xd92(\xe9\xdb\xda\xd2\xcc7\xbb\x99\xf0~\x89\xb4c+\xed\xd4\xde\xd4\x00\x00\u07d4\x9d4\xda\xc2[\xd1X(\xfa\xef\xaa\xf2\x8fq\aS\xb3\x9e\x89\u0709;\x1cV\xfe\xd0-\xf0\x00\x00\u07d4\x9d6\x91e\xfbp\xb8\x1a:v_\x18\x8f\xd6\f\xbe^{\th\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9d@\xe0\x12\xf6\x04%\xa3@\xd8-\x03\xa1\xc7W\xbf\xab\xc7\x06\xfb\x89\t4o:\xdd\u020d\x80\x00\u07d4\x9dAt\xaaj\xf2\x84v\xe2)\xda\xdbF\x18\b\b\xc6u\x05\xc1\x89B\x1a\xfd\xa4.\u0597\x00\x00\u07d4\x9dB\x133\x9a\x01U\x18avL\x87\xa9<\xe8\xf8_\x87\x95\x9a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9dF\f\x1b7\x9d\xdb\x19\xa8\xc8[LgG\x05\r\xdf\x17\xa8u\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x9dG\xba[L\x85\x05\xad\x8d\xa4)4(\va\xa0\xe1\xe8\xb9q\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9dM2\x11w%n\xbd\x9a\xfb\xda0A5\xd5\x17\xc3\xdcV\x93\x89!d\xb7\xa0J\u0220\x00\x00\u07d4\x9dO\xf9\x89\xb7\xbe\u066b\x10\x9d\x10\xc8\xc7\xe5_\x02\xd7g4\xad\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x9dQ\x15C\xb3\xd9\xdc`\xd4\u007f\t\u051d\x01\xb6\u0118\xd8 x\x8a\x02a\x97\xb9Qo\u00d4\x00\x00\u07d4\x9dn\u03e0:\xf2\xc6\xe1D\xb7\xc4i*\x86\x95\x1e\x90.\x9e\x1f\x89\xa2\xa5\xaa`\xad$?\x00\x00\u07d4\x9dvU\xe9\xf3\xe5\xba]n\x87\xe4\x12\xae\xbe\x9e\xe0\u0512G\ue24e\t1\x1c\x1d\x80\xfa\x00\x00\u07d4\x9dx1\xe84\xc2\v\x1b\xaaiz\xf1\xd8\xe0\xc6!\u016f\xff\x9a\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4\x9dx\xa9u\xb7\xdb^M\x8e(\x84\\\xfb\xe7\xe3\x14\x01\xbe\r\u0649H\xa40k\xa2\u5e5c\x8ahX\u02f5,\f\xf75\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\x9d\u007f\xdapp\xbf>\xe9\xbb\u0664\x1fU\xca\u0505J\xe6\xc2,\x8a\x02U\u02e3\xc4o\xcf\x12\x00\x00\u07d4\x9d\x81\xae\xa6\x9a\xedj\xd0p\x89\xd6\x14E4\x8c\x17\xf3K\xfc[\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9d\x91\x1f6\x82\xf3/\xe0y.\x9f\xb6\xff<\xfcG\xf5\x89\xfc\xa5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\x91;]3\x9c\x95\xd8wEV%c\xfe\xa9\x8b#\xc6\f\u0109\tA0,\u007fM#\x00\x00\u07d4\x9d\x93\xfa\xb6\xe2(E\xf8\xf4Z\aIo\x11\xdeqS\r\xeb\u01c9lO\xd1\xee$nx\x00\x00\u07d4\x9d\x99\xb1\x89\xbb\u0664\x8f\xc2\xe1n\x8f\u0363;\xb9\x9a1{\xbb\x89=\x16\xe1\vm\x8b\xb2\x00\x00\u07d4\x9d\x9cN\xfe\x9fC9\x89\xe2;\xe9@I!S)\xfaU\xb4\u02c9\r\u3c89\x03\u01b5\x80\x00\u07d4\x9d\x9eW\xfd\xe3\x0ePh\xc0>I\x84\x8e\xdc\xe3C\xb7\x02\x83X\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x9d\xa30\"@\xaf\x05\x11\xc6\xfd\x18W\xe6\u07779Ow\xabk\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\x9d\xa4\xec@pw\xf4\xb9p{-\x9d.\xde^\xa5(+\xf1\u07c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\xa6\t\xfa:~l\xf2\xcc\x0ep\u036b\xe7\x8d\xc4\xe3\x82\xe1\x1e\x89A\rXj \xa4\xc0\x00\x00\xe0\x94\x9d\xa6\x1c\xcdb\xbf\x86\x06V\xe02]qW\xe2\xf1`\xd9;\xb5\x8a\x01\x0f\f\xa9V\xf8y\x9e\x00\x00\xe0\x94\x9d\xa6\xe0u\x98\x9ct\x19\tL\xc9\xf6\xd2\u44d3\xbb\x19\x96\x88\x8a\x02Y\xbbq\u056d\xf3\xf0\x00\x00\u07d4\x9d\xa8\xe2,\xa1\x0eg\xfe\xa4NR^GQ\xee\xac6\xa3\x11\x94\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\x9d\xb2\xe1\\\xa6\x81\xf4\xc6`H\xf6\xf9\xb7\x94\x1e\u040b\x1f\xf5\x06\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\xc1\x0f\xa3\x8f\x9f\xb0h\x10\xe1\x1f`\x17>\xc3\xd2\xfdju\x1e\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x9d\xd2\x19f$\xa1\xdd\xf1J\x9d7^_\a\x15+\xaf\"\xaf\xa2\x89A\xb0^$c\xa5C\x80\x00\u07d4\x9d\xd4k\x1cm?\x05\u279co\x03~\xed\x9aYZ\xf4\xa9\xaa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9d\xdd5^cN\xe9\x92~K\u007fl\x97\xe7\xbf:/\x1ehz\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x9d\xe2\n\xe7j\xa0\x82c\xb2\x05\xd5\x14$a\x96\x1e$\b\xd2f\x89\r\xa93\xd8\xd8\xc6p\x00\x00\u07d4\x9d\xe2\v\xc3~\u007fH\xa8\x0f\xfdz\xd8O\xfb\xf1\xa1\xab\xe1s\x8c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9d\xe78m\xde@\x1c\xe4\xc6{q\xb6U?\x8a\xa3N\xa5\xa1}\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x9d\xeb9\x02z\xf8w\x99+\x89\xf2\xecJ\x1f\x82.\xcd\xf1&\x93\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9d\xef\xe5j\x0f\xf1\xa1\x94}\xba\t#\xf7\xdd%\x8d\x8f\x12\xfaE\x8a\x05\xb1*\ufbe8\x04\x00\x00\x00\u07d4\x9d\xf0W\xcd\x03\xa4\xe2~\x8e\x03/\x85y\x85\xfd\u007f\x01\xad\xc8\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9d\xf3*P\x1c\vx\x1c\x02\x81\x02/B\xa1)?\xfd{\x89*\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4\x9e\x01vZ\xff\b\xbc\"\x05P\xac\xa5\xea.\x1c\xe8\u5c19#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9e \xe5\xfd6\x1e\xab\xcfc\x89\x1f[\x87\xb0\x92h\xb8\xeb7\x93\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9e#,\b\xc1M\xc1\xa6\xed\v\x8a;(h\x97{\xa5\xc1}\x10\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e#\xc5\u4dc2\xb0\n_\xad\U0006eb47\xda\xcf[\x03g\xa1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e59\x90q\xa4\xa1\x01\xe9\x19M\xaa?\t\xf0J\v_\x98p\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9e>\xb5\t'\x8f\xe0\xdc\xd8\xe0\xbb\xe7\x8a\x19N\x06\xb6\x809C\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\x9eBrrQk>g\xd4\xfc\xbf\x82\xf5\x93\x90\xd0L\x8e(\xe5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x9eL\xec5:\xc3\u3043^<\t\x91\xf8\xfa\xa5\xb7\u0428\xe6\x8a\x02\x1e\x18\xb9\xe9\xabE\xe4\x80\x00\u07d4\x9eX\x11\xb4\v\xe1\xe2\xa1\xe1\u048c;\at\xac\xde\n\t`=\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x9eZ1\x1d\x9fi\x89\x8a|j\x9dc`h\x048\xe6z{/\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x9e| P\xa2'\xbb\xfd`\x93~&\x8c\xea>h\xfe\xa8\xd1\xfe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9e\u007fe\xa9\x0e\x85\b\x86{\xcc\xc9\x14%j\x1e\xa5t\xcf\a\xe3\x89C8t\xf62\xcc`\x00\x00\xe0\x94\x9e\x81D\xe0\x8e\x89dx\x11\xfekr\xd4E\u05a5\xf8\n\xd2D\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9e\x8fd\xdd\xcd\u9e34Q\xba\xfa\xa25\xa9\xbfQ\x1a%\xac\x91\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\x9e\x95\x1fm\xc5\xe3R\xaf\xb8\xd0B\x99\xd2G\x8aE\x12Y\xbfV\x89\x03\xe7A\x98\x81\xa7:\x00\x00\u07d4\x9e\x96\r\xcd\x03\u057a\x99\xcb\x11]\x17\xffL\t$\x8a\xd4\u043e\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9e\xafj2\x8a@v\x02N\xfakg\xb4\x8b!\xee\xdc\xc0\xf0\xb8\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x9e\xb1\xffqy\x8f(\xd6\xe9\x89\xfa\x1e\xa0X\x8e'\xba\x86\xcb}\x89\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\x9e\xb2\x81\xc3'\x19\xc4\x0f\xdb>!m\xb0\xf3\u007f\xbcs\xa0&\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e\xb3\xa7\xcb^g&Bz:6\x1c\xfa\x8dad\xdb\u043a\x16\x89+\x95\xbd\xcc9\xb6\x10\x00\x00\u07d4\x9e\xb7\x83N\x17\x1dA\xe0i\xa7yG\xfc\xa8v\"\xf0\xbaNH\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x9e\xc0>\x02\u51f7v\x9d\xefS\x84\x13\xe9\u007f~U\xbeq\u060a\x04+\xf0kx\xed;P\x00\x00\u07d4\x9e\u02eb\xb0\xb2'\x82\xb3uD)\xe1uz\xab\xa0K\x81\x18\x9f\x89,\xa7\xbb\x06\x1f^\x99\x80\x00\u07d4\x9e\xce\x14\x00\x80\t6\xc7\xc6H_\xcd\xd3b`\x17\u041a\xfb\xf6\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4\x9e\xd4\xe6?ReB\xd4O\xdd\xd3MY\xcd%8\x8f\xfdk\u0689\u049b4\xa4cH\x94\x00\x00\u07d4\x9e\xd8\x0e\xda\u007fU\x05M\xb9\xfbR\x82E\x16\x88\xf2k\xb3t\xc1\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9e\u0710\xf4\xbe!\be!J\xb5\xb3^Z\x8d\xd7t\x15'\x9d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9e\u07acL\x02k\x93\x05M\u0171\xd6a\fo9`\xf2\xads\x89A\rXj \xa4\xc0\x00\x00\u07d4\x9e\xe9?3\x9eg&\xece\xee\xa4O\x8aK\xfe\x10\xda=2\x82\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9e\xe9v\f\xc2s\xd4pj\xa0\x83u\xc3\xe4o\xa20\xaf\xf3\u054a\x01\xe5.3l\xde\"\x18\x00\x00\u07d4\x9e\xeb\a\xbd+x\x90\x19^}F\xbd\xf2\a\x1bf\x17QM\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x9e\xefD-)\x1aD}t\xc5\xd2S\u011e\xf3$\xea\xc1\xd8\xf0\x89\xb9f\b\xc8\x10;\xf0\x00\x00\u07d4\x9e\xf1\x89k\x00|2\xa1Q\x14\xfb\x89\xd7=\xbdG\xf9\x12+i\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9f\x01w\x06\xb80\xfb\x9c0\ufc20\x9fPk\x91WEu4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x10\xf2\xa0F;e\xae0\xb0p\xb3\xdf\x18\xcfF\xf5\x1e\x89\xbd\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x9f\x19\xfa\u0223$7\xd8\n\u0183z\v\xb7\x84\x17)\xf4\x97.\x89#=\xf3)\x9far\x00\x00\u07d4\x9f\x1a\xa8\xfc\xfc\x89\xa1\xa52\x8c\xbdcD\xb7\x1f'\x8a,\xa4\xa0\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9f!0,\xa5\tk\xeat\x02\xb9\x1b\x0f\xd5\x06%O\x99\x9a=\x89C\x97E\x1a\x00=\xd8\x00\x00\u07d4\x9f'\x1d(U\x00\xd78F\xb1\x8fs>%\u074bO]J\x8b\x89'#\xc3F\xae\x18\b\x00\x00\u07d4\x9f4\x97\xf5\xef_\xe60\x95\x83l\x00N\xb9\xce\x02\xe9\x01;K\x89\"V\x86\x1b\xf9\xcf\b\x00\x00\xe0\x94\x9f:t\xfd^~\xdc\xc1\x16)\x93\x17\x13\x81\u02f62\xb7\xcf\xf0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9fF\xe7\xc1\xe9\a\x8c\xae\x860Z\xc7\x06\v\x01F}f\x85\xee\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\x9fIl\xb2\x06\x95c\x14M\b\x11g{\xa0\xe4q:\nAC\x89<\xd2\xe0\xbfc\xa4H\x00\x00\u07d4\x9fJq\x95\xac|\x15\x1c\xa2X\xca\xfd\xa0\u02b0\x83\xe0I\xc6\x02\x89SS\x8c2\x18\\\xee\x00\x00\u07d4\x9fJ\xc9\xc9\xe7\xe2L\xb2DJ\x04T\xfa[\x9a\xd9\xd9-8S\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4\x9f_D\x02kWjJ\xdbA\xe9YaV\x1dA\x03\x9c\xa3\x91\x89\r\x8drkqw\xa8\x00\x00\u07d4\x9f`{?\x12F\x9fDa!\u03bf4u5kq\xb42\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9fa\xbe\xb4o^\x85=\n\x85!\xc7Dnh\xe3L}\ts\x89\x1e[\x8f\xa8\xfe*\xc0\x00\x00\u07d4\x9fd\xa8\xe8\xda\xcfJ\xde0\xd1\x0fMY\xb0\xa3\u056b\xfd\xbft\x8966\x9e\xd7t}&\x00\x00\u07d4\x9ff.\x95'A!\xf1wVncm#\x96L\xf1\xfdho\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9fj2*mF\x99\x81Bj\xe8D\x86]~\xe0\xbb\x15\u01f3\x89\x02\xb5\xeeW\x92\x9f\u06c0\x00\u07d4\x9fy\x86\x92J\xeb\x02h|\xd6A\x89\x18\x9f\xb1g\xde\xd2\xdd\\\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x9fz\x03\x92\xf8Ws.0\x04\xa3u\xe6\xb1\x06\x8dI\xd801\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x82E\u00eb}\x171d\x86\x1c\u04d9\x1b\x94\xf1\xba@\xa9:\x89\x9b\ny\x1f\x12\x110\x00\x00\u07d4\x9f\x83\xa2\x93\xc3$\xd4\x10l\x18\xfa\xa8\x88\x8fd\u0499\x05L\xa0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9f\x86\xa0f\xed\xb6\x1f\xcbXV\u0793\xb7\\\x8cy\x18d\xb9{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x98\xeb4\xd4iy\xb0\xa6\u078b\x05\xaaS:\x89\xb8%\xdc\xf1\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\xe0\x94\x9f\x9f\xe0\xc9_\x10\xfe\xe8z\xf1\xaf r6\xc8\xf3aN\xf0/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9f\xae\xa1\xc5\xe8\x1ez\xcb?\x17\xf1\xc3Q\xee.\u0649\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa0\b\x01\x98c\xc1\xa7|\x14\x99\xeb9\xbb\u05ff-\u05e3\x1c\xb9\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xa0\t\xbf\ao\x1b\xa3\xfaW\u04a7!r\x18\xbe\xd5VZzz\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa0\x1e\x94v\u07c4C\x18%\xc86\xe8\x80:\x97\xe2/\xa5\xa0\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\xa0\x1f\x12\xd7\x0fD\xaa{\x11;(\\\"\xdc\xdbE\x874T\xa7\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xa0\x1f\u0450j\x90\x85\x06\xde\xda\xe1\xe2\b\x12\x88r\xb5n\u7489\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa0\"\x82@\xf9\x9e\x1d\xe9\xcb2\xd8,\x0f/\xa9\xa3\xd4K\v\xf3\x89V\xbcu\xe2\xd61\x00\x00\x00\xe0\x94\xa0+\xdedahn\x19\xace\f\x97\r\x06r\xe7m\xcbO\u008a\x01\xe0\x92\x96\xc37\x8d\xe4\x00\x00\u07d4\xa0,\x1e4\x06O\x04u\xf7\xfa\x83\x1c\xcb%\x01L:\xa3\x1c\xa2\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xa0-\u01aa2\x8b\x88\r\u97acTh#\xfc\xcfw@G\xfb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa0.?\x8fYY\xa7\xaa\xb7A\x86\x12\x12\x9bp\x1c\xa1\xb8\x00\x10\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa04\u007f\n\x98wc\x90\x16\\\x16m2\x96;\xf7M\xcd\n/\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa05\xa3e$x\xf8-\xbdm\x11_\xaa\x8c\xa9F\xec\x9eh\x1d\x89\x05\xf4\xe4-\u052f\xec\x00\x00\u07d4\xa0:=\xc7\xc53\xd1tB\x95\xbe\x95]a\xaf?R\xb5\x1a\xf5\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa0E\x9e\xf3i:\xac\xd1d|\xd5\u0612\x989 L\xefS\xbe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa0O*\xe0*\xdd\x14\xc1/\xafe\xcb%\x90\"\u0403\n\x8e&\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xa0l\xd1\xf3\x969l\ndFFQ\xd7\xc2\x05\xef\xaf8|\xa3\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xa0ri\x1c\x8d\xd7\xcdB7\xffr\xa7\\\x1a\x95\x06\xd0\xce[\x9e\x89\x14\x0e\xc8\x0f\xa7\xee\x88\x00\x00\u07d4\xa0r\u03beb\xa9\xe9\xf6\x1c\xc3\xfb\xf8\x8a\x9e\xfb\xfe>\x9a\x8dp\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa0v\x82\x00\v\x1b\xcf0\x02\xf8\\\x80\xc0\xfa)I\xbd\x1e\x82\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa0z\xa1mt\xae\u8a63(\x8dR\xdb\x15Q\u0553\x882\x97\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa0\x8d![[j\xacHa\xa2\x81\xac~@\vx\xfe\xf0L\xbf\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa0\x95\x19p\xdf\u0403/\xb8;\xda\x12\xc25E\xe7\x90Aul\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa0\x9fM^\xaae\xa2\xf4\xcbu\nI\x924\x01\xda\u5410\xaf\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\xe0\x94\xa0\xa0\xe6R\x04T\x1f\u029b/\xb2\x82\u0355\x13\x8f\xae\x16\xf8\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa0\xaa_\x02\x01\xf0M;\xbe\xb8\x98\x13/|\x11g\x94f\xd9\x01\x89\x01\xfb\xedR\x15\xbbL\x00\x00\u07d4\xa0\xaa\xdb\xd9P\x97\"p_m#X\xa5\u01df7\x97\x0f\x00\xf6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa0\xb7q\x95\x1c\xe1\xde\xee6:\xe2\xb7q\xb7>\a\u0135\xe8\x00\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa0\xde\\`\x1eif5\u0198\xb7\xae\x9c\xa4S\x9f\u01f9A\xec\x89\x12\xc3\xcb\xd7\x04\xc9w\x00\x00\u07d4\xa0\xe8\xbaf\x1bH\x15L\xf8C\xd4\u00a5\xc0\xf7\x92\xd5(\xee)\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa0\xfc~S\xc5\xeb\xd2z*\xbd\xacE&\x1f\x84\xab;Q\xae\xfb\x89\xa3\x13\xda\xec\x9b\xc0\xd9\x00\x00\xe0\x94\xa0\xff[L\xf0\x16\x02~\x83#I}D(\xd3\xe5\xa8;\x87\x95\x8a\x01e\x98\xd3\xc8>\xc0B\x00\x00\u07d4\xa1\x06F[\xbd\x19\u1dbc\xe5\r\x1b\x11W\xdcY\tZ60\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa1\x06\xe6\x92>\xddS\u028e\xd6P\x96\x8a\x91\b\xd6\xcc\xfd\x96p\x8a\x02\x02\xfe\x15\x05\xaf\uc240\x00\u07d4\xa1\t\u12f0\xa3\x9c\x9e\xf8/\xa1\x95\x97\xfc^\xd8\xe9\xebmX\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\xa1\x1a\x03\u013b&\xd2\x1e\xffg}]U\\\x80\xb2TS\xeez\x89\x03\xcb'Y\xbcA\x0f\x80\x00\u07d4\xa1\x1e\xff\xabl\xf0\xf5\x97,\xff\xe4\xd5e\x96\xe9\x89h\x14J\x8f\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xa1 M\xad_V\a(\xa3\\\r\x8f\u01d4\x81\x05{\xf7s\x86\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa1&#\xe6)\u07d3\tg\x04\xb1`\x84\xbe,\u061dV-\xa4\x8a\x01\xcc\xc92E\x11\xe4P\x00\x00\xe0\x94\xa1*l-\x98]\xaf\x0eO_ z\xe8Q\xaa\xf7)\xb32\u034a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xa13m\xfb\x96\xb6\xbc\xbeK>\xdf2\x05\xbeW#\xc9\x0f\xadR\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa1;\x9d\x82\xa9\x9b<\x9b\xbaZ\xe7.\xf2\x19\x9e\xdc};\xb3l\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xa1<\xfe\x82mm\x18A\u072eD;\xe8\u00c7Q\x816\xb5\xe8\x8a\x1d\xa5jK\b5\xbf\x80\x00\x00\xe0\x94\xa1C.\xd2\u01b7wz\x88\xe8\xd4m8\x8epG\u007f \x8c\xa5\x8a\x01\xb1\xa7\xe4\x13\xa1\x96\xc5\x00\x00\u07d4\xa1D\xf6\xb6\x0fr\xd6J!\xe30\xda\xdbb\u0619\n\xde+\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa1P%\xf5\x95\xac\xdb\xf3\x11\x0fw\u017f$G~eH\xf9\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1X\x14\x8a.\x0f>\x92\xdc,\xe3\x8f\xeb\xc2\x01\a\xe3%<\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1a`\x85\x1d+\x9c4\x9b\x92\xe4o\x82\x9a\xbf\xb2\x10\x945\x95\x89a\t=|,m8\x00\x00\u07d4\xa1f\xf9\x11\xc6D\xac2\x13\u049e\x0e\x1a\xe0\x10\xf7\x94\u056d&\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1m\x9e=c\x98aY\xa8\x00\xb4h7\xf4^\x8b\xb9\x80\xee\v\x89n\x11u\xdaz\xd1 \x00\x00\u07d4\xa1pp\xc2\xe9\u0169@\xa4\xec\x0eIT\xc4\xd7\xd6C\xbe\x8fI\x89lk\x17\x03;6\x1c\x80\x00\u07d4\xa1|\x9eC#\x06\x95\x18\x18\x9dR\a\xa0r\x8d\u02d20j?\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa1\x83`\xe9\x85\xf2\x06.\x8f\x8e\xfe\x02\xad,\xbc\x91\xad\x9aZ\xad\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa1\x91\x14\x05\xcfn\x99\x9e\xd0\x11\xf0\xdd\xcd*O\xf7\u008f%&\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa1\x92i\x80\a\xcc\x11\xaa`=\"\x1d_\xee\xa0v\xbc\xf7\xc3\r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\x92\xf0j\xb0R\xd5\xfd\u007f\x94\xee\xa81\x8e\x82x\x15\xfegz\x89\a\x1f\x8a\x93\xd0\x1eT\x00\x00\u07d4\xa1\x99\x81D\x96\x8a\\p\xa6AUT\xce\xfe\u0082F\x90\u0125\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa1\xa1\xf0\xfam \xb5\nyO\x02\xefR\b\\\x9d\x03j\xa6\u028965\u026d\xc5\u07a0\x00\x00\u07d4\xa1\xae\x8dE@\xd4\xdbo\xdd\xe7\x14oA[C\x1e\xb5\\y\x83\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xa1\xb4|M\x0e\xd6\x01\x88B\xe6\xcf\xc8c\n\u00e3\x14.^k\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xa1\xc4\xf4Z\x82\xe1\xc4x\xd8E\b.\xb1\x88u\xc4\xeae9\xab\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xa1\xdc\xd0\xe5\xb0Z\x97|\x96#\xe5\xae/Y\xb9\xad\xa2\xf3>1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa1\xe48\n;\x1ft\x96s\xe2p\"\x99\x93\xeeU\xf3Vc\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\xf1\x93\xa0Y/\x1f\xeb\x9f\xdf\xc9\n\xa8\x13xN\xb8\x04q\u0249K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa1\xf2\x85@P\xf8re\x8e\xd8.R\xb0\xad{\xbc\x1c\xb9!\xf6\x89m\x03\x17\xe2\xb3&\xf7\x00\x00\u07d4\xa1\xf5\xb8@\x14\rZ\x9a\xce\xf4\x02\xac<\u00c8jh\xca\xd2H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\xf7e\xc4O\xe4_y\x06w\x94HD\xbeO-B\x16_\xbd\x89\xc7\xe9\xcf\xdev\x8e\xc7\x00\x00\u07d4\xa1\xf7\xdd\xe1\xd78\xd8\xcdg\x9e\xa1\xee\x96[\xee\"K\xe7\xd0M\x89=\x18DP\xe5\xe9<\x00\x00\u07d4\xa1\xf8\u063c\xf9\x0ew\u007f\x19\xb3\xa6Iu\x9a\xd9P'\xab\xdf\u00c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\x02TrB\x80onp\xe7@X\xd6\xe5)-\xef\xc8\xc8\u0509l\x87T\xc8\xf3\f\b\x00\x00\u07d4\xa2\r\a\x1b\x1b\x000cI}y\x90\xe1$\x9d\xab\xf3l5\xf7\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa2\r\x8f\xf6\f\xaa\xe3\x1d\x02\xe0\xb6e\xfaC]v\xf7|\x94B\x89\x1a\x8a\x90\x9d\xfc\xef@\x00\x00\u07d4\xa2\x11\xda\x03\xcc\x0e1\xec\xceS\t\x99\x87\x18QU(\xa0\x90\u07c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\x14B\xab\x054\n\xdeh\xc9\x15\xf3\xc39\x9b\x99U\xf3\xf7\xeb\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xa2\"\"Y\u075c>=\xed\x12p\x84\xf8\b\xe9*\x18\x870,\x89\b\xc83\x9d\xaf\xedH\x00\x00\u07d4\xa2*\xde\r\xdb\\n\xf8\xd0\u034d\xe9M\x82\xb1\x10\x82\xcb.\x91\x897KW\xf3\xce\xf2p\x00\x00\u07d4\xa2L:\xb6!\x81\xe9\xa1[x\xc4b\x1eL|X\x81'\xbe&\x89\b\xcd\xe4:\x83\xd31\x00\x00\u07d4\xa2W\xadYK\u0603(\xa7\xd9\x0f\xc0\xa9\a\u07d5\xee\xca\xe3\x16\x89\x1c7\x86\xff8F\x93\x00\x00\u07d4\xa2[\bd7\xfd!\x92\u0420\xf6On\xd0D\xf3\x8e\xf3\xda2\x89\x12)\x0f\x15\x18\v\xdc\x00\x00\u07d4\xa2v\xb0X\u02d8\u060b\xee\xdbg\xe5CPl\x9a\r\x94p\u0609\x90\xaa\xfcv\xe0/\xbe\x00\x00\u07d4\xa2\x82\xe9i\xca\xc9\xf7\xa0\xe1\xc0\u0350\xf5\xd0\xc48\xacW\r\xa3\x89\"\a\xeb\x89\xfc'8\x00\x00\xe0\x94\xa2\x91\xe9\u01d9\rU-\u046e\x16\u03bc?\xca4,\xba\xf1\u044a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa2\x93\x19\xe8\x10i\xe5\xd6\r\xf0\x0f=\xe5\xad\xee5\x05\xec\xd5\xfb\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa2\x96\x8f\xc1\xc6K\xac\vz\xe0\u058b\xa9I\x87Mm\xb2S\xf4\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xa2\x9d[\xdat\xe0\x03GHr\xbdX\x94\xb8\x853\xffd\u00b5\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa2\x9df\x1acv\xf6m\vt\xe2\xfe\x9d\x8f&\xc0$~\xc8L\x89\xdf3\x04\a\x9c\x13\xd2\x00\x00\u07d4\xa2\xa45\xdeD\xa0\x1b\xd0\ucc9eD\xe4vD\xe4j\f\xdf\xfb\x89\x1b\x1dDZz\xff\xe7\x80\x00\u07d4\xa2\xac\xe4\u0253\xbb\x1eS\x83\xf8\xact\xe1y\x06n\x81O\x05\x91\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa2\xb7\x01\xf9\xf5\xcd\u041eK\xa6+\xae\xba\u3a02W\x10X\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa2\u0145O\xf1Y\x9f\x98\x89,W%\xd2b\xbe\x1d\xa9\x8a\xad\xac\x89\x11\t\xff30\x10\xe7\x80\x00\u07d4\xa2\xc7\xea\xff\xdc,\x9d\x93sE l\x90\x9aR\u07f1LG\x8f\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\u07d4\xa2\u04aabk\t\xd6\xd4\xe4\xb1?\u007f\xfcZ\x88\xbdz\xd3gB\x89\xfb\x80xPuS\x83\x00\x00\u07d4\xa2\u04cd\xe1\xc79\x06\xf6\xa7\xcan\xfe\xb9|\xf6\xf6\x9c\xc4!\xbe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa2\xdce\xee%kY\xa5\xbdy)wO\x90K5\x8d\U000ed84a\x04\x83\xbc\xe2\x8b\xeb\t\xf8\x00\x00\u07d4\xa2\xe0h:\x80]\xe6\xa0^\xdb/\xfb\xb5\xe9o\x05p\xb67\u00c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa2\u1e2a\x90\x0e\x9c\x13\x9b?\xa1\"5OaV\xd9*\x18\xb1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa2\u2d54\x1e\f\x01\x94K\xfe\x1d_\xb4\xe8\xa3K\x92,\u03f1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\xe4`\xa9\x89\xcb\x15V_\x9e\u0327\xd1!\xa1\x8eN\xb4\x05\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa2\xec\xce,I\xf7*\t\x95\xa0\xbd\xa5z\xac\xf1\xe9\xf0\x01\xe2*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xa2\xf4r\xfeO\"\xb7}\xb4\x89!\x9e\xa4\x02=\x11X*\x93)\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xa2\xf7\x98\xe0w\xb0}\x86\x12N\x14\a\xdf2\x89\r\xbbKcy\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\xf8k\xc0a\x88N\x9e\xef\x05d\x0e\xddQ\xa2\xf7\xc0Yli\x89llD\xfeG\xec\x05\x00\x00\u07d4\xa2\xfa\x17\xc0\xfbPl\xe4\x94\x00\x8b\x95W\x84\x1c?d\x1b\x8c\xae\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa3\x04X\x8f\r\x85\f\xd8\u04cfv\xe9\xe8<\x1b\xf6>3>\u0789\x02(V\x01!l\x8c\x00\x00\u07d4\xa3\x05\x8cQszN\x96\xc5_.\xf6\xbd{\xb3X\x16~\u00a7\x89 \xdb:\xe4H\x1a\u0500\x00\u07d4\xa3\t\xdfT\u02bc\xe7\f\x95\xec03\x14\x9c\xd6g\x8ao\xd4\u03c9\f\x1f\x12\xc7Q\x01X\x00\x00\u07d4\xa3\nER\x0eR\x06\xd9\x00@p\xe6\xaf>{\xb2\xe8\xddS\x13\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa3\x0e\n\xcbSL\x9b0\x84\xe8P\x1d\xa0\x90\xb4\xeb\x16\xa2\xc0\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3 0\x95\xed\xb7\x02\x8ehq\xce\n\x84\xf5HE\x9f\x830\n\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa3!\t\x1d0\x18\x06By\xdb9\x9d+*\x88\xa6\xf4@\xae$\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4\xa3#-\x06\x8dP\x06I\x03\xc9\xeb\xc5c\xb5\x15\xac\u0237\xb0\x97\x89l\x87T\xc8\xf3\f\b\x00\x00\xe0\x94\xa3$\x1d\x89\n\x92\xba\xf5)\b\xdcJ\xa0Irk\xe4&\xeb\u04ca\x04<-\xa6a\xca/T\x00\x00\u07d4\xa3)F&\xec)\x84\xc4;C\xdaM]\x8eFi\xb1\x1dKY\x896\xa4\xcfcc\x19\xc0\x00\x00\u07d4\xa3,\xf7\xdd\xe2\f=\xd5g\x9f\xf5\xe3%\x84\\p\u0156&b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa39\xa3\xd8\xca(\x0e'\xd2A[&\xd1\xfcy2(\xb6`C\x896\U00086577\x8f\xf0\x00\x00\u07d4\xa3<\xb4P\xf9[\xb4n%\xaf\xb5\x0f\xe0_\xee\xe6\xfb\x8c\xc8\xea\x89*\x11)\u0413g \x00\x00\u07d4\xa3?p\xdaru\xef\x05q\x04\u07e7\xdbd\xf4r\xe9\xf5\xd5S\x89\x04YF\xb0\xf9\xe9\xd6\x00\x00\u07d4\xa3@v\xf8K\xd9\x17\xf2\x0f\x83B\u024b\xa7\x9eo\xb0\x8e\xcd1\x89\u3bb5sr@\xa0\x00\x00\u07d4\xa3C\x0e\x1fd\u007f2\x1e\xd3G9V##\xc7\xd6#A\vV\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xa3O\x9dV\x8b\xf7\xaf\xd9L*[\x8a_\xf5\\f\xc4\by\x99\x89\x84}P;\"\x0e\xb0\x00\x00\u07d4\xa3V\x06\xd5\x12 \xee\u007f!F\xd4\x11X.\xe4\xeeJEYn\x89\u062a\xbe\b\v\xc9@\x00\x00\u07d4\xa3VU\x1b\xb7}OE\xa6\xd7\xe0\x9f\n\b\x9ey\u0322I\u02c9\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xa3\\\x19\x13,\xac\x195Wj\xbf\xedl\x04\x95\xfb\a\x88\x1b\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3e\x91\x8b\xfe?&'\xb9\xf3\xa8gu\xd8un\x0f\u0629K\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa3n\r\x94\xb9Sd\xa8&q\xb6\b\xcb-72Ea)\t\x89\b!\xd2!\xb5)\x1f\x80\x00\u07d4\xa3u\xb4\xbc$\xa2N\x1fyu\x93\xcc0+/3\x10c\xfa\\\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa3v\"\xac\x9b\xbd\xc4\xd8+u\x01]t[\x9f\x8d\xe6Z(\uc25d\xc0\\\xce(\u00b8\x00\x00\xe0\x94\xa3y\xa5\a\fP=/\xac\x89\xb8\xb3\xaf\xa0\x80\xfdE\xedK\xec\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xa3\x80-\x8ae\x9e\x89\xa2\xc4~\x90T0\xb2\xa8'\x97\x89P\xa7\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa3\x83\x06\xcbp\xba\xa8\u4446\xbdh\xaap\xa8=$/)\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\x84vi\x1d4\x94.\xeak/v\x88\x92#\x04}\xb4az\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\x87\xceN\x96\x1axG\xf5`\a\\d\xe1YkVA\xd2\x1c\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xa3\x87\xec\xde\x0e\xe4\xc8\a\x94\x99\xfd\x8e\x03G;\u060a\xd7R*\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa3\x88:$\xf7\xf1f _\x1aj\x99I\al&\xa7nqx\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xa3\x8b[\xd8\x1a\x9d\xb9\u04b2\x1d^\xc7\xc6\x05R\xcd\x02\xedV\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa3\x90\xca\x12+\x85\x01\xee>^\a\xa8\xcaKA\x9f~M\xae\x15\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xa3\x93*1\xd6\xffu\xfb;\x12q\xac\xe7\u02a7\xd5\xe1\xff\x10Q\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xa3\x94\xadO\xd9\xe6S\x0eo\\S\xfa\xec\xbe\u0781\xcb\x17-\xa1\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xa3\x97\x9a\x92v\n\x13Z\xdfi\xd7/u\xe1gu_\x1c\xb8\u00c9\x05k\xc7^-c\x10\x00\x00\xe0\x94\xa3\x9b\xfe\xe4\xae\u027du\xbd\"\u01b6r\x89\x8c\xa9\xa1\xe9]2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa3\xa2b\xaf\u0493h\x19#\b\x92\xfd\xe8O-ZYJ\xb2\x83\x89e\xea=\xb7UF`\x00\x00\u07d4\xa3\xa2\xe3\x19\xe7\u04e1D\x8bZ\xa2F\x89S\x16\f-\xbc\xbaq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\xa5{\a\x16\x13(\x04\xd6\n\xac(\x11\x97\xff+=#{\x01\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa3\xa9>\xf9\xdb\xea&6&=\x06\xd8I/jA\u0790|\"\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\xa3\xae\x18y\x00}\x80\x1c\xb5\xf3RqjM\u063a'!\xde=\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xa3\xba\r:6\x17\xb1\xe3\x1bNB,\xe2i\xe8s\x82\x8d]i\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\xa3\xbc\x97\x9bp\x80\t/\xa1\xf9/n\x0f\xb3G\u2359PE\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xa3\xbf\xf1\u07e9\x97\x16h6\f\r\x82\x82\x842\xe2{\xf5Ng\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa3\xc1J\xce(\xb1\x92\u02f0b\x14_\u02fdXi\xc6rq\xf6\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa3\xc3:\xfc\x8c\xb4pN#\x15=\xe2\x04\x9d5\xaeq3$r\x89+X\xad\u06c9\xa2X\x00\x00\u07d4\xa3\u0430<\xff\xbb&\x9fyj\u009d\x80\xbf\xb0}\xc7\u01ad\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\u0543\xa7\xb6[#\xf6\vy\x05\xf3\xe4\xaab\xaa\xc8\u007fB'\x898\xbe\xfa\x12mZ\x9f\x80\x00\u07d4\xa3\xdb6J3-\x88K\xa9;&\x17\xaeM\x85\xa1H\x9b\xeaG\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xa3\xe0Q\xfbtJ\xa3A\f;\x88\xf8\x99\xf5\xd5\u007f\x16\x8d\xf1-\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\xa3\xe3\xa6\xeaP\x95s\xe2\x1b\xd0#\x9e\xce\x05#\xa7\xb7\u061b/\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa3\xf4\xad\x14\xe0\xbbD\xe2\xce,\x145\x9cu\xb8\xe72\xd3pT\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa3\xfa\xccP\x19\\\vI3\xc8X\x97\xfe\xcc[\xbd\x99\\4\xb8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\x03Z\xb1\xe5\x18\b!\xf0\xf3\x80\xf1\x13\x1bs\x87\xc8\u0641\u0349\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\n\xa2\xbb\xce\fr\xb4\xd0\xdf\xff\xccBq[+T\xb0\x1b\xfa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4\x19\xa9\x84\x14#c&uuV`\x894\x0e\xea\x0e\xa2\b\x19\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xa4!\u06f8\x9b:\aA\x90\x84\xad\x10\xc3\xc1]\xfe\x9b2\xd0\u008a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa4\"\xe4\xbf\v\xf7AG\u0309[\xed\x8f\x16\xd3\xce\xf3BaT\x89\x12\xef?b\xee\x116\x80\x00\u07d4\xa4%\x9f\x83E\xf7\u3a37+\x0f\xec,\xf7^2\x1f\xdaM\u0089g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xa4)\b\xe7\xfeS\x98\n\x9a\xbf@D\xe9W\xa5Kp\u973e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4)\xfa\x88s\x1f\xdd5\x0e\x8e\xcdn\xa5B\x96\xb6HO\u6549j\xc5\xc6-\x94\x86\a\x00\x00\xe0\x94\xa40\x99]\xdb\x18[\x98e\xdb\xe6%9\xad\x90\xd2.Ks\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa46\xc7TS\xcc\xcaJ\x1f\x1bb\xe5\u0123\r\x86\xdd\xe4\xbeh\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa47\xfen\xc1\x03\u028d\x15\x8fc\xb34\"N\u032c[>\xa3\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4;m\xa6\xcbz\xacW\x1d\xff'\xf0\x9d9\xf8F\xf57i\xb1\x89\x14\x99\x8f2\xacxp\x00\x00\u07d4\xa4;\x81\xf9\x93V\xc0\xaf\x14\x1a\x03\x01\rw\xbd\x04,q\xc1\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4>\x19G\xa9$+5Ua\xc3\n\x82\x9d\xfe\uc881Z\xf8\x89\xd2=\x99\x96\x9f\u0591\x80\x00\u07d4\xa4H\x9aP\xea\xd5\xd5DZ{\xeeM-U6\u00a7lA\xf8\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa4O\xe8\x00\xd9o\xca\xd7;qp\xd0\xf6\x10\u02cc\x06\x82\xd6\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa4T2\xa6\xf2\xac\x9dVW{\x93\x8a7\xfa\xba\xc8\xcc|F\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4f\xd7p\u0618\xd8\xc9\xd4\x05\xe4\xa0\xe5Q\xef\xaf\xcd\xe5<\xf9\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\xe0\x94\xa4g\a1\x17X\x93\xbb\xcf\xf4\xfa\x85\u0397\xd9O\xc5\x1cK\xa8\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4kC\x87\xfbM\xcc\xe0\x11\xe7nMsT}D\x81\xe0\x9b\xe5\x89Hz\x9a0E9D\x00\x00\u07d4\xa4l\xd27\xb6>\xeaC\x8c\x8e;e\x85\xf6y\xe4\x86\b2\xac\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4wy\u063c\x1c{\xce\x0f\x01\x1c\xcb9\xefh\xb8T\xf8\u078f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4\x82kl8\x82\xfa\xd0\xed\\\x8f\xbb%\xcc@\xccO3u\x9f\x89p\x1bC\xe3D3\xd0\x00\x00\u07d4\xa4\x87Y(E\x8e\xc2\x00]\xbbW\x8c\\\xd35\x80\xf0\xcf\x14R\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4\x9fR:\xa5\x13d\xcb\xc7\u0655\x16=4\xebY\r\xed/\b\x89\x90'B\x1b*\x9f\xbc\x00\x00\u07d4\xa4\xa4\x9f\v\xc8h\x8c\xc9\xe6\xdc\x04\xe1\xe0\x8dR\x10&\xe6Ut\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa4\xa7\xd3\x06\xf5\x10\xcdX5\x94(\xc0\xd2\xf7\xc3`\x9dVt\u05c9\xb5\x8c\xb6\x1c<\xcf4\x00\x00\u07d4\xa4\xa8:\a8y\x9b\x97\x1b\xf2\xdep\x8c.\xbf\x91\x1c\xa7\x9e\xb2\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa4\xb0\x9d\xe6\xe7\x13\xdciTnv\xef\n\xcf@\xb9O\x02A\xe6\x89\x11}\xc0b~\xc8p\x00\x00\xe0\x94\xa4\u04b4)\xf1\xadSI\xe3\x17\x04\x96\x9e\xdc_%\xee\x8a\xca\x10\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xa4\xd6\xc8.\u076eYG\xfb\xe9\xcd\xfb\xd5H\xae3\xd9\x1aq\x91\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4\xda4E\r\"\xec\x0f\xfc\xed\xe0\x00K\x02\xf7\x87.\xe0\xb7:\x89\x05\x0fafs\xf0\x83\x00\x00\xe0\x94\xa4\xddY\xab^Q}9\x8eI\xfaS\u007f\x89\x9f\xedL\x15\xe9]\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa4\xe6#E\x1e~\x94\xe7\u86e5\xed\x95\u0228:b\xff\xc4\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\xed\x11\xb0r\u061f\xb16u\x9f\u019bB\x8cH\xaa]L\xed\x89\x0e?\x15'\xa0<\xa8\x00\x00\u07d4\xa4\xfb\x14@\x9ag\xb4V\x88\xa8Y>\\\xc2\xcfYl\xedo\x11\x89a\t=|,m8\x00\x00\xe0\x94\xa5\x14\xd0\x0e\xddq\b\xa6\xbe\x83\x9ac\x8d\xb2AT\x18\x17A\x96\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x94\xa5\"\xde~\xb6\xae\x12PR*Q13\xa9;\xd4(IG\\\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa5$\xa8\xcc\xccIQ\x8d\x17\n2\x82p\xa2\xf8\x813\xfb\xaf]\x89\x0f\xf7\x02-\xac\x10\x8a\x00\x00\u07d4\xa59\xb4\xa4\x01\xb5\x84\xdf\xe0\xf3D\xb1\xb4\"\xc6UC\x16~.\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa5>\xadT\xf7\x85\n\xf2\x148\xcb\xe0z\xf6\x86'\x9a1[\x86\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa5C\xa0f\xfb2\xa8f\x8a\xa0sj\f\x9c\xd4\rx\t\x87'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa5gw\vj\xe3 \xbd\xdeP\xf9\x04\xd6c\xe7F\xa6\x1d\xac\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5h\xdbMW\xe4\xd6tb\xd73\u019a\x9e\x0f\xe2n!\x83'\x89;k\xff\x92f\xc0\xae\x00\x00\u07d4\xa5i\x8059\x1eg\xa4\x90\x13\xc0\x00 yY1\x14\xfe\xb3S\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4\xa5p\":\xe3\u02a8QA\x8a\x98C\xa1\xacU\xdbH$\xf4\xfd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa5s`\xf0\x02\xe0\xd6M-tE}\x8c\xa4\x85~\xe0\v\xcd\u07c9\x123\xe22\xf6\x18\xaa\x00\x00\u07d4\xa5u\xf2\x89\x1d\xcf\u0368<\\\xf0\x14t\xaf\x11\xee\x01\xb7-\u0089\x05l\xd5_\xc6M\xfe\x00\x00\u07d4\xa5x;\xf342\xff\x82\xacI\x89\x85\xd7\xd4`\xaeg\xec6s\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xa5\x87MuF5\xa7b\xb3\x81\xa5\xc4\u01d2H:\xf8\xf2=\x1d\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\xa5\xa4\"\u007fl\xf9\x88%\xc0\u057a\xffS\x15u,\xcc\x1a\x13\x91\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa5\xabK\xd3X\x8fF\xcb'.V\xe9=\xee\u04c6\xba\x8bu=\x89HB\xf0A\x05\x87,\x80\x00\xe0\x94\xa5\xba\xd8e\t\xfb\xe0\xe0\xe3\xc0\xe9?m8\x1f\x1a\xf6\xe9\u0501\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa5\xc36\b;\x04\xf9G\x1b\x8cn\xd76y\xb7Mf\xc3c\uc263e\nL\x9d \xe2\x00\x00\u07d4\xa5\xcd\x129\x92\x19K4\xc4x\x13\x140;\x03\xc5IH\xf4\xb9\x89l\xfc\xc3\xd9\x1d\xa5c\x00\x00\u07d4\xa5\u0578\xb6-\x00-\xef\x92A7\x10\xd1;o\xf8\xd4\xfc}\u04c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xa5\xd9ni}F5\x8d\x11\x9a\xf7\x81\x9d\xc7\b\u007fj\xe4\u007f\xef\x8a\x03\x17\xbe\xe8\xaf3\x15\xa7\x80\x00\u07d4\xa5\xde^CO\xdc\xddh\x8f\x1c1\xb6\xfbQ,\xb1\x96rG\x01\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xa5\xe0\xfc<:\xff\xed=\xb6q\tG\xd1\xd6\xfb\x01\u007f>'m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5\xe9;I\xea|P\x9d\xe7\xc4Ml\xfe\xdd\xefY\x10\u07aa\xf2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5\xe9\xcdKt%]\"\xb7\u0672z\xe8\xddC\xedn\xd0%+\x89)\x8d\xb2\xf5D\x11\u0640\x00\xe0\x94\xa5\xf0\a{5\x1flP\\\xd5\x15\u07e6\xd2\xfa\u007f\\L\u0487\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xa5\xf0u\xfd@\x135W{f\x83\u0081\xe6\xd1\x01C-\xc6\xe0\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xa5\xfe,\xe9\u007f\x0e\x8c8V\xbe\r\xe5\xf4\u0732\xce]8\x9a\x16\x89\x01=\xb0\xb8\xb6\x86>\x00\x00\u07d4\xa5\xffb\"-\x80\xc0\x13\xce\xc1\xa0\xe8\x85\x0e\xd4\xd3T\xda\xc1m\x89\vA\a\\\x16\x8b\x18\x00\x00\u07d4\xa6\t\xc2m\xd3P\xc25\xe4K+\x9c\x1d\xdd\xcc\u0429\xd9\xf87\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa6\f\x12\tuO]\x87\xb1\x81\xdaO\b\x17\xa8\x18Y\xef\x9f\u0609\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\xa6\x10\x1c\x96\x1e\x8e\x1c\x15y\x8f\xfc\xd0\xe3 \x1dw\x86\xec7:\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xa6\x13Ei\x96@\x8a\xf1\xc2\xe9>\x17w\x88\xabU\x89^+2\x8a\x01Y\x19\xffG|\x88\xb8\x00\x00\u07d4\xa6\x18\x87\x81\x8f\x91J \xe3\x10w)\v\x83qZk-n\xf9\x89e\xea=\xb7UF`\x00\x00\u07d4\xa6\x1aT\xdfxJD\xd7\x1bw\x1b\x871u\t!\x13\x81\xf2\x00\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa6\x1c\u06ed\xf0K\x1eT\u0203\xde`\x05\xfc\xdf\x16\xbe\xb8\xeb/\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa69\xac\xd9k1\xbaS\xb0\u0407c\"\x9e\x1f\x06\xfd\x10^\x9d\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa6BP\x10\x04\xc9\x0e\xa9\xc9\xed\x19\x98\xba\x14\nL\xd6,o_\x89\r\x94\xfb\x8b\x10\xf8\xb1\x80\x00\u07d4\xa6D\xed\x92,\xc27\xa3\xe5\u0117\x9a\x99Tw\xf3nP\xbcb\x89\x1f\xa7=\x84]~\x96\x00\x00\u07d4\xa6F\xa9\\moY\xf1\x04\xc6T\x1dw`uz\xb3\x92\xb0\x8c\x89\u3bb5sr@\xa0\x00\x00\xe0\x94\xa6HL\u0184\xc4\xc9\x1d\xb5>\xb6\x8aM\xa4Zjk\xda0g\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa6N_\xfbpL,\x919\xd7~\xf6\x1d\x8c\u07e3\x1dz\x88\xe9\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\xe0\x94\xa6T&\xcf\xf3x\xed#%5\x13\xb1\x9fIm\xe4_\xa7\u13ca\x01\x86P\x12|\xc3\u0700\x00\x00\u07d4\xa6jIc\xb2\u007f\x1e\xe1\x93+\x17+\xe5\x96N\r:\xe5KQ\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4\xa6\u007f8\x81\x95eB:\xa8_>:\xb6\x1b\xc7c\u02eb\x89\u0749sw\xb0\"\u01be\b\x00\x00\u07d4\xa6\x8c14E\xc2-\x91\x9e\xe4l\xc2\xd0\xcd\xff\x04:uX%\x89\x04\x13t\xfd!\xb0\u0600\x00\u07d4\xa6\x8e\f0\u02e3\xbcZ\x88>T\x03 \xf9\x99\xc7\xcdU\x8e\\\x89a\x9237b\xa5\x8c\x80\x00\u07d4\xa6\x90\xf1\xa4\xb2\n\xb7\xba4b\x86 \u079c\xa0@\xc4<\x19c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa6\x9d|\xd1}HB\xfe\x03\xf6*\x90\xb2\xfb\xf8\xf6\xaf{\xb3\x80\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa6\xa0\x82R\xc8YQw\xcc.`\xfc'Y>#y\xc8\x1f\xb1\x89\x01\x16Q\xac>zu\x80\x00\u07d4\xa6\xa0\xdeB\x1a\xe5Om\x17(\x13\b\xf5dm/9\xf7w]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa6\xb2\xd5s)s`\x10,\a\xa1\x8f\xc2\x1d\xf2\xe7I\x9f\xf4\xeb\x89\xd9o\u0390\u03eb\xcc\x00\x00\xe0\x94\xa6\xc9\x10\xceMIJ\x91\x9c\u036a\xa1\xfc;\x82\xaat\xba\x06\u03ca\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa6\u3ea3\x8e\x10J\x1e'\xa4\xd8(i\xaf\xb1\xc0\xaen\xff\x8d\x89\x01\x11@\ueb4bq\x00\x00\u07d4\xa6\xee\xbb\xe4d\u04d1\x87\xbf\x80\u029c\x13\xd7 '\xec[\xa8\xbe\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa6\xf6+\x8a=\u007f\x11\"\a\x01\xab\x9f\xff\xfc\xb3'\x95\x9a'\x85\x89\x1bn)\x1f\x18\u06e8\x00\x00\u07d4\xa6\xf93\a\xf8\xbc\xe01\x95\xfe\u0387 C\xe8\xa0?{\xd1\x1a\x89\x9csK\xadQ\x11X\x00\x00\u07d4\xa7\x01\xdfy\xf5\x94\x90\x1a\xfe\x14DH^k \u00fd\xa2\xb9\xb3\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa7\x02L\xfdt,\x1e\xc1<\x01\xfe\xa1\x8d0B\xe6_\x1d]\xee\x8a\x02c\x11\x9a(\xab\u0430\x80\x00\u07d4\xa7\x18\xaa\xadY\xbf9\\\xba+#\xe0\x9b\x02\xfe\f\x89\x81bG\x8960<\x97\xe4hx\x00\x00\u07d4\xa7$|S\xd0Y\xeb|\x93\x10\xf6(\xd7\xfclj\nw?\b\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xa7%7c\xcfJu\u07d2\xca\x1evm\xc4\xee\x8a'E\x14{\x8a\x02F7p\xe9\n\x8fP\x00\x00\u07d4\xa7.\xe6f\u0133^\x82\xa5\x06\x80\x8bD<\xeb\xd5\xc62\xc7\u0749+^:\xf1k\x18\x80\x00\x00\u07d4\xa7DD\xf9\x0f\xbbT\xe5o:\u0276\xcf\u032aH\x19\xe4aJ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa7GC\x9a\xd0\u04d3\xb5\xa08a\xd7r\x962m\u8edd\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa7`{BW;\xb6\xf6\xb4\xd4\xf2<~*&\xb3\xa0\xf6\xb6\xf0\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\xa7i)\x89\n{G\xfb\x85\x91\x96\x01lo\u0742\x89\u03b7U\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u0794\xa7kt?\x98\x1bi0r\xa11\xb2+\xa5\x10\x96\\/\xef\u05c8\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xa7m?\x15bQ\xb7,\f\xcfKG\xa39<\xbdoI\xa9\u0149Hz\x9a0E9D\x00\x00\u07d4\xa7t(\xbc\xb2\xa0\xdbv\xfc\x8e\xf1\xe2\x0eF\x1a\n2\u016c\x15\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xa7u\x8c\xec\xb6\x0e\x8faL\u0396\x13~\xf7+O\xbd\awJ\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa7w^J\xf6\xa2:\xfa \x1f\xb7\x8b\x91^Q\xa5\x15\xb7\xa7(\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\xa7\u007f>\u1793\x88\xbb\xbb\"\x15\xc6#\x97\xb9e`\x13#`\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa7\x85\x9f\xc0\u007fun\xa7\xdc\xeb\xbc\xcdB\xf0X\x17X-\x97?\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa7\x96lH\x9fLt\x8az\u902a'\xa5t%\x17g\xca\xf9\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa7\xa3\xbba9\xb0\xad\xa0\f\x1f\u007f\x1f\x9fV\u0654\xbaM\x1f\xa8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa7\xa3\xf1S\xcd\u00c8!\xc2\f]\x8c\x82A\xb2\x94\xa3\xf8+$\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa7\xa5\x17\u05ed5\x82\v\t\u0517\xfa~U@\xcd\xe9IXS\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa7\xc9\u04c8\xeb\xd8s\xe6k\x17\x13D\x83\x97\xd0\xf3\u007f\x8b\u04e8\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa7\u073b\xa9\xb9\xbfgb\xc1EAlPjq\u3d17 \x9c\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xa7\xe7O\v\xdb'\x8f\xf0\xa8\x05\xa6Ha\x8e\xc5+\x16o\xf1\xbe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa7\xe87r\xbc \x0f\x90\x06\xaa*&\r\xba\xa8H=\xc5+0\x89\vB\xd56f7\xe5\x00\x00\xe0\x94\xa7\xef5\u0387\xed\xa6\u008d\xf2HxX\x15\x05>\xc9zPE\x8a\x01\x0f\f\xe9I\xe0\x0f\x93\x00\x00\u07d4\xa7\xf9\"\f\x80G\x82k\xd5\xd5\x18?Ngjmw\xbf\xed6\x89\bPh\x97k\xe8\x1c\x00\x00\u07d4\xa8\a\x10O'\x03\xd6y\xf8\u07af\xc4B\xbe\xfe\x84\x9eB\x95\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\f\xb1s\x8b\xac\b\xd4\xf9\xc0\x8bM\xef\xf5\x15T_\xa8XO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa8\x19\xd2\xec\xe1\"\xe0(\xc8\xe8\xa0J\x06M\x02\xb9\x02\x9b\b\xb9\x8965\u026d\xc5\u07a0\x00\x00\u0794\xa8%\xfdZ\xbby&\xa6|\xf3k\xa2F\xa2K\xd2{\xe6\xf6\xed\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4\xa8(U9\x86\x9d\x88\xf8\xa9aS7Uq}~\xb6Uv\xae\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa83\x82\xb6\xe1Rg\x97J\x85P\xb9\x8fqv\xc1\xa3S\xf9\xbe\x89\xbf\xfd\xaf/\xc1\xb1\xa4\x00\x00\xe0\x94\xa8DlG\x81\xa77\xacC(\xb1\xe1[\x8a\v?\xbb\x0f\xd6h\x8a\x04\x87\x94\xd1\xf2F\x19*\x00\x00\u07d4\xa8E[A\x17e\u0590\x1e1\x1erd\x03\t\x1eB\xc5f\x83\x89\xb7:\xec;\xfe\x14P\x00\x00\xe0\x94\xa8f\x13\xe6\u0124\xc9\xc5_\\\x10\xbc\xda2\x17]\u02f4\xaf`\x8a\x02C\xd6\xc2\xe3k\xe6\xae\x00\x00\u07d4\xa8m\xb0}\x9f\x81/G\x96b-@\xe0=\x13Xt\xa8\x8at\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa8\u007fz\xbdo\xa3\x11\x94(\x96x\xef\xb6<\xf5\x84\xee^*a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xa8\x80\u2a3f\x88\xa1\xa8&H\xb4\x01W\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa8\x9d\xf3HY\xed\xd7\xc8 \u06c8w@\xd8\xff\x9e\x15\x15|{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\xa4<\x00\x91\x00al\xb4\xaeN\x03?\x1f\xc5\xd7\xe0\xb6\xf1R\x89\u0548\xd0x\xb4?M\x80\x00\u07d4\xa8\xa7\b\xe8O\x82\u06c6\xa3U\x02\x19;Ln\xe9\xa7n\xbe\x8f\x897\b\xba\xed=h\x90\x00\x00\xe0\x94\xa8\xa7\xb6\x8a\u06b4\xe3\xea\xdf\xf1\x9f\xfaX\xe3J?\xce\xc0\xd9j\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xa8\xa8\xdb\xdd\x1a\x85\u047e\xee%i\xe9\x1c\xccM\t\xae\u007fn\xa1\x8a\x01:k+VHq\xa0\x00\x00\u07d4\xa8\xac\xa7H\xf9\xd3\x12\xect\u007f\x8bex\x14&\x94\xc7\xe9\xf3\x99\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\xb6[\xa3\x17\x1a?w\xa65\v\x9d\xaf\x1f\x8dU\xb4\xd2\x01\xeb\x89(b\xf3\xb0\xd2\"\x04\x00\x00\u07d4\xa8\xbe\xb9\x1c+\x99\u0216J\xa9[kJ\x18K\x12i\xfc4\x83\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u0794\xa8\xc0\xb0/\xaf\x02\xcbU\x19\u0768\x84\xde{\xbc\x8c\x88\xa2\u0681\x88\xe7\xc2Q\x85\x05\x06\x00\x00\u07d4\xa8\xc1\u05aaA\xfe=e\xf6{\xd0\x1d\xe2\xa8f\xed\x1e\u066eR\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\xa8\xca\xfa\xc3\"\x80\xd0!\x02\v\xf6\xf2\xa9x(\x83\u05ea\xbe\x12\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa8\xdb\v\x9b \x14S3A<;\fb\xf5\xf5.\u0544\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa8\xf3\u007f\n\xb3\xa1\xd4H\xa9\xe3\xce@\x96_\x97\xa6F\b:4\x89\x11\xe0\xe4\xf8\xa5\v\xd4\x00\x00\u07d4\xa8\xf8\x9d\xd5\xccnd\u05f1\xee\xac\xe0\a\x02\x02,\xd7\xd2\xf0=\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\xa9\x04v\xe2\xef\xdf\xeeO8{\x0f2\xa5\x06x\xb0\xef\xb5s\xb5\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa9\x14PF\xfa6(\xcf_\xd4\xc6\x13\x92{\xe51\xe6\xdb\x1f\u0749\x06\x12O\xee\x99;\xc0\x00\x00\u07d4\xa9\x14\u0375q\xbf\xd9=d\xdaf\xa4\xe1\b\xea\x13NP\xd0\x00\x89M\x878\x99G\x13y\x80\x00\xe0\x94\xa9\x1aZ{4\x1f\x99\xc55\x14N \xbe\x9ck;\xb4\u008eM\x8a\x01&u:\xa2$\xa7\v\x00\x00\u07d4\xa9%%Q\xa6$\xaeQ7\x19\u06beR\a\xfb\xef\xb2\xfdwI\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa9'\u050b\xb6\u02c1K\xc6\t\xcb\u02a9\x15\x1f]E\x9a'\xe1\x89\x0e\xb95\t\x00d\x18\x00\x00\u07d4\xa9)\u023dq\xdb\f0\x8d\xac\x06\b\n\x17G\xf2\x1b\x14e\xaa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa9K\xbb\x82\x14\u03cd\xa0\xc2\xf6h\xa2\xacs\xe8bHR\x8dK\x894\n\xad!\xb3\xb7\x00\x00\x00\u07d4\xa9Q\xb2D\xffP\u03eeY\x1d^\x1a\x14\x8d\xf6\xa98\xef*\x1a\x89^\x00\x15\x84\xdf\xcfX\x00\x00\u07d4\xa9`\xb1\xca\xdd;\\\x1a\x8el\xb3\xab\xca\xf5.\xe7\xc3\xd9\xfa\x88\x89R\x8b\xc3T^Rh\x00\x00\u07d4\xa9a\x17\x1fSB\xb1s\xddp\xe7\xbf\xe5\xb5\xca#\x8b\x13\xbc\u0749\xb8'\x94\xa9$O\f\x80\x00\u07d4\xa9u\xb0w\xfc\xb4\u030e\xfc\xbf\x83\x84Y\xb6\xfa$:AY\u0589\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xa9{\xeb:H\xc4_\x15((L\xb6\xa9_}\xe4S5\x8e\u018a\x06\x90\x83l\n\xf5\xf5`\x00\x00\u07d4\xa9~\a!DI\x9f\xe5\xeb\xbd5J\xcc~~\xfbX\x98]\b\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xa9\x86v/zO)O.\v\x172y\xad,\x81\xa2\"4X\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa9\x8f\x10\x985\xf5\xea\xcd\x05Cd|4\xa6\xb2i\xe3\x80/\xac\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa9\x97\xdf\u01d8j'\x05\bH\xfa\x1cd\u05e7\xd6\xe0z\u0322\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\u07d4\xa9\x99\x91\u03bd\x98\xd9\xc88\xc2_zt\x16\xd9\xe2D\xca%\r\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa9\xa1\xcd\xc3;\xfd7o\x1c\rv\xfbl\x84\xb6\xb4\xac'Mh\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa9\xa8\xec\xa1\x1a#\xd6F\x89\xa2\xaa>A}\xbb=3k\xb5\x9a\x89\x0e4S\xcd;g\xba\x80\x00\u07d4\xa9\xac\xf6\x00\b\x1b\xb5[\xb6\xbf\xba\xb1\x81_\xfcN\x17\xe8Z\x95\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa9\xad\x19&\xbcf\xbd\xb31X\x8e\xa8\x197\x88SM\x98,\x98\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xa9\xaf!\xac\xbeH/\x811\x89j\"\x806\xbaQ\xb1\x94S\u00c9\x02\xb5\xe0!\x98\f\xc1\x80\x00\xe0\x94\xa9\xb2\xd2\xe0IN\xab\x18\xe0}7\xbb\xb8V\xd8\x0e\x80\xf8L\u04ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa9\xbaoA;\x82\xfc\xdd\xf3\xaf\xfb\xbd\u0412\x87\xdc\xf5\x04\x15\u0289\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa9\xbe\x88\xad\x1eQ\x8b\v\xbb\x02J\xb1\xd8\xf0\xe7?y\x0e\fv\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xa9\xbf\xc4\x10\xdd\xdb q\x1eE\xc0s\x87\xea\xb3\n\x05N\x19\xac\x89>\x99`\x1e\xdfNS\x00\x00\u07d4\xa9\u0522\xbc\xbe[\x9e\bi\xd7\x0f\x0f\xe2\xe1\u05aa\xcdE\xed\u0149\n\xc6\xe7z\xb6c\xa8\x00\x00\xe0\x94\xa9\xd6KO;\xb7\x85\a\"\xb5\x8bG\x8b\xa6\x917^\"NB\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa9\xd6\xf8q\xcax\x1au\x9a \xac:\u06d7,\xf1()\xa2\b\x892$\xf4'#\xd4T\x00\x00\xe0\x94\xa9\xdc\x04$\u0196\x9dy\x83X\xb3\x93\xb1\x93:\x1fQ\xbe\xe0\n\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa9\xe1\x94f\x1a\xacpN\xe9\u07a0C\x97N\x96\x92\xde\xd8J]\x89\x1a&\xa5\x14\"\xa0p\x00\x00\u07d4\xa9\xe2\x837\xe65q\x93\xd9\xe2\xcb#k\x01\xbeD\xb8\x14'\u07c9wC\"\x17\xe6\x83`\x00\x00\u07d4\xa9\xe6\xe2^ekv%Xa\x9f\x14z!\x98[\x88t\xed\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa9\xe9\xdb\xcez,\xb06\x94y\x98\x97\xbe\xd7\xc5M\x15_\u06a8\x89\n\xb5\xae\x8f\u025de\x80\x00\u07d4\xa9\xed7{}n\xc2Yq\xc1\xa5\x97\xa3\xb0\xf3\xbe\xadW\u024f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xaa\x02\x00\xf1\xd1~\x9cT\xda\x06G\xbb\x969]W\xa7\x858\u06099>\xf1\xa5\x12|\x80\x00\x00\u07d4\xaa\f\xa3ss7\x17\x8a\f\xaa\xc3\t\x9cXK\x05lV0\x1c\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xaa\x13kG\x96+\xb8\xb4\xfbT\r\xb4\xcc\xf5\xfd\xd0B\xff\xb8\u03c9\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\xaa\x14B-o\n\xe5\xa7X\x19N\xd1W\x80\xc88\xd6\u007f\x1e\xe1\x8a\x06\t2\x05lD\x9d\xe8\x00\x00\u07d4\xaa\x16&\x9a\xac\x9c\r\x800h\xd8/\u01d1Q\xda\xdd3Kf\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xaa\x16p&\u04da\xb7\xa8V5\x94N\xd9\xed\xb2\xbf\xeb\xa1\x18P\x8a\x01\xc1\xd5\xe2\x1bO\xcfh\x00\x00\u07d4\xaa\x1b7h\xc1m\x82\x1fX\x0ev\xc8\xe4\xc8\xe8m}\u01c8S\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xaa\x1d\xf9.Q\xdf\xf7\v\x19s\xe0\xe9$\xc6b\x87\xb4\x94\xa1x\x89\x1c\xf8J0\xa0\xa0\xc0\x00\x00\u07d4\xaa,g\x00\x96\xd3\xf990S%B~\xb9U\xa8\xa6\r\xb3\u0149l\x95Y\x06\x99#-\x00\x00\u07d4\xaa15\xcbT\xf1\x02\xcb\xef\xe0\x9e\x96\x10:\x1ayg\x18\xffT\x89\x03\"\"\xd9\xc31\x94\x00\x00\u07d4\xaa2\x1f\xdb\xd4I\x18\r\xb8\xdd\xd3O\x0f\xe9\x06\xec\x18\xee\t\x14\x89%\"H\u07b6\xe6\x94\x00\x00\xe0\x94\xaa9%\xdc\"\v\xb4\xae!w\xb2\x880x\xb6\xdc4l\xa1\xb2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xaa?)`\x1a\x131t^\x05\xc4(0\xa1^q\x93\x8ab7\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94\xaaG\xa4\xff\xc9y622\u025b\x99\xfa\xda\x0f'4\xb0\xae\xee\x8a\x01\xb8H\x9d\xf4\xdb\xff\x94\x00\x00\u07d4\xaaI=?O\xb8fI\x1c\xf8\xf8\x00\xef\xb7\xe22N\xd7\xcf\xe5\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xaaV\xa6]\u012b\xb7/\x11\xba\xe3+o\xbb\aDG\x91\xd5\u0249(\x94\xe9u\xbfIl\x00\x00\xe0\x94\xaaZ\xfc\xfd\x83\t\xc2\u07dd\x15\xbe^jPN}pf$\u014a\x01<\xf4\"\xe3\x05\xa17\x80\x00\u07d4\xaa\x8e\xb0\x82;\a\xb0\xe6\xd2\n\xad\xda\x0e\x95\xcf85\xbe\x19.\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xaa\x91#~t\r%\xa9/\u007f\xa1F\xfa\xa1\x8c\xe5m\xc6\xe1\xf3\x892$\xf4'#\xd4T\x00\x00\u07d4\xaa\x96\x0e\x10\xc5#\x91\xc5N\x158|\xc6z\xf8'\xb51m\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\x9b\xd4X\x955\xdb'\xfa+\xc9\x03\xca\x17\xd6y\xddeH\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\xa8\xde\xfe\x11\xe3a?\x11\x06\u007f\xb9\x83bZ\b\x99Z\x8d\xfc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaa\xaa\xe6\x8b2\x14\x02\xc8\xeb\xc14h\xf3A\xc6<\f\xf0?\u0389Rf<\u02b1\xe1\xc0\x00\x00\u07d4\xaa\xad\x1b\xaa\xdeZ\xf0N+\x17C\x9e\x93Y\x87\xbf\x8c+\xb4\xb9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xaa\xb0\n\xbfX(\xd7\xeb\xf2kG\u03ac\u0378\xba\x032Qf\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xaa\xbd\xb3\\\x15\x14\x98J\x03\x92\x13y?3E\xa1h\xe8\x1f\xf1\x89\x10\xca\u0216\xd29\x00\x00\x00\u07d4\xaa\xca`\xd9\xd7\x00\u7156\xbb\xbb\xb1\xf1\xe2\xf7\x0fF'\xf9\u060965\xbbw\xcbK\x86\x00\x00\u07d4\xaa\xce\u0629V;\x1b\xc3\x11\xdb\xdf\xfc\x1a\xe7\xf5u\x19\xc4D\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\u04b7\xf8\x10f\x95\a\x8el\x13\x8e\xc8\x1at\x86\xaa\xca\x1e\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaa\xe6\x1eC\xcb\r\f\x96\xb3\x06\x99\xf7~\x00\xd7\x11\u0423\x97\x9b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaa\xe72\xed\xa6Y\x88\u00e0\f\u007fG/5\x1cF;\x1c\x96\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\xf0#\xfe\U0009091b\xb7\x8b\xb7\xab\xc9]f\x9cP\xd5(\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xaa\xf5\xb2\a\xb8\x8b\r\xe4\xac@\xd7G\xce\xe0n\x17-\xf6\xe7E\x8a\x06\xa7\xb7\x1d\u007fQ\u0410\x00\x00\u07d4\xaa\xf9\xeeK\x88lm\x1e\x95Io\xd2t#[\xf4\xec\xfc\xb0}\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xaa\xfb{\x01:\xa1\xf8T\x1c~2{\xf6P\xad\xbd\x19L \x8f\x89I\x9e\t-\x01\xf4x\x00\x00\xe0\x94\xab\t\x863\xee\xee\f\xce\xfd\xf62\xf9WTV\xf6\u0740\xfc\x86\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xab\f\xedv.\x16a\xfa\xe1\xa9*\xfb\x14\b\x88\x94\x13yH%\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xab\x14\xd2!\xe3=TF)\x19\x8c\u0416\xedc\u07e2\x8d\x9fG\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xab \x9f\u0729y\u0426G\x01\n\xf9\xa8\xb5/\xc7\xd2\r\x8c\u044a\x01\xee\xe2S,|-\x04\x00\x00\u07d4\xab'\xbax\xc8\xe5\xe3\xda\xef1\xad\x05\xae\xf0\xff\x03%r\x1e\b\x89\x19^\xce\x00n\x02\xd0\x00\x00\u07d4\xab(q\xe5\a\u01fe9eI\x8e\x8f\xb4b\x02Z\x1a\x1cBd\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xab8a\"o\xfe\xc1(\x91\x87\xfb\x84\xa0\x8e\xc3\xed\x042d\xe8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab=\x86\xbc\x82\x92~\f\xd4!\xd1F\xe0\u007f\x91\x93'\xcd\xf6\xf9\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xab>b\xe7z\x8b\"^A\x15\x92\xb1\xaf0\aR\xfeA$c\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xab>x)K\xa8\x86\xa0\xcf\xd5\xd3H\u007f\xb3\xa3\a\x8d3\x8dn\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xab@\x04\xc0@?~\xab\xb0\xeaXo!!V\xc4 =g\xf1\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xabAo\xe3\rX\xaf\xe5\xd9EL\u007f\xce\u007f\x83\v\xccu\x03V\x89\x0657\x01\xc6\x05\u06c0\x00\u07d4\xabEr\xfb\xb1\xd7+W]i\xecj\xd1s3\x87>\x85R\xfc\x89lj\xc5L\xdahG\x00\x00\u07d4\xabZy\x01av2\ts\xe8\xcd8\xf67U0\x02%1\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab]\xfc\x1e\xa2\x1a\xdcB\u03cc?n6\x1e$?\xd0\xdaa\xe5\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xabke\xea\xb8\xdf\xc9\x17\xec\x02Q\xb9\xdb\x0e\u03e0\xfa\x03(I\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xabp\x91\x93.K\u00dd\xbbU#\x80\u0293O\xd7\x16m\x1en\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\xabt\x16\xff2%IQ\u02fcbN\xc7\xfbE\xfc~\u02a8r\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xab|B\xc5\xe5-d\x1a\a\xadu\t\x9cb\x92\x8b\u007f\x86b/\x89\x126\x1a\xa2\x1d\x14\xba\x00\x00\u07d4\xab}T\xc7\xc6W\x0e\xfc\xa5\xb4\xb8\xcep\xf5*Ws\xe5\xd5;\x89\x0f(:\xbe\x9d\x9f8\x00\x00\u07d4\xab~\v\x83\xed\x9aBLm\x1ejo\x87\xa4\xdb\xf0d\t\xc7\u0589\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xab\x84\xa0\xf1G\xad&T\x00\x00+\x85\x02\x9aA\xfc\x9c\xe5\u007f\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab\x93\xb2n\xce\n\n\xa2\x13e\xaf\xed\x1f\xa9\xae\xa3\x1c\xd5Dh\x89W+{\x98sl \x00\x00\u07d4\xab\x94\x8aJ\xe3y\\\xbc\xa11&\xe1\x92S\xbd\xc2\x1d:\x85\x14\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xab\x9a\xd3n\\t\xce.\x969\x9fW\x83\x941\xd0\u77d6\xab\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\xab\xb2\xe6\xa7*@\xban\xd9\b\u037c\xec\x91\xac\xfdwx0\xd1dcG\x8a\xe0\xfcw \x89\a?u\u0460\x85\xba\x00\x00\xe0\x94\xab\u071f\x1b\xcfM\x19\xee\x96Y\x100\xe7r\xc340/}\x83\x8a\b~^\x11\xa8\x1c\xb5\xf8\x00\x00\u07d4\xab\xde\x14{*\xf7\x89\ua946T~f\xc4\xfa&d\xd3(\xa4\x89\rk`\x81\xf3L\x12\x80\x00\xe0\x94\xab\xe0|\xedj\xc5\xdd\xf9\x91\xef\xf6\xc3\xda\"jt\x1b\xd2C\xfe\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xab\xf1/\xa1\x9e\x82\xf7lq\x8f\x01\xbd\xca\x00\x03gE#\xef0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xab\xf7(\u03d3\x12\xf2!(\x02NpF\xc2Q\xf5\xdcY\x01\xed\x8a\x06A\xe8\xa15c\xd8\xf8\x00\x00\u07d4\xab\xf8\xff\xe0p\x8a\x99\xb5(\xcc\x1e\xd4\xe9\xceK\r\x060\xbe\x8c\x89z\xb5\u00ae\xee\xe68\x00\x00\u07d4\xab\xfc\xf5\xf2P\x91\xceW\x87_\xc6t\xdc\xf1\x04\xe2\xa7=\xd2\xf2\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xab\xfe\x93d%\xdc\u01f7K\x95P\x82\xbb\xaa\xf2\xa1\x1dx\xbc\x05\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xac\x02OYO\x95X\xf0ICa\x8e\xb0\xe6\xb2\xeeP\x1d\xc2r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\x12*\x03\xcd\x05\x8c\x12._\xe1{\x87/Hw\xf9\u07d5r\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xac\x14.\xda\x11W\xb9\xa9\xa6C\x90\xdf~j\xe6\x94\xfa\u0249\x05\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\x1d\xfc\x98Kq\xa1\x99)\xa8\x1d\x81\xf0J|\xbb\x14\a7\x03\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xac!\xc1\xe5\xa3\xd7\xe0\xb5\x06\x81g\x9d\xd6\u01d2\xdb\u0287\xde\u02ca\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xac(\x89\xb5\x96o\f\u007f\x9e\xdbB\x89\\\xb6\x9d\x1c\x04\xf9#\xa2\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xac(\xb5\xed\xea\x05\xb7o\x8c_\x97\bEA'|\x96ijL\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xac,\x8e\t\xd0d\x93\xa68XC{\xd2\v\xe0\x19bE\x03e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xac.vm\xac?d\x8fcz\xc6q?\u0770h\xe4\xa4\xf0M\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\xac9\x00)\x8d\xd1M|\xc9mJ\xbbB\x8d\xa1\xba\xe2\x13\xff\xed\x8a\x05<\xa1)t\x85\x1c\x01\x00\x00\u07d4\xac=\xa5&\xcf\u0388)s\x02\xf3LI\xcaR\r\xc2q\xf9\xb2\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xacD`\xa7nm\xb2\xb9\xfc\xd1R\xd9\xc7q\x8d\x9a\xc6\xed\x8co\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xacJ\xcf\xc3n\xd6\tJ'\xe1\x18\xec\xc9\x11\xcdG>\x8f\xb9\x1f\x89a\x91>\x14@<\f\x00\x00\u07d4\xacL\xc2V\xaet\xd6$\xac\xe8\r\xb0x\xb2 \u007fW\x19\x8fk\x89lyt\x12?d\xa4\x00\x00\u07d4\xacN\xe9\xd5\x02\xe7\xd2\xd2\xe9\x9eY\xd8\xca}_\x00\xc9KM\u058965\u026d\xc5\u07a0\x00\x00\u07d4\xacR\xb7~\x15fH\x14\xf3\x9eO'\x1b\xe6A0\x8d\x91\xd6\u0309\v\xed\x1d\x02c\xd9\xf0\x00\x00\u07d4\xacY\x99\xa8\x9d-\u0486\u0568\fm\xee~\x86\xaa\xd4\x0f\x9e\x12\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xac_br1H\r\r\x950.m\x89\xfc2\xcb\x1dO\xe7\xe3\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xac`\x8e+\xac\x9d\xd2\a(\u0494~\xff\xbb\xbf\x90\n\x9c\xe9K\x8a\x01EK\r\xb3uh\xfc\x00\x00\u07d4\xacm\x02\xe9\xa4k7\x9f\xacJ\u0271\u05f5\xd4{\xc8P\xce\x16\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xacoh\xe87\xcf\x19a\xcb\x14\xabGDm\xa1h\xa1m\u0789\x89Hz\x9a0E9D\x00\x00\u07d4\xacw\xbd\xf0\x0f\u0558[]\xb1+\xbe\xf8\x008\n\xbc*\x06w\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xac~\x03p'#\xcb\x16\xee'\xe2-\u0438\x15\xdc-\\\xae\x9f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xac\x8bP\x9a\xef\xea\x1d\xbf\xaf+\xb35\x00\xd6W\vo\xd9mQ\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xac\x8e\x87\xdd\xda^x\xfc\xbc\xb9\xfa\u007f\xc3\xce\x03\x8f\x9f}.4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xac\x9f\xffh\xc6\x1b\x01\x1e\xfb\xec\xf08\xedr\u06d7\xbb\x9er\x81\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xac\xa1\xe6\xbcd\xcc1\x80\xf6 \xe9M\u0171\xbc\xfd\x81X\xe4]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\xa2\xa883\v\x170-\xa71\xd3\r\xb4\x8a\x04\xf0\xf2\a\xc1\x89Hz\x9a0E9D\x00\x00\u07d4\xac\xaa\xdd\xcb\xf2\x86\xcb\x0e!]\xdaUY\x8f\u007f\xf0\xf4\xad\xa5\u018965\u026d\xc5\u07a0\x00\x00\u07d4\xac\xb9C8UK\u0108\u0308\xae-\x9d\x94\b\rk\u07c4\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xac\xbc-\x19\xe0l;\xab\xbb[o\x05+k\xf7\xfc7\xe0r)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\xbd\x18U\x89\xf7\xa6\x8ag\xaaK\x1b\xd6Pw\xf8\xc6NN!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\xc0bp,Ya]4D\xefb\x14\xb8\x86+\x00\x9a\x02\xed\x89QO\xcb$\xff\x9cP\x00\x00\u07d4\xac\xc0\x90\x9f\xda.\xa6\xb7\xb7\xa8\x8d\xb7\xa0\xaa\xc8h\t\x1d\xdb\xf6\x89\x013v_\x1e&\u01c0\x00\u07d4\xac\xc1\u01c7\x86\xabM+;'q5\xb5\xba\x12>\x04\x00Hk\x89\x04E\x91\xd6\u007f\xec\xc8\x00\x00\u07d4\xac\xc4j*U\\t\xde\u0522\xbd\tN\x82\x1b\x97\x84;@\xc0\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xac\u015f;0\xce\xff\xc5da\xcc[\x8d\xf4\x89\x02$\x0e\x0e{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\xce\x01\xe0\xa7\x06\x10\xdcp\xbb\x91\xe9\x92o\xa9\x95\u007f7/\xba\x89\x1d\x1c_>\xda \xc4\x00\x00\u07d4\xac\xd8\u0751\xf7\x14vLEg|c\xd8R\xe5n\xb9\xee\xce.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\u2af6;\x06\x04@\x9f\xbd\xe3\xe7\x16\u0487mD\xe8\xe5\u0749\b=lz\xabc`\x00\x00\xe0\x94\xac\xec\x91\xefiA\xcfc\v\xa9\xa3\u71e0\x12\xf4\xa2\xd9\x1d\u050a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xad\nJ\xe4x\xe9cn\x88\xc6\x04\xf2B\xcfT9\xc6\xd4V9\x89\xbe\xd1\xd0&=\x9f\x00\x00\x00\u07d4\xad\x17\x99\xaa\xd7`+E@\u0343/\x9d\xb5\xf1\x11P\xf1hz\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xad\x1dh\xa08\xfd%\x86\x06~\xf6\xd15\xd9b\x8ey\xc2\xc9$\x89\xfe\t\xa5'\x9e*\xbc\x00\x00\u07d4\xad*\\\x00\xf9#\xaa\xf2\x1a\xb9\xf3\xfb\x06n\xfa\n\x03\xde/\xb2\x8965\xbbw\xcbK\x86\x00\x00\u07d4\xad5e\xd5+h\x8a\xdd\xed\b\x16\x8b-8r\xd1}\n&\xae\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xad7|\xd2^\xb5>\x83\xae\t\x1a\n\x1d+E\x16\xf4\x84\xaf\u0789i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xadAM)\xcb~\xe9s\xfe\xc5N\"\xa3\x88I\x17\x86\xcfT\x02\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xadD5~\x01~$OGi1\u01f8\x18\x9e\xfe\xe8\n]\n\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xadW\xaa\x9d\x00\xd1\fC\x9b5\xef\xcc\v\xec\xac.9U\xc3\x13\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xadY\xa7\x8e\xb9\xa7J\u007f\xbd\xae\xfa\xfa\x82\xea\u0684u\xf0\u007f\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xadZ\x8dV\x01L\xfc\xb3`\xf4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xadr\x81!\x87?\x04V\xd0Q\x8b\x80\xabe\x80\xa2\x03pe\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xads,\x97e\x93\xee\xc4x;N.\xcdy9yx\v\xfe\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xad}\xd0S\x85\x9e\xdf\xf1\xcbo\x9d*\xcb\xedm\xd5\xe32Bo\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xad\x80\xd8e\xb8\\4\xd2\xe6IK.z\xef\xeak\x9a\xf1\x84\u06c9\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xad\x8b\xfe\xf8\u018aH\x16\xb3\x91o5\xcb{\xfc\xd7\xd3\x04\tv\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xad\x8eH\xa3wi]\xe0\x146:R:(\xb1\xa4\fx\xf2\b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xad\x91\n#\u0585\x06\x13eJ\xf7\x863z\u04a7\bh\xacm\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xad\x92~\x03\xd1Y\x9ax\xca+\xf0\xca\u04a1\x83\xdc\xebq\xea\xc0\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xad\x92\xca\x06n\xdb|q\x1d\xfc[\x16a\x92\xd1\xed\xf8\xe7q\x85\x8a\a\x9f\x90\\o\xd3N\x80\x00\x00\u07d4\xad\x94#_\u00f3\xf4z$\x13\xaf1\u8111I\b\xef\fE\x89\x1b\x1b\x01B\xd8\x15\x84\x00\x00\u07d4\xad\x9e\x97\xa0H/5:\x05\xc0\xf7\x92\xb9w\xb6\xc7\xe8\x11\xfa_\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xad\x9fL\x89\n;Q\x1c\xeeQ\xdf\xe6\xcf\xd7\xf1\t;vA,\x89\x1bv|\xbf\xeb\f\xe4\x00\x00\u07d4\xad\xaa\x0eT\x8c\x03Z\xff\xedd\xcag\x8a\x96?\xab\xe9\xa2k\xfd\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\xad\xb9H\xb1\xb6\xfe\xfe }\xe6^\x9b\xbc-\xe9\x8e`]\vW\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xad\xc1\x9e\xc85\xaf\xe3\u5347\u0713\xa8\xa9!<\x90E\x13&\x89j\xdb\xe54\"\x82\x00\x00\x00\u07d4\xad\xc8\"\x8e\xf9(\xe1\x8b*\x80}\x00\xfb1\xfcgX\x15\xaa\x00\x00\u07d4\xad\xff\r\x1d\v\x97G\x1ev\u05c9\xd2\u470at\xf9\xbdT\xff\x89e\xea=\xb7UF`\x00\x00\u07d4\xae\x06,D\x86\x18d0u\xdez\x0004-\xce\xd6=\xba\u05c9,\xc6\u034c\u0082\xb3\x00\x00\xe0\x94\xae\x10\xe2z\x01O\r0k\xaf&mH\x97\u021a\xee\xe2\xe9t\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xae\x12k8,\xf2W\xfa\xd7\xf0\xbc}\x16)~T\xccrg\u0689\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x13\xa0\x85\x11\x11\x0f2\xe5;\xe4\x12xE\xc8C\xa1\xa5|{\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xae\x17\x9aF\r\xb6c&t=$\xe6u#\xa5{$m\xaf\u007f\x8a\x01\x00\a\xae|\xe5\xbb\xe4\x00\x00\u07d4\xae\"(ey\x90y\xaa\xf4\xf0gJ\f\u06ab\x02\xa6\xd5p\xff\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xae#\x9a\xcf\xfdN\xbe.\x1b\xa5\xb4\x17\x05r\xdcy\xcce3\xec\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xae/\x9c\x19\xacv\x13e\x94C#\x93\xb0G\x1d\b\x90!d\u04c9%\xdf\x05\u01a8\x97\xe4\x00\x00\u07d4\xae4\x86\x1d4\"S\x19O\xfcfR\xdf\xdeQ\xabD\xca\xd3\xfe\x89\x19F\bhc\x16\xbd\x80\x00\u07d4\xae6\xf7E!!\x91>\x80\x0e\x0f\xcd\x1ae\xa5G\x1c#\x84o\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\xae?\x98\xa4C\xef\xe0\x0f>q\x1dR]\x98\x94\u071aa\x15{\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xaeG\xe2`\x9c\xfa\xfe6\x9df\xd4\x15\xd99\xde\x05\b\x1a\x98r\x8a\x05\xba\xec\xf0%\xf9\xb6P\x00\x00\u07d4\xaeO\x12.5\xc0\xb1\xd1\xe4\x06\x92\x91E|\x83\xc0\u007f\x96_\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaePU\x81L\xb8\xbe\f\x11{\xb8\xb1\xc8\u04b6;F\x98\xb7(\x89\x01\xbc\x93.\xc5s\xa3\x80\x00\u07d4\xaeS\x8cs\u0173\x8d\x8dXM~\xbd\xad\xef\xb1\\\xab\xe4\x83W\x896'\xe8\xf7\x127<\x00\x00\u07d4\xaeW\xcc\x12\x9a\x96\xa8\x99\x81\xda\xc6\r/\xfb\x87}]\xc5\xe42\x89<:#\x94\xb3\x96U\x00\x00\u07d4\xaeZ\xa1\xe6\u00b6\x0fo\xd3\xef\xe7!\xbbJq\x9c\xbe=o]\x89+$\u01b5Z^b\x00\x00\u07d4\xae\\\x9b\xda\xd3\xc5\u0221\"\x04D\xae\xa5\xc2)\xc1\x83\x9f\x1dd\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xae\\\xe35Z{\xa9\xb32v\f\tP\u00bcE\xa8_\xa9\xa0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xae]\"\x1a\xfc\xd3\u0493U\xf5\b\xea\xdf\xca@\x8c\xe3<\xa9\x03\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xaec[\xf781\x11\x9d-)\xc0\xd0O\xf8\xf8\xd8\u0425zF\x89Hz\x9a0E9D\x00\x00\xe0\x94\xaed\x81U\xa6X7\x0f\x92\x9b\xe3\x84\xf7\xe0\x01\x04~I\xddF\x8a\x02\xdf$\xae2\xbe D\x00\x00\xe0\x94\xaeo\fs\xfd\xd7|H\x97'Q!t\u0675\x02\x96a\x1cL\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xaep\xe6\x9d,J\n\xf8\x18\x80{\x1a'\x05\xf7\x9f\u0435\xdb\u01095e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xaew9\x12N\xd1S\x05%\x03\xfc\x10\x14\x10\xd1\xff\xd8\xcd\x13\xb7\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xaex\xbb\x84\x919\xa6\xba8\xae\x92\xa0\x9ai`\x1c\xc4\xcbb\u0449\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xae\x84\"\x10\xf4M\x14\u0124\u06d1\xfc\x9d;;P\x01O{\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xae\x84.\x81\x85\x8e\xcf\xed\xf6Plhm\xc2\x04\xac\x15\xbf\x8b$\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xae\x89T\xf8\xd6\x16m\xe5\a\xcfa)}\x0f\xc7\xcak\x9eq(\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x9e\xcdk\u0755.\xf4\x97\xc0\x05\n\u0aca\x82\xa9\x18\x98\u0389\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\xae\x9f\\?\xbb\xe0\u027c\xbf\x1a\xf8\xfft\xea(\v:]\x8b\b\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xae\xad\x88\u0589Ak\x1c\x91\xf26D!7[}\x82\xd0RR\n\xfb\\Wm\x9f~\xb9>\u048a\r\xd0A \xba\t\xcf\xe6\x00\x00\u07d4\xae\xc2\u007f\xf5\xd7\xf9\xdd\u0691\x18?F\xf9\xd5%C\xb6\xcd+/\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xae\xe4\x9dh\xad\xed\xb0\x81\xfdCpZ_x\xc7x\xfb\x90\xdeH\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xae\xf5\xb1\"X\xa1\x8d\xec\a\xd5\xec.1et\x91\x9dy\xd6\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xae\xfc\xfe\x88\xc8&\xcc\xf11\xd5N\xb4\ua7b8\x0ea\xe1\xee%\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xaf\x06\xf5\xfam\x12\x14\xecC\x96}\x1b\xd4\xdd\xe7J\xb8\x14\xa98\x89\x04\xc5>\xcd\xc1\x8a`\x00\x00\u07d4\xaf\x11H\xefl\x8e\x10=u0\xef\xc9\x16y\u026c'\x00\t\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaf >\"\x9d~mA\x9d\xf47\x8e\xa9\x87\x15Q_c\x14\x85\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xaf X\xc7(,\xf6|\x8c<\xf90\x13<\x89a|\xe7])\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\xaf&\xf7\u01bfE> x\xf0\x89S\u4c80\x04\xa2\xc1\xe2\t\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xaf0\x87\xe6.\x04\xbf\x90\rZT\xdc>\x94bt\u0692B;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf6\x14\u0736\x8a6\xe4ZN\x91\x1ebybG\"-Y[\x89z\x81\x06_\x11\x03\xbc\x00\x00\u07d4\xaf6\x15\u01c9\u0431\x15*\xd4\xdb%\xfe]\xcf\"(\x04\xcfb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaf<\xb5\x96Y3\xe7\xda\u0603i;\x9c>\x15\xbe\xb6\x8aHs\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xafD\x93\xe8R\x1c\xa8\x9d\x95\xf5&|\x1a\xb6?\x9fEA\x1e\x1b\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xafL\xf4\x17\x85\x16\x1fW\x1d\f\xa6\x9c\x94\xf8\x02\x1fA)N\u028a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xafR\x9b\xdbE\x9c\xc1\x85\xbe\xe5\xa1\u014b\xf7\xe8\xcc\xe2\\\x15\r\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xafg\xfd>\x12\u007f\xd9\xdc6\xeb?\xcdj\x80\u01feOu2\xb2\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xafw\x1094Z40\x01\xbc\x0f\x8aY#\xb1&\xb6\rP\x9c\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xaf\u007fy\xcbAZ\x1f\xb8\u06fd\tF\a\xee\x8dA\xfb|Z;\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xaf\x87\xd27\x1e\xf3x\x95\u007f\xbd\x05\xba/\x1df\x93\x1b\x01\u2e09%\xf2s\x93=\xb5p\x00\x00\u07d4\xaf\x88\x0f\xc7V}U\x95\xca\xcc\xe1\\?\xc1L\x87B\xc2l\x9e\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xaf\x8e\x1d\xcb1L\x95\r6\x87CM0\x98X\xe1\xa8s\x9c\u0509\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xaf\x99-\xd6i\xc0\x88>U\x15\xd3\xf3\x11*\x13\xf6\x17\xa4\xc3g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xa1\u056d8\xfe\xd4GY\xc0[\x89\x93\xc1\xaa\r\xac\xe1\x9f@\x89\x04V9\x18$O@\x00\x00\xe0\x94\xaf\xa59XnG\x19\x17J;F\xb9\xb3\xe6c\xa7\u0475\xb9\x87\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xa6\x94n\xff\xd5\xffS\x15O\x82\x01\x02S\xdfG\xae(\f\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xaf\xc8\xeb\u860b\xd4\x10Z\xccL\x01\x8eTj\x1e\x8f\x9cx\x88\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xaf\xcc}\xbb\x83V\xd8B\xd4:\xe7\xe2<\x84\"\xb0\"\xa3\b\x03\x8a\x06o\xfc\xbf\xd5\xe5\xa3\x00\x00\x00\u07d4\xaf\xd0\x19\xff6\xa0\x91U4ki\x97H\x15\xa1\xc9\x12\xc9\n\xa4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xda\xc5\xc1\xcbV\xe2E\xbfp3\x00f\xa8\x17\uabecL\u0449\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xdd\x1bxab\xb81~ \xf0\xe9y\xf4\xb2\xceHmv]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xf1\x04Z\xdf'\xa1\xaa2\x94a\xb2M\xe1\xba\u950ai\x8b\x89\x01\u03c4\xa3\n\n\f\x00\x00\u07d4\xaf\xf1\a\x96\v~\xc3N\u0590\xb6e\x02M`\x83\x8c\x19\x0fp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xaf\xf1\x1c\xcfi\x93\x04\xd5\xf5\x86*\xf8`\x83E\x1c&\xe7\x9a\xe5\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xaf\xf1at\nm\x90\x9f\xe9\x9cY\xa9\xb7yE\xc9\x1c\xc9\x14H\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\xaf\xfc\x99\xd5\ubd28O\xe7x\x8d\x97\xdc\xe2t\xb08$\x048\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xfe\xa0G7\"\xcb\u007f\x0e\x0e\x86\xb9\xe1\x18\x83\xbfB\x8d\x8dT\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xb0\t\x96\xb0Vn\xcb>rC\xb8\"y\x88\u0733R\xc2\x18\x99\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xb0\x1e8\x9b(\xa3\x1d\x8eI\x95\xbd\xd7\xd7\xc8\x1b\xee\xab\x1eA\x19\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0-\x06(s3EE\u03a2\x92\x18\xe4\x05w`Y\x0ft#\x89\xac\xb6\xa1\xc7\xd9:\x88\x00\x00\u07d4\xb0/\xa2\x93\x87\xec\x12\xe3\u007fi\"\xacL\xe9\x8c[\t\xe0\xb0\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb06\x91k\xda\u03d4\xb6\x9eZ\x8ae`)u\xeb\x02a\x04\u0749\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb0A1\x0f\xe9\xee\u0586L\xed\u053e\xe5\x8d\xf8\x8e\xb4\xed<\xac\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb0U\xafL\xad\xfc\xfd\xb4%\xcfe\xbad1\a\x8f\a\xec\u056b\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0W\x11S\xdb\x1cN\u05ec\xae\xfe\x13\xec\xdf\xdbr\xe7\xe4\xf0j\x8a\x11\f\xffyj\xc1\x95 \x00\x00\u07d4\xb0n\xab\t\xa6\x10\u01a5=V\xa9F\xb2\xc44\x87\xac\x1d[-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0rI\xe0U\x04J\x91U5\x9a@)7\xbb\xd9T\xfeH\xb6\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0v\x182\x8a\x90\x13\a\xa1\xb7\xa0\xd0X\xfc\xd5xn\x9er\xfe\x8a\x06gI]JC0\xce\x00\x00\u07d4\xb0y\xbbM\x98f\x14:m\xa7*\xe7\xac\x00\"\x06)\x811\\\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4\xb0{\xcc\bZ\xb3\xf7)\xf2D\x00Ah7\xb6\x996\xba\x88s\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xb0{\xcf\x1c\xc5\xd4F.Q$\xc9e\xec\xf0\xd7\r\xc2z\xcau\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xb0|\xb9\xc1$\x05\xb7\x11\x80uC\u0113De\xf8\u007f\x98\xbd-\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb0\u007f\u07af\xf9\x1dD`\xfel\xd0\u8870\xbd\x8d\"\xa6.\x87\x8a\x01\x1d%)\xf3SZ\xb0\x00\x00\xe0\x94\xb0\x9f\xe6\xd44\x9b\x99\xbc7\x93\x80T\x02-T\xfc\xa3f\xf7\xaf\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\xe0\x94\xb0\xaa\x00\x95\f\x0e\x81\xfa2\x10\x17>r\x9a\xaf\x16:'\xcdq\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb0\xacN\xfff\x80\xee\x14\x16\x9c\xda\xdb\xff\xdb0\x80Om%\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb0\xb3j\xf9\xae\xee\u07d7\xb6\xb0\"\x80\xf1\x14\xf19\x84\xea2`\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xb0\xb7y\xb9K\xfa<.\x1fX{\u031c~!x\x92\"7\x8f\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xb0\xba\xeb0\xe3\x13wlLm$t\x02\xbaAg\xaf\u0361\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb0\xbb)\xa8a\xea\x1dBME\xac\u053f\u0112\xfb\x8e\xd8\t\xb7\x89\x04V9\x18$O@\x00\x00\xe0\x94\xb0\xc1\xb1w\xa2 \xe4\x1f|t\xd0|\u0785i\xc2\x1cu\xc2\xf9\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xb0\xc7\xceL\r\xc3\u00bb\xb9\x9c\xc1\x85{\x8aE_a\x17\x11\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb0\xce\xf8\xe8\xfb\x89\x84\xa6\x01\x9f\x01\xc6y\xf2r\xbb\xe6\x8f\\w\x89\b=lz\xabc`\x00\x00\xe0\x94\xb0\xd3+\xd7\xe4\u6577\xb0\x1a\xa3\xd0Ao\x80U}\xba\x99\x03\x8a\x03s\x9f\xf0\xf6\xe6\x130\x00\x00\xe0\x94\xb0\xd3\u0247+\x85\x05n\xa0\xc0\xe6\xd1\xec\xf7\xa7~<\u6ac5\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xb0\xe4i\u0206Y8\x15\xb3IV8Y]\xae\xf0f_\xaeb\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xb0\xe7`\xbb\a\xc0\x81wsE\xe0W\x8e\x8b\u0218\"mN;\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\x040\x04\xec\x19A\xa8\xcfO+\x00\xb1W\x00\u076co\xf1~\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\x05\xdd=\x98|\xff\xd8\x13\xe9\xc8P\n\x80\xa1\xad%}V\u0189lj\xccg\u05f1\xd4\x00\x00\u07d4\xb1\x0f\u04a6G\x10/\x88\x1ft\xc9\xfb\xc3}\xa62\x94\x9f#u\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb1\x15\xee:\xb7d\x1e\x1a\xa6\xd0\x00\xe4\x1b\xfc\x1e\xc7!\f/2\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xb1\x17\x8a\xd4s\x83\xc3\x1c\x814\xa1\x94\x1c\xbc\xd4t\xd0bD\xe2\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb1\x17\x95\x89\u1779\xd4\x15W\xbb\xec\x1c\xb2L\xcc-\xec\x1c\u007f\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb1\x19\u76a9\xb9\x16Re\x81\xcb\xf5!\xefGJ\xe8M\xcf\xf4\x89O\xba\x10\x01\xe5\xbe\xfe\x00\x00\u07d4\xb1\x1f\xa7\xfb'\n\xbc\xdfZ.\xab\x95\xaa0\u013566\uffc9+^:\xf1k\x18\x80\x00\x00\u07d4\xb1$\xbc\xb6\xff\xa40\xfc\xae.\x86\xb4_'\xe3\xf2\x1e\x81\xee\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1)\xa5\xcbq\x05\xfe\x81\v\u0615\xdcr\x06\xa9\x91\xa4TT\x88\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\xe0\x94\xb1.\xd0{\x8a8\xadU\x066?\xc0z\vmy\x996\xbd\xaf\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb14\xc0\x049\x1a\xb4\x99(x3zQ\xec$/B(WB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1?\x93\xaf0\xe8\xd7fs\x81\xb2\xb9[\xc1\xa6\x99\xd5\xe3\xe1)\x89\x16\u012b\xbe\xbe\xa0\x10\x00\x00\u07d4\xb1E\x92\x85\x86>\xa2\xdb7Y\xe5F\u03b3\xfb7a\xf5\x90\x9c\x89<\xd7*\x89@\x87\xe0\x80\x00\u07d4\xb1F\xa0\xb9%U<\xf0o\xca\xf5J\x1bM\xfe\xa6!)\aW\x89lnY\xe6|xT\x00\x00\xe0\x94\xb1Jz\xaa\x8fI\xf2\xfb\x9a\x81\x02\u05bb\xe4\u010a\xe7\xc0o\xb2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1K\xbe\xffpr\tu\xdca\x91\xb2\xa4O\xf4\x9f&r\x87<\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\xe0\x94\xb1L\xc8\xde3\xd63\x826S\x9aH\x90 \xceFU\xa3+\u018a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1M\xdb\x03\x86\xfb`c\x98\xb8\xccGVZ\xfa\xe0\x0f\xf1\xd6j\x89\xa1*\xff\b>f\xf0\x00\x00\u07d4\xb1S\xf8(\xdd\amJ|\x1c%t\xbb-\xee\x1aD\xa3\x18\xa8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1T\x0e\x94\xcf\xf3F\\\xc3\u0447\xe7\xc8\u3f6f\x98FY\u2262\x15\xe4C\x90\xe33\x00\x00\u07d4\xb1X\xdbC\xfab\xd3\x0ee\xf3\u041b\xf7\x81\u01f6sr\uba89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1ar_\xdc\xed\xd1yR\xd5{#\xef([~K\x11i\xe8\x89\x02\xb6\xdf\xed6d\x95\x80\x00\u07d4\xb1dy\xba\x8e}\xf8\xf6>\x1b\x95\xd1I\u0345)\xd75\xc2\u0689-\xe3:j\xac2T\x80\x00\u07d4\xb1f\xe3}.P\x1a\xe7<\x84\x14+_\xfbZ\xa6U\xddZ\x99\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1\x83\xeb\xeeO\xcbB\xc2 \xe4wt\xf5\x9dlT\xd5\xe3*\xb1\x89V\xf7\xa9\xc3<\x04\xd1\x00\x00\u07d4\xb1\x88\a\x84D\x02~8g\x98\xa8\xaehi\x89\x19\xd5\xcc#\r\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xb1\x89j7\xe5\u0602Z-\x01vZ\xe5\xdeb\x99w\u0783R\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb1\x8eg\xa5\x05\n\x1d\xc9\xfb\x19\t\x19\xa3=\xa88\xefDP\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb1\xa2\xb4:t3\xdd\x15\v\xb8\"'\xedQ\x9c\u05b1B\u04c2\x89\x94mb\rtK\x88\x00\x00\u07d4\xb1\xc0\u040b6\xe1\x84\xf9\x95*@7\xe3\xe5:f}\a\nN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\xc3(\xfb\x98\xf2\xf1\x9a\xb6do\n|\x8cVo\xdaZ\x85@\x89\x87\x86x2n\xac\x90\x00\x00\xe0\x94\xb1\xc7Qxi9\xbb\xa0\xd6q\xa6w\xa1X\u01ab\xe7&^F\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xb1\xcdK\xdf\xd1\x04H\x9a\x02n\u025dYs\a\xa0By\xf1s\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb1\u03d4\xf8\t\x15\x05\x05_\x01\n\xb4\xba\u0196\xe0\xca\x0fg\xa1\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xb1\u05b0\x1b\x94\xd8T\xfe\x8b7J\xa6^\x89\\\xf2*\xa2V\x0e\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94\xb1\u06e5%\v\xa9bWU$n\x06yg\xf2\xad/\a\x91\u078a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xb1\xe2\u0755\xe3\x9a\xe9w\\U\xae\xb1?\x12\xc2\xfa#0S\xba\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\xe6\xe8\x10\xc2J\xb0H\x8d\xe9\xe0\x1eWH7\x82\x9f|w\u0409\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1\xe9\xc5\xf1\xd2\x1eauzk.\xe7Y\x13\xfcZ\x1aA\x01\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\x03\u049elV\xb9&\x99\u0139-\x1fo\x84d\x8d\xc4\u03fc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x16\xdcY\xe2|=ry\xf5\xcd[\xb2\xbe\u03f2`n\x14\u0649\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x1byy\xbf|\\\xa0\x1f\xa8-\xd6@\xb4\x1c9\xe6\u01bcu\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb2#\xbf\x1f\xbf\x80H\\\xa2\xb5V}\x98\xdb{\xc3SM\xd6i\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2-PU\xd9b15\x96\x1ej\xbd'<\x90\xde\xea\x16\xa3\xe7\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb2-\xad\xd7\xe1\xe0R2\xa927\xba\xed\x98\xe0\u07d2\xb1\x86\x9e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb24\x03_uDF<\xe1\xe2+\xc5S\x06F\x84\xc5\x13\xcdQ\x89\r\x89\xfa=\u010d\xcf\x00\x00\u07d4\xb2G\u03dcr\xecH*\xf3\xea\xa7Ye\x8fy=g\nW\f\x891p\x8a\xe0\x04T@\x00\x00\u07d4\xb2ghA\xee\x9f-1\xc1r\xe8#\x03\xb0\xfe\x9b\xbf\x9f\x1e\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb2y\xc7\xd3U\u0088\x03\x92\xaa\u046a!\xee\x86|;5\a\u07c9D[\xe3\xf2\uf1d4\x00\x00\u07d4\xb2|\x1a$ L\x1e\x11\x8du\x14\x9d\xd1\t1\x1e\a\xc0s\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb2\x81\x81\xa4X\xa4@\xf1\u01bb\x1d\xe8@\x02\x81\xa3\x14\x8fL5\x89\x14b\fW\xdd\xda\xe0\x00\x00\xe0\x94\xb2\x82E\x03|\xb1\x92\xf7W\x85\u02c6\xcb\xfe|\x93\r\xa2X\xb0\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xb2\x87\xf7\xf8\xd8\u00c7,\x1bXk\xcd}\n\xed\xbf~s'2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb2\x8b\xb3\x9f4fQ|\xd4o\x97\x9c\xf5\x96S\xee}\x8f\x15.\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xb2\x8d\xbf\xc6I\x98\x94\xf7:q\xfa\xa0\n\xbe\x0fK\xc9\u045f*\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\x96\x8f}5\xf2\b\x87\x161\xc6h{?=\xae\xab\xc6al\x89\bu\xc4\u007f(\x9fv\x00\x00\u07d4\xb2\x9f[|\x190\xd9\xf9z\x11^\x06pf\xf0\xb5M\xb4K;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb2\xa1D\xb1\xeag\xb9Q\x0f\"g\xf9\xda9\xd3\xf9=\xe2fB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xa2\xc2\x11\x16\x12\xfb\x8b\xbb\x8e}\xd97\x8dg\xf1\xa3\x84\xf0P\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb2\xa4\x98\xf0;\xd7\x17\x8b\u0627\x89\xa0\x0fR7\xafy\xa3\xe3\xf8\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\u07d4\xb2\xaa/\x1f\x8e\x93\xe7\x97\x13\xd9,\xea\x9f\xfc\xe9\xa4\n\xf9\xc8-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xb5\x16\xfd\u045e\u007f8d\xb6\xd2\xcf\x1b%*AV\xf1\xb0;\x89\x02\xe9\x83\xc7a\x15\xfc\x00\x00\u07d4\xb2\xb7\u0374\xffKa\u0577\xce\v\"p\xbb\xb5&\x97C\xec\x04\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xbd\xbe\u07d5\x90\x84v\xd7\x14\x8a7\f\u0193t6(\x05\u007f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2\xbf\xaaX\xb5\x19l\\\xb7\xf8\x9d\xe1_G\x9d\x188\xdeq=\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xb2\xc5>\xfa3\xfeJ:\x1a\x80 \\s\xec;\x1d\xbc\xad\x06\x02\x89h\x01\u06b3Y\x18\x93\x80\x00\xe0\x94\xb2\xd06\x05\x15\xf1}\xab\xa9\x0f\u02ec\x82\x05\xd5i\xb9\x15\u05ac\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xb2\xd1\xe9\x9a\xf9\x121\x85\x8epe\xdd\x19\x183\r\xc4\xc7G\u054a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xb2\u066b\x96d\xbc\xf6\xdf <4o\u0192\xfd\x9c\xba\xb9 ^\x89\x17\xbex\x97`e\x18\x00\x00\u07d4\xb2\u0777\x86\xd3yN'\x01\x87\xd0E\x1a\xd6\u0237\x9e\x0e\x87E\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\xe0\x85\xfd\xdd\x14h\xba\aA['NsN\x11#\u007f\xb2\xa9\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\xe9\xd7k\xf5\x0f\xc3k\xf7\u04d4Kc\xe9\u0288\x9bi\x99h\x89\x902\xeab\xb7K\x10\x00\x00\xe0\x94\xb2\xf9\xc9r\xc1\xe9swU\xb3\xff\x1b0\x88s\x83\x969[&\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xb2\xfc\x84\xa3\xe5\nP\xaf\x02\xf9M\xa08>\u055fq\xff\x01\u05ca\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xb3\x05\v\xef\xf9\xde3\xc8\x0e\x1f\xa1R%\xe2\x8f,A:\xe3\x13\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xb3\x11\x96qJH\xdf\xf7&\xea\x943\xcd)\x12\xf1\xa4\x14\xb3\xb3\x89\x91Hx\xa8\xc0^\xe0\x00\x00\xe0\x94\xb3\x14[tPm\x1a\x8d\x04|\xdc\xdcU9*{SPy\x9a\x8a\x1bb)t\x1c\r=]\x80\x00\u07d4\xb3 \x83H6\xd1\xdb\xfd\xa9\xe7\xa3\x18M\x1a\xd1\xfdC \xcc\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3#\u073f.\xdd\xc58.\u4efb \x1c\xa3\x93\x1b\xe8\xb48\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb3$\x00\xfd\x13\xc5P\t\x17\xcb\x03{)\xfe\"\xe7\xd5\"\x8f-\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb3%gL\x01\xe3\xf7)\rR&3\x9f\xbe\xacg\xd2!'\x9f\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xb3(%\xd5\xf3\xdb$\x9e\xf4\xe8\\\xc4\xf31S\x95\x89v\u8f09\x1b-\xf9\xd2\x19\xf5y\x80\x00\u07d4\xb3*\xf3\xd3\xe8\xd0u4I&To.2\x88{\xf9;\x16\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3/\x1c&\x89\xa5\xcey\xf1\xbc\x97\v1XO\x1b\xcf\"\x83\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3<\x03#\xfb\xf9\xc2l\x1d\x8a\xc4N\xf7C\x91\u0400F\x96\u0689\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb3O\x04\xb8\xdbe\xbb\xa9\xc2n\xfcL\xe6\xef\xc5\x04\x81\xf3\xd6]\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3U}9\xb5A\x1b\x84D__T\xf3\x8fb\xd2qM\x00\x87\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xb3X\xe9|p\xb6\x05\xb1\xd7\xd7)\u07f6@\xb4<^\xaf\xd1\xe7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xb3^\x8a\x1c\r\xac~\x0ef\u06ecsjY*\xbdD\x01%a\x88\xcf\xceU\xaa\x12\xb3\x00\x00\xe0\x94\xb3fx\x94\xb7\x86<\x06\x8a\xd3D\x87?\xcf\xf4\xb5g\x1e\x06\x89\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3qw1\xda\xd6Q2\xday-\x87`0\xe4j\xc2'\xbb\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3s\x1b\x04l\x8a\u0195\xa1'\xfdy\u0425\xd5\xfaj\xe6\xd1.\x89lO\xd1\xee$nx\x00\x00\u07d4\xb3|+\x9fPc{\xec\xe0\u0295\x92\b\xae\xfe\xe6F;\xa7 \x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb3\x88\xb5\xdf\xec\xd2\xc5\u4d56W|d%V\xdb\xfe'xU\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3\x8cNS{]\xf90\xd6Zt\xd0C\x83\x1dkH[\xbd\xe4\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb3\x919Wa\x94\xa0\x86a\x95\x15\x1f3\xf2\x14\n\xd1\u0306\u03ca\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb3\x9fL\x00\xb2c\f\xab}\xb7)^\xf4=G\xd5\x01\xe1\u007f\u05c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb3\xa6K\x11vrOT\t\xe1AJ5#f\x1b\xae\xe7KJ\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xb3\xa6\xbdA\xf9\xd9\xc3 \x1e\x05\v\x87\x19\x8f\xbd\xa3\x994\"\x10\x89\xc4a\xe1\xdd\x10)\xb5\x80\x00\u07d4\xb3\xa8\xc2\xcb}5\x8eW9\x94\x1d\x94[\xa9\x04Z\x02:\x8b\xbb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xaeT\xfb\xa0\x9d>\xe1\u05bd\xd1\xe9W\x929\x19\x02L5\xfa\x89\x03\x8d,\xeee\xb2*\x80\x00\u07d4\xb3\xb7\xf4\x93\xb4J,\x8d\x80\xecx\xb1\xcd\xc7Ze+s\xb0l\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb3\xc2(s\x1d\x18m-\xed[_\xbe\x00Lfl\x8eF\x9b\x86\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4\xb3\xc2``\x9b\x9d\xf4\t^l]\xff9\x8e\xeb^-\xf4\x99\x85\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xb3\xc6[\x84Z\xbal\xd8\x16\xfb\xaa\xe9\x83\xe0\xe4l\x82\xaa\x86\"\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xc9H\x11\xe7\x17[\x14\x8b(\x1c\x1a\x84[\xfc\x9b\xb6\xfb\xc1\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3\xe2\x0e\xb4\xde\x18\xbd\x06\x02!h\x98\x94\xbe\u5bb2SQ\xee\x89\x03\xfc\x80\xcc\xe5\x16Y\x80\x00\u07d4\xb3\xe3\xc49\x06\x98\x80\x15f\x00\u0089.D\x8dA6\xc9-\x9b\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xb3\xf8*\x87\xe5\x9a9\xd0\u0480\x8f\aQ\xebr\xc22\x9c\xdc\u014a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb3\xfc\x1dh\x81\xab\xfc\xb8\xbe\xcc\v\xb0!\xb8\xb7;r3\u0751\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xb4\x05\x94\xc4\xf3fN\xf8I\u0326\"{\x8a%\xaai\t%\xee\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb4\x1e\xaf]Q\xa5\xba\x1b\xa3\x9b\xb4\x18\u06f5O\xabu\x0e\xfb\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4$\u058d\x9d\r\x00\xce\xc1\x93\x8c\x85N\x15\xff\xb8\x80\xba\x01p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4%bs\x96+\xf61\xd0\x14U\\\xc1\xda\r\xcc1akI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb40g\xfep\u0675Ys\xbaX\xdcd\xdd\u007f1\x1eUBY\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb46W\xa5\x0e\xec\xbc0w\xe0\x05\xd8\xf8\xd9O7xv\xba\u0509\x01\xec\x1b:\x1f\xf7Z\x00\x00\u07d4\xb4<'\xf7\xa0\xa1\"\bK\x98\xf4\x83\x92%A\u0203l\xee,\x89&\u009eG\u0104L\x00\x00\xe0\x94\xb4A5v\x86\x9c\b\xf9Q*\xd3\x11\xfe\x92Y\x88\xa5-4\x14\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb4F\x05U$q\xa6\xee\xe4\u06abq\xff;\xb4\x13&\xd4s\xe0\x89-~=Q\xbaS\xd0\x00\x00\u07d4\xb4GW\x1d\xac\xbb>\u02f6\xd1\xcf\v\f\x8f88\xe5#$\xe2\x89\x01\xa3\x18f\u007f\xb4\x05\x80\x00\u07d4\xb4G\x83\xc8\xe5{H\a\x93\xcb\u059aE\xd9\f{O\fH\xac\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb4H\x15\xa0\xf2\x8eV\x9d\x0e\x92\x1aJ\u078f\xb2d%&Iz\x89\x03\x027\x9b\xf2\xca.\x00\x00\u07d4\xb4Im\xdb'y\x9a\"$W\xd79y\x11g(\u8844[\x89\x8d\x81\x9e\xa6_\xa6/\x80\x00\xe0\x94\xb4RL\x95\xa7\x86\x0e!\x84\x02\x96\xa6\x16$@\x19B\x1cJ\xba\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb4\\\xca\r6\x82fbh<\xf7\u0432\xfd\xach\u007f\x02\xd0\u010965\u026d\xc5\u07a0\x00\x00\u0794\xb4d@\u01d7\xa5V\xe0L}\x91\x04f\x04\x91\xf9k\xb0v\xbf\x88\xce\xc7o\x0eqR\x00\x00\u07d4\xb4j\u0386^,P\xeaF\x98\xd2\x16\xabE]\xffZ\x11\xcdr\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4m\x11\x82\xe5\xaa\xca\xff\r&\xb2\xfc\xf7/<\x9f\xfb\xcd\xd9}\x89\xaa*`<\xdd\u007f,\x00\x00\u07d4\xb4\x89!\xc9h}U\x10tE\x84\x93n\x88\x86\xbd\xbf-\xf6\x9b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\x98\xbb\x0fR\x00\x05\xb6!jD%\xb7Z\xa9\xad\xc5-b+\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb4\xb1\x1d\x10\x9f`\x8f\xa8\xed\xd3\xfe\xa9\xf8\xc3\x15d\x9a\xeb=\x11\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb4\xb1K\xf4TU\u042b\b\x035\x8bu$\xa7+\xe1\xa2\x04[\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb4\xb1\x85\xd9C\xee+Xc\x1e3\xdf\xf5\xafhT\xc1y\x93\xac\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xbf$\u02c3hk\xc4i\x86\x9f\xef\xb0D\xb9\tqi\x93\xe2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb4\xc2\x00@\xcc\u0661\xa3(=\xa4\u0522\xf3e\x82\bC\xd7\xe2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xc8\x17\x0f{*\xb56\xd1\u0662[\xdd :\xe1(\x8d\xc3\u0549\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4\xd8/.i\x94?}\xe0\xf5\xf7t8y@o\xac.\x9c\xec\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb4\xddF\f\xd0\x16rZd\xb2.\xa4\xf8\xe0n\x06gN\x03>\x8a\x01#\x1b\xb8t\x85G\xa8\x00\x00\u07d4\xb4\xddT\x99\xda\xeb%\a\xfb-\xe1\"\x97s\x1dLr\xb1k\xb0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb5\x04l\xb3\xdc\x1d\xed\xbd6E\x14\xa2\x84\x8eD\xc1\xdeN\xd1G\x8a\x03{}\x9b\xb8 @^\x00\x00\xe0\x94\xb5\b\xf9\x87\xb2\xde4\xaeL\xf1\x93\u0785\xbf\xf6\x13\x89b\x1f\x88\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb5\tU\xaan4\x15q\x98f\b\xbd\u0211\xc2\x13\x9fT\f\u07c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5\f\x14\x9a\x19\x06\xfa\xd2xo\xfb\x13Z\xabP\x177\xe9\xe5o\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\xb5\f\x9fW\x89\xaeD\xe2\xdc\xe0\x17\xc7\x14\xca\xf0\f\x83\x00\x84\u0089\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xb5\x14\x88,\x97\x9b\xb6B\xa8\r\u04c7T\u0578\xc8)m\x9a\a\x893\xc5I\x901r\f\x00\x00\u07d4\xb5\x1d\u0734\xddN\x8a\xe6\xbe3m\xd9eIq\xd9\xfe\xc8kA\x89\x16\xd4d\xf8=\u2500\x00\u07d4\xb5\x1eU\x8e\xb5Q/\xbc\xfa\x81\xf8\u043d\x93\x8cy\xeb\xb5$+\x89&\u009eG\u0104L\x00\x00\u07d4\xb5#\xff\xf9t\x98q\xb3S\x88C\x887\xf7\xe6\xe0\u07a9\xcbk\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb5-\xfbE\xde]t\xe3\xdf \x832\xbcW\x1c\x80\x9b\x8d\xcf2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb55\xf8\u06c7\x9f\xc6\u007f\xecX\x82J\\\xbenT\x98\xab\xa6\x92\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xb57\xd3jp\xee\xb8\xd3\xe5\xc8\r\xe8\x15\"\\\x11X\u02d2\u0109QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xb5;\xcb\x17L%\x184\x8b\x81\x8a\xec\xe0 6E\x96Fk\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5I>\xf1srDE\xcf4\\\x03]'\x9b\xa7Y\xf2\x8dQ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb5S\xd2]kT!\xe8\x1c*\xd0^\v\x8b\xa7Q\xf8\xf0\x10\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5Tt\xbaX\xf0\xf2\xf4\x0el\xba\xbe\xd4\xea\x17n\x01\x1f\xca\u0589j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5U\xd0\x0f\x91\x90\xcc6w\xae\xf3\x14\xac\xd7?\xdc99\x92Y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5W\xab\x949\xefP\xd27\xb5S\xf0%\b6JFj\\\x03\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5jx\x00(\x03\x9c\x81\xca\xf3{gu\xc6 \u7195Gd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5j\u04ae\xc6\xc8\xc3\xf1\x9e\x15\x15\xbb\xb7\u0751(RV\xb69\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5t\x13\x06\n\xf3\xf1N\xb4y\x06_\x1e\x9d\x19\xb3uz\xe8\u0309\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xb5uI\xbf\xbc\x9b\xdd\x18\xf76\xb2&P\xe4\x8as`\x1f\xa6\\\x89\x18-~L\xfd\xa08\x00\x00\xe0\x94\xb5w\xb6\xbe\xfa\x05N\x9c\x04\x04a\x85P\x94\xb0\x02\xd7\xf5{\u05ca\x18#\xf3\xcfb\x1d#@\x00\x00\u07d4\xb5{\x04\xfa#\xd1 ?\xae\x06\x1e\xacEB\xcb`\xf3\xa5v7\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xb5\x87\f\xe3B\xd43C36s\x03\x8bGd\xa4n\x92_>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\x87\xb4J,\xa7\x9eK\xc1\u074b\xfd\xd4: qP\xf2\xe7\xe0\x89\",\x8e\xb3\xfff@\x00\x00\u07d4\xb5\x89gm\x15\xa0DH4B0\xd4\xff'\xc9^\xdf\x12,I\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb5\x8bR\x86^\xa5]\x806\xf2\xfa\xb2`\x98\xb3R\u0283~\x18\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xb5\x90k\n\u9881X\xe8\xacU\x0e9\xda\bn\xe3\x15v#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xa4g\x96\x85\xfa\x14\x19l.\x920\xc8\xc4\xe3;\xff\xbc\x10\xe2\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb5\xa5\x89\u075f@q\u06f6\xfb\xa8\x9b?]]\xae}\x96\xc1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xa6\x06\xf4\xdd\u02f9G\x1e\xc6\u007fe\x8c\xaf+\x00\xees\x02^\x89\xeaun\xa9*\xfct\x00\x00\u07d4\xb5\xadQW\u0769!\xe6\xba\xfa\u0350\x86\xaes\xae\x1fa\x1d?\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xad\xd1\u701f}\x03\x06\x9b\xfe\x88;\n\x93\"\x10\xbe\x87\x12\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\xba)\x91|x\xa1\xd9\xe5\xc5\xc7\x13fl\x1eA\x1d\u007fi:\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb5\xc8\x16\xa8(<\xa4\xdfh\xa1\xa7=c\xbd\x80&\x04\x88\xdf\b\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xca\xc5\xed\x03G}9\v\xb2g\xd4\xeb\xd4a\x01\xfb\xc2\xc3\u0689\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xb5\u037cA\x15@oR\u5a85\xd0\xfe\xa1p\u0497\x9c\u01fa\x89Hz\x9a0E9D\x00\x00\u0794\xb5\u0653M{)+\xcf`;(\x80t\x1e\xb7`(\x83\x83\xa0\x88\xe7\xc2Q\x85\x05\x06\x00\x00\u07d4\xb5\xddP\xa1]\xa3Ih\x89\nS\xb4\xf1?\xe1\xaf\b\x1b\xaa\xaa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb5\xfa\x81\x84\xe4>\xd3\u0e2b\x91!da\xb3R\x8d\x84\xfd\t\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb5\xfb~\xa2\xdd\xc1Y\x8bfz\x9dW\xdd9\xe8Z8\xf3]V\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb6\x00B\x97R\xf3\x99\xc8\r\a4tK\xae\n\x02.\xcag\u0189\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x00\xfe\xabJ\xa9lSu\x04\xd9`W\"1Ai,\x19:\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb6\x04|\u07d3-\xb3\xe4\x04_Iv\x12#AS~\u0556\x1e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x15\xe9@\x14>\xb5\u007f\x87X\x93\xbc\x98\xa6\x1b=a\x8c\x1e\x8c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb6\x1c4\xfc\xac\xdap\x1aZ\xa8p$Y\u07b0\u4b83\x8d\xf8\x8a\aiZ\x92\xc2\ro\xe0\x00\x00\xe0\x94\xb60d\xbd3U\xe6\xe0~-7p$\x12Z3wlJ\xfa\x8a\b7Z*\xbc\xca$@\x00\x00\u07d4\xb65\xa4\xbcq\xfb(\xfd\xd5\xd2\xc3\"\x98:V\u0084Bni\x89\t79SM(h\x00\x00\u07d4\xb6F\u07d8\xb4\x94BtkaR\\\x81\xa3\xb0K\xa3\x10bP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb6YA\xd4LP\xd2Ffg\r6Gf\xe9\x91\xc0.\x11\u0089 \x86\xac5\x10R`\x00\x00\xe0\x94\xb6[\u05c0\xc7CA\x15\x16 'VR#\xf4NT\x98\xff\x8c\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xb6d\x11\xe3\xa0-\xed\xb7&\xfay\x10}\xc9\v\xc1\xca\xe6MH\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb6fu\x14.1\x11\xa1\xc2\xea\x1e\xb2A\x9c\xfaB\xaa\xf7\xa24\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb6o\x92\x12K^c\x03XY\xe3\x90b\x88i\xdb\u07a9H^\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xb6rsJ\xfc\xc2$\xe2\xe6\t\xfcQ\xd4\xf0Ys'D\xc9H\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xb6w\x1b\v\xf3B\u007f\x9a\xe7\xa9>|.a\xeec\x94\x1f\xdb\b\x8a\x03\xfb&i)T\xbf\xc0\x00\x00\u07d4\xb6z\x80\xf1p\x19}\x96\xcd\xccJ\xb6\u02e6'\xb4\xaf\xa6\xe1,\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xb6\x88\x99\xe7a\rL\x93\xa255\xbc\xc4H\x94[\xa1fo\x1c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb6\xa8)3\xc9\xea\u06bd\x98\x1e]m`\xa6\x81\x8f\xf8\x06\xe3k\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb6\xaa\u02cc\xb3\v\xab*\xe4\xa2BF&\xe6\xe1+\x02\xd0F\x05\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb6\xb3J&?\x10\xc3\xd2\xec\xeb\n\xccU\x9a{*\xb8\\\xe5e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xbf\xe1\xc3\xef\x94\xe1\x84o\xb9\xe3\xac\xfe\x9bP\xc3\xe9\x06\x923\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb6\xcdt2\xd5\x16\x1b\xe7\x97h\xadE\xde>Dz\a\x98 c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xceM\xc5`\xfcs\xdci\xfbzb\xe3\x88\xdb~r\xeavO\x894]\xf1i\xe9\xa3X\x00\x00\u07d4\xb6\xde\u03c2\x96\x98\x19\xba\x02\xde)\xb9\xb5\x93\xf2\x1bd\xee\xda\x0f\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\xe0\x94\xb6\xe6\xc3\"+ko\x9b\xe2\x87]*\x89\xf1'\xfbd\x10\x0f\xe2\x8a\x01\xb2\x1dS#\xcc0 \x00\x00\u07d4\xb6\xe8\xaf\xd9=\xfa\x9a\xf2\u007f9\xb4\xdf\x06\ag\x10\xbe\xe3\u07eb\x89\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xb6\xf7\x8d\xa4\xf4\xd0A\xb3\xbc\x14\xbc[\xa5\x19\xa5\xba\f2\xf1(\x8a$}\xd3,?\xe1\x95\x04\x80\x00\xe0\x94\xb6\xfb9xbP\b\x14&\xa3B\xc7\rG\xeeR\x1e[\xc5c\x8a\x03-&\xd1.\x98\v`\x00\x00\u07d4\xb7\r\xba\x93\x91h+J6Nw\xfe\x99%c\x01\xa6\xc0\xbf\x1f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x16#\xf3Q\a\xcft1\xa8?\xb3\xd2\x04\xb2\x9e\u0c67\xf4\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xb7\x1a\x13\xba\x8e\x95\x16{\x803\x1bR\u059e7\x05O\xe7\xa8&\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x1bb\xf4\xb4H\xc0+\x12\x01\xcb^9J\xe6'\xb0\xa5`\xee\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb7\" \xad\xe3d\xd06\x9f--\xa7\x83\xcaGM{\x9b4\u0389\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\xe0\x94\xb7#\r\x1d\x1f\xf2\xac\xa3f\x969\x14\xa7\x9d\xf9\xf7\xc5\xea,\x98\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xb7$\n\U000af433<\b\xae\x97d\x10>5\xdc\xe3c\x84(\x8a\x01\xca\xdd/\xe9hnc\x80\x00\u07d4\xb7'\xa9\xfc\x82\xe1\xcf\xfc\\\x17_\xa1HZ\x9b\xef\xa2\u037d\u04496'\xe8\xf7\x127<\x00\x00\u07d4\xb7,*\x01\x1c\r\xf5\x0f\xbbn(\xb2\n\xe1\xaa\xd2\x17\x88g\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb78-7\xdb\x03\x98\xacrA\f\xf9\x81=\xe9\xf8\xe1\uc36d\x8966\xc2^f\xec\xe7\x00\x00\u07d4\xb7;O\xf9\x9e\xb8\x8f\u061b\vmW\xa9\xbc3\x8e\x88o\xa0j\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xb7=jwU\x9c\x86\xcfet$)\x039K\xac\xf9n5p\x89\x04\xf1\xa7|\xcd;\xa0\x00\x00\u07d4\xb7Cr\xdb\xfa\x18\x1d\xc9$/9\xbf\x1d71\xdf\xfe+\xda\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7G\x9d\xabP\"\xc4\xd5\u06ea\xf8\xde\x17\x1bN\x95\x1d\u0464W\x89\x04V9\x18$O@\x00\x00\u07d4\xb7I\xb5N\x04\u0571\x9b\xdc\xed\xfb\x84\xdaw\x01\xabG\x8c'\xae\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb7N\xd2f`\x01\xc1c3\xcfz\xf5\x9eJ=H`6;\x9c\x89\n~\xbd^Cc\xa0\x00\x00\u07d4\xb7QI\xe1\x85\xf6\xe3\x92pWs\x90s\xa1\x82*\xe1\xcf\r\xf2\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xb7S\xa7_\x9e\xd1\v!d:\n=\xc0Qz\xc9k\x1a@h\x89\x15\xc8\x18[,\x1f\xf4\x00\x00\xe0\x94\xb7V\xadR\xf3\xbft\xa7\xd2LgG\x1e\b\x87Ci6PL\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb7Wn\x9d1M\xf4\x1e\xc5Pd\x94):\xfb\x1b\xd5\xd3\xf6]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb7X\x89o\x1b\xaa\x86O\x17\xeb\xed\x16\xd9S\x88o\xeeh\xaa\xe6\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb7h\xb5#N\xba:\x99h\xb3Mm\xdbH\x1c\x84\x19\xb3e]\x88\xcf\xceU\xaa\x12\xb3\x00\x00\u07d4\xb7\x82\xbf\xd1\xe2\xdep\xf4gdo\x9b\xc0\x9e\xa5\xb1\xfc\xf4P\xaf\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xb7\xa2\xc1\x03r\x8bs\x05\xb5\xaen\x96\x1c\x94\xee\x99\xc9\xfe\x8e+\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xb7\xa3\x1a|8\xf3\xdb\t2.\xae\x11\xd2'!A\xea\"\x99\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xa6y\x1c\x16\xebN!b\xf1Ke7\xa0+=c\xbf\xc6\x02\x89*Rc\x91\xac\x93v\x00\x00\u07d4\xb7\xa7\xf7|4\x8f\x92\xa9\xf1\x10\fk\xd8)\xa8\xacm\u007f\u03d1\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xb7\xc0w\x94ft\xba\x93A\xfbLtz]P\xf5\xd2\xdad\x15\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb7\xc0\xd0\xcc\vM4-@b\xba\xc6$\xcc\xc3\xc7\f\xc6\xda?\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb7\xc9\xf1+\x03\x8esCm\x17\xe1\xc1/\xfe\x1a\xec\u0373\xf5\x8c\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xb7\xcck\x1a\xcc2\u0632\x95\xdfh\xed\x9d^`\xb8\xf6L\xb6{\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xb7\xcehK\t\xab\xdaS8\x9a\x87Si\xf7\x19X\xae\xac;\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xd1.\x84\xa2\xe4\u01264Z\xf1\xdd\x1d\xa9\xf2PJ*\x99n\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\xd2R\xee\x94\x02\xb0\xee\xf1D)_\x0ei\xf0\xdbXl\bq\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\xb7\u0541\xfe\n\xf1\xec8?;\xce\x00\xaf\x91\x99\xf3\xcf_\xe0\xcc\xe2\x8c\xd1J\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xb8R\x18\xf3B\xf8\x01.\u069f'Nc\xce!R\xb2\xdc\xfd\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb8UP\x10wn<\\\xb3\x11\xa5\xad\xee\xfe\x9e\x92\xbb\x9ad\xb9\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb8_&\xdd\x0er\xd9\u009e\xba\xf6\x97\xa8\xafwG,+X\xb5\x8a\x02\x85\x19\xac\xc7\x19\fp\x00\x00\u07d4\xb8_\xf0>{_\xc4\"\x98\x1f\xae^\x99A\xda\xcb\u06bau\x84\x89Hz\x9a0E9D\x00\x00\xe0\x94\xb8f\a\x02\x1bb\xd3@\xcf&R\xf3\xf9_\xd2\xdcgi\x8b\u07ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb8}\xe1\xbc\u0492i\xd5!\xb8v\x1c\u00dc\xfbC\x19\xd2\xea\u054965\u026d\xc5\u07a0\x00\x00\u07d4\xb8\u007fSv\xc2\xde\vl\xc3\xc1y\xc0`\x87\xaaG=kFt\x89Hz\x9a0E9D\x00\x00\u07d4\xb8\x84\xad\u060d\x83\xdcVJ\xb8\xe0\xe0,\xbd\xb69\x19\xae\xa8D\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x8a7\xc2\u007fx\xa6\x17\xd5\xc0\x91\xb7\u0577:7a\xe6_*\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x94x\"\u056c\u79ad\x83&\xe9T\x96\"\x1e\v\xe6\xb7=\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\x9c\x03n\xd7\u0112\x87\x99!\xbeA\xe1\f\xa1i\x81\x98\xa7L\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xb8\x9fF2\xdfY\t\xe5\x8b*\x99d\xf7O\xeb\x9a;\x01\xe0\u014a\x04\x88u\xbc\xc6\xe7\xcb\xeb\x80\x00\u07d4\xb8\xa7\x9c\x84\x94^G\xa9\xc3C\x86\x83\u05b5\x84,\xffv\x84\xb1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\xa9y5'Y\xba\t\xe3Z\xa5\x93]\xf1u\xbf\xf6x\xa1\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\xab9\x80[\xd8!\x18Ol\xbd=$s4{\x12\xbf\x17\\\x89\x06hZ\xc1\xbf\xe3,\x00\x00\xe0\x94\xb8\xac\x11}\x9f\r\xba\x80\x90\x14E\x82:\x92\x11\x03\xa51o\x85Zew\x9d\x1b\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xb9\xe9\f\x11\x92\xb3\xd5\xd3\xe3\xab\a\x00\xf1\xbfe_]\xd44z\x89\x1b\x19\xe5\vD\x97|\x00\x00\u07d4\xb9\xfd83\xe8\x8e|\xf1\xfa\x98y\xbd\xf5Z\xf4\xb9\x9c\xd5\xce?\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xba\x02I\xe0\x1d\x94[\xef\x93\xee^\xc6\x19%\xe0<\\\xa5\t\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\x0f9\x02;\xdb)\xeb\x18b\xa9\xf9\x05\x9c\xab]0nf/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x10\xf2vB\x90\xf8uCCr\xf7\x9d\xbfq8\x01\u02ac\x01\x893\xc5I\x901r\f\x00\x00\u07d4\xba\x151\xfb\x9ey\x18\x96\xbc\xf3\xa8\x05X\xa3Y\xf6\xe7\xc1D\xbd\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xba\x17m\xbe2I\xe3E\xcdO\xa9g\xc0\xed\x13\xb2LG\u5189\x15\xae\xf9\xf1\xc3\x1c\u007f\x00\x00\xe0\x94\xba\x1f\x0e\x03\u02da\xa0!\xf4\xdc\xeb\xfa\x94\xe5\u0209\xc9\u01fc\x9e\x8a\x06\u0450\xc4u\x16\x9a \x00\x00\u07d4\xba\x1f\xca\xf2#\x93~\xf8\x9e\x85gU\x03\xbd\xb7\xcaj\x92\x8bx\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\xe0\x94\xba$\xfcCgS\xa79\xdb,\x8d@\xe6\xd4\xd0LR\x8e\x86\xfa\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xbaB\xf9\xaa\xceL\x18E\x04\xab\xf5BWb\xac\xa2oq\xfb\u0709\x02\a\a}\u0627\x9c\x00\x00\u07d4\xbaF\x9a\xa5\u00c6\xb1\x92\x95\u0521\xb5G;T\x03S9\f\x85\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbad@\xae\xb3s{\x8e\xf0\xf1\xaf\x9b\f\x15\xf4\xc2\x14\xff\xc7\u03c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbam1\xb9\xa2a\xd6@\xb5\u07a5\x1e\xf2\x16,1\t\xf1\uba0a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xbap\xe8\xb4u\x9c\f<\x82\xcc\x00\xacN\x9a\x94\xdd[\xaf\xb2\xb8\x890C\xfa3\xc4\x12\xd7\x00\x00\u07d4\xba\x8ac\xf3\xf4\r\u4a03\x88\xbcP!/\xea\x8e\x06O\xbb\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x8eF\u059d.#C\xd8l`\xd8,\xf4, A\xa0\xc1\u0089\x05k\xc7^-c\x10\x00\x00\u07d4\xba\xa4\xb6L+\x15\xb7\x9f_ BF\xfdp\xbc\xbd\x86\xe4\xa9*\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xba\u0212,J\xcc},\xb6\xfdY\xa1N\xb4\\\xf3\xe7\x02!K\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xba\xd25\xd5\b]\u01f0h\xa6|A&w\xb0>\x186\x88L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\xd4B^\x17\x1c>r\x97^\xb4j\xc0\xa0\x15\xdb1Z]\x8f\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xba\xdc*\xef\x9fYQ\xa8\u05cak5\xc3\u0433\xa4\xe6\xe2\xe79\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xba\xdeCY\x9e\x02\xf8OL0\x14W\x1c\x97k\x13\xa3le\xab\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\xe9\xb8/r\x99c\x14\be\x9d\xd7N\x89\x1c\xb8\xf3\x86\x0f\xe5\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xbb\x03f\xa7\u03fd4E\xa7\r\xb7\xfeZ\xe3H\x85uO\xd4h\x8a\x01M\xef,B\xeb\xd6@\x00\x00\u07d4\xbb\aj\xac\x92 \x80i\xea1\x8a1\xff\x8e\xeb\x14\xb7\xe9\x96\xe3\x89\b\x13\xcaV\x90m4\x00\x00\u07d4\xbb\bW\xf1\xc9\x11\xb2K\x86\u0227\x06\x81G?\u6aa1\xcc\xe2\x89\x05k\xc7^-c\x10\x00\x00\u0794\xbb\x19\xbf\x91\u02edt\xcc\xeb_\x81\x1d\xb2~A\x1b\xc2\xea\x06V\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xbb'\u01a7\xf9\x10uGZ\xb2)a\x90@\xf8\x04\xc8\xeczj\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xbb7\x1cr\xc9\xf01l\xea+\xd9\xc6\xfb\xb4\a\x9ewT)\xef\x89_h\xe8\x13\x1e\u03c0\x00\x00\xe0\x94\xbb;\x01\v\x18\xe6\xe2\xbe\x115\x87\x10&\xb7\xba\x15\xea\x0f\xde$\x8a\x02 |\x800\x9bwp\x00\x00\xe0\x94\xbb;\x90\x05\xf4o\xd2\xca;0\x16%\x99\x92\x8cw\xd9\xf6\xb6\x01\x8a\x01\xb1\xae\u007f+\x1b\xf7\xdb\x00\x00\u07d4\xbb?\xc0\xa2\x9c\x03Mq\b\x12\xdc\xc7u\xc8\u02b9\u048diu\x899\xd4\xe8D\xd1\xcf_\x00\x00\u07d4\xbbH\xea\xf5\x16\xce-\xec>A\xfe\xb4\xc6y\xe4\x95vA\x16O\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xbbKJKT\x80p\xffAC,\x9e\b\xa0\xcao\xa7\xbc\x9fv\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\xbbV\xa4\x04r<\xff \xd0hT\x88\xb0Z\x02\xcd\xc3Z\xac\xaa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbba\x8e%\"\x1a\u0667@\xb2\x99\xed\x14\x06\xbc94\xb0\xb1m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbba\xa0K\xff\xd5|\x10G\rE\u00d1\x03\xf6FP4v\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbbh#\xa1\xbd\x81\x9f\x13QU8&J-\xe0R\xb4D\"\b\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xbbl(J\xac\x8ai\xb7\\\u0770\x0f(\xe1EX;V\xbe\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xbbu\xcbPQ\xa0\xb0\x94KFs\xcau*\x97\x03\u007f|\x8c\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbb\x99;\x96\xee\x92Z\xda}\x99\u05c6W=?\x89\x18\f\u3a89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa3\u0180\x04$\x8eH\x95s\xab\xb2t6w\x06k$\u0227\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa4\xfa\xc3\xc4 9\xd8(\xe7B\xcd\xe0\xef\xff\xe7t\x94\x1b9\x89lj\u04c2\xd4\xfba\x00\x00\u07d4\xbb\xa8\xab\"\xd2\xfe\xdb\xcf\xc6?hL\b\xaf\xdf\x1c\x17P\x90\xb5\x89\x05_)\xf3~N;\x80\x00\u07d4\xbb\xa9v\xf1\xa1!_u\x12\x87\x18\x92\xd4_pH\xac\xd3V\u0209lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbb\xab\x00\v\x04\b\xed\x01Z7\xc0GG\xbcF\x1a\xb1N\x15\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xbb\xab\xf6d;\xebK\xd0\x1c\x12\v\xd0Y\x8a\t\x87\xd8)g\u0449\xb52\x81x\xad\x0f*\x00\x00\u07d4\xbb\xb4\xee\x1d\x82\xf2\xe1VD,\xc938\xa2\xfc(o\xa2\x88d\x89JD\x91\xbdm\xcd(\x00\x00\u07d4\xbb\xb5\xa0\xf4\x80,\x86H\x00\x9e\x8ai\x98\xaf5,\u0787TO\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4\xbb\xb6C\xd2\x18{6J\xfc\x10\xa6\xfd6\x8d}U\xf5\r\x1a<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbb\xb8\xff\xe4?\x98\u078e\xae\x18F#\xaeRd\xe4$\u0438\u05c9\x05\xd5?\xfd\xe9(\b\x00\x00\u07d4\xbb\xbdn\u02f5u(\x91\xb4\u03b3\xcc\xe7:\x8fGpY7o\x89\x01\xf3\x99\xb1C\x8a\x10\x00\x00\u07d4\xbb\xbf9\xb1\xb6y\x95\xa4\"APO\x97\x03\u04a1JQV\x96\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbb\xc8\xea\xffc~\x94\xfc\u014d\x91\xdb\\\x89\x12\x1d\x06\xe1/\xff\x98\x80\x00\u07d4\xbc\u065e\xdc!`\xf2\x10\xa0^:\x1f\xa0\xb0CL\xed\x00C\x9b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbc\u07ec\xb9\xd9\x02<4\x17\x18.\x91\x00\xe8\xea\x1d73\x93\xa3\x89\x034-`\xdf\xf1\x96\x00\x00\u07d4\xbc\xe1>\"2*\u03f3U\xcd!\xfd\r\xf6\f\xf9:\xdd&\u0189\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xbc\xe4\x04u\xd3E\xb0q-\xeep=\x87\xcdvW\xfc\u007f;b\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\xbc\xed\xc4&|\u02c9\xb3\x1b\xb7d\xd7!\x11q\x00\x8d\x94\xd4M\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbc\xfc\x98\xe5\xc8+j\xdb\x18\n?\xcb\x12\v\x9av\x90\xc8j?\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\x04;g\xc6>`\xf8A\xcc\xca\x15\xb1)\xcd\xfee\x90\xc8\xe3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd\x04\u007f\xf1\xe6\x9c\u01b2\x9a\xd2d\x97\xa9\xa6\xf2z\x90?\xc4\u0749.\xe4IU\b\x98\xe4\x00\x00\u07d4\xbd\b\xe0\xcd\xde\xc0\x97\xdby\x01\ua05a=\x1f\xd9\u0789Q\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbd\t\x12l\x89\x1cJ\x83\x06\x80Y\xfe\x0e\x15ylFa\xa9\xf4\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xbd\f\\\u05d9\xeb\u0106B\xef\x97\xd7N\x8eB\x90d\xfe\u4489\x11\xac(\xa8\xc7)X\x00\x00\u07d4\xbd\x17\xee\xd8+\x9a%\x92\x01\x9a\x1b\x1b<\x0f\xba\xd4\\@\x8d\"\x89\r\x8drkqw\xa8\x00\x00\u07d4\xbd\x18\x037\v\u0771)\xd29\xfd\x16\xea\x85&\xa6\x18\x8a\u5389\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbd+p\xfe\xcc7d\x0fiQO\xc7\xf3@IF\xaa\xd8k\x11\x89A\rXj \xa4\xc0\x00\x00\u07d4\xbd0\x97\xa7\x9b<\r.\xbf\xf0\xe6\xe8j\xb0\xed\xad\xbe\xd4p\x96\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xbd2]@)\xe0\xd8r\x9fm9\x9cG\x82$\xae\x9ez\xe4\x1e\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xbdC*9\x16$\x9bG$):\xf9\x14nI\xb8(\n\u007f*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbdG\xf5\xf7n;\x93\x0f\xd9HR\t\xef\xa0\xd4v=\xa0uh\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbdK`\xfa\xect\n!\xe3\a\x13\x91\xf9j\xa54\xf7\xc1\xf4N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xbdK\u0571\"\xd8\xef{|\x8f\x06gE\x03 \xdb!\x16\x14.\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbdQ\xee.\xa1C\u05f1\u05b7~~D\xbd\xd7\xda\x12\U00105b09G~\x06\u0332\xb9(\x00\x00\u07d4\xbdY\tN\aO\x8dy\x14*\xb1H\x9f\x14\x8e2\x15\x1f \x89\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbdZ\x8c\x94\xbd\x8b\xe6G\x06D\xf7\f\x8f\x8a3\xa8\xa5\\cA\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd^G:\xbc\xe8\xf9zi2\xf7|/\xac\xaf\x9c\xc0\xa0\x05\x14\x89<\x92X\xa1\x06\xa6\xb7\x00\x00\u07d4\xbd_F\u02ab,=K(\x93\x96\xbb\xb0\u007f *\x06\x11>\xd4\xc3\xfb\xa1\xa8\x91;\x19@~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\x9eV\xe9\x02\xf4\xbe\x1f\xc8v\x8d\x808\xba\xc6>*\u02ff\x8e\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xbd\xa4\xbe1~~K\xed\x84\xc0I^\xee2\xd6\a\xec8\xcaR\x89}2'yx\xefN\x80\x00\u07d4\xbd\xb6\v\x82:\x11s\xd4Z\a\x92$_\xb4\x96\xf1\xfd3\x01\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xba\xf6CM@\xd65[\x1e\x80\xe4\f\u012b\x9ch\xd9a\x16\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbd\xc0,\xd43\f\x93\xd6\xfb\xdaOm\xb2\xa8]\xf2/C\xc23\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc4aF+c\"\xb4b\xbd\xb3?\"y\x9e\x81\b\xe2A}\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xbd\xc79\xa6\x99p\v.\x8e,JL{\x05\x8a\x0eQ=\u07be\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc7Hs\xaf\x92+\x9d\xf4t\x85;\x0f\xa7\xff\v\xf8\xc8&\x95\x89\xd8\xc9F\x00c\xd3\x1c\x00\x00\u07d4\xbd\xca*\x0f\xf3E\x88\xafb_\xa8\xe2\x8f\xc3\x01Z\xb5\xa3\xaa\x00\x89~\xd7?w5R\xfc\x00\x00\u07d4\xbd\xd3%N\x1b:m\xc6\xcc,i}Eq\x1a\xca!\xd5\x16\xb2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbd\u07e3M\x0e\xbf\x1b\x04\xafS\xb9\x9b\x82IJ\x9e=\x8a\xa1\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xbd\xe4\xc7?\x96\x9b\x89\xe9\u03aef\xa2\xb5\x18DH\x0e\x03\x8e\x9a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbd\xe9xj\x84\xe7[H\xf1\x8erm\u05cdp\xe4\xaf>\xd8\x02\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xbd\xed\x11a/\xb5\xc6\u0699\xd1\xe3\x0e2\v\xc0\x99Tf\x14\x1e\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xbd\xed~\a\xd0q\x1ehM\xe6Z\u0232\xabW\xc5\\\x1a\x86E\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xbd\xf6\x93\xf83\xc3\xfeG\x17S\x18G\x88\xebK\xfeJ\xdc?\x96\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\xf6\xe6\x8c\f\xd7X@\x80\xe8G\xd7,\xbb#\xaa\xd4j\xeb\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbe\n/8_\t\xdb\xfc\xe9g2\xe1+\xb4\n\xc3I\x87\x1b\xa8\x89WL\x11^\x02\xb8\xbe\x00\x00\u07d4\xbe\f*\x80\xb9\xde\bK\x17(\x94\xa7l\xf4szOR\x9e\x1a\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\x1c\xd7\xf4\xc4r\a\th\xf3\xbd\xe2h6k!\xee\xea\x83!\x89\xe9\x1a|\u045f\xa3\xb0\x00\x00\u07d4\xbe#F\xa2\u007f\xf9\xb7\x02\x04OP\r\xef\xf2\xe7\xff\xe6\x82EA\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbe$q\xa6\u007f`G\x91\x87r\xd0\xe3h9%^\xd9\u0591\xae\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbe+\"\x80R7h\xea\x8a\xc3\\\xd9\xe8\x88\xd6\nq\x93\x00\u0509lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe+2nx\xed\x10\xe5P\xfe\xe8\xef\xa8\xf8\a\x03\x96R/Z\x8a\bW\xe0\xd6\xf1\xdav\xa0\x00\x00\xe0\x94\xbe0Zyn3\xbb\xf7\xf9\xae\xaee\x12\x95\x90f\xef\xda\x10\x10\x8a\x02M\xceT\xd3J\x1a\x00\x00\x00\u07d4\xbeG\x8e\x8e=\xdek\xd4\x03\xbb-\x1ce|C\x10\xee\x19'#\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\xbeN}\x98?.*ck\x11\x02\xecp9\xef\xeb\xc8B\u9349\x03\x93\xef\x1aQ'\xc8\x00\x00\u07d4\xbeO\xd0sap\"\xb6\u007f\\\x13I\x9b\x82\u007fv69\xe4\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbeRZ3\xea\x91aw\xf1r\x83\xfc\xa2\x9e\x8b5\v\u007fS\v\x89\x8f\x01\x9a\xafF\xe8x\x00\x00\u07d4\xbeS2/C\xfb\xb5\x84\x94\xd7\xcc\xe1\x9d\xda'+$P\xe8'\x89\n\xd7\u03afB\\\x15\x00\x00\u07d4\xbeS\x82F\xddNo\f \xbfZ\xd17<;F:\x13\x1e\x86\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbeZ`h\x99\x98c\x9a\xd7[\xc1\x05\xa3qt>\xef\x0fy@\x89\x1b2|s\xe1%z\x00\x00\u07d4\xbe\\\xba\x8d7By\x86\xe8\xca&\x00\xe8X\xbb\x03\xc3YR\x0f\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\xbe`\x03~\x90qJK\x91~a\xf1\x93\xd84\x90g\x03\xb1:\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbec:77\xf6\x849\xba\xc7\xc9\nR\x14 X\ue38ao\x894\n\xad!\xb3\xb7\x00\x00\x00\xe0\x94\xbee\x9d\x85\xe7\xc3O\x883\xea\u007fH\x8d\xe1\xfb\xb5\xd4\x14\x9b\xef\x8a\x01\xeb\xd2:\xd9\u057br\x00\x00\u07d4\xbes'M\x8cZ\xa4J<\xbe\xfc\x82c\xc3{\xa1!\xb2\n\u04c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbe\x86\u0430C\x84\x19\u03b1\xa081\x927\xbaR\x06\xd7.F\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xbe\x8d\u007f\x18\xad\xfe]l\xc7u9I\x89\xe1\x93\f\x97\x9d\x00}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\x91\x86\xc3JRQJ\xbb\x91\a\x86\x0fgO\x97\xb8!\xbd[\x89\x1b\xa0\x1e\xe4\x06\x03\x10\x00\x00\u07d4\xbe\x93W\x93\xf4[p\xd8\x04]&T\xd8\xdd:\xd2K[a7\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xbe\x98\xa7\u007f\xd4\x10\x97\xb3OY\xd7X\x9b\xaa\xd0!e\x9f\xf7\x12\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xbe\x9b\x8c4\xb7\x8e\xe9G\xff\x81G.\xdaz\xf9\xd2\x04\xbc\x84f\x89\b!\xab\rD\x14\x98\x00\x00\u07d4\xbe\xa0\r\xf1pg\xa4:\x82\xbc\x1d\xae\xca\xfbl\x140\x0e\x89\xe6\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xbe\xa0\xaf\xc9:\xae!\b\xa3\xfa\xc0Yb;\xf8o\xa5\x82\xa7^\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbe\xb35\x8cP\u03dfu\xff\xc7mD<,\u007fU\aZ\x05\x89\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xbe\xb4\xfd1UYC`E\u0739\x9dI\xdc\xec\x03\xf4\fB\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xc2\xe6\xde9\xc0|+\xaeUj\u03fe\xe2\xc4r\x8b\x99\x82\xe3\x89\x1f\x0f\xf8\xf0\x1d\xaa\xd4\x00\x00\u07d4\xbe\xc6d\x0fI\t\xb5\x8c\xbf\x1e\x80cB\x96\x1d`u\x95\tl\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\xc8\xca\xf7\xeeIF\x8f\xeeU.\xff:\xc5#N\xb9\xb1}B\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xce\xf6\x1c\x1cD+\xef|\xe0Ks\xad\xb2I\xa8\xba\x04~\x00\x896;V\u00e7T\xc8\x00\x00\u0794\xbe\xd4d\x9d\xf6F\u2052)\x03-\x88hUo\xe1\xe0S\u04c8\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xbe\xd4\xc8\xf0\x06\xa2|\x1e_|\xe2\x05\xdeu\xf5\x16\xbf\xb9\xf7d\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xbe\xe8\u0430\bB\x19T\xf9-\x00\r9\x0f\xb8\xf8\xe6X\xea\xee\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\xec\u05af\x90\f\x8b\x06J\xfc\xc6\a?-\x85\u055a\xf1\x19V\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe\xef\x94!8y\xe0&\"\x14+\xeaa)\tx\x93\x9a`\u05ca\x016\x85{2\xad\x86\x04\x80\x00\xe0\x94\xbe\xf0}\x97\xc3H\x1f\x9dj\xee\x1c\x98\xf9\xd9\x1a\x18\n2D+\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xbe\xfbD\x8c\f_h?\xb6~\xe5p\xba\xf0\xdbV\x86Y\x97Q\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbf\x05\a\f,4!\x93\x11\xc4T\x8b&\x14\xa48\x81\r\xedm\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbf\x05\xff^\xcf\r\xf2\u07c8wY\xfb\x82t\xd928\xac&}\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\xbf\t\xd7pH\xe2p\xb6b3\x0e\x94\x86\xb3\x8bC\xcdx\x14\x95\x8a\\S\x9b{\xf4\xff(\x80\x00\x00\u07d4\xbf\x17\xf3\x97\xf8\xf4o\x1b\xaeE\u0447\x14\x8c\x06\xee\xb9Y\xfaM\x896I\u0156$\xbb0\x00\x00\u07d4\xbf\x186A\xed\xb8\x86\xce`\xb8\x19\x02a\xe1OB\xd9<\xce\x01\x89\x01[5W\xf1\x93\u007f\x80\x00\u07d4\xbf*\xeaZ\x1d\xcfn\u04f5\xe829D\xe9\x83\xfe\xdf\u046c\xfb\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbf@\x96\xbcT}\xbf\xc4\xe7H\t\xa3\x1c\x03\x9e{8\x9d^\x17\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xbfI\xc1H\x981eg\u0637\t\xc2\xe5\x05\x94\xb3f\xc6\u04cc\x89'\xbf8\xc6TM\xf5\x00\x00\u07d4\xbfLs\xa7\xed\xe7\xb1d\xfe\a!\x14\x846T\xe4\xd8x\x1d\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfP\xce.&K\x9f\xe2\xb0h0az\xed\xf5\x02\xb25\x1bE\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfY\xae\xe2\x81\xfaC\xfe\x97\x19CQ\xa9\x85~\x01\xa3\xb8\x97\xb2\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbfh\u048a\xaf\x1e\xee\xfe\xf6F\xb6^\x8c\xc8\u0450\xf6\xc6\u069c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfi%\xc0\aQ\x00\x84@\xa6s\x9a\x02\xbf+l\u06ab^:\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfw\x01\xfcb%\u0561x\x15C\x8a\x89A\xd2\x1e\xbc]\x05\x9d\x89e\xea=\xb7UF`\x00\x00\u07d4\xbf\x8b\x80\x05\xd66\xa4\x96d\xf7Bu\xefBC\x8a\xcde\xac\x91\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\x92A\x8a\fl1$M\"\x02`\xcb>\x86}\u05f4\xefI\x89\x05i\x00\xd3<\xa7\xfc\x00\x00\u07d4\xbf\x9a\xcdDE\xd9\xc9UF\x89\u02bb\xba\xb1\x88\x00\xff\x17A\u008965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\x9f'\x1fz~\x12\xe3m\xd2\xfe\x9f\xac\xeb\xf3\x85\xfeaB\xbd\x89\x03f\xf8O{\xb7\x84\x00\x00\u07d4\xbf\xa8\xc8X\xdf\x10,\xb1$!\x00\x8b\n1\xc4\xc7\x19\n\xd5`\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\xae\xb9\x10ga}\u03cbD\x17+\x02\xafaVt\x83]\xba\x89\b\xb5\x9e\x88H\x13\b\x80\x00\xe0\x94\xbf\xb0\xea\x02\xfe\xb6\x1d\xec\x9e\"\xa5\a\tY3\x02\x99\xc40r\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xbf\xbc\xa4\x18\xd3R\x9c\xb3\x93\b\x10b\x03*n\x11\x83\u01b2\u070a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xbf\xbe\x05\u831c\xbb\xcc\x0e\x92\xa4\x05\xfa\xc1\xd8]\xe2H\xee$\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xbf\xbf\xbc\xb6V\u0099+\xe8\xfc\u0782\x19\xfb\xc5J\xad\u055f)\x8a\x02\x1e\x18\xd2\xc8!\xc7R\x00\x00\u07d4\xbf\xc5z\xa6f\xfa\u239f\x10zI\xcbP\x89\xa4\xe2!Q\u074965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\u02d70$c\x04p\r\xa9\vAS\xe7\x11Ab.\x1cA\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbf\xd9<\x90\u009c\a\xbc_\xb5\xfcI\xae\xeaU\xa4\x0e\x13O5\x8a\x05\xed\xe2\x0f\x01\xa4Y\x80\x00\x00\xe0\x94\xbf\xe3\xa1\xfcn$\xc8\xf7\xb3%\x05`\x99\x1f\x93\u02e2\u03c0G\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xbf\u6f30\xf0\xc0xRd3$\xaa]\xf5\xfdb%\xab\xc3\u0289\x04\t\xe5+H6\x9a\x00\x00\u07d4\xbf\xf5\xdfv\x994\xb8\x94<\xa9\x13}\x0e\xfe\xf2\xfen\xbb\xb3N\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbf\xfbi)$\x1fx\x86\x93'>p\"\xe6\x0e>\xab\x1f\xe8O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x06O\x1d\x94t\xab\x91]V\x90l\x9f\xb3 \xa2\xc7\t\x8c\x9b\x89\x13h?\u007f<\x15\xd8\x00\x00\u07d4\xc0\a\xf0\xbd\xb6\xe7\x00\x92\x02\xb7\xaf>\xa9\t\x02i|r\x14\x13\x89\xa2\xa0\xe4>\u007f\xb9\x83\x00\x00\u07d4\xc0\n\xb0\x80\xb6C\xe1\u00ba\xe3c\xe0\u0455\xde.\xff\xfc\x1cD\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\xc0 wD\x9a\x13Jz\xd1\xef~M\x92z\xff\xec\ueb75\xae\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc0$q\xe3\xfc.\xa0S&\x15\xa7W\x1dI2\x89\xc1<6\xef\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0-n\xad\xea\xcf\x1bx\xb3\u0285\x03\\c{\xb1\xce\x01\xf4\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc03\xb12Z\n\xf4Tr\xc2U'\x85;\x1f\x1c!\xfa5\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc03\xbe\x10\xcbHa;\xd5\xeb\xcb3\xedI\x02\xf3\x8bX0\x03\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc04[3\xf4\x9c\xe2\u007f\xe8,\xf7\xc8M\x14\x1ch\xf5\x90\xcev\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0=\xe4*\x10\x9bezd\xe9\"$\xc0\x8d\xc1'^\x80\u0672\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0@i\u07f1\x8b\tlxg\xf8\xbe\xe7zm\xc7Gz\xd0b\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xc0A?Z|-\x9aK\x81\b(\x9e\xf6\xec\xd2qx\x15$\xf4\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xc0C\xf2E-\u02d6\x02\xefb\xbd6\x0e\x03=\xd29q\xfe\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0OK\xd4\x04\x9f\x04F\x85\xb8\x83\xb6)Y\xaec\x1df~5\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0V\u053dk\xf3\u02ec\xace\xf8\xf5\xa0\xe3\x98\v\x85'@\xae\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0[t\x06 \xf1s\xf1nRG\x1d\u00cb\x9cQJ\v\x15&\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\xc0i\xef\x0e\xb3B\x99\xab\xd2\xe3-\xab\xc4yD\xb2r3H$\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\xc0l\xeb\xbb\xf7\xf5\x14\x9af\xf7\xeb\x97k>G\xd5e\x16\xda/\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0r^\u00bd\xc3:\x1d\x82`q\u07a2\x9db\xd48Z\x8c%\x8a\b\xa0\x85\x13F:\xa6\x10\x00\x00\u07d4\xc0~8g\xad\xa0\x96\x80z\x05\x1al\x9c4\xcc;?J\xd3J\x89`\xf0f \xa8IE\x00\x00\u07d4\xc0\x89^\xfd\x05m\x9a:\x81\xc3\xdaW\x8a\xda1\x1b\xfb\x93V\u03c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x90\xfe#\xdc\xd8k5\x8c2\xe4\x8d*\xf9\x10$%\x9fef\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x9af\x17*\xea7\r\x9ac\xda\x04\xffq\xff\xbb\xfc\xff\u007f\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x9e<\xfc\x19\xf6\x05\xff>\xc9\xc9\xc7\x0e%@\xd7\xee\x97Cf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc0\xa0*\xb9N\xbeV\xd0E\xb4\x1bb\x9b\x98F.:\x02J\x93\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0\xa3\x93\b\xa8\x0e\x9e\x84\xaa\xaf\x16\xac\x01\xe3\xb0\x1dt\xbdk-\x89\afM\xddL\x1c\v\x80\x00\u07d4\xc0\xa6\u02edwi*=\x88\xd1A\xefv\x9a\x99\xbb\x9e<\x99Q\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xc0\xa7\xe8C]\xff\x14\xc2Uws\x9d\xb5\\$\u057fW\xa3\u064a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xc0\xae\x14\xd7$\x83./\xce'x\xde\u007f{\x8d\xaf{\x12\xa9>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0\xaf\xb7\u0637\x93p\xcf\xd6c\u018c\u01b9p*7\u035e\xff\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0\xb0\xb7\xa8\xa6\xe1\xac\xdd\x05\xe4\u007f\x94\xc0\x96\x88\xaa\x16\u01ed\x8d\x89\x03{m\x02\xacvq\x00\x00\xe0\x94\xc0\xb3\xf2D\xbc\xa7\xb7\xde[H\xa5>\u06dc\xbe\xab\vm\x88\xc0\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0\xc0M\x01\x06\x81\x0e>\xc0\xe5J\x19\U000ab157\xe6\x9aW=\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xc0\xca2w\x94.tE\x87K\xe3\x1c\xeb\x90)rqO\x18#\x89\r\x8drkqw\xa8\x00\x00\u07d4\xc0\u02ed<\xcd\xf6T\xda\"\xcb\xcf\\xe\x97\xca\x19U\xc1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\xcb\xf6\x03/\xa3\x9e|F\xffw\x8a\x94\xf7\xd4E\xfe\"\xcf0\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4\xc0\xe0\xb9\x03\b\x8e\fc\xf5=\xd0iWTR\xaf\xf5$\x10\u00c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc0\xe4W\xbdV\xec6\xa1$k\xfa20\xff\xf3\x8eY&\xef\"\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xc0\xed\rJ\xd1\r\xe045\xb1S\xa0\xfc%\xde;\x93\xf4R\x04\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xc0\xf2\x9e\xd0\af\x11\xb5\xe5^\x13\x05G\xe6\x8aH\xe2m\xf5\u4262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc1\x13(x#\\]\u06e5\xd9\xf3\"\x8bR6\xe4p \xdco\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1\x17\r\xba\xad\xb3\xde\xe6\x19\x8e\xa5D\xba\xec\x93%\x18`\xfd\xa5\x89A\rXj \xa4\xc0\x00\x00\xe0\x94\xc1&W=\x87\xb0\x17ZR\x95\xf1\xdd\a\xc5u\u03cc\xfa\x15\xf2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc1'\xaa\xb5\x90e\xa2\x86D\xa5k\xa3\xf1^.\xac\x13\xda)\x95\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xc1+\u007f@\u07da/{\xf9\x83f\x14\"\xab\x84\xc9\xc1\xf5\bX\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc1,\xfb{=\xf7\x0f\xce\xca\x0e\xde&5\x00\xe2xs\xf8\xed\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1/\x88\x1f\xa1\x12\xb8\x19\x9e\xcb\xc7>\xc4\x18W\x90\xe6\x14\xa2\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc18Lnq~\xbeK#\x01NQ\xf3\x1c\x9d\xf7\xe4\xe2[1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1C\x8c\x99\xddQ\xef\x1c\xa88j\xf0\xa3\x17\xe9\xb0AEx\x88\x89\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xc1c\x12(\xef\xbf*.:@\x92\xee\x89\x00\xc69\xed4\xfb\u02093\xc5I\x901r\f\x00\x00\u07d4\xc1u\xbe1\x94\xe6iB-\x15\xfe\xe8\x1e\xb9\xf2\xc5lg\xd9\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\x82v\x86\xc0\x16\x94\x85\xec\x15\xb3\xa7\xc8\xc0\x15\x17\xa2\x87M\xe1\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xc1\x8a\xb4g\xfe\xb5\xa0\xaa\xdf\xff\x91#\x0f\xf0VFMx\xd8\x00\x89lk\x93[\x8b\xbd@\x00\x00\u0794\xc1\x95\x05CUM\x8aq0\x03\xf6b\xbba,\x10\xadL\xdf!\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc1\xa4\x1aZ'\x19\x92&\xe4\xc7\xeb\x19\x8b\x03\x1bY\x19o\x98B\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xc1\xb2\xa0\xfb\x9c\xadE\xcdi\x91\x92\xcd'T\v\x88\xd38By\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1\xb2\xaa\x8c\xb2\xbfb\xcd\xc1:G\xec\xc4e\u007f\xac\xaa\x99_\x98\x8967\x93\xfa\x96\u6980\x00\u07d4\xc1\xb5\x00\x01\x1c\xfb\xa9]|\xd66\xe9^l\xbfagFK%\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\xb9\xa5pM5\x1c\xfe\x98?y\xab\xee\xc3\u06fb\xae;\xb6)\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xcb\xd2\xe23*RL\xf2\x19\xb1\r\x87\x1c\xcc \xaf\x1f\xb0\xfa\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xc1\xcd\xc6\x01\xf8\x9c\x04(\xb3\x13\x02\u0447\xe0\xdc\b\xad}\x1cW\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xc1\u052f8\xe9\xbay\x90@\x89HI\xb8\xa8!\x93u\xf1\xacx\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc1\xe1@\x9c\xa5,%CQ4\xd0\x06\u00a6\xa8T-\xfbrs\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xc1\xeb\xa5hJ\xa1\xb2L\xbac\x15\x02c\xb7\xa9\x13\x1a\xee\u008d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xec\x81\xdd\x12=K|-\u0674\xd48\xa7\a,\x11\u0707L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc1\xf3\x9b\xd3]\xd9\xce\xc37\xb9oG\xc6w\x81\x81`\xdf7\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xc1\xff\xad\a\u06d6\x13\x8cK*S\x0e\xc1\xc7\xde)\xb8\xa0Y,\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xc2\x1f\xa6d:\x1f\x14\xc0)\x96\xadqD\xb7Y&\xe8~\xcbK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc24\nL\xa9L\x96x\xb7IL<\x85%(\xed\xe5\xeeR\x9f\x89\x02\xa3k\x05\xa3\xfd|\x80\x00\u07d4\xc29\xab\u07ee>\x9a\xf5E\u007fR\xed+\x91\xfd\n\xb4\xd9\xc7\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2;/\x92\x1c\xe4\xa3z%\x9e\u4b4b!X\xd1]fOY\x89\x01`\x89\x95\xe8\xbd?\x80\x00\u07d4\xc2C\x99\xb4\xbf\x86\xf73\x8f\xbfd^;\"\xb0\u0dd79\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2L\u03bc#D\xcc\xe5d\x17\xfbhL\xf8\x16\x13\xf0\xf4\xb9\xbd\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc2Rf\xc7gf2\xf1>\xf2\x9b\xe4U\ud50a\xddVw\x92\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\\\xf8&U\f\x8e\xaf\x10\xaf\"4\xfe\xf9\x04\u0779R\x13\xbe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc2f?\x81E\xdb\xfe\xc6\xc6F\xfc\\I\x96\x13E\xde\x1c\x9f\x11\x89%g\xacp9+\x88\x00\x00\u07d4\xc2pEh\x854+d\vL\xfc\x1bR\x0e\x1aTN\xe0\xd5q\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc2sv\xf4]!\xe1^\xde;&\xf2e_\xce\xe0,\xcc\x0f*\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc2w\x97q\xf0Smy\xa8p\x8fi1\xab\xc4K05\u964a\x047\u04ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc2\xc1>r\xd2h\xe7\x15\r\u01d9\xe7\xc6\xcf\x03\u0209T\xce\u05c9%\xf2s\x93=\xb5p\x00\x00\u07d4\xc2\xcb\x1a\xda]\xa9\xa0B8s\x81G\x93\xf1aD\xef6\xb2\xf3\x89HU~;p\x17\xdf\x00\x00\u07d4\xc2\xd1w\x8e\xf6\xee_\xe4\x88\xc1E\xf3Xkn\xbb\xe3\xfb\xb4E\x89>\x1f\xf1\xe0;U\xa8\x00\x00\xe0\x94\xc2\xd9\xee\xdb\xc9\x01\x92c\xd9\xd1l\u016e\a-\x1d=\xd9\xdb\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc2\xe0XJq4\x8c\xc3\x14\xb7; )\xb6#\v\x92\u06f1\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2\xe2\u0518\xf7\r\xcd\bY\xe5\v\x02:q\nmK!3\xbd\x8989\x11\xf0\f\xbc\xe1\x00\x00\u07d4\xc2\xed_\xfd\u046d\xd8U\xa2i/\xe0b\xb5\xd6\x18t#`\u0509A\rXj \xa4\xc0\x00\x00\u07d4\xc2\xee\x91\xd3\xefX\xc9\u0465\x89\x84N\xa1\xae1%\xd6\u017ai\x894\x95tD\xb8@\xe8\x00\x00\u07d4\xc2\xfa\xfd\xd3\n\xcbmg\x06\xe9)<\xb0&A\xf9\xed\xbe\a\xb5\x89Q\x00\x86\vC\x0fH\x00\x00\u07d4\xc2\xfd\v\xf7\xc7%\xef>\x04~Z\xe1\u009f\xe1\x8f\x12\xa7)\x9c\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\xfe}us\x1fcm\xcd\t\xdb\xda\x06q9;\xa0\xc8*}\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\xc3\x10z\x9a\xf32-R8\xdf\x012A\x911b\x959W}\x89\x1a\xb4\xe4d\xd4\x141\x00\x00\xe0\x94\xc3\x11\v\xe0\x1d\xc9sL\xfcn\x1c\xe0\u007f\x87\xd7}\x13E\xb7\xe1\x8a\x01\x0f\f\xe9I\xe0\x0f\x93\x00\x00\u07d4\xc3 8\xcaR\xae\xe1\x97E\xbe\\1\xfc\xdcT\x14\x8b\xb2\xc4\u0409\x02\xb5\xaa\xd7,e \x00\x00\u07d4\xc3%\xc3R\x80\x1b\xa8\x83\xb3\"l_\xeb\r\xf9\xea\xe2\xd6\xe6S\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xc3.\xc7\xe4*\xd1l\xe3\xe2UZ\xd4\xc5C\x06\xed\xa0\xb2gX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc32\xdfP\xb1<\x014\x90\xa5\xd7\xc7]\xbf\xa3f\u0687\xb6\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc3:\u0373\xba\x1a\xab'P{\x86\xb1]g\xfa\xf9\x1e\xcfb\x93\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3>\u0393Z\x8fN\xf98\xea~\x1b\xac\x87\u02d2]\x84\x90\u028a\a\x03\x8c\x16x\x1fxH\x00\x00\u07d4\xc3@\xf9\xb9\x1c&r\x8c1\xd1!\xd5\xd6\xfc;\xb5m=\x86$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3F\xcb\x1f\xbc\xe2\xab(]\x8eT\x01\xf4-\xd7#M7\xe8m\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\xe0\x94\xc3H=n\x88\xac\x1fJ\xe7<\xc4@\x8dl\x03\xab\xe0\xe4\x9d\u028a\x03\x99\x92d\x8a#\u0220\x00\x00\xe0\x94\xc3H\xfcZF\x13#\xb5{\xe3\x03\u02c96\x1b\x99\x19\x13\xdf(\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc3N;\xa12.\xd0W\x11\x83\xa2O\x94 N\xe4\x9c\x18fA\x89\x03'\xaf\uf927\xbc\x00\x00\xe0\x94\xc3[\x95\xa2\xa3s|\xb8\xf0\xf5\x96\xb3E$\x87+\xd3\r\xa24\x8a\x01\x98\xbe\x85#^-P\x00\x00\xe0\x94\xc3c\x1cv\x98\xb6\xc5\x11\x19\x89\xbfE''\xb3\xf99Zm\xea\x8a\x02C'X\x96d\x1d\xbe\x00\x00\u07d4\xc3l\vc\xbf\xd7\\/\x8e\xfb\x06\b\x83\xd8h\xcc\xcdl\xbd\xb4\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xc3uk\xcd\xcc~\xect\xed\x89j\xdf\xc35'Y0&n\b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u00c4\xacn\xe2|9\xe2\xf2x\xc2 \xbd\xfa[\xae\xd6&\xd9\u04c9 \x86\xac5\x10R`\x00\x00\u07d4\u00e0F\xe3\u04b2\xbfh\x14\x88\x82n2\xd9\xc0aQ\x8c\xfe\x8c\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\u00e9\"j\xe2u\xdf,\xab1+\x91\x10@cJ\x9c\x9c\x9e\xf6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u00f9(\xa7o\xadex\xf0O\x05U\xe69R\xcd!\xd1R\n\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xc2)s)\xa6\xfd\x99\x11~T\xfcj\xf3y\xb4\xd5VT~\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc3\xc3\xc2Q\rg\x80 HZcs]\x13\a\xecL\xa60+\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc3\xcbk6\xafD?,n%\x8bJ9U:\x81\x87G\x81\x1f\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\xc3\xdbVW\xbbr\xf1\rX\xf21\xfd\xdf\x11\x98\n\xffg\x86\x93\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xc3\u06df\xb6\xf4lH\n\xf3De\u05d7S\xb4\xe2\xb7Jg\u038a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc3\xddX\x908\x860;\x92\x86%%z\xe1\xa0\x13\xd7\x1a\xe2\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe0G\x1cd\xff5\xfaR2\xcc1!\xd1\u04cd\x1a\x0f\xb7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe2\f\x96\u07cdN8\xf5\v&Z\x98\xa9\x06\xd6\x1b\xc5\x1aq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\u31f0<\xe9\\\xcf\xd7\xfaQ\u0744\x01\x83\xbcCS(\t\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xf8\xf6r\x95\xa5\xcd\x04\x93d\xd0]#P&#\xa3\xe5.\x84\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc4\x01\xc4'\xcc\xcf\xf1\r\xec\xb8d /6\xf5\x80\x83\"\xa0\xa8\x89\xb4{Q\xa6\x9c\xd4\x02\x00\x00\u07d4\xc4\b\x8c\x02_>\x85\x01?T9\xfb4@\xa1s\x01\xe5D\xfe\x89~\t\xdbM\x9f?4\x00\x00\u07d4\xc4\x14a\xa3\u03fd2\u0246UU\xa4\x8117\xc0v1#`\x8965\xc6 G9\u0640\x00\u07d4\xc4 8\x8f\xbe\xe8J\xd6V\xddh\xcd\xc1\xfb\xaa\x93\x92x\v4\x89\n-\xcac\xaa\xf4\u0140\x00\u07d4\xc4\"P\xb0\xfeB\xe6\xb7\xdc\xd5\u0210\xa6\xf0\u020f__\xb5t\x89\b\x1e\xe4\x82SY\x84\x00\x00\u07d4\xc4-j\xebq\x0e:P\xbf\xb4Ml1\t)i\xa1\x1a\xa7\xf3\x89\b\"c\xca\xfd\x8c\xea\x00\x00\xe0\x94\xc4@\xc7\xca/\x96Kir\xeffJ\"a\xdd\xe8\x92a\x9d\x9c\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xc4K\xde\xc8\xc3l\\h\xba\xa2\xdd\xf1\xd41i2)rlC\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc4OJ\xb5\xbc`9|s~\xb0h3\x91\xb63\xf8\xa2G\x1b\x12\x1c\xa4\x89 .h\xf2\u00ae\xe4\x00\x00\u07d4\xc4h\x1es\xbb\x0e2\xf6\xb7& H1\xffi\xba\xa4\x87~2\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc4k\xbd\xefv\xd4\xca`\xd3\x16\xc0\u007f]\x1ax\x0e;\x16_~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc4}a\v9\x92P\xf7\x0e\xcf\x13\x89\xba\xb6),\x91&O#\x89\x0f\xa7\xe7\xb5\xdf<\xd0\x00\x00\u07d4\u0100;\xb4\a\xc7b\xf9\vu\x96\xe6\xfd\u1513\x1ev\x95\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0106Q\xc1\xd9\xc1k\xffL\x95T\x88l??&C\x1foh\x89#\xab\x95\x99\xc4?\b\x00\x00\u07d4\u0109\xc8?\xfb\xb0%*\xc0\xdb\xe3R\x12\x17c\x0e\x0fI\x1f\x14\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u010bi<\xac\xef\xdb\xd6\xcb]x\x95\xa4.1\x962~&\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0113H\x9eV\u00fd\xd8)\x00}\xc2\xf9VA)\x06\xf7k\xfa\x89\x02\xa7\x91H\x8eqT\x00\x00\u07d4\u0116\u02f0E\x9aj\x01`\x0f\u0149\xa5Z2\xb4T!\u007f\x9d\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4\u011c\xfa\xa9g\xf3\xaf\xbfU\x03\x10a\xfcL\xef\x88\xf8]\xa5\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0136\xe5\xf0\x9c\xc1\xb9\r\xf0x\x03\xce=M\x13vj\x9cF\xf4\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\u013e\xc9c\b\xa2\x0f\x90\u02b1\x83\x99\u0113\xfd=\x06Z\xbfE\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xc4\xc0\x1a\xfc>\x0f\x04R!\xda\x12\x84\u05c7\x85tD/\xb9\xac\x8a\x01\x92\xb5\u0249\x02J\x19\xc1\xbdo\x12\x80\x00\xe0\x94\xc5\x00\xb7 sN\xd2)8\u05cc^H\xb2\xba\x93g\xa5u\xba\x8a\a\x12\x9e\x1c\xdf7>\xe0\x00\x00\u07d4\xc5\x0f\xe4\x15\xa6A\xb0\x85lNu\xbf\x96\x05\x15D\x1a\xfa5\x8d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\x13L\xfb\xb1\xdfz \xb0\xedpWb.\xee\u0480\x94}\xad\x89\xcd\xff\x97\xfa\xbc\xb4`\x00\x00\xe0\x94\xc5\x17\xd01\\\x87\x88\x13\xc7\x17\u132f\xa1\xea\xb2eN\x01\u068a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc5\x18y\x9aY%Wb\x13\xe2\x18\x96\xe0S\x9a\xbb\x85\xb0Z\xe3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\"\xe2\x0f\xbf\x04\xed\u007fk\x05\xa3{G\x18\xd6\xfc\xe0\x14.\x1a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc5$\bmF\xc8\x11+\x12\x8b/\xafo|}\x81`\xa88l\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc5-\x1a\fs\u00a1\xbe\x84\x91Q\x85\xf8\xb3O\xaa\n\xdf\x1d\xe3\x89K\xe4\xea\xb3\xfa\x0f\xa6\x80\x00\xe0\x94\xc55\x94\xc7\u03f2\xa0\x8f(L\xc9\u05e6;\xbd\xfc\v1\x972\x8a\nk#(\xff:b\xc0\x00\x00\u07d4\xc57I(\xcd\xf1\x93pTC\xb1L\xc2\r\xa4#G<\xd9\u03c9\a}\x10P\x9b\xb3\xaf\x80\x00\u07d4\xc58\xa0\xff(*\xaa_Ku\u03f6,p\x03~\xe6}O\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5;P\xfd;+r\xbclC\v\xaf\x19JQU\x85\u04d8m\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc5=y\xf7\u02dbp\x95/\xd3\x0f\xceX\xd5K\x9f\vY\xf6G\x8a\x01\x13\xe2\xd6tCE\xf8\x00\x00\u07d4\xc5I\u07c3\xc6\xf6^\xec\x0f\x1d\u0260\x93J\\_:P\xfd\x88\x89\x9d\xc0\\\xce(\u00b8\x00\x00\u07d4\xc5P\x05\xa6\xc3~\x8c\xa7\xe5C\xce%\x99s\xa3\xca\u0396\x1aJ\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5U\xb91V\xf0\x91\x01#\x80\x00\xe0\x94\u0166)\xa3\x96%R\u02ce\xde\u0609cj\xaf\xbd\f\x18\xcee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u016e\x86\xb0\xc6\xc7\xe3\x90\x0f\x13h\x10\\VS\u007f\xaf\x8dt>\x89\n1\x06+\xee\xedp\x00\x00\u07d4\u0170\t\xba\xea\xf7\x88\xa2v\xbd5\x81:\xd6[@\v\x84\x9f;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0175l\xd24&|(\xe8\x9cok\"f\xb0\x86\xa1/\x97\f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xc5\u01a4\x99\x8a3\xfe\xb7dCz\x8b\xe9)\xa7;\xa3J\ad\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\xe0\x94\xc5\xc7=a\xcc\xe7\xc8\xfeL\x8f\xce)\xf3\x90\x92\xcd\x19>\x0f\xff\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc5\xc7Y\vV!\xec\xf85\x85\x88\u079bh\x90\xf2baC\U000498a1]\tQ\x9b\xe0\x00\x00\u07d4\xc5\xcd\xce\xe0\xe8]\x11}\xab\xbfSj?@i\xbfD?T\xe7\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xc5\u050c\xa2\xdb/\x85\xd8\xc5U\xcb\x0e\x9c\xfe\x82i6x?\x9e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc5\xde\x12\x03\xd3\xcc,\xea1\xc8.\xe2\xdeY\x16\x88\a\x99\xea\xfd\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc5\xe4\x88\xcf+Vw\x939q\xf6L\xb8 -\xd0WR\xa2\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\xe8\x12\xf7o\x15\xf2\xe1\xf2\xf9\xbcH#H<\x88\x04cog\x89\x03\xf5\x14\x19:\xbb\x84\x00\x00\u07d4\xc5\u94d34\xf1%.\u04ba&\x81D\x87\xdf\u0498+1(\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\xc5\xebB)^\x9c\xad\xea\xf2\xaf\x12\xde\u078a\x8dS\xc5y\xc4i\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xc5\xed\xbb\xd2\xca\x03WeJ\xd0\xeaG\x93\xf8\xc5\xce\xcd0\xe2T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc5\xf6K\xab\xb7\x031B\xf2\x0eF\u05eab\x01\xed\x86\xf6q\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\xf6\x87qrF\u068a \r \xe5\u9f2c`\xb6\u007f8a\x89\x01\x8d\x99?4\xae\xf1\x00\x00\u07d4\xc6\x04[<5\vL\xe9\xca\fkuO\xb4\x1ai\xb9~\x99\x00\x892$\xf4'#\xd4T\x00\x00\u07d4\xc6\v\x04eN\x00;F\x83\x04\x1f\x1c\xbdk\u00cf\xda|\xdb\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x14F\xb7T\xc2N;\x16B\xd9\xe5\x17e\xb4\xd3\xe4k4\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x18R\x13!\xab\xaf[&Q:J\x95(\bo\"\n\xdco\x89\x01v\xb3D\xf2\xa7\x8c\x00\x00\u07d4\xc6#FW\xa8\a8A&\xf8\x96\x8c\xa1p\x8b\xb0{\xaaI<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6%\xf8\u024d'\xa0\x9a\x1b\u02bdQ(\xb1\u00a9HV\xaf0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc65^\xc4v\x8cp\xa4\x9a\xf6\x95\x13\u0343\xa5\xbc\xa7\xe3\xb9\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc6:\xc4\x17\x99.\x9f\x9b`8n\xd9S\xe6\xd7\xdf\xf2\xb0\x90\xe8\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xc6<\u05c8!\x18\xb8\xa9\x1e\aML\x8fK\xa9\x18Q0;\x9a\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xc6R\x87\x1d\x19$\"\u01bc#_\xa0c\xb4J~\x1dC\u3149\bg\x0e\x9e\xc6Y\x8c\x00\x00\xe0\x94\xc6gD\x1e\u007f)y\x9a\xbaadQ\xd5;?H\x9f\x9e\x0fH\x8a\x02\xf2\x9a\xceh\xad\u0740\x00\x00\u07d4\xc6j\xe4\xce\xe8\u007f\xb352\x19\xf7\u007f\x1dd\x86\u0140(\x032\x89\x01\x9a\x16\xb0o\xf8\xcb\x00\x00\u07d4\xc6t\xf2\x8c\x8a\xfd\a?\x8by\x96\x91\xb2\xf0XM\xf9B\xe8D\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0197\xb7\x04w\u02b4.+\x8b&f\x81\xf4\xaesu\xbb%A\x8a\x01.W2\xba\xba\\\x98\x00\x00\u07d4\u019b\x85U9\xce\x1b\x04qG(\xee\xc2Z7\xf3g\x95\x1d\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u019b\xe4@\x13Mb\x80\x98\x01D\xa9\xf6M\x84t\x8a7\xf3I\x89&\u009eG\u0104L\x00\x00\u07d4\u019df<\x8d`\x90\x83\x91\xc8\xd26\x19\x153\xfd\xf7wV\x13\x89\x1aJ\xba\"\\ t\x00\x00\u0794\u01a2\x86\xe0e\xc8_:\xf7H\x12\xed\x8b\u04e8\xce]%\xe2\x1d\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\u01a3\x0e\xf5\xbb3 \xf4\r\xc5\xe9\x81#\rR\xae:\xc1\x93\"\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\u01ae(}\xdb\xe1\x14\x9b\xa1m\xdc\xcaO\xe0j\xa2\uaa48\xa9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xc7\xc1\x917\x98\x97\u075c\x9d\x9a3\x83\x9cJ_b\xc0\x89\r\x89\xd8\xd8T\xb2$0h\x80\x00\xe0\x94\xc6\xcdh\xec56,Z\xd8L\x82\xadN\xdc#!%\x91-\x99\x8a\x05\xe0T\x9c\x962\xe1\xd8\x00\x00\u07d4\xc6\u0615N\x8f?\xc53\xd2\xd20\xff\x02\\\xb4\xdc\xe1O4&\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xdb\u06de\xfd^\xc1\xb3xn\x06q\xeb\"y\xb2S\xf2\x15\xed\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc6\xdf u\xeb\xd2@\xd4Hi\u00bek\u07c2\xe6=N\xf1\xf5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6\xe2\xf5\xaf\x97\x9a\x03\xfdr:\x1bn\xfar\x83\x18\u03dc\x18\x00\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xc6\xe3$\xbe\xeb[6v^\xcdFB`\xf7\xf2`\x06\xc5\xc6.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\xe4\xcc\fr\x83\xfc\x1c\x85\xbcH\x13\xef\xfa\xafr\xb4\x98#\xc0\x89\x0f\x03\x1e\xc9\xc8}\xd3\x00\x00\xe0\x94\xc6\xee5\x93B)i5)\xdcA\u067bq\xa2IfX\xb8\x8e\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xc6\xfb\x1e\xe3t\x17\u0400\xa0\xd0H\x92;\u06ba\xb0\x95\xd0w\u0189\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc7\x05'\xd4D\u0110\xe9\xfc?\\\xc4Nf\xebO0k8\x0f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\r\x85mb\x1e\xc1E0<\nd\x00\xcd\x17\xbb\xd6\xf5\xea\xf7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc7\x0f\xa4Uv\xbf\x9c\x86_\x988\x93\x00,AI&\xf6\x10)\x89\x15\xb4\xaa\x8e\x97\x02h\x00\x00\u07d4\xc7\x11E\xe5)\u01e7\x14\xe6y\x03\xeeb\x06\xe4\xc3\x04+g'\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xc7\x1b*=q5\u04a8_\xb5\xa5q\u073ei^\x13\xfcC\u034965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\x1f\x1du\x87?3\u0732\xddK9\x87\xa1-\a\x91\xa5\xce'\x897\b\xba\xed=h\x90\x00\x00\u07d4\xc7\x1f\x92\xa3\xa5J{\x8c/^\xa4C\x05\xfc\u02c4\xee\xe21H\x89\x02\xb5\x9c\xa11\xd2\x06\x00\x00\u07d4\xc7!\xb2\xa7\xaaD\xc2\x12\x98\xe8P9\xd0\x0e.F\x0eg\v\x9c\x89\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xc7,\xb3\x01%\x8e\x91\xbc\b\x99\x8a\x80]\u0452\xf2\\/\x9a5\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc76\x8b\x97\t\xa5\xc1\xb5\x1c\n\xdf\x18ze\xdf\x14\xe1+}\xba\x8a\x02\x02o\xc7\u007f\x03\u5b80\x00\u07d4\xc79%\x9e\u007f\x85\xf2e\x9b\xef_`\x9e\xd8k=Yl \x1e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc7>!\x12(\"\x15\xdc\ab\xf3+~\x80}\xcd\x1az\xae>\x8a\x01v\f\xbcb;\xb3P\x00\x00\xe0\x94\xc7If\x80B\xe7\x11#\xa6H\x97^\b\xedc\x82\xf8>\x05\xe2\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xc7J9\x95\xf8\a\xde\x1d\xb0\x1a.\xb9\xc6.\x97\xd0T\x8fio\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7Pl\x10\x19\x12\x1f\xf0\x8a,\x8c\x15\x91\xa6^\xb4\xbd\xfbJ?\x89 \x86\xac5\x10R`\x00\x00\u07d4\xc7\\7\xce-\xa0k\xbc@\b\x11Y\u01ba\x0f\x97n9\x93\xb1\x89:y#\x15\x1e\xcfX\x00\x00\u07d4\xc7]\"Y0j\xec}\xf0\"v\x8ci\x89\x9ae!\x85\xdb\u0109\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7`\x97\x1b\xbc\x18\x1cj|\xf7tA\xf2BG\u045c\xe9\xb4\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc7a0\xc7<\xb9!\x028\x02\\\x9d\xf9]\v\xe5J\xc6\u007f\xbe\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xc7e\xe0\x04v\x81\tG\x81j\xf1B\xd4m.\u7f28\xccO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc7g^VG\xb9\xd8\xda\xf4\xd3\xdf\xf1\xe5R\xf6\xb0qT\xac8\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xc7{\x01\xa6\xe9\x11\xfa\x98\x8d\x01\xa3\xab3dk\xee\xf9\xc18\xf3\x89'\x1bo\xa5\xdb\xe6\xcc\x00\x00\u07d4\u01c3z\u0420\xbf\x14\x18i7\xac\xe0lUF\xa3j\xa5OF\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01d8\x06\x03+\xc7\xd8(\xf1\x9a\u01a6@\u018e=\x82\x0f\xa4B\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u01d9\xe3N\x88\xff\x88\xbe}\xe2\x8e\x15\xe4\xf2\xa6=\v3\xc4\u02c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\u01ddPb\u01d6\xddwa\xf1\xf1>U\x8ds\xa5\x9f\x82\xf3\x8b\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\u01e0\x18\xf0\x96\x8aQ\xd1\xf6`<\\I\xdcT[\xcb\x0f\xf2\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01ef\xf9\x19)yt\x89UZ/\xf1\xd1M\\iZ\x10\x83U\x8965\u026d\xc5\u07a0\x00\x00\u0794\u01f1\xc8>c ?\x95G&>\xf6(.}\xa3;n\xd6Y\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\u01f3\x9b\x06\x04Q\x00\f\xa1\x04\x9b\xa1T\xbc\xfa\x00\xff\x8a\xf2b\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\u01ff\x17\xc4\xc1\x1f\x98\x94\x1fP~w\bO\xff\xbd-\xbd=\xb5\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u01ff.\xd1\xed1)@\xeej\xde\xd1Qn&\x8eJ`HV\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc7\xd4O\xe3,\u007f\x8c\xd5\xf1\xa9t'\xb6\xcd:\xfc\x9eE\x02>\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xc7\xd5\xc7\x05@\x81\xe9\x18\xech{Z\xb3n\x97=\x18\x13)5\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xc7\xde^\x8e\xaf\xb5\xf6+\x1a\n\xf2\x19\\\xf7\x93\u01c9L\x92h\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\xe30\xcd\f\x89\n\u025f\xe7q\xfc\xc7\xe7\xb0\t\xb7A=\x8a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\xea\xc3\x1a\xbc\xe6\xd5\xf1\u07a4\"\x02\xb6\xa6t\x15=\xb4z)\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc7\xecb\xb8\x04\xb1\xf6\x9b\x1e0p\xb5\xd3b\xc6/\xb3\t\xb0p\x8a\x02\xc4k\xf5A`f\x11\x00\x00\u07d4\xc7\xf7+\xb7X\x01k7G\x14\u0509\x9b\xce\"\xb4\xae\xc7\n1\x89:&\xc9G\x8f^-\x00\x00\u0794\xc8\v6\u047e\xaf\xba_\xccdM`\xacnF\xed)'\xe7\u0708\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xc8\x11\xc2\xe9\xaa\x1a\xc3F.\xba^\x88\xfc\xb5\x12\x0e\x9fn,\xa2\x89K\xe6\u0607\xbd\x87n\x00\x00\u07d4\xc8\x17\xdf\x1b\x91\xfa\xf3\x0f\xe3%\x15qr|\x97\x11\xb4]\x8f\x06\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xc8\x1f\xb7\xd2\x0f\u0480\x01\x92\xf0\xaa\xc1\x98\xd6\u05a3}?\xcb}\x89\x0e\x11I3\x1c-\xde\x00\x00\u07d4\xc8 \xc7\x11\xf0w\x05'8\a\xaa\xaam\xe4M\x0eKH\xbe.\x89\bg\x0e\x9e\xc6Y\x8c\x00\x00\u07d4\xc8#\x1b\xa5\xa4\x11\xa1>\"+)\xbf\xc1\b?v1X\xf2&\x8967\tlK\xcci\x00\x00\u07d4\xc86\xe2Jo\xcf)\x94;6\b\xe6b)\n!_e)\xea\x89\x0f\xd4Pd\xea\xee\x10\x00\x00\xe0\x94\xc8;\xa6\u0755I\xbe\x1d2\x87\xa5\xa6T\xd1\x06\xc3Lk]\xa2\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc8>\x9djX%;\uefb7\x93\xe6\xf2\x8b\x05JXI\x1bt\x89\x0fF\u00b6\xf5\xa9\x14\x00\x00\u07d4\xc8A\x88O\xa4x_\xb7s\xb2\x8e\x97\x15\xfa\xe9\x9aQ40]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8M\x9b\xea\n{\x9f\x14\x02 \xfd\x8b\x90\x97\u03ff\xd5\xed\xf5d\x89\x06\xab\x9e\u0091\xad}\x80\x00\u07d4\xc8RB\x8d+Xd\x97\xac\xd3\fV\xaa\x13\xfbU\x82\xf8D\x02\x893B\xd6\r\xff\x19`\x00\x00\u07d4\xc8S![\x9b\x9f-,\xd0t\x1eX^\x98{_\xb8\f!.\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc8S%\uaca5\x9b>\xd8c\xc8j_)\x06\xa0B)\xff\xa9\x89\x19=\u007f}%=\xe0\x00\x00\u07d4\xc8^\xf2}\x82\x04\x03\x80_\xc9\xed%\x9f\xffd\xac\xb8\xd64j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8akN\xc0\x91(\xcd\xff9\xd6\u4e6c\x86\xee\xc4q\xd5\xf2\x89\x01\r:\xa56\xe2\x94\x00\x00\xe0\x94\xc8a\x90\x90K\x8d\a\x9e\xc0\x10\xe4b\xcb\xff\xc9\b4\xff\xaa\\\x8a\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4\xc8q\r~\x8bZ;\u059aB\xfe\x0f\xa8\xb8|5\u007f\xdd\xcd\u0209\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc8sR\u06e5\x82\xee f\xb9\xc0\x02\xa9b\xe0\x03\x13Ox\xb1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xc8|w\xe3\xc2J\xde\xcd\xcd\x108\xa3\x8bV\xe1\x8d\xea\u04f7\x02\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xc8}:\xe3\u0607\x04\u066b\x00\t\xdc\xc1\xa0\x06q1\xf8\xba<\x89j\xc5\xc6-\x94\x86\a\x00\x00\xe0\x94\u0201N4R>8\xe1\xf9'\xa7\xdc\xe8FjDz\t6\x03\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0202U\xed\xdc\xf5!\xc6\xf8\x1d\x97\xf5\xa4!\x81\xc9\a=N\xf1\x89\x0f\u00d0D\xd0\n*\x80\x00\u07d4\u0205\xa1\x8a\xab\xf4T\x1b{{~\xcd0\xf6\xfa\u619d\x95i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u020c\xa1\xe6\xe5\xf4\xd5X\xd17\x80\xf4\x88\xf1\rJ\xd3\x13\r4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u020e\xecT\xd3\x05\xc9(\xcc(H\xc2\xfe\xe251\xac\xb9mI\x89lj\u04c2\xd4\xfba\x00\x00\xe0\x94\u021c\xf5\x04\xb9\xf3\xf85\x18\x1f\xd8BO\\\xcb\xc8\xe1\xbd\xdf}\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0222\xc4\xe5\x9e\x1c\u007f\xc5H\x05X\x048\xae\xd3\xe4J\xfd\xf0\x0e\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\u022aI\u301f\b\x99\xf2\x8a\xb5~gCp\x9dXA\x903\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\u022b\x1a<\xf4l\xb8\xb0d\xdf.\"-9`s\x94 2w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0231\x85\x05%\xd9F\xf2\xae\x84\xf3\x17\xb1Q\x88\xc56\xa5\u0706\x89\x91\x8d\xdc:B\xa3\xd4\x00\x00\u07d4\xc8\xd4\xe1Y\x9d\x03\xb7\x98\t\xe0\x13\n\x8d\u00c4\b\xf0^\x8c\u04c9\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xc8\xdd'\xf1k\xf2$P\xf5w\x1b\x9f\xe4\xedO\xfc\xb3\t6\xf4\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xc8\xdezVL\u007f@\x12\xa6\xf6\xd1\x0f\u040fG\x89\x0f\xbf\a\u0509\x10CV\x1a\x88)0\x00\x00\u07d4\xc8\xe2\xad\xebT^I\x9d\x98,\f\x11sc\u03b4\x89\u0171\x1f\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xc8\xe5X\xa3\xc5i~o\xb2:%\x94\u0200\xb7\xa1\xb6\x8f\x98`\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc8\xf2\xb3 \xe6\xdf\xd7\t\x06\u0157\xba\xd2\xf9P\x13\x12\u01c2Y\x89Q\x93K\x8b:W\xd0\x00\x00\u07d4\xc9\x03\x00\xcb\x1d@w\xe6\xa6\xd7\xe1i\xa4`F\x8c\xf4\xa4\x92\u05c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\f7e\x15k\u028eH\x97\xab\x80$\x19\x15<\xbeR%\xa9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc9\x10\xa9pUl\x97\x16\xeaS\xaff\xdd\xef\x93\x141$\x91=\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\xe0\x94\xc9\x12{\u007ff)\xee\x13\xfc?`\xbc/Dg\xa2\aE\xa7b\x8a\x03|\x9a\xa4\xe7\xceB\x1d\x80\x00\u07d4\xc9\x1b\xb5b\xe4+\xd4a0\xe2\u04eeFR\xb6\xa4\ub1bc\x0f\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\xe0\x94\xc90\x88y\x05m\xfe\x13\x8e\xf8 \x8fy\xa9\x15\u01bc~p\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xc94\xbe\xca\xf7\x1f\"_\x8bJK\xf7\xb1\x97\xf4\xac\x9604\\\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9?\xbd\xe8\xd4m+\xcc\x0f\xa9\xb3;\u063a\u007f\x80B\x12Ue\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xc9@\x89U:\xe4\xc2,\xa0\x9f\xbc\x98\xf5pu\xcf.\u0155\x04\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc9A\x10\xe7\x1a\xfeW\x8a\xa2\x18\xe4\xfc(d\x03\xb03\n\u038d\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc9F\u056c\xc14n\xba\nry\xa0\xac\x1dF\\\x99m\x82~\x8a\x03x=T_\xdf\n\xa4\x00\x00\u07d4\xc9J(\xfb20\xa9\xdd\xfa\x96Nw\x0f,\xe3\xc2S\xa7\xbeO\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc9JXR\x03\xda{\xba\xfd\x93\xe1X\x84\xe6`\u0531\xea\xd8T\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc9O|5\xc0'\xd4}\xf8\xefO\x9d\xf8Z\x92H\xa1}\xd2;\x89\x01\x9f\x8euY\x92L\x00\x00\u07d4\xc9Q\x90\f4\x1a\xbb\xb3\xba\xfb\xf7\xee )7pq\xdb\xc3j\x89\x11\xc2]\x00M\x01\xf8\x00\x00\u07d4\xc9S\xf94\xc0\xeb-\x0f\x14K\u06b0\x04\x83\xfd\x81\x94\x86\\\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9f&r\x8a\xaaLO\xb3\xd3\x1c&\xdf:\xf3\x10\b\x17\x10\u0449\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\xc9gQel\n\x8e\xf45{sD2!4\xb9\x83PJ\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\u0240Hh\u007f+\xfc\u027d\x90\xed\x18slW\xed\xd3R\xb6]\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0241\xd3\x12\u0487\xd5X\x87\x1e\u0757:\xbbv\xb9y\xe5\xc3^\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0242Xmc\xb0\xd7L \x1b\x1a\xf8A\x83r\xe3\fv\x16\xbe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u0249CO\x82Z\xaf\x9cU/h^\xba|\x11\xdbJ_\xc7:\x89\x1b(\u014d\x96\x96\xb4\x00\x00\u07d4\u0249\xee\xc3\a\u80db\x9dr7\xcf\xda\b\x82)b\xab\u41c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u0252\xbeY\xc6r\x1c\xafN\x02\x8f\x9e\x8f\x05\xc2\\UQ[\u0509\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0255{\xa9L\x1b)\xe5'~\xc3f\"pI\x04\xc6=\xc0#\x89h>\xfcg\x82d,\x00\x00\xe0\x94\u025a\x9c\xd6\xc9\xc1\xbe54\xee\u0352\xec\xc2/\\8\xe9Q[\x8a\x01\x05Y;:\x16\x9dw\x00\x00\xe0\x94\u026c\x01\xc3\xfb\t)\x03?\f\xcc~\x1a\xcf\uaae7\x94]G\x8a\x02\xa3j\x9e\x9c\xa4\xd2\x03\x80\x00\u07d4\u0276\x98\xe8\x98\xd2\rMO@\x8eNM\x06\x19\"\xaa\x85c\a\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u0276\xb6\x86\x11\x16\x91\xeej\xa1\x97\xc7#\x1a\x88\xdc`\xbd)]\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\u01ec\v\u0753B\xb5\xea\xd46\t#\xf6\x8cr\xa6\xbac:\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\xc8\r\xc1.{\xab\x86\xe9I\xd0\x1eL>\xd3_+\x9b\xba_\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\xd7dF\u056a\xdf\xf8\vh\xb9\x1b\b\u035b\xc8\xf5U\x1a\xc1\x89&\xb4\xbd\x91\x10\xdc\xe8\x00\x00\xe0\x94\xc9\u073b\x05oM\xb7\xd9\xda9\x93b\x02\u017d\x820\xb3\xb4w\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9\xe0&\b\x06h(\x84\x8a\xeb(\xc76r\xa1)%\x18\x1fM\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xca\x042\xcb\x15{Qy\xf0.\xbb\xa5\xc9\u0475O\xecM\x88\u028965\u026d\xc5\u07a0\x00\x00\u07d4\xca\x12,\xf0\U00094216\xb7HC\xf4\x9a\xfe\u043a\x16\x18\xee\u05c9\x1e[\x8f\xa8\xfe*\xc0\x00\x00\xe0\x94\xca\"\u0363`m\xa5\xca\xd0\x13\xb8\aG\x06\xd7\xe9\xe7!\xa5\f\x8a\x01q\x81\xc6\xfa9\x81\x94\x00\x00\u07d4\xca#\xf6-\xff\rd`\x03lb\xe8@\xae\xc5W~\v\xef\u0489\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xca%\xff4\x93L\x19B\xe2*N{\xd5o\x14\x02\x1a\x1a\xf0\x88\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xca7?\xe3\xc9\x06\xb8\xc6U\x9e\xe4\x9c\xcd\a\xf3|\xd4\xfbRf\x89a\t=|,m8\x00\x00\u07d4\xcaA\u032c0\x17 R\xd5\"\xcd//\x95}$\x81S@\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xcaB\x88\x01N\xdd\xc5c/_\xac\xb5\xe3\x85\x17\xa8\xf8\xbc]\x98\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xcaB\x88c\xa5\xca06\x98\x92\xd6\x12\x18>\xf9\xfb\x1a\x04\xbc\xea\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\xcaI\xa5\xf5\x8a\xdb\xef\xae#\xeeY\xee\xa2A\xcf\x04\x82b.\xaa\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcaL\xa9\xe4w\x9dS\x0e\u02ec\xd4~j\x80X\xcf\xdee\u064f\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xcae~\xc0o\xe5\xbc\t\xcf#\xe5*\xf7\xf8\f\xc3h\x9en\u07890\xca\x02O\x98{\x90\x00\x00\u07d4\xcaf\xb2(\x0f\xa2\x82\u0176v1\xceU+b\xeeU\xad\x84t\x89j\xc4\"\xf54\x92\x88\x00\x00\xe0\x94\xcal\x81\x8b\xef\xd2Q6\x1e\x02t@h\xbe\x99\u062a`\xb8J\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcap\xf4\u077f\x06\x9d!C\xbdk\xbc\u007fikRx\x9b2\u7262\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xcatuvDjL\x8f0\xb0\x83@\xfe\xe1\x98\xdec\xec\x92\u03ca\x01|\x8e\x12\x06r*0\x00\x00\u07d4\xca{\xa3\xffSl~_\x0e\x158\x00\xbd8=\xb81)\x98\xe0\x89\t1\xac=k\xb2@\x00\x00\xe0\x94\u0282v\xc4w\xb4\xa0{\x80\x10{\x845\x94\x18\x96\a\xb5;\xec\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u0284\t\b>\x01\xb3\x97\xcf\x12\x92\x8a\x05\xb6\x84U\xceb\x01\u07c9V\xbcu\xe2\xd61\x00\x00\x00\u07d4\u0298\u01d8\x8e\xfa\b\xe9%\uf719ER\x03&\xe9\xf4;\x99\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u029a\x04*j\x80o\xfc\x92\x17\x95\x00\xd2D)\xe8\xabR\x81\x17\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\u029d\xec\x02\x84\x1a\xdf\\\xc9 WjQ\x87\xed\u04bdCJ\x18\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u029f\xaa\x17T/\xaf\xbb8\x8e\xab!\xbcL\x94\u89f3G\x88\x89lk\x8f\xce\r\x18y\x80\x00\xe0\x94\u02aah\xeel\xdf\r4EJv\x9b\r\xa1H\xa1\xfa\xaa\x18e\x8a\x01\x87.\x1d\xe7\xfeR\xc0\x00\x00\u07d4\u02ad\x9d\xc2\rX\x9c\xe4(\xd8\xfd\xa3\xa9\xd5:`{y\x88\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u02b0\xd3,\xf3v\u007f\xa6\xb3S|\x842\x8b\xaa\x9fPE\x816\x8a\x01\xe5\xb8\xfa\x8f\xe2\xac\x00\x00\x00\u07d4\u02b9\xa3\x01\xe6\xbdF\xe9@5P(\xec\xcd@\xceMZ\x1a\u00c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u02b9\xa9z\xda\x06\\\x87\x81nh`\xa8\xf1Bo\xe6\xb3\xd7u\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u02ba\xb6'N\xd1P\x89s~({\xe8x\xb7W\x93Hd\xe2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\u02bd\xaf5OG \xa4f\xa7d\xa5(\xd6\x0e:H*9<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xca\xcbg^\t\x96#T\x04\ufbfb.\u02c1R'\x1bU\xe0\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xca\xd1O\x9e\xbb\xa7f\x80\xeb\x83k\a\x9c\u007f{\xaa\xf4\x81\xedm\x89\f\xef={\xd7\xd04\x00\x00\xe0\x94\xca\xe3\xa2S\xbc\xb2\xcfN\x13\xba\x80\u0098\xab\x04\x02\xda|*\xa0\x8a\x01$\xbc\r\u0752\xe5`\x00\x00\u07d4\xca\xef\x02{\x1a\xb5\x04\xc7?A\xf2\xa1\ty\xb4t\xf9~0\x9f\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xca\xf4H\x1d\x9d\xb7\x8d\xc4\xf2_{J\u023d;\x1c\xa0\x10k1\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xca\xfd\xe8U\x86L%\x98\xda<\xaf\xc0Z\u064d\U00089380H\x8a\x03\x00\xa8\xed\x96\xffJ\x94\x00\x00\xe0\x94\xcb\r\xd7\xcfN]\x86a\xf6\x02\x89C\xa4\xb9\xb7\\\x91D6\xa7\x8a\x19i6\x89t\xc0[\x00\x00\x00\u07d4\xcb\x1b\xb6\xf1\xda^\xb1\rH\x99\xf7\xe6\x1d\x06\xc1\xb0\x0f\u07f5-\x898E$\xccp\xb7x\x00\x00\u07d4\xcb=vl\x98?\x19+\xce\xca\xc7\x0fN\xe0=\xd9\xffqMQ\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcbB\xb4N\xb5\xfd`\xb5\x83~O\x9e\xb4rgR=\x1a\"\x9c\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xcbG\xbd0\u03e8\xecTh\xaa\xa6\xa9FB\xce\xd9\xc8\x19\xc8\u0509\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcbH\xfe\x82e\u066fU\xebp\x06\xbc3VE\xb0\xa3\xa1\x83\xbe\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xcbJ\x91M+\xb0)\xf3._\xef\\#LO\xec--\xd5w\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcbJ\xbf\u0082\xae\xd7n]W\xaf\xfd\xa5B\xc1\xf3\x82\xfc\xac\xf4\x8a\x01\xb9\x0f\x11\xc3\x18?\xaa\x00\x00\u07d4\xcbJ\xd0\xc7#\xdaF\xabV\xd5&\xda\f\x1d%\xc7=\xaf\xf1\n\x89\x1b\xa5\xab\xf9\xe7y8\x00\x00\u07d4\xcbK\xb1\xc6#\xba(\xdcB\xbd\xaa\xa6\xe7N\x1d*\xa1%l*\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xcbPXt\x12\x82#\x04\xeb\u02e0}\xab:\x0f\t\xff\xfe\u4189JD\x91\xbdm\xcd(\x00\x00\u07d4\xcbX\x99\v\u0350\u03ffm\x8f\t\x86\xf6\xfa`\x02v\xb9N-\x8964\xbf9\xab\x98x\x80\x00\u07d4\xcbh\xaeZ\xbe\x02\xdc\xf8\xcb\u016aq\x9c%\x81FQ\xaf\x8b\x85\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xcbty\x10\x9bC\xb2fW\xf4F_M\x18\xc6\xf9t\xbe_B\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xcb}+\x80\x89\xe91,\u026e\xaa's\xf3S\b\xecl*{\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u02c6\xed\xbc\x8b\xbb\x1f\x911\x02+\xe6IV^\xbd\xb0\x9e2\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u02d3\x19\x9b\x9c\x90\xbcI\x15\xbd\x85\x9e=B\x86m\xc8\xc1\x87I\x89\f\x90\xdf\a\xde\xf7\x8c\x00\x00\u07d4\u02d4\xe7o\xeb\xe2\b\x11g3\xe7n\x80]H\xd1\x12\xec\x9f\u028965\u026d\xc5\u07a0\x00\x00\u07d4\u02dbQ\x03\xe4\u0389\xafOd\x91aP\xbf\xf9\xee\u02df\xaa\\\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\\zP<\xc8\xe0\xd0Iq\xca\x05\xc7b\xf9\xb7b\xb4\x8b\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\x88\xcd<\x1e\xb4\u055d\xdb\x06\xa6B\x1c\x14\xc3E\xa4{$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u02f3\x18\x9eK\xd7\xf4_\x17\x8b\x1c0\xc7n&1MJK\n\x89\x0f\xfe\vg|e\xa9\x80\x00\xe0\x94\u02f7\xbe\x17\x95?,\u0313\u1f19\x80[\xf4U\x11CNL\x8a\n\xae[\x9d\xf5m/ \x00\x00\xe0\x94\xcb\xc0KM\x8b\x82\xca\xf6p\x99o\x16\f6)@\xd6o\xcf\x1a\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcb\u07974\xb8\xe6\xaaS\x8c)\x1dm\u007f\xac\xed\xb0\xf38\xf8W\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcb\xe1\xb9H\x86M\x84t\xe7e\x14XX\xfc\xa4U\x0fxK\x92\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xe5/\xc53\xd7\xdd`\x8c\x92\xa2`\xb3|?E\u07b4\xeb3\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcb\xe8\x10\xfe\x0f\xec\xc9dGJ\x1d\xb9w(\xbc\x87\xe9s\xfc\xbd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xf1j\x0f\xe2tRX\xcdR\xdb+\xf2\x19T\xc9u\xfcj\x15\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\xcb\xf3\u007f\xf8T\xa2\xf1\xceS\x93D\x94wx\x92\xd3\xeceW\x82\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xfaj\xf6\u0083\xb0F\xe2w,`c\xb0\xb2\x15S\xc4\x01\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcb\xfav\xdb\x04\xce8\xfb ]7\xb8\xd3w\xcf\x13\x80\xda\x03\x17\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcc\x03I\x85\xd3\xf2\x8c-9\xb1\xa3K\xce\xd4\u04f2\xb6\xca#N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xcc\x04\x8d\u01f9]\xca%\xdf&\xee\xfac\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc+_D\x8f5(\xd3\xfeA\xcc}\x1f\xa9\xc0\xdcv\xf1\xb7v\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc-\x04\xf0\xa4\x01q\x89\xb3@\xcaw\x19\x86A\xdc\xf6Ek\x91\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xccA\x9f\u0651+\x85\x13VY\xe7z\x93\xbc=\xf1\x82\xd4Q\x15\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccE\xfb:U[\xad\x80{8\x8a\x03W\xc8U _|u\xe8\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xccHAM*\xc4\xd4*Yb\xf2\x9e\xeeD\x97\t/C\x13R\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\xccJ/,\xf8l\xf3\xe43u\xf3`\xa4sF\x91\x19_\x14\x90\x89I\x15\x05;\xd1)\t\x80\x00\u07d4\xccO\x0f\xf2\xae\xb6}T\xce;\xc8\xc6Q\v\x9a\xe8>\x9d2\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xccO\xaa\xc0\v\xe6b\x8f\x92\xefk\x8c\xb1\xb1\xe7j\xac\x81\xfa\x18\x89\v\"\xa2\xea\xb0\xf0\xfd\x00\x00\xe0\x94\xccO\xebr\u07d8\xff5\xa18\xe0\x17a\xd1 ?\x9b~\xdf\n\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xcc`oQ\x13\x97\xa3\x8f\u01c7+\u04f0\xbd\x03\xc7\x1b\xbdv\x8b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcc`\xf86\xac\xde\xf3T\x8a\x1f\xef\u0321>\u01a97\xdbD\xa0\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4\xccl\x03\xbd`>\t\xdeT\xe9\xc4\u056cmA\xcb\xceqW$\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xccl-\xf0\x0e\x86\xec\xa4\x0f!\xff\xda\x1ag\xa1i\x0fG|e\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\xccm{\x12\x06\x1b\xc9m\x10M`me\xff\xa3+\x006\xeb\a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccs\xdd5kIy\xb5y\xb4\x01\xd4\xccz1\xa2h\xdd\xceZ\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xccu\x8d\a\x1d%\xa62\n\xf6\x8c]\xc9\xc4\xf6\x95[\xa9E \x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcc{\x04\x81\xcc2\xe6\xfa\xef#\x86\xa0p\"\xbc\xb6\xd2\u00f4\xfc\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\u0314;\xe1\",\xd1@\n#\x99\xdd\x1bE\x94E\xcfmT\xa9\x8a\x02\xa7@\xaee6\xfc\x88\x00\x00\u07d4\u0315\x19\xd1\xf3\x98_k%^\xad\xed\x12\xd5bJ\x97'!\xe1\x8965\u026d\xc5\u07a0\x00\x00\u0794\u031a\xc7\x15\xcdo&\x10\xc5+XgdV\x88B\x97\x01\x8b)\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\u0320{\xb7\x94W\x1dJ\xcf\x04\x1d\xad\x87\xf0\xd1\xef1\x85\xb3\x19\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u032b\xc6\x04\x8aSFD$\xfc\xf7n\xeb\x9en\x18\x01\xfa#\u0509\x02\xab{&\x0f\xf3\xfd\x00\x00\u07d4\u032e\r=\x85*}\xa3\x86\x0f\x066\x15L\nl\xa3\x16(\u0509\x05\xc6\xd1+k\xc1\xa0\x00\x00\u07d4\xcc\xca$\xd8\xc5mn,\a\xdb\bn\xc0~X[\xe2g\xac\x8d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcc\xd5!\x13-\x98l\xb9hi\x84&\"\xa7\u0762l>\xd0W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc\xf49u\xb7k\xfes_\xec<\xb7\xd4\xdd$\xf8\x05\xba\tb\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc\xf6*f?\x13S\xba.\xf8\xe6R\x1d\xc1\xec\xb6s\xec\x8e\xf7\x89\b=lz\xabc`\x00\x00\u07d4\xcc\xf7\x11\r\x1b\u0667K\xfd\x1d}}-\x9dU`~{\x83}\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xcc\xfdrW`\xa6\x88#\xff\x1e\x06/L\xc9~\x13`\xe8\u0657\x89\x15\xacV\xed\xc4\xd1,\x00\x00\u07d4\xcd\x02\x0f\x8e\xdf\xcfRG\x98\xa9\xb7:d\x034\xbb\xf7/\x80\xa5\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xcd\x06\xf8\xc1\xb5\u037d(\xe2\xd9kcF\xc3\xe8Z\x04\x83\xba$\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcd\a.n\x183\x13y\x95\x19m{\xb1r_\xef\x87a\xf6U\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcd\n\x16\x1b\xc3g\xae\t'\xa9*\xac\x9c\xf6\xe5\bg\x14\xef\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\n\xf3GN\"\xf0i\xec4\a\x87\r\xd7pD=[\x12\xb0\x89\x8e^\xb4\xeew\xb2\xef\x00\x00\u07d4\xcd\v\x02W\u70e3\xd2\xc2\u3e9dny\xb7^\xf9\x80$\u0509\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xcd\x10,\xd6\xdb=\xf1J\u05af\x0f\x87\xc7$y\x86\x1b\xfc=$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\x1ef\xedS\x9d\xd9/\xc4\v\xba\xa1\xfa\x16\u078c\x02\xc1ME\x89\fw\xe4%hc\xd8\x00\x00\u07d4\xcd\x1e\xd2c\xfb\xf6\xf6\xf7\xb4\x8a\xef\x8fs=2\x9dC\x82\xc7\u01c9\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4\xcd*6\xd7S\xe9\xe0\xed\x01*XMqh\aX{A\xd5j\x89\x0e+\xa7[\v\x1f\x1c\x00\x00\u07d4\xcd2\xa4\xa8\xa2\u007f\x1c\xc69T\xaacOxW\x05s4\u01e3\x89:\xd1fWlr\xd4\x00\x00\u07d4\xcd5\xff\x01\x0e\xc5\x01\xa7!\xa1\xb2\xf0z\x9c\xa5\x87}\xfc\xf9Z\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xcdC\x06\xd7\xf6\x94z\xc1tMN\x13\xb8\xef2\xcbe~\x1c\x00\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4\xcdC%\x8bs\x92\xa90\x83\x9aQ\xb2\xef\x8a\xd24\x12\xf7Z\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcdI\xbf\x18^p\xd0E\a\x99\x9f\x92\xa4\xdeDU1('\u040965\u026d\xc5\u07a0\x00\x00\u07d4\xcdU\x10\xa2B\u07f0\x18=\xe9%\xfb\xa8f\xe3\x12\xfa\xbc\x16W\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xcdVj\u05f8\x83\xf0\x1f\u04d9\x8a\x9aX\xa9\xde\xe4rM\u0725\x89\x030\xae\x185\xbe0\x00\x00\xe0\x94\xcdY\xf3\xdd\xe7~\t\x94\v\xef\xb6\xeeX\x03\x19e\xca\xe7\xa36\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcdr]p\xbe\x97\xe6w\xe3\xc8\xe8\\\v&\xef1\xe9\x95PE\x89Hz\x9a0E9D\x00\x00\xe0\x94\xcd~G\x90\x94d\xd8q\xb9\xa6\xdcv\xa8\xe9\x19]\xb3H^z\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xcd~\xce\bkKa\x9b;6\x93R\xee8\xb7\x1d\xdb\x06C\x9a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcd\u007f\t\xd7\xedf\xd0\u00cb\u016dN2\xb7\xf2\xb0\x8d\xc1\xb3\r\x89>;\xb3M\xa2\xa4p\x00\x00\u07d4\u0355)I+\\)\xe4u\xac\xb9A@+=;\xa5\x06\x86\xb0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0355\xfaB=o\xc1 'J\xac\xde\x19\xf4\xee\xb7f\xf1\x04 \x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u035bL\xefs9\f\x83\xa8\xfdq\u05f5@\xa7\xf9\u03cb\x8c\x92\x89\x04\xe1\x00;(\xd9(\x00\x00\u07d4\u0361t\x11\t\xc0&[?\xb2\xbf\x8d^\xc9\u00b8\xa34kc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0361\xb8\x86\u39d5\u027aw\x91N\n/\xe5go\x0f\\\u03c9\x05\xbf`\xeaB\xc2\x04\x00\x00\u07d4\u0364S\x0fK\x9b\xc5\t\x05\xb7\x9d\x17\u008f\xc4o\x954\x9b\u07c93\x10\xe0I\x11\xf1\xf8\x00\x00\u07d4\u036bF\xa5\x90 \x80do\xbf\x95B\x04 J\xe8\x84\x04\x82+\x89\x1d\x8a\x96\xe5\xc6\x06\xeb\x00\x00\u07d4\u0375\x97)\x900\x18?n-#\x853\xf4d*\xa5\x87T\xb6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xcd\xd5\u0601\xa76,\x90p\a;\u07fcu\xe7$S\xacQ\x0e\x89-\xa5\x18\xea\xe4\x8e\xe8\x00\x00\u07d4\xcd\xd6\rs\xef\xaa\xd8s\u027b\xfb\x17\x8c\xa1\xb7\x10Z\x81\xa6\x81\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xcd\xd9\xef\xacMm`\xbdq\xd9U\x85\xdc\xe5\u0557\x05\xc15d\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcd\xe3m\x81\xd1(\u015d\xa1Ee!\x93\xee\u00bf\xd9e\x86\xef\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcd\xea8o\x9d\x0f\xd8\x04\xd0(\x18\xf27\xb7\xd9\xfavF\xd3^\x89\xa3I\xd3m\x80\xecW\x80\x00\u07d4\xcd\xec\xf5gT3\u0370\xc2\xe5Zh\xdb]\x8b\xbexA\x9d\u0489\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xcd\xfd\x82\x173\x97%\xd7\xeb\xac\x11\xa66U\xf2e\xef\xf1\xcc=\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce\a\x9fQ\x88wt\xd8\x02\x1c\xb3\xb5u\xf5\x8f\x18\xe9\xac\xf9\x84\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xce\x18\x84\u077b\xb8\xe1\x0eM\xbanD\xfe\xee\u00a7\xe5\xf9/\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\x1b\f\xb4j\xae\xcf\u05db\x88\f\xad\x0f-\u068a\x8d\xed\u0431\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xce&\xf9\xa50_\x83\x81\tCT\xdb\xfc\x92fN\x84\xf9\x02\xb5\x89\fz\xaa\xb0Y\x1e\xec\x00\x00\u07d4\xce-\xea\xb5\x1c\n\x9a\xe0\x9c\xd2\x12\xc4\xfaL\xc5+S\xcc\r\xec\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xce.\r\xa8\x93F\x99\xbb\x1aU>U\xa0\xb8\\\x16\x945\xbe\xa3\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce:a\xf0F\x1b\x00\x93^\x85\xfa\x1e\xad\x82\xc4^Zd\u0508\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceK\x06]\xbc\xb20G 2b\xfbH\xc1\x18\x83d\x97tp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceS\xc8\xcd\xd7B\x96\xac\xa9\x87\xb2\xbc\x19\u00b8u\xa4\x87I\u0409\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xce^\x04\xf0\x18Ci\xbc\xfa\x06\xac\xa6o\xfa\x91\xbfY\xfa\x0f\xb9\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xce^\xb6:{\xf4\xfb\xc2\xf6\u4ea0\u018a\xb1\xcbL\xf9\x8f\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xceb\x12Z\xde\xc37\n\xc5!\x10\x95:Nv\v\xe9E\x1e;\x89\b=lz\xabc`\x00\x00\xe0\x94\xceq\bmL`%T\xb8-\xcb\xfc\xe8\x8d cMS\xccM\x8a\t(\x96R\x9b\xad\u0708\x00\x00\u07d4\u038akmP3\xb1I\x8b\x1f\xfe\xb4\x1aAU\x04\x05\xfa\x03\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0397\x86\xd3q/\xa2\x00\xe9\xf6\x857\xee\xaa\x1a\x06\xa6\xf4ZK\x89a\t=|,m8\x00\x00\u07d4\u039d!\u0192\xcd<\x01\xf2\x01\x1fP_\x87\x006\xfa\x8fl\u0489\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u03a2\x89f#\xf4\x91\x02\x87\xa2\xbd\u017e\x83\xae\xa3\xf2\xe6\xde\b\x8a\x01\xfbZ7Q\xe4\x90\xdc\x00\x00\u07d4\u03a3JM\xd9=\u066e\xfd9\x90\x02\xa9}\x99z\x1bK\x89\u0349QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\u03a4?pu\x81k`\xbb\xfc\u62d9:\xf0\x88\x12p\xf6\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\u03a8t3AS<\xb2\xf0\xb9\xc6\xef\xb8\xfd\xa8\rw\x16(%\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u03b0\x89\xec\x8ax3~\x8e\xf8\x8d\xe1\x1bI\xe3\u0751\x0ft\x8f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u03b3=x\xe7Tz\x9d\xa2\xe8}Q\xae\xc5\xf3D\x1c\x87\x92:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u03b3\x898\x1dH\xa8\xaeO\xfcH:\u043b^ L\xfd\xb1\xec\x89('\xe6\xe4\xddb\xba\x80\x00\u07d4\xce\xc6\xfce\x85?\x9c\xce_\x8e\x84Fv6.\x15y\x01_\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xce\xd3\u01fe\x8d\xe7XQ@\x95*\xebP\x1d\xc1\xf8v\ucbf0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\xd8\x1e\xc3S?\xf1\xbf\xeb\xf3\xe3\x84>\xe7@\xad\x11u\x8d>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xce\u0733\xa1\u0584?\xb6\xbe\xf6Ca}\xea\U000cf398\xdd_\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xce\xe6\x99\xc0pzx6%+)/\x04|\xe8\xad(\x9b/U\x89\x11\x9a\x1e!\xaaiV\x00\x00\u07d4\xce\xedG\xca[\x89\x9f\xd1b?!\xe9\xbdM\xb6Z\x10\u5c1d\x89\a8w@L\x1e\xee\x00\x00\u07d4\xce\xf7tQ\u07e2\xc6C\xe0\v\x15mlo\xf8N#s\xebf\x89\n1\x06+\xee\xedp\x00\x00\u07d4\xcf\x11i\x04\x1c\x17E\xe4[\x17$5\xa2\xfc\x99\xb4\x9a\xce+\x00\x89\x01\xbb\x88\xba\xab-|\x00\x00\xe0\x94\xcf\x15v\x12vN\x0f\u0596\xc8\xcb_\xba\x85\xdfL\r\xdc<\xb0\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u0794\xcf\x1b\xdby\x9b.\xa6<\xe14f\x8b\xdc\x19\x8bT\x84\x0f\x18\v\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xcf\"\x88\xefN\xbf\x88\xe8m\xb1=\x8a\x0e\v\xf5*\x05e\x82\u00c9\x89Po\xbf\x97@t\x00\x00\u07d4\xcf&Ni%\x13\t\x06\xc4\xd7\xc1\x85\x91\xaaA\xb2\xa6\u007foX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf&\xb4{\xd04\xbcP\x8elK\xcf\xd6\xc7\xd3\x004\x92Wa\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcf.*\xd65\xe9\x86\x1a\xe9\\\xb9\xba\xfc\xca\x03kR\x81\xf5\u038a\at2!~h6\x00\x00\x00\u07d4\xcf.s@B\xa3U\xd0_\xfb.9\x15\xb1h\x11\xf4Zi^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf4\x8f/\xe4{~A<\az{\xaf:u\xfb\xf8B\x86\x92\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcf?\x91(\xb0r\x03\xa3\xe1\r}WU\xc0\u012b\xc6\xe2\xca\u008a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xcf?\xbf\xa1\xfd2\u05e6\xe0\xe6\xf8\xefN\xabW\xbe4\x02\\L\x899\xa1\xc0\xf7YMH\x00\x00\u07d4\xcfAftn\x1d;\xc1\xf8\xd0qK\x01\xf1~\x8ab\xdf\x14d\x896w\x03n\xdf\n\xf6\x00\x00\u07d4\xcfO\x118\xf1\xbdk\xf5\xb6\u0505\xcc\xe4\xc1\x01\u007f\u02c5\xf0}\x89/\u043cw\xc3+\xff\x00\x00\u07d4\xcfZo\x9d\xf7Uy\xc6D\xf7\x94q\x12\x15\xb3\rw\xa0\xce@\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf^\x0e\xac\u0473\x9d\x06U\xf2\xf7u5\xeff\b\xeb\x95\v\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcfhM\xfb\x83\x04r\x93U\xb5\x83\x15\xe8\x01\x9b\x1a\xa2\xad\x1b\xac\x89\x17r$\xaa\x84Lr\x00\x00\u07d4\xcfi@\x81\xc7m\x18\xc6L\xa7\x13\x82\xbe\\\xd6;<\xb4v\xf8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcfnR\xe6\xb7t\x80\xb1\x86~\xfe\xc6Dm\x9f\xc3\xcc5w\xe8\x89\f\t\x01\xf6\xbd\x98y\x00\x00\u07d4\u03c8: 2\x96g\xea\"j\x1e\x9a\x92*\x12\xf2\x1f\xaa\x03\x81V\x91\x8cO\u02dc\x89\x04E\x91\xd6\u007f\xec\xc8\x00\x00\u07d4\xcf\xf7\xf8\x9aMB\x19\xa3\x82\x95%\x131V\x82\x10\xff\xc1\xc14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xcf\xf8\xd0k\x00\xe3\xf5\f\x19\x10\x99\xadV\xbaj\xe2eq\u0348\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcf\xfcI\xc1x~\ubcb5l\xab\xe9$\x04\xb66\x14}EX\x8a\x013\xe00\x8f@\xa3\u0680\x00\u07d4\xd0\bQ;'`J\x89\xba\x17c\xb6\xf8L\u6233F\x94[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x0f\x06r\x86\xc0\xfb\u0402\xf9\xf4\xa6\x10\x83\xecv\u07b3\xce\xe6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x15\xf6\xfc\xb8M\xf7\xbbA\x0e\x8c\x8f\x04\x89J\x88\x1d\xca\xc27\x898E$\xccp\xb7x\x00\x00\u07d4\xd0\x1a\xf9\x13O\xafRW\x17N\x8by\x18oB\xee5Nd-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0!\b\u04ae<\xab\x10\xcb\xcf\x16W\xaf\">\x02|\x82\x10\xf6\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xd0*\xfe\u03ce.\u00b6*\u022d Aa\xfd\x1f\xaew\x1d\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd01\x919\xfb\xab.\x8e*\xcc\xc1\xd9$\u0531\x1d\xf6ilZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd07\xd2\x15\xd1\x1d\x1d\xf3\xd5O\xbd2\x1c\u0495\xc5F^';\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xd0:-\xa4\x1e\x86\x8e\xd3\xfe\xf5t[\x96\xf5\xec\xa4b\xffo\u0689\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xd0?\xc1eWj\xae\xd5%\xe5P,\x8e\x14\x0f\x8b.\x86\x969\x8a\x01sV\u0633%\x01\xc8\x00\x00\u07d4\xd0C\xa0\x11\xecBp\xee~\u0239hsu\x15\xe5\x03\xf80(\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd0K\x86\x1b=\x9a\xccV:\x90\x16\x89\x94\x1a\xb1\xe1\x86\x11a\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd0ZD|\x91\x1d\xbb'[\xfb.Z7\xe5\xa7\x03\xa5o\x99\x97\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd0_\xfb+t\xf8g O\xe51e;\x02H\xe2\x1c\x13TN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0bX\x81q\u03d9\xbb\xebX\xf1&\xb8p\xf9\xa3r\x8da\xec\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\u07d4\xd0c\x8e\xa5q\x89\xa6\xa6\x99\x02J\u05ccq\xd99\xc1\xc2\xff\x8c\x89\x8e\xaeVg\x10\xfc \x00\x00\xe0\x94\xd0d\x8aX\x1b5\b\xe15\xa2\x93]\x12\xc9epE\xd8q\u028a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xd0q\x19)f\xebi\xc3R\x0f\xca:\xa4\xdd\x04)~\xa0KN\x89\x05\xf6\x8e\x811\xec\xf8\x00\x00\u07d4\xd0q\x85 \xea\xe0\xa4\xd6-p\xde\x1b\xe0\xcaC\x1c^\xea$\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd0w]\xba*\xf4\xc3\n:x6Y9\xcdq\xc2\xf9\u0795\u0489i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd0{\xe0\xf9\t\x97\xca\xf9\x03\u022c\x1dS\xcd\xe9\x04\xfb\x19\aA\x8968\x908\xb6\x99\xb4\x00\x00\u07d4\xd0~Q\x18d\xb1\u03d9i\xe3V\x06\x02\x82\x9e2\xfcNq\xf5\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u0400\x94\x98\xc5H\x04z\x1e**\xa6\xa2\x9c\xd6\x1a\x0e\xe2h\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0402'_tZ,\xac\x02v\xfb\xdb\x02\u0532\xa3\xab\x17\x11\xfe\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\u040f\xc0\x9a\x000\xfd\t(\xcd2\x11\x98X\x01\x82\xa7j\xae\x9f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0413\xe8)\x81\x9f\xd2\xe2[\x978\x00\xbb=XA\xdd\x15-\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0414J\xa1\x85\xa13pa\xae \u071d\xd9l\x83\xb2\xbaF\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u0416V[|t\a\xd0e6X\x03U\xfd\xd6\xd29\x14J\xa1\x89\r\x8drkqw\xa8\x00\x00\u07d4\u041c\xb2\xe6\b-i:\x13\xe8\xd2\xf6\x8d\xd1\u0744a\xf5X@\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0426\xc6\xf9\xe9\u0133\x83\xd7\x16\xb3\x1d\xe7\x8dVAM\xe8\xfa\x91\x89\x10CV\x1a\x88)0\x00\x00\u07d4\u0427 \x9b\x80\xcf`\xdbb\xf5}\n]}R\x1ai`fU\x89\b\xacr0H\x9e\x80\x00\x00\xe0\x94\u0428\xab\xd8\n\x19\x9bT\xb0\x8be\xf0\x1d \x9c'\xfe\xf0\x11[\x8a\x01a\xc6&\xdca\xa2\xef\x80\x00\xe0\x94\u042b\xccp\xc0B\x0e\x0e\x17/\x97\xd4;\x87\xd5\xe8\f3n\xa9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u042es]\x91^\x94hf\xe1\xfe\xa7~^\xa4f\xb5\xca\xdd\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0431\x1do+\u0394^\fjP \u00f5'S\xf8\x03\xf9\u0449\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xd0\xc1\x01\xfd\x1f\x01\xc6?k\x1d\x19\xbc\x92\r\x9f\x93#\x14\xb16\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd0\xc5Z\xbf\x97o\xdc=\xb2\xaf\u9f99\u0519HMWl\x02\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\u0422\xadE\xf5\x9a\x9d\xcc\u0195\xd8_%\xcaF\xed1\xa5\xa3\x89-\x89W}}@ \x00\x00\u07d4\xd0\xd6,G\xea`\xfb\x90\xa3c\x92\t\xbb\xfd\xd4\xd93\x99\x1c\u0189\n\x84Jt$\xd9\xc8\x00\x00\u07d4\xd0\xdbEax o\\D0\xfe\x00Pc\x90<=zI\xa7\x89&I\x1eE\xa7S\xc0\x80\x00\u07d4\xd0\xe1\x94\xf3K\x1d\xb6\t(\x85\t\xcc\xd2\xe7;a1\xa2S\x8b\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xd0\xe3^\x04vF\xe7Y\xf4Qp\x93\xd6@\x86BQ\u007f\bM\x89\u054f\xa4h\x18\xec\u02c0\x00\u07d4\xd0\xeeM\x02\xcf$8,0\x90\xd3\xe9\x95`\xde6xs\\\u07c9\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xd0\xf0OR\x10\x9a\xeb\xec\x9a{\x1e\x932v\x1e\x9f\xe2\xb9{\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd0\xf9Yx\x11\xb0\xb9\x92\xbb}7W\xaa%\xb4\xc2V\x1d2\xe2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\x03\x02\xfa\xa1\x92\x9a2i\x04\xd3v\xbf\v\x8d\xc9:\xd0LL\x89a\t=|,m8\x00\x00\xe0\x94\xd1\x10\r\xd0\x0f\xe2\xdd\xf1\x81c\xad\x96M\vi\xf1\xf2\xe9e\x8a\x8a\x01C\x12\tU\xb2Pk\x00\x00\u07d4\xd1\x16\xf3\xdc\xd5\xdbtK\xd0\b\x88v\x87\xaa\x0e\xc9\xfdr\x92\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\x19A|Fs,\xf3M\x1a\x1a\xfby\xc3\xe7\xe2\u034e\xec\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1-w\xae\x01\xa9-5\x11{\xacpZ\xac\u0642\xd0.t\xc1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd15yK\x14\x9a\x18\xe1G\xd1nb\x1ai1\xf0\xa4\n\x96\x9a\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xd1C%8\xe3[vd\x95j\u4563*\xbd\xf0A\xa7\xa2\x1c\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xd1C\x82g#\x17\x04\xfcr\x80\xd5c\xad\xf4v8D\xa8\a\"\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd1S\x8e\x9a\x87\u5729\xec\x8eX&\xa5\xb7\x93\xf9\x9f\x96\xc4\u00c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd1d\x85\x03\xb1\xcc\u0178\xbe\x03\xfa\x1e\xc4\xf3\xee&~j\xdf{\x8a\x01;\xef\xbfQ\xee\xc0\x90\x00\x00\xe0\x94\xd1h,!Y\x01\x8d\xc3\xd0\u007f\b$\n\x8c`m\xafe\xf8\xe1\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xd1q\xc3\xf2%\x8a\xef5\xe5\x99\xc7\xda\x1a\xa0s\x00#M\xa9\xa6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1w\x8c\x13\xfb\xd9h\xbc\b<\xb7\xd1\x02O\xfe\x1fI\xd0,\xaa\x89\xd9\xec\xb4\xfd \x8eP\x00\x00\u07d4\xd1\u007f\xbe\"\xd9\x04b\xed7(\x06p\xa2\xea\v0\x86\xa0\xd6\u0589\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\u0441\x1cU\x97i\x80\xf0\x83\x90\x1d\x8a\r\xb2i\"-\xfb\\\xfe\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u044e\xb9\xe1\u0485\u06be\x93\xe5\u053a\xe7k\xee\xfeC\xb5!\xe8\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\u0453\xe5\x83\xd6\a\x05c\xe7\xb8b\xb9aJG\u9509\xf3\xe5\x8965f3\xeb\xd8\xea\x00\x00\u07d4\u0457\x8f.4@\u007f\xab\x1d\xc2\x18=\x95\xcf\xdab`\xb3Y\x82\x89*\xb7\xb2`\xff?\xd0\x00\x00\u07d4\u045c\xaf9\xbb7\u007f\xdf,\xf1\x9b\xd4\xfbRY\x1c&1\xa6<\x8965\u026d\xc5\u07a0\x00\x00\u0794\u0463\x96\xdc\u06b2\xc7IA0\xb3\xfd0x 4\r\xfd\x8c\x1f\x88\xf9\"P\xe2\xdf\xd0\x00\x00\xe0\x94\u0467\x1b-\bX\xe82p\b]\x95\xa3\xb1T\x96P\x03^#\x8a\x03'\xbb\t\xd0j\xa8P\x00\x00\u07d4\u046c\xb5\xad\xc1\x189s%\x8dk\x85$\xff\xa2\x8f\xfe\xb2=\xe3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0473\u007f\x03\xcb\x10t$\xe9\xc4\xddW\\\xcdOL\xeeW\xe6\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4\u0475\xa4T\xac4\x05\xbbAy \x8cl\x84\xde\x00k\u02db\xe9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xc4YT\xa6+\x91\x1a\xd7\x01\xff.\x90\x13\x1e\x8c\xeb\x89\xc9\\\x89K\x91\xa2\xdeE~\x88\x00\x00\u07d4\xd1\xc9np\xf0Z\xe0\xe6\xcd`!\xb2\b7P\xa7q|\xdeV\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\u0571\u007f\xfe-{\xbby\xcc}y0\xbc\xb2\xe5\x18\xfb\x1b\xbf\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd1\xda\f\x8f\xb7\xc2\x10\xe0\xf2\xeca\x8f\x85\xbd\xae}>sK\x1c\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd1\xddy\xfb\x15\x81`\xe5\xb4\xe8\xe2?1.j\x90\u007f\xbcMN\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xdeZ\xad:_\xd8\x03\U00071bb6\x10<\xb8\xe1O\xe7#\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd1\xe1\xf2\xb9\xc1l0\x98t\xde\xe7\xfa\xc3&u\xaf\xf1)\u00d8\x89\x03\xf2M\x8eJ\x00p\x00\x00\xe0\x94\xd1\xe5\xe24\xa9\xf4Bf\xa4\xa6$\x1a\x84\u05e1\xa5Z\u0567\xfe\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd1\xeaMr\xa6{[>\x0f1UY\xf5+\xd0aMq0i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1\xee\x90YW\xfe|\xc7\x0e\xc8\xf2\x86\x8bC\xfeG\xb1?\xeb\xff\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\xd1\xf1iM\"g\x1bZ\xadj\x94\x99\\6\x9f\xbea3go\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\xf4\xdc\x1d\u06ca\xbb\x88H\xa8\xb1N%\xf3\xb5Z\x85\x91\xc2f\x89\r\x8drkqw\xa8\x00\x00\u07d4\xd1\xfe\u042e\xe6\xf5\xdf\xd7\xe2Wi%L<\xfa\xd1Z\xde\u032a\x89'\x92\xc8\xfcKS(\x00\x00\u07d4\xd2\x05\x1c\xb3\xcbg\x04\xf0T\x8c\u0210\xab\n\x19\xdb4\x15\xb4*\x89\x12\x1b.^ddx\x00\x00\u07d4\xd2\x06\xaa\u07736\xd4^yr\xe9<\xb0uG\x1d\x15\x89{]\x89 \x86\xac5\x10R`\x00\x00\u07d4\xd2\tH+\xb5I\xab\xc4w{\xeam\u007fe\x00b\xc9\xc5z\x1c\x89\x11e\x1a\xc3\xe7\xa7X\x00\x00\u07d4\xd2\r\xcb\vxh+\x94\xbc0\x00(\x14H\xd5W\xa2\v\xfc\x83\x890\x84\x9e\xbe\x166\x9c\x00\x00\u07d4\xd2\x10{57&\u00e2\xb4ef\xea\xa7\xd9\xf8\v]!\xdb\xe3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\x11\xb2\x1f\x1b\x12\xb5\ta\x81Y\r\xe0~\xf8\x1a\x89S~\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd2\x18\xef\xb4\u06d8\x1c\xddjy\u007fK\u050c|&)<\xeb@\x89\xa1Fk1\xc6C\x1c\x00\x00\xe0\x94\xd2\x1asA\xeb\x84\xfd\x15\x10T\xe5\u31fb%\xd3nI\x9c\t\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2$\xf8\x80\xf9G\x9a\x89\xd3/\t\xe5+\u9432\x88\x13\\\xef\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xd2/\f\xa4\xcdG\x9ef\x17u\x05;\xccI\xe3\x90\xf6p\u074a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd21\x92\x975\x13!\x02G\x1b\xa5\x90\a\xb6dL\xc0\xc1\xde>\x8967\tlK\xcci\x00\x00\u07d4\xd25\xd1\\\xb5\xec\xee\xbba)\x9e\x0e\x82\u007f\xa8'H\x91\x1d\x89\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2:$\xd7\xf9F\x83C\xc1C\xa4\x1ds\xb8\x8f|\xbec\xbe^\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2=z\xff\xac\xdc>\x9f=\xaez\xfc\xb4\x00oX\xf8\xa4F\x00\x89\xc3(\t>a\xee@\x00\x00\u07d4\xd2C\x18L\x80\x1e]y\xd2\x06?5x\u06ee\x81\u7ce9\u02c9k\u0722h\x1e\x1a\xba\x00\x00\u07d4\xd2KfD\xf49\xc8\x05\x1d\xfcd\u04c1\xb8\xc8lu\xc1u8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2K\xf1--\xdfE}\xec\xb1xt\xef\xde R\xb6\\\xbbI\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2Q\xf9\x03\xae\x18rrY\xee\xe8A\xa1\x89\xa1\xf5i\xa5\xfdv\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd2R\x96\v\v\xf6\xb2\x84\x8f\u07ad\x80\x13m\xb5\xf5\a\xf8\xbe\x02\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2X\x1aU\xce#\xab\x10\u062d\x8cD7\x8fY\a\x9b\xd6\xf6X\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xd2Z\xec\xd7\xeb\x8b\xd64[\x06;]\xbd'\x1cw\xd3QD\x94\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xd2|#O\xf7\xac\xca\xce=\x99g\b\xf8\xf9\xb0Ip\xf9}6\x89Hz\x9a0E9D\x00\x00\u07d4\u0482\x98RM\xf5\xecK$\xb0\xff\xb9\u07c5\x17\n\x14Z\x9e\xb5\x89\x0f\x98\xa3\xb9\xb37\xe2\x00\x00\xe0\x94\u0483\xb8\xed\xb1\n%R\x8aD\x04\xde\x1ce\xe7A\r\xbc\xaag\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u0484\xa5\x03\x82\xf8:am9\xb8\xa9\xc0\xf3\x96\xe0\ubfe9]\x8966\xc2^f\xec\xe7\x00\x00\u07d4\u0488\xe7\xcb{\xa9\xf6 \xab\x0ftR\xe5\bc=\x1cZ\xa2v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u049d\xc0\x8e\xfb\xb3\xd7.&?x\xabv\x10\xd0\"m\xe7k\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u04a00\xac\x89R2_\x9e\x1d\xb3x\xa7\x14\x85\xa2N\x1b\a\xb2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u04a4y@CG\xc5T:\xab)*\xe1\xbbJo\x15\x83W\xfa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u04a5\xa0$#\nW\xcc\xc6fv\v\x89\xb0\xe2l\xaf\u0449\u01ca\n\x96YZ\\n\x8a?\x80\x00\u07d4\u04a8\x03'\xcb\xe5\\L{\xd5\x1f\xf9\xdd\xe4\xcad\x8f\x9e\xb3\xf8\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u04a8Oug\\b\xd8\f\x88ulB\x8e\xee+\xcb\x18T!\x89A\rXj \xa4\xc0\x00\x00\u07d4\u04ab\xd8J\x18\x10\x93\xe5\xe2)\x13oB\xd85\xe8#]\xe1\t\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\u04ac\r:X`^\x1d\x0f\x0e\xb3\xde%\xb2\xca\xd1)\xed`X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u04bfg\xa7\xf3\xc6\xceV\xb7\xbeAg]\xbb\xad\xfe~\xa9:3\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd2\xdb\xeb\xe8\x9b\x03W\xae\xa9\x8b\xbe\x8eIc8\u07bb(\xe8\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2\xe2\x1e\xd5hh\xfa\xb2\x8e\tG\x92z\xda\xf2\x9f#\xeb\xadl\x89l\x18O\x13U\xd0\xe8\x00\x00\u07d4\xd2\xe8\x17s\x8a\xbf\x1f\xb4\x86X?\x80\xc3P1\x8b\xed\x86\f\x80\x89\r\x02\xce\xcf_]\x81\x00\x00\u07d4\xd2\xed\xd1\xdd\xd6\xd8m\xc0\x05\xba\xebT\x1d\"\xb6@\xd5\xc7\xca\xe5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\xf1\x99\x8e\x1c\xb1X\f\xecOl\x04}\xcd=\xce\xc5L\xf7<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2\xf2A%]\xd7\xc3\xf7<\a\x040q\xec\b\xdd\xd9\xc5\xcd\xe5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd2\xffg \x16\xf6;/\x859\x8fJo\xed\xbb`\xa5\r<\u0389\x12\x91$o[sJ\x00\x00\u07d4\xd3\rLC\xad\xcfU\xb2\xcbS\u0583#&A4I\x8d\x89\u038965\u026d\xc5\u07a0\x00\x00\u07d4\xd3\x0e\xe9\xa1+Mh\xab\xac\xe6\xba\u029a\u05ff\\\xd1\xfa\xf9\x1c\x89QO\xcb$\xff\x9cP\x00\x00\u07d4\xd3\x11\x8e\xa3\xc85\x05\xa9\u0613\xbbg\xe2\xde\x14-Sz>\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd3\x11\xbc\u05eaN\x9bO8?\xf3\xd0\u05b6\xe0~!\xe3p]\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd3\x15\xde\xea\x1d\x8c\x12q\xf9\xd11\x12c\xabG\xc0\a\xaf\xb6\xf5\x89\x03\xc8\x1dNeK@\x00\x00\u07d4\xd3+,y\xc3dx\xc5C\x19\x01\xf6\xd7\x00\xb0M\xbe\x9b\x88\x10\x89\x15w\x9a\x9d\xe6\xee\xb0\x00\x00\u07d4\xd3+EVF\x14Ql\x91\xb0\u007f\xa9\xf7-\xcfx|\xceN\x1c\x89\x0f\xc6o\xae7F\xac\x00\x00\u07d4\xd30r\x811\xfe\x8e:\x15Hz4W<\x93E~*\xfe\x95\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd31\xc8#\x82Z\x9eRc\xd0R\u0611]M\xcd\xe0z\\7\x89\x1e\x93\x12\x83\xcc\xc8P\x00\x00\u07d4\xd33btE\xf2\u05c7\x90\x1e\xf3;\xb2\xa8\xa3g^'\xff\xec\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3<\xf8+\xf1LY&@\xa0\x86\b\x91L#py\u057e4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3Mp\x8ds\x98\x02E3\xa5\xa2\xb20\x9b\x19\xd3\xc5Qq\xbb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3N\x03\xd3j+\xd4\u045a_\xa1b\x18\xd1\xd6\x1e?\xfa\v\x15\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\xd3Pu\xcaa\xfeY\xd1#\x96\x9c6\xa8-\x1a\xb2\xd9\x18\xaa8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xd3g\x00\x9a\xb6X&;b\xc23:\x1c\x9eA@I\x8e\x13\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3g\x9aG\xdf-\x99\xa4\x9b\x01\u024d\x1c>\f\x98|\xe1\xe1X\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94\u04cf\xa2\xc4\xcc\x14z\xd0j\u0562\xf7Uy(\x1f\"\xa7\xcc\x1f\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\u04da]\xa4`9+\x94\v\u01ee8\xf1e\u007f\x8a\x01f\xc5H\b\x89\xdbw\x00\x00\xe0\x94\xd3\xd6\xe9\xfb\x82T/\u049e\xd9\xea6\t\x89\x1e\x15\x13\x96\xb6\xf7\x8a\voX\x8a\xa7\xbc\xf5\xc0\x00\x00\xe0\x94\xd3\xda\u0476\u040dE\x81\u032ee\xa8s-\xb6\xaci\xf0\u019e\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xd3\xdf;S\xcb;GU\xdeT\xe1\x80E\x1c\xc4L\x9e\x8a\u0a89#\u0114\t\xb9w\x82\x80\x00\u07d4\xd3\xf8s\xbd\x99V\x13W\x89\xab\x00\xeb\xc1\x95\xb9\"\xe9K%\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\x02\xb4\xf6\xa0\x99\xeb\xe7\x16\xcb\x14\xdfOy\xc0\xcd\x01\xc6\a\x1b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd4\r\x00U\xfd\x9a8H\x8a\xff\x92?\xd0=5\xecF\xd7\x11\xb3\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xd4\x0e\xd6j\xb3\xce\xff$\xca\x05\xec\xd4q\ufd12\xc1__\xfa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4\x18\x87\v\xc2\xe4\xfa{\x8aa!\xae\br\xd5RG\xb6%\x01\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xd4\x1d\u007f\xb4\x9f\xe7\x01\xba\xac%qpBl\u0273\x8c\xa3\xa9\xb2\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xd4 U\x92\x84@U\xb3\u01e1\xf8\f\xef\xe3\xb8\xebP\x9b\xcd\xe7\x89\t\xb3\xbf\xd3B\xa9\xfc\x80\x00\u07d4\xd4+ \xbd\x03\x11`\x8bf\xf8\xa6\xd1[*\x95\xe6\xde'\u017f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd44O}\\\xade\xd1~\\-\x0es#\x94=ob\xfe\x92\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xd4>\xe48\xd8=\xe9\xa3ub\xbbN(l\xb1\xbd\x19\xf4\x96M\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd4C4\xb4\xe2:\x16\x9a\f\x16\xbd!\xe8f\xbb\xa5-\x97\x05\x87\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\xe0\x94\xd4M\x81\xe1\x8fF\xe2\u03f5\xc1\xfc\xf5\x04\x1b\xc8V\x97g\xd1\x00\x8a\a\xb4B\xe6\x84\xf6Z\xa4\x00\x00\u07d4\xd4OJ\xc5\xfa\xd7k\xdc\x157\xa3\xb3\xafdr1\x9bA\r\x9d\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xd4O^\xdf+\xcf$3\xf2\x11\xda\xdd\f\xc4P\xdb\x1b\x00\x8e\x14\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xd4Oj\u00d2;_\xd71\xa4\xc4YD\xecO~\xc5*j\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd4[3A\xe8\xf1\\\x802\x93 \u00d7~;\x90\xe7\x82j~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4]]\xaa\x13\x8d\xd1\xd3t\xc7\x1b\x90\x19\x91h\x11\xf4\xb2\nN\x89\x1f9\x9b\x148\xa1\x00\x00\x00\u07d4\xd4`\xa4\xb9\b\xdd+\x05gY\xb4\x88\x85\vf\xa88\xfcw\xa8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd4g\xcf\x06L\bq\x98\x9b\x90\u0632\xeb\x14\xcc\xc6;6\b#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd4k\xaea\xb0'\xe5\xbbB.\x83\xa3\xf9\xc9?<\x8f\xc7}'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4o\x82#E)\x82\xa1\xee\xa0\x19\xa8\x81n\xfc-o\xc0\ah\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xd4uG\u007f\xa5c\x90\xd30\x17Q\x8dg\x11\x02\u007f\x05\U0008dfc9k\x11\x133\xd4\xfdL\x00\x00\u07d4\xd4|$.\xdf\xfe\xa0\x91\xbcT\xd5}\xf5\xd1\xfd\xb91\x01Gl\x89\x9d\xf7\u07e8\xf7`H\x00\x00\u07d4\xd4}\x86\x85\xfa\xee\x14|R\x0f\u0646p\x91u\xbf/\x88k\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\u007fP\u07c9\xa1\xcf\xf9e\x13\xbe\xf1\xb2\xae:)q\xac\xcf,\x89-\x89W}}@ \x00\x00\u07d4\u0502\xe7\xf6\x8eA\xf28\xfeQx)\xde\x15G\u007f\xe0\xf6\xdd\x1d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u0507\x9f\xd1+\x1f:'\xf7\xe1\tv\x1b#\xca4\xfa#\x06K\x1c\xaf\x00Qn(pJ\x82\xa4\xf8\x89Hz\x9a0E9D\x00\x00\u07d4\xd5\x00\xe4\xd1\u0242K\xa9\xf5\xb65\u03e3\xa8\xc2\u00cb\xbdL\xed\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5\b\u04dcp\x91oj\xbcL\xc7\xf9\x99\xf0\x11\xf0w\x10X\x02\x89\x05rM$\xaf\xe7\u007f\x00\x00\u07d4\xd5\x0f\u007f\xa0>8\x98v\u04d0\x8b`\xa57\xa6pc\x04\xfbV\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd5\x13\xa4P\x80\xff/\xeb\xe6,\u0545J\xbe)\xeeDg\xf9\x96\x89\bN\x13\xbcO\xc5\xd8\x00\x00\u07d4\xd5'o\f\xd5\xff\xd5\xff\xb6?\x98\xb5p=U\x94\xed\xe0\x83\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5)KfbB0;m\xf0\xb1\u020d7B\x9b\xc8\xc9e\xaa\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xd5*\xec\xc6I98\xa2\x8c\xa1\xc3g\xb7\x01\xc2\x15\x98\xb6\xa0.\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xd5\x99x\xee \xa3\x8c?I\x8dc\xd5\u007f1\xa3\x9fj\x06\x8a\x022\xb3o\xfcg*\xb0\x00\x00\u07d4\u05568\xd3\xc5\xfa\xa7q\x1b\xf0\x85t_\x9d[\xdc#\u0518\u0609lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u055d\x92\xd2\xc8p\x19\x80\xcc\a<7]r\n\xf0dt<\f\x8a\x04\x05\xfd\xf7\u5bc5\xe0\x00\x00\u07d4\u0567\xbe\xc32\xad\xde\x18\xb3\x10KW\x92Tj\xa5\x9b\x87\x9bR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0571\x17\xec\x11n\xb8FA\x89a\xeb~\xdbb\x9c\xd0\xddi\u007f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u0572\x84\x04\x010\xab\xf7\xc1\xd1cq#q\xcc~(\xadf\u0689j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0579\xd2w\u062a\xd2\x06\x97\xa5\x1fv\xe2\tx\x99k\xff\xe0U\x89\a\xc3\xfe<\aj\xb5\x00\x00\u07d4\u057d^\x84U\xc10\x16\x93W\xc4q\xe3\u6077\x99jrv\x89-\x9e(\x8f\x8a\xbb6\x00\x00\u07d4\xd5\u02e5\xb2k\xea]s\xfa\xbb\x1a\xba\xfa\xcd\xef\x85\xde\xf3h\u0309\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd5\xceU\u0476/YC\xc0?\x89\b\xe3\x1f\xe1h\x9d\x8a\x00\x00\u07d4\xd6\x06Q\xe3\x93x4#\xe5\xcc\x1b\xc5\xf8\x89\xe4N\xf7\xea$>\x89\x15\x9ev7\x11)\xc8\x00\x00\u07d4\xd6\t\xbfO\x14n\xeak\r\xc8\xe0m\xdc\xf4D\x8a\x1f\xcc\xc9\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\t\xec\v\xe7\r\n\xd2ong\xc9\xd4v+R\xeeQ\x12,\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6\nRX\a(R\r\xf7Tk\xc1\xe2\x83)\x17\x88\u06ee\f\x8964\x89\xef?\xf0\xd7\x00\x00\u07d4\xd6\v$s!\xa3*Z\xff\xb9k\x1e'\x99'\xccXM\xe9C\x89z\xd0 \xd6\xdd\xd7v\x00\x00\u07d4\xd6\x11\x02v\xcf\xe3\x1eB\x82ZW\u007fkC]\xbc\xc1\f\xf7d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd6\x12Y{\xc3\x17C\u01c63\xf63\xf29\xb1\xe9Bk\xd9%\x8a\x10\x17\xf7\u07d6\xbe\x17\x80\x00\x00\u07d4\xd6#J\xafE\xc6\xf2.f\xa2%\xff\xb9:\xddb\x9bN\xf8\x0f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6.\u06d6\xfc\u259a\xaflT^\x96|\xf1\xc0\xbc\x80R\x05\x89\x04\xa5eSjZ\u0680\x00\u07d4\xd60\v2\x15\xb1\x1d\xe7b\xec\xdeKp\xb7\x92}\x01)\x15\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd69]\xb5\xa4\xbbf\xe6\x0fL\xfb\xcd\xf0\x05{\xb4\xd9xb\xe2\x891T\xc9r\x9d\x05x\x00\x00\xe0\x94\xd6J-P\xf8\x85\x857\x18\x8a$\xe0\xf5\r\xf1h\x1a\xb0~\u05ca\b7Z*\xbc\xca$@\x00\x00\u07d4\xd6X\n\xb5\xedL}\xfaPo\xa6\xfed\xad\\\xe1)pw2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6Y\x8b\x13\x86\xe9<\\\u02d6\x02\xffK\xbb\xec\xdb\xd3p\x1d\u0109\f%\xf4\xec\xb0A\xf0\x00\x00\u07d4\xd6dM@\xe9\v\xc9\u007f\xe7\xdf\xe7\u02bd2i\xfdW\x9b\xa4\xb3\x89\b\x9e\x91y\x94\xf7\x1c\x00\x00\xe0\x94\xd6g\f\x03m\xf7T\xbeC\xda\u074fP\xfe\xea(\x9d\x06\x1f\u058a\x01D\xa2\x904H\xce\xf7\x80\x00\u07d4\xd6hR:\x90\xf0)=e\xc58\xd2\xddlWg7\x10\x19n\x89\x02$,0\xb8S\xee\x00\x00\u07d4\xd6j\xb7\x92\x94\aL\x8bb}\x84-\xabA\xe1}\xd7\f]\xe5\x8965\u026d\xc5\u07a0\x00\x00\u0794\xd6j\xcc\r\x11\xb6\x89\u03a6\xd9\xea_\xf4\x01L\"J]\xc7\u0108\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xd6m\xdf\x11Y\xcf\"\xfd\x8czK\xc8\u0540wV\xd43\xc4>\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\u0587\xce\xc0\x05\x90\x87\xfd\xc7\x13\xd4\xd2\xd6^w\xda\xef\xed\xc1_\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\u0588\xe7\x85\u024f\x00\xf8K:\xa1S3U\u01e2X\xe8yH\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u05a2.Y\x8d\xab\u04ce\xa6\xe9X\xbdy\u050d\u0756\x04\xf4\u07c965\u026d\xc5\u07a0\x00\x00\u07d4\u05a7\xacM\xe7\xb5\x10\xf0\xe8\xdeQ\x9d\x97?\xa4\xc0\x1b\xa84\x00\x89e\xea=\xb7UF`\x00\x00\u07d4\u05ac\xc2 \xba.Q\xdf\xcf!\xd4C6\x1e\xeav\\\xbd5\u0609\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05ac\xff\u043f\u065c8.{\xd5o\xf0\xe6\x14J\x9eR\xb0\x8e\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xd6\xc0\u043c\x93\xa6.%qtp\x0e\x10\xf0$\u0232?\x1f\x87\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd6\xcf\\\x1b\u03dd\xa6b\xbc\xea\"U\x90P\x99\xf9\xd6\xe8M\u030a\x01\u011eB\x01W\xd9\xc2\x00\x00\u07d4\xd6\xd05r\xa4RE\xdb\xd46\x8cO\x82\xc9W\x14\xbd!g\xe2\x89?\x00\xc3\xd6f\x86\xfc\x00\x00\u07d4\xd6\xd6wiX\xee#\x14:\x81\xad\xad\xeb\b8 \t\xe9\x96\u0089\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd6\xd9\xe3\x0f\bB\x01*qv\xa9\x17\xd9\xd2\x04\x8c\xa0s\x87Y\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6\xe0\x9e\x98\xfe\x13\x003!\x04\xc1\xca4\xfb\xfa\xc5T6N\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\xe8\xe9z\u90db\x9e\xe5\a\xee\xdb(\xed\xfbtw\x03\x149\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\uea18\u052e+q\x80'\xa1\x9c\xe9\xa5\xebs\x00\xab\xe3\u0289\x01}J\xce\xeec\u06c0\x00\xe0\x94\xd6\xf1\xe5[\x16\x94\b\x9e\xbc\xb4\xfe}x\x82\xaaf\u0217av\x8a\x04<#\xbd\xbe\x92\x9d\xb3\x00\x00\u07d4\xd6\xf4\xa7\xd0N\x8f\xaf \xe8\xc6\ub15c\xf7\xf7\x8d\xd2=z\x15\x89\a$\xde\xd1\xc7H\x14\x00\x00\u07d4\xd6\xfc\x04F\u01a8\xd4\n\xe3U\x1d\xb7\xe7\x01\xd1\xfa\x87nJI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x03\u01a4\xf1\x1d`\x19Ey\u054c'f\xa7\xef\x16\xc3\n)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x05%\x19uj\xf4%\x90\xf1S\x91\xb7#\xa0?\xa5d\xa9Q\x89\xfa61H\r\x01\xfd\x80\x00\u07d4\xd7\na+\xd6\u0769\xea\xb0\xdd\xdc\xffJ\xafA\"\u04cf\xea\xe4\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xd7\n\xd2\xc4\xe9\uefe67\xefV\xbdHj\u04a1\xe5\xbc\xe0\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x14\f\x8eZC\a\xfa\xb0\xcc'\xba\u0752\x95\x01\x8b\xf8yp\x89\x05\xf1\x01kPv\xd0\x00\x00\u07d4\xd7\x16J\xa2a\xc0\x9a\u0672\xb5\x06\x8dE>\xd8\xebj\xa10\x83\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\x1eC\xa4Qw\xadQ\xcb\xe0\xf7!\x84\xa5\xcbP9\x17(Z\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x1f\xb10\xf0\x15\fVRi\xe0\x0e\xfbC\x90+R\xa4U\xa6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\"W8\xdc\xf3W\x848\xf8\xe7\u0233\x83~B\xe0J&/\x89\x18+\x8c\ubec3\xaa\x00\x00\u07d4\xd7'MP\x80M\x9cw\u0693\xfaH\x01V\xef\xe5{\xa5\x01\u0789i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd71\xbbk_<79^\t\u03ac\xcd\x14\xa9\x18\xa6\x06\a\x89\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xd7>\xd2\u0645\xb5\xf2\x1bU\xb2td;\xc6\xda\x03\x1d\x8e\u074d\x8a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xd7D\xac~S\x10\xbeijc\xb0\x03\xc4\v\xd097\x05a\u0189Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\xd7Jn\x8dj\xab4\u0385\x97h\x14\xc12{\xd6\xea\a\x84\u048a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xd7ZP*[gr\x87G\x0fe\u016aQ\xb8|\x10\x15\x05r\x8910\xb4dc\x85t\x00\x00\u07d4\xd7m\xba\xeb\xc3\rN\xf6{\x03\xe6\xe6\xec\xc6\xd8N\x00MP-\x89mv\xb9\x18\x8e\x13\x85\x00\x00\u07d4\xd7q\xd9\xe0\u028a\b\xa1\x13wW1CN\xb3'\x05\x99\xc4\r\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7x\x8e\xf2\x86X\xaa\x06\xccS\xe1\xf3\xf0\xdeX\xe5\xc3q\xbex\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xd7x\x92\xe2';#]v\x89\xe40\xe7\xae\ud73c\xe8\xa1\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u05c1\xf7\xfc\t\x18F\x11V\x85p\xb4\x98n,r\x87+~\u0409\x01\x15\x95a\x06]]\x00\x00\u07d4\u05c5\xa8\xf1\x8c8\xb9\xbcO\xfb\x9b\x8f\xa8\xc7r{\xd6B\xee\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u05ce\xcd%\xad\xc8k\xc2\x05\x1d\x96\xf6Sd\x86kB\xa4&\xb7\x89\xd20X\xbf/&\x12\x00\x00\xe0\x94\u05cf\x84\xe3\x89D\xa0\xe0%_\xae\xceH\xbaIP\u053d9\u048a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\u05d4\x83\xf6\xa8DO%I\xd6\x11\xaf\xe0,C-\x15\xe1\x10Q\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05d85\xe4\x04\xfb\x86\xbf\x84_\xba\t\rk\xa2^\f\x88f\xa6\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\u05da\xff\x13\xba-\xa7]F$\f\xac\n$g\xc6V\x94\x98#\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\u05dd\xb5\xabCb\x1az=\xa7\x95\xe5\x89)\xf3\xdd%\xafg\u0649lj\xccg\u05f1\xd4\x00\x00\u07d4\u05e1C\x1e\xe4S\xd1\xe4\x9a\x05P\xd1%hy\xb4\xf5\xd1\x02\x01\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\u05ed\t\xc6\xd3&WhSU\xb5\xc6\uc39fW\xb4\ube42\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u05f7@\xdf\xf8\xc4Wf\x8f\xdft\xf6\xa2f\xbf\xc1\u0737#\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7\u0080>\u05f0\xe0\x83sQA\x1a\x8ef7\xd1h\xbc[\x05\x8a\x06A\xda\xf5\xc9\x1b\xd95\x80\x00\u07d4\xd7\xc6&]\xea\x11\x87l\x90;q\x8eL\u062b$\xfe&[\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xca\u007f\xdc\xfe\xbeE\x88\xef\xf5B\x1d\x15\"\xb6\x13(\xdf{\xf3\x89\xd8\xe6\x00\x1el0+\x00\x00\u07d4\xd7\u037dA\xff\xf2\r\xf7'\xc7\vbU\xc1\xbav\x06\x05Th\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xd1W\xe4\xc0\xa9d7\xa6\u0485t\x1d\xd2>\xc46\x1f\xa3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xd2\xc6\xfc\xa8\xad\x1fu9R\x10\xb5}\xe5\xdf\xd6s\x939\t\x89\x12nr\xa6\x9aP\xd0\x00\x00\xe0\x94\xd7\xd3\xc7Y Y\x048\xb8,>\x95\x15\xbe.\xb6\xedz\x8b\x1a\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\xd7\xd7\xf2\u02a4b\xa4\x1b;0\xa3J\xeb;\xa6\x10\x10\xe2bo\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xe7J\xfd\xba\xd5^\x96\u03bcZ7O,\x8bv\x86\x80\xf2\xb0\x89\x05]\xe6\xa7y\xbb\xac\x00\x00\xe0\x94\xd7\xeb\x901b'\x1c\x1a\xfa5\xfei\xe3s\"\u0224\u049b\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd7\xeb\u0779\xf99\x87w\x9bh\x01U7T8\xdbe\xaf\xcbj\x89\x05t\x1a\xfe\xff\x94L\x00\x00\u07d4\xd7\xef4\x0ef\xb0\u05ef\xcc\xe2\n\x19\xcb{\xfc\x81\xda3\xd9N\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\xf3p\u053e\xd9\xd5|oI\u0259\xder\x9e\xe5i\xd3\xf4\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xfa_\xfb`H\xf9o\xb1\xab\xa0\x9e\xf8{\x1c\x11\xddp\x05\xe4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\x06\x9f\x84\xb5!I?G\x15\x03\u007f2&\xb2_3\xb6\x05\x86\x89g\x8a\x93 b\xe4\x18\x00\x00\u0794\xd8\x15\xe1\xd9\xf4\xe2\xb5\xe5~4\x82k|\xfd\x88\x81\xb8Th\x90\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xd8\x1b\xd5K\xa2\xc4Jok\xeb\x15a\u058b\x80\xb5DNm\u0189?\x17\r~\xe4\"\xf8\x9c\x80-1({\x96q\xe8\x1c\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xd8K\x92/xA\xfcWt\xf0\x0e\x14`J\xe0\xdfB\xc8U\x1e\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xd8U\xb0<\xcb\x02\x9awG\xb1\xf0s\x03\xe0\xa6dy59\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8_\u07af*a\xf9]\xb9\x02\xf9\xb5\xa5<\x9b\x8f\x92f\u00ec\x89l\xf6Z~\x90G(\x00\x00\u07d4\xd8q^\xf9\x17o\x85\v.0\xeb\x8e8'\a\xf7w\xa6\xfb\xe9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8t\xb9\u07eeEj\x92\x9b\xa3\xb1\xa2~W,\x9b,\xec\u07f3\x89\t79SM(h\x00\x00\u07d4\u0613\n9\xc7sW\xc3\n\u04e0`\xf0\v\x06\x04c1\xfdb\x89,s\xc97t,P\x00\x00\u07d4\u061b\xc2q\xb2{\xa3\xabib\xc9JU\x90\x06\xae8\xd5\xf5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0637}\xb9\xb8\x1b\xbe\x90B{b\xf7\x02\xb2\x01\xff\u009f\xf6\x18\x892m\x1eC\x96\xd4\\\x00\x00\u07d4\xd8\xcdd\xe0(N\xecS\xaaF9\xaf\xc4u\b\x10\xb9\u007f\xabV\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xd6C\x84$\x9bwg\x94\x06;V\x98x\xd5\xe3\xb50\xa4\xb2\x89\t\xa0C\u0432\xf9V\x80\x00\u07d4\xd8\xd6T \xc1\x8c#'\xccZ\xf9t%\xf8W\xe4\xa9\xfdQ\xb3\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xd8\xe5\xc9g^\xf4\xde\xed&k\x86\x95o\xc4Y\x0e\xa7\u0522}\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd8\xe8GB\x92\xe7\xa0Q`L\xa1d\xc0pw\x83\xbb(\x85\xe8\x8a\x02\xd4\xca\x05\xe2\xb4<\xa8\x00\x00\u07d4\xd8\xebxP>\xc3\x1aT\xa9\x016x\x1a\xe1\t\x00Lt2W\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\xee\xf4\xcfK\xeb\x01\xee \xd1\x11t\x8ba\xcbM?d\x1a\x01\x89\x94\x89#z\u06daP\x00\x00\u07d4\xd8\xf4\xba\xe6\xf8M\x91\rm}Z\xc9\x14\xb1\xe6\x83r\xf9A5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd8\xf6 6\xf0;v5\xb8X\xf1\x10?\x8a\x1d\x90\x19\xa8\x92\xb6\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xd8\xf6e\xfd\x8c\xd5\u00bc\xc6\xdd\xc0\xa8\xaeR\x1eM\u01aa``\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xd8\xf9$\fU\xcf\xf05RB\x80\xc0\x9e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xfe\b\x8f\xff\u0394\x8fQ7\xee#\xb0\x1d\x95\x9e\x84\xacB#\x89\f[T\xa9O\xc0\x17\x00\x00\u07d4\xd9\x0f0\t\xdbC~N\x11\u01c0\xbe\u0209os\x8de\xef\r\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\x10;\xb6\xb6zU\xa7\xfe\xce-\x1a\xf6-E|!x\x94m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\x13\xf0w\x19Iu\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd9D\u0226\x9f\xf2\xca\x12Ii\f\x12)\xc7\x19/6%\x10b\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd9JW\x88*Rs\x9b\xbe*\x06G\xc8\f$\xf5\x8a+O\x1c\x89H\xb5N*\xdb\xe1+\x00\x00\xe0\x94\xd9SB\x95<\x8a!\xe8\xb65\xee\xfa\u01c1\x9b\xea0\xf1pG\x8a\x13\xf0l\u007f\xfe\xf0]@\x00\x00\u07d4\xd9\\\x90\xff\xbeT\x84\x86G\x80\xb8gIJ\x83\u0212V\xd6\xe4\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\xd9g\x11T\x0e.\x99\x83C\xd4\xf5\x90\xb6\xfc\x8f\xac;\xb8\xb3\x1d\x89_Z@h\xb7\x1c\xb0\x00\x00\u07d4\xd9j\xc2Pt\t\u01e3\x83\xab.\xee\x18\"\xa5\xd78\xb3kV\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd9m\xb3;{Z\x95\f>\xfa-\xc3\x1b\x10\xba\x10\xa52\uf1c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd9wYe\xb7\x16Gfu\xa8\xd5\x13\xeb\x14\xbb\xf7\xb0|\xd1J\x8a\x01\x13.m-#\xc5\xe4\x00\x00\u07d4\xd9{\xc8J\xbdG\xc0[\xbfE{.\xf6Y\xd6\x1c\xa5\xe5\u43c9\x06\x9d\x17\x11\x9d\u0168\x00\x00\u07d4\xd9\u007fE&\u07a9\xb1c\xf8\xe8\xe3:k\u03d2\xfb\x90}\xe6\xec\x89\x0feJ\xafM\xb2\xf0\x00\x00\u07d4\xd9\u007f\xe6\xf5?*X\xf6\xd7mu*\xdft\xa8\xa2\xc1\x8e\x90t\x89\x10\xcd\xf9\xb6\x9aCW\x00\x00\u07d4\u0659\x99\xa2I\r\x94\x94\xa50\xca\xe4\xda\xf3\x85T\xf4\xddc>\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\u065d\xf7B\x1b\x93\x82\xe4,\x89\xb0\x06\xc7\xf0\x87p*\aW\xc0\x89\x1a\x05V\x90\xd9\u06c0\x00\x00\xe0\x94\u0677\x83\xd3\x1d2\xad\xc5\x0f\xa3\xea\u02a1]\x92\xb5h\xea\xebG\x8a\a3\xaf\x907L\x1b(\x00\x00\u07d4\xd9\xd3p\xfe\xc65v\xab\x15\xb3\x18\xbf\x9eX6M\u00a3U*\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xd9\xd4/\xd1>\xbdK\xf6\x9c\xac^\x9c~\x82H:\xb4m\xd7\xe9\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xd9\xe2~\xb0}\xfcq\xa7\x06\x06\f\u007f\a\x928\u0293\xe8\x859\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\xe3\x85~\xfd\x1e *D\x17p\xa7w\xa4\x9d\xccE\xe2\xe0\u04c9\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xd9\xec.\xfe\x99\xff\\\xf0\r\x03\xa81{\x92\xa2J\xefD\x1f~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd9\xec\x8f\xe6\x9bw\x16\xc0\x86Z\xf8\x88\xa1\x1b+\x12\xf7 \xed3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\xf1\xb2d\b\xf0\xecg\xad\x1d\ro\xe2.\x85\x15\xe1t\x06$\x89\x01M\x11 \u05f1`\x00\x00\u07d4\xd9\xf5G\xf2\xc1\xde\x0e\u064aS\xd1a\xdfWc]\xd2\x1a\x00\xbd\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xd9\xff\x11]\x01&l\x9fs\xb0c\xc1\xc28\xef5e\xe6;6\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xda\x06\x04N)#&\xffil\x0091h\xceF\xff\xac9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda*\x14\xf9r@\x15\u05d0\x14\xed\x8eY\th\x1dYaH\xf1\x89\x02\xa1\x0f\x0f\x8a\x91\xab\x80\x00\u07d4\xda*\u054ew\xde\xdd\xed\xe2\x18vF\xc4e\x94Z\x8d\xc3\xf6A\x89#\xc7W\a+\x8d\xd0\x00\x00\u07d4\xda0\x17\xc1P\xdd\r\xce\u007f\u03c8\x1b\nH\xd0\xd1\xc7V\xc4\u01c9\x05k\xf9\x1b\x1ae\xeb\x00\x00\u07d4\xda4\xb2\xea\xe3\v\xaf\xe8\xda\xec\xcd\xe8\x19\xa7\x94\u0349\xe0\x95I\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdaJ_U\u007f;\xab9\n\x92\xf4\x9b\x9b\x90\n\xf3\fF\xae\x80\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdaPU7S\u007f\xfb3\xc4\x15\xfe\xc6Ni\xba\xe0\x90\xc5\xf6\x0f\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdai\x8dd\xc6\\\u007f+,rS\x05\x9c\xd3\u0441\u0619\xb6\xb7\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\u07d4\xdaw2\xf0/.'.\xaf(\u07d7.\xcc\r\xde\xed\x9c\xf4\x98\x89\v \xbf\xbfig\x89\x00\x00\u07d4\xdaz\xd0%\xeb\xde%\xd2\"C\u02c3\x0e\xa1\xd3\xf6JVc#\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\u0685]SG\u007fP^\xc4\xc8\xd5\u8ed1\x80\u04c6\x81\x11\x9c\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\u0687^N/<\xab\xe4\xf3~\x0e\xae\xd7\xd1\xf6\xdc\xc6\xff\xefC\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u068b\xbe\xe1\x82\xe4U\xd2\t\x8a\xcb3\x8amE\xb4\xb1~\u0636\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0698.\x96C\xff\xec\xe7#\aZ@\xfewnZ\xce\x04\xb2\x9b\x89\b\xb8\xb6\u0259\x9b\xf2\x00\x00\u07d4\u069fUF\tF\u05ff\xb5p\xdd\xecu|\xa5w;XB\x9a\x89\x1b\x84]v\x9e\xb4H\x00\x00\u07d4\u06a1\xbdz\x91H\xfb\x86\\\xd6\x12\xdd5\xf1b\x86\x1d\x0f;\u0709\xa68\xabr\xd9,\x13\x80\x00\xe0\x94\u06a6<\xbd\xa4]\u0507\xa3\xf1\xcdJtj\x01\xbb^\x06\v\x90\x8a\x01\x04\x16\u0670*\x89$\x00\x00\u07d4\u06a7v\xa6uDi\u05f9&z\x89\xb8g%\xe7@\xda\x0f\xa0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u06ac\x91\xc1\xe8Y\xd5\xe5~\xd3\bKP \x0f\x97f\xe2\xc5+\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u06ac\xda\xf4\"&\xd1\\\xb1\u03d8\xfa\x15\x04\x8c\u007fL\xee\xfei\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\u06b6\xbc\u06c3\xcf$\xa0\xae\x1c\xb2\x1b;[\x83\xc2\xf3\x82I'\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\u06bb\b\x89\xfc\x04)&\xb0^\xf5{% \x91\n\xbcKAI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06bc\"PB\xa6Y,\xfa\x13\xeb\xe5N\xfaA\x04\bx\xa5\xa2\x89\x0e\x11\xfa\xd5\xd8\\\xa3\x00\x00\u07d4\xda\xc0\xc1w\xf1\x1c\\>>x\xf2\xef\xd6c\xd12!H\x85t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xd16\xb8\x81x\xb4\x83zlx\x0f\xeb\xa2&\xb9\x85i\xa9L\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xda\xdb\xfa\xfd\x8bb\xb9*$\xef\xd7RV\u0743\xab\xdb\u05fb\u06c9\x01\x11du\x9f\xfb2\x00\x00\u07d4\xda\xdc\x00\xaby'`\xaa4\x15i\xfa\x9f\xf5\x98&\x84\x85JJ2\x8an\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xe7 \x1e\xab\x8c\x063\x02\x93\ri9)\xd0\u007f\x95\xe7\x19b\x89\x91\xae\xc0(\xb4\x19\x81\x00\x00\u07d4\xda\xed\u052d\x10{'\x1e\x89Hl\xbf\x80\xeb\xd6!\u0757Ex\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x04\xfa\xd9\u011f\x9e\x88\v\xeb\x8f\xcf\x1d:8\x90\u4cc4o\x89CZ\xe6\xcc\fX\xe5\x00\x00\u07d4\xdb\f\u01cft\u0642{\u070ads'n\xb8O\u0717b\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x12\x93\xa5\x06\xe9\f\xad*Y\xe1\xb8V\x1f^f\x96\x1ag\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x19\xa3\x98\"06\x8f\x01w!\x9c\xb1\f\xb2Y\u0372%|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb#\xa6\xfe\xf1\xaf{X\x1ew,\xf9\x18\x82\u07b2Qo\xc0\xa7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb$O\x97\xd9\xc4K\x15\x8a@\xed\x96\x06\xd9\xf7\xbd8\x9131\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xdb(\x8f\x80\xff\xe22\u00baG\u0314\xc7c\xcfo\u0278+\r\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xdb*\f\x9a\xb6M\xf5\x8d\u07f1\u06ec\xf8\xba\r\x89\xc8[1\xb4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdb4t^\u0785v\xb4\x99\xdb\x01\xbe\xb7\xc1\xec\u0685\xcfJ\xbe\x89\x04V9\x18$O@\x00\x00\u07d4\xdb?%\x8a\xb2\xa3\xc2\xcf3\x9cD\x99\xf7ZK\xd1\xd3G.\x9e\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xdbK\xc8;\x0ek\xaa\xdb\x11V\xc5\xcf\x06\xe0\xf7!\x80\x8cR\u01c9/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xdbc\x12-\xe7\x03}\xa4\x97\x151\xfa\u9bc5\x86x\x86\u0192\x89\x0f\x04%\xb0d\x1f4\x00\x00\u07d4\xdbl*s\xda\xc7BJ\xb0\xd01\xb6ga\x12%f\xc0\x10C\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xdbnV\f\x9b\xc6 \u053e\xa3\xa9MG\xf7\x88\v\xf4\u007f-_\x89\x04\xda\x0f\xdf\xcf\x05v\x00\x00\u07d4\xdbo\xf7\x1b=\xb0\x92\x8f\x83\x9e\x05\xa72;\xfbW\u049c\x87\xaa\x891T\xc9r\x9d\x05x\x00\x00\u07d4\xdbsF\vY\xd8\xe8PE\xd5\xe7R\xe6%Y\x87^BP.\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xdbw\xb8\x8d\xcbq/\xd1~\xe9\x1a[\x94t\x8dr\f\x90\xa9\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb}@7\b\x1fle\xf9Gk\x06\x87\xd9\u007f\x1e\x04M\n\x1d\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\u06c8.\xac\xed\xd0\xef\xf2cQ\x1b1*\u06fcY\u01b8\xb2[\x8a\x01\xedO\xdez\"6\xb0\x00\x00\u07d4\u06d3q\xb3\fL\x84NY\xe0>\x92K\xe6\x06\xa98\xd1\xd3\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06e4ym\f\xebM:\x83k\x84\xc9o\x91\n\xfc\x10?[\xa0\x89\t\b\xf4\x93\xf77A\x00\x00\u07d4\u06ed\xc6\x1e\xd5\xf0F\n\u007f\x18\xe5\x1b/\xb2aM\x92d\xa0\xe0\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u06f6\xacH@'\x04\x16B\xbb\xfd\x8d\x80\xf9\xd0\xc1\xcf3\xc1\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06fc\xbby\xbfG\x9aB\xadq\xdb\u02b7{Z\u07ea\x87,X\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xdb\xc1\xce\x0eI\xb1\xa7\x05\xd2. 7\xae\xc8x\xee\ru\xc7\x03\x89\r\x8drkqw\xa8\x00\x00\u07d4\xdb\xc1\xd0\xee+\xabS\x11@\xde\x13w\"\xcd6\xbd\xb4\xe4q\x94\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\u015e\u0609s\u07ad1\b\x84\":\xf4\x97c\xc0P0\xf1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xdb\xc6ie\xe4&\xff\x1a\xc8z\xd6\xebx\xc1\xd9Rq\x15\x8f\x9f\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xdb\xcb\xcdzW\ua7724\x9b\x87\x8a\xf3K\x1a\xd6B\xa7\xf1\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\xd5\x1c\xdf,;\xfa\xcd\xff\x10b!\xde.\x19\xadmB\x04\x14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdb\xd7\x1e\xfaK\x93\u0209\xe7e\x93\xde`\x9c;\x04\u02ef\xbe\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xdb\xf5\xf0a\xa0\xf4\x8e^ia\x879\xa7}.\xc1\x97h\xd2\x01\x89\b=lz\xabc`\x00\x00\u07d4\xdb\xf8\xb19g\xf5Q%'-\xe0V%6\xc4P\xbaVU\xa0\x89n\xf5x\xf0n\f\xcb\x00\x00\u07d4\xdb\xfb\x1b\xb4d\xb8\xa5\x8eP\r.\xd8\u0797,E\xf5\xf1\xc0\xfb\x89V\xbcu\xe2\xd61\x00\x00\x00\xe0\x94\xdc\x06~\xd3\xe1-q\x1e\xd4u\xf5\x15n\xf7\xe7\x1a\x80\xd94\xb9\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xdc\b\u007f\x93\x90\xfb\x9e\x97j\xc2:\xb6\x89TJ\tB\xec !\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xdc\x1e\xb9\xb6\xe6CQ\xf5d$P\x96E\xf8>y\xee\xe7l\xf4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\x1f\x19ya_\b!@\xb8\xbbx\xc6{'\xa1\x94'\x13\xb1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xdc#\xb2`\xfc\xc2n}\x10\xf4\xbd\x04J\xf7\x94W\x94`\xd9\u0689\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xdc)\x11\x97E\xd23s \xdaQ\xe1\x91\x00\xc9H\u0640\xb9\x15\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdc-\x15\xa6\x9fk\xb3;$j\xef@E\aQ\xc2\xf6uj\u0489l4\x10\x80\xbd\x1f\xb0\x00\x00\u07d4\xdc=\xaeY\xed\x0f\xe1\x8bXQ\x1eo\xe2\xfbi\xb2\x19h\x94#\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xdc?\x0evr\xf7\x1f\xe7R[\xa3\v\x97U\x18: \xb9\x16j\x8a\x02\b\x9c\xf5{[>\x96\x80\x00\xe0\x94\xdcCE\u0581.\x87\n\xe9\fV\x8cg\xd2\xc5g\u03f4\xf0<\x8a\x01k5-\xa5\xe0\xed0\x00\x00\u07d4\xdcD'[\x17\x15\xba\xea\x1b\x03EsZ)\xacB\xc9\xf5\x1bO\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xdcF\xc13%\u034e\xdf\x020\xd0h\x89d\x86\xf0\a\xbfN\xf1\x89Hz\x9a0E9D\x00\x00\u07d4\xdcQ\xb2\u071d$z\x1d\x0e[\xc3l\xa3\x15oz\xf2\x1f\xf9\xf6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdcS\x05\xb4\x02\n\x06\xb4\x9de||\xa3L5\xc9\x1c_,V\x8a\x01}\xf6\xc1\r\xbe\xba\x97\x00\x00\u07d4\xdcW4[8\xe0\xf0g\u0263\x1d\x9d\xea\xc5'Z\x10\x94\x93!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdcWG}\xaf\xa4/p\\\u007f\xe4\x0e\xae\x9c\x81un\x02%\xf1\x89\x1b\x1b\x81(\xa7An\x00\x00\u07d4\xdc_Z\xd6c\xa6\xf2c2}d\xca\xc9\xcb\x13=,\x96\x05\x97\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdcp:_7\x94\xc8Ml\xb3TI\x18\xca\xe1J5\u00fdO\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94\xdcs\x8f\xb2\x17\u03ad/iYL\b\x17\r\xe1\xaf\x10\xc4\x19\xe3\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xdcv\xe8[\xa5\v\x9b1\xec\x1e& \xbc\xe6\xe7\xc8\x05\x8c\x0e\xaf\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0703\xb6\xfd\rQ!1 G\a\xea\xf7.\xa0\xc8\u027e\xf9v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u070c)\x12\xf0\x84\xa6\u0444\xaasc\x85\x13\u033c2n\x01\x02\x89F3\xbc6\xcb\xc2\xdc\x00\x00\u07d4\u0711\x1c\xf7\xdc]\u04016Vg\x05(\xe93\x8eg\x03G\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0730;\xfal\x111#NV\xb7\xea|Or\x14\x87Tkz\x89Hz\x9a0E9D\x00\x00\xe0\x94\u0736M\xf47X\xc7\u03d7O\xa6`HO\xbbq\x8f\x8cg\xc1\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdc\xc5-\x8f\x8d\x9f\xc7B\xa8\xb8'g\xf0US\x87\xc5c\xef\xff\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xdc\xcb7\x0e\u058a\xa9\"(0C\xef|\xad\x1b\x9d@?\xc3J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\u0324 E\xec>\x16P\x8b`?\xd96\xe7\xfd}\xe5\xf3j\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xdc\xd1\fU\xbb\x85OuD4\xf1!\x9c,\x9a\x98\xac\xe7\x9f\x03\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xdc\u057c\xa2\x00S\x95\xb6u\xfd\xe5\x03VY\xb2k\xfe\xfcI\xee\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xdc\u06fdN&\x04\xe4\x0e\x17\x10\xccg0(\x9d\xcc\xfa\u04c9-\x89\xf9]\xd2\xec'\xcc\xe0\x00\x00\u07d4\xdc\xe3\f1\xf3\xcafr\x1e\xcb!<\x80\x9a\xabV\x1d\x9bR\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdc\xf39eS\x13\x80\x161h\xfc\x11\xf6~\x89\xc6\xf1\xbc\x17\x8a\x89\x12'v\x854\x06\xb0\x80\x00\u07d4\xdc\xf6\xb6W&n\x91\xa4\xda\xe6\x03=\xda\xc1S2\u074d+4\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdc\xf9q\x9b\xe8|oFum\xb4\x89\x1d\xb9\xb6\x11\xd2F\x9cP\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdc\xff\xf3\xe8\xd2<*4\xb5k\u0473\xbdE\u01d3tC\"9\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xdd\x04\xee\xe7N\v\xf3\f?\x8dl,\u007fR\xe0Q\x92\x10\u07d3\x89\x04V9\x18$O@\x00\x00\xe0\x94\xdd&\xb4)\xfdC\xd8N\xc1y\x82S$\xba\u057f\xb9\x16\xb3`\x8a\x01\x16\xbf\x95\xbc\x842\x98\x00\x00\u07d4\xdd*#:\xde\xdef\xfe\x11&\xd6\xc1h#\xb6*\x02\x1f\xed\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd+\u07e9\x17\xc1\xf3\x10\xe6\xfa5\xaa\x8a\xf1i9\xc23\xcd}\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xdd5\xcf\xdb\u02d93\x95Sz\xec\xc9\xf5\x90\x85\xa8\xd5\u0776\xf5\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xddG\x18\x9a>d9qg\xf0b\x0eHEe\xb7b\xbf\xbb\xf4\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xddM\xd6\xd3`3\xb0co\u030d\t8`\x9fM\xd6OJ\x86\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xddO_\xa2\x11\x1d\xb6\x8fk\xde5\x89\xb60)9[i\xa9-\x89\b\x96=\xd8\xc2\xc5\xe0\x00\x00\xe0\x94\xddc\x04/%\xed2\x88J\xd2n:\xd9Y\xeb\x94\xea6\xbfg\x8a\x04\x84\xd7\xfd\xe7\u0553\xf0\x00\x00\u07d4\xdde\xf6\xe1qc\xb5\xd2\x03d\x1fQ\xcc{$\xb0\x0f\x02\xc8\xfb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xddl\x06!\x93\xea\xc2=/\xdb\xf9\x97\xd5\x06:4k\xb3\xb4p\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdd{\u0366Y$\xaa\xa4\x9b\x80\x98J\xe1su\x02X\xb9(G\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdd\u007f\xf4A\xbao\xfe6q\xf3\xc0\u06bb\xff\x18#\xa5\x043p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0742T\x12\x1an\x94/\xc9\b(\xf2C\x1fQ\x1d\xad\u007f2\u6263\x9b)\xe1\xf3`\xe8\x00\x00\xe0\x94\u074a\xf9\xe7vR#\xf4DoD\xd3\xd5\t\x81\x9a==\xb4\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\u0755\xdb\xe3\x0f\x1f\x18w\xc5\xddv\x84\xae\xef0*\xb6\x88Q\x92\x8a\x01\xc5\xd8\xd6\xeb>2P\x00\x00\xe0\x94\u0756|L_\x8a\xe4~&o\xb4\x16\xaa\u0456N\xe3\xe7\xe8\u00ca\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u075bHZ;\x1c\xd3:j\x9cb\xf1\xe5\xbe\xe9'\x01\x85m%\x89\f3\x83\xed\x03\x1b~\x80\x00\xe0\x94\u0763q\xe6\x00\xd3\x06\x88\xd4q\x0e\b\x8e\x02\xfd\xf2\xb9RM_\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\u0764\xed*X\xa8\xdd \xa72u4{X\rq\xb9[\xf9\x9a\x89\x15\xa1<\xc2\x01\xe4\xdc\x00\x00\xe0\x94\u0764\xff}\xe4\x91\u0187\xdfEt\xdd\x1b\x17\xff\x8f$k\xa3\u044a\x04&\x84\xa4\x1a\xbf\xd8@\x00\x00\u07d4\u076bkQ\xa9\x03\v@\xfb\x95\xcf\vt\x8a\x05\x9c$\x17\xbe\u01c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u076bu\xfb/\xf9\xfe\u02c8\xf8\x94vh\x8e+\x00\xe3g\xeb\xf9\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\xe0\x94\u076b\xf1<<\x8e\xa4\xe3\xd7=x\xecqz\xfa\xfaC\x0eTy\x8a\b\xcf#\xf9\t\xc0\xfa\x00\x00\x00\u07d4\u076c1*\x96UBj\x9c\f\x9e\xfa?\xd8%Y\xefE\x05\xbf\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\u076ck\xf4\xbb\xdd}Y}\x9chm\x06\x95Y;\xed\xcc\xc7\xfa\x89.\xe4IU\b\x98\xe4\x00\x00\xe0\x94\u077d+\x93,v;\xa5\xb1\xb7\xae;6.\xac>\x8d@\x12\x1a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u077d\xdd\x1b\xbd8\xff\xad\xe00]0\xf0 (\xd9.\x9f:\xa8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u077e\xe6\xf0\x94\xea\xe64 \xb0\x03\xfbGW\x14*\xeal\xd0\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd\u059c[\x9b\xf5\xebZ9\xce\xe7\xc34\x1a\x12\r\x97?\xdb4\x89k\xc1K\x8f\x8e\x1b5\x00\x00\xe0\x94\xdd\xdd{\x9en\xab@\x9b\x92&:\xc2r\u0680\x1bfO\x8aW\x8ai\xe1\r\xe7fv\u0400\x00\x00\u07d4\xdd\xe6p\xd0\x169fuv\xa2-\xd0]2F\xd6\x1f\x06\xe0\x83\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94\xdd\xe7zG@\xba\b\xe7\xf7?\xbe:\x16t\x91)1t.\xeb\x8a\x044\xfeMC\x82\xf1\u0500\x00\u07d4\xdd\xe8\xf0\xc3\x1bt\x15Q\x1d\xce\xd1\xcd}F2>K\xd1\"2\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xdd\xe9i\xae\xf3N\xa8z\u0099\xb7Y~)+J\x01U\u030a\x89\x102\xf2YJ\x01s\x80\x00\u07d4\xdd\xf0\xcc\xe1\xfe\x99m\x91v5\xf0\a\x12\xf4\x05 \x91\xdf\xf9\xea\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdd\xf3\xadv58\x10\xbej\x89\xd71\xb7\x87\xf6\xf1q\x88a+\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xdd\xf5\x81\n\x0e\xb2\xfb.22;\xb2\u0255\t\xab2\x0f$\xac\x8a\x03\xca\\f\u067cD0\x00\x00\xe0\x94\xdd\xf9\\\x1e\x99\xce/\x9fV\x98\x05|\x19\xd5\xc9@'\xeeJn\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\xdd\xfa\xfd\xbc|\x90\xf12\x0eT\xb9\x8f7F\x17\xfb\xd0\x1d\x10\x9f\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xdd\xfc\xca\x13\xf94\xf0\u03fe#\x1d\xa109\xd7\x04u\xe6\xa1\u040968\"\x16`\xa5\xaa\x80\x00\u07d4\xde\x02~\xfb\xb3\x85\x03\"n\xd8q\t\x9c\xb3\v\xdb\x02\xaf\x135\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xde\x06\xd5\xeawzN\xb1G^`]\xbc\xbfCDN\x807\xea\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xde\a\xfb[zFN;\xa7\xfb\xe0\x9e\x9a\xcb'\x1a\xf53\x8cX\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xde\x11!\x82\x9c\x9a\b(@\x87\xa4?\xbd/\xc1\x14*23\xb4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xde\x17kR\x84\xbc\xee:\x83\x8b\xa2Og\xfc|\xbfg\u05ce\xf6\x89\x02\t\xce\b\xc9b\xb0\x00\x00\u07d4\xde!\"\x93\xf8\xf1\xd21\xfa\x10\xe6\tG\rQ,\xb8\xff\xc5\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde0\xe4\x9eZ\xb3\x13!M/\x01\u072b\u0389@\xb8\x1b\x1cv\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xde3\xd7\b\xa3\xb8\x9e\x90\x9e\xafe;0\xfd\u00e5\xd5\u0334\xb3\x89\t\x9c\x88\"\x9f\xd4\xc2\x00\x00\u07d4\xde7B\x99\xc1\xd0}ySs\x85\x19\x0fD.\xf9\xca$\x06\x1f\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xdeB\xfc\xd2L\xe4#\x93\x830CgY_\x06\x8f\fa\a@\x89\x02r*p\xf1\xa9\xa0\x00\x00\u07d4\xdeP\x86\x8e\xb7\xe3\xc7\x197\xecs\xfa\x89\u074b\x9e\xe1\rE\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdeU\xde\x04X\xf8P\xb3~Mx\xa6A\xdd.\xb2\u074f8\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde[\x00_\xe8\u06ae\x8d\x1f\x05\xde>\xda\x04 f\xc6\xc4i\x1c\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xdea-\a$\xe8N\xa4\xa7\xfe\xaa=!B\xbd^\xe8-2\x01\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdem61\x06\xccb8\xd2\xf0\x92\xf0\xf07!6\xd1\xcdP\u018a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xde}\xee\"\x0f\x04W\xa7\x18}V\xc1\xc4\x1f.\xb0\n\xc5`!\x89\"%\xf3\x9c\x85\x05*\x00\x00\u07d4\u0782\u030dJ\x1b\xb1\xd9CC\x92\x96[>\x80\xba\xd3\xc0=O\x89P\x18nu\u0797\xa6\x00\x00\u07d4\u0797\xf43\a\x00\xb4\x8cImC|\x91\xca\x1d\xe9\u0130\x1b\xa4\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\u07d4\u079e\xffLy\x88\x11\xd9h\xdc\xcbF\r\x9b\x06\x9c\xf3\x02x\xe0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u07b1\xbc4\xd8mJM\xde%\x80\u063e\xaf\aN\xb0\xe1\xa2D\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\u07b2I]j\xca{*j-\x13\x8bn\x1aB\xe2\xdc1\x1f\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\u07b9rTGL\r/Zyp\xdc\xdb/R\xfb\x10\x98\xb8\x96\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07b9\xa4\x9aC\x870 \xf0u\x91\x85\xe2\v\xbbL\U000c1ecf\x89\vx\xed\xb0\xbf.^\x00\x00\u07d4\u07bb\u0743\x1e\x0f \xaen7\x82R\xde\xcd\xf9/|\xf0\xc6X\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xc3\xee\xc2d\nu,Fn+~~\u616f\xe9\xacA\xf4\x89G\u0257SYk(\x80\x00\u07d4\xde\xc8#s\xad\xe8\xeb\xcf*\xcbo\x8b\xc2AM\u05eb\xb7\rw\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xde\u0221\xa8\x98\xf1\xb8\x95\xd80\x1f\xe6J\xb3\xad]\xe9A\xf6\x89\x89*\xb4\xf6~\x8as\x0f\x80\x00\u07d4\xde\u025e\x97/\xcaqwP\x8c\x8e\x1aG\xac\"\xd7h\xac\xab|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xd8w7\x84\a\xb9Nx\x1cN\xf4\xaf|\xfc[\xc2 \xb5\x16\x89\x141y\xd8i\x11\x02\x00\x00\u07d4\xde\xe9B\xd5\xca\xf5\xfa\xc1\x14!\xd8k\x01\vE\x8e\\9)\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde\xee&\x89\xfa\x90\x06\xb5\x9c\xf2\x85#}\xe5;:\u007f\xd0\x148\x89\x18ey\xf2\x9e %\x00\x00\u07d4\xde\xfd\xdf\u055b\x8d,\x15N\xec\xf5\xc7\xc1g\xbf\v\xa2\x90]>\x89\x05\x12\xcb^&GB\x00\x00\u07d4\xde\xfe\x91A\xf4pE\x99\x15\x9d{\"=\xe4+\xff\xd8\x04\x96\xb3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xdf\t\x8f^N=\xff\xa5\x1a\xf27\xbd\xa8e,Os\ud726\x89\x1b6\xa6DJ>\x18\x00\x00\xe0\x94\xdf\r\ba{\xd2R\xa9\x11\u07cb\xd4\x1a9\xb8=\u07c0\x96s\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdf\x0f\xf1\xf3\xd2z\x8e\xc9\xfb\x8fk\f\xb2T\xa6;\xba\x82$\xa5\x89\xec\xc5 )E\xd0\x02\x00\x00\u07d4\xdf\x1f\xa2\xe2\x0e1\x98^\xbe,\x0f\f\x93\xb5L\x0f\xb6z&K\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdf!\x1c\xd2\x12\x88\xd6\xc5o\xaef\xc3\xffTb]\u0531T'\x89\x87\x86\xcdvN\x1f,\x00\x00\u07d4\xdf#k\xf6\xab\xf4\xf3)7\x95\xbf\f(q\x8f\x93\u3c73k\x89Hz\x9a0E9D\x00\x00\u07d4\xdf1\x02_VI\xd2\xc6\xee\xa4\x1e\u04fd\xd3G\x1ay\x0fu\x9a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdf7\xc2.`:\xed\xb6\nbrS\xc4}\x8b\xa8f\xf6\xd9r\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xdf;r\u017dq\u0501N\x88\xa6#!\xa9=@\x11\xe3W\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf?W\xb8\xeed4\xd0G\"=\xeft\xb2\x0fc\xf9\xe4\xf9U\x89\r\x94b\xc6\xcbKZ\x00\x00\u07d4\xdfD\xc4\u007f\xc3\x03\xacv\xe7O\x97\x19L\xcag\xb5\xbb<\x02?\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xdfG\xa6\x1brSQ\x93\xc5a\xcc\xccu\xc3\xf3\xce\b\x04\xa2\x0e\x89\x15\x93\\\vN=x\x00\x00\u07d4\xdfG\xa8\xef\x95\xf2\xf4\x9f\x8eoX\x18AT\x14]\x11\xf7'\x97\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xdfS\x003F\xd6\\^zdk\xc04\xf2\xb7\xd3/\xcb\xe5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfW5:\xaf\xf2\xaa\xdb\n\x04\xf9\x01N\x8d\xa7\x88N\x86X\x9c\x89\bH\x86\xa6nO\xb0\x00\x00\u07d4\xdf`\xf1\x8c\x81*\x11\xedN'v\xe7\xa8\x0e\xcf^S\x05\xb3\u05890\xca\x02O\x98{\x90\x00\x00\u07d4\xdfd\x85\xc4)z\xc1R\xb2\x89\xb1\x9d\xde2\xc7~\xc4\x17\xf4}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdff\n\x91\u06b9\xf70\xf6\x19\rP\xc89\x05aP\aV\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfn\xd6\x00jj\xbe\x88n\xd3=\x95\xa4\xde(\xfc\x12\x189'\x891T\xc9r\x9d\x05x\x00\x00\u07d4\u07c5\x10y>\xee\x81\x1c-\xab\x1c\x93\xc6\xf4G?0\xfb\xef[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07cdH\xb1\xeb\a\xb3\xc2\x17y\x0el-\xf0M\xc3\x19\xe7\xe8H\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u07e6\xb8\xb8\xad1\x84\xe3W\xda()Q\u05d1a\u03f0\x89\xbc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u07ef1\xe6\"\xc0=\x9e\x18\xa0\u0778\xbe`\xfb\xe3\xe6a\xbe\n\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\u07f1bn\xf4\x8a\x1d}uR\xa5\xe0)\x8f\x1f\xc2:;H-\x89\\\xe8\x95\u0754\x9e\xfa\x00\x00\xe0\x94\u07f4\u052d\xe5/\u0301\x8a\xccz,k\xb2\xb0\x02$e\x8fx\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u07fdB2\xc1|@z\x98\r\xb8\u007f\xfb\u036060\xe5\xc4Y\x89\x1d\xfc\u007f\x92I#S\x00\x00\u07d4\xdf\xcb\xdf\tEN\x1a^J@\xd3\xee\xf7\xc5\xcf\x1c\xd3\u0794\x86\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf\xdb\xce\xc1\x01K\x96\xda!X\xcaQ>\x9c\x8d;\x9a\xf1\xc3\u0409lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdf\xde\xd2WK'\xd1a:}\x98\xb7\x15\x15\x9b\r\x00\xba\xab(\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdf\xdfC9P\x8b\x0fnZ\xb1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe0\x06\x04b\xc4\u007f\xf9g\x9b\xae\xf0qY\xca\xe0\x8c)\xf2t\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\r\x15;\x106\x91C\xf9\u007fT\xb8\xd4\xca\"\x9e\xb3\xe8\xf3$\x89\b=lz\xabc`\x00\x00\u07d4\xe0\x12\xdbE8'\xa5\x8e\x16\xc16V\b\xd3n\xd6Xr\x05\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x15G\xbaB\xfc\xaf\xaf\x93\x93\x8b\xec\xf7i\x9ft)\n\xf7O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x16\xdc\x13\x8e%\x81[\x90\xbe?\xe9\xee\xe8\xff\xb2\xe1\x05bO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\x18Y\xf2B\xf1\xa0\xec`/\xa8\xa3\xb0\xb5v@\xec\x89\a^\x89\x1e\x16,\x17{\xe5\xcc\x00\x00\xe0\x94\xe0 \xe8cb\xb4\x87u(6\xa6\xde\v\xc0,\xd8\u061a\x8bj\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xe0#\xf0\x9b(\x87a,|\x9c\xf1\x98\x8e::`+3\x94\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0'\"\x13\xe8\xd2\xfd>\x96\xbdb\x17\xb2KK\xa0\x1bapy\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0+t\xa4v(\xbe1[\x1fv\xb3\x15\x05J\xd4J\xe9qo\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe02 \u0197\xbc\u048f&\xef\vt@J\x8b\xeb\x06\xb2\xba{\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe05/\u07c1\x9b\xa2e\xf1L\x06\xa61\\J\xc1\xfe\x13\x1b.\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe08\x8a\xed\xdd?\xe2\xadV\xf8WH\xe8\x0eq\n4\xb7\xc9.\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0<\x00\xd0\x03\x88\xec\xbfO&=\n\xc7x\xbbA\xa5z@\u064966\xc9yd6t\x00\x00\u07d4\xe0I \xdcn\xcc\x1dn\xcc\bO\x88\xaa\n\xf5\u06d7\xbf\x89:\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xe0Ir\xa8<\xa4\x11+\xc8q\xc7-J\xe1al/\a(\u06c9\x0e\x81\xc7\u007f)\xa3/\x00\x00\u07d4\xe0O\xf5\xe5\xa7\u2bd9]\x88W\xce\x02\x90\xb5:+\x0e\xda]\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xe0P)\xac\xeb\axg[\xef\x17A\xab,\u0493\x1e\xf7\xc8K\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0V\xbf?\xf4\x1c&%o\xefQqf\x12\xb9\u04da\u0799\x9c\x89\x05k\xe7W\xa1.\n\x80\x00\u07d4\xe0a\xa4\xf2\xfcw\xb2\x96\u045a\xda#\x8eI\xa5\u02ce\xcb\xfap\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0f>\x8c\xd6g\x92\xa6A\xf5nP\x03f\x01G\x88\x0f\x01\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0f\x8f\xa8,\x14\xd6\xe8\xd9:S\x11>\xf2\x86/\xa8\x15\x81\xbc\x89//9\xfclT\x00\x00\x00\u07d4\xe0i\xc0\x173R\xb1\v\xf6\x83G\x19\xdb[\xed\x01\xad\xf9{\xbc\x89\x01\x064\xf8\xe52;\x00\x00\u07d4\xe0l)\xa8\x15\x17\xe0\u0507\xb6\u007f\xb0\xb6\xaa\xbcOW6\x83\x88\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xe0l\xb6)G\x04\xee\xa7C|/\xc3\xd3\as\xb7\xbf8\x88\x9a\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\u07d4\xe0q7\xae\r\x11m\x0353\xc4\uad16\xf8\xa9\xfb\tV\x9c\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe0v\xdb0\xabHoy\x19N\xbb\xc4]\x8f\xab\x9a\x92B\xf6T\x8a\x01\x06`~4\x94\xba\xa0\x00\x00\u07d4\xe0~\xbb\xc7\xf4\xdaAnB\xc8\xd4\xf8B\xab\xa1b3\xc1%\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x81\xca\x1fH\x82\xdb`C\u0569\x19\a\x03\xfd\xe0\xab;\xf5m\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x83\xd3Hc\xe0\xe1\u007f\x92ky(\xed\xff1~\x99\x8e\x9cK\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x8b\x9a\xbak\xd9\u048b\xc2\x05gy\xd2\xfb\xf0\xf2\x85Z=\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x8b\u009c+H\xb1i\xff+\xdc\x16qLXnl\xb8\\\u03c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0\x8c`11\x06\xe3\xf93O\xe6\xf7\xe7bM!\x110\xc0w\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xe0\x9ch\xe6\x19\x98\xd9\xc8\x1b\x14\xe4\xee\x80+\xa7\xad\xf6\xd7L\u06c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0\x9f\xeauZ\xee\x1aD\xc0\xa8\x9f\x03\xb5\u07b7b\xba3\x00o\x89;\xa2\x89\xbc\x94O\xf7\x00\x00\xe0\x94\xe0\xa2T\xac\t\xb9r[\xeb\xc8\xe4`C\x1d\xd0s.\xbc\xab\xbf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe0\xaai6UU\xb7?(#3\xd1\xe3\f\x1b\xbd\a(T\xe8\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xe0\xba\u064e\ue598\xdb\xf6\xd7`\x85\xb7\x92=\xe5uN\x90m\x89\t\r\x97/22<\x00\x00\u07d4\xe0\u012b\x90r\xb4\xe6\xe3eJI\xf8\xa8\xdb\x02jK3\x86\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\u0380\xa4a\xb6H\xa5\x01\xfd\v\x82F\x90\u0206\x8b\x0eM\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\xcfi\x8a\x053'\xeb\xd1k}w\x00\t/\xe2\xe8T$F\x89\x05*4\u02f6\x1fW\x80\x00\xe0\x94\xe0\xd21\xe1D\xec\x91\a8l|\x9b\x02\xf1p,\xea\xa4\xf7\x00\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0\xd7kqf\xb1\xf3\xa1+@\x91\xee+)\u078c\xaa}\a\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\xe0\xb2\xe2\x9d\xdes\xafu\x98~\xe4Dl\x82\x9a\x18\x9c\x95\xbc\x89\b\x13\xcaV\x90m4\x00\x00\xe0\x94\xe0\xe9xu=\x98/\u007f\x9d\x1d#\x8a\x18\xbdH\x89\xae\xfeE\x1b\x8a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4\xe0\xf3r4|\x96\xb5_}C\x06\x03K\xeb\x83&o\xd9\tf\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\xf9\x03\xc1\xe4\x8a\xc4!\xabHR\x8f=J&H\b\x0f\xe0C\x897\b\xba\xed=h\x90\x00\x00\u07d4\xe0\xff\v\xd9\x15D9\u0125\xb7#>)\x1d}\x86\x8a\xf5?3\x89\x15y!jQ\xbb\xfb\x00\x00\xe0\x94\xe1\n\xc1\x9cTo\xc2T|a\xc19\xf5\xd1\xf4Zff\u0570\x8a\x01\x02\xdao\xd0\xf7:<\x00\x00\xe0\x94\xe1\fT\x00\x88\x11?\xa6\xec\x00\xb4\xb2\u0202O\x87\x96\xe9n\u010a2\x0fE\t\xab\x1e\xc7\xc0\x00\x00\xe0\x94\xe1\x17:$})\xd8#\x8d\xf0\x92/M\xf2Z\x05\xf2\xafw\u00ca\bx\xc9]V\x0f0G\x80\x00\xe0\x94\xe1 >\xb3\xa7#\xe9\x9c\" \x11|\xa6\xaf\xebf\xfaBOa\x8a\x02\x00\uf49e2V\xfe\x00\x00\xe0\x94\xe11\xf8~\xfc^\xf0~C\xf0\xf2\xf4\xa7G\xb5Q\xd7P\xd9\xe6\x8a\x04<%\xe0\xdc\xc1\xbd\x1c\x00\x00\u07d4\xe13N\x99\x83y\xdf\xe9\x83\x17pby\x1b\x90\xf8\x0e\xe2-\x8d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe15@\xec\xee\x11\xb2\x12\xe8\xb7u\u070eq\xf3t\xaa\xe9\xb3\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1;=+\xbf\u073c\x87r\xa23\x15rL\x14%\x16|V\x88\x897\xf3y\x14\x1e\xd0K\x80\x00\u07d4\xe1D=\xbd\x95\xccA#\u007fa:HEi\x88\xa0Oh2\x82\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xe1F\x17\xf6\x02%\x01\xe9~{>-\x886\xaaa\xf0\xff-\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe1I\xb5rl\xafm^\xb5\xbf*\xccA\xd4\xe2\xdc2\x8d\u1089i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xe1T\xda\xea\xdbTX8\xcb\u01aa\fUu\x19\x02\xf5(h*\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4\xe1l\xe3Ya\xcdt\xbdY\r\x04\u012dJ\x19\x89\xe0V\x91\u0189\a\xea(2uw\b\x00\x00\u07d4\xe1r\xdf\xc8\xf8\f\xd1\xf8\u03459\xdc&\b \x14\xf5\xa8\xe3\u8262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xe1w\xe0\xc2\x01\xd35\xba9V\x92\x9cW\x15\x88\xb5\x1cR#\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1x\x12\xf6l^e\x94\x1e\x18lF\x92+n{/\x0e\xebF\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe1\x80\u079e\x86\xf5{\xaf\xac\u05d0O\x98&\xb6\xb4\xb2c7\xa3\x89-\x04\x1dpZ,`\x00\x00\xe0\x94\xe1\x92H\x9b\x85\xa9\x82\xc1\x882F\xd9\x15\xb2)\xcb\x13 \u007f8\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xe1\x95\xbb\xc6,{tD\x04\x0e\xb9\x96#\x96Ovg\xb3v\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\x06\xfbs$\xe9\u07b7\x9e\x19\x904\x96\u0596\x1b\x9b\xe5f\x03\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe2\aW\x8e\x1fM\u06cf\xf6\u0546{9X-q\xb9\x81*\u0149\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xe2\b\x81*h@\x98\xf3\xdaN\xfej\xba%bV\xad\xfe?\xe6\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2\tT\xd0\xf4\x10\x8c\x82\xd4\u0732\x14\x8d&\xbb\xd9$\xf6\xdd$\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe2\v\xb9\xf3\x96d\x19\xe1K\xbb\xaa\xaag\x89\xe9$\x96\u03e4y\x89\xbb\xd8%\x03\aRv\x00\x00\u07d4\xe2\r\x1b\xcbq(m\xc7\x12\x8a\x9f\xc7\xc6\xed\u007fs8\x92\xee\xf5\x896d\xf8\xe7\xc2J\xf4\x00\x00\u0794\xe2\x19\x12\x15\x98?3\xfd3\xe2,\u0522I\x00T\xdaS\xfd\u0708\xdbD\xe0I\xbb,\x00\x00\u07d4\xe2\x19\x8c\x8c\xa1\xb3\x99\xf7R\x15a\xfdS\x84\xa7\x13/\xbaHk\x897\b\xba\xed=h\x90\x00\x00\xe0\x94\xe2\x1cw\x8e\xf2\xa0\xd7\xf7Q\xea\x8c\aM\x1f\x81\"C\x86>N\x8a\x01\x1f\xc7\x0e,\x8c\x8a\xe1\x80\x00\xe0\x94\xe2)\xe7F\xa8?,\xe2S\xb0\xb0>\xb1G$\x11\xb5~W\x00\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xe2+ \xc7x\x94F;\xafwL\xc2V\u057d\u06ff}\xdd\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe20\xfe\x1b\xff\x03\x18m\x02\x19\xf1]LH\x1b}Y\xbe(j\x89\x01\xfdt\x1e\x80\x88\x97\x00\x00\u07d4\xe27\xba\xa4\xdb\u0252n2\xa3\xd8]\x12d@-T\xdb\x01/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2A\t\xbe/Q=\x87I\x8e\x92j(d\x99uO\x9e\u051e\x890\x0e\xa8\xad\x1f'\xca\x00\x00\u07d4\xe2Fh<\u025d\xb7\u0125+\u02ec\xaa\xb0\xb3/k\xfc\x93\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2Z\x16{\x03\x1e\x84am\x0f\x01?1\xbd\xa9]\xcccP\xb9\x8a\x02\x8c*\xaa\u0243\xd0]\u0187st\xa8\xf4F\xee\xe9\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xe2\x8b\x06\"Y\xe9n\xeb<\x8dA\x04\x94?\x9e\xb3%\x89<\xf5\x89Hz\x9a0E9D\x00\x00\xe0\x94\u237c\x8e\xfd^Ajv.\xc0\xe0\x18\x86K\xb9\xaa\x83({\x8a\x051\xf2\x00\xab>\x03\n\x80\x00\u07d4\xe2\x90K\x1a\xef\xa0V9\x8bb4\xcb5\x81\x12\x88\xd76\xdbg\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u274a\xe4R\xdc\xf3\xb6\xacd^c\x04\t8UQ\xfa\xae\n\x89\x04Z\r\xa4\xad\xf5B\x00\x00\u07d4\xe2\xbb\xf8FA\xe3T\x1fl3\xe6\xedh:cZp\xbd\xe2\xec\x89\x1bA<\xfc\xbfY\xb7\x80\x00\u07d4\xe2\xcf6\n\xa22\x9e\xb7\x9d+\xf7\xca\x04\xa2z\x17\xc52\xe4\u0609\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xe2\xdf#\xf6\xea\x04\xbe\xcfJ\xb7\x01t\x8d\xc0\x961\x84U\\\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2\xe1\\`\xdd8\x1e:K\xe2Pq\xab$\x9aL\\Rd\u0689\u007fk\u011b\x81\xb57\x00\x00\u07d4\xe2\xe2nN\x1d\xcf0\xd0H\xccn\u03ddQ\xec\x12\x05\xa4\xe9&\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe2\xeei\x1f#~\xe6R\x9beW\xf2\xfc\xdd=\xcf\fY\xecc\x8a\x01'r\x9c\x14h| \x00\x00\u07d4\xe2\xef\xa5\xfc\xa7\x958\xce`h\xbf1\xd2\xc5\x16\xd4\xd5<\b\xe5\x89\a\x1c\xc4\b\xdfc@\x00\x00\xe0\x94\xe2\xef\u0429\xbc@~\xce\x03\xd6~\x8e\xc8\xe9\u0483\xf4\x8d*I\x8a\x02\x99\xb3;\xf9\u0144\xe0\x00\x00\u07d4\xe2\xf4\r5\x8f^?\xe7F>\xc7\x04\x80\xbd.\u04d8\xa7\x06;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\xf98=X\x10\xea{C\x18+\x87\x04\xb6+'\xf5\x92]9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe2\xff\x9e\xe4\xb6\xec\xc1AA\xcct\xcaR\xa9\xe7\xa2\xee\x14\xd9\b\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe3\x02\x12\xb2\x01\x1b\xb5k\xdb\xf1\xbc5i\x0f:N\x0f\xd9\x05\xea\x8a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xe3\x03\x16\u007f=I`\xfe\x88\x1b2\x80\n+J\xef\xf1\xb0\x88\u0509lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3\x04\xa3/\x05\xa87btJ\x95B\x97o\xf9\xb7#\xfa1\xea\x89Ur\xf2@\xa3F \x00\x00\u07d4\xe3\bCR\x04y7d\xf5\xfc\xbee\xebQ\x0fZtJeZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3\t\x97L\xe3\x9d`\xaa\xdf.ig2Q\xbf\x0e\x04v\n\x10\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xe3\x1bN\xef\x18L$\xab\t\x8e6\xc8\x02qK\xd4t=\xd0\u0509\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3!\xbbJ\x94j\xda\xfd\xad\xe4W\x1f\xb1\\\x00C\u04de\xe3_\x89Udu8+L\x9e\x00\x00\u07d4\xe3&<\xe8\xafm\xb3\xe4gXE\x02\xedq\t\x12^\xae\"\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3+\x1cG%\xa1\x87TI\u93d7\x0e\xb3\xe5@b\xd1X\x00\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3/\x95vmW\xb5\xcdK\x172\x89\u0587o\x9edU\x81\x94\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe38@\u063c\xa7\u0698\xa6\xf3\u0416\xd8=\xe7\x8bp\xb7\x1e\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe38\xe8Y\xfe.\x8c\x15UHH\xb7\\\xae\u0368w\xa0\xe82\x89a\xac\xff\x81\xa7\x8a\xd4\x00\x00\u07d4\xe3=\x98\x02 \xfa\xb2Y\xafj\x1fK8\xcf\x0e\xf3\xc6\xe2\xea\x1a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe3=\xf4\u0380\u0336*v\xb1+\xcd\xfc\xec\xc4b\x89\x97:\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe3?\xf9\x87T\x1d\xde\\\xde\u0a29m\xcc?3\xc3\xf2L\u008a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xe3A\v\xb7U|\xf9\x1dy\xfai\xd0\xdf\xea\n\xa0u@&Q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3Ad-@\u04af\xce.\x91\a\xc6py\xacz&`\bl\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe3TS\xee\xf2\xcc2\x89\x10CR\x8d\t\x84i\x80\x00\xe0\x94\xe5\x10\xd6y\u007f\xba=f\x93\x83Z\x84N\xa2\xadT\x06\x91\x97\x1b\x8a\x03\xae9\xd4s\x83\xe8t\x00\x00\u07d4\xe5\x14!\xf8\xee\"\x10\xc7\x1e\xd8p\xfea\x82v\u0215J\xfb\xe9\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\x1e\xb8~\u007f\xb71\x1fR(\xc4y\xb4\x8e\u0247\x881\xacL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5!V1\xb1BH\xd4Z%R\x96\xbe\xd1\xfb\xfa\x030\xff5\x89G\x03\xe6\xebR\x91\xb8\x00\x00\xe0\x94\xe5(\xa0\xe5\xa2g\xd6g\xe99:e\x84\xe1\x9b4\u071b\xe9s\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xe54%\xd8\xdf\x1f\x11\xc3A\xffX\xae_\x148\xab\xf1\xcaS\u03c9\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\u07d4\xe5No\x9c\xffV\xe1\x9cF\x1e\xb4T\xf9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5A\x02SM\xe8\xf2>\xff\xb0\x93\xb3\x12B\xad;#?\xac\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe5E\xee\x84\xeaH\xe5d\x16\x1e\x94\x82\u055b\xcf@j`,\xa2\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xe5H\x1a\u007f\xedB\xb9\x01\xbb\xed x\x9b\u052d\xe5\r_\x83\xb9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5Y\xb5\xfd3{\x9cUr\xa9\xbf\x9e\x0f%!\xf7\xd4F\xdb\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\\\x80R\n\x1b\x0fu[\x9a,\xd3\xce!Ov%e>\x8a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe5mC\x13$\xc9)\x11\xa1t\x9d\xf2\x92p\x9c\x14\xb7ze\u034a\x01\xbc\x85\xdc*\x89\xbb \x00\x00\u07d4\xe5})\x95\xb0\xeb\xdf?<\xa6\xc0\x15\xeb\x04&\r\xbb\x98\xb7\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\u51f1j\xbc\x8at\b\x1e6\x13\xe1CB\xc03u\xbf\bG\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\x89\xfav\x98M\xb5\xec@\x04\xb4n\u8954\x92\xc3\aD\u0389\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xe5\x8d\xd228\xeen\xa7\xc2\x13\x8d8]\xf5\x00\xc3%\xf3v\xbe\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe5\x95?\xeaIq\x04\xef\x9a\xd2\xd4\xe5\x84\x1c'\x1f\a5\x19\u0089&)\xf6n\fS\x00\x00\x00\xe0\x94\u5587\x97F\x8e\xf7g\x10\x1bv\x1dC\x1f\xce\x14\xab\xff\u06f4\x8a\x01\xb3\xd9i\xfaA\x1c\xa0\x00\x00\u07d4\xe5\x97\xf0\x83\xa4i\xc4Y\x1c=+\x1d,w'\x87\xbe\xfe'\xb2\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe5\x9b;\xd3\x00\x89?\x97#>\xf9G\xc4or\x17\xe3\x92\xf7\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xa3e4<\xc4\xeb\x1ew\x03h\xe1\xf1\x14Jw\xb82\xd7\xe0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe5\xa3\xd7\xeb\x13\xb1\\\x10\x01w#m\x1b\xeb0\xd1~\xe1T \x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xaa\v\x83;\xb9\x16\xdc\x19\xa8\xddh?\x0e\xde$\x1d\x98\x8e\xba\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u5def\x14i\x86\xc0\xff\x8f\x85\xd2.l\xc34\a}\x84\xe8$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xb8&\x19l\x0e\x1b\xc1\x11\x9b\x02\x1c\xf6\xd2Y\xa6\x10\u0256p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\xb9o\u026c\x03\xd4H\xc1a:\xc9\x1d\x15\x97\x81E\xdb\xdf\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u5e40\u048e\xec\xe2\xc0o\xcal\x94s\x06\x8b7\u0526\xd6\xe9\x89%\xaf\u058c\xac+\x90\x00\x00\u07d4\u5eb4\xf0\xaf\u0629\u0463\x81\xb4Wa\xaa\x18\xf3\xd3\xcc\xe1\x05\x89Q\xbf\xd7\xc18x\xd1\x00\x00\u07d4\xe5\xbc\u020c;%on\xd5\xfeU\x0eJ\x18\x19\x8b\x943V\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xbd\xf3OL\xccH>L\xa50\xcc|\xf2\xbb\x18\xfe\xbe\x92\xb3\x89\x06\xd85\xa1\v\xbc\xd2\x00\x00\u07d4\xe5\u0713I\xcbR\xe1a\x19a\"\u03c7\xa3\x896\xe2\xc5\u007f4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xe38\x00\xa1\xb2\xe9k\xde\x101c\n\x95\x9a\xa0\a\xf2nQ\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\xe3~\x19@\x8f,\xfb\xec\x834\x9d\u0501S\xa4\xa7\x95\xa0\x8f\x89\u3bb5sr@\xa0\x00\x00\u07d4\xe5\xed\xc7>bo]4A\xa4U9\xb5\xf7\xa3\x98\u0153\xed\xf6\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xe5\xed\xf8\x12?$\x03\xce\x1a\x02\x99\xbe\xcfz\xactM\a_#\x89\n\xdaUGK\x814\x00\x00\u07d4\xe5\xf8\xefm\x97\x066\xb0\u072aO \x0f\xfd\xc9\xe7Z\xf1t\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xfb1\xa5\xca\xeej\x96\xde9;\xdb\xf8\x9f\xbee\xfe\x12[\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xfb\xe3I\x84\xb67\x19o3\x1cg\x9d\f\fG\xd84\x10\xe1\x89llD\xfeG\xec\x05\x00\x00\u07d4\xe6\tU\xdc\v\xc1V\xf6\xc4\x18I\xf6\xbdwk\xa4K\x0e\xf0\xa1\x89\x10C\x16'\xa0\x93;\x00\x00\u07d4\xe6\nU\xf2\u07d9m\u00ee\xdbil\b\xdd\xe09\xb2d\x1d\xe8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6\x11[\x13\xf9y_~\x95e\x02\xd5\aEg\u06b9E\xcek\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xe6\x1f(\t\x15\xc7t\xa3\x1d\"<\xf8\f\x06\x92f\xe5\xad\xf1\x9b\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xe6/\x98e\a\x12\xeb\x15\x87S\xd8)r\xb8\u9723\xf6\x18w\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6/\x9d|d\xe8\xe2cZ\xeb\x88=\xd7;\xa6\x84\xee|\x10y\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe6>xt\x14\xb9\x04\x84x\xa5\a35\x9e\xcd\xd7\xe3dz\xa6\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe6FfXr\xe4\v\rz\xa2\xff\x82r\x9c\xaa\xba[\xc3\u8789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe6N\xf0\x12e\x8dT\xf8\xe8`\x9cN\x90#\xc0\x9f\xe8e\xc8;\x89\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\xe6On\x1dd\x01\xb5l\akd\xa1\xb0\x86}\v/1\rN\x89\x02\u02edq\xc5:\xe5\x00\x00\u07d4\xe6g\xf6R\xf9W\u008c\x0ef\u04364\x17\xc8\f\x8c\x9d\xb8x\x89 \x9d\x92/RY\xc5\x00\x00\xe0\x94\xe6w\xc3\x1f\xd9\xcbr\x00u\u0724\x9f\x1a\xbc\xcdY\xec3\xf74\x8a\x01\xa6\u05be\xb1\xd4.\xe0\x00\x00\u07d4\xe6|,\x16e\u02038h\x81\x87b\x9fI\xe9\x9b`\xb2\u04fa\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xe6\x9al\xdb:\x8a}\xb8\xe1\xf3\f\x8b\x84\xcds\xba\xe0+\xc0\xf8\x8a\x03\x94\xfd\xc2\xe4R\xf6q\x80\x00\u07d4\xe6\x9d\x1c7\x8bw\x1e\x0f\xef\xf0Q\xdbi\xd9f\xacgy\xf4\xed\x89\x1d\xfaj\xaa\x14\x97\x04\x00\x00\u07d4\xe6\x9f\xcc&\xed\"_{.7\x984\xc5$\xd7\f\x175\u5f09lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\xa3\x01\x0f\x02\x01\xbc\x94\xffg\xa2\xf6\x99\xdf\xc2\x06\xf9\xe7gB\x89/\xa7\xcb\xf6dd\x98\x00\x00\u07d4\xe6\xa6\xf6\xddop\xa4V\xf4\xec\x15\xefz\xd5\xe5\u06f6\x8b\xd7\u0709\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe6\xb2\x0f\x98\n\xd8S\xad\x04\xcb\xfc\x88|\xe6`\x1ck\xe0\xb2L\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u6cec?]M\xa5\xa8\x85}\v?0\xfcK+i+w\u05c9O%\x91\xf8\x96\xa6P\x00\x00\u07d4\xe6\xb9T_~\u0406\xe5R\x92F9\xf9\xa9\xed\xbb\xd5T\v>\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\xe0\x94\xe6\xbc\xd3\n\x8f\xa18\xc5\xd9\xe5\xf6\xc7\xd2\u0680i\x92\x81-\u034a7\x0e\xa0\xd4|\xf6\x1a\x80\x00\x00\u07d4\xe6\xc8\x1f\xfc\xec\xb4~\xcd\xc5\\\vq\xe4\x85_>^\x97\xfc\x1e\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4\xe6\xcb&\vqmL\n\xb7&\xee\xeb\a\xc8pr\x04\xe2v\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe6\xcb?1$\xc9\xc9\xcc84\xb1'K\xc33dV\xa3\x8b\xac\x89\x17+\x1d\xe0\xa2\x13\xff\x00\x00\xe0\x94\xe6\xd2\"\t\xff\u0438u\t\xad\xe3\xa8\xe2\xefB\x98y\u02c9\xb5\x8a\x03\xa7\xaa\x9e\x18\x99\xca0\x00\x00\u07d4\xe6\u051f\x86\xc2(\xf4sg\xa3^\x88l\xaa\xcb'\x1eS\x94)\x89\x16^\xc0\x9d\xa7\xa1\x98\x00\x00\u07d4\xe6\xe6!\xea\xab\x01\xf2\x0e\xf0\x83k|\xadGFL\xb5\xfd<\x96\x89\x11!\x93B\xaf\xa2K\x00\x00\u07d4\xe6\xe8\x861{jf\xa5\xb4\xf8\x1b\xf1d\xc58\xc2d5\x17e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\u98ddu\x0f\xe9\x949N\xb6\x82\x86\xe5\xeab\xa6\x99x\x82\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xe6\xec\\\xf0\u011b\x9c1~\x1epc\x15\uf7b7\xc0\xbf\x11\xa7\x8a\x03\xa4i\xf3F~\x8e\xc0\x00\x00\u07d4\xe6\xf5\xebd\x9a\xfb\x99Y\x9cAK'\xa9\xc9\xc8U5\u007f\xa8x\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xe6\xfe\n\xfb\x9d\xce\xdd7\xb2\xe2,E\x1b\xa6\xfe\xabg4\x803\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe7\x10\xdc\u041b\x81\x01\xf9C{\xd9}\xb9\ns\xef\x99=\v\xf4\x89\x14\xee6\xc0Z\xc2R\x00\x00\u07d4\xe7'\xe6~\xf9\x11\xb8\x1fl\xf9\xc7?\xcb\xfe\xbc+\x02\xb5\xbf\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7.\x1d3\\\u009a\x96\xb9\xb1\xc0/\x00:\x16\xd9q\xe9\v\x9d\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe71\x1c\x953\xf0\t,rH\xc9s\x9b[,\x86J4\xb1\u0389\x97\xf9}l\xc2m\xfe\x00\x00\u07d4\xe7;\xfe\xad\xa6\xf0\xfd\x01o\xbc\x84>\xbc\xf6\xe3p\xa6[\xe7\f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xe7<\xcfCg%\xc1Q\xe2U\xcc\xf5!\f\xfc\xe5\xa4?\x13\xe3\x89\x01\x15NS!}\xdb\x00\x00\u07d4\xe7B\xb1\xe6\x06\x9a\x8f\xfc'\f\xc6\x1f\xa1d\xac\x15SE\\\x10]\x04\x88~\x14\x89\x06\x96\xd8Y\x00 \xbb\x00\x00\u07d4\xe7\\\x1f\xb1w\b\x9f>X\xb1\x06y5\xa6Yn\xf1s\u007f\xb5\x89\x05j\x87\x9f\xa7uG\x00\x00\u07d4\xe7\\;8\xa5\x8a?3\xd5V\x90\xa5\xa5\x97f\xbe\x18^\x02\x84\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7a\xd2\u007f\xa3P,\xc7k\xb1\xa6\bt\x0e\x14\x03\u03dd\xfci\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe7f\xf3O\xf1o<\xfc\xc9s!r\x1fC\xdd\xf5\xa3\x8b\f\xf4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xe7m\x94Z\xa8\x9d\xf1\xe4W\xaa4+1\x02\x8a^\x910\xb2\u03897\b\xba\xed=h\x90\x00\x00\u07d4\xe7s^\xc7e\x18\xfcj\xa9-\xa8qZ\x9e\xe3\xf6%x\x8f\x13\x89lM\x16\v\xaf\xa1\xb7\x80\x00\xe0\x94\xe7z\x89\xbdE\xdc\x04\xee\xb4\xe4\x1d{Ykp~nQ\xe7L\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xe7}}\uac96\u0234\xfa\a\xca;\xe1\x84\x16=Zm`l\x89\x05\x049\x04\xb6q\x19\x00\x00\u07d4\xe7\u007f\xeb\xab\xdf\b\x0f\x0f]\xca\x1d?Wf\xf2\xa7\x9c\x0f\xfa|\x89K\"\x9d(\xa8Ch\x00\x00\xe0\x94\u7025c\x06\xba\x1ek\xb31\x95,\"S\x9b\x85\x8a\xf9\xf7}\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xe7\x81\xecs-@\x12\x02\xbb\x9b\xd18`\x91\r\xd6\u009a\xc0\xb6\x89C8t\xf62\xcc`\x00\x00\u07d4\xe7\x84\xdc\xc8s\xaa\x8c\x15\x13\xec&\xff6\xbc\x92\xea\xc6\xd4\xc9h\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\x91-L\xf4V,W=\xdc[q\xe3s\x10\xe3x\xef\x86\u0249\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xe7\x91\u0545\xb8\x996\xb2])\x8f\x9d5\xf9\xf9\xed\xc2Z)2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\x924\x9c\xe9\xf6\xf1O\x81\xd0g@\x96\xbe\xfa\x1f\x92!\xcd\xea\x89[]#J\r\xb48\x80\x00\u07d4\xe7\x96\xfdN\x83\x9bL\x95\xd7Q\x0f\xb7\xc5\xc7+\x83\xc6\xc3\xe3\u01c9\x1b\xc43\xf2?\x83\x14\x00\x00\xe0\x94\xe7\xa4/Y\xfe\xe0t\xe4\xfb\x13\xea\x9eW\xec\xf1\xccH(\"I\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xe7\xa4V\f\x84\xb2\x0e\x0f\xb5LIg\f)\x03\xb0\xa9lB\xa4\x89 j\xea\u01e9\x03\x98\x00\x00\u07d4\xe7\xa8\xe4q\xea\xfby\x8fET\xccnRg0\xfdV\xe6,}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u7f82\xc6Y<\x1e\xed\xdd*\xe0\xb1P\x01\xff \x1a\xb5{/\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4\xe7\u01b5\xfc\x05\xfct\x8e[C\x81rdI\xa1\xc0\xad\x0f\xb0\xf1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\xd1u$\xd0\v\xad\x82I|\x0f'\x15jd\u007f\xf5\x1d'\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe7\xd2\x13\x94\u007f\u02d0J\xd78H\v\x1e\xed/\\2\x9f'\xe8\x89\x01\x03\u00f1\xd3\xe9\xc3\x00\x00\u07d4\xe7\xd6$\x06 \xf4,^\u06f2\xed\xe6\xae\xc4=\xa4\xed\x9bWW\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xda`\x9d@\xcd\xe8\x0f\x00\xce[O\xfbj\xa9\u04304\x94\xfc\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xf0oi\x9b\xe3\x1cD\vC\xb4\xdb\x05\x01\xec\x0e%&\x16D\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7\xf4\xd7\xfeoV\x1f\u007f\xa1\xda0\x05\xfd6TQ\xad\x89\u07c9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\xfd\x8f\xd9Y\xae\xd2v~\xa7\xfa\x96\f\xe1\xdbS\xaf\x80%s\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe8\x0e\u007f\xef\x18\xa5\xdb\x15\xb0\x14s\xf3\xadkx\xb2\xa2\xf8\xac\u0649\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe8\x13\u007f\xc1\xb2\xec|\xc7\x10:\xf9!\x89\x9bJ9\xe1\xd9Y\xa1\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xe8\x1c-4l\n\xdfL\xc5g\b\xf69K\xa6\xc8\u0226J\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8,X\xc5yC\x1bg5F\xb5:\x86E\x9a\xca\xf1\u079b\x93\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe84\xc6C\x18 \\\xa7\xddJ!\xab\xcb\b&l\xb2\x1f\xf0,\x8965\xc6 G9\u0640\x00\u07d4\xe86\x04\xe4\xffk\xe7\xf9o`\x18\xd3\xec0r\xecR]\xffk\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\xe0\x94\xe8E\xe3\x87\xc4\xcb\u07d8\"\x80\xf6\xaa\x01\xc4\x0eK\xe9X\u0772\x8a\x05K@\xb1\xf8R\xbd\xa0\x00\x00\u07d4\xe8H\xca~\xbf\xf5\xc2O\x9b\x9c1g\x97\xa4;\xf7\xc3V)-\x89\x06.\x11\\\x00\x8a\x88\x00\x00\u07d4\xe8KU\xb5%\xf1\x03\x9etK\x91\x8c\xb33$\x92\xe4^\xcaz\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe8O\x80v\xa0\xf2\x96\x9e\xcd3>\xef\x8d\xe4\x10B\x98b\x91\xf2\x89\x17k4O*x\xc0\x00\x00\u07d4\xe8d\xfe\xc0~\xd1!Je1\x1e\x11\xe3)\xde\x04\r\x04\xf0\xfd\x89Y\u0283\xf5\xc4\x04\x96\x80\x00\u07d4\xe8}\xba\xc66\xa3w!\xdfT\xb0\x8a2\xefIY\xb5\xe4\xff\x82\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe8~\x9b\xbf\xbb\xb7\x1c\x1at\ft\xc7#Bm\xf5]\x06=\u064a\x01\xb1\x92\x8c\x00\u01e68\x00\x00\u07d4\xe8~\xacm`+A\t\xc9g\x1b\xf5{\x95\f,\xfd\xb9\x9dU\x89\x02\xb4\xf2\x19r\xec\xce\x00\x00\xe0\x94\u807b\xbeir-\x81\xef\xec\xaaH\u0455*\x10\xa2\xbf\xac\x8f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xe8\x92Is\x8b~\xce\xd7\xcbfjf\xe4s\xbcv\x82/U\t\x8d\x89\xb9\x1c\u0149lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xc3\u04f0\xe1\u007f\x97\xd1\xe7V\xe6\x84\xf9N\x14p\xf9\x9c\x95\xa1\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xe8\xc3\xf0E\xbb}8\xc9\xd2\U000d5c3a\x84\x92\xb2S#\t\x01\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4\xe8\xccC\xbcO\x8a\xcf9\xbf\xf0N\xbf\xbfB\xaa\xc0j2\x84p\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe8\xd9B\xd8/\x17^\xcb\x1c\x16\xa4\x05\xb1\x01C\xb3\xf4k\x96:\x89\x1e\xd2\xe8\xffm\x97\x1c\x00\x00\u07d4\xe8\u077e\xd72\xeb\xfeu@\x96\xfd\xe9\bk\x8e\xa4\xa4\xcd\xc6\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xder^\xca]\xef\x80_\xf7\x94\x1d1\xac\x1c.4-\xfe\x95\x89\x85~\ro\x1d\xa7j\x00\x00\u07d4\xe8\xe9\x85\x05\x86\xe9OR\x99\xabIK\xb8!\xa5\xf4\f\x00\xbd\x04\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xe8\xea\u047b\x90\xcc\u00ee\xa2\xb0\xdc\u0175\x80VUFU\xd1\u054a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\u07d4\xe8\xea\xf1)D\t-\xc3Y\x9b9S\xfa|\xb1\xc9v\x1c\xc2F\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xe8\xedQ\xbb\xb3\xac\xe6\x9e\x06\x02K3\xf8hD\xc4sH\u06de\x8a\"\xf9\xea\x89\xf4\xa7\xd6\xc4\x00\x00\u07d4\xe8\xef\x10\r|\xe0\x89X2\xf2g\x8d\xf7-J\u03cc(\xb8\xe3\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xe8\xf2\x99i\xe7\\e\xe0\x1c\xe3\xd8aT }\n\x9e|v\xf2\x89\xa2/\xa9\xa7:'\x19\x80\x00\u07d4\xe8\xfc6\xb0\x13\x1e\xc1 \xac\x9e\x85\xaf\xc1\f\xe7\vV\u0636\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9\n5L\xec\x04\u059e]\x96\xdd\xc0\xc5\x13\x8d=3\x15\n\xa0\x89\x1b\x1a}\u03caD\u04c0\x00\xe0\x94\xe9\x13>}1\x84]_+f\xa2a\x87\x92\xe8i1\x1a\xcff\x8a\x05\x17\xc0\xcb\xf9\xa3\x90\x88\x00\x00\u07d4\xe9\x1d\xac\x01\x95\xb1\x9e7\xb5\x9bS\xf7\xc0\x17\xc0\xb29[\xa4L\x89e\xea=\xb7UF`\x00\x00\u07d4\xe9\x1f\xa0\xba\xda\u0779\xa9~\x88\xd3\xf4\xdb|U\u05bbt0\xfe\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xe9#\xc0aw\xb3B~\xa4H\xc0\xa6\xff\x01\x9bT\xccT\x8d\x95\x89\x01\xf7\x80\x01Fg\xf2\x80\x00\xe0\x94\xe9=G\xa8\u0288]T\fNRo%\xd5\xc6\xf2\xc1\b\u0138\x8a\x17\xda:\x04\u01f3\xe0\x00\x00\x00\u07d4\xe9E\x8fh\xbb',\xb5g:\x04\xf7\x81\xb4\x03Uo\u04e3\x87\x89\x03N\x8b\x88\xce\xe2\xd4\x00\x00\u07d4\xe9IA\xb6\x03`\x19\xb4\x01j0\xc1\x03}Zi\x03\xba\xba\xad\x89*H\xac\xabb\x04\xb0\x00\x00\u07d4\xe9I[\xa5\x84'(\xc0\ud5fe7\xd0\xe4\"\xb9\x8di ,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe9M\xed\x99\u0735r\xb9\xbb\x1d\u02e3/m\xee\x91\xe0W\x98N\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\xe0\x94\xe9QyR}\uc951l\xa9\xa3\x8f!\\\x1e\x9c\xe77\xb4\u024a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xe9U\x91\x85\xf1f\xfc\x95\x13\xccq\x11aD\xce-\xeb\x0f\x1dK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xe9^\x92\xbb\xc6\xde\a\xbf:f\x0e\xbf_\xeb\x1c\x8a5'\xe1\u0148\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xe9e\u06a3@9\xf7\xf0\xdfb7Z7\u5acar\xb3\x01\xe7\x8a\x01\x03\xfd\xde\u0373\xf5p\x00\x00\u07d4\xe9i\xea\x15\x95\xed\xc5\u0127\a\xcf\xde8\t)c2Q\xa2\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9k\x18N\x1f\x0fT\x92J\xc8t\xf6\v\xbfDptF\xb7+\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\xe0\x94\xe9m}L\xdd\x15U:NM1mmd\x80\xca<\xea\x1e8\x8a\x02\x95]\x02\xe1\xa15\xa0\x00\x00\u07d4\xe9n-8\x13\xef\xd1\x16_\x12\xf6\x02\xf9\u007fJb\x90\x9d\x1b;\xc0\xe9\xaa\"\u007f\x90\x89'\xcaK\xd7\x19\xf0\xb8\x00\x00\u07d4\xea,\x19}&\xe9\x8b\r\xa8>\x1br\u01c7a\x8c\x97\x9d=\xb0\x89\x01\x11du\x9f\xfb2\x00\x00\xe0\x94\xea7y\xd1J\x13\xf6\u01c5f\xbc\xde@5\x91A:b9\u06ca)\xb7d2\xb9DQ \x00\x00\u07d4\xeaN\x80\x9e&j\xe5\xf1<\xdb\u33dd\x04V\xe68m\x12t\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\xe0\x94\xeaS\xc9T\xf4\xed\x97\xfdH\x10\x11\x1b\u06b6\x9e\xf9\x81\xef%\xb9\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xeaS\xd2ed\x85\x9d\x9e\x90\xbb\x0eS\xb7\xab\xf5`\xe0\x16,8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xea`Ci\x12\xdek\xf1\x87\u04e4r\xff\x8fS3\xa0\xf7\xed\x06\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xea`T\x9e\xc7U?Q\x1d!I\xf2\xd4fl\xbd\x92C\xd9<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeaf\xe7\xb8M\u037f6\xee\xa3\xe7[\x858*u\xf1\xa1]\x96\x89]\xbc\x91\x91&o\x11\x80\x00\u07d4\xeahlPW\t<\x17\x1cf\u06d9\xe0\x1b\x0e\xce\xcb0\x86\x83\x89\x14\u0768],\xe1G\x80\x00\u07d4\xeaj\xfe,\xc9(\xac\x83\x91\xeb\x1e\x16_\xc4\x00@\xe3t!\u7262\u007f\xa0c\xb2\xe2\xe6\x80\x00\u07d4\xeay\x05}\xab\xef^d\xe7\xb4O\u007f\x18d\x8e~S7\x18\u0489\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xea|Mm\xc7)\xcdk\x15|\x03\xad#|\xa1\x9a \x93F\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\x81h\xfb\xf2%\xe7\x86E\x9c\xa6\xbb\x18\xd9c\xd2kPS\t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xea\x81\u02868T\f\xd9\xd4\xd7=\x06\x0f,\xeb\xf2$\x1f\xfc>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xea\x83\x17\x19yYB@A\xd9\xd7\xc6z>\xce\x1d\xbbx\xbbU\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xea\x85'\xfe\xbf\xa1\xad\xe2\x9e&A\x93)\u04d3\xb9@\xbb\xb7\u0709lj\xccg\u05f1\xd4\x00\x00\u07d4\xea\x8f0\xb6\xe4\xc5\xe6R\x90\xfb\x98d%\x9b\u0159\x0f\xa8\ue289\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\x94\xf3(\b\xa2\uf29b\xf0\x86\x1d\x1d$\x04\xf7\xb7\xbe%\x8a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\xa4\\\xea\x02\xd8},\xc8\xfd\xa9CN-\x98[\xd4\x03\x15\x84\x89h\x1f\xc2\xccn+\x8b\x00\x00\xe0\x94\uac3d\x14\x83\t\x18l\xf8\xcb\xd1;r2\xd8\tZ\u02c3:\x8a\x02C\x9a\x88\x1cjq|\x00\x00\u07d4\uaed0\xd3y\x89\xaa\xb3\x1f\xea\xe5G\xe0\xe6\xf3\x99\x9c\xe6\xa3]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xc0\x82~\xff\fn?\xf2\x8a}JT\xf6\\\xb7h\x9d{\x99\x89\x9a\xd9\u67ddGR\x00\x00\u07d4\xea\xc1H(&\xac\xb6\x11\x1e\x19\xd3@\xa4_\xb8QWk\xed`\x89\x01\xbe\x8b\xab\x04\u067e\x80\x00\xe0\x94\xea\xc1{\x81\xedQ\x91\xfb\b\x02\xaaT3s\x13\x83A\a\xaa\xa4\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xea\u00efW\x84\x92\u007f\u9958\xfcN\xec8\xb8\x10/7\xbcX\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xea\u01b9\x88BT.\xa1\v\xb7O&\xd7\xc7H\x8fi\x8bdR\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xea\xc7h\xbf\x14\xb8\xf9C.i\xea\xa8*\x99\xfb\xeb\x94\xcd\f\x9c\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xea\xd2\x1c\x1d\xec\u03ff\x1c\\\xd9f\x88\xa2Gki\xba\a\xceJ\x89\x03\xf2M\x8eJ\x00p\x00\x00\u07d4\xea\xd4\xd2\xee\xfbv\xab\xaeU3\x96\x1e\xdd\x11@\x04\x06\xb2\x98\xfc\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xea\xd6Rb\xed]\x12-\xf2\xb2u\x14\x10\xf9\x8c2\xd1#\x8fQ\x89\x05\x83\x17\xedF\xb9\xb8\x00\x00\u07d4\xea\xd7P\x16\u3801Pr\xb6\xb1\b\xbc\xc1\xb7\x99\xac\xf08>\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xea#\xaa\x05r\x00\xe7\xc9\xc1^\x8f\xf1\x90\xd0\xe6l\f\x0e\x83\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xed\x16\xea\xf5\u06ab[\xf0)^^\a\u007fY\xfb\x82U\x90\v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xea\xed\xcck\x8bib\xd5\xd9(\x8c\x15lW\x9dG\xc0\xa9\xfc\xff\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xea\xf5#\x88Tn\xc3Z\xcaolc\x93\xd8\xd6\t\xde:K\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xeb\x10E\x8d\xac\xa7\x9eJk$\xb2\x9a\x8a\x8a\xdaq\x1b\u007f.\xb6\x89\u063beI\xb0+\xb8\x00\x00\u07d4\xeb\x1c\xea{E\u047dM\x0e*\x00{\u04ff\xb3Tu\x9e,\x16\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xeb%H\x1f\u035c\"\x1f\x1a\xc7\xe5\xfd\x1e\u0353\a\xa1b\x15\xb8\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\xeb.\xf3\u04cf\xe6R@<\xd4\xc9\xd8^\xd7\xf0h,\xd7\xc2\u078a\t\x0fSF\b\xa7(\x80\x00\x00\xe0\x94\xeb;\xddY\xdc\u0765\xa9\xbb*\xc1d\x1f\xd0!\x80\xf5\xf3e`\x8a\x01e\xc9fG\xb3\x8a \x00\x00\u07d4\xeb<\xe7\xfc8\x1cQ\xdb}_\xbdi/\x8f\x9e\x05\x8aLp=\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xebE?Z:\xdd\u074a\xb5gP\xfa\xdb\x0f\xe7\xf9M\x9c\x89\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xebO\x00\xe2\x836\xea\t\x94%\x88\ueb12\x18\x11\xc5\"\x14<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebR\xab\x10U4\x922\x9c\x1cT\x83:\xe6\x10\xf3\x98\xa6[\x9d\x89\b=lz\xabc`\x00\x00\u07d4\xebW\r\xba\x97R'\xb1\xc4-n\x8d\xea,V\u026d\x96\x06p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebc\x94\xa7\xbf\xa4\u0489\x11\u0565\xb2>\x93\xf3^4\f\"\x94\x89\x04:w\xaa\xbd\x00x\x00\x00\u07d4\xebh\x10i\x1d\x1a\xe0\u045eG\xbd\"\u03be\u0cfa'\xf8\x8a\x89\x87\x85c\x15\xd8x\x15\x00\x00\u07d4\xebvBL\x0f\u0557\xd3\xe3A\xa9d*\xd1\xee\x11\x8b+W\x9d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb| +F+|\u0145]t\x84u_n&\xefC\xa1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\x83\\\x1a\x91\x18\x17\x87\x8a3\xd1gV\x9e\xa3\xcd\u04c7\xf3(\x8965\u026d\xc5\u07a0\x00\x00\u07d4\ub268\x82g\t\t\xcf7~\x9ex(n\xe9{\xa7\x8dF\u0089+|\xc2\xe9\xc3\"\\\x00\x00\xe0\x94\xeb\x90\u01d3\xb3S\x97a\xe1\xc8\x14\xa2\x96q\x14\x86\x92\x19>\xb4\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xeb\x9c\xc9\xfe\bi\xd2\u06b5,\u01ea\xe8\xfdW\xad\xb3_\x9f\xeb\x89j\x93\xbb\x17\xaf\x81\xf8\x00\x00\xe0\x94\ub8c8\xb0\xda'\xc8{\x1c\xc0\xea\xc6\xc5{,Z\vE\x9c\x1a\x8a\x01p\xa0\xf5\x04\x0eP@\x00\x00\u07d4\xeb\xaa!m\xe9\xccZC\x03\x17\a\xd3o\xe6\u057e\xdc\x05\xbd\xf0\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xeb\xac+D\b\xefT1\xa1;\x85\b\xe8bP\x98!\x14\xe1E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb\xb6,\xf8\xe2,\x88K\x1b(\xc6\xfa\x88\xfb\xbc\x17\x93\x8a\xa7\x87\x89+By\x84\x03\u0278\x00\x00\u07d4\xeb\xb7\xd2\xe1\x1b\u01b5\x8f\n\x8dE\xc2\xf6\xde0\x10W\n\u0211\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4\xeb\xbbO,=\xa8\xbe>\xb6-\x1f\xfb\x1f\x95\x02a\u03d8\xec\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\xbdM\xb9\x01\x99R\u058b\x1b\x0fm\x8c\xf0h<\x008{\xb5\x89\x12\x04\x01V=}\x91\x00\x00\u07d4\xeb\xbe\xeb%\x91\x84\xa6\xe0\x1c\xcc\xfc\"\a\xbb\u0603xZ\xc9\n\x89!\x9b\xc1\xb0G\x83\xd3\x00\x00\u07d4\xeb\xd3V\x15j81#4=H\x84;\xff\xeda\x03\xe8f\xb3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xeb\xd3{%ec\xe3\fo\x92\x89\xa8\xe2p/\bR\x88\b3\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xeb\xe4l\xc3\xc3L2\xf5\xad\xd6\xc3\x19[\xb4\x86\xc4q>\xb9\x18\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xeb\xff\x84\xbb\xefB0q\xe6\x04\xc3a\xbb\xa6w\xf5Y=\xefN\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xec\t'\xba\xc7\xdc6f\x9c(5J\xb1\xbe\x83\xd7\xee\xc3\t4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\x0e\x18\xa0\x1d\xc4\xdc]\xaa\xe5g\xc3\xfaL\u007f\x8f\x9bY\x02\x05\x89\x11\x1f\xfe@JA\xe6\x00\x00\xe0\x94\xec\x116,\xec\x81\t\x85\xd0\xeb\xbd{sE\x14D\x98[6\x9f\x8a\x06ZNIWpW1\x80\x00\u07d4\xec,\xb8\xb97\x8d\xff1\xae\xc3\xc2.\x0em\xad\xff1J\xb5\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xec0\xad\u0749[\x82\xee1\x9eT\xfb\x04\xcb+\xb09q\xf3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec;\x8bX\xa1'\x03\xe5\x81\xce_\xfd~!\xc5}\x1e\\f?\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xecHg\xd2\x17Z\xb5\xb9F\x93aYUFUF\x84\u0364`\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xecM\b\xaa.GIm\u0287\"]\xe3?+@\xa8\xa5\xb3o\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\xecX\xbc\r\f \xd8\xf4\x94efAS\xc5\xc1\x96\xfeY\u6f89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xec[\x19\x8a\x00\u03f5Z\x97\xb5\xd56D\xcf\xfa\x8a\x04\u04abE\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec]\xf2'\xbf\xa8]z\xd7kBn\x1c\xee\x96;\xc7\xf5\x19\u074965\u026d\xc5\u07a0\x00\x00\xe0\x94\xec_\xea\xfe!\f\x12\xbf\u0265\xd0Y%\xa1#\xf1\xe7?\xbe\xf8\x8a`\x8f\xcf=\x88t\x8d\x00\x00\x00\u07d4\xeci\x04\xba\xe1\xf6\x97\x90Y\x17\t\xb0`\x97\x83s?%s\xe3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xecs\x11L^@o\u06fe\t\xb4\xfab\x1b\xd7\x0e\xd5N\xa1\xef\x8a\x050%\xcd!o\xceP\x00\x00\u07d4\xecs\x83=\xe4\xb8\x10\xbb\x02x\x10\xfc\x8fi\xf5D\xe8<\x12\u044965\u026d\xc5\u07a0\x00\x00\u07d4\xecu\xb4\xa4u\x13\x12\v\xa5\xf8`9\x81O\x19\x98\xe3\x81z\u00c9\t\xb0\xbc\xe2\xe8\xfd\xba\x00\x00\u07d4\xecv\xf1.W\xa6U\x04\x03?,\v\xceo\xc0;\xd7\xfa\n\u0109\xc2\x12z\xf8X\xdap\x00\x00\u0794\xec\x80\x14\xef\xc7\xcb\xe5\xb0\xceP\xf3V,\xf4\xe6\u007f\x85\x93\xcd2\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xec\x82\xf5\r\x06G_hM\xf1\xb3\x92\xe0\r\xa3A\xaa\x14TD\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xec\x83\xe7\x98\u00d6\xb7\xa5^*\"$\xab\u0343K'\xeaE\x9c\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\x89\xf2\xb6x\xa1\xa1[\x914\xec^\xb7\fjb\a\x1f\xba\xf9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\x8c\x1d{j\xac\xcdB\x9d\xb3\xa9\x1e\xe4\xc9\xeb\x1c\xa4\xf6\xf7<\x89\xe6d\x99\"\x88\xf2(\x00\x00\xe0\x94\xec\x98Q\xbd\x91rpa\x02g\xd6\x05\x18\xb5M<\xa2\xb3[\x17\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xec\x99\xe9]\xec\xe4o\xff\xfb\x17^\xb6@\x0f\xbe\xbb\b\ue6d5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xec\xa5\xf5\x87\x92\xb8\xc6-*\xf5Vq~\xe3\xee0(\xbeM\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xabZ\xba[\x82\x8d\xe1pS\x81\xf3\x8b\xc7D\xb3+\xa1\xb47\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\xec\xaf3P\xb7\xce\x14M\x06\x8b\x18`\x10\x85,\x84\xdd\f\xe0\xf0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xb9LV\x8b\xfeY\xad\xe6Pd_O&0lsl\xac\xe4\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xec\xbeB^g\r9\tN \xfbVC\xa9\xd8\x18\xee\xd26\u078a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xec\xbe^\x1c\x9a\u04b1\xdc\xcf\n0_\xc9R/Fi\xdd:\xe7\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xec\xcfz\x04W\xb5f\xb3F\xcag:\x18\x0fDA0!j\u00c9\x05k\xc7^-c\x10\x00\x00\u07d4\xec\u0466(\x025\x1aAV\x8d#\x030\x04\xac\xc6\xc0\x05\xa5\u04c9\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xec\xd2v\xafd\u01dd\x1b\u0669+\x86\xb5\u835a\x95\xeb\x88\xf8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xec\u0506\xfc\x19g\x91\xb9,\xf6\x12\xd3HaO\x91VH\x8b~\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\xda\xf92)\xb4^\xe6r\xf6]\xb5\x06\xfb^\xca\x00\xf7\xfc\xe6\x89W\x01\xf9m\xcc@\xee\x80\x00\u07d4\xec\xe1\x11g\vV<\u037e\xbc\xa5#\x84)\x0e\xcdh\xfe\\\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xec\xe1\x15&\x82\xb7Y\x8f\xe2\xd1\xe2\x1e\xc1U3\x88T5\xac\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xec\xe1)\bw\xb5\x83\xe3a\xa2\xd4\x1b\x00\x93F\xe6'N%8\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xec\xf0]\a\xea\x02n~\xbfIA\x00#5\xba\xf2\xfe\xd0\xf0\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\xf2L\xdd|\"\x92\x8cD\x1eiM\xe4\xaa1\xb0\xfa\xb5\x97x\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xec\xfd\x00M\x02\xf3l\xd4\u0634\xa8\xc1\xa9S;j\xf8\\\xd7\x16\x8a\x01\x0fA\xac\xb4\xbb;\x9c\x00\x00\xe0\x94\xed\x02\x06\xcb#1Q(\xf8\xca\xff&\xf6\xa3\v\x98Tg\xd0\"\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xed\x10e\xdb\u03dds\xc0O\xfcy\b\x87\r\x88\x14h\xc1\xe12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xed\x12vQ;o\u0186(\xa7A\x85\xc2\xe2\f\xbb\xcax\x17\xbf\x89\nZ\xa8P\t\xe3\x9c\x00\x00\xe0\x94\xed\x12\xa1\xba\x1f\xb8\xad\xfc\xb2\r\xfa\x19X.RZ\xa3\xb7E$\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xed\x16\xce9\xfe\xef;\xd7\xf5\xd1b\x04^\x0fg\xc0\xf0\x00F\xbb\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xed\x1a\\C\xc5t\xd4\xe94)\x9b$\xf1G,\u071f\xd6\xf0\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xed\x1b$\xb6\x91-Q\xb34\xac\r\xe6\xe7q\xc7\xc0EF\x95\xea\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xed\x1f\x1e\x11Z\r`\xce\x02\xfb%\xdf\x01M(\x9e:\f\xbe}\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xed10\\1\x9f\x92s\u04d3m\x8f[/q\u9c72)c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xed2z\x14\xd5\u03ed\u0641\x03\xfc\t\x99q\x8d~\xd7\x05(\xea\x89N\x10\x03\xb2\x8d\x92\x80\x00\x00\u07d4\xed<\xbc7\x82\u03bdg\x98\x9b0\\A3\xb2\xcd\xe3\"\x11\xeb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xed@\x14S\x8c\xeefJ/\xbc\xb6\xdcf\x9fz\xb1m\v\xa5|\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedA\u188f\\\xaa\x848\x80\xefN\x8b\b\xbdl3\x14\x1e\u07c9*\xd5\xdd\xfaz\x8d\x83\x00\x00\xe0\x94\xedK\xe0J\x05-z\u0333\xdc\u03901\x9d\xba@ \xab,h\x8a\a\xf3zp\xea\xf3b\x17\x80\x00\xe0\x94\xedR\xa2\xcc\bi\u071e\x9f\x84+\u0415|G\xa8\xe9\xb0\xc9\xff\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xed[LA\xe7b\xd9B@Cs\xca\xf2\x1e\xd4a]%\xe6\xc1\x89m-O=\x95%\xb4\x00\x00\u07d4\xed`\u012bnT\x02\x061~5\x94zc\xa9\xcak\x03\xe2\u02c9\x03\x1a\u066d\vF\u007f\x80\x00\u07d4\xedd\x1e\x066\x8f\xb0\xef\xaa\x17\x03\xe0\x1f\xe4\x8fJhS\t\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedfC\xc0\xe8\x88K-2\x11\x857\x85\xa0\x8b\xf8\xf3>\u049f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xedp\xa3|\xdd\x1c\xbd\xa9tm\x93\x96X\xae*a\x81(\x85x\x8a\x02\bj\xc3Q\x05&\x00\x00\x00\u07d4\xedsFvn\x1agm\r\x06\xec\x82\x18g\xa2v\xa0\x83\xbf1\x89\u064a\t1\xcc-I\x00\x00\u07d4\xed\x86&\x16\xfc\xbf\xb3\xbe\xcbt\x06\xf7<\\\xbf\xf0\f\x94\aU\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xed\x9e\x03\f\xa7\\\xb1\u049e\xa0\x1d\rL\xdf\xdc\xcd8D\xb6\xe4\x89\x01\xac\xc1\x16\u03ef\xb1\x80\x00\xe0\x94\ud7bc\u02e4/\x98\x15\xe7\x823&m\xd6\xe85\xb6\xaf\xc3\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\ud7f1\xf5\xaf/\xbf\u007f\xfcP)\xce\xe4+p\xff\\'[\xf5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xed\xa4\xb2\xfaY\u0584\xb2z\x81\r\xf8\x97\x8as\xdf0\x8ac\u0089\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xed\xb4s59y\xa2\x06\x87\x9d\xe1D\xc1\n:\xcf\x12\xa7'OV9a\xf57R\x9d\x89\xc7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xeer\x88\xd9\x10\x86\xd9\xe2\xeb\x91\x00\x14\u066b\x90\xa0-x\u00a0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xee|=\xed|(\xf4Y\xc9/\xe1;M\x95\xba\xfb\xab\x026}\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\xee\x86} \x91k\xd2\xe9\xc9\xec\xe0\x8a\xa0C\x85\xdbf|\x91.\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\ue25b\x02\xcb\xcb99\xcda\xde\x13B\xd5\x04\x82\xab\xb6\x852\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xee\x90m}_\x17H%\x81t\xbeL\xbc8\x93\x03\x02\xab{B\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\ue5ea\x8a\u019e\xdfz\x98}mp\x97\x9f\x8e\xc1\xfb\xcaz\x94\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xee\xa1\xe9y\x88\xdeu\xd8!\xcd(\xadh\"\xb2,\u0398\x8b1\x89\x1c0s\x1c\xec\x03 \x00\x00\xe0\x94\xee\u048c?\x06\x8e\tJ0K\x85<\x95\nh\t\xeb\xcb\x03\xe0\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xee\u04c4\xef-A\xd9\xd2\x03\x97NW\xc1#(\xeav\x0e\b\xea\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xdflB\x80\xe6\xeb\x05\xb94\xac\xe4(\xe1\x1dB1\xb5\x90[\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xe7a\x84~3\xfda\u0653\x87\xee\x14b\x86\x94\u047f\xd5%\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xee\xe9\xd0Rn\xda\x01\xe41\x16\xa3\x952-\u0689pW\x8f9\x8a\x02\x1e\x19\x99\xbb\xd5\u04be\x00\x00\u07d4\xee\xf1\xbb\xb1\xe5\xa8?\u0782H\xf8\x8e\xe3\x01\x8a\xfa-\x132\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xfb\xa1-\xfc\x99gB\xdby\x04d\xca}';\xe6\xe8\x1b>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xfd\x05\xb0\xe3\xc4\x17\xd5[3C\x06\x04\x86\xcd\xd5\xe9*\xa7\xa6\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xef\r\xc7\xddzS\xd6\x12r\x8b\xcb\u04b2|\x19\xddM}fo\x89&A\x1c[5\xf0Z\x00\x00\u07d4\xef\x11RR\xb1\xb8E\u0345\u007f\x00-c\x0f\x1bo\xa3zNP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xef\x1c\x04w\xf1\x18M`\xac\u02b3t\xd3tUz\n>\x10\xf3\x89\b=lz\xabc`\x00\x00\u07d4\xef,4\xbbH}7b\xc3\u0327\x82\xcc\xddz\x8f\xbb\n\x991\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xef5\xf6\u0531\a^j\xa19\x15\x1c\x97K/FX\xf7\x058\x89<;\xc3?\x94\xe5\r\x80\x00\u07d4\xef9\u0291s\xdf\x15S\x1ds\xe6\xb7*hKQ\xba\x0f+\xb4\x89V\xa0\xb4un\xe28\x00\x00\u07d4\xefF<&y\xfb'\x91d\xe2\f=&\x915\x87s\xa0\xad\x95\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xefG\xcf\a>6\xf2q\xd5\"\xd7\xfaNq \xadP\a\xa0\xbc\x89\x87\x86x2n\xac\x90\x00\x00\u07d4\xefa\x15[\xa0\t\xdc\u07be\xf1\v(\xd9\xda=\x1b\xc6\xc9\xce\u0509\x034-`\xdf\xf1\x96\x00\x00\u0794\xefix\x1f2\xff\xce34o,\x9a\xe3\xf0\x84\x93\xf3\xe8/\x89\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xefv\xa4\u034f\xeb\xcb\u0278\x18\xf1x(\xf8\xd94s\xf3\xf3\u02c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\uf4c1\x8fhM\xb0\xc3g^\xc8\x132\xb3\x18>\xcc(\xa4\x95\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94\xef\x9fY\xae\xdaA\x8c\x14\x94h-\x94\x1a\xabI$\xb5\xf4\x92\x9a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\uf9b1\xf0\xdb`57\x82h\x91\xb8\xb4\xbc\x169\x84\xbb@\u03495e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xef\xbdR\xf9}\xa5\xfd:g:F\xcb\xf30D{~\x8a\xad\\\x89\x05l<\x9b\x80\xa0\xa6\x80\x00\xe0\x94\xef\xc8\xcf\x19c\u0269Rg\xb2(\xc0\x86#\x98\x89\xf4\xdf\xd4g\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xef\u02ae\x9f\xf6M,\xd9[RI\xdc\xff\xe7\xfa\xa0\xa0\xc0\xe4M\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xef\xcc\xe0k\xd6\b\x9d\x0eE\x8e\xf5a\xf5\xa6\x89H\n\xfep\x00\x89 \x86\xac5\x10R`\x00\x00\u07d4\xef\xe0g]\xa9\x8a]\xdap\u0356\x19k\x87\xf4\xe7&\xb43H\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xef\xe8\xff\x87\xfc&\x0e\agc\x8d\xd5\xd0/\xc4g.\x0e\xc0m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xeb\x19\x97\xaa\xd2w\xcc3C\x0ea\x11\xed\tCY@H\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xee\xa0\x10uo\x81\xdaK\xa2[r\x17\x87\xf0X\x17\v\uff49\x01\u009c\x9c\xf7p\xef\x00\x00\u07d4\xef\xf5\x1dr\xad\xfa\xe1C\xed\xf3\xa4+\x1a\xecU\xa2\xcc\xdd\v\x90\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xef\xf8kQ#\xbc\xdc\x17\xedL\xe8\xe0[~\x12\xe5\x13\x93\xa1\xf7\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xef\xfc\x15\u41f1\xbe\xda\n\x8d\x13%\xbd\xb4\x17\"@\xdcT\n\x89\x03\x8599\xee\xe1\xde\x00\x00\xe0\x94\xf0\x11\x95\xd6W\xef<\x94.l\xb89I\xe5\xa2\v\\\xfa\x8b\x1e\x8a\x05ts\xd0]\xab\xae\x80\x00\x00\u07d4\xf0'\x96)Q\x01gB\x88\xc1\xd94g\x05=\x04\"\x19\xb7\x94\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\u07d4\xf09h={=\"[\xc7\xd8\u07ed\xefc\x164A\xbeA\xe2\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xf0Jj7\x97\b\xb9B\x8dr*\xa2\xb0kw\xe8\x895\u03c9\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf0M,\x91\xef\xb6\xe9\xc4_\xfb\xe7KCL\x8c_+\x02\x8f\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf0W\xaaf\xcav~\xde\x12J\x1c[\x9c\xc5\xfc\x94\xef\v\x017\x89p\xa2K\u02b6\xf4]\x00\x00\u07d4\xf0[\xa8\u05f6\x859\xd930\v\xc9(\x9c=\x94t\xd0A\x9e\x89\x06\xda'\x02M\xd9`\x00\x00\u07d4\xf0\\\xee\xabeA\x05dp\x99Qw<\x84E\xad\x9fN\u01d7\x89\x10C\x16'\xa0\x93;\x00\x00\xe0\x94\xf0_\xcdL\rs\xaa\x16~US\xc8\xc0\xd6\xd4\xf2\xfa\xa3\x97W\x8a\x02\xd2\xd6l1p\xb2\x98\x00\x00\u07d4\xf0g\xe1\xf1\u0583UjL\xc4\xfd\f\x03\x13#\x9f2\xc4\xcf\u060965\u026d\xc5\u07a0\x00\x00\u07d4\xf0g\xfb\x10\u07f2\x93\u962b\xe5d\xc0U\xe34\x8f\x9f\xbf\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0h\xdf\xe9]\x15\xcd:\u007f\x98\xff\xa6\x88\xb44hB\xbe&\x90\x89D\n\xd8\x19\xe0\x97L\x00\x00\xe0\x94\xf0j\x85J<]\xc3m\x1cI\xf4\xc8}m\xb33\xb5~J\u074a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf0y\xe1\xb1&_P\xe8\u0229\x8e\xc0\u01c1^\xb3\xae\xac\x9e\xb4\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\xe0\x94\xf0{\xd0\xe5\xc2\xcei\xc7\u0127$\xbd&\xbb\xfa\x9d*\x17\xca\x03\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xf0\x83*k\xb2U\x03\xee\xcaC[\xe3\x1b\v\xf9\x05\xca\x1f\xcfW\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf0\x9b>\x87\xf9\x13\xdd\xfdW\xae\x80I\xc71\u06e9\xb66\xdf\u00c9 \xf5\xb1\uab4d\x80\x00\x00\u07d4\xf0\xb14\v\x99oo\v\xf0\xd9V\x1c\x84\x9c\xaf\u007fD0\xbe\xfa\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xb1\xf9\xe2x2\xc6\xdei\x14\xd7\n\xfc#\x8ct\x99\x95\xac\xe4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf0\xb4i\xea\xe8\x9d@\f\xe7\xd5\xd6j\x96\x95\x03p6\xb8\x89\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf0\xb9\u0583\u03a1+\xa6\x00\xba\xac\xe2\x19\xb0\xb3\xc9~\x8c\x00\xe4\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xbe\x0f\xafMy#\xfcDF\"\u0458\f\xf2\u0650\xaa\xb3\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xc0\x81\xdaR\xa9\xae6d*\xdf^\b _\x05\xc5Ah\xa6\x89\x06\x04o7\xe5\x94\\\x00\x00\u07d4\xf0\xc7\r\rm\xabvc\xaa\x9e\xd9\xce\xeaV~\xe2\u01b0'e\x89qC\x8a\u0167\x91\xa0\x80\x00\u07d4\xf0\xcb\xef\x84\xe1ic\x00\x98\xd4\xe3\x01\xb2\x02\b\xef\x05\x84j\u0249\x0e\v\x83EPkN\x00\x00\u07d4\xf0\xd2\x16c\u0630\x17n\x05\xfd\xe1\xb9\x0e\xf3\x1f\x850\xfd\xa9_\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf0\xd5\xc3\x1c\xcbl\xbe0\xc7\xc9\xea\x19\xf2h\xd1Y\x85\x1f\x8c\x9c\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xf0\xd6L\xf9\xdf\tt\x113\xd1pH_\xd2K\x00P\x11\xd5 \x89\x1b\b\x93A\xe1O\xcc\x00\x00\u07d4\xf0\xd8X\x10^\x1bd\x81\x01\xac?\x85\xa0\xf8\"+\xf4\xf8\x1dj\x89 \x86\xac5\x10R`\x00\x00\u07d4\xf0\xdcC\xf2\x05a\x91'P{+\x1c\x1c\xfd\xf3-(1\t \x89\x10^\xb7\x9b\x94\x17\b\x80\x00\u07d4\xf0\xe1\u07e4*\u07ac/\x17\xf6\xfd\xf5\x84\xc9Hb\xfdV3\x93\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf0\xe2d\x9c~j?,]\xfe3\xbb\xfb\xd9'\xca<5\nX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xe7\xfb\x9eB\nS@\xd56\xf4\x04\b4O\xea\xef\xc0j\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf1\x04b\xe5\x8f\xcc\a\U000d5121\x87c\x94Q\x16~\x85\x92\x01\x89\t4\xdd]3\xbc\x97\x00\x00\xe0\x94\xf1\x06a\xff\x94\x14\x0f >zH%rCy8\xbe\xc9\xc3\xf7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xf1\x14\xff\r\x0f$\xef\xf8\x96\xed\xdeTq\u07a4\x84\x82J\x99\xb3\x88\xbe -j\x0e\xda\x00\x00\u07d4\xf1\x16\xb0\xb4h\x0fS\xabr\xc9h\xba\x80.\x10\xaa\x1b\xe1\x1d\u0209\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xf1\x1c\xf5\xd3cto\xeehd\xd3\xca3m\xd8\x06y\xbb\x87\xae\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf1\x1e\x01\u01e9\xd1$\x99\x00_M\xaew\x16\tZ4\x17bw\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf1;\b0\x93\xbaVN-\xc61V\x8c\xf7T\r\x9a\x0e\xc7\x19\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf1O\x0e\xb8m\xb0\xebhu?\x16\x91\x8e]K\x80t7\xbd>\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf1Qx\xff\xc4:\xa8\a\x0e\xce2~\x93\x0f\x80\x9a\xb1\xa5O\x9d\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xf1V\xdc\v*\x98\x1e[U\xd3\xf2\xf0;\x814\xe31\u06ed\xb7\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf1]\x9dZ!\xb1\x92\x9ey\x03q\xa1\u007f\x16\xd9_\fie\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1^\x18,O\xbb\xady\xbd\x934\"B\xd4\xdc\xcf+\xe5\x89%\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf1bM\x98\ve3o\xea\u0166\xd5A%\x00\\\xfc\xf2\xaa\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1g\xf5\x86\x8d\xcfB3\xa7\x83\x06\th,\xaf-\xf4\xb1\xb8\a\x89\x81\xe5B\xe1\xa78?\x00\x00\u07d4\xf1m\xe1\x89\x1d\x81\x96F\x13\x95\xf9\xb16&[;\x95F\xf6\xef\x89\x01\xb2\x8e\x1f\x98\xbb\u0380\x00\u07d4\xf1z\x92\xe06\x1d\xba\xce\xcd\xc5\xde\r\x18\x94\x95Z\xf6\xa9\xb6\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1z\xdbt\x0fE\u02fd\xe3\tN~\x13qo\x81\x03\xf5c\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x8b\x14\xcb\xf6iC6\xd0\xfe\x12\xac\x1f%\xdf-\xa0\xc0]\xbb\x89\xd8\xd4`,&\xbfl\x00\x00\u07d4\xf1\x9b98\x9dG\xb1\x1b\x8a,?\x1d\xa9\x12M\xec\xff\xbe\xfa\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x9f\x195\b9>M*\x12{ \xb2\x03\x1f9\xc8%\x81\u0189\xbd\xbdz\x83\xbd/l\x00\x00\u07d4\xf1\xa1\xf3 @yd\xfd<\x8f.,\u0224X\r\xa9O\x01\xea\x89ll!wU|D\x00\x00\u07d4\xf1\xb4\xec\xc65%\xf7C,=\x83O\xfe+\x97\x0f\xbe\xb8r\x12\x89\xa2\xa2@h\xfa\u0340\x00\x00\u07d4\U000753ef\xfa\x87\x94\xf5\n\xf8\xe8\x83\t\u01e6&TU\xd5\x1a\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xf1\xc8\u0129A\xb4b\x8c\rl0\xfd\xa5dR\u065c~\x1bd\x89N\x8c\xea\x1e\xdeu\x04\x00\x00\u07d4\xf1\xda@so\x99\xd5\xdf;\x06\x8a]t_\xaf\xc6F?\u0271\x89\x06\x96\xca#\x05\x8d\xa1\x00\x00\u07d4\xf1\u070a\xc8\x10B\xc6z\x9c\\c2!\xa8\xf76>e\x87\f\x9f(t$\u04a9`\x89J\xcfX\xe0rW\x10\x00\x00\u07d4\xf2B\u0684]B\u053fw\x9a\x00\xf2\x95\xb4\aP\xfeI\xea\x13\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2RY\xa5\xc99\xcd%\x96l\x9bc\x03\xd3s\x1cS\u077cL\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf2^Lp\xbcFV2\u021eV%\xa82\xa7r/k\xff\xab\x89\xf3K\x82\xfd\x8e\x91 \x00\x00\u07d4\xf2k\xce\xdc\xe3\xfe\xad\u03a3\xbc>\x96\xeb\x10@\xdf\xd8\xff\u1809*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xf2py%v\xf0]QD\x93\xff\xd1\xf5\xe8K\xecK-\xf8\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2s,\xf2\xc1;\x8b\xb8\xe7I*\x98\x8f_\x89\xe3\x82s\xdd\u0209 \x86\xac5\x10R`\x00\x00\xe0\x94\xf2t.hY\xc5i\xd5\xf2\x10\x83Q\xe0\xbfM\xca5*H\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf2\x81:d\xc5&]\x02\x025\u02dc1\x9bl\x96\xf9\x06\xc4\x1e\x89\x12\xf99\u025e\u06b8\x00\x00\u07d4\xf2\x87\xffR\xf4a\x11z\xdb>\x1d\xaaq\x93-\x14\x93\xc6_.\x89\xc5S%\xcat\x15\xe0\x00\x00\u07d4\xf2\xab\x11au\x02D\xd0\xec\xd0H\xee\r>Q\xab\xb1C\xa2\xfd\x89B\xfe+\x90ss\xbc\x00\x00\u07d4\xf2\xb4\xab,\x94'\xa9\x01^\xf6\xee\xff\xf5\xed\xb6\x019\xb7\x19\u0449&\u06d9*;\x18\x00\x00\x00\u07d4\xf2\xc0>*8\x99\x8c!d\x87`\xf1\xe5\xae~\xa3\a}\x85\"\x89\x8f?q\x93\xab\a\x9c\x00\x00\u0794\xf2\u0090N\x9f\xa6d\xa1\x1e\xe2VV\xd8\xfd,\xc0\u0665\"\xa0\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xf2\xc3b\xb0\xef\x99\x1b\xc8/\xb3nf\xffu\x93*\xe8\u0742%\x89\x04\x02\xf4\xcf\xeeb\xe8\x00\x00\u07d4\xf2\xd0\xe9\x86\xd8\x14\xea\x13\xc8\xf4f\xa0S\x8cS\u0712&Q\xf0\x89J\xcfX\xe0rW\x10\x00\x00\xe0\x94\xf2\u04775w$\xecL\x03\x18[\x87\x9bc\xf5~&X\x91S\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf2\xd5v<\xe0s\x12~,\xed\xdeo\xab\xa7\x86\xc7<\xa9AA\x8a\x01\xacB\x86\x10\x01\x91\xf0\x00\x00\xe0\x94\xf2\u055c\x89#u\x90s\xd6\xf4\x15\xaa\xf8\xeb\x06_\xf2\U000f614a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4\xf2\xe9\x9f\\\xbb\x83kz\xd3bGW\x1a0,\xbeKH\x1ci\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf2\xed>w%J\u02c3#\x1d\xc0\x86\x0e\x1a\x11$+\xa6'\u06c9kV\x05\x15\x82\xa9p\x00\x00\xe0\x94\xf2\xed\xde7\xf9\xa8\u00dd\u07a2My\xf4\x01WW\xd0k\xf7\x86\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf2\xef\xe9e`\xc9\xd9{r\xbd6DxC\x88\\\x1d\x90\xc21\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf2\xfb\xb6\u0607\xf8\xb8\xcc:\x86\x9a\xba\x84\u007f=\x1fd\xfcc\x97\xaae\xfbS\xa8\xf0z\x0f\x89:\xae0\xe8\xbc\xee\x89|\xf28\x1fa\x9f\x15\x00\x00\u07d4\xf3@\x83\xec\xea8P\x17\xaa@\xbd\xd3^\xf7\xef\xfbL\xe7v-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf3F\xd7\u0792t\x1c\b\xfcX\xa6M\xb5[\x06-\xde\x01-\x14\x89\x0f\xffk\x1fv\x1em\x00\x00\xe0\x94\xf3U\xd3\xec\f\xfb\x90}\x8d\xbb\x1b\xf3FNE\x81(\x19\v\xac\x8a\x01\v\x04n\u007f\r\x80\x10\x00\x00\u07d4\xf3m\xf0/\xbd\x89`sG\xaf\xce)i\xb9\xc4#jX\xa5\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3s\xe9\u06ac\f\x86u\xf5;yz\x16\x0fo\xc04\xaek#\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3{BeG\xa1d-\x8032H\x14\xf0\xed\xe3\x11O\xc2\x12\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xf3{\xf7\x8cXu\x15G\x11\xcbd\r7\xeam(\xcf\xcb\x12Y\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf3\x82\xdfX1U\xd8T\x8f?\x93D\f\xd5\xf6\x8c\xb7\x9d`&\x8a8u}\x02\u007f\xc1\xfd\\\x00\x00\xe0\x94\xf3\x82\xe4\xc2\x04\x10\xb9Q\b\x9e\x19\xba\x96\xa2\xfe\xe3\xd9\x1c\xce~\x8a\x01\x11\xfaV\xee\u00a88\x00\x00\xe0\x94\xf3\x8al\xa8\x01hS~\x97M\x14\xe1\xc3\xd19\x90\xa4L,\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xf3\x9a\x9dz\xa3X\x1d\xf0~\xe4'\x9a\xe6\xc3\x12\xef!\x036X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xb6h\xb3\xf1M\x92\x0e\xbc7\x90\x92\u06d8\x03\x1bg\xb2\x19\xb3\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\U000fe679\x10<\xe7U\n\xa7O\xf1\xdb\x18\xe0\x9d\xfe2\xe0\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xc1\xab\u049d\xc5{A\xdc\x19-\x0e8M\x02\x1d\xf0\xb4\xf6\u0509\x97\xae\f\u07cf\x86\xf8\x00\x00\u07d4\xf3\xc4qm\x1e\xe5'\x9a\x86\xd0\x16:\x14a\x81\x81\xe1a6\u01c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf3\u030b\xcbU\x94e\xf8\x1b\xfeX;\u05eb\n#\x06E;\x9e\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf3\u0588\xf0k\xbd\xbfP\xf9\x93,AE\xcb\xe4\x8e\xcd\xf6\x89\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf3\xdb\xcf\x13Z\u02dd\xee\x1aH\x9cY<\x02O\x03\u00bb\xae\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xde_&\xefj\xde\xd6\xf0m;\x91\x13F\xeep@\x1d\xa4\xa0\x89\x13:\xb3}\x9f\x9d\x03\x00\x00\u07d4\xf3\xdfc\xa9q\x99\x93308;>\xd7W\v\x96\u0101#4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xe7OG\f}:?\x003x\x0fv\xa8\x9f>\xf6\x91\xe6\u02c9\xa3\xcf\xe61\xd1Cd\x00\x00\u07d4\xf3\xeb\x19H\xb9Q\xe2-\xf1ax)\xbf;\x8d\x86\x80\xeckh\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xf1\xfa9\x18\xca4\xe2\xcf~\x84g\v\x1fM\x8e\xca\x16\r\xb3\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xf3\xf2O\u009e @?\xc0\xe8\xf5\xeb\xbbU4&\xf7\x82p\xa2\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3\xfar5R\xa5\xd0Q.+b\xf4\x8d\xca{+\x81\x050[\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xf3\xfeQ\xfd\xe3D\x13\xc73\x18\xb9\xc8T7\xfe~\x82\x0fV\x1a\x896b2\\\u044f\xe0\x00\x00\u07d4\xf4\x00\xf9=_\\~?\xc3\x03\x12\x9a\xc8\xfb\f/xd\a\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\v\x13O\xea\"\u01b2\x9c\x84W\xf4\x9f\x00\x0f\x9c\xdax\x9a\u06c9 \x86\xac5\x10R`\x00\x00\u07d4\xf4\x15W\xdf\u07f1\xa1\xbd\xce\xfe\xfe.\xba\x1e!\xfe\nJ\x99B\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\x17z\r\x85\u050b\x0e&B\x11\xce*\xa2\xef\xd3\xf1\xb4\u007f\b\x89\xc2\xcc\xca&\xb7\xe8\x0e\x80\x00\u07d4\xf4/\x90R1\xc7p\xf0\xa4\x06\xf2\xb7h\x87\u007f\xb4\x9e\xee\x0f!\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf42\xb9\u06ef\x11\xbd\xbds\xb6Q\x9f\xc0\xa9\x04\x19\x87q\xaa\u0189\b=lz\xabc`\x00\x00\u07d4\xf4=\xa3\xa4\xe3\xf5\xfa\xb1\x04\u029b\xc1\xa0\xf7\xf3\xbbJV\xf3Q\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf4G\x10\x8b\x98\xdfd\xb5~\x87\x103\x88\\\x1a\xd7\x1d\xb1\xa3\xf9\x8a\x01v\xf4\x9e\xad4\x83P\x80\x00\u07d4\xf4O\x85Q\xac\xe93r\a\x12\xc5\u0111\u0376\xf2\xf9Qsl\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\xf4V\x05Z\x11\xab\x91\xfff\x8e.\xc9\"\x96\x1f*#\xe3\xdb%\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf4V\xa7[\xb9\x96U\xa7A,\xe9}\xa0\x81\x81m\xfd\xb2\xb1\xf2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf4[\x1d\xcb.A\xdc'\xff\xa0$\u06ad\xf6\x19\xc1\x11u\xc0\x87\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xf4c\xa9\f\xb3\xf1>\x1f\x06CB66\xbe\xab\x84\xc1#\xb0m\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf4h\x90n~\xdffJ\xb0\u063e=\x83\xebz\xb3\xf7\xff\xdcx\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xf4i\x80\u3929\u049ajn\x90`E7\xa3\x11K\xcb(\x97\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf4kk\x9c|\xb5R\x82\x9c\x1d=\xfd\x8f\xfb\x11\xaa\xba\xe7\x82\xf6\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xf4v\xe1&\u007f\x86$|\xc9\b\x81o.z\xd58\x8c\x95-\xb0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf4v\xf2\xcbr\b\xa3.\x05\x1f\xd9N\xa8f)\x92c\x82\x87\xa2\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xf4{\xb14\xda0\xa8\x12\xd0\x03\xaf\x8d\u0338\x88\xf4K\xbfW$\x8a\x01\x19Y\xb7\xfe3\x95X\x00\x00\u07d4\xf4\x83\xf6\a\xa2\x1f\xcc(\x10\n\x01\x8cV\x8f\xfb\xe1@8\x04\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf4\x8e\x1f\x13\xf6\xafM\x84\xb3q\xd7\xdeK'=\x03\xa2c'\x8e\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xf4\x9cG\xb3\xef\xd8knj[\xc9A\x8d\x1f\x9f\xec\x81Ki\xef\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xf4\x9fo\x9b\xaa\xbc\x01\x8c\x8f\x8e\x11\x9e\x01\x15\xf4\x91\xfc\x92\xa8\xa4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf4\xa3g\xb1f\u0499\x1a+\xfd\xa9\xf5dc\xa0\x9f%,\x1b\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\xa5\x1f\xceJ\x1d[\x94\xb0q\x83\x89\xbaNx\x14\x13\x9c\xa78\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf4\xa9\xd0\f\xef\xa9{zX\xef\x94\x17\xfcbg\xa5\x06\x909\xee\x89\x01.\x89(\u007f\xa7\x84\x00\x00\u07d4\xf4\xaa\xa3\xa6\x16>7\x06W{I\xc0v~\x94\x8ah\x1e\x16\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\xb1bn$\xf3\v\xca\xd9'!\xb2\x93r\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xf5U\xa2{\xb1\xe2\xfdN,\u01c4\xca\ue493\x9f\xc0n/\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5X\xa2\xb2\xdd&\u0755\x93\xaa\xe0E1\xfd<<\u00c5Kg\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xf5`H\xdd!\x81\u0523od\xfc\xec\xc6!T\x81\xe4*\xbc\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5dB\xf6\x0e!i\x13\x95\u043f\xfa\xa9\x19M\xca\xff\x12\u2dc9\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xf5yqJE\xeb\x8fR\xc3\xd5{\xbd\xef\xd2\xc1[./\x11\u07c9T\x91YV\xc4\t`\x00\x00\u07d4\xf5\x93\xc6R\x85\xeek\xbdf7\U000fe3c9\xad@\u0509\xf6U\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf5\x98\xdb.\t\xa8\xa5\xee}r\r+\\C\xbb\x12m\x11\xec\u0089\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf5\x9d\xab\x1b\xf8\xdf\x112~a\xf9\xb7\xa1KV:\x96\xec5T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf5\x9f\x9f\x02\xbb\u024e\xfe\t~\xab\xb7\x82\x10\x97\x90!\x89\x8b\xfd\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\xf5\xa5E\x9f\xcd\xd5\xe5\xb2s\x83\r\xf8\x8e\xeaL\xb7}\xda\u07f9\x89\x04\t\xe5+H6\x9a\x00\x00\u07d4\xf5\xa7gj\xd1H\xae\x9c\x1e\xf8\xb6\xf5\xe5\xa0\xc2\xc4s\xbe\x85\v\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5\xb0h\x98\x9d\xf2\x9c%5w\xd0@Z\xden\x0eu(\xf8\x9e\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xf5\xb6\xe9\x06\x1aN\xb0\x96\x16\aw\xe2gb\xcfH\xbd\u0635]\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xf5\xcf\xfb\xbabN~\xb3!\xbc\x83\xc6\f\xa6\x81\x99\xb4\xe3fq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5\xd1ER\xb1\xdc\xe0\xd6\xdc\x1f2\r\xa6\xff\u02231\xcdo\f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xf5\xd6\x1a\xc4\u0295G^[{\xff\xd5\xf2\xf6\x90\xb3\x16u\x96\x15\x8a\x06\x92\xae\x88\x97\b\x1d\x00\x00\x00\u07d4\xf5\xd9\xcf\x00\xd6X\xddEQzH\xa9\xd3\xf5\xf63T\x1aS=\x89\x06O_\xdfIOx\x00\x00\u07d4\xf5\xea\xdc\xd2\u0478ez\x12\x1f3\xc4X\xa8\xb1>v\xb6U&\x89\r\x8b\x0fZZ\xc2J\x00\x00\u07d4\xf6\a\xc2\x15\r>\x1b\x99\xf2O\xa1\xc7\xd5@\xad\xd3\\N\xbe\x1e\x89\xa7\xf1\xaa\a\xfc\x8f\xaa\x00\x00\u07d4\xf6\v\xd75T>k\xfd.\xa6\xf1\x1b\xffbs@\xbc\x03Z#\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6\f\x1bE\xf1d\xb9X\x0e 'Z\\9\xe1\xd7\x1e5\xf8\x91\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf6\x0fb\xd797\x95?\xef5\x16\x9e\x11\xd8r\xd2\xea1~\xec\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xf6\x12\x83\xb4\xbd\x85\x04\x05\x8c\xa3`\u94d9\x9bb\xcb\xc8\xcdg\x89\r\xd2\xd5\xfc\xf3\xbc\x9c\x00\x00\u07d4\xf6\x17\xb9g\xb9\xbdH_v\x95\xd2\xefQ\xfbw\x92\u0618\xf5\x00\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf6\x18\u0671\x04A\x14\x80\xa8c\xe6#\xfcU#-\x1aOH\xaa\x89\x0eh\x9emD\xb1f\x80\x00\u07d4\xf6\"\u5126b>\xaa\xf9\x9f+\xe4\x9eS\x80\xc5\xcb\xcf\\\u0609\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf62\xad\xffI\r\xa4\xb7-\x126\xd0KQ\x0ft\xd2\xfa\xa3\u0349K\xe4\xe7&{j\xe0\x00\x00\u07d4\xf69\xac1\u069fg'\x1b\xd1\x04\x02\xb7eN\\\xe7c\xbdG\x89\x15\xaf\x0fB\xba\xf9&\x00\x00\u07d4\xf6:W\x9b\xc3\xea\u00a9I\x04\x10\x12\x8d\xbc\xeb\xe6\xd9\u0782C\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xf6E\xdd|\x89\x00\x93\xe8\xe4\u022a\x92\xa6\xbb55\"\xd3\u0718\x89\aC\x9f\xa2\t\x9eX\x00\x00\xe0\x94\xf6H\xea\x89\xc2u%q\x01r\x94Ny\xed\xff\x84x\x03\xb7u\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf6JJ\xc8\xd5@\xa9(\x9ch\xd9`\xd5\xfb|\xc4Zw\x83\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6N\xcf!\x17\x93\x1cmSZ1\x1eO\xfe\xae\xf9\u0514\x05\xb8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf6O\xe0\x93\x9a\x8d\x1e\xea*\x0e\u035a\x970\xfdyX\xe31\t\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xf6V\x16\xbe\x9c\x8by~t\x15\"|\x918\xfa\xa0\x89\x17B\u05c9*\xd3s\xcef\x8e\x98\x00\x00\u07d4\xf6W\xfc\xbeh.\xb4\xe8\xdb\x15.\u03c9$V\x00\vQ=\x15\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf6X\x19\xacL\xc1L\x13\u007f\x05\xddyw\xc7\xda\xe0\x8d\x1aJ\xb5\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xf6{\xb8\xe2\x11\x8b\xbc\u0550'fn\xed\xf6\x94>\xc9\xf8\x80\xa5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x84d\xbfd\xf2A\x13V\xe4\xd3%\x0e\xfe\xfe\\P\xa5\xf6[\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf6\x86x[\x89r\va\x14_\ua017\x8dj\u030e\v\xc1\x96\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x8c^3\xfa\x97\x13\x9d\xf5\xb2\xe68\x86\xce4\xeb\xf3\u45dc\x89\xb3\xfaAi\xe2\xd8\xe0\x00\x00\u07d4\xf6\xa8cWW\xc5\xe8\xc14\xd2\r\x02\x8c\xf7x\u03c6\t\xe4j\x89O\x1dw/\xae\xc1|\x00\x00\u07d4\xf6\xb7\x82\xf4\xdc\xd7E\xa6\xc0\xe2\xe00`\x0e\x04\xa2K%\xe5B\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xf6\xbc7\xb1\u04a3x\x8dX\x9bm\xe2\x12\xdc\x17\x13\xb2\xf6\u738a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xf6\xc3\u010a\x1a\xc0\xa3G\x99\xf0M\xb8n\u01e9u\xfewh\xf3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf6\xd2]?=\x84m#\x9fR_\xa8\xca\xc9{\xc45x\u06ec\x890\x92\u007ft\xc9\xde\x00\x00\x00\u07d4\xf6\xea\xacp2\u0512\xef\x17\xfd`\x95\xaf\xc1\x1dcOV\xb3\x82\x89\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\xf6\xea\xd6}\xbf[~\xb13X\xe1\x0f6\x18\x9dS\xe6C\xcf\u03ca\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf6\xf1\xa4C\t\x05\x1ck%\xe4}\xff\x90\x9b\x17\x9b\xb9\xabY\x1c\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf7\x03(\xef\x97b_\xe7E\xfa\xa4\x9e\xe0\xf9\u052a;\r\xfbi\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\n\x99\x8aq{3\x8d\x1d\u0658T@\x9b\x1a3\x8d\ue930\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\rcz\x84\\\x06\xdbl\u0711\xe67\x1c\xe7\xc48\x8ab\x8e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x15R\x13D\x98\x92tK\xc6\x0f.\x04@\a\x88\xbd\x04\x1f\u0749\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\xe0\x94\xf7\x1bE4\xf2\x86\xe40\x93\xb1\xe1^\xfe\xa7I\xe7Y{\x8bW\x8a\x16\x1c\x13\xd34\x1c\x87(\x00\x00\u07d4\xf74\xec\x03rM\xde\xe5\xbbRy\xaa\x1a\xfc\xf6\x1b\f\xb4H\xa1\x89\xe5\xbf,\u0270\x97\x80\x00\x00\u07d4\xf76\u0716v\x00\x128\x8f\xe8\x8bf\xc0n\xfeW\xe0\xd7\xcf\n\x89q\xd7Z\xb9\xb9 P\x00\x00\u07d4\xf7:\xc4l ;\xe1S\x81\x11\xb1Q\xec\x82 \u01c6\xd8AD\x89\x0f\xf77x\x17\xb8+\x80\x00\u07d4\xf7=\xd9\xc1B\xb7\x1b\xce\x11\xd0n0\xe7\xe7\xd02\xf2\uc71e\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf7A\x8a\xa0\xe7\x13\xd2H\"\x87v\xb2\xe7CB\"\xaeu\u3949lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7Nn\x14S\x82\xb4\u06c2\x1f\xe0\xf2\u0643\x88\xf4V\t\u019f\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf7P\f\x16o\x8b\xea/\x824v\x06\xe5\x02K\xe9\xe4\xf4\u0399\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7W\xfc\x87 \xd3\xc4\xfaRw\a^`\xbd\\A\x1a\xeb\xd9w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7[\xb3\x9cy\x97y\xeb\xc0J3m&\r\xa61F\xed\x98\u0409\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xf7h\xf3!\xfdd3\xd9kO5M<\xc1e,\x172\xf5\u007f\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf7oi\xce\xe4\xfa\xa0\xa6;0\xae\x1ex\x81\xf4\xf7\x15ep\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf7w6\x1a=\u062bb\xe5\xf1\xb9\xb0GV\x8c\xc0\xb5UpL\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7|{\x84QI\xef\xba\x19\xe2a\xbc|u\x15y\b\xaf\xa9\x90\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\u007f\x95\x87\xffz-r\x95\xf1\xf5q\u0206\xbd3\x92jR|\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xf7\x82X\xc1$\x81\xbc\xdd\u06f7*\x8c\xa0\xc0C\tra\xc6\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x98\xd1m\xa4\xe4`\xc4`\xcdH_\xae\x0f\xa0Y\x97\b\ub08965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\xa1\xad\xe2\xd0\xf5)\x12=\x10U\xf1\x9b\x17\x91\x9fV!Ng\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf7\xac\xff\x93K\x84\xda\ti\xdc7\xa8\xfc\xf6C\xb7\xd7\xfb\xedA\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf7\xb1Q\xcc^W\x1c\x17\xc7e9\xdb\xe9\x96L\xbbo\xe5\xdey\x89tq|\xfbh\x83\x10\x00\x00\u07d4\xf7\xb2\x9b\x82\x19\\\x88-\xabx\x97\u00ae\x95\xe7w\x10\xf5xu\x89w5Aa2\xdb\xfc\x00\x00\u07d4\xf7\xbcLD\x91\rZ\xed\xd6n\xd25U8\xa6\xb1\x93\xc3a\xec\x89\x05A\xde,-\x8db\x00\x00\u07d4\xf7\xc0\f\xdb\x1f\x02\x03\x10\u056c\xab{Ij\xaaD\xb7y\b^\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xf7\xc1\xb4C\x96\x8b\x11{]\u0677UW/\xcd9\xca^\xc0K\x89\x18\xb9h\u0092\xf1\xb5\x00\x00\xe0\x94\xf7\xc5\x0f\x92*\xd1ka\xc6\u047a\xa0E\xed\x81h\x15\xba\u010f\x8a\x02\xa99j\x97\x84\xad}\x00\x00\u07d4\xf7\xc7\b\x01Pq\xd4\xfb\n:*\t\xa4]\x15c\x96\xe34\x9e\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf7\xcb\u06e6\xbel\xfeh\xdb\xc2<+\x0f\xf50\xee\x05\"o\x84\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\xd0\xd3\x10\xac\xea\x18@a8\xba\xaa\xbb\xfe\x05q\xe8\r\xe8_\x89Hz\x9a0E9D\x00\x00\u07d4\xf7\u05ef LV\xf3\x1f\xd9C\x98\xe4\r\xf1\x96K\u063f\x12<\x89\b!\xd2!\xb5)\x1f\x80\x00\u07d4\xf7\xdc%\x11\x96\xfb\u02f7|\x94}|\x19F\xb0\xffe\x02\x1c\xea\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf7\xe4Z\x12\xaaq\x1cp\x9a\xce\xfe\x95\xf3;xa-*\xd2*\x8a\x0e\x06U\xe2\xf2k\xc9\x18\x00\x00\u07d4\xf7\xf4\x89\x8cLRm\x95_!\xf0U\xcbnG\xb9\x15\xe5\x19d\x89|\b`\xe5\xa8\r\xc0\x00\x00\u07d4\xf7\xf9\x1ez\xcb[\x81)\xa3\x06\x87|\xe3\x16\x8eoC\x8bf\xa1\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xf7\xfcE\xab\xf7oP\x88\xe2\u5d68\xd12\xf2\x8aMN\xc1\xc0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\x06:\xf4\xcc\x1d\xd9a\x9a\xb5\u063f\xf3\xfc\xd1\xfa\xa8H\x82!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\bnBf\x1e\xa9)\xd2\u0761\xablt\x8c\xe3\x05]\x11\x1e\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf8\bw\x86\xb4-\xa0N\xd6\xd1\xe0\xfe&\xf6\xc0\xee\xfe\x1e\x9fZ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf8\r6\x19p/\xa5\x83\x8cH9\x18Y\xa89\xfb\x9c\xe7\x16\x0f\x89l\a\xa7\u0471np\x00\x00\u07d4\xf8\x14y\x9fm\xdfM\xcb)\xc7\xee\x87\x0eu\xf9\xcc-52m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf8\x15\xc1\n\x03-\x13\xc3K\x89v\xfan;\xd2\xc9\x13\x1a\x8b\xa9\x89Hz\x9a0E9D\x00\x00\u07d4\xf8\x16\"\xe5WW\xda\xeafu\x97]\xd958\xda}\x16\x99\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8$\xee3\x1eJ\xc3\xccXv\x939[W\xec\xf6%\xa6\xc0\u0089V\xc9]\xe8\xe8\xca\x1d\x00\x00\u07d4\xf8'\xd5n\xd2\xd3' \u052b\xf1\x03\xd6\xd0\xefM;\xcdU\x9b\x89\x01l\x80\x06W\x91\xa2\x80\x00\u07d4\xf8)\x85\x91R>P\xb1\x03\xf0\xb7\x01\xd6#\xcb\xf0\xf7EV\xf6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8H\xfc\xe9\xaba\x1c}\x99 n#\xfa\u019a\u0508\xb9O\xe1\x89\x02\xa1\x12\x9d\t6r\x00\x00\u07d4\xf8O\t\n\xdf?\x8d\xb7\u1533P\xfb\xb7u\x00i\x9ff\xfd\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf8Q\xb0\x10\xf63\xc4\n\xf1\xa8\xf0js\ubeabe\az\xb5\x89\xee\x86D/\xcd\x06\xc0\x00\x00\u07d4\xf8X\x17\x1a\x04\xd3W\xa1;IA\xc1n~U\xdd\u0514\x13)\x89\x02F\xa5!\x8f*\x00\x00\x00\u07d4\xf8[\xab\x1c\xb3q\x0f\xc0_\xa1\x9f\xfa\xc2.gR\x1a\v\xa2\x1d\x89l\x955\u007f\xa6\xb3l\x00\x00\u07d4\xf8j>\xa8\a\x1fp\x95\xc7\u06ca\x05\xaePz\x89)\u06f8v\x89\x126\xef\xcb\u02f3@\x00\x00\u07d4\xf8pL\x16\xd2\xfd[\xa3\xa2\xc0\x1d\x0e\xb2\x04\x84\xe6\xec\xfa1\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8p\x99_\xe1\xe5\"2\x1duC7\xa4\\\f\x9d{8\x95\x1c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf8s\xe5ze\xc9;n\x18\xcbu\xf0\xdc\a}[\x893\xdc\\\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf8ua\x9d\x8a#\xe4]\x89\x98\u0444\u0500\xc0t\x89p\x82*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8{\xb0{(\x9d\xf70\x1eT\xc0\xef\xdaj,\xf2\x91\xe8\x92\x00\x89K\xe4\xe7&{j\xe0\x00\x00\u0794\xf8\x89\x00\xdbsyU\xb1Q\x9b\x1a}\x17\n\x18\x86L\xe5\x90\xeb\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf8\x8bX\xdb7B\vFL\v\xe8\x8bE\xee+\x95)\x0f\x8c\xfa\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf8\x96+u\xdb]$\xc7\xe8\xb7\xce\xf1\x06\x8c>g\u03bb0\xa5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xf8\xa0e\xf2\x87\xd9\x1dw\xcdbj\xf3\x8f\xfa\"\r\x9bU*+\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xf8\xa4\x9c\xa29\f\x1fm\\\x0ebQ;\a\x95qt?|\u0189\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf8\xa5\f\xee.h\x8c\xee\u3b24\u0522\x97%\xd4\a,\u0103\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xacJ9\xb5<\x110x \x97;D\x13e\xcf\xfeYof\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xae\x85{g\xa4\xa2\x89:?\xbe|z\x87\xff\x1c\x01\u01a6\xe7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8\xbf\x9c\x04\x87NZw\xf3\x8fL8R~\x80\xc6v\xf7\xb8\x87\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xc7\xf3J8\xb3\x18\x01\xdaC\x064w\xb1+'\xd0\xf2\x03\xff\x89\x1a\u04ba\xbao\xefH\x00\x00\u07d4\xf8\xca3l\x8e\x91\xbd \xe3\x14\xc2\v-\xd4`\x8b\x9c\x8b\x94Y\x89-\u071b\u0173,x\x00\x00\u07d4\xf8\xd1t$\xc7g\xbe\xa3\x12\x05s\x9a+W\xa7'r\x14\uef89\x02F\xdd\xf9yvh\x00\x00\u07d4\xf8\xd5-\xcc_\x96\xcc(\x00{>\u02f4\t\xf7\xe2*dl\xaa\x89\b\x16\x90\xe1\x81(H\x00\x00\u07d4\xf8\xdc\xe8g\xf0\xa3\x9c[\xef\x9e\xeb\xa6\t\"\x9e\xfa\x02g\x8bl\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xf2&\x14*B\x844\xab\x17\xa1\x86J%\x97\xf6J\xab/\x06\x89\tY\x8b/\xb2\xe9\xf2\x80\x00\u07d4\xf8\xf6d^\r\xeedK=\xad\x81\xd5q\uf6ef\x84\x00!\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x01\xc0\x0f\xc1\u06c8\xb6\x9cK\xc3%+\\\xa7\x0e\xa6\xee\\\xf6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9=[\xcb\x06D\xb0\xcc\xe5\xfc\u0763C\xf5\x16\x8f\xfa\xb2\x87}\x89\vb\a\xb6}&\xf9\x00\x00\u07d4\xf9W\x0e\x92L\x95\u07bbpa6\x97\x92\xcf.\xfe\u00a8-^\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf9d \x86\xb1\xfb\xaea\xa6\x80M\xbe_\xb1^\xc2\u04b57\xf4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9d\x88i\x85\x90\xdc;,UVB\xb8q4\x8d\xfa\x06z\u0549\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9d\u064d(\x170\xba5\xb2\xe3\xa3\x14yn{B\xfe\xdfg\x89S\xb0\x87`\x98\xd8\f\x00\x00\u07d4\xf9e\ri\x89\xf1\x99\xab\x1c\xc4ycm\xed0\xf2A\x02\x1fe\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xf9h\x83X$Y\x90\x8c\x82v'\xe8o(\xe6F\xf9\xc7\xfcz\x8a\x01\u0127\x877\xcd\u03f8\x00\x00\u07d4\xf9kL\x00voSsj\x85t\xf8\"\xe6GL/!\xda-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9r\x9dH(,\x9e\x87\x16m^\xef-\x01\xed\xa9\xdb\xf7\x88!\x89\x05k\x83\xdd\xc7(T\x80\x00\u07d4\xf9v~N\xcbJY\x80Ru\b\u05fe\xc3\xd4^Ld\x9c\x13\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xf9x\xb0%\xb6B3U\\\xc3\xc1\x9a\xda\u007fA\x99\xc94\x8b\xf7\x8aT\xb4\v\x1f\x85+\xda\x00\x00\x00\u07d4\xf9{V\xeb\u0577z\xbc\x9f\xba\u02eb\u0514\xb9\xd2\xc2!\xcd\x03\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf9\x81\x1f\xa1\x9d\xad\xbf\x02\x9f\x8b\xfeV\x9a\xdb\x18\"\x8c\x80H\x1a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf9\x82Ps\fLa\xc5\u007f\x12\x985\xf2h\b\x94yEB\xf3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xf9\x894gr\x99^\xc1\x90o\xaf\xfe\xba*\u007f\xe7\u079ck\xab\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf9\x98\xca4\x11s\nl\xd1\x0etU\xb0A\x0f\xb0\xf6\xd3\xff\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x9a\xeeDKW\x83\xc0\x93\xcf\xff\xd1\xc4c,\xf9\x90\x9f\xbb\x91\x1d/\x81\x92\xf8B\t\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf9\xbf\xb5\x9dS\x8a\xfcHt\xd4\xf5\x94\x1b\b\xc9s\x0e8\xe2K\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf9\xdd#\x90\b\x18/\xb5\x19\xfb0\xee\xdd \x93\xfe\xd1c\x9b\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9\u07ba\xec\xb5\xf39\xbe\xeaH\x94\xe5 K\xfa4\r\x06\u007f%\x89ZB\x84Fs\xb1d\x00\x00\xe0\x94\xf9\xe3tG@lA!\x97\xb2\u2bbc\x00\x1dn0\u024c`\x8a\x01\xc4y\xbbCI\xc0\xee\x00\x00\u07d4\xf9\xe7\"/\xaa\xf0\xf4\xda@\xc1\u0124\x0607:\t\xbe\u05f6\x89\x9bO\u0730\x94V$\x00\x00\u07d4\xf9\xec\xe0\"\xbc\xcd,\x924i\x11\xe7\x9d\xd5\x03\x03\xc0\x1e\x01\x88\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfa\x00\xc3v\xe8\x9c\x05\u81c1z\x9d\xd0t\x8d\x96\xf3A\xaa\x89\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xfa\f\x1a\x98\x8c\x8a\x17\xad5(\xeb(\xb3@\x9d\xaaX\"_&\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa\x10_\x1a\x11\xb6\xe4\xb1\xf5`\x12\xa2y\"\xe2\xac-\xa4\x81/\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfa\x14/\xe4~\u0697\xe6P;8k\x18\xa2\xbe\xdds\u0335\xb1\x89.\x15:\xd8\x15H\x10\x00\x00\u07d4\xfa\x14\xb5f#J\xbe\xe70B\xc3\x1d!qq\x82\u02e1J\xa1\x89\x11\xc7\xea\x16.x \x00\x00\u07d4\xfa\x19\xd6\xf7\xa5\x0fO\a\x98\x93\xd1g\xbf\x14\xe2\x1d\x00s\u0456\x89\x1c\xbb:?\xf0\x8d\b\x00\x00\u07d4\xfa\x1f\x19q\xa7u\xc3PO\xefPy\xf6@\xc2\u013c\xe7\xac\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfa'\x9b\xfd\x87g\xf9V\xbf\u007f\xa0\xbdV`\x16\x8d\xa7V\x86\xbd\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xfa'\xccI\xd0\vl\x98s6\xa8u\xae9\xdaX\xfb\x04\x1b.\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfa(2\x99`=\x87X\xe8\u02b0\x82\x12],\x8f}DT)\x8a\x01[\xca\xcb\x1e\x05\x01\xae\x80\x00\u07d4\xfa+\xbc\xa1]?\u37ca2\x8e\x91\xf9\r\xa1Oz\xc6%=\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa/\u049d\x03\xfe\xe9\xa0x\x93\xdf:&\x9fV\xb7/.\x1ed\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfa3U2\x85\xa9sq\x9a\r_\x95o\xf8a\xb2\u061e\xd3\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\fK\x90?n\xa5.\xa7\xab{\x88c\xb6\xa6\x16\xadfP\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\x1a\xa4H\x8b5\x1a\xa7V\f\xf5\xeec\n/\xd4\\2\"\x89/\xa4~j\xa74\r\x00\x00\u07d4\xfaA\tq\xad\"\x9c06\xf4\x1a\u03c5/*\u0259(\x19P\x89\u0633\x11\xa8\xdd\xfa|\x00\x00\u07d4\xfaD\xa8U\xe4\x04\xc8m\f\xa8\xef3$%\x1d\xfb4\x9cS\x9e\x89T\"S\xa1&\xce@\x00\x00\xe0\x94\xfaR\x01\xfe\x13B\xaf\x110{\x91B\xa0A$<\xa9./\t\x8a 8\x11j:\xc0C\x98\x00\x00\xe0\x94\xfa`\x86\x8a\xaf\xd4\xffL\\W\x91K\x8e\u054bBWs\u07e9\x8a\x01\xcf\xe5\xc8\b\xf3\x9f\xbc\x00\x00\u07d4\xfag\xb6{O7\xa0\x15\t\x15\x11\x0e\xde\a;\x05\xb8S\xbd\xa2\x89#\x19\xba\x94sq\xad\x00\x00\u07d4\xfah\xe0\xcb>\xdfQ\xf0\xa6\xf2\x11\u0272\xcb^\a<\x9b\xff\xe6\x89\x0f\xc969(\x01\xc0\x00\x00\xe0\x94\xfaj7\xf0\x18\xe9yg\x93\u007f\xc5\xe8a{\xa1\u05c6\xdd_w\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xfav\x06C[5l\xee%{\xd2\xfc\xd3\xd9\xea\xcb<\xd1\xc4\xe1\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfaz\xdff\v\x8d\x99\xce\x15\x93=|_\a/<\xbe\xb9\x9d3\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfa\x86\xca'\xbf(T\u0648p\x83\u007f\xb6\xf6\xdf\xe4\xbfdS\xfc\x89\x11u~\x85%\xcf\x14\x80\x00\u07d4\xfa\x8c\xf4\xe6'i\x8c]W\x88\xab\xb7\x88\x04\x17\xe7P#\x13\x99\x89\xe6\x1a6\x96\xee\xf6\x10\x00\x00\u07d4\xfa\x8e;\x1f\x13C9\x00s}\xaa\xf1\xf6)\x9cH\x87\xf8[_\x89&\u009eG\u0104L\x00\x00\u07d4\xfa\x9e\xc8\xef\xe0\x86\x86\xfaX\xc1\x813Xr\xbai\x85`\ucac9lj\xccg\u05f1\xd4\x00\x00\u07d4\xfa\xad\x90]\x84|{#A\x8a\xee\xcb\xe3\xad\u06cd\xd3\xf8\x92J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xfa\xae\xba\x8f\xc0\xbb\xdaU<\xa7.0\xef=s.&\xe8 A\x89H\x8d(*\xaf\xc9\xf6\x80\x00\u07d4\xfa\xb4\x87P\r\xf2\x0f\xb8>\xbe\xd9\x16y\x1dV\x17r\xad\xbe\xbf\x89lkLM\xa6\u077e\x00\x00\u07d4\xfa\xc5\u0294u\x80x\xfb\xfc\xcd\x19\xdb5X\xda~\u8827h\x897(\xa6+\r\xcf\xf6\x00\x00\u07d4\xfa\xd9j\xb6\xacv\x8a\xd5\t\x94R\xacGw\xbd\x1aG\xed\u010f\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfa\xe7g\x19\xd9~\xacA\x87\x04(\xe9@'\x9d\x97\xddW\xb2\xf6\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xfa\u8053pG\x89Zf\f\xf2)v\x0f'\xe6h(\xd6C\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xfa\xe9,\x13p\xe9\u115a]\xf8;V\xd0\xf5\x86\xaa;@L\x89\x05\u0174\xf3\xd8C\x98\x00\x00\xe0\x94\xfa\xf5\xf0\xb7\xb6\xd5X\xf5\t\r\x9e\xa1\xfb-B%\x9cX`x\x8a\x01Z\xff\xb8B\fkd\x00\x00\xe0\x94\xfb\x12o\x0e\xc7i\xf4\x9d\xce\xfc\xa2\xf2\x00(dQX0\x84\xb8\x8a\x01\x0f\xcb\xc25\x03\x96\xbf\x00\x00\xe0\x94\xfb\x13^\xb1Z\x8b\xacr\xb6\x99\x154*`\xbb\xc0k~\a|\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\"<\x1e\"\xea\xc1&\x9b2\xee\x15jS\x85\x92.\xd3o\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb7\xcfkO\x81\xa9\xe2\"\xfb\xa2.\x9b\xd2KP\x98\xb73\u03c9\x02\x1auJm\xc5(\x00\x00\u07d4\xfb8`\xf4\x12\x1cC.\xbd\xc8\xecj\x031\xb1\xb7\ty.\x90\x89 \x8c9J\xf1\u0208\x00\x00\u07d4\xfb9\x18\x9a\xf8v\xe7b\xc7\x1dl>t\x18\x93\xdf\"l\xed\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfb:\v\rkjq\x8fo\xc0)*\x82]\xc9$z\x90\xa5\u0409\n\xd6\xdd\x19\x9e\x97[\x00\x00\xe0\x94\xfb?\xa1\xac\b\xab\xa9\xcc;\xf0\xfe\x9dH8 h\x8fe\xb4\x10\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xfb?\xe0\x9b\xb86\x86\x15)\xd7Q\x8d\xa2v5\xf58PV\x15\x89K\xe3\x92\x16\xfd\xa0p\x00\x00\xe0\x94\xfbQ%\xbf\x0f^\xb0\xb6\xf0 \xe5k\xfc/\xdf=@,\t~\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfbU\x18qL\xef\xc3m\x04\x86]\xe5\x91^\xf0\xffG\xdf\xe7C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb_\xfa\xa0\xf7aW&5x\x91GX\x18\x93\x9d 7\u03d6\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfbh\\\x15\xe49\x96^\xf6&\xbf\r\x83L\u0468\x9f+V\x95\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xfbtK\x95\x1d\tK1\x02b\xc8\xf9\x86\xc8`\u07da\xb1\xdee\x89\x02\xd1\xc5\x15\xf1\xcbJ\x80\x00\u07d4\xfby\xab\u06d2\\U\xb9\xf9\x8e\xfe\xefd\xcf\xc9\xeba\xf5\x1b\xb1\x89a@\xc0V\xfb\n\xc8\x00\x00\u07d4\xfb\x81\x13\xf9M\x91s\xee\xfdZ0s\xf5\x16\x80:\x10\xb2\x86\xae\x89\x04V9\x18$O@\x00\x00\u07d4\xfb\x84,\xa2\xc5\xef\x139\x17\xa26\xa0\u052c@i\x01\x10\xb08\x89\x10\x96\x9ab\xbe\x15\x88\x00\x00\u07d4\xfb\x91\xfb\x1aiUS\xf0\u018e!'m\xec\xf0\xb89\t\xb8m\x89\x05l\x006\x17\xafx\x00\x00\u07d4\xfb\x94s\xcfw\x125\n\x1f\xa09Rs\xfc\x80V\aR\xe4\xfb\x89\x06\xaf!\x98\xba\x85\xaa\x00\x00\xe0\x94\xfb\x94\x9cd\u007f\xdc\xfd%\x14\xc7\u054e1\xf2\x8aS-\x8cX3\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\xa5HmS\xc6\xe2@IBA\xab\xf8~C\xc7`\rA:\x89k\xbfaIIH4\x00\x00\u07d4\xfb\xb1a\xfe\x87_\t)\nK&+\xc6\x01\x10\x84\x8f\r\"&\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb\xbb\xeb\u03fe#^W\xdd#\x06\xad\x1a\x9e\u0141\xc7\xf9\xf4\x8f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfb\xc0\x1d\xb5NG\xcd\xc3\xc48iJ\xb7\x17\xa8V\xc2?\xe6\xe9\x8a\x01\xcaqP\xab\x17OG\x00\x00\xe0\x94\xfb\xcf\xccJ{\x0f&\xcf&\xe9\xf33!2\xe2\xfcj#\af\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfb\xe7\x16\"\xbc\xbd1\xc1\xa3iv\xe7\xe5\xf6p\xc0\u007f\xfe\x16\u0789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfb\xed\xe3,4\x9f3\x00\xefL\xd3;M\xe7\xdc\x18\xe4C\xd3&\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xfb\xf2\x04\xc8\x13\xf86\xd89b\u01c7\fx\b\xca4\u007f\xd3>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfb\xf7Y3\xe0\x1bu\xb1T\xef\x06i\ak\xe8\u007fb\xdf\xfa\xe1\x8a\x10\x84cr\xf2I\xd4\xc0\x00\x00\u07d4\xfc\x00\x96\xb2\x1e\x95\xac\xb8\xd6\x19\xd1v\xa4\xa1\xd8\xd5)\xba\xdb\xef\x89\x14\xd9i;\xcb\xec\x02\x80\x00\xe0\x94\xfc\x00\xa4 \xa3a\a\xdf\xd5\xf4\x95\x12\x8a_\u5af2\xdb\x0f4\x8a\x01C\x17\x9d\x86\x91\x10 \x00\x00\xe0\x94\xfc\x01\x8ai\n\xd6tm\xbe:\u03d7\x12\xdd\xcaR\xb6%\x009\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfc\x02s@3\xe5\u007fpQ~\n\xfc~\xe6$a\xf0o\xad\x8e\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfc\x0e\xe6\xf7\u00b3qJ\xe9\x91lEVf\x05\xb6V\xf3$A\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xfc\x10\xb7\xa6{2h\xd53\x1b\xfbj\x14\xde\xf5\xeaJ\x16,\xa3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfc\x15\u02d9\xa8\xd1\x03\v\x12w\n\xdd\x03:y\xee\r\f\x90\x8c\x89\x12\xfa\x00\xbdR\xe6$\x00\x00\u07d4\xfc)R\xb4\u011f\xed\u043c\x05(\xa3\bI^mj\x1cq\u0589lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc,\x1f\x88\x96\x1d\x01\x9c>\x9e\xa30\t\x15.\x06\x93\xfb\xf8\x8a\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xfc6\x11\x05\u0750\xf9\xed\xe5fI\x9di\xe9\x13\x03\x95\xf1*\u020aS\xa4\xfe/ N\x80\xe0\x00\x00\u07d4\xfc7/\xf6\x92|\xb3\x96\xd9\xcf)\x805\x00\x11\r\xa62\xbcR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc9\xbeA\tK\x19\x97\xd2\x16\x9e\x82d\xc2\u00fa\xa6\u025b\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc=\"k\xb3jX\xf5&V\x88W\xb0\xbb\x12\xd1\t\xec\x93\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfcC\x82\x9a\u01c7\xff\x88\xaa\xf1\x83\xba5*\xad\xbfZ\x15\xb1\x93\x89\u05ac\n+\x05R\xe0\x00\x00\u07d4\xfcI\xc1C\x9aA\u05b3\xcf&\xbbg\xe06R$\xe5\xe3\x8f_\x8966\u05ef^\u024e\x00\x00\u07d4\xfcU\x00\x82Q\x05\xcfq*1\x8a^\x9c;\xfci\u021d\f\x12\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xfcf\xfa\xba'\u007fK]\xe6J\xd4^\xb1\x9c1\xe0\f\xed>\u054a\x011\xbe\xb9%\xff\xd3 \x00\x00\xe0\x94\xfc~\"\xa5\x03\xecZ\xbe\x9b\b\xc5\v\xd1I\x99\xf5 \xfaH\x84\x8a\x01ZG}\xfb\xe1\xea\x14\x80\x00\u07d4\xfc\x82\x15\xa0\xa6\x99\x13\xf6*C\xbf\x1c\x85\x90\xb9\xdd\xcd\r\x8d\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc\x98\x9c\xb4\x87\xbf\x1a}\x17\xe4\xc1\xb7\u0137\xaa\xfd\xdak\n\x8d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfc\x9b4td\xb2\xf9\x92\x9d\x80~\x03\x9d\xaeH\xd3\u064d\xe3y\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xfc\xa4;\xbc#\xa0\xd3!\xba\x9eF\xb9)s\\\xe7\xd8\xef\f\x18\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfc\xa7>\xff\x87q\xc0\x10;\xa3\xcc\x1a\x9c%\x94H\xc7*\xbf\v\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xad\xa3\x00(?k\xcc\x13J\x91Eg`\xb0\xd7}\xe4\x10\xe0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc\xbc\\q\xac\xe7\x97AE\v\x01,\xf6\xb8\xd3\xf1}\xb6\x8ap\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfc\xbd\x85\xfe\xeajuO\xcf4ID\x9e7\xff\x97\x84\xf7w<\x89\xa7J\xdai\xab\xd7x\x00\x00\xe0\x94\xfc\xc9\u0524&.z\x02z\xb7Q\x91\x10\xd8\x02\u0115\xce\xea9\x8a\x01YQ\x82\"K&H\x00\x00\xe0\x94\xfc\xcd\r\x1e\xce\xe2z\xdd\xea\x95\xf6\x85z\xee\xc8\u01e0K(\xee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfc\u0434\x82|\xd2\b\xff\xbf^u\x9d\xba\x8c<\xc6\x1d\x8c,<\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfc\xe0\x89c\\\xe9z\xba\xc0kD\x81\x9b\xe5\xbb\n>.\v7\x89\x05\x03\x92\nv0\xa7\x80\x00\u07d4\xfc\xf1\x99\xf8\xb8T\"/\x18.N\x1d\t\x9dN2>*\xae\x01\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xfc:P\x04\xd6xa?\v6\xa6B&\x9a\u007f7\x1c?j\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x19\x1a5\x15}x\x13s\xfbA\x1b\xf9\xf2R\x90\x04|^\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x1f\xaa4{\x0f\u0300L-\xa8l6\xd5\xf1\u044bp\x87\xbb\x89\x02\xd6\xeb$z\x96\xf6\x00\x00\u07d4\xfd\x1f\xb5\xa8\x9a\x89\xa7!\xb8yph\xfb\xc4\u007f>\x9dR\xe1I\x89\f\u0435\x83\u007f\xc6X\x00\x00\u07d4\xfd OOJ\xba%%\xbar\x8a\xfd\xf7\x87\x92\xcb\u07b75\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd'W\xcc5Q\xa0\x95\x87\x8d\x97\x87V\x15\xfe\fj2\xaa\x8a\x89 m\xb1R\x99\xbe\xac\x00\x00\u07d4\xfd(r\u045eW\x85<\xfa\x16\xef\xfe\x93\u0431\xd4{O\x93\xfb\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd))'\x1e\x9d \x95\xa2dv~{\r\xf5.\xa0\xd1\xd4\x00\x89\xa2\xa1\xeb%\x1bZ\xe4\x00\x00\u07d4\xfd7z8Rr\x90\f\xb46\xa3\xbbyb\xcd\xff\xe9?]\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd@$+\xb3Jp\x85^\xf0\xfd\x90\xf3\x80-\xec!6\xb3'\x89h\xa8u\a>)$\x00\x00\xe0\x94\xfdE,9i\xec\xe3\x80\x1cT \xf1\xcd\u02a1\xc7\x1e\xd2=\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xfdKU\x1fo\xdb\u0366\xc5\x11\xb5\xbb7\"P\xa6\xb7\x83\xe54\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xfdK\x98\x95X\xae\x11\xbe\f;6\xe2\xd6\xf2\xa5J\x93C\xca.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfdM\xe8\xe3t\x8a(\x9c\xf7\xd0`Q}\x9d88\x8d\xb0\x1f\xb8\x89\r\x8drkqw\xa8\x00\x00\u07d4\xfdZc\x15\u007f\x91O\u04d8\uac5c\x13}\xd9U\v\xb7q\\\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xfd`\u04b5\xaf=5\xf7\xaa\xf0\u00d3\x05.y\xc4\xd8#\u0645\x89\x03\x0e\xb5\r.\x14\b\x00\x00\u07d4\xfdhm\xe5?\xa9\u007f\x99c\x9e%hT\x97 \xbcX\x8c\x9e\xfc\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xfd~\u078fR@\xa0eA\xebi\x9dx,/\x9a\xfb!p\xf6\x89Hz\x9a0E9D\x00\x00\u07d4\xfd\x81+\u019f\xb1p\xefW\xe22~\x80\xaf\xfd\x14\xf8\xe4\xb6\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\x88\xd1\x14\"\x0f\b\x1c\xb3\xd5\xe1[\xe8\x15*\xb0sfWj\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xfd\x91\x856\xa8\xef\xa6\xf6\xce\xfe\x1f\xa1\x159\x95\xfe\xf5\xe3=;\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfd\x92\x0fr&\x82\xaf\xb5\xafE\x1b\x05D\xd4\xf4\x1b;\x9dWB\x89~R\x05j\x12?<\x00\x00\u07d4\xfd\x95y\xf1\x19\xbb\xc8\x19\xa0+a\u3348\x03\xc9B\xf2M2\x89\x05\xb9~\x90\x81\xd9@\x00\x00\u07d4\xfd\xa0\xce\x153\a\a\xf1\v\xce2\x01\x17- \x18\xb9\xdd\xeat\x89\x02\xd0A\xd7\x05\xa2\xc6\x00\x00\xe0\x94\xfd\xa3\x04(\x19\xaf>f)\x00\xe1\xb9+CX\xed\xa6\xe9%\x90\x8a\x19\a\xa2\x84\u054fc\xe0\x00\x00\u07d4\xfd\xa6\x81\x0e\xa5\xac\x98]o\xfb\xf1\xc5\x11\xf1\xc1B\xed\xcf\xdd\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd\xb39D\xf26\x06\x15\xe5\xbe#\x95w\u0221\x9b\xa5-\x98\x87\x89 \x9d\x92/RY\xc5\x00\x00\u07d4\xfd\xbaSY\xf7\xec;\xc7p\xacI\x97]\x84N\xc9qbV\xf1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xfd\xc4\xd4vZ\x94/[\xf9i1\xa9\xe8\xccz\xb8\xb7W\xffL\x8a\x12lG\x8a\x0e>\xa8`\x00\x00\xe0\x94\xfd\xcd]\x80\xb1\x05\x89zW\xab\xc4xev\x8b)\x00RB\x95\x8a\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u0794\xfd\xd1\x19_y}O5q}\x15\xe6\xf9\x81\n\x9a?\xf5T`\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xfd\xd5\x02\xa7N\x81;\u03e3U\xce\xda<\x17ojhq\xaf\u007f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfd\u357c\vm\\\xbbL\x1d\x8f\xea>\vK\xffc^\x9d\xb7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xea\xac*\xcf\x1d\x13\x8e\x19\xf2\xfc?\x9f\xb7E\x92\xe3\ud04a\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xfd\xec\xc8-\xdf\xc5a\x92\xe2oV<=h\xcbTJ\x96\xbf\xed\x89\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4\xfd\xf4#C\x01\x9b\v\fk\xf2`\xb1s\xaf\xab~E\xb9\xd6!\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xfd\xf4I\xf1\b\xc6\xfbOZ+\b\x1e\xed~E\u645eM%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xfda4\xc0J\x8a\xb7\xeb\x16\xf0\x06C\xf8\xfe\xd7\u06aa\ucc89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfe\x00\xbfC\x99\x11\xa5S\x98-\xb68\x03\x92E\xbc\xf02\xdb\u0709\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfe\x01n\xc1~\xc5\xf1\x0e;\xb9\x8f\xf4\xa1\xed\xa0E\x15v\x82\xab\x89\x14_T\x02\xe7\xb2\xe6\x00\x00\u07d4\xfe\x0e0\xe2\x14)\rt=\xd3\x0e\xb0\x82\xf1\xf0\xa5\"Z\xdea\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe!\v\x8f\x04\xdcmOv!j\xcf\xcb\u055b\xa8;\xe9\xb60\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\"\xa0\xb3\x88f\x8d\x1a\xe2d>w\x1d\xac\xf3\x8aCB#\u0309\xd8\xdb^\xbd{&8\x00\x00\u07d4\xfe6&\x88\x84_\xa2D\u0300~K\x110\xeb7A\xa8\x05\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe8'\xd5v0\u03c7a\xd5\x12y{\v\x85\x8eG\x8b\xbd\x12\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfeA\x8bB\x1a\x9cm76\x02y\x04u\xd20>\x11\xa7Y0\x897\b\xba\xed=h\x90\x00\x00\u07d4\xfeBI\x12yP\xe2\xf8\x96\xec\x0e~.=\x05Z\xab\x10U\x0f\x89$=M\x18\"\x9c\xa2\x00\x00\xe0\x94\xfeM\x84\x03!o\xd5qW+\xf1\xbd\xb0\x1d\x00W\x89x\u0588\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xfeS\xb9I\x89\u0619d\xda aS\x95&\xbb\xe9y\xdd.\xa9\x89h\xa8u\a>)$\x00\x00\u07d4\xfeT\x9b\xbf\xe6G@\x18\x98\x92\x93%8\u06afF\u04b6\x1dO\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfea]\x97\\\b\x87\xe0\xc9\x11>\xc7)\x84 \xa7\x93\xaf\x8b\x96\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfee\xc4\x18\x8dy\"Wi\td D\xfd\xc5#\x95V\x01e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfei\u007f\xf2,\xa5G\xbf\xc9^3\xd9`\xda`\\gc\xf3[\x89G\xd4\x11\x9f\xd9`\x94\x00\x00\u07d4\xfej\x89[y\\\xb4\xbf\x85\x90=<\xe0\x9cZ\xa49S\u04ff\x89\xb8Pz\x82\a( \x00\x00\u07d4\xfeo_B\xb6\x19;\x1a\xd1b\x06\u4bf5#\x9dM}\xb4^\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xfep\x11\xb6\x98\xbf3q\x13-tE\xb1\x9e\xb5\xb0\x945j\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x80\xe9#-\xea\xff\x19\xba\xf9\x98i\x88:K\xdf\x00\x04\xe5<\x89.b\xf2\ni\xbe@\x00\x00\u07d4\xfe\x8en6eW\r\xffz\x1b\xdaiz\xa5\x89\xc0\xb4\xe9\x02J\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x8f\x1f\u072b\u007f\xbe\u0266\xa3\xfc\xc5\aa\x96\x00P\\6\xa3\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xfe\x91\xec\xcf+\xd5f\xaf\xa1\x16\x96\xc5\x04\x9f\xa8Lic\nR\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xfe\x96\xc4\xcd8\x15b@\x1a\xa3*\x86\xe6[\x9dR\xfa\x8a\xee'\x89\x8f\x1d\\\x1c\xae7@\x00\x00\u07d4\xfe\x98\xc6d\xc3\xe4G\xa9^i\xbdX!q\xb7\x17n\xa2\xa6\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfe\x9a\xd1.\xf0]m\x90&\x1f\x96\xc84\n\x03\x81\x97M\xf4w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x9c\x0f\xff\xef\xb8\x03\b\x12V\xc0\xcfMfY\xe6\xd3>\xb4\xfb\x89R\xd5B\x80O\x1c\xe0\x00\x00\u07d4\xfe\x9c\xfc;\xb2\x93\u0772\x85\xe6%\xf3X/t\xa6\xb0\xa5\xa6\u0349j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xfe\x9e\x11\x97\u05d7JvH\xdc\u01e01\x12\xa8\x8e\xdb\xc9\x04]\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\xe0\x94\xfe\xac\xa2\xactbK\xf3H\xda\u0258QC\xcf\xd6R\xa4\xbeU\x8a\x05\x89\u007f\u02f0)\x14\b\x80\x00\u07d4\xfe\xad\x18\x03\xe5\xe77\xa6\x8e\x18G-\x9a\xc7\x15\xf0\x99L\u00be\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfe\xb8\xb8\xe2\xafqj\xe4\x1f\xc7\xc0K\xcf)T\x01VF\x1ek\x89TQt\xa5(\xa7z\x00\x00\u07d4\xfe\xb9-0\xbf\x01\xff\x9a\x19\x01flUsS+\xfa\a\xee\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe\xbc1s\xbc\x90r\x13cT\x00+{O\xb3\xbf\xc5?\"\xf1\x89\x14\x0e\xc8\x0f\xa7\xee\x88\x00\x00\u07d4\xfe\xbdH\xd0\xff\xdb\xd5el\xd5\xe6\x866:a\x14R(\xf2y\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xfe\xbd\x9f\x81\xcfx\xbd_\xb6\u0139\xa2K\xd4\x14\xbb\x9b\xfaLN\x89k\xe1\x0f\xb8\xedn\x13\x80\x00\u07d4\xfe\xc0o\xe2{D\u01c4\xb29n\xc9/{\x92:\xd1~\x90w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\xc1NT\x85\xde+>\xef^t\xc4aF\u06ceEN\x035\x89\t\xb4\x1f\xbf\x9e\n\xec\x00\x00\u07d4\xfe\xd8Gm\x10\u0544\xb3\x8b\xfag7`\x0e\xf1\x9d5\xc4\x1e\u0609b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xfe\xef;n\xab\xc9J\xff\xd31\f\x1cM\x0ee7^\x13\x11\x19\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\xf0\x9dp$?9\xed\x8c\xd8\x00\xbf\x96QG\x9e\x8fJ\xca<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe\xf3\xb3\u07ad\x1ai&\u051a\xa3+\x12\xc2*\xf5M\x9f\xf9\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xff\v|\xb7\x1d\xa9\xd4\xc1\xean\xcc(\xeb\xdaPLc\xf8/\u04498\x8a\x88]\xf2\xfcl\x00\x00\u07d4\xff\f\xc6\u73c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xff'&)AH\xb8lx\xa97$\x97\xe4Y\x89\x8e\xd3\xfe\xe3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xff=\xedz@\u04ef\xf0\u05e8\xc4_\xa6\x13j\xa0C=\xb4W\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xff>\xeeW\xc3Mm\xae\x97\r\x8b1\x11\x17\xc55\x86\xcd5\x02\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xff>\xf6\xba\x15\x1c!\xb5\x99\x86\xaed\xf6\xe8\"\x8b\u0262\xc73\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xffA\xd9\xe1\xb4\xef\xfe\x18\u0630\xd1\xf6?\xc4%_\xb4\xe0l=\x89Hz\x9a0E9D\x00\x00\u07d4\xffE\xcb4\xc9(6M\x9c\xc9\u063b\x0074ta\x8f\x06\xf3\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xffI\xa7u\x81N\xc0\x00Q\xa7\x95\xa8u\xde$Y.\xa4\x00\u050a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xffJ@\x8fP\xe9\xe7!F\xa2\x8c\xe4\xfc\x8d\x90'\x1f\x11n\x84\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xffM\x9c\x84\x84\xc4\x10T\x89H\xa4\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xe0\x94L*\xe4\x82Y5\x05\xf0\x16<\xde\xfc\a>\x81\xc6<\xdaA\a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xa8\xe8\xf1G2e\x8eKQ\xe8q\x191\x05:\x8ai\xba\xf2\xb1\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe1\x94\u0665\x17\x9f\t\x1d\x85\x05\x1d<\x98'\x85\xef\xd1E\\\uc199\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\u08bdBX\xd2v\x887\xba\xa2j(\xfeq\xdc\a\x9f\x84\u01cbJG\xe3\xc1$H\xf4\xad\x00\x00\x00" const sepoliaAllocData = "\xf9\x01\xee\u0791i\x16\xa8{\x823?BE\x04f#\xb27\x94\xc6\\\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\x10\xf5\xd4XT\xe08\a\x14\x85\xac\x9e@#\b\u03c0\xd2\xd2\xfe\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\u0794y\x9d2\x9e_X4\x19\x16|\xd7\"\x96$\x85\x92n3\x8fJ\x88\r\u0db3\xa7d\x00\x00\xe0\x94|\xf5\xb7\x9b\xfe)\x1ag\xab\x02\xb3\x93\xe4V\xcc\xc4\xc2f\xf7S\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x8b\u007f\tw\xbbO\x0f\xbepv\xfa\"\xbc$\xac\xa0CX?^\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa2\xa6\xd949\x14O\xfeM'\xc9\xe0\x88\xdc\u0637\x83\x94bc\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xaa\xec\x869DA\xf9\x15\xbc\xe3\xe6\xab9\x99w\xe9\x90o;i\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u1532\x1c3\xde\x1f\xab?\xa1T\x99\xc6+Y\xfe\f\xc3%\x00 \u044bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xbc\x11)Y6\xaay\u0554\x13\x9d\xe1\xb2\xe1&)AO;\u06ca\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xbe\xef2\xca[\x9a\x19\x8d'\xb4\xe0/LpC\x9f\xe6\x03V\u03ca\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\xd7\xd7lX\xb3\xa5\x19\xe9\xfal\xc4\xd2-\xc0\x17%\x9b\u011f\x1e\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xd7\xed\xdbx\xed)[<\x96)$\x0e\x89$\xfb\x8d\x88t\xdd\u060a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\u0665\x17\x9f\t\x1d\x85\x05\x1d<\x98'\x85\xef\xd1E\\\uc199\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xe2\xe2e\x90(\x147\x84\xd5W\xbc\xeco\xf3\xa0r\x10H\x88\n\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xf4|\xae\x1c\xf7\x9c\xa6u\x8b\xfcx}\xbd!\u6f7eq\x12\xb8\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00" const holeskyAllocData = "\xf9,\x85\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\x7f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\u0791i\x16\xa8{\x823?BE\x04f#\xb27\x94\xc6\\\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94\v\xe9I\x92\x8f\xf1\x99\xc9\xeb\xa9\xe1\x10\xdb!\n\xa5\xc9N\xfa\u040b|\x13\xbcK,\x13\x8e\u0344h\xa0\x03\x7f\x05\x8a\x9d\xaf\xady\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xf9!2\x94BBBBBBBBBBBBBBBBBBBB\x80\xf9!\x19\x80\xb9\x18\xd6`\x80`@R`\x046\x10a\x00?W`\x005`\xe0\x1c\x80c\x01\xff\u0267\x14a\x00DW\x80c\"\x89Q\x18\x14a\x00\xa4W\x80cb\x1f\xd10\x14a\x01\xbaW\x80c\xc5\xf2\x89/\x14a\x02DW[`\x00\x80\xfd[4\x80\x15a\x00PW`\x00\x80\xfd[Pa\x00\x90`\x04\x806\x03` \x81\x10\x15a\x00gW`\x00\x80\xfd[P5\x7f\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16a\x02kV[`@\x80Q\x91\x15\x15\x82RQ\x90\x81\x90\x03` \x01\x90\xf3[a\x01\xb8`\x04\x806\x03`\x80\x81\x10\x15a\x00\xbaW`\x00\x80\xfd[\x81\x01\x90` \x81\x01\x815d\x01\x00\x00\x00\x00\x81\x11\x15a\x00\xd5W`\x00\x80\xfd[\x82\x01\x83` \x82\x01\x11\x15a\x00\xe7W`\x00\x80\xfd[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\x00\x00\x00\x00\x83\x11\x17\x15a\x01\tW`\x00\x80\xfd[\x91\x93\x90\x92\x90\x91` \x81\x01\x905d\x01\x00\x00\x00\x00\x81\x11\x15a\x01'W`\x00\x80\xfd[\x82\x01\x83` \x82\x01\x11\x15a\x019W`\x00\x80\xfd[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\x00\x00\x00\x00\x83\x11\x17\x15a\x01[W`\x00\x80\xfd[\x91\x93\x90\x92\x90\x91` \x81\x01\x905d\x01\x00\x00\x00\x00\x81\x11\x15a\x01yW`\x00\x80\xfd[\x82\x01\x83` \x82\x01\x11\x15a\x01\x8bW`\x00\x80\xfd[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\x00\x00\x00\x00\x83\x11\x17\x15a\x01\xadW`\x00\x80\xfd[\x91\x93P\x91P5a\x03\x04V[\x00[4\x80\x15a\x01\xc6W`\x00\x80\xfd[Pa\x01\xcfa\x10\xb5V[`@\x80Q` \x80\x82R\x83Q\x81\x83\x01R\x83Q\x91\x92\x83\x92\x90\x83\x01\x91\x85\x01\x90\x80\x83\x83`\x00[\x83\x81\x10\x15a\x02\tW\x81\x81\x01Q\x83\x82\x01R` \x01a\x01\xf1V[PPPP\x90P\x90\x81\x01\x90`\x1f\x16\x80\x15a\x026W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\x00\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xf3[4\x80\x15a\x02PW`\x00\x80\xfd[Pa\x02Ya\x10\xc7V[`@\x80Q\x91\x82RQ\x90\x81\x90\x03` \x01\x90\xf3[`\x00\x7f\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x16\x7f\x01\xff\u0267\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x80a\x02\xfeWP\x7f\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x16\x7f\x85d\t\a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14[\x92\x91PPV[`0\x86\x14a\x03]W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80a\x18\x05`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[` \x84\x14a\x03\xb6W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`6\x81R` \x01\x80a\x17\x9c`6\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[``\x82\x14a\x04\x0fW`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`)\x81R` \x01\x80a\x18x`)\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[g\r\u0db3\xa7d\x00\x004\x10\x15a\x04pW`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80a\x18R`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[c;\x9a\xca\x004\x06\x15a\x04\xcdW`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`3\x81R` \x01\x80a\x17\xd2`3\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[c;\x9a\xca\x004\x04g\xff\xff\xff\xff\xff\xff\xff\xff\x81\x11\x15a\x055W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`'\x81R` \x01\x80a\x18+`'\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[``a\x05@\x82a\x14\xbaV[\x90P\x7fd\x9b\xbcb\xd0\xe3\x13B\xaf\xeaN\\\xd8-@I\xe7\xe1\xee\x91/\xc0\x88\x9a\xa7\x90\x80;\xe3\x908\u0149\x89\x89\x89\x85\x8a\x8aa\x05u` Ta\x14\xbaV[`@\x80Q`\xa0\x80\x82R\x81\x01\x89\x90R\x90\x81\x90` \x82\x01\x90\x82\x01``\x83\x01`\x80\x84\x01`\xc0\x85\x01\x8e\x8e\x80\x82\x847`\x00\x83\x82\x01R`\x1f\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x16\x90\x91\x01\x87\x81\x03\x86R\x8c\x81R` \x01\x90P\x8c\x8c\x80\x82\x847`\x00\x83\x82\x01\x81\x90R`\x1f\x90\x91\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x16\x90\x92\x01\x88\x81\x03\x86R\x8cQ\x81R\x8cQ` \x91\x82\x01\x93\x91\x8e\x01\x92P\x90\x81\x90\x84\x90\x84\x90[\x83\x81\x10\x15a\x06HW\x81\x81\x01Q\x83\x82\x01R` \x01a\x060V[PPPP\x90P\x90\x81\x01\x90`\x1f\x16\x80\x15a\x06uW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\x00\n\x03\x19\x16\x81R` \x01\x91P[P\x86\x81\x03\x83R\x88\x81R` \x01\x89\x89\x80\x82\x847`\x00\x83\x82\x01\x81\x90R`\x1f\x90\x91\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x16\x90\x92\x01\x88\x81\x03\x84R\x89Q\x81R\x89Q` \x91\x82\x01\x93\x91\x8b\x01\x92P\x90\x81\x90\x84\x90\x84\x90[\x83\x81\x10\x15a\x06\xefW\x81\x81\x01Q\x83\x82\x01R` \x01a\x06\xd7V[PPPP\x90P\x90\x81\x01\x90`\x1f\x16\x80\x15a\a\x1cW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\x00\n\x03\x19\x16\x81R` \x01\x91P[P\x9dPPPPPPPPPPPPPP`@Q\x80\x91\x03\x90\xa1`\x00`\x02\x8a\x8a`\x00`\x80\x1b`@Q` \x01\x80\x84\x84\x80\x82\x847\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x94\x16\x91\x90\x93\x01\x90\x81R`@\x80Q\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x81\x84\x03\x01\x81R`\x10\x90\x92\x01\x90\x81\x90R\x81Q\x91\x95P\x93P\x83\x92P` \x85\x01\x91P\x80\x83\x83[` \x83\x10a\a\xfcW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\a\xbfV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\bYW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\bnW`\x00\x80\xfd[PQ\x90P`\x00`\x02\x80a\b\x84`@\x84\x8a\x8ca\x16\xfeV[`@Q` \x01\x80\x83\x83\x80\x82\x847\x80\x83\x01\x92PPP\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\b\xf8W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\b\xbbV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\tUW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\tjW`\x00\x80\xfd[PQ`\x02a\t{\x89`@\x81\x8da\x16\xfeV[`@Q`\x00\x90` \x01\x80\x84\x84\x80\x82\x847\x91\x90\x91\x01\x92\x83RPP`@\x80Q\x80\x83\x03\x81R` \x92\x83\x01\x91\x82\x90R\x80Q\x90\x94P\x90\x92P\x82\x91\x84\x01\x90\x80\x83\x83[` \x83\x10a\t\xf4W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\t\xb7V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\nQW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\nfW`\x00\x80\xfd[PQ`@\x80Q` \x81\x81\x01\x94\x90\x94R\x80\x82\x01\x92\x90\x92R\x80Q\x80\x83\x03\x82\x01\x81R``\x90\x92\x01\x90\x81\x90R\x81Q\x91\x92\x90\x91\x82\x91\x84\x01\x90\x80\x83\x83[` \x83\x10a\n\xdaW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\n\x9dV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\v7W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\vLW`\x00\x80\xfd[PQ`@\x80Q` \x81\x01\x85\x81R\x92\x93P`\x00\x92`\x02\x92\x83\x92\x87\x92\x8f\x92\x8f\x92\x01\x83\x83\x80\x82\x847\x80\x83\x01\x92PPP\x93PPPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\v\xd9W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\v\x9cV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\f6W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\fKW`\x00\x80\xfd[PQ`@Q\x86Q`\x02\x91\x88\x91`\x00\x91\x88\x91` \x91\x82\x01\x91\x82\x91\x90\x86\x01\x90\x80\x83\x83[` \x83\x10a\f\xa9W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\flV[`\x01\x83` \x03a\x01\x00\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x83g\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16g\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x81R`\x18\x01\x82\x81R` \x01\x93PPPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\rNW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\r\x11V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\r\xabW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\r\xc0W`\x00\x80\xfd[PQ`@\x80Q` \x81\x81\x01\x94\x90\x94R\x80\x82\x01\x92\x90\x92R\x80Q\x80\x83\x03\x82\x01\x81R``\x90\x92\x01\x90\x81\x90R\x81Q\x91\x92\x90\x91\x82\x91\x84\x01\x90\x80\x83\x83[` \x83\x10a\x0e4W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\r\xf7V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x0e\x91W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x0e\xa6W`\x00\x80\xfd[PQ\x90P\x85\x81\x14a\x0f\x02W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`T\x81R` \x01\x80a\x17H`T\x919``\x01\x91PP`@Q\x80\x91\x03\x90\xfd[` Tc\xff\xff\xff\xff\x11a\x0f`W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`!\x81R` \x01\x80a\x17'`!\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[` \x80T`\x01\x01\x90\x81\x90U`\x00[` \x81\x10\x15a\x10\xa9W\x81`\x01\x16`\x01\x14\x15a\x0f\xa0W\x82`\x00\x82` \x81\x10a\x0f\x91W\xfe[\x01UPa\x10\xac\x95PPPPPPV[`\x02`\x00\x82` \x81\x10a\x0f\xafW\xfe[\x01T\x84`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x10%W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x0f\xe8V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x10\x82W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x10\x97W`\x00\x80\xfd[PQ\x92P`\x02\x82\x04\x91P`\x01\x01a\x0fnV[P\xfe[PPPPPPPV[``a\x10\xc2` Ta\x14\xbaV[\x90P\x90V[` T`\x00\x90\x81\x90\x81[` \x81\x10\x15a\x12\xf0W\x81`\x01\x16`\x01\x14\x15a\x11\xe6W`\x02`\x00\x82` \x81\x10a\x10\xf5W\xfe[\x01T\x84`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x11kW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x11.V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x11\xc8W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x11\xddW`\x00\x80\xfd[PQ\x92Pa\x12\xe2V[`\x02\x83`!\x83` \x81\x10a\x11\xf6W\xfe[\x01T`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x12kW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x12.V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x12\xc8W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x12\xddW`\x00\x80\xfd[PQ\x92P[`\x02\x82\x04\x91P`\x01\x01a\x10\xd1V[P`\x02\x82a\x12\xff` Ta\x14\xbaV[`\x00`@\x1b`@Q` \x01\x80\x84\x81R` \x01\x83\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x13ZW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x13\x1dV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x95\x90\x95\x16\x92\x01\x91\x82RP`@\x80Q\x80\x83\x03\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x01\x81R`\x18\x90\x92\x01\x90\x81\x90R\x81Q\x91\x95P\x93P\x83\x92\x85\x01\x91P\x80\x83\x83[` \x83\x10a\x14?W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x14\x02V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x14\x9cW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x14\xb1W`\x00\x80\xfd[PQ\x92PPP\x90V[`@\x80Q`\b\x80\x82R\x81\x83\x01\x90\x92R``\x91` \x82\x01\x81\x806\x837\x01\x90PP\x90P`\xc0\x82\x90\x1b\x80`\a\x1a`\xf8\x1b\x82`\x00\x81Q\x81\x10a\x14\xf4W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x06\x1a`\xf8\x1b\x82`\x01\x81Q\x81\x10a\x157W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x05\x1a`\xf8\x1b\x82`\x02\x81Q\x81\x10a\x15zW\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x04\x1a`\xf8\x1b\x82`\x03\x81Q\x81\x10a\x15\xbdW\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x03\x1a`\xf8\x1b\x82`\x04\x81Q\x81\x10a\x16\x00W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x02\x1a`\xf8\x1b\x82`\x05\x81Q\x81\x10a\x16CW\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x01\x1a`\xf8\x1b\x82`\x06\x81Q\x81\x10a\x16\x86W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x00\x1a`\xf8\x1b\x82`\a\x81Q\x81\x10a\x16\xc9W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SPP\x91\x90PV[`\x00\x80\x85\x85\x11\x15a\x17\rW\x81\x82\xfd[\x83\x86\x11\x15a\x17\x19W\x81\x82\xfd[PP\x82\x01\x93\x91\x90\x92\x03\x91PV\xfeDepositContract: merkle tree fullDepositContract: reconstructed DepositData does not match supplied deposit_data_rootDepositContract: invalid withdrawal_credentials lengthDepositContract: deposit value not multiple of gweiDepositContract: invalid pubkey lengthDepositContract: deposit value too highDepositContract: deposit value too lowDepositContract: invalid signature length\xa2dipfsX\"\x12 \x1d\xd2o7\xa6!p0\t\xab\xf1nw\u6713\xdcP\u01dd\xb7\xf6\xcc7T>>\x0e=\xec\u0717dsolcC\x00\x06\v\x003\xf9\b<\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"\xa0\xf5\xa5\xfdB\xd1j 0'\x98\xefn\xd3\t\x97\x9bC\x00=# \xd9\xf0\xe8\xea\x981\xa9'Y\xfbK\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\xa0\xdbV\x11N\x00\xfd\xd4\xc1\xf8\\\x89+\xf3Z\u0268\x92\x89\xaa\xec\xb1\xeb\u0429l\xde`jt\x8b]q\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\xa0\u01c0\t\xfd\xf0\x7f\xc5j\x11\xf1\"7\x06X\xa3S\xaa\xa5B\xedc\xe4LK\xc1_\xf4\xcd\x10Z\xb3<\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\xa0Sm\x98\x83\x7f-\xd1e\xa5]^\xea\xe9\x14\x85\x95Dr\xd5o$m\xf2V\xbf<\xae\x195*\x12<\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\xa0\x9e\xfd\xe0R\xaa\x15B\x9f\xae\x05\xba\xd4\u0431\xd7\xc6M\xa6M\x03\u05e1\x85JX\x8c,\xb8C\f\r0\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\xa0\u060d\xdf\xee\xd4\x00\xa8uU\x96\xb2\x19B\xc1I~\x11L0.a\x18)\x0f\x91\xe6w)v\x04\x1f\xa1\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xa0\x87\xeb\r\u06e5~5\xf6\u0486g8\x02\xa4\xafYu\xe2%\x06\xc7\xcfLd\xbbk\xe5\xee\x11R\x7f,\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\xa0&\x84dv\xfd_\xc5J]C8Qg\xc9QD\xf2d?S<\xc8[\xb9\xd1kx/\x8d}\xb1\x93\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xa0Pm\x86X-%$\x05\xb8@\x01\x87\x92\xca\u04bf\x12Y\xf1\xefZ\xa5\xf8\x87\xe1<\xb2\xf0\tOQ\xe1\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\xa0\xff\xff\n\xd7\xe6Yw/\x954\xc1\x95\xc8\x15\xef\xc4\x01N\xf1\xe1\xda\xedD\x04\xc0c\x85\xd1\x11\x92\xe9+\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\xa0l\xf0A'\xdb\x05D\x1c\xd83\x10zR\xbe\x85(h\x89\x0eC\x17\xe6\xa0*\xb4v\x83\xaau\x96B \xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-\xa0\xb7\xd0_\x87_\x14\x00'\xefQ\x18\xa2${\xbb\x84\u038f/\x0f\x11#b0\x85\xda\xf7\x96\f2\x9f_\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\xa0\xdfj\xf5\xf5\xbb\xdbk\xe9\uf2a6\x18\u4fc0s\x96\bg\x17\x1e)go\x8b(M\xeaj\b\xa8^\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/\xa0\xb5\x8d\x90\x0f^\x18.\x01t\u0285\x18.\xec\x9f:\t\xf6\xa6\xc0\xdfcw\xa5\x10\xd7\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\xa01 o\xa8\nP\xbbj\xbe)\bPX\xf1b\x12!*`\xee\xc8\xf0I\xfe\u02d2\xd8\xc8\xe0\xa8K\xc0\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\xa0!5+\xfe\xcb\xed\xdd\u94c3\x9faL=\xac\n>\xe3uC\xf9\xb4\x12\xb1a\x99\xdc\x15\x8e#\xb5D\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\xa0a\x9e1'$\xbbm|1S\xed\x9d\xe7\x91\xd7d\xa3f\xb3\x89\xaf\x13\u014b\xf8\xa8\xd9\x04\x81\xa4ge\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\xa0|\xdd)\x86&\x82Pb\x8d\f\x10\xe3\x85\u014ca\x91\xe6\xfb\xe0Q\x91\xbc\xc0O\x13?,\xear\xc1\xc4\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xa0\x84\x890\xbd{\xa8\xca\xc5Fa\a!\x13\xfb'\x88i\xe0{\xb8X\x7f\x919)37M\x01{\xcb\xe1\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xa0\x88i\xff,\"\xb2\x8c\xc1\x05\x10\u06452\x92\x803(\xbeO\xb0\xe8\x04\x95\u8ecd'\x1f[\x88\x966\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xa0\xb5\xfe(\xe7\x9f\x1b\x85\x0f\x86X$l\u9da1\u7d1f\xc0m\xb7\x14>\x8f\xe0\xb4\xf2\xb0\xc5R:\\\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\xa0\x98^\x92\x9fp\xaf(\u043d\u0469\n\x80\x8f\x97\x7fY||w\x8cH\x9e\x98\u04fd\x89\x10\xd3\x1a\xc0\xf7\xe1\x94F#\x96\u677f\xa4U\xf4\x05\xf4\u0742\xf3\x01J\xf8\x00;r\x8b\xa5o\xa5\xb9\x90\x19\xa5\xc8\x00\x00\x00\xe0\x94I\xdf<\xca&p\xeb\rY\x11F\xb1cY\xfe3nGo)\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94K\xc6V\xb3M\xe28\x96\xfa`i\u0246/5[t\x04\x01\xaf\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe0\x94M\v\x04\xb4\x05\u01b6,|\xfc:\xe5GYt~,\vFb\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94MIl\xcc(\x05\x8b\x1dt\xb7\xa1\x95Af>!\x15O\x9c\x84\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94P\x9avg\xac\x8d\x03 \xe3ar\xc1\x92Pja\x88\xaa\x84\xf6\x8b|\x13\xbcK,\x13\xfa<]\xc1\xaa\x19;\xc6\x03=\xfd\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94jz\xa9\xb8\x82\xd5\v\xb7\xbc]\xa1\xa2Dq\x9c\x99\xf1/\x06\xa3\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94l\xc99|;8s\x9d\xac\xbf\xaah\xea\xd5\xf5\xd7{\xa5\xf4U\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94s\xb2\xe0\xe5E\x10#\x9e\"\u0313o\vJm\xe1\xac\xf0\xab\u078bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94v,\xa6,\xa2T\x9a\xd8\x06v;:\xa1\xea1|B\x9b\xdb\u068a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94w\x8f_\x13\u013ex\xa3\xa4\xd7\x14\x1b\xcb&\x99\x97\x02\xf4\a\u03cbR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\x83M\xbfZ\x03\xe2\x9c%\xbcUE\x9c\u039c\x02\x1e\xeb\xe6v\xad\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x87]%\xeeK\xc6\x04\xc7\x1b\xafb6\xa8H\x8f\"9\x9b\xedK\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u150d\xf7\x87\x8d5q\xbe\xf5\xe5\xa7D\xf9b\x87\xc8\xd2\x03\x86\xd7Z\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\x9eAZ\to\xf7vP\u0712]\xeaTe\x85\xb4\xad\xb3\"\xb6\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa0vke\xa4\xf7\xb1\xday\xa1\xafy\xaciTV\uf886D\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa2\x9b\x14JD\x9eAJG,`\u01ea\xf1\xaa\xff\xe3)\x02\x1d\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa5S\x95Vk\vT9[2F\xf9j\v\xdcK\x8aH=\xf9\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xac\x9b\xa7/\xb6\x1a\xa7\xc3\x1a\x95\xdf\n\x8bn\xbaoA\xef\x87^\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xb0I\x8c\x15\x87\x9d\xb2\xeeTq\u0512l_\xaa%\u0260\x96\x83\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xb0J\xef*=-\x86\xb0\x10\x06\xcc\xd43\x9a.\x94=\x9cd\x80\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u1531\x9f\xb4\xc1\xf2\x802~`\xed7\xb1\xdcn\xe7u3S\x93\x14\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xbb\x97{.\xe8\xa1\x11\u05c8\xb3G}$ x\u04387\xe7+\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xc2\x1c\xb9\u025c1m\x18c\x14/}\xd8m\xd5Im\x81\xa8\u058a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xc4s\xd4\x12\xdcR\xe3I\x86\"\t\x92L\x89\x81\xb2\xeeB\ah\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\u010e#\xc5\xf6\xe1\xea\v\xae\xf6S\a4\xed\u00d6\x8fy\xaf.\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94\xc6\xe2E\x99\x91\xbf\xe2|\xcam\x86r/5\xda#\xa1\xe4\u02d7\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xc9\xca+\xa9\xa2}\xe1\xdbX\x9d\x8c3\xab\x8e\u07e2\x11\x1b1\xfb\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xd1\xf7~L\x1cE\x18n\x86S\u0109\xf9\x0e\x00\x8asYr\x96\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe2\x94\u04d9NM2\x02\xdd#\xc8I}\x7fu\xbf\x16G\xd1\xda\x1b\xb1\x8c\x01\x9d\x97\x1eO\xe8@\x1et\x00\x00\x00\xe0\x94\u0726\u9d0e\xa8j\xeb\xfd\xf9\x92\x99I\x12@B)kn4\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xe0\x99\x1e\x84@A\xbeo\x11\xb9\x9d\xa5\xb1\x14\xb6\xbc\xf8N\xbdW\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\u08bdBX\xd2v\x887\xba\xa2j(\xfeq\xdc\a\x9f\x84\u01cbR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xea(\xd0\x02\x04/\u0649\x8d\r\xb0\x16\xbe\x97X\xee\xaf\xe3\\\x1e\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xef\xa7EO\x11\x16\x80yu\xa4u\vFi^\x96xP\xde]\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\xfb\xfdo\xa9\xf7:\u01a0X\xe0\x12Y\x03L(\x00\x1b\xef\x82G\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00" diff --git a/core/genesis_test.go b/core/genesis_test.go index 002e58a961b9..ad602db4be23 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -35,15 +35,6 @@ import ( "github.com/ethereum/go-ethereum/triedb/pathdb" ) -func TestInvalidCliqueConfig(t *testing.T) { - block := DefaultGoerliGenesisBlock() - block.ExtraData = []byte{} - db := rawdb.NewMemoryDatabase() - if _, err := block.Commit(db, triedb.NewDatabase(db, nil)); err == nil { - t.Fatal("Expected error on invalid clique config") - } -} - func TestSetupGenesis(t *testing.T) { testSetupGenesis(t, rawdb.HashScheme) testSetupGenesis(t, rawdb.PathScheme) @@ -105,15 +96,15 @@ func testSetupGenesis(t *testing.T, scheme string) { wantConfig: customg.Config, }, { - name: "custom block in DB, genesis == goerli", + name: "custom block in DB, genesis == sepolia", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { tdb := triedb.NewDatabase(db, newDbConfig(scheme)) customg.Commit(db, tdb) - return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock()) + return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock()) }, - wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash}, - wantHash: params.GoerliGenesisHash, - wantConfig: params.GoerliChainConfig, + wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash}, + wantHash: params.SepoliaGenesisHash, + wantConfig: params.SepoliaChainConfig, }, { name: "compatible config in DB", @@ -184,7 +175,6 @@ func TestGenesisHashes(t *testing.T) { want common.Hash }{ {DefaultGenesisBlock(), params.MainnetGenesisHash}, - {DefaultGoerliGenesisBlock(), params.GoerliGenesisHash}, {DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash}, } { // Test via MustCommit diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 59c580dacaf1..46558a6fceec 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -270,11 +270,10 @@ func (p *Pruner) Prune(root common.Hash) error { // is the presence of root can indicate the presence of the // entire trie. if !rawdb.HasLegacyTrieNode(p.db, root) { - // The special case is for clique based networks(goerli - // and some other private networks), it's possible that two - // consecutive blocks will have same root. In this case snapshot - // difflayer won't be created. So HEAD-127 may not paired with - // head-127 layer. Instead the paired layer is higher than the + // The special case is for clique based networks, it's possible + // that two consecutive blocks will have same root. In this case + // snapshot difflayer won't be created. So HEAD-127 may not paired + // with head-127 layer. Instead the paired layer is higher than the // bottom-most diff layer. Try to find the bottom-most snapshot // layer with state available. // diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index ecf07b6a2cc9..6eb0d04f6ba8 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -122,7 +122,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2 // NodeInfo represents a short summary of the `eth` sub-protocol metadata // known about the host peer. type NodeInfo struct { - Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Goerli=5) + Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Holesky=17000) Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules diff --git a/internal/era/era_test.go b/internal/era/era_test.go index ee5d9e82a099..883e30f7b659 100644 --- a/internal/era/era_test.go +++ b/internal/era/era_test.go @@ -132,7 +132,6 @@ func TestEraFilename(t *testing.T) { expected string }{ {"mainnet", 1, common.Hash{1}, "mainnet-00001-01000000.era1"}, - {"goerli", 99999, common.HexToHash("0xdeadbeef00000000000000000000000000000000000000000000000000000000"), "goerli-99999-deadbeef.era1"}, } { got := Filename(tt.network, tt.epoch, tt.root) if tt.expected != got { diff --git a/params/bootnodes.go b/params/bootnodes.go index 5e2c7c218102..124765313a81 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -47,23 +47,6 @@ var SepoliaBootnodes = []string{ "enode://9e9492e2e8836114cc75f5b929784f4f46c324ad01daf87d956f98b3b6c5fcba95524d6e5cf9861dc96a2c8a171ea7105bb554a197455058de185fa870970c7c@138.68.123.152:30303", // sepolia-bootnode-1-ams3 } -// GoerliBootnodes are the enode URLs of the P2P bootstrap nodes running on the -// Görli test network. -var GoerliBootnodes = []string{ - // Upstream bootnodes - "enode://011f758e6552d105183b1761c5e2dea0111bc20fd5f6422bc7f91e0fabbec9a6595caf6239b37feb773dddd3f87240d99d859431891e4a642cf2a0a9e6cbb98a@51.141.78.53:30303", - "enode://176b9417f511d05b6b2cf3e34b756cf0a7096b3094572a8f6ef4cdcb9d1f9d00683bf0f83347eebdf3b81c3521c2332086d9592802230bf528eaf606a1d9677b@13.93.54.137:30303", - "enode://46add44b9f13965f7b9875ac6b85f016f341012d84f975377573800a863526f4da19ae2c620ec73d11591fa9510e992ecc03ad0751f53cc02f7c7ed6d55c7291@94.237.54.114:30313", - "enode://b5948a2d3e9d486c4d75bf32713221c2bd6cf86463302339299bd227dc2e276cd5a1c7ca4f43a0e9122fe9af884efed563bd2a1fd28661f3b5f5ad7bf1de5949@18.218.250.66:30303", - - // Ethereum Foundation bootnode - "enode://a61215641fb8714a373c80edbfa0ea8878243193f57c96eeb44d0bc019ef295abd4e044fd619bfc4c59731a73fb79afe84e9ab6da0c743ceb479cbb6d263fa91@3.11.147.67:30303", - - // Goerli Initiative bootnodes - "enode://d4f764a48ec2a8ecf883735776fdefe0a3949eb0ca476bd7bc8d0954a9defe8fea15ae5da7d40b5d2d59ce9524a99daedadf6da6283fca492cc80b53689fb3b3@46.4.99.122:32109", - "enode://d2b720352e8216c9efc470091aa91ddafc53e222b32780f505c817ceef69e01d5b0b0797b69db254c586f493872352f5a022b4d8479a00fc92ec55f9ad46a27e@88.99.70.182:30303", -} - var V5Bootnodes = []string{ // Teku team's bootnode "enr:-KG4QMOEswP62yzDjSwWS4YEjtTZ5PO6r65CPqYBkgTTkrpaedQ8uEUo1uMALtJIvb2w_WWEVmg5yt1UAuK1ftxUU7QDhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQEnfA2iXNlY3AyNTZrMaEDfol8oLr6XJ7FsdAYE7lpJhKMls4G_v6qQOGKJUWGb_uDdGNwgiMog3VkcIIjKA", // # 4.157.240.54 | azure-us-east-virginia @@ -97,8 +80,6 @@ func KnownDNSNetwork(genesis common.Hash, protocol string) string { switch genesis { case MainnetGenesisHash: net = "mainnet" - case GoerliGenesisHash: - net = "goerli" case SepoliaGenesisHash: net = "sepolia" case HoleskyGenesisHash: diff --git a/params/config.go b/params/config.go index 871782399d14..c4e6ba6948cf 100644 --- a/params/config.go +++ b/params/config.go @@ -29,7 +29,6 @@ var ( MainnetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") HoleskyGenesisHash = common.HexToHash("0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4") SepoliaGenesisHash = common.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9") - GoerliGenesisHash = common.HexToHash("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a") ) func newUint64(val uint64) *uint64 { return &val } @@ -111,32 +110,6 @@ var ( CancunTime: newUint64(1706655072), Ethash: new(EthashConfig), } - // GoerliChainConfig contains the chain parameters to run a node on the Görli test network. - GoerliChainConfig = &ChainConfig{ - ChainID: big.NewInt(5), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(1_561_651), - MuirGlacierBlock: nil, - BerlinBlock: big.NewInt(4_460_644), - LondonBlock: big.NewInt(5_062_605), - ArrowGlacierBlock: nil, - TerminalTotalDifficulty: big.NewInt(10_790_000), - TerminalTotalDifficultyPassed: true, - ShanghaiTime: newUint64(1678832736), - CancunTime: newUint64(1705473120), - Clique: &CliqueConfig{ - Period: 15, - Epoch: 30000, - }, - } // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. AllEthashProtocolChanges = &ChainConfig{ @@ -313,7 +286,6 @@ var ( // NetworkNames are user friendly names to use in the chain spec banner. var NetworkNames = map[string]string{ MainnetChainConfig.ChainID.String(): "mainnet", - GoerliChainConfig.ChainID.String(): "goerli", SepoliaChainConfig.ChainID.String(): "sepolia", HoleskyChainConfig.ChainID.String(): "holesky", } From 00294e9d28151122e955c7db4344f06724295ec5 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 20 Aug 2024 08:02:54 -0600 Subject: [PATCH 486/571] cmd/utils,p2p: enable discv5 by default (#30327) --- cmd/utils/flags.go | 3 ++- p2p/discover/v4_udp.go | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 22dd6645de7a..611189a2cc00 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -807,8 +807,9 @@ var ( DiscoveryV5Flag = &cli.BoolFlag{ Name: "discovery.v5", Aliases: []string{"discv5"}, - Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", + Usage: "Enables the V5 discovery mechanism", Category: flags.NetworkingCategory, + Value: true, } NetrestrictFlag = &cli.StringFlag{ Name: "netrestrict", diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 321552ddc371..cc2a3fb9247e 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -547,7 +547,9 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { } return } - if t.handlePacket(from, buf[:nbytes]) != nil && unhandled != nil { + if err := t.handlePacket(from, buf[:nbytes]); err != nil && unhandled == nil { + t.log.Debug("Bad discv4 packet", "addr", from, "err", err) + } else if err != nil && unhandled != nil { select { case unhandled <- ReadPacket{buf[:nbytes], from}: default: @@ -564,7 +566,6 @@ func (t *UDPv4) handlePacket(from netip.AddrPort, buf []byte) error { rawpacket, fromKey, hash, err := v4wire.Decode(buf) if err != nil { - t.log.Debug("Bad discv4 packet", "addr", from, "err", err) return err } packet := t.wrapPacket(rawpacket) From 2a534ee133f294b2bfcce29127d4f2ad9e7f00ce Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 20 Aug 2024 17:34:03 +0200 Subject: [PATCH 487/571] travis.yml: use focal for builds (#30319) --- .travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index edb16561d556..fa56fe383ef3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ jobs: if: type = push os: linux arch: amd64 - dist: noble + dist: focal go: 1.23.x env: - docker @@ -32,7 +32,7 @@ jobs: if: type = push os: linux arch: arm64 - dist: noble + dist: focal go: 1.23.x env: - docker @@ -49,7 +49,7 @@ jobs: - stage: build if: type = push os: linux - dist: noble + dist: focal sudo: required go: 1.23.x env: @@ -100,7 +100,7 @@ jobs: if: type = push os: linux arch: amd64 - dist: noble + dist: focal go: 1.23.x script: - travis_wait 45 go run build/ci.go test $TEST_PACKAGES @@ -108,7 +108,7 @@ jobs: - stage: build if: type = push os: linux - dist: noble + dist: focal go: 1.22.x script: - travis_wait 45 go run build/ci.go test $TEST_PACKAGES @@ -117,7 +117,7 @@ jobs: - stage: build if: type = cron || (type = push && tag ~= /^v[0-9]/) os: linux - dist: noble + dist: focal go: 1.23.x env: - ubuntu-ppa @@ -133,7 +133,7 @@ jobs: - stage: build if: type = cron os: linux - dist: noble + dist: focal go: 1.23.x env: - azure-purge @@ -146,7 +146,7 @@ jobs: - stage: build if: type = cron os: linux - dist: noble + dist: focal go: 1.23.x env: - racetests From df645e77b71877982abc4c956900ca0c1c7cfe1c Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Wed, 21 Aug 2024 04:00:31 +0200 Subject: [PATCH 488/571] trie: use go-verkle helper for speedier (*VerkleTrie).RollBackAccount (#30242) This is a performance improvement on the account-creation rollback code required for the archive node to support verkle. It uses the utility function `DeleteAtStem` to remove code and account data per-group instead of doing it leaf by leaf. It also fixes an index bug, as code is chunked in 31-byte chunks, so comparing with the code size should use 31 as its stride. --------- Co-authored-by: Felix Lange --- go.mod | 6 +++--- go.sum | 12 ++++++------ trie/verkle.go | 35 ++++++++++------------------------- 3 files changed, 19 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index 8b18ddfce232..49f2835c3e77 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 github.com/ethereum/c-kzg-4844 v1.0.0 - github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 + github.com/ethereum/go-verkle v0.1.1-0.20240726143912-7dc5142667fa github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.2 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e @@ -69,7 +69,7 @@ require ( golang.org/x/crypto v0.22.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.7.0 - golang.org/x/sys v0.20.0 + golang.org/x/sys v0.22.0 golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.20.0 @@ -93,7 +93,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 // indirect github.com/aws/smithy-go v1.15.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect diff --git a/go.sum b/go.sum index 089c05c2ecb7..4540dbfa42a8 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= -github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= +github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= @@ -170,8 +170,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= +github.com/ethereum/go-verkle v0.1.1-0.20240726143912-7dc5142667fa h1:mXkPoR07WlPVAClNzWuGAQNqmhxLqQILXhm73J5d9Ew= +github.com/ethereum/go-verkle v0.1.1-0.20240726143912-7dc5142667fa/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= @@ -689,8 +689,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/trie/verkle.go b/trie/verkle.go index fb4d81281cbd..fab1ccb48ac5 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -216,35 +216,20 @@ func (t *VerkleTrie) RollBackAccount(addr common.Address) error { codeSize := binary.LittleEndian.Uint64(codeSizeBytes) // Delete the account header + first 64 slots + first 128 code chunks - key := common.CopyBytes(codeSizeKey) - for i := 0; i < verkle.NodeWidth; i++ { - key[31] = byte(i) - - // this is a workaround to avoid deleting nil leaves, the lib needs to be - // fixed to be able to handle that - v, err := t.root.Get(key, t.nodeResolver) - if err != nil { - return fmt.Errorf("error rolling back account header: %w", err) - } - if len(v) == 0 { - continue - } - _, err = t.root.Delete(key, t.nodeResolver) - if err != nil { - return fmt.Errorf("error rolling back account header: %w", err) - } + _, err = t.root.(*verkle.InternalNode).DeleteAtStem(codeSizeKey[:31], t.nodeResolver) + if err != nil { + return fmt.Errorf("error rolling back account header: %w", err) } + // Delete all further code - for i, chunknr := uint64(32*128), uint64(128); i < codeSize; i, chunknr = i+32, chunknr+1 { + for i, chunknr := uint64(31*128), uint64(128); i < codeSize; i, chunknr = i+31*256, chunknr+256 { // evaluate group key at the start of a new group - groupOffset := (chunknr + 128) % 256 - if groupOffset == 0 { - key = utils.CodeChunkKeyWithEvaluatedAddress(evaluatedAddr, uint256.NewInt(chunknr)) - } - key[31] = byte(groupOffset) - _, err = t.root.Delete(key[:], t.nodeResolver) + offset := uint256.NewInt(chunknr) + key := utils.CodeChunkKeyWithEvaluatedAddress(evaluatedAddr, offset) + + _, err = t.root.(*verkle.InternalNode).DeleteAtStem(key[:], t.nodeResolver) if err != nil { - return fmt.Errorf("error deleting code chunk (addr=%x) error: %w", addr[:], err) + return fmt.Errorf("error deleting code chunk stem (addr=%x, offset=%d) error: %w", addr[:], offset, err) } } return nil From 733fcbbc65bca69e28480f624e2aeb170c97cb3e Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 21 Aug 2024 09:22:33 +0200 Subject: [PATCH 489/571] eth/protocols/eth: handle zero-count header requests (#30305) Proper fix for handling `count=0` get header requests. https://en.wikipedia.org/wiki/Count_Zero --- eth/protocols/eth/handlers.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index bdc630a9f467..b3886270f3dd 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -42,6 +42,9 @@ func handleGetBlockHeaders(backend Backend, msg Decoder, peer *Peer) error { // ServiceGetBlockHeadersQuery assembles the response to a header query. It is // exposed to allow external packages to test protocol behavior. func ServiceGetBlockHeadersQuery(chain *core.BlockChain, query *GetBlockHeadersRequest, peer *Peer) []rlp.RawValue { + if query.Amount == 0 { + return nil + } if query.Skip == 0 { // The fast path: when the request is for a contiguous segment of headers. return serviceContiguousBlockHeaderQuery(chain, query) From 30824faf90bf5d1f5e4a1cf0b50de80f10d16490 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 21 Aug 2024 15:16:08 +0200 Subject: [PATCH 490/571] eth/tracers: avoid panic in state test runner (#30332) Make tracers more robust by handling `nil` receipt as input. Also pass in a receipt with gas used in the state test runner. Closes https://github.com/ethereum/go-ethereum/issues/30117. --------- Co-authored-by: Sina Mahmoodi --- eth/tracers/js/goja.go | 4 +++- eth/tracers/logger/logger.go | 4 +++- eth/tracers/native/call.go | 4 +++- tests/state_test_util.go | 14 ++++++++------ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index fd8f74fc54c8..b823ef740a86 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -275,7 +275,9 @@ func (t *jsTracer) OnTxEnd(receipt *types.Receipt, err error) { } return } - t.ctx["gasUsed"] = t.vm.ToValue(receipt.GasUsed) + if receipt != nil { + t.ctx["gasUsed"] = t.vm.ToValue(receipt.GasUsed) + } } // onStart implements the Tracer interface to initialize the tracing operation. diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index ef1d47146682..7638c3cd09c3 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -268,7 +268,9 @@ func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) { } return } - l.usedGas = receipt.GasUsed + if receipt != nil { + l.usedGas = receipt.GasUsed + } } // StructLogs returns the captured log entries. diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 2b84ecaf4057..1b94dd7b6771 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -225,7 +225,9 @@ func (t *callTracer) OnTxEnd(receipt *types.Receipt, err error) { if err != nil { return } - t.callstack[0].GasUsed = receipt.GasUsed + if receipt != nil { + t.callstack[0].GasUsed = receipt.GasUsed + } if t.config.WithLog { // Logs are not emitted when the call fails clearFailedLogs(&t.callstack[0], false) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 416bab947264..2bf0056cbc9e 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -297,19 +297,17 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil { tracer.OnTxStart(evm.GetVMContext(), nil, msg.From) - if evm.Config.Tracer.OnTxEnd != nil { - defer func() { - evm.Config.Tracer.OnTxEnd(nil, err) - }() - } } // Execute the message. snapshot := st.StateDB.Snapshot() gaspool := new(core.GasPool) gaspool.AddGas(block.GasLimit()) - _, err = core.ApplyMessage(evm, msg, gaspool) + vmRet, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { st.StateDB.RevertToSnapshot(snapshot) + if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil { + evm.Config.Tracer.OnTxEnd(nil, err) + } } // Add 0-value mining reward. This only makes a difference in the cases // where @@ -320,6 +318,10 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // Commit state mutations into database. root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number())) + if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil { + receipt := &types.Receipt{GasUsed: vmRet.UsedGas} + tracer.OnTxEnd(receipt, nil) + } return st, root, err } From 941ae33d7e0b36afc2f8551884f555d963de7c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Thu, 22 Aug 2024 13:29:40 +0200 Subject: [PATCH 491/571] build: fix hash for go1.23.0.linux-riscv64.tar.gz (#30335) build: fix hash for go1.23.0.linux-riscv64.tar.gz --- build/checksums.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/checksums.txt b/build/checksums.txt index 432e36150580..3fed6625ed50 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -31,7 +31,7 @@ dc8f723ce1a236e85c8b56d1e6749e270314e99dd41b80a58355e7ffcf9ea857 go1.23.0.linux d522770d32d6ee963f61331a695c4f8a730f2445b965d8d56db0a2e75c62af57 go1.23.0.linux-mipsle.tar.gz 8c884cb4f2593d897f58ec1b0f23f303acf5c78fd101e76cb48d6cb1fe5e90e7 go1.23.0.linux-ppc64.tar.gz 8b26e20d4d43a4d7641cddbdc0298d7ba3804d910a9e06cda7672970dbf2829d go1.23.0.linux-ppc64le.tar.gz -87726205f1a283247f877ccae8ce147ff4e77ac802382647ac52256eb5642c7 go1.23.0.linux-riscv64.tar.gz +a87726205f1a283247f877ccae8ce147ff4e77ac802382647ac52256eb5642c7 go1.23.0.linux-riscv64.tar.gz 003722971de02d97131a4dca2496abdab5cb175a6ee0ed9c8227c5ae9b883e69 go1.23.0.linux-s390x.tar.gz b203fa2354874c66c40d828e96a6cce1f4e4db192414050a600d0a09b16cafd3 go1.23.0.netbsd-386.tar.gz 1502c82c3ba663959df99c2cc3ca5e7a5e1a75a1495fd26bef697d63bf1f291c go1.23.0.netbsd-amd64.tar.gz From ada20c09dcc73149769f8c578f53c8dd71c47a2c Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 23 Aug 2024 09:48:24 +0200 Subject: [PATCH 492/571] build: make go buildid static (#30342) The previous clearing of buildid did fully work, turns out we need to set it in `ldflags` The go buildid is the only remaining hurdle for reproducible builds, see https://github.com/ethereum/go-ethereum/issues/28987#issuecomment-2306412590 This PR changes the go build id application note to say literally `none` https://github.com/golang/go/issues/33772#issuecomment-528176001: > This difference is due to the .note.go.buildid section added by the linker. It can be set to something static e.g. -ldflags=-buildid= (empty string) to gain reproducibility. --- build/ci.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/ci.go b/build/ci.go index fe507cf48f94..bdc89082e744 100644 --- a/build/ci.go +++ b/build/ci.go @@ -237,6 +237,10 @@ func doInstall(cmdline []string) { // buildFlags returns the go tool flags for building. func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) { var ld []string + // See https://github.com/golang/go/issues/33772#issuecomment-528176001 + // We need to set --buildid to the linker here, and also pass --build-id to the + // cgo-linker further down. + ld = append(ld, "--buildid=none") if env.Commit != "" { ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitCommit="+env.Commit) ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitDate="+env.Date) From 020f026616782c37ca7cb5ec3c452b5c4c3e1497 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 23 Aug 2024 18:27:06 +0800 Subject: [PATCH 493/571] trie: avoid un-needed map copy (#30343) This change avoids the an unnecessary map copy if the preimage recording is not enabled. --- trie/secure_trie.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 6eb6defa45eb..9d19ee58a4f8 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -250,11 +250,11 @@ func (t *StateTrie) Witness() map[string]struct{} { func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { - preimages := make(map[common.Hash][]byte, len(t.secKeyCache)) - for hk, key := range t.secKeyCache { - preimages[common.BytesToHash([]byte(hk))] = key - } if t.preimages != nil { + preimages := make(map[common.Hash][]byte, len(t.secKeyCache)) + for hk, key := range t.secKeyCache { + preimages[common.BytesToHash([]byte(hk))] = key + } t.preimages.InsertPreimage(preimages) } t.secKeyCache = make(map[string][]byte) From c12a1c9bcf05a2245a0f71839c8a228bd7552c55 Mon Sep 17 00:00:00 2001 From: Karl Bartel Date: Fri, 23 Aug 2024 12:29:02 +0200 Subject: [PATCH 494/571] beacon/blsync: better error information in test (#30336) this change reports the error instead of ignoring it --- beacon/blsync/block_sync_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/beacon/blsync/block_sync_test.go b/beacon/blsync/block_sync_test.go index 3d3b9e5e8d5b..e7c2c4d16311 100644 --- a/beacon/blsync/block_sync_test.go +++ b/beacon/blsync/block_sync_test.go @@ -70,7 +70,10 @@ func TestBlockSync(t *testing.T) { t.Helper() var expNumber, headNumber uint64 if expHead != nil { - p, _ := expHead.ExecutionPayload() + p, err := expHead.ExecutionPayload() + if err != nil { + t.Fatalf("expHead.ExecutionPayload() failed: %v", err) + } expNumber = p.NumberU64() } select { From eaf4285f0a4dca5737d6b964eb35afb782f2171a Mon Sep 17 00:00:00 2001 From: Gealber Morales <48373523+Gealber@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:31:24 +0200 Subject: [PATCH 495/571] beacon/light/sync: basic tests for rangeLock (#30269) adds simple tests for lock and firstUnlocked method from rangeLock type --------- Co-authored-by: lightclient --- beacon/light/sync/update_sync_test.go | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/beacon/light/sync/update_sync_test.go b/beacon/light/sync/update_sync_test.go index 8329bf28c9d8..88d573165ee7 100644 --- a/beacon/light/sync/update_sync_test.go +++ b/beacon/light/sync/update_sync_test.go @@ -201,6 +201,34 @@ func TestUpdateSyncDifferentHeads(t *testing.T) { chain.ExpNextSyncPeriod(t, 17) } +func TestRangeLock(t *testing.T) { + r := make(rangeLock) + + // Lock from 0 to 99. + r.lock(0, 100, 1) + for i := 0; i < 100; i++ { + if v, ok := r[uint64(i)]; v <= 0 || !ok { + t.Fatalf("integer space: %d not locked", i) + } + } + + // Unlock from 0 to 99. + r.lock(0, 100, -1) + for i := 0; i < 100; i++ { + if v, ok := r[uint64(i)]; v > 0 || ok { + t.Fatalf("integer space: %d is locked", i) + } + } + + // Lock from 0 to 99 then unlock from 10 to 59. + r.lock(0, 100, 1) + r.lock(10, 50, -1) + first, count := r.firstUnlocked(0, 100) + if first != 10 || count != 50 { + t.Fatalf("unexpected first: %d or count: %d", first, count) + } +} + func testRespUpdate(request requestWithID) request.Response { var resp RespUpdates if request.request == nil { From 0378dc8367e529bb95403741af62b7911efd8a2c Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 23 Aug 2024 16:30:30 +0200 Subject: [PATCH 496/571] build: debug travis build (#30344) debugging travis build pipeline --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index fa56fe383ef3..913fa54e963c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,6 +63,7 @@ jobs: # build 386 - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib + - git status --porcelain - go run build/ci.go install -dlgo -arch 386 - go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds From 1d006bd5bf478334bac5adfeff4d6f03a83e3f68 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 23 Aug 2024 16:48:20 +0200 Subject: [PATCH 497/571] gitignore: ignore build signatures (#30346) Ignore files are generated during signing of download-binaries, which 'dirty' the vcs for subsequent builds. --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 62f3a96e30ef..a1d48cc72b4d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,11 @@ build/_vendor/pkg # used by the build/ci.go archive + upload tool /geth*.tar.gz +/geth*.tar.gz.sig +/geth*.tar.gz.asc +/geth*.zip.sig +/geth*.zip.asc + # travis profile.tmp From 4e17f2874077488f8eb61a2fca490386fd1a9e52 Mon Sep 17 00:00:00 2001 From: Oksana <107276324+Ocheretovich@users.noreply.github.com> Date: Mon, 26 Aug 2024 04:29:24 +0300 Subject: [PATCH 498/571] doc: update 2021-08-22-split-postmortem (#30351) Update 2021-08-22-split-postmortem --- docs/postmortems/2021-08-22-split-postmortem.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/postmortems/2021-08-22-split-postmortem.md b/docs/postmortems/2021-08-22-split-postmortem.md index 0986f00b65c6..5ec4f37e8798 100644 --- a/docs/postmortems/2021-08-22-split-postmortem.md +++ b/docs/postmortems/2021-08-22-split-postmortem.md @@ -62,7 +62,7 @@ Since we had merged the removal of `ETH65`, if the entire network were to upgrad - Announce an upcoming security release on Tuesday (August 24th), via Twitter and official channels, plus reach out to downstream projects. - Temporarily revert the `ETH65`-removal. -- Place the fix into the PR optimizing the jumpdest analysis [233381](https://github.com/ethereum/go-ethereum/pull/23381). +- Place the fix into the PR optimizing the jumpdest analysis [23381](https://github.com/ethereum/go-ethereum/pull/23381). - After 4-8 weeks, release details about the vulnerability. From a223efcf39855c92730e0f6a269c90d1e89fd7e4 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:39:35 +0200 Subject: [PATCH 499/571] core: implement EIP-2935 (#29465) https://eips.ethereum.org/EIPS/eip-2935 --------- Co-authored-by: Guillaume Ballet Co-authored-by: Ignacio Hagopian Co-authored-by: Martin HS --- cmd/evm/internal/t8ntool/execution.go | 9 ++++- core/genesis.go | 2 + core/state_processor.go | 42 +++++++++++++++++--- core/state_processor_test.go | 55 +++++++++++++++++++++++++++ eth/state_accessor.go | 6 +++ eth/tracers/api.go | 17 +++++++++ miner/worker.go | 5 +++ params/protocol_params.go | 6 +++ 8 files changed, 136 insertions(+), 6 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index a4c5f6efcb0a..d240d161a980 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -196,7 +196,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } - + if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) { + var ( + prevNumber = pre.Env.Number - 1 + prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)] + evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) + ) + core.ProcessParentBlockHash(prevHash, evm, statedb) + } for i := 0; txIt.Next(); i++ { tx, err := txIt.Tx() if err != nil { diff --git a/core/genesis.go b/core/genesis.go index cbd3bcebf79d..d83aab0baf89 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -583,6 +583,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b // Pre-deploy EIP-4788 system contract params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, + // Pre-deploy EIP-2935 history contract. + params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode}, }, } if faucet != nil { diff --git a/core/state_processor.go b/core/state_processor.go index cc415831659d..44224958ddce 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -77,6 +77,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + if p.config.IsPrague(block.Number(), block.Time()) { + ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { msg, err := TransactionToMessage(tx, signer, header.BaseFee) @@ -178,11 +181,13 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // contract. This method is exported to be used in tests. func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { - if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil { - vmenv.Config.Tracer.OnSystemCallStart() - } - if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil { - defer vmenv.Config.Tracer.OnSystemCallEnd() + if tracer := vmenv.Config.Tracer; tracer != nil { + if tracer.OnSystemCallStart != nil { + tracer.OnSystemCallStart() + } + if tracer.OnSystemCallEnd != nil { + defer tracer.OnSystemCallEnd() + } } // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with @@ -201,3 +206,30 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) statedb.Finalise(true) } + +// ProcessParentBlockHash stores the parent block hash in the history storage contract +// as per EIP-2935. +func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { + if tracer := vmenv.Config.Tracer; tracer != nil { + if tracer.OnSystemCallStart != nil { + tracer.OnSystemCallStart() + } + if tracer.OnSystemCallEnd != nil { + defer tracer.OnSystemCallEnd() + } + } + + msg := &Message{ + From: params.SystemAddress, + GasLimit: 30_000_000, + GasPrice: common.Big0, + GasFeeCap: common.Big0, + GasTipCap: common.Big0, + To: ¶ms.HistoryStorageAddress, + Data: prevHash.Bytes(), + } + vmenv.Reset(NewEVMTxContext(msg), statedb) + statedb.AddAddressToAccessList(params.HistoryStorageAddress) + _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + statedb.Finalise(true) +} diff --git a/core/state_processor_test.go b/core/state_processor_test.go index af4d29b604da..bf29fb97733f 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -18,6 +18,7 @@ package core import ( "crypto/ecdsa" + "encoding/binary" "math/big" "testing" @@ -29,11 +30,14 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "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/memorydb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/triedb" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) @@ -528,3 +532,54 @@ func TestProcessVerkle(t *testing.T) { } } } + +func TestProcessParentBlockHash(t *testing.T) { + var ( + chainConfig = params.MergedTestChainConfig + hashA = common.Hash{0x01} + hashB = common.Hash{0x02} + header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)} + parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)} + coinbase = common.Address{} + ) + test := func(statedb *state.StateDB) { + statedb.SetNonce(params.HistoryStorageAddress, 1) + statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) + statedb.IntermediateRoot(true) + + vmContext := NewEVMBlockContext(header, nil, &coinbase) + evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + ProcessParentBlockHash(header.ParentHash, evm, statedb) + + vmContext = NewEVMBlockContext(parent, nil, &coinbase) + evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + ProcessParentBlockHash(parent.ParentHash, evm, statedb) + + // make sure that the state is correct + if have := getParentBlockHash(statedb, 1); have != hashA { + t.Errorf("want parent hash %v, have %v", hashA, have) + } + if have := getParentBlockHash(statedb, 0); have != hashB { + t.Errorf("want parent hash %v, have %v", hashB, have) + } + } + t.Run("MPT", func(t *testing.T) { + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + test(statedb) + }) + t.Run("Verkle", func(t *testing.T) { + db := rawdb.NewMemoryDatabase() + cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme) + cacheConfig.SnapshotLimit = 0 + triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) + statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabaseWithNodeDB(db, triedb), nil) + test(statedb) + }) +} + +func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash { + ringIndex := number % params.HistoryServeWindow + var key common.Hash + binary.BigEndian.PutUint64(key[24:], ringIndex) + return statedb.GetState(params.HistoryStorageAddress, key) +} diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 372c76f49692..90f7c013919b 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -239,6 +239,12 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + // If prague hardfork, insert parent block hash in the state as per EIP-2935. + if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { + context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) + core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + } if txIndex == 0 && len(block.Transactions()) == 0 { return nil, vm.BlockContext{}, statedb, release, nil } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 51b55ffdbb1b..9ee108d0f12f 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -382,6 +382,12 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + // Insert parent hash in history contract. + if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { + context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) + core.ProcessParentBlockHash(next.ParentHash(), vmenv, statedb) + } // Clean out any pending release functions of trace state. Note this // step must be done after constructing tracing state, because the // tracing state of block next depends on the parent state and construction @@ -534,6 +540,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + if chainConfig.IsPrague(block.Number(), block.Time()) { + core.ProcessParentBlockHash(block.ParentHash(), vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}), statedb) + } for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { return nil, err @@ -613,6 +622,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) { + vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) + core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + } for i, tx := range txs { // Generate the next state snapshot fast without tracing msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) @@ -771,6 +784,10 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + if chainConfig.IsPrague(block.Number(), block.Time()) { + vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + } for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution var ( diff --git a/miner/worker.go b/miner/worker.go index 9aae6e16099d..4e566f14897c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -200,6 +200,11 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) } + if miner.chainConfig.IsPrague(header.Number, header.Time) { + context := core.NewEVMBlockContext(header, miner.chain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) + core.ProcessParentBlockHash(header.ParentHash, vmenv, env.state) + } return env, nil } diff --git a/params/protocol_params.go b/params/protocol_params.go index 8ffe8ee75db1..638f58a33992 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -174,6 +174,8 @@ const ( BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing) MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block + + HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935. ) // Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations @@ -193,4 +195,8 @@ var ( // SystemAddress is where the system-transaction is sent from as per EIP-4788 SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe") + // HistoryStorageAddress is where the historical block hashes are stored. + HistoryStorageAddress = common.HexToAddress("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e") + // HistoryStorageCode is the code with getters for historical block hashes. + HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500") ) From bfda8ae0c651585e2f1142924854ba467668798c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 26 Aug 2024 20:02:10 +0800 Subject: [PATCH 500/571] core: add metrics for state access (#30353) This pull request adds a few more performance metrics, specifically: - The average time cost of an account read - The average time cost of a storage read - The rate of account reads - The rate of storage reads --- core/blockchain.go | 24 +++++++++++++++++------- core/state/metrics.go | 2 ++ core/state/state_object.go | 1 + core/state/statedb.go | 20 +++++++++++++++----- triedb/pathdb/disklayer.go | 1 - 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 05ebfd18b830..733525bc706f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -76,6 +76,9 @@ var ( snapshotStorageReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/storage/reads", nil) snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil) + accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil) + storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil) + triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil) blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil) @@ -1947,18 +1950,25 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s proctime := time.Since(start) // processing + validation // Update the metrics touched during block processing and validation - accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) - storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) - snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) - snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) + accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) + storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) + snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) + snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) + + accountRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read + storageRead := statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read + if statedb.AccountLoaded != 0 { + accountReadSingleTimer.Update(accountRead / time.Duration(statedb.AccountLoaded)) + } + if statedb.StorageLoaded != 0 { + storageReadSingleTimer.Update(storageRead / time.Duration(statedb.StorageLoaded)) + } accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) triehash := statedb.AccountHashes // The time spent on tries hashing trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update - trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read - trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read - blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing + blockExecutionTimer.Update(ptime - (accountRead + storageRead)) // The time spent on EVM processing blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation // Write the block to the chain and get the status. diff --git a/core/state/metrics.go b/core/state/metrics.go index e702ef3a81a6..fb45bc4b8414 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -19,6 +19,8 @@ package state import "github.com/ethereum/go-ethereum/metrics" var ( + accountReadMeters = metrics.NewRegisteredMeter("state/read/accounts", nil) + storageReadMeters = metrics.NewRegisteredMeter("state/read/storage", nil) accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) diff --git a/core/state/state_object.go b/core/state/state_object.go index 880b715b4b37..1e4da105b2ec 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -239,6 +239,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { } } s.originStorage[key] = value + s.db.StorageLoaded++ return value } diff --git a/core/state/statedb.go b/core/state/statedb.go index 80a53dbb1772..ee91c931f3b5 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -163,10 +163,12 @@ type StateDB struct { SnapshotCommits time.Duration TrieDBCommits time.Duration - AccountUpdated int - StorageUpdated atomic.Int64 - AccountDeleted int - StorageDeleted atomic.Int64 + AccountLoaded int // Number of accounts retrieved from the database during the state transition + AccountUpdated int // Number of accounts updated during the state transition + AccountDeleted int // Number of accounts deleted during the state transition + StorageLoaded int // Number of storage slots retrieved from the database during the state transition + StorageUpdated atomic.Int64 // Number of storage slots updated during the state transition + StorageDeleted atomic.Int64 // Number of storage slots deleted during the state transition } // New creates a new state from a given trie. @@ -601,6 +603,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { s.SnapshotAccountReads += time.Since(start) if err == nil { if acc == nil { + s.AccountLoaded++ return nil } data = &types.StateAccount{ @@ -629,6 +632,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { return nil } if data == nil { + s.AccountLoaded++ return nil } } @@ -643,6 +647,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { // Insert into the live set obj := newObject(s, addr, data) s.setStateObject(obj) + s.AccountLoaded++ return obj } @@ -1286,6 +1291,8 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { if err := workers.Wait(); err != nil { return nil, err } + accountReadMeters.Mark(int64(s.AccountLoaded)) + storageReadMeters.Mark(int64(s.StorageLoaded)) accountUpdatedMeter.Mark(int64(s.AccountUpdated)) storageUpdatedMeter.Mark(s.StorageUpdated.Load()) accountDeletedMeter.Mark(int64(s.AccountDeleted)) @@ -1294,7 +1301,10 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated)) storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted)) - s.AccountUpdated, s.AccountDeleted = 0, 0 + + // Clear the metric markers + s.AccountLoaded, s.AccountUpdated, s.AccountDeleted = 0, 0, 0 + s.StorageLoaded = 0 s.StorageUpdated.Store(0) s.StorageDeleted.Store(0) diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index e538a7928055..b6ae39446cf0 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -139,7 +139,6 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co dl.cleans.Set(key, blob) cleanWriteMeter.Mark(int64(len(blob))) } - return blob, h.hash(blob), &nodeLoc{loc: locDiskLayer, depth: depth}, nil } From 9b5d1412cce142bad88455d71fcb82cc91efb946 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 26 Aug 2024 22:18:47 +0800 Subject: [PATCH 501/571] core/state: fix trie prefetcher for verkle (#30354) This pull request fixes the panic issue in prefetcher once the verkle is activated. --- core/state/statedb.go | 8 ++-- core/state/trie_prefetcher.go | 60 +++++++++++++++++++++--------- core/state/trie_prefetcher_test.go | 44 ++++++++++++++++++++++ 3 files changed, 92 insertions(+), 20 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index ee91c931f3b5..32c20a3b7b4f 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -887,8 +887,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { return nil }) } - // If witness building is enabled, gather all the read-only accesses - if s.witness != nil { + // If witness building is enabled, gather all the read-only accesses. + // Skip witness collection in Verkle mode, they will be gathered + // together at the end. + if s.witness != nil && !s.db.TrieDB().IsVerkle() { // Pull in anything that has been accessed before destruction for _, obj := range s.stateObjectsDestruct { // Skip any objects that haven't touched their storage @@ -929,7 +931,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // only a single trie is used for state hashing. Replacing a non-nil verkle tree // here could result in losing uncommitted changes from storage. start = time.Now() - if s.prefetcher != nil && (s.trie == nil || !s.trie.IsVerkle()) { + if s.prefetcher != nil { if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil { log.Error("Failed to retrieve account pre-fetcher trie") } else { diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 491b3807c8d3..29dfdf04fa6f 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -40,6 +40,7 @@ var ( // // Note, the prefetcher's API is not thread safe. type triePrefetcher struct { + verkle bool // Flag whether the prefetcher is in verkle mode db Database // Database to fetch trie nodes through root common.Hash // Root hash of the account trie for metrics fetchers map[string]*subfetcher // Subfetchers for each trie @@ -66,6 +67,7 @@ type triePrefetcher struct { func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher { prefix := triePrefetchMetricsPrefix + namespace return &triePrefetcher{ + verkle: db.TrieDB().IsVerkle(), db: db, root: root, fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map @@ -196,12 +198,18 @@ func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie { func (p *triePrefetcher) used(owner common.Hash, root common.Hash, used [][]byte) { if fetcher := p.fetchers[p.trieID(owner, root)]; fetcher != nil { fetcher.wait() // ensure the fetcher's idle before poking in its internals - fetcher.used = used + fetcher.used = append(fetcher.used, used...) } } // trieID returns an unique trie identifier consists the trie owner and root hash. func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string { + // The trie in verkle is only identified by state root + if p.verkle { + return p.root.Hex() + } + // The trie in merkle is either identified by state root (account trie), + // or identified by the owner and trie root (storage trie) trieID := make([]byte, common.HashLength*2) copy(trieID, owner.Bytes()) copy(trieID[common.HashLength:], root.Bytes()) @@ -320,29 +328,47 @@ func (sf *subfetcher) terminate(async bool) { <-sf.term } +// openTrie resolves the target trie from database for prefetching. +func (sf *subfetcher) openTrie() error { + // Open the verkle tree if the sub-fetcher is in verkle mode. Note, there is + // only a single fetcher for verkle. + if sf.db.TrieDB().IsVerkle() { + tr, err := sf.db.OpenTrie(sf.state) + if err != nil { + log.Warn("Trie prefetcher failed opening verkle trie", "root", sf.root, "err", err) + return err + } + sf.trie = tr + return nil + } + // Open the merkle tree if the sub-fetcher is in merkle mode + if sf.owner == (common.Hash{}) { + tr, err := sf.db.OpenTrie(sf.state) + if err != nil { + log.Warn("Trie prefetcher failed opening account trie", "root", sf.root, "err", err) + return err + } + sf.trie = tr + return nil + } + tr, err := sf.db.OpenStorageTrie(sf.state, sf.addr, sf.root, nil) + if err != nil { + log.Warn("Trie prefetcher failed opening storage trie", "root", sf.root, "err", err) + return err + } + sf.trie = tr + return nil +} + // loop loads newly-scheduled trie tasks as they are received and loads them, stopping // when requested. func (sf *subfetcher) loop() { // No matter how the loop stops, signal anyone waiting that it's terminated defer close(sf.term) - // Start by opening the trie and stop processing if it fails - if sf.owner == (common.Hash{}) { - trie, err := sf.db.OpenTrie(sf.root) - if err != nil { - log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) - return - } - sf.trie = trie - } else { - trie, err := sf.db.OpenStorageTrie(sf.state, sf.addr, sf.root, nil) - if err != nil { - log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) - return - } - sf.trie = trie + if err := sf.openTrie(); err != nil { + return } - // Trie opened successfully, keep prefetching items for { select { case <-sf.wake: diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index 8f01acd2214d..a0a9d4110b00 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -24,6 +24,9 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/testrand" + "github.com/ethereum/go-ethereum/triedb" "github.com/holiman/uint256" ) @@ -62,3 +65,44 @@ func TestUseAfterTerminate(t *testing.T) { t.Errorf("Prefetcher returned nil trie after terminate") } } + +func TestVerklePrefetcher(t *testing.T) { + db := NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), triedb.VerkleDefaults) + state, err := New(types.EmptyRootHash, db, nil) + if err != nil { + t.Fatalf("failed to initialize state: %v", err) + } + // Create an account and check if the retrieved balance is correct + addr := testrand.Address() + skey := testrand.Hash() + sval := testrand.Hash() + + state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie + root, _ := state.Commit(0, true) + + state, _ = New(root, db, nil) + sRoot := state.GetStorageRoot(addr) + fetcher := newTriePrefetcher(db, root, "", false) + + // Read account + fetcher.prefetch(common.Hash{}, root, common.Address{}, [][]byte{ + addr.Bytes(), + }, false) + + // Read storage slot + fetcher.prefetch(crypto.Keccak256Hash(addr.Bytes()), sRoot, addr, [][]byte{ + skey.Bytes(), + }, false) + + fetcher.terminate(false) + accountTrie := fetcher.trie(common.Hash{}, root) + storageTrie := fetcher.trie(crypto.Keccak256Hash(addr.Bytes()), sRoot) + + rootA := accountTrie.Hash() + rootB := storageTrie.Hash() + if rootA != rootB { + t.Fatal("Two different tries are retrieved") + } +} From 87377c58bc7acd437b6495706e0dcfece6aa1d21 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Tue, 27 Aug 2024 14:10:32 +0200 Subject: [PATCH 502/571] p2p/discover: fix Write method in metered connection (#30355) `WriteToUDP` was never called, since `meteredUdpConn` exposed directly all the methods from the underlying `UDPConn` interface. This fixes the `discover/egress` metric never being updated. --- p2p/discover/metrics.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/p2p/discover/metrics.go b/p2p/discover/metrics.go index 8deafbbce47b..9261ae1376dd 100644 --- a/p2p/discover/metrics.go +++ b/p2p/discover/metrics.go @@ -18,6 +18,7 @@ package discover import ( "fmt" + "net" "net/netip" "github.com/ethereum/go-ethereum/metrics" @@ -47,7 +48,7 @@ func init() { // meteredUdpConn is a wrapper around a net.UDPConn that meters both the // inbound and outbound network traffic. type meteredUdpConn struct { - UDPConn + udpConn UDPConn } func newMeteredConn(conn UDPConn) UDPConn { @@ -55,19 +56,27 @@ func newMeteredConn(conn UDPConn) UDPConn { if !metrics.Enabled { return conn } - return &meteredUdpConn{UDPConn: conn} + return &meteredUdpConn{udpConn: conn} +} + +func (c *meteredUdpConn) Close() error { + return c.udpConn.Close() +} + +func (c *meteredUdpConn) LocalAddr() net.Addr { + return c.udpConn.LocalAddr() } // ReadFromUDPAddrPort delegates a network read to the underlying connection, bumping the udp ingress traffic meter along the way. func (c *meteredUdpConn) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) { - n, addr, err = c.UDPConn.ReadFromUDPAddrPort(b) + n, addr, err = c.udpConn.ReadFromUDPAddrPort(b) ingressTrafficMeter.Mark(int64(n)) return n, addr, err } -// WriteToUDP delegates a network write to the underlying connection, bumping the udp egress traffic meter along the way. -func (c *meteredUdpConn) WriteToUDP(b []byte, addr netip.AddrPort) (n int, err error) { - n, err = c.UDPConn.WriteToUDPAddrPort(b, addr) +// WriteToUDPAddrPort delegates a network write to the underlying connection, bumping the udp egress traffic meter along the way. +func (c *meteredUdpConn) WriteToUDPAddrPort(b []byte, addr netip.AddrPort) (n int, err error) { + n, err = c.udpConn.WriteToUDPAddrPort(b, addr) egressTrafficMeter.Mark(int64(n)) return n, err } From 9eb91542def0cfc231ba63a7637237ab8be5b0e7 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Tue, 27 Aug 2024 18:11:50 +0300 Subject: [PATCH 503/571] accounts/abi/bind, ethclient/simulated: check SendTransaction error in tests (#30349) In few tests the returned error from `SendTransaction` is not being checked. This PR checks the returned err in tests. Returning errors also revealed tx in `TestCommitReturnValue` is not actually being sent, and returns err ` only replay-protected (EIP-155) transactions allowed over RPC`. Fixed the transaction by using the `testTx` function. --- accounts/abi/bind/util_test.go | 12 +++++++++--- ethclient/simulated/backend_test.go | 13 +++++++------ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go index 592465f2acfb..04d1bb63bccc 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/util_test.go @@ -82,7 +82,9 @@ func TestWaitDeployed(t *testing.T) { }() // Send and mine the transaction. - backend.Client().SendTransaction(ctx, tx) + if err := backend.Client().SendTransaction(ctx, tx); err != nil { + t.Errorf("test %q: failed to send transaction: %v", name, err) + } backend.Commit() select { @@ -116,7 +118,9 @@ func TestWaitDeployedCornerCases(t *testing.T) { tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey) ctx, cancel := context.WithCancel(context.Background()) defer cancel() - backend.Client().SendTransaction(ctx, tx) + if err := backend.Client().SendTransaction(ctx, tx); err != nil { + t.Errorf("failed to send transaction: %q", err) + } backend.Commit() notContractCreation := errors.New("tx is not contract creation") if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != notContractCreation.Error() { @@ -134,6 +138,8 @@ func TestWaitDeployedCornerCases(t *testing.T) { } }() - backend.Client().SendTransaction(ctx, tx) + if err := backend.Client().SendTransaction(ctx, tx); err != nil { + t.Errorf("failed to send transaction: %q", err) + } cancel() } diff --git a/ethclient/simulated/backend_test.go b/ethclient/simulated/backend_test.go index b70086b3854c..308f5c44c9c1 100644 --- a/ethclient/simulated/backend_test.go +++ b/ethclient/simulated/backend_test.go @@ -213,7 +213,9 @@ func TestForkResendTx(t *testing.T) { if err != nil { t.Fatalf("could not create transaction: %v", err) } - client.SendTransaction(ctx, tx) + if err := client.SendTransaction(ctx, tx); err != nil { + t.Fatalf("sending transaction: %v", err) + } sim.Commit() // 3. @@ -256,11 +258,10 @@ func TestCommitReturnValue(t *testing.T) { } // Create a block in the original chain (containing a transaction to force different block hashes) - head, _ := client.HeaderByNumber(ctx, nil) // Should be child's, good enough - gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1)) - _tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil) - tx, _ := types.SignTx(_tx, types.HomesteadSigner{}, testKey) - client.SendTransaction(ctx, tx) + tx, _ := newTx(sim, testKey) + if err := client.SendTransaction(ctx, tx); err != nil { + t.Errorf("sending transaction: %v", err) + } h2 := sim.Commit() From 0e5546f032a9aadf1f3049e5c8a35c72e7bc613e Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 28 Aug 2024 08:18:23 +0200 Subject: [PATCH 504/571] core/state: semantic journalling (part 1) (#28880) This is a follow-up to #29520, and a preparatory PR to a more thorough change in the journalling system. ### API methods instead of `append` operations This PR hides the journal-implementation details away, so that the statedb invokes methods like `JournalCreate`, instead of explicitly appending journal-events in a list. This means that it's up to the journal whether to implement it as a sequence of events or aggregate/merge events. ### Snapshot-management inside the journal This PR also makes it so that management of valid snapshots is moved inside the journal, exposed via the methods `Snapshot() int` and `RevertToSnapshot(revid int, s *StateDB)`. ### SetCode JournalSetCode journals the setting of code: it is implicit that the previous values were "no code" and emptyCodeHash. Therefore, we can simplify the setCode journal. ### Selfdestruct The self-destruct journalling is a bit strange: we allow the selfdestruct operation to be journalled several times. This makes it so that we also are forced to store whether the account was already destructed. What we can do instead, is to only journal the first destruction, and after that only journal balance-changes, but not journal the selfdestruct itself. This simplifies the journalling, so that internals about state management does not leak into the journal-API. ### Preimages Preimages were, for some reason, integrated into the journal management, despite not being a consensus-critical data structure. This PR undoes that. --------- Co-authored-by: Gary Rong --- core/state/journal.go | 168 +++++++++++++++++++++++++------- core/state/state_object.go | 38 ++------ core/state/statedb.go | 86 +++++----------- core/state/statedb_fuzz_test.go | 2 +- core/state/statedb_test.go | 8 +- 5 files changed, 173 insertions(+), 129 deletions(-) diff --git a/core/state/journal.go b/core/state/journal.go index ad4a654fc6a2..f180a5dae4b6 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -17,12 +17,21 @@ package state import ( + "fmt" "maps" + "slices" + "sort" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/holiman/uint256" ) +type revision struct { + id int + journalIndex int +} + // journalEntry is a modification entry in the state change journal that can be // reverted on demand. type journalEntry interface { @@ -42,6 +51,9 @@ type journalEntry interface { type journal struct { entries []journalEntry // Current changes tracked by the journal dirties map[common.Address]int // Dirty accounts and the number of changes + + validRevisions []revision + nextRevisionId int } // newJournal creates a new initialized journal. @@ -51,6 +63,40 @@ func newJournal() *journal { } } +// reset clears the journal, after this operation the journal can be used anew. +// It is semantically similar to calling 'newJournal', but the underlying slices +// can be reused. +func (j *journal) reset() { + j.entries = j.entries[:0] + j.validRevisions = j.validRevisions[:0] + clear(j.dirties) + j.nextRevisionId = 0 +} + +// snapshot returns an identifier for the current revision of the state. +func (j *journal) snapshot() int { + id := j.nextRevisionId + j.nextRevisionId++ + j.validRevisions = append(j.validRevisions, revision{id, j.length()}) + return id +} + +// revertToSnapshot reverts all state changes made since the given revision. +func (j *journal) revertToSnapshot(revid int, s *StateDB) { + // Find the snapshot in the stack of valid snapshots. + idx := sort.Search(len(j.validRevisions), func(i int) bool { + return j.validRevisions[i].id >= revid + }) + if idx == len(j.validRevisions) || j.validRevisions[idx].id != revid { + panic(fmt.Errorf("revision id %v cannot be reverted", revid)) + } + snapshot := j.validRevisions[idx].journalIndex + + // Replay the journal to undo changes and remove invalidated snapshots + j.revert(s, snapshot) + j.validRevisions = j.validRevisions[:idx] +} + // append inserts a new modification entry to the end of the change journal. func (j *journal) append(entry journalEntry) { j.entries = append(j.entries, entry) @@ -95,11 +141,90 @@ func (j *journal) copy() *journal { entries = append(entries, j.entries[i].copy()) } return &journal{ - entries: entries, - dirties: maps.Clone(j.dirties), + entries: entries, + dirties: maps.Clone(j.dirties), + validRevisions: slices.Clone(j.validRevisions), + nextRevisionId: j.nextRevisionId, + } +} + +func (j *journal) logChange(txHash common.Hash) { + j.append(addLogChange{txhash: txHash}) +} + +func (j *journal) createObject(addr common.Address) { + j.append(createObjectChange{account: &addr}) +} + +func (j *journal) createContract(addr common.Address) { + j.append(createContractChange{account: addr}) +} + +func (j *journal) destruct(addr common.Address) { + j.append(selfDestructChange{account: &addr}) +} + +func (j *journal) storageChange(addr common.Address, key, prev, origin common.Hash) { + j.append(storageChange{ + account: &addr, + key: key, + prevvalue: prev, + origvalue: origin, + }) +} + +func (j *journal) transientStateChange(addr common.Address, key, prev common.Hash) { + j.append(transientStorageChange{ + account: &addr, + key: key, + prevalue: prev, + }) +} + +func (j *journal) refundChange(previous uint64) { + j.append(refundChange{prev: previous}) +} + +func (j *journal) balanceChange(addr common.Address, previous *uint256.Int) { + j.append(balanceChange{ + account: &addr, + prev: previous.Clone(), + }) +} + +func (j *journal) setCode(address common.Address) { + j.append(codeChange{account: &address}) +} + +func (j *journal) nonceChange(address common.Address, prev uint64) { + j.append(nonceChange{ + account: &address, + prev: prev, + }) +} + +func (j *journal) touchChange(address common.Address) { + j.append(touchChange{ + account: &address, + }) + if address == ripemd { + // Explicitly put it in the dirty-cache, which is otherwise generated from + // flattened journals. + j.dirty(address) } } +func (j *journal) accessListAddAccount(addr common.Address) { + j.append(accessListAddAccountChange{&addr}) +} + +func (j *journal) accessListAddSlot(addr common.Address, slot common.Hash) { + j.append(accessListAddSlotChange{ + address: &addr, + slot: &slot, + }) +} + type ( // Changes to the account trie. createObjectChange struct { @@ -114,9 +239,7 @@ type ( } selfDestructChange struct { - account *common.Address - prev bool // whether account had already self-destructed - prevbalance *uint256.Int + account *common.Address } // Changes to individual accounts. @@ -135,8 +258,7 @@ type ( origvalue common.Hash } codeChange struct { - account *common.Address - prevcode, prevhash []byte + account *common.Address } // Changes to other state values. @@ -146,9 +268,6 @@ type ( addLogChange struct { txhash common.Hash } - addPreimageChange struct { - hash common.Hash - } touchChange struct { account *common.Address } @@ -200,8 +319,7 @@ func (ch createContractChange) copy() journalEntry { func (ch selfDestructChange) revert(s *StateDB) { obj := s.getStateObject(*ch.account) if obj != nil { - obj.selfDestructed = ch.prev - obj.setBalance(ch.prevbalance) + obj.selfDestructed = false } } @@ -211,9 +329,7 @@ func (ch selfDestructChange) dirtied() *common.Address { func (ch selfDestructChange) copy() journalEntry { return selfDestructChange{ - account: ch.account, - prev: ch.prev, - prevbalance: new(uint256.Int).Set(ch.prevbalance), + account: ch.account, } } @@ -263,7 +379,7 @@ func (ch nonceChange) copy() journalEntry { } func (ch codeChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) + s.getStateObject(*ch.account).setCode(types.EmptyCodeHash, nil) } func (ch codeChange) dirtied() *common.Address { @@ -271,11 +387,7 @@ func (ch codeChange) dirtied() *common.Address { } func (ch codeChange) copy() journalEntry { - return codeChange{ - account: ch.account, - prevhash: common.CopyBytes(ch.prevhash), - prevcode: common.CopyBytes(ch.prevcode), - } + return codeChange{account: ch.account} } func (ch storageChange) revert(s *StateDB) { @@ -344,20 +456,6 @@ func (ch addLogChange) copy() journalEntry { } } -func (ch addPreimageChange) revert(s *StateDB) { - delete(s.preimages, ch.hash) -} - -func (ch addPreimageChange) dirtied() *common.Address { - return nil -} - -func (ch addPreimageChange) copy() journalEntry { - return addPreimageChange{ - hash: ch.hash, - } -} - func (ch accessListAddAccountChange) revert(s *StateDB) { /* One important invariant here, is that whenever a (addr, slot) is added, if the diff --git a/core/state/state_object.go b/core/state/state_object.go index 1e4da105b2ec..5946683bc051 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -114,14 +114,7 @@ func (s *stateObject) markSelfdestructed() { } func (s *stateObject) touch() { - s.db.journal.append(touchChange{ - account: &s.address, - }) - if s.address == ripemd { - // Explicitly put it in the dirty-cache, which is otherwise generated from - // flattened journals. - s.db.journal.dirty(s.address) - } + s.db.journal.touchChange(s.address) } // getTrie returns the associated storage trie. The trie will be opened if it's @@ -252,16 +245,11 @@ func (s *stateObject) SetState(key, value common.Hash) { return } // New value is different, update and journal the change - s.db.journal.append(storageChange{ - account: &s.address, - key: key, - prevvalue: prev, - origvalue: origin, - }) + s.db.journal.storageChange(s.address, key, prev, origin) + s.setState(key, value, origin) if s.db.logger != nil && s.db.logger.OnStorageChange != nil { s.db.logger.OnStorageChange(s.address, key, prev, value) } - s.setState(key, value, origin) } // setState updates a value in account dirty storage. The dirtiness will be @@ -511,10 +499,7 @@ func (s *stateObject) SubBalance(amount *uint256.Int, reason tracing.BalanceChan } func (s *stateObject) SetBalance(amount *uint256.Int, reason tracing.BalanceChangeReason) { - s.db.journal.append(balanceChange{ - account: &s.address, - prev: new(uint256.Int).Set(s.data.Balance), - }) + s.db.journal.balanceChange(s.address, s.data.Balance) if s.db.logger != nil && s.db.logger.OnBalanceChange != nil { s.db.logger.OnBalanceChange(s.address, s.Balance().ToBig(), amount.ToBig(), reason) } @@ -590,14 +575,10 @@ func (s *stateObject) CodeSize() int { } func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { - prevcode := s.Code() - s.db.journal.append(codeChange{ - account: &s.address, - prevhash: s.CodeHash(), - prevcode: prevcode, - }) + s.db.journal.setCode(s.address) if s.db.logger != nil && s.db.logger.OnCodeChange != nil { - s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), prevcode, codeHash, code) + // TODO remove prevcode from this callback + s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), nil, codeHash, code) } s.setCode(codeHash, code) } @@ -609,10 +590,7 @@ func (s *stateObject) setCode(codeHash common.Hash, code []byte) { } func (s *stateObject) SetNonce(nonce uint64) { - s.db.journal.append(nonceChange{ - account: &s.address, - prev: s.data.Nonce, - }) + s.db.journal.nonceChange(s.address, s.data.Nonce) if s.db.logger != nil && s.db.logger.OnNonceChange != nil { s.db.logger.OnNonceChange(s.address, s.data.Nonce, nonce) } diff --git a/core/state/statedb.go b/core/state/statedb.go index 32c20a3b7b4f..d93271d76b86 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -23,7 +23,6 @@ import ( "maps" "math/big" "slices" - "sort" "sync" "sync/atomic" "time" @@ -48,11 +47,6 @@ import ( // TriesInMemory represents the number of layers that are kept in RAM. const TriesInMemory = 128 -type revision struct { - id int - journalIndex int -} - type mutationType int const ( @@ -143,9 +137,7 @@ type StateDB struct { // Journal of state modifications. This is the backbone of // Snapshot and RevertToSnapshot. - journal *journal - validRevisions []revision - nextRevisionId int + journal *journal // State witness if cross validation is needed witness *stateless.Witness @@ -258,7 +250,7 @@ func (s *StateDB) Error() error { } func (s *StateDB) AddLog(log *types.Log) { - s.journal.append(addLogChange{txhash: s.thash}) + s.journal.logChange(s.thash) log.TxHash = s.thash log.TxIndex = uint(s.txIndex) @@ -292,7 +284,6 @@ func (s *StateDB) Logs() []*types.Log { // AddPreimage records a SHA3 preimage seen by the VM. func (s *StateDB) AddPreimage(hash common.Hash, preimage []byte) { if _, ok := s.preimages[hash]; !ok { - s.journal.append(addPreimageChange{hash: hash}) s.preimages[hash] = slices.Clone(preimage) } } @@ -304,14 +295,14 @@ func (s *StateDB) Preimages() map[common.Hash][]byte { // AddRefund adds gas to the refund counter func (s *StateDB) AddRefund(gas uint64) { - s.journal.append(refundChange{prev: s.refund}) + s.journal.refundChange(s.refund) s.refund += gas } // SubRefund removes gas from the refund counter. // This method will panic if the refund counter goes below zero func (s *StateDB) SubRefund(gas uint64) { - s.journal.append(refundChange{prev: s.refund}) + s.journal.refundChange(s.refund) if gas > s.refund { panic(fmt.Sprintf("Refund counter below zero (gas: %d > refund: %d)", gas, s.refund)) } @@ -508,20 +499,17 @@ func (s *StateDB) SelfDestruct(addr common.Address) { if stateObject == nil { return } - var ( - prev = new(uint256.Int).Set(stateObject.Balance()) - n = new(uint256.Int) - ) - s.journal.append(selfDestructChange{ - account: &addr, - prev: stateObject.selfDestructed, - prevbalance: prev, - }) - if s.logger != nil && s.logger.OnBalanceChange != nil && prev.Sign() > 0 { - s.logger.OnBalanceChange(addr, prev.ToBig(), n.ToBig(), tracing.BalanceDecreaseSelfdestruct) + // Regardless of whether it is already destructed or not, we do have to + // journal the balance-change, if we set it to zero here. + if !stateObject.Balance().IsZero() { + stateObject.SetBalance(new(uint256.Int), tracing.BalanceDecreaseSelfdestruct) + } + // If it is already marked as self-destructed, we do not need to add it + // for journalling a second time. + if !stateObject.selfDestructed { + s.journal.destruct(addr) + stateObject.markSelfdestructed() } - stateObject.markSelfdestructed() - stateObject.data.Balance = n } func (s *StateDB) Selfdestruct6780(addr common.Address) { @@ -542,11 +530,7 @@ func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash) if prev == value { return } - s.journal.append(transientStorageChange{ - account: &addr, - key: key, - prevalue: prev, - }) + s.journal.transientStateChange(addr, key, prev) s.setTransientState(addr, key, value) } @@ -668,7 +652,7 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { // existing account with the given address, otherwise it will be silently overwritten. func (s *StateDB) createObject(addr common.Address) *stateObject { obj := newObject(s, addr, nil) - s.journal.append(createObjectChange{account: &addr}) + s.journal.createObject(addr) s.setStateObject(obj) return obj } @@ -690,7 +674,7 @@ func (s *StateDB) CreateContract(addr common.Address) { obj := s.getStateObject(addr) if !obj.newContract { obj.newContract = true - s.journal.append(createContractChange{account: addr}) + s.journal.createContract(addr) } } @@ -714,8 +698,6 @@ func (s *StateDB) Copy() *StateDB { logSize: s.logSize, preimages: maps.Clone(s.preimages), journal: s.journal.copy(), - validRevisions: slices.Clone(s.validRevisions), - nextRevisionId: s.nextRevisionId, // In order for the block producer to be able to use and make additions // to the snapshot tree, we need to copy that as well. Otherwise, any @@ -761,26 +743,12 @@ func (s *StateDB) Copy() *StateDB { // Snapshot returns an identifier for the current revision of the state. func (s *StateDB) Snapshot() int { - id := s.nextRevisionId - s.nextRevisionId++ - s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()}) - return id + return s.journal.snapshot() } // RevertToSnapshot reverts all state changes made since the given revision. func (s *StateDB) RevertToSnapshot(revid int) { - // Find the snapshot in the stack of valid snapshots. - idx := sort.Search(len(s.validRevisions), func(i int) bool { - return s.validRevisions[i].id >= revid - }) - if idx == len(s.validRevisions) || s.validRevisions[idx].id != revid { - panic(fmt.Errorf("revision id %v cannot be reverted", revid)) - } - snapshot := s.validRevisions[idx].journalIndex - - // Replay the journal to undo changes and remove invalidated snapshots - s.journal.revert(s, snapshot) - s.validRevisions = s.validRevisions[:idx] + s.journal.revertToSnapshot(revid, s) } // GetRefund returns the current value of the refund counter. @@ -996,11 +964,8 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int) { } func (s *StateDB) clearJournalAndRefund() { - if len(s.journal.entries) > 0 { - s.journal = newJournal() - s.refund = 0 - } - s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entries + s.journal.reset() + s.refund = 0 } // fastDeleteStorage is the function that efficiently deletes the storage trie @@ -1431,7 +1396,7 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d // AddAddressToAccessList adds the given address to the access list func (s *StateDB) AddAddressToAccessList(addr common.Address) { if s.accessList.AddAddress(addr) { - s.journal.append(accessListAddAccountChange{&addr}) + s.journal.accessListAddAccount(addr) } } @@ -1443,13 +1408,10 @@ func (s *StateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) { // scope of 'address' without having the 'address' become already added // to the access list (via call-variant, create, etc). // Better safe than sorry, though - s.journal.append(accessListAddAccountChange{&addr}) + s.journal.accessListAddAccount(addr) } if slotMod { - s.journal.append(accessListAddSlotChange{ - address: &addr, - slot: &slot, - }) + s.journal.accessListAddSlot(addr, slot) } } diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 40b079cd8a43..153035b9c168 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -73,7 +73,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction args: make([]int64, 1), }, { - name: "SetState", + name: "SetStorage", fn: func(a testAction, s *StateDB) { var key, val common.Hash binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 2ce2b868faa9..a8ae6eb6d3f5 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -360,7 +360,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { args: make([]int64, 1), }, { - name: "SetState", + name: "SetStorage", fn: func(a testAction, s *StateDB) { var key, val common.Hash binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) @@ -372,6 +372,12 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { { name: "SetCode", fn: func(a testAction, s *StateDB) { + // SetCode can only be performed in case the addr does + // not already hold code + if c := s.GetCode(addr); len(c) > 0 { + // no-op + return + } code := make([]byte, 16) binary.BigEndian.PutUint64(code, uint64(a.args[0])) binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) From ea3b5095f439d63e35c8c37941836f4815fb380a Mon Sep 17 00:00:00 2001 From: markus <55011443+mdymalla@users.noreply.github.com> Date: Wed, 28 Aug 2024 22:12:09 +1000 Subject: [PATCH 505/571] signer/core/apitypes: support fixed size arrays for EIP-712 typed data (#30175) When attempting to hash a typed data struct that includes a type reference with a fixed-size array, the validation process fails. According to EIP-712, arrays can be either fixed-size or dynamic, denoted by `Type[n]` or `Type[]` respectively, although it appears this currently isn't supported. This change modifies the validation logic to accommodate types containing fixed-size arrays. --- .../apitypes/signed_data_internal_test.go | 46 +++++++++++++++++++ signer/core/apitypes/types.go | 7 +-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/signer/core/apitypes/signed_data_internal_test.go b/signer/core/apitypes/signed_data_internal_test.go index 8067893c2134..8b4a839c1d87 100644 --- a/signer/core/apitypes/signed_data_internal_test.go +++ b/signer/core/apitypes/signed_data_internal_test.go @@ -240,3 +240,49 @@ func TestConvertAddressDataToSlice(t *testing.T) { t.Fatal(err) } } + +func TestTypedDataArrayValidate(t *testing.T) { + t.Parallel() + + typedData := TypedData{ + Types: Types{ + "BulkOrder": []Type{ + // Should be able to accept fixed size arrays + {Name: "tree", Type: "OrderComponents[2][2]"}, + }, + "OrderComponents": []Type{ + {Name: "offerer", Type: "address"}, + {Name: "amount", Type: "uint8"}, + }, + "EIP712Domain": []Type{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint8"}, + {Name: "verifyingContract", Type: "address"}, + }, + }, + PrimaryType: "BulkOrder", + Domain: TypedDataDomain{ + VerifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", + }, + Message: TypedDataMessage{}, + } + + if err := typedData.validate(); err != nil { + t.Errorf("expected typed data to pass validation, got: %v", err) + } + + // Should be able to accept dynamic arrays + typedData.Types["BulkOrder"][0].Type = "OrderComponents[]" + + if err := typedData.validate(); err != nil { + t.Errorf("expected typed data to pass validation, got: %v", err) + } + + // Should be able to accept standard types + typedData.Types["BulkOrder"][0].Type = "OrderComponents" + + if err := typedData.validate(); err != nil { + t.Errorf("expected typed data to pass validation, got: %v", err) + } +} diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index e886d7fc443e..72cad88ec200 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -40,7 +40,7 @@ import ( "github.com/holiman/uint256" ) -var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Za-z](\w*)(\[\])?$`) +var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Za-z](\w*)(\[\d*\])*$`) type ValidationInfo struct { Typ string `json:"type"` @@ -332,8 +332,9 @@ func (t *Type) isArray() bool { // typeName returns the canonical name of the type. If the type is 'Person[]', then // this method returns 'Person' func (t *Type) typeName() string { - if strings.HasSuffix(t.Type, "[]") { - return strings.TrimSuffix(t.Type, "[]") + if strings.Contains(t.Type, "[") { + re := regexp.MustCompile(`\[\d*\]`) + return re.ReplaceAllString(t.Type, "") } return t.Type } From e9467eec1cfc882afb47623147c64b7fbf22bfe1 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:50:27 +0200 Subject: [PATCH 506/571] consensus/beacon, core/types: add verkle witness builder (#30129) This PR adds the bulk verkle witness+proof production at the end of block production. It reads all data from the tree in one swoop and produces a verkle proof. Co-authored-by: Felix Lange --- beacon/engine/gen_ed.go | 74 +++++++++++++++++++---------------- beacon/engine/types.go | 74 ++++++++++++++++++----------------- consensus/beacon/consensus.go | 35 ++++++++++++++++- core/chain_makers.go | 5 +-- core/state/statedb.go | 13 +++++- core/state_processor.go | 6 +++ core/state_processor_test.go | 15 ++++++- core/types/block.go | 28 +++++++++++++ go.mod | 2 +- go.sum | 4 +- trie/verkle.go | 25 ++++++++++++ 11 files changed, 201 insertions(+), 80 deletions(-) diff --git a/beacon/engine/gen_ed.go b/beacon/engine/gen_ed.go index 6893d64a1626..0ae5a3b8f1f1 100644 --- a/beacon/engine/gen_ed.go +++ b/beacon/engine/gen_ed.go @@ -17,23 +17,24 @@ var _ = (*executableDataMarshaling)(nil) // MarshalJSON marshals as JSON. func (e ExecutableData) MarshalJSON() ([]byte, error) { type ExecutableData struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` - StateRoot common.Hash `json:"stateRoot" gencodec:"required"` - ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` - LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"` - Random common.Hash `json:"prevRandao" gencodec:"required"` - Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"` - GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` - ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"` - BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` - BlockHash common.Hash `json:"blockHash" gencodec:"required"` - Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` - Withdrawals []*types.Withdrawal `json:"withdrawals"` - BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` - ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` + StateRoot common.Hash `json:"stateRoot" gencodec:"required"` + ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` + LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"` + Random common.Hash `json:"prevRandao" gencodec:"required"` + Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` + ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"` + BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` + BlockHash common.Hash `json:"blockHash" gencodec:"required"` + Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` + BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` + ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` } var enc ExecutableData enc.ParentHash = e.ParentHash @@ -58,29 +59,31 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) { enc.Withdrawals = e.Withdrawals enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) + enc.ExecutionWitness = e.ExecutionWitness return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. func (e *ExecutableData) UnmarshalJSON(input []byte) error { type ExecutableData struct { - ParentHash *common.Hash `json:"parentHash" gencodec:"required"` - FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"` - StateRoot *common.Hash `json:"stateRoot" gencodec:"required"` - ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"` - LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"` - Random *common.Hash `json:"prevRandao" gencodec:"required"` - Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"` - GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` - ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"` - BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` - BlockHash *common.Hash `json:"blockHash" gencodec:"required"` - Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` - Withdrawals []*types.Withdrawal `json:"withdrawals"` - BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` - ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + ParentHash *common.Hash `json:"parentHash" gencodec:"required"` + FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"` + StateRoot *common.Hash `json:"stateRoot" gencodec:"required"` + ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"` + LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"` + Random *common.Hash `json:"prevRandao" gencodec:"required"` + Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"` + BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` + BlockHash *common.Hash `json:"blockHash" gencodec:"required"` + Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` + BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` + ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` } var dec ExecutableData if err := json.Unmarshal(input, &dec); err != nil { @@ -154,5 +157,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error { if dec.ExcessBlobGas != nil { e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) } + if dec.ExecutionWitness != nil { + e.ExecutionWitness = dec.ExecutionWitness + } return nil } diff --git a/beacon/engine/types.go b/beacon/engine/types.go index d1b3aa22abdf..8687a6f5041d 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -59,23 +59,24 @@ type payloadAttributesMarshaling struct { // ExecutableData is the data necessary to execute an EL payload. type ExecutableData struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` - StateRoot common.Hash `json:"stateRoot" gencodec:"required"` - ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` - LogsBloom []byte `json:"logsBloom" gencodec:"required"` - Random common.Hash `json:"prevRandao" gencodec:"required"` - Number uint64 `json:"blockNumber" gencodec:"required"` - GasLimit uint64 `json:"gasLimit" gencodec:"required"` - GasUsed uint64 `json:"gasUsed" gencodec:"required"` - Timestamp uint64 `json:"timestamp" gencodec:"required"` - ExtraData []byte `json:"extraData" gencodec:"required"` - BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"` - BlockHash common.Hash `json:"blockHash" gencodec:"required"` - Transactions [][]byte `json:"transactions" gencodec:"required"` - Withdrawals []*types.Withdrawal `json:"withdrawals"` - BlobGasUsed *uint64 `json:"blobGasUsed"` - ExcessBlobGas *uint64 `json:"excessBlobGas"` + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` + StateRoot common.Hash `json:"stateRoot" gencodec:"required"` + ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` + LogsBloom []byte `json:"logsBloom" gencodec:"required"` + Random common.Hash `json:"prevRandao" gencodec:"required"` + Number uint64 `json:"blockNumber" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` + Timestamp uint64 `json:"timestamp" gencodec:"required"` + ExtraData []byte `json:"extraData" gencodec:"required"` + BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"` + BlockHash common.Hash `json:"blockHash" gencodec:"required"` + Transactions [][]byte `json:"transactions" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` + BlobGasUsed *uint64 `json:"blobGasUsed"` + ExcessBlobGas *uint64 `json:"excessBlobGas"` + ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` } // JSON type overrides for executableData. @@ -251,7 +252,9 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b BlobGasUsed: data.BlobGasUsed, ParentBeaconRoot: beaconRoot, } - block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}) + block := types.NewBlockWithHeader(header) + block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}) + block = block.WithWitness(data.ExecutionWitness) if block.Hash() != data.BlockHash { return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash()) } @@ -262,23 +265,24 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b // fields from the given block. It assumes the given block is post-merge block. func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar) *ExecutionPayloadEnvelope { data := &ExecutableData{ - BlockHash: block.Hash(), - ParentHash: block.ParentHash(), - FeeRecipient: block.Coinbase(), - StateRoot: block.Root(), - Number: block.NumberU64(), - GasLimit: block.GasLimit(), - GasUsed: block.GasUsed(), - BaseFeePerGas: block.BaseFee(), - Timestamp: block.Time(), - ReceiptsRoot: block.ReceiptHash(), - LogsBloom: block.Bloom().Bytes(), - Transactions: encodeTransactions(block.Transactions()), - Random: block.MixDigest(), - ExtraData: block.Extra(), - Withdrawals: block.Withdrawals(), - BlobGasUsed: block.BlobGasUsed(), - ExcessBlobGas: block.ExcessBlobGas(), + BlockHash: block.Hash(), + ParentHash: block.ParentHash(), + FeeRecipient: block.Coinbase(), + StateRoot: block.Root(), + Number: block.NumberU64(), + GasLimit: block.GasLimit(), + GasUsed: block.GasUsed(), + BaseFeePerGas: block.BaseFee(), + Timestamp: block.Time(), + ReceiptsRoot: block.ReceiptHash(), + LogsBloom: block.Bloom().Bytes(), + Transactions: encodeTransactions(block.Transactions()), + Random: block.MixDigest(), + ExtraData: block.Extra(), + Withdrawals: block.Withdrawals(), + BlobGasUsed: block.BlobGasUsed(), + ExcessBlobGas: block.ExcessBlobGas(), + ExecutionWitness: block.ExecutionWitness(), } bundle := BlobsBundleV1{ Commitments: make([]hexutil.Bytes, 0), diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 19763ed303f1..ae4c9f29a1cd 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -387,8 +387,39 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea // Assign the final state root to header. header.Root = state.IntermediateRoot(true) - // Assemble and return the final block. - return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil + // Assemble the final block. + block := types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)) + + // Create the block witness and attach to block. + // This step needs to happen as late as possible to catch all access events. + if chain.Config().IsVerkle(header.Number, header.Time) { + keys := state.AccessEvents().Keys() + + // Open the pre-tree to prove the pre-state against + parent := chain.GetHeaderByNumber(header.Number.Uint64() - 1) + if parent == nil { + return nil, fmt.Errorf("nil parent header for block %d", header.Number) + } + + preTrie, err := state.Database().OpenTrie(parent.Root) + if err != nil { + return nil, fmt.Errorf("error opening pre-state tree root: %w", err) + } + + vktPreTrie, okpre := preTrie.(*trie.VerkleTrie) + vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie) + if okpre && okpost { + if len(keys) > 0 { + verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys, vktPreTrie.FlatdbNodeResolver) + if err != nil { + return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err) + } + block = block.WithWitness(&types.ExecutionWitness{StateDiff: stateDiff, VerkleProof: verkleProof}) + } + } + } + + return block, nil } // Seal generates a new sealing request for the given input block and pushes diff --git a/core/chain_makers.go b/core/chain_makers.go index 58985347bb31..6cee6fdc8a11 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -467,9 +467,8 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine panic(fmt.Sprintf("trie write error: %v", err)) } - // TODO uncomment when proof generation is merged - // proofs = append(proofs, block.ExecutionWitness().VerkleProof) - // keyvals = append(keyvals, block.ExecutionWitness().StateDiff) + proofs = append(proofs, block.ExecutionWitness().VerkleProof) + keyvals = append(keyvals, block.ExecutionWitness().StateDiff) return block, b.receipts } diff --git a/core/state/statedb.go b/core/state/statedb.go index d93271d76b86..300ce29a674f 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -130,7 +130,8 @@ type StateDB struct { preimages map[common.Hash][]byte // Per-transaction access list - accessList *accessList + accessList *accessList + accessEvents *AccessEvents // Transient storage transientStorage transientStorage @@ -184,6 +185,9 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) transientStorage: newTransientStorage(), hasher: crypto.NewKeccakState(), } + if db.TrieDB().IsVerkle() { + sdb.accessEvents = NewAccessEvents(db.(*cachingDB).pointCache) + } if sdb.snaps != nil { sdb.snap = sdb.snaps.Snapshot(root) } @@ -709,6 +713,9 @@ func (s *StateDB) Copy() *StateDB { if s.witness != nil { state.witness = s.witness.Copy() } + if s.accessEvents != nil { + state.accessEvents = s.accessEvents.Copy() + } // Deep copy cached state objects. for addr, obj := range s.stateObjects { state.stateObjects[addr] = obj.deepCopy(state) @@ -1452,3 +1459,7 @@ func (s *StateDB) PointCache() *utils.PointCache { func (s *StateDB) Witness() *stateless.Witness { return s.witness } + +func (s *StateDB) AccessEvents() *AccessEvents { + return s.accessEvents +} diff --git a/core/state_processor.go b/core/state_processor.go index 44224958ddce..c13b69602244 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -153,6 +153,12 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) } + // Merge the tx-local access event into the "block-local" one, in order to collect + // all values, so that the witness can be built. + if statedb.GetTrie().IsVerkle() { + statedb.AccessEvents().Merge(evm.AccessEvents) + } + // Set the receipt logs and create the bloom filter. receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index bf29fb97733f..307ab75c5ba5 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/triedb" + "github.com/ethereum/go-verkle" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) @@ -491,7 +492,7 @@ func TestProcessVerkle(t *testing.T) { txCost1*2 + txCost2, txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas, } - _, chain, _, _, _ := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { + _, chain, _, proofs, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { gen.SetPoS() // TODO need to check that the tx cost provided is the exact amount used (no remaining left-over) @@ -512,7 +513,17 @@ func TestProcessVerkle(t *testing.T) { } }) - t.Log("inserting blocks into the chain") + // Check proof for both blocks + err := verkle.Verify(proofs[0], gspec.ToBlock().Root().Bytes(), chain[0].Root().Bytes(), statediffs[0]) + if err != nil { + t.Fatal(err) + } + err = verkle.Verify(proofs[1], chain[0].Root().Bytes(), chain[1].Root().Bytes(), statediffs[1]) + if err != nil { + t.Fatal(err) + } + + t.Log("verified verkle proof, inserting blocks into the chain") endnum, err := blockchain.InsertChain(chain) if err != nil { diff --git a/core/types/block.go b/core/types/block.go index 4857cd6e50c8..e6ddf2012f61 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-verkle" ) // A BlockNonce is a 64-bit hash which proves (combined with the @@ -59,6 +60,13 @@ func (n *BlockNonce) UnmarshalText(input []byte) error { return hexutil.UnmarshalFixedText("BlockNonce", input, n[:]) } +// ExecutionWitness represents the witness + proof used in a verkle context, +// to provide the ability to execute a block statelessly. +type ExecutionWitness struct { + StateDiff verkle.StateDiff `json:"stateDiff"` + VerkleProof *verkle.VerkleProof `json:"verkleProof"` +} + //go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go //go:generate go run ../../rlp/rlpgen -type Header -out gen_header_rlp.go @@ -197,6 +205,11 @@ type Block struct { transactions Transactions withdrawals Withdrawals + // witness is not an encoded part of the block body. + // It is held in Block in order for easy relaying to the places + // that process it. + witness *ExecutionWitness + // caches hash atomic.Pointer[common.Hash] size atomic.Uint64 @@ -401,6 +414,9 @@ func (b *Block) BlobGasUsed() *uint64 { return blobGasUsed } +// ExecutionWitness returns the verkle execution witneess + proof for a block +func (b *Block) ExecutionWitness() *ExecutionWitness { return b.witness } + // Size returns the true RLP encoded storage size of the block, either by encoding // and returning it, or returning a previously cached value. func (b *Block) Size() uint64 { @@ -448,6 +464,7 @@ func (b *Block) WithSeal(header *Header) *Block { transactions: b.transactions, uncles: b.uncles, withdrawals: b.withdrawals, + witness: b.witness, } } @@ -459,6 +476,7 @@ func (b *Block) WithBody(body Body) *Block { transactions: slices.Clone(body.Transactions), uncles: make([]*Header, len(body.Uncles)), withdrawals: slices.Clone(body.Withdrawals), + witness: b.witness, } for i := range body.Uncles { block.uncles[i] = CopyHeader(body.Uncles[i]) @@ -466,6 +484,16 @@ func (b *Block) WithBody(body Body) *Block { return block } +func (b *Block) WithWitness(witness *ExecutionWitness) *Block { + return &Block{ + header: b.header, + transactions: b.transactions, + uncles: b.uncles, + withdrawals: b.withdrawals, + witness: witness, + } +} + // Hash returns the keccak256 hash of b's header. // The hash is computed on the first call and cached thereafter. func (b *Block) Hash() common.Hash { diff --git a/go.mod b/go.mod index 49f2835c3e77..a8f5d11a89eb 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 github.com/ethereum/c-kzg-4844 v1.0.0 - github.com/ethereum/go-verkle v0.1.1-0.20240726143912-7dc5142667fa + github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.2 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e diff --git a/go.sum b/go.sum index 4540dbfa42a8..ab9bff9960be 100644 --- a/go.sum +++ b/go.sum @@ -170,8 +170,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-verkle v0.1.1-0.20240726143912-7dc5142667fa h1:mXkPoR07WlPVAClNzWuGAQNqmhxLqQILXhm73J5d9Ew= -github.com/ethereum/go-verkle v0.1.1-0.20240726143912-7dc5142667fa/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= +github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A= +github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= diff --git a/trie/verkle.go b/trie/verkle.go index fab1ccb48ac5..60293e899894 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -69,6 +69,10 @@ func NewVerkleTrie(root common.Hash, db database.Database, cache *utils.PointCac }, nil } +func (t *VerkleTrie) FlatdbNodeResolver(path []byte) ([]byte, error) { + return t.reader.node(path, common.Hash{}) +} + // GetKey returns the sha3 preimage of a hashed key that was previously used // to store a value. func (t *VerkleTrie) GetKey(key []byte) []byte { @@ -303,6 +307,27 @@ func (t *VerkleTrie) IsVerkle() bool { return true } +// Proof builds and returns the verkle multiproof for keys, built against +// the pre tree. The post tree is passed in order to add the post values +// to that proof. +func (t *VerkleTrie) Proof(posttrie *VerkleTrie, keys [][]byte, resolver verkle.NodeResolverFn) (*verkle.VerkleProof, verkle.StateDiff, error) { + var postroot verkle.VerkleNode + if posttrie != nil { + postroot = posttrie.root + } + proof, _, _, _, err := verkle.MakeVerkleMultiProof(t.root, postroot, keys, resolver) + if err != nil { + return nil, nil, err + } + + p, kvps, err := verkle.SerializeProof(proof) + if err != nil { + return nil, nil, err + } + + return p, kvps, nil +} + // ChunkedCode represents a sequence of 32-bytes chunks of code (31 bytes of which // are actual code, and 1 byte is the pushdata offset). type ChunkedCode []byte From ab3ee99ca9aa46163f1dfbaf10260718d8de9e10 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 30 Aug 2024 09:13:02 -0300 Subject: [PATCH 507/571] trie, core/state: Nyota EIP-6800 & EIP-4762 spec updates (#30357) This PR implements changes related to [EIP-6800](https://eips.ethereum.org/EIPS/eip-6800) and [EIP-4762](https://eips.ethereum.org/EIPS/eip-4762) spec updates. A TL;DR of the changes is that `Version`, `Balance`, `Nonce` and `CodeSize` are encoded in a single leaf named `BasicData`. For more details, see the [_Header Values_ table in EIP-6800](https://eips.ethereum.org/EIPS/eip-6800#header-values). The motivation for this was simplifying access event patterns, reducing code complexity, and, as a side effect, saving gas since fewer leaf nodes must be accessed. --------- Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: Felix Lange --- core/genesis_test.go | 2 +- core/state/access_events.go | 69 +++++-------------------- core/state/access_events_test.go | 36 +++++-------- core/state/database.go | 2 +- core/state/statedb.go | 2 +- core/state_processor_test.go | 31 +++++++++++- core/state_transition.go | 2 +- core/vm/operations_verkle.go | 18 +++---- trie/secure_trie.go | 2 +- trie/utils/verkle.go | 80 ++++++++--------------------- trie/utils/verkle_test.go | 21 +++----- trie/verkle.go | 87 ++++++++++++++------------------ trie/verkle_test.go | 16 +++--- 13 files changed, 140 insertions(+), 228 deletions(-) diff --git a/core/genesis_test.go b/core/genesis_test.go index ad602db4be23..fde458c4c837 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -294,7 +294,7 @@ func TestVerkleGenesisCommit(t *testing.T) { }, } - expected := common.FromHex("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b") + expected := common.FromHex("4a83dc39eb688dbcfaf581d60e82de18f875e38786ebce5833342011d6fef37b") got := genesis.ToBlock().Root().Bytes() if !bytes.Equal(got, expected) { t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got) diff --git a/core/state/access_events.go b/core/state/access_events.go index 4b6c7c7e69bb..c593f8202721 100644 --- a/core/state/access_events.go +++ b/core/state/access_events.go @@ -94,11 +94,8 @@ func (ae *AccessEvents) Copy() *AccessEvents { // member fields of an account. func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 { var gas uint64 - gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite) - gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite) - gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite) - gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite) - gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite) + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite) + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite) return gas } @@ -107,8 +104,7 @@ func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 { // call to that account. func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 { var gas uint64 - gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false) - gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false) + gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.BasicDataLeafKey, false) return gas } @@ -116,8 +112,8 @@ func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 { // cold balance member fields of the caller and the callee accounts. func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 { var gas uint64 - gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true) - gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true) + gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BasicDataLeafKey, true) + gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BasicDataLeafKey, true) return gas } @@ -125,32 +121,22 @@ func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) // a contract creation. func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 { var gas uint64 - gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true) - gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true) - if createSendsValue { - gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true) - } + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true) return gas } // AddTxOrigin adds the member fields of the sender account to the access event list, // so that cold accesses are not charged, since they are covered by the 21000 gas. func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) { - ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey, false) - ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey, true) - ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey, true) - ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey, false) - ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false) + ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BasicDataLeafKey, true) + ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeHashLeafKey, false) } // AddTxDestination adds the member fields of the sender account to the access event list, // so that cold accesses are not charged, since they are covered by the 21000 gas. func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) { - ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false) - ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, sendsValue) - ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, false) - ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, false) - ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false) + ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, sendsValue) + ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false) } // SlotGas returns the amount of gas to be charged for a cold storage access. @@ -275,39 +261,12 @@ func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC, return statelessGasCharged } -// VersionGas adds the account's version to the accessed data, and returns the +// BasicDataGas adds the account's basic data to the accessed data, and returns the // amount of gas that it costs. // Note that an access in write mode implies an access in read mode, whereas an // access in read mode does not imply an access in write mode. -func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 { - return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite) -} - -// BalanceGas adds the account's balance to the accessed data, and returns the -// amount of gas that it costs. -// in write mode. If false, the charged gas corresponds to an access in read mode. -// Note that an access in write mode implies an access in read mode, whereas an access in -// read mode does not imply an access in write mode. -func (ae *AccessEvents) BalanceGas(addr common.Address, isWrite bool) uint64 { - return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite) -} - -// NonceGas adds the account's nonce to the accessed data, and returns the -// amount of gas that it costs. -// in write mode. If false, the charged gas corresponds to an access in read mode. -// Note that an access in write mode implies an access in read mode, whereas an access in -// read mode does not imply an access in write mode. -func (ae *AccessEvents) NonceGas(addr common.Address, isWrite bool) uint64 { - return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite) -} - -// CodeSizeGas adds the account's code size to the accessed data, and returns the -// amount of gas that it costs. -// in write mode. If false, the charged gas corresponds to an access in read mode. -// Note that an access in write mode implies an access in read mode, whereas an access in -// read mode does not imply an access in write mode. -func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 { - return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite) +func (ae *AccessEvents) BasicDataGas(addr common.Address, isWrite bool) uint64 { + return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite) } // CodeHashGas adds the account's code hash to the accessed data, and returns the @@ -316,5 +275,5 @@ func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 { // Note that an access in write mode implies an access in read mode, whereas an access in // read mode does not imply an access in write mode. func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 { - return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite) + return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite) } diff --git a/core/state/access_events_test.go b/core/state/access_events_test.go index c8c93accfdfe..a35266950e64 100644 --- a/core/state/access_events_test.go +++ b/core/state/access_events_test.go @@ -40,55 +40,43 @@ func TestAccountHeaderGas(t *testing.T) { ae := NewAccessEvents(utils.NewPointCache(1024)) // Check cold read cost - gas := ae.VersionGas(testAddr, false) + gas := ae.BasicDataGas(testAddr, false) if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want { t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check warm read cost - gas = ae.VersionGas(testAddr, false) + gas = ae.BasicDataGas(testAddr, false) if gas != 0 { t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) } // Check cold read costs in the same group no longer incur the branch read cost - gas = ae.BalanceGas(testAddr, false) - if gas != params.WitnessChunkReadCost { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) - } - gas = ae.NonceGas(testAddr, false) - if gas != params.WitnessChunkReadCost { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) - } - gas = ae.CodeSizeGas(testAddr, false) - if gas != params.WitnessChunkReadCost { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) - } gas = ae.CodeHashGas(testAddr, false) if gas != params.WitnessChunkReadCost { t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) } // Check cold write cost - gas = ae.VersionGas(testAddr, true) + gas = ae.BasicDataGas(testAddr, true) if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want { t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check warm write cost - gas = ae.VersionGas(testAddr, true) + gas = ae.BasicDataGas(testAddr, true) if gas != 0 { t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) } // Check a write without a read charges both read and write costs - gas = ae.BalanceGas(testAddr2, true) + gas = ae.BasicDataGas(testAddr2, true) if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want { t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check that a write followed by a read charges nothing - gas = ae.BalanceGas(testAddr2, false) + gas = ae.BasicDataGas(testAddr2, false) if gas != 0 { t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) } @@ -113,7 +101,7 @@ func TestContractCreateInitGas(t *testing.T) { // Check cold read cost, without a value gas := ae.ContractCreateInitGas(testAddr, false) - if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*2; gas != want { + if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want { t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } @@ -131,17 +119,17 @@ func TestMessageCallGas(t *testing.T) { // Check cold read cost, without a value gas := ae.MessageCallGas(testAddr) - if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost*2; gas != want { + if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want { t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } - // Check that reading the version and code size of the same account does not incur the branch read cost - gas = ae.VersionGas(testAddr, false) + // Check that reading the basic data and code hash of the same account does not incur the branch read cost + gas = ae.BasicDataGas(testAddr, false) if gas != 0 { t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) } - gas = ae.CodeSizeGas(testAddr, false) - if gas != 0 { + gas = ae.CodeHashGas(testAddr, false) + if gas != params.WitnessChunkReadCost { t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) } diff --git a/core/state/database.go b/core/state/database.go index d54417d2f91e..38ec4ef8b85f 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -94,7 +94,7 @@ type Trie interface { // UpdateAccount abstracts an account write to the trie. It encodes the // provided account object with associated algorithm and then updates it // in the trie with provided address. - UpdateAccount(address common.Address, account *types.StateAccount) error + UpdateAccount(address common.Address, account *types.StateAccount, codeLen int) error // UpdateStorage associates key with value in the trie. If value has length zero, // any existing value is deleted from the trie. The value bytes must not be modified diff --git a/core/state/statedb.go b/core/state/statedb.go index 300ce29a674f..f81c8a055b0c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -557,7 +557,7 @@ func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common func (s *StateDB) updateStateObject(obj *stateObject) { // Encode the account and update the account trie addr := obj.Address() - if err := s.trie.UpdateAccount(addr, &obj.data); err != nil { + if err := s.trie.UpdateAccount(addr, &obj.data, len(obj.code)); err != nil { s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err)) } if obj.dirtyCode { diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 307ab75c5ba5..4149cd2df3b9 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -486,8 +486,35 @@ func TestProcessVerkle(t *testing.T) { txCost1 := params.TxGas txCost2 := params.TxGas - contractCreationCost := intrinsicContractCreationGas + uint64(2039 /* execution costs */) - codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + uint64(57444 /* execution costs */) + contractCreationCost := intrinsicContractCreationGas + + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* creation with value */ + 739 /* execution costs */ + codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (tx) */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at pc=0x20) */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */ + params.WitnessChunkReadCost + /* SLOAD in constructor */ + params.WitnessChunkWriteCost + /* SSTORE in constructor */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at PC=0x121) */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */ + params.WitnessChunkReadCost + /* SLOAD in constructor */ + params.WitnessChunkWriteCost + /* SSTORE in constructor */ + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash for tx creation */ + 15*(params.WitnessChunkReadCost+params.WitnessChunkWriteCost) + /* code chunks #0..#14 */ + 4844 /* execution costs */ blockGasUsagesExpected := []uint64{ txCost1*2 + txCost2, txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas, diff --git a/core/state_transition.go b/core/state_transition.go index 1a6a66a2fc14..37807d3d2b68 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -470,7 +470,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { // add the coinbase to the witness iff the fee is greater than 0 if rules.IsEIP4762 && fee.Sign() != 0 { - st.evm.AccessEvents.BalanceGas(st.evm.Context.Coinbase, true) + st.evm.AccessEvents.AddAccount(st.evm.Context.Coinbase, true) } } diff --git a/core/vm/operations_verkle.go b/core/vm/operations_verkle.go index 73eb05974dc0..722d5ed2ce09 100644 --- a/core/vm/operations_verkle.go +++ b/core/vm/operations_verkle.go @@ -40,7 +40,7 @@ func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { address := stack.peek().Bytes20() - gas := evm.AccessEvents.BalanceGas(address, false) + gas := evm.AccessEvents.BasicDataGas(address, false) if gas == 0 { gas = params.WarmStorageReadCostEIP2929 } @@ -52,8 +52,7 @@ func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, if _, isPrecompile := evm.precompile(address); isPrecompile { return 0, nil } - gas := evm.AccessEvents.VersionGas(address, false) - gas += evm.AccessEvents.CodeSizeGas(address, false) + gas := evm.AccessEvents.BasicDataGas(address, false) if gas == 0 { gas = params.WarmStorageReadCostEIP2929 } @@ -102,17 +101,15 @@ func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Mem return 0, nil } contractAddr := contract.Address() - statelessGas := evm.AccessEvents.VersionGas(contractAddr, false) - statelessGas += evm.AccessEvents.CodeSizeGas(contractAddr, false) - statelessGas += evm.AccessEvents.BalanceGas(contractAddr, false) + statelessGas := evm.AccessEvents.BasicDataGas(contractAddr, false) if contractAddr != beneficiaryAddr { - statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr, false) + statelessGas += evm.AccessEvents.BasicDataGas(beneficiaryAddr, false) } // Charge write costs if it transfers value if evm.StateDB.GetBalance(contractAddr).Sign() != 0 { - statelessGas += evm.AccessEvents.BalanceGas(contractAddr, true) + statelessGas += evm.AccessEvents.BasicDataGas(contractAddr, true) if contractAddr != beneficiaryAddr { - statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr, true) + statelessGas += evm.AccessEvents.BasicDataGas(beneficiaryAddr, true) } } return statelessGas, nil @@ -145,8 +142,7 @@ func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memo return 0, err } addr := common.Address(stack.peek().Bytes20()) - wgas := evm.AccessEvents.VersionGas(addr, false) - wgas += evm.AccessEvents.CodeSizeGas(addr, false) + wgas := evm.AccessEvents.BasicDataGas(addr, false) if wgas == 0 { wgas = params.WarmStorageReadCostEIP2929 } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 9d19ee58a4f8..91fd38269f0f 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -182,7 +182,7 @@ func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error { } // UpdateAccount will abstract the write of an account to the secure trie. -func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error { +func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount, _ int) error { hk := t.hashKey(address.Bytes()) data, err := rlp.EncodeToBytes(acc) if err != nil { diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index 2a4a632d4926..12e02de9a46f 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -28,13 +28,13 @@ import ( ) const ( - // The spec of verkle key encoding can be found here. - // https://notes.ethereum.org/@vbuterin/verkle_tree_eip#Tree-embedding - VersionLeafKey = 0 - BalanceLeafKey = 1 - NonceLeafKey = 2 - CodeKeccakLeafKey = 3 - CodeSizeLeafKey = 4 + BasicDataLeafKey = 0 + CodeHashLeafKey = 1 + + BasicDataVersionOffset = 0 + BasicDataCodeSizeOffset = 5 + BasicDataNonceOffset = 8 + BasicDataBalanceOffset = 16 ) var ( @@ -177,31 +177,16 @@ func GetTreeKeyWithEvaluatedAddress(evaluated *verkle.Point, treeIndex *uint256. return pointToHash(ret, subIndex) } -// VersionKey returns the verkle tree key of the version field for the specified account. -func VersionKey(address []byte) []byte { - return GetTreeKey(address, zero, VersionLeafKey) -} - -// BalanceKey returns the verkle tree key of the balance field for the specified account. -func BalanceKey(address []byte) []byte { - return GetTreeKey(address, zero, BalanceLeafKey) -} - -// NonceKey returns the verkle tree key of the nonce field for the specified account. -func NonceKey(address []byte) []byte { - return GetTreeKey(address, zero, NonceLeafKey) -} - -// CodeKeccakKey returns the verkle tree key of the code keccak field for +// BasicDataKey returns the verkle tree key of the basic data field for // the specified account. -func CodeKeccakKey(address []byte) []byte { - return GetTreeKey(address, zero, CodeKeccakLeafKey) +func BasicDataKey(address []byte) []byte { + return GetTreeKey(address, zero, BasicDataLeafKey) } -// CodeSizeKey returns the verkle tree key of the code size field for the -// specified account. -func CodeSizeKey(address []byte) []byte { - return GetTreeKey(address, zero, CodeSizeLeafKey) +// CodeHashKey returns the verkle tree key of the code hash field for +// the specified account. +func CodeHashKey(address []byte) []byte { + return GetTreeKey(address, zero, CodeHashLeafKey) } func codeChunkIndex(chunk *uint256.Int) (*uint256.Int, byte) { @@ -249,39 +234,18 @@ func StorageSlotKey(address []byte, storageKey []byte) []byte { return GetTreeKey(address, treeIndex, subIndex) } -// VersionKeyWithEvaluatedAddress returns the verkle tree key of the version -// field for the specified account. The difference between VersionKey is the -// address evaluation is already computed to minimize the computational overhead. -func VersionKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { - return GetTreeKeyWithEvaluatedAddress(evaluated, zero, VersionLeafKey) -} - -// BalanceKeyWithEvaluatedAddress returns the verkle tree key of the balance -// field for the specified account. The difference between BalanceKey is the -// address evaluation is already computed to minimize the computational overhead. -func BalanceKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { - return GetTreeKeyWithEvaluatedAddress(evaluated, zero, BalanceLeafKey) -} - -// NonceKeyWithEvaluatedAddress returns the verkle tree key of the nonce -// field for the specified account. The difference between NonceKey is the -// address evaluation is already computed to minimize the computational overhead. -func NonceKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { - return GetTreeKeyWithEvaluatedAddress(evaluated, zero, NonceLeafKey) -} - -// CodeKeccakKeyWithEvaluatedAddress returns the verkle tree key of the code -// keccak for the specified account. The difference between CodeKeccakKey is the +// BasicDataKeyWithEvaluatedAddress returns the verkle tree key of the basic data +// field for the specified account. The difference between BasicDataKey is the // address evaluation is already computed to minimize the computational overhead. -func CodeKeccakKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { - return GetTreeKeyWithEvaluatedAddress(evaluated, zero, CodeKeccakLeafKey) +func BasicDataKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { + return GetTreeKeyWithEvaluatedAddress(evaluated, zero, BasicDataLeafKey) } -// CodeSizeKeyWithEvaluatedAddress returns the verkle tree key of the code -// size for the specified account. The difference between CodeSizeKey is the +// CodeHashKeyWithEvaluatedAddress returns the verkle tree key of the code +// hash for the specified account. The difference between CodeHashKey is the // address evaluation is already computed to minimize the computational overhead. -func CodeSizeKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { - return GetTreeKeyWithEvaluatedAddress(evaluated, zero, CodeSizeLeafKey) +func CodeHashKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { + return GetTreeKeyWithEvaluatedAddress(evaluated, zero, CodeHashLeafKey) } // CodeChunkKeyWithEvaluatedAddress returns the verkle tree key of the code diff --git a/trie/utils/verkle_test.go b/trie/utils/verkle_test.go index c29504a6d0cb..dbec29685bc4 100644 --- a/trie/utils/verkle_test.go +++ b/trie/utils/verkle_test.go @@ -33,20 +33,11 @@ func TestTreeKey(t *testing.T) { smallStorage = []byte{0x1} largeStorage = bytes.Repeat([]byte{0xff}, 16) ) - if !bytes.Equal(VersionKey(address), VersionKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched version key") + if !bytes.Equal(BasicDataKey(address), BasicDataKeyWithEvaluatedAddress(addressEval)) { + t.Fatal("Unmatched basic data key") } - if !bytes.Equal(BalanceKey(address), BalanceKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched balance key") - } - if !bytes.Equal(NonceKey(address), NonceKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched nonce key") - } - if !bytes.Equal(CodeKeccakKey(address), CodeKeccakKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched code keccak key") - } - if !bytes.Equal(CodeSizeKey(address), CodeSizeKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched code size key") + if !bytes.Equal(CodeHashKey(address), CodeHashKeyWithEvaluatedAddress(addressEval)) { + t.Fatal("Unmatched code hash key") } if !bytes.Equal(CodeChunkKey(address, smallIndex), CodeChunkKeyWithEvaluatedAddress(addressEval, smallIndex)) { t.Fatal("Unmatched code chunk key") @@ -76,7 +67,7 @@ func BenchmarkTreeKey(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - BalanceKey([]byte{0x01}) + BasicDataKey([]byte{0x01}) } } @@ -96,7 +87,7 @@ func BenchmarkTreeKeyWithEvaluation(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - BalanceKeyWithEvaluatedAddress(eval) + BasicDataKeyWithEvaluatedAddress(eval) } } diff --git a/trie/verkle.go b/trie/verkle.go index 60293e899894..6bd9d3d1af5a 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -100,20 +100,10 @@ func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error if values == nil { return nil, nil } - // Decode nonce in little-endian - if len(values[utils.NonceLeafKey]) > 0 { - acc.Nonce = binary.LittleEndian.Uint64(values[utils.NonceLeafKey]) - } - // Decode balance in little-endian - var balance [32]byte - copy(balance[:], values[utils.BalanceLeafKey]) - for i := 0; i < len(balance)/2; i++ { - balance[len(balance)-i-1], balance[i] = balance[i], balance[len(balance)-i-1] - } - acc.Balance = new(uint256.Int).SetBytes32(balance[:]) - - // Decode codehash - acc.CodeHash = values[utils.CodeKeccakLeafKey] + basicData := values[utils.BasicDataLeafKey] + acc.Nonce = binary.BigEndian.Uint64(basicData[utils.BasicDataNonceOffset:]) + acc.Balance = new(uint256.Int).SetBytes(basicData[utils.BasicDataBalanceOffset : utils.BasicDataBalanceOffset+16]) + acc.CodeHash = values[utils.CodeHashLeafKey] // TODO account.Root is leave as empty. How should we handle the legacy account? return acc, nil @@ -133,36 +123,36 @@ func (t *VerkleTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) // UpdateAccount implements state.Trie, writing the provided account into the tree. // If the tree is corrupted, an error will be returned. -func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount) error { +func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount, codeLen int) error { var ( - err error - nonce, balance [32]byte - values = make([][]byte, verkle.NodeWidth) + err error + basicData [32]byte + values = make([][]byte, verkle.NodeWidth) + stem = t.cache.GetStem(addr[:]) ) - values[utils.VersionLeafKey] = zero[:] - values[utils.CodeKeccakLeafKey] = acc.CodeHash[:] - // Encode nonce in little-endian - binary.LittleEndian.PutUint64(nonce[:], acc.Nonce) - values[utils.NonceLeafKey] = nonce[:] - - // Encode balance in little-endian - bytes := acc.Balance.Bytes() - for i, b := range bytes { - balance[len(bytes)-i-1] = b + // Code size is encoded in BasicData as a 3-byte big-endian integer. Spare bytes are present + // before the code size to support bigger integers in the future. PutUint32(...) requires + // 4 bytes, so we need to shift the offset 1 byte to the left. + binary.BigEndian.PutUint32(basicData[utils.BasicDataCodeSizeOffset-1:], uint32(codeLen)) + binary.BigEndian.PutUint64(basicData[utils.BasicDataNonceOffset:], acc.Nonce) + if acc.Balance.ByteLen() > 16 { + panic("balance too large") } - values[utils.BalanceLeafKey] = balance[:] + acc.Balance.WriteToSlice(basicData[utils.BasicDataBalanceOffset : utils.BasicDataBalanceOffset+16]) + values[utils.BasicDataLeafKey] = basicData[:] + values[utils.CodeHashLeafKey] = acc.CodeHash[:] - switch n := t.root.(type) { + switch root := t.root.(type) { case *verkle.InternalNode: - err = n.InsertValuesAtStem(t.cache.GetStem(addr[:]), values, t.nodeResolver) - if err != nil { - return fmt.Errorf("UpdateAccount (%x) error: %v", addr, err) - } + err = root.InsertValuesAtStem(stem, values, t.nodeResolver) default: return errInvalidRootType } - // TODO figure out if the code size needs to be updated, too + if err != nil { + return fmt.Errorf("UpdateAccount (%x) error: %v", addr, err) + } + return nil } @@ -208,31 +198,33 @@ func (t *VerkleTrie) DeleteAccount(addr common.Address) error { func (t *VerkleTrie) RollBackAccount(addr common.Address) error { var ( evaluatedAddr = t.cache.Get(addr.Bytes()) - codeSizeKey = utils.CodeSizeKeyWithEvaluatedAddress(evaluatedAddr) + basicDataKey = utils.BasicDataKeyWithEvaluatedAddress(evaluatedAddr) ) - codeSizeBytes, err := t.root.Get(codeSizeKey, t.nodeResolver) + basicDataBytes, err := t.root.Get(basicDataKey, t.nodeResolver) if err != nil { return fmt.Errorf("rollback: error finding code size: %w", err) } - if len(codeSizeBytes) == 0 { - return errors.New("rollback: code size is not existent") + if len(basicDataBytes) == 0 { + return errors.New("rollback: basic data is not existent") } - codeSize := binary.LittleEndian.Uint64(codeSizeBytes) + // The code size is encoded in BasicData as a 3-byte big-endian integer. Spare bytes are present + // before the code size to support bigger integers in the future. + // LittleEndian.Uint32(...) expects 4-bytes, so we need to shift the offset 1-byte to the left. + codeSize := binary.BigEndian.Uint32(basicDataBytes[utils.BasicDataCodeSizeOffset-1:]) // Delete the account header + first 64 slots + first 128 code chunks - _, err = t.root.(*verkle.InternalNode).DeleteAtStem(codeSizeKey[:31], t.nodeResolver) + _, err = t.root.(*verkle.InternalNode).DeleteAtStem(basicDataKey[:31], t.nodeResolver) if err != nil { return fmt.Errorf("error rolling back account header: %w", err) } // Delete all further code - for i, chunknr := uint64(31*128), uint64(128); i < codeSize; i, chunknr = i+31*256, chunknr+256 { + for i, chunknr := uint64(31*128), uint64(128); i < uint64(codeSize); i, chunknr = i+31*256, chunknr+256 { // evaluate group key at the start of a new group offset := uint256.NewInt(chunknr) key := utils.CodeChunkKeyWithEvaluatedAddress(evaluatedAddr, offset) - _, err = t.root.(*verkle.InternalNode).DeleteAtStem(key[:], t.nodeResolver) - if err != nil { + if _, err = t.root.(*verkle.InternalNode).DeleteAtStem(key[:], t.nodeResolver); err != nil { return fmt.Errorf("error deleting code chunk stem (addr=%x, offset=%d) error: %w", addr[:], offset, err) } } @@ -385,6 +377,7 @@ func ChunkifyCode(code []byte) ChunkedCode { // UpdateContractCode implements state.Trie, writing the provided contract code // into the trie. +// Note that the code-size *must* be already saved by a previous UpdateAccount call. func (t *VerkleTrie) UpdateContractCode(addr common.Address, codeHash common.Hash, code []byte) error { var ( chunks = ChunkifyCode(code) @@ -400,12 +393,6 @@ func (t *VerkleTrie) UpdateContractCode(addr common.Address, codeHash common.Has } values[groupOffset] = chunks[i : i+32] - // Reuse the calculated key to also update the code size. - if i == 0 { - cs := make([]byte, 32) - binary.LittleEndian.PutUint64(cs, uint64(len(code))) - values[utils.CodeSizeLeafKey] = cs - } if groupOffset == 255 || len(chunks)-i <= 32 { switch root := t.root.(type) { case *verkle.InternalNode: diff --git a/trie/verkle_test.go b/trie/verkle_test.go index 55438d45e12c..4cd1717c0e7b 100644 --- a/trie/verkle_test.go +++ b/trie/verkle_test.go @@ -61,7 +61,7 @@ func TestVerkleTreeReadWrite(t *testing.T) { tr, _ := NewVerkleTrie(types.EmptyVerkleHash, db, utils.NewPointCache(100)) for addr, acct := range accounts { - if err := tr.UpdateAccount(addr, acct); err != nil { + if err := tr.UpdateAccount(addr, acct, 0); err != nil { t.Fatalf("Failed to update account, %v", err) } for key, val := range storages[addr] { @@ -96,7 +96,13 @@ func TestVerkleRollBack(t *testing.T) { tr, _ := NewVerkleTrie(types.EmptyVerkleHash, db, utils.NewPointCache(100)) for addr, acct := range accounts { - if err := tr.UpdateAccount(addr, acct); err != nil { + // create more than 128 chunks of code + code := make([]byte, 129*32) + for i := 0; i < len(code); i += 2 { + code[i] = 0x60 + code[i+1] = byte(i % 256) + } + if err := tr.UpdateAccount(addr, acct, len(code)); err != nil { t.Fatalf("Failed to update account, %v", err) } for key, val := range storages[addr] { @@ -104,12 +110,6 @@ func TestVerkleRollBack(t *testing.T) { t.Fatalf("Failed to update account, %v", err) } } - // create more than 128 chunks of code - code := make([]byte, 129*32) - for i := 0; i < len(code); i += 2 { - code[i] = 0x60 - code[i+1] = byte(i % 256) - } hash := crypto.Keccak256Hash(code) if err := tr.UpdateContractCode(addr, hash, code); err != nil { t.Fatalf("Failed to update contract, %v", err) From 36a7134367391e315eab70e00a26befc8e7251a1 Mon Sep 17 00:00:00 2001 From: Karl Bartel Date: Mon, 2 Sep 2024 10:30:33 +0200 Subject: [PATCH 508/571] Include tracerConfig in created tracing test (#30364) Fixes the tracer test filler for when there is tracerConfig. --- eth/tracers/internal/tracetest/makeTest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/eth/tracers/internal/tracetest/makeTest.js b/eth/tracers/internal/tracetest/makeTest.js index 3ad7a5df736c..7a5074893013 100644 --- a/eth/tracers/internal/tracetest/makeTest.js +++ b/eth/tracers/internal/tracetest/makeTest.js @@ -49,5 +49,6 @@ var makeTest = function(tx, traceConfig) { context: context, input: eth.getRawTransaction(tx), result: result, + tracerConfig: traceConfig.tracerConfig, }, null, 2)); } From 922eb033d3553d97907506d08fdb1e0ccdc5bead Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 2 Sep 2024 16:41:44 +0800 Subject: [PATCH 509/571] core/state: pull the verkle trie from prefetcher for empty storage root (#30369) This pull request fixes a flaw in prefetcher. In verkle tree world, both accounts and storage slots are committed into a single tree instance for state hashing. If the prefetcher is activated, we will try to pull the trie for the prefetcher for performance speedup. However, we had a special logic to skip pulling storage trie if the storage root is empty. While it's true for merkle as we have nothing to do with an empty storage trie, it's totally wrong for verkle. The consequences for skipping pulling is the storage changes are committed into trie A, while the account changes are committed into trie B (pulled from the prefetcher), boom. --- core/state/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 5946683bc051..e90d3a5d0562 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -143,7 +143,7 @@ func (s *stateObject) getTrie() (Trie, error) { func (s *stateObject) getPrefetchedTrie() Trie { // If there's nothing to meaningfully return, let the user figure it out by // pulling the trie from disk. - if s.data.Root == types.EmptyRootHash || s.db.prefetcher == nil { + if (s.data.Root == types.EmptyRootHash && !s.db.db.TrieDB().IsVerkle()) || s.db.prefetcher == nil { return nil } // Attempt to retrieve the trie from the prefetcher From de597af9c58871fd8bb8cb8e5ea609ec92d2d143 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:22:32 +0200 Subject: [PATCH 510/571] funding.json: add funding information file (#30385) Adds a list of funding identifiers. --- funding.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 funding.json diff --git a/funding.json b/funding.json new file mode 100644 index 000000000000..72a29e795fb9 --- /dev/null +++ b/funding.json @@ -0,0 +1,5 @@ +{ + "opRetro": { + "projectId": "0x79c2ae8858a5a3bd7f2e0da9509d727833ffa01f358b5969355f38ff32b20122" + } +} From dfd33c77923986dc9c20f99c5b0db6ddc87751e8 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:33:51 +0200 Subject: [PATCH 511/571] all: implement EIP-6110, execution layer triggered deposits (#29431) This PR implements EIP-6110: Supply validator deposits on chain. It also sketches out the base for Prague in the engine API types. --- beacon/engine/gen_ed.go | 6 + beacon/engine/types.go | 39 ++++- cmd/evm/internal/t8ntool/execution.go | 24 +++ core/block_validator.go | 20 ++- core/blockchain.go | 22 +-- core/blockchain_test.go | 96 +++++++++++- core/chain_makers.go | 13 +- core/genesis.go | 11 +- core/state_processor.go | 39 ++++- core/stateless.go | 6 +- core/types.go | 15 +- core/types/block.go | 39 ++++- core/types/deposit.go | 103 ++++++++++++ core/types/deposit_test.go | 93 +++++++++++ core/types/gen_deposit_json.go | 70 +++++++++ core/types/gen_header_json.go | 6 + core/types/gen_header_rlp.go | 18 ++- core/types/hashes.go | 3 + core/types/request.go | 157 +++++++++++++++++++ eth/catalyst/api.go | 112 +++++++++++-- eth/catalyst/api_test.go | 108 +++++++++---- eth/catalyst/simulated_beacon.go | 4 +- eth/downloader/downloader_test.go | 3 +- eth/downloader/fetchers_concurrent_bodies.go | 6 +- eth/downloader/queue.go | 16 +- eth/downloader/queue_test.go | 2 +- eth/protocols/eth/handlers.go | 6 +- eth/protocols/eth/protocol.go | 9 +- eth/state_accessor.go | 2 +- eth/tracers/logger/logger.go | 2 +- ethclient/ethclient.go | 2 + internal/ethapi/api.go | 6 + miner/worker.go | 13 ++ params/config.go | 3 + tests/init.go | 2 + 35 files changed, 974 insertions(+), 102 deletions(-) create mode 100644 core/types/deposit.go create mode 100644 core/types/deposit_test.go create mode 100644 core/types/gen_deposit_json.go create mode 100644 core/types/request.go diff --git a/beacon/engine/gen_ed.go b/beacon/engine/gen_ed.go index 0ae5a3b8f1f1..b2eb1dc9822f 100644 --- a/beacon/engine/gen_ed.go +++ b/beacon/engine/gen_ed.go @@ -34,6 +34,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) { Withdrawals []*types.Withdrawal `json:"withdrawals"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + Deposits types.Deposits `json:"depositRequests"` ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` } var enc ExecutableData @@ -59,6 +60,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) { enc.Withdrawals = e.Withdrawals enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) + enc.Deposits = e.Deposits enc.ExecutionWitness = e.ExecutionWitness return json.Marshal(&enc) } @@ -83,6 +85,7 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error { Withdrawals []*types.Withdrawal `json:"withdrawals"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + Deposits *types.Deposits `json:"depositRequests"` ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` } var dec ExecutableData @@ -157,6 +160,9 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error { if dec.ExcessBlobGas != nil { e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) } + if dec.Deposits != nil { + e.Deposits = *dec.Deposits + } if dec.ExecutionWitness != nil { e.ExecutionWitness = dec.ExecutionWitness } diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 8687a6f5041d..19d2b2823e37 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -36,6 +36,7 @@ var ( PayloadV1 PayloadVersion = 0x1 PayloadV2 PayloadVersion = 0x2 PayloadV3 PayloadVersion = 0x3 + PayloadV4 PayloadVersion = 0x4 ) //go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go @@ -76,6 +77,7 @@ type ExecutableData struct { Withdrawals []*types.Withdrawal `json:"withdrawals"` BlobGasUsed *uint64 `json:"blobGasUsed"` ExcessBlobGas *uint64 `json:"excessBlobGas"` + Deposits types.Deposits `json:"depositRequests"` ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` } @@ -231,6 +233,19 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil)) withdrawalsRoot = &h } + // Compute requestsHash if any requests are non-nil. + var ( + requestsHash *common.Hash + requests types.Requests + ) + if data.Deposits != nil { + requests = make(types.Requests, 0) + for _, d := range data.Deposits { + requests = append(requests, types.NewRequest(d)) + } + h := types.DeriveSha(requests, trie.NewStackTrie(nil)) + requestsHash = &h + } header := &types.Header{ ParentHash: data.ParentHash, UncleHash: types.EmptyUncleHash, @@ -251,9 +266,10 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b ExcessBlobGas: data.ExcessBlobGas, BlobGasUsed: data.BlobGasUsed, ParentBeaconRoot: beaconRoot, + RequestsHash: requestsHash, } block := types.NewBlockWithHeader(header) - block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}) + block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests}) block = block.WithWitness(data.ExecutionWitness) if block.Hash() != data.BlockHash { return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash()) @@ -296,13 +312,30 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types. bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:])) } } + setRequests(block.Requests(), data) return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false} } -// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1 -type ExecutionPayloadBodyV1 struct { +// setRequests differentiates the different request types and +// assigns them to the associated fields in ExecutableData. +func setRequests(requests types.Requests, data *ExecutableData) { + if requests != nil { + // If requests is non-nil, it means deposits are available in block and we + // should return an empty slice instead of nil if there are no deposits. + data.Deposits = make(types.Deposits, 0) + } + for _, r := range requests { + if d, ok := r.Inner().(*types.Deposit); ok { + data.Deposits = append(data.Deposits, d) + } + } +} + +// ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange +type ExecutionPayloadBody struct { TransactionData []hexutil.Bytes `json:"transactions"` Withdrawals []*types.Withdrawal `json:"withdrawals"` + Deposits types.Deposits `json:"depositRequests"` } // Client identifiers to support ClientVersionV1. diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index d240d161a980..a0805722d669 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -66,6 +66,8 @@ type ExecutionResult struct { WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"` + RequestsHash *common.Hash `json:"requestsRoot,omitempty"` + DepositRequests *types.Deposits `json:"depositRequests,omitempty"` } type ommer struct { @@ -377,6 +379,28 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas) execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed) } + if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) { + // Parse the requests from the logs + var allLogs []*types.Log + for _, receipt := range receipts { + allLogs = append(allLogs, receipt.Logs...) + } + requests, err := core.ParseDepositLogs(allLogs, chainConfig) + if err != nil { + return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err)) + } + // Calculate the requests root + h := types.DeriveSha(requests, trie.NewStackTrie(nil)) + execRs.RequestsHash = &h + // Get the deposits from the requests + deposits := make(types.Deposits, 0) + for _, req := range requests { + if dep, ok := req.Inner().(*types.Deposit); ok { + deposits = append(deposits, dep) + } + } + execRs.DepositRequests = &deposits + } // Re-create statedb instance with new root upon the updated database // for accessing latest states. statedb, err = state.New(root, statedb.Database(), nil) diff --git a/core/block_validator.go b/core/block_validator.go index 75f7f8a94b68..a944db0bf896 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -121,14 +121,17 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // ValidateState validates the various changes that happen after a state transition, // such as amount of used gas, the receipt roots and the state root itself. -func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error { +func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error { + if res == nil { + return fmt.Errorf("nil ProcessResult value") + } header := block.Header() - if block.GasUsed() != usedGas { - return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) + if block.GasUsed() != res.GasUsed { + return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), res.GasUsed) } // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. - rbloom := types.CreateBloom(receipts) + rbloom := types.CreateBloom(res.Receipts) if rbloom != header.Bloom { return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) } @@ -138,10 +141,17 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD return nil } // The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) - receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) + receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil)) if receiptSha != header.ReceiptHash { return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) } + // Validate the parsed requests match the expected header value. + if header.RequestsHash != nil { + depositSha := types.DeriveSha(res.Requests, trie.NewStackTrie(nil)) + if depositSha != *header.RequestsHash { + return fmt.Errorf("invalid deposit root hash (remote: %x local: %x)", *header.RequestsHash, depositSha) + } + } // Validate the state root against the received state root and throw // an error if they don't match. if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { diff --git a/core/blockchain.go b/core/blockchain.go index 733525bc706f..397d917d73a5 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1927,23 +1927,23 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s // Process block using the parent state as reference point pstart := time.Now() - receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) + res, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { - bc.reportBlock(block, receipts, err) + bc.reportBlock(block, res, err) return nil, err } ptime := time.Since(pstart) vstart := time.Now() - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { - bc.reportBlock(block, receipts, err) + if err := bc.validator.ValidateState(block, statedb, res, false); err != nil { + bc.reportBlock(block, res, err) return nil, err } vtime := time.Since(vstart) if witness := statedb.Witness(); witness != nil { if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil { - bc.reportBlock(block, receipts, err) + bc.reportBlock(block, res, err) return nil, fmt.Errorf("cross verification failed: %v", err) } } @@ -1978,9 +1978,9 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s ) if !setHead { // Don't set the head, only insert the block - err = bc.writeBlockWithState(block, receipts, statedb) + err = bc.writeBlockWithState(block, res.Receipts, statedb) } else { - status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) + status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false) } if err != nil { return nil, err @@ -1994,7 +1994,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits) blockInsertTimer.UpdateSince(start) - return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil + return &blockProcessingResult{usedGas: res.GasUsed, procTime: proctime, status: status}, nil } // insertSideChain is called when an import batch hits upon a pruned ancestor @@ -2491,7 +2491,11 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool { } // reportBlock logs a bad block error. -func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) { +func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err error) { + var receipts types.Receipts + if res != nil { + receipts = res.Receipts + } rawdb.WriteBadBlock(bc.db, block) log.Error(summarizeBadBlock(block, receipts, bc.Config(), err)) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 4f28c6f5e681..9148dd6f08d2 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -163,13 +163,14 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { if err != nil { return err } - receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{}) + res, err := blockchain.processor.Process(block, statedb, vm.Config{}) if err != nil { - blockchain.reportBlock(block, receipts, err) + blockchain.reportBlock(block, res, err) return err } - if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { - blockchain.reportBlock(block, receipts, err) + err = blockchain.validator.ValidateState(block, statedb, res, false) + if err != nil { + blockchain.reportBlock(block, res, err) return err } @@ -4220,3 +4221,90 @@ func TestEIP3651(t *testing.T) { t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) } } + +func TestEIP6110(t *testing.T) { + var ( + engine = beacon.NewFaker() + + // A sender who makes transactions, has some funds + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr = crypto.PubkeyToAddress(key.PublicKey) + funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + config = *params.AllEthashProtocolChanges + gspec = &Genesis{ + Config: &config, + Alloc: types.GenesisAlloc{ + addr: {Balance: funds}, + config.DepositContractAddress: { + // Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7 + Code: common.Hex2Bytes("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033"), + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + } + ) + + gspec.Config.BerlinBlock = common.Big0 + gspec.Config.LondonBlock = common.Big0 + gspec.Config.TerminalTotalDifficulty = common.Big0 + gspec.Config.TerminalTotalDifficultyPassed = true + gspec.Config.ShanghaiTime = u64(0) + gspec.Config.CancunTime = u64(0) + gspec.Config.PragueTime = u64(0) + signer := types.LatestSigner(gspec.Config) + + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { + for i := 0; i < 5; i++ { + txdata := &types.DynamicFeeTx{ + ChainID: gspec.Config.ChainID, + Nonce: uint64(i), + To: &config.DepositContractAddress, + Gas: 500000, + GasFeeCap: newGwei(5), + GasTipCap: big.NewInt(2), + AccessList: nil, + Data: []byte{}, + } + tx := types.NewTx(txdata) + tx, _ = types.SignTx(tx, signer, key) + b.AddTx(tx) + } + }) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{DisableStack: true}, os.Stderr).Hooks()}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + defer chain.Stop() + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + + block := chain.GetBlockByNumber(1) + if len(block.Requests()) != 5 { + t.Fatalf("failed to retrieve deposits: have %d, want %d", len(block.Requests()), 5) + } + + // Verify each index is correct. + for want, req := range block.Requests() { + d, ok := req.Inner().(*types.Deposit) + if !ok { + t.Fatalf("expected deposit object") + } + if got := int(d.PublicKey[0]); got != want { + t.Fatalf("invalid pubkey: have %d, want %d", got, want) + } + if got := int(d.WithdrawalCredentials[0]); got != want { + t.Fatalf("invalid withdrawal credentials: have %d, want %d", got, want) + } + if d.Amount != uint64(want) { + t.Fatalf("invalid amounbt: have %d, want %d", d.Amount, want) + } + if got := int(d.Signature[0]); got != want { + t.Fatalf("invalid signature: have %d, want %d", got, want) + } + if d.Index != uint64(want) { + t.Fatalf("invalid index: have %d, want %d", d.Index, want) + } + } +} diff --git a/core/chain_makers.go b/core/chain_makers.go index 6cee6fdc8a11..dcaa36e08ccc 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -346,7 +346,18 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse gen(i, b) } - body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals} + var requests types.Requests + if config.IsPrague(b.header.Number, b.header.Time) { + for _, r := range b.receipts { + d, err := ParseDepositLogs(r.Logs, config) + if err != nil { + panic(fmt.Sprintf("failed to parse deposit log: %v", err)) + } + requests = append(requests, d...) + } + } + + body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: requests} block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts) if err != nil { panic(err) diff --git a/core/genesis.go b/core/genesis.go index d83aab0baf89..67f5d56cfe80 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -447,7 +447,10 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block { head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) } } - var withdrawals []*types.Withdrawal + var ( + withdrawals []*types.Withdrawal + requests types.Requests + ) if conf := g.Config; conf != nil { num := big.NewInt(int64(g.Number)) if conf.IsShanghai(num, g.Timestamp) { @@ -469,8 +472,12 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block { head.BlobGasUsed = new(uint64) } } + if conf.IsPrague(num, g.Timestamp) { + head.RequestsHash = &types.EmptyRequestsHash + requests = make(types.Requests, 0) + } } - return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil)) + return types.NewBlock(head, &types.Body{Withdrawals: withdrawals, Requests: requests}, nil, trie.NewStackTrie(nil)) } // Commit writes the block and state of a genesis specification to the database. diff --git a/core/state_processor.go b/core/state_processor.go index c13b69602244..2844693a9e5c 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -53,7 +53,7 @@ func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StatePro // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) { var ( receipts types.Receipts usedGas = new(uint64) @@ -71,6 +71,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg var ( context vm.BlockContext signer = types.MakeSigner(p.config, header.Number, header.Time) + err error ) context = NewEVMBlockContext(header, p.chain, nil) vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) @@ -84,21 +85,35 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg for i, tx := range block.Transactions() { msg, err := TransactionToMessage(tx, signer, header.BaseFee) if err != nil { - return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.SetTxContext(tx.Hash(), i) receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if err != nil { - return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } + // Read requests if Prague is enabled. + var requests types.Requests + if p.config.IsPrague(block.Number(), block.Time()) { + requests, err = ParseDepositLogs(allLogs, p.config) + if err != nil { + return nil, err + } + } + // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.chain.engine.Finalize(p.chain, header, statedb, block.Body()) - return receipts, allLogs, *usedGas, nil + return &ProcessResult{ + Receipts: receipts, + Requests: requests, + Logs: allLogs, + GasUsed: *usedGas, + }, nil } // ApplyTransactionWithEVM attempts to apply a transaction to the given state database @@ -239,3 +254,19 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state. _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) statedb.Finalise(true) } + +// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by +// BeaconDepositContract. +func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) (types.Requests, error) { + deposits := make(types.Requests, 0) + for _, log := range logs { + if log.Address == config.DepositContractAddress { + d, err := types.UnpackIntoDeposit(log.Data) + if err != nil { + return nil, fmt.Errorf("unable to parse deposit data: %v", err) + } + deposits = append(deposits, types.NewRequest(d)) + } + } + return deposits, nil +} diff --git a/core/stateless.go b/core/stateless.go index 4c7e6f31027f..e3168747cf27 100644 --- a/core/stateless.go +++ b/core/stateless.go @@ -58,15 +58,15 @@ func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (c validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block // Run the stateless blocks processing and self-validate certain fields - receipts, _, usedGas, err := processor.Process(witness.Block, db, vm.Config{}) + res, err := processor.Process(witness.Block, db, vm.Config{}) if err != nil { return common.Hash{}, common.Hash{}, err } - if err = validator.ValidateState(witness.Block, db, receipts, usedGas, true); err != nil { + if err = validator.ValidateState(witness.Block, db, res, true); err != nil { return common.Hash{}, common.Hash{}, err } // Almost everything validated, but receipt and state root needs to be returned - receiptRoot := types.DeriveSha(receipts, trie.NewStackTrie(nil)) + receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil)) stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number())) return receiptRoot, stateRoot, nil diff --git a/core/types.go b/core/types.go index dc13de52ce2b..b1808c9ffbfc 100644 --- a/core/types.go +++ b/core/types.go @@ -33,9 +33,8 @@ type Validator interface { // ValidateBody validates the given block's content. ValidateBody(block *types.Block) error - // ValidateState validates the given statedb and optionally the receipts and - // gas used. - ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error + // ValidateState validates the given statedb and optionally the process result. + ValidateState(block *types.Block, state *state.StateDB, res *ProcessResult, stateless bool) error // ValidateWitness cross validates a block execution with stateless remote clients. ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error @@ -54,5 +53,13 @@ type Processor interface { // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. - Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) + Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) +} + +// ProcessResult contains the values computed by Process. +type ProcessResult struct { + Receipts types.Receipts + Requests types.Requests + Logs []*types.Log + GasUsed uint64 } diff --git a/core/types/block.go b/core/types/block.go index e6ddf2012f61..1c00658d5b38 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -102,6 +102,9 @@ type Header struct { // ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers. ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` + + // RequestsHash was added by EIP-7685 and is ignored in legacy headers. + RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"` } // field type overrides for gencodec @@ -163,10 +166,11 @@ func (h *Header) SanityCheck() error { // EmptyBody returns true if there is no additional 'body' to complete the header // that is: no transactions, no uncles and no withdrawals. func (h *Header) EmptyBody() bool { - if h.WithdrawalsHash != nil { - return h.TxHash == EmptyTxsHash && *h.WithdrawalsHash == EmptyWithdrawalsHash - } - return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash + var ( + emptyWithdrawals = h.WithdrawalsHash == nil || *h.WithdrawalsHash == EmptyWithdrawalsHash + emptyRequests = h.RequestsHash == nil || *h.RequestsHash == EmptyReceiptsHash + ) + return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash && emptyWithdrawals && emptyRequests } // EmptyReceipts returns true if there are no receipts for this header/block. @@ -180,6 +184,7 @@ type Body struct { Transactions []*Transaction Uncles []*Header Withdrawals []*Withdrawal `rlp:"optional"` + Requests []*Request `rlp:"optional"` } // Block represents an Ethereum block. @@ -204,6 +209,7 @@ type Block struct { uncles []*Header transactions Transactions withdrawals Withdrawals + requests Requests // witness is not an encoded part of the block body. // It is held in Block in order for easy relaying to the places @@ -226,6 +232,7 @@ type extblock struct { Txs []*Transaction Uncles []*Header Withdrawals []*Withdrawal `rlp:"optional"` + Requests []*Request `rlp:"optional"` } // NewBlock creates a new block. The input data is copied, changes to header and to the @@ -242,6 +249,7 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher txs = body.Transactions uncles = body.Uncles withdrawals = body.Withdrawals + requests = body.Requests ) if len(txs) == 0 { @@ -280,6 +288,17 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher b.withdrawals = slices.Clone(withdrawals) } + if requests == nil { + b.header.RequestsHash = nil + } else if len(requests) == 0 { + b.header.RequestsHash = &EmptyRequestsHash + b.requests = Requests{} + } else { + h := DeriveSha(Requests(requests), hasher) + b.header.RequestsHash = &h + b.requests = slices.Clone(requests) + } + return b } @@ -315,6 +334,10 @@ func CopyHeader(h *Header) *Header { cpy.ParentBeaconRoot = new(common.Hash) *cpy.ParentBeaconRoot = *h.ParentBeaconRoot } + if h.RequestsHash != nil { + cpy.RequestsHash = new(common.Hash) + *cpy.RequestsHash = *h.RequestsHash + } return &cpy } @@ -325,7 +348,7 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error { if err := s.Decode(&eb); err != nil { return err } - b.header, b.uncles, b.transactions, b.withdrawals = eb.Header, eb.Uncles, eb.Txs, eb.Withdrawals + b.header, b.uncles, b.transactions, b.withdrawals, b.requests = eb.Header, eb.Uncles, eb.Txs, eb.Withdrawals, eb.Requests b.size.Store(rlp.ListSize(size)) return nil } @@ -337,13 +360,14 @@ func (b *Block) EncodeRLP(w io.Writer) error { Txs: b.transactions, Uncles: b.uncles, Withdrawals: b.withdrawals, + Requests: b.requests, }) } // Body returns the non-header content of the block. // Note the returned data is not an independent copy. func (b *Block) Body() *Body { - return &Body{b.transactions, b.uncles, b.withdrawals} + return &Body{b.transactions, b.uncles, b.withdrawals, b.requests} } // Accessors for body data. These do not return a copy because the content @@ -352,6 +376,7 @@ func (b *Block) Body() *Body { func (b *Block) Uncles() []*Header { return b.uncles } func (b *Block) Transactions() Transactions { return b.transactions } func (b *Block) Withdrawals() Withdrawals { return b.withdrawals } +func (b *Block) Requests() Requests { return b.requests } func (b *Block) Transaction(hash common.Hash) *Transaction { for _, transaction := range b.transactions { @@ -476,6 +501,7 @@ func (b *Block) WithBody(body Body) *Block { transactions: slices.Clone(body.Transactions), uncles: make([]*Header, len(body.Uncles)), withdrawals: slices.Clone(body.Withdrawals), + requests: slices.Clone(body.Requests), witness: b.witness, } for i := range body.Uncles { @@ -490,6 +516,7 @@ func (b *Block) WithWitness(witness *ExecutionWitness) *Block { transactions: b.transactions, uncles: b.uncles, withdrawals: b.withdrawals, + requests: b.requests, witness: witness, } } diff --git a/core/types/deposit.go b/core/types/deposit.go new file mode 100644 index 000000000000..172acc36ed3e --- /dev/null +++ b/core/types/deposit.go @@ -0,0 +1,103 @@ +// Copyright 2024 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 types + +import ( + "bytes" + "encoding/binary" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rlp" +) + +//go:generate go run github.com/fjl/gencodec -type Deposit -field-override depositMarshaling -out gen_deposit_json.go + +// Deposit contains EIP-6110 deposit data. +type Deposit struct { + PublicKey [48]byte `json:"pubkey"` // public key of validator + WithdrawalCredentials common.Hash `json:"withdrawalCredentials"` // beneficiary of the validator funds + Amount uint64 `json:"amount"` // deposit size in Gwei + Signature [96]byte `json:"signature"` // signature over deposit msg + Index uint64 `json:"index"` // deposit count value +} + +// field type overrides for gencodec +type depositMarshaling struct { + PublicKey hexutil.Bytes + WithdrawalCredentials hexutil.Bytes + Amount hexutil.Uint64 + Signature hexutil.Bytes + Index hexutil.Uint64 +} + +// Deposits implements DerivableList for requests. +type Deposits []*Deposit + +// Len returns the length of s. +func (s Deposits) Len() int { return len(s) } + +// EncodeIndex encodes the i'th deposit to s. +func (s Deposits) EncodeIndex(i int, w *bytes.Buffer) { + rlp.Encode(w, s[i]) +} + +// UnpackIntoDeposit unpacks a serialized DepositEvent. +func UnpackIntoDeposit(data []byte) (*Deposit, error) { + if len(data) != 576 { + return nil, fmt.Errorf("deposit wrong length: want 576, have %d", len(data)) + } + var d Deposit + // The ABI encodes the position of dynamic elements first. Since there are 5 + // elements, skip over the positional data. The first 32 bytes of dynamic + // elements also encode their actual length. Skip over that value too. + b := 32*5 + 32 + // PublicKey is the first element. ABI encoding pads values to 32 bytes, so + // despite BLS public keys being length 48, the value length here is 64. Then + // skip over the next length value. + copy(d.PublicKey[:], data[b:b+48]) + b += 48 + 16 + 32 + // WithdrawalCredentials is 32 bytes. Read that value then skip over next + // length. + copy(d.WithdrawalCredentials[:], data[b:b+32]) + b += 32 + 32 + // Amount is 8 bytes, but it is padded to 32. Skip over it and the next + // length. + d.Amount = binary.LittleEndian.Uint64(data[b : b+8]) + b += 8 + 24 + 32 + // Signature is 96 bytes. Skip over it and the next length. + copy(d.Signature[:], data[b:b+96]) + b += 96 + 32 + // Amount is 8 bytes. + d.Index = binary.LittleEndian.Uint64(data[b : b+8]) + + return &d, nil +} + +func (d *Deposit) requestType() byte { return DepositRequestType } +func (d *Deposit) encode(b *bytes.Buffer) error { return rlp.Encode(b, d) } +func (d *Deposit) decode(input []byte) error { return rlp.DecodeBytes(input, d) } +func (d *Deposit) copy() RequestData { + return &Deposit{ + PublicKey: d.PublicKey, + WithdrawalCredentials: d.WithdrawalCredentials, + Amount: d.Amount, + Signature: d.Signature, + Index: d.Index, + } +} diff --git a/core/types/deposit_test.go b/core/types/deposit_test.go new file mode 100644 index 000000000000..ed2e18445d3f --- /dev/null +++ b/core/types/deposit_test.go @@ -0,0 +1,93 @@ +// Copyright 2024 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 types + +import ( + "encoding/binary" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +var ( + depositABI = abi.ABI{Methods: map[string]abi.Method{"DepositEvent": depositEvent}} + bytesT, _ = abi.NewType("bytes", "", nil) + depositEvent = abi.NewMethod("DepositEvent", "DepositEvent", abi.Function, "", false, false, []abi.Argument{ + {Name: "pubkey", Type: bytesT, Indexed: false}, + {Name: "withdrawal_credentials", Type: bytesT, Indexed: false}, + {Name: "amount", Type: bytesT, Indexed: false}, + {Name: "signature", Type: bytesT, Indexed: false}, + {Name: "index", Type: bytesT, Indexed: false}}, nil, + ) +) + +// FuzzUnpackIntoDeposit tries roundtrip packing and unpacking of deposit events. +func FuzzUnpackIntoDeposit(f *testing.F) { + for _, tt := range []struct { + pubkey string + wxCred string + amount string + sig string + index string + }{ + { + pubkey: "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + wxCred: "2222222222222222222222222222222222222222222222222222222222222222", + amount: "3333333333333333", + sig: "444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", + index: "5555555555555555", + }, + } { + f.Add(common.FromHex(tt.pubkey), common.FromHex(tt.wxCred), common.FromHex(tt.amount), common.FromHex(tt.sig), common.FromHex(tt.index)) + } + + f.Fuzz(func(t *testing.T, p []byte, w []byte, a []byte, s []byte, i []byte) { + var ( + pubkey [48]byte + wxCred [32]byte + amount [8]byte + sig [96]byte + index [8]byte + ) + copy(pubkey[:], p) + copy(wxCred[:], w) + copy(amount[:], a) + copy(sig[:], s) + copy(index[:], i) + + want := Deposit{ + PublicKey: pubkey, + WithdrawalCredentials: wxCred, + Amount: binary.LittleEndian.Uint64(amount[:]), + Signature: sig, + Index: binary.LittleEndian.Uint64(index[:]), + } + out, err := depositABI.Pack("DepositEvent", want.PublicKey[:], want.WithdrawalCredentials[:], amount[:], want.Signature[:], index[:]) + if err != nil { + t.Fatalf("error packing deposit: %v", err) + } + got, err := UnpackIntoDeposit(out[4:]) + if err != nil { + t.Errorf("error unpacking deposit: %v", err) + } + if !reflect.DeepEqual(want, *got) { + t.Errorf("roundtrip failed: want %v, got %v", want, got) + } + }) +} diff --git a/core/types/gen_deposit_json.go b/core/types/gen_deposit_json.go new file mode 100644 index 000000000000..a65691188f58 --- /dev/null +++ b/core/types/gen_deposit_json.go @@ -0,0 +1,70 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package types + +import ( + "encoding/json" + "errors" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*depositMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (d Deposit) MarshalJSON() ([]byte, error) { + type Deposit struct { + PublicKey hexutil.Bytes `json:"pubkey"` + WithdrawalCredentials hexutil.Bytes `json:"withdrawalCredentials"` + Amount hexutil.Uint64 `json:"amount"` + Signature hexutil.Bytes `json:"signature"` + Index hexutil.Uint64 `json:"index"` + } + var enc Deposit + enc.PublicKey = d.PublicKey[:] + enc.WithdrawalCredentials = d.WithdrawalCredentials[:] + enc.Amount = hexutil.Uint64(d.Amount) + enc.Signature = d.Signature[:] + enc.Index = hexutil.Uint64(d.Index) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (d *Deposit) UnmarshalJSON(input []byte) error { + type Deposit struct { + PublicKey *hexutil.Bytes `json:"pubkey"` + WithdrawalCredentials *hexutil.Bytes `json:"withdrawalCredentials"` + Amount *hexutil.Uint64 `json:"amount"` + Signature *hexutil.Bytes `json:"signature"` + Index *hexutil.Uint64 `json:"index"` + } + var dec Deposit + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.PublicKey != nil { + if len(*dec.PublicKey) != len(d.PublicKey) { + return errors.New("field 'pubkey' has wrong length, need 48 items") + } + copy(d.PublicKey[:], *dec.PublicKey) + } + if dec.WithdrawalCredentials != nil { + if len(*dec.WithdrawalCredentials) != len(d.WithdrawalCredentials) { + return errors.New("field 'withdrawalCredentials' has wrong length, need 32 items") + } + copy(d.WithdrawalCredentials[:], *dec.WithdrawalCredentials) + } + if dec.Amount != nil { + d.Amount = uint64(*dec.Amount) + } + if dec.Signature != nil { + if len(*dec.Signature) != len(d.Signature) { + return errors.New("field 'signature' has wrong length, need 96 items") + } + copy(d.Signature[:], *dec.Signature) + } + if dec.Index != nil { + d.Index = uint64(*dec.Index) + } + return nil +} diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index fb1f915d01d9..322c5d56423d 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -36,6 +36,7 @@ func (h Header) MarshalJSON() ([]byte, error) { BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` + RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"` Hash common.Hash `json:"hash"` } var enc Header @@ -59,6 +60,7 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.BlobGasUsed = (*hexutil.Uint64)(h.BlobGasUsed) enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas) enc.ParentBeaconRoot = h.ParentBeaconRoot + enc.RequestsHash = h.RequestsHash enc.Hash = h.Hash() return json.Marshal(&enc) } @@ -86,6 +88,7 @@ func (h *Header) UnmarshalJSON(input []byte) error { BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` + RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"` } var dec Header if err := json.Unmarshal(input, &dec); err != nil { @@ -163,5 +166,8 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.ParentBeaconRoot != nil { h.ParentBeaconRoot = dec.ParentBeaconRoot } + if dec.RequestsHash != nil { + h.RequestsHash = dec.RequestsHash + } return nil } diff --git a/core/types/gen_header_rlp.go b/core/types/gen_header_rlp.go index ed6a1a002cdb..c79aa8a25023 100644 --- a/core/types/gen_header_rlp.go +++ b/core/types/gen_header_rlp.go @@ -42,7 +42,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { _tmp3 := obj.BlobGasUsed != nil _tmp4 := obj.ExcessBlobGas != nil _tmp5 := obj.ParentBeaconRoot != nil - if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 { + _tmp6 := obj.RequestsHash != nil + if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 { if obj.BaseFee == nil { w.Write(rlp.EmptyString) } else { @@ -52,34 +53,41 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { w.WriteBigInt(obj.BaseFee) } } - if _tmp2 || _tmp3 || _tmp4 || _tmp5 { + if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 { if obj.WithdrawalsHash == nil { w.Write([]byte{0x80}) } else { w.WriteBytes(obj.WithdrawalsHash[:]) } } - if _tmp3 || _tmp4 || _tmp5 { + if _tmp3 || _tmp4 || _tmp5 || _tmp6 { if obj.BlobGasUsed == nil { w.Write([]byte{0x80}) } else { w.WriteUint64((*obj.BlobGasUsed)) } } - if _tmp4 || _tmp5 { + if _tmp4 || _tmp5 || _tmp6 { if obj.ExcessBlobGas == nil { w.Write([]byte{0x80}) } else { w.WriteUint64((*obj.ExcessBlobGas)) } } - if _tmp5 { + if _tmp5 || _tmp6 { if obj.ParentBeaconRoot == nil { w.Write([]byte{0x80}) } else { w.WriteBytes(obj.ParentBeaconRoot[:]) } } + if _tmp6 { + if obj.RequestsHash == nil { + w.Write([]byte{0x80}) + } else { + w.WriteBytes(obj.RequestsHash[:]) + } + } w.ListEnd(_tmp0) return w.Flush() } diff --git a/core/types/hashes.go b/core/types/hashes.go index 43e9130fd170..cbd197072e5e 100644 --- a/core/types/hashes.go +++ b/core/types/hashes.go @@ -41,6 +41,9 @@ var ( // EmptyWithdrawalsHash is the known hash of the empty withdrawal set. EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + // EmptyRequestsHash is the known hash of the empty requests set. + EmptyRequestsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + // EmptyVerkleHash is the known hash of an empty verkle trie. EmptyVerkleHash = common.Hash{} ) diff --git a/core/types/request.go b/core/types/request.go new file mode 100644 index 000000000000..7b1cade26e75 --- /dev/null +++ b/core/types/request.go @@ -0,0 +1,157 @@ +// Copyright 2024 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 types + +import ( + "bytes" + "errors" + "fmt" + "io" + + "github.com/ethereum/go-ethereum/rlp" +) + +var ( + ErrRequestTypeNotSupported = errors.New("request type not supported") + errShortTypedRequest = errors.New("typed request too short") +) + +// Request types. +const ( + DepositRequestType = 0x00 +) + +// Request is an EIP-7685 request object. It represents execution layer +// triggered messages bound for the consensus layer. +type Request struct { + inner RequestData +} + +// Type returns the EIP-7685 type of the request. +func (r *Request) Type() byte { + return r.inner.requestType() +} + +// Inner returns the inner request data. +func (r *Request) Inner() RequestData { + return r.inner +} + +// NewRequest creates a new request. +func NewRequest(inner RequestData) *Request { + req := new(Request) + req.inner = inner.copy() + return req +} + +// Requests implements DerivableList for requests. +type Requests []*Request + +// Len returns the length of s. +func (s Requests) Len() int { return len(s) } + +// EncodeIndex encodes the i'th request to s. +func (s Requests) EncodeIndex(i int, w *bytes.Buffer) { + s[i].encode(w) +} + +// RequestData is the underlying data of a request. +type RequestData interface { + requestType() byte + encode(*bytes.Buffer) error + decode([]byte) error + copy() RequestData // creates a deep copy and initializes all fields +} + +// EncodeRLP implements rlp.Encoder +func (r *Request) EncodeRLP(w io.Writer) error { + buf := encodeBufferPool.Get().(*bytes.Buffer) + defer encodeBufferPool.Put(buf) + buf.Reset() + if err := r.encode(buf); err != nil { + return err + } + return rlp.Encode(w, buf.Bytes()) +} + +// encode writes the canonical encoding of a request to w. +func (r *Request) encode(w *bytes.Buffer) error { + w.WriteByte(r.Type()) + return r.inner.encode(w) +} + +// MarshalBinary returns the canonical encoding of the request. +func (r *Request) MarshalBinary() ([]byte, error) { + var buf bytes.Buffer + err := r.encode(&buf) + return buf.Bytes(), err +} + +// DecodeRLP implements rlp.Decoder +func (r *Request) DecodeRLP(s *rlp.Stream) error { + kind, size, err := s.Kind() + switch { + case err != nil: + return err + case kind == rlp.List: + return fmt.Errorf("untyped request") + case kind == rlp.Byte: + return errShortTypedRequest + default: + // First read the request payload bytes into a temporary buffer. + b, buf, err := getPooledBuffer(size) + if err != nil { + return err + } + defer encodeBufferPool.Put(buf) + if err := s.ReadBytes(b); err != nil { + return err + } + // Now decode the inner request. + inner, err := r.decode(b) + if err == nil { + r.inner = inner + } + return err + } +} + +// UnmarshalBinary decodes the canonical encoding of requests. +func (r *Request) UnmarshalBinary(b []byte) error { + inner, err := r.decode(b) + if err != nil { + return err + } + r.inner = inner + return nil +} + +// decode decodes a request from the canonical format. +func (r *Request) decode(b []byte) (RequestData, error) { + if len(b) <= 1 { + return nil, errShortTypedRequest + } + var inner RequestData + switch b[0] { + case DepositRequestType: + inner = new(Deposit) + default: + return nil, ErrRequestTypeNotSupported + } + err := inner.decode(b[1:]) + return inner, err +} diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 48bfb021b948..7ea1c9ee0760 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -86,11 +86,15 @@ var caps = []string{ "engine_getPayloadV1", "engine_getPayloadV2", "engine_getPayloadV3", + "engine_getPayloadV4", "engine_newPayloadV1", "engine_newPayloadV2", "engine_newPayloadV3", + "engine_newPayloadV4", "engine_getPayloadBodiesByHashV1", + "engine_getPayloadBodiesByHashV2", "engine_getPayloadBodiesByRangeV1", + "engine_getPayloadBodiesByRangeV2", "engine_getClientVersionV1", } @@ -220,7 +224,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa if params.BeaconRoot == nil { return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { + if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun && api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads")) } } @@ -443,6 +447,14 @@ func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.Execu return api.getPayload(payloadID, false) } +// GetPayloadV4 returns a cached payload by id. +func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { + if !payloadID.Is(engine.PayloadV4) { + return nil, engine.UnsupportedFork + } + return api.getPayload(payloadID, false) +} + func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID, full bool) (*engine.ExecutionPayloadEnvelope, error) { log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID) data := api.localBlocks.get(payloadID, full) @@ -508,6 +520,34 @@ func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHas return api.newPayload(params, versionedHashes, beaconRoot) } +// NewPayloadV4 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. +func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) { + if params.Withdrawals == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) + } + if params.ExcessBlobGas == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil excessBlobGas post-cancun")) + } + if params.BlobGasUsed == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil blobGasUsed post-cancun")) + } + if params.Deposits == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil deposits post-prague")) + } + + if versionedHashes == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil versionedHashes post-cancun")) + } + if beaconRoot == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun")) + } + + if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV4 must only be called for prague payloads")) + } + return api.newPayload(params, versionedHashes, beaconRoot) +} + func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) { // The locking here is, strictly, not required. Without these locks, this can happen: // @@ -553,6 +593,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe "params.ExcessBlobGas", ebg, "len(params.Transactions)", len(params.Transactions), "len(params.Withdrawals)", len(params.Withdrawals), + "len(params.Deposits)", len(params.Deposits), "beaconRoot", beaconRoot, "error", err) return api.invalid(err, nil), nil @@ -826,8 +867,25 @@ func (api *ConsensusAPI) GetClientVersionV1(info engine.ClientVersionV1) []engin // GetPayloadBodiesByHashV1 implements engine_getPayloadBodiesByHashV1 which allows for retrieval of a list // of block bodies by the engine api. -func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engine.ExecutionPayloadBodyV1 { - bodies := make([]*engine.ExecutionPayloadBodyV1, len(hashes)) +func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engine.ExecutionPayloadBody { + bodies := make([]*engine.ExecutionPayloadBody, len(hashes)) + for i, hash := range hashes { + block := api.eth.BlockChain().GetBlockByHash(hash) + body := getBody(block) + if body != nil { + // Nil out the V2 values, clients should know to not request V1 objects + // after Prague. + body.Deposits = nil + } + bodies[i] = body + } + return bodies +} + +// GetPayloadBodiesByHashV2 implements engine_getPayloadBodiesByHashV1 which allows for retrieval of a list +// of block bodies by the engine api. +func (api *ConsensusAPI) GetPayloadBodiesByHashV2(hashes []common.Hash) []*engine.ExecutionPayloadBody { + bodies := make([]*engine.ExecutionPayloadBody, len(hashes)) for i, hash := range hashes { block := api.eth.BlockChain().GetBlockByHash(hash) bodies[i] = getBody(block) @@ -837,7 +895,28 @@ func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engin // GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range // of block bodies by the engine api. -func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBodyV1, error) { +func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBody, error) { + bodies, err := api.getBodiesByRange(start, count) + if err != nil { + return nil, err + } + // Nil out the V2 values, clients should know to not request V1 objects + // after Prague. + for i := range bodies { + if bodies[i] != nil { + bodies[i].Deposits = nil + } + } + return bodies, nil +} + +// GetPayloadBodiesByRangeV2 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range +// of block bodies by the engine api. +func (api *ConsensusAPI) GetPayloadBodiesByRangeV2(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBody, error) { + return api.getBodiesByRange(start, count) +} + +func (api *ConsensusAPI) getBodiesByRange(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBody, error) { if start == 0 || count == 0 { return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count)) } @@ -850,7 +929,7 @@ func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) if last > current { last = current } - bodies := make([]*engine.ExecutionPayloadBodyV1, 0, uint64(count)) + bodies := make([]*engine.ExecutionPayloadBody, 0, uint64(count)) for i := uint64(start); i <= last; i++ { block := api.eth.BlockChain().GetBlockByNumber(i) bodies = append(bodies, getBody(block)) @@ -858,15 +937,16 @@ func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) return bodies, nil } -func getBody(block *types.Block) *engine.ExecutionPayloadBodyV1 { +func getBody(block *types.Block) *engine.ExecutionPayloadBody { if block == nil { return nil } var ( - body = block.Body() - txs = make([]hexutil.Bytes, len(body.Transactions)) - withdrawals = body.Withdrawals + body = block.Body() + txs = make([]hexutil.Bytes, len(body.Transactions)) + withdrawals = body.Withdrawals + depositRequests types.Deposits ) for j, tx := range body.Transactions { @@ -878,8 +958,20 @@ func getBody(block *types.Block) *engine.ExecutionPayloadBodyV1 { withdrawals = make([]*types.Withdrawal, 0) } - return &engine.ExecutionPayloadBodyV1{ + if block.Header().RequestsHash != nil { + // TODO: this isn't future proof because we can't determine if a request + // type has activated yet or if there are just no requests of that type from + // only the block. + for _, req := range block.Requests() { + if d, ok := req.Inner().(*types.Deposit); ok { + depositRequests = append(depositRequests, d) + } + } + } + + return &engine.ExecutionPayloadBody{ TransactionData: txs, Withdrawals: withdrawals, + Deposits: depositRequests, } } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 64e6684be155..0a58e1eaee02 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -74,6 +74,12 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { Alloc: types.GenesisAlloc{ testAddr: {Balance: testBalance}, params.BeaconRootsAddress: {Balance: common.Big0, Code: common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500")}, + config.DepositContractAddress: { + // Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7 + Code: common.Hex2Bytes("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033"), + Nonce: 0, + Balance: big.NewInt(0), + }, }, ExtraData: []byte("test genesis"), Timestamp: 9000, @@ -483,10 +489,10 @@ func TestFullAPI(t *testing.T) { ethservice.TxPool().Add([]*types.Transaction{tx}, true, false) } - setupBlocks(t, ethservice, 10, parent, callback, nil) + setupBlocks(t, ethservice, 10, parent, callback, nil, nil) } -func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header), withdrawals [][]*types.Withdrawal) []*types.Header { +func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header), withdrawals [][]*types.Withdrawal, beaconRoots []common.Hash) []*types.Header { api := NewConsensusAPI(ethservice) var blocks []*types.Header for i := 0; i < n; i++ { @@ -495,14 +501,18 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.He if withdrawals != nil { w = withdrawals[i] } + var h *common.Hash + if beaconRoots != nil { + h = &beaconRoots[i] + } - payload := getNewPayload(t, api, parent, w) - execResp, err := api.NewPayloadV2(*payload) + payload := getNewPayload(t, api, parent, w, h) + execResp, err := api.newPayload(*payload, []common.Hash{}, h) if err != nil { t.Fatalf("can't execute payload: %v", err) } if execResp.Status != engine.VALID { - t.Fatalf("invalid status: %v", execResp.Status) + t.Fatalf("invalid status: %v %s", execResp.Status, *execResp.ValidationError) } fcState := engine.ForkchoiceStateV1{ HeadBlockHash: payload.BlockHash, @@ -690,10 +700,10 @@ func TestEmptyBlocks(t *testing.T) { api := NewConsensusAPI(ethservice) // Setup 10 blocks on the canonical chain - setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil) + setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil, nil) // (1) check LatestValidHash by sending a normal payload (P1'') - payload := getNewPayload(t, api, commonAncestor, nil) + payload := getNewPayload(t, api, commonAncestor, nil, nil) status, err := api.NewPayloadV1(*payload) if err != nil { @@ -707,7 +717,7 @@ func TestEmptyBlocks(t *testing.T) { } // (2) Now send P1' which is invalid - payload = getNewPayload(t, api, commonAncestor, nil) + payload = getNewPayload(t, api, commonAncestor, nil, nil) payload.GasUsed += 1 payload = setBlockhash(payload) // Now latestValidHash should be the common ancestor @@ -725,7 +735,7 @@ func TestEmptyBlocks(t *testing.T) { } // (3) Now send a payload with unknown parent - payload = getNewPayload(t, api, commonAncestor, nil) + payload = getNewPayload(t, api, commonAncestor, nil, nil) payload.ParentHash = common.Hash{1} payload = setBlockhash(payload) // Now latestValidHash should be the common ancestor @@ -741,12 +751,13 @@ func TestEmptyBlocks(t *testing.T) { } } -func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal) *engine.ExecutableData { +func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal, beaconRoot *common.Hash) *engine.ExecutableData { params := engine.PayloadAttributes{ Timestamp: parent.Time + 1, Random: crypto.Keccak256Hash([]byte{byte(1)}), SuggestedFeeRecipient: parent.Coinbase, Withdrawals: withdrawals, + BeaconRoot: beaconRoot, } payload, err := assembleBlock(api, parent.Hash(), ¶ms) @@ -814,7 +825,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { commonAncestor := ethserviceA.BlockChain().CurrentBlock() // Setup 10 blocks on the canonical chain - setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}, nil) + setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}, nil, nil) commonAncestor = ethserviceA.BlockChain().CurrentBlock() var invalidChain []*engine.ExecutableData @@ -823,7 +834,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { //invalidChain = append(invalidChain, payload1) // create an invalid payload2 (P2) - payload2 := getNewPayload(t, apiA, commonAncestor, nil) + payload2 := getNewPayload(t, apiA, commonAncestor, nil, nil) //payload2.ParentHash = payload1.BlockHash payload2.GasUsed += 1 payload2 = setBlockhash(payload2) @@ -832,7 +843,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { head := payload2 // create some valid payloads on top for i := 0; i < 10; i++ { - payload := getNewPayload(t, apiA, commonAncestor, nil) + payload := getNewPayload(t, apiA, commonAncestor, nil, nil) payload.ParentHash = head.BlockHash payload = setBlockhash(payload) invalidChain = append(invalidChain, payload) @@ -869,10 +880,10 @@ func TestInvalidBloom(t *testing.T) { api := NewConsensusAPI(ethservice) // Setup 10 blocks on the canonical chain - setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil) + setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil, nil) // (1) check LatestValidHash by sending a normal payload (P1'') - payload := getNewPayload(t, api, commonAncestor, nil) + payload := getNewPayload(t, api, commonAncestor, nil, nil) payload.LogsBloom = append(payload.LogsBloom, byte(1)) status, err := api.NewPayloadV1(*payload) if err != nil { @@ -1285,24 +1296,35 @@ func TestNilWithdrawals(t *testing.T) { func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { genesis, blocks := generateMergeChain(10, true) - // enable shanghai on the last block + + // Enable next forks on the last block. time := blocks[len(blocks)-1].Header().Time + 1 genesis.Config.ShanghaiTime = &time + genesis.Config.CancunTime = &time + genesis.Config.PragueTime = &time + n, ethservice := startEthService(t, genesis, blocks) var ( - parent = ethservice.BlockChain().CurrentBlock() // This EVM code generates a log when the contract is created. logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") + parent = ethservice.BlockChain().CurrentBlock() ) + // Each block, this callback will include two txs that generate body values like logs and requests. callback := func(parent *types.Header) { - statedb, _ := ethservice.BlockChain().StateAt(parent.Root) - nonce := statedb.GetNonce(testAddr) - tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) - ethservice.TxPool().Add([]*types.Transaction{tx}, false, false) + var ( + statedb, _ = ethservice.BlockChain().StateAt(parent.Root) + // Create tx to trigger log generator. + tx1, _ = types.SignTx(types.NewContractCreation(statedb.GetNonce(testAddr), new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) + // Create tx to trigger deposit generator. + tx2, _ = types.SignTx(types.NewTransaction(statedb.GetNonce(testAddr)+1, ethservice.APIBackend.ChainConfig().DepositContractAddress, new(big.Int), 500000, big.NewInt(2*params.InitialBaseFee), nil), types.LatestSigner(ethservice.BlockChain().Config()), testKey) + ) + ethservice.TxPool().Add([]*types.Transaction{tx1}, false, false) + ethservice.TxPool().Add([]*types.Transaction{tx2}, false, false) } + // Make some withdrawals to include. withdrawals := make([][]*types.Withdrawal, 10) withdrawals[0] = nil // should be filtered out by miner withdrawals[1] = make([]*types.Withdrawal, 0) @@ -1314,12 +1336,20 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { } } - postShanghaiHeaders := setupBlocks(t, ethservice, 10, parent, callback, withdrawals) - postShanghaiBlocks := make([]*types.Block, len(postShanghaiHeaders)) - for i, header := range postShanghaiHeaders { - postShanghaiBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64()) + // Make beacon root update for each block. + beaconRoots := make([]common.Hash, 10) + for i := 0; i < 10; i++ { + beaconRoots[i] = common.Hash{byte(i)} + } + + // Create the blocks. + newHeaders := setupBlocks(t, ethservice, 10, parent, callback, withdrawals, beaconRoots) + newBlocks := make([]*types.Block, len(newHeaders)) + for i, header := range newHeaders { + newBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64()) } - return n, ethservice, append(blocks, postShanghaiBlocks...) + + return n, ethservice, append(blocks, newBlocks...) } func allHashes(blocks []*types.Block) []common.Hash { @@ -1384,7 +1414,7 @@ func TestGetBlockBodiesByHash(t *testing.T) { } for k, test := range tests { - result := api.GetPayloadBodiesByHashV1(test.hashes) + result := api.GetPayloadBodiesByHashV2(test.hashes) for i, r := range result { if !equalBody(test.results[i], r) { t.Fatalf("test %v: invalid response: expected %+v got %+v", k, test.results[i], r) @@ -1458,7 +1488,7 @@ func TestGetBlockBodiesByRange(t *testing.T) { } for k, test := range tests { - result, err := api.GetPayloadBodiesByRangeV1(test.start, test.count) + result, err := api.GetPayloadBodiesByRangeV2(test.start, test.count) if err != nil { t.Fatal(err) } @@ -1509,7 +1539,7 @@ func TestGetBlockBodiesByRangeInvalidParams(t *testing.T) { }, } for i, tc := range tests { - result, err := api.GetPayloadBodiesByRangeV1(tc.start, tc.count) + result, err := api.GetPayloadBodiesByRangeV2(tc.start, tc.count) if err == nil { t.Fatalf("test %d: expected error, got %v", i, result) } @@ -1519,7 +1549,7 @@ func TestGetBlockBodiesByRangeInvalidParams(t *testing.T) { } } -func equalBody(a *types.Body, b *engine.ExecutionPayloadBodyV1) bool { +func equalBody(a *types.Body, b *engine.ExecutionPayloadBody) bool { if a == nil && b == nil { return true } else if a == nil || b == nil { @@ -1534,7 +1564,23 @@ func equalBody(a *types.Body, b *engine.ExecutionPayloadBodyV1) bool { return false } } - return reflect.DeepEqual(a.Withdrawals, b.Withdrawals) + + if !reflect.DeepEqual(a.Withdrawals, b.Withdrawals) { + return false + } + + var deposits types.Deposits + if a.Requests != nil { + // If requests is non-nil, it means deposits are available in block and we + // should return an empty slice instead of nil if there are no deposits. + deposits = make(types.Deposits, 0) + } + for _, r := range a.Requests { + if d, ok := r.Inner().(*types.Deposit); ok { + deposits = append(deposits, d) + } + } + return reflect.DeepEqual(deposits, b.Deposits) } func TestBlockToPayloadWithBlobs(t *testing.T) { diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index 86355a153387..cb27810aac8e 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -109,7 +109,7 @@ func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, err // if genesis block, send forkchoiceUpdated to trigger transition to PoS if block.Number.Sign() == 0 { - if _, err := engineAPI.ForkchoiceUpdatedV2(current, nil); err != nil { + if _, err := engineAPI.ForkchoiceUpdatedV3(current, nil); err != nil { return nil, err } } @@ -226,7 +226,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u c.setCurrentState(payload.BlockHash, finalizedHash) // Mark the block containing the payload as canonical - if _, err = c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, nil); err != nil { + if _, err = c.engineAPI.ForkchoiceUpdatedV3(c.curForkchoiceState, nil); err != nil { return err } c.lastBlockTime = payload.Timestamp diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 0cbddee6bf7a..c440b40e9dc7 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -230,6 +230,7 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et txsHashes = make([]common.Hash, len(bodies)) uncleHashes = make([]common.Hash, len(bodies)) withdrawalHashes = make([]common.Hash, len(bodies)) + requestsHashes = make([]common.Hash, len(bodies)) ) hasher := trie.NewStackTrie(nil) for i, body := range bodies { @@ -248,7 +249,7 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et res := ð.Response{ Req: req, Res: (*eth.BlockBodiesResponse)(&bodies), - Meta: [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes}, + Meta: [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes, requestsHashes}, Time: 1, Done: make(chan error, 1), // Ignore the returned status } diff --git a/eth/downloader/fetchers_concurrent_bodies.go b/eth/downloader/fetchers_concurrent_bodies.go index 56359b33c94e..709df7757507 100644 --- a/eth/downloader/fetchers_concurrent_bodies.go +++ b/eth/downloader/fetchers_concurrent_bodies.go @@ -88,10 +88,10 @@ func (q *bodyQueue) request(peer *peerConnection, req *fetchRequest, resCh chan // deliver is responsible for taking a generic response packet from the concurrent // fetcher, unpacking the body data and delivering it to the downloader's queue. func (q *bodyQueue) deliver(peer *peerConnection, packet *eth.Response) (int, error) { - txs, uncles, withdrawals := packet.Res.(*eth.BlockBodiesResponse).Unpack() - hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes, withdrawal hashes} + txs, uncles, withdrawals, requests := packet.Res.(*eth.BlockBodiesResponse).Unpack() + hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes, withdrawal hashes, requests hashes} - accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1], withdrawals, hashsets[2]) + accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1], withdrawals, hashsets[2], requests, hashsets[3]) switch { case err == nil && len(txs) == 0: peer.log.Trace("Requested bodies delivered") diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 5441ad118791..adad45020040 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -784,7 +784,8 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, hashes []comm // also wakes any threads waiting for data delivery. func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash, uncleLists [][]*types.Header, uncleListHashes []common.Hash, - withdrawalLists [][]*types.Withdrawal, withdrawalListHashes []common.Hash) (int, error) { + withdrawalLists [][]*types.Withdrawal, withdrawalListHashes []common.Hash, + requestsLists [][]*types.Request, requestsListHashes []common.Hash) (int, error) { q.lock.Lock() defer q.lock.Unlock() @@ -808,6 +809,19 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH return errInvalidBody } } + if header.RequestsHash == nil { + // nil hash means that requests should not be present in body + if requestsLists[index] != nil { + return errInvalidBody + } + } else { // non-nil hash: body must have requests + if requestsLists[index] == nil { + return errInvalidBody + } + if requestsListHashes[index] != *header.RequestsHash { + return errInvalidBody + } + } // Blocks must have a number of blobs corresponding to the header gas usage, // and zero before the Cancun hardfork. var blobs int diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index 857ac4813a7d..e29d23f80b7a 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -341,7 +341,7 @@ func XTestDelivery(t *testing.T) { uncleHashes[i] = types.CalcUncleHash(uncles) } time.Sleep(100 * time.Millisecond) - _, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes, nil, nil) + _, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes, nil, nil, nil, nil) if err != nil { fmt.Printf("delivered %d bodies %v\n", len(txset), err) } diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index b3886270f3dd..951352319ffc 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -316,6 +316,7 @@ func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error { txsHashes = make([]common.Hash, len(res.BlockBodiesResponse)) uncleHashes = make([]common.Hash, len(res.BlockBodiesResponse)) withdrawalHashes = make([]common.Hash, len(res.BlockBodiesResponse)) + requestsHashes = make([]common.Hash, len(res.BlockBodiesResponse)) ) hasher := trie.NewStackTrie(nil) for i, body := range res.BlockBodiesResponse { @@ -324,8 +325,11 @@ func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error { if body.Withdrawals != nil { withdrawalHashes[i] = types.DeriveSha(types.Withdrawals(body.Withdrawals), hasher) } + if body.Requests != nil { + requestsHashes[i] = types.DeriveSha(types.Requests(body.Requests), hasher) + } } - return [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes} + return [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes, requestsHashes} } return peer.dispatchResponse(&Response{ id: res.RequestId, diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index c5cb2dd1dca4..cbc895eabb8e 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -224,21 +224,22 @@ type BlockBody struct { Transactions []*types.Transaction // Transactions contained within a block Uncles []*types.Header // Uncles contained within a block Withdrawals []*types.Withdrawal `rlp:"optional"` // Withdrawals contained within a block + Requests []*types.Request `rlp:"optional"` // Requests contained within a block } // Unpack retrieves the transactions and uncles from the range packet and returns // them in a split flat format that's more consistent with the internal data structures. -func (p *BlockBodiesResponse) Unpack() ([][]*types.Transaction, [][]*types.Header, [][]*types.Withdrawal) { - // TODO(matt): add support for withdrawals to fetchers +func (p *BlockBodiesResponse) Unpack() ([][]*types.Transaction, [][]*types.Header, [][]*types.Withdrawal, [][]*types.Request) { var ( txset = make([][]*types.Transaction, len(*p)) uncleset = make([][]*types.Header, len(*p)) withdrawalset = make([][]*types.Withdrawal, len(*p)) + requestset = make([][]*types.Request, len(*p)) ) for i, body := range *p { - txset[i], uncleset[i], withdrawalset[i] = body.Transactions, body.Uncles, body.Withdrawals + txset[i], uncleset[i], withdrawalset[i], requestset[i] = body.Transactions, body.Uncles, body.Withdrawals, body.Requests } - return txset, uncleset, withdrawalset + return txset, uncleset, withdrawalset, requestset } // GetReceiptsRequest represents a block receipts query. diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 90f7c013919b..7b6f5ba1507b 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -146,7 +146,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u if current = eth.blockchain.GetBlockByNumber(next); current == nil { return nil, nil, fmt.Errorf("block #%d not found", next) } - _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) + _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) if err != nil { return nil, nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 7638c3cd09c3..b952c822863f 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -390,7 +390,7 @@ func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, r // OnOpcode also tracks SLOAD/SSTORE ops to track storage change. func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { stack := scope.StackData() - fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) + fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, vm.OpCode(op).String(), cost) if !t.cfg.DisableStack { // format stack diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index f769ee847554..a1148bcedbc6 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -123,6 +123,7 @@ type rpcBlock struct { Transactions []rpcTransaction `json:"transactions"` UncleHashes []common.Hash `json:"uncles"` Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` + Requests []*types.Request `json:"requests,omitempty"` } func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { @@ -196,6 +197,7 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface Transactions: txs, Uncles: uncles, Withdrawals: body.Withdrawals, + Requests: body.Requests, }), nil } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1c3cb4adf936..aeb3e8adc289 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1268,6 +1268,9 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { if head.ParentBeaconRoot != nil { result["parentBeaconBlockRoot"] = head.ParentBeaconRoot } + if head.RequestsHash != nil { + result["requestsRoot"] = head.RequestsHash + } return result } @@ -1303,6 +1306,9 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param if block.Header().WithdrawalsHash != nil { fields["withdrawals"] = block.Withdrawals() } + if block.Header().RequestsHash != nil { + fields["requests"] = block.Requests() + } return fields } diff --git a/miner/worker.go b/miner/worker.go index 4e566f14897c..1f49118c474e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -105,7 +105,20 @@ func (miner *Miner) generateWork(params *generateParams) *newPayloadResult { log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit)) } } + body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals} + allLogs := make([]*types.Log, 0) + for _, r := range work.receipts { + allLogs = append(allLogs, r.Logs...) + } + // Read requests if Prague is enabled. + if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) { + requests, err := core.ParseDepositLogs(allLogs, miner.chainConfig) + if err != nil { + return &newPayloadResult{err: err} + } + body.Requests = requests + } block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts) if err != nil { return &newPayloadResult{err: err} diff --git a/params/config.go b/params/config.go index c4e6ba6948cf..9ecf465bb67a 100644 --- a/params/config.go +++ b/params/config.go @@ -58,6 +58,7 @@ var ( TerminalTotalDifficultyPassed: true, ShanghaiTime: newUint64(1681338455), CancunTime: newUint64(1710338135), + DepositContractAddress: common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa"), Ethash: new(EthashConfig), } // HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network. @@ -337,6 +338,8 @@ type ChainConfig struct { // TODO(karalabe): Drop this field eventually (always assuming PoS mode) TerminalTotalDifficultyPassed bool `json:"terminalTotalDifficultyPassed,omitempty"` + DepositContractAddress common.Address `json:"depositContractAddress,omitempty"` + // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` diff --git a/tests/init.go b/tests/init.go index c85e714c0023..4bb83f9300bc 100644 --- a/tests/init.go +++ b/tests/init.go @@ -373,6 +373,7 @@ var Forks = map[string]*params.ChainConfig{ ShanghaiTime: u64(0), CancunTime: u64(0), PragueTime: u64(0), + DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, }, "CancunToPragueAtTime15k": { ChainID: big.NewInt(1), @@ -393,6 +394,7 @@ var Forks = map[string]*params.ChainConfig{ ShanghaiTime: u64(0), CancunTime: u64(0), PragueTime: u64(15_000), + DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, }, } From b0b67be0a2559073c1620555d2b6a73f825f7135 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 4 Sep 2024 15:03:06 +0200 Subject: [PATCH 512/571] all: remove forkchoicer and reorgNeeded (#29179) This PR changes how sidechains are handled. Before the merge, it was possible to import a chain with lower td and not set it as canonical. After the merge, we expect every chain that we get via InsertChain to be canonical. Non-canonical blocks can still be inserted with InsertBlockWIthoutSetHead. If during the InsertChain, the existing chain is not canonical anymore, we mark it as a sidechain and send the SideChainEvents normally. --- cmd/utils/cmd.go | 3 +- cmd/utils/flags.go | 2 +- cmd/utils/history_test.go | 4 +- consensus/clique/clique_test.go | 6 +- consensus/clique/snapshot_test.go | 2 +- core/bench_test.go | 4 +- core/block_validator_test.go | 4 +- core/blockchain.go | 107 ++++---------- core/blockchain_insert.go | 5 - core/blockchain_repair_test.go | 8 +- core/blockchain_sethead_test.go | 2 +- core/blockchain_snapshot_test.go | 20 +-- core/blockchain_test.go | 138 +++++++++--------- core/chain_makers_test.go | 4 +- core/dao_test.go | 12 +- core/forkchoice.go | 113 -------------- core/genesis_test.go | 2 +- core/headerchain.go | 15 +- core/headerchain_test.go | 31 ++-- core/state_processor_test.go | 8 +- eth/backend.go | 6 +- eth/downloader/downloader_test.go | 2 +- eth/downloader/testchain_test.go | 2 +- eth/filters/filter_test.go | 2 +- eth/gasprice/gasprice_test.go | 2 +- eth/handler_eth_test.go | 4 +- eth/handler_test.go | 2 +- eth/protocols/eth/handler_test.go | 2 +- eth/protocols/snap/handler_fuzzing_test.go | 2 +- eth/tracers/api_test.go | 4 +- eth/tracers/internal/tracetest/supply_test.go | 2 +- internal/ethapi/api_test.go | 2 +- miner/miner_test.go | 2 +- miner/payload_building_test.go | 2 +- tests/block_test.go | 11 ++ tests/block_test_util.go | 2 +- 36 files changed, 185 insertions(+), 354 deletions(-) delete mode 100644 core/forkchoice.go diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index fc66e11dca96..791b3d1d205a 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -262,7 +262,6 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ start = time.Now() reported = time.Now() imported = 0 - forker = core.NewForkChoice(chain, nil) h = sha256.New() buf = bytes.NewBuffer(nil) ) @@ -305,7 +304,7 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ if err != nil { return fmt.Errorf("error reading receipts %d: %w", it.Number(), err) } - if status, err := chain.HeaderChain().InsertHeaderChain([]*types.Header{block.Header()}, start, forker); err != nil { + if status, err := chain.HeaderChain().InsertHeaderChain([]*types.Header{block.Header()}, start); err != nil { return fmt.Errorf("error inserting header %d: %w", it.Number(), err) } else if status != core.CanonStatTy { return fmt.Errorf("error inserting header %d, not canon: %v", it.Number(), status) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 611189a2cc00..f55c3b52d094 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2210,7 +2210,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh } } // Disable transaction indexing/unindexing by default. - chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil) + chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil) if err != nil { Fatalf("Can't create BlockChain: %v", err) } diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go index a631eaf49036..1074a358ec2c 100644 --- a/cmd/utils/history_test.go +++ b/cmd/utils/history_test.go @@ -78,7 +78,7 @@ func TestHistoryImportAndExport(t *testing.T) { }) // Initialize BlockChain. - chain, err := core.NewBlockChain(db, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil) if err != nil { t.Fatalf("unable to initialize chain: %v", err) } @@ -171,7 +171,7 @@ func TestHistoryImportAndExport(t *testing.T) { }) genesis.MustCommit(db2, triedb.NewDatabase(db, triedb.HashDefaults)) - imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil) if err != nil { t.Fatalf("unable to initialize chain: %v", err) } diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index f14c8cb5bae3..bacd2074931e 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -55,7 +55,7 @@ func TestReimportMirroredState(t *testing.T) { copy(genspec.ExtraData[extraVanity:], addr[:]) // Generate a batch of blocks, each properly signed - chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, engine, vm.Config{}, nil) defer chain.Stop() _, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) { @@ -87,7 +87,7 @@ func TestReimportMirroredState(t *testing.T) { } // Insert the first two blocks and make sure the chain is valid db = rawdb.NewMemoryDatabase() - chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil) + chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil) defer chain.Stop() if _, err := chain.InsertChain(blocks[:2]); err != nil { @@ -100,7 +100,7 @@ func TestReimportMirroredState(t *testing.T) { // Simulate a crash by creating a new chain on top of the database, without // flushing the dirty states out. Insert the last block, triggering a sidechain // reimport. - chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil) + chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil) defer chain.Stop() if _, err := chain.InsertChain(blocks[2:]); err != nil { diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 4ef7a7b3aee6..6c46d1db4f4b 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -458,7 +458,7 @@ func (tt *cliqueTest) run(t *testing.T) { batches[len(batches)-1] = append(batches[len(batches)-1], block) } // Pass all the headers through clique and ensure tallying succeeds - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create test chain: %v", err) } diff --git a/core/bench_test.go b/core/bench_test.go index 97713868a547..639d36e9aea6 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -195,7 +195,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. - chainman, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chainman, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() @@ -312,7 +312,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } - chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil) if err != nil { b.Fatalf("error creating chain: %v", err) } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index c573ef91faca..16824467c16a 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -50,7 +50,7 @@ func testHeaderVerification(t *testing.T, scheme string) { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer chain.Stop() for i := 0; i < len(blocks); i++ { @@ -160,7 +160,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { postHeaders[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) defer chain.Stop() // Verify the blocks before the merging diff --git a/core/blockchain.go b/core/blockchain.go index 397d917d73a5..b0c8da98ffb1 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -259,7 +259,6 @@ type BlockChain struct { validator Validator // Block and state validator interface prefetcher Prefetcher processor Processor // Block transaction processor interface - forker *ForkChoice vmConfig vm.Config logger *tracing.Hooks } @@ -267,7 +266,7 @@ type BlockChain struct { // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator // and Processor. -func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis, overrides *ChainOverrides, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) { +func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis, overrides *ChainOverrides, engine consensus.Engine, vmConfig vm.Config, txLookupLimit *uint64) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = defaultCacheConfig } @@ -312,7 +311,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis return nil, err } bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) - bc.forker = NewForkChoice(bc, shouldPreserve) bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) bc.validator = NewBlockValidator(chainConfig, bc) bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc) @@ -1243,13 +1241,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ // Rewind may have occurred, skip in that case. if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 { - reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), head.Header()) - if err != nil { - log.Warn("Reorg failed", "err", err) - return false - } else if !reorg { - return false - } rawdb.WriteHeadFastBlockHash(bc.db, head.Hash()) bc.currentSnapBlock.Store(head.Header()) headFastBlockGauge.Update(int64(head.NumberU64())) @@ -1548,42 +1539,30 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types return NonStatTy, err } currentBlock := bc.CurrentBlock() - reorg, err := bc.forker.ReorgNeeded(currentBlock, block.Header()) - if err != nil { - return NonStatTy, err - } - if reorg { - // Reorganise the chain if the parent is not the head block - if block.ParentHash() != currentBlock.Hash() { - if err := bc.reorg(currentBlock, block); err != nil { - return NonStatTy, err - } + + // Reorganise the chain if the parent is not the head block + if block.ParentHash() != currentBlock.Hash() { + if err := bc.reorg(currentBlock, block); err != nil { + return NonStatTy, err } - status = CanonStatTy - } else { - status = SideStatTy } + // Set new head. - if status == CanonStatTy { - bc.writeHeadBlock(block) - } - if status == CanonStatTy { - bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) - if len(logs) > 0 { - bc.logsFeed.Send(logs) - } - // In theory, we should fire a ChainHeadEvent when we inject - // a canonical block, but sometimes we can insert a batch of - // canonical blocks. Avoid firing too many ChainHeadEvents, - // we will fire an accumulated ChainHeadEvent and disable fire - // event here. - if emitHeadEvent { - bc.chainHeadFeed.Send(ChainHeadEvent{Block: block}) - } - } else { - bc.chainSideFeed.Send(ChainSideEvent{Block: block}) + bc.writeHeadBlock(block) + + bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) + if len(logs) > 0 { + bc.logsFeed.Send(logs) } - return status, nil + // In theory, we should fire a ChainHeadEvent when we inject + // a canonical block, but sometimes we can insert a batch of + // canonical blocks. Avoid firing too many ChainHeadEvents, + // we will fire an accumulated ChainHeadEvent and disable fire + // event here. + if emitHeadEvent { + bc.chainHeadFeed.Send(ChainHeadEvent{Block: block}) + } + return CanonStatTy, nil } // InsertChain attempts to insert the given batch of blocks in to the canonical @@ -1634,7 +1613,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if bc.insertStopped() { return 0, nil } - // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain) @@ -1667,24 +1645,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // 2. The block is stored as a sidechain, and is lying about it's stateroot, and passes a stateroot // from the canonical chain, which has not been verified. // Skip all known blocks that are behind us. - var ( - reorg bool - current = bc.CurrentBlock() - ) + current := bc.CurrentBlock() for block != nil && bc.skipBlock(err, it) { - reorg, err = bc.forker.ReorgNeeded(current, block.Header()) - if err != nil { - return it.index, err - } - if reorg { - // Switch to import mode if the forker says the reorg is necessary - // and also the block is not on the canonical chain. - // In eth2 the forker always returns true for reorg decision (blindly trusting - // the external consensus engine), but in order to prevent the unnecessary - // reorgs when importing known blocks, the special case is handled here. - if block.NumberU64() > current.Number.Uint64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() { - break - } + if block.NumberU64() > current.Number.Uint64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() { + break } log.Debug("Ignoring already known block", "number", block.Number(), "hash", block.Hash()) stats.ignored++ @@ -2006,9 +1970,8 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s // insertSideChain is only used pre-merge. func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, error) { var ( - externTd *big.Int - lastBlock = block - current = bc.CurrentBlock() + externTd *big.Int + current = bc.CurrentBlock() ) // The first sidechain block error is already verified to be ErrPrunedAncestor. // Since we don't import them here, we expect ErrUnknownAncestor for the remaining @@ -2059,22 +2022,6 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), "root", block.Root()) } - lastBlock = block - } - // At this point, we've written all sidechain blocks to database. Loop ended - // either on some other error or all were processed. If there was some other - // error, we can ignore the rest of those blocks. - // - // If the externTd was larger than our local TD, we now need to reimport the previous - // blocks to regenerate the required state - reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header()) - if err != nil { - return it.index, err - } - if !reorg { - localTd := bc.GetTd(current.Hash(), current.Number.Uint64()) - log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd) - return it.index, err } // Gather all the sidechain hashes (full blocks may be memory heavy) var ( @@ -2541,7 +2488,7 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header) (int, error) { return 0, errChainStopped } defer bc.chainmu.Unlock() - _, err := bc.hc.InsertHeaderChain(chain, start, bc.forker) + _, err := bc.hc.InsertHeaderChain(chain, start) return 0, err } diff --git a/core/blockchain_insert.go b/core/blockchain_insert.go index 49e913aadab3..ec3f771818fa 100644 --- a/core/blockchain_insert.go +++ b/core/blockchain_insert.go @@ -170,11 +170,6 @@ func (it *insertIterator) current() *types.Header { return it.chain[it.index].Header() } -// first returns the first block in it. -func (it *insertIterator) first() *types.Block { - return it.chain[0] -} - // remaining returns the number of remaining blocks. func (it *insertIterator) remaining() int { return len(it.chain) - it.index diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index a4761f337b85..07f154b4fa97 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1794,7 +1794,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s config.SnapshotLimit = 256 config.SnapshotWait = true } - chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -1859,7 +1859,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s } defer db.Close() - newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) + newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -1931,7 +1931,7 @@ func testIssue23496(t *testing.T, scheme string) { } engine = ethash.NewFullFaker() ) - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -1981,7 +1981,7 @@ func testIssue23496(t *testing.T, scheme string) { } defer db.Close() - chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 8b77f9f8b20c..b06ed83616b8 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1997,7 +1997,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme config.SnapshotLimit = 256 config.SnapshotWait = true } - chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 80f8035df151..45d33bb0a053 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -81,7 +81,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo } engine = ethash.NewFullFaker() ) - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -228,7 +228,7 @@ func (snaptest *snapshotTest) test(t *testing.T) { // Restart the chain normally chain.Stop() - newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -270,13 +270,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { // the crash, we do restart twice here: one after the crash and one // after the normal stop. It's used to ensure the broken snapshot // can be detected all the time. - newchain, err := NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } newchain.Stop() - newchain, err = NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -313,7 +313,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { SnapshotLimit: 0, StateScheme: snaptest.scheme, } - newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -321,7 +321,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { newchain.Stop() // Restart the chain with enabling the snapshot - newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -349,7 +349,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) { chain.SetHead(snaptest.setHead) chain.Stop() - newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -385,7 +385,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { SnapshotLimit: 0, StateScheme: snaptest.scheme, } - newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -402,7 +402,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { SnapshotWait: false, // Don't wait rebuild StateScheme: snaptest.scheme, } - tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -411,7 +411,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { tmp.triedb.Close() tmp.stopWithoutSaving() - newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 9148dd6f08d2..40f00982f227 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -22,6 +22,7 @@ import ( "math/big" "math/rand" "os" + "path" "sync" "testing" "time" @@ -61,7 +62,7 @@ func newCanonical(engine consensus.Engine, n int, full bool, scheme string) (eth } ) // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) // Create and inject the requested chain if n == 0 { @@ -763,7 +764,7 @@ func testFastVsFullChains(t *testing.T, scheme string) { }) // Import the chain as an archive node for the comparison baseline archiveDb := rawdb.NewMemoryDatabase() - archive, _ := NewBlockChain(archiveDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { @@ -771,7 +772,7 @@ func testFastVsFullChains(t *testing.T, scheme string) { } // Fast import the chain as a non-archive node to test fastDb := rawdb.NewMemoryDatabase() - fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -791,7 +792,7 @@ func testFastVsFullChains(t *testing.T, scheme string) { } defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers); err != nil { @@ -911,7 +912,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { archiveCaching.TrieDirtyDisabled = true archiveCaching.StateScheme = scheme - archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } @@ -924,7 +925,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb := makeDb() defer fastDb.Close() - fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -944,7 +945,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Import the chain as a ancient-first node and ensure all pointers are updated ancientDb := makeDb() defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers); err != nil { @@ -963,7 +964,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Import the chain as a light node and ensure all pointers are updated lightDb := makeDb() defer lightDb.Close() - light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) if n, err := light.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -1036,7 +1037,7 @@ func testChainTxReorgs(t *testing.T, scheme string) { }) // Import the chain. This runs all block validation rules. db := rawdb.NewMemoryDatabase() - blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -1110,7 +1111,7 @@ func testLogReorgs(t *testing.T, scheme string) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -1166,7 +1167,7 @@ func testLogRebirth(t *testing.T, scheme string) { gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} signer = types.LatestSigner(gspec.Config) engine = ethash.NewFaker() - blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) ) defer blockchain.Stop() @@ -1247,7 +1248,7 @@ func testSideLogRebirth(t *testing.T, scheme string) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} signer = types.LatestSigner(gspec.Config) - blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) ) defer blockchain.Stop() @@ -1266,7 +1267,7 @@ func testSideLogRebirth(t *testing.T, scheme string) { } checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) - // Generate side chain with lower difficulty + // Generate side chain with lower difficulty, after the merge, the chain will be accepted even if it is lower difficulty genDb, sideChain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *BlockGen) { if i == 1 { tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) @@ -1279,14 +1280,14 @@ func testSideLogRebirth(t *testing.T, scheme string) { if _, err := blockchain.InsertChain(sideChain); err != nil { t.Fatalf("failed to insert forked chain: %v", err) } - checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) + checkLogEvents(t, newLogCh, rmLogsCh, 1, 0) - // Generate a new block based on side chain. + // Generate a new block based on side chain. Should not emit any events anymore. newBlocks, _ := GenerateChain(gspec.Config, sideChain[len(sideChain)-1], ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := blockchain.InsertChain(newBlocks); err != nil { t.Fatalf("failed to insert forked chain: %v", err) } - checkLogEvents(t, newLogCh, rmLogsCh, 1, 0) + checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) } func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan RemovedLogsEvent, wantNew, wantRemoved int) { @@ -1346,7 +1347,7 @@ func testReorgSideEvent(t *testing.T, scheme string) { } signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {}) @@ -1370,15 +1371,10 @@ func testReorgSideEvent(t *testing.T, scheme string) { t.Fatalf("failed to insert chain: %v", err) } - // first two block of the secondary chain are for a brief moment considered - // side chains because up to that point the first one is considered the - // heavier chain. expectedSideHashes := map[common.Hash]bool{ - replacementBlocks[0].Hash(): true, - replacementBlocks[1].Hash(): true, - chain[0].Hash(): true, - chain[1].Hash(): true, - chain[2].Hash(): true, + chain[0].Hash(): true, + chain[1].Hash(): true, + chain[2].Hash(): true, } i := 0 @@ -1403,7 +1399,7 @@ done: timeout.Reset(timeoutDura) case <-timeout.C: - t.Fatal("Timeout. Possibly not all blocks were triggered for sideevent") + t.Fatalf("Timeout. Possibly not all blocks were triggered for sideevent: %v", i) } } @@ -1530,7 +1526,7 @@ func testEIP155Transition(t *testing.T, scheme string) { } }) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() if _, err := blockchain.InsertChain(blocks); err != nil { @@ -1623,7 +1619,7 @@ func testEIP161AccountRemoval(t *testing.T, scheme string) { block.AddTx(tx) }) // account must exist pre eip 161 - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil { @@ -1681,7 +1677,7 @@ func testBlockchainHeaderchainReorgConsistency(t *testing.T, scheme string) { } // Import the canonical and fork chain side by side, verifying the current block // and current header consistency - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1725,7 +1721,7 @@ func TestTrieForkGC(t *testing.T) { forks[i] = fork[0] } // Import the canonical and fork chain side by side, forcing the trie cache to cache both - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1771,7 +1767,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) defer db.Close() - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1787,18 +1783,15 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { if chain.HasState(shared[len(shared)-1].Root()) { t.Fatalf("common-but-old ancestor still cache") } - // Import the competitor chain without exceeding the canonical's TD and ensure - // we have not processed any of the blocks (protection against malicious blocks) + // Import the competitor chain without exceeding the canonical's TD. + // Post-merge the side chain should be executed if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil { t.Fatalf("failed to insert competitor chain: %v", err) } - for i, block := range competitor[:len(competitor)-2] { - if chain.HasState(block.Root()) { - t.Fatalf("competitor %d: low TD chain became processed", i) - } + if !chain.HasState(competitor[len(competitor)-3].Root()) { + t.Fatalf("failed to insert low-TD chain") } - // Import the head of the competitor chain, triggering the reorg and ensure we - // successfully reprocess all the stashed away blocks. + // Import the head of the competitor chain. if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { t.Fatalf("failed to finalize competitor chain: %v", err) } @@ -1842,7 +1835,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -1862,7 +1855,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) { rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash()) // Reopen broken blockchain again - ancient, _ = NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ = NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer ancient.Stop() if num := ancient.CurrentBlock().Number.Uint64(); num != 0 { t.Errorf("head block mismatch: have #%v, want #%v", num, 0) @@ -1914,7 +1907,7 @@ func testInsertReceiptChainRollback(t *testing.T, scheme string) { } defer ancientDb.Close() - ancientChain, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancientChain, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer ancientChain.Stop() // Import the canonical header chain. @@ -1981,7 +1974,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) { diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) defer diskdb.Close() - chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2042,7 +2035,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon mergeBlock = math.MaxInt32 ) // Generate and import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2196,7 +2189,7 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) { } defer chaindb.Close() - chain, err := NewBlockChain(chaindb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2280,10 +2273,10 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) { if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { t.Fatalf("failed to insert chain data: %v", err) } - // The head shouldn't change. - asserter(t, blocks3[len(blocks3)-1]) + // Post-merge the chain should change even if td is lower. + asserter(t, blocks2[len(blocks2)-1]) - // Rollback the heavier chain and re-insert the longer chain again + // Rollback the heavier chain and re-insert the longer chain again. chain.SetHead(rollback - 1) if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { t.Fatalf("failed to insert chain data: %v", err) @@ -2367,7 +2360,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } defer chaindb.Close() - chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2481,7 +2474,7 @@ func getLongAndShortChains(scheme string) (*BlockChain, []*types.Block, []*types genDb, longChain, _ := GenerateChainWithGenesis(genesis, engine, 80, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } @@ -2657,7 +2650,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in b.ResetTimer() for i := 0; i < b.N; i++ { // Import the shared chain and the original canonical one - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } @@ -2744,7 +2737,21 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { // Generate and import the canonical chain _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + // Construct a database with freezer enabled + datadir := t.TempDir() + ancient := path.Join(datadir, "ancient") + + db, err := rawdb.Open(rawdb.OpenOptions{ + Directory: datadir, + AncientsDirectory: ancient, + Ephemeral: true, + }) + if err != nil { + t.Fatalf("Failed to create persistent database: %v", err) + } + defer db.Close() + + chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2771,7 +2778,6 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) } - // Now re-import some old blocks blockToReimport := blocks[5:8] _, err = chain.InsertChain(blockToReimport) if err != nil { @@ -2844,7 +2850,7 @@ func testDeleteCreateRevert(t *testing.T, scheme string) { b.AddTx(tx) }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2959,7 +2965,7 @@ func testDeleteRecreateSlots(t *testing.T, scheme string) { // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ Tracer: logger.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3041,7 +3047,7 @@ func testDeleteRecreateAccount(t *testing.T, scheme string) { // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ Tracer: logger.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3217,7 +3223,7 @@ func testDeleteRecreateSlotsAcrossManyBlocks(t *testing.T, scheme string) { chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3355,7 +3361,7 @@ func testInitThenFailCreateContract(t *testing.T, scheme string) { chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3442,7 +3448,7 @@ func testEIP2718Transition(t *testing.T, scheme string) { }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3536,7 +3542,7 @@ func testEIP1559Transition(t *testing.T, scheme string) { b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3649,7 +3655,7 @@ func testSetCanonical(t *testing.T, scheme string) { diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) defer diskdb.Close() - chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3758,7 +3764,7 @@ func testCanonicalHashMarker(t *testing.T, scheme string) { _, forkB, _ := GenerateChainWithGenesis(gspec, engine, c.forkB, func(i int, gen *BlockGen) {}) // Initialize test chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3895,7 +3901,7 @@ func testCreateThenDelete(t *testing.T, config *params.ChainConfig) { chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: logger.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -4007,7 +4013,7 @@ func TestDeleteThenCreate(t *testing.T) { } }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -4092,7 +4098,7 @@ func TestTransientStorageReset(t *testing.T) { }) // Initialize the blockchain with 1153 enabled. - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vmConfig, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vmConfig, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -4187,7 +4193,7 @@ func TestEIP3651(t *testing.T) { b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 6241f3fb6960..61d09117bddc 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -123,7 +123,7 @@ func TestGeneratePOSChain(t *testing.T) { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(genchain); err != nil { @@ -238,7 +238,7 @@ func ExampleGenerateChain() { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index b9a899ef2f92..5da9e91b036c 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -50,7 +50,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), Config: &proConf, } - proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer proBc.Stop() conDb := rawdb.NewMemoryDatabase() @@ -62,7 +62,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), Config: &conConf, } - conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer conBc.Stop() if _, err := proBc.InsertChain(prefix); err != nil { @@ -74,7 +74,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { // Create a pro-fork block, and try to feed into the no-fork chain - bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil) blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { @@ -97,7 +97,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err) } // Create a no-fork block, and try to feed into the pro-fork chain - bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil) blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { @@ -121,7 +121,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { } } // Verify that contra-forkers accept pro-fork extra-datas after forking finishes - bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) @@ -139,7 +139,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err) } // Verify that pro-forkers accept contra-fork extra-datas after forking finishes - bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) diff --git a/core/forkchoice.go b/core/forkchoice.go deleted file mode 100644 index b293c851bf27..000000000000 --- a/core/forkchoice.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2021 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 core - -import ( - crand "crypto/rand" - "errors" - "math/big" - mrand "math/rand" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" -) - -// ChainReader defines a small collection of methods needed to access the local -// blockchain during header verification. It's implemented by both blockchain -// and lightchain. -type ChainReader interface { - // Config retrieves the header chain's chain configuration. - Config() *params.ChainConfig - - // GetTd returns the total difficulty of a local block. - GetTd(common.Hash, uint64) *big.Int -} - -// ForkChoice is the fork chooser based on the highest total difficulty of the -// chain(the fork choice used in the eth1) and the external fork choice (the fork -// choice used in the eth2). This main goal of this ForkChoice is not only for -// offering fork choice during the eth1/2 merge phase, but also keep the compatibility -// for all other proof-of-work networks. -type ForkChoice struct { - chain ChainReader - rand *mrand.Rand - - // preserve is a helper function used in td fork choice. - // Miners will prefer to choose the local mined block if the - // local td is equal to the extern one. It can be nil for light - // client - preserve func(header *types.Header) bool -} - -func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) bool) *ForkChoice { - // Seed a fast but crypto originating random generator - seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) - if err != nil { - log.Crit("Failed to initialize random seed", "err", err) - } - return &ForkChoice{ - chain: chainReader, - rand: mrand.New(mrand.NewSource(seed.Int64())), - preserve: preserve, - } -} - -// ReorgNeeded returns whether the reorg should be applied -// based on the given external header and local canonical chain. -// In the td mode, the new head is chosen if the corresponding -// total difficulty is higher. In the extern mode, the trusted -// header is always selected as the head. -func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (bool, error) { - var ( - localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64()) - externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64()) - ) - if localTD == nil || externTd == nil { - return false, errors.New("missing td") - } - // Accept the new header as the chain head if the transition - // is already triggered. We assume all the headers after the - // transition come from the trusted consensus layer. - if ttd := f.chain.Config().TerminalTotalDifficulty; ttd != nil && ttd.Cmp(externTd) <= 0 { - return true, nil - } - - // If the total difficulty is higher than our known, add it to the canonical chain - if diff := externTd.Cmp(localTD); diff > 0 { - return true, nil - } else if diff < 0 { - return false, nil - } - // Local and external difficulty is identical. - // Second clause in the if statement reduces the vulnerability to selfish mining. - // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf - reorg := false - externNum, localNum := extern.Number.Uint64(), current.Number.Uint64() - if externNum < localNum { - reorg = true - } else if externNum == localNum { - var currentPreserve, externPreserve bool - if f.preserve != nil { - currentPreserve, externPreserve = f.preserve(current), f.preserve(extern) - } - reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5) - } - return reorg, nil -} diff --git a/core/genesis_test.go b/core/genesis_test.go index fde458c4c837..0fee8741386a 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -124,7 +124,7 @@ func testSetupGenesis(t *testing.T, scheme string) { tdb := triedb.NewDatabase(db, newDbConfig(scheme)) oldcustomg.Commit(db, tdb) - bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil) defer bc.Stop() _, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil) diff --git a/core/headerchain.go b/core/headerchain.go index 9ce8d11c40a4..c587a83fa6f7 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -254,7 +254,7 @@ func (hc *HeaderChain) WriteHeaders(headers []*types.Header) (int, error) { // without the real blocks. Hence, writing headers directly should only be done // in two scenarios: pure-header mode of operation (light clients), or properly // separated header/block phases (non-archive clients). -func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *ForkChoice) (*headerWriteResult, error) { +func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header) (*headerWriteResult, error) { inserted, err := hc.WriteHeaders(headers) if err != nil { return nil, err @@ -270,15 +270,6 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F lastHeader: lastHeader, } ) - // Ask the fork choicer if the reorg is necessary - if reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader); err != nil { - return nil, err - } else if !reorg { - if inserted != 0 { - result.status = SideStatTy - } - return result, nil - } // Special case, all the inserted headers are already on the canonical // header chain, skip the reorg operation. if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() { @@ -336,11 +327,11 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header) (int, error) { // // The returned 'write status' says if the inserted headers are part of the canonical chain // or a side chain. -func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, start time.Time, forker *ForkChoice) (WriteStatus, error) { +func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, start time.Time) (WriteStatus, error) { if hc.procInterrupt() { return 0, errors.New("aborted") } - res, err := hc.writeHeadersAndSetHead(chain, forker) + res, err := hc.writeHeadersAndSetHead(chain) if err != nil { return 0, err } diff --git a/core/headerchain_test.go b/core/headerchain_test.go index 25d9bfffcb0b..3228d82f0f3d 100644 --- a/core/headerchain_test.go +++ b/core/headerchain_test.go @@ -51,10 +51,10 @@ func verifyUnbrokenCanonchain(hc *HeaderChain) error { return nil } -func testInsert(t *testing.T, hc *HeaderChain, chain []*types.Header, wantStatus WriteStatus, wantErr error, forker *ForkChoice) { +func testInsert(t *testing.T, hc *HeaderChain, chain []*types.Header, wantStatus WriteStatus, wantErr error) { t.Helper() - status, err := hc.InsertHeaderChain(chain, time.Now(), forker) + status, err := hc.InsertHeaderChain(chain, time.Now()) if status != wantStatus { t.Errorf("wrong write status from InsertHeaderChain: got %v, want %v", status, wantStatus) } @@ -83,34 +83,33 @@ func TestHeaderInsertion(t *testing.T) { // chain B: G->A1->B1...B128 chainB := makeHeaderChain(gspec.Config, chainA[0], 128, ethash.NewFaker(), genDb, 10) - forker := NewForkChoice(hc, nil) // Inserting 64 headers on an empty chain, expecting // 1 callbacks, 1 canon-status, 0 sidestatus, - testInsert(t, hc, chainA[:64], CanonStatTy, nil, forker) + testInsert(t, hc, chainA[:64], CanonStatTy, nil) // Inserting 64 identical headers, expecting // 0 callbacks, 0 canon-status, 0 sidestatus, - testInsert(t, hc, chainA[:64], NonStatTy, nil, forker) + testInsert(t, hc, chainA[:64], NonStatTy, nil) // Inserting the same some old, some new headers // 1 callbacks, 1 canon, 0 side - testInsert(t, hc, chainA[32:96], CanonStatTy, nil, forker) + testInsert(t, hc, chainA[32:96], CanonStatTy, nil) - // Inserting side blocks, but not overtaking the canon chain - testInsert(t, hc, chainB[0:32], SideStatTy, nil, forker) + // Inserting headers from chain B, overtaking the canon chain blindly + testInsert(t, hc, chainB[0:32], CanonStatTy, nil) - // Inserting more side blocks, but we don't have the parent - testInsert(t, hc, chainB[34:36], NonStatTy, consensus.ErrUnknownAncestor, forker) + // Inserting more headers on chain B, but we don't have the parent + testInsert(t, hc, chainB[34:36], NonStatTy, consensus.ErrUnknownAncestor) - // Inserting more sideblocks, overtaking the canon chain - testInsert(t, hc, chainB[32:97], CanonStatTy, nil, forker) + // Inserting more headers on chain B, extend the canon chain + testInsert(t, hc, chainB[32:97], CanonStatTy, nil) - // Inserting more A-headers, taking back the canonicality - testInsert(t, hc, chainA[90:100], CanonStatTy, nil, forker) + // Inserting more headers on chain A, taking back the canonicality + testInsert(t, hc, chainA[90:100], CanonStatTy, nil) // And B becomes canon again - testInsert(t, hc, chainB[97:107], CanonStatTy, nil, forker) + testInsert(t, hc, chainB[97:107], CanonStatTy, nil) // And B becomes even longer - testInsert(t, hc, chainB[107:128], CanonStatTy, nil, forker) + testInsert(t, hc, chainB[107:128], CanonStatTy, nil) } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 4149cd2df3b9..3ed0eb75799c 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -133,7 +133,7 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil) tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} ) @@ -293,7 +293,7 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) ) defer blockchain.Stop() for i, tt := range []struct { @@ -332,7 +332,7 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil) ) defer blockchain.Stop() for i, tt := range []struct { @@ -481,7 +481,7 @@ func TestProcessVerkle(t *testing.T) { // genesis := gspec.MustCommit(bcdb, triedb) cacheConfig := DefaultCacheConfigWithScheme("path") cacheConfig.SnapshotLimit = 0 - blockchain, _ := NewBlockChain(bcdb, cacheConfig, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(bcdb, cacheConfig, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil) defer blockchain.Stop() txCost1 := params.TxGas diff --git a/eth/backend.go b/eth/backend.go index 51011ed0b228..f7b67be4dc7c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -216,11 +216,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.OverrideVerkle != nil { overrides.OverrideVerkle = config.OverrideVerkle } - // TODO (MariusVanDerWijden) get rid of shouldPreserve in a follow-up PR - shouldPreserve := func(header *types.Header) bool { - return false - } - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, shouldPreserve, &config.TransactionHistory) + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, &config.TransactionHistory) if err != nil { return nil, err } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index c440b40e9dc7..0f81e152ef4d 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -68,7 +68,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { Alloc: types.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - chain, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) if err != nil { panic(err) } diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 6043f5137231..8fa2e8341339 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -217,7 +217,7 @@ func newTestBlockchain(blocks []*types.Block) *core.BlockChain { if pregenerated { panic("Requested chain generation outside of init") } - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, testGspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, testGspec, nil, ethash.NewFaker(), vm.Config{}, nil) if err != nil { panic(err) } diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 2b3efb51b17f..d8b703fee4e9 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -250,7 +250,7 @@ func TestFilters(t *testing.T) { } }) var l uint64 - bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) + bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, &l) if err != nil { t.Fatal(err) } diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 39f3c79b98e4..fdba2e584b42 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -210,7 +210,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe }) // Construct testing chain gspec.Config.TerminalTotalDifficulty = new(big.Int).SetUint64(td) - chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("Failed to create local chain, %v", err) } diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index a38059ca953e..c41c9abc267f 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -98,8 +98,8 @@ func testForkIDSplit(t *testing.T, protocol uint) { gspecNoFork = &core.Genesis{Config: configNoFork} gspecProFork = &core.Genesis{Config: configProFork} - chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, gspecNoFork, nil, engine, vm.Config{}, nil, nil) - chainProFork, _ = core.NewBlockChain(dbProFork, nil, gspecProFork, nil, engine, vm.Config{}, nil, nil) + chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, gspecNoFork, nil, engine, vm.Config{}, nil) + chainProFork, _ = core.NewBlockChain(dbProFork, nil, gspecProFork, nil, engine, vm.Config{}, nil) _, blocksNoFork, _ = core.GenerateChainWithGenesis(gspecNoFork, engine, 2, nil) _, blocksProFork, _ = core.GenerateChainWithGenesis(gspecProFork, engine, 2, nil) diff --git a/eth/handler_test.go b/eth/handler_test.go index bcc8ea30e415..7b250df2e915 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -151,7 +151,7 @@ func newTestHandlerWithBlocks(blocks int) *testHandler { Config: params.TestChainConfig, Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}}, } - chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) _, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, nil) if _, err := chain.InsertChain(bs); err != nil { diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 934dadc9a5b3..fc82b42947f3 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -104,7 +104,7 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, Config: config, Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, } - chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil) _, bs, _ := core.GenerateChainWithGenesis(gspec, engine, blocks, generator) if _, err := chain.InsertChain(bs); err != nil { diff --git a/eth/protocols/snap/handler_fuzzing_test.go b/eth/protocols/snap/handler_fuzzing_test.go index 4e234ad21b4b..777db6387c90 100644 --- a/eth/protocols/snap/handler_fuzzing_test.go +++ b/eth/protocols/snap/handler_fuzzing_test.go @@ -126,7 +126,7 @@ func getChain() *core.BlockChain { SnapshotWait: true, } trieRoot = blocks[len(blocks)-1].Root() - bc, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), cacheConf, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), cacheConf, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) if _, err := bc.InsertChain(blocks); err != nil { panic(err) } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index e717f5352d7e..47e36934953b 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -81,7 +81,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i SnapshotLimit: 0, TrieDirtyDisabled: true, // Archive mode } - chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1014,7 +1014,7 @@ func newTestMergedBackend(t *testing.T, n int, gspec *core.Genesis, generator fu SnapshotLimit: 0, TrieDirtyDisabled: true, // Archive mode } - chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index d608b1e002af..5c11b5e47296 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -557,7 +557,7 @@ func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockG return nil, nil, fmt.Errorf("failed to create call tracer: %v", err) } - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), core.DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, engine, vm.Config{Tracer: tracer}, nil, nil) + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), core.DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, engine, vm.Config{Tracer: tracer}, nil) if err != nil { return nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 7465fb55295f..3c5da840d30a 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -449,7 +449,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.E // Generate blocks for testing db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator) txlookupLimit := uint64(0) - chain, err := core.NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, &txlookupLimit) + chain, err := core.NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, &txlookupLimit) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/miner/miner_test.go b/miner/miner_test.go index da133ad8d0b6..779626c0452b 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -152,7 +152,7 @@ func createMiner(t *testing.T) *Miner { // Create consensus engine engine := clique.New(chainConfig.Clique, chainDB) // Create Ethereum backend - bc, err := core.NewBlockChain(chainDB, nil, genesis, nil, engine, vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(chainDB, nil, genesis, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("can't create new chain %v", err) } diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index ac9b2ab704ba..7a235d88e11e 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -121,7 +121,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine default: t.Fatalf("unexpected consensus engine type: %T", engine) } - chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil) if err != nil { t.Fatalf("core.NewBlockChain failed: %v", err) } diff --git a/tests/block_test.go b/tests/block_test.go index 52184eb27432..4bbd2571d73b 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -49,6 +49,17 @@ func TestBlockchain(t *testing.T) { // using 4.6 TGas bt.skipLoad(`.*randomStatetest94.json.*`) + // After the merge we would accept side chains as canonical even if they have lower td + bt.skipLoad(`.*bcMultiChainTest/ChainAtoChainB_difficultyB.json`) + bt.skipLoad(`.*bcMultiChainTest/CallContractFromNotBestBlock.json`) + bt.skipLoad(`.*bcTotalDifficultyTest/uncleBlockAtBlock3afterBlock4.json`) + bt.skipLoad(`.*bcTotalDifficultyTest/lotsOfBranchesOverrideAtTheMiddle.json`) + bt.skipLoad(`.*bcTotalDifficultyTest/sideChainWithMoreTransactions.json`) + bt.skipLoad(`.*bcForkStressTest/ForkStressTest.json`) + bt.skipLoad(`.*bcMultiChainTest/lotsOfLeafs.json`) + bt.skipLoad(`.*bcFrontierToHomestead/blockChainFrontierWithLargerTDvsHomesteadBlockchain.json`) + bt.skipLoad(`.*bcFrontierToHomestead/blockChainFrontierWithLargerTDvsHomesteadBlockchain2.json`) + bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { execBlockTest(t, bt, test) }) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 62aa582c828e..b3957601bb83 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -153,7 +153,7 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t chain, err := core.NewBlockChain(db, cache, gspec, nil, engine, vm.Config{ Tracer: tracer, EnableWitnessCollection: witness, - }, nil, nil) + }, nil) if err != nil { return err } From fdb84993d8e4b12df695400815f63fc62c63358c Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 4 Sep 2024 15:13:20 +0200 Subject: [PATCH 513/571] core: fix compilation error (#30394) un-borks a compilation error from a recent merge to master --- core/blockchain_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 40f00982f227..fe0c527a0091 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4277,7 +4277,7 @@ func TestEIP6110(t *testing.T) { b.AddTx(tx) } }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{DisableStack: true}, os.Stderr).Hooks()}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{DisableStack: true}, os.Stderr).Hooks()}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } From 7ef49e350b53734d89c03c6dc582bd38a836f973 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:19:18 +0200 Subject: [PATCH 514/571] all: remove funding verifier (#30391) Now that verification is done, we can remove the funding information. --- funding.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 funding.json diff --git a/funding.json b/funding.json deleted file mode 100644 index 72a29e795fb9..000000000000 --- a/funding.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "opRetro": { - "projectId": "0x79c2ae8858a5a3bd7f2e0da9509d727833ffa01f358b5969355f38ff32b20122" - } -} From c3f13b2a1c9a22926e5f5535178ecbd2796c4e32 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 4 Sep 2024 16:15:41 +0200 Subject: [PATCH 515/571] node: fix flaky jwt-test (#30388) This PR fixes a flaky jwt-test. The test is a jwt "from one second in the future". The test passes; the reason for this is that the CI-system is slow, and by the time the jwt is actually evaluated, that second has passed, and it's no longer future. Alternative to #30380 --- node/rpcstack_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index e41cc51ad318..c6f598b7742e 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -383,7 +383,7 @@ func TestJWT(t *testing.T) { expFail := []func() string{ // future func() string { - return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + int64(jwtExpiryTimeout.Seconds()) + 1})) + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + int64(jwtExpiryTimeout.Seconds()) + 60})) }, // stale func() string { From 23973bd3a0291d1a288dc3b2c8325dd6d37fe6f5 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 5 Sep 2024 10:50:34 +0200 Subject: [PATCH 516/571] build: increase go test timeout (#30398) This increases the timeout for the go tests on ci, this should prevent travis from erroring. see: https://app.travis-ci.com/github/ethereum/go-ethereum/jobs/625803693 --- build/ci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ci.go b/build/ci.go index bdc89082e744..2932d2c9ce57 100644 --- a/build/ci.go +++ b/build/ci.go @@ -304,7 +304,7 @@ func doTest(cmdline []string) { gotest := tc.Go("test") // CI needs a bit more time for the statetests (default 10m). - gotest.Args = append(gotest.Args, "-timeout=20m") + gotest.Args = append(gotest.Args, "-timeout=30m") // Enable CKZG backend in CI. gotest.Args = append(gotest.Args, "-tags=ckzg") From 623b17ba20daea8cfd2530dd906fda0193b79579 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 5 Sep 2024 18:10:47 +0800 Subject: [PATCH 517/571] core/state: state reader abstraction (#29761) This pull request introduces a state.Reader interface for state accessing. The interface could be implemented in various ways. It can be pure trie only reader, or the combination of trie and state snapshot. What's more, this interface allows us to have more flexibility in the future, e.g. the archive reader (for accessing archive state). Additionally, this pull request removes the following metrics - `chain/snapshot/account/reads` - `chain/snapshot/storage/reads` --- cmd/evm/internal/t8ntool/execution.go | 9 +- cmd/evm/runner.go | 6 +- cmd/evm/staterunner.go | 2 +- cmd/geth/chaincmd.go | 2 +- core/blockchain.go | 48 ++-- core/blockchain_reader.go | 11 +- core/blockchain_sethead_test.go | 2 +- core/blockchain_test.go | 2 +- core/chain_makers.go | 4 +- core/genesis.go | 10 +- core/state/database.go | 132 +++++---- core/state/iterator_test.go | 2 +- core/state/reader.go | 313 +++++++++++++++++++++ core/state/state_object.go | 49 +--- core/state/state_test.go | 27 +- core/state/statedb.go | 179 +++++------- core/state/statedb_fuzz_test.go | 3 +- core/state/statedb_test.go | 98 ++++--- core/state/sync_test.go | 8 +- core/state/trie_prefetcher_test.go | 13 +- core/state_processor_test.go | 5 +- core/stateless.go | 3 +- core/txpool/blobpool/blobpool_test.go | 14 +- core/txpool/legacypool/legacypool2_test.go | 9 +- core/txpool/legacypool/legacypool_test.go | 41 ++- core/vm/gas_table_test.go | 5 +- core/vm/instructions_test.go | 3 +- core/vm/interpreter_test.go | 3 +- core/vm/runtime/runtime.go | 5 +- core/vm/runtime/runtime_test.go | 15 +- eth/api_debug_test.go | 21 +- eth/state_accessor.go | 13 +- miner/miner_test.go | 2 +- tests/state_test_util.go | 9 +- triedb/database.go | 7 + 35 files changed, 661 insertions(+), 414 deletions(-) create mode 100644 core/state/reader.go diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index a0805722d669..5fd1d6a4a6ad 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -403,7 +403,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } // Re-create statedb instance with new root upon the updated database // for accessing latest states. - statedb, err = state.New(root, statedb.Database(), nil) + statedb, err = state.New(root, statedb.Database()) if err != nil { return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err)) } @@ -412,8 +412,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB { - sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true}) - statedb, _ := state.New(types.EmptyRootHash, sdb, nil) + tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true}) + sdb := state.NewDatabase(tdb, nil) + statedb, _ := state.New(types.EmptyRootHash, sdb) for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) @@ -424,7 +425,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB } // Commit and re-open to start with a clean state. root, _ := statedb.Commit(0, false) - statedb, _ = state.New(root, sdb, nil) + statedb, _ = state.New(root, sdb) return statedb } diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index c02f9f059085..235fed66302a 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -155,8 +155,8 @@ func runCmd(ctx *cli.Context) error { }) defer triedb.Close() genesis := genesisConfig.MustCommit(db, triedb) - sdb := state.NewDatabaseWithNodeDB(db, triedb) - statedb, _ = state.New(genesis.Root(), sdb, nil) + sdb := state.NewDatabase(triedb, nil) + statedb, _ = state.New(genesis.Root(), sdb) chainConfig = genesisConfig.Config if ctx.String(SenderFlag.Name) != "" { @@ -277,7 +277,7 @@ func runCmd(ctx *cli.Context) error { fmt.Printf("Failed to commit changes %v\n", err) return err } - dumpdb, err := state.New(root, sdb, nil) + dumpdb, err := state.New(root, sdb) if err != nil { fmt.Printf("Failed to open statedb %v\n", err) return err diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index fc2bf8223f30..4514367e8a45 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -107,7 +107,7 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error { result.Root = &root fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) if dump { // Dump any state to aid debugging - cpy, _ := state.New(root, tstate.StateDB.Database(), nil) + cpy, _ := state.New(root, tstate.StateDB.Database()) dump := cpy.RawDump(nil) result.State = &dump } diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index ca2f00512b34..018bca4a0f6f 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -584,7 +584,7 @@ func dump(ctx *cli.Context) error { triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup defer triedb.Close() - state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil) + state, err := state.New(root, state.NewDatabase(triedb, nil)) if err != nil { return err } diff --git a/core/blockchain.go b/core/blockchain.go index b0c8da98ffb1..5d1cf533fc13 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -72,14 +72,11 @@ var ( storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil) storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil) - snapshotAccountReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/account/reads", nil) - snapshotStorageReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/storage/reads", nil) - snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil) - accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil) storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil) - triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil) + snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil) + triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil) blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil) blockValidationTimer = metrics.NewRegisteredResettingTimer("chain/validation", nil) @@ -220,7 +217,7 @@ type BlockChain struct { lastWrite uint64 // Last block when the state was flushed flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state triedb *triedb.Database // The database handler for maintaining trie nodes. - stateCache state.Database // State database to reuse between imports (contains state cache) + statedb *state.CachingDB // State database to reuse between imports (contains state cache) txIndexer *txIndexer // Transaction indexer, might be nil if not enabled hc *HeaderChain @@ -311,7 +308,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis return nil, err } bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) - bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) + bc.statedb = state.NewDatabase(bc.triedb, nil) bc.validator = NewBlockValidator(chainConfig, bc) bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc) bc.processor = NewStateProcessor(chainConfig, bc.hc) @@ -449,7 +446,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis AsyncBuild: !bc.cacheConfig.SnapshotWait, } bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root) + + // Re-initialize the state database with snapshot + bc.statedb = state.NewDatabase(bc.triedb, bc.snaps) } + // Rewind the chain in case of an incompatible config upgrade. if compat, ok := genesisErr.(*params.ConfigCompatError); ok { log.Warn("Rewinding chain to upgrade configuration", "err", compat) @@ -1767,7 +1768,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if parent == nil { parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1) } - statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps) + statedb, err := state.New(parent.Root, bc.statedb) if err != nil { return it.index, err } @@ -1793,7 +1794,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) var followupInterrupt atomic.Bool if !bc.cacheConfig.TrieCleanNoPrefetch { if followup, err := it.peek(); followup != nil && err == nil { - throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) + throwaway, _ := state.New(parent.Root, bc.statedb) go func(start time.Time, followup *types.Block, throwaway *state.StateDB) { // Disable tracing for prefetcher executions. @@ -1914,26 +1915,21 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s proctime := time.Since(start) // processing + validation // Update the metrics touched during block processing and validation - accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) - storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) - snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) - snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) - - accountRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read - storageRead := statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read + accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) + storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) if statedb.AccountLoaded != 0 { - accountReadSingleTimer.Update(accountRead / time.Duration(statedb.AccountLoaded)) + accountReadSingleTimer.Update(statedb.AccountReads / time.Duration(statedb.AccountLoaded)) } if statedb.StorageLoaded != 0 { - storageReadSingleTimer.Update(storageRead / time.Duration(statedb.StorageLoaded)) - } - accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) - storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) - accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) - triehash := statedb.AccountHashes // The time spent on tries hashing - trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update - blockExecutionTimer.Update(ptime - (accountRead + storageRead)) // The time spent on EVM processing - blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation + storageReadSingleTimer.Update(statedb.StorageReads / time.Duration(statedb.StorageLoaded)) + } + accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) + storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) + accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) + triehash := statedb.AccountHashes // The time spent on tries hashing + trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update + blockExecutionTimer.Update(ptime - (statedb.AccountReads + statedb.StorageReads)) // The time spent on EVM processing + blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation // Write the block to the chain and get the status. var ( diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 8a85800dd877..6b8dffdcdc63 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -308,7 +308,7 @@ func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int { // HasState checks if state trie is fully present in the database or not. func (bc *BlockChain) HasState(hash common.Hash) bool { - _, err := bc.stateCache.OpenTrie(hash) + _, err := bc.statedb.OpenTrie(hash) return err == nil } @@ -341,12 +341,9 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool { // If the code doesn't exist in the in-memory cache, check the storage with // new code scheme. func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) { - type codeReader interface { - ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) - } // TODO(rjl493456442) The associated account address is also required // in Verkle scheme. Fix it once snap-sync is supported for Verkle. - return bc.stateCache.(codeReader).ContractCodeWithPrefix(common.Address{}, hash) + return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash) } // State returns a new mutable state based on the current HEAD block. @@ -356,7 +353,7 @@ func (bc *BlockChain) State() (*state.StateDB, error) { // StateAt returns a new mutable state based on a particular point in time. func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) { - return state.New(root, bc.stateCache, bc.snaps) + return state.New(root, bc.statedb) } // Config retrieves the chain's fork configuration. @@ -382,7 +379,7 @@ func (bc *BlockChain) Processor() Processor { // StateCache returns the caching database underpinning the blockchain instance. func (bc *BlockChain) StateCache() state.Database { - return bc.stateCache + return bc.statedb } // GasLimit returns the gas limit of the current HEAD block. diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index b06ed83616b8..5a62d6b25f3f 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -2040,7 +2040,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme dbconfig.HashDB = hashdb.Defaults } chain.triedb = triedb.NewDatabase(chain.db, dbconfig) - chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb) + chain.statedb = state.NewDatabase(chain.triedb, chain.snaps) // Force run a freeze cycle type freezer interface { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index fe0c527a0091..d8c436fcd65c 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -160,7 +160,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { } return err } - statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.stateCache, nil) + statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.statedb) if err != nil { return err } diff --git a/core/chain_makers.go b/core/chain_makers.go index dcaa36e08ccc..8e75abdea0ad 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -379,7 +379,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse defer triedb.Close() for i := 0; i < n; i++ { - statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil) + statedb, err := state.New(parent.Root(), state.NewDatabase(triedb, nil)) if err != nil { panic(err) } @@ -485,7 +485,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine } for i := 0; i < n; i++ { - statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, trdb), nil) + statedb, err := state.New(parent.Root(), state.NewDatabase(trdb, nil)) if err != nil { panic(err) } diff --git a/core/genesis.go b/core/genesis.go index 67f5d56cfe80..8ea9bfb30ff8 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -127,8 +127,8 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { } // Create an ephemeral in-memory database for computing hash, // all the derived states will be discarded to not pollute disk. - db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config) - statedb, err := state.New(types.EmptyRootHash, db, nil) + db := rawdb.NewMemoryDatabase() + statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb.NewDatabase(db, config), nil)) if err != nil { return common.Hash{}, err } @@ -147,8 +147,8 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { // flushAlloc is very similar with hash, but the main difference is all the // generated states will be persisted into the given database. -func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database) (common.Hash, error) { - statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) +func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) { + statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb, nil)) if err != nil { return common.Hash{}, err } @@ -497,7 +497,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo return nil, errors.New("can't start clique chain without signers") } // flush the data to disk and compute the state root - root, err := flushAlloc(&g.Alloc, db, triedb) + root, err := flushAlloc(&g.Alloc, triedb) if err != nil { return nil, err } diff --git a/core/state/database.go b/core/state/database.go index 38ec4ef8b85f..de61dee036eb 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -45,29 +46,29 @@ const ( // Database wraps access to tries and contract code. type Database interface { + // Reader returns a state reader associated with the specified state root. + Reader(root common.Hash) (Reader, error) + // OpenTrie opens the main account trie. OpenTrie(root common.Hash) (Trie, error) // OpenStorageTrie opens the storage trie of an account. OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error) - // CopyTrie returns an independent copy of the given trie. - CopyTrie(Trie) Trie - // ContractCode retrieves a particular contract's code. ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) // ContractCodeSize retrieves a particular contracts code's size. ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) - // DiskDB returns the underlying key-value disk database. - DiskDB() ethdb.KeyValueStore - // PointCache returns the cache holding points used in verkle tree key computation PointCache() *utils.PointCache // TrieDB returns the underlying trie database for managing trie nodes. TrieDB() *triedb.Database + + // Snapshot returns the underlying state snapshot. + Snapshot() *snapshot.Tree } // Trie is a Ethereum Merkle Patricia trie. @@ -147,47 +148,62 @@ type Trie interface { IsVerkle() bool } -// NewDatabase creates a backing store for state. The returned database is safe for -// concurrent use, but does not retain any recent trie nodes in memory. To keep some -// historical state in memory, use the NewDatabaseWithConfig constructor. -func NewDatabase(db ethdb.Database) Database { - return NewDatabaseWithConfig(db, nil) +// CachingDB is an implementation of Database interface. It leverages both trie and +// state snapshot to provide functionalities for state access. It's meant to be a +// long-live object and has a few caches inside for sharing between blocks. +type CachingDB struct { + disk ethdb.KeyValueStore + triedb *triedb.Database + snap *snapshot.Tree + codeCache *lru.SizeConstrainedCache[common.Hash, []byte] + codeSizeCache *lru.Cache[common.Hash, int] + pointCache *utils.PointCache } -// NewDatabaseWithConfig creates a backing store for state. The returned database -// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a -// large memory cache. -func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database { - return &cachingDB{ - disk: db, - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), +// NewDatabase creates a state database with the provided data sources. +func NewDatabase(triedb *triedb.Database, snap *snapshot.Tree) *CachingDB { + return &CachingDB{ + disk: triedb.Disk(), + triedb: triedb, + snap: snap, codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: triedb.NewDatabase(db, config), + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), pointCache: utils.NewPointCache(pointCacheSize), } } -// NewDatabaseWithNodeDB creates a state database with an already initialized node database. -func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database { - return &cachingDB{ - disk: db, - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: triedb, - pointCache: utils.NewPointCache(pointCacheSize), - } +// NewDatabaseForTesting is similar to NewDatabase, but it initializes the caching +// db by using an ephemeral memory db with default config for testing. +func NewDatabaseForTesting() *CachingDB { + return NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) } -type cachingDB struct { - disk ethdb.KeyValueStore - codeSizeCache *lru.Cache[common.Hash, int] - codeCache *lru.SizeConstrainedCache[common.Hash, []byte] - triedb *triedb.Database - pointCache *utils.PointCache +// Reader returns a state reader associated with the specified state root. +func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) { + var readers []Reader + + // Set up the state snapshot reader if available. This feature + // is optional and may be partially useful if it's not fully + // generated. + if db.snap != nil { + sr, err := newStateReader(stateRoot, db.snap) + if err == nil { + readers = append(readers, sr) // snap reader is optional + } + } + // Set up the trie reader, which is expected to always be available + // as the gatekeeper unless the state is corrupted. + tr, err := newTrieReader(stateRoot, db.triedb, db.pointCache) + if err != nil { + return nil, err + } + readers = append(readers, tr) + + return newMultiReader(readers...) } // OpenTrie opens the main account trie at a specific root hash. -func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { +func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) { if db.triedb.IsVerkle() { return trie.NewVerkleTrie(root, db.triedb, db.pointCache) } @@ -199,7 +215,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { } // OpenStorageTrie opens the storage trie of an account. -func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { +func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { // In the verkle case, there is only one tree. But the two-tree structure // is hardcoded in the codebase. So we need to return the same trie in this // case. @@ -213,20 +229,8 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre return tr, nil } -// CopyTrie returns an independent copy of the given trie. -func (db *cachingDB) CopyTrie(t Trie) Trie { - switch t := t.(type) { - case *trie.StateTrie: - return t.Copy() - case *trie.VerkleTrie: - return t.Copy() - default: - panic(fmt.Errorf("unknown trie type %T", t)) - } -} - // ContractCode retrieves a particular contract's code. -func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) { +func (db *CachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) { code, _ := db.codeCache.Get(codeHash) if len(code) > 0 { return code, nil @@ -243,7 +247,7 @@ func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) // ContractCodeWithPrefix retrieves a particular contract's code. If the // code can't be found in the cache, then check the existence with **new** // db scheme. -func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) { +func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) { code, _ := db.codeCache.Get(codeHash) if len(code) > 0 { return code, nil @@ -258,7 +262,7 @@ func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash com } // ContractCodeSize retrieves a particular contracts code's size. -func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { +func (db *CachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { if cached, ok := db.codeSizeCache.Get(codeHash); ok { return cached, nil } @@ -266,17 +270,29 @@ func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) return len(code), err } -// DiskDB returns the underlying key-value disk database. -func (db *cachingDB) DiskDB() ethdb.KeyValueStore { - return db.disk -} - // TrieDB retrieves any intermediate trie-node caching layer. -func (db *cachingDB) TrieDB() *triedb.Database { +func (db *CachingDB) TrieDB() *triedb.Database { return db.triedb } // PointCache returns the cache of evaluated curve points. -func (db *cachingDB) PointCache() *utils.PointCache { +func (db *CachingDB) PointCache() *utils.PointCache { return db.pointCache } + +// Snapshot returns the underlying state snapshot. +func (db *CachingDB) Snapshot() *snapshot.Tree { + return db.snap +} + +// mustCopyTrie returns a deep-copied trie. +func mustCopyTrie(t Trie) Trie { + switch t := t.(type) { + case *trie.StateTrie: + return t.Copy() + case *trie.VerkleTrie: + return t.Copy() + default: + panic(fmt.Errorf("unknown trie type %T", t)) + } +} diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index 73cc22490b6e..26456d7a8934 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -35,7 +35,7 @@ func testNodeIteratorCoverage(t *testing.T, scheme string) { db, sdb, ndb, root, _ := makeTestState(scheme) ndb.Commit(root, false) - state, err := New(root, sdb, nil) + state, err := New(root, sdb) if err != nil { t.Fatalf("failed to create state trie at %x: %v", root, err) } diff --git a/core/state/reader.go b/core/state/reader.go new file mode 100644 index 000000000000..6bddefc2a7dd --- /dev/null +++ b/core/state/reader.go @@ -0,0 +1,313 @@ +// Copyright 2024 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 ( + "errors" + "maps" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/utils" + "github.com/ethereum/go-ethereum/triedb" +) + +// Reader defines the interface for accessing accounts and storage slots +// associated with a specific state. +type Reader interface { + // Account retrieves the account associated with a particular address. + // + // - Returns a nil account if it does not exist + // - Returns an error only if an unexpected issue occurs + // - The returned account is safe to modify after the call + Account(addr common.Address) (*types.StateAccount, error) + + // Storage retrieves the storage slot associated with a particular account + // address and slot key. + // + // - Returns an empty slot if it does not exist + // - Returns an error only if an unexpected issue occurs + // - The returned storage slot is safe to modify after the call + Storage(addr common.Address, slot common.Hash) (common.Hash, error) + + // Copy returns a deep-copied state reader. + Copy() Reader +} + +// stateReader is a wrapper over the state snapshot and implements the Reader +// interface. It provides an efficient way to access flat state. +type stateReader struct { + snap snapshot.Snapshot + buff crypto.KeccakState +} + +// newStateReader constructs a flat state reader with on the specified state root. +func newStateReader(root common.Hash, snaps *snapshot.Tree) (*stateReader, error) { + snap := snaps.Snapshot(root) + if snap == nil { + return nil, errors.New("snapshot is not available") + } + return &stateReader{ + snap: snap, + buff: crypto.NewKeccakState(), + }, nil +} + +// Account implements Reader, retrieving the account specified by the address. +// +// An error will be returned if the associated snapshot is already stale or +// the requested account is not yet covered by the snapshot. +// +// The returned account might be nil if it's not existent. +func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) { + ret, err := r.snap.Account(crypto.HashData(r.buff, addr.Bytes())) + if err != nil { + return nil, err + } + if ret == nil { + return nil, nil + } + acct := &types.StateAccount{ + Nonce: ret.Nonce, + Balance: ret.Balance, + CodeHash: ret.CodeHash, + Root: common.BytesToHash(ret.Root), + } + if len(acct.CodeHash) == 0 { + acct.CodeHash = types.EmptyCodeHash.Bytes() + } + if acct.Root == (common.Hash{}) { + acct.Root = types.EmptyRootHash + } + return acct, nil +} + +// Storage implements Reader, retrieving the storage slot specified by the +// address and slot key. +// +// An error will be returned if the associated snapshot is already stale or +// the requested storage slot is not yet covered by the snapshot. +// +// The returned storage slot might be empty if it's not existent. +func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { + addrHash := crypto.HashData(r.buff, addr.Bytes()) + slotHash := crypto.HashData(r.buff, key.Bytes()) + ret, err := r.snap.Storage(addrHash, slotHash) + if err != nil { + return common.Hash{}, err + } + if len(ret) == 0 { + return common.Hash{}, nil + } + // Perform the rlp-decode as the slot value is RLP-encoded in the state + // snapshot. + _, content, _, err := rlp.Split(ret) + if err != nil { + return common.Hash{}, err + } + var value common.Hash + value.SetBytes(content) + return value, nil +} + +// Copy implements Reader, returning a deep-copied snap reader. +func (r *stateReader) Copy() Reader { + return &stateReader{ + snap: r.snap, + buff: crypto.NewKeccakState(), + } +} + +// trieReader implements the Reader interface, providing functions to access +// state from the referenced trie. +type trieReader struct { + root common.Hash // State root which uniquely represent a state + db *triedb.Database // Database for loading trie + buff crypto.KeccakState // Buffer for keccak256 hashing + mainTrie Trie // Main trie, resolved in constructor + subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved + subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved +} + +// trieReader constructs a trie reader of the specific state. An error will be +// returned if the associated trie specified by root is not existent. +func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCache) (*trieReader, error) { + var ( + tr Trie + err error + ) + if !db.IsVerkle() { + tr, err = trie.NewStateTrie(trie.StateTrieID(root), db) + } else { + tr, err = trie.NewVerkleTrie(root, db, cache) + } + if err != nil { + return nil, err + } + return &trieReader{ + root: root, + db: db, + buff: crypto.NewKeccakState(), + mainTrie: tr, + subRoots: make(map[common.Address]common.Hash), + subTries: make(map[common.Address]Trie), + }, nil +} + +// Account implements Reader, retrieving the account specified by the address. +// +// An error will be returned if the trie state is corrupted. An nil account +// will be returned if it's not existent in the trie. +func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) { + account, err := r.mainTrie.GetAccount(addr) + if err != nil { + return nil, err + } + if account == nil { + r.subRoots[addr] = types.EmptyRootHash + } else { + r.subRoots[addr] = account.Root + } + return account, nil +} + +// Storage implements Reader, retrieving the storage slot specified by the +// address and slot key. +// +// An error will be returned if the trie state is corrupted. An empty storage +// slot will be returned if it's not existent in the trie. +func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { + var ( + tr Trie + found bool + value common.Hash + ) + if r.db.IsVerkle() { + tr = r.mainTrie + } else { + tr, found = r.subTries[addr] + if !found { + root, ok := r.subRoots[addr] + + // The storage slot is accessed without account caching. It's unexpected + // behavior but try to resolve the account first anyway. + if !ok { + _, err := r.Account(addr) + if err != nil { + return common.Hash{}, err + } + root = r.subRoots[addr] + } + var err error + tr, err = trie.NewStateTrie(trie.StorageTrieID(r.root, crypto.HashData(r.buff, addr.Bytes()), root), r.db) + if err != nil { + return common.Hash{}, err + } + r.subTries[addr] = tr + } + } + ret, err := tr.GetStorage(addr, key.Bytes()) + if err != nil { + return common.Hash{}, err + } + value.SetBytes(ret) + return value, nil +} + +// Copy implements Reader, returning a deep-copied trie reader. +func (r *trieReader) Copy() Reader { + tries := make(map[common.Address]Trie) + for addr, tr := range r.subTries { + tries[addr] = mustCopyTrie(tr) + } + return &trieReader{ + root: r.root, + db: r.db, + buff: crypto.NewKeccakState(), + mainTrie: mustCopyTrie(r.mainTrie), + subRoots: maps.Clone(r.subRoots), + subTries: tries, + } +} + +// multiReader is the aggregation of a list of Reader interface, providing state +// access by leveraging all readers. The checking priority is determined by the +// position in the reader list. +type multiReader struct { + readers []Reader // List of readers, sorted by checking priority +} + +// newMultiReader constructs a multiReader instance with the given readers. The +// priority among readers is assumed to be sorted. Note, it must contain at least +// one reader for constructing a multiReader. +func newMultiReader(readers ...Reader) (*multiReader, error) { + if len(readers) == 0 { + return nil, errors.New("empty reader set") + } + return &multiReader{ + readers: readers, + }, nil +} + +// Account implementing Reader interface, retrieving the account associated with +// a particular address. +// +// - Returns a nil account if it does not exist +// - Returns an error only if an unexpected issue occurs +// - The returned account is safe to modify after the call +func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error) { + var errs []error + for _, reader := range r.readers { + acct, err := reader.Account(addr) + if err == nil { + return acct, nil + } + errs = append(errs, err) + } + return nil, errors.Join(errs...) +} + +// Storage implementing Reader interface, retrieving the storage slot associated +// with a particular account address and slot key. +// +// - Returns an empty slot if it does not exist +// - Returns an error only if an unexpected issue occurs +// - The returned storage slot is safe to modify after the call +func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { + var errs []error + for _, reader := range r.readers { + slot, err := reader.Storage(addr, slot) + if err == nil { + return slot, nil + } + errs = append(errs, err) + } + return common.Hash{}, errors.Join(errs...) +} + +// Copy implementing Reader interface, returning a deep-copied state reader. +func (r *multiReader) Copy() Reader { + var readers []Reader + for _, reader := range r.readers { + readers = append(readers, reader.Copy()) + } + return &multiReader{readers: readers} +} diff --git a/core/state/state_object.go b/core/state/state_object.go index e90d3a5d0562..422badb19bc3 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -187,52 +187,23 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { s.originStorage[key] = common.Hash{} // track the empty slot as origin value return common.Hash{} } - // If no live objects are available, attempt to use snapshots - var ( - enc []byte - err error - value common.Hash - ) - if s.db.snap != nil { - start := time.Now() - enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes())) - s.db.SnapshotStorageReads += time.Since(start) - - if len(enc) > 0 { - _, content, _, err := rlp.Split(enc) - if err != nil { - s.db.setError(err) - } - value.SetBytes(content) - } - } - // If the snapshot is unavailable or reading from it fails, load from the database. - if s.db.snap == nil || err != nil { - start := time.Now() - tr, err := s.getTrie() - if err != nil { - s.db.setError(err) - return common.Hash{} - } - val, err := tr.GetStorage(s.address, key.Bytes()) - s.db.StorageReads += time.Since(start) + s.db.StorageLoaded++ - if err != nil { - s.db.setError(err) - return common.Hash{} - } - value.SetBytes(val) + start := time.Now() + value, err := s.db.reader.Storage(s.address, key) + if err != nil { + s.db.setError(err) + return common.Hash{} } - // Independent of where we loaded the data from, add it to the prefetcher. - // Whilst this would be a bit weird if snapshots are disabled, but we still - // want the trie nodes to end up in the prefetcher too, so just push through. + s.db.StorageReads += time.Since(start) + + // Schedule the resolved storage slots for prefetching if it's enabled. if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash { if err = s.db.prefetcher.prefetch(s.addrHash, s.origin.Root, s.address, [][]byte{key[:]}, true); err != nil { log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err) } } s.originStorage[key] = value - s.db.StorageLoaded++ return value } @@ -527,7 +498,7 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject { newContract: s.newContract, } if s.trie != nil { - obj.trie = db.db.CopyTrie(s.trie) + obj.trie = mustCopyTrie(s.trie) } return obj } diff --git a/core/state/state_test.go b/core/state/state_test.go index 9200e4abe9f9..9de50beb12dc 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -26,27 +26,25 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/triedb" "github.com/holiman/uint256" ) type stateEnv struct { - db ethdb.Database state *StateDB } func newStateEnv() *stateEnv { - db := rawdb.NewMemoryDatabase() - sdb, _ := New(types.EmptyRootHash, NewDatabase(db), nil) - return &stateEnv{db: db, state: sdb} + sdb, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) + return &stateEnv{state: sdb} } func TestDump(t *testing.T) { db := rawdb.NewMemoryDatabase() - tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true}) - sdb, _ := New(types.EmptyRootHash, tdb, nil) - s := &stateEnv{db: db, state: sdb} + triedb := triedb.NewDatabase(db, &triedb.Config{Preimages: true}) + tdb := NewDatabase(triedb, nil) + sdb, _ := New(types.EmptyRootHash, tdb) + s := &stateEnv{state: sdb} // generate a few entries obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01})) @@ -62,7 +60,7 @@ func TestDump(t *testing.T) { root, _ := s.state.Commit(0, false) // check that DumpToCollector contains the state objects that are in trie - s.state, _ = New(root, tdb, nil) + s.state, _ = New(root, tdb) got := string(s.state.Dump(nil)) want := `{ "root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2", @@ -101,9 +99,10 @@ func TestDump(t *testing.T) { func TestIterativeDump(t *testing.T) { db := rawdb.NewMemoryDatabase() - tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true}) - sdb, _ := New(types.EmptyRootHash, tdb, nil) - s := &stateEnv{db: db, state: sdb} + triedb := triedb.NewDatabase(db, &triedb.Config{Preimages: true}) + tdb := NewDatabase(triedb, nil) + sdb, _ := New(types.EmptyRootHash, tdb) + s := &stateEnv{state: sdb} // generate a few entries obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01})) @@ -119,7 +118,7 @@ func TestIterativeDump(t *testing.T) { s.state.updateStateObject(obj1) s.state.updateStateObject(obj2) root, _ := s.state.Commit(0, false) - s.state, _ = New(root, tdb, nil) + s.state, _ = New(root, tdb) b := &bytes.Buffer{} s.state.IterativeDump(nil, json.NewEncoder(b)) @@ -195,7 +194,7 @@ func TestSnapshotEmpty(t *testing.T) { } func TestCreateObjectRevert(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) addr := common.BytesToAddress([]byte("so0")) snap := state.Snapshot() diff --git a/core/state/statedb.go b/core/state/statedb.go index f81c8a055b0c..1a12f519a46c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -82,10 +82,8 @@ type StateDB struct { db Database prefetcher *triePrefetcher trie Trie - hasher crypto.KeccakState logger *tracing.Hooks - snaps *snapshot.Tree // Nil if snapshot is not available - snap snapshot.Snapshot // Nil if snapshot is not available + reader Reader // originalRoot is the pre-state root, before any changes were made. // It will be updated when the Commit is called. @@ -144,17 +142,15 @@ type StateDB struct { witness *stateless.Witness // Measurements gathered during execution for debugging purposes - AccountReads time.Duration - AccountHashes time.Duration - AccountUpdates time.Duration - AccountCommits time.Duration - StorageReads time.Duration - StorageUpdates time.Duration - StorageCommits time.Duration - SnapshotAccountReads time.Duration - SnapshotStorageReads time.Duration - SnapshotCommits time.Duration - TrieDBCommits time.Duration + AccountReads time.Duration + AccountHashes time.Duration + AccountUpdates time.Duration + AccountCommits time.Duration + StorageReads time.Duration + StorageUpdates time.Duration + StorageCommits time.Duration + SnapshotCommits time.Duration + TrieDBCommits time.Duration AccountLoaded int // Number of accounts retrieved from the database during the state transition AccountUpdated int // Number of accounts updated during the state transition @@ -165,16 +161,20 @@ type StateDB struct { } // New creates a new state from a given trie. -func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { +func New(root common.Hash, db Database) (*StateDB, error) { tr, err := db.OpenTrie(root) if err != nil { return nil, err } + reader, err := db.Reader(root) + if err != nil { + return nil, err + } sdb := &StateDB{ db: db, trie: tr, originalRoot: root, - snaps: snaps, + reader: reader, stateObjects: make(map[common.Address]*stateObject), stateObjectsDestruct: make(map[common.Address]*stateObject), mutations: make(map[common.Address]*mutation), @@ -183,13 +183,9 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) journal: newJournal(), accessList: newAccessList(), transientStorage: newTransientStorage(), - hasher: crypto.NewKeccakState(), } if db.TrieDB().IsVerkle() { - sdb.accessEvents = NewAccessEvents(db.(*cachingDB).pointCache) - } - if sdb.snaps != nil { - sdb.snap = sdb.snaps.Snapshot(root) + sdb.accessEvents = NewAccessEvents(db.PointCache()) } return sdb, nil } @@ -204,30 +200,23 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) { // commit phase, most of the needed data is already hot. func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) { // Terminate any previously running prefetcher - if s.prefetcher != nil { - s.prefetcher.terminate(false) - s.prefetcher.report() - s.prefetcher = nil - } + s.StopPrefetcher() + // Enable witness collection if requested s.witness = witness - // If snapshots are enabled, start prefethers explicitly - if s.snap != nil { - s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, witness == nil) - - // With the switch to the Proof-of-Stake consensus algorithm, block production - // rewards are now handled at the consensus layer. Consequently, a block may - // have no state transitions if it contains no transactions and no withdrawals. - // In such cases, the account trie won't be scheduled for prefetching, leading - // to unnecessary error logs. - // - // To prevent this, the account trie is always scheduled for prefetching once - // the prefetcher is constructed. For more details, see: - // https://github.com/ethereum/go-ethereum/issues/29880 - if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil, false); err != nil { - log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err) - } + // With the switch to the Proof-of-Stake consensus algorithm, block production + // rewards are now handled at the consensus layer. Consequently, a block may + // have no state transitions if it contains no transactions and no withdrawals. + // In such cases, the account trie won't be scheduled for prefetching, leading + // to unnecessary error logs. + // + // To prevent this, the account trie is always scheduled for prefetching once + // the prefetcher is constructed. For more details, see: + // https://github.com/ethereum/go-ethereum/issues/29880 + s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, witness == nil) + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil, false); err != nil { + log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err) } } @@ -583,57 +572,28 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { if _, ok := s.stateObjectsDestruct[addr]; ok { return nil } - // If no live objects are available, attempt to use snapshots - var data *types.StateAccount - if s.snap != nil { - start := time.Now() - acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes())) - s.SnapshotAccountReads += time.Since(start) - if err == nil { - if acc == nil { - s.AccountLoaded++ - return nil - } - data = &types.StateAccount{ - Nonce: acc.Nonce, - Balance: acc.Balance, - CodeHash: acc.CodeHash, - Root: common.BytesToHash(acc.Root), - } - if len(data.CodeHash) == 0 { - data.CodeHash = types.EmptyCodeHash.Bytes() - } - if data.Root == (common.Hash{}) { - data.Root = types.EmptyRootHash - } - } + s.AccountLoaded++ + + start := time.Now() + acct, err := s.reader.Account(addr) + if err != nil { + s.setError(fmt.Errorf("getStateObject (%x) error: %w", addr.Bytes(), err)) + return nil } - // If snapshot unavailable or reading from it failed, load from the database - if data == nil { - start := time.Now() - var err error - data, err = s.trie.GetAccount(addr) - s.AccountReads += time.Since(start) + s.AccountReads += time.Since(start) - if err != nil { - s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %w", addr.Bytes(), err)) - return nil - } - if data == nil { - s.AccountLoaded++ - return nil - } + // Short circuit if the account is not found + if acct == nil { + return nil } - // Independent of where we loaded the data from, add it to the prefetcher. - // Whilst this would be a bit weird if snapshots are disabled, but we still - // want the trie nodes to end up in the prefetcher too, so just push through. + // Schedule the resolved account for prefetching if it's enabled. if s.prefetcher != nil { if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]}, true); err != nil { log.Error("Failed to prefetch account", "addr", addr, "err", err) } } // Insert into the live set - obj := newObject(s, addr, data) + obj := newObject(s, addr, acct) s.setStateObject(obj) s.AccountLoaded++ return obj @@ -688,8 +648,8 @@ func (s *StateDB) Copy() *StateDB { // Copy all the basic fields, initialize the memory ones state := &StateDB{ db: s.db, - trie: s.db.CopyTrie(s.trie), - hasher: crypto.NewKeccakState(), + trie: mustCopyTrie(s.trie), + reader: s.reader.Copy(), originalRoot: s.originalRoot, stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)), stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)), @@ -701,14 +661,16 @@ func (s *StateDB) Copy() *StateDB { logs: make(map[common.Hash][]*types.Log, len(s.logs)), logSize: s.logSize, preimages: maps.Clone(s.preimages), - journal: s.journal.copy(), - // In order for the block producer to be able to use and make additions - // to the snapshot tree, we need to copy that as well. Otherwise, any - // block mined by ourselves will cause gaps in the tree, and force the - // miner to operate trie-backed only. - snaps: s.snaps, - snap: s.snap, + // Do we need to copy the access list and transient storage? + // In practice: No. At the start of a transaction, these two lists are empty. + // In practice, we only ever copy state _between_ transactions/blocks, never + // in the middle of a transaction. However, it doesn't cost us much to copy + // empty lists, so we do it anyway to not blow up if we ever decide copy them + // in the middle of a transaction. + accessList: s.accessList.Copy(), + transientStorage: s.transientStorage.Copy(), + journal: s.journal.copy(), } if s.witness != nil { state.witness = s.witness.Copy() @@ -737,14 +699,6 @@ func (s *StateDB) Copy() *StateDB { } state.logs[hash] = cpy } - // Do we need to copy the access list and transient storage? - // In practice: No. At the start of a transaction, these two lists are empty. - // In practice, we only ever copy state _between_ transactions/blocks, never - // in the middle of a transaction. However, it doesn't cost us much to copy - // empty lists, so we do it anyway to not blow up if we ever decide copy them - // in the middle of a transaction. - state.accessList = s.accessList.Copy() - state.transientStorage = s.transientStorage.Copy() return state } @@ -979,8 +933,8 @@ func (s *StateDB) clearJournalAndRefund() { // of a specific account. It leverages the associated state snapshot for fast // storage iteration and constructs trie node deletion markers by creating // stack trie with iterated slots. -func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { - iter, err := s.snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{}) +func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { + iter, err := snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{}) if err != nil { return nil, nil, err } @@ -1058,10 +1012,11 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root // The fast approach can be failed if the snapshot is not fully // generated, or it's internally corrupted. Fallback to the slow // one just in case. - if s.snap != nil { - slots, nodes, err = s.fastDeleteStorage(addrHash, root) + snaps := s.db.Snapshot() + if snaps != nil { + slots, nodes, err = s.fastDeleteStorage(snaps, addrHash, root) } - if s.snap == nil || err != nil { + if snaps == nil || err != nil { slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) } if err != nil { @@ -1299,7 +1254,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU return nil, err } // Commit dirty contract code if any exists - if db := s.db.DiskDB(); db != nil && len(ret.codes) > 0 { + if db := s.db.TrieDB().Disk(); db != nil && len(ret.codes) > 0 { batch := db.NewBatch() for _, code := range ret.codes { rawdb.WriteCode(batch, code.hash, code.blob) @@ -1310,18 +1265,16 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU } if !ret.empty() { // If snapshotting is enabled, update the snapshot tree with this new version - if s.snap != nil { - s.snap = nil - + if snap := s.db.Snapshot(); snap != nil { start := time.Now() - if err := s.snaps.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil { + if err := snap.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil { log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err) } // Keep 128 diff layers in the memory, persistent layer is 129th. // - head layer is paired with HEAD state // - head-1 layer is paired with HEAD-1 state // - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state - if err := s.snaps.Cap(ret.root, TriesInMemory); err != nil { + if err := snap.Cap(ret.root, TriesInMemory); err != nil { log.Warn("Failed to cap snapshot tree", "root", ret.root, "layers", TriesInMemory, "err", err) } s.SnapshotCommits += time.Since(start) @@ -1336,6 +1289,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU s.TrieDBCommits += time.Since(start) } } + s.reader, _ = s.db.Reader(s.originalRoot) return ret, err } @@ -1451,6 +1405,7 @@ func (s *StateDB) markUpdate(addr common.Address) { s.mutations[addr].typ = update } +// PointCache returns the point cache used by verkle tree. func (s *StateDB) PointCache() *utils.PointCache { return s.db.PointCache() } diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 153035b9c168..90250819e3b5 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -197,7 +197,6 @@ func (test *stateTest) run() bool { } disk = rawdb.NewMemoryDatabase() tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults}) - sdb = NewDatabaseWithNodeDB(disk, tdb) byzantium = rand.Intn(2) == 0 ) defer disk.Close() @@ -217,7 +216,7 @@ func (test *stateTest) run() bool { if i != 0 { root = roots[len(roots)-1] } - state, err := New(root, sdb, snaps) + state, err := New(root, NewDatabase(tdb, snaps)) if err != nil { panic(err) } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index a8ae6eb6d3f5..9441834c6a24 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -19,7 +19,6 @@ package state import ( "bytes" "encoding/binary" - "errors" "fmt" "maps" "math" @@ -53,8 +52,9 @@ func TestUpdateLeaks(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() tdb = triedb.NewDatabase(db, nil) + sdb = NewDatabase(tdb, nil) ) - state, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(db, tdb), nil) + state, _ := New(types.EmptyRootHash, sdb) // Update it with some accounts for i := byte(0); i < 255; i++ { @@ -90,8 +90,8 @@ func TestIntermediateLeaks(t *testing.T) { finalDb := rawdb.NewMemoryDatabase() transNdb := triedb.NewDatabase(transDb, nil) finalNdb := triedb.NewDatabase(finalDb, nil) - transState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(transDb, transNdb), nil) - finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil) + transState, _ := New(types.EmptyRootHash, NewDatabase(transNdb, nil)) + finalState, _ := New(types.EmptyRootHash, NewDatabase(finalNdb, nil)) modify := func(state *StateDB, addr common.Address, i, tweak byte) { state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak)), tracing.BalanceChangeUnspecified) @@ -166,7 +166,7 @@ func TestIntermediateLeaks(t *testing.T) { // https://github.com/ethereum/go-ethereum/pull/15549. func TestCopy(t *testing.T) { // Create a random state test to copy and modify "independently" - orig, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + orig, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) for i := byte(0); i < 255; i++ { obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i})) @@ -230,8 +230,8 @@ func TestCopy(t *testing.T) { // TestCopyWithDirtyJournal tests if Copy can correct create a equal copied // stateDB with dirty journal present. func TestCopyWithDirtyJournal(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - orig, _ := New(types.EmptyRootHash, db, nil) + db := NewDatabaseForTesting() + orig, _ := New(types.EmptyRootHash, db) // Fill up the initial states for i := byte(0); i < 255; i++ { @@ -241,7 +241,7 @@ func TestCopyWithDirtyJournal(t *testing.T) { orig.updateStateObject(obj) } root, _ := orig.Commit(0, true) - orig, _ = New(root, db, nil) + orig, _ = New(root, db) // modify all in memory without finalizing for i := byte(0); i < 255; i++ { @@ -274,8 +274,8 @@ func TestCopyWithDirtyJournal(t *testing.T) { // It then proceeds to make changes to S1. Those changes are _not_ supposed // to affect S2. This test checks that the copy properly deep-copies the objectstate func TestCopyObjectState(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - orig, _ := New(types.EmptyRootHash, db, nil) + db := NewDatabaseForTesting() + orig, _ := New(types.EmptyRootHash, db) // Fill up the initial states for i := byte(0); i < 5; i++ { @@ -527,7 +527,7 @@ func (test *snapshotTest) String() string { func (test *snapshotTest) run() bool { // Run all actions and create snapshots. var ( - state, _ = New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ = New(types.EmptyRootHash, NewDatabaseForTesting()) snapshotRevs = make([]int, len(test.snapshots)) sindex = 0 checkstates = make([]*StateDB, len(test.snapshots)) @@ -699,7 +699,7 @@ func TestTouchDelete(t *testing.T) { s := newStateEnv() s.state.getOrNewStateObject(common.Address{}) root, _ := s.state.Commit(0, false) - s.state, _ = New(root, s.state.db, s.state.snaps) + s.state, _ = New(root, s.state.db) snapshot := s.state.Snapshot() s.state.AddBalance(common.Address{}, new(uint256.Int), tracing.BalanceChangeUnspecified) @@ -716,7 +716,7 @@ func TestTouchDelete(t *testing.T) { // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 func TestCopyOfCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) addr := common.HexToAddress("aaaa") state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) @@ -733,8 +733,8 @@ func TestCopyOfCopy(t *testing.T) { // // See https://github.com/ethereum/go-ethereum/issues/20106. func TestCopyCommitCopy(t *testing.T) { - tdb := NewDatabase(rawdb.NewMemoryDatabase()) - state, _ := New(types.EmptyRootHash, tdb, nil) + tdb := NewDatabaseForTesting() + state, _ := New(types.EmptyRootHash, tdb) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") @@ -787,7 +787,7 @@ func TestCopyCommitCopy(t *testing.T) { } // Commit state, ensure states can be loaded from disk root, _ := state.Commit(0, false) - state, _ = New(root, tdb, nil) + state, _ = New(root, tdb) if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42) } @@ -807,7 +807,7 @@ func TestCopyCommitCopy(t *testing.T) { // // See https://github.com/ethereum/go-ethereum/issues/20106. func TestCopyCopyCommitCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") @@ -876,8 +876,8 @@ func TestCopyCopyCommitCopy(t *testing.T) { // TestCommitCopy tests the copy from a committed state is not fully functional. func TestCommitCopy(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - state, _ := New(types.EmptyRootHash, db, nil) + db := NewDatabaseForTesting() + state, _ := New(types.EmptyRootHash, db) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") @@ -902,7 +902,7 @@ func TestCommitCopy(t *testing.T) { } root, _ := state.Commit(0, true) - state, _ = New(root, db, nil) + state, _ = New(root, db) state.SetState(addr, skey2, sval2) state.Commit(1, true) @@ -915,10 +915,10 @@ func TestCommitCopy(t *testing.T) { t.Fatalf("unexpected code: have %x", code) } // Miss slots because of non-functional trie after commit - if val := copied.GetState(addr, skey1); val != (common.Hash{}) { - t.Fatalf("unexpected storage slot: have %x", sval1) + if val := copied.GetState(addr, skey1); val != sval1 { + t.Fatalf("unexpected storage slot: have %x", val) } - if val := copied.GetCommittedState(addr, skey1); val != (common.Hash{}) { + if val := copied.GetCommittedState(addr, skey1); val != sval1 { t.Fatalf("unexpected storage slot: have %x", val) } // Slots cached in the stateDB, available after commit @@ -928,9 +928,6 @@ func TestCommitCopy(t *testing.T) { if val := copied.GetCommittedState(addr, skey2); val != sval2 { t.Fatalf("unexpected storage slot: have %x", val) } - if !errors.Is(copied.Error(), trie.ErrCommitted) { - t.Fatalf("unexpected state error, %v", copied.Error()) - } } // TestDeleteCreateRevert tests a weird state transition corner case that we hit @@ -943,13 +940,13 @@ func TestCommitCopy(t *testing.T) { // first, but the journal wiped the entire state object on create-revert. func TestDeleteCreateRevert(t *testing.T) { // Create an initial state with a single contract - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) addr := common.BytesToAddress([]byte("so")) state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) root, _ := state.Commit(0, false) - state, _ = New(root, state.db, state.snaps) + state, _ = New(root, state.db) // Simulate self-destructing in one transaction, then create-reverting in another state.SelfDestruct(addr) @@ -961,7 +958,7 @@ func TestDeleteCreateRevert(t *testing.T) { // Commit the entire state and make sure we don't crash and have the correct state root, _ = state.Commit(0, true) - state, _ = New(root, state.db, state.snaps) + state, _ = New(root, state.db) if state.getStateObject(addr) != nil { t.Fatalf("self-destructed contract came alive") @@ -992,10 +989,10 @@ func testMissingTrieNodes(t *testing.T, scheme string) { CleanCacheSize: 0, }}) // disable caching } - db := NewDatabaseWithNodeDB(memDb, tdb) + db := NewDatabase(tdb, nil) var root common.Hash - state, _ := New(types.EmptyRootHash, db, nil) + state, _ := New(types.EmptyRootHash, db) addr := common.BytesToAddress([]byte("so")) { state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) @@ -1009,7 +1006,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { tdb.Commit(root, false) } // Create a new state on the old root - state, _ = New(root, db, nil) + state, _ = New(root, db) // Now we clear out the memdb it := memDb.NewIterator(nil, nil) for it.Next() { @@ -1042,9 +1039,8 @@ func TestStateDBAccessList(t *testing.T) { return common.HexToHash(a) } - memDb := rawdb.NewMemoryDatabase() - db := NewDatabase(memDb) - state, _ := New(types.EmptyRootHash, db, nil) + db := NewDatabaseForTesting() + state, _ := New(types.EmptyRootHash, db) state.accessList = newAccessList() verifyAddrs := func(astrings ...string) { @@ -1213,9 +1209,9 @@ func TestFlushOrderDataLoss(t *testing.T) { // Create a state trie with many accounts and slots var ( memdb = rawdb.NewMemoryDatabase() - triedb = triedb.NewDatabase(memdb, nil) - statedb = NewDatabaseWithNodeDB(memdb, triedb) - state, _ = New(types.EmptyRootHash, statedb, nil) + tdb = triedb.NewDatabase(memdb, triedb.HashDefaults) + statedb = NewDatabase(tdb, nil) + state, _ = New(types.EmptyRootHash, statedb) ) for a := byte(0); a < 10; a++ { state.CreateAccount(common.Address{a}) @@ -1227,15 +1223,15 @@ func TestFlushOrderDataLoss(t *testing.T) { if err != nil { t.Fatalf("failed to commit state trie: %v", err) } - triedb.Reference(root, common.Hash{}) - if err := triedb.Cap(1024); err != nil { + tdb.Reference(root, common.Hash{}) + if err := tdb.Cap(1024); err != nil { t.Fatalf("failed to cap trie dirty cache: %v", err) } - if err := triedb.Commit(root, false); err != nil { + if err := tdb.Commit(root, false); err != nil { t.Fatalf("failed to commit state trie: %v", err) } // Reopen the state trie from flushed disk and verify it - state, err = New(root, NewDatabase(memdb), nil) + state, err = New(root, NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), nil)) if err != nil { t.Fatalf("failed to reopen state trie: %v", err) } @@ -1249,9 +1245,8 @@ func TestFlushOrderDataLoss(t *testing.T) { } func TestStateDBTransientStorage(t *testing.T) { - memDb := rawdb.NewMemoryDatabase() - db := NewDatabase(memDb) - state, _ := New(types.EmptyRootHash, db, nil) + db := NewDatabaseForTesting() + state, _ := New(types.EmptyRootHash, db) key := common.Hash{0x01} value := common.Hash{0x02} @@ -1286,9 +1281,9 @@ func TestDeleteStorage(t *testing.T) { var ( disk = rawdb.NewMemoryDatabase() tdb = triedb.NewDatabase(disk, nil) - db = NewDatabaseWithNodeDB(disk, tdb) snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash) - state, _ = New(types.EmptyRootHash, db, snaps) + db = NewDatabase(tdb, snaps) + state, _ = New(types.EmptyRootHash, db) addr = common.HexToAddress("0x1") ) // Initialize account and populate storage @@ -1300,9 +1295,10 @@ func TestDeleteStorage(t *testing.T) { state.SetState(addr, slot, value) } root, _ := state.Commit(0, true) + // Init phase done, create two states, one with snap and one without - fastState, _ := New(root, db, snaps) - slowState, _ := New(root, db, nil) + fastState, _ := New(root, NewDatabase(tdb, snaps)) + slowState, _ := New(root, NewDatabase(tdb, nil)) obj := fastState.getOrNewStateObject(addr) storageRoot := obj.data.Root @@ -1340,8 +1336,8 @@ func TestStorageDirtiness(t *testing.T) { var ( disk = rawdb.NewMemoryDatabase() tdb = triedb.NewDatabase(disk, nil) - db = NewDatabaseWithNodeDB(disk, tdb) - state, _ = New(types.EmptyRootHash, db, nil) + db = NewDatabase(tdb, nil) + state, _ = New(types.EmptyRootHash, db) addr = common.HexToAddress("0x1") checkDirty = func(key common.Hash, value common.Hash, dirty bool) { obj := state.getStateObject(addr) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index b7039c9e1cb7..cc15422c0cf8 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -53,8 +53,8 @@ func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, c } db := rawdb.NewMemoryDatabase() nodeDb := triedb.NewDatabase(db, config) - sdb := NewDatabaseWithNodeDB(db, nodeDb) - state, _ := New(types.EmptyRootHash, sdb, nil) + sdb := NewDatabase(nodeDb, nil) + state, _ := New(types.EmptyRootHash, sdb) // Fill it with some arbitrary data var accounts []*testAccount @@ -94,7 +94,7 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, scheme string, root com config.PathDB = pathdb.Defaults } // Check root availability and state contents - state, err := New(root, NewDatabaseWithConfig(db, &config), nil) + state, err := New(root, NewDatabase(triedb.NewDatabase(db, &config), nil)) if err != nil { t.Fatalf("failed to create state trie at %x: %v", root, err) } @@ -120,7 +120,7 @@ func checkStateConsistency(db ethdb.Database, scheme string, root common.Hash) e if scheme == rawdb.PathScheme { config.PathDB = pathdb.Defaults } - state, err := New(root, NewDatabaseWithConfig(db, config), nil) + state, err := New(root, NewDatabase(triedb.NewDatabase(db, config), nil)) if err != nil { return err } diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index a0a9d4110b00..529b42d39cdb 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -31,7 +31,7 @@ import ( ) func filledStateDB() *StateDB { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") @@ -67,8 +67,11 @@ func TestUseAfterTerminate(t *testing.T) { } func TestVerklePrefetcher(t *testing.T) { - db := NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), triedb.VerkleDefaults) - state, err := New(types.EmptyRootHash, db, nil) + disk := rawdb.NewMemoryDatabase() + db := triedb.NewDatabase(disk, triedb.VerkleDefaults) + sdb := NewDatabase(db, nil) + + state, err := New(types.EmptyRootHash, sdb) if err != nil { t.Fatalf("failed to initialize state: %v", err) } @@ -82,9 +85,9 @@ func TestVerklePrefetcher(t *testing.T) { state.SetState(addr, skey, sval) // Change the storage trie root, _ := state.Commit(0, true) - state, _ = New(root, db, nil) + state, _ = New(root, sdb) sRoot := state.GetStorageRoot(addr) - fetcher := newTriePrefetcher(db, root, "", false) + fetcher := newTriePrefetcher(sdb, root, "", false) // Read account fetcher.prefetch(common.Hash{}, root, common.Address{}, [][]byte{ diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 3ed0eb75799c..9678f2828c3e 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -34,7 +34,6 @@ import ( "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/memorydb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/triedb" @@ -602,7 +601,7 @@ func TestProcessParentBlockHash(t *testing.T) { } } t.Run("MPT", func(t *testing.T) { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) test(statedb) }) t.Run("Verkle", func(t *testing.T) { @@ -610,7 +609,7 @@ func TestProcessParentBlockHash(t *testing.T) { cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme) cacheConfig.SnapshotLimit = 0 triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) - statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabaseWithNodeDB(db, triedb), nil) + statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabase(triedb, nil)) test(statedb) }) } diff --git a/core/stateless.go b/core/stateless.go index e3168747cf27..f323cc2e8eb6 100644 --- a/core/stateless.go +++ b/core/stateless.go @@ -42,8 +42,7 @@ import ( func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (common.Hash, common.Hash, error) { // Create and populate the state database to serve as the stateless backend memdb := witness.MakeHashDB() - - db, err := state.New(witness.Root(), state.NewDatabaseWithConfig(memdb, triedb.HashDefaults), nil) + db, err := state.New(witness.Root(), state.NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), nil)) if err != nil { return common.Hash{}, common.Hash{}, err } diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index d658a6daf44a..feccb1792211 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -33,14 +33,12 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "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/tracing" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" - "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -545,7 +543,7 @@ func TestOpenDrops(t *testing.T) { store.Close() // Create a blob pool out of the pre-seeded data - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) @@ -676,7 +674,7 @@ func TestOpenIndex(t *testing.T) { store.Close() // Create a blob pool out of the pre-seeded data - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.Commit(0, true) @@ -776,7 +774,7 @@ func TestOpenHeap(t *testing.T) { store.Close() // Create a blob pool out of the pre-seeded data - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) @@ -856,7 +854,7 @@ func TestOpenCap(t *testing.T) { // with a high cap to ensure everything was persisted previously for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} { // Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) @@ -1266,7 +1264,7 @@ func TestAdd(t *testing.T) { keys = make(map[string]*ecdsa.PrivateKey) addrs = make(map[string]common.Address) ) - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) for acc, seed := range tt.seeds { // Generate a new random key/address for the seed account keys[acc], _ = crypto.GenerateKey() @@ -1328,7 +1326,7 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) { basefee = uint64(1050) blobfee = uint64(105) signer = types.LatestSigner(testChainConfig) - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) chain = &testBlockChain{ config: testChainConfig, basefee: uint256.NewInt(basefee), diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index fd961d1d925c..1377479da11c 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -21,7 +21,6 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" @@ -80,7 +79,7 @@ func TestTransactionFutureAttack(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalQueue = 100 @@ -117,7 +116,7 @@ func TestTransactionFutureAttack(t *testing.T) { func TestTransactionFuture1559(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) @@ -150,7 +149,7 @@ func TestTransactionFuture1559(t *testing.T) { func TestTransactionZAttack(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) @@ -218,7 +217,7 @@ func TestTransactionZAttack(t *testing.T) { func BenchmarkFutureAttack(b *testing.B) { // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalQueue = 100 diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index c86991c942da..39673d176db9 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/common" "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/tracing" "github.com/ethereum/go-ethereum/core/txpool" @@ -160,7 +159,7 @@ func setupPool() (*LegacyPool, *ecdsa.PrivateKey) { } func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.PrivateKey) { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(config, 10000000, statedb, new(event.Feed)) key, _ := crypto.GenerateKey() @@ -251,7 +250,7 @@ func (c *testChain) State() (*state.StateDB, error) { // a state change between those fetches. stdb := c.statedb if *c.trigger { - c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) // simulate that the new head block included tx0 and tx1 c.statedb.SetNonce(c.address, 2) c.statedb.SetBalance(c.address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified) @@ -269,7 +268,7 @@ func TestStateChangeDuringReset(t *testing.T) { var ( key, _ = crypto.GenerateKey() address = crypto.PubkeyToAddress(key.PublicKey) - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) trigger = false ) @@ -468,7 +467,7 @@ func TestChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) @@ -497,7 +496,7 @@ func TestDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) @@ -697,7 +696,7 @@ func TestPostponing(t *testing.T) { t.Parallel() // Create the pool to test the postponing with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -910,7 +909,7 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1003,7 +1002,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { evictionInterval = time.Millisecond * 100 // Create the pool to test the non-expiration enforcement - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1189,7 +1188,7 @@ func TestPendingGlobalLimiting(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1291,7 +1290,7 @@ func TestCapClearsFromAll(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1326,7 +1325,7 @@ func TestPendingMinimumAllowance(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1375,7 +1374,7 @@ func TestRepricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -1495,7 +1494,7 @@ func TestMinGasPriceEnforced(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(eip1559Config, 10000000, statedb, new(event.Feed)) txPoolConfig := DefaultConfig @@ -1668,7 +1667,7 @@ func TestRepricingKeepsLocals(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -1742,7 +1741,7 @@ func TestUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1857,7 +1856,7 @@ func TestStableUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -2090,7 +2089,7 @@ func TestDeduplication(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -2157,7 +2156,7 @@ func TestReplacement(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -2363,7 +2362,7 @@ func testJournaling(t *testing.T, nolocals bool) { os.Remove(journal) // Create the original pool to inject transaction into the journal - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -2464,7 +2463,7 @@ func TestStatusCheck(t *testing.T) { t.Parallel() // Create the pool to test the status retrievals with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 02fc94840d60..babe9a5b6a1e 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "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/params" @@ -86,7 +85,7 @@ func TestEIP2200(t *testing.T) { for i, tt := range eip2200Tests { address := common.BytesToAddress([]byte("contract")) - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.CreateAccount(address) statedb.SetCode(address, hexutil.MustDecode(tt.input)) statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original})) @@ -138,7 +137,7 @@ func TestCreateGas(t *testing.T) { var gasUsed = uint64(0) doCheck := func(testGas int) bool { address := common.BytesToAddress([]byte("contract")) - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.CreateAccount(address) statedb.SetCode(address, hexutil.MustDecode(tt.code)) statedb.Finalise(true) diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index e17e913aa3ce..a3f9ee81d16e 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -27,7 +27,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "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/crypto" @@ -582,7 +581,7 @@ func BenchmarkOpMstore(bench *testing.B) { func TestOpTstore(t *testing.T) { var ( - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) env = NewEVM(BlockContext{}, TxContext{}, statedb, params.TestChainConfig, Config{}) stack = newstack() mem = NewMemory() diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go index ff4977d728ed..a1369648da8e 100644 --- a/core/vm/interpreter_test.go +++ b/core/vm/interpreter_test.go @@ -22,7 +22,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "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/params" @@ -43,7 +42,7 @@ func TestLoopInterrupt(t *testing.T) { } for i, tt := range loopInterruptTests { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.CreateAccount(address) statedb.SetCode(address, common.Hex2Bytes(tt)) statedb.Finalise(true) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 1181e5fccdc3..f83ed682cd13 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -21,7 +21,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "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" @@ -128,7 +127,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { setDefaults(cfg) if cfg.State == nil { - cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) } var ( address = common.BytesToAddress([]byte("contract")) @@ -165,7 +164,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { setDefaults(cfg) if cfg.State == nil { - cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) } var ( vmenv = NewEnv(cfg) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index f56d4a74520f..9046dad5fef9 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/asm" - "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" @@ -105,7 +104,7 @@ func TestExecute(t *testing.T) { } func TestCall(t *testing.T) { - state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) address := common.HexToAddress("0xaa") state.SetCode(address, []byte{ byte(vm.PUSH1), 10, @@ -161,7 +160,7 @@ func BenchmarkCall(b *testing.B) { } func benchmarkEVM_Create(bench *testing.B, code string) { var ( - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) sender = common.BytesToAddress([]byte("sender")) receiver = common.BytesToAddress([]byte("receiver")) ) @@ -227,7 +226,7 @@ func BenchmarkEVM_SWAP1(b *testing.B) { return contract } - state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) contractAddr := common.BytesToAddress([]byte("contract")) b.Run("10k", func(b *testing.B) { @@ -255,7 +254,7 @@ func BenchmarkEVM_RETURN(b *testing.B) { return contract } - state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) contractAddr := common.BytesToAddress([]byte("contract")) for _, n := range []uint64{1_000, 10_000, 100_000, 1_000_000} { @@ -393,7 +392,7 @@ func TestBlockhash(t *testing.T) { func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode string, b *testing.B) { cfg := new(Config) setDefaults(cfg) - cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) cfg.GasLimit = gas if len(tracerCode) > 0 { tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil) @@ -880,7 +879,7 @@ func TestRuntimeJSTracer(t *testing.T) { main := common.HexToAddress("0xaa") for i, jsTracer := range jsTracers { for j, tc := range tests { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.SetCode(main, tc.code) statedb.SetCode(common.HexToAddress("0xbb"), calleeCode) statedb.SetCode(common.HexToAddress("0xcc"), calleeCode) @@ -922,7 +921,7 @@ func TestJSTracerCreateTx(t *testing.T) { exit: function(res) { this.exits++ }}` code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)} - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index 750cee5e44e8..cfb8829b5cc0 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -64,8 +64,9 @@ func TestAccountRange(t *testing.T) { t.Parallel() var ( - statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &triedb.Config{Preimages: true}) - sdb, _ = state.New(types.EmptyRootHash, statedb, nil) + mdb = rawdb.NewMemoryDatabase() + statedb = state.NewDatabase(triedb.NewDatabase(mdb, &triedb.Config{Preimages: true}), nil) + sdb, _ = state.New(types.EmptyRootHash, statedb) addrs = [AccountRangeMaxResults * 2]common.Address{} m = map[common.Address]bool{} ) @@ -82,7 +83,7 @@ func TestAccountRange(t *testing.T) { } } root, _ := sdb.Commit(0, true) - sdb, _ = state.New(root, statedb, nil) + sdb, _ = state.New(root, statedb) trie, err := statedb.OpenTrie(root) if err != nil { @@ -135,12 +136,12 @@ func TestEmptyAccountRange(t *testing.T) { t.Parallel() var ( - statedb = state.NewDatabase(rawdb.NewMemoryDatabase()) - st, _ = state.New(types.EmptyRootHash, statedb, nil) + statedb = state.NewDatabaseForTesting() + st, _ = state.New(types.EmptyRootHash, statedb) ) // Commit(although nothing to flush) and re-init the statedb st.Commit(0, true) - st, _ = state.New(types.EmptyRootHash, statedb, nil) + st, _ = state.New(types.EmptyRootHash, statedb) results := st.RawDump(&state.DumpConfig{ SkipCode: true, @@ -161,8 +162,10 @@ func TestStorageRangeAt(t *testing.T) { // Create a state where account 0x010000... has a few storage entries. var ( - db = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &triedb.Config{Preimages: true}) - sdb, _ = state.New(types.EmptyRootHash, db, nil) + mdb = rawdb.NewMemoryDatabase() + tdb = triedb.NewDatabase(mdb, &triedb.Config{Preimages: true}) + db = state.NewDatabase(tdb, nil) + sdb, _ = state.New(types.EmptyRootHash, db) addr = common.Address{0x01} keys = []common.Hash{ // hashes of Keys of storage common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"), @@ -181,7 +184,7 @@ func TestStorageRangeAt(t *testing.T) { sdb.SetState(addr, *entry.Key, entry.Value) } root, _ := sdb.Commit(0, false) - sdb, _ = state.New(root, db, nil) + sdb, _ = state.New(root, db) // Check a few combinations of limit and start/end. tests := []struct { diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 7b6f5ba1507b..cb5a233a83ba 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -68,8 +68,9 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u // the internal junks created by tracing will be persisted into the disk. // TODO(rjl493456442), clean cache is disabled to prevent memory leak, // please re-enable it for better performance. - database = state.NewDatabaseWithConfig(eth.chainDb, triedb.HashDefaults) - if statedb, err = state.New(block.Root(), database, nil); err == nil { + tdb := triedb.NewDatabase(eth.chainDb, triedb.HashDefaults) + database = state.NewDatabase(tdb, nil) + if statedb, err = state.New(block.Root(), database); err == nil { log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number()) return statedb, noopReleaser, nil } @@ -86,13 +87,13 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u // TODO(rjl493456442), clean cache is disabled to prevent memory leak, // please re-enable it for better performance. tdb = triedb.NewDatabase(eth.chainDb, triedb.HashDefaults) - database = state.NewDatabaseWithNodeDB(eth.chainDb, tdb) + database = state.NewDatabase(tdb, nil) // If we didn't check the live database, do check state over ephemeral database, // otherwise we would rewind past a persisted block (specific corner case is // chain tracing from the genesis). if !readOnly { - statedb, err = state.New(current.Root(), database, nil) + statedb, err = state.New(current.Root(), database) if err == nil { return statedb, noopReleaser, nil } @@ -111,7 +112,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u } current = parent - statedb, err = state.New(current.Root(), database, nil) + statedb, err = state.New(current.Root(), database) if err == nil { break } @@ -156,7 +157,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w", current.NumberU64(), current.Root().Hex(), err) } - statedb, err = state.New(root, database, nil) + statedb, err = state.New(root, database) if err != nil { return nil, nil, fmt.Errorf("state reset after block %d failed: %v", current.NumberU64(), err) } diff --git a/miner/miner_test.go b/miner/miner_test.go index 779626c0452b..b92febdd1254 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -156,7 +156,7 @@ func createMiner(t *testing.T) *Miner { if err != nil { t.Fatalf("can't create new chain %v", err) } - statedb, _ := state.New(bc.Genesis().Root(), bc.StateCache(), nil) + statedb, _ := state.New(bc.Genesis().Root(), bc.StateCache()) blockchain := &testBlockChain{bc.Genesis().Root(), chainConfig, statedb, 10000000, new(event.Feed)} pool := legacypool.New(testTxPoolConfig, blockchain) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 2bf0056cbc9e..cf0ce9777f67 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -222,7 +222,7 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bo if logs := rlpHash(st.StateDB.Logs()); logs != common.Hash(post.Logs) { return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) } - st.StateDB, _ = state.New(root, st.StateDB.Database(), st.Snapshots) + st.StateDB, _ = state.New(root, st.StateDB.Database()) return nil } @@ -462,8 +462,8 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bo tconf.PathDB = pathdb.Defaults } triedb := triedb.NewDatabase(db, tconf) - sdb := state.NewDatabaseWithNodeDB(db, triedb) - statedb, _ := state.New(types.EmptyRootHash, sdb, nil) + sdb := state.NewDatabase(triedb, nil) + statedb, _ := state.New(types.EmptyRootHash, sdb) for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) @@ -486,7 +486,8 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bo } snaps, _ = snapshot.New(snapconfig, db, triedb, root) } - statedb, _ = state.New(root, sdb, snaps) + sdb = state.NewDatabase(triedb, snaps) + statedb, _ = state.New(root, sdb) return StateTestState{statedb, triedb, snaps} } diff --git a/triedb/database.go b/triedb/database.go index aecb900f31d3..c1e6f9af4e69 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -92,6 +92,7 @@ type backend interface { // types of node backend as an entrypoint. It's responsible for all interactions // relevant with trie nodes and node preimages. type Database struct { + disk ethdb.Database config *Config // Configuration for trie database preimages *preimageStore // The store for caching preimages backend backend // The backend for managing trie nodes @@ -109,6 +110,7 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { preimages = newPreimageStore(diskdb) } db := &Database{ + disk: diskdb, config: config, preimages: preimages, } @@ -327,3 +329,8 @@ func (db *Database) SetBufferSize(size int) error { func (db *Database) IsVerkle() bool { return db.config.IsVerkle } + +// Disk returns the underlying disk database. +func (db *Database) Disk() ethdb.Database { + return db.disk +} From 5035f99bce9bc23db27b68dd8c4a927f9d7d2ef6 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 6 Sep 2024 15:42:59 +0800 Subject: [PATCH 518/571] core/state: get rid of field pointer in journal (#30361) This pull request replaces the field pointer in journal entry with the field itself, specifically the address of mutated account. While it will introduce the extra allocation cost, but it's easier for code reading. Let's measure the overhead overall to see if the change is acceptable or not. --- core/state/journal.go | 78 +++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/core/state/journal.go b/core/state/journal.go index f180a5dae4b6..a2fea6b6ecc5 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -153,7 +153,7 @@ func (j *journal) logChange(txHash common.Hash) { } func (j *journal) createObject(addr common.Address) { - j.append(createObjectChange{account: &addr}) + j.append(createObjectChange{account: addr}) } func (j *journal) createContract(addr common.Address) { @@ -161,12 +161,12 @@ func (j *journal) createContract(addr common.Address) { } func (j *journal) destruct(addr common.Address) { - j.append(selfDestructChange{account: &addr}) + j.append(selfDestructChange{account: addr}) } func (j *journal) storageChange(addr common.Address, key, prev, origin common.Hash) { j.append(storageChange{ - account: &addr, + account: addr, key: key, prevvalue: prev, origvalue: origin, @@ -175,7 +175,7 @@ func (j *journal) storageChange(addr common.Address, key, prev, origin common.Ha func (j *journal) transientStateChange(addr common.Address, key, prev common.Hash) { j.append(transientStorageChange{ - account: &addr, + account: addr, key: key, prevalue: prev, }) @@ -187,25 +187,25 @@ func (j *journal) refundChange(previous uint64) { func (j *journal) balanceChange(addr common.Address, previous *uint256.Int) { j.append(balanceChange{ - account: &addr, + account: addr, prev: previous.Clone(), }) } func (j *journal) setCode(address common.Address) { - j.append(codeChange{account: &address}) + j.append(codeChange{account: address}) } func (j *journal) nonceChange(address common.Address, prev uint64) { j.append(nonceChange{ - account: &address, + account: address, prev: prev, }) } func (j *journal) touchChange(address common.Address) { j.append(touchChange{ - account: &address, + account: address, }) if address == ripemd { // Explicitly put it in the dirty-cache, which is otherwise generated from @@ -215,50 +215,48 @@ func (j *journal) touchChange(address common.Address) { } func (j *journal) accessListAddAccount(addr common.Address) { - j.append(accessListAddAccountChange{&addr}) + j.append(accessListAddAccountChange{addr}) } func (j *journal) accessListAddSlot(addr common.Address, slot common.Hash) { j.append(accessListAddSlotChange{ - address: &addr, - slot: &slot, + address: addr, + slot: slot, }) } type ( // Changes to the account trie. createObjectChange struct { - account *common.Address + account common.Address } - // createContractChange represents an account becoming a contract-account. // This event happens prior to executing initcode. The journal-event simply // manages the created-flag, in order to allow same-tx destruction. createContractChange struct { account common.Address } - selfDestructChange struct { - account *common.Address + account common.Address } // Changes to individual accounts. balanceChange struct { - account *common.Address + account common.Address prev *uint256.Int } nonceChange struct { - account *common.Address + account common.Address prev uint64 } storageChange struct { - account *common.Address + account common.Address key common.Hash prevvalue common.Hash origvalue common.Hash } codeChange struct { - account *common.Address + account common.Address } // Changes to other state values. @@ -269,31 +267,31 @@ type ( txhash common.Hash } touchChange struct { - account *common.Address + account common.Address } // Changes to the access list accessListAddAccountChange struct { - address *common.Address + address common.Address } accessListAddSlotChange struct { - address *common.Address - slot *common.Hash + address common.Address + slot common.Hash } // Changes to transient storage transientStorageChange struct { - account *common.Address + account common.Address key, prevalue common.Hash } ) func (ch createObjectChange) revert(s *StateDB) { - delete(s.stateObjects, *ch.account) + delete(s.stateObjects, ch.account) } func (ch createObjectChange) dirtied() *common.Address { - return ch.account + return &ch.account } func (ch createObjectChange) copy() journalEntry { @@ -317,14 +315,14 @@ func (ch createContractChange) copy() journalEntry { } func (ch selfDestructChange) revert(s *StateDB) { - obj := s.getStateObject(*ch.account) + obj := s.getStateObject(ch.account) if obj != nil { obj.selfDestructed = false } } func (ch selfDestructChange) dirtied() *common.Address { - return ch.account + return &ch.account } func (ch selfDestructChange) copy() journalEntry { @@ -339,7 +337,7 @@ func (ch touchChange) revert(s *StateDB) { } func (ch touchChange) dirtied() *common.Address { - return ch.account + return &ch.account } func (ch touchChange) copy() journalEntry { @@ -349,11 +347,11 @@ func (ch touchChange) copy() journalEntry { } func (ch balanceChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setBalance(ch.prev) + s.getStateObject(ch.account).setBalance(ch.prev) } func (ch balanceChange) dirtied() *common.Address { - return ch.account + return &ch.account } func (ch balanceChange) copy() journalEntry { @@ -364,11 +362,11 @@ func (ch balanceChange) copy() journalEntry { } func (ch nonceChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setNonce(ch.prev) + s.getStateObject(ch.account).setNonce(ch.prev) } func (ch nonceChange) dirtied() *common.Address { - return ch.account + return &ch.account } func (ch nonceChange) copy() journalEntry { @@ -379,11 +377,11 @@ func (ch nonceChange) copy() journalEntry { } func (ch codeChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setCode(types.EmptyCodeHash, nil) + s.getStateObject(ch.account).setCode(types.EmptyCodeHash, nil) } func (ch codeChange) dirtied() *common.Address { - return ch.account + return &ch.account } func (ch codeChange) copy() journalEntry { @@ -391,11 +389,11 @@ func (ch codeChange) copy() journalEntry { } func (ch storageChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue, ch.origvalue) + s.getStateObject(ch.account).setState(ch.key, ch.prevvalue, ch.origvalue) } func (ch storageChange) dirtied() *common.Address { - return ch.account + return &ch.account } func (ch storageChange) copy() journalEntry { @@ -407,7 +405,7 @@ func (ch storageChange) copy() journalEntry { } func (ch transientStorageChange) revert(s *StateDB) { - s.setTransientState(*ch.account, ch.key, ch.prevalue) + s.setTransientState(ch.account, ch.key, ch.prevalue) } func (ch transientStorageChange) dirtied() *common.Address { @@ -466,7 +464,7 @@ func (ch accessListAddAccountChange) revert(s *StateDB) { (addr) at this point, since no storage adds can remain when come upon a single (addr) change. */ - s.accessList.DeleteAddress(*ch.address) + s.accessList.DeleteAddress(ch.address) } func (ch accessListAddAccountChange) dirtied() *common.Address { @@ -480,7 +478,7 @@ func (ch accessListAddAccountChange) copy() journalEntry { } func (ch accessListAddSlotChange) revert(s *StateDB) { - s.accessList.DeleteSlot(*ch.address, *ch.slot) + s.accessList.DeleteSlot(ch.address, ch.slot) } func (ch accessListAddSlotChange) dirtied() *common.Address { From 83775b1dc7f59053ec69085e746c4dd9b9be3a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Fri, 6 Sep 2024 10:11:14 +0200 Subject: [PATCH 519/571] build: upgrade -dlgo version to Go 1.23.1 (#30404) New security fix: https://groups.google.com/g/golang-announce/c/K-cEzDeCtpc --- build/checksums.txt | 97 +++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 3fed6625ed50..06de819c70b5 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,55 +5,56 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.23.0 +# version:golang 1.23.1 # https://go.dev/dl/ -42b7a8e80d805daa03022ed3fde4321d4c3bf2c990a144165d01eeecd6f699c6 go1.23.0.src.tar.gz -257f8560bb4001fb81a5e0ee84f32fecbe18d4450343c9556557d296786847b6 go1.23.0.aix-ppc64.tar.gz -bc91d2573939a01731413fac0884c329606c1c168883692131ce772669caf27b go1.23.0.darwin-amd64.pkg -ffd070acf59f054e8691b838f274d540572db0bd09654af851e4e76ab88403dc go1.23.0.darwin-amd64.tar.gz -d73ae741ed449ea842238f76f4b02935277eb867689f84ace0640965b2caf700 go1.23.0.darwin-arm64.pkg -b770812aef17d7b2ea406588e2b97689e9557aac7e646fe76218b216e2c51406 go1.23.0.darwin-arm64.tar.gz -8fd2ab5ac8629fc97d25a056693e23f332446603dd3c2b764ccb496872004b0c go1.23.0.dragonfly-amd64.tar.gz -2c9b76ead3c44f5b3e40e10b980075addb837f2dd05dafe7c0e4c611fd239753 go1.23.0.freebsd-386.tar.gz -2c2252902b87ba605fdc0b12b4c860fe6553c0c5483c12cc471756ebdd8249fe go1.23.0.freebsd-amd64.tar.gz -8ec48b8d99a515644ae00e79d093ad3b7645dcaf2a19c0a9c0d97916187f4514 go1.23.0.freebsd-arm.tar.gz -f476bbe8efb0db18155671840545370bfb73903fec04ea897d510569dab16d9c go1.23.0.freebsd-arm64.tar.gz -b0e254b2ea5752b4f1c69934ae43a44bbabf98e0c2843af44e1b6d12390eb551 go1.23.0.freebsd-riscv64.tar.gz -09716dcc7a2e19891b3d1e2ea68a1aab22838fc664cdc5f82d5f8eef05db78cf go1.23.0.illumos-amd64.tar.gz -0e8a7340c2632e6fb5088d60f95b52be1f8303143e04cd34e9b2314fafc24edd go1.23.0.linux-386.tar.gz -905a297f19ead44780548933e0ff1a1b86e8327bb459e92f9c0012569f76f5e3 go1.23.0.linux-amd64.tar.gz -62788056693009bcf7020eedc778cdd1781941c6145eab7688bd087bce0f8659 go1.23.0.linux-arm64.tar.gz -0efa1338e644d7f74064fa7f1016b5da7872b2df0070ea3b56e4fef63192e35b go1.23.0.linux-armv6l.tar.gz -dc8f723ce1a236e85c8b56d1e6749e270314e99dd41b80a58355e7ffcf9ea857 go1.23.0.linux-loong64.tar.gz -3332cc76c73c05b3413cdecccffc29aaa3469f87db8ed9f9b784ebb527ca5352 go1.23.0.linux-mips.tar.gz -0ed5cee92433d09fd0816ec5adfbf4b16d712944e833f6342bbe2df18f7826ae go1.23.0.linux-mips64.tar.gz -06a579dd6d1f9a84bc43cab063e7c759a92a6d4dd01fec3d860f22a32df93406 go1.23.0.linux-mips64le.tar.gz -d522770d32d6ee963f61331a695c4f8a730f2445b965d8d56db0a2e75c62af57 go1.23.0.linux-mipsle.tar.gz -8c884cb4f2593d897f58ec1b0f23f303acf5c78fd101e76cb48d6cb1fe5e90e7 go1.23.0.linux-ppc64.tar.gz -8b26e20d4d43a4d7641cddbdc0298d7ba3804d910a9e06cda7672970dbf2829d go1.23.0.linux-ppc64le.tar.gz -a87726205f1a283247f877ccae8ce147ff4e77ac802382647ac52256eb5642c7 go1.23.0.linux-riscv64.tar.gz -003722971de02d97131a4dca2496abdab5cb175a6ee0ed9c8227c5ae9b883e69 go1.23.0.linux-s390x.tar.gz -b203fa2354874c66c40d828e96a6cce1f4e4db192414050a600d0a09b16cafd3 go1.23.0.netbsd-386.tar.gz -1502c82c3ba663959df99c2cc3ca5e7a5e1a75a1495fd26bef697d63bf1f291c go1.23.0.netbsd-amd64.tar.gz -dd50c05c7f613522c8d3d74f598bfc1862c0fee9182b738225820c9b458c7be5 go1.23.0.netbsd-arm.tar.gz -728a94a648f9502cd6175adaac2b770acde6b26f5f92dcbd8c5a1a43cc44bb10 go1.23.0.netbsd-arm64.tar.gz -e1ff3584778257778a4e3f0093b09044072423aebedf2015a550537853c46745 go1.23.0.openbsd-386.tar.gz -d2e30cdb0de256360b51a43f5e551587a7369d8c248120010d5e9432f698a6e8 go1.23.0.openbsd-amd64.tar.gz -bd5224c8a5f195f4128c866c0d418f1b61db865a1042913fd07714ed85da28db go1.23.0.openbsd-arm.tar.gz -fc0e0af3a1b4b7168455e8492a5bb6aa96ceaf46321cef1fc04187301c058890 go1.23.0.openbsd-arm64.tar.gz -ce7ea9343c7c2ef2700b55b80c45549ce39d164031e4d7bb98bec7ca593ed93d go1.23.0.openbsd-ppc64.tar.gz -93b970a8a41f6c89113daaea12e39f2580038af155e823550d0a94a5502c5e2c go1.23.0.plan9-386.tar.gz -6231862acbb6c1e02b1455b35446b9789b0b4b3230d249953e6957c393a53011 go1.23.0.plan9-amd64.tar.gz -632bdd3a1f84b2fe691203423dd2c3f536d4ab250bb52a48e9b05ebf327ae594 go1.23.0.plan9-arm.tar.gz -16773f85003d9e610960f9af67e00bc6c02359d7914de7224079538cc9c1e93d go1.23.0.solaris-amd64.tar.gz -803ef1d4f431d37ac8572ad9b0b65a4f945798208cd16b7f0588960e6b0949ba go1.23.0.windows-386.msi -09448fedec0cdf98ad12397222e0c8bfc835b1d0894c0015ced653534b8d7427 go1.23.0.windows-386.zip -93e1cf580893303d0f6ac10647335de9f0768199d7027d8a361639cae6ab3145 go1.23.0.windows-amd64.msi -d4be481ef73079ee0ad46081d278923aa3fd78db1b3cf147172592f73e14c1ac go1.23.0.windows-amd64.zip -2a361c94879258309343e88c5de5df17f6425df4d74bdf7e333b7298b29f6f29 go1.23.0.windows-arm.msi -006d93712246a672bdb57906dd5bffcab62facc36169e51a27d52340cdac661f go1.23.0.windows-arm.zip -a876ed2bb130d9146152aaf391638abd79dcb3a4f2e9cc59b78709dcef29ced3 go1.23.0.windows-arm64.msi -0be62073ef8f5a2d3b9adcefddf18c417dab0a7975c71488ac2694856e2ff976 go1.23.0.windows-arm64.zip +6ee44e298379d146a5e5aa6b1c5b5d5f5d0a3365eabdd70741e6e21340ec3b0d go1.23.1.src.tar.gz +f17f2791717c15728ec63213a014e244c35f9c8846fb29f5a1b63d0c0556f756 go1.23.1.aix-ppc64.tar.gz +dd9e772686ed908bcff94b6144322d4e2473a7dcd7c696b7e8b6d12f23c887fd go1.23.1.darwin-amd64.pkg +488d9e4ca3e3ed513ee4edd91bef3a2360c65fa6d6be59cf79640bf840130a58 go1.23.1.darwin-amd64.tar.gz +be34b488157ec69d94e26e1554558219a2c90789bcb7e3686965a7f9c8cfcbe7 go1.23.1.darwin-arm64.pkg +e223795ca340e285a760a6446ce57a74500b30e57469a4109961d36184d3c05a go1.23.1.darwin-arm64.tar.gz +6af626176923a6ae6c5de6dc1c864f38365793c0e4ecd0d6eab847bdc23953e5 go1.23.1.dragonfly-amd64.tar.gz +cc957c1a019702e6cdc2e257202d42799011ebc1968b6c3bcd6b1965952607d5 go1.23.1.freebsd-386.tar.gz +a7d57781c50bb80886a8f04066791956d45aa3eea0f83070c5268b6223afb2ff go1.23.1.freebsd-amd64.tar.gz +c7b09f3fef456048e596db9bea746eb66796aeb82885622b0388feee18f36a3e go1.23.1.freebsd-arm.tar.gz +b05cd6a77995a0c8439d88df124811c725fb78b942d0b6dd1643529d7ba62f1f go1.23.1.freebsd-arm64.tar.gz +56236ae70be1613f2915943b94f53c96be5bffc0719314078facd778a89bc57e go1.23.1.freebsd-riscv64.tar.gz +8644c52df4e831202114fd67c9fcaf1f7233ad27bf945ac53fa7217cf1a0349f go1.23.1.illumos-amd64.tar.gz +cdee2f4e2efa001f7ee75c90f2efc310b63346cfbba7b549987e9139527c6b17 go1.23.1.linux-386.tar.gz +49bbb517cfa9eee677e1e7897f7cf9cfdbcf49e05f61984a2789136de359f9bd go1.23.1.linux-amd64.tar.gz +faec7f7f8ae53fda0f3d408f52182d942cc89ef5b7d3d9f23ff117437d4b2d2f go1.23.1.linux-arm64.tar.gz +6c7832c7dcd8fb6d4eb308f672a725393403c74ee7be1aeccd8a443015df99de go1.23.1.linux-armv6l.tar.gz +649ce3856ddc808c00b14a46232eab0bf95e7911cdf497010b17d76656f5ca4e go1.23.1.linux-loong64.tar.gz +201911048f234e5a0c51ec94b1a11d4e47062fee4398b1d2faa6c820dc026724 go1.23.1.linux-mips.tar.gz +2bce3743df463915e45d2612f9476ffb03d0b3750b1cb3879347de08715b5fc6 go1.23.1.linux-mips64.tar.gz +54e301f266e33431b0703136e0bbd4cf02461b1ecedd37b7cbd90cb862a98e5f go1.23.1.linux-mips64le.tar.gz +8efd495e93d17408c0803595cdc3bf13cb28e0f957aeabd9cc18245fb8e64019 go1.23.1.linux-mipsle.tar.gz +52bd68689095831ad9af7160844c23b28bb8d0acd268de7e300ff5f0662b7a07 go1.23.1.linux-ppc64.tar.gz +042888cae54b5fbfd9dd1e3b6bc4a5134879777fe6497fc4c62ec394b5ecf2da go1.23.1.linux-ppc64le.tar.gz +1a4a609f0391bea202d9095453cbfaf7368fa88a04c206bf9dd715a738664dc3 go1.23.1.linux-riscv64.tar.gz +47dc49ad45c45e192efa0df7dc7bc5403f5f2d15b5d0dc74ef3018154b616f4d go1.23.1.linux-s390x.tar.gz +fbfbd5efa6a5d581ea7f5e65015f927db0e52135cab057e43d39d5482da54b61 go1.23.1.netbsd-386.tar.gz +e96e1cc5cf36113ee6099d1a7306b22cd9c3f975a36bdff954c59f104f22b853 go1.23.1.netbsd-amd64.tar.gz +c394dfc06bfc276a591209a37e09cd39089ec9a9cc3db30b94814ce2e39eb1d4 go1.23.1.netbsd-arm.tar.gz +b3b35d64f32821a68b3e2994032dbefb81978f2ec3f218c7a770623b82d36b8e go1.23.1.netbsd-arm64.tar.gz +3c775c4c16c182e33c2c4ac090d9a247a93b3fb18a3df01d87d490f29599faff go1.23.1.openbsd-386.tar.gz +5edbe53b47c57b32707fd7154536fbe9eaa79053fea01650c93b54cdba13fc0f go1.23.1.openbsd-amd64.tar.gz +c30903dd8fa98b8aca8e9db0962ce9f55502aed93e0ef41e5ae148aaa0088de1 go1.23.1.openbsd-arm.tar.gz +12da183489e58f9c6b357bc1b626f85ed7d4220cab31a49d6a49e6ac6a718b67 go1.23.1.openbsd-arm64.tar.gz +9cc9aad37696a4a10c31dcec9e35a308de0b369dad354d54cf07406ac6fa7c6f go1.23.1.openbsd-ppc64.tar.gz +e1d740dda062ce5a276a0c3ed7d8b6353238bc8ff405f63e2e3480bfd26a5ec5 go1.23.1.openbsd-riscv64.tar.gz +da2a37f9987f01f096859230aa13ecc4ad2e7884465bce91004bc78c64435d65 go1.23.1.plan9-386.tar.gz +fd8fff8b0697d55c4a4d02a8dc998192b80a9dc2a057647373d6ff607cad29de go1.23.1.plan9-amd64.tar.gz +52efbc5804c1c86ba7868aa8ebbc31cc8c2a27b62a60fd57944970d48fc67525 go1.23.1.plan9-arm.tar.gz +f54205f21e2143f2ada1bf1c00ddf64590f5139d5c3fb77cc06175f0d8cc7567 go1.23.1.solaris-amd64.tar.gz +369a17f0cfd29e5c848e58ffe0d772da20abe334d1c7ca01dbcd55bb3db0b440 go1.23.1.windows-386.msi +ab866f47d7be56e6b1c67f1d529bf4c23331a339fb0785f435a0552d352cb257 go1.23.1.windows-386.zip +e99dac215ee437b9bb8f8b14bbfe0e8756882c1ed291f30818e8363bc9c047a5 go1.23.1.windows-amd64.msi +32dedf277c86610e380e1765593edb66876f00223df71690bd6be68ee17675c0 go1.23.1.windows-amd64.zip +23169c79dc6b54e0dffb25be6b67425ad9759392a58309bc057430a9bf4c8f6a go1.23.1.windows-arm.msi +1a57615a09f13534f88e9f2d7efd5743535d1a5719b19e520eef965a634f8efb go1.23.1.windows-arm.zip +313e1a543931ad8735b4df8969e00f5f4c2ef07be21f54015ede961a70263d35 go1.23.1.windows-arm64.msi +64ad0954d2c33f556fb1018d62de091254aa6e3a94f1c8a8b16af0d3701d194e go1.23.1.windows-arm64.zip # version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ From 8f4fac7b86227e3ceca095e60d58f126d692f379 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:31:00 +0200 Subject: [PATCH 520/571] internal/ethapi: eth_multicall (#27720) This is a successor PR to #25743. This PR is based on a new iteration of the spec: https://github.com/ethereum/execution-apis/pull/484. `eth_multicall` takes in a list of blocks, each optionally overriding fields like number, timestamp, etc. of a base block. Each block can include calls. At each block users can override the state. There are extra features, such as: - Include ether transfers as part of the logs - Overriding precompile codes with evm bytecode - Redirecting accounts to another address ## Breaking changes This PR includes the following breaking changes: - Block override fields of eth_call and debug_traceCall have had the following fields renamed - `coinbase` -> `feeRecipient` - `random` -> `prevRandao` - `baseFee` -> `baseFeePerGas` --------- Co-authored-by: Gary Rong Co-authored-by: Martin Holst Swende --- core/state_processor.go | 11 +- core/state_transition.go | 38 +- core/vm/contracts.go | 42 +- core/vm/evm.go | 40 +- eth/gasestimator/gasestimator.go | 10 +- eth/tracers/api.go | 20 +- ethclient/ethclient_test.go | 2 +- ethclient/gethclient/gethclient.go | 6 +- ethclient/gethclient/gethclient_test.go | 6 +- graphql/graphql_test.go | 1 + internal/ethapi/api.go | 234 +++- internal/ethapi/api_test.go | 1327 ++++++++++++++++++++++- internal/ethapi/errors.go | 92 ++ internal/ethapi/logtracer.go | 151 +++ internal/ethapi/simulate.go | 418 +++++++ internal/ethapi/simulate_test.go | 120 ++ internal/ethapi/transaction_args.go | 51 +- internal/web3ext/web3ext.go | 6 + 18 files changed, 2427 insertions(+), 148 deletions(-) create mode 100644 internal/ethapi/logtracer.go create mode 100644 internal/ethapi/simulate.go create mode 100644 internal/ethapi/simulate_test.go diff --git a/core/state_processor.go b/core/state_processor.go index 2844693a9e5c..c74a33c378f4 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -147,9 +147,14 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo } *usedGas += result.UsedGas + return MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root), nil +} + +// MakeReceipt generates the receipt object for a transaction given its execution result. +func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt { // Create a new receipt for the transaction, storing the intermediate root and gas used // by the tx. - receipt = &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas} + receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas} if result.Failed() { receipt.Status = types.ReceiptStatusFailed } else { @@ -164,7 +169,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo } // If the transaction created a contract, store the creation address in the receipt. - if msg.To == nil { + if tx.To() == nil { receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) } @@ -180,7 +185,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo receipt.BlockHash = blockHash receipt.BlockNumber = blockNumber receipt.TransactionIndex = uint(statedb.TxIndex()) - return receipt, err + return receipt } // ApplyTransaction attempts to apply a transaction to the given state database diff --git a/core/state_transition.go b/core/state_transition.go index 37807d3d2b68..d285d03fe245 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -142,27 +142,31 @@ type Message struct { BlobGasFeeCap *big.Int BlobHashes []common.Hash - // When SkipAccountChecks is true, the message nonce is not checked against the - // account nonce in state. It also disables checking that the sender is an EOA. + // When SkipNonceChecks is true, the message nonce is not checked against the + // account nonce in state. // This field will be set to true for operations like RPC eth_call. - SkipAccountChecks bool + SkipNonceChecks bool + + // When SkipFromEOACheck is true, the message sender is not checked to be an EOA. + SkipFromEOACheck bool } // TransactionToMessage converts a transaction into a Message. func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) { msg := &Message{ - Nonce: tx.Nonce(), - GasLimit: tx.Gas(), - GasPrice: new(big.Int).Set(tx.GasPrice()), - GasFeeCap: new(big.Int).Set(tx.GasFeeCap()), - GasTipCap: new(big.Int).Set(tx.GasTipCap()), - To: tx.To(), - Value: tx.Value(), - Data: tx.Data(), - AccessList: tx.AccessList(), - SkipAccountChecks: false, - BlobHashes: tx.BlobHashes(), - BlobGasFeeCap: tx.BlobGasFeeCap(), + Nonce: tx.Nonce(), + GasLimit: tx.Gas(), + GasPrice: new(big.Int).Set(tx.GasPrice()), + GasFeeCap: new(big.Int).Set(tx.GasFeeCap()), + GasTipCap: new(big.Int).Set(tx.GasTipCap()), + To: tx.To(), + Value: tx.Value(), + Data: tx.Data(), + AccessList: tx.AccessList(), + SkipNonceChecks: false, + SkipFromEOACheck: false, + BlobHashes: tx.BlobHashes(), + BlobGasFeeCap: tx.BlobGasFeeCap(), } // If baseFee provided, set gasPrice to effectiveGasPrice. if baseFee != nil { @@ -280,7 +284,7 @@ func (st *StateTransition) buyGas() error { func (st *StateTransition) preCheck() error { // Only check transactions that are not fake msg := st.msg - if !msg.SkipAccountChecks { + if !msg.SkipNonceChecks { // Make sure this transaction's nonce is correct. stNonce := st.state.GetNonce(msg.From) if msgNonce := msg.Nonce; stNonce < msgNonce { @@ -293,6 +297,8 @@ func (st *StateTransition) preCheck() error { return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax, msg.From.Hex(), stNonce) } + } + if !msg.SkipFromEOACheck { // Make sure the sender is an EOA codeHash := st.state.GetCodeHash(msg.From) if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash { diff --git a/core/vm/contracts.go b/core/vm/contracts.go index dd71a9729f34..104d2ba814b2 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -21,6 +21,7 @@ import ( "encoding/binary" "errors" "fmt" + "maps" "math/big" "github.com/consensys/gnark-crypto/ecc" @@ -46,9 +47,12 @@ type PrecompiledContract interface { Run(input []byte) ([]byte, error) // Run runs the precompiled contract } +// PrecompiledContracts contains the precompiled contracts supported at the given fork. +type PrecompiledContracts map[common.Address]PrecompiledContract + // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum // contracts used in the Frontier and Homestead releases. -var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{ +var PrecompiledContractsHomestead = PrecompiledContracts{ common.BytesToAddress([]byte{0x1}): &ecrecover{}, common.BytesToAddress([]byte{0x2}): &sha256hash{}, common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, @@ -57,7 +61,7 @@ var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{ // PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum // contracts used in the Byzantium release. -var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{ +var PrecompiledContractsByzantium = PrecompiledContracts{ common.BytesToAddress([]byte{0x1}): &ecrecover{}, common.BytesToAddress([]byte{0x2}): &sha256hash{}, common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, @@ -70,7 +74,7 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{ // PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum // contracts used in the Istanbul release. -var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{ +var PrecompiledContractsIstanbul = PrecompiledContracts{ common.BytesToAddress([]byte{0x1}): &ecrecover{}, common.BytesToAddress([]byte{0x2}): &sha256hash{}, common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, @@ -84,7 +88,7 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{ // PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum // contracts used in the Berlin release. -var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{ +var PrecompiledContractsBerlin = PrecompiledContracts{ common.BytesToAddress([]byte{0x1}): &ecrecover{}, common.BytesToAddress([]byte{0x2}): &sha256hash{}, common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, @@ -98,7 +102,7 @@ var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{ // PrecompiledContractsCancun contains the default set of pre-compiled Ethereum // contracts used in the Cancun release. -var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{ +var PrecompiledContractsCancun = PrecompiledContracts{ common.BytesToAddress([]byte{0x1}): &ecrecover{}, common.BytesToAddress([]byte{0x2}): &sha256hash{}, common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, @@ -113,7 +117,7 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{ // PrecompiledContractsPrague contains the set of pre-compiled Ethereum // contracts used in the Prague release. -var PrecompiledContractsPrague = map[common.Address]PrecompiledContract{ +var PrecompiledContractsPrague = PrecompiledContracts{ common.BytesToAddress([]byte{0x01}): &ecrecover{}, common.BytesToAddress([]byte{0x02}): &sha256hash{}, common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, @@ -169,7 +173,31 @@ func init() { } } -// ActivePrecompiles returns the precompiles enabled with the current configuration. +func activePrecompiledContracts(rules params.Rules) PrecompiledContracts { + switch { + case rules.IsVerkle: + return PrecompiledContractsVerkle + case rules.IsPrague: + return PrecompiledContractsPrague + case rules.IsCancun: + return PrecompiledContractsCancun + case rules.IsBerlin: + return PrecompiledContractsBerlin + case rules.IsIstanbul: + return PrecompiledContractsIstanbul + case rules.IsByzantium: + return PrecompiledContractsByzantium + default: + return PrecompiledContractsHomestead + } +} + +// ActivePrecompiledContracts returns a copy of precompiled contracts enabled with the current configuration. +func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts { + return maps.Clone(activePrecompiledContracts(rules)) +} + +// ActivePrecompiles returns the precompile addresses enabled with the current configuration. func ActivePrecompiles(rules params.Rules) []common.Address { switch { case rules.IsPrague: diff --git a/core/vm/evm.go b/core/vm/evm.go index 7617d843c7f9..a9c4ae9fe54d 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,24 +41,7 @@ type ( ) func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { - var precompiles map[common.Address]PrecompiledContract - switch { - case evm.chainRules.IsVerkle: - precompiles = PrecompiledContractsVerkle - case evm.chainRules.IsPrague: - precompiles = PrecompiledContractsPrague - case evm.chainRules.IsCancun: - precompiles = PrecompiledContractsCancun - case evm.chainRules.IsBerlin: - precompiles = PrecompiledContractsBerlin - case evm.chainRules.IsIstanbul: - precompiles = PrecompiledContractsIstanbul - case evm.chainRules.IsByzantium: - precompiles = PrecompiledContractsByzantium - default: - precompiles = PrecompiledContractsHomestead - } - p, ok := precompiles[addr] + p, ok := evm.precompiles[addr] return p, ok } @@ -129,22 +112,13 @@ type EVM struct { // available gas is calculated in gasCall* according to the 63/64 rule and later // applied in opCall*. callGasTemp uint64 + // precompiles holds the precompiled contracts for the current epoch + precompiles map[common.Address]PrecompiledContract } // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { - // If basefee tracking is disabled (eth_call, eth_estimateGas, etc), and no - // gas prices were specified, lower the basefee to 0 to avoid breaking EVM - // invariants (basefee < feecap) - if config.NoBaseFee { - if txCtx.GasPrice.BitLen() == 0 { - blockCtx.BaseFee = new(big.Int) - } - if txCtx.BlobFeeCap != nil && txCtx.BlobFeeCap.BitLen() == 0 { - blockCtx.BlobBaseFee = new(big.Int) - } - } evm := &EVM{ Context: blockCtx, TxContext: txCtx, @@ -153,10 +127,18 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } + evm.precompiles = activePrecompiledContracts(evm.chainRules) evm.interpreter = NewEVMInterpreter(evm) return evm } +// SetPrecompiles sets the precompiled contracts for the EVM. +// This method is only used through RPC calls. +// It is not thread-safe. +func (evm *EVM) SetPrecompiles(precompiles PrecompiledContracts) { + evm.precompiles = precompiles +} + // Reset resets the EVM with a new transaction context.Reset // This is not threadsafe and should only be done very cautiously. func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index ac3b59e97e8b..d43057dda27d 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -221,8 +221,16 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil) dirtyState = opts.State.Copy() - evm = vm.NewEVM(evmContext, msgContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true}) ) + // Lower the basefee to 0 to avoid breaking EVM + // invariants (basefee < feecap). + if msgContext.GasPrice.Sign() == 0 { + evmContext.BaseFee = new(big.Int) + } + if msgContext.BlobFeeCap != nil && msgContext.BlobFeeCap.BitLen() == 0 { + evmContext.BlobBaseFee = new(big.Int) + } + evm := vm.NewEVM(evmContext, msgContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true}) // Monitor the outer context and interrupt the EVM upon cancellation. To avoid // a dangling goroutine until the outer estimation finishes, create an internal // context for the lifetime of this method call. diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 9ee108d0f12f..a8289512069b 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "fmt" + "math/big" "os" "runtime" "sync" @@ -955,20 +956,31 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) // Apply the customization rules if required. if config != nil { - if err := config.StateOverrides.Apply(statedb); err != nil { + config.BlockOverrides.Apply(&vmctx) + rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time) + + precompiles := vm.ActivePrecompiledContracts(rules) + if err := config.StateOverrides.Apply(statedb, precompiles); err != nil { return nil, err } - config.BlockOverrides.Apply(&vmctx) } // Execute the trace if err := args.CallDefaults(api.backend.RPCGasCap(), vmctx.BaseFee, api.backend.ChainConfig().ChainID); err != nil { return nil, err } var ( - msg = args.ToMessage(vmctx.BaseFee) - tx = args.ToTransaction() + msg = args.ToMessage(vmctx.BaseFee, true, true) + tx = args.ToTransaction(types.LegacyTxType) traceConfig *TraceConfig ) + // Lower the basefee to 0 to avoid breaking EVM + // invariants (basefee < feecap). + if msg.GasPrice.Sign() == 0 { + vmctx.BaseFee = new(big.Int) + } + if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 { + vmctx.BlobBaseFee = new(big.Int) + } if config != nil { traceConfig = &config.TraceConfig } diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 2f3229cedcb5..1b7e26fb74f5 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -219,7 +219,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { t.Fatalf("can't create new node: %v", err) } // Create Ethereum Service - config := ðconfig.Config{Genesis: genesis} + config := ðconfig.Config{Genesis: genesis, RPCGasCap: 1000000} ethservice, err := eth.New(n, config) if err != nil { t.Fatalf("can't create new ethereum service: %v", err) diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index b1678b67664e..02b2598b37d2 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -328,9 +328,9 @@ func (o BlockOverrides) MarshalJSON() ([]byte, error) { Difficulty *hexutil.Big `json:"difficulty,omitempty"` Time hexutil.Uint64 `json:"time,omitempty"` GasLimit hexutil.Uint64 `json:"gasLimit,omitempty"` - Coinbase *common.Address `json:"coinbase,omitempty"` - Random *common.Hash `json:"random,omitempty"` - BaseFee *hexutil.Big `json:"baseFee,omitempty"` + Coinbase *common.Address `json:"feeRecipient,omitempty"` + Random *common.Hash `json:"prevRandao,omitempty"` + BaseFee *hexutil.Big `json:"baseFeePerGas,omitempty"` } output := override{ diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 59ad370146bb..36ea290a857e 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -57,7 +57,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { t.Fatalf("can't create new node: %v", err) } // Create Ethereum Service - config := ðconfig.Config{Genesis: genesis} + config := ðconfig.Config{Genesis: genesis, RPCGasCap: 1000000} ethservice, err := eth.New(n, config) if err != nil { t.Fatalf("can't create new ethereum service: %v", err) @@ -510,7 +510,7 @@ func TestBlockOverridesMarshal(t *testing.T) { bo: BlockOverrides{ Coinbase: common.HexToAddress("0x1111111111111111111111111111111111111111"), }, - want: `{"coinbase":"0x1111111111111111111111111111111111111111"}`, + want: `{"feeRecipient":"0x1111111111111111111111111111111111111111"}`, }, { bo: BlockOverrides{ @@ -520,7 +520,7 @@ func TestBlockOverridesMarshal(t *testing.T) { GasLimit: 4, BaseFee: big.NewInt(5), }, - want: `{"number":"0x1","difficulty":"0x2","time":"0x3","gasLimit":"0x4","baseFee":"0x5"}`, + want: `{"number":"0x1","difficulty":"0x2","time":"0x3","gasLimit":"0x4","baseFeePerGas":"0x5"}`, }, } { marshalled, err := json.Marshal(&tt.bo) diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index f3f9d1778ab0..ae3a58a98301 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -453,6 +453,7 @@ func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Ge TrieDirtyCache: 5, TrieTimeout: 60 * time.Minute, SnapshotCache: 5, + RPCGasCap: 1000000, StateScheme: rawdb.HashScheme, } var engine consensus.Engine = ethash.NewFaker() diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index aeb3e8adc289..79f94892c5d5 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -21,6 +21,7 @@ import ( "encoding/hex" "errors" "fmt" + "maps" "math/big" "strings" "time" @@ -474,7 +475,7 @@ func (api *PersonalAccountAPI) signTransaction(ctx context.Context, args *Transa return nil, err } // Assemble the transaction and sign with the wallet - tx := args.ToTransaction() + tx := args.ToTransaction(types.LegacyTxType) return wallet.SignTxWithPassphrase(account, passwd, tx, api.b.ChainConfig().ChainID) } @@ -523,7 +524,7 @@ func (api *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transac return nil, errors.New("nonce not specified") } // Before actually signing the transaction, ensure the transaction fee is reasonable. - tx := args.ToTransaction() + tx := args.ToTransaction(types.LegacyTxType) if err := checkTxFee(tx.GasPrice(), tx.Gas(), api.b.RPCTxFeeCap()); err != nil { return nil, err } @@ -968,22 +969,54 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp // if stateDiff is set, all diff will be applied first and then execute the call // message. type OverrideAccount struct { - Nonce *hexutil.Uint64 `json:"nonce"` - Code *hexutil.Bytes `json:"code"` - Balance *hexutil.Big `json:"balance"` - State map[common.Hash]common.Hash `json:"state"` - StateDiff map[common.Hash]common.Hash `json:"stateDiff"` + Nonce *hexutil.Uint64 `json:"nonce"` + Code *hexutil.Bytes `json:"code"` + Balance *hexutil.Big `json:"balance"` + State map[common.Hash]common.Hash `json:"state"` + StateDiff map[common.Hash]common.Hash `json:"stateDiff"` + MovePrecompileTo *common.Address `json:"movePrecompileToAddress"` } // StateOverride is the collection of overridden accounts. type StateOverride map[common.Address]OverrideAccount +func (diff *StateOverride) has(address common.Address) bool { + _, ok := (*diff)[address] + return ok +} + // Apply overrides the fields of specified accounts into the given state. -func (diff *StateOverride) Apply(statedb *state.StateDB) error { +func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.PrecompiledContracts) error { if diff == nil { return nil } + // Tracks destinations of precompiles that were moved. + dirtyAddrs := make(map[common.Address]struct{}) for addr, account := range *diff { + // If a precompile was moved to this address already, it can't be overridden. + if _, ok := dirtyAddrs[addr]; ok { + return fmt.Errorf("account %s has already been overridden by a precompile", addr.Hex()) + } + p, isPrecompile := precompiles[addr] + // The MoveTo feature makes it possible to move a precompile + // code to another address. If the target address is another precompile + // the code for the latter is lost for this session. + // Note the destination account is not cleared upon move. + if account.MovePrecompileTo != nil { + if !isPrecompile { + return fmt.Errorf("account %s is not a precompile", addr.Hex()) + } + // Refuse to move a precompile to an address that has been + // or will be overridden. + if diff.has(*account.MovePrecompileTo) { + return fmt.Errorf("account %s is already overridden", account.MovePrecompileTo.Hex()) + } + precompiles[*account.MovePrecompileTo] = p + dirtyAddrs[*account.MovePrecompileTo] = struct{}{} + } + if isPrecompile { + delete(precompiles, addr) + } // Override account nonce. if account.Nonce != nil { statedb.SetNonce(addr, uint64(*account.Nonce)) @@ -1020,45 +1053,78 @@ func (diff *StateOverride) Apply(statedb *state.StateDB) error { // BlockOverrides is a set of header fields to override. type BlockOverrides struct { - Number *hexutil.Big - Difficulty *hexutil.Big - Time *hexutil.Uint64 - GasLimit *hexutil.Uint64 - Coinbase *common.Address - Random *common.Hash - BaseFee *hexutil.Big - BlobBaseFee *hexutil.Big + Number *hexutil.Big + Difficulty *hexutil.Big // No-op if we're simulating post-merge calls. + Time *hexutil.Uint64 + GasLimit *hexutil.Uint64 + FeeRecipient *common.Address + PrevRandao *common.Hash + BaseFeePerGas *hexutil.Big + BlobBaseFee *hexutil.Big } // Apply overrides the given header fields into the given block context. -func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) { - if diff == nil { +func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) { + if o == nil { return } - if diff.Number != nil { - blockCtx.BlockNumber = diff.Number.ToInt() + if o.Number != nil { + blockCtx.BlockNumber = o.Number.ToInt() + } + if o.Difficulty != nil { + blockCtx.Difficulty = o.Difficulty.ToInt() + } + if o.Time != nil { + blockCtx.Time = uint64(*o.Time) + } + if o.GasLimit != nil { + blockCtx.GasLimit = uint64(*o.GasLimit) + } + if o.FeeRecipient != nil { + blockCtx.Coinbase = *o.FeeRecipient } - if diff.Difficulty != nil { - blockCtx.Difficulty = diff.Difficulty.ToInt() + if o.PrevRandao != nil { + blockCtx.Random = o.PrevRandao } - if diff.Time != nil { - blockCtx.Time = uint64(*diff.Time) + if o.BaseFeePerGas != nil { + blockCtx.BaseFee = o.BaseFeePerGas.ToInt() } - if diff.GasLimit != nil { - blockCtx.GasLimit = uint64(*diff.GasLimit) + if o.BlobBaseFee != nil { + blockCtx.BlobBaseFee = o.BlobBaseFee.ToInt() } - if diff.Coinbase != nil { - blockCtx.Coinbase = *diff.Coinbase +} + +// MakeHeader returns a new header object with the overridden +// fields. +// Note: MakeHeader ignores BlobBaseFee if set. That's because +// header has no such field. +func (o *BlockOverrides) MakeHeader(header *types.Header) *types.Header { + if o == nil { + return header + } + h := types.CopyHeader(header) + if o.Number != nil { + h.Number = o.Number.ToInt() + } + if o.Difficulty != nil { + h.Difficulty = o.Difficulty.ToInt() + } + if o.Time != nil { + h.Time = uint64(*o.Time) + } + if o.GasLimit != nil { + h.GasLimit = uint64(*o.GasLimit) } - if diff.Random != nil { - blockCtx.Random = diff.Random + if o.FeeRecipient != nil { + h.Coinbase = *o.FeeRecipient } - if diff.BaseFee != nil { - blockCtx.BaseFee = diff.BaseFee.ToInt() + if o.PrevRandao != nil { + h.MixDigest = *o.PrevRandao } - if diff.BlobBaseFee != nil { - blockCtx.BlobBaseFee = diff.BlobBaseFee.ToInt() + if o.BaseFeePerGas != nil { + h.BaseFee = o.BaseFeePerGas.ToInt() } + return h } // ChainContextBackend provides methods required to implement ChainContext. @@ -1094,9 +1160,16 @@ func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.H } func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { - if err := overrides.Apply(state); err != nil { + blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) + if blockOverrides != nil { + blockOverrides.Apply(&blockCtx) + } + rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) + precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules)) + if err := overrides.Apply(state, precompiles); err != nil { return nil, err } + // Setup context so it may be cancelled the call has completed // or, in case of unmetered gas, setup a context with a timeout. var cancel context.CancelFunc @@ -1108,18 +1181,32 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S // Make sure the context is cancelled when the call has completed // this makes sure resources are cleaned up. defer cancel() + return applyMessage(ctx, b, args, state, header, timeout, new(core.GasPool).AddGas(globalGasCap), &blockCtx, &vm.Config{NoBaseFee: true}, precompiles, true) +} +func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, timeout time.Duration, gp *core.GasPool, blockContext *vm.BlockContext, vmConfig *vm.Config, precompiles vm.PrecompiledContracts, skipChecks bool) (*core.ExecutionResult, error) { // Get a new instance of the EVM. - blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) - if blockOverrides != nil { - blockOverrides.Apply(&blockCtx) - } - if err := args.CallDefaults(globalGasCap, blockCtx.BaseFee, b.ChainConfig().ChainID); err != nil { + if err := args.CallDefaults(gp.Gas(), blockContext.BaseFee, b.ChainConfig().ChainID); err != nil { return nil, err } - msg := args.ToMessage(blockCtx.BaseFee) - evm := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx) + msg := args.ToMessage(header.BaseFee, skipChecks, skipChecks) + // Lower the basefee to 0 to avoid breaking EVM + // invariants (basefee < feecap). + if msg.GasPrice.Sign() == 0 { + blockContext.BaseFee = new(big.Int) + } + if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 { + blockContext.BlobBaseFee = new(big.Int) + } + evm := b.GetEVM(ctx, msg, state, header, vmConfig, blockContext) + if precompiles != nil { + evm.SetPrecompiles(precompiles) + } + + return applyMessageWithEVM(ctx, evm, msg, state, timeout, gp) +} +func applyMessageWithEVM(ctx context.Context, evm *vm.EVM, msg *core.Message, state *state.StateDB, timeout time.Duration, gp *core.GasPool) (*core.ExecutionResult, error) { // Wait for the context to be done and cancel the evm. Even if the // EVM has finished, cancelling may be done (repeatedly) go func() { @@ -1128,7 +1215,6 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S }() // Execute the message. - gp := new(core.GasPool).AddGas(math.MaxUint64) result, err := core.ApplyMessage(evm, msg, gp) if err := state.Error(); err != nil { return nil, err @@ -1151,7 +1237,6 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash if state == nil || err != nil { return nil, err } - return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap) } @@ -1177,6 +1262,41 @@ func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockN return result.Return(), result.Err } +// SimulateV1 executes series of transactions on top of a base state. +// The transactions are packed into blocks. For each block, block header +// fields can be overridden. The state can also be overridden prior to +// execution of each block. +// +// Note, this function doesn't make any changes in the state/blockchain and is +// useful to execute and retrieve values. +func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrOrHash *rpc.BlockNumberOrHash) ([]map[string]interface{}, error) { + if len(opts.BlockStateCalls) == 0 { + return nil, &invalidParamsError{message: "empty input"} + } else if len(opts.BlockStateCalls) > maxSimulateBlocks { + return nil, &clientLimitExceededError{message: "too many blocks"} + } + if blockNrOrHash == nil { + n := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) + blockNrOrHash = &n + } + state, base, err := api.b.StateAndHeaderByNumberOrHash(ctx, *blockNrOrHash) + if state == nil || err != nil { + return nil, err + } + sim := &simulator{ + b: api.b, + state: state, + base: base, + chainConfig: api.b.ChainConfig(), + // Each tx and all the series of txes shouldn't consume more gas than cap + gp: new(core.GasPool).AddGas(api.b.RPCGasCap()), + traceTransfers: opts.TraceTransfers, + validate: opts.Validation, + fullTx: opts.ReturnFullTransactions, + } + return sim.execute(ctx, opts.BlockStateCalls) +} + // DoEstimateGas returns the lowest possible gas limit that allows the transaction to run // successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if // there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil & @@ -1187,7 +1307,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr if state == nil || err != nil { return 0, err } - if err = overrides.Apply(state); err != nil { + if err := overrides.Apply(state, nil); err != nil { return 0, err } // Construct the gas estimator option from the user input @@ -1206,7 +1326,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil { return 0, err } - call := args.ToMessage(header.BaseFee) + call := args.ToMessage(header.BaseFee, true, true) // Run the gas estimation and wrap any revertals into a custom return estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) @@ -1546,15 +1666,23 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH statedb := db.Copy() // Set the accesslist to the last al args.AccessList = &accessList - msg := args.ToMessage(header.BaseFee) + msg := args.ToMessage(header.BaseFee, true, true) // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true} vmenv := b.GetEVM(ctx, msg, statedb, header, &config, nil) + // Lower the basefee to 0 to avoid breaking EVM + // invariants (basefee < feecap). + if msg.GasPrice.Sign() == 0 { + vmenv.Context.BaseFee = new(big.Int) + } + if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 { + vmenv.Context.BlobBaseFee = new(big.Int) + } res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { - return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction().Hash(), err) + return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err) } if tracer.Equal(prevTracer) { return accessList, res.UsedGas, res.Err, nil @@ -1823,7 +1951,7 @@ func (api *TransactionAPI) SendTransaction(ctx context.Context, args Transaction return common.Hash{}, err } // Assemble the transaction and sign with the wallet - tx := args.ToTransaction() + tx := args.ToTransaction(types.LegacyTxType) signed, err := wallet.SignTx(account, tx, api.b.ChainConfig().ChainID) if err != nil { @@ -1843,7 +1971,7 @@ func (api *TransactionAPI) FillTransaction(ctx context.Context, args Transaction return nil, err } // Assemble the transaction and obtain rlp - tx := args.ToTransaction() + tx := args.ToTransaction(types.LegacyTxType) data, err := tx.MarshalBinary() if err != nil { return nil, err @@ -1911,7 +2039,7 @@ func (api *TransactionAPI) SignTransaction(ctx context.Context, args Transaction return nil, err } // Before actually sign the transaction, ensure the transaction fee is reasonable. - tx := args.ToTransaction() + tx := args.ToTransaction(types.LegacyTxType) if err := checkTxFee(tx.GasPrice(), tx.Gas(), api.b.RPCTxFeeCap()); err != nil { return nil, err } @@ -1969,7 +2097,7 @@ func (api *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, if err := sendArgs.setDefaults(ctx, api.b, false); err != nil { return common.Hash{}, err } - matchTx := sendArgs.ToTransaction() + matchTx := sendArgs.ToTransaction(types.LegacyTxType) // Before replacing the old transaction, ensure the _new_ transaction fee is reasonable. var price = matchTx.GasPrice() @@ -1999,7 +2127,7 @@ func (api *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, if gasLimit != nil && *gasLimit != 0 { sendArgs.Gas = gasLimit } - signedTx, err := api.sign(sendArgs.from(), sendArgs.ToTransaction()) + signedTx, err := api.sign(sendArgs.from(), sendArgs.ToTransaction(types.LegacyTxType)) if err != nil { return common.Hash{}, err } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 3c5da840d30a..f2dd93e4ac0a 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -24,17 +24,16 @@ import ( "encoding/json" "errors" "fmt" + "maps" "math/big" "os" "path/filepath" "reflect" "slices" + "strings" "testing" "time" - "github.com/holiman/uint256" - "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -56,6 +55,9 @@ import ( "github.com/ethereum/go-ethereum/internal/blocktest" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/triedb" + "github.com/holiman/uint256" + "github.com/stretchr/testify/require" ) func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainConfig) { @@ -502,7 +504,8 @@ func (b testBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc } panic("unknown type rpc.BlockNumberOrHash") } -func (b testBackend) CurrentHeader() *types.Header { return b.chain.CurrentBlock() } + +func (b testBackend) CurrentHeader() *types.Header { return b.chain.CurrentHeader() } func (b testBackend) CurrentBlock() *types.Header { return b.chain.CurrentBlock() } func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { if number == rpc.LatestBlockNumber { @@ -814,6 +817,7 @@ func TestCall(t *testing.T) { })) randomAccounts := newAccounts(3) var testSuite = []struct { + name string blockNumber rpc.BlockNumber overrides StateOverride call TransactionArgs @@ -823,6 +827,7 @@ func TestCall(t *testing.T) { }{ // transfer on genesis { + name: "transfer-on-genesis", blockNumber: rpc.BlockNumber(0), call: TransactionArgs{ From: &accounts[0].addr, @@ -834,6 +839,7 @@ func TestCall(t *testing.T) { }, // transfer on the head { + name: "transfer-on-the-head", blockNumber: rpc.BlockNumber(genBlocks), call: TransactionArgs{ From: &accounts[0].addr, @@ -845,6 +851,7 @@ func TestCall(t *testing.T) { }, // transfer on a non-existent block, error expects { + name: "transfer-non-existent-block", blockNumber: rpc.BlockNumber(genBlocks + 1), call: TransactionArgs{ From: &accounts[0].addr, @@ -855,6 +862,7 @@ func TestCall(t *testing.T) { }, // transfer on the latest block { + name: "transfer-latest-block", blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{ From: &accounts[0].addr, @@ -866,6 +874,7 @@ func TestCall(t *testing.T) { }, // Call which can only succeed if state is state overridden { + name: "state-override-success", blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{ From: &randomAccounts[0].addr, @@ -879,6 +888,7 @@ func TestCall(t *testing.T) { }, // Invalid call without state overriding { + name: "insufficient-funds-simple", blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{ From: &randomAccounts[0].addr, @@ -904,6 +914,7 @@ func TestCall(t *testing.T) { // } // } { + name: "simple-contract-call", blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{ From: &randomAccounts[0].addr, @@ -920,6 +931,7 @@ func TestCall(t *testing.T) { }, // Block overrides should work { + name: "block-override", blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{ From: &accounts[1].addr, @@ -932,8 +944,36 @@ func TestCall(t *testing.T) { blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, want: "0x000000000000000000000000000000000000000000000000000000000000000b", }, + // Clear storage trie + { + name: "clear-storage-trie", + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[1].addr, + // Yul: + // object "Test" { + // code { + // let dad := 0x0000000000000000000000000000000000000dad + // if eq(balance(dad), 0) { + // revert(0, 0) + // } + // let slot := sload(0) + // mstore(0, slot) + // return(0, 32) + // } + // } + Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"), + }, + overrides: StateOverride{ + dad: OverrideAccount{ + State: map[common.Hash]common.Hash{}, + }, + }, + want: "0x0000000000000000000000000000000000000000000000000000000000000000", + }, // Invalid blob tx { + name: "invalid-blob-tx", blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{ From: &accounts[1].addr, @@ -944,6 +984,7 @@ func TestCall(t *testing.T) { }, // BLOBHASH opcode { + name: "blobhash-opcode", blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{ From: &accounts[1].addr, @@ -985,28 +1026,1175 @@ func TestCall(t *testing.T) { want: "0x0000000000000000000000000000000000000000000000000000000000000000", }, } - for i, tc := range testSuite { + for _, tc := range testSuite { result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) if tc.expectErr != nil { if err == nil { - t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) + t.Errorf("test %s: want error %v, have nothing", tc.name, tc.expectErr) continue } if !errors.Is(err, tc.expectErr) { // Second try if !reflect.DeepEqual(err, tc.expectErr) { - t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) + t.Errorf("test %s: error mismatch, want %v, have %v", tc.name, tc.expectErr, err) } } continue } if err != nil { - t.Errorf("test %d: want no error, have %v", i, err) + t.Errorf("test %s: want no error, have %v", tc.name, err) continue } if !reflect.DeepEqual(result.String(), tc.want) { - t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, result.String(), tc.want) + t.Errorf("test %s, result mismatch, have\n%v\n, want\n%v\n", tc.name, result.String(), tc.want) + } + } +} + +func TestSimulateV1(t *testing.T) { + t.Parallel() + // Initialize test accounts + var ( + accounts = newAccounts(3) + fixedAccount = newTestAccount() + genBlocks = 10 + signer = types.HomesteadSigner{} + cac = common.HexToAddress("0x0000000000000000000000000000000000000cac") + bab = common.HexToAddress("0x0000000000000000000000000000000000000bab") + coinbase = "0x000000000000000000000000000000000000ffff" + genesis = &core.Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + accounts[2].addr: {Balance: big.NewInt(params.Ether)}, + // Yul: + // object "Test" { + // code { + // let dad := 0x0000000000000000000000000000000000000dad + // selfdestruct(dad) + // } + // } + cac: {Balance: big.NewInt(params.Ether), Code: common.Hex2Bytes("610dad80ff")}, + bab: { + Balance: big.NewInt(1), + // object "Test" { + // code { + // let value1 := sload(1) + // let value2 := sload(2) + // + // // Shift value1 by 128 bits to the left by multiplying it with 2^128 + // value1 := mul(value1, 0x100000000000000000000000000000000) + // + // // Concatenate value1 and value2 + // let concatenatedValue := add(value1, value2) + // + // // Store the result in memory and return it + // mstore(0, concatenatedValue) + // return(0, 0x20) + // } + // } + Code: common.FromHex("0x600154600254700100000000000000000000000000000000820291508082018060005260206000f3"), + Storage: map[common.Hash]common.Hash{ + common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(10)), + common.BigToHash(big.NewInt(2)): common.BigToHash(big.NewInt(12)), + }, + }, + }, } + sha256Address = common.BytesToAddress([]byte{0x02}) + ) + api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, ethash.NewFaker(), func(i int, b *core.BlockGen) { + b.SetCoinbase(common.HexToAddress(coinbase)) + // Transfer from account[0] to account[1] + // value: 1000 wei + // fee: 0 wei + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: uint64(i), + To: &accounts[1].addr, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: b.BaseFee(), + Data: nil, + }), signer, accounts[0].key) + b.AddTx(tx) + })) + var ( + randomAccounts = newAccounts(4) + latest = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) + includeTransfers = true + validation = true + ) + type log struct { + Address common.Address `json:"address"` + Topics []common.Hash `json:"topics"` + Data hexutil.Bytes `json:"data"` + BlockNumber hexutil.Uint64 `json:"blockNumber"` + // Skip txHash + //TxHash common.Hash `json:"transactionHash" gencodec:"required"` + TxIndex hexutil.Uint `json:"transactionIndex"` + //BlockHash common.Hash `json:"blockHash"` + Index hexutil.Uint `json:"logIndex"` + } + type callErr struct { + Message string + Code int + } + type callRes struct { + ReturnValue string `json:"returnData"` + Error callErr + Logs []log + GasUsed string + Status string + } + type blockRes struct { + Number string + //Hash string + // Ignore timestamp + GasLimit string + GasUsed string + Miner string + BaseFeePerGas string + Calls []callRes + } + var testSuite = []struct { + name string + blocks []simBlock + tag rpc.BlockNumberOrHash + includeTransfers *bool + validation *bool + expectErr error + want []blockRes + }{ + // State build-up over calls: + // First value transfer OK after state override. + // Second one should succeed because of first transfer. + { + name: "simple", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(1000))}, + }, + Calls: []TransactionArgs{{ + From: &randomAccounts[0].addr, + To: &randomAccounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, { + From: &randomAccounts[1].addr, + To: &randomAccounts[2].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, { + To: &randomAccounts[3].addr, + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0xf618", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0x5208", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x", + GasUsed: "0x5208", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x", + GasUsed: "0x5208", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, { + // State build-up over blocks. + name: "simple-multi-block", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(2000))}, + }, + Calls: []TransactionArgs{ + { + From: &randomAccounts[0].addr, + To: &randomAccounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, { + From: &randomAccounts[0].addr, + To: &randomAccounts[3].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + }, + }, { + StateOverrides: &StateOverride{ + randomAccounts[3].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))}, + }, + Calls: []TransactionArgs{ + { + From: &randomAccounts[1].addr, + To: &randomAccounts[2].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + }, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0xa410", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0x5208", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x", + GasUsed: "0x5208", + Logs: []log{}, + Status: "0x1", + }}, + }, { + Number: "0xc", + GasLimit: "0x47e7c4", + GasUsed: "0x5208", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0x5208", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, { + // insufficient funds + name: "insufficient-funds", + tag: latest, + blocks: []simBlock{{ + Calls: []TransactionArgs{{ + From: &randomAccounts[0].addr, + To: &randomAccounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }}, + }}, + want: nil, + expectErr: &invalidTxError{Message: fmt.Sprintf("err: insufficient funds for gas * price + value: address %s have 0 want 1000 (supplied gas 4712388)", randomAccounts[0].addr.String()), Code: errCodeInsufficientFunds}, + }, { + // EVM error + name: "evm-error", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[2].addr: OverrideAccount{Code: hex2Bytes("f3")}, + }, + Calls: []TransactionArgs{{ + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0x47e7c4", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + Error: callErr{Message: "stack underflow (0 <=> 2)", Code: errCodeVMError}, + GasUsed: "0x47e7c4", + Logs: []log{}, + Status: "0x0", + }}, + }}, + }, { + // Block overrides should work, each call is simulated on a different block number + name: "block-overrides", + tag: latest, + blocks: []simBlock{{ + BlockOverrides: &BlockOverrides{ + Number: (*hexutil.Big)(big.NewInt(11)), + FeeRecipient: &cac, + }, + Calls: []TransactionArgs{ + { + From: &accounts[0].addr, + Input: &hexutil.Bytes{ + 0x43, // NUMBER + 0x60, 0x00, 0x52, // MSTORE offset 0 + 0x60, 0x20, 0x60, 0x00, 0xf3, // RETURN + }, + }, + }, + }, { + BlockOverrides: &BlockOverrides{ + Number: (*hexutil.Big)(big.NewInt(12)), + }, + Calls: []TransactionArgs{{ + From: &accounts[1].addr, + Input: &hexutil.Bytes{ + 0x43, // NUMBER + 0x60, 0x00, 0x52, // MSTORE offset 0 + 0x60, 0x20, 0x60, 0x00, 0xf3, + }, + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0xe891", + Miner: strings.ToLower(cac.String()), + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000b", + GasUsed: "0xe891", + Logs: []log{}, + Status: "0x1", + }}, + }, { + Number: "0xc", + GasLimit: "0x47e7c4", + GasUsed: "0xe891", + Miner: strings.ToLower(cac.String()), + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000c", + GasUsed: "0xe891", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + // Block numbers must be in order. + { + name: "block-number-order", + tag: latest, + blocks: []simBlock{{ + BlockOverrides: &BlockOverrides{ + Number: (*hexutil.Big)(big.NewInt(12)), + }, + Calls: []TransactionArgs{{ + From: &accounts[1].addr, + Input: &hexutil.Bytes{ + 0x43, // NUMBER + 0x60, 0x00, 0x52, // MSTORE offset 0 + 0x60, 0x20, 0x60, 0x00, 0xf3, // RETURN + }, + }}, + }, { + BlockOverrides: &BlockOverrides{ + Number: (*hexutil.Big)(big.NewInt(11)), + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + Input: &hexutil.Bytes{ + 0x43, // NUMBER + 0x60, 0x00, 0x52, // MSTORE offset 0 + 0x60, 0x20, 0x60, 0x00, 0xf3, // RETURN + }, + }}, + }}, + want: []blockRes{}, + expectErr: &invalidBlockNumberError{message: "block numbers must be in order: 11 <= 12"}, + }, + // Test on solidity storage example. Set value in one call, read in next. + { + name: "storage-contract", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[2].addr: OverrideAccount{ + Code: hex2Bytes("608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea2646970667358221220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033"), + }, + }, + Calls: []TransactionArgs{{ + // Set value to 5 + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + Input: hex2Bytes("6057361d0000000000000000000000000000000000000000000000000000000000000005"), + }, { + // Read value + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + Input: hex2Bytes("2e64cec1"), + }, + }, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0x10683", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0xaacc", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x0000000000000000000000000000000000000000000000000000000000000005", + GasUsed: "0x5bb7", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + // Test logs output. + { + name: "logs", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[2].addr: OverrideAccount{ + // Yul code: + // object "Test" { + // code { + // let hash:u256 := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + // log1(0, 0, hash) + // return (0, 0) + // } + // } + Code: hex2Bytes("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80600080a1600080f3"), + }, + }, + Calls: []TransactionArgs{{ + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0x5508", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + Logs: []log{{ + Address: randomAccounts[2].addr, + Topics: []common.Hash{common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")}, + BlockNumber: hexutil.Uint64(11), + Data: hexutil.Bytes{}, + }}, + GasUsed: "0x5508", + Status: "0x1", + }}, + }}, + }, + // Test ecrecover override + { + name: "ecrecover-override", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[2].addr: OverrideAccount{ + // Yul code that returns ecrecover(0, 0, 0, 0). + // object "Test" { + // code { + // // Free memory pointer + // let free_ptr := mload(0x40) + // + // // Initialize inputs with zeros + // mstore(free_ptr, 0) // Hash + // mstore(add(free_ptr, 0x20), 0) // v + // mstore(add(free_ptr, 0x40), 0) // r + // mstore(add(free_ptr, 0x60), 0) // s + // + // // Call ecrecover precompile (at address 1) with all 0 inputs + // let success := staticcall(gas(), 1, free_ptr, 0x80, free_ptr, 0x20) + // + // // Check if the call was successful + // if eq(success, 0) { + // revert(0, 0) + // } + // + // // Return the recovered address + // return(free_ptr, 0x14) + // } + // } + Code: hex2Bytes("6040516000815260006020820152600060408201526000606082015260208160808360015afa60008103603157600080fd5b601482f3"), + }, + common.BytesToAddress([]byte{0x01}): OverrideAccount{ + // Yul code that returns the address of the caller. + // object "Test" { + // code { + // let c := caller() + // mstore(0, c) + // return(0xc, 0x14) + // } + // } + Code: hex2Bytes("33806000526014600cf3"), + }, + }, + Calls: []TransactionArgs{{ + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0x52f6", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + // Caller is in this case the contract that invokes ecrecover. + ReturnValue: strings.ToLower(randomAccounts[2].addr.String()), + GasUsed: "0x52f6", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + // Test moving the sha256 precompile. + { + name: "precompile-move", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + sha256Address: OverrideAccount{ + // Yul code that returns the calldata. + // object "Test" { + // code { + // let size := calldatasize() // Get the size of the calldata + // + // // Allocate memory to store the calldata + // let memPtr := msize() + // + // // Copy calldata to memory + // calldatacopy(memPtr, 0, size) + // + // // Return the calldata from memory + // return(memPtr, size) + // } + // } + Code: hex2Bytes("365981600082378181f3"), + MovePrecompileTo: &randomAccounts[2].addr, + }, + }, + Calls: []TransactionArgs{{ + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + Input: hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"), + }, { + From: &randomAccounts[0].addr, + To: &sha256Address, + Input: hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"), + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0xa58c", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5", + GasUsed: "0x52dc", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x0000000000000000000000000000000000000000000000000000000000000001", + GasUsed: "0x52b0", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + // Test ether transfers. + { + name: "transfer-logs", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[0].addr: OverrideAccount{ + Balance: newRPCBalance(big.NewInt(100)), + // Yul code that transfers 100 wei to address passed in calldata: + // object "Test" { + // code { + // let recipient := shr(96, calldataload(0)) + // let value := 100 + // let success := call(gas(), recipient, value, 0, 0, 0, 0) + // if eq(success, 0) { + // revert(0, 0) + // } + // } + // } + Code: hex2Bytes("60003560601c606460008060008084865af160008103601d57600080fd5b505050"), + }, + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[0].addr, + Value: (*hexutil.Big)(big.NewInt(50)), + Input: hex2Bytes(strings.TrimPrefix(fixedAccount.addr.String(), "0x")), + }}, + }}, + includeTransfers: &includeTransfers, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0x77dc", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0x77dc", + Logs: []log{{ + Address: transferAddress, + Topics: []common.Hash{ + transferTopic, + addressToHash(accounts[0].addr), + addressToHash(randomAccounts[0].addr), + }, + Data: hexutil.Bytes(common.BigToHash(big.NewInt(50)).Bytes()), + BlockNumber: hexutil.Uint64(11), + }, { + Address: transferAddress, + Topics: []common.Hash{ + transferTopic, + addressToHash(randomAccounts[0].addr), + addressToHash(fixedAccount.addr), + }, + Data: hexutil.Bytes(common.BigToHash(big.NewInt(100)).Bytes()), + BlockNumber: hexutil.Uint64(11), + Index: hexutil.Uint(1), + }}, + Status: "0x1", + }}, + }}, + }, + // Tests selfdestructed contract. + { + name: "selfdestruct", + tag: latest, + blocks: []simBlock{{ + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &cac, + }, { + From: &accounts[0].addr, + // Check that cac is selfdestructed and balance transferred to dad. + // object "Test" { + // code { + // let cac := 0x0000000000000000000000000000000000000cac + // let dad := 0x0000000000000000000000000000000000000dad + // if gt(balance(cac), 0) { + // revert(0, 0) + // } + // if gt(extcodesize(cac), 0) { + // revert(0, 0) + // } + // if eq(balance(dad), 0) { + // revert(0, 0) + // } + // } + // } + Input: hex2Bytes("610cac610dad600082311115601357600080fd5b6000823b1115602157600080fd5b6000813103602e57600080fd5b5050"), + }}, + }, { + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + Input: hex2Bytes("610cac610dad600082311115601357600080fd5b6000823b1115602157600080fd5b6000813103602e57600080fd5b5050"), + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0x1b83f", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0xd166", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x", + GasUsed: "0xe6d9", + Logs: []log{}, + Status: "0x1", + }}, + }, { + Number: "0xc", + GasLimit: "0x47e7c4", + GasUsed: "0xe6d9", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0xe6d9", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + // Enable validation checks. + { + name: "validation-checks", + tag: latest, + blocks: []simBlock{{ + Calls: []TransactionArgs{{ + From: &accounts[2].addr, + To: &cac, + Nonce: newUint64(2), + }}, + }}, + validation: &validation, + want: nil, + expectErr: &invalidTxError{Message: fmt.Sprintf("err: nonce too high: address %s, tx: 2 state: 0 (supplied gas 4712388)", accounts[2].addr), Code: errCodeNonceTooHigh}, + }, + // Contract sends tx in validation mode. + { + name: "validation-checks-from-contract", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[2].addr: OverrideAccount{ + Balance: newRPCBalance(big.NewInt(2098640803896784)), + Code: hex2Bytes("00"), + Nonce: newUint64(1), + }, + }, + Calls: []TransactionArgs{{ + From: &randomAccounts[2].addr, + To: &cac, + Nonce: newUint64(1), + MaxFeePerGas: newInt(233138868), + MaxPriorityFeePerGas: newInt(1), + }}, + }}, + validation: &validation, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0xd166", + Miner: coinbase, + BaseFeePerGas: "0xde56ab3", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0xd166", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + // Successful validation + { + name: "validation-checks-success", + tag: latest, + blocks: []simBlock{{ + BlockOverrides: &BlockOverrides{ + BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)), + }, + StateOverrides: &StateOverride{ + randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(10000000))}, + }, + Calls: []TransactionArgs{{ + From: &randomAccounts[0].addr, + To: &randomAccounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + MaxFeePerGas: (*hexutil.Big)(big.NewInt(2)), + }}, + }}, + validation: &validation, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0x5208", + Miner: coinbase, + BaseFeePerGas: "0x1", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0x5208", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + // Clear storage. + { + name: "clear-storage", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[2].addr: { + Code: newBytes(genesis.Alloc[bab].Code), + StateDiff: map[common.Hash]common.Hash{ + common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(2)), + common.BigToHash(big.NewInt(2)): common.BigToHash(big.NewInt(3)), + }, + }, + bab: { + State: map[common.Hash]common.Hash{ + common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(1)), + }, + }, + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + }, { + From: &accounts[0].addr, + To: &bab, + }}, + }, { + StateOverrides: &StateOverride{ + randomAccounts[2].addr: { + State: map[common.Hash]common.Hash{ + common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(5)), + }, + }, + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0xc542", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x0000000000000000000000000000000200000000000000000000000000000003", + GasUsed: "0x62a1", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x0000000000000000000000000000000100000000000000000000000000000000", + GasUsed: "0x62a1", + Logs: []log{}, + Status: "0x1", + }}, + }, { + Number: "0xc", + GasLimit: "0x47e7c4", + GasUsed: "0x62a1", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x0000000000000000000000000000000500000000000000000000000000000000", + GasUsed: "0x62a1", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + { + name: "blockhash-opcode", + tag: latest, + blocks: []simBlock{{ + BlockOverrides: &BlockOverrides{ + Number: (*hexutil.Big)(big.NewInt(12)), + }, + StateOverrides: &StateOverride{ + randomAccounts[2].addr: { + Code: hex2Bytes("600035804060008103601057600080fd5b5050"), + }, + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + // Phantom block after base. + Input: uint256ToBytes(uint256.NewInt(11)), + }, { + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + // Canonical block. + Input: uint256ToBytes(uint256.NewInt(8)), + }, { + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + // base block. + Input: uint256ToBytes(uint256.NewInt(10)), + }}, + }, { + BlockOverrides: &BlockOverrides{ + Number: (*hexutil.Big)(big.NewInt(16)), + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + // blocks[0] + Input: uint256ToBytes(uint256.NewInt(12)), + }, { + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + // Phantom after blocks[0] + Input: uint256ToBytes(uint256.NewInt(13)), + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0x0", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{}, + }, { + Number: "0xc", + GasLimit: "0x47e7c4", + GasUsed: "0xf864", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0x52cc", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x", + GasUsed: "0x52cc", + Logs: []log{}, + Status: "0x1", + }, { + + ReturnValue: "0x", + GasUsed: "0x52cc", + Logs: []log{}, + Status: "0x1", + }}, + }, { + Number: "0xd", + GasLimit: "0x47e7c4", + GasUsed: "0x0", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{}, + }, { + Number: "0xe", + GasLimit: "0x47e7c4", + GasUsed: "0x0", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{}, + }, { + Number: "0xf", + GasLimit: "0x47e7c4", + GasUsed: "0x0", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{}, + }, { + Number: "0x10", + GasLimit: "0x47e7c4", + GasUsed: "0xa598", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0x52cc", + Logs: []log{}, + Status: "0x1", + }, { + + ReturnValue: "0x", + GasUsed: "0x52cc", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + { + name: "basefee-non-validation", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[2].addr: { + // Yul code: + // object "Test" { + // code { + // // Get the gas price from the transaction + // let gasPrice := gasprice() + // + // // Get the base fee from the block + // let baseFee := basefee() + // + // // Store gasPrice and baseFee in memory + // mstore(0x0, gasPrice) + // mstore(0x20, baseFee) + // + // // Return the data + // return(0x0, 0x40) + // } + // } + Code: hex2Bytes("3a489060005260205260406000f3"), + }, + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + // 0 gas price + }, { + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + // non-zero gas price + MaxPriorityFeePerGas: newInt(1), + MaxFeePerGas: newInt(2), + }, + }, + }, { + BlockOverrides: &BlockOverrides{ + BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)), + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + // 0 gas price + }, { + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + // non-zero gas price + MaxPriorityFeePerGas: newInt(1), + MaxFeePerGas: newInt(2), + }, + }, + }, { + // Base fee should be 0 to zero even if it was set in previous block. + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + }}, + }}, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0xa44e", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + GasUsed: "0x5227", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", + GasUsed: "0x5227", + Logs: []log{}, + Status: "0x1", + }}, + }, { + Number: "0xc", + GasLimit: "0x47e7c4", + GasUsed: "0xa44e", + Miner: coinbase, + BaseFeePerGas: "0x1", + Calls: []callRes{{ + ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + GasUsed: "0x5227", + Logs: []log{}, + Status: "0x1", + }, { + ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001", + GasUsed: "0x5227", + Logs: []log{}, + Status: "0x1", + }}, + }, { + Number: "0xd", + GasLimit: "0x47e7c4", + GasUsed: "0x5227", + Miner: coinbase, + BaseFeePerGas: "0x0", + Calls: []callRes{{ + ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + GasUsed: "0x5227", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, { + name: "basefee-validation-mode", + tag: latest, + blocks: []simBlock{{ + StateOverrides: &StateOverride{ + randomAccounts[2].addr: { + // Yul code: + // object "Test" { + // code { + // // Get the gas price from the transaction + // let gasPrice := gasprice() + // + // // Get the base fee from the block + // let baseFee := basefee() + // + // // Store gasPrice and baseFee in memory + // mstore(0x0, gasPrice) + // mstore(0x20, baseFee) + // + // // Return the data + // return(0x0, 0x40) + // } + // } + Code: hex2Bytes("3a489060005260205260406000f3"), + }, + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + MaxFeePerGas: newInt(233138868), + MaxPriorityFeePerGas: newInt(1), + }}, + }}, + validation: &validation, + want: []blockRes{{ + Number: "0xb", + GasLimit: "0x47e7c4", + GasUsed: "0x5227", + Miner: coinbase, + BaseFeePerGas: "0xde56ab3", + Calls: []callRes{{ + ReturnValue: "0x000000000000000000000000000000000000000000000000000000000de56ab4000000000000000000000000000000000000000000000000000000000de56ab3", + GasUsed: "0x5227", + Logs: []log{}, + Status: "0x1", + }}, + }}, + }, + } + + for _, tc := range testSuite { + t.Run(tc.name, func(t *testing.T) { + opts := simOpts{BlockStateCalls: tc.blocks} + if tc.includeTransfers != nil && *tc.includeTransfers { + opts.TraceTransfers = true + } + if tc.validation != nil && *tc.validation { + opts.Validation = true + } + result, err := api.SimulateV1(context.Background(), opts, &tc.tag) + if tc.expectErr != nil { + if err == nil { + t.Fatalf("test %s: want error %v, have nothing", tc.name, tc.expectErr) + } + if !errors.Is(err, tc.expectErr) { + // Second try + if !reflect.DeepEqual(err, tc.expectErr) { + t.Errorf("test %s: error mismatch, want %v, have %v", tc.name, tc.expectErr, err) + } + } + return + } + if err != nil { + t.Fatalf("test %s: want no error, have %v", tc.name, err) + } + // Turn result into res-struct + var have []blockRes + resBytes, _ := json.Marshal(result) + if err := json.Unmarshal(resBytes, &have); err != nil { + t.Fatalf("failed to unmarshal result: %v", err) + } + if !reflect.DeepEqual(have, tc.want) { + t.Errorf("test %s, result mismatch, have\n%v\n, want\n%v\n", tc.name, have, tc.want) + } + }) } } @@ -1343,16 +2531,40 @@ func newAccounts(n int) (accounts []account) { return accounts } +func newTestAccount() account { + // testKey is a private key to use for funding a tester account. + key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + // testAddr is the Ethereum address of the tester account. + addr := crypto.PubkeyToAddress(key.PublicKey) + return account{key: key, addr: addr} +} + func newRPCBalance(balance *big.Int) *hexutil.Big { rpcBalance := (*hexutil.Big)(balance) return rpcBalance } func hex2Bytes(str string) *hexutil.Bytes { - rpcBytes := hexutil.Bytes(common.Hex2Bytes(str)) + rpcBytes := hexutil.Bytes(common.FromHex(str)) + return &rpcBytes +} + +func newUint64(v uint64) *hexutil.Uint64 { + rpcUint64 := hexutil.Uint64(v) + return &rpcUint64 +} + +func newBytes(b []byte) *hexutil.Bytes { + rpcBytes := hexutil.Bytes(b) return &rpcBytes } +func uint256ToBytes(v *uint256.Int) *hexutil.Bytes { + b := v.Bytes32() + r := hexutil.Bytes(b[:]) + return &r +} + func TestRPCMarshalBlock(t *testing.T) { t.Parallel() var ( @@ -2072,6 +3284,97 @@ func TestRPCGetBlockReceipts(t *testing.T) { } } +type precompileContract struct{} + +func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 } + +func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil } + +func TestStateOverrideMovePrecompile(t *testing.T) { + db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) + statedb, err := state.New(common.Hash{}, db) + if err != nil { + t.Fatalf("failed to create statedb: %v", err) + } + precompiles := map[common.Address]vm.PrecompiledContract{ + common.BytesToAddress([]byte{0x1}): &precompileContract{}, + common.BytesToAddress([]byte{0x2}): &precompileContract{}, + } + bytes2Addr := func(b []byte) *common.Address { + a := common.BytesToAddress(b) + return &a + } + var testSuite = []struct { + overrides StateOverride + expectedPrecompiles map[common.Address]struct{} + fail bool + }{ + { + overrides: StateOverride{ + common.BytesToAddress([]byte{0x1}): { + Code: hex2Bytes("0xff"), + MovePrecompileTo: bytes2Addr([]byte{0x2}), + }, + common.BytesToAddress([]byte{0x2}): { + Code: hex2Bytes("0x00"), + }, + }, + // 0x2 has already been touched by the moveTo. + fail: true, + }, { + overrides: StateOverride{ + common.BytesToAddress([]byte{0x1}): { + Code: hex2Bytes("0xff"), + MovePrecompileTo: bytes2Addr([]byte{0xff}), + }, + common.BytesToAddress([]byte{0x3}): { + Code: hex2Bytes("0x00"), + MovePrecompileTo: bytes2Addr([]byte{0xfe}), + }, + }, + // 0x3 is not a precompile. + fail: true, + }, { + overrides: StateOverride{ + common.BytesToAddress([]byte{0x1}): { + Code: hex2Bytes("0xff"), + MovePrecompileTo: bytes2Addr([]byte{0xff}), + }, + common.BytesToAddress([]byte{0x2}): { + Code: hex2Bytes("0x00"), + MovePrecompileTo: bytes2Addr([]byte{0xfe}), + }, + }, + expectedPrecompiles: map[common.Address]struct{}{common.BytesToAddress([]byte{0xfe}): {}, common.BytesToAddress([]byte{0xff}): {}}, + }, + } + + for i, tt := range testSuite { + cpy := maps.Clone(precompiles) + // Apply overrides + err := tt.overrides.Apply(statedb, cpy) + if tt.fail { + if err == nil { + t.Errorf("test %d: want error, have nothing", i) + } + continue + } + if err != nil { + t.Errorf("test %d: want no error, have %v", i, err) + continue + } + // Precompile keys + if len(cpy) != len(tt.expectedPrecompiles) { + t.Errorf("test %d: precompile mismatch, want %d, have %d", i, len(tt.expectedPrecompiles), len(cpy)) + } + for k := range tt.expectedPrecompiles { + if _, ok := cpy[k]; !ok { + t.Errorf("test %d: precompile not found: %s", i, k.String()) + } + } + } +} + func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc string, file string) { data, err := json.MarshalIndent(result, "", " ") if err != nil { @@ -2088,3 +3391,7 @@ func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc s } require.JSONEqf(t, string(want), string(data), "test %d: json not match, want: %s, have: %s", testid, string(want), string(data)) } + +func addressToHash(a common.Address) common.Hash { + return common.BytesToHash(a.Bytes()) +} diff --git a/internal/ethapi/errors.go b/internal/ethapi/errors.go index b5e668a8050a..ae38061234db 100644 --- a/internal/ethapi/errors.go +++ b/internal/ethapi/errors.go @@ -17,10 +17,12 @@ package ethapi import ( + "errors" "fmt" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" ) @@ -76,3 +78,93 @@ func (e *TxIndexingError) ErrorCode() int { // ErrorData returns the hex encoded revert reason. func (e *TxIndexingError) ErrorData() interface{} { return "transaction indexing is in progress" } + +type callError struct { + Message string `json:"message"` + Code int `json:"code"` + Data string `json:"data,omitempty"` +} + +type invalidTxError struct { + Message string `json:"message"` + Code int `json:"code"` +} + +func (e *invalidTxError) Error() string { return e.Message } +func (e *invalidTxError) ErrorCode() int { return e.Code } + +const ( + errCodeNonceTooHigh = -38011 + errCodeNonceTooLow = -38010 + errCodeIntrinsicGas = -38013 + errCodeInsufficientFunds = -38014 + errCodeBlockGasLimitReached = -38015 + errCodeBlockNumberInvalid = -38020 + errCodeBlockTimestampInvalid = -38021 + errCodeSenderIsNotEOA = -38024 + errCodeMaxInitCodeSizeExceeded = -38025 + errCodeClientLimitExceeded = -38026 + errCodeInternalError = -32603 + errCodeInvalidParams = -32602 + errCodeReverted = -32000 + errCodeVMError = -32015 +) + +func txValidationError(err error) *invalidTxError { + if err == nil { + return nil + } + switch { + case errors.Is(err, core.ErrNonceTooHigh): + return &invalidTxError{Message: err.Error(), Code: errCodeNonceTooHigh} + case errors.Is(err, core.ErrNonceTooLow): + return &invalidTxError{Message: err.Error(), Code: errCodeNonceTooLow} + case errors.Is(err, core.ErrSenderNoEOA): + return &invalidTxError{Message: err.Error(), Code: errCodeSenderIsNotEOA} + case errors.Is(err, core.ErrFeeCapVeryHigh): + return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams} + case errors.Is(err, core.ErrTipVeryHigh): + return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams} + case errors.Is(err, core.ErrTipAboveFeeCap): + return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams} + case errors.Is(err, core.ErrFeeCapTooLow): + return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams} + case errors.Is(err, core.ErrInsufficientFunds): + return &invalidTxError{Message: err.Error(), Code: errCodeInsufficientFunds} + case errors.Is(err, core.ErrIntrinsicGas): + return &invalidTxError{Message: err.Error(), Code: errCodeIntrinsicGas} + case errors.Is(err, core.ErrInsufficientFundsForTransfer): + return &invalidTxError{Message: err.Error(), Code: errCodeInsufficientFunds} + case errors.Is(err, core.ErrMaxInitCodeSizeExceeded): + return &invalidTxError{Message: err.Error(), Code: errCodeMaxInitCodeSizeExceeded} + } + return &invalidTxError{ + Message: err.Error(), + Code: errCodeInternalError, + } +} + +type invalidParamsError struct{ message string } + +func (e *invalidParamsError) Error() string { return e.message } +func (e *invalidParamsError) ErrorCode() int { return errCodeInvalidParams } + +type clientLimitExceededError struct{ message string } + +func (e *clientLimitExceededError) Error() string { return e.message } +func (e *clientLimitExceededError) ErrorCode() int { return errCodeClientLimitExceeded } + +type invalidBlockNumberError struct{ message string } + +func (e *invalidBlockNumberError) Error() string { return e.message } +func (e *invalidBlockNumberError) ErrorCode() int { return errCodeBlockNumberInvalid } + +type invalidBlockTimestampError struct{ message string } + +func (e *invalidBlockTimestampError) Error() string { return e.message } +func (e *invalidBlockTimestampError) ErrorCode() int { return errCodeBlockTimestampInvalid } + +type blockGasLimitReachedError struct{ message string } + +func (e *blockGasLimitReachedError) Error() string { return e.message } +func (e *blockGasLimitReachedError) ErrorCode() int { return errCodeBlockGasLimitReached } diff --git a/internal/ethapi/logtracer.go b/internal/ethapi/logtracer.go new file mode 100644 index 000000000000..456aa937367f --- /dev/null +++ b/internal/ethapi/logtracer.go @@ -0,0 +1,151 @@ +// Copyright 2023 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 ethapi + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" +) + +var ( + // keccak256("Transfer(address,address,uint256)") + transferTopic = common.HexToHash("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") + // ERC-7528 + transferAddress = common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") +) + +// tracer is a simple tracer that records all logs and +// ether transfers. Transfers are recorded as if they +// were logs. Transfer events include: +// - tx value +// - call value +// - self destructs +// +// The log format for a transfer is: +// - address: 0x0000000000000000000000000000000000000000 +// - data: Value +// - topics: +// - Transfer(address,address,uint256) +// - Sender address +// - Recipient address +type tracer struct { + // logs keeps logs for all open call frames. + // This lets us clear logs for failed calls. + logs [][]*types.Log + count int + traceTransfers bool + blockNumber uint64 + blockHash common.Hash + txHash common.Hash + txIdx uint +} + +func newTracer(traceTransfers bool, blockNumber uint64, blockHash, txHash common.Hash, txIndex uint) *tracer { + return &tracer{ + traceTransfers: traceTransfers, + blockNumber: blockNumber, + blockHash: blockHash, + txHash: txHash, + txIdx: txIndex, + } +} + +func (t *tracer) Hooks() *tracing.Hooks { + return &tracing.Hooks{ + OnEnter: t.onEnter, + OnExit: t.onExit, + OnLog: t.onLog, + } +} + +func (t *tracer) onEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + t.logs = append(t.logs, make([]*types.Log, 0)) + if vm.OpCode(typ) != vm.DELEGATECALL && value != nil && value.Cmp(common.Big0) > 0 { + t.captureTransfer(from, to, value) + } +} + +func (t *tracer) onExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth == 0 { + t.onEnd(reverted) + return + } + size := len(t.logs) + if size <= 1 { + return + } + // pop call + call := t.logs[size-1] + t.logs = t.logs[:size-1] + size-- + + // Clear logs if call failed. + if !reverted { + t.logs[size-1] = append(t.logs[size-1], call...) + } +} + +func (t *tracer) onEnd(reverted bool) { + if reverted { + t.logs[0] = nil + } +} + +func (t *tracer) onLog(log *types.Log) { + t.captureLog(log.Address, log.Topics, log.Data) +} + +func (t *tracer) captureLog(address common.Address, topics []common.Hash, data []byte) { + t.logs[len(t.logs)-1] = append(t.logs[len(t.logs)-1], &types.Log{ + Address: address, + Topics: topics, + Data: data, + BlockNumber: t.blockNumber, + BlockHash: t.blockHash, + TxHash: t.txHash, + TxIndex: t.txIdx, + Index: uint(t.count), + }) + t.count++ +} + +func (t *tracer) captureTransfer(from, to common.Address, value *big.Int) { + if !t.traceTransfers { + return + } + topics := []common.Hash{ + transferTopic, + common.BytesToHash(from.Bytes()), + common.BytesToHash(to.Bytes()), + } + t.captureLog(transferAddress, topics, common.BigToHash(value).Bytes()) +} + +// reset prepares the tracer for the next transaction. +func (t *tracer) reset(txHash common.Hash, txIdx uint) { + t.logs = nil + t.txHash = txHash + t.txIdx = txIdx +} + +func (t *tracer) Logs() []*types.Log { + return t.logs[0] +} diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go new file mode 100644 index 000000000000..bccf87f8efea --- /dev/null +++ b/internal/ethapi/simulate.go @@ -0,0 +1,418 @@ +// Copyright 2023 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 ethapi + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "maps" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/misc/eip1559" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core" + "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/params" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/trie" +) + +const ( + // maxSimulateBlocks is the maximum number of blocks that can be simulated + // in a single request. + maxSimulateBlocks = 256 + + // timestampIncrement is the default increment between block timestamps. + timestampIncrement = 1 +) + +// simBlock is a batch of calls to be simulated sequentially. +type simBlock struct { + BlockOverrides *BlockOverrides + StateOverrides *StateOverride + Calls []TransactionArgs +} + +// simCallResult is the result of a simulated call. +type simCallResult struct { + ReturnValue hexutil.Bytes `json:"returnData"` + Logs []*types.Log `json:"logs"` + GasUsed hexutil.Uint64 `json:"gasUsed"` + Status hexutil.Uint64 `json:"status"` + Error *callError `json:"error,omitempty"` +} + +func (r *simCallResult) MarshalJSON() ([]byte, error) { + type callResultAlias simCallResult + // Marshal logs to be an empty array instead of nil when empty + if r.Logs == nil { + r.Logs = []*types.Log{} + } + return json.Marshal((*callResultAlias)(r)) +} + +// simOpts are the inputs to eth_simulateV1. +type simOpts struct { + BlockStateCalls []simBlock + TraceTransfers bool + Validation bool + ReturnFullTransactions bool +} + +// simulator is a stateful object that simulates a series of blocks. +// it is not safe for concurrent use. +type simulator struct { + b Backend + state *state.StateDB + base *types.Header + chainConfig *params.ChainConfig + gp *core.GasPool + traceTransfers bool + validate bool + fullTx bool +} + +// execute runs the simulation of a series of blocks. +func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[string]interface{}, error) { + if err := ctx.Err(); err != nil { + return nil, err + } + var ( + cancel context.CancelFunc + timeout = sim.b.RPCEVMTimeout() + ) + if timeout > 0 { + ctx, cancel = context.WithTimeout(ctx, timeout) + } else { + ctx, cancel = context.WithCancel(ctx) + } + // Make sure the context is cancelled when the call has completed + // this makes sure resources are cleaned up. + defer cancel() + + var err error + blocks, err = sim.sanitizeChain(blocks) + if err != nil { + return nil, err + } + // Prepare block headers with preliminary fields for the response. + headers, err := sim.makeHeaders(blocks) + if err != nil { + return nil, err + } + var ( + results = make([]map[string]interface{}, len(blocks)) + parent = sim.base + // Assume same total difficulty for all simulated blocks. + td = sim.b.GetTd(ctx, sim.base.Hash()) + ) + for bi, block := range blocks { + result, callResults, err := sim.processBlock(ctx, &block, headers[bi], parent, headers[:bi], timeout) + if err != nil { + return nil, err + } + enc := RPCMarshalBlock(result, true, sim.fullTx, sim.chainConfig) + enc["totalDifficulty"] = (*hexutil.Big)(td) + enc["calls"] = callResults + results[bi] = enc + + parent = headers[bi] + } + return results, nil +} + +func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, parent *types.Header, headers []*types.Header, timeout time.Duration) (*types.Block, []simCallResult, error) { + // Set header fields that depend only on parent block. + // Parent hash is needed for evm.GetHashFn to work. + header.ParentHash = parent.Hash() + if sim.chainConfig.IsLondon(header.Number) { + // In non-validation mode base fee is set to 0 if it is not overridden. + // This is because it creates an edge case in EVM where gasPrice < baseFee. + // Base fee could have been overridden. + if header.BaseFee == nil { + if sim.validate { + header.BaseFee = eip1559.CalcBaseFee(sim.chainConfig, parent) + } else { + header.BaseFee = big.NewInt(0) + } + } + } + if sim.chainConfig.IsCancun(header.Number, header.Time) { + var excess uint64 + if sim.chainConfig.IsCancun(parent.Number, parent.Time) { + excess = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed) + } else { + excess = eip4844.CalcExcessBlobGas(0, 0) + } + header.ExcessBlobGas = &excess + } + blockContext := core.NewEVMBlockContext(header, sim.newSimulatedChainContext(ctx, headers), nil) + if block.BlockOverrides.BlobBaseFee != nil { + blockContext.BlobBaseFee = block.BlockOverrides.BlobBaseFee.ToInt() + } + precompiles := sim.activePrecompiles(sim.base) + // State overrides are applied prior to execution of a block + if err := block.StateOverrides.Apply(sim.state, precompiles); err != nil { + return nil, nil, err + } + var ( + gasUsed, blobGasUsed uint64 + txes = make([]*types.Transaction, len(block.Calls)) + callResults = make([]simCallResult, len(block.Calls)) + receipts = make([]*types.Receipt, len(block.Calls)) + // Block hash will be repaired after execution. + tracer = newTracer(sim.traceTransfers, blockContext.BlockNumber.Uint64(), common.Hash{}, common.Hash{}, 0) + vmConfig = &vm.Config{ + NoBaseFee: !sim.validate, + Tracer: tracer.Hooks(), + } + evm = vm.NewEVM(blockContext, vm.TxContext{GasPrice: new(big.Int)}, sim.state, sim.chainConfig, *vmConfig) + ) + sim.state.SetLogger(tracer.Hooks()) + // It is possible to override precompiles with EVM bytecode, or + // move them to another address. + if precompiles != nil { + evm.SetPrecompiles(precompiles) + } + for i, call := range block.Calls { + if err := ctx.Err(); err != nil { + return nil, nil, err + } + if err := sim.sanitizeCall(&call, sim.state, header, blockContext, &gasUsed); err != nil { + return nil, nil, err + } + tx := call.ToTransaction(types.DynamicFeeTxType) + txes[i] = tx + tracer.reset(tx.Hash(), uint(i)) + // EoA check is always skipped, even in validation mode. + msg := call.ToMessage(header.BaseFee, !sim.validate, true) + evm.Reset(core.NewEVMTxContext(msg), sim.state) + result, err := applyMessageWithEVM(ctx, evm, msg, sim.state, timeout, sim.gp) + if err != nil { + txErr := txValidationError(err) + return nil, nil, txErr + } + // Update the state with pending changes. + var root []byte + if sim.chainConfig.IsByzantium(blockContext.BlockNumber) { + sim.state.Finalise(true) + } else { + root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes() + } + gasUsed += result.UsedGas + receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, tx, gasUsed, root) + blobGasUsed += receipts[i].BlobGasUsed + logs := tracer.Logs() + callRes := simCallResult{ReturnValue: result.Return(), Logs: logs, GasUsed: hexutil.Uint64(result.UsedGas)} + if result.Failed() { + callRes.Status = hexutil.Uint64(types.ReceiptStatusFailed) + if errors.Is(result.Err, vm.ErrExecutionReverted) { + // If the result contains a revert reason, try to unpack it. + revertErr := newRevertError(result.Revert()) + callRes.Error = &callError{Message: revertErr.Error(), Code: errCodeReverted, Data: revertErr.ErrorData().(string)} + } else { + callRes.Error = &callError{Message: result.Err.Error(), Code: errCodeVMError} + } + } else { + callRes.Status = hexutil.Uint64(types.ReceiptStatusSuccessful) + } + callResults[i] = callRes + } + header.Root = sim.state.IntermediateRoot(true) + header.GasUsed = gasUsed + if sim.chainConfig.IsCancun(header.Number, header.Time) { + header.BlobGasUsed = &blobGasUsed + } + var withdrawals types.Withdrawals + if sim.chainConfig.IsShanghai(header.Number, header.Time) { + withdrawals = make([]*types.Withdrawal, 0) + } + b := types.NewBlock(header, &types.Body{Transactions: txes, Withdrawals: withdrawals}, receipts, trie.NewStackTrie(nil)) + repairLogs(callResults, b.Hash()) + return b, callResults, nil +} + +// repairLogs updates the block hash in the logs present in the result of +// a simulated block. This is needed as during execution when logs are collected +// the block hash is not known. +func repairLogs(calls []simCallResult, hash common.Hash) { + for i := range calls { + for j := range calls[i].Logs { + calls[i].Logs[j].BlockHash = hash + } + } +} + +func (sim *simulator) sanitizeCall(call *TransactionArgs, state *state.StateDB, header *types.Header, blockContext vm.BlockContext, gasUsed *uint64) error { + if call.Nonce == nil { + nonce := state.GetNonce(call.from()) + call.Nonce = (*hexutil.Uint64)(&nonce) + } + // Let the call run wild unless explicitly specified. + if call.Gas == nil { + remaining := blockContext.GasLimit - *gasUsed + call.Gas = (*hexutil.Uint64)(&remaining) + } + if *gasUsed+uint64(*call.Gas) > blockContext.GasLimit { + return &blockGasLimitReachedError{fmt.Sprintf("block gas limit reached: %d >= %d", gasUsed, blockContext.GasLimit)} + } + if err := call.CallDefaults(sim.gp.Gas(), header.BaseFee, sim.chainConfig.ChainID); err != nil { + return err + } + return nil +} + +func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContracts { + var ( + isMerge = (base.Difficulty.Sign() == 0) + rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time) + ) + return maps.Clone(vm.ActivePrecompiledContracts(rules)) +} + +// sanitizeChain checks the chain integrity. Specifically it checks that +// block numbers and timestamp are strictly increasing, setting default values +// when necessary. Gaps in block numbers are filled with empty blocks. +// Note: It modifies the block's override object. +func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) { + var ( + res = make([]simBlock, 0, len(blocks)) + base = sim.base + prevNumber = base.Number + prevTimestamp = base.Time + ) + for _, block := range blocks { + if block.BlockOverrides == nil { + block.BlockOverrides = new(BlockOverrides) + } + if block.BlockOverrides.Number == nil { + n := new(big.Int).Add(prevNumber, big.NewInt(1)) + block.BlockOverrides.Number = (*hexutil.Big)(n) + } + diff := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), prevNumber) + if diff.Cmp(common.Big0) <= 0 { + return nil, &invalidBlockNumberError{fmt.Sprintf("block numbers must be in order: %d <= %d", block.BlockOverrides.Number.ToInt().Uint64(), prevNumber)} + } + if total := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), base.Number); total.Cmp(big.NewInt(maxSimulateBlocks)) > 0 { + return nil, &clientLimitExceededError{message: "too many blocks"} + } + if diff.Cmp(big.NewInt(1)) > 0 { + // Fill the gap with empty blocks. + gap := new(big.Int).Sub(diff, big.NewInt(1)) + // Assign block number to the empty blocks. + for i := uint64(0); i < gap.Uint64(); i++ { + n := new(big.Int).Add(prevNumber, big.NewInt(int64(i+1))) + t := prevTimestamp + timestampIncrement + b := simBlock{BlockOverrides: &BlockOverrides{Number: (*hexutil.Big)(n), Time: (*hexutil.Uint64)(&t)}} + prevTimestamp = t + res = append(res, b) + } + } + // Only append block after filling a potential gap. + prevNumber = block.BlockOverrides.Number.ToInt() + var t uint64 + if block.BlockOverrides.Time == nil { + t = prevTimestamp + timestampIncrement + block.BlockOverrides.Time = (*hexutil.Uint64)(&t) + } else { + t = uint64(*block.BlockOverrides.Time) + if t <= prevTimestamp { + return nil, &invalidBlockTimestampError{fmt.Sprintf("block timestamps must be in order: %d <= %d", t, prevTimestamp)} + } + } + prevTimestamp = t + res = append(res, block) + } + return res, nil +} + +// makeHeaders makes header object with preliminary fields based on a simulated block. +// Some fields have to be filled post-execution. +// It assumes blocks are in order and numbers have been validated. +func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) { + var ( + res = make([]*types.Header, len(blocks)) + base = sim.base + header = base + ) + for bi, block := range blocks { + if block.BlockOverrides == nil || block.BlockOverrides.Number == nil { + return nil, errors.New("empty block number") + } + overrides := block.BlockOverrides + + var withdrawalsHash *common.Hash + if sim.chainConfig.IsShanghai(overrides.Number.ToInt(), (uint64)(*overrides.Time)) { + withdrawalsHash = &types.EmptyWithdrawalsHash + } + var parentBeaconRoot *common.Hash + if sim.chainConfig.IsCancun(overrides.Number.ToInt(), (uint64)(*overrides.Time)) { + parentBeaconRoot = &common.Hash{} + } + header = overrides.MakeHeader(&types.Header{ + UncleHash: types.EmptyUncleHash, + ReceiptHash: types.EmptyReceiptsHash, + TxHash: types.EmptyTxsHash, + Coinbase: header.Coinbase, + Difficulty: header.Difficulty, + GasLimit: header.GasLimit, + WithdrawalsHash: withdrawalsHash, + ParentBeaconRoot: parentBeaconRoot, + }) + res[bi] = header + } + return res, nil +} + +func (sim *simulator) newSimulatedChainContext(ctx context.Context, headers []*types.Header) *ChainContext { + return NewChainContext(ctx, &simBackend{base: sim.base, b: sim.b, headers: headers}) +} + +type simBackend struct { + b ChainContextBackend + base *types.Header + headers []*types.Header +} + +func (b *simBackend) Engine() consensus.Engine { + return b.b.Engine() +} + +func (b *simBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { + if uint64(number) == b.base.Number.Uint64() { + return b.base, nil + } + if uint64(number) < b.base.Number.Uint64() { + // Resolve canonical header. + return b.b.HeaderByNumber(ctx, number) + } + // Simulated block. + for _, header := range b.headers { + if header.Number.Uint64() == uint64(number) { + return header, nil + } + } + return nil, errors.New("header not found") +} diff --git a/internal/ethapi/simulate_test.go b/internal/ethapi/simulate_test.go new file mode 100644 index 000000000000..37883924acc6 --- /dev/null +++ b/internal/ethapi/simulate_test.go @@ -0,0 +1,120 @@ +// Copyright 2024 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 ethapi + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" +) + +func TestSimulateSanitizeBlockOrder(t *testing.T) { + type result struct { + number uint64 + timestamp uint64 + } + for i, tc := range []struct { + baseNumber int + baseTimestamp uint64 + blocks []simBlock + expected []result + err string + }{ + { + baseNumber: 10, + baseTimestamp: 50, + blocks: []simBlock{{}, {}, {}}, + expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}}, + }, + { + baseNumber: 10, + baseTimestamp: 50, + blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}}, + expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 70}, {number: 14, timestamp: 71}}, + }, + { + baseNumber: 10, + baseTimestamp: 50, + blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &BlockOverrides{Number: newInt(14)}}, {}}, + expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}, {number: 14, timestamp: 54}, {number: 15, timestamp: 55}}, + }, + { + baseNumber: 10, + baseTimestamp: 50, + blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12)}}}, + err: "block numbers must be in order: 12 <= 13", + }, + { + baseNumber: 10, + baseTimestamp: 50, + blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(52)}}}, + err: "block timestamps must be in order: 52 <= 52", + }, + { + baseNumber: 10, + baseTimestamp: 50, + blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12), Time: newUint64(55)}}}, + err: "block timestamps must be in order: 55 <= 60", + }, + { + baseNumber: 10, + baseTimestamp: 50, + blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(61)}}}, + err: "block timestamps must be in order: 61 <= 61", + }, + } { + sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}} + res, err := sim.sanitizeChain(tc.blocks) + if err != nil { + if err.Error() == tc.err { + continue + } else { + t.Fatalf("testcase %d: error mismatch. Want '%s', have '%s'", i, tc.err, err.Error()) + } + } + if err == nil && tc.err != "" { + t.Fatalf("testcase %d: expected err", i) + } + if len(res) != len(tc.expected) { + t.Errorf("testcase %d: mismatch number of blocks. Want %d, have %d", i, len(tc.expected), len(res)) + } + for bi, b := range res { + if b.BlockOverrides == nil { + t.Fatalf("testcase %d: block overrides nil", i) + } + if b.BlockOverrides.Number == nil { + t.Fatalf("testcase %d: block number not set", i) + } + if b.BlockOverrides.Time == nil { + t.Fatalf("testcase %d: block time not set", i) + } + if uint64(*b.BlockOverrides.Time) != tc.expected[bi].timestamp { + t.Errorf("testcase %d: block timestamp mismatch. Want %d, have %d", i, tc.expected[bi].timestamp, uint64(*b.BlockOverrides.Time)) + } + have := b.BlockOverrides.Number.ToInt().Uint64() + if have != tc.expected[bi].number { + t.Errorf("testcase %d: block number mismatch. Want %d, have %d", i, tc.expected[bi].number, have) + } + } + } +} + +func newInt(n int64) *hexutil.Big { + return (*hexutil.Big)(big.NewInt(n)) +} diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index f199f9d91253..f9835a96dabf 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -421,7 +421,7 @@ func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, // core evm. This method is used in calls and traces that do not require a real // live transaction. // Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called. -func (args *TransactionArgs) ToMessage(baseFee *big.Int) *core.Message { +func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoACheck bool) *core.Message { var ( gasPrice *big.Int gasFeeCap *big.Int @@ -452,27 +452,42 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int) *core.Message { accessList = *args.AccessList } return &core.Message{ - From: args.from(), - To: args.To, - Value: (*big.Int)(args.Value), - GasLimit: uint64(*args.Gas), - GasPrice: gasPrice, - GasFeeCap: gasFeeCap, - GasTipCap: gasTipCap, - Data: args.data(), - AccessList: accessList, - BlobGasFeeCap: (*big.Int)(args.BlobFeeCap), - BlobHashes: args.BlobHashes, - SkipAccountChecks: true, + From: args.from(), + To: args.To, + Value: (*big.Int)(args.Value), + Nonce: uint64(*args.Nonce), + GasLimit: uint64(*args.Gas), + GasPrice: gasPrice, + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + Data: args.data(), + AccessList: accessList, + BlobGasFeeCap: (*big.Int)(args.BlobFeeCap), + BlobHashes: args.BlobHashes, + SkipNonceChecks: skipNonceCheck, + SkipFromEOACheck: skipEoACheck, } } // ToTransaction converts the arguments to a transaction. // This assumes that setDefaults has been called. -func (args *TransactionArgs) ToTransaction() *types.Transaction { - var data types.TxData +func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction { + usedType := types.LegacyTxType switch { - case args.BlobHashes != nil: + case args.BlobHashes != nil || defaultType == types.BlobTxType: + usedType = types.BlobTxType + case args.MaxFeePerGas != nil || defaultType == types.DynamicFeeTxType: + usedType = types.DynamicFeeTxType + case args.AccessList != nil || defaultType == types.AccessListTxType: + usedType = types.AccessListTxType + } + // Make it possible to default to newer tx, but use legacy if gasprice is provided + if args.GasPrice != nil { + usedType = types.LegacyTxType + } + var data types.TxData + switch usedType { + case types.BlobTxType: al := types.AccessList{} if args.AccessList != nil { al = *args.AccessList @@ -498,7 +513,7 @@ func (args *TransactionArgs) ToTransaction() *types.Transaction { } } - case args.MaxFeePerGas != nil: + case types.DynamicFeeTxType: al := types.AccessList{} if args.AccessList != nil { al = *args.AccessList @@ -515,7 +530,7 @@ func (args *TransactionArgs) ToTransaction() *types.Transaction { AccessList: al, } - case args.AccessList != nil: + case types.AccessListTxType: data = &types.AccessListTx{ To: args.To, ChainID: (*big.Int)(args.ChainID), diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 4a1a37d722d6..4a53e2c82955 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -616,6 +616,12 @@ web3._extend({ params: 4, inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputDefaultBlockNumberFormatter, null, null], }), + new web3._extend.Method({ + name: 'simulateV1', + call: 'eth_simulateV1', + params: 2, + inputFormatter: [null, web3._extend.formatters.inputDefaultBlockNumberFormatter], + }), new web3._extend.Method({ name: 'getBlockReceipts', call: 'eth_getBlockReceipts', From 88c84590057acf0bde6fc7a2fb3ca9cf593a2318 Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Fri, 6 Sep 2024 03:32:01 -0700 Subject: [PATCH 521/571] eth/fetcher: fix blob transaction propagation (#30125) This PR fixes an issue with blob transaction propagation due to the blob transation txpool rejecting transactions with gapped nonces. The specific changes are: - fetch transactions from a peer in the order they were announced to minimize nonce-gaps (which cause blob txs to be rejected - don't wait on fetching blob transactions after announcement is received, since they are not broadcast Testing: - unit tests updated to reflect that fetch order should always match tx announcement order - unit test added to confirm blob transactions are scheduled immediately for fetching - running the PR on an eth mainnet full node without incident so far --------- Signed-off-by: Roberto Bayardo Co-authored-by: Gary Rong --- cmd/devp2p/internal/ethtest/suite.go | 11 +- eth/fetcher/tx_fetcher.go | 177 ++++++++++++++++----------- eth/fetcher/tx_fetcher_test.go | 88 +++++++++++-- 3 files changed, 193 insertions(+), 83 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index b5cc27a2b590..5cb9fa0297d9 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -849,7 +849,16 @@ func (s *Suite) TestBlobViolations(t *utesting.T) { if code, _, err := conn.Read(); err != nil { t.Fatalf("expected disconnect on blob violation, got err: %v", err) } else if code != discMsg { - t.Fatalf("expected disconnect on blob violation, got msg code: %d", code) + if code == protoOffset(ethProto)+eth.NewPooledTransactionHashesMsg { + // sometimes we'll get a blob transaction hashes announcement before the disconnect + // because blob transactions are scheduled to be fetched right away. + if code, _, err = conn.Read(); err != nil { + t.Fatalf("expected disconnect on blob violation, got err on second read: %v", err) + } + } + if code != discMsg { + t.Fatalf("expected disconnect on blob violation, got msg code: %d", code) + } } conn.Close() } diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index a113155009e1..97d1e2986212 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -17,7 +17,6 @@ package fetcher import ( - "bytes" "errors" "fmt" "math" @@ -35,7 +34,7 @@ import ( ) const ( - // maxTxAnnounces is the maximum number of unique transaction a peer + // maxTxAnnounces is the maximum number of unique transactions a peer // can announce in a short time. maxTxAnnounces = 4096 @@ -114,16 +113,23 @@ var errTerminated = errors.New("terminated") type txAnnounce struct { origin string // Identifier of the peer originating the notification hashes []common.Hash // Batch of transaction hashes being announced - metas []*txMetadata // Batch of metadata associated with the hashes + metas []txMetadata // Batch of metadata associated with the hashes } -// txMetadata is a set of extra data transmitted along the announcement for better -// fetch scheduling. +// txMetadata provides the extra data transmitted along with the announcement +// for better fetch scheduling. type txMetadata struct { kind byte // Transaction consensus type size uint32 // Transaction size in bytes } +// txMetadataWithSeq is a wrapper of transaction metadata with an extra field +// tracking the transaction sequence number. +type txMetadataWithSeq struct { + txMetadata + seq uint64 +} + // txRequest represents an in-flight transaction retrieval request destined to // a specific peers. type txRequest struct { @@ -159,7 +165,7 @@ type txDrop struct { // The invariants of the fetcher are: // - Each tracked transaction (hash) must only be present in one of the // three stages. This ensures that the fetcher operates akin to a finite -// state automata and there's do data leak. +// state automata and there's no data leak. // - Each peer that announced transactions may be scheduled retrievals, but // only ever one concurrently. This ensures we can immediately know what is // missing from a reply and reschedule it. @@ -169,18 +175,19 @@ type TxFetcher struct { drop chan *txDrop quit chan struct{} + txSeq uint64 // Unique transaction sequence number underpriced *lru.Cache[common.Hash, time.Time] // Transactions discarded as too cheap (don't re-fetch) // Stage 1: Waiting lists for newly discovered transactions that might be // broadcast without needing explicit request/reply round trips. - waitlist map[common.Hash]map[string]struct{} // Transactions waiting for an potential broadcast - waittime map[common.Hash]mclock.AbsTime // Timestamps when transactions were added to the waitlist - waitslots map[string]map[common.Hash]*txMetadata // Waiting announcements grouped by peer (DoS protection) + waitlist map[common.Hash]map[string]struct{} // Transactions waiting for an potential broadcast + waittime map[common.Hash]mclock.AbsTime // Timestamps when transactions were added to the waitlist + waitslots map[string]map[common.Hash]*txMetadataWithSeq // Waiting announcements grouped by peer (DoS protection) // Stage 2: Queue of transactions that waiting to be allocated to some peer // to be retrieved directly. - announces map[string]map[common.Hash]*txMetadata // Set of announced transactions, grouped by origin peer - announced map[common.Hash]map[string]struct{} // Set of download locations, grouped by transaction hash + announces map[string]map[common.Hash]*txMetadataWithSeq // Set of announced transactions, grouped by origin peer + announced map[common.Hash]map[string]struct{} // Set of download locations, grouped by transaction hash // Stage 3: Set of transactions currently being retrieved, some which may be // fulfilled and some rescheduled. Note, this step shares 'announces' from the @@ -218,8 +225,8 @@ func NewTxFetcherForTests( quit: make(chan struct{}), waitlist: make(map[common.Hash]map[string]struct{}), waittime: make(map[common.Hash]mclock.AbsTime), - waitslots: make(map[string]map[common.Hash]*txMetadata), - announces: make(map[string]map[common.Hash]*txMetadata), + waitslots: make(map[string]map[common.Hash]*txMetadataWithSeq), + announces: make(map[string]map[common.Hash]*txMetadataWithSeq), announced: make(map[common.Hash]map[string]struct{}), fetching: make(map[common.Hash]string), requests: make(map[string]*txRequest), @@ -247,7 +254,7 @@ func (f *TxFetcher) Notify(peer string, types []byte, sizes []uint32, hashes []c // loop, so anything caught here is time saved internally. var ( unknownHashes = make([]common.Hash, 0, len(hashes)) - unknownMetas = make([]*txMetadata, 0, len(hashes)) + unknownMetas = make([]txMetadata, 0, len(hashes)) duplicate int64 underpriced int64 @@ -264,7 +271,7 @@ func (f *TxFetcher) Notify(peer string, types []byte, sizes []uint32, hashes []c // Transaction metadata has been available since eth68, and all // legacy eth protocols (prior to eth68) have been deprecated. // Therefore, metadata is always expected in the announcement. - unknownMetas = append(unknownMetas, &txMetadata{kind: types[i], size: sizes[i]}) + unknownMetas = append(unknownMetas, txMetadata{kind: types[i], size: sizes[i]}) } } txAnnounceKnownMeter.Mark(duplicate) @@ -431,9 +438,19 @@ func (f *TxFetcher) loop() { ann.metas = ann.metas[:want-maxTxAnnounces] } // All is well, schedule the remainder of the transactions - idleWait := len(f.waittime) == 0 - _, oldPeer := f.announces[ann.origin] - + var ( + idleWait = len(f.waittime) == 0 + _, oldPeer = f.announces[ann.origin] + hasBlob bool + + // nextSeq returns the next available sequence number for tagging + // transaction announcement and also bump it internally. + nextSeq = func() uint64 { + seq := f.txSeq + f.txSeq++ + return seq + } + ) for i, hash := range ann.hashes { // If the transaction is already downloading, add it to the list // of possible alternates (in case the current retrieval fails) and @@ -443,9 +460,17 @@ func (f *TxFetcher) loop() { // Stage 2 and 3 share the set of origins per tx if announces := f.announces[ann.origin]; announces != nil { - announces[hash] = ann.metas[i] + announces[hash] = &txMetadataWithSeq{ + txMetadata: ann.metas[i], + seq: nextSeq(), + } } else { - f.announces[ann.origin] = map[common.Hash]*txMetadata{hash: ann.metas[i]} + f.announces[ann.origin] = map[common.Hash]*txMetadataWithSeq{ + hash: { + txMetadata: ann.metas[i], + seq: nextSeq(), + }, + } } continue } @@ -456,9 +481,17 @@ func (f *TxFetcher) loop() { // Stage 2 and 3 share the set of origins per tx if announces := f.announces[ann.origin]; announces != nil { - announces[hash] = ann.metas[i] + announces[hash] = &txMetadataWithSeq{ + txMetadata: ann.metas[i], + seq: nextSeq(), + } } else { - f.announces[ann.origin] = map[common.Hash]*txMetadata{hash: ann.metas[i]} + f.announces[ann.origin] = map[common.Hash]*txMetadataWithSeq{ + hash: { + txMetadata: ann.metas[i], + seq: nextSeq(), + }, + } } continue } @@ -475,24 +508,47 @@ func (f *TxFetcher) loop() { f.waitlist[hash][ann.origin] = struct{}{} if waitslots := f.waitslots[ann.origin]; waitslots != nil { - waitslots[hash] = ann.metas[i] + waitslots[hash] = &txMetadataWithSeq{ + txMetadata: ann.metas[i], + seq: nextSeq(), + } } else { - f.waitslots[ann.origin] = map[common.Hash]*txMetadata{hash: ann.metas[i]} + f.waitslots[ann.origin] = map[common.Hash]*txMetadataWithSeq{ + hash: { + txMetadata: ann.metas[i], + seq: nextSeq(), + }, + } } continue } // Transaction unknown to the fetcher, insert it into the waiting list f.waitlist[hash] = map[string]struct{}{ann.origin: {}} - f.waittime[hash] = f.clock.Now() + // Assign the current timestamp as the wait time, but for blob transactions, + // skip the wait time since they are only announced. + if ann.metas[i].kind != types.BlobTxType { + f.waittime[hash] = f.clock.Now() + } else { + hasBlob = true + f.waittime[hash] = f.clock.Now() - mclock.AbsTime(txArriveTimeout) + } if waitslots := f.waitslots[ann.origin]; waitslots != nil { - waitslots[hash] = ann.metas[i] + waitslots[hash] = &txMetadataWithSeq{ + txMetadata: ann.metas[i], + seq: nextSeq(), + } } else { - f.waitslots[ann.origin] = map[common.Hash]*txMetadata{hash: ann.metas[i]} + f.waitslots[ann.origin] = map[common.Hash]*txMetadataWithSeq{ + hash: { + txMetadata: ann.metas[i], + seq: nextSeq(), + }, + } } } // If a new item was added to the waitlist, schedule it into the fetcher - if idleWait && len(f.waittime) > 0 { + if hasBlob || (idleWait && len(f.waittime) > 0) { f.rescheduleWait(waitTimer, waitTrigger) } // If this peer is new and announced something already queued, maybe @@ -516,7 +572,7 @@ func (f *TxFetcher) loop() { if announces := f.announces[peer]; announces != nil { announces[hash] = f.waitslots[peer][hash] } else { - f.announces[peer] = map[common.Hash]*txMetadata{hash: f.waitslots[peer][hash]} + f.announces[peer] = map[common.Hash]*txMetadataWithSeq{hash: f.waitslots[peer][hash]} } delete(f.waitslots[peer], hash) if len(f.waitslots[peer]) == 0 { @@ -873,7 +929,7 @@ func (f *TxFetcher) scheduleFetches(timer *mclock.Timer, timeout chan struct{}, hashes = make([]common.Hash, 0, maxTxRetrievals) bytes uint64 ) - f.forEachAnnounce(f.announces[peer], func(hash common.Hash, meta *txMetadata) bool { + f.forEachAnnounce(f.announces[peer], func(hash common.Hash, meta txMetadata) bool { // If the transaction is already fetching, skip to the next one if _, ok := f.fetching[hash]; ok { return true @@ -938,28 +994,26 @@ func (f *TxFetcher) forEachPeer(peers map[string]struct{}, do func(peer string)) } } -// forEachAnnounce does a range loop over a map of announcements in production, -// but during testing it does a deterministic sorted random to allow reproducing -// issues. -func (f *TxFetcher) forEachAnnounce(announces map[common.Hash]*txMetadata, do func(hash common.Hash, meta *txMetadata) bool) { - // If we're running production, use whatever Go's map gives us - if f.rand == nil { - for hash, meta := range announces { - if !do(hash, meta) { - return - } - } - return +// forEachAnnounce loops over the given announcements in arrival order, invoking +// the do function for each until it returns false. We enforce an arrival +// ordering to minimize the chances of transaction nonce-gaps, which result in +// transactions being rejected by the txpool. +func (f *TxFetcher) forEachAnnounce(announces map[common.Hash]*txMetadataWithSeq, do func(hash common.Hash, meta txMetadata) bool) { + type announcement struct { + hash common.Hash + meta txMetadata + seq uint64 } - // We're running the test suite, make iteration deterministic - list := make([]common.Hash, 0, len(announces)) - for hash := range announces { - list = append(list, hash) + // Process announcements by their arrival order + list := make([]announcement, 0, len(announces)) + for hash, entry := range announces { + list = append(list, announcement{hash: hash, meta: entry.txMetadata, seq: entry.seq}) } - sortHashes(list) - rotateHashes(list, f.rand.Intn(len(list))) - for _, hash := range list { - if !do(hash, announces[hash]) { + sort.Slice(list, func(i, j int) bool { + return list[i].seq < list[j].seq + }) + for i := range list { + if !do(list[i].hash, list[i].meta) { return } } @@ -975,26 +1029,3 @@ func rotateStrings(slice []string, n int) { slice[i] = orig[(i+n)%len(orig)] } } - -// sortHashes sorts a slice of hashes. This method is only used in tests in order -// to simulate random map iteration but keep it deterministic. -func sortHashes(slice []common.Hash) { - for i := 0; i < len(slice); i++ { - for j := i + 1; j < len(slice); j++ { - if bytes.Compare(slice[i][:], slice[j][:]) > 0 { - slice[i], slice[j] = slice[j], slice[i] - } - } - } -} - -// rotateHashes rotates the contents of a slice by n steps. This method is only -// used in tests to simulate random map iteration but keep it deterministic. -func rotateHashes(slice []common.Hash, n int) { - orig := make([]common.Hash, len(slice)) - copy(orig, slice) - - for i := 0; i < len(orig); i++ { - slice[i] = orig[(i+n)%len(orig)] - } -} diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index 0b4764666984..f80b1d6096d3 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -701,7 +701,7 @@ func TestTransactionFetcherMissingRescheduling(t *testing.T) { }, // Deliver the middle transaction requested, the one before which // should be dropped and the one after re-requested. - doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}, direct: true}, // This depends on the deterministic random + doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[1]}, direct: true}, isScheduled{ tracking: map[string][]announce{ "A": { @@ -1070,7 +1070,7 @@ func TestTransactionFetcherRateLimiting(t *testing.T) { "A": announces, }, fetching: map[string][]common.Hash{ - "A": hashes[1643 : 1643+maxTxRetrievals], + "A": hashes[:maxTxRetrievals], }, }, }, @@ -1130,9 +1130,9 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) { }, }, fetching: map[string][]common.Hash{ - "A": {{0x02}, {0x03}, {0x04}}, - "B": {{0x06}}, - "C": {{0x08}}, + "A": {{0x01}, {0x02}, {0x03}}, + "B": {{0x05}}, + "C": {{0x07}}, }, }, }, @@ -1209,8 +1209,8 @@ func TestTransactionFetcherDoSProtection(t *testing.T) { "B": announceB[:maxTxAnnounces/2-1], }, fetching: map[string][]common.Hash{ - "A": hashesA[1643 : 1643+maxTxRetrievals], - "B": append(append([]common.Hash{}, hashesB[maxTxAnnounces/2-3:maxTxAnnounces/2-1]...), hashesB[:maxTxRetrievals-2]...), + "A": hashesA[:maxTxRetrievals], + "B": hashesB[:maxTxRetrievals], }, }, // Ensure that adding even one more hash results in dropping the hash @@ -1227,8 +1227,8 @@ func TestTransactionFetcherDoSProtection(t *testing.T) { "B": announceB[:maxTxAnnounces/2-1], }, fetching: map[string][]common.Hash{ - "A": hashesA[1643 : 1643+maxTxRetrievals], - "B": append(append([]common.Hash{}, hashesB[maxTxAnnounces/2-3:maxTxAnnounces/2-1]...), hashesB[:maxTxRetrievals-2]...), + "A": hashesA[:maxTxRetrievals], + "B": hashesB[:maxTxRetrievals], }, }, }, @@ -1759,6 +1759,76 @@ func TestTransactionFetcherFuzzCrash04(t *testing.T) { }) } +// This test ensures the blob transactions will be scheduled for fetching +// once they are announced in the network. +func TestBlobTransactionAnnounce(t *testing.T) { + testTransactionFetcherParallel(t, txFetcherTest{ + init: func() *TxFetcher { + return NewTxFetcher( + func(common.Hash) bool { return false }, + nil, + func(string, []common.Hash) error { return nil }, + nil, + ) + }, + steps: []interface{}{ + // Initial announcement to get something into the waitlist + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{111, 222}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, + }), + // Announce a blob transaction + doTxNotify{peer: "B", hashes: []common.Hash{{0x03}}, types: []byte{types.BlobTxType}, sizes: []uint32{333}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, + "B": { + {common.Hash{0x03}, types.BlobTxType, 333}, + }, + }), + doWait{time: 0, step: true}, // zero time, but the blob fetching should be scheduled + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, + }), + isScheduled{ + tracking: map[string][]announce{ + "B": { + {common.Hash{0x03}, types.BlobTxType, 333}, + }, + }, + fetching: map[string][]common.Hash{ // Depends on deterministic test randomizer + "B": {{0x03}}, + }, + }, + doWait{time: txArriveTimeout, step: true}, // zero time, but the blob fetching should be scheduled + isWaiting(nil), + isScheduled{ + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, + "B": { + {common.Hash{0x03}, types.BlobTxType, 333}, + }, + }, + fetching: map[string][]common.Hash{ // Depends on deterministic test randomizer + "A": {{0x01}, {0x02}}, + "B": {{0x03}}, + }, + }, + }, + }) +} + func testTransactionFetcherParallel(t *testing.T, tt txFetcherTest) { t.Parallel() testTransactionFetcher(t, tt) From d71831255da7ecb3817c9e14c9142fe9d4441d3b Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 6 Sep 2024 23:02:34 +0800 Subject: [PATCH 522/571] core/state/snapshot: port changes from 29995 (#30040) #29995 has been reverted due to an unexpected flaw in the state snapshot process. Specifically, it attempts to stop the state snapshot generation, which could potentially cause the system to halt if the generation is not currently running. This pull request ports the changes made in #29995 and fixes the flaw. --- core/state/snapshot/disklayer.go | 23 +++++++++++++++++++ core/state/snapshot/generate.go | 9 +------- core/state/snapshot/snapshot.go | 38 +++++++++----------------------- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/core/state/snapshot/disklayer.go b/core/state/snapshot/disklayer.go index f5518a204ca1..76928edf07f7 100644 --- a/core/state/snapshot/disklayer.go +++ b/core/state/snapshot/disklayer.go @@ -74,6 +74,14 @@ func (dl *diskLayer) Stale() bool { return dl.stale } +// markStale sets the stale flag as true. +func (dl *diskLayer) markStale() { + dl.lock.Lock() + defer dl.lock.Unlock() + + dl.stale = true +} + // Account directly retrieves the account associated with a particular hash in // the snapshot slim data format. func (dl *diskLayer) Account(hash common.Hash) (*types.SlimAccount, error) { @@ -175,3 +183,18 @@ func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro func (dl *diskLayer) Update(blockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { return newDiffLayer(dl, blockHash, destructs, accounts, storage) } + +// stopGeneration aborts the state snapshot generation if it is currently running. +func (dl *diskLayer) stopGeneration() { + dl.lock.RLock() + generating := dl.genMarker != nil + dl.lock.RUnlock() + if !generating { + return + } + if dl.genAbort != nil { + abort := make(chan *generatorStats) + dl.genAbort <- abort + <-abort + } +} diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index d81a628c91fa..6d9e16307516 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -631,16 +631,10 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er accMarker = nil return nil } - // Always reset the initial account range as 1 whenever recover from the - // interruption. TODO(rjl493456442) can we remove it? - var accountRange = accountCheckRange - if len(accMarker) > 0 { - accountRange = 1 - } origin := common.CopyBytes(accMarker) for { id := trie.StateTrieID(dl.root) - exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, types.FullAccountRLP) + exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountCheckRange, onAccount, types.FullAccountRLP) if err != nil { return err // The procedure it aborted, either by external signal or internal error. } @@ -652,7 +646,6 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er ctx.removeStorageLeft() break } - accountRange = accountCheckRange } return nil } diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 752f4359fb85..d1ffb5cc2d97 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -258,24 +258,11 @@ func (t *Tree) Disable() { for _, layer := range t.layers { switch layer := layer.(type) { case *diskLayer: - - layer.lock.RLock() - generating := layer.genMarker != nil - layer.lock.RUnlock() - if !generating { - // Generator is already aborted or finished - break - } - // If the base layer is generating, abort it - if layer.genAbort != nil { - abort := make(chan *generatorStats) - layer.genAbort <- abort - <-abort - } - // Layer should be inactive now, mark it as stale - layer.lock.Lock() - layer.stale = true - layer.lock.Unlock() + // TODO this function will hang if it's called twice. Will + // fix it in the following PRs. + layer.stopGeneration() + layer.markStale() + layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale @@ -730,16 +717,11 @@ func (t *Tree) Rebuild(root common.Hash) { for _, layer := range t.layers { switch layer := layer.(type) { case *diskLayer: - // If the base layer is generating, abort it and save - if layer.genAbort != nil { - abort := make(chan *generatorStats) - layer.genAbort <- abort - <-abort - } - // Layer should be inactive now, mark it as stale - layer.lock.Lock() - layer.stale = true - layer.lock.Unlock() + // TODO this function will hang if it's called twice. Will + // fix it in the following PRs. + layer.stopGeneration() + layer.markStale() + layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale From c70b0a9138fcc711f6b9a3d3007b102ab3b2639d Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:52:20 -0600 Subject: [PATCH 523/571] beacon/engine/types: remove PayloadV4 (#30415) h/t @MariusVanDerWijden for finding and fixing this on devnet 3. I made the mistake of thinking `PayloadVersion` was correlated with the `GetPayloadVX` method, but it actually tracks which version of `PayloadAttributes` were passed to `forkchoiceUpdated`. So far, Prague does not necessitate a new version of fcu, so there is no need for `PayloadV4`. Co-authored-by: Marius van der Wijden --- beacon/engine/types.go | 1 - eth/catalyst/api.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 19d2b2823e37..906056b0a114 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -36,7 +36,6 @@ var ( PayloadV1 PayloadVersion = 0x1 PayloadV2 PayloadVersion = 0x2 PayloadV3 PayloadVersion = 0x3 - PayloadV4 PayloadVersion = 0x4 ) //go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 7ea1c9ee0760..435b1997ff56 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -449,7 +449,7 @@ func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.Execu // GetPayloadV4 returns a cached payload by id. func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { - if !payloadID.Is(engine.PayloadV4) { + if !payloadID.Is(engine.PayloadV3) { return nil, engine.UnsupportedFork } return api.getPayload(payloadID, false) From ec69830b6f4520c0d847cad3cf61d8a4da9db178 Mon Sep 17 00:00:00 2001 From: Dylan Vassallo Date: Wed, 11 Sep 2024 15:11:08 +0200 Subject: [PATCH 524/571] core/vm: remove panic when address is not present (#30414) Remove redundant address presence check in `makeGasSStoreFunc`. This PR simplifies the `makeGasSStoreFunc` function by removing the redundant check for address presence in the access list. The updated code now only checks for slot presence, streamlining the logic and eliminating unnecessary panic conditions. This change removes the unnecessary address presence check, simplifying the code and improving maintainability without affecting functionality. The previous panic condition was intended as a canary during the testing phases (i.e. _YOLOv2_) and is no longer needed. --- core/vm/operations_acl.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 289da44be3aa..1cdaaba51669 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -39,16 +39,10 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc { cost = uint64(0) ) // Check slot presence in the access list - if addrPresent, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent { + if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent { cost = params.ColdSloadCostEIP2929 // If the caller cannot afford the cost, this change will be rolled back evm.StateDB.AddSlotToAccessList(contract.Address(), slot) - if !addrPresent { - // Once we're done with YOLOv2 and schedule this for mainnet, might - // be good to remove this panic here, which is just really a - // canary to have during testing - panic("impossible case: address was not present in access list during sstore op") - } } value := common.Hash(y.Bytes32()) From a01e9742d997ea9e6cedfee41cba433433de9e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 12 Sep 2024 16:08:29 +0200 Subject: [PATCH 525/571] beacon/light/api: fixed blsync update query (#30421) This PR fixes what https://github.com/ethereum/go-ethereum/pull/30306/ broke. Escaping the `?` in the event sub query was fixed in that PR but it was still escaped in the `updates` request. This PR adds a URL params argument to `httpGet` and fixes `updates` query formatting. --- beacon/light/api/light_api.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 45b425164f91..91f66c08be94 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -24,6 +24,7 @@ import ( "io" "net/http" "net/url" + "strconv" "sync" "time" @@ -121,8 +122,8 @@ func NewBeaconLightApi(url string, customHeaders map[string]string) *BeaconLight } } -func (api *BeaconLightApi) httpGet(path string) ([]byte, error) { - uri, err := api.buildURL(path, nil) +func (api *BeaconLightApi) httpGet(path string, params url.Values) ([]byte, error) { + uri, err := api.buildURL(path, params) if err != nil { return nil, err } @@ -150,17 +151,16 @@ func (api *BeaconLightApi) httpGet(path string) ([]byte, error) { } } -func (api *BeaconLightApi) httpGetf(format string, params ...any) ([]byte, error) { - return api.httpGet(fmt.Sprintf(format, params...)) -} - // GetBestUpdatesAndCommittees fetches and validates LightClientUpdate for given // period and full serialized committee for the next period (committee root hash // equals update.NextSyncCommitteeRoot). // Note that the results are validated but the update signature should be verified // by the caller as its validity depends on the update chain. func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64) ([]*types.LightClientUpdate, []*types.SerializedSyncCommittee, error) { - resp, err := api.httpGetf("/eth/v1/beacon/light_client/updates?start_period=%d&count=%d", firstPeriod, count) + resp, err := api.httpGet("/eth/v1/beacon/light_client/updates", map[string][]string{ + "start_period": {strconv.FormatUint(firstPeriod, 10)}, + "count": {strconv.FormatUint(count, 10)}, + }) if err != nil { return nil, nil, err } @@ -197,7 +197,7 @@ func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64 // See data structure definition here: // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error) { - resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update") + resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update", nil) if err != nil { return types.OptimisticUpdate{}, err } @@ -250,7 +250,7 @@ func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) { // See data structure definition here: // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) { - resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update") + resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update", nil) if err != nil { return types.FinalityUpdate{}, err } @@ -316,7 +316,7 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool, } else { blockId = blockRoot.Hex() } - resp, err := api.httpGetf("/eth/v1/beacon/headers/%s", blockId) + resp, err := api.httpGet(fmt.Sprintf("/eth/v1/beacon/headers/%s", blockId), nil) if err != nil { return types.Header{}, false, false, err } @@ -347,7 +347,7 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool, // GetCheckpointData fetches and validates bootstrap data belonging to the given checkpoint. func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types.BootstrapData, error) { - resp, err := api.httpGetf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:]) + resp, err := api.httpGet(fmt.Sprintf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:]), nil) if err != nil { return nil, err } @@ -389,7 +389,7 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types } func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconBlock, error) { - resp, err := api.httpGetf("/eth/v2/beacon/blocks/0x%x", blockRoot) + resp, err := api.httpGet(fmt.Sprintf("/eth/v2/beacon/blocks/0x%x", blockRoot), nil) if err != nil { return nil, err } From 7c6b3f9f14b79b68e86ad2b04b63bf840cce3242 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Fri, 13 Sep 2024 02:16:47 -0700 Subject: [PATCH 526/571] eth/filters: prevent concurrent access in test (#30401) use a mutex to prevent concurrent access to the api.filters map during `TestPendingTxFilterDeadlock` test --- eth/filters/filter_system_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 013b9f7bc26c..1d52afb28243 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -601,7 +601,9 @@ func TestPendingTxFilterDeadlock(t *testing.T) { subs := make([]*Subscription, 20) for i := 0; i < len(subs); i++ { fid := api.NewPendingTransactionFilter(nil) + api.filtersMu.Lock() f, ok := api.filters[fid] + api.filtersMu.Unlock() if !ok { t.Fatalf("Filter %s should exist", fid) } From c0b5d428a9a88ddd82605983bbd1b612dc61672d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 13 Sep 2024 17:17:40 +0800 Subject: [PATCH 527/571] core/rawdb: more accurate description of freezer in docs (#30393) fixes https://github.com/ethereum/go-ethereum/issues/29793 --- core/rawdb/freezer.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 6c050ee625e5..1b8df958d1f7 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -52,13 +52,11 @@ var ( // freezerTableSize defines the maximum size of freezer data files. const freezerTableSize = 2 * 1000 * 1000 * 1000 -// Freezer is a memory mapped append-only database to store immutable ordered -// data into flat files: +// Freezer is an append-only database to store immutable ordered data into +// flat files: // -// - The append-only nature ensures that disk writes are minimized. -// - The memory mapping ensures we can max out system memory for caching without -// reserving it for go-ethereum. This would also reduce the memory requirements -// of Geth, and thus also GC overhead. +// - The append-only nature ensures that disk writes are minimized. +// - The in-order data ensures that disk reads are always optimized. type Freezer struct { frozen atomic.Uint64 // Number of items already frozen tail atomic.Uint64 // Number of the first stored item in the freezer @@ -152,7 +150,7 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui return freezer, nil } -// Close terminates the chain freezer, unmapping all the data files. +// Close terminates the chain freezer, closing all the data files. func (f *Freezer) Close() error { f.writeLock.Lock() defer f.writeLock.Unlock() From 9be2e010c1e48fe9a042866b15bab074681f08fe Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:37:30 +0200 Subject: [PATCH 528/571] core/state, core/vm: Nyota contract create init simplification (#30409) Implementation of [this EIP-4762 update](https://github.com/ethereum/EIPs/pull/8867). --------- Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: Tanishq Jasoria --- core/state/access_events.go | 14 ++++++++++++- core/state/access_events_test.go | 6 +++--- core/tracing/hooks.go | 2 ++ core/vm/evm.go | 35 +++++++++++++++++++++----------- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/core/state/access_events.go b/core/state/access_events.go index c593f8202721..2b270ccafab3 100644 --- a/core/state/access_events.go +++ b/core/state/access_events.go @@ -117,11 +117,23 @@ func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) return gas } +// ContractCreateCPreheck charges access costs before +// a contract creation is initiated. It is just reads, because the +// address collision is done before the transfer, and so no write +// are guaranteed to happen at this point. +func (ae *AccessEvents) ContractCreatePreCheckGas(addr common.Address) uint64 { + var gas uint64 + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, false) + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false) + return gas +} + // ContractCreateInitGas returns the access gas costs for the initialization of // a contract creation. -func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 { +func (ae *AccessEvents) ContractCreateInitGas(addr common.Address) uint64 { var gas uint64 gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true) + gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, true) return gas } diff --git a/core/state/access_events_test.go b/core/state/access_events_test.go index a35266950e64..10630b3181b5 100644 --- a/core/state/access_events_test.go +++ b/core/state/access_events_test.go @@ -100,13 +100,13 @@ func TestContractCreateInitGas(t *testing.T) { } // Check cold read cost, without a value - gas := ae.ContractCreateInitGas(testAddr, false) - if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want { + gas := ae.ContractCreateInitGas(testAddr) + if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + 2*params.WitnessChunkWriteCost + 2*params.WitnessChunkReadCost; gas != want { t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check warm read cost - gas = ae.ContractCreateInitGas(testAddr, false) + gas = ae.ContractCreateInitGas(testAddr) if gas != 0 { t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index aa66dc49ff09..4ac4e0c8c518 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -306,6 +306,8 @@ const ( GasChangeWitnessContractCreation GasChangeReason = 16 // GasChangeWitnessCodeChunk is the amount charged for touching one or more contract code chunks GasChangeWitnessCodeChunk GasChangeReason = 17 + // GasChangeWitnessContractCollisionCheck the amount charged for checking a contract collision + GasChangeWitnessContractCollisionCheck GasChangeReason = 17 // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as // it will be "manually" tracked by a direct emit of the gas change event. diff --git a/core/vm/evm.go b/core/vm/evm.go index a9c4ae9fe54d..616668d565cc 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -448,6 +448,18 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } evm.StateDB.SetNonce(caller.Address(), nonce+1) + // Charge the contract creation init gas in verkle mode + if evm.chainRules.IsEIP4762 { + statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address) + if statelessGas > gas { + return nil, common.Address{}, 0, ErrOutOfGas + } + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractCollisionCheck) + } + gas = gas - statelessGas + } + // We add this to the access list _before_ taking a snapshot. Even if the // creation fails, the access-list change should not be rolled back. if evm.chainRules.IsEIP2929 { @@ -484,6 +496,17 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.chainRules.IsEIP158 { evm.StateDB.SetNonce(address, 1) } + // Charge the contract creation init gas in verkle mode + if evm.chainRules.IsEIP4762 { + statelessGas := evm.AccessEvents.ContractCreateInitGas(address) + if statelessGas > gas { + return nil, common.Address{}, 0, ErrOutOfGas + } + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractInit) + } + gas = gas - statelessGas + } evm.Context.Transfer(evm.StateDB, caller.Address(), address, value) // Initialise a new contract and set the code that is to be used by the EVM. @@ -505,13 +528,6 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // initNewContract runs a new contract's creation code, performs checks on the // resulting code that is to be deployed, and consumes necessary gas. func (evm *EVM) initNewContract(contract *Contract, address common.Address, value *uint256.Int) ([]byte, error) { - // Charge the contract creation init gas in verkle mode - if evm.chainRules.IsEIP4762 { - if !contract.UseGas(evm.AccessEvents.ContractCreateInitGas(address, value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) { - return nil, ErrOutOfGas - } - } - ret, err := evm.interpreter.Run(contract, nil, false) if err != nil { return ret, err @@ -533,11 +549,6 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu return ret, ErrCodeStoreOutOfGas } } else { - // Contract creation completed, touch the missing fields in the contract - if !contract.UseGas(evm.AccessEvents.AddAccount(address, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) { - return ret, ErrCodeStoreOutOfGas - } - if len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) { return ret, ErrCodeStoreOutOfGas } From f544fc3b4659aeca24a6de83f820dd61ea9b39db Mon Sep 17 00:00:00 2001 From: Guillaume Michel Date: Fri, 13 Sep 2024 23:47:18 +0200 Subject: [PATCH 529/571] p2p/enode: add quic ENR entry (#30283) Add `quic` entry to the ENR as proposed in https://github.com/ethereum/consensus-specs/pull/3644 --------- Co-authored-by: lightclient --- p2p/enode/node.go | 14 ++++++++ p2p/enode/node_test.go | 72 +++++++++++++++++++++++++++++++++++++++--- p2p/enr/entries.go | 10 ++++++ 3 files changed, 91 insertions(+), 5 deletions(-) diff --git a/p2p/enode/node.go b/p2p/enode/node.go index cb4ac8d1726c..4d93d3f6be8b 100644 --- a/p2p/enode/node.go +++ b/p2p/enode/node.go @@ -200,6 +200,20 @@ func (n *Node) TCPEndpoint() (netip.AddrPort, bool) { return netip.AddrPortFrom(n.ip, n.tcp), true } +// QUICEndpoint returns the announced QUIC endpoint. +func (n *Node) QUICEndpoint() (netip.AddrPort, bool) { + var quic uint16 + if n.ip.Is4() || n.ip.Is4In6() { + n.Load((*enr.QUIC)(&quic)) + } else if n.ip.Is6() { + n.Load((*enr.QUIC6)(&quic)) + } + if !n.ip.IsValid() || n.ip.IsUnspecified() || quic == 0 { + return netip.AddrPort{}, false + } + return netip.AddrPortFrom(n.ip, quic), true +} + // Pubkey returns the secp256k1 public key of the node, if present. func (n *Node) Pubkey() *ecdsa.PublicKey { var key ecdsa.PublicKey diff --git a/p2p/enode/node_test.go b/p2p/enode/node_test.go index 56e196e82e2d..f38c77415e07 100644 --- a/p2p/enode/node_test.go +++ b/p2p/enode/node_test.go @@ -68,11 +68,12 @@ func TestPythonInterop(t *testing.T) { func TestNodeEndpoints(t *testing.T) { id := HexID("00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") type endpointTest struct { - name string - node *Node - wantIP netip.Addr - wantUDP int - wantTCP int + name string + node *Node + wantIP netip.Addr + wantUDP int + wantTCP int + wantQUIC int } tests := []endpointTest{ { @@ -98,6 +99,22 @@ func TestNodeEndpoints(t *testing.T) { return SignNull(&r, id) }(), }, + { + name: "quic-only", + node: func() *Node { + var r enr.Record + r.Set(enr.QUIC(9000)) + return SignNull(&r, id) + }(), + }, + { + name: "quic6-only", + node: func() *Node { + var r enr.Record + r.Set(enr.QUIC6(9000)) + return SignNull(&r, id) + }(), + }, { name: "ipv4-only-loopback", node: func() *Node { @@ -209,6 +226,48 @@ func TestNodeEndpoints(t *testing.T) { wantIP: netip.MustParseAddr("192.168.2.2"), wantUDP: 30304, }, + { + name: "ipv4-quic", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("99.22.33.1"))) + r.Set(enr.QUIC(9001)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("99.22.33.1"), + wantQUIC: 9001, + }, + { // Because the node is IPv4, the quic6 entry won't be loaded. + name: "ipv4-quic6", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("99.22.33.1"))) + r.Set(enr.QUIC6(9001)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("99.22.33.1"), + }, + { + name: "ipv6-quic", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + r.Set(enr.QUIC(9001)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + }, + { + name: "ipv6-quic6", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + r.Set(enr.QUIC6(9001)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + wantQUIC: 9001, + }, } for _, test := range tests { @@ -222,6 +281,9 @@ func TestNodeEndpoints(t *testing.T) { if test.wantTCP != test.node.TCP() { t.Errorf("node has wrong TCP port %d, want %d", test.node.TCP(), test.wantTCP) } + if quic, _ := test.node.QUICEndpoint(); test.wantQUIC != int(quic.Port()) { + t.Errorf("node has wrong QUIC port %d, want %d", quic.Port(), test.wantQUIC) + } }) } } diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index 155ec4c02320..58e660c15471 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -77,6 +77,16 @@ type UDP6 uint16 func (v UDP6) ENRKey() string { return "udp6" } +// QUIC is the "quic" key, which holds the QUIC port of the node. +type QUIC uint16 + +func (v QUIC) ENRKey() string { return "quic" } + +// QUIC6 is the "quic6" key, which holds the IPv6-specific quic6 port of the node. +type QUIC6 uint16 + +func (v QUIC6) ENRKey() string { return "quic6" } + // ID is the "id" key, which holds the name of the identity scheme. type ID string From 07b5a04bd61e851cfb530d21828dc4457b554f05 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Sat, 14 Sep 2024 15:44:42 +0200 Subject: [PATCH 530/571] core/tracing: fix copy/paste error+comments in reason listing (#30431) Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> --- core/tracing/hooks.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 4ac4e0c8c518..d3c86485483b 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -300,14 +300,14 @@ const ( GasChangeCallStorageColdAccess GasChangeReason = 13 // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert. GasChangeCallFailedExecution GasChangeReason = 14 - // GasChangeWitnessContractInit is the amount charged for adding to the witness during the contract creation initialization step + // GasChangeWitnessContractInit flags the event of of adding to the witness during the contract creation initialization step GasChangeWitnessContractInit GasChangeReason = 15 - // GasChangeWitnessContractCreation is the amount charged for adding to the witness during the contract creation finalization step + // GasChangeWitnessContractCreation flags the event of adding to the witness during the contract creation finalization step GasChangeWitnessContractCreation GasChangeReason = 16 - // GasChangeWitnessCodeChunk is the amount charged for touching one or more contract code chunks + // GasChangeWitnessCodeChunk flags the event of adding one or more contract code chunks to the witness GasChangeWitnessCodeChunk GasChangeReason = 17 - // GasChangeWitnessContractCollisionCheck the amount charged for checking a contract collision - GasChangeWitnessContractCollisionCheck GasChangeReason = 17 + // GasChangeWitnessContractCollisionCheck flags the event of adding to the witness when checking for contract address collision + GasChangeWitnessContractCollisionCheck GasChangeReason = 18 // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as // it will be "manually" tracked by a direct emit of the gas change event. From 0dd7e82c0aef3c27303b4a7b30016790dda949d4 Mon Sep 17 00:00:00 2001 From: maskpp Date: Sat, 14 Sep 2024 21:45:52 +0800 Subject: [PATCH 531/571] core/txpool/blobpool: avoid possible zero index panic (#30430) This situation(`len(txs) == 0`) rarely occurs, but if it does, it will panic. --------- Co-authored-by: Martin HS --- core/txpool/blobpool/blobpool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index d66a08aa17a4..aa76ef774df0 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -566,7 +566,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6 ids []uint64 nonces []uint64 ) - for txs[0].nonce < next { + for len(txs) > 0 && txs[0].nonce < next { ids = append(ids, txs[0].id) nonces = append(nonces, txs[0].nonce) From ae707445f54972f4fddc7c6cf8ba2de083636e50 Mon Sep 17 00:00:00 2001 From: steven Date: Sun, 15 Sep 2024 08:55:53 +0800 Subject: [PATCH 532/571] core/rawdb: remove unused transition status state accessors (#30433) --- core/rawdb/accessors_metadata.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go index 859566f722f5..6996031be2cf 100644 --- a/core/rawdb/accessors_metadata.go +++ b/core/rawdb/accessors_metadata.go @@ -174,16 +174,3 @@ func UpdateUncleanShutdownMarker(db ethdb.KeyValueStore) { log.Warn("Failed to write unclean-shutdown marker", "err", err) } } - -// ReadTransitionStatus retrieves the eth2 transition status from the database -func ReadTransitionStatus(db ethdb.KeyValueReader) []byte { - data, _ := db.Get(transitionStatusKey) - return data -} - -// WriteTransitionStatus stores the eth2 transition status to the database -func WriteTransitionStatus(db ethdb.KeyValueWriter, data []byte) { - if err := db.Put(transitionStatusKey, data); err != nil { - log.Crit("Failed to store the eth2 transition status", "err", err) - } -} From 4c4f21293ef5243267c9fac7deab0b0dc7630141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Anda=20Estensen?= Date: Mon, 16 Sep 2024 08:44:47 +0200 Subject: [PATCH 533/571] internal: run tests in parallel (#30381) Continuation of https://github.com/ethereum/go-ethereum/pull/28546 --- internal/era/e2store/e2store_test.go | 5 +++++ internal/era/era_test.go | 4 ++++ internal/ethapi/api_test.go | 7 ++++++- internal/ethapi/transaction_args_test.go | 2 ++ internal/flags/flags_test.go | 14 ++++++++++---- internal/guide/guide_test.go | 2 ++ internal/jsre/completion_test.go | 14 ++++++++++---- internal/jsre/jsre_test.go | 8 ++++++++ internal/utesting/utesting_test.go | 6 ++++++ 9 files changed, 53 insertions(+), 9 deletions(-) diff --git a/internal/era/e2store/e2store_test.go b/internal/era/e2store/e2store_test.go index b0803493c7cd..353942f0bde0 100644 --- a/internal/era/e2store/e2store_test.go +++ b/internal/era/e2store/e2store_test.go @@ -26,6 +26,8 @@ import ( ) func TestEncode(t *testing.T) { + t.Parallel() + for _, test := range []struct { entries []Entry want string @@ -53,6 +55,7 @@ func TestEncode(t *testing.T) { tt := test t.Run(tt.name, func(t *testing.T) { t.Parallel() + var ( b = bytes.NewBuffer(nil) w = NewWriter(b) @@ -83,6 +86,8 @@ func TestEncode(t *testing.T) { } func TestDecode(t *testing.T) { + t.Parallel() + for i, tt := range []struct { have string err error diff --git a/internal/era/era_test.go b/internal/era/era_test.go index 883e30f7b659..d0f56b6f8864 100644 --- a/internal/era/era_test.go +++ b/internal/era/era_test.go @@ -34,6 +34,8 @@ type testchain struct { } func TestEra1Builder(t *testing.T) { + t.Parallel() + // Get temp directory. f, err := os.CreateTemp("", "era1-test") if err != nil { @@ -125,6 +127,8 @@ func TestEra1Builder(t *testing.T) { } func TestEraFilename(t *testing.T) { + t.Parallel() + for i, tt := range []struct { network string epoch int diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index f2dd93e4ac0a..384ca9f1cc73 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -61,7 +61,6 @@ import ( ) func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainConfig) { - t.Parallel() var ( signer = types.LatestSigner(config) key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -98,6 +97,8 @@ func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainCo } func TestTransaction_RoundTripRpcJSON(t *testing.T) { + t.Parallel() + var ( config = params.AllEthashProtocolChanges tests = allTransactionTypes(common.Address{0xde, 0xad}, config) @@ -106,6 +107,8 @@ func TestTransaction_RoundTripRpcJSON(t *testing.T) { } func TestTransactionBlobTx(t *testing.T) { + t.Parallel() + config := *params.TestChainConfig config.ShanghaiTime = new(uint64) config.CancunTime = new(uint64) @@ -2460,6 +2463,8 @@ func TestFillBlobTransaction(t *testing.T) { } for _, tc := range suite { t.Run(tc.name, func(t *testing.T) { + t.Parallel() + res, err := api.FillTransaction(context.Background(), tc.args) if len(tc.err) > 0 { if err == nil { diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 6750fc07a944..531782817328 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -42,6 +42,8 @@ import ( // TestSetFeeDefaults tests the logic for filling in default fee values works as expected. func TestSetFeeDefaults(t *testing.T) { + t.Parallel() + type test struct { name string fork string // options: legacy, london, cancun diff --git a/internal/flags/flags_test.go b/internal/flags/flags_test.go index 681586b46c74..cfe16b340e72 100644 --- a/internal/flags/flags_test.go +++ b/internal/flags/flags_test.go @@ -24,6 +24,8 @@ import ( ) func TestPathExpansion(t *testing.T) { + t.Parallel() + user, _ := user.Current() var tests map[string]string @@ -53,9 +55,13 @@ func TestPathExpansion(t *testing.T) { os.Setenv(`DDDXXX`, `/tmp`) for test, expected := range tests { - got := expandPath(test) - if got != expected { - t.Errorf(`test %s, got %s, expected %s\n`, test, got, expected) - } + t.Run(test, func(t *testing.T) { + t.Parallel() + + got := expandPath(test) + if got != expected { + t.Errorf(`test %s, got %s, expected %s\n`, test, got, expected) + } + }) } } diff --git a/internal/guide/guide_test.go b/internal/guide/guide_test.go index f682daac91b0..573898d7d07e 100644 --- a/internal/guide/guide_test.go +++ b/internal/guide/guide_test.go @@ -35,6 +35,8 @@ import ( // Tests that the account management snippets work correctly. func TestAccountManagement(t *testing.T) { + t.Parallel() + // Create a temporary folder to work with workdir := t.TempDir() diff --git a/internal/jsre/completion_test.go b/internal/jsre/completion_test.go index 953bc5026dac..8fbddbc299c1 100644 --- a/internal/jsre/completion_test.go +++ b/internal/jsre/completion_test.go @@ -23,6 +23,8 @@ import ( ) func TestCompleteKeywords(t *testing.T) { + t.Parallel() + re := New("", os.Stdout) re.Run(` function theClass() { @@ -85,9 +87,13 @@ func TestCompleteKeywords(t *testing.T) { }, } for _, test := range tests { - cs := re.CompleteKeywords(test.input) - if !reflect.DeepEqual(cs, test.want) { - t.Errorf("wrong completions for %q\ngot %v\nwant %v", test.input, cs, test.want) - } + t.Run(test.input, func(t *testing.T) { + t.Parallel() + + cs := re.CompleteKeywords(test.input) + if !reflect.DeepEqual(cs, test.want) { + t.Errorf("wrong completions for %q\ngot %v\nwant %v", test.input, cs, test.want) + } + }) } } diff --git a/internal/jsre/jsre_test.go b/internal/jsre/jsre_test.go index 18ef39e2f470..a812d6116d82 100644 --- a/internal/jsre/jsre_test.go +++ b/internal/jsre/jsre_test.go @@ -51,6 +51,8 @@ func newWithTestJS(t *testing.T, testjs string) *JSRE { } func TestExec(t *testing.T) { + t.Parallel() + jsre := newWithTestJS(t, `msg = "testMsg"`) err := jsre.Exec("test.js") @@ -73,6 +75,8 @@ func TestExec(t *testing.T) { } func TestNatto(t *testing.T) { + t.Parallel() + jsre := newWithTestJS(t, `setTimeout(function(){msg = "testMsg"}, 1);`) err := jsre.Exec("test.js") @@ -96,6 +100,8 @@ func TestNatto(t *testing.T) { } func TestBind(t *testing.T) { + t.Parallel() + jsre := New("", os.Stdout) defer jsre.Stop(false) @@ -108,6 +114,8 @@ func TestBind(t *testing.T) { } func TestLoadScript(t *testing.T) { + t.Parallel() + jsre := newWithTestJS(t, `msg = "testMsg"`) _, err := jsre.Run(`loadScript("test.js")`) diff --git a/internal/utesting/utesting_test.go b/internal/utesting/utesting_test.go index 31c7911c52f0..526d36bab1e3 100644 --- a/internal/utesting/utesting_test.go +++ b/internal/utesting/utesting_test.go @@ -24,6 +24,8 @@ import ( ) func TestTest(t *testing.T) { + t.Parallel() + tests := []Test{ { Name: "successful test", @@ -90,6 +92,8 @@ var outputTests = []Test{ } func TestOutput(t *testing.T) { + t.Parallel() + var buf bytes.Buffer RunTests(outputTests, &buf) @@ -116,6 +120,8 @@ $`[1:]) } func TestOutputTAP(t *testing.T) { + t.Parallel() + var buf bytes.Buffer RunTAP(outputTests, &buf) From 03424962f11bbbbfe79a6d830944ce194a61c3b1 Mon Sep 17 00:00:00 2001 From: piersy Date: Mon, 16 Sep 2024 07:51:03 +0100 Subject: [PATCH 534/571] core/types: more easily extensible tx signing (#30372) This change makes the code slightly easier for downstream-projects to extend with more signer-types, but if functionalily equivalent to the previous code. --- core/types/transaction_signing.go | 36 ++++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index dd25f081f79a..73011e238b58 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -64,21 +64,24 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint // Use this in transaction-handling code where the current block number is unknown. If you // have the current block number available, use MakeSigner instead. func LatestSigner(config *params.ChainConfig) Signer { + var signer Signer if config.ChainID != nil { - if config.CancunTime != nil { - return NewCancunSigner(config.ChainID) - } - if config.LondonBlock != nil { - return NewLondonSigner(config.ChainID) - } - if config.BerlinBlock != nil { - return NewEIP2930Signer(config.ChainID) - } - if config.EIP155Block != nil { - return NewEIP155Signer(config.ChainID) + switch { + case config.CancunTime != nil: + signer = NewCancunSigner(config.ChainID) + case config.LondonBlock != nil: + signer = NewLondonSigner(config.ChainID) + case config.BerlinBlock != nil: + signer = NewEIP2930Signer(config.ChainID) + case config.EIP155Block != nil: + signer = NewEIP155Signer(config.ChainID) + default: + signer = HomesteadSigner{} } + } else { + signer = HomesteadSigner{} } - return HomesteadSigner{} + return signer } // LatestSignerForChainID returns the 'most permissive' Signer available. Specifically, @@ -89,10 +92,13 @@ func LatestSigner(config *params.ChainConfig) Signer { // configuration are unknown. If you have a ChainConfig, use LatestSigner instead. // If you have a ChainConfig and know the current block number, use MakeSigner instead. func LatestSignerForChainID(chainID *big.Int) Signer { - if chainID == nil { - return HomesteadSigner{} + var signer Signer + if chainID != nil { + signer = NewCancunSigner(chainID) + } else { + signer = HomesteadSigner{} } - return NewCancunSigner(chainID) + return signer } // SignTx signs the transaction using the given signer and private key. From ec596e06a58f3c4c4bac0262ebfc57539c3e5fd1 Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 16 Sep 2024 16:56:02 +0800 Subject: [PATCH 535/571] core, trie: prealloc capacity for maps (#30437) - preallocate capacity for map - avoid `reinject` adding empty value - use `maps.Copy` --- core/stateless/witness.go | 4 +--- core/txpool/blobpool/blobpool.go | 6 ++++-- core/types/transaction.go | 2 +- trie/trie.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/stateless/witness.go b/core/stateless/witness.go index 7622c5eb610d..0f2d6cfe079c 100644 --- a/core/stateless/witness.go +++ b/core/stateless/witness.go @@ -101,9 +101,7 @@ func (w *Witness) AddState(nodes map[string]struct{}) { w.lock.Lock() defer w.lock.Unlock() - for node := range nodes { - w.State[node] = struct{}{} - } + maps.Copy(w.State, nodes) } // Copy deep-copies the witness object. Witness.Block isn't deep-copied as it diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index aa76ef774df0..685c017cbdb6 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -940,7 +940,7 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]* } // Generate the set of transactions per address to pull back into the pool, // also updating the rest along the way - reinject := make(map[common.Address][]*types.Transaction) + reinject := make(map[common.Address][]*types.Transaction, len(transactors)) for addr := range transactors { // Generate the set that was lost to reinject into the pool lost := make([]*types.Transaction, 0, len(discarded[addr])) @@ -949,7 +949,9 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]* lost = append(lost, tx) } } - reinject[addr] = lost + if len(lost) > 0 { + reinject[addr] = lost + } // Update the set that was already reincluded to track the blocks in limbo for _, tx := range types.TxDifference(included[addr], discarded[addr]) { diff --git a/core/types/transaction.go b/core/types/transaction.go index 4ac9187bdbfe..6c8759ee69b6 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -560,7 +560,7 @@ func (s Transactions) EncodeIndex(i int, w *bytes.Buffer) { func TxDifference(a, b Transactions) Transactions { keep := make(Transactions, 0, len(a)) - remove := make(map[common.Hash]struct{}) + remove := make(map[common.Hash]struct{}, b.Len()) for _, tx := range b { remove[tx.Hash()] = struct{}{} } diff --git a/trie/trie.go b/trie/trie.go index f44e10b918d4..885b6b79628c 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -666,7 +666,7 @@ func (t *Trie) Witness() map[string]struct{} { if len(t.tracer.accessList) == 0 { return nil } - witness := make(map[string]struct{}) + witness := make(map[string]struct{}, len(t.tracer.accessList)) for _, node := range t.tracer.accessList { witness[string(node)] = struct{}{} } From 8dd296201d828933cd49f4a2e874b743f324a49a Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Tue, 17 Sep 2024 02:57:31 +0900 Subject: [PATCH 536/571] core/tracing: fix typo in comment (#30443) minor fix --- core/tracing/hooks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index d3c86485483b..3d4a162da0eb 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -300,7 +300,7 @@ const ( GasChangeCallStorageColdAccess GasChangeReason = 13 // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert. GasChangeCallFailedExecution GasChangeReason = 14 - // GasChangeWitnessContractInit flags the event of of adding to the witness during the contract creation initialization step + // GasChangeWitnessContractInit flags the event of adding to the witness during the contract creation initialization step GasChangeWitnessContractInit GasChangeReason = 15 // GasChangeWitnessContractCreation flags the event of adding to the witness during the contract creation finalization step GasChangeWitnessContractCreation GasChangeReason = 16 From 8032b63f167938e6441d4be3eb49b12014d9bfc8 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:10:59 +0200 Subject: [PATCH 537/571] core/tracing: add verkle gas change reasons to changelog (#30444) Add changes from #30409 and #29338 to changelog. --------- Co-authored-by: Martin HS Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> --- core/tracing/CHANGELOG.md | 21 ++++++++++++++++++++- core/tracing/hooks.go | 8 ++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/core/tracing/CHANGELOG.md b/core/tracing/CHANGELOG.md index cddc728fc0f1..e8aa3a9e2ebe 100644 --- a/core/tracing/CHANGELOG.md +++ b/core/tracing/CHANGELOG.md @@ -2,6 +2,24 @@ All notable changes to the tracing interface will be documented in this file. +## [Unreleased] + +### Modified types + +- `GasChangeReason` has been extended with the following reasons which will be enabled only post-Verkle. There shouldn't be any gas changes with those reasons prior to the fork. + - `GasChangeWitnessContractCollisionCheck` flags the event of adding to the witness when checking for contract address collision. + +## [v1.14.4] + +This release contained only minor extensions to the tracing interface. + +### Modified types + +- `GasChangeReason` has been extended with the following reasons that will only be active post-Verkle. + - `GasChangeWitnessContractInit` flags the event of adding to the witness during the contract creation initialization step. + - `GasChangeWitnessContractCreation` flags the event of adding to the witness during the contract creation finalization step. + - `GasChangeWitnessCodeChunk` flags the event of adding one or more contract code chunks to the witness. + ## [v1.14.3] There have been minor backwards-compatible changes to the tracing interface to explicitly mark the execution of **system** contracts. As of now the only system call updates the parent beacon block root as per [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). Other system calls are being considered for the future hardfork. @@ -75,6 +93,7 @@ The hooks `CaptureStart` and `CaptureEnd` have been removed. These hooks signale - `CaptureState` -> `OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error)`. `op` is of type `byte` which can be cast to `vm.OpCode` when necessary. A `*vm.ScopeContext` is not passed anymore. It is replaced by `tracing.OpContext` which offers access to the memory, stack and current contract. - `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above. -[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.0...master +[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.8...master [v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0 [v1.14.3]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.3 +[v1.14.4]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.4 diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 3d4a162da0eb..987dfa7a1e03 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -300,13 +300,13 @@ const ( GasChangeCallStorageColdAccess GasChangeReason = 13 // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert. GasChangeCallFailedExecution GasChangeReason = 14 - // GasChangeWitnessContractInit flags the event of adding to the witness during the contract creation initialization step + // GasChangeWitnessContractInit flags the event of adding to the witness during the contract creation initialization step. GasChangeWitnessContractInit GasChangeReason = 15 - // GasChangeWitnessContractCreation flags the event of adding to the witness during the contract creation finalization step + // GasChangeWitnessContractCreation flags the event of adding to the witness during the contract creation finalization step. GasChangeWitnessContractCreation GasChangeReason = 16 - // GasChangeWitnessCodeChunk flags the event of adding one or more contract code chunks to the witness + // GasChangeWitnessCodeChunk flags the event of adding one or more contract code chunks to the witness. GasChangeWitnessCodeChunk GasChangeReason = 17 - // GasChangeWitnessContractCollisionCheck flags the event of adding to the witness when checking for contract address collision + // GasChangeWitnessContractCollisionCheck flags the event of adding to the witness when checking for contract address collision. GasChangeWitnessContractCollisionCheck GasChangeReason = 18 // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as From d09600fdf9638cf9a3dc35aec9697b7d97cff200 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:53:50 +0200 Subject: [PATCH 538/571] Revert "core/rawdb: remove unused transition status state accessors" (#30449) Reverts ethereum/go-ethereum#30433 --- core/rawdb/accessors_metadata.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go index 6996031be2cf..859566f722f5 100644 --- a/core/rawdb/accessors_metadata.go +++ b/core/rawdb/accessors_metadata.go @@ -174,3 +174,16 @@ func UpdateUncleanShutdownMarker(db ethdb.KeyValueStore) { log.Warn("Failed to write unclean-shutdown marker", "err", err) } } + +// ReadTransitionStatus retrieves the eth2 transition status from the database +func ReadTransitionStatus(db ethdb.KeyValueReader) []byte { + data, _ := db.Get(transitionStatusKey) + return data +} + +// WriteTransitionStatus stores the eth2 transition status to the database +func WriteTransitionStatus(db ethdb.KeyValueWriter, data []byte) { + if err := db.Put(transitionStatusKey, data); err != nil { + log.Crit("Failed to store the eth2 transition status", "err", err) + } +} From f321dfa827119d1b46751b0a61fe9d095e2d467f Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:27:03 +0200 Subject: [PATCH 539/571] params: release go-ethereum v1.14.9 stable (#30455) --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 22e59d6838f9..a7d8a4a6d283 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 9 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 9 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From af794ef682bc2c481ccf9ad01d3492910c50ce61 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:48:47 +0200 Subject: [PATCH 540/571] params: begin v1.14.10 release cycle (#30457) --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index a7d8a4a6d283..22eabc08f9a1 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 9 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 10 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 868d53c2f22ab97259baa8e978276db6d30e7058 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 19 Sep 2024 08:35:14 +0200 Subject: [PATCH 541/571] genesis: fix dev mode alloc (#30460) Balance being null causes `getGenesisState` to fail as the balance field is required in json marshaling of an account. --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index 8ea9bfb30ff8..31db49f527e4 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -591,7 +591,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { // Pre-deploy EIP-4788 system contract params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, // Pre-deploy EIP-2935 history contract. - params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode}, + params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0}, }, } if faucet != nil { From c4c2c4fb141c46fc0d6d7547700bdec4c9046a84 Mon Sep 17 00:00:00 2001 From: Szupingwang Date: Thu, 19 Sep 2024 14:38:06 +0800 Subject: [PATCH 542/571] core: minor fix for the log wrapper with debug purpose (#30454) After this PR, https://github.com/ethereum/go-ethereum/pull/28187, the way to set the default logger is different. This PR only updates the way to set logger in some test cases' comments that existed in the codebase (since this commit https://github.com/ethereum/go-ethereum/commit/b63e3c37a6). Although I am not sure if it a good way to leave the code in the comment, it truly makes me more efficiently to debug and fix the failing test cases. --- core/blockchain_repair_test.go | 6 +++--- core/blockchain_sethead_test.go | 2 +- core/blockchain_snapshot_test.go | 20 ++++++++++---------- core/blockchain_test.go | 14 +++++++------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 07f154b4fa97..aeeb9095d87d 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1757,8 +1757,8 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) { // It's hard to follow the test case, visualize the input - // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - // fmt.Println(tt.dump(true)) + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) + // fmt.Println(tt.dump(false)) // Create a temporary persistent database datadir := t.TempDir() @@ -1908,7 +1908,7 @@ func TestIssue23496(t *testing.T) { func testIssue23496(t *testing.T, scheme string) { // It's hard to follow the test case, visualize the input - //log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) // Create a temporary persistent database datadir := t.TempDir() diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 5a62d6b25f3f..123c2c9af16e 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1961,7 +1961,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) { // It's hard to follow the test case, visualize the input - // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) // fmt.Println(tt.dump(false)) // Create a temporary persistent database diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 45d33bb0a053..3803c153e700 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -222,8 +222,8 @@ type snapshotTest struct { func (snaptest *snapshotTest) test(t *testing.T) { // It's hard to follow the test case, visualize the input - // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - // fmt.Println(tt.dump()) + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) + // fmt.Println(snaptest.dump()) chain, blocks := snaptest.prepare(t) // Restart the chain normally @@ -245,8 +245,8 @@ type crashSnapshotTest struct { func (snaptest *crashSnapshotTest) test(t *testing.T) { // It's hard to follow the test case, visualize the input - // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - // fmt.Println(tt.dump()) + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) + // fmt.Println(snaptest.dump()) chain, blocks := snaptest.prepare(t) // Pull the plug on the database, simulating a hard crash @@ -297,8 +297,8 @@ type gappedSnapshotTest struct { func (snaptest *gappedSnapshotTest) test(t *testing.T) { // It's hard to follow the test case, visualize the input - // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - // fmt.Println(tt.dump()) + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) + // fmt.Println(snaptest.dump()) chain, blocks := snaptest.prepare(t) // Insert blocks without enabling snapshot if gapping is required. @@ -341,8 +341,8 @@ type setHeadSnapshotTest struct { func (snaptest *setHeadSnapshotTest) test(t *testing.T) { // It's hard to follow the test case, visualize the input - // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - // fmt.Println(tt.dump()) + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) + // fmt.Println(snaptest.dump()) chain, blocks := snaptest.prepare(t) // Rewind the chain if setHead operation is required. @@ -370,8 +370,8 @@ type wipeCrashSnapshotTest struct { func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { // It's hard to follow the test case, visualize the input - // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - // fmt.Println(tt.dump()) + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) + // fmt.Println(snaptest.dump()) chain, blocks := snaptest.prepare(t) // Firstly, stop the chain properly, with all snapshot journal diff --git a/core/blockchain_test.go b/core/blockchain_test.go index d8c436fcd65c..d2bf074c6557 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2126,9 +2126,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // [ Cn, Cn+1, Cc, Sn+3 ... Sm] // ^ ^ ^ pruned func TestPrunedImportSide(t *testing.T) { - //glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))) - //glogger.Verbosity(3) - //log.Root().SetHandler(log.Handler(glogger)) + // glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false)) + // glogger.Verbosity(3) + // log.SetDefault(log.NewLogger(glogger)) testSideImport(t, 3, 3, -1) testSideImport(t, 3, -3, -1) testSideImport(t, 10, 0, -1) @@ -2137,9 +2137,9 @@ func TestPrunedImportSide(t *testing.T) { } func TestPrunedImportSideWithMerging(t *testing.T) { - //glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))) - //glogger.Verbosity(3) - //log.Root().SetHandler(log.Handler(glogger)) + // glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false)) + // glogger.Verbosity(3) + // log.SetDefault(log.NewLogger(glogger)) testSideImport(t, 3, 3, 0) testSideImport(t, 3, -3, 0) testSideImport(t, 10, 0, 0) @@ -3629,7 +3629,7 @@ func TestSetCanonical(t *testing.T) { } func testSetCanonical(t *testing.T, scheme string) { - //log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") From 7513966d6e0620f2ec0ff78a234a839da16ffc2b Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 19 Sep 2024 15:41:10 +0800 Subject: [PATCH 543/571] ethdb/pebble: handle errors (#30367) --- ethdb/pebble/pebble.go | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 8203dd136dea..7a3be797a3b7 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -293,7 +293,9 @@ func (d *Database) Has(key []byte) (bool, error) { } else if err != nil { return false, err } - closer.Close() + if err = closer.Close(); err != nil { + return false, err + } return true, nil } @@ -310,7 +312,9 @@ func (d *Database) Get(key []byte) ([]byte, error) { } ret := make([]byte, len(dat)) copy(ret, dat) - closer.Close() + if err = closer.Close(); err != nil { + return nil, err + } return ret, nil } @@ -519,14 +523,18 @@ type batch struct { // Put inserts the given value into the batch for later committing. func (b *batch) Put(key, value []byte) error { - b.b.Set(key, value, nil) + if err := b.b.Set(key, value, nil); err != nil { + return err + } b.size += len(key) + len(value) return nil } // Delete inserts the key removal into the batch for later committing. func (b *batch) Delete(key []byte) error { - b.b.Delete(key, nil) + if err := b.b.Delete(key, nil); err != nil { + return err + } b.size += len(key) return nil } @@ -558,19 +566,22 @@ func (b *batch) Replay(w ethdb.KeyValueWriter) error { for { kind, k, v, ok, err := reader.Next() if !ok || err != nil { - break + return err } // The (k,v) slices might be overwritten if the batch is reset/reused, // and the receiver should copy them if they are to be retained long-term. if kind == pebble.InternalKeyKindSet { - w.Put(k, v) + if err = w.Put(k, v); err != nil { + return err + } } else if kind == pebble.InternalKeyKindDelete { - w.Delete(k) + if err = w.Delete(k); err != nil { + return err + } } else { return fmt.Errorf("unhandled operation, keytype: %v", kind) } } - return nil } // pebbleIterator is a wrapper of underlying iterator in storage engine. From deb5c087c41e5d7692fac2cff4c5aa547a108bc1 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:23:13 +0200 Subject: [PATCH 544/571] .github: add release maintainers to params/ CODEOWNERS (#30458) --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b50561172fbb..5852865f945e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -20,5 +20,6 @@ les/ @zsfelfoldi @rjl493456442 light/ @zsfelfoldi @rjl493456442 node/ @fjl p2p/ @fjl @zsfelfoldi +params/ @fjl @holiman @karalabe @gballet @rjl493456442 @zsfelfoldi rpc/ @fjl @holiman signer/ @holiman From b018da9d02513ab13de50d63688c465798bd0e14 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 20 Sep 2024 14:06:12 +0200 Subject: [PATCH 545/571] build: fix macos builds by working around travis osx flaw (#30479) This should fix https://github.com/ethereum/go-ethereum/issues/30471. See investigation in https://github.com/ethereum/go-ethereum/pull/30478 for more background. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 913fa54e963c..b7ba4569932f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -85,7 +85,7 @@ jobs: if: type = push os: osx osx_image: xcode14.2 - go: 1.23.x + go: 1.23.1 # See https://github.com/ethereum/go-ethereum/pull/30478 env: - azure-osx git: From 9326a118c7c074a6c719b381033845c47c1168f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 20 Sep 2024 16:43:42 +0300 Subject: [PATCH 546/571] beacon, core, eth, miner: integrate witnesses into production Geth (#30069) This PR integrates witness-enabled block production, witness-creating payload execution and stateless cross-validation into the `engine` API. The purpose of the PR is to enable the following use-cases (for API details, please see next section): - Cross validating locally created blocks: - Call `forkchoiceUpdatedWithWitness` instead of `forkchoiceUpdated` to trigger witness creation too. - Call `getPayload` as before to retrieve the new block and also the above created witness. - Call `executeStatelessPayload` against another client to cross-validate the block. - Cross validating locally processed blocks: - Call `newPayloadWithWitness` instead of `newPayload` to trigger witness creation too. - Call `executeStatelessPayload` against another client to cross-validate the block. - Block production for stateless clients (local or MEV builders): - Call `forkchoiceUpdatedWithWitness` instead of `forkchoiceUpdated` to trigger witness creation too. - Call `getPayload` as before to retrieve the new block and also the above created witness. - Propagate witnesses across the consensus libp2p network for stateless Ethereum. - Stateless validator validation: - Call `executeStatelessPayload` with the propagated witness to statelessly validate the block. *Note, the various `WithWitness` methods could also *just be* an additional boolean flag on the base methods, but this PR wanted to keep the methods separate until a final consensus is reached on how to integrate in production.* --- The following `engine` API types are introduced: ```go // StatelessPayloadStatusV1 is the result of a stateless payload execution. type StatelessPayloadStatusV1 struct { Status string `json:"status"` StateRoot common.Hash `json:"stateRoot"` ReceiptsRoot common.Hash `json:"receiptsRoot"` ValidationError *string `json:"validationError"` } ``` - Add `forkchoiceUpdatedWithWitnessV1,2,3` with same params and returns as `forkchoiceUpdatedV1,2,3`, but triggering a stateless witness building if block production is requested. - Extend `getPayloadV2,3` to return `executionPayloadEnvelope` with an additional `witness` field of type `bytes` iff created via `forkchoiceUpdatedWithWitnessV2,3`. - Add `newPayloadWithWitnessV1,2,3,4` with same params and returns as `newPayloadV1,2,3,4`, but triggering a stateless witness creation during payload execution to allow cross validating it. - Extend `payloadStatusV1` with a `witness` field of type `bytes` if returned by `newPayloadWithWitnessV1,2,3,4`. - Add `executeStatelessPayloadV1,2,3,4` with same base params as `newPayloadV1,2,3,4` and one more additional param (`witness`) of type `bytes`. The method returns `statelessPayloadStatusV1`, which mirrors `payloadStatusV1` but replaces `latestValidHash` with `stateRoot` and `receiptRoot`. --- beacon/engine/gen_epe.go | 6 + beacon/engine/types.go | 41 +++- cmd/geth/main.go | 1 - cmd/utils/flags.go | 9 - core/block_validator.go | 24 -- core/block_validator_test.go | 2 +- core/blockchain.go | 120 ++++++---- core/blockchain_test.go | 2 +- core/stateless.go | 24 +- core/stateless/database.go | 7 + core/stateless/encoding.go | 63 +----- core/stateless/gen_encoding_json.go | 74 ------ core/stateless/witness.go | 81 ++----- core/types.go | 5 - core/vm/interpreter.go | 3 +- eth/backend.go | 1 - eth/catalyst/api.go | 340 ++++++++++++++++++++++++++-- eth/catalyst/api_test.go | 108 ++++++++- eth/catalyst/simulated_beacon.go | 2 +- eth/ethconfig/config.go | 3 - eth/ethconfig/gen_config.go | 6 - miner/miner.go | 6 +- miner/payload_building.go | 67 ++++-- miner/payload_building_test.go | 2 +- miner/worker.go | 23 +- tests/block_test_util.go | 2 +- 26 files changed, 669 insertions(+), 353 deletions(-) delete mode 100644 core/stateless/gen_encoding_json.go diff --git a/beacon/engine/gen_epe.go b/beacon/engine/gen_epe.go index e69f9a5951a2..fa45d94c4c20 100644 --- a/beacon/engine/gen_epe.go +++ b/beacon/engine/gen_epe.go @@ -19,12 +19,14 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) { BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` Override bool `json:"shouldOverrideBuilder"` + Witness *hexutil.Bytes `json:"witness"` } var enc ExecutionPayloadEnvelope enc.ExecutionPayload = e.ExecutionPayload enc.BlockValue = (*hexutil.Big)(e.BlockValue) enc.BlobsBundle = e.BlobsBundle enc.Override = e.Override + enc.Witness = e.Witness return json.Marshal(&enc) } @@ -35,6 +37,7 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error { BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` Override *bool `json:"shouldOverrideBuilder"` + Witness *hexutil.Bytes `json:"witness"` } var dec ExecutionPayloadEnvelope if err := json.Unmarshal(input, &dec); err != nil { @@ -54,5 +57,8 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error { if dec.Override != nil { e.Override = *dec.Override } + if dec.Witness != nil { + e.Witness = dec.Witness + } return nil } diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 906056b0a114..74c56f403de2 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -94,6 +94,14 @@ type executableDataMarshaling struct { ExcessBlobGas *hexutil.Uint64 } +// StatelessPayloadStatusV1 is the result of a stateless payload execution. +type StatelessPayloadStatusV1 struct { + Status string `json:"status"` + StateRoot common.Hash `json:"stateRoot"` + ReceiptsRoot common.Hash `json:"receiptsRoot"` + ValidationError *string `json:"validationError"` +} + //go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go type ExecutionPayloadEnvelope struct { @@ -101,6 +109,7 @@ type ExecutionPayloadEnvelope struct { BlockValue *big.Int `json:"blockValue" gencodec:"required"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` Override bool `json:"shouldOverrideBuilder"` + Witness *hexutil.Bytes `json:"witness"` } type BlobsBundleV1 struct { @@ -115,9 +124,10 @@ type executionPayloadEnvelopeMarshaling struct { } type PayloadStatusV1 struct { - Status string `json:"status"` - LatestValidHash *common.Hash `json:"latestValidHash"` - ValidationError *string `json:"validationError"` + Status string `json:"status"` + Witness *hexutil.Bytes `json:"witness"` + LatestValidHash *common.Hash `json:"latestValidHash"` + ValidationError *string `json:"validationError"` } type TransitionConfigurationV1 struct { @@ -198,6 +208,20 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { // Withdrawals value will propagate through the returned block. Empty // Withdrawals value must be passed via non-nil, length 0 value in data. func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { + block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot) + if err != nil { + return nil, err + } + if block.Hash() != data.BlockHash { + return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash()) + } + return block, nil +} + +// ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used +// for stateless execution, so it skips checking if the executable data hashes to +// the requested hash (stateless has to *compute* the root hash, it's not given). +func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { txs, err := decodeTransactions(data.Transactions) if err != nil { return nil, err @@ -267,13 +291,10 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b ParentBeaconRoot: beaconRoot, RequestsHash: requestsHash, } - block := types.NewBlockWithHeader(header) - block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests}) - block = block.WithWitness(data.ExecutionWitness) - if block.Hash() != data.BlockHash { - return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash()) - } - return block, nil + return types.NewBlockWithHeader(header). + WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests}). + WithWitness(data.ExecutionWitness), + nil } // BlockToExecutableData constructs the ExecutableData structure by filling the diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 9354684b718c..2675a616759c 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -156,7 +156,6 @@ var ( utils.BeaconGenesisRootFlag, utils.BeaconGenesisTimeFlag, utils.BeaconCheckpointFlag, - utils.CollectWitnessFlag, }, utils.NetworkFlags, utils.DatabaseFlags) rpcFlags = []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index f55c3b52d094..ff0b3a403173 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -600,11 +600,6 @@ var ( Usage: "Disables db compaction after import", Category: flags.LoggingCategory, } - CollectWitnessFlag = &cli.BoolFlag{ - Name: "collectwitness", - Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.", - Category: flags.MiscCategory, - } // MISC settings SyncTargetFlag = &cli.StringFlag{ @@ -1767,9 +1762,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // TODO(fjl): force-enable this in --dev mode cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name) } - if ctx.IsSet(CollectWitnessFlag.Name) { - cfg.EnableWitnessCollection = ctx.Bool(CollectWitnessFlag.Name) - } if ctx.IsSet(RPCGlobalGasCapFlag.Name) { cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name) @@ -2194,7 +2186,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh } vmcfg := vm.Config{ EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name), - EnableWitnessCollection: ctx.Bool(CollectWitnessFlag.Name), } if ctx.IsSet(VMTraceFlag.Name) { if name := ctx.String(VMTraceFlag.Name); name != "" { diff --git a/core/block_validator.go b/core/block_validator.go index a944db0bf896..4f51f5dc1788 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -20,10 +20,8 @@ import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" @@ -160,28 +158,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD return nil } -// ValidateWitness cross validates a block execution with stateless remote clients. -// -// Normally we'd distribute the block witness to remote cross validators, wait -// for them to respond and then merge the results. For now, however, it's only -// Geth, so do an internal stateless run. -func (v *BlockValidator) ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error { - // Run the cross client stateless execution - // TODO(karalabe): Self-stateless for now, swap with other clients - crossReceiptRoot, crossStateRoot, err := ExecuteStateless(v.config, witness) - if err != nil { - return fmt.Errorf("stateless execution failed: %v", err) - } - // Stateless cross execution suceeeded, validate the withheld computed fields - if crossReceiptRoot != receiptRoot { - return fmt.Errorf("cross validator receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, receiptRoot) - } - if crossStateRoot != stateRoot { - return fmt.Errorf("cross validator state root mismatch (cross: %x local: %x)", crossStateRoot, stateRoot) - } - return nil -} - // CalcGasLimit computes the gas limit of the next block after parent. It aims // to keep the baseline gas close to the provided target, and increase it towards // the target if the baseline gas is lower. diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 16824467c16a..80e682066163 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -201,7 +201,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { t.Fatalf("post-block %d: unexpected result returned: %v", i, result) case <-time.After(25 * time.Millisecond): } - chain.InsertBlockWithoutSetHead(postBlocks[i]) + chain.InsertBlockWithoutSetHead(postBlocks[i], false) } // Verify the blocks with pre-merge blocks and post-merge blocks diff --git a/core/blockchain.go b/core/blockchain.go index 5d1cf533fc13..f7c921fe64fe 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -78,10 +78,11 @@ var ( snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil) triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil) - blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil) - blockValidationTimer = metrics.NewRegisteredResettingTimer("chain/validation", nil) - blockExecutionTimer = metrics.NewRegisteredResettingTimer("chain/execution", nil) - blockWriteTimer = metrics.NewRegisteredResettingTimer("chain/write", nil) + blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil) + blockValidationTimer = metrics.NewRegisteredResettingTimer("chain/validation", nil) + blockCrossValidationTimer = metrics.NewRegisteredResettingTimer("chain/crossvalidation", nil) + blockExecutionTimer = metrics.NewRegisteredResettingTimer("chain/execution", nil) + blockWriteTimer = metrics.NewRegisteredResettingTimer("chain/write", nil) blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil) blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil) @@ -1598,7 +1599,9 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { return 0, errChainStopped } defer bc.chainmu.Unlock() - return bc.insertChain(chain, true) + + _, n, err := bc.insertChain(chain, true, false) // No witness collection for mass inserts (would get super large) + return n, err } // insertChain is the internal implementation of InsertChain, which assumes that @@ -1609,10 +1612,10 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { // racey behaviour. If a sidechain import is in progress, and the historic state // is imported, but then new canon-head is added before the actual sidechain // completes, then the historic state could be pruned again -func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) { +func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness bool) (*stateless.Witness, int, error) { // If the chain is terminating, don't even bother starting up. if bc.insertStopped() { - return 0, nil + return nil, 0, nil } // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain) @@ -1667,7 +1670,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) for block != nil && bc.skipBlock(err, it) { log.Debug("Writing previously known block", "number", block.Number(), "hash", block.Hash()) if err := bc.writeKnownBlock(block); err != nil { - return it.index, err + return nil, it.index, err } lastCanon = block @@ -1681,12 +1684,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if setHead { // First block is pruned, insert as sidechain and reorg only if TD grows enough log.Debug("Pruned ancestor, inserting as sidechain", "number", block.Number(), "hash", block.Hash()) - return bc.insertSideChain(block, it) + return bc.insertSideChain(block, it, makeWitness) } else { // We're post-merge and the parent is pruned, try to recover the parent state log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash()) - _, err := bc.recoverAncestors(block) - return it.index, err + _, err := bc.recoverAncestors(block, makeWitness) + return nil, it.index, err } // Some other error(except ErrKnownBlock) occurred, abort. // ErrKnownBlock is allowed here since some known blocks @@ -1694,7 +1697,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) case err != nil && !errors.Is(err, ErrKnownBlock): stats.ignored += len(it.chain) bc.reportBlock(block, nil, err) - return it.index, err + return nil, it.index, err } // No validation errors for the first block (or chain prefix skipped) var activeState *state.StateDB @@ -1708,6 +1711,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } }() + // Track the singleton witness from this chain insertion (if any) + var witness *stateless.Witness + for ; block != nil && err == nil || errors.Is(err, ErrKnownBlock); block, err = it.next() { // If the chain is terminating, stop processing blocks if bc.insertStopped() { @@ -1744,7 +1750,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) "hash", block.Hash(), "number", block.NumberU64()) } if err := bc.writeKnownBlock(block); err != nil { - return it.index, err + return nil, it.index, err } stats.processed++ if bc.logger != nil && bc.logger.OnSkippedBlock != nil { @@ -1755,13 +1761,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) Safe: bc.CurrentSafeBlock(), }) } - // We can assume that logs are empty here, since the only way for consecutive // Clique blocks to have the same state is if there are no transactions. lastCanon = block continue } - // Retrieve the parent block and it's state to execute on top start := time.Now() parent := it.previous() @@ -1770,7 +1774,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } statedb, err := state.New(parent.Root, bc.statedb) if err != nil { - return it.index, err + return nil, it.index, err } statedb.SetLogger(bc.logger) @@ -1778,11 +1782,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // while processing transactions. Before Byzantium the prefetcher is mostly // useless due to the intermediate root hashing after each transaction. if bc.chainConfig.IsByzantium(block.Number()) { - var witness *stateless.Witness - if bc.vmConfig.EnableWitnessCollection { - witness, err = stateless.NewWitness(bc, block) + // Generate witnesses either if we're self-testing, or if it's the + // only block being inserted. A bit crude, but witnesses are huge, + // so we refuse to make an entire chain of them. + if bc.vmConfig.StatelessSelfValidation || (makeWitness && len(chain) == 1) { + witness, err = stateless.NewWitness(block.Header(), bc) if err != nil { - return it.index, err + return nil, it.index, err } } statedb.StartPrefetcher("chain", witness) @@ -1814,7 +1820,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) res, err := bc.processBlock(block, statedb, start, setHead) followupInterrupt.Store(true) if err != nil { - return it.index, err + return nil, it.index, err } // Report the import stats before returning the various results stats.processed++ @@ -1831,7 +1837,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // After merge we expect few side chains. Simply count // all blocks the CL gives us for GC processing time bc.gcproc += res.procTime - return it.index, nil // Direct block insertion of a single block + return witness, it.index, nil // Direct block insertion of a single block } switch res.status { case CanonStatTy: @@ -1861,7 +1867,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } } stats.ignored += it.remaining() - return it.index, err + return witness, it.index, err } // blockProcessingResult is a summary of block processing @@ -1906,13 +1912,36 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s } vtime := time.Since(vstart) - if witness := statedb.Witness(); witness != nil { - if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil { - bc.reportBlock(block, res, err) - return nil, fmt.Errorf("cross verification failed: %v", err) + // If witnesses was generated and stateless self-validation requested, do + // that now. Self validation should *never* run in production, it's more of + // a tight integration to enable running *all* consensus tests through the + // witness builder/runner, which would otherwise be impossible due to the + // various invalid chain states/behaviors being contained in those tests. + xvstart := time.Now() + if witness := statedb.Witness(); witness != nil && bc.vmConfig.StatelessSelfValidation { + log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash()) + + // Remove critical computed fields from the block to force true recalculation + context := block.Header() + context.Root = common.Hash{} + context.ReceiptHash = common.Hash{} + + task := types.NewBlockWithHeader(context).WithBody(*block.Body()) + + // Run the stateless self-cross-validation + crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, task, witness) + if err != nil { + return nil, fmt.Errorf("stateless self-validation failed: %v", err) + } + if crossStateRoot != block.Root() { + return nil, fmt.Errorf("stateless self-validation root mismatch (cross: %x local: %x)", crossStateRoot, block.Root()) + } + if crossReceiptRoot != block.ReceiptHash() { + return nil, fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, block.ReceiptHash()) } } - proctime := time.Since(start) // processing + validation + xvtime := time.Since(xvstart) + proctime := time.Since(start) // processing + validation + cross validation // Update the metrics touched during block processing and validation accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) @@ -1930,6 +1959,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update blockExecutionTimer.Update(ptime - (statedb.AccountReads + statedb.StorageReads)) // The time spent on EVM processing blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation + blockCrossValidationTimer.Update(xvtime) // The time spent on stateless cross validation // Write the block to the chain and get the status. var ( @@ -1964,7 +1994,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s // The method writes all (header-and-body-valid) blocks to disk, then tries to // switch over to the new chain if the TD exceeded the current chain. // insertSideChain is only used pre-merge. -func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, error) { +func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, makeWitness bool) (*stateless.Witness, int, error) { var ( externTd *big.Int current = bc.CurrentBlock() @@ -2000,7 +2030,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i // If someone legitimately side-mines blocks, they would still be imported as usual. However, // we cannot risk writing unverified blocks to disk when they obviously target the pruning // mechanism. - return it.index, errors.New("sidechain ghost-state attack") + return nil, it.index, errors.New("sidechain ghost-state attack") } } if externTd == nil { @@ -2011,7 +2041,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i if !bc.HasBlock(block.Hash(), block.NumberU64()) { start := time.Now() if err := bc.writeBlockWithoutState(block, externTd); err != nil { - return it.index, err + return nil, it.index, err } log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(), "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), @@ -2028,7 +2058,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i for parent != nil && !bc.HasState(parent.Root) { if bc.stateRecoverable(parent.Root) { if err := bc.triedb.Recover(parent.Root); err != nil { - return 0, err + return nil, 0, err } break } @@ -2038,7 +2068,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i parent = bc.GetHeader(parent.ParentHash, parent.Number.Uint64()-1) } if parent == nil { - return it.index, errors.New("missing parent") + return nil, it.index, errors.New("missing parent") } // Import all the pruned blocks to make the state available var ( @@ -2057,30 +2087,30 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i // memory here. if len(blocks) >= 2048 || memory > 64*1024*1024 { log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64()) - if _, err := bc.insertChain(blocks, true); err != nil { - return 0, err + if _, _, err := bc.insertChain(blocks, true, false); err != nil { + return nil, 0, err } blocks, memory = blocks[:0], 0 // If the chain is terminating, stop processing blocks if bc.insertStopped() { log.Debug("Abort during blocks processing") - return 0, nil + return nil, 0, nil } } } if len(blocks) > 0 { log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64()) - return bc.insertChain(blocks, true) + return bc.insertChain(blocks, true, makeWitness) } - return 0, nil + return nil, 0, nil } // recoverAncestors finds the closest ancestor with available state and re-execute // all the ancestor blocks since that. // recoverAncestors is only used post-merge. // We return the hash of the latest block that we could correctly validate. -func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) { +func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (common.Hash, error) { // Gather all the sidechain hashes (full blocks may be memory heavy) var ( hashes []common.Hash @@ -2120,7 +2150,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) } else { b = bc.GetBlock(hashes[i], numbers[i]) } - if _, err := bc.insertChain(types.Blocks{b}, false); err != nil { + if _, _, err := bc.insertChain(types.Blocks{b}, false, makeWitness && i == 0); err != nil { return b.ParentHash(), err } } @@ -2336,14 +2366,14 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { // The key difference between the InsertChain is it won't do the canonical chain // updating. It relies on the additional SetCanonical call to finalize the entire // procedure. -func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block) error { +func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block, makeWitness bool) (*stateless.Witness, error) { if !bc.chainmu.TryLock() { - return errChainStopped + return nil, errChainStopped } defer bc.chainmu.Unlock() - _, err := bc.insertChain(types.Blocks{block}, false) - return err + witness, _, err := bc.insertChain(types.Blocks{block}, false, makeWitness) + return witness, err } // SetCanonical rewinds the chain to set the new head block as the specified @@ -2357,7 +2387,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) { // Re-execute the reorged chain in case the head state is missing. if !bc.HasState(head.Root()) { - if latestValidHash, err := bc.recoverAncestors(head); err != nil { + if latestValidHash, err := bc.recoverAncestors(head, false); err != nil { return latestValidHash, err } log.Info("Recovered head state", "number", head.Number(), "hash", head.Hash()) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index d2bf074c6557..d157a7bc3c93 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -3674,7 +3674,7 @@ func testSetCanonical(t *testing.T, scheme string) { gen.AddTx(tx) }) for _, block := range side { - err := chain.InsertBlockWithoutSetHead(block) + _, err := chain.InsertBlockWithoutSetHead(block, false) if err != nil { t.Fatalf("Failed to insert into chain: %v", err) } diff --git a/core/stateless.go b/core/stateless.go index f323cc2e8eb6..5b37d5020ec3 100644 --- a/core/stateless.go +++ b/core/stateless.go @@ -25,21 +25,30 @@ import ( "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/triedb" ) // ExecuteStateless runs a stateless execution based on a witness, verifies -// everything it can locally and returns the two computed fields that need the -// other side to explicitly check. +// everything it can locally and returns the state root and receipt root, that +// need the other side to explicitly check. // // This method is a bit of a sore thumb here, but: // - It cannot be placed in core/stateless, because state.New prodces a circular dep // - It cannot be placed outside of core, because it needs to construct a dud headerchain // // TODO(karalabe): Would be nice to resolve both issues above somehow and move it. -func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (common.Hash, common.Hash, error) { +func ExecuteStateless(config *params.ChainConfig, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, error) { + // Sanity check if the supplied block accidentally contains a set root or + // receipt hash. If so, be very loud, but still continue. + if block.Root() != (common.Hash{}) { + log.Error("stateless runner received state root it's expected to calculate (faulty consensus client)", "block", block.Number()) + } + if block.ReceiptHash() != (common.Hash{}) { + log.Error("stateless runner received receipt root it's expected to calculate (faulty consensus client)", "block", block.Number()) + } // Create and populate the state database to serve as the stateless backend memdb := witness.MakeHashDB() db, err := state.New(witness.Root(), state.NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), nil)) @@ -57,16 +66,15 @@ func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (c validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block // Run the stateless blocks processing and self-validate certain fields - res, err := processor.Process(witness.Block, db, vm.Config{}) + res, err := processor.Process(block, db, vm.Config{}) if err != nil { return common.Hash{}, common.Hash{}, err } - if err = validator.ValidateState(witness.Block, db, res, true); err != nil { + if err = validator.ValidateState(block, db, res, true); err != nil { return common.Hash{}, common.Hash{}, err } // Almost everything validated, but receipt and state root needs to be returned receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil)) - stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number())) - - return receiptRoot, stateRoot, nil + stateRoot := db.IntermediateRoot(config.IsEIP158(block.Number())) + return stateRoot, receiptRoot, nil } diff --git a/core/stateless/database.go b/core/stateless/database.go index 135da621934c..f54c123ddaa1 100644 --- a/core/stateless/database.go +++ b/core/stateless/database.go @@ -26,6 +26,13 @@ import ( // MakeHashDB imports tries, codes and block hashes from a witness into a new // hash-based memory db. We could eventually rewrite this into a pathdb, but // simple is better for now. +// +// Note, this hashdb approach is quite strictly self-validating: +// - Headers are persisted keyed by hash, so blockhash will error on junk +// - Codes are persisted keyed by hash, so bytecode lookup will error on junk +// - Trie nodes are persisted keyed by hash, so trie expansion will error on junk +// +// Acceleration structures built would need to explicitly validate the witness. func (w *Witness) MakeHashDB() ethdb.Database { var ( memdb = rawdb.NewMemoryDatabase() diff --git a/core/stateless/encoding.go b/core/stateless/encoding.go index 2b7245d377e3..5f4cb0ea3c0b 100644 --- a/core/stateless/encoding.go +++ b/core/stateless/encoding.go @@ -17,42 +17,31 @@ package stateless import ( - "bytes" - "errors" - "fmt" "io" - "slices" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) -//go:generate go run github.com/fjl/gencodec -type extWitness -field-override extWitnessMarshalling -out gen_encoding_json.go - // toExtWitness converts our internal witness representation to the consensus one. func (w *Witness) toExtWitness() *extWitness { ext := &extWitness{ - Block: w.Block, Headers: w.Headers, } ext.Codes = make([][]byte, 0, len(w.Codes)) for code := range w.Codes { ext.Codes = append(ext.Codes, []byte(code)) } - slices.SortFunc(ext.Codes, bytes.Compare) - ext.State = make([][]byte, 0, len(w.State)) for node := range w.State { ext.State = append(ext.State, []byte(node)) } - slices.SortFunc(ext.State, bytes.Compare) return ext } // fromExtWitness converts the consensus witness format into our internal one. func (w *Witness) fromExtWitness(ext *extWitness) error { - w.Block, w.Headers = ext.Block, ext.Headers + w.Headers = ext.Headers w.Codes = make(map[string]struct{}, len(ext.Codes)) for _, code := range ext.Codes { @@ -62,12 +51,7 @@ func (w *Witness) fromExtWitness(ext *extWitness) error { for _, node := range ext.State { w.State[string(node)] = struct{}{} } - return w.sanitize() -} - -// MarshalJSON marshals a witness as JSON. -func (w *Witness) MarshalJSON() ([]byte, error) { - return w.toExtWitness().MarshalJSON() + return nil } // EncodeRLP serializes a witness as RLP. @@ -75,15 +59,6 @@ func (w *Witness) EncodeRLP(wr io.Writer) error { return rlp.Encode(wr, w.toExtWitness()) } -// UnmarshalJSON unmarshals from JSON. -func (w *Witness) UnmarshalJSON(input []byte) error { - var ext extWitness - if err := ext.UnmarshalJSON(input); err != nil { - return err - } - return w.fromExtWitness(&ext) -} - // DecodeRLP decodes a witness from RLP. func (w *Witness) DecodeRLP(s *rlp.Stream) error { var ext extWitness @@ -93,37 +68,9 @@ func (w *Witness) DecodeRLP(s *rlp.Stream) error { return w.fromExtWitness(&ext) } -// sanitize checks for some mandatory fields in the witness after decoding so -// the rest of the code can assume invariants and doesn't have to deal with -// corrupted data. -func (w *Witness) sanitize() error { - // Verify that the "parent" header (i.e. index 0) is available, and is the - // true parent of the block-to-be executed, since we use that to link the - // current block to the pre-state. - if len(w.Headers) == 0 { - return errors.New("parent header (for pre-root hash) missing") - } - for i, header := range w.Headers { - if header == nil { - return fmt.Errorf("witness header nil at position %d", i) - } - } - if w.Headers[0].Hash() != w.Block.ParentHash() { - return fmt.Errorf("parent hash different: witness %v, block parent %v", w.Headers[0].Hash(), w.Block.ParentHash()) - } - return nil -} - // extWitness is a witness RLP encoding for transferring across clients. type extWitness struct { - Block *types.Block `json:"block" gencodec:"required"` - Headers []*types.Header `json:"headers" gencodec:"required"` - Codes [][]byte `json:"codes"` - State [][]byte `json:"state"` -} - -// extWitnessMarshalling defines the hex marshalling types for a witness. -type extWitnessMarshalling struct { - Codes []hexutil.Bytes - State []hexutil.Bytes + Headers []*types.Header + Codes [][]byte + State [][]byte } diff --git a/core/stateless/gen_encoding_json.go b/core/stateless/gen_encoding_json.go deleted file mode 100644 index 1d0497976e34..000000000000 --- a/core/stateless/gen_encoding_json.go +++ /dev/null @@ -1,74 +0,0 @@ -// Code generated by github.com/fjl/gencodec. DO NOT EDIT. - -package stateless - -import ( - "encoding/json" - "errors" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" -) - -var _ = (*extWitnessMarshalling)(nil) - -// MarshalJSON marshals as JSON. -func (e extWitness) MarshalJSON() ([]byte, error) { - type extWitness struct { - Block *types.Block `json:"block" gencodec:"required"` - Headers []*types.Header `json:"headers" gencodec:"required"` - Codes []hexutil.Bytes `json:"codes"` - State []hexutil.Bytes `json:"state"` - } - var enc extWitness - enc.Block = e.Block - enc.Headers = e.Headers - if e.Codes != nil { - enc.Codes = make([]hexutil.Bytes, len(e.Codes)) - for k, v := range e.Codes { - enc.Codes[k] = v - } - } - if e.State != nil { - enc.State = make([]hexutil.Bytes, len(e.State)) - for k, v := range e.State { - enc.State[k] = v - } - } - return json.Marshal(&enc) -} - -// UnmarshalJSON unmarshals from JSON. -func (e *extWitness) UnmarshalJSON(input []byte) error { - type extWitness struct { - Block *types.Block `json:"block" gencodec:"required"` - Headers []*types.Header `json:"headers" gencodec:"required"` - Codes []hexutil.Bytes `json:"codes"` - State []hexutil.Bytes `json:"state"` - } - var dec extWitness - if err := json.Unmarshal(input, &dec); err != nil { - return err - } - if dec.Block == nil { - return errors.New("missing required field 'block' for extWitness") - } - e.Block = dec.Block - if dec.Headers == nil { - return errors.New("missing required field 'headers' for extWitness") - } - e.Headers = dec.Headers - if dec.Codes != nil { - e.Codes = make([][]byte, len(dec.Codes)) - for k, v := range dec.Codes { - e.Codes[k] = v - } - } - if dec.State != nil { - e.State = make([][]byte, len(dec.State)) - for k, v := range dec.State { - e.State[k] = v - } - } - return nil -} diff --git a/core/stateless/witness.go b/core/stateless/witness.go index 0f2d6cfe079c..aecfad1d52fd 100644 --- a/core/stateless/witness.go +++ b/core/stateless/witness.go @@ -17,16 +17,13 @@ package stateless import ( - "bytes" "errors" - "fmt" "maps" "slices" "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rlp" ) // HeaderReader is an interface to pull in headers in place of block hashes for @@ -36,10 +33,11 @@ type HeaderReader interface { GetHeader(hash common.Hash, number uint64) *types.Header } -// Witness encompasses a block, state and any other chain data required to apply -// a set of transactions and derive a post state/receipt root. +// Witness encompasses the state required to apply a set of transactions and +// derive a post state/receipt root. type Witness struct { - Block *types.Block // Current block with rootHash and receiptHash zeroed out + context *types.Header // Header to which this witness belongs to, with rootHash and receiptHash zeroed out + Headers []*types.Header // Past headers in reverse order (0=parent, 1=parent's-parent, etc). First *must* be set. Codes map[string]struct{} // Set of bytecodes ran or accessed State map[string]struct{} // Set of MPT state trie nodes (account and storage together) @@ -49,24 +47,23 @@ type Witness struct { } // NewWitness creates an empty witness ready for population. -func NewWitness(chain HeaderReader, block *types.Block) (*Witness, error) { - // Zero out the result fields to avoid accidentally sending them to the verifier - header := block.Header() - header.Root = common.Hash{} - header.ReceiptHash = common.Hash{} - - // Retrieve the parent header, which will *always* be included to act as a - // trustless pre-root hash container - parent := chain.GetHeader(block.ParentHash(), block.NumberU64()-1) - if parent == nil { - return nil, errors.New("failed to retrieve parent header") +func NewWitness(context *types.Header, chain HeaderReader) (*Witness, error) { + // When building witnesses, retrieve the parent header, which will *always* + // be included to act as a trustless pre-root hash container + var headers []*types.Header + if chain != nil { + parent := chain.GetHeader(context.ParentHash, context.Number.Uint64()-1) + if parent == nil { + return nil, errors.New("failed to retrieve parent header") + } + headers = append(headers, parent) } // Create the wtness with a reconstructed gutted out block return &Witness{ - Block: types.NewBlockWithHeader(header).WithBody(*block.Body()), + context: context, + Headers: headers, Codes: make(map[string]struct{}), State: make(map[string]struct{}), - Headers: []*types.Header{parent}, chain: chain, }, nil } @@ -76,11 +73,8 @@ func NewWitness(chain HeaderReader, block *types.Block) (*Witness, error) { // the chain to cover the block being added. func (w *Witness) AddBlockHash(number uint64) { // Keep pulling in headers until this hash is populated - for int(w.Block.NumberU64()-number) > len(w.Headers) { - tail := w.Block.Header() - if len(w.Headers) > 0 { - tail = w.Headers[len(w.Headers)-1] - } + for int(w.context.Number.Uint64()-number) > len(w.Headers) { + tail := w.Headers[len(w.Headers)-1] w.Headers = append(w.Headers, w.chain.GetHeader(tail.ParentHash, tail.Number.Uint64()-1)) } } @@ -107,45 +101,16 @@ func (w *Witness) AddState(nodes map[string]struct{}) { // Copy deep-copies the witness object. Witness.Block isn't deep-copied as it // is never mutated by Witness func (w *Witness) Copy() *Witness { - return &Witness{ - Block: w.Block, + cpy := &Witness{ Headers: slices.Clone(w.Headers), Codes: maps.Clone(w.Codes), State: maps.Clone(w.State), + chain: w.chain, } -} - -// String prints a human-readable summary containing the total size of the -// witness and the sizes of the underlying components -func (w *Witness) String() string { - blob, _ := rlp.EncodeToBytes(w) - bytesTotal := len(blob) - - blob, _ = rlp.EncodeToBytes(w.Block) - bytesBlock := len(blob) - - bytesHeaders := 0 - for _, header := range w.Headers { - blob, _ = rlp.EncodeToBytes(header) - bytesHeaders += len(blob) - } - bytesCodes := 0 - for code := range w.Codes { - bytesCodes += len(code) + if w.context != nil { + cpy.context = types.CopyHeader(w.context) } - bytesState := 0 - for node := range w.State { - bytesState += len(node) - } - buf := new(bytes.Buffer) - - fmt.Fprintf(buf, "Witness #%d: %v\n", w.Block.Number(), common.StorageSize(bytesTotal)) - fmt.Fprintf(buf, " block (%4d txs): %10v\n", len(w.Block.Transactions()), common.StorageSize(bytesBlock)) - fmt.Fprintf(buf, "%4d headers: %10v\n", len(w.Headers), common.StorageSize(bytesHeaders)) - fmt.Fprintf(buf, "%4d trie nodes: %10v\n", len(w.State), common.StorageSize(bytesState)) - fmt.Fprintf(buf, "%4d codes: %10v\n", len(w.Codes), common.StorageSize(bytesCodes)) - - return buf.String() + return cpy } // Root returns the pre-state root from the first header. diff --git a/core/types.go b/core/types.go index b1808c9ffbfc..65cd4973e488 100644 --- a/core/types.go +++ b/core/types.go @@ -19,9 +19,7 @@ package core import ( "sync/atomic" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" ) @@ -35,9 +33,6 @@ type Validator interface { // ValidateState validates the given statedb and optionally the process result. ValidateState(block *types.Block, state *state.StateDB, res *ProcessResult, stateless bool) error - - // ValidateWitness cross validates a block execution with stateless remote clients. - ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error } // Prefetcher is an interface for pre-caching transaction signatures and state. diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 6e7d28a0ce25..4a39aaad00b4 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -33,7 +33,8 @@ type Config struct { NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled - EnableWitnessCollection bool // true if witness collection is enabled + + StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose) } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/eth/backend.go b/eth/backend.go index f7b67be4dc7c..f10d99c3a70b 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -183,7 +183,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { var ( vmConfig = vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, - EnableWitnessCollection: config.EnableWitnessCollection, } cacheConfig = &core.CacheConfig{ TrieCleanLimit: config.TrieCleanCache, diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 435b1997ff56..991cdf93f328 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -27,7 +27,9 @@ import ( "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" @@ -37,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params/forks" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" ) @@ -82,6 +85,9 @@ var caps = []string{ "engine_forkchoiceUpdatedV1", "engine_forkchoiceUpdatedV2", "engine_forkchoiceUpdatedV3", + "engine_forkchoiceUpdatedWithWitnessV1", + "engine_forkchoiceUpdatedWithWitnessV2", + "engine_forkchoiceUpdatedWithWitnessV3", "engine_exchangeTransitionConfigurationV1", "engine_getPayloadV1", "engine_getPayloadV2", @@ -91,6 +97,14 @@ var caps = []string{ "engine_newPayloadV2", "engine_newPayloadV3", "engine_newPayloadV4", + "engine_newPayloadWithWitnessV1", + "engine_newPayloadWithWitnessV2", + "engine_newPayloadWithWitnessV3", + "engine_newPayloadWithWitnessV4", + "engine_executeStatelessPayloadV1", + "engine_executeStatelessPayloadV2", + "engine_executeStatelessPayloadV3", + "engine_executeStatelessPayloadV4", "engine_getPayloadBodiesByHashV1", "engine_getPayloadBodiesByHashV2", "engine_getPayloadBodiesByRangeV1", @@ -188,7 +202,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("forkChoiceUpdateV1 called post-shanghai")) } } - return api.forkchoiceUpdated(update, payloadAttributes, engine.PayloadV1) + return api.forkchoiceUpdated(update, payloadAttributes, engine.PayloadV1, false) } // ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload @@ -211,7 +225,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV2 must only be called with paris and shanghai payloads")) } } - return api.forkchoiceUpdated(update, params, engine.PayloadV2) + return api.forkchoiceUpdated(update, params, engine.PayloadV2, false) } // ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root @@ -232,10 +246,68 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa // hash, even if params are wrong. To do this we need to split up // forkchoiceUpdate into a function that only updates the head and then a // function that kicks off block construction. - return api.forkchoiceUpdated(update, params, engine.PayloadV3) + return api.forkchoiceUpdated(update, params, engine.PayloadV3, false) } -func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes, payloadVersion engine.PayloadVersion) (engine.ForkChoiceResponse, error) { +// ForkchoiceUpdatedWithWitnessV1 is analogous to ForkchoiceUpdatedV1, only it +// generates an execution witness too if block building was requested. +func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV1(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { + if payloadAttributes != nil { + if payloadAttributes.Withdrawals != nil || payloadAttributes.BeaconRoot != nil { + return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("withdrawals and beacon root not supported in V1")) + } + if api.eth.BlockChain().Config().IsShanghai(api.eth.BlockChain().Config().LondonBlock, payloadAttributes.Timestamp) { + return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("forkChoiceUpdateV1 called post-shanghai")) + } + } + return api.forkchoiceUpdated(update, payloadAttributes, engine.PayloadV1, true) +} + +// ForkchoiceUpdatedWithWitnessV2 is analogous to ForkchoiceUpdatedV2, only it +// generates an execution witness too if block building was requested. +func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV2(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { + if params != nil { + if params.BeaconRoot != nil { + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("unexpected beacon root")) + } + switch api.eth.BlockChain().Config().LatestFork(params.Timestamp) { + case forks.Paris: + if params.Withdrawals != nil { + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai")) + } + case forks.Shanghai: + if params.Withdrawals == nil { + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing withdrawals")) + } + default: + return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV2 must only be called with paris and shanghai payloads")) + } + } + return api.forkchoiceUpdated(update, params, engine.PayloadV2, true) +} + +// ForkchoiceUpdatedWithWitnessV3 is analogous to ForkchoiceUpdatedV3, only it +// generates an execution witness too if block building was requested. +func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { + if params != nil { + if params.Withdrawals == nil { + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing withdrawals")) + } + if params.BeaconRoot == nil { + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root")) + } + if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun && api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { + return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads")) + } + } + // TODO(matt): the spec requires that fcu is applied when called on a valid + // hash, even if params are wrong. To do this we need to split up + // forkchoiceUpdate into a function that only updates the head and then a + // function that kicks off block construction. + return api.forkchoiceUpdated(update, params, engine.PayloadV3, true) +} + +func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes, payloadVersion engine.PayloadVersion, payloadWitness bool) (engine.ForkChoiceResponse, error) { api.forkchoiceLock.Lock() defer api.forkchoiceLock.Unlock() @@ -378,7 +450,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl if api.localBlocks.has(id) { return valid(&id), nil } - payload, err := api.eth.Miner().BuildPayload(args) + payload, err := api.eth.Miner().BuildPayload(args, payloadWitness) if err != nil { log.Error("Failed to build payload", "err", err) return valid(nil), engine.InvalidPayloadAttributes.With(err) @@ -469,7 +541,7 @@ func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.Payl if params.Withdrawals != nil { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("withdrawals not supported in V1")) } - return api.newPayload(params, nil, nil) + return api.newPayload(params, nil, nil, false) } // NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. @@ -492,7 +564,7 @@ func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.Payl if params.BlobGasUsed != nil { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil blobGasUsed pre-cancun")) } - return api.newPayload(params, nil, nil) + return api.newPayload(params, nil, nil, false) } // NewPayloadV3 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. @@ -517,9 +589,10 @@ func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHas if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV3 must only be called for cancun payloads")) } - return api.newPayload(params, versionedHashes, beaconRoot) + return api.newPayload(params, versionedHashes, beaconRoot, false) } +// NewPayloadV4 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. // NewPayloadV4 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) { if params.Withdrawals == nil { @@ -545,10 +618,186 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV4 must only be called for prague payloads")) } - return api.newPayload(params, versionedHashes, beaconRoot) + return api.newPayload(params, versionedHashes, beaconRoot, false) } -func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) { +// NewPayloadWithWitnessV1 is analogous to NewPayloadV1, only it also generates +// and returns a stateless witness after running the payload. +func (api *ConsensusAPI) NewPayloadWithWitnessV1(params engine.ExecutableData) (engine.PayloadStatusV1, error) { + if params.Withdrawals != nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("withdrawals not supported in V1")) + } + return api.newPayload(params, nil, nil, true) +} + +// NewPayloadWithWitnessV2 is analogous to NewPayloadV2, only it also generates +// and returns a stateless witness after running the payload. +func (api *ConsensusAPI) NewPayloadWithWitnessV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) { + if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().Config().LondonBlock, params.Timestamp) { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("can't use newPayloadV2 post-cancun")) + } + if api.eth.BlockChain().Config().LatestFork(params.Timestamp) == forks.Shanghai { + if params.Withdrawals == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) + } + } else { + if params.Withdrawals != nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil withdrawals pre-shanghai")) + } + } + if params.ExcessBlobGas != nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil excessBlobGas pre-cancun")) + } + if params.BlobGasUsed != nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil blobGasUsed pre-cancun")) + } + return api.newPayload(params, nil, nil, true) +} + +// NewPayloadWithWitnessV3 is analogous to NewPayloadV3, only it also generates +// and returns a stateless witness after running the payload. +func (api *ConsensusAPI) NewPayloadWithWitnessV3(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) { + if params.Withdrawals == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) + } + if params.ExcessBlobGas == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil excessBlobGas post-cancun")) + } + if params.BlobGasUsed == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil blobGasUsed post-cancun")) + } + + if versionedHashes == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil versionedHashes post-cancun")) + } + if beaconRoot == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun")) + } + + if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadWithWitnessV3 must only be called for cancun payloads")) + } + return api.newPayload(params, versionedHashes, beaconRoot, true) +} + +// NewPayloadWithWitnessV4 is analogous to NewPayloadV4, only it also generates +// and returns a stateless witness after running the payload. +func (api *ConsensusAPI) NewPayloadWithWitnessV4(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) { + if params.Withdrawals == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) + } + if params.ExcessBlobGas == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil excessBlobGas post-cancun")) + } + if params.BlobGasUsed == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil blobGasUsed post-cancun")) + } + if params.Deposits == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil deposits post-prague")) + } + + if versionedHashes == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil versionedHashes post-cancun")) + } + if beaconRoot == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun")) + } + + if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadWithWitnessV4 must only be called for prague payloads")) + } + return api.newPayload(params, versionedHashes, beaconRoot, true) +} + +// ExecuteStatelessPayloadV1 is analogous to NewPayloadV1, only it operates in +// a stateless mode on top of a provided witness instead of the local database. +func (api *ConsensusAPI) ExecuteStatelessPayloadV1(params engine.ExecutableData, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) { + if params.Withdrawals != nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("withdrawals not supported in V1")) + } + return api.executeStatelessPayload(params, nil, nil, opaqueWitness) +} + +// ExecuteStatelessPayloadV2 is analogous to NewPayloadV2, only it operates in +// a stateless mode on top of a provided witness instead of the local database. +func (api *ConsensusAPI) ExecuteStatelessPayloadV2(params engine.ExecutableData, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) { + if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().Config().LondonBlock, params.Timestamp) { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("can't use newPayloadV2 post-cancun")) + } + if api.eth.BlockChain().Config().LatestFork(params.Timestamp) == forks.Shanghai { + if params.Withdrawals == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) + } + } else { + if params.Withdrawals != nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil withdrawals pre-shanghai")) + } + } + if params.ExcessBlobGas != nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil excessBlobGas pre-cancun")) + } + if params.BlobGasUsed != nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil blobGasUsed pre-cancun")) + } + return api.executeStatelessPayload(params, nil, nil, opaqueWitness) +} + +// ExecuteStatelessPayloadV3 is analogous to NewPayloadV3, only it operates in +// a stateless mode on top of a provided witness instead of the local database. +func (api *ConsensusAPI) ExecuteStatelessPayloadV3(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) { + if params.Withdrawals == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) + } + if params.ExcessBlobGas == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil excessBlobGas post-cancun")) + } + if params.BlobGasUsed == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil blobGasUsed post-cancun")) + } + + if versionedHashes == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil versionedHashes post-cancun")) + } + if beaconRoot == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun")) + } + + if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("executeStatelessPayloadV3 must only be called for cancun payloads")) + } + return api.executeStatelessPayload(params, versionedHashes, beaconRoot, opaqueWitness) +} + +// ExecuteStatelessPayloadV4 is analogous to NewPayloadV4, only it operates in +// a stateless mode on top of a provided witness instead of the local database. +func (api *ConsensusAPI) ExecuteStatelessPayloadV4(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) { + if params.Withdrawals == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) + } + if params.ExcessBlobGas == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil excessBlobGas post-cancun")) + } + if params.BlobGasUsed == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil blobGasUsed post-cancun")) + } + if params.Deposits == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil deposits post-prague")) + } + + if versionedHashes == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil versionedHashes post-cancun")) + } + if beaconRoot == nil { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun")) + } + + if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { + return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("executeStatelessPayloadV4 must only be called for prague payloads")) + } + return api.executeStatelessPayload(params, versionedHashes, beaconRoot, opaqueWitness) +} + +func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, witness bool) (engine.PayloadStatusV1, error) { // The locking here is, strictly, not required. Without these locks, this can happen: // // 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to @@ -656,8 +905,9 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe return engine.PayloadStatusV1{Status: engine.ACCEPTED}, nil } log.Trace("Inserting block without sethead", "hash", block.Hash(), "number", block.Number()) - if err := api.eth.BlockChain().InsertBlockWithoutSetHead(block); err != nil { - log.Warn("NewPayloadV1: inserting block failed", "error", err) + proofs, err := api.eth.BlockChain().InsertBlockWithoutSetHead(block, witness) + if err != nil { + log.Warn("NewPayload: inserting block failed", "error", err) api.invalidLock.Lock() api.invalidBlocksHits[block.Hash()] = 1 @@ -667,7 +917,71 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe return api.invalid(err, parent.Header()), nil } hash := block.Hash() - return engine.PayloadStatusV1{Status: engine.VALID, LatestValidHash: &hash}, nil + + // If witness collection was requested, inject that into the result too + var ow *hexutil.Bytes + if proofs != nil { + ow = new(hexutil.Bytes) + *ow, _ = rlp.EncodeToBytes(proofs) + } + return engine.PayloadStatusV1{Status: engine.VALID, Witness: ow, LatestValidHash: &hash}, nil +} + +func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) { + log.Trace("Engine API request received", "method", "ExecuteStatelessPayload", "number", params.Number, "hash", params.BlockHash) + + block, err := engine.ExecutableDataToBlockNoHash(params, versionedHashes, beaconRoot) + if err != nil { + bgu := "nil" + if params.BlobGasUsed != nil { + bgu = strconv.Itoa(int(*params.BlobGasUsed)) + } + ebg := "nil" + if params.ExcessBlobGas != nil { + ebg = strconv.Itoa(int(*params.ExcessBlobGas)) + } + log.Warn("Invalid ExecuteStatelessPayload params", + "params.Number", params.Number, + "params.ParentHash", params.ParentHash, + "params.BlockHash", params.BlockHash, + "params.StateRoot", params.StateRoot, + "params.FeeRecipient", params.FeeRecipient, + "params.LogsBloom", common.PrettyBytes(params.LogsBloom), + "params.Random", params.Random, + "params.GasLimit", params.GasLimit, + "params.GasUsed", params.GasUsed, + "params.Timestamp", params.Timestamp, + "params.ExtraData", common.PrettyBytes(params.ExtraData), + "params.BaseFeePerGas", params.BaseFeePerGas, + "params.BlobGasUsed", bgu, + "params.ExcessBlobGas", ebg, + "len(params.Transactions)", len(params.Transactions), + "len(params.Withdrawals)", len(params.Withdrawals), + "len(params.Deposits)", len(params.Deposits), + "beaconRoot", beaconRoot, + "error", err) + errorMsg := err.Error() + return engine.StatelessPayloadStatusV1{Status: engine.INVALID, ValidationError: &errorMsg}, nil + } + witness := new(stateless.Witness) + if err := rlp.DecodeBytes(opaqueWitness, witness); err != nil { + log.Warn("Invalid ExecuteStatelessPayload witness", "err", err) + errorMsg := err.Error() + return engine.StatelessPayloadStatusV1{Status: engine.INVALID, ValidationError: &errorMsg}, nil + } + // Stash away the last update to warn the user if the beacon client goes offline + api.lastNewPayloadLock.Lock() + api.lastNewPayloadUpdate = time.Now() + api.lastNewPayloadLock.Unlock() + + log.Trace("Executing block statelessly", "number", block.Number(), "hash", params.BlockHash) + stateRoot, receiptRoot, err := core.ExecuteStateless(api.eth.BlockChain().Config(), block, witness) + if err != nil { + log.Warn("ExecuteStatelessPayload: execution failed", "err", err) + errorMsg := err.Error() + return engine.StatelessPayloadStatusV1{Status: engine.INVALID, ValidationError: &errorMsg}, nil + } + return engine.StatelessPayloadStatusV1{Status: engine.VALID, StateRoot: stateRoot, ReceiptsRoot: receiptRoot}, nil } // delayPayloadImport stashes the given block away for import at a later time, diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 0a58e1eaee02..395deef61549 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -507,7 +507,7 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.He } payload := getNewPayload(t, api, parent, w, h) - execResp, err := api.newPayload(*payload, []common.Hash{}, h) + execResp, err := api.newPayload(*payload, []common.Hash{}, h, false) if err != nil { t.Fatalf("can't execute payload: %v", err) } @@ -684,7 +684,7 @@ func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *engine.Pay Withdrawals: params.Withdrawals, BeaconRoot: params.BeaconRoot, } - payload, err := api.eth.Miner().BuildPayload(args) + payload, err := api.eth.Miner().BuildPayload(args, false) if err != nil { return nil, err } @@ -922,7 +922,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { Random: crypto.Keccak256Hash([]byte{byte(1)}), FeeRecipient: parent.Coinbase(), } - payload, err := api.eth.Miner().BuildPayload(args) + payload, err := api.eth.Miner().BuildPayload(args, false) if err != nil { t.Fatalf("error preparing payload, err=%v", err) } @@ -1704,6 +1704,108 @@ func TestParentBeaconBlockRoot(t *testing.T) { } } +func TestWitnessCreationAndConsumption(t *testing.T) { + log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(colorable.NewColorableStderr(), log.LevelTrace, true))) + + genesis, blocks := generateMergeChain(10, true) + + // Set cancun time to semi-last block + 5 seconds + timestamp := blocks[len(blocks)-2].Time() + 5 + genesis.Config.ShanghaiTime = ×tamp + genesis.Config.CancunTime = ×tamp + + n, ethservice := startEthService(t, genesis, blocks[:9]) + defer n.Close() + + api := NewConsensusAPI(ethservice) + + // Put the 10th block's tx in the pool and produce a new block + txs := blocks[9].Transactions() + + ethservice.TxPool().Add(txs, true, true) + blockParams := engine.PayloadAttributes{ + Timestamp: blocks[8].Time() + 5, + Withdrawals: make([]*types.Withdrawal, 0), + BeaconRoot: &common.Hash{42}, + } + fcState := engine.ForkchoiceStateV1{ + HeadBlockHash: blocks[8].Hash(), + SafeBlockHash: common.Hash{}, + FinalizedBlockHash: common.Hash{}, + } + _, err := api.ForkchoiceUpdatedWithWitnessV3(fcState, &blockParams) + if err != nil { + t.Fatalf("error preparing payload, err=%v", err) + } + // Give the payload some time to be built + time.Sleep(100 * time.Millisecond) + + payloadID := (&miner.BuildPayloadArgs{ + Parent: fcState.HeadBlockHash, + Timestamp: blockParams.Timestamp, + FeeRecipient: blockParams.SuggestedFeeRecipient, + Random: blockParams.Random, + Withdrawals: blockParams.Withdrawals, + BeaconRoot: blockParams.BeaconRoot, + Version: engine.PayloadV3, + }).Id() + envelope, err := api.GetPayloadV3(payloadID) + if err != nil { + t.Fatalf("error getting payload, err=%v", err) + } + if len(envelope.ExecutionPayload.Transactions) != blocks[9].Transactions().Len() { + t.Fatalf("invalid number of transactions %d != %d", len(envelope.ExecutionPayload.Transactions), blocks[9].Transactions().Len()) + } + if envelope.Witness == nil { + t.Fatalf("witness missing from payload") + } + // Test stateless execution of the created witness + wantStateRoot := envelope.ExecutionPayload.StateRoot + wantReceiptRoot := envelope.ExecutionPayload.ReceiptsRoot + + envelope.ExecutionPayload.StateRoot = common.Hash{} + envelope.ExecutionPayload.ReceiptsRoot = common.Hash{} + + res, err := api.ExecuteStatelessPayloadV3(*envelope.ExecutionPayload, []common.Hash{}, &common.Hash{42}, *envelope.Witness) + if err != nil { + t.Fatalf("error executing stateless payload witness: %v", err) + } + if res.StateRoot != wantStateRoot { + t.Fatalf("stateless state root mismatch: have %v, want %v", res.StateRoot, wantStateRoot) + } + if res.ReceiptsRoot != wantReceiptRoot { + t.Fatalf("stateless receipt root mismatch: have %v, want %v", res.ReceiptsRoot, wantReceiptRoot) + } + // Test block insertion with witness creation + envelope.ExecutionPayload.StateRoot = wantStateRoot + envelope.ExecutionPayload.ReceiptsRoot = wantReceiptRoot + + res2, err := api.NewPayloadWithWitnessV3(*envelope.ExecutionPayload, []common.Hash{}, &common.Hash{42}) + if err != nil { + t.Fatalf("error executing stateless payload witness: %v", err) + } + if res2.Witness == nil { + t.Fatalf("witness missing from payload") + } + // Test stateless execution of the created witness + wantStateRoot = envelope.ExecutionPayload.StateRoot + wantReceiptRoot = envelope.ExecutionPayload.ReceiptsRoot + + envelope.ExecutionPayload.StateRoot = common.Hash{} + envelope.ExecutionPayload.ReceiptsRoot = common.Hash{} + + res, err = api.ExecuteStatelessPayloadV3(*envelope.ExecutionPayload, []common.Hash{}, &common.Hash{42}, *res2.Witness) + if err != nil { + t.Fatalf("error executing stateless payload witness: %v", err) + } + if res.StateRoot != wantStateRoot { + t.Fatalf("stateless state root mismatch: have %v, want %v", res.StateRoot, wantStateRoot) + } + if res.ReceiptsRoot != wantReceiptRoot { + t.Fatalf("stateless receipt root mismatch: have %v, want %v", res.ReceiptsRoot, wantReceiptRoot) + } +} + // TestGetClientVersion verifies the expected version info is returned. func TestGetClientVersion(t *testing.T) { genesis, preMergeBlocks := generateMergeChain(10, false) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index cb27810aac8e..dbf561ca4176 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -181,7 +181,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u Withdrawals: withdrawals, Random: random, BeaconRoot: &common.Hash{}, - }, engine.PayloadV3) + }, engine.PayloadV3, false) if err != nil { return err } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 5a955d9bbfc3..c781a639408a 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -134,9 +134,6 @@ type Config struct { // Enables tracking of SHA3 preimages in the VM EnablePreimageRecording bool - // Enables prefetching trie nodes for read operations too - EnableWitnessCollection bool `toml:"-"` - // Enables VM tracing VMTrace string VMTraceJsonConfig string diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 2854c870975c..d96ba0ccb734 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -44,7 +44,6 @@ func (c Config) MarshalTOML() (interface{}, error) { BlobPool blobpool.Config GPO gasprice.Config EnablePreimageRecording bool - EnableWitnessCollection bool `toml:"-"` VMTrace string VMTraceJsonConfig string DocRoot string `toml:"-"` @@ -82,7 +81,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.BlobPool = c.BlobPool enc.GPO = c.GPO enc.EnablePreimageRecording = c.EnablePreimageRecording - enc.EnableWitnessCollection = c.EnableWitnessCollection enc.VMTrace = c.VMTrace enc.VMTraceJsonConfig = c.VMTraceJsonConfig enc.DocRoot = c.DocRoot @@ -124,7 +122,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { BlobPool *blobpool.Config GPO *gasprice.Config EnablePreimageRecording *bool - EnableWitnessCollection *bool `toml:"-"` VMTrace *string VMTraceJsonConfig *string DocRoot *string `toml:"-"` @@ -219,9 +216,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.EnablePreimageRecording != nil { c.EnablePreimageRecording = *dec.EnablePreimageRecording } - if dec.EnableWitnessCollection != nil { - c.EnableWitnessCollection = *dec.EnableWitnessCollection - } if dec.VMTrace != nil { c.VMTrace = *dec.VMTrace } diff --git a/miner/miner.go b/miner/miner.go index ff81d0e8f5c8..9892c08ed6e5 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -126,8 +126,8 @@ func (miner *Miner) SetGasTip(tip *big.Int) error { } // BuildPayload builds the payload according to the provided parameters. -func (miner *Miner) BuildPayload(args *BuildPayloadArgs) (*Payload, error) { - return miner.buildPayload(args) +func (miner *Miner) BuildPayload(args *BuildPayloadArgs, witness bool) (*Payload, error) { + return miner.buildPayload(args, witness) } // getPending retrieves the pending block based on the current head block. @@ -156,7 +156,7 @@ func (miner *Miner) getPending() *newPayloadResult { withdrawals: withdrawal, beaconRoot: nil, noTxs: false, - }) + }, false) // we will never make a witness for a pending block if ret.err != nil { return nil } diff --git a/miner/payload_building.go b/miner/payload_building.go index d027cd1e1f3a..d48ce0faa601 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -25,6 +25,8 @@ import ( "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -67,22 +69,25 @@ func (args *BuildPayloadArgs) Id() engine.PayloadID { // the revenue. Therefore, the empty-block here is always available and full-block // will be set/updated afterwards. type Payload struct { - id engine.PayloadID - empty *types.Block - full *types.Block - sidecars []*types.BlobTxSidecar - fullFees *big.Int - stop chan struct{} - lock sync.Mutex - cond *sync.Cond + id engine.PayloadID + empty *types.Block + emptyWitness *stateless.Witness + full *types.Block + fullWitness *stateless.Witness + sidecars []*types.BlobTxSidecar + fullFees *big.Int + stop chan struct{} + lock sync.Mutex + cond *sync.Cond } // newPayload initializes the payload object. -func newPayload(empty *types.Block, id engine.PayloadID) *Payload { +func newPayload(empty *types.Block, witness *stateless.Witness, id engine.PayloadID) *Payload { payload := &Payload{ - id: id, - empty: empty, - stop: make(chan struct{}), + id: id, + empty: empty, + emptyWitness: witness, + stop: make(chan struct{}), } log.Info("Starting work on payload", "id", payload.id) payload.cond = sync.NewCond(&payload.lock) @@ -106,6 +111,7 @@ func (payload *Payload) update(r *newPayloadResult, elapsed time.Duration) { payload.full = r.block payload.fullFees = r.fees payload.sidecars = r.sidecars + payload.fullWitness = r.witness feesInEther := new(big.Float).Quo(new(big.Float).SetInt(r.fees), big.NewFloat(params.Ether)) log.Info("Updated payload", @@ -135,9 +141,19 @@ func (payload *Payload) Resolve() *engine.ExecutionPayloadEnvelope { close(payload.stop) } if payload.full != nil { - return engine.BlockToExecutableData(payload.full, payload.fullFees, payload.sidecars) + envelope := engine.BlockToExecutableData(payload.full, payload.fullFees, payload.sidecars) + if payload.fullWitness != nil { + envelope.Witness = new(hexutil.Bytes) + *envelope.Witness, _ = rlp.EncodeToBytes(payload.fullWitness) // cannot fail + } + return envelope + } + envelope := engine.BlockToExecutableData(payload.empty, big.NewInt(0), nil) + if payload.emptyWitness != nil { + envelope.Witness = new(hexutil.Bytes) + *envelope.Witness, _ = rlp.EncodeToBytes(payload.emptyWitness) // cannot fail } - return engine.BlockToExecutableData(payload.empty, big.NewInt(0), nil) + return envelope } // ResolveEmpty is basically identical to Resolve, but it expects empty block only. @@ -146,7 +162,12 @@ func (payload *Payload) ResolveEmpty() *engine.ExecutionPayloadEnvelope { payload.lock.Lock() defer payload.lock.Unlock() - return engine.BlockToExecutableData(payload.empty, big.NewInt(0), nil) + envelope := engine.BlockToExecutableData(payload.empty, big.NewInt(0), nil) + if payload.emptyWitness != nil { + envelope.Witness = new(hexutil.Bytes) + *envelope.Witness, _ = rlp.EncodeToBytes(payload.emptyWitness) // cannot fail + } + return envelope } // ResolveFull is basically identical to Resolve, but it expects full block only. @@ -172,11 +193,16 @@ func (payload *Payload) ResolveFull() *engine.ExecutionPayloadEnvelope { default: close(payload.stop) } - return engine.BlockToExecutableData(payload.full, payload.fullFees, payload.sidecars) + envelope := engine.BlockToExecutableData(payload.full, payload.fullFees, payload.sidecars) + if payload.fullWitness != nil { + envelope.Witness = new(hexutil.Bytes) + *envelope.Witness, _ = rlp.EncodeToBytes(payload.fullWitness) // cannot fail + } + return envelope } // buildPayload builds the payload according to the provided parameters. -func (miner *Miner) buildPayload(args *BuildPayloadArgs) (*Payload, error) { +func (miner *Miner) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload, error) { // Build the initial version with no transaction included. It should be fast // enough to run. The empty payload can at least make sure there is something // to deliver for not missing slot. @@ -190,13 +216,12 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs) (*Payload, error) { beaconRoot: args.BeaconRoot, noTxs: true, } - empty := miner.generateWork(emptyParams) + empty := miner.generateWork(emptyParams, witness) if empty.err != nil { return nil, empty.err } - // Construct a payload object for return. - payload := newPayload(empty.block, args.Id()) + payload := newPayload(empty.block, empty.witness, args.Id()) // Spin up a routine for updating the payload in background. This strategy // can maximum the revenue for including transactions with highest fee. @@ -226,7 +251,7 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs) (*Payload, error) { select { case <-timer.C: start := time.Now() - r := miner.generateWork(fullParams) + r := miner.generateWork(fullParams, witness) if r.err == nil { payload.update(r, time.Since(start)) } else { diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index 7a235d88e11e..aad87627e674 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -160,7 +160,7 @@ func TestBuildPayload(t *testing.T) { Random: common.Hash{}, FeeRecipient: recipient, } - payload, err := w.buildPayload(args) + payload, err := w.buildPayload(args, false) if err != nil { t.Fatalf("Failed to build payload %v", err) } diff --git a/miner/worker.go b/miner/worker.go index 1f49118c474e..930c3e8f5b1b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -56,6 +57,8 @@ type environment struct { receipts []*types.Receipt sidecars []*types.BlobTxSidecar blobs int + + witness *stateless.Witness } const ( @@ -73,6 +76,7 @@ type newPayloadResult struct { sidecars []*types.BlobTxSidecar // collected blobs of blob transactions stateDB *state.StateDB // StateDB after executing the transactions receipts []*types.Receipt // Receipts collected during construction + witness *stateless.Witness // Witness is an optional stateless proof } // generateParams wraps various settings for generating sealing task. @@ -88,8 +92,8 @@ type generateParams struct { } // generateWork generates a sealing block based on the given parameters. -func (miner *Miner) generateWork(params *generateParams) *newPayloadResult { - work, err := miner.prepareWork(params) +func (miner *Miner) generateWork(params *generateParams, witness bool) *newPayloadResult { + work, err := miner.prepareWork(params, witness) if err != nil { return &newPayloadResult{err: err} } @@ -129,13 +133,14 @@ func (miner *Miner) generateWork(params *generateParams) *newPayloadResult { sidecars: work.sidecars, stateDB: work.state, receipts: work.receipts, + witness: work.witness, } } // prepareWork constructs the sealing task according to the given parameters, // either based on the last chain head or specified parent. In this function // the pending transactions are not filled yet, only the empty task returned. -func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) { +func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*environment, error) { miner.confMu.RLock() defer miner.confMu.RUnlock() @@ -203,7 +208,7 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase // since clique algorithm can modify the coinbase field in header. - env, err := miner.makeEnv(parent, header, genParams.coinbase) + env, err := miner.makeEnv(parent, header, genParams.coinbase, witness) if err != nil { log.Error("Failed to create sealing context", "err", err) return nil, err @@ -222,18 +227,26 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) } // makeEnv creates a new environment for the sealing block. -func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address) (*environment, error) { +func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address, witness bool) (*environment, error) { // Retrieve the parent state to execute on top. state, err := miner.chain.StateAt(parent.Root) if err != nil { return nil, err } + if witness { + bundle, err := stateless.NewWitness(header, miner.chain) + if err != nil { + return nil, err + } + state.StartPrefetcher("miner", bundle) + } // Note the passed coinbase may be different with header.Coinbase. return &environment{ signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time), state: state, coinbase: coinbase, header: header, + witness: state.Witness(), }, nil } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index b3957601bb83..b0a31a69720b 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -152,7 +152,7 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t } chain, err := core.NewBlockChain(db, cache, gspec, nil, engine, vm.Config{ Tracer: tracer, - EnableWitnessCollection: witness, + StatelessSelfValidation: witness, }, nil) if err != nil { return err From f4c6c033c8246371d2f963b74719096472840e2f Mon Sep 17 00:00:00 2001 From: Martin HS Date: Sun, 22 Sep 2024 10:12:47 +0200 Subject: [PATCH 547/571] travis: work around travis/osx/go1.23 setup bug (#30491) This is a work-around for a strange issue with travis, specifically, `os=osx, go: 1.23.1`. When this is used, the actual go that ends up being used is `go1.19.4 darwin/amd64 `. Using `which go`, it told me that the `go` in the path was a softlink at `/Users/travis/gopath/bin/go1.23.1 `. However, this was not true: using `command -v go`, it told me that the actual `go` that was used is a softlink at `/usr/local/bin/go`. This change rewrites the `/usr/local/bin/go` softlink to point to the binary at `/Users/travis/gopath/bin/go1.23.1`, so we get the right go-version. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b7ba4569932f..3c639d40f971 100644 --- a/.travis.yml +++ b/.travis.yml @@ -91,6 +91,7 @@ jobs: git: submodules: false # avoid cloning ethereum/tests script: + - ln -sf /Users/travis/gopath/bin/go1.23.1 /usr/local/bin/go # Work around travis go-setup bug - go run build/ci.go install -dlgo - go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - go run build/ci.go install -dlgo -arch arm64 From 118c84af5719e5b52c002da1c681dab5df460233 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Mon, 23 Sep 2024 15:17:18 +0800 Subject: [PATCH 548/571] cmd/utils: fix `setEtherbase` (#30488) Make `setEtherbase` fall thorugh and handle `miner.pending.feeRecipient` after showing deprecation-warning for `miner.etherbase`-flag. --- cmd/utils/flags.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ff0b3a403173..da2814855a66 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1307,7 +1307,6 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) { if ctx.IsSet(MinerEtherbaseFlag.Name) { log.Warn("Option --miner.etherbase is deprecated as the etherbase is set by the consensus client post-merge") - return } if !ctx.IsSet(MinerPendingFeeRecipientFlag.Name) { return From 956d32d3e432124043705276e760239159d7e6ef Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Mon, 23 Sep 2024 15:29:07 +0800 Subject: [PATCH 549/571] core/state: fix comment of `mode` (#30490) --- core/state/access_events.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/state/access_events.go b/core/state/access_events.go index 2b270ccafab3..7f67df64eb07 100644 --- a/core/state/access_events.go +++ b/core/state/access_events.go @@ -28,8 +28,8 @@ import ( // mode specifies how a tree location has been accessed // for the byte value: -// * the first bit is set if the branch has been edited -// * the second bit is set if the branch has been read +// * the first bit is set if the branch has been read +// * the second bit is set if the branch has been edited type mode byte const ( From b805772cb41581bdb6536f51c6e9f1998474e324 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 23 Sep 2024 19:27:29 +0800 Subject: [PATCH 550/571] core/state: commit snapshot only if the base layer exists (#30493) This pull request skips the state snapshot update if the base layer is not existent, eliminating the numerous warning logs after an unclean shutdown. Specifically, Geth will rewind its chain head to a historical block after unclean shutdown and state snapshot will be remained as unchanged waiting for recovery. During this period of time, the snapshot is unusable and all state updates should be ignored/skipped for state snapshot update. --- core/state/statedb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 1a12f519a46c..b2b4f8fb97b1 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1265,7 +1265,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU } if !ret.empty() { // If snapshotting is enabled, update the snapshot tree with this new version - if snap := s.db.Snapshot(); snap != nil { + if snap := s.db.Snapshot(); snap != nil && snap.Snapshot(ret.originRoot) != nil { start := time.Now() if err := snap.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil { log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err) From 564b6161637fe7e7c28e7c10a1f1978a22861bd2 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 23 Sep 2024 18:31:56 +0700 Subject: [PATCH 551/571] internal/ethapi/api: for simulated calls, set gaspool to max value if global gascap is 0 (#30474) In #27720, we introduced RPC global gas cap. A value of `0` means an unlimited gas cap. However, this was not the case for simulated calls. This PR fixes the behaviour. --- internal/ethapi/api.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 79f94892c5d5..8c38d7d03761 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1181,7 +1181,13 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S // Make sure the context is cancelled when the call has completed // this makes sure resources are cleaned up. defer cancel() - return applyMessage(ctx, b, args, state, header, timeout, new(core.GasPool).AddGas(globalGasCap), &blockCtx, &vm.Config{NoBaseFee: true}, precompiles, true) + gp := new(core.GasPool) + if globalGasCap == 0 { + gp.AddGas(math.MaxUint64) + } else { + gp.AddGas(globalGasCap) + } + return applyMessage(ctx, b, args, state, header, timeout, gp, &blockCtx, &vm.Config{NoBaseFee: true}, precompiles, true) } func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, timeout time.Duration, gp *core.GasPool, blockContext *vm.BlockContext, vmConfig *vm.Config, precompiles vm.PrecompiledContracts, skipChecks bool) (*core.ExecutionResult, error) { From 2278647ef2692e6e8f90e4dba429fcc002de16f1 Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 24 Sep 2024 15:26:29 +0800 Subject: [PATCH 552/571] core/rawdb: make sure specified state scheme is valid (#30499) This change exits with error if user provided a `--state.scheme` which is neither `hash` nor `path` --- core/rawdb/accessors_trie.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index 0f856d180457..bfe20767d9b9 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -302,6 +302,10 @@ func ParseStateScheme(provided string, disk ethdb.Database) (string, error) { log.Info("State scheme set to already existing", "scheme", stored) return stored, nil // reuse scheme of persistent scheme } + // If state scheme is specified, ensure it's valid. + if provided != HashScheme && provided != PathScheme { + return "", fmt.Errorf("invalid state scheme %s", provided) + } // If state scheme is specified, ensure it's compatible with // persistent state. if stored == "" || provided == stored { From f2e13c7e333fb9c27bcee62fe18177989c365840 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:14:38 +0200 Subject: [PATCH 553/571] internal/ethapi: fix gascap 0 for eth_simulateV1 (#30496) Similar to #30474. --- internal/ethapi/api.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 8c38d7d03761..7981f35ae391 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1289,13 +1289,17 @@ func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrO if state == nil || err != nil { return nil, err } + gasCap := api.b.RPCGasCap() + if gasCap == 0 { + gasCap = math.MaxUint64 + } sim := &simulator{ b: api.b, state: state, base: base, chainConfig: api.b.ChainConfig(), // Each tx and all the series of txes shouldn't consume more gas than cap - gp: new(core.GasPool).AddGas(api.b.RPCGasCap()), + gp: new(core.GasPool).AddGas(gasCap), traceTransfers: opts.TraceTransfers, validate: opts.Validation, fullTx: opts.ReturnFullTransactions, From 55ed8fef0b6f21ed07dfa9f28b00651c61e8015f Mon Sep 17 00:00:00 2001 From: Karol Chojnowski Date: Tue, 24 Sep 2024 13:18:36 +0200 Subject: [PATCH 554/571] core/tracing, core/vm: add ContractCode to the OpContext (#30466) Extends the opcontext interface to include accessor for code being executed in current context. While it is possible to get the code via `statedb.GetCode`, that approach doesn't work for initcode. --- core/tracing/hooks.go | 1 + core/vm/interpreter.go | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 987dfa7a1e03..882eb52837aa 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -34,6 +34,7 @@ type OpContext interface { Address() common.Address CallValue() *uint256.Int CallInput() []byte + ContractCode() []byte } // StateDB gives tracers access to the whole state. diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 4a39aaad00b4..793f398367a7 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -84,6 +84,11 @@ func (ctx *ScopeContext) CallInput() []byte { return ctx.Contract.Input } +// ContractCode returns the code of the contract being executed. +func (ctx *ScopeContext) ContractCode() []byte { + return ctx.Contract.Code +} + // EVMInterpreter represents an EVM interpreter type EVMInterpreter struct { evm *EVM From 80b529ea713d71a27282ae76c2741c8bc5486502 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 24 Sep 2024 18:53:46 +0700 Subject: [PATCH 555/571] core/vm: more benchmarks for bls g1/g2-multiexp precompiles (#30459) This change adds more comprehensive benchmarks with a wider-variety of input sizes for g1 and g2 multi exponentiation. --- .../testdata/precompiles/blsG1MultiExp.json | 268 +++++++++++++++++- .../testdata/precompiles/blsG2MultiExp.json | 254 ++++++++++++++++- 2 files changed, 520 insertions(+), 2 deletions(-) diff --git a/core/vm/testdata/precompiles/blsG1MultiExp.json b/core/vm/testdata/precompiles/blsG1MultiExp.json index 62b91f6f4d78..b708f3c0a6fc 100644 --- a/core/vm/testdata/precompiles/blsG1MultiExp.json +++ b/core/vm/testdata/precompiles/blsG1MultiExp.json @@ -719,5 +719,271 @@ "Name": "matter_g1_multiexp_99", "Gas": 64128, "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000002c7919b322a84cb1e6164043d745a53535edad9ef74533d3155900d4e1d63674b2616d87ca8b3dac6def99441cf196c00000000000000000000000000000000069f2ddefcadf0463b0c40e389837d1079781e04ccd8262623d5df6fb1989973ef6fcb8628b978a088e4f043f54d54391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000012ae6bd01e522bdc8854237da1cff327a09d34683811398bb58a45b5672fc93aea9903e14edaa4a6af3b2b58db051c3000000000000000000000000000000000abb87e947116b3d95dfcde9327f0711ea7dc52cc16c056faf0a325e36955efe4da65c9c8ee9a89b60fac7fafaf49c85", + "Name": "g1msm-1-jwasinger", + "Gas": 14400, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000044c8141f453400b5eaecd905a163ff950775a1a147e68eaccff25dff1d77c0fe9b2abf8311cf04993a615c1209a2a20000000000000000000000000000000000e6728c19f90dcbb3477112effe8bc4d65eff34814c2945170c7843d72702b90a1d97adc9a1a857e95f69a9ce56d2d4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015011119f24cc9325aa4b578d9fa3430ccba523ca0bf0359b221b172afa32a8c80135bce8e04cb774f3cd04999409cff0000000000000000000000000000000012978dda7d55bca7498a4c797bec5d170cbc90f739b1e20985262d422ea154ff35cf5c71bc23791efb5148fbdc47d63f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000179c5193a1eec7522458270c65d4fefe0cf72774498687925a47b21e7060975d02de34832fb709ae8ce98b396a9b8eb00000000000000000000000000000000004d522468140afde2f3d40841e020b0b240a817ff4ee1cfd13c62497f0d9446132dd5c0f36ba226a397721ba4a6e7be6", + "Name": "g1msm-2-jwasinger", + "Gas": 21312, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000002aa3a1c6386bc21eeac062fbe70da8f9079003a574805cf997d0f08332dc3dccc22d1ccfd81d29178b5aa01bd803bb50000000000000000000000000000000011954af068b6e7b16ff453bf139793eb909c438237339eecf79daa48d9f9a84b3732e6ada9e1fe1ef96081f3015a39541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005125a08621bff979dd62adeea6e90adf736f2e70141adbe90c01eeab94e2929cddc80d1ccc3ff186a582d79e33e22c40000000000000000000000000000000007cb53875e527241ce7d2770c949bf188dbbd7babbd14fa26f9b5ac59fe13c6e2a1d667a8315e9612297e764e1428e621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066aeb84c4d25bbaf0e73d578b1d155092d4d02b75602b92ad1a8b2300a1c00389ada213ee3783d8d7c1814ba4349040000000000000000000000000000000000791699767760030bea023b1cc91edc9773ad9921fdc7a1e404504ad29260bfa3376f894fff311fc0acc3a1c2f04ca541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000010870702934c1136e6c4318a49b9b0ee08aaa292732ac268a49defe1ff4b5214104341e13de106456bd2c707f69c0b48000000000000000000000000000000001294117a4266ece3fe724937ecba3d967c90adbfd2f6605ae3b339e0c38c8b58bba5effec32cd9d69b0cecba57d17015", + "Name": "g1msm-3-jwasinger", + "Gas": 27504, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000b37533d0cda25930ea84e22c2230909934eeb4e79b9852dda61c1a0c69f3319e62a5e13c60d18ee669d041d51c22f66000000000000000000000000000000000ee646d305d99b163a19ee00840178ad7ac7e45a5eb835ce05392b91488e67134196fec73928bfdd90870ffd9e94468f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f278dfbf249949bb514f3498727173a6cbc4aa6e11df04ea2f3bada502d42a35791ca308fa1fb5d8083e0cf439ae21000000000000000000000000000000000851116ebe6e0e0fcb7ef115ebe78625e9d3a4e4a12a484edfc4da17ca15e53c4f1b3e72248b335d379d4f3d0186e6551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000040357c69d7eb9f119f5251ae29490b2f01d3c5cb8e00db82b955cd55a498c1c6e380866b7ea02c9511beaf506fdb17000000000000000000000000000000001329d35a79127fc02f35e82388b86a0faffd3edee776406107c9f67554f980fd6710147f824e863da461c1e7033d79171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003fe52e1443ea05bf9476cdd5e80f36740071113800b57cb9214046e2624a7718307e2ff6252a6434e93e5af6b4129900000000000000000000000000000000016709f07278a749668d8f08f29d460a753ec56c2a66825df0760d2ff7a0a4cba14e4354cac8bf0dc967b698bcf49ea9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000ebbd670bc84bffe83659958ca5a3220517b9468cc7de5aca79be564e30f0a4ad3a01e44c79e63d8342dea2b3f1c9be20000000000000000000000000000000012f8dfc5099c08287030bc56d90e114fcfb92df8c88a4827f026560120c257333a7b33f07846d1161032bb8d6f9d6548", + "Name": "g1msm-4-jwasinger", + "Gas": 30768, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000f519184d70784b4c70107842da9a1d76d7b4f3c6cd2155f03e53dd212f2ee04330cb418b0a05378c1b51d45d52be79e00000000000000000000000000000000146f7821be5dda33e7139ec78a9454c534a125c6be4332b1490fc26d0134880fa8dc0ce14476648863ccb49ff3c223001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a35dbd7a31c32387dcc0f38545d6af66aea9f56fe527eacfd5793a0f0134b40ab4788b25ff1284c4791ffe59791dd400000000000000000000000000000000071263be3524fa82a2dc52f8d536e6617dff4677264eddde49d0e828d12d23d196fe36e0f10967e5060d5b3478d32eee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036583b6b6387f9c6d0526bf1073ec996661a730e64203b4aafbfb0342e048fed94137da221fb8d6190ae717310b351a000000000000000000000000000000000ceed361a9188277704b38dc066675db2ad4e85d2a11686d215dd6c579ce3f79397c30814d0ce3fb79f4d535b16c3daf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001426901693fa83ce2c198d983f76d56f9992f640c760bb77755eb61a9212a7588c6ce53d1ed61a8f2c13a29f376189a20000000000000000000000000000000010a0bcc9b806ca9dd97d01c475d00cc8a9d506a630b5dc973cc31de2685fdd4bbb13b89543b4b7ab288a9b24a9faa1661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b486024be34d0438e7de92e8dc8bad0a24c85cfb89bd9f19bc9ac45fbb3c8dea6b8186f5527d38885bb50ee580aa1500000000000000000000000000000000044672326b50c038267ceb004718a6a3b95ccc0963fc858e2cde28e72fba67b4b5b65c9dcc0729bca2835d0859edc47f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000113448507e722b0ef404d34e2f1d8c4060c8fb4fcb83c8abfa7c74155e6f2e0e3f9def3716c0361c74d920a216292f2e000000000000000000000000000000000af9c4da1ba373f9baec6f382a69de22ca92e3244ee14a913dd439b25309852a0e8f3fd7f35252473aa5520af6f4bc7a", + "Name": "g1msm-5-jwasinger", + "Gas": 35640, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000194200dc14a9804a1a5c1753c0841a5a0e3dc16fa991c11943d8d71bcbf04aa26b6ad3947c4f10bdfa4377f06c07335d000000000000000000000000000000000bb95b9656a97f5207aabffbacfffa9c309911822ac3a9468d9525e3896d1570de2d011df4ad894b1192cbbc8d385bb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b4986439468970c29ae3a584d0ed1581436ceb93afb782c30a0f33caccd1343d694347664edce63749435bd13fa48e000000000000000000000000000000000a6ec59c4515d6e90c62df123b5c60e635c1782bf7bf0f55eb041ab40549ae194f9f4cc3da33698c5a7ec9c5f5730bc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aaf32778d314765c5bffdbf6f98c21ded79d1a00cf1253d98c89bf181edaf5932dcb12a976c0fbe0d532c0bc396c202000000000000000000000000000000000f8f7041e2c8bb02ddae783648a3d0dbe878de4aa64cf3f7bd730c74e44ed976e1232dbb8475fa16fe7c4af5b15682ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044a18bcbb3e43bdabc51eec762e63fae7d7f3f5a31263efec1a51f82dd9b9da23b69ac8fbb505402b3970b94238184c000000000000000000000000000000000382bd8abf1ac4d697fee371ba0f775206ad1976054d1b28ec007f70cd0aa57ef6eb1068de195749b7a72e304ad074d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054f97b674dfc0f5660725badc1a269ddcb36f55cc03c4c8b29bd1f780883cbff14b8bfe18ab17746dde676cba1ed0a800000000000000000000000000000000174d7653690b4dc6b1d4b46cb6253472320db0288b95775bc9db08caffc4c9ace957f2c275b1c518e733e926d81b99241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4b24d59b070d2e5983e10b17a3b4f780a19c9df891cb558a1e3b479608ae87b9762351c108b6263b261287c589777400000000000000000000000000000000057af5e5f9bb829c81c9b860f61b6ad4a4980b9271662be215737664b5caa7dabe9525336b82bc7f4aeb24d8e30f755f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000ff76ea5fba3727d3b233bb6a0125eb3ed0ced6ac365775209ec6b3bacd8642987afe18b4eb25ee8d74ba8013b07152a00000000000000000000000000000000159e4abfa29b89b4ab4a6dd26751018c52fd42ff8562500e52f72ee2ec1360763604d1fdea5c81e168234ec90f063214", + "Name": "g1msm-6-jwasinger", + "Gas": 39384, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000009244bb564d4cf8cedab0e183f70d316b674dd86e57073a94fe3b1ac13af3da384bce888f770be42d80b2ae70bf5c5000000000000000000000000000000000007f0fd12e870c65d30e620616828ef081b6afab6d44b111fd90a3229b6578458945e6ba73d0860095a3f69d8aff620981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151c24f97272d9bcdea3c4b817b6b95e2854ecd828f5ffc811ada89412072cf595269e525f41e0d74fda87b207750423000000000000000000000000000000000555a9169c7e3c650546b343abb8d883bc6ff6c61f23ba519f96aefd1f2e5da92d02c7026cda4a61938ca1f610a8d2291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017101412f7727228e6fcc870dc23f45d052fa9e090971b4b5861daf47147ff60506d4535488ef5a39ec80b67d4ce3ab300000000000000000000000000000000190d8b757ffb078d8ff89746715fcae23b50d520c7ccf5225a64cda87fecfb6cbeef015c647d988af11f8843cf36eedd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006b6da29cac72094979726a0804ded3ae24c3db9f8573d7e7b97312dc3346acbc22af61722623da04a59b8aa4379c9b00000000000000000000000000000000162f33dd2cc52527ef11bad3d8ccfe74d562254002134a8c00b7b1a7335b8970e8fd9d2d394de099c82ed2d89c41257b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d3ad6734f481c70b66f457dad66007bac60ad2c0e6e1439a55f413c6dfb8ba79c7b923f5863d3481b6f42659a81155000000000000000000000000000000000252ff4f00e375cc206e0b210b92a5f911336bb09fa628ee23ee336fea20e4ae783b7f37a671119fec0b8459c84e8bff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099c0ce5941241bce6ab831eaf85ce2f37995a1e07c36d1415c7399bde2c7c124e9164326568171525df2a698a500f3e000000000000000000000000000000000d20866e5f4573ceb2986d0f0996237a6c743b4cb822331cea394a06f75e47f37f562bad478e559a9700ac3968a0c4161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f7f0920242ccd38b2c3f489dd45eb8e9d4f20e37b212bc8d8dbe912dbf81d35a8a25d5d4d8a1e84083edf8412105ff0000000000000000000000000000000007b5340e1decdbf119317ee913265a31d861656a167839fde1f674c81c96b0160f2afcdbda43f8546ab0b723f087a3791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000066d2afb5420710cceae2f3e0be2a8bf0a8578dbbe31651949df004128d9c90160c844c8c0e872908449078b97bec633000000000000000000000000000000000aa07ad23d5f73608bbaeb5617d3efac71120608879542e5d76d86e6771bc8aeb2160627ddef8b7665d031bec6b29e09", + "Name": "g1msm-7-jwasinger", + "Gas": 42000, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000002eca26466a23e459022e6137af74828a4a043de76fd42739c291c77658117d4ccea4ed95a0e2d83cf8cbcb855fea1cd000000000000000000000000000000000a4dbb9da003acf2aa0498b88ce7a5dae8f6bcdeaa65e635c951ecb0f3de61ebd7d72317b9852741de03ae709c2be4571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090988fb4f98c8bd6f61551c4a95db33b0c25861a60bc98a7dce6e67f9258ba4086606990779b18db37af56566aee62c000000000000000000000000000000000d5bf1b2efa7711fb7a91dc7ae1941a06b424ed878e2db9726f710c676623f200c688a0160f2b848988cdafd0e26995f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018504266b12b76c706908d9d3fc124e43f0264c165bed121b3fe61a2279d86b7c2e9c2dd549b92979f06bcc41162342200000000000000000000000000000000049c310741619781ac34e1949d360a99430807175b5de87a00f0babc56427ac2f7168b3e69e006993887af60d56a7b7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000162b1a58359f1f12175e02a456a604b68680b97362cf4eff8b3c62e7d6aef60729b5a9cbce9e462623088387c749cdd30000000000000000000000000000000008593e3170dce9d621ee58fe4c598144688b59ef4d5f5c886d0d395995d16c980f826dab9710fa6df84b271c0f099cc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014bcd8d6460badd9c853a99e6892dd12efb7592090ef876761db4ce696008743dc90b14eaa57936d8f4d29951eba4201000000000000000000000000000000000db8d628d6a4dc0d431e26de35179f8800975e1c3c8b633c8255c3a9024a3d25d4c96bcb062d1d56e4ed185d2bf77e7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f89e93e5de6b266657886ac70580d52e3c16dfcf153c89a898e53ac914ff02adfcd3c31aabe90115d09230dfcb3bd3000000000000000000000000000000000a7ef19765b329ab16a780e40b09560af6e47130c9235166694bab7cc772938c7778ed329a2db45b385859308ed1357a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eae4de441b8d7ec46ac27808424284b797f0957d74b129ee36ed68b507cdc3d37065bd36cc7fa2a7522b20b6ffc464b00000000000000000000000000000000069783912b0317702031455240075555ce6fe238df76cf8753cac98c5151e408f38a3f097ae79c43f7955d508e84dc9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7d2823148c233c00121672db578930084bbbf8c33b048f0c9a26167494e698ce7c6c6f0e0aa1c3e4ce53f2df52dd7100000000000000000000000000000000062c22f57f1c4b60d9919ff827df171aaf43dd8aef6195a1ee3f33d3c25e040dbc4ad52c93ddd4b847087d62a209d59f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000004ef10c8626b08ff21c61076b379ca4a4253dff9c1531182008b9e21b90c5be30aaf2d80849643d89cf068f9e79e1a1c000000000000000000000000000000001038dab69904dc709cd72a67542aeccebbb45b1f6dddbf59e5ecca6380bf77cd9fa2731109043748e163cc64f070e7d8", + "Name": "g1msm-8-jwasinger", + "Gas": 43488, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000093f799d21b03bb0396b88f50cc0b1ad84a1b1c6fd6031d84a80f3fdf3a8e72c0ef09499dffb90c681ad769e0d0756bf0000000000000000000000000000000006ee1909818c0b316df9d7a26f65a917ce144e3bb117e7352af708042d692056c2e462deebc5545452c2edf09b5ad9e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b536901fecc0449e4ddad02561de8fdd99b1f83dd74555c4ee03e9c809320b467fd0d3c035f5dc11014475e8fa0a63000000000000000000000000000000000c82e5b5985ade16e31f91180d8863aface2572c580a442055866990e3a7149ea3cb36053b64326928734ea67f5fb71f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6d5956a92d615a4dcd439c1c2ec61157805b30b6f6976b5b6e6b4cdbcba9d109e42eea22e0b3c39bd09e4c0f29e7d60000000000000000000000000000000002906bb6f7b0061b73cad18f81a9c4ec5fabcc283cdb55321d19ccd877873bcbd753c1178023dabc49f30578c76480cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4e6a79ea06e3f2edf0ad18aa44b43e970336ba44cb563c7d10d3a4e32fd6a2353079f57cd702e951c7c339369b375a00000000000000000000000000000000116bfb996e4eaf4776a5609f49f53013b170c90e6544e3c08cb1416774868301e8046ad72087efbfae352a8490c498d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e9357f0b3845eaa905e4f7b4eddd22da9832abde56041d2267271cf9298c9cde217d8d18892856b53d782812a5b48e000000000000000000000000000000000a7381cf76b51a880a95341720109622e289a01e3dd79527f2338b7f94c7802c64fbdcc251fde45a76ff423d0c1342631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009610461d9ab363ed7004b567a28ab93c46faaee8dd648bd833c774ed5537d7aae3fbe9ecc8677afdcf1f898512dfcf30000000000000000000000000000000006f93c06b24123a25d836fef217aab76923f1aa8d0c382c996ef1b9644b295d896525a6279845a0cb65eb1ee506228d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e04a45349aa28f6255864f8bab0885f1d80d7148a979f8501950b04121df1aefcc424a378fa07e6d0c67ad06065df40000000000000000000000000000000017d0468f16ed765b21730dc9ff4fc17b6564cbadf6c1e42d7e3d0f4b1b1d16ad1702464f69275e05ed95697c9621a1b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ac61fd4d99d9091a3333542063f5d21499a6c658dbb08f70dea7d4c3d8876be7804ac44e545ba8b27b6834518f720c000000000000000000000000000000001273a718507114158268dd9c27f951dd49dd5db3ae8ec4e5894c1b6710a53b00ddaed67767266a600ce4347473da311e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034da7f8a1e35fc4e5bb23225f8a7cfff284733bc337f38034f7580dbd46cec87462d12e7465a77e555fa6690a2669d8000000000000000000000000000000000a482a1d6322f5a9c9a7f1ced8115d72bc82f1e15a5557380cf5ed772bbc818c247d73864bc82fa3c4d6dd558ac97f381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000006a4260eb4ac7d806b4388d435bcd66b1184dea4ea6f13d70f2f272e122df4216a1b867520a5f4b2482c09b2bd7b55a10000000000000000000000000000000017727f0f9b7f1f49ebb8c2434ce1c028ead44f88ec2c9e8d7e39f4fe708d5487f2fe7a879bec6fa8a2926b4b8ffdc69d", + "Name": "g1msm-9-jwasinger", + "Gas": 47304, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000016705211c92899c825453eed6736a6e28583f896d9877bc8a876408ebb287b1683af65277bad546f7bd282029e45ef110000000000000000000000000000000010cabcae88300a6593f82511ea4105fe172aeafb34a0b4456714352a0a1fadaaf1310d38a8e29abdeb6aae8cf53a77ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019df8e0065b8726e509ca5a161e89423ee15976ff3b85e2915a1e495ab24a7c773d4da0e33f72c17d9c7b33ab6fb47bf0000000000000000000000000000000011f71bde9c996b4f96da6731e17ba1e226970c4671df38ebf322d151b8e9e1a9bfb2cf45420740f8233519d66b0c4e101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e23874b2f986fc78a10735e22c7816f1ff782cda99abe24dd89470aafbdad09dc539f21de39dfdbcdb1749701d08c6e0000000000000000000000000000000011d2be3742e3b1544a225fd9d2ee057c65079d8fa7b1573e835a17e0e1819d8e791bf790c4df21903d6b9e0092bb0c421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001846b75fc5fc7d5c1963e78544c8b1391c9d72f99c00c60bdbc113734729322da87c4f7adc16b72420be166da80013cc000000000000000000000000000000000a4cb50cd41b11ea6e1b6743114499ad436a0b42f7fa852237df2f0efc0e9fe60534e6cdc5992e29bb92a25d39722d9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000481a03f574bdd12deee516a98e29f6588c85e7e78103a5a3c0992f61fdf1c359e5bfa819feefb3660321952a28c9893000000000000000000000000000000001395bdb7c6513d9cf92034f43d85239f2faf0c0e203b68120256463392a41005b3c95053aa29450c330273b218c2efb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d22b452c7228b55056e1dde2680370bdd0fc832adbf5a84f1b3148e0d7cda9f43dca5e93e23e9f9292a244cad202ee000000000000000000000000000000000303af535724493f64ca6814db8e1b36efad4b80cd2ef9bdd892b0b31674a786402c948ac41f3e05496fe34e2b40edfc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105e0994b703afc218288a7ce70f5b1914cf40e4b5d048772616a31d787041ff82146577b615e396c20944c8c861deb60000000000000000000000000000000011b34269219b44742111dfbbc4dbe1edd369d839b814c3230986056a67b16b8b0866bccd9527ad031f9dfc5583d17c081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000706305ee8421e2b0440bcda446d3ee12d5b2113407039f3bb05a86ad993bf49a1a7304fc05e696dd653aba612417000000000000000000000000000000000000c29b5f70d4d3cadb847e1656217a5d0ae4c7a3a30c2765f420ceeca98aa51dc8c637ffd3ded037cfcca0f8f2853ed8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a170c581f42bc25d5d65c23027257a60a6695e4d651dfe04bd6f2bc9af9f259975e9422be97f34e692aef84d43994880000000000000000000000000000000012ea6518a398181e54ee077a69a0aaffb0f3efb536b9acd6fc84f4e0a08e9526252d0f1a1b58830fa91188a4137891251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013bda8c576c73f6cb981dfe5be4a06fbf5179a5fae4b116acc77d51eb058e1cfc5bd6d0731dde2c08d35924c6392527e000000000000000000000000000000000c39549eda06719155da7e24b8e2017d13646be8798350b533c5d7572f1f789f7f9df6feab49b82863795f0b71ab08681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000028b7cc37f804fb553158bfe8f5fc08935931f7efccea159fcd9c91e443803c7833868bf09a2c94a7a91ba2cf8ea4f3300000000000000000000000000000000123bce0576a8a414657356a85c8245c80f0df437c91430826929da7b86ee404dd52bf7c3f452052d4f5541764b117f15", + "Name": "g1msm-10-jwasinger", + "Gas": 50760, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000009521928d219edc9ad62c5af4e79632dd5f7dd2b2937fec1c3a255a9f57b5ca03a64c34583fb39006a0649f6efc23f6c00000000000000000000000000000000074f86277eddfcdef246f7e09f40314c73c0f986e112cbbb54d28e5059d699ad75523023ab9da78d076a4945f995ef851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f804a2cc57817f1e0c423f2a33db2e40a4104dce5c37ebf4386a92ef9c180796f211e0fdbb40159d0ba089f9b2259e0000000000000000000000000000000013369d33037d63bba45803f952617f2eae07fa4de6752c5ecee6da3ca4bae3ed651f1c5934622b7ad95c4f3aa87eb1b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054d18d6f239a706252d62f06e2258a781fe4d75691e145c86ed333e7471fdb2ea123ca5bd9ce9adebb06d750b612295000000000000000000000000000000000b03b3cc5adafa59ee58745acd8d49a36b3af0fabc1e0014d99871c8fd06247af2077259f05ee400c14d7ed387367d6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ce65ffb1806ad6597457aa70e78b55a8e725f59dd5d72b48c39820c35821142f5fd5dad2ef7e42747cc3595a7e016c0000000000000000000000000000000015942a64bdf367c5ba728b57e0c4086323e3d3ead5431a7ffb1e98939b5017e1d9a2632009656155063e177a5e4f998f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a55a5f3a2177a5eee23598914faf60d4a99c8e0ecd4a2d152a13c9961ed14ec5ab7a200b2b02e319f83e3f8b9753f40000000000000000000000000000000006c8b88804eed3823bc58dc0362f007f91fdcd067473a519c3e17e33ae43b327540022e6b9dceed47af398dac835bf321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d197fceca7aff1f830d14631ecc87b482bcd268840b5cbf99b3f8b94c5a65e4229b47fa3bc66e5565ea82e9df266a49000000000000000000000000000000001696d53e95438eb1fc68131067f15b0e9b771f4d2cbc6731bdeecac36c4ab15764ddc6cf0c2a22c600abd7bcc3561c2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057f04f02a1c1ed32b1d33d6b12c8c762d937803bb752793be5f34fb30267ab1fa73c54ccab2391ab1aae3e3dfdac3370000000000000000000000000000000002701e4c990328f2fdfb76f0660592a5c683401e4c9ab170754372d3c76fede1e4616228e96228964b9e5bd0d4e3c6e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5710e3385836d44b714df25b0dbdcdf198707ad0bb4ce7a85d827aa477d64990b025a4783c3ab42580d993da91f24a000000000000000000000000000000000210bd6f2003df037efd9212039b424f672ffed8dcd6986cf33d2b21b56625b32982cecef98b0802ba004ca1a0226df21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000106a24548ec98c349e31d5acdcb6e1378af44ffd2fed05a4fd41611b7a23c577856675c0a7d9169b4a36fe521eb9fc33000000000000000000000000000000001495cd8531f9c25f2093d14e7df3251b06657afa0a8745f690603d295db20db226bc3e21943d576e0d87c58a5f9846a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136199fdbec21b92f6a23cab8cb33e4e5d2faf21f3cc8a279426ab64e86b34fa7d8b36903d3d48c44804b727fc01d78100000000000000000000000000000000128817bea4280c89efe1d6b3b9bc9ee1901d12c50b7b980c9a46727ec6ddcf09582d29068b46d603a8f143938248fbd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000734f72a55f3ef3f66aeb4fbc045da7d6a80efec8f4256938362180721e9258f0da6c7423a8b6506645aa7bdf0e8e60b00000000000000000000000000000000125e4757ee88db9d2a943e18dbde7933f96dfa76f787c355c58665e7bc6b260abb954b7ead5255dc020e9b699e39bd6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000043bfe6fec13ed186bc5550ecb89f3b2de12f10288a59bf8c0e219b64a4f3da72e6e38dcee195ce0e573af09605b2b280000000000000000000000000000000003383e3d2840e642f81bf1df6915dd3c37b810bceb15543de997e0199a5852fb2b971d11a1f634d9e8ac81e29a00c316", + "Name": "g1msm-11-jwasinger", + "Gas": 53856, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000ce81adf86a553fbd4454974cea6c989c19c447af5f874f469c0d5355039c05a2aa2b298860af6cf23a24d11e7bb613c0000000000000000000000000000000006539b7fa1ff62255ef80c43d26dcb71685e86c8a1d088d53e254866aeba20ca53457be749306b21d56d6086475fb8ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007067fe2a228f0842ecbb7a6388e78405dbd9a1022db031a9a0f58f11928dc34913b7ab13a596adf51c51082e722acdb000000000000000000000000000000000505db0adf1c0e5faec9596d5555f810037b9ad5a2ae1b5668fd72f52228447625a2012e7189522d2e1d7524f73d81521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131c26aae83661017a32e22ce388f12d362609d4ca93c5266486f601bb0ade1c2cc6d798ef4d1645268d538e330e6014000000000000000000000000000000000e8c93332bc07915ad1057913c698b924c3f4237c7532ed9592923235c540381455aff3d28030510f0e114a5b5c8a66e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018157dd5c5df467282b2ea8dbf696fb9637bced360d82c569014ecaf7b350062ac7ceae22d5fe5f25bc6cf2868308ccb000000000000000000000000000000000394672c48d0590cf33287fd741ff1d366cb3461ad9511d33f4fb12b3059fed7f1c2884e7fba65b932081b49b969868e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c0e480bcf4a92835b46822d796af998318ba860d8940c542009e95a4ee1bc92c97150ca8dd4eae157de0b39f4fff8e00000000000000000000000000000000010f3cec81c5979d5c9e622fe42fbfd7ad7f1e7b406e1e49c1b7632a1aaf4b1aa79c02714480806db4f4b6361443f5711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055042f2406721cde522648f08fd1eae26913fa68d0d481eb8f4dca1b0b6fff5b09e3e17cd997c122dc53f09dbf04c6d000000000000000000000000000000000ab21421a4d6895b91a5df00cbfbb6d05f83a8562959861ef4be796c40e2a6be10e6612e34e71800abc9493a2ea341a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff19df95e0f477f6b6c16c7256b9910dfd857892232b8d87e1de9bbd4799b69b2e976078001f7f9f39afda0a747134800000000000000000000000000000000021d1057956fdb34b36dee4f6ec4bd9edcdf3e11d8c50b9ef0daec7b444ba649d7da7d6718f137425f894609487652091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fee161b3767735eb98ca6159fa9b125f17fdb1cc135a9b6c751ef1d22dcea595b47ad76a0d2f8b5b7713874c9ed668a00000000000000000000000000000000196a79fc2c12a25d2702a0efd1804c4e176e046484f34f1064e6e2dcb3ab217895ee0dca2d4c6ffd737fabb9d98f40c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ad6467b9e249333f8cc744c7fe0a87fb6d6d0d9f538d5a6c344a1f07b4c2a0869e968ed041c4df33667081b318c66200000000000000000000000000000000043643b7310c753a2b48da33bccced892c57e1b8146db9ad746621bc014bbf489efe8dcebd247d590846b6791ee02d041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e001b324581503e1b1e18e13300b3c7616ebfbe9723cf71375da30de5e2374140f7aa6dda50e482a05325a278722bea000000000000000000000000000000001520e9dd009ee5086839b348b715f7ac8bb9bd20e24b1b52bf4660561cafec72fab7acc2bc4227e79be4b12cc16901e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018029c4dcddb7546219af291e66698484890a979498a95010cccb0ca818a83476a07b9aa4cfce30484eee2964fecd27700000000000000000000000000000000100a2e6f3666d850c10ba8990509e73983ff6085c2568ef092129566f82ab2771da25d6f491ef9bbc2b878ae61df82b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e80fc17b09a759f6f7447f5102b672717dc20d776caf07062129a000177ad2349e6a6639af4dbf68e5300474cc9ae2b000000000000000000000000000000001838e2d26a29b8d019e7be2703ee8b9baabc76013126223877ab067abbe1508bc0b171d130e2dd36d9d40327e63712a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000253e15fdb9bcbef253872cb21bc3d6dffc855311b6c03caa4de21966c467859a368f349d836ecd8b92f9902529456b90000000000000000000000000000000019bed0c957c26977f215587aeaf1d757b8895d1104202ef8f1d3026386bcab1ce917dd336a37194105406881b306f15f", + "Name": "g1msm-12-jwasinger", + "Gas": 56736, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000008721597853b86a7ba46a406fbdd1c3d1adc764499ba1c1ae652cf45c79ee91c0e95eb081053e866d0d48241f8cf941100000000000000000000000000000000051fb8a8cbb17baae38fa575ce2a46c6597c7fabef6f449bd8c011a4c57483ad0aeea99b61c5ab68226c167223b19ec81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a928423212136a0c5d5b7fbeb33b30d1f1b0dcfd736e93e65b614572ebeb219a9a0328b2a33b61f99d714889b3dc6920000000000000000000000000000000006a889cc23060006da36b44834981542580e9bfdd482ad8f13e4af4c2df01e70a0d39a37119ab510b4aabdd83da591861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044dd71853073f677b058e3f22316b12a375837b04d5b03d2e21a25b9d7c8afde35c35a0b83990262e8b2a66a9c6f0f1000000000000000000000000000000001657a16ebf87ac7df3ee4f8adeddcdd4db1de13c6b69a1f7cc45610ef44a9deab66409af49e616f251740570494c12771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000275ab91e7bf0fae793ea07679c98bc5c15bbfb3cf6e3ff0ced124dbb33a7ce844cfe2d842cb47a5092389c58e1e63800000000000000000000000000000000002543d8d5a5f7add0f96378fb27b3fa1adce7af9517659590b8034a4c930f1b773a01827c1678a9ee89b131ceddc5bed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001021429aa92759eb6a5e783a9eba40302929b289ab019ba22ad9c960caaf68e5edea94ee00064fe1b43d638895172ba30000000000000000000000000000000004cc0c70306fb9a0b9d13adc00ccaf6e1d25600be21422782a4bc3c7344413dea62ce71ce774aa9c34633ed042b151f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000810a1164551bfd6bce1e1cc2e349a3ec0522385e274ee8ec9a1fd3fe12e855c1848db0d01f5481353831767e75893650000000000000000000000000000000003cd90e71e5a8ac70d17eaa4d6d1c453c6afd9b91d4fb37a4c404919555790d35594a278e12e9f128dadecd5af68a0791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177205ed88acbb6c36e82a124bafd3c84bef87f13ec82edc52fde2914e0222e028dbb9b93c426a6a5abfed569c6863c70000000000000000000000000000000005e98c22e98c416920c9f8e87b2ba6312347d9aa9774a0075e926f888351712190fcca351d96f68b9636aab48489013b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002b512074899ca5cb6b9ab5a7d5967b6af8a28108728a8da935ec8be0ab8873b79516243b24c097acc0d06aa17c91740000000000000000000000000000000017b9a0b0b74d7161bed182e70f69a863bd2e048039d2d8c5e2ef6694fe0ccef2d868c914b44af30b2c08e39518695ac51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030f5def86b5299699e89c754eb046147987eb5197c314aaa546fe9142f24af8dbd582ae28716013a9c843fe36e2527100000000000000000000000000000000130c289b7077149950c7d05b8379709f59d3d6adf8649d46b0ead5f723da9a0d99aa0df2aa1157d3fb978d8fb0037d2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ecbd2e088f2b710997439a9bdafced514445b29a638e0e3a2fcc239448111579c8497415d4addf4bea3d369f0bb0a42000000000000000000000000000000001657cfee90ff4e0701a3f58ad4ed35475bf711b8042ce8c8335083998302c3d5a36854049ba55bd991fdcc5c2d7589aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a0f91b5cf9eeb4e090ad121a2a8ee8b8d0680fe5b151a7a1fbe7ab85a19988fc1007b9ca9ca5d972e71f6ed22bba9100000000000000000000000000000000128383913c7b86b788f155f4e36fc8125e4d561e4a0b80869b014c9d3cb100deb37f2978fab2f9cd5406c43cc06aff191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c00d041e667c436cfb822bc8f8a743b05ae2799bfb2d32452ed7b3dd2b45270bab82e7db730f50af6e0373d49a0ca95000000000000000000000000000000000b09b5a34537aa0a47a65d2833413169549e23a888baa11c65a2f15152946ed1d0204fbb5bbe03a8cd7fbb8ba56a90961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006551944aa88d457cdf9ae02f55309be73b67132901705ac168ca993d23aa2c81ba431b68eaae98dfbeb300e819f81a3000000000000000000000000000000000e9286c999dd43f0977aed6f68daa60d91063193836b981cdf183e39bf5b8df18e1bf5263ec9443961b08b3ec6348a001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000f9aa7c02a39a03692c818203ba7190ebeac8daf7036b9955b7e98c45efdbcbab5eeb042cb06890babbf2c8b0bd7fe8a000000000000000000000000000000000215e04a2f337c247da4c8c1f2e0652fe50e15fab12418620e03ba840614ff54457b31632889c1aecdf6eb8deaf3d2b8", + "Name": "g1msm-13-jwasinger", + "Gas": 59124, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000164e9d07cbf6f92dac7bb20a6d60834979dadbec525fc9ae6a0ff8b23ad9d4c22edba6b93aa10bcc2b5a948fdc581d2b00000000000000000000000000000000086ed6d730ea2f98f6e3a2056672acb46c1952eec136d1ccf3d02a13107f71fd9160736267f2b093abb781f9e91d417d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007484ab08ddcc18eb8e7f9b5cb9e48ddfa36f92c69526dd01e85c273dfd0e705cfba697fc5cc93cce3b7701f830a9618000000000000000000000000000000001000cc4aa41ffdeccb61a3558f69a348645b2dbacc259273cd7da2a2f05fe90d46c4a9bddeb734829c850af7f902ad721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017d1f7e469754ed995feb9b181dfcaa60468d8fb3c169130e71d50c730d88b6aef2a77d58b660bf1478e029f82e0bf8000000000000000000000000000000001862a54a708da0ba82a5696bfc69e5dbf7fcc4fae7816e937bdafc70e0dcf1f91657975e8c55310b5ff032193f4429631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2aaae336a281d5f7599926e10aad8451a629af6f2f9a33a01d506b8f0f7b710c34c8922c499f689ec136597be60c360000000000000000000000000000000006262b6cd9b4a241f3cb5ac8494b71da1b6e7af3e2beb5719aa60572586b7df23b57663452aee9393984c84c7c2313321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c4d222b477873d394f07dd8eb04d69bc2ba437b0d0bd53f6ea137f1f826ba89f1e1f2047e60a05f10eeedf0b0c7056f000000000000000000000000000000000dc97f5761d0b791cfaafc45ecb868f49a47f28ecfde4249f60956d5b2ac72a4388804860b7e2d64b4dbe7d33539cdeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001143a6c321182045d735b3eef8799d7a782191b5c4e5ea0a7d1df67e70bd32570889219d776679bfe4aa700f54a993be000000000000000000000000000000000dfa65fdd47a2afa608e080172f1506504056f01b0712551e5bb9b354ccd5f0760796a76270e4331f3074fa1467772891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019af409ca1ce865d84802ce41f280626c43f7d7747ec82ee9eba82f5c9f47d9329cbaed9cd33de32b635d08dc48d9cd3000000000000000000000000000000000646a4f6069d1cd3045aeafd75ca6b0ad637987da41dc53989ff75be2eb55b9959c711dab9a78147115a48ef23ab0b621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010719d70a7e3d0a90420eca3eea4ba27f127b892b62d1002014b65caa879a575cd3e3c714fc47e2bd2f8190327360de8000000000000000000000000000000001685b6fae8cc481a2860f659dff86baa5d557ce7209f231ea7258eb2dbd0ff202ce85a37575821227051ff8f596c273c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017931e6f7f77b3506919f09514dcb1915fef15d8e82a9d4ff1f8a97e34c3fdc0f02857cfdde23acf57c9cebd381d63a70000000000000000000000000000000012350eabea534e4c6bdd0b9630120c07db7d8d610da988363929db7621c3e02b44b9b80120925ca7a3c87f0df06eee461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac190f7cfd3d4ca30f8c86399992305f530e4b111ee1525621d65492d61f25372fafb6a23faf67cdf08f47268a6203f00000000000000000000000000000000155fbcd718e64c1466884700e5bfdef62fd842df87b8a6fea1903808b32c363ba6acd741da366004e513cfe5102444ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152d5134fc78edc9c3eb0b2227b1cb1176296cd8d8d60ff6764279935c7b4dec3d54dafbf37cc2e4f2269015be1326950000000000000000000000000000000015d09a037449ee1b9750eea805ef51ae5d0091f903313867096d3115e1e8986fdd9e24635aa910c36453dccf94ba848e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000951a0bc7bd54c6f32e2238146a32238f017db10bc8da86ce6b817ee2376e6de631ae56488151f34d07b2be60d4494620000000000000000000000000000000017d8b124eccd256dca21877525d3a74da064a9ad7dacd49f7401b03919100b36b9ad1fdb0c3b5cc7f0cdf0a512e2b8951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045f269e23516a34784e41de132269510a328bba7ac6859b14bba872bb4d57761b0c51f4201c1480c5507708a100d3c9000000000000000000000000000000000bb57a30e19ac91c5095e0baad738f626059cc2e44cec6e014e8af95ecde72396ba50d9a98a1733bb0a131a9a6f767421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117e91aefc2094d370363f8c727c2802330f3b193f9d14851f0fe669c12c940e82e2eb9758d78daee09b137a4b447404000000000000000000000000000000001380d34ace5e0bece88e5a4c59c83bfff359fa0f617cf74d53cf9ab89cf6d4d72b65897c076ef7851feff9ea6ef62e3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000001203654f7be8ee24e8577d141c7a4b1a35bcfd5dabc6a23ee0ab5579321c01396cef8e5b72fb6436a204eee63bafb47c00000000000000000000000000000000022fccd7d3ab8ce938d46bc1a1e375fc53f6190037959b05ff5056259177da83924f96e2418945be939e8fbb00000471", + "Name": "g1msm-14-jwasinger", + "Gas": 61152, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000671a645b2e6dc9dc0c106d2ed44c7a9faf9ea2d19ec71019d4d7c59d44e2c3c4be27ad2c274cb9f3ecaf0be5c98963b0000000000000000000000000000000017d8a4d07bdd30f263c9bcc64c9caf6cb59b7b7ac0d73b2c641c3e733e5d3177ae17d9f9c76c7f43d1d41171048ab6411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e58c7f079888684c89f863eee960496e00890b1ee49af1acb8a2b2eaff2fc95e0ae4df9114b10279c3db6fa97ef8a500000000000000000000000000000000023ee51d4a8ce170851f42a098da808fd5e37940866d9268e19d053d111bde34081151b6722089f191b319d7befe2ba71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dcb8e9c73b01a863a4b94781f2cf8176e0cec3ebe8d5ac601dd667cb0170a366da1cd390838dcd22a93e734acfe83110000000000000000000000000000000014b2f45b72ba14ae5763bc9a8d37f8dc4b8a2eee94a0704236b228f7a7b43e8e945d8aef9bcbffeee7c7c9d791d4379f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141a02c583d179d1dcd43ad57f81d6ab7f0e02aaa840db78f9bf8f9bba802df4d32071f80d7d6228acc092f8401ac5e90000000000000000000000000000000017cef78aeb96b0483d1151d7c12760befbb9e89c569c8c95684d7fbe4ef74595976082f755707d45fdda9c8cbefda8751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001057c7bcb62624b8b85887c2cb3aae0f29aba618ef014820c9a6d4d63e6cc68adcd1486d8f0b87aecd0e800da44f61a00000000000000000000000000000000197cf504149808f5c879138cfd09d7278a333d6e1486020571a5811303d775013c5a2bc040ecf407651c711cb6a66a041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005fed276bd78e056c71f5750fd39f5612ed523dd4fd1837e465afe530990a193cdfdd339d886e050cc7d666b854279a40000000000000000000000000000000005697b3f45e54f248ac5a7bd7481c1fdbed3a43ae493e469aca1eb571134ca3c47a21afffba7498a0a94651fdffde4c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e4db89ede0d42db8d7043ae68c5e9a4a82c04152db6a895462facd84f49a43c519a5d826a22b78c3b7e05611fe4fa50000000000000000000000000000000012a819206705721d30412f76c943c655295840178ebbd558243f2bb645891a030db8fd492593b7c1ce223e76215fdea81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001567ba907e1a492d8b02aed55c738c21d24dc27c9de7644226cac21759a6efec47e7e0ee916a6699b25259d4443267f50000000000000000000000000000000003eaf55edb9579b76445b5d799dfa46095aeafbb30deb40bb6f9a0d4265a02c0f85cbe4a91ef023f94303b3e1030af841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029323c61dbe4a0290fc5e5415517bade938418a8710baea714e9726d2ab4b1fdc787a300aa52d79fd09f6acdc6241480000000000000000000000000000000006f9a817ee473e510bfd48f64e0e5af3fe2d1a8f4edb1b2b65c57fd601bc5df06eb6de0e90f968a8e1642d312febe0a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005cff774d5579c4d9aca6063cf700c8d909c398b9a1cab0211762f75d8be55f9d914eb86a68dfe1f4218771e39e2f430000000000000000000000000000000017325b534a0ac721f83f18495256520fbb70d2b14d8127edae5f8a9c27b63c16a2646a4b92f0d5bd18c3158b14e24a0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168a530d4a54626c8d01b8e52a24dc3bf6bdae5fc8c27e766c8ed7282835fd71a9082f8f27ab39ee79f2e1c9640512ed0000000000000000000000000000000014734e4a53f760b96c4dfa7563ecc977961343920fe0b6ffe2daa606928ff1af5ae7bf1c95ebb11c5b5f796390cae1d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c685f25f539c23945d55b025fa49f006fa406a70101712c34333bf1e931e73a2bf54203e2a481a2441106f5f2170a2000000000000000000000000000000000dbbb1697fe5817a5bf89421dd6afb241a696872c9996c92b6372f258ad3b540ad04ecfa5b86189dbaa25355b4278e441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036c4f2b709b765dbb07dfb934e163171632eb1dd02663dd53bd7e203cc4b2368c3a2a53d10bc55597f2f8f1aeb9fcb4000000000000000000000000000000000f6925f067f72c5184281e0b410d38e1b95afea31d28492ff3f22d15ed7f1364793bb0e3570374d0ef411f84feee730b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019584436d1b4154f43b64fa3d870ff809217bf12a3cb9ac364e43e938f2bfb566c056b44df1bdd1c3816ca05bcde3ab6000000000000000000000000000000001741ef532f3869c8fdd586f23e647847bd108e65ba57d35334be69767d436ca75d11f15c1ae1c267ffd6edbc232d33441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0bc8cb8d6834dcb4d69235194033819e2532693324f712f7c1be7b23c16b1e5cf06ac835b88a2895cc96a528769c820000000000000000000000000000000002950db7b91bd972c58dd047ba3621d5c3b83f20e527d45f6c840b4ae9ca226fb00d16d6c4a92c005f9f4d028661062c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000001883c0ea7caeb5a560d871deb72318417e032b6a9c1fc2987e9ae1ef90c8db336ad093e71781352197b806b41229aa500000000000000000000000000000000003854e857850e05ac4083624b4c1de281f2bc308870a2ac28f679840c8c1a5e9ce6bcc8ed4caafd8b40ac3b054f84551", + "Name": "g1msm-15-jwasinger", + "Gas": 62820, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000e36a348a4daa3cf19396d542fdf3f9464daac718f26b31b16752639d4335508551ffc4c36f1e2a2f68157f1fd588af000000000000000000000000000000000171124d2fb1ea2469680158b8a1c830c573e99eb60f83da6b72a9b6bc1aa85c062ba38fa6eff3d5df31d2e64fdb846561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ffa51fe8bce43b78da4a9c27d85061f84baf877567ea9c3cd0790bb129875b435264f8555ec36b15767f88247081db000000000000000000000000000000000f75f654a446c36ecec0c6b516730352ccdd02d82717cd064efa82b58ce45fceaadbbb8fbb2417d162fe7f03239be7a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c5d3d04604deeb36311a8d36b825d7604832cff57ce3855e0ee418256d7bb5aff224a442de20aedd2a306a29ca5f2b0000000000000000000000000000000004217eb8cbac66bf3cb92c125c915caefd81b221930fe022b6c5cf8db4c94cc89decc0826d296ba0b906f22e461da8911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073fa905a9f5b38d5310b606d816c61af5e383c5872ec3e3afc57a628930b4bdef25519fe3463b4756b9d7052fbc93d900000000000000000000000000000000115752501c57c02162fb31325971d58a51c406925e576c6cc641250602bc6a3b54904dd38ba46f533b01f8004a688c7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197df8acc92b88c2395f97fc58a34f5e120fbacea5ae9ffa1bf7dcbb4bf6640d13e92bb99faa3feabb0f5b2610ccbc950000000000000000000000000000000001bc6d7aeab1df541f592cdac4a1366a6e4293ed57922866e1145e7297c5ae28508985127913fa33788913c2e0af77711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff66fb8a9c260d1bbe4ebf4bcd6d079b10d2047ea53ba5d49d119735bfc8e152503ba5106ceb8261f14662874286a640000000000000000000000000000000019a4731c96992eb07d595bb2a3d53e81230a53774c676cdd3e77e14aa2dce9ea9c27652b27c02b8fb3d60ef8c2c95ec01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f54c989e66350dc4d79b113236a95aa1bc8ac3f8b0d8a0a1d4b358fcdc8f329c8e73b9f41cd4bf1ab63ab2268282bb00000000000000000000000000000000137e0dbde2a21520fade2ef6ce8405f814db4167f290e628b5e1539ebcee9a0ee8aa83de3f69a920c5a445eb910d447b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063df22d372a24fb60366f793de7bc45dc92dee2594f3a72b1ca8efb7175aa8f68a2ad7fd1ee5853e041d36308db455100000000000000000000000000000000071cd08097bc2002431090993caab712398db07787b88a506d91388bd2abb8463cad6d362b23113dcbdbd808a99ea5ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b9e2a30b12883961a53e70b61095809201ef2aa42c91072ad8e5581cf79fc54cb11981fb67fd654290a6754c99cbb700000000000000000000000000000000147b30badb1544163f0f81f58f35548b72533affc4390a75c11c3a70be34d7915f43e345d171e2ba4000ffaa8602d8f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e5d437f6b8554a4708fc0488314af417a7e4d8af0701d16c69aed13282a52cdea7afc912279102f5251914d09c4e6600000000000000000000000000000000187fa0d3e59f19077d1bb77865061c2a73ae883677b2dcbb651b6c449b586098b40ed82fad839c5cc7bd5ba73d93ad211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002bbd8101343653c5ce16b4e721d6315cd180428980f421f291c10e1c6a0f6b5d5ad5874648aa8cd26f9205e0f5b564d00000000000000000000000000000000032f89866615cd2a6781afbd16152d4d08621f4733c6ff60c669402b42886fc47b4f61213b85ebbab14f51696a6cc5781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098b50dc9c786d58709c7b7eb63df3d6dbca3a20c30d46a25fdc608dab5fed19a73bf35c7a2c1d39d1592bbee1d593ce0000000000000000000000000000000008b428ddccd19d127e5ae369cc9f674e9cc2d78f08aa99b1889c303e7743261de3077d3e69f10554bb6ab2ada1f76c5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be237a4f8aaac6425cb972a7399bd0c2b0b97e2db05509b12c4ea52de42ac8ceabc28d486eaeff2559c5d62dcd0e5f900000000000000000000000000000000072f19779873895c0cc3d00b1f5d20dd0ccf6645c98a34585fd464537f07c7017c5f54de1fb4587ea0b2e0b7a8f561c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002946ea43fd6327ccf34ebbc0220eefa96478ba18765ee3cabd595c91e63cf27758d0d2f14608ba885b0b422ffb9152d000000000000000000000000000000000db1e990595ae59cf498b8cee67e500439e4bda192754ce46b3b9c515da97fa67472dcdb3fe469231c22aef6931bec971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163ca4a71d926baed3e458f84aa5dd36ce96fbef320dc323aa1ce42f071f2b32376fe2d6c66a86d37ab78a73d788e6030000000000000000000000000000000018d200acf24142deb5675e3eeefcc15040d1359fcb7e8a1515c9dddc661c9d0bf83f0c6a931cd6cc4000c15c752c8f911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069ac270cb712656dc8745e060bbdba2cbff9ada910ee1670f2ab86ef5e9b1896670148f4f81b31b070ebcc14f2c0e800000000000000000000000000000000003d7a630148b77baab8be499d06efe3620627c73f5895aefb408c067c36fe9d21c66f7dfd6d84b654b45b84439c009911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000162b81ce43d3df6ff618be50cbf51d0a07c5ca8b5a9488dbe17d740bc07512604c459da7900447c0738d9dfc3a25083d0000000000000000000000000000000016940839cba1b7e8baf9f14cdeb68a7c57acc4e83f71b7a242e066088ec17b5a7e84cc6d1cd73341b74143f91c06427b", + "Name": "g1msm-16-jwasinger", + "Gas": 64128, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000012da2c3b4ca5ed4470f16c540fab8954dbf1a61a9f1d2cc521230451c46ecb6fef6be9335354887d311b480ce3abafc30000000000000000000000000000000011786226634a6969aa8844862316ed6f3d5036429005b7ea60d07c1ddb6558fe8ad6712a44e546412dec471d192881d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bad347bdc7ca3a9ec974353f5ff697c13235625e88fd5d9c775bd05cd7e7afe2d5cf3e64e16ec05300939751bf3f5f00000000000000000000000000000000131b7858197c400514a81047de69af7698d3023b317e08939cde83e2f745e147cb217df4ac61a2db45bdb787cac6675f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061c98a4d974525ab3dd406668795f695600e558f118793562d99debd1cf2df5a4085ff15aa03713a76670056a7fc799000000000000000000000000000000000851b9b59850e846b2fea9904cdb59111ea865e3ea8327678f99ac6ec87f54d484fd005405ca162c07862db8af84494a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000644bd28775e38b03f0c8b252de14f77b090c828d02024bbbf784785b6f2a26edd74fbec2472fade7c6dfc1bd9c80e440000000000000000000000000000000010cb8910d2ee27f535cb5901a8c85c15980c349ceae8656570b0968e28bb9d75343534c1b71a6587950963e3987144d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d39017f9e5ed6e37beb3b4e30558accf607651e60a4baecc45ab694589c24e03889a454e41c5a76d115bdfe3241e49e0000000000000000000000000000000009bfe371fbcc7e8792f6f335e923913d6acfb734930fb23497372d93ae0834c97b176ba56d348cf9f1eb082925ee81941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cb2901b71c727daa7fd854cde13c7eb3468974eb63aaccdfad0fa904b60bb9d395126067e9178694de5f8305fb51ed00000000000000000000000000000000105335168b9088a45810dfe79a25aa0d293f3c6fc5811650b2fe35612f6e0a76e29e155a8c248c1ce841a605a89d003a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cce99b2e7064aded9b77342cd334889a3804ba6679940ca83495d67ca9e77002f49f03f4a075b6cbd72a0623ab0ef20000000000000000000000000000000006a45377cbe41402894d9f885cb08f3691dcb2dd8abe9c79c777fd2e4d4b2449566c0e6501e455c06b9f1b1e4bc4f7831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ba10bb924fa67bc3c782d4883e098b4b7225d329ebb28714e9efe77ec99c5723c2c165e577ada70d0fdad537488fa40000000000000000000000000000000011e1632431321ffa835583c20a059423b8fd1b96f0eae8da99bf118e36ecf20e5ae12426ada7b76d968db54c7e3223931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009555a4c6be383a1de08af26a799e431665f0c9ba67d95518fdb8ebe6c55a8e8518a357a451231bccc604af27629e98d0000000000000000000000000000000016b26c561d534d73c21d387e871a6cb5054f3eead42d9389117bb2d9a9de78a6a31218e3275d468e2d0964e41fb5f9df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c19f914a91aa669c7877d54333c3bc4038790289f983dd6e6f37a03da63b10a68d67e268edbb9ed7ad20ec1053eb55a00000000000000000000000000000000099bfc7a129366439a71f9f715956abb1ccdfa15931cc5edfe5b75e7d94512ce36890091b7c356b54a23dbee98d1df441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d38bfe2a2d5c692658f4f39d06bed30296b245072f5880439244b378cce4e48eada84892cdf8928f5f02abcb7a1031000000000000000000000000000000000c5d773c622e158a7597c7214e3e7ba0206a66223931d173591e06a7970cd5e173ca7252de2a43a5dccb1674176ef03f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a6805dc3edc293e22e9d24bbad770d04b97a0db947897e455fa9c80ccfd67f0f973d546493b36f7295b3d8d5c01f6f000000000000000000000000000000000f3e09dcf7b487b000682ccb0b71c9f98bd133fd682fe7a1cb2f1d83ef0ffc2699987a766e23c5cb6a2080e8540266691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d6c771415df4333b7506f4bb7415f790d066cbfb1ae4907fb7a955447bc1b894274d234747718414da878a6e1e68440000000000000000000000000000000018e5fd07dfb41922f45293f02e247a065ca68b45b20527ee46f67bc6223f2fbcdef418b949838b0dd30d6425a059034e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb4dbc74102f6a4940f6a0f6f4a84f441181d58a20113eccb0549e8b41cc6394c804b81c3b0484bccd8689777664ca5000000000000000000000000000000000bd600bb45ad3aa5c6cd0ca5e133433017226c9110d8abf9d490602364100f34402fe8c07020c0beca1ab0ce548b35351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e84050303b8942b73c9e9e9b80adec1903648a82f353617536c4e2fd5cdc89693afe26916b0350021fc41bd625963260000000000000000000000000000000003ad3c1bdb591a66e9567060a8726a2abb9fb99bab009f4f734fa386c973b0bbc251bc2c9cb525b60fdedb3a172c67ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c1a7e82407964f9ec94221a2ad98df7bbf677941d72b93b15f5d706805b1315a08881b1cb00cb2ff1a25a83870df6d000000000000000000000000000000000aa426764c60fefc5a87f6812b2b479dacac2ceae65e1da7249f84f888521e4b691788191d8cafbc75d47489ce8382741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018797757b20f4eabbc0cb3dd28fc503438d988a6e7a7e44d603a4780dc859e426ec7a8b6ee130176778268e4c2512dca0000000000000000000000000000000019666ecbf1b42026cbc1d42b59b325ebf9c57d7664bdc26b93373e827a38fde1bcb9874360df3a902de92137adab275a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000008aaca2307e744151c94ba429dddb0702c0dd9c945782127c387f530e3477885ac3622961311b953e209699bdb9a11f10000000000000000000000000000000008d7175048049787424d019d60ade8f2e973ddeeb54669c32701db4def22e98b1608ca319a49ee28258d4d418eb063d6", + "Name": "g1msm-17-jwasinger", + "Gas": 67320, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000017fabdc2a00bd374668c1634f52e6845278f60d24e8ffac5ad1a0305de8d8f633fe66f103fbbf97103725afb5a61baf800000000000000000000000000000000032b04b5d778da193f62daee3964b4470857b4a0f0f5a698e31592b3bbc9ed2ae72cb481fd71ea83e464a2819a06e0a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de6060b7260fa7eac70b2c09526f8ffc5c6704be2c18c47d7c4b11ab11cb243f55bf5dceedd48287dbe00dcc7a5c39d0000000000000000000000000000000011728aaeee67be70faa4d7dc8ea48a60d0c54a9d7722a52b02c9da861f9962d390ef27e1058e8080815e142bff0b36671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f938d3847277090a771785da05e77fb3f51e628fc4ad07f3201380b9a1a7a2deb88ace689c0964ef5ea1d36e56a76960000000000000000000000000000000016aeb91f1b57b83fc4e944b5cc638e2cd2bedf1de3aae51e892bae7121c73704ab2d61fc205d35e404ea94102564a7e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009fc12ab9cea6669968b95486b0b66f55f32269bf7992ab80327ea2780060aa979f00a22ba2bfdd579e71a959f6e535b0000000000000000000000000000000017957cb675ecc2a8ec93626d5d345e1ec9742f0b4f706052ae25abdf1cee0474ae893f90a7cbe78b5acfb6be510527db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f682f4c9156f161b794555ee41c58a900bf55ab576768b14eb73f0f3f85da3cca64ce718b7757d6b005e7ad733597f70000000000000000000000000000000000988605131f66453fc09e71c005277d81294186fbeec39c9e36ac832d814787c0119531480b87846782c3b3ef85b2741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d26fcda1fab4b53bc1b09053d31e02f783cd8fe6bcb1ab0053d1fbfe1fb9449ce48b47d3ec409e749fb3ebbf98b4aa00000000000000000000000000000000155d31129b3d2d6b61dbc87b8d2f55e7c6956391d9d08c72af8aaf5d42e8d7008a2c6a43bf526f8699375a140b08280e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000408a2969f1c297e6f21ab6d1a1d5f00e8a40b890e9d8c7b573afc3eeea60259e92cdf0b6dfe3601bb1180795328dfb700000000000000000000000000000000169289d8f7ec09b6d9ab2ef8bf271f19926ed715e1428034ea4806a1ad9dd5edca784f72734f6d5dc69c6c910769617e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e6a9812fb0da1d5f1fcc3ca92cc12cf17d46d40a4329169e01d0024b27383ed28a92fb52eb37ffbdef076dd610dbc5000000000000000000000000000000000de7170b36adc59e538991834696b1f3c876840c5f1bcaabc585243b65e2cf832da4ad78aebddfbd8d947936a0525a001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000108e2f1cc4a9c5aa707082f634ee8de51ec9a44897ee7e4cffafa3272dc61b6e30eba030145912ef21b9ec965ccd8b0000000000000000000000000000000012145af2e467ab2148e3a3320e01da20124e0293d3fe89bc6e89d2d37c12ea3bf09ec5073cd0c41f5aafe933e2e5713c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4186cbfdbb3aa860cafa5f6451c07c46156fd91488d32ade115b295adf39396f0c4265937621e18f641b224a7a934c0000000000000000000000000000000007c145ca75a9cd7a67f20535d9a68b56750b180c19a7bd145a0fbad930235d0ef70561eb31076b2c587190893a75b1141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122382f9424b81fb6d0397d07de001ff93666e4f39ad8b514979e65206a949e698b4fa5d1961c852eb6da19193be0a3b0000000000000000000000000000000015903eab7f515deed48be1b2810b4c43d09379e0454cbb2f71a603ffcd1cc7c53b2d4a4bdee50ae8a555050fd9c96a1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001818c548104bf6f3f231395f46561a0ebf321039ae7cf3cb54c0b2e901bcd59f38bc488055193f2ead49d8da41e5db2f000000000000000000000000000000000275b44713b2d70ad0ae7e08cbd4933dffaf51915292067e4877887325c220cee554ab9f9138d09259cf223841ed7d901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001454d1af22b3950d332726f6674f06e0be4d8fbee8d00da94ef38e6043d6ec0183a7fa685dfc2e7f278c2d66d0754af20000000000000000000000000000000009f7e4b1b73ecc1c4e1aec55b78724568999136ca5d4baf7f2c61f9fe11b80535dee231da6e2b8224958652496bea48d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004392c3c6d7d3ca22cb06b5122210c59905284e831fbcf0ad8a1b88fabb2333f4cc4c1d90596ad2adddee0634c1cc899000000000000000000000000000000001469bd6927bb1d191eecd9379dbd5c70e91ecb37ddf09eee67d897008a2fb0c366e6182d259b20d44d6aeb41ca28f9011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001347ee924b4b01057d19146402eebfb789463a9bd60f859d4391d680ad99314da2e44ff5d27ba3ec8d2b3c28119b6ef20000000000000000000000000000000019f63c3cd259ef162fc021c5bdb6fb11b7666830ff50508341b87a054988c293f6ca08cb27f62195cb2c77194e3663bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148a3338a8cf177095b53e676d0da6f5c37fc1d42a6ee18a1dd9175b1ffa0137f2fe3b71c21d1794837497763fd46d4a00000000000000000000000000000000061addc73b5f8f6dfc1210d3144bde791ca9761cef3e7cba9e917b3220699b587b535e87dd1af2522a476632419b839c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176afcb9c7400390f1f1bfb074715352d9a4ef4ee3c39795026b8833f6b1f228baee37722fd9985d7f10812a788281de00000000000000000000000000000000018227759040ae68f1f86cc8feea5526d6c318bc3686fbfae7309a423f23e4110015e58d76cb78098b60efbe012d486a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8237343b653c927da00704c1767a65a90391c8af4306e6e7b90b74d5a6f83a90ba31e4e96ab3f7c353a02ae0ef2a5f0000000000000000000000000000000014b0ab4d0f0e252719bfd25223c8586cb77eaf8b6c884357aff57935e2942c5f928276e86cb87774891792366779bf181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000011b3bc4cea81d9afcc344193bc2c22b968375e0143f885b9a9f6125bd36907ab731b062df9978947e8efc9b7d61beff1000000000000000000000000000000000614db843f5d0762fd28dd57bc58fdbf15bc64dc275590d4c120927be89eb9bd9657df2c6c680e5da78f2eceaa0b77c2", + "Name": "g1msm-18-jwasinger", + "Gas": 70416, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000545e436641b75f0f28d4add04f670161de38b9900ad384b29d441742266316fb00ddf89e986685a554412c31fb2cb93000000000000000000000000000000000de13f457a3b61ad0ca17a74c72f3ca6cd10f392bdd2193f4e076ee8b8f48f464c59ec0a3080711bfeba93658f4613831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e26fc4e12be71c6fa4aa4e5934172f0dcfb5bcd3aace8f2203374893b14deac434fffe0451f3e5230a410c7957242b00000000000000000000000000000000088be2171d9ec6d320323efbb6bad2563a854663e987de2ec2a74a7a672f8b50f5d9afeb11e43bda1637a29fb042a3eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ee0dcc1dea9fe89bdf0b62648b82cebd7163e3996f4e48763094615a3f4d8f72cd88858f25c2895502943bf9af8d33000000000000000000000000000000000cc76cd900976bc11b5f6db7836b4895bd54b1bfaca2eeb04f386fa16c31c6b41924cf845f3c79475dc96170d00b17ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2f2207838655616df1c25bc1668dd2265b87c2016dd3b03b58938a786e203c7ab46e892eb48e404341e193fda247b80000000000000000000000000000000011851f48e230f3e9e8ea9a8cbb02564a03f17c43e8acb3514c6a4792e3d5d54839abfeeb0e83280178f680a3bc8eba9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000382bb1457e59a6775990fec46996e6eaa15936d918f6e9a1d07ae0a771b4fd47c470d29f91db996a03ac16bcf882040000000000000000000000000000000000efdc8042c7c72a9b7dc6d86710b66e8d19b86f565a73eda25921b1670945aa0e33187e916b6a5911ee4c73d9284e611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030671b2ebe6a301853653c269d81d09624d07a6e029f7360803f1fb3fb17264be900310ac7e06fe09d6b9f95db45176000000000000000000000000000000000e19fefd6cbf2bbafbd97288d994f45a2491a5c6eeb2cab98130759e335ab444cd866e4ea01568da7b67704f7e87f8471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040303c670abd8692a1a313aac605104aa25945d570efd725282a171809ccfc4f5b2af77cbf266c5bad6a281512ae390000000000000000000000000000000000fee9d9029289fa97b02ca86841b5256bb723b89292c27c02e6053d0a0eb6e18a821d3732e3cfcb6be5873312bbb020d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003877ae82810ea962c6cbea466020b96a3a1bc1198d25ad4e274ce1a87deb613adace75e1b092d040f675dcc67b77746000000000000000000000000000000000e3d732ca213b28f8393af748b9a7caac60c122ee374d0f54ff82529eb5838516886c86e92caae6c0f4d540a3af08ae11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170c47600f58e575b527b6af67024a0104cf4ef61ea3f0a26d23d6d41c4f5c9155c5434cf101b7f36a1bcbd7d6ccecd6000000000000000000000000000000000a19e440d6644896362a3e3569f919d6dcd7922da8861b65873559c9d5cd976cb6ddd624284839a8d04edd6095cc6e681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f13a4ac688eb07cd9a19607b6a40694c8b48ec8aa86b097c663d4a4c06cfd9aae625d5809a26d53782053af7bd6e3f000000000000000000000000000000001036583806384109fc75273579762e7ae189dc262f1377f4fde33f9bca8d0ad909ff462f2588204809602498231d1bbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eafd2dbda55e2c4a29a28e4ef40723a0c90852ca3e625338aef9f96f07a47d1095337deac16b5d0f6dc3a5a6f0ab493000000000000000000000000000000000dcbc21b74d522e9bece5a57ec1d1c44690dacdde6f3395dda84bbaa3ed5b3f8b5ea822a2d9b9de7955e8c5fa290bb791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce932f1a653a2b17695d7483e57f33bc005382c0c65b21395e9707c1d63bbf23f4e0c7a0d12d5439379bed771fe18760000000000000000000000000000000013e4de35f2982aef82ed31e725645beffa79ba6af402809b07dbd291674906a5d1cd0332aee259c45108a0586e6be4321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012433b7797ea7074096caaa208fdc30f22bfe6dd5c0f3bf151a4423b251aaff64d0526d6d2ac351c9b641e5529d8b01f00000000000000000000000000000000146f24f4801da81a67b87ce77b29fb24b1e3660aa068231e4b2f8e80fc6f9561339e79e8900102d3097894e63b8fcd811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c8fae65a08a0f42cff0aebd9d3cbb88476845ad11953bbd6f1e7bf19ec3d7af5cc375add971f996288c24a0a356d330000000000000000000000000000000013d5b3beba22cb04ef3cb6b50307834785165aacdfbd8b19ccb58e965c92b099ada86fe5bdd5da9cd72e6b165d2a7d811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c0d1e21755d4314c7e3f7b562cd55d75bfa76f918d015fd3d7b49805e001f8296ac2ce03f7050b321aaaa9142427c2000000000000000000000000000000000aaf63c91674896079d2bef6d264edad161b290eac2c05696397d703c9a8a051c2ea53bdbacfc97863e387e82033d0ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b0933d1f61ac4a7f1cfda77d0453958eb3436a68db47eefe8f55669db2d8f8ae6b98b1f73713bf3662868ad5e6af4b0000000000000000000000000000000006cfa53e31e18ac4b64f934cff5beb679aa72938a8ed658ad795d52a198232b0de5eb588d7d337bb08f48ca7220a40d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000394873c2fed1e467d66af28b85c39949878001c7aaba5bffd73acabd02a8f233fc4c6a89414edbbed15dea9c623e4b4000000000000000000000000000000001465738fba3b7303c46724f02aa6df6d43507f3139290dec66df37329827a038401f72d2b49e3e851897eb6338ad026b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f62ccb47e362803627f0949e5549d16c4061efaa8bf333e000256a765ac28e25ea42753e6b0531f9630b038dc74c17a000000000000000000000000000000000905a3cc7325ea0b436335025d903098fa35de0a786d76704a72632f19f71884a4c340385d251171bd60e98fa21039d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a4599b811796aea95742a0ef7638ce8fc848e526411b0df61c4c2c12d3098e5ff3a7b54b91260446e412179be5cd140000000000000000000000000000000005679a86026866c373f351d2880a5ddf043c1c67253353b730f6296abf686b3cca2e34120ecd60938d0b2e2546cc29a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000001474e3fd13fc42af3149453deaf6e64b4ac93960e6537b33a99bb72047296b5291545a1ee0b9b6316c617c61824f51710000000000000000000000000000000002f4de7405d1b9d0a2fd50443b343595c1ca8cbcb1e6459b7508daf11126b589dfe4c68cef3e631462fcdda7885cfc2e", + "Name": "g1msm-19-jwasinger", + "Gas": 73416, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000132bc434e48d473357753c8dd920b2a2d0fe0725b3adc8956c5938214121bf18815ae969c73c438b94a95caaebb7140e0000000000000000000000000000000019e9d07c11ab7aa7257008dbfafcc746146aca49202de5e9c9e0cad4212eedafc71be8487f814adba17ec782a78291471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001122419326f0e185528fbb941e8a27156b6a25a4facca37dd2fffa223eea2a270043ca3a3ff2e4be0da52f94f7ad5b43000000000000000000000000000000000002ae60bafa9af75c09c23174dab8bd4d113170369914920185d02cf5e94eb1f5b2a17826c549f46dbf12490776455e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001326e697127e0d847550c37c641eb2c898180df0f8c50d7704d4bb79da9a43b9733dc1de3c0a67a2dbcef3cfb10dd017000000000000000000000000000000001033931d90f06c0806c6a9c1c1a856f489b82b36d8112e8f7cce07ad1596e2ffc972252c32a155784733611a235d5ed11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020b1cd41e31eaa7946dd1bd7668e386016de077c82d17bb0a7543dbf667b8df888438202139fb224413c9e4b395754f0000000000000000000000000000000019aea3f434a98d476f7ef459f556258d762d99165ad0a9a63f8121abe7937917ffc05ff16799934c568df9a7925f26b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011289a42ae2bb1e1bd5e35bd4c251db7c56b44f27d1d5fdb2d225c1100203e6f81bcd876d46c40d7e7d2f032ea1bee880000000000000000000000000000000014426b8868954c77d8c51f90414294b1f3254282fb01073624bfb5e84fa70a6256e0fbbc6a9540f605f4a91fc075a3eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059893d2ceec0ffa31ba4f6ada42199d4da6d846f921bcaaa214448d6a1856c44e0332ce78dfa1a0921e8ecebec58183000000000000000000000000000000001463e0ebdefae0ae7fc100f799effb6947695c6f3bb94d5ec3ff6f27da1ea482a4feccf1ffb0df48099278fd5eb32c6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fcf0f22a86470f8b7bd74e80edaceeae3919abb65151248bd5781767a8b31993bb6eec0661cc32dff8c1deea2231f4700000000000000000000000000000000099ead44a200eafdacea929ea852cf7c633355c4d32349e8c0fff2689edf576bd22c0eb2082a3819abb1c55161719fae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1c47dd5fabe2b396544222bbd5dc9b006fc7f24f99e911955725abacdce5f1cb5f571e7c030b20e24a6621e4e47d8700000000000000000000000000000000144796ed5abdb593e359307004e6d9de7534dcd31b837c364a239c4490d97211b411d8945421e980b3a85cc0d5ce6fc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e2cfc567cd2a32d5b66f093e9ca8a4bb7f59191b11da962993f66607beefd625e9bd3ec3d3eee36dbb07c1abe5d1ac000000000000000000000000000000001951f4056c957483a2e88e193e40eab2cb6bc4a6d2f6d72fbfb9888e0af35ca44a075bab0e01ec94bf426a4c7b5aa7eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001687c7dbf40f050b409a4143b9c20e5e2c058f1d5926f1c7b29821a659d4da2f2a78c3481da07f6665513e6426c1039000000000000000000000000000000000102eccccbe47b8fa6c3e68176aca5def09aed31de87a69b82d4f484c9e4c34afa3308f7835586e58e56fdc793087cc6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009003c1861ef78913c0d70aa531c8d696089b70ab7bd6c22a2f4b08242c37b71e118e8b6bb23ccd7b5b290d8f305bd000000000000000000000000000000000019cc59172f9f7e1bb75b620192a23faa3af396420a827222d5503917a6ca7eb26092336fc2c0a27b9d70cc24f780d13b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002217a8990d2ec8dd6081b5bb1bd7a5703ded9552f5160500cdfe117ecd70def95394cfeadc5dfb42f444d53200963a8000000000000000000000000000000001942c9b156cd5bc99b299206f609f1680607fbf2cec202c9325147225cc4ac9bf0e10f9cd32dac3881c772224e6827a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018581ed8147813c72000022206150d858252c79a87aea69c829364060e167857c2c454711205f9de6878b86300136f1000000000000000000000000000000000eb5241686b60467221dabc4e2d3e18a92e342058be282f68229f6fb14bd51f68bf6c54843575766b22450a7b760984a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f453559b199ca208db36b21a2c7858f1f3e9d30f2566f9466e2f9ab2ed73ceac05a1f7fb5834a10afe90af55cba569000000000000000000000000000000000abe52048855d574b4cde8c2f35d82a3fd23ea1eefdd49c4731823500bacc933475f24ea3716f836a5a5de81aaec46931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012dd1f1e263e5b2b6ea604bb7bbc9c272b2adf2f4b450677d1900787000ee88062debc10355892b948660c6ea6375e610000000000000000000000000000000008e449d045bc6ecee6287e98036008dba3060e2b4f6602b199792d7a4bd31bb248c48a0f0ea0f07c3eae96d118a071991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dedd05e4d27fb71dc62af9ac40556ef1077cb8fbae8e9dcf037dbd4ebf71f5a02b2dabec1b0f1ae13b5eb9591ef5bb0000000000000000000000000000000006252be4eb450078f37d845be739239820dcf7a93cb26777e67e16f834edc57ba143c82080c493d557c3c2708f96a3821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006803e53cff8936205d02afb27ee07e924d42d9a12f5da913941b78ecbfd79e716c741393a39c5df008772fa30d0792f000000000000000000000000000000000e59a8cb64ea37db6c7ef92abfe29098b5f897746c19aea732d9a321198186f8157d3781ed7d4b46a867f35b636672741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002998a4c031aba2f5f0b78985fa6de35d7c8b4856a037f5aedfddac9e16b9ddd7a0067eb4676fad62840b4438566819600000000000000000000000000000000107c286b9b4d931bec0212a83ec4c4c4143f4916b64968f0a7f54ad88e8a69444a82f1122cc73f34baa540f775b11d421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f603dec5ab6a3e421c3cb12a4033fe3fc8e10b50428ce09dfe1c3b432f9731da008f4dcaed2edf37ec01690d52efdbd0000000000000000000000000000000011294a5238934fd78c1c28814cdb33b85e004ee59965907f13d3e3ea3a408bb4d0cd14a1937eba8fc3c2d5c53140a9bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016460c4af8ca797cc7d10af7e8c1592bfd749cae62f39a8fac6121e5fec95000e0968293c667bef80d4227a4235e8200000000000000000000000000000000001380bd18d7260e6a37ea44029120fcc0428cead4a259d11ef28b45f8b1a8d6adfa1b264564b5d6b33e45063e72c546cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000154203f424c1170fc65ee9b5eb1115ef77c64f892b5947dacfd3dd728c602ee3198a0050b074482a176db7d04ca5ba7e000000000000000000000000000000000b311a97a9da2e9f71f4f2703857412249ffabc0511d7ebd0a9e1e59a0b51b261b9193d44cd7744ae4e758f6226c6d8f", + "Name": "g1msm-20-jwasinger", + "Gas": 76320, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000015bc64f31d45ffa9185f935d1d118d253dbf222ce5e60141aa3e233b9ba5b55770d3ec5cdeb6892c0e050e4b802423690000000000000000000000000000000015838131709922a7f4d3181a1eacaaeed1e242251fb3079de6bb95627bd9eb16c7bbccfb8b47dce1ab293cdc543e42661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101474b64c5839a3a843e7f36ecdf91835bdd0328a77c0c1517fdaf0b985c5f553d5ce79245f3bbd01f97433b79138e40000000000000000000000000000000018b64f40cf0ded14585325c9ffca9cca458d90eb18cac7ab74a990df3df3a0ef9e76ea8050e9646ac23302d5bf51698d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf9ad556cfb7e2785c21be67e9b50bd034338a12d6dabf47734bb4309f350ebb7537e7cf55f262ed8f3d99510a0e9a0000000000000000000000000000000000c4c9f76de44e76066a2b10a9d48c4fb36a5518bf66e9542b033fd185b77262583b005a2cee0e61d75b56264ba16f7c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000054e11da7caf079cbb39ab0c386e98b43b99df7505e0388b9891254d24da31987231ead48e8f2d2554fdda5213adf070000000000000000000000000000000000df4bdd692decaca65957b5cc4cd34c33d6b5e85c9ca4a1e820e771fe67efaf0f32aa6872d3ff91bc038e40a9a3b83f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080c27e8389635a1f1219cf420adf5437cb2ba7d2905406d41e1197c9b5280b38ef2ad0bda1673d973dd4bb6b8111d61000000000000000000000000000000000a851fae3033cb150055f8992b1fcabacd86e5de084fe8af29bb06ff22523429f7262a73c20667bb75045732358b05e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000953e9e19d7e6a1a540bd5e254df7c72b34b5e58307a2e36931550e1b9dabe8e3207932e3e0d76f0b8f6f2abca06b4c90000000000000000000000000000000015304799d98bec0605238865ec6a9721b59cea7bd3ba721f0ca40e8404d1a55b13bfae47126db16386aa4fe386c187911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001de88b30b2d7963d901f392b1fe38d6b19511fe6360486ff63af6598cf071dbc2ba984d9450a39a0e036606fc2712af000000000000000000000000000000000af2ab4b3000ef303c2230b3b0eca9c6edaf9a7df5e8d4f83678ee0a2024dd462dbd5ec698e60aa118684305aaddd0f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148995c67088528f591eeb46892f299148056803a3ef0748a84fedc983963398a71bafebd52e9a7eb25e7e7c25873fef000000000000000000000000000000000a6f1cd26a1d1b284c5ed6274359826af934fb7231de804b6d1b98676fb6038536e96c0d0f6debd6d4ed6284c98e54941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b96d6fdafeb1e1289715f3d7471a367df97a7c34d4b6fb12b0a2e85a5ac495de986232b34718c3d11280afe82c4e77000000000000000000000000000000000b571426280599d2cbc2758ebfc33f3bd21e6a9091700b5d8b6c2e85b9c9cb337da24039e504eb1da866c7c60394d8e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007addc01bb8a8c94010407777e504523a6ced10c898594b0e659b886d82c0e5f7af39706875f6143f9b282d75687f02a0000000000000000000000000000000002ed6edd4e0e41bb0d4ee156b2dcfcbe58793701e2170bb98138f25666d1f49fed33ac366e2df79399daf6d4606d47991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000878c2dbfc20804fd2dc4528d742119cdfe06eef72bdbe39c3ebf6416a4fdb2ec7455d731dc37c64a0eee45be6a1636000000000000000000000000000000000711990604ce169bca55b086cc08be5c6ced607aed02bab7ce5e23c9acd1a3c730273ebd9c3e3a9c96049276281d72101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c7e0b38723be07408ad4b39b2bef1b60dd259fb58008012639aca83a30925fd7a6c5b2b1fd03c04a3190ce2a659436000000000000000000000000000000000643ae3f4ceb0faf7198855e4c218d2bce3a84eb24e22e7ef04a071f9fe8646349a059cd9f7b9df3d03af8dbd31154ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e26b83f125d67bb590ecdca6fb6cf3d80a7736c4a72c58b5cdf554d9a5ed49524cab86ea90adf3e791c08520a4955c000000000000000000000000000000000960773525a96f28df485c6c2e2cc1fcbb8f61c73cab05944dde96756b488b78601333fc24ebd522445f9a34a07524b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003714bf8581de78482c555daa72e47d180125ccd8e07ee863134f752455c1492b155e1276e3a2c84d6c8a24f772816e40000000000000000000000000000000016810dfe3220e8af10df32e152404a140ce28afda3b0a10e90761de7d0f177e6e0cf8ae1489b98dcab5cfdaea6acd6f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a49ecd2fe73245fc2cc055afa5d0cfbf8ea242c6a66d19f05b27c9fd0a392992c8671dc554e39522b1bf70db85dc13000000000000000000000000000000000762fbcb583ad96d8e10281d11de847edbb64581ca58fe848abff3fa328a75d522fe8e721411b8aece7d1caf5d5be52a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099b8bb6661ab5395a0a5797beb21479cfa46b67faf6e7faa92e43c692ba3e9241c70c2fb5ebee0211447fdb98cdc46a0000000000000000000000000000000009f193b600485465c6af4b2752927743d0dd265cbdaef29cd441a02e263e17b89056250a3bd31dafa95c04e8fcb1b3661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e12a33e1a5d8bfca57e04504f1a38cb4aa1e5fa166fbaa4c2ca771862ceabca9f61eb64a6e67db45f0c944f6c1efdd000000000000000000000000000000000c84f3f126a8c243e2e551724f3ca237bb3380e5435cac7257bdd4dabd7e8c159aed600cb83b5d0feabce363c5fdd39b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e87050c11c633f2fd76b328069bb564a20d5ece1d1a214aba046bc34af0408184f7cb42d7ec1f160fe275d9aa197361000000000000000000000000000000000f36a03ea617c050594c8eaf6d3c3f0282c47a1a2c4b696f4dc1007769e9755c1ea2ba3ff1fef0ab060e6efff16646911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3742c60c3363fcdf70d2fbc5f267197d37e60ad718301bbf5bedc81627444c4f498fc141abb87a8f293f799896abde00000000000000000000000000000000163aaacaad32777c6b78e6644dd04f257965714c07c2f9e76843bc8d5a7183eec35a0efcdb8392a4110f2704192d25f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129e170a7c21e69257a01143e3964f38b85c8a1de7739cc72a6f374b2f51fc8d3baa7b5e1e8787d74d6c646be4f3bd9f000000000000000000000000000000000976e14fc451626c1c6b7a464a9cf2033bc2b269f57ec9910b04f15a6b98007aeaae08f82defa96b97fa695307255ba81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011bfc72ccb4083136e8ea2e708d8b6bcfd9eade230ff68794bf0153d01fc5ad16cb650c76ed06f9fd40f5b35e12f7ca4000000000000000000000000000000000ea4fb8b1a6c1f64e0505ef9db75419c1aa9fdd1611e7d361f28a6f8a6e84999cf242e2d212b72bb94f79476a6fc858e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000132e540a9c76a1d0926d857f6ad0bcb8faf82f66ce6d134bbf35281398fc9109d017aff2e445bbb27511843d409d914000000000000000000000000000000000a562ebdbcee78be8efbf730ee30469727ba3a89b690d20614d96ca1885c5cded1c56f8293b9e4cbf4da1552025b395d", + "Name": "g1msm-21-jwasinger", + "Gas": 79128, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000630d8a3899bb020f8f123b8efa6f471cf3bc0a7b24f95adfacd2c6bc3c4342de197eaba0b27861ea6bdcd6555ed5c350000000000000000000000000000000012da1972158eee1aeccc48b4edf597b779dbaabb9ca6001b0f35cc457816e54fef257fcc3d1af536d1d2c115aef5dc2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c0ffd2cd274cb7c146596723a2c26f0c1f339f5d2fe0828d7919ebf977745fbf2f9ca5e7a8e244e3d86a7fece34373000000000000000000000000000000000ed343c846bde6c4fadb4510dfa383c264d605e0717ee8453846963a13e70b1cb97c205fcf9b3d649e83b27e2951f2571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000879c9853c955fb060bdab01a7beb1a09b21596d546d91ef420c0dc53cee445fd91affded5c551653444b0b4ccd15347000000000000000000000000000000000a7a9f59cd134c59f27498b751ee66367940e82e06a2d4952055d6cd4254452e29aea2e4c65b2531c355b9858e3feff01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141c76e1e862570f1c1f00fcbbcb661dcb5efbbd5f2d3a908bc0fd9dd4b29b55a220f000c68e772b47b096f93a07dea20000000000000000000000000000000004890da769727d2b81e4946fe454309c39e246125c660cfc1c302141945dfc79cfa96934b908ec31f32bc4fc3f6e6eb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bb338d98da77aff4f9252e8e6334532e8a2026b69416f6256b965962a6221ac840968d63de36c5021a3aff774cfdb9000000000000000000000000000000000d101e749765f3d28ed9aac7afaaa87f93d5dbded71236ab703343a8d9147b5078aac46f8a401ffc973a5fc6c39a18301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c4bb823ede88102242f1badf202bcb61d49d6639e0984b4b9ea288dafaf62e8e7b288ebea8e2d0625c7b76ea1745b30000000000000000000000000000000000ca87cbaccbcaec6a3a68511df40c7b474b275d46fbcc3efd145538763e6a401eea7f0c1b4bb0b90f740c8ee9057ee5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df536ead3755e616cb8e6459a599488b0ca8501c19f53c373e8684334810e0132d685bf78dbbb0d16ac1ce4bd80a135000000000000000000000000000000000ccecc27365fcfc7176e665861021e4bc363c1f5411423929f1e0f31df2d48f04f9183efb913e4cd97501d0d4a2386081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171e5674010b2608faedf1ba90f343803ee186634deb046b78ccdd0dd99a0f05e735c2367129d141ae5035d1c81d98ab000000000000000000000000000000000b428956ec9d5c44e3dd46a9a5912a3af07fb95a6af109bbb0876cd3ff480f46b563a6bd1a7b180ac697cadea5480df11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000681aa8ac7de6c7320c6fb45e15433f62cc6648043424a0565eb9cc65410574f4bdffa41814831c11df9ff791c9f729500000000000000000000000000000000088dcd87e67cc7d354262a7c5bafdf1bd61e301b98c70c01da3ef8a4373db943a7d5e9076ee51656b69903fa7faff4e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e42abd90762c3b0a863753370d477fce663b1d6845854cd78c54446d1a80ca5c5747b4ca4db8585987ecf70fc6a84a0000000000000000000000000000000003940bafe9f66b705be519553931f63291d557274f7ef3dac98c27d2fcc30f82d301ec7ff5bbcbb4975176dc84e772e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118fb540b05580b66fa2ef3792f102c6def24e0f77d3a9c990826122f4b8ddf5f60c232ca1588a054938426b8b1a253e0000000000000000000000000000000001a0f4bc31f1d7c02394a8d1b383a6e50f47b78cbe9e480e00fb6eee16d5192a42bd6687e433629d581010d76ebbc61c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a311f0219808ef67149af64009a0f4822268699a0ba11f4a89a2ab89b9822c5bf8c5b67b0893c38c199e88918a685d000000000000000000000000000000000963d71642f3127c3a25420f2da66df0d13c57682b6df7e6c77648b2438b4b697b8fcb5349fc4fdea9a3d51a449574c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186b60de25c5eb08254868851c057fd10c86bddd7df505bbb307f189480504bcbff2b02dd36f52328229171bf4c6f05700000000000000000000000000000000146b461d08753f4783685385eac0080ded6b7f972a1b7748f55e6e8270974ec164e03e8cb2d2e2f16e943c7a629900021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f8c951266013304335955678c9d2d1fc6e4438f3754273009047b494909f9f24c68d4d7d2d4b9f51e25c4ed066a8b00000000000000000000000000000000016dee0cc2fd25e408c69d66325bc0e522327cc3b6b7724f0daa071ea371239b26399d62abb7212d1e9a0bba6cfcbfded1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000843e22165aa7dab4ad827e80a21321bfda5b26eafcdb76186953711a214f103cbba3ba112205d9b2d6afa9b8b91111d0000000000000000000000000000000018440a66fd14fcd88072c9bb97d69ce8877e403d99ccbf87cad3fa44b4bca473293e4d83a5128bad90803c93bfddcd021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe2c8d5603c21ebcd6682aeccd9f27e5aaca6e79d4765eeff0c99e032e02df47f87c65a4ae8adfb4b398d44b2b85ad7000000000000000000000000000000000381081b8bd577fd03cca9176a22cd628b9373d1b72db0d7468032c0104a687d0385884ce9f8641f875bdb5af69f9f301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e47e2d03142903cb6e8b4772407305ecf81db62359bea545f8f4903b7b804725a34a8461b1fed82a94b7a75eeb594fd000000000000000000000000000000000b2538ac1774e397e80366418a8d13bcfbffaa46c032f82f380853b39306e8f4eca3c4a25ea98abeb1335284d6c9a94b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000959f0fc6ed7b3d0a42be318cd059eef5ed6a88f3afefbb52feb2e93a91f56b92ec904e8404a3e82f6a8dba2837c56ed000000000000000000000000000000000d3226cc36bce4d16e24d3e92982bf0222c1f6e1d3d985d3fdf9ae4ec311cbbca95ee1e420a321cda75ba131f3eb90221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f554e09658526373e2a962b8114aa5a6ae4e479a85548fd000b18a1129c5307d97a398b2db4389fe2f327efd16d7c380000000000000000000000000000000019a0ca577212de3617c7999b1a695af1d6e65764796d4abc7113bf906fbe844d993032f3d0244f2b321bb940ca437d371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e0c80927023794ccc27f075907d24bdf1431e2d10d08b6f09bfc278514cfa2224b8292e2701f8b3fb18ac4622b6d19000000000000000000000000000000000f42933ca3a07345d00fe9d479c701d088816659f467d0638db54be0eaaef228ef01e3b94e71a99894138d12de699be31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007acd1c87f6f854cb0727d33bc179ea2aad69f822a70b77ad57a2e102e2c6e6eb0e57e0f5389d59b8fd0284d903652ce000000000000000000000000000000000d200877b980c07b191b490ea6c5e733d9a2758a88129676f7c218b00fb14cdc798d7f4dbee7620888dc6318ada63a671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e09285782ba9800a45fbca1b35d11ccb56c617114087eddac54700202b118613e0fce44f6a8c41e77e14f17295e8cc60000000000000000000000000000000019c0d74b25744ffb8301159d5a888d4eddf0090e7798f5053317ae3a55d8c8604a872498b59b22eaeee9960cdcddf91e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000079ce475ca4c6832183c8e35b888f2a4a7970f5c1df2269857b32ee78d541344f40ee22aee21412905032b626575da5f0000000000000000000000000000000010a6f229b07571d0a833040de9c406afbbc9d525499e917e1a1a376d4ab0f5e129265180ff96ea297defe41537e3a99b", + "Name": "g1msm-22-jwasinger", + "Gas": 81840, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000013a1ac003ee6c6a39fc63179be0daa3924071b5f3fbc52bd8ea84146c396bd036dc7fb29aeba4b68044c8ad86525b4ba00000000000000000000000000000000080500a0234da123f16713b8e7bc7ddbc615bbb2dd2009427d1c4f6ad0d66ca403a2df8802c68cd86cdf45b70f4371c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cbe587f05dd76373862ebe0e9328d029fe472ff36635232ec4321ccf89725d258fe7935ac427c3daacc98ae70b1dc700000000000000000000000000000000194dc5b447c63fbd9422713e2bb9c16c75f275dd784872a3854577eb12409c28bfa3beb7548fa55f11415955bf8234591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170796d67b9c300069945dc152754b5e32fba08c369f8fd2cebed503aa12cf36e5365c8ed6a6b741428c6ce36137d9a4000000000000000000000000000000000ab0241542e754c92d1621c99e4e5741dbdcb41d85cc20d1641334526dc411edb1961f32423818d1104a5d499b3506f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097984ea412e6527f0691cdf1eb784adb01382e07f3ce8cae287d5ce8dd9742cfd4e945c2a9dc321cda51b91c9b2b5ab0000000000000000000000000000000009d018f20be4762f7892da5bdb3dd5e4b96faaa042a2edf0cebcafd483ffdbdf961658f461742dfe81814c4c12ca868e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001629134c3a9993123c31b7aa704f4d8041303809f1c2740949db80a25acc93d13f6917197088456e8e26a7a5dc8a215f0000000000000000000000000000000000bf30c5d6cf6dcd953cdfbba1542ab7d90f8356d54f6d1a59c74996bfdf73205dd06ab0218046052d57bbf3384383111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a6e2d4de71f07e950d78063bc0f013c8b61e0a331ab58396a13c6280cf72399a963497956fd1823ad96812603dd10d00000000000000000000000000000000165b322d91def7ec9fe4c01f19495d5dcfa1396f0f72aff2afc8290a512d78a7f25cc7db95323d39677aee224c04572b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5357adc1a74e302ea033a65428d5b5eb62e50d36e268fa19eeb0ca24d9d4057847b3ada23fa957590f68d287078498000000000000000000000000000000000353c8d6455b5b2f86585a8310bd3446249e0adbb168242929baaa86cfe61d8f59a376e8a0f887e2ce5a9bc2f51a2ad51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017de9c7f64513d775412007f4d5cc8717d72bfff75f2b4cc079ba0366339456a212e3867f9ce38d8a6f3453d920e7e70000000000000000000000000000000001468a9def6838b2ff3ce0d9604d5d2711996e9238fa30e141e701642e260bc87c88489c163eb414af4a2e60e427746a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003815ea43da1556965c08e84957565c883189d6f6479e00a03f863cea065fbcc94c1c4dd9f7ba35f7e7d14a95ebadcf3000000000000000000000000000000001624b798cb98c5d91db7e0c7ceb664aeb72c2f523382a22f10c3f9d003572fa87ede4a1e77ce52eb0cc4cd8db8b663981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac26829dbd1e983eb58c1f1ab9fb0abcf240c4832c45b3ecd45af900fc77de2262b3c64a3539dc4495a7351478c017800000000000000000000000000000000070054c1fdaa77461f95792b73d8a6394eb227ca3adbe4376de5c4ffabfa8c36a40a51664a72c3887e5f43763cae5e1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000466ffe30dff728f51b6441bac62ae70d7e454c8fa0a17e709637eca99ca365151560ab2f4869437f705e9bf3e2d3fd80000000000000000000000000000000001faa0247b6c248edfac0f5ed644d2cf04d572296f74f26ffa7171f8027bfe9e04a7ecbdf43cd7f5def400017729c5161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000549d6b517a824df976f77ec3f141a637403531c5ba87048860fff31ea9f148a2bf35d0b784348242fbafdc034abe1d2000000000000000000000000000000000a97f1c5ccf4f972a0be22a98e696d86e395431e63bf358b4913956e5c80242757dade0a881ba5147b62c00d26b266a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ad7a558af3eecd79d35ad3b4732e840c9250005e6e3381b7139a989a358ab8fb8eb1978e2208b06ac744f20e44624900000000000000000000000000000000020a52094ead196a3066dc9f2073e61c3742d68ac3524f36a056d334a99d9199b7b9c653252853b8eabb1d1b63a78be11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8e0dbcf575f4f3d2438a8cad4a3f8842dfc0f724e965105c68c79919fd00fd072c05be5beb746f9b2c415a09312fbd0000000000000000000000000000000008672784a8f9a247fc78a11bd9183cbf6f53196cd836cc785cd4944a921c4b3f8bdaaa579f004d5ae06689a9a9eb83251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010faa5bd353ac7d8d7760fb01783abc3c184c747a41d48808826ba3eba17e36956a4fae422d3de4e2bc5278d59a811a70000000000000000000000000000000008f7dd420c20dc0f1fd03b806217723f58c497cbcef94cfe8607ee2db2a154b748a7611e7013119626514c159d26bcd41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f20b02a8709b06246f9aeb4b440bdc62cf277f7da20a962eff9047fe09626d87456fd69a194c0f137680944197b8ea90000000000000000000000000000000010588e4765722c502ef2dde60c2aaadec00ab9d01cadfe2c384485fb16e3c6cae071b555bf1a2e03a60bb4055f84754d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000054f7c7bb1fd20435945897ec5c41f6606d5bde7f0696679327ef4bc813c7e2235ce9a291717c59f3cafbad3ea2b61e000000000000000000000000000000001245b4ae97be92d071cc112e136fdbd6bb686cdd62d2e8fb797b87fa5c9168c6ed49b03906d1c72c7f073888976c2c181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101ddfa4ebcc06050c0b2e3d6cf220c2c170ff474b9b6d844752bbd1e3d0660c361dd61025ce65d679d78510bde481ae000000000000000000000000000000001979fbecf4eefab0730f38548764bdb81efebade794a94f2620d952771e529048bffa392b4eee2469b566596df2f504b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea3b8c541a4e71551d38f558c304c93652058526353cb78559cc0360c75944e222e11d11165d1f46421d449b305909c000000000000000000000000000000000a6d16729cbe57b94dd84f8503b00e97d27c7318bd5e8c44f0a1d061f8fd83a44ceb5b74c50f5199d469de439ca07f2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000441c138400d85320df25d3bd4aa3577fabf1ef8ca33f6f961dcfdddde3c6f81ade3c0b93d39c4773f5eefa3a1789990000000000000000000000000000000009c637b4cfb300ebfe5ec2c5d8ba3670b5ce13a4ace2b5c5c1888b51c87ba092fd34ea37be80e86d8de7f8669e1653791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e8d7ab01e13cbb9a1e122d3672609e9c26601512b1a9e866ba7b7674aa0c090cadc8207a8db483b73da6d74af31f19000000000000000000000000000000001768bb77818c8e7b9762980e3135d5eb6cec5ff265838352475f109255fc9fe053d7534f1369ce2b1206761e7421446d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084c99e05522447d77726a67fd536efa9d1392d09d59bc5fcd0d7ac6a50153dc430aea09e17dd6e7fd27907449a09ecc000000000000000000000000000000000b6e80c5cc34427959487838223293e93c2f97cdac85f12071c6badb0b42221624e0357f01786d83f6c6b4dd8a57bd341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005dddecc56f797e579cee1f00e2513742d4c6d55f00017bf7ddbe37e2e7a52f58200d664f7c821315d40d015f7c06d20000000000000000000000000000000001b83f022f408138178b09c9435fda4b9ff269b22f600b54c572f49d5db7a35d4456c11dba7bcca41514fd331b3bcc051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000017a5d98586eba4ba185cff26b92ba6958dbb31436481ed2a42cd8a3eb2445064aaa96c7698d4fe480a5ff6e2292a2b550000000000000000000000000000000001c16f0114faff885a347386121f32e78e1b17d790e568eba75f487da6bd19e0fc172ef7d751e67dee7066f0d9c8bd0a", + "Name": "g1msm-23-jwasinger", + "Gas": 84456, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000a4738cc3156bb552f729ee495754d1c84fad3c00c42ec3bfd0a54be986cb5b23dfc7b4d502c5c7d661ab0960bb66980000000000000000000000000000000000234fd63c2ba4eb25e226795b29a48fa0ca92d8c40724c4c45fea039d0c13aa978754a97f3bcbfd9543112b821fe280a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011fdba950b878a595da471cdff22f8d80ab29992011a8ea25bcfd554fe6b809d28d328014c660d825db1f0863b446aa50000000000000000000000000000000001e4823bafdb73f006c7dd0b765eea8f81cac996ef004eb260e3cbedbacee9d6e8c8c64b366d0e94eec95ced4aadbe411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffa8689df9d14a11c72816983fbcecbcc480671365a7bb6f8006571f4671e777ca42631a671ab4586973e77fb0ce9dc00000000000000000000000000000000191fd2134edd82915a18e7f7804073c52f8d6ae95b6fe6299618e205306ebbf5d9e77805181d96294a7908bd72b5b5f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153a48bf28d40ba06ba0c754d355d616542153b46b383629e5c6993e40cf5b7f6068de7c4c0d0714ed35300200f614ca0000000000000000000000000000000017991aff5596a276252b61be8304a2930f5610c151fd588ad4a12f1e0d718a43d15d5f95ad20618c7092e61f440226ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014bd03750c8fc5ebc4c213b610e2b64da59843e2ad755611b0b3002792a225e7a9abba6037c0c3f878ed84f257c26520000000000000000000000000000000009c7a068c5a405fc6b13d8c70d6d3c426dce9e0518293fc003e74262839616b1054954c22f07b905901274d9de914dd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f6a270bbbc681b924b87c785f5f91db32d0a3261dd2b15db41e020ddcd1b92d3db3aa82d0c050bbd4c90b201b51239000000000000000000000000000000000141f9139c391fbb7f7286ab2a5497abb72f7eb661deb8f9807dbed4b2ada41840e5093c961722567beb2ab52809156b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d625feff25c35e5b1e7dd4b6670c8ab8e1935a781c492c177ecf91a079287a34025473ce7b1fdbcbe38cf7499af47a30000000000000000000000000000000019579322ff08f6e7fe8e4d7e041ebc1c1970ec7b4d132ecb7cc3fdbb5593fb783929b447892d7ea54e97fdc842f214cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b95cb4c25ae1584ad6599c41c5eaf876b070e5b4e63f237c564b993c57e836101fd53e6097f732c31b23bcf5073ddc0000000000000000000000000000000016fde7d3a596fdf26409506527bfae0597768426a47064d6924a05d6d2919a0c93fddf1c84b4027167d1cb07c5c7aacf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074373e9531023a5e7a7c5196affbd7ce392658f5bfb777491a48a1130cd16d2f12f6f57555ee682b2565115815ef0c0000000000000000000000000000000001342e7e3ee8d68f55d49108d150717cd8bffeede5854302f6e90af0a1e44c77320c8bcb2abb2045df1e96ec003b098ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000104888376cb8ebb14f1c801fd10381612ece16dfe2cee55988c56ba4a61e0fdedd6c61e59ccad70494a519e9f9d9a533000000000000000000000000000000000ce442c17ac2e16e4fffd181b8faa022381c07a4d22fce9b15b37e41b91765c89c7cb7a696cfc8653b29429267f699581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c9979238ec82876d78c90fef5d7a84c288baa11eeae00a60dd3829e0977f001f0f8708c8da4945fe06548cbac030aa000000000000000000000000000000001129ab96fe4f45a4e5b3a2b3c6ee0232eae5ceba74ebeae5c0fd4b16815806f1e581c7fbbbc6ee56353fd0c4873874bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003943baa286d9359fb89f03bb6c533f7f0d21818785c45fb34b11f6e606970025294b81319ef8a16a24558fc71c1fb4c0000000000000000000000000000000002f1f85a505537efa74ed629ccd6f3924043f1b287a4e657a1963cce358e3129f84fa4da19ed6dc2664297694428019a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166b30b28044eb0a55f9eabe957661b280a636d986873e9bd5c762e8410144da9e7ec05d523267a49c9ad72f9da044f6000000000000000000000000000000001013f1703b603277fd0d48bc3c08c1562d13ba0aaa1ac1f415998f2c46eb69528a4552559faca7cfe6f266b9ac2c5bf31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000064e00e52e0dd1b449245cdb0b1b536a3259b94860528d07f379900acc1015386e6c568a14768c071e40155b22739b290000000000000000000000000000000019135f89a51151dca8766e4e951dc2c163553073f640ff6e1ac7c859a764c3cfa02c731bda9167aa1b06280d945813591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f09862ebf7e8ca39eff96221c4d44f73d5c8e82bba5a43e1265fa0af5095e964797be9da569bc20f05b0d1ddb9e53300000000000000000000000000000000151b33bacefde5f34c1ca6270a4cedf95014a41c3e277becde7a94b0fb8e50e7c5af6bd3801e743d57ce682d480b94831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000103e42bdbdf1f56d007bca4e943f060d7309b334aee1f101c9a22c5e1b15c0e60eaa55fa57c7fbd8732998c0bdc10950000000000000000000000000000000002fce06ea3c574704457431124353b62cadf392c3a842bd329096afc8be9623e1c54a34f6ad29e6fb4b00a82278213f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003abbf94c4e00652e0a8eeb45cd4e96ff3b35e7df8f3f4f1213b474636965e537c3e523c380ac56d08b617ec27d69b8f0000000000000000000000000000000017389987dd424b20ed670a7f45506c9b0a283e133c9a84c070490539fd25d4a803452aa6ba8a434ac2742b1f7bcf850d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018786ff5bba07115a01cf0161fae631a6cc355e9e636b799b0150b72d6c0526b717af9efe17657070db9389939a3f3e10000000000000000000000000000000000d1c1bf3fa884f89eb36f2ca1a035c438d87d2188f6c843218db89cecef0dbdcea2dc07c0d1ec7c203d0fc9b9ceee2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001032147e2d14f8dce766db528dc6673545c2009d594e971d42f07c3d9b1401b00d558fd7e3be7c49a9a5ab02df5f8784000000000000000000000000000000000c3baddae6eb4e38c94f3679618f4748a7039f5ef1624c1d78d35628c7bbf8b14f50226598912d5eeb68fb98f15b84071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e459b72271310e5f8e9a42aace59b9aa8cb9d702c01182044e0cb8c2236c30e559acaa68138f09a767b28f5b90de6340000000000000000000000000000000001cc037db3b2ef8298ff3e29b1d9d556c4b3560d1fdde76a2e3aa2cc5e5bb0117a4c1dcf09ddc2f2f4ea794d6bda72971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018845b7230408de355c94d234107b11b635ad3e828997996303f5affc1a246a8865bd8e051bd1f453760236af55d7689000000000000000000000000000000000c61e009626cc3bc33b6857c49a32802748a196a572e6ac6d0ea015a64bcc269b1288bb5f12e614ab981362ab229fdfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f92b8da86be8935032601e475302729625810a789cc7840a9e29164c8d66df555a16b2a40947c42403d24333503ae700000000000000000000000000000000042c8ee47c4ca101a8b6d0d9b8928d853db5e3de885cfa48e39d8a2204751691dc32922f0b3bd14f5197f6e677a45b731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174800ed8fe830ef9e171c8bcfc0af5a3c3a93cd50678a62c318517359345e64cf436374732ed7d1cbc0bc005c84bab7000000000000000000000000000000001501da61cbd8779ff03eaa50fc83db7b7166d7f2185338fe91bb33606e279adfabb6595600854176fcb7a2951da5d7eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055e2d4098057e21d22f2279d7deff63cb14d73ca4099fe1511d3f9e714b62dfc1478a12798080df78f30586088df9cb00000000000000000000000000000000117e2de8668dc49d5a4cb01147cf5970687ee334d1368df17dbf99fad6d9fa331acbeb6be770641ebe4c1229cb5697641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000001d946f05084daa8a79841696400f81d374ea47bd4d4eb9f657bd3829e8ec3bf2f7c5507cf629cd323548965842a8bf100000000000000000000000000000000164412723364cfe2ea2cd8590d9d5628a0930f9941021a6251198b092a833825a97d26a68d1aba7778d4ca964911d42f", + "Name": "g1msm-24-jwasinger", + "Gas": 86976, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000000235d2408bfa4471db485cd1455cdde3e04827251c064bd4d94d5cedbcd78a245cb84d8ca2f371b0641cfb01025784f000000000000000000000000000000000c34920e6403885dea9afec556c72449f3f1097f23024a991bd3ce06ed598bdb1083b08b114b34980bc1a173ae6ba9141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031eb3fa83089ac3084ecaacb735f0b6c4713f0d231be19def1812c1e589fd44dd436b50a1f4d13f5843676f0da7879f000000000000000000000000000000000ca643ed43a8461dbde574b5d54b1e6fa0598509c44c7595a788f15f7ae2e94bc8eba7847bb6b9b594142d57032dc85b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056ad633b5c181526d4499c63b4b2c136896f5dfa0bce582be57cb0e85542d5a217a81c93b9d2bf930119618332207c90000000000000000000000000000000013aa0a2dbc6ef32489879197aff5918c422665e8a1d8ee3859078bc53252cc3207add13e9c1963ec0d197ae2203972c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194bc26b94cb769ce7635982023a42c2a320d5dd0ffd75de1d923f99c57f2f72e15220dbb1606e4c49dec53a738ab54500000000000000000000000000000000032242a58f4b6962b49078790f52deb75d3e71fc0a9133e5bcd4c3200ad62c3de67b3584c83860dec9232e2ef29248e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9eafdb7d3ffc72a3a38d0b41e7c35e3773636902d33b210ae6d27d08cb3d3869abc8ec2972f47bb2c7d602259205f200000000000000000000000000000000059b81a9c06364a4c55ad532131263784196201cc6d8e1518ff012f0568281d92fa1588636b4bf48d8bbaff7fb77b5291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082b9cf43c85e5986f363c13da78cd2cb9709dd45ce965467d717f9512eb0cb482cabc220a2d28760a7823f28f624ce5000000000000000000000000000000001687613e9b94fa39bb943c3b4d8d1b94b7ffd19a762fcbb974f3c987e821bb1f275f61bed5817b98dd745c18d5d9bf871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e182430f07126e309b18b1611a773e529ea24da52cf2d5577feb3789cedbe9e35ac6ebe045f34b0a571bcfa92125e0e0000000000000000000000000000000016c4502a44fde0de2a4135efeae38148bad8fe1b07ee6c5b83f5530c2ca4512543a650342c935910f1a852ad0f6058dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc9ecb239c30ab970cd8c616aaa66ab01f4e70dc32e239a4bb09fab9e8a9b1229148b658e2c0ddf3dc4ab7cc93f50630000000000000000000000000000000003b87365410062d007091bfca6df1528122afb1a1dc7fdcf25dc28a023b6cfc320aca7eae1eb0d8b9a05d51eeb3edaeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7b8bf43d4dd7cc4e415c8771a9ce73da1806f5c0edeac9c853a48a095d3fd0950585ed6869757ccd12bd6ce268bc65000000000000000000000000000000000dce832d95af32b79b941e8859ea5c418508613392849b8f5b327f1c645c66648a5b80637d2123c02bccb150d6d0fd381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e36c36ef164dc542d249e6a38f749c0ea3ae0a1a401cd8026be41e69f43eb14a74df55aaf5ff0e8994c25890a0beb900000000000000000000000000000000023eb730f755ad6728619093eea3eade4d6e263c41fd673c3a502e012637bffbf61041b6a38baaaf8f4fdd276954dd021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009eae87eef73beb3b94052a4567761b797ee6a2d9e6faaf0ca28aa50bc39f3b20671a70d6030cab34d86504ebce75f680000000000000000000000000000000004a92c32ad072ccd5ae26ecf5ff73813c9d7cc2888d40f70f31077775a0f547d140d8ce142e5164c5763e9095e9a0c501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185b76dcf2c4a0190d40dcccb5b8b2d549afee8d0950a33a7b234342e62e1da6bcab0eb5d6383437bdf329367e74f6a400000000000000000000000000000000139f9971b5bfb7aa7a0f0e1913fef4c338599161ca04a2da4a12a1e26f068958081def6b612c58e2306c08f8efdb50b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043d5e7aa03c735e6d81cc70ce636431fb79414ba924dcdae39f71a432507a06ccaf36eb4c8fe868a8d3453c3cf2cf4b000000000000000000000000000000000e261facf6200a1043444c32c2d207eea995e88f4dfc0a8a4ca4a57701bf858f9e938d17705b1016b8976869885410ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000854e02008b6fd4a78fcb704c3c475790e2daf7e4aee6e92e6227efd84123760d7ee01d1992b638392ecc41e8efe5e0b000000000000000000000000000000000e5d6bf1b1c2bfab353273d2ceecee4f8e76bb7f038ba25a142b2cf51f653244154f01f1f684aa04536c6d932bb9f0951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f293d464c06742d0ca894275919e1e30be57d39101fae62ef357fc73d5f11b2e5519bb9ebd51d39594164386b7d951900000000000000000000000000000000188dbf2b794da389421832ab76369c0378943247ba4a6dadffcaf073cf11ab45ac877782d4ccd2a15cf6f4acce0372231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a6c1bab7dc8089f0a62581294bf729808d231d3171be45939e96415c61b3df7216e6fa4be5f59fa080f888ffcc679f000000000000000000000000000000001367797b3a81c3f9db9dfb582f15b5a8a710a8ea6fbc6549247fdc386025b95742e23ce942633974ac18fab6de138de81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c31a3bc57625598543c49fc846e5ed4b53ed157ad54f1a114519cabeb797550b7e65711ca5d4bea70050ea70e73290000000000000000000000000000000001693cbba09fd3eb5f1ae522e8f67c99acc4d01a963dcf7653002e9591a3bfe9a59d14a9cf9f56af1b2a4b3ab2444adfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120c49e3d2f222ddc28d33c2859c010a33eddd18ad400666c35005ef2fdd4732c27ef0d5fd4f0223254f09f58197401e0000000000000000000000000000000007d1c9c088c987c90a6a63ccbbf73580a8cc92bf372b38448706270a64fe43e8fb904a489f535678931ad71bc4835bcd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041298fdfa4b33615bfaeb8578cba891cec83ccdf1ac30b3dc66616e9d3b22472a72d7712f0ec92b52308bbba9b5350800000000000000000000000000000000130ee8e36bcbbab76692a295e2f9f308b24c04b2cf73bdd8cdcb3d619965a02fca118a6a6cc1c25747f1b0ba336c776d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf9291061ebe11a69f275a5991efe9e508c4dc78652e0e4842ab1e4458f6af284eecbe4967c405078f8236292ff0a800000000000000000000000000000000000a5254fcb787af85ea1547f5e10d6e38c5ef81745c5ff3053eced33b4452338d2fed8619fd39c2255dea2bce7ed68a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f5c027704bc592e57f80341f158f72485cc1662d6eb923ee88f533e96eeea1ff482a73e1f9d02ac6a70ebc545c41480000000000000000000000000000000012b00941f661621f3e432b5937ad19ddf53e57673bfb97a22d33fcae2c1897a9191145e09fcf1599ce92d167a1eedbf81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000862c3d342f3334f4d3861d0f9c225e3580726143db68d219d053bebdeb29014e7cb9aa97c20f50e30829ca4cc2da6c30000000000000000000000000000000007527aca2f0191f57127fe5cbfc8186a82fd3f035fbbaa6874a7086378fc273b81bfa74b448f4298f58e776412d32ffd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b26caab542048631860b7e709505250a9a6703920b278ebb0c142923cb9c6bc6916927821a1821bfac621bdc8cf35c000000000000000000000000000000001241e26cf089857f566b81e5d4b2f51f5da37cfcbe83b3e18bd59a20cacf5b5ca751556bea36cdc7907eba9148f48bcc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fb55f2c57de44ed007d562608368b189ae0828889203c61f233cb34cd39f498417524919907ff416d8ffa13dfaef15000000000000000000000000000000000ba15c6748340796689f986c1cc2667b084d18c271c3b8b1b6f876f52c0164d36e7eb221af8696c79e5f1501a23b6f0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4603c72e1e939f5b45b97a90ebd563c8f4c46bcb81d4e2453581eb0a2689711f1b1f6cb3971407787e1041812fe3a300000000000000000000000000000000155c6b5951ee061964593c14db0a11a1788b1bde3554bb818417f3e043e29276c542c21154872062628dd845b5e0efc81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000dfd568de7d285f8f6f3ccde0d341833d17e147a8d31349b585dc5ec885d5b4dafe10a530605b07c70f5b3a835592c270000000000000000000000000000000003d34d6b194088fefdaf30ea38a64e606336cad4fdbc3da49982ce5965c3cca0b4b5e5be05f144a819c04a9c064f34f2", + "Name": "g1msm-25-jwasinger", + "Gas": 89400, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000ce9753302dfba17e3a5e4e5e565051db2f842aa61142ac238c420a8592da4f0222b96a6aeb64eb277fb33f296aaaf0400000000000000000000000000000000007b543abc90ee8ba44c789a9746c6617b40c680b94655e3dde5d47092f2b094d77f446dd19ef721145f96ec851b21371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000839fd424c87a71b33c34f86abb6ba1473781919d9cd9f834e1d4dfe66bc9c31366c235e8c3284a565c29f1fe7c293240000000000000000000000000000000006621867beff4c6d93a8f1339e26c5c376fde186395f8369d3b891b03db5890b3d51f0a8f9a79456c81551e2b58027671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114691463c74f51dfc471dae3f0238a5acf3456041504834d8067a1d15931fe3a5dd2a57dc7679ffe9960fdb6257549d0000000000000000000000000000000005565cbba6925b650ed20a68601078246761e5ce98a27485a03187ee5eb520d2fc2e209c4b71cced73bc006069b42c221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000953e39807f846b1aff5da72d74e8cc979ec6636bd36eeb660759e363f160cd4ddd0f4fdb92f52cc14dd981b5fad09010000000000000000000000000000000001a9a88166a9a18cd215aeb2cd0aaf8442cd7113943bb1b6a79682cac5e2f3b1944e397300e3ddcbbca66f305a5138a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db7f955da72db06382dec5845ca0eda17d403489242cdec8865c6c00d7690b08c25f7dfe76b312e439a01ad3d36679b000000000000000000000000000000000d1341742c79e98a5e70e9c8955d5dc42147e3a88c5519d8671772589151ca669a7ee7f2a22f8a185e13875c23a3ba841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b42f6b3c01b08b48b4b1efa9de673b37c2ce3a79ff77cb8e170455481fa7ab15357b268c9650107b02cc7ddb135e6200000000000000000000000000000000019b49ba5762e50262b8ac78c171795ea2c3786dc804a83c8a316202bbb4e5704a8b1bf36fd4ad0054d15994d1caa98aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a44b1bbadee3913218bd983343cf6e206ffa2227b9b93057ea1ebbf4163bf2df148ec688ba124f59a046738712a6b090000000000000000000000000000000005fa672348e03f87fda45d637da4c4d62ed8790d8ee8f56cbd19b8ffb404c9f66d9777d9aa85ed20656720ffbce8dead1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067e195950b5267a0b6c43f51e7ad66676d489e0760f6ffa7ea92156142d63a41edabe8e64787ce4b064ffb11b7bf1bd0000000000000000000000000000000000bd92e95dcc7b62f4eea980324d49fd200003d6433562fd2434a7bd42b5d34c0a731d34cdc80b332311f26461b5005b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001393da3e85fc1e50d8f1f9424de7290b868ecb5b23fa96b543400bd13e172f76f74e107497a93a2ede02493f22254087000000000000000000000000000000001049d8b1d9c88d7a6d97721ccc3060790f1994e43006f1469fd73858e592f31cde817457d68ff9af489e319fecbbf9221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbb2431e80606a506ab625bb598d27d494b3f144638374d416b43ef6af8de9548282bd0a0ad83d5dd707fcc156133eb00000000000000000000000000000000158235a7cf71509cf435cddf76d1a7541fd1c072f9183499f0cc200d971c46c9dc4c3bf4d6071436719e70db726f1b471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028d7287529c7fff128cab1bac5fea6e269ede300c70c651eae2cfdb9285092a4479421edf59d80577224c6958a43a0f0000000000000000000000000000000017cf2ef1ba9830ee8b0baee5defef6ba289d4863979cc956c102cc91f7f1c889c6ecd0b8cb69e997b983ce1d1e3fd4b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000096190d31a3bf0aa4f5b0acca903945a8597e39c2e8e5f28e1a86cb9c638c88983ca185ffbfad0a1925af1e581e438cd000000000000000000000000000000001298b5bee0a84caf01386182a7ebc1ce9db8c2edf9271d9c899ee54d6e5c3cdd91d7fa93339d40a1dae99231794968791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f40667791e7e3593edcf82de9b29e0690ad31c6144aa3816f9a30dd058a61686d83979488878559457cbee07f6e330000000000000000000000000000000000e03fa2472b2c17c877c62bf209b4598104e70c8ff8db809d40a8d65167acc51ca18958ae5ba83cdc39bd4404d56a4b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000956235f7c535a19d589c7726a8eaab9cfd1e8fc5b4f1f783dc67586c6d5ff688c1a3a57dd8133456549b26e62ca74ac0000000000000000000000000000000015f03253d3e4ca1fd914717bcc1951ca28e98a443e0dd162ba3ef7b6d592174227f143776eebdc58ad4e89caa0812b901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e0bd18feb68d0dc33baa0836d9e0503029178b9a757426053523d60b14147985cd9f9d1d3001204150aed625ce63f70000000000000000000000000000000011248797b806a8788446b96dc28514b0f62e5e72e15b889731d1f4a17c2b8a794e64fe98c2a520fc2f7ac0bea03c9ae81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd0278d4e2f05b3b78c3e75cafeda397102630024c97ce0911932b9146d520607f86ce244bad27af14255e0e4146388000000000000000000000000000000000ee07762fdd5797949eb778176fb986e3250a337d46e78394cbf944aa6104e8a7761b5d1b6c461fb1a8deeb73c4a04881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f776e23a46411ec0e8a8a8a15272e283568a389c1e385652b915754d385c38dad7435ae206b641d25d2228765cb1689000000000000000000000000000000000f6c05da2396a75aae5a121870ca31ab26807317888fcc92d8b3582a596bac19efdab82d03248144e7cb1ff22451ff8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000559a5cec51b8fddf3d9ab751a18d2302acbb2c8071a293416c36e7bc65db6e4dc2da898d48d0551676e068ec2c966dd0000000000000000000000000000000019917b3b69815984664f40f4442fe327c630a5809e68362d20a555c086a06001775e4550bfb9601be4f451e4490c8dd91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001744f7cc4c51c0660db599c584e63f26603d3ac18e789fb8d7e877d47a78d021db04620cfa51baf14e9ffbb1dd35258c000000000000000000000000000000000b0177b67edfc6814805cd51e4b0dbe65e493d5a2ae74f64346c2b5c2b20723497924d8676c927084678fc9fb5f512be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000598b2e5bd540fc6f7fd37140308e3c8e8a20a4ba872e1a12ca156ffec661f46f10378bb68b77f1b050dc08a35aeac55000000000000000000000000000000000e04d91672b1684c2581d249e3e9ed16335403103a9afd4e87c1acbd5919d630352e591e905b4b85deb3e999368e0cfc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d0e8f69685726e0394c17e79e6070e13d4ac1c84951965f93f6adaaa24d7750efddf5f9b5eccf2afba07b658e1a2fb00000000000000000000000000000000082213946c007b425169cdc7357188157807996c2050cf9c29f2f4e036fe5ecc06102deaf170a59cb13eac96238282941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193691ed496b5b20c3c3cff87edbe09fa34ae312462b0a516cd44568d89d9e4a75d8534e24eb39d489a3188f5caa9d4e00000000000000000000000000000000077b0e6645a6f16391df529ec4a06c26c752deb2445ce7b96bd379063285ff3a0adc7b4becd1c39cd2fdbb739f2074ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008984c29d334e3dcd9d8ba70037ed1d7320747977f564c530773cc76d234d915cd7e40bb5eff489c1f00b2ae49b20ccb000000000000000000000000000000000ce49b8d792706461deed4d79dab50442c5367447cb46ef71fac590beda2898051a05deed8c5225a40001656fb94f1911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c492fa47c395e8b4a39a994c6fe56c7a31e0ba8e10682cffb9d814f17f2a0cd176e048d67d69bb29f6726a9951d1b5000000000000000000000000000000001770a1d263499d3324b522c195d2556f4e9f1c9537f55793d986d9f797bb4a53de66a8939b8c155e13d51f12caa1512d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f6f24e6b2fa011e22e39c8be19e98985a34e4949af5682ab16058b509d9365678c0af4d72ba7adbfff44c84ef79f680000000000000000000000000000000009836ad460387009597a8f843eb9f392e0488a759801db6ad230fcac6d641f9a53779bb2ff9cf20b9743638af501f5881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177d2e51294e9f9ee2061410008c607f408f59b8e48136af8947049d27b30dac84113f72fb2e5f675d5515da960d69720000000000000000000000000000000006e11feb4c3b75f69583c40a5870bab583235888797cd9fbc76bc96d95f2f23f41f25cb68fa985578720f309e19015851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000012998698282eca2a640581744f287effa3e7d8c7a4938371d2d5b85a6b8c6b20963f1d6d8afe9fb413e8bf069522e0df0000000000000000000000000000000005f61450c346340f4534e4c777cde8dbcec7875376e0d7f95da8fc8e840c42d2d4828fbc1e7dbd657d9eefd3164c3a29", + "Name": "g1msm-26-jwasinger", + "Gas": 91728, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000014e55c63149315d5a956d037024beabec83b3b4f7ffefaff95653f9b46281197972bbed6ccd8d58821ae361f86e45df80000000000000000000000000000000001cb2ec6054b8eafa49f129d09a9e465c93517232878f250552ba561dd6fffc6c04fb4db2e478eda5b3db4029a827f3c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001aa1998a2a4e125b364d96b8ba33328cfa394e99dab85bf94c2acf6fe7c6b9f5731e7e38d5beff058b8b8b8bc7745170000000000000000000000000000000004a2199fc3ebddac9581f3e8a0254f79232b377930459a6dabb4026143776af603bc0078b471c80ac2f9f58402df5e6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c953410c9a9827dc3b388be812413141b8ca8a2fa3bf11570ed0d29de92f71dd36a003d5743365f8c7a82a2f37be2600000000000000000000000000000000114bdf4178449da4b68ba3febfa5f9b94d6c34b542adce263402af54d7656e18c4b20f60cecf9ba5fcc35c71c68eb7dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085185e582bd53f72627be579e19f1e94f07f7bd07989ad2ccb4cbaa9552b8bf9730924d0aa143fadb3f8050c03a882300000000000000000000000000000000015fe1c9a31c606898edca9bfb91be69e97d3058918a4332429faf1d3411d40705db123b42620af654d75430ebc89b0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116295fccba781b9e5706293ba518fc7b404d3e1b7b3c33132ca92093590674f2c7e2c1dbae6247c16d18c1c29244cbf000000000000000000000000000000001812649f872b9fca969653d24a441f9f928f67b460db9150c18f9f2912e56a1fee4ec542b8f4999e9e0f5a13a5e06fbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002da11bb0a7c2c4c3ad3e515708957352c8c59b0183ac23db8309a861e3eb4ac760591400d869bd5f86ea98832efe39c0000000000000000000000000000000013ec0ed116282892727388958054a4e61b5877fbb05b38999acb824ffa368988bab987d3d2a7a96de0c4654047b984c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6ab795330e0978856ae7f80ad8260b51de25d379071b80758f12d96e514852e6dc5510133f1e716cffeb0d3ef969250000000000000000000000000000000015b9f40759535222ba456c98cc2b52e44b81f63a235220a60fad66e23a19c3df9fdff8aa009c1d4ef6b7600eca65a7351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000277fb70bcfc2579bf87d49d16cfdbc47270629b43e24f052b48637b412e023ea2edaa28f27314038f5cc36bc4b524a90000000000000000000000000000000001a82d0f81e055210e5411c9e8fa38858d8f13787eaeb6cea4d721ef873ab9a65723d2d48bcdb8d3f4e800e4b97b25ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076fd54045e1caa89b6a097ede403e4638109770b6d414008655ab42603fc7d0ae2b61db284cce39af9dbbd0e5b310080000000000000000000000000000000000d5e7740dfcfda6717eb4174073306e2c67c31c12baca5a49c492f26f04ecbcdc03f4cdc3f62f5e62161c735c9fefd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015026ee438cc215e6c1729580030e347baa5f29871e7c60eaa15da9924cca26513565bbc15ab7caff3ecf03b0e586384000000000000000000000000000000000c4f82be20ea6c14998f1e82e84559688e6c69a154b0de775210e68dd94467179f9ea6e8f79a13565170ee75edae188e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016e74435b7fd76f82aa66bab892f26464fd524ea6c93c91557a5e975b2c235510d3e62d11f0d91e60aee656a3296141000000000000000000000000000000000ea9d99e3046b1b88ac6a670eed9ce8e79106acbf4e159cfb0684bb9465c7a878a8309d3e4320848dfe0daf6677617291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078ae2283d795e04ca54fd087f128768e4b5eb602d0daf3810711db89136679e20653e21fcd96a8c275c9b65bf18f495000000000000000000000000000000000488dec1c26d2f825173c6af1b8eaed3b8c1e9e3d819caf93f5baf3f1c891dd9343575a0c039e3be63776bd9ab5829271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012bc97ee113d2a93fe47d7e99212eb4ca5733b993686601ebe9145ddf8c489dfa89f97a52ac02cb9c093827e759c268800000000000000000000000000000000071ce743eed2f579223db24ed5acbe90bddca3c34482545a9c93e918f102a1834e28e959a04f502a910adbd971bc9ea81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041ffb10b221a22d846410172c82bff81c3912daaf1662e450b519667c0ed93a48b3e628b251e1a389dc2f73006d6faa00000000000000000000000000000000157778106e5fb1c2335801706f376ae85258839b944d660905722bf082e4554ebea7d06494cbcb3f8963e7172b69d3031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010e8d67c3ea9f7bb788c64ff6226b25e3793b44dbe9ebe303e40aa7d66ab842063de1b3dbbc9cedb80b47a08d936f32000000000000000000000000000000000c69123f3e892e39a2afbb86c351447483a1eedd67c5489748b6eb09893fdffb4ded1e9baec8621e62a75b4bd04b3f7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000776d01a68cb383f2bd5b3f73eb7a93da71719980d71c7c9186fc7f5faef395b2d41914d4304a6e522091ea718d3ef3d0000000000000000000000000000000013f3cdc96e12edd8ee64ddc66d846f31637bce17bb057514d9b85d141691ac70e8b2a8e3d725a860d9b67b61734a22d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001280fe93f0a9f901e65b6ad9d345ee799a57f296fdc5b27e861639261528fd5fd737a4e30123d9d46183ed0f49e1881b00000000000000000000000000000000018380f83084be1fcf4bd2a40bed840eb8bbab67dd5508e287bc748652a7fbef1705fe709851ec99742ee07bf6cb6f8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058368b427fc6258d57dc25e1cd004ca96e6d1f05e5377a124c7dd5ef07c4750fb1c47a387bc0b4d785952e150269ae800000000000000000000000000000000185304474b1784ef2d0d38e2825849beda13622b2fec16af6a9aea24ed1344810c00762a44be4dc633ad6ae909caa7751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f05de898077e64f93e001080c93d8a753a487724abf52247ac1fe02167293ba0f775f3935c1a4a6868b5f46f69bfb590000000000000000000000000000000009a9d5285526a730f1f14ab85d00cb7c7e78e48b4cc9c247df7612ee238cd7b42ddcb9dd8031c323d9f0c49df0595e5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013654d71309be0b5951d08f8be4b5acf3ce5ab3fd0dc635854f9c919cb7286a9e759d2a52835418b589ceddc6b96583a000000000000000000000000000000000b73df0edcea1f78edbc928b27b34c653aeae8cbc501b3b6001df0a23021b412d6d9f95fa6c56cc5660330e408d5ca7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ce08017ea4e317ad617c9c8c43ec5924e92370aa87db41cce342d351d7b2b67ba16e95793dc293e8ecca1c5a0495f900000000000000000000000000000000023efa50d15316145430a4a7bc87077b79d7a0d4488cf7d4c98bacd7df8565afc00f59f21f67b7cd4e3d4f3df620188d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154307f8674a8bdc2ecc157289270aa431a72f6e2ee1ac83311e4bc2a658350cded79aaca4ea3504a26967a9f296bc460000000000000000000000000000000006a67b4c943607c1dff1b2254ba19c003923314bb7a7e7914034df82daf6e625465411493c56d672e47b55dd6fa3671c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c0a67df6d93799dda1c55f1f1235f1f831b04d69532d6262941beb59e7ea7159d6718a1fd321a953f7bb61f7fd290300000000000000000000000000000000147990a10106a46d3fff1c84987942b4ad845584ecaf0b53512c03f3ef35252d09ecb86e9729c6cc96c9e06e485512141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e894a52fe2e5ada9c9f0355108ec21295bf5ef12e663a199b47d2ed2dc92f25e6a4eb88d0bddcfc7a71f8194e2585720000000000000000000000000000000000cf3a3810b2fad1ba1b9418c92ee99e4f1255674482d76283f07701396cba3a7b21878f687f6374ccf1aa98b4e9184d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba37f285113fafc68a8df3a66b7737e96cbf821559ae1c836ee756b378b77076d76ccb20b3a7c5b5d8720ba496de44b0000000000000000000000000000000004b78e8aec32fbfef577b8bffcd4fab3c3e67f9e054243dbfd5a41ec85c3164d065b482156529ef485120b39ae61a43c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9ec96cd3468c18a6aa7bdde2210c7a05b7199c2f25541349d3fb0a1310a0a61263dd5866c50dc4a77482b9473e4f17000000000000000000000000000000000989801b9af10f39fc6b93831048a936bdb7ba863623ea3058cd63a987d12c000ccc20a6ef661818979b9f31c17deac91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018738ecda79624ceb3be685314edaf3b71dfb43227a33dfd4de2c25a7a59750f05222f360d62d4026698be90bd147919000000000000000000000000000000000188c1d2b8e2e67a368bf31b099549f1fd0ece36cf6d5b384bafec94d78fd1f76937ae0edce19b6180c6994f0ccbef9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000142d164fad514c6a9c1eacb3cf1fcdfb03a0c47d06d9353c445b0017338a4e698c1f05fa4050e21e1ca2c154f237cf670000000000000000000000000000000012896d9f1d7a82231f5f220b7cddd7ce926f4aca902d0e95730c74600eca2cf48a328994801a70affdc307029d3f97e5", + "Name": "g1msm-27-jwasinger", + "Gas": 93636, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000b671b6fa1ffef32bc8e4a6d9167eed86bd7de3a83047f8cbda24a60c3f0c89d4d494fa663f3d38292d0d01eb7bbaf450000000000000000000000000000000017cdf30da17cce561475a279d0e02ef333b2964dbc55ac66e7597224c1492b0980f4ef28edf87e2bf2917f62f68fda2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1aa624e925b519767a8bb9bad32fc53a69c7ea706d38a52160ffe422333adbdc6730ce72ed1c54a3a442b59d6ded5a000000000000000000000000000000000fa19e5e45e741056ba3e9f5e902b817c11000469d007bdc5639cee966fbd2b399600fe17bbfb38fb63b0c8a5a9693781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa1d92df06ff59d895fe7c3cdb9ea8efa05ed5f4f27251d25ebf5ac6117c1bdabec5670002f7b0c5ecc526b879d254800000000000000000000000000000000119c68fc18fdf89e2c64937ec8e450db95ef15f7301063b7f32b200d43ea44d654eb71433f80b9d6ca032c126f5aa0171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd4d1adfbab369c4c24d74dfb634283b6a90c2c7fae7143dad5176ad0a5bb722c3f1ff6fedb10555cacb23614ad43e800000000000000000000000000000000099ae14e33d2f94bfa1f647ee91d28548116e1e606fa75bc3133c3cf8c2a0e5f7b8231ff4b8246d169732e226df370cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001650df56e0d3ec45fe1dddcb69b0a9552ef6a3ee4f1cbbf3a2ef6da8bf688a7612260008691f72f0583ce6d2138dea510000000000000000000000000000000018a88b162afd631195c1e50b09a76615b4970cb4635e3d0c79f1c83f8a2fe1cd59975d0641baaae7d908d5dc445f7b1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001114eddedc8a3dfe331b348942a1dbf2f0b739067bb4665f21a0ba159815f742b0a9c3b81df27b2a033a914924c121e100000000000000000000000000000000118fd3e50660c5fd6660d28366e4d06372e4e59351fef1748f8ae1e1ae0215f026aed79f94f84b8130ec55fae14e9fc81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139ac987f6255baa1834ef0b7fe702b2929069ffdd70b222cf25427feaa38860aac072345ddc573bb06670478209e8f5000000000000000000000000000000000347a5d0cb6026304f3b6f87d7435fee667c18bc45c93fddf6dcd364bf6b9582a19e6735f60545a57cdb9f7c7def30931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ceb5f626d2360525a960130191a446b071d9d52c27c9756e359ad427c4a3b2369b7fe72de157f2b1a5857ab9a778d3000000000000000000000000000000000216c57834aa41f7e28afff828823e79687cf975634f1e8ebe173c88ed88d94855d8ad987d4701c05069db15003d163c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c6740f73ff431829d7642ada1c6afb4615d26992ee192021723fcb34a7772cd0149ad876b1b755717285f803da8163000000000000000000000000000000000cd1bebbb1cd783d88c6aaa668e7226a3cd83142e2e02032bf91e60c66c9a1ada4356c660fa2e9f9e7e33d481895979e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d032d6a1d26863f7db9ed24e13c3560d15702a8d94fb2c72aea81ad3f7a030c10fdb1940d1fc9b1340ce7c57e61c2e000000000000000000000000000000000145a0fb5f3d605daeff25979a6e14b5585ad3fe23e9f355ff06a15e5ac376d4c936090666c968ed5779fb8f60ea84c2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c60c8e2be4bb31c10c464183b1acfdb935d63b4130a407df2e812797161092f1e2fb6f9a1b6430fb3c682ed609df14000000000000000000000000000000000ebf559e9aa921ad6b57cd1cd6a42a424fa8060f8c6a1329784f6e61f458c6dd8ebd89fc3fbb405c458877fa30fdb0a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043cfaf034d9911fe9f93dae1bb114b067d03463e535e44d1ca3f19bbb5d68fc03b31f8bb860135387e368f093cea6d90000000000000000000000000000000006074494ce722cb508b4fc234a4e2e666bed50c2232284d52a111c6443060e386e5fdf2de637b7af47f5689c4d6cb5f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae7299f95b9fac7a4591f6c72e2d4540671bee843dc603c2f22bddb40704207d3385df1e84e3b16257aa2d7f1385337000000000000000000000000000000000c9f9041058a91edbbc5954a4cd45e4a8428d2dac4f98d78dc569f7cdf34afe6040682e8836684cd54a16bf3c766466d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff5ba8b9486cc75c51856937895485117aabb33d5764a6dd7b0b5d20707f5c118294d937821094c6f0e90c829e93bd300000000000000000000000000000000165d7827869ce6c1c126a14630d2a19c086f04bae51d2308b9da21de83fd7a16e48c023eb379ca2fb95deea59a8ada921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010238de68aed30e74b5cd1d97bdbd38758aa7b5e35a3f9453a06c9f499ca403b03ab0b06548d090ad59a9af89855eca9000000000000000000000000000000000df9288cc4de7fff60bada1582bbc66023ac149cf4c540211ca568d6e495aded85340f18eed6f6767f219e5057ffd5921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cbdc98bccb1f34cebfb31560dd17622c3e61531d53fdc2b93902b7ccbfb6509b28edea43d92835e6ed233979cf5996000000000000000000000000000000000ae6dcfe1a032ca82fe93cc363aac9dff13f08d8336603fb7e908f9ecfae6748a51db4d34e3fb9ead827e8c0a9d7ffa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030651dc35e5ea6553b365e0746aaf7e6b5fdf8d2ddae4eaf0b6ad3d6a79f2ddc6e87e63ee10afcbb404eedaa41cbc720000000000000000000000000000000005a791c706130587a5340b53a5fb8031daed1d7ae980a13843d9bf7f6ac847c62539469e6e079a30cd661ddf43cc29141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8064e76148d1b44438a42afbf4d8f7c0b1edf9aaee022ab2291871641e67fe679645c86bac99b769b0d6a7884753b200000000000000000000000000000000160246a845870954ce70e3d17aba4cdb0b532f8c495d86a416f9c2e600fe5e8fca27c1fccd00343f663c87b2aab78b2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f141e47cad23053f311da6cb7734bce848f9e89fa271f319376114b3a6b74c982bf3250edf2b22d1cd2f99d53d1ec300000000000000000000000000000000193a5ee66dc0b1598c0579c49c77c1c3ac99a1441e9891cd9594834866b08949e4ff8fce08825a793a6239a06a3c8ff41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b923ddb92a060b1dfcae175fdb915e401a91fa8a5cfefd4ad850c1cb505a025d82e342e12f01679baab3b2ff540da00000000000000000000000000000000001019ef43bec2f4c10d8e13cb6144492bbc4e90ce6ced3baba48fb0d127f69c32035ffc44ecd096cb9d2cdc51d6943cb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3b6b90ef6b71e7dbb152f874f2626e1732cfe4f89d1ffd66f254a19145e5dacc822950930dc62f4cd1a6c2c0afc0c60000000000000000000000000000000018a6dbf2620aaebdf0fa34869ef0d3dc77ee2ca2a28b4ac3ac8ff7a5d69f451fdb6bb0af67095777c39794df5693bc0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a97c90bfafee64bdfa42c46db15c222ee4efc2f2f4e3e4b3a156586df14cf088b442136a41df42b2c2a275626fa7b7f0000000000000000000000000000000013d11eefedd5859a95a8ab5e867253b55ca4e62bb24057fbcaa8f49ae1af9b46cd03a43f734a6b07eee531ad39c817281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019744d870276c2eb01b37c57fdc16d0ac3a887c7fb6607e8439d4d878aa20cc7767e4ef9ced4366bea6b10995231cf5b00000000000000000000000000000000175236f548eed1dbf17ddf14570f517a78502ca360c21c2e274baafe806f15de0126c5e4491ccaf1071e4f57dca1ecf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000113bc3f047153acac2eb9296c68eba801615f4bc68d1f4a031c43c827debc35fda79ed329e2c763e0c4f635fbcbe4250000000000000000000000000000000000119a6fa45488f6bd10771ae34b32a35239eaea4031d3728e97b308f1ba119634bdcf1f5a2763f44d179773f6d537be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8e207d65893e94e607181eeed4fc6a5ba830af32e42749eea44e44660fe9136bfb6e27a2d27a75b4002fd96279c374000000000000000000000000000000001253c67e4afe1966c6bb4c0e2c841094d9eac8927650bdb00c8022221f6aeb1d8ef5a4cab294b7f282b7b5955fee95061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000981f51694e12c93146fa131586d647599f9d27f25e6aa32d49396e1aac39b567675254f0ae2444acd6c8645d777e09300000000000000000000000000000000071bca4f2a1cf2684eabef0135d99cc565b5617b46267f943a3f7b8824b7daf5a4ce060730a85a4e07a2436282de9b921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd0877be99bce859fb6af140297be415f8b0f38721f334372123becb4f236a53cf87ae39d6b3efa8e6446a6df7cbf9b00000000000000000000000000000000031cd6cc001854a3dc70afb8cd459a7d18861e1884c15637047eed07d3b2f06c17edd27ebca6e046340981aed8021e241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d19bd27df46dd6806593ce829fc39e158b2508d86dd3c2f29a78ddf091dac53c525e00be9fcf81b5718e63f98d0ac4000000000000000000000000000000001674ae0d75fcadbb00bfc456ca00cd7520be271ca112e8597eddcbe9a140c7c5a2f26eeafa9ac84a06a06056335dbed21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000013037f535e801db713c6f08138babd1eb66cefdd9166398cc812af8a5141fe8948a9f7fde4f5c6fc1db3a21f7f51431400000000000000000000000000000000099abeb171ed76775e3316aee3fb60f1b2ceb285a4527eac7c05ab250ca461b7a694b4cb08ae119bca13b213331fae56", + "Name": "g1msm-28-jwasinger", + "Gas": 95760, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000009deaa7bddeda215550f788814fca12048d24493f66c1d261dbbdedb7d1bd4a1e2a7583b7ad301dfc4aec26bd192a46b0000000000000000000000000000000003be9888062363d820bdfb497cb4ddf78b1e9e4224121caae5642d094a8aa578002152f369c3327f286610f62dcf9f2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159fddf9515762e6d689cd76266ea3d5c6303770b9f0ecd71a0a6319e3e17d509eef8ca7f4e948fa2040eae62fb7e83e000000000000000000000000000000000b2319cfad5d7002c083a99ee1c3fdd7094740831338296d3f6847861664636c390f293f655b6b1463c3dbe664901cea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e227e03891b9c5a0ec10b75c60b03dbf766287205a75d2d22f0b22a0a7dc7478d7530f61202cfda49186e36ec247de700000000000000000000000000000000194b9cc68bae6984c52f02e946f110b2d0316e1f298ebc96a53f8b7b2e3e06cf9e1ef518ee5bd46b64e689228e6725131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e8fb17b172b7db9854fa58ead9b58f62ad838bb903512131710cc4fc946f878186eb01bfa3021fc8e716a0d2adc8d20000000000000000000000000000000002a2ef05362b53461d16bd2176922514c7a50c076b6427414565a8b41bf1d83d5998df3c3d7cd7d8d1cd6054ab2e6eb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170092351854368a668c0e11b768755359fec6c197bc48aaaea04f55c2c5413ff3be56582461d4fd1b3e07a5b776b667000000000000000000000000000000000f71931700a45db435c1f9566699981eb1840d569a72887539375f9f32bee8c4d00221d9cf52ce8a40a83d421bafc7d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134d46c376536b5192c36eb24c742e473ebd7690c1153a3d0ef6c1af4b727c2bbd99e3b96fc9bbd9684e7b9037155722000000000000000000000000000000000e6d7f8f63f46f54f28016436b068e4db6145ff45d42c703449223d6a1f6e0ebf40e635631d0ad9f1e9e030fdc7759971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175ba1080101e04501bb4e79024ed203093691ea50a5c2553eae7a3f4a7164844af0b31a60840aa327bed5f98379bd120000000000000000000000000000000003eab303c85225e60655539b73e494b144787c03ea10bedbd919071ed4b32a308a9634393a0db1f6500d16dc25d482901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127fb8e7f0e171fbabbf13f2512cb8656481480aa5a379d5d84f756561714e3de305dbdac5417bd50c183325648a776700000000000000000000000000000000046be9ec841d1f62c3e0ee1d380caa42741197d280867e871ec37403cf962077dfd981091b5c67b97666af7bad119b681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f69eab5b387de9a58d76043ef789fbc1a876480294b56f4d377b122ec12d09b3fbb3aeb929d6d3c071aecc9057ffa6f0000000000000000000000000000000000c2c8ba062a054d50516d55e6e9a92d2e92ef797571ddfb2d5769afec873455bb275bfe3ceb20b01fe29ee9cb3156321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037ec8ccc94f09d3d64aee1bce7e9cc3b71455b8909ec20e4272e9c3b25df66214e6bc63d0e03df16dbea548783d3f2b000000000000000000000000000000000402a568af12318c840cfd4e0875d0f8989184c9f3beea7f6fe6e6e2c69a2a751b8d70b0f5e237e13c6cc4c208e772ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b38314c062a05375c5b6f945f8b99a81ed1fd4c8c9dded5f9de69e4dc6d49afa505547606c28deb0b49cdfd2eb83b400000000000000000000000000000000166402ae3cb07937c930db5a024f98017c8ec14a78a1c78636c54558a5cc9eab6b9a061f4da0fae92c067783c90629bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000673e6cd9cb0fcfd75a8e950344a55a249d4621bb2fea663f5a26e3dda34e792d401b8337d6b0ba47c6dd2d5870d0f520000000000000000000000000000000019947bf5c3efdcc30e489118680fa4a149cee2ad3d2a3342777a5324b5a31dd14beca8b7e0df8f184afaed525a33f6801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007301aa9fddc2daf6470cb3dfac1648048a554d91b51ab75797497de3be48200482ce313eede021d3dd0130fb4c3572800000000000000000000000000000000124aedda89f48a4e48110e179060e928dc14ecebe52e5a69ec129e9a531f3324370a38d7f6fd30d02551c6b675dd249f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2455a7896cae11b394cdc78404003fda8cf4d8b430475d64e3b13904ba2086b2702313046955dc5a943ae64b0ec0ab0000000000000000000000000000000012ca266c8bd0471ef9d5f14bc40a52785aac46f9316989100c7521444911ef5455b143e584eb5bcc6e3f11ed46ce81861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ddf235c26358701ba51e8a25e10b8d65f300194d964939887a57d5772c1fc7f49b7261396cd7449add2bdfdb86b660000000000000000000000000000000000bd1f2fbffb103a9e852622e0c08bad882a70cd468e96db6473b57805de72bd3cfc306985d34e5080ca999b4634a90831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011680139072a57ad5035181dede494d4a71f56a543368c63121989c248ebc8b11f5eb03d07485cc55de9f73f5eaabe66000000000000000000000000000000000d4e543d023bbf26c05a2f78ccd29d98e112e69052055e621964e757d93ca42b0ca54b2ca3ca20eab956d84250c2a4c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc35acdfc77f6d37a3dd8badcbc53deffcbb14bf5833722c17fb8e5cfeb2baaf8c59bbf5808e4660fb22978ed6c6dd50000000000000000000000000000000019bfc29a2c827ea2c4e0d34ac661129d93294b80866d9f20e844ee0e1178f26b39c1f0b35359f5b8d3bfd1f7943b145f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf21e612725ba6ba17ec8078796219bd3681f0612deb1185949ddb35a863b7fa7d162e7908f676f9e73d1539d70c68a0000000000000000000000000000000019595810cde3aab9cf6c61d2763794ce83bf315ed87c59e5d8d9adbefac85c100d9f57ce0682cbd8061c90cd58d558e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011032d0bb6344b43f554082567b2ccab9b296c75d0b4662b685b8aa724132fd95aa756f3d4705c3e381d3f6b0ad0de6800000000000000000000000000000000082e15316752ef17a981397684f0f21f83a7d8d5b00dbd47e4151558dc5ecbd159a3bc79d458a11ab0a435cfe0579f911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009804eddb57b83075b6eeee8acf7763d775900ae00f32212834cc04ae72da1a019af1c7fa10dff5ab11d7b5a78d0c4930000000000000000000000000000000007245b4f65a1c10cc4a3f8c268858b47a63cb18d28b8b632e3ca8d86cef7adc9f353855cc25294bc4420c8a0d2ca531d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142e37cc5cd8e90ae2f38e6258a1696dcc9bf06310810322a38b912ed79f6ca6e33537f225a40c0284afa8fe3af8dce80000000000000000000000000000000017097a9002f88ca4f4813eab7e7c0a25eb56d9b9884810f509aeaa19945a5fe2319cd143ec05cb07524107c6f95717df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000003bab6716625a5ace741ab06ade2a7250364e31e7f494c7b6115bbc6e8d997afe367085fdff6d26b290a456223f179b000000000000000000000000000000000b0dfa444f8c53c60dcdb6792a0eca02467a7a77bd399cfc9df7eeb019e04c16a483dc3a82eb372fc21cc1403a0466c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000625fe83733f861d953ee8e683abd3d89e39014239afd3b2d6f959ab67e24af137ab439dac224fe3a594d1a5af3bdff0000000000000000000000000000000001333ea86ae79fbdc5bd10830d772e5ec989d41efbfc76c02a7c14c0dc3f0fb76a018134aa2cb70a059b3a9975ee791a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d42dfb90abda27a0b9a01f4e7f14cc07c56c59c465e66408c89e55a47a4b5e9173da20882d83ecb73e018209e2d8d83000000000000000000000000000000000a6065ea4636ba4092c4b502c9d95402605054852717d061824cb371f0f318f72494891f11267c8406bd5ccf9fe104ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b161e5409f17c5d34a0e1fcfe849c08fa070b882099754f500fc8315b7e746fed39a42769019620f9b8e05def94cec90000000000000000000000000000000014e1cbe28dc8c05f56e2d914a3ecfae5407ed701197d7bb0931dbf7554110c44354e2427f26338336825259e6cf231c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159256259e24c01fe2f2eb5e5af97c3709dec85e0570d754480f02f7a798f4a21b7eb5f466e447b9f17599e94d15d01e00000000000000000000000000000000121743fd20324d93803cbcd0c984fde68c8cc44dddaccc95853bd0f1e2e4b99c9aa99e40f56bade8b1e8f5032c16dd141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000677ceefab74f7ad376a80aa3697049241c048995c0db22bd4edfb7086d7101efbc3d2a456aa888d5b77c1f1158a016f000000000000000000000000000000000cd78e0050e18b24ca36e1d96f3d074e97a63e63e8199785922cca29f5aa03ec0bc91775e3f4fae78675659c563780131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da3a712ecc9ce5e7de1501186ff3d6849656bc254941482f3764fa0d05543a9d297211e23a8d6eec49ef22d01e9dece00000000000000000000000000000000051d20af46f3e036b1d1ac2285adc55b2f179a88c86af304c11989d1d372aef3f1dc73693adece66cc8b1e4c5fd0631d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157f4fc7c1050039151ccc59d8e59bf2cb95198200783551bdb21ce91ed00e9db4d5059b4e690dd731048ae53cd54cb700000000000000000000000000000000152a0f7bf648856e76b616559bbd89979fb07e96be084bc395712411b07dfcee27f4576d976ddd4ad645f72548d67e2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000004b5883f1d8f8a4283c7ca03f9b45c7bea0796daf50a62073464c91a10ee4524b842daf754ecb490b0f44641cb57a96a000000000000000000000000000000001199c4d8092a2213f2759f43fb4b755be20494226192421fa1bfab7ecc6c4b8034c84b1a4df2cc2afa563741431b2e9d", + "Name": "g1msm-29-jwasinger", + "Gas": 97788, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000002b9e44e06816cfae20682bc898a1ab484b9b72c9d8178225e7e80a6292718de7324f7feaa05c31120274816feba50ef00000000000000000000000000000000152991e2f52f22d52309b16daa0a056bd77f4419ebb642ae071436b85a53baf89253f2e1a6e9cac132cd42f4cd26c4821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001770f05c6d7767a23e43fbecbb6bf2edc987e2a5b1a4a999185bc55b4292e6e29d4e81f31c218a154f77f033492ce77d0000000000000000000000000000000007a8181cdcb96730435243c4c1221f370f90240dcb1ec9a23f5b944a4132e31289540f989b302a54133f594677f1a90b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a18dc7d24e3de2f4e03557dbfd3112fb4e01510bf0f54a89fc2200ffc0a24d290612e2d9554bdb511f927dd118370400000000000000000000000000000000167556a4f645223c8164671c9a0e2d888d130059bf92a62f470ee5780f365dc5dedb5bb0504d7757467378cd35acbcd91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af1ae53c18cff2289065889160c2727e4ba095e1d23b78c1fdd5006d63870afe8ec24e68b5ec7f636d0258a8c013f4800000000000000000000000000000000129110a7b8492de97304f5113e49dc8a26615b25c3284a2c5e6e99d96d6be2806996c0279ac195befd13a4ebe3919c901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153b7381c3cab7a5e0e9231544a0f5a2f8ba20b24bfea94ce2b7c6eb4bfeb9cb93320b3aeb7c02c630122e68f436914100000000000000000000000000000000033cc06f57841cb9c915c1b3f493fae8414abd6dd950364d45413996cb261054f28ab34ffa1a36d6eb3b9f3a3992c8191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014748ca48f11509fb638b1d6719cc8f6e5d7568dc4b92e0e0ef5995327bfcc133ee6ea41b7b20bf2b16fdc3bdd3f7fe80000000000000000000000000000000018c9a0fae8ecd9a38d574369b5a00878b42eac3be05afc05775c619d6e86a1a2ee31aa0fe4a08bc6055575681b3c19231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001996bcaa707a0b142491a98eee2dd35d26347ca9c9270fe720c941c02cda6475b072ea3d2b904e7fa1a37dc77cac9e40000000000000000000000000000000009ab9c0b544bee583f597ad2f8134a59d09b4bc45196f33722603fde0f9dc3764aa70608a2590c28163aadd376a990621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1a51eafb917118a8644cd118ed5c63f9d80ba8707fcbb43797cf708cee814f2c40992c7372d00967605e6ec98b57cb000000000000000000000000000000000b7372c79a7a9e35d44d6b90a342656589da8a6942cfca4a059c5961fe0c3440c81cc0407b8c0456651b9b33bb7fa01f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c69c240a6f0b612e3d8adb261683a1a867a1a71c3c898c1e3b7b05ac3baa6a4f8f170c3b672d109dc1dd4628de0e1f0000000000000000000000000000000016800464d803983163817a5c3a9d7e4b9f3e7077119fd2f57a2910a720ceb113557e99958c43a26cd975cc54d5c33e601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ed65f5328a5973f6fe40ff54526f3b8f99c4c8c5dcdb1b288679523c5c461eb7c3d274188c9c21547af560b9e6256a0000000000000000000000000000000001d800cf9fca6d5e479f3076c2348d307ec5b0312a23f3ff29eb81c7ffa455e1d056f0a0c2e935384cdebd2765919a6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080f917c73fddacc110ebc2a81e46d8991858cbac30a698795ccaca6e808ca7077cdf553e26003e55ae9fe3aeb5c1daf00000000000000000000000000000000046ee199d683b9fbf229cc3212559234268072ed91f0f3e250819642b045ff9d8a177cfcbd619f4e597676c80f47c6f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000240da36871d9e4cd927b3efa64ed43d94fde664c4335e14348c856426a9e0b85f43e5ab1cd609cd625640c6985b16ce000000000000000000000000000000000a4d962530e4ed39f36c20b4dac245122920fd657df7ebde8028e56583a7c8e17f93fc5a2e0ef4a16c97c11d4374780e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132d8d80c77b84d832f55e893151c3241b5b68fc9655fb18dd38234962f085e13e6e5b1a7c7c58655a2295dc4dc8796c0000000000000000000000000000000013f45fe46511c095b215d2d3caae2a8b7223f99f8b8c3f5cd9994e7f3cca6d803ac2a06c268629f9c5af18931764951d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc909ec3514cfb8bd03f18135f91362894f90706eb6ca67ab8f1c9720667f6d51aec157c5ba8456922c995a88ca86e2000000000000000000000000000000000b8425cdec7b0457f6c972a0d83ad623224358ffeff8e9bbef0b1e512cad6f5233bf980752c5af8e04d98cf502b62add1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117d0eb9d010a8af979cc3b71988ff0d70868dc9ce4f41dd75fcdf22acb9ddc98266b62f56b456211b3b51e16e2aceed0000000000000000000000000000000018e0013024776e7613395787d4477aea7c3e620155a3e72635b62bb372b94e3a2af6371787b014a1ac18e643992aaaea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000432c30f711ec5bbfbb84fb08507cded0979c8ae7b5804d7c32686460772c9bb87dd65bc2b5376bfeb1dcf678531870b0000000000000000000000000000000019e84f906e902bab0816843e4fdc6e4a10d656883b740def861338b0b11d4e623b04f1dbfab240f63e02e63e9d838e041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013336ce45daa4bd0debfacda1d9cad393aa07f8b95b75c0beb4d2ab88de66611a588a263706bf0e13c26a8c006dcd0b30000000000000000000000000000000003fc7a4636164719c67166671705649bce7ffd567401a6a739e538eca6a1b36a72fb6039a1a0e1089aa37c74615932061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067478a083a4d8e7d86c09d6317d7d93e21d09c29cd76faef172f36136ada680999349d7457728c9564a8b4f3c2e072d0000000000000000000000000000000013701e2ae6275745e1e548e663bd41bf377b2d9b7ec4c3d5c438d5d8228150b0cb92be4d438d8a74d11c8d7f1bc6ae9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c44e8a073951ac9e5bd70dc54aba2094f32273a793916f0753065171c736ef7db0616d013a3611fb57b9250510f5e4d0000000000000000000000000000000011c67c469c906aad6e3a3e5db0ddb0b4dc714ef7a1c13f2906d8c25bc3324370a42d258ea0084b6b4b596a7f22f149811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d856f7d5e2dd998de8478e2e45b3a5396ed0f706daf47625b22384126d2efcad686804cbeeb93b5661622807d4de320000000000000000000000000000000007a8a1cf20242e1eaa9584ba2a4e8ad4112bbb65b56fabad550c1188ad3b7c28ab6c75cc294691ea1057e8ff1b52f0b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e2c633c5f2ffc73ddab8662f8cdf40daf36a1094c609ae4e8606072eeba5da127560f667df714c844ca17f7f497a2400000000000000000000000000000000120a8f621a65e77945bde8825d2c505bbec453bd992784719a585c0d1273a4dcfb405005eaa90102ca3ee983401ea1551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e45fe2e0b8197ceddeb0b945c0a06eb91e19d75dd9056788b67f74e5ecde895153d46ec8556d5d627a1b8ed4b5c70500000000000000000000000000000000062a544d3ce2bcae0c3fefdc5ab4c05dd289db39f9e6cbca8c805dff41d3afd7eb09dcd292379e90bf23e50070d5534e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176631964f888b65bc3a67da9419badf7bc72ef19f9969a9d405e30c693a81c8bd44345a0cb285666e0e21587a1399de000000000000000000000000000000000707083f74979185ca45e342dee46179acc80d638e0e89c729d30a7dbb0d538466b9946f77cc5d8cb5d8cd13c03a33921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015626f56848b08c84d556e3cd507e8a3aed507f87466f0102df73c878e2ef3453f84b2dfd83a33aeaa4869cddf5a66d90000000000000000000000000000000017157627ca5f1715b8237bf846965539a2510e1b06a44223034c01d19e0183148a38d07f905faab699e39774c63f4df61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f0130fecdce0cbcafa3283c5c8b311df2f40512e03d99b2ecade8afa6db400046749d49ad53e044505bd017f40bbd4000000000000000000000000000000000d4a84466e6f880f9dcc59284c61b25540e9f99440c706ac419de9d09b7a0c33a4916746226f34a7775efefcddac14461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000881238bdf4f995971c92cb67508ac8a1864a19d347b24ed330f5c19658b4578e35c23e8d5e2877ce2f66fecd70f651100000000000000000000000000000000093d8bce3f8d507c28808e44d09ae83998e2939b488eac4bf20e3fbe36ef1d1577fdbbbe35bb05a7e79b17cef7f238a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8350e06676f343731f9338f3bba71e1230fcd1527c3bee6af55095898b39d99451c94b1343b26423fd4b761469d6e300000000000000000000000000000000042b7665834d7a442a757383898e3ae5ad10cc080aa0e81f4d142d180d9e0d0fed17d3f3b4c52be96b246845c5724dea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040905a0be06f0524c002788ecef03a459f2af0037e186fc2f43c04ad3a46cb17f43cff1a682585e508a4249bee54d5b000000000000000000000000000000000a4a14ba57219c4b04da5761da72324645208c958f463a2940da330cf66d23e95e55eb86d466937f897e920f88884c061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088f46102e5082fe9513fd6cc424e25b72fb122c9c27471dc048f3e808d2bdbb775c87784582b6864278368d132ad6690000000000000000000000000000000011a34f3a405cc2aeeb6f8fd5bd39f10922a9c01990329d061bd1d54fafa41555b12e05a3e3f440c83497f24088e75f581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185d0db9e2f0cd4450234c1ede55690a38b66932bc020ea7d7e7780453d94d44c08ff53c8337c1a2a267a325b1196daa0000000000000000000000000000000014430d4ce207e06f1430a8529d888c1a1c317ae6d1fb2d86a45f9d91b06e3899b804b52f838f28abc29a26c665bbb9a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000873e0479b6dfc5ef1712a949670b0d30ecd792018283f9874768cafd3f47e9639ae9eea1ad00955dfaec81f19736aac000000000000000000000000000000001946af1f035da684c8896f8241b3563110975108a6f6300bb1a6fbbc182a3bbe72e2db123b137b4b02bda5a71fb33fc0", + "Name": "g1msm-30-jwasinger", + "Gas": 99720, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000e3c63ba695a3808541c9cd3b8bc01d53a39dc8fadf315497b5094f0a06ff0a7879e1c5f70206d91cac86def9d1647e1000000000000000000000000000000000166e40a7d6c364df834d6a91cc5d27252711f3132f7a369a64689c6b8cf7b0007a041c09bc0f03fd027556fb1ec16371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069ad3b249590107c37ecd8255156c35eaf3306f4cc6d3fb4d12c83d094b7cf63c9c3429c9725996474da7201fe90c1f0000000000000000000000000000000002b4414d4043936fd70f147583836f33cc50021c4fa16721e31ac645fb448b63a4507a6c1c0f82094757803d900ccae01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150d059fa0f679366b8c41735776ff08f12431e8dec6de1191c75fda59f6e370f41ef5023a47ffc2710e457fc5430d27000000000000000000000000000000000c49cf896e58ce98d4c55eb75a8c7f5177dfa13e6b2a1f959f338c651743265e7304a588a0639de511c7e5fb10c50fa41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca343b85aa2b9a01c60ca4d2587bd3e6109d37123a29cb5b4f7465861f6848d9dd537924969f266a2a640ef0ed2023b0000000000000000000000000000000011f27be05c30a569a87f5aa0762a295fa3e3a061703e54a00b33e7f7c6748f5f913ddb81972ff19c070c6fdf37d927b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006319aa506af95457705cf24da1359a39e6ea13d4e79259b92335bcf3e32296c607d2510c79e081f1b9154cb7a12d6320000000000000000000000000000000002ca4018088e8ad085bf4627725d6165994b65a0e101288689c435ca4fbabc2201537e52e6bb01fe59130a8fad97d8751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004bae476ae5a4a4163aafe14884f6558663cfcc8fffb8f660f9385cb6bbacad2476c314ede2c589ab3b185799bcdeafc0000000000000000000000000000000002f2fb93be1463a992996b7f99b0082269a23bae4d48788d2b9b538090253978c46158a7416d56d4dea6678c56168b0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c1359809b04eb90e53ff4442cab6f2337d3012008f64498caf44fde802c4a367d9193c878aa93975cc65d3d6ee9dc6000000000000000000000000000000000da070d301687721124cceb59c6e5c0a1bb3cbf114d72ba810a7e122d4fcff1619537a1392b1ecf8d8c5858e0a2806611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f3ad6f481b16825fb081a8c7e15087a8dce28f98b1535de8a39c0a58f1053ca8c31036cfa020b09d4b40c989023c3400000000000000000000000000000000157d3727b52fd6601bc47ed9a4a9d6b41b15475403f2b8ed83e8fca247cbb2f2606e2a91efea8aec72f4f191b8767ac41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a743a1c0d1532b9b572a44899ed615123d8b9bc17bc923ec52c345a08e9d255844e1cef633e6781cf2850fa93679290000000000000000000000000000000010a1a5f7aad10e9f0a7d0d63fcc3de086a1b3acf61d86c63c930b827b2c9a22936c3fbee946eeb3fc80f10a777958b801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c20bc4089adf1f6561b71eff4911f77613b45d5a11ef3bdf4973348ab9a868a141bc0af1f1cf87ebaccc8dea41d2fd0000000000000000000000000000000008e5e1c309cb32f07e380121aa7523a2677cccd4e6b47fb1e7a440763a5f92c82e65680dc301ddc295d428ddfb887f001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168a5d2bfa3bfe7657dea14591234b466d47c07f8775325fc6776cb91f93ea47ecb69026f6d7d70628de0dfa92e060870000000000000000000000000000000012562cbdb7e2a9864b3a322c718fa4c3a59e6c4c7c0fefc32ef0573ab414120e7999f237a0599eb3292fe14f64530b231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001479bd549140ea5771a797b50ea9365df7602678ff6ab0cb64144dfd53bae934429fb91c91cee71dca5594761d5c8ba40000000000000000000000000000000001d7f0852112f3f785dcd885f9342a05be6a5548f5ad4b55c705fb448a0ab5070499569372dd247a8e91daf4267136c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c27b584b10530369ec515f7d32c483e7d8bd11c5e60ee20b260edd73d3c67f44322b13c7375fdeadebff8f5a1d5d7300000000000000000000000000000000059b98e9f3dbf54fb476169d1188b260465cb1eff4397c101400924c62314b968fe20525deadb8dedf8ca450445fbc7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc7115dc54b90020f826a60dce917acc9ccb4f02920ef9471216fe829f2a464672cc73a3e978f104d04660051c9d123000000000000000000000000000000000197574aceed901f5c790a5fd14e6c0da12494c68fb4acdd0d68c1d3fa0b0cc006081167069849455b3c24790213ca1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086fa8a7ffdd7e54bb287011b00e88faa72a7537cf6197d8bd5e2abb6fce29f696875d2bc0dc4f81173e08a90e4057410000000000000000000000000000000002c803dc574c1a992f5e74e96900f4067f95ab881070ec92de54b177f3f190774fe2b7ad2f642d26d2811cb1dd3bc2471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f5cf3b11c32f1099b636e28029e6ab7daf7388460ae327537937c164b505f084931a909b80c6f86d6c933a302cdb4f0000000000000000000000000000000014e68a0d87d9af6cea2346231b1afe2f42c1d724b547d4a2c61c2a4fa12fe03ed1cd425659b37a5e718a14b4ecb6cf531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e812e9174195ed6584edb3e3d58d9fa13e0f762336ebef4669067bce8406d100ba8d750ea5419246a718889102726c0000000000000000000000000000000012d6f62aa832318b7d2bda6e43c4ea0820aaa2e8574595fae4029e88c6ac8727b464dea92bf0b7e6f84bac2ec05a6e981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b3e1a579f8970d651341ead810048220a2fb8ea9087cd8ba157002fd01395f22cfb387239de0a6f902f5f410c366ea0000000000000000000000000000000009e7f44a45018c185dbd141c07d829bc6a71dd27e6d33968836aadd1f9fc74396ef922e0833af40485a9b1761089ea7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006569f437dc9b104e587fea00aadcd221c6ce3507dc0ff8a347750306d3e07446b3165b5efdfbd003627df472ce2d3b9000000000000000000000000000000001214fe8fccc3d4ee001230d73fbb27eb333ebc950d6e85ab3175a7e740db710b6dffba3428db52064b4c1e873237b6b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d32223a25964d9ed648e87fad93aec761acb5a3c455ba817b6b4a6b11318543328dd02eb7d680bec8497b9aca7dac3c000000000000000000000000000000001972162a30c9ee4364c409cd843d0f41a82fe7b7484054cb07cdd66cac9216965dd71736b4a5c0e6367fa1ea038fbc501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad4b64141166dcc80987c6b04a32e8bf85f977d53545bf7d6e88caa07b1434799c43f1ebf8d800a6e8ea095ab5807f40000000000000000000000000000000004684fea6eaee9fd39c5c78d46c747e4bf06a9a0d5b66c59a342589a7006a737faadade56744ea332e95feb48fa28b3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195451cedec15c8ec64ab8000d72be6ca7a80192b013b3835ca585025c669b36c0138af4fcdbe280c60b8d59bad8018e000000000000000000000000000000000bdaa74fa5ca31cdee2d39c78147d172f54c421eb2ca4b8c478b3d837e760ba51bcffe324cc32bd4a91e5f9ba6dafaa81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110f2c8eaebe78d583a7b5dd30a6d0ba72e64e57a1dbef4981591902062dd25ea7ecc6b47061bff7b43d14093ed8a9ee0000000000000000000000000000000012684227cdd0689746091ab27c9f93b891f6718525bcef91c7622a6186ab95063b6855c8224946bae4a01ab626f01e1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131ed2e8fc9446ef99af754522a4af9fedeaf1f8f4bfcfad5122a0e9152ace72ff79b73600aa997550522adb1cc692f000000000000000000000000000000000059c953e88ef4d699c5aa75c33bcb4535946b2abd081ef40b1179337a860027691114d710acbdc873ca45398554819b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ca086a8eeee058ae8e5b79c54be4b2711ac2a0907a5108c517c1300269686064de1ab4dab9ff7408a990f7580f480000000000000000000000000000000000123fbf931054c4b2db1131c89747f305fae6a9de89ce73a98693a6b25ae1ae81dd30a2ae7d1cf912c5d0a1cadc235ff51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001407a763736f688006efda863e7b3b18d566cbf7b4c3f67668f6c3f87f1cad250f55730ed04a5432b1f3f36429e0e6aa00000000000000000000000000000000075b3400bfbc3b7091588355f77673b73ff211a91cda2c6983e478378998312697d9041582218c21abb6d741a5906c751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005353db0f1023f6a8d7f02a6a13aafcf425176708f3a6b6e18b7428fb1f523a7cb9be23d6b125c4e133e465a7ce9d8f4000000000000000000000000000000000e766e39ac9a4bf922bb52a906a062eccb6310c1e50bae2ae30a8c68cada7a317a8202f7fce5351c62ccb0dbac917abc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000124172ed2665f37c89546b903bd525ab25e24f2cdfa3e452ea4be09e5b5d628e7badf34ff4d3454895456e7a3c97c340000000000000000000000000000000018bfc1642e114aac694d20d8d903cb671f803137e14edcc3262931aefb8230176f0232c6444326e552a239d3f07bfc3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082732670056e205dee5040fd99adf4cd93fcf46bc72f0479a3efe73e426167dac3c005940270daf30fa97ad823291e60000000000000000000000000000000016134ed2822a37eb7f14c4e4597efba0b4ab33289ae7898f33627a0a7ac2078e586ce521e02fa039f2e37340dd35b6121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122795b419e10d2cfe52740d69b91c3d1ace2b31cb8a7c67c10bae6a2b02b0412847f653447c53cbf999951abb4422470000000000000000000000000000000005a253270cca0aae4a36c5f3dd8bf60c7f31d336bb9ea7e3cfd42681dc1b71134ea7e6905dac1b0169a7ebe7724253331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001086c589cc0419f2620ce157edc4b011a36c6ef414107032200001a8ca3dbd8954a918ab7fc4dcfdcc52475a0d524c650000000000000000000000000000000015dbc50113ec7cdb433ae00e66bb0631358a9d130c5572bde42a1dc9c5319e6d50914afb6617ecc4b150fd3baba929bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000014bac2a905d41965f5f5a9f82a9002a5b1929980dba64c1e0f8d742481a9448047aaf41daf73eee27ec6127c39b02e09000000000000000000000000000000000e7d2e5665c66f9eeb28b6913aa96813226069589bf3ff50e409eaeef44368908252aabdbb99445734ca0efb417baf58", + "Name": "g1msm-31-jwasinger", + "Gas": 101556, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000019d287c613f97e5264863db37c848e9fea9cbb6546399050b71fc5146419cbf301c94a7537403859cd890bafe01d704a00000000000000000000000000000000069075c0942a4739f6dc9697dca124896d76d9c68b038f20111aa5065e2162303b4b0421eac2f1fc6fe7317fe5a3c2b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016aff1c3ddb51b90cff734da0024572efbcbea41269ee918afee86571cb852ba14906c09e4afba2fcb6d1ad5d1527f24000000000000000000000000000000000f2b30cc72dd75ffb17bcf549e8013c277332a65ef1d942317fbb6605e6334ea672e1fc9bfa36ccfafa11ab893d62e791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ea336d6bdb60395561ef4336e9937871b8b276d7a12b776e012bc1a3d7d6f3a45320fc0d9ccd8b4b6e3eacd7b1d1b30000000000000000000000000000000007ee33e7f55a1a6a33993f3c661927888220100a0f2651f6256e2625b7e07ee835aa37ea0cd3d06e1b75262b341e29471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000461eae22ddc0592a171370dd15161c63f6ef39d4dc99ebf1af0219a182be0a1cb8ac7f5178a88b36fa192414bed124a0000000000000000000000000000000014176294456404298220604a91aa85093f912ed80d7eac4a4ad176eaea8360b96305cdd003a31523098c848fd0fd0a0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1357572dde202679729f062cbe8ddcd5f880515e57f6935dc2574f8db894d1ad0237f1324158047fe1806e84ae79f90000000000000000000000000000000009c72e9fb8d39a2640764aad16190b45ba5c5b72a2d0b1101fb2d389a36f2a3b60f5363dd0fcd228189b507bcc68f8061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041690a78c5acc19caae338ad039529f335b4c38b2dd3c7132d7e49a15a70147e7d290f78bf1d09d9dffc88f19ea2ce6000000000000000000000000000000000632a4ad6a19eeaa934573ef62af519aadb924faa1085ed4f82bc646a320c35afca6c63cd7233f48abee0ee435a158341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003210ba8743da34c3714d8e4dedcdbbb87e7574cea45f23310ef23c4200a93a8905c6ba0c9fa6fca5daf459d50434c7f000000000000000000000000000000000eee68e70c58ccc3d95116ef4b19c3b2d62c32a2e13ab9cfd75adf921b58d0ede75ebc9e9a66a2bc49da86f06c04d2861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000beb009c1f2d8442ab9bd865d3180d1d6475ae381deb935f6c963949cf88c1de55b8913765715a4c69a597c7bdf89b49000000000000000000000000000000000333cfda212d316a00c5649f23696f4cdc2ee2558c38992b325155ad60e875cddae143e42bbd2a7dd52b81df8df7db6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a0f0d4e6cd49c5760d94a2cad72e03120320eeed79fc382da9a045a42cceeb9fdca806f702c77e4ece36df808f993b00000000000000000000000000000000003183a92d370f62f9eb69b64394d0da94f09c2d4e6e9dfd9d9144eed5973325390aba00b8c6af1c283c408d62e81c721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001534f8f7772d7e6d5abd66005799dbc77abde9de1439fcd8986321ac07caa77937028bdf22f7527f92c39ea1ef38cceb000000000000000000000000000000000b824eb53ef0cbf44daa2d375f98a8b6d867ca2c88e39ebddfb0c0ee0af6b3fc3239a9680156c25e0dbf93abce236f7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d0f24f27440c8c574239a37d3a0877424b0d665550ae6cf13d0a1204e64456d6cc1c9aaa5aa02f7cc2ad22022c7dc000000000000000000000000000000000091d6a0d57a6f13e8abe18e009b9191f4c3d5866e20990797809c565b806872f5036a1fa9b7d46e3bd53608970390d201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037b2034e4d2cd69c4258fd14ef0859d5747489ca9f153b19fd5a7a97bc7313a49ffc7f26cdfa76490323f49767528250000000000000000000000000000000019537ac731b69d4baeb5a0c8e8a7a3a37cc8b5453dcb4d60cda957f674c17afca037b58bea3a836125926b2dff2ae2921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034aa7202b2cb8d81f9ccee4e686fcf31cbaa270dafcd33e5502505a5c561776df863894427f5350c33f358d92e22a130000000000000000000000000000000007bc7421e75228cf41dc5363b4a4fec9bbb5545bb49d6d2b14765eeb411d08996d563878942b98e101049272904c91dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031ff6d2b08541011291ff01bb6f86cdf477cbff3ee55305701f90a24253bcf1ee047e841fb8531487a1c86837c541b30000000000000000000000000000000008aba53c27c7f47a5b19e6dc7f4b34de13550d6e18afd6bd83e6022f808eb8222f8fd5d89449db589f6218c4bff523c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1e64dae2f76e206f6eadef54f3f03e77bc591bc176f461d317e2cedd52f5427b7e664c46013e15fa85174665df03cd0000000000000000000000000000000015e798c6e08b4f2cc00046df6482f6a03135445445972073881593bd5c006906ebb12180ecfb19c94c8c221e3d08e1fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001483d19d713aefc4c8992f3aa1c9b2110031df7b8e3cc0f6c201da6dfa92ba5e814aeb19493decd5667ce46f49cbe3870000000000000000000000000000000016c0edfc485d18c50c176a182ccdfb36dccbf81186b68a7f3b952adb637b205c7e8cf52b65f65f0d24aa4e5846a483691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb7000ca247ae09eaf9bc1b3a0516b64beb46eec7481a9e866bbcc645e51d23dcdf41e3da2d990fbb653c18ad2cb9a80000000000000000000000000000000012f912ea4bca1770e31092451d0c8cebbe39f50f989b8f14274404ae75541505f0eb99a6432f97cd0721c38db4f28ade1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004414237707f77a26d31def216ff034450f1b9c149d4dc0ca34389e2ce3144ade9dbb9d23e36c47cbafcd230cfd83f75000000000000000000000000000000000950c4454ba2a112267029c3bddab5b107c7bc034ff5bd1db370464a87b112cc6a580e90b99f8aad74fdbf93b269a7a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073432231f2ca609592f749bfe84985d1ec529f659216fe4741ee6c4937a450ecabf4506be0c11ed16c50c3ae76dbf25000000000000000000000000000000000ac351c2c570aa559bc2f4c53878bb03d9799a5e12f86a17ca1591e66ad8009999b2f88b84bd5ed117834bb534e413401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d090a1f3b7a073c79181f0157cda0fc6f33c65835ac4a3eda8021e794268e337d2e18ed190d877054dd646c1982479000000000000000000000000000000000672bd74371fd932517ba7d754eee24080029feb5abd4b80e5973925dc951268f54d5219edf6f1177c8a3f85d8f39fbc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049f166d2ac77bb131818c57d2d01f2a54d06ba21ab2ae6a0c192a5555b3d3c7c5a94732185e336692c86db664ea999d000000000000000000000000000000000dde7f8fb1a09546779cb93a9117528e2ae2219c2d5827b9cca028061fc2ee0a339f72598bc9be7570d1dfca0883c4c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fabdfde35af770c5db7987dda9bfb039fb3b185184588a73ccca1913385fb8adde20aebfb77a2cf4e7241eb8cf5bbb00000000000000000000000000000000184c013fc18dff866d9a96c37e2d09b9922ae57bdfcb689dae1b21b5c11054393d968467a83acc54d230bf8579f738aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc07731aec255a2c7eb59b3c30e31742d7c147673a682d2b7723c78f1b03d735c99122251cb581a10543656fed6910c0000000000000000000000000000000008eaf937126d3e6f96f0927a397347ba551e44e08d2db820bed4911468165ff339c3c7c6fa1be1448ba0332ff65f814a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000158049c2547ca8359ede78e9be5c45022de55401e6e4e26716a59ba7f2943bfc9a552c802382c1a16ca2afbf86e3c19c0000000000000000000000000000000002eb661c7bb49e761eae7298f7aa1205257f2834c58063e2344540e0b4801b41234bf4ad8bf74dcb0c638d18f8e4057e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050e0306f649c0f7555a59efcbb6ba944700437f17990fd49405bbe3fe3d13dba545b53391d3e1b985795015cadeadb0000000000000000000000000000000001938e1943cd4a8dd3c9dddf6019e175fa3c4b7aaa511166c0c91eab5af04db8ebcf790b9b8cb367f0384a0463442f6001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180075f1a8946376a12e67449b926e3f18a92e473da9947b662be925d71ac6ceedc2b676e04d5eff5d8cb751e5d66ef8000000000000000000000000000000000b2a639a58a562df4ea1ec5eba0ae37b09f8635daf7c04142c36e369db66bcda7263d98d74366a579ff51a567d2652901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163e473287982698c7fa5ed63fa65bf3b7ee5809f766a25ff685e130213f45e524b0bddf09d9f3d6a9017aef91f4f071000000000000000000000000000000000e29738d8732958e4bc751a80993149672b0f219558d6b8306efe1609fa20e1f42042e60f0ba7315d2784b6b21e9713f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e06651dffd04bb3d56dbe3b65542b621adc97530820519da7ee240247beb8f8154578efe2090ef55757d801e58b1cf0000000000000000000000000000000001197f3c3ca8da2296f5000f7a72f1ee8e39677d9e90a0d619ce1c8e7de00d7f219bc5dc3f59ce4f3fad4451c17b1afb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000519f32c067725c6d496a939c245ef1801ce34b28ee4c3038e3655cf55eed1cd1ac36f48fc51a24538e5d92060d750f7000000000000000000000000000000000ef52b70c8c6e4c63b79499ece38cdf9f3919720cd14dbc7e1fe581a4bcc4a228f8901ee848459243b19cfda3a80ce711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014359f9f01fc00fbdfc08b4671bd4e99298696adf985c3515f2164bf1c120c38709f6011853374c455912fe615b287d1000000000000000000000000000000000a312122a9c978d5cae3cad06fa1a70c8f6aa0b56fe6090832620e0ba63f462605b08e743c29c8bba2686c0919ba60171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e205d64b977695df0b229b2b007aac9f0d5b479f32c6aef544a4a1a8ec1dde0cc7676dd757aa03654f359d40478e520000000000000000000000000000000001d6a0f86dba26735bd1cc499ea56e7d081cf66ebbda303f21177a61962e8f11bf92b826d235eb743d22992c46055f541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9052a39858d58148ae6457fefc90e5f14314f8b5be0234628307c08849231ca450f6ecfbbf15d42aff58d04a45372900000000000000000000000000000000137a7708da3b5c47a34ade4a954646f119803a75c2f104e0718037a1243a302e3cad8bf9d3e497f45f625db6c591d34b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebde9522362d2780b0111b02371620fd1c1d9272306be1e31fe140794ef5d883389835c4d96cf9e8428faedba32f53d0000000000000000000000000000000000d0fa8770bb03923bdaf724aa54e88a33bef03b6e40fdccada1dbc73561de3a256ee39a893e0d0f26cf9db1a0fceea11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed325cfb227a8bf4034423c6c4b58f3cdb1bcaf98ba1c13f5d18ea6e425235c4c6ac6171a7531dc23535350625f06c7000000000000000000000000000000000c66b73bb56be0457e25ffec1c691300d57736268b2aea97e5d3851981bbe0c871a092f9682107c14766c986f1a7615f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d50b8e1fb81c5ea2a2ec171d3993110f5387f59a42aa8cfe7c371434d1c7d7d1c4344de18aef2bc2f618d657bbc51d000000000000000000000000000000000451c7e352a055c7e0c77a5a1866938c1602aca90a73325214bb2f6ad99afcd0efcc73de56254911952a2ed6851a908f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2f62effaabd8aac2d0d0d664decb0b92138f49c584a5dc0923ada2a88972e2525b1f0ca31460a3dd45ef2930210d6e0000000000000000000000000000000003122d5938764dc5330a4dd4ae42d95855c9f3acb36dd8236cf418f46358aab0a36b0f69dff50680bfe04d4b47fdc5e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014adedd94ffcb8d3911ac2ffb37121c24a32ea64c3e2bfa2cc0846fe373f3f8f87bd5bee6aa1e9ded374dbd903e1ae6e00000000000000000000000000000000159af833584493952edabfc819127d92d1da078de48722f0ecf7a75108383ef0647ece492442e28ae32e0e3546297e9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a1e66148e81194003019a071004eb2a3378c4f52041e035d13e102fecf7f3658a829d3fda7cfe12ae711ee3b688cdf00000000000000000000000000000000182988ded44cfb383a49ddb76345ebc56bd72f33ee544f8b30dfdb3dfab9ab58545e9ea1c4bd756b3805807dab061a201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001067a2e1d961764779d809af7784c2791863a648fd179a65177b9d722fdd4fe972d19f09a0705e8195525279f4cb5353000000000000000000000000000000000ac3ce4b221da594af3a39afe25da52a6cc049ba673efd78b58ec4fd9a788da3a66042ce13320aa1e5d51cc02407f2a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e4a27d7495f5dc684dc951a096f9263cd952e51e3f53e1f52e7e50e6ee6363b935cfb1b53284c9594eacc5f927eabc00000000000000000000000000000000125065071bf30a2ed95e71693047645b418181c53843d286ba2e4186a3b46700b3795fbf6e5da1f4c763a28e8c71ba081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000519ab0595dcdd9e25eeb9d5056d2107c6333376f203b932d5af00e14825fe04e933068db9d077d2f6227f313358fb59000000000000000000000000000000000578805ab6f48cec24a0284bec90b07da435239d18f838bf6892130569c383cc8382bf4f6816475cb3ba16608285816b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006df40e53e07134dd93d85556b60feb78beeb934b72dccf87784dae43740ea66ade5820f2dbefe0ffaa366eed5a49b0b000000000000000000000000000000000fcc01fe63760bfe6dcc3e11b025b5d89033f4f8f08b18092d13ffbe872e2a9717406bdda38c75ce85f38cab28fac6c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2dbf85fc50d15f9de3033661cae043f902ccb860cac848d47f8ac1b15e96ddc900cb00439da88be21aac59a53084ce000000000000000000000000000000001734b6e92ab54406891fddbebde115100183ff020e7d9338c016443f2f84af0c03e301551cf3cc6a48bd4dbbd02e248b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ed77cf5301448ce2f2bde873c4e17a0875935681603779e11103b78dfb4397674cace35f980c4e6437f96825f8d40b00000000000000000000000000000000066cb5075658461ad959b40560becac0062bf80b7ba524f5b09d7df698dcdd90724306c2f94e68b275680f3ae0d017321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b3a0c322010adb6c2df0a1e22eac991ffcc6bcc6a36f87651379e7296177ee662f3b678367011d87663bdf443579ac0000000000000000000000000000000014d052138e19b50fb48077d0a14485da7eca8bd9ec20fa1dfae63131f39fe0b2f40e9437afad2e4b671efc087e7295771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d9ff4fcc3139399148b3dbd74103fd229386125912a05ffc979e019bc33a36919b306660f78a73c8cebbad46bdbccd00000000000000000000000000000000009dcfdf1b29ac61624b91290a3061a463f65e3c6125481c2b13fcdbc795c786349dc570ed6e171f50f45b4b529deab01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d26643d2d05df74e7a711f9065e2e3a9a9b066cbe0670bda48fcc18d53ed1b489d0cb0cc57e03b4982f58fe538163310000000000000000000000000000000017e28402baf6bf55b99ed22696111db518a885f09eb34fe0328d1db7973eb9b05feb9d2a900b57d7195f80c9c001bc391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001570d55bf0b2788bdddb7832954c55f23983a762083c09cf4c9ecfcdd3b8a545c5d57efa6bde8943075c3e35ccbcdc3b0000000000000000000000000000000015f5591d4ef4e98d0ae8c994801b3aa1a1dbd1d15ea202e6a4d854566fadd9264146342796ea96022985e4997f5a39251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055f900ff9e51070c137185a5916bae361c9b2ba410879e7436cdf929db71e8b270576803ab24169e43faf9e2a8ac5290000000000000000000000000000000011a207dd903bfad0a761010ba6eac8d7af0e5ef90f1c0ba6eb5a23b137979eb2c6eb4a7f8105a3fb689e8546e1c9980b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100e9720ee0fafd34c609382edd0162e4fb8e726dfa124be4754046487f58fc6c88b9fa9560102e3c390502261aa0a9c0000000000000000000000000000000004f0592bbfb6e196267ec88bdb856c69522743888733c635006cb1ae1cb69b717705a99159e180527304baeca7fc200f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012906d00532a8dabcf3e2f82a84e0901ca5fe54fbdaa3a449483b9314249c9c948675f4cf2fff3bb4c140593e793079d0000000000000000000000000000000019b2d0379fe758767e27e68a075771cd8c7be6f4bcf423184b736c734041484f97f693d7111fba2e15b38b21144c668c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010802953a917dc7e5f943761716cd6511f1b442266c68dda57f3c78ca4fe600d2dbecb19e81a9bc2083010a960da31be000000000000000000000000000000000569e20a5276ba0c28171c69a4e75c7666ab9b94973df6e81c21bf3ef578b7519eb80fedbf9afb295aa37264448c8c141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166d321bb24093e1c27666d8106419addceeb41db5d2fef2478d700123cd75712fee245de2bb37b3306c7ac4f97b89bf0000000000000000000000000000000014ae98d6c527f4e30404678d29129aced607342527c5d3f7009178f202edd160a90ec5b445f40a60aad113559b89f7501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000605ca7d1c1988922f36d71413b0244870a6254bd4f92d9e223b225e3f6a8290b5d25995fd7051761492077a1f75d7a6000000000000000000000000000000000b5093392868f58f3bf257ac1dc70647bc7028e927591483836c2a5d6063aee02c655082dd02e1d2a7a240e1a39338f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014cd9fd2e5bba513545a73c8bbd857ac785edf0967f30951a92c69ec85127edfeca1c756aa569ea02b570f7babd827260000000000000000000000000000000016b9d9264bfdfe024debbb894bb5b3abf2d11b3b463e24c17b5e6dab0dafdcebf57dd6b340f3a1d4be13b7900fcf95a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001aaa45232af3598917783b76bdb800c0544a995ed6ad462eb163ba46a370b3a039ab2b069339bbc257ab5b1feeffe74000000000000000000000000000000000c3efaa66469ba0f32afb746bfc2dbd143b26f165bb37aa1b315878b7da55a3c1223fbbe9c89ebfe4af58d6a2233e72c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c5d8e371844b96b1c61fc9af2d6df658155575e3085332e45dac35f50c9c3e4908a925c4dac5f91c49fa31e8d0ddae00000000000000000000000000000000001a0c502108df614c7edc6005b804e3abe834cd4af6b797653eed6f25c83f5eda0514d7ae02cc621aba801dbae9b0631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cef840eef6908866876170c57cbad6f43e1849fc86b32e5be23e4f1e2d5e567e4205fd796037c854fa70db32e9809e000000000000000000000000000000000258eaa5ff7ec9958d07751f00e002ea86754151ead1b3e71127f25948b984a081ed98e27743fb7d6ccfa1a3c0ee5d671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b136ce45dc2455bfae269d34cad265faeeaf8ba454397fb786cf81618a2c9eaa2d1d6137460d1ff3bd66b7b419b85190000000000000000000000000000000003a1ad64e15375ce747114ca4c6efe485e980e4add3d91a46b019988fa727bcd999168c2c4cd42e02a36a0af4b2641b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c4acb6a0cc26f531cb3d228c524cefb593be7d7af241fc74da2544731a40f82fb9d5ca1e0e5dd54d1c6ac61e7a7ea59000000000000000000000000000000000f4707023d123a7aa1069f89b196b8ee012c644760ca0620c478ce00d787e72a7aac53c8f678ffc143a5ef36a3dc36db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002043f97aad2afe0f66cf2b2d899cc4530b8d0a54761f92302bd77cdd2379fe6991825fa665b2ea787d5dfd13523225a000000000000000000000000000000000f9bd1cc0f85d56c96f9a3cb8e3926974f8ce0810208248882a7b2cf4e836b6c6e456968cd0ef9edeece925df6973b111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000068468e1e951230d33ea026ccf0745876bdabb52a7fddf7204ab8cef66907326fa73a7125c2eb4a889f4a3079ae27438000000000000000000000000000000001359e66cf1805c387d83df607965484ed5fbce48fd246e5ef3d8a92429d2c685787fd307c1a78312d877b15d1000fcce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030e8521a520261d7c7ed184d13ffea6db3c87ee4f23e4baf4caadeff8daf0d895c9bb342ff44e705294affbade43bf700000000000000000000000000000000191ffae9e26f21fa6455937226d4aea09cc99b5bc64998d858d7b1d74d7d0ba59d00fc0eb54d84585863086604f6e5a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000067534ffa2d6d6051b121a910201c2a358cd193ff016b32f27284e327f673e086d683480370ed517e72795c76ad93af00000000000000000000000000000000099668b30065dbfbe8178de2f0215c0e3cfd4a1ce0f8d446d9ea419bdf9fe2a555d83984736264dda2a2f214e4f9f5541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000309210e8ec338e365cc2a6f40c50d52dee090b5b17221647f81349632249530a69c618fb5d7ceb1230be1538be30581000000000000000000000000000000000a25848101deead43085ac381da81c76d6528cd95650c74466c58fbfa4cd63a85ce25dbe6b4dddaa0187aae9861c9247", + "Name": "g1msm-64-jwasinger", + "Gas": 170496, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000c5480b6630e8ea29b9be1f9f5dfee8448bb57e0f2c3dd1525db702c3e491b3c1c41875ccbd038e224d42007f571bafa00000000000000000000000000000000047926913cd01d62be5a15bdff074ee02af49d741c9a8e8f32ca608cbaaef7e491fe2fe2bb0375466d2c9512a015e68d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a848aab1c5836b4cf5580353537313468d6d20ff4f7b553ceec8a343da6aeab297e043f6df9f1fb1c05663e5f86ee7000000000000000000000000000000000a6447bb4e711b206608044367d9c9dc079e4d52230b06add2e898cd4b1866fe880edd47cca83329b60f4114a98d933b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000949b16bde26e0863fe55aae62229cfb1c055a4165675150d7661ebfc7bf4f2761479b4cf7b5f71b2c7f633fcc48b3600000000000000000000000000000000001df90ad1bd2ed049867062a13dce7bc9efbb39115fd9428383ce44b0255b0910dd6d1e4df68bc8abf32c994cc43dab81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f559444a4d1acb707f95108cfaca51a38fcf4f503025b125c874ee9043b2e3c03276f7c11a46906f37e8c38af91994000000000000000000000000000000000f97645b0145a62b837afcd0d372c005e948182e2c03fbbd87024f608f647af5ca533b7f81c695fbd85ea75304c176661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4255565aa608df897d02666f5012556fce5bda45314f0e9ee5330bf237987c9ad25a2777d2843d9d741899977afb78000000000000000000000000000000000d226176a17080ed2393c36d00e9850df3d1460d240f639646b667e79f3b72e1c5d7d467031645eb232c056e91268c361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101204298425fd8accc314a26759abd07c310c7700bde2af3e64f88016e400f6235eb3541a246dcaddb4d25fb85f73b8000000000000000000000000000000001344f6307bec6a4d65c2a1d0d42410dff37fcc99922d6087506351430365de64abfefce3c8be2712756f822bd730a76d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171da420c3db1c4cc857028c03371c033c6fccd44a655f9821ae81d8d0ffb16d50ba4dab67100ccf7bff93b33768496500000000000000000000000000000000099a94a3cd9060cbefab383d96d5aa1ecd1bb8b8ec4276b27c0761cc883bcec1bc8e72bc1f0643cb0cfc1efb0641731f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d5a6e20be3a9b9275fab5f417b8840525788069f1790332fcde430f0a347bd012769eff83e19e0b8098b23e7befca40000000000000000000000000000000009e8b35f122e7f87da4daa98c9166d7ca7cdd3c692a16f9812585e079ed632f7446e08223ef5811c426659141722bce81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004fcaf99d25414c157900d9c7f6333a630ce5903e14ac13148ba0fcb8acd0b95f74dab5c8cbcac3285517c93ae0093b4000000000000000000000000000000000b976633dc157ea3852629bb8ba64950f2fa1b7af5f1631ad128d05d27259da04a51bd287081f35d90fe6a391e41bddd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001945649b3aca765a4808884c55e6e823c1a5050e42308066af64238b3ba4bc890e9b4b9cdf78590128c16f81f2621c76000000000000000000000000000000000590e08976aaf099aed416d4b34804fe4a0ffa14abe1235209502acc2c034a2a71be3abdd9c76f3ecbac6417fdbee3211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7a5a107708e163be101bfb382550e740aa834719f3a786afae31829ab2e22ad8d47cbf8c58cbdf2005df9fe2e503370000000000000000000000000000000011eea93709751f42d0b0af0b2eaa23d13dedfa0223df076c39ea3909ffa39f8157d0787a67d8220d05bdc2c4e425602e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c6b305b492bfcbc964c076ca0723a02d58986c206be46680e557d4f34836440791d7df36f3db1e26c4ad66f28c0eea0000000000000000000000000000000009c266b6060df811d1980b2caad6cc4fa7fe9962ef27bd0fc2d543ea5ad8cc9f9948b9bbbac3ea53c3a2577c1f6daf201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000683d7b3e8ca147b372449cde76f2cd083712445f387230fe27013ff8ab56ec2d3f14c56491c7877e8ca8cb0eb9e23d000000000000000000000000000000000087bb3454189c41ddb1c2ab3940ab321b5dd65c4f6d77a18039f3296a40a3a5605d2a1bd866261e55b4dd6994eda77c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055c66f2198b6084c17854de9798919176a2976a2b20832121c4c0617e104ffe0446de55861ed6f53506dc19d5c89ca90000000000000000000000000000000014e5082c30310fce95a4df7f1acade2965e1e32291703b9b3f1ee106397062a4f93119ef60e0f6aaf01a270722d0eb881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d7da98a4419960126f7602ddb2322734198deaa678bef3dc8fa0da48d87b5485b95bc067eb9ecc01b66300c6296d8b0000000000000000000000000000000002e2ba5c2adab840ac9bf4a059666c8f2b94964406056e41deccb029a8803461dad456e96c6bd974197f0d561f164c871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159e13355d7750722aa48972dec63e6b0fab20468ebabcc6a538ee100b844f30081c1fada27cc9114a93d7ed14aa95f6000000000000000000000000000000000488b731423ea5800c2397a288c0446257e47d5e1b3f8cf3a1389926bcc95e78fe5b2dad79b14ff233558780fc54aaa91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b445c0e6b0a4bf64ac4b45cbffa9196bae9f293c1c8bb0de4ce96cdacfccd20a5c65fae13461e508289cbc73a6f17390000000000000000000000000000000002175b24a1080f80f50180380488ece7c621f5a31db2b6f292294cbe60d9bebbf90051df5f6cfc9f6bf6c1d26a94e4f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001530640ae99b6f7ae02d567e060fa469fcbd87131253c8cee12d8e891d44ecded5930f631463e6ab37a2afb6b511de160000000000000000000000000000000017acae258af502adc7032283528f93cdcee1d6acfe4dde7cb975c9901967df5489b4a1aaab4dfc80f0253c71ffb4d3d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b989d2e41669309b950d1ffe78e89ac89fa83e31b5dae07ea98281552127332fef3429c25a2c72e6d60c28808e83650000000000000000000000000000000008644b074a3617e5c18af53b663829bfb45fe5a4762be00aecfd261e6204fdcc107ff879a21a06f5c8ae71b1a5b8c1ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc0a0d1d8eff56b7790169dacf460e8e04cb7f0fc6403a6a4076809ec2e9f1d685d95302b27fed5d33f5266fab232110000000000000000000000000000000006c6a8fcb415e40fecce608fa512e19ff3a76ab275dfaf10048593e5e768105d3580219b58b3e207ea0eb102944c0da11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001192ac337801cf127720be76f2759775b4ce93cfe1aab197d41c1b7d5e493b9b5ff3551f0131a14c570dbc2dc1b7fc6c00000000000000000000000000000000104df98d3a176363626edb1be59d7bf41a5c65db7d10ed525ffdab53930d117a578e3c82ab3bfe4bc8db5e1c0b71d3c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015cbf252fe6e6326259358dc3be5326299153dea508e3443497198dd93d65bdff71cad3c62c8b63512286fb079295f3e0000000000000000000000000000000011d12d816fbf1dcb6c3ab25954d3325e23793aaff8d9a67840225eafb9c970b03afecae5d123dde39b46e4834eca7cfa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c24263947f211cc1a43436372fb03aa38c0862b7db7b7b7d4873dab6ec808b09830d756341cd5121a49d0b16f94f37f0000000000000000000000000000000003fc7db117cb0c3bc9d9c87520ac8fd395d4ab9196b9f950368b828d8c471e980c6580f40bd4686d3f9a3990aeb440301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e676ae3eed4902ae9461a2721676f1c2b8f5dd581d297b014e6c902764211c4fe0dee198f993a48b76fcdcaedc3e26000000000000000000000000000000000689bb44e55f2c0e1a13a4715234f061e2f1c23320f928fa34a16dddf82b4daaacb53afbfa52786999e4005e70b33d6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131a0d6a8e04ce117d72617b6690f31c1e4cbff089eb11caef1bf5c83c5d7d734202e4957f980fcd3e725209fa36bd91000000000000000000000000000000001405ea86e271b1e9e3e8a15cc11889531a3de0acd7c4615f36b596948a778c60eda6b848e7e2391390571d15aabce5661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001937c1a27812904597dc98529aa58c683d42a967084125a9b825cee425ed97ff4e62eba34172d99e7445b2b4301c4100000000000000000000000000000000000c07e417024e855438ea693070b8598518e9718756da1e2dd9289b98c3f9e6e0d4fb44cd6d34106136d4b56a839a43481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153aed91e2393c7214eb89a2fa07b05c9676a468c1bea72eff7c2aa915b68c6da473d685af7eef186e1455c5ee0252ac0000000000000000000000000000000007739bb486df8e3980f99e9ebdaa2df021d912ab0c2c4c5364ac5cfcada2a53af28d61b16fb3f9d152e423dc7f3f9e771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8d0453b54b297745e37ac3072971e5d9158f5da9cd2832304b563bf0b419f567ee4285cd380e5f4b6e2fb07e3b8ee30000000000000000000000000000000011825d458232f1e4bd05354de1b249f3d1bb6a6c439efc3b89e3871a64f4e23bd96bce719d914a9c998f8d5105874f801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010c2c14d8bd7a5ba678290b6f1fe778a89ea3979fb0c854876c463e08ab707094687c1a4b490d70bdab16affa7ecfb6000000000000000000000000000000000fa5b3af935f27cf94f3ac95dc9df7168828662a02e14afe567e99030a8007216452846c2b2a88e7ade88e249fd2b08b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb480355c08747b7c7d0ae67205140d0c23d9e55b27ec71b4509d7f1369229c0f0de34c1c9f0e9f62b48d887718359c0000000000000000000000000000000007c528d3dc229827ce226d57269cd0179b6158a9d595ce03f5186e7ac7e0303e79d223256732a1c0ea8016a2bd0ada841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019853f29c1525a17855e599bc58a3a608114b88161f958befe011128c41bc11eaa4d8a2262a9cbf134f2dee805d53a78000000000000000000000000000000000eaca01e1a371a98f99183818231d64617ab4baa5c8b5f65d7c0dae181cfb22b3ed598ec30fe386bed02181ecd6193e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e9a661bcfc5dd0aecf9ffe76a39d2aa69d7133520bfd11d9035165c172e139b66e6e75371f2d7d8c14ac597a44c3e000000000000000000000000000000000175c348c556914a2b5be9541491d15b8beefc5650671a5c59a3114ea765ad7b3664cb4528be29f3c13a74ae3ea5dcdea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008263f247e53acebb9e8ee2ad62a1570a79592b0818954cace7a42b31d56f9d29a503c6d691a98a95a730c8ab70efa920000000000000000000000000000000015192c3b4811ed3cbd780a99e426fbfb5d4baf2f6356a0e2243f88db2ba040004ba5406210f3af95b55ad4e5559f06ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000830402bb71ba8c3a80a671f43e5895c5408500e86e78c9b2b44cffb1c114a8a540b7ab0289b0480a8e21f63a81ea4c700000000000000000000000000000000163178b27ca33cf677d29544e4703ab318cebcc368621bbeb4d675c54371ab9386ae647932da145e2f14ecddd4709fae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000187aea5bf912fd9310f0f33e3a3561251222e5a6f8d5ab3b9343b650833410f7454e4220126dc4cb42ecc1f52ad9bb100000000000000000000000000000000042b88af46faf8ab9238af620b3fa24c843f113abe64e111c1c6dc41b2bd5b12d3b263220bae37ee93f6ace35b551c301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000070b5c0689bcdc704c21a1c68c30174e6693f85ad1a8911dcae5d54c19f76de872532e7bc32c890d4ed4f1ee91049fb5000000000000000000000000000000000fcf4d51d573613b868ca4c30e97d581a213d731fa4861a88ba08eedf0ab42592fa5bf3d7a0a4bde07039791a508e1781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a47ec3f54f7e5f864079838c7c0598248ec65cedae64cedf0928ca8062c90f6dcaf568093e7f54e422d1d90fc413e05000000000000000000000000000000000c25b6fa4ac33e6500827854763bedddc496bd32fed1648f84ab35f17d28c15b679980cd2a4da94184acc7a31a2dd6ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb57366230a1d93541bc324a8df1ff5ce78e29ddf7fd431da4d4ab9723f364e7ff22fea276a2561fc95f4240af5c6f70000000000000000000000000000000009fb56d7d74acfafff1de7c5d4f6ca88c641f197b7ada7e713716d645b58e749db9d9c44062da7957b0826c0d6f5c2601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a20462240b3bf33808f0ce013fcc2926a6c6d747641fcc3108d059e29d6670ee529186a348fb7ea120d5d9ca915fc00000000000000000000000000000000007462373259bb48c1b74e5d9fb44166226482c9e035111ffeaf953c41c1260f7bae9abef840353c280e1785ff143053e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f56ba68c344ad1ffa0a93459cb18b9f0102f2ff64c7f723c4bd50b6c7a3a37fd39d12d324286a4e92c0a3c31412874d000000000000000000000000000000000a2446d990125492368c0f73a19a4bc8d48ea87bc5cd94eea8086d684ddfaa553027073586fb247dac03d53cda512fea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138b3d5074d75dac121b6493a1a1948452fd794d6533175dd09147083891ae20f0dc8885cce542907335eac8227680ce00000000000000000000000000000000097ea343b5b29dc13b45abda615051f3c20fff3e868cace370ca1581ee09e6499a15c6b2aa1db04c1a9addf0ebf7d8601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dbffc6892b2da7856614022847eecf24bf9407dfe083e475bf47a9ccc516d66181abb987370cfc12d330f841e85da400000000000000000000000000000000140be000f7262f4de8aba77c2089c5754e9056cf7d7dd7f3f9697f030dd6317a71fcf185a3bf7ed6e6706cbdf6a379f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069d5e397f3052864ab34769de5a1e6f11f70a56bddc16f38090b5276a18f64bc390e6d24f62cdc828c2480843d2353f00000000000000000000000000000000146c37055a35c25ecdff41dbd7072c2896b672abda99df9f586d568647666b3008f1e99c83fee059ccbe6064ec05fcfa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017aa3d2fc424eff0c4c6d5fd28b76f3add6280c8c45317ffb756e92d4215869e209e1b563d62faa0f3615d9d28901f750000000000000000000000000000000005cfdfff01a093011726116319da6c3aad8c5d4670f2690cc714f4c8f517eff9f65c003db9ff38497a2a2e1cb5f28a2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a54b293ea8832f8098f8f837d02a4db2df41ac341ff3eecf6814f0c6ca8e94b7799ebdf10ff3d76c38c5e7785bdef500000000000000000000000000000000093768bab8fd54f3c2de804c7b12d504c8b4b8e09e175371aaf3d439e5acd361e93b9373d4991f2648606c278bc05caf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f696927237ec7907f0bfd6e263bccb1c3c83921dc45276afc0a1733fab76f6aa992a95109cb28775f450d650017f450000000000000000000000000000000000597866ac4f8763a2f313242919f176ba631da5653c8bf855b277bb6caf761329a2ff1a15d255863b8be9c89ee5c9d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ace497cce932aabeb3550eb3a16bfa3a3585f07e18ac78576fb2021f7f8905a2843d8daa5f8cd00eeb7a9f6e7a4ec4000000000000000000000000000000000f0381894f0ba7347bc883a3a193e605fad9cb90ed809ed53539ad2ae5d119a0c9f2367bda6f70632a91e58c371ba2a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001623e86bdca29cb30dfad0404e8f23d4af7dcec514898aefb9369ea54df9801070aa1181df0a4416461061cb01b2256b00000000000000000000000000000000025907568042fb7ed12f60dbe3059545b80b519736b35c44dcfbf2f03991a95e28c42e7cf66eb25712dfbc236fd3484a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178df93ba13f174a15e7fb353112cc6742bd6b02b0a251b129e756b7b9a2f288bd71edf043d63957baceda1132086d00000000000000000000000000000000001340e15f0f105f545335e8887713ecee646d2cbe88703fc45634fb47e5fe3d0fc54f5cc7f5743bab52b701974e96d3ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea00023ef3ae135e56292f9e57214fee8f95c36d83cae2373028bb1c79c7ac56461beb0b2a487227671f94f3223dcba0000000000000000000000000000000004ecbaccfc0d18221b0508e8decd2f768d943c72df434b7b5ad1164d389d029e5af92033462e4d8fc952f921f29924e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066e8d506698a3a6502be6e5161170fc95aa564542b80b2646a17cc8a28ada3e810d8e771f5fe882d1e3e807a8ebf28d0000000000000000000000000000000007ddbf57c8f5b84462cdd6b8f5c35eed611f7d8898a27ca6a10e5905a455b189b7ce261cac235f8c8661ccaa43ee6cc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f23bc58d2e2d3932f2523425ba88bc4f617ebf4a9c43620bc3e5fa004b8fd74d828889282de7bfcd14d7ec1dd1685280000000000000000000000000000000007b97338c3b74026c05b9219be54d263794dec1e88bf32b100560967793100daa796bdc555b23c39db47a6238713ae161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bffac74360b4abe2df341e2186ca5c6dcd1f2d2aa6d007751c3fe137af242dca90a044d78e4147a08869aa6f5c5795f00000000000000000000000000000000174b0ba5580b08c8b98f3b6baed836aef9f5a660ae320a7316de90897e009cbd6cff7401fa8f2f7d8c6e872fc12271081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014e80a5a30447d87159fe0d0423f31ce32ef0d02eada7c26e033192507527dee2de39167e417afb17fd12e7d7a87f6e000000000000000000000000000000000dd14b5e3c83f5f28035327a45e8fd568d6215c6721efc5de6c74e30ea901aeba92a126f33814755dbee8adea1a30d9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cfc4e1a1299c5f9dfbf62f172d6315262127b5aeb525d18fb48c0702b5cc56341cbbfc8eba45a3f548fa6c7ecfdf8f0000000000000000000000000000000013bab2a6247dece4c1c0763f59033fee17a6089f0c59c438a76a2cad53d92f8ac2859df64d1bfd31e1ae0f2e0ff8e6ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c62abc02febfccea7074b67eada8e125c914146d429d00d88af296ac95a91d82dcbe23782d127375f2281c4e3b222a000000000000000000000000000000000cb11999c68cc3c22174e87ddc502a77f84e34033bcdf7ca9a4d339de16c72218667ae481e6c77eba593fff22c354a4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001470aa725bc9a350efde69e6da97b83a60f62eb46592fa315121d2f2cecc1628c3e0edba70068fe1515ec2a4c6dcfce70000000000000000000000000000000001ffa071cebe850e635d6e6a65d80c58ac33450d8eb7ef4e4a8f854db42bcb3074cb6043d289a76102516a2aa076dade1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012385bb137c75bdcfcafacc28a893dfc3610baaba443c3de7ada4f5b7c88f1b8cae01bc6f9ba2a1e58bf861976d727a9000000000000000000000000000000001338663ad434c70a8646786b72c75361ee19afcdd897c731ef5d15085e34f53c3e361972f3622d9bcc1b21c599430e071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073d86263ca62df5e3b5cfb9f252ae188c04e163c65cbc25e686f44c44d3ed2e3f9c53a15ede2fa687afd4e7f96f5e860000000000000000000000000000000014b7dce0a57c372ac6c7304a0c370207f937f036acdb20c5da71e3fcb80fd7dbccf2926a2440f9ac982a07d48fe018ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124c5808cd59ec0c8a8b983c5ec7ea83e5deb78834074d9922f481db41d4ff56b9fa43d06fa7790939b19ff6c7a7ec920000000000000000000000000000000010f77bc4cf326c5643fe1e993126f28b50342b8533aa74e0503430efb3904a9a019d64772af771db170947f6b2f879bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c443a3a96a150ee100cd8b2ad210cb74ae3b55e9847baed30db5a77db8d5f2f5f5214a24c991e6736149c949945348000000000000000000000000000000001176754d10b03fdc72defb70965b9c93675ff462840ab847bc86ad0f22db926017d690238d60516e644da12bb28db7151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000354b4c8fabfbce771dfee456a6f3ddbac34233941d542f5560dec63850be517642bed05dff650b48a08b3f71bf44e3f00000000000000000000000000000000182d999a39f4cb1ac0a3bd4ea8b9944c42e939d3bb65fe2027a0ebb80185456730e92bbc73efeb37c3e50179bef79bfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061181c505d50b7ad186666f440254a45934a07acb7980827ab75351b3cd774955ad809dd01be7823a5cc54f7a8568790000000000000000000000000000000015113397f83bf687bc98ca924243708b1dd630321203cb5c59674898f1d45a1afdc29196c7ddacbcae1a54435421d7361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001382d7b57154c8ae004b9ff7b4d23bb4b078f4d113ba4a74ad6fb3d1a9da1941fe2c48a06df0a3f386d959fc266809c500000000000000000000000000000000060efd96f4cabc14b0551c4ab423ce035bfbbf055248fbadcf51951b6c858ffd831b31a7f7113bce1c6b6f5adad4ed781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf9d7391463d8fa2c236804467fb550e75bba19925b182992497df5fd76f667024929ca7b530ba2d9c2db1b8b2e4f0d00000000000000000000000000000000098d659bd1a414f5e5876e4b93c449b944cd192787f7da37d6f76caf235ed7a883e6f9a151bde8cba4b907694b4d96bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055be45ce5724fef196b7f9fdd05ed77b6b6ad1b7c01094ef11c8a34eb06f396dc005fc5e1a4cb0643f4fc568431a9ee0000000000000000000000000000000008c8db9eab64aa258b5feeae6a8643fa01c2d144a8daa38cdb25530eb27309f40bf4d9ab6efba79c28c71483600fbb7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047fa198d37144b81772eea5ef6026a142ad55da7141f2e022d3d377d57a003d6c5842101ba37f3594765d858e1e34cb00000000000000000000000000000000030a81129b1ad9d634ae8cfe75e6eafd9e03ac6bb9c77deeef6032bbfb4c78601c540c02d895f9b438f6b4980a4d57a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000dd142bf9ba8b29665fc93aa8267a38da28793bf3713c2abb2c2c2eed031a309cdd0050082c05d47bc5ff8334084d420000000000000000000000000000000002fd0f2f1767f981270a99ce85322cc163b02899b4150cba8613289e9253379a2741a953ec4dfa7e5a5f91abb171584c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000756ade17b13266f113794fe759603940b8575fb0b471fc76b2f5660494f7e6060bb641f41078754b4992855b75d28f20000000000000000000000000000000003d2b76534296b232e9465c87838e1eab335ab56d50fa83c4fe851285ab348c960566087c4999ce3f91a0ef41671dc191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000817b860b283f015efda3c3fc94841ca0f80bd8a51af1aa1627238cab0ccc89f35381152de8d46b1cc4635554b05fb900000000000000000000000000000000091f3c27bba08c11888b9159241eae16159ee9ebac991966e1f8b30793c881e2384002b3f7dc576813ba17c9f8d31d441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159ac51e7a570b2a76a7ec09f8d30f26536faa7e5653af02b6ab345d3a4bb0bb03e802957636cff8f5cb80260463dedb00000000000000000000000000000000075949c6fea9dd0632b6294906a2b2626fc5ff44db38af721875b854c1f0cf53ea9b52b62ba6c6ba901b341564b40b4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013543adfa19cfe28e1a0ecdd22e00fec78dd23c26ade476b03310ff1366e690e9053101d37b1efb5fa7602e7cd190aca00000000000000000000000000000000102ce60bb32672f821bf84da26c840147fd26692afba5fd44f404f3130178a2a4ae6240880a3c752c3a0e9b080fb194a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c62734a97a613f99b322798f0595390c0846e00c44e428d4a27c49067657ce65ea51503d49c873aee4c0be7e1269eab0000000000000000000000000000000014ded13784f741a5bb86affbd116b2076e8850ae7035a7e6bc2a1787e79d728c71d6c5c4ea6e8e11c344ff9bc772cc491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e8297973d21679f615ff0dcb30bea4dc334c54b1281f8477d6994274cb0d88dd695168fe749ec0ba2b87ad2957e4910000000000000000000000000000000006dc6e3e85b2873df12cb062eee346b598015c6ffb8ee977d88c1e527e2d032accbe4cc1b22c9dedb1d998c0c4a9ba161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174c9bda7fa709e34c20f4e6c30a2ee061138e217ec875da0929c24f1f053827e5d9b9587375a72a16e8ac9ec7c58a0400000000000000000000000000000000060297f36587a5101dc81553501dd0b2ee83edbdaa62b0d746412e933f08ad6434efcd9200e7d40b3dcba0956bf5e6511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f948300fd46043100d912c2fcdce98d03aeb922f194c9054d2a3350fbce5aa2acbfef9f68a916bb17372a7728e9181e00000000000000000000000000000000120feeb6b93703157494252c97172ae33665d0bf8a68ce79912bc9f6d2ab38a69adf6a7e6c45f43ae592ddca996593e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094df65b2da7d84c3d7220d02f46a7cba5404393f5417ad3e1861a9e6a3cf33001fa1968787003aa9c61a1dc39a3184200000000000000000000000000000000030e177042970eaeae4dfce6ffcf696e42a9e9e7c0e89ca24b26586006ef0b0e6bd0266df7221092e059f296bece616e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc76c7805aadb1d6ba7baf59063331789e335e0f4766acf70aeaab85cd0a772549e3f74c221c3c3cacc3816d1d13846000000000000000000000000000000001690707236cbaaf153ab847c8c9db49a8012f685f1a6af929884d10ce4faac84d99d1b114a1f31ccfc7447f8f906ab191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1b1a07b76165a39b681a24e1abc6317992ef11eb633a76285aba187bafb87ee3b188464e4312f140d537da0d7c923b000000000000000000000000000000001413de60945b4a97b8c4ac1dfa77f82347f2f362ec2f5bd9901148537a7a3250998c347500fccb3a635afa0ac627d9d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f29ddae9bf285ba25616fc47c09602915d4e456c6547895e8c444276de172201b3f929cd00cb3027c91f384f76b8a9300000000000000000000000000000000073eff1f50b49401e64180da721d05efb210e524ee8c2abaad9eb1bbcb08b6b48223c7ed862d7d982f9340caa46fcccd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c92ae3dfcec8bd5a900d3c00d865381b79799f285207572c16cc42b32f3950c5e81dea53da59fc6b4e0dbfede33a5d00000000000000000000000000000000026a42dff50043a54ed3ed9f45a6505da23e57d7eeadec17a02e621a34807e793de18e2d18b5ec2a061231cb69288c081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030ec12c249fb0864b634f6362bae857bc58126399b288561cc0177aed60f8642a012b21b4ca8f0fade406c8427d6ca3000000000000000000000000000000000c93341af6191ec7f0782829f5ded8f655055018db92c457e0afdf59a0153c5ee4fe3aa44940cf17787db1e5d8b188531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e7f02e6a62131eb674c31f6cf54b60faa76f4a130eaa5d9b68654263393d50d87fdcdd9c2dbf3a6f9c7bf782ac38ce000000000000000000000000000000000475883b0291d994433c68432456713e516f8239b858bb6c69bd2391be2ffdaba67bdc9d2c5de7b8a70cbbadec082f5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d97377679fb476d638e3cf45a53ace740d5fecbe63e779a0fe776395b5ce58e5f613c218b8f2daef86f237a3ccb63680000000000000000000000000000000014b6e926e8a684e456196a1b9863b3244d9435971fad5ae4481097853a2d7acceb076e11bf5fa6aaecb0f5e9a202d5581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023cf11b7628a09dbdac7f1705ee41f5964da20ba3636131c4b457cfa73dfeee289d594f7e49078c4a6efd6e754f8e88000000000000000000000000000000000b0b5e86eebc0b9b035bf7b81e11dd0ba96c42c779206c6f10aa84deab4086131cf18b5163a165e98aa28ab888d1d4a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d432a0f9d84f09f477478b300a6fb73d628841d25b2798940f46a35869a7c5a709fc36221a25a5486391a2aa9d5e6a9000000000000000000000000000000000e0a014adea49a370b26d7bc92eced309e56805bbab54964ece4cdb88d5e426a799cb79b05df9cedd8d0174dea269b591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076be0a1e3a47d9674ecbcfcee00f25966f31a09d3efdd8b32c6f5223c1360af038e6e9b51cb85522573306ad9d866400000000000000000000000000000000018bf6e9a4cc5f653971378ccfd1d4bb7111b8044ea9a22f599913b77011d044dffb5994dc65315fb63f8e01c2c07a8b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b0e7d820e0ee2b64bdda08de7211ec1aa60780c7d879549d3c9d24fecbc808c9b0ffdeac5845afee43cb6d0ce910c500000000000000000000000000000000144c3e848b78149f4cc7f746a3acd35947867dc8f9ded8e62136ccc089e7dabf4c7990e0efde2588eb5fc27284240a3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125de1e555e7179a8c1ac056181c3e65de8ed40b05a33184e342532a29471032a757f58843f22b7239d7dd4170a577880000000000000000000000000000000006ed91ec7fa76fe2762b3fd852c24af455c7e5dfd512b69f4f0a9cc841e6b8330892cd221159dd14809a9fbb8af2061d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ec697fea121a7a857b03c0fc04badfab45be46fb0d1aedcedc3fa2a9bc63a59e2f165971cee7fa44fe6c8b8ebe5bd8000000000000000000000000000000000eb81bada054f66f2f296db5331e9cf6f01d08c322f2314642111647981fc8fa87a0104260f32a7b2626f801285ff4bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6d609732c1e4d59dbf1f4de887c425807a0baf6b16d0a276c00fb6eef63a6781ffaa9245a3c92a2afe82ab5d2d63db000000000000000000000000000000000fb962cacb7d9ddca818fd32ca967aa6290b6dea5b7ef25f510ef2568f4c35bcd24ac2dc1b0aa90cb00bf16a0447184f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001268f0f881951ee6e5910590b7ab6a281182c23d76ac5a587f81930e4910108d39e00062b0dca6e222b310e5db291f3d000000000000000000000000000000000e300432392b01194e1254dc24b55435cde006b90fa9ccdbce23df38c70ed542129e4cd9266173ad59cd79b356d569031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017eb7626c50f5112686189e79cc02f794eaf95f7d3956272671de3b213b430b0adc27709e05f766ecee13ffd632701d9000000000000000000000000000000001438ca26728331fdcd9f123155110ec0ccf5377083a36f53072b4ecde5bb5629e49b1f950c721d13b9159337f1c654d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147f9a60f39dd3c57535670cbbbe35a2431a0b7057a095f2ec1912b283623bf35c88c72812cbe9bcd6afdfdb8d771b780000000000000000000000000000000006384a53be7a7461b63d44c6d8695cc3c094d740e77b49f83ce139e16a1a52fcd0b955b3222283079f8e34a7828f277c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091d7f7647f153ce3359e1a5916609b3c2b2218ed231119863ac6ffc963fd0524918f95abc42657050fcc1b52e031dac0000000000000000000000000000000012e3bd2a080878d8c7997cc7954360c69e655618126869bf9e821c96134570e239cf1086d3d3a848cecfff143be11be51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000941ba4790f818a40f9ab6d8eddb472094cf1b871c31546db996440dc44fb40dd53d5e793f8ddfb229a86aede4e2e124000000000000000000000000000000001951350a2daf2b8032c4c86a4459b5aac53bd34eae7f2a205dc196b4e5d5fcc31bc9c927d8ac130419be5196a95faac01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000435b643c0f8649b5022636f417f2c85f3b693ee745ad0fd3cbd0ce49ab92aa4908d2a43d9576e2ee66929b5680520000000000000000000000000000000000014f17faafd9eb0ef53949d3d8bdf6d3ed3e2e62872cb442e1797c5e33b2b74e3498832c81ea7abaf2e9058b536d01dda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001626ec647136e5a3c99addc3da8ddf6441e0fd9755e21eda3fb24c9c97e3e8538612d1bf1fb4d30675d557bf68f9aa39000000000000000000000000000000000fe8a3a9551566cce18353d298d07d0933038d01b20d7d6d1527611ede74ee41d9e377dacfea7f674ffdd653b0b0db431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014066ca915fd121b492a641cfd6775afe8989c295e80f2973d73ede12d308a39e2277430f69da1e7e9668a503d1e2aca0000000000000000000000000000000013e4d7bb49670752dbce18960c68745074bb83d65596bc4b1b5526a8cfacdf29b0ab733d00c68084a6c6b9c4a10e1fca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2b5b1dfa6c862a7d744ceaf5d9a0ac50171c65902d5ea4f8aaff191b16871d111b0df71af9f6cc4c736ef6e07737f80000000000000000000000000000000012faae303cc7671757b7ff54535496b7b9786daf3cf29ac889f3ea9bb02d8ce3e08e7d303792ea6a4fa2cbb70e871a691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb13351c1c0ea62191f374be76af4ee5c22dc16b319370fcf7979f4dc32d827e29372c51effe5af00a5aa90a2e1f3120000000000000000000000000000000011d5d0edc8ed1c32904066960cb45742634a2fd2d6255ef7f684f4209fa11aedf1136e62bed4833f70b5dd6cd2625fa51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059c9b124468d9b3140d96968ebe941740d83f7f3ec25f30cb60a0e225fda6d602d6d4c24f0616371f3eb0351223ad1a0000000000000000000000000000000005431a5239a2323f7e5d9fb5f1b2d37deecc5b3f36681bc276815c4789f8a64a2df096076b8d71c2afda0ccc1fff2bbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065ec66fa8fe5733632d7d1f8e3a33a43253216b6a8553bca343135d9b2a23a006f6888fd3dbe3ff7ffaa11f121579af000000000000000000000000000000000faf956425898eca3bba05de3f2e16b2317c5e5d0859c994ae19ccccb5928dc1bb2f28fbd01bb5e14aa56228b340fecf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123e76aa159de76973189bd61a534478fc3b95e0ee624f274efe88412c586d346c4a80413192c984906fb8ff863e30d6000000000000000000000000000000001184caf5c11bd8c0297be777d4031262359dfff9985f44886d04dd89a313f7ef260c116c09f8271704fd675e86af61021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a970130ea6687b1f78dd35e806e8351c8f94bd4ea11edf443ab123b6d925c8e969d14d3af678191e9a989e857794570000000000000000000000000000000006ba1eac93c64d2f1f4d7becfb4e54e980d06359227f1ee252f7601acb92534721caac1e7577483702daed4794e600461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015eb7dda73051d38bcd81ff2a714aec3d4237c5d249c2dfe371a616a6106f0fc7838f078ec5fcfd9b4a92ab0a74e88590000000000000000000000000000000009b90175986bd7f8d4f59934e43e1dbca0b82ade7b8183c9dfa8a92e402c9661292b14df9397b4682607847c80ced04f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c781c3220e6af8053c37cf618d873b2565412a46a22ffd287f4fbeb53128b650ae27c3bc733dc876032a84aeae5f3d0000000000000000000000000000000018bc178ae0cd72ca2ccda209beb00f0cdab57ffd21de96ebd223e0889259f26cebe46c78155feba7f08fb539503d97fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9b0aff8bcd594e93d18dda1dbbd87679b9c3229f31a1870c05db6259effefd4f2acfe7e45deec67abf7ad7d639f9be0000000000000000000000000000000000b0b80f3e69b1d0ff25cb408c60ad7fb4be1cedb7f8b9dd7191c34d4b431fedac16931e7bbac6f1aa56846ea6124a491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c75c201e3566f5339b348afd507f7cf493b06196ed6a0f3d759965ed150d5965b21d7ce9759c4469221a4a2abfad08f0000000000000000000000000000000011e4fd017d8662af3c43c2f44947ecfa4eaaf7f50acd118c31c1cb18b97a079e4c953a2b02fa8b9f578a647eac3504af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d385e2272e1ca0eb0bb277e8fa4d14d389d5afecd2fde5acc190b8064f00db86eb7448f689b715be1c0d12eedc49b1d000000000000000000000000000000000f65219f49edb0cff554a855876d35249506d0b3fa661554cf0eff6669b6ef4378a18fe3db036585fb3be7e10f0ca37b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018442d56243760a3626f5b7229a2781a75c8c065a62e08ff31998e9dfa1219c0deffecfed7b49cfae62b2c85e1bb69a7000000000000000000000000000000000602d343d66a31506854ec098687ca37cae56a8342476e03031c114cbbfb3997fa0242e398dd20b7b03ef101d75d545b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006503251371051bff87953ecab736c79460621aaba525147299564c8dd9786b275f0e1b3dd83e11d88e87d419c3b4905000000000000000000000000000000001000a46855e30b3b2ffd72f274492ed17cc928ebb3e13ec70baeff4085af77ad1da1bf9592f2fe77bb545c1577261a991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf9cbc1cdf529ba9bc2c73df19215b51c17e4981a56bdf0d70efa0139a5284ba5b83f9e8a2b2e3b9f5520b28f75461400000000000000000000000000000000056083fd07895550ed357268ea99ccb1f8cc1f4162cf1e31f292b211cf390498da96994ab09a41a4ebcc1934f3bbb9081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000552a248cf05063a0c015c9c50780c15aac8503fb97eabea39d919787d0b171aff25d4b54672cd77ad909030c28490d80000000000000000000000000000000019f07da6f9b45c81edd091024573a6d3d6a1d2213e48b3b8d14afeeeede3d8c594ef00f0a513435dd2e6b9be7df915381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010becb4288d7da4afeae7c38544bb4c24e739551b496efb156664ed85e5476e4a25ed5b82406281df62a82bf217d4690000000000000000000000000000000000d7acfa535482f9a996528f183167fe20a5aa8b8807efe26f031ecaba7df0cd4b6c580d55dc10dbb9b4667c57643bf9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170e2c50f93455b0bb8dcbb204260a972c069578c826b18f7d582c241ad636cc8f239234dea1e2dd15d9c207d533890800000000000000000000000000000000007a2b7a9519f4f7a83145cf788276cb5f0d4d85a6dc40c920562ad3c55c8349c574cbfee66fe2a8d7d8e34c68cf757e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010859221a09529e649271a611dbe66e0757cdeac80ec9aab8c67ae2288de55164b548e53943d4d89adb6699a2c54fad0000000000000000000000000000000005ecf6b8f62e4979a204e3cbddbf61e541f414f097c68d4bc5f631bcf45399b2ddd5b42d327bc8af9d2f165dfa99f8491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005cdc9d8182933d451f6c9c18e1cb4e3a751d0c8cc8bc48d5170370525319bcfe8cd0407fb5b67185d4854e2892352e60000000000000000000000000000000005fa283ceca6e0c8d5efea2b3ffe472473df97974c3ad4fa71c9f7065e67f2d99ea31d6df4ed6ae035e7ffa15583c32c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024efcdd1a52460fcc73fbb1129680875db0c803c99506500b72be4d1e174cd4bb9304ed977f4e421b33690e0d379c0900000000000000000000000000000000095a3da5274e6dfd84075ba4634079e92f51506a9b9c8468109d2ece6a6bc70ee2b23d290618b9755051e0c588b825e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001411f71c1e2cc1c13e7ae6019a3d3d388e8887c330620400cab7d27311c12e00e750311dd57df98d2273bd6a6434483a0000000000000000000000000000000011524602625fab1bff2163e8c604f4cbcf5b60030258eec26769892e1c5fabe3e85db8629dd01415b1286b057820bf6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8df76ffd22184b758f46543acf391431d495195bb6c2b075ba40d4c6600dc4f5e801a3176e690fdecf8bb229e0a57a000000000000000000000000000000000f36ada6593e8794e64e1fd92f3800efcba0890e4cd2d88ee0630a1dc5ee36414fb4f6a130ec000cfb83d3abee51f9341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006303067d821451b8486726356653adf804822e64b48c9f1e638b233609ecfa7de746666b3eaec579bb073a307dfbea20000000000000000000000000000000005963d626a69aaa6f223a0a37484b93570b4b48814cce7fec80cce1d53f3d0195e2cf5243e29d2c0aaebf90aa06b41fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008938e2462116b46660a554da49d142d91911594fafb3f59b8dfd4a2227c6b1740bf73017e9a9d924905c2127279d2fd00000000000000000000000000000000197af39dfdfc069a5b16ba0132ac0eef537eda857129afae5e734d14e7fba757c73c35da7a4235ba869e47b68d1496dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029c053bd75501b53040c29f4011040f9b8a788d0d42e08693b34617d14c690f0a7120cecfd05f03277180ba9f8499b90000000000000000000000000000000017c68c5dd28027a224f5b154341dee627b7e6ba5fadbf7dc98c9856d6cbeb83dfc6a6787e65511ddcee8b67585cac9b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de018041f374f1af7c62cc274302a993f68a19a4fadc802fe3b4a92b6b99f37092fefb1ecb1707a7934c2ca496de93b000000000000000000000000000000000f15b67bce44bcf7a9ecbef85a1dced3e97b40fef7cd2b50882575a1fbacceb2100b04bc0355e97670b91fe0e4633e9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b616be1eff6bc9143ab0abe85cb2b570299d4c1043fbf81953b27bae9dec41724dccc021d5656949ff69ebb3f706090000000000000000000000000000000013f6c8e291c403409364f3c1b11341e2ea5f116382cfb5924bc990fb37eea8b216281c19baae9ba35b302fcf49904f531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bd8db07495979ed877083dd762ce13b2c11fcf844a81568a7cbe5fe9d44924aa900608fd99dd3a4b1a6060e8d90a4a00000000000000000000000000000000119f344c29facb2f2c4f4935d306b35f21e06707040240ffb32ccb5edd957250f1d37602b709666a998be8d7f7a48f661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fac986db92e9d773839f284ce6d375f6116c8c32cf9107bf0e06c15f8b9047f57662d5e7f48bd0214dd8ea026edbf400000000000000000000000000000000114e3b385de38f6a58b76921a6afcf3044853e9cc1d347bf2242568c29b4181dbdbf84173bb77a36132392af4f29fc1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000013c13e6b9cb5bbe9a8f57821b678c05f59e116fcdabb685efeaacdc1bb104070904957a92db532c1ae19c65feadb8d4e00000000000000000000000000000000016e21f441248197ab403faec9c697f2fce2f87a5fe9075d1fe7e692328b6432e76ab0f2110d60ddc2acd6f8a860d9ec", + "Name": "g1msm-128-jwasinger", + "Gas": 267264, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000009e91d6cfc75742ba2c1bed7bd1b2e1d74bd8d0f8732ee61ff502cb1932cfebee7fe27a8035f4b4d8ddf9cbd9dc66bd00000000000000000000000000000000005c4296ef1764dd57749d77934c658944b76cf80fba6ae676c600fb21fd984d31d1307eaf6bae8683c2c892667dccaa21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f2550cd304ed573cce9425b7820918763e6e3c4be889bada5f91f8683493a38a8a3b0ff0d9762847ef148f2e701b8300000000000000000000000000000000125bcaf1a655a70f34598289f2740abc71a6483876f8da1bf3a9c4b43b09082fb759be3c87b181ae6115bd9c01a622d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5fed071727d16baee9897951aa81bae719f71b3f5a57c3bf2ed1df6c0e8c9c231f5bf3493ecfdc43acd9b159794f84000000000000000000000000000000000f126d831e2690fe44dacb25bdbc0cfd77d4ea0e8381dc75ef2679ef8e11195ba5b44577ff2f67cf225b48e53a0c3e5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138723907e01c4b012ccd710b00cff2fba5d52893cbcbe834e746d05f064ddaca2ccb9999b81afb3a6212718d6698dba0000000000000000000000000000000005dfbbf4fd639819a752edd0c5967ae0e05685d6d2ae6dbe18a78fa55d50ddab4a6ef6ff63c1841058724605beda37231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a7c519124cea54593174d156394310b62ff4685fc72c1462585e8e31c9d56fa566254cd52c92282564673e8c0c4121000000000000000000000000000000000628a202f598542565c9af22387fb1457d52507f21706cfc88ea0f40b03dd70a89b438a2d19ec8be6b2b111e4e0547791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9861b68e9d217d1358e9c41cf5aef75ab0a408c2e47a1de970ed5ea457f86df8bf0c655566fc774c6bc3b21301e511000000000000000000000000000000001258a0c3796ab0188c7dcf621e54242c3e71f9d1fa6a451aba365a9cd173980ddec7f722d89a4a6fce32190544443de91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dadf1f558e5b846640b5e238a535e65e20d418498fa1d4ed128bbfb79b6b5798b8b07bef37b3af00856fb0fb839e0270000000000000000000000000000000000e864e2820c1fbe73e623d73c0dc7cfb90327988467f67089953d0ceb6ec488ee858555681423a02078523464bf95d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ac3fedc7a28efb1bdd48744f5f42d1560c61dce1b0c0e9ac0e1c9d890d17e046b6b3c49f7e888628cd29f25fe7174b00000000000000000000000000000000171dfd4e7b34aa68a59ce367a8514997dc0b96c1852f67ec42f40bdaeca3ceed7e6cc45aef4564dea85559765bae28391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001252f5eefb18b7d187ccd99c0911cd64383e2a8bae2853d15b8e823fe08205bd6e87f554408763d75e7cd4806e7e3e20000000000000000000000000000000000779dff3ca853e54e3575799631027f13f296d3f42615fe5ea479977d502dde4dc12c60a6f08dc08382d67d5bd45aca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d041d30605eb13d447aa97f40a5ce5d074f843f9ca4276ad1f95dd6c52e83fd846f397629954f8698dc59309c6c6a90000000000000000000000000000000007b898357e809d714b251409ce9e5adcb866fccfd523c44d928c634aa22d54525578c6c69ab4b3d6d235df743a9309e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc8b2445687a1bfa41ccc6df117f00ce020190b8c889c57bbea26ede67309ab3ceb7d1503b928365d236450f85c188a00000000000000000000000000000000134ff7652eec202f0753f7c0150db6d2462e8d488131bb9f434bcf82de101c84beba6cf39471a44ab57de576d730d8e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100f4bc2d1d6f4757a130b6aaf0b83cf777dc06d64f10bc043cb66013e5a0984149ce4b00f7d15a6ae237e263cc8a4180000000000000000000000000000000006508e2ffcbb35e6d29a9ecb827a5dbd19cef07eae5c6e66c70d42642cafde65a731b9b00550d909f0e85932ca9064911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190b5af86dcb6ca6bf424073ff933630a45bc79c7aeb3bf5da575c5a83a0251819867f18aa2f7c2820aaca8a0a1c03e80000000000000000000000000000000010d50abf3a74c81ca45b594f4da4266b051470b1ccb3e2cffce8eb8dd0b942d543236137c760836462972a58859d9f3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088b48cd5839c058b812551c8599b1dbde06a949a49a79e64ae3feabc917694dd8d1eb62dd86167a60510ce224cbcb3100000000000000000000000000000000163989ed7bb5764e628ce7fcd0912adfd73eddb3e1d526605d3e6610d34e0d253d3b8de1311573fe6c0bdfae3e30b00a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e9b448477e778dcdcaa132618b9368838d6a81a22c5815c4ab934ee788ad8eef36cac638462f56ee221e379a71c90d0000000000000000000000000000000016fd8ff7347a7369b75f4ec3aa3b6d358d5152c6ad53f3fdb7413a2d15637703477f63fdc89decfbb301247bdd77ec2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078db71b1a7b706f51203efd009cc9839143d177c192d6ac3fbc19b7c95b23ea40b6256872627e711ec995490de387a6000000000000000000000000000000000017ea4b81ba7181c2cd7e8535273e029101f0985f6d90c5b617e85592b623550211993aef5561b05133707a7e9adc1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000589f057f21692c5c577937f0ae659d36afada2f3655bc86cf1e15eaf229ff8e8308911e60064466bde4db00531393e8000000000000000000000000000000000a1cda4ed81fd0de9757bd96dda3fe7fc07ab09259c41eb5fccc52bf1d85d9cd221a3e1d12aae7298c3bb00fd1db4d201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013841fa47194fcb9d9961e35fc5d85b408e6e9de06903c881683fd9a7262a7f9c51b15f579f250b95eb8ae704d0564b20000000000000000000000000000000007a24683313dc89c732b5f04371e75626195614e24e31c7a52867d5d058314d994d14b3e47c584864c0ea83629384e6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001744165930396c2bf8ee77fdbecdac747a8400ae0abe03d50b266a5dc7988dbed6aca4a89a6ffbae78bb2ee0beb8673e000000000000000000000000000000001823252d83f64681415d989219bf0e82b1cd449ff8a60feeb5d15a4bbf5452f9baf867941027f8821464c14f7d76292e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002bb4ce1f9a6e32914b127765d49d9d1c288c3be7d7b9e4d690c1619f17c62295bf8957704d37f142b0a2ea100b9df2300000000000000000000000000000000063c4591e511c3ac10be9f26a7a15f687ac87efeeffae04c7e15089334650481be8fa8e57ec31fdbf7ebca11f85246d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b6cfaaee9fa077ed35e8ba86bc488719eb8066e84a4fd601a02bd95dbf7436938d58b04cad0ff84749d146bd44218500000000000000000000000000000000014732f98ed3595c4b60a1c485dba08e25f39eaed65ff7b1223d0e6dab1083c6e9588c047c25236358e9f9b3ca761da51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001426461fb0f88e1fcbfed8d7cd373f5f687c168ca399b24ca867c071ec8b0080e96aa1a8c1b7729c8d1fc500457910fb0000000000000000000000000000000017d4db9f60f8aaa3e698e9823da9e4bc2c7841542c57a7f26e0f93895e32ad6dbc2faef86adb5282b75c9b75f03ad7911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b155c539c4a6d40bda83aa233244875903c1eec61626860d1bd3392694e19cde9ceba9b80dffb498dab14159571afbf00000000000000000000000000000000051c52b7c12f17933a874393a27353e7781df4e068418992ee61b443be8c270fde69422e8321852a5753f41696f22ce51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001049fc11ffdb03a018ae2b2476cb0c0b889ff9e452e85b9a130ae52ccc57b94bded9c1128795d84c94ed918ed2b927750000000000000000000000000000000001efd8d005b6e2f64cab828593bcffbd55753cc209260d2f41b107ea459f8bf372c513764779b1546a5e0613ff11f4e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134c338761e6f79bc1d912cb1652ed65c6ff29eaca2e214fb6dce1239e40a233942e5daf0bfc4b5e7d4fd1e3f20d9c7e0000000000000000000000000000000002ec9a93bac0d60d03f9d29263048e2be9d8a1b56eee06c8cb7b7adaf5b9db61d48b0a27c2c1be590153551b99cebb341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000172427716505553f3bf0430b64ee829456817c64d036ed4a4d6f3055d4f54b50ba8c5d2bb87238ed6f9a847f0a32da000000000000000000000000000000001044a6b14a66e8266532ebc762e9edbb8f5b2113181fd33f00cf6d97017f42371b5598c02b9eff08dd08a9bb3ae5a6a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b9d55641b649f11ebd12f153d8ee5af82df5f939058a866e958fae0de8befac11e5969785f0d0f2404de1f1337145d0000000000000000000000000000000017db484714aaffd8cc49d547bcc1ea4438fda09d77ceb7fb42c42703fcc7e1f16b27d135fcea829daa9c74865009bedd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000985d307e840645bac5b58e5f614891c9cb6296119c335c1918c3680832ba69d493aca926396329b63856d03d2cdea6f0000000000000000000000000000000013a5918387c44eb0101bd86ce8f1f44fd6c552556f4f94102a7227789d2c120231f39bfb283c079d3b0493fbdc13611d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072ae382ca7523572548e370d3072d6ae39f3945f9052bf46a9de76d0d5301617362a0e61ab4ba1974a0df24392d23fa000000000000000000000000000000001263bcc1efb1141245a563ed76d89b3ed3f9246e591514a7af74d7214f82b2f6ab13e3f884dceba86eca834b268a3dc61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004cf8961be344c7939173095767d5ed54add1572d9be6e18532812611a09703d1a99337c23dd6270974b3a97c1ab7a69000000000000000000000000000000000cb443b5ac9a02b1d9a9b7a971e79b6961cded1d8ae0f8f3a37453d4f57fcee0d560a8cd2cc4a79f62c13074659f8c6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001155c09875543a5ca4c7bb05523d6d34f85e0b8f2c72de18379a975b4558b32046442d32491216438773d90b0352595d000000000000000000000000000000000c02d4870f3666e397e85c88d5c17cec476a5d2d0bc179304098d205497483d2d6bd6b5c442e6abb4b7d3115cec54fee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f00e5cc6c6659d6bcceccc6bc0a824718f60419533aa3cc626e7e70a005835aa93aa96ed318e8ae5176344629ae9bb0000000000000000000000000000000016fd2f037f3b8ceb958eddd6e1833f154a342c8d6cdc14218ad061a3e73868297b3c9f7c5fdcc3b99da21769608c18511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b783dff1da396ba3b17dad3787f6cf91a56e8e34f5a9c793ee8b55c099c78a68136fd966c3fba8668e1de4d316f1d260000000000000000000000000000000000684bdb5866218f60934245d4bbb1945e878c29bbecc830f9093e5695c67b478ee2a3fd16dab7939cdd77573d2b73d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101d19965c84f1e7ff7fa1082adaeab41b4c879b480c0484f097a41c89201f8f02b1bd7401bae55b871985cbe48a40fd0000000000000000000000000000000016440681fd6d81c2ed2c3a333f41a0d983619e1d490b90e5ab6db5cf5bd2f2cf8d0b278b1d164866beb853b8ca8bf61d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d80a542c3ee056786b8ffe8066faf0959af6fc3339e38d76fd0063f3e7862b564d78219b155e6b6d5f310684884cdb50000000000000000000000000000000006d5e88101dc1e8be177becfa5c4b3427da20ed50c9d4ddbb1fa9113a486faa15ced7709a5054f3de3c1716dfa914b881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b8f138c21aa6b5ca9514102c54f4021c3709d74bbd59d1c88cdb6059008fec4793a29ef1f30ad1c0ad36f47a97282f00000000000000000000000000000000170f6b9e271aa35ffc57fbece080ae75098b177acd930446437207e3566273dfb457a51a7eeaceec7abd488526db0f421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189bb1f7b1cf6c26ab48ac23f362c329612e9a074a587def8629f45da18382965088bd5b55a46920cb786927278c014500000000000000000000000000000000068cea32498385a2ab424d187defada8e94719cbc4926e4a307615c4271f05e62704e3fc9f4337f7ef3d83792c0d9bcd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000131b7a928e347568173f9b4cef4f10991eacb9ad791e75867675d94a94fd095ae99f858be426eebeb3a415a116697e6000000000000000000000000000000000290db9c7336c8d0c114f8de9a3bfedf3ee5d3042ec4c719a72e0122e4adda819fe45d098ec5c3ce1532870ae8f68fbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000682500c65bcf7f4451eaa59335ba78160a2aa6e9335008ecc9ab776e08b25077a9ab5ded4dfc6657fc40e0ab1cde480000000000000000000000000000000000f003e7660f0533b3744d4bc59fa491b31a094ee090283c8d863b2580b668ef40a377b91f9826cc6775248a13a804fd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067790cac3713008068ab6fa8e36347148196a9c913368c19f4ae1a110ba0c7a3dedfb7b281b94b36ab9876a3cd5f86900000000000000000000000000000000128b14f59bbd97765419f8e983b6a8c43d9f8561d3f2acf31f0ec9cbe350747cd5cb13040bfdc0b576e6bd5f2f7c2adf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a38c9802cfc7764058ff6f64d45a44c05bf7d66346b8fc300141b1096d574ab3515dc28ff7a410b65f03808fa557fd0000000000000000000000000000000015d0735380fb31d9883cfa3c2d225fa8c7b36b88b980398020c4e44759d3c8ab7749ecc0161051bfb1845eb0562c3cba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e8ca088354bb2ca19d8f0ff18c5cffe5aaa61eb1c61c9afd5c73b1b88dc5f1dfb5bb2f4a2fe0bda7de383b55f569880000000000000000000000000000000009f511e563ec35a9c8f1f6a09d0b4a7404bdddb2dff4f8b3522f142225df634469c7a706097eb3855397c87644d32aa01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000162bd802812dbf581d49cd75c8ffc30faff693a792834b5a1a901ce899dedd211e0a21935b26f662675c59152e7ba67d00000000000000000000000000000000173e40ed1645f7288d3ca0767f335f6228583bf09f5ad7da0d76842eac241bb677cd2d01d5aa3e3630d72d4bc0ffff3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010191a0f57724e25482ad1fdeeddfd7e0404ba39538663f115d9e3d26d350a7746dade59fe4ce2cdc883b4f0004ad349000000000000000000000000000000000a72eb26c7f19b209b986421a9e82b8a47e748161422a5eaf49b87da3b1fb221b54bc3273354a7c4946ed17713468b0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a0d1ee22c23e348be331c852852e77dc0aa9f5b7c829bee1106791759db9b91087939b0b9393d712998398428faff51000000000000000000000000000000000868983a94cd482c1b84b6904097feac74ea18b420594fac6a9d3894085b6051842329350fcb5516d385312e56d61a381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001223b25cf7734f8d041905fb1f714757f3981773a03e189d764ab41dfa6facf6ae82ab98df35c1ac77ada5e32334021d0000000000000000000000000000000006dc5a1632c0e24ab4e16efac750d87672c3846c37cbe6e4ea74f1b4a0513dabd08f7d8f01047e08c4276576c1d801741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007feb788422b265fb997e56e1f64bb8162fbf8950cefee37544ef79ed398af1fad1a71fd2145706643f4f82f8700dad800000000000000000000000000000000082748b4ddca00adf83111a93bbded0284312341e9eadcf1d233c2b921b6bd6b7aa9187d986d013c39c1942bc23f13141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000166489e72e8e55373581aa648485e09ef4f5251630e64af1bbb0d8d47617bb9c9a08795b1e0a0010a8cef03590138200000000000000000000000000000000003cb8347d3a9245101b75267ad1abecc416ec9bfff9b536d44c39b81935e51f7bff88c4d974a8056acf99d1eafe4cc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018aab686c94471a8db9f7d2d67e11a6d858a09f8370f2198e894d1178eac284f5ee9dcbd77b3b122fed710aac970cb880000000000000000000000000000000018a37b5f7a124154eeffa6489ade64ea2f0844c276cd61706c5f248332c47894d6056fef6f54a66154ebbfe443a143181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138fab32ef71f9428cec3b459d351666b45b719a3c69cab80e9cacd3d74b2fb8d210c8e981bf490e3cd95d2a3c06fec600000000000000000000000000000000003b098b2bf3c7b6465d7ed84ff6d5ed1c6635999cdabae2f0ee816c0d651e510b65733ddffeb78c0e44ad3895f3aa931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017648a870c8d525abefc2146761ef7d9c97cc8f3c63e47072b328d0a9f03e48b1e0b6c77fed044ae2b59d39d63f937a2000000000000000000000000000000000762dd6b582b7e7bd71e7bc972c6d2b8f4a5516f5550d169b27ebef3e5413c3fe71a28cfdd7ebd8ea5d4081eb55740dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c727d1f1bb3c7724277575249899a3075a260bb9c442c875c3b0077e46af3a8aa178da36688072405e2dc2c5a1ac46000000000000000000000000000000001831f3faa4c7c8af825d3cb641b48eba66d60b18f7c56cca205687b85d6e5c87671ac7aa90d5dda24d41fbb87be76ed31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ed006f031224a211e9638fdab167e15b07ff493d9664570b0ecbac8685a99d713b6359241c0ceed42b16af168df4d300000000000000000000000000000000071404ba9bda8b8e48c54e491dec70794f4c15ba10552dc5fd691e8e67331f9b3285c9077fb97c81670343b7075fba0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b378dba3b5f1271cc51704d521240c9583530268aea0b9f862743085f92ec83b0863bf82ac0598cb2d8f58dcb6745d000000000000000000000000000000001242ce81924702eb9eeb37e50f08e2ae7caf7c34f376e7f14a598cff213415a0441be85c1201d44eca49ddbf000f27481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000656148f8b4f7848f834db3301e155707f19291e62abdc5fdf4931e79e9fff47ea2ec403529df90fca61af9887572ef800000000000000000000000000000000153b4f19741d3f26370c91303bf8f72cc193d3cdcff1a86456f85b9e7b2f5f9366330800d75eb67f5ad3ce00c14aa9241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001901b7685794ad4351707a127afefdca84b240946f9fd1a3c60f243ae91f4f843500909162cbac7feb55c458dc555bcc000000000000000000000000000000000e61f077b23f1545213b807a2f9724b8629761679a34b1d849dee689eec6696f2662f42fa2afd27d5cee29db94fd3e881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113ad30041d07a664a93f37399f6516b4773036dbbfb0a2cc82913c14e24b383420bb6e5ebed40e5c86d6a130bdc888b00000000000000000000000000000000197b767c92016117ba3482f1ff8a81ad026820b0bc611056e7b544b10960854516c2c1318de7246315bdbd3d3fc6c7661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000467f63c0011b8e92f1400ada3befa7430e28f2c29ce35f4c7413cdd48181f52cba3aa7dda9de98bfc59b77a02a5d50e000000000000000000000000000000000ee287651052d39cbd1372f9560eef6642693f0217f456d031541f015d0a102ebefadb41609ba29944eea3a7ecb5ebc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027059f3dd2f80f90e5dbd27b45b4adea8eb149682b94fe3e2547dc40b85a8360af82a4d1e86ad1bd93fbfb39e20635b000000000000000000000000000000000e8582313e868c6f0b57490642b467b8c6473671bf297109b142888ad5a5b287cdcb6358112b3f7b3988ceecc51b90e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013aaf6c3889b8e92d8036da2b5b07c2fe17c1c734c85ba70641376d3dae4bcf417eaaea297ee7abf267c705a5ea0bc81000000000000000000000000000000000a3ca51551316a126347d657c2e116554fa28cd514910602bcc5a771695541a011c2dc3312b71a96a2d92ce649804fd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1200e27a7198fc6801d9fbd9359150371746857539c69b53983bb90f9a5baf585ed1d6077184539ba35ea8255874d2000000000000000000000000000000000f6892ecdaa1f947a1b7f69ec7a56bb2107819f55a3ec20eb6d4315320e9c89885c6dbfe2e62cf57c57d08d1cb04a4af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f07661283e5f7bc46bbd0a62153c5a355cf6e36050f09274d63efa3fbc2d24ff35d0919dd207125ee90f478486936aa00000000000000000000000000000000193568e74edf17b8acb42db4e2359008a044db8b145ae2d133fdcb647b8789e15bc06132b45bffe9a89e914ee5a60fec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd73b4183807ad1cdde370578fa1f70e935350cbc06c98762fad895f22df060e153fcd4dd1186e059b7b14b4798c32d0000000000000000000000000000000018c38b1c4de20cc4d8dd686b2ef25ac9b62f107502827b56ef8b7131e9e57d527b64401d4c9acd52900ed534f690c9a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e0c4ae387a97f1460a893ab362d5300de0ec4190aefacc483670bc7bad31008a2fe995577ce1287bcdf6315698433b0000000000000000000000000000000006f75e65370f74aa194d3b9905c5f5428ecef8387df4f4378860544bd02b6a877a7d51df850e5c75979a6be2100981331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011fb03782c6a8589ec033f0f74cc7bad4317da68921653d20451dba406130d217bad9faaac6adfc64edff73ef8a579e4000000000000000000000000000000000cda4d57e4c183a95f2a0b3299d12b88a939470fff0a03ab7033082c8afd35fbb0890a7653cf96b7b983fca088793f0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e5d564b830effaf39ae666299c542d06bb6701f69126bb1c85264f74d41075ca23598aa2205326334fde7fb8fae953000000000000000000000000000000001008e41b7f47086b0277166992df928c6498de3d548e571237f6bec053b3b15de9d0a4ed6ae9275213c08f5446dc87581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010aeb74bf5e5104d6e2785fbd1bcd4f192787a9761532dfb9e8cad3bb8b04f2b09c2d233eab3ace0ba1df92004008c110000000000000000000000000000000005bfdb99c712072015815f981a9e29b7ecb7acd5a061737e12e10d57b5e8ce0a796ae021712052cbc699223850fccb2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c32a2e242c3a4e18449be4394e59241d2e784b2e55198f43642ed6b8f8a23e26c1d3197635e8f00b6073938a047960000000000000000000000000000000000c01a1b4ec8494307a17e3567d230d36dee3e824e30cba162c6dd4803c1f941d001d85b5e75697b185b03fc4ec6c37821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017588178a37f6eac01ead62ebaff0bd219a1e3fdbf51a2b5556fadd86653aa7f9c20cfdd3fc0eaf56e7cdb59bf97b3840000000000000000000000000000000017f4024bed03b7d4d146c06e50e934cc81d17cc11dd2116d90605f41c701491e1d0fedb1a7046e4b918a21139825e6381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001585caef47bec8382370f3cf4527cb89de18e8b7c693485024327bc612618ffa4531a9763244ab59a6538e07ecc7ff1b000000000000000000000000000000000693ff60ef41293e240bcb150de728c92f00ebb70f17ecbcd37c217bfb5b0c61c2a5679642503043d9056952d7ae77c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8805156f94bbc6ecc9095b450826efcca05dc9422becc6d3bef10c0edc9b6e0244743b335dc2fdb830f299a541f26700000000000000000000000000000000028ee1854c89f84df27e7c74ff917d34b8473085d61c5f185d07b7f320aeaadd632731bf8f4d83a9ed07938d29b69e0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017aa106ab9ff11259d25d00557e15e8987d1bd4cdf7a17cce12311d4925693338ff7aa15573b2959f88cf2ed911d78bf000000000000000000000000000000000f89215340f7fa3f6f42c0d7e290849a9c158cd43644379f79960333d5ae03f7e5a30a0106213285780754089c6e36311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d681a270017d3ae542fd2ffc0c157b0c9046af7180b795700c574fb66baff68024d7a0eab053637acf586e7a51e80e0000000000000000000000000000000016d67eed2c7d4c046c7ae8cef0e9fd875bdbf101515f944debef95982308ea619b499dca3e12e04703c2dc94e2adc38e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001edb72c70e852924006367e7454396fd4493037bdafa1b090e450ca5fabf708ea0bc867d80282e5f40f3ed577bd4214000000000000000000000000000000000ce8e5dba23232af6a5455b99e484362146e69621896970872f20fc4d02da46b257c6869bd94f7c031e7351c67c392d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000011c39127ae09aed33f7d0897ab27f707c3dfdfb5e90b53d742b29b9c710e7bd1daad7cad25622c7d07cd3b3ea1db7f00000000000000000000000000000000134574d668e065a1a82904c6090c164f9aa4d13e142e3c1d9c3668af9270b5510d0a547c07d6b4fd464bad3d1168f3c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebc39442324f7b48f459cb3b2e66445b2a226733fcf4c15a3457ced4a86f721a24c6a0b971df9ee533f5b5e553bc0b20000000000000000000000000000000006a30bdda08dc53b031124a62e383fbb4759d4668485fa6d91c47f3c2b50ef168c4b31817eacd76be45537d46fd3a8bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e9b39f1c875a07d8ca33b078f5856ce6e5071ce26894f41bb80c06d4a71a2613ef6d634e40e0fae4c215a2681f2e5e00000000000000000000000000000000133ba2c86f4b4d11d3d507b7f370d0ee2a11ba47b9267df59f0698e6ea76e73e689b71af427a0347924419c4f05b25d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037856112dc4b0a244c6a298c403fddda9b0173f0aa1861a3a9aa04abcec060992a7fd9aa0a228eb00a29fb0cb79180a000000000000000000000000000000000689b620566eb37b2319df8fdfc3350dec0c56161600846bbfce06743241d3d37ad2c6794c1ac19bad79d8d84abdeed61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001844610b6fb106496ef4dd43e4ec4eeff22f2757fabaafc8966fbba3c4adaed6674bea91320c6b29110fe317d40f584d00000000000000000000000000000000151da3c678af1721a174b4878fd3a3b25967dd07d571e7cb439a1fc766642224dbc5081581e12371b9e80040597221091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134911f593df132195f912cf634092cdf7dcf8db33f403f653569fdda145cda1ed48ed545468e23f9c4b6e250b3b7bb300000000000000000000000000000000151a6789bfc6aa3deeb773d8d0a342c19b9e3f72099e1503f37e62fc2482ea63fe39d552f619d7d7287f590e5c3c6e4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d3fc0e7918853f0106fcc67e742f54b8f249d7ce45742fcad227cb01b977e014aae58cebe0ac9cd89ef1bfaef338480000000000000000000000000000000005d5d5be7c52ceeda68021c0f6b7410612ede7b731341a18871ac6972893feabda9e5bbe29fde430d4725d2578d449781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc0a2f033a91122c220085f1bb44ab0138e4c4bc39ad9d38309d54dd6f50a0d8e343d74fcf628a661d06568e75b589e000000000000000000000000000000000ea46bd9b4bbc286d7215a1ca0ea49d94dcd0fd69b85e4d1e9aac182149f763359f0fc8e889cfaedcf5c2a6ba00ab25b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ede6ad68613e8bd24c34cdc265f4206f5f75de1ae85bd3b1ff521b73b644b41cbad32175d2a6ec923cbfb15352abfa00000000000000000000000000000000006a85d15436b6889ddb7724f1efe8440c7336e5e3e13992a8ae3ada9982bfd1d80ad580f3f39f5fae55398af07444b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000798a6499923ad1447fb8bec3ea6a63216528e8c5f8726b7f20758813b9324f05fbc01589aeab9dc3ea4f256f1ac477100000000000000000000000000000000167b40122cb049b1e7c783c895264998ede8a17d6fa8e9105370e46eaddadbe0fd813a16a84b8002ac6f49b2c3b3e1bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e02fcfebe7190e8d960b7cbe5be85ab0b35577693a472596d6cf292165d93fba7152253e793b889f13ce2c0c40c54400000000000000000000000000000000084386f7af138fe752f87f7ab47b2165bbb4d2d0db2a510aa2da3fe1408fe3c114cfaa3b13b0d25801b80ba923fe2acc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156a9db98a271ca9ef8bb182ccbbc031f2b3ba131113afa156f13552e18dad4729085e2574ec16af08a4a01a954558970000000000000000000000000000000018fbbcb500f76b24f65d7a630f6a1137eb1d46491fc6af58a55f6b75383c32eb9fc36da9cd22e3f3aa10f1c417b3f8001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008f82f7c8a4bbb0ba25233155b75d9995beb83f4ffb38e44c7d70155bb7146fe76c504ed453ecf046d97b16a44fde57000000000000000000000000000000000562c7d0f57594c5a73cd0deaa26e82a3ff423d91f1417d6fa8705fdd9f19d940c1dabf497aa775991d54471bd1204ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f593e0c2882addc1e8498b09749ff401643d598515d0919541aa6b5696d19e9cec1461f9cec06f957be1848cd38b110000000000000000000000000000000011cd8c5c2291772d441bbaa70bd58f5664cb7d6a64434dfaf2309de9c56711e5063d3049c3789a590f035b079d01d7551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a09625d73df67266afa74cc90fd328f43ba2edad08371116e84c6c0c79572f2fc6f067199b11fb82ffed501e3498110000000000000000000000000000000009880126bda0918142c283ea98438053d5bdbe175286e939edf84b18906a49f7cc39af1219909a5ba4f5262a8a9e3d601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c24190dd4545c6cef2bb30d727df22ecdfdcde2af4feac2d3ee3968330feb5cbd65d4d430482858fd83df53adeb16c0000000000000000000000000000000017edb16ba089e0ff5084ad0c52836ab72c47d77a3deac4884ae547e935a8c779a0073c3654af4c22b0e63e20e7a7b57a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d96e767c8cfcb000c12090eb162f83a2f7e006415464a394e5b91475ccfe6a69edab8fff8c91b574b93b07f585e4c12000000000000000000000000000000000b3962482d347c58ec93213633fc413298d3fc47bb290f444b051b6834fa5a733a1bad042b80a7af9832f7471c1c20101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ca82c9e56f2f6f72a52b0f9d1c7d9168c5ee97a56d6c82f0eb8e68fd2ebc6464a766500b10acffd541cbbf03863bdb000000000000000000000000000000000ab27d0f3e6b802cb661208c5b9a425634ed9e66803435f9698877d15ee596037160304dfb039dfafe564a76e70fb2761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c11ee4e540b3874a10248903e0da0110eea5fb015c7b22d2053178603dfb6c1249243b474a8c4c5f26dbadbc1553d8f0000000000000000000000000000000015fe4b9ada79296a22d4493919545e5046bf8b95d5a7bdd9a7467f4b4bf723e6c1c64532a4af71d5875c571e9bf0e1f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d85ddb3a738882b83e9508f6a80ea6e97cb995de4d8268d4ece1b6654f6418f447581284f7c22a65ebc66612d47ab7000000000000000000000000000000001387fb103f138d93634c63dec396de6375588d90efc363920129f330ff9c551c435150d00c1386271bb7f72c18c7306e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181508666b83acabb89741ac11762f15af5ff8cca96d3abc5282dd39b8db86be17834b953e66b573ff06b4469321b4b70000000000000000000000000000000009555fc937513fb6395ba881acb3b78e34478d3c058bdc706275c61af6c3711fda5a6005d2965779ed3d5cab7d60f90d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092b32dfb73577b4f52b257b54206811c107697413b7e83398ad4dda90679f262287894c1253abbb1dc362d1d7686473000000000000000000000000000000000594c991cf66afa425315cd658edf27c7d7816638b4391dc01fab3eb38bb5d0e3cef6000c54787507dff64ec226572241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b26a967489f03de80bf04086b9be036100a041a5e093ad4aa80ca24f4690694f42820b54e323b25b5e93b9c2486b1aa0000000000000000000000000000000001b76905be5e662f6b795044e45af7b094589f7de99c24846d69d5cca8f6bdfe35227e0723e736c1859c4618b73441eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f15b3d211d6d0594334d1db06dbd9ed7beffb0268caa64b231a91ebb7c9ca6bc71bd4498d374ea3e9b4bfb8865ab86b000000000000000000000000000000000572946fd085340dae2f378cd4bee414c7bc1f11c30ee6c4b63a69420ff678dfb0b488443d1e8184837ae5fe7d8a1dcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec8b3d38331169d99f81f65c1e2821c7522adbc32c2729a4f3e83ebd6865c28118af90ed60be466d69640023bdf8e740000000000000000000000000000000019051e0ec7f090dc5b6dfb57801bf903c607df52b07f47522e3e6ad03d94e0b162a6034288208952d267c2bd38ea70b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eaa40c604a22d37581efa475dd09a71a172659e452ffc14cc9a7bc3d7bb59016b53251c81cf4633d2f8fe1be62ae4180000000000000000000000000000000013a0332d3e348dd4d5706f32601dd82b8e26dfba93ce15a7b90ed622eec5d619cc6173f8a76ac9bfeb8e050c981220c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb8d1fd3f6f5b8f6f8ce288fc0e0d7fd5a9374fc661e2079d6a07b90c15fb52eaa36f24d4b9f5c3ae03eb8b1c1dd8a7000000000000000000000000000000000c851f5df50f57f4055f08a3a97deac8fad3344d3663b43dcab596021a760708dba708b7e258b4641df87541129a58641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7d446058be2a0e92c604bf9b27192fdd50bbb405ef6684a477c586ca9ec2a1de7ec1bbd0326fd589a0f9c697ccf93c00000000000000000000000000000000089486826506cf258ede79bc85ed0db995d76bf45ba1e01091848f2743a5e76e67a6b09abedc8a497fa462dbac8cabdc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eccd6fa7e83efa3db93ac826a142bc85d86ec367950fb3e5f286fe9eac01ed557b7d3ec36ced2458aa01869f5c309c70000000000000000000000000000000014bf5d4e4f018e21311c0e8d61c6e77e4ff6d5cad68d5707ebc18ff43f411ea8b9e9d5629fea1479802da5f516c6ecfe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a80d98ab896e559b1046a518656d0704369ae5b04d8ebc55e17d49a5b9b7a8f6c878229eb52dcf586f0ea7377008c200000000000000000000000000000000158654d92027a1a6ead8d74219112a346777110798967a12015cf838416e08ba90b056274eec7c9bf1de40756b3b42681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5380bd320f492115e48dee6a4a1aaf0e5eb9d9755cbdee02b8a791967996c7e2f61e0cb6eb11d109d8f4601e618192000000000000000000000000000000000b2acd51c6f3ba9ade467f04b015f17a2fe63a1df79dd5eb32c3d35b76b6291cb0acdff95ee7970ce0e3623d7b6ec6851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6f96d190da3b9d64ff4735ed1ec18d80b3db9bbf85879c7b432cdd2637e02f8032a4c435ff8e8323f2d9f7dcf855170000000000000000000000000000000001dccc8cb1ddcb6ead0fc2a7dd69c4005d7cdbac3cc3f4f9fea2172ca467d34b84890deb6f59da16d99f1495990184c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e98a0734523be174a7ead24fb00f4744b78ccf25adb781971f6223e836b626277b1b9f790e629ed9178d27b3fa5068000000000000000000000000000000000fc7be82199fc6bb2dd1acf882fc00b56542feced159f730f6632516c8c7ece4280e348cd8272a7879362d2be47fbd161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019afd9b0ea8b91a45e5388f0d1aa93472821ba188fcb0d9c1f125e7b2cafe63e7e0b112215028f5a39a6d452637e488100000000000000000000000000000000171a2569a6fc48ece55589cfed029488f2647c92ccb04dc5e7aae7827ef9dd59340a5b995211724b1bffbd619cb5af6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7aca785258feeb285f7b021c68ac1a299d7f10ffc7cb359e9c85e5af932ed48c648f1f03d8cc33a118f0cb413dc0ca0000000000000000000000000000000012910f68f47db2011616e4866c719fddd5b97a6d04b5bca4d6e8d0f545341841b84e670fa4cef62e51f34ba1566c6c9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1f1985de79d9e60079d346b872c0ae9e6f76cbb4605ca0d02caf18e5f7964e7422bb4a57c46c628a859f4f9653ce0f0000000000000000000000000000000006d6a2689eb289deb65ca2c88f0fe51cd51a41959c020c5e1c64c1c11850f0734b53618b7f155b2a1c7e9ddd9111da201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d7b8526d7ad427f5aeb8ffbc9e25de927dea01502616390bd06b2685f0378fd4f2aba941adbb4a1339dbda0d82c59f0000000000000000000000000000000014e51b572a0eda530b7e2aa53d0454e88035bb3aa7ca5ab090ff6ae5fad10d619830b187280a991b56302d856832bca01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007789c79653451e1715387a738d404353b592acf2ad0c23acee0ec3c533e540b0d60d040b1128e14c64500bb1fd4cf4900000000000000000000000000000000187bb42e981bfd0226b2801fce153ddeb1f658e907cb2422e823ddc8a00db6b7268ab3f497cd67def249c8eec8ce320a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ab44bf22f599738327f737006b3b1877f159ac4fac6cd480dc29785cf9eea6b5076c55dd91fbae5fe019f9fb8bc8c500000000000000000000000000000000153ba01b478d567b660801e6d66fd398c4eb8c74bb65463f3656b13a992a4f1aba52b182c0f4a2c58472e3f92afd14131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c2a9474ecbf5cc2b71588a0c8ff094e3b836f4ea5bab6d7f251c81af4807cec7e595e024284c02bb574f6322551c05000000000000000000000000000000001203298828d31c25f888bf668c76808598f3b1c4941be00e6f253e991230ec662758211a2d72b86680c11174b28a520d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f908c98755408879e791c2137f8f62043ef77ec6d7d71146ba02765b23bfa9728442285d12abeb7e6a29bf1ece0bd2a0000000000000000000000000000000013742633c217a5b4d9167dbcc210def68a400de6832ec3ef87196ffc028cd3c14a66d769c628cbb28b3c23be6d9d64421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013fbcc5fb48b3eaf70e6f90b9bb8e532c5eff028098aa79f407b55fae65aa91f211eefba01f8bcd7cd7bf995203d9b9c0000000000000000000000000000000018139425d3aba0e05d60d1760a20653493d57b8e177790277b61f13402171bb071fbce50fe10591a342ff123c26d14ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015764e6a821042564779edd5ccf7d11313ed0c5d0c51ab2fd0f082e70bf0a2e4ad4e9d65b1762abaa12da11e8948948d00000000000000000000000000000000089b78c1fe03dd5996cde45a42d32af12065a2c4087c84c812297110ce2efc99c2836c573fb300419cc39efdae55cc6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017579f63003742ebd584f6d8b64ce072b59ed4936a291bb420c74e8cb2e1ee4fd57b040dfcf21e5523a50bb67bc71cde000000000000000000000000000000000019568d1ced5e3e2ac1dddb66efbe06f6e601992e58ece451c8017d39c7cb22909a3be5eb53d046945b938572be63921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025fed6d4aefe93b807feb052e309c16a6c2abdb6f262c5b2edc9112a3daf93c1a449a411eba9252bc620c7cce432b680000000000000000000000000000000003470cb64c67c80543a5fde913a4cfad791dcba741b979424ca99a3eae67c3613ec96daf181867b67c9f67f8f32c05a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b71f61cf73e7dedc1f9eb4539c5dcfd9e7e6e9c8febb07f1dd41c02a7c3621c9bf16a7d500b0e564e7c154cb4a1f050000000000000000000000000000000003e65d6184fcbceab8cd2de4869d11c00e3f3be844cc4fcce2e1afbb37ea9386d313c765be5fe64d212e5410ca6c607f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0aad176008af80ebe2f7150272cb41d04e177c47d4e19449b18f3eac7c7e8c73f12640d8d65c124685e9c68ebd798a0000000000000000000000000000000016e9c506189b410a7129fd3b09cbadbbaf1365fc79735c5a92fc23a34d0893d724486f7fb77fa42ccf1fbfe5d3a00de81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e2a8e7f9662bec69014bac4a244d59a48767d2ec18cfdabde96434ca603ba57b16aa687088968ee4a5413824371ca3000000000000000000000000000000000c7e6a5d43abd9b79b84ba78adb287a1e056c498504aabbf948b945c02091a5ee68c9178eaaf9214593c7a3b97ce0b371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014679cb7fee2ebd76e64fdd7de0791c60e02569863ae41face922d3d8c05b3ebb8687da928b2a7c73de5ff36b97183b2000000000000000000000000000000000111001c8c56e9c335154be11f802c0f5ea176ffc180101b79b89870099b3778fb618d0b7cb96f3ef2f55f2c08a58c891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018141e0e1c276f1b92e6fc3957d673da2e9ac4c4e92f3e6b2cb9e1b64c0a76505b9862b2680174670500fcbb2a4c7a2400000000000000000000000000000000076914dc9b5d9ec395640b1741631481888b112f4ef3ec79f684b2433c4f6b647f113c88647b7843c6c58399e9bd5c001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb18db0c3d7144b5d0239d5f060fc887d07d2402ebab13e25a46e1133396a2db2a3280f4d1c84e38767d5fdc9dc7dc0000000000000000000000000000000000df7d934afa2022b314eb5a9f31d6e817f52e86c7e6b2db809461b58688ed708e48eea6ad318cd0de67d84c1a44f5b851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168102b01882931a3448d717fb1d9d8c0a9f218925b01c07b2088fb47cecf02aa95cde3c0f4a6e0b0a83a42915ea41950000000000000000000000000000000015441cc6399728b1dfe1f484394db8711eca75e3655913c92ccd0c3c14487945c57064310928f1bc9aabf0fddd37d9151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001092b458bb934149b213aaaa6cd72eab830b35044e580e14e20c2fed88b06aff58fbb7d99a7b8cf7a4f6f2162278c052000000000000000000000000000000001903143fd8bde295029b371c542255c693e05ec80918d5e1f997094ac3dadcb4803206d9ec40d3dae8b46ed368a43a1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047fa31f0fc59feeef84339be0561ab52752ce5efdd893c0a33be5cd3fdb52e0875a6601cc7964969f639d9c217cc46b000000000000000000000000000000000708d187264a0f1866e979dd55a155a10bf171942be62e694fd8f2aa50724bb823e92fdd2a75e5b83d717bdb96a0ec001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010caeb4597bf90ba9e2c13ebc32dfbe6d373996c403104a0cca3da1b1b87e4279d8c4f0bbbccee63b78148f0e2a427660000000000000000000000000000000007840b5d1a03e8ad1fc44f2782ff1194f7ebf173b58d552cd128de5a626a24328c8f03f46c258d04f84b1cf89eff4c0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014878d019d48a83d4a0f69243eaa23698ea5baeacc6d4c0b80d2400f8c3f21f5e68ede1977073bc89f4ca622ee931a2c000000000000000000000000000000001435052d32dc50fd25d648222e9b267b75159b86c5d3eb63e13694cf57510ff8b4c646863751c3f642c4fdfd206bd6c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbd35d2c78d784ccc29676a19894739f1911eb6f3438983fe2fd93dd05aff84323129fb293a907369d8a82a9acf82680000000000000000000000000000000011b313a5324e291ecd13e2ed9e34eb97ccfeac01b0fc9f18281960884112d213bb24883800e75b34e8d5a9bca85f16a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083117d9e2d123b55826dac06c97ae4270050f712195533b82bf817aa9b23f060f6799b029823470bac09f55dc42a33e0000000000000000000000000000000004451ddc9eebdfcac9f32406b25822c0e506490298822cacde77258329c76c792c1d7833bf8bcdc7c0b386cd5ba553731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ca66b676a7e7e2ecc63a4a183ddad788fb26516d7f87d8addef08ccce61a67894bc361000b9e4490597940aad3a3bd0000000000000000000000000000000006df0d1b077b7cc5622d39214a1b27666bd93e8d960bd4a6bea9357212a6b0a1bf0a810dd84076927629ced9b18dd6201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e673897b850cb9e87fb3ccee9efa6e98476e2cadd7b7ca840e5ede598f63be63e440a2a40f068a25a3663441de715700000000000000000000000000000000185ae2963a37f580a2aee3c91a99e42bf1f6ccceb3068df93158083ede286d344b704de8fb35f152ebe9dcb206a561051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094b8571f5f49f57bb926d87d34884b551da98f8597aff4d82fa37f83dc6d8cead55360791daeb91aefb29eab29aa83700000000000000000000000000000000118aa62a4de452bba339eeb2f4ace3a817bc01fe8effc6c2a23377774f92da374864ed3bc15ac56918d1dce94077eba51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ada220d8f2480b6663de8656762885e66310cb0f204c8014a70e380981a2ff72ef920d38a7f701a90f88586a237b450000000000000000000000000000000000291842f0e7e466a796b6a9ae41e0bc658aa0feaf53daf6f7cf6a64157b1e5b166c84a8eac76a0ca80f04d0a83eb8f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d3071b5a14e0052de49d2923632ca54ace073e4f0bde3740328dd483f65d001773dbc80ad92337bed65a10878086b6000000000000000000000000000000000f857ca53062788f39dd9363d2a3862791b6974057dc2edb73a503b187ccc15bd035bace26165b8df1da7dce74cbb9f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a1441a8aa4d440b1d62de8191221b83dada7a1e42610c54b2bac0a4f75bd77207e67a329f7204f15639721b2a09f1000000000000000000000000000000000154cbf2cbe73c52a81c1e4a18d34977e3bbe4ca6b52ca8f116fe8d82028e74e78603d1e8cc8e06df9fd0f1345e87c9cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000acb2e1bde0c48ff04cb9223607601212b1b31b3a010ddeab08855d86dd3aadc799a04ffc253bdd7b2e492430323bdfd00000000000000000000000000000000133cfb141cdfb5564ab0497fdea57fbaf8f54d8f4f5b4d6af14246ff9b70a6d716e774d828fcb1a4ce8f634e45fb81ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128ec94b779419054f15c038b410269a420d4add8920d6d935f9dc496ca42ae1f097fb665b5234b5cba4adb4159aa38f00000000000000000000000000000000083a43c508253340ab9e7c38c3e5c68d913d5886581d95dab29e12718a8a24aaa6725e9f075d56b9afb227b5fd5ebd781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c7d4326ef2acfccffbf9d578cdf31e38247d1270806a8713226c12d9cbb4b1447c26fc2e4d6b3a43e37eac2dd61ad00000000000000000000000000000000006eaa9b0d1f578f78751493fbcc91aea04316a02a9faaba1edc00a860ef4b1abcfdd3387d822cbc52f5ee98c2b5435171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ce159a4baad76256fa7e33a48131de57b41e6cd437fdf5082791b32ae8a9605a082f1aaf439db221cc3b13dfa3049a000000000000000000000000000000000881aa002831b15937e061a64037d3337bd3c30cf9a0c3cf3281ea9e2705843a541c5675659239383c47612bd2f6647e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b94dcd5e32d9050945b7a38b03ba90d4304e55bad92e85f8d0e52b71f72dd0312149f8f1c56dd99b67d74198f4fc2b00000000000000000000000000000000099540949d887d6b7de20bf785b0e3c36cb12ba44895278a8275b9cfcb7bdb93cd39ebcfa8b7b12ff77d83d5a5bac0331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004953535b59a7e1377c4e9c556e9a7d0be26d6839110cf5c278930900a5e56b1fde975cd1492115eba8309ab1d2a69870000000000000000000000000000000014a622f4c6df000339b2d419f0c0e7c90c8452e51f7b4309fc2fa4f124a6688c3029321345f06283cd50a9e0d9602e2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141f5739d263695e88b64ffb57212d311d65226e1e4c8aee20239400457ef9ce380f0bd9c21e42bf5d0c4696add35e21000000000000000000000000000000000eaf328b6ed3879a941b00c6693e6bcd8c5a5cbdb51a25fa46f6f8902af98d14fe4a70ba0ff129723a8ed3de16a045601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057c16e1c18e5012defd762fd881c556c173e12553a3b3f6109e7ba658a3f2e7ef82ffd16b03e142c4793f1f237ebddd000000000000000000000000000000000b08540c3a4731818e186063891165162306fbf6a6a42c50d4f8fbf31bfee3af7ef9af8a4dee4426f2bf5116b50dc7b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f3744c9aaf28812f8a9dde58452d1bae3efef0f8a99c220ff68c9c1ae5400d6fbbb1566eac35b75ab44aa635f2c205000000000000000000000000000000000ceb294d6401975795ba86bd5555f4bb302454c87121b7dc3288f8dd1277cf0e1e86d4aa83831d0a7f8d08c9b5a51d7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000106f02dbb46b3abf05513dae8de2d3145a04afab9744a6ac6f0a6b83fd4840f6a4b1d0ba4278fe01b759f875939f6310000000000000000000000000000000001de555d18d1bacf1aa8a2f9ab69ed1fa98be07cf3ae8edbf7004664a5a00716fedb53b288a443a4c2a5d233975f4dcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d8746e8a9f6c2cc53a899348b64c31606aa5f09ee30f23645f0baada13339ffb9df3fffb2f2eac481ee64f56d4f5b400000000000000000000000000000000126a18d223c7578e45618ffcfbaa26b8ba4e494422e0d414c3c3f7016bc36cbe1932dde0f06257039cf309a12b2135661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001782c36ec8c76c3ce1e62d72c978aaa7ed0f58af914614cf539553e9a3a2c8f50a920031d0dcacd27fef1f8b44c064fb000000000000000000000000000000000180d75d21e44e278db8bda9a4c8ffab691dce3216fb67bb2229994e72cd7469a11d6cd2d68dcc8d395b061faf535f6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197e95bcd7bd6e69dede6f0e4a510520c149a5473b500e4080b93f1d24118fd2ca3bf1ba2fa95e36b1efcede53bcbf79000000000000000000000000000000001891bb0ccc02d6f40822c06dafec8ec4daa388e20dcb3cbf9cbc3e579809973fd88151f29c99d9d9290d80289676cd261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000071838afaf2d35710fb72db4b826e745e2a7d69b62a2d134b77d1491bcb412842ebb7c7a73baaeccd7ab1c3f72bae7300000000000000000000000000000000041ab4877f90a8f990da9e50f94a98a082c663dc69c0c7b141f3432e6c7a2d33782e6b28417f8471b3ca0b20199db2cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d4eeecc984742bda5985acbf63b983ab4aa20a6b389e6160bbe820b264cca60494e5143b62e6a60dd0bc795861ada7000000000000000000000000000000000a5977cda7481ee6b56dd55f56dfc4cacb1333ae6e035f3efd2d12ac239edd58dde2abbada97b5595729bcf1bfbcc1b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d7fe3e218b455aedbde7bdf52148206d9f80e497debf0c5be05936e1b456329a96f9663f024309bd29c152752f9a9e0000000000000000000000000000000015fd0e923a208e9af3d2d72f9c86e5164a8d5a0f332d577f757cb50c8f2990ba5e05a7e76287980ab2e508dec25fd6171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156bc719449ea4f74c2758cfd0a003941c49c14b0e2474e0cd777a98a1da8ca78580997a7e7a6de2872a98cdf7080e9e000000000000000000000000000000001013a7b72a6e604ae9b576977c764aa72859d1f5b114ed68d87d3d80421a0ddd7fbaef21881ef505fa5aafbf9b9d416c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000efebe540e6e84bdf1615eaed97b1aa5523792ddb86dce3eb7425268b8c0131b392292fd27adff12dca4f50dca9b375c000000000000000000000000000000000832713047ec830c5246195ece0c9232603f3a25a35d7739faafcc6adc8205fc0e2727421298d755407b9636ac6384331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036d25a892cec5981c1cc09e6e20cc45d762dd7f76eb0362008fb21c57e01ca493335503427c10366c9833ef2d52909b0000000000000000000000000000000008ef717a33006f9438fe6f7937cf6f792a68b9f8863a94da8b86be1f82443822ebb0bfad752d83344c61c260f4a61db41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181ed308661abedd37203df1c9851938373ed77285607fe0060842d4d3b33716d2a2900eadf84a26fa2b58683f9a00d5000000000000000000000000000000001514f8b37a835f7eb7ad3e58f47d8f1cb195eff091874a0ff2c40ac43abc535933432ffa87b507f9bd43d61fc93fe3fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c19ebab51333fbae49f552291475635d5b083e107ef6c2481137683b6dfd327c80ccd39ca8177b259dd2195aadc12350000000000000000000000000000000007d67c3351fd98e7964ef3d943d070144d7e7513fc6f4054efa79dc98da25d118f0067fabd554fd926c2744cf8f9f7fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7e62340fc7f0cd528d88cacc87382dc37a65b722995e2d84dfc0304faa039e45a05c3073f4999dc6a05cae7a23cfbe00000000000000000000000000000000166ee356c45c196e762e54da3f5b0c93f461b0727a32fdbbae62b80cd245907106653c9ca5bf245c7a3c7ec3a414a30c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a2e1253318087af2808f92420ed811cb56937d7b908ebd3dc71f49ad98519ff1c924d8e0091adf1c74bbef2e4db3cd0000000000000000000000000000000007eeb738b5f83276a9019f66d5e4a8bfbc994044e36c9f6724b499f3d5db20f588f458686ca950614b0ba3a2147cb9b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010cd40c7b92d64fcea54dce4baa211a7e2658f96d4c880e6210de566b033246752083c129ed0b224a2c6596f01778049000000000000000000000000000000000da0a56e024bcecf709538114e123f1f1aff7e760ec41b0f87b5e2861266f791bf9f3a32437577b969629720020208581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001042d2a3893612a57f7e69af9d20989e7e629bcb7ff00a3d3504e6ccf91bf2eb86bcd5f69ca4393d7311298f606d69770000000000000000000000000000000013e41c6596c937c8f3bede6fac8cc68516fc7c9a212c09691075ce44253cdd83a5dc2afcc79c9aac86a783a57620c8031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119cbbbe26e50b02c634b54c9059c264602a79cb37e9a3c5be507364a5eb4a20b7285dcc8d2847d06d2e86c126d3c2fa0000000000000000000000000000000008dafcf9ec3af386fd69bb44666ca6af13854344ae066efcce17b35f7c3852466ed7c6946747673769e2d658677998421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000570a2f4bfbf8e65f13da4e047747e148a83428215283051f53920ecb4cbd9b70eda22570e76fa62598aa15539a87fd9000000000000000000000000000000000384faa7e7652c0063a8e37a3f2945d13895ebc691937daff407ab28b62a8a8f5526959867f8b755eec1910b3a4e5b791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127f59537d7dba170a2674c33c2fe1db1383aa860854dce31100974cfdbb2dde8e04204a87ec5f6e960aed2409a30249000000000000000000000000000000001945aef5ac94be227cf956fb181fe0daa0938391a88efd8ccf8285855cbccd40616dbbe4143993d088389cd001ea50bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b03e860b7b7d43cef7400dbfa0511cef1a7d01eae78166ff25379c84978e16ee898eba7820c9ab7e44e3e812d67e85000000000000000000000000000000000b47c438438a396972acb9e5af9b6633c6f270a51adfd79e7d6e7e40b011166855d53ef63c3bbee357c4a92165547b071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007bb23f8a43eb7d0feb08d17566367516d5b59568d3da44c1656bb4b20473bfa68209a14fc37530e2631652f81f8649e00000000000000000000000000000000072be2314739fdd9dcb9faab9105d6d9ef8be1b88928cfdb7e2c928063e710629b98a8e42209abfb2b0f63cbf2201b001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091d0eb7dfe296371ec7773493e22a33e6ed1d6a2cdd2f2f6584113e91599e3d13e19d68257818202716b69f32fdb93b0000000000000000000000000000000009404fcc1502530ca43b47e8994f2cdee1366d1b1d18893246c8c041fa5d95381ca3b3255431bc55c93c607b7d36306c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053f98a0336cae5d2261df894432856a92c6644b125c9e4f9db4754f96fb40b718ee2f2197565c8a0e2d252fa649b1f20000000000000000000000000000000003444f03d1fab5ce3daaa2d08093c55b3e0870d598e3d838da94c5317da8eafdbcec546ec072ca8748410a4fbceca9ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9303b61b8cf50e77ebae5b573b900eaa9aae8d17ef7ee667a0539ae91a51daa4f3c2374d92333bacc6dd77ce570672000000000000000000000000000000000193f02e3384c863ffbad633255079e591a629c623c3c78085be032c96ef188e1f9a6f933a532020dd998f6a316632371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017f96ca7ce16b82a93d1d71d6aa62ec850e132ef9678d67718b95c340489afc93e78ec85aa20a63587561d5cdc039b9000000000000000000000000000000000c8a38b58f0fb4a2b3c2a2b9c896b5212384cca21c9d8e72e1b1162d5557269a02e59310e5276913644ec9b48087a5621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076b3b9141a92bf89f30abde91724f0c28eaebd8b7f1faa51f97d221eb1fa8e0b15bde7904974b7bda4fa08078d917ff000000000000000000000000000000000e840db629377ffff8aa5c8dc28c7d3d478b9f40b0f721bfbe371ff918040fefba316bac4c68159b83a6d448232572fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1c16fd7ecc725da1b1918edaee61742ad15aa89a6ce717a876643990cdf60ced8fe427d66eefb497106911cd2d832400000000000000000000000000000000066ff1a339bafb14e44a5b559323a9a4e5976d8a202be7664bd9f9475e771194ebeee02452e62290f471e0bc696af9841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001708a9ef760380c5366929b51df68b256fdb47e977dedb3fcbad0b68ffdf1a021da832d2a49271109d02673e203a992b0000000000000000000000000000000009700a0a106abb238a9cbed06f1a4e2f2335f014a33965874ab6e891005d830c328ee0a4bbbb7ce78a21774e110be7691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001811994efff8a9fc77e8bd436f9736f8de2a99313c42f753e83bacc3c50952565e47f6194b34665289b9a885cb103a170000000000000000000000000000000003952c2a994987ec10814d22291204488af6f2fee058dd32857e9f0d34b5aff5d1e69522c90743c4e67eb7a64168e9d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170784c421f6982ac64dbc33e388c12686810b40357ff1d67ee45edffb0ce01921c97681120c75d81579ddad0d415b3b00000000000000000000000000000000012c62034705f9867db095ee095dcf864e091236ea21d99c776c6854afd116a0bb014fecc719b853dcdb02c4a92654f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000855e63b42a018bf34459599d224ead759d924994a288dc3f5da46c1db4907ad0b210a52526fe58a9733b06763bee73f0000000000000000000000000000000012bfe2e613ce1d6d439a8c95c99ee70f4fec4874f741315d5eddf2ecc3a182bd8415a03f16b1a565f634232f29a26ce71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131b8bf680defed3720bc23c5a169ea75c1b3fb93579b8f1c69837810fdaf6fc756fbac1610a4c13b582540b4a3efc4b00000000000000000000000000000000119136eb6d7b82c4fea39283c5a70886d5a41ff678b40d1d7a72396ed7565145dea39920434db19d0b9dcfc9ee8fb2f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e3a031d833baf041f6bbce2c071fdaf4e24d1dcfba811784740a058cf8fdf1ba832db6cfe1fcc57ba2c50255c65f25000000000000000000000000000000001316b3356b0a24b26fcc5984550e0374559418419b89f0d71885b9d3b3f3c62a8f3d518073922f58d532e1d71e6022ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112fe53b450f17e70c37d8e62006e3bd91a6bcd59cb786bd3c76dfe41a19f325b5ec2614d4bd1d3162d2b1c6bd5723490000000000000000000000000000000013c5bfe8ca8f6192bdef003a4c950888f17ab175be4b97c4b0f54deb0a26164186472013f76337cac71adab0fc097c5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014846d8b5cb98364fbc0f079c47f19b63906e69019f6c5f1d6dee1a26ea01821d108e55f0a49da9b06d78123be0a939c00000000000000000000000000000000163e4ef3f792844f81c71af14a4f77e302fbb345cb42822485fe3d9f631675de989e9b9734b86fd7da9987e5f6d56d8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cadad68d5e656e82ecbe846a0a045ca495eece2386a5a717ebc96d5be1b88a27c02de4ba337429ab1a8ba4d1c3f70190000000000000000000000000000000006e479435b793ea08c3a9fee22bcc5f833314b201468796d962b22087bd5da013e9c96887eaa8fc9149bcf790d2f2ecd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000faa486f217fac43e94968b3fc550900d6ce97603377b4663530ba76b029ff8d5a275813c0c1ec08fddbe78cb89b367c0000000000000000000000000000000008fe06558b29bc8512afad09a483e1acef857270cdffcb56f28a06ca28df488f50f9731b462957d3f39fc4290ba5163e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001995f15d1759303e07b4707b582dbf42f48aeecb58dc57d55e1a4b9137fa058e7069eabec01098ecca2ca9c4921d28b700000000000000000000000000000000119d2c2383f07ad7f840d3cc6d9ab8280bc4bcfc8523fa10e44033476788cd693e3b0d5a3b3a2928c401f0da9dae65391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002739a47b2007857f8d143ecdb3d2898853145a6ee13eca6bc9dc8998d5b773ad001f2af597a0cffae6ad5322bbcc9c70000000000000000000000000000000016c3832f1ae3e9fbf62daa00a1e1b4cf46a4335377e58e18604081f8643b315f956d35382fad6ff8f4fe07ebcd60f49f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cf83bb70f9e708f173ec8a18d1f9a31dabf7f4f7c639d08f6f22b48745e68a166bbb54ae6378bd1a829fe2765122ba000000000000000000000000000000000a63a9d81901dbd6378c0e1d47e4819db3781c1025292f7c515cba662ef5f9c7aaa6af978d6b25c066df82a78a8e76e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea6ca775dcaa0f06f305ace5fde12e06431be0c77bb935ac84f32117d2d06bfe513ec85f36a82ab8abc1fb5a3034a780000000000000000000000000000000000562dfb1f521c740f14dc19233b029956a194cfe934eea208e691dc9ad33cd3ddd99db40ce40f268e814575ab4418be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011cb9bb5ecc4ca97f9af1bfee0ebd259e2254903db674b019e2c1226c4ba052a9bde09bb5f13161d88860159caf6d22c000000000000000000000000000000000cb31a0e4555f6b22dab7491010d922ed6bc861b34761ce13215fe7d3a6ce061fccbc14da03d546377d1ca0f0ee6911a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042515d2693e5919d019b8afa83b57dcff5cc5b9a4d88513cdea8489618f530231f0ca35ea84a70da0d024c601a656b000000000000000000000000000000000084f0b76cce5f303cfe0453b3da1348cf62451144cb9b4736068cd46c76e678ffe9dae2eb6db1eb59ecd815bd3b50bfa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001839b49268eb9a55812af59c055e6f9b68cbcc22418a7603da07aafef2a1748496d10ed3d7b094bcb05e43102f11d3ef000000000000000000000000000000000486ba39834ab8ad14dbb1c43ebafbc7e2ddfa28a6dc0a67d48e1e151b7dca057f84d51857e8506f8310b5ea0ad2adad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e858f93d2724dfea4bd146117990d79efeec5c4f5c927ec493962e451dbad88687015afdcb30c378b334b17ecccf210000000000000000000000000000000019dc97efa35f4766f51cd4f93765795b76893e2d079be7a48862cc93d5421d3ef4184c5e335d7118998724b27dc710291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a2b5196b8be417a7a935d0f12fe31cacee7442557cbbb409551d7050d1572e6cef54a7fbbfc0d9239ecade620cb96f00000000000000000000000000000000130070a2ceb1e7fc87bc4c5ad4df5d2c9e076051630576d88d180d8f9971c710c3e202c95968df62a49dc93b407ccffb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009913aadd0664fa07104972008c26af4869c838f969654c9e13c098121c20dd624af0dc2b53c04c1109d56a5a7e0123c0000000000000000000000000000000017ab6b3890d397f7d798b99eb3235af1dd2c60f5036af3aeec60fd4fe1f41cf36758522859455f40a25a48c3d7aaac161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009de8655c5e7eb0d809ea284ce492b56ddaba2c5df5b36b7e586995f58e77c662d55be0cbb29af139b295063e63ed9720000000000000000000000000000000011a50d3edbbcbc2903f3931a52e87cbe5e4df7a5bc672779e1ea6e0c4d8c963a26cf32ea0d2e195f1db0189b3347747c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e4fc68183cab5d0fc065866d38161a5deade97e6b09a5a54e9a8caaad9e57fba32720e7a51430f6a5041a8e60de7770000000000000000000000000000000015ffd68db1299aebb543c492b392d4233c319c0745d95e59e8984d8f9ec3a4765a4b81df129b7e9045f30fcb5b81cc801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014de7dccebef2d3e9194651c4ef8955b7c6a812202eb46f713f4311327e8268173a6a9f97e5fddf8b5daad46788d34d60000000000000000000000000000000019e5f14b7260ebee35a6b287c034595677263aa6ef2616b3700706aba494e110f8a5ef9891c9d5b74afc2b0a0ed5ef6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ea41bfc4e6077de30416d3f48952a2f2b80c72566e6ae9bdd94c5598f2510e928318393814b4492f51c5b7dfc09af1000000000000000000000000000000000b142bc3d52f95b66af951a3d8447c5c4ef58f9f0a3088dd41d48289f0e8d6b49213c7bd0df73a9efcb8d0ce2d7950891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001983c136dd787b593f9de878c0be2f776aded8189a415f25d8526d5288ead1a3ce133a10199fe6864dfb6e1e583134f8000000000000000000000000000000000178b3a93ff11caed714293b7836331c86a0b2b3c438b3ea094610311cf1ec2ee0e45bf30bd4ac69bf18b059e924e53a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8af5f133df392287d690e720465702e3c9adee6885d889b152ec4e75625e9377b08f4f8f64d8165f74872cf4588a9f00000000000000000000000000000000066083df5e8c4bcd053c6b5f51284d71b05b8787955666ee5d4fad5d492fb3a5c51e33a6e5eeaa5b4e807115d620e1e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5bdba84864acec670b7b7d1ed243cc84b275da0e77aea36a066c000f5fe8009ffe8f0581c5dce4eaf89a1da646005e000000000000000000000000000000000b65fe86059b9b0a052da0dca59f0a20378a046f04e85a317b3a892adb330f498978036454b8c1e9beb9b563c6c60f771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000087a1530d477c9d322ac7e30261875a1c907d67b318fb61e32c2698915beab1ddfbdff81638bf90f1b85915577e7214a000000000000000000000000000000001617618e3c6e4e6c529217acbf8322ad33df61ea43ff23162117462182a8c1943b8b24386bd22ba6f570aebba6634fce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091eba09469e5513c33402a796873998d13749f0f0f0768fc0eb75ed32eb76c811f8b76f5c9735fe9c99331a529e73dd0000000000000000000000000000000001d68d0adbe6014c4b085c3f50b57f5b72fda82643ce97c0f82dc92de43214d4a4f67465e0e85be052c2814a09a60ebc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d10b5843e9290caaea1e3d3d2ea829be24239d80a0367bdd352f35aaf8d0e91ad3bc76cf34087a87b3a807e38c19bd00000000000000000000000000000000002c710ba1de01fab7baa625506b700cd852296f3f2307246de2eaa73a71fff3158bac99a0b0194cfdd12a6bb08013061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004bfa8e44c067cf500a2aff79f1c14b7cec731008ce05a39567310c241cf026762cfeccf9810604e098d58aaa262d8cf00000000000000000000000000000000162c993700e788b8274bb799f569a55a0baeea5eab95ad1658c0bcf11cd4909db72db0ce760b0d92c430318795815fed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0bbaa3022cf2909cbe0fade6e4f029ac4b4a16fc4f4e6f081cb411113e3fe1bbad3329b3b1b7efca62b558d2f4bf95000000000000000000000000000000000db0976a1997217e90dd351d50586f7fd524481453d4c86392e407c8bff3338cb86d849302158fcd296c9487b19e55e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b013275a0d3f621a6af337a59985cdcbe84af727e1bdcfe30f61ee7ff275d9c414e0069898c07520ffa098d40870a30000000000000000000000000000000001b4e2d52768423046776a009df4aec0c7fadf644f8f76ff82a29ec6f8ded49651df839e8f6e1e381e0740d65dbb611a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001062b55e2cf3ee2034579091a7c8addf917ee680fb43360dbd8c2b2e7c23e71494adffbcfffdd5179e13f7da4f7e359300000000000000000000000000000000038d3cc6f7a3944fea40fd518ee7ff00a4d8b92168e94a8db1db7fa6416ec0f6e904cb6663a6a3c4fa065afb25cd2c601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015aaaa8df2662cd690b468ab03bb9c785cbda41d6a7a844ed92d3f73954f7c2dc17b13769ab8c53db83e7e61269ba1bc000000000000000000000000000000000ca26871a313010aa9a86c1901dda8cfb3432c258bd1c96e66624bf54787eff940d2186029a20cad37e7ec428a14e2f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ae936813317c94869bd8317e689f54902d73101b06a5732c09451dd4cd5721107a86aa7bffbeb7d17733ea45c9ce430000000000000000000000000000000018e547e0944c711bdf1c4994f89ac004ef9c04a5a03b20c1ca702b9545537efee7403adecac02a77c41e94015bbd07b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016790efe4b82dcde614b8931d6a25ce417753c1bef2a1ee1692aaeedacb14b444513c15705d8ece891f667d42dc47de80000000000000000000000000000000009b19e232b5f306f8de6e98b31d85b51b7cadea3552ef51d3d92a348889b8e29c887c0a0b1575f35c4382d6d7bfa2f401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dcd6364eb7d0ec0b5258719220fe69feddc47bd17887775019ede05d429f727bc94d2e06ab315f7cb170d9a7b54f97400000000000000000000000000000000019b3b86bfbdbba0924691ec0d66e3327936ce3d0212baf85aae6729bfc6d7d6dde875f8b4facee5842aea557ed93d881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017da7037499b229f7d55296fb2e55c6f110103dcf8e12779778302f8f94919658b9ccc4938de416dc1067190701789c60000000000000000000000000000000011b92400daec46980addb5d5900fd411bbf0fa952381d206dd9606f62f07fd3c1cfd3c69c8bf4bda998af0581e8b7db71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c638745d19052e7a0c112b0c9009666adb7f805b16aea3e796347d82227aabf9e9a6a60af21b4ae34d5f05f5824aab000000000000000000000000000000000e4722e433c7b7ec0cb22847de4be1eca97ea228ded2eef8c0edbaaa76db27b91d00dfc897a78a37a90e45f4456ef6501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d687d732fbdced94d5f9ecbed5fbf98a4f2bf65e16a188f7fef2e126b73eccb9e442685722b0e6d7e7c9a25dbbd8a3000000000000000000000000000000000a2044ddf20de6e19a7e567704edaf1ef0ea83ca30b67d4afc374f34fbcaaf10a2838fc5a1758376f44556efb56378821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5bc97dc830b73e6ce7c6a47a0cf1083952e1a4fbc5c24734e6cd28845180a42991c627e7328df68e918fb8972e78fc00000000000000000000000000000000108a958bf9b0284918454bd6ea20c157bafdbf5c9ea4dd0fb3fe85825c93a2cee2e06503d925f0fcf67bac5b023991651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071866b57d50c73f3f4f30dbe016ae24e6c4ef9330077f8851fb8dbac37b4ad20e6a6c48d215b102517699dec4b2b9e1000000000000000000000000000000000aaf064e542c19ab90c9f4d3deb17877fbee0122cd674ff619fc59cae3c28107e04781bf1f2e43e55114402432c9a36f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118ce088e0cd4b66df3b0366a551a4d54ae76133235ea5a2b3f074266b3d7f84e737867d907e0d014eca7132336dcc85000000000000000000000000000000001320acfa92c87735d34762cfc61bab1eb7f384d07c3f1faa5eebcd8d2dc615bfdbf7ce5c3982b1c5ec2a6cd5dea3ea3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116330d790fc56b0047ce1866dedc3cd3551c6d618fe0f2be69b70f12f024ed625bc9bf366de68644916c8835ddd7f560000000000000000000000000000000000739a3fd6a67bfb45ee45bb95986e2dba04b6aaee0423203d69221364d14830a59493a1c62fa455c6e4d862f745e59e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bebd036b96525ea96cfd47f62e55f92d397cf3a13af0f0a5704a274958ebc8bc7b6063818b6e98fd86578e8c47f8d88000000000000000000000000000000000ccb140931550ca68597346f74b63723f7f9c1f8d63526341b45dc96e34ef4d911c1c7a46ac1b422b8c599739f3914641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb8a00d8168ff3f28294c423fe93740c7f52fcba0604d3e23546c1909a0baf34a61803a3200e34de56bc9fb239a10ff0000000000000000000000000000000015f3fb50ede2c632dedd8644f119ba77ea5e2629f115b83916452edb51d3f7d2f9b16562e4ee6efa5aa6e03e28b595e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179ff44766ad25edcdd58e6a0c1ffb8acedd7f8f4d198b18337e6a08baaaac95649b7bdbb21a256459e196527e2de72a00000000000000000000000000000000078e247cfa9ff9f72a908137996ca3e76954cfe2da0c472c8ca005aa565de7235e1bba3e504dd041ef4b62cf6bd124f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c9301294660ce4eafea209fa7c078be335916c162c721bd4187def32afbfe73b25e3bd721949188594ed654fc7b8ba000000000000000000000000000000000fb41ae7dbd4cd4a837e0d07a2d02bdfd5e40b424e0bd68896166018a20bb15a5ca8e0d0a95cc72c0af53398423439261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018685afc44721f38a2bb7e73e403e1588c09cd9c6370994a72114f0bea4b8bf370f1721e9f25b95dd018bfb6b6938cb9000000000000000000000000000000000ba51632db64e795e68faac8a55d81282f13f1b84e5893c42b5003db4d2faf5c50b53b939e88a4d56e938702d14271401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000534351ed6728390bc67559d92d82709723a271daad3a3c28c716c762de4f3bd39a39d2e34bce0de99d9562e946d48ee000000000000000000000000000000000d730b2f4fd82626364998bae177f20a10c78778550c51e1ddd017e34c905dd43931a05fadb2e5eda1d24cbc94523e291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001363cb7920aab3fa7de8b49bf6bad01f0155d429da7217558362a6c93a8c9c186203cbfb058ccda492beaf8ea1a3c880000000000000000000000000000000012c997698913af7763bcb9d3c4b0249cb3510a39e7ddaa858ba7ca11f343b6b37ed1692fe167e3749303bc55a1e227861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e34b30d9033a4e6e941bd9bbc07b46cdb25990e43c7e86e7384794c28ec1f6866fb3b34a8342affa585caa0beac1b00000000000000000000000000000000014309ce6cdd10197002f7fdcde0e1fe85a7423857e4d0a824c98918ff2222aae394cb87487e9975385749c9c0e34b6bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034839d5b9536e5c7ada6bb9169e9ec3326d5a80c7b530cb0e2103bf6dab27d8c3ac5d71ada81f7ed8e067b708fc89da000000000000000000000000000000000b6d9272b74705bdf3a7d707993d427c4d3c8b91902130e3a203694f813018bb74ed2771545da294c6df16de573263071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9f766ece814917946be335caaa13861d35d2f34055197f0666c7319f942e9689def3d6db443309a4f90c88d58ca5e500000000000000000000000000000000169adb818225f5860c52af7c85bfb41360272689359ac73151c00f0d87771f4affe3fe77c3837d20ab4f595dcf49495b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fb7cf6eaa5bc485664c166211796b001cb20ec9bec47119838041bb5b0f57bc665bf72b1a34ae6f66645a3af63d9e40000000000000000000000000000000008b02162f4802981cd3302e7db5d844fc7bbff083969248378bf621ef6b25297578e334afb3c8eb8bd99b99f97015b541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8e3fe3ef149a1710ed568f3aa376e9db9215624e0658b6f94ac9e55dc838c2c138d9b86670245deb401856e9593eba0000000000000000000000000000000016c1eb0d36d150b4cffb995fe9488cb831f882597810c87bad036104eebcf3c5f43d7164728990251609a4a712474f231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013747075419153101b76f3dcc1d908568e156208eb48cd4557ce55e7f0e5a1fa84c85b905cc8013d0f85cf3cc8f760b4000000000000000000000000000000001559634aed4491e19eff20314a1d9f88d3166eee4de46c16ab7c3e4a14227d3e20dd779a9ee77d83a6561258255b36461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e282b9dc942f81cb165154e0b5b307d3d3abe6c152d733da0e2a62bb6a6a335a206f4c72d82f1abc19bd82dec666ce0000000000000000000000000000000000ce9821d323eed628e9765e4e7242604eabd6706ddfd722d70ab5a460a04f18774d58c774726a5b131b91bc6466d94c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151b426aed83d4246ad6d563ad7926941f4c5400b0759881c928d666622b0661d22394a645d20fb8c839122ededd7c2100000000000000000000000000000000179a0e7a98f30313c1764ab9322563594dc818ddb48ead37734c7905fb71abaea6ce702f7be9cfb70a1b201f377bdf351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167614c4ebae80aa0f54ff8973b477994905f4beda38dd08737cbcb0127449ad9ed2ada115a09f41879ec167617421b60000000000000000000000000000000000cf7d0f80f8b4b47494f7f069fa5685d5c5b11f5eb92b7893d45a854d2016f86c2442a6d06a8f9ecdd8748c548f9e841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012980fcbf77c238486272f6aa6feeba05204625f660e13e4dce2429b2301366a82a37f7a7bb73764c1fdd6fefdb9ad0700000000000000000000000000000000086ea68c7da02ccd56754dbc697db4ec452ab17cdd8385d0d1cb71ea0a71dff29362809a67226882fb91820c2d0eb8391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001056dcc04b55fc84e63c830aef44e53394439ebf8c6d856d3e444f4cc742abf67a62f16e38e3f4cea21489ca023bef54000000000000000000000000000000000c5fdc98fd1df5ca161965f95db18b52146a94c6b7e7e586695b75c105c28c3703fbf4f1a0a7d01aaae158b1deff97741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007bc08628ac314db2d0df80aa1642c1b6b15d9a8fc7a53da181aede785212d2341dabbe616fe13d947b748350585d889000000000000000000000000000000000f6caa39240d5daa0c5cdb3e8aea7698c9e9c43f8d285f610138174bcd7217621ab81e17f3214b63cbca2af012ad73dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e35d889006324c7f1a6cc9151446919ac23131a6a4dd9554908d450e9d491e4475027fff69daa1f489a921b7e70d7a3000000000000000000000000000000000a34b4ed032355a44f02a3239c053b3e50915cbc7232cface5d1805a3341d5bb67508b8bb118cf39e5c8c0656b7d2e7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013b790df48550951293d76bcb64f351550d4d65fedea23d45260df33f93c395bff8d77810223d9dcf1bd50ee4bc1199000000000000000000000000000000000b9933602717af4ead843cda9fff47b893ac36e63f83dc6df96a158a1c83da1d5f89ec32f8e50ebec374d73bff769d131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001949f9a63fdd03651968d0606a7f7a3bfd02f19fa00af1649bd9721050fc37da32f69ff406ba60fa64655e60d1b633c60000000000000000000000000000000003e075b56327c060e99c72dc198ef9b73aa42869d1f49acb6bb639867a1d71a6bc8f2346f88aba4e47d999516edb1be41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e50183d57cc446d088814345100994e2156e524d2cd88f96c1590a2b16462240de058ce245952eac8c93b703935f3840000000000000000000000000000000014cd1af73bbbde453ff3090c57a4b9a3fda8579b3a7f5668ea2a53eb514498c2581303ea49c4e2138724c37b025194ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124dffcc8eddb5310ebd4de55be4214ba405bdf21dd11b7614a6a0434b299a619fe7f37c46ce7405ec0bc2ff47fbfcf7000000000000000000000000000000000f8dec31d5dd4a2fffc249d6056f528c2c7ccefc3763b777b082bca726b35126ede3aac894078429931c513c7461f51b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000645a92961374f7c96bf41d4271954ae939bd2b3e07e655e936bfd7b34fd26df29aad00fd3bf11bb0e68c9048ffdf612000000000000000000000000000000000dcdbe596006772dffe0363d79f49597b6c1fcfa433e6ccd399a2043271dce6c1d3b26cb6bc1b7ad87ea3aad232cc9e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176d00b1108d2c0bf814bd25d2f1208fcf704c1bd9fa302c235b08fd3be0a73af960957d27101a0a9cc3e62002e595c90000000000000000000000000000000010df2c7cf154caf0d8c401f689dae28b4b2c21d73ee04133503bee9dcb88a8b645cd3e6aa0733742c4572160c688bee51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d734bd0e4b9b588d5b0a6a87c79ebc7cd43e0e7e90ccb4262aee3f92fc99e92f349c3fd0b3f30f1790d09bbdcf0f7a00000000000000000000000000000000070ff4cdddcafba9adae1966209e6346157b32677dcb70f1bad3efe2d119d6c8812cf77f3dda6ee0594629e1c532c8e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2f68cac3b89c938d7a2f19bd9fc2ba53311bcab1631c36d19c7dd0462552ef1bf74cec5bfc5838d9cefe45fcd745e20000000000000000000000000000000018e72b4800497d9e9351f88f50d8ff1a686cca8f2591a6816592d0ce8187fd0ae844638a7392312083382d4410b5a99e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f3a5bda48e0d507677b614b98f2f8b53979a47930a5e4b979321391d044a7561a27ae2cecf5b2ee95ae960ee297bc900000000000000000000000000000000062aa4c6b86c68516f9a178761b918b3bfeada8b1d8c48f5dee8058c91c1d17c06dedb6bfff463361a92f79a37448a5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051c0061acc7d4223a1510f33459041726d6997571fcae41250989ac7bcfa790b49fdb3cb78e73d56719423d18760eb70000000000000000000000000000000012244e53e33d59856e3b67600db0c63a8d3948a8d31fdc98bec32e5ae7f0b00516ce7effce4ff686b0776b5dcc6a29751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d29f0db0845d9181ddbcfd45fb8229fb812d69e131de33ee3083a6c8199ed618ea29705a4aa860cfbd602dce349eb70000000000000000000000000000000010bc8a7c3eb7267e17dd7277595449fdb7d6357b2d8b1e5c87140b5a9944cde3bced65db1708db67135398d3fbf16ced1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001293d1df5c00da7c245bfba82d0325a11d9e987151cb789f4a31421b053c1768b38c56d510ed65b446c22285833627d2000000000000000000000000000000000d5d0220f7d9ecb1f25eaf14829ae4e67c5f975da95781280fb8d2e8b169af2ec1c431fdcac98af15496cc993bdd122f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002816fad0f46a5bd3d8f3f6efee2aa199e8df44eec89928bfb5d2bd120cd26d5eb83c007c9f0b9819cdb95bb69849bb400000000000000000000000000000000079c91fa657943be028d103bb0306bf2ddb248ad7491266f23a2a5a91efbc39433d6d0be5f0d00616248e110f20fd4401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d907672dd066ff630d1190a35e3a868b85b861846bfd315ff120bcde4f0b299c1ce26ec0dba8f8290e4a4b667a85670000000000000000000000000000000008163bde37562f7f8d288812e2caae49ca9855f1bfe462cb80fb70bb6ebd6d2a80d3923bba8f4aaf1e05ea7412667a801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d43a8285c4968a1842e7bd6b3e075fac7a78198915244cd080432705305da10c0b5787bb382028bf9b0918088371d7000000000000000000000000000000001097dbc47ba22944bcb153311cc5affffcf877dc154a764388968cef8de2f39076900225a801302a63b986a4abf41c381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0244bf3dfb9ef5902da6038cda9afa6a2033fa8bdb702a9639eff89075d7591f472def2ba622b328470d28197895f100000000000000000000000000000000111e150ddb83a27f9cea3633e35ee90ca0b1ccb8a2c14c01e527ad419c05ac438a6286d94d8f3c07aef7cc640708a58d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e74c8fb2bc3cbf40f9169e21866fb7490cced691814d830b3a4350c2b53b1deeb5e87e8ea12ff6be263310eeb13274a00000000000000000000000000000000190d5831d2c33bffaf7534a2367b512b2669b671ea5afef7b1c3a7dfdfc6bb53fae01fc5f17c476813094e4d6ea1a1041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000008b9a6d752053eb6de5d4ff58970bba52434cec632207fa534ae0f0029a15982afc805b9421a4c610f163811312f0afb0000000000000000000000000000000017dd2c343fe248bf8d97a1b5ec09bde9e92ea63c24bec6a9453d041099adde402a6ddf798ecb8ea5fb9a962a1575eef0", + "Name": "g1msm-256-jwasinger", + "Gas": 534528, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000187ce84998b854802f88ad4173c436c43970ef8de0065a10fb93036a7b203ba751ced055bba354b63d53d676e47338a00000000000000000000000000000000010b272ac018b886988ef4fd5f835eae94e8cd1cd7fb7a1229f60a2ac25c9612ec73354a3b0aef8b56ee011339b8934a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195ad1965afb993862c149cfd70b3e21253cd38d831867750c7f3cf59dc4f0776d43ae3adfc3fbb7cf72aae22684fb84000000000000000000000000000000000e0502529af1e4b5f8ddf4ec0bcdd0c1f0ce6909634bd3075dfa9bb057756f2644354df49eb23f99905becda751c5d241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e554267b1fd3605c0e3250193d91024ed8face3f03a3d52676ac948af6cfdda5aa946fd6bc621b5173e4fc0b6ccd7640000000000000000000000000000000019f966a24b8339d3cc80588e423408e903ed83fa804777dcf464aa582ccb6cb384aff837567768353a3ebdddcf959de51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c045b02230677a23025a7c1da892cc80177735b33aea4047f6464be3d030edf27e30d2a3f51b8f77d5ad046c7fac700000000000000000000000000000000001e34ced0cf1f7393bc4749f085ea25eb786bd20f774049eccfb571ad06f3f1fbe99bce0a45842646e82afd1d8d816e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120d885048d8a308ee42d6f6393eaa63554d28a4ef9b33335b475db26d8257df0edddbb933117bba03c9cef836c6d8c900000000000000000000000000000000193a9b9aef41274b9b7098e52702f1e7697112697ac07615c0ef44a91748703f8993eb472ecddf8f79dc0addaed2e6931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001586e2cd55ca73dd3f4f7f2758b2c19bf42b05edaa03f3f9147c2b46731c157dcfa8e164869bc6762e4feb5385edbc450000000000000000000000000000000010b3086c347c86c01c8812c066b77c8ffd89e5537737d800b55f17c795512db134e5e1f2c1205285e8467df183c7cded1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001581b16583f0066af82aa49375eef64f82a72fa43a0f129a1f62adeb9ddc44535263120a5cfd57edb58bd394e45ab32e000000000000000000000000000000000bb99e4c6a1d01f700105a0e6d2bae9d81191ee7a3f784dfe32ee632af0f314719676e96cc52037e6de800b2380401011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001161a52455bd3b7fa5e43a574f8dc8b9b5bf7fb684d6dc92b81b73aef325fff67fc79911522018ade6cfc10fde5cb59400000000000000000000000000000000063f97ac26ed3060035d89d9a59e0c1091af88b9ff599a1e0323567a863ed4c3148cfc5969f3689d76bfee26895031b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000641a852118cf0a6a05a78463786292daab40116c798b1447131b6713bbb4088ba6a5e01969a689230d8a138d0a05b190000000000000000000000000000000004578810e6099aa9eb274fbff7701273836303fc5ee5e374aa4c3dfba23a349eacbe07b6245ea9853327b6cf7ba0ef1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102847f66d4c2e8690e282ab10b55a8a4dfe0f121b4e157664c83bf45276532798b861049e8901a813c4d9b0d31386f6000000000000000000000000000000000e7cad0243743a13018f0bc944d31edf6f8d7366ce72d0ce60711bcb3102d77b528959120899f8bd83e727948bdfc0351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b2c872a0c874d8e66cb5eaffd36a38d6a7768f96526132939a85da4b428cb887f62daf58c7cac0f4406d1d8a995e560000000000000000000000000000000005eb0768c8127ac70f5f7a9fd30bb0b5f8082c4b20a37d5133666b70673b9e74994f29f9a2eea1e6d9f17555563b95231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186d756fb34a2764696f703388f6a7aa59d02a5f36958fd1e0b06498811234532e24b93f8c17b2dc2eb48d0b7c41deee0000000000000000000000000000000011c6d08c56a82cc263b5b9018a3929021b7a5fa3fc9dbef58a02550e32594394644829330b6cc1ecf0498b21a519d2291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175c7726054358855fdb12c972ee512657a0702a78f032868958d81545a32372c111436d887f3c445347b616011429e4000000000000000000000000000000000a4ccb54601b7ab6167406924716d5f00d8a57206bc8ecf58fa879ac6e162e6aaf8822fc6d66f6fddc74f207c0b273801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e9de7a193e44172178d6e47008f51ba2452a24d6c19ad436faefc0d39cccc1f9625d3d5c76ee2ff068e72411333a44000000000000000000000000000000000d4df9060e36c437af11f37f35e967486abf67662342909172b350198681e86c6ab296d4e5e9edbf9107f413d3be77501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001056b2709578723639db0109371f4821af1f8520163892e5f1d7e365749d4f3ccde6cf214debb0d6e87270d8adea2d8e000000000000000000000000000000000784bd7cec07e59e07441b96000b72da4f5e596a6f38450835354d55ae56c952f0ad441241de05fb643c13bfc8f5f5a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013a3964d2770792ff55c8a5d0b72ede30853e50801b45aa9b74c83feef7ee388a8a41132c34d383aade574bc48980810000000000000000000000000000000007c4328f2baf080ef97421d89a39f1f1ec08d5d7f644f3abf64d057ee75956796c5ff21ba2da7735bc2f69d756ce881f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e67e08559a66ac77cdc2b4b205a51170b79405762a33adc9da0c05e1ae9f501f627be547ad19fc2a42a5f1d6b2b413000000000000000000000000000000000a171d6f2f15cd97ee575ca2864a0ea1457299745a6ef37d84e08c61a713a33e4adef886bdbf5ac1f8407265b2d913ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001605a9f674d1e5716a47b0a27859fcd4321705d305c5f972ded1a3b6b35d675cfb500d9fe6d58f1321050dadb84e77d600000000000000000000000000000000068ae969912b75a840a0bb553a502b7a0b655f8ea1134217fbe4e5d2114df44f2e7c97887525cb73ef01ab3c59972e901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a141218ef8d853155fd994333f8495469a7b4c5e3eb7360f7b7fd0a1d90e2146c94ed32f4e528bf60f1c83482d734200000000000000000000000000000000034894c3e9e45d1e213c0ade99f2738688dfc7eea763dc9904c4d2003d07273c590c38ac51b6285300335253449e29941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e15285c31e5e54f0a46562005007027bb38066001d2f00ec0015f9da149a477929e40a4988d8f370352b8ee58f3b17000000000000000000000000000000000488a996bc590e150f8a3a78a051a6cdec91a9f96122988c53e7d20cbf2abf38765889256b362fdc663b71ca1f6c3fe21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178dd54cb644b36ee8808e28325334f0b9b8788c8f5127ef17b3bb71435882f8a35c6aa852492421fd5526b70f4399f900000000000000000000000000000000102980f257a2493a1657104f6f32e14a1e83083def406bc31e1781ca28a41d83e4efab88a3017e655c0fd1d2a28c6b091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a7550ac358e93dd0758d1e08d9893a126a294a0b28e83c7349d3e5987e7c88936251109ca01cf8aa9c641dd890d450000000000000000000000000000000000e588452a3dfeb04cc361cdc2b71e3197d264b681c7cfd4aed83f4fdde83032b94862abe464d82e8ccaa99f5cd18bba01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001725ccf063832c4be0eaea56952ae38a86d1054889ebd870e1c7b5eb49556931310b63938712fd3c95b55d585956b59000000000000000000000000000000001153698ed6d6e5afca492fa1fd9f35f00b5868ed9fdbec1368c303583e4e3927feb52a6f842c00e935f37f73e1373f571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008dbb8bb33a641073dbd96fb2f0986ab86d78b5a3f003c241556cd50f157a6700c94a731ce02cf3dc9661c5c9d2a289400000000000000000000000000000000158fdc083244605ac4816fb042d957071eca9ac8055c8c788436bd7c1b1d63a486fbb830f99f964d31a7199071087aa21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000328e58e92e5639e5f1e5b6f252cc8e9543c4fb483cb1457225c0e870c125ff6f5ea76f3f1b908a1a258cffb59fb36d800000000000000000000000000000000042df1dc419c0e4804f7154e64eda8d2c6e59d33df473ee8efc0a28f97bea6add7de509386f50250fe0608176f4bff351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7170e4232dcd331ca554cb3ab76b77cc9fc168c14232ed3d55a87a9051ba62e83ed467ec2326cf5c8f622ca5d769c40000000000000000000000000000000004fceefa8dcc518d02531162876b6176751e41be1d157e552ec6ad96d63a3d6f8c2bb9d090d30449df926d15db900d581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d67c5391f1e8cacfa074c0df5343ca99027272ae90bec85eff0ad5cdc254df8736f4f882d0ef9cd0a9139a7220c5ef000000000000000000000000000000000a0d50a8688a5c48bea149d2429d327d8ff974ef8fe9018d3ef76c6bef71e4186f1e5f184a956b6be76dafa868161f861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6211f83d0e73f321b9d7996318a452e56df0c3ea9d2b248e0376526f46c5e4c3a30b014e916b3d5c0e92f002e3b7e500000000000000000000000000000000088d117836cb94cb468ceb40e2a31709a25b46e7fff6d065ddb51adf9339fcbc3d8cc046a8847029a40cc08e6a1e58761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e7b33464590ce097932c739177fa679085f1324c993f5d15d4eb913615ac5079457b53a32fc5710cf0f04573c2ebac0000000000000000000000000000000009d86a4905d01b09118dafeb79ee65b3ef30525296c587e48abacc4cfce7901926fe6335f5881c41ca0341e6eef8a6761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7cf3fc44440b4976f5d264fef4f50cb3e79dc8df90a006d0e3ea91bb547ea19ea43ee24a06d27366eaea851ce2dcd4000000000000000000000000000000000049aff14e870c1d28663bfb416900d335f1d58a62faf6c35bedc4677946e1f7ac74eb4f2780d6200674ca73ed9ec64a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c2ce9433cb42dcf70d2c99edd97e0702afab3349e91255d3e7e7f1b71085ff7ac422a140d43083eadc71e8b31d2fa100000000000000000000000000000000041b87b4d6fc420a120273a5762ef25fd38d8c9014efad359af8c363cf0eff959b3adbabe1e26de0537c9a56e30cbd831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002100fa192aea9b42d0ee1fbf06ea43564f96af80ea70b14dc908a2e323cab7247385ea99e801192a2a192136f5f18d20000000000000000000000000000000019a11c656dfcb9f0bcebf9e37ed7e40d1235a89dea2cd7ec4e9db34c6ad92af7e7b0e82759dd88c9bdfe4ea8d0c1e4a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c6cbee9a045595d488d6d7ada13324e350391c5f7a0b9b7e076e34eeda306e77bbc7c7c26e82eea928293eecbc11a0000000000000000000000000000000001307ec99dc693d57633dc04929db287fa7b90ceebadd28ac4ccad539e97f462562fcda97d36496bf5849e1acd3ad242b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e1d7848271fca7d769adf3d2395a18e00f08c7cd68b38d02907804609200a2327f38afad57dd824667c51d8de83bb3000000000000000000000000000000000ab958637abff351b982c4110abd717226e4c105b046d61ae84d44eb3634ef29c226d5bf5baafce314981de6bb90526c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000171ef222bd35366a7e3338b270c660e614927b23edfca94188690ad6194afef8e27909e9c2c838375258177efb3aa0b0000000000000000000000000000000018c16ccabbaef85432ca28290773c80dd92455c33e5ea9a62ae450364f25e083c444a31a18d113877971e18b9a99a6371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f6f398867244467c7786dc4ac5d464a31d3787b41e88aa1a419d10acd58277208b4b0d3545490b9c2d713a6cac27c20000000000000000000000000000000017ad1eefc1ac1bf9e0c54a14ab2e14333bd325be2447c0e6ed48fb733019f6c4a8e5f59ffe8768e977489280cd2715e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea993fec56b53ed68f3b61a2278d0f4f3bb6104352efa3df09a6a55991000c6e66ae3fe4b69db84f938f33b59f541f6000000000000000000000000000000000737a52e04dba5fabeac7193d52dd5857c84115581a7db764ea2e78e79fa27f677d3032a05c3045613e3dc7d418174251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090048c31e9e06ce14757b304d3b55e63d19c08dcf06616558eba80419051f23ef82a8ef9e04e109b93305a19a12f2a20000000000000000000000000000000004270beea1b5daa5b6adbe3b3db34d6d673f65789cca2ed0bca5eae56d90ab7d1a1c45ef9e00ce7a866d5fdc71a23cc31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e2ba4ae3f07ac233518eac4d9c583cdc3688cb5c9822725dc0e42f88c948404d7e76c37f9ea6537d5c226d3b8db99a0000000000000000000000000000000017cd40cf09067078aadeb41e11fdaab3c7e7f2229eb8f51cdae932f45865f14217988208295fac7491576f00d7f59c7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b381cae23f27665dee91932c327b4c38a439ed08f7a2d4007bff04edf72b7e9617c4427c2b1ccdb01a43294879ef04500000000000000000000000000000000073f42604df8a5757667f534cae4e7f44f853c94f52ea72847be82af09b23af5dfac373577c4d21a095b9b13862497411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018634df6012923147b446c084718d355b329f4a43f8ec2ad46b4fc14bf960679de85a2aa5347e806dcb1cbd44490310a000000000000000000000000000000000640a547b2098b0812dd3ad883eb3b9c53198b487b68594007e084ac70c716229aa53bc8c37b39e96998a0e0cd595c1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097df85fc903cd4288c6b682d581789e386fd74addc36fceb3cdb184536b6c2bf8c01c73aef75baaafe776f6b98bd6890000000000000000000000000000000011069db7f6c46d8ca62b1f67280c3c7afc5bf64dab5292843d8235dfb47b3377b43ba46f8c575086a6b95f730da7487b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168ea9eb33c2d394e8b68a93d01e9c58bc3c3079540363a9a3a7531e5c2ff57889236c1daf71930d0d19f4e89763f73800000000000000000000000000000000044881325d5bc0e981781cc92613ddcdd066e7fd5471d1111c30f6a3754185cc20b50744e276da2d834c5dbaf152908c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3f32651782acbfd8e62ee758cc9d4407428e2176bafccd951fb0cb21323d0fa6a7c8753ba3ca136efdf12e080bc6fe00000000000000000000000000000000037c66bc55dcdf376086e2d2d1499210ffceaf3c73eac4fa98d46e99291319d0903b386fc6047d5456d8df089cf15dae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a67b20c5b23e1597a5a1aed5f20523aac6646f80f34b22f5137ba16c88f7194ec6ab3a87d6dcf1aa466778ac7af6bc0000000000000000000000000000000007b5f3e65cd42fef6db9a6969f296f931f83e10912a459377513429f1bf32aa19861dd98e0ebc3ef92396392093fc44f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000153d9bd9b5658cd072674eff31a0916f3b9d1eba2db71f59035ea1b5013d87da5588e09cb4ef129b5b4ee03e84176ee0000000000000000000000000000000010ca3c087b3a78f55e3aa476d9879fbf4cddad4290716984aaf3efaa15837712f2855d825f69a93e5a33b62c8c77baf51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c8f72f625afa983ae57929ae0fe74a668719c7e10aeecbbc11137437359a5a0bbb72c3f6dd6b0ea09717d2ac1f3eaf00000000000000000000000000000000017fbf8ca15319ca19bfa4a4e560d9371ba7a5b7680e9fda75e2dcd4e5e87380865a6662f231ce194c6cf3dae38215371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c2f802fcb22774399178729e803da4c26c5a403cd7bb9d40c4bf9699ce55bf62325827e506525dd0fa46e5dd70376200000000000000000000000000000000144ec492ad03b62baab04dfe1f5ba6a30a40ab91947517c1f7fb3eb672abdeee1484e318c44ecc86f0e97f6ef5049c3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007bfc52aba0aae0cf6c114e69777da40606433b54f1a1db93cda6c656d8ea7586dedfced3a19d4b1f16030fb6d0024490000000000000000000000000000000011f9a04ed4386f64172db388565f8fcc3bb24c1510a629e4866951453d595e4c15de15ee22c583502c87e62e1c4a27631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f629b8d2246854ac5247f6b362e2423dfd04aade69d4d404ef11ddcc631e8e155a9d98f91b2aefd01e8e867fb1e4ab000000000000000000000000000000000c8cfbbfe2d6b43166666746d174d9c15dc8c59f3877d6667642ea7e53a366eb099ccbefaf63662ca09f82719f3e57aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121295886baee2bf7757a1ae44542700a635074461cb43b9f247b8883adb1dd4257b8c507682c7d37089b07f460d65a80000000000000000000000000000000003284d6070f7b568f85beeba1f7ace3707856796f4441050ea2daa2fbaccf3bc963f07aafbfe08e858c2ee861c442c021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b97ae0cc4e755f7c13c398242f0e835819be8cdecd8010731ecfd3dd8b6d7d0af1302889a9e25479ece8c68344ba01b0000000000000000000000000000000011afc7d51d8e91628be8d8dfd2af4e6e5e72e5f8da5b289e7a63415e8a98dfe5cb8125b8214f1bda68e12a9b7d43ffc61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000146f48c6e54923484e6314dd7b5116a208e0f7129a8bbae36427d2e7949246b4e2dcab61f2e9ae1a2535c64974ee0270000000000000000000000000000000000d162440369cdb5b1159eaa4012d2e00f4a0f06b9bf2e4ffb7ba97ffeb294340561dec66b1abfe36f895c38f41361f3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b84c410178ba1e4c4623b5c0f60fa0e75e041867dcea95d7e3b484c2bdff5ee2a1cc471b222868332b1fd23d3e9749000000000000000000000000000000000f942436ddd1747f3102c5ea5152ae2e5430c8ed5debff266d6a90c4dc175e051d9d562406e6ea2217a6959e20c22de51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba526fa92809b114e64fa99314b8181cce9919566b86e95d4833495bb0815b1c444d2a1dd5a77ce1bf86b9b61d936f200000000000000000000000000000000046938538113103942056a627a508c33ba201c3a7a6a57ee69005b26c19da8add6df00eada5b75bff472760b7b89552e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015313865333b896364ec7ca0ced1fe99c52cbed33f93915f3c362d71bb13b8ff1c32b84bc25da68a21bfdf63d9556dd000000000000000000000000000000001703aa367cdfd16e4cf3d117c99222f19f37f59822caf1c97df52d5b813a6a9f6ac58a67a5e35356121dace6d2a7fc761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ef0ff059ebc749971114f4bd42f3ad760fb49e45b4691aeef816dbef5f37275260d50e245754750ac16cec8cca45dc0000000000000000000000000000000007963a2e356324a1b46d8bec70642d525dc0a97e6b7830640fbf1a8954291da4a9f5d3bd40fec971c87754369dfa5f0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148c26d5e36ecbf6c961d9c3c84c28c9cdc7545f98e3733180bbc786f3c5cbec1942ba06fecdf9219ffe029d79eef69300000000000000000000000000000000114c67c2d34ba9b9d283fb9db8ca40abf3c0183de46ce17bd2217adbe13baa245e1855a5eabecf2493fb744e1392c80d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000661e1b7916472f79acc694a370b7931f6b6fd13535327d6e757d7ed9bc6255e7244bdf28844db674b989f33f8841280000000000000000000000000000000008c8af13339e01c69275aa77fd84f0735dcb0de73fc33967edae819484f3208726acc4b4a9f31b9829ee8f0c8193b1881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2fa1377b58bb5669c93d4d45c23c3538b55c2d9c270dd899aaa0d7a57da003973d654eb173f92ad07f3facf27c4ac10000000000000000000000000000000009a078170c1625429ef432a1f44173fb2f5dc72f510326ab65ff1bb66b07b3eaf717488e2b2b090387df471e7b9db4df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b6c6021a9832d5936a120895f2761614ec31fdd148974d4eb60309dce03670e9468dc56100db920d036c1d5751a5080000000000000000000000000000000001f8ef08d930ad076e92bc4fdab39dabf566d07a6aa0aa70d66a805ae581b24f7f3d7e39e1ee920c3028da110f03213d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007de9befd46cf1ad2849c07238dd7437eacd71d8df36b1f1241b75a17f4d9872b746804814fe10a6f18501a8a4f8cd44000000000000000000000000000000000a4375fa31b0f4c75c73edcf1864c5859058305e0de915e6da682532d37663085c8fbf92f22148deebc84da53fa241c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d45b05acff40a7d8d74ea5f83af1693534ea7b489a065d0cfc735f2a3ab5ad31930f743d0c48556cb3cffc4a6b891190000000000000000000000000000000000ceabc819d92aef6a63c3ee6c50f1f988dee1e5de0b17efac5a1285c5aed0342d9aa89fa641df499af64655ac5861151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120799e4b1f8ddba887942683f441317874515e9fe722bdf5b575fcadf0687eb5ab1c333720841cc6b00a2b4b56ff560000000000000000000000000000000001959e728c8719aab9c9b519033d35f173e904109b7a73996ea4f8a46c3e5834026c5f6c82e3bc39215b6154e61e4176e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026c309913cc8fa478f7911cc3ce4b915fd2ac29c2cf0d53cfe00bd04ddd8012e5c73bdebb8081b702c6c2a44e2b7dd1000000000000000000000000000000000e8b7e4d5601690f91a20c1d47ff9f08855944040c54e8b5986ce8fc3c3e53b955e0615e2c2fe04472bcd552ff2e01861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d28c9f1ffab3973a89100405d697c06f98d51d8a91f99415d5690069abeb912a1b7f9429e39cc3198d9d37b0e1c073700000000000000000000000000000000054a4d33d8c0393f98011eb94231f6883054c2b8b702b56d128218a555d0cf3dfb128d0508a22b65017f818d686077a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036af704eef88757e451b0cf390ba0186a961aee2aea7808172cd516e0ea1a929a8a4d591a98bf548ec005f00299f1130000000000000000000000000000000019479829047c50ca69a4b33edc23de1d81c9a98ac2817069b1d3f0d618b47692f580237ba88c5555bc37276739a4d2821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f16db8311ca90b20189e7e437bd3c883e63ee584fb3e747b34c4189355287421dddf4d8c9ab979bd50db29ffd3349f0000000000000000000000000000000018d5c39c167a331d583e16c713761e7f8fa0fb495c7f4e3a2eeb10e949c20b123854f9e31df5af510ef1fd8c058fdf2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d43d59d34e97547ab696eed1b99371000d3958cd088cdc4f954c420527d51351efebc7e680624494c4cae548664d735000000000000000000000000000000000a083f701851df77eb70bc05dfae6378d34a8cc466aeefc208b45fabfc192a32d14af9422f93bc8f45321f3f3a11755c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b5ff1022458ded52797f632120e4f25831ece08c68a5b2e4ed600d5ae9ffa0f187eedc442a0889620733ada2835de7000000000000000000000000000000001963c7f98bd579e5c822f7bb3adc50440f1c2f35275beac62e4900bdf918d1eecb2d3de326c5f4727373341eabeb70511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7ce068d7e92761743d7d2ef0b0209be2e6af909ab5cb31b00e5051cef08bdebd3703c86d9ddd56f9e4a0550d7f90db0000000000000000000000000000000014f2721e413eec9f9ee73554b1f11c310aefe359c77d792768e1a022b07f3bfd8f0b0d72c73c9480a03535f272b2129b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001691bd31f05952aca41c7c4288d1fa9becafb7dd97195a36412199c4fff9c52581df526ea25a28d897d413383d5becfb000000000000000000000000000000000e8ab7bd4311ab78e76f5d7e5e504cdf6e3d7fa0b31e693bcf2339c406738c553adacca21676b484deaa489d1a47e57d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ef81c5ffcfffb8126b46d73e03a79c2d977f18215f3af5b0e1711c16e6e98a48363024554b5220044591983eb0c4bf0000000000000000000000000000000007566f2197ba1f80150d41b4d6154a71bb93016d5d4f14c3d16dedc5c50e425938e472c16379336a9217c676a3448c071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165c9fb380549174c569d0f8cbedd333d873d839fb062545d0fe604272f88bdd0e16a65c9fde4e029048cc041840b96800000000000000000000000000000000016f37e931d1f8ccbacb0a7ef9644a32df6c79d980a7f824502cdccc8ba189f0606ba6f691aa2bec3ab600afd89559051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b28e11fc482195d636514108105c492bd557ca984cc4a02b152a8e4e9d92b338d255f8b4142792b43daf68cad78f7b4000000000000000000000000000000000c571f3828d50183452ed29ac99006e209c99c3ca369d436542493c539e92507d1b356634c14a23e7ae61040118018f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001172349944a78777e7ec4f3114aebfe0a6be8b47e136c266539ea9ac83d4554d6465019e8201d6906900d6add7e1b9a400000000000000000000000000000000003e4042ac4353e9100029ae784b1e2af5907f4b80972d37b193d4b8f5f745684492a2f8a8ee310283bf4efb0a4c76c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061158decdb4c556c7339d525f27f9b114078833292d1d829680464e88a0d5b08e75375ed29a8d7cac3c827a24f93055000000000000000000000000000000001731ab9fc78e98371a3eb9618c755bf2e74e96c12e64626b551005d0f80a85bd2d0aa8836ece65df010151530871d8861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd41da79f6a65fa52d32d0477b308757a08d1cfc71549ea7c89af17c75fd1bac1d37b051f10d9b21e93ae1f1382dbd7000000000000000000000000000000001110428ee61a888939d6dc767170e84e91e5adf4ff76f4b925925015d2f12b1720378417d81c0576010d7dd494e736371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000848e4fae0756dc12386104c599bdf60e795867798e3ed36b6c46b3eb92bcf7aeedf66438e037dcca22dc2e42b304e3c0000000000000000000000000000000012d635e6936a60a66585d4bd9fbbbeafa024a1897431d4957a35a912e2558b0162538cf8f012c152ffac758f8b691ea21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aaf2e0c027acd16e14c66692a0c264682cd0e59ce492f0d76b3e8b32a381ac1aca628c9efb6a76275d0a5b909ab4fdc00000000000000000000000000000000190bf8ce0cb0c2a0b2e4fc153587087fa8a36f2416dd1a070d6aa374f185d82adcc5b66f66eebf359596da234aea7e251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca28684198a8b3228d9c95cecef7b8c9a741cff807fce559644a7fb2ea41b4a85447fb24420fc31d0127d95a97b8d87000000000000000000000000000000000e02fa43d5db249d3f764a621d40fd4fec3daa9100a51c48c3066ec1f3d8102df994169e66f15326766e521dfbbe8e211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3623467b72ed7a387633886b1d7989df973d15c68748828eb8325c8cf1e4eee75f0c57ae36d9909e8036f5dfe2e5e500000000000000000000000000000000117389d123cbb614c27b503458de53fe51daae7381f63aeb04708fc8bef0d30787d380048d97f49c2207f98fc87f83df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015809e7720f15fcbff51ed9e1e808e1d982b9a931e79d4417f03a3330dd64865c9b0bcfc5a5211eb4d6af33b2be9960f00000000000000000000000000000000159cfe3711c51b53c2c53e1dace3587a4ad341b92a5ace2d12e912e1dabc73c41ef1a6e766d67b53907476eec281db4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b8d266b3054059a835d162c69fa93b448eb471e1f1a0132f534fb5e2acdc5319209d54f400dd7b44109909003e200400000000000000000000000000000000174790f3b0b36afb6abd8b03c150ecc8aeaa9ace4d676b82c4d2e5c8279b6b0649d9dfb75990e84bc3864e0bdec660301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d49e6661c53f4be8c4c8d23a4accb54bc7ba31eb8366713cb7b2e04ecf8d5b4fa570a591139425337eca656f68a57bc00000000000000000000000000000000085a90a20537be92aa338bd96bbc8a2dcb625004f6fdd1d2ff97ede587be843fc5aeca3dba036ecb9d093819b0b99f501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040505a517e14e7f14d1e2925299ed1ff0541328fba22441aa822879e947a2a8107537a90ee3fc51758e2417f66cf15500000000000000000000000000000000084c14d86e972a21448864aa109f32c85529c7a2c3cf237d94147fc922f2c3f557df05d21a5350229ad9ad9a5b3a53ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dcd08f39a6447c27df658e3ff81ee949b0291cc791853a0a6561ef02a1d654f775dd908fd3bdef520492d9c35d3b0800000000000000000000000000000000135d9b1b8a86b759169cfc2703be8e11568e3212ebabe4b1cfc3ea7eb60915de8cd2b27958899d814479a0252e5706581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002bd0d71f9aa7c0d77bb7791bf3af08be3cba4758e059a471ce5b11a3a7cba71b38614692a499f7524ab8bed031e5f4a0000000000000000000000000000000007f12736be3a4220d2600f2aad470e5fcb925148e356316d5040bc61eab7fbe5e05839292ca7f973c409545ae6045b361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016728a052de13a036742bccdb2be7171dcf6e820bc566ba7d3168768e49d0749e536d49676bf548105ebfb1416db84c90000000000000000000000000000000011146cbcdc9b1772b7d4ebe3091a3c98e620ed51ee1d296ba116f7e7d5c864d37c8eda23f0a7fe5972060cff73f3bb901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d8faee7092c5d9217b6926f46b70ef18d9058f0cf3ec93f915922f8f6f6dc7a87524ac76d8540aefc33e71dec493cc000000000000000000000000000000000399784e638cb987cad3bf60b7b7c0d5c0650f94cddf9229b97f385c9270804b47f9856a581bfa100f911a02e87882621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b7fdbd91a9bf084cdd80dc80574fee83e788dad84049fbecf0ab0930e6fd3d2a9fb60e10640436a2df594f9a387458000000000000000000000000000000000e009c7a903d267feb659ccd5d0a2e71aa8c98e668c249eeebb4146f8cd877dc11621b609382d9afeb6e3388cd76db701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8e38fb80aea5e293f3c2de00a002f113d1f4d756f39167951d5160beeb7be34088eae7018b02f9b96fb16613e272bc000000000000000000000000000000001554b36101a403e1c465b2123c9fa80997243b33cb7b0b678d6f578a55a2cb45e94326087c53c6dfc6af9f98d07ffc041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d701748f6dd4710c931efc26ab797bdcc32aaed25cfba60052fb9f01a1663b98592f35a05c6ab67073c73fdd4d3d54000000000000000000000000000000000bde0cbf90b70c9f1e7b9acb4cefba137681e8cc6158dcb51064adaf5af32803f59468b0ffe24e0200c8ba1086539ad31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a46d294852c301a9c4032fae4630cdf006538467d9789f237527d836c4d41fe98f5f42f1128bbbbc1dd39d5aaed15f000000000000000000000000000000001880b395967f991d7e182a9c110d2b507c92635f5ff7225de8932492e2bd9f311cd9ebb9fec26118bb77c31ee59afe671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012cffa994a209df15a27014ca485ecfa96d7208187707d8a64e6bde1059005d957fdb5a6b43ed9a07d83cc730d42d60c00000000000000000000000000000000176a5f0c4b33931db5a3967886f14e2a0f98d99089c21933cca4e0c58b4c4b9b7ce56ed1cf157e34e149311e9d0f5ba91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a178b204d5a16f860fff3f1486ce3c64478fe7d3e2ed617de627f1c542df555ca2e5c2172f9ca525142bc96d8397a70000000000000000000000000000000000b1888dbb2c1aaa69425ecb6e7da76913f3596103c6081694da24bb35c5c372265783225635a55a9a8889aa69dc18651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001032a6cf6330fb308fa9a50d9d57f20eede8d9e9dfb7bd101611d25cc58d69dc43b15552126a77bb535d7941c4f598bf0000000000000000000000000000000014dcbcf503ccfa3f11c4b49f4906915a075c38e74603129b9b7e13a4cb5d61e188f3a2059fe2ca3ec93846631e598a421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d26ac26b584533005d88f8daa715dc635823bf5f4337e2f1b1b3c1b108150d4855c36bce98fd9ab26a477b0d92a464000000000000000000000000000000001717be1d7d622643c1a5f55fe113a8624f23874f8d627d75c27f9619b2bb7e6114017b9657e799eb9b8e33e6b1a575851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122fd6942675a9b5ca6b653a0d72508af61c2e1cef60a84ec4b74589c8f1845e640855eff3a860bb51de52690fc9f6f7000000000000000000000000000000001925a16fc58cb484568900df04a38002687ad764a9b0cc45f98e70ab50c6047fff2efe1e5f79bf150d7f404bea4722df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001954e4a93db320ee261d17764ee80d1b6e2364532bcb5fe6ec2c8413b08b41d15061b3d83752dd8a35391ee98add79810000000000000000000000000000000013b54a3476068070d20f9bdc4f22177fdfa3aeef0479cabb1f67911970c4203f196d5459a5ae4642bff23b3d12bb403e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000989ec55503cfb70cf1469a0e0211c06444bf21d0676cd6d0e1d471c105e75191215f447227e354c66812bd550273d78000000000000000000000000000000000fdc9e514828ac56a44e710d98a5076dd481293ff5122d1cfd7e542143b691352c1120043df13d3333db42412ae162651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000095c4494dfa724832a953ace7de099875890b60e560add9c425317f5e8c08f46d13282918c3a3088432b861002c84bb20000000000000000000000000000000011bf5919188495b8b82721f81724893f66a0019207f3d5903074b8bacda46fa272cb400e14cc185bef4a5bb5a5f3d11a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000508588409e75e8eacb21f6a0929aa89a8751e92c0a0c2810d65c19d49c29408ad2ec7600c482597a0d09ab66126bded000000000000000000000000000000001192f286d4603a3ac2478fa1661753d61c240aeab14b8906d8996094d38d4eacaf936958c1a58b7bd6d1c4a5f211f54b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e1fc0d95f058bdb92cd1950932f9da78dc8a703766ff3bd7fad2f8f5930fb0718953f7c884e1e133e5823f4ea50721000000000000000000000000000000000900f97232b802f0e0ad64ba28b4037aff89c9698e2f283ba87abd0f39788f386a44de47a072ac6398eaee2b518381171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008656dfd42487b616c0d6c1833e94c71bc520535deb5c6bfaad8a12b1cb6288243f00b8b5dfeff090e920155618dcb98000000000000000000000000000000000d920aa0b38b2c316a1bae304bd58f88437c0ac0d83ef2e17f229cce76e452646ef89b79204d8d3d3d1d38c7383a5bde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cd18015b13c87b51e87b5f2feb6ac9b263104880f8c2c1dd6664d7ecb822763c1a332fa52dbeb0f4195bb717db1ae700000000000000000000000000000000063899f04ee4f900c1ac3584d13144fb8db23caeb15b88341b0a30ad7a91706bcf993ce098a4f9d2b085ea305f189d381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d28c1edd08dedf740eca2fb8b61bf3e8e6601de10cf2ea3a67ecf6a3af0e63ca7f2ee4809831c2d294ce24baaf25790000000000000000000000000000000013c4c5d5717648810f3c10be05f8ac34bef23292b23aae0bfc11aa12ed1d71fc55f169fd611dc1796e7ef88b2ef328191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aeacf66b2786c63ea50cc28de694b096539c4e13dbee2488f1502740bc88cf17872ac6c7fabb78075e05f0c78e13ab900000000000000000000000000000000020d72f67c9e097a516b896d57134424b4b1366a1b43684e066447fb0ff22c61b92f6dfdc113682d690c103653fcc3e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081aed9143c5a0c0ef52269e1188ac11e610853bd616f3aa7a6f534fb77dee8197b4ba9e1fd64587afaf3b8ad5c860a4000000000000000000000000000000000c55be1a246b598dd66c7924342d660fbf84220ae54c8b96c813dad06a81d509daa590a525cde77c456a99c4a62e0fbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017aa3ef7d5fca8ce684b25f448cb57518a3ea69f7bdceb25101d80977f4ca259a7c340b2454f91c38f5a656bd16f21ce0000000000000000000000000000000002b4d4295ae6a1c977fc89df2a8ad4394a0787c361f4f043ae74881766e01e2c4e60306ab0cd19762353517184bba9061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c6347539caba6812f660f7d5c2bf94cbc933f109a78c87d9652733f4038f9f7c12b5ed7abb6c8dcea7762f95c88fd1000000000000000000000000000000000b24dc3e8788231a33fb3a301c4b949ab0058c3fd318911c5c905813561f6ec0df7b24c646dfc3db258c5c1de854027a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009592a70f5adfa7f9d201fd900d82d3c149f7f4f1271bcc8e365c01e956d7c15197f18a5af4ce2167487741791a65ee200000000000000000000000000000000024e2e045d7103555f75efc12969ea12bbd4196b1bfde2395b945d31fbd6a058fb247874291642bf63cd6b7c8910ac6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f475d96a080180909efe6b50a8182027a14870719af86364ccd0c177de5c9a4538b4f348b21ba0661d18a3d9380591000000000000000000000000000000000700ee3f78150fb3b6caaa34397f06733c34991a224ea661ffa131adbeae8e68341900164aa0e3f4e23692b2312437471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d5bdac2e8bc91a39ee1eb4070c8b9b8a421fec28fcfb5052d586e0e3f7da9c4d18ed56bf1524a4c95ccd0df1d46fb100000000000000000000000000000000187f6b2bde9ffe06b71581b5a9219c5adb2e6f68002aa904c0ddfcf4e0bb01b76b2d256190a02bcd672c6a789cee77d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001912cd2aba1a125004291ae2fb334688001d98986bc8c13cf8a425914a96c30f3dfdeed8284d717d54014a017742188300000000000000000000000000000000183069181922f57f55401cfeb5fdbab9c66c8dd9748a90a995275638012f337d2758edb8d404fccd6b7b25d59e9468d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001182e8bbc392645d1f928bb8c27b41afeff62d50455a792ccb403390155ee8500aa97551618a44c7c7799b59be5ddbcf000000000000000000000000000000000d25607f2671c2d67d54ca544f53b24d788cf9b8baf2ade998f3c0da3220a864dbbb8909144764a3a00615c39606e2851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a29d13152b753bff6d91e071c8aee015e1d4fbd2ecc213734355511dddb5bc2b1a2cc39216e574a26ffb69fd8df1f54000000000000000000000000000000000558f91ab90ec9d4b2223daa6922953634099afa363bab7ecb4fcf0d428a0aea1e7698b57657ee221f59c5a0f1a67a5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001194e54f98f875e0f6e3a1471ee6792f82fe0ff719b20d6336eaa56a985b58bb2fd8cd4447a1ef225485a05638c86d170000000000000000000000000000000008f1ef8883a8a5d8afe796d862352136ff1f39ef61e5e51886b1a0ea415d78741fec47ef86643f34a05e907e1d1605431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8e90e5bbc31449fe33804d951e8e8594f31254f19e03b2ddae779cdd0141d6f1e6b1802a5165a260e876ba015039a6000000000000000000000000000000000fbe697a7eb4a06b66c7bcb5cc7ae5990988ab41423008b52782921848e803c86314abf2c5fb154006aac8bbdd42f58a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001231a789e88ceb1842806681e510d8cef71c3ed6e21f7c57405c5b6e3988fce6d8e505c5efda9085db9f31dcd65b388400000000000000000000000000000000013de640a40bb049373f95a74b87e2719b5e729a929e367d945a3ebffb45a5200bc4781fa1b10b9230bdc174e74b38081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000835392f9fa067f5c021af0e2b295540018c0cd35ca3a54f540fe0eb0447aa5028066f10f417e909fdac34a76bdb2fb300000000000000000000000000000000100fffc2e520489323092a81dec2efe3fd855333b89c0e6c078274a9900b3925975b1ed17537fee170fb42b8bac092ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019180eea264e00a5441a2867b7f8c9733bcc573fc484b717039048da8f5cd58a79e90fd68686eb41a662aa522c50690500000000000000000000000000000000083fddcee295291ac17c485ac67b1d5a806c3000f4d8a6bdf9c43c1975662427e7e6522888c8000d7448528d472dba261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001813fc185f88462b7df9219e36eec45e97fe25a3bdddcb2a46f63ff1c02cc02975f39328770fe5de003e4fad71f84f4f000000000000000000000000000000001997b61eb0476f4814496a413b6b79e27651bf050a9d250c1fef7d5ab6316d29e60c6683a9eab4f21626c1977be1ea4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006de1d4e040ed66be9d988affb8f214525d51e7e742a60418915c0964964284df2d80e51b9a465b687735baa6ae7f756000000000000000000000000000000000d42ec5817831aaaf04a30edbbf71dacac2d92fd42e5c1d30fe44b0a1baec632bcdb94ce656eb8ec593ef664e82cb6f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e0e30c443c6213c5910d2ae5711db8ba0afcfb82b26fa5572cbd2479488af2be6808689c696e67fc6f3d4813f6083e00000000000000000000000000000000017ec011161492b402350362af79f20590ee156b400e49356618fa8f5d966d2cb4edea0e9fc0a165c0f242bac86512541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d92d2bc19cf3fa68b8a37ee1ca4a7abc1f4875b9f7d543f345fe3e669c21afc885d18954f50bb516039fa3a62db070f000000000000000000000000000000000b043043f55f48fb977b999418d353f48c578ac855cda969ef85aa3b3788dab84c68599d5ba1ccc1f1f2ef539e71a7ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eff1d79133d08684f1b9df108969e01af7c4206d05a4a60f63196fd18f62500dadf194a45732b84f1948cc505123306000000000000000000000000000000000c3df07e231aedc3ecbcf94c7678ea7e1d20d9a32bc4278b0f98feb863396115bff3708b29e482de889183777915204c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056902aaee517efb3b9b432ca72b9afa5f1b735171f29faf052aafc5f16fc1191caa0ab487f540ce54418a549eaeb45e0000000000000000000000000000000012ade4686e4cd9a176f0a659b1a76da7a06e06fe2f1f58e1d1713063051dc3db81710077a322a0141238177e0a826fd91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000962e05107935a415c7de6aa361cccd12beede3cf2c28f4f443b65fb06330d7d8665deeed5617623508565d55b4fd83d000000000000000000000000000000000bd69c524cc5dca834feb945417cfe0b37fc7a769a6597ef9f7c8fee4b8c23c04865dff2cfe99b33f54117fc18ffb5e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000586e3f1060a2970f6218faa8eca725cd2f47b35a9c65019be530a12d785d3dd7017ede774aed700471130f07bb593160000000000000000000000000000000013f63245348078b5e9c2522e8f06e54194a0588e9d0e532f75a362e5c1aecc6e0f925938917741539be9729c8d3415a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125ebfd019f418710a871c74fc0aef0ef732ea4f4f597682b1c5b0c2bb2a1d018c05d3722f5bc78df04a8ee20616e870000000000000000000000000000000000cee157262d216cfc91946526471ddba396e755eefe5c3d4917dd88cb5c304410080253bd0321382ce306b756674e9001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ed62af3ab11d5219643e84c366d47bf0108cfe09d6474cc4fbbbbaa7ba091568429127a1b0a36d9f98c191fe3feb9e000000000000000000000000000000001041eda4a42df7a2dfd7c7460d4fb4ae6ed0fe9a39fcf9a72e03e5469c070ce316197dab24339de0918e3d89bfefc17a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ede3b2d8a3d09b53e446c6bdfad3f431bb58f9b19ef7ba73d83327d36345a9a41f396692406656d90450e2218f60680000000000000000000000000000000016f06ba41d8b8632d36dffb6fb88a98ad03a0c6c12f7886b9f01aea3d2f424124e0ea6af9839a54532e737ddda0ac2f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8f55086dec464b616ab7aa8491d694562e9fb77b469c0e63e057569407e0751f25eb5aad8139c4f69e95e12319d95c0000000000000000000000000000000011fbe80430e5aecd7df7c3569480429216fa07a256ae80d2a5713f47299b19954c139220ed2f86e28dbd6b4fbe3a35351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc4f00e6bacf98f6f9237f351b99ea307fe9adc23b85021f0ae4a31f2a726f1e6a7f9478d616a34027d66f9dda3233c0000000000000000000000000000000009fd5edca2af19b8e3dd0404922d65986af2ca2c2b9976110d7f520582de9703d5ffd7a3beab648f44a166b7c68b0c7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e590ae68e16697edc724f4a2215940450d222cb65046541c7f6d83da33551f13f3db68e9e5eb1fee53068f4fbbb979b0000000000000000000000000000000010e91c9a13fd31f950ba72f98883e3bcc09538678a4fbea63034d525b117560cff911c118219eff6b7767ac001a493ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045275e2a1472b054ac828bf779f331cff064d2e7860bffcef9bd6f07442b44bfd5073a8aea4c87b1cb532c4a644fdc7000000000000000000000000000000000bea98f747139a694722ef5845eb5b1283404ae3885ebcb2d4b502abc12592dfd5ec709c2c1eca054b6996f9f1832b0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001022fd83728aee92ef9e6617083ff851494db7f6685db97fd497180e70fda9475fec7cf25692cc7f4c2efa9e6fcf8a6000000000000000000000000000000000dec85bc6e0c0cd8194aaf49eb994884bf8228d72920ae9dc9dabe61ba1dd743f6447dfeed5ecebeb7ee6a301d6f091d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001560830a49bc8664152ecdb5bc3fc62ad7b80b210e7043bfb59895cc106fbc76e3d99a24983e650e47a8ae43d43f4b290000000000000000000000000000000007fa83a37be767def70dbd7a65d01d1052222f192e14716d0c41533379568a66fbf003947e1fafe83d035d18d5ce6c991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001339d6ae0f32fe11504fd99b4297db2c51938674c9f58c3f569683f17b771df711735a9882e53d8a5b3a6a7ef0dbfee800000000000000000000000000000000071967edb11258d2852cd79c7e2f231b56e3748d42b9145f3f94cf909cf07e638946a851d0e5b9ae57b64133783562ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003805b77492c9e1a2ca329e4168b3036ce1130f58dd2afb94a6cc0aee114bcfd545f587a4241f9563e6e834a3d7d7490000000000000000000000000000000000df3d393b221d99eab98d605c184d653b993841a6f5461c55ad5619984fb21401528362abb343e9fc45a8152aad569381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ff1365558ac7b62ea3cf8959cee9855ae6e9737c495e97a91983cba11f3de74942e56587fd0db41fe9aab3eb05976a000000000000000000000000000000000b10da32d114e554d57692c81a79c7f1aca9d22b33cea6a4f7815a947b5fbe6ff21a14bc5f22bb47b5b138c89237940e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea59c0a602e25f1f9bb3d16ec0f663a232b22580d12726386af51a14e98bbc1d8b5f03584c255d5fa6a74b631ba1a5b000000000000000000000000000000000bf3b55a38e08b43d65d4eaaded4cc56a84ce12101397d35f0f8b22673044af068cb0f88f6a2f4398c02763fee8522231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011dbcac6b6c59dd59a7f9d6c96c9390f7d02b2cdf70b1c94bc376ab255d233c7afb5c4467f413b4890d26811f021576300000000000000000000000000000000104f1e502be45816c22766bae3eca432e84de5a6c0b61353c35ed3969b32f65facaf0b084704bf3030a2e2a458e0f8481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008323909660026ad9abc22dc64ba9ad4b7a33c9cacd214a61244402d0971290dc39785edf65c4288a7b71dd37cd764ce0000000000000000000000000000000002ffb8edeced6150a221cdd9e9a6023715c95f947b77559415fe8231603cb19bc1266ba201c6ce465017082efdc5d0941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001dd87b77ac04777e28951c6c81a1eca78a0269e685c7e8b4712c7b2ae819a875261ce59634b567f2370bced488b68190000000000000000000000000000000016583652580d0a3d5066c0ca089ae38669028d778cbb1f53e9c2df2144a10afde8cfcd56b9fe8ee3e943d39a023a97f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a916ee4c064aed3758767e103a0631f89031360ed8d1104eeb6b90dcef90f8b98a2460bf6b219898bc0c57012370d50000000000000000000000000000000018d1e73641e2952354334a3f9d252bf836612c86382ddc190efe837b5cb6ca0082046b24d4eb51a2bc53d4e6f2f578211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c7d04cedab74880e7343b136e84c0f7fd6c12e694d3007a40788d37be17443bdcd49991b3c37ffc0b1c8d1de6ab0470000000000000000000000000000000005c413e4f50bbb1124e56a2cc6ea8bf994b908835e5981fe4c3038c64c1aa62017915a74da9d1d97ee9731409a8f268d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001996d6ef064a9491fcf9f273db107846bd24c11ae20698b39e9db3b58560a0034d22f4bf745f6102a92943bda3767f400000000000000000000000000000000005bf07bdffbc17ece59dc60d3244ade2ce398fe6b1c825b3b9704bc7b2c90f4df6b36b73cf7959e6727dd118597690ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001182ff7f7b75aa47bc8da06ab32ddc64de3142181c0fa58c1beb554c31fd02da591e0ccdc4e539251eb56530a97b3df00000000000000000000000000000000129a39690e1849d55e8e02e50e23272e706c9e33abd8f587dc8b1c66c491df5ddfcde27e0965ae7aea252f8ca27415a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b4c447f4a5d5492f2c9ccbff8282f9c08a0bfdf8cd3c5188b64575b3131cfc5fbd538caca991179cf9f3e78084482a000000000000000000000000000000000f54742b7c7a370e3ef7aa5d08b7ce8445b0bc371333b195f9535e5797a5c2a8bd840bcb4d22269bfec52927fa0c648e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016440aa723e28ff71b637786f55c222a7bf700f9a22b064b839054595c87f00086d6682c66a42f654fe977bb600df059000000000000000000000000000000001296a11fa47488cefb9f2523e260d3fd8833a09e4f33cdea0f36c81cae66b7fc1b7c1a30ada81140bcb496fd2cb6c7f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001990c56373cbbc99ae158217134722624434c5eeb12c78200b5dbccc84e49bc19aa92193295bbd944a003696a8e70bfe0000000000000000000000000000000001fe51e9e6999c101efdab04fc3c21aabe8411e827da3fce0de86392aab427be97210b412511af0f43d94954513d5d581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c0a53de7a35d8301d2c4934bb5becd473e3a52464fa08070fde9b9f7e0f2980db82f0aefdc280da9e16407e6aff82e0000000000000000000000000000000002f5c5a8f919e0aa524865d98c3f3161a846eadc897df925f737b9959dd03af27d7c9b62f481788f384b61466b9872231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2514dad591944de343dd3d092aecca56a4c73327494bee75c3b491ca8e0ff3789ab29e6c64c7e44de34e39991eca4600000000000000000000000000000000144666355234aa895e8966c8da8e9d6cc2db3c4cd7a61b4090243162f035b459b52a9007236e17bdceec502a5588fdd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180b0e5249dd8c3dabce1722229ae81edd8127083cd973aefcac450242714ad7db5a8a8259211ca7a0bf8fbff159b79c000000000000000000000000000000000da31243e1e87dbdb1126a63a181490d8a1d764ab0dc184b0c3f14d3341363ff0d0f5f712737aa08e60058fb0847ce4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f72d14a55b63fe9194cba08280bbc96885e7ad8008e4678fd2c1d90318d47a5e105a181f72fd190637daa109bcceb3000000000000000000000000000000000cdc56eb293932f737bd82c159e930883136d3557a116e7d2d33b14a32abd7a987d410be3bbd1d4de4d9efab5ead634a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120c8bda1a6b74c5a43d57d2bcdfab37a5c625d3713532e1895bfc5dc57ca977bbf419da62a5eb88b0603b2dd23348530000000000000000000000000000000008692842047ddab481c7badc87ab2846d75b3fe5fade05f37cf4b049f52b895a3c49cf6410ec9dd7bc627aa2121730c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003523bf22b4836dd845325855628e8022ce5833c57fe0e05361a8bbdf9dcb2a47d5a5bdb4201a01b7d9cdec23d2c08a100000000000000000000000000000000066c3c4fac131c9c6669c7f165b279a45c999124cb84830e5999ee3e67fb9fa54dc72a12c5c35782caa7b6f9f5a649621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4cbf35b5a2fab72a3281c6983072154dd81207f87a2fd428b85b56fc50724d52938a6b1206aec3f30d2af786709d9a0000000000000000000000000000000009c7ac106b64477e81e46dbe4bb780f5eb385e2f8916ce221bea0c7e020d7e72f078525ec19c81faace9ec323a70ba391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057744664ef45a90c2da37a6acd3c46225c2f835ea5caa2b54802cd8f7a31a15540b369fafeedd40a81c2646f6d2b7b30000000000000000000000000000000004884dd879ec6f9a1a28606047699b79d89133b4d55e5bfaa3ce98f8f3f1cec9998eed47f7be34ca490eb77bf8955d261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021ed0fd8a30092058b31f545244daffa266fbb0f5f19a58c3fee5f7b707873b8627dd539034f9f721a7b04ef3f92da0000000000000000000000000000000000c55167d77b14c5112002af9adf1be7479e50fc942ebe224d80e4fa1fb1afae468ad92a535483261e1a9d3991f359f7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff3629c4273ca1226dbfbacb92c8caddb7be13bb8ff529959e75fc97ba710dc9e87a1ca5508a01fd9b3c65488c2048c000000000000000000000000000000000668650db07ef079d46f96f2f544157dee60322216de4c53a9d786660bf59a363378027e669a31f6610795394df64e851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142d3a8466096b93eb20408b22f2f739eb1b714d42ebcb82839ab20f680316bf11d0b717d6d521000a6f009579aaa4710000000000000000000000000000000012830f60bba15ee65a504dcdf22e3d4eb2413930c89812921509eb1c199a47deb3923c5a9de6c8b2fffcdf6d393740681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f57245779d45d25a4ae8e3d36aaceadc5897523e60046c802a2f4c5d931164e60002e70ede46da7a74891a182b8840000000000000000000000000000000000003c936cf96a9f07cd2f4813ef50deb178d6241022ab7da87f72916e3248c9671a5f33b92ad89552ee8f310076721d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af00eb49059f6f811e8d8b340ae959fb2239aed5f66b40520f7a1c60953ee4ede29ba1342fe2e4d09f3cd13dbe2f245000000000000000000000000000000001868cb18ca0fda70396f99124ba228f8ec1f362702557f450e611593f926568bbffb2b92336c1addf93b57c07db91a3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d182918a468f9f11c8d8b8f7b2a5ca48bc9266c39493a717ce93af6a4acd390b53f50e927589cccca8f1821f8a53bb60000000000000000000000000000000016a9cec4e4986091ce3172179ebe61ef902b06886f47e1c2805fb462e994736db1d397db2f02376ad3885bb599b104731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e6910803a2b88c03d36d778274cdad9134899edb6d5a3809c2b93603a748d53be4dacd2f01864a82f97b79c8bca8cb00000000000000000000000000000000031ad6a51a6b1daedaa234778aa78aa1ddd5c5044366c4aeada760ef6441912cc863c178999a497a9b6298679f0551eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014820481162d49a13d95e930ce35471f813ba283649d2e486658667831d013ad5929d2b9be872278815dd79cdf63ef490000000000000000000000000000000015f7b2bb2bd086ffa3c6db139c5e54dc5f8380de1181ceaa21b2b5546ec9821887436d2c788cce696ab731a5b55add941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e15694db72b174e9db75e511aaf8974b998519bc1612c9b2f42de7c70e832e84c6e91e315b25786f4e4be62b1bc73c50000000000000000000000000000000006aaa677139fbc25f57c6f071bd47db739689f59fd7321692571da5fb3512482cf543b7c29a383569ff2f11e78b02cde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119449183391aba016def0769281f8c5183042d797ad7be09146f6b19de09c46058f72c8c366eb2e3b55f49e4510e31800000000000000000000000000000000044e2fdb29aebbd197e14d0d6bc7f50385ee6bc7f8c0c491b96acdb2b450703e25942ade2fbbcebc766212f145fca9d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010991b7c9f097f734271879ae2d792f9255be74022b883149e36e2b26a8f3a901986c4789e7ea8b2d306715e04cf4693000000000000000000000000000000000605569989f9b2107163c1298801bdf619065b4cca224ea7e054c8db2082a61b45941a6fa0685dc9686b8ed6cb8bad0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054c8061a1e024f45d4088ab6f3db03b5f7e33f80e85983f98639548ac3d3ba315ae4fa51d357304b0df613b142182d100000000000000000000000000000000154963f12c9fa4b4d441b4a5a2a78fd2e48a745c863208dbd9df961f103aa8785e8b75a7b7609a91c2b1fb763bd223a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2426eb525958e5d651f72ae7d62c10ab67beff7bdcb0d05703c8a1e6591deb16dec21673cec2a5f08d3727aac8086c00000000000000000000000000000000083380a8ea30089bfba7f40c8530a12d1d088ada72d3ffa3dc17cd82ae6d8b533bd3a396b1a21410a4c2b922d3c52eee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df4e208a645db5e63bbb2f4693b4de328c12770476200aa3c64cc9989dd00690bf915fdfc9e4dcd73167f7a54a95f6b0000000000000000000000000000000004513d54e2ce1a27ffc0242e48db1fed817d9f8fcdf6be0f1b9ba8fd873f6f0709014ab244070b501a93589a6710d1d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001dc9fa3eb9406ab8067a2426ae1a11b6b2508c14607cda503be45eb6b7fe5ad53b105ad6660687e8bee81e948a57dba0000000000000000000000000000000002fa2289b6784c1a285eaae9fa9a096b140b7003790e3e0fa9178fe2f7a80c7fa0e12e51bea2c7f892d346d8f2c010311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191acd79e783f796ad03f65952227baf1b8dc8eb8fadce09008953b2c48ef8bfc16504c1839ba354450d0d217d5e86480000000000000000000000000000000015fc5b9db2ae4e614e6c64ce64fdd585126fc14357fd0bf9f7303ec1a2c137914554f520a51907a502e0783fd6f2f23c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148233cbc88d035b2d85a24dfa9a2b3aacbcf0e296234be6912a7b8656b7595410e96479f1eb4dffd6e4ea5ffd81aa760000000000000000000000000000000006f227844dd6fe6633457da716e747d8fe0dddb0e37d6659691f145b6e7964c41766c502f50982ca3709987a1f5777d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011b86933f94918d5db737efbccb31600c1e979d0c4074c489a6734407407bd4716f0dc79683a1396c81583b2369795aa0000000000000000000000000000000001734f6bf71dd27c41bf909352874658431b71c1e8b477210f1ab32bd4d02e5945909ba3071be6d5c8f6036c5dcf539f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001486ebeccd21eddf6401f5b8f1a4e2613a2b50aa407928cfe76b398f2a060e99d06b2915bd13cabe385493feafcfc191000000000000000000000000000000000df9b94f3e5e3e8b81b32621b4c8feeb1fc199f435237ec2e4b7b2031e3f9efcbe29ecb4ec5ce2dcd96b9326038f70e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098db46a3240d87bdaa8e7c0f04a1479ec6e2781a4bc3b77b19965ad5adcfcd05e6e308ee598cfd11dd46857235efb9200000000000000000000000000000000154d33cb52a8fedfb3dedeb04c036367350f4bde8a444b8acdfb2c1fea527487d40464da50ed6b9b1faa6fcb212aee491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010cf952b1761728f9ecf0e71362a8f224d61436c94706377c26c3a702417257d6fa480475a8e30b028baeba728349f03000000000000000000000000000000000333981a3e4121615958623eaf5625d719a07f75bda7242817536977a421750fab513e26b28d416ea16965623cb8ff1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000840ca623954154217c285ccc666033a1b27f34c3a0fead1deb037af2d1a3507d970ea43a04c4e11069717a1691657ae000000000000000000000000000000000e6248ddabf3c3cfe2a787cf898794c4d3106ee504fa91df76f59bf0ebce4b1956e8398a702498aa22868d51e96e39ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f90dffd6fb19d7c9ef0bd14f5bca6df70a0731c9f941d00ad0bd27d15a1708014c3679a8233c5b4354af1398ea478f9000000000000000000000000000000000cd98d818f57650d9c65f1f8484f2d4c8fbb79fd6ed33947b2161dd88f4a3db81f0a3e17f3bd6a0f852e881399897a1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ebc1638975768a49a0845cd9a7dc4a23642f0796edb200438e9bef6b46059d9fb9581b8ec3597fbf54eb41453cacc2000000000000000000000000000000000d43bfe311c0d6d77208304ed89dd0ca230551fc4ad1f2b71ec8668ac3968e034b2fe68b78d78ee1732860f30c56808c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112e89ba33333114567e974901dd3579c39a7b6940ad1fe1911637296bea356df9582fd86578283e3fa7991e75de0f5e0000000000000000000000000000000000119bab0d071b6a133d121a425aa675c4793a2f073a9d015b50102acc9d295a85b7ed88fd0825e800106af2cd2bca661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a8ef6e7f83ffb640872168eae078e12ddada9f0180754243f880adb340a6f0bedf56fc03246dd6e6346198bfc7d778000000000000000000000000000000000700b9d7a46528bb36029d6074aaff74a09c471cf14efcb5df4b228b2e72bd5192a7d192c83c537fa065b8ddb5f7cb461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bcef72389294ca7f3236c24278f3684630338882ca0ba24840ab6c15772e3d103f797508b726f9283a00149c3aa532300000000000000000000000000000000053590dc949e5feb3645b9d93547dade2b4402bbe225303e6ecbef225c6dfc2274f286249b5b44b3021e550e42113d741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020e9d9a09df7cdd15efc86655dbc4424a5051614e717431320329225b70a8fbfcfd4e421d2dcd4aafc55278c14db611000000000000000000000000000000001605644f41380d8ad746490717893e93f008bbc1e58fc31d2021675656d0b7e27e120de55788eae6003d277286bc90c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ade08845a57faed440537f34b6053f8123eacbef95c73752d9f8c1e20c40ebf390d893c71a903f03befbe3e7d770d710000000000000000000000000000000004340ee2170c0b14a0bec5a2974b5b4339a5e9761fd452f00e04f55c0dc6751ae70620115aeaae9b563b2538533f1f8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013766d1cd7d16b169e86dbc089a5763716be6055718cf76d692b5fd413a9c7d99d930465a3fa77979de55c92cd83435500000000000000000000000000000000113710afde43c6f2bcfc7833678dd673e1339cd015bb21643fbc45c3befa56b8d3b8ac4cc3298d2a82b23f1e8fc48a101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024bf65ea632d69db0a2b583ea35ff94df4fbe94b1ae8f69ca5eccb981db64844c3b492f707e1ee4d0b965b9cceb27340000000000000000000000000000000000e66119af9e9480c94a3c95b33149b71d5dc5f32bc6bae9db6b18d589e524deb5ac0726528fba6dc03d04cedabcf8c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037e0c69dfa9afb5b4b5c2d18042d8272d64d4b4d5f122b63dbfcca69b5d7e39517c6fdc2e05d479616dad76f23743e60000000000000000000000000000000004a06847f116d21a179788dbe9048aefd7c560cb10bd46cde111bc96a4ad5547827b3da85e24bae2220cd38b8ff90cbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018778f6fc719f726dc847e3d8ac2b9898fd2a9c71d964c1bbfc23f3adbf59cb57db4ab94421c7959d525661c4f9fc6780000000000000000000000000000000010ffd434170e556e708de926bd4433653b8801b90914ce33d0c85d75cdb9d9bf453b38964612a472231f4fa6866dc9191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018150e7231d9da2339716e770e38ea422340c1defd4f45ff39720193758256d366d46d97c9dbcf5923247990baef4d40000000000000000000000000000000013f384f80e62aea06946d12d4c0ce7d41e79576ad2b92904c79d379bd4d896477cc0851d7411b8b7d8054b214b48059f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a745f94954c7d992d5537e086a4a8ed7b1791851b7c2b73ce9b27753c7484a8fb157501320d2526742c44790aada5bb0000000000000000000000000000000009864abb1d2b1a6da9da3108dcf6be8e342988a56deb1aa744187c23c8442711d695b7d7c8b5e7fce25cbd5df8c223f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f705312d68ce0998ab63df7cdd98ad60cef9d081886e323ee179b6aebcd3bc4ddb0189eae8295ba3b8aa6e45c9746100000000000000000000000000000000088927a267c3dc7a26be02f6086015ebbb7df74d8c262fb9e2c6c7107b10ae3ed0f3c252267dac312159ed34647c8a7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c93720b64e970f3672d13ca5136e089fd6ba66d8131545222f835e3814e3cf11fe103d6c55b1b9aa810323ccd65c6e000000000000000000000000000000000122bca3516253f35e919145e7b24ef7541aa7ab8c581f77aff81d77e410122392937343d2817ab16754135ecb3aaa001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b914b4f2a92ddb540bebd7753103d806602ef55938c96fa4fad0a83cad6091181be2c0fee561e9a2cd4d475ab6e725000000000000000000000000000000000695fe5b0cef4bebaef02847502ec620e4b64eaeec509faeb464f57d1092e1774a5ea4fd6b1eab1f61bd014b7e47b8d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048a5090a7fdd5354a3b2b8b87c7f1bbd4c9d4a196b92db76c951de103fbd5ee36fc46d232ff804f2568db4dace1a7c3000000000000000000000000000000000234bbcfae4f7618d506ec54200b24c21ad078b73db7589304841bc43e5a556cc7739b5009d2d8b13ba26e7ddf180d481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190f8da249d05588e675e83e75a9c5b5b12860cfd61b9a09b0158033e26664c1728b0f807808121f5e9e30a50b5ca5460000000000000000000000000000000013056b3dcb76ad2c18913b82df3f64c81710856b9e865f69cde8c2bfe8dacac22a4d0847d79a33c0ec44cbe27b6f7ae01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a97e79f9e5a3279bc83d24bc246536bb4d8a76f1bc1d9080da4cb3105fc2d86efd505b8d3ff2305d7f9876edb2661e1000000000000000000000000000000000be5791d4d8f30dd9b3d6cf8fb3ecc7ea3918bf2ec08d05e4abe4ab04955b9320fc75e3c4ee5ce51abc3eaaaa7a5237b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005a13dd950b7bf1d07c4a56a8f77a0c11c8809cbe1ddb6167d429bfaaf38948e056def9842459d604bbfde48a41b243000000000000000000000000000000000a590c1990cd8652b5db89dd7b36dd4e15d2e0a310beecba92166d4162a2f0338207e801fbaf10eadbe1f21ef5eaf28a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d0fb4f341574f0e177f84a7cf08d1076811536252bd2c2cd589c581c256c7128da35b6faa71b6a168a7f2aed20ddda000000000000000000000000000000000706f968838c569c50d2806d6222992f80161631434d122e1e64430effde2b0639ae6a38b98de09b37171f82117d992e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a33189bb49f4e00bc2bf1f37025acbf63b1d9a267189014783a2e86278904e6e073738ecae36972354dfb2faafb4635000000000000000000000000000000001647d5d26dbee9e82a3ae49bc50f582ceb64fa8ea6f2ef4f8e1c5807a389249e975436e50bda9b14ea38bb896a4ee63c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037fde4659f3ad3a819c4a3d0d84ee44d8dadda75a85a55df0086aa443d9ce36b0d59faee8706980b58bc27218987dd000000000000000000000000000000000191233d0e2eb06b94db74db20d69f74e46106c5f2e0c8b8502bb9d19fd41e78c08f062d1c3943796e7e12906389df3261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f7793014f120a78cc129369c8d046346170dad8256d67c0bfe567d61d5e8be2e8e16951e2c82b30ccb105f9c5c1510000000000000000000000000000000000c76446134c04cb24534a6c25704f249bfd0943ae31794e16ecf4af3c073d0187061549c6c8ba7cce109ec2b841602ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ef47a315b8d7b1a374336bf74712653bdd80bc9b4b0d5ce72ce82a535cc4f8b71e9267247426b9ef388cd8384c97f1000000000000000000000000000000000a6a6e3731bf19700d4c53f5d2f7bad7f5686177cf8a171d63329dfb4d61c4335ba44aecca54a11a25b6aad966e93c8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063666d7286006fdf948944493da4b9995ab783a513d4402e609c34fc74dc4ddb7b6bdf20ae075cc170d87d779d86998000000000000000000000000000000001572996ed032223affc2953afa3b0f03a32c1e54400497bb2f8f4c7d49bb8ec85602e4349be1c0682104420286b207841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001792280ef2c32b7be58ff701c3ca77164cd230dead833ac3540305bfa093b08f8eb22d3948edfcb4d95fc00914ff2312000000000000000000000000000000000876658c8aadb4cc7b866dcf8377899f2709834adb1c036d5611d45048c48729795431d5decf5918c2349c94d63d1c111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004bf6dcc0965bd45c35a8580e3c3beb9e93aecbce2c3776b55a3ecb48ca1b56082c87538a1859ac795635cdb4477f244000000000000000000000000000000000e7f564dab4cfe7ead2fcbe8485465ad0ee0a2ebe544afea0a10fe36f616f43febbbf5fc2ac0099c5337bc039fef82f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007382994146d698985317128bd59138f89b596c51a08350bdd025bc5d8ade4adf74000dcbae2ded5660d739373e81b600000000000000000000000000000000026f1b55c2ad1fa0a26f507d9d3fc7d5f6909b53c8599cb16ae16ec63a9ae74e293687673f782aa7c8e6f5257a00849d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3d2daf889e4fe66c7079b3b2e3304a628dce132d01370de654b9119cc7755545b9f991946fe7b5ea6188683e2625a80000000000000000000000000000000017f43f939aeb777418892fe61f2945f7878fb92cc694838d6bdc183ffb8a50d6b54d53abfb1bf7ce793276d08229eb921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000255951c3f935f7b3ff36b596308f30a0236a37200026b7553c540c0d3e188f037af8f1b3a4ad6707ec7a8f9a11a82630000000000000000000000000000000014322a8519ad669bccd35f85867cb8e06556174047cc74b21708c9011192d47130434396d4a92860a3769c108bede1f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4f6e3697cfe3138f815f5c5c9a183d171fd20b80d976a2b47780d77512a7efe7b3d3112eccbaabc0ad41fdc0146880000000000000000000000000000000000207443da4a3ba22003f9d046795c0a59fae9985410255e4adb3784ba4c39be67bb6d536d239975adde49f3b476016701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000090b500ddce8d5b6f0afbca4ff335ebb7e87ee14a6293711363d449fdaab9aea4acb15672a829303d8282f3bd1b288000000000000000000000000000000001885ac696ac967b533e81bcdee49622caa9b7a918af0dfb47e9c9d31da81c4738c4a2fd3b9be7113df89198d110737f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f05f942da58d5f645e2c995bf49fbad3b05d682459e182b9a90ab95df5815119df4ae5c8c06c4c364a039e2789bef7000000000000000000000000000000000eade2a2a36d8bfe3112d7890aec737150624bbd79b32c6b932a7d4402af5b89228eada5d8717efaea215714ac3901bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012930b7794c41b2038c045a4b24fa7ed4d518d9517c250802163fb1f3d85e6640a859029e287612b7e2735850ac4d6560000000000000000000000000000000001a99bbdfd991d241c0e2f4394f641bdea725243a5d0077c5a9fe62be31c49494a0840e0b09171d8e20b703322bc9be81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001923986c1bb94ed004bb2708d43a382853cf32c41c904186635019e1b1e0aa794a06203709d6d9d489b07b3e6d2ca6d6000000000000000000000000000000000f5dbbd42a835d0053dc6132dc496f049d9a87e43c8bf906de8d6ec61c939bbd81f2a402dcc9b1bb440c1d57a574cf901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030173ddf3641830d8290288c355e188a03c79fbfa9eecb3ac3b5beaf9c482c6ed21c1089be8cabed679c8a860aa1d7b000000000000000000000000000000001252b7cdef51880f8af24afc6c03be8219fc90d3fd58741c795b58b825a81c41e8fcd341fe2ad3b1f329006c33eecb701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175fadb3b46e2d0da951f1a72c63ca52c2008f3d9b6202ae5d0d2b231019fc4529c39e05df52a29fd2663b11abab2377000000000000000000000000000000000b371979943c306de152ca54342af0166059879c3e6f88a607b80df9b0e7a052b2a9a430506321617e3e8986ea9f35fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008009e0ade21bf039cbd3ba18ef2fc3c131cbe9e67271f9ee654eda01d5b637fc654a3059161e60e526952e16766ea0800000000000000000000000000000000175416490af86eba8c5a2f33cc6ff5d593f7364a2eed074f912cde28f86c247f132d527dd67b1dc9ed5b25bb05759be31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052225c752f25a20a8fd60075f49dec9f9f990517fb04b5aeb9274f1cdb00f03f208fcfdbadad27dc331a6bb23e395560000000000000000000000000000000006c60d92cbef15bc696bebb951356de6080346e50c02a6e837dbe3de9208922d0038f47e3e74efa2c2fbd3faed61f7d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c76a5fde3bb99046440573fdeee5bfb6a673baff56c2654fac726dc445f999f28b1a47d5df2b4ef19aea5a8e9a2ec100000000000000000000000000000000156f1fab5aad9dec20f87489f353a10945a68db1279f83eaaa7758649fd6370387e31a919f91c4d80501707355e4602c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee80ea62ed531f02d04a6f6322d25f653e5d17c8f8c85a33e149502b34bc6b3d89adf65da1fb64ff7b45535503717b4000000000000000000000000000000000db1d694d6f27247d282adce93d48d866ab4d79746b66413560fc39236480c12af5bf2ce5699f00af74b5701a4ba30f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c316ee4222ed6acafab06a9f8e0cf8e46e33cfad309d65dc255c3a4ccde0098cf942589c9760ed279c5787d2ac8b1a000000000000000000000000000000000d493087bf3fedbd0013426e65c34e44ccc5b0eeda236edf4a09ce724259ee41366b57338fa0676e5e810957803b75c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c395b81c20421afa879f256031e23665a417c6478577e7e88ce0756ada7f657ac241eb02b420213b3e08712fda7dad6000000000000000000000000000000001132fc47984aacb637fbce7b26d14d73818ec4682e6d9dd3fa222729d570a8a174d0e2e85b7e548d5ca61ca1d0971b681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a3a1fc6b7954459d0729e9e7f717b2edb6a239e8e8f082ddd486dc516132bf5be743ac0a97c6f546968a359c6a3c59a00000000000000000000000000000000164729bf3edf66bd171a8d777389bf29dc4c743aecd2c1fc65045051d201f412b6330cb87c97d32dbb63a4437ab116121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a446d4773e912957146625a34b4306a2cfa95f542a27de5d46fb3147161c7ca402fbcb70b4c0803aaf4765d686345a0000000000000000000000000000000016af2d460f197b9b60cc546625abe0ccb89839e3d77d57bba7ed6b0d36f69f8b13a9c1b972c52f60397a31ddafa9a0081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001033206e7b8568cdc111c648d483d83950191118810d2bf4f35a9d76cf5a9e0bec7940e36df61431d8f3e39b8a6324b100000000000000000000000000000000120e1473687ff3be83835cba7ed113d371c7485f4223eead64d8af33f79bd195e472f63419713570b9d9b422fbeb98a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037ff0da677dbdeecd3bc694ef87c73c2d139161d7c7242d7380ed6dfc065534c0b3be6c0d1001eda5f52d623b30f4cb0000000000000000000000000000000004e95ff53cdba08ea69082d52e8fca786efe20113e170b0f0eaba0db07b3f60e42ab74c418bfe26b4438fbfb2649ca1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d512ccf1867ea5b42232c2c9c5440eeaceaf8f1f3d6e12ef7942abd9bf6af99b4a0457247f094fe52667b6bfd185e630000000000000000000000000000000001efcf1508c0472cb287beb7291652c0eec439da10c5b4b00108565c03ac4d8b14b797c376649a5c0c5592bb0b7488b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000861bcbe76b814e02be7b2aa836f91cf44221f3a618758b833321f2719b1cfec7e91844aeedfadb744fdf90561cd9cee0000000000000000000000000000000001ab42f0c2885a5f6d79a02a5d4ebf694bf151ec5573ddce9c3b413e30079ffb88cfbc723fb2f769bd5ff5955d4f6e761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122e8a2e760dbe1678195a5d5d94b9337d7a26a6603054d78f568fcc43d7bb9ec8838b9fc42e7282a7da4d2fc79cb4400000000000000000000000000000000002adfc0e53185bc43e54770a4436ea47e1c06df0471552f4828b3133c8d27f0a9f6ae28f27dfea4e99c9a12e17571e111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009268dc939e3b6a4aa60449536175832c97f39d4ea7d056e2fe8c9768199d6d0a1176059197a51ae91fa5053a67cb7e50000000000000000000000000000000015d2d23f629fd79961295f29fee3c09903dfc6637e7ea60629e6c05cf7d7c47a8e717a733a51864d04807dbdf2c034b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001716dfe8ff07ece1487faf1304ca59855527c2e27ac5f226385e000f149faca8f602774e7f20d8542af73911deff71160000000000000000000000000000000016d2fad8c614bc49f89fc8d26318e92552b0c77f7ba8d755a987e78c1e2c2852cb1a2564e649620721d60da1e3ffd76c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa5a7ca5c1b22ae109f232c91413343c878a8258f9ea51daf4488875bc7225fc2351abbf0b0ffaf9cc44430b5ae4fce0000000000000000000000000000000016934ede20892c4ff736e319a48df847dae3deba172e51a84229b14b8651e71c7ef8370cb00559de4665d69d50c53c351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000527ac8f6492d188a8fbc196287cbf7f49cab49840a35a4f9bc3acec7902b402243d746c05a01cc8f02f3d0f7f4902720000000000000000000000000000000016550e5c0365f9c7e1401f6b80168a02f32b843f9c4e080f53d4e665429125678c540351d44ec0ef5e556da878d121a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005cc1d1cddae637453fb11c9a9cc6ab0febb11b0506eb3b6725afd97fed22ba14e6f6796a370f7d1aa5b1d51c5dbdf01000000000000000000000000000000000918f8bfba790d573892369f2770842a307c4018ea53039cbec616c106eb2bb182bde25f2feaa3edd870d61485b39c8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114ab8c0552e1df94ef0a18f67d69c502c7fe773e2bf430e7c3deb3510916bef24910b2ae3d4be8708731861f9cef0c600000000000000000000000000000000137f8539645a6897d5efa34cc6e27f9d6f91a9406b2097f029af20dc2c8a36330c7348abe7c6dca5227ba40e0423b66a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001627f518ec0d2db3e97a1d593199e3c7e328f9960f4bc9522c6351b644ce337e91d62e924e3e1da6c8b25350dfa1ec1a0000000000000000000000000000000005ff49a77c895e0f4e4c249e39020a6033cdbdee00e2e3cfdd7fb260085bee5534e5f5dfca44de90d5520c1538b2ae581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da044c3be9e47f479788432d8113a38808ad6b18504206439573ce02703ecc53b0c5558db38d255c40f1414b393f7d1000000000000000000000000000000000e79a39f8db1a9394fa4844aa6b4ca15a9bdd0470856919b94a32a4fffdb3b3313baa12d5161b2829a9804a1719ed3c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9b542c2898aa6084ae3d08b21ae0de6d195b117d2e62162b06780d3d418aed9bae2d3743e4784d4142e03a748b791600000000000000000000000000000000175500c0dbbbee64aaa03c8defdd78f5787939467247d6f0a9021bfe8152afa8227213fdd5886f4eda4d2f2315ac3b161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007383504231e05600c5905635d74a3543e146deb8f39e38c4540c13ea98588a5ed83589f6b705732519c4e7329b599a200000000000000000000000000000000067b481db48deeb9e1a1481cf671ea351fbf461b56476efc71121591471c1600815bfb1b68f6346108d1a0118d73e6f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001608610f70541e945bc94605180769e51020ac8728ed00401246bcb2d59e3ac7d8cb5cccb8138817095ba199380bc3e20000000000000000000000000000000014cda2e886238a8efcdd86f13dd62f6f53a2bb6022b7053da21aa41c7aea656297521394c37b3350b08d042aa74b25521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006723ef861f615c3bdec859e8b1d4b2d1685f7ddb9dc34dcc0c9f71c98b0597fcb086d7c320d329bde59a640e839b204000000000000000000000000000000000d806c4c4848dd50297e57c13cb0cbac3aae0dea76f8966c332203383ae0b8fd07587f9d3ba33adf2650decbd06743c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d300e4dc39fc1c6ac750de943def8f9e6a203fee72de5c562ddf5ecbf91a627af58e18780df265a61a7de240e628cc800000000000000000000000000000000182bd0cf1d22103ef2111539a37b12596fe4f022bf70ac705a14c9cae1b88f817ed881b5bef6a41d90628a04724653a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006959c55e13d0954fa8f3acbbcd779e1b3e31d020f6f4833e8e07493b7819a97ab7bf4a26fea8220fb2e85d3b32e7e1e000000000000000000000000000000000b224266b8d32f8fb68e722ea79268ea81511f7aeb0c1dca82076e1967569c04953507e800b0375216f3d62862aa877d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011cea485569b753a820c4dc57860f460204f9bdfe704ab1f773162d6558b403835755657037349d29eea6a9ebe9b727f0000000000000000000000000000000003fd1751c31581d223173ce1ceb252ace9053ac24e9ba49507bae5dd6b288ca717c5f010dbbec669fb3a1f51597e13af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003cb545ddd049bb50a0d3deb80b5eb687d8ae6c7eed2ea23feaa65007530a6501d27d3cbb371fed84178daefb1c88cc60000000000000000000000000000000000e5c8d84146f5fe2dc344b1bdd2b4e1738fa95c0e15143d3ba2f24a4de45b1f5ac5765db8d7e75be08b5da8fd4c469a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb1c6e52bb2122ebc123385aa25ba5e39068631a0d5dbe117f2cd8254f44bf4a80c561250348d38c5d41b2a9b4c45c80000000000000000000000000000000003dc0bd091f460be7c904310a2cc019b47c1e5dda048dca4f9a7f307a791daa3167babf71f50732b73ab0ddf7c958a661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086c2f52c7c7f096d18fbcf15d34f349bd365b2cf487b0979092c9f06dfd65a2f07dfb3ba905c39d0dc83a53e28cfd2d000000000000000000000000000000001138563300c37a436a629ac815c00de899e8d93d2470fd94cba04c1db754db56a122e0fa1d29730bdbb1f7f9af4093841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015301c870935047bde609d5d79e44e0821177b4ea9bed8a0657d85d45a129627afad4078e7878af5ecd6eab50159959d0000000000000000000000000000000003e07fd37b82a6f13dd7910db74639103d2396df273a8372b7289b52a9c8c9008bc3afeb668873eb01335da7e15b07561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c5eb81b3cbb2d4322fd67747e2b71763677c919421b8178ac71ca15a06735713a87dec3cd293947dee2301cd181587000000000000000000000000000000000de3a2279ec9220fe5a7e6311589aaff3956846238886c9ff9fc61d28724da782da74b30fa6236c80f35907b11e6507d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011373fc32c6ed0d7b0f16ec8042182c8d30d1699dc2a8c33483d1f87f1e9216b616eb97bce398f5e2f09de6235b756d6000000000000000000000000000000001480a2b70280b00966b594bd7f498d19916c64575bc56de592d931e08843b56d5c49ee1baf0075b68ea4f3038c8e70d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d0beb2996217a25d9db5e18f8ceaa777d8041585ed8df4b4d6d6dd791428fd74df5c0657d04ab11ced38fca96d124e0000000000000000000000000000000009909da3932cee823c738aec036e351b12e1c28505fb53e9538a9b513dfb53d963e604268fb0baf6ff7efddfc41e8cdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d205dd1a47a70c180978e1ac77f890302ad153e8cfec9d48b4f6c5f5b67e520dd3f8142ae83a998fe772da5db31c8af0000000000000000000000000000000005e5ab712c5d1b4af6828f09d55114f051d4b1f5b56ce4a678ee993b81b91a11fda058947e4de3dd9fa187133ccbe2b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055e0b41d3ee2ced148f578cb483ba485953489e48fc4cff20161cf20e28c80a7e24b26491768a105cc7d45a7c5d767400000000000000000000000000000000069ed977784388018f32e886b189f2cc6f36c47ab406764b340889df86ff3f67f4150a2c566cf5456631dbd92ccac8741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100201a018c938e701f3d1aa10451f99c1a1535899328edb0a5308995ab83a4cee32f2dbfa7c84db02ab9f8a046010ba0000000000000000000000000000000018ed320c95751dbe30d5cfcc49770c0641935abf79c86a99d306b9dff726d5128265898bcfe9093845a0088a787c97ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008133282c3d0ca1cef416c581bbddd7fb5fc5df0f80fbedf9dfdb899f6c0130d1f5c0f96a1e087fc990d544dfd5230fc0000000000000000000000000000000010a0c8bba8ffd7afa560f3963bca116513eb60efb243cc0af13f9abf9778409d33c70d2c85616cbeb6c2afe3972f544f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121b970a8eadbad775ff1b86278b2c5b97f9496e718f753156915f3c4baf4167ade2454853f283b2953d1b4d90263e73000000000000000000000000000000000ec027ba1760dec118a761d7ebd29e99a95bf760a7fc417687dbd9400105e143e72f5cda842c656d70c5da90365114d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f445b48336af484bd3058e6268ec8ca929730d5c516f3788f2320d890d8f4220592efc35319e57994c0760263976daa000000000000000000000000000000000d12b7f8c91cf6ce977ab40282ef1bef90d4253c833022829964fddd0cff050fb2b9e481dac1c48338f0e3331ff6e09a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039d386be120fd7bf268589ee5fbdd8657c5a113628b4c562d672e186af9fcb08bd8d41dc57db75815ea5782902101eb000000000000000000000000000000000dc6758efad8901b429016380454254df80e66c6cfe3e6610c5d42f520fa5687ff093fe1722b3a6b6fd98b2b7883a5af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031fd82a2986a002615bbfadbbd4c5737970c94e7c28f5f03e2534f319c52e3bd1d5205ea75eadea8831e3bb5bf3815c0000000000000000000000000000000004711fa6b10cfcce554ac8c701196d5f0b95e62fd5ba8dc0750fe6c8f3b29a2292101bf037016360508522a7c822da171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009548d26310b6a3186c00ccf9fc8e9f8b6a1ad08f91a6eac3d2daa402a02d3d76d76eb7f3dcf0828e1f78b117ce1de4900000000000000000000000000000000150066f0844ec29cd34ec16a4d67cda0fba6dee9894efc64011307b46c87e56d474b9e2eaea01668f69bc8d7030b1af41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001013b323ff553409aa4877e0ed75882c4bc821a34701a31cb201b673cddbdcd472afcbbdfcd72d8edf955e25c1be06ed0000000000000000000000000000000004cea29593e77cf0763940df148f1238ed21440175cc02f36d388a370ddfac2511517f09d646d73451bc63e22af3f4411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fbb0c86907349179c6b00175d14952abd81ecf2e92c5d01874655b0758c1319033a6e065605318a134ab5fdee8e804a00000000000000000000000000000000129712fb3faf7372ee36a5f4567e620d6c7ee4ec424b93bcf4930151355fce2013a58174c7e5015b31d94570124601d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9179138c797fe7d30669dae613e3392bdace34c1a5e326d2a7ff4f0de48063731ff17dcddccfe1227ab408a0f8bc290000000000000000000000000000000005ec6fbe16214443eb937a74bfd9b7385c550630a5ae918d1e40b7334a8e6297e73d22923c97b750d7fa06addb16cbbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ca47b69d0b1e84aca371bfa7e1bef12fc24c371157e9d9258922211aabcbb79626e06d2154e633a97ee13ec66ea4bd000000000000000000000000000000001467a42879068bcfb952f1b0ed8403f157ae1b2d65ebb0e4f1c0093c985373f2634c95e9c1a4036c7844024bbd710f4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1ce88e6b6f7a46cf6bcecd5cb4d9569eac2f8ae1a5af0dc202917deb10ecf3239a6f22b2651e2f3e5ceade1e68531e000000000000000000000000000000000be8efab103a2fff70cdc8edd9c1e6f7719ec5c8e25e2b7db70b107353cc8126b20347ba20c6b71c90f9a4970648bf251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e2f8b6dc5da2c4cc27e304d82f8f804439e40e46620912d57de9605c32bcca31859cbe153c7c9800b21066113e41420000000000000000000000000000000018f9bf3dd190a2c81e3438ca21198398f25f50d8ae654439b41eb3fdf2d95847c4864e7f37277548ddf2f35e3b56af411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001fae158d60280c77c306f1c3c9f687d62e7bffbc4e204214635661218b13bd13f4b57dd20aa5d76db7089511564c8c3000000000000000000000000000000000f8d9f8290b75656116c3a7a61c34583175a2365481b3505ae27cb207d65c7253e49c0811e71119be9fc3d0e951a75291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192c5c6ff96e11e34983fd9f732952788564034ecdcc813419bd1222f74ba01ce6240b13420aebcc3eb3db80cc27f60e00000000000000000000000000000000123a3b848d12f114593a0eaf7a64549fd10b3296210b6c8e49e5f6e39a6272c1673f2e6f0a648731413c6e73e13648ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014695fdc404fd22b3590ba16911230f9596e3204a066a866653b6619ed91f6335f80494311b3de8e0dd6dd4a5dc39ad20000000000000000000000000000000016ea50cac7240ecd1e392078f3031ad74a8727a8749e8a75176713b4d8b1e0325e9b53f831f32fd4f4d3274a6359daa91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b2328ed83828937fb21874ccad8fac2a5a3a88b449afa1198a693dbecefe3a9d3028ca041627de8fd580718b102d6200000000000000000000000000000000022b3264387ffbe5e3389b094a5400c0f2395d01254e5496304b82514322c63ee705403c9a9d3c2420facd26f2bc98911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117ea6432046276820b178d163d25ada931929869e4fc677d0931e21e598d2475568b2809b662975a52993ae006c0b3700000000000000000000000000000000154a057406f5d0bfd153625e54e2c48d5c24bea56a7e4608ae16e23fe9e3ea2fcb0083e058ffa08e978c72ad6d5d49b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129350d333454e2492591a58a62fb5f9374b9ef7aeafaf1cbc91806d089538e977ac8aff9c9d1b359b70ae741cb7a1f5000000000000000000000000000000000524e2d162734eb131e54ec7b16eb361a6a06f9ff718dee6a348ec37ddc2660f39977623723035aeede16b245d5b6a811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad83a20118c6efadcdf84dfcf9bd1e52193bfa09dfc1cef5a22350721ee4ec10d7950cb0999fecb6896782fbe0dcf2800000000000000000000000000000000175e0b2444b76562acd1a21666efb6b88021f5ca3f0ab5f75299a5782e5715415218dfe1473535cefacb8eb202ab3ac11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f22c63b01fed2597d923c8ad194ac27b720ab171cd3e1e17e40c7a43c84f8afada0f124a1b8f40700ce5e73e436e6b3000000000000000000000000000000001420de91e4423aa0c96c54d14e4bf234b394b784f5ae5537a58c3f6b58384284ed78c46a1b1a4ccc500cfe87c560d9f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a88f4c44cfc744877f8fb3223897f505e4960c52f5cd777c6ed1e92714408d866784c4dc0367c431f85e5eab1580d4000000000000000000000000000000001709a908199fefa6f8719e9c6a8ac031dcc17fb15d03cd65020738d31ae524d66e807acc9f0bf8b7634e9719b56043f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0474f73442fa9c45fbe3bc1b036f127293a49889833f90272b722e24d5cffce88e736f2c1bb614bde3e304150351110000000000000000000000000000000015a657201c5784629cd43806329d10aa48becc72cfaaa7e52d6f813925d2cfe8929cdfafa1a8ef3b0ee58dec3f1e074d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105d29c690cb37af781da76e2f8ccc5d6b66cdce6e7fa3613191851ed88319d976efa89ded621f784180bb9ee14b86da0000000000000000000000000000000010bcf7d7bdd63e3cf0e12cd168056dedb0f8b59fcf7c3b663c4846a89bad5bc587112c1b90bb9c2c38f9968307a33d711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000348f2b0cfa2504daf0f9077b02d77deda23004124c85685c7babf6fcd0d5fa3f3877b2fc66148e82c304c8cc5d3c3d00000000000000000000000000000000090291970f42b4147fd47b340198b2bc4aa169b170c4fb0e4351c777e64696905e5213b0b5f9094be76369ffa54b5aee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cdc4bd4dfe5068cc9b34404aa4c781c035d49f4a4d90236b850e0a4c1ae7995dc62883333b9e02d5b0aa4498f92bed0000000000000000000000000000000012ffbcee74ea370333ebbe870e03cbc43b32666781d1b60885505f66c3f21130ab23e6cc8be37958e181b8e858d81a4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000079363264e024174da5289345bf50a7c5be5abd62ced3799752cef0dfa22b19c8047f6307cdc6120c21a829fabb91ca0000000000000000000000000000000018b901b7927ba85d3e90cc07c2c9839200a271913efba5a6edf9ba07d6695b5210ce4f3bec49f8da10f2af561fa55de81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001458b82b2263849914244b4ef7c970bca071f2bfb6d9a32313f6a5a41205219dc95afcc2ff46377b588c90380c0806f200000000000000000000000000000000022f6e218b7739541c28b285876adb5537fbb6be4713c0026da29e891b5aeab267fc410ef4002e3abe8cef67431972441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a0a0397719e7a89dd9efaabc80f74e24c09d5925526acfe84f919ff17e4ff39e6f0619fa1ee83a789c36468fdda515000000000000000000000000000000000860bf1281d1c06f5b5e7425f1b86b8cef0bb5e7b757afebaa8609420da2a497b985929504bca6d574f2c87a8188d1241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa37aa765c1922318d5acf6641935f4927bcbc7e4f917ac7dc7384df42dcbc2883ab84b5ae870ef268bda8f646d24b6000000000000000000000000000000001537a1c8125b576bbb29073950daa91fc580ab2ef319bb40e54cb8560ec640c75d25b6c90d57cf4bbb590e2e3ed26bbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e10866905ed0fa46718af22c7e7004fc9a28fef1e47b94c90eefcb939a2a91738da44899649d9f0b6e4c48ccfbaed5000000000000000000000000000000000760bdc7d22356c5ba16e10f350c8672e617acf4bed21354cf46cfe93dc4cd4face0b05cd12dd191462efdb370505ca21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001241700077d383a02b1cc9b5da5d02e44490e691209afae8ac8456eb080f2d8b62be77e70dc954a9620b5e86b84e2b6100000000000000000000000000000000125cea27e6046e396f5e57ebc9fd791efff98d018be9a462aa8606f6927839daa3515d0b616300255b282a11c93caf751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085eabe2a8de985811e225eae5020d4ad73f2fe5688a00ed96d7bd1c701ea65d7b33fc9c97d6a4dfbf2bb6893f7d7e2c00000000000000000000000000000000142f2f44c1eb2b253e1be99d50ce655fa0bb1c6df17c6f99922c1638b8ebb20c8cd253ae70302bdd65b9a8b8296e0fb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000142f17d3e62c10c822977c9fe35c49ee6866fee26b28e62a1506219a9463d95ce8ae59ec670429753dc5680a54bcd840000000000000000000000000000000006687b542a29318dc64c656bd6f2aafcfa9175aa44df1bacaef818618f756f48c52894e172f1359c10f7872f8dc483df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108b0a1a167bf043af0e621b6dc41fecb5c6eeef9cc7f1d9b7bd99e9cf64eeda6a0f018d2aea64bd013c38b0d2cab4150000000000000000000000000000000014a366d68cf08921fb6b9cdecd63454d1d698267ad2972a797683ef1ffd958fdefb6f7f341d829574d7f68726dc5e7661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c19b0d8477c1cd8ce1f601e9cf05a89678cd4ecde4863cc36c4d233a5167ad17c7405bb91ed713e22b50f480847172000000000000000000000000000000000f500a824de41fd4278856171322ab43c2c8d74a4adb643f02aacefcb06ad6ce43bce2655433e83e4cac4b59a475bc191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010dfddf5797928a83df6e6ddfb4cf504a51095f2e34d412041fa9695e7525725d2662706f3ea5b2d21e42656f7b9252d0000000000000000000000000000000013b8827d2231d6d5fa9d59c19ab34bfccdd511d82f90c6e1cd62863facef0278e3a96497f679515e6d7ea579548f00a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007008a6dde693f9290d0b7d806e888ef719a81741264114aaad9b615b0cc5ef88a9c7ea1767919583d2c16ee29afe36800000000000000000000000000000000041526788120a8944731ecbc368eb905f48df7c4cdc3b428cb0909bbe43ed5bcb9988d269922ed72b1349d5c939c19b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062d699366b776097089be7e9d23764ac1b9a896fe3081eee5f82dab71c47e1c2b25d200d21b50eb539e4ad9be78b05f000000000000000000000000000000000ce929c09c907f21327294fbf27a3c223bf00427b2a960ea06a1f28897f9f9455ea1d4be2643d1356d05a2d1b398946b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000135a1a68b382678ee6db7a72f9ec92ab1999f0a98d4455191d01b11ea7cacb2a6d50be8dbf8606d5f99746f7dfcecd99000000000000000000000000000000000802c80689a2fdf0123520934842eee70c99242c9a57b144fc7d37975b896f25d4da814e775bd2d469e2964e105b6e981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f48a6d6240d49e81c8f7d61d14bd16dc15b867131fb74ff4d748db2a5f00dd80083b7228333f5a23cb84a79c8a46ad000000000000000000000000000000000a8f7a200ee82845018a7a509ac1d5492db67002d168453573eb1638d604e7d798d06d3db566bbaf985c39185511041e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e7d122cbba97de87d5bdf9833d0cb88f65437343fe3d20fb83f5e6df55a31905754a139726b4b3cc926022a44d6a2a000000000000000000000000000000000fe2ad6aea6648ef2735b5380faefd9146608cbc03b08997ce2e3b08110277c23d536cf3955b602b5e0a17d97bd8efba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5e6a5d11f973da9bbe1a789b954d3e4988d511b3a5a4c9e06b51fbd38dd166fed273a883cb34c6b583d6af7fe7d6d1000000000000000000000000000000000a12fb3203f34508da401e5c6e66675f1e8a02bd93028c6aed82a0b0728b67ba9d79068764d84be53a9a4037c4dd9c561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001057a93be9a1e826076b39770a04ed192b118e925d652ef5c30a680c3fde7bd1965c95eb073e2981ccf65c20bc79849600000000000000000000000000000000084cec06b43d2a0722bb7ff2987548c954b59b9ec57956fe3ea5e2a1576f05dc3a20a2e83868ec21a4756f7ac11e0e381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137b09417d2d269f325e6b879c24b6033970bc9ef59c4b081425602eb1e5aae1d44dff6a7602e5f4508f5124b9899f15000000000000000000000000000000000c682154a4892ba07c4b2fbbe6d13999098dbc66a821373e0006f96977ba8c54f9bedd16de231e13b894e8f774be21811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013eb4c8b44a27705c84262966bcd37fc815de13edc10cda7e07057ca5826ec3793f76e6673617296ef9cb7eff2aaf30e00000000000000000000000000000000187dae8659feae1fa7583619a1c5d0f89bfd62efa18004fb5a50c3bcdf1cab09344dafa7c4439355ee1e308453e4146d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185da7dd7ffdd5749648b9c0b9d645ed1236430a2e77f692341b3ce5dcc4e8e53d4c05c575b8db28ba7142d16fb11a6e000000000000000000000000000000000f7b3cb64216841c54ef39f0dba026b1ed303c5b5d053292c306901418806e7ef7f1a8ff0e5fe0f2ae7b98c2032c03e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e0d3a87f704dfa61f0957e23af5a7689e5847d217351ba16747f8fc8bd91d77857998902b7fb9e3cc549f809142e7600000000000000000000000000000000004d757313c4ccb5cef57a9bc7d60aa36589e716bcd38dc7a09044b75b4b6aa3d859cab46f2398ad3a38d8d3edf8126c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073bec0ab8ee9f2bd9a47de1f827455a33cd2cbeb8ee01649b29bf360af72397e6ca8c82e87ea92b32b336327dfe87e9000000000000000000000000000000000fa7b5dc707f726aaace955ba3f7814ff5d653b64840e355fb969aedb171aa84ddb425d374c7a58d92425737c9eaf19c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007bb7051a27b6a96fe6dd38f63cf589d8a40416b80686317367d7567935a6cfc82b73806d7a51dc9b6ff86153cefdc1100000000000000000000000000000000145c7dfb51de559debe0c84fe4e7937f5fcd7808033fb01d7735d91b4e32b4bbb0fec50bfe2b2f05a290932acd44f97d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc3c9b8eda29c75c88515df46acce45fc86a98736b7c682b05a6988b4005c8a7ed5b95b655cfd7d503f9f751fb583f900000000000000000000000000000000044880c8c319e4ff67363ff921ea2601c97cd3e6417ccb7c5e2f902a4514e4b92bddce19e206d1fa653533faf36992a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007167feba987c31e2c017b63e3c3229ebca10de7300a4cf1eb2945cdb2c5c1bcfecfb5951e71d10ca1b245db37486ace0000000000000000000000000000000014c029288f3b0cf3eff9f81f32b0517ee1ab4caca00c93caf6c615e488b4c73ce204404f6ab719d46f513c09466873d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b240c89f1bbef35f6e1857b718569943d2adbc7776c9f3b8923ef9a49a34ad7908b21d2534b4cdf2c57535d5cf5c3520000000000000000000000000000000010db39a4419af80f0c7cf53736b7932b3d3cdc46f9a984c5ed7cef6beb7dfee5a5f496e7a68f81c17deee60cdf47c03b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142e8b7e9ff592ec6b8ba5303171de48cf692b0f1fa74a1174382ff7b6c1114ae15b4545cb3798303e27b44035ec1b3e00000000000000000000000000000000127be3e21f39b378de086279c2e1e01dab6f6351befc79e47ed92bcb3e02239a6534e1ffc073e448bd18c96ce449ec971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a8a524a83950946221df476e8249a60b4982ce0f12018f8c965272883f1fc8d13f67b698fb418816510557bf93e5d70000000000000000000000000000000016141caad0fab72b16609eb10269a5b9bc1f973c8904193ec0c8106f6bca18f18506e60349556fb761c513b52e43ea511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000856ee5359e38460ffc10b5ee8ec8217ff550a94c8f0d70f2617eb4c3ea12135bc1b69a81ab28696377ed69fc8454d20000000000000000000000000000000000d3bb01c23a038d407bb9e150f237ce4460b78738c1e407634c12c5712c9ce527e17cf51038768b8ca2535df56a9b5dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f440e9295635e7ab3ce3a5da6ad0ed6b193d597ab93e858bd2049dfec07ca886c20081626cf484418746f0552c35d8400000000000000000000000000000000049ecdb02de4999c365e244f8e8701ff92a1c43710f1107eef50a25ad2c288fb9a2a906398ea895e267ddc18f6b2736c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a503a2035bb0b055372844bb996b65d15f24b969767241c4bfbb94b02d398ca8a23b1a198b1ff1fd924a8993a306b100000000000000000000000000000000105a846564185baf49b5739cb69aec11ee2af3c17c7abe85b5883c84ee5b1af29af4dc48c0da70da926ab7abff962b091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045cf98103239bf0a710e766e4c168f23eea13ff7108753e4b6786c81556b4e5a66d74520a9b20f34faa9608e985cbc30000000000000000000000000000000000cdcebe39676bff5c52c1a539ca57a00d1b6934854c7af0efe9e82be1a7a6cb53dc3118fa47e22179e27f28a4276a891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad6728172a80e56d724d50fb6f784e0d270ea68e1f0740f8a142fe5d439c26a3c7bf935d28caa75811a826e968a1a550000000000000000000000000000000007c792ba9dbb914d3ee487872d983e9d03c9a46b6598936382e43a77a48829092ca64ec605c45041e87c2718ae1f6e231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010569dc5ba25f094c5c773cd9c9dfa6e49eb519005d3c45890ac7b375c3a729e43e2ac826a62e0fd51159a4fbe2384f60000000000000000000000000000000008c0a1aace274b33e3a6c5a15ff84b7a9d72cb05482bbb96d1abccf999b85042d5326689dd6bfd3bc6928bb4c937a2981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc0308b36b6a2fe53358127c25bbf7a83069a390af3c512d31b9550174a9de020ab6153ab081de0589d0336ba91c672000000000000000000000000000000001396d76adb7ba91a26712f65c0cc38db33389a00c776815c195a1f53937f9d5cc10a53b716e47302b987fdebf3edba361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000570d7f6344812e1275c2cb7044a33c8d9d65630c2f8813a3a6417ef81fe9b469674e468974764d447f0e04fa981a6330000000000000000000000000000000003a74f3633f320e4c7c078edcdcb5f268b2a7d33bcfb14f319481ac63df4e9e4c7fd2b0cba0b81dd39e3d6a7c21856781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbece52e8a4360bf8631c80fc09f4ecc74f3f36b17f80d40e484d62a305649f6668bf9ba51cd383d1e370c279be3b6b0000000000000000000000000000000011158a17132f17cdd24e5da3eafbe9fbbaa2270822a1da2243c99bc239e34d74aca0da5b59379e60130650551c48c70e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dcec204e3fc7be70649ce455307827708915d541899037e0bd7c59e0e2dfa7e464c4251cd55e217375c89ef36349987000000000000000000000000000000000229a72db2d3a0ccfece3d1a9b08ff6a4d52a7d4eec40abf9bf3c5860134bd1af84f589d091a740e5c3a183ec9aa381f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f74b811aaf9af101496412b823b426085ff8cbe0be16ec146f716b93b67a9d49478e3a61a670e2d926063f4098d8980000000000000000000000000000000009c99bdb057d780ba322fdaf0d64b0ee2e108e9265a9c7a43f547d3e219b072defa51550f0125ba8d4e8ff682c43edec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000007528c336fff5a2e805040acf96ad5acf88dccb539ec4e7f7a0fd6af0990d11acd751d8dbe2fed7e6c00af2176402a000000000000000000000000000000000b59ed6d23573e077f8c53f4712a1db38cafa177c283941fc29b5237cef7e06c8388a725a8f0bc34fbca703b9f78790f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008eb9aa9b1c8fbe3ffc605e27753983fdccbfeea0478d2a0701da93263562c42fa7c27b1b1c92fcbc7cc780ece35a8d0000000000000000000000000000000019ddcd894aa3b50240cb1ce805bfcbe90b4838f4471b3bee37ff62544d032fa768663fe05844abb7ca6b7c604ea318551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000246ac97af8d7f651358c7f0146e790764fcc7d4bea68dc283895a397fae670f50f9a8ab2703a8c182420fa0cb9e57df0000000000000000000000000000000001f3dfa895613cfa0fd82bf07b0bf8d31368cf33e21312221c0ae8880c1679fe10179c726e624a9eb78ba41ebc5d285e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093456a46a4fea6ec912ef59379eef2def307badde4eee92b12e2890aff0b1bccb3b11378705b2f1c5849629372e760b000000000000000000000000000000000cb35f5b7eba73af36e6748863d90c2fae7ec578b70cae36d1895a7517d96b04fce7f058b7c115f211c39ef5a012e02a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae50ff2c556fcf11784836313ed209c0c248f9f5d0bfc0dcac5e0b5d2c23d54bb2e420bc5260d1a8ea17757837655a500000000000000000000000000000000031a4b0ebd75687920856558f9ba8925cea6aecc2d15bff06bcc093a7cffdf146c74ea81132755b83aa6cb0b5b07744b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029261dfef4a6147b77087c43c2fd4c51f5a8d3dc4b56e47222081db386efe87e0f4ba71e73a3300cdad0ebde51671d4000000000000000000000000000000000afc84590fc84f628ea6b3a7dcae723f453ad02bdb9e16490cba2ed2bed7698aa44222467a7aaa8841603654b038c37e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007da9e1693edfa8b13f6bd775274e6cbe0fa6ca64ab5696e8890de3304f8caf7da0897c5187d31f3af4baa5e8c4f3f0a00000000000000000000000000000000090cd618ba398407b21186a3b654ca74e8b4b81fee9182e59ed85ff36aa7b00fa4746283512cc8d64b314937b8a959321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001281492565b70cc9233c5c51059a3acbdbcdaf61bc5325d5be4464745f6bfffcbdaa9cfc0034d29ac03e44a53fb4c8b80000000000000000000000000000000012728011592f23c7ee53c47c199a6fb00eb2fea611b5f6fb0c91c3b89d0247101dfb5519023661ccd648c3cf6b94ba381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ced9449207cf29b8807e36e521e635e3e911e25e283564199dd50e0ff95a82a64ef2e4a34e2c00e853d24e4c601767000000000000000000000000000000000b9364c31b5f1ce6ff8748909d6ec8e9237a648f876c3a36a79812b108c32b6d571ab2bd809c531db0022ee2cabeecb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000caedde99aa3c3248e529c9f885dfbf7c19957adb0a2ba9f38a5a64046b25a7af39666baf072d12d32f29d9c778138c4000000000000000000000000000000000587416adc0a5cfa686487837980c8b2eec281781cc50ef1b90d59b918e00fcbee8b6b55f88bb61fa1eeb1998772848d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ead29df3954bbee044ab074bd5d7869f07f0c016b1d4e9ab97bd9aa9e748a735808db53f47217d57969e7f57dfb557000000000000000000000000000000000c9bb04732fedc62369771135ac46b883bb27c7c5563bb77bf275502a5a344f2c5876d59daa89645a936ee4f593bf0841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7b242f5370170cf80da57bb3bc86a2e602f742c98f428a62dd91cd608d6fb6e119effd1f01cb6bcf0aaaf454fba1ce0000000000000000000000000000000003f64e278d8f22bcf0f648736d175f99f52bfc5429a9c3773626c41fc94dd13fe676a1a2604f71061be0dcc84847556e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014407ce6b6a8dfe423a7e8bd38aeddf8e00f2b19d6a928c07fad41445572deb5ac9b4842a04c8b1ed61a7e80c6cbd04b0000000000000000000000000000000004e6fe54a119ca3066610a55dcdb4b10b7186fac430dd18bff32bcce309042e7fc98ae21f27c09b2b247a00aa6cfc6db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008eed44596ca5f7c8797bf9356ceb21008ec86d1063937d2e66375447f33a61a5f296eb7205adea7c4a2dd04169d5666000000000000000000000000000000000a97286030fb6c35945e2acb59eff3892d748b736feadbdae16d44baba3b2dc8be83630456ced4d1e045ff7dc5a68df61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c495b8569d3411fcedae08ce202e74a0f6ef89abb0294fdec856fac5c84f3b4c0018c71d0dfe680bf0dcd4cfa7b7d550000000000000000000000000000000000c5279e0dd49b68dd48a2d040ce657178698655a9ee26f21ec798f274a19bdab7d217469566a879b65bec937ee6f8811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123ae1cd645b49b72701d0a904a256cb12c9afd86811caf50580c7e579decc067ad3594785f12b25c1e0f75df36f7391000000000000000000000000000000000add1b25c67f431822ba0718a8bc8f44f5f98c7e97a4d50f532a5000ec14d0470332d65b59173fd5dba1be77727adda61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a0b0ce79d88896142137213396a5f8b54a67808b55c94e5dc1e1460004d26ea3f837a06ee511ee2cc0cb71ceee0145300000000000000000000000000000000088984d6f5b9e37345b62befbb2fea981d3d9817fdacab28ad7b0cfbe8d5f94f917db1c461925d1a758fc9275cc7ca4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7e13eb9cc0051482bbea7fb59b3cae0e38b16799996d38beb2e90de973d9bc9187f87efdfbd2624482736c67fd326600000000000000000000000000000000040b46c2dfb63eee17a60ca05b005bdd2b0c30ad63a731471355d89d7909aa3e3e9a5872aa2c900c1dbdb2757c1553a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000311a4bb683804d5d49b6a1bc574df73a2d090faa52e72f9a0bb698609f7aaf59f79c5409433d8e4568a7a775546a6ff00000000000000000000000000000000083cf005c2ded093b12875d111e779caccad2ffe3f8152ef455364d45870d92894fec763b3337da2ddd99097f96024921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce63190c2ebcb124ec63f1ebb3c73d7e570a3ad86b1f4ab20ac5f709b43ce915f95690e49da42df0ecaca2421395acd000000000000000000000000000000000cd5f5bd826f22feac664c5daa0b445831680052c0443869e6a88f14ea204f8778942853dd33779c753253040062a9ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000196047e249328b2cfc9d5e1c433e36d41ee93de3533f3acbb11090cecd4652895ebb0a5327d26e6edfe0a50b203cba2900000000000000000000000000000000034f8df3e55143ebfb0710a66851c04f2b742cfe3c83816ceeba467890ab05facae0eca6be0d6521d8fa9f73031631d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b09503aa85a030ce334db16dc866b537c03bd828c2f5be724e3286cedff3d4a65f6b114775b4d591f323cb92dc638b600000000000000000000000000000000025843816d5e48807e2659aa59b25f35069f3d9541179fdb0274f5433b752b6b749e7a711b9c5860c67c6e114d9b4ee21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013fbf7da5f0139f1d04a9686e21f56054f079bb2c3410001bea4d76b546e72319839a5f8c185e1aca1b10e0390275a020000000000000000000000000000000013bf26b17c026c23b361afe021a993d9da1d2bff873b9b6d0abcb84f095149825f9b942600e05743f35b17b6449e73361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179f8dbd223ca88bb320cd84c66c34e3dbc6fbfa3ae12b0e9c0681b43aa8bfdc1a6a4f068802cb0b087da5bdc4fffecd0000000000000000000000000000000019ef8d91263bbf28a8f0e335323c7419471c677b5df1e461f686c3e61d707c55e2524b83e4e784abddc484b078986f461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002172513e2ff4c594a9c16fa585e903777e05642d49fe9ef73e70d34faaf9b7e81a590fa53e42ce163415077b17e38ff0000000000000000000000000000000014350eb03764a955283559957ef67c3a37ff8f87095f0d7954af591c47d88690caf0d8624aa8e9bf02aa8f2e8cfa02231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059a71b9ffd9f4978e80a697697920af2d77bfb61242a51aa6b6aab63f5e247c8a847011383fd7548fc6d49b4138876200000000000000000000000000000000172053ff657ae2ad44388c8ab4d04aad5067e575e86b3176fb6630f38da9eff72f65ff1c39e6c753539ff6f15e4fec401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd1a0549ae9abe3f5a52d77cad7f0086918348e2609dc9f0623ff5c6ea46f3aff1c0cc50f2aadccfcb3a2a294af75330000000000000000000000000000000007b308c4ea482c5f2f1d651244fbc7ca74185a1b811ace62817341be6476892c19e848315a50cd2bb82a5f726ed8633b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114848e5bc681991e5cda4366ddf182e13305c89ad2b729b0ec92731d473e5aa06df8467e70100a7642df4495f478f000000000000000000000000000000000006bdc557ded0c5711662e8e0057c9c60a37ab1503fa393c1a1b63e1a4dc071500b0bf9405b766b925b0f9a5aa1cf3bff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac0bf345e3324bbe63bdeaf3b8f3673b86bccc755195e85112c8f2a7c97957a9a11f08ab4116022ed91e1e5d7a4b7ed0000000000000000000000000000000004e8ce20527ef222fab385e59f423634ebfd2377ad273dfa108ac181af687bb26cc8490184e578fbfb5a709c19d174431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f2fbbc0b1a24022880d2b31290a6690ecdf352d6ed7e7111d67c062b52ebd655eb2d9f909c5c87980b9c7bebced5f0000000000000000000000000000000000fc05357a9fcaf113fd7c4aa9209a2d168d9647ba21ca8bf5e5c812ac602968dc8697efcd5731485eb74e1d997cee9881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2821ba7aa97c542255e9192f851c3b9af3ea45c8d97918ca31aec422fbcc00eea23a4596ad9f36f266215aee26799400000000000000000000000000000000192732fc540be66557b3a81c7956b0566901fd9b7aa37614e326d26f247692910dfb2cfeaf95a68dd8ee2639ea98f4831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b9dafaa2a584122879ed712493f1959563b9ed9d5c304544648e446658c727255412d8fc2cb8ebbc5b1963c858e5e100000000000000000000000000000000185033131994263e2f789fbd902f2abd1cea63bd329515f3d11045f3638ab4c9b11f2117b173091578e7ed0c728cf2c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000243d34b81544ab6b1b14dd5a211a974b96f7fc1f569ef3716713351c727b6c7844bafabae8cd44bc80ee2cc0a42f4f6000000000000000000000000000000001642cd6e6c1d7d9f766be080c0781e5061e84d66003430810e29c915c3021fc23993901fee34fe8f18886c2538d3ffd91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005adfa462a75b7d89ddcc2bbba8e0d2086cabb05c4060a7d34d3d221c4fe0e20f816f23b79ff4e8599f824fff71ad0df00000000000000000000000000000000196f222466276b99a788952a5e37de4ad41b73dbf3cb8f8cd273235bc1b1375ddea7e452473a02acf386f70110765d6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e3b2257faec3f134aa05a1d2c082ba541dc0166016215bdfab56ca3074a505eade74e62244c8d0c51e7ac2b9ea1365000000000000000000000000000000000315ec81c4ad43cc0e180d78e820c2003900afa5960014642d0ce983a5a7387573e46a917bdcd5aa9de2329069477ba71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e83cfe8c59e2726acdacb61e3b14378226c452aa785abb06bb605fe007078be179d860f68b0dd0f0622bba8b979b93000000000000000000000000000000000fc31b5b4539b9c894f2a7ce576fa8b1c40e7cc966d009edb94edc9dc4f3bbb3dcb64391fae90d4d00fc12c47d2bdc761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de1935ca804ac88ef61f419a7aed1f148290bf2b581e414b79840e4544dd161d6156d2b9392a1da537259a728b85679000000000000000000000000000000000f9b27ff389641d5f23163057a2cf6bf25174a418ced9f89b50aa2a9af13e10536cfecaa5c8e63f5f70fd3662898a7761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c2d0fb963f07f2ca1196823777ea177571f39823a2bf4edab79e6f94ee3231bc9870ec1cd0499c4c9327eba585845b0000000000000000000000000000000003bc14cf8faa822b6daac2d60ac1c421c82a64dd128dc17f0253ed3392069c5a86e615a87a6d194df5d9c635058bd4751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ad4659eb28c45d60bf53ded2e7e9847dbb62f876e38da562e19bfcc29c46c97fa3f06432c1a8f1d0ee0de1d31818c7000000000000000000000000000000000f5a686c72b8e544c11cc607d2506e272185f0da7cb5970ae28bd43e75b603b684b2236e54e2961fae66d7ff500c80101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d0ca629f53eb1eb756ac6c76f9f50a2680c604e351897e7a26fb3344791ced6057c6dbabdf445921cdf76800388abc0000000000000000000000000000000012c7e69ba63134588f30f0cd97e3e957346d42ed7c0fde500e8004e58674dd83040ab0fa115c41ac0080407aa36945761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001703c764bf94f14e4cd32cff19544c1d5207b9920c4ded117b0443b3f1e94531b23566caab388a0ab49b2ec65ab9a435000000000000000000000000000000001809a77c65f10b4e12d88ca6590bf44eb4047a21a5a497f138f2fcbaf8b7a08dab00944a10d244af602a06e219088c891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff8fb06bbe836cd3da90a336a2153e206653f6e48e81771d9528f877c9ed408c222854529df091b4945f25392354f9b000000000000000000000000000000000f0940d1b9214ee0137f47b21f998a9e6aa2560dcd58140d3ecc08d48fe9d04757ee832d9a7a5d4fa819712a45fd263d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a3f2553fb2803310a36912b61d2f93942a042cd2df39bc350d3c3667218e5d6f9e92c30ca357e7cb1d6dba48d8162200000000000000000000000000000000173c5bdbfaf7fdf53dc28e781c5c0864f40cb8f6d305ecba5414ff8720417d2e9a90d9ddaa6e83b14efd247b67cfcc301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001035fbc97d4099786b654a5913c3f10d4176391d95e1437b7e88bdc493b0fb640712ffdfa407af1dc6468d59a235a4580000000000000000000000000000000010d99def8571a278f30a5e77e35e39b1a10a282a8157f586ddf1977c7b95e12babdf9ac0d6d9ce9da79c09adf10233031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001fe6b5959473c5fef481b4669c5317dfeb7ce53882f3997a729cfeefa2acaf16e6866733b192156e7025adb788a30460000000000000000000000000000000007bdaa0cbeb99d086fb5a9cb84d0dc1318e2771e8451cc5e457ee62754bd9e70e5044bf93a8e43fd1cdab51eb19be36d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000479763c84dfaf62cceb0046b61ee30ac2f8ba7424f2ec3668f77f8840bd57d5d3b28a0b7e045f6ade4a965a123359c700000000000000000000000000000000107339ee00aeea2742777a47062e72d65a35b5509282972c7d0b7ef0b4cfe89514549783a4bc824aa3f40c36a4f29af71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de40d1de534205a5d823ee0afecc7bc76d359ab8e97e01a100f62c3b0e30682016627218bf2012b2e839b2cf61a181a0000000000000000000000000000000004f5c1d74ebbc4ef21049afb926d27978e611b21d5ce3b89a70b4f12436c0b7116e33aefaa69be50a37afa41c57dd1d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000390c37942642f2d0a05c7d24f3a3c755154b3a578cb9a3cbf3a8bb78f11e479c101cedbbd91ef55919b91368379d578000000000000000000000000000000000f54122b97242d517429d553d74e426235900d95dc974868ef9957227906c16bee168078568bafb232fd35ca324eb9541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001623dd5d7ffb0a226375666a3172a6af5ad38ca13e15225df3db300aca99d7f0256cc2bb5d293280a1efdc4a123a9c75000000000000000000000000000000000695233473669493d02cea4092cf3d063cc5ac01670ba26a9cf23b202dca9fef96c75423296a71b602be96455fdc872e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c404babad3aa816fac104e86291bcaf009d0ed83bb2f27768698b2abca91e2c6d6d52bc692dfe5b53e6e7d28d9e71030000000000000000000000000000000006f4e67532789cf268d0ac32202909122fa27f662ca5c541f810bf0bdcb5e27b8824e1c8c15881ceff1853bad621ff381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000486282c7a2263f6e67887269aff16c84b32366675335f2a49f3edcdd9e2eaa566650e77ce1d36af57ed396f3cfa222a000000000000000000000000000000000a3bfbeffa8d55e34a9c51b400fdbd40ae69dd6092ec5248ae2da0557d75b52a569b5617b683ddf9ad1c26264a5384f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001156d305d09e6bd3c6c10a98035b939e21ad210ea39cb78a3a32f8b67767cb09babff9cdbaa9339eeeb7cc182c7d4b8400000000000000000000000000000000120011b3450633d1d02f71da660e278e73941af243fc64ff94082b25c5f7efa776473eef593d61c4c71f9a8d0219d4cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008d14b868c9996ced4068f0ad8d77c9c8e87b6090b4a1a07ce47529c12ee6ee2e9ee3254338bc7a74d002c0d0cee19400000000000000000000000000000000148caeeb9064285567e33f54972c2b7be2b327e4f7d64c15cdbb2d65a4a38161753e5af0a36391b03cf8c5d9ffe5dfdc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cc30f665dd9a1a1feb17b6ec7ba0043e2b3db35b920283785bade41c0ee86a2a6e5fcb423b4a07e2c1e0d400ebf3f000000000000000000000000000000000152e82d69711ac6e95081f82ade6a739dcb063fda716fba0c04e820febace2abffc031bd9f83d18875e3bd385fde58621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e68a9655a0e70bb32e2adfcfd3a493bc0e376b8778e918ebce9829eb38987e1ab0f9a1ad365a7a60aaffd62c23e41720000000000000000000000000000000001aff8b0de8964cb814383a186fe3c09b4f3bf8d1009e021eba8033c9ba586b4d1bbce42720cfb9aca437bca1c8015e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008bd1c66a9eb8a2ddcd00bd889dcc46cb1d02b270612d5cb56f1fc7d421599ee9f33e25400145c7075432e5127d2af470000000000000000000000000000000008e7e9216088e67dfc95fccc8e88ade66fba14280457d2513e792b4e53a94eebf34089c025062594c1aab34b63661b031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ea6910ebeddc1951546260427856df51acfab59dea6261c710db5478bd9e9e3a4dd7d281308a4976ce628afba80af900000000000000000000000000000000163c190e3306cc23398dabbac510109d449a565cd6687235dd2ef1a76c95adf722d80e69dfb95a171849f6ba8ab9ed5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2a3646d8e1dcc1fdadf04c767ae49362431ed64154d3e56e0b3c02a229a4333a79834642a81748b429eb51307f9fbc000000000000000000000000000000000ea12605b0baca56cccf5c78756185ecf353950901eec1d9033e698b20494b01ce64bc4e2326d80bc94fd831757488271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091a40ecd412f97305308706b3120156c5d6f3dcf02740269c066dc332440bff4ad20cf779fa1694b22d0e133c3cf01600000000000000000000000000000000007574790f2d963b178bddfdb0813a67a467a1d6671b900e1050773c698868784559ad131931ac21c07d289912116dcd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a50a5d6fadf34fe9a09d28ccfc931a919e060241481f4dabfa25f8f8f76ce1c89482fb90de55ac9d71e7196232a6c00000000000000000000000000000000018ed384f6664d8fdc6dde21fdc15f10c9e4171524f13078f6e2baaef0b476655b7c85e63d4fde3bcca52d3dc249a52fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015b022cc99a8fa9078d5a430cc183d177df7a7acd08a4c33cf7e9afe637fef1d9f0da9fcf31ec736da2b50a4f1d9c02000000000000000000000000000000000ef4d20853926038aab325b06f8a0e22b6f13d99b2e7d643f968ad5f340edd50b2aec38f311fa0adc2fd9664cbdc9f9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b478861de307c9dd8513491c85972428ea6c5733e8ced606527bd75ece1686adafa4985a9307f1f567494e262b90d5c0000000000000000000000000000000017d2115cc3ed79d2218fd4a7823bd95c4a13536f5f55ead3fd98d056a29518fc3dcf08910b6a02c9b6a4d38f867095b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010464728668166a25c821a9e18e00b293be05cea966942667b9f44ba78c1a185a09e26b8a99dd5e36b58d5d7005570530000000000000000000000000000000002cb2cbea6bd87cbd5a01540c26a36a53612c4a4a2e4f28b6a32494be1d21c09f719e80d0cdc6c182b7c0c166768caa21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c4e1319dac24d0b1de9ece94b42d27744a05f70175f6bdbb58280ecf7f94f05d7808e4e30f915199b32ea5f1ba13df00000000000000000000000000000000030bfd7eb2b5e70082a24c9ce64f75982b3f891d205c285728c8ee2a262e6b106fa83874db731f0f3774388af5be6f431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002424f7327ab0dc953a86f88e016ccb440b5d71be20351f52cad07c8d3f0a62b21db21d08639dd8a05b38e5a387ab90a00000000000000000000000000000000013078a8e395c37fad65b5122495b1a2318109e082c71239028dcb4aea8fb0150e76afabdf585b15db646ad715354d8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186d563e1a4d912e04a903df464452971ed082baf3504f03f668dfb9cd7ad8d8ac123da7f2cfd48599da7ce08a374c72000000000000000000000000000000000704cbb33b24f9eab11a15a322d18bcd31ef541a53ebfd4dfc4ea25869bbb29dee23d2d5352e4b13aad7abc58280e3bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000eafe00a2d36979878686a4dab0154305ff2a671e66d3ade8889c39fc1bdbb3ca63c2861479a369e96e52b4d219c087000000000000000000000000000000000bdadeedfe95ed197fc565ed380545c94e338e5dd39177becc510e0d69ec95c42df6a1e0bb8e84175d54656d6045040b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013428ad2774e8a5b64f264f8f7029b1c37cf95cd8cf3915dc82a5009846e534493fb9c0fcac5c7c22d62d9c170882ace0000000000000000000000000000000000f0d0f0b170b0f0c155ba6d354076a37149914ff74b717379cb09843ebbffdd1ea1032d7382cac3bbc84942054ad3df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6d1b073120489e79237027b38fd6044e39a346e1b5f08a1ad24c050537beec7d29fcdf9fa02fcc7240df6cd4762adc0000000000000000000000000000000008f0bcfaf2e66f48f9315bc2cfa2cfee31437a8eee5f16586c158eafdf429849d50c73047b04de0aed7333fcf14f8ca31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b21e83775497318753c61fc471355b73134e578dada07c1f687e74ecf1de5e92b3f164ee70fa8d034adc67ece3ccaa9000000000000000000000000000000001071c60604806801af0a7e90287738903cf077adfd5effdcb185b034e6875d05aa543a6c31271538492f25908b1458b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e838da7af4138a2b97de5374eecf651155dbffbc289b8ec25d7ffda09b954b8b17420e35146cf8079f25c719ec9de490000000000000000000000000000000011ef6892a27e024d370be5bc24ebc20d7df6712675a88d0d37102a8abef4376024d7e48168cf58c947bd0fe98109ff8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ca508b3a966e983d0ce9e9867cf880ba06cc315bd4727d8a88edf5ed4e027c2ff7aec031b760066c58c453d7734ac400000000000000000000000000000000028b63b094a8d86fbce842a53dd32f9ef5afdae5d9bc34b8cf1cdddd836696d8c675ce6a8e78c870f6ca716360c774741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f86f0b35a28fd5991563a53e7c48e4e286e14fad884913641c4bffbb9d6a6ff4b5c66493028b293aa5982599a069b76000000000000000000000000000000000264a06277f40aa4c028046adb18227df143d9084bb4a78cb04b06abd10fd87a54c4d9d86c279a7c7053b3b0182dc29d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a146ca3a00e52ee2aebe6549c813e0d84eeae207dd7ddc04d9483ca89758e772d9344e13327f3cc0035ed9f9c114f3000000000000000000000000000000000fe02b49ae9af686ba4df1974970d23a451e0677420ce121d0385358e929046b70e84ba628f1bc196c81afdd0362b6dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001793650228fe4e9967adefba5a8c4ac11a7a2c67f89fe59859f0df93af9fa7523794a281d91a895c1d5977a42e814d2e00000000000000000000000000000000048822e74234d552aff9b745529c8f944995b99d544cab9ad383ab3c12708062d2e7831daeb21e771e2169de4c7825b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000794b03d2e74bdbe359a83edd7caa80c263166a0957064f1ea9ec777ff4388272582b5327d152fcbdd9ab6026e91028b00000000000000000000000000000000076c7bb97f6a410b55e18243d0bd8a0765aac01bd30f554b70954490635c1209573936f85c47d7bc4f2d3f35542699fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000155c15b2dc77537b9bcb990f071c75f443bda672543b32e22bdb38fbb2849479a4d365fa355572bef556d087c06b98f000000000000000000000000000000000175aeb978b7429d7c4ebee3f60562fdc690b66de592fb092d87c602b0920f4e074bd9746810bdcdc86a406def5f86b0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f9e536073688c3b5e10d0638bb1fded27316c7d886b1e8d36a10700ed430af1e4dd8f32d1742860cd512fed8ff389b0000000000000000000000000000000008d6d8e782b34ca7fffacf06793b8d298ee7530a1dd23c83642966fafe436a92c72cc323ea587528f41b67f2dd3f9fa51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fb866b97455eb41cee5003358842325b15103faa1c9852de2fc2cc67885c6851871c7a4510991f533d7cfb2233e476000000000000000000000000000000000aed5d8272afcdf0b1ec01c8a3391c424b79b97616b5a4d3305ebc475fa97d4901304d750f9f564f5edbd42f19fd27d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007fadfc5038ee177f237b819694e731419d62aebda7e21277d19294a43a51ef9c8f22c366e3a124ecbb8944ba2b9bb890000000000000000000000000000000006fa5acce813fcb979789c1156a9bbdbbf1559644443e680c797fd9dc0bec17a62e10d9ba33704bb50b86fafdba709a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c39ec27d78349f7181cba585a39781d841624c6e57fd208c8a8d0c37847ae461fe6300a8a9257dc7da44ec8cce0053000000000000000000000000000000000e8e00a75f7561475128612bf6ef56e8dc569ff862473a1cd7525659baab6cf744ab159f73dde0fb6c6bd09a18fd0c791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006affa0c9c1b768aaf7b1e2260814b77a6f8aa15ed56be64a06763db8878696beacb7dc24ee152975bad425e40d75f8600000000000000000000000000000000090b2128725879a47345e54b7f39a28aea6fe76d768b34662b70c2c633bfa1be1df304686593948f587a94592ebf21f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001542c6ed5180ab050b49d31be82a87b7ddd8bbaef7735352648c8568d8d9fe102a2a2899f97f8a7df3fd75736e64b14200000000000000000000000000000000086b6ba7cb58c7423a4cd6f2cdcb449534b53076b39078cf4c935af844157d528f26e60fac3eb3adaca2921f59dadefe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000953b1103f5abdfe88860fdd6a3f90250117f64bca5e03c9f5965932ac9ce312c9d2c8d19091bf68f87801f5b543b22300000000000000000000000000000000132be64b57b2e759b146e7760ac1a53ed1a3254390562720667a40c63d32a2331fdef926c4f06cdf64209187541053e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000331758b7be8ff4a64ec908c5140b933796b2a07d637407843bf79bc613c431d66edfcfe684c4dfb4b129d8eb27a874e0000000000000000000000000000000008479ed2b5695566bc3994d682560631d9565568126d77b009702944361a256fe35b4e66b927fce84e5ca994fdf3b6b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e893eb55fb0f55056fdc82b0f6e41d664f67252a265d4b5594815b46f0789373b74fececcc9d2e81ddd04dccb426730000000000000000000000000000000004bbae027113ad216d8328062d96aea8c45874b353ce77d19b2dd14ceba84552fea9fd4c7e222cc946bc07866151d9c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102b42aef6f2adab2f76334e7bb08bdc2b953cb309dcffa31708acb0ddf0b7aa3588e08dd7e86940802b34676164722b000000000000000000000000000000000e0c018f9c43e9770c10b54dd8dde001c46f6a919c283e7fb1f3ba29de335f9dad0ccf4038ee9ad37cf980ac961183361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000933bb077687ee622afc5526562ccbedf07625aff161e6006df1a46e203cfe8731d42a61d11144ec4314ebe84ffd4933000000000000000000000000000000000e83e5102f14bd1a6473eb086c4126d7dfeb4f64d5af12b873f5966f16fa6ce5662f7eb50129545b281baa5b116b0a341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007083de341510837c7bdd0e6f51aa0f6e349675a7d3082602c3b8512ef1394128ae2998f99975cda75e857b5a08d85fa0000000000000000000000000000000002011896213fe4bbe185b8d162198d5ede677f08a6812fb6f0140c96e79d14aa73bc837a05ffac78325b85bea18019a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018080d135b5ca27ed909790a81882ba4ef3a3ede0cb00825f76cb7d7beb119ae0595f0a9acd5a95a5a79507069e73a14000000000000000000000000000000000be82cf3cd5ae1469b8db11d86a2ba976c5bc20cea89390cb79a6c0d611e0da134a7de7f6464ccad24cc1c1d9f40e7561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037302bbe9bb49dea9b0aa5a22a831baf90737ee4cd327b8726365d78f34b4064798a6783e14940a1a773b65149c4319000000000000000000000000000000000a7e7099caf057213b267a02ad5585402e522bfeccb7818637c3305066aa9d28bceeeebd9430207db20fed0b9e08cacb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000121cae27647d2e02f3c43923af556a3eda2e5c22220a32e4dd41d100c4d4c31bf35295b9219ee9fe4ab0081dd51bdde000000000000000000000000000000001999191f645cf20ec8515ac5c1c95c84ba80b51ba8834cc12d6507e0200eb554a35a1a179d74ef555cf0c7ac911d8f0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014768f7c76e7166819bffe5f58e8aabaf46b7a1ebe407a5f83e05fbbd3f4609260b690dd09e2d0f03e579bfbc466f50600000000000000000000000000000000135127353681d15b513061d817af122c1e0d8ec5e948be376d2b34a71a3f7c608cbd183166dffd70ca727c8cbedae3ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006354c42ca4449a9e9a983795f059a70752cb164e5b9a845b8fbc4edb4f44a0166597ab0293835de7911ed4063f00505000000000000000000000000000000000fb5501b5b733903ef053122257d8adca07bf0e3e333a969206c6386fccf4b4539b5ba9d40755485a633240b3bea207a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a71e8a6655847a09485b049a3d0c23837f6d96cb674e4b94f7799c825edf0389fbd25a7c8e5ec33578ee82f193b6db0000000000000000000000000000000013f9e00df2cf47117fd1468467bdabc00ec60f413e683540d2f0d3ca8289e981effa1a043df028622035627894a891d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006375f88dddd3b804da297692e8bb8b90fa73feaed748194502b9671f1ec826c5fe6a26d7add27cc380fb4028e0ca0ef000000000000000000000000000000000830ea097f451e784aa34e1524a354f57f85cfd63515d3ae1a9906d226ae67563532318bc3172bb69a7d425f312c52a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000846a424ff14eca9df30ecaf599ef62aa08d1e5698b64dea21e6eb79d995a35f70b0fd31b9e4ee12e679123208ada404000000000000000000000000000000001424367c38e2ebd6664b8e48a85a2e0cc9b297d94e473161280ccd1027e6ecf41eded5ec81a6a66ecfbfad7d33a097121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd6111af85f5bd4536452f3015c4d2d6beb589017dd4bc13c6bebe9a3af6a8748d3ea6338db6da9fa7f35bc8432e0a40000000000000000000000000000000016b80b7196538399b4bb193ade0e85b76d27f7a68c9a2dbdc2202873c428efc34660fbf69d0997127df6a69f88134b1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006acc0cfd0cbd079960c7f9e836cee7caf9cf0f54de368ba7638c825d0d4546ccc9a337bec1887398531753b17bd86e60000000000000000000000000000000018d1d4284057fb9aba6957f579bc7ef6fcce5c6c5aa35a04b31a9aeb5ad19f3200547caee022dd7b295dfff5d3f2704c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101082ae48861dcb8fcf305c400a1cf7233eb0761061b9206e502f47bcad693d6a6219b5689c7a7e7ca7f2fbcbc2a8aa000000000000000000000000000000000c4130c8d3c4fa31b77f988873067cde306f9371cba12715e5fe5c4e186d510549333b53190b85343e8aa4b1f362d26e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000504138e95e37a9c2d4e095d2fec28903c66bebb772066988ce59d2a29f9c3c015508985a7a176def99a2abce4de616600000000000000000000000000000000111e201662e9d65f31510309b23b162188d64426bcb9bf578a03676b575a870122bd1f7c9af82643627234db450337d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f28e792e50d609cf386b1a93c564a9a1c300eca0680ba712542e26f29194bf0766559bee85d56b8f294d3e86d7d15e00000000000000000000000000000000120835cf4f386f2feb77571b73c1e47772bd10737172ab468e8cb6c59e6fe149a65a0685de2f138778942b4cc3e234131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120cbf33df5a672af8dded8c7053d880b3a83f9eeacbe40ca19219511f29d124d89d8a97953e941951b765477e593af4000000000000000000000000000000001107f2c380c782e59a86e94f0e76711c1223cb639f1551183e1edbef1f4333f84cd8f0ae8e723e6ecf212f44061941141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001edee51b8abeb21f54aef507f4724a96f81e3d5ca7437c4803303e5b01ffd2c7de10aa628ebee3decdbd305fb5baf39000000000000000000000000000000000445f8f00c969bae5a6d54d238100c52f7eb4f35736f1d5988897ad5e300696d41c0d7f9193bb04914ff2b0be3e035dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000687a77ef6a60972ad3432cba6b873f6a2b08b48083793fbf4a87c8290adb5172997f94e3296c8306056e07147df370f000000000000000000000000000000000d9cfe84e5801ea837e4ec1cab4544039aa2e3768609b6461bcdab951b3d9d3741dbfaca7b01aa94e7d247455ea7de131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001679c2eb18b050738580fb246c7a55122e488bd2edae779ae6fc7a40656a9f4828b5cfc1ff7021eae2f8fa6c04ad3db900000000000000000000000000000000114c85ccfe5f7a89f2030b1dcc11f938b936eacfd925e83303ac2be460a118fe5d2759595649da30befd8b6a06807d1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001303af356b6b6939dd259500d8cc4b1676bb9171302f0ae4e001b37d6ae1246aa40cdafbf0c34e29ba9ad24b3205701c000000000000000000000000000000001734c4193f4a18589eb6d5b13625840ee2a7a2be7c542146b0d438f51d2d84370a94141ab5c7032407759c06472d3d961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001dbd31e8de7318b2e270be60d2dbcd4767fdfd7c960201fed2c7829cf3f584e7ce3b0c258d1072fae11832849bbfdf900000000000000000000000000000000145195dbec54185bc1e6c2e4dff01b5d26b90dc5033e50ce314c5cc64d18bdc4a5308d5d4ee0fc1b4e1105785f74b2d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ae8c4563a72f06ffaf04413f8ca804358a17db5e8e3fe0d6b41c2ee838b8c2689085625b25171bc65215e6d2b2b644000000000000000000000000000000000ba2cbaee5414addb5bedc652e178818de954a978973ea7638db701532544d64f48f67d9d3704e77b72d1d500d5b69561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132fccb6c20ac77091c3c5aae6d07cb17ac172acc2892a5263ce108bd8c2969ac7bc4f932837e3caf409207af8d8377e0000000000000000000000000000000001274ebf16c73daeaffd9cf38f01ebf44364c4647f42661a5b92f4d3c9b33cf2b5fae9c4be40a75c9d24b43b63192f601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000faf54a39aace8820e9ae36fc2e8f1845a970164ca88d4af5962386039f6f07ac0d48a9f95353c9710fae037513d8a000000000000000000000000000000000011d31bfe8c993a3f6ef42678332cfa8016b8663866302062316c3e79318c54c90ca535b739eaabb78b961a68058898011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010659413c701e67ce4a34cc928a8c087f6c8de05b92d3b0dac75f47fbb1aeecdae1ff45a421c5dc5ee3e3f74589c2700000000000000000000000000000000000f22ac991aff543ce72b98387933547411706e729223163631f485cca3b534a5aea24df5bb53c9ad80805a8f3feb8a931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069255de4844a192d0c3c90cdb3ec35ab01d27f1a06f2aa995a18a30435a8eedade9875dc6e605d4897b84b5cdebe57d0000000000000000000000000000000013883849f8a9be30bff9b68f1a0e8129d1c8a59f0afc22d66a40f0144bb3cdb8d796c8ddb290670aaef63a54ca447aec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001300271c3af761784dc724116041acb1018a9cca9199b4a42dd2fa64a3ec73a15d7f5cb12e54f618b39fba8adb1d2231000000000000000000000000000000001704169e0868e4ddaf6f095a2ad8563a3074e5e1f616a8cc2115ac374742fda9e89f673da3d0cd14f73cb735729cd45f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a2fbbdf84b534ae99b01a6aafe4710870d4d5e5ae7e081aab75a552ca1713567cd83fcda0c85c96c3a48a69cb107010000000000000000000000000000000003670f38bbb499b2049ae5bbbb23d4301d6868c34d5210f60c0554d79c68a4b3052b8ca816d1f3c8c98194c5b9ef52381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a8ff87dea01412962ff6f139cec07efbe71d1f82bbc0e1dc16b5e51e96216c78a15baa3ca6b98fb7f9cfc5017d868a000000000000000000000000000000000b117e0415dd33dd550f953f970c429327dbf2765fbb1fbc67ad1452bba0e6ae40359cd282b11b5b8b2a64c64675a5d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019dc9ccdea5be610853f3cc3f038a3160dabffd0fb5699e5a6fdb9ee81b18ca380578d93bcbd5756d37865fb01c9887500000000000000000000000000000000155ec6cd23a7b999cc56f3fc478d09f9bd6944160893b10ad1f0c6f6213c22949051f17c24e53373e9a9cc634a32ed181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a838720b32f7ffc4fbf767716da941aea60419a891321633720323908bb2a844d54c7f79aaed6fd89b01dcc12d758fc0000000000000000000000000000000019570dc54a55b7fdb0ad8567a63bb3859990e92a180d72d84abb64a52a41194fbfdb665f3c71006ffc13f8f6e53cb0ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179ce38d8751ee0de1ba4b7a002b21f1735621e47934e999fbefb75e66a7782b8a058120d4bee09dd1fa0c2d23dac328000000000000000000000000000000000594d4a1bef78e6d48597037276ad72f79de664edd41be96701f6bd95ad218d718a98465a3a21288718635e6bed394671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005fe6881494843a51f0c1ebcd282c9752c21df1a4e213f05b8e2a2b20cf78c90fe3e3aa40ef2cba2395309d9754308d000000000000000000000000000000000be839bbc2997c0faa69a0625a243a18ef81912d9331885e5c1f5ab2d3781ed4055b2e5addb8a82b7772a9730fd5ad7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6154e29cc1766b50ff0c7028bdeb6b618e0774e8d2e6e4d1146e968c75d2ae66717a5b556cb95e3ffdf73bb0bcb61900000000000000000000000000000000181f370f3da74defd80351b73e0922a6b1a8be59770b7d419e48ec8ccb5989be41cc9773e9737b8b4adc0a03051bbc941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192717b42a44600e9b15c482fca35e5a1b0f9f409773e249d2ba1575b19ed200a54337a21e8937cafcc23fd8d390ff480000000000000000000000000000000001743643b43c9691bc3138e5717f76002f84da6f5c7b6d1d1963c488968cc0667b1130e6b82caee257ae1437163c1c6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e539e00b705dd4c5ebdad2bda367f388af1bc17d58f34bef0cfa1bf81053bde78883e45d98ee02836f30ea17cb2bff000000000000000000000000000000001772f1635eaeff8bb5fa403552bf09e93b1b12ac177966402193add71b658c8839d24ac67b812da75d0676cef5526ece1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a260e154947659a63c1ed7e77647dfc21810b12779b3a25c6b24b1d2f303b0617eb4642605bdbeaacefbb5c24c7d9300000000000000000000000000000000128f13cf0d57cfdde4838507e43cdb45c777051d332272d99cd969f2d9e217a72960cf790d702e89c778877dd0e759101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2d77c29ebfb8d72da1776fba255d303f7c93bb65a7cf863a82810a37cfded93ee19f963ed29eb4518ae1f7139f30fa000000000000000000000000000000000bfcb2a2ae252e4385f81cb229980c35997afed388e60394edc6eeb9e71bb02e23e3166c0f51a0b8b01626aecdc9179f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ca6288b0ea2c3150e49fba5119a54700c010a45f3bd6a1b0cebdf015378b49d00afb3ae550438c7a11345202240b270000000000000000000000000000000011c138d729d246fef585a7b705583eba764a2c3152473101ef0aeb012303008eee1ff1d3ffc00858eb214b9933fd4d911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f90e4ac0a7b1be67b0e56aa75b125c7f5a80be8e14598f2e2822c506b3c100451047f8fce8d653ce8709a8c786cf0c000000000000000000000000000000001813d56dac08123ca87c630316bd9866aaf5b3a0ce3be06f7a82a5ee63297c8a886b3be7d1523d1d0b506733c80696271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2d784b83fe2ec700ed5795a40c193652af97888ecb6ef72d08392d830129e576154a5541825631b0e61e58881eb37d0000000000000000000000000000000013a9d61b64643b678b9c699fb3d674fd490a914f0ed38a704fa5a56bc3d35e337493d8617898d2b57bf43c6bb29494761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165349a37ebd169f0260c7db05d44ae2a76a44bf5d316deeae16698d4d3d9058c422f1e2d9905801cbbf4f6043bc401b000000000000000000000000000000000c5934f5d1d2647cec611bc7630d2efb7acbf45ee16b55fe905c223bf7e05e6ff79f0c39ff5398f91f5ba9e7cf174d661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100d1ee368345f9a87054104064d0f75dfee109ec604f154dee6e1af3b1b08d424fa9e66029731937c2ad851f753d11b00000000000000000000000000000000083210b1726bceac51c24687dc4bb6d4567c6e618209d92334970169830480818dde1d64c5a5a6700c26788d1091e98a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b2c06b3f6f2a1a60089f5342cada61581e2fff1e370b7dbbb5a22077ce22dd04a9ce479c10d11d5666bccd1fe632fb000000000000000000000000000000000b3cbf13819cc2f66fa5545e11d0bb330735f742e3801f5e54631f0369e3bc4727501f6a15edba2e2c1d1fd1ae3276f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005dc64798454e1aa7d68f7d9baaf9ba385e8951c4132571bfbdbf2a487803921fd9317f955e7916e535259738ce18e870000000000000000000000000000000005c28c8dc84c1d7b3eb0e29af53860fa91eee0c714a5d4e8de64d78465ca907360ed34d2b64be348c142ba112035e59e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8b0c897519bd76ede3e7c0f4ab79ea126d1d357533aba9f6c23f59824f78aaaefaf060016f6f5560bdc6dc5fb318010000000000000000000000000000000006794bda5513135cd855f6dffcc1a65bf47ececdd17dbdf6e0a1f3e06aecb2a97ba04e91662bb110b21739fb7be34ebd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099c8e51d1a4f7199b54e97ed61a7480b41ad27d5ab206e15ece4b5c7a987fe0471749999ad2c8a744816994d59f19200000000000000000000000000000000009e167a005678b7f292edc4731bb6670c43d0474072a20516d20b70ae81ad1fc3413582a968fc1db40a72d8578e2cd331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000facff84b66610d77f9b78bcfc57f4f61e46cbcaafe72922e7a1e873d633aba2efdab3bf4ee28889492198040a1aa68b0000000000000000000000000000000010ba41684014c1eea90d7abed012bbb7089b634d6723d9b8edfaef9cd6563d88fb8dc3b537a51b38e42cd7bea48a3a221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9f3cd92904b1309e7cb1317b8cf38911bfeb4aed1498708aaf23f397653d1fe05713739804152e114a916bf424d22d000000000000000000000000000000000fe7d99ea5ddb1be034b287aa2c8e4423c5dbcbbc7dbf4dca86ba62bd8d8397bc955c68273ab678cdb05ede3b286ac3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000201503d875067ee42d47dd9579885878c296836eb4ee2c38e5f73dd37d25cb78c42224352433e7c86746322d3562081000000000000000000000000000000000776a1c257f995761b0d7fc0285ede92007ef59845adc326f9bd5f768cc072dc5a2a90a458c5ee0655f1a889f93a0a561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102d6e00945c7bb47f49efe30c1293538a791f0dd8b072b2cc84aa5947bf6b45f0cdecb3f63160deea6aaa8daec136ae00000000000000000000000000000000015d35b59e1b9177b52414276a2bbf1467581cb889fbdc418ad7127597f7ede72cfe884b58797a22b798c85bac0ab0a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026dff238e4beb8a38a0069f24abf65fc9a4c186819577d67acb646c49c21941740c5c947d24ed5df325662acc30f972000000000000000000000000000000000828bfd7419679dceac17308942449122f17cc0b4f81deae5eb3525e96df376cd1259303602a1af03c26343424c71d691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000190201b688466c0cb8a17df1c911d9bdfc87c3587ab75f2841e21f394259d465e454e030727d7f3f026b32b10d4c28000000000000000000000000000000000aee0110214bd92791622bad2ccdbf3db6313d78a8b664e8b5eb375f13dfbb9972c366675f4bc983678df72a705845461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008be8f9ec9e6934d1d33f1f39245e9ca489499d6a75b87ced583424718685d75d48436da9efa52f62a2940f632a5bfd00000000000000000000000000000000017fb5c649143e926f03e481b769c16259523b6799d32a7a024e0a886b3467746db9d8fdbb653ce0d791d005ee3a2c8c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000155f74735b56df1977767a359aa72cc752e5d2509a36c03cf293be90b56dc0c06adc031869d3b8dccde550c2ea7a66d00000000000000000000000000000000000e2447157d6c989dcd9c1655740d4fef8101edddec11f9ce7f7360f9683705bb6fa93a18b8f55ed11300bb5fa3780221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001600caacef5548d43d540e4de69bf7410c25f1e82bba94aa26cf7a5c8e352d3194791f3a235dbbdf86ac2ee36220aa91000000000000000000000000000000000d16fd83c4036ba7b6ac2a4c6912e1f31770fe2016465c545e3d3efc5382714dcd592430697b88fa9b2ea886bd470f6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001481a31ad1ef049758736efc9455de4e3aba3c2bd2ed0ef029a594edc0329e8ce8fa8c011c0d033535f0b85de81dd634000000000000000000000000000000000de3aea61f123096618ce9bb27146d970b15221e3af62160a7cae9c2ba895a15b012ecbbb116a25a2d114c4843e748d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d646dead28b0d943b76ac13df588d9636e9dc4ffa98b246c59700235add17ea8d3e73b92ccfd34734c6a81b2fec56f00000000000000000000000000000000076cb837003c71b953ed3bb2382737fc48ca20b6662e1a86c26b6721a7880f62c9fe95834115b14d389d80eaa52efc801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018929d6fce2d5bb63b818c2599280bd1d3c88c6e5fed963687970ed51ba2f35b03a6eefb4504c2188da37696b4a3ad470000000000000000000000000000000011fd125043db4f53c2893bae9986f8eb4df977662f8e43c39413ca4e02d2e3063806a8e647008d1b4b98dacb68a1d0db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001214e7d85275fffc166c407c36e7136318c3b1354c394cd63cba451a13634ac4665db37f70126b595d7af0db6c3e86e20000000000000000000000000000000000fd57354bbe32061edead22368eb7a482560736865b56a1e8e9b4807d5fe67be7c26855e8b8f1b098407bd12b3519fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e3383a2c836964cf4cf1af0e1dd031a9add1699a52de7405da135b4daa2b245b92cd03ffab4bcdab438889a0143cf0000000000000000000000000000000000a47b9d94e3e6391f4ae43c890b0b376fa476840e9ace40b3521dc8aa28dcdce6aa9c4dc523311b6e783f4ba0be504fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c47320c9e5c0a24acc7a390ef285e6f8fc824dcc59b37911159eb710bbb1056b7245544099a4f15c0f45d4c2fa608e9000000000000000000000000000000000e65579a534e6439ffa92cc5db147a383713c99a1c8a4978ed1b23863657e99f417c35382aa959d4dbaab399a2882e591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d816bb18ff5c9134741e176858252250cf8ce0645a5968ad97b8ed887a2bd2b8c9baaf883213fce5bcd0252155d879000000000000000000000000000000000e068ee148faec0073fa4d0d9550d34b3bcc6fb1d1200d79ba83ef96432e443c149c0ce961d260cb295adfc7f333b1551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056c60dadfbcb37fbf6cccc9488993ee231ca3879ac286e9157157e785593b7c4b4b6bac35c12876155480b1ff087e5b000000000000000000000000000000001314e5da6ae7bb509c6fd653c6d7e188935ac1d144fc1ea470663223360a7fc981ded7290ffe5ffd175d7f1a9139fa2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d50f204e4712cd679b3d22df1daef11753c7a7176881206eba212d1c10986e6fba28b6805812dfe57795165d4c16b610000000000000000000000000000000011ac3d389adc7b5ef73dd685a31591bb2c5cd9337cfb89a04b40d1c91e1c3d13da9a6f759fc0066d159e0e720c096d811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d844baaf2c5845ae19bffcbac2b700266fbcfb05af7aae68413c486fadea5dbcb84a254669f8f28a2a96c816030655500000000000000000000000000000000048f871d8257ec42c66946dc1586e56cd7d484122dcd1eb8f80d57d18cbaea74af17cdca248ec2ede4a2715c555dbfe51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006333835480b27866874bb645e4edd96627cd3d3a1feb970cf1a0e322e653db5397fe51613d6f551ee7dfdf0e3e8b064000000000000000000000000000000000f427767fb9fa4caa1a40664f2826f11a903aaeb15d21d0ef3d43d4ed2542ab0a9ca9f906154e111e93d49a98514bde41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000240e4c915d9623039391c31698b67774b58bf5e66860a0a3de754bd619ac37c1baed781f4fa03b0706b2866b49c0a6400000000000000000000000000000000194f10c086e0c516d24a04cb9572a22ba6160bcc7e41fc463e8e5014c98b306991ca45062e99c5609e7f1f57d57ea8a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a98a3f2680e9fca1a339f4d6e3aba899b5928455077ea91460459204eb455c4ef30bc96345868a3f8fcc77b6d97f3d0000000000000000000000000000000009ce080aa2996c7e05250d2ad55b5ddc34473ab9835643cfac3c469385559e5f38aadac274a2318a6d908655525181641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001af04544270c96db2c69f66970f78c2df16310dabdec9669fb76a8fb6d77898d4c9e877878e54f1e071594bfc87a30000000000000000000000000000000000d17e6817bfb3d5219ddb6d321ff350c6895634ffb59e34c304311faf3a1baf193a7b2e28ce4027e9397d2e89159be8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d35fa8ceb4006f445a874eae9feb799de300d4804c41e9dac61fd548d9a2b9b17874a952fc2ed3e3c02a6c9bd3655180000000000000000000000000000000000ac704982d1fa04c0a1743f7c1291f32bbf7eb1543a4cbf020bd383f05da9ebfc7a5bfe4e8d84666389026d20d9c30e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c4a5c18e9579f40e71c9c7d14621c0eef45415886e859682dfc157b017d8ff95d26abb53ba6eb2473313da54bd19cb0000000000000000000000000000000012e4fd99b3b5716b2809a9b3472824fd3e97a899da85a815f18ba8c82a2dbbfe88be355430fc53abce874c3caa8a5aa41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000089f21496b764dfd698ce3217eabbbf9a52835f4175287c773e071dca489cd5e591cc3e12f2955dba614e2434ec3be930000000000000000000000000000000004b85b8101db1c0b9cad5db76b91b66a627ffa80eef895376c92feb33d932884fbbfaa92ce709b852bdc0aa198ee5ab51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b16f7b24ad10e7fcd563011dd0aaf91c65c807e24aae60e101f256c529c4a6f629795d77428a8151c335925159c4030000000000000000000000000000000019756b0edfa02a09845def99718820fa83884c738894f3966c185e876b2020265b072f4b6c03898a89f94112a210afe41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa0590cf2a5d251280aadc3696e333a5c78708f67b61e2242497862094c1bf81e935cadf77ef6bae9166c757b7bddc000000000000000000000000000000000092a33b018afdae7424d85d3751f223b9daa9bac43b0a39851a77489c57c1e473668423653d3f4ea361536ac54d8ceb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094ba3e7c34d34d089f152718943e611dd6d55f1b87515842ff1159755f54521ad44389706b1ba53a2dd1562b08cf7ef00000000000000000000000000000000142ce57e9546541366ce7105bc08f9aa3fba88c713488ddd9eeee1a01e42f43d21f77c4e78dbf214a1331bf85d7109881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031a0259782fc7858a1693cef18b1f0a417d331f276c09ee24c3a7bda56cec32e9cc928a9ad94dfe73d7c4fd7f880aa00000000000000000000000000000000009aa2f062bbde2a43719802a23681c93b8a30a1f6e831fa5031ed714cced335338d368d4cacf149a8218cf7a1bec7e6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a90b55d5b1ea865bff9a24fbe0b2784223af2ac89e650fee9089f6346bf8b68398fcdd65a3692cae226edff9d5d5be0000000000000000000000000000000002318b9ff0110d98075177c441af7cdb8685924d1d0016141502b6cb67235fd2ddd7a8778576eb21570b9d7400f6d2801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000790b91e65e8f72d54620a4a9909461db27a50c3d3c6a617ce012510396c3f5fc40dfcc39dc39b41f2bd4306a16f5b6a00000000000000000000000000000000089ae1065da7c181d410cda0ef8fd73a3eb4f93b18952ca9816819498e4523bd02b320917432de5c16c12cc62fb029261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012239cddf03e892e24cc685fb69ec606436499d89451bed33fbf5fcfde2346a0586bcd1f6d707d856efdd1373067fcd600000000000000000000000000000000030b03acb56905dc505e6a1fca8518c4abee498eec5ab6190a2914994aa43a8e7cae90289d78af17ff8e75e547b1e48c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f324fae49476c33145d1e5c7945b2e8ad1480d626238ce79483e041031b7a892234713b396df4cf9c331a2a433052900000000000000000000000000000000094d8615289244960b09f609bc326f6fa65e4df9f18627b9fafafe4e24b078fa068de9dbbe6b873e32987d7689397ee41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5efaacc23398c3bc7c94494b726605b4c6b50de59200e6fa336fd04d09a021952e27ca9bed41e5ef65e3bf7d485311000000000000000000000000000000000deab38e2665ccf482815f3d873c1cfd5a2ada6cd5242cbf8b63f60e2e132da79a6f4e75d52a22cb8e71fbb578a31be01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154bbdfdb9b004ce9d4aca1206616b788bab2e4fc34b2ec238d174d6b4625080f6ae62fc0eb074815ab611f6caf7ff690000000000000000000000000000000017e1892456b287dc447af8326f764a532eb9046f76f3f82779f30966e72cde734199d9cddf7271749659f8b2ec9016a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009903507237c5d0dbc2b9f449d02646e5036270bcfebfa4ea75baeadaca336c73cc2cbb316cbb13d75522807096da592000000000000000000000000000000000e28b6566f0191af4af5e00851aa32517a3b8d11e04135d1ae7f2e846be466d62d4f872f5dae6ec9c88d9050a3ced9161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d901a94f3ba007f50f6ad201f2e3fc987d59bd975af97e8445bdd97ece929e5c4caeb25e6e47263b4de4bdf2643be0b0000000000000000000000000000000001e8baa00a480e4fa4494b4eec0701d0f8a18b29c09c1e195db40c8a32ee3f4696d325138551a881172916463de66dcc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131f465d71e863f700c96bffbe7981b1a99cc36e6ef552d20702ab8d05a6159713ef524a3622a527778b751870a541ff000000000000000000000000000000000f4305e3c3bf73987d3a436f5865d254f41bc441ac9f981f4d4c99123247cba9ca25e574fae5e91c390a66b97e4dc1e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175df3d0490b6552bf3586d942d325e3409b536a178bf661d74b09b1b11528295c64b0e6108f972a498a1c7211972497000000000000000000000000000000000285d7d92c26cfcb6490463261441d80b2f7db507661f60c4f2fcfba5395a828fd4cb161caa4807a2324ec32d579695a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a337ef7c201af544735c98b476e399b3a8f8d7d24da93aa71c87ecd9159bec2a27250dbf7266a16070e04a65fc99af3000000000000000000000000000000000d4c907d884a60750a286bea5be8431b34dc2fd176247c454e512399b6619429c5954d0e2e37015f39210d9f34ad58ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3141418dc7c3d920b4632b0d2d130ce96447c23e33147873a0f09b966174ce87bb79693d6a9bcc6b244a94f6e08f2400000000000000000000000000000000009db9a9987602cefdaa31c4d989939416201c8108e3b2018fcb2a16b66f2c6467f58040b94e06d0ab887d9c43d440fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c31630dab0e0267be1e851d53879c25f9d88ac00af0d8f954f49fd9f7710811ef73d765b7dcd5a5f65c69db0e9af4680000000000000000000000000000000007f574e34136fa80d053ae54b09ac88174293ba4c11e2dfff0c2fbd71c629049fbe1ba2d5f273e7f54315e3a5f5379481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125583fdc8108e2fbcb99e7e552df1df1f4cc1391a199367d2d5bfb2f0e668c824e211dd870656069a4acb31f7db287100000000000000000000000000000000000e8c15c242d3b30898490e770cd234a06548b538641c1d6a833b8a78a246a8868ed63a345726c5029a7cc4684cab201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001060e5b2bc5f77f1eaf14eddcfd26a9308d13b301babe482fda07530015b1a3f8e4f40378e35e9d7089429c3681fed7800000000000000000000000000000000040019fabc6d8c43318f76fb0a86c5cb52c80d2353024028c0804d67bbd3d33eb1870647233f9e84e9b9239f5ca48e541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151ff39e48f25ddbe062ff19598bfdfb2822b7e95d6bd1da15692837fcc09187c70188aaeaf86321f6f2aff8f80ed15a000000000000000000000000000000001376c76e98c21c36edda629dd0e97a3fe7e4d4afe0290a4fba39b411f756dc5b29eb2923f624b5e28a69ca600548eb0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb951d73ac5738e7017c387608a414e7361b2856c8a1d7c31f1a8c8914ecd567e3d0b83114a74a84f28f0b42fb763e2000000000000000000000000000000000743e58183755d438540fec0de9bef9f59fd38d2fa8b63ae397991f76f9113f5d64571706a703124ac580e6960a2d50f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9f25ee7f403ec7c353362d82eb250b37d97c1e261d8ea93aa5d0357e7b89182c3f194f240e1eb3a55595c1808279e40000000000000000000000000000000009f6d611a8299d79c7b95256ec0c486049596696160264217f3c5bffcf510cd2bf9732c4a45daa4b989576c04c6b59211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b0e4bbb5cd184f068cbe77d39bb5ebf6ccfd9ff3005ce2dbc0c97650179beb6757952c17d54e9a56a77f4eab6f970f000000000000000000000000000000000c871aa76217ea83a9cae63fbbe08b82ea2fbbdcb3dd182dd397f25c683e58ae3decdaf0ec30d77fc21e3014608cfdb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079d34ab1059ece3caaeeb1931834221f0d09e9d92003bf7d3f2827e2c1cbaa1c14f59eab12ff64cab4e3e376c3bba2e0000000000000000000000000000000011b1087ad170c12615c61ea76052ceac6fb6e7ceaacce91519975d564e26ef31b8af1a4b423920cafa187df4e0a4d3811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d19a1ca365a0c41c0d2c7bce87479ed493502413eea3b723c5563dd457a9fe3e9b30fd32da7b6e243b828243365fa800000000000000000000000000000000091bbe83570387ee0090988814277a3141afceeb7a22ebf868297d1f6ead99f6e4ce4b4c14f722254917a0941a753ae11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f7868b12ce590b753053ca5ab698e3bb46b881668fcf5256e676985c0251d645937b124f78b1c6d60012f85e2b57210000000000000000000000000000000018e156282bf224311a9cb5c37f5b473489a985996a2c234ace771cc953de48174119ce057d3716299969baca362305241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014bdeb9bf087b5f0d8b0d637d6688f30d9ecf45f2a44fa723cb2080989bb50049a9efa5d03d27bae2bb2ef55784d246b000000000000000000000000000000001629db3d95e96e79ee2daae6466c1bacfc7dacc8142f9006c44c8cb38c07b43847615cc96594e1ede4df6f3497a442be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061e486c3e706f7b661ff29e10086df6ed632c1922f35e6507f84658041230b2547335f3683a66f658b72aa683dc9acc000000000000000000000000000000000e09c23d4e9a4a80d6888ec63df61dd4eb28b0274d2da0ba6b54a958cc1429175ee82c5894247262e78e839f2a720a251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000006ea7fb918f8a472f6581b53d78a3474fa2c5ffc3871db3ef30c5f197c5d914b8243293b8d4b010e7e6c0e0ee6fa5670000000000000000000000000000000018be0b8edd63228e5ef968d6f65e63a0aa5b588231e9991fdb61ef429443c57b3a1e3a6d430ad61aab48a08e5a9ca27e", + "Name": "g1msm-512-jwasinger", + "Gas": 1069056, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000113432aee77ba2a2cce46320b0e6b6ea7f1e72d5089189ee383fc282ee68e121464014f2d8cc1ce9589e4681d84389e9000000000000000000000000000000000b77a1adcbd5037e3cd58e0ecaa34fdc5fce2f9cbedaf7842ce88feb585e93f0f44a0c008dd61b97c2de3fceb7e702621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019365a84f7f18cb1f77621838b3fbe27f988954d10b4761b6f7b70fcd97c4044423dd2dcebc4de2e310fe6e0f9ac53590000000000000000000000000000000000098c84ae8985cc5a3b7abc99330028832694f98a7a1be3e20a39471c20b6b956537fbea455f710067ba2adf4fc70db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc2cadb6838504a5f72728d36344461e9c750bbaa5cdec43b4e0cc8357e1b59d5c14096169fbaf73a810a9b5195f4550000000000000000000000000000000010896fbb1229fcb031bc75710f543a108065a58d44c136f7d8d948b9c2b6d3726f1823d16d6263b2df8ea8277d511c8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044561988e8841270f2507a7df77cea2c297400c2fc5d62f589312e9bbb62051a2e7370a5d1e19f114ff4b8c6b9c2f8c00000000000000000000000000000000147510462aecae094f843673231cd3100a2773103c7d295986414b7b8972ccbc4a6de2fc63b47e3749c1c514f57a474e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a3fc99f05b8c637e291a664d62e6144cae845146cbbb9771bf3cd542c2dc2e9a118cf06bf3342e3aef1edd17c4c372000000000000000000000000000000000ee1b77b299a4e94f11da54949508de1db2e6255ac1a66712b8cdba1e85b5ee03a9d471afa089c027333b5f5805ca0631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143f9bccd959d294e7c216fd8a036fab7eff35f28bf07d71c7f54d43adc3418ce79223e481a6d1f972fbcff544308d8e0000000000000000000000000000000011f92a6ee225f73eaf8ba36c11d622e87faa14a8a90f56106b92e9a62fbfd45759fda7085b565b12e0b8237d0cd5aa4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c0ef9097e37f2a86731f7c5911ed15039eabd8c27e1d6a64d87a70999c349eec724e13c32cc42578258e0655030f720000000000000000000000000000000007f0a5c7609ff876553752f61451c347a654fd8b031d2850454882c8fa0d7150843310317474ab276ae26e4ff98971501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191fcb881bf42e69891d5ebcaa31c2a3bf5be434aab60d9bc5054c636f94952c78a7a0c11f24c6f81f80818cf008c8ab00000000000000000000000000000000141ecbf1443a22a2f84ef25af0c86b94ea22421813f2611fc3b10d9dbee81f02be6035e6bfe6a584260544ffc5c87eb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019481f27232878f7fe934b5ddcb8dcbee6f8188ce95d239016b757e105558f8c2e5544aa2cff848679f51b4963fdab030000000000000000000000000000000012c08ecf9f478bb1bf8ddf2c604dddbc42ad64d38fc7929e0444e9bab55784a3e7ac10bd3243a42b107f1dc6727326841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008bcb0e19234cea0c962c31262ed250edf012078bb7239ee2013343a20291465d1e07edf6147660b9438bc67e3fdb808000000000000000000000000000000001694f48838c54e757ffad3cdda14bcdeab8bc262519b66519e0837c5e096985f4de3df7a96b106a9409323fa353d50da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013459fe4bec1150486ab637852e20167b2710237a68cae58d55e05576754d6f24826e6cb70c13bf1bbeb9475f0d724fc0000000000000000000000000000000010e6e256393e308886084f0dafb8aaf62c66a8a047a1988b0cea32da87ff54de090e437ff401928b70d21f6e24e0cdfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084b0283a379c20cb86b5f16a19ecd988d073399a6bd079fce82286084b19f28007b78774be69f2a1bf9e25746b5041a00000000000000000000000000000000066a1eea5139937ae5370c2c2507622bc68f7f8e4caa516a77affe736ef8be22f319d9f37cdb999836e22b01fefcae761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010e858a7463c73d1c1459306d0bfae15d798ab6f84cfa69a2631011b7e54d1381ad5cd59e5e9bb21129233258a4e3480000000000000000000000000000000012803cafa2fea7989674d1b9565846ca506112b1a30245f653110ead0f786c9d5f8cf81e7415fb76b4419a08bae40a131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a25429ffa555112ee05a9ff02fff3ca4ea6aa23c22860a3c6892bad0dabab19fc024d2eca336a634529f381ced696f00000000000000000000000000000000083504d5a4e30bf78edcb43efecbf27b4e1825975108f2358634d34b87826c977d5e237bfbd88a7e329efd616ccc386c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000444ff3d3a8059f826623fcf31708ebeba63213568c01cfc5d84c6671d0c1849ef0eddfdc10b84d8f9c92c3ef111a21c000000000000000000000000000000000870a8448d00a3522bae6258e56fcce0a860268cb1a1b4287274c5ce1c46df3cdeb247aa26e9a02ff06f1a78df62a1161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c410231302d2c3fdb6149435322991e113e5e3a35f00418c9c42856cc4334759310476340723e65e41d244b06caa4ea0000000000000000000000000000000003ac8d2af96ce1892e0309ea65ea28dc9080a28048202023e2a1068ae6f77050d10a8e2603a5cad03535dc50162d201b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d93d50d94a9ed3a0df2798d380d726bf0215db6594187626d56f793debd40bb89bb8ec3016be41f4550d3d6f9f982b0000000000000000000000000000000014c63ce8c29eaca6fdd5d2118c741137ab4c3f210460dda3ee7d47025ed041b9857b5bd054d9bab131fbc95bd334be821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bdae65e2cd1ebc8baf215c47eed76ad0e2aa6a3ade22ec8e5576a66cc07d0d95db9b0677fb3d4a4f91e8e491c90cca00000000000000000000000000000000135a9a76d97c9ae1de332044ab9b136ad9d432a37f8ec6b3308fec708afe22d6cee3c6cbdd5b82f9ab9b3ec787b697711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5929dd20f1880ddf606baa8dbde4906e382d12cadb4b04ce8adc06cf2d983cb7491acdcc33414c5f1f26b508d3429f00000000000000000000000000000000035888738296f8fce34181526f2235add4d54942b0c6373fbaef9384cfdd3385d5227862e023d29fb571c2eefe0f5db01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017aec438a6e711bf8c2b38a668f67a6de03c75fedba39576ef5a148cf9e3066717ef402f8cc0b9cce2296e866d59c570000000000000000000000000000000007ed2fc97feec8a3cb20515bf18e1082cd425f2ad0a56a24ecc06f030479b82293a3a12e7c4f8aab615c1f8ba08ca39a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011fe02fb54cdfed3c73f51b4c7936a82421d3d28cec40c647b0ec2388abfd917a7fa98d686acc128e1b9a8f61c84077d00000000000000000000000000000000088be45e91eb084b6c04bca12f27b58a21f5fa79955bc8ecec16f2f63d76abf1be188640614dd56cbaf2d7d96ecc8f061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf7453ab6722bcfa9b7888785283c2f1316dccad68a3a36fd6f6dabfc984b03da4a27df36101052c54bf9f45ceb59ff000000000000000000000000000000001473e2050368bff88f1393a8f85e91e29b705045f73eada886149c1321d907c3cab9d16e6ce62eb9d0dfb06a3cf5f3df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055c06d09464ca260b636297b2a10ac9a51abe2a3eb31a534d0d98f7acd5b9ea6fcc825e9507cc3845d94728d0668c3f00000000000000000000000000000000129ed1aa5219dfc87fcb406c7a8bef68878a718f32b150ac63e9e376d5f5fd93f53ed7e9d59e1963e00695523eab47661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001183182fc93c8593605a39eb4c386d27ab3e0421d092745e2721f3b63a639cd5f339a53135179441760189105b2d9a92000000000000000000000000000000000d7ed44b0fcf1bf597d90c248888cbb8bc18379a8839c1dd8c6ac2c6546ce92a9a9a0f2b178202bb3efda39547ce21bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4f122d6c3d10379f3c218e3e2dde647906d7a6c59b6521a368de00739cba713dddf859d10bf2b50c297799f86956b400000000000000000000000000000000086f9d93d7e92e57ca74f63f9e0bc03e21d1db120c59461e945655e3aba0b40b878dcf20163da835647be19911ecaa781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164b21e192894e4fed3ec6ce32d1c88e67dc0de7469b2e0858242320c3961559ce9d1374da0f949a62a68e356a63d63e0000000000000000000000000000000005e40ecf59ad7f944cb4da0c032c431978c15b06f31667cbc84003b6120b4055952347ec829fbc1346b194cdfbb28f771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fbac2f436836474a126878b311b14d890d97dc5d652e9abed79149145b9a1000e574eb55508c85d8dd92fc853721d0e000000000000000000000000000000000000be9e25489d986d674a0b670bfb0aead1c2434142025c86fad81d61e8ab31e68b97cb43e980e3ad6cf9c9f1ed2d091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001fdcb157d80318b592e0648cee81f665de61c6bad4d95e6715d8d47e8f5af8f9d934b114a49182b8a89a0a2220481c7000000000000000000000000000000000bfad6466fc3412296cfd923d7855459a28f6216e18a2b04887b5402456d6a45fa6cc6d2a0f5c990499e9fa2f542b4201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006343b246eb41b2025529103a01fed93b3166fab4a8e443651d0bf5e5bbb76b918aef6b462c20a2a9bf209db2a3029a3000000000000000000000000000000000913538ed2dc347af51cb5ca9d38503dc8a61af0dfda6c6b10915c1a6b71e6b877e78a9c4504e0a8abd92eed45a4f84c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140d8df747c9a38f2ab269a09a98f574db42aad68829038e0e6d68084bbdd5bef03416e62cf6a83cef6763f3923d554c0000000000000000000000000000000010897cf20a0a2265f3c6f2b46a209d9392c99e239751840cff7401139770cf79a316a26667694d044e8f56f3aab1f1761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000104f01786601a06fa2e6ab9b5521345da3affdf308f0700eb3417e68ebd0f470498c897f8bc7dd4865cf462dc8a2782600000000000000000000000000000000157085425016e8a44d2d4dd6690bd51609c7487667938aef9e2467b08b83be4b4337700bae58056563b739ab20aea43b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018e8ebc052123fb4c2be29c93d1840eb76d99e24950765860a2a55ef0e91b510cafbb09fc23e899f3abe969869ce20e0000000000000000000000000000000019bed2558f66055a42a9a4d4b8cebaf08b528b4eb07024d1c23d93785e36603cfb398a7bee9b9685b6c7a6af3e5d07961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a98a69c0ec3c50f679ed1a9e2fde094bc4b7ac1ab127d476c27e93ebe4b3f7b772c568b1c6ca112d37b11296fe42980000000000000000000000000000000002bfb6e4f34be8c0d56285583f4ebc50ffe1105ab3d30f5b7eded8b6f7c6bbd239a65544a189f023f37487303d6627711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181165c202d0ade64c98b1fde43221ceb988f360c4d3fc1a507786e9eab4bfa79dc2924fd8bf178b19ed7b6ea5432cc600000000000000000000000000000000189df594b88f707ee4f1412a816aaf71b15fc82fbfbdd282360fcc3aef1e76a71b82237552bc68a36bb67f869eafc6421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177a1edce370c8378fc34354383edd33764fa82f4f83d1f3a03aeebfa34fed482fa7bd6f2de0b208746d12fb7d02b2a6000000000000000000000000000000000d7784702b4e48629c14770b1b2dc2a22b61b65d1abd088210e5d2044cbe1fbdbfa60f241611f4cde3d669b65f166a0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154d45698f34f675ac31e0b1cee2def586c59504de43a132a859c50454ab3bbc7f030cefbc06b0528c60a3b72b7e14b200000000000000000000000000000000185c4756f344083a8bebe9e418584e4e642f6f16899c4cffa1bdbf1ee8e325fd48931c43e5c76e407912c110c1a5aa7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8f6902408cee5588c0a4d930c1a7a5c6b7f958857c354941dc2b6e74b1b173ee92345f8279cf901c6623f9279c0aec0000000000000000000000000000000007daff042757839d806e3eb43bb56bccd6ddfded58b0f7e52a9c31547e03a0f3f813c77411b235359a6ca4183d964ea51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfe22b9dad98c514fea304fab0401c0b9fddc0b3bf1ce41cf14f6d50e33c723f5b343743249c3a9cc90753c823f9753000000000000000000000000000000000dbbb8f68acd384127897b4dfea0e609175d82745d0a1680d3b1805047a6f2b404fabf29fd471144c3b73cfc403c19061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022427f2eb79cd3ab6f2ae8451d3e923e8c27c9650d78b94dd04ec634b72465e779730df9ccef798d4a72b6172fbc06d00000000000000000000000000000000155ea660501bb5bb86a4a3b68392f1acc89b5f0fe2a04356432476bcde758e6318c471f08c5a7cb0837be655cdca3ef81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab6d2a9771d036da214582c737ce30bb695de0c24a512bb24abb52f25637f086a7933589b40de0121552ec066c92a1f00000000000000000000000000000000008762f9d1e83834db8aaf7e267389dcd7fb5c70c9485e306a162a58cd6571224f234e7c1d7003f9ff42773f6dfd72621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bddfc8a21a151c6eba652a098fc5abdd1f81b7e707b95d3ec8d8eb57edb7399671333f6742adb17e314ccf8311503370000000000000000000000000000000007888d52c6c8c847a4b81e2fd49593149b1ba0f4ee23accd4caeba8ecaa4095a1eb3a61fa17bc50c545bebcf77009ebf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e3847cfa6ad889c68c1c09f1ba6a1631e16d92f4457ae2d062f539745cbd8a7a3bcdd80395a4d91dc9967b8c8996060000000000000000000000000000000005040517ef8fc9e4a10343443ca1cddf895a00414b727e2fa032400cd9180b80dcc10d9622ecb76107c19c2555a685c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a08b9d581e8f1d64d2007926baf9212201d2ac9c8fd0be47f995a3506cc9b0e735d5ac40ce3dc774fe1b2718bc7d7dd000000000000000000000000000000000b49b3a823b9cb729509296121d99255e96da30f07857dfad0b99937c8743b1bb9261e0d03a89023cc0bfecc8192fd571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a40653b3a13f5787970933ee2ed85c24999dcb8b6bed5f6bf593a7709c84a71a0d5ac6690258ec1c47351648da58b9000000000000000000000000000000000c6c002db3d832c376a332a7624d7f2e69c718e16edb69e177560914ca42cdd3068123d92176d161f039f7b007ba05341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce4e524e1b89f6dd89488a847db170fbb0bb71c12f4198dea1d9e2254bd6f62393e12d358f0abdf4815b35b831eb5aa00000000000000000000000000000000052cf89e2dabaf87205c0b79f05d0ad6c206d62ebefcc773abd6a2fbd30ef01d7c8e190c54c1d2996173dc64598fa1ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011b694d5a6149aa513d1aa60fb0abb78fd70ddcd83ca903a424435228f7388d96eeaccc4f7be48c770f3d9ddd2bb454d000000000000000000000000000000001956dbd36f98408bc3f2f8ce8ba4397ed636b6acb34db868d8bdb65c1bc32e5f3f2ca92f687c400741d2ee0ac1fde1ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f20e939e331a538910f8a17ea8ee13fa92a2936dac48803d076888ea12d19faee92f7a32ac26aba3229e4aa567f0c50000000000000000000000000000000015fd09c6c9084d2e8480ae8be516b77f4ed2158980851717adcd24bf5f907bcc4ce9f7fc0a6a5e087444fd1c1342b30e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d3c5159c715f8eac9e65dcb0f178900b6bad14e1e944d86268de2e043ecbcfa807a8912620a7e7c423635d93d458d200000000000000000000000000000000072243dab541568ef69bd010ddefe90791af082efc2172c9e43b378f330ea17c817397fb6f98ee6607a17da9d41c0afb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093df04313fd1290d6722e992c00cb5138337270f34c3351a486a4d666233744e2733d8614b7c95dc6938b9001fac32c000000000000000000000000000000000db734a72cd9bcba0d279cb583c521f74dfdc2744708e9910f0f63b3b17f9683cfa8451dba782e350c9557a0676573501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015445ba4fb83941f77be59e0417dd2410b0b9e224e43fd26f043ad2df77a5734e8f5488f0c4548c572b697cba74622d00000000000000000000000000000000014c5050bee65ef4748c465cf01b8b508bd41177330b8ab9ed17b07675f3f3b43a18de0e9f896d17352d7df5cd75be8481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015af83c28bc60242354dc3baa0a79bb1c371d2d494b800be7cad45e86b0461e4b60115e9f623b64da8e613980e222f31000000000000000000000000000000000021c0a80a5dc0c4fea6b1b91fec9ed43415e46d857f1d888c9807a2d535430cfba8de69f447490763877204022cf54d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184eecbda7e39c7859dbba6dc1e9e3e8f87f03c34bb9fbb621f5e92c23d2b0238fc2dfda8a4a1ea615eb78ff86db6af400000000000000000000000000000000113bd9a35f542f0b7ecce296de411d64e04a38759043b9df839bface16e1f0f42338d2591a540649b0b4f5bebf56dc4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000605ecfd75f47c629a38ecabfe4ecc2db77d0ecb9acd4a9ba1b7048af28c3db85eff2dee65aaeec6fb29b9a204cf4e94000000000000000000000000000000001482315d581689fac95b8351fa06e8f2b1cd59cb6b0b563b688c622af938a7cece02e74044298f60c605a430960756ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012240b484e38b76bd60b94a10be77ffbde50dd4fbe7150557124b47bb68286fba69de663cbf3467aa84675b0d486263a00000000000000000000000000000000172695581329d3567fee2e2288108d70ee0b5bec850a737fb00e9c557564542de9cf35255770bed75331991007f92b4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f210c70c40d79c0d8184c721a1ade9844ad4494425bc3c1b02d8c968dd234e21ef29bbf36f630506934ba3e93409df00000000000000000000000000000000010c9218dc264a26807ee3493eb8370e5d7efb2866b964088db496900979d3df359099b1e36f6b8afa3e2c1d26e07383a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008eeffbc6b3a06c83e21feb005de9e5ba92bd26e0fc1c8e2f7369b77bc494a0af34e751f8ee4abea5c506d141c7c6ff0000000000000000000000000000000000c75e42c02863a339c9220915a34dc2ca2d896943726c84698272ca902707e4a6dc2020d172ce7e5eb1c892b4b0b22c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000bd10978f04a6adb74695422f343275ecf332974621989a359505d62537b912af08cdcd63bcda23585102c6108f8052000000000000000000000000000000001292a95520a356c23052dacf5e1373a9be815ad997000178eb6eef7788e283ffcd9c320b8a4fd5b3148335b2be5fed641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001185aea3296220a9ceb68269091ae746eac8558789c0ad155639c18c8463ed6fc085d1f5b21974e6ead398ac16145c780000000000000000000000000000000013527ae006b2fbccc4113802d7f22efbe50d50c6d528a5b99e87186f05f86c5c17b85a747a579c80cfc5a5a94147dbe11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079f54abcb22678de04f2239c38b88f96493628648f76bfd3fea2161cc3536b426facedaa35ac353eb486e7c273f97e4000000000000000000000000000000001664209d8878c122e7c02db123d11b51af9d053a36c42a98ac755c50829c3039885da926d5207d5b18b4aa08bd3516501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d35674c08b74967e1e2854034457da8a2f1be3f7da40dfdfa3ee80588d69abb7bd793d49489a65e92a95ee945f7000e000000000000000000000000000000000141322e0aa7557235a45e230f8a28daefb12674a7eb7dbb2c7bbee8ccd95fa447d4e3fb7a6be6e25f31b0a28f71c72d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000be8e10b614cd9be2a7db8175aff0eddd4f28286e5d849298b8a48c33dd877dff61bbd2d5ad2d0c9edfa765059a8bd5000000000000000000000000000000000f002dcb7ffa031aef5dbd5e266725e5e2403fdda2f80b08d30aca2709c8c8dd43207ffb18cb046feb793a4a650cd9c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000196d6359f304311747b27f7280bf90c5d531979a568bbfe3b5ab5320911472c60ee102e9cac69961a5f45815d781a48f0000000000000000000000000000000005f672d6f95db206093ff62db1bda0b6328837e908d809e687e3a3e19eb09f2cf833ea6b5702cdea4d1ba8cb89ddb6451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001562c20fd6700d55db0d4acf937e559e1d8e9bec5e614feded03fdaefa3047c4be5fcf0ac69cf3648b2106b10677d48900000000000000000000000000000000086ea0df6f5e8834455806e7ce2cb30e748fb2f69cb0094b7aff152f55d81ca8b5fd0d4efe94dc4da9ce9b73d97b4d661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fef2f1f685f6421e706b14d682650dcd23472216da2c666aaedf818d32d08cc6e4bbbf3e9005e00b4b76f9da8ba4df20000000000000000000000000000000002b6dcbed3a686ea536ce33f8e0e197cbc9178eb16bdb69d817a1e18a60524e725aa5c94b6eca4be726830627a0f75591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008915dc5dd3201dda1c54caccc8613a5bf9f6e905cdf8b0db6058567227d8062d357abf7efc219e70eed2237676deea5000000000000000000000000000000000bf05246d535971006f72cbdf9160150a7fc10d65d92c4e5214e818d3cd5e338f6d284b53f09da5e18f3fd0f3eec201b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001499a1182247b508c7cf165ab5311ef642aa661428ec0519ec5eb716b7da5e1b4c0f37e95af75734ad310c3cec7d89ef00000000000000000000000000000000114c1b503c5bcb7e85eb1d7aa6a32864762a0c5802687d954c9557d87c706f761648f483aebd324bf621f3fba09632001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c87e933975b84c5580ae94372fb4a43c908fe00c8b30ba04eec29c1099a8e273a6faa2b3df098ea5a0a2b1dd05f545000000000000000000000000000000000a6dcfbf00e0c0fe0e9801da72f5226886b0795312c30fb3a943a5f3c3299f536ab412b900fa2d60b757e7bdd601b09f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7e49b90d0da39fa012fc70345e0c7ef85af8fb5e9e1aeccb7e4af03f2d2717fc43935252fbb7a64d77ef727d33ba280000000000000000000000000000000018a20334a63f2b30461c8bfd565c38de0c960747971df349d6b5ffc91aa57685066ffa32f7e162788391f6c274b663ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008c886e44e41bd6c10226622080e9053b6a3770ce7be613686f2066c0f5f1395462ae8bd8f11f3a47a22ba5edf642e8000000000000000000000000000000001260c94683391227bfdc2bdac233bb1d839a4068608560b793b9b3d91ce5c7e96a589f8d9ca4ab57ca25a67a6a308bf01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dc64a86195da7e8e8712a4f0c7f57d77a70d7c3fbba01c8566503f7d15ab739e2a789d3260e2e384e8b7d125ecd549000000000000000000000000000000000421aad94c5f2b46b862c776670b670b4086339e31b08500a8bd7d06fa9965f1cc604feee092a2652a96e7a164c856b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bdb6dd88e0ba4988caa2cb606c9b1e6e98344d805ff5fb4b0014616bb4fe2c0d84f34f9064c9ec971a86103aeae90e0000000000000000000000000000000004c6fce550949da34fb8c104cc89f24ee6bbdf3004a4cec1a3ce58b055da7113ffadd70656bd89ef703652306de51bf21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008344155b08fecbdec477d3bb7f83979057cc5c7dc8aa53a3399398fba15ff5601eb1ffc8a31bd1f8049244b033bc750000000000000000000000000000000000b9fe09e19e8719944a3dbd1aad6d11cd924167767c1c9315a1dfa55dc6600ef7c1b6b9db20553cb123774e12345a80f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008ecd8a2b42735d33152aa4c5c11d4d70b56f3bc0cb1555eb4f7697d8ea9c5f8438547c9981dbd87d20e4a21036cbab000000000000000000000000000000001317f8236c13d28ac0e206f4eec23f90c357f7c5ff180ca4b798c8847363ffee3ff9f840603f274eab38fedcc276801a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116977d08deab67c359b70ecf87b407201032b592ce240e9ab103fa3730ef17bb61efc001773ed79f037e0b87e58d17d000000000000000000000000000000000878d259403fb0d999f6d20c2e78d3b1568731796349d7ec0a594c8ff1578ca645e4d93c565979337a58c4a917bca5631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117abd010a56a8aad7f6280008984b524ac6752e8028a4fcb7d5430445f73c11e6dc9a33bd81ce01ba781df85854b06300000000000000000000000000000000105e85b8620528f679109518e41db3235cad73c09f471adb3ffdde641ce6e17a59c9ef26bd656e915f82712c2c001f361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a32e87394abf7b7458bc9f70f64374be673c4008f37147c5526b4597fcb5bca5e5492c13b4599e31a5a3da459e95950000000000000000000000000000000016c8bf3f7cbe1e92aefc8f92f18e62d8617d2d3c49991b5ce2766cd9d76a4c2a5fea1d14a7e6e8b6873a52958624b72c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022694132a2da8e095339a2013fc6901f0d7dfb9ae6dbdb10ce229648c74767bf327ef10f8fe9c07b5479451a22e7d8c00000000000000000000000000000000049702b8cfbf1c6709f49e32c88fbaf2f43c293bbb0052ce0c84cf5aaca448c43083d8f36bc00595fa244ef9d21dc6ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb3e0b3288ece732354a4466e8c0e754dbc266fda9a48c21022ac2666b64fc8cf2d34fb21ae5fc025aa2f80302f93d5000000000000000000000000000000000ce933426c03433b3610bdc3bb587b5ee7b76ae3ed7bf6d657560a0063e0c59682bb0337b627680aec5e93c9f053928c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001257f5e39eb0b6c5360fbdd9310fe5729aa1ab13c294bfc328d8b7841dd56d3dd64ce0e7dd399a0fa7b91fcf660ae864000000000000000000000000000000000361262ebb12e109e6df9f0cd5c1af780e4f0312afe430c129c30bdfd66531e85556fa20000b87c112766e67a7ab27e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001165cf72c679bece8569f396986fd404994bf7ff53a0e6d1d74bcb6b41f552df77ed03cca215da239c90c79b1ce0adac0000000000000000000000000000000001269f0fec516ab43406124d602848f248e4c5331373e4917fb4e0f26da3c882092012a3df63199525962956255c539d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001544727d3e43974c18d9af31eed8c7d63a122d4bf6b1c23183b0a2654ff858f4b2660da0c2c47296644d9bf7a83a6e9b000000000000000000000000000000000ff01a6ad1f7900f0d0fbe75742b7688eebd4c85c7739cb7bd12ca5f6ec57168b7764b5dd0043591ab919e19b64601281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bd5845872dd61b9a7a316e041994e7324d1f6fe3461f2050c310a47422f156c9986a4cb2fdef3d358a776648ac9d6b000000000000000000000000000000000f7ca1d07bf33f980aaa4909b655d31f4b5ff5eb47a44c21ac68cd08f8d161cdf15cbfc5c3133232587f5f54f37034b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001478c800c5cee2c9ab44b5d19692e8190d52da3810fd1b47d468cfa7791c182fcd0a015c224b1e17ab969238be5c583100000000000000000000000000000000113abbad4a2f36132c12ae591822f1a73db6cf25f5ab6c57d6d512066bc3806d98454f402ab52ecc644b642dcac69b621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a29b9fecdaf1e48febe612de51145fe781e1b2b2eed789063fac100c39d6a6d096e8e27fe24b5d3ddab657349826496000000000000000000000000000000001673920727133074499441f8770e82b96a7a0749bcfda944252df4b603829eb5f3b2c93f3ca3ff14660a5a137646b6141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a3b618640c6d2a1d516d542dacdcb7db327ad6cbb41bca7b665a5cbb4994858ac56ee78a0c8ced274e5c6aa3b6eea5000000000000000000000000000000000639b3d87568535dff6312b1169dbb2169b16b99a4008002c145200cc384c1dbf996abb4bfc71e36920d571bcfc08ede1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000678889302af0e4bed48df91d0a7770f298cd9fcd215ee2fb52da359b140438c8def6765349b006f879a633a12de5f300000000000000000000000000000000012ec8cfa008747745e883cdffdc1a1d91c828612c6216c92327967c0df663c99d9b756846dd44a55034f37d32be8e8081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bfa7120f6be86d48d1f82639ce83f3b8cd1e71114102fe9221558e08756a531f969dde5a9fabbb5b78f67a0c652bccf000000000000000000000000000000000d8b59f918abb02b037dba2c59ec48a0ad46729a91c81529b8f2390a7fca8ba67e20874debfd6f86d66a7d748bbd94241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001942d7c60646b7623314a86355cc52a2d4b72a4def9f397a99b5febaee2eea99d6fa7c60d1fd76707eba09a09a48fe63000000000000000000000000000000000aa2ea821df89ee7ba8b490c047386ca995caa2ea201b18c14ab9fc5d174b0d7ebc3b41f950af1c64439424b5f0667af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c9d3923ca8e139254fdf62255ae21159b59452db864855eb0138fe758e904f17f94a19e860df8a96ce167bf1342094000000000000000000000000000000001893a2854dfc30db00204e70fd63b1646b83d0cfd720c3b3a404761af5017de0487faaeab6d8bc8023a5bcbd96440a231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a7fec282b395dfcaac44dbed3a2534ec3686c81d755477af8adc7bb479d27c8066dab16ce0ae6ac2921229f16e4366000000000000000000000000000000001937728fa858ca5e8e7567c1907bc264907700f0b13aa1b491133d5a8a265b35bfa3bdbdadc2f1ad32e6029551565c2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d253a6258190bb98a76cb607420d18911ce90c3b923b57805921a96eac0d3b3b1ac736a73182d86e181b6142426b110000000000000000000000000000000008f11dc67689b83bc842002ef9f8157ad55a60012a5e50073751450236570f729ef3a21af881a3a39f8fdd5985aa38511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d64520da7370ef20cfc5d34e9de86622b94c203f712c5eab878ec29d88d75fe913cb81eafaec739aa61ab4c705402f60000000000000000000000000000000004725881b121f87270593873d8e5db53a69f38c10f2756d8ca284b803274981670994d24613649ef2f7301291b90cb131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e31638c6795a18435328771a8864e9cc45d35ab9c34e5538d9856bac392c082fc8480af6573eb8c11d451e6e999bc1200000000000000000000000000000000162f9055f0a8594af1b6b4fed3a7ae893936ec1a5ac31679434a6fc724b62e8a7611d352f5da1bc8adadf89d3b26053f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d56ef89cde69dde26d3855b57825c71c6b15e777bef338a009a54411953410b348ae10c26348fe58d67fd903419a8e0000000000000000000000000000000000030ad2c93a64295e83dfad68e46b42bef5720b2bd37bebbb753fe23eb44b15717f23f11bbce3be62272120b03e95b831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100796a5acc9ea29b98914bde8fbc092afe381df3e2a5303f52a82d2e341d60198b82cd058e3dc9c6460d34a217f190b00000000000000000000000000000000163e9b84bf66803994aa89125b625ca132316a47a447b090c82b2e01cec33f932db497b6d05976274f10c6ab79bc6bf71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124cbd4f1d8096c3a68edc266e859175c6a64d160eebbf16970b1e7d20df90b177bc72271ce61b656a2c1a923277bff90000000000000000000000000000000014d21a86532310dcc3baa2b4e29dd112c176fa8fc5bbd0bf44caeea6d5bc743aeecc158d323cca444ffb4d4d3a0d84811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150f5b302f8cc66868388b7125ef253a29d356c470b2dcae43617165a1c94e4a0fc15c933f9c84d647024a343cf21e98000000000000000000000000000000001628ad346579f572456a6d18f4deb860fe157b8cd991913777979ecaf880ed24092fbd3e74ffde5efe5ceebabc8389ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000087048195b3034d172f80216bc932267132a7a2e3ff779a91c37151cfc76a068d134f3acb35166423986f9615a4089b9000000000000000000000000000000000074b8a9137fa3cf060d5d812464f37715b977358648b16e4d81f6c4b0d4a91735c144578c0aab1c7726ae2c73c1d2301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c50ba3070753f5978ba0f776699c2e77ccdf30d52adab21c4275c60d6a63749b064423a8bd4e16d73eb143f4655404e000000000000000000000000000000000091249ebb6e00e85ea707c183a703c8c00cdcc0e4ba64acc0b0ed2d3d205ee345b2b6dd5afc3d8448220953779d28c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015355f6e366d86a968481d7c45e2a8ad3f7da657d8bf6460aeda25d4f39444a77aa5749543200b511e833f76ea6876ae0000000000000000000000000000000005ff1d833326d951a961ea01bd075506c695bfe76ee1f14d027424a5d36ba401f77a8c4222a92a78559dffb6c37111f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017bd0cb9f23b21cc4d15d23ef10c70aeb1d0f2718fbae3dce33cf1f66cb1058edbda151b5db5ac9a852d706d2a54db9100000000000000000000000000000000019ecc080f51a4beb30fce7d42c2d1ee9d61ba860cfad9b592e4c5ae9c6c7d3e8ac69cd08512ab3f1cf5438e741b451e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e3da9ec34bff4e29669244c11abca81d0c040cd3c706fdbec5601127b314abbd0cc62e45d2ffd14527333b055e1e1e000000000000000000000000000000001011a24543586689c26e0cf913c93165fd8ad0b1fdd16028835a527f0e6f9a1c739b5b9c45a2c6f36425f672a68aaead1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144f9e6265310af62485751d484f4d6b4636d999c0f13186df9f6f5667db88ad0cbc8c3df0822d99bd7e34728723269e000000000000000000000000000000000003d44a9f265046a8269a00e40b64aad2c18032467ada3c8e2c2071a81f0b44de5b20f100860ff9e27833e8a8c5c77e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093e3e54a8ccfb04e580dad28651547153f65e79b1f8ece8ad4bc351eff8dc227da3935a992bb8d965eedc07bfbd4edf000000000000000000000000000000000aac6d8976c746ec4a017c0f23f7b7e05b7c1d6149f5a9b127ed41103bd3588f60836f908cd66d7dcae37672ad2e7f301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094f5e996ebf539d3285a9eb723d9ac681735a5a4358f0f7b8acf47e6136ea6e784a62b7ed2dd457e8add31d4012f6160000000000000000000000000000000018578c22c12c1b98ad87518f1aeb60a2aa9e36c8493be9a87ea40197b67c39874c7863d1617a366a8fa1b7ccf2b99a041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012132c0296e2db40472f9a41cf9db6dfbe624d77300eef944adefc9fe3b3fc606e45ee819fb0bdc889b9f6ee6d2de8ee0000000000000000000000000000000002ab9ed00be684e9dd0a557793b7458992ca77922d5af6137a68d3f1c50d01807a0f4748f7c31302ddcdb0fcf2f5680a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000921993d69bc3839e44d330ac93814d2413e6aa61705dcfdc78a36ef3c35dc894d7e772bbf746d55e81a8a3e9c88f0730000000000000000000000000000000000d021895fe60087b8b3ee6f18571e16547405e6ccff3f09fa8534fa951544381cf04e151dcc7261a086ceeb1cbf0aa91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187cffd8ea99a2f6423595312b4dfb671bca3e9196f558cbd603db44a9a991bd9ed489542490faeb7b1089e21b9e70e60000000000000000000000000000000013a58e3ff69ec3306f685687e7d948b0b82b21f1e268deed6ffd242efadc29380b6ebce380e498d9856bc09c1c06f9b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b159ddc536ee60deea4508f999dd6e7651a370e7a6df7ec7800c33c975652cc40fe87bd63d31c73dd012ec3aecfa639000000000000000000000000000000000b688511d4289bb6aea32d684998b5d64287c00e3dc96935cb1ba93af8ec18c3d8c81bfa623448643655346739c98ec61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e940a37b9ae8bca962d55c29598a0990297b73e5983d0656f304a64285211a611c0bef1e984bfe2ebdc138f3ed0ebf00000000000000000000000000000000145b715fc2fa7e7dcdde2b5f1eefe5e90f8b7cacb49b449f3b3a88a9c8040d68fb792839748734a040d47a68386f126e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a171f431570132f33ba146062e03a0c70af4507b5883f8c2dffa0d83922252a0482471dc6e03cce9ba2d76888dfcff00000000000000000000000000000000000afe3d65ecb0ad020605d054dc3bc188ade1fae36d5cedaac1f2a14d9b13eb6b6d259ac9789583ba4ff3b362ef318c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108cc3d110f5d4f071e17d60e4f1c9cab8e5cb97dc9be55f0b14b678e2a242382332b6b6ea4a42a22de65fde8b58a892000000000000000000000000000000001003531937e8e59eb78da52bbd27a2eab4a14c151f404630dcf4e1407a0bfb1b5784a546c66e6228f59a90e99e57728b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001993edb6b661eec274bc5ff4b5bae0a2a31f9b27c0282059e9ef94d86e82043113fad8181a46fc34a20ffeaf2875ea6500000000000000000000000000000000078b75b6ba57a0026ef818f1a7d73790b92086c5e6500accd13393da1328c719a9c745d6a49c42b7ca12620a50c3fdc31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005373a30a5d5d9a92fa0252c9a3acd1aff63c84c369f79d0975ed757ef7414918dc68003b6c021f54822af091d4c797f000000000000000000000000000000000ea2591f2b4ea290e71b002ea5aa41c7404a13d9c5d642f79b990777b10a1d94fabed95ee7ef4ef2330cd7e65c82cbd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f942e397af95229ceb620556516a04f85a83c56a29f984d880b68902495ab32711246b9605a741f5ca0574b963e8350000000000000000000000000000000001676474b86cc5a0bafde079d612409a28b08d111d38bbcb0009fd252e18295ccd4fded376b330864f56b98c5ee92b0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009dde37034c8903669be6e1582b8ebface264a8d35bd09f267f52f658959e47867d840c9a33931031cad2d368f9ed97e0000000000000000000000000000000001c8aafe077f3a5fca0fd80f3b37f9ca5c50c90ac4f0b8496fe56511977750e3ba658b07e92fabe9095dc6e0b63da04d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017506008c74c130a90b50be12993ad4ee10582abec46b9e1e80ca7caf69e98f39b5579545b216f758ca68363d680f2040000000000000000000000000000000015367146f27feea78d2c9acf6dd52e11af3bbec205bcd376a13b36bed8aa83f1db4d0d426c6283550dfab6f465f2c1aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041e6a792f5eec48d2c4b064e1dabd7a0f35ee0bdabdec252fee55f3d0756d8b8161b688b03ad430d2a4b4ff006285cd000000000000000000000000000000000e18d655812aa2bf1a7e8fb6be0bd6d590d4f75885a7b0b3d8881dab341b30e414f3695a1160278b3b785588aa1b30df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e799fe6c96c0885a3b67961a246f48ed36d954f0c5da9da4db8cb1336dd5eb0bbb60b6e4d3d84630a7c5ca59e9dfb00000000000000000000000000000000002b41fb9465bcf215d6a49afea7e39153c48ca5f2a80fb6d79ff664cd60466593630279d035495d11d79ce9e868ff19c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126c9ab0d6e7fcb4a958fabc265b9f854285f4d44faefcd561b0a772b52321e5e1d1e87c7d6f5a0c5fcd4aca8cc098b00000000000000000000000000000000018300bc626c70d70daa6a6d64583a8f1b405efeb8d9a82159824ed4feccf07b8d53bc775fb37142deb1842c6cf6c70d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a22cd8815b1b4fd1d971a8de9e7e1a662a563dfdb0e679086e696c26c165ee4e1cecc11357e9b3f62cc08c7afaa890000000000000000000000000000000000bea2a81db2272817a8f37a3ff5a68b27d9eaa7dbea7ad42c6c1a692a18fec400b305b823ee9680ef899f7efba991d661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a6d76384f54dddb0bcc1edf49a07f62d66be24fefbb9fd8a03e9d57ef9ae49ea4a657e275a25193a8b82d55d999b24000000000000000000000000000000001195f9c0932a2dd5276eac3b429a1b88e8de4fd59a93a31e3fcafd62e117056993585aac01d6d9d4623e562ca35949d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007334a8600f35cdc47b3ccb8dd3bf3c1e8638cb689e74c18aa1ab20665a1a83be890fca284b72f83b2f2919d6c4ee36800000000000000000000000000000000074ecc0f3cb5319725fa51a7a25da1a99f9b1887b28b474fe8afe96b79fc8adecba43b00f961284c75016d24ec20ae0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017598c68a06888687235ba747742c63eb0d35278d68cea25dbbaad96261baee8464791f38c95a742a5ed8521d38615b6000000000000000000000000000000000bee0774fcce2ee5e4d5042746f5cd51f8e150db7a3b9176390ec79c5f6795917e6a91a4f00384b3b0e653e02b64c57b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009692752e8ec5c6804cd81a2a940b1fb0c8beea9477d3b1d71d59065e1815787a48be68b0adad8b2023eec2d5790096800000000000000000000000000000000125b8844c69adc040f28a6b0f87451d0a3e486ee595f0deb0e14a7ebbeb71b2a15c89dd5b234ae0d28b05a32cf88d7341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b8b76a5bca21fede5c356f4721dcfdacf2251edc54af825b8d258e3eccbe42fecf2d4535aa785d86fec18ad376b5b70000000000000000000000000000000004ade7fb5862ce10b71fa32dd9a147677b6d4938aea10ceb16bc2fdd1307cbdb157b4397bc135429d05db959e4e0da2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177c3e18f5e0c493c5e27a7a3f3117e8025ca9ba237a7e3e16425e957657cecc2c4e2a82663810dc0b8d958c08b2123900000000000000000000000000000000154b9d7d0da2dd9c21b99dc45fefa18b1ac6d58e71307001760b74aee99d96ff45e275456062f10f747df3f86e73f1b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079441666569ebc93ce78e14222c756d9ea0dc333953e87d9d8ea5a1dba45cd804f701d68949dfbf54c7e92ed66ee8110000000000000000000000000000000010d6a0368bb41f5545b9d8e3f04641999a2f9060be05358178efd85092ea4c9c3245e99aaf7101665c766b6d1f3f11d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e88dfb7b57a8d56c23c67b7117145696b77e08556534beecc98b74315e1d1a2fdc67a868f883a8ece2a7e3f28dfc9b0000000000000000000000000000000007b5d319c3217e38a5606774e406e8606f7e3e79943f1e13bb7027eb10da9c64412688c28d8d5730739261d5f7f0cffa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000309d4c6ffccb9286a618d535e76264243cb7fd12fde3802faa5684867f1a8c2dea556f3787ce0b64c10dae948f3a3e000000000000000000000000000000000054d3200487e240d6cd3f6ad7fd2221e9707a44354bca6486304a074b8fff6144c75628b14ea6f1478457bce92ac81b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b8cef374aad61039a08af304ae3c0c9ae15a236956361bf369ff83789e9c281428f1be72f2f42fe0a6fb24fcdd7ee70000000000000000000000000000000004d7b094a3c5681def525085d8a4c077b027b7929d1493b470d8c13cb14a355c548544778dbacd7785db03962f9623211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f404c8ed5c65699d7073df9b16292a1149c8eb0a64437ec0dfae1efa93757d4a6bbc741a474dd212742cd70b709de700000000000000000000000000000000074cd8ccc97e3e65ed65dd94699728c6633c37fb77cee4a8d6eb18d2f24947e9c7ae245b515d915bf408025b60f085e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004681afbbe644aacc0ad09b61638c855820cb3b3fa4b40a8a1257965c827bfe134f7eada84789e480d437e8c43978aec000000000000000000000000000000000b48f60c00d97ebf87b729a2eef3ffe070b1cd936476f385c153b61ccdedb26ba46efa489ac96004208a656febd4b42c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8ad45921e3e682e756194bfa98dad032ba8f9573769fa1205d6527f299cfa86c05dca7ab3a56bfd8830e11c19bd21a00000000000000000000000000000000129dedd84e87fb73c8f4050acfbfb1f4ae733635054210a069b023ac3a64189c4d877e7f2eeb1f0ef7cee4338ca1a9d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132590f0466df7f5e4448d2d41a574c7ce7ef3af602f10e3c531e5ab9756fb6ad60930c22a6a2d6ca8c991b8e087c53a000000000000000000000000000000001082e71cdd210b0970beb839b6f423e0f1812a159f2ad5f6f5d9bfa145fd72a4662f490b005d3b920b8e23c2410824c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164e6e009fbade389f6af86c8644088c672e3f7ff0f797a046327f11e96deb896dd41be4762b318cdb4757eb161408d70000000000000000000000000000000015de30b0e0f5f491ccd80c3ad68a57139cf01e973465437ea383a7133ec0cf594825c580598f1421a5e71fed0e79fb171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165d8432199a33a8d5fd6656a02cafbefbe6bb3d778f6c8608e3e6cde6951af4e24356005780a405c3f23cbeea110556000000000000000000000000000000000526446adbea96925be489cf16d177db5ac1fa93290207f2a924e16ba3b41c7994e2b7bbb1888e38febc96abc12301f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053731c3ffc7d480b4282ed6d70548ffe83e379243ed4cf6d76fbbd2a86ac79cac89789fba3b9ea6c2d964ed53be75cd00000000000000000000000000000000156095a5c2088e1d094f887dd018a16c82520dbedc92c99feb6d7bcb015623cb419a03eba0314c90748a78126dfb045c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001204635e1b70f2e8f047af63341bd3b17b3e18c9568355ad1d69eefbbe95e43f4281cbc07c910cd985afff26cc7477310000000000000000000000000000000010b5235fdd84cf9a525d6b41a47cbb30527122b4a6aae8ebb45e5aeb22c5c90625954237252bb6d703c6c2c4bc5f61431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012649981d089e627dd7d778f859b5e3a6584744477233828882501fbde0a83ebb4b4c89fdae5ead6162a04982c2c9d68000000000000000000000000000000000ce17500bf763fbb1561aa5b5ea38eebe45a6b085a7083950f0656fa0fb3bccc2db5d89293574c8f313aafd7caeb11311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060b4766dee2cb0f6f31282758c0c0be1f2c4af35a76acc4730428f32b31344613660eb074229b5585c0a027ac96ce320000000000000000000000000000000018a24147b522c72b732ba24499315290161a891e4d073338b0a81b7c036811d9f124edda8de0638f11677aeefa3b5b071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000687727795a2cfb3e8db56f11db3d326b9b8a5d8d33677e5c622098449ff7b377c80b01ce5da9612287d9702cc55e2460000000000000000000000000000000018f771e55f21098f5ef5d307283a056ecd40a52e05225a8991f7acaae5ee825515656337ccbe7aac4565c51f59dbb1061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001cedc6fd7a81bf936ffa8415c5533eb7007c2f9d8965bf3c0eb84ab218d69c0d395452869ac45aedc654b911156562e000000000000000000000000000000000dcec09bcad8d5e2f1796c7440f0f148ca9fb7c826c7ee6a24ff3d3c6b39bdd61e5efb17661669277ce02b5b7c947f491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124e556ec555df74746e9041edbdcaf8642873960ba3a7ca8c9681e86efb311f772f822139fe1eff8559f94427041b19000000000000000000000000000000000a941d7a0ff924a019b49b7b2514b9002ce34c4192c4e5154669dd3bfbc108f51775fdd08c0b82feea54eb4f156140c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081f01e7681ea7f46bf8a486878f82815a4adb186a4f10401505b47f5e2edf029aab2dece056effd88ffd93406ab05b3000000000000000000000000000000000b34d5c705c02ba9ac8f87fbbfa0c8e62a2fe0a1bf0bf013da75540e5b823cfa49f83acc31fd0a8c405e96db1fc0d77c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d598b22b95c491b5088d38ce9d29a7b5c87870e4c80cf4677273d7ea22ec13bbb980c9249caf438333eb41a8fad8cf400000000000000000000000000000000099ee22ddf1831c4ab2c5bd7c5143e535777a5529a33da353ccacf3848c4b8068411572c3b317c5ea4649a4db4c770cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b977843bcbbbe78513556234f5b594a57fb496fa2736908ca83aa3619a28dcff600d5777d4bdd151cc919e43b121087000000000000000000000000000000001830c6874b7e1cd6e0db500389c4064fcc6cda29f9d4bc2381da7ea02c4a77a484beeac065296180740af4e4961f35bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023cd1c54522264fa742f30c5f9aa6adfa726dd361c4be2cb79776167fa02a4c4d8aa5b1a0a9821df539abee57ba878d0000000000000000000000000000000004bbc6b409e973d0698f0cb5c4713ebc00a900472c50c2f0b0a487fdbd823b9244c599b31e2e8cd3ec0f6c3db3574a181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092aa6698f39c150adaf8d2ed8d0025303a2c50ca48ffbd6067e1e95ef294e1a8d8d9a2b16249929d180ae48c38552c40000000000000000000000000000000015cdf3eba3a21e4c2662dab064fe4ea9f626fcb025fc769405bba09c1ea78bf329d41aaf5e9e3ff422bb76c13465ba661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018212838176bee0c66b0de51d9833a5535e006281741b51631e3f3b08e758cdee7298781cb5f3c2cb2602afb276927e400000000000000000000000000000000034a6acd164cd03a048acbc7bbaec125cb8598cdf4ea526b488d86993de99c144e3162ac0a2fd5c23760189d18c397791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e2085e16b94d873e7eb23676a277b699486672f8db2f237f1ba1e80a460067810632da6f511a84a3d4dc7e060a1f2c00000000000000000000000000000000037ff1367a118d74318d553ca51ae6117cc7e399d34ec5453c39818515a9434da6b8c3c571a1123b8d46c00b717a7d7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ff191e2dc8f1f10ae3a43abbe94d33d404eb62a1214fc8dfc67ba5cec860165cf1555d63c2f2d0789d230d60cb8197000000000000000000000000000000000c587ea9984edc3407075dee003510e09eeee3b3dbdefa11a88aec0f6edc2a208c57605c099d5f25c9d0dbf2fbad64421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b04c0f101ec16c9f63ac8c8f5cfc0b3dc7ec0aef97e31e0e84713778062e43804fcb61fb2aa8b3abe4a2debc3716dd0000000000000000000000000000000010f14083f709e95eee3cff8fe691ebe2aa183b3a6132e524690b5bd47191bc4d0aafbb156cb173c1f7c50fffc51f70441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6317f2e4444a3a84161215227ec63c039a9291a7ba6405c6d4029259e39918405ac0655b49103c315abc11c9a6451000000000000000000000000000000000119630288b45808bc42a8b6e0bc767bf98a9cfdc0152d1d6fe01e4716988c14e4fdf3e0680d337cdc3cf7574ca84861e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000700f8256b34086d526811b4eb2021acdca83762a21d82520562054afca6dca950ecf6eefada7fccbeefa317dbc62e4c000000000000000000000000000000000ef74af1ebcd12481cae4e09c6a6477baed85106cb76e64ca011cad457fe4715b050a24f8db20bec82f19f9de4ed2f0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110ebff9433b7e2d6e690191fafe6fc582befed11e9c1cd4d97d1d7426bfcbc7f837e42b52144df14fa579ad1337bf5500000000000000000000000000000000098ad3f3fc63bca3daf8171a56a481f8d6cbcef26610cb1e798cebf47cab358f099f0eb81d5d822decb5a574c2c3ccb81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005735add8b3a5bd94087568996d9ba5c6be9bd93f9a19b2700caae5b4b6ea19a3e84f2aded1a21c12b6c15c7bfa4bdfd0000000000000000000000000000000011bdc4febf477b00cdc8f8247ca942d2f4a59907b49b6fe786d3e2c5b18e44677402329f76e8abe0f3f584e1f24b37a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bfb88aff16bac6b4741a34a701c1759536de659cdae405794582b0f618fd9f379c023731065f6e6962ec1ab69983e00000000000000000000000000000000000794cd45401b015e8ff2b851e52e21092c3093831efc8f341b8ccc3a450894bd6cb27ec8c21b00991fdd50649e4382fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062d33d68d42e1a064aec9696d07f5a25bcc4df150ef16cb2a6e8918f59854665b5c55bb8ad60f0d9fffd45d5d7b656200000000000000000000000000000000114ede9230708466b5b399850d0f28ea02bb9bc736ac728da2883235b65890609ab1820f117cb8dc16957a929299385f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001041198f0e9c4bdd6a0f3937994aaad238dec9af4668f0a63f0e76107e3a11ec0198319aad0bd1c4d30d6f99d81ea71f000000000000000000000000000000001223bc56216eeeb5b832f107bd5a2da83b21345962a13b8c8441ae3639ade8c33773fd3d8d1055b95e6ead0c8c884b011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006091c489bd76ecdc9238b10e69eefbb5cd69f9ee31d46c42051f90f9cbaf6177619f88063df6d126d2648b3a66366b0000000000000000000000000000000000c516bc163a835e9eeba12f4cdd58af18cde5ef9374f2c100ff2d52065b7494a5d0c5071de5815218e7b00c972fea41e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e136e76168a3e912120df9da5e1d416c08d8e50fa08f3f06d4b86a1e666dc4cd7f56e2314caa8d08e4619d5194400f0000000000000000000000000000000009d4151cbc73027664ae1e52cdd949e521760d6b5a651263d31f8a434c527156b95d1ef15e05e53fee43776933fbd0681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a2f419701e52135831638544c08f839fab08270c76782fc62a949b2082a0c4bcb0001cc772acd95b5f5fe2c8ee4db10000000000000000000000000000000009a2afde0c4c8a15a387005062a686f41a8b480159adbe868a5178b15b2a910d6c358d0b31862bb9c88c8f6b96d4250f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c287e60355d614684284310069c433c9b61dbb6eb7dd8150edef0c860cdb586d61261cc71aec0a564c33beb6479642f000000000000000000000000000000000338e3f8d90da0d602775c87f206055a28f7ab945554c6f0aced8aa9ac8a86310373f096f0dee09d3f193300fcb2aabb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133fd20770b4ed4f8588bdbf4f9aec275be4c8c069e85a102863c316dd560b9d567d2f9ab6bb8f5ecac0d524755bfa94000000000000000000000000000000000ea7ebdf36f867db2687c6e86491469b2123c0f84fb34a658ccc8aafc08155bcbb09a4df85ae837a9068f1bb6db0f5d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001a00c47e629d63c68907bf5a69a130f36ad788f6b1d2331c3505ae8ffa462b3259436d42f2bfe3a3ea864dc190e0a6d3000000000000000000000000000000000953bde81b431da8335cb2e30534d4b2cb7f05b1dd3d350a6bb7450afd2c6b0d91e35dbee03356aa58b1fc9bc8add5e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008514da7d76238c42ad53742d4f13125d8ca3bd00ac7dcf4c3b9404db3922f09ec4b5ec61de9d022b307723467b4477d00000000000000000000000000000000149c2541a7eb42225138c36a5763f8d5034e716b50dba1577c3d37f4df6f31fd81fe39a00dcee78ac1df4fc3fa7850c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141e2990bcb25cb1f18ba9bfbc4bd0ba061bc37ee96dc6eb8751c22105224e44d2af6d16024d1ef2d5535cc809ce82290000000000000000000000000000000005f496073893d7d3c4168012a54e71ea417b91864320f63c7a574c30c97b07006810b69b8edf054dbcf6a962597b198e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bac3bcd303d917c8cfca4b9c087d1f154f93ae29ced50456cbbf303cb662a1986f2a63d7ada0202926e8ca4280c5470000000000000000000000000000000000ea18d9f4368ffa578c90710d77e0859bc94eff225c78cc42110ace451d7c4f8b4c63844a7b785184542f116ee6d1591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000acdc5db706abd7fcdb6dd73e2a3d6d499de2423a72521f12b99f995141d1aae7c234677d70008fc00f9e964dc89633500000000000000000000000000000000153bb1b64759dda9144624ef2257c973eb5fdfdfe22ec89c79a3d9771cb142516f8bd4193731b6014ac567cdbf47550d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f61b643a8724525c514a319ccb5ed291b0de3262e25ff66fca98dbf54536610256ed1b5d09301e1a17ff14a7f97ca6000000000000000000000000000000000099d3626cd99a35355a75217155a672d355572166a32eacccc93b9cc2bf3db430e330b0bc55f6337431315d040adf101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d21657c37ec0f9c9309b4eb54967a845cdcca244c0a587ba2388f08aea1a5dc7ac8a02623049f640725cdb39fb77b1000000000000000000000000000000000b988219594e66b553454bcfbddafe121a2eb8f5ba9881dd071e51d6d0b2dfe50a94443260c53be2d0b65ff77f0a5bc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc0b9b835bf7a249f97ec3322770bb103b5d981e05725c0266bfed44728deab4ccfaa7264a8fc54f11c0269052eebaf0000000000000000000000000000000012ffb67e9bc18e59df74ccb3c3f53add73426b2ad26c218e9ac6cd2ddf8a27927d75da80257467531b353a9242b5e1bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d142a8d34b3818472432fbd9435a46c65e1d5e0807f8e2d531d94b5ac5ac24fe673b359c11ae2cd251623da2f2038800000000000000000000000000000000195202b0744645df948110d29c2499ee55beb7b740f61538af2537aa2c319969e9bd992de2d3f8e63e2807977ea098591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ccbd35a825734e3bf49261c506e86fce7f4c008b9489b19ef43a484f27d828108cd391038cb9ce4164cc63290e71eb0000000000000000000000000000000015217b34803a59641421e67b6e6d1c2f026be006052db8ffc6da58c54eb610bc880ae08afaa3cf320ecb2a5965d27e8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163e5573f09c71da91ab2a1d9e7b94953cbfa9acc4f14101538041b8ef2b4976b24aed53155460f1a75720bb8e014e0200000000000000000000000000000000187715ad4231d0530ba48ade2c0e42006c6e0c7fdb21f44a7b3a22617d8c4c7a9305ef833d71c82e2baabeb96eb904c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1787f030cfe1fa269dfd71a2005cdbfdfcb4476b9c26552d9af4d355d530e9fb2461bd48604aa702412b9d67fa89b70000000000000000000000000000000006a0930e941eed3893d329b2cd08f14b84002008064c92af32eff752023897625b87c89a69733741fbb9693d5e186ded1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d27fff8a3a76a48288cdfaa4dd9795798c8ded054fffa77ea7a559529d95e78f377292923bda348aea8e8fbc7eb7400000000000000000000000000000000015bd8be0f49e0410139b7e9d7bfd1e5816c01866de37fb46d803fc74401e09a7be398b76bc272230360b70c92e8a755b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de19e7be7ba775ceda719c6e193c75635f2403e8c4616f58970428a5b5e85c1782915af7716c272fb4e5e4243c55aeb0000000000000000000000000000000014dcf7d8252bb17bfab258ec39181b192742e312e8af13f32cabb32b776e907ff33f502ae0951a501d7a28c1dd29a0c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045e37bfd063f81b3e20152add47515c1e70e8cf5b6385a5b999d83351ca71856495b656b654ae1233a5376918c1c28c0000000000000000000000000000000000ecabe67d8112f407e745886fffe27c4792710b285ac5a27c1e779ce58e7a0d12865c0cbb309589792c81ab1a7547c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5d8771c1dbc8ed2565cfa344c73747006bcebb7ac0f48d78f14861d0cf1e93068512219a628a613eddfddaf34aec090000000000000000000000000000000009c56650fe82ba9e775633926f27d959a4439ad3f465829a920a069f420d1fb05920f6b7752a1d81f16db3ff5d7f72231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000392fcc799769ffbbadabbcb0c04ae258be28b47d68acf1792d36be1cc1466c8a7208761ca207f9b5a19351f8155ae9e00000000000000000000000000000000001e08357c781dd0ffc2d5083e80a16f8dde9b573ff27e9001292623a0722e555ec01233fabc006870235dbebf7076fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001294d841cbe0dfef49449253232e67dfd32eef1591b1842323e3ddef7f2c17342dbf1cee16be676fabf5a2349f10c713000000000000000000000000000000000e20c90c3f5fcecdc973fb692b012887e2293de12b8ef052cf5c5e49e07f70f64f65d7ca37f4435d30fc855a05ecee071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c6374269b76cb60cfdb6768b764ab284932a1c26daca6e3e93d7e05b88d27a2eb97f0f294efd12cb3311926e8133f1000000000000000000000000000000001028c20d1d1ec5d4446c2e680d0fa6e2c6882cf9efd5ab4839c964e188b2ab16ca6e4c7e36cc2478fa498cff196c840e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ae61d214f1803b8980db0fed8fa76555e666b5d11830c06dbb89b5328365b6aca79fc3bf388ed711697672ddca956e0000000000000000000000000000000007501b114a731c8d2043a668d7f6adf1f60dbb11bf6d9e8da8a03fd9bb1169b85973ba0890cf90cc0b627a617bc9d1ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000089e28ca8426b4b7b70bb3fdb75fe1c06cbdc3a8b818b060c6687dc072e28a60f09bfe4c51cdbef8fc2d418211f455cc00000000000000000000000000000000180b4064223f92335ccb457801b78041e615615a76c0610cc9675e14636faa0851daf52c1301848e1bbfefdf675441991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002bb4d6fd9b494a5160c4758e7ad54117314bf8063b53289eb7f535a712cd3f63fefa020f32b6e5ef859cb9a5b37d14d0000000000000000000000000000000008be0b1836d20818a7ade1bd623f973bf7cd5621384f812943240aea1051fa25fa1c392168b9140802126fa0b812bc381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b21fdf5818878be6342ba0f7f088ae448aab0c7f5f2bbefbd595a5f7b9f64b96010f1ba5336ab391e1e5d7705279c5b0000000000000000000000000000000010455779b738b2aa1950bc276d7b8d529739d6bb53783b694a6b0ee9bd0489187e08f3f656c29b7c5c0d11692907ad301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c714dcfe8abc24a662b77f0c9f8403a9e78a7695c7c8d06ccf9775e7a48b005bfceb9c9687378f3f5154bcdd3b2fc800000000000000000000000000000000097e078b4c8d46ce315b1cf845e1caf6ae2ad935d5f780ed9c6925dc03632026d4ffde711c9fc1f97e897fd136e2511f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a819d969c2c51ce6fe4d11cfa9cb8bcce92ff2eb18a4406971f567028a0021d73add7d418cb446d817a674f5b2465740000000000000000000000000000000005d33850ad448d3e5226193768d53dd8162f1e19bdb98d8be7668f70d1b9870a1469cecd91afbf3fffc561d48038ec3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014dc6f08c1061eceffef89bcbd62a7a946da712c44ee56efe61c9710ceb954e18233e39b7f50bdb1f776592ff44bb38200000000000000000000000000000000153beeb5cd485a611b876e511da4d11e26d745330f09bb017a7ec4f70c31e1fcd5286e59443556eebc6c6f208117ad791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e1d603ec12071a0634485dc809c7c8cc913b479260f4a79282c9a265cbdfed95b72fdab30fd2f586c316b9b72862490000000000000000000000000000000011bc6b99e642bf47a5e31e1a5ccbd72ac3d912a9e0b0b3ab3313ba44b8f16ce0e259138dd25dabb689c1ad8d14b899831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001183097b2cbe79a86b8483fc26b246661899a56d528bd1003a5c3c5d57aa154b94c353d4a336c587e1c13ae1c25c5b9100000000000000000000000000000000045d8fc1ef2a1e1240672e8394c9e2b8117b2797e14c9b782e04269d544286431fcf7f4d87485e76417f0f1bdf4363a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ece20a1b4d8f66a4045a2cbfec6ed45e408e9d8c3b5542e3b976bc3ffa0b2c97ac385bfe54e304c2d2f011394a7d5290000000000000000000000000000000013fbe27b8bc30962a4995488d84d69de05e2c94a8ad7244f52667f789b272b5ad79a705700b0e0828edf166b52141b1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5ce6f738a81119d99ffa13413c962b1a2cf04b46877c219256c8c149d0fd28cc0bbd12b6c36775cd858746b4ebd2e300000000000000000000000000000000102f7217f8c8cbd4100590f6976d559abe32abfa2be0a2f63e6b7ac436cdee36e74043d43884497b5c450dfcf9b5fcba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dca075dc9cdf21a280e4884bc3ae4bd9959b638130784a665384ee3a3ef8df9d12904edadcbefa2e5754f350f6b519a00000000000000000000000000000000071b25357b1c130d4e4ed392cb5806215211a39cdb288093ea0a7126f415eaef28688ffe37149c06a6959ddf9a63fdca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b96bd57c8d0510aa7b4f6fabbf0bff46ed2ed1db4d37002138c3eaaf28c36cc5b96e6c6992be925e2e83fd1151b6c10000000000000000000000000000000005ede28f7e31154a5d1721d09282e6b214e94ea622f3b28247fadbbb62fb1b737bdcffd912ce5b408bb839960a3b10c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058480cf561f5e23969d79ddf13e2a45a21539f715f393e61b6bdebae469900a3bfe1aa04ad3a57a7034382ac886f78e0000000000000000000000000000000015dbe1c274c90699b2ce386473397e009231197e21b1d39b92a1fd3a0b3b1c600a0579c874617ddfd953b0fbb5b7e14f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6d613ca6b63ca1308ef85a08c0905f80f8f41247a3c5910b102f52354419b11577a0232ce930e5bb6b05850db46e4e00000000000000000000000000000000124ee9c95eaa57ba7b570f44f6bf5d91de7915a540b12758a57a81714ef9785883eb296a28da77362caebb7906dbc2b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034198c1926741c247ed4f0062fa9a4c7699b9e36132f78f67390829c6889f6664b96f32f734f081e3ae7e9377985ed7000000000000000000000000000000000be07da5b50ef7c138c37a0d3e032bd0294211a7c05d1f6ed1b429807819d71ed8adc5e00799ff51ae45f6a79f86e1471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac502794bc463e45bb6c6acacb5c0a83fce0f66bf89b8b4f6aca25a996d1acc9fd39c07b255c3eadd0958598cd6698d0000000000000000000000000000000002483ab2369ef3506d6c5e4119296ed817b8f34b4e730c8248c9be36ac229fd46159538633ae8b47c5dab76091babbe11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e1e674ba1336b28ea3218d29d41b1fdde32c9411de3756b0ea3d438babd6dc6560eb10b2c9942338d3110292038e6900000000000000000000000000000000061855a12472342b1cbac1835964dc616ffd9f93f902ba61979c8308f2050b529ba15f13f953ac6a16d6fa18241c96421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002ae5d46ffd3a50a4d4696ec50fc4d270bce248bf7da01851ef16bab6911ef178d2f9d54f96d5e5d337e1023468529f0000000000000000000000000000000003040ce18f8674fab288810e50cbc573019ac3912a4b7a3697fa2499472fa18325bb589635d3d8080a551833ed4204541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000038749f3f30b38b7f8f1e66bbf316040e8cd594bba6cc77c9e199ec9f77aabc2701296f27a012d53441346ebd4a94bde0000000000000000000000000000000001880e8d0aedf27a2e83979e05e689d9c4894cf2c9c7f7f9a2e4bed8369161a83ea7a71422361435b05d4f817f0324721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028a2aa8b16188a64abe533a1ed42a127daee0537af6086a19f645e249550c88654a908a8bae9b9c0b08a3739af7a9b0000000000000000000000000000000000a5f19d542349cfbb5aabc0db46ae9b380410d8b764c876fe005584d76c0e9539fbe3f69911a244a9b72377711770a0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ddbe938ed2d6f512c30a346750bd1d16cbabdde7fa8121c770f4163ba569060efd20dadb69e0c5042069f0108dd05e0000000000000000000000000000000015efd66d5ab30d39d96854eef192f5edaa215d768a24e62c9c3962a6e2eaefb22eb49f9fb8ca6e5dae76e746a5e216c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003340433266f640af71855c912f5bf01cd4c7c7a84cdbbbe127c0a23b3aaf5c6b19f920ee87f2e9c8569d8d913e84b39000000000000000000000000000000000bf472b10d0eed9650ade76bc0fa9f0faf77228576d8b9ba4d641c537c1c4cf0c49c09594317ea8b296201f749bd0a801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c523f24ca64afced64381742329aa0fbdd99b2bfa5188bb1cbd9e832532d2a840d24ac4f04777582a50c2d44cf0db9000000000000000000000000000000000080f56c3a7eaac4ccf8b70195b1727c9e484b3507a008c021c516ea7b767697f7467ce2c63f6528db5f9cfa76976e00e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103e2adde90b18d4216df119e0d92ca0a836216073ec8ba609a662305a9a432c77aefee70b8cf32aceafa9f79296917e000000000000000000000000000000001236c5f18e601364fece8eabdda2c8b077d6579353365ed1d5fe928a1a66273b4937756a348d2438d252f38b3914c8d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001388be336fce4954e3d35a4fdc4f7ac156d180dcfdd3d8923a3a78253a6138ea2e5ed0d1b0053442d0d0377d3fb425120000000000000000000000000000000007ebe7540c64011d5d6803fc457678b2821b22586170d35995398e25e943680428209b76ae827f535f3359606e6f0d491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019fab9ca1d95d442ae47d58ae7e1bf496a21cdcc5fbd9541b5b64e31def867d3ccc9157ba3b1a050e092a02517dd08fb0000000000000000000000000000000006c033bd390bf274f6f3e4e97035745e40d752a8293258ac7ea62631078d1385a38bb07e6da739f80ee192e8481b96761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7bff0a4a71bc1cbe17645baeaef08a6d0416197eb08a83af05e30772ba1a94fc1655476b6880283645e75194194f0a000000000000000000000000000000000fcb87143e658d0782203676af902cedc4f88f0db642adbf9e4d7327fa71d9131d5041e4e14e1880f2ad6c5847c326d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6f5f8281d500cbcee1e83e5474f03465d7229b4f794f03d72fcdd4ff620b955277c385860d00e59d1518f40f2460f70000000000000000000000000000000018c9a5bfcf3d1bb9001f666da2404251c4080d147ea800d84ddf2f9e3ea6cefc5dfc767b40b42220b6e88821746baece1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c76242ab146fcd892aec3354e2f1e2dd3546a57f5b1bf5213e69562c50b313a7f82b671718ba3f8cc2222bbe19a3190000000000000000000000000000000019b63bcf8b241edf079c1b311cd76f787c0d832ea98207b50daa92308c5f174205dfb6b1240b078bdf774b8e7c5a395e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ae21924707e7c445af28324527da6758529175ad4c657ba06acbfbf3058ff655901a35e6b77ba94b0ed74756739aa600000000000000000000000000000000030d903cf9ff53bf6a78080637865ee95d8d7428a783cf68aacae1fa4fba67c9d730d6c1363112a53bd1c7b4eb93a8441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000407c2e490ab58c7449e03fa2c07a16c17c9029b1ca50fd1b7ffc685bdbe903dcd25edac5a91800b594f32055dd456f30000000000000000000000000000000010f6a8d7ad9bb0188de21a6fed04a58192f70df7331186c4d63b19a40c140af467f1ec8c38ce75e8fcd611583247619b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000820130bc4cefaaaba7ec743b04a8ab78e78397a150c1b2c2e68f59b289939031f9797b6ec04c6e5f308bd97b0a43a5400000000000000000000000000000000044f4f6fa7219652fd2025876b2ff3a61bc68452d43b1643c0ab108bff0d2e8057db0f986685c6e53b17356f9d9a2c261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ad2bb7d7aec7e35dfc84ec689e5398e03cd7c9f2c9d0f94a2dffc59488b51bb1f614d8bde3330371c45f2734a9f012000000000000000000000000000000000dab495b318c28aaf23070d5656453b070937a54617908224492a663a639c1a0e2c6b44b40b77eca55e3a94fb1eab80f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e89e8c410c7b6cadf1fba733df1f8746b714b14a73701970b88201cc329fa9d4c5ca844b2d7e423ee86824487b432c000000000000000000000000000000000a2ba0d5bb33342b68e12f85d9fce6655fee43c8329e66d4117bf77e224be7842956de28a88e3674bd13985ac59b69de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b00a0f7f8a5e4a41c5218efcd40c269a2f12681666df1d0ea80a2796d419d36e7890cad0093d1df793de3465227a200000000000000000000000000000000018d725e462110c8b8f3df1ca2f7a330ebfc0809faacf65e5da2a5acb9964849fa3cd03a197bc4c00ae1c516630e7c2121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f8e3c4cbbab06cae109475c74682a95cf555f57406677c3111fc4a838dc95053fcc72cb57c1fab17d8f0e39f7b88680000000000000000000000000000000014fb8ff2433b0f12aa572415b6a8f808149ad6bf310b610d20cd89b2feadec271db9b86c861fe1e94544d83b9c287ab11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b55ad62dcb19931a465a2a57e7c2d47afe192aaa6068e07a4d487bf719c84f1ed08c5a833fed78c515581decca9d650000000000000000000000000000000011ef532555c5cee1075b4ec58edaf29acd27f0e99f1b7684b207a630f281ce886cbcf5c5e86ef0d4979503d414ab6e4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f51cddea6ba1aa1df801993a998344388bd4a13cce582b91907172d10b0ff0356775744234723bfb2ee2da799382d7000000000000000000000000000000000c11e775a7a354e75281c62886cdae96e2b72e4198a586ff76815898e8e7e0dc5a93270e5b567635a2f3ab8e9f2f4a771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a5874ac376ef5b24ed8c3841a0e08cd62c4847beba2189ebc9ee8c7e2b95c700560cf1d6abbd254a8f8c0364aa82c50000000000000000000000000000000012c3123189a6db9904c22426af71321c96475f0bfba28bee1f672e12750b7f61bd56a7e13eee82d1ea112ade3ca399691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ae54d5a38c9f95d63be4f8ba393f8775b277df6e761abdbf03b842d07973c01de9058285723979912201beaee263a900000000000000000000000000000000105c0379dd8926606138fbba9d8ce8b538ae31155b7ceca0a06d3fb09f281d9303308ffe1c3919084c8dcaa06019d0c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005af9a1a8c2ac496d1defa3d8c304c60273ab4d63d6a2f634c51c2ccd1221f1787c151ffffc222c0c68fcf4c249608140000000000000000000000000000000007e83b09219b17d506a2b396ecb15e52d857d67b5699144c0d84e81c1e57d2e92eedad9513a6b3e1800a75ab57ae9aea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175b33d9d1d64833f2b21cbc783a53e0e8de0c93cf39bc6cef3fe69830453f4081872ae91304f498b364a985fef5a576000000000000000000000000000000000fc72ac37889a0e9fe683d679a10958e1afb50b402adcff0020634a692f5188d934f5afc8c7381c9308f92b09dcfef291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f893db85b655221873c0ee4ade715848c4363e354e8e63d3537ef4a81b1b95e48b56b8cff1a3816e14a6c5c6e61a6c000000000000000000000000000000000f8bcf7fcad5a8150eeeb409978295d0eb083d9848dfbe21c040fe5f24a2884327b8e48f640d5416a8c35f1bcdf3dafe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed6ef877f2000f5ed7198fb04f670dac7085315d6c6c861f81805682a3b7f467547843a23d5f6d4b391c16cc6d7bace000000000000000000000000000000000bc3078f0018a97732d0c51e1550cc781f374013d9948f2fc6ba0ccdb801819a4e772eeb529f4c9bfe6d79299995f9bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019d9ba8f4d630172515ca0a73243cf642704c784d2d250c25bfa32c6d209f63737f6ef40084283fe6d25c0328c1e7bd000000000000000000000000000000000a76cc3ece037a6ee501f553e0383824c52c036f291175e1bd60f30b482aca0d63b45f75c67eb6e90690eeae801da3121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a92f71e51a6025045d6c1846bc7bf65a7a906c26676b41544fa3334637e7129742c27e4a2001df5a364bdc39436b9d0000000000000000000000000000000000a73c7452d5f927a7ff165d6168c143166457752bfb52bcea405878ac13ec56413742a0d303ce39e5a647103924140a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f595416adc7d48185f109337ec58f23af7841b9cbd851690e4eee5f8b0e127387c11eca47d1e56794669e4a9e34efc0000000000000000000000000000000010bf7591ad03772ef5b3f7c63f16e5e072ff688c86a920d3a7baebf975b1a2b0d0dc25d6644ea2273218ead256ede37d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a243d8c9f495f39e09550c8664693744f1d3606e851272f1e44af8538700a5ae6edca22120883616963ac2bf757b4800000000000000000000000000000000014e5b2e5cccb3c314c333ead2067a40d92449355d1df4537c8bc6d947b5105152f5b4428ec223d74b029e086480697b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7f5bf1e784d3fb5c536af9f3f37bbf4185b6967840885d3b9a667a5d908d1b0c8147d83fb32848fbc0f419b340bc5e0000000000000000000000000000000014b3a6159fbd99ec09b2588162687afc81fc9fb85baf3c0338511079cc7e4a9ebe609da042541a405f3972fefbe9b7461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac31c65d98d000433dea00e8bdee90211d285a08d7848c8f20a48b170219b0e7ed610ec71b98a514fbe9bb520c16ce700000000000000000000000000000000060f68ae3f5520d8a546f49891b045e0078237b3137b7e8b19b50239dff21b354e9e1ee38babc66fc168f8d808d3695d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031db8ccee1d7807944581f833fedf0b13fb6bb706b2fe8693f7118a52923f2e25e084e287d5c824ed5fee0999a69f960000000000000000000000000000000006a377d46c828120792ebcf9135c12d57edaa5eccde526d2bdee732de2b1ea98505d461b36470d12e05c3747ecb11c901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e90412f70480ae3c12c58901a838ada09965ae86e66c6b9326b580e644495781885ddba567686efc06a27908848b4fb00000000000000000000000000000000096e679e4fc99a85396e0eaed159530ac6f8290614eaa505bbc275b1aff9fb47003ea76cfca64bff9a9ec7864925176f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008275d1295e4207f0fd3a67e29bba8050c094cf336fdb42f18a0b77bae48517e7884d725684ebd36c548664be94ba5920000000000000000000000000000000007a8ae5e04573fccb404c20bd28d72a42cb36eed254d41326be3768a14bf88a0e21e2c43d4f48e62502d36bab65333181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9c6d2a1534a35d25162fb552436a952328fabad2d1ccdbbe0b7d70983eb07f8bc5b257627c9012d8ae8b6cf849bcf70000000000000000000000000000000006e6430bf17affa757a8d3b674b47d23fdfde9c1bb02153ce1e31b57b8c323902e0dea29827b42780dc5a8e764746c941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001564b3592702066a099b58db02fa3db5c1ae67ea9c7cc7418d21f5d9dc83ff14a7bafe77b5e9e97ab1d6b8588de60719000000000000000000000000000000000b6cd1a87205d8f9e26575c63846e3cb63c61d633af24e72c4849e554f27602a5be8e4ef1c81606259349d8f611d95921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a65294210b47f6396a3a4a041fa7add35a7cf4b79e0788104cb450021b100874f4d7367101a7dad30c8660f928314c8000000000000000000000000000000001067d9000fb5aaa48a1b9726ed098ec89dd15751521c51c8630e067048ef1f211d137cbdad303f7bbe0d254b8f32c8c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000afb014945ce49a2427b9bb32d2bdbfd2b178c57b102cb6ed31a0d7163a7f5e5ea283cfb3ec0885f367cafe0ff4333b0000000000000000000000000000000016885b28b43c4fb987371fbccc52e4fd8ebd61681f9e0babe4e3cc3b38a6125f20cc49350278b742002c842c63d53b271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000395a7ff03d0e1aa6b97f7064af5d7b2744d56340c4b7407cef57debcf1ce356a7ae4acfaa4d10ed0bc2b28e59a962ca000000000000000000000000000000000609c9d537420ca2bdc3930e824e31f824c2c6a7a50dd121509c6fdcd66091350d87990abb8b747a363ce8eca6505d721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039418b6ef48761b9b9734fa6cfbf184a490600fa9b014865d3519130b5d04b1ae2e113e798df7962d9fb9ceee6d8cb500000000000000000000000000000000182a765e62feef1720979c9c858e84b883c9da8c4d012885119fff2e61e239dba0df9d822c7ce34603091fe4353786d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000197b9239600648f73e54a3884568eb89010a7d86216eeee7e5f0720be75ee45c084113489408feae1f1c115857cc557000000000000000000000000000000000056c5a8ed91c52f6d7042abc117e392af424268e2ab33e818d726b31fbdb05d223ab4128e19d3da67bb2c887222a43b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a461b1c881e59717d8c433ff138f167eca88d7acf383522c5a69fcea248eac0790d83aa023ac77ab1d508096e27cb1000000000000000000000000000000000d92a449470836c6a3fe6be2fab8bba8de526aeb6bd9659b6f5e19941dd5c23c7670a86ff3ad66e6be49f54f56668be51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051e27fc21839f6d2f1e210572b3ebf3fd571f0ca2f89b2d236fe1d35ba74b2f3bb582f06eb4e7c6a0c376a9dba605eb000000000000000000000000000000001901957e991930d7e2b51fd5834f6591fb360fff892f9acef74392406a01b1f44bce62f41c035a169c3b92bf5be2a1931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001823765a3d22dfe41a8c5f874ef46c783e4d44239c611f74cf895a25f7b29073090e8257af1cb6ab2c32b2df4eaae311000000000000000000000000000000000f7b25227f7d88b3680f6f6a86af6bb631cabf26a3f5e351e93e081220aa5aed4b93f7938ae15dd90f92d115e136984c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001431f051ef89b344f50575c1f628a5f7140101076dfe09875734aa533d1d8046d6585db2c2692544798195fff3db7600000000000000000000000000000000000460a7faeb7b31d68f8157da6e42e581d67addc3bd837ab5a2cd5736a00e9fcbbbb85e6058236293af9e23d085a3ecfc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7b0b10385ac6bd1a0f90ce2a2c6ec87c46db498b235ac27d84c8fe672e8c0cf521e011e7bd87becb6f7e8cf2edffc00000000000000000000000000000000009493bd9ac530f7eea5a8aefca76e2f4be67e15762e935826710f8c0323c9cdc9ebb91db3c7697b4918af117f7e283021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059efcd6a9c84dcc6f4bc76602cd5ab64dad9dfba2920225c0e0cb2c1c5f515c8f28aeb373f5ec3f6f3f4045df03bbb30000000000000000000000000000000017e5f84a2c04965b7098682f77b7753d0341f9b9c4049f4ceb682e1af6c6926b3098d0f2a3bc40152c20cf36ecff37e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008432360a0addb9b833c77a0a33631afab70bc2a7f1f590dd6a992defc8bad4b5a17babd259094ce301ce9d31d39e352000000000000000000000000000000000b06c7fe46c2fc8ef42c96a8b929d0e2c9b86b1e2c01ed96d48add8920b6f449921651176ea804665e6009d8764fcb131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008bbe46bfb169a9676e997a20aa501983a411c9737be87187f950e2c2e3e6a3755aa765d4fdb5825785f4d3cc60b563200000000000000000000000000000000124c204d7f3c6ea2df9c0074f670335120c50e493556db8efd1ac1d883db5a65bdb76a8d0808c0f5aaab174b6516b8bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001282bf2f514af539142269f649704f1bc1c0ceb67a10b01761332e32966bf796308d3c1bce7c2e7da37b0be8ab2312d000000000000000000000000000000000139fe7c8ecb824225a32da04d83c0a9707298426d8044fec96029bab91961e44c3ec7bfe889806c96b376b3ff63a307e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f6813640addf21856f4629116527d06ba771debdc2151bd56568b2beabdcc45677c67e80d430da463874d0b5fedbfb000000000000000000000000000000000348aa82c874289bd9f2b05bbd52c8eaae58a973dd00fa49d988309086e28dabb4f5b816e1fa9e110beb68cca89a73a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000007872f35bdb204b6327dbbd7ad775bda615eb30925daa8ae3c86e13341781d85518884f179efb0adfd90b5a42f7909000000000000000000000000000000000bbd8cd2fe496febc550c9517c2110816f1ef7f5a0b6c1c2a47ce0657efd5551a96d21c08d1ae78de80a1f090c4ac9821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007029c7310093f196832a99df00a350d05fe480a2ea26b23ea13d27b6b0e3e426139cdf74d50205727041061c3ef01df00000000000000000000000000000000037fa92fd0efa979db73ce7a50406aee4336c75bd700dacf4fa30b358e330566e19ce016bf3dfd09dd9522d40502512f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed2181d29feeff1c235b93dfee7bf61dc425a387ea703993459d259b045552eea4239975c4a27532a94793979969520000000000000000000000000000000000c3b7d5669630bb67374d2a7c9aad6b4b408b95cb6492eeb1834ed1d90c0ea7db7c034b8bd668564551b208eec30d8b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000779357704fae49f866d301a1b28bb7536dfc6a420148f7d2954a3832d2cd69f8ff5dd059f8e098e6e138d29cdea9ada000000000000000000000000000000000a27bd6c4dd5c7e226f5099a7b8f38694ac313f94aa78798821ad657b53aa2019cc3a45c8e2f40f357d45f835c8e74011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5a41c18205e368545c7bb4b9e7811c176c7b062729be14b4f8bec23a6e3faa326ebad12315960e285478d01709e4b90000000000000000000000000000000017bafbbe027176ac44165c470f942635b2909a372835d8dff421adbc07799b64825adc9f18a1b333209a052b87041c2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014110ba7bc682a0d4b9fedaeb5ed4ab8ca3f4f321790e0985c28760964fad0e29e0a303020c443735b5457b15bf85a100000000000000000000000000000000186ec37bb3557750f78c2d4b325093956c83f368a8ca7d5157ea7b1e1d8bf14096468b86b1ba850423ff0ff0a4076c261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031f425375b58829ecfd8d9295b67051e2a2438e97a28ac225543203bad9cf23596944a236f69a55fba7487ec24aade70000000000000000000000000000000014fce889975e94c8b51320b0365e0e38d5f5f8b9a6a163a158cdf05d82debe12ca38e34dd65ac4c1d7351ed3b38b61bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001819da455d89718a9710f8758ecb6e57f932c74bc1c4dd0998a82361e5193f38b9a39203460d2995dd30759ac7224b30000000000000000000000000000000000d7d5bd3fcf8351c77df5cdf7986b9f5f1600e7f704d26794eebfa32678bb724a7e6bd80f0cfd26fc5aef1204913c6871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077480d80988d453047545d67bc6b583f5711a54b5e8d96cfc776b3078e746b17b09e82fb44c389216f53e7da1b89c340000000000000000000000000000000003f04dbaab6be287b9c4136eef637c73759edaff3e1b56d669e8d37be5a06ec01ecc4a680260830c5e02e62aefaadf4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e599ae7604045136712ba67b019de2eaa569c84a4c00909f72ab671691c51cdef6c91c628cd22021efb9cab52503d0e00000000000000000000000000000000165f27c82d3075a3c5dcd926eb3379556895fe850dbbe7fc7911ac8ea9a12d376fc5d825b3af1fc4792ed84ea613b9421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163fa68801225853a6a56a2ab553042d93126c3aec695c437ce7e9ba8d7bd0dffb3f488caea9ee2ae85e15dce6ea825d00000000000000000000000000000000155fbc1fe231127c2e5d17827635d1a2f47cc0071fb2c9ece4dddd74ee0dfb7083a0d5ba7bd9ce1f791353461654bfbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c5d567b869736ae85bfba5112a1126000fed8fbcfb90bc2d90198c6fed9975dac4c994fa8a9203d5ec1375ffdab091000000000000000000000000000000000cab607febf71cbf072bcdd8952d169efe557b94c32f2f5b6211b09d1fde8d74e63dd13204046544c25804e66f2e2f8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b73be0705865a16d3ba7f2d1828cb8a027af47ae436474a18044be6205383874383a8d83375d7da74f1d8712a0e47ef000000000000000000000000000000000ca6384874e2011bf6cd6d9246e2646c196cadd50f83099c04904df8ad2202a505dfd27fabb5f379ccaa09ca8fbdddbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000652959c0891f96cc7a7111c45987751fab9a770a9359b45631f3788e194be2c2d92b51c9de23001883e4380e765dc25000000000000000000000000000000001685f0dd8a0df83f80b5fea28aa9b13f2a268e85eefc8f0897986557696f3e09b45d39336e8d1519489c2199914a1df11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e4172d52cdeda6c4ea310036f5cd681766473a8074fe892e5e7c996d2306ba31198ed02052ad760f36cfa44d13356e0000000000000000000000000000000008a78e775c73bc4ae26a816496762a418ad517c7d9363504a9adc6a372b4bbaad89acd98854ef53d9753a5e0fe52e3781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e44553c0cbd43de05c35e6f2fd31b2615e56571ad1cef0c33bc6119a1ebe054f1a0e16e5a6e32839575133819f2508000000000000000000000000000000000a1619b47cd9d769daeed3a03b5fd138e0ca61d3243b738441a9ab1d770c53a67fcdc1258b5841dd207d591607608ecd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000378bb1cc2739a7160e6697b64b70cb8da96e51e1237bdd71b0240bc2c9000f70ea79d40adc691f5c3fcc7b29cfc78e400000000000000000000000000000000009c94198f776cc50958978fbca838b5b7b4843c94368afd038271af1d6525f9be0aa3a69334975713dba3ec3d1af9ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5775e28d3d774264be1f83834e20b6fa6edd5abf683f026ae81f1991c3caa1eef33d29bbe73142e0802bdecc63ed85000000000000000000000000000000000ccd2ded7c6997ad3406a03d621a13eb1d52e3472be37346ac2988c083be24763d8f44349accfc47fe6d4b83eb3b91f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018772447d2c1a35f00376cfeda5b719086fe9b4f6736cc1cd5db754b0d52a26efee34dd17fe7fc15bee160670c06e59000000000000000000000000000000000a019fc1101980a85e073e2159368eef1ad0de634e736b2b6f7873d26ef378e518cd08fde3cd8f2cebf21f8ec68bb2d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6c66d5e6eb6ee4151597a12cc5b817e271f2eb8ca8055e012efd86cc27072cf0615f93451778f8c2ce5dde551f8e30000000000000000000000000000000001599659829368b02b8b2f86c831dd70cdb5cfcedff2e6b189580d07c7ca67c4873ffa93a3f87d4e9ce5bf68f82648bcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085ca8409e7f94c70d2128054afe4b2629b47eb981f7e7bc75dbeaf9758dd8d276aaecf1acfa6e330ec123d6ecbb65bf0000000000000000000000000000000002dd3f77be91036d2bd6e3487455fde3a604e20a415c0d44183ceaaff486b650a13874cde5fb96b71423e1335c3b58d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001357f5a242a559ac54733056ed955f805a64c7e709ddcffd83ee9cca74008ee9b9f7997081eb680e8857c38cbbf6cf300000000000000000000000000000000016d5cad269366bb769278192e58804501ca241cb38bf46813ba03f5a769d08b3abaa409cd196b2df5c984141da9ce65e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150ed8d536c17bbc1781530f2e04c142f8ce0db43882acf5b4af05daba790902603a61195d9b10650fc6d6fc08fe198f0000000000000000000000000000000012fb9a59ed4ed98fea0187f4727d872039a0789361a3790e15de057ec35044eafb34ab6ef43752fde7863bf4099413cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005fad1994be876ee6fad506fa19a1fe26d3c4db6575d3676381818de77cd5cfb8323ea50bdf38ec1286291262ff34921000000000000000000000000000000001396fbc29e77693db4c3a87b4f0d748686fb5967903106313bf441d2e102b402e961569f96fed315f5ee76ba105ac6c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019706ae7985bec036ff8dc7a0f2939b3ec7c144022274f4b52abbf6efe6cf7cadaf86e0f890c4406a190c10d98bd4f10000000000000000000000000000000000872caf5dac41c43b614180929c2519932b8936c989e01f73363d08becab6decce3c8b6d9d232f4f8de9f43867e3f7ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123676021903fde800c288c07751d42dcdf66a81f069cb77134bfe2ae46a4a5e16d2ed54ce853723c4dfb16477d6e79400000000000000000000000000000000185b4be8351b73f3c8b8580942903899088f53027c8ab1576f8fa001a7df2b613dbffcc1b6d5c6eb1c35f40600b9b96e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ad1c11de98b6fffdc2e156be6bd2b8c9cdfb078a60cc341a2ca3eda413b40e702d0e7481538d15d24b4948b148f4a60000000000000000000000000000000015e373f5090e22d9a7c860512964aa11917bf752bb38c0e5846bd964ea4fee5f5ff3e54d640f0f8a69e5662520765de41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b76aa7ba46e578af7117d96cef107f2dcc53248842898a8bcac635e54f937c48d4098e31f9425381a533105a7ba6ab000000000000000000000000000000000f6d5e2211f577e0b5359f00879b3ad6efd95c5f74e8bcdbac49d35585c09d8d9b06edc248329fd4227d7996107799f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9b3d170bfb363557e6c2c0bcb960abedce7513986e7326788642fbc2440d71263b14609c7337860e1a49211f60e00d00000000000000000000000000000000146a70ea9a69371aba6a3b8f279ecf2b9635218e74a9619da30433bbbb48e71a74c06e79449d96ac4d0d1185589945901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c732970e5e602abd31f1c556685f4675ec100ee4a886b8dbe5be6065a8561a4d4749613e7da5b8b323f66da826b3690000000000000000000000000000000017e322d5c0e73bfff850c1aefe8571c57360a85fbc02babf0959686b26bb810bcdcfee06bdc06cf3e85baeadb11df1181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bf3a9821c43421e8e4e2d9434e2ac0be59acf9f2d9c9911ab999e4d959044ab3cdfddb612a6d9a7f2b4c9af5f9360200000000000000000000000000000000132a3eb5f4300f8101784f3bb53eabad8c63da291c6bef0724c0e8e4c36b7ea07b82958d59eed7d6fe4a528b3320339e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198f80f0845c2afa4ac513de4ff3279095d1f95000e011498a56a51f635817a7ab1e294daca98ca683b8bd44ad913313000000000000000000000000000000000844e125f28c30fa22563808593a3a2c073b937ecd85faf3bd544ee81088c63c1c3eed62876d4649a6852a138dd49b5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb4fb563795e532eff3e3398a9ade2567222eb423d8fc847c1ad52d580417df5eff797af7e2c0cb2c426bcb3e3f50040000000000000000000000000000000016b6f2ed9adc708a7cd01e836b7ec7cdd1fb6d39c0efd0fcab7c0c7ed276c9a613c142b20780d545a2423127ba0589d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006de44339406805bf245e4ebdc61ed32ed3eab98640e8732aef03583914b59a45a05c5215d2d2968e110e6d417d53f8a000000000000000000000000000000000ba92a232bf4220d955eb87897315d33d24e3bc7ae4a8e5d021c72fb189294ec450bcd358b41aff2ac6ecceb943fc62e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f93023d31931a212d519dfdaa5d02bbc0f2cc7a3e0109362f1f0a22e8956fcc4e2de382c3c8f1f7884ccc4eb61a4bd0000000000000000000000000000000019f23824162c49843d9d3879e8698cf7c9099eca223f4a42162d48c38526de97396cb33f7e22d2ac0ce8e3270e63f9391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000edb8be521625477270116d95266698f362e615cc5ac18bcecd8b6742777947229900969ee6495f20d4fc27ae57256570000000000000000000000000000000012529ad5e084293db07babcbfe97135a1e55d4f0225fa8dd9f009882cadbf5561abb86e116aa496e95d4ed6a4dc8aec91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc71e8386e2b112d2e4aa5ecbf7fdddae64b55e423b946a1599fde2b4fb2feefa318284ef81730f8b11b9d6317bc8a700000000000000000000000000000000124f45012789cb7e361eb705b6ac9164f3a0caebb66efd3e6f1da5636922ec050fb6271431663177d8af6e5a7c3de37a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000036e095fad73bcac542ec6a8b613305a193cdaec55366e186999d9ea4d7eef5feb195e8ed2503a5a02ad13037084775000000000000000000000000000000000699c63681350d469b3388d10d6c1b58550ffa7b0726931a1919241ed40b4c89b2b6ee89f9681df59876e0eac26b92911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001311427af3331bdcb1b63b60d9cbbce40a0b51eadcf67423953d4b7877b5abbf0b92b44d4185163a06ad19bd857aafe40000000000000000000000000000000001ffc7120e422d63ff5f54fa025211b329ca2507fe9d6418d71309c0dc3465253a203f5f5da32c25deccdd81cd2f42bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a890bfdc1c8e3a7f558cc7f74aced505c71a66066cee32c6770fa4a5de53123cecc3f5a1963e4fed884d4077a21e440000000000000000000000000000000009280b66c2b596d7744918db6ff9fab9556cc5baa96fdc2a5b3c4e2a3d72a99b1b23010f27f7782888b7c57fccccc7701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118872dac0cbb49bec69d60e7674a063fe23cbd0ddc80dae210e43769885d9f2f07ba4df90d4871807497f543421c00e00000000000000000000000000000000034ee1788085c4b83f683800d761495ddcc4d29c0c0684b0fa469f38905b768d13968df86cc2e6695447c7ac05a241c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126ba4331dcc1eb0f0ab8fba37e000433623d6c85d76e7d1b479957f07b051bfc605666cfd34adf747380de73a74de4500000000000000000000000000000000140ec96822b457b9e0990997d5d04186b770d3d0285b28c271f075529d143c7dc45c01457c3f9d2f77313e6eb8ecd47a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184f21f7c06b6b6ddc4e26ddd55f386560d2d13086df383d1d6d712494a6e4ae316a1389bf4de41f47175c38beaa670b000000000000000000000000000000000359239848314c2dd716497144b99b2e3bbe5adc7556ae0ed751f9c8a3e980a0cb9636609bc5fc7a7d750e12c16b63f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141f469110d069df3fd6c014ff5d90e030e312acf08dea6c5bab5dbc6962886d119a8e9554c2c0f953c2b2c35ecb9422000000000000000000000000000000001403c5004fea08c57e325f95c7a8bfbc9552792c186af10436d2a7a1ca38abf193483c90adb5adff22a42d7a98d36bf01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee3bdc697647dd57523cd1d7f61f0cddbf5c16a1495869f2819a63fe196798858e4f365561f76b50bcf12b5189a5afa000000000000000000000000000000000b675667fbb500f9d0d5037c011fef8261c4bdf19f240d6d2435d8ccd605a942003bb09eea045a23db055015fa07e0b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000756bc58939ecf60a2dd0349362f3cecd757fd6cb0710930e7c6c366d865b8cc90386ab6af6ea77bf95e36544fd102b000000000000000000000000000000000cebef3f301421e4d3a51d0478e3c6828c2d93c8b22bc2d48d43c8fe56727761aa4eb6297f58d875a1a3f6b07907f9b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c33a0be4ec8267b3e1606d1600b5d2b9343810721d68ef83b523744ad352d48f2c07be9203ffcb42567bcd0185cc553000000000000000000000000000000000f01c1a0f42ccad5d28e5ea88e55afa7f5e27764ce8d864aa55de43a62c5184218a51a86c33fe7f6a84300310e7ff4091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015edecc0c0c5ae51f0a100f51c6ffa1449303c00ca20db5bc27f5ec6114e4447b3d15897bdca99443a65177d729068ce0000000000000000000000000000000011e64459cca4411cd2558a15208d8c2f2170fb988e5857dda57fc0d93770d45a187f7b4578d5651f2ce09491e163e8e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121df4a58be6de716b996b3e06ae71f21ffae78f65eb60e0fabbb97185b985eb0f6bdecb3177248e20919d2ca8e19b11000000000000000000000000000000000fd188a625994994ef96b8ba734f1534b5b8c0c4744bd873715f3b701947aa297ed562b4c2002d3d4116f91714178c061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009dc946d71475881499320dde1727d19e897a096466a318b8047cbd1dc3bc30dad8e6ee17e698db1d1bee0b1796f9c02000000000000000000000000000000000e8a568a3400bd0150e8dec55c1ca3162e09b8fe26d607f34dff4bbde4156806dc58dd990ff47b95b90823ffb69997591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000699006917e93918d8b278098692783d16541c816684def1da3a0412dd0b5ec313e4045137e3193a3522eda93dfb70820000000000000000000000000000000012591eac0bf37346da8ae69b4366509383b5327dbdcc728311b715501e2e7ee8d407182957dd3114ca2ed207fee56b901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142ee4c1eceb85d789f4d2c55c92eec8e47ef878ace960f63896593f115f95267e4dde607627c1f56fc18db54df7eec20000000000000000000000000000000008048e2696ba3cdb362de917a86095084cbe79ff9a88bf1b2a2b1a75de893f77b232ad8a46872645c908564d49bbafe31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021abde2ff40b8060648493bb491bc5246213a619d76053e7f252e0ce1a28acdee1fa785e6a9495e1aea6c1dc03e5022000000000000000000000000000000000d5a48daefc9983a8bb4ac17c9d4b095d1d3037db2cc85d6513123a0cb2daf7597b102722fdfd38aa173ccff444af6cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef8875e376437420c269ec540133c5024dfdb14e6ef3af602dd0e3db5d0522c4091e052f49cf99662971bd2bc18054400000000000000000000000000000000176c555ac88b30cf6c536fac890c7a8344ba3a546a1afa1cbbce7d7e0f525c37f0baa782bbbf5e7506c6a1522ff6985e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c5b3c7e201e85dbfbe80a4c5da68275059f085d0b5cad13bafd28de796ecfb7de0bcfd8d76d2b0ee49ec9071f52b270000000000000000000000000000000008b107b3bb231c9de8a5fa2c9e9a6e06edf48b0deabd290340cfbfafe5e6b78df342f347d6643142ab817eeeebfc2fe81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144a740fbfccb1dcb836bdb7a75f59fb5448d8d763902ea6b0019def3ccf7a816b2ab7e3b06d573da2ae23b4ba3dde8d0000000000000000000000000000000017cc01c9e7ea6f5b805eb8080b6cebed6da203076ab2dc63b94dbeada24da0cb66ac1d702a7255fc3bafd64f2966f86f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000743033d7f17b223991e86dcc6397c41961e5f433d529e7b2d70bd802b23a300ef1216c6c2a6a08d02a42b30b1ece6ad0000000000000000000000000000000019379244295f3901b61cb302bd311f942888eb8c8144e16ad3c235f4324ce00d041fe88340f702b975c01017224750ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d471a3b42295c97ad955b5e8dd70593874a1ce5d2caa02caa8312c0041a9e91e150ccbb417e1180c6ab830c4a3615b4000000000000000000000000000000000e6bc984561df57e37468d6671d7875caff1484ab4bed6497ffb7a89d8d80e84d18da64115bcf9f616b8f103e1bc0f1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d3f37ad63642b66ed2261c48e474c513cb754a62e9a14d6c2b5e65e20d818b9de4e82bfc1c7d783c18cc31097c49a300000000000000000000000000000000002c3cfa6cccc44a5f59607352c64be7a25f85a4c827022719b84746e0154dbc44810d2af38d45fd20a178e546bed4561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bedd09310652582a972b6c668b7ebec95248e2d80e121a14ec1b004ad2a039e714f16cb3b4f2dce5f1b80e3814a7df8000000000000000000000000000000000dc9b7c86c7ae4a62b06fd73e3b3363ba00b10b9e4517a8994b21365a4ca56a7b967bf846b32a02c7ab616268f7a88031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c1e55e8ce0fd83bfca9a92dd7b07e6119e3f99808ea1e5ed8b4b8ed2d34d23d551ab5e317603026c36b1959f0b8420000000000000000000000000000000000087bab4071035bf9a68232467cdfcca2bba846059137b087a9f4bec2325ab9626451c74c0fa910095dfe8fe4d85f3401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e7143af838b07482810fe089e51a04bb457257b86f85ade1f11a9dea8a5ca8b83dd5e1052214297be23fc218b1d5700000000000000000000000000000000004413957ff81bb49e3e61773bb4c794af304bc91933be8a11f5203527ce7a57489bc97e3220186068b2b5c88d853bdcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006be0a42ffb60887309a9886eb1185ac733b91c3a3a11cf44b5de0c9ddc20e5a7851d082982f3f7df0d8e5da64273f32000000000000000000000000000000000f8c8ac95226472a9ca4450d7f845dbcc161dd5e8b589c4a2b999af3ffc8aaa2a6bd9a487c0351b950ca5f57a959070b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6155056136afb4ac4f970944df93ea3b981570ecacef2fe636454ac517da9da4d0d124bbfedd40a215dc3fa565b3560000000000000000000000000000000006e1be9e5aef1ff27b5b0a82075d14433fe3cba0831c145a8f491290e9832b474f4fc343d1c44bc23a8f3a3a8d020f2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154bea7b1b48f22e10b6f3c71d876fe840d441bbccd81ade8e8781df2d960dbc6ee2ecc8fbbb6e6df68830cce3add92f0000000000000000000000000000000004042735cb8a5130597991496fe9964167e86f60a7417d7b7825ee59b3e2e6851a620f64424d9193d9fe56af71578fa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6857ce8a394ba8d4bed54de6ee15b513640319be99cfd7b97693695e1270cc4cb1bc6939b3e78d04cba8c574f3a453000000000000000000000000000000000a96877018396e1a439d4e2718d66518e19919d19abd89a730053170f1b9402dd81c79f175a69c10153d52dda53104821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012211e8fdcd093bdfba5de39140cf8c1f502821969daa3c235143360e96c769adc12ecc839aff67bcd14e9d5aa68c2df00000000000000000000000000000000162a49e7a364838b23dad9bb32d839cb9c92a5e8e45c58bf18ebc425c27b8043835e56b2429f8f171851d7ea7e38d3e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e53c67ca7f58bba88dc6862e3522b133c37ab09786faffbf1b6c8fc6d394a02f0aaeef47982234f08b19705377188eb0000000000000000000000000000000009df642dcf69ff4224ae0e9a55b592c0205a2ef81afe9d8b39df732b8298dd6496a4f56ff8ae2d10ec1129a71e8459a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074421114956cc5a2af15df2dec9ce7f0e3ba61dc59f5319755a56595bcfc949d68626829fc333d625468c32f1aa9f5500000000000000000000000000000000065d96088d236eeb78211e3505784487cc7a254730e0843be579f317033a8699891c6fee1f7d64149196abc5bf9f38c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003dbf699c6947e098aaa9f4fe273dcffab86cbfdb13131ea0bae4b3f3ce134344b75f87992cb9be75ecb1e246e0f72990000000000000000000000000000000000cf4a77292c2be26a87d3bf7307d25a1f77d961b0143de455c940f885f883f5af358440f133069a74d0edac76c0c8ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145397d8dc6523a66d3081398e9799e965c787564cee729636d9b883711576ae85cba0d9d326e1a13df8231dca7eaccf000000000000000000000000000000001490e2a58cf87d08201b662a8dd4945dad713708e976804644ecf4105b25e313ea041aa028eb4ecc58404adb169803f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001268ff3bcb8a780ef75049eb120af32678e220a51e19d8bf09ca680f69770c166d81c401edb00676482e4e14c0eebbe20000000000000000000000000000000007c3836b848f0f3177b13a6d7279a54999e8151eb02f687d676d7943b85bdb4171615a21075d1c3c1a264e09c0217b341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000145cbfecf805c405e70c17af105e0ce724218fba898a23346ab911be56f551d9fbc4e6d75445466dd0a68f7c0806fed000000000000000000000000000000000624882a3c7d8d9e09c438646d7725ea9f6f0cead1f87e5a118cd73668054793302b84a218d596b88046f57f2dc80e7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013217272b0f15aab22edcf834b5eca759d83e2383c0fc0250e1b944dc74507570d0e18da1ea212d30e477cc648faea02000000000000000000000000000000000e50a2713ac88562596d7694034db5c0685c1e13052cd2226f2c7afa41e38c368a849bf12a393c7a50df9c0dc011eb1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004031ceb53b3f4bb8e8afb24a55eba83468a7da43c474d86c28df6857a8e667825a0d0204257690952e75cfe616d2e41000000000000000000000000000000000e0de19d901da10cc9fe49c4cd9fda32ff7588dac593e43e5b672ddc4d6c856e5ac467bb167fd70cb5e7f38d1dab694b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c533a89904e447c5a6999108f0da29d0fd6f2aebe77699f9c993c7b71cd5d79233ce4e83821ad19026a8d7acd31efd9000000000000000000000000000000000364da713f087808476fdcc327137e7e235669a89796b900360ce51b939b847c25f8dba57832a070d5f364ad522cfdf81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037dc84e2c648dabfa90ec7f5c12f92b50b1e77eb986896a706fb249571bdf70dca2b2ed4a53e03b163652ba5f7d8cb800000000000000000000000000000000115ac87beed0b14a51da62e21a26a1d83fc824e6e291d102ebac2ba218235e8163e679bba80c4ab08901e9c52978c3571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001815c2dde829f569f1df0d5b7b29452866e783bf8e519d85c106e29c8d89e96fdb10a63b4df4147b7748cf5aedf0bfd00000000000000000000000000000000015ab8f2ea66c2d751f7f914cb0eac2ce2923a6fc612a5f93b197b692f501db2853028b1bfb76344f926603b83bbf000b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e36c68bc2bca54a4e3beb25401933b663e7599797c00b6d870fdeca9c4e1a4554c612568c37b24b3283020d3887323000000000000000000000000000000000b236c73422c4c69a74f5a8d7327bb73b422d7f4ca0866c7d67195afa5cef5ee122bee32045ea5c06f528b654409c4f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001157f02500f6aebd0a26a8fb4ba6bc9f05e761ad5dd8fa3ba177dbd208821e6a06938eef5841dfbb707dcfbf66aeac8e0000000000000000000000000000000018b9ff3d924eb50c376c6e15a0fa0b7383553fcc5ffe8c62df52256e206f497e5fad8c7d22717fe25dc8beeccb3fe21f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015c765d8aaa1a48ef97fd64fab9ec998bb9d58f2ac4addc628e517f88d50c5f2c7248ad7c0cc208fcb0d81b67be195f000000000000000000000000000000001752a28b5f00b7995354e14af907831bf47b591d8698abca0aafc2d13c2457f7a670dcf1aa869572c59fddf7913c31df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a1edf4baf0aa8cb4687e41d76b45d63c31825ab6ca398bfa93f2e4c8ee16ec551cd1d921ad7f32eb47f8747cd8b4b00000000000000000000000000000000012eb6350c10527702bf8e1087a5a518416ceab856b42176e3cb91a1ac10c414e97c0e26c62e739398d0121d68be98f441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c807fd50212c39028c4813f857a0d79b7a1991f1c1234d39d9faea31ff56f864e252d0bdc02699ee4a103cdef9771c00000000000000000000000000000000084a04e67d374e089ad70f1744d0f7d0b406da513f81bd902eff34172f631abd40d528f28d08e60d75b95610bee3dd521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003dd9a7e0634c87dade48af5d5fe8b412cd18ef5884791555e8c7578c2fc1a090158bfbc22fe79ba1f68e402b03f6aba0000000000000000000000000000000002862528ee1f242c165f4c27075df4e376366330b00706aae5670f44c89ad101f2dcfaf9c5cfb82f0582f5206f101db51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191b47e70106c153e3fbb1c5f357c87fb0354773cf68a7a2a7df9760b3566b2085991859fcf17685bc29f68b534d64440000000000000000000000000000000010fbdfa29ef21f220641470bd3e73d1688776fe8c5077a3823e573aff799fa4263a378e4acafbff41433c5fdb539763f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9a0ad12870fe604e27a84c5fb23bbde6aaf57ae4de644ac9b559b1360827fbf99c85280e7eba1bf7a497f849c4a0780000000000000000000000000000000002509ff06932995092c9c7b9b026c08e69c81ba54dad2902fa5930d681b8eec4b7370c98aa4a42968f5f1e2ab17dd2571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b986c21282f87f2f14d2bb9166883c4399f96a72300b97a391c5eb1ab1d72cbe7c9a997122f8335ad1800ddf8f62e0f0000000000000000000000000000000000da13981618ca2f7bc9dc171f60e74ff57df21da80ec36493020d69075d8db8e9a91020757f7493003261991c633e851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eca7d4d7313129ce4800576af1b697fdc4fbfa3a5913738c67d6d1b383f52901585db9691ce2821217d8eb2194d8307000000000000000000000000000000000312f82d57916cd0ae1e4da8faee30311da773b2e8e5fc880952aef367bbd56491811b6c6e01305a5c55b7edb7d6259b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001069a0f057410ff71abf433dd28d879fbc83d83777b963cace91ccb7d49497c2ab08e31d57f708d98568650c33abc0fe0000000000000000000000000000000005f01f7b0333297a3197722396e3d0b56edcc0e3caf393a602a71d8520fb86a9ee10c219f1bb193c0c04874848bfc9cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2edf6e6443c88fff071175530e1efdb48bbc951d24449b88fafc714d6faa4237d7777fb6b29cafc02cfbfd02bdb3da0000000000000000000000000000000017ee7ed5d203cf97240d0f0a1eea42036de179a54b61419a13cf6643b6556d3077ad1d532bc7535c5b66c70a87c86b4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000619be43458cc61aa6d06dd850a465c9a21f4527d4ba34660602750ef29a2c331fe083199f3caed0275a67cc89082cbb00000000000000000000000000000000127ea18a27643b8686643e889d11f712f352bb2ee224b2963fad34840f3eec0dee37d28e6169894c5c45adf99e5ce3311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8d7f15636e7ca9c016d82cbedef1bc35126d38bf8907640ff4e83133f6899ae6adc05830a0b02aaf608dca9e3f51f0000000000000000000000000000000000d43fe091ddc80f4d9f2506a9e4c1e75c7805a94e634bd18a267b1357e1fa9e0e4deb2969d7067db6280504551406d091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9e0ea3e9660ac5ea57500cc5bf29fd424114e47f6807bafd1f17e924c947fb29155c041517f159ec4596d13f6862e4000000000000000000000000000000000d3be5e76cfc84d0d9b6efb08d4a99bbf1b58077b3619a0f194c30e1d35ee38272cd47ada08819ed94819ee90088dd211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001828908d602186306ef8ce89cfb963f03381cd4c81d503a18518840025028ec7e1b8a8d386db3a38ccfd802ca1dcf98000000000000000000000000000000000d305699635b6db5a40b851617ecdc0b5817bfc44f8582582dc6ed6738e55625537935435507b310c3c4e81e5da008061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154ab34c4819decf5e23bb82cca28ce96663d0ed8b51e4ab95bb98e5ce8d9b398108f872b6e61cf8e33836f7560981c600000000000000000000000000000000105585801dfb130376bff41aead33aa29cbfc475240444ab433c46cff54feccdf7a0dabf1ac273151ad9cefe58e2d0771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128a800b0b2f19de244dfa3dc94790119c44b8fa6a3e4229615b537c89586e1d418a762fd342858ebe6de294d194ee0600000000000000000000000000000000057931bc8a3b17d8a120aeeb1b966e46d84039b998547d09485d8631ce773edce7557f9aea830864c2de8169aef7d67d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001007f7600a3d4d66199457f1365f59495fae9201cab61752a094a7cff657772bfd62482de69221ca2636490b62a100d9000000000000000000000000000000000213a019ef9d7fec41304122079c33b7d0a5405aa42561426c39131714e44dbc0ff419feb2e5d26a92da93f1b232ecde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017010a3a78bbfd11e198f3843d88e430da71f413fb35962d9b36fa1a8a829fb9f47cab3bb9b4c5ef64025b40a8593d38000000000000000000000000000000000a127c02042f8e96d29751d4f8a4441be2c5bfb2054a4fa511bc06223aaf2fddb62a0ff5728b6f578d1b8ffc251d30fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c890f992614742590462417177bbdbc2e1a1273bba99181cf2959fea95d54d9f64d5b1136d34f62e401185aa245a2d00000000000000000000000000000000019d8c91b8569eeb2707c221b5bf9211daa1274cac523febe10b7c2a187d3d9f1afc6100e94226e9b5512586073e56bda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010866fb0c77bdab22c854211f853eded9a75b00a389b5cd0895af62ca46a67b74cef149260fd1b38f6d7b6a2417194bd0000000000000000000000000000000013bd86e8eec9d56c659e1e75ff788234f045d86887832ae702ce55240e2957dcb42fb5e2831a854ffeac5e056d420ad61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004cd04cd812ff178037846c102bf819a4c6abd1040b8f2da0720e790ae5e185895acd379013d9c8cda5eaa491dabb78a00000000000000000000000000000000015109df531c7b44a2f0bc1974e08a74d73544c5110278a862399866d1caf93161ad122a06931d31c572ae9fe3dcef591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001568e628441de2ee69238f1bb58695a8c55a8ae59d7f9d3f424c8c3007069134a9f65ec72c644d6c6d82790557378a400000000000000000000000000000000019fb7aa527b58f83180160977f946dc05a40ad0d46073488cfb0613921524c6eae4c6be89a103c043a0539773506ae301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083ef11db3f4279f4be33887d7b6055c62a3ae0e7434e85955cb18243686478f709dc2b4cce44eec020a427bac4c74ed000000000000000000000000000000000b6eda2339e19782b7c6558d9ee1110b1061d904fc6b239eece067bbef122122e5c24e92ad8f90655240ba7827d1c5521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001836767c24d768cdb5240ac0f9b700dc389fa2cefe2b458d3bc99ce381a40bd8d65c0f179e6d3042e2a46e9a9f964f1100000000000000000000000000000000023548a51d397503267a767d7c7b9b590bd15c05b76c529a6a2994ad3d78e3539f8d1db2c080dabcc63d0c7a58276e5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd858559d6e083305f03ccaf363945aa0be4bd1381cc3bd09412becc37bce0b54e30e7278fc63c4c3a6914414faa65f0000000000000000000000000000000004de8fd554804adf28e775b975100cdc3c1db1566d7408c4dbb0b4401f3485a6171150f12fdaf5613f7a5f8187703e301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ce85e6e6cd40dcc83ac267549bc67e0d01001fc5af6175d5f97dba809f1e433c69c123ab71083089e2cdc88a88d32c000000000000000000000000000000000b08fd777f1f88fb30f1fc81a43a825da0cf8f983a94ddbdab75c42549e81d7662d4de1c2bee7bd74ca318e7b17a41f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000114895cb9f757500b7d5cc8ea6ad2b7dff13baa0943e25e42a5ae2769ce484f1fabcb58dfc1ae95820599ab7be718df0000000000000000000000000000000005bba7d46bfcf867e3d5dc6b84ca9c645c90318e7e1c47152a54639c733e86253fe68a1b2b663fa58fb24b8043829f291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012630ef0d437be224ad9bb9b9c567e3a4040799a4f69af73a9f503947cf23f6d5f567cd67f9ec634ed7a088ec02145780000000000000000000000000000000018c4dfc51c3ce162682d1009f7bf7123537efe4676a8a3dc08d79ee626bdf9a876bbea1b5bf39cdbad5f391f60f920851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc6f41294863036193eebeb3e8e5c06620e5888a86aabaf4569fc2eefead888aa17c9643f8b63785f809b7b5d34bba600000000000000000000000000000000016ab14e90cd13a4b2a586f9d34579ccd4aae3b026853915a03349984c3bd8f38f43b4cd4618382942db07dbb07160661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154ea69a7b8cec7219daa470c8d7f38a8668dd9446bcd8c084d014875cd04a04ee3667e36a55fb7501bde672244105fc000000000000000000000000000000001544a6ff55e51ab1cb89031f9028e89a6ac6d015dd686409c3913972fc207a72c3878fb1ea465f7f1b03cdaddfc8f4911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098878c9c736a5321f596d9873f0ca50dd859cae8056c19ee69b629419e5779f6bd45cef6993511bbbb68f40bdf2848600000000000000000000000000000000193103c5cdb3f7d5541b7b3b930ccd1b84a008addb6c0f726774f51207ed1f30680fc59311f70146014eb5f0756cb8eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ef09e8249af0e60c11e76d088671e2f6ac421e9ea0e9e5d4680be885171a698881cfbcc210550fd015222a6d4830a1000000000000000000000000000000000bcef87d0d39b8f828873c909ca31b682d2ace7e5f5744bbf5086801d0f3ae35e1e39266ec683b47668b6458640869b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016b25a4f3091cd3261d7de0027e49e91b8bbd6a464e3dd586a12f1dd77ab75b05e7d1de349cf47d545dbd77cb610eaa00000000000000000000000000000000055f3392c75a8c638a5146a6b001936bf6cc6d1dd39e8009d881ca30c7065595b5c75acb53a9dd72746a880aa06e43d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c229fb295e892fb5fe971d0ff5bc74cc36dfffe0f93d90701d057a43ecc4943e9c3e8ea744a983ee6f5ce49f8c4ae2000000000000000000000000000000000120195ccf1ee4e740e2a0d363aebb4dc36a48f623f70dd8702e2ec308e56f7c80c9f83d86083c7b366ba1e5356e6ecc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dbc848e6d74cf58b9e3127cbd9a4aaefc8128fef7e9a43172a3c7522829e3b7fe3fd078a0ab849e2a1ed5b86d417d44000000000000000000000000000000000dcfa794e0f7ad565eac0e7b9f4992e8023471456d34b35dfa0dd8ccef832dd2eac3c9877d0d8a5880ee47577f71fff11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143185db8b76f85ad930c40db60c7b92fbaa0e85dbf52fa6e526664b2f33d3a976ed4908d195506921a770d5319f386d0000000000000000000000000000000012b7556f604e32e720d012e274f19ad9a8f99a8204a2de33d99979f0b87fa8a11842b04c99276680815fe413a72470981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1f316e66c849299386f00d8db861d9f36a751470700d4873134468401cb71930382ba6f1bdd311b07e9303d22a6a7200000000000000000000000000000000150a097559fb85c34728a9f0e778e4cf1c21e0c51a99f74440bced814f0e4374dfb91da4d54913060c78f9fb2e04d3011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c678fc32fa63b7a7dad518f16df22cfa0798ad21cd01004e0632bda4e90039f4227b5ad4073e926b9fddbc907961af0000000000000000000000000000000005a612500d21a7b4f9852e87052996b888818abdf4fe4465559e74b43164a74a1ad13988e2fff6a49910ba09fb80559a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a4ad2a8aa1b661529fffcc23c3e68d5f3aa2ce7c2e396981bd9c4738c91d037856269e1a8c0a3c7b1d836b41ea26640000000000000000000000000000000010abbae874b42673f1f4ce0b12748947bc75b3f14d42676c24ad538845c3bce5bbaff7d5ea119c5f6be951ebb6638a761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008175cb8e6134fcfaa4aa15f238e50488b7197afbbb8dd0670f4141d49ff7142dffa3779f8f5bbc9c8e460bd82855e97000000000000000000000000000000000a95fad49bf16d1378b2856f930877644fbfdc016834ec2c1b983592da9ad7ebd67ffd9c334f059f584b26e73afe36ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f869ea7cd4d94c006778223fb70e1ec9d0a87f0ee8b7c240b2dc4234bd01e20912cdcdb33f166a4d706132b394e5927000000000000000000000000000000000185304fde25c4f9859518c888dfa6caaf160b352cefe8c54b1e83b92d3a5489c876695a4c094eef4c9c24990eadaf3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066daa3c6dde4643f10d5862e3641b9aff43a03fc42846f51cc52a0ad325e4d68d9e83be1564c3865c5e8fc872a4e31c000000000000000000000000000000001614a8479a4338d804b785e3ace73e12ce2f04cb07ab493c336efcf78e9e2fe2fa0e35d0693876af10a40ddec21dcaf31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012233db40a14d7811f6ecbaa6e24d11555747fac9cf2f36c88b72f44e4075352c511dfb73ac76a47545f342d4f84404c00000000000000000000000000000000122692bdc45fa1c0e8c3be22c9f91884efd19c9c76725e755c0225bcfa6e64f07383577fe69b87596066e18cb59fcd901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d994d57e90500a0884a73d4dabffc7df8aaab82d4585c9b58000f9a44a25560296206365de6944a6790276266ead2e0000000000000000000000000000000016aad68acaff53950f389709377f4f9e6d9409258a1eae4e29b04d094dc266b90288587d7c5b2388c642612b39abfe7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4d7c713712fdf7ba3f6d20f522caf6419dd6a3ba43c4aeea8da0d0259f5a2f96a039b98b29d42947391520c2bd137f0000000000000000000000000000000004b2708fb0f84dd3d248073ec80d1e7fc6b6f3134dca5f8ed25a50a7ef73170e146c6c08fc4adc2f662a844d4c8e25861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c2e2d57cc7cec793571e27701bcacc7d3bde470ee8ddeeba0741d15fdac4011548d8afae9eed76a41286446155d40500000000000000000000000000000000195889feaeb2575fb1f663bbacfcc18acedb14df2645ac64a640df667235795817b726db68d69f5d0d63c85cc7cb82de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c47827f5723d859693447bf7185ced38cff1ed839846c910a107a42e1a047fbe202e0cbab8844dca58f8d5266df111d00000000000000000000000000000000151f495648457ffcd1e7d7be2e180da1cd38808c1bf9d4aad310bd3486095df2051b99a25fb035fa90796f34b47e98701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aae260574bb6da71056c3c8a5d84200826b6a97abe867855182e8e6e53cbe19325502ded340269453292c3f762585620000000000000000000000000000000003cf6d453f059779c878c3a01d390c995d122bd80d5351092175742cdb4a1ff166f674c457f456518a47876a73d5dfef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ddea6f071371f56a4b2dde2d2f8219cd27216a569de21360824111fcf24f3457ec8e6aa2067811819897e9def6fb7200000000000000000000000000000000121d3a14f0790b17b0c968340ab83b1d784d2c48b09c779ac250d6c269299be964f277d6c66ed59c068adcae41c6ff941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099234473ca20260b0398b2f5ee78c2239436926539c448b43422a0384caae2b334cccc008076c07e9de60e4127eec350000000000000000000000000000000012aac764870bbf5e184823bdd565a27571ef67c46cceb8acd28038abdf3a420366c6736fb225243ab7485ebf52cec86a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6766f7a792838d01dc24e54b65a6da5e052c786d04950800e04e82f6efccddfe911653c9344b61998cafa905b54dae0000000000000000000000000000000018eaee2ceb76ce13300c9f0feff94c55bd7045a53bbe885641664ddba9fe816d6cafb96434019bf5328acf3a337c13741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040eebf62e09bfc901443082876fd3cf07bb8c53c0a9aec1eec96cf001f27c856a379e659a85dc9d3f24e12c334347990000000000000000000000000000000005f658ea599eaed57a0e7938399feb863108de0a1f3cac41f432c0fe3300bab4b6bf2f846f3dba035ebca8fe0fea68b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001493580df4755e68bdba31105f2ff22b975b84d1187cbb40c2de99e02be61e78d629d29476b0a2d5cbf2cc0bf3f0829c0000000000000000000000000000000006d2f4206a52f8b1c84e2050a84b98746ff613d3dc3d5273a7d7bee924d343bc760b85b80140393fcfa8085980fa8e831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4492c3209920dfb86c1406616ea4919fd725ee4a3f6f8457db5495ac3a225a9d522a46e0d13973adf51f8af3c01707000000000000000000000000000000001252873b9fd0639be7f39cdc8a79701842d3110e4339fb2447e7fcc39c78059bd116c4da60a3a54a57b4dec0a59870481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b3dead7f62ab4c21aee71e55b020c8314bc24a325d8e71da810f706324201f4c96f99d572f118c29d9664852fe664d00000000000000000000000000000000085de1c80296a4a56103c5c47afd9160023e71cdf47426fa26ce7faadc802f4b776412dc4b3af445a13a1de6a4f8fc0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013432280dabcb187702a74039f51dec08d36f4856670f7df1c55b9edc0fb091f6956a4785d641c3d39afaef155803ce000000000000000000000000000000000948a4aec824e5219a67bb281f9f907e143e279758597c14ec0e2b3ee9fe1ec9d0ace4bd4cf16ec4e0f75fdbe6e8892f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035c5ffc3596c329582a89967e8c06639b9806b5f741e8cfd2ee13b806906e01742772130f5670ac21af059ef796c177000000000000000000000000000000001028fe8e131bacde6b81cd04f23aab71af6b8885c82e609bb285a8227e11846ba84024fdf99a2f3deaf2f6384d1631021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001875041f25a3300503986e7e0ce56398aa7ced078b229b30886ac544a3f874a22202d4ea91051b50c1de44744876236d0000000000000000000000000000000018c89626221d6ef6e87a40839ab4290306da65fa3ea9838cc0043a151d8cfd09e6ddaa9fc2f0b1e26be6a15ecec31a7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f8b148fc49ffee4b2239cbf62b55cc7047d6632f2b4ca3e49d7e141fd6a752b2ef24db0850d5ee001df02d32917b2300000000000000000000000000000000077f46d2e90eb6343cd42750b8149a8c530f04bbbd6a3cadd6272ed1ac135bffb7f809388191e04f0517e9a2a2cf6b931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001886c741014fa20892453ff11cf4ab340833fd11de79f9f1cd637be12567286b1b7ec1316ab059285dff91e6119b83530000000000000000000000000000000002b5a460276425f38083a161bf429de8824d5d7e6490876595c2ed8860e40732d6c14ea5ca2b12a56c64c1054b4651ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bdb73ff0e856603f9fd7df55f376ba70bf4d907a29515f5ead5c6a4b07f4e5b923b8a78418d4187fd76778a03475710000000000000000000000000000000000495ee67bebe4fb0ad67dd591c05cf52f983ea6337ef981fc2bcbba94af3a07f10e72651158d01704a54218d7c7d70591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005b1a3a01e8ea884762181a21e6d60b8043f30d983d32fe9bc7c4d1626a3881c29ac53f18e0f96953f6fb08b2d245674000000000000000000000000000000000d3574de3d835207863a04ee677559ff0dec0f6ef6fd1017c2e92614670f6a675794df2ae69e6a7dca46033961dd3f2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000930375014bd014ed2041793ec4c9624da85ff3c175cd4c24ff681f0d98d717a6033b2f9a568d483c8c45295278c283500000000000000000000000000000000074ea0c9de9f5bac5eb796f43f09ac55c127199da97cd3c10e115b8ff7132b2f58457e26c2686a4d312e9073d808b7451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffb3c93d9a328c17176e83e9b713c5571ef4623515caa1ef14996c61fa1958dd823c149c54063d81356c80851f976c10000000000000000000000000000000007fc21ce2a49e6212d06ee39346a182234d870dee57b561a1695c1ad6971270084d760610368b3b1f365ed0d829e3a6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca4d580bb1a6a1ad9fcf2947056f1e8bcfc468532bf22a614dac94f5791f9cd8db4ea371a3c7d896158d7e4c0b0a7ec0000000000000000000000000000000003bb0a5586ace18cee632a266f92f80eaaf41d9157ce11fb709a0f6dce067bf786649394291414d8ed01058e0263804e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012105eba9cc0d1781c546d89d8e0c36aaee958837d78b00a57afb00fef1e962afe7367be0c66ff963cbe5d2252f4a4060000000000000000000000000000000015a23392ba36cf75ad14d9cf6e16eadb52c4ea83b3c7e668bd50c1c08eabebd0b46f47d37f48ca2dd80feba83ae7abbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3568497080900aee6088fc2c1a15e81936d4379ab1a9e93f9056b0c9f1c9b494e41f0f3630556f6ab63ae542d8321a0000000000000000000000000000000011d974c8d02a8a92364d66049e9e49fd4a81faef328cfbf4b471d6fde8a397b50e55d040059f493944134e33889c76231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108939de8775999e594fa333f249b2508db217a0359b6ef1913f2b7e8eb7de4d125f41400a0e42451e63c63bc8fa2f3a00000000000000000000000000000000181097890c21da497449c563a6b79658f92057d3341bfbf0348af59a86c6250592cb913418067d80b4f9966ea03916b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e78dafc7e44571c92889f1290817e9deb13fca0befba6d10142d02d5eaf83435127c35c9c0883d8921be43d8bb1bc330000000000000000000000000000000013ec88b3a5c989cce81e016396f74a3e36938ba26502f0566361af474918f8a9ec29a0e3ee8ac04b2235dd380789e2bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a28f5d968e7d53dbfa2d05bf017bf4effff65477afb47fc7fe77a402eafa3a199d04f5a9ef5d3441a5da0e9b201c27a0000000000000000000000000000000000d76e939ad10ae63441193699f1ab63876fb06eb9b1fc9a825a3aa3dab34864513bd8a0d1d2fab7e5238498000f71761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000138d6ef41385e1d5bc36821a7793e048a435bd8937cd7c1105b58d406a1783a988547ab4a0a7468e022dfc388eba4f6000000000000000000000000000000000f2daffe9319a4ff8a0f576fe616e160622c1f388b5bf3952f707225243482c0f3583709d8f58b73cd0e8ad0eb0cbae61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0aa5ca109ed4e94f2797202b16b62a988ad36556facbfe8fd4dfb9d487e055d67d456eb4542e29b5dada1d465e602800000000000000000000000000000000004607f9ca1ad5fc1698046a1160564ac6787fe944eb7d689d440a49461b67cf9e4f6cbb2d9a7c0f0d50c5153fa792e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018db9f7ddbeb66de80b4c09f7f84892f426003e5461f3b5607b0fd9ac3bc2565403ae59e0f1505c404f44dc07f2f8dcf000000000000000000000000000000000ace3a9b7fab0f174d8358ed3c937da075c41024fc14a68de172f03b1ecbe0054da269c3258462f595795db1e2879dfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b886483d9b0c17899ab7803271308dc30749b57b536ea41377e903b9f59bb072da4d3837fbba18750403de69a0cabd6000000000000000000000000000000000f44967c5b5b5aff09b48765817aeeedb150b2fac543d63d308ed1e290703f10fc8c3ce3033aeecbe54a10bfa0faa0211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7219b83db0f9fe6d54bc20ea95b22ccc6b9b0d4fab1d9a1ad77755d6f6e5eb2027139e900d6c4a43ec5e4d81516556000000000000000000000000000000000453587fe3772ee344c90e8beb40f1a6ff512d83ba8afb89b4cd7ed0e2edf2d9a5f09f9dee3902eeb89552354fd33fd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e079fbbbdce1c4b6916cd4e286a7546d7d48e2addbc476214cd6d73b8fc7b9e8ef9814222c173b47bf99e5793eceef000000000000000000000000000000000c36cb0b1d61103aee3ba4302c74dc39eb9746ca547aa864176cf555431c2f84c7d89b6b5b91def85bb5c78dd0626da11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c13ad4792dd1a367294b6e23ef25bf40c24541708a0aa8732e3e00d3110cacd4ccebc302053a195b6a939af3cb01a30000000000000000000000000000000016e6149eba722cdfb5d093ab07fce6ef56d6905ca701bcd3ea5573016be73d55d02ad45ea8f291a1217509097f0d03951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cef392b1866ee3859cbb6c0984a0f1daf8be64b10ba8df55917b56649634ea6429746110c2279ccf7a6620e529a9f900000000000000000000000000000000002841bb1ec89a8174a530a5be548c5b17f49d28c3abf5ef2fbdace53b26c57f86843611508d3c6f4a26fb4c9ba3d6a5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000302211e4f02f5e66d923a1d0099c47d5cbd4a52cc46978e3e159f93434187a88778b8bf6f9ad5209d311184596cd805000000000000000000000000000000000a4130c234052eb553d08b9e8fd5cd3b89a3ec4ab4effe73fec180b807c27cb83a5e8185008994524fdeebce1ef1db571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189e798158758e16e400d73e83c86ee246f7a96850a966a823910f768b043e119cf29bdc1ebf84f11a1c4f4cfc05cb6300000000000000000000000000000000081f772839b0cf02a5e6bf99b72f38e97db853dff6f8db59875c72c08a4228e3083477c86bff5ff1c168375e36c73dd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a4ce739ca82b934419642a96188df95080a5f292b2328a33508aab93df98cc3be4af12bb94df30e1411b8bb73905170000000000000000000000000000000015d55141c4d00b23c8b349bea0d27b74097e15637dd984b3bc8937e2dc5f984e2cc268009c22acbd04e56caf36062b781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9342387c9f761bd6898c0af02588b8d7818e0b2a03202555ef22dbdc4714220f96faf3243ced0f8919ccbc449ddb510000000000000000000000000000000016370ca022f1ea2bcfae1d889ac7e2ce2bfbfd95d86595b4080ec4bb2be3700b15895206efc5c68dbb6fc9bd4f81b6371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000435bf7116b62f44a6d85e355b71c3660272fb74aef730f85386bfb38c11b2084d9e72d76863be7fcebf368746df5c0b000000000000000000000000000000000a9f6b1de627a140fe2a8ad7dc21ea25f0a21f528527a48ea961262d609fbd1af60f47931b95236d693141bd6790022a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000530acc675d5c9bd8d592d982af64af7e60a72788e930581cb7293258db1646a4c1ff7c2ccbcff5f606b3fcda4d246ee0000000000000000000000000000000001f7f8bcf4c62cc47de86ce3648b73a7f50bf86db8c2bafaaaae8dd50889428b2ef92dc1f5a1151b3d146b98832f1b4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198e840576e44e2338d6ae9928bb4a3c4aea152cae033e221be9720444593f68857b4bbf810b3e16ebac64fcae3fbaa80000000000000000000000000000000017b188bdfc6e4ff1e46fbcaa9af3e1f5c397dd8718a1a2a71ca3c8fba2283335f894bcced59f00d7d97837673a8eca961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1e8f8d4cd7ef39895df1f5a1bd3116c25731af66ebf6784ae944a7f0adb6dd420214f93b2d3533f9d3f5c089925bb50000000000000000000000000000000014a43754ad5a364fbc16c04e252a8122f079c224a06921399d400c1bfa47905cb532161aaf834da2cf424623ed328b1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016eb791c11d3c4e9259fce002dce0d8c065d777d3a00f6e36a86f734272fa230bf87553e1a805dbeea2124b9d7a4c1ba0000000000000000000000000000000006e16bf7d0e5879c276ad0362e2129281520ec9acc0931bf87f90470fd0d8ca71a75954ec6b8411acb5bf478dac63d881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a3c008c7bd09f84f9d2e27bbd0ca37a90b4c46023336e22a2f7acd102f1c5c39c61af890cc4b52fc269919b37decdf0000000000000000000000000000000001ed0a323bcada851055acfe683ceb61a05561c12acba4a04f4965a87d07a7ff0b09c35127254a015a8244a39cc3cfc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001243efe3b1f4b9045ce819cb5f05959a629613fde94f21543b68a38c19f478d16b528bd0440e9e952318a6c5bbc4c8ef00000000000000000000000000000000065e968481d8cefe1073f66c80c43a013fd48358e9ff8b2b4fcff50f494169b3b66a2a7f60f281768db5a6292882f3ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031a84a336ced048687ebadb75b8c3a199a59e0ad7870c707257b6f3936692235316149106cf706c22fea2fb2dcedbdd00000000000000000000000000000000022d3239fad8fe21adb726dd748b110be09b7fad304fe70b731b9d0c4701b2816992657d5d78e42b484b75a497ee13ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164fae5177baad7c4463b6e07a1c1fba7b945d1127b3b3f4e8b20d6977e3adce7c5046424d3e44cce3388c2ceb968e8a00000000000000000000000000000000017f62e94a394e063907298f58ff135fbb741903f2129f40e8ca193f1534b845fe9c9a6f1327a070cc19d71f7a69f5121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd59365a6b49323ba5f8aad6793cffe739ad7ae9b37f65624d2432d7aef2b243063f57094de3dc2f930c1438a3b3254000000000000000000000000000000000299afc35f82281d20db13c62284b66890df7fd76f6c73366c3f076de7c4b4d9c83248e0020e0ab216e4f5bba5a340821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112b890a18520f0b96e61569eb0969705e9833286a4490ecc7074d0195391ee90015c65af09d3f4ebe71b99ed692324500000000000000000000000000000000189c003954a811838e6a270a8853f9dc8d3a677d3c8193fd9689689177fbd33ac17fa299d23b94c9088575f419da0fc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047c9125f565cdb09ef1d87bcb296c6ca017f7002bc22e85fd9af04c610aac0f6de16cc2b3963aa25f01f3fd3c78d584000000000000000000000000000000000c637e6be49818ef5f5e437bcb4df33868c1f1873f802f52fff10ece9c4728cf0fc2330a6e0afe39a168128a8b1ed4551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c666645475545a5bc6c26156af5a63453538041151ec7e2081c37d9392ca650a8137e974c4d83b29893622f674d5190000000000000000000000000000000011b6d50f414b4e1ea7eef5106f7be76936b0e0b5248064bccf910171bb9ee8778d0f4167cd109c720852181900d8e60c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa96499d1882318fcc1d0f3416edfa957083ed9a513f14beb05ea569e2b89487663c41d1040a55bf2262ddb2054e26d000000000000000000000000000000001383c4ce3b72da8cb914494d7e22e449d395d1479d498fa4a19e4b4ecc7443096d4e74a51dbbc6ac4acce55498b241ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160276faf62d4a300626f8e02715fa8c910f8994ef90bb5e38062732dc86f551b88cc05c30cf4bee73e57d7307b504920000000000000000000000000000000013d0c622a654180e5d6e81555605926c98f5d49da6fd633ab09dba5c2bb89b21857c6b1baa7aa6b203495db441cbd2421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001393b7b9c61a6839e421bc9ea04e58caf8937d5afd265c1bbd42cebff6c532efb98862063c9a687166b14e0fe5a4f990000000000000000000000000000000004c68038b8713950c0cabbfbae7e3c339fbae54103aa837ac76de8f90fb796cec3f19a3b744aa966d62b38f493b54bbc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006690665c09bb093f55c468e244e68416ddf174a876e928f62524822b345ea2e63a5e32f15919d62d86692ef1b552323000000000000000000000000000000000757039336f92fcbf0598b48e2b6a85acfaac756665dfe2fe5687cd69da931aef0a8feed3a1646eb1000fd64d547340b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ef527aa052e67b3b76703f9d34dde85df8c310760500ce21811e388e3df6ebdd531e233b8eeb5a95a797b0d30965f2000000000000000000000000000000000588cf8566df35e3862dbaf9a1d25567992bab182a99064b8fd713f9ae539dec3cdc653dae0cb75b710db0a9b6b01d731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8161373f08de661ec53ab6f8abed34a168420c8e4587e9d51e62b41cb43335ece586ebd0dea13ee508e45ceeb1153f000000000000000000000000000000001352548009c573b6541d01be109f3c1bf7fd99be74465ad82e6e36049f73b2c290ce8ccdd069ae60fc3a644a767ed0021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015aaecbd2a4ec8a5b1e0c49bc8a69c4dfcfee1d755ed527f9a7b41f845becf144d42650fbc44a50533fdb801a53ef5720000000000000000000000000000000011c4361c94154abd6e59e6356b68b78e1089d86e802d5827af9a30181c47e0101edc36b51340c4577838300042952b571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5a51545c855d0610fcf4bab6f3e57be705797bfb5f475d1acc6f55ae5e298b027a8bcef24654240835117947ce56590000000000000000000000000000000001c2acd076537cedf746d080287f561d8a6dfaab226e1a34a4843a16f59e9075c95d1613fab052bad6ea1e2a5ea744311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2cd413075677ec340d96d5a15b2eb37010b3691f07e1feb32c75d3491d5e4c3220209b452fda419dcc0fdde3fefe480000000000000000000000000000000003955d42a6268c6a02b10b763816f404aad938f82479db3df7681a7baa4e57cd7c3a5aebbb5b899b3217b93b734820c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2d5e66ef50c59f164a93764f2462001c0a23733e83bfc7dae7ec123eddad518cd0562fc2f724c55a5617d531bd8e830000000000000000000000000000000018c4741589637af91f8bfef16a0987a6941190b80383e52f7eae196632e8228e86430ac1d1ddb8985e430e04ef7b70f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea1753ae659f01a619056f112a9d0608e39d5929ec158ec75a2450adb8744e305cdb18cd7fb104f0b264b27309f6338000000000000000000000000000000000bdd2554c0540bc39a4e6fca09423c5685b4639bb038b4c4bee83997a69c21e9803c3c8b39cf859fc9c2af47dd8517d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ffc536e194e4cfaa1cd1d1fbad846f0dcd9c3ed3c01598d9eb747bac7d8015a905fd07ca6199434c75ce4f13965fc9000000000000000000000000000000001188472f0a0c4d95a118d680f8086dcb2ce712b6eae605aea66384f690f74a68d0bc295d595cded6348c226ad3a041a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000315216fc29f6cdc99efe569436813eb4d6c87f6ca03da211db92d116ece0f7a80dc18b353e036c52b204179f54b36e1000000000000000000000000000000000fc21011f2c45332a5c6368a0fa53ca5f8fbc56275fe17567416ffe2ddba2508442203d0b65838a732975a04173d968b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015503871cc7a2816ec3fd76d8023dd4107b4f9e2e29d8549181883c9ba143426a35f33879e2d0ba8c4348abe1fef737f000000000000000000000000000000001540f751e970df1decd8b52283648abf103d94923240b78b0fce876a0a1d1868e61d2a72b67f09c3478e258afb7b48c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164b6f046c2849a9c77955582720f780e57ed48c1b3fdf07c35d980dbb1ab457d3a304363dd81911b52433d90eafd710000000000000000000000000000000000d295e43978262168226810b1ad87e8aa797633068b6352716cde81463f80c550b6f6663bb23769faa15072cc4b6dee31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009a2535c1f365c36f4d1bfd0de2fc722f1bdf4b0b37234764cf10391b28e346b3d94e8a54b52b1cf6be2e07a11fc987000000000000000000000000000000000fe3e4ff1fe36fd8d4db31e73159ac147224f544a434a1007e2f76822b4cf2ae3e6c0da66a2f20697518c2cfc84dc80f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f0ec7e98e5beb1bc39e6f2cbbcd03924534e55d815f164ec25c0bcf709433c14d367b6aaf658f7ee3a8799583632a3000000000000000000000000000000000a882ae00b1e77e44542540452201e413792d0b3ede3b6d983a8d5c7084dea307fd1f095e4e98f1b6b598567f6f7db871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cca4d54e31926d6ff0a1c1b5f8b8e70898ed901a77e911f65c466ebd1b03e49fb27a503b34c754e31e175aeade61160000000000000000000000000000000000ed720f7031dd9659146d7c9854fefa8569d5d447a70c4941d56aefcd1e477c262dc0d47ee4120d652b35442294ea9da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134989020f041cc6192499089d6ba5a4f5b5621a85631533431dc5ff56a2b51cbf90d8545e1f2b32dbd4b13d7a6a0079000000000000000000000000000000000354bf2e9ff71b817586c69048857e0a3b2da7969cfd4545341dc87106fa33e341c23f93d5b5b44deba1d36b107fad861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035ffbfd73190e458f0bdd1e318fd976ba5fcd4417a90cd6378d252967bacb173b2246d140742ecf6a02bcfb85b2e953000000000000000000000000000000001093a9b1d945f8ae1b90ae397fad6e80994ccdd7b7618e93c651b4beca2c1d6e76bf9153cc783957ffce742dd72f47051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d335dfc7bcbce3b175ae7a1c02bff38917fc0ad4bef773ea8b99fcc3925bf15b6eead654c7849e6b75151b83de901e000000000000000000000000000000000bb724ab3bc1f433e57cbc0881d3cb96bed801f4385b66dd22b4cda1de5e544a0d328ecd64ff11cc3bad82de8b02d63e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c9b25915cb62750b212a172f77e6dfa372bf7db342033dae59e36ff777482e2695c94e640e1081f63bba6daf3c9dee000000000000000000000000000000001587affab814b03af684eca5e7d559423a3b7515085c0fa2b404c2b87884f239eefabef0da6f8aadfb6579394d4bdba61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c97e6b8081c0e0921e353b8ee53bc64b5c99a1268b1379c38c47618b5d4499bf44b8ea8a87f439817041c5790b65c000000000000000000000000000000000013572c1726698694d23f0359b8db9a306592a3ef2f80485e1441b7affbfb9c8e7034992fe5bb911d68cd552c25e390d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e46a966b89db8a14e7aa4249acd0da1d7888adc3530b1b6618f477fc98e1cd053c01485b4dc6238e1c573cc026bdc70000000000000000000000000000000004cff853ec6760ee594be1be1a3c2751b8b6ae0fe10c277109dfb2db019088a18a7a927d05b7a5f164b808aa9fb9d7d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8ec641b6322e04124af0effa1a7e291d9d907777a9237184672369fb6554bc5bdc517d40dd447dc594c498f99d75040000000000000000000000000000000008c9bcb5d03a21873066e2459db0c7d209d05b761e788baae5a6aabaffad97c410b6efb9fa51d2dae32ec1ca10bc00531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a98ac2abad8cd8e720332d4e9c6d3687471262baaf2d6ea152b3c1e406a0b5b2204b7a69aecc4934349761846e73b2000000000000000000000000000000000c22c304c66271daac8761383a260140849818d99dc12ca454c01852b80ec96272fdd8b4b251fb76c56a56c5630af8b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9a45f32d9f063f4cec240b142ef27ae2a67e1c621f333848d1ab5c5a09db76bfa2008db9c9f860c3fc1907393d931d0000000000000000000000000000000006d44ae844e7b3d0fae574ad8f2f02920b8a62075b6f95fd147ce34771624f170481466efdf3fee3d17e9fb6c997362b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119dbdb18713f74b168bbab079a88051c2218ce51cfd459e169896cf414d521b146d0e364137a56113b390d1410f9dcc000000000000000000000000000000000f0f7d93357e0b25ce19e07f55c04f6fbef2ce6868cbff9ab299cd501f9561398cc4d2d6b650afbf6beba6104c6aca0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001523c20ccc082ef4bbb749377533fe5780199b9553f8d73400b1db6f8c0004377395568f68553f8b35c2cfbf24ce2b560000000000000000000000000000000011929b67b69dfd2ec08a29f8b55c464ccb3ed4d733cca8f0a4fa529fc2e1901e0eae5995eca0adaa3265d50c1c6036c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117f557fd51fafa95eb1a94222b1824582814f0e7e2d32fce81a75453afa515d13921ccf490a84a6820e3d2a9cdb8ac200000000000000000000000000000000100ec56b1379252134438909d27c2e9f7a5eeae278d55395193b6ecd07008cbef1e5fe5b3a09fcc6f0923d9c3a7ee1ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa122f31d2364372c50429abe448583299811cb4412417210cc7df29edeaeb8a112764c37d2c72a87641c357c08e22000000000000000000000000000000000144f778b78658118bbbfec1669c79ac2a1197cc1670c2940a425480963bd92b6480f24ecf1010bd9ab297d04874638981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000220cd8335080d027b450f0cfa7e18dc37c000c97d78ef3e959959b4a1fb7b542112c8c77d90b3101c91421bd3236cb10000000000000000000000000000000019ee1dcbadfdac26a4a41d9b2b5e31297783885bab7582e53d612206a5d9dfdaceb38dfebd0ec6e29b52c2b49cfa2a321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006854471e372695b228c641f9f55507351ca471fe66d1ff9f4bbe079fb95cfb2e6093a621c078ee149cf9a335469c8230000000000000000000000000000000003168b241317420146ba9489ccb8c819b8f4375511059dc042f2d177461b142c4bd666216ed86b10290fc18f7f9878661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ea95c1d37163cd6cfaf0d5f1deae73f9c912b3d2e123ed35957624d71bbfcdf166f016108d0e0451e812f24448532d0000000000000000000000000000000011dfec476c8f20c0e574b2b1fd159b7ce21287aeef5c7f6995e25c51bd9954d4b9c091a6f826c8a4be92eede2bd165001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000169c46fb292c189e65a47b312b76261bf36cac0ca3be5541c7798f23334911ebc88d9fd6277c3f1f2a16d82757519f5e0000000000000000000000000000000012fe623fed785fa8e9de9a45f65e055895f7db2380224b467190aa81f74e4074fc3d7ba8ac91f8fb85d3953767c6c6df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150e9b314d3a0ac3a1be87ba743932f984a09b78e5f9db632cdfec067fe4b0ade871840f8f0297c4c7a1e599581ee21d0000000000000000000000000000000019a1c96cff130fe123d8d1498066b880daaef5ab5fea097d16b5584c66ef3c5c0ec1fb4789c728fa4ec2a596ebcf23db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff3ad2bf12863cfdb696fb44ada6cc5b8a76aaa7efb66b3c39c0aa371e5d45cf3e5ff7305dc70803a8c4bf25def54a1000000000000000000000000000000001640e7d48ea4e0b3e0cc4340f1dfbe1db3a2065ac0617bbff62b941956ef8dc5d4bcb83ba5f8b0b5c1dc258a92c724191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083835d05a95852733263802f6c7beb1beccd9b9fc94ddaef6f6b1a2c670fc96e599663e626d57ab8573eedd38611f320000000000000000000000000000000009c36872ecc565313208797e99e7e5aa5f272b53665bb01b9a82b4d6ffb2ce0be81e1d26aff58437afb54742486eee6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000527f321d4c62001efa64b356c3b2d7b0e28da7844ca9bf9cb96a1d2fbbace50718535f9d18eb66b61b483afeba5898e0000000000000000000000000000000008dee026c050b186a08edf39e79fa108946926550baedbbfc71641f87b8d452dfadc8580b200c1941283afb17792652f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db9a07e76d35265ccc8cd257a7098f8bda290541dd420cc82883f2079b89ed79712e7349889778b6cef5dfd3d13ee9d0000000000000000000000000000000002905cc4e47ac7f7843e581935fa5d5d3d8488fb53eaab120ff93ca98972c56e51b47c792f6cf4e510dffb1dbd7086b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e7f4c53658c0d3534d2c11821fd428803e0f11b0a680c58bc88eee4bace3092ae4b417a794f05eaef8ef0102b031d20000000000000000000000000000000012e78906fe742ec2dfc08f9791f2b674a7ad060bc49d763782f4d1cb0271b8e98c45e0babcde47afc166173b67620a5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000267484a1a4f12be6b6141604df89ae1162337b592565d461f53bc3b2f741e126f172d183fae70001866bc8566979b70000000000000000000000000000000000e9a61d04bee149e09204a63e751f56609235edbfb68f6652b10b7b29344dff1349c285b921386376edac6693bbdafbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097cbbb3c01cbc448425fd69fe78f8593743e3847c876b14b4807e99e3f309ee8bcc23a866cfdb7f9847a95b3a125959000000000000000000000000000000001500cc80dd5cb23a6d15198e824c48e21609b6946c291d5df64a73dccff0488576f7afa5868592176f43b2cb1b10659b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050548709c01b1fe2db24e2ea82cf86b96aa4ca0ec9667177ca02d270801ff2e43ca3d4e975646d615182e647621d33d000000000000000000000000000000000836c31d07fe2cbcd2e1b4fc3e420f30333b47ded8cfb54e0743a79c74b4111f52f97b9d2eebc7a7aba72a6c8f8e4d501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d1f7093308d01b329cc41b58c1076477ba633cdf98e8149daa04aaee9223c35224b9af8012bec80747f55807f1521e000000000000000000000000000000000787045ceaf5e1b4b88baf8a52879e864e8f45334659e759924182536742d065d0996bceb2caeaf21960e84d359923471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152486a4410c3fea665c1144e76b770c87cf71b2bbbac1b620168aeda3d77d62a1b18634a52d0723ba4567b332bca71e0000000000000000000000000000000002aca801c4b02b2e271be6d9ce8a14ea7c0d408e25b4196b48e9110dd6a33b6286248bcab75e8154ccc04c1d129084491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000137a03c96936f51837af098d5056a03edb8ff8a860cd190898df169ee03e9205a0a6fcb0ba148465a233d7c14fb22e600000000000000000000000000000000115dc35f0c7fdae3035612f4575da177729166b2fbcf96ef1180f6a016467d1d084916bc74f5a5d6c20dd0dd79c7b6721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bfce31f7548cce1b28bd18f9ebf9cd4c836a21cbacec66980e246bb5a273acb336953a89f78bd439975443a32a4b310000000000000000000000000000000013a1e301c807025d71a01d7871d1aced1be0bcda89ba469e0c0dae5ac774d18ca810dfd0d7daa670dabd74aa65671a1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a530f0de0e981338a062583916942615f97eec6ac86e5280eb1a805017d0fbfd5e36ee29f24ef32f6da394e8c9eea780000000000000000000000000000000003c1563875945f7d13cb66ca1b97db02bd86c2e4ff0415978e416969441b59bc70431b97b69e7babcf03a19e5dbee1241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b9b8e3e7005114038b0f993feca08b4792f327270db58047488d0623fabac9ace3607ee678212529ac1ad8c30999850000000000000000000000000000000010baa9583f68adea3f36cc2200220f789820266c73eb71c0969bf2bd3f7817ab02e87d6d8dd036de1dad5c40cbf91aa91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008338aab668ec52fd250463034ce8be30356b0794e7a774e306303e0a0703be239ed2426010f1b99c674605b6dac42e1000000000000000000000000000000000baf0ee84da8bd17e0ff1a536b85b657374af0c2243e63392ddb4cc24aa399cb42cd089281ddd469b6b3db9869aef2461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d68a480eb0b93dc2698b6446606a05c4baf90e63de0d66932850ec8478759585626dcb4839603e64fef5ba05acb5ae70000000000000000000000000000000005ec3c3ee1ff2c2c4c5d2df8260b46c5b2aeae710a1878e8e8d0014360707158eaf7e31124e8716b1bebe5b862b8fe651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184da928dd10e414f72d6afa28d9375fd364617e1472c8cf118422e89b116e6b11e256af9ff45d750fcc3c132fe6a42a0000000000000000000000000000000002babd65b08448cd63e62b5638285d84eedb936e5d9759aad8bfbb60d5f6bd23f92126d394832172b93a8239a035a9c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001087b609ceddb89606ac4628511e2d98d47ca3f68608091b0f3c1dfa7ce8963301e3c23e20d083ce4436d28cbe3095f2000000000000000000000000000000000b2939b319d698287a40cc7e143c79653cede3fada316e375c47282b59128abe8a1b0b5c14484a8c841dfdac7ffeb56b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187a4168234cc1e9bf9485be5b0e44213a0619895abb513e2c6870ab242aa4297d48e5236ddc10a42fe02aaf304d16570000000000000000000000000000000009bece883d740b42755a84aa6b875284a24e03f9536390126fc5446adfe5e471652571c3a3f44b84283574157c64757f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103bd13a9c1e2f18da2cb53f41e21012ef3e273e90fd59ccbcd1f29e1d8b519754fcb20e327c30717253a980e65d9ed70000000000000000000000000000000004bbdd5a8d82a22e3dcee5b564cecc86a27ffe8bfccd9afeece9a4ebe6a200a4f37388d0474e4b837efa40bfb3b3b2531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f23c45ff324926d487219f736d132dda2e598c93d37ca89fbbf06a45ec39dc55bfefc06462196092e8d9c91d24fbb4000000000000000000000000000000000bd76fe0aafc50ad2f2b3eaefa83b471212393bbe42fa3686280f14aa08d1efd915eac7a91f9df5444032aff9075c6431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b00497a6b27d85e36e60ecfb58a0cb3bef3da9f7c9c406fda6a340fcc53521b6a306c7685ac7226b40b3a67d1639f72000000000000000000000000000000000d6d753b57f88e43f18ccf4e170c2208dbad68d427d6524a04f8c437026c60f2e6d7e01d1347d2d5ca956bf2e4d7617e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a4beb361e648dda6728a8bb09cde1a650ba64a9113a6e98f8837111d217b47cc7cefd22ff324fde9a000d0fe7649bd000000000000000000000000000000000252ca803bdfd92b50bfb17dccc81141357f6eaff1db8c012631ba8703a40d159e6fefca388de757f185177d408ee53a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176eb51de414c3f20c44fc47dad4f455dbfd38d390aa0dbef462cf63cccfa5e9fe16658bdfe2f1ef8cefabde40d58e230000000000000000000000000000000002e934a56acea15f810ce5ee1cb43ba509d580b1c1006edfbadb374bc7945e96ae36e3f0a3014e68dc863feddd9ea1f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0e35615506a516c79ea132384f44f7248295e7488b6ebe876c1f0b2c643a6b4391d1d147e24f0402e7a9642d50486a00000000000000000000000000000000077dcc7378977134b9c8edcd541e93534c9f7b5bd365f21c4bb8b23d47aabef0828218d45fa2c9ec5567782422d745ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009849d6ff15bdcb2ecfc60eb6db65a4c4ad25b1ad21cc0654375bf3572a8c63d45328bd1e44b800d8d7e230c6b13eb4a0000000000000000000000000000000006660bc859160aba9c0c252b4298029d409741712b9e6a1ca96babc84c5a19867c584ac8bec76abf85d736b6f56060d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f0ce1722d76f0a15c12911efc53a34c6e3e3f151608d4575c83cd4a59f12f789c6c102d2612798abe03b22bd1605a8000000000000000000000000000000001201f584b81041ad93e44514911b79f7e5c39edff7cfecbedf2804428d89724f25af3fa53c2a254695cbb5002c7dd6f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002da020244f7c757cde5c6022c0f93aa236ff3705e8016444c0b7f7d91b69f50a3497bcd9385b96e4aa303856b56f0c10000000000000000000000000000000007d195ce92425858dc533e3e1870cbdbb8ee5018e232bf59f92e04923ea93781de29131bfbf248ff4a9c544d76a6c4cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6ff1abf3295fe0e78e041cb7c63c69b96382fcae33ed797e99e89ad9ed5582a8525a9a2d50dccbfa90453581e2a18400000000000000000000000000000000027c68ad204e49e6d89dd1779c8b3f8b895d184124d64400b3e0c57bf2bf04ba8208f877dad5aa657fd8f957c99e08581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011629ae32ceab2c017ffe9033097946de821058fe6962ffd6a274da550e88d34ba54c2228cf09b57ac2367053f1aa9fa0000000000000000000000000000000006030322a9b78b69f5aa4821654b60a8daf3be4fb4d5464098edcfdc95eb7471a3414859d64e92d4272e33434a670d1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001661127f2685beb77ef99f3102eb26c2cade99a7ffd01bc97613d1de78cd1337a731d340f59a2b20a253caa2f28e1f0e0000000000000000000000000000000016f8ec7a55297fa53175567f6db27629e5a8db628e7de01cca47e01ed90baebdd1cdaa46f6777268cd8b57be8bb813291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d4ff4fe35d883be002d8035b0ecfe4481c540b959993c6e2e97149ffb0ec96e757746b81df7c085d705cdb8a2c076f00000000000000000000000000000000069a65101a04086163329d07762c0418949de15152fedb1151d52b16eecbc11a22723f2fd5b53141257d9dab4f899eb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019754449eeacde1d6495a0f65474abab8e25f576b3a4e25cc097abc3eac4f7f9f2814b5640179748fd97c5784486d63d00000000000000000000000000000000134315169556110ce561b8b9c0a0a4eae44c993bd44cd74899e84b40ef1e83a704242cfa38f5831735756040539bef291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023d0b134be21a459f69083559fa10e8e9a4d68d0013702fd94a3e78a76e96390e1010093319e2eb7f31bfd3a4e408be0000000000000000000000000000000003c6e935f17deb5aac2597ae6c447c3b92631f8684c6d5c92a16ba6ca88ed5dee095b6e314179482395f4f921dd43e721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000caf4b086ff11abccfaaa6e74552940d3cee41af90e1d23d5a0e55c0677cad71d787efcc04c77740ff007f0d471c499a0000000000000000000000000000000015139d9764d9ee1a98c0220afba937ed077045abfb4fd404bedc5335089fd2363aa0de0a314ec94b23d3d5749898cc6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b14c325ebea88d29e351bc659edbfe6bfbbc00ea9e32b8e5a6c28d76cfe17e8d26fee00fb63864c5ec8a7eab0a79343000000000000000000000000000000001860303214c6a66823b3746eb2fa70f9849d3c27aeadd498379142c9e6aa77e9791ee96b00463ef5978fd4a4d3fca3ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aaf5241435628445adbb337f8185704f486792299fbbe151758a5aa3e5f3dd8f0a82afb398fc50411f0fc985b350575000000000000000000000000000000001195a49ac5ad9ad5681374926ad32c47f127fcce8d21e174f49b8e3149c0e8e9e5c47344c91a3f3837d55827ea5ba9531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7b6491fe03a73a003b283cf88bd5f752704f60e35708c5036992590c88e44badcce37b9b1cc488de6bc3da91d9d16d0000000000000000000000000000000002668145670c537c8c17e4299b0fd7f36b0d4a618fb2d3d4dd45c89b2f26efb3e41d6f58ae0be33b51a388f4306861d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c688fab75193ac833957d8abb6dda22d83ba4f00fb80bfec5ec45c582c30d59bc430c624a694f4bb58e479ef12e11e000000000000000000000000000000000be0528bf873004b2fcdfb301fb39db430c58d0d3371e1d1466790f3d9611370bad99bddb5c6c883de0468bba7987fab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013afe6fb6699f20d23d877cd680fd371b301b88b8767b982fef24f600adc332b009544bdb81d3363e987aca4e06b2661000000000000000000000000000000000bca69ae19eba82610e098b5163bce9637d4fc2b72151068cb89be885b3afd95ee917ed05be1a395f615116b47f280551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014bd7df1c04680c2c8152a3a14d4046af465fa9bf44a3e207c104ef70038339430cc993ab1450606fb76d8c36acbf610000000000000000000000000000000007058c869c026bb9d9c97f5066f50132abdca048cd5f798df6f4ff6cb557c71d3d81d57e99693eba8a0eb59787a4c95c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061d11040a35d048d5407a5e27ceba815d7ae8fe1508b26c6959df8473201df97d8b2e1b3c06c1de234dc7e3dff3adc20000000000000000000000000000000000bef08a1ca38660d13793e0c99fa6c7756045993baf09ab81d30d44f1cd54ca143b19ed8ef2e7bd02b0ea9797073f9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010bf580b76515f440fb8a05f4655305e883823b55cd7ae1e7212def104a1e1cd1aa31c68cf4cf26f22dd87b26780ad550000000000000000000000000000000012aa61bbd1c8350374061e89c03b6a86cf3edfa2ffbb9e610edf9ed3804cb4550cc25f9b41ab455811b4e2f056e4408e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170dbdb25882adbda085b8ea4dd2953885342e3462a7ecd066f8f338fea19bdf6e9ec93814ac5f8b711074096323322f0000000000000000000000000000000011fb5df973cfd74470dcb73183f96c5593050e723126c80fc8803d3b75eb2060a2621798d1f3c8453ae3f188cc9f1e371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112cb5fa3b9fb1fc89ee11ee37f688da176cd023e04e1f7d4737684d00126fbe55f13576170e5eb065c7ffd553fab8c30000000000000000000000000000000019ba1a470e4a46c18d28aaea87a36548a1bd95fcc24e7f4bca587e10205b1d05659dc54357b2261e1d12b964ce56be601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000356344eee82f8fcdab51d102cc8e53b7a427e2a4142e2952d9c2be17f8f681d25b87ab9fa1ae3c7a86d60819223f387000000000000000000000000000000000a95bcfb8d1851a828097fac5e5b824aaca0c5911279e7e8422603f38496b487183bcbe26e6e7e3e1f817fe5e252cfe91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166df75509f895f7f3002a6aaf7cb39abd8204eb770092a055f72272e8c862ead75cbbbf4e7b1e91a0b73388d7ac41f500000000000000000000000000000000017d5100b37ed9e3ff69878ba0bfea7e97b466003b0a2878aa4d26daed1dd583942e84dddf8156e3c08b5f4b805f474a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9b160cbfb0b89780d9b80d41933530fc322ec05fcf99d301d55409a23eafed4b781eee5194a86431c3e02f9c1c53f100000000000000000000000000000000130b6a02eff7ecdfe69b311b009e8acdcaa09347c2a5d5a1a55a297caf838397725a7a1d3e54b4b91efb604408cc4d691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001675d89cbf8d80ba0273726e2ec5078f2cc5960a658faae0c0b53e37515c4e36d3fa7524f76731f67cba8ed98efb1450000000000000000000000000000000007591218ad18dc21e32a5e8d60b95ad5a4aebd8225fd37f7290d667a4011f83c13007e7b0248cd9287e54899378857641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003025554c64d04935ee950d0373a7ced5f1b93b47a75464977ace64c49c54fafcd8267a0d0b02057e56979cb048b588b00000000000000000000000000000000023a38c812e4b43a983304859facfcd81bd77bbfa5466bdc08d89802ddf5a333fc2127fd14badf4d634f5b56f9215e211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cbfb23bf71919f8592bf47a561c3bf4a684a043c4de8633c83e09cdd2bd54cc44d9d757459369dc4c4d673531600c200000000000000000000000000000000022277fc57a9f666e1bfd219ff8a35c44225ffdbf061836c2be356a70d81cffa4b15683ad4290a4939cda40ccfa28dcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ec8b080de41e822826c0fc7a10d43c785f55cc679eea24ee750b6a99dba5f7679985732e4b5d2cdc74c44ae9f8a5b20000000000000000000000000000000010efcd6dc9c3e3f138bc8fcc3f214840eae0eccf11610a2849422121c3b40afa91e246597acc865ba5ccb2c7108cef661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cb80db85717dfece6f892960a2ce946e23040c1de19d731dc1152441fccad7995ffa85e7f97907d15860927dc3c92600000000000000000000000000000000083f43e28109c6bda83551e99c3c773141d0cdcd52b25be4710058697e223f3b191776551ebfc3bb70474b85395d32301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123e422d66b0a35e525993ce1d0e433537c2f63455bf4adba3dc7ca19c5698a84209c9535cfc4cf12e89b4900b6e955a0000000000000000000000000000000002407e3a00ba556d181c154f3a3bf508ae9e94887178cae0f4f109d0f062ba74b114450b1efcdbea0adf526832b516a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175d88638cdf5d3d108cf673e85984eced797c6ec29d6e91f25ee4cb226db699ef4924835bf0ef6e224c8cdaff10bd010000000000000000000000000000000016a742bfade9b1d5197edf1a92508a6cafb42fc21937c7e14a70df63d4728029b8a2fec421e9c5bb1cf42788e1b1fee61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cb6fc23f64d4a4642e059bc002cd6d5bf5013b0e97aef710bdbc6dedd5844d7ef69707ed5cb45776a245b4fae0dfda000000000000000000000000000000000ea56ab05e8a0e07ec52a8e3ae3111eb66e2a4e783ae7386c722f6a9590fd0f3587374af19dce45080d51f7512a2d44f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a17e93ee388f3446a31ffd62f7dafdb68116fe470e1077f082b564267db94ac58844e46c035ad4684ffbc5dc8b38bf00000000000000000000000000000000158ecec76da484c88a4b2019b53cc1013cf0e8064f38a971a0811e99ed4bc76fdadd2282623988533b783170f9c2c3731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001532dcd042faba6cbdf0d92314e19ea3e7b04eb69060df3e33c8a61bff2e16f1f3443dbfbac75459925e1f7922d31fac0000000000000000000000000000000016a0b073c2550a25a4e8c49939f40acb2df7b1c2810a45989e418a70b9d290fa33eb365b7366dcb26250a987d59453c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5dbc1bbe213176c3182e5b12776276569f92451772b3113461499cc91b28ec2b467b26e3af5d2cc4ed7fa57bf2c19900000000000000000000000000000000011f955e74761379a12f4a5238873a2359bcd29cde3655789af8ee8f994d0322d0b707f6838b693161e94fddb694dd731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d3cc124698a9f9c6affce4fc9926c704b89ba96c7533ef3d1bd65ed6824d39da21e7810fc468f9e975d126075547d1000000000000000000000000000000001069bde8914471c1d289954ec5f3156df7be0913103feac97356442bfe0b5ee6c9ec12bb6815a41ec3245921173961771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001378058b1a1724b510f0393bccca4dd9989b6ecede5c46c6386b7332f8087aa7942ddab6c0c4b9d4e6e5922d63ac48a5000000000000000000000000000000000a2511fb1f905fd37699c69dbff6488b798fa9b15da1d2b28c86593874c3a3cae4cff27236f9748da0268bbb968130c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000146b1e6c7de5f518f98d0ffe762310b488c83853f25155d00785d9363132e408778d08228745dbff902bc6158fdddf00000000000000000000000000000000000cf80071d9f7bc01af9ea66a18b22efab74fed5f72ca23dc3ab45fbd13aebd362259e4b8cc9cb314e6208271b299aa771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ded09d54723382d622f1c46b2cbca4f192e471694d002b2888b0e8a7998453512f9d9d5584c43435957babe023eae2000000000000000000000000000000000a39c495e6193c5c81824654d9d24ddf7a138f192a372a9ded8c85a301f0218a5c5030eacfb670f727fced455b4008b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b1a8e823d6cfc4936bf33b7c31f5b55b0baa13b2f74c32c5dd7d10e56e44db11c3ff74a3b702e07930f4aa9ccaac4e0000000000000000000000000000000003cd8c9f55f9cc806bfb7f0ca1fc948755448379be58f105db0b1e00076d93d5b69f88a92423522faea500c0cc3c93f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd048161b967fe4e49a879519de96512a08e827f0a07130b7686cb13a4f897636d7edfc3105359d482406bea7fc5964000000000000000000000000000000000e1e7e1a9cb9df5ea4ed18a03fb97bd5ab2733271534e01d85541c7d2e194cf8fd2826341f022d867cdcd667c865fb151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f6654dc9029f77afffe0ec46bdcbb06fe6806c90077cf5fe49c92bee504b9d0a78fa1249b23c962e3db008a635ba41000000000000000000000000000000000a013a0b600ca6d1c36fed4233b0882c7a6c41357b8fc4502ef6aa130de8e11c4818e47b4108d2e17c52b79f762f78bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000196491f1d774a42f6aae2e8d15b66837a5e98aabbfa03ced3e8e763f639aaa64172d9599777e2ff7170b00696371c5ce0000000000000000000000000000000007092f0a6c93d78534f9d6e8c5445d83799ed09836ef70985b9092252c095a58e14250fced8302bf12c4811fdce7c8b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026336d6e3d381ced708743f1db8fb5ee35ba43ecbead926a11f2517e08da9edc6888427516a5f3dd47b2647f096d2fe00000000000000000000000000000000003068696dd7f5e459dba5e5e4075c02b2fa48190ff9d5396ee5d61e48cdcca1decb1600b49c0ae522423bc85a3a63f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e168d302bdf4454eee0ade9ded73d08dec3dcc48af91e04da62d8a125c9ca3433f56da8c9f0e69b4e0a817b0f68f8b20000000000000000000000000000000005c451271aaa1ce53ad1e02a30cd98d9c01082de714d6cddf396fb094f3d244ac89b96742d0b022e473bd44a4f2234a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011293d77d4573c256006a6eb009f1514a4a71111f197345adc9538b11349feb3522b72b321797f38faa86bcfa75b14a00000000000000000000000000000000014fb17949003003721ac0a0473a264896ef3f2f29700e287943f4b2e7cf8650403c96cb792fc4e117c67ed11d22669de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b0eb17e3da101d72ff13c213a4ec6c2d332d551aa60851554ab072d5425b54a722c4d565653583bf1fd3d4be0657af000000000000000000000000000000000fa031122cf8f2f47c09ae0f13d57529c00b11602f5abdfba29763876c7da68af66f399bb0535d50ff43de70bd18ca7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7c6a736ecd1e15cafc4a18aa045278b4f1e9d5f13d814ecf5d9a935be7b60cce6535285e41af019b30d02d154d68400000000000000000000000000000000000827e76a1f090a27c8eba82fd2e9989cfff806fd4cdc141d1083692d1933cdf1f0715b6f58257dc3bfe7ba1ced693a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012385eeb308b2ed0fb55a8dabb9113f9112e7f583a9df0143cf9f2c54d68603e9589385fe7e1f87e71fc56b95c82be8c0000000000000000000000000000000003ff8b8d87dbb388005f440ff1dc0f2fe9f558ecb4fbd9507adcdf7046cba89bd9957b26123965837f857a9d24ca7c081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2136386c2da6731f5676282dc12efe43e9f06ba00e990c9ce7f8868a1f74f534ed2a95767cd922fa6b7cc63006a6b7000000000000000000000000000000000230fb3c2f7c30d920e4606483041dca9d5d6d7e958b1748e175acaa4ff11698c95fbe8cdde55b11653e39f8ab80250f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012482cd18ee4291b129ecd222e3670b1f647e255e1ee047e6603f8581f08d291105a4aaee1bf9d6ee3f2a86a9c1b0d7500000000000000000000000000000000076ac013586e0b49b89501244e680472d34c957a9b6426e8e94fe06496a4fed6d6e943003f375ab518154d805b5b6cee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a37f4b6be8bd5536e314fe727608cafd7796fa6e9608a7346e7d9265b02f357ed2542def824f78f68f603b1d00d4240000000000000000000000000000000007e63cae5b6d6cf6faa6fdc54c61a84586184fba9038c29063d298ec44ed03b930b8d16018c74cf253f5955cda7aae8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048e75e3a9e7c0fa8cf19fabad9986f7f9168b782f63a1a68ae2985fb11541943126900cc0dabd92b3becca7e9aadbf200000000000000000000000000000000115e86d8b51f0471e32c442327c2d4853b4864f3e9a7e8c6b8fc4460f276935c1209b334bed29a52dd57b5c8b57d61021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000721519040d82fac82cedc1ec2a601395981bbec0c912200a3ee98f201971854c960ab595f2597ea6ceb39063141c0dd0000000000000000000000000000000010d3ddbe76fa2457ffe6fc29dc4e6947e88b567f40fe65eb2b96a7d5762e2afcbda36cb77a87b4c3ae1c77314d84ebd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086b02ce230d01e47756694b58ca50bc3b820828d236ac9958de2495792ad15ba5df97813a831c8e368e97caa7c4530d000000000000000000000000000000000f4560347c1e60e4cfb04727887642ffe7e0df57286c80a1f181f0d4c2b02eb5759efa7415f396c31d9a4a0128644dcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f86f3dbb2dd837b654bdb8fe4262cdd9a008115ee3da9cc8d83b73d6bdf63c058d0c16ee0d3fc8e51d5b168da15f28000000000000000000000000000000000cc2f7b2060ef7e209bd0dfae9230ca23111e56209bd347d7fc9af8072ca023df949421a84998f646da422f0953436091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000862a70ed619e2495b101d2489b511d36c4c9378c4834789e951686e78e2a21fa7e1c2f173172c5d6271ee03eb024110000000000000000000000000000000000b26d1db8d11569c58c050c0b114b056e97f5a794826173cce7a2a72407f6d6b201c67f3602a1ba94c19702ec7646f341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a2f58466336fadb11a413d080bfeca1e596e7a5c37ff724f890c810017343da132798ae2af73ef664a8c11c49aee92000000000000000000000000000000000b3d92cde2a7acc50a207b88c18e41d2a40d6486fc51da825ff57af2af628a80ba3e7eb6919e3009aff61f710e58c8821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134eaeb0a3a8df81b98c2376a9050138b0814f9c93a9801a516bab050fe0cc2e556cab4b404fc877848ba0dbb17f8b4e0000000000000000000000000000000012cc987b68c23eac2fc83d041ff8017b1b95370653252fb3d1b65ee7a0bec3b566756fc3cd792a7886c9bfd9f8b6de251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147f37edf3a2ffa922540a15274d2c380c7b211e9cd51211088fb3933810eb87b690fd44dddeb0d3921e8fdeeba2a2c900000000000000000000000000000000028b84c811691f54b1b649e2d1dd699098f9af455e1a1fccbd82e372189789524320f1853e13cb17d0ddc1551d3e71e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca72fb85d44d7740c1c0faebb2d74d9fc8e7164f1e53785702288e5824fd737750d85c7d9337ff7dd35f8451cddaf650000000000000000000000000000000008a7099ca90a27268bac9dcc887cbc63d6f11b9d423b2ce6b62cdd17462acfbe5c42fa0d4f04c8fa64c1c5a13ad6cd091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088100c1de0d9babcf472bdd6fbc379b1e999ca6fc5186fe122dd6523a8610819f81aeb2c3df3dc58f83982f4ba0f4e70000000000000000000000000000000009da08b462a86f22c5484b83ba67a2c0ee1844814d1337fc4c0a614debffe1c5fc4ece775e558075266675bbf1e991511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e87ee0fe488e4bda38ea601a2232a195c1aa1f56c5d59c8c7b720ccf87fc4fa39f7acdf6b1069b50401b9f3a260296c000000000000000000000000000000000e7802e1f70aafcd367fc240f99927571030e05f98484d3c74f039a71b1b8e934edb1de9ae48717fb455c93099c6a0fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026fc7c314fd0c23f5c602d1e1a3ab7e0178c51138ef38be09d420ee60e063b1ab5e184a5e501815674b353a0c2e8733000000000000000000000000000000000e6aaf1a7c59ac9c6a144fd9edd2fedf782551f3b3e747b821b0cfbb2bd805d83b90ce5d7474fc8d416d81ed9060796a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001442bec21467b6c437bb5108d77ff3584d66c075a762ca69ff818f88f6f8e257caac99baef71fa958d4efd64cc0b4d810000000000000000000000000000000013bffaa69639c9ba77656a9a425d9a9d11b98fa5fffab4f4aeffc75c0bd68bfe8897ffca397409978b7f7da2fb5872041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d3af812f430b93f6e89f4780c31b4a99b0a463ac1a8328f452b722f20e13be81011755f977d20f7d4394167ef1159a00000000000000000000000000000000197e1c6f4fd6537f0d9dcd8ead3cf2b2dd7f5425b63afb0dbc4cd93d15da5cd2872ed418d515c8391d7b5b797c2f706e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026f51847bf0e79f98cbb53fdf3ffc76e1e96b63f1aefe7469144f1559ed0b859bad4caedd71e51d23434712145002bd0000000000000000000000000000000012ef18e777edb9219952ef871d150ef1b856373a94ece8c54e717d28695326adbafe159f9109051357d72f833613cc901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000406076c4046d54e0a146ddaa49e86c29f81254bdc7cdf4581326be86d5477adfbb2b92236a80a1e4501e2c1c4f13fd7000000000000000000000000000000000183e9df29a652fe095cbb8a97546266c0bea118ef3e9455fc72464c066d55f70aa53c3eb4ed0355ce417d404f5cdec61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aeb61235c5b0bea0440ef96cc83f29f1e3d6d86f3cada4ce25abab5d177463cfddf5e906ec5d86cc38df57299c8559400000000000000000000000000000000185de092b387f1f1123396c0dcdafcbde7649dfb644f0288d951b55c1cf6f71b0a6476dd6808a7a69cc9d9f768fe68ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118cc245bd1c84053aff9e79c1232221cfb7936458c307c82b7000f7885c268ccd5db94474488152d50e0531e7c4b301000000000000000000000000000000000d93fb909a0d7100ffb4d9035772ed6159cb3c974a77ed02ec2af89b4360ae849cfb7c6cc2d79353dec0e2a084f44a051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001579cf597c2054362c5f3a4ff3e7016a1c161c65d04b0b94714e13486b7e33618c4956f355782b266e0d111f04d71cfd000000000000000000000000000000000ce7c37b7b7a216dcccad16a2697f2188e15a2c9d1b028fa5caa121834daec6b7b70dc8b57a719d8b3205b43f49354731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041b53b795c1fe7da922e5095e5c76f21f95afabc06ad7e259cf6a5d18e35e1b45d33fdea2429edf7f4f68dbba1087880000000000000000000000000000000000a21b8114c58988bb79516392bc32da970c94cdc0cfe4e2a4cd7d275f63ff0f548ab1b5b3d1e1418da69f23fab871d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099ff7fb67387860fd9e99daa4906c5424099530f78b4aa7022643b338c8b375b574f5a96db3598f32d560dc94afb181000000000000000000000000000000000d04a2ea930b54b8df5447a6f069f8dec98bf05a5ac80395453b951fd82124bf9201d7ab705a850a2c7533fcccb5a52b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000afdf98f08ab187c95699eadfabfa355c627ae96a84816834ae72ad22d0b7df03c3ef11586ea8e65f37cdb7c694b8d3f00000000000000000000000000000000079ec8bc973c18b73365a675f18a5b231cf072340984d008e23f762caf91f2492f4c579d8a809f07359e5b221b9c24301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e28896db18eef129bbc7a3377b6bd0042699c2465a10af2c21c9b87834a13454c10a5b5d3d05f19d78eabe2b1f20f1600000000000000000000000000000000157577cd0718dad72affb164d77dfa6be75605415fd8eca516a6dbe9bec71e5ec29e67a822aedb27f80b4aec13c102391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd0761222611a4347d456c407a14820111f325c2a3bd7fd8b169917977c1abcdd6b05436b3592b53c2066d156dc29ee0000000000000000000000000000000005cd038a534cc6d5ebc484bf8345431dcf6208c225fac852b2e57f9f535880fff78bf946e16a5dea7ea9805ada0ef6101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4ff468d06274778eef35bcebbb209e487efcc91e39fad64e2a73376b6a5eeab73d05ba2a1cfd53e30dab93b9a0942c00000000000000000000000000000000032b70cd9d2a72b79ed23213a3b6636949ff9a715cf234adc5f43fb7c16586b472a869db68827926752c931a17e85bcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000046b158395e8167943347e13dfa67c3b469d1607e37e2b761faa4b8134e13d26f574c996fc2689e795e8203ef6192633000000000000000000000000000000000f9c57070af6e0bc38726e8ecf940ca232703b68c584dd2436fcda0a33e1d8f9b1b0ab0c8abe6e3591a3fa95ff8489021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa64e13e0f68575ca656dde9ec9437b036b7c0699d6bb18ac799d2aaec8918be741d979f98aaf8f80a81242beb4dd9c00000000000000000000000000000000051d8a24c7eff9fa07b093e5a081ad4af9f6b3cd85e3d26d64bf63e6f75b6269846c683c7d48ed93e7b474bc84d29df91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000192011d5687efcded8884908b0ac6b74b9aafe343ded3e40f4528febf8a3e3a0d648dee6e9af88ebc166db9f136a11c00000000000000000000000000000000116198fd19a29a732f7e7c3839110f77728e1ea62b684ff08e9da771586d43cfe4ae2a0684720def1f17a4ab63d75ad11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111ae24b92623d0d8690e889f21014fb4292dd80e8cc69c725653c97a5f77e3e4d99c996ddc4e96bf2f8bd5d7fe5528e000000000000000000000000000000000ef14d2cd881bc59c6907c7c28a7fe467e8b8af15b8e6dc25d9d204e399edfd7a74ae94c9b107db9e5498d583d0a02a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b033cfc76447cd2f03c73e328cdf3d9e938aab4cb4f0a0235286a143947192c860317f40d1cc9125d23cffa06a5e7300000000000000000000000000000000149fe74424ebd76ea9c2707b011c955abdabd2b7209f17a29d766e90a566384468dad2fb799e22588500c3e9fd62d8361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016142f4a416993a61d5487b5a4f176d6961d616e6b0c9c927e9e95112b8f005f7e792b804f09034cd08dab7bc2335dd500000000000000000000000000000000100ff54db712de35c5480cd8959db494313a5047a61c38facb63325c37c4d76010e3ed8659665094b99ca928bc2ebbea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198526ac6830bd04258f1ed50b30c3f2dd1dc4cf1de23ca36a4847e603e48ca16480eb4c54b0610ca23f392ac3027424000000000000000000000000000000000d564f52835f8c8a996389fd94a38e9400377b1af8869b0a9a79f05525f398410621f8e7624f0d8d97e5474a7833c7e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001221a62c653abf1608545c83dca12c701994b93fe7339d33a5b63b70f228b543c6a04da4518a251a77b7803c75b6761f000000000000000000000000000000000d88b9ca9cf7ca600b7aaefca23ae8138412db207343e83f6630cd1e5a58a13391a38436e8137fb0a3bd3035d16af16a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067eca475e997c320c14eaea437d331975d622b8874e5ed3f3398a361860ad071aa3cf1b6d5ce9284ba0b3ec99df16150000000000000000000000000000000001b25057218907f7d5121a70cff5e218e1b0f31d473fc4b2895fd1533b9a6ce32d27d6201227000d8ff682cc5b388e331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000302f831861ba0523836c7c38516afe94ed8e282ded74db20b62269bf875ecd7b0e7a5c1fbcaa142c632985dbfaa8ed60000000000000000000000000000000007f3b4001d2beabf82894ff03105a2246e19611a208ccde36760bc7f6952d6165f9f350e982696c08eb93141545bcd071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccf05262fbac12e459384c3cf1119b8c8cb87c9ff310f609972f17e9885c74824a010d5c32059b662faa049e7fb8e590000000000000000000000000000000002043adcfa8af733cad7e56a7db5dbdf28774426d135f67460f83bb801355e0ad5bac3bdd76d12786a37f9de896b84101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140de0f8e8bea89821003f5543c164611fec949a620f0debc533fefdd20fa8a3a288fddb01076011c500bde22a1e10d20000000000000000000000000000000002343a8d00d0ebcf1536ec7f5ab42aeedbe8ea4bc6045e5da7396674bd90acdd81bebde4044552334cdd7952854af19e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cad9de3c4c006cd9487dcad2c9fb3c2b1f72c8a662af444aafbd905208fbc8a092dc11e1cf45bc269238a2b8e4df3700000000000000000000000000000000027902f309de9626424bb328c376d6c8c00b5336deff3d9b22baa3e4b1794a5099d3587e3e1db5c2d2046b0c257ade551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077a58bc41bae6c9267c0b4b464824c19892689a657cac1dc4c6705bb2fa2f025231e82b337612a4d97c069e2975db19000000000000000000000000000000000f72b8af3528582c2ef07b158ef2192f0c2c6d1850c6cdf848537b87acdfe7cfbfeb8530119d26762fc8c30d1d5592701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077ea9cc66cf5a2336478c321251abc32a16644527a101e584cab8512442d280fe107832878c5a9691bc31dda59211390000000000000000000000000000000002ff2bc4c6a3682a1aed7ad5dd5974728837fc49ef13dae3b0153f23fb3ec5b386627c455b3d7d440c8f0559023098431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba68b6e85bb5d59d2d9e5969f86fd3b2ee974b38c644efb63feed9e4fff7c99ca7d0349fd85b0570dd2debce89cc831000000000000000000000000000000000b12cbbf373b3403668f2fe259d4dbafd8164fe7b8c840151e3e02976bc03524913f89e62b873a3b9dbff387623578801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001133bf2779e6131aa0f4584c8afac7e091d3ee30473ac174e31b2d3dceb21acaa66817b53b3ad073bac57a1ccd12d2ff000000000000000000000000000000001422994f22d9e35d732ec4292bec2f088211687d7f2b75377b1dcd9486fff6ff59993216424fb66c462f09d84cc943e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006aedc27632ae723ad76d439527a5b1c00533f303f607dabdbe92d4f51e8f78393b82f71d7f1b6b8e7fc8e9bd9ee256000000000000000000000000000000000895f619e5a9663b10698aff460fc820e3e1b2951ca5adce707f762085bb874f6ac4b2c93c6e372281fa366968daf2681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d07038a24b8a30620254d30b2fe33b78e2e630b84c60209ee626cab5d3f5fe633448380e599cc973a2863c5b0ec1d700000000000000000000000000000000140b50a2324e0fbfe35bb30cc56a59aa5c7a6ad8d7abfa95c7e190adb462bd561ffcf24ff4fabb1a29c229cd550628421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000563e01f19ac216aba65a3c08b48375d677383df3a523c8c4eefa9003e90a878014c6b21695bc654e153cd39eb0b98460000000000000000000000000000000005240b2f7ba245679e9747ac4785961b0563f25fc30170d466a17a869736f6e27751abe58b4ea25a40809199e921be581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126ff2c36696633c84576158b367a813087887793b17d2402a73dc270a52d4c157293ccc2f1ae05f3229547491573c900000000000000000000000000000000016de49862a53a78ac4ccfc58b805860d6aa5f64938267330a61b47149011020f73e7b47a8711aa03900e1fdd3857c5591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110c34c1d59c26fa98e23fa5623a5c11c599e10b28933b240368ec37122a286ba2aa6d06941bf5be48e9593f2e10de6b0000000000000000000000000000000017f8dbffa28376eaa130ec1292ddae4e1bc5a89912b85e81760080e73a915ba05908df61c83cd9ea7290a058933853ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000caeeb19a559a61cf10693f536a0c7910a1b0d17a9a1af27dee0e9781c9fb3b9d9f060c34b277e2bdb245a019d97de650000000000000000000000000000000008d3258a6bd9e305fb5b0c7b122e73d42cca9f408938782c62f4f9bf985ca498d719f14720050062157317d416b4f5011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000242a215a778e8634c5de9869ba376a45a3102144a931106395eacdf6dedf176668faf8fa3f1c9bbf3da91f2026d4df0000000000000000000000000000000000be0e93b43b5cfd1131eeaa429284fff00071f216aaeecccb09eee8e16b0d1c8369f11b29a0e852a2edfa1d12f462f7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011477ee937f1038f11629ad107692793bd57987949c437c0d22c60fa9f6a702a7205f4cd7112d01c22a6c4c35a3cbf8f0000000000000000000000000000000002b615d83f669b47fb930904b95889a16ce7556a85740e9b17cbddac3782b40c861de8403e24b8835bcfc3ce66a9439d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e251580a4ad87fcb221ae10ca50acfcf0ae0b04e61bc89c599b256ce226ba58a9dee7d870f1127fad0eb06433dfa110000000000000000000000000000000016ad82672935ea4357c28e8e68a04c94dddeb2a87bae29115beaf5463db32aacc3313fff13041a3735611ef9a806fd661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001990cf8b986b039aaed5b3148b5e64e2d2a7878a829dd3f47a42ab0dfc7d5f2f73af754493fd70bc8b2f06dfa93de5ed0000000000000000000000000000000010e4ece74a0211dcd65cbcccaf7ecc5bfed268cfd9913ecd46d4c36fe70d28b8630b90ad7cd1007a8a6e2ddabf349c331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a4b0486177ae05b3c3434c2a6f418788a9985e71a0f0bc1f2364b3958874aa535b178dbc321e5b8c8accf7fe485c170000000000000000000000000000000019055decb137c1dfaf7a80dbd99a36f7558643a55f0796fb374d484e842d1c53d315c1d4048009c2e3a2ff61a5a507aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5bfd0833ea70b619d3a7802d22c48d69152b8f87ee456ec7034a80c62d57a7adf24289e0c4f2b2ca53721010ac89ec0000000000000000000000000000000008209ab9f56c17737110f8bd25dc0d6048d8dc98b053c07a8819d09df3a1979ea333e96328c05535b15ff003438aa60a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009aefe07618e05395d7ef6f84f0dff137ed97c6045b3418032f7cefe643b1d8190ddd00c515b0be39955e810bc3f9fbe000000000000000000000000000000000f1a67966b1f94853569c13e061fade6f2ec0768c89d8947c377102e8afe186a6dd9297cb05716e6fc2010d35c49e22a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de26424f245824b162cdf016bf5a7a2fb39b11b120145e61d9e36c37f425cca3806ce67ae0f502609266a1a1abb5da4000000000000000000000000000000000e4b2f7c92e791e5c1458e0d28cca80c389592ddd4e2b1652a4f8d9808441e969f4bdb0a17510d658abab9c2ef0126a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fdd1c0a0ae9b58ad4461395a643b5ffd5e8f17221dfe11aeeb3ea447e7f8c15d699271f12c8255c61ba39e2adc22d9f000000000000000000000000000000000b426f2bf81287c64af3032a93ac6d66b5835aa50d9a58340adea4d05189d2d3e7fe3b4849b311a4bad36af9d0b8b7df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f250f17235c0f8ce8a3aa846d7b4a21a2a12afcc0e864df154a8a4deab299cc82fecb3c0cd0aa4a907741e5892c1840000000000000000000000000000000009fb45d5dd81e18e4d79c089b406856cdb956163916a0ce206bf02a4f7e59fa765f1a0496ee1e8816fd3d6e83708617c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094dec66fd6c404091599d8c5707e285abfb74f8cf7deb4813f04e6103b49603bbb3ea33ebfb607c1b41361e5a9b40660000000000000000000000000000000002c43d7dd2744e3503799781f00d5276c43a8dcb5e0d13c8d26aafb0ca8742b1228f07b0587648d36982df61700a75481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cced53c4c1bcf32b7b1b4d6b393f88eabf6030123dacab45589d1c5ce05a0f4748b03c7ca4f9b69bd8a209037227406000000000000000000000000000000000cd6d52e37d01a8cae2a554159e48f195a66704d2e3a074283a82389d729f8975aa152fac8254ed1bafd222e18ce810a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a249aa25d58f85df35b24e3748e0782067de47b9486dd9e9fed035e9f5cbfed8cf855ff1d92d2fea7697af9bf7e980000000000000000000000000000000001212542c7d3a5f2701087dbee68eeb70eba74aee461a8d50eeabc3acd75b00e57021780babcc7733930d7319d431a7141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001452e5ae053f59b7d7469eb6bcc02bec43495a6108c9d82e9eb8e3f753300a9de73505022ee042f54740c848e4b791fa0000000000000000000000000000000019aad1914e4a083b3175493cc71e3d2a217a2a53c9a0651577b7206a5ec337135ed606e12e74a7a77e8489e50bbbe1291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011fb0dab493e4a49a35de125f487e15fc682cd65ef1d828e053959a3b9c4593db52d0eeae7623d993c7200cc4ec11bab0000000000000000000000000000000002d37a38d18740adcf20d900b967abd2a351ae0071694f42134ad0a02f4beabedc0beca28a82ed5fb2d68a1c7456f68d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0e798d1da2bb8a0ac6195cb38b64216b08de09d862261466a8237a1baa9dc43473bfe88d2a4fa29b3bf86ef9b2f0c5000000000000000000000000000000000fc213b0bc63334eb19dbfa75cfb931a1d45e264c4ec1ac8788b6d10d84203eb767d9257542517362e70af2df7870ea31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5031cc04d61f37230de8b3891b235fd1d99699e605cef5b2b3cd0ddfa37e73ea6c46bac98172dabb1eb0f3a29cc4dd0000000000000000000000000000000011cb1096b4f7e8aae4719071e251d416d75beb400c3d38d65814c501b2190bdcfb278a58bd7648f0878bc628da0ae01a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f8e3d5c0647040c97680f1ff18d498914738bcd1f19c6d2bd1a145a39a46212929a37b59b50200b4a778ab30a7a1df00000000000000000000000000000000125151b058639b0e843671e2f03aa164887a7953963cc345827269519eb75fb97751092039ed4eed02fb0b009283ed441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7bfd0d277d96603a189e91e5aeb54c5e27b1011617810038fc70c3f4fa4433712785f9fdb159ae52560f4e9782fd6a000000000000000000000000000000000097671df6ba0bd058e25258049b8e7ae654cf0d6880adea55f7271cd05619febc3338508056259c3548d680611eba7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b8c137d7b1989addcdae3c61ec4e2b03eecb72449018df3654c182271c4b87d643fcefe224cbf3822313bd4478da3500000000000000000000000000000000170a8203907101521500161e30432b12e6c606f168706bf348b068564926b3cee82de01ef6c8279cd17e6335d44625bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131423b93ff65fc78c6eb057bb4b82c0c6c76bc8effab1eb8ccc685600e98eddd691301ac040dfb4685938bee3607d42000000000000000000000000000000000ae9a39de24083333b8eb4ee5c915d26d47747e19438c88a6f46e9c0578b54bf6b46c389fcd8b8489789d46c8dd862d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d38f07a8859d00a18780484bc61fb7e69d1300a8a6dd43cbe6812ab2eb358624d675768615798e44f63b925e9586ca0000000000000000000000000000000009937dbd99108644ded74e25453ce7dc61681d5951f71cce3b0f30a1396be3bc711ce74f597c42b43a31c441852318611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f3f5373af9130984eb844c41982868ffab4e78451c914debe415f85e54853dc3b9e007b4bc070393b72b6ad31f893b0000000000000000000000000000000018c9bf39ab48634ef64f524c0890998355393b8ef3e47835d1183f22d8ab1c21f082961ff64513a31d8b030c86aab8cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171a3c23e36c24c840f12e0ee556eebce10fc8bff3544de7573daf980f2150761dd859f0fc7f5b4c28580533a5dbd2f200000000000000000000000000000000036ee10e8606b22681eca0ae22e82c8658d1b74fd9e67d015ce51e3c1a5431b12043049197bd1bcdfd67fbd616f8d9251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015b60d487564e0c5d891ab55dfa66b97d89cfb6a82b042752fd2f3febed1f3f05f126a2acce31b479bd4792ce849b7a00000000000000000000000000000000079a3c8264dc09a4e0c079dedebd6ea74be6f583c4c709a6723f80006b9034b9d1ab33288f42d75ffd032bced45279c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a685de9d665ddcdee62c1e46d2c23eb14af57c0456b0f2e1f87036336e02e4b1586d9fbfa1d220694a9fce9b1f2589d0000000000000000000000000000000016efb020d23d4af065b1faa35cff126fd559673558c3521464d11444d36d53b51b4d2d57200dc3edac61850c93c934a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004945befbb3cdf1a402c35e52a4f98af64374b16955c89874de5c94de6172c80d1b5ef45f452f5695ba69f2b6c98fa4700000000000000000000000000000000198708aa1e6ea62e206936266887630689901fae676d20ab9710301474b6d9ab7300cef1b2fa7c29fd5ac7edc183d7b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3afb4e51ff5b7490de6443043a5fd09602744582b7e09b8df37bae921036832311c813e61b5f251d8c2b2a75279a97000000000000000000000000000000001967679d4deb5b5eba52707d29db1f7b7497fff4a6b8a466f5032530847b3961d92b66659e2f00af76ac4d8c0f47d9411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197c6b6ad61911fad0c2176f4831fdd904479fccf095c87fd3a4f03284a358fc7cbaa990e1c7cc4f5c7b97708ea0dd6800000000000000000000000000000000181ff59a9d5eaa24551dbb8aa41650148b898b790118cdcaaafbc9a6601eccb4d073b0103b30a1ad7e86a71aa5a8f9841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150da3842fb9828f472e7e6e8d8dae087dc6675fdaf5cab1d18b3599fdfd1b1aa3738e99cbe532178ed4f35bd3302bcc0000000000000000000000000000000009361016c5b9298429686f05f0e6ac31422c85d0a0e9df3e8f978bd211a2a448ddc272118c859da42e9005e46b7c6b7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000774244d0644a14f92fbb056cd22c2b3eabf8f68b464d71eb07c6bfb77d455240c3278f647d7b1bb5ba3bec64ee96b6e0000000000000000000000000000000000febf6fde372aede0d8770246bf1ec6c19e8497c8cbc7efc778bf068bc008426e560fc405c35b7e5c50421bd3ba86241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109a51d9e8ccc37d4b9f4d13398705e21a5758a8cd35c52030ebccbb9bc9e9f39d2b923c39e5b812493e4a7ddb62f15b0000000000000000000000000000000005083b394ea0b910be8d4b6cead97d3db3e5d7bdf0c6c85316db9199e5ec7ea11f9c8c0547863fc2e99df74f7d36fc911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001607dbab442113facb723e44541206374b6481ae149e0bc02ec8c7d8a63b78a985bac16f8a8160571a17d5b6265e197f0000000000000000000000000000000016526ce3598223f4dd5700496cbf1a40a9bb9c4e57919ee550b704bc075b5898249f2b4bc4db916fa259980d3416b7911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133dfc469ddd7b2bd54313e716990aaa96452228fc5059e4b31793a5031d664fa83b4535497b1d9c5d2ec5e8267aadd80000000000000000000000000000000014a3978a8f93c805833223798353f84f6be8fe2eecae8efd765aba76ce0b425a1a923fb9ea6be3e9d7539645f415b5e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c82768c6bfab385d9b159e5700c82afd6c3f9c278223cb05fa5f560dde74e6469b2191828f2ee28d0c494f67e58f770000000000000000000000000000000016b6c3bf3d54f70748fb2ca87403e28dc1ef8f8e1a307c93cde10147b64fd48cf38305aca587e48b4738e76593cf11d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ea26a395949cf53468899d9ce5e9f8f25ee897b153418f221c3b7d0c0cc6e7c5badf322eb5782fde997b867084511b0000000000000000000000000000000015ffd14c42b08749579c3023e01e57c66ec60e973f8393a8fe1cc0fe521786c536a229d735f7af4b628a21f40f9a54331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0e02f5a5c565c87bb4bb97f69ba851865c255a28621e3c1d8d39c91a5c78544d7dbbf9cc12e49cf99496c928c5f57b000000000000000000000000000000000a52c5d0ed4be22a71a8a1b46b7657d552d3bbb1961fb53b63df75f6a57a540a7480627acb036ec151bc8448805cee0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003274aa4c02bc485433000c2dfce9d2f1ab44f86bac34d83783173dd120e4c13875786cfb4920074b8ecdcd2c61951270000000000000000000000000000000011e9c9884851a9fe4f4657f68fd7b09f365090cf5e4d43feb98b95ef4a130fc226c373d32b8c89d60aa90de019f2be1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a2899996b6bdc626a62bbcfc5d2bc3f0d95b7fb8d4438ed75536bc3dfcb393877bd2c6b9fbc0d9f2b80d862ef475ca0000000000000000000000000000000008b73eee57266cc61259ce83f53dab0a2b7d4e32518ba022a9337f248eb3f81dc2a0df069b8856c9fe1bcc0c7f8711281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002edbddcc30581691c513db0786ec43efe1fe7bc477e94a38cfbec6e38b5b5eb127eff6f4a1321491ca1b038e95e58b300000000000000000000000000000000082a9ae9c695869ba96858055172ee5a4a96a7a0c87752da598be88ff563441a2817719900f1b55cf50e2f45a1886fe81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c4333a1d3851ee7172165b101ee9527e4835b127cc372b0e1c9bc428bfe631cff04b19aca7371cf9d34a4600804dac0000000000000000000000000000000015618e3c00134ab36feb79a09b4ebf369a3ac662c4a5affe95b34ba3f037b2d2f71d9bcb0c99878c33304ae670e702f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114253ca63a94decd5d8b5d548dd17f2212f46b670f37555789fbc8ca996f541e84ccf3867c651e538800b66f4ab22b4000000000000000000000000000000000143139321cc48d95aa54d419873406e776dac6e72abf439e1bd022d04d06ce6845f350ff792e87e78a552ba0b2595b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180014cabdee922106b29d197f87102ccb508fd58e3f1dc4e0ae3ab0d7871f26a81cc33fef3a0d9c80192941a37204ed0000000000000000000000000000000010dc3f6debc11ce1d4e00cda5a2b0fe7ee99ce0d42496ffb6a39c468c5ce99ae45788490a66d0d2bf5d30d1905432d101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6a1c7c280b998e03cdbdc5bcdb45845e3ac4e902e3e0d36dfc144f6a43807809848cfe2f2a4442f44f98749ba0173300000000000000000000000000000000041ca7a24242c2523816457f0fc422fd61b050b66242bdeedabb065655cd4f96ef0444da0f5569ce0930b2d8777888b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b29559be9c39450a939adac805032cef8ba1f96cbaf2471ce2d4cee4e12ea908591cb04b8a5c556cb13b49fb0a03610000000000000000000000000000000001552e0d859c5ff13a2b2ea5638ddc6852d459b7235adba1d9ece5337563db1ef770fa9f1cf934de7b25b9f6ba5bc2a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195aa4e6d9d38437f8aa7c0ab3a0b4223daa17bfdd4c10cffd3e3456ce0edf76fa0609d29ff212d13aa52512f7308e78000000000000000000000000000000000d1d5cb791811d9f55ae09e7e5fd6bd861b0cd27c96adf82d1017dc1551b4955c7e7b3265a8d381e99b231051a82fc2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a1570f4140505804d5e0296512bf1f5e0dcc905d3319a687d4271687cc811241cb3bf1ffa4922c3fc206b826bc94780000000000000000000000000000000008b6b4598a843a47ce3f2a35ca41399140159c2d5fc9b957eb8867cdb810844cdf3c0d4946a95ec027497b0325793df01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167600db1a9daa481cedbe0fcf1072f6278d3a3ae3c440bf4da08982c1b254fc735c3b219c9c98605e1992f32f76079b00000000000000000000000000000000181a0400f3cf861cba151595b98a637d6530f73c7bdb0078ae010e8b8b6970edb2d5b578fccafa0130a308e5aaddf60f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ddb2876bbbeb37e50c4d70c296845d2501c13636fa0ba4f6ecddb6629865824b17f5fbd32366ca1032c23cb6f5598ab0000000000000000000000000000000007cff62339543fe6a550ee20e0603c266e09a30834d31165e2b7d9e63be328e7dafbfd74838d961d6a2c73f074884f0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112381896388f90d65520fdc925c7893980f0f05f93334d312486234e0c4e7b8106cfb4f42b80b49ce11e9214bb0833f0000000000000000000000000000000002d53bb9e60e1ef98e353205f61a2e42a3503358c8d92242392a28ba6be2b18560e142734348dca32fd693033224b21a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001539505d4cc65aff5b9bb9bfbfbe3b9da5abdd007aa24515d9326e6b754fbb60480f1b362f90ca44fcbba01377d1c5f4000000000000000000000000000000000b3f19a0283a444885a2247213f341c6fef72c80fed62267b812cdacbbf90bcd82af8f4eb1875d9669cef6ea0f3a0f0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006388d0d25d15b28dd926d9f3c3a9fdf56940489aac2c0a0d54f03c2e2699ef4a9d5ead9f71e5cb8c550c5443a3da8b0000000000000000000000000000000016bc859ce8d49a91aa2a703bb2d7be212912cac8b1e48b8910686c1cb92bf7c4ae8300864c011f184b95041a64dab8e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e78916b232617ba4043d3ab46a12ff26442d529aedd991257571b5afd27a13497e801bfecfec7e8ea87abc67515ebb20000000000000000000000000000000008ff2f32d68630778bddf9be2b3d0656e2a5d2d9216f37459c69270eeb33a5cf6237e7187aded023deaaba577f7a9c3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142bda0f29d6c1c59c613914b18c455d4032c10063e11aa5b34eb29840f506fecf36f3c967e1c974ec354f2ce530c8c900000000000000000000000000000000101c60718bb92eab7825f6582fd13c8f18d6036de3e00e5ae84ffe9fad68c3934a0746923eb4fdfc797889c40ce2dd7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021ee757ed311336856ba53ac652a67bcbc692fa7648f86ba7a9ad58d61ed24615782db8759daeda40d5c6c68aa397a000000000000000000000000000000000118c983952339eb74c4c84d111d118bdc9febe779b83209a0fc18463ef52560b4405742717295c4bd22b61a5917dc6731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2a41d496de0909db486ae7ca58bfc00a21c2bc9feceac02af82dd6456ee23f13209359e4951eb48f7e7e6730a4467b0000000000000000000000000000000005ba9d86b1d877256cfa13a9e4b4bfbe97d68dbe2dbdc6b4ee94c3eea5c94c648581ba85a1b98062b4d2247546ad6f3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc177c333583e0b5e0cb32bb9bbf8a4c1429cdf36fd9289ab267f56a67f911f028966ddf48e18ec38b0b167fd5987990000000000000000000000000000000002f074558961335e8ee08cf740df85560b8effa31f3feb0a323714fbdabc41a46873100f2b089305779b20143244150c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff9fd245055c428d23ca6ff3431508ab12b97f04aadec9a2abd52227d0dfe24d06094f440d94001deba94c77f5f74f00000000000000000000000000000000003ae73396d6a8e4b44dc563d09e02e22aeda4c6b94376597ab077a0fce443ad07887300adb331ed08f6977c4c6b4bb731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d473f29191cdbdf0ca0ee6ce8ae97ebb1e6fe037f7dbd72b4e25254eb356ee5a5a0fca6ad46c3baf79d860b7df3cf10000000000000000000000000000000009b175841a596dab5f7c7ccc502c2725dc1026776125bb25e781464a0f56aeb68211c2b1e08284085a500be2fe4fce6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001534d435f1e1355fe59ad34b4a49c134a73f72239211d0bcd2e99f73875470e994e4d27384dda9a9386b0b0411580ed30000000000000000000000000000000003b9d7ea495baf120907b57b62a2ddf555f1eac696a8b7117e6fd995e1b4428986028c6777d3cdf66c888c1ad22d0fa61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012ccf42c61f487c5846577553a8f859abc0032329ade6b1bf46af1487feff12ff2f07b607ec4fe5911d25b364a740af000000000000000000000000000000001176865521d72193e29435b1e2c4938de6634d1aa67b129041e3793a1fe2fe1359c4ea1ca40dee75b0ae3b0f652cd3841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000547e5fffe8e658de2fb5e3dee8aac138c2ba0a134dfd547b4a5d033b23d322b9ec7fe8d677abcbb12104b7ac93b78fc0000000000000000000000000000000006a0a850573ff1bf3ae82aa8cf4642883dddad2a8d298ae0c9d6d0264cc61d7cfcc794047f93dfa1e3f3865cd9d192f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d52ad8fa14e7251acd6961a82fff5589a9ca9cc1480a1a374ff51a2ccce11a77dc479dc91267508a7c1643cb7999e2e0000000000000000000000000000000008e9af828b3bacbb6a6b8b120245f9a396aa33a374fab868e952e935c7449f3794afaea8c9914820a9942862c1951ba61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000732e4e0135648f4c84b6630eaffcb8ebc0cc1d16c0bb3503f54ae42c21f2eccd5e7500750a0cf718f1066f4bd4917e6000000000000000000000000000000000fafca10b5b321edab833df1ce4f507b3d340de10f4ab9dca5a624fcbacbf83027ac8ce611c9b12bb26625df8b8a23ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b5e652b6aa0d9c690f0da08927b34edf4ea38fcc3688cf403560d6ac85420e6e82a1671a5f8e1aab71cab365f314b40000000000000000000000000000000001b4dea1697b91d70dd336e6995324a774795e30e3c489b517abd785d2b7476684d5ddecd46c9ac8040bd36ad66ac0df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000abd338e96cc47d6bfe6fbad6b5570128b3062a96b3788e660a686ff500dd31198313f8aae952026bcc4813636a71443000000000000000000000000000000000571d5dedfc87c1c511359f3e92937c31bc8b2f9ce2ebf0cdec8650264b48675070592a8f75b0915c5073abe92bbeb941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001676ca539d13baace8f9b334cab59efdf25a6051074e55a3d0d0d5b295c8f32a78d3b74ebe0631ccd04c4228251d731c00000000000000000000000000000000175c364a04c2b998791aeab7194951d2e59e0b2d68e5c11fec8d7efd3008b1e12208779ad3d84c294d677e1baa191d8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aca2ffc34b424998c4dd93fca3b0353fd0d742a83f3fd1075b34ad7fe7346812e0f3ef387cc02304de6d8a9387a004a0000000000000000000000000000000008edfe6a171773b2c3cebb0dc1608b747c0ebcfa1dfeb17932e7e86b5930c4d1774b5d496573526d2cf0f91fc04f64b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019769dacd1a79fbdd91b6a9c790e1e65f48df7551df4376237338c930f594c2e357d3c10c6565448fb8b154914f43a1300000000000000000000000000000000064dea8e3b87ca7c6e0c50c9a3fe0266be84fa7e32cb05ec6d92cd47a604b85691830abd3aedac60e14ee857f17392951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037f9f3d931309ad77e19bd41985423c99330c1a429497e5686d7548cc9ca64d5ce11750bf9d3518b4a7d0e457a192a20000000000000000000000000000000004d950e3aa80f8da86a900490328dad8d3b6c91f5ae69bd331bc753bcd304c8dc6426df32b92ff014d6d1e6081ed718a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f261ff25dc59cd58f178bd2ec11bba46af97081348cd36f5b9abc25cabf919e4634e5c13decca152b4ee9a19fc38cf8000000000000000000000000000000000e41fc18b3a98db5d642badadbb3cee7a51caa75bb30336668865fac6cb1d829b5d803e0cd563e13cf7eeb729f2539131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fc80b9aa9c19f224c9656f8b286d463b2df493238efafdc2b0d19855a7c69a53df3c8fb067d5300c98d78bedfc2bdf000000000000000000000000000000001081013c98b98c58873eb5accbb1c65b6b4a2fd62717e0b472a10d990ee93d0d6243e99a14eec096ac0c5b448eaef0591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092e11281788bc7c587e7eac90cd2128c2139a472548db402263d57e3bb25cf989df4cf180ae60e4af3d5f06e9286f1800000000000000000000000000000000004b7d1048343fef29c6caa0b3b99d56830298d53a5ff21c08b0f42cf092a53dc3c1af3bfc7be1203d965a65f17c7ebd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018db196508e915adbc208a8e865d6fa3c42ad9555040fc4cdaefc449e8f4e491176e046e295d34049353cddbce1665fd0000000000000000000000000000000008e2fc2335f9837b0d6644315d4e268a0fd2e4f7d8bd2ec7cd6f331df01733128ba7f37d3078d662a3ee3419434cb3ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014783c4a9297709af354e5bde16c7b9ed06667c414eb58b1fd76bda9841fa79471fa3103738735dee7577c7462204b890000000000000000000000000000000019accae5e488a5e5bd43ab907967aeb56b53b89988915fb23f69d3613601d0048bfa9e962155de644aa5c4e6bcd28f811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000039fbbc7f3071e4a65d0cffaab8400b12a4e65a388eb1095a410d59d54397f07208edaaabb1e035ed7c1beb2f5d9177000000000000000000000000000000000c4050242a0a68e3a96741ae12e2135a4f9a760bfc704802d6f8f3fbf4c81f33e988d66939fb0e413c2f6bf36b4835bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c879e3d837e11c02c1717ced2528daeb49cc9c7339f2b15a78df1cae041de196c310839e0442cb2fb1e19530a8e7e9000000000000000000000000000000000b9934df03dd15cfbf7a08b897cffb899115e15c2da20e9a6150f1ee9561a5d1c2c126147d77320fc90bb08589a7019a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c3abbe331e153cac15fd6879e28c11eaaf795a93d0f4effbb96c0060810a3560080d3aa1b829ed7715ab121ad383be0000000000000000000000000000000003cf6e75502c72cf4af90aaf8335cd9c5b9ca58ea7344fbd39c1c2f86ca8ea05b34508021bd75a28fd890c49eb3a84b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000908154c46cd9010bd1ed652929ecc2f80c3d6d5e21ffc779935b3c2ee68b05a414e774f832625c5a237a72fa31ed19b000000000000000000000000000000000ee02036cd21a78a9e3fda568e23142493ffd40af6a44241f2dcf0398d6c5d741ac7e2e059b1b60aea7d27920661b3651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000746175511538463411609ebae42d55665532e27f7cc72fa41acdbdec00dab96300fdad67f5f97435b47075937e860a8000000000000000000000000000000001897b46a0fe8a4ee0f7a5aa675952fcd895f62fed550fd12bc093f9bf9472191c62c399c17b9ed2c86f38e9c09aead561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126a14415234f7b7f4961ce08c1e2f5c18aaf6a5643fe8cdd35483645ea8e5040b3279516e1e5392a0915d50848523aa000000000000000000000000000000000b1ca84dc81bd18c355046c637a06f6fad3e79f5e1bb464ebae2f9146e71420a9ca10e82577f33b40204f74e18315bd41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ed2143f8ff2ceee5f7c0ec019624c60dff32ead310363a3a6a2a4302ba533c012e1f221165eec387811e42b94d79f700000000000000000000000000000000138077561a3a47b50df6012a1b12dee3942435cf456becc9f5f2a02f0bb07e3f722c081b4c94d6289f11eea5783f78181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174785e6ee2dc015edadc2c06fa12f7b52605e2d350a2031d85bae750ef1e668fe728ce6993b7fbe4712abf10df46dbf000000000000000000000000000000001344e109ff7dc1be4e0ff92c56c24d87c1ad7ada62dbb6403650ae810b0911b4d72bfb568621fa0547645e3ac0836bc81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000950ddcadd811589052a27c9202cfb690815643addad28ce53fd3603ac27487fb921b6eb78bc8a55ebee0cab5c5aaa770000000000000000000000000000000009435f3b84da69e4b390476099a29e5d9689203ea903fe85a083e9b8f69d9c2f3e8bfdd15d8718dda149b3e102a9a8781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d8c5bffb0270ee86dfa6fae368ff227f02cfd651656d2689413ca4fdf7d4508b172606ec79f96d858003ae4039252c00000000000000000000000000000000114fc1a76cf7e00a13d5a6a48e30a40bbd9e18afcddae1e438111c154ea45cd18f0c43c55cbec6b65e192bf164b3f5dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000645d299d8e43acb8c4ed68875f1894dbb62d92c303d1a8f17397c6196f96d2023143fb9b7ffa654679444bb44606eca0000000000000000000000000000000010a962a86dba6e7aeb3924fdc8e1bcb71ddf261783cc78ea32632e22c8ea0e4d880cf476bf01c5bb0c9edad819d9b8081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129064f29ba660f2beacbcaac8edf9db069ea9040af0c1328beabd4f22aa0775460ada37c8b977adf413a5fdaf9726af000000000000000000000000000000000015945e9a1cc0c7dc44e004a0d7e37104243c455583c650ba89b16d4a3e937713165d74d7e1ba27431eb84668bc152a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165b3b0755376540131bc9dabcf5f2eecb5313ddbe3175a5833aca0e2708ad3ab4608743f142f290cf48289af685daca0000000000000000000000000000000016925fdf22bf307f4c79df436fc6f703cbbc62222c5999cab66b3647c7932362a1899d1e4648f12235e4cc94bda8606f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001125721eb65720484c8e4ce025a5747852282ffaa074b6dfd02db5fcf35242a115118cad1d9a9353a52327f698125000000000000000000000000000000000006fc88222f75bd46d256cd51b0d7e831822f3364fb95a95fadc7fc03568a756f2194a1471b67a0d1c7223396f48ecd2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c28094f7effaaa5063b3248ad3716fe28021ab275ba03042f79eb8591b56a6c8847a865ea72139ce3d3ea16ba88fe1b0000000000000000000000000000000003c5daf1698b71e496f4ce285d543916f6733a1d680975b3111b37ccf58a456187256d001b4259b4582b7713725c3f381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a70c414a4b2b1d016bf3264011b61e3ff595fb13c39ff274f71d36de4b3eef313b688d19ffcc5ca74342abb9c095b6c000000000000000000000000000000000c8818c5f90a43da2b6b83aa90643a158dfc28393e2f4931cdd38e7a3447c9404c5e16f7156ee0c64f126754ef1153201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001743d262f73919d0208a68816e52625edb7b29dd72452f14efdbdd8fdafd9d85c8bd45170a072bf3c66e4e8a18a14eb3000000000000000000000000000000000232146218c7cf14a78cf16e040732c329fea13128b401a382b0f937af555034d79ffd5e4a546a1db52f295b3d28ac281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015069740b395f97f5253898ada3660600e80f9aa0413b9e175d7168771c3e3e42f288480710210aac610feb22b1594f20000000000000000000000000000000015582ffef832ddd6a4c006598852eb3613775948e2c558ebfdf24c444403ea32383ea248076b1040ec0b3c29a166be481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a282da2e9cbf23a606d0b824d9833600b80d89607cab48b7ed0326243ff90b70a9b6e1ad13d6e25f2fd82462d43e4ab0000000000000000000000000000000000dd79dffb171851c22641e80b1cd4a44d5fc9f07e58e54d24a361aaab1a8ed330fbd8cb8884a52e4a20e348ae0903871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006fa5999ccaab6901669249cca9ae06bfd7a571e09b58bf8284ac27a884ece77bfaadd3726682fe7ba9665a1f4c52f90000000000000000000000000000000017a4801d1cd9a59e9377b8286ee006136cc97662afdfb00e57fc0ff294f7f2641cf0d56afd6b2197827c4797740e0b0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018aca47435916ca93d4e0b461b1c03d23a786cea4940ea36cbcb4eab2bc9a624e56369891e6fb118b40953fa53a0c983000000000000000000000000000000000f679d5aeffee26dc4c200b1f948308ea011e1c1f2aa3b55924f576a9f4a0792e44519ec92a7a7bbd31f31b0c82c89551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023e5d1f2834b61c8cd56ddd41b00b9009de594ed77480f20498bfec01aff6276b39cd8bbbc872a011d3c79dc10cf8ba00000000000000000000000000000000103dd30d89064d91c77101c101f5d6e026255c4029ec39f43023b929fe4309c1ed072c5318399902376e38567c3392601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000306989696e4b04f85681594ce571923228801e99f3e464a3b1623b4f977079ebda82c0651cc23cbe80c8d881f1eb48b000000000000000000000000000000000c0081810b38f1834da22452d289ba62195a3d429ae39565e7b85fea00102c40ab20b0ac6bedffc01446bf01d05f5c1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bcb596eb18d3f69bc65152705082d10ce3f25925a314c0bd12d9e0c5ddfb874223771cf95a4a7b7176361501c4c2ad70000000000000000000000000000000014b954c6a8092830afeb67b969189f51bf94a2da7a3bcd9b7b42c0e238f3ffc435ff9b989a3b39d9ca0dec769c3b6b8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007bd4b3bb2e4781d4df164f6bf4123c38325e4de0bc86edc41ec56d66bc2746255d1575005c3e242f0a12d1f017b089f0000000000000000000000000000000001f821dca34b5975aa61ffbc793cce09c2e277be72aa7bdd32158167e9703865db0f14c24c82831498178750954ffcae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c9d9a961b2dab955ef5aae435c7e96f3b0f37c686215256f6a75e656bfd9d47b0260da0ae0e2b7f4944350b52db459000000000000000000000000000000000af14a1b1553646662a418f824aecec052ac5e3eaba4747e4a1ec8b7b8f32f5e2c78233672d7924352db9f512428b24c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002af4be64b52ae057b7dfa1b96a8ad8844678b538e70051d38aa1d7a7c36a8b9715992dd670d9cd9b66f37d565f7deb500000000000000000000000000000000133e9a600d959de72ec7174f77ec998ef4890733bcf231ac781e4c45ec3a323151ec2d466fba636c3a9aee3edaf5adef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b87a1057f4e551a0ca8553b19717d751d63747225ab595dbf242df2f49eba09dbe8d1f1bb2df7879a6753bd76085e70000000000000000000000000000000015dbf6e786a4182858650dbd4d61bb39c3a4756d42527423c9748c2d9c04ccf24ad4409cf389af9b4ea55713d92b149e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d938d1f3e39b9eb6bb024a726befaa15a894132a38f835285ae61d164ecb050689fa38b8afda095b2494131cc24737000000000000000000000000000000000199166ad2d50c43c496bdb355d55ec25dae47bd5b8514a8b55204b6a407684db30a88d0cda6943db4e9122449deb71d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173ffed3a502923a0cdee0001301907ed3e91ac6598cdc602aac5d295e3b3da62c720498e535bde3726de2ad52e1a2a9000000000000000000000000000000000e9aa6578309e7d1a71ccac1da24d37310801020b55cbf0c58bdab7a7ccddde9ae1952b17707dce05216e59da6ef6ab91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe95a99f180d017d57b30c962dcebe63861eb0d93cfe5f50be8e41cd8af8f65c0e9cf83c2ff21cc5910891fbbeebefc0000000000000000000000000000000014d169be60848ec8b48ea05fd2cc84a51c18abf613e08efaf7d6fff38d2265f03b5b3fd24b51bbf1efe80ee4d7ba473e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bcc600ef376aa3f0c003cbfd8ae0c2aeb976bf3cac9d1d81194e0b2db1a3a4186b455590ffa94ccbc331bccb9d6ecf0000000000000000000000000000000017606e7b18f12ace88c4467399b78282e1f201da409233f20b66d9c9ab2ffb31202887b5bc285dafd642a9e89ac0a53b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092736594e2eba4784f87da49b487e94d9c0054a5032b57e7381f7cd08544121e4f5a74e7efe74ef997093edd745af35000000000000000000000000000000000349a2ef6c262f37691072edb1591f9586f8983abae2d7cda2d77c7cf3683c86dbd32cc0ec25cbfa2dc46840aba8b3421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c526d8ef8c924fc55c756be87da1de5840f63f6cafdb2ba9e1da9837efa602c677d1680cddd948266c958fd1bbfb6100000000000000000000000000000000157b83c5be8c49424c444362dbcdb5e301a37ca51a795696eda9b65e3ec9e062021102a43a49d4440ce5317682f94f0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002596396344d6bdbd642648aea4f33fa8c8ed14f0ad44b801ff0d361c10b4c666d876495ab0ff6482e930d0cafeed983000000000000000000000000000000000bc2c579af995417abe907e1bc51f5a9ce3aa19e35fa188642c2d0ceaf1c4460e21c498d35b78019033e80666ab1ab671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001294bbe57bfc324e73f9d46028ba61b681f2e28b047f952dd15315a11967d03a5ee0bcffbcd50b5f04bb222f88549f0d000000000000000000000000000000001803915af476cef3ab0b861b6de485bfd8ad9b165827b31ebeabe77c69ff4bfd951f241da59922fa90a8c44d18565cc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c4f34adade99d3b2ba56d3fe71bc04de25eb1d6e89f0fcd052555ee9730133768b1d27ab04c2626201a46a1e8e69950000000000000000000000000000000016aeef79f5c9c2441994624a25528f337a94b772fda1239459a2285fd804cfc34c9423cb0efb2ac28f6dbfeb922e54d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178764d19668f57efe5dda5ef850a52b8998787262888c971f0b87c14231d430978240a507755df9f3df325823f4c782000000000000000000000000000000000aafc8833bbd099c172f3199937daced1ebeb036b568db5dca0245adcb5a41466301d57bc658ed2770699326360fb6851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a89732284af75f0b00ba60652e0b30b160b61a7248b87a44c6007d13b51f6cbcfa23a6f5f392fae9650d3a6a72ded6b00000000000000000000000000000000055df8a7e8bb2e5267774428695a249450e44bf191e1dccac007980fedc261991785a850319e73b3b5433bd5403de5541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016d5d3bba8c9f45634da77af07bfe104db7fefef40fbe082facae4ce6d00ea2390a506cf05dcd6acfdf25e663f56095f0000000000000000000000000000000016a59aa451d9f4e62c719a9e8d914fe8bca8e7744dc68e860e3e9ecb5ad2f9943050579fdbc711406213964f2231ccc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001385428013d8f81e65d2c318568c304451a611ed33e83b63557e1911eeee3c513bb33c6a6472964bab6bf1fc01f5ce84000000000000000000000000000000000c24a17eaeb3efaebac60fa72554fc409bd58e7460cd03c7a339ab5bcff4db2781d674618a41d5f0653990a532e4bdf01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000427b896bbfc3cfdffe6cd45d52fa199a4cb00b82e2b7dae09cd6a40b79bc3543a3a736def66a33b812579dd27e1cf57000000000000000000000000000000000b9bc65ee5d2876e6643f64e108c5ff33f97323dfe34033cb74dee1b2d7dce22ac00523ffe2067eb14d5b304dc7759fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cde14008e6604a7ef648dcc6cc65963c63f10cea8d3532a996ad6459e5a98c5dbb32e456740dfc44b4e5e6e4d297c6000000000000000000000000000000000cc3099031b2a7238d391d4e42b9c6e491a132ab4f5fb931c395100c9dd93950149b77011c010323fad88cbf60a08aee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012cf05fca93fcb755b2d62986b6fdf81e470cb61d712fa389f4fdfde4b037a40be6d8890e312632de8434d0ea755f2c00000000000000000000000000000000017294c2b8d346536d4aa96f14b38f82a6a2f37103f09417fa58a0f890d3ffd53fe2fbfb6197b09b18810a87433d071c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000950f1ff2d698b9ad82428f878cc58e8bf76bf86851f79758891f1190e7b61440ab7cdd4b190cfa9a9f6bbd1762b682a0000000000000000000000000000000008637379a889dca6ab39f1a4b117dd9adf70b97508916f772b799fab9be3ae53fc392cecc259b4c58b0804eeb29409ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001406dc561b9762fa2a902f38cf4bace57a72e8bddc4b7ce096fd258debef773a3f98acf9dbc744490311fd88453a0e450000000000000000000000000000000001c3b481b056db9669640b362fdacd5b788bce16332b3f5f680a62665db7c676f8d2a6b3ae0c378ce687350f40269d901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f24ee4a62d0051d991f9f21e62537ff59831feef78e2ef917bfaea1412db8a328f11fca5e257289d46ad2e4d95adc81000000000000000000000000000000000d7b3e56d18c174d23bf08f1ebfba02a49e80d50776a1ce5544895954e0648413768cfbeab9a3be97fc361e1a7a961bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f37fcc8aff701f7577aba494fa5e12070d7908cf36eaefe6a69ebea5d0c5ddaa7bb2918467ae33e5788f4d4f24bc4cf0000000000000000000000000000000011adbcd33692fb2750e2b2d938c8ed2edce5f699449ccdf8ac5b8f330be3508cbc32bacce9d07cfcbd97a4abc48219f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c873f4b93312dfc235afeae4a123b9e4f24bff25975a3f14ff925eb73d00e78204cc3a82021e32dcedacfd9c91db080000000000000000000000000000000006dbce9a89622e0f1a3661888f3d2f69a15824209f1cfdb01807542ab82d21f8c3df64302c8d1815ca94383d8a17ecc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7138cbc0c40a165fbee5dd12d5640bf0b28147a3147862fc7d3cbff4e92b27d1042221d387b5072e8263171e6c24c600000000000000000000000000000000042b5b8785ad5c14a4494234542b41034ba2fd008e2942f78e0ddcdb44af54aed8c79ce52b1cb1f0ff931db80fe4e70d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6d0e1411fbb446e6916c50127bebdfe6dc106314f55be1ea5d13840f07a60769aae888f4718607d83943c634c350970000000000000000000000000000000018db45d519a981be6021fcc3942916ea72dd80407b679fa50061b899c789b87a010654bf0ed9a5875f2bd112cda25f641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c5b813aa47c06f21b660584d6422cb3f2132fe8b988855c418bd43ff771989a06e41afdca6a2d6a8273750e94c563a000000000000000000000000000000000b6a8644067427ab5ebd5b8fa30a9da8ffb0d60119de5634a6db20684ced1de5d5f058f525fef24d89a483f5259c39981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007aac64751f021f7cb5b3f80a3ce5437b7b03f79125e05b6900791ce938fc4c4459d90d00ed1e9f669fb0489f4929ca20000000000000000000000000000000001da0a5c2eb2317373d59fd16d4db0edd3886d4ebfbc9eaf19c2642f1f2e6f3dcb44f6a0cd7ab238a842b21a8348925a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000267bd2a8e40a9e9ee94af1fa9fa5d7559ffb98c9c8135cb382d97fc6e66e6488f690e2a16344c4e5f48aedef29d1ee90000000000000000000000000000000005d75fff326bbaae44d670d52bf74a8b02534de696bc9eaf66fbe17100ec8408be497044abbd0dfa2422ee797a949c341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029c261b11f552bda47f8af49386ca4ee973ab8f477974ef1a60c3c20838e13e88940576a5f94b7d1f58c23ec5a8c86d000000000000000000000000000000001676b9e9ad2a239b033666b5a417b4210e0c9f8037310d3f0f642cd63c62387d656c7e13f221b501f35736915b50663b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f47f01e087a2b2eb701102aa920b67dda1d2595acd813b0a9414d0cb37769e2ed9fc0aa6bd9ac5d424bf038155505d00000000000000000000000000000000068503cfc4d79f3032927c8b0e8f54030bf2b9f83979b0da4f7db5382c928d08723038a8247a157289e796cd983156c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a01a80ef24416999f9cb8b1d50753a607fd87713637bc4e57ac2b49ef668c0b9ae5ee5427e4c616d2d2f20225419c200000000000000000000000000000000055381c235ad7a7814a04a82feaef27c7645c53ffaf5df4fff5b3b60eb0931530841bdc527854b23bab51b354192badb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7b63bcf9a6025f35ad029eb483bb48bb51291dc82e5689899f75351ee2fe6ab927045c196cfab5815ab58ddcdb58fc0000000000000000000000000000000009c25a6e3753b67bc87cc25f4679774b6ce00d37e5aabe6caf3c4b58cb10ad1ac0d96e0fbfb20d485f9a853c9de791531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018616fac9052ab534418434683983c7b144f2b7622813ec2c6739d7bdad6d706d5c72d94380cf3e38604d7a3098fbc340000000000000000000000000000000017c19b62f47bbd0197cbb33d813e8bacf464adf82ab4f6fea6269f5609cbe2275db082e9883856cc8b0e1b577e13b1d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6d73266155d16e6dd44daf053b77bcabae22ceb19aa8deb47143d3593d63fcc30b2e0edd146021bf00467824f6f110000000000000000000000000000000000da0256ffed3f387e8171efaa335ebbae211244886bc586bbb8d155a0ce7374bb6bb9d8bfc286638337ccb6d3fd920791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd1a9ff8d4b11234eacb6d8e362f2c800c03156057303fcb64fa18dac3260d8c0e57d10d42ba9719117ad2a71cfe072000000000000000000000000000000001757b3d2f217d5070673b78b49e6e4f33bf373021c6c56dcfa8b22bdd66cae266e091dc8ef14ea28528afed5d8268eea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098530102ab318cfb1d126c670c03319b0cde6149bee761ddfffdfbbcf2dd608ea671cbd91b9f02420df44ca3ff7cb8000000000000000000000000000000000048dc71118929473206ff870dda9db6d15a727b6907b1dcfdc8e350df94dc1042adf295c44bf632ccc348c0d94ea62981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aed1e6e862dc2316fa04049a064f4771cf6c03c91b5e1ce72d6a20bc0df8c5c2a9891ccac5a15fd56fe1e2263cedfa70000000000000000000000000000000000b140c3a50c6082cb311ce8be3ad09440f54a732ee26e420220f18a1358fd1f8fda88729e4a0e8ac1e25abd93de43ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008570cce293e71e2efd6cbf757f275b471beb92698f0088511834a9b627c146e1cc62f6f1233586501db97aee6c0beb40000000000000000000000000000000011510affe010d23cdfdcaa4483672cdd783eb2c91ea87bc9b50ea26585bca1c892bb783d19994b2a9d244e37065b9dca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c74029a5259eed3d4e6d816639181184dd4196cbcab69ec66e61d53db7a4c4c953ed9c605ab475b4f67e9801839d9cb0000000000000000000000000000000015ceae837fef73b1339343be14e36d125657e78219d18582c32a65d2af856314e6560c5d10a2e260e3f821ed60ebf6c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009810aed331821fe9628ffdd22252723f68c8f6e5ccd12ed91e0620c9ef03cbf81a02bfb27de0885ee6bed5671e916c0000000000000000000000000000000000d981ce8a913c32114115ff0ec28cc528e7cbe77b351bc75cc842ca2d3ec6907214b37dee36550d86d63051dea0c40521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f41ebf4dc2a1a0b6ea0145d691adcdd16da47323454bcc598dc24cfc99cd13e0ec6d1abb7186c8bf5bd196b949bdc300000000000000000000000000000000193663df67da9390502458194a10449e85212207af0afc7245ff917e4388ad4b52ab5f15452ab55388d40a91ae43d1f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073bd2bc68a882d64e355236eb5a8e3d3043691e97b1882f02624de9ee9378148c2245a720127af9053c6fa373318cc20000000000000000000000000000000010f587c17bd131b4720288281b08b34777367b8d045ef908135488f2a3685caa07e22ec653db565c6c5024d0bb9ff7c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139c00a3519c033c7d19624a171b205ec172a663469b5b825ac4570efa77e0613a66e6446d0848dd73e48bdd5254f9100000000000000000000000000000000008e0da7802b823a49f3ca30fd9e8c36d2233a1d519ccf3877ddf841b060c4b068527fe8a69744db8c2d1173998a7dd8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133c435ed6173adc2ef341e3e1359432fc6963c9df17ea6df67151be27b5178adc95bba3592134adda1df90a59302963000000000000000000000000000000000629836b1c908aeca28e755a021c15e9b34bfb6aa296822d9f5d0ee74d6883036878e47d202c62c1faaa4e10bf6b311e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2e59eae1c975d87b6238671ce5d0e5ac55c5780822a183fb083ccc042b9b5021b5485660353373730572704934e42d000000000000000000000000000000000ff51161a3a473ca78820bd23174a058c7e57e855e01be5fd7e234e0879cf4cd268b04cb7abbcc58aaf4e7ebfd9d62551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011143b11e7048bbff0d0768d5d53023f72d1828b6fab2a571afa9e54c31616c63141488fadefd06fbf40b6777e8bd5170000000000000000000000000000000011f56cda8503ab79579457ded3da095de9ae40286b1761d566558f1307233928190a6e44188f7a1490ea74c645816c091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005cdfcbab392bed9af7a163296dc0e03cc322bcbae0312c4e90470bccd3a8c7ddc2410b8e67798552514f173a54dc0d000000000000000000000000000000000b4e42558c328e8e6edafc714ffc8119bfffd2a707c67cb76ae4cabd5259baa6870a6901431d6af743ddebb1fab472cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c541b69431810ddf0d36d9aceb1e489f1150eb7ed2a700d3c629813fc2b5ad70a37243f32f6e0904e838f5adfaeef7000000000000000000000000000000000a16949686065925bdb2158102e273a567eb4fa17f4bb5be9b5eadfcf9d7a7853bde3c379b5273dbf080bea9f07d667c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010763d3a4dcd76ef383ed2a286aadb321c632d0e8131321302ca4bce637f1ec0dc421a135792b1dbe8917b46331667f1000000000000000000000000000000001920adcd45120840b68d7cb59de44f14fbf5bca828ef421d40925bc9cc42a6d7f6f00ea48a972faa81725b5183270bd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0e9614cd67f9fde907898814ae4ac7d0fbf4100f2feea3d7d49d05baff2dd29c0e00fbf4a5c8d16d953b76dd497caa00000000000000000000000000000000130c74a102c92a2bb442ae05f782ecc7ca2d56725df95f6bfb7387f9579a31a9c40ee9016499e7bd1cca3a3bcbfe168a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072b8012a3d30deda44955b8edd2d5d18166f148474e1113034909989188da1795135af8d4769aa71d04ff53e166389e0000000000000000000000000000000003de9c26320a159e18bc6846e00af52b78a60917b829e431b911742c241c0c965dd9abe214949f620faa871c98b664d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001abbd030cab8dc9c113521600af533c759e50ea1870c79a891ae34f15687c907d2d6d77a46fe5d8277401f3752e137500000000000000000000000000000000046dcaaa8a7da0498b7481776da1aad35075317d106a4635de4d9116982149b0bd388f37ad3bee5e5999d2b750cbd1f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa47f2c5f1438f9e121e7b09770cf6a5b3d7a1522040da6af843581a03eb5ac6af93e9b970500f5dc07af577e8874c800000000000000000000000000000000042ed459f246188a860d20b20680f9e1a6e19b7d2d8938a4a3646900506b09eaa9d67dbf54b35019a6d01fe515d243271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011daa6be4c418480f31e415d80349cb567f030a64e6b183890ddfb1d690ebe01a40c83584ac256dee1ca58d3ab9375950000000000000000000000000000000015bd24858629156c50384d6cb1507396bff8e4dcf8b035a09fcfb4ff40f7d2183cb3dee9c8c17fb93048dedcf85957581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd700cebe3fac881a8c5924e7f29d9d135a58c8a23208161644414638db73dbc7bbec4ea9711de9619ced383c9f0017000000000000000000000000000000000ce131b4af6c881250c47eca0e1f3938884c1aedd7048e990b8ee9f09d36743ca2ecd0654493c2e2970bb55b94d070961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018361375652152eb1495002264e1927bd90aad00c3d82a32ce96f1184a1f2d744201f4f943ef6f717dd6b96d3af50e11000000000000000000000000000000000e2eb1cf8d8111f0d614d1b5186ef1238c57c3a3907bfc23a9f98d31de07864f49eaa3322ccdc4128fdaf9b2e5fd304f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e312092d487a105d3a962940c6e84c849ccc34273ab9228ca0b3c30d4b2ecdabeac9ce9578b174993536087fdfa8e200000000000000000000000000000000164815418fcc5e50bf4a7ecabeb8ccdf8fc721ca4ba24af54cea83026bf0b10d35e93e8a3ab4ee51a456db89a11727621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000369c0052f210617a01181ede90aee47bfc4321361637109b09d59035b60a34590107768bf4295947436dfd2cdf9b1ef000000000000000000000000000000000dab21a273c8e9b87af07f1b19fd7f5216763cd2e04566b85f4de1b10b1f65d458d0d3540ccb35027b549ef0e312c9ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183b501f63779942caa12316fe00479745a2717fc8502509c2fef2b995b1b140bfea106f622fdb000d917558adc2784200000000000000000000000000000000101fefd8dc66885cbe039f37777446237042aa12f417b68cd5d5942a6729f3ab941bd409815e6d5c15d21b65ac0d42941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dee3988a8410062f0aa41c28cdf7807a2e43c9cddecc5afc970416f37838d06ced979f465730298d33361a60a5b66900000000000000000000000000000000078a53dbe04a7ebca62a0dd6e21766a2dba416735dad9cc35b2b7eb7798a0202f29d924583519552b9082ce311fd313c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001742e2c7c336bb78e8d568ba6a5d5d3a99dbbe21b8aa754319b98282eae2d318e0237c7928bb6d91889dc452a6643edc0000000000000000000000000000000019b13d8dc3aa9108af620a5045b58b163594f679510efc725f35d4e028005eecb217cec8fee5b4853ed3f5e453fd29911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002857f6d7065da9beddc64cb6b7e4fc0208a4a2bec25a77c7cf80749dc12baa8cad350dbb5f5b719702efde7b353e005000000000000000000000000000000001687a1d1c8fb22dac02a67bef158b12cc166c54f92c5b09910b7d5018325364a933fa77bf419f6c50c86d7fb7c741f921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170c80454cf14fc2e38885ff416b6b15dfcb4c71b8501fed7dfec7d820898fde9ecb75cb3d99186db1f1618b98e0595d00000000000000000000000000000000103be57ae37ca5d3260e091f46632ac36ccc2e8d21d7f916425610c76431eea6984101773d5e97ba83d5ec389671bcd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a944bc3c69610cbcb0e30aa3ebc86c331bae14b3786056396b4eaa89b51b700eea0d989613bc37ae341788e3c91a4c8000000000000000000000000000000000fafc203a3e081cb92509e0701d84c602d4408038ae24a04abf377956aa40d7eba65041b99250f06880c82bf659d72811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001629c8bc95f143c205152c2aa4ee97a56f09122bf91d101ac72ee254dbf4acdbf9b91d0e350d81f15acba2c804b3c91b000000000000000000000000000000000c76ee1d073351a63a3f080e8ade4dd602014b1716cc68732a9bea0dcfe08687a01edd8722a26697b3e6ddc7ca6c58c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b0d7d1bb038e7dd0b17f3c425460a9c2254345f69559b2de5f341d07fc3a32f01b547777c82dbb2e6071a02d7e7f7b00000000000000000000000000000000161a7e2ae3405b762b06104fd904526a91f4588c413c172f9562f3fbca340fee3c13023d24ebff0381a641fc4388bbd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef12e1679b88aff313fa2426642fbeb62cb68ac6605ae33ebe0e00ca396ff3a8bec7254b33360edbf7b14214b07cc080000000000000000000000000000000000b436f6d2ceee3db3eac89133b4f5be31841a7b0e505c5b2166379abdbddb7a7e25de447ebd698b50e256ffff43afee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072084ca44403d9cb942bcc1618ea4790ffb293d48515f5e8e489134273162427edfd6ecbc7d5b2afb3d06ec69b0128e000000000000000000000000000000000a1d13a8e9789de0320dcbd43b0a2a80212b76038c154e213cfa018360ce5f2ddea6384e4d119f52e9d5493574aaebd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000104ee685e35e23a581ad06f24f3cb98fbc8dc41887b02466f60f05b12534ee63b98b05e359efce8c0670303d6e5e0b4600000000000000000000000000000000146f6b774e1e3a42f8e009477d25ea3203ec3727b2bc857d148a29545549d707fe4724fa3bcca306f5645e718471e6b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b7e556cf2eb7b4bcb817c7964a11c39738820bdb41eb2d0f222c749246d07aeb1a479cc7c70c81529ea5c1f2d46d510000000000000000000000000000000003330e67685649128c5fea9dea20ebcbe698557740481d47a09484dee09e0de9e26a7dd9c4b771ef8d934b287b83aef91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031501aad4279f50b369cefc0038a7811f6f24d78c8497354258696770062c591f0a8156fd2720a9d25299f8deff57f3000000000000000000000000000000000871d0f5d69923ad1c724091cacb7d49a8c6c231bd66c94b4ed2ba729201dd5fa41b35de1332fa47bec780b6eab5656d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd1a92967447ef8d58f8646edc5ee43353a24d7fc412049126d164b348e2e45e85464884a3c9fce9051a7df15c778ea0000000000000000000000000000000014240846743301dbd3b3e8198bcf6313266e3b0d8b959201efd434e0e6b6e3b00c07402b0557cfc09d0398ad47fa69441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c321cc923815035ee51c1adf2693f169486e23c7be995867414c6347f2f402aeeb7615bedbbb2955e22f10b28789fe000000000000000000000000000000000169edddd17968dfc019b989aa529337fbc6fe93d841d39db96a64ecfcc5e4f3283ee6771f5fb46b40d1aeebbd1432961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180a8b800a722fdff99dafeee24e696f5bd3ee8cc43b1c65f74fd3d6e0ee08928dad0032b86ff4dfdaf8927409aa796c000000000000000000000000000000000a346e071b757beeb12e187faa00190cb0c0cedc9b291b2201937a8e1e48a9ddf5172a4456f6ef63876e77fa195ec6561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011389a42c8494ba585cb22345a7feb47e38049960842f108604829e1b45694b2d1c804fbf85cbda092f2df7bd2d7ca1500000000000000000000000000000000121bf878379dfd6272662975bae1c9c6a5715ebe624e8dcf97a296d22d9db0a9280bf7fff23a55aac91f700f3a95963d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e522229006e9faea36eb4da89afe28277dbc76dae0e30c07402484dc53c9ba754d499403ce70d3b78c2dcf595ff6510000000000000000000000000000000007ae03841d24a48acddce4b902126646befc66b8870edee94e307c4d78b8ce69560ad94813ebd1424df480215fcdcc671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a63ca7d71bbe1c3fd80879cee32969f90992297a1b27a3ace516a64317e50eca6589e277b4b76b733a9a169c3cc4dca0000000000000000000000000000000017d0de9c4fed354fedde304d8639a9cea59cef0a60db729e89381c8d55552f8a3e7429a4856406171dddde05982f319d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001205c786a95dd3a559f643d9a41a0bab7f92064c77ed33070074f6269d9ab3b9d76f77e5f1d1df0d3773d13c2e2a442800000000000000000000000000000000074f31b38260754059ad3a0ce3086286f1224c8bce830d670d1b15397f7904b3dab3907b2a4e76f99f0edf09f26b73401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184bce68052d06c341b2c981156dc72e4c88f0615da6448b4063fa35ea54382a1fd649b6065d5471b4d4be59149f8ba40000000000000000000000000000000017c77f25fbb60958730b556c3346250b3743824f14b18f3808fe093e86e29e2dc16fff60d32ab55d852c3b186e1277ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a470cd7453757ed6369a1223af5f50398f5b3678c70d9acbf5f06960a9f9904b1675cb5961d34dbf274f03f05ffcfaf00000000000000000000000000000000043e5a432c001ef4774067736c9f15d09c304c58408a852f10d2c4c439035200dcfddd927cfcf543974e306c9cec94ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000046dcbdbfe7e4b90e6dc89d8f167f4a1100db4e75ae8dea976bfc7787fa9bdc467a4f3a385748821ffdb2255a10b72280000000000000000000000000000000002156f571f9dff275099b599192154ae5f4a9985b04e576b9716dbfff904ab7586b0b8eb24a8f571ff4bb4d47cc40eca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000765b82e13b52e76ceae9794061c755260684d7e7615b2f3a62504e2844a6cf85d1d7cf6fda39ff9d17eff15c805c93b0000000000000000000000000000000012c71693dfba217039a10281bbb95c59f0b8d4501707f534cb45a6144f1d44e6a76a443962ee4dc344ea1c36f8d2442d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007308bcb2fa13d30cdaa806c48b4bc11d6423d9d59f7ab78264df7bca8ee03b892f6e9b6813468d01be0432682d755ce000000000000000000000000000000000ea33f2c2800dd1c94841f137c9d2877e63ac4f046ebf3aa4f59b38811f55ccfa4d179d42a4c3911e102ed36a7c47e541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8bd5681589bb083445fa8aae38105ad7e448b6bc2b36a1bdfc1748f8761d24000298d6efd37e67f75049cbae72e9c2000000000000000000000000000000000274cc3ebdac9d4c053bb5ae71a03f731593a0bdb035ac1cad406bbcf72cb90c8f4a92a8d8589f1628e587346b83744d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fbbd7941f6ea166742aea1a88f61c217210eafb7e6a2b3faded8cd036cd1c27814f4699094651493f96c782d310de30000000000000000000000000000000003b9fc99928023c37015b34017451ba68115c0ade22ce8249e51ff9b7d58b24ad1e38ea0f4cac043b0aa8eed1f9029cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e9f478bb0b31f1b527562e83da937bc718ddaccac3b729e03c87c6a7dcfce8d4600fef84d587eead1a0eecbfd2d7de000000000000000000000000000000000714c6cb8c2f34ea9205b842b8278cc17843c546a82bfe012dc6160156f41c3aa7584fe2925ed6d11df3edc4d4d16c491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001370df9ec561e69c902e9c176ad0e02332e47404ca6981bbdac3ceec171f61a5e9ad9dd94589bc654f40651d81d0a8a4000000000000000000000000000000000c12ec9143bd0915d1ab80fb1d5bcbc5515473ecbd1a0d393cd6ce1e781b7cf302796e4865405093c89f1ed5b54ff35b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8fd577d3e12d6bf87471876099f81edda275bd7697cba7876bfd58bb1478b8ac59d102bec3cd658f22aa2d613ac3f70000000000000000000000000000000019380bbbd7b532e0c386058dee1cdc36aa632679a5fdd9ade46ab3906e7c021bf6fe985c8387ec3485d64cc2c515ae1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036f96bd1d34c0d46d116256d2983c32081af467cdcf7c73c6c9042dcb1b57aa867ce0d3c4531198ae05217779ea734400000000000000000000000000000000145fd274b536bf175ffcd342a78c9123350b9520db744d6c3b0852dab49afed7b1704b07e4447e9f0ba5958e7a9350101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000336e2290bad016296807e7a46b8246d32edd8b2b7628ec2a38d86962af4cb939e00bcc08eecf8a1c6418dcf3bb86d1000000000000000000000000000000000e473bb5585fbe385d325d761845d1170d8a0116a676a11fcb271bfe6a5adce5b74b0ab2a54fba2fdadc75d3dccd11241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a59b1bd3cdd56b4c98608641c6c5cbe54df9b25004fd4fb79516806b95d40737b1e0e8fd06216a0d91d81f60b9418cb0000000000000000000000000000000007455e41e85e846e22ecebc65737b945f250f346941918f80b1175b4a5ec0a927050ee7839c3d5de9d68773638bc8f1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138458a8b15ae14c7631e2e59ce3bdc8926594f7903173a305685c11848889819861a26250c16a814cd5a005941ec915000000000000000000000000000000000ce62fc63c148b02ca63df1a4d2167d921bfd99278cf4b235613d12c177c7af3cf4149aa91db68af26118a272897d6381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121b854dc021681d4b0b52c499e00d8e8e7d614950e03f4e850270a5243b6fa8ec35d5349c5cf2804b1b0235c264e3210000000000000000000000000000000010699c101af4855d9b9963240c097323ff2f4f01a50e663f00c3911668ef1d9773637210f1315c9aa37a52b1a72e662b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e32cb9667f18134f018ec040fed61571eff27dc2107c03532faad6aa3bd25ef2b63b2e3b68c96503a5bb63b29a20290000000000000000000000000000000000a039b46f7b48303191a6b1a5fd5409c02d492238274159a0a6dcb9c3e06ce3b1c76ee3582fad064ef9ad32ac07639f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033d7bb66cbf5094df15820e69ec80e63f3bfb98671015a440548382549d934673828a1b4831112c76c81c4c6a032065000000000000000000000000000000000de4d3d1acd6f7828621496e476890f98f7229c66cc2fc2da963646f90c45c553f37bd17a53afca717011b33641166061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001503020b96ddfda47a5c654d27fc3fc69db6b40fbd88ece0fd4bb36d6bf509bde1872bb25bab1840451dd5087c6950be0000000000000000000000000000000000ff371616b334737ec545edba2fa532755e7be967d115c2c129d428fb9a6b360715ce03556a1fe5fd24228cbca4924e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019562b278b8cc4adbbfcdfc460a098a896f7315751abf2ed58b3a098b99f955d6d5350bb52d9a194152eb543ae74d4f00000000000000000000000000000000168a1329b576e00ae1b69f94fd49ba623d6fc9dc98e9b26efc8eec7298e5ebd59db4e5034c7026647b44cb0f626478ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3796128efa82e44d2eb70a3b95187033d08b9a929c3f0103ca392eca46d4d91d9f0fc4dbe59a65da2c0274818d575800000000000000000000000000000000047598c3d37ab08ddec9dec5e7cd6c850dfe014c8134f89504af51920953640e87d7c72727656f36c1fb4fe7fa989fbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ef60864f4a4b4d2c0645341fc18bd03df5fbf7ab00d06a0ad743faafbd86793c6bf98ba6179ca44d8cd5548bb442c300000000000000000000000000000000089da90f8b003f5df8963a246590b49a7de2c5fcd99c04605d61b0c255c929d1d2f52b355210939cdf996a1dc58135441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b13c66260333c1c802de032f3d6f242937a2f244ccd133724145c60e06e8abbb3d3d4acfc155dabdac3d8070a18e96200000000000000000000000000000000113916c9b5b685c85acda28aa0764a698912267b80e294924cb88557de710a58ae016cb5c1c72dc144ab3addc82197b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce959f5775cb29a32cc75e48c570dc76b93faca72ca6248dff520a9157c7c99475b278b4989fb344748eb3b44fa4976000000000000000000000000000000001516c2e0984bea90edaf24897cba7e3b843912c83bbc565216b592c626dc061f27a5c93018519cfbd38f902388fe07311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d7013ae671d60c2d6585faca68745cdf19630088b2cedf62eb5882eef6e70c6f53bec7ef760d3a1151daf33906af010000000000000000000000000000000005f32df06ab2eb0671d07dda2c3086d1fd78bbd26fbb2a8065717c4080d0f7224473987eaf8bce52fc52092e639402c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b79efddf383b6360307f10cb8fc59a0bbe2fe2a0df9f83193473ac050c850b749fd59223aaae8e904d34c1016e6621000000000000000000000000000000000695fb2acfdbbb2155811c0be831b18fdadf23e3327793255833a2afe005f10aa0c440ce361be5828fba939bb878af291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d14754af415218c285df7c33f42ecdb176bc246236dbf217fffa21a6c8e01df19c55b979c2c9840551cdae5af603be000000000000000000000000000000001262ac8f0ef308102969d8b6aca662d3e8d2ff45ea11539b348bf1f5bbcc69d1a99cb1823b10ba8c28888bacc980278a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016284179b880e1e08315f169460d49774254181a18c00b73844c26d51d80d8a9a22b818a6714649585d718ded941ba4f000000000000000000000000000000000f798ae360bfffea73094028c39fff1eb2548ae60381d7be6565e56270d90352325b660d5d8c736d5b75a4d531bcd3821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154fd46adebede4e361ef31aec505fa418e6f058c916b0feb74bdcdd61612386679f0236602e0bfcc1c71be5855b7c0b0000000000000000000000000000000006994b386832e7cbf95a47ddaa6b86c7d73ea25b137a435a9fce36d5b8ce9603ca21652e21cf21f77e20cca5549efc581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005dd9bd4d9ac6f25ebc95aec597a6e51c4d76a18bbee3a70fe710f228f7193b797752c0f2329095e2e212c4db3f08d970000000000000000000000000000000014ea3262729837dd8cf09983549fb7836d0cbdbd737e8ff15bdd79353a6f2951dce30f5dc9cea87878e94c19407630871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109934baff95dacf4cf92bcaea56426a732391b0c0a36ba481367e832729c58558afb9a15391efade82d4121397fb2240000000000000000000000000000000013cdf5d0828341d1e25cf287866d773d087c26208205fcd4edd32aa66682613e4c0c7f83ee5fb11261852c05463e0f8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176a689450ecb6a5c48bed8ec4bc6bc63020edb2162c6df2f32d4e2e33188259b03d77aeb543c6e463e0fcf5f43942020000000000000000000000000000000014032970f4e8a2d9af7353cc93a3f0522e90f8fd9d4fdd50b1581295d00899ffe953d009b153647e42674b094cbcd0251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176b9300935c4cabefcf6b46ac2617ce29a321b4e1a62794af7d9709d9d5d8e8a409874bdf71adcfee4a637090dad504000000000000000000000000000000000924478019fd8cfd8c6630a51e25ab6cda3668839a112e1f839766a097ee8207829ff0a410d49d8c3bef235cd3ed787b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c2df58e5aa40ad9d5e96c4505df7904213106a88c386fbd34f994fad8227622a244896011acc1de0a536b14d5684fb00000000000000000000000000000000184c323f04c0beb118d036b1f4b3c79f9e9a5287fc79e2453838f5b71330bc68748fcc7f07deaa04c6682626546367ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a4f1622be1fb32ef380e1b1b4199e5cdceb9ffdb3d9c1778df6f9c214ee079d528621eb7f444fc1b30ecaad1e4ec35000000000000000000000000000000001395a99545c848827d76ac1ae0cc3a0f97ef81720ae11c17e5a1469567df87012bac79b4af1b3ca38914060e4cb1ad4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124699eeedbdf20ace526f6254beed8dda7fc95ef4898b10c66db6a1ca351597442bf27bdccf9d9eb48dad59b48d118f00000000000000000000000000000000125a0c19547e42b62a0a710c3a0f91354e0dab66a19c988e6c2784b12b8eec76a11235320511820672133b4f3b43607d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d0ff0ff3d2c61da49a23246d9a43c2fe3d676177597a9a998cd3f1c8e700d9400fee9f79be8e5d40c7de1ccaef5c52000000000000000000000000000000000d13d47a19880b7cb26cf89437350e302b7285999901c53df3071583d7bf0b2ea328a3b67a2af5f869a068fbb375dfde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032945dd4df0b78a591b6497423ad871e203440527ded4c37d981d72df90e8c345561213c662e9f2ab19fd3c1de307aa00000000000000000000000000000000179a700329a81e49e16025407ab09616e71d8194ae99168bcaada304d1d58d1f4013f2bc5204e8f110c0cdcfccd63d6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d82a637559aee20f8728c894000b4369a1c90487fa29a40099e92b3032135d10abdd768bb132941de6e776472002e300000000000000000000000000000000163bb573c0b1a3415dbb0bce0424df75d72332e93c9017b47faa3932f3679775f8e08b7001c3805cd9675228f5d7032f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167183a84509bc6bb1aae22c507b0de870bf199e58aedfe2a9ca9f3f6c07f84b18f9b8ed252327a0915e2cb3355db5b70000000000000000000000000000000009401cd9ddc828051d78dcdae3864650d4dee7352124150a3011d4b18334563f859f3d275e43f1d1385c258b3a9e05e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d4d23d581e117e0452099752c114e3a3c38abbbcd22251933d6c10aab8cbc9f00e257e75518e972c98b4a2e497b21300000000000000000000000000000000134660daeaaf0e47ddf44f9c239f94a341697411e7bfce9970d924d7f47ce870440aaff6915fff1206d65bab3feee4101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bac3231d663c7e511ae24bf298c2024d90f377b43d64a183c12f8c42a055a5f6c806e8f219f705cefa62aca0d332ab40000000000000000000000000000000019fb4f8cca6b29178fecd4abb4be9c459fb5378d3b2a4131c0df364ec997fefabb974e0102e8f9e074bfba7e740b72141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2f001b75628aa50824737442b2c9e40e7f349861dea93070397f933c758efab9f23c1c0aaaa9b3b09c02fa727d05080000000000000000000000000000000006b0ae70c498cb11698014ddce164807f2881ec3a91456c6c1878d5579717bdec1d7900adf6f730af4c5b718824325141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f9193a4fc1cbb0a2f91adcc4f3aec2b0ad2c9c374d1dfb37c25232a8be56f4d27c846674148142b3c25dc0bb7456f200000000000000000000000000000000091d3665e27165a961a0cbbcd05a4d0a76f1f8e0484004b48d48352e616d60426625527e0682f119cf0765264d2c8f2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6040c77a6099d2c656e113ef9eae784a6ff8aecdb0dd3422cc96f08c79714d86e090676072fb7880f8db3a19e105700000000000000000000000000000000018f42b2f6579ab8641c44ac2d80f35261e4f33452e2c26e789a9f7335e892e469530e856e4b56736287fb7dd3a86f6481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001025a2a0e6e7c6dbea85d133e7f7957a1161cfe0c3ca6093d4f4dd469a0afb4cc24270c878a48a3a7bbf53229a7509060000000000000000000000000000000005a0b6079465da587de94f9b77d908bb30d8ad6db876f787e171a26fc4c9d32b765dd546c57e106420ea9f0cbb82e3ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a961fc66feffb93ca228fcf7cffb9f5d67395089cbf41b66abd82f0272ac593500c91550b918a46106149b9b23de5480000000000000000000000000000000014d65e58b6044c85846cf500b3c848f2d8a4dcaa289efe721ddcafb9b43d18780add9da5e3119d2794144d87d5d65c491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007260786620db1781c952652e41cedb08248bb3435029b21f0ff18a059d4bb33f3e95b02360eb465d0b8ad65364f6a86000000000000000000000000000000000021056eae46876032568df9bad77563d0af8a93c246fdd81939e4caadda28c907d117ecadf5a5c28a16ea10689c92171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eaf228203e88a7cb20cfd33e6df7a7d27360b28e5252545766e1f6057a427afeb04cc3d6e54c68d4a8d16c2c5d39c5a00000000000000000000000000000000192b11fc12edaa22227046382a5b175da2807fc9800b4d3a48985fcdfeb3bdd925b6dd802dfc78e03c58326a9dcc1e3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197f5e12269c2ca204958f523cab81fe2201a913b228db65a8119db403c3c8de6251c53bac2aa28f59849ce5e22ea2d20000000000000000000000000000000008fc2ea559ae7f8d477c09968dc0a8518dbe220fa4b5b4d23a6edf77b0c58c8caf36339854337ff1138fb0ff272a684e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083d98e47f0e06772a8a30043c675f81aeabfbcfc0e796e7a3692a3cfd4a509212da826ad7b8a611753e18d21ae4a838000000000000000000000000000000001680ab3c7a1050099e5c356809c5c789594dad01ccbdc0f5aba886118fb951ff3586beceed4a547dce97abe17b0f50bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b843f3795eb1607e9ae75523734f419d305317b1b9bbcd086721a983762e86d0c03f143714847d1b8b8a9903abe55c00000000000000000000000000000000067a17939ea352f88cde5c55006d513eeceb140ab93c26239f52a5e38ca5fea5ea79eb361a8a88b4583558a05bde0a661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e5c3ae9ff09d628e73a8456841bd78a455bf0c9fd4bc3d6b156380b2f60f1bac3cbe295217851591ef77f3c2286dc30000000000000000000000000000000016dc5713cdeef34f1be00c55788ceccd28d6d4e96f208ab2be2725eb26db55ee86984d0b13be20da2dec3eb3d66d22c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079628e0c0a804e98f4b614000dfe2c8d928c3d2a81d1080fe0708d43427721f006d41c30d235fd5c7b9cd840d4f586e000000000000000000000000000000000262c752601fac3faf8a5b912136795d86a0bf2d925eda9d8b5191721fe5f025eb82673643114c6af8fa5ff2e1e39c1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019fc05759a65e865c6830aefd749c41a4da41217cd1f1f12c8ed0631d87bd3361ac66bbee5f245572aca05f103cf08b00000000000000000000000000000000135a7e24a0459d43c011f2f28723f3bd6fb3a941653bb8e2fed63198fea31b3788b71a6a54bd704254452654913e56671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100bc109e397ce813adfd5e84096642aa8676264527f70d911d4268f28c07a340e16947f1d547f6d94a03bfc560104bb0000000000000000000000000000000014f872ab7890121018289adff4bcf9d2506227edc4f306f301eef95ae3281d851d4339cf8d04447fcec9c33b0fa49d481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b4f6a57eed3dc147fb54ddd5da3ce00ae476f2798e7f1804abc714b6e049bb32aed30bba5a6cae452dc07a1bd657740000000000000000000000000000000003dea4a75ed07f12b51b1d0122650f903b174be68bc04dd9d75a1faa62522fb2ae61ef2d74b5a4a5b9271665ad1c4d051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001102a48bdcd0d19659fcdf51c192f1aa8ae9dc3560b0e705a934c6cbefd8f298b36142eed377aa4d4c76111004c059100000000000000000000000000000000007bbf83d19c0bd4617b89d4bdf697c26c8fa6a159510cfaef9acd399fc18ef93e8397af9c07bd6502389082b2603b4a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001505408d585f287714d93f7b3106ec74fdeaca1748aa28ba0db788e377489b859068fe858d02a13cf1a97c902b6551100000000000000000000000000000000151fd7b1e8320fcaa9aeb963765121173179b67b711da8f26d76e5f663eb9a997cc3c5bbd6a73fc9ac6c02179061f6421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fcf8f4828c2a94f384d277e60ef8f678b4fa37a5617d9ba94962851a0701f22c887560a2ef53c362f48a8483c4c7e40000000000000000000000000000000019613f6a81ca13b1caef16050f368aabeecfe837a8991855f9f0f1a1e280ceccfc0c9106a225a4a2a30f0445ca1556531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8c566d1a302dfb6e2be730c2b4bb665a7f6c9f034c62b7fbe0a5b01caaa8c14eedb6aa0695ca3ee2e4407ff648e3f00000000000000000000000000000000003bf037b5322dd80e1d0776aa371f006adf30cc84d04bedac51a6b6519a104605d97a0e0c2eb0d2115a6b352466ee2881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f0bc4548a92e7cacde86faed9d6b217e33c116d9c051ae67a65343573fa3b87a0b27fe31d0c98eab7eb68abdd9393d00000000000000000000000000000000004b2749df919104ac6c553641ee1f86092bdcd3f7c07df6c13655b78d1dbec685b3fb62014b7c12a8b8b05b5143c7491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d709a7ab1a9e35c381cafaa2f1452bc6896a26d2e9969b39ffbf81024c42eaba769a028ff2ad2de0aab544e61eedb100000000000000000000000000000000007c703ae78bf8fc80e860ea804e58e7b828d8cdc3eea2a2eef85b0708bd5ffb6b6026d1806227f58e7badad2969c76501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134667d45b0ee37cb354ef27c73ffa5b66b1113db69590f24ee1c1533e79be9b33aaa7f4179cc21ec8e2e2800bd78e45000000000000000000000000000000000986f4ca56b08606dd7118600a618904a6b89041404eac0a198adf9d31c4aa5591b9f9c5ec8f0569523b64787440a8ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019155b09b3e8169272b5291062d13f353dced086e78b524e8068dd048b36d05e408a90016ec0ed803288152920aa050000000000000000000000000000000000103765755b359fefbf130b61c8a129dbc39082627a6db013f4b6e7b4ae6a3ae8af6059b45dbd5d6e6a4d8bd1f8aa32981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011dff77e842c8700d082f7df69e3257315c13260be1d42e3d81741a3b3e5595e73cb4c66a52362e69f70b91b475b27680000000000000000000000000000000003c936edee5bfca30a0738e344993be1072ed30135b18de6f7b622a8ca5cb05635c54ef16a05ebf3ce3cd1d4c40258641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019aa88e710f0365a87180019f3fb321fee4de04f33a902cf05db964ed398d2f89e7b0aeea3284bbacfb6f9e7ce3f33cd000000000000000000000000000000001490f3605639a747d9a6969e325e96ae19fb7f4f15279e9a6df0d13fcd548b7b283611e915cd1627e4006c02f4bb1f551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2257e517b472d41c89b334319428bd68cbab0118ee1bb263324b8c3ad29bce2385565aeccca87ac97378ef6fb9c59c0000000000000000000000000000000006aec4d628bd073304cf87a7f1e6d26b02ea28caa8020af95bc67706eb0e541c05e02416f285061aee86f59c1f96f05f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eca502344dfbe58cbae2f146dd5840d934549f3ddbb9df5907a06a0bf590958bcf9dc28c1cb77cd6c8f9de9bb0007e100000000000000000000000000000000197e889f4705b35f527a9b89cab29cfeb99ccf960aa33e97b3f0a4f9107ff52500cec10cb13dae7f2b37bba2106594ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e9fd37414c0d9e7dc654d8138bd3fef399eb51a5fdec7ee5803faf8187fa23d65d3500bf988dad4e1676a06053a4630000000000000000000000000000000004a8a2e8a6b07bacb46b7d9204a3f9ce10f252bf70ac1721f2a839ec32b1432788e11882215875b36831bb64a067b8f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056468eeda5c3cdb901732ee682ddc325c986dfcd8ca86b1ed949d6eb6cbd40bf6c9958ff9ea0058e9a247e6b3ea8918000000000000000000000000000000000b51b37005bd0f0776aab2151f09de1a27e50d0c4419fc78f0ccc14990abb6438ce274cd7528bc7ec6c2c7619cf5ec4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b6e9c6db3aa48554210bc926b0c8c69b184caeefd1a802e50e0b1d0233876dfbf3ded220c0e80a5b43e9278d50487e00000000000000000000000000000000055f1099c5e825f9300c94a4f23a9532f8b18f138cf1cf7568dd7190bf271b9e195b1643ba9895a0c6215ab5f55df2891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011866e5371449139ec5ce6136d5611a9dbb975a8906d6d98b9893794af41f2edf6a2a24e2da7b67fa708f99689201c68000000000000000000000000000000001179c17f2d8a1c9b943e924f6f82b5028eb20bc02ca43e0760405211464ef5bab3ca183adea1fb391f896b91bd61b9c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ec2d9d849ecb33e6b84f03d9b7b00c4b17175d84506439ea1c03de626a8c41f83ae8b35a05f278f80c4416cfc2036b000000000000000000000000000000000ccd841790bb65d9b0277e935a38340317786d18511bea4997eb0c11de2f75d31240fa429f4ed73a20ead3986c04ed941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013675a7eed551d195c07af4301d5a41782d844acb1cd4596a1303af719cee79d0d6a7fbc5f93846b3c7a68a604101f600000000000000000000000000000000017743c4f79cf7836ee42808b978d97b0a88b758e9b32a7b0bc5a1e575a25cad6dcba2acf2b5927f11bc303a471084ba01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa73bc4535bab1a05d478b6a65d9d90fbf446beb4d1401d10cfd8e468f737a18222e0a0e524537fccbf73536f938732000000000000000000000000000000000852e15ebddd659575ef192a8b3a6c80b6afe627b47cd8494c66a6fc8b79c4258e332f6c514c421810ddf628f67be5121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000304298e645f19640ad6b07b863b0278802b190fd2120935bb4edc9198405a235f9cf42287975142cd89dbb56eb8d6450000000000000000000000000000000006d3ff4ff8f9dbe1e2bcf42ca445992b229097859496feebceb7520b6d8c6e6478c99f0ead2e40c55b1c59ac38f813151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f90cc9b70538dc1e1ac84e8a575414b8f307f3a006f9d6891b54147fdaf7036c0764d5c55ffc2263e8afa791d14efc000000000000000000000000000000000cf3d03dd6ab07ede83e2362db3f4662d7fc51ca515b9e22d38d7d53f6fb76e207f18fd4e97387ef55213b2763ab31141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b01c7b82d487ad4413dfee72822f1033e222ad8af3bea969dca56be7c2d83a0956f76a633cfbb9e8acea00bd3674d00000000000000000000000000000000013b14899f5a86cef5f34931b710350bc3488aacfcc53b874fe5090246a2eeac9d1a4b3a24df26232ed6f4dddb037848e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f0ac2cc0855d7e71583ffda042bb5913394f48a0c12d98f475d22e94882ad7ca6c699b212091733ec6ed9edc22331c0000000000000000000000000000000019dd3c8096e6b7e7956f877f7a173567dfec34cd1372d62d73ef50f47dcff0453beea54d0d408289f4c63e109d95ba141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153c613da8ab42bc18f58b95c2872e38a83f612d86c2f34c4212f68628d57bcc44e65431a754179dcdd2577751974f980000000000000000000000000000000003e3d7b8a78f2959ff0a95ab333c0606366fdc15b76a0f9a558850ba170ded891873802445c4519388b9961382d356cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ab1c6c8e5ee87364d8f88ccc2dd8ed3e5b367d81b4a86f10d7c7204fbf675cb6bc8d1ac50c336e09f9ce00305a1653000000000000000000000000000000000e4ed2c26ff4bfce1995eff736c2d0372995135e01d11fe0ab16b8983bb3929ba9cd31d161da4093536be757deb080381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043c2964ab368bccf3125586702619c2980579bb4e645aeb91bc438736b9e1863a67b43557daef3a1e28f391b76ddc370000000000000000000000000000000003f1a1892aa164a1d35be30baa7308672ae8d7591f00245991926e2b9fa108b2a35b1290a3bc815990c9ba8d7f2d6f461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018201db5729d940f1001f65e509ff84218a8f18c23c1e956a18b5d94198e7f91d15a03de584a7be5355943b5366d558d00000000000000000000000000000000118aed76f6871c38f3ce7784d7c0c0d5bcfe9cb56ebf49b7f3250c173b3cefd354d8c8c3b7f587cd37f0dbfbc6db384f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017749c5a65ebf7d6f2ffe5922dd3d65d8ccdd01fc0fd0982ad82f1539c95d2a43c308d748277a84febb89dd6168de240000000000000000000000000000000000ac76fec61e2b5cf1b8686c89962f46338b343b86a4e8c73ddae425990f3f6d1f461ed220b4b62a8528311b50b4f3c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f62331d2267b2212462c11bf2c7185b46eaebfbf159d799097bd545215592d3e20b1d99ace56f9239c37cf60887da00000000000000000000000000000000011786f28d2ddf291490ee11432aa33daea7fe558e33b0ae7783c9ac606e0e79fcc9b147bda9468800b78d6a775c2f4d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a481a2a3a5a0ce05a1fd64576d844d05f7d621a43ba9da46e4516ec63f95de4876beeeeeb3cbfdfda57a3b7eb9d713d00000000000000000000000000000000085cf5f5c59f675deede80f60f2dcfd1390996481f0a9321fb02f1732bcb60d72a821969ef53fe0b60d43cdf3eae41121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040e4fe640c8fc4db159272baec4f2815630fa77c8123e6dac95bffc6187c7106c25c3d36cc97d0ce3234c548ea0eb0d0000000000000000000000000000000018cf0d4086ed624618ae2abcd2dd66e5b664097d0eff57251dd3e1277bb4359679784f8c4c6b25d6e01cc2a330df4d7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d43f713a9f67dc170c504bb13f2c5967fe12482ed296ef09ceed819d5a652429e096905a29d73ca9fe9bbc8d9ecbabd0000000000000000000000000000000011e63fcb13e7a18a941465b1a0e4ce7e3f92a41fa83a4334a729c1cc2ab8b04c1d8e3186f6bcac8ebdab9fc54a8a63ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e518f402026bd1923f210e14bfacc55f8af8ff6360f174c12ab18af7bbd343e6ed2f59849c371ec1a3df3efb80ee1900000000000000000000000000000000168a0ba2fdbdb6309d7300c43be81f6924cba902635532ff0709d4c103ae04566d45945c0c775d93e178cf2cbbc2e0c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000491e9d9ebc43b16b0f3624c2023ed584ac67b1135704b77de4b337f3fbb53f5ff83c16d664b8e28f2a5952ea375765200000000000000000000000000000000121d9f926504a8d806eaa9ac921acb53bff7830c56c882a9efd94d5324d2f372be98b9ce61e4ba3674da09bcc2e7aa411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000120a3d1e261e9dfb91c54b1d1d342b190b1501b914e089c770377564f520cca50ed34958993947c1b3f1daeb6435d8d0000000000000000000000000000000004f05424238adde2374a73ae618ea738ffffe36acc9ebe17821fbec914ec5f129d2a6aa1a0e4a643fd6ab67883638ee41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000608182e6d48b7f8ff5221cdf5df561703c2fad686da44efbd9d4489399c10d32d8678b879737500ca3c2a6962313d800000000000000000000000000000000099ab9ce92786af80132465fd1b09c5f9aa00e5137c5182dfedb7c284f08d9d755c833b377a4e353f4665df21a02fad21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117e6f9c26779f4b789dddcc5710640f269302baa0530a90a0226ab647961d4cc201188a9b1fa0c0f1f13081ba7f4ce90000000000000000000000000000000008e0715ff3c9cb350c1c8bf7846ac495f5f65194f2299ee2791b28e1783fb14e499a43c5a84176549307b221d628f8301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001795d91318d488f7f0b5f17070485e7001197f95a1685920cd5dc2c12fb6c8faba48aca95bc4cfebd59640232dd75d580000000000000000000000000000000016d9d911535082a282d41a087984c034ed2d061b8ed33dae3d379ecb4316e04be57273dacf5937e988cad84827bf22cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e85b0197dd3b33e247ce9f3381fda91b035f2fb73249de8fd1a15b316d1eb92d12a1fdb0dca9854b077c2f63fa5f9200000000000000000000000000000000041b687fd04bce8225dad41c9f5e431afa562c07730939d4a05ad02464fff26d538c702dda6ce235ef0cdda303d044c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f67f536339f48878ff73c0d74fbe020815312a88fba65e98409edb0fcf87c6c49df95c01aab4f64f451f2e7f73259f0000000000000000000000000000000009e3a7aaeb55572d0592dd86d52b71d60d1caf98207511f2c8d7ef70032976a9998e220daebebb59fbc58b5bbb9e48bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136d49b5c53ba13ba8d4979a548f0e3ad72d2401b8a287c8ef40f5a6c80842e2b1c5e11379efbecfabd6e76c552aa97d00000000000000000000000000000000039ccb40325c08ac5a56677b497e9e5a289971fd15a76da80bccaa8d10a8b39d8432437788b009119b6a0ed3081d6cee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b1577a85cb87cfa9b3fd757a728a151005527c227adedfa792fece5df93b7f0f26ab8317cbaf8710626e0e7835518c0000000000000000000000000000000016aaf8d979bd0d1d8239cda831aa9eba553f22490d3f167fe8d61ea24fe58e6a451fb4a0762747803f55f5a77aa66f3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b52e671feba534926fb9d9daa7d72d4c8fb9ec5f9f0a4cabd7dce41b11a23459a65feac65825be57049b026f0be8290000000000000000000000000000000000885c5dd6ba7b328fe13c17384b54e41aa8af832d380fd5b5c1aa3dd8dfb354eb9c53b4c3d46969bbfb1a1f7bb78fa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ccb0ad92eee61bb59a9fb0bd6068bea9a3255eeb18f3ddf93b597a655e189b59b8d8ef6d21e42b7756dd96fc2e2a6d000000000000000000000000000000000a72c6cb9cd6d549224440b0479ee49a391a2e31a55f567e5a739d814b0dfeec5a79db6068695455a942bbb8c84331b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018684860dd8a83c505e69adc5724c25397aec2dd73714d211df1c891a2af074cea229fac76e91baf3fe7fac6d4ff55770000000000000000000000000000000015e7c017af76c941684411091908c63b566aee9dd47c71da1170ef2826c9441d24b675fefcb529abd712e717e1684a5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037d4341041bd91c93180523d83f8b785c9e2616faf41e97fdf48b22524b4525eeb6e1def30343d5fbca577bbcbaa13c0000000000000000000000000000000007111b3bb6c5dbb99d93a1df9789bf2b8122598aca78b9f7b010f94f5676780299280b9eb59e7145b7af85c19ee2331c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168cfbb62e1f747d67b45e6671f5a2dd60ce1c12a1f5e17f9eddb16105ed3196faa252a36ce5452fea3afe9a5a524f9a000000000000000000000000000000001094cc1cbd3381a6828b4ae641c1d8922fc96ace1ed08f3d9b5f777ae2df106089d5d211aa61afe2792fccd8d2fec55c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000011b59b33b90ebb180d1c9a4a1f575751c93b3a34497c0b4db65cccbdaa39cd0f49839779e837d65030de0e37351f6400000000000000000000000000000000013d14ced4cf59ff65f38a2d7d4b055b5329e1b8f79eb0b8795ec14cc65c351c930f85ff0b247496dca500cca147d78f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e4bdca95a46518fcd3a631951abb6dfd937e41718f93ccec35f8aabb765dea23ee082633a7fbf5690d954160b37db70000000000000000000000000000000000ec48cb7ff0ac797bbedde6635adeeefe0be0ec3067472c4d78f9482bd60055328b3214924052b924afe48b305221901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f8b7b922d0085ae8ee2ec577fd9e45c02f6208a6fd3bc4b4a3aac1ae3aea0012044f02dc7e592bf5eed9fcc7882c88000000000000000000000000000000001139eec2d41f669beac5bc249f5daf07a8e9543d5c663079d68a9efaa6707076d6a1661852dd0f55bd289bf642573ac81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126355ab6d40f2c192ead1cda9d5758089bf3697e1b167c344f5f3b18afe4c97bb87fbc15eac768eaab38bae53453cc7000000000000000000000000000000000d723b8a9703902d6762e538406be1e238e86602661b2a9e20d9105944a5e3253c720ace41dc150e36f6ba02aaf9751f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba5a37d98f9ae0e4fa81d4c1c3da1e9df589358d8330799d6a33f1f896823dbe9e34174726d74cda8d0bbfb57476baf00000000000000000000000000000000115cca57c86d8bffb547179536ed9e4e0b3df08e4efd0c3b80375088f7fc27b68b4a1eae1a2d28f71c3ff94b6e5e9f7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e8c942e597c9d9510259e8118ab35623dd994dde4a778f32714cbabfed9479fad9ea9881b9925e3330627ce61781e20000000000000000000000000000000000e2772a4176772898be703111ea7be07cf035c852299cdbad8f088123e1cabb58627e56915495c8a2966de239837f7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010de9e937b7aab8cff6bbdf969a4585304422d62c482487005af771b066da1d66564b9302a0f34224d51f9808a29ee92000000000000000000000000000000000da02a576f6896b6f244d8123a80e025a0705b8b837ee60177a60dacdc8108973e7885ea953a63cd426a1e20b1a27b4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001384031b0c47367e6ce851b2105a68d242b9f709b0a1b5f62df8e33619aa811a574f4f63f5bfb8ec98befcafd22ebd33000000000000000000000000000000000dd894072a2d3fe7e1d01f7048f394b2b8cd102b32108f5918fce9c36de3779cabb18da48c2284ce1f121c38aa3c3c8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fdc376148574e2afb2c77db4ad630c7b01266767852a6f6b6c2a7871e43678d7dd4a1fbaf7aead7aed7941d1241f36a0000000000000000000000000000000002fc06e129b3ef2a823bf042e5a73a5c0c886839f0eeca5583b867de96926fc2defbf2d8b344ed8273269047050685091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d4798604fb9b9f971c5d520ae4e5836b7789becc9e00e3094c4cda0598e9d2c6d64a78894cde5992c6775b1069f7c800000000000000000000000000000000038dda1cb2c6d566999a490ca855bd8e4e800149195bd8290aa947f7adb9c7642b8c2a1107e66176e393f62c5ef519951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002eafde67e5067a9fa0ff24e7d0427aff98f45ae3fbf9ac0e66cd7a29fef14fc787d4c7e54cdf290fde7c82edfdd06260000000000000000000000000000000008b795b1feb5b4a268cd28682dac5582639e037e6239cd17665aa559583aa14a1ce5a2801f0b86dd5b1965234f5095be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa9c5c827256e12840e06fa284b8385ab470a93d4bf74219cc1ad396411f4215135342aba52e590f1c6b52d347589f00000000000000000000000000000000010152439125202e0f7711400a55d947ae636245d3b8afb60876a1e0a72c69c39f06747ebd8e27604b621b5f8bc81f66e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f469cfd73a1d93a431a83181876d67074d1af0b0456d63a31ce70895c478a7f44426237ff1250f652565fd7d32b0db000000000000000000000000000000000ae7a7e99f2d3b48b51b5249e46c2ccf4e01a77516488f55cc4d7856772c1214aa7673d3d850505089d4248af3b518f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9c04b77c46891098535bef14dc0d3034912e19cf77c0f6c28165c529a0a594232fe4c0e21a36b0bbe7fd17fc298c990000000000000000000000000000000003f4ae3f9f7556f5f5f56ed4e3e78f3775f3a5e36c1f4db47704550d40b3b84299584cdfdcbb56fc8b3eaa9ff5097b601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c2a7289432ec5e79a4558645bc213072ef4949a17811a2eb1e90dce1dea8079ce389d0b50cef59be2dd5318b1858e60000000000000000000000000000000000701f6cfddfd1d68496c8063bb73e16266a250f1e2722faf95c261ecdfff33438646738e8c28bc136996489e22013801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020652f68c6494558533c1abed1087a5bc70120f2a57f4f8d0c7a2dfe4da4852b9d4b5d65cc49f520da2efdb0334a8740000000000000000000000000000000010fc81e44985a22084881d4f4e3547c2e261616331a7e0165c3e3d11b879ff2ce2fbdaa44268020e0ee0cb2fbcc272f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001333f633a5f60f4407f24d3bc351f5292f5d33fea7ecf01ff82872980fbc7650d2851cff83cf1af31b221d1888b43943000000000000000000000000000000001626408d253bc06e447fb4fd2a133c28a2618077c2c165de45d7b6b6d03c81e430d490ef1724e3a0492a7a00fc2cbcc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5b77c19ab18df72424fbbd4d2fbcee43424c27a2d927cb282e9d1a5b2ed7b69c0cf60c1abb1819e40a387d1206aad900000000000000000000000000000000067471803a7e73009ffd885515c8ef3db2e8d23280eeec84d5520b443acf9b44a31e92032c96cf5aa0c2e369c4fbcc391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004049f4b969ea678351b05f0aa4dfc20e20a215232b69fe6a05f733b08fa0431aa6f3d5ece61d07047582e89caee19810000000000000000000000000000000011a3e97f01244fb2a54c07389c3f8ddd5024d42a519b671f2d0fdb95ad003313edcc12982fcb08715a886a6845c86f1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e5b45f4770fcf4a4d5dc04fc00f587e720c0f0184c49c7cd0236009b4446f8378b83e6fdfdd571009751fe123d918b0000000000000000000000000000000004a6f103d678af9379e6b03d47b88f4d58e1bce0bdbdca67ac539b4acebce5a1d56cdef2ab6e74c2ddf652244f86077c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001688d72c07f3f67c64bc0f28e593bca09e792bbc453a34acb1bfe66d9cfe924176c6418b86684fefbf55af1a6801be3f0000000000000000000000000000000007d5ad12c260d7830c0652427f72b2a3756513fff4cdf491b1bf396045fbae36e2e3a9dc089757354880c67eba8db2cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1ea6565ac96c5dc137d3e9dea66b73b6b0962026900dc75312fc42121f0dd0b3ed8105a31daaaac2a099d02901a8750000000000000000000000000000000005ace1992ddda822827d29d99d8600ef0aad6e306eff2b52d8b8b66df3b6299e19b43abf331a81f55822b4e5c4621c5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce9cac0e5988a04d1d1b2ce2ce06136e86e46d6136180cfa8a44e7009453ebd6610e03a4ab28189bfc708e24ac9815700000000000000000000000000000000111a5c1cca8378fd16aa75fe6a117b335299cca6b79b47cdc19d91dc00b7dcf62b40eb609ccde47833113aaf651e4aba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000155557470538b31f51b293a5552d635d26ed02e80c4f06113b2f46d20d91843c50e445315a657048e32a9f1f0b07938d0000000000000000000000000000000016f91d844ee427003f5d3ee766c8d23b91865cf0f67a541933ced2ef88e1250638a2c18d125912d9fda4060c481b35711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2c41f15333f54864792b5344caaf727c4183c3fcce547c322c9e5afccc19b8b4d1a3f55023066483769611f9a980d70000000000000000000000000000000000ee18470bf2676827e9fd037e4d76f5e51182f29bf74dbc3ccf05840db9ad8bd4a0679e8988dafc8a25e8ec0f366f961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081ba236786a55802562d5eb7e034988253a8a3e5dc8f2dda76e65172190189903387309dee12fa0ecb460eee5d7b879000000000000000000000000000000000ef242785e006a1f3361766b60d82ece2cb5fdce40ce0cb61e4fb4a3d74fdf12d5707292b2c9fd43eda88854f0b2c0861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003384ec8132ee04de514f6999b2385cbf93cafde4c2b39a56748ce67ca205641ff88974bdfc897e5179b9daab902653600000000000000000000000000000000022ea2e8d99d19273d0496fd46942d49bf4b2964c2aa0cb20d61ab78d9a6ef2fe4cbb31ac95c0d40e22f42305b8ea45d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd9c35a3209ae2240c85aa71b09e5c706bbe0b2fabd829abcffbec6bd49bf1f9228b7893e7c577d62f060627d470c2a000000000000000000000000000000000aed38d577b00bfdbc8f4c78b76fe76f161d3e56baa3cec08c9e19592b208ac93c113a08710d1df01095272b1c7874a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca8d3f0f4ee6e6d5c7089eeed0387b51239ad74b3cdcbd2e18ad02434286647061f50ec168c063fa055edeeb8eb3f630000000000000000000000000000000005e204d847309137e256faf23388d2f225108fe9fc2741bd4ddbf452fa6b8fc61e0c1f8810fafdeb150b1e691e42d40b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b99158821f422add2795359efb2824a6d3fe459bb456857810210d9059bff4de6a1f1baab8598e1c05c2d50dee217600000000000000000000000000000000104ecb3e7b729e2dda53bc8de3b2cf33e5a7230da2e19fab4e3a4b8c442283c52038fc563e7f66bb9a3a231e3b2a062b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f40d22e3cee29341e91c936af304d08c5c16ad44d51d03cbc4e96492bf9567528ceb942a382600fcde3a950be68d790000000000000000000000000000000007ed795c876b31646eb45dc8c63ad974783fe0dcf4e0e8e9ee3cbf5a0287cac3787f0f1ecd94e8b4bb5e27361b3db4e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001156c741f39488e43e0d79d8284f72934995ee03fdbcbd033748235ca83b036599f0fea86548bf3343acdd07f360fdc2000000000000000000000000000000001720e2e70e708ce3e296684d584f277024edaddc1a8edbfdc6fb569d18c2648040798ebbf759c810c84a0eee8edf97061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4ab3ebf2811590a2caead3967b5d9970cb3459a4e8cc9b34db0c6654e7986d05176f97a34fe60b5096bed53c2a09a500000000000000000000000000000000171e05f29c47c3a95acc27422f1c997dd1570a3a3dd6b742d1de21ec33aebc718543db98ef46624d4231496bf67926001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000818b4603fe095ffbf063b214e19d065bc1441b535342714167de6f5a772ed98832e1f6e74e7ead657fd453aea96e893000000000000000000000000000000000b6fd6af91dec023287b8e3c15405ef54996c7d8f234770ccbb1ecee27c62bce3eeb72aa718ecaaad3f306aa3d2962f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001658d558e2b947cc6ca28cfa4acc21495f55108ef04cdc9ceafa7e82514332620d41bd6500ae8d284ef59f2e1792e22d0000000000000000000000000000000008b5949db1097a1f9676a151a08f902b3e27024b3d52ec8b0f7d25f75ba7036f56c11173149281ac775af7dc4a2916e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cb91664d01c41f36316814fcb35c8e50ade0160520a281eaa1c6853c7d5ca8cd0f525b350a91beff2470a0e5355e96000000000000000000000000000000000e1091bdd43ed58a2555ef53f8404792a6936d28c679ea9a3f2e30a6d5bf539551cab3a01f0982c33e8dab23703ed7a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000618ae8a3e503231c27a7dce860dfd06daa17f956bce449b8fb0b4cadeea37a64f8c145ae1c6058713dec0bf08b75b110000000000000000000000000000000013412c6e6e4362a1f6d5b154c4317d6b736d4599383f3c24bbc0df3a0048625f6c2aa3e009ca2ef3686b966fdd3921c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000265b744f5d43d68d863385ef43a875cb0f911959b47248f951d8bc22462a02528f586d81bebf84488dbff262ceb7b0b000000000000000000000000000000000bd0dadce86079bd92cf5afbac30b1b95456c906cb0852aa487a47a2fb67770755045da6fb7e2332b5c7d979e1b5a3af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e518a0114af9f6d2e82035af499dd6fe41a3d738cf6ff17d5b04cb585df5cda65aafe501218d362cdfc3043f871ad900000000000000000000000000000000120919f609d37d02f00eebb0afb3ce620dede7940358fc2fefb935c8fb4ee8c71b011b2c9ec582243830d508ac7406ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001673b02fb6dd24f44ef89ccf533c778a38d8cecacb885750af6956b801aeb67cb55706b122e71483466a0607149dc92f000000000000000000000000000000000550f5b02c4efb8864eafe94b8790d83d85bbc6e4d22053c724e6ddafa3ad6da184c908fac5406570e88f8d67e9d4ed31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016abeef972685c1ecae4db5f0056771f2a66f8c14ee4a39cdbaed703d2d66c53589494b48fd858801de153777368cacd000000000000000000000000000000001535493b8edae5d2804ce0855d79c223b6499b831ee14b541a4099a387cf67ad21a26b5b004a2399836836e3d45843941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153ef01bacab389b8aca28bf5e46a8d4f33071feaaf397678c16cb09c1a1d97bebf7b384acd0360a5a570c3c378e5fa1000000000000000000000000000000001999106bb1a51013b256c0d27b5792c44c3d71e95c3ec5ee13f9630e6741ed502f3ba51879fc1a387a196de038d6eb821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a0f193a09019d4e127d2d41d7202616ccc164cc831845c471e8b2becd9ddbd8193bbaa38845e276346988bf6c3238b9000000000000000000000000000000000b67a89aae818b1281b1586a57f02942dcbaa0c063e266def098bede46115cd513da7c65046155e32fa83d4ff8d2f4a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffd9488d7ec87c071c305091dd06da5166933535811d7e680fa1c1220c7e1acfc96c3a8887204ee69196e49fb65c5f2000000000000000000000000000000001771a88c07e0214f33986dfc627bacdd2b6c20cc9d54209a59fe98e568178b6e522990fa19c8cad30dc3960af40714831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c3941c3872ca141bc25fe8e414b6619dac5e5b1943deb8917cea3ba34e038fa05ac5e665f8f01dadf1f61c25baca1700000000000000000000000000000000156ce779a2c263ce7da9acf14632c21099571da31c77f9ecf62de839d17567f44d7be1a72e18ec8a9dd59b17390f6bb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca1b249e61571695c9c9f1de9fa513c99d094377a045045124ca58e4264a7bb087b6982cc610cad92ab66808eaa534c000000000000000000000000000000000bda0e5bafbcca8104eb7c9812b66a4a79ca0d58b2a5f54362a3e9ef76bddc79d0517292ea2dabf460782254cd920d1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005fc737ebee4afe1373345a8d6952bad18d9da7b56c2f869e2d76b3008e411d3abbb1b7cbe0bc6bf7e140c0e63f686b9000000000000000000000000000000001016fc1189c7479e3fb028a71403722c179729b4a688f35d7c8f1f1496b334b244563e8c11725c6e4b670a4044ece2d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009786d244d5c8a447a82818e2b12d4d7f57891929fffca7aa1bc626685b196f2e37d4a86680e79d7ba76830ce22dc21f000000000000000000000000000000000b1334e1bd8eae00becb0a06e6a663be43863eea698e639753b67bebf9e5f8d8e3454c7eaede4e0e5051f8a90632537c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a4a0a370f5ca3dd0d2819bb73c64cda995c890cf09453b237cc7d6a55b9c67f71c7c196cf5b799c3979b4a0eb3b2aa000000000000000000000000000000000f522244a641c16f3de32fb56154bd335e6f2299cbeaf14b8cd15a89478e0f64e264a54a6fc6006003dc118edd1919ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd8b7469d3d36cc7ce0a8843d66de8e4c8f848b2e6c871231b8250870c3db66dcdc893ffbff709e2e9cca43bf893d9000000000000000000000000000000000063352165e6deb56acf2aebe8025e7c42d3eb47c53bfc6f38d89cea3d18cb84539ccb59799fa8cb3ea6189d8d085559f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5b6837b4047c3c3b9ad743c1f71f3787cbbd8cc274ea8dac3b1dda5abfeaf529eca830dc533a1db81e88621a2345eb000000000000000000000000000000000d0e03ca3767f3b54b7701163916f4f564d4eff4534f4722015f90fa2ef2c541863800446390154ddc83e64d8de0e9cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb2b9efca7044b1c2ed99393c5718ff1f9a7d4bd07d7d5e4694565359dd6db5fd6c8e5648f1cfec60587a20ea7012d4000000000000000000000000000000000456941d3a1b366e2d4e37a6bda52435eef8c165031d2152de2a0a7998218339b296da84717b0c6b83e8c8156d32a49a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012491b7bf68adfb7523bdf15e72d3b3a21f3638614d391e4d71a5478243312dbaf4d7975657426a1ad2534fe27b6eade00000000000000000000000000000000192f08f3cc9500e1c056bebd18909e76934aa9ea5ed8927f5725f5168c0ca3d11e46b33300e03c647f46ac59d5904fa61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003deeb83083c9e24e4e455f14ed2378f67a9752f5140d4b374fbd56bccbc2e0a48a2d4a0c38c900756380ab958bb8532000000000000000000000000000000000d6e027d5b6445f1eb1cf658985191eb61828d05ca40cf939719f5f40076eb76a1ebf0b332f549d37c7abca6b5e12d441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f337852713fd09ec735da927a3fa478a32d5d8cca76b7ef363c2c708f217e536f74d51b0f0adac511d1cad84329194800000000000000000000000000000000011b6202c3bf97e4650e15771632a465d86f35780b255490be87300eef6eecc8c2937418eab1fc668d22fca8300f7dce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009d56932c3e4168c9e9d2b3af80f8e1b7b2463be720418d5f80a2702d1c65e409fe8d93fa0a10a0eb4ee7a707c5fd6100000000000000000000000000000000073581208ed579ce4d58ce90fd03e84228395e8dfaa8083fc83704d1e8da907d77582910aa9312517397e893b27b77321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124ecc7c91b111a7bb7fd42a9988da68448ded20837b6ee7813d220c8951752bb16b239cf9d13e580849bc949293bd530000000000000000000000000000000015c98b0504d6d8a88a953954bf4f4ee10d4e497ae07054f19af67defc06c0966bbc7b8f535407145533acd0a4a22ac7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014af136bc4e066ffd839853276adba657c9b67519ced82bf51695ecde8fcbb56610632edea3d0f3ecad30ba3ffa9ff2a0000000000000000000000000000000001ac938136f98de79d19587cc5f728fef35089cce55ba919ceda08166fcc6619d0d50c1440035ce608516601f893f9d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126bb9671e517267792dd4ed2243cd357703cc1629cb7bf08ef0d9ef8cd0175fe1495ad9cb8a090f89e0f98f95eb7b8b00000000000000000000000000000000089ff09b2748aa3c722fa744397ec470f5eac218e1e8b20538641c27924921a8de8b29ee560ad88f854e03595c99102e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000764a2a77904401f737762c762b06d26b08a235fb3796680a17ac003b2930d698bd9174ab119970decb7952d5ff4acce0000000000000000000000000000000005912d311d38341dde42f7403e7f7a6e2d7dc6e773dcad32b27dcb2e1d74256f6972eedecde900846951e4f2c249c3561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100381469eabe1327bd3298fd73abe89f7a77c1844f1ec3fe36b8b71b6fd58ab4c3eaf4eb7bbe356ccb6299086d31bd20000000000000000000000000000000018a1377c49e0f05f1ca89f6d483b474b6b77ece9d714ef8934d19535092da0da9b885f89fd6dad8d7b4a1af8a814455f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168fd4c7928724a6807a2c53a155c77c6008b9cc3691ba67ab6ee3e7478ccb8e61df4fbadcc5ff0dd4de09d84f60dac400000000000000000000000000000000078f1a5aa1522956ec82ff461e2b1c286b1587217ced3c88a70f269a19165d664f937390bf7be25037debe10390716e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e6a67526b8b74a4bc5aea67e179f7d16ac42c4c693a7bdcb1109e71cd960d10f18e4513015ab1f9e9cd55fb32e24e8000000000000000000000000000000000d3b19f7129006481b26c5b7d161cf9369a2bb93fa017a93d394c300b3d8ec20c1e5e53364b65984a12616ab1fc4917a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001922a38508a578d012db1c6863b03739e13c1da571213d92148f7605579a9e150c30a83cc514c1445c887610bf5252e80000000000000000000000000000000002cf9a4bb6bf9852bd58175b391e4a1c9dd6da027f404f8878da6a83f5fa0d7cbdcda03aa5444329333a268730955d271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4bbd4d0ac43bf6ddce5569ef9335ee428f366a8483c6ab339ec6c269bdee7acf3eb186c720be346e8584e2632b83570000000000000000000000000000000015eb237acd09dce01d17ea0c21cc66994eb42be77d38a5c07b84187b53d63c76a8b7d6dd4b821e90d35ba89e3bf6bda11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da3710be16aca675c2bf2aacd9ca0470948a960e059d74ad8b84e280fdd95c228541551aaea76335bc19333b92a116400000000000000000000000000000000119671acbfc39b553cb821c881bdd7f72f501bc4fb45e6bdb8dfec9e7517f6d9b3ada8793c06bad0dc6961dcf35ac84d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065f74559e1e24fbaec2c2b9b0dd123183c2462a448265b2731e2e0928a80602cb828832a1ba0025261dd1e3beacd5de000000000000000000000000000000000746ec52a802fc70614fa33623a07750ac300ecdc8043251968c6e6b4f0b49915d2596befe84058fe1708a96c6ce76be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001091932c74bc39089576ffd44f2f6a1c8bab022629986f67b8c022ad93d2a05c08641560d105d725556da7ad8e58c76a000000000000000000000000000000000a2cad59e673f2abf1c0ed2536c9b787131379ca5d55aa6625c8f5c8e73508524e07b4c5ab09dd28145980417f2e99bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187efd24effdfe761cf8b97742bafd1f41bd9dad678d2c3117c54b46f48388f9256eea89319a7f632f586c6f4927b29c000000000000000000000000000000000bd476a7804b3e43b68ec928f0e1faab4c5ef81496fc1c97d7edc7844fc1bf350e9499e09bc700aff0864d95aed371571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c1b27da1af76ece7e7e3e4e741b04803a098c0af9ae3310039a9276d6b35cea1594aee3db23863d9152debed6e45a3000000000000000000000000000000000ab7d2019417c48ce97e56817336a0608c459cc55d807197cf6a1e99ad8c63bce753b76d33623abf3d5b40475ca70f1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d465cab0cff80f17030671b0f543000d607e361a7edd48d92e5668173b2de628f3d8269425cfc3042893ab4f521d010000000000000000000000000000000003b3d4dc2f2158c4cb7850c5fc1a08c257e8e4257bbb2e601a6efa476248758a6b5358199c0218b50cf6e30bdc10cf5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ccc8e8af726afaf2944470f04c62015c362cff9b041bec0b9050dc27c53708dc72cd34b0b7856afa0489d074d8061d000000000000000000000000000000000c2c84ff780d135662f32dac3f21d428279660e56c64e9fbaac7e06c951ecc892eb431c0fed0047a8cf3a964ddddb3581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fe644f472ddec2f8de2d1a42775c50ff6535f2075072c6ca058a3d4a29e8b59fc1a0d823a23edf90c2af0a854253320000000000000000000000000000000019a9bfd071c81ab09e22dedca90567999c4322d99968b4cda602e4b914b1d45397832f6ccacd48e16dea96fb4d3b6f391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191e4c6dac139289a62ac28d1d044e40af53efc4e657d1777a36ebde3261da250516eb7708f1f52236794ab8b03c9ed600000000000000000000000000000000018d22c0bef069edabee7dc518cf596c02ea3289a896ebc96233e539b05feb9ddb6023fcfcf5ac0f04d24b198fd9e9571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ea420a67fa3384c28e78455abc0ba28a1e2489ceef4ac82e68416411f55ddcc48c6fede3314d95f2e4fc73ff2a6b360000000000000000000000000000000001ac8de611fea805f10e544eb9eb6e63fa0d7e559d8a225ef1934114c5397b5e52e05defd4443f503ac2b804ce0b87c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161b3beb6f28b5b229927e0a37713dd499b7ca2851c9c0d95c7d3b4d83376fb0d747b80d8067c64f0c5b55f2452b84be0000000000000000000000000000000012af658c46a15139f36d4d5f25adc63dfaf5e77046ee868b4acb37da046c19a85497834d67c996c3cd427bb0b7fd3b5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001315b21c683bc730a0306ccab9310d8829737366db41011bac4d6bdff6228a5f61dff33f730348c2b9da6a16285e0a0d000000000000000000000000000000001170f50200394cbb53c8edbde2918555b6b5c8dfa8046e411b4b61cec988cc1f18ea9b8d9332cd5701ce42f631cf76b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014653176e3cce4dec0fad0c977757e070f013739a39a0bcb08823bfcdcfef05744585ea050107c5fac3c5e35005c09f0000000000000000000000000000000011457735dd2ddffac03f1e7f1a86067a7d979349fb67567d87c6f462b81c7593ca7d8c9c8d75a0e486777d7af05db3f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001da04b157962b502f738773bdc1f0390fffcb5cb05c2c18ad14e742954ce02500ff57877e25cfdec7f2f1b6844c42d000000000000000000000000000000000f7c97a711c5fb7670d61e2068b75753a5284b4e61770bea3a722bcc2e4f3393ae805517a7cbf8a60745b16a3cf50fc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ac7173e2271a6cc7dca6f1c80e77acf5953ed6ba59692ccc7766eda835e553df95ef71897b11cf29cfed191cd31b1b00000000000000000000000000000000158f732a9f2ba7fe3f054a0cf0bd50b06ac1115260cfdb1796a76fd630468fcb5acdd2cee4a064ebb672d9623bf517261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a75eba744d4b8b57c6effdd11cc722ad7a1a94f5aab609832390cefff2f6105e790837ac485ed339e2724a2ef8418b000000000000000000000000000000000fba023eb6ef6f757765dce72d18e204065ab137e48c9f2383088e626c9cd023a56dbd5afdc2ff492a1a9505f8c869e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007afce48c13014171e0dd9ce4fc6040cc420785a2e390fc58b79ada006c06421b1465e582a1d0f9029b441b1c10f2e7d000000000000000000000000000000000d4f3c17e6c6923624d887a5134495edd3f4d7e8bb6a82ff23dbf842f03d460fb4d71f584b8cf5be7fe06e8ea7b5851f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012235511341c1a6f326e85516f499f11dcb199efd33ba9af83b29858720f15e079ddaea88c2d0234a7a01b497ede511800000000000000000000000000000000199c7491ea10013f9277a840eaad1b00122740466db127715909c944ab70f364a6439f846458196c37d36a0478b3fe111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4e32e07b410c0d2d087363e55afe637734fc4ac624bc3531d56054d5161793e82bc7ed33c88327991e1a053f67b3ff00000000000000000000000000000000156c6c134393e1fbd9571fd2971bade2577fa2e9f38ba18f7706bf622d66f8e86cff0089ee49ed5c7fd9b01c22a5db591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cf179a94ca8f132fb7b103a3bb4caee3e29d608b16a303e32a9def5060fe030fa899220dc59e9316b8d099d2fe42bb000000000000000000000000000000000a5bee93c84159dc0ee62572e2a0868ad8a91e98e1992d1a393a4bf7c616683ae352c951a7c166633e1acea41b81d7171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006304a02c93f2419835cdb324b78719f3e62fca5cd0e366e5510d09ef1de1ed9ee9a0d4bee920671c4d1c91749b901910000000000000000000000000000000014f2ca64d0df7ee607bb8c39cabc811b84ba52afa8fde5070d78cd358784bd89ca307c2c1015fb57513f4918730c34b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ca8aad4f45fa6c6e4305b3008d966277117bb0b706154b640c5af1e5222b0391cdc8633b46731fe9b32ccae8088cef000000000000000000000000000000000e856f9efa65d3df3fa53365ec34d93046ab71e0f1246f8d7336d60ad6814cd7f5f3a8310cd5d1b894a4d81cdaf0bbfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b89b6e17b64f41f303055446d8e36cde67b33cfde98ab9ceb467366069423007ed17d6fe74f92d179bdf027c7c3039000000000000000000000000000000000c448267092f77dd005d1efb118e01dc4eb0aced975378f8b27add0914e3768092eeac8bcb13e667d977f190012edf7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f64a59f47f83e83408832d7cd277a78abfeda384c24f5b73604fd50a3ecbbc1b06c0217468d8d517171695dbc8537b000000000000000000000000000000000fc5ed81fc233f79c45da8f30af16faccb52ce2284d1a9e7de72d55663e147a0d0a7a641c7a6056a027150fed7b4e9791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e326a229b627999880ed1fa6dd20aad6d3652bf6ad9a0dac6a1c61b4b9b95092698bd491bd72a289bdff826499aa840000000000000000000000000000000011c9c349313ae92ef97167260e499c541176652bb5751e2a2e5a7739cd72507c09f94f02491d107ac781bee1169347531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013de445364ee9cb93adc419eef88c2b5dea831f655c0d3adc416925ad8f68f53a9d8877548b6807bdfd9a6388dcddcfa00000000000000000000000000000000096fd770f94c6475cdb51487da8e51c5023f040590bc6e9d19a54b747dbe8906a76e2b59b64fc2bfb2bd547356c464b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf1d4a18762878f1437c625785bd3342e9bd7bbc1f5eff961f13dfd0567dd29d3c43027c76d650cbd97ae2c11fa93ca0000000000000000000000000000000014f8be3c695584125937d54d58a67185d11a2d3092ed67f45167b09c4a2abd188b83ab0201971004aef4bcd1edaae48e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce05bfc73115713d5c33d9cfdaff819de53974305d860e79b7edb232a429621347e4bed057050c46978b80b3bbfc07e0000000000000000000000000000000002283c0a5e93e583a4d20fdb7d9820461eeb9804fd91f2107c78bf9af575125d930642fa76cab995b90670f524120f2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a0ccbf45e16175a552e74010a5ab54af6bcb52478c4a1d7aa65e8bf7e240df856e7bf7cb1b88795417075a1cbc9ca4e0000000000000000000000000000000002a9e3f553de57a3ec13defbc8be91c153b74d22491cf2dcd92698f19cf4e9442cad1ac8d8be2793bfa71adf04a9c7811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001252fbc302c483efd300cd0fc4cba889eca8fc8ae329cf65b5f23d3623ba98b35ef7e167b31e0cb66b6ffd95c61a5b0d00000000000000000000000000000000118137f13f381e930a54b7f986c8b809b4e2b3add44a9b38314d66debb9c73cf55dcfcb6476c7d51d0b09e2dc911c2ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ba31716b261bcebab58dab2abf16aa35b0661a33298843b81ff38f600a632c82866b157bdc05e787c0caa1063fe5bb000000000000000000000000000000000d664bff23d5539d1fc378021f3bab203407ad30094a961b9aa21b9605f94ca8de9320a27946fa7c24f8e42e61fcd6201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011155b2240cb3a982fddee6e049bce6dfa00233f130dc55a57c1845b1d631ed5c0d40b06471461cec7266ba4bb78c1980000000000000000000000000000000011f35714f49747b0d5a5027c2e9d1dc632e2731b34742f5f216a9c967c10217b5e343a1682daf1b1aff45e445c56722a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f89a986e548a35e0c014755ed0a38325f9bcfdf4a74739cef09883345438c1d7d5b2ab5f6f792827d2e13fd7a7b0ddb000000000000000000000000000000000c44541a5b6fadb90bf5cc88ff053c10119867f99b44a2672997a570cf2c818a2e9967538bb509042b33830c1b5a64f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000551cf72244897c911f6cb7c1ba15dda34b10c974b8dfbf843fdf2a07c14404bac58f7ea552b4e0699ffbbfebe32dbf8000000000000000000000000000000000bc4bb1038e2171266d0ce5def581bbdae500819102725021397f4c03df816fc9b2d38988448d030c519fa45b0cbe70b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001824c5ea12c4b75d413b609469776423b26a75f559e44463535cecfe6fec469fa75fe8e9a437377bf1413a8aff70055f0000000000000000000000000000000010a0dead767f3ee1c22f8da401c7120c51a4947bdc350af8380b6fd679537ebaf718966b18664094c06d93b0f812ec261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001072719fc8cea906a0c4a79c9800f1b56493d57bec18bd9b963e5abec8200a4a8e0c8c02a194749f2326a495f128a9b00000000000000000000000000000000013418b76ed9da79c42349fa533e4560c67ab80706d9c84bf2c604e3cfce15e823eb03756e6577080575b94dc06864fd41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c8bfa132fce79559be4132ebd735ab296c03702001ba85c234b4205e0c067da3ca3e7e20dfcdc3382ede048495d959000000000000000000000000000000000172f47d0f251daa4cf320b959b6276ca0add15ab1ce7fdb71b0d553eb167081cb5a00a64495e5c7579a1d764e56a47a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4732c1a10cc9f2d9911d029e4ef26db04c57c3d6151b73e633d2c95fdb3596fd665474128ef11b6237400816c2e12000000000000000000000000000000000055384e5e247ad359a7d46b2178460ab36edb9a959962927a3925ecb812cbf10e314f67464309a9dd361a99c46168c2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f796d028887fa5b3d4634d9e0bdb573b93ca936066e6f04b773bba53518ad30203eec1a6042936d071514e6bfa5f2920000000000000000000000000000000002fc62c26a7353b52db6b4b9a42d7c05d73b57ffaf3f30e3477f09570f53c493f547f5b6885e099259d1539792ce5d7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b8f2c5223f86c694ff7943775192b750a7649935f901c10fdb0dd5f7414bada981904d0c9bb4d46531e36d71bf753e000000000000000000000000000000000b536cff8477ccf93e45283cb63418d95312e2c0ec261c759a6b9f6c5d7d13fc398b432c859eccce89ac5b8c072f3b0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011da94a5be90d556e5162cb3a1137fee28e589ce8e5a63a9e4eb107a83dd2e491b6da3f28057dd405d3405299089eceb0000000000000000000000000000000017df38816141a18bfa41aa6aae3eeacd8ac6531bea08179220b0823867149193334bce6cdd2984eb08a41efceb51b6f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b09ae260c192350741a8f8e6049746338ab6a808d580ead6c5f1cb92457289ba35c32a330abf9038fe015ee42c6d8800000000000000000000000000000000081a581b92f7e0b3ca6ad1cfa8d0a7daf32fdf7574dc59b4bac0d14174982860c960395a2aa070d466e7e6c7d1833e061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058a98eaaf21b149184b499044daf38760234ca5aa8b20036e39ad2936a80e71c352b1fd0b64a090b0e0764cc7d67da00000000000000000000000000000000010db0406de126e8e05dc07fc896c4b1d12a8ab336158e3b0636ff00b981656b9a39f0fd9b629b8109eb6911012b89eac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010201bb8d227c6985435a7c205768170c42422ce90016bc4b77390a3088e7de30ec7873a5642eeb87f908d86129113ce000000000000000000000000000000000b16ba2f42208ec8aeb80a7967f667f002a55272fa83b9be910fbc4b4974a273b4edf45887f1935209c026e44b3470e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001811c178195bdc73e7c33cd10f4a0fe8e41dfe230e334153950028fccf9ec804ccbd726990e7d6c5639552684c18bf320000000000000000000000000000000004ef8e3c72d14c79a226a8336f808c2b72c48d927907b732fd99f15072e3c81dd39a1dad5b0da1b2fce3adbd74bbcc9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003149736b1352b7e23226af2aedd449881fa5403a13e7649385032b030f9f715619862a9c2dd2f1eca777898b339d4900000000000000000000000000000000013a55a271fe5c02939758bcc631cb03e8c98a3e47c4a05df3e2822536538391dac611b77d5aa82b098774fa38e1666991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001314ce1ad8e1a3a35e50544a7ff3b9ef1eb6ea0193eeaa1d2968046b4f09f8086f3ff63c048753d20e30e9dd4272e827000000000000000000000000000000000cece16e82979dca32bf380982025270caf9ba81bcbe2c0b978063e7d6bcd1cc2d1b87d10711c25cdfe3399bf847f11f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b063dfb76ed32b09e807f17e347807c5e9b1408bbfe82c865e4013cd93b980e2e5afad45973cd865722e98e2b7483b00000000000000000000000000000000080833813b73cdb0984d33bd1d51266965cb951a5b2981c8b17155f867edb896d57dce1619646896e301a5f4846825ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043ed3a325a82269a3bb5ef98cb94f08e0e9b490bb408ab21fe305ae32dd75ebded16a0a5efb0a89eca8c6a0568e32110000000000000000000000000000000009f0592ff5d0929e65a1341fb5525e078a5319dc1d0e4e8b8e11751ce484a8b19acc9090c42ec46e6761db637857f8771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea3a4b87cc251ad311af3dd8db1d238052ea94651352c0093492e4ef57aecf21de575a37626e762d17378a3ce27d7be000000000000000000000000000000000141d0d51a2d50231f762b78ebac3c59857576927aea9a4bd3a302e4328362cc4b8f829792c5a818ca7e33434aa0a0c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c521d9fc7ca94945c5d9d8756f7ddff08f9d1ea012bfb77c3fd9f78fc30746738c196fe6f793d10ee06c552fa9c3912000000000000000000000000000000000d2abe395135a540564abc2ea1151923e13ea05d87840ecc9aa0cafaeb1209d8498d6eb024fbeca3276b478d41e45b5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140e53c54c48b5e00134d8ae57af2cd5374a191df05f6248c2d51cb1a8630b86d070c2743a20cef26043ccba2943eb91000000000000000000000000000000000273be71d80d705c24217d2af91b69ced45a8abc17e67c76e2c370af5a05eaba9bd706421141bbfe7f44d47fd181ce591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111d6765dcaa2b9c539f5c9df1f727e41945f1a0c0394d2fd6daf799bc331a972e1a4d844b293da427adc1bb3fc9f36f000000000000000000000000000000000142b3d87e2b607919d6abdfa81efeeb3abd092eca502c18399a9b4205787c7003e9327f6fce1b85fe76fd5cab23cb7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000933c400fe9431ba93a3663e386b00dfd35a54b4faf339db14d4410fb0f3cd63aa9ac6580082e26a7f118512a8206f4800000000000000000000000000000000185cfedfbd48fdc163f854995737153eef4708601a1542773912680c9f1e264027c93cd137d0f767124e593acd4af2d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000762f284c082cea4262660a404614faf737d4d70dd7c270360888248c081a4090a4aad047143f84657ee321c65d065d60000000000000000000000000000000004be67e36ff93aedbc832f5d7809c7f6bb45293c5b953d25fa11ddf10f7bea99c1992c241c68a4dc51c3d4c0c1b7c9df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124611fbba211a186ecc58466173d5a219ce335cb4d239bb60873d10e982379b75cd9ed60b22dcb17e0aa4f2f0f53e2b000000000000000000000000000000000cd4951d1eff4ace94331303b93408e1689bd0c3c2a8439ffa8d1adbcead124b75576591cae7ea503d4b58f3a08bf8121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a506c0785857aa0acfc1c3b9a5cdf83a5d17e507f33b7a082adc5395baab436fe01a13f25e2f6c1be3553cfbc33031700000000000000000000000000000000150f07ea176aab73e149736edcc5d34d49400f6c57a37c599328ff822d74a9079b42ef33ae01219bf017f79c4308a1cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018aa7bdf0a75e10c7211c155727326ac964af2484642138fbbddcafc6dbb5e617f8c659a2dc400526cc2481608565cc10000000000000000000000000000000011f74e59202b79c3c231b29695a841c9120f4dd68ce5864c5f4789c404aab8bf2e0c6e18c4abe2dfde5cdea50acff99c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174fb722dad03efcad8a91f4ad4ec8a7d577daeffbf724c281514ad1a331d3d650335357274a029492ad11efa294ac4d0000000000000000000000000000000009b13b6ffb6063a678c49cd4e1bddda88cff5dea88df40758aa0eccf95e46da50a22087c36dcd4a04e6547d7144e8b911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001348461ecf787f12563efe0cf0c1f5988f56b55fd13ac520f4acca53a2f9e19af4548e535500ad381dae30be60614c4d0000000000000000000000000000000011ea3931a1dc682177fe902c7858fa62ee9df7251a5c1b99796f33602520222cc87217b0f727bfbd93b6a3cd19e0ac391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152f2807a0007b494f8d734d8b3eef29385f274d040f725352be537339441f3040c12116b7a84e49ebbfff5e778507020000000000000000000000000000000005fbcc42a8f28c11281d481e9f804a58abf1920e1a65f159dc8fcd4934a2e041d3032e3a95d0c84dc51e0e11aae3fad31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012be6c9ee0ca13b8a5447f45fbb006771862ec48f027dcc55fc15f62a7fcc240a303eea805aa52278fe4fd0e280f0a7f000000000000000000000000000000001644ef46d1e3eea8ea2bdd728ed91a0c660d0256d85859f32e6490c2f5449c03748905e1518b8384e3224f20d039bf7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a1b250d9c69ede6574fba8bf0472dde873048cf2bc38f695f29fd81dad746f095dd42e486037b8fa70d04b98e9488a00000000000000000000000000000000156a7087177469d649e33f8ae7541c27e90410b91f3680f858fa7c543e59c9e72c0d1146a1636ae839af1fe77b1cecb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000671f9c314b848b8469f4813bf60c76e13412436bd6f51ad653ecdd00cd248cfca02ad08d5273b2c31fca2fbd89e950e0000000000000000000000000000000017a4f7e5277cd5feb2bf4928e7b9505c1ad076042ee709dec892760e7b419f4362e62cd4d6188e99f7c3eaee3cabb09a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8ec3c28172c233c0b8738fc4b011b055709c9ce1be04fd77b996babf1755eb75233cddd67dda45f771bcba6b58c7ef000000000000000000000000000000000fd70a87c019125e0628c7b1165cdfdd3bd19405628cc7e8646d55c83a9b109aea563f5d8da21d47b0df8b0417cfa05e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025492fe97c73962b601cc101960b2c8320fed415266eda664ec550243943b45db460ec116e889b0f94196c31530a1840000000000000000000000000000000014dc3c680abeba696827c272ed9f04104348593297a58788e7198c004c3e8e43ba8a3df13c0c79273ac1387a1c60d0ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a755d2e452ef95db10d824feb95286f9123877bf61ef973e7abe85b682163829f78cfd738ebd9a8ad6688539e13235b0000000000000000000000000000000006427dc1402836734d528a8806a9d4188eaa051407a3ff35759ee17428a718f5c6f49c23388b892ef31cada19f272a0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b77275b7a6f7e11364b533db09d06a32e9c9da9026177d51f64735c2c56f72983853fde4c467b73ef105f3a5ae443a000000000000000000000000000000001307bac72e80b471fa4aa987291c58bce55c9a87dc891e201bcc51552df118012903187804e436dbf262ff3c998429d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003975a28d20f150b5401070cc89326906071d5e5eeeac33a6a5502637752f8269cf42ea144ec2341c22c70de24fd4b160000000000000000000000000000000002d3f2aabffd93f15fbe6094a5a49d8f92bc0971412dae7bb9e759460252cd70a206fd68391362e5f6630e139dc0541a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e207c190551cd071c020ad92b96a4f0b9be4fec42edb1b61ac03cfa097f675dde001bf600563a7af92803aa1fe83978000000000000000000000000000000000df65349b486a1942efef08e0abc980ec7def10cf0ec4ccffb495ccfd5d86d11abf5aff7a30ccf0632c740281c8ea64d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ca44f4ee0025619ffe68769ed7392449ec0be0481ec2c735060241b8cebf54db7c98af29a4eb61e370bf6707efb13c0000000000000000000000000000000007c9fd725796fec1df27b23feb78fb9499c97f452c65faae40900eef68348fb21c62f5c0d1f54c6fb444e7e37d5de21d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001731e86b057431215aec6e17f1b5175d8f0cd645392568f57fce45ee357ab6f98d3ac46b0b529e44d0450a82a3a24b0900000000000000000000000000000000133adec624a8e434c8a38e05888b7765c715f91c9312e976bc18aa6e633786d79ad2c37975feef494c6ae654c328eb2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e12bc922f44c44fa39c6df1e8b0f2a4029ed54eab8ad1787e27afe7a66a7964ab5a25346600d6debcd25fb18f9b2641000000000000000000000000000000000b3777d782f9671a93fe5ca28d5b36e4c2e6f241570334614058a31382d941a136fbfe9843e190b731ed19ec8bc648301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016fb13aa6124d72667e54267d08ae2fbce363445aaacc5e5998e48a505c3e834c7dd1c183edb1e00997fed082bb169d4000000000000000000000000000000000b73b94cccbe87e5d25f4e94a2023c4149738ffddfcddd38524edffb6af321933d759f2087992ac7280fa0b73422056d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b480c3f10d980383d208d72b20eb9f49870b0c5a37c718768485c82dbe9e8a81e2b14ed542fd46239a28e38c65b480c0000000000000000000000000000000005696db865fb41ce037f4b414fe3634c61f50c5b9aebe36fb634d836dc61a7814169f6b642589d6522c0921014b980e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016397e2c6f2d0ab33736e8cea2ed87f5d565ca342602cf9ed3366245f4d8cee2a910bc0c3275f86fccb72a6b0eabcb110000000000000000000000000000000014feedc5e5cff755ed7eea591978df0d170eae3d0b86d646b2a8e72d46f59bdc07e788568f5f0cc461b898a8920c8ec41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132589a6a7938dea56b5a6b6e7b46dce23c0a33a8d1b9ef046e07416e1b4264f17868d86837bd1425d6598de4d49bb100000000000000000000000000000000012c1b6485b69b9fb385a7016023a40e166baaf89f4d466d698899228fea35c77039d47937dc086222177f4d54e32ac281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175d8758b3c28fefe3b34f46f5c25fa7567dadb691f1db89537fe456579e42c072c39efb1febb63a196543a9450b933000000000000000000000000000000000081d663d7eda00def9d8b1c2898f56c11581ccda4d39f6bd696f8ea99caa966943f38ecdaad7a40435d40d02162237f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149ebf3e20f69f49a195cd0cf6f28b0e25a26923d94713b434c2c0265ff10e54a729ef6caf3713477f8da497e6e210720000000000000000000000000000000004f05396f703d55de60bc31fa7ab97ebb199315275833fb9415c4ea122f914eb906b46d65e294a5a8a247a7401eaec321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027126bd7d94e91ac30f9f9b9a5096d1761f1edbc6d4d5721138238ad3ed1877f6fd6feae4a67efdd16b000dd04248d700000000000000000000000000000000094d4508eae7dbe0ada5c6774a9f5ca2b9795734fd5137845232248e9cf51c6e3171bb0db255bf3c1c25898060aa6e551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013341daa2a745adc0d0ee34f2392298476fc3b1eb295f1c7fb62bfe0b88cbbe89ea58530c0aad90513eee62a7420a1000000000000000000000000000000000007259a178dd247847f6b933a333b98564365a2d29447d156d6f1514a674452f2ac797627dc7e471e6e21f8a453ada5d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d0005a7bf3bd27bc6ea8ab49f5ce83c374c535f76a9e7f039292b830e1f193a50a84f41ffe5dd55b83ba210cf3e37900000000000000000000000000000000119f069d93c6c1e0b448adf3de843e4cc370ca2f16d428278bb632c6c4e34e3ffe24d27b162ba5da92d0c487a43f14851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001544a235a132924f7ae985965acd4ad409043f61dc7b880a69786621c417aeb34b026299e0508e78d581bfea2fa9afc2000000000000000000000000000000000e3b93b553b53374e856d70cdc29f2c26c38c89c0f5d80b7f46acfc2a54b42683403e805f4eac6c29a65799d702b35a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159322c900ec37623ef56fbf72ceab58f89c70f4ac42aa2b4b526569f92b405374bd19a3cf58d836adcb0732bc4fcac6000000000000000000000000000000000fede779dd11eedf222e80713bf6f01a92fe4e15431544e6d10a7f1147d3d02232ca394f735a43ba12c7c810292a87491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0d922dde2cc3cb5170bb9e26c3887410d1abcd1392b76793ae3fe226c267734bea16d3749b5c335c5217d8ad85e1270000000000000000000000000000000015d20038526a12199959f74bed93515ace97dc09530868ff4f172f7deb030ac2ac2ee92b4782d4804fe3918cb5aaea271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2d2e8b389241ecea9213b810eb4a66ce9e467011d8361f379a9c40c2f073df1bce54a4ee38b4a022b87ad2e2ec398b000000000000000000000000000000000dbe06455356f3df6a917dbfa25f4305cf0f0b2b3db401b4a246de6201016d18a4e97f32f3ae5d6c3f7c36027e0698aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152e694a8f18e3c27ace9566cb294b5d7534b3dd29f27d1876e2f0374cfdc7b3223487e2553edd4bd009583e02dfad09000000000000000000000000000000000cfab86e673594f4759b2770d1faa6db3fe6e02a5a18c0379ea26f2f81bead5dbd7a551727b0ee3d490d071ccb88c9831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000421cd4a80bf1dd13fe4629c7223f90036f680457129ac1832de4c46f93680e75280ab6fb37550da062db1e53b3d5625000000000000000000000000000000000737e00b47d2be7240dd558e01c25d4b61a9931d57a3d435a25a7909ca48d0ea672d74e7ad9c101372be2d7b67581dfe", + "Name": "g1msm-1024-jwasinger", + "Gas": 2138112, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000032007cd3b483e58ad66b9d31e32576d448922874a6a811bab27c6b99991b1760667240c17c8f725d14b9ae03d3975ed000000000000000000000000000000000e074e23a2f0fed94017184199ba2779a4728d33c3116c6634206eaf46dbc149d9531e0428d3ae98f33e3f8078e4c96b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6b3ceb0412b1887a8e93debd54b8f853521040f44ff311ace6be13037a031f4e6347abba34eff95b7b330d34bcaa5e0000000000000000000000000000000015ecf07218e3155a8a93c6a0c87a91bdcc0783f6b9de0d49753ba7cf833e643501e0bf0c308762d6b5e11375ac86740b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef5a85caafdb82adce7441ecc0322cb457d1e689512310787e98e378cea1ba91c18e9a520cd1cff8f6639365ac99ec70000000000000000000000000000000007501aa83ee78e56907c2ad81932f35d35c37f4e200d6a6aab2c9a54699a4d83cfd8ed43c60a11a2101b0c020a2f89981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088f4fbfa210d9263a014e688ce17b51784830ca6522eeaa3434cc3199cf73f7c636b4a052237bd52e273ace2ffaf7bb0000000000000000000000000000000000c05fbab30db84cdd7c63ccac3abffb8310c65c257af40a0de928dd28e5550046bb1bcfea5fc3085c118dbe0c9f46c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143b927a4a23924aeaf3b97aa0a6dcb5c2e609204414a39b0693affe36d65d33e059d9e3d3786f3a1ff9c9c7346bfb6e000000000000000000000000000000000754f407226e2b080868d3da913dcdc263cc1253098dd49d763ba671b8bc41cbf12e87b878df1a936cba0cbc01e9b7631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001286fcdfb4348c9f35dfe3e006d8ee64d3d09a09163ce6e4c17c6b09ec6f487e9ee44fea6c83666eb86ad4e59b8e44b90000000000000000000000000000000010923d71f470fbe0d26d4c3e4bae44cea3cc5d1a358f1fe1c0bb3c07e745b221058a0ac75d24b09f528924a770efb8591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2959a6c02274ca15b459e88ba5466eea318686059ede0935e8d4f5e8b60d551e2ba3184b3b058dad7ec5dd4b2d913f0000000000000000000000000000000018bf3dacd0542aa7a388684328f67d0971b4045f2967223af6f280d5e42b33e238b69cb43dbe8ec07c36bd9eb08d9b321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c45fe4ccb91fa877878719f8e3146672a72d6fecdbed0dc4c76f74cb8a32959dad028c9af5ceb94201b1a1b1f936370000000000000000000000000000000012a67ae13f41d886cb552177981681f035002034c31dc0252fe704b4e445e94062a8cac411f7d260364ca09c745889771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e351934bd8d5acb96b9a6b5cc496f419faa26d53130e04f8378e4c0c8b1f6efb530a97fd7a5f46ed8b22a683ee6c980000000000000000000000000000000010f37d114779513790d73a4f7e2945dc443bfcb3034a263bb02c44c204750266d9b14c9ed8d7a4a9ee2ddfb1daf837fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb7ad23b86d661c2d81f74e5555fa117eda06e18f1924f31a1eb12fc3b8a7a33f12dae599e21cb1aa447405cb69c348000000000000000000000000000000000442833695039ef95667eaa264b5ae242545edc1d1cb98e650985dd34f4f4d6c6f1399970bd440e6c5d7618e0b75449d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152d36103e4bfd235b508df977273bd25b3cb595ed2b28eb23e7f601350d688087aa5465a4c16d81e5716d2dcad03d31000000000000000000000000000000000bb49310af633ca47312a14055ae15296c64b287de7f62641d092104448945faf27af92e0eb5f2fe2d92a83d77baa0421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4883ebc79f7b950e1ddeb699291c79671c41642b7dda699c796bc668f194ed0c4220f00cd466cb370a56f327445027000000000000000000000000000000000bd4051f0e7e2bcd9bb0bff7ce07257429ec684b705397ee7ab0e76146eeb1ccbf3e253d9ef0d539d9c6bca197a22ab11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d381f5d5a0a8cbaf34d0ec9211a1f35f0ecc8055e2c93bba4ae05cfe3e9874323f4c30afa5f43cb71ffdda7320e7dd1000000000000000000000000000000000b90dfe427466755871d6c0dda71382fb9768a0f39e694a319aa182c84f1e7049218cafe791a03cfc3afdc604d0ffb841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5a81270434ec9bee1ec77cb1cb9302e184f88cdd0248c8ad16ddf5cdaf88ec5e616fcd75f209801c26e316dc9b3030000000000000000000000000000000000ea6967b748a55b34e5326a517c586f124ac90743e122db0e28f1675492acc48d3ead68e475e054f7e77e17ac1c1dec21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cfe1a0c029ee59e67b00ddf61451f85adcc50de559b40be805c4575af2699e4a311ec0ee1234429aa0ebdc6d1921cf000000000000000000000000000000000132bbe7e63886bd9922ab742f1a1b61d0209786e3bf640fb1314f195a1113069b0c2c7eba636b240d8f8674969ed1861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000038b843c973efad1b8edc51e346a3564ed54deae2b57845884b78dee089bb8982fa82deccd47013ef7524d7df13490b80000000000000000000000000000000012b8778b25cd1cc301f22cf9c4918199035bb68d2d7a1ec5dc6873ac0983227ef59e51838520df74ce20fc8b70a0b7991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e85bab1f99f515fd31060877ecab50dc8d494ec28685ee048b5a4a252eb0829a27c08208501b25cb19dbf188171cf94000000000000000000000000000000000c3125746a939e59f4902ff79abcc5d4f92dd087d89cd3d2515dcb8c6716a255f9e2ef52fd3ea18b453158b2ddc101e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001067c1c7b32ba31ad257a8c2b249362e3802de0d08316826ccdf5d0620292feedfd0947bb6a8279e8f3116d3c9d6a0390000000000000000000000000000000018cd58680a615c13bac94648e1c651b98fd4490b18267e86f7a733d6a1fdd8ee0c6ff3c3d2ee33466e03e467c86312811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021679ddaeeb1679f165b53efb32dbb76f3c3b7a338a04efdf4564d6c0f642409be752a9cdb148284a60f439dddeabd4000000000000000000000000000000000bf6ddc74dc5c7f5a7e95d3ef36e7afdb5fb620066709ef1f225e2865a2e808fa2cfa8d9bb461c6d8c980d22ccd5f2541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033f40464a093aa771150801d3fc2124fac5d70a35a0202284baa9e0d1e926036c1d1636aca98b5999599251852108210000000000000000000000000000000016ab78ff003361a19e3c2fd0cf0dd1bf81d947e7b9d85835a7c3e930eace725fdf8655426e89dc19b837c90dcab546041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e6f927754ba9539ee3fbc962394488ddbeca108ca74d26e396652f49b58e2a621bb5a24eaf4d5ed68bd04e4f888dbc00000000000000000000000000000000172d6f63a7f70d89a6cae192d069661775adf6c5297eddf29ac7c2f1fed25c4d07994527c31977060154266239c611d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001689095426885beae3f8f147742ff9f2c904885d7273f751dc06d8337dd89ac888a47ce7a60bddd1a6825c032105a5130000000000000000000000000000000010e2d430236f97377b55b3ea938da46e7894caad02c290509fcdb11905ec51e8d4c58f67f6be23640f025fae1e598cc61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000003a6c6717dbf1b3a707aa7c2d77aa2b05a58c87b011d3fa4ca549af916e3cdab14c318d7f380fb258fec7ea23399ca0000000000000000000000000000000000df4b139cdaca8d8093d8c4e73ba8debec68d79a98f8b5a71d0d5b6b22b8968cad2ac068dd10bf905411069eab30f7d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b8c59fe028f1e9de599a30bd461ff6a8f52c029bee709e136e5d389ab0f17a5bb684982cd8eec25a77017a4412f979000000000000000000000000000000000b88f9cdd214887939d4b5b3b0b91ba7012f50fbf7211d40f4b1bad3cf06de29a1606b75cc02636527149e0bd6c208071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057ecdfbc63653eb22469763509db3a462a06c8b55777b93c973bd55b4ad4d556a3f7d542334875711e636fff27839620000000000000000000000000000000014d65f36ec3188b646ed06b3909b2b68a33320b710bb73009484ff54c4e59b13003d9181fc3c5ce78f0d24e250ce59c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001085a46ab150ab3c9efa1d27cfc70c097f3d870150bc0e9b77d3281a3ac236f60000991693d91a46229c31a5bdd6097f00000000000000000000000000000000120fa6328d34d7fcbd7d9ab28640bf3dc5607d2ad019d2772e44a7f4126b36e0c6754d8810ab835c98f03c3edefc22941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001052894142a43feace25e0940ea0eb9109446235f9d80955296c0e6eb9fb437752730f375b7574b0ce51e6e73ffb986a00000000000000000000000000000000143a9abb96abbf5cf89ff70bfe5c6fe1b698070e47f12e3836d83ef273474911d4a62343eff96b0b9e6e07efeba197061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b159c90d7142b25b142ad6273b80408d31c4a5f25f8bfdf8c6802bd735d063c2a4677aa85daed153323bb3b9c5d4c9200000000000000000000000000000000084d099e93955509c53d0e226be0fb1925439332121ecb5f014f5084b509a4618ff37505ef7ea963eaebb0503dd3dd511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125341c3362719ea01c16bc7cad91d12d61d831d0e6776ec9d5b6977435a997ac959f8ee87d1afed5d635bc51a5f9b60000000000000000000000000000000000bab67b2091caf5d5e2ed5b9582f060a6e34872c672bd063bf42a9d962a55ae5cc921a6e5444c0070cb52ee6bd83d1071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019d5e6c469006a4927bcfcc6d8e44714639f8480e7d781a778e4ddb32c8290fc6840b208650cb2c3f41708b17b21eba000000000000000000000000000000001030727bdc730e39eb9cb0cbf7ff49279869ccdd6e7b72ccc00802de953804f0fd3aabdcbad2ea3148b0e7dde373f4961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182d1a8bc85002c762603b0857cab576c68ef1353f3c45f7772a24cf0a684a422f5747e2ebfe7999d54d4d8519f9faed00000000000000000000000000000000073350f9440de88130e07f826445cab28906741ad8956a54cf375030d8425482e3c8e3ef9c74c0f2ef0d9e12a3bcd81e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001997d74cc5cb14562556df3c05282a3c71516d2635477bdd6f3dc103c9251efb26dd269c7847cdbd538f339a9dd5b2c300000000000000000000000000000000098262680f3971fb3fbbfe40be99f80932150620d3bfa299322be22291d03c78a62c14816f125dd283b8adb72a827a1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026a87621ea32b6d66ae8f1255d3dfe188224c42f10165fdf664c4b63ac3c387dece6dc786f86f083b6c672562c2ea0f0000000000000000000000000000000017388f32a0c1dacb6eb492fcedccb90a72c84258e374bd264c69f5b01ae376b2abd697f0236bb27c72d94e3d81ca9b951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a2d89c80df97d1427dd94e59ba07ea9aaeaff6a2e36cf4d34c40e7c75374470d73bc2990f9e6dd79d25c038fe49e50000000000000000000000000000000000baa6f4e1239f2ff8ff0195eee0aafea0628d4aecf36ba572edce0607dabb8e82446849b08d52f8dada4a5ee496ad5d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019250da40e17a94e7aa02ccdf4ff466c9c6eed3af7f37eebb91c4c331f1c8451d82a6704c4214bfe6a0dda87b0b5f6d9000000000000000000000000000000000f045301c4fe1bfef3681d4d5f631e5fad1627a77c8a43c19684b1e4847e195031fa47dae857fc2077019e2c7e7b24471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1b6bf707e25e1fb6402c32c7b994f64ac36e63c774afdf17091f6ee4bac0106352e541a4899991f0022c4d343d7db5000000000000000000000000000000000307c4244f1159c1324993a252012856242d578360c8bc6e3bfa706fd5766174bb832a69b2c2c472d56e2353a238a62a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004469855880a8a089eb7006362650d617ec5e09e67889bbfed11c6342dbfc20b966cf73e473adbca1798746a0845ddd700000000000000000000000000000000030318e8e18958ac777c7716d98a07bc81c23b3c34c7df73768f40278ab36b94f187c39280eb9b239ae3e875818fcb451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f8d347c12f90497d88a3a6ce49c993af8e35921c9c2bd790d160520fa275877a7d0e56d0403ac169650a6e449c7838000000000000000000000000000000000187405f96434de0e073619bcab0ff0f6e595bea588007a0a7e90bbefde4e5241aaca77d4841e7690c67b2029cee43311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b964cb25a3b580053fa30f91865a24c0986257cbe9e46403ef98416f12d04ffff5fabec3e01de824a1eb072d729e0700000000000000000000000000000000151de234008bd69b51cdbc2ffcc7e2d7d7c90b86ca05fff2b35b19ac339582feb01885315c799b584a7e9eb94d3a27261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028a6dc8bf282283ccfac9410426f70431e2a12bd3b30c8cda309c45ed0ba7fd34944d45055144604fcd4519158ecad6000000000000000000000000000000001412af8ad71474649d27334d19133dbdf89556dd35924e081393498e4118d29b34ea211f270baf63ab64320b42ef78611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037c9801aefb7293e96589fef72c0b20911bbf585caa2b62b2743418366696687e8d6ad421efe860c241c76bf4045db50000000000000000000000000000000010c20eb3608dad85c1ed8d3f5531d5bead8d5b939b70558b572f90a383707014202b1c2c940c3f96aac3743a81718ed51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001779e1775b0a6c342c85ffa896f2df91891bb719ce3b1f5f09913c17cec6291333fb1ac28d4f5e708eabb2c02dac3cb10000000000000000000000000000000015c09641e704667026bdf4b3bc78dd62205e01bfdff6ec52de776ed8a3bebb81452170a9926ce90d6affc70667f138911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001866280c6def3853ead557c96924505b12421a3813f6bcf776b0f01b8d0ad4e33699407f60a01fdf3b623b2f6c36a97c0000000000000000000000000000000016ca2304bff90ba992d857e43e51484464db111849946ed606b5f5fc769afd1d454d8eeff25fa59d8fb86cee3e45d4d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171ca1fe6c3a569d66f1427872d2bfbb945a3515c71ada66914eb5b39b9e12d66de4cdafc4d1fb8f64667070d631d40a00000000000000000000000000000000165a23d82e31b797356e4cba86c4cdaa92f2cfc9750b056a84ddee5b4d21543fabbf03e4760df90de2b0a80c0c7a25c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012207fc1854a740cc6cc443d7974c19a0568d373e404d4ce6293ac4ddf4b81b01c67b88b1c6d4aa075765ea55983b028000000000000000000000000000000000cb790d9609c18371be48b834ffa53ea0375b268e593d084172f522d6bf58609d473f1ed28825df1940e6ea08b0e63c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001219f7ebb4609d93161b954b54696884225d985519a3013c64bd21d82b209cee5f9f2a23b7c95d859ed0a5b9e0cddf27000000000000000000000000000000000786453141e45096929b03dc2c7710b6a163e4fcfc51e73c08fd20878ae8ec431105d000eb9374e183cb15adf96e6df51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002efbdc82c92a2a663530c4cf5eb6e179b5704dd79c472d24afe2f7514766e72275a1ffebf2d29336481f28bf10fc9d70000000000000000000000000000000012de417a5aa2cf3ba38faffffade38eacb8a829771b8302ded729f0d1e02707d62365e24f6fc5ebaac8ebd382917d95d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019951e64343465dda2130b8f5917e6448dde1b2cc4e76e8af410f2040e82c7865b030b4b3db862328c99850156ef5a3d0000000000000000000000000000000001009b1c9afdef8f6a8df4a87de5e6ef0d61d4b6aed2b721e9bef84a6e2dbaeec4307d47a4eeb155f61b7f353bb77b9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f1ce3c8db6d7f744fc15df28bcfd48b3cde56a52e9f78894e08d4a770579c01e6dbfda682b1d7ee593660a249ca489000000000000000000000000000000000434f7cc6d08ba7ed39b57a33edf80d45e9c5493854dd74e5c42c34af9dccc9c58c265c53d449db86653fbb00413083b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006598c499533b0b32bf8c7fef46b2b32d2de899182c79e1082dbc82d3fa749b7a96acb1c1cc2c0e3cfd8a0bb0d27e68100000000000000000000000000000000101b8e6fdcd5ba1203b83521b44e65003128b36f0f27a19c52744173331a15bdb398e98d1698bc5fcff8c82704fe0c311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006dd5a4b9e21754f0d81db9bdb0c6e2acb3a57ed1680800ce652d19abfdda4f4fe82108e80c135bd66992dcc0f92f8f0000000000000000000000000000000001512f2aa5a7ff68e38b830e23043d99730a5e6be3288bc18925a785c27e405b8f98ad48d776bfbbb56039a795237ab91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f3f4078268aafbd374ef27a85128f4d0a2d6e28a68c09ccd320c8b61942b87947d0cebd62d88e659ed5d50bb3e84270000000000000000000000000000000018f64672dc8d1989c962b751c9ed932c0990e3b28579d24f55c72c5a5f715007bc69b0442a260dc9645e86ab65f176c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192629af670e5197154a571d9bedad378b497d5e9d644d73d2a3452fd047698717653de2955a16c4bfc0cdb1940c760000000000000000000000000000000000187a27d93fdb7710a54bdfda60b09b62f69f6f7d4a18c8b15c80dd8d57eda20eb9bbe62af1b72ebb520246c81eb4c12d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000476e95d2e71ef3a156fab73b700244bd9512eb337fb4b2511e1648f1d0de6c34f4b2f38bb9143d01f3db39f8f1255180000000000000000000000000000000014443354ab9822c7dd6b72ad979a39539a7ac75876fb16a4d6af4cdaf88ad3826c3b168b2c8f2827bf2b0092d6c678561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef83fdd7c3dd23ed4edc8bbd32a553c125a3f9a8750170c70e248f8fe39e6a385d0a021769d361774db81e5be00022d000000000000000000000000000000000decfd66779f3ba05fa4e5fb0e189d4d20afacc58553d18128a8ea98a67729526dbe682f61db961112082fa1aa6e8f221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc0b339e5bfb39f21d9be6db705c131d8684bad473f9e885ea545dee22918bd0f1a86841140969918a951bcd457c42600000000000000000000000000000000036a51df51ba575651a7458ef08168c0694cb848625d13e2f5b744e00fd8ea8b878cb60f1a41e4fd25c62073ccba66081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b684ff9f60ce57b457224ac43fc5d88d3f94e0ecd538a95b5c8c4d6a29361a8d43dacfb5210380634f08f343a8b564000000000000000000000000000000000a6708684cf5272742d3ea7ce0dee63a0106cf28cae80e7ddbd2833013213e7f763af1e8e2912faea1544ea0058696741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1ed05d66d11e2b28f37c5098e8e707f0751bdff48756343c3a54b45a126ec5af938c03d1c05a714a2223ce96bba0330000000000000000000000000000000016eec9338cad83721c90443a91cba1606895ca7ad61e20b4bba64ba541cdf7cae5c6c753869fba35f266927299daa3311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001841dca2a38bf9e33876a7bd4cc092535455b026c3a80e4bd0403cbba5766d491345a3560c6d265d93e40e1c5ffec38d000000000000000000000000000000000a506f72deab22a3724b94dd7518a6680efceb7a8b0d33f066f338f97166469ec11d27a2dfc7e430e9121a0c555ed22f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016fbb69704970c1cd56e0751721a4fcd8dad1b2d3d14361b4229267dc76bba021458b1f69a14957a10a5f58ee32f13e300000000000000000000000000000000014ad8937e701ac0c969a97e64790e693813de432e5f68f78441946f603698ae0e39d6483453fc54dc7dcec21ff828091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040a43241a0a03501dc6c6af6512243ce956d9077bd0892d72c97f5dd558f31d8dbc2cfd0361d909454d83a5215b83b20000000000000000000000000000000015f82b5e63c39594bd5309fcc327df698a9f05f4840dc651058e9aea7d1599e51c8cd3af2adc6b83ea8663003747d6dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f9c56625f60561739e36891786e6e59fa0702b3aa0b497f66246f9570ce49833e195bf556d1ff9d835b7141d85cf04000000000000000000000000000000000d4a7f99d3f67cb2be1c471f01d2c5ce89ef2fbf985fccfa37fa8c550b9eb87d21844e5bc714b55beb5fc8a183c3d0891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180ac2655133504ddfb97b292cc9be3bf276c345cad53f8ede52e81d8c51f82ec48598f77f06595eb2a071b882d0d9d4000000000000000000000000000000001461783ef9c6b72556d79ef5f8a3edd3d91b9c114412f42c523b9f0fd4a156c4e9789ffec37707c38b793b4730d85efa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cae6aa287a1dd866917a01d9679d1ea29aedab0ffef3b5b6ed8509e1c674208261e56ff1ca375fe3d41fb6ecb9ec1f000000000000000000000000000000000e6c937433f95e25f4ee8aabd24b701cc211bc22db208f422ee45826ec6b56fb6b50fc6c5449d021e03f42b4397b93301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000b7e8f674bad965d023b019912a7d2cfb5b5db5998dfc182763c2db4ae13d3120b9b59673781290e38777028fac6eb0000000000000000000000000000000004b23e96ef43a19439b9ee78bf52490804ddcfecb43137cb8b99ed0be83670c16541da61bc24fc1ce763ffe2b33473531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d73a3103aea50eede0ad6c01810bf2af21ba18533cdbc47c03d69eb26b63fdb54a0661935b9783df2d57d49450417800000000000000000000000000000000041af0ff9b643cb6f068cf1b75fe857e7c98aafb7fe1e2138bb8ce739d674929910dd1830824dddb8dc1e6ed8e795e921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170e16fd0252a09d025b1995478d0b2097547a79b415b4044b8308118bd0c55da08c9fa28c235e7ed8af1cf7b71620b90000000000000000000000000000000015009f6f01560195f4ebfa2904f1cbab5a9dc65582a63b08e45a99c59d7aba13d62b1ca5eb0c9b0d85d0ec18e376d5161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193ab882c2e79b5714f30d57dcaecf87519f70a3fc3fe7d6f02a59da51578892f0c7ed5ac5b6372cc5856a0aff7da0fd0000000000000000000000000000000008ff891fa28d25e1215159ac4359316d4da5c0ed9d44b2a941190050e4936a7ecacc3b92c62c75b5c1e5aa4a8d0da46d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000115489cf5dd9f289b372e219f9f3c15f768c69c94264fdf6aa6a5f81a5ca2cdcf5b7ff86c9b6bf732f40a99310873615000000000000000000000000000000001700c38ad4be29e9d022ce18377fe05bc767c5997527a85084042a88a72d62a1cdc9049b1db3c6a7a9939deb9c0838b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102de80550ae9aa9e25ed441967e875c3d17519611bcdaa93874665a6b21a6218621dd5c75d2e09bfa4afd5563730be8000000000000000000000000000000000bd608717a0791ae9aee400a082d6bba1985717be3b63d5c8ccb7432ba9f0d397f04e91522604a60ffbc5032ab6ecb0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d9a153393b95ed146f6da48f3f72295fc530073df4f22a613f9695cd92fda563184d37c150fd1446b1c2d94f1250940000000000000000000000000000000005c35a609a67e2b8461ffae2a5283fce152f968030d1fc1d330b06bed9a37140fd39e4663524e1ba55b690d6188715e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f82dd7f3672472148efd9935eed494fde50662092b1d08022464bbe8672eee6cdc369b8de570ff5637f9ae04b93af27000000000000000000000000000000000c4005fe2db14371ccbe55257657629a769fd8d3e6cc37e3cd11d79cf1d020306b48ddc68627c98623924cc1749df7901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b41bd861c49cc19cb6988a2e2d426b37eaa5cd32c457c1404d5efb65f07b0039b1bc1f5dd5e55916ba666b1e105d3600000000000000000000000000000000102c868732e30cd7c727653d58394a29475087f6aa02f19b855ab41be201bc606e073d8cd2efbe94efbd03bb06d461b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005150e5832642973353e161bb49f4780ab6bf1e91f23ce7320f585d9c784860f88905fddad1ee558045fe83444c68a870000000000000000000000000000000011027a2af0036bdf21fee8f2a250eb37b9e44cdf42ef927fcbea1d50c74f56a650630fc7984e88c84f58b823be3def601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001156b0ef584bb46734bafc0b9579358476c57f318b097708e8f9dd9add8aae53aa8a95d10461366d7a215b481004b021000000000000000000000000000000000468f36128fbe1c65453396f7f1218f2a28a7b2060c4286653db8ab786e7fdfc51f4a9f6271b7c58651b59409e3c288b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000147302fd7b65c86a0e87e959114784cb65f72ebbd43a9f03d84780eeb0c1efe10f815ce731d91e83f191422d89b882b0000000000000000000000000000000010d0019ded6feb2497a982f5d92e11a11114c535a2434d9ffd3fc7833625312aa3210718ba33ec123319733861f6c3d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a284d05e32251965be5d13f54db18b2548acde54e2ceb395e94aabeca3dcc338741963a245dd4cc0bbbcec2287bdd890000000000000000000000000000000002a7673189eb5f0fc5bb223a7142d32d4c2f76f378b47c3c01d37fef858a2bd913f8c263e0336e149cd0925774574f711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079e02cb0ba6a3e5f0e04d96463f56b70b93b1db504997f865df3216bd310964a2d3f253e180907748c7e707334df8140000000000000000000000000000000001d62217fa6e91423ba839ea8b50a6525c4306b896ff2eec52475a9b675058f9b83075fa91a62ac431b796726b60b1c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001462756dc8b793923770e87bfd8a327f70a83c161048bc868eb47e2561fdddda9f3cbc991544b3d10b60a5de8988e1aa0000000000000000000000000000000000c415624d92b17a8744a468244db414e8e4b980ba04ee7937838447a706d01c68f4bdf10433e92463306c35b76348591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001859da83245613ec3a91c04b5fe32cd4f242f6b58e4823e5d9133b6efbc196889ad70d3665008c80ef7716f31432a8f50000000000000000000000000000000003c1f6fce218c6a206f3e863a33d4151e53e91adc0bcebe7c5ca9c5ce38f49a7483f21a909cc01a2c5c69532aad743761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb2e148232bfc23ee9f904976cc2cd9439a57d5bc221e8ec68fc4854cf5598b06459eb0b3354492cbe2dd211060fb2d0000000000000000000000000000000018ed57ba2f2b86ac7d834d64f7cff8e556e325e9e088dd630f649c3f4617ba4f9c0373508a0c7367298ddfcadfe1037b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159ebce2f2e32976fa23c7985a517f95a7471587895b11e9d741b024111ce5c5dda5246f97b3a33c259b271f4d70c29200000000000000000000000000000000063f87dcd69ad605ab0f643ecc81a1e9688d6d0a7b42107d7f2c4f48658db4a475391299feddbd08442f1b65ea92315a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c018cf79452e50882e10fb629829a038f48c93fa916e5793c0bdbc1be19c7bc75ed5738db96bceb99cc861b4953ff7000000000000000000000000000000000df949931aaa56834a119d1a4766bc397153027b9e98f67cf1c9413ab016eea3319b8fe6dffb2ab0aab7d98617e0b1be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7dacd162f1fd7b1def536c4083529561eb0e500ceea94992c78f6e3023b5580d3012b89f7694c7aa9da18c26c12bf3000000000000000000000000000000000043f80774cd47a8a2f3054076120917e5046a16917e0a16acc32773eb5caf25299c6a7c6652b18aa4820d75f6dd97401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001302487ee0766fcff5c21d3a6da03bcf6847ff1e9d3504f69aa9594ea00a65a6c6028050cb1eaaa7c45250fef886776a00000000000000000000000000000000147781f4ee28bc31c1abb5eace55a9e3b58f7b3644f790174ecb0c1eee913e52f6eebb5dcac42d67a482adedc33bb0821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039adec2ede880b0c96e13b60589e4f9e65e86a14703915b6311918f81fe3af2bf434be941facb5ae03b585e7dfc5009000000000000000000000000000000001268f097825a6ba6947549bd4a3c051d59fa6846379778c53872c66391ed59b14ef80d41969743a989149bf7f6b44fa51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152b4faa107163d6f5e7738461a7539b71d6585465ec3b77cf84ec5f11138dcd1043bfebdcfa26ba58cbc26fb1cf77f500000000000000000000000000000000088782327f8e8c98c3afa9fa2e4f881b374f7c4cfe567b481081f6bb256dca6eb10a3c51ba5aad953fb531c6014e0a271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059069a63e4c1a51df90605f0c604ef23b1bec2f6c2ae87344514292baca2d4adee3b5fda85c00c437446a853984a40f0000000000000000000000000000000014d5b41aeeff5e3c1c9ec8545d400d41da4157b2607159756b4868282b665ddc39b9573979c89ab1a0482c0ce94a67c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010316a016f8976ab60502b324f94ff1a5186fd179238cd8d894d78fb89d6def54ae1694ab223ffac7f188fdb9a1bb6750000000000000000000000000000000008a66b5bc4836338d05f9f6b04fe1a366f37d4cc19eefe5517616154e0711a8385c8a1359e2c6716e5417e2d0d251d241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d61f67622c76fe10953b942555acf258a6a73b2101339cac812bf68735e361ec74efe01a570760f1257701718d3986200000000000000000000000000000000029a6562ca4261117a34277a45340ac6385dd77e494e2b639732eed24896fb55c040839d7ab982f2bf642b212303464e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071fc210cecbd2443115d13b1b890aab0c33182e8fb35ec912afd5ad0c1441019cdfa353dd886ff2deda0fe72f6e005e0000000000000000000000000000000013745d02eda254cf2acfbe8c7e5a4fbbfd31d6bb993da3cb180a834380be0934ed51bab195af18090db2b814520d953b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000867815f868c5efd7ffe8bae3f0fe3beb85379cd4264f770e165c000cb49728f7b40386b5020e07f39569dc83fe3dd2900000000000000000000000000000000085bd4ade2f1f134da5af39abda5e5dbe91de3e9d37b1bac92c505971a436d7110b64f44e3a14fec40dfa61dd43312941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ca9ca0ff9e6f96ec2c7996b31e79c9103e7ed80b74508ee45adb744be0a18f8f22b704992e6fdabdc05819ddf66272000000000000000000000000000000001731073fc0048a7c92079754baa5a5e8e5afd6bb599eb7a31952bee9cf20e246ffc4e0381dcdf2e1dafecb067caca7881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d934b73bda02d06e90709b50d5d13e2375d7dd674a4ce67c47238ad2b8fe5548aca2af33973b042336cb5bc0b05a6c40000000000000000000000000000000017f45be1b13312e020fe9d74b83cde81db164cf3b17951ed336edd59cc31572295b16e24dd9441a98dfafdd4548b129a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004504d4a96824b343989f62f18a82ecc4a96a92795cc63c2c5c8f7777edb3c5bf16fa9560a699ad58cd152253abcba3b000000000000000000000000000000000b75ce9b422209d35cb380f0d6a1c18563cb23f708bcf9e88b21290ee00449561e7e88857192907d86546959702484111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccadb065435c2a54ec8dbb414f7e14d83ae2fbe09b7da697c9db14c72a7f571913d54d08ae1746650bae6e9dcaa43c10000000000000000000000000000000003b924369ccb05c65e9a4271daf88c3ebf07594f2f05ab7070307ce3093f82c9e2aa8f02c776f766291554fc780b61f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2766bfdf616f95dffda112d2681bb1a093e6c5c65ee8b254d95bb64dbf76efffeedc7a85153496348c04e8c413d8020000000000000000000000000000000011a90ee51123e41ae9b7357544a3bee1e604a1dd818b773ffd181783e5f592b202770647fdc196d4ae33b923b4590c991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c5352571653eef2c93d9e84ed8b1a8ebf94a5e8fea352497edde7288acef453b4bd00cf0bddbb2271e4947cf5a6f650000000000000000000000000000000008063c1211f66e9ddefe67cd93aaa5dec7890ca25b43d18b38a999ac6010723861bbd6e1250f70e62da1a0f8f119090c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012769606353454065c2ab1cb25d284744adb5fb9a9524526203f30f0c266ebb9af11d58518b087d06b06511e4329318e00000000000000000000000000000000138969e051a71302ff060f5ad9679101f06b40556d3bc7082b41c1d4a92f38c75df919bc5033fd7a8a32a5f050e994f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c478c5df9ca90ba1cc4367941a2bf68e69159fc4e40a4a701aded777209fc1f8b185e8b13311f5623ff6172e4d543c600000000000000000000000000000000048cbac81daeeb22a81ed04790da93ca2612b708f4f9d871996a6b1e7ef1ddb4470a3dede075ddb84c198097a09b0c731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e433bd30ceed5c4bbc555c5f09772ad5a2268ee2adfe8e499253534f066316aba70f05e1193a7e3958d3c7f4a1ddd200000000000000000000000000000000161e8e9c455e75c30977de9678b38bd3d1f0bf6d20a8e3b5e4e918cb6a51f9be833b84bc2d6942b4f366dfe0537217b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000beee16abece6c2abdb2cd560554562c01cc42ae3ce8ccef79531de962e3f921b2905d30f16baea0290cfe687903a309000000000000000000000000000000000091d5e5ed66dab10904efffb132dbf633a2edd0c47a511398cfa6c555e16020052fd38e3f3f6519d961aba547cd61351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001002d1aaed3845d4d76b8ae07be19895d1e4a0bb0c90c3c5c8837af979cd1411ee1b2f056280e4a02822d8020aa544a700000000000000000000000000000000179a25f8c5558dbfa3a00fe127c91d819c3394d5c5851a9a9ba5084569f60d5869e4d411c53a5602d4b48747d60513511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194b5f869052c2c753ad31e82caa3e8ab987edf64b701e94a6b4c9432a286a9efee8bb1adf6d0ec592b84aafbc76af78000000000000000000000000000000000be06f43b813da7362f5437f5580ed3d9017115e758acb0267a75a844c1919287ece8b5cb17d9647521a832a2f6e5e141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f3a14cc154a635110cbe481072d8b783bb2fc1c5c079e946fdd0f53c23b1c27f79908f1f49a5f1799bfafb47332fa1000000000000000000000000000000001446f925b64dfe4b678a9a1c6a1c972f9bb35448aa5d10c2b5d5ee28a6c5e0ba75248a0d4ea7583d524323cf8abf56561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c0b3ce58e00c4d91554f5c4abdde253da3fe567da96c8f73b121b7aa09e5a1daa3743f3d0ab691a3e80f3ce5e88ca2000000000000000000000000000000001965a264a01bd107f9521d7044e7f4c7beea1000d9c318ba3b84f6db395011874dfa7f7dd3e4dcd235d38f893542c7b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013473897769214a91c5ab026f385ff3873b73826971e27955c27891c3b7f10cb526f4c5137f98a1dd132ee4e2cafd5100000000000000000000000000000000011c1b45da6aa3a24bac0575b0a3a109d1c185612df1eed53944c099ac0c7abe1ce61c5079d1b3fdc3746d9d740eebb771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132694e7d6a021f7d05f7479aa171e2e1746cf1903a8b325522bef4b773997f66ca708d786b5995df1c615d8f04e96f50000000000000000000000000000000009c48456478b05ff74ea83221bba6dae5abc14a64214fabe4b092385289400c148754a9f5e1bbc08b6fbdc50654506e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012662e0633cea5435cc896b6de3af926adab899098a6bc0816aaeff8e0d706d7bc9c6032172e65631da76d8224c5bd80000000000000000000000000000000013a93cd08319abab8115b995ee8945ad748bd20d215cfc19adbf3bc4fc060b7e77de956a962afe922d8377bdffe06f5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097dcda137766c1965306264a9ee37ffc0404021b2721a0d05750f62a78c920b51ed8686744ab650ef824d5604d5372f0000000000000000000000000000000000e2fb06b77e1ea0dbbcc0d120fa00fbf86d5bf31eceb54d9e58cfb8d87b4b857bcb792c66f5b912ae7b88a2a00d689d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005de4e8167035d2a6c2ee9682ffc0da2f9ae1cb898c216356a30c82fc44f142f04a8ee68faabf1dd0f9df89428c2317d0000000000000000000000000000000016174869e2cd1dd9d938479a8c43f75f7bb9ade206ccdecae5ee675abeb29870b622e838e5fcbbd94e3e09573bd7f4521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b662d61dd10617b053ac3796e0d8c1cc6a4210c95791b615628fdb8f1d41c79d5281dcc5d62b361efe3e18648ce2a6d0000000000000000000000000000000010063b63e5a0d8b2b0ca168eac8b49219b098204682986a3efb251a8bac1b88b3e6d74f42109c3ea527e9cdba9d41b371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1c29864c493d10320ecca3f201fccb1e821e83f8a68e6e1eaa3bc8a734f93d592991013b880333edab581908afff7e000000000000000000000000000000001083c06feed32a6ea6f54b59c63856c458c217089cee55626f401cfc07cad80fdfb56483178919095dd02815b552f10d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001849467444028ff330fa842950ad471d7f4751ea9ba52050ae6580fb2897e91bbfd185d7d8a607bf03b0758db478ce550000000000000000000000000000000009f73653f3e2a7a5db07f3a41a31c1fbf1d2f09cbbd4a608df8e72a68dd07ea2272d69067d80a074542e33c25661d2011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ef0446b723cb2945354ae45f2b32b70155ff8a4f7d883027fc01fff5bd8981ac1b763ec79a7eec0b3fa713796d25d500000000000000000000000000000000125ded99bcb64d92d9de082cfa69e2f2b21af891c049c5f98e24f5788ba3aa04d71e799fd87f02fb020462365fb9dc5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001698f3e1c65548aaa68001399237b87ee60e701116c3d7c77b33343986c98095e1e68f1e8086c05746cdf43049a1ec6c000000000000000000000000000000000f7a64ce4ed9ce2c3458fb9d4377d751369dca025b48029a285f901dd3d514f6f09d71c0cbed576f5ec201d3865727911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9dbaf6a26d6fc045b65098ba16795a80e757d567d8fbfc8187d95f2c84635ed411054e030589f5a1ddb91b8cbdb1c9000000000000000000000000000000000d29ecfe4cb00fa10714b0f685c28900fb6d6bb16859baf03e95db361614691f01c851eb02f3740abce045d22a7892841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cdbb96c7a0f090fdda28d90568d9065ee20574f3f841ef589f96428f7b658f06db8f2beb5c3dc9e8d23cebe24d0d4a000000000000000000000000000000001428857ccf3c898d73821e06accf7d5ca8e2b941b7e8492c8f2595fdad49a2b0a42d1d9320381a5ce6c40ba5939fd41c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d389ec102f24ee8ec8bb9764e895f71e46e5fd2dfda4b572c5327ac2a76fd3ab4f0e23e98a2c3eefa4c249480906dd000000000000000000000000000000000306156750e8b0e8d2499fd9425f425b553482e68d1cdaeb96c9c2f158bbda5d9ced4e581b749799a85dee15889df8f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018556fbe25e00f028acd3d4c6119764118e88044a11b4d256358c71e9b246ce5f0543e38e94743e9db8cc00680dd5bdf0000000000000000000000000000000002bc95e45cef2295a3e7cc6e9d81e22dd755f65ef9515748f183db267e9c627a5b771e11373ce05f1f5072362128d81f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065b19014d6aba377f2adf8c37e9497e36c2f5bdc47d99b0a204d90361d12f1f3ad4cfbff0823ba5a9b4a60758ac3352000000000000000000000000000000000731a6da0852e4583c94224ae71d87115347390da3e6b1666806dfcce169857bd7285109614b4e4bd92b5bc74ec941e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010bcb9ccd4bfbf762501b873c50d185e296c8976c96f3d485008446c56b719711f580678c0f4b700e9064265fe9829230000000000000000000000000000000005dea90a4ea17a6ca553ca1097e34a9a92be34a4270a62e6d4a5a74c86c3881daef06b242e1e85ee579c95ff6a45e3e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000541720a25e3829a49e1398b256cde6278304b0ff29ff8ae766d2f1584d9180e74b852490f620efdc6ed4ae9b694817b00000000000000000000000000000000184220283757a77dbd04f4f2e47296d9b4829fb788faf03463af6cd116b3beedf3bd47f42274b56867f72b74a7ccd0ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001777a85496fc37cca483cdafbe2ae22a196aecda9a43c90312c2ce10c1aa34d2a7f3e4584ad3acacdbbea02ecf17ffaf000000000000000000000000000000000aece05dfdef5e0c921f0dfc04ae9a5f03bb39ca8a862a3628998718ff2c47413c081c586fe2d53e218b4eb6918a6ef41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb84be5262fac27bf796cf2cd8c3f5dd46e9f86c146be5a84090372007df74292ac66e8b9cb8b39db34ecef62fd64a0000000000000000000000000000000001635934b146d516875562990df328cfe2791935bfd61481d2745a849ce52d2d49c238d1ad3338b47d67de49bb1c6235c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159614781925f6d57b8dd89acae268e113dc21e870b2ac099f8b581eafcbb3a7f2a9e58f4fdad1795e9c425d81604bef0000000000000000000000000000000012265fcb86336b06f83539198b57e7893dd051309c3977941c36afe2493f806133f484df54a9c632635a3e8eb5ea83d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001319f83bab38ea61515b0230e525373d5d756442c88724cceb652090e47dbd6de1fd5f98b07eb50651e58b391737750a00000000000000000000000000000000077d25851d2f1c64b14ed30ea48e2824b3cd93a2922d78073a5c3bdd1e2cbd633aca8e3e11435d77aa3640b5edf0fe471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189cbdc7e969aa333fda9d00daafa3ca7ae1f0ded43d19c6ed9b5c29097ff4d7e47c433c71cece756a18f2791dce0ed800000000000000000000000000000000086b88a1a3a3532e54ea451b6fe7bca425c5753fc1fe9b2223bccbaf22b11d27ecefe4c8b0809c4a79740ffb7893bf921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013bfbd5ac57dda92068a47cd9aef8dff0e5417c94c031524eca6ee6fad749b24b3a5028f8882d9ac919debe3986d0268000000000000000000000000000000000808ca692cd9690990909dc38fbeefe7bfb2fb1c5538e2b8489c89918657e3844e4a95f67535288cd77db0ff4021f0ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfe3b15aac6a8b04cf4f8c4e1caa99f7a035112dcf160a79f34ef0ed725b4e23738d150138ef236132b5b6809e0cb2f00000000000000000000000000000000020d2bdf1a62babe7f685a41b23216038ddd03fc8f9dd8e84b62b055bacfd3c2a8ec2f5663e35199d539109be305f6ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da4dc6bd1b290f7593f27e64401ca3dcfe8dfa266490b3cdd1216dc471d0e4507fa88b7bc72dfeeefd9357d28a230820000000000000000000000000000000004b84b35ff110279a8cbec8f5f00d04934bf1b64671c2a8325720a243ac63a3b601ddebda7443ff406c0910bd7497a401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000babe817d6d5f0a39f0c5b720b31c4f7c8430da3976bd68502bbf42a6e79ba188636193ca68acf73d9f93b4661aa304b000000000000000000000000000000000b4b26ecaa5ab138d3def229c28d4b9207960bdce29e2fa63ffd3f182f86e835826a66b4fcba323d7cff4c8af82d17801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042cef5814745b9953197c0853ddd210a9179e25ae8a71857ca06ece63926692f1f60ca1261503f5fe45fc5f155c0c0b000000000000000000000000000000000b4620e4c151881f6c629fcbc4bcdea4be19a180683b14f5b31a153154e4b0760c6fb5241da531bf4daf79c14863060a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ea4bb25d0f3116155d1f77ca8bf51c8bf48c3a6183299ec1132bd2fca92165a3e39bba2c6cf074c3822ad942e9a3870000000000000000000000000000000015338f1d0fe0871ca513168f25ab1a801bfa915aa03f569e86bc71e2bca55754fd0d834cbcf9d5fa38453226011627ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084249d816cc6ed2cdcea62b58d7852c19bd586ceb3870f36be476160c336abb874e5449c7458a9715a520602340315b0000000000000000000000000000000001607d0545f1d2977d3673adb80063442458d519571bfbac599542dc331566740dc9c366a860dda8e78d15d7c15e30521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185ce194db60f6250688b869f0c7b26bb758d535c35e2fc1308826781c52fa9f168ba6392929a0a762ba8713d3800f61000000000000000000000000000000000db29e64fb43067d1eda7e69090c8cf5145c7239966553262b7543eb5d536c05fd7d0df3f631cdb8926074a0baacb8d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015265f76c9923b8462a2f052637a3172ef371164f75f5dd59efd49b84d4d33df53040de25782a0c1299f0fcde0074f32000000000000000000000000000000000b9ae1f6ceb27bdbf08642f66eede79b63917000c64c88a08ecc4fceb4e0dd83a5448a4cb66e7c0c4bad6ecaf7dae19e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113dc2fd6cc3d2d3d41b8573233ab54b055448288088842f5c74c3354b3566227de84b3dbde9555505bef60d349da28c0000000000000000000000000000000009c77c78ff364592588221485a64867933267f6ac15c454add80d4fd22e4af85d872f2ec36651a3167d901a34bfec11b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac42c8955d4487bb2b2e3a9a76c94c2b9b53ef636a949e8318158c76bf481013512df51f6cf9620132c80497d14269c0000000000000000000000000000000001d96c4dea5e0166dea465e490034b31242a8c3225a3f7c048ede9b05a732106c4aff5f099136a8222bb9785445d53b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009665f6e8a77b02be1cf251eb13488fcbbafe0697b7a6ffab02cd222216b830eb70bdb6d7b422258332057244fd45189000000000000000000000000000000000277f279f30aa9dbf6e8e4ac71eab6b2f166b48e5ccf3acfec4df756a8eb85d5fd1e7d1877acd853741c3de70d36f2081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011373b0c5de75897f5ac9a032f067736bf1e9a18bf3681911f4bdace09aab2bc9c3e7425f401befab054a16eea09d97500000000000000000000000000000000179226fe77262079a1f167982df566f7c2af78b49cf2539d7b273f02c81827200eb8af97683ae12aabbbde5436bd9f9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000368ec17b90e382b9abc8a833e647d010053af3152696d76bc89d4c84c4860562ed42c04ada7f8272a6969dfdccb5bab000000000000000000000000000000000c167a58793136d67436d9df1735bc0c53370f216b4aea46cfeba02b2072142b2c488048ad97f58b38441d7175c1f30a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c7ab8731a68c8886043f2e5caed45b30f79a0142f374f99b30f65d54dd5350f39e8cbc59e7fc066a0e5b47599b0de90000000000000000000000000000000010c8cdb86060ba474f03570d100488b1d70ce313ae98790687b5c201c27f638b91d6fb28e7ae858e0bb69e79192a6f201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b54e262c824b32353517637986da2e6aa2e23053a5c20426c5016f716b1bee0f5a753dc7e0ca15b7f4f53312376c21000000000000000000000000000000000ad1a8200a402136f9d71abfbe8cb745169eb35732992bc8cd240c4219b9ade073daf8d7cc96ade28a16aab4335158de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3584599dadc7a7f55902fa94d69404c33d78def92dd1cbaeba6ab60ed61885004716bf4749662e3d285ab32dce464a0000000000000000000000000000000013adefdbaab3f1aac72b4fe8778ed01c4f2fd65874d73703347e6d6c714718378dd3f03592b77e5d889ecf3cab10bdc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000452cc48da32937293931d463dcad00fb4a7fbbfe449376b38d3942bc84196552a5b66cde42adca0925dd2007dd7d0c00000000000000000000000000000000078e47899067070d935303c40c61b4488e8993c0f4c0f2f55019c74b1bd0404a7f6894d7bc5fd55f7e384e9a00b271f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164b029ab55cbbf12314af058055968d3a9de7c195cbf6bba84cff23331bdb49ebb205e668e2f403cf568e640decd20e00000000000000000000000000000000148c6deba1af3a27bfb1a69b9034701178d290a058211b359b7b5c28dacf14e2e48cd3e737318e1bab2f52bb597b45631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120a25de8a703f4ea826264a995cf83ee441582e20cfc64168fc9fa7970d668bfa0167fc81d121a19abb07dccf960326000000000000000000000000000000000440942721fd7054a9e42108fd92260afa5945ff7defc210bd46fbcce105e1ea6ad707132030489848b26e89ffbc34b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067584e32b0a6d395511201591cd505778b26622f4f44692ff33a48844a87e544778896ac93fcc963f459f11500851f60000000000000000000000000000000011038b1a7ff10e7aa31dc8730a7ac9c009da3fd0757f233672856923cbc785c9ce419eb9f26be7cdde3e5cea696aecbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002458897a574f44145fc9e3a01c82bea3e4d7cf3f5f746eb87c8f2680bd9ac384b3e88b4e71df0f2c438a61c216f6c2a00000000000000000000000000000000177ed2ee1bdcfed82236c9001af939391028f183aebd7d78e3a59ede34cc61282b967faf6a7af739a8c9875b9f7750151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009792bc09a1e30c4f67c0e5932c26950de8080ccf292c7cce5ff02bb47644adfff5c9da4a62a55a50b6187041f6ac32f0000000000000000000000000000000009bbdd621ce67fc75d01d7a7a1c33eea3fb87f051f9d161a7598e0e6a65751ae9458b7f9287c42e26d65a93436904cca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001498776665e429690285c133b4292f3508628a90e43d705590e14778b8124d09e883fff8a4c9747d437f58eee524e7180000000000000000000000000000000001e73af4f2f1d506d0ba5bdfbb2493eaecfc26107ae75ac76fa6295bd6f7605cffc11c04dab4b7a069ff4d5bb596c2d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ed45cb2432a31100205bce096050f8be2579a68967f8ff6178c7c76e87c2597029668784afc7e32d9ddb39df3b2e89000000000000000000000000000000001905f497d5d2f30f54f1eade15f3f3ffdccf14dcefef513df3eccc95932731d46da3e777ea02255283e3bff107dc6e0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151e56a55a8a3a75a6ec7da7f3ad97e09641875f9f7c076420a4c61fd93f76175889fb8538469deae0e334aeb4cde8fd0000000000000000000000000000000006b701457e0be02c0081f1dd4b29164667044291a329678d558fe6d6472609ad94355e2eba16c212cd388b4c0dcac9d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176b699913ce4a2577dcd3db9bc21c1ea73e6ce44ed4eb1016177afe6a38ea6b75f8ed73a37e9396f702698e691f39cd000000000000000000000000000000000bc4e399065a23dda4cf31f1956651a110247867560105dbefc307a431e61030c8a7942cda050db8486581facbbec74e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3ad2e4bdd58a0596e6c1280bcf4b97baaf67443277bcc174befa306262085d05fcbbeac1371d988914bbaa012b860b00000000000000000000000000000000087fdbb7c0d258d24df98043e10e40f986f69dcd6ca9f1d5d2411a86be1889897af289a51b40909e635e0c3ca941eaa41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fc3ed2d4f44251a1c869fbc2c0f4509d347b4e3e6d3faf0ea0b42b2fd474323476df128c007be0ceb54926d2fedcbd0000000000000000000000000000000006eb94e026a12fd27435aeb36ac623c65305fa941b5c0e047557dd71d019827b45d4e9b2a26baa9273df0d1a03a9fa8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078fd3c1bd4f816e48c01d175cbdc60f6a9f5d053ded7ae21d105e0aa3a1a749c0544b901f39c862e2f7e651e80c2d0a0000000000000000000000000000000011d634735d8c4d91dab2106e99071c46a9ee2fed7aa30d9de75f249dbefbdf0172867da9f8b734b69168e7b5561588461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086387505a17cd30daf6f5e462e224d4161dc4a308fad82658551c38848815c8199ae42d2e6af16bdc272b1b6513cbe90000000000000000000000000000000013a2987c8eec7ff55cb3cd36058beabe1021bcdad80561ca702f8147ce9b3a2d756df41595044ccc8df7c21651b566e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001485fed6024ee50f26b05f86f061d50872430f5a88457aa187b57a5d3b7cb0dd8efee006db375d5c1c70bdb213b8d05b0000000000000000000000000000000002f4e7652dde9da8c6bd37b9603bbdcdde0f2de628fcc133d51df5b396a5512720ea1884b4f98bde5a343296a80cb60c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103cfcfe3d9e929f40ebf81f329dc63c1a8117c93f18e060c80c68e88cca715b8621e6f864f79231eded1921ae04c602000000000000000000000000000000001398c29a1a8585f6d308f99d3a56acb2eabe6736cf348edbcd03676f6ac3976325afc2a3639ffe7079b42ebeb88a222e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001141d80481f45582d4d1be602d0a065e2bb1e93619fad6ed9fc643560c8fde3af9c01ffb6a461a1931ffd0ef816d74320000000000000000000000000000000000a838f1b5718d5b8de8b6accd1b49c920261992c9c82dce8d99c02a3289bf9cad37fd458c5574334190c432ec557dd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007281a214ba7e92b4c9d76b5c048eac4c970cae5190a81938983256b9506c9d3dbaf81fcd90604120e9d743df86d60600000000000000000000000000000000120558c4998f5c07d64a6686f18122bfdf873e1f97b13133ee8bd7264594c17babb4f0f270d21a2eb6916d5f65c85d1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001902af0399fc9bb169c1a64925f6d1bb2e5b54ec8a32efd47e31b1e639ad440ac6d3a43265f47b66bdb75f960b2e099b000000000000000000000000000000000c77c24dd3969b03d68e04e6978a7fd5d1b03f2cb0001ec1947d8edc373c2655b69e342d46300f888f09b561368dca1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079235d06a7efc54cf53d9042841adff4bea22823b55531ef51b14acb6e58ee25c80107979b2fcb0bc22c8fc9d10a58b0000000000000000000000000000000005fb88b4a80d56c78c2e46218511a37108fb31e9fa9dc8eb3e7cd5c559a18bc7a7c35b83a9cc9358297870b43af0103f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008bf4293d4148ddc8c80aec8b512ab6d285588837b381195b21d8d09f3cace7cb3b2532d5bf1cd97c2a18a0475d6be99000000000000000000000000000000000ef0ce84181c1834f52bbdfd409f838ef70710f7c31db946b8f825648505bf08a57dce5dcf541cfb67b987c22861bab11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a1a1fa2095db1891e3ade6deb3cb8c1458f09dada8d02dda37790d3408d1a3f3b646be4c571babffb52e4fca4ad3ef00000000000000000000000000000000027fe5d22981bf45dd6d072c46961633f66f3eec09df47e7875893cef22a3384efc76b7410c1dd127d0a4356cf4517031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e2e9a83d178dcbd9af498f243f89e00e073f49cb041a9305a168f54da1efabc486c020ebbbc2ac00ae0274c19761810000000000000000000000000000000015ef2ad8ce539d04189915f8e8418dcda616e4d65056842f72caff3dce98b0d975737b4dd7f9474405f61173dbf781101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e42f269dac1e170500cecc68c902529704f8337148174509f18565645f8aa59b87ef772d7bd702a6b0cc38c28169311000000000000000000000000000000000d682c2c1f0ce5712163cf9c087ad4a72a2fe4530afa372ee9c58b8471aecef445b30da39109d7351c5d69dc1d2504811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1f5f8de755a26646002182a1135511cd2f231a675d83248efbd216e722a5b353e543b55e3aa25f6f424c11cd749c75000000000000000000000000000000000a72db2586ae36f2bf9fc5c0028fd8a2c8542b87ac6523b200ca9191b565d43c013f48faf2212e4a1b515c0f0d140a811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a2138c81bfb8d55a7a743fe280eadb25587c046dd693b0253dc9fa12d4e840f4655f6a1228ec5e6d21c975d6e322e200000000000000000000000000000000103ac8246743940ac842659972e5feddb992c09a1a39d12b89e8f05d8b0907427aca7dc03cc826a70352b572d3974c861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012188eac38d09f7d8f1111ed2032667266178cd9d1d97874f01574b724dc5e212cafeab63938a7e1b976d8c437229dc100000000000000000000000000000000184a53da6e59898f7a942e1077bf4999780391c774d457d0c65b8071330f4ab42438cba935979646b2c7e58c5250ccfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063a405105eb730478280bb4c12d3daf56b5ade5133e11eaaaaf995004fa83b49bd06fd1218f8b69a9c9e55fb9038af8000000000000000000000000000000001591ef398b9dbf06715b53a26c5532728ba4dfa41cd89ac257392b30932e8059f5281e40076a83ed640210524447306e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e7f44081243d8574d7ce0529330ac1e5602de5be468162c85d224daa7f2a0c12cf179cdd0521bd80299045adb4076e000000000000000000000000000000000844f3ff8ddcee8a3b83dff1660bff7c964379980bd90dc057c737ca4f0f5915948acbb308ef5448a9a43e3307fd0a901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123333eb0987e94ec732a461c9a55a244d0c4ced073d95ea9e5644fcc6e55130f4d13a900d7c7e82c03df624a12890d50000000000000000000000000000000004c3c4854c8b97d82fb223815d0f858369cd06cfd0c85ae38ce4caaaa1689835f0cff7b41de3b09535051c2e6a15eab51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7c1e8de4c1ba3950a57975e03655d0aafc284611daa777e4d7d39c97556f3d3a2c1e6549d48a9d00214417272da524000000000000000000000000000000000f8f75d64939dcc3b98f9e366bc55a4602e0a862283765b60a83079fdfbdb2e13f7eb5632d64db8b08d529cd554ad5591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000acd6ab8d657773ca289c10046a4f9733582ea140e165562753dc7f0bc088eb5e01282f3afbcbda64f498f85baffbb0f0000000000000000000000000000000019faee6f734069450af8b8c1dda24e967d35c662503bbe982494710c5afa830828646db550f61a4002f579ece55e3cc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d00ac49563805b0c642452d957763348a6a8d4705eca327e1a2e76f87d5c841a0ce282502d4574e5fe584098dcd44a000000000000000000000000000000000bc2bb11026c365e21d4cbad7975021c93a4bc696233795267ce7ab84edef7dc8c2f79663b9b1b88a36fde37187758af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001568b8cd4a1ac261b765576fbe33058f734ce17d9850bef78592540c10311509b486715b0d55971bda1ba0993a410ebb0000000000000000000000000000000004eb6c3e030d791dee4c786f1a607f5b3cd9ff1c448f1b1fe1b880031a833f7138e7caf8cbe4f5ea083b8bd00f6188c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000223df77eef43b0956cb14076e38526531449896a5da8320c290bfb448b0c40dc18d242bf184f658018487e26a70c0cf0000000000000000000000000000000012d38c364fa8b787ab2ca2de82962e3f81b67895ecd273b6d63ea88abe7d6f56d45b09da74b959a8467e87767a95f7041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000349f0884e725291bc3518bfa6d5802cafd1c905cac0d00cd587fe6be7cc2d58fac49e28bdc8a5dc5f3d4e59c04dd790000000000000000000000000000000012413d2475d98108523212b8ae74bffff236d7d980d7d07b1711dc9edf8bc7234a61243fe0c48626444888383ce4a10a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167677937ba9898b0848c9329b0f442b00896bdcf38f1a65023edbe2278d1d47f06bb9ece56aee655eed2731a8f1f8f3000000000000000000000000000000000618c1438f46432b58cfa042bdb535b69bfae91716d05558297f99a9b22e84cf8249909a10d98450867123b743faac7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060b287e2a5b1aca8df91d805cbcf73a790b41084728c1284e439787db2993c3a9981ac2dd1a7f93c3e1de5b3c2a6ba30000000000000000000000000000000005bab38e0ee20d088db20287def31185572bfaa5db4d7b5f015017e32b8df549df5661c418618d3cd6ebd44888841cb91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057328067132bd75a551f6108da018bc2bebc7789d77ff754e6bf9f5609bebbbb56b7482751b6cb5abeaa9d507e5930a0000000000000000000000000000000001778e80c8ff9647bdc187b257c00e34d7a183f2174fcbc38501b3b6a3651681ba98af88c81c1716941a0d7e80bb4e541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d920dee21d3e44d6d27bd14c41f49ebf7fa3dfd136e7b7feee5ee9bf43ae9797a6b3ff290b7a3e074c6ed850819f21000000000000000000000000000000000b6cdb238b8a3d9fbfc814830d7ce10ea71f49094367acfc2693ffa3637c847d745c42d176fff8f03c679f73d6ae4d2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001003e84593ff63e4c4b7a0de75439bb38afcabe5c6b9a087e737ef4cb1e8f05956cfa48137d1f26d3a3b555c75ffbb780000000000000000000000000000000000d7f19210a5ffa6926f46d492be60abd160741339e549572c3ea787ded63b53d62b8904e162d19fc0ff962badd6b8a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077470cd0e716a383ead5186625c3ad47309ac77e08654810feff787884d0e4c414b094c2c77f6e08b04c7c5280301f90000000000000000000000000000000013b114a6459a4f33ea4813d5dd5b753ccf418014cc718652bf1d574a80146fa3b26995c8c67673799c01bb45712703121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006508ad991570185f389409fbbfaf619103744729cf158da3b8995b5f8bf302bc0b8c137a94f95ec7c3ee29f3a5024710000000000000000000000000000000006737a7af173d3fdc226327b5df0d5c86bbc498527c524f454956ae25fa8d134de0dbaadc9a40880fc3a7bcee0a27d931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6c907cd3abacf79edc6d152965b445897929eb5384f803d38d1dc260dc2298ab764d48f29d8f5cd85a639543d17b82000000000000000000000000000000000cd123e96c9aac3fc82fdd4dfcc05151ec04b755e8e52111c664c9f4b2998d6eef2142e41f3d04f4e3441d28660e75e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc6905c971c0df26c7a82517acc21b117dd2204bc5612ec157bc819d421e394fd62f13a00c19d4880ef0572bd25e06d00000000000000000000000000000000001b2e3f750043fe10d8e1781e1cd677f405db3cb47648cf855cfa21bf9f1d80bde6e31e8a333d2da89af25c5a00e1341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6d3b2bfefa8b83519bb7caaa5841b7522dad456a6da16d046a33575cb30ceae709d55fd758861fa4eb6f2d517ec81b000000000000000000000000000000000fe252ec76ccbb598e5848685d048472e8f68d5a55e67b57ae52e9917fc5b3c68cde435106dd1f5064c2caacbe0ecdcd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d9604c6ca1948e4d15d2f4d1e6de191a6ccf88264c6a69fc1473b3502cc64cbbd3c0de6e805e4e1d2f3ec884bcab9e0000000000000000000000000000000015f249778f004b62f7f432a2dd931752195885a6726acfa9af5211c5f5710a4a73b6d373abf7d2136b7481d827a211f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002410d56330caadfd9186a95d184216d19e9bf94a61534431677052d1bdf5b8b9b2d55a2a5a18459c87ef1b8049dbb8c0000000000000000000000000000000004315b3363b9e6ccb12152bc00d3f9dfc138ca538a9149c72ee6ea367e46a95d78822b20d39b50305032049e78533d9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016434f8c752791545b985212bfa0b213548902a6c1c996f935103216507a8e432eb46a803d29642666fe0a99674757970000000000000000000000000000000019c38ecb62e6917600f7c8381dfea444a46391353b3628aa3a33145bfa0f1fc6c50ae7efca19f160a36f3dcffbc6dc631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e66925725fbb5285d52a2c09687620419e3baa74cc2519cb1c881d6a1b1ff191bc22542f3cc3fc55af14fc5714b2c300000000000000000000000000000000184196315e745ba4756b8cd3d53e3ea936ed4e8ee47ca336dabdf0074356114eedd1730a5ca8a7f3eb0444ed812d9b161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef485978e910ebe2ee8500da07aa5696656b1984a2e8702c63493201053a3871511a38b9d3b0a4f009cd2c6a46358f000000000000000000000000000000000117d0ffac855b6beea17a726a7fd66d90f1d35e59475b139007f4e83ae0735e91d130b61f81923d0059e8a9286ff7dcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006185d1ad02785a38ec700c7aa1787670794850a54ae1e144231599fbb430a8999e4f00e892bfde88d8e91cd0103f3040000000000000000000000000000000014c1f6f5018e6b886756141a08a8cc9aaca478a8292ce59be95115e20298fa3a8a5ad4436a6b9a8feb801008243139421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055395a15c61502e8cf676187a8ee4c07a9002d2d3d1a6c5bd0cf8e64a7e7a9a10f69a4f13275afe5a901d637a6bc9cd000000000000000000000000000000000d310857bf3b7e0cc904641386804535fe1cad339b8576d0ec3035d92c7d2cfb995c9696a83367b48e2345b5c273797a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071f4537b0eaae5887c00bfb0995a3169a0fcc9ad571d28a7a5c4fd5cb0e231a20c07c598ef92ceee6a84561dc86816900000000000000000000000000000000055597bdd0f41005a99b4ddd9f8d5fb8d7e353df90d4c6b7f906d675515b1dd5ab17f3afaa6422bb522cedd9f2fb33401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186a7c38f05c5acf62b2372769669117bec525d8d89359f52b5a2db0806242283cf854b1c314b8dc1d8dcc58bdc91fb4000000000000000000000000000000000c930cc6a1aa4e91f5ab2e0447613a9b69b0384d8fe577b7c34dd1055d0e89d5181adb587c6bfaf64f265d8740396ccd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a3b0c0475a29b42ac358bfd7b3ea674e1a9f204ed1e92f908e5a18715c7d4a71bac04b7b3e0a2317cadbad77afff1c00000000000000000000000000000000085b6d81a1d1a4db97bfe2bbefa3d4e05dc3b7deb4cf975742129a8c33aacd41c5903191ea930af0922f4990d2fe90431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000708108158ac9e8e99b248b69d2f9c7bffa52672d3be6e2a1c5ed8ab55c79c04c74f2a9509b094192a17cb718d0ad7d700000000000000000000000000000000135a82ab3802f57c05d908e1293e5361ea425be2ecadd8ae851b3bfcfe09443c8d0209590a6b32d11bbcffdbdd89ce7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009aee69955170db9d4285cfcedbc3d35b61459a9b3868cbcb6b8eb469e9265a3c1adcb9f68a65ded00f13c4a49675e57000000000000000000000000000000000f080eccd4c199c88316c228446614b941d73b50bc2faf1fe9f794dc72726c54e9406553cae05234ab085bf2bd1bfb9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000db63520c96251283688f97852bae7538e9c762f4992c28029b0d1f5941a92e70906d49e27c64ca69c61abb9d37659700000000000000000000000000000000094f43d16d02ab68e85d49986d4f0a3804bed0f22b45ca9405f9eefeaaba038c6964f693f0552c2f26b87c1908307b4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016034a8d5ae1cb7252c0587b8819e0dd722bedbf1561613f3fc1407a61ac3cf50aa81f4031d9e837ac3e5f535dbbf04700000000000000000000000000000000037b8bedcef2e40b81f4082d9e83489f6caaadae825f9ecbba3d7a61fcca22ba96907ef3e87a60820832e9a18c0da3ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109fe6c5d1c991f5f1ecd97466c9b6dfc361a0983dd0b303c356d43cb4db39f0b909077547bfab0641c93f8f3904f77300000000000000000000000000000000154c4f05332de6b79d2040ac20fe9faa5b7bbca05705f73caeebaf832e26c85d30a9b5da435e4159e7b303e1cf2322771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019c50e2ce57936daea1a0e8186849418ee2364ae2bef81007240431c1697aae7e349d226ab9f95ab2d3d3adb32a67a500000000000000000000000000000000006e7c4c17e9495bd021edef9f1206878b7fb37b2b7dc7cea3ddae80b116d816221fc25ab5ee9ebc65cea02c7ff5d7fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001732df8b8a8196dc1bc35c41fe2e7b6ad40b17abc41a2717515a27415484942e2263508fe70642b6d396ef915b0bcd10000000000000000000000000000000008627c7a84e3e7366a966cdb7859097e4d5ab032b37692215cce3d6646c294b47182d0c31a8bee1acf9b2b305d19da121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192e9a49506cda4d13736550a386f87ec34b9caec5927f6e09eece0b3db7c72abbb417645f8e02de71264c480627b32300000000000000000000000000000000143785a4f6811869bec77494c27658d094c0f1a9c1e74ef5513c86599e2a077794cf01536c2e1b0b96117870c99bd0861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136219ec387717e54517cd80a25cf440ca2223204e023759ce5a3c2c7245dd43103f764004a8b589fa2ce0cdc55526ec00000000000000000000000000000000193e80c9af397fd2ae8b48318fa1a15a251396fac90a993a4c78afeef1c7c91c19f3ab8874a92ef4caa0df87204a43eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c46d10e2990e076de07ddcd7776eddb53147265f8ed574ba63cf6f2950416df58973aa298d501188bd880bc50a7f2f0000000000000000000000000000000012f0fb44ba0ffd24109ce2013d4ca1431df5a8b58eaa264ba30fe06e9cb2141c663335a3074fd92fea3d0445e235699e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d7ba01ee498456bbac6e75709cdb8a1d0921041dac84e446f7acb821e2cecbe2f3d5cff9dca64484e097bfc1020f69000000000000000000000000000000001426579234531acba2f0a14fbfd730ba2f470d6d2009427600df5e271be5bb9a95483b2418e09ecb6fac9ec994db8b941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001587d7de5776f6c3154035af574c25a1238078940de8380f5abcb4dd0716b3edcac9ff5db3cde96adfe629b24c3c4b340000000000000000000000000000000004cf46db82cc7080741e33eb4e14e905ff2b750535a8d43657fbf0f936ec038f0b239a5c620718bcfed7dcd18ee47a3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061325b172ba4ad7eb20ce1a2eb2ca242da9522f9f8ca0617061166e27d19884f10304fe098534e941846d8d0e510f6d000000000000000000000000000000001160fdb0f63dd20763d50f46cab5c4ff1121870b6b105677cbc1f6b0d31fafab20289a9f789ec950bf92951240516daa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001620f4678c14242e3cb398147789c73739fcdcf90716e9925b21507ffb3fc8708e043d216c80d851d126e76eb3b4f6db00000000000000000000000000000000149880a1d8b2caa34ec2150bd71f6e145087be0bb436f7d57e65f674e75f91f5bc0ba1ed3a1d0eef4ded9345f6dc58391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f770e891788042e8da8e0d6a28adeb78fe42cc8d80b541a05feff27a5b162d053c40e9fc1c558064a81f449ad7218c700000000000000000000000000000000139efce42001c1105b2bb301c75a26e1d093dc557dc556102dbc0c12e7b584363f3a708fc93ee5eeea47efce748072631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d42870b296eede640e36befd6a56762c5528ecbacab1d26f828ff3d9a4199e1aadf4989ee9fd928d378448006c3ec100000000000000000000000000000000139f0adff5e9377baf84913788839acef8517119edacba63c62d47fd1a4cee06c3b31c76f35c3d4999771005147971271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e62e7f7d3bc805958decb4be93f7b8e1c323eb4bda22d988e6b623788440940b806c605b033d380c085a7a54130daa00000000000000000000000000000000151688efdff162f00825090f0e6962aff6956e0fce11b3c5f50619d4a10ff6375e8e59f8292047ad5385634b975d7e431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5d6a32934cc9fe2b75ece02a52f13f4d2bddec07ebf0bd87e6f9bc3768572fed736733d339890b4cfca046d7e3b9700000000000000000000000000000000017d2617cbcf3029b3a024e5f87192253a85b05cf658334d76b9b7afb555169523f0ab2015b75c6d50b0ba627f98b6d541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000614a92748905741006e49e144e9d07a55fbd50f0e6105d513a1acfcaad203f5fbfd2ae1ad0c7967d8f0a0f092263e040000000000000000000000000000000014684a9ad9ba0dcc46d95b6a853f0552cc195e78a294b5047f90d4532fc3ef09846fe4618d7cab5168dff1bc1f83e3831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec2b1d68581186abc5e3a0a1a4a3500c3e2387b7d206cfeca37cb742f52678a9fb7028d613451464d544860ec45b4e0000000000000000000000000000000001053a980b671f45b5066e7dd65627e247daff1e4e9a111b549e050a4bf55c690540d6f5c686a0d10217b57f02e752e381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d6f0d6c0a2b1330dc14788b0da2f9fec098b85e26256ec42269d28c297ce563b9c6089c18d39cf60631d62cc213d6d0000000000000000000000000000000009a939af76fece30c8d47f45831ed5358800fdf1bd5c765e79921bea3fcadcdd035fae86011db453cc5927e1a0a292611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086d48d0dfd38218caac55b596c5a5502647e0dc64a22fbf1b56cf420970c5b457501a3beb0e4f5398bea461626eb2140000000000000000000000000000000002719797d6689956c940420e6c66c2e77470f2f396f2fbffe32a6f7a3178c7f9edf29d7918d3512d6ece682c0c5472fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c22ac560d253e6f212a74f88484a03536dd363040956e72ee9341228fabc4263971b08b137faf1cebf665f72d9190a0000000000000000000000000000000003d93daba595e4885ed55d0e809e062afe4cffc654e1c0296d622a752b225bd2fd951624a90a0b055e840dbaeea1328c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071228a1bb21f492b8e80397cb9a03bfa897cf24314f5e39195a3f90fb2d4c09fb9f55e6262fd8939eabbc3333f1e8380000000000000000000000000000000017e3dec06c00211c754fb628de5d7df7ceae6243ca8b535ac619acd93dc40f1c1be2ba8c92ce991899a2ccf1695a9a911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001872601b4212fa01d443b335e6244982675e842826e875a72f7d0405549da22e46f728cb35ba073f9eecee5b9caabcc2000000000000000000000000000000000c2afe425e3ddb4f2d41921f792c9edb86296990bb1d5b0d84e70bd26aae306f46443f7a7ee6d8fbdb807b6ceae288371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000028902d7eff252eeb7ebbf4de3a481a5cdff5d36541581439d6701750c3eebca45ed3e0bb4d255050e1f9c1d5f1b26f000000000000000000000000000000000feab30d6f386103e1e01dabe91cfc8ab8aa82f395a7f86d72b91eda38436855f5add9cdd564fb60eea78a1fa1c033be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188fae8df2b9fbd86ed21e2e2f90be5886ec5db6c238d52870f406066216b0b4b5658eafe7c9e265a9a936c0894a351500000000000000000000000000000000119dad0641daab1c23ba99228bc38c16f8c09a656340c720f502918b8e59ea1da7027f0546b3e6fb48fcf4815270e37c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147d6d7524ae2184ac718145b0149b9d72347596eb940ce7cca9476c674641062f1d55128c676ae52a70d3b07172fdd1000000000000000000000000000000000f3aad8a3659d0167de805aa7ead7680648465e0093fa2f96a772001a2d7551c4c4c2c4ee0c6b1e6c5a52a710ba03b631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f374e7e268f5beb5ecb001073c7bcd5212c692a910894e26901d268b4531fa49f802c15eaa987bcd5aec88b27defe5f000000000000000000000000000000001171102b3eef34a3938b40443051417dd8e2cca86b0101d24a5f1e6b51876831aa7b2752dd4e5eedb2d0c98e2734a7321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3d92577fb2d1f18f8d7c0f8941665b5128b05ae773cdebab3bc889452af61c6cc89204ff65f8ec2e5aaeaba336d9690000000000000000000000000000000016b4e5f95ae838789c411d2bcfba7d17732cf2bdd96e7ff567b8ef94b5d7b80f59b0cb35e874c869a48d8428a99ce37f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001499285a8d67cae5e1b71f6f4a642893475c4123f1357c5228297f7f1e0533449f81e2aa596f01271dfb8de7f02aeb0e0000000000000000000000000000000015b504d899a1b02d790c2f646f15e97e20b6252ba6a56fb49735dde41a7b33c6933dd4ccdf4d02ec5dd68389bc79f8341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6a79aaf9a049991b7b776ece59f7917eb9c50e20bb533737baae8d5881964915b5ebf5582bae471ed33fa3db51254400000000000000000000000000000000085a8e1c6290cf6069ae662474fa006aa3f87a3838eb2162edc8fa7e2f8595716cb730a3eacc80f4ce323ee2968713381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd2f004ed843b76cd7a291aebb04e3b266d91d3d1ab8e287b9961a54f97b00b87e419f97a22c0e56c32259ca243272900000000000000000000000000000000161e8e82f06d704b6821522b64a5fc759325471ae98208b313b42eb9a6485979fd0da35ad221d6acfde9a15f9824d3701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100951df5fda90b78c6bf2a8a27d4e2fbe1ca0294644afd99952f10234f159b74f83c7f51aae7d7386ea4eae076a5ad5000000000000000000000000000000000efa6bab032a516ea6a08b2931dca5db86b927cd87e25ca71173adb3e0c322ec5ace76129812ec4d2c0c892696e288091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000541fa79af313a4575535bd00b61ee5b1c6d7cae431856017f8eecb925f1bb6e8f56c25a29f3b483d43f30c37cf1f73200000000000000000000000000000000004ad6fcd8965a58c77b3ebc5f654fc8c7719eb562d543cf75b9f5abc1d1b3f9f37a931b5994eceea3d869584d57f69a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018193081f522f57261ee8e93961c791b2f93cbc0d511536b76312413f7f070cf07f6280a030862d16945b80c52176ee4000000000000000000000000000000000cf169151eceac29983fdc0b1c42bef19dd657b9a3c6b4450fe71b29b9616ec6cbf9841b3dbd1b540f8aff3759e0d1e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006eb192b75d41ae7a0447975d343b3797e8876c6386fd6e13ec6d7131bb7ec400b5321723b369c41062c1cc2a04e3d55000000000000000000000000000000001037ba5338cb2185724e4d26d3230616f4cab4aa7da473084b1b37f3c171fc3cdb18e4e2fdff012b86b0c2369adf0e841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e1682c9bf0907c46cc0a2120f2e494dd9fcdc8e0814284927fe404d5334eb2f584331663e3bad863328c353a66a35d00000000000000000000000000000000189209dc3262e36f42060b6687b9dc3b092362a80ea3783996a12044c564744bc5fff921df27e95ab61750c8a238567e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbb667a785537d6e6d906802f24e85bf4afd634c31ea5e3de45d5d31dfdaad327463a434c3c8c56b2fc3e916cd00f0f00000000000000000000000000000000181f4ffa345991cd52bba3850eeb88af2940a8ba834cf49186bc278eaa4ef63fd98df70e7e9c347d79cc3a62dbd6c6621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4f333ab73bc9a758dac7d1b2e69471616a7c76b37dbf3bec9e4845069dc5c2f7d54fb126e3b9d61e0e2f29918cbc5c000000000000000000000000000000001298abe5d5f47c4dff791a318c47701ef373c76aa2b1ec4e6eecca589fcfeda05b167fb4f1618e51daf104765faa10f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db516539454b7b9040d44bd0420464a0174c9dd6a992767a8106823329f4b63c580b13cdc3cc77bd680fcb83228a96600000000000000000000000000000000112fd05917627d464a4cb60dd3991d7b472adb6ee14528a36e3f0af680be72b526452ff6bda647d310fa5c620b0744cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000532e78ec3dafb9f957e42f9c49dba5c821a076af4e337d947f17a1756b12cf144850b2d9a27f4c4126bc2b7d64a844d00000000000000000000000000000000145ce8a6318ac9d2f074f4e1b5e8c54d869b9b35398561a09df89805520d94b7a04b38ca98b6fb88dddafc153837d3351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000706a516cd06e73076e228b4c2fb036449611fa4307f6bebd0975c1b722968f703ae431187d1a5f755eff43f8b41cf740000000000000000000000000000000017938e6fd63059c5d6409184a54776aa789c524a0b1afbcc26b6065d3ea4662412d125348c3676a6ac43e7e4d03718c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7e3c36698faa1c31b68ad1ec22f51f08b658901cf49976ba7a6158e958a11b30033c82a30181e36812acd6a5d3e9340000000000000000000000000000000009953f382ec63c6e7e27c5255a859f91135411bb4c7bbe172adc619415f32bec0ce7b6c5f499d80220ed5060079a92ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c98fe321e413395e57fc6e3fdc5e8a9c1cb632e347b272b4866f7eb42da714370a97e7897c8622a0226b279f6a426d00000000000000000000000000000000004c975bd7d5723fa35d63d003c90cf3eaf1aad036a307b6d2959c99deb850516d2f920a176c3962355a72a88e9d4fc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eff3e33676d0ebeed03add1476ce79ade9ef81fbfa5af0b1a5f3d2ce53a40440a2cfbb8f6810856e46deb01a119c4b20000000000000000000000000000000011e5b0618ec54c2692c9141c856db4949ba347041ff318dbd15707afc682144afa088594975d2049e994ec93ca8ce5811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170dcbe4c867bbec261e69e4d1135e4a6ab521d6aec9f993ecd5e3d17315302a16f99eb036851957184c56bb49ac97d3000000000000000000000000000000000ead6bbddb0cb90c3312cd1b92ea1bffabac5030e7be5c6f4b7102d05847f841c0fcfaf6b53907e65c832946586eb75f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164c4b4acc15075d253e298bf0fa64f664a0c6639db88f0eafab3ca585510e6b54949e4be4ead8d4e552e9156a4fa878000000000000000000000000000000000f9c290172c6c2ea7cabcc7778698c908646444e975d28f03638999df8193e378b9e7b0c346ac2bab44e47c63d5fb8011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b6fc27accf54ceb8326e0e99aa7ee5ff9209f8f6ef34885f49063aff5fc612d82007c51d89b1100c752f8239c09af10000000000000000000000000000000017261bec4802fd4b4ac34e6a06cdf591a063dc4dc247f84ac51fecd79cd7a2fd669b740373fa0c216e6661a023da7aa01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a8c4f6eda083387d892b14c32150f4a4714bdbb12f847a410e70dfbe74908cfc8d615b5a0717855c48a32af7ad140f000000000000000000000000000000000cd2580f0196192617029f8681ae951aa2c095d913d301da1c82b048b05d139dfcbc7d466d726ffa448eb23631f4a9f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd156f3e0828f92f52581a07a065d8d85889ded1b0b738cbad08f28882e518b93e3ac0f924276c6818c88826d3ba658000000000000000000000000000000000b1e4d0dafe9596cae9536cfcce7e523db522234cecccdcea9bd579e111bbb907d7d831f0de7e0005b48e7fe001a08c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e1792bbd7dbb479ee2aec11e9ed0b3121942bb82526a02200a31c13737b6dc1ae05a295d7db398f4ed6c3115aead3b00000000000000000000000000000000005663f797aa9268b36557b39de35c259ee0c7af49d7c2b60f1e4f58aca95e2f3e73d9eab0e9983cae7e9b6359e2fd081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e5d6c0936574a108ca584098e01f72dd5160a68fdab44ca24f23427b74039956e1da01a9601decb9fac8b70d2a42e9000000000000000000000000000000000b43c96316a2902197d35c9da42a5844dcdf32e117ea4cdbb43b80df488acd111efc7b1cc7bbf68427685d92d40351ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7c35ce21d2e878c5d1ae4213746329d05550770fac80ed5a8dbb46f54b77908230ab9e9067c88586fdbdfcb5fff55b000000000000000000000000000000000c6dd2a68e6a80ee049f2c3d3e60ce9f72db75e05f4c4b2c514874850f55ddbf4d62442cffb35042c1f8c554574d32291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004169e872b20813112ffad59cb043819c1c780d3e160de7cf12ca339a4be912c4c39b6a514ce876c58a69d4bd8b7c8b600000000000000000000000000000000096b300c0007bbacab9195df89d273582f8295374fe81fc73342733bdcd42a1047f2adcaa7a7c8c2c634b3cfb9e4cea31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1b6282c3b03c52e646cd8c2269acf48e06658ad8b10ffb925f21ce47650795303d0827578bda26b89fb88d0fb7cba6000000000000000000000000000000000b5ba78d0c00070bb5bd2f278c51b496a14bc571da8e232f0a386b4d7abb52761c3d50798d9280c77e7e8ab8fb9bb9d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112673a3caa7f0e6845a24f85c41977759d5a4d5f06d50f1f501b89d349fa92b353b94943d8d4ce4f7418f789269628d0000000000000000000000000000000015ab56834fac5bb3d374e0b57783c5cae1020ff08440a73c64ef15fe0fb6ab08137b3b224aa9bb3b3ec450faea41c1771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156c3e7b78c5aace14d7ee4071f5f91d1f6bc0ab2627158b4df4744a5cf1f9afdfbbbb4b446b572da73530d6a4f9517300000000000000000000000000000000042adfb740b021d90d6e80ee6be60c4301aa65ac8d66e91226e23e849d757c1967d3451d4f08a394f0e0dd82680adb961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006fc3e013b44b75671f10fdece84ef84dd45721bc2d558a733158b70d44a49a9133521096d8ee99710f4cc403662f8220000000000000000000000000000000009159c4fe16ade0b58c8c8cfe91ee564d98c5a126ac64f1f92f7e1225c43233f20367b9d2d885c02ac11d1ed8b60e5d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004c4c42d227ccd9c0c745d9103f3592796f0a1df5da7d07b5daa1b4097a3f8e1db6284f38558afa06a8129850e8285400000000000000000000000000000000041518ed4f5607fd9a335cebac12922634c79ffa21fbfadbe4fd86066ed29fb5c4fba4c26c4aa5602e7943b4e2dd37ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144f7939bd3a503e123bab0aecb3fe86acf9309431e48f63726ae11cdb121dfb7cd4df23dbdc388e48b13694404c5a7700000000000000000000000000000000188ecb65dae4940be167fb649d14787d0ba0ba0b86199815e850f7a6ebae9a1b25c14e8ce47754944d1f752c43d987bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f9a123ffe84d1caae6a752aa6f6faa458ae5285a2cdf3950996ed3044db942732402de77f4300319eab84a924a4fd20000000000000000000000000000000009b693431e49923472e1e2e40f82674b293591bc3c76f20cc0413baf454ca9007ceceac172336c0a2794bc3c6cd8db851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097ec2280bb1506234a181e08e1a9f0344bdd20e0d008b622b4e08a208f673661d090dcc314d1948968771271f4a96c1000000000000000000000000000000001385f6160b4f3106b370758c3d5472fd561813b18c3bc9abfc78ec69f67d73f2954d2499ca1329ffc46b5e98986a50911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000804e5c84bf37f9269e630da289e5ff50e77764ad19b43d5ec57c4e3b1d12c17e1fcbb64d923c172fbb4f1097a955eab0000000000000000000000000000000004cc3569eca32f83c7cbc71312774662a9a0ee3a99b12f0633869198c14b950a200571a2973c4409e3423cd67c2b91b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001afcb56c1690fc1cf71191e275717d688476d90b22143677237cab9d6b6ffeef3823a7e525c981662b768d59a9c468700000000000000000000000000000000083af25a46953881dea78dc73005c233979bcd1c25d3f07dbbb128b78043ce6274a79c927f241ae682f81ce63cdca5711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007defe49418f28f904abed1c8866efbd7595065b8f28469bed7c493d6d2f6e6e8f593be20cbe4b29a8bedf2cf08646b10000000000000000000000000000000014649fba9d2f95c74c9b22b97351578afde9aee8bd3716c9357b81a0e3a36aca6deb9f35edd66eb904d4d044c1c2cf691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4dae9a9fe8220f95551e919ea6d714d7cb6dd73e33cfac9f15c7e73f94016e5b1aed07b50d29eb475dd7221d431a7c000000000000000000000000000000000cccaf42bbc200f7c6c3bc4efdf138325919756b36103e120e9a8b2ac5c3ec42d981bea4649cb09766ec8f719c056a1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1e1cdb155093aacf3a1afd711cad4c694d63674b0cd7842df6884095f7933f8492592cc042649ea70cd91445368ecf0000000000000000000000000000000001eef0fb70f777deecec044a998fb79a620b30fed52891f96605685650c7745f5d6c522d99afba98cc6cbbd50f5297eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019fd0196ac7b4de4919e66687bc86963e1770e9db4e578eeb2b283a6030817c45cc90dadaf70e19daa459da36bb9e24d000000000000000000000000000000000afe1fb7a2dce7ca9fa2d6f349241e8fb2ac2a712a8aff1e15940cc01cbff3e3d7bac5cb1b93fe0255ef702758a085711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c95c17593e2160473962f6775504a1992bfca655ce6e207c9c40295889f6bd3988bbb15451af79b27306f57a828cf07000000000000000000000000000000001064e5e187c356ee674158e46fcd03da8ab9891d471a443034f32c003a53ac81de9aa0adc71806ac308b3ba6fd2383501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183db9a3fd140a49ab53704d2661117bc60305410e7c088f753e35a659de8e0aedad09b3f3b1732956adec4859c4dd1d0000000000000000000000000000000013ca5511351cbb712df2c5d8895a60e02b2c28af39b1647a3e56c1b6378603b1811d07cac68e1cdde03afe85e0ea99541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1b7992ea089729bf7a5224e64ad737dabfb789eee95ff82bd1356b6c765548d5879585d3b0330ed5071f218c705acb00000000000000000000000000000000114b963127ed55cd158c99daa1f921d2f7ea0a2f3a7d98da3a66d1738fa34dee72ce6bdc39c4213ed63acd9c803394e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029010c65975636648464c0828b47b4c3c4aa75b69d09e133eb1df2c4fa999c8302dd277bb1628f713ceaa0c8c9b3c6d00000000000000000000000000000000086b1ca94a9c80127bb6f243ec354a84f54fc3330c5b667ea9f12ebcdf2bc4fafbff8c78bf362ec2600f4b2e81d959851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3622314fcf0cc6723e1682538c5a65ad4d535e2fefb884aaa09ddad3bcae874ba4e5d290de75fec79a4be052d98cde0000000000000000000000000000000000a6e0aa2c47473a5a607f1d555af6ddc0fe2ac1ce824fdea32ac3a6008e9e103a5d140e651923dbf7c80ca9a8a07aa51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8d05724ab947b691e28ed8fa57601e666ca9283c1d05809a7622db9240dafc110b8fd35bd358a31983cf7398cbc7ee0000000000000000000000000000000008e0be0255149f195897bcd77f61fce2161458da965a81eb7861334fb6769977db0abbca42de61337dc88aa537db23771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e9035623a9b1823046a9e9bcf1981366926bab6d33b10bf3651023571846b7d09467c224c4f90b0cde13d092288022000000000000000000000000000000000f06f13456eebc2208172ac1f33c3d3e16a2499978ddf9cd9ad7633787a79a66c5a364df6b418b6526c95b620bff73301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001907e9bfcf7ad7867817f59b94202cba059d83c604ff0b0cd4f8cf32ab55143819850f95803be57ff55b699aee00c977000000000000000000000000000000001152f0fa26cd14b1c79fa79da9532e62ec2a3330d06e1661e4cff82c1b2e144673be00c0b3d867bc8979f2de839f7e001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cc878433c0dfa238222347ec16a05c7c068b6f5cf75f2945ab910d81c2f7afe6724e5ac8ac164f715741f70135e7720000000000000000000000000000000010ea0e52f574b667dcfb80863de1a1aa06925a5ca2f8257ee5ac064f49dcbacc79f9d964625ed6a201fc920f6e648d411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000648d4e19f5a8eb871a1b5314527316d97cb3b8184c6f22acdf6b9e57da17bfbcc5efb3c53a0dada168624ad9b1266b5000000000000000000000000000000000ecca5627aac4da54fac0c839ec430ef6b75635ba4a5832707eb156e45f5149524eea43561dbe8fd5229d710cbd5fdc31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000995e3042d9ae1a0b72c1f7c444b5db9fdad0db7fae649025f13a0e0d73d576e957fbbfed5cd8e03be363e9123cf7cee0000000000000000000000000000000019d3342291f41c7983ce2f253e84bff27ec965e393bd770963d5eb0333aa0878cf8b9c046177179ca963876ceedceec01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000874854849586769455fc679507906c1b0247ed4283936e319a287705463fe0a33c84d6c09a7ddba523b70c24c293fc20000000000000000000000000000000013389810197f7582850a08f30264f5da25d087154f2c2c0f5bd4643493801b94ee154bdb389c71f84d670e4a18034bfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7096dc6b04c380113f32a61cd77b6c0dc99be18e25e57e0aa6fc2e340948c4f2f46842143b90348226efdc7dd55ae70000000000000000000000000000000014d73304f950c062bfafb025174b841b0c16322fc7b1bf65b6a69b6a87ffb1c3d57312f8b17df51a9a006b851b0839741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011849a6f1fdf85ba3e01087f851f4bb445bbdb74f524b80bb2e4c76fcd211b88d8aebbd19f8551630daf3d4b1c265ea8000000000000000000000000000000000086d087527eed86c2725fa2887def15087a17eb87b619ac3fb334279b11acff2507324e775921101dd82d63d52976d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130374f11ea770df36dd18cb3831040edfd87b1aadd03366119adac1367d7ee5d758938866369db7918ee4a848da5cfc000000000000000000000000000000001577d8d05d586089f107aa9efa19e0adf19ec25f1ccac0747ce7a44727be111f7e1f56a547be8a2aad98892deed34a081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102389ec9650fe78e523e8d9b1fe4f3c3f065152c26ae40bcc63c960e2928138b48d977634ffd97527ba131a58b7f9ef00000000000000000000000000000000145317623c7bec3e7d80bf5c4a2f34d524e968baf6afce4106c07ade26f16501416fd83279a283d45666a59c4de7225a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ddfb47f525cdfe2dbf677b340cd1041c88c304adcf7a9c02e0a348ba18f5bd30adbb023671f5ec409da090fa5fba46d000000000000000000000000000000000a1242108cb0c57aefbec61fc8a620f1806503fe7d4b1a6a1c7168569a62f393567ec999a2be2c49f4d1cfdc732ad67c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018067831186a08baecea61bcccc34d3a61941c8eed8ec353942c4c8587d26d1726776f26367b56a6554adcda1d541e9400000000000000000000000000000000185b44c48e4f7a186cd98e498b1dbe879a04bcd3662d8617e1f7aaaf2296f35314bd7534e25de6f564b20e85f1f4d9b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002223eb133c8be9c294ce8585d5337f0211d3871cc0eafc1448343813da89dd8fd942509a650e7008d309bcba384fb0400000000000000000000000000000000004cdc07299325b20cf278441e48bf005f39178ee1fdf69e7d0ca792996b660211114ef633608d42718686eca33afeea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9264235969b3c5684d817a5c043a9f76546ed2d5ef358c2a0dec0edba67224a723b71d172f64fdca6c085a4dae0107000000000000000000000000000000001548654b9910a573304e1ccf34ccdf73f240c96a7e9ef46be1277926bea83d8fe8f81e8af3fcaca1adb47a6d1bc4062e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ca1e46ebc798e92445a0aadb05c4335e8dcc711a90977a180e919ec3a7dc73cb18b00756edcd5d095de23275f3d3b500000000000000000000000000000000046be4ffddd250a949ef5d9a8e3fb8b547a70efcf683578f242d11b848ae15bbff71038d066adc4053fde607bdb3b0881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011444ec9d095cac7f8f0b4cf320635d10577753f34fe56e76d5b28e84060996fbbb9cc55035b4b5c1bced7cb11313c44000000000000000000000000000000000991b1a37e95436018cbd0be6b068d4e6f802d782cad8751b463999e22e408f91d48777d4c31e2a63d09f943fb9473141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000135b47ce8d62d23dbcf43513499e997b50bce59906d94633374015ddeb74763f1c7f445ca4bbf48fdae56fb95fabdb6a00000000000000000000000000000000024a7c43135b5fbf2b987180a90a2ae9accbfa22d1cffcb582768d8b31bbc31cf7fe9a82fad5e4853effd2191eef94621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aebc6a46b961b7f06bce58c83cf5c2c8a82247b024d0458938abc6e22f0c58cefd109d1ed19f63b3fb9d038d0853061000000000000000000000000000000000ca8a05aa3466befaa77473f321621ccedbfb85e2fc1de8d91e1c68ff40155f9db2a53f566df2edd24085e65e47661551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3677f0d9917b8e7f0f940f0b2ee928ce15679f9db66277d64b8cbe64a4b65fcd61b8eef79b95212b165fc573d1eb370000000000000000000000000000000007485c772f91e69d5b8bbd4e081ee358189cddf53e37530063772abbce1994d61519e9bb5529b7b2d2b6c7e95d8f09881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9a2e2bafb08e4e3de3e0decf459531a63b66385450c242c1d18f469fd6bc54c98c2603eecb86434aaadef5974119de00000000000000000000000000000000024df245829b7cea913cc77edd7ed76316394276763d97075b70125c3f8ba19c5adb23f974d7ba548aa880210cbd68a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000581e32661155b9eefd8591c2e1fff3ac409d7ab9a7866d48c7fddaddd550ff23531a47161e5f0e03b123c395668f171000000000000000000000000000000001437d9f01a837dd478fe17c67a8cbddc62c94d65b99de9d462474115eb258eba7cf80dd99de4f763cebb97399d6e1fb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d4acd7bfa255fd826788c7deadba60c082d9120e7ab2d6e79a88a94b8f0c0d82b1d1fe51cb85fde889aa19adb3d28b0000000000000000000000000000000012b2d20a8e1ba660a537f9bf0dbc7ab53a72996d8ace255c8fba1a613b09abbe916ec444d2701b80ca39d09fff46adf31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f57b023f8be03965ec900852b73bab809d9674480030871744b1089ceb555cd40b0ab3a74b7c566b9eeab018455a40000000000000000000000000000000000efd21f0cfd87f6cb99da29ab03e518142c8ce8f7a46264d0437fae8a2358492ff0875c8c598556de5a877ad167e33401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f9676d650c0eedb68104b990fa0d6b89971a61c380714f20d36153237ae5e2757daf5badb50b214960f295161973a900000000000000000000000000000000120c6fd84cb97265da18a474267a9a7af1f4327f92b18b5d22b3cd6692ae5e1e92b0b82a2b7e817bbc3e162b64e991a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008f7015de3a56dcc09bb5e87e0b3a47dcbab73e0b3ec4e280375f5c1b820f175b360175edbf16d23f61cfcd33e8db30000000000000000000000000000000001914eabf620052971a87d9eda25e98c2b92a94eaa9bdaccce4c48c2b8fcf9cc35e5e6354bb6365c61436a5ca63bb59d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009fd4331fff0d7b74b2cd455aac382298211abd2b774a53529ec3b93041390edd6150468da836699ca993de3a6be3bd2000000000000000000000000000000000994ef7368b1b2bae34d2748f0e12514399b69b43492794fbb7c45fb2ef7c36cdda988ee05b867bb8d2f6211beaf96421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001028bd49d5b03f6c546fd66fa20aef9bf8304aa9678fe6a0c910ad74b494eb99ef709da527763cf4fd82dc6e275814b9000000000000000000000000000000000617af35c4860cca38e17b1aa9a603a22a4f08655ce618152221e6d52f72faa735d99efa88030101e87e5b1d460935c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011fdc8dae7d59b823eb70c24dc9037874c2039231d2c88e768200b9a15d0f194d0fccf362064ade9fb88c53e3dd334c500000000000000000000000000000000125cd42aa2d0c6bc79abb8ef38578361af12c586d342d016bbe8116c5c99531fe1baa16c95020b0ea6c39e5f079b3f1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb5b1a777889342b697f5bef0919bc0a3617c7eee93a650be5370e861d2031bcd7880c788b1cf40345aabd96a4eea50000000000000000000000000000000000b7c5be7d85c5774f7f4581297a674a8213329cd55a6bd64d27519c7611ab099afdf970b7648c19cb68fc457a62429271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034a99ae8489bf29c8d37e54ddcf3844a1f284cdaef9e8775bcc595ceba444116c352ce972ea7fa1aca2434f4f238c620000000000000000000000000000000019c2b8717177d7de8011efea25523e88187bb2fb5a1d85b57db7d0a29a68abf2b2723ca3ea0b3827e7ca190953b0681b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000608f2a6aadfcba03f91f65f1c6f911333e3bc3ca50e2060dfe5af5305c00f485e3ddfe32e88e67804d5d4cf9b999757000000000000000000000000000000000dc0475a0e78bfc77eda3c3ad1c92a352b65f0d99db47da6d4d7ff967fb7715b53ef408722bff08f3a2cd2b2523c2e041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008475b8cea77a15bb5fc457bf264846dc05c47b927b0949401ee94bea619554c714fabb604fb406b972116e3a00c37c00000000000000000000000000000000014776a8e78e7d3aa155e890717048e27c07fdb5068e06247fe370911213c980ab540fc93c0aa41bb4b44d14e075cacd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014d89ad78c92dd2a29446b78cd6a6f3031b1625d20d50710da8afbc800172eaf68568c1303ed4bc341bf4866d6a1d6a0000000000000000000000000000000004abf2cfc1d8b701e3795e6f48db7e931958f11e11969eab2cf3259183c26b07e37a8e4f78360ecc453662aa2c25c89c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008bce712b99a779b3be31a8c28fae56f29eeb83c181b30982300e42f6ea382b35363b0a7a38bb0b2cd1e9e18da292e0e0000000000000000000000000000000015926512d9a0069dea49310c36ae19b4fd2021031314f7e4ef1e59bb213fa2506edd8faeed624ec08b904de2faacc1bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003dbcb9a6a81bc04fd4b5e2cbef6fd758d3514f2ec475d939b09fc6567c94f5966c561e2ef6c2b530e96918802794539000000000000000000000000000000000b0c63e4f8f83cbfb13a7c4a2554e767edeb6bd65d648d0c729a8637abb9af34b974e558e2884249ef0f415bf83df56b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116c9bd0a4bfa67a78e6044e44f255c8a75d61cbb5fa1f4314addbca7cfbdf24579662b0cafcd9fe156833bdba8325be000000000000000000000000000000000e2025dd6a05625dee5fdd93b3bce77f00fe36c2cfafbf60edfe807b90465535a315f56c8d75935b843b7c33d21da1931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016165beb6c6273343e979eaea809a65d4be9e7bfed856dd7a07fe3e9e62706c5bf7b30e2ea575e241100a439efc4044e000000000000000000000000000000000aca4996279b719adc1dd95e5d1587aee80483504e53a75bb0be1f48193fc01a5b0e896055085783dc57c93d783e6e621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001640b2796843db11c3fc4f366df9a6987c8f152c5d0ec1f94d4a2e7081129e02a14c58f126b6be174c44f4c072c938d90000000000000000000000000000000013f8264935ebf4ed75ed9279c5594c986a9f344e4473acda058830d81848eba854a96fe1ed6202652099e635ecd3a59a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f2342fffc9b84a32aecb30f4ae439b56e914d5368afecd887a9fa5e4fa68d4ddb20660b596fd93b223ec65aef086f90000000000000000000000000000000017045599ec201cef97d5404e512afc2a4116724e71547db8b9013d4a5d958f4dd4e4475254bb2bae879f2d31179849601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f78ba4dc45d5dd58371a60877f15b9e47acc58c5229342254d5a147bd93312da21b66f2e596e49b468b1f4715d7f1800000000000000000000000000000000152b7d1bb81e9adf35c7d380909da7596326d36cd8d45fd411922887d1d8c8e58d2388500cec9425a64212aa5daea1311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca4147f154e1b915b23168f573956f599a2253c5176e9a2fee0f0710efa5e89d2f90b12a304689f1a086867eb70a9e80000000000000000000000000000000005174d0c90dfeb3c6b2db73d09b83289b52a154b522be6f068d07bfedfa4f1091aa1f713ac5b6e100fbc2f17e17c2d8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bb1c917e8785ae4f4bdfe18108c9ab2a6d8772b6ba764a5a662b8524a1e957b2724d3cedd03e65017d37551afefd3900000000000000000000000000000000014ad857d22f19e55a64c9ceb2ce54f6c96d62c503bc3c224e69d4683d1a39125978a8bf65931bf903d8da94ff51ed341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151e8870c9d9681a70b64cc4bc25dc9b803eb013eeb8ed0eefab48c841a3eb6b5f9563f7a76664845018cb435bbc8ebd0000000000000000000000000000000015241fcc18bd49b069c49ae541a57a5abdf1e920efe40385acf1c7c64ff5e0b5f81b7a369d4b02ed9490ac7cc0def7531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003323d2a87678203cc54877c7df836e53ebac12d9d6c280f6b54ef6b0d17f2e0a65ab4345c3965d47f7df0e3f5ed740d0000000000000000000000000000000003fd3af23a6caccd2f80db3905e9f001bc5633fa5c4170b8c54770e3fd8b95f40bcc50e7e61c68df19e57389de670ede1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1c7e8c5e6e629b9d8de1818ed6b63bb7838a7b8eb33ca8cd19aea33d2a6f4166c70b86ad58ffb15139edd401f7ab2500000000000000000000000000000000038292d6fc281883afd307b75dd3cf5188e812a6e01a5d21caa7af5f5fc60c409ee7fb56205696961d0f013c292da2921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f429f22d2eaaed99ae57ad1ace58f8700ad4d9e26541fd801d74eabe14c11626cabff59c36e39f6a12903a1b78c210000000000000000000000000000000000ccb99df5b7b80f62f129111127ee0dc7259a8edabacefefafe42c882a8e5b9623c22a4a6b9fde272d983e534e1a991d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019cdb148cd630b78602c5da04aaa971b1b91c6c7210ffec6de2fb132a2b20d907def6a1742d584ec6b6c72ffee0116890000000000000000000000000000000010f791a223fe8fa561e53fdca268c65975b95c18176767a4120040514b0a5eaca487d639e4040e3ee62c61831c59aa121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120916fc4c1bf20923f8bf02373c3f62eab0257ddac78793365953900d9cc9379233453c9d516d281111355c5118cb5100000000000000000000000000000000034e3288469df59cfb33ca253f90337d1501a3489401ab18de3ed31019ca77729f83a589dd20e7207276917b6a740ba51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000177efe5ea7115ae661dec468d7af5f6350fc58a6df8f5fd118c066bdbda2e0d6839448c7e3e9659f5d96b4c6bb7fe730000000000000000000000000000000009dfe0a8eb0bd74fa27eee1e0588f3d9ba61cdd1ed4dacf3df2c0bdbc668c98579f4079b10b6ebbeb9c5954e18d806151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e911a1429736bffecfd8f88cec05922cdbd235956992ccb337388803e93fe6d472bffa69b6445fd3bfd7ecfea8ee04b000000000000000000000000000000000d31eeff680ea08598e7d6e2a8363dc64ecf68f8aa7ed4b320248c03925f47de804a3d1032304a440db826adbca6bdf41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b2a9415184f0d79ce8f774bcc74a5ec611ec43928768ac2b531f310bf0c4947d4eb0625a97bf7a168f5089122e4a170000000000000000000000000000000000840cbf61df78fdbedbe5975581a5e7bd41b19ebc61e8a0541ef2abc34f5a1bbdf9afef2d6c9713c1615cda000fd8b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a83040679087e5e88a005c69aaf4ed4e9c01c511b930f2f234aaead4b4df52aa89deb22c6391fe314ae93e8438038a000000000000000000000000000000000790f5f03c81805b9f238bcec04e99f6d89565988f85c70a1214a28f29ee6b487941a0e0fb121979a02dedba4d94c6b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112c67214a585457d14003d451bb4e1d2cd82de1b4ae8132f8407d1c5f8bfa8b22c81b220186d1f2de4abdf49a9448c00000000000000000000000000000000001c30e3a774a60110fc6fd3da7a341be0f9b783320e6834c6c8bb929be84f1eb2ef6761daf3a700f8ae6087f277dc6df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036caa1f4e66f153257ad4b44865ec4f073e395856118b04a3445372d3c6e941b3962a27ccf0d99ec242f095fa908517000000000000000000000000000000000943e03496bddff6c96d69d633e49328edb49b5eb97f1632bd8d29167448e0b92e051b892747d9a3521830bf7d69f9cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019dbbe2a71a450988b380624c928fd79ee3fe7324514f6bba24abe9272766a0a6f0b894521f63a5342eba95b4cb5d8b70000000000000000000000000000000004f612e2eb3c2400e45ad0fad3e5edb65948f4bb4fcffe5e235af21338121a334cf1b920fa78a331f1d64d62f78902fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da04ea8aea344e5f5df1b4bb3b24331cc234bc3050537997a502643c264f94118da289cf0b9be0c5102ede3ba77b9a0000000000000000000000000000000000e555b5778b64b9767df062dc49f691120e20fb2b96207ab01cef7c21fd7c418a36559fe2a70d0ddd71342f831e2c5581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005aff6350b4444ee4c4907da991a42452a39cf85db2280f962780230e0056db723b113b5cd6e54a18a51ac811d46c7dc00000000000000000000000000000000058e1e75dde66beeb3309691f8e7958620b51f20e46b6bf9dad70964679bb8d1866ee17cd91a8de3d608d817df34244e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154a5031ae67d378d507e19fe6b1572b1cbb267a819f083a3c06642d37296e4406545f4c31991a6fbb4b9a88640398c400000000000000000000000000000000130c6ba58d3a660cc9324a26a33183459c726162ac2176004c0267f0936483ecdf76f2a0270cd820b56035e29d99b7bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ec5c6fd52b295b6b4084e67aee813873be442eab6793f18520862843ed36a3725c47c76bd34520d45c93504ce2e1e800000000000000000000000000000000065bd3eeb2fdcd19ef458f24f9b7ac6c8736325e55fa728140743ed8899e75cfc133d7eab743e9a2a6ab853bbabe73f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018786b3153d61fb9a3057b54734e84e0419da3ed2bac0b1b2653d2253ea604810b4dc5df2cf66e92e44c607d5845baca0000000000000000000000000000000005add1276b17074d1622f3bcc93f1be0c544c1398fa301e1ea95373eeac208d1d06905ab995a50bc2f4aa726f44136981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031f9465481405c1e9656a1a1b93fd4d271e0c1c3e86a38bef3e54f0acd865c0576531a3c0988b8d335ff1562f36188b0000000000000000000000000000000015b2d3b56b1b7c1e30f3d4d7d0fd03a2f0a7324253da551f04805233330208bf07bb6ae1ba5cff41bf793553c1637c681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0bc38ca3ca1636d4142a41e65e9a201a33dfcd0189fa01a9d67e31cb4f28a72e87e08b1cdce85869eb2562885069410000000000000000000000000000000014618c3d92be0492ec2be0ab1a058486228763e1b0e67dedee1fdab4d0eebb9a4afafad5be4bb4db8a4ce43216a78aef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8e4d431d80e96598d258901e0cfd796bc27d8f023a3fbbb583df311fbfbf292d9404ef6540d1a6ce34ca0f2bac3b31000000000000000000000000000000000bd28e5570188c7c316797b0579a5139906fa42d4751be15437a8f165487c81ce8fd75cf646a7fbe4ef2c5d3143d1ac11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000320c17a19aff64752e12764363af9d46493104d537794c46bb2c5b9155cf863f5d9212dac52f5b305872b6fdb600c800000000000000000000000000000000007758532f15fec81d22e669a711b3a3e37c88947c1fca58cbba0779ab5fc8af6b52a2f2bbd689e4b46a920d3958f45af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001bb78aaf07d53a0cfdff0d7ed685d4b8944e2a2560f730c524444cf97bd40632654e778c15395207ec2fa9ef94e70460000000000000000000000000000000007f006a31be4be21c7e7417a1d535581e833cef211f3182a864eb2e93dbe86ee64d28fbf9f7be47e5dcf93d42b25d81c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e809d0ce711cd762010b2da69a934de4a09e9764a135bfb45fe4e8e8cfae7d1cda014201148d68a7a25d75788139ea000000000000000000000000000000001147856996f11ce95475fc9e8d2599c26bd1103a976ff448b7b3f96f78bd6d77798b9f166d426334e26f156cf2f27b751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001392a1e8e24f607a0a6f00ff9747fd1f8d7de472c542a56c00102e22d9f2cc0d8b0ff35a3a54cac20ecef25aa5d3ed96000000000000000000000000000000001672d438d03110ae1d7333fde735ef164ec03bbf0e1a074045c619ce988d96a9385ed9f2731a373f0a9a76f8e31a2ca81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d845c4b71e765b7d489271790f08ca9b009eaaaa4702956ff7854d2b703f95568cc6656f72c3a31b6328631e6045a2a0000000000000000000000000000000014e7c6b2b055d2db266da3f7635dad731ac9551489be998a995aaf28d2bbce0e7bff05f3e5f364bec42c4172108bbbc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a80fa372cb49f5e66a9e7b5c56db05c3f141f52ec1c987a7e98cb0841a1cc8ab59622f45beabd7622f805b162c1d08a0000000000000000000000000000000005374402d5f5b09f52d8f072c1880c78910a28e5c510f55c82335152cb1fa9a4af8d735c7d2e069e5a779df8433eda471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001069583f1f3b45057b91e4460d728cbbfc18609823f959b8c78abbd04cce8f21f5e594961d6c6458698286408a8b52f20000000000000000000000000000000002ad9013fadd9f8b2c559c63fb0014c0352fd9894f596dc1ff4127c356cc9b4c5930880034154eb8910e7582f37842db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052212c391d999df71e3c212946c286809205d1159b55bc9475f59ad0a8f587a0ebd5fbdaa5c219cdf591bb7338fbd2c000000000000000000000000000000000bdb32b4b6fe1bfc7d96e447620b7be4fd9a40e2edaca99efb86f7ed4dc180a80f8ac11755582daf440fadeedf9b3bb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054f57574d71171c82fb5d3abb1c92d5350709d6b2275aec41b1f8eabdb48290833896d4925e1461f70674e4e555cfbd0000000000000000000000000000000018eac4aaf3cb2cdb5d5243b1738a34e68d7aad42a1f45beed29209e2cbe9aecfcf0bf67939f1b93d30a98ef5750e74051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b35c52e2bf7ec91f41a060906a6f38727da8254376a1c238c198d2343d844820ff0117739240dcec2b812fa490fd97000000000000000000000000000000000ac7e38533ca88b8d7502f607ae9cf91d9d929b85ddd4eee327a766a98592d6549960a972a298e0900fa2f661d1e4c851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1764f43c537f0143c6f01160cc284964d5054e34dcb5519f1de3706d31063d408fb4cb20bd94479445c8725560b6300000000000000000000000000000000001c0ae98ed2cf78cb0ac25153a7d6230796473b8c2413ae60cbbe314d61e3470723eb9b35610f3f06ec70c3ef0b569471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000396e5bf77beb600b6cece5aaf125a304083f1a4f90cfae44aa72e858dd8d8e8e0b141d6a76159022a7517c69eed920300000000000000000000000000000000039381d29dc299ca1086843a1bdedf76604ef78321fbf15fb07f3e92de84cc2e74e3287dd535260ea2e9f19012ed9f6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f3af78edf2ed4e6fc01ff29ac963f0cbf6573e8310224c30758322b80df2218409069d11c106956e94ae9f3c156e2f0000000000000000000000000000000000d1417774d4f11acf5a572bbde0758f28d9fb659dd082b740382bbaf8b64c2b8a5965adf8660f77ecdccdb0867e5eee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001325814275069acb96cad37a3dec0545c1ae407a5f50113c6a60c5bad44894f56bf3dc28037a7b6a93c3b5d66dee1684000000000000000000000000000000000139b11f71f934027a6eb3b12de798819aa3caa151a38ffaba883a6e27e70929eb3b563d7bb3ba307697bd7e2a96ad3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018dbc7515d691003743727d56c36056d1b42c1ca66747b372c0b8a43a86e768db4530b5158b360f174f93193bf77474b000000000000000000000000000000000034c2c9c482b32f9d0c721eb27ff1da0cd9941d875eae797e846e489aeff2ec6408b3baa7b4ccb6a8fecb074f8757301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fee60d0b028b3be37861a29bed8411eb90fc333320e2eb12887d21f06246b7a38caacbd846b81ac505a96fda580a6f30000000000000000000000000000000016250dfd534a20076765d63439ca4584d8bcb49d028131479556a67eb27b7f7ba01610e53a062da06563231e37bca1851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da114231f704d7c7fc1fdc6fc213857afdaa902eae3f96336b68dfa9eb0ff91c91a248892382706cfe856e64e3a37e30000000000000000000000000000000001c44f9834ecd5d7f4b4a88cb878ec190c3cf2b4a2f16509e1ca33d84e7c8efc4846a9a156d7ab70e31d894c70712d551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e4194664198dfe3792a184bc375834376592c7cbe977781424c19e664c0bd17d28a679073ba3e1297ff4752d2b52a90000000000000000000000000000000000aa36adece6647d454afb83cc1d23dc0aa7ce4346ea004cf324667da96cce6c6ed2819aaccfbc879814cf726d0b93ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b2f877df52aa6287731c89dacaba184662e29daadc6aca2ae2abfbc0685d9f2bfac933934ee079a89e4603134c012c00000000000000000000000000000000192d3014c14eecb3c63d8e1e98c8bdc32de3414c65a06f24441a689c86f9761e624ad9acf50034fddaf5c479eaff93761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018214a7f6453f0034b9b53bbaf69316940f1f313af5bf49f6787efdeee8fc3c27cc9dc07c5ec8458ceaa9fb15d94813f000000000000000000000000000000001766b803edb19b2ace02fee6c207ee7377760b30fca1b27e050cc8f89ab39e102ca952a33e6647ecb9c4632f169950ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f31c65b92199c144de3d44e52340a40a086bae99e6b807a0341dae5afa547d6982f8cd20de46a4625756cb69588145000000000000000000000000000000000a36b54929a717711ce0c3aab11f43dcf991d2978f753f45c11ef3bd914ff671844b21c8e9bbaa43dfa550b9ab29e9d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ce157ac22514c3828ab6c4e3e53e05740a2cfd847ce3a63869f9b535d74361e555db67cd5be55f19cc82e01895dcc60000000000000000000000000000000007ce7c88725fc7d53d188e8adfdf2b305298649427672090c670b626ab4df66f2e14d1645a76b12cfb5fb16349cb2b3c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8d82eb98a3a5e194ccab916554ea42f097836ff43c2fe910639988bdc063ad64b463376c3c2c289a6be9dc04c10888000000000000000000000000000000000a3aab07c13aed10715f38f20501aca4c6b69a4f6196c0c049defafefa873a907fe807e55001cc066edbcd32194ab1de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b51edd39b5b6461e001297c80b60e89f624ce960000bdad4f680da1ae44c4f891a16f61c0db0ffe251f346d1e8445fb000000000000000000000000000000001492317fa3877744bab150f303d0edee2dde992876aaedbbb0d7b6666650b491dd9319905bd6a85b4b9a18c349dd963a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001459257e78ccf3bf82f00529fa6dbf7b40a535054475bbf92140623e6097331393bb620e8a2cef47f200e231a3a439a80000000000000000000000000000000019d2f2ff813d63e128b2894d67a46dd5fb45d729e6c6e438326c7c471fe371cfd29377a95ac2833e51b194169fe4e40a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e71bb76562528d03294d9411796f44c4fd4c7ca52605653d168be70c8b28ba3790664b3820fe4a96f669bbaf4f44b40000000000000000000000000000000014c6025a996c78ad95bd66d532090e34b5ac9e95479fb7fd6f490a2aa9dff005a9f74aa79dfbe16f401cd2c08f4905171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107bfd6ccd3b1e7a9be262edb1ce55a08f5e87650286c679bfba4d6088bc265c4ee490c9cd5b05b471d8e008b267c4ce000000000000000000000000000000000228f702abe1b18a086cefe61f0692cc151929ae8e07cdf4d33f4d85ed0f54301740015cf7c2fc2fd957b9a45d5245c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019cb348fe4d5897b38281690dee14c61920d0064ec1f1707a190f3501e24bc61b839b9ee0f4236b4df2c5f420d0efb5c00000000000000000000000000000000013974a5a8ea2d46b9a709c981d2875c5799ba45bc6c5523380e63adc867fa6b0c33b1794bd422c6b01ad279e3dd85101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153138b4af4123eebb0bf5242b39bc49bb1d7e8d9944c11f6daac2879144cab0fc3a40655bdc30ed804a1d9287726c5e00000000000000000000000000000000025917942ac76cdf20c96a5ce693a8320a0206da64cc2a6cb978605ea4350765f99372f3dd713c2ff11f7b15c0efcfb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e98d5b5bfad6e5cf49b36c20ea4ff3724e0bbec5ac241476410311ecc21c68b69b307ec33ea776900b05116df6dc9a000000000000000000000000000000000be9ea6e8d6893cf5975207b52e226204fd41fee655ebdb9b901887e3735c4de7be340ce6ab68826d999acc41a66d1501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4d431e72d4068fc6516d158900d276225eab74b69a35ef4c37e44b9ba4ff48ed2091af627435d0af2243c02adcc5540000000000000000000000000000000016757338f57046fe8b2edec642b2a4ea5d500cad331aab54a0241f74260b342713264bdc678ba98e8ff98fa0beb709fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ca9f8d241535cf61c100d2697fd1b0d9596a5288cd1277a2d1b1192914eb270a8c61e15ba9e31b8d885512ac8a70db00000000000000000000000000000000036d28ab97a65690ec2db8a35ad74c56c3af9124d01fdba76bdf0462b7e2b551b28b34dfe0ef641e684f8feb1ba9f1b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc7e468f401ed1da5f4b6a970e8ff35d75f214220e0ed39baeac2bd43c6f052567abf29f99266c7cd81d011f6cb1b7a0000000000000000000000000000000014170f10fd24a2aeaf7ff88f21dd4bdb0fb79e6428a2ddcf75691f601eae84f26b3208f8901c93cfd63355f405fc318f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e395da6751313835c97ce998117da08e7bbe5993662350ea48df03a30fc65097020d55ee266419739964194dd06f88000000000000000000000000000000000fd9bee77374381d29d8f37633fb3167d65c94a2141a5e20cbc5939a049e50d4fe0a7b868b0f598b898ab43ab607d3781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d98b8c9a2e5802d7778cf10660d1d4dade4063bec355b243b46a9dbd36f7127465e2ee5803cbbad76ef1e198a5f8f100000000000000000000000000000000187f2f5c276b4bc52129fa1ef2f05de3ea2ebfdf6593587f7dd87744ee2810e43bca6bdb04005543339df351b83368631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff8535755b078ed2182ff3a8a49f5890215254785fbbfffa7a2790171084d56aacbd01fb5553a07852f7d1dac759beb00000000000000000000000000000000113a6adf9ad1da55b395782de6ef7f56b44c0cb572bbbcf30f662d7b6ae6710a26ac020d456228a8a879ee834b4200841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e95296679513066215466fd77d5db89a61e962e20ae3eba6f24f402d6823355480af9ace526b42764cd3529ab555d100000000000000000000000000000000008dcc1823dc83c493a275d1c837eaa446c872837e78b7d34328e518df42f04d50ac517ba27982d118ea3f8488e3b3a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001523aec3444f4e16ae8cdb153e8f1d9ca20de23449011c50e1dca749d55c2098240ab85513c0abd97097c60c8f471ad00000000000000000000000000000000017238027c2abf0ff696fe7f98f14177018e378d715b3f98c3d3dc06d2813e9146010cd3bee3483bb7712e8031b59a4dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011360e4586cb6fb2a864d19f54bed7e1e122fb2ea43cf16de2a6c41d936150bb011037cca5b1e9021d721d54c3156b820000000000000000000000000000000000bd5a730913bd277858a9685cb2eab31c55bdb0783fe11994dde5fb1b49b73dd6b6169a5c602a09cce471c2a603c97e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b6e95644d9266ddd8abef08978cb9e84577b71e8fefff1d25f038a645a4a426b90da08c278b6cbb1bb4d2cc7ebcfdf00000000000000000000000000000000032c82dd432f8365296d2abaac4081423110145d1fb17e45edf3093a9627a00b257303959aab46134fb03c7f7643e3ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc217708886694d1e1546078bf41107adadd76b1244249c0d9529fad652edf7ba1bd91ad1644b450d73cb081c4cb503000000000000000000000000000000000fe236ec172417311bbb4906b35083608632650f917eaa1580a462b0370247b8c095ca209ac4765a922077a9e5344f011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018c85cd9aab84571430dc7c9c484b350d0f600ee80090606c493636681e8755eb5a86d334f4d2b961302165055e60bd0000000000000000000000000000000011013b1f59634f653d213112a6ffd0ee7666aeee3c62747704bf3d8a7d77a037cce20181421e906b6282fc9c872eadca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187ecdcc37fae66136f2abda2d83bfb3b16343da7ae39baf18bd89cd563fbff896cdf1274e470eed05c3cdb817ba7f9300000000000000000000000000000000036d96d253b980dd81714850f15861f13291655df7dfb1db24708ff4828901c7d0bfc053c926c33b5c1c85a3fe52ad691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001547a7b1727361f8fd2302dc47dc7e61dd6fea23edf8cc8e77607ebc01bbd7776e134c3b7b5f6ad4d38e76b2a1feae0200000000000000000000000000000000194776623554e3451a2bfd9fde00dbf548b1367bc1fa1b831143334cab86a6300665e84850519de030ed642ce877bdd61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108ce08c47afc76bb2b426932c431560925f2c5f5ad38e6db22e6d3662180e5617bd0fbd3f50a38425ecf2396868c4100000000000000000000000000000000002c3728742fe095696c91f81f96b91482d1359f071ef72a222badf186858c67cf3f2196ee75ac1d66ac8635271190cc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000172a0509acf8853b256dd02d621111f1062279be8503dff8b60e200eb0e6b9025a026f021bab63386af83989fb48ac1f0000000000000000000000000000000011dd6ba6fa97cc9976b47d18b3db61dc1d16f276b46c4099dfbd8cd52bc82ba43d7935da6706ee37025fbf3a394146e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d697207d18ae9a20a274601a1242940cf46983478fdb0c842670838c29ee0b8038405c52ff9822eb7bd912bf3f1b20900000000000000000000000000000000178ce27d6bace369eef2d202dab0bc294b275ade6ac574762afe72e0af5282010d3f154db39941bcc962f477c73efb0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001068a5b132aeb84002f3a80cdebc44ccf1c9e7551b3114640721e039af73921c2dc4f06e78af033876b7e9cce189a22a00000000000000000000000000000000126454a74d8ce9cb9bb0e00b5921b9e9ddc816ce38e2accfaaed506ba2ad527040e42cef8aefd5dc36608b86cb20e5dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001789bef9dade1971f998f274bb176c0bc17f87fb82482d95e4dc1103a04a705a29a541d2c40203c948ec0f9f14ccd2900000000000000000000000000000000102448edf58f27db4482825e830ca787bf8c4d53fd21dc264c5f35a921dfaf8c9fb36ff6a10ed4dfb67eb1f2d8e6d7e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d842c9a1937c6f6eb8ad2c92dee8eae3f2d6835852bfd60346dfcb67df62578b4dd1ec536201dc6bfc62259a24152ff000000000000000000000000000000000ef6d4b8f5c4b9619608c6651514ca55658e2d32cc7caefad49d5c7d627cc8a4070e53733a80f41656d848aafedb5aed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fcd732ad217abb89a936fe170381b9fd759dc53ccd977905cd1048a2e6182f5f12e128504c9afeea633550fe48b94f1000000000000000000000000000000000b2d178d358ef76e7359a06da3844fd3953893fc39ee3daf835e73693d7ac70e42f7f8ba3b2a938e74dd04bc3f2bb5a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b19c11581cae45c9b3d76125314df9883013c3172f523c54278c05d01f60126e0a3661904363aeb242a3cd9a9c5034000000000000000000000000000000001441be72393ef709317448d76957c624938f8d6a50641169e847a8cd3a2916d9cbebf91ca6e32943716c1881916f03851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001127f60282ac550a5ceb43cf485a41cf59f0955d0d8d5505d977cb74789643f1d59bf3029ef5d083325492a8bf72daf0000000000000000000000000000000019a81fd35a6238f1e25dac4e09812df9520cad98fab8baecc04a00d3d687de6d43c291cb046ebb1aa2a2ab56ecf411fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f80e6d946790890b64c076c80fd973222161156a90e66bc41c61cde08330cf0b2f548cc142c568ba51312f5026cd735000000000000000000000000000000000a8b41735ff3367bfbeadb87290494d223acafbdd6fc96a9ccac4a1a637d7e7534dd88064327f41413052a1b4b831e461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe57f65172775f893c4ae5d45c60eaab4396fa7544f0c45ba29369a05b5c3610e1437346d5ba4262f371e190ee28bb300000000000000000000000000000000069a7596e8c82c65c5ddd8ea8c9f608b74d39dfd8e5797b695ea258550a0da7c2bd982a8f1bcfb24cc3a2bd1bf10daa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130f8c5847d31dd5888c11e53ff5543d9d49e01ca1eac3ba7caae847fbd2bd1256daf190885defc13041bc5b832266c9000000000000000000000000000000001628b9e76690238e00d806264c00776e151b89043d0a5c83c25a350ad9692c0c3a76c2c96327a4acb02cdcf24cafccaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148b3fa9fe5708a6bd022e0eee7768e291c0c33689ddaf7393bb8961d86543154bca566feae2691e0b43602566913311000000000000000000000000000000000cf5fe4fe971753d340717a9a2610e6f01f9e54e3477211b2f45b1b0906489cbb16fc4a90c394dcaeef6268bfe2007131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019baf5109be1dcea35e2e7166612d578ad8eafe1cdc8b68b1edc5fd61d9951565c73c9aa4f06c0d08f51677c87910b160000000000000000000000000000000012cff62815ed156824b1d0f9b278f60b4d4d3f312ac9d9b70894c500e0811823e3744a541576b588fccd7d4f688249541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fece9be0c8574a9cf243c773a868aec118407adb29d54b75938558f0941c23d32f5a061899c9ccf16b02d495fc20043000000000000000000000000000000000ba39346401aa9067816750fe1234a9f24f9724dadd761126472f8c59bcccc8783ea96d4e1a91f1f11943a59cf0a1e331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5ede8dbaf49711363b3db099d2d1717b14b4194205da385755288988ef5fbe614c5183c557f1c37df323d7833a74690000000000000000000000000000000004863b2d47c4d3f198eed1067bdb872c98dd19d442f9700f5a742862b663ce91213380942773c586959330e0abb80bd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9056f07c1190f59706e3edd8c58f8380cba6104cfc99c372cc720638fc5b7c3d62ba082fce6726b4bdf5101be5912c0000000000000000000000000000000002e6e903c825e96fae44f0305ec1ff2b7f9562163d1d19ed43a8faf9b45b621a71018f5cedafeafa245788c35b2f49791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d6f3a54b0838f5e0d04f7762f030f208228631d316c2292e9b5625ddf9e23992deb041aa6f7dbfdd6930a6002af870000000000000000000000000000000001743213de89b61877f528f73c9f39755ae62bca6b855985ef20ef9fea29e49addd807adf1805c6b2bc56ea78297e43da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001881632285460b4546fe60fcdf7537c674b75f92c0d35d0e85a97b46b29e164b49817940078b8c4c87ff3cc3906ef5f9000000000000000000000000000000001230f1ba7a7cf3c7ef0fdf2fa3b9a74087ee16aeb3ae32eff8029e8eaba18793f61c1a96e77c192e609308ae21faae6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020d323b0c98ee70b77391d0744243494d40ad59343b6f53848edac72b8f9f47baecafc207385926dd2c1ba6a2115539000000000000000000000000000000000b223e2aaf51f8ff5774d6b126c5b47bad07d7d2c849e5a44f926d0e53192d754bcac761a51042e32f303697a383678c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186f8059f2d094d7e6edf241ab917700fbd966cdbd178ca625ed836d4be6f456c1af37b44841a0a763cf9695498b450b0000000000000000000000000000000019d51fce03f4713ef40bfd506886a07aab0da3044a475938425e8497f576f0b28b73bc506291262382075ec028b6b7081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a74667b92ee623fdd066808ce7965cd4e938bf6eb636919103da1f47da6fe5d7af4fead3a5f007198f9095b08014df800000000000000000000000000000000025aa9902420e3356e1646f5f5dd2b845101c4c15ccf687d56e8677e33ee6d0fdb3cfb3b313b3a0ceae8401005cdbf461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004cb85016867d6d26fd6555d2fec6f60f0cb55e425ec99af5e90f08b2f16af0995fddfad8632df5269d1c55899513ee60000000000000000000000000000000000230d2973e94ebf8274108dbf01835b0e62a0f8ed70c2a4468103521677d2437dc344d2749c2f5a273c6a5f5c91c2901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b31821d1e4027786cbcbad728209972df08a0c7d2aee94a6f9b02f810b2e09744d446feb8387297fde0e3bbca613152000000000000000000000000000000000e5a14cc17b37a43b8d23d9efab2250a281c8d362ec1e974f33f375b2e7f9801f013b9f69b9f1913c04e4259c11af6221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b839aa36b7b06537ff0e014cb72308c407a775e9f75a3e14a69c578710ff59ee5f79f34427d281251f59f2f035816af0000000000000000000000000000000015727fee06b027758b4a4d6bc0155baf846bce98bf66a16ed3d2834a20a3338c2317a063f6c12ac172cca73ef5cb0f7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000120485ea8768b97f87e3cc11f59cf798787629975ae6c7d3148e6e0f06f50b840090038d3f21c3c8ecf540b2cc3f58c00000000000000000000000000000000115f5bd276500c909a7fd26e37372608c3bb55be4de854914ab1e611b87fb3dcf26d47d72dd9daf31260b924f22d72691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb444c08ea1ddd8a7fdb9034cced4f2c345419c07e748425b8bee30ee799d035934150117ab7ed30b20c21f8877c0a8000000000000000000000000000000000b4d627a8bef0fb3ece9b554cdf830e3e4e2b51534c776294522c461eb81124119cc91dce3a2da9ae1fe67b7c350b94d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ccdb74e8f32d377956c91a1a8f0e6f611cb768266c849c68b581bbae90e9c7f7ecca0e6c3d21821dfdd50a8aa1f029000000000000000000000000000000000d9e734b9a2adcba55469857086f2a2cce6646da6c518a699e76ead4f2b39fd231b0ccccfe639316c70cc8b60ef22f911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001835997583f5629da4eb34c240a206f9a1404ff638b215a47472f44ec53d8161e2d2b82e0be14af24e9f977bc7595e9c0000000000000000000000000000000004c895840fc89f0d380bbad45a998951eca010c7224c3ad09b8c67b57fffc7e4a9ac715dc2992846f2640c59a524ee2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a730802cd62d4011a92217b5a47e345b615006d3338a6bdf86f539493f3c65a02095a900cb2a87e2558e37c12e6e63000000000000000000000000000000000292898b8c6f6a5ae41bf31b814dab69e01d9df350e32e831d10d0bedb2c5bda9c41f5b8c991e21451a7663bf9e719d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001865011b70c3832d4f6252f539588dc16d98392af17842d5e37b03a4b7ddd0b1c4c87a41c96025a50630751feb073090000000000000000000000000000000003d3ea5c21e8ea79e76d3dc80e29d11f2488bca6a28f14a704da5e41bfa99d9bf25f88f3df1baf61631c927a175dc0b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d7a8181075a81886835b59dee0eed9d0772056b19a8c694624675ad3335f74943dc7feab7f639af567c70b85764ded00000000000000000000000000000000061bcee0aa7fc41e661fd039b0e8e0276f531f5ef8a89be48f441d1dfb1c731d7bdc341d3599517da4be25cf316060d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ed06a01daa9671a7a7f81cdb3539d87dff264294be8eebc816d1790e01224e81252d133439da9bad5e26d2d53ac42e0000000000000000000000000000000002e569bde8c6985d91504cee76d9d375cb57ebdc739bb5d3ed5a2df7b83848abde94a995debdc19cac0b77aad9bca1601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a009b393c61a86af9b4014d08f9f33654e680b48445307c4ac1522fb05ce7798bc7a6f5c224ac7f187af43b5ab43ad7000000000000000000000000000000000ddc149fcdf51db41606df83d3e49771e7dd9a3610d23fab84a896f04da404b1084e361a7c9a939e7d12ab6894d2c5771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c09089b878bb691a58b26ef07bca1c578c44a4f69f207c12eb2c64ffafc87e780e769a975a56ccff1c49bdb2a90d990000000000000000000000000000000000c338644f3e0f19e0e675fbc47ccc70f3fc25ce2d0ef664b8eaa97aa30237b36bfb0d46a04c12bf9e2fbc6c6b5f67b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ec59a363f721465d9fe4fc0af80aa8e3393a2188d8f95822ca8fff07fe8906fd522e7e76e6a1d58d1f0118de3432cb000000000000000000000000000000000994b3e9cddd65b2559bcfbd8b538bfd5b6aa7937650a699226b97e14ccb4cc0d478904f5679723d3caf5c0f477a53b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2087e21df1da91336f5c3ddfcb1666ee66335363e01e5c23574cd8f39a3d0dfd044d39baeebe71dd31dd972ebe7eb1000000000000000000000000000000001681c56571fe767ac7e08bf8cb03d1680c5d33cdab2221a5ceed6eb25742c8bc140b8df934cd5157d86455eaf59c4d331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079cec6ce1d188a094734833c5529006f1c0447830d42cf8a7b3990e57783d897a9383f5e2251a13bf42e1449b9c9c170000000000000000000000000000000013ec1f908af9c5a05543745a1f4a7883365f757a73dd8a24dfa28c79fe08a3409806e7f451ae8c7d4abe9174763e20c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175a40d1eabd39cd09d191ec5fd11148515f63eee66a9b45a4d0e9eda27e50bd1d198debf087bf3c6782d1fe364b2d0f000000000000000000000000000000000d58c9f43e4138a6e6fc53322e640befd78dbbf983304a032a23c037515f9388dbd781c08345599dab56728249c791ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114441a09145e8929b881f69c89bda8e7fc3c9568b65b5a909020c29649e2a3e93a0070cd8a425600f0e01b792391bc20000000000000000000000000000000001ada046c6e083351a506a59f3db226606bb5b761e40c8e5b95623a06ec75cc144b6ea4604ac9c192c6ac62a261268811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a498fb2c9a02dd4c9b9410804b4b1914bb42d566c6c101002e6a28e5667e80e0d326d49d4c9c519cceda6b28e806068000000000000000000000000000000000b5468d41123fb55dc4388994fab27cb837f5890c685f1666f6415b94555285df448a7fc8c0ef0a636857f6ae30c66c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a94a17292b26687b9174fd77d47c2d0bc741b0dce8d929409f904b774f917563c9d8b91773aaea7f76fa144cad72057000000000000000000000000000000000b85d8f2819975ec663837b133359f88454db44287b6230ffb23e015d14bceecbdb8e65b32f949ad22e3a329ac82a85d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100ff69abacccd6820324d4652f1b7d208fcbb39d6f6d440cfdd392450f7d06d09210946fd22221c53422dcd239aeaf80000000000000000000000000000000008ae8a4bc94aaea601c3ca4c8c537053d75ac3e97a1787577084459d0b445d2f1e939aea3911c28cd79c571ca402001e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d170590491b00a645282f79b012e1735f2342a57c5dca848f3032fd82a72efd7a5a57375c699b7d103c2110685be6b4000000000000000000000000000000000cfb74d7f007f8820048e9b213d32a5499cc0494a2dff396874fd38656fb6cb3a76892f02db0f2fb81b73f417c4e2a731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160c1f3f87f509ac5993162494c85ebc82b4ad7c7683e120c7f766c7b29599454a06141b0b316deba7d5e15e1c2bc47d0000000000000000000000000000000012a9b539eef5a057b699b0b764ca87d820b13b46154584efa36ddec5398820e5a2de91f184a32605cd357cb0cd52bfbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2d142b1bddd87f4e3ee229876fb4318eb2f1cbaf64773c5d2c25cb8b6f18cb8fbdcd2d37d859fdbaf568b8dd38cf960000000000000000000000000000000010acc3d377132629dcc25a39d2404ce318a31b69f718e4600ff75e7244fb653311baea030db1668dbf59cd5477d0295c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6574ce7415a772aa066bb792895a3d7e9923fd392a8ecaddb4e63f8482a566cf91df3ec615915607d466c7ee80ff84000000000000000000000000000000000fc4ac2659d31b0c300ba58380057c9c96330afb661418a2dd825936df29c39790e79697998c15b6e3c4c21ec0d787311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a019a34ea88974159ecdca82659e21f2cfacd1c5a9405d81a380ec5541ed272869a3949482c346c72605a8369410ede000000000000000000000000000000000e53f6462b19e5ecda90644269173ac4238cdc50e56bd385ac8d3c0b1d70062ee4d342a1193e259421b0fd13867a76a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001471137f09985cbd2de91fc00e547a1c50326a10ed9b34555ef6c20562a26448cd82076fe14352a4472d19806f5b6b6b000000000000000000000000000000000b48a8061e60fd3eb54bdc1a405cb73e2ed465706847199c1ae4ea3b355b6a60430d8fab64fdf26727308be94d7ade781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000361d9b30ec0b22a1b56543dc5dd6ffdb6b480d041fcdb28524bdfa184e7793ed368ba3fe8a2d4a6e8ec3cd40817439200000000000000000000000000000000139fdcc15b248e0146e11d909909010dc78a3ad22c812a9ca5b0d8799f8680d53ea81773166d056d43f1ed027c60fecc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129caf3dc0af718e9e38b4cca490ea774ea33df1a0e40db4cdd8fcf4aa15a7ef08e68d6bf54ab82aa25f03396d324ca80000000000000000000000000000000010592a427cd1aaab021674637d836dd55fc70990e0a6d9896867f4f0dc49232620a96bc30504a82b27babe9752e8160f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd5f332126f75d71699d84a12b8da2fc8ab474b41925c92497ea231ef0a96bced111d8e5cc621f6b2fc38e061ac74e20000000000000000000000000000000016921e63b5fe43b027f4273a125b0eaa291fc40a6479f366f9b039f730e423a52274db8e38595cdabac8974e309ee4f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002569f84c676ff3f1488a4449a4dd825e621e2513461ebcefdfb35a7dfe7d8309f0bdbe1358ba88a264d2b9fd53667c90000000000000000000000000000000019fc3307bcf83d12c6586aa58f742e028475ab5b1990a87081d71a8b84b20bebeb076fc09bcb5a024a9ccc66526f7aee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000060f7eaf2f5f098bfda593148dcd3c9c37f1c34b574cc48a9e67bfc2fe50261de116e1e92f2954cca1af041cb5b0de000000000000000000000000000000000ecb93b042a48e6df82e3428dc80fe85214ce664b38404fb88fd670e831c8f4da7260ad6a12b3b1d2d917ba3b242825c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000324cc5cdb2cd1bc0189fbd7d464f55153df20767e275cf6a3cee85c66fe92a2efd58e54246ec9bf412cec58e020f929000000000000000000000000000000001573f833669e2fc97eca4d725b0127d97a88556bf7fca9bd7fca1e4faec98b5b7beb0892f3152ef8ae879cde3edbecac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018b71f98faee5c8c4164a676ec4e0aa241f7e723b31f6f6cb1b9197eacfa12f3af872fe6fc0de2e9790a67f26068e66000000000000000000000000000000000bc7d304b282001ec4080165c7119001ebbe60087742e5f227eda96954e45861e539a5811add5987194b6280049971bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000daafc7b029ab715ab7a2dacb21240463827bd5cfc9e225693a74dc34cb4d859416a8e12c7f963b531d7b07a781b25b100000000000000000000000000000000040675ae6b27b73bc0f71be9d9dafb0ee9e2954b2768c2255d7ac177bc34ea57d4acf43506254041d5ae3868a2cb0c1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000007b5a3863bcb9b6c49cad893ecfef3d34c6b88a1dadc81746f027b3ef37e81cacefbc2d0a68d99e2b952358434db250000000000000000000000000000000007391cd37ccb995db44a5f61721d28ed67ed76bc2c8619574c29e8496941527907a17cdaf6d8b13b4385e6eb9c05b8ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001073e86555ef9db8652dceb021c0cf562d1c5c9833e2c50bc2192cf4f446788c6ac7b3df1e1cf076ec6d953e50d95c74000000000000000000000000000000000a31d76d8d7c6161d358415ea6ba423f0af78494af50a118ac36ce4831fdd2aaf01084b5c98ed1840db9027b5eb9fa9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022cd497ba6274b09e4463bc6396ae257cb21cdd4298f9ae534769f6b7a1cdda3f4abe4f05a07aa6ccbb2ad519ce1345000000000000000000000000000000000ffb58bfb64c7fc6f8167a19c4de93d498179fed803d41e220acaf2ebeb4c532c4c921b0feb5040b5ed555d3e0b12bbc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000999f6229b581d5420ded5d71580856a484642acc49970b25b21bcdb8814c1c3aaddd6d59f5403101acf4d3855de298e000000000000000000000000000000000470c532a10ca9e609b04f09152184bf884a4497ef4e4f2257fc9e39e98b324db933567859b446db861db724627a71231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086e7e4467015a44f4ffcfd5c185f926215fb7a16f57f93872496d6537c85ea330764a6bf9560910ff539c3e7d6cd8aa000000000000000000000000000000000fd94df18a12496827681df9467e167f178b0de3c588ec883025fe02d8c17c4a2608b26806089fa6d3f27a32698af1ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001bf6299b4628ec7eb19422402fbae1794effe10f1cbec86936007dd62f97cb11d98c74c4f91a04aa29c1b9dd8c1e6b700000000000000000000000000000000040d6d86eb507fb70a4066b8a20c07077aa276c24d9faf427d99764573ce708cbe0b0945854c5207de5a37a290cefca81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ed45bb21220841e0b9ef7b19832770977e81447bf52ccdd1c7b73f5a8d122515ef3d0cb2e0652b457c1c3bbfdcd463000000000000000000000000000000001051359c9fc98d39d4de5e46cd33189e5423aee58e3f4a3a66b57a7eec2af9e97d3b3d420ce4a142b2f079d8e365b4c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0b371c20558206718a0456aa7637166f0dcf16cab7d960f330503d363513e58022ab43cd5b4e38608ac16bc78b94dc0000000000000000000000000000000007b11965051f0c6b573dc4e399ceacfc50c86f766f12a37fab3459954886a6649812915ac9e0021e528cc656ecfd294d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000692bf377b1c5f6e84836cad689cbf41800abfca0770a3f9c6a8c4d917e6d93de039ddee22e013ef05c6ae51c1557df200000000000000000000000000000000074f90fa9d645ec84a4681500abba428055eeba3c1d2f8ea8f88f577e7e7b0a261b2d2ac6fa799f5c45bfd31f7c248d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d0c633b8241329a5e5cdd13a2450db3485031b225a50fe8ce60dba9b496b5931ba7b3214f6be9d63c019186023c65300000000000000000000000000000000067b9d7e6931fdf518b10ba0c3557d4c16291e80ef148c4a2fd578a69ad7a094f2286a3b3a2b42eb8137df748d3b7e6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034ab73f7f8731cc42ece61199a67aabea2434724689a7ebe19533c27e0cc5b4d8dfce52be27f8892301fefede8f9a930000000000000000000000000000000017c1ee4fab35d9fa7a81ccc2eb9ea73f19ef394b31cda79afc9fc77a69326f2b16c805ec16e8d68cdcb3bdcaa16192f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0980f4c5dbceb47769af9f640cece2a80c6cbcc3058dd62fbc0d0c89e166354233635067c87609c011b5f293a21fda0000000000000000000000000000000006e77dd8384f3ffc75b97799d4df6a8bdafbd71803b7dae9332c21643194670e154d7d49e2f6adde178fea7b2e3f6b131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000355c0dc652a1a9afe66faa4e202f0ca12bb368c345598e98ad854c8e28813e91d4e6d7a29f47a7614a215e3748e5a5d000000000000000000000000000000001444aedbaa412b06ed6e374982b8e7ed3a9e3dd89807f5c94f19d7d1a6348fc64a017af639ede1a7bcbc9eb0ae87295b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b1d5ae4c22bc3ae8f024a56c0f35db6b7f38faf226cf768dfae0689ac5097278f6c63ca796f5f2b9c0d7dba4adf38d0000000000000000000000000000000019e4f92b9cc4ffd58a0e7e7868d5368d283ef337ae3a83922dd62e0f8961d025da10ac6313199f13a586cbe2610fe29c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd6930ed1818f5e86c4248ff2b36be4bbdc5cbdadcc83e5d3cd9527a7be7695a359e12ac1e4c628063c00604e68931000000000000000000000000000000000112c28b80e46d9e5492ed5adbeb66079f072a510cd27e580ea6a8f732a2993ea490dddfe573079088964181016d220e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130074006800303cd1080d212e330d0f17690c09c44af87c0323996b79644f30202dba6ff09a9316d9dbc9a588ea963e0000000000000000000000000000000008fab72f336753eebe20f72640a3b79c76dbd5447dd422b20697a9cfb2482621f038e1a1643e6f4c8b2cda73502c098e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001633fce7eb0738c5f70afbdaaa682f27bcf10236b74b3f2b08bdf0ced225e31230265a7eb94ddbf6b64ff750a59aa8f500000000000000000000000000000000082e32e526a6a950a0de05698e5637752082d52597e7125d2ed3b85ecfadac65879b9794a546078605a3537fc7e00e371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030d3b77e2185ea2cfd3c2f0f1baa93a4438f0551e240858e04bf47a48452f26b409f93bed7a8059e18d4ecb4fecba1a000000000000000000000000000000000e51fe174b701f7151d8a8b06dea7c80c99f6c5d091a7998c39d250057c05c45a8c40e5df09b39d5933b44feb727b4bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f51839e6ddbcc89082f926651444b4be14d4dd9e46d668406fa4d05332ffa442c8e2f79080d6ed3099fd29ef95bce03000000000000000000000000000000000e9c55c194106933dcde74c90715eb74c7b66ddf617329bcf06bd48ca0120d38155aed66668965c1e2547fd57320f1771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124dc87907902a30b4ba2dd84e7574f3358b213849d1e3830e208aed82ffca81cc4be62d3e68c64b1f4bb1770775249e00000000000000000000000000000000199b8daaf7017b6940fb96558e6de26cdeaf016bacc7cc181be448c31553df11bac7e674e25d2993cb7132b2b7e063b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008fff871d376f0841f98c53933819e0a628d6b6f3c95ab1c317b79f28dab1852a03806eadd1b3aa74d797beaa3f0832b000000000000000000000000000000000d073605fab40a9c60eb8c3363a519139a6b813c289d288a2b23dec47f755244e437561b045866076473bfb8f65131a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092b6b42d133179d029682d5cd22542d2c22bbf14c814a08d9d6fe957b3308b8a7dc3c31df1ba47820fa8252cfaa2a350000000000000000000000000000000008ac643c485fcd0cc7696481da467b54b94d05ff923865fb09fac132aa6e8845b59128adc9d617579aa799ef0b0efbfe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c34ad44b7326f8746c4f03abf6633a426095464b96cb410091f26d30bbac675895ccc0b70d42ec141cf8472f4bbc17000000000000000000000000000000000eed56242bbb8cc5c4ceb0f170de5c4b8180ab39582b20d21e18baf316f3ae1e449e1134d19dfb9558e73606afd955951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011563978a057d2790bb8fe9b2d12af5cd65d3e83d1778279593c02b4332d698bd6f8d43d4d8e9e0e2238a40134bde558000000000000000000000000000000001721be325f7ea7478658e65a2fcf9ee018c4b743a52836d4ce5745e6781c17346f120ed73ac8f01193c78f2958cd89eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d9a504755dc73585b6a1b2a7d6121e7df704c5d2479e550b012c5bb0c0143e570c561216609f24862a300b2499bc8b00000000000000000000000000000000017c07a85ceea839d4add65466fa57b1f70dccc5acc6e6e068d59ef4290a66c8dec61de72c793415ae1a0efdd36f69a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000712d668a1dbcbe170aedc8e6261b740ec74cc2b02d558fa628860a2d8e66f923be2e939e81bfc574f3d437320cbb06c00000000000000000000000000000000041c855cda274c651d62418ffc6b19843cf4349475a78d1d14cd1bb15ebc2096651df7ce4123e8d242a113b12219d5141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007fd4a5d8d261ad3edabd56ddfdb7ba34ff77f6619bf50bd611f3bcc62c6c01f917a519b21dda61e2a80a49adb39c3f800000000000000000000000000000000127b0d164cd62ec4f6c0732c8916eafa6fe6b422da0033bc80ee8e5d0a6c3a65b123b82430e0d487008963602794450b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000571c0031fdb10799569d024444e40f433d106708c4e9b51bb32fa2e68a8c3eeb81eea87ef37c953ec2376d36442acaf0000000000000000000000000000000008e6ad7b9da2afcb7153a8a384beeffbbc073e4edd623570bc4edf1705b455766d7ee87d99dc4ebbfd28e33e5f5cdd3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a985aeceea0cbea0db060af3e5d44d258f28f3cc2abb47212387634fc999401fc5feb9d6c6a10b277063d13e85cf114000000000000000000000000000000000e000590867dce6cb0ac7f22341f81feb4c6654086366f4456d502aea159bac410501b57fd9b43a89ed750978a6d6cf11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef1cbf90ce710ab6b41fd33ba8f723a9a877dd2f992a336cf3c4d2f72d8ee10444917841df33c4ea51a560a1c2bb2260000000000000000000000000000000007d42afa00313b97af6f29c7c436b971a1b4fe63023333dbeb21073621a9d1aa03897e562f5852926430035652fbb04f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045ad6dbde9da5b685f6d7dc10b51a78a2edfe476fc12e992fd3dd386dba78c7bd6326fb469a4754c007c3d83d6ea99a000000000000000000000000000000000e4a62bbb3cac8449c39ad99a247be5284de9f26a3ee99c0f98f27aa0c840906ef3521d79eab7db7690e2c7893cdc2831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001049bcf8e75fa9b56fee6cb36251da6248ff342954bccc3fd23ac3324c464ca5705571813f104ec9ac2cfa3cbeff51790000000000000000000000000000000008732848dc5991b0e1e7838140450eb6f97c0c78aa7535ab15b714e1d63556d4fd4eeb009cad4f7bb485dc5e1c7aabf71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090fe58e288b8428caf41594e646d84228ba2dfb9b6a1437a21d07b1b5e182919da570420bac6d68db41e740780e95be00000000000000000000000000000000040929cc25f42673d2ad3fccc101419a106e28b3dc982f01a7f350448b5b745561e59d18a000c10969c493d4d9ae94c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc41bee11269a9a5ed0ead2642f887f0daf524af7148b802f9b14a3e69bb828a135437613ee6e2652a4396f57da791100000000000000000000000000000000053ff390177eb1cc3a23ce37eed4c4548ee8000190e6ff387d3c6b9d0a28ab36b0c376be8bb5727061caf8de0c004dd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001216eccdb6a4d4c61e6bf241e9ddbfe8e0e4ed08d20184f5c24cc9f4810d9fedfeef229c161b1441bf0c99f47b36fdc4000000000000000000000000000000000eed8866cc67afa6506695bcb14aef302db96424a51603e1f00f011ebf0c6923f0520cb114131769926372ec0d7a806e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed0c1042977811663bf1d525b8bdd47e9b03b314674a840309df70f518353fa044b8086fc61eb49d64a1e3727bbf74c0000000000000000000000000000000001e4c45d3c1107f58a41ce9c553e8897ce6192ea559d66178f54b9826ac48eb1b4dea328b81864dff854501bc40a3eba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5d9c689bf0008a826963c11142cfe1d738cc510ee476ef723d06999bd72e052ba6c61aba9c0c4bc56a399041568a450000000000000000000000000000000001f955adcbb01aa50f81e1e5a3e089d26a360147876ab4a28640f33d8be39f33f2e3d430fdd1ebccf6fbe86b355475581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5f4fda5c986f362d8de4305b61c1fc0daf2c04601499464042285cc0d35fb4f46a777e7a4d6e935fbc49611ea620d40000000000000000000000000000000004096293abaf5943f6535476b92682bd1531488a3e8a4a9fa7738f877788c172fa185306a34b82f83474181d0b87c98c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009096ba37dee41a8695ff721e7c6a0f714596f254dae0612819ae14a037850c13f9e9c5aafe4edbfc4ecb9d89d8fa37e00000000000000000000000000000000068cc4712ac28a8db9d3eeb79e0d72c2646a31349d8bde9562eba5137d33c1da2a45d065d2584b3bec25331d14d7c6001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e370aa978a717492e2d08f1006b9c04287d199c92b1fd7014e75aa075d72aeea10b89a2f326ae2e174d77ec6af2524000000000000000000000000000000000a820bcf80628d179135abd412993313ffdee30283e1907f67f37200913dd1cdb04b50460918134b280fe7cd5115267b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085a6233e328b2517d75b5cb8c2c53b5782f095e79015478624eda0ed338aa07c7ef287c37c7a15662c26e7b49f1d615000000000000000000000000000000000388ea5bffbe057bc5aec3a15a035ef29935df001e8a6abf01b1719767ae39620d3193c87b9ebdb8b176870c9e75e9301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a2d6dbee2f182ae123bf064f0231a314bbdfc3ad46adcca7c25218f784eabae814c6de9180bff76ed4188c084ed58a0000000000000000000000000000000019cd3e1c87f1ece124d5e6bb3681c48779f9ebb215409805e6a926842cba22750f4536be7f6144ea57ec51e798facb5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055267d6e93d635e5b7a382bda7c14853cf964c05c81effd0a7a9e0a0bf947f382bc023fca481d5ecbad49d2411660e30000000000000000000000000000000013bb88834b0037ebf65dd15296ea0889a393d6edf53300f2c53634509021d8127b33dc9d665d15635c5ccf15e5bc3d7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005684292efadcf43de6665fd2410d3b4b073fa5754dbf4063277c9ff3d36d46758344f8d7e59aa1861527e958d440d2600000000000000000000000000000000117938f23a121ea17d27b8a57f0aa4a73f76be2b9fa5af46a38dabad187087545e9f1463263146149abb3622d3faf49d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7e2f73d20113702d1c95bfaee5830aab022d7f80047bddff912a884da2a538bc9d108d607ac8cffd870a7c9fa5ca4c0000000000000000000000000000000007622edcb2c84d7ae3b0895d8eeab5d4b4a7a879b1dcbb624bb6148be6580057887db95605d0b21a9c858a84b6d6e7a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e440b2b4480a19957095e7e884eb29efd6f8949114a91240dae77464c437c79b5a7fbd3f59a83377679d948dcf451b000000000000000000000000000000000cf68dfaf6ced5a6496984acda652289da71c86f385d1585cb21297df843faf0434978097407c9d03e30137e8f30beb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a195cda7a60e83da8636e1bf8795cfda7e49d2877346a04bcd9a99771a77cef77dfaac0ed3deac5522b1d1988259f30000000000000000000000000000000019703a0ce8a51a72b5bb31f494a2b934345ad7629775b8ba6f4256b1987ab7f64c9041b370255d9edb3a07f408005aca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173795fc5219025fcad0be04873b66e271a6f2d10d62640cb10e93c8bb42a74b203115bc85615aa85f9b5a13484ce1c800000000000000000000000000000000126fe23a8acb30bd36264918acf16d9676b466d8e4db1ed1c61496ad05401316462c2ce4ac19bb35e3812ad21974965a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001796126de82544616a8e0daaa1ac755312c301d6410798016b32d8c57b65b1343afe1d8aaba1f0512ad028d1545fc0c50000000000000000000000000000000006ce0af8db44d95d4686e8dfd2f2772070fad8e8c12bda55336443ceaa9f6ac12dcc8acdb0bed889638fd6a9a63a0ac41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c003e819754fa93590f73b567c35d6531ef649a224d7dfb4b40141217e398548f9fc88d2e724398355725b99cfad8c000000000000000000000000000000000e0d7441a592da8bf1b56f89d5549042093f203a54da638aa071d588fcbfa9875e38141c1ba6d26910f0d958c5dc5d091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001968aeba818b7ce877725b3fb8cb3442944e7d12d71809d4f7b34753e5092b467500acdd59733bd250e8107cea36c3390000000000000000000000000000000017c775964c6475866322633bfb100f50208b667b951245f41a8a361e5cf41db563099bd6027c3b56a91071638f9e221f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163e5e026c9adc51cefabc991079d116796c0e625b891bbfb51cc57f4bef975df47898b01a5b91e081f496078106a9e300000000000000000000000000000000143977f45e579b464ee22985eca3f0aa257e506eeafe185453662f215820d75f6e20587775329082fc94874ed16c90ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001070680f83e6554530be517747be1cb367a40427002d2fe4c74f982e2e74247235940e28c6f6c2e1b4ab29def63895ab000000000000000000000000000000000dfe3f610b119993193b10b62a86945b6b234220f4467af941d414b2934dc8294b56a7f02e6ab02c2d4ae7ed11e5b5a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5085b2d455ca2da033a8cd03f1ce8badab0ba2fd968e57d5d86f927ace96ba760c917515dd18d14d8fbe4e7a7be15b000000000000000000000000000000000346d6add2cb16a50cfce28b3aae66beeeccb463d1b92d258d5cf06b6f3981d7d87cb20a6d80335ddf6d18c65d2a93501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc469d47861d2e61f15522680a5051a4c0cea7569a570d8e822bdd4ab43e741206cdb4f1873fe485f55cfb016e0b866000000000000000000000000000000000c000300a234fc5f160e7e41d050d592867772f5c051dbf8c8efdbe6206808563b94b2fe76c327b16fd9e66936132d021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014bc9d6e66dd33d8bec3ba38e94a4c876ac2204e4a0a0f07249c2f4669b2e76f969c69732f0660ad4a8396172677b35e000000000000000000000000000000000c580810b033b308a0ed3854be7fef74770056cbc508b868ead00fef512acd7a3df7b01426a146d0c7f42922322d132e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b40ce2140196395850b8fe8b295e0037f6d84655c5d6ec2749b556c4a673e4e0c8889346216eeaf36a599bc7c149d400000000000000000000000000000000183c3e32492cb1af03495a7be23be07d2e868187477dfa523213bfe54f63a3372fa42666fedd316925cab9e3511cc70b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000865fa2918adab8e8ef9ceaad21181e055fa56468906cc70f4561b391bb81e2fc6c2ba2cb8868183e80c7a6f5b2b9121000000000000000000000000000000001523aacf75a1d07747eb9c5b37aa302777dccca95346e5e836ab506ccbe72502c75055f74e5a082c9ba54f9e36801dce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b2bfd0ee491183ee659501e3661bc29b0f862fc21be9ec8f167fdb37f7b91d9765a38a5ef6419529c8016b46b94698000000000000000000000000000000000b93d410bd4353b04b97068cc45db00064180392d919b64fca0f54e5484567204408bf8bed364fc31e3aea738234b2bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001017eaf9312a6f272a8b0f7af3c9f41df13f4d029b9df87d8d325592562d37fd7719087596e28685d91bb9fb71b1926b000000000000000000000000000000000b5f8b51b6d8636d33b6049d6398de5f1f615abee6d7827683d4eac0a8af00a4cee5d7c45269a88ed3880df6e2df19661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009482bec00076421be6a00247b40510e2b7cb78967b16659d95ff77b837a9d474fe5a67441acfc180e8bb672c5cd4da2000000000000000000000000000000000cc00cbfdf5303055df6faa42f619fa44b35a1ab6f8bc510fa8a8309c5e4cbbc7b6f09aaacdc01c7b9b060166cbe05501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d7dff24e51c0d068392461c688d9dc2b3aedc118fee8f0e0d00467fcbd2fc8594d3bf658fdd83ffdd028bcef005c0d0000000000000000000000000000000018c4a95917fc4964ad68ff3cedfb42f28f3d4887d31fa4934ccae38af85d5c5b685df87af29a84e98e63b75f0f75ab4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052e41463a212b2b7ef8dec1c118160eef1e72dc0c5e1efffd35a9e164c8890d68d15b57c41db7883e84b25c8e2f0f2200000000000000000000000000000000025cd2480fda96c3763e63c7fc7654be0fd96e27b272ebd0f0138a88737b3d089af719771aa85c480d73861b9199f3261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d93fd2a09bba916090c92d8906fb5b8323b47794334f7dbe354d982bcdc03c786f2f8c748010c8459f44b8da559a8b0000000000000000000000000000000001658ef67e917692396da86f8d8b357ba24ae7bb8ba1524a7f1ca2a560c258f6900e8fb48c4c093ac1033d849a60ea811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017645c46479a4519c7af6a1bd9258ec5382095f218e32d1d0836ba24fdb343763272ea7a4c355bc3b53956e22e53509d000000000000000000000000000000000de9ee904483bddad4db59c9f5936c91ac9e4f12c89d18766ae217de3d10a8155999b75d5c32bd01aa39ffde7110e00d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b501e9be7fb0d482d08e03673d28393e72fba2c9f3a0c4ae8269bf6b77493115de55b154f9bdc0bf54903fd3400f57000000000000000000000000000000000b3637069e9cb8e157407d8280e8e187674185626d6b2b7fc5d06205ab6fcf030c95a84ebb70bd1b575c4e38a1837ce91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec1011168da8c3867f814ebc5ef2039d524927a64dbe929eb0cc98aaf8d0c23890a1219d202feb90fc22e000d4eb40500000000000000000000000000000000088018ffbf4f90d97367e3981e66a6e445254479d29791d50d06042b4412c55d79a06010948e62359c8fa000c5e67b711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000196be932cf504ab83ef240b768c77b6c0648e60845ea52547b217cd62bca574fd5e91baa81b348b926a0c1080fe983440000000000000000000000000000000011cd458aa807cd3e950475520af9ce84e922d5dc8c1a17e02340cdd29c19aa8619a9d6a7be4db5554d980c2793215eb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d44eae9233452e0b9fcfb36bea78d228b6c33a94d15ff6442de0369ad3940ec4635a36f56a1b9f4aaceada0f76535920000000000000000000000000000000009737cfeb396c5b577338cd892342f45206077af456e552b9a44b9149c379daa0b22dda5b009d762153f26f9862391ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058567c7196fabb31d8a61dc2f925f594acf9b9a365e94034f39fa5766dae1660b30225a81b4bf1c921e311333de6b2c0000000000000000000000000000000002cea39ffebb2663e95a67e46e8b78a00519f3f2dee9dbd3cd01446e3fe653735ea48ea30ad6c6aae06baf7a78e46c661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195d2461a86511caffee542888bc1da2eb85254108bfeed7deb1bde1c66a3e5fb723b6ef7567c47d0fbf3202a788d9e70000000000000000000000000000000009d9749340139e9b3e658ef0636e402b783318e551e376296825e3115b961c3db1e623114f685b8c32422f092811b9301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013536f9f4d7916e6fb9ea555c3f47bebc36df4e46a34ebb27c62f3eccc33a8a426853e22158d2a1d6057a2fdf207b6a30000000000000000000000000000000003171982f0dada0f6bce712d079a428c2956a4608892635057cf87f995c1641e9e04b9f48c06864e74020cc8456dca8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001968f7371301e0d5bd27da19b7b558bf8d599ccbbfa25d7c41a59ed3202717f135cab52fb37c52611ade4c7145662ad900000000000000000000000000000000053d4b2f1b36fb22f01fb812b0d37addaa1504089cd9985266d216adf9f269be1234598cb6adec72cb0a2babd2143a8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f16a28e6abf79f88657f75392f98dec34620c5016713abe3199d9fa4eb3256eb74bb8a6bf79567985122d9b8eba698000000000000000000000000000000000e274ad2fe795b3e301a561432b5ddff85037fd8d8d32e96e8e5eed92a74898a95c115607f6043cbaa19a5b6949800411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a17771cb54e5775bbb61c02b6e5b4bb19bd0c55ca3ae0182ada7619b37b426bb3f1a30e8cb062b7fcba0424ab1ac6a0000000000000000000000000000000010056a77c0ccd3069f5320fcd1618297ebd45ccd132dbbe3813379c1ed2d51e8149af082bbee560e3df59497bfe1bb641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165508b6c7b1560929ce24e28764eb2de7d5c82bcb83706bb13b52fe637cd31ad9fc443b76362dc1bb071d5de6fb7f4a00000000000000000000000000000000109d6be605f2e257f42360f2f993a0d7625d292ef06b09c2b3a5cf1d8e94ae7aefe0566bf7f8116bc9b843bb8cafda6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000195b2c0be0a515c3c8e7907ebb994c2e4cf4b835d083cff0b7f18316763ec05055602263b5811ff02d5f6f885fe425b000000000000000000000000000000000730c0c8ce4ddc9cca60626a4682f483f67b920369ceca5c27a8e9305c21e5abb5e75a2c001163702083a76d1e54aa671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b076051bf16186f01f51a7ade47aba844e5d8c32b0a2572d8004a23914fb60aa277ee0cb0afb253bfb2ecac89f77330000000000000000000000000000000006e5e82f6871b37f5d06d4f5ae1932603a79f118e77c2666682f79e4a0e79a1fd92047984a247f9634cc4d8d7af7e4b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018717324748f996c7da373bcb2b82dc85cd4fc0bfb2954645b1947cd0bda629a3a7d37882d543ceece0ee1a513d8c88d000000000000000000000000000000000eaaf23e343e0c4a02c5303ad2c89089fb465cf8eb782e44bf5b1bef338f91410db399510a30ca3efe628a048494cde21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058f96b9701cc411eba7ac4e5a3361f3fd7aa42c11d08c158b73be4e04aa83a3978e59c68dde2fe00f2a3381c4daf3b90000000000000000000000000000000007ae03634c7969c6ec0e6644efc62cee5915991d6b3a1160678baf00441c756cefd255c41f890b9546ad993eeaa530f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ecb05561c0b37110186848008fbbc3accbed4c6016a749556118ea0df45e9c1cafb91f931b292cfef050ac3190b847000000000000000000000000000000000b62fc7d2e65268d1842b4fe28116b96040d2abbfae6c23a991321b30981326787f60e5f6cfc8a828fc498b7160791a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db432961a006ee2205233ce23a800e91e9fd118bee6ee79a7d1c96b3df8e6931690ed58342dc5f6ca971c6ccbefed46000000000000000000000000000000000e4a4e90d39200595e83ebfc75b62e941203684ca06d594262894baa24b83d1ae0b4a6f92854520d4cf0023005170f171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f14ef95cd019af7fe1ef7ce3a4efecffdd9fcc88ec5e50b1498a431f9287a078174bc60fc37ef1261adaee5c21c4bed0000000000000000000000000000000016fabf8a4bb076b7619588f328deda563402c0620727a8047f75aa57055433450f0c2e93956f837f6466a4fcb8e7b7441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014453d804fbfb2ac7c1c55e86dbd3423f814987bffdb6cdc84fd30703f12a1d19c53f0ff2019cd880caa7d6ecbcd0cb4000000000000000000000000000000001183f2ab16fe9eef4a4b70d8ed8974d1eb555ad61d524a3d5279a311e80bcf2c2c9aab8019365b2efd9a3cc3901b03d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ab0aa8e5ccae66fdf35dcfba4c4028d6e5b8af1799cb0150f53e128c368ef8da2212a56ea5286d6b06ef322ea26719000000000000000000000000000000001789e48cd3ad5c6f50257b649485f016f85c4c73ef8c4873656bd2a49306e1661ce349627b7ac615300b760bcbca04241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cae2bf1659d7dd9a384d75b3b650675f0ce2b213f375cf61f4455906fe2c4d7ddc6d6a84757ae5135f3c42dcbd1dd730000000000000000000000000000000006c5f4ba5a38077762b2a16cc997f47155979fcc07c29f4a6b56234b1f37a4b0d90ae6b83838af3ccd2679763c7c5f191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f8236407988ec1428b6395718aedd125cfe98ef37ebba89521eab8a598d682caac88a641209f4fdac9e883eaf6c27a0000000000000000000000000000000013d3c352c72c31d6de2cc469b4c5dfcb3e36e4969777944a4e1beb42a328b3560a8b3663ca7e99d9afcf83e1102910101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f63b952f9e60a765bdef50067bed6c1020c980c2afeb722a1385b424c5fc79f797ec0ca480da34ed2f04857e0d1b0000000000000000000000000000000000057938dee614b947d2d8af9846255644ed3bf70969b05f4e29b7f17c2d1050eb69dbdb9ee24ff1a79682cf567c5d2a431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f4b7331a961e3078c6974b28a49cb4956c44a9f366042fa9ea071acc3a8a14b28353837e4d89c986e5aadf2eb5ebfb00000000000000000000000000000000059752b5bddde7c3956b3f1f3d21319f08c38524963e738fc7f72fb0c84dfe3cb84b6d53d3ded9048d064adb6936f2831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136a0cf9a571869fca267186eb347ab24cbd8a7fce5d14eb07a53b064d0c04dbb899f83049eeb03720d21a93b6cdf6d00000000000000000000000000000000001726d2ee5793b23db417963e64c80bd72c7cf8c1becf1c9fb155d2a4116b91466f572f61fc54bc6dda7a97d3d30c99f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017cf9ee32d0e9cba8266753fbf374a317d5009731bd390e5a31f9f3e32fce8dc3f36cf9c08fecdf32ac55a87d72a50e40000000000000000000000000000000005c550515bff3bacacf6268558a9dd0045ff581087df755456c7b6b3d3e0593717573fb2c9859268f0aafe5cf825e1401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000490401f13da73dc5e73b500349ad5251832ab2c132ac46dfbda72e649d17eb90ec8e506b66c8759e3d4a59b0c8f6d3d00000000000000000000000000000000127c82eadb70618bd9725156e7ef9472f230f981922b40fb9841822368b4cf10c8f750268c8a13a8f3eb489bc895d8101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f6b83157c648209d8c57cda768271b21994300461a609607e2bf71585539bdea34bd89cfdcc391b1cbd1ed027a6628000000000000000000000000000000000edc14ec7bc059170164779d6371ce7fcfd833e3fa0e5b1ff7bbb55b7dda893bcf946c33bab3a3b0af1f48df3aea68511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000090b0cf059f9087e247cc990c75d85d6e90bb554c9123907c5461c85ede897b0d2819ebb11672f205175eda4d2d96bd0000000000000000000000000000000008403c18c972de72396a9c297fee41c195d74ad51f7e3e409de564ae245c80393d49a9ceaed14b08a57259be06e7c4331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a6b6a9c392d19b59998facac5cc6c69f9b99111559af43078e113da6d6ff80e086de98bc61e0d1a71833802f065e1d000000000000000000000000000000001995e63570cdfd9091588b742ed7aaf6ac574907d58037f8db0c9db59eadbd9bfbb2069e1b957eaff7fe79d8845725931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000046bbe94965d4b5e111368529757ba0dacef4570de9777e17cd3846322f556156e170db64568fe8602cd14f660079b1e0000000000000000000000000000000010d92d67917506b90f3d27e9c242855cc5b3341bd2e6b57014f939df8f63fe02731f540fdccc954c3350bb774a2f8a991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006fd18d851767afacb5430f921f39d72c7638992bb50ae95d2670e17cfb9e931ec527b49396b36502bbaf2a00034dfed0000000000000000000000000000000014e384562dbc2ef409c09094caf23d88803f9c13074f747c2256277b545a3891eda292f2866fd5e7f8056468dd7857a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b5e84a6a9ef0de15551123436bfda5000460117b9148bcca5ed719096cb10b81bf6b310be90cc3cd7c0a22bdea59a60000000000000000000000000000000013771b0b4ec65d56a912fd855ae2cad38dd344b8ecd6003ca0a21daca4485c93be32258cb482bf97519a8dca5cd997591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001256b7bbfc139f1e0df1153eba6e15d22bc9dd1a95959b409c36bf1112956499f628c13aadbad454c3333356b90adeb800000000000000000000000000000000055ab42ed7b05843114f22af1b6419bbe85d19213050fe1030c28944c19c8aa9d0b0dcee323fa0fc529c5b066f9be42a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170ebe6e34b6b8609fa8119c327b002445999865006a1f8108d11ba4faf49e1c28f214bc5b44311553f01ddb92120d9f0000000000000000000000000000000014e3cc6fe5f50c328706d3981ea483978d102a25bb4654816d972175a640fa20fb45f86e784a598ff746f64032d6985a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a189c1f374024ef70c64e3ea708a6080a82917e518be522c92cf7798de8569cd775c0b5de2810864cab8443f5ccfcf6000000000000000000000000000000000424bc1c9acdb55fb48ccbd9ee42f0ed6e9509ae8d07f028e444e52f3fc4fa6d9eda23dfd5dde256fe63d66da51310c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001444fedd7a4851bcb86594cf66449f5c10851422c409baef41542fa10196fa36519424bb3484d6ee4798bee8ef47d4c2000000000000000000000000000000000ab559465b0a9a263e3946222fac471c257b6394082b978b5ee9a0357602aa51a63d4c107cfbb2ccdef872115e6739941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b9a331f3e22c702d0f626472e1b6eb92382d26e2b115f2e5dcef89994a721ad05eea962e880442d9033907160d168e000000000000000000000000000000000af1e3206c787c35035689f0dc6051482831bef48429d4aa5ecb56c30da75f05d2b22edc59d4bacb20117a8852a552341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029efbd7a80138e7ffd86248a6b07214ba4c8bf289d0006d8ef9f8c4ed5838263d189dfe09d71efc9a77eff4ce84ce2b0000000000000000000000000000000004c75b773eab13527323b31c485396d7206ee7ef76524b81ad348279258329cb275842ff41d25da8d07f82eb72ae55eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002388d889ef1f0ce358062dae8295db3f5932234521e89ed99b01a4431b3b87959f711a6d7e879f8b121e23a9385b2440000000000000000000000000000000001fb2912ad78d9523895b6099631e3312b54f272f9defc116225fc8e3f4a23dc2e330230202775dd0710d6d54cfcd3d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b6bced2e14a33801f48c41f9c60cd7ec76816efea0aad0496fbfd40966ca8d2df45d4b30271b03b290448c9ebd62140000000000000000000000000000000017cbd8abbf1f17d869917252b88dfaff433c36740a97b53d85a74d043c7dd333f8e34445a76d83bf30fe5664f00bc8791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000412d88f8114e4d499c408513965cf851f1bb278e4d1517a93cd7b16aacc7eb3255de9561a9e443d9bdb23753290ed670000000000000000000000000000000000defc87f2648ed0463a5333c57d412001aa7ace114779347afa4095078c1743934626bde7393716b1968f4936f9e5a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079b7e119a2716def435e100871130cb999252ae47e0ec5ea3b39399a22eab06959da516cf054cbe8e12ecb6217b6089000000000000000000000000000000001956c25151c851a61836764366e68a8a94b19b2756de31e088b1e1aee7baec41bba223d61ea08b9fde3ac5968f9435971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001667e291c7085f4f5305960f20ba1aab9f4293d6df23f069b0958c5166e4adbc29df7f775d1c7c3d785b739622fefdc5000000000000000000000000000000000617bd1af62f2cd28aeefe60d4f0b0635a6c604aa67b4adcbb962e61d808c788f47f4777b971b3289f72083935756a3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082206aed81e0a71ec263146c81ee7919fa0749a6279723e891a2c15ef1d2db8e99f51126ae7236f177dd40f4ad81cbd0000000000000000000000000000000006893001c309bc017c468d6b40632bd039c58d99016fbf6cc8c93f2d04ff7c7c771f722a9b937d655999fbda05a23abc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ed7f0c4d58dbdafffb3d710491a20e71d2ff5a73a88278f038026818986c6754d6cbe862e0a0cca21f574661bc24af00000000000000000000000000000000096756952fcd30a77058f37dad6e80ab6427baad2e82bfcf647cd07cb5a1216e3544451ebd49c63c5da64bebdfe797b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfb5528e305af44841ad78e9e3005f65daf7c8b4301650a2315bc81abe9d603b518ed77d8c0f3047295213aefda72130000000000000000000000000000000012d3738f4a4bb366ac7b81b4127e76eea4b60ea7e94d708aa8be2a02bcaec678197689f500e43f9301eed2c7099497481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f71c567f0e75eda67b76627b57de16da316423dd76825960019ea8dcef44ea4a6ffa8c349bc56ef4bd229f7f09415400000000000000000000000000000000072dfb67eab9147f33f69981e70f0f755696279972a2f220dab2d03b9d20f7badf428156abb2d624cb56fa6531aaca6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000036a5f85050a4c19ec8e571ae4ce1f4c7a85687db6263d867d012760194c85903cbf4c921378f91e52f7895c97fa2d5000000000000000000000000000000000a9fc6002d73ba10eee503066a57f21fb1129bbb2786c55e2cbf22a282a0716c61155b794ab85e2cfb9ec43cb3798ef11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091f4a425c5dd7d7c417602850d8696a1b6b93650a1045c6599bdb42fdfb5a36bd6fa8bee427bb698ce0392b56ab01260000000000000000000000000000000007b8e459a68895739cda3d1064b2be478f620f8cec83be70d72ae7a09387aad280d063b63bb0975f93e9534ae285981d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a4811d1529c290f23d306c204d9a1551b1c82996ea6bba9e4abe12b77649eabea6a671abcda6e45b8143f6ff9966d20000000000000000000000000000000012b98219286ef575ffd53b8a30c2e126ba7cf98d59df2801ad8d9522aaf8621b02a4a97e2a296cb9bf4aad2588a75eeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2ad4aa6e75762b2a63ff4828ee99af1fe7556e7451a831ffaf08c58f07de7781015cd4d61776863de01f89e3c7521a00000000000000000000000000000000047ac48835ef62151e9398bea0fbe7c895f798cc03f6988c2242d1f4fc1ebb5c670afc76ae43c8b201a6f473f03bac981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002414cb45041d2dc3bc3ee62d6895baf05c4df98193be13a7a7f60450049cc39f9c5f5a816f78b7419726498ad43d1fb0000000000000000000000000000000010f2a5c1e0f523af84227634aef8afa6c3757c9de52046cbb511ef5c4b218b06d25e662f821513fec64396bafe2a06971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014427895a5b87a359d278298c58b00e57ae2665bd1d34adf52f8fd323779371081c105e67e66df497bb535ec77abaad9000000000000000000000000000000000386f074e0f6b0d7c3e3f5eb751316bcea4a17142f89c17ebc7e5fafeaa8be3724dd7c792330c041a0b700bf21e472d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001187afff5c060b5bdf044fbce8659be0db6f10adf35f6fab4576e4d17d1c49cee17f338e34bbbf88ffae73a1263a70a00000000000000000000000000000000032f2fc39fb5c3995d27b991934396145a2410889964aa700491ba6e5181c7f621fbe3a8a0b11304d281cf5527ccac6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000038ccef5a2e4b7630bbae3625eb9cd99db637aaf48d5232f6c5e8b7ee9b49f994167454398d0c63daf8f7978631e0dec0000000000000000000000000000000010d3b8b17a6f64237ca23d1ba360e40aee80f0f7284ca1322b19dff466eaf47e73b0c2d099cd90b420a480d1d8a0fb921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016819bb869d96d0c0d919155bea40ba6bff378c6ff49f108ee89426b4087a9ffd8c4210cd5624c52d5ba112a2c52a0df000000000000000000000000000000000cd01bb76c7a572437ac4f2c43bdc6a2abd512bfdc0949f3221a673a731e232bd6fd50e94dc2a8c1f65ba94ff091eff31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071d16f494cca29df2deb5fb1de585b701741b102d70478990f2c9dbbe44d899986200bad1a97528894bfb63738567e70000000000000000000000000000000002e9495f8729db545bda1a2b44e18c78aba1c5c29d10785f27dc853a234bcd2335d92577731bf73658a0490f7ea2c5fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153d6c0168f1d9581275a470b4be0ef3a69cd85a6acdb3b72479697f47e9351a90e0f7e91dabbb2a361bb01e2b3541810000000000000000000000000000000004926ed58cc1693485517e23c6fbd45548df27736f57c6a6a40026b7bdd557f8d2dfc4ec1c17a1f472d7b4f3f2da54171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e6ccfff9087dad4892b1881f0cd76ecbd9510a32ecf12ed6d51f1520af7a6ec37f78004ab5c334550f6a262c5e401800000000000000000000000000000000167cc603de8b7892fbd80d49450b740c29722084ea455f0a7ef041913438afdac48eb275c5cdf0830bf9005d00ac32351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f7b23ecf9de352ef23d66171f813104897a7c5ec5f736565311741d25f77dd318d20ead294791f812f2c48b2a9febb00000000000000000000000000000000171e04537c1833e5f31812adcb23e62b0ccf2eb61f2ce391fd7d5192e80f93dac78cde29d483ba5300516d4084dca83e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb84a074cb9f11b40013ade413680802d08cc4d5e58a3eb14937c8105fbf110bd229dfb3b335e981ceb57cc2572133500000000000000000000000000000000115239b2372b2a34997d7d216241dd4d639f1ae57a61ba8eb32d808efbd615b8c43008e54fe9ffb513baa831a27a4f9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001962ef21af82f8cd4f6bc6de3bf61e79c3d05c38a126dc61fea5cb1ab5745743871819529ae59990ea051259973e7c45000000000000000000000000000000000c772de569e55429f955730ca6beb2009a0fc65ae6e4eb8a6ce4d15775cbcced19d81cb1f8076eb7fe946e649fdbf84b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba2e2c4b28d6fe3061eeb5cd89df8624353f8c62cad5f8cd015cd95ddd86a2d6a9ce13077657ffc9597cde565f150f600000000000000000000000000000000022697ee91b6e54a2e80147b8e85649ef17c17e4b9df1302a76ad0cd767f36353f40a176a59d237ceb7972736435ac5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d591963945e5d73ee5fe37cd2da52695858283ef1df7a05867ddbab6519c47d8da17c92b6db3ab8059d6f94a3ff789000000000000000000000000000000000ba23783ba1db7f7571c7c0b039cfc218bafb9a6ea2de2676cbd9f06dc4c2dbe828ad3eed8c6532b8846684e77a340091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a793c34459307d018d4e6d0fc3d6a84fc306a170b039dce4f31df709e51cbd23a01a45c37229ddfbd848bd32288da1c000000000000000000000000000000001432e19b43b130c2bcae3a7ecbe0a1ee8deac081ef43785f24491b36b7b0b43eccbe35e0fbb64c2e624d028260d2cc771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000226d95b0080b5393ce69055e344fdf1bce9326d3d0abbf132d6c2bc8176f752a9d3ed44669b2c5d3eeb539854864875000000000000000000000000000000001311213bb526e9efe3e8c04811e4b2712e4a6525a176737401b0f9b23ad75cd523ce57f2cf544413567fc207998b53e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a99fb521926922d98ca0521b606f50367a7175735e1c842d8064bca6fd351de5421bbe8f73b15bd56ab8459f9f4d56000000000000000000000000000000000cdc1cea7f728aa712b6817a82a230590bc53c6a38a685790512ac4b452d080d8d93a8ee9b1db3c94e9156ee2e172cf41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011873f043f42c2e96657766688001de8bab46421033ddefb6e1539ba72024ec28295b37611f04ae848a89f3a3a093d08000000000000000000000000000000000c47d461aad37a7213e4106f136f1280995b56343eab58f62fd45510ac35a2333a97829474ecdfc0852a03fd1b9884bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dcd5ea04c9307c9e10bb61d7f3540757930238c7605661ad0b0894a6686b465b4dc02006d9cbe990b5867a752574c0b0000000000000000000000000000000012fdbb1383d29e9b7668cde6ae6e5674066245497019f07869790633f7707771fac2f615e51b07ac68c95aadd4a8218e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027147b01d53738af34aa3dd3314841c35d35a11d90bd8fa84121172d3f7728017bfec909c31f68b4c4f24f2c29324aa000000000000000000000000000000000a2d2f8f868c0dd6f70a7b0dfaf3e1de13eb4a7a41eef9067b0eccbd4e27c3b65f36435da3d9a4d72be91cab03a645e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001726222813603f2a2fe7e4ecbfe1fa015a27025334c759b483d482d5572e137f75f819e29e86edd186fdad37f04e66d00000000000000000000000000000000015d75a5c537761d4f11fd5d231c555f6acbc1da24213c14c4d400748a0c8c3a6a002bdc94fb9f2238f6b70b8451304eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013140f8d0a64463828e8dd9dbd967ef38e5212ec9884fb3c196222ec962e0d53a961e35de2a05c327e0df33d9d7ad280000000000000000000000000000000001884820a4496d9ab0ba7fd6156daa99b864cb06e8f5ae3fceb2327bd6214c0019021bb68db557405e854a0e953ad97571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf0098f1a0f8ce55e4957851636c526e3282559ad9b14c62da94a637b33f9a84267bbe2f0222d988d83457e4426fc120000000000000000000000000000000017f9cea8edfdfc46ec9d6e701aa9278b0ccf5c4224eadb58cf7828f8d717e4efd7f67f1ba7d93ff410d8bb948b20837e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7bcc69e4291a8535ef99645260425dc3d22c793063a5d227dfa4c627cb71ee4792a072f6757babb9fd9eb99c42cabb0000000000000000000000000000000011e7bdb631bc280f6424fca344a5b91081996b88ac9b3c6d6a06749da370244be698aa137debe419ed6bec125b1a6a481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033bd57061984faeb50bcfba33e49855addfa9dee04497e7ff6b2c733b081590aa4f5a05d684aee591265fec24c8d7100000000000000000000000000000000009af6ac5c732402831c8b319fb20bbf59ed83ca7f8770e5bf2dfbeee9431aba0ffc079a6b30e9e4c89894de8e13b62031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001230473aad671d7a062fd993c311ff3d16725ffea4238de73c40da753e62ceade23b6d12ef8898c3ebfce050d2d964b40000000000000000000000000000000013a537a1591bd440e178a753330c0e330b6a79d2202b7dad02c5a78ecbf0a8a891c0553aa6c80236e67ad4e0a47c5dfc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001314b1fa89fc3b01b4f23b9d72493667489e508b218b3fe75b4a00c8f2564d8a6d6c05bbe3ead439f1e312d014765141000000000000000000000000000000000601132bf5058cfe88131628fd28321c5c8ce72b5e5ae2696c55a391c1bacf4f885a15261e83fe7b4a834ae9d2731d7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dc8650e6b1e2bb7b44b2d7607d101fe9b2ed0f3e8f26a972b6fbac77ffecb8e96ce9082618bf75fd5d977a47f79b010000000000000000000000000000000011fe7474810e706df57f40d6d976e9ae14532c8e9780474c2874725e741a9422674c0d54ceff8e96aa2dbbdcb0f029551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e940a6c8cc619f868234fd74874cd5b181221a8bd282e2ab0f690d3b00a66ab536f8067499fcd53b0e0327782f18ad00000000000000000000000000000000021d872da387c2e57a416c2afce59a5d81677a8951fa60be8d1236fd88f697ae2783e6fc02f4ea2f4f16035dfff249071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be35e271696e4037ef82226e26f561512caa6b8b7bcbb1a0536c8af81bd9526d8d74d1319ac3bf340886b1f6b0e163a00000000000000000000000000000000102bb876f49c76a3737ac243b877dca91f0840e72b9ff510f3245bbdfdfcff66c3d9adc47519ea9db725b56e609b39631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036b4eab67c87e49356842a48989dd37afcc1299e92ad181efb67f754cf4fe389fcb017ccc53e0a2fbe7c94666a21ad900000000000000000000000000000000163f4ff13243987c9ce4670c30a1e8f50ab0325539375d232f1f603b46d4520822e7b6893d85a50a9e54e6cd6ae807641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000438ceca6356c37c66d7ed674e474e65fa4f2efba2c4d392b5f1182dd9f4970cfe3f2bfd9c78dccf6d739151419dbdf8000000000000000000000000000000000f7d97a52e5cd9c4955db7e2561d562ea1dbb117f434f6ea3f6e2cc713d5354327966e32fe43d505733ce75905f6f2a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120b69653d0057394c5f1542ded11ecad31eccdf97fe5a7dee4d31b007028161a5f00352d681c0670a09909cf8776f8f000000000000000000000000000000000bbc61a17568f94e7f4c2e6dee51514d44a1092777ea9a71c17cdd176ef542da9f13f3ab210df2d67e09c192036bd64d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017aa09b166a384d3bff7c93c7f47278a78301378d6d0574984b7e2b0b02ce3820022954f404c8781632adeed814acd32000000000000000000000000000000000213b863d962c23997b1387e8d3761c04dd4d19c5b08da0c554d563079003f004f5eedba0e2572ef3604c7afaf3fed5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001180158b411b3ddb466c0ad94c9ebdeb490f91bc393b69d2db9652381817212083d045fb7ea280c8b940bf392429865d000000000000000000000000000000001610c5c6535fdfc58ad51f3bc63d4a2dc5f1f51cc836696230aa4f2d31acd1f5f6c592e18b5058db82a77325fc16092c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001378ed1a1318435462086e814f68717e724d6bf1d235cfe00fa0b6a1f694da983b9ee7b4bf235cd417975786969d8b0c000000000000000000000000000000000f76389aa8baf6be42f247da78eeb87fce48b98499b8d0d44735b1652a9f3552c2fb2e2d611a7758fe6fb87f4964de791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025e60c67e01f501c9a45c07372f228940a62fce3e30d0e39d2e6791b2b6c86c35fccc98067d4f51211eddf29be8a8270000000000000000000000000000000001bd0f4476cbbc14316f3fcdea81b88178044ef5f9a339a91d7c20def236d14422dd576a221980b49793389542fd23651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd29d1b8dc0e1c66acd1fdbe6c3c37262fd596c237ba06b9235f92fe3df42fd8334affec03ab059c8bbdf84e387e6240000000000000000000000000000000013e84002e508289b820af2dd6611131bf8a59ff593cb87ed6c042f77b07acd13e3b09fcb2416a24c182f04d49e0776631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bffca8168829485b52e76d8155396d728a958a92d071ffd1ee3c801a0f69520df8ea596da544f617cf76ed2afa64bf6000000000000000000000000000000000f46926586ab6264664800babcb53f5920afbdc9249810d04c122755797654faf332c65b797ae62fb0589320422f07dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000158540e90ac612b363125b6bfeb782a6f7721870db25617c6dc797cbe75aeb8239d54c06b0072e3a6366465235668fbe000000000000000000000000000000000aa9878eb1a6374cb5cf4eff2f6fd89460aef2b6a6eb906e807242cb39926c4d47a6071793d7f06916c59d3856aa337e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187038b45b079a2c342175eb833b3f56e35e3155291313acdbddfa5c9d8fc9c7451bb5e1094001954958617e99db726f000000000000000000000000000000001334c6debc42aa7b4ad075584076e57515f3624a761b2438e76c52063a3d7ceb6b28c38ffdd1d577a6943048a4a58f181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000079ff426ff17d6e4dd32f831334f9dcf129abe77f38eeb81e9c3bdc06624bd31aba4f11335097a5857d5d2a7d8c93040000000000000000000000000000000015087ac80bebe5b873a6b49f3e271cf733f8f8d9ed9a5303020c65b5fdf8d28401beb5a34270a6ead70ab5e58b0b6b1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8b19f820114aff1e91b49e587c851057c41a2df584e1330ce404852ff738784563206c6d8dcdfcaad9485f82d06e3d000000000000000000000000000000000d53f0dcde9d193f0c84f3fc0c7d093a58796bde168f223a38cd1b5e8ba3c30b07e77a741f1182eb403e35b14819465b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164ac813cc3b45b64390cdb09b68e7d79f0ed6b6ac2056b604449d1874ef6780944cfedcec6d9c274006cbdab414af5e0000000000000000000000000000000014f96f88e580df705ece706d43a8b98bb89eab33443f5e98cfb1bc3bc3955c837ab9afe26f530673ba033c8ccfea9e4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b74171ff9d8a494ff1680b77587aa7f5edd8fd4346762c1bb14f163767b1cea9cda885f20dce0aa07f59b82259f855000000000000000000000000000000000bf0aa17635224a1e47e4aa5a21f49b46c268f5c0582b94a66b189ff399af7503a45831de71f120e0f3f0979f1b351a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b3359f0c58ea8dccce0f0793a04456a2089552ee83380ba160b354ea96682596f787f5991d5cb8c63a1aad724fbe36000000000000000000000000000000000147b7d7e84cfaf9ac3d79f64a8926e8eb6228e760c979dd79517430a44aed8c622a8cb367f056fae572338b9f4947d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000406ccfaba58f5b19b3ab6696ebc36de407dc7fa84e0000a78ae53e8884394aea252776f5e78826f7ae446ad37fc2717000000000000000000000000000000000a8c058acbe8deeafb4a1e7f046cf02147c73fa1155745b7d41f41631fcf166c6d1bd819bb29fe1ccf38a154712b1a741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000382639b79f0f04f653ba5e98803bcc79feab89724cd8473a3c99dbdab70929177ae836a8379cbc29b0805d744b3a5bf000000000000000000000000000000000a575522682cde8fafd74d6be77d79474269b10c2eca89f9808ca312b57850fa55fc2637030a44e87b1d2e56f048e80f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164b53f24c20bdd9b084f71d8077a603795d6bb4d85b3ede29b06012b5519605fb96fe995c7d8767c7ca4c9022abf4c00000000000000000000000000000000014f99b1dc9f9cb40304570bf16153dbaa944dfc95e13d597d7b7ed5e3565fdbdbfc9fab694e8dd3a8f49468c8f34b6d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dda86643d21d2cc1ffb3ae47bb68ac48d5799f6d23f9a99ca094cecef98dab0fe64cc118aea3b4588aa7093a79e1c2100000000000000000000000000000000020a08c9fcd09eff76c368682afefba154978faf68ba73414e50a83a9e6a76d2c425d044df241aba30ee8af49a812ae51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164992abc7b798aa8bc219225c8f2ea32cacd2f759d352674538852a79fce87262ae58fa4805ac19bd0cc24fc40e7fef000000000000000000000000000000000dc6680540fe41815cfb5c186e4252bdc18d9347a0c0bb4443014d1f0dd728f733679a1be68337c91abf7a11af0fb99a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191747f7588e2fc4179f35f8c273934bbcd29c370300c18e1f352e3249e7d79dd2694d5f874dcb9235274c2987240ab5000000000000000000000000000000000d92b72e8d02eccb193f9308fe31d7984c8eefdd91d53f89166c668fd1517a70d91db1d25dd20af1630e04fda4ab159c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000727b94700431b1f54c34dd666e1142f40ab4693e7f57d240603c45137bba0b5efabef4d1fc436b06b0ca0bfd533e7c7000000000000000000000000000000000581cf87bfc4890a301a7d06e92c93c60405dfc1c5b1cdd9070f08e4d0f0e4cd1130edb9a8201bea22e54f6d029675461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001477ddaad1ecbcd9a067eeac5687d609af1968c2faaeabb73fe0326c4b0a1fb9770850027f0a32578c78ce7cf3be434e000000000000000000000000000000000b552a04af6233ced891223cdba7d980cce5162c0b9e2f62a227a3e2ce6ed3fccc2825e1b3b8ca0ef6eb6a7063cbfec41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013370c81c296ab212588634066b146ead2e0f870a125761164de1fd6ebfe70a9807746a9837b98ca0e5a026335fe011d00000000000000000000000000000000132d48237ab432e50929e256346c3264c2c45c4f3e0fc4ba67edab3e427825ccad596d139224284dc0429e35540352061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004969220e2d09bf662840766239258a3fc4e6312fb4692b8a14ed915df4d9e781018309ae963cafe73aac26e269207410000000000000000000000000000000006532a4ef6fcd40ae6fb195ba32053ff9404a500c4a236eaa90c99ef0e0c4a8e44b6fd6c7a098964428f4df19296d6001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000070c14e36980c29d9012bd6c4051238245303d23351bbe58c531bcc179a29d9e5a8c26f5453b06f905000d5634052fa6000000000000000000000000000000000e70bd62e47181addf1313d7e8073e7cc93070088ed87389e2764810ad8c5ce9801ec01586cbed7739fa2f94b8bafe3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f83368f3887e86accbec036c8bc269928ec0ce71be6937d5c675b95680eaf8a6e58215fa710a4d1253002e29fa3a340000000000000000000000000000000003004306feb3618fda39e38fd75f67d7f1054cd9afbf38a3f0dcd5c39ba1763aad7ca62511610034983ca1979729fe291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167f47dcef982f27d1f48140568d149add2a06b1ef4592979a5877e52fc0b2ebf58042d910fb16312a1d213bf731e8ef0000000000000000000000000000000001b821152424d5e69383fdcdd4370e11a2135258cb6497053460c12de4086715a013123cd23e90ea7e719fbad1da50091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001598b6c1d9693c4e538075a645b3d84dfbedcb5093a2a2627ee7d652a204487140adad7c04f6a85254e95bc27a07070f000000000000000000000000000000000b7348ee14a6884e0e3c7a0091024eb92814b711688ee0845659e208cd183c3dafa43c3b05d82ef811c3addcc505a1761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024b594515da045e65a39089cd9bd75867a6aabd2cce4f6ee92f85b76fd9531c4b7fa4e0f9a3ccdf9fe0131d2164519f0000000000000000000000000000000014f88496072c189ca01fd83ba718a4c905e659abb3396505b79162ebb14d04ab2d8b8f5b9fbeb25f78e99a34b80e2e861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f845192fcec8256df2a289fbcc35f77d920b67085edd37311e7444a362af051ac7578e2b2d2146aed3c209ede46aec0000000000000000000000000000000000b1304c3fdbcba42f9ebcbb624a2ecae13a98882a45ea86a3f18bb42f4d5d8fdd78dd445013574ac12a8245bab31e811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001022cb8522b20732f3206bd5e3c8ccfb60c5f6d4ae2eef93d7968f361818ed7a519c0e691c8fc75e3b69a3375bb2eca00000000000000000000000000000000014b9c960eb3ee6748c1be21c3519477b42d2da1a092214de50a9cc5d86a1013158373408dbec01d04c9954710a86bb351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042e16808a7febd2db26336ebaf19e05562ac9413855b2e751d04ec954de02c1f0daa3d5dd2e1425b1754dddcd115f1d0000000000000000000000000000000011cab26d5082eaf641d69985d488e930dbc73e0e55e03eac71b458f2a9f0e74782cae4a6fabc62ac7dff120f4e67cc131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067e27847598b00251feb02188087dc402a23fc6e69de155ede4ec15257377ab26685e498ad5d7990bfc1f6e83facdec000000000000000000000000000000000b9e8b48785ee96723a07fb91e70e545e3d9797d3b8f30821bb3217e8a155db6b5d47024ce1f3d1593cc54fef8811b171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025301f0180aee7159b3f2b8c4e87ece03337f00a8fa06c092112c46f3e8d5fd2902fb13ee1f3fd23cbe4bde4dcc6470000000000000000000000000000000000a94c030055c550b224ceec91c883483adaf67eda82ee3fe82914632d1873b969db60452288edff0ad9d586074ab137d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001133dbdd74995fe59c85976db507df2d78fe70e9c2c0465c9689e013ebf02fb71d29afca0e17cd6b28baa895c92e8e3200000000000000000000000000000000112d1cf1cf5a5a11787f12bea68f8d9e04986f67eb045992b5f302146801422d060f1d06e4436bd236b0df68b1d4312d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002539a66795a02e13a711bc58de141600e36477d7c86fef67dc7b120f0808ea6983b457f955114a951ef4f4727a42b5c0000000000000000000000000000000019e3db6e8903b94eb9d016d2604cd590f1ce2ff618ee28bf273a48212c35ed78edf1d9e8b98f25ab385070740317cd381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017126c96e747f3b8736d96491a1434a73b11e563163fb76c42c77205bdc3485060da531b2cd9bc412e51255c4ff7d94f0000000000000000000000000000000010e33f3f68f9a95d257029798968136eee52502413827fc6beebae0551562ba1d0b0569732b07636d3c5f98863fc7b2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a6de613af4c9ef26ee55ddf9c217fdbbdcd25956d0fea91c485cc7942f93b7bb8b2551f52c04ff139404c125a6940b00000000000000000000000000000000112c9880614c3ccd84ff7ed60eaaf15c9d1743d869d0186c687ef3d3bfa91cb92c08347aaa79f50580b94e593fb062a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000860da09771df210b36c60f0a0f5bfe01ac7cf0834458fbb672e737ddc8979085d7616c1db347f1cdbd5b6b1128968750000000000000000000000000000000010b78112913366a3aa225ae1ace9f6e323d2eb63be1df8f3394fee9aa883772b28765c6e8420524d457b00835c63b8421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f86a8054120b0e8fbe9ae39eb6ae8db7ded10e1f440d726ccdc26cf2f275e6d145fb83133d726f3699c74bd616c02d000000000000000000000000000000000ff8ad9d3bee0484b128145953a79c6b8c6bf5d493f93acae34914ec373970ca3dcaaefb32183e746ed7ece4b21b345f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074fbc7a0cfbfdaabce6c54ff7d757d2399867aff98b74c0a8b8d0e903f7ee580d512c78274fe3f020e9a83cf83795580000000000000000000000000000000013de902931d058dbba2bfe75b67565f7feb8a8aa854bbfee4e128363f4f7438d06e17402a71ee7a318c47f1cabe9a8881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001756ae5b63a7171f19603008feabbbc5e13a4e7226ddbab0bdf532b08f8a1a444080333d0b2721921aa3b2a6c26f3623000000000000000000000000000000000c1926d2cebac3d2e1f07b35425025d83a8380712c0f4bc6f66cb2f5e0c05be2bf6c59fd81576548a832c7bab4b694711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bcc53bd6c2cdc3c3749194850b115098e521439b2542d8ed5008dff0bb65e19484fc132488cd2c2a6a3aaa3403952c0000000000000000000000000000000015a238963b95e85ac0598f07bb5820e2f85caec8afedf6c871388e1e88eef802a79c893617ba595a3a383605b7978cca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e49bb242cef9aa4c5a771c7630aa236a0ae567039ddb42822f707382b0cc25d5b5ce849c2b71b4d0d681d3a1a2a3360000000000000000000000000000000004168201da90fec8fb7cd0291f58c77f099a0074922f3a22ad5a0935d005bd14cbc6ec8bb4f7cc5d648ded2ac9b197f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003720b263599359968ffb1011bcdc7d19ffcfee11ed33a021c886c6b120f6b86d2a669a2cdb873cf901b2c4f8ae2ef8b000000000000000000000000000000000ef3a9d585909bbe18dce9ccc4c97993a39b7d6a9310459b87845667d533273d17b5fad9e790fbdad2f24f02d7237fb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e82e5a39fa806e156d224b2f10bf8943668c07407f6783965ee8e4410ee55846193a8b3206a8816cbb1f2abc3d5dee70000000000000000000000000000000016825c1a93be6d4b80e0a89da82a1cdf8c53a363a83d174c21d9094e37d3c51f286a3f7fe8b7a61c374ec8723a9a92a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e419fea158143e209fad39a025c1f092580901e0f8b3a697e40fd4bc413dc68133420fa5cf33855df3eb0f0b035e7f00000000000000000000000000000000187f77f8f10cb9a1a7f18af6d731193729656fab98d4255e3c9ca3756e211c20d5dacdf355ca0e2f6bbc7ec003a862f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001093fde9f71d50aa53f57121b3353cb862520f25e52481834efae55141ed97a19167b49daef0a8b94c5534283c7799f70000000000000000000000000000000015a316314b0227d2144f9eff60e7ee8c55a45d35d809ee7538793e6b1ffedc7036e657f0118a5f3ad27541c0d92f480e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5ed4f39bcb3bda471051fd252b422b7fe199ea7b3abdffe2c47d6a6c413d34a7c642e5ac43df66cd99b1176f809aac0000000000000000000000000000000017d288927597b27adee29e7529136171dc09dfcb3121ec828f41a344a949611cfc59b5b87ef1d15076506a89cb766e7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000023b9a77f7a8586bfd9073f16b49c7f03929bfe4484ee4fa535bbcb11b74894ffd7f39d69c9af6e52d880e97a079772000000000000000000000000000000000e2ccafb39fc1f663f3416972277acd1b9497bdd4c4ab280dc4585a0af628751a3c57a80a84a8738abeda8796b7916e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000844ebbe018df01f7b8651d3288db8feeccb24cf686c132685daa1576aba1f32dd6be19499fbdbc34fbc964b6478c0ac00000000000000000000000000000000139264eb6d110d97e1e18a928c9eb6bdc2de4578c52b77c232a92ba741bb454b8c62b2589ee6200b28b105bc0b9f0a5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd4ab38a37f18dc22139059a1587380724e80650023eccaab109039ff2b33dc641aad816d1b2292a6bc63f01876dac1000000000000000000000000000000000b62ca4f8e4fac00afaabcd66a0b6655d4a5a9b9a400297e91487365013c807796cf0af5927ba761b3aca3b7b64594591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e991eda400b18f91ed05cfb26101cb5b4c2f890386a84c8376ff83e29f8c9896ff8cb07f2e29484044841887d4daac000000000000000000000000000000000525a917051b32db4ae3b037a928f9a83e4a9981f76d7213bd232829e10b1069455b42e6eb5b2f1537f19207c294455b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000662a4e8106064ba11d9681895029deaad968842b756391b2a7d0ba744b7f2aeaf8209b7340bcd34eeff0277f1bce3920000000000000000000000000000000014590db213d9f23e444882e21def8e991fd8233e1f354b05019e4e63cd44d1587f04a5e0ed623570d0793c43c820e4461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077c160cea39b6ae8620e342bdd9bf60c30cdc17116c5cf75d6debc579aa0948e8bb4593a44a654c8cc010dac41ecf8e000000000000000000000000000000000a75c55524a6a9eb45a65d95ba69480a79c81904b99513cc0581886187dc206d633588fd1aec55fdf37315dacdb87d5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee28a7b0b539deafb583aaf0047c8dc57cff3e41ca4e6a1a0287d029959232a72cfd5454f68e8595d7eba8d21abe23c000000000000000000000000000000000889777cf303f057d532de75bda3c9a481aa93de704e7639453e22b6c39d1f6c38f7f0c991eab15e5ba223aa9074c7bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8909e3fb5333853f2a5157c22cc8b9efd95917d61bdfb8096b4f38b2ad23b61d92834f98416832a8845f12d330a13100000000000000000000000000000000140b29744a9a7fbad8ccea93fc320d1bde715ef48632803402ec34d5a60494b5b9972144c6a59e1a2dad563e61080afe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ec61b70c9f0dfadabbbacd90a3cb7f5dc8c06bf0482f6c2919bef5c26bc789a74b5e2e69f5e07a05eb9c55a17a881100000000000000000000000000000000089bf178569f4d95b872a10d33489afae2de71f7c0b0c70039d0ef311fb87d644468ee271cf4e50c27890847b411794c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c8703ceb2deb5d8a63003fc52eebc534d2e670a360123f5e2c9195ddfc7c13ffcf35646215711f51b43acd53879e51000000000000000000000000000000001894126efc9b0a888a43681c6bbb070b605d9bb9fd0910d5f92df227d8cefe0b7c613dc88704c0b8ed52a4b05370945d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000003ef9b19a2425aaaf00202d9c1b1e49364b6e73a99e8b32992ebbf4586ba5962b3fb68154a8ac52b4c87159bcacf2890000000000000000000000000000000002c9300a843ee187897395a9265adf1432786c6f3ed6f0fc272eaa3a919fd503735b8a93009a080c916decfb00ec09441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b52c94b01b464c85750c7790b5be5dead57154b20fed1b36dd21e5e231fff38d848651e44be7d49c32b06c6cd6bb01b00000000000000000000000000000000138a05f0aff2595665ace929f6304ddff03dc801cb2d1074fc5f78932b0cebed39666d9fd9ecdd31a71e3c6d248352b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf9fb77fcb472b173507bd8f2f60d9815472a11f82b7c9e1c5dd62361477108c431bdd5f1e7a81e83e49824513f8c5f0000000000000000000000000000000007dfb87c54b8a22ea70ec543d5bb51bfc542bbe71a54adebdce1a1b3df869ad341dddcdecd2e8bfa51e301562ba289271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d6819d438924be9784dfdb0394bfa5ae022f07c3f81944719f07ec460c80d424c0cbb00da2fe94d6afb2453394816500000000000000000000000000000000143b79db18018a8d8b8beb23080929a6769610f24cd6280011178533b6fca277647c96e86f7e78db3f4f15173be072bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7cf4c43bfcec98224d6b5f9d4325eeb759d96aaf103be1be300968f4405bc39832a2c063cd36fde576b5d8f1b168730000000000000000000000000000000013e99712ec0b46e8f464ce0f08b15746e35efc0f642f21b07625c28a951bfb38ad802826709d27ef5f0d0907c465123c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076107e3b96ce90dac2e193046c08f0c5441995f7daa1652abc01cc2dd85cee1553c5b52f73e85ee74a56e93000051960000000000000000000000000000000003cd19e2df7ca79cd65dc0cff6a707578355fcbc0bcad44480dd58a290117132e14a4bfb662ffae9035d01ef7359c79f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010995422a8d80f906e4b7efc22c1aa012f6cd4bd6a4703ac038769c4691d69a4ae0ad1cfd15c0066a352b1b8ba04e5b60000000000000000000000000000000001725947dbffbeb57d0bb2c56d1311e64a38c8dcef8ea3a762d2543e18ccea6c7ac3b5d8baf3226bea7956c3f721c6881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a36e1c0b9210e2295bc1dc2c0918b058474f93ad772ef1635fd32c8f276a680a6dd61037859490d620110d7808e4b7300000000000000000000000000000000158cf44db63565bf98c8537dcb682dd5a96b8bd63a929398a7738632f08a33fe65501e172c7fbd9c567702002d04f9e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000723c083b9c58107e0be9ad76479236d9c2f139e3780467b93defe79225399752ca30bc94e93b869ed6118709db1d17a000000000000000000000000000000000da89809c5d1e21972b0bd8bad2a7634b4c4e48ec2b927605df73443dee54f5f9b3f245f13915cbacd526cf310b9c3a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000290a52a6dd7aa892dde93b69103c4245455a0d8bd225aba9c64297d13b220b1bb305ebe321516344b8f9b20aeef348c0000000000000000000000000000000015ddb3290dadb16912b25cc60714d5605ced00852d8abd257e6c07c3a1f4d22e6d077471ed3abf8ff739e944e1865de91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6c220ea1ca282f6043e3a8f2f5c7b638044283e6afbd6ab2159aae284a4d37714bdeb76a4419a306b88d0d575a6cfa000000000000000000000000000000000393d24918be09ba33dc8b72c84d935e2d3b7d6533e55024a0c1ffe4feb51a866e1a8a8088d71d16db6f2d542cd07bba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016faf65fa08e50da2396cb718c079ff8d39ddcfb6f012ba594c96c9d2f5ee095502aae9be97d74b89eb6f8a23877e330000000000000000000000000000000000466802a9b01b3d54fae3f68b8580ed4f62ae040b378834ebc152a55be6ae8a018a389f11c8bb5c842362b313b6abe411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b968d05aadb9944b96f08cbb3a8075f45dfb9ec191a5087460c0b09ff0ada28da63e7b4a731ee6f77ae7b4025a503100000000000000000000000000000000017cebf15f390c72758e65809b80f55f06faddc12e3f0d1b371e4e08d6073cf3854a73a45c58a47778ec7613086ecf381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe5046727863f81bc5e35520c437f08ebe3d6979571eac03e5dead6a4e27fcbf5b0fbeb266c1c7a000b2105066e95180000000000000000000000000000000003b6d837f23e1fa6d84ac4f67705a6a1f9e139cc1a6ff3fe1a5e36212cd59ff617ff491683c633ded78e01fde4c0d84e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050831b3a735045877b83e407ad7eeb7c62ba2a5eeb40608531f1ddac41fed114c7346f5be478b1385bd9e96a374642200000000000000000000000000000000107cea6938c2f3f56ebd6c006aa5839a8ab1fcbce4b1db8ea77b228826c81e371aaaf4f9935bc0ff41896f31c1812c961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000282f4c11ae5e6ff5bd33d7857e1500c6226dd5b95041722bdd2fd51273262aa881a2c76652ddb06dfe94c58ee6ac873000000000000000000000000000000000d673a030b738687aea2c09e8b22a96008d86a3276c825299dab0d1e0ac8d89fed56adf6c014ea66ca5fb139c0b25c971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079920e9006385096c34c99fe4fc7cffc054abec7970208c97dfd4ab11ed383b14e0476af8ac62efe08688b10effdb84000000000000000000000000000000000e3bc1137795ae1550d9315e9882998d883f8394caf54663e380a6f63c58294a96ff4a635248c74eaf041cfc7248117e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e12396122f6d59f22dadc2c5a8f8b885db440757c5c98696453251ed60dde9284b66968faa36ad0edabeec7065756a0000000000000000000000000000000002fe37cecdc1d508fe2bfde3d62597887e21b12deb864908377b5e0d9d3e11aa969ad0d9e9bdeed34a05f7add4c294051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f84c6bcc60d0fd0fc34b9506e6350f0a7099188ce8be4be8c7830a16df628bf83c63553f3dda6d349c21b82be47aa50000000000000000000000000000000010b8656c56db06db1c0afb2cbaf9eab00d21d917135934ecbcdb0cfb572ac841060c189576e684c58fbc4b49dc8653241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a046a028afb690a6e1b5d9b308b0fbcbe58b1ad3c1092111eaa5152c78c77e6054ce3ed8402b5c482871c22e427003f0000000000000000000000000000000001be6dfdf60abf1efae7bf95fe57b17ebcecb2b95c495b120e4ccc8088bc115def10f752679e5fc30cf4252d53a6cb181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010950ee8b9cf6657a82916223d001bcb9a1ba17a9176eb40bc6b465ce32d5219025387eef51f8d0a28587d4d0775efd000000000000000000000000000000000a129a7e652d173e3e0de083ed7e0d589c7f1ceb7dc70d5e90df18baf69b2b4320567d195a99c288090128ef7804d5d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009a1f90b7ce5c08e6e3782263687898291fa759a3db24bff38787b49a06344a322abe57cd5e0e631aaa9c321b27b76000000000000000000000000000000000131fa5b486679a4d205b937bc37ba7015a306708ba676d935defe536249d65350e360e19774551167c7145e01f8daa041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e63fb8caf70fe6364eaf3786c846c050ac2a64baf0c343244ae81ddda292e56e7b1aeaad002a555044885e9a742dd34000000000000000000000000000000000fa59d09eb7f4a7344dd75f46a706655a7ffe30be38f80331dd5b9395ea8d6ef22bae858a670f58f8c803e68fd9814511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e952d3890695cdc8b0d5a97bcb99abbe1090467e1c7ff8f75bdf92eb8e4a80e7d74b4f5253a9174ca087c862312a240000000000000000000000000000000019ee5dff6261602cb7063eceaf8201bd39358d16d9eea0a9f4900082907ed82bd82895ff6627ff475f7e8a31977efa801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d0b6a6813af916cd3fee44f4f77eb0ac8ef2100cf4d3e65d6822039c882e928b4972d2b89ac5d9cb5fee8e3193359d000000000000000000000000000000000c43ca171944a1f31bd9ad52dfe1a6a200a5dd1f420342fc46ac9bf27338804cf283ad0c6064e9bc893b4424a0fd0eb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b051b381b341f053129e955cbfb5ec05bfb4b3ac46547b8dd8aa5b04e4806afbbf2ae8fe3f42a847ce797aea44611850000000000000000000000000000000009d2b5935ac0ef09355642f7bfc9984256cc8a1d3f6937b0f52e3ac506d723ed0808dc2a453ce912b65cc5a6a5ec8c721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000dad12c00f84ac04f85986f2e325b8bc297f79c48f77f40f202818fb81cacf1c0292c2ac5a0d4eb372bef21920e70f4000000000000000000000000000000000146bf3a19ba21d45b4ccd5ead95a0683f8d2ee6eb881a3b149c71f0dd0f4eead6dc6c01343cf4697bdbe28becd2a0661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f49c2300a84c38c9e213bceae9a00005932a25ead2d416f60cffa026dce3a6719716f61056a770fce0912f76d436c750000000000000000000000000000000007f909194b965910b441931405ba0db0b44fc71f56882fc2ec08dd01e292703a66d4fc282621ec15d1b5776ceddb55dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac302ac3b5d103308d9674987d6a3534a6ec2fa20f93387729ffe8a49f36b11e6042fe82e2b33b45b82a7be93506975000000000000000000000000000000001527a2c0921df212520f5268a60476ab1a1a57db0af3a10976948f2910b227dda427249a48ef92f83eacb84e61cdeaf11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016166106f823e6f9622ac1decf57ff1d535d366db729835566f2167fb4bcc16ef3d6e59c7a34ac38ed8536dd8100259400000000000000000000000000000000078147154032e9ed0d52e933d83a7532b9ff33674960929008a85227e6ff20ce477053909320e5072a0eb728c425b2be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b41afe1df5be62069bba2a71ef325424b0c5608d18ae425bdbd4186f15096ac1ac106deeacec866ef776852a62aece0000000000000000000000000000000017aac1b42b21c5e57dc8392d7e948a4c9a10be03595fb9e49d060b4253318bd9fda2761f3cdb314b61960810129563f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187c1abb8cb78b126c760f5f4445d7b4344899c6ba153ba94081dbe8286dbaf32218ccec0a8166937a51765df7ed98310000000000000000000000000000000015fe3724e2eb7ca7895f765def9c38f65c62faafd9d323ba9b1a6bed8121379ad9afa207c33211488863d5ca29ca9a101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050db936b15509f4b127e31c3f627a869940f51371a1974de56e68392fdea618e062f322b8e19126acdde8e1f59511960000000000000000000000000000000008da0a02adb849720dd6d4d13c2b4d665acfb0878df5df55cdb7ec8787d90c078bb8c0d893b1fabe96d7aa3812b2213d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f152adb4346ba3320fb73d263a1f9aced1dbe4b5ae357611c7a6cf3c73e1e06f91d5eb51d37d89c55f904937bac732f00000000000000000000000000000000029e8dc42ae1da7184e5ade15413dda58529fe98a7a1904dc087085c091aa68d77b9b509d594b6887414f8193c60cf2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b7f0918093c177fd90255566eedc349e857071ed24bbf6ce7d65b5f7fa292930f28d327581ea2afa2a91eec23240cc0000000000000000000000000000000018b5632b6f7cadbdabb56f6db9af5ae346e2c5e9495b0bbec0a0d43e7e28e04e1ac2e921198ec167c180858d86615dff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000517a79892072fd20927c10b69bd3a2444059fa7aaf3f14f0513468c2da088a49a28d417e6e38bf98ae78cd9b94f72500000000000000000000000000000000008761e6b67bebb6b572ed921b3c44aea507ccae47f4e099ba84852b540d265ab556c143d71e083e90e891107018e03661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8d9e339b7bff9753ee58d49a779a1050a490acf7432b3a5cc3901ce603b33cb12f9ac73d91bd9664429fdc580c047d000000000000000000000000000000000508090147f48efced9188e980bdd386d43ceed9afa4607e6436df6ad885703ae02243c3887d9c2cdbcf9da09c5480301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f143047d610b02f7f1fb9b7e9ac9e62f0260a19991fe62f3c80825dd704fd35add86a88a07341c7a9145ef558a43770000000000000000000000000000000001362c7976f83b7b1886de38cb5c9c90bdbeda6b65d317b245ed71f7baa03a1e649eab4c2a72501c572215f3e26866e8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123eeb802db0c2f446f29cffa2184e92623ba6bbacfddd8983d0da52c3e4a3f60e98c5c4cf93658930406b03a64a1f2d00000000000000000000000000000000075d46ae3ee0a0f2d94bd2c45800a24eed849e5d40ade62b09f2beace7ff7ec1431653cafe42882e9d475d2af4c855af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006ac508f53dfdf24481c15d7c1d89cbd9c9636b6508668f63defd69ae7d8e6a0305afa0f2a0caa6aad0a654541aac17000000000000000000000000000000000e18eedf3f776d73c5d667e8b37d770b385b6e432b793dfba920c43504d2ed09c04fc0736c8e927b85287650e6e015e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002126b9c214dd9542b15a7bdfce7f6a462c0ab8ddfaf0abfb8e730e7e57f955e0b06060096658b9c3119eb0bc68c738d0000000000000000000000000000000002419ca1b9cdb7a08d7de9032bb23312da7284992d54ec58bb8e8b1fbe7c70e6d33aeaa07e26b0a328e0e454bd75deb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f7a0fb3fe333a92b8ee37117e30ddb4a145c2ff58a3173494b5ea1e577ee3bcc8a54dfde20ba7ff3bd9514939b5428000000000000000000000000000000000fa720bccc05c2ab5f377cb70a20196ae3ccb1f611301b2f44b95d47db0ce0cf28bf669148300592c9798a44d1e72aeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b38f0f576d43f07d79ad99a62457b169cbc8c235b47aeb7d0f8388fe995431ff2ef736782bc22b8bac00a09c38229950000000000000000000000000000000011a8382187a97492f5da1cff5fb145c859d6085db0e18aa1325bff944e918cfca8c1febe8b492cffc3195b6cd98e66fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000be172b62803645f02953906ac29b1993adffb9a030cb4f6310f92b16e72dda02fcf13659581ee0880b77fe1b0abff500000000000000000000000000000000115c81153c25f5a08b546ff91706e3b040db1b153af2781a96a8005c5706153ba3f030b85e26792e8be6a80aa04a970a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c898228ba06a919f4ee8743e25493b65492527e936999fe0d4a834bcba9b768807564927d4d037e82de07b96f9c226d00000000000000000000000000000000037ba972eba7f0315d262398bea0ea0fa7091063f77c7c14a2ca1da97c882d3afe00822f8f4d4c69cd4e56e3f4f28c0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016377e9b486f434e99480291e3ab2e87feccc329f4bbe6101c2f5c96c2ea2f39c355cb7ba28e1b3758fbe86da0d567b80000000000000000000000000000000015fcaa7a6c4a884315e3a550e44f2f36d3d8666f272ff26d1d94ff0cef1b8f739b9861d57ca1bb14a0b05b9e38ee992c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000107c47fd0e4918ff15b3cbe48d66f61c9e92ee119e959f5382d42ab20109f30080a08829228755dbbec083e734dfcb30000000000000000000000000000000001a7428fb01468b201b5f9c9893a19e3ab1cc1cac471bbaf6cad29cd919f4fa17f78a17706035bcc24b2a76ba07818df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001850e6d6385850925372e956c04014e357ac4f12c7daf15219b4b8547aec8c0d7cc5009a34bce170d2f9d2f468da96520000000000000000000000000000000006a58ada59e20dfa5f4535f2d1a72977e1efd144a232183833394951b5454ab64b943b3ac5f64cfbffc84ef8d2567c691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012aa887b5821d57ac79f21baa23c9bd109a1ae485cc33c81fb170172b09b6f0e75120ea69341e172ac857feeae0be6710000000000000000000000000000000018a20704aa17cb24e92cbc1e0bf88107913095a3a908f3b5f0c953003e8392d6e7c71f8f9363101a58d171dbd92d974a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178e4206324d82695da9ed70d6486b9ea5718c1999b0f9b97e603b21d2d5c84b657c487eb8364967e67f798112045ecf0000000000000000000000000000000008922c279f2fc6c702d0a7cb79e6ddbe7c459d4114e3f5660ad146af988338da7dcdc12261cdd919ef2d2aa1bc0a458f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc06fc5d19f0308c0ff3166ee5f3860b5913035063f1a31b6414ff908c1fee5f5266eddd73ae89502ac866b9a8b1c750000000000000000000000000000000002fa1072955c6f686c09a7074c56369c7946e93cb4b3a5cb0e2d3c02cbad742cf80c01159ce4730249540bdf856109291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac5c22af41567a8f4daf7b9ca20d5702d47054336e3eaaaf130a4e1299de1ab81f966cecf11b8759aa36f64f372cdbf0000000000000000000000000000000018129bbab7814eaf3d8da66c574452af4f63828b1dc143607f6cb82ce356bc7fab2c89db4b332d68142bd03d3ad12d5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cfa4ab31cff6c1495ba3200c6a2d58f8b4ec520b769b3ab619f225cf2fa57a36c0dd2ab068d8cbd2a1f2a39d14cb93000000000000000000000000000000000aca2768ef8273043a6242c885c405a5911664b63b69cd37328e9636775704bb8851f2b6c54c41bb0a598d0a0601fbf91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000343ee3cfe739080d3f7dbf61af8f0b5328ca6d620850b8463bf9320794923c4a49b08c34468afc5a97c1b2196ecbb1a0000000000000000000000000000000005cb3f25ceab2c4cfa550813a5f0669f914dafa311917366c13f28305386d9e894e47d13a7644f59264b74a4d1f21cb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a4e8be12baa785e7e0a55f3b63214e0cd467b5e1d2ba771853bb7f699b4d6cacf6d11fe2b72fea2d847a69f987d191000000000000000000000000000000000803549dedc10598508f43b76adfb581ea4f6cf7f63868cd4c397238f431f35a8cc31060c9933366ad89e4c4dfb9dfea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5237c0e69648bf70412cfc0169a8a682995cd4dba303eb0375ae434256fdf2ea8c1299a186cf38633fe9c939cc4f2a000000000000000000000000000000000ec481bcff747a436cc403a90464f24ac0eb1b23568384d914bcd2aff753ef0184ae8e2ae4fdb29d1854b2e84df900421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b3a6409347046541f0dd2f23d215fe4e66fa1ffb1182d78e9dfeed4bdd530557d3f06f1e293c58f8d65552393d2f880000000000000000000000000000000001de0d23e8f12031832cc4e33376ce400629de8039faf2f91d204e7c64a5319ddd903071cdab95f7577c609a74eab5fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001811f19283aba662f1531c306a5b99d7c3f59400f30acd2e2002b51434e87cac5acc933b8f7c53556c32fab3f5cbb72e000000000000000000000000000000000ab3d4a00dc651357f6a4c4a2e21f239fca0a437e4bfabb2ca575b3816a518022fbd9bdfd68aac839bec1769615453fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c81a72807e1d9f8134e9925365ab4da7f958e35d1b3614aa4c044b681b27e5fa706aff573a0b204f6d06690308fa43400000000000000000000000000000000057b0e465c3e0c2cd01c21596854efc63029982924d4af17a461a5046d6e84921e80e4f11a4fc86c028aaadd727710161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a6a880f00389495ac590390381beb67f51d192143f1e412fe4fa5ebb0567850dd869fdaf33680e6c6952a4f3d2d1a40000000000000000000000000000000002689a0d5f2738518fe29a9a50fe61ec50c06f0aeef29bad334947617e8d9c4b9a40efd5bf56f3c0b7cf6b8238c708fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127cf776c2400db8d771db5ffe75a0387aeca50668f97247505bb50ed3efe50a161b26f3c8375f60580716cd8e403cfb0000000000000000000000000000000013d26f82ca62eda2a1d779900ae66da6ea529046de818520e472a90d967114016a64d45df622bff0e66d273f480e84e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dff191b6b4f64e56ef2ee0b2ead49d4db2dd7299ff43e40c817b7c2d34cf7b961639dfeb7d11028b4a90e6e9d7ab643000000000000000000000000000000000d4315d38109c08e0b6c61a5dfdc99130b781c8fe781c768098bad8866315df2e767968d997526eb0a955f1cd7f4dca31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f61d385cda73446f87341bd089f53c3c42def6a34b1a26dbdad575ed353b7a25ce0febdb89e88b3ef7d4e3309fdd5700000000000000000000000000000000137d8d8de4977c5d3bb3bb4beb1b15389168fe57273fa59acf2286c1c4d9558ba8577ccca971e5502c4383ae0807a99c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b192e213a2c740356e608629e623e1444c50559b66d91b83ab934d14c524855a1695b49bf35954c268f9e17ac99a0e700000000000000000000000000000000154a58c76ea2c5920d9b7a8623290bddbb21da15219edf75e32d4c32e9b725daa4bb6fa509b3b881d9493569fd0ca8431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c6490a675fc775162312749fc02e18a196208e2293d2376265665779e000a4da6e6e1343666e6f87417dd058f48b6f0000000000000000000000000000000006048710a80cb90cc6fc95202b014506f002ba14080cd6ec08424891e807f97eda59dc88767c88858b793e7b5a7bfafe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009954dd2d1d332e76c85d5b736705030bdcc06cc8b731c56feee7403c00255eb918a370b35faa21f98abb8c96a1a8c56000000000000000000000000000000000b65ea3b664969b461c693ff5adad600f224788ded552e2b2a97503c058595e5944bb74979977f6aceed01d108d1efc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004aeea4a5e8fc6032b562a4b5455f2af36c983b9d4567c961da0b4a9bcd26e6fa1d0258f344136f2122580131fc6dfdc0000000000000000000000000000000013c7c74ecd0131427ce1c1acc189ed68888273f8a78c932bd0e9be0e3d35301a471fa41e0a6416196a1846d58c6961631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001684d7d87ea69ac759c7694f56441c45cfe0113b7a58d608f93a2f23402966a9c031ab39a58b775917c1e1644034540d00000000000000000000000000000000168b7a9cc121cc01c5e7cdbbe32f53612ad0cc67e9d719b52250d1953412713f959b992b542a7b25cf717ed0b7d191d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7544c69ba679ed4f9ef2d812a65bf6c94b6aed766da1acbf464c25c400cef4bd2364e147c71529a5dec376c332d1c100000000000000000000000000000000135b58b276d7d79506e0a80df5aded63db11a68927752d7182c0f0176d2383d2a906bc23a89f144567c96e5ea07b9c121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c9da50ae458d2e512731a11286ffed8d865d59f2dd708c28449ecc5d4ed4a3e5ddc62242ece9caba40089ce12513ad0000000000000000000000000000000006a36f2a31029733f3da4dbb3fcb72c52b4edd21e182895d476e6ee6e0e0f018aefb6f213fc180d0fddf6f1d0384b7f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001492862a8b2d3d21ed5cf525f1d413f9268cd1b591ec36c6d9a13c6f77e92978bf4221911308ef084c9adb12c10449420000000000000000000000000000000009b84c40c5e6dd81fdb1deb769f32b1254c2fdf1364ad9fae7da1d7827b95f1edbcc73d72a72d4746464e999f8ed48f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001744fd3088095025ff76c2e29560d0cc330f2bc72d2a42e3627d2df7a1a916e4ee63a36074637b8f2876ac4395321ef1000000000000000000000000000000000f65f54bed4549b3cf11e779a558f52d27d2970045d42e2e312e8ddf6e7aa846a5ce3b682d05fddd3459de00036a18b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b25d37de90656446e1cd89524c46762cb5687bf7751517feace1711ba244c0b3565fe52da1e8e66db0004e6e3f5f0000000000000000000000000000000000047bae4d2347d6488cc2d1d06e27227d7ee95f4cf00cf0d16bc936d6a3715fac9cc7aca54f02a26aa5be3bb2c668832e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005dc926a98e68c78d9e9c7ca0448d511990f457342bd821e1e30fcfca60f3fc3714880d20449a8a1b0142009724d8298000000000000000000000000000000000bfd3aa3b486a0d818eccc680932bfa5b525d7c4d77d42d1d176a7f4f11cb81a2c65a6e3e5378978ae36dd29920c6fbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008aa5700b5e8c39310f3b48586a312e1e623d355c18e242de8cd68ffab9d1bd786cb656b9ae984b9bea081b62db05c2d0000000000000000000000000000000009c9f58e35dfc06f1a516b17294afa5167ef90314e70064f2b5efdbd12775205bc47d7adc216dc62046a300e84ce52291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003605bafdae0a7bc09bada9c42f4cce2adfb28862b60f50d8034de6ad50e2bc0e1f81185406d6bda716fbe74062329ab00000000000000000000000000000000110a7b7944d97595ff8fee1d2ed7efc9a64c2cab9b71c3d0e246fe1c8f9d17b2a3a2333ed5394f89215787fb68dfbc251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf4f370ec9c2a04bfcb97d06bdfe33ef71bfcda3ad5173aa6a48ef00827c96adfa73cf6498c7b11d07e7ac5af1c7a11000000000000000000000000000000000e8eaa2b214122d041e275a927de61b6a3a2582e4acf29e782fcc6d9e10873874655589ec8b458f1fae91860ca6b8e581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142cbd67a893cd24658b567c4e7132f3c3aecc397ff4615fcab6f3295986309d5b5d8bdd006c081232d23250a5358721000000000000000000000000000000000c6304c6383884da2bc74019502a2b085b7645872de8321fe8469ae1f29bb969490ed78f0665924f5013037d4f4ab6481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3b7e4c01f7256b0f535b75b4256094dfa0a87b6f1af50c529f3adc82a9838ba1a0252f33424748051f1d9b355d413e0000000000000000000000000000000013c9aadbad2e26e5f196b97b7ca1a16b36514ac3297d239f1c24e102884704dd02fd26b0a2a5b21226c8df594f6250a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116b595463dd9efffa713622b9213ef4b93b23b57ae8a029cf207f3d10093daa9a660782f0ee57a127b1a0b50d2d96b8000000000000000000000000000000001518838efa4f46763896720536a1bea0353355280c8e650cd747f38855afa6de06a186ca3e09a38c4bf33320f88048761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ccf8d304ace09c576bb83f4510669e7cb160864444b4037ca68817628a2a6fdf8e671e8f269947ccfb7d7a958b812e0000000000000000000000000000000018eda754602632ddda4af2d702102f59abab31dcf4ab943f1f360a0e7f0003922c66a97c10f98c2d153a7bc2cc8dc1071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016c747ab2a6568a6b21fc221d6df4907d8be9bbef9bd9a5c8ffad7ad59ccbaa3784ed8af0cc01b082660aff6fcb583f000000000000000000000000000000000ef37eb24a2715440ff0aedd0daee3751cb66422b720cbbebdfb90e35d96aabd5cc6f08661948c5b3791b84373528b701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014acfd5c8f05013db4af8ba42879882cd86a7611765d2787acafdeafa01c7ac0b64a06b85e6602626e5912c02d61e5e4000000000000000000000000000000000338bd539cbc31c53b70543aed4e1a85b8a50d8853a523bab27954acd30a50e9eacdf6e47bf3d4c8f0698420d01d12d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018167b5ed7830bff61e900caaa19cca326c5c60898c26f87a7f716ce0901d740387a5ceb317a8f26582253cf96bb11ea00000000000000000000000000000000172367c4b5f78cbc3a3f0e85d0ffd802f11f806e590082a71128ae1de3d293149093daff6b59c17b1ff3a6d0c1483b011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cafadea79d2b36adff03530f0f36c67e7a78f0db1ec23a736dd938a487d2a759b171ee13bf875a86cb636da5abc9a9c000000000000000000000000000000000fd74fd075f946d96269395563f6947b3a428cd19edc00a89c5d44e7cd4b011dd28d679a4d5fe2dbdf3ce7d8828391141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a73e98b38fadfd4940f0cb1b020b5eec20a9f7514672807ac762ab23f5db3954e6848438198274c27f3f991980daa7600000000000000000000000000000000134ab48ee70f34b1558f2b99fb18558e6d8a50d95121ffc193358c9958ab8e98ff5ac607ad30448e9751d480986568261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e0e0cca7f2529bc7c264b4975b8c2b8cc1cabb3cb51b216281876331a45274422fa35e4be6f5959c557605a07e006a00000000000000000000000000000000182aee61a6e18a6d386020bdeae4ac52dceec81a41e6e5d42d36ca66020be2d6137d76b745e780c17e33056e4efcc2a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019fce199e6c20db79719ef4628867141d606a44cf920605bf07ce36a6f03b568d2763f2e69f13984a3fff80a9c48102b000000000000000000000000000000000718d2d4d1cf742a65700b4e1f381a1b84af3958c4e3a8670b17a0c0cd344617ca73fde662b56960bec067449858ba891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133a9816fca200f57b0ea30e3c9cd54f971cb9377231b1915279ad75a6c4f4bada568d60311b4835caf5a27134debe9d0000000000000000000000000000000011849824542e0c079029fcef54fd2e6d07afe05ec5b4c1cd6e3565f7b643d2edfe6acb4cbef200190507a59b2399ea8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002194fe7fcb9e1ce063f2c01f4c50993a4c029aa941a859ff91e15e3a3bbec28a7651bb34747944e7bfb0f8b96f4f7e90000000000000000000000000000000005aafb5a9a84ddead31623e3f567b3380be34ad23e783374665d25c71f52ec1692b949cd8c9d6ce34134e36024cb23201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c79c77a30863d778a45203e41c01b3a062b4507c1f7dc60e1bf7d040ab74db6b180a841f8ac038bd798821d76094fe000000000000000000000000000000000373c28df5de7fb7f2ffb4c3d114b73b1eae364a774a7cfd19d3dad6587e934385bd8a4bb7b3a88f55bb321646f0dccc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bf02193e4697eb78afe3405721638acf980135c52eda0d1e97cb96cd4f2253782125586c58a1841b60548da475623600000000000000000000000000000000108bc3a95b7c53f7b6258aabfdecd67361f5241cb913d0e11461a89e982ead96ce96933f3753d15fe6b1e315fab7e3281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125a6c7767adcf7f67a0a5aa32f701808b9b3cbb85ed94a219412e6d80d7705716221fe644ae9f7bd35b99602c1bcf2e000000000000000000000000000000000ec9eccb6f4bcb15bc2498910e546044231e28c7705363793fa98aab4a112fecce87d01e7da7751f8593291d5735667c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001966718b31c504ea12f09a981137d3a5554582bfd3cf4c377333209cbb0c1bfc6b874c14034ba26640dcf465e205d9ba00000000000000000000000000000000063c0c6ee9f30f325f3c57a61491217a9635a47f3ab350b7db610247faf5171cfe91c2dfc649480582ae4a434a8a4cf21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001673ac402eb2bd092c43ce780c2e57b6860119f0b646d7949febbe4b3dd535fb73e89ab845afcb3491fafd1d8267b8d30000000000000000000000000000000001975c4eff091d49ec01fa7b12c9473854ce7cd966e04d6f19829ef0a40f3f0d7e07cea12fb9d0a866c698458fa5232e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bd503388ce235a49347b06a59d7045994482479b55490ecb038e14f9b0acf5d3266321ff4a39e536bc0b3614240331000000000000000000000000000000000d9accbd244d3b824a2ca4c81891285c99693a2a9ca70030f772c2dac1ee75eec539ec115ddf1142bbda67756502317b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f57341fbe964a56df5d4b3d93662aaaefcb66b66c1c20895eaa36edf01906949e842cf4b676d0c4ecbf53ffb1d8e980000000000000000000000000000000014ba76f40858bd67e0def739f6895846b24919fbe73cafdbd8e2565fc198e86ed6e700b5b5fc67822c3c1e7b021a60a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001023e7844bd2a34fd0335f21702b0b4bb4a905635cf23eb5f3342a117a418dc9cacdc83c376703ac6414d4fb954e498a0000000000000000000000000000000006476f6b4fea601ddde15f83b94f250d773d2239926b5f82555d06ca0e257483cca4e70285eb17a681a2ffe174e03d511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cb06ebbe9d9d4c31bcb6109828e435e41eca49bdf810da1f8c9f8e5ca1094e625f89bd878a8c55d1ec1d17b7c543dd0000000000000000000000000000000011a9602be668b7fd6f8554193ac74a02cf5b399d62649571caa5fca6126b5b33d5b085e70751bcdbf8a66845f3ae6b421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013efa58da1fc78ebe4c9cea402f50f1ed5ac302935157fc78ad9edf53899912acda05fed6c94b5e40ee9e3acb6a0134000000000000000000000000000000000d9f1d498117e59718d01c82e6c1f5a70f97d994a3644c890e4ec0d5b692a89214cfb80661c1d4ca87c4e524170fb07a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000056b92e22b221598a4ff581b51add6c3a90de63146bfbe00a278b63a42ac7edd53246d4d670c82bf0123442092160350000000000000000000000000000000004ebaf4323b019bcaa5b6287644c30db64ab48762c54455dc8e8756d14917498b62e15b9259c0db3da456282694c8b021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d39f63042e20753ea3438150a060f24820af32601fb4d82a0604fe046d089f82e844ad220ec072f19b26e38fb1b2d8000000000000000000000000000000000adb7b0e4d52d81c93316aa3ab747ad7915cbef11e51ccabb61029889047cc55571eadef554b19921bc0604cf069fe4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190072ed20096256a4303c80ee4283a485ce3912f05736f27d8c94c2e6031ccc4f9af73960b7775adc694357aba0e1ac00000000000000000000000000000000039b9452906ad72d218532fd03eee7abee89b419f2d358ac89fe3abc4211eed30f6148397be24c5386faecd11a364dfa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7972fc63a035a1fe9606b52621f1ea4bf5a5f7ebbcd66535f5b48d43a3b4c4a133d08a32116337cca785cb10a0275e0000000000000000000000000000000017729ee6d78b5d4e55755f3ade681e10e8a97e1d58d7dff66b4e40b800b54f482ba1a9c6ceb8d9bdf7560c9097c9f94a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f679df52ea8fbc73ef29483da630e616e1fe7ad4ae3a2e315905f0bb882db6de2da13d247a027b1e684a4c4885d3110000000000000000000000000000000012dd2468dff38e9464643fc6dbb6c948d601caf462a267469b06a4d72b058a7d3158a3ec223f856093a984a1e73ec51f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001997a246693e0a01344e5e7d14cc8bba54fea5a7b1755c2def0fdd3335855036c1aaa0a201384edad8f3828c7d8bbd5900000000000000000000000000000000073aa8a814e610eb7abec355cb578acafdb92a9e84ff2df800e5852eb9165da3693ae857d7880aa2e378e80d0f1c78501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165334b5ea793575ded7e347819866807f3912b23afcd16ae5556d1e22574efc0fcae014ea62f9038fb4ceae22ec10c20000000000000000000000000000000002c2fe8622b6da8963bbea32cf314e813d396b9de50a256c6160bd7b83179e023990ecdc3d74415bf29f2aeabcaa630c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ae2ccde78a44a3eabca4213a509c0f2752c7488c5e70d26f65ea3875db4cdfc093dd3323cbaab30beaccaa87c8d2500000000000000000000000000000000013ac0fed61c96bd7032f0711add9e7901e539c1c579018532b3270d33ecf6d3a6f16bd749711d36bc2cb4e1be9416ef61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000661fa014f07947626a0744e29bc64c93f79328f1883a09934b2e35c8be93b5c9f9ccff2f138a9a28934f1689a42a35400000000000000000000000000000000137f170ff52e79c4fd0f11445296e01cc823a3c64b5de3a2f746a699eed6610446fd7260f730a3c92a8d46f4f5fbd1731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150e62275213410da1fd99f4b284d0a983af739a59ba84b9df118c9c013871b563f6bdb6ee30e87488c7cd84fd3f77720000000000000000000000000000000014bbaaff6f5f9728cc414598583407ecb8e49212ecd574fbee6afc07cd7a69d332c12dc202dae75e101a195d7c6df9fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a0a4f4b7375db4ab709c41473fa88432742de68efd7cd3c652a84efbd3c1c1416f426a0093691bc1d5d689617857780000000000000000000000000000000004c7be76577721d32cea70f30dc1e27c2935db3f51a60046d6a97b78cbbeda424e94b745af3ddbb95da2b7dcc1ebd5781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183961151e1308ccf1dd0c3edfdb0d8fa3fa55f678241d812327969c6838d87682f7b6231a777d0ea4a944738491c2850000000000000000000000000000000018b635aed5b3e6f3f14c9d147239e805fe1cdafc055a4235ab3b711fc3dfa5074617bc6d3e5bc62b10e93722fbb922691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e934826618ebea7b70dd3fb1b8858b3b33a518b8d2dc89b56d8dc31c3bf3576834b0af717db5fdeb362fbfc8f49bc200000000000000000000000000000000018a8e43431bb3aaa57db39526cd5be28cc11cc7f22113b4d8bb34abd7442cc4308481b62bc937886b7d2509d5f8435b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b133090accfc8198c0101be804fa771bbab85070c962b3d55b8ca9e683c2074bef91397e6e472f4fe49226291fc5b3a0000000000000000000000000000000000531d3e6b8b16a091ebe111b41289c705ed00bec7357ff6cd37a20fd4a4e0a74ab02bf72ee122656ecce4a65b40f4481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000acf1de55b18dfa6aab398cb5b936f824a9ebc1a16ece09cbc8c3f5f0194bb97eadcb69830efe519764687f2a0ec51ec000000000000000000000000000000000dddb0a0a50355b4a8b1fda33ad4c8cd226474e49ab62bbbabc979121ab8040d0b3660c450c8e7cc78df0c7ec5b309eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6c50c8b5e57b1c396484ebbca423c5a08a4190dbdc020920705b15692a126be97b70e57689f19f1754492731ca1c0100000000000000000000000000000000037b7d1c6372666748b08fff1cb3995acda3206f1aaa13668f6370caa871f964c7901ac8a5dfe09da44b012816782b2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000811d757ed709dc893e0873e32482c9f7a27db1f4178704d472848dfe09c0c67dbc36410b562d82ce924630b502786b200000000000000000000000000000000014c6b966ac1c2b46e6183fc5ff348e2ef1445e4dfcca49917d6803deee4e63d55870806d056ed44bb093681975f29f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a2dd0a8d15287d86826490e8760c21963b2a3779acb5e3dafb5ec457c217c908cbbd63a7ce5deeac44bda51c2b2b75000000000000000000000000000000000f3459596d662692dd96e541f4086af27bca94358fa3b7e484f7b1b6e1f3e335a3164626a629bc1a009ac881f16e56341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8b505f447d6de33df40229109ae3602f9bce1fd7885fd6a20453fa268d891b9381389a29a0543b60f01f3971c1277f0000000000000000000000000000000013081799654bfef12fa57936fd928f050ac89406f0b8917a8d357eb7af52954a8be4db98e95c641045876e2570c272f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7d0ae16c79dfc225055d92146234f9600abb4bfbf975580b9b830094813d14bf0691f1d8090e078ef3806078613b8100000000000000000000000000000000146e65e824ff866cb76eda4d75fb0680605726c470744504197c93296ecd2e091d540d7ee761404d3b6b48e847994a1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042231c089344fc9c09d80731ee734c8491b72e5ed1441dd9346661849b59f19e4d02812e9a4b812c86810b499e7803b00000000000000000000000000000000182d8875100f60ef28c6f7ca70edc0dd9b9f2c279650a452a44b16569b72d3ad113b324b10a24a0a050fa2f44704e84e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026df9b95bf9b21c3d6af8d79c43505ebe1dc2ea7d7e67e8ac609d14e45858d59de43901e90e6d760f98808dc40647d7000000000000000000000000000000000b8c1e03b7fc79e1c05e1ed7197b9f5d0f3c9fd324f31fac7c282bb0ad51735e683e9dde0f1f7773266f62119d9526011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137ce1c6c73a9f6d585b0aa9ffa3c076d0ff1c64f14ba4699c2b82f05266e3aaa6c7bd499e4bee39c1273e1a0b1d12f20000000000000000000000000000000013d94acac79a253181e2f9e251b3f7011e5202737f0fa46dc77e675a3b7608078f7ca12ce329da543520391acafc02b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fb0c98e8cc9425bfff98d32affbdae33f723409b32b282053972892563263d09be0b7516b725719e5c14c9d5b80a19000000000000000000000000000000001077b72534743ecde12b6a994944bba7d2d4f1a913a089fbcfb36199b1730c524315896e65f1756348e603dcd28729b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b57d7f46a8b2efc7636b95bbe2e3db4add05c7351bb6080882694cdb563e615b9f6b474ad07b1ff8f76a68c618f7c10000000000000000000000000000000014e36e7e70bfde5f22063ece7e4ef7beb6d33ad79c68f6c0f31966a9089120e4442884591580955c93e871ebe7d707ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d46605d1320e724a1e707c09cb2a9a46dae1cb159910eba01b5964bced950ff444e9f62165dd9666f30f6cbfbb7a8120000000000000000000000000000000010c6ffc262073c4f3a041103e1d0a0b6523fd6bb5bf86f0a62ff0d92a91d3eb85da4158460fa12ccbe93d6d18c33352e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f31a7a6b91d6268a9acaee973f62d883435697169173416aee8b8fe708bee04a0aa1ea3d6ff9681b9747a4aed6b7830000000000000000000000000000000004ef41111cbd28f1ffeabdaa67998d90cc36a5a37f021a7eed23980d8c74c33580ba5e8ebbd039f29e13c61ee93154e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113dde670bb398e65d49fc13d61168bba93013c0b4d63a4066705679cd6ed6e19fafd25f8f3736695847d47bb29b122c0000000000000000000000000000000012383adbc5860c38569e6879b14a08128c4b42ba878dac7c44fbc2ea548ea4969a7ee86e7cc7228a735fe1cb2f0d34d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001008b69f6ff2e8121ca788be709f5c121a1425c57bcdba7e6338e8d4bf8fcbfaa6c5666e88539459ab558704ef07792700000000000000000000000000000000094583cbd3f9e5de234ecbbf1c07918502764050722af7da1014b122524ba8f19c271160b782f848c4d2410bfbda6cdd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b25f20cd6bfc8e61dffadf7690895e78e9c0e2fc57699386ce5fcd4b3a9a8b56f2274daf9bd2aa571d7d14d0dc53070000000000000000000000000000000002b4a98f9c592586657a788aea618cc2fe74d11dd3055dde1439946ffca1834f71bb7ce097e6e89e76d056956023e6f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c8135856ad44f19aa60946926a87ec59bb8cfbcdf9158200a6f6217b16587f15f0ea324f0d5cbd865474ae19db8c220000000000000000000000000000000010730b4000035d23bd5f0095f699c0bc28b614210ad7704e63b289975298196739573a217e6b0d4a040821b7e0a70b521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ea66027b903d033f6d3aa0a5dd9b9ccbaad009fb0472193c8b615475a542d937570df36650c253f4d5be079f9be13c00000000000000000000000000000000016e7546fd38011c7412ed787a6149d069538b4f071bc89bfb34f8c9e75205e7ef59d441471d230a6c22b1e4ef9426411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b790a6ef1e6d21140ee601de150a768f6f8e22b3b1085ce227f9ed70625d0ff6fab617b6684043d9f23a321c4ca013000000000000000000000000000000000cc9d0f2caa382a8581ada103d683fb6cb01a4bbb029b82b2207a5d864f5f5924b8735aa48c092baa41d42011321e4121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007fe10b37048d75be5315cc4a3be9ed16f6c65c1a5ea36ac1c8f1d36eeb755789898e4e2091abfeb53c81825aea7c2cc00000000000000000000000000000000142d6c97a41d8facdbfb57ea6073d4e6ea67cc80564a93a9115ef99338f4fdc6d96ef6b4abc9e7c3a5d6fd6e5c6792c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060cb93dfd4dce7551732f75cfd707e5fab0d0174efdbeb95f134e3689a90f8a873101aa72350c50b31c414c0d3c1f2e0000000000000000000000000000000017517483e78db30c9d574755b8d95536e89a50a68c61fc4f62eaad9299a131a47a6009c11764616c188e51eb12f04eb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175491847481df452311edce53b35e8bf5bd7d162c8f94a663ea036e70eaafe8cf4b3f6a9d8fb308c8dacd9939efd3ba0000000000000000000000000000000001b1eeabba269639904d0b2fde01b0f00309a391f91a601a8a6046044bc4ec16c8b221eeac6439581dcb86c2e7dab9761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012bad947c211e9ed9632e098b21dba1a2d78234e018befa8d39ae1777d963a1d13ae05665a769f18995fff260f0dbec0000000000000000000000000000000000cc34f2e4b54811e64137f617ca712d04b2c4e75e5b45b835772adac37e3d1093f5989932b0268013944a758ae5dc4971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c59b5d850866d1c7d88850a3d1b87fb135bd24a3aaaec08779fdbed33fedfbb293a08c16ddf3b56cc6e0177aa84a490000000000000000000000000000000014001a5da2642ca1cd1b079571ae8dafc23d0c94a61999b292c3b3212da604144cb5136a4fa267988d8abe79c15edfcd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c92854a0d114f27ae33442307902c96bf05a8a4b8696ace0396809b442ca5a016ee0da0c1751bf2965a5ab0fda2c660000000000000000000000000000000011353e746b711ffce1315844f75c447bcfa8b178f474863be4348f30cd0239be7ae468eb4a475bcd2a0ec610c07550721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e3e41b684dbe8d04414cb6529f7c7eeac7e463946d3e65c16286063917ea5b19bd955f2ae4f66d2c8cec740132886c0000000000000000000000000000000006fa5c6273020d1b21b621f75a31a39d95f97513010e0629e95c297a64959bad9bcfddebc23be4e83d6ec8b21744acda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5994739094ed036eba753b64f297e6c7b355c7a0330929f0dd3b4ebf451746da51f4183a007def6d1e9b6e184730ef000000000000000000000000000000000c9f85c12bb508c1be890dfec05f46c6e94f2b3968843fc9a8de24cd565fcd26c0dc1be7198fdc3b24a81276609812121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d17d24fad0f216837b9e2b59bebea91bb78eb9453d7cdc85030d666089710202a8c754cc7352ee4a15c05ba2d27d0a0000000000000000000000000000000011985b9e44ec67365b49f96b6a69d8364f12bd0d20998679d7d6df9c39d79228840dd9fdd8f42127e2e5a860956666a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002711ff76847476f4f7456e47e938d8bebc2ac55c12619b66aaa619d4866d77221c54b9d8c843365ae248d685968e166000000000000000000000000000000000a2b84651691b96445cd6ec6b1a6f1caae37a8d7dc216993bd934ddf44a06c0ac1f2c5ec283ba2c5cc79e39aafee87f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001853e765b9ddb214e9b6a1b03541cbd66bc06ad66ae5be871938e8e3bb0ce68fd64d75f4e200c602d84b4f820c7a01cb0000000000000000000000000000000014eec4aaa7ad2b54e68ea209c34d39e9425fddfb21680747451ee0e0412ee2b1c0256526dafc09dee7548a485ef185fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f89634e5d6fe355e01c6c7233164d63e6367dc3a5520e6fea3dbd147aa9cbce7fd9fc38ba98aac2629f7fa6168145af00000000000000000000000000000000015306b8f46c5a1cea4517b98318eed290006247011a2a0be3ab51e303be24b0fe1749a2c1eb30b9375b53c65850a90b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033031e42e5e139061631509e852cf0b84542de1ebd43547e37c4a8af378d3493b9f35f87611f4bb147b926de3d1d107000000000000000000000000000000000ef7dd8241a6b051f205686f4e2ce67e6ceac4df93ce299edff5a491e460d791776f455a99c42bafed95cae8603ad8ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015cf7553686c59c5cc9ea059c701c6be23c886b5794921ddb63464fb2ef218bcddde42af99a98737a6959d06636a01030000000000000000000000000000000015b79e7d6dde6ec10d5f6d8dbb73a43f4922eb683213b321c51db9e8bb533013a15d7ed0f4925ebadd60b8388315da451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a24c0009badc2c8b01866272e7537b7786e8c3fb66bd77cdd8ddda8599a9209ba774244d6d18b4ca0d9512046ce71500000000000000000000000000000000100cdddee8a25eb17f88043321a1cf1774771321edf41d27cac7d9a9dcebaec18cdc68cc640de7ac64a354cfac0ab3051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142fdf224370c235f838fdfefb09fa1ef026d741d24bfe18f6b49926575c530b18ba328a81d873e6f8980f6c9c7570820000000000000000000000000000000018192bd931c1e2003f2e8294567ab9b6d8a4c6611871b320678d21fadc45cf7c7f275a8ae30ec2a0da9c0e482943ceb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000595ade45a1bd71a2f6930a0b37d63431fb0527824865b97f6841d839f71b5b956fd6ed807c9271d2290e208a0a363240000000000000000000000000000000013d3ab83e0223ce9a4727c069a59d6233acb527fd58548c38a65bcb1af36b2f5f8069bff5bff5b63b5ebdaaf083c318d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000037c14c346765731a5749b603481cc6f93963c041259fe7c5e22f8cdb2ffa66870b8a4782ef8559b9a534143ede6ce6000000000000000000000000000000000829c7314e2d2862bc6baeec3b7aa45bd2fbf5be9bfe201f6753c270afb1ce635c229edea98b89da821636127b54deae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001425d58abe34549bab67d814590099f431fbbdd1e7da98c889da4e7efa49ac58cb003ec6bb22a8185ae58cca2de8a5d9000000000000000000000000000000001741c76516e8c2bdeceb2ab1d9822d3d34ea267342a4da3a394e34799b41d3c88626b89c29b019a7b94ee231538594ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007422603dd8bd78acf6f36dc2384e0ff02f599e62aeb6cae26d59af16531c0890696b05d440749e6bd6db5b301ffd27e0000000000000000000000000000000012739703562e31a33678a72a1a8d822bfc4b0210b2cf936d3d4e0b8706c9e7652725aa8ffc88b1993928b8a544a013471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000caae310c6709a77141a190976a8223a70437a9854caa397631f28ac4257894581c41022c568fcc2755cb6e2918b32f4000000000000000000000000000000001487940d50bea9f7dac4717f89cb5b13f9042d19836047d9d54b67cb616b94914770d7c82231486ad143be3c057089fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b42c2a87faea8def82a4b5d6da9a58ad92a5142aabd527601f584de887a4ccd3d7777aab11f55889a73a0ba498cac30000000000000000000000000000000003b318ddf9d7299819408daf7543b2f8869e280b320a69b654f1a164e384cb062c53d1c2c1506479bac8d9b7196d132b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019791737e690d5c174cd26cf5c9ad23271525fd7b60a08a09d77ccbab3d00ffae2acf2edf8e05842bf0e25c8473ffc3700000000000000000000000000000000161298f470f57284851315af49aa4c416d90dd4733ac63e9e0e802cfa287ca7f10e03d0b7d8cb49d30bf28ffe2bec96f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff82fc1216f6bf48793e1c99fcfe3ddf8dfbf1df20fe0981cf282e428104e220628109d5ae9c7ade1e0351017975a310000000000000000000000000000000006dd1b893f940efaf6f0fef340d9328e3a8d461fe5b3cf1cc6d4ca05ffa59e1da06d42cbc23e2c021bacdcad8ad347691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000759168487e5f38d8cec9d244d59364632788346bef56d04d0094e340bf7d6b0cf62aad7bd73ba9c1652e42de5266ad4000000000000000000000000000000000fc3f4a03094c3d528fb03a12d657227ce1e61b77bf733ed5ca60e35a0dd8ffa230d8c691ddde72c983a5c8ee6a4b2e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156293d5c5cc00091666c8dc47aa2d5c1310703af4dd86098618cd986c1256709114ae9298315bfb5c19d890cd0a928500000000000000000000000000000000137ab1c1277b8a7d87bb9b6940c5a5379fd70e730df4279e8956e84a32638cdbf61bca9b9a2ca126efbc5f1014e2d3951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065a55834e5e40d12f95d789adf364020bb11872ee7dcbca20cb9ba165cb885ad0151fa5079888476f0883e4893f96a7000000000000000000000000000000000b3b20eebae3e658afeb77b4e66b859035ae6a182edbb4c762690cf297a9b416071281df1c02af5dfef96c955e70eb021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bdf478f1f0dbfc1e603344b61a34250ff8c08fdb84e8988815629eb2d6f0c011e797591e003ca7e620d2eb2e1484e2f0000000000000000000000000000000019ab5d62ff27572c7183af7e12898eb0554a678dd1a3b70b5bf9ffa42927af412a7b27591c31eb469092bd6f9cfe8a191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b5747d848c968d1d7f03387a70899274db7cdbe20e98a80d15286ced50e528ad7a622b5ca19f879467b2c3351fc3f000000000000000000000000000000000123de59541602ea9635375e572f01a39d7f9eba98b65e632ee36e912cd57db7cbf4d2dda750f07f0c776b531827fb1791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6f5356f9be7c05f5373b79d710d15b2a76df384adad6c0bd6701a1e9e086bf10f6f2a1fde3f06ba45c89ee87637fa200000000000000000000000000000000175f06c41428abc6cdd1a5f527d816b2d3689396a252a622fe9e4b822868a20199fb045e3aa8a811338e7c047a69c69c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130f1f47a101b93a98eb91265f032cad950d11a16ef9cde66a740f5a550659d0eab7795ff6c56dadc01824f7070f202100000000000000000000000000000000087231f19f246e6398743b15212f9faa3c983f016e052366b3454dddf9c79c20524cc3533472b9c0197bf405ec4160cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016fc97f58472a01cfbe5429eb559c31a9a00c3e797e6409f5fbc2854b05204e5c147d77a7bd6442ade8ebf15a9327fea000000000000000000000000000000000c413723ae66ead9c223a074d47bd817984dc91cf4dfc49876e4feec4d6fcccd9e7b7e6320978da950deadc2961af5a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a77235dbbc1b2c2cf2ddd353c56707b61e75a0e28b3f94f7d9809b1a220c70af31204a6e1332ae860e17706b32d419800000000000000000000000000000000037b84256c6f768eb5a057c1a865ffca79c95daf1afef21aeae1a63c0cbcc729851ad16ffb2eb9f2481534020c624f1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e67eeeffcef0c04e53265e5534c4ece37385c767bf95779498c87cf72d053ca28aad30485d0d56806e606a8fc220e1000000000000000000000000000000000cfa38da02853debecd2c9957a22d4f8cd4a0c1b364d8d440beb3ce2d8fd51192d96113b1c3d89e9790dadc267e899e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000434db4ca161e47a5f99383e89572bd613591d2b90364ea863f21f471b50c64b3d1883bad7a8c910abe25e9be54518060000000000000000000000000000000001eecbbd35e2b0f0d3dd42252d52951b494de78bd425b7d7994962115a3d290fcc1c970dc7ffd0776d367968b0e3fea11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149c99b029149fe5e9d1f8d984e7ba22a7c591a3800a9c53efa65ffb1070a44716a4016cb513a8a81fca0fe8dcdf06920000000000000000000000000000000000cc3e08e02cbc862f4ef9da5d9ce67cd4ee543c887ec46326ab0ba60ae987d6eaf459d7667dc2b9f3f9a4094abc98e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013935d17a97687a562e0e048041dac85cedc728c4c0e96872276d4c21e6c4971b4df846467dbfd0abe22a51afd8a7c3700000000000000000000000000000000105d663335d884601da565e6e74ead6b7c4530dc4a22de901a5e1133b22b0823f30bba4d6e550b39d04f659ce98824141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a52cc8bc6207af0546a5acf66f319b24ef21fdbeaa0ce890b94d7c8c465a13826bcb447ce2d67de0acdbe2a92fd33100000000000000000000000000000000084ac9190de8c46d2a1dd590e9e40addbcd425a527345d721a0871486eaedf189bb140363a3ed30b7ad72d4d76166f8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b86efe1f7b8fb6a7163b1b142215fb82c8bfa83bde03ae5fc6c5851436ec42aaaa8c54de4a86eba1d4af8c038f68a22000000000000000000000000000000000228c9289d4806acb45d12062b3dd0ba94f64be372d09a48831f4797a2b9bca235ba8a8fe20dcc54275af7c28d880c2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005660aa7d7235a7b95ea3f3b210638cd5fc77c63064bc20741ed11e4693af1786f0d11ee2043a1f324e02190a126e6cb0000000000000000000000000000000008497aa15a31aef7020975ae0275a30d63a229e5421153feeb95b8c8e146741111a3c3ada3faf25480c3e9134728427c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010211288a84a0f734c6f00e56ec926ce191048627c29f0f627ce87990a484597b0383afb889c92499eb4712d1aaf177d000000000000000000000000000000001914157c0b2581c656e70b6593d7eda41eb915507099c5021073875a50f435490c531999515b81279c0ad2c7806651151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c25f3280b3f3f642ee083ca59d45cebe5c4b24a2a0e55e2592c239f3f10377001443b61403eab42ae64557b51ca06200000000000000000000000000000000001f14aa3e724ee21f9f7a0db09d926144ba53bb6f4226dd880c80b7b92a301af6368f3ebec9b1d8268dabbf1bb8dcccb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9605b895cfd007a7ff246d288485be5049cf0bf2808c2c3695a585f29527492f1e0981b38f8f597946f978e2902e2f000000000000000000000000000000000042768e6b159f9d297d59f1a3b4525e55ba168044aa4f374b631b3d76fde1d526defd64d56b4bd740464b56ef3363221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001a2d59f9b3aaa4d91f0d51803d559f4b422c16b9869cd3ab8954bb01eb7f64e6762211ca37b6c7cf035a43b3bf0dbb0000000000000000000000000000000019458cdcb53683713de1a020acb5666b91aa813c4440daca0a6d2b8c68d4c61ed1b4c8812af490c50b1289ce62d2c2221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013daeedd76807aaebe0dceb29a0454c41a5e1711680ac4c0956191f6e2271523e68b301ba3ba3637a067e0737aeea52b000000000000000000000000000000000c842f38681df32dc8e2b3dc48e9a98a87eeebb135ce8887a25320afd4a22767b17217168fdbe7673d0dc4f4b8828f531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078c52f3352ef8666b4a7ab6e02b751cf42ab0f67772e947903220fbc493ba8c729f89c9864e97d0adccdea0730b34a6000000000000000000000000000000000e88e0e51dc0c4583de937753513bfeeb6a0b83b6b8b916c29585aefb11817c4eb15198face86415c83cb541253171e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001523d527ba948b18a922f135873e94c86b72bfe637d8139b05a09672bd311f8dce4e77f9b70ffaf22fdeac6aaa8305080000000000000000000000000000000000ab481d920eeac58d2110432b0ef4a53a3b9dab024a01edffa8d5a0267d2bd593fc7dfbd26eb290f2a26bf9b81501451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031c17d1dc34a8926baa64c39827e2634df57649e866f6d5b5a466181e74932473a93f7821412af71776baade843365600000000000000000000000000000000179ae236d19e02702f03f79fc4a2df73f1e78d7e396f1b4d93b72d5c9e3edeab5361eaee8236fa10c6c9fa5208f5ca771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000242a54aa60ce662759a3dbc073e620cb1274b66b56607eb7226dc56e0d630d5f222357af0c925dbb344720b701e1900000000000000000000000000000000000af7a28c75b54681d31cea97ea0c1d0760f43cf36b38e7892f2566ff595c464c4c2658c7995e82edc8c5cac6e14e511c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000797ce7c88f8b92bee00c66acb9f44dc6b0c97715acb2551b278742046011383fe01f51433e846eba05fdde06468164300000000000000000000000000000000092a85310ef2293c4b6687ad3076b81f1d2fe2ca8ac5079173ec9b92ca368accd1bff31ec5f398966c8476cae1a58a0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001870ff2e74b8c9b9fbc0d841b0670aff0641cfef16c6fe8e1074de3cc167a0d7be96f1e313839acb43a3d1808c3db9180000000000000000000000000000000013e9b07debcf3c0cf834dbe9b976eb709e87c9888693a7cb279301b89a7f8085dfaa8a73e73b8956c1396ca83b29f3f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e61ffe58718c79d4739bb63ae922fd6a7ce12d0db0f7ce451f58b10dc8add9a5ea8c69e769ddeccd52c643992649430000000000000000000000000000000004d21e6b4f86c345a8297f0065c1c029c636d8e94717210f692c26cbaeb5153a94f3a48508b0497a1ce0db86a8dfa3e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e0bd9109a5fa9f2766cdd043fae09f8757056eed27dedfa6c3d400fa28501205ae172ce77a36846b36183b9c007f16000000000000000000000000000000000cb48f5677272c2e617776a44e8f3a3a47e24a59ec63f94eeaf9d3b0e1a70ae825af11e646f967a48a1a542dc0ab0c901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c2f27da60e1d9bf894295bbf715a029e6be14ff32f1ccd12115ebdcb0cc825ca8a6bc46524d77640c9884c05ec5e8f0000000000000000000000000000000015b9652fee7c9febcd32a5ff466bc4ebdb73662e411a3871a203330c5eabedf4eb849f3e86a819e60dd78af14cbb82681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001915de1c647292bed3cf0f626a0a7579dcd42514bf216c2a2c33fabce4dc630256911f7d82703882f622679262def9cd000000000000000000000000000000000982dbd51471ec2fe780f116c1e67efba7a2b7068d4efa76fb4f9b62b61d0cc717e3b4cafd4d33a7bc5eb86186326ef01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8b083ac5073d49f91dcf2f4dd2d64ac36b68e7be9aabfa1b1e006beaeef23c668787b499f55445eae76a808cbd48cb0000000000000000000000000000000014cc2521de20bdaa49a60c55aaeefb919800aafe54df3e682463cb44c847044aff2586bd53a677ed986cfd95353c31d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f25f87a363ccc6c50fa1ad639afe59201fd1497b0d8d534b0f78c1fb8c5f2f3ef924f607d3c038ca2af843564f0ff00000000000000000000000000000000010fa0c55838bdcc278abd417c3bc8fda1c77910576439338f4e614222894e1e7965d35804407bc86b5df14906e1698b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000504af0122b4b6423ed68a9063e8ccac9ec3042bd671b391d73e43a7bcf32fe01e900b79e38cb4bcb8cd19407c3c833a0000000000000000000000000000000001184ac4c76678c71067863c156d0f9a184dc7e141916e811475ba1f8ed7c734123ea6c9331248767e791916ab9df5e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003381961f2eb0a485dcf7f7b7cd3e9472c353b022c263f1ea50ba8b706cc31e08bcfc5d58165ae36309669c40d550ba10000000000000000000000000000000006389847fd6dcbf8fb896d7f235c93bd4237a0dc8d8b107c5285f8088b7e77de7a17efa381448a4cb9a65038ac02cce31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017837a963684a8f0d66ede7d54166d443ec72463365cf41a357ad4db67765a61b2780cb010b5e63dba2f0008e4cc0ebc0000000000000000000000000000000006fa81b011db765fea0328baf86cfb1c52a3202a9377c8ddec0ff7f096676edf5ef7bb723f77c9c4fb9fe2059a2ca8e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd4608596e29ffdc156e4ee9a34490e4391ce5635cdd23a3d14177c2a226a7986b32d612d5e75945f5222413285963e00000000000000000000000000000000193c7273463a7b626221da82b246d03d335abba13ea3dedf08d031054ec6bb2eb3753a212b364ff003afc1a5b02bf5c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c65946cae08c4bb1d5d9d9e88d8e1b6352c668b843887de7103cfdd11bc7cc8695786bbb59af1f9f5a62e74df2262f00000000000000000000000000000000018ecf72efbd7b51c1b439c3bf90e8569681ef6674b6fe99d602f1ecbd663c0a3267e1b473774c06065df946193b23941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a59b440519cc27aff499971118e8fd208d896f782d42d13fef77620437707b5253d00126e63745dff73b8bc675e879b000000000000000000000000000000001600c96ae36e316cb7000c50f5252b87a3aee98a8eb401b74e86acb28f9202a7f874dc9bec14b78f1a8956389e0df1201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037943a748862e0ef68849a0f01d6c46012fe33fb45414e0927767927c4edd4f03b23088b6bdd5cec856fdd8216f5b5c00000000000000000000000000000000009f3960b95c71c2c955b8b2a607503600b38f60a25a9b3a4d8004567803cda3a97534eaa1c6bb3753b2befbd08d0d521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004eb21b34f330481b3cfa17d3e34daaf89d733c55c3117f84f87b42f00b52cdc00d9a25d9e33b38ae29a069bdb1ddbc400000000000000000000000000000000199fcc646fc80a71aa6c0c399e23da824f8a9ae85bb0b676ef1cf3f182c8b6cdc9267b722b5b1aeadee8b9396af6d41d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a58a23f8b32dd16eb33935e4f350930ea43ce627fda908e8369fe819a222eb5939b7f7ca1e3966af6a01ec8a4800b800000000000000000000000000000000100514e87f96d999e2099f3f43406cf7ebad2b0200af38bf925db6aa4e393d466f4781a95a5c65c56d642ec2c75669431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d6dcb70b9abf4de386a036e6fdd322f961006c0e41920e387b7a5614ce67a516804d1d95d4920b244b8d301b8425540000000000000000000000000000000004fdc7e22bd53dd8c0682178c299964a26b225744d1397112b6630454191326bb74e18ae896f431a115f14920fcd34541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e9777cc480c91a39b7bfec16ecb5aacd86e5ed349dfa7d87c20f966617a69809c915e8cf3db3296ec9354ab783161a0000000000000000000000000000000019959d41887cc7f245df9950614dbe5e058ad0688c46263aa930b8d7be6f685a15974e308388b07102aafa6c481d80191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d8c6cd8d42556f07d76f17e347175c2808cd9cad375c905d2cd49995a9c6bf98ddd511b67183d1659817a1384257df0000000000000000000000000000000018ce8cdf9cc7ea57766a851136b265f147758fe859d1015020c9c7b0c7152178da431f456cb996423e191bb5f9581af21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072cc6276cd004b85751f361ac83d78b81229dca5467fb4c478b6e27144618a8ed7e281cdc8c59c185fd4751b502f74c000000000000000000000000000000000b37960fa9e16662f389628c65bcee50107f850f3307be578896718003a0e292f4ba5c91162913ed28311be2b030d6be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e026e225dff7d20d43b1e68b5954f8bb501c667abc4160fef966a3a35de4b9407a8e540d16d6acd768688c53445392000000000000000000000000000000000e42d3cdd76f104bfdf7549e324836878a11832c56c3f41023cfb173c4c149803be2f179fea2d26eeeb68443991025981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099283e7e76707f7b9b33fcb838740538a4638e686562645cbfb4dd504d93074e2bbfd0185ac29546918f8622379c3f10000000000000000000000000000000002539b10a4c125269d0ee300256422899e48c4def2ae165df7d9f40607a3a7e65af2d2e3a12086010db80555f259aed31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110fbecacf2989d31877ffe36fbeb537d8f49ae677b1e2bb5f1a02df45bf4be41957f9aa811c3ecdaf8f6d48a6b08cfc000000000000000000000000000000001507566a144a09cf5faf8725163cbec5fc6e9ce61b606a30700fca163c9453c7f4baa71e5e1d12d78b5a6cb92e011f391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cecbe40d14feac2cc5a530b01543e2261a7c6432fc88b10e24d76bc1bf6e816c0fbe4c7f0fc19cf81eec889c324ae20000000000000000000000000000000007ea3671a42cde13027401f6761e022df18bdf59557ea30ac9ff3b33b4c37c236a10734ff0aa96a4ef3e24b2c5a599c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b654ef9a4cf80be2df1a1954b647fd43889c98c868371b195cefab2b44bb8ba65ceaa3ef40d7b25aaa3084592989a2c000000000000000000000000000000000a5c25a80823e96d7866a10abeca8cd60988f39e5c15494ea670767a8818a1f6134bf197c856b2558604ead7f14ec7571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022e77d0748c92298d0351f3ecd78a53051f85b370e803b3bef56f896a8c919e64b9f9bbe46163c5803e645104b613390000000000000000000000000000000011f422ef67a973c8548b933eb83b41a12993c0bca651ac4bde625932064b1c18ce2551a178902f7aca5f2d9e0771d4271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b25cca8ca1800f2effe7b73b26fac8bdb4dd52bab133f352556f0c4ef803b27e1db7efa46e0bbd0b223b61add16126200000000000000000000000000000000138c31a3c1dbbe739979cad8046e419d93ecc61f7af4a77cebac16f91c6d9725a2de02527a47522d8f8999f489f566b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b4541dda14d014b5c660c64605abbb8938bcad2a5a8ef88010be8f8c44ada7522eb9a926f6d4e15dff1bf46a63281e000000000000000000000000000000000379bd9b32cf5769365ec07a749880a08a52d90e6672e4f99e1d68994e76b124388a6fbd2fbec4acb6791b5f932fe5561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f327ff6c4208423a09aa244d0bb652d58457d1da9207d16de30d5e50b119aa5834a981c740b6c81197295637701f2fa0000000000000000000000000000000019b89be5e0c619603e6dbc48d8aa80e22a96e0ffa8d4636033ebcd34ebcf051c99e0227ff397181ec26def107407ef0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c27c00a28372d17b821465bf78b475b5dbe2d5e352cee5898c4cb2df0e96c6870f9769084e27a5be3d94a1e8f3bcb70000000000000000000000000000000015dcd307586ba7aec7c000f7bc26ad67266f8b7560c7e61cb43104484f4ac2438f3ec20ffc9c4d165972baeb1e3d97601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000959dafd305d580b6c5204b16ece2884125dadff0bb47cd4d385739da36d673a98ef3ca92770384e5154c837ed7d088a0000000000000000000000000000000009c62087e6d6a6f4ee5f9f85d246c61ed5050c8f4ce92e7482b5196c3d91b87acb22729afeb4640afd9a22931af79a851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001374226a3faaddd287c13d508116bc156e5dc9aabe3a8e43b7a4ba8a20073b9b857b29d34a626abdcc74a7f76dd150a300000000000000000000000000000000149faf8190e19640064246c2a669e061a87c235db16b29b0902fbbf6507ccaad40604d2ef4f42d7569c1f6dd5ec6c01f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012149361cb00324924ab1c537a295833cfcce0ddd985682545f5be462d9483eb1e7388bea3a687c4bfa5e3721c515903000000000000000000000000000000000b92a05caec1f1f8e8a19632d4e9e188d39364deada60764042d3bc49440d4e1c55f5e27a5c19c9bf4fbf1da5e106be51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbe62a12a4e3c6ee1c2d9baa17d039cd706944ea8777a8506ae925bf981a04dfd0d2af8776fd9cba93b4fe98a8c2728000000000000000000000000000000000140fce64d1bb8ecd23164d7162a3e621b95f4cd77352b207b0ff8f024f244c43111118d9932ed8f494393518e76cc351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ba939aed0955f2a27b9d4f1953fa9b02c51140da6cb6bff23a1c6817eb98392d0fcc6749ea10b493d783d9c38015fc000000000000000000000000000000000a737980b50e4aad5492d2f8314bde67112576e07fa771f82af3c987a094172cabc6fc93ae44113b49b7c42a4be1bbc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe73bb5219780f30966f76810f2bcf92fd118ac83947946827e444d139e720d87bae7ea299ef4fee23968ae543018b5000000000000000000000000000000000419177640d967c11a436457f42fbd1111edf2b34831b0f3784b45eada7546f7eb49d51bafa47d63372614d4142bec2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b3a2585f96f27e335db7b80479d716f758abbbe6d5ae2de8856e6dea0b09332a95040caa094af1e3a06dd59e047b460000000000000000000000000000000012c7467ab17344443e91ae8220576293be411e2298b528e14bd341a857674e0a7947edc5d909a8eff1bd232ec4c0ba6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e869a41a4c8c3a7cc03b60146a72c3b07eb9208a6d1ed57663f2be9230987323802969d4a30dc7c61a6dff04bd0a48000000000000000000000000000000000701fd43d4f9c3a8fa880ccf88a7168e13528ab1f9989d7593c10779fc1d9263d86e61cd99d62188c3a496e054293db81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f944f746e34e5c4340518f2c43a59d9d2966fb56970cd91901e27aeee3d43b35924995042d7edd139d3193ff6a82c8000000000000000000000000000000000946c7a80ff7690530bdef41c69e7b116498d75e2fe42baa7b942a5be82e150461cb82db3db8ad6ec043870130d9249d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013082e93c4df7903a6ebb9d3cae1553e7ef457579b8cafd705379b6299534aa1a289a5a1f946af3b03098b0977a6e9dc000000000000000000000000000000000e10cc8ac4b9ce09c91690a13b6b2ecd8269c622f27b7e03558139d7dc3d3a4df5d271d722a5338f47b0285068f03dbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003721f1df3ae17b3bfb440ea29bd4518848935974e198d881ce3ce6a2ca38ec1066cb9bc7b76f02d6f3b5e27c192fa07000000000000000000000000000000000c5713077165428ffb53fb892df24543c3ae20dfc5f98ead0c0f4e7d9299ccd22f581bc67e84f26af16b86d4b1b679411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001764325a97862342a95fad17a3a56be14d320f120b310e3e043790cf581afc952aa5013d3109adc8a34b53bf2baf9b320000000000000000000000000000000012c0c53fd6b20e3c087306a781fa05e5926477fdc5667d68620d7506c8bb41cc50028c79a96d72577a73a5cf5db4dd861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d52efeb200d553e72772fe4003baffd1bfa8ab21e791447d68ba1a9ede29dd61ce7602455832ef04e100d1f33cc27b1000000000000000000000000000000000d8db28b044832d2ae490d7cfb1958f37c1e6d3810ed2be3280934757bc073248daf65da68e8ca282a121fe11543e7971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002baa028bfee4ea2d8383a594e0a8dbab82e195979c3da981278174650baa06296dfc845e3de7f8498828ce57312d3d30000000000000000000000000000000007a5063759d4bf602df5d1539eef2114e40b5248065efa678a35f4beefdd277e8dfb1b1f555bd20354f24f5c6c453ca11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001841b858e4fca2ef8c6dde997b14e0f74c1ca1117ec3d4ea787f403c44cc2437b208a01214daa11be9a42a5efa7b5a700000000000000000000000000000000000e36da1ef990e8c6ca161a5d935e6d40d3cd33029da27558ee5ebad8646eb269da33e77262b16fd02ae759ff05a3cc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4101b03b3899603b7fe2e48e2d19ecf0d1bf3292ccc6e58d9fb7e5f9b7f4f8e58f33c5c0e28d0f0f5e6a88f1a2eda4000000000000000000000000000000000845e086f6a0bd9ed7b8ce67426c2c7d6a7535c127c88e2c223756e32c7385b52cd25d47dffe4f31d15dc659f251a0f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017362e42f80fbe3d408a55ce25f7b39d7927e82d0b71a202b8c2fb05e7092a27bacc9a04ec0cec2448da08005e4f1fdf00000000000000000000000000000000079a8ea525e98d5ab3f4bd0b1e428ad8c2bde15e4c3b74d61258b692f4c497211808a46658c419ce3cd5173f1acde14c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000307f5701f7e90982fc03739cee3ea484529e0c88cbb34d692ac3ff7f4a502a05578b3323bf3aaf62433dd4f519803c00000000000000000000000000000000131a48875cb930e87f495a78e80e111030c3b13ac6089caa4853f08f54689655fe30160ca3951fa5de1b8f787b7917ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000095a56aa6424772e757dbee4976cfd6042a66a37f42c1b845d0411b7fc7d359704ddde13deb094b42342834480da13cc0000000000000000000000000000000016ddd1dbb74bc38b9beb25313d78fe91a6d088e71b244d0586f93852eb5c9a79d3f810bb9e40e2496af71a8f8615c4021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007206abacec86893ce4b7be5673cbeb8ccb80a1e46087472f542733c163f90a1ca524b448aadd243b6f9c7e214c0ba7f000000000000000000000000000000001570e0208b9adff5051da5aef7a8b3d404749ba7db925e5831a1bdcdb8cb98ab30436383edc3f35d9a257dba55c1965d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004deb1a6b8ac7248cda184a3dcacb67771450303d06be28185c26ff81ebde1dd49f01ef1963f9d8269997dfaf12382e8000000000000000000000000000000001200daddc288898e8ebbbadac3225ba68000779d55a049401228b4de1eea69394e7244a2f96ffd88fff3b26e171cccb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b9a5f9d1d00a5c9a13245f66aba3484ee8fabd4fed08ea3ee2846a8abb5d2e3e170f500b0a6912241ee26f82f8403100000000000000000000000000000000189bdcd1170a7eccd9474183b96a7905f4fa970b5af3ce281f63cb068f86bf255fcb9b7d282e3a12e31e8053c9c590571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e97979b8db52f4a8b32e74404b61521266049a54b5c0e5e16367641776b0359031302dfb37ea189438fc45e2f7a93c0000000000000000000000000000000016927c16874e70b9ea3ec9ff81862d62704ea86e3cf2fe08af235435e49a2fa868aaff66e975274dc7723147421844411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001336140109a3b222ef3a8ff1b5c43472d5afe6ad9d3730f53e4f442d54fcf72993554ac81161cbfd965b39fc28df12ae00000000000000000000000000000000180e2489700d2af03654fc0daf434e91f9c13e2404be49c308ef1c96140865b38b153383869ab05fae2445b6d16998e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016d756d504d51b1c16737783d8704b5c9b28a6c2acbf3361fe675a2a85b74ac38ff4fc6f1c50a74c5aa6f13df0842aa0000000000000000000000000000000012abbc0c41bea3154be90981f370cba3948c4615e94b1c5684327d107bcb98980282794c42570e2e72985e1db7dbbb9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007feba989f5ca654abbb9c3f94e6bb2947044fbe8e24a5ade346bb8e21850b8d1f96f196d49b5b7a814e1ff18835877000000000000000000000000000000000088baf2fbebfffd64faa42240afb4052cfeb2ee7fe655f81ce5d90d5e5fe6eb795f7c8fc298ab18e7c7f1dd59c5dd1e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b396bf889140595686d9cab55f8d0b5f445381e2598e7e09e33f011457e9479f96cd8b82b1171c4130f158fddbda8c00000000000000000000000000000000089481b1f774bc57db2c55b869e57021b263cc44d32d978fe6d164db60a69fd19c2196b51dc3c164ead9982fe59ada371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076408fba9c5def26d5c4e2d51d27b9175976dd76ca136194107ad2f9bd2884df7d5a388865fcf1a69d7d65b88390ade0000000000000000000000000000000019ca52a9f338f7fe53c84fecd2b7b0ba685ee00c0468ef3f95f20d59a8fc9fff48e95af7ccd0ad2b5d54fa2f8d26778c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ef5ed1107b0cacfbcd0ec4826a541dfaa58012bd36d8e7d1d263296d00263526d59d74c30f5cead2b21c295fbef09100000000000000000000000000000000134234abe4f6dacc63d81d72b4ac8496871ee241b273bc6de57ca7db986adf2b16efc9824ae5f1e3b86568ec1e52e0a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130466efb332149a161a753dd9081cd125054e71a6f4c3d4bb518bd18a1dacdd15588961e3e7152a1b4a7d8f10425624000000000000000000000000000000000bb37247fd334f757255cf369dcd160c3c57c66ee59618f001df3dd82fa8e5f22f04bfb745c20e48a6b9540296f3c5401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fec50fe91297632a74949de95c6d9709753138832747c05c727cf3c762462630ae4f6b40db59f6989521a2047a0974e00000000000000000000000000000000076e8039cd188a076f7699f9146a755b204660b9ab7a2cca2f52eb4caf23c39c15190b90a9e4d6a8e9dafcc2e539d14e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d46ae8b44e23ab46e6ba794472664605b4708d0f8058eeb57251f7cf5cedc7892da092e7cee4b41d4086164c67b7ea0000000000000000000000000000000019d6acc78ce3e0e1b5a3112dc9d11e4b0d8f6d01b14df117ed2dda3f95f729ae97daa2b2716c31d6a886c1732e4e5b3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000601b821982b1d3cc47d27954fdf58a9d0079f3938ac8739e6881366ca95e925b185fe5807a1a084f73adce26cb2f606000000000000000000000000000000001566cf78b7f467cf593f6bc497b722374fe25c5add8ab1e37b0e7ca0a49eed7a05d8fd5ab5ce192f5feb3dd4e751f3c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f197ab1535890a0c9dad930903a18fe9182d62fb0a5febdbad360e3393628350f73b28fc02e875d6db20e28431706ab0000000000000000000000000000000005a94ec83909abe938e8e3b8a60c9a05cfe52983feaaedd6db606f794fa5981dd6dc45d3bdacfb8c475cd82702fd92bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a55c09bf72cdb9204fe57b1bc49757f4dfe647f8273b02adcc22a8cd5505275aa02abd5041da83c065dbfc0e46e47b0000000000000000000000000000000002dbadc1edaf5ab65dfed69d700d1303559a955850089c011e76bfd91a5e4be68c2633ead93bc55164d1b8778ddaa4991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092d628b9b8443c0087bdfd3b3c1cf9060ea2ccbef3388acd130b6e85d382276910932e217b65d8280e0ea59ce2c32ba000000000000000000000000000000001906d266723fa2e1a7ad20c97c596be4c3ed6844696d3554e9332f2d7d41c2e3c7d47d88b9812722ce9ecb03c8803d191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f031599ba21cf15e24afc2b5caf796c7cb5c748260dd19a0230a934acd1e4f057e1fe5469d7088366f06863898348340000000000000000000000000000000018b3aa8d5a1fd73c39b23330ba6ce150d85e744bdc4eb1e89e79176e9c55b5ea5724c9bf64207c654fd61f363f44ad021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001994a4790df134ae14ae149786b027943fb4a222487d0700fe64dfdc47b9309d7d14c2221b75445bf0cc3d87325a14b8000000000000000000000000000000000d753cb5a28081096e8b10887df5f787e718be9e37a4f9f25f514015f99d56536953b0122a5e44d7b2ecf996845dbeff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c788b4b3d572bdf266e1448d6f616f5a32190eb36cf86f7dcccadfddc6b8cef2d6e8176f5337986c1d031f52437b3f00000000000000000000000000000000103e58853bc4e821aecf81aa2eadff7621983d28ec2b821b123cf70fbb83735228cc917282e58ce1f69af939efef099f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000759e04cd6bfe63141c828c35b726af3cb300fc3440a7f53131ef96793f0337280d58ec44d4e9220d40b1ee4e28a472d00000000000000000000000000000000185ee56d6b2fb9b54fb0bc8de6c707cae9abcf4013c404f4e60021b58bc9478ed964924324edf02a3fdb4719f78eccb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082a4034ac630bb1e6c175edb855574ba3a32e791578e0e2a37eb77e5ec0e33e19c5e381f589fc495262e266109755f7000000000000000000000000000000000fe4ff65445bbdbdde90a0e24fe3ae9b60bd114166ffdd96e540e85841d6d7b2381804880d61af92494742b538ceb41b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4f52c043bc5b7061b70c32b75e6a23f5d60625dd5be63c4c0feb62b93476043c55981e5dd25dacbb4940fc49630fed0000000000000000000000000000000016c4dab374fdb507264de51e1c02649b4948c5350ca0dee8ecbd006c8bcdb8f6140ec707d5c77e86bd571b2f89db44941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017604117a199ffafdf9e3c0c601ddc97700d971d684680ca555e84ed5800a10a852c4438c9d4ef7dc278aa7e21e24c32000000000000000000000000000000000fe7425221fe3dc62b28c3fb17bf1dd1f75d70ce46a66cfa06fb49d72827ebe7521f036b6deee349c17ab53e382c87681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000895c511ad824039acd2a68662ad8861267233ae760121618b76ddd0331f85eff99feeecde95fb5240d76e6bc9d8652e000000000000000000000000000000000aaa407055a1894dd30a00d817ecd16e1380802b1e50aa76a08f1b1fc8b2e2b5e8b05f07dcb0563b75d7746eb563f2751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082913ce03bd087958281d6d4e925c3c4973047c7dc2aa06e08607d36db0c7aafc52ec8271f6052fcc7a8d1d48946e2600000000000000000000000000000000150ed6050298f26cb78c2d89fd247d2b03f6eb9f78bbece69b2558220288a3e98edd11e34dbefaa944eb3ecc50bcbc1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001220e91025956120ad3c0a1d195ddfb03a24f8295f7da3f848f3ada7aa6fc7c428a9e89b1f03e4c64b6ef3593f11b64f000000000000000000000000000000000f679e8346db24fd2a5e9c97c196e1366e96b9b2e3bbdee7bfffa2e81317e62edbf40aaea46f8edb33e0fd78ff30180e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aea4d6e8b5bc1fc871500e4403af57a39db7174e8eb43ef5400067d295c4ce4fb98ad8a583227ddc22bc717d2055a610000000000000000000000000000000002a91e7f14f3e1032f0ba54e65118f182c877de098ff265469b1c9c0e3d0ca2afa6cca4988b8f4cdc11e4b681e6d5b561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f1b13f8a0afdea83dbe58f2d7358004df183103edf053d5a5b66684ef801d7e552b030458807f773418758b411a5f8000000000000000000000000000000000b53e8b1c0993fec54d82110a0d9f0791cdb45f507dd853267935125e09d8fc191c7da072f15231ea5570bcc6cf1375e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f15a7f2fc4d0e6d99431e54d3c1ec067e90964bf6da6333ae11b97067e20cf85750e38797f2dbe72b38a0dca0c7e6c000000000000000000000000000000000141a00e60a3cc05d4b01846fbb24740a28e8bfaa1229e80c28389b0817519c0ab1fbdb7ec96c94d4509450fceca3df01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001480b1cf8cae6f1df6df5b77a5a018f32f5990fe2d9143ac9c6721a63db804ffffdd63e360bccacdc6b5f91f941f9aad000000000000000000000000000000000d6187fd6d329a2d2fb7205f6c69091b5e72eb4d693d7b44be1894174de0dee2400a8c93c0f8e30a535b408ace483c641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001232a3ae2a9726895a150c79e151e0524e32e4ab21d2e3400752577b92c0034a51f563f1b817562838fd5bfb6134e606000000000000000000000000000000000212e413ae3de9b098bd15420948c85bf048547ef678c1a28116d5672a4df10965d6a68eb388d6c1ba6786777d8dbd061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197846af412005e71496df79f0c8c35cbb0f0be4c84ddf0928125ee0aa21257464c5b24bed0b8a306f85d9383b1f6d4a0000000000000000000000000000000000084999a9761157a601820ed61819636e5d4174c2e02aa3d442887757daca735091a755747e9e104818ab43f3e70f751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000470f3a35a1b8d9a0fdd988567da1ddbce8ec0eb777527f29fa94c65fa07250eac6facf16667f7ed3891458226ec4c0c000000000000000000000000000000000c750070aa47567357b042e664595687a7a9114176d88c141d035156d3f9a41bb43ff43e16574a16b03081c1286f8cd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040a06b4b14da7522eee96fca05fd48f0dffc4c7529f67c58b188eb8b1d9e2abdc1d9118fed5f8bcf5c533be105ed69f0000000000000000000000000000000007c17b89bdee1a4418099901a65da0325a3203f0e180609344bb1f647b6c9745be8bfe3d7dd90450074bb3f8b8f431171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000140977dc235cfa7da42badb6dee5b180337d5be4a6aa06949a6f3183224f4eec24af01bbf1b128b95fd3b3991592973000000000000000000000000000000000fdf8cea050130ce6baea53d27156533264774f00753785f9b66aea05949879f137000a2289ad657ac97832b9779e2481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b32f3ffa905b1cacacde77ba1dacec89528def3c42f8b501aaea66b316ced3c7b632a1c5a45f9431728c060e06c092900000000000000000000000000000000129c84e748433bf402ab0ea6ae5868064dae4c09767ce4fe8b3064f0a1bce94ac547e9119f3228846a903a3c84551c4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a535796c5cd1683eb3c373ec66bc837c2e37fd06015c4201f8fdeb2a4c3dac307c7e8554c6f3ed2d82d051800513d1000000000000000000000000000000000e25dd60588332be0b546dc7e16af828ad17ff9132c1980de7132d80a76c382d7bc69774818297044e0271f2b6028bff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001417ef898ca333654e342827a80d621ff18810661a609ea6cbfa7ef25001bf694e390511d1c0489ecac8fcb368a9db380000000000000000000000000000000011a193bde26ec56f6583d76f7ec43e2cc1ad86384e3d5c9574ee0b7a5f0d2ee2d6da1ff5bc073b696ecc24107543caec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8ab5b6a5e45ef44620801c0726f3f03e072888055b0bd7d767a9fbf4760eb70a959eb474c8da8bcf4294f22cfb44f7000000000000000000000000000000000dff76fc074985b900720051408fb3bd0340fdd487d5cf9a7a8d146fa6b3a673d1fd453cb4f7ba06a167738b9323acd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008c3508ff0d3925b153cf4f37ccfe0a042f042d5e8e98f1ad80d1607b1ec74b6a98c09d48ea48f19b96f2be06479a18000000000000000000000000000000000fb5743cecaa42cb9ba6d2f4d5329c672219b9e478c691879561c00d4ed801cd23b1329f1e115030cc9d3a2f2a6134801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c37917aa38aef28855ac55a34c73610cdb8c6e0e4c8e69e2fed1af5628931e22e58c7b8e356ecda1742ccc4d61868c30000000000000000000000000000000017643bae0b0cccc2c94bf0ae59802fe91b6a04374bfe3f0c7874ce435098d7a091fd6607e651711d5b88ea227c43a6551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000685570349adaa9fe48b0e12f192e28e76573c86bb8343244f644f8124d2b66be6f51105b2641d8d6634169802bbd630000000000000000000000000000000007373603070b47a89660674e1ec35b57472343c4a47a876fcb83e7042320648f8badc47a6ce6df84a56616218209d3941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000417b236fe09854fa8b6fbd304b450674f22c6cdcb21cf3fc6c1525e10a87ec296683dfb5be661eed1d7742217e24055000000000000000000000000000000000569fd7aa0ac0588d44c06045469cfc11eb4c8fd352c0d9f2bc613d4b2cefa642cff9e9ebdc7bcdb250ab8f00a7db2fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d59699041be95d8e3e5d3b57163f87eecf9dad15f3df46f2eb0e942452bc7bc19ae8a8e02db27f630617a662b01e7f3000000000000000000000000000000000108be5b5f52aec359bec1955b5f2c16181c0da201db6dcff2b86cb002965a2fb5b0b7cd687fc81073752adce855749b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029e0569ce7efd45f96cc3c0a5e53da1cd444c3a27396d31eed14a60232e2a74442f3b6ddba3abbc1947aed187ce9a210000000000000000000000000000000016ceccbf33d7051dd100b782e26642de6a995d30e2fcf659f488aafd665baff51ab2e3242963a6c622d270d205e6df141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004667a4fcf3ddc6b3fd2cf20984dad32840c5c5d412d78bfd9e56f860549d8782ef07fc45b40d28e4c034ea1b17a8e26000000000000000000000000000000000a125aa927092dffb9c4fca9d6f874654dab8d7838b7b7b10825f763eb6767fec8f74d4614ae5eeb43c8239560de9dc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004411261d3faee96dbaa59988eb64e7f66095bd1bcbd8264fdb291658fc8772daee67968dc98fe8492ad3fba6f72f4610000000000000000000000000000000014ec1fcb60acbcc80c9aef300e426d3a8698c30ba75e854451799434c38cb19bce1fb1adbbcf33d4e19b1cd930ccc2381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016dae937fcdb65e634bd24860def5982b112b750b91ab0a057dc13aa2d5cd3ae6cc45014db447bdeecd9708f9f91579f000000000000000000000000000000000f3833cb40cfc03e00ae502930af502944e51ea4ec3127dfbd9804565a897536d0d13a9a26b3abf3539d37d5e49bab741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a895d2f609a062c21554e0874fa41d8a21ee2c115441bfa50985df795a4ef40bb502600d9113fc00e653cf664678bb20000000000000000000000000000000002e8c9886cf24793aabb82a57893a985f2c0e590df6f30d7f0c0a0e124aa57c52a0833b153ad614335236f2c89e794971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb0d59bbaa9737bb4c90b1b5e331a09ef9d96e521c1f1ecc2f79ead7c5059f1f391a83a671f496199a3ba2589addc8c0000000000000000000000000000000006e541162a11f0aa7fd4f48549a83a3bd63c5eefefdc25d3bf04ce81f86d35b162558222ca0a80bdb165de21e06320011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000655ea6ab02467d1c65c4716780c9f22f40782b41ddbeb6da9239afdcce220e40512cdd914d31d7ad7332248ee783e2b000000000000000000000000000000000d9e931a296526a99d3ef08dfb1d4775a2e55c836bb0e86cd3359efcf67cf865aa531a8d49e143e9086fb0dae3087d2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a281a4b80cc821fd1a13fe5a2e6ce0b5370777451fcffe8431835f459b31d4074cebc933bc24e19d1350f959a557ba30000000000000000000000000000000019b9fb71bd4b7a2807a52576401dae1aaa1dfaaed062db9499deea249b2fbab0d26675a8e8391156125b50f6dfd861c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000031d083dabb84d61f57cf41f75d0b378160dd20ea659828ca5681cc82f66d36321b16d4db29c7603a5a81723c253f970000000000000000000000000000000003dcb50264ba8286b8cd0494bb0db3abd2703a9da4149249431271102709b377b958988fbb3928a1d666a6f963dc46851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000115e6601da2dcda7aee8acb6fef2150899275da9a44a84d3a5db548a42b897fc8e65690f7c38536345df9dd618068ae60000000000000000000000000000000002d4681118aae618a15a005cece766f00054105cde059d419fdc7b62cfcaf5c158962885913e12eae66917e4c06d3d641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017011b0d2246f43beaf8dd707d6881e4950aef1e08c38e08cbafcb2af7e8ecf4940744e5353c37ebf0068a4b8930d5dc000000000000000000000000000000000b34ecd6bdd1f4d2a5d1d8bf088abdc4be0892f51e22fcdbf1f3b8a969577ec6b14b6f7e4269d6ea014f2ffd8729728a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f8a4443e250c7fa5745cb3e719c48e304d0ca344c22d0226d2ea65e934de8898f4ac7ac5a643cccbde9246c8ed8e8b0000000000000000000000000000000001aea5be3c7878155a5e43aec8b86e62757d2a1b5211941eb2efe5346ecf7e9d61f3aeda9526276cbcfbd0251d5cb9941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130df446b9bf740740f503e9c3d8c6f3e97333e0527904cf70f230c020c7a6ea6e2c52ef334391177312f0099c801bbd0000000000000000000000000000000009d8f1e9f87e13cab8b5208de4833d870158018e88b86aa380850b0b6aa9c69bee37afbd7f25631137f6a068c9d75e6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012a98fde1b4ba46073935f7ada2666859038e7668e3023d8d5471cc6835c9d7fe56d10360d348e279a0a9089e08d9160000000000000000000000000000000005063c18a9bf161b6d7e4c11fb7f774b48c1737d8e2e7258f655a7f691995bd5c7ef9ac3bca0bc27586fc636a6753e581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004fbb522ce0dcad916b7fe27db8210bc75132a811ccc966fb1cb10f839291a4e064df6db0af560bebabb7f0dbfd6de6c000000000000000000000000000000000138004922c7c2240ce8a221eadc88a2dbc5b41af887da8eb34ac9caad07a5a4dc5528becf6ea955fa23a0a6fd4b85c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168f7c11dd99679efd54b362907320046e65d1e9b0f2653f6b4e98a2db621c601379baffae0c418ef6bf41df18c48cee0000000000000000000000000000000003d1e78881301a415182e6d1d29999ba1de23dde7954e6ce1b7ac7e68ca4ff324adea9886c41bcc6d0e5af0f1edfbd181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e84003be9055e3775ae2eeb9ec97602156327711008bc6dff034a075294016d2a6ce2a40b26e1668678c25df6b7022000000000000000000000000000000000225d84753141fd56e9be6e4efa1f9621cb95e6ea635fb3697e5503954db3699b24c8129b7ce8323badefad6c025983f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005580465f8f9ba4bc4060d856fe456a88ba432a7c4d5e05e999fa877292f4adb09715af85bc1fb2a7d1d543453ff8500000000000000000000000000000000015bdbcacc9143c4fbafa1255144cf0e07fb826117d4cb0b24b38f3b60f482fa5fef3b0d9ac94c39d6d22db765d89c40a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000779171e02bce548bec3d1094e41795803ac275791b5833bcc85548e1054260e74bceb273aa583f2b425fd07c9e67540000000000000000000000000000000006e7cfe6ced8b9cb867ab34219e8d6c12ed27a68adc69777b34fcfd00ab9699cd45fc7987aa8587f462f680d6d6ad6571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001904cd4d37d69f8345a72397bd0e4db961c60ec9c5cf44a49fc76c0ba468078ce61352cd3bff784620d3beb24353476600000000000000000000000000000000140521926bddbf07547b0162cc6c57de98fc9a15686a9de12f86c0a81715183e5ee9cc7ec2149665aa1f77fd9baa31381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000366bbc35b451f297b8bae0fae2ddb6f8130c89a297ddd4adb5a84cf83c48736db6ff814611a51cd9ea02ffd95b85eb000000000000000000000000000000000cb73fdc813ea478e07a1f88aca3e17687fcf83cbc926fe4928a3fda683223df1619e2688a495707b819a43cb6de1bb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000501b3428c2674ddf7e7342964af73326ff93528d137a29c976cbb95e150110a477bcc6a517399eaffe8b185517eab8f0000000000000000000000000000000001f2eea4573fc994596154a1c7083cb26b8c7b64bbdd2c121eb90f36b25caa30d766a2aaf987961aa378092f84d42e741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001363f22a2855c14249a1f3ef321fd39780905982d5c6b338b22074f2497b970a82241e2b8538170a3927d5d428440ecb0000000000000000000000000000000007f672f968b23ffd23b79929b0e16dd41d42fc97878e9467506517b31248b2094faee9f8605e6debe0bcc3ef9908b6101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170b24df30d9c6ed018b04f31e02fcb07bf7f89ce9ba5f1e2b0f6899dbe975bd60266f5e8240fc130d18519384b957ea00000000000000000000000000000000157913061578ad1cc083ac3d2decda6b2effbcff260a802be3276da9e9825f8ba23a190391d26e9b04c5bd1130cdbc201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000115e1e1f545c26058b93dd5c0ce82759aee69f928d06ebd5519e3830d08f3fadaff436127c69bd9d03ce949866eedce900000000000000000000000000000000098d4f3fbf6a6db281f6262ed2bd7e2f7af47ef2e77f2876de489bd9ce3b8b241330437a2684310c4ccb1cc2b28119971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000496fc523e07eda6a3d01caee4a9fd6ab93174222f9ac3cc62207d3fead137608435792d0c215d7ad0434c08b4577643000000000000000000000000000000000c3c349e1bdaaa6e36300610899762cea2905a37e5e72bef8bc5b80c411a549642c8fc5ebf0ba47042b69ba4e5fd60e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e9d56e526441f93993fcb36470c12c0b579b616bcd5c63e1385729277a6a27c4fd14c09f1e257e032562aba8bed4070000000000000000000000000000000003187bc57f92772ac2438c51bead0219b5ec2886fa0a780b0a699f345657f98b77fd6cf784c131cb87c04c26b2b236741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cac711712f8d16422c70dfc3c2b88984bd47be413e8002466bba5460c8fbdb7694e4980d500c05ba5f110768b632370000000000000000000000000000000001416292bfe461e0f910e821792cd92820c31628010335b94b91528cf3eb18fbe87534ff489cb4528fcb2285c0fde77d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010020bf3d218d9515448fb3eea708191624aa0ff10ade36e6eed770b71fcafc56f9d386ca3c6656bd7edce08087122a500000000000000000000000000000000140867bf7105643cd23a030d547ce83850e1e0304c2274aa467b172fe432bee2ac082222983793769c0d3804b63d79441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a6aec9d7cd3f027dededc638c4c6b3b2a7958fea48bed0fd2bc675313e4d2ba12d9187d113bca0850b17e20e2e6b1200000000000000000000000000000000021656c781b21b7383c8f90b1065745cc750f056a4a20610e3efe452a28235d074e247fff074fdf4ad9718497c10e3701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000993cee3735705aaabb0eb7b0c05ced270af2559911929e4601729c283952b5399226d6caf8018414db54a61cd814dcc0000000000000000000000000000000004f8ba2c096c1fcf792f826a7900dd48fd1b72f4cf6f260941b1f4d4c1a2727b7ae30cd274309da12f092ace6b0f565d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000095ef9449afdf574b92290a955bd0e7077104a5d94b8c17427a161a47e3b970af7fed5ab3e6fedd961c6d11ff8ff671d000000000000000000000000000000000e2358fee0e7a559848d30d1bb3f8eaab926d78d11ebf05854f653f6ccf8b9ed8a34114b881207ebbace86577b5711541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000abf43984cbcbd25ebbf9b5c5686be803d2baeadbd4ac4e769eac118352d21c331a86fda6fd4128442009989206706620000000000000000000000000000000015f80a0d1dda56177a48834833e214824b99c0a6f408b4e8e99355b499fc4199387b50dbd61447ce08633a9814c5421f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee61140d93e426376c13cd8a8fca79f3ee99bd601881e3b8d8a825601f1b8f1818e011365f8175c26b66071628539bd00000000000000000000000000000000193dd261d1482c0579157b4baae94c9c7b87eda36fe5e8c906feb7f3cd54bd0851822995725081557a35557cfbc10a361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042435457b5d2d7d5e3dcc6367842a6a88ac7c470a9461c47780c7a5ce4417e0038853ebcc9fe7fcd2722df539a3537e0000000000000000000000000000000017f685f25839da010ca2e599586636dcf1fe2d5666b494c228994dcae8e1f3b6c74bf0c8110f4644cab17e6590c0cee91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a1316bf89d5c10794b2f1770621bad1a6e94933fda91f9fffb7fd58cd79414e5f2c3ff9c4ab5601aff27bb9f008d1d0000000000000000000000000000000014771ff9753521e4dab0d6f0498ada6621b64eb690c469bf5d86260fe105f68b063661f12edb0fd0f66fd4f91c4ae1f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f6cdd467c5524e1c4ed88e8ca75bc3e00a0c32edb01170f3606e6cb38800a7b751e0824a5cd6c92c8a6286f1d0edee00000000000000000000000000000000024c22cd170c400e847ac665575230d66c47f2361a45ee9acc08c7ff80d99266ff2408bc1e341f20eea482b92e149dc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b126a68a45af7dcca9fadd40031ab4a8b92707518bd389781366d589dc4d9491d4293ae3b2cfcf5d24e59c1f2b9d51000000000000000000000000000000000eeef1f0c26c47d8ca8d52a3474579bc6e0bb3a845c81e9161281ef3dbd80384cc171250e134144894c30ee49b10c5e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a576c1da3e5fe21d419a0530f3d4444db1e2c067fad0a692fcce400e383f3cb0fffdf1993c06f0ec337d93e63cbf13c0000000000000000000000000000000002824120ca2865d634e89f2b5c32a131ff9f9efc5e226dccab602dd37d7e568b3ace6b8c8b9f55e98918567483ac674b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043d7e54205465d0cce77a05441f216df5484fcffa68a691106136554332c8a9699ef4dbc90917a625f9549e5ea08807000000000000000000000000000000001769ca9a6efc8f69e947c853416639055e24a871f1c1c67377db631c4bd23772785ed4cd667278dd153973b81f0efe251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186f4ef83f425e13fa82d5e4756b176fc2f2ca2ce05ba273924d4bf282a4b2e9fd7f3918135a14e9e4ad99f2b66f45f60000000000000000000000000000000000ee32349fa4ed2759ed7260d0f75798263527cd741bc3e16a7ec8b83bef0fffef25f80d31ad47603cd5ad44ca1ec1721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe087ba8066bd7f0f4e364875502e149c8512b684cad0b60190816e1f5aab2a7af75e0bb11663070620f4dab0b892bb000000000000000000000000000000000c8cce3300bcc43ed7377f9cb97d51d2188b76a0c4eab20c884da991014d030b21391434c27824553c801753631376be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006441569fd4eb04c729df0c562c935b3d1e7ea29b11c39dcd92e32cd4a793dc7856ed9dcf293490b6c66f4d5ff7cccb4000000000000000000000000000000001887927525329ac248430e2f6ba5abeb1f5c285f1564d98378b6666b5501598eebceaae66a126f57562bafdc91bf59391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa13c71ee07cf927940acc09be245cf9360bc3fd1cf22d049c0596faff3d879c0089b9036226ef1351ed5be266170ba00000000000000000000000000000000064a699e9ca11af818e9fe6f4eee0985fceeadde53ceac455c7fedcdefec908971641d91cf0c845b9f14d0720cb0f4a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109f80df81131f7542ec6e7930ae323bde0bf23c28e8e1b9cd1e0550d01964616bec75f90fc620ff4e47fb5a01095105000000000000000000000000000000000ff16c51cefb8b8930d135831bac5081fa5852993ad525b81a62db21b5535f6b6989c7aa6e7ca7a17f8b9aaababe5ee01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9ddc36475c23781995342169d2c0b190d38cb1bf4e9db7d89d00f0ada52b194c98ee9a9c520acc5b5cd3f2f5c1155200000000000000000000000000000000027e3f123c61e162aba9e639b0e6af44a4a265885d9fa5527f9d0966f6b62bd941e75057164687aec3b8d51ef52fcb6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000704dc6cd2ae310b3a8489cc0e00b3a91f928e6198e3639289134dec0874c342e8a68a1d490068cb955442d690de431c00000000000000000000000000000000075a2cf0f900d2d6dd86ef7976d6599c1ce095432454a3de1773f02dc64bbb58b6a744b5a212e5b188fbc688557367351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121aca798f99bb029fabd886070db0b61e81ff94764ddcf8159ba87ef8a4f36f6ceacf3a6185c53aa1f9d93a4bb2b91700000000000000000000000000000000126cfeacd1e0834c0aa4ff136dd617de714cd7afd7b22bcee6549a97ba539de4148271d26882f422f308b698e97b7d5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d592947aa79b870f2e2cc63ca07a90ee00ee3d515fa312f0c9a4131995c3e2f6d18525e0fac5b485381912d1fff87000000000000000000000000000000000166460bb93817ac666615bd068b49c30aeace0dbb0048bb909ad5dd16fe601d9508b12cc06c39f415357b676c31c7b441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026b4afa3430a07727537e376da8eb5fd6fb3c607841a602da1453c7dcfca7cb0b32876cb649eb7f4e97f948fae2e20100000000000000000000000000000000186eedb37b465aa682537b65fa0d25433eee73c7acda818cf46f2b8d68c969f56bd3c6a95be9fda9f93bbd53261a41bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004c754f93fff201605620decc02ccc509ea6b6b06a8b473a1c0bb1fbc5b2c5bb9d40a057ffe7bb7c36e667a51c9237c0000000000000000000000000000000011f6d16e29d6214a3577b0d4ebff3c737945fba79eda7ad5dd6d3b3a92cd7c1bc3002eca642c09d60d99c5884dd7e7ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063dd8ecc3e2b6e07296a2a6a7d844693d6a8fecdce3070a43a43c0fdf132e11d0d1b3d74bf48e62f58c1bbbda52bbca0000000000000000000000000000000019862384b8ee86707d454c2fe3f985b99f88d5ccf19dda994a8a4c3fcaed407bba8e2979344f046d02f1fea36ce26d511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d13b8545eafa1c274968cccbfc3a7ab274d1e798b8bcfa245863e17891694515396d2938309edb101ee4aa42168bab0000000000000000000000000000000008ea8ecd6b750e1427451afaf4259a10e7c0bd9581c359d8b515585c73e04dc302c0c9e977e395f47c26cb086844b66a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010821a1369efb387af7a5532ad1203bea209ba365cf554ed61120437920b1a3e5f77f1182d54ae82fb38c5aa95b5599f0000000000000000000000000000000009fe11718f6f05410e67d44c0549841cc078a0e5623f18f193470d64ddf0143eb27feec8548b1949f46874fe90720be91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018dbd92164c7ce18fa5c16108b514949bb522bd8fc12bee4794736e3c576794fbb3b75be219a63c02657ed9f280574700000000000000000000000000000000011c7539b583d223932b48b45a5816bc450a736dc700cfd510e4db303d6175cb048a87058870958d0e6ce8f09e20368631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c3db43e31da03a6d0da7529d766bf2839964e7971347a40536f5abaaf91525996628f66777bb7465872645ea0957af000000000000000000000000000000000875114158b4eaebdb7581a90d201b34463df9a87464889244f005fac6eb816a55f6bb36a50664bba790eccba050352d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000373a124a53ba5e7ba5296414be02ae89d7425ff0ef934a2a6d4741c21ee4437c43a23f9cfed0be7bb314b056d95c7c000000000000000000000000000000000357eadea1eb51402c1824f61d239a089788cf8e1e1a5bfe0095d49f7f266c23ec98a9d7584cabf375d1423bf34bfc421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000579da742878757df9c6c983596e491b0823c339e61fad7b5c6cbd735ddd2188e46b16b3ce0c58e079ae8e08eb205c72000000000000000000000000000000000d5b053a1637aa80003dfc2ec1c99b17f2f1e10b1589fcfdc28cdb382cd300215314095d6649bb250272be6341f8fa3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010519ef34482a1fcdf0bacee9107dbbf778614c266c1414b713cf1e955c14d4c317434eecaf683d33caa399587993d0a0000000000000000000000000000000009d72280e8698267b1483f5f52dff05c6e91d02cf91310c43ec52b9ad202c1e985ac9380bf387d9a587225630ef226691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110c0043405e6d957a98fbdc65e8c10e6d82f30b5642042a5b2b70b84114864eaac3fa7371727a4dc278d49db5390f5a000000000000000000000000000000000406b258f81ac32933d3f55cc6e313871794ff14e7e1d8bd183fc1589926e922de4496ff2fdc1e57d4945cbe53c190bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002bb2697d79b24540a51f6d1a6a04715cc67a7a052752e600cffd782cd3bef38e0a958080e5850c48dc1a3499ff623b00000000000000000000000000000000099f89d6618fc7dbdce69f884965fdd5e0bc01f50d3ad6bde2a0ac61729850481e8281fbd6799e02b2730c75eb35f2761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c96eee9a5c445a57f6a39a308ed32aec39d444a50f2340750b741f01d68adf6ce933993cb4bccaa4b4ca54262f28a800000000000000000000000000000000117abd1de879221b5b60eded5df77e50c27204a5e5b78f4378621e39c77d76ff45d2128bc1357a1c7e44b16efee0415e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccd05154b487ac2b73753b6dff8f6d46f2457e168ed23a8520effc8aff9ed198348f8de359a596d9e1ecdf3b5f8aa95000000000000000000000000000000000e00ffd26fd4fc73b78ed95a60dbbebe9f04b6313a62955f612e3947769e3a12f70c38c0af64bbc9ebf77f10d85033351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011de5d407eb9f38341c61e0eac0ffa54d063f08fd76590ed69f06af816ec29e761a706676a66124a7758b44650a1142e0000000000000000000000000000000004b7f49b4cbd30f1cea3b62b25b0fbe1f1333a9251a7f8f024e50a2e55499351bb94e14a358099d209262dc264bec6121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019ddfe05940e7629f77f1cbd5fea4514ad4aa25ffab529954ee7c9d7cddf6bcfcaa7ad57dd61a271dc5771599d48e58000000000000000000000000000000000ce428ed85e6b660b65d9803d4d91514b1d1e9b56c18b171ec41a540ef512c306e39a1383b0ef8ff62f266dd33d9b1991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000528dad1cbeadfb1b1012130ee3549e189b0df22b96b9d3abc7c3b95d84e13449528b05ce9a310132958fa907d5eeb56000000000000000000000000000000000801686e9022c9e5b8843f69451e3dc1e1117262226b6501af10f38a66fb0307a70e12be4eb1563898f99039595be8aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039f42706f314602a432c40a7ca51feb150bc6b38d514594d6846bef8fc61f84fc23362f23cdd2a9ef61d0a671d917050000000000000000000000000000000015d914776e0b7c827fc9ce86365f92c6d4993d8d6843c3cea555bc4eb82c34ea33d65f3cd3e2b15ba156093d4b5a705f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ee9f7ad9673c22c5a5d908064cfe418e4b28b68a7a50cf3f0534d4e9f8d60d1a8f6c6cbf8a74e99ca97bfd602acb7a00000000000000000000000000000000027a9e2d1e5adbe923fbb8c35c039afcf6d91d31a249a36c7425d1e7d626adacdd683c66bdf80f97b8f231a3c2b901a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001673a72543cfab54492560aae86ee55e7149985bc466a557be38386ecb04a52f319d1d96a8379f08bf9020d96ec8a988000000000000000000000000000000000aa32345281cac1fdfeaa709daafa764838404902285053fc4606b62569c8d1c59baad7578ebe8596da94c8c52e78cfc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7b2c7c4817d5e605e6bbb93b16db551c865e31795536daad279a7ece0415589636813c2927d927cae37b535660799e0000000000000000000000000000000011f892351555b1237b0ee16391723ba3e31dcf5c0badbbc2714af27397bc8ced3f24cfecd922bd287ede8f6fe5aa311e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f965f3ed7a123a4a2dcb8cda707d913384bef6cd1006c0c3e1649e9a7f2c0f7191ca9c61e105ec2864c9ca1db92ad50000000000000000000000000000000014af0007ee0136c93ac2fe10fb9f5887d21a08ecad1313d0105b574aaf41a99917d27113b09db792dee5c19281bae0471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013da69ab41103c2e1594d183481c619494de16c50d92d86a2f1f5b52a52bc85383d5d2892cabe1fc14ad1be5e44e08cd00000000000000000000000000000000101707b1dea772c90f1331b9281dedbfac38e229a7e3c8a49d636236d05cc085d2b25abeefc29c045fd739ac6580d21c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001208c293a83e64bfe136afa87f67728a364cbf18a2120f08ba4f14eb90b561ca3ef59cfd91a6711bebc43aef2fd982fe0000000000000000000000000000000008d079099e412f4c36abc0f04bb69b288d8202c2150ed4501edb12fe06291c12df14dd6a740887855db7e49770da58ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013db5abac41c67e843b97e7e37cb0739b61ae9b3eef335d3e9276a09c6c371ff7966cfd8a118d357c5b281c289879c8100000000000000000000000000000000092725da8b4c7c04097cf1f1cb9c79f50e946ba8b621dda62b33135c29d6dbd98677b27d0dc493311739e40a60be2ee71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187944038146b034f10dd304c1766de8b0ace0751c92d5dcfdfe0433e209b2752b36df0d30c126abe1ccc03c83a12df0000000000000000000000000000000000de01a494677f435ae434ca91ae5c79a187b160cfd6896ebdc584b294b01dc08e2ea530c36d4aa22e41ee1dd1e9a67aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2ee1169f81a81b890f9c4b6d695ad02f8ecc7f2b6c40f6fd0e36b7999dd92bf7f5eb82dd4aa0468f5c563d81477b5500000000000000000000000000000000110878fb4258f9e20189dd4f28356bf37ab9aeb15c534b99d312770a91d0c60f608009eb74f46c50904c6da9a5c3e3041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000483df709fa7a1c34e92d006005cc77c6ecc41cc1b66c47ed012a4a277eb383f5d8187071bfa2e3780980810f0b7648300000000000000000000000000000000176571ea0a2c3f06b6606358974db9b1c08a901fece4505c42020ac86d0d2f7b1817cf5a554520e198ad13b2a28741db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137f0a0e188337f1ef76969a5ca87805ba7e9c3857f74a4ab08c90ab9c23455bd968908e19735e63382303bfb2d6997e0000000000000000000000000000000001c9acdc427b5691fb1c57ef6e15a0e4ee91a54e6192714d5648e80c405bb736d59b41aea377334ef26d5c4a5508600d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001852ca5cc7d3314a81ef7b46bd47375304c1386512d2d8490e826fe4079fd875d51da2405ca75a8a68aa7c4e90d1d9a90000000000000000000000000000000001e7e572f7fa35ff495b1dc612bccaaaf77f4d86698b5d3b6e977aa811e2138b7a343e858bf2d437e0f102c645f6c07d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019dab5d38f5b4e87d755e66f64752409a783481ce42dbbba85eb7f0df88bedd8e746eabbeeb13096d5f742d4c9df081a000000000000000000000000000000000f88200542ef65e322adcdf33ddb2df1952de97aa0123ea076bd67e8bbba87d16808db6900c6f6af68be20ce601f88ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a443fc39ddf1e9ee0f5d148b2f46a4243611c0c44acba37f71a2f20b55be8629774154a046242c97acd8c759dcb12370000000000000000000000000000000010505cad2a0766080b001be5be4145f14dc2a86e425ecc2617e64ea7312d8538edd914c56af128bf52899cc099495b931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f8e3ecce7e68d8eafcfae82be606ff2dec4c27ab0c8b1e7afa6f89c3c8fbb429017d5ad8bba808cbe27eaaf04d1d37000000000000000000000000000000001992263c3dcf27a9adec71fec8ea8c5737076eed05427d527d06702ac822ae86d117ef8e3ebd7947a2770ea7bb57c6da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0056fb5e9e4b611e6a8c126ecf8c60fb424d3722645d6bd1b526e7073f41b2d7e05be35ea88a97044e1abb4d3d8e790000000000000000000000000000000004318758af7a9f49b634ee651ecc69ca79781103d38afd8eb75e882c7b4969c8bb1b9f3111a030d1e14e174681f990fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e70a6475a06d542494b703691d1b91fc6b593e9669b5d5ae4868ef1181df0ba92f81ba548c72b48370467975fcbb82000000000000000000000000000000000ccf0c053198f0af003a342770391a6cb298d57c418ba6b18bec38e9d00a91f1e985def08729085f2d2ae10fd6b682341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000723fada9e052ee9e8d9095bb98771a06b2e579c5fc20aea7df41236a53717f4c5b9d68a4278d70cf8ffced409ef737e000000000000000000000000000000000beefa1c536ee32714c391b6f7d4573e7cd239dc6e749c5474ba53faf1341cddece6e3ffbebd4f74198d92dda216124a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001852ddb23f3b7e8f562f80ccaa6bb9b3d5603b029d4e90dea9936421d5247b254360e72768f510c66b5fe836e4494bee0000000000000000000000000000000010c9002c21cdc363f8fd78907b1df78bfb42c8b0b98fa95f9561ba1ec512bf1fc94f4d096a2b6b48a3ae9fe981ee5b291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f4d7ac401da77522695b882b49358c64636a844026158995d9c8df9cf1b10dfdb21473d11dd866e0639af0ecde4a67000000000000000000000000000000001875999c398f749ce8109dd532161069623bc22faf3873dd44a87639e92ab6c932332b17dbe3dc7f470c8f9173b2ad0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017bb9a5f7ef6a77d451855850debba0b4fbfeb2997b39caf72906a7a488e11fb8ccc726438954a58f04d3049719ca4fc0000000000000000000000000000000005d1dda4ba546015d10db80d7c1e10466ab8ccfef4f9c4fd978391fb1250c3f0342a61249561011a4d74c5a5e10f0fc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122cdfad891523382368dd1f9e28e1e6e857f70334c3cc05bff85cc21bb43dd3b471378eb00464567e143eb55d12ec5f000000000000000000000000000000000343db67e4f54c4173ecdf95d4ab129e9695e2b32e6856e9ac3d2c544a4f64e5dd99f73da4a235ba5e7e944db63151621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009df2771e9ea0b07867e494c0cd34eb168693fb086047310827bc0a80107369ad5d508ea90dbaa50f788b3bf87dff963000000000000000000000000000000000ef9e3771dad1efcc30c58c179a554a947a0f91d8713eb31fd94b81208feabcb0642ece0d467534e69892e568d12d6cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6a1502dd2b15a100e690505ded8391e1679eb62f4bfc34d8653ee5d8b6db8013a2d27b845e29b09bc3e2320a4ad7f5000000000000000000000000000000000ca0c32ff5310120daae39651222d04c9b726cdc934b6caf8da6880454190657c09a25b4262b5045d69a8abf8e7f758c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000945e13f2e734596865db4f6ecaf56accfe5281eeedd7bcc70328fd46b1fad6b3c10eec768509ff3cdd1d29cf7805d650000000000000000000000000000000001dbb0cd0b1d41a7064d06b9e1ccbc834d707e3ea5536907e5be756f9f44b0c2d5508f7b989400e872dcd1c5b48b5cdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f53e6e87a46a3fe07a8ea41f12f6d7a693dc07909a3fc9d62e8d9441bbd73ee1fb6881be0de840e890859ee0742d300000000000000000000000000000000005c8717e28112e49e0846e47826179ad15c40294f2e72444a6c6c3e278880c2793eddca8a9f817449679fa5321408ad71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110a44d3adab3bc260782f563068c3651527004a968dd69d63a8fe030a37399eafc3660f43ddf4bddc300e73b672dd6f000000000000000000000000000000001684f7eced92bdd4b616959d5262b30b7edd93dd6d2b25924816fb0f4647e327a25a7a90d7287348dcba86bfe420fe631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a98e81a6b71e43eb430b7d85f98ff88eca55cb405fb125c5fa04d4f635674793a203b709de52b7d19612a252bfaae6200000000000000000000000000000000135ae46954abad4675e2329d46d5f54c13c4c878579be016fc8ec1de5e4b354de32f413b10d7c755b4887d950ba84aa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1263feb2ca2f50dffab8de58b1dba92f053b61ba6294da3ce6b69aa97ab326bd63ad9d29c4a1849bc64178b95a7951000000000000000000000000000000000235b6b3ff7f5255513aa2088c4391620de20d80e6ab866c9d8cd5d5af4d9e2bf40b9b4371bced47c6cb741f3c48ffad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a558a8d99a7a9d73e134d1d8b15a27a1f27b42261dec55992fc6f82cf6ca1b3f4cf814a52a7c150f7ab56c40e186e20000000000000000000000000000000004aa1ca0a0f27e9f42c42b99a01a4d60973996d7a543ae15fb7f176f66899b2a82903855a2cab2b6fedd0af929d909341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009563e68d919a8b32b5c019ff8709fa59e8311590412224810d67d1cf56135c3cedfac6c50f5acc23c4d2753150921de000000000000000000000000000000001982a3505db9288f3af594593fea076fb2b853bf794e3b843a9274f1e812cee80bbf0653b3d7fd934f9414506ddef8181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec7f4ec4758593ba4690e4e830048aca8cb6d251d89dd08910f299a1fcc38c044476ddb7b388dcddba28080a544841b000000000000000000000000000000000ed13d7871e6b524e04d3316723cb069d980de2f43f0bbcc301bc65cb4d9d8c7e5119df98506ba848c75a1f08b19db301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b7a728468f7ca884cb4c69cec3a6af45aa0f986ff79155135dc0b21592d6206eff4afc6eae736b62d617d5fdea63d300000000000000000000000000000000002c3c20dc23476ba3e2626cedbf7c303981c43ff67c5664bc8452964af61c230f0e4278530a738fc421793c0e3203601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001338d579db7a784f10e0534beb16d380f8090719338f92e6d210bae913fa1aa140539ec0e76590233d8e1f5ba2effaab000000000000000000000000000000000b4f57efff088214162de1f12cf564f5f4b256a4aceecabc5f0b654c82ed13f2bafa4e01ed35773a038e58fc87ebf6691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b90b2c59c29ee1683d84e2f55683495cb8fa2da353db75948e1d7c3f2784562cc1792902d6f30b2a8065b15153b57c5000000000000000000000000000000000844901e21ddfd94b2c074592c82b5c76ce318e1145c776dad79c71d78170088cf29d45393d16eeb54f016b11c070d431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001390764d5de94efd678c6b531fc63e5255e68394f029966978c3d2692952d4edcd076c28596977c725e4312f5412ccf500000000000000000000000000000000135a5c0c969e9eac78e57399aa4f40a0d1afad3b05ce25746acec614a7c62fff6e4852a3cb18b4a671bb467837dd2c941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c450880deed35621558f9d949e1dd98923e1f7dc9dc6247bfd523e617cced6d5131c19c1c99668992308ec3118e2040000000000000000000000000000000008a1fc4d4625876df290978b017fffb9abb5379aeb91cd284fe880d65116199f9c6356c85c4d821b483871e84fcc307d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c094fc12f6aa9f4611d4e2ef273b42b3082c123570645da9579d32df57d61ae475e5bd0b9f1e1040d1fea0c41d8d0d000000000000000000000000000000000fd153094e0ddb80ca2a58d11743c6ac77b9eb9e29d7741fcba303b039be6529b100c29b9f5213ca08fb316bacad6ad31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015621e00a94afbe8117a04d021a5b8c5d2d1e3381a4979ed62085980151ef63bd3a8934072c053f0168dd9b921ec85d100000000000000000000000000000000149f09ed2f79be47f87cc435460049e908cc28095da3971156265be6ac0b458e90603f5fb412b688bb84a719859348f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8a886b0ea9e5f7255f6a57eb05fdcc1b089318de86089a571527d5ea47154c18b22a4b144efecddaa747fed999456200000000000000000000000000000000109214676a57b867090bc3b978357d264e16cfd58317c4e7597db3e88edbe7c90102585714eb03c004a4978645c12ba71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4a3f0188778d2ef54365ec782389ed97016c1c7b2c7629151bea40f31f3ca0d4f1eeabda2c7c54fa1ef969cb267b2f000000000000000000000000000000000033caabb2a512770a5bd36a67e1f07126e16c09740fd5cb5281c70ac8520eaa30244b0a468d4f68f2d8ad80d5e571b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3dd698a801ebcf32ced199038b72c912e0d35263a4ee6237a2bbc82159ef02f17e802fb94126e475e09a5bce89c6bf000000000000000000000000000000001872764c8ac505c36651da15bc86a62445038478ad6c4eae2d552db6702c03a7ac185ff17f9bfe6fcc64dd6190d667581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006daef9a9b2037671914ba4362f3a573e544ae4603a05667d97d6302fa32d9b3d6709548f7cdf315575d4f7d58bcc05000000000000000000000000000000000073bc768871551650036e92d39298920f0c72b6de24ba02cb49bb5bb8b6cb2cd9e78f1da92efaeb6393a14bdc2ff3a211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001194f0c810b1071040b6dceb7cbd4e76de4f7f57537476f6eb49f2e83bb248d6768452af90929aa9e1e0bfc7f7a3f1d000000000000000000000000000000000decd2838d4f53f9997da4cb29f3745065f21aa75cad6a8bc56e64d6dc0cedb20ad3594fdb0eab9e3acbf0ef1293fc671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189ca78f8018a505f3ae1baa4c89d6a64a9f874bd503eee23864061070e75cac4310b42e280a3cb693e1d113e39ecabd0000000000000000000000000000000011bac44598642c14f41f3f0bd7c9eb43ffe5e1dfa35fe39ac4e7e444eddd7a6e930b8952970b05753a3e7ff9d9a5c7121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d17c56bad4abb4e69e92c7624c540988ade19e97e3ad7368ef9b5fd659047064ef7a12cf1748d77fd1fe4d085f0a130000000000000000000000000000000014952313acd884c9a77b08fd1515a9b8c9996667e43bd1fa52e12c256a7daa84814fd27e4aefa0f2272ef9b4062c0eeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105f70193d48e445101f41eea20bf89bc722c7df0309b2032bc0b6344dfc62039feeba9018a50985a325507b4ca8ed2d000000000000000000000000000000000018b34cd0d7c1669ea54df5d809749d46bc66a29a961ccc5aab50ee3d2569268c135522944f8b7a8423f3426f0d32821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b32564e6da33c47f5f4ee4eee394ccb7595cd89da56bb18d489a105bb8ef1b8095a6f89b390b0b62eeb9348b879730a000000000000000000000000000000000c0913987a59a213407335004e0ee374c2741f505f1c117b3efcdf57ab6fa79e47039a9f06895fe5e7c9b0c4eeb2c6ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131925162982b2ab0359badb008ce0bf1f653e800bffdd2a78c76581857302d0b91987870afa779b3165aaa6db1ff2b20000000000000000000000000000000010271b35bb046f6a38c78438eb3817c51b00b6a228772849cb50b5abe63d14e005ecd8bf59293aa9dab88d84e14cca391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000565aef1ee55db5e742e6d37eb9d469e1e49c416ca0880ef957119883b4a668e0b7d7e4baa26dcfa736ff6c65003017300000000000000000000000000000000042f981dd588c8d0cef2db46a790ef26582a39dc64aca18d2e7cf8b6f14111f216d4de0528208b0b70698fe424a75cce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103e4810bd4a9b08d38e81e05c4de55c6aadf5c7318b4c8a7274d757e7f4371e7d52864c582fdf0ffb069bbcb5fe387300000000000000000000000000000000189f59b6ce93677f2a622a6e5d5a8440016c0ec117efdb2f89d46fdeccd37a12d452afe4808ce585e6065af1f4413eb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca39fc8d3eca63e7c7fb0f6431de476905961551e9ac2c44bb2f60b5db0669ab4ed9f44c71b350fb86e4a0b464fdfd50000000000000000000000000000000002bd726cf22db43e2d99e3ebfa2cadde6f2e1c00e2882a96c86fa65fcab94cfb5292f883a42591e1b46a7b07c1b373ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186d75cf1b7b161a8fc20853335337c6ee2766a844b8bd9ec6b5bb969c2c632d52e6c41170cbac9710258c40576ec7d2000000000000000000000000000000000272855808e61348c24e55ab8bbb94c77d8751598c026c5406b9c5497031b6d3e4f79a79896e8257475734a063221faa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc5d1f677da41f78da055b7794c9b4ed43a83068d5629a32404fc2f4f6d1115e32528a4b71410ad22295569975875890000000000000000000000000000000000db0eed2992a6d0b7fd9e82b34869eec0161be61f4634b26c3bc82ce16a89e5cf4cb63c47d1c1385f837eb9ae2d7bae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002be0f7f78e79b5f5fbbab1e813d2f69265862ac6d32f569604f33a41b39ccdb95cff56eab3e0376b0f862e0b0578ec0000000000000000000000000000000000fab97373008c422e2acfb3be0c9ab6431efacbc26d84bef2c80489df2d48403f3d358d2d6915bf4c8f9dae634d5954e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009824973abd3c728d02b2045a0bd1695eac2dd1013f329e0a6a88b49fd74bd13cfe849edb8b55536bf329eebff89622400000000000000000000000000000000169b57eab9a49dce2f678645a1510ce80d5da8173684358381590f9e03c7be35389ec6143a575005eea9b723bfeb11b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014bbd270f511a6f953c78426ad6139f97e9fae967af786b3de31d511b557faff0f005a73f1a29dd1d42dac95418b83de00000000000000000000000000000000173414012561ae8c04539915098a7c4adb06f6326f4b1e3d3c7c710148c1088dbad8ae756f960f117c6e547cac562c821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d6734c76ecc9dbade31e8452a38ce2b45b0aae3dfce208a7707442b906d85a5ef1832f63448687aadea5b6cacc9f440000000000000000000000000000000012edbe4f2bdb326d5e9bb0e41693ac8113cdeef1c605ad0206e2b3f9bb8439d54ac9d54d3e38ca88f4a69c4c11ccf2e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e72bfb5f5816f10c6f10d340e61a369485709e044aae6e80fc8256e2bd5edc065ba1c749a1fc85f7d94602b510944f000000000000000000000000000000001287db37dc67a39dd177d317469505f7aa9fcfddcb7e6d9542f5e5746127a18fbaf16a56f3570e6b24bc82264fdcbc981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3de0c9e848eaa2bccca1ee5c393cef1fa4aa15a2d6b8b936e851c13589e1804b124308d8d45caf773e1cdd584b3ae800000000000000000000000000000000180ad47eed54b964f366d34d01452a39cbcc3c985d8bf417bfd97d7324057620b89aee2481d8cc95a7cf540d44beb6851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148cc071144c74f858c3863813603ec102f28d4df5c872c6523296e275784902e7dad3267d9700f5aa80d85ff62f7b1f0000000000000000000000000000000017d1ab953f6523b48728868a6432884b2b2722bd430145da548946d9a60edab788d53539298632b5f125f74f58595ca51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002849cfafff6fb2a7768d9a256fbb8cd809e24ee3fa7d204b7f09c326b5cb03863c91352002458ebc19ef49bbb969cc60000000000000000000000000000000018d1a88bac26a824bdd90068a58e0508c25769e0e0c6cd8cb4c30718d724c35c7d44f229cb3afa46fb07eb708fa48d071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6240d14f6ce6d65e19b72aaffb0244f21f5651d21a872c6131e41bd0dc021709be25525d2cea6a0ed7f01c9dff88b00000000000000000000000000000000010e749fdff1f63296bdb033f59d7106164c5e19c7b33a63419402e9d98011ee0fbd4ce404e370e3a55760adfa8b225c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001567404a725454d997f77357ea181fc8cc8eb45abeae1e4e1be34d3ea25ad92eeba66fa038284d03019514edad2b48970000000000000000000000000000000006463c1c076ff62aa5a2ac496e9db979730cc8e4392285361503c2c764dc4fa1273e9bd33e44d6bef8684a6e7baf6cdc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af0135dafe61dbd8a1780bcec8e4221db83e43d1d81a90e25785cbddfb991ce267400a088b132be51600e53aa88a1f20000000000000000000000000000000008b7ade5b3f8380bb086e55ffb6ec32d82870ec3cf136a8264956a0427e3b515018f853dcc720f819c6d6478f84aa1ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000172f49165a571b730a79f21b9b3afff0962033d297451bfe11ffe3085c1ba9c4e978bef45a38c82188407a025f5b79f7000000000000000000000000000000001634d3a795eae4cb05296553d5abbc35d09bcc44743c6129ee8d43f6ed7eda27bc7d0255832a9c4fc7da764a11379d311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6ac7e35ab8d48de22a45bc3f31dc012d564c935e59887807ab8ce149ad152026b6d001054c01cf2ee969b6d2956747000000000000000000000000000000000edf13915914ee21bf0b270c4e1f645a43ec5baf7d70efcdf33de1ccda1d52c5f9adbb69ef5ed07127b606f6e89ab02f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001655bf5f49c26fab24201681400682a10b0ca784f1da596377e95d784f784d3d6346d9ece18520547e6ef0852ef0c9140000000000000000000000000000000016f95cd32bd672b7d4bfcaaca4b28091cf1a1393ea40797d7ef5d7d99721943eca021fd67a26b848a691c7c0c863148d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a743ff0117fa8d2b879818f8d2486943c9617b080eafd658d37c63bcf7ad42e00c6e5e827114a00f6a89407b2d70a1a0000000000000000000000000000000016952b04a90edf126e6b5188f5b0d2e21b884e0233da035cb9783e7591989e61f50c628d0cc81cdd288f446e9cefa2c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e4e33c1075524a560c736b0b3d900d472b1b86af802cfd27c43384ebad81d867dc72c2dcb9c24e4b32446f0ab388130000000000000000000000000000000015c406c06a0911c2960ca837a9acfd551c0776db5e2375cf13899a20096222e1fd46fc70834aa2155e248a0b2ae4efbc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbf3163b9753b16cb381221e350b145f212274c68250ea61fe978ddd36230d7e5225ac6e334091483a3bf2e25c02e15000000000000000000000000000000000ab812b73f4d2ab50540ed81ca212ebef636fdc14cf593a2e2f917a53c6c8a92be97e6bababe20cbf7d6b2e4cb5da7341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001a2afde2bbf3d60c8d182d63a214508820ac51698ba797de4152be872f0161d7b789247ea73788b47218fcfa3f2b5f00000000000000000000000000000000138e78986d9f9834dbd6948bb42c5862339b260a6ecf24bf660d2da0328c3312eb364a4bf3681834c5b25a74c83ac2fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f87a869a18005791d76bcdf1ce64077b68da217554811b97bc776ab40c89cbc6cf8941e9a8d3675d9f9afbfd3208980000000000000000000000000000000006801f794aa066fcc118d8415ed53308d4516f6376ec5e6a4ea35d39dc127b34b1b56f798cdd8ca2f532f566b27f2b281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aeaa8149a596a97e9f15018e946b5b31e250aab729443d54332e65bc268ee72d9b7f2d4b93c151d8eadceef5d4110e5000000000000000000000000000000000c47666641ec861aeab8c6fa0672ff1b5e43a1ebc7caa1777c1d4202991613094a3abd3cb71ae8cdea9d61a994ee5f131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c41e11183ff135aa1e12f8371e0c31c07eeec11442a3fc5b4a7eda2ac531cbadf137236d4b3fd491e0be7b4b153638000000000000000000000000000000000a1b347e894b324e76fd6dfad28889eb368a870c414a5ee3116419dec06d2e2d8789866cdb5d83d8916a7374a63939201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001840cc889e8ae4a91505e5d14e52bbc87957dba34ac8e379d43928fb97262760f731f6b1497d250a8200c113414e3757000000000000000000000000000000000becad162c908bb1a20439370715edcd32efd4bd6487f6dca1031130b1f8d6d0d9b39998f2e7bf07c2fac052de37d2831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cf6c67900ae433f570dd5687b2c4e4a3e056251c1fe5f7f42a629acb3f08fbdad55b793e52a8a71395a6d52deea13e0000000000000000000000000000000011c5126a203e93d59f777b9e6cb719567a5b440c074cab1c25e977ccc5b0dbf75ef19920340ca57e1371a61e19b9d7cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b582932e14e059c35c4f9793a544223d4af0e089349d523e892471ab2c7de82a43414063b7fba47da36ab04b65be4c000000000000000000000000000000000d5b0c1258cbf6af0ef5fcb6b6215824f0bec8269979804d5e8ba11b69a2e3750a653cfec0ce4dc30fb2cfe1b2462e4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b618a951954ecf61f8cfeca12da72895449457c294c515fdc67002bdfb5855211b02f2d382a4a918e9abd6c8afe9e700000000000000000000000000000000015abc43343a55fc0907955ee26c1cbb415c40d8d543a1ca5d8d8b8c0c7289819901c7c0c2fe7d767573642749b777821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112ca64a7c34fa3807a10dcb94463f21e38d243d0730a7e3dd3b8fe6ba519673f85f0c6d5bf613a495d22fe77bbbdcf30000000000000000000000000000000018b712a6c0c545d0aa6e712c01b9a27a1f5402950aab23edd1dcdb11fb63616869c076a045cf0a13d6886c3044dc5c271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016fd745dca9b87537450a222e7a6a0ab1a58aa81f1459b8a7ca0c256a6eb2b800268a779c4a61f2f9d30572c663624a400000000000000000000000000000000001f9b012d6e243805debe7f4978a4d2e9a086116e031d8f525469e768d52887075d395ce2b0b8841bbabce78cb7dfaa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f5674d1473a05f3882c5719a045ebde7c50fcbda6de6f094650bee8267b26c79abb8b9a6241b95e299fb15b656102b000000000000000000000000000000001773f0d20002fc229114608c3bf6b81fc35118172e1a7486e75f5cd7d9f025b3bfd579aad3ea440a5fb557f96d688d0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057ae8a6c76dc1572f4e7ff164b36d66e7fa7d5e436fa295472be39e1fb46fe66d8a7d36b2bd949d52c1a5dbb826994d000000000000000000000000000000000885f897f0a0e62632130c5258e053bcab60aeb89700551aa8efe492784e6c8a589fe522c065e31d29d1161aef28a8621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110a04591e110495e721b21ec18cfa6cf1cabd8722669ebf43fcc771916ad3199e774467db46c347bd0959de53014d30000000000000000000000000000000000afb50bef961725afe70b7ac2ae5ff298d336477b4427b737f27cb3271fe41377ce9246477e33f2cea3390305d29e6cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001608abd8c9b8bdbd8f08bedeeb2bb44debdb842f781ca484f18bc12535a252427fb078ca735981dc48450f267cd5708b000000000000000000000000000000000023063fc39679e9c615473d08c20183b59d28698ddb22cd462a22112749bbe5757b20e9db706a8e12ba059da0cf61ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f25995dc9fefb2749a8d36788023dd286a138c188c57e246877ba36db96a43b715fda169ffd3bf3e1439cfe84149a64000000000000000000000000000000001778f51c7b23bfcd7f0fc04adbd4f46bc6cc2daf56ef3f6c4b3507729f5f9a1c164b80f942cf2df727916f252565d2791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f5efd23dc4a6c30a0490e8cc20a5094efc7ef2ead0fab9d73affd46c015f17b96faea7602edbb9683ebc6007801a1c00000000000000000000000000000000041eef5118ffe97a6a6637784f15c27eb0297a895193650d965ab24479f891bde3321eac035d979d0d723a16c689b6201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049b85edfd564cc9afafc28b024be48af8d81462a3cc0a12fca56fef475438d3621da58bc7c66c24b1ccab49e2393082000000000000000000000000000000000b76d1b97c383d2210402e95be7a40a55d4669d7911c29f1206934d5f270a89b3cb165eaff4865ef7a124e7e4863c7d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b9c6df96cd2b2bc86b2ebde0e69521e72ece5677f1bc012e3e4aff50eba95795243a1c7759bdde6ddb1395016354c30000000000000000000000000000000009fe687f65924382645ed92edf5027f7b2b626d4748a0b97799a684ff4eff63a7e7bd4aaefe569a2b7562bbf78e039a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002fe9b027020a2e071ff88c2779224e7e4571c2697eb32c0fdefe4316e498ecf76c62e8baa4c3d396ac70840b1746c4d000000000000000000000000000000000d8073ec215c3adad9177da1a4915a7eaa927a5f34de052c422ba212b821f9d344db72db6dac06d61640682572dbd5b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd0695f5d152fcd3ecd8a0cc47d90a1596876b63d03087143f6e1e6de688d576064b838f292345490a035dcb709090e0000000000000000000000000000000019e0318dd94dfe8ae3ed3fc4a2e69f357536da9bfb8b6b505952b54fbbbc7f87ed16d94ee1f1ff370764cefe8743c2321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000622a1d6bd1acd2c1795e6a90433d9536738446c20253f5dd4264bf0e0a68884bf87f0fde7a4fac8d713e3f9cc033a300000000000000000000000000000000005faadaa99cbfe16a6005f4ddc6d6c88d6251b1e97b42c65e3003a22c52229932839a1ef0869a1842d00804a93b0aa1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b2bb722f8b8bb7fd517ead291ddf9d768838a75b84092de562e0dbe2469cf12c61d376d6320316b667a78068fd468200000000000000000000000000000000008b547d2d036578115a8f10c3bd3dc212860ad22c20d244831e23048e031957951361f0d8bcf94822dde919dc0e30041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000535ffc1e8f265b0fd3180c3dd36eaf0dde560cc7266750d3936fe8d0d66de23af7af29da1c0e80786d3a778f332af4a00000000000000000000000000000000094fb43c07069943d3bb8cdb06409e301691651cbaa47ef30a985316fcbc7bd6675d0a26bef0dddead6e3e7128e897871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6d5f571d4259af01966c232a2d0478af3f8a5e437ea2654e3aa22dd8126a4559ed822d80f23a99fd47e32e585f540e0000000000000000000000000000000012126ddff53a254e2549a4e3625f97c8049406f338e7cbc9be45d54693aefdc85a88fde7c2876aa84ab3deca13a3f9bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035b3a83abdb6a3f26cc632f096786d4f86dd4b2e23a511313bf394f2dbd857766012a5dc2a652126bd2d4c40a55e8660000000000000000000000000000000000b0eff72869ee494a35890af83127d63aef983a1e4fb14f5c2f01a40aa520c470eab279849318cd09d0b892217794d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001380f371d43ef3a081c52e19aec34e6565f1deac51ae23d6b27dcfea4f0262ac0abd3ae82793d9b3f4e7e85dcd922d6300000000000000000000000000000000038aa7a5659b21cb046eaadb3c83a2de06551c4697ff8a38cc5b01d53d6282ecf7912af5981f39b404d8b3c1367c8e121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054c96632a740641e3832560c862fcc126627865c3cfcf3898086cb8932a4c711379bd4dbf881113b02a543cadd91ec700000000000000000000000000000000042b55177a03567cbf2bac828d6c91f65ca8b64f2ee3383ce66b0bd29a9c01f34b87a967f289748b492621679d26c21d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000eb8bd52bb4712df06935892d0c8cff126db7500dd698a40aa9a7115396a5e22ac65d01623a510edad31af1b043dc530000000000000000000000000000000015e227c6eeca6ad5162209b1c64f52b7b7ad6f5f236f91a7d651743dca752d320383fe3d57f353b9e8f37f93b498fb0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032801b26033c561b6262d1d2f9cc3391e57aa0fb03a900e66a3e1af7cd00d3554ab8134b2a364d3874d1ceac70d83d5000000000000000000000000000000001164285afb3010d08bb0dfef245c742c7c947a4b8a31f097d368b66568a3712b0882ab0bf0aa24c0e28064cf139308821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014db504075b12150b2bf4bb3bd726b30a6a61278c976f16afbd7884f4a7086768a0aad8317abefe632083bbb13f62e5c000000000000000000000000000000000f4af249c94f689673715c208417a79e56af1d9f73337f1d53bed2561395d7b9d8c8f243dfd2ea2914494ce165f6c6561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001466d0b266c6b66d1e81594ad7e8275d30c72768839a1777e6cd211315a394dc1586085a608db11696160a2598bef78900000000000000000000000000000000109a3ec7b59fa58699c8e6dceac4a5b94afa517d7a4cf7bf40df59e535056870b23130a021d4eac6cba20d9583003a061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001609c271c8805878a0870af860992ce714efa0615806e6745f534cb7fe5017b231e851a62a01db66d90141551a7b6e7700000000000000000000000000000000009ec54393017419021e56519751a3dde3169e8a4debca3eb0bf606d7d8cf0d0694b4d096b934d4cc58dcc0f4992fd5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fafaf6645b84bba45a7cac36636ccc23e325828b232215ebbbb34b807c0226e515c84ab6d63cab8ca13034db978b608000000000000000000000000000000001020f63d1990a1844cab6f2dc86a756a1f565464de9f4b09f3187039ace9c6b9e83f12b1ca7aa06c5713f73aafec92f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014496cacb938b522c6568d95fe06eecaaa01ea584c9aed2c7d4015d6a53f5118cb780c3526776c2fb83835b920d5a405000000000000000000000000000000000ade76cadf54a66fe79212595e3fe355d960e02768f198edc5a8beee727551946398abc1f82b4404fdd88df3971d5b451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c9ba3ad47c1f23d9d76f6547b97107f8351b41c7514118de1ed2ac11a7a3e80fcb5dd8fd85079aa0636bbff4c8a07c0000000000000000000000000000000001d5aa8fe93b8a9e71062965da2880fcb29fcd776be9c51c1d9b5f45ce2b00b917436a0cee6ece95c192aa53216c0adb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f65dfc2ec2d408eeab0ad43eb425d381c6d04c33f6d50905b480e0c82eaeb706b9cede0be5446437911eb7db828fcd00000000000000000000000000000000037589bce74200534a1c25a87b0252efe6ac2670f0628b518b887fd95d0b61033c304399797748c2e363986cd8d03d5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086d272501c102d3869b8718636c3c74d19751e011e4919e87d03c6ccbea09127d4a516e4dab08815e0ce178bace28cd00000000000000000000000000000000072a263dd2b21f6a917ca5656f03b20e3a0aa8f9c86682f23d140855ddb25699c3ea0384fb5a8b90274baf02585bb11c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001742c85fd129b459267280a35fd2197efca3a574f02e5aaf9a07e4dd07c477487227892c5f07a075e9f6eb71855e40560000000000000000000000000000000008d5d90997c41ec5654098a6594bd9425f2ae6990e1f6f96b00b8d8da2532405cfc3cbd72f282347ca980275ddf8a4aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db330aca445448b28f877fee42c52c20fe7678a964e7fcabff829e913886e42bcd841c10fd1552e4ee74d9abac5bb3e000000000000000000000000000000000468b10dd604607b1d597ec7db6a4f38c71d7c2d16b92844a2826aed9bc98e07dcba8ad4167055c693403f86546362d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161c9ff70bd15e2cf8b3705b6d4000cbb6c57ccf466fccea7dddd3fc7bdc5fe9771a1787ebc2ad62a2c79fa24d335742000000000000000000000000000000000f422dc138a5a44750966c4b4bf800c9f2cceaa3b1fcfed393310526002f019fa8152160eef0a6de91c09b957eb388e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000011f55536a12029224804dbdb505085019a9a3f7f2385ed180f6073feec79f4a7842239f1c22cbff300d269d32a21b8a0000000000000000000000000000000013891ee8c6a06354b13aff05acd0f0ea39bd1931fb6b220ffe0bf5e47e7404aff92c0227ef527767d41e8860943f4cb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151d7ce322c265889ec51efc9dfaec0f9484b7196312656b2a0ccec2050e3ce2dc67ea6e5845fa982b9600023badde020000000000000000000000000000000007d07a21f7a291e33a70d1c97eb48467fb28477279433a7afdc2fc7da6963ce11256016b73c6c6d00e0ab46ae1f4cf651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136bf0b0af899b5d612ab92b3b4f1262ca0c6c14acbc2362af81353514a00a2ad20d45ef194b6f33780d505f356d229900000000000000000000000000000000151c0801de052ab1ef24db90d43a7ad6fe2a622aae6fdede328be0ec3cd23bf92ceb8bf9fd7787930b048d9cf97a64001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c7b01bd44e06f2dfea99d416a5b54ed3c3408d037a4bf2e4176de4c2be8ccd3cb9e30582d62372d31909c832c3ce850000000000000000000000000000000007a1ec03a0f012a3c1b881ba6a6f65e824a77a8ffa79f6968d1feecbf5ab4433b359438de7556f5383148cd9ffae1f141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d719b658ba6a3f2b4f84afe77a7cc3e1ebeabd49364403788db9972b8b7566e1f916306dbdee17de5fe51c618d3f3c0000000000000000000000000000000002bb87cfcc1cd29e954e211216cf89f9e7e2a583f4aebaa956da0443e5d0ecec0906cba146cf06beeced4993369eb70d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b828ac1825ea0fc41892cee243f440f96b858df3b11ea4002cf0d35d1328366f877cfd5d9622367f119975ffcf933b000000000000000000000000000000000f057e8fd1c0e30d32db258380642ea19fa8b44da2194595018b63360809cf344051214772a8cb305c64823075b8924c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001242b3d3a9ebedd4e91f60827d28d84f05bb0db40d27ee69be6925e7b620e5c8a854e5795ef1c6b478b400d95b675a3e00000000000000000000000000000000043a9c897f3dbaf024cb8200e5e551c2365c44d7018af31a008cadadde2b38dee77777cc44f725681f7eb518e0e1ec541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011283ebe63911db8c67f64f377b13b85fd6c8b8dcaa2e1dc6524bf1be9698244b22dafdc6dcfb03b720de332b995b79600000000000000000000000000000000155e5d4e7c658c0a28abe4fa28f16d1493260e6859b8274de58e6f23314480bfeaccb12036355e77706b37fd90cbdf5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ace541937df3a0eafaf3948e829b357591a3a0cf31cad41ff6682abdf55239ee450a2da1ec9e29e67f1671c6809d9200000000000000000000000000000000088c84e9dabfa5dcd8a63e2d9ff3e540b9b8f99def1e0f23515f4ae337d501182dc08d0eb2b4b53045c12fe8e3b299ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a8d258062dbba5760c84a336470cb769304c65fd3149268bdc1b44daff125860e00ead98cd6ffe757e6ba149e69207000000000000000000000000000000000f2c843043dbc78dc56a45c56147a6717cd4f45b294619f490153590dd120e7f60478a12c06a3e5e678335036a74f2ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052862b589abfcb2dab1cb1ef80658341c95ec55dc22c59b0e035a216e73b4ad10ec752890ed7fe8e0475074620c544f000000000000000000000000000000000c5b5c9c4c330fb3125f28cb5346fccee22deb0a504a736aef34a04b1e57f6866a1b4d9613cc99302d0f9df86950cd391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cb6fbe236dd6761a2522d48b68b97055aef2be538f0105b242d138bfb83401617219c313eeac6c548419799f04fc5100000000000000000000000000000000012c301c993f17b3b15005fc4db6dfdca4a9d6cec498c0070d69284c2f145ea2ffa1e1c246fd677127a24ef5de01d8d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8c482f97fff549bdccc9e255b8bf7f341598ba19e04451e9379f794a9869eea138a6c83ac9e103d37e45690d5026e6000000000000000000000000000000000ed94db46df11f21e761c59d078b4ce4da283061f20580ad451e07285a1a46c1a05c5bfd2f3c7998f37832591e42dd6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101abd00e62c73ce99d8c2624e711160a2a90945a1e03f01ecfb1913b706e8a6b6ef9a055c54676808bdbc804955819b0000000000000000000000000000000014d971cb41c6b2a610ad92ab43c1449f87702240cb899907b66adf41a8ba5c7147a418409cdd03546d1ff990fa69f8e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185559440cd44edd0dcd144a99577592bccd1e313cd451beccfe5e48b88a1aaec02ff7a940e4d71a0fb937aed276f7d7000000000000000000000000000000000ce9d70ea4ce88c64f07598c5fa7e1c57dd15e4438ca5e160da5ee7e923d9e54a1fa891b473a13441f6623d2588680691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c1c5b647a51ec74fc181e270a70b9f837f6c9a0275a8a7f55d86f1b14d12ac77c2da595e1d0486c809f1a6984afef90000000000000000000000000000000019311ebabf285877b0633daa5a08267fe76f071d8f1f3bedfef7090af8ca18624f527e248f9229bff22bac10d5709fe31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6fb1fa39089f61fa7b699c8e408ba3620ca24b60b89a94467811c73c44509657515584839dc169d95e3f5c23f0e9b10000000000000000000000000000000013381cce2b57429f6e4aa94c2c76330a21bb75b306d17bc348a48da4072f1f85e792cf0537447feed6a2e93f03e7a52d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a28c4fc7f90f4fe21bb9b67c63a1573e0445b36884ccf276ed7e6342bc41af999fc4ca7c0c70738f185e37f419ecbfc000000000000000000000000000000000f37e8fe4a44eebc486cb213b256a6d3299f8f344a7f0360caaad46a6fe91bda2d181c72e154fd4122f1f837fb3e27481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010cd812ce9160202975214f2994ae54c279428895c10e224350d96c5f7f1594e6e84e75a40005ac8c809870ed34d15ee0000000000000000000000000000000018c1dd6b459049e81269ea9909901652f9af3b05e2b5891b075e6b540e61031aadf0950075e0617097771f382e72a29d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006271fe057667da2d37b0e0e98a4c5dd20a875a8a76dc9c2fb1b66fcb22ac6269daaaf0a2d229241fa153a313324a5f90000000000000000000000000000000019e2162d8bbe052bde936d0aac598aebaa2e70f2871f72bb58d4da413266da79e637d57ff9a794a171aef910f9219b151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ae08a28ab4add98d3245b7d1a4745558aafb3e002954b89a39bdb5254556a63be6cd96db0ee127776958469a7db027000000000000000000000000000000001457f07c310550e4997fa925a6026009c7c227da8abab7efdd5de5d7e41dc402cf092850ef0662f1acadf043226a41701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154959caeaf34e938ba5fc09fa0dc030c98cd48bc1c348f6258f60e75d9b80f21c51fceedc1b1274409c56a0814ff5ff0000000000000000000000000000000009082ac1f9ad90d9b839eeafddee87c49fbb9ea89e4f820c8523be5c5aea4a03af5db7712d3bd5d2e288dae64c1cbb4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000155ae8032f93487ccc8296fcd1eea54517effb8a34bd4dbc09a4f9ed9e4f541b82a9cabb8d2cd57cad74274c993a3b2c0000000000000000000000000000000011048184a765e0285e4d799b1ae45c7151b0c1aa54f59d165f276501ac8c5d5ccbd44288bbdbfde58e18a55a03db4b3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000477d4b85b0f75548854ed23a321933fda4e527853b64edb02565e6d6f60e2c5fe3a1d8da5b8b689af79eec471af315e000000000000000000000000000000000cf3fd958e8406358364674720ae91494e43d089349b3ae4912d3134a5d1af38f506055bc8468d90820fa3eccbe80c6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6fcc585c9dd530249af11e20cdb83ecc0cddf42658b13b1f4adebaaab5d03a4b3221b155779fa313331da8ed3b0e1b000000000000000000000000000000000bf11cc3eec2168423cd8348b113f4139ecbeabdd8ba778a543c5271db58816f892ba0d7f969cb0c7f18d435101630d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061e021095e6de6caabe2f27924928702f2b84fb38be9f954a018b6c312bd05607654dc1431762e7edad1941db7f751300000000000000000000000000000000079905af69fa10ccc714ce1b105e751813e9316d15c38807013b2ec4111d9d3733b77150355ef8cd56031d35e29b2d501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bfea88db432daa1a657d04c2b0fbb42b9cbd23a2d4ab47bd57fe2ebde3f8dffa6b01ba745530435ea38101ff8095c640000000000000000000000000000000005df5bcf93ea02050e9a472c2c3e4bff9fe47461818d78be72af77793e76ac4fe90c39d7080f737a40fff17087b02ac91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008cc2ba0e52b4962edf02e0992080d4e9a51838e62dea00248598a8e0e72df3de91f0c7b3e4ec3d59c96b1f164d62cc600000000000000000000000000000000117135bcb61ea19e4617a440a4802029c038551cb407e0dce79a321975066ec5bc60fa41ef21ccc27fcb7e4e5c388d0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012550ade0fd3980bccb6a803bd1468a10d01a8260405f1ab66247801e3795f4af22adb2f2e3cb2bf6a3a355cedf1a05d00000000000000000000000000000000093348fbf2587d071ddd358da9e7a96b324c50c0421b66e2ff6f4c32efa281477d1b3e163eafcf977a4ddac3f63176f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e22814239e4f5ace9664400f3787efb9ef4eef8f4c83921c0b3c3309d80b5d5e427a2a097ec78b8f3c68d5d59326c4500000000000000000000000000000000182ef856ab48686af204889bbde2518318d20bd4a10960c657ba5b5c601e84182abdd836af7ec8df2e72529af2865e151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6caca1a63b589d43666371d533b3c0f1baba0fa544c62eb8c8efa2d99108361070f743e0daad354a68c823f636ec1d000000000000000000000000000000000f039815f99ccf7fbf856c9f7afdd6c5297e7787608c99d109edeca04b2f2213a5759aa5d3d35d758f35a70c2938ba831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189bafe56321cee3d9bad92c5ed0b27c1598a231d6222d65223c8da5758bbb9d30c2dbfc179382e7df1adb65e05a46e5000000000000000000000000000000001790ca2d4d4292732e64926e6662035e026e8c94f2db6248dc64ec56bd9363437e0cd3df34b52291cc802f89c64859f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001a00a01dd3f08c433498c4df0ff181ecdd77ef32c3321374097c192a5ca0c01d85a3e1729e565c70ed2c2e32638fe47500000000000000000000000000000000147ff41cbb097145987389700348a8834fe082f9a2df1f975e988e4033b965a26f523ea87f34821edddc8b4afd46299f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8e71d75397d16bb61212f476e71aa7c77dc6f0426b316e90ff2da6583526288540bef759953adcdae547588539be24000000000000000000000000000000000331fcb9ba770dbc8c6fbcce76fb8147d2c1a3e9ea7f77296400a79ea25ec599dbd77d6ee493b5aef58ed836737da1761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001da354ebdcca09e3d2acf60f7325bd80f9dff4b693868dbbb3c99e0e72a98b9be7a9c2f0d0f2e6e3245c711d52f37400000000000000000000000000000000067f0f97ae597c3ba0cb5a9f9c9fe85e6c485b8fa188c85c0284f7c157a097603469a8a8a6e216e887e7d3fea9a3acc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c8c82ba5af2f60dd8547711f81e6f5e8220847925398d0f05f6c699b0fd3311540c7a84f09f2c6f38ecdc4682ce9f20000000000000000000000000000000000360fa81f07bd049a481d5241f36984d90ec04f362b589f4036c6d9d5d9aaee7f7a7060fd45c1208062dd54073d6fe21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f472da772e1c9f2b44f2a5d3049d75f7058a40dcd6339790f8fd663e50093b942220c733dfe494113da89c8b1f1e4a000000000000000000000000000000000b4762ad8088bff4de67369aeb0dd9390fd9c26dd94817acf5172d6e528751197946f993288daa372197c159d54975841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a2738d64cbf20db3c6c31cf7a3ecc97ae17120d6f680044cf0f39dae0c993ab513184b6a182ba95e90dccb196ea7bd000000000000000000000000000000000226e6ab7752de192d0f84b9b981e0e8ba2c1da15cb7e2d75f214457655ac0f30c9e7a1c4960ac552a5510368d1b0bcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128ebc68003d9c3aa3330e8b4fef0b6df21071b264cfa35c9aa1a69ee87ce799560f5fb80232a82c44a913a18282f2ff0000000000000000000000000000000019e830519686d17a82714d958d6b943ddae7caebf95a7fdbea07edb376f92ab17084858c747607860a8694e5181650d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141a57ec7735b458576d58531596c996b5483fb401c5e25fc75abc81a18ceed9905d93d5c622ba24cfcd658d764b60af00000000000000000000000000000000030e119731dc868873f1e60c191442ba608a3493cf20f0f02fc19f9997b528b7c7f99dbc85bbd05aa9c8dc2ca656c1bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145c638120329be5cd9da5c60833bf63c6b8a99b340ba5a1c22e0d905b457d6370bf6d36a5a63ebea595aff3024437e90000000000000000000000000000000011acea0b6a20f158527e1f62a9c07d42097071ff1667dc7063a371ccfb7b8369935981381f6932625837432fb61a1c5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b32e42599259123bcc24215b7cb1e98d3b95571ee127be2d5df4b7f2b0714120213c0c586ac6cdf3fac4402729876c0000000000000000000000000000000014bbda24e9ed3c6b1a029c5b9a81f164fb0dab00c3a81572cef52791d10b8c6a84c48da296daf49d2645ff454e9f72ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d1daa744f61fb6b80a725c59b49aada75804237063e31e62dfbc2c498f8f398cf55fcd09da4f4431b90d39e8bf650a000000000000000000000000000000001325723acb0a485d57acb8400e6191cabb4d3a3f725dafaeafe35a93203eb3490b4a49f02f49b259c6c70bdbc352bdb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188d3210be6d46134965b71ad5081f22bf32b3113a0b825198f495a47a4b3414d48dc6b9268b39178cbe28a999407aab0000000000000000000000000000000019ee7e7b3408d7f882e6a696231f68b61005a078a745d7cc4caec6d365de03212e562c2da208860b6500d657679d91dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e78fa2838e1e43de7baeffa280ae5ecddb6f7642a8b1a76423a88202b96cab8653273d5a96305b375608dee4d69d8c30000000000000000000000000000000013de4ff293bc87c6f887bbf304cf63ee506844ab8b3f897d537e212c60f641c47379af4d6b5a330fcf6cfa95c6054d731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cee92913c4c31570a7fd5a4478ef128f0c77b6713c5f037382a44c49bc560bff7657b2b02a8120ce086ec1d955a64e000000000000000000000000000000001962d475c82c8d20fa610ef33ea4b1873a09a42d8c9e5c54162197be22dc3fbee574da7804808dda9e9da0fe31f266491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c41c697c1cf5932d4e2166d988f844974bbe419c845e0f4530ae2be46250594dca8d57313348dd0860f970d17245f4000000000000000000000000000000001161b52bbf5d74c8e5c4b150453d11feb6cf48b5cbc723f3a5be0cf08432fe1928eb446f42a37bd603d7878e7d3777391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c28dc5e564c1e9c8df0634fa3d24977c7eb3a95b0e836309c6dd62b98a3448e597092450d2354d5dbe33a32b4e26a93000000000000000000000000000000000c9315b58b4c8bcde61357f0e8998718baa5f8d52506c8c7094fdd3dd9d908cdcc035edcbadb57ab747bb5ab8ad93e791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165719d7739f073b5ba138b2ec9304308d88fdc69443b8b5c41babfa416778abc2e26f6b292a96720ce43c2c38cbda7b000000000000000000000000000000000488153cecefb2021b059eb37be80cceb2f0170a201ebe82583b23797b5bb798b7fd911a28223285c373f00c119114f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001962a364e7470e4a4430a96a411d39ed9ee29979e1d1b4c39eb0ab2527d93ca80a2e167af61099c125e485f1d3428537000000000000000000000000000000000c236555b115b662ad29ed24e060ef4cf9d09177999fcd6ea5a6396f3b6b4b3e9988f34694964248d27f0ab045e2ab941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc0b44005249a529ede11475a755f1227f35ffa5e6a255690717486bc7059a29b1174f4fac70d620554501f51794eb6000000000000000000000000000000000ffe3ac61120557dcd4f7c6b05f6bf1b28fcc432e98947b428bf5d45f4fd6adfb34d7ffcc70aaeb079ff5c5b578644971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e20a17b90e22eb49658a0f97869d4639761ec9e4feb0800f0eb984afe454953b998071258409ca6e9ca68d5a6a24db0000000000000000000000000000000002aa4923edd62fd2defb77ec619727f88311b52c9774bf917d3af57af1db35db4175333580991f93bf2f55abdfe65e171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001961fbcb94238358a71022c9a29d72078fb55df178165095604a96bedb1045aac718cbfa95b6f44b281d82e02453c22c0000000000000000000000000000000008f96658df276b8b5cd2163494543e25e210da599d3b6aec5fd861e89261ea0e7985e986aef33fb154a906fd07790a841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001331750f9dfad97546116278bf352563426dfa14fa64f863d22afc6679c4aa7f9f0375682f0ee542f2b72f1b9dca435000000000000000000000000000000000b52ed382eb5e474af86a728eaeba55995b075034cc4eab4b58631bf7bb80f1995e04e4e53dac427005048859425b42c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e7b86d6e1c5d63aeca19db808b754569421a8adf1f80a82ececcef01aecde0b167d5fd5985adfcb7fe03076d9494470000000000000000000000000000000000a6444694094133d0fa5fb27ebf40dd9f89b4b2daebb5f92ba17adb03246210e9a17a29ac4983dca59452dd15c9fdd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e775024e7dd8d7e7e6329681c3142c71961676b196b0268ef38f3131a27dbcb77a48ea10a9657801796f6ee02a4b71400000000000000000000000000000000039345a9cdc53788142c79d3a993c81d0ccde639a65a43289721f998eb33229cfb59ad6b6497e297f04dd30d91ca170a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000070e23fe5efd8e48ebaed43b678de98522bc11cb1d68ce0ab8562c8f7c9b1d7b21417ff0a5482b9509e45661b173ca3a000000000000000000000000000000000607c8dd18a3df5308d217cf95edd3cc20ae81cbd706f031fd94da667dcde7181362c1c8cf469253c8405c4a485777861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195723a2e119821cbb391964db4c5522f3456e9ed1d8710653460cde00ba229b303303455741309961ed7bf8e649c4bd0000000000000000000000000000000018cd9c87b364c48c96d4c88bb911f2bd7513ebbd62e4200a32ee3b81327f394cbfe8a86f4ec38c046ed6677be7cabc971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098f011985c1852aa7b6aee6c391d52bf3bdd841d77477b06a723fe6de19d7ff5cb37856fce035d65cbcd05c6b246d9800000000000000000000000000000000085ea71b5e716685f46bef93afe39cf7f78414decd2e00b34cb0a17ff6419934c6786ed347cd0fa92f5752e55b5e6a5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f1b3b47e529ec8d101cd5414d806291e09dd6747c6d4baee723244144114c0c494bb386e2a6dda63aa1fd4f44fec580000000000000000000000000000000015db8b8fc7f0e402932773902472c66f5ce78e7f922aa287a8619ffc344b55dea15e3f973810c05426d381754dd83fef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063c8125830a4bde7a90337e15a706230309454213427129968025bcfd6f162948972f4355349ee9fd7241e729ce26ed0000000000000000000000000000000000cc6503ba1a09ec8f77089503661255f755aaa1cd266ca5804ef50db8848159aa9b840eb7f4f5b4ccd1cd553fcacb131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189b299dd0e06c5a3e24fdf8a2bd97fd01ea8e1ab622fba0948c0e81bbc9d82ec17ebe6b07788f189a49298d6b4fa121000000000000000000000000000000001705a6a64909557f18c43945dfad11ba44934751616481dd7ce366789d25ab1c3a260c423d097aefa7cd458374f0b8101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c74958a23d3f6867a2aa16035ec56d965cb35a6e471d843b9cddf420f4f8a671f31e2dc4fdb3cf0fdf330e17f15e56000000000000000000000000000000000e980adde2310179db5f307ff0ec23c442c2e72b96316c8e390668950ded2e1cec2b5dc6ea23e0990f50e1e87543896e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e87c4ee0557de92d9db4e3d3b720f9a752d8da4f9ad6123b3dceb1afe0c812278554d05c74e18af76193fdbe31f7990000000000000000000000000000000006a5c3e3f06498d90efd9cbdc830d06e556cf52f2f6c30f56d2ee797560f99cdf01f181bbc2f1c8ed6d83b670418aa541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056d6538213cb78a601306f8bd1be8e90c372af4bddb35bcedc720f9eb778cff236385358bb54b370220f297c47a000d0000000000000000000000000000000014c181538dec7e9ddaa0b067febf02fb6ebadc09da53e5cbbdb357ae638ceb42c2d0c56814df4524af31ee515219f2d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079181eed3d24462bc74897c084c86fafe24f1c4271611352dfbd3afd975c57ccd5f90e42aa615c429611c745a75d4270000000000000000000000000000000006904cae0ec31d7c3e6aa8449ee530ea31885142d120227ae26f367024f56a5f13d3126d212cd3594b36e07c36891f331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d5ccd720d47ba683e7889e1b9a3ba818c600c5302dd8b4de41ce39de24ba78b0e375e1de8fdf885be75fffe6a0a2db000000000000000000000000000000001796e45c3005a795140922962a9d7aa3166db944aaa01f73b39fc3455b77884f7d75baefd13f5c123e7c5f456eed5dc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009fa86fe649c2b129afb7f37f539cf074aab4978784f092515fdd3fa159f6052c34d9bdf066898552b0899409fe81fdd00000000000000000000000000000000158032329f1522d747bf442523c54b1c93fce867d96554ef47e006b2a1f106a7c2bfe8da9cdbac84a2d416c2ec42f7711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eeabbca3e85887f7549cc286fc5249b0ca2143c1bd67b1e80c35ef908efd06c2ea9a9bc5f79ec1b060ecf70fad6c2da000000000000000000000000000000001448c1bb70993e7918c626774e143079c659a0203606a774f293a994c40b69983871f309b91c2b99743414e4f378f1bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001540d2dbbd7bb5c3a43410f0a9c6f9105a417c0ea52bfef688bb89cec542e6e756a609b5d4dca3f06e256c0e5d885d64000000000000000000000000000000000ccbaea47d304b5fd1e62528ca555396f4416615a5c6dd7e0c5d066098f0ac65fd4c8ff5fd85557f21acc4e7dde8b1ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffa570f0d83387a4ff26273574bb94dacdf92ab195d923a9aed40134a03b075eabf7c9db5c69c950ab37e97511de319000000000000000000000000000000000ae85daca5ba906ffc0860f58ee0360b0b723ecc75b37c0b38695a17009ee58e63c5bb5804baeff275266a3aa118768e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000002b7503c40bb2893c815822dca084300a1871394f539dd7ec07018afd359610278461853d375a5b57fe0f3767bc6f0000000000000000000000000000000007aff4b8659be35c9a4da9a8669e6f19398ad3d940e3df6e06534e727787863178809e2cc79672e66946719442ae3d0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000465f658a14fd8bbd054199af94e886e0b3fcb46eaccccddadb9a40f1d1a1e8312df5c41914b4467da114dc4158d7607000000000000000000000000000000000a94261a49c1aaf17d54e3ab1efe8458d9eb3a79b3f775e96ea7d2133b8975912e873b8a8981c46d9516b7aee424575d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000705e20185225eaba9743d9b776b66e799c4883f22ff8fb93cec7a9934671b8c460b844da090b011a5a04876420cfd1500000000000000000000000000000000029f60f51d109b30e7aa7969a313faf62fbc0402e212927c470ad5600cc382c69982cdf8b1166556cc762726578d453b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b12f72b49616cee6c297527a08d24d6dde88f4cd52249f0d76168be8d1c982c93b784af3243d82059c839f2016b57730000000000000000000000000000000018206f54d28e5bfec1ae3bd7fb3ce239103450e6d7b6d10dc9b8acd2c16234c9891c8fc66082def422f1b386673dcb9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001693d4d5a35beab10bf91133c1731f03d5bd7f942afeb07427e644962f7127e7afc1b52285049d6436ad1e95a4759f99000000000000000000000000000000000c18c224830ea65670de0581d266c9213a2ded20a848d1067b4ebee00bdf60ceaefa757e3140239d16d374d213fbe4101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004ccd8f64594ed787886244f40adc18d06fdab060be46d7b5aba96f9484e27dabec436db52b33b8638bb446d4a067c900000000000000000000000000000000130947444d41e9427b71d4b83bd94e7e98747c990c0e219c5d08189569f36dc7c933f5fd783658762d016cb91d7fffeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000637cfd0b2f6d2a77a23260b775b47df7d2966a8ebc0a5493e1ce4a5b849c1d9bbed1075700c5910b3c10e5a9c1efb050000000000000000000000000000000014b573d573834f1d9f045d708836607b75d80763f802b75f626acfa75fa39db46246d9121ec70652e92074128d3f1a9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b9ea7944b98a647f0570314eb273283e218a404a98c0d07fcc023eb3c0461ee5cd488f47792567aaf21bd6f623129b000000000000000000000000000000000b7412cbafdc74a9b0bb7b3c4b053280a136d6154ce5ff49399952e122307beb58caac5f825114c4a7797cdac9f950dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063edfff9f7d6281d702a85cea7c41ad3bc076af07484a7749d04c679cbd03fa59b23636bb5c8457edcffacd1700212d00000000000000000000000000000000045c7275cbf5ad941c919aad462c3a242ef65024c5a671561a9a3ae9a8a1c9ca41bfd18412e8da7ed2a48a8c80e078fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e25af8ee5f8ac1e6547d81735d477e3d745177b0906db211536e2ce5c9faa77aaa99397fb68e8f6e13c2d2196ee029000000000000000000000000000000000f38805d1f0efe78454708aa19a08d03c760280747a22e2a07e41a2882ea3626f2f6dd4cb3213be037208e9ce0c0d0c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c8bde4608791b96ca947397be46e43676e0872c3f85c76f9df85a6a50a0e5a186e4a18427bdcac7cc39a2f63df6f51000000000000000000000000000000000ffd73415a588865fecd709a2a9570ab218d7915904b5c34c7fe3a8590ab2f20a82735edd9cd2c3464a26808ba1dacd61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c632f5b1391049be0dd9d63a1d307c2f6a9c69971e4059341d510936438eb78d60d93561c2ea9a2745bf3e0fa6b62dd00000000000000000000000000000000191d511e1024ba5c00ffea3f018cbf83de05f510e03f198c03a8741e4e8013f1268bab5a43f3879c8bca4182d116c6d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b3a3b722f3929634b4264532229c25e1cbbeb2d7bcbe27ed9a7ce77925ae7323dc621f6e9e9fd563b38df715bed9280000000000000000000000000000000006d5b02f9389df85965f25616fa56ed77c3f5cb815fa796aca9cece3e1cbfbe74663afef1623c6fa8d7b897b5238bcf51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123f9914cb063cced7b6bfa21e4f4c4599e0c19c09b422c75497f7c89a6a1cf72ebd560e79fe2df058b161f47cae903f00000000000000000000000000000000074789ede4d477511409676cf71383533bfb488e8be572d6d3e53ae571acd95ef3f18bcd22065a284adb31051dcb04381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d704e21957529816830777c9bfa8f197a355946aa63c14b6a50f1880dbb75de05875a6fa27c09db983de15242896a000000000000000000000000000000000138e2b0c0b632f9d01b3e7e721a471db48537447f71db2d280e3ecb36093a33ad6b1419066df052a7f79f5a4e4c89cac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f34cb14bd29d06bf511f952d92139477572532aeff6ff352c62039c678ffc7283fdbcbfc9588b60e22fcdea9e32456000000000000000000000000000000000e2b45add5640480b9dd65b480bd1135c3bd261c8c5bacc1183f7060488704ff197f5f4cd61742472b0aad7d7b46f7411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfe02f20edea3c7c81e0fb98df7e7389e59058a049aca367d129d5c88ec8cbb9cb441804a17ba411de7d197d599d7ec0000000000000000000000000000000002ab15d1704e69756804fd940f00fa1b37c1993de135e8e1a3c75149278a011df35a5b3bf1221833411d5b7004ee35bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137ed39fcba2df9734453e3884d21d17ac422bd9e72e5ae7b63c19fada2bd7e8ed9f97d100bbbf80f2b9d709b769c00a0000000000000000000000000000000018f1ee43e9f214f84b455a83eabe208fc2c772cdfd8e7bda8daa58ba422e2a9d71e8e3fa7de513ed3951729d7bd96c711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c86fe1fc28590fb919c6d814d83949c61270756014bd35542af957b023d8a7aebf4070e21ea74254d19ecc6edf481d000000000000000000000000000000000d4170246614c4a4ee4a4c523e3970b937bc33220746db20554ffad9aecb1b47e2a6dcf89929a0aaf173efce65a5296d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca1602c13be84e3e69c7f81c3df81e7624c623aa884ffad757c97791589d97936c934ad0c6f9707618d163e119b15c40000000000000000000000000000000005f8c9b9a6f1537b8583d3f36694925fa6ecb2c00d862c08c824c06d5c4e1da22df81ffb8bcdc02fe477a3dd86fe62861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c01c3f0e5e76c378774b215e665b082da9ed72ae3091b322881c041e070dc85d7f7f6e24cec4fb2ed7a689acccfe5d000000000000000000000000000000000ad1dd6c2658cd8b43a83bf2af17ee58d9c60c8f2de6b45132d7ebbe76c850bd3f535e9300eca124f953daca4d3c489d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000169d65d36c32cce1a664ad8110bbe36b0eb5c854d538774a2b70640b3f6122203bbc7af9e4f3989d693e2306d969ef5c0000000000000000000000000000000019be8bfc44f53ff818279cbe4bd24b7d5a647c7af3930141dc73296ac9fca84fed2b00622fa7717e48b34c5dbe9dfb7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b941dcc14117647b4d5ec0c663dcb70ef41e19e0aebe9ceeb97d72947d6c48c7b38fe623fdc6eed42d47d5e19117a74000000000000000000000000000000000d7bf395d86f6d3155c3b59a9d76fbd72b7cc321e60e758ed5f4399b23a51f8310186d62ccca1d59199734a628fc9b341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9154e91da2093749c99413d6fd7fce40afb38124ff87a841b7f0eb33abe7630b63dde7dfb91506cf295b1bc68a71c00000000000000000000000000000000001ebf1aec3365464c67cd2ba77b4a690b5d1be72541efacc09a86c141bb197d52e93f9cd6097a89881d8cd22321fb7bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011bc565564f6f465b6f7595d4f947a4e534927be7646319dd863733566d9ab8b101129a71b719b2bdea7fcd09423fcc1000000000000000000000000000000000285a69b286ce370b5d28067ebf270cf66c4df33d0d35461e709c4fe823a49830d91fd8812d00d045b6d3eacc3f912bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113b9404e290ab59d0057ffaee2899c49581712abab1340ee74c4c5b6facaf46dd683a0bbee068a6619409dfece5730e0000000000000000000000000000000008361232b18707a7727c024f0e83a66de8700b58e9d651211db104b1c045780de34bf9309164c8d5034c550b66d76b091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009940de312bcf7ff7ed282035e1dea1dd7123cd3e0e8f04c0dd9614b7226e3b8dabe4455a97caf5fff085419efe093400000000000000000000000000000000195d4837b010f1801766e0d673ac925f73610b71ddf0be6a7ecf7575bd7f8b111fe9833b3e110dd266cc1552f6a06fc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b828543577be9242347551bc6621349fc271043d3191a187930cdd941553ac6bbb263cae15c8630a14cbccc811dc4a0000000000000000000000000000000010b8e5ab94318fbf9973a6f8adc3065ddc7f6d3f0918d3eb6d71fc14470a6eb041f0b1cf370920414374dd7d4d8702971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001143833d136e1b3cb40bfa34331e9ac52533c8a64c7c3e7a3077f547c45108bf03df6bcc2a0322f431184e7460189e5000000000000000000000000000000000d11d8e052d49b4a52925a0038f593202dbfa879be63051aa8bc03e1c2f37367a34cfbbc4f5b7351e38adb7ebba36b981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013750414582e6fecd5b0a53389a44dc073970f445dd394056c3614f919be46a85bfa70d9156fa9b7ae7a3fe370af6f33000000000000000000000000000000000223df72c4c8d98619719912d01bcbab0f3bcd5f8955b1490aeafd4d8adbd882b18a8494dcd6bf16d418789f6c2a76e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120fa1e72db0c3f4fc7ed7c53c9fd77bf2b2ac89f1dd0c8af54adfa408f4a44fd16cb28346293dc599de045b8d4aae850000000000000000000000000000000017734cc479ee2515197fab9b3cdd4558ba7a304c4ef2495dfe935c7e54ae4e48101ad93b09b83ff404969150011e54b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001de602f8b09e9d47df893461e4db65c86f15d09b309a2399101704c42fbe65dbf3d640e52b571643f75d552f405e17b0000000000000000000000000000000009cf90af95a3cf5ca6e5cefb414fc923dd139eb1a815babd25057f0911bb0257267f73f31fa3e71ef5ace6583d9529b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000041cb05deeea4e41879a2340498c97d9c0aa459f9622943c6387a5e32e5b96ccbc3c335c369bdb7d7bf00da7d4b3d9e0000000000000000000000000000000012c92598b88864501ef55b8d9894a3bbf36c5a4ce12b6a9a7024f1f84ac0537a3662a375a2a28d4b723be60861e65a7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000784b8b2dcb771cd42e543557d98bae393d652e71a1619625dde33e86079cf216d32bed64ad6090a24c5aa1abac874a400000000000000000000000000000000026869ece7ea865928bd81064913eb2570d0569f06cf14f491d2856282928c2449f39e772a95e6205a9e2242ba5167581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009ec383fe0f68d41668093caf86f46d40454937ad29ceef6ceee0f3522a9f52f35fa08b2a7a741a1d8acfe5dcc1c6da0000000000000000000000000000000004be1cb08c81226fb4c7f32f086cf933ce5a4af615e657de68fba967c70dc50a3dc013d32095a187702ef9c9ec8fdd651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001601e253d663c01427194d309c2a311a885d4ad03b6f336433a4f5aa2cc0c0fe2c55933c497e19cbaa172132b25e8dda0000000000000000000000000000000004295f9fb86aea6e7c1bc26b9e5468c7fdd370924e903177f863373c19da19d7156f71acf61ca2027ca137b425c595801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d293a8e0633af32e2dc5c5ea444e6461cdfd6ce6faf50b991e31fc60af96d1f2b1e21289a8eccf2a02a9063c735e1c0000000000000000000000000000000015e7ccfb25b90abb4b2bf11bff4e08f430b519dd1e895e34ecbd879bed4914a3ebef8f19ac9048c5139cdbdf3055397b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cc614eb8c27fb9af064fdca8d5b4c90e6d719067cd86869cf0652a4cc037d69e2c7a8a684580843f73f0d81d1edff1000000000000000000000000000000000daaf6f172f31d801c87a623786487db9e2929d8701c7e212fdf997dae785b9bb4b9d5321d99a341773f9c07dc08db031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a6001714bfb5147b1b1152e0f701147101686970779037fbeaaeb0ecef8a0033b09619d76cb8e6ed42f72c0d179cf30000000000000000000000000000000007138e0874f0af15535481860a784ea17606056e030532f8d39190a18ab4e9f4da3248912f656a8ffdbd30b7b142329d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188b57e18bac0ca210a48199567b99af637afda70b9ca8d523bff6fdfd401e0ba139f47d1df2464f850080b07e08f26d0000000000000000000000000000000003d4f64caf21182766a81efc1e0d90dbb49836f9e3fe6798d3c3e6d36b4b147f3ebc5c8180be356024526427abd2c0c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c421117f5ceba5d854f4f614172e16aaeb5e3553f1cc0daf6c0eeaeb7946da146bc8641710d701ecde71c0374733b800000000000000000000000000000000166c20ce406a615fab1f7866ae2bf771563c4468441d9cc0db941a1131a37f4eb25e7b158d66f790069120f0e49d5e1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f369fcfb0b9c79d581b05364869b9a43f23aabbd969c37f148b14a924c560f3a7e79edef244d5350cd3378f9f2ed52700000000000000000000000000000000179c661350bc05d4ebe4406ec2ea5c9bf3f51e8140931b9b6a6b5d78d0ad08fb51a478b57ebce35550a7c2c9948965d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb091ca17c67e4320c285dc856703ef4b1db833f4e6e367110265decb53efeba8b3b1ff4ae96fe8c17f62bb977c67d500000000000000000000000000000000065e5f1f40da76caa9ed568e4c2445acf4f18eb72c653eb3850df8602b1c805c19887c9cc8d482bfb1dcca97a7a7e1d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c7858ae8e362f80d06370212027cae6f2843022041ae296640677672f9bb4760d70dc53ee7dac9937d65173b7aeeab0000000000000000000000000000000019f5f0f75e4fbcab50a030038837dad3f72574ec117ab4fdd0b63599a6982b7d4b41aeeb14a3c23e8d0052498b16cd011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145e2c82b834d2cfa4307c57434646a418068ccc68ae2f2eae21f3c6c0501d798b6a90fd891b1b9403501df7c0deb2ef000000000000000000000000000000000fa49a30f76b510136f654154fa06bc35f9b4a7048cc5d407d175cb0902002d8a0a92cd2e77e1a938910625d4326c0c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013988a56a09788ef8d402926f14e11f21dcfefb0247303a9058ead03e68c9683dd24abe0c273907b841e6dbece0a6464000000000000000000000000000000000d26709a6e022caf725febc3c8139278bbfc9f995ce2b93612eda7426c815900fc3a0113505a89d522859bd817a40d501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000600e2e8afb23565d2fd50ce70012d21714aad68ea82f221519502ad4b1b0fe8e536c039a0fa121a9e27c695dbb4a3b90000000000000000000000000000000014819c937b51d0af7a8875536faa6a8e790c60b0ca9bdbc7dead2e882238142a7794c3382bb73d02d547bb74c52298d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199683539ad2d7c34963b7c74242045acbf28172b87d05011e86fb748521fe84b36bae7277b52b1561aa3e6be4be637c00000000000000000000000000000000098ef38b1fd6f047a86f544177473860ca147b48bcec653421828a16a9d98e27ec4c0f104d9413d2820211b96b6c74251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000424a335ddba0dcf0a736f8154177ad87dd133a65544d047a1e7c14c91fe75bb7255fb65d00e78d4799391284f3bcab90000000000000000000000000000000011a32aca62cda6bf5fd47520d52b6c7928418f0fce747825d3d9a0a7456e3df4e14c61474d9632a98547a0254ed25e831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001238e79aeb6636d43aee04aa67fb7d04ee65da479f92395225720dce1e5197fc2eec954faea5eb8de7302e207df9209a000000000000000000000000000000001858a4ab878fe4f081d7d32847bcd0f8590fdc7be6f756158c71ae6aff662072fbb8af6d5a78b3ccceab8d83bfcc591c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ad5cb907a8f6670b25fc0138ecc9093630e9ac3820042f9e3662c43db53a0acb2762482045ac030a7422424fe9b4170000000000000000000000000000000005c3dee62de9bb92936a00e066ab76456e9d3c35226eae4f14c25d7faf8b6dd3428a5776a3da21fd943887dfad2291561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f6280f0a614598480b4074594d6ffdb57985277b2d79baa01712930f64c5028e5c5a288a60a3d03c75e0a8bfa4b32b0000000000000000000000000000000013daf3e4ec5fe1595152ad31cf5a5de9c5ca4a7c7b7c18c9f46fc56fce68fbba14cea302f97b9dc118710399efc133921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ad1e54aa9ea5fc576a74bd71622bd200354455f73a84041530590453cc2c3b1836d600420812d441879c5b44fee65800000000000000000000000000000000097ba0d583ffbab156783943e86d23972b49bc839dc9d2bdab4e29741f0cec51b584ddb8978e3fc8c5881cc5c04a84031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba786b0e864e382afcf2a2d902ec818b7cb4632069afabbaa2434cbf1d52feac99784350fd32628462705778b04e7f20000000000000000000000000000000017368ad3c1cc0e8ad79956403c1c756bfef99ae7d10e3ec17b774fc9c5db90b3ce1a2dbd48c5817c45c12e1773659a9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173393717405fa8a11896c9325cb8e7afd270fd4ace6507ad2f03d449b5afa226cc8db5fa24679eae2124c67699360630000000000000000000000000000000005ec55dd33152794f2bb99c0c3100e41c90f18e6c1de9e750a6c0729f51a9f2a6435bbe14615a5cae8a72b2391e18eef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005b5be17463267787223e0855d15946d262d5f14c36e636289f2f45aa581f89a3964f9f4e27ed673f6ac45c4e922f8d70000000000000000000000000000000006a1e21de777f6fe1e4d6947a48c15c23ff66b69315bc7055d442bcd7a9e002eea21fb09d53c6a5c32ac8f6f454c985c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044faafcf404c7e3890925eef240919b668891fba385765d66a72aa25b9788fc66af2160ebfc4d7b9a18fa99bbb22280000000000000000000000000000000000c44efac6f1e32dff6809d563a389ad041997daec740af25a70c1936ebbf3fccc185c6b117aa778b24bde67f318ff6911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001902810d7fbfca99008d86142511d3cbea0d68d8a5595ce9d7d4b57b9a224c70c12e4f8b06c75a84f7694619ca36238200000000000000000000000000000000075a69a11fcbdcb083e88044fc7b0f0f997454b92517feeb6dedeaed1c6a00bc88d2931a5a59daf1ea42d03a9923d1c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b35b6023befb075c9bfd4c0a7bedd6abc49dde537afe62a1daa6d90113149bf6ddc9bde129e6d7be8f95652d15f4ba1000000000000000000000000000000001196593a29fa3a10134307ea4334b9a04457466617bbf83a4aef71afea937d668177395068a36a9a06623376841412f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc3fe05ade32c478946ade2fb9f8130feddf6a0036c820795242e37ec588a7dd59e82c96114875414be86e672dcba110000000000000000000000000000000003e78f6bb2a353fb48c95c0e5dfb44e3862f2fc7af25b51e202327cd20c8fea1a6ee00c8713b6f2e761dd35e94e6b82b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2e1589176e4d9d18777e3df6d3c8e08210c6ca96fbb8dc6060ec3c5f2e360f922343ad2e0f8e3cd1919990f343258f00000000000000000000000000000000161ea4389e89f80b8193f411a6e223091c2b1ff90b2d9093b0a4e02bf3d829663db94aab7e02f972c55c5c639b1f7d021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0036a5674bd0d796990eb8f10e7d4bf4190864228d93f981b4f0aad29d9f3d1ef3343d7479f31fba4cc8f045959ec70000000000000000000000000000000007a4d3fe27bf5dc98f8c9a66b30562c6ad5cf0619c14f869e0c7a2cc26843eec5d87dd2d6e211d893f2919c6c1e74d7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178751924e460a4c4d7c07c6b2dab58c0d997dca3eba51041a7bf196269509af14018d3e15a0ed3b96b977a435eb8d4a0000000000000000000000000000000011ac437acd31f2a5d38a665d15550d4087ea62ab987c8f332b40c4e8bcb5ad44b0de6aaed228880a6d692176a88adb0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000087d58abbfdffc77a46569262c746ec91c4b03399b7d9e8ab043375cdff0f6373fcafdf84e1bd6098917c3fe9e12d2610000000000000000000000000000000017e332732034531da2f39ca9744c4616ebccdc3b7c6be2b6ab0ca7a108fa6d0f0b3f51c4dc0dc69c868b8959c9e12c641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c01d508f330fb3e4c9aad4bb0aa45fea1c8d833886010005ac65f028e09705f39c5d712e97d42e922afe68ec9227cbc0000000000000000000000000000000007609e0e7f664b083e96febc8b52af7ce330f3d0591778aa574b38d330c1fb113338d310435ae8a215488589e03d67a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015133a6c5b8becfd8b13ffc85b96b132a7b3182cccd710573b91abf8c92031665897345cb60baa10de673e42349218e90000000000000000000000000000000000e5ffb24009889a6c66c40e49e85fd210aa44c56b94542f9286279a383f12a75b31ee9542c0afb02d37e33046451fe11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000865f597728f754b931b4d262c98460181bc9201f488b72efe6a7fad2b7eda99341e771fbb45b606b2856db8f61d0a1f0000000000000000000000000000000005f25ad127044c72cf6bc9e2926c96f68dabd9dcf0a8ed96097de04bbe8401e0430f02ff2a81b2b1cf69891d29cde7e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000557dd5508da0d6024fed5892e439987388ea82015c7606c3b330be485ba0b7d838b077d482b51e32135160781964a8e00000000000000000000000000000000195b89cc39d65d4294ac46fa2e8b7eba0a0c2d1a74b70e83e15e0381407d7fccfd512182247f5d87daa9ca38f008cd381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011274b2bb04b713a0d4705bba63e2fafdb219166e985dd77896095268f5f7f5a27df1376af47f664011b3994ffa6ea6f000000000000000000000000000000001688a6f821056a3011313b44c0c1c30beb01bcbc58677ef926ba658581aabdd4584673cc2c59560b711031c84bc8bb531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b98870af3e92b92101c21f56fba66bcc75f3665983938736f417c9827db1802b4858d1362d1f8dcd796cfc5baf18be0000000000000000000000000000000009609130c9e299ccbf0c0aa37e2d2a6d6457fcad697eb35f34d1383ab79cc51e9040e5050671ee6b7234ba48bb4086691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e29224ff1227a2319cb893060365c78326396256b979ed77035ff112290c119e29a19b21b52d0df34d5a2bd4811a0600000000000000000000000000000000008c8caad76963e7ba7d15b1e60bb1a6cc9f2ccebf9299daa947d3808a52d93f4523a238b5ecc50cdf7b954544e32dcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022c8ebe8ba1e43eac1a0cc24d1341241e514f976d05683942f213809e6494a124599f2837b0e9f67cea1a2de8223c460000000000000000000000000000000001b6cac2d4bdf9dada0ae6567eef08b19c7319bd7d76fd6321a59f5a42f20893a75791159eb9bd42f1ca490ae9300b1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e86fa869b27771e6dd5f6ab81b12f290696e760d52dac9cd4050ee26040d0179ac0b18e8eddac37cdb411f1023f77d90000000000000000000000000000000005b8ec54ce2816889fda281ffed0f81a99808f23c578b777a4b5e0a915aec1f8a1b643ef5a5634ea025b83e3a957c9f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112095af9c55ec5423fe2186f80a29bfd3c5cb72d405d7adba1ab8bc6327ee8f28b73298095b7c118c5327db6a48b0f6000000000000000000000000000000000fd45756f1de446bc751fadd2db191177f390ffc9139a3ac71f5dc5e4698dbc21f8406b0161bd8636c4be2cc85ccef121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ce186ebdd55f6ee63427eea55a7e77bf0d2c02d9037c5b20d0b9b87ad24612359366c9f01ceeca1721c84fe34ee2e300000000000000000000000000000000037e2525373e198b28d389ca5236f361a8c88d9ba41ac7f0347cadb6a3b202d8574e2d23562046c4faca8dee5ad964061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012af791919fe5ecdc2e9c29edb3c895114508324eecd3fe0eba717730e3b6b2582e5055dc0a49afde3826abaf1ff9ab20000000000000000000000000000000012fb10b6ad4cf5e50e04763a71cd8642b761ff18eecb74c031607535777cdfa77dacc6d2b565d4b42adea935ae1b226a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001944c2bdb35063a045b5141e652fe102e6dfd8b86afac8fcf3c7f9d8305909bbccb644ddff0e6647f6c543dac45a32660000000000000000000000000000000000e75b7c25d3a3785bfedb1a0a978e57b92087d213101c352315d6d8b6420a3eafd2d05d1dd7fd70c2a9405214585cc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c4fea0c2570d05f7bfc1fa955cb16699a7a08797870c43f3569a41050858e2968d0dd259cae010744771446d55c150000000000000000000000000000000000ac8c11729008232195350eea6e604a594abcfb9d4efc0ffccbb39862e8aae57fe1e2aec9a4faf035629d818f0897e1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001432b595e90a783398b918a4edf2a7874e825ae621f5fe6923d38c6e1711a17138f3dac96d6787b5dfd2ef3d9af831a3000000000000000000000000000000000b8adeb7b9e46f292461db8ea4da0a6e548d7f57a2cd7601d97a959be138d21108e5f71da7baae98f3fae6167373d7411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b04495b9765cf4479ec1c48f9c2f59f8d568860838a5e06d9a234e41c565e8e254cc7795f049ab8b88703bbbae5198000000000000000000000000000000001026ecc5eea22e8a0468d258847835dffc12842e3b1802b65745ad043c4368e26e2a5e51178ad60db3604c57ec9393691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007eedaeae6295531b6b9c3de66a54a7e98f5fe4a6d0044adb4869d1b896e64d69390344420af491eb8447f4b7fcf1c8000000000000000000000000000000000ea40892c6e23a4f2b3bcdee4ee64531456d15c37b60e17ec32319b742eeb113511246112ae6f6b25f59d965223b66f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192b314507f254ea7bba02a98143f5ca7701dbfdf091095b016a6a7377dbf3fe0ba2f1d5b941a47e86782cbfe20e79d5000000000000000000000000000000000b0568164f38bd8350c65f1fa6a39b20fc4ae73d1eabf25060a31640e30445c82ad98443082fc2ac909c9364a04324681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001644242da17651c7cbd5eaac89222bc82c75a3df2b40902460573b7f2aad2f1ca2700d86a7b7dfff411a7f0563c643530000000000000000000000000000000019f9bc9f901762d658d9bfe53f0c617e4d37b4e22906254bd262a567f5a3b8eee5d5150eba74fd0b70dcd32ad9c3bfdd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e1535ac548b33ded6cc26be524ae7892b065dc4e5369f0c9f2cd982c6a08a486d14ec540ecf7599127734daff2566700000000000000000000000000000000030e455f011ae5f47c6e49b51ad629a67e521e07bbd97cb8a870db4a02e14d818375a30e8bdeedc06c556bee97381f311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000587378f429f92641d46381881247c5205f165baf9ac9b7dd7a7b80b698532b4b5cc9edc4f2e7cf4fbc21b5a5e049e5500000000000000000000000000000000004381d30959d87cb2af3dc8a10b660adf58271c307aad22d3c9f69026e457f5f7f4dd52dfee3b99d82de7da483bcdf71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000934ef5ce9bc7f8bac10a7e80ba1b2e5450d0a6e168515c426e56c9c29fa3697f425800e0f34adcad9af7222bf5668d00000000000000000000000000000000011df5cbc583e28ca10d7317a7ffffb1d466245735fe0d54fbe6c816e47536a0d27310d1fdabe89db0ad73ecf36b2f6801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178977a4188dcf62995efeef158e45c2a5f2ee6898a25a3509d0a10e11a74da51897065da34464fa3426707d0b9b5736000000000000000000000000000000001887d9d7b139fe689687fd330884f88fa97c3d8f5b4f249bcccc9ebda6af417ab0587ef7e704ab829110cb4f59f718481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a29b9eb38e1302cd0a264021edf027d1426c1d9b1159014c1a11f0c45ad9592072132fcdc73efc3923a73f58d8519c00000000000000000000000000000000165c6b26965a3e5d0a01c47c459b133174ecd9a9e7e8e6bc154a3b2250975e3fb7bfc537704636b939d00d9d473dca631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d5f1145d783d10e60cdf1287341a8a2838d5c8a798fdc90cd9b4910c6da4e237aa5142dc2840fd158a57899a14a6b40000000000000000000000000000000001b2e1daaf9853f7b880377a29567b778d3d4200c6227d171c54c4196359baafcaf5e8d20a79993fa8ebf5473726768a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f56aabbc86322c2683de66ce3778e6e15c3e95ec34a75cbc72aa0dd9f42a7771fafb4d81b9c7e82306feb5a7496c9d3000000000000000000000000000000000200f7c472a699844177439fd274eb80dd5d7642c4c59d5a04cf77f585f8d7689d84fcecdd1ead1291ed535080e268e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133493bfbadf2b95f1dd8bf263e25651c0f10a7f442ecffc5ec905739c2999d7e4714fc71f63170f8cd4fc3ed4160ce10000000000000000000000000000000019397e5fc4d40418fd991ec5d82d469b5133d3f5c63084e6c36d621478e5c05b0afa4e0890892ef8baffb743d8c7abb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164532b0adb51b97cd8c46e4602a153a72057ca5fde11e82428f1c7a32f00c27f14605e6b5f1d58248ce7e5f771528d70000000000000000000000000000000018270ce81d72cb32557b77fd7566f68cd152612b80325bcb82e94aa301e867da3666245b6affdf6d8aa3694933edba691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac6654fad1a9cb850a999c5ba5c303efd3416db092cb8ca260d7e15b1cc76250c884f3fd4d496b7559bb98c0b5b0fac0000000000000000000000000000000003f7bbe509a39a8e73a10286a7d5c520c80588875f562523af1aee9de9f4b0902df29d28d1bd20adcdc2f2479da49c731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000709656752447787f2513541f3c1e147fd9df83893c448719d44af9fc0cd7397ea84c851b899e81e32894485445268c1000000000000000000000000000000000d4a25806f432f56e85791c3e082de11be5c75754a781b9c2c126643cb5a7f5ee77c6749fce1c0e7dfd628251b5f179f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9c12164084e2633a083b0ff4d2f69718fa141852b2bea1ff56bb90baed017e73fd4806ee684a69a872dd102685a5cf0000000000000000000000000000000004c6c6f5b204e02946b0c1deefb4301015a3002cf9c0394d4b09da2f034d3caf781aa99c854bea61b10f7874fc4bcacc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156adbb584bee59620251323f9c2697b9f9b6d527a85339c0781078154ac893f060739f03702334ce6bd4be18f135ee60000000000000000000000000000000011960659ca49c3371264da7a4ccbd67969ca5278ee0a5c24af47e11e761b4444f84546b800f566f0924d25bc6621b9791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b720f853dc92da487ca06d48eb48d0cf0826da51464d75d4f9faf38c18dd39e3d5b01d2717920e3df13e4044c1bc21e0000000000000000000000000000000000e6c8ce7b0df94afad12a600166998c61b40e42e049dd600189aa4945345879eaae059850b71a63e239972fb8b3ed9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf8a0f9979d96edfdc6f7e7caf64b8611427d4c7c7eb4b350a86d2d92ab2de914d924f81bd5ceb0855b77baa3c8d2a60000000000000000000000000000000011cd82d3b5e7e30f39aee829cb4f29e7d2edc199c123278e1df46236e0ba7dbad9391156e752bae633514f865f3426231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061ef6fc23899be1f5843f8f60f203e5a0ebe2f1d323cc73dc16ce7243e98d105d8963aac0eaa3a0daac587f4ed8ec8e000000000000000000000000000000000422418de2168fea3837fc30a4d9c5ecee3a57892de6b360a1ecae6e23e41a25e6246968e8fbfe4317181ce6d13c22701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ec41bc0d0cd1bef5047b042192f75be67e3bc3fb779ee7539e9d9fdb48933e001b58632d0a16fc3f8591333d5085c3000000000000000000000000000000000106c4c3cdeac0dba701dd10676f51b9a0803f8146591d1facd118fd25a02ca35ee7dd2b7db9eab0163316fcd59335911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a71f669f37b3497cde82ecbf0811d5f53c4f3add8e4e4355c40237ecd40689ed21e50b6789b99f00f25843ab47f0706000000000000000000000000000000000c52d4d797a5b212323b262d429144ed1b04e26622ed74d75a4700d1a34ef2f8da51016b1a6ba28a978b65ea6e8214bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009161754ae54a4be331b1b35f38e30f3841c9c60ec10a67e43b8510143a70b225328453c511b48afc9dfdef1438cedd90000000000000000000000000000000017c1dc337da61b16978356f24c1215adbfb9fa249500202aaabfa7840c6d265b37fc5045feb3b125c3a0afea8248c0381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002653c587522fbbee9c7f969bba1f6a0a7f3329108e8e431f68751570d63ee6f3e111274ad1e4a5f79ff7f8e72d86c0f0000000000000000000000000000000003636bb66d97b490ba6c02c505803ee6f5bd2e216ae048cba7098192008e68209a67c077e2d0a962ca911f2c897ba67b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b61a8a9134805b78cab9c17bfcd07479fa108cdfe3edeaa8b46b9a287fa747b323943a736c53bc80d405f003caac980000000000000000000000000000000004db63c3ee6e1f942ed62d234f0f5e917ed6ac3c903b96ee9d071ee07a8d767754dae1d40b473935f6c6175b2c552cc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001558387f4c9bb9f5224eb8ddd68ec26ac133d2df08e6d81a0c1878f2ad7a9cecc57a7d99ffb0f8dd65ffe3509df5d8d0000000000000000000000000000000000870603a38bbc2454577edcdd742cc884421164468c6bc6024e471ea698df47d2677b8bda3b95df24f64ac86769c15ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8071c35389d02ebab67b4ddb81e4befd28970c9227a06b7cbfdad4257008bc3fb4f11fc56b7c06ef67e59bbb293609000000000000000000000000000000000c08914cc823559d749654260381ce2a34476cebdaf707aa17209861da7702dc00f10d440efe4e53d31b2bcb56f679041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194b16efde683c06a8fccdd5abe2059b07e216572d6397e6e8b7292616a86dcbf3a28260b1d7b49459dcaa4a437d12d700000000000000000000000000000000036e686593eebeeed81c0138ea51733ef22f6c282ab058ae4e7b534b8af124ae428ddb6b0a71b32835cff320974409b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121e343a8421ca45549ccaf3a674648b45bcd24ee297f91f3945f62a6b30d8fbe85b3bc9b290fb06d3ba9d7db566789600000000000000000000000000000000050949833c055605b8783e26cef0072d112490624bc3ba7fbbc3dab486aaa413d1e2bf00cd2c788412ff41b9496218691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014ce9fbced65a4a0ce7b86d75afce01ced0700d126cc3b740d7055419689acfb700142a492b3ad1e236797ae77b5558000000000000000000000000000000000cec0f90a956cf122d8dd64d1e09ac0927c35a6a3fb4f2f92c4bc835996d60a7f294d410ad90ddac90ea30ac491242411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001473fe10a4b7e2e1b7a8c083553eb3aabe4219e9819c6e08240e342f1c95d0a29c5090948024ec6a77435ea474b0f6b000000000000000000000000000000000e77bf2e6fc185970603c29a0464c8c938f165efd244fd4f450686589337b9e9f0a1c92ca73ac8ecb33679e89dc585881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d49c6900df36a63910ab835c7de14a841267c468c9482141cf2a3e79b339f2b7c3298f759504e11be23bf10b326435c0000000000000000000000000000000009fb36cc0f5d4803737aa198cd7f657ff9635f56076fc25ed18b3dcbe35519d92cfbc6c8bbe54f2b452fecc9c756e2f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b44e4d5da0d8ae286a3aa6a6155ec436c3ac63147687a60dffe88a1a762ba9fd753c73b111fba14c16746484ab79ea000000000000000000000000000000000a92a5d031e0b8075319fa5c3200c5d2f766aa960f4f61d85baeba65a5d17d7b4b02991b8759b958d63fefcaa005f03f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a724478556e65eb32bab3a520422a843ff9309d26fbd601cd23b078521fe4b561cc13a8a4e9752a1e9789488dbee150000000000000000000000000000000014081b1b0dce399df8bde059f7fe67879c1126e9ae063e7e226766260b30ba59549622c4a8e6e20df85b053f8a84acae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f51dc11a317ceaece075a62da25f0f4f029d7449540207213a8d5841b7a57f41f92f0bd9d798a005ad3aa0fb4ed050000000000000000000000000000000000379332973464fc62b26cb05297a4a0733b79755cd775c51677fe69eaa5bc1fe957fa4579a20dec17cb2307f082286bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000575e748867692f6286163b257e64e28b46bd5af2cfd268143711b445e80b23fb5931694396cc5615958b3b44bf489a30000000000000000000000000000000019971075321b105447e71996faea681e441cc2e529a52c852945a62c99f0d92cba674a1f70587b8c755467fab72fd5b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017668cde6fe168fe1b38d1af57284893cdbd9c06372715676b5826478188c83cec280d6937c3f470b680cf31b96d370900000000000000000000000000000000034392441a6b0acbf6b11e035ee0f7ed950d84aaa361424f52956bb9781e362f48ae6b596db46d0b3e539e24a722ba121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee31409f46f48a480bea1eacbd0f5a6d3cd748415bbd42406a0cc77090c32f30c5e2cf1fb6b2fe2b6d7b09dfa35ecf000000000000000000000000000000000024cac75bfe6c5b6edd76e2cbb885780410a43ec8be9295a1bbe30fb90f41dc0823316a8b91c8b239ad0de8ceeadc1961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147dc460a6b1ec8f82d9156accb418e0410948f6b22c6332a2ed9a562f6feb0967ef261c5d8cd4351141acbfbf26b6d50000000000000000000000000000000013003c7e5ce47db3dc4d6be2b688e51931f0c4b3ab314743ae56ba7ec2e4288b96a846353f3542701d82b90dd32c9fb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163070f474f08599608aa6367c5d9c736f2842d995b408387f9fe25fd0c142e6182dbc50dbba556f25843ec5bb83ffa50000000000000000000000000000000000840c7bd5918b3fe7360d191ee178feeee71f7e8d13bce81025f00641cbd4639ff55558587f40f97ce11417157775801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e84e3a74dbb55b995aaeafabd9043c33c54c769b1f520763d2a8c889715a183f575de90d9ad00ac389dc5996c7466cf0000000000000000000000000000000014c6666c7241e3b95ca489cc435f8cfb658be370d5893a514d797d690f303b9ed96255419eac3402a889bfbc2e75589b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005dadd2862ddec6c23a89b6c0429d292a8ebd5eb9b0add5b1513e6cf0b599f9063cd0bbac2b30c4fcb349b65fa097880000000000000000000000000000000006d9e0416107ac597b36caad37999de8b878f0a310417921832cd61f0fb0bc530fec3b1e858be756021f307ade91a5931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a30491776ff6465e75d9f89a1122ffb0f9ad8b1c9505a239016d3f06e108afb8586899fbf25cbf18ec6e1318c8446e30000000000000000000000000000000010fcf81eb321ed6b930f7631bccddf16d3fbacef02a3803db5d3abb91685c0258f6ede867bb2ae29199ffed7777422311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1af6ade8c405c8f509b7828a754880791d9ddf4322b963c5809620ca1a8ade8863f4c432e379d8b9a80fcce4925a1e000000000000000000000000000000000c6638c39623036eedfd3a9ee1c6f4a2c1a6b62d70f71c59fba40edeeacd595969353baa8066c20de04c44a70c29a3841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009357270bf46560cef42dbd251686a7211dd1927b87f57519fbd06f902d282b9cf3fb0ded9e3cd4cb602c236b065f77f000000000000000000000000000000000b83bff22f3b795f025fe78ac7ff1a2db600c7e64fcc01a0684ffbf314c8685e937f49f00a38bac4ae16069dac5e0bbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091356e68e8f754a1f72b1749b38b4545ca9ef8d6e06e8df6be16800d87481caeeea3c68dc75271ae866e5b4ab4a5642000000000000000000000000000000000d292422226d39d78ebc8d326a0406ac1cdb415619feb8754afd7bb31397f945d418f18077459a32807dd5f492f7d13c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000680ba8f899e5c96cf0964383153a96e523e2d97a2510072184e2b99a4ad70fe95ec0bb84798c68fd7f6238eb32187ff0000000000000000000000000000000004c52a429750a71c784bbf0513dd98cd45729aa24a55cf21b168e5a3197cb47c0a5c313c66bc3ff6c4da1af75bd1b1c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008df700a7348debaaeb2d1adafeccf07687f0a46c6aa54365f20e959933c9b535fdb190c7384cdf0059a589f704e1eb70000000000000000000000000000000003974849274f1f56f4a8b2e9ecb7f0087725708f470f840d287813b45463a71366d04d2f157c0bdc5963d1beb0a983251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013055a2cd6e48a80e859801518ed959c7f22a16f1cfda4840c08b6291406e5659d9afd5fc4e66b6750e034a4d1132fa000000000000000000000000000000000fe1f227e8141099a8370a88cc3649857f10d06f5a5ea77b39b401ab96911bfa360967592e6660dde6bf9db838a649411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b097ab40a90baefb6d09fe9a9ca66f170499570c9c76bd8dad56bd923112304b45dbe755a9a334ccb3f2dae7de617c0000000000000000000000000000000007a8cce5344f8b211088e50148cd2f0d359102bf3689e398b2bc1115a96626859262bfdebdde6875db4066adb38ffd961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152312f40868cfaa1803d17ae446f31cc2e2f3e8fd6c6bc529ec2c2b24671f38d94e2df98ceb0fd9787e7010895412c100000000000000000000000000000000124b8fe0e4bb4a2379451ece4c29d72811f1e3f70d1d51af4baff5de42423be1bde91cb409c2de019bedb77978a3d57a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5c6892fabf1ea76b416613789579e5a6caedd20ec486d7afc4fc84eafc080c981314d0f30f6855dce1b1bdb4d0ee0a000000000000000000000000000000000dae57a87386b0870089398d8f1faea4038b51cfb9cfba68254521a54893bc86b353eb3043893a4df90a5788f909175a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000115e0044af94fc3a9e9e2404c36f86ea140515eee337a847af8eebd884c243b069fedbcf1440c0dd5c2a9cf0cee9d01a000000000000000000000000000000000df60cd5ac4df3f20a03b29168b28ecdc3d18a85e69800ef3e26e48a9d579a5602b8cb1b45ae668465e8ec022dd684931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3dfd50ccfb89d620be5c275e0e2e110f1d23f85e0300f5286a1c0a0224feae11419834941ad40e8ee6891083d2495d0000000000000000000000000000000003814aa2439b63646f2262752d0b5c928532af07f1ac76418fb0f93a80b95087342df42f359cbe168b3d04b0e258ef761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013bf8c18eeca8a1a25747cd39eee9c2e83c37ab1e95ff357424e070688c9e3cc4529e9ae66bfdcfedfdb291eebdf3bdc0000000000000000000000000000000012f1992f566011b31eb932ae4a9264727de154dbacf579ba78bf148f4007b13bcf80ff188e867499e3e699981d90cc971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001492efc24fdccbee87adc55e26276efca68fe995408b50dd48513c0486896248635024da4cfc215fecbb7b019b80654c00000000000000000000000000000000065d232c192fbf5b3d548232322983f079aa3c78b41d74fa4b00b9fb0adbaa2b91bd4732a1b74d813173aa4a6ecc87d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019971562f441c69984518778bc064ffd51b12804b1fb434d138ed1fbc99e935e248de40995a4b0378d702b1739201a25000000000000000000000000000000000bb8d24a48d522da40b7ea26b6a790c66e42d98eeb1edee4485d273ef7fde731012799964f7e618bfffcf7f977a0a9921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094d794e7d42b85954a6c0377b53fc53d84b0b62d32ccac4b74bb25b18859cc39395b0464fba4b35a7470c9c2f446cef0000000000000000000000000000000006db2504333d4de2f3a4f0457a3260c57e8f47e8c5dbf29e957cb5eb1daf025495d11acf1265a10c6f5b1a82114dccef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008912d140625889210d4d72edd0a4bb46c1645b60e590a80bc78ebf199b64c5147ed3363a855593ed6b1b5959639e5bf000000000000000000000000000000000545dc5a2c4eeee79c00869e5f53f4ba87af9badbf7234f2cf8449f9a125da72515df437efa261d629009d27822969211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085a57e68732ad2c8466e7267bd9b793278865e98df1dd65ee19a774d60224e709033977fa2ad4756007cce7016230f1000000000000000000000000000000000c544802c42028979f2cbecd9325cfcebc3f4d54792c09f9539d2b4a9f5df8b4f9631ce7ba2a6faab75a451f67cdcb861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e3f4d577cb731d7d620916971bcc310417b8a2d1b9bf3fdb387d161d722f495b5fa558a99bf4888c30d0ed7cbadbd9000000000000000000000000000000000b03dac7fc647ff3aa8081d520ca5100511637c6440d3011ffc5a40bdfb85b44bd257f5f0a0af2184c668e76ffefc3af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c2dcc955d3d5dcbae3c50621561afdb27a146b5f761e2d31a2415f320f168da260f1c971a84ca06c34768888f87b850000000000000000000000000000000006ce6f027052a8f3e65e5a72d671a404269d4ddd413a4e02f3f7efeaa6be324528fd6d159d4a4ca62b1aed89ad39e3c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185a9c80cabf0e987010638b5a6733c7418cef664d5671b0b5f5dbbcc84c988ab8356dcabe7c83e52d941d79130b6c1a000000000000000000000000000000000b0dc84a67177e72879e3a8685cb089971624b0343479418cb06f11c66dd2b46eddb5fc52d286d3d8da869bf9b0553461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b9a44a6231e23397a7f926240a6ff6fbe25411eae71b5ff9394b7c41db03decdf75f900ba8078834cb48bb7f38f0c60000000000000000000000000000000014e4a60dc0f81d9134a1e5a80c4abe82d6a73076a341566caa844be47816243475b0dcc5d7e43e6e427321ca884f0fb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098313a197b57ea3afc8e0c991440c050bc4742624ac528f2dc80c36afc646be75fc5b943211ad48387b8c4bae6ebf7500000000000000000000000000000000119987d5698b783dd6c81e564c36f312bc552f76977356e3c27d6d8fdde8a79cc12e88696ca7831727ddeef65b7f9bfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d994253ddafa13ecacab8a4a60bdbd6a445920f96da4518b89019a1b7a242eca83a673ef97088c944e2f94ff85c16500000000000000000000000000000000192b0d826819977548f97aa59d3d3f97e75dd73712cc9a77b0f8d38469b2e9697301e7d381a5c40a7bf3273b51a988eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197c3a1006bb9c747bd3ebd657d97eda34856af5ead590fed4f655424bd0b39d7bcb6ac4bec898b581711356ab91ee7900000000000000000000000000000000081a0caf40a8f723f9d1e69a541e58807c66af59a42ea5625790cc7fda9c6a9568608b0f0e404e05d6af88ee8812df8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019159a8197dbf4d68f4ecca1a51339c30c76798de00c1ea1e78e9fee9415bea2741dcc0b44a0e377ff9edc41cb47f9b1000000000000000000000000000000000124d14efb3048190fe2c7e0117830952fda684db1f9f027a801ca400346e5cd75d1f43bd6a586bb2afeca32b9fba2f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e804f3584e185bcb1b6c49ac1800f26c6459dd14430d773cee116332f74a6717e6eb58e8ff5e9db70430eda3cf0ca59000000000000000000000000000000000c955146a036d7791b80c01fdcf524abc91ccf722ffc76217c3e63c19d7aab931ec4149c14bad7836343809bc908be4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d00097ca449952baf50f345c013e854a956e7896ff7c31083611a921d01514373afdcfa17f450e409dcef2db52327dc0000000000000000000000000000000009b9e867d632d915f3bd2f2d6b315160976224061dabb99e5f0c911c9a001c4d7f53c66150cf1c5607f61931f82e57c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a3ea15b2d73fbb72c7052cac17d81046f2a46b3e433e1afad0f1be1698a2b49811a62652bf24dac4f32f7b04d009ed000000000000000000000000000000000d6ca10860f5eadd005866c3e0ad07a3c277f72c961cbbe64bb613f47adb7567dec6d7f4f66e13d6efec45971b101fce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003deb30db62b796cd64c4aae532c86c12fcaa3e89713df3683d80535f2fcf18fceb4e982de48043aecdc364b4b487a320000000000000000000000000000000011dff25380dfc3d50ae24b93cbcfe1266fb62560e7e10bed612973b8170bf1d07c9140130aba82c7e6a9d641c605d9db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019aebb4cfd5d3db15403a280ec6e0e55e430857e2b29af764a6ecc82be172432f27ebe6d0f5a2f8c8209ff484953589000000000000000000000000000000000180e29868aebd114f703c6ff8dda3a4fa9e58a0c0b7b54bd599f9e691384b20ae73e2e953529e27031b615c959e3e86f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fbce672b1ca155f5b0c6bbc7edf76f60463cc96887428c22589db05d3bbf337d48026ab323670201f8e9f8bf2a8d1ce000000000000000000000000000000000aedade057e01bdb05ac53650a8ebbd3ca536a5271ebe416b06597ea441a6e2d4a28cedd3522d37a6a967671e1ee7b851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc4b601facd28516d2f438c55707ee19b88ab7fa0c1b1d67361524deab137fce42fbe77c74377477e534a1b8d8a93db000000000000000000000000000000001849a56fa345261cc373bc81d49f3daa0c1469c19781c0a4839e111a57656f4775993b58f5fd394b8c6adb30608f31e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc7f9e4f72c2f8ea0131c7992977a0cb811c38598d9c8fef9efcd662f993b569f2fc5b80fd58e9f3e203bb79009de04000000000000000000000000000000000865e5b6b16fa6fce05b29e0e85075cab87dae3155fde12c4e66e15f204714ef32b6959188605c38858d72d0011f6bad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e7f861ab8d8bb6ebef0660c196775c02b209dad9a177c0a892fe71e9faa736214b6a212fb020895d7fdd3a10aebc1d0000000000000000000000000000000017f430a4344d00e35609c915789add8ee31c9b52093e8f7d2b64c53263634f861d13212445f6a874ab0d3cc216542b4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005789ee1ae1bd390912797a7bbcb83b3a26df947ab980b2b0d198827ad06b329b161597be490cc8a78dd6759836b66a900000000000000000000000000000000191982c2febd53d354bc9b2ba5bd0d26472de805cec91967b9cbae0cfb73dec346ab019b09bb8071b103b718e60e53c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000964617d67f169cad6aff8f1a877fd8db45113d483cb789d30c931c6e0dfb4f7e13662ba9b9432ba05dfcc2e5b04b2890000000000000000000000000000000007454bc0057cc2289991ef666ff1818d0b4da4db5c498b330611395ede9267b37fa4486492aa07a134c4abdd9dfa19431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013255baacee3115c7a37704ddcd935067a2e01539404fdfd5d3831d7caeef29f664d3a8174dc016cf0370ec9a057f1510000000000000000000000000000000003c6a1f4e4f04b7eba45342396e8b39db65922c009ae00fcd92f2db75b3d64aaaae92e0648fa871576fd2b1823f964231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014680e4121a5ec209bde069b52744fec71b766275580f0ee939c5c5ed9e004b2904ecfa55da81e27134945ea00416b4a0000000000000000000000000000000016737a799141295bf04c4222ae5fd0a296f9229536345a1b441d1bbd09ac25c28c0888744b1af789917a3cdbeec3a2d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000064cef1213732fda38663cfc5d03cb13856ada6b32a32686a05e57a2991b3632a023ea772d8aa18c47e1301ea239050e000000000000000000000000000000000832816acf8001fa758203c61236a313c306eac4f5c7cc1d3576cc8f05ed2390490ba3e2fd80fe43cc744fdabb88dd831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175c03f25980ad2fb5200c3b01518340d57743589435ed355bb8049ffe67c75842d1952581b66ae73447efc39e188d330000000000000000000000000000000005463c58843f3500f818af51bd53bce8ea4969d72f3802cdf30168895f3b927115a8b6c22d72576a932827b7ceec41891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8ee14eef3910d08b7581e83cd4289fa03bedafcbe991fa909ad78454f35151daa13775e48f3abb94785952690a11af0000000000000000000000000000000010566ec88d825bffdc831fee82f78c37c30d6bdec966b0cc2019af4c0e76fd5f3984b74bb6ecd9c753bcb363492efcdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005034dc4b0c9c559c4e8754998f9fe3c8731b8d1b0d68cff44173ac0418f6ccc070d14609a73f5d04e7e54c82dbc963f000000000000000000000000000000000450ee98ee4c95981c605a63a119eaf2a63e4f46dd1a33414bacf7c1229521d22031e138a27ea28897f5f432cd92eba51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e321a57b61b8336922d7b429bb5ef4e3ec3fe17e7b28aeff96ab06eb95d4809a3ff6a4c11e4401bd118630cedb17000000000000000000000000000000000018bb0dfb2a8a3bae60c6d709995eca65ca8c519247b75dd27627f3a759fb43380fc230a3c4b856dbb6f6a7ec4250556d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000965b896d34898676be2364d65d38e25e44a7eb63636ca944f5ff1b9e9ea521ff737046d63b5c6a84e6f61a26af4e350000000000000000000000000000000001957f3b667c111f16e040d323d277415604ed1e7108052ce4bd2a074006e19afaf57b4681430b423f12bbabefe8e05761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019998cd0f91c9263e232cb8c9f2c6d2df614fec7fb6689e341681c071ca67a7be1871f1dca5ae8b9ca57e6cc43f8f8ca00000000000000000000000000000000108de74b482a3c0e4c3fe22226cfb4ae92ad3beb883569d75f238820be12d1946162390269e543e16d13f5de477fdccc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015aea3a19354729679e5da9f0f73362ed96dab415c4d028dd9d31cf133822c1e6eaed70ef31adbf7159b7cd52d043e38000000000000000000000000000000000d0e62fa7355c5aa723b6984c614361024ac9d17fcfbf7f47f4ad5f41f5d7421fc1e9c71af2bf65c71f7f90a7ea88bf91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c144b3651ee93e0039ab3bddbbb485be6d7381e16de46f9f193edfc6b5854a958ce7506dcbf13af678e76e0ce6462a0000000000000000000000000000000014d132dde8f087112294a128cc2ca668f6f40cfdc19b281ae1ff9083b195e604e0a4081c06439e6edd9046de668f93191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186d7846bd118561de4d98284e414d0a03fcdfac842f699552bcc1433e55a6b5a24be461a3f152893fba95f98ae99b4700000000000000000000000000000000041ac833e2f56a86ab8000c8ada2772c57d06a8b58725c91dd614fa1360695f5c2ec961102deaa282b8973ffb4e932981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb61dc0fdec8aa2bf7d35c63e650b599f2438df9e69d0cbda3d0812d72533cd9408aaa1e9d73105660b4861d637e78c000000000000000000000000000000000265561781afbb577974dda50def44918aa559601b49519c3aa2f192607b419ae2d580b92f06a7cf5c3263b165c8e88a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7027d3a26f5b1472a7e7d9659ce670d5d2895a62903ec07263fef96762bdc8b005fe0ffefd55eb8f24d0b553acd410000000000000000000000000000000000a1111a16a30d9d7a12a7903af68eb30acdd3666732fa210f1b00402888314f00d9bade83df22cf7a5412e7680e546b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c04f646b08abc84cfd2c7c1d1fe7af5cda7294771623fd005c1bce9aeca57a53222c5bcde5d267fed40e30a6d26f1b0000000000000000000000000000000012e42e1a7ae5798c3e96e873a1d2cc2160a9c5165e5dbdea61daae4fb20fa53b3c17808c02431037f986b814e34a4a1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061b9eb388461bff173a20e7407a33335f0a1329647fd2736d4eec8d802197b13cc35b6fac718c60650cbb95515ebe67000000000000000000000000000000001075e59f6376b8a8380dc3a4458bf2ab1c43839067da8a8b2e3bed0ffa115b7cd7895734e48a981c10517cae7eea20981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019ecef925f1e7a4f9c4ba638de0871879071ecb5c5d6ac412c777331bdaf51677e00a2b3b243be79af2fe334ccca365000000000000000000000000000000000ab8bfa536eb618e89343a5f4b750e17fe15527bf5efc6337f06439dbe8e7dec0f2c1f37ad337ab91815848aaaa5e77a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c12555c07c85351a7e933dcbfbd60e54a3de649caa9cabb8086bcc46fff069c57a82d13826c3fcaa613b91c650c81a0000000000000000000000000000000016cb329c57144c08d484141375bf30a71d857ef8f39a8682dcd6c43b9ac52640386ab007a03512916bd0c434291330aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067ef11d4b04cdad17205197efacb296d7348be65e1715b9b451a934f9d9398b8b199e47c2f8f0cfacdcb6820f61b352000000000000000000000000000000000b1bd820253d5e8ec9174ee1e322b24f82c07c092c32e8b3583ef71816bd0ba138ab35e5a0bff7b65586b699e6f098651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c43e0133170334b15e13ad289734b337c243e734f65ef20b6ff08886532de569507b7f599a8a64be8fe2981687d5200000000000000000000000000000000000eefa44c57aa35119639ca7d14668a386e6d77d9a13030bbaa45f1b3d465a36f6423b65e7e4216b22ace73e34cbf18a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016fd5b2c2f8a5b410b74936b2b33e81dfdfed67687df761750ce9c19d15bb4eff18581c72ffba955fd4d21e38d7d67de000000000000000000000000000000001252b760c3ccc423ec35b4c5431212e11aa258a56e6e35cd534f8a2e1cc819a5343e8ec2e0696254e1447d8a7ddb41341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152f684e3ac6fe6ac7df7e6621198fe52aae36c4d2b3ba93044f52046aee50e66c35411477892ae8bdec3d6c54fb35790000000000000000000000000000000017d166d85a58549558dcc4de934f1b60116d684f84744c1863c8f675629caea689706ec7fa427a1923c5142a3642b4d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005870db230fbda010ae540e6dd923f79011925a2790234a839ebaec87d6aecbd65a84d5d55d80cda41c2f69e3aa4b7b3000000000000000000000000000000000f469fa80ac924c332dbde488f196d3ca161130662ab076270005e0cc6f7fe434d5a351358aceccd8708d6efb4ddde2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ba2dd1d8ac3d02106c7fbb64ec15919238cfe5b73ea719ad27d2c1cc51ff7e611f7dd977523ca907bd04f5c5dbf35e000000000000000000000000000000001909f5e81de424fdbb543a2fbd419a6dc4c95b18569b1196f4855a046e7e1963f88838572409d60c0e64bba59d6d78ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dc50fdc09db9053ae709e7235ff09a30a875a052028e52eaca7952f27b90f6c5c560374813417d4034e78d93a4f83e000000000000000000000000000000000c058510b2bfb35e434f430d64eee5d313f241abcf2c7775f5ecf3b3360a14cfaf947cef77c911541a327694b91c75ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002ec1db6bb488025b0d861f59fe37ff4483a9612b6a3854a61ae5b80d922b098ae51978663926d526c893290980856e0000000000000000000000000000000001d521aaeca2df95d17fade0db6077009c7445b5b5b925891746acf3fef9df97751f1be42caa154e77fb49e67dbfca791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019131379dd190ec9111959cf7fdb12261858cc4f05deea28da351128ea863b531de5077f6d3aaec697118a4509a73f790000000000000000000000000000000004d1965f37af6eee68a7b9826f7608a46c09fd168e5d55c2733c45af339619cc551fda5cb599503527cc3f478e547cb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015afeb8ce5bdca8a0d77a7a3edcef6dda10431f41b2e840590e7b26dc46c058eb94c30df06c99ddd669f43a23e362a890000000000000000000000000000000002c01c16dd26749e5f4e3137979a6fa73b2993f4451bf9f99fef12122fc49b2794fc46b7dd17d8bca8bc16491e312c751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c408d2e8580095222b4203c06b8a6a6c2d5396873779a3678b80f7bd99f408879277f72da13ff2f6b87e752501aaef400000000000000000000000000000000047d97338975f51108acd393b014d0a6869eeea5933cfdade82f8e713e2f431571bb8d87271ea9d539ad02c5c47337341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf31f959d6ccc537b03835f9ce6ba98565f702a496c5f4b52818c79403e870dc83aaa7f1419e77a760ac7a117fa4f1c00000000000000000000000000000000031cd33e07f332da3a56cc75dbfb2376467b71f82554ff6bbf2c959f63bd2f784453f942a47b43ef0d9318bfbcdc246c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008e6a36b67f756ee2bf8a78d2d88b2948fe5b9ae8364d448166502448c41e3bb2fbb68e92d60a00420e933bf384852a000000000000000000000000000000000ed364ec6f9ccbda1d6507e5a3a00517d1d7bc2fcc6d390a591a037c72eba36217aa07e7554fd76ce3288aee8469d08a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015486bc47b915ceb10c0b246b529d5133cf3007b53cb95610d5b70568c45b258c42b7e9f3ac40774ec14188cd967c7f20000000000000000000000000000000010954c5d6212c50e74de0e6a7752649feb18c45f0fbfa67f85dea09f37ca8c6f9b61ab13f1c901e90935a0cc9c28b5b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd34acee072657b1190c5fd2a5b60ed23f5bd150f63c55db78d917d42b0362dceb46e44a43bff6f9f09284a0b7e0aad0000000000000000000000000000000004cf48ba2801045ea7791b9376e3e233da7cff43c87a3075cc25b991980b67ca1caab4aa75eb5fe7132a1d3e3623758d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000976bf5a79c90facbc3ea806e20286c96edf9a48d277405a2d825968c3546591c74895599970ea7dd2302de883431b8d000000000000000000000000000000001031acca7d331ba32fbd0410d0680c0a4d8b33c9c91437f1f9263ca0f437a75edb3eaf45b492889287a3c7b3001065641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5dead2607a2da62aa3e76200ce65a181b0a17f7b8e5814b45f08436c7e50a34d99a90b1615aba96626e9c31e4f8daf0000000000000000000000000000000015005b1ce370efa385b39c0c29e238b98f131d7ae78b489796633aafa24f9a594100de32993fd9799c69fb0d21146f8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041fe5a6f93756d22eb1c72eead88ed791b58d66758b63e3cda7cabfcf3dda5f2c7e09ab2bcef89fe093041431ae258c0000000000000000000000000000000012e9a6518faa3abb02b6402c357a39db8105ec82c204a1735e792c0587b6b781b427dfe14cc1956ae7e2a0a1ba666a9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a06fedbaee0b21c5d1016bc9339107b47fd75292fc822763aa84ee401f0fa257a491e44ffe3683ed81ef8a945c9f9c0000000000000000000000000000000001f82a217d92c62ace556157742943d42b22b4ab46af8e9f0bc7ca9051bcf98cc78394fa8d97ce93307775eac7a233181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063e2a482dd07da954264985eadab87e392747327834fcfe9e23172fdf0ab0f17dea73a317bb33ac56dfe0f250b2121f0000000000000000000000000000000014036b9434509906a89b817ddb2335a1aa7e8c753a14dfaf2e7a97e4cb31e1895078bdbd625e7002ad4197c8df6d0c941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005605558de69cdacd67da47ae1e27476e51b6b9d2aec3a3d381401fd06d3f6200cee7785b38dded80af4897c9459dd8b000000000000000000000000000000000734cf01256d4c36499f7895acb3aca1dfbfe316c9757a9cdffcb4a326913c990017a48d40ff544742848414ced32db61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1a52bd36fe1d30f81137e31ae4c759e2c6dc86bcbd8e491abf7b506e0ad9c0a0bdfb0050bddee8a14d490532534c1a000000000000000000000000000000001774d3b97b57478a5c2c8ff46e59820ec09fc73954cf30f7e1bfb7decfeee5497c65366daf5fb55cc71890e788db7b771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000becb0ea048daa55c08292354b2f7f3f87a772c122c28b3c192e7f352bdca3097710ff8ffeac5c903def0893be1f1565000000000000000000000000000000000499f4f781a97d6f6499dd90828ff56108ca70c9074cf3ffd699b17bca3415acacf7b81775df4ca9aef69094eeb2ee0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed216e6af7f5ad67518a6edebe57608bde0c7afd49aae47127403144470a6c3b7e14b31b000f4eba1411f004cdf4ae400000000000000000000000000000000139ac0586483490c670a75c775db97c5a41dc010086b5a7d62ed372e96913d47d83d9ead99611b4baa6ba619600fbf0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153c83e385cf2446646645280489c3270ab146e791d78fce37b12cdf7b02eadd4d64326d49b6fd2fcedab08007ddde650000000000000000000000000000000018ddba58b1b5101c1ac1ef43bb72f7bf96e58a1da2c985b71db1a33b9273cc72bf4bfc251a25df6e03ae3f70d1d9c9431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c740261b9e340150250b096f8372ec484bf4d5e7faf8a7b826002526dffafac37ff23adaaf8239b8bf5f67d316a00b000000000000000000000000000000000f92c82ff6ea1333e6a50b40b9cd5eadfdc34ffddeb5a86eed52be8b85ea98789d94ef24763d4d00515585ddc84411711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0856a6bdc1a62cb07231879f8a46b288d73c0cdb3c270011c657ccd98e7754e146b68f659ce4ed517226a3af23c21a000000000000000000000000000000001085d5768619e4295683507015db2062ccdbef08c81d1a2e31c1353ec759ceccc52b5cf1eadf428c195ae8da70124ebc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad4e6f6252ee8d639265cc534fe8aabca517c54c149baeaba29a4015578d372c7a41092eb43d19207d2aa7f72c91efe0000000000000000000000000000000017c745a4895037631ce3210bcbbef7590f05c7b33eaddd1f52fbec80bdfcf1fb0299422b623546e3d0ad1584e76aa1ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080ec62c35cb632f9068608ea6511d945225ab4d60b14c81464b105df31f852e4024584eae04b238fc2aeb146b13eca400000000000000000000000000000000147f8e3fdcbc1329b5b30c32c879366c5d999bb8b7f34646929ab9f6e7156bd18daa16840353816e28ccc46d93f8f0871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b56496e4888fd0fdf388160f7bc0d0e539712c934f505dfdda79924ef428db0a4b7f5702e00c4636d5ef7c43d031046000000000000000000000000000000000812b266cd98634b4b08a2ff6433ee000497fe1c764c9461a5b401eba4b6e6b1f745920da59b6bd88a51d48add3329c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055a8cfb4495e0f1ea81ba44899170d983402fa2cdcbc42dfe0be9c76eabf73ef029857bfac2647b84e7808521bb9f8f0000000000000000000000000000000003273fb2ff26bff62c4aea0f721976854f7522ad1dbf4bcaf594e62d4c77cc6a43d3192aef39c7996851a0e0d300d0df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd8f6a526c797f549479137c181357c8b73777702f4c2e293832b7c5d382345f55099589b5b761d691593b3d7911abf0000000000000000000000000000000012eae7966b31a0975b21ab3d79c809dc1317ed14963351444606d33f6673ffeb650bfc9f3177ae2bf44a360c0ef958dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001542b6a5358f73c6392e0ccbc628f402168b121dad2c119a3583dc5ffb63c7abada8702a58402fb865163442084f2bb900000000000000000000000000000000044b381ea59f07427a2e296887d4f8cb78fb93e739876b424b25475cb2daf68d6a0518d5509ec9742c158685089c3c391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012aa0a6fd26b1ef831d0c452c425aae6260e5f483b714c20ce807463ac28aef2d3e749d1110b9f4576cb7729ae73dfd70000000000000000000000000000000017e68fbb10d9bbeec1055dcf109824eaae8980a60704b18185dd9792a5d1932fc1146fbd7138c6460d9ddcfdb80988e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001729e530cd85c9b8bf107d9144ee13adf6422148c6f1dfa07f7f00764ec092a3dc608a8d26e4fac1550707697e6bd4560000000000000000000000000000000009a270f69d7332df2d2ea143a691d3273d37834d2935b48e6dd04d1d34bbcf758f097ba158bb3efedb707f53b6a628e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178044b47c8c7ca293ec349cd5bd9158b928cf34f2bf0ce44f094518d755c12ad90b9fa0ccd3e63583d1072c9d205257000000000000000000000000000000000cc52efd543665babdefdae276db517cde138c8efaa1f1b803e43bdcfe5f0d661bb6aa55a1e8336fdb7611cf8255a44c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007df99d257ea1dbd0e20bfb100a24840ab79f38788547c027943b79046e612df0536aa96554f9437978cd5703458d49c000000000000000000000000000000001434e7da6fac87b5190b23a9b698238c1d4382be9d398caf187b3610f14cd458061501d97ec4391b3a60988f0e37bb7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001789fe1597ad51eabcfa4865ca7328962dac0b681049060b94dcaf54612dfbb872d77cfbd11ea6e38d66ee774a88efdc000000000000000000000000000000000d2717fd2b3a78285fa3451f02b75cafe0fa94341a45551dc09bfd3c93dcc427f6848ffb6e33f55b765927b558d144261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c875303b5342a96daf5feed7274fc26f7db8aecf2eb193eb4c38c6772f9dd2e49c0b5ec37f613f43e6f1f84d0eefa8a000000000000000000000000000000000777c5f3c4f6f37db51413c58cce1157148f0f9eb4304377eeb0d162d80c44a9ec2381a775c0454e9b8c65e25801b7341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1234744b9874a6409a150660cf1d3a4e3eeeecf4b25ac11c3e134f6b110e8764fbc9401a200918b5881ad6bb0a3e11000000000000000000000000000000000d9d8e7b5b5b010db6d7e5bfa7463c82b17939a9f000bb60aff9339fdcae8619f11fa35955c63fc58e82725e93867df21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166bf929de63f4734f3ad38af9d0fb6284c5a4ceca175f4d37ec5b8d164678e0c88f49a30b278551eef7e09f58c5c8ff000000000000000000000000000000001060372a3e7cc12b25896a449b1df2666eaacc2713ce1f9e6af650ef574b26658d5c08093678f2478db36b002f5a849b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f24f42e64fe73921de8eaf76a89cd659ac1a9be4d4a64e726c3c008b0609d2d6f77e9e141c0434e7fe4e1e318144a900000000000000000000000000000000049a61744929e7ea7eb9c3f22006536c290e5721e5476c18382a09f00cf6377601928606cfb90c0e4832a9e2baa7445d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088030f13c12b299bb2734a562192be3694436803af1a6cf64550a9df7dd11d582c403d458b53ab19c157963b71976a100000000000000000000000000000000077bb47db6172549ea6b00f1f278f58bb4c88f78663d82c7d8072fff04578703f5a8d7db19c006584f728dd4312bc9f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001470434a67ec265eed708efe232907314cc94ee6fca9bfd15745c60f20a7e049cad88cc6013e954e364ded3cdfcb463900000000000000000000000000000000115d0709a6a7249e5644afeefc93db2e935b69258ad9de6822b175f87c2b5a34dc5a22bbf14d05295c18931334d73d0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d463b20914562e55fc19d3101f19d858207bfbd45ccb876690c1f202fa2600d719c2b9d229564e03a61951b316400d000000000000000000000000000000000387d6e9826d40849257fe305d682ea3ea8d8d74515fa854b0e281a2acb291b8173673253171a6ec4b5a48a2cb567bf11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000087d32aa3196cf37902e3e22676ca838fdd54cb1e92833bcb4f437095f51f2967771618fd59fd593215e86f9d5c31f39000000000000000000000000000000000ff45ccbe8bbf76cb3accad67554dde5cfa1fdd225c85c075f51a6988fb9957f36992bacc52f1281564d64f46d3a24261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc9291fc98abab63ce72791dab5cc28bea069adabdc7e25a720113bb19a5613b814491d44f0221b0d4ba98291f5076100000000000000000000000000000000073082e8f724bc8938da46a47fabcb9d1c8e708790a435043dfa0b1aab5281e579ea8e091e0ae3447221924eb360414f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6ca7d603249b62ef448f1abb71244ccebc2ca178ece155dbe3a47b052b8c903f4d1fbc5115f1b4b65a9ba42b506dd30000000000000000000000000000000005923a3ac9a83670c9694df8c3dd4b90b908d15ae03f43543b52aee150429cc5f1460077545ecb8b0c1813dabdc7f05b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001115665e5938e1d6fbbc9db56cf19c6863a5be5b35c4237df8d5460e1d11eb4f82ccc0c2354b949843be16d92cb6dd000000000000000000000000000000000b5f64887e13d3cba7abbd86ed48325705f5ec14db7c8c70add677faf2fdd3baaaf0f34de497425b9d36c41db35ae1311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f6c2dcfb709e8e9d47c15fc545161ee50d0f1147f195f055cfdbcdd1ccdec191fa9519aef70e63f5fe2105d77abddd000000000000000000000000000000000e963e6433fefc34036cc77b01049c14bd28f17d54274a68defa9380e3d6bfeb6a0f0106b3b1128a3cdbc85080cc80051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001cd27d3730da9b25d5071c5146d103adb6ce6c4b1145621a2728dbd91bc30784611666c36ba2aff32e519a63a7f76a30000000000000000000000000000000017f805efc967f09f4c4c46b37273d1fb232a105917c81f69682122bfb90eeda89f766cdbbdb123396e6ddda0db3bff551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffe73e4123863278b1771d8385b870e1483165bb038d504e476f66106d0778f9d21c68fc7e2342e0a1ac486ff571b4b00000000000000000000000000000000052b0a09fbc0da14110a9459cbe61056b5562c1ace79caf55e58baa86c16240638492584ce9dfbff5100c6c4faba3ed41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d84e8a53d78d669d5876253bf188412ea16e7b8ab7390789ce13e519b13f09af3957a40b4beb6ba8a027966d6a12660000000000000000000000000000000001133d79ba731923bdc78ce6286a50f2470bf28d195c1e2b42c0ee738f38be38b4f6bf20785a03dc8074ea01e5bf5caa11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017323c5490150dfbf38faea5fa478d058fa4b5ef7fa3614c04cdd5432489553f61384f385a23cabd5309bed7ce7aa6e20000000000000000000000000000000008df614ed10b00144c6ab4387883b0be5f907ee69382705033d0adcfe235e69813f45a9c0ee00700e6509bb23400dd9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea4439f9da9e484a7af5d582dd57099c335ffe410c2c2d32af7886410f0badcd9b220230208a8b4db1a765efa8133f900000000000000000000000000000000198e8e1cd28ceb274321ca5ea0b4ba44c8e1121100a7cb7f360eb0f48e493c8bb407106473efb4259311939168c74d9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8623f9b47f22866dab20281dac6a417353ee873aa6179c081ffbd64c2311ed3c646ec09bc205080323cf568b1272b70000000000000000000000000000000010b03698bbb760c05f6d729729dc751c652bb669712f45b82ceb7e84c0fc668f701e2d4e01b2b456b5571703e90c5cf91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100a0ee49d4f5597eb541ece7d97e1ff350b5fca33e70f8b08dee9d73321b7b540ede7db67f0c44957a999a439d21ded0000000000000000000000000000000003caa9c201d59820288d6f1f827f33a83196d5bb3dc7a42613dda61712840d57d4d8181a211a8e615baa5806ef2d477c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035a0893a9ca5bf544650260714e977be1de2916d31e5a1387f303b05725581ddd2aa42dc9129a08ef875c00833289dd0000000000000000000000000000000003ad409e30a7f4031113dadf1b97672709e7f9bede4fe3aefededf759af17fda0567621dd81f3f2407d40e17eb73963a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019dbad5b0288777419e219d7d77daac73b6981c9629ebb0953b864fdb6e97d60c7d033c44d103ecb1a74b3403375db440000000000000000000000000000000008d7b7a3613fefd4058dc7f2572c129272c8be4b578cd7b59d64ddbf7b587f1587a3a03d75632ba291cce765ad7729b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012194949874408f90ff0d641c7579941b87db3f01f3dd20f84bfc52dcd5487caf28bcb22e9d0d332bb93dc2e42007d7a0000000000000000000000000000000002df041fb394585357b968993f13bd808d21a6b7b66aa26fd6a22067949ff2d999693216402366b5e9e4a9c5bad3f2681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001877ab5f2294598de83e411037857b10a6aca53ccdca72971a6aca66b77fec97e879c0a9b0b0ed0dd288075cc70e6cf50000000000000000000000000000000005439a16c1c70a94973686813549c279a82b3954b39345f6de329c093891651cbba7f9cc08e707174703d3bb0bde2cc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000684a214e3d5ed90d20c1a7b18a4fcf701c1042eac31c15824aa54e2a67d367bb2648edfe7c0356ed7643da1a96438e800000000000000000000000000000000142293cc80550d166e6188cb02e66fd63219564958c1d5a686e0645dc44f0f7da77a43eb8a0c26a5a09013f79210964e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082dc740877929016940089cbb67ea8da4e733cb65453904bf52e36aa0e0e06ad8050afc500f0694a1c02ac39aefebea00000000000000000000000000000000187fddb1760ce9db417cc426428bc03652986f6f6efec75ac8fa54eef1c2bc216ac3d5d17c9f23dcd037c4fb36cd94ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001825289ad9aafddfec7dfd8720023c1a8a04c22926ee1a2231ef2ea8fc9c5e88c5adcaf11c4c6b82b05d989c2da3dda5000000000000000000000000000000000617b38d561b3cf090c070d9e5b8f3d97eda7ac39322c312bb2389fa49c78fbcaaad2c973ad96fa20a2dd168f92289321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8b140c4e65f7434f86473ed147c2d8c03ef1ed6bc6efaa1b405cc5b80d3b6604dbe9bab74bacd50955b22741cc1324000000000000000000000000000000000b216f7e02c4a9bbd3ecc6b7f2f107459326a27d5df974e91255dd14165e17688ed6538d179d7f44a3e4c9ff4343dad41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016017948e754a3440a7c78b2c7ad696a9a701c905eaf0621ee48e80a54404887d7172701df403e8d9913fd868785e5b9000000000000000000000000000000000c02b21928c59819bb27ae9d05b1e0647e22857b994020b646a9c98ea33c00eb3458f219174a02242b7f45dc00505e041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000460339b13ca7eca4d7e6550fc7b1047972c36ed0dd285ed3d05394b153961234311454775bb601892c0896ab1b047b700000000000000000000000000000000193deeb32d52e14ac7beb131961b401441856c3fd307b919db511ecc6fbdf656c11f3d6af2aa2508a990ca01b3f2c9da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f2478a8de6f40a4282713295ef3e5fe537ee29b480a31860150e97783b9f7adb0f76abd107bca4c7bb6818c75849060000000000000000000000000000000008795d4b975393bd43ac07728171a6411f50f7825a579edd212e17293b9563e5b72a27132edcd2a9c37513225709dffe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001451bf0d41ef46d0626f580c93dc112752379be4480c63d188c54d1e04c43c22fc3022ea736c22b9faf69a9caf037e1b0000000000000000000000000000000003d6083061523ea5e28b0c037b68cafec5eafef297f40207d4ddc914e526e5f5f2a0522bb09d08051121be0f3a0b1c2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5d5a37e9009df0ed24f589aa36dde0f5eb51f65f0ee8e43a20fa0688cc24f8e1dfb273392ce2ce3d79a9269575a3300000000000000000000000000000000010ab230a5cc2d9dcf5b67f1be7757eaead84877bff6a561233919eb8e1b713b77ce320e2812cbbf003dd91f924f952491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000bb99b3e2c49ba31d648a0ee0315888576302d375899171e60ec6b34c344d6c21058e58656dc59e36fa68033c4c70f00000000000000000000000000000000027734c169529a04414aaab0fc27c383d4ad8ba9fac391a122127f2d151a7558388bf590be7df1e78501b02288e657111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010977b35ee9322e5c9df70062045449c6c46824dea989d7abb6aa536e37340c46a003b3725d8b127199d9e813c316b2d000000000000000000000000000000001197957f64b98fe84390fa9c4bdb3d882fc1929524a9e2de4f7dc5694d83701c5e502e5d8c98673518f8490e2a7102731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d219275a2399cc78e99fb00725088c83c48607fdb6653c4a9896147988596c21cdcd0e81fd0f09db1ba32374eeaa550000000000000000000000000000000000a225824ec32ec8d7cc53ad8766805d8f88922987541a0e2777b6beff68abf5f03838a4d013a58cb02571eb90f31a2af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b7aa3e8b687a233af5b4d4ae3ce830f4df51aabeca09465e4e1cf3e2446a5c83e51538bf74b182c342aaed3f014167000000000000000000000000000000001808d1b4884c4dc24363b0aab9e6f0f1e653f6dc0f00a40b6177f65b54b8668a0e2a234a1f2c91f6cc449e5fa7edef401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012698165841a63b5df6d62cfc671cb03648927203323462a47b3f3550417228e79f148fe717e61296e8b33157042eabc000000000000000000000000000000000a87c946c710d9efd8824e2ff59e0eeef09a0fadf1ad0493799da44395cddf5e1b47ff48d319baa50fe9ba53433a167d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4e13efff93add9bb8dcb2624218a01759618c165adc90357cfb9a13e75aa9544cb82cf40c3b06756e8559e28202771000000000000000000000000000000000d237e6f8082280ddaa1a164b258f19b9bdbd51041b0573a43967a593df5c2bd9358208451583be0b4093561b36483951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122dec2ee37c3d34c96d81f7826312e15dbbd9d5aac9c24efb5ad63639241e093cc4d20da3dc8e69badf1f2ddf8eeecc000000000000000000000000000000000a53a91bf1407b9497e26d96016574c9b7575a93865df003589002c27523d6ee33e7047360e6313a6de9f288dbc560e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c2abada9888c25c28a90ab756bfd260691a152cc1653bfecf022ad53f14d5beea5791a54bdbf7c1178c34dbc6d30b70000000000000000000000000000000017b4e030b32dee8dd8e94a6986016e5f22048d78ab0dae8973021aa33fdcb6da3521b566a8d9d6e084d375797d7b26f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f519fe291dfa0479fe78121d25598314c92e3d352d23f2447b00a153ce0e2317f2410bf3e94e87cdacd9fb21f868ee000000000000000000000000000000000ea3ec51efd63353195b34dec9c819eea616d8dbd2a73fba70e4b158e8cbf46088dddf6c6420017432e9b25a67745b291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cdd51e99db42e2a42d23c61c2bc65fd2136ac519a1325f1850fa4f37c4e3071384077106a276cd4cd52ad6e67edb7f000000000000000000000000000000001133a35ebbc24e24bdda8c563a09c602951ef9cd0fdbd8509246ab50208b0c9d5590adfd9eadc352ad8aafe5c872d6671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ad3f7be36677a2519a3df2ab8c0e6a4dfaa8bdb0f060f999c8ca3dec31df10268148146bda3c655bf52eed2d2e8bb30000000000000000000000000000000010c2871d77af0040bbc8efb542facce80f3a5df0c3642d94c18011243d2adf3156a4ae0f1188da2967f7c8b648d65c1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b2f964230494254be4ca9c7fd473ce3117dd4b346cf85d81bc6c27c8f2544bcee0e2d1d0a097f6800160ae170f40650000000000000000000000000000000018174de7be43fed86a2b4301b4cc2773cc4f57192a9462b713368e14a0b0a065d865572bfb2f6a151cb23f92d8a90d9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001195b8cf90456f5e34b04973a9219fbfb8d04105e280d75f1e58e9e450a6725ec8488aa499373ee926a15209b831fd2f000000000000000000000000000000000289029aaf50f08102e44a0d8cbd35766fd15008a9ad3c3be6890ee9da9d76c1dcc1d29445440af01740e9fc823a7c331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000357cd6f20b474c2c375af8ecfb76346b18d8fba0791f1b1379d1417b33354cfdf4bd4802487740b40c2ed112df8e5f7000000000000000000000000000000000af259c37282510fb70c8f8afa28886c8762722afdd8092b3f173da80b44c79ac3017d09276b71514f173258d95a36371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c5886109cae47e540c566b804739383bc491c449692137619aa7150cbf1a7e144cb7afe0b22cc142eb4d6e6c4c2bfc000000000000000000000000000000000f7395f7fa3c5786b356265487628fe4479060f62be48acf466199b742ddcd9b2c3636e9a34933486cab4ca106a0ea881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee6392dbc2d04d9d1a0da43ea4a4e4fa86d48ef95a96494a5e8779055dad085eeb0db7874f0fe02e2d5094ed2bcc92400000000000000000000000000000000058872b881f2daaf7d2c1248932be6818cb4edca146b8cb9f34ecf74f7393babfd019168a258b8f87e60abebbcdea11c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009012cd169b4bc6ce52087ecfcb3e1e4a5565b3557720fe0336e4830dc01ae99169d7bcb7593372fdd1ecc773d2b35af00000000000000000000000000000000132ac9808c126b1e3d34f5626be8b693e1503d28927d021ea0a9dd1aa64ce0f4a05bc82bc6ca40f6b3882f2e33c3e3321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7e692292564d2c08a20396922055e2a3d8fbfed31f8a05d0090b554d5f318fae7ab45acd5cd54242522cc1b2ed8fb50000000000000000000000000000000003bb6ca15fc9e3f8ffeb1714ce27274b990ce117231922a273decfae4dae940cb5f155a1eb5e67851c2a380635346eba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043c33618242415f2bfb939f6f9ae2d3d1623a6372800b68c7bb06c75a9d02547bb2c49908864a96b97c3a554f99b9d400000000000000000000000000000000074965028b92542e140596a1030ac234a08bb5ccdd450e41eff53ee8f88d2d3f0c473a499d1cfe8de76f1029c9bef78d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cab60d959cd0972b7265a92ec6a8f50679539f8b337f4607b0496531166fdb22399e4f62854cb37dd3c31e945005900000000000000000000000000000000006ad9d94db5c6bca460338151357492a2a219e029be62049f03ae675d92fb5fea3b4a8924d65c72c4740ee5c09e501561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a387893ea1fb87c3437d405a4715a2abe71d505fdca4cd6b10426b77dc411ac5844402a5649f0a37a296dcaf908a17900000000000000000000000000000000103424b912f3575b4a46245349be127850977d7e97768b36bc96940be63a14add24bafea0aba6aaceb1496cf257078191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cdcb32cddc97f800535e87e9fb4897470a0d9b1c5fb8be60f6030eabc8a02ad437b372174b7008cacacb8ad51013a9000000000000000000000000000000000e643ac29852f16f7a990bd455406e8d54ee4c4b53ded6a251e8c268a1261f1b2f3f0fde5c45395e81d4fb1584b6a5fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143a6be72808901e0f73f7e41b3b636840501c7bab43d2fc5a767d5214de4388529acd8b6618006183fef112b8c7da460000000000000000000000000000000005f9baea082ef1f6155740a8fcbfc604211ccb5d785902718372becc39c8c52e03504e76f6c8c7be00c477d68fb589291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a21c330c5360ffb3ff27e84baf1be5a9cbee1cbb7a7e9466757d010ef1cddf2c27a7236b1da6de24b3043e0e735bc400000000000000000000000000000000002d009211ca2e3594069e7c5edbbef17cc16cae340e1c8f26b95c215abfc39ee1e7745a77aab78000f1292fd0a0c21de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000196a9b00b7aaec5f1cd3271e721ca31f1d8763c2387f6b3a41cfd1643bf38ff113f3872bb05748888e45f847966ebc62000000000000000000000000000000000ca7fb0df9a424d0b963a3e0177abb9a739f66948b00ba41b4c498325fd08d8f98dc7bd68ef067d018a3f655f0ea5c8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9ee00a50bcb3e75c9e16ca09173974939c3f9b024d7194aca4ca11de26fbc357cad20450de030ad45d911952741951000000000000000000000000000000000e1a0d6c1ddb87a1ead84582f940a714d90234fa9ce67d63d70b2f4ecd9f9dc80eb085d6b770eb9ff76dcfcc0062c3531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7718f728ee75df0700d32a36efecaf58a834627e7e9b6c275fbbca136af575d3c08ce4e958b9fc9723fba7c123cd94000000000000000000000000000000000cb3d8d625c701d70f6f17760824041c8e85e4eba6e1ff52f4f8b28ba210dd51eb7f02e8b887365a094282239f8ad2011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062aa94a7249e47a1b89c447922c6258b80a3236756974c105e7138b415e06189ddf7e9b6be120229320205102ad790d000000000000000000000000000000000264390d34a7cb6c63fe4efccb6dc9bfa7a00a1007e8c9ed83b8fd9be02a785f9187eec4af454b5e7642bb1a1fa2059e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012911b166ff6630e39d465efeb1e5a39350c58dc8d90f9dab2d584a6fdd7b6a060a1a012870b1fb3041d9d6c8e8efb85000000000000000000000000000000000da888491f18a7c08c3ae3dd9dbae3cdafd0ead10d2149e077807f9e165611f9854630f5ba12f1e69b2dcd7fa922e86d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b4ca9840219728ad548735afa2bcbac50e57c3fd616e64e1de856026499aa20dbf15735041882fced148d58b2e066d0000000000000000000000000000000018c5897c9ca74e7010a4a5840370c52e7ba8eab65265c617b0f9c77dcc3cab68a2af1a1e4b5400f0ec88fabac9b20cf41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030bb0c5ee343ffe5138c75a2a1fa4e39526e96093bbb628f9125c7688a98dbd5e7ea6c3d48f3b5125cd995026af7ef3000000000000000000000000000000000f480a1d6f81ddfe607c820b3497b3471f7a359c4bb086f4bf3077348f1ca0d40a38b8a36501f861aedefda584c77ba11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ab48bb3a60a8b8a751db878a0e3148fdebcae9a8989416d584993e3f8d436f4c96bcf6ec2ae539921e7a923f24bae50000000000000000000000000000000007e7da3c1bd5dc539505d60ac4923efd56fbeceab841e0360e60dce53cf2190eff8005036967f7b8c80ad402024d75c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183297092462d554b459c3367dbcc9c5160108b8279c62171873869155cd725fb8f6772794aeb262b43092372f570ef60000000000000000000000000000000010d549ebfebcb9058ca4895485f21b0f3b9e2dba707b16fee90ac859dd8537d75d32c6c51384135aaa6aef4de6eaccc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000216cf040ee2a7420c6cd35a9550c607a74760f1dde8a7ba5e06c7cba7599c820ab945600fdd691d77993d8b9eb8b23d00000000000000000000000000000000185b86e05890bde07814b99e7ecf87c980cf914d7f349bea886e5064d3ee12368e6647eae415c06894d8e3a18cfcc05d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b14dbaa80399f6f0951a13eb3bdd383b3709d0c7e023fb96f5c4182dd926266c5a1ae25bb7fbcb00bf8257b98c863de00000000000000000000000000000000044ef036bd4b28916045f763f33c6f85359fa80af15302678046d5f4a9463ec4ec4a1873b847642e766fdc0d128e7ae11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057a45e6bf6efe47e05f380c0d3dc4f106cb6c07e839f10c125517417fee39eae903668d073eddc5d5096077daa38aff00000000000000000000000000000000102cb800ce0fc31c9164b0a53880566394bb61b72d28975e7bc3c0091ad79af0b927f1500b6505363cbbf1b78aa850f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099279b9024e24e4c335d10e2ef668de59a45af0dcd2e687c1defe350ab8d63eaee952eb2e208ef1e715f900c114013900000000000000000000000000000000038c4bfea318d152d3a69cf188b1f062bef23f12f0b1d226869c268bfa872a88be2423afb601ca7ed0a13b4901c8d4ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e2aa6106dc3bfc74b7b5d18a40d09e7b58635279aef9730929c1967e0712a7569d4add49770f4132cfb5b2b6cd5343000000000000000000000000000000000b2afbbd6cbf92efa9694c437dfeab42584109eb324b40109f93786288cdd1301d9da58dd68d2b565938fa820e86e3581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132b87a78584e03504954744cfe0715d01ffa53ce607e01a96a3262663d427b85638be739ef7f5433f12352a70b061350000000000000000000000000000000000840332389d474b72dfcd968fc5839892a8f43fdadc7020d67cb0136f4617846d278e2c2435986e335968370236cc941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000faed983cf87be5196cca1efbfdd07cd2463bd97ca6f624daddc0f020ae0e6f233d6a644cf361f666471b7836266caa40000000000000000000000000000000007ba2587eb49d2a6be0b531093deda8df81313cdd6642f68a53320cbb786d8928db40317776de8374ee88c2998b25d3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000139078db19d01a59605c2a874b0cb56c5fd3b425d8cc79632a27ff658a8b173d1ebf29f93e92afba301461df8daf865000000000000000000000000000000000f9d212d26abbadf585c0b3b30eca7e0b91bc71a991da72c13658322eb9dbfb9df3a9034cbfb9482ff0a3ec9aecc72c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080a9d8a4ce382f0d10c283e68ddcc63aa326c60673b38eeff3cc9f05896e81d974d56c4b1950b55ad73f173d63e11b50000000000000000000000000000000005543c67fdcd5ffdacd6a41a50c8cc262db42ef6d4aa22aebdfe21446429d24f1c9a6188ffd6466b8d421e750a26d99f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e849e401dff6f79cd747ba63d9d095f1184b97c3074122c24c29b2390396cb6c609fbe9f7ad824f4a51ceca25326e20000000000000000000000000000000015bb5334f987eb5171c92f0c4041a291c3666f81bb1d9fc7881de4eaa56c80db0ebf8d1981875ca1a022c2e00d90eaa81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130872752943c5dcb86ef3a0fcb098a14bf69d3871ea20f27b7d4fcc4429db45668af0b4f35ca7dee663e766fd1cde400000000000000000000000000000000012ce566dac7c1147c6a47b4e19fde9ebe2dbcee1ff689d90c372e5a66c77ea10a664e1366c323211fa18ea69ea46db4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001400ed428a6e6a388a9870ac92b548bfddec0dce75ba3a22af4667825a0d5649ad6ea9146d4151a148285c28624d6258000000000000000000000000000000000dd3c6a15f4f6bf616712fc611a99ba42eff8ba404b8e0faef0f583cdbd567145403566b1c8375f4595e248750ee71ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049b8cdddce2226c068e52d273f7711a0913cc471673295ffb200bc980f7c465476cfb5bd9df4307e46c6238a2b98d2d000000000000000000000000000000001080d006ea4096567cc56d1cbb5dc568dafae8930699ea5c18738b3d81ce9e8ea27a05443063b5219aeee98ec65d569d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027c06c03bef72d7e547268b6a9d5c649225b7d861d84e3b04b1fca6bb994dd03df198062a9a2a46725ea75bab51527100000000000000000000000000000000137cf32048ca8ba8b52f3983a8afc6835cbc0305f6f71c6fe05f14c527b082170f0d089189a5f09603279af1915897d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2d4adc368a0e84072fd2f8e45016eddcec7251d11b5bb641389e34a4d7a752fc0258ffd4b7a7db7acc3ad8fac587770000000000000000000000000000000016a9399021fb80a2fa57ab9416609be8d0b5bdc2af1e1db77beaf0eb6525528e35b0ac6720ff781147fb66272aae0e621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e2420c7b6cdd61640266439eee1bcd5f081da72c94bb1e45f90cf2c22c4e4f53e4bb816a3334472fc89622a4a8490d000000000000000000000000000000000975421734c1a0b90f8992448a09cfff974d802bcad7bfadeceac3feaf7d1e645be1e19edc3c94b060e1401d7b2dab191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001914b335c07a336c6ba6d59c502177028bee782ee9780a1f02e239d119ff6c135161654aacb860473a2d6cb4161860e4000000000000000000000000000000000f7dfe4d2401ddbec12028b8f6f4296ea2b1fcc2ad16af91d56c0b8cd1c5b9753481919f2518925770317045e706eb511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001738437b6638aa216876860fa37a53bc7f1fcee4393d179e9fe92ced9baba5403aafc443f1c68a18dd4b861ab63b545a000000000000000000000000000000000703b4d1f9ef4b0dd434a2062cc48a289bcf08fb22f14f293f0342e8a6bf139116b8694554b3b4b8363614cb9e2b90701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001395844a02056a97810a67609dc818986c2e2d9aaa8505d30fc751be7305d9dc752edb93318f66d59d987af2c0fe6f3500000000000000000000000000000000082dc2148b20cd39280bfa2183d11012bf5c594ad26661b65beccbd3ea3b27dc6775831e55941ad5593276d5fdb2d19e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cdac8924ebb2a2875cfb4142cb62c73d9daaa7ae72c9969f6eb817e17e256e987ec0629fc244e69ca2678a37fe44ace0000000000000000000000000000000001245ba0f72335612749eba13b842c41c937af88e19b1ea6b91361195d88231b1253c35022666b191d28fe727173ac711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e0e73172afe306c148574e89d0149b65056491bd180b0b35713ab76b4cf01d53f3be5e3aa0f28e0eba907a3becf81f00000000000000000000000000000000153006f92ab9b70c3885d6b099f41db8f903b69e417adc94f93c53dca493d3557c8ccbf55d55f06825226c0adc983d2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f85321ff8c282cf4d6d72ccc02cde927fdd020ed5b95cdddf4810f8b07ae71aa335988ba4b5fee2d55c4a7e438634370000000000000000000000000000000004a0b041e264dd653eb8de9d9ae95bbc6ed81ed769853011b7942e63d2c9b530d2c1da7733a02b23741866e2d04355f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005b358dbcada3a456ddb67cdb0b8f9979eb396f07d2c33d6f08d2f6d4b09ab04cf155cc4950ece534459f7b53335f9aa000000000000000000000000000000000691b39edb1b00041761a12e2c7425dadda0aea6a50e9c45606d9755c0e015685ecc1cce91e0ac8936c3ff69104667aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7bfe72c99854c4585ad751131829509a796a5d722ba2103421d197f9874e41f6ac7161a6a883f1d413367e093766fa0000000000000000000000000000000019c08dba2e8a5ca3d59afe3a37b161f400bae355339292fba4105f58dd4bc764e845c32092ffdd3ac846979a86c017541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba553541a118d9abfa89775c2f8b362bb5d88411dce6e12ed611573c1b02be0f56ed44100fd39aba193bd079005a14900000000000000000000000000000000157e5bf2eb12a530ea29bd268d90ab03c64a6f46d19f90d4044229106d19a371a6dc3c73a23669e02ac83b345e6988f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014952918815aea3c98b79cee39c9c3483666f2091c9c5dddd9acc2a19fc39529497c07f484dbd9364ea845c3b78b5453000000000000000000000000000000000653a2257afac9f711c9197937e43a3d4b389317cb29b4b289b97843cb65daaf64ced8345240f4fbe4ab42f24c8415451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001818b11e2174ea89d71baa50641fdde66bca58bcd583a8f2147feb92009d2cba2ab326cdee87fde5c9d03aab97a43346000000000000000000000000000000001706a596255d9d0fd573a45c2ec171d240de37eb3900e5f4f6c046d488554049bf5cc6828156518548f8573f0c41de391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019dbe6bd0b4105dd9d48cb0dae7a6565047f46c3cf388608621cd60939e632b0f8ecd0e741bc8442a4e270aff1a0a08b00000000000000000000000000000000105f7cc77e5cec9ffa975ccf8792d6ce97ce554bbbb7b075c7c660df5feb659ddfd86e17fdbb60cdb0390dfe8a3635ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182a5ae750b45b4b7fe5221da0b4d9dea782688e0dfa6b6ac96d3c0f960b2d1a32c8b6242629c221dddeaebf2b32931400000000000000000000000000000000154556ff16caa2586831dce8fe83ebbac880d16c7b84b317b30a7b76b89c9a84209f9dd6c1060cc8621e1f34045ac5b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098a42c83827de71d1eadf012606d7c596f7b97eb600a6e91b1ac858b0aea038ea7840982b332000d113e325d6c6c74f0000000000000000000000000000000005bdc8f299251735a7a362840b48c7ffd08503496de13379f0cc4a9e32dd2eb43e8833fb163ec979987e9df9318e07f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000965efee82bcd6d9ea87b285b7186d11480decd714fbdb083b93111ac81e8ff4c9da659b6d27aa706ed77adb6882e9d300000000000000000000000000000000130567c569704b7086e8ca1e42ab92806b2ddbfcd7c94701b380284074cb5b883aaab1bf645763885de24ba4c0ffdbad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001942b149319968cda4f9d7a3b20d983e53bc51fc9e63a26a149a1c9c51081dadfa6861948279a3d63bb9d3ad195ba89300000000000000000000000000000000092e0a0d32f6fbcad7a911fb9f2b3c8abd66f49e3d2a98d701854351a5655736f799ca438d5b7630148b0f0a71a4d7641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005de8812a827ba6c2eda2d15fb5a512c6567b8ba35107dee99f07f70e77d1f809565e1709aaad755066c25e90eff99db000000000000000000000000000000000cf0b29848ca2150a6e8fc30d0a2fff095e3cdba2cf05eb6b4f9e7baa012fdf30013182982d898984f5a35a02c2d88d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee118ac4f40f6a8557c4e15cba996d5c80a03214d561b6fcd56696775ccd88b01a1285411995e1672071541bbe2a5f9000000000000000000000000000000000067beb2003398d36feae9f418a2d0d8f200b922534d3bf018fe6234105ebe8287617337b6a0b034ed22f389614afc081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bfc352ecb32c491bc978fb115dc6e9779ded0e9aaf7d2e5586d2a21b12cdbcecc22c4be5648203643c56e8a2517cfa4000000000000000000000000000000000fd9804ea2cf917c485ab65faf9f52715a03dac2f4f0803b4a3949398060b7af106fda3eab55179a8ddc11d3179712b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df2935b11f74fb47d6f7d1e50b2dbd65c4a31c267ace95e7389739724e5e26c0e21e2bd1bd7c02eaf05cf945b9593600000000000000000000000000000000012b667af8d120a0b26fecc610214565f94f1ded4c67ced5828c74b5e14ced751eaaf9cba8bfe3743f056d2f20c8a867b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a13d122dfc6d6aa8315e775574b960eeceaf2e53b2e5ad1dcbcdfc785152fe4f56f667fbff4dffdb99c528f5150141a0000000000000000000000000000000002b791f1585342f9c98975912a64dd56e41dbd43466394598f0f5e0024f9cbc6f7dc02b1bc6ca9e37e4c9fb86b4a33241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031e61fac9a5ad59f21f0a4df6fd17ad02c52c27e797b516114bfedb3be79dcf9596f0feb56234c2889451032c517dc6000000000000000000000000000000000df261ad5f4028967b63e6b82a2a32d5a05e326f2b7a153f17f97b944289c670dc37a9252e40f03a38c289cfe233a9661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4450b069f179258b904c4280dfdd660f216521f6d44aab245e3887d5eb244889b0816f8602bd4b6337728e0640306b00000000000000000000000000000000061c39ace8d371c4a10a596b4879ec61615c1c070c0fb46b23074851f94576c60b9331c3f285fb59c656504f50338e9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001675245ab016871af948c95d5a164e981256a0aa5e5b5c1845f8d5322bf8196929ca204def38358c5ec786de70ecfbd90000000000000000000000000000000003b5f2672ac084e1cec821b60f82bc8630ae904998fdf62542eedf9a6d08706d25945dedaa1d05ddecea7ad9cf4fb90e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180474fd96ed91dc70f2ffc9c3bcf6160fce6e42e481c5ab1ebbff1717911525fa7da22180b9461044392e025c206cec00000000000000000000000000000000061c5930f08cb4fe3d584edaedb5873a21a4f1496496f46938db1bd2ab1e8ab186cf7f2d81fcf09d97182e133b9d77641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ceff9ccf7a40575dc01974c1d9a2707896e96cf96d8317c94d288e9fe1c651a6afd06b73db5257ddce5e3492e6075050000000000000000000000000000000002a8d731e5198a077676ff03adcb0d998b857f0b0f734b2f72c89ac51f49c671db28eb229e34a1c7dae6d95025683dd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005cf49f46ae22d66f8eeb3442c62c89a6fcd7811608e18c3addfa8b261ee17ec829aab147685812f8bb54276b785123d00000000000000000000000000000000033909e12dca5ba7de515ca46e2ea59668768e6fe7d5dae35fa49a42427d224a6c1b71102056528fb9e2b0d8e792b1ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062f46f68ed283ca0bd90171167fce9a1dd00e467671ac3895e41a64c082ca934fac3c41f9e4f09f2f64e6d372a680a90000000000000000000000000000000008c7a314bbbac36f9baea503312ad72c593cd2d1d4073fbcb21ce87c5c3ac416165d6b49b9e0db0c6c73db6e007a74021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b05ccee05d515d411a62c1d7f90106c0f8453c8ed2ad97b633b52c0b8b7be8275214c886c8c750c3ada41f45165a0c000000000000000000000000000000000c7fce37d21540739cd6e98a67549f9db725f34b3279c02a5e663b03503009c3f3019571fb0f68c1dfb86b2fcfdcbe661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000625f70fb3ac0c9ec964ca9f5b68eb9802512864e4e149d9f567eaa6b28566597da6c26f978fafd2199d93c9858cf1ec0000000000000000000000000000000010e447377c13f49e36e85498f66ee5bcb40f492854135330979a3d9b37dfb3fb68f8d41efe5d425e9e67d7125e7c11cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b98c753fc64f29c26f48f7e8ba20a77119d5070b2348eece41eacf75f3e5343d095be24830a1d7a7330e23d71d9694f0000000000000000000000000000000015990f125ee6ed6c438176eae44eea0a1b1fa8c6a5b211ec2709d72e5ddb02e6890d1ce60e90804db39d7666ab2cd49b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011570c19ca60f248bf4258407507268363a31926627dde77e52c086be6e3dd56b6f5ee717360eef87e78c560a9c4976d000000000000000000000000000000000a978192f987cc0f03bf4872c764c354000f93fc9f364a340ff76d4250883cff4642acd3a8b47fd47d10636ba0656b431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae8040231c919f0f3e6ccd46f4bafe2b464e135b478b7b8c76c01b9cdd01cb5ef520e7561190bc5b982ec5e38920a87000000000000000000000000000000000c7f4d72e869dd3c859cd1416569b2ff3278fcfb230a737fb9931f29194d0f1b765554ad5b4462267409609738fd08361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b18279295538e4199e716091d75b7206bd8d82861fc0ccfc8425e123cde5b233640196c37ec54f339934f7e0afc52d9000000000000000000000000000000000675565cbb9c2f281faac5d416bcb7c346a278c2b00370999d1c6865ac5f2ec4703c52cc7b52b7817027b9331a383cc81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030a0b18c5d0f0a14945983b34d5fe119067d69939164b7239d3bff43b0a9b3dd911976b91d744636fdcabec1a618f04000000000000000000000000000000001571fb469a12f70681dce097be89822dea93aa68a91c309a513fc36ccb2c9964abec0b723d864bf0b0af94d40c511cae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000771a6ad18fb99edffb66c11b6e54664c72f6ac11380888adfbb95da2645ccb76a62335ca152fe3d10bb17c1bf1970d800000000000000000000000000000000148627c05233c6507f5def752bb27639f8e356e42fd723514bfcbf304df0270d169f4ac0c2e8f7703ac97ea4735ac95c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c2c615405a1962a798f56b75d5d6d2164e5f21ec9f08647c725190b7ccae38f19407e9c36a2ef4015a449bb881d3a80000000000000000000000000000000013712a73ce0cd3e15ccc55e41506bfa9e1f87ddec178e0e4716807b22db7ebafd2a766ff55a1caad274afb9be98b156a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000254bb2e7bf42ea22908b313d3ca8dfa4ffeb194073a126df0023b6eee47c1b4de97b777747648e9146e60f989f08c8600000000000000000000000000000000192911cc9070a8a95cb6b0f5bea78cbc75645b7f1e4beb9c3d117a04b25188b8ebd0e1fcb5611bd85f2f7692f5e290181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160754037da240a910fda111a060dfc16700e5ce7ffb5e0fb8c8a7e3fa4780589e194bc416a7b3f1c5a691c483e504fc00000000000000000000000000000000049366b802fc4b025356872ad66d4cafd34c234fa7c4115e6d08a60acdf61f55b57e28af84e6a99e2a6739529b3eae1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012151d0ab0b97a56e01003b8eee2a0a54f59a018fe85b9a3a88466382e2f0eddc246276d8979e7a30d2bdcdd6dfbc9aa0000000000000000000000000000000007d7dcf664dbe78ea1eb5af4b9118359e54aaabb32f365e643269578e125c42a483acbcd3f107b5aa814c2672170ad341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c50194295e8853a3cbeceafcd549a63a0ee12a8dce5ab4c1f7c8751ea8a8980eb3706eb9711a1eadb8f6874e3ae71d00000000000000000000000000000000086382b73f8379fdbab190a31f36900b1894a028a732fbde3e37d70d3a8c53d5cbf1d60797b09a7756cf1cc8bd3738561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053f1f1a61bcaa76b6b13d4cb9656edd5d1b0b6c9f3c2f935afd990f9e196ddf3fe94d6961e87bbf7457aaaabc15fa840000000000000000000000000000000000902a9782f8af65ca135c6aa62e1ffafc1c3663a57aa79f30d203c832c873dccb94d3fc70ccbc024475112139393dcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e1cdafa828687c55e58c1a2faa1746ff737cf0eada80cf664ea3528a4de8b43647438e377f74fe7fb8d207a8e2e44f00000000000000000000000000000000124431f43eaea1cac8d0ae373d8f514ae84142ebb5e10be9466da0d56aa45fab333332a8f51414b15e991300ca0361351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000162f0b3b51a486ba9f9dd5371b7d44286d6d8bc066646005149571a387e5af2b24a41f7f82db561c9206dcbc82442a8d00000000000000000000000000000000173c69fd43f04ec3f2d4ded29367b790ca8958413585ac0423bbdc6a71bd888cc9f3ff905e0006848a8ac79aee080f9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001311ca6267fd37f2dbd066c33a639830f1cdc77ddf173c8ec0f422d09c8e7595bafc46ba8faf4a89841bfbbbfd6aca26000000000000000000000000000000000e1998fabd618e84d5cbe4abc5c4743b6a34e9aff7c43c3084e549de5dc323ac4a5e62be9afa530f11c80a298aacd86d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082889f7d334c8bce97a84b790b5b0b07241fba8efe91d61f0b7689a9c3c43c92c777bd66927cae9911c8f19afbf2ef000000000000000000000000000000000051114d50edfce8ad48550aa62e55c29348ee5d1a96d7ed497a8b98ba6707c6b06029a93c11743e94783ec689eeb5e991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013dca5dc0e4d005ce43f920b8055e903b156ab5ebc8231f34e2a68bd022b6b3308f97d3aacdb8b7edfe5d327b1acd0ee000000000000000000000000000000000bbca756fa632ef50ea75f1ba9518ff1bad2e95332f7c089baba58c0fc6d8bb517af01b458eabc069e6d305ab639cbbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e246c26a722ac2488eecb546fd27d3ce231e7525ed27d8b0a007c85e18b27f4142ff7b0a11227b0fdffc4dd9ad542900000000000000000000000000000000058d01b26984665222bd59512798faeb160a540cb77dab9b7cb4fb1d3a25ab1ecc477702f0561d333c3e0e9afa7f91011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c62b3e1c1042a51f113860a7570d8b6f7b5adf21e9902d2854022007d80cf58fe9f65417649a8b19b9f2d1de9405c7000000000000000000000000000000000bf588bb802df12f15769ffb802dfca4e08550383ba0f9dcaa940281f780bd4b3fd02eafa28feba1ef94be340db96e581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184a256e50eae99cb5252eb429ce3954066ff6893416854a0b2f5f60a3908aff263e3fc0fd63023402aa256c6f2878ce000000000000000000000000000000000775130031dc563ef9866d63969e6940917a12318b4c7b58a7aed3986ecc37e268bbc6b491c9b1415ea310065f8297b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074ebbf5dc9e032bd6a8e2e6de5c7d961ea4714b1404e8ddc70621a5df7ea36a502b0d277eefefb71c2a19c04c1517db0000000000000000000000000000000004913dc1cfdf43c8a950879734a8bcf6a6af35166e1cd48c8a3a950e0a035afabcb8cc961a19e67e3e9711739e8eb7c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000135c3ac527c06b3254938a85b08962b5a1eedb0f29d989b8a621b90893d52110fafd8c8da2ec9307110a0cc5fac58b8e0000000000000000000000000000000001a67bcf1b003afe537a756fae59c0b5410e2c29757a3093f64d36d7be557f57339935e1b7729640659817682c6ea7011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010fe309f09a54119ae8f088f935ef6c77c3969e04f556bb0604752a9d5e6df4d8138bba9405776aaaa9173f16ef5f0a700000000000000000000000000000000139d424475f4b5137b93528d5f219b473b03aaae685e17d262d83dfd5ea28117a32cb1f818ca28cdc9447edda387e8961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192798d81fa09194a7f31ee602f4e475240d6c647e29de9775b3385ea1e51684507ee1473c0226ac0277339e88eec22f00000000000000000000000000000000047da48c8b3e02eb93818e2fd58167f01e780172979fa296959359544faaf18b27f37cb4861fc86da476cee90707fbab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012cc4d11017b08e0fbf7a37ac4bd97471f34418c8fb60b8a974c5f60a0a11adfbf204a9edf20163de2e1ab8d812a895e000000000000000000000000000000001471b65b5a0d7b3a3656780dae231016f7f9c6afe5cc7bb21f30a0ac09b2983c6c1019165f3ce1ec80cbebbaa4ce755c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ada32571d1f4f9dd947d0d3fcce17c705cd4ad2f3ad139df092ac74e0102e36f6337f0f64e5acf6e331c08c91b14b88000000000000000000000000000000001316a61c0be759344bf7028209291e31a6cbba20ed77baee5e7de1a8d2362edc1b2424cc11fb036b9c04e86a3e445fd61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d76a13f9c68429d6b585515a2cf96bd32a9be4029717c6020f1a36bcd27efb146ac8e69497bab61aa290dadd77a58e00000000000000000000000000000000033d2abfb69b069c313205bbbd4662bc3e3e7b46e43912366f03512f896043b640dff00fd2cea141e9abcc971329e27c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088a223842be7cc6c514f589984dad64463be4fb9ea4840cba0690a58e5ea207f86fa01ac2bae3b82686c1358de7db95000000000000000000000000000000000c2896e7717e66a8b4fdf99149287662ae3af2f8a047bc631330a55410af88bb2ec7957f54594a6f338a101f0bcedd1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003253734fc1f61a537f4c0b3899bfc37cf8cf6929566f3749051b3602138adc52ae169dd35365afa3df71a6cd28e15af00000000000000000000000000000000044e355cd514c361f9b7c190e4d6bbef6790e05bcbb77b386d249d0e1af46969c13cdff5b062e3bfbbbfef225e18ed9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022340d75eb7e0cce293316f8b5b2f8a3166db1aa356d4ec1d7a3d74a0b5afb6c9a197cee094a3d0179c8e0c8059d0f60000000000000000000000000000000007d27f07ad5820f6188560f86198c42f87548a42c6e7ba7805c181afe43f837bba51e15e4620f79e1d60cb18348612041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004279cc1f57a5dca8615b1981ba8bafbae157f4253f7da72f8ccd5be1b29795c931df3d9f95d711483017a9f20d1e04500000000000000000000000000000000016c21ed357700f02a37b3f025809dbb2bb5ed6c60e195ba35ebb2cbe3850e11bca71550f2d59290a5bc3a44e19c94431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f0dbb75b967ac6b5e31c460ea7513a66ce15aee0d3b4a4b0219923ada64d62b27e93d1ca5cdcee59a4216d706b5a9b0000000000000000000000000000000016164f86f0efe58170600abe7e500daeccbbf1e9e41b6e625e8cbbf299c2899dd57e1196ed2f4b000549f13d99d7a8f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a208615ad2f10179584e03ffa40d736d7a4fd06508b41d08e2fbb7dcd03ec871d602dc8495d94c85b645d017b5a1c2c0000000000000000000000000000000002dd1cec0de565a72e47c655af94ed366747859c8ee60ff62c491b36912298dc6e753b387691fb4c71bc9b280fad10461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000266a685c9612d7f382b04d38b50ad4202944657d35b87fc0a0234fab5446adfaa431cbc9a1cae794997a1a32aee5f530000000000000000000000000000000001c1428e505fd1182e73aa962a9ee272996a708cfe02ac311b5c37faa9e0608919ed411cc3233074ab6f78b7dbd8df4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef23a87125937fe9908725d79373c80903cdc4ed2bcacccbc25cf5837c1179c9dc534480063ee0d5ffacb384205f9bd00000000000000000000000000000000111f0fae06bad6e524d00af3ef1f3347f46121a32f8d52315ff21789063eda4601ac3b6cd3acf33c7e52c71ee2cf4c791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c0beca26609f6ae5f6cbd0859eef71b4cd7d75511d3c6935a7eecedc0abe5da9789ed1a0be4dbc3746f9a82fa1dae10000000000000000000000000000000012adff1919439558e71d276e1e21f061000ab267bfb8423ff69a921c85ca5ad7ba0aa4f33e387216f0e88a410375ff311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb930cdc25aea3a082a4e291f04493d9bcbfd59610ce51ae1cb6aedf61387977d42ad3700fe0cc1cce37a570866111b000000000000000000000000000000000c9760228f5ba9c7befc6ef763d1017bc8a2a8988327df60f047a4a20728892eef0a21c4aa4fb73e093359078bcd10e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c80912bf79cbc32b4bb44a498cd463d77cacdd1ef3592687c96a03e28ca0700145e118462970fe0432849110b7cb780000000000000000000000000000000016008807e5de33b666cc573952649ada4643b67940b65be0f9dd54a4afa33b67f53c0c6c2bf5020ebcbafac048dbb7aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bef0a054f5c8d82a37b793c507fc0841c755a25f7dce1540441696c936aacdd292096aff26194c1311e61b5f7d42f700000000000000000000000000000000169043a4c3bd801272dc7e2425cd91e02b8fabae5345e331dd72fb3dd5c4f8e4a80e47d2c9f92e5ebe78a73c34e43d261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000452a5e4f04bf67257eabbacbe2b38bf6a950dfb08080fa7d7ad8928d5123a567e0636ee6da9b767098ac6682b79d5000000000000000000000000000000001352e89c105a085c68bdb04b05cc6abfaf29e28c61d960f884aa3f50b5417741d1cf1fbd3946625b6b7fb80218342f051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014124127c5db150232e88a103808736c202dcc63801516ebda06a1fdc8d7c7ecaa66d083c5fd830eaa907bced902d5db0000000000000000000000000000000007f388d2e7387cef0f53f9527236e12756db8cd94e785bb43dfd9f3c0916d51caaadacca6279aa175fc306b23506a4c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b65fb3942a3bc3a0da7fdafdff5fc37db4094e3f1cc7a70d80e094f728e587e355438a24e731edf4647d051550ba1e0000000000000000000000000000000010f97a12f00cfb30bf7c80c685a4fbd0adfb05264fc7c67f5c4e92c5f82c6f427335ea06a535aff38d98e8737ac990281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007539670c793d1b91f9234458e884210e42eaca0aa1668a85760d2bf311c8f05e1ce5a9c44c178d9f1c644320c6fef3c00000000000000000000000000000000100764d18aed2bdf55c3ec424a2af427be4391c5b523ba99c57acae456da579090f7a312f6fdf304c0bc777ef705d7401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f52e825bc139e23a7ff129f27fe6ee15cb3c7aa5d0dcfda2f405f689823d8328836380aec73c974ad9c9034364b55400000000000000000000000000000000053bce7bc8a15d8dbda96162c642cd6e1b69b7d2718d861616105a28abac2c0a784a329c4fe50b74413e0ca24ebdb2b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001110c9f83d5817a82e1182f6bc6031dc6112ec048dbfc0741d3df716b5ad2c206032a606e296dfed31ee1d93edc1e82f000000000000000000000000000000000089749512c1eb0572c867943218d24cd1c5aadfc610dfbc7a2c4e30e016d093767605a53a6824463971525fef1fdd7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181857afd7cc75aae25bcb6b5acaeae41fcd98771b9b1a1efc9bfc8cd3df0a7e7baf4311ca4411710651cfe7e451f7d90000000000000000000000000000000009bb95d0ce01fcc66db69b59555b44959d86dc01a63038018826d59240759f79981f3001512ae95e76eed6fbb508026f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019604b9d149ff4448a986e478f6c0e733d1195894439d768e3d65f7e5be36037114bf6801786641e82575a034fc45d7c0000000000000000000000000000000000effd3a2377bf0e90fe25c733e64c08471995ff6a114552998a84fb3791a103d8a07e71a5ab470e619a8be1e8a005131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bcddbec700e6706075a7d2d28c51b683ff8ab557cda780b2437697e868c92882684e7a285c4648465643616e049ff330000000000000000000000000000000003ccc01c5c8a9e09bf8029c8eee9000c1e7963a2afd06a090345f899e8b1baf34f9b2cfe9e8ec8c471a61cf075530d491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df0f041608a5da0366362aeca3e43a3b59de0d4b21fa0a37f83c2b006029f41d3c57408aabc3207d26d4c5bd2269028000000000000000000000000000000001487675e8946ab4942754b61a2edd145e5482956947e5a28b4e780463bc695481be1e555f837892e3f8f979daf44dc4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f02505ff355766385e7c545e0d5fc37339ceba0e6261d8cadfdf2c71d7d0f9e0385a12de1224ab282b115bfceca1a630000000000000000000000000000000013a1d1c03bc36edcce182f01582677e40ea178fb8505e4fcbbd73583514af6d100b6ebd608e4db06a375f80e59918a391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011800815b749063fe1f3da8744a9812dbec6b12f4352d06463ba254141473e6bbfe5ed94678d289b01463fa0602d4b410000000000000000000000000000000015d6b529a33da12a0c17a038f21504e44414d9ac2ac618d0a57796db1ad28e10e53b42b418fbac2f3476f12b3abd27a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec4e5d42ae2b64111da2f2ea314f311d03508c36fc4222e06c5822f737fdab113b32e9dda18dcacd84a576d905af9110000000000000000000000000000000002bd0f3f9a26f356a060d043f0e6fa361170e83cbbf30ba9ab57aae053bb827a38b17ceba8f766fc63d55fd5e9bdbc931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040b0ed65fb627d069d81b9b9c6bae97067c0823a868db83a0b31b722f346f21e2dbfa18aa570a3221ed16c4331370f90000000000000000000000000000000006f315db56b39689bc706bee757c67fd68ea0d782e74b64e48fab793e001acc524aa0371578a86d70be271cb59325f741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110afe91e7a6ed75249e80b1157ff9be5dd99491e0e4a0739391b9aae1144bde8119b972e887a7ce1e2093535eddbc3100000000000000000000000000000000063536343d922473984ff1518d678a0dff486d315483ad89b7106967489f2ef6ecc315cbf552168f36a4536d4eb7219c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175ac1ddb840c29a57e31daac52803bdc63dc860e25e2beb7a999de9ba92f3ea21035be7fa42fcb15afe5ae068a898e10000000000000000000000000000000004173e78c6b790631576ee36668e3fb9d9ab5b95b0c3c9e12356c4f5da0c776ed0efd6ec5dce57b5a9f0eabecc79f3251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e1256efea124ebeee7536fa67d52211cb2d6e21dd153b7b56d3c75a88ea13fabd44472774b560c827c773767bb5d7500000000000000000000000000000000090d01c8f4fcf382a9f3a7b9a384a878f10607371609c9ee6cc2fde6cbe52d5caccdaeb13b5426c2e4ee9628a1f109d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013e68c0d21448eb799c7b9a66152d2132ffcca5e86abd6b4af57893ada49a16306b380095ee2ba5b01f0359ed9b31620000000000000000000000000000000018a353b8cb237774ab89332c08c93c94dd45e9f1ec270102b0d055753a2a95dfe34157d9dcb873b5375296528e2b7a5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bcdd62d94bdfc9c8827f2ff7cd80d4542a6d993d5b18a2234761ec8ee11b4f4b65e18456feb9bbd826606b306445330000000000000000000000000000000001592c717f9ca17d96caadfbad9761c9518e4aa53f486812f80438b03466c84d2d797c1cd963183ab41db36c47f1c48d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000740fa9821228f6b48df5cdf277a613278f9bbfc5596da8cec7608f15c030f0617a04bdda9ca17347a614c4c460ae50c00000000000000000000000000000000064b8da267527980e4207c730f7c38e1b13fe3d13798befac5e60ee730eee77debcfa42490b6bf14cfa3a853e83271c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047360af520ad7d81a1c30b77c585bfaf8760776d0f5f4c1044e8022994c9688dea200e91c08dc40234dae1a016136f2000000000000000000000000000000000faefc86164dfdbc128d0072bb4d15524723d3a191814d9cd6eb25d34393f240cf6ac63e03494e40f79d9076848bd6f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f1a402a33fb33af259e6f3eb373ca148cc60f61bb46bb59dadda95282a73292778091541d1a63c8471d3a9e8682ebf0000000000000000000000000000000014a8c48feb5936aa1fec493172130d1363e8431174e9bca811546a6c53b881e84e2b4781a342d1b6954184a1b78e25761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187b5460ecce36ed8e5db02f204a4871b7b1133bd4c2182dd2d9e70f62e8e62a0165914dd3aa197f28860db9de6ae4900000000000000000000000000000000007b0277d455bcb423a917c9f57fa0b5bee51af6d96fd68bf220b0b27100d58856535a272b87163db2fcf499fbd85856a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9246004f91d44fc52129958618b36670d00e587537c5f3b53e760d56165a4b5f4d3371fe11ee3b8de0af2f610838680000000000000000000000000000000008dacc4bc6768ee62cb9138a33a9483ed13c3a3957aca9dd697e1be3eeba5c1d385376b12262ebdebc6af35d7b3345ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3ba1774e67f66fe4337746c0947c915cba9d16206672aa419df8790b428112fa2ff9be0dc2b945f223eed6068eb93e000000000000000000000000000000001246cbe76e597cfbd0fcbd28b7b576c73e123951ac44f74f58094d8ed4f05ba6a69a66a0c71be13d25c38da5afe80c231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0613bb9860ca07fc7f1949876a03f29fcac55ce46b1c9d486e9c2ff8e7eb8303269b70b38b0d62395b0c70b66d3fb8000000000000000000000000000000000ad153db2504c85637797ed9dbc342617afb150bdb593783d9c8cd1b1eafce41f8e4ecb16da4797569e36dd56b3665691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d5ff3ba7159046de97b10793137f49097db4459c099da627cdb6b91432cccae95d91995747c5423aeea8f09fdcb23b00000000000000000000000000000000091b15b4d1e3cbb1679f9956e66fcfd276d8e00e270cea26df5d3cd744bed003180d302beef8a39a32a96535569a9ed01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019cc8be6ed3bc6fb85d996168c3cd77d9343016b131312d987d2a063afa2aedd532493535090a71bd3a4557f64fcd5990000000000000000000000000000000013dfd6c33a326400fa8e5575a5f09887f0c90eef7126172789f52771a03dbd42e117c2d386633c6499e47c0cf44591e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d531d643e289bd33a114e91cc6805cf45fe09cfb46756d252c78e1c72721b3482ee58a55b92b3df8466a3e5b2c5e67000000000000000000000000000000000b382b5cbd7379675347f58bb9c9ba9df34b420eabef1b437bfede6923d23b68097743eccd981abaf82dd623aa13bc0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001318f56a548d8bb658c3b8486d1ffb90621ef462d832a7bffc695342491a44125e6c3d571f1afe12592b427e673551960000000000000000000000000000000005bff673c9a4fc9533bff8abf979228a30141a33647686213e08652d94af293de577e944b7def9db6482435e11c994bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190dde2e55db6b51380ac359ebbf71e32aeb12cb87cee2a042970e203be778ceda3b90a68cc2231460d39c6f38f972a20000000000000000000000000000000009985913290ebc4ffdb154b54c34e20b5b951cdbab8f4bc6d678f5a0e34dbe9756a95d951d8fac0ef526ff006a77c1151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001054f66a716aad2b1a08cadf2e0c8f430820761d765c6646afa93602a8b287f9add1730f307842b63a2ec5382587d95d000000000000000000000000000000000425d03c26fefab667ee9c2b71e84cd055e56499aa889f050a0a6eb256212868b1fe1dccb8dfb2be9782064ea1bcd71c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000b4ad86ea0164ac538586a337e425a9ecc4bc5bb762197597cae01e0c8468d33f58c24fcf4010ce686bb0482982bee0000000000000000000000000000000003f932096cfde9bd5137c024c8659b35d63be77d4f8ea6bfdefcf6ca04ebf143d550d1d830ed15d317c1edbd5eafc42c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f0cfc0cd5b06508bfdcb5718a4c63d80a261b8306d84461c4b0866794200bd28be233adf5927da1f35ad76e3d3faee000000000000000000000000000000001216142ef0ef4f3079860828467493f2e07ddceb663b97d103352e87b225eb24f0698e4050b062393cc0e93daacd8ad01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000129f3504419d86bef4b46bb46cf7c36c97cc6b5d08936c8d304577b691b43daf6d2ba3550e0d153e6718aad028b2c9100000000000000000000000000000000018abf4a9f4dd92e1a67f05c6905c1e79be30d6e201c918916eb13fb75346739449bab0ac86ab9ed51d30bc2f408771a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000970b3998896c60a3afc2e3caa70bbd75fccda97e2c20a815cc0044a73143635a693321ca2dd62b2f01311e9b45ec7e20000000000000000000000000000000012847e67ff8427e1fa065525ef18340cfb7d41c82c0c381be87a623120aeb075a6c193d760ac2ea2a1b2b935d245bc1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073481000bbedeae7a8ad2624b6753716a34f006af524eddd10a93f561217102adef7247d9c82acacee2cbb8c110ef500000000000000000000000000000000004758b444c59dede5ac76371d7fd30fcf0d34126cb768ac8ede356db3bd8e8bbe91bee032a3c6c07edfc95b3b22fde461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000def6ef9101a742dfb22d46f92fb318aff64accc19b93e009970d0aee0743f0eaa1f90c4918f9a37dd3d18f9d3b57f5900000000000000000000000000000000157f8895be634a8d235a50c7ba4c98666c2132d91451d071c89595e2a41c13072921764fa84812242a0f6aa164c39f311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d5aa79518cd9d5325d0127631e124a1a148b45bcdb27f3fa680d5e868e2de7747752b64af72786e70d008e101db0e9000000000000000000000000000000001894c2a988a99d578567c182eeb36170c3895ba71fb05104ac16f630e5d89bf30272fed3fbd008f3a0c0a48bb777b4451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c144f5c012d36ec58d75c09040429048e6a317c550714e4ba091b681eff493dcd98f9bb6a267491433e1ce995d96780000000000000000000000000000000009b3010abb7431240373199a50d865f1808b4bb6c55a7f65f7e06fc8042f3753b8b4a9f4075d3e60a6e9af15dbc357701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e7552f97296d60ff327a5b1e6857325b09f0dd5b6aec3df9c8e0ba061e9eabca61e072568ac0b885e20b6fb212efa900000000000000000000000000000000136807cc16f4e18c0e540915883bd7afed95ff6c9d10079fc2713fac90e7d4d43f22033bfcc4079b179fc77906d4b84c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbc60f948c2c733716702b8d0fe9d2fdc94c49104b314a94c5dc5dc4a278d89b814b4493dcc5ad47528f70a49865f74000000000000000000000000000000001901bc9c97ea3bb05dcf2ae05e6c2a38b3693f173c7ebc5d71d535f88e491d5ceed00dc049b6a47155c20549ea1edf631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018265bb96eda1b3fcde6c527836fe432b8b952895cd3978db66ba0aee789367e657ddaa68d9f0701412f6f05d1b6fc3f0000000000000000000000000000000003a8e4910ac4391ad9297f2fd7903448fadb9fc981b4819725cdea045d8a2b2ec55d71e604c40623267e4104d4221fa41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000404c9badef6e616d93c59835aa0f1d4eeaabf2127e5165fb78ec6eb38e83e4f6c4c6aa792116e795c854d643dd714eb0000000000000000000000000000000015b0d1e2c50f5b91c28e7da910350efc381dbbe250c4268e306914516fc6a30da073b67fc80b7dc87c55dfd83d9898da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160e2fa8bd979f815f7c045e61d82b7ed0a691d5254d69d8e7e5e48a899497f34fe0ddd3f193cfc5ee68a3b4eb544af40000000000000000000000000000000006c9f80802676cf98ec2abbd8ea0716014ded2b9ef9262ea19a90236a036c19750c3ba0860bf1ecb7c0e0ce0bff44a031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001538ec0f501b1d931a3d84306c3157e4e2292530df497de260559944b238ee14a06b45b630772b462a7571b78bc1e7d20000000000000000000000000000000006384117b5f0b02209bbf0dfa92b54f4e8e4d0a62d58e00dca479756094fc1c9317c42d7dae1572561edaf9408e52af11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f2a0a1fb45ec2f0b14460be6c09481e86da415a1c138f2f015ddf19dadb224abd6df0d107a25b2ca181b41fd524003000000000000000000000000000000000e1fa78bdf9f2a8f7cf4c04946b5cbd7ac50eb43dacdb3177d1f250ab8ec53a0d13af67d2dbb190a026db605626d4ced1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f80dbc50371743ea40d30377ed7eabf6830b786e229c5bbee9a7614b90481a0ee0e38e27d0bd803e12aeceef57289b200000000000000000000000000000000092dead05b3db300f709bebed4fc30585b65067d842da14157c2387212648ca945e1cc993db1afd310cccb478f2659911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049deb16851751c49459066fd1a0f7270beb6970e223a0fae31ffa3ea69633a6b8fb7ee9da6e60d4c5ef6f2db48f0569000000000000000000000000000000000278c1182df37adef5d388ce43cc07d3646b27ac5a5bc5f7a9b50f6f74c094f5cfd814a0aa8a6fd217b4f48c1ce853351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014bb7b73babd35842cc1ca65d0af68e0c70051a38f9ced716600efa6b517624930daa7546e4da61069d121b943798d74000000000000000000000000000000000b14bb1160a76e907de9df7452dc8400671c125e3e82bb21945212bd21a2e3f57397427eee5db701f13a551b2052d2bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112fa4eb5db97f269a8487069fbb2e03f0c51a70f45d33611e17609d1b0609d5e2baebe866d99fff869e39019ca1a80a00000000000000000000000000000000170ef4a68d0f5b60c4d9f6eb6b629d7ab71bf7fff1eafc06e1ee317c2547b448505d67cc96e1166bbe7e905ce9bec3331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c4ebcbbd6216cdde825be522e61a8625560e4f24be225885f9323ebc3cf331e80f18f1eba286f761314ce2ef2fc99a0000000000000000000000000000000005a5b803adc0e76f524d1d93a5d99a988e3913489d2009394da5441d69db213466c6ffc53c9070ceb7321de77b4761f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128578ba01dd688c1e6cb12492a288afbd277072d42a15e81cb54f3853ee5131396e5415ca185833f19daec396b656a8000000000000000000000000000000000b42e06c9404da6e7b34b37e48c9b8c1168cf4537fd59ebb06e3d990cccd348c1c49d7e8ff2536843c6604854e3356321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001590520725d5dacfd807f0e9d7b90046a5c506e6541058f0611d1f7d0ed54518f7339069f816142de77bc78e1ce1956c0000000000000000000000000000000011deef3425107a3c0765485c9bd3f399dec88eddd9040d8562565cfb55715178699a452972795950fefa385db5044a831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063150b62411d859a7d76fd378c67403478198744032ed2ed32cf3982fb3c483d1286f33af452e9191b166ea7d13ea3c000000000000000000000000000000000be24bd912f43cfa1566a427876bda2cc462fb1e7f1f5d5421aeae495438dae106365efb5d68b42a3ea67e083b70ac641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183abe01770dd743db6c40e46f9b263a00c8cba950224c8a51c897a92c78a7798b0b85ba59c404f448be395901978fed000000000000000000000000000000001927776cc278f4841734e4d3ce661fe843e11d2ab134d98c565fbdf05fa179694d2ce841e80418d70126105d3c10442f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001448f7a88e1790f7fa989f2f2582ea6dcb39dc674bf404032b512c9f9588000fe9a9795d39db6cd3add1e31b21d8c44e00000000000000000000000000000000193a24d86e1b707273e640fa98a2a068ef5b1b662634df813d1ea87284396a1a18ea634b8934a0b3104a0f1f2bced2111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9fb507acf4b1bb575ae952ed84d5ec4e6a29b5ea24a897753b90d49db1886397dfae349856e0d2e69ef09c4f28fd6e0000000000000000000000000000000007d5421637f5de504eaa49c22ceacfb8583963d6f10666e3a0d64cdc57ef242d93cacdc5bd86da8b9c2f33c0263e06d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c453a342e940da4e0c4fafe0ab6706505248ac3a8781ababa62d3e47d747ceda2ed34ea15b76315fa50d9fdd4c36918000000000000000000000000000000000e326d5e2a7e70e8070cd9c54f78f1872b40786f3edf6633779bae6e90efb175356b9fd706d65be84f5460a4b52c58841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001652ddeafcf821253c148db89a648d830ad613ec0ff6bd602935547ee1cc8900088dda0fcfdbd271debeb7ba8b31ef2c000000000000000000000000000000000753e9a5acf86af7d977a473daa5fa6d27ec934513063f16fda5a86b512bff702ce1c4c34c542e69603158c129c89d121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001948be4f4d88ef5c51013756c53451e3fce7326c8623d58ca4afbec5bf8d1a825a461d7b39ed6a8224d534d06c6e32000000000000000000000000000000001579ff5700907668a9a1ee047f1947413ef9546696adce370e32af316b1089e00bc61b27ebf6433592b4fcd97640a51b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cdfda36069d8ed76eb4cea657f13c1489f5ac1f8e0f62bd214ce24aef1245dc1453d3c45b827ba38132abac0cce8263000000000000000000000000000000001625f5dc86acb1e58465f3f44cac49631d63755b4949ebb235560032f34a0c22b68a3411aac826d9fa9d8f78d4c746911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091aa69660689333fb60a38d105c443462e0aeb49e6cb59c47080e92093a2d824f1f9f0aa6a2c86fe50a4e8d9942549f000000000000000000000000000000000ff0f77b9a6a6138951ff811008008d62c1020c30b2ac29e635eb3ad753f2a443852ef3c8ae63b816d0be327515a35be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128562158ac53555989e3879e577e7a97a99e1758b68bbaeba5880d6d70592ba60829554bc1e29668c5009d27a728c230000000000000000000000000000000004abc9d2942359c1656519e885154cd0488e7a5461f7c924e771648fa0635d8978cf18cbef8a87e708218215d10f060c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ca203f58cf12faea4ae0e79ed91f07b3d4075d5e524919a92b7a411ebe4b9efdac5c7f19c2d3244b4d9d9134361ca20000000000000000000000000000000014f6c0d4751a6781324fa4f0d152adb9329f22453a7fc27b50632baf8d9c5713c9996594ea883964834b2bd379f46d8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e38f31e1ba0a15720d569041cb751f885808a195ba4016f5e1e9d8e39783c813cd0826917ec9334516328a56327dfc0000000000000000000000000000000003146f4d4325f78021c28ead7bdeb307a9b51fac79f342c29cbe79826f9427651bed51c8c25ba006e2ceb1dcb44b0eb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004067519e8ee71cc8bbcc2289a1a22472ad758eebd26902e80b7885852b9e202421f25fe7f3ac21c34ae0edd1ca2dd72000000000000000000000000000000001847709676a8d44cd1d60a3590e558505372d929bc95d93642d0955e68b0b376eabedda257280a552a7ec3373046122f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000046035d172dd7cf267880286a3e8ced2dcf16625f912da4e8657244a1434844205f1d72ed6e82ef2d714129b2973bd9a000000000000000000000000000000001050ca3bebcb84ecd73d448f7d9a9d3ab8253618450e6654ab68d861b58954d8c5f5f5752171f357a02e4d6aa1493eb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a71b78237c4e15d8e7a57bc4113e9d87a16d0905440c420f8db7fd5154d4f2b77387317060ab556db85929679f2ab60000000000000000000000000000000003ed16459ae558388bf410b41ece27d6bdbb02501078b9b46fa4065b664f8e08e051974b2ab2bacaced66a3ff2399a3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001705fbdacba90c504a414796326cf867e0b21bf959ac1bd63df2adb5df983998667324049bc302f13db07b6d27b5a0a50000000000000000000000000000000015a8b20341a2bb1bb4a7aef8614c8aaf7b770702a31f1db92596b650bfdea873cb62248b41951462e9afe9fdd4e1d6ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010aae2d94fc6595293fb63fe20a6480f3a8403ca2f47f04543f461a414695a86f1eff0fe7a603631cc7a8a0cc503d04200000000000000000000000000000000069c867a7468268c6ebed32222622484fab001b01b51dec6d009f73a8daa879ea572faabbdb21b6d45c0be0753d5a1b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e885ef239df6064c88a3b219ad40a8d01a2e02a771b544f2648582e433c78fc8714dc3b22be4d2ac01d02498debda100000000000000000000000000000000115eb97d959b55cc272f3974b2fb0c7954f8512ef0a95064ebcdb38db772d9946bd4bd0a8941ec59241faad65b19ca591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041aedc786ab8dca9a201805814bec8ca6fab1ce90b2c6571f398e312963a4d9448127cc9c485faf4e904af46445bc3000000000000000000000000000000000106c249bf9245b9bb91bd7befc7c69d397c1d4bf0a727057ae9801e5b2df23c698b1369ff6464f4f9fc551a7e333d34c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f64069c6b19172a6c92a4c492faec713a11b4dfdf606fa4eab902980952eddb33170b77056506e5a676b81345a7b7d90000000000000000000000000000000012f828b349d974dee88585a23bfa3ead4aa457af004793f86323653fff8b7640675db17b34080ad68df8fc784f7817151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190daa8593e3ff56d0cd389162cc472a091386fdb3a2a1a503f86d89a1c31f3ca4ee7319cd12bcdd22ab7836957841dc000000000000000000000000000000000f69c92a106b6c8ffe1cf0643f507af0174721bb4c44db4f3eacbe4280fbe24e2435930d768c822b3a4766dedc57453b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074954f0da7f196fc65af579cb7a649d639f1a820b48534169ea7d2e9f6c9bdf685be2e8e2c230e77a9a818e840ff6cd00000000000000000000000000000000111184bb532feb6bcb2da352c0a273a383b232e8cd8ee8f4e92af0b640d311afa348d4a0fb711c228f1193ff940409501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ea7bbe602058c1e4e43e5844ae21ecb809e6024c477fcc03eb0e7a5fca10fcaf896bfcb4223ecaa4de2c9b5ee8e14b0000000000000000000000000000000009992bcbef9505503d29c07e71db857707f3405a7a9d16765975e51a5effcd10aeb529fc3b990e220b6a2380c7ac4d341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ec149ae811524bacae845b2b36418ebbcd9f572995a9ff11317426968d4d19519aea52e866f10eddeb5a73b569460e0000000000000000000000000000000012a88d14b708b6f5e42bb6cf1d70c3f400df8937c6c27aa0bf40a582153bd2798187a027bb09a38a9c9eaafcb5b948121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183c8ebeb011134172f5e1e6d74c769f5bd50620702c72a3d73ecd014523c505feedfd24ab7b14a650873f8c9f8566590000000000000000000000000000000016c5f4c83143f67aa6f4a4110cf767f8e61dc40abf654dea54a54ffc3a6fa40227a5b796eb7a16f9f2d965c0cb1981cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de3f7837bbba918ce0326a773e2904f08a9403679562f46b18bec25786baa32f274f61a7cb2a632183db698e3f416c0000000000000000000000000000000000d84f5a218a5aba7dfe2b44d9364fc4d8c68bfb28d619e159a6dd1f0811fb3e1aa258281cfd3a83dc474ef0a45e06b1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001700f9453e0b7fcee68bb4d5dbe5a14b990bfb4cbb16ecd2fbabfd61eb6c301adc08a1543b08cd0d650b55202f2f552d00000000000000000000000000000000119c952aadd2be608400e60d49519ad0644ee4b5ed82a27075bc79c9e8a72081e7886160ff58c427906ac87341d22a051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000003c0eb1396eb5d57e0fbbedaecadfc791b002f2ccfed2fcde2081d132e1ebdef082f41b243dd0aeb03daa8012c743300000000000000000000000000000000018ddd528ac7a9c32a9bda8bdc93ab3f7700946859d5e94533694c09b63b2821d2fbc560ef187b210b1ee5a55ba72a27d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6d440494b0af2bed95ee0833dfea0a624b97ddb2bf3dea395dea1fc688b76d8f2ec54bc0421c6baff4ab47eeb3decc000000000000000000000000000000001346400505d27a7e01cafbcc4a9ba5351589da2c107197a945a16d39d8e9a4cd09b5d287702fcf6c6a7860c330c175401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c4dd90ff36976646bed1cfbaab176bff5ea25dcebc1a59be65db11d7763000520891a0bae74ab7a38b2463ef04d87bf000000000000000000000000000000001618cb0eceb117e2e46b5f49563bdb5cc9edcff0fc2b32dfbec1e68cbcde4d09d9493f6e6558447ec8cc5d3eea7b8c091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018afd1a009c293139778f073406b15977c77ef96ef377ecc5f7e757784a32cda917f14a305062bef0ca0356002970a6c0000000000000000000000000000000017d0905bc7e07943f0c7ab2ef00410ee6f08115ef06a7bd5d258890aec39ba1e98152b45d202c35b23a995aa626120351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ce87242957009efd36e79ab13e6261bcd1a68c678fa723a4dc3ec30ef37a56f44c0756d9f190802507a8f3e0fd5122000000000000000000000000000000000bbb06e79570bd3389479f3dd193f96778572b8c77c68f8843ff4bfac4baf66d26a3c50c4fea3b6bc2314af35eaabe4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eabff10f2a2c2e84201658083a53cf673f33747e7079353473c53e8844462aed9d0ed3172ac75af36b03c15626b29280000000000000000000000000000000015ccc21fba91bd99ab5a2c4963b1f39ae85c1dc5a5e912239d252af6b1275f2db78b4d81c11032443f4704942e57d2751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a38e5c29411815846d9289773a80275e47c735ddd28f7ac91d5b0eeb6e295f333e973ebb7c1c487083a41765e47fc6b000000000000000000000000000000000094f0c6cbde38e264256fa4976968436ad2eafb3ed70c9e0ad9e4852b2b02624efd33db61628c7ce78165971b4ef9c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e747178b058dfdcf5360c465fc05fa210e844809c28304a875fd14c067cf49197c93c3847425e0974b3b2c1c420c5000000000000000000000000000000000051eaa2b2773af3a4bb5bccffab1d00bf7108fd875d5c94d439967daad7aa235797c2ca6008000b70ce26633e21c72d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001062040cf5e1274682adfb86b8616d73546160a03346a9c9ccd27836177a4216dd6a5e4b057108335a65b7e80c559e61000000000000000000000000000000000f85729f0305855c575e9ff7b6efaecdfd58f1db35ae5e64cfa2b83873129cc17c9654bd6596d1aa174bd9efd4d490c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194c6118f8e69220d27c2317a2ba2db3d50eecd107f85acbc3bcf7ed334507920f6bd3761d70d316399db451cf7ec6d40000000000000000000000000000000012026ad1bfa0bbd73c8d766b70063b89f44846b4f12084c49f128f14e85098ad87605cb4185032f5a1704fdc566fd2d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091e62ada7e651d558a58da4fde22e49ee23fa0e8e90afc9577e86447a54d6ee0beb372fcac90e68da3bca36aff67a2200000000000000000000000000000000029109f236fff7808e09803558d443ecf03d5a637a22baffeaaa6a15d6b6b28bd50f192515829996cf9accce73e91b491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b41373279827efc80412515f56c1b69606153e61f7442af0ce9f32fa0a20a923f6b90348d1b8008cdce8f3f8c80bcb000000000000000000000000000000000b08f23c875f8b1360648ebc2669f0235f5d4a35d376a5c7c67a45b9eeed8b2c8db750c8f0064c01993d4bebc64242ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130d345705c5e950c89375710091da73bb04ba8401335d150b8c843ed88153edcb099c2a2f135aee844b057935a02d5b0000000000000000000000000000000005e9b1dcd6e1942627a76a68edcda212818d283756efd9e45541235ac4f3a5a4356db7006f8601f7c713400362d1c5531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008432db6c86aecbf88c13221b7d8d46a6d51b1ac3d629aaa57804f5333ed5a438ee1dd4c47238169c74c2ed008755a8b00000000000000000000000000000000168047ff280a9ea7e02e2832700121cd61db6983af941d46b47de6d90e0e1b2f69d3ee038b330ba4643afe00ffad40371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2684a6f30e95c1609fb48213baea58d2dc34756a6768bc5222350bbb7c8f2308da3c6589b32ff12677c7e665f537c30000000000000000000000000000000002f0b18c4eb976c147dc356ebeb1d81b88a5a56c0f352df993f024deb1a91f47a747491bb83fa98824ac26aee19eaca01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063ff43dac0dc78fa4b4ca5047c4a70d9a716d7f68903b9ff3377f70494c8db35b83d22c0e718352d411839e8d4885a800000000000000000000000000000000085d88eba08500813a5240a64fa0e638fb37242c4503701384d49d62aa87e9ad79a709deb2ac5853d241cfa1073caa5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012522ea0e13df61f1d9a4c628b5e17cb15fc850bcc9471b7056a4cf020882ecf4dd290bfe643ef20aef17c068aba6ea6000000000000000000000000000000001393e8c0742206a45e0f221cabb38a2d383e1e864cdb660e4676da56fbbfd38ade70490b0b41162f902dd1667b439a751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8bdfcbaf7675e0fe270fafc17bf6440366c2f62e162267825c850b64d7af7272ec86b7e9e8d9df9a1aac642cea4769000000000000000000000000000000000a40c6e462aea08702386860b7193ff8377c2c674309b915bbb8ceea7632a0781f8120970234671525177730cf7cb2421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c02516a2fc738c460b4b5105950f30041d55e81c905404c89a4cbdc48f62207a46301cec257237bfbb9706834d2756000000000000000000000000000000000a13273590963e1048f2fc46dec82d2064ddee0a339a46ccf0db3a0c0fb246db8a0047212c2adf10cde5b3ca07da8e261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c3aaee4080003971ebe98953c20158ed1cbf123a41449ac67da43358903add6bf51b54312928ed0e47389413d5a1a600000000000000000000000000000000026a85acb562697c7041e3cf96a269cf54848719b07f919d2e1e602f443ad76255eeeb7e7314640d36c85280dec22d401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018503e0071d3c8dfd7e25f74a8b248b9d4611c9bba17730d94c0637e40486ad8acc75858edbd26ecfe034059bf43a020000000000000000000000000000000003aa2b335cdeaa14fa83733434afa028460f7ccf1c7e84c8827ae1b763073478395450e39d9847a8f6b2c5b13f85366f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078604a999bcbfe5f60fccd2afc5e2b60b4275fe90e385a230b54e28a4ca5453f4ef8af1240d627be0be74235cd833d90000000000000000000000000000000003a9ac7682d3befeeadf99fb4cb75a5b4e6e709ac22d94cc09452bfab631087728c13db99aafaf61feef38b9d06bcdf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b947081e4ab6278b5094f71530d0a04d094a9edd24fd35586e457b39b11acfa944eab65526cdb282eb9500400e2c1460000000000000000000000000000000014be062ea2dc13b173ab950b0c943df48df7ccd21390c6b0098d80092d4bc165e5b11352c0807d556b6d0970d315333d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000104e4e155f24e25ee1fa6014a7d967597dea825d1d37b6a048eba64b498110f0f93a0e9e45a961b990643568e02cea30000000000000000000000000000000000a0d2a8e7ca79c0c1d8ec7d35dfd19f66fefac148dfc303d0d053fbff786ab33629e735bee042884d45cadcabcab2e141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178d98bac763b8409d9743d14f5f8350a00079177f83b484aaf6dfbe8121c8322878ed323e02e4dfebd2c75d682f80ae00000000000000000000000000000000058236bef349391bc836504eee4069b1fc5e5c5ecab99c6f797a1c1cbd41cd44768d392324b8c0d1697862de7379e9741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7177aed94cd16dd91c490b20dd6b52d6ac5b846dd586f3d528a40e890c185f808c3c9ffc3d574a96be5ca2e28a15b4000000000000000000000000000000000cc48a9a1bba2d7109c8542b93f66aa7d4640c6d129c0a2fe7a5de4a08a637e231c6ecb7c624e6c4f430600c203d3df71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091bdd84fbcc36a5a2ebb1ec02469480367230791edd6655440266e16ac69e0094582e6f26541726b95fae04d77c1bce0000000000000000000000000000000014952e5582d9e639ad106133d8c3914980ef2cf109977fb5eaf9e0d0e539db877320298cce5002419161767fabc678ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000312dc4905d50fe3e0bdc92b61a32b38b8a7c88bddba57532c2a3d34efad3502c174724983d8486f1a2b4cc488eb13e3000000000000000000000000000000000e336a02518a109524cfadd8bebf3a1bf35e468e6f94ecb575c4c105d5079a903566ec2188e70611867d68c6192da4141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131bbaa14d4d7fd46e6c69b4bc5e70ab98cc4eeb4aad80e522ec2a5bf568c8f78b20563155e180d833624c354da3235b000000000000000000000000000000000b65c30282a38ed95d3580f74f92c845496753aa8f093f79eb56a7fe2cdcd364f276bea369b9ff8a899e35ef3ad4e79f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030444fc22c9e353f9764bf331b168e55c03f564b2bf1f176500b78b47e65f16a2a095ed640c3a280bcd5cfad3e9bf4000000000000000000000000000000000031c3013f51cb5663b3b47c66f81c132fc95bff8d23f9442ac79f87bb638516455469bb9cc3dd7c9a97732279041a88a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165bf1fdc3fb5b1c9e1acd80a33eee7d9f15a0224337408b13571f6627374c6b523680c76b95403d10a9390b9aabd55e000000000000000000000000000000000d3ab62bf060348463cfdc94b6234a23b7b5934c1390d8aa5e075ab7f7a15b8671b47bd2b532f4b05b6e64caf9685b231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2550408fa1f7e5d6250151038aef9519177fd329fdb7436c25c04a833d859c868febc13da5824ec090a8e2e789950300000000000000000000000000000000141837a401c63a4778654f815ed54d85dfc61a73a61175b3ea4acb7ac0ba3ed8b506d08f302b91b5ce9a303ab795bb141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165779fefe916c61361d690ce281a37b8dfe7a0568014c56088881c135dac25c9f1323753410fe72a81f276596faa12a000000000000000000000000000000000d29af555f18f8717fcec1a1ae023bb0a8da6722fa94e0e54c6ce3ba424b2de0cf2bf08bc5bf594cb042fa43cc706c5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005be40542e14053360b3ac551e38fd1482f5bd5224ebe17cdf71a46836c5b684a82fdd606166b019633461ffda0f76260000000000000000000000000000000018b77b97a0aa768a53bc2853a897aaa2411bbf98a9169ac6734891dc87fd0458613cbe9d5156c7ec77c42f18689b9bcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067545b06140d2d3fbfe3aa706444af10e07a1efbc1d4f0569b37db00196ef73a26a0f126bee93b70bf15c40022f53530000000000000000000000000000000016cc9942d16a7ef6295c13200cd8a9afd97c945b09bdb54c2eab05c6311d92772d598d9d246e1356a18a5da4aec25fab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011264c8415e3ec6b5bc743745f4ce84c6af6474d5b6616347b720e9b9fb89dcc782995c626c76ea8e061139ba8ab9a1a0000000000000000000000000000000005d7c7be4c2090cea6cf05063e31230158d96b2ff7b96d9831babd557285ac090abcfb213c3d52903b97874751bfdd6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005475aeb243b9b04de4a22d71e5711308f552408e6b6f1c76730e6b81fef3f0ff3bf79778dec8116b304c864a32f6b26000000000000000000000000000000000e3c31a159e8449a9a100760ecead5ca79af78ae151d95e12be5979e9d10c38bb785430765e7bcf38b702a61e5bc8a181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b924090f2389f6b3f089dbdc3d98c361fe2d425274257addb8d448015fc6b3e6088ec96c1c40b6d4a610b2495f3e810000000000000000000000000000000007ad7d0a06c2be69f7032291f0895b93b22623d996d1ea1f976415f35d9a70a0c458562c59ec5fd13ae9fef18ee9d5321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa32bceb655b5c832a33a0405762a13491aa71f57b1d7b2a920b8abb51870b34b2e6161f51f90ff9b4029216e19397d0000000000000000000000000000000018c3ede1d4ab1e7e65bf7b15b3e4c18ac4187920249fcf5057232df37ba2e40b5a8cf0169f1ab6b508b1a0834a468b081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015af2cb45b9a9cbee29c09b3aa2207557e2a7569f77e6ea7bd38431f5d8a591e3920a654292cb406aaa888d7ace525f0000000000000000000000000000000001985f3d8df5b0d98e34b711abe7195e54dc5e98578a1a178a9c79512577f343eedcf85daa98fc24d93f1c9d5a908dd091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ada11d3798505a5a613a17884baa67b71ce1235fc0649e1b5a13b5b55fc4df7b95303b6aea51a7b346157a44076adb000000000000000000000000000000000d31a38cbc46efc66f80cb46c872ff7e1f1a6b7858fc24bbfc676a1020a22f7ca65a093278ff89040c82c71e35f598e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119b9e58a4444e4e9e81ac8a69d9ad96fc6837135ea845daedd3629945b01ca82939ba1fb0c300fac47ffdbbc65a770f0000000000000000000000000000000008394b6a8eb77d7d1936312d7d09a77d736b40269b8ca7611c31a7547d0f17d7b11a8b891e6cca952ea41f4ccd77bb0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016686829189e32380c1887b4d93e04f1f57d257db3b79e36d9293a1401a3005b9d5cbd07d0fd4aaa6e7a0c2090ffb4ca000000000000000000000000000000000dd781e58a33a7ae65cf9b9462b222f289c9a48845fdbb9624c122d7fbc7f096c7f1f9a1511adf1379e126cc29650ddb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d42759f4b3eef0a64c6bf891a6f33bd9eea5263e69a86721b5fb2e6f0dc9ea05fe9b5f984005836a2cd6c3be18656f40000000000000000000000000000000014870d36acae6ca33f8a519fa37d81895c7eebf0d203c41bc221c967ada57cc1bf8180ed9cd177012667ca4a0eacea551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142f74f20258e07e91f890f4db876d5be7057772a9262c5e67a3f378d26cedb21493a442aed3d05f05427812842ed880000000000000000000000000000000000adb2c79b6951f1155cdbd12dbcd548154ac5fe369205334bf6dc366b753440f0555adec4815605b1b516ee79466b3191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177a0f3b57e86909aa4ddc39d9780acf35f8e085bb0ea8d2b5599ca44904a737d03d316f4e1456d277aa79ff2e95a102000000000000000000000000000000000fdb19590aceb7406b9960b69dcfdf8f6bf1dc942aeecef601e375e5e00bd95ca283fec78ad7f31327de97301613cb431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035c14036ff867bc40d1e06697e64c6d1e2f712ca7c9a012ffc4ec8116ad66fb40d94ba463d6f8664160cd88208710460000000000000000000000000000000016ef0067524d0277349302fec0c12fedcd878d13d0fff211bc65bfa72ff979a6652f7aad552b308fcd4122c278cacdee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117cced5032c03ccad304054cf1dab7fbaf3139a4c8c918aeb4bedb8876be1c0a293775367f993308343cf3a4777fb4f000000000000000000000000000000000331daa33caedc1cdcdb38f47cae790a85914cf854a0fbfbb92ad03cbfe428b311dbf86d0a24fd97af29202d6b73d8dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010297af9e5a061f89190a3bd7af999af98f846c8e1ea04903a31a2c9b51c4f3feb190e169b2afc4a4acf4286e8d43bb20000000000000000000000000000000006a03be46b0534b4bf4cb2c0aa6dec3a12e5405750c8489f684cca0e03878af2e0eba7257ac0bd6c4af53aad6b1761df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120d7034a270eda2921eff3405281e42f76efc013f4d855fb232d5d6f3f9a1e291d38a39e07fe766f6c0e942a6ee6aed0000000000000000000000000000000000f652700229831a0ff6511f83726de98782be1c6c2223eccbc9f2bb25161e0c80010c163610a81cea686cf56c9976721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000785864b1a74a782d2854dc50d7f0b6d3cecc344dca0be1238c0526ad4e6c7f56b00cefcb3bf5f46da5ca0620bd069d40000000000000000000000000000000014ecb7fed008ede18d2aaafe3a5ef90453d1fa18e26c32a23ae53e357f461c63d8fcf20e281f7477fa0d475e51bb5cac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3d906645bb06b3e7875ec0110c630a355d0423cbf613b8c9ae435fa10642383e502f05206208a26145d7d9ce3ff1fb0000000000000000000000000000000012f88c7b2a1351a2cec61bf5fa824a2568845f969e22d8b0ea4651e7a10c306160636d7b89fb2d4865e761108b96f5d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e61e2a7539aa200c26252d3cae80b49d6d694c7f2ad7da45cd3a17653b73df295d85ee924680e0f3f237e1247445f4000000000000000000000000000000001704f6ee513f7cc07dc2dedc50cd5cc8df5b7490a132c6a5be2f50a972cf985f06cfe6dae1ecae46baa3997b92d7369d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9809bc703e6637438eb5ff2910ae3aaccc637c73cb2986bb076b9451c1e59e8f585c207cbf3fe89917e9bf104c3dc800000000000000000000000000000000056c847cbcc3d2826e3190d5ff03b7e2fd74c862aa38c23063756ab37b12c855d49816f1d2eb8774e60a5ab806a41a481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8e3a89454f4407455144da1d3269e8f0c2d40a0301956741b5ae1eb66811dd0cb9e8a80c47fc8e6c51b77f6509a2af0000000000000000000000000000000012127381d513a5e1fef86a6811c91785fae288337af3fdb247af5f4e7abfe19c8a1352390d490587c9f484b2be0995441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031084bbd4eddf5fad8cba15675c53c54e82be30438fec449df904efaf4fd8215e07be98c80bfbb483be8511b3858c9b00000000000000000000000000000000009a9a023a4158adf85f2c7853026d693cfbcf96996da530f90ab890b0225770ced035057cee431ce9f7bd2846b259601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0b08b21b24fdd8b9daa4b0f7dce27c78fb5e6dec6e2aabcf434b7e3943fd51d5574c6e9243c83bbeacc49b61fa54ae00000000000000000000000000000000153b7d3ce0e8b42521d00a5459db91eda13bab60f878eca9a28c5f668b15565f52e897c506a5f238591dec9fa99839d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128d189c8e3d41cabbc68fcf83bf58f6665ad836719d52d21e7499e7b121c3202c5236ea2a87091ee7e85b1f14a680b900000000000000000000000000000000125543ca2fc4a954f6be6dca42ef87aa96f1a07793bdc1404369945c6dba1a5b163e01d8638e14b913542060cb5369a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001790e335b2283dc7f9390347fa45f97da6c790d1f7024a39def5d709925c2ffe67bec7568ea5b850bc72cc091ad2956a00000000000000000000000000000000136e7bd1b776cb436994079c0cd4e70ab5b01b78282b423762116f19b16b0e3cce2551f1e78703b5412c48d156f1dfab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156b21a9811e880b73aab79b491ca78fdf34a6b8cf11729caf9925e164fa880e582f563aebdf7511924f545e8e2be4f700000000000000000000000000000000157a8af9960d525e718bf4cbf815f760db51bcf9256060718d5b6664cc436e1d5c2f640903696d8b5556a6bb8da4f7d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4e274d226fe6511adb8ff4019ec904adc75fe70c4d54863f30188a7fa1ee7990b22bd39a8d6e608859d7e68f173d8f0000000000000000000000000000000007126497247e941d46d9634abfa9e211b390867a8577b28a1e475f4977d5fc5aef73be339186f65654c06baac1e895df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c3a0f8b2dc7ee0a045b4fd6b5bf58f89166417211221a064555bf94b5cc95c41614e3671e3c0415d3eef6eb5a4fd3000000000000000000000000000000000081586cabde74252e5a0d6b057e28d4a2915c8106fe31a38c96643573de8429865123b627246916d0b3bce5b44eb6b241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d09404447121503c1270ba6a8e9563ab0f4b4edde0b6792269985e357523a5932b584ce2b38b388fa8dfe9de6dc6e8b000000000000000000000000000000000d469afa64d6b74214eb6af0a35fc73954e8127129dee1bd8a1c5072db1165a26f8a50f91e0216e0e0292edba49ac59f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d59a79ff88bae650cd40ad984f8048ae1b1488dfbb8ddbfe1966c9690ace1369f3ccef09b14de5f3825f12758cab98b0000000000000000000000000000000012d336b5f0fcbc3eb7bfae5ebd5d69fce58e335ae26ec81c99764dba4262fdfa7b53e1d5d55996deaa1618d240497d6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000140021d531ce1194b801b2e92e9ec096f74769062643120eb65d031cb38b13b28b5f55c73ab794e75f4cac61e84dc54000000000000000000000000000000000ad74fa287d5af2c2467dd101ca5b0b69e09988682f424e6e089e1ff65c68ba651da7a7291f180192e6bfe453e12c9d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e9d72847c0ce6c6a9d70eca36048004dbe0ab579d37431cba92f3a53b4e2c830aabc3ae431839721881f140f40a81500000000000000000000000000000000078413deae4ffaa019fc1be05a9a104d5a7c1384f6d64b59bac69abc22e5f7641644a40e834a4b9644000dcd50f696cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e80723b788640da8190c5540e3ab68e107e37791be78d4b0fd79cf41b523de8c0094337c09f02a0b9e46a628d45b300000000000000000000000000000000013104f5470f6de2b0a6fcd1155a89448337a06f00497c3e2f9a2747e976ef7f5deebddfd03191ace9e5c728aa498a9501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013231f3e1a15cb8897eefd942ce289c23f8a1aecf5361e7317b0758d673c9adab6dc7b1751ba455a8be1347698681ef000000000000000000000000000000000c9d9e3a2f8b93e677e12e13750672ece721e2f359c20d161b3703655180113e73d9092882d06d31c1a1b5d1d6a81f951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006783c20da9158a57065c6e050b8fcd9b6995e73cf4800ce1ec811b8812ec5b7296b5e2f728dc239454e0aea8e9993e50000000000000000000000000000000010e8312d7fdd9119e955e68c59961c3b932a94db432b78922898473cc5a26b914260e000856072f777e49a5247839c1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005efccfa80f98d4504f8c72a18eaf33aca8df5117c5513cf62a23f29fd6071842f2a07cc1b17c86504410e34b8d9109d000000000000000000000000000000000080be0dc25c315824bf4bf22243735f2ac0579699a43bbd7aaf6e558ca889ea99278abf26d360f633ea1ea2c03f090b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000553a939826e4af9d5aae5158c66b3566d24adc76ff27333c1d9937d599211320df9035b83df6c5073d47669611ca4140000000000000000000000000000000019d57b703c532d26a6e8631017cfd183063dc77ec67cee1f26a13025ab23926ad0c913acf5932af05a42f667eeae53ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000965c90b66d7ee3c9fac25501d7e208c2c9a98c95daeda52c65e4b3b0ee832a4a807a88118e0f773b7fffa663679d3960000000000000000000000000000000007c9a4ae934d1dd89dbf4e05bd9ec4172984ac3355c926024a240bd5e08d9e423b7a1eb7339a1db263cfaaa4d1cf09dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c5f40066629ec55cd7244c651ddd161efd549da7171b7cca06e6002e613bf723b0eec2727165d4abc33a3d9ef2f34000000000000000000000000000000000135b50049d03d04215ccdd904fb9b41f7849f451f7a049bf02920311f1887b5e0aa0f5517d295d9ff2386a263bd010091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005691cea3e9f22b69389d7da82a897b5521269f30cbf0721b38809739b513c0b3738aa5f137d588ec10f870e6dcdc55c0000000000000000000000000000000009f1ebad8c281ac9d403c81160a8830329d7859e159bd5389c925abd78e2a155d263f530d836855304674e47bc0907241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002eefacd7ef50eab87d65d99b6a977fc0e1a269a9a41e5d849bc129f4f6f200fa6153aca4ee3bd0c075e619a9dc302b10000000000000000000000000000000011e618ff8ee5efc5cddcc51615960fe38b898ef0fad0e62f51cf41deefb4ed0212f4f194cd5f4fd1640871b1e327071a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e98f75b39919e90e740178101df956ce1967ff86f7f6e4a1d4c22ce289bc096327e5840a02328ecb1f886f09bb8bb0e000000000000000000000000000000000aa01cfa40683b45a5676e986803b98805aeb8e35a10da72fd6a6687a54b37ac1987cd24865db979ee8175fb59d7bee71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037496e21899a743491622e4b70ec76d12248dd1956ce339e130d3ae1e60e773fb87b45ec139e8fc31a9da4c91de94d2000000000000000000000000000000000a11b261a77edd34096736f9ec19f77df3953a1e8224f47468affcbbbfa9e32463b12dfaf5d02171f2fd09306d694ed21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000871d54bfabc3a68a7dacdd1078443ea1250051f97f2b6ecccae51e6b9c21ff9e432f891c82ef18b7e4185ed77c4a6ab000000000000000000000000000000001389f53beff07ff56230755f8d69a95499ee496f14bc098c092e57b279f9654e418d3b9064c5ba0b23043a8bc01691441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c5e72d55ea16eeadf77a9c8ef3bf326c49824068a17971fc721de8e461a1b2d5515eadc3d82873607988cfd6292136000000000000000000000000000000000c59e84aacf343a067c606a318f7ce1d89cc6039e7d3ebc4dcff57d6e385e45cb1311261287af430c7bb39fe1475d3fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d38637200ba9061ed86eca6642de7807baeebd01fc47c7a0bca687e54550832dfdcbb4fb036a3d8a338654730335c3200000000000000000000000000000000116a156ef8c67349b1654e8a4ca8f07165c220069d2be24a99c936e2f2e1b8580eed61965f76220b6a4ba2de9c2d1f4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a8a5ff2a4138da85f557a260c20d1783b9dc9df5d047e8c03e01f9541a7e8922f20e94fb9e057c930c80d8c5a4ae700000000000000000000000000000000017f5f3492f2d8f76df0e7894689f1d04e29d1326f937040691587cd3c4a879c17c89ff1de6d6598d4a064b1a5e7fab551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008241e53fb868b922bbe91c29327e55735c80aed846f5bb497f79e5eaa40ea3c0d96b2832c27a6a67e3e31b9953b7bb60000000000000000000000000000000005a5aff72ae801a006b4deafc7b7c3563aa761a82c4510e63e00c3a7f3826fbae62349b040594b34f1871487b9dc02ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018acacf8a679dd25e18112e2276d45a76563f8f639a175652d755970f330f131260b0664b4e93b858b1ae415d8e7db98000000000000000000000000000000000275b055bf52e4fd1d48496f631765c3ca8be9b3c304bf579c610e2ae2da0c36bb512053eece513337d7031faa54e5cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001710359d31a61efb50f0b8776e3b961cc814e9a5388efdc4d9059a5daa11114effb2691d07aefd4e63ae65f4695173bc000000000000000000000000000000001892a5512f20016b3c755c01649165ec51a9d81d531a77402168954dac97db63bb125d64df28090cb2efd7a27473a5e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a2366558b7801a81b266c98b6b87b80dea8a0a3d342a235dfcc834a19fef5bc68ec5756f16fbebaafbc20fe4c688ad000000000000000000000000000000001886106d5f07003e8dadb94c192d04aab73ec195d417a3ab43d4e40de1598713626c810af15291aed05c149793ca16621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ade2d487c0c9e4b07a11758949c757b0e5204591deb64d68380de87ca23aa47536cc9353bc40ed44a9bfe2f1f8c8d6c0000000000000000000000000000000002e437138d8d0a24dcbf03e83d11fc8182fbdc6a156811c4d5e8bbaae4360f0a6c66d97cb446c3147bd764cbf3b2fd341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a20d28b9e2591590643e4af33ff5a8fb2398b06b6d2e399d8e9a1b33d01e774e58cb376645d488d3e0b5f2e4b14e284000000000000000000000000000000000b2a576c1b862d7c72f7843fd5baa0f91ceabf0f37f956916577da5af4b791dc63bf0f540121b24ca03e1284a727e8ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000063ba4963b8b4ff3e5433c1cdb7f808e2355d583083673ff57cfe69a01464f69a71f15f20ca91e0806fc20ad598b4290000000000000000000000000000000012b54ce9cd92bd323242cde713b1af174454ca050e53c3c0de7601d9b2bed9561997090ae8c7248df715afa8bf5d4c781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec68b7520fb8a8f40f1d0a7f6c07c61c26384f9be89f076375e8b3b04e7260a6cffdfccff13b3580b9073af55976d580000000000000000000000000000000012ee742d37da2e1245b48da1a9a88863c1567deb7cc5b70c4792babb6d0d008366710285b1f8e52b6ab051e4b08368b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097bc511f5e59b189cfb0d67db04c10a083d329ad5c2a5a30c967a633ed4234ad25060ab5dbd658d81500a5164f1ae5f00000000000000000000000000000000129316409f017c8f0dae8105131630022495b240466181d623aa97e2cbdc8494da109c8da8def3deb4c5540728dcf7421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003799118586c551a0c6e00b2d92d9b860b69a02366d843b6c636afe3bdf589b2dadca20646de3711075e80e46b881ccf000000000000000000000000000000000bbc5c8268adea4af4ff5dbc73d5653a0748568e8faf4b48ddaf2bce55ed421fd433b6beb2f2841e0fd33ce97bfe4cd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f030d731cf794b3924a287cb9718f3ea9fb7702aa0b2cea6e1fbf143efb68c8b1ce144a595e542c6cf9434fcf5a806b0000000000000000000000000000000003b744bbc210a41a25ea33fb704646d4f1260634667ecba3a0994f9ba9622973e304849a4ee08b6f3fc3988b68b335831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b48d835c83c64efe538847ee6a8ece0df7ea033cc12ac22eae517225db2fc16211a9a1b91e5eb89a11d149ae1a00580000000000000000000000000000000018e2131acbb6ddef2a05e51c2f3c65e56bcce1579c7d745b1d6a9ed5d68498982de9a911f76e42ec12f0e1749e1411ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ec072b45f593e294a4798ec52e6b5e0d225cef122b4d80ca5a9b953f123c9e6037eee9ee69cce336e89d6933a4b24f00000000000000000000000000000000166cf2de8807d46a063e7fa21141039a5d2ce8a8593b98797251f997c5e984a78d6c87194c040d8dec23729c01865df11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019fec7579e550d261d3b4be761a3696edf45daf70debcb0d19cfea6f85f54e6da8afb5027af634d5ab809876ac4bd1e80000000000000000000000000000000009b7fdee5e162620699ed6892f0e2c472385418fbfeeed4ed24a5d590f62d334f44939a7a61368e88d810c990c6bcc981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001890fc4f1ded9c6082f83d68bd79e12610ac05212942a4cf14827e6f366bfd52067ccd7e00425341eca0296e96305ff30000000000000000000000000000000006b519d626323b9e2828d438acc0c0a51e451694719539bed5b2d1297e4592535073480ee0bae7cf594e430208484c231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001562186d9227bee2748a4387e8fe395cf429e399c45a89412791ee4d3aa840fa166731c4191b86dab5b79cfa669e9cff000000000000000000000000000000000f643cd18384070f442e134b2aefc5f8d29c4c3f8b677ada25dccaabcf8eea58ee012aef5341f0d4023461dc33e3cc131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ad86a50a3c13d0c87ce5ec8747f9b3e286c8097df229e4ab6f56e1ea34a11da78d3f54c3e308e439490fa083682ed00000000000000000000000000000000001edfcabd8785201013cbcb9ed9abf9fe2f3fcd0ac3c890a9f2174a8dfee16a7db6b17a94803a31a806d5b8e8291427f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114e0e0e85f47700059bccdeffea30dd3f9ac0dcf73e63850dff71ca101a8ceee8893b405fe381782c83322350b070e1000000000000000000000000000000000873fbaf0478915a5bed38cc1ef0977b78a3c269ea7959752cc436a291eec7332716f15ba24d415c3b230b7c489cb5401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d25987d38eead40474303d121b659013a1eec84c5b653ba1725e6aa73394b39625ec687a730a0e0328388cf3b79eaa0000000000000000000000000000000002c46e8944c6262db393a81c27c3d970188d132c8d6ba38a6a5e1679b8cbad3d6282afe27eddca8d007914d651230b341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005496f1aeb84f693abe7282d3da1566cd066c33b77d662aeda7065dc75c2d3dab6a9be18efb700b37e8d315e53383b5d0000000000000000000000000000000002d664a80eec5a20f81aad8bb791f44f1ca6cb608a1fb24201dd029c4cf45f3e6ed3df7bdcc123b7037dfec3d93d4a0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0e6ff47b4b2bc6fc531a3ce06852fb0b1a2d43f6e816ae157b9de3a3e758fa9bfd219f063fd42f989fa17ab674beea000000000000000000000000000000000fc3e4b0e6748058b658b299737994aa0591c056c506b79f57e03b4749efa339565079ecc1ba2304b009a3d1a7330d171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a89d70dce1e67bc0550db3715b4bd96dcb23b1971a5d7c28b1e67b0a176b60ed3b66b51bc3e495f36dfe8077d0b81950000000000000000000000000000000005144a6407b4566cdba7d5c0a8388a075fee80aeb2aeaead3f18f6229f4f15c0d40fadc139bf9c10e57583312126dbf31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca0637f614823c1489d6a6800c8ba382032e7ce7619aeceb255c38d83e51e1b07c51c307449924f32c5f4b7137c1dfb000000000000000000000000000000000cf4667098146807e27b953182868656afb0b928eb8042ec1225a9c090604a0aa73e4ea6c918999c18c25112bd746b641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001326f14057519c003a057f2af6b62b5611ff40467e5b7f78f815773b07293425ac2f55135bb836b5872349fdf3e7f8af000000000000000000000000000000000e03225b11009eea69dfc5f53f4e91d1a6a9bed701193c92f30febe00094bcab3dff1cc277d06088bc2409a9c27545b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b48d9e9538a06728503f412cc9517b1c76680bacf85c4f4a3499b2501ef585a13d027763770c8ec3ae8716e5cb998f00000000000000000000000000000000187393ebc3f88a503d262f78e910fcf8406572c942016b223b35459cd6f1d6427ebecc717d05fead70d311727fd583ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f8dbbea33095f2447eb9371dcaf8716d2be70ea7ddc9f9bc92719e561f8d3d938a8463134cc751607ce68fa4401a2c00000000000000000000000000000000093e67f737dfe24634a7c423edb5aa167095c99a55c061d2cff6b8e8d7896725aba38f8ef71e878bca06cd249913d9e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000822c8d44a86113ba2fb36b8064596e4d5816bc340aa26fe414ecc92265f5ee468b4a62aa565cd4c94d4007eef7a920000000000000000000000000000000000154483f0a4a2cdce89b62893d26ab5fc2ce1c26a24382a78693a56f9a2024d24d1d4d41ad79e9fb69793bd8f9892ed1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed31c0fcf97549a278dfe6e8cf7b00a004f1a75eda46a5cf474faf031c27ddb57fb6299f3c2cff486069c580d45008c000000000000000000000000000000000ee36011b11236e4f7df627c737271cec1d624df0727e94517066298507a28bb7a5a8f8e56138cac8ae2b57a21aed3631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c4d9a1ec9a5ae3c60efe24e4210444e44d0720e9d39bf47c2ead437a9b533f7432c65308bfa48a74f0faa205e33a05f0000000000000000000000000000000009beda6d3be4b5755b3db0f931a735b60590b888cbdd69755995cd70ac5967dcf976e79192de88fda15394948279dced1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000737bccbd79e54f428cc33e9302e8ee2911dfd23793329017e00e4b9cc303673b67c82f22150b009ddb660fac8372bd900000000000000000000000000000000133e556c646fed5c7c63e07fb0badedfdf988aed7e32cc59a9a5e5de85ac0a82f1dc6bb94f4b8ebfa476fe06084a54ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189a4ef3635ca9b40203257450d4e3050de4f9bfdf9f9b859c936e140f27ca512afc052eabed06b179536689aba8b1700000000000000000000000000000000006fe52018815fcc71c6d236e912f6205daf613002312a086fdfe602c97f450cde5b105cb7190f305c2f316c6bdb254481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113106d1b744936b2c1c5419ecf403a1937d77f3e92b6a72d70c04a62e1e7b0283cfd736799e6e93bfbd485009cc7e19000000000000000000000000000000000c30ad2eb9bb1ce949e56982eede0c5013d668d0e32d36a261a476cf03ed6c2aa5b5168f5574bbd7c52b5749aa31c4941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7411ed9769e37b6f7e6c2c767f9d1fb80d9bef6eb50f9ade585b3bffd926df755cb32e33f26b1eb9812654ac1e82ad000000000000000000000000000000000c58b3d5434b6dba29a329b6cf2b6355063d6d853b13a0156ce75e376841dcc160cfd44da4535b254ae8eeecaba329c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086945700398cee1a149c68f29783b9a45781b2f972723639ddcb3fd85537931e3996a168a0bc4aec074b0665736eac1000000000000000000000000000000000639db2981af84e101e11919568cf017cacf5004a8e49f864265a045cc05e4023725c83cb1227da791506051565d56221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f8ef889b32607b7a0a5fb2e950129cf44f757afba8924996f5a5421f850a2315f4948f6b5bf1fbc9b0675af2b076a30000000000000000000000000000000012a6a2271f57735b78839b58545a90b1388a2e84d37c29538044ed9e1f93e012aa8b6f940ee2231a0534441f9e7488601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091d1305dfd5e573cec3e35850ce79b29dfb8c296584cfd794436fef1d9d02c67bf444590895903350ef737a4b28e035000000000000000000000000000000001408da122aa028cc5708d326633a31d2c5b1e0150fda07c90ddf441eaaf75c39b5fdf8d52493f7c3d495d18f9fdf73df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c00881f2f0c37d7d5b9d97bc29035d2c9ae7252f81c8f1e8f571c4f768234a1558a375682591a5e2cda484db2831e7c000000000000000000000000000000001165c8536171d0ed7658bb6f21fa17a5c75d6d1bd934f6a112a47091ca1df7712bab41e83f8dd6397fd31080692e99f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000881f7c17358d61058fe7b4a7337f27562ed490d0f3f89aab44c55cc61435e7c2880432717c6fe7fe913da02cbfd6a7800000000000000000000000000000000093eb98e9299a3195908e0a0fd0e2794e0bc11bfc94d7ad95624b9c9a7fa31b1846bf955f60dd7d1ea2ee41d63b534ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ad014d7709684ffc29e93f3024963a046c227ae36b348698be8ae6333dea5dd212e564fc7be75225f28f7e3020949f0000000000000000000000000000000007831910f16875f741fb3ecce0cb73834fb1ba8468483a0cd862605161210ee7d1f2e4fbd3d55e07c27f63a6c357f6bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b42b6f353e108aa38c26cb6387f7010c6c1eca17b03d2595fc900c4fc083905b7aaa8481027bd97edc016a850d703b00000000000000000000000000000000128d963119740811beeb3984a8f37d2c8a1dcdaff4e3367366e4318974b9e04e4a47cf13ad709e4eb31f19b2affecdd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ba16c76a01932a245ac21bfbcf7947183ec9edf25101bf2f7a6034ee26ddc95a0e5e398ddd3c9be2977571027b74a200000000000000000000000000000000092917851d092c5dbf050015ed451b93cc4f45fc7d5dad2fb27062b54d87422db24ee55e8a91c7e2653a1db823fc64531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165ae81d0c813d9f980aa37ba48a546513fabe1c9e0a38ba7160792e0c8a2588e0ceec56cb2722bc7a8d38d934e41d410000000000000000000000000000000013cbc86094719af6353cb42d51cbb12e5db4b74015acd5dbdc2fdf9f136bef91de539fc45412f1f50b7d16228ca47de91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000514243edb723a05d62658224021db9747d0f41c5cff6234a5ccd6b8bdb7747edecc6375a38e71038afa210bebd43d110000000000000000000000000000000018d0679c806b10e1427662ae2c1a05208ead185b9c351a243130b71a97805134b7cadb2d38e68c4c6aca30558d02a3c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023b8f03b05600cbc38d574e59f89be8cb2b442be4780d7695fbf9f5544fb67d941931a25ab5cf825775b2ca412538380000000000000000000000000000000000f508374d9e6f510f3cc842e351486ba04937d0a8223bd772aa9cb686b18890917b6051c9bffd46344645126a77e1db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007612670c7b184732b5e555b1955919f266840b2ce7940354cf4bf25677936905f4e3d341dde46cead1b0e9e48ffb7b90000000000000000000000000000000006f7bcb2a5147425619593db4ab9eb37ac2683980f5a61abd8fcc8d5135dc41d4efad0b8db09b049422b151747425dbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001dbd1ba66474cf97951603d7c29ff65aec7cc91513d6b0deb2c1d21e3aa5eac68a3a4f7d1c04bc7343fb39227646439000000000000000000000000000000000a9306b6ba9c819448f6a216b4a0d7f7aadbddc9536dfbdf126e31fc15803b2071f9441773e4bca9068e43a51fd4e92d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b0bbfb0f66cca3fe522b7bd8cb13b6eaafdeb2d303d71d44376837005150bc38f8bb7acd24a71af894ca6b862168bc0000000000000000000000000000000019c3294f6b392356e209320916746169bfcb1a992696977ddd54485a5c5d69d099aa878b0ac3fb2c036a24149677b8081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b74bbb45abe85742ac9b59b490d90472ba2aef53da18489758fbd3bf9b692f2e9216189f4790856b60d3c439e4176a0000000000000000000000000000000005e7e0c7d7422cac5c7a2a4a2a7d2497c438bd41cf07e051ed947464528c3900e6c038f57d2ecc4f4b193a8a52bcb31a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069b0aceca4515b4179a5c500528ff0608843d03a8aeac9c694cafcd2af89c18249a55ee1ea3b9d17fa0c7ddbc4500580000000000000000000000000000000001985e44abef01215d87404499f69034cd0d4241534c2b4ba0ab9d85bd45813b204528bcfc0b1df3307c1a6f77ca43701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c38720522cd0eff260157a0ecaaacd6adbf8963b651a6bed9bd10a4f2bd67dc665cfcdecbb7ed7a28ac3b4a191f29d40000000000000000000000000000000014063ebcc0b1107c84ffe395b6204f4e14203061d018564d14978bde203b3daf709e72b144325035ca53a4747375daaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000912de492afc46f39bbea9b8521e76eaa0acd44713927722b9f1922461a3e2635fe77c6e4a945c3cd4889319b7210427000000000000000000000000000000000e356e23eca6d1a9e40e4a813f5cb0c5d8ee35c6c8b01d90a909aa9b07c486db3b4929bbbf0c37a20fcc899cbb4d8e0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d173b148a20902950cb15306838be3abffb036397ae9d638d7e2f6f9d15dd03d814cd328ae14bbebd51e8322348ad20000000000000000000000000000000002749a17d89aeb4eeef05b850a2b9079cfbbd02a9ab631ddc4ed6b448eb620f79b77e7376ab450c63883afbd90c57f6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ce42e1a1636f2d723e79a5fcb3fba5eb9d27dea103f301f27375feaf3e858110a80cdca4291631a48b68222bf9812d0000000000000000000000000000000014495a155aed9851ccc87ead597a6f530c5f45f888ac9e87da5a613cfd0f300b2668e3f69ad796b1c419588c71161bc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001620fa048f8fa229fc9cf71d2ae900d9073a4ab057e14e2225fe617712827a63da030990e4dd251cde5696156bd66c8c000000000000000000000000000000000e7ffb778f2f31d25f8b882bbfeb5b7b471b47295aaa2b5a6bd0bd1370479a5b4bba517da37f3e2c7e5d6e60e56cd74f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed32d715acbd6c502af3fd49f965bedc936bf238abb36644c9ae320434071049cea4b8993947c4dad5a5ab37c39f5fe000000000000000000000000000000000376041cc9c915f529e22c07a619abfeb540345057338130f358c5eff4d00183873e5ee820801410c18ab1bc7cb86fa81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a6ac2f81a2fdb8382915ab0b72d01a51c14b5a3f6d4baf56ae1885ab574d4533d4f6028052d224a9625a9916ebd8f1000000000000000000000000000000000a0da16cef13799b7b7470a804a1f877b611545936f2a84a9f2115dd255e10dac549721ae425d257e703f083c02647b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f3e4d957f871f3b03a3164cbf36cd62e4e550a56190794714fadd0507106271b43bb74a80927c4604de7a372c44801000000000000000000000000000000000290e1dfb5ac3a6f9fa7c3b5e83ea9fba12108a1c559dab1caeedb9ab15bf56c966b4f0bf7d27d6a6aaddc69ccbd9fc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbd55867ad63cfc4fcd38d2d98f59e5155724292154430146c407da6ffefcc48b922edc30b5759b12b426d45d8b766d0000000000000000000000000000000002d7bf93ca5ac9e708671baccdce4110e8754d94de1e69e32c8f45655e06b4c34be76fb5008ea408d7c41a808e6403ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001178cfdbffc0f910f39b81b8d7a4e371aa8745ae1ae74053d13aa90f94e82f56efee051fb7054c0bed1a78fd93df08910000000000000000000000000000000016a6f5cd4c859c5176c755991f88aaf8d603559419c621c2e25c75c24a478d074be283778d735129d1d60ff4e7146c1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001551be4464ef1aefe6fecce96de12199d777b8c1829f7f50241d1f88eca44ecb9c719b7aa93a2b4790721bd29d71291f0000000000000000000000000000000000d2c8c7088d19c834214ee8dd27e013f690a32c1b476eef98806ed56a2cb5d79c532b18ee3957ed753330768451b3cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef5376c93d82a2957723d1c0fddc8694a56ab0df0d9ca639616c03a80626a49ddba023226327222cb6e310f37718d8d00000000000000000000000000000000148d96e2d367eed19b0a93e3ffaf92885076ab5908555b18b785ccc2ad725a2743ab546a4f4d4bef365500e2cf5f249b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c13ef8aa7fb353de6f965c5c637f055803453a062d8def3f77a48d09bcb4c72c2e28a7d3c439a9775a7cc7a57e8de000000000000000000000000000000000123bd915e5499074f5a05f283985333597558f8c0c5549a51015a9b31f4988802b91279c8794490c56699e3ebe4a67b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000056389ba2dcc052fb3981f6932c80c7a2482ae51a590fb0bd8550a4fd50815bc6495c2ad7d52957090d08d3c79c78de0000000000000000000000000000000002a95367f919b91939e236c5d11904e344bd4213aa5533c79c92ab51955a5e6bf7a76556f489c09b57d39dec3f8b5c4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d339263b3b1afc5edbab744ef1a0f981905621d0bf3db71284fce5e5672a7565f1af6c5f62599156e3cfde3b506957000000000000000000000000000000000dfc8243a7ad96b04f7ba3a2220803eceb989703769360495157d61fe744f2339ff9e3328e669aa1b0eb7f76ff8e26fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190544712535736edb6cc0b4949b5d0a040ebbb851dc26bcdf02e442497c066996d90e34bfebf3fd55826c5bb02df2840000000000000000000000000000000017c0b4ab5f48f2d0b26f5d49532154a2338d235e34811098ee59c1d663d03fd4f97b4b7c353f0f6d386ebadbbe14fbb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007eadcd08a64752fe88f38b50286d1a4b00d7474a3f00a9e646b48b03d850dd49709d4aeb0d0b314bfbd955def7864230000000000000000000000000000000001b78342d9747aa1349443842a9e7a05742b8a5aa3caa35ab38d4710e21f2db47573ed8c7a66a97e84ade9c6210825431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000901c6f7304ddb31a289e9825a572df60711b59b6095ca13cf912f8d2bd3c76956949723066e8f797f24d9959c1e961400000000000000000000000000000000023daa1adb601db783560b8711ba364e4af6348a41e0829629b9e7ff38d36c727740c7bb70bf3a8d3acb65be4a658ea61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a4dc18958fd0252a6d7ef4562cc4a2fc724b86f971ce22f134c6d70fb175bd7a397be822bf72b2e47d1e63d880ca2c000000000000000000000000000000001820f614dea92dd500e8bf7a4dacfd6254231c53967dbb9be5ba306a0e06d5643219ebf20497ec4a073566d5b1237ed31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001184ebd10132286a157be5d6edaaacc780a355a2a5d23ffb3de2960d064f0150787131e1e54bc4a25c40ff10cb33af88000000000000000000000000000000000c8afaa3648f31568479e5366d5c9d08333ca7f58c7b6da08d5c66c4e24c6e3d569f0dd7115231b34225cac0212cbaf41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167a43a6757e0ef11c981f52096a22834e70c2bc0fbf3cabcb60f2e73a0f623edff59992d9b6d4521c27787d77baeb820000000000000000000000000000000006de6b5c5b39b4d1e6d0b02ae5561d248cfcefc97b1e70422729c8b9f09a9b383a234dbb984e511efadebe8f6a0caa341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba5450e01fe52fdbe84abde2037fdd37da6ae24ea0b117de72845fa06c23caa7dde9c6996e0e935d2115ea19cfdac88000000000000000000000000000000000ac77830b0150483e9093918ab2f054496aa1e59cbd0c122674d14ea8861c385d85271cd30aa3143b756b44b2d2d0bca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040384bd2e85f83acdae5673a5aede3bcae41230d81f3377c0b6a5a357d4a053e890146459fcc55c055e1edbf3e80b88000000000000000000000000000000000595ffba244438208ded3b0667478a41bed268accbfda6cf04b6deda97f96204219131a8b75e46a9fdfa3c4855a280001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f89ae4b50700faca55387043804ced7c60e582f90de771cf8eeb252ed4e2eb56473c57555e59101d4d5b8e6190a468a00000000000000000000000000000000073c62e0851c6f836c08f5e5663bcc7acad0aac4f822fb65af12e15ca40b1ade50e5a782b392bdb7b0ba14aef04a1ace1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063397d2890e58ba3f027f418a3d9de26fcba11d61042a0135b394920bc45e60d28bc1d71984d6977e3f497e0a7415d100000000000000000000000000000000166cfa88133d62d4e93760c2b0355b223027592b71d58d286bfbc9b09452781ab8034d4e27faef27134911145550f26d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cece3f42d5d9b5192a6c2247c3c401e8d69eec654d7700bcc0dec3409fae81f3400d7be1c511c19ce739c14df5cec7c000000000000000000000000000000001070988ffa4e696fca398ecd816249af16ea7d9c4c8228ae3899166bf36b4cf7e6437fe5277adbb332d1711484c31fff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8963aeeb9b2dc735f707bafafbfd8448d143f8bba378b4c088f76e90781a1321cce4edc2d73b220383da93a6e258130000000000000000000000000000000007a00f81b0430873dfeb6a0350369d9bd74d0bfe32f8dbd5a23759a69d1f58d9ccbdc41275ec5b4ce7eef69b6f0c9b841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a22a6f85805d009a40059bf5b921dfc67cab1c455b0a68846e4836f4f61f48ee34bb7bdc4b6d8ae2bda494d9078efba00000000000000000000000000000000032e577c7f801d8e8316debfeb6b195af1e9e08871c10d2dadf9b3707af45e1fee9dafdaab4691f9bc99733c477792891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008cfeb714c46489fb9c79258e550878385335ea7324e48f9ed749bac3a515d50ba10b09727cc9683d964bea71f431ca10000000000000000000000000000000012d824f815a59ed78a0446fb8cfb7e615b448f04360c2b5261d4b24474d5e48918e8ddd37bdb2ee5badc996354cdc12a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001590051121a084934fd381067b262aada5d688ef11b3f97ec10cb62b46276689ce5937f80d1967f49012ce460ec73e0000000000000000000000000000000001787d06c7c9891c33ac0555d5f94dc90841bfa2df0e51872508967403754ee9d8ef97f2329f44ddd805cfed6597a31fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076f60f8215319c32126977772c73b459b6fafb5990ea1c49a4e2eefff2286841f20d2c93c63375b4b6aeca7baca55860000000000000000000000000000000011225564e25ef8b98e777a53969888ba139d466a8c3dd4765c6051a0a6e8b3f33b91e08e58bcc5a10ec694768e5103641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e4b06e631dcfe3aedf1299c55927d9b0486611b690fdad15dd76afdb9a4f147a7673853703ffd66cf879750935917c00000000000000000000000000000000120cbb99ad9852c5db18c86b3701435c3cc8189510ad6c443d3562a85d1f794521f3685e1139dd58e82ad75dd95598491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138bc109ff2d31ccea8d556a56078062d0f7542e46cad7836867a73a46e973c3a45b57479cbbdf3d4fe61eace6076edc000000000000000000000000000000000e781d7918c80d927455bc30ada70389852423942acf73557b3128b8b6c384819192a5bba7cc3f6af95c5ec575c695f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015751eed718b395dcec1381a25ffe31c3db047b6fd85f92243ea4fd7e7795cde56998c0185d59e70f12081c9f3150e5b000000000000000000000000000000000784740fb59bc5074211c77d1cd104ff5267d2c955096fb8d46efdb62cdf5b0b10bee599656368cdac54162b9899e20b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047183098acbe57eed0f77996e222554393a6b4d05b40035985285f128147edc60b28f5fe43c42a4b602324a2bcf537e000000000000000000000000000000000dd79051e293357664fa484d061ba18b57fa1466754fd019ba624a2211746bf3e9e5f1d4250a313c524d3669dcd1635f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e1d6e24c1a368b8fe64243d9dd2a3c8bcfbafd84d0fa0afcee3cb7db4632f10ee324c9b3cc298d3b584666bccf5b63000000000000000000000000000000001162b287823cc1cf18561935b20def124e91310b43931a9a5f7354c2cc0c584dcbbcdbe616245fd28f6680a0a32a859f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018619b644da88b7fe3adf1902229fe374b0a78a82649500bf89f4a1f8e77d7049d076e9db19e5fddf25455fd861c0a240000000000000000000000000000000014260648fca46f0b21c523526e590f1e05925b69a6d0583e27e230893f80c0aba8d08aa4936ee616a7f5f607f752fcf31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a68e5a4b5944cf8b57e441c0c0b42966084f2d7c580c58dcb1790b55ab76c8260ddcc21a9929de904b4a1883979db7000000000000000000000000000000000e9d95f1bc27128670ac591b3454197e0e65800ae1700464fc53a750d013402da050c5d85c148dc9b9b0e9ce7c76f93f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d15b66a81a58665b132b448a3dbfc40c450b0d30b318c920e40d757aa24933b8a1c2d2dbdc66e91feb08d292d717ee200000000000000000000000000000000025602cbc28f4d682fe33df506c6f1a7b07c02b26c543837a9c76d1b8ad4535d5292202d5fcc391dc88fc58cb0776ba31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142d49fd5387d746d9f97b8ac32638c5179956494c6043c6b269e82ff89764b4db9c0102db192429836f41a16c45e91e000000000000000000000000000000000ab4c731c155293b9380774ff5d83b95b294f3c9e078d0010eac0c96185dd3d25c4c4897117523976cd673df20be216e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a3b8933c08ff3d92593c9fec9430d6844910f1e04ef2c583c528fcb4afd9c6939411f20a621605eb6dfdf20d9426160000000000000000000000000000000014ffce1452814a7fc518ce9fe9ac16cfa43d7d4cac20e96da514cdf9bf4427b21cdc736efa2e1ed296e4fd28c4a4a7fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c85c900edf01ed86648b997785e02375118d9ddb5ad69f1dde7c3f4290707d36b17d94446fd423c1d5e7518ec61b130000000000000000000000000000000013ef4eefe9d16dd222e87e96047c2ebdd8e74d3a1e84c04252deb00c8abf1b6d73d7db6c8060ac976064a6d325ce17311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb495cf841bff7682a9df9f0df58a20f1737fce178968c39e8406fa7e758cc594be4f65adf1e6a466c17cfd53d118a400000000000000000000000000000000076dcbf885f54cd8464f5c6dc5c0cd454293c5d988c2b249b5d50c028ed86f4210df769bc9a4654fd258a04c3a0db97b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015c32741acb5a8c46f943e1b87e4bc76abad655b96ec4f4f39a6ea9741b7fc4b73bff8bddf6c45ef1e0f2ae8c3b2ec2000000000000000000000000000000000c3da142c2475c315bdd08452ca3a72f3642f60f76a6fb51ae28e0e6b2fd10b14cf365641be5a019c5e5b5bd80d39e6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4d8898762da5595849e6e245ec7eb391680eb3ad1f42ed4901aea988b3051f5be7d091491362fdb84d3980bca857e700000000000000000000000000000000034ebc46e7ab5a726ee467348fc2692232af80541b689656be2584a74c5698dc2b06e5e7c436fcbaf1a72d2ad0a9f8711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a4b21b49bbdf6a4ef12acd8da1dec1a02328ae127ff9faa98fef345f3fb97f4532b2ed887e6e0c2e946f051730d215000000000000000000000000000000000bf8a19b9d187b5bd720b6b5b23d0c675f99ec78065eb5fb1f825a45e1f66508ce1046f14af425a61796581cff3c1f591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001654f08932b433d62defe726eb40561dde98e4b127e50993ece5a26d9de2c9e5a1dbe6bbf2cab4ee47eff59242f690590000000000000000000000000000000015ed8ae18c9985f79e774cb6a9dd711c0386eee84d4ce22df4e6d8939ae32cceb3eb91549b0eab306b500a6829cbb1fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001545c5f3845940a58e39e9b94eefad0a1214d7e756c88c84af30e2661caecc36a2f755ff30ed1858d93d072c272d3eb6000000000000000000000000000000000a0779ee83cc3d847ec206b18a66b90bb9f6413896bf429ed0d8c28968a9b0a514283f09685e415420cf43bdbd4deb351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c9643244e71e4a47d5b2e16486cd664494db959f005c8ba913a12c37b1d3a7499bb9ad15c64ed9d54ad5c9dbae9eaf0000000000000000000000000000000015603459849726db1c69554882a42ddd80ebc3cfc673dcf2e165e319ff3eb4bc97443eac25d69a41eff492432b059a071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db49fb3f6f19b70178996fcdabecab437d6592983179fe586ba0cf806c7ca6407f49d4600344ff365516c4907bd3f640000000000000000000000000000000004a7044d7f59f42c7290bee2d2530b4caac4cb1b245329368f77488e3ccdbe1937f1effa3282bbfcc26d01bbb8fff7271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007886adb3c8e5a57e23d513b1f74221f2588e593b6002f5fd149c23931f48daca2093673ff8b2565559e2d8949db2d9d0000000000000000000000000000000003d1241cc955650721bc45517d4397a8f0ed97df4176151dcaee631c18a6db2cb96e126b563fd476f21d433f338bc0c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002dba7bd1542eda4a6dbc9a949c57add893529bce1930ed07e278259aee91e9d3afbdd963d932b2090d9648ceba1ad3f00000000000000000000000000000000000ed3347ffb0db43885c946d46c496556e423e9c06bdd861e97ddd131e7a4a7af69498774805a52e5ca351fc26587ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4d36e627e86cdcf91a3872382a16860fb09ea1d13a7283ddc45cf71252cdad99e5e61644deb1200d45d29ef7868664000000000000000000000000000000000681e0eaf607a9e9b8e9360ac9b83a0f1aa496286e1f9023b0a9860027288775e5af2fd1bb2fc082cccf25b1ae174b0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016cced40381e9df0923d970b023c5b5f4c88dfff7ab2f8cfad283f6a2a171431ef6087cdc177a1e18c23b7d81074abd1000000000000000000000000000000000caa36b1b833457ed29dfbe30db55d97b0b9dc00ad7d0ef94fad9e8d3804d9218ffb29e613215d96a53ea881962805351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185ee6baf1a64785f231ed200a8a811e3a77e7e6f44a4ad2e51ec15800765b36da741ad3d3d8ff342137eb2db066181f000000000000000000000000000000000fd083a364face0b024aa2a865e687b2b38434b4d84294ebd8ed7be97465414346aa2dacc8820e8cfdd67e662c7cc6c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e188eee4c8507ed93925af2873660a6c3e0cb8e46227a73f51ff17f5cdbc57c30ba4cae734bba8aecc87f6d858019600000000000000000000000000000000198c77cf793ae6f5ffec95eeecf8541be8b2fc28df71db6e5e7152c5917dad8785159762e746a9fa6a928a4544c3ae401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058869b3aa4c251bf7a1c997f49dfd7a12541d619204eefb7cad59eec103eeadc28e5f7c5f67376e92b3172ea408a17b000000000000000000000000000000000595d941f23147d8d81f1bc163d70b8c9e1609c46efabe5f5b5fb6526befc6201ca66c4897ef523f268776abee349ed81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014adb7155bee4bfb38b34c3af7860ee2023cd3697c2fd739d4ecb145fe49552132be468e734abd45745f349a42eed12300000000000000000000000000000000078e1e05c38e6141da8a4ceace4bcf3cfad21813823b86b479ba547fa8120832bd2b909f459f78095a6ed6d31018a1041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193fcd1290109825b9d361e9d79ed99ad3d39015dc6997a4ea4df3ed6bd16f1b8c5d7dc022ac446366940c8a9d96dfad0000000000000000000000000000000004a10c4853a29b4029bca4199fcb3bafc300c209f2b32079905c888a31bbbe5a4795f0b69a492538b6a9ddbd54d41f051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001826b9626237a037ee0d2ce2894983d206b47c15051c8e8b2fa74bdd8915ee487413266ea74821b136d9cd238fa2328400000000000000000000000000000000044b173f839c3df14fc7ef922a93b593a1babc5bfbbf809244bf34af910381c91cc5013a578a953d093f69ebf5d527331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e1f9cd54610b885e198509845189d219b0fb838e2fda9eaf541006a4de35941544e089b2e9b021ccbc8dc36e5674550000000000000000000000000000000004960bda6e6f7095451a859b11b5fe080394f8917d48bb5cbf6372bb3a1236f05647fca260e50faff0436b70e44a47131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001140662cb8b88b8a9b91850d93e4276a03ea19b9619748f4dce6a2a9a1468635f0edbfc9e8436362c53fc4fd0d370fd2000000000000000000000000000000001418f5e3b3117fd8b6c4f8e1e613063f31a88363600f421480a153f011df274b5b66f681e269bfee5709d2b65abd8f5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004da2910a8031b7926309284d4cce1a8b6aa0d077139e1a0309b05bd10bd4eab7e40f622fd33087fd3058ef437cab2f8000000000000000000000000000000000bd8c522f82ec7d451f7555e7262dafd434a56c1f38c3517405b30bc862d35c4f7fcd8af23d71c1b16748e6594e0d9e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e735230407c7dcbaa1685101045e346626833ba8edff0db6a25076d5db3ecfb766782fe2adc54c9c83c5b00adcd3890000000000000000000000000000000003ffce54b0d9b57af15f7cd148ecd3811b8b560c7f5076a386f8b0b221f38d5ca6d0c2272110bbaca079f44ec5ddec2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000baf0041f7b53a126fe390fdf3d264ceb9dfbcb2ffa51380c72824c3959fe2a0ee36728e146a65299fd7c561c6df622000000000000000000000000000000000131b8d7c31fd96a4c9c02cc8a5281bfee25279be5a4113c7a3c8311032cd7ff890aae4211f929f4559f578043132cd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd64ea2420ce31c253711b653f27336e4cafac3b46b391a406cdbf5425f3c128e294de46f382ff3bfe48dac3dbab6680000000000000000000000000000000005b1b1a2833ae879914061c8c6421983f15591398a174a42234c16c82843b9e01d350aed973ebc3a61dba6f0abedcb501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e18d6c6371b65cdb95ce6a3b963869925f170e17d9ed5e5e6e7d7c3e35cdc299006eff202241ce487d4dd24a7a4b690000000000000000000000000000000008199ef4c6618a71b5e1fa2210a5211780d9daa9da4129bd82a9ec69f544557bc0d26cf22fc0a0f221d475ae150c04271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f1aa1f08b08c9f1fb0b6bb502a18b8336e4f44f509676499e74c46ee38b05f8e1c9b13a24bd6c4cc333e1602acfd4d0000000000000000000000000000000002fdb55872944a45f7d39426bfd664946c6d84a2c9ebd504a1b2d644da194eb59764217c9e2d3fd7784cb638ab5f54211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f059b7f8a4fb2b8341f55b468c01b2df418cddb0f15aed42ff1b9147585ea53c3a4846dcd542d55faf485400b929a86000000000000000000000000000000000f4074cf3d5737798a2bb4e5011224e96f6434c3cacc5e212cd0d54114bf835f335e870df5dd088105dde5b6c99003b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001260766694ae2197793fcc56d61957b344a111d49fb81c0474f4f191f83a79065d64ccb00e35e03c7bb2117e49138501000000000000000000000000000000000ad60e623a7dbf8c94b7f2f4649272a6e39f2cf21dc09f2f21e5901a32c67a404460e1a011a5ec4183269aab4952c0e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141220c320d9bc0ebcc7db83b2d86316ffa7c37c48efad1e80815ddc73fc3a735511f829ef1c9e0df9fc21651a0817d600000000000000000000000000000000014ebfa44246aab61717a36e785f93bf6681eea4172aa1ef9af9138c2a97faf65f590f381da6f6cc1658f8c8200699951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c17b681d90055663899c2c0a6399acecb31f618488fdc4ae11e18c6eb8b4820a37019db29927a278f769fb104fa81c000000000000000000000000000000000c2244bf4d389f043acab3c7db58c4fbbe6061d5a305d4a8c4bfdaacd5ebec96cdd366dbf7fb45ff10476c4cbc5bdd711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ccb4c3d73da4e0331af41351735e04dfa7a0ca2df9d97e299576f4fc1a87446472903b82130212724356a0dcf872b6000000000000000000000000000000000eff7342bab5a18266f42ce93d3e11efd67d05363910da902a99de80252c35def80ce57f0613b976e0d3cfe29303f22c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a651edaef46e3d2515eb8d465479a2e574296cc9f9f4ad586262d4b31a48139ab4fb86c592cba97fab08a954f1d9aa000000000000000000000000000000001015f3b8b0e1a9c4101f8b34fc68bfa6e43d26c0633f13045940f3284785af36556e7718d11247343d68d7dd1604b5a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067213d9685da752eb8898189777910948e5c396171dce9e40e7de8b9aace1c0597798b32633fee24a5a5d55f78e070400000000000000000000000000000000115583417cba5efdceb7a828114e589c7adcdc2bdf471832fb3b7a96bbca9210fd20b4ae39241f829df26bfb09290d281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f2ab7d003ce8bad794dc4b458be56b57c6ca2e4a92b5e54bcb2f73ada174388966ad58eaa9cf15de86a557b986b1af000000000000000000000000000000001735c69d93a905b786fdb00b91da2c4ca306224ecaf31da122229e4d244a2b0cf024b70bd1b409b94aefc4fd003f367b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6f68cd338f14f17aed11dce52eb4f83564068ecfdad5c779564ca6e245cdd8aeccb9d8790c93dcefba5509bf6fef55000000000000000000000000000000000127573a73abb85be8916b0fdc4542d056ad6e8fb9bfac043e995ed91c7b751e6965b90a759c024675053b3537a534c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a60ea2eeb86a22e1e271ac63f89236fb023b445b88e0bc5f2020af1f774ca1e819d8e6b928b3389ca06c7b580ca9b50000000000000000000000000000000019757a653c175c7196ce7cfca76257887b9044cac70f6bf4c93a265ed81b88a89708b13841349516e87b561f8e12c5fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f558bf134da0dce52e9c820a8ab4b1be24e8eb37c95fa245477644f8ca78e2bfa8153d9bcbf302019de3b7bb6b2e170000000000000000000000000000000010ac083438ee76271364a409f226559d16bcc79dcf83cbc4b1e0bfd389655be8b3eac4d7d6f94f7cd8b631325cbbde511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a63bbaa683f0d422c6901952d6fb399c230d84e20a3d99d0eddf0ade0ddc61958b02201042307f60b195c9ed4c425b000000000000000000000000000000000bdadec09d890141eaef0a5cc8e12c00552e3fa8270ef63eb111784ecacb5dbbb535377d25ec7941d0293cc960ef20e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028f0cb15cc179543c39cd424366259a29996b6739b709572da6d0b2ff57d537043deeaa67430530641c261186765308000000000000000000000000000000000c9498deca86636865290352c8a0193ba9053e61e98ffd228a1fe3aebdc347e109735f16b70d1475be47041aa06f4d4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c936fc77099e57a1f697f69bb44114624dd202e24b45c6195b08e744a655cf1f3bd3c0849cf24c429d408d6077d97b00000000000000000000000000000000013df11aba6c7bbf89a28c0f9da7dc52e69edaf68d200f392348ad8f17245bedab60502d60b8ccb151dff1282ddd3dd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b336dc23590dc12669b3bae2e6dd61cba465f55c8547c494a10580611d687f7126e50375119bee85535a7242319d36b000000000000000000000000000000000eee78d1ba5a4f15a05bb6621a9615e22bc50761c709e171095227a92aaeb31473220832c80844fbe4ad357146a76df51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086259a0cea7cdbf04c61d86a5f4928b43f6b9456a0a87f323214607255ad6f99655954348e8f561eaeb8954b2c466a5000000000000000000000000000000000935872090297741d605a1d1439648baee5ff45e2f2e2d2eaec6859b6315bca1d85bc5ea58d58d662eef0c93ae64d3ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121b6561ed1de7c694284b4cc9c67d6ea776f3f072c2d3179d97dfb21d6bdb0baf3a704449cf794cbae3ab063a4905290000000000000000000000000000000015a558fa6b497f0b0519a887e92c25471899e887d4ad1988998e0228e4507af0884c34474686bb9ba0e92bb6563de6b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e116459ff88ed81513ab793965816526a88fdca0cc6681ca1b5a536037d48c133b3ff2dbf13fb44fd4355f36ef166620000000000000000000000000000000002bf0436be880c338b0003bbeffd4a7bc7f264a7d4931a31a755cfc259e5d63a532ec72081bc935e15501ce4a22ed2891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e22c15f8e4445579207e406d492a4d27f0f6898108a3aa571ddb62d1a2b46e0cc6ce9e02a0b565657fdcbb144949260000000000000000000000000000000017ce50ec798f9b2362538a737dbca84fb97759b8046e8ff2daa53ca38487047bbc3112f68a63a4dc13403331e261a3e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d2434274430323de37bdf71da462232a719144fad2fb2127583f0418ae677945a339fefb5899b826f474b3082fc35a000000000000000000000000000000000996db0b08a2911da7c2ad2263e0d9c110fbaad57530aaa80ef0a90ad5f42c74390c55236043d9fa6c8e6da533f9b4831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001854e0fc75b75d2516145e22c10946040245801b7ca0ef68e47c9d06af0b2c6d6804c03d643b17dc858a07e33259edf800000000000000000000000000000000108a15e82329816849fc83ed4a0932eadbd41c6031cfe4c34b63fee885bbbedfa2bce50d03ebafe2f01cb680d66dd6e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f61135e9dc2b07c7323ff99689b2643e4dd8de61900f036f0c64b08ca49e334f72a58fe65596160233e4b55bd21eb0000000000000000000000000000000000a0535c32805ee6791033cbd2b9444ff048a7d3a8802d48822af84e05b5926d873c2d48010a29e0cda8a6a33cf7dd5241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000068e137db7bd348852113e6007cc99b77bc4046aaeab666a1b27aad73e0fe0a9cef555320ac89b79af2d553fc2627920000000000000000000000000000000007a54044f2d8abdfdbbbb8367a961949e01ac9a2204c272125e75295acf8c249482418352409324ad6957ef324e9c5031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023931a4d090ce4d798f219cdbd1b23e99dd1a745dbb5f5b01fe7449c8a1077899dc9c404fe2fabbe3fe208f55627efc00000000000000000000000000000000127a4ee85874fc84a4a38756b6cc1ab8c99a402659a6892ba4c2a6598dea9cf11aeda811dd6d62c3db3eae2228d7acab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a60c7c8e723c208fc90af1cacf37fc035534945b3da6e405d5fb05b1a1b77e7234cc938e7962d0bddd13437388651de000000000000000000000000000000000307eaad9fef5deaf958341ef892d136d07dbbbd13da01fb2abf993d73d68e9d3383893d31bd1a2889a3dc3d4381e6dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000167b3a8e1659f042972ac35450259488a711ab2ea5fc24bbe0af6168ff297b957e5881bdf36fd64aa63d66246af5d58000000000000000000000000000000000172a73b0c84ff7a587fb4cdf18d5020dc3041651943371367c493a9c10a535224b5b80b958e0e1f4470c8db562b60191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180acfb74d948a4e0736f782296ac66ebb49be6d329ffb57d352803d69c65546a1615691ae369cbeca2138da1df5d7d800000000000000000000000000000000029f6ee011db7de94c5289537c0353f140b15ed66a4ef44493b923974f99b04d7636d3d9860e8904fd3bf7b227c1a9e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c439980fa21ea1d3a4adcacbbc911759012bc9f54c78e873526806afdf4cc4db454f53a38776024bc2a2ec33404218000000000000000000000000000000000eb61d3a60bcfd9b94568a4d286a1cac1d410a08932d14723a60b07424be3d6ae7801fa676901a87d8338cf98e9c32171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016bfaae6d4575a6b01d71f557c5f25f21a9cff88b7939280e3189a8c52470cb4d33bee0a5aa05320d5b7b9bbbcc406d100000000000000000000000000000000047d844bfd9a53c81b33148e985e9d7faf74e9208f46afe78750fab0c7e02881c5d71739598644c797ef8fcd26d068791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029706a909ebf642eb10b57b592899a710c0d9a1ea2ca13844761885732edd327f5404189ba895e23b55326b51caf9300000000000000000000000000000000003a82793aab771c1bdc7ec8159dd64eb07e93be2e42e9c392a7e817828c3a716c48b48240584724719a6e7d0401408561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000884ad21c0393e133da9a79af06311add389f7de6f2d79b2f7014f811e24db0894ea4fcd874b1bb2d46c0ca1ec9080e1000000000000000000000000000000001697b7ad2826481480a264e31b6db86fa8e8e10ce539277d2887ccd63b92d8817b5ca89399fac52af7dff44ea98db1241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030445ea7780ba0b73fa802ab0ddde2f5d6619ddfc4d32ea3d142d0b8280d351df8ef055435e4e7ae6ff18dffdb0dd00000000000000000000000000000000001915df3ed014397359652293d2d6c76e2e87edfcd3b2f239d1c538af07768acca146565d434317b24f14a63438c537b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017467df73a1a06807a59df888586ea2a386eb627c6d14ea37c60e21b2339cb386b910b29c9aa88e024849f5240ba222a0000000000000000000000000000000005e7703e7dc2a99b3f1b016467b14b7d5b7e988850e94dec8cc22f1e5a864306a900ec68476a7f2d134e795a5df72bd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cd4cddb96619484e61be11acf1c0a1570ea061ed36a6a80bee377d30c3418e627904bbb32d86ee98b35d9e80a0589e00000000000000000000000000000000051f7615c7f6aaae22754691b4d73ed9e8272a5ea51af1f60e9a815b911d71aa78ad41f3ecdd07b84d81cb2b26f9f46f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018144aa2b796921a35f0f5e65d546738677df679c09c3bac57463027a54bf182910c595bf6fb7b13a60c300ec728f390000000000000000000000000000000000c3b9fec4c01a3d333357746a61349e71864a9b5965c3c480eec1071ca7e5a18c71aad0b5fd169c0c3a4895aa370bc341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d9799693bbbae9b5781609bd2d349d41fb17b07cea94d73a822b1bda33ba47f4ec4d55690a6d8ac4ff16cb32960dd50000000000000000000000000000000011512bb39ae06b7c36719624a7151c1f92a1ea227dc243a801d7e369986f670dc1708815b96078011bab22a161899b221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b40739e8aa4a2950889c9830dd358adc16a31dcaf779f5f936ff669a07e004a8d1f2a985db05d84ac24b115fccbdc090000000000000000000000000000000007edf499bd56229e65c007117ba055efc2789b08e8ee725be02cc653bfe6549dbcfde4e62c893d31928274a27665a50e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000358f3539d76fe3b4f0210dabc4b8d75677ee854376b5803940bab1701601f7b13a593baad51fcf7436ff05c53e2372000000000000000000000000000000000ec36014c9968f898b0d85b96ee935501473ec6185f4a2aca562ddf017a8bc5dbea8a77d38e72ba75a74127484a2127c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d80d0db1bc2b6016dad5190f9b9498a312a33a3094bee94c1c6749012f4667f76c534670b06fcbd5c4837e308700a82000000000000000000000000000000000950c5882f8a8385bbeb32304c6d4b2e1590d0b652f1647985fcdb6a2447db2a487e336c74c316c29d40b6ed62d4f1991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b5e9810bf844d425ac9f44349872eb19b047fef683ab5adea53019ba7ab1c49c9555f37fe0418924f40b7481850ff7000000000000000000000000000000000fba7994f389b3863f5f70aa5e30dce156baa4c9fb33c9e64383609756322a8e2767321f623c68578e7694202ad528201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183c9c5c754c9aef1c85d9234ad380bd98ba60e829b84788be951c8488cc7d5fb5f3cc4c07f6c018a9cc6de5bd0748670000000000000000000000000000000010abfa44b037eca1457ccc12b3d013e1617753c59d476d5336db9c87a08d6cc8963315cffc808535df2fc15078bb40551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001893f20ffa0b680ede98a4ac5c763d980d841833eca5e2c4586b819dbedab8dd804eaf99fd2fea21ef22ba56fcc1901f0000000000000000000000000000000007f921fddd21e75d1845c2925bf4b0d8dae1b5b52f3756f4147a4597ad4168bbef40069dd048f262e5154f3839568bbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013abdaa044a73f7481d20b7b309e85d84b953ea24823d57a3d8b87ee668c6c7e8ea9e1a711b78a92ec8b1874d5d789f9000000000000000000000000000000000e1a0aa671215617d3b9725723cd524015190e87e4397162f407e56380769157f66a4b6955b09e07c1b388af299cc69a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b602a4e1d757b630abd7bc4cb3c5386d8f64813f6c10260ee49fdf09593786c55374a92f5b42fdd6367d9e485265050000000000000000000000000000000001c6f3af834b07f685959682d6d91832dbb9eb37c3e4698f71864b7d6d4614f220c3b16176a0324eecfe2c57f08ecacd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000478767439c82381a0a5eb9dc301620f261ad5a6afc0a2700aac292ef926c4b8c43f113f7a5888e6df1169ed88cdf3b600000000000000000000000000000000135a229a90d923f7bd9264eb3af03371ebde0073e644a2e3289485a5d3480a6f02a518eeb606f8d66ea7f4a4a6c0bb871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121910719b09ac8ef9c78561169a20229fc8ead0d4f42f5327e9130f07c7a9c68af3f18795a9de753d704b32dc9eed00000000000000000000000000000000000713e1152eb454a330bd2e5e726432fe5d1e59acf4e64cabf4a3cc6133e5dd1a87449ae4b704aa8c5b0a5dcda1e260fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001524a2490ad9fce68d6c26e2dc7c424592a29d5c4d04472916d44a61f30291f4c8fe6f5c89db2169e2a2eab73382b6cb0000000000000000000000000000000014d606953a86684bc184c16bfda76b9a797dd5c2a6900c5bc789e49079adbcd8a8a4da0f3930e86be904efbd13bbc61b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f9c42ec5221d061c7192325b5f051731a5a652ba6cb72f6d4d454a7a7c9e43b947fb29f4e37fc4fb9ed78ffe74b9fe0000000000000000000000000000000013ed2be22c1df754bbc66b659c13c92a2e7bb0984872b70251ff04a525db41cb7501ee49acc0ca62e0f1abe8488d7c7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dcaa1293cd29b966a3a0813661b18c738e762235fcd8738cb0b7f3776b615ddc35a38b7904ff9cffc3b35a437efe2b40000000000000000000000000000000004904578221a1cc6c62518cb6e7dcbca7f17efc86d5329b54cc04ce51917e6ab1cffc06371828d817a4542584c2f11131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187d820063a1d46b115d8b65bbbf0ae6d56f475ccc324b2ce942bb94f55e1a9efb7ed5fe0769d86ba47bb22bce2fbb60000000000000000000000000000000000c2daedaa9f1d044f2bf95a733615f20259f09f6aea16c8760d94fb494c37f4d7d14dbd0506104544a9ae3a09fa50bcd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051e157a71e1678706cb82922200d15fc3bcc07d334fd0b06bee40eb7a5198d9f6a0c4b6de603041edecc325683ff840000000000000000000000000000000000b9e0e6f1267c4e6b9a7663baa138180d33f297a5ad07dd369a2fe037344380d47c77ad732746d23451b714bd4e7ffd61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001804a53760572300e00bccf2d3461ac77af784bc65ac01be9e374a07d055d604e32db40b4356e95a293d059a494b2f5000000000000000000000000000000000af1cd35bca5740a9a92fab62531760f3c9608a45b548bacd8118a7f4ec9470a7e5d60762e9c9823b93f9a9a0e63051b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006da7aafc25391c7b591b6079fea4f35fa28b69883d45168596c1b899f7d0e1ad7c19e10951f5d5d755ffa3cfc8d14d20000000000000000000000000000000003e2de39ce894986c95bdb831c39aa26d1042cded410ea1228337fafad81155d03c1b70f2f4091bd44123ebd953bb67d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a0b56b3e06e9a4cb748946d0193981f24999828ccf50a9a172d71d78a57e6094ecd6d218495e409471a3e9628da13b000000000000000000000000000000000fde7265e8c4d6d8c15f9127883783bfde4e6438578d2d9858f332455255c1c4f0344ebb82b85b940acb35e33d71e61c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073da75bd47306002b7130cb78883d4d0c055f62466f59473d6dae47758ac46da64ab8e543c77d1201492224621362610000000000000000000000000000000016d1aa37d8387595fa75167941100e641851c4b57fd659777e3a79bcc249c0b6ad8a6306e6d4411e84425c0fd395e0ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000bf38ee26c7076ed56683506a06fb54f4babe0b5c8ffd3dfb477f2986591e023338ca9cd58335545a18af4795b8d2a4000000000000000000000000000000000c6e3bdd97a87a07eb3979f0f486fe832dbdc4815d70a3c9e14f44b51283ce55044d686b709af58d3338b68f73cbe9521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6901aa3061540c90dd13f3deeccdc07dc300717dc5e8d8c78fd3176a2014a9b17a73410d816e39b08675923b5f7652000000000000000000000000000000000f123beb981e97389b695e7942292e4c416fb7be81077dce0b668419bd63fc2273526e5972fc9c143825dd4f0f9f28c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e8531f5bf90ea098374db41c990fb4d7b5e8f9d55daf206a7d585bec537d176d582481dae164c13374f7d0898b6305000000000000000000000000000000000b125674edd6ff3229ae8d86337dc4afcf699a0e665a06c85a13163235705830c60d1df7ba721f293decba8f2294b1b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fa96c23c82d82a80c6496eb0d28e14aac1cc0b85d48120da4c57f28f79f8263a78264caac9b911bf84337cc5b632f20000000000000000000000000000000013f432042d6582eb2191bd4cdf01f299f3a225362032450c2e4d56890df836bb7b2ba1ed20577b5331f033d8d28f05551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000354e6767527570a4a0972e9fd7d7ec4038ca8a0ccece2b8226549062ea3271447e3a9295129eeb472be1557eca3740d000000000000000000000000000000000582ea1aa9be0451188f6d5bc457c2fbba689b1c360c114ea8c23bbc4d91b6b7a13279e91644099b9d0ff83a842fe3e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001150a34a299d7a0e7cd42bb955707d0ef980a17570ec3d29be2b3a00949cb68ba0d261083cacd35ed5d16c574612fcbc0000000000000000000000000000000018fc879b2204178841c0098a6546eaf5295230bad47005a735e1437bd4e265e8e29f95bdd40294e82f5e5ceed271ab0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017cab28759256ae12c36be4f41fbdd948a385669405977dd34870c92d9dae7dd34d6286b6e79102b7f9aeab86e2ce085000000000000000000000000000000000cc18b5bccea8717dde660ff953fa4de2421f7a4503fd10aa158963a939d945407a49bb47a9b29525979f5e421182e1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c6d7939beb06aa0788df4045cb0833a86b115c871e7713b7137f18950304bf1900fe8f4fc447f71de0d54e1bfd2fbc000000000000000000000000000000000e9798f25879e29e81e315e6b438e4041d9337c9afe8f6e222aafe44730deb3ba4e055b3ba2372b4c2955f7735a004f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b91192ffc961baef2895bab8eb91bea26e3f82cf3ddecc766a7173917c3474be0dfe074aa181399e3121fea433e6c5400000000000000000000000000000000039e3494dc9de760c9cc602c2600cca28c3b2c59e93897e4f820a2ab804416985c1a7a0ce41ec718421d84042c1947c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113da26716776065e599ad8c03e5a83aeb6342c0226ff6aa16d99f8c1f14fc223cd0a5e4d9587258b65a73d667a66e300000000000000000000000000000000011d377f905252560995787bdf67607a78193ff64dc66dbebf6a0c22e4d8bd4d36b924d2c8ca591b08b4b37f3a5ebe1f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ae620b94c34f75e07fb2b4b0cd9ed53bf2fe5fde9dc7ace232f6b5afadc47ecf90e8d414d8dc87f68ae9c5ccfd92540000000000000000000000000000000006e0c1703d64d75adbdc96404a885e9b731ea833101e28394bd48510a1bbe8a2cd22180dab16f27e427311a18a9246391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a23b760e11e4cb2e7cfc5f612fa33fd9e4f960dd74eb9eec75c1256c4740bb0b0ba0e0958a5e67f9580ede91e39a2020000000000000000000000000000000005a977679380f4dc8246c0ed3ec7afe3a9b886f96660ebe86a14d704ac108974f753b1b6c4993ff52ef1809885897d621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbbebe9d82cb18059064a6068a12e671f4f14fef3979eebc514275c3c85c2819893a0b38b7be1183d75baf8bfee0a1e000000000000000000000000000000000f2b1c423da2111f9e4e98936ccc7b59fa8bec782fb34004d8c5d6f7f1d71803e175d664c425dc6e2430dabd90d8dc241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c96a15227e962a080ee5ad16e09d7c607dcd418b3093148fa6e4546294efab1228cb6842fd3ef131261a087dce81560000000000000000000000000000000000ddd392fd9bfef6af3b5361141f5a20b681384b6d5fed252c4ec95c8c4ae94a1350bf355b7651c792d0344ee940773fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015eb92cf3dfd70d4b4d669310cc5424969cf96e4091748e7586e040b96b47f0faa179e989a9cc549a1611583f402e81c0000000000000000000000000000000011e5dc27433b268fea5ddfe7c342598e5521eb6d5b89a1b1fd9a5b99ed9395777cd68a399efa8702f2394ee9463755c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010625e728ed2acc936cb99738721d573d58255febd7ccba09bab4dbdd5f5a21c0f97660e003ef15da9ea1489e8c3374500000000000000000000000000000000089298cf52a135ea35032a392e6439ea10d8d313bc9d8ef953f2da7f12cc29f97a0babf64e813ad226a161091d6d2e5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b0d33c656a6e4f33d97d690158ad3f387528ba63db1587a71c5672703f9d50ee1d6668cd38a8fe10ee78df8b0b5b62000000000000000000000000000000000b4896f958313a544e462419d8ff1bc0e72b5a91e782c4ce204dfe4bfdda9983a5b0f5de029f28a8764f680b762c1e4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050a36e428f0651258c0224b024ededbd34b31803bb11c1000f45371cb74a33b85c0da1118dcb08f4e935c0e7f01934a0000000000000000000000000000000018b5a92eb415377ade0db12de1f398e6c854653b4e319b23c02e903dd19f13ffb5d5dacb89d9b5274a35b3bb3e318ae41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b080a9991bf945f25e9e3f4cf7e3a99c2549d4200df0d0e0c531a68111825cba95f472a66f0443d1d55b17290e5ec8900000000000000000000000000000000174e795142368cff844277257cc95b0d180669f73239db80cf5eea4756aab431f64bf5ce7782db729335346bff2b9eba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147626943a0bb74d061969b16f1928381cad7810ad162caebe1482725fb6b3178eb9e85a7cc233df98dc7cc937bebc230000000000000000000000000000000005c8cbb684de372c8772be3df59e807e6423e39bdcaf75da00711ccdeeecae003ab9aaf3c28e98a81a1dad4d318117a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f79e48c24d2cbb4e30d4b06fb0a49d41a23f586e2472d1cba1ec0c762bfb9c27491434b1e7a48fe39929db79448fbdf000000000000000000000000000000001060e66daa0b5ecea92824f2f8eacc1076b3ec0c9903db829d2c41f3e8a56edfbb6e1abe4312786507bf9477c05295da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074c9beb0625b8972b380cb0271908e4176c800346a73cb85a91d3ae18ede308593919fc99bde12378eb35cec465622d00000000000000000000000000000000190badfb4e529e864995b9c17ee6cd74b792af2b548db005c7b3fd3b412069bc8a1c4972dc1b3852dd4acb0c0525bb5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e7a3c54d473abafa9d9ddb724a325638f0de14bbb49f0c7a3c35aa43f72f5761705bd79da03182945c917e0df81deb00000000000000000000000000000000124cedcd30a7926b9d689c5bd368135c15308ae8fa2f5e8e6cf2d5f5b37f5098188723d33ac4f3db44030b47841dcc151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e12b3941ac008fbd6201b7781272e9353352ab4e90f15a7006cc2ec4102a53e207c4db288d7562914e5bdf295d5f8800000000000000000000000000000000063b84d43322ce7ba28bc0380368afe24897e5c23c718a90231e8f52418db499ff0f342fd71d7dd2700c462826c9f5601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000835f7f18c6028ee64e689b1be4f6566776abec08fa235323eeb4b24e9668599c8670e460bb1d41aaedf3d2fc12bf32f000000000000000000000000000000000aa2655eedb6fda6b78fa7e522d0715e1907d657b331bac2a16f6b3994d1e3b05ffd93e1c76800d700247ce3681b1f9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001689b90708594f5d3a67f75f05c91a28773654e4714c5c283545c5aade7f933730b38b75d80b7888a101f17d77f1e788000000000000000000000000000000001029b7f5587f50ce70ef02f9bd58f9cec823c1fc7aac07a5b8ce30a040ee4801075fee129ea3a5a5e036ba50300c13d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e56c36c4a5547a9cd7446b9cd3cfc8a4c6e4773dea364df4811a1231c07a456945c7c83fdedc4cdce2132b0db3d4840000000000000000000000000000000018aa0e11b0464164393c950202046f38019a5f1147bcfd79564ac82ce6a16eacb6ee9269a25f05ba96411baadfe0e9501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116f39b4ae156184d0c74dd275b752bf2ee8a094b2642acd1817f7b04eb0099f0d69329f69775ef6fec6d97c6e09915e000000000000000000000000000000000992537ebba244b3ebba4028b5422326f55884b53dfc03b75a76ed1aeee3d3bbaceb0dd2b11e391d83048b5504abdc0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea1c1e139a2b9e01d1c114efc0252f36bec019fd07bc732ecad8e4a36d041ccc8efbc606503f4cd8bdf0cab718f9e6a000000000000000000000000000000000042a6880fb6ecd68df831d6d4255b1859b0e486c95756cfbd484d8c005665e1473811b1f2ff7bc5fcc44131197f09491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000803fa3115cd921acbad7d441efbb92cb13410ffd974742dab7ce88f08e48f5792cb57c1d11c833ca28e3d428e8206db0000000000000000000000000000000008f74a222397e0ed0fdaadae67a98942e1f1221fc2a3d9e83d34f991afa104d5a704b0f61a77915c683602e628a84b991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050c70036a2c272b0d4dd5ed54017448eafe542ef58f99cc4f108cc6cae0b10b6b18d5d7bd7388c9bc536dd6e59c91ec0000000000000000000000000000000018a5f2f4933b1b829f1f591b2c7310eb9bc56d40c10441a46d286c72d18e7ef3df057c855f35eaabef6984b03f2a3de31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137d95994193a0ad423ef6f90a7ec2e003c733e0da890a9c8d756461f7603c9baaa0afb626341664634c6646239ac6dd000000000000000000000000000000001813a8f6960e621b67cb8ce31157d0de23483739b9d03aa818dbcfa067709046fa7b913829dbd81bd9a1a4fe748875881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f7d0eaeef234399b1b585018fb9f49f28ff3c5e4b96484764cc5588841a11b2fd722f828d32ab9b0ed06af9aa5941b0000000000000000000000000000000007d8e9a06835508fc8cd0ddb97df1a0726c5c4c97e82ca90fdd687fd8a367b7fe5b25be52857010b8e047c4bfb160b001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001043c9141144c84ace125a0df6f81cc44221820e45bc842ac117b016b26396bde506407ac2350505785a681b783ae5cc0000000000000000000000000000000006dfbb8d69f19864fce2469beec2a11709ad4ced6393551b302c33fb82250055e98e4ee61f4cc4500b42536538e4363c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cf5d55991981a4e431d896e5ebedcb437599b9f678bd54e2b0331056d5a549f5a8e773086cd5bead08710e9df601b9000000000000000000000000000000000b930719148bf4fa8ed858fb1d9891dfab144df0ec49054548a51d1a14824103d6d88ad90e9d77da938e88140c53cb9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc4cc129f83d350c2d0a9f223bd5b83a53cc60da3f486b17d1f980311be02a61a82a9f28833fce943124c2761b82f650000000000000000000000000000000012acfaa552c17917a4e594b8b254b0106edccc1a3212e2c8ddb44227d10d0edee55e00b725d82d9eea34def70b084ca61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000146bae5fe4227ec94d1fd28e383c5bcceed5159ad91a65a6baf2e88be3d28a2a69dbcb0c913c07d74b04f31adb781743000000000000000000000000000000001081cfe902840aaf5b8c78a8d274c043559bf48f731fa0c942d75521a8142fdfd0b7f1750762ac330c66d26bda8f9f5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae074a9d3426babad7565d9bfe50359812a0e7f6eb214cc9297212a3f2de547d4d51cef62186f20d7ff5fb717b6f122000000000000000000000000000000000fd712a181ac8f9570f1977c76e6f99e54ab6af3ac9b7f216034de44c7dfc3f91f1f1a6ef7654c5a31e3f0ea3025c3961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e77326dfe61b083117b3333f0d6d3e4c747dccd3faa2a31998f8196608c3e0a41038f760edfe1b3bfb094f476d0113800000000000000000000000000000000160d2271afdd7a2ccd4bea2443e263ed86aa0ca8af6a69d4d6e35b2a09ca9e2d3f90892639ddbc33a92eddb52fee61a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca8e0ae650b19977fd6298fbd0ee2cfe1e5661f2b821753b549c2ab3a47622dfdd6e08ca89dc91d545ae555a59b3958000000000000000000000000000000000af15232593767435e86500f2f1b8922cb23e4fa72f45e10cd14b7f66200c859d4b8dd2c657a4a7aa083e5bf9d2360211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e987b3e194143c6a8960ed87333f9eac4ada59e5f17207317be05376dab64377151e77160fd1d11e5cfdc7ec868fb61000000000000000000000000000000001843f101a396b2b2e9d8ae95d1a1cb9b72c1e35344402b80726d47149bb55b6867e96aaf66a4d70bcc5c6d1e22ae5d601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072d47a27852bf70556b0713fc3879846138a039b49c204b59007e6a7afcaa6926e521c9cb38a9d9ee68a83e7b3a81ed000000000000000000000000000000000623a771dc7a0aade68f3e97ca7c35907ef6b95f03b81f65741bcb5f0fc04f8a238052d80a93e8657b1a39fbd179d2f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a473c948874d2b4d27c0a6a2d71dffd04eb966c75c13709b2dc9e47f2d9c325afd6b6e15d5009e958027764f817ed8000000000000000000000000000000000733933d7ea933bd7353e9e60fd42c406429bb68ac07094c161283ab7b4bf4efaf9f31f48dab1dd6ed7f1051e034e3791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd165ef4b04daf0d904f9f0b0b7743b8e1af8192b0ccca1b60d64fb3b65f2d3a88f3afdc67a01cceed93c10f7b687ac000000000000000000000000000000000bb1b760e397ac78acc2c6834557c782a56f83a8beae5365a385109edc722fd095e0f01ec7183cca8daab6489758431c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006259cc10b419a8d5ac55823899140e53a84aa2fce1ab8f8499680d405b48251549b65477bb90e9ce2095ccce31a610f0000000000000000000000000000000017d81ae5a3748e6ec118e0c7dc2e128658f06da33cd0ec79000065a9928fd3a3332f3547ec7522f45518615e3b45da8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149fe2ccbeffbe069090a4ca4ea1b47cd82494c9b501eb13e798f244e8593fc71c1b14d374a6113c10115107a8cba36c00000000000000000000000000000000072244a287ada3450ba7fbdc871bebf038420caef541ed295ff31db8ea054eb7ed4a45e63c3b2c36538a712ead620faf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bca769f090440197f815273c348a468afd1e5b43ad7bec1f24933c1b8b7445f2c9382583a61ff6a0e7c2e468f242cae0000000000000000000000000000000019f2e8b57ec17a2fbf461d5f5a10476c604264f5992da6a6ede80a23cab61103c4a73eaae4a43106c31c4ddb13a160491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175f5cebe49a9d9e0b8019aa55804a298cbc4e944c0a16b0f89b3d217c17e3486c0c61e70099d7ad578fe9600354c0ce000000000000000000000000000000001532ce826cef5464b652d5494e407a3e25851ae97919eff054baefc4a1dbbfd32d833d91a2291917c4eb1e9bdd57616a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001899e6529ac23ab5a412596828b1e192638a2f87c13c83acd61ee7ee377fa16d029408196d22a9b3fdc74985d9ccb45700000000000000000000000000000000021a95bd3f437bacf173a8f9d38dedb2b81cff014ec9372f7cf26acb7291bfde7f24140d280f6d7a2b44153cc2f3ea011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db3207016b163008e9001ebb72daa3313a555bfb571a0181b8cad9026d6cf1714c4fc5d559e6f927243d2b5cf50cf21000000000000000000000000000000000fb6c683858d00208e36393a396edd2fc959771720c4df27d03815758f55ef2f149ea92204cc984591811395350da4911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e21db878a3f0a7dd8a481a60374d28d76fb1305399fcdde5c20e8922d0293274dfc722c2c1400af6eee75f2fcd0995000000000000000000000000000000000719994ed98e76cdfb51c030b2ad1064d3f3bd45203a89aab20a3d0df6b0c764e306a90d0436fd24e49850e30775e7f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be766000482f589339e5fa516073c7f0f57f3b61fd1e8096e43bdcdc8265ad5bfce2851fd79c493888cbf4a2ff2e7b3000000000000000000000000000000000dca0e74f86d565b61cbde53aebd0f71254daa4bb575e1f4630ab33b6e165d2744c842c2b62acc0812f0bb3c1ad6ad9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f6b9281c5a11b945cd44a82a8590ef4e3af7ea8513a74bae21d0fc41a6f7cff4d9236081fb38812ff34c32f08430fc0000000000000000000000000000000002e2091e6dace0032b2c5525ff7a8e1fd365bbffe1474e85d15e46dc5f883db0b9b0a187befadf18f60fc81f6fa3dc6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c7b244bd94b6ccdab961ce17d157dd379d01ecdaf53b36da3e35f70cea2cd332ebb5a17a45a88fc4fbf0f57a10e71f000000000000000000000000000000000da6ed38ac031f365309508a1f9c592fbe76c837b45085511010a203ed6ace88cbc5a7900efd4548c121e068ca55ca101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c35f5aa682db98901f476e41d5f4578c90b9236722569af34c32739f9201387bc6bfc22acee0607684140f445a905f20000000000000000000000000000000017b9a78469a201d1147e1d208b74ab3ad785a87684917168761371fd3677c6a4cc1a1d972d12f5beffb1608e61ba41791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d95026ac7cd4501cefde256c50f90d9ef30f76d1ce01695bf3ab8f9c81a3473723ca21c5242efb87c9a45f7b3029a6000000000000000000000000000000000dfbc635443aebb9eeb2f292f4f678766ca4ab0208697ca3f459944b8e1a765eeea453c61de023b68bd680c149d70d0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f4d68788e35a38fa1100d42c2d32b357389f3755712a32de187fa24f058f33bf65b8f91731dc253ca1ca615bc2bda90000000000000000000000000000000017d4260b359ec53ce661f5d6885bfa190b585e2e5b6b390a7cd78f1a8039bd52f4dfe80e6d08998592b22f9c4ec4d4b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013d23197273cb72b9eb49d1b79523950928b1359cbbc219c8663bb3f004591e7a64108ab8072b04b52e9695db39a2870000000000000000000000000000000000676b33bc024a565ee1d6620883cd67bd3d0f89155e37686be817cd557cde6101f5c3d629d1af7fbdf361dab23379a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000864d88630ba013c1316f8e364cc4c0b39a13153900b1393885cefb0ee0ed72768a90d52d0aba61925982032efac6bba00000000000000000000000000000000081c2754adbfe9682f58c834b4f6664147b1108c1fa98303b7e2d9a8f05071eacb5d98cfab76768729ba246cf52524d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001372fc2791498bd11c89dcc8fd6617a4bd8ac4069d1a15f535b132f6636dc5e16c95b7bb7d358f3a6e9c55d778141c00000000000000000000000000000000000761e26e9ca8c064f00c7eea8e6672d96be2e18a3edd324befe7d4b70ea39ac325872424aedf8d3395196796ec06efc81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015711323df9bdf9dbe5423bf73ddd1573696a88b0f6d29edb300e2fd60441094f9ed6dcc0d61d7e1b6a54aaf2609f8590000000000000000000000000000000010e9acbdcd956a783359d84fba8e4a71cd231919b92a1e772f624347b90b310bbfdd9453502918acdadee21834542f401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c70c5d4af6a876bffcebd08bab2097f0f16160865373652111ff17f2ea96f483e170de13a489f392c19b7ad3f754ef7000000000000000000000000000000000c0f3d4ca084337f8de962c289ec01c8b8cb8798f7e717c5082282ecf9a967d821729efafd4f603b65c8832e56e7b7131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f00dd8777a3281ab2595a362e1299da287d5b34fb18617d82479a82ea90510d7048997da7059b76cd7e3388dfa4dcbe000000000000000000000000000000001320d82168d5d6911068d1e7bfa1a89b321098caeaa4fae7f38c57e4191cddfca284808c5225c82edf747bc37615c60e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004de15fd12b669b89c81ef4226b35e546b056bb8a0e48c9eeb90abe007670d9f5a2126be4e211aa027b424435d05c87c0000000000000000000000000000000008f2568e0ffdbe56451d45aa8a3306aa8e0b219db72970591ceb7bf07ba9f1a296d395eeae7267fa4cda51ac499d352f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014edf21be3b77894e79b0a55d9e0ab4fe8f399ad6eaa2bcbbdbdbfbe8b8c7d49ab31bea8335883c570d4ee32d35cf7ef00000000000000000000000000000000160c929baf538af899a618f916efba0fdc597dc46572ef66fc2fd25e8acb28634af18270180c1771534b1faea20894061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002bf5f4bb8d24aca0b58868c485ec80aa1535689161d43361bf794f179771797ac76dbe65345b2035ec0f969fcf1d2a800000000000000000000000000000000113d3450ecc7ad7b0723dc53ab41abd81de81c22e1a853b56156e725a6a5c1c45875cbeeeabac8c35104570425bcdfec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016d567aec9f19d8d9d2b17ed34f87384914badb67caf546413ddea616f666b4d453afe681073def102ffd93577724b9100000000000000000000000000000000197d67e0f2567fbd6960f2db0e4439939ec6ad1b68258d3a3c657611300f80b1424e61b0504778e43fcf3a7cef14dbe41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000040975e73640c05baa6ef2f5dddcd6c828b41b945403b5d83afe898412942ad435d49f650c49292c095af216fb25cf000000000000000000000000000000000020ad1ae763e2c2abbec0e88194e91dfc58c650687075823843af8e7792525f905acc8346c7cba8cfa4107ff37ecd2f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebd1714c727f1ab81dcf39a92860d1fdefe590ba680642c65a55d14a7d4726e4eba6b651d5651783394a4405e2c755400000000000000000000000000000000186eed887c2b22b5471f6ebc70daf747684b8317a900acd1ca884fae27393969276e66873a78feff0839fc88d15492191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ba9f7973c3f8c6e1002cde146bf9be0a2ec0360ac7b3acfb2fbfa52cb6da5be7f1bee392c2c3d9f0530aa59c4d95d1000000000000000000000000000000000a9f0fbfc226136a255445faafb1041010d240f3f8d5f8122069bc3e7df4491b83f9dc09ed9eedbaff68df1b3aceee511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1fc17e5fcb57ba387547763c73402c293aa6df757d2215ea7c47a1e00d48a69ae925dd8e6d5c1bffed2c0490fe21540000000000000000000000000000000007d9445bc180a97d1939b602276287ac932ad0fa6f5ee64238721212b46565f7182b79ced8c1c7a833fbab32298f8e9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001750be6b878b3615a53d7d9228870031eb93926e03d12f2359e787c98e4780b6c75f58034dcab4143f8575fa8a1ce5e9000000000000000000000000000000000bdcc4617999eef67022dcf838546b79c54b6724d6f1f0592b72bc73a5d62cdf45f8e69fa2c6f2fc7236272e554856601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035eb2e1f4bc7cc53c9933608d859437518253a8d0aa09d23463e0e42aa7e5d311be4fa365bf0327ccabab3e8d3ce8400000000000000000000000000000000001ffb7940359984031aabb105fd22d87a21559eb45b32fe998f9736de710ed1e63aa65b3484dd66972a7cc88e21085201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a74687c072d2a4c86ff5b4b59f917fc48ade84986bf3be94d73b33bbce2fab01ee8860d06bc4e7d16d6754c55bd47e50000000000000000000000000000000008f8854acac323c4a0208f72ce385adbcf02d0f2d8063c854fc20013917dd1446ed54e68c25179cee135fe57771594c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000513537c74da804e205803dd36d8c517f4d44c622d585b5604a386e16edf5609e0e40d6acef6b1a02ac9f9bd08da4e38000000000000000000000000000000000edeff635e75c5e0954e57a982d65e43e7deeda3aa57a743e98b6326929995c6684e9725af3559752791b9498caa92901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000396ca682de8c10640472834339221b789b6f3bb316781d4d7aae85531a8489c3f5f4c42e49d96380d955540f046c3b40000000000000000000000000000000007e19154f4e2382453d1a6d49672eb35ee1fd1869dd952dda4b8aa2b863e77c98b662aed1d9aad3caa6ab7abb1ffcaa21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061cd0d402fdf6fd82edc75564cc84bf8407be05e6bddf733e79e293fb0ef5aba5fa450215aec4a8f1b3f9f84c3c8d510000000000000000000000000000000007fe8f816bd15d636b42f6e063a359524944d4974767734a41ee7d0cbc0ada068f08fb3e5ae19ae90b337e1d2819d64b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b10032555ced8cabe9cc9bc3c2a11e716696d7d21a120e5ac5f5e74242cc9be741940a604b6763f84e935350e661620000000000000000000000000000000017ae001defe7b6e9f07fd9ee7bb1b40f5e7c386f53ae2a38901634534a78f98e49f249addd5c571f6a8392d0b68c5e551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001287137a0b495c9251e49d4fd1b39c9dfc4e18a2e4bb9ddb25f0fc3a4a909d84c0263ff92c5f971f67280b3b8781d7800000000000000000000000000000000002b1d687f4b9f8365393d0776486ab31e02fed21c0f681f90ab97fcf22cb2c627be59063587563891b13861124de3cd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e10cf4c4644ed6d5cdd44ae7711405ca67176b21bc650749b5a6205f56397fbac705ce1cbc6e6550d5ea65f1ff6565000000000000000000000000000000000d4e9d54b1ddd1a651e772bbd78788cec86dcebe839f6ddf9a28502f69203f952520e658d331c269c0be7e576b8657661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fa26775cca3f3182644ebe07fba23525934acb881ed622cb37270279877ae8bd18090d8b7e269d74e7924a0b22afcd000000000000000000000000000000000410e136378da2cdd00a5357705747a8242c2b881a890b355565491491b4ce6771955f921e8369d9b82d802ab355b51d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092822fc67fc229b88115ee36091c2bfaa68f415fbf447d07bdb38cbde07f763bb2ecf879c32b486a07949518d92b2cb000000000000000000000000000000000cec33b21a2b63939bafac2fddefefc57d0f8f6074d2acbe33fcecde1565a47376cbf74980a3f3bb3e3f7c11cc6f4c301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001460e93c82df1bd3a31aaa3a04d88647f133b0e6d16d4bea27ae5269b73fb8d70be69cd267fa6a8bf03b3b2d8231d4530000000000000000000000000000000008d008828d1219875dbe482e497eeefc49ffe22f65d80099b1226468af77320ebe42330b5ec51e56d207ca2133839efb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000956a4d45bc8f90604780aae88a458b623d271e5f2de92603f0a4bc830c0e0c74228e9ee374153d955b212dcd3312ff1000000000000000000000000000000001050f36c8529334c07057ccb09ca80a58a0b43b16087ea11c7429bbdbca3a1fb7dc10ff82443077f417349d31a308e881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9b1addcda6725c46dc3a7d1020de298ced55f1693f6b56b1c5ec8be3bc9c87d9176b2d48bb9ddd36ad8db533621a2e000000000000000000000000000000000d859a9cfb5f79de00e7285604c756c1770f1dcfee03011af0b64493fa3f1755b9d7769aece05b7efc585ea336467b211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040836499a84961f8d6b3b32dba2c8d7bd3068838f9acef584dbdd2194db56051662ea41073c83b016c49924cb2b5c1f0000000000000000000000000000000005853537d50a00f43e5de61d8e8141a7ef6182db08668717c19ae9ba0d4012bf2db2e093b9a986adecfbd5fe71f9f1ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199b1dfaf88ca431ae49192f069b74f8fd62acbe80c2818e404dfd0450725d8939a4a4a73fb0bb0d1fe64529a175d520000000000000000000000000000000000aa8778336022ef875b6b4ce44edeb2ea274ff3c11f06246b417c17bc8525c0089ea16cf08d4be990a82176b74d2fd8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008127cfa03cf0ce8e672438ea94b4f94114ab71d48332e9f05c83df045215cb1e0800ffd053bc7728a4fc17bfca186f0000000000000000000000000000000009a21359c62cb582a9ae82178a3ddbe156abd820dbd35668137483ceea84c1a2890b598b0eeb7224f3b146dbdc8194421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065729d9d1f5b452fbaa48a25e221d5621f5176911d346c33ae098c98081c5e97991b9dcd316f2e216246f62c787120700000000000000000000000000000000073c49b125b1346b8fc129ac99c8146800af7f307806e346f405e91987bc0a8afbd748c305f3e3ad70e9db0d62ad0c091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000763858cc7e97310e5030fce31f07943f1eac57487bfc45d820166ff8d1327d8c844d3f477eedf0943c6f1dd23e62e5200000000000000000000000000000000070f317d6a28e79cb3e6eda44ce3fded3b9dc822141683defa80e28b8c94003fb9e25978649b81832b2bbb206a7361181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000473c0f0c926b3ccc844456a117a479cf037223341191fdd1a1e6ad1ebad1229ddf290f4c87aa95660b46628330ddc3200000000000000000000000000000000082ef1dc0beda0b30d2180cb3df8ee6e39c83fcb0e12736e009ba60d69422323695303a618291d064bc0e2fdda415d521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d322f7c0460e724c7981294df9d3404b14b18613ec64fddc8ebf46fe916c85b23607905136e583e571b2176df224167000000000000000000000000000000000f4a78eed408a92e258ba4894f276817bbbdc2b42722aa92d5e34aebbb3227aad6353a62bdc158601d4692e0c0b14eeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030814ace0fc2fc9d766d2d67ad6c018b3f8eaa51fc7be5402965c6b216eb24399addc8bd70dac11af998b2412d05d1f000000000000000000000000000000001466c0680735bd81fd315401a10dfbc7ecc3ebb8d7904e4906ccd4969a8f05dd7e4dc9a194d34be5ab08ac56d42821cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108f66f4e220ea80a594721cade80fe5fd0207813aa16cf13092cc034b05f9b2125e0088199ccafd56e7fcc36763ca540000000000000000000000000000000002a4c80c6e405069b838dd034b4914aaa7c0ace6c1e184945ea370244268d80ef8d849be967886189101d80f5378233a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000061b5a278c3e4f9a5a441b70a610dfa807708b039633f93918de0fc59437ae17bea40a4bcd8b5aa6bc9281032e9138a0000000000000000000000000000000000ac40e7bc9347ebb8b9a88f00d56527bfbfbf64344a5ae796d2185fd3794d41644cf1894fb04e73a88954ba335cb18f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008885616a26b1f1e9c75b349d4edf291e25b7b1f93da877485c582e8887766cdbcb4d082774ca092e31404da4963e82d00000000000000000000000000000000032b165e72957877bda52351268734b53f436ab25fe933e5a1ea2579833284ef958533c3b40fee209d8c85fd1ddcfbae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000811939654715967f79a1a7ffd4d6fff0b45de35886bf7d399eebbb4dbd673823180a17c8ebaebb7d0a2203616983f330000000000000000000000000000000008f060d0cd98450ffb8df8c3dfedbc528d28a8b96d5cbc96bd9916f93613bd9314b33c82bcd6a90330463f98b72f31481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006370168172032573b726e9c9ea9725fb7896b848e03dc530016ce0bafe34c317f686d7c54e8c9ba350c576416d03309000000000000000000000000000000000cdb96cb4648af55be9b5d9f8b36ae1453e6867531534f64ff7ec3a074e8c1e68e24dc702b0245bd4f5942c76878e7e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013952bf6e5f7f8bc0caf9f0f9b193717b90bb23c3f5cdcb91d789ce286e1415a675cdf3d9fe5369ddb1654b1a02495cf0000000000000000000000000000000006010725c8d83e11f0c7e95539d1cec4d4ad2dcce2f64e63f74812921229bcd86eea04cf68406a54588b0b62da80a9581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f24976039b76a6a71047f32498b491ca1ac9a70f67d2ec96afba3f36f4de3faef4be933f8bd34496f90e23229e2ea820000000000000000000000000000000016b8337a96495b5ee2603e6dfc27853388f8e9e92144d38fe50bfe8df49b087e2d974c486bde3e8afd34796c44d8d9111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ca381c789bfb65c6908ccf68d573af90424272489dda7420d8daa6d99d2f9fc42da6b74f24c66d53d11ddbac89128b0000000000000000000000000000000006c6157289990500741b6384d529d87d66b8b4c49f17898a4919fbd7a2b515d2e19907b5b49ffa8ed7b1b08f377bee081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137cc28952170bdf54613d57b8d64d4d134f8227b6be7fd9c90ed73006c79e802776a17a9dba6b3d80df5b6e187a18fb00000000000000000000000000000000046023a6de6c99d01353b2f2d0776f5fcaf410390d9638df993d7c3663d6ce5be67a3e10cbbfe55f953523d4fa2852501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e9e328352c4ddfdcff0954eb8fe686cbe66caff29e75d9ce760fa1ee96bf53aa8e3e1e5d6a6199ae758c8ad2f5094700000000000000000000000000000000008db49767c72d62ef1e5567c362629340b0d270cf465f636162e751f4854bb6d5bce10e1fb01e8552240008531296ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfe601d0eee89e94f16e5b7bbddcb03dd36225f4800999088a56c29282084a8f81f033cf46d1b420dd426a837cf6a3200000000000000000000000000000000077df5b662b6f3a18261cc7407ff929d08cc7993e875053cd72b59a81342b5342ba186651e4102437b0b1f7b673ac39b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017cfee3036a352eddc8272290598e66e0a01f63c610901f25f3475a8df2564a28fa78a20635683c06274cf500aa0933500000000000000000000000000000000041c0c9cdf9cc2971ff9275d1944ebbd91acca5b3623783262fd768cb828f97f6d92c26789674eb75cb67a93268328fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148f9d1fb9a75e6fe8e3a1a8841960c28f87c817f34c2ba0b947d56e51180e7aaafb73a9257aeb1f6bcd78256076458500000000000000000000000000000000108920ede87f0732393274e2990510eb01081587e50b53c59c44334626ee450565ac5f380375bcc162fd1c93208a863d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e44a683d95b957c790e2eab4766ce8c5529657f953cd14c17be536962b15ed5cd8643a5c452d9c0d814f674e55104610000000000000000000000000000000008aaec51383ab7bd709f9a8b3b67c2dbbf038965a2169a7eb8812260ca750ec81cdfdf8078ca73b65597f67bf6b077651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab413ff5e4c05e1c3e3392a59328a8765f9bcb8fe7e23e0be8228eefbdcb1641377404fdbe2029b34f14f6ceb9763e80000000000000000000000000000000018d24a78c4fce1c41fb160f2899033e1eaa9c5fba794a93993a2455624fb02b002e28b8f2483524dfefbc079068d65591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee9c2e736e12b19b90c5303d521080ee69640703c1754ac6c4152d2de62b6cdec118ae4497b0f25b1cee6727ce6d1710000000000000000000000000000000000fd2a4abda83147ab7a4d602d33666bbf9ecbf8c3b46c795f4f1bb5824be61c0cc34376b2e5c42b6a6fb5d1dca480341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ffa325131b62f24a33e4ab6671aba21e88ed99246b60927fbd0e6e1a0c34b0a6a63218bff025bc63501316fbc7dead00000000000000000000000000000000044b65a54deee4ca65ef58c363680b01dcb88e81389b14c4712559083689c2d8a0bbeaf43097e89a45a80f531bd42d321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c5ace6433cc539600fa8e001a6a20b09aa5e03912a828094319fd79ab72d2e3d9108850151e773834f4671c35a16c60000000000000000000000000000000011db2ae0a95f4854d835b767dfeca4a0747da3f855e82d85ad026170f1c7be93eb4baa13ccaa55cd7ac1f57424c5c4e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb5ae120d5a9d211f5d9daca16a5bef4425135ba75eb7e9a97621e5f35b9191fc405d34e844b22b45d302a19d0f9a8f000000000000000000000000000000000fe116324424f38d69fbaba9a0e228860be5c81ff9844403facce0f49c089e615ca83f16467f829893b1e959e4413a751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f4a39fbc15ebd6c23561b5cc5120d97515712a3b9b7fb5d75884760ba5f7afc68f761d4b2a1393affdbf19971c15b0000000000000000000000000000000000574e251b22446ada61464835a8f1620e292e624a3193079df2df1bcb3aee2da30bbadfd5e3b6f7fed3c599eb2fa9abc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159bb5561f3ad4a74167be4ec4b79af84e5f83ed2df14922cd048a0fba227b685d51123e4d326bc8042d9b13abc695db000000000000000000000000000000000c43be7d98d5525637d790b07917b840f54e500276dd364219feba419bda275899c99ea5abe1d0a5d6a1972b0ef4ea291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000763a7bde57e58cb69f8a34c28405c48bde7b0e5807fe9f81effaf45bd96e475808c11c4c72cf5fb285bec2688c2b6bc000000000000000000000000000000000d4aa1c10a030d7de39b74de6dbfa158331e70ce664335c3d750565fa0820860492271ac55f5ec451f2e46703878cea31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a1ef2394ebdb558ff688c47fc79aa9d7a0707383a9f67fa9188cb643ab25811ccd253fedc0c7dae4ff77b54fa5aa5f000000000000000000000000000000000247d25d9d688a054d46d53b43aaa4e63f239c91c3086b568cb092dfa694c285bcf69c34ff329b976e3e3b29dadd9ff31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042182a619178d483eaf287bfc23909e36efef791a9318ce9d66a2fabdce4fa1a318e4ece9379188aae2ec63bb78b5a700000000000000000000000000000000174f6696194133d8b500b90457d9de7afef0345d14cfb6def1baccd16f7c34c10671dcd8a8f235f8e79e5a352df1138f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001697cf85252ee50c9e52f7b0822ee7bf2fa690f109086125bcf4bc24bb5d8e6ecc45e95f2fb4343360301c401893c8a0000000000000000000000000000000000cc903b21d3347a0ec1f88c90cfe5cb29725dd4d332eb2a3dd2f2668867173964785327ab4b907ef97f70ad73207679f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b29f57ee653a017aa6bd0b89d48ab2df7ff083276d3376895d6481f0cf99a425d54524c002afb6f985da4031443a74a000000000000000000000000000000000231a8b90b77a58e42638a3575a81f87a7af311adae80ab12e6b314733c819d74dbf315f16b40eddd0d6435f17a0760b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035124899f58a0ab28dd9d41bdde4190c6101606b6ec42b6670bfb2d7fada41b6fae728b72b1373e463b22737646736b0000000000000000000000000000000014c8348fbdddecfb418aa553573ddb9cd3892f2ed660bb1873458afe086c2adc2dbd999ae77e7ecacea23e416bd3b4ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065fb382c0ac61bf04deaec0938fdccf3cb86ca6e6b6fb83a0679587a62bbc2fab92fdc80815a439558a057df006edb9000000000000000000000000000000000cb888ba75c42a3abbe79e3fc8fc6d720b1b54b3470157228a4c3d797cedc4ef48ce3f0b536a0d75db4ea209fa27c8c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ff0551f558ba2cb02bd156b71a955dba9a7673746960f7040a067370d8ec3bb19ca12e24c82389900c00cc70c545d00000000000000000000000000000000007019f11712f452d18c994d52a0c31db4fb8c718c7efe6271847c687b6be23b4ce5fce434bb29f57cccfac1e197aa7871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009322ead30a644a96c7a431e167483e3474c00abe9b47e64f123dc296e3b8a495341595cbfe38fef12cb17110473fe6800000000000000000000000000000000170c3cdd855347b2f7ac01ceaa18d0f980b37a79a96b0bcaa4e9062c24bb39dfc331e8b257dfed1b0c18bf6d198c174c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4b6bb60b71a4c5bad58f0c2f8d282b9b2b8952ab9073a0583a7a6f0a56679a18e3e42f59534b984e9ec7b160305b1300000000000000000000000000000000027f62c83bf03b65cb3e9ab90e3104d65b291850233e1ccbd6379f29a042323915ad2d312d3fad88f745f89f5c6ca2461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009342e39e49c0ff7291714e830b4ec3ef76e6b071fd71c35d4369678b0593dc522f62ee6938a129e5c17be140535711b00000000000000000000000000000000093559c79516f7c71db4473460fec93b79f601b7c35568590f21a9793fd46f50e703bb19f04df53afd80ce95f914754c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117f6da9bb120e783d03a08ee56118d3843a791dfa398125f097652cdbf9e5eabf10d403d09064223ed4a971830a7e1500000000000000000000000000000000064469a7424bde9e45b3bba41e5e196a1c518076d121df271741abb2e47f1bc9c6e69a845964c6b4265d0746843612a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bbd87e6dd10fa07f4637c8346f196b77392e58ec729b214f1b2d6268c361584b89eabd52bb99942ffb13909f849545000000000000000000000000000000000fadfd8e2ed7bc7afbfbd697b88358093ef5d965ee71afd9e899bcf45e5dec88f3e4546ac0bac2089b90cbd6ed577eff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e77bff20ff9efcd866747da07027d917a52167974f0993c179c8e4fcfcb9021498709b5327e597a1486e281ba2276610000000000000000000000000000000012a7098f193c54dcf4bb9af7dd45d3616e1405dc8fd7cd28c955cb8f67ee04eafb708fdf3fd4d1a6ce23e68106e711aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000702d7334921562dc0e81e0d9565d58845b059a6978c1e7ec541d37754e1407e7ba945eba53934223bf8a80dbd80a4c900000000000000000000000000000000017ecdb9a4aa688b9901efe8ceabe33dc846c6ad31c367b791d0ce69293096ae6a6fdfd9b0542f906e58d1ca9ee8bb291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013bf36571a46fb136451300ebe32b2b2afb55ef7e3c62663d35f28f52bb82bfa7e4481fa81723727df2d828af3be65e3000000000000000000000000000000000652c2fcc391da6271b28593af460893b7a23e5f0c6cfa840abb7111f353c38ba5b4cf775d13f84e460402f76f2956001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017571f4ac610bdde007e838b1e3cfdd852b67cd46fd7508de64aad01204143aeb13054c9a320ff3be146a36efc95b2450000000000000000000000000000000017ccd16290d32ab0d72966fbf0104cbf05d510a4a232b055fa5ee0087166ac35d9c737e21b8e845ca673dc76cc3ed0531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8b823e4e24962389ea96212d886338f4bc9a4e7ff2be7fa4edf0c8dac7b7317049e3e0ab5074e2455399743485017f000000000000000000000000000000000b1aeb78d1dbc71e2045ca6e128d1b8a924babb9ccaa48bae01aad0a24be8b1193646be2c0c0fb4624c4ac7f33e6d82a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a83a6a1f2e2a4a390a17a13e7bf3ab1cc227c7976818c7e22b111072cd7fe46541032c2277588c8f1bf58592c75ec900000000000000000000000000000000085c79123fc6575c8ae8afc068397bfbf49cedc1018315183d5849e3bef65505c4978b4cb8c8258eea326e024b8785161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000502e2682bc2d212cc7675ebafac2ccf6ee6e8fe5d56cd46cfdc1d9f65e1bcdba56650c3a1a8d4d545fc62600cb3b7ed0000000000000000000000000000000016e68923a51dad89f65780c9868aa7560970e51fc35ee09e0fec9f685673e52a25d4ec148a2b8b969082408637bb49d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180b1dec1a5faf0fa04b417ab9aa96417669d5ec650596a21563f07e3f6db060939f0357a52e6c874828812f67087f9f000000000000000000000000000000000292cc178a39052e4d8cdc5c3b35b5d907e082558eaa197fa3092c12a888dd76c4e5ab1a57c8208008f64e911217d35f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000485421dfce3bb5b31466f52a9eebf8de23d77b9dcb0adc6d67c9151afab181038d289422cc58e34f99f7b1034ff66300000000000000000000000000000000034e031556b96e0fd847bdad124be5505028bb0fe8c1a61f8ab5e1077fc052efb0ae1955368d762fbca554c3853d513a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b048fa6198ed21ef406c9a62caea97f04eea5b6ead3ae5f3651e60da6f670310cfa4970bad2629991f61350ea0259b0000000000000000000000000000000001635f552dd8dae543006214523abe6bd4a12e25563fb52505fdb89fc60553b9ecffd7e0d8f69e4ca2185008f064c78d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005c5eee11257acafe86bfbff9947f0956d1a744cc4eb9386d13ba49537f5c1f7ebbeb52ac1ae57f13dbc458eab7c4c10000000000000000000000000000000011ebb90f116c32f8031d23494089f78aff9c48864475e772e8fd5495ba0e76e6fcf02797fd4c349517a981da3de481191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e99858241af981d2bc129a7393b3bdc93478a278a5a72f290633bc66b4983a6d3b2b0374bf5d6595946902ef405e67a000000000000000000000000000000001360cd4d2be3a963a309e68d0d001a0508a3c85feecaf3be8f5f023e277a82824b570c1b644565d1c483cade402058141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000386b89402091048fae55be428c7ee6d00b921614242b6baefcdeaa87b2fdb9358e0c4a5a632450739281990c9142497000000000000000000000000000000000be5d7ce8e9377a98d52398f0ce9fcfd40550b35564c40a10ced0be046c5cb7704594ea175e93c159c189f5864bdcc941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5061fa5e74c6c01d1c20fd2c88f9ce5c11952d4656959ec39dd18c9bc1a0f8a0823df9184ce9c9fdd73e8615d338a9000000000000000000000000000000000e5422089f752f5f62df213d5c47d59445728f8fc1e29ff79c0c21e3d05fb7d831e2fe6921698a1cee5cdb59a197849b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151a67dc79601c44e752545520edbc37e176e3cef4d9d7fe67bbd1abd73bfc7e704e784f5bbc317dbe847271276d688d0000000000000000000000000000000011687a342fc0b3f5ef14a86da718f6d6d2db9b4a63193c3e045a3e67aae20126c018f3954b528a2502b8e7635af8d1691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000095f7579d4ea4de95fad8e23effe5745d69cfcfeb2c28195a9d0141b88f999a42ef50548c293a39010463ba3b1eee79e0000000000000000000000000000000013914fe434be4ef6333641661672ef317a373f615c701a95323ecfc52b5ac5306f1564b4908acac1d92bea9467286e551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c90a6ab03ba1e40b759c3eff77f70c9362bf27a0b415fa1eac6f210cca9d8813c8fe6ad1a1f11eb5b4cce005f705c90000000000000000000000000000000003e78bda2bd69a1349a86405d436f5ee0595236119e1c6925ffb7a821b3faa4a120804fa70915b0f5289c88ad95626601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c1810f66c313cb5cd8329244ceb3e538a34fb5dce737e96cce8aee1042d4d900ab82831fd6e449e57db4bf603c82310000000000000000000000000000000003eb976bd84fbb7655773782129858ae8289c7d6dd08eb6cdcea047c185fe442fbe3136219216c349ef16a5260f5875d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b885537229dcd9e8f42e00e9d62cabd3957210855cc92a60c0ce35ed4d21d077cf353d7534eb1c46171942143d1ce00000000000000000000000000000000009a57128d7bc9f3809d05b8466f5310852e3b50ebee2029f35f76ab81e825e67299205c7ce9c558b53ae1a6850c20da31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001576d11e4c4094a82d6307010332bfc299be1b6c5f2b2d2b1476436befb061c163ab17deddb47f361aaa2be0a12c37f2000000000000000000000000000000000d8767c224837c2d1f2093fe7a352d7dc530f012a1f0a1ef8f011880ff3ca705b9d15284d1b8468a65cae94c9accf5b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000527eee0ff91b68dda2fd5d43511d20578d225496defc97e1e6f8d7897ce80a1b5d66e6dcce7aa6c374b209594d3587b00000000000000000000000000000000007aa971ea8f2942de31b5765663a479e2cb92d633fd2bbbff722da14db500e8b184e51b2e9f3df49fb88568e47ad42d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056d56b368bbb6f06439f124f3246e5868d12b7d11539ecc3b8547126ec40641859416f871f4dbd2ebdf3b5b48c2fadc000000000000000000000000000000000a6c7164c17dafc85d844da68d8dd11bba8dd45307d118a6d83dd79e85f0e3577b2c0af2bdb6bce47f632e6228af97ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160dffe6d01b918b0c468b487b005cb6cf139b946d66c718dfc63b273599aa3e5c3041b163d94defec5d4e4b92560f9300000000000000000000000000000000188d52e52ecef9fd3edf87b0e7145f8d4038301b58e45ea891c2c71212e23f5aaa115c901b169aa059e658f89ba21e0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000411894e35d547722b761f3275b400292b0b8aad42c69c9818fd3a8fd9fc8deb28769efca48059d20ac8d3f4178a38700000000000000000000000000000000029ba85e1121ec3b914df7a35db64d7b8480b04d16f57fd43cfb4e5d47b4c38f5b2a904dd471991823eb72c89cb091b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001813363c6e145148c114cd83ba38d4ae8274272e35b1432e39204431f2bdba50180b74e5b3d3c4cb198263243f412ab200000000000000000000000000000000027f9fae80b29acb1a16ee510d86c75a47bd390e40f2a639862130e3a34f6369dabf44205f06d5dbbe43d18c5fd27f731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075b3e2f7ed60c87a0c3e5f0cd2e4b06fb5b6eb78bd94e033f03ac79a8c8220d3656425c76cde8c8d61708a85113e497000000000000000000000000000000000e0d1924a92ba1133ada7d4a76aa4a7a5df51f46abd7d8228880c78ec112b09da61d8544dfd57f0cb62a9716395bb1ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098ee937ca7dc00a8f71b3d020426968ad0d4ec0e06c6f628537c9c486eb047a2bc56316871f4aa3a2885851c4878dc900000000000000000000000000000000165d17cd127d262ceb7c18b79deec502173ca3fc1b06e89b967127511fafe044198898914ea2bd6784071b8b8f02b9231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035033ddba0c6a00a5246ac8dc7c662e5a90486fb184952498d7f269e7ba9402cdf1db237808c0bb1e25c20447fac014000000000000000000000000000000000e38f5efe637f8fc54e165faabfb58294d51569db89912ffa55162dfd952412b32747a48a5759d9c8b04c252e9e8624a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5fe5f0c35dcaa100d3470644f541484a8e928c226ef53c0786fef4639c70defadf416170de1039f4f542bc8ab1aa0700000000000000000000000000000000158cc9cc88a8a281495bb321a808bd202cf79d37d3f693b92440c60ed72a3bc6a999a9136d0b80a0455d736ae11a2d1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002683087640ca2f9cc72bc8a9fab391d98a6f77d2cf6952caa8b73113f812794779dd8c479c2e373ac8a27097fd3b2750000000000000000000000000000000018b8af4532021ca43649dcf83564212f53c3b6c13fc63ee2f6ac45a5aa4ddb2cd1484024c1835a46d655c0547999ad451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012042a79dd5d9082a34f418ae88b8fddad2249f9c6923a3c70cc28e88815f3215147d7eef52e93e50a4508ad4013a921000000000000000000000000000000000a68b33446e2a40e31ff43858c0d4f7b2909eac72b88bb196a8475875ed095c9bb30668dbcb6f815c700bc97d32aa69d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad7a60b0f9b798f9ec744f88fc04c05e8d3e4b20b01f0cb6d3a7bcfc00ccc171507a569a6e912cd8ea910ed4d1102ee000000000000000000000000000000000fe0f84cdbc80d3182a3211952efd9c80d906145b321cd609b5837978d6e4a8d5fa25fc5615a451ef1c7c263586f4d9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a90296d49aa133074f79f104910428f9bba6928c9b7aafdb50e1f749eb54f46894acacbbd36ef9e1317226ac583c540000000000000000000000000000000014865ae3e38b87f26d9fedcbd88633dd34215409e271861a2d291a19efb1680a32ce6bb935a89c5d0544c6b5b848de8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062b20a559b3d08aeac6fc78507570224547478d45ad5502618865b0265c74f1e11379802ccba0bd1f63de5e58927968000000000000000000000000000000000d37355458d73c776252f2370a38457330aa0321e7e0c577fc8ffb0e1256bd02d9823a76b21bcb23986127c732e08f3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001352a9ea1c603e4831347a65e8d3e5bae73ced0afd4d716d5f8d61e0c0dabb59e7ef67a967e27d073e66412e380f3080000000000000000000000000000000011f3d0d9d53f5d1a9a10a343faa8287bc6bf63d21e556e8ab06e9ce7c0d87e524345fca6f9d0b7afd56f12877ec09e9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4085e3b29fdfaea8ffb95f341d71012b186ab31057d0ba84deca90e4ccdb8666d130a0f879fb4b4f4ffe71319aa5bc000000000000000000000000000000000b455673b7afa2a412cc2a4ce7f672c2ff56e0bacef9e2efbd549061c3afbaf28c7d665857d47c987f04641f842a76711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067bc7dc93f1fc5ae13d6cf623d9320fee1a6e3c9189e96fe571a57d2fa9323bc515ea201eaa3ff56af35bea4de74cb700000000000000000000000000000000152875c58cd8f0554651b874f00ccdfb51d06ac22175baaf8726a69985edc2e37e4537673d95b4f860806338cec715c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000101679a1704c083f4bc6ef8977eca52d6010a4aa716101a94e1f4e9e51f0e7a2e7318f62266b38c92dadbf03b8947ba000000000000000000000000000000001767857cbf680c1a02c527f2155b88a5d3eb1260f66aab848253cc3b22086b239070f91f64d77c177d82ba666d2eac6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000563400196e3b2bc30aaa9c0ab8ab0ad8497995f3ea7fce04558c827434cbdbe3d211cdcf1601b9da4ef31d089e6c4c6000000000000000000000000000000001580c0e650488c186817c53b7f04ad1e1038b7c1c957f6628b92a07aae88e524346d8cfe40e269c4a53b693a9a2fb1721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002422e90d3c9da67aeb6f487e0ac60b7948d766b37d318c72fe454694ab901c666e939b453e7eabe0afde69c5fa66f0e000000000000000000000000000000000908c99d5e8c0fa8382115ca083d3cd91d1a709878a5ea9023639f9dfae2f6f5f6fc86eec0543caa8dfb4b5b02d2161b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6f9e8aa323df1226f097a2fae52ceb646038b37bf7f30c7123185c82a29e083e8c4511c149b3cf15a6c1f48270e89a000000000000000000000000000000000c53eb2772b99e3ec63487b67a4d0c6e9db31199f1a60aa878c9181c28a9f3cbfa06d46afa47845c484c7ecd47fd1eb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c2c29eac81f5bbee9700b7ab0051843aa4f5bd2d785e7532e7d83818ad05b8e9c96cbb4f0000e4c4c57295b9dfabd0000000000000000000000000000000000475385cd89a62172a09633b2ad1ca5d489edd5dc65987369e9c86d2cd5a1cf7a5a17584b590be8dd04096eaab7716561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026c40efe3aac2b7807948724ae3437de67581c4d0126028b74ec374572b75d74c181aa599936f5e3d2265eccb3b75c800000000000000000000000000000000104ffec118d710e01ffbd0ab625d18d823d730356ad3e7c1c1439feeb0193cb2eca3a3e3059a8452175edef161400bb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb6764f835ab810c4c98b34fb01bc5b87632aa36d97dfff6ba05011500e61457e8e77e7e3f9f82562e5180456ed676800000000000000000000000000000000087d8e882d64776fb8f4bf9aea0c0c15004a0a9f303eee2677746806f7197e21c30d996d7a728001b5a101a529742a681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056d2d37f86675ee5c7297f352439f2303833e8090f3a099212756cb6d6d963ce5cbec226b0877b7945767a7031428a2000000000000000000000000000000001591272b308bbbd30d682296a7feb34eda7d44da2953854d76c05954d53b18ace8ca0f5c32d5cebd6221271648c15b771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001dc34329b06516d11bb7a98bf698c0b140caccb213d1d5ba130622087965fe2eca5154f4ba52fd3db944cf2064fa5240000000000000000000000000000000000f7572eef30eb62711d4e6365c52995d36e26833b249a3731fabe7f25c0481a78f460ef7a45e5131e2f7a914767877d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d48cded4e28855ae5af35fd787f8bdc49cd8dc58024c15e413ef0ab34b3a5e8330ab6aef621bba28806cbc8e50ce418000000000000000000000000000000000057416b2b9b29483a8bd853a8d9ee9038862d11b0822d9d8aa3f1fff71e5a1b5d58d7bfe5afee922818d4195fed74741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dff1685cbc9e9423f8dcc513e3c958ea106a3f2f800406569bc7b86365f10023e3d13740f1315dbcd0e1025cceb980c00000000000000000000000000000000128ed8907e2539034c7cde95f8d6916cdf4c3e352031419871887e9cde6ef87c57deb76a4712e9abc386641198d5825d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000096bb778735b3867a5dc185de75b7732f6490508d0927f76748c300424a6638101bd253fde0d989c70d775ae99c95fba00000000000000000000000000000000161b527e7b0edb91c3eba69808042fa84d168b1adfb39549b3946ad04ab757c9ffb8e9a93da910c4a92b7bc7de5387e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136f63ec0c4ee18f1a90b36541914e5307c4c33f3f01e3ea6f4c12f4a21c6c3c3f82b7cddfed5cac821b7bf60ecbb9cc00000000000000000000000000000000196116911a5980d41397304b5e87cf54ccef10d76e21ecea42fc9d9247d7b63913b92c6a1d55fd8d69ba3174d14ba1d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000015b874b6d84bd5b7157e2a3b267e361653ede58b098174a22d6dec096572d05d5e4a2ad7e60a67ea6a3f5e5781a9fe7e000000000000000000000000000000000bf50e866245db6446e8a2b294f6987a9305f5cc8f855bf4e04b9707552307dc497f4706cde8f5c849f3554ab642ca35", + "Name": "g1msm-2048-jwasinger", + "Gas": 4276224, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000a1730de8e6abe2efc1e10dd1ceed419d14ec6ec5e8701e17217ca974fa33741a444d65b0f8f59961ebb354c37dec39700000000000000000000000000000000023c960b709fb4a0789e2fa2496bdda7330ba40410eb959dd32cf620787b5cb52ade72ebc3d7c57ac62f4ade497e93111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001398a54c25090c1cf9eb94504693ba8718a8c40150fc47c24959360e0569e45a0fa40691b3abee78e24d55785b4f7c4a0000000000000000000000000000000002fa98a402d6470e1a14e7ce61bc952e6a3bd17816b25231aa0ef9be1da07dabebd7d4399d12c7a80dbb8f33cb7844871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000774f2bfd349b970016d57bb932bb43be2cfab127e2da90cd4d2d2221a1246e7efbf684097c7121c7c677cd1092ac751000000000000000000000000000000000093049f314f8a8b613975c9d3e16571abbebaab1e4d09efa6e12dc27f519b918b45990ecfb4ea41772d53ce78f2e53a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001122c9857481ad1b06a42e2d6e419563853538592d37cc6d27481f7505f5efdacd3808c3b44e47923aa5ec34e81ee23f0000000000000000000000000000000017cbebe357bfe70738d4a656f5203bec6f371aff0f777dc58516eda53792906ff31b824dc22d5594fb5caeb20ce0447e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d49e3f5a9959904c285b12bf0d3585d4dc32ce9b72f6918759c4cd0adf71ae1e10bf5e0976081906494265e881f9e5000000000000000000000000000000000dfd2340586ef9b3627e1b442c986d507fac383384da9da504678b121db9c0400d2e5445a86f3981885d0bd0a02ea8201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001065f05c75bea3129a55715fe93d4afc347a792697720e96d06b08697091264d01a2372904e47816e458ae38f56203340000000000000000000000000000000005130ed7a8d1c1719a9c4982b0a0e61e08c59910e719e5298760066edce86adab6892d18d01df7503dcfeead616c25261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153b75e97ffa9a7a41de85b2c413d1f2138cccf6e27ef3e3f3ece12340333204843b4c2c2e8b86d136b5c6c7fb30df110000000000000000000000000000000009914563dc40520452f0c4456133ac9eaa2b44014aedef3dc48569b63502f8f298c71aa502c72808a1cae66e81ba49621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130ab51776303e6cfd0cc3ae7566aa24cd2dec7dbfdd06adc50a7f6fea630958defd538104aaee0b00f7b35d0773f19b000000000000000000000000000000000b0bef4683439b5df92dce913ba9c55672fe2641d59f5f6e51ea85f33b3c69eb69274de5bb0d97c6973ffa51c2a157271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac37695878cece25ce28edb58dce9376f6ba1cd100fa1f958bbc0f3e9d16486948c83c8ad4a13c03dd533b2671ada84000000000000000000000000000000000b9ae369196cf33149389013ded774f22b779b834771a77d02ba5586d6510f0c160d2885637cf91900164fd9b215b0f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a2c23c761c3e0097dfb2edd635031d99bfa9d8e44755892cadbad078e2081056695c00934a38910de92f32af53e3d0000000000000000000000000000000000f32fd7a71143553af09d0a45634b449a5f100e492d710a385b3c4c4ec589784bf6b0e80d8c36ae26bc4bd19c12be4d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c2aca4e569bfe9c54dee9413a42f96a69d3297011e0634ada6da227844263a74eef8cbcc9100ff7c0dce57f3d906140000000000000000000000000000000006556e5837abfdabaaef168ec47da7fd644ab9701074f6e4d429986fca50eb9188feb6b9aca5837ef78fa396fdea79651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f10d835345a0724804324f9df74d6c0a1744965866a464a9f21c334a7ca76150423a5993c77c890357ee038db7e9360000000000000000000000000000000008aea7e714c796dacc479d89a5e3f62d0797ae39132bffb4fb8a1188dda2be4b4d59dd992453f709367046c5f95544621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa8473f7f71ff2157bfe94e6792ecbdc940b63820704c0e0c627fa159693f9668af4d247f4d3af9521407c1bbf3dbd700000000000000000000000000000000098f74730f1624d709fe7eaa0fe019c0deb4858bf1674095c4437ff67549db429d6d82e6adcdcbc9f2f2c7f29ccd45e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e302678aa16a3c88bc89d5a812abd0b5f22e33f8a65ce56ed9a08c8c9f3b963a6d87f343bb435af7b8ee44b0c2439000000000000000000000000000000000078bab275c87423fc7f9d0327d543f66d15c1c9847ea4cc60a0f5cc4f1fc4555e86638f8563addcca236ddd2f998a9f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8d4a91ba9603d51104a6a47ac02a2eb4ef6535a1b3395d6f4a11e2c62afda1be2342850f74b316be6c957fb2c6d9400000000000000000000000000000000010c5b48fcf1f6a832046b11befbb89fe9729391caf395ce7f38be6188f55259e0c414e2e4783290c2d2c8a534f9a68161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182af9fa2929fb2298438a3d9512493c7089f11677a68260947bc9a624fa2b8ea1e4a9e08c288ff4b2f383f8a122dff90000000000000000000000000000000016d28fba47fddc65af954c02dfc5d9cdddfb3f9b0d6652639fe86e919c3207dd06426042c92c6ff480e195e405d743391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c975adf0433578398db50f567a97e27b17e89837dfe3f30cb6e220b810be1ff1aff1d192724d5ccc378c41026b26f70000000000000000000000000000000009e6540cd564d6a0d46627ef833d46c4df2cb4691069257fb068bd793f361a7992ee39314a37c148c26f4454fc4e6d8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000360c05b68d18819d5556c49149558e7b02814506e386d943789677c243c7a635f8a36d3d6ec465e0dc6769356813b5f0000000000000000000000000000000017139f82f4c15f64e8f1be020ceeecb0dacf0579094483ce84333bfecd267a7219cfc9e03bd148ddecd9419ff90feaab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7d135883074547c37e5e92c929e510ffa66020c50ee332a77ecd27ad19cf379dd769a134ffa7e2f0886efd03a3630500000000000000000000000000000000198895a37464291134dd59ccadac7a8a550da6b4af64d991c465f007b2e287c9a7d84dc7b366a3b57414f5b74a9593e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086b9e3b72ed9ffdbda1c87c9d84349c6648a028ba4be9fbabf02e3ca28d6ecf64ed3a5d435cd0d640857d63f82f3ecc000000000000000000000000000000000fe64c18a9b7813a3b71690607deb267436114fdb23524c2c3e078efa5dd774af32d1dd4f86eaa1f8cea26f06b6b98f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081bceb5b09db69aa9a6c89394828e3ea221afbb39ddac67b01fed5ec408901039226320b24acc501eb9668dc6ad0886000000000000000000000000000000000f86b25a356066e8f461047104efa13325493945a287fb7c1cd916b968d4f60257a534398bfda135090ba0687b74be1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b60efd3515eb74330c47b364aba0de8df518563a6042779f4bab35b3e3cd6071c70ea95e14ff4343d52777b493f113000000000000000000000000000000000fe88fbbd16a0d650bcd2e449cb45302d4f4a65fc4e6beda5b7dfe9d5c82cc562cc00fd0c6613655da131217ceda27f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cac4f34fe4cbaa792793dc0ad73f5f320ac9572e80d25cea8fb37fed59ad191e53d151ab94697952154e44e82ec60f0000000000000000000000000000000001c2def9f22510b9de82ec0bbfefe31a3d539539116eb62f0ddfa14dc85d8391387159a53215f7df86292215c0ddc5cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e952333968cbde29ab5432bde7428d24827a51ed37649811a9a702f238b676d7565d4a73ae761768411023d8b43cfc00000000000000000000000000000000074c7fab6efffaa74d4a5ffb6b389ec3d41acf99cfb03f0f9f262884353c4c8184440c720551dcde08db4d024a6fd3e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181ebee92127b88fc3e45f1d4c113bd07a0c742dcb2ee7a5942c6e965bab8ec9e6fe0348bb8d96ae551c5cd2b6f00379000000000000000000000000000000000f6cc9b1665a1e7be035eb692f1d220d73b62655f3a2689a757890bc794db261d53c58e656c4213b369e10e03f56df171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016254205a057a86f4be8fbe0f13dcc0bf1826c5b587f143bd2ea7e7e1895dc99702a9029b5941ca7722e301f28b17b6c000000000000000000000000000000000ff97a0e49189b70f26b6a70ce316d450cca8d0f25da4c44d239d6d8605369ceacba152248855a76c1b6e104d44d27f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153205e65188decb59c780508f6d9659a4d341214138f414f367af6491baa85e5f8b0b863d211740a15a021149fa808700000000000000000000000000000000177bdd9a2b8fba59839a5e7f6d4c88ade9cb88f8aafd3c65bfff84f664a6fa2f69cb1acbe05abd2e4ae85e08160a79211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dae18aeeb8bd44ecf858046a9a737cb560db4a49dc72009192b348fa2c8e583138257cb294b28b47d3ee0c4e62d4f35000000000000000000000000000000000d4d7e883779ce0e3b2a33fb837cd908369fcf09de40f547792ab5555a413af9ac14ea2c23e22f3ebba4003bf356eec91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ebf7d3fee2894d17762ee6564e2105c0721c9543e3dc6103ebbf14b57b238e3211c7225b94a90cc4d72bbe8e1e0f580000000000000000000000000000000008ee85f223a1d131a4915e9bf09b400e5935c28bd08575612385e19c56064e1d8eeda5c62b4bf363240820d2cc1f49711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d35c4dec0125f2eab6caff93079a923fd2fc72e08088c258e02c429ede7653ea97cf8b8935ee254dc45cffcbd580b7000000000000000000000000000000000ec6c19d3d4801112c8b510bfd80c63c533e316f715b603692e7630a0bf6fa4ed246b6d81a259aed3f8bc79044d491391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147dfa0157cb13b4754101921c44ba948237b5113a4bf30587825598a00c10ab81c5106aea824211b55f494f95047d050000000000000000000000000000000018945753ba687426af1e26702e9c0cda4e96da4e269f745284d0ca188c60432fb7fb6740e1912053c04176b1006383b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6d36c5fde7b87c4e21bbd395b6a77604cf7b5dbdb73fa99d2cfaf9099f9464839c11ba868f061b66b26e6e467aee7d00000000000000000000000000000000029059e464905e61c93a59d6e0112500306b5533bc5a99509806bfda9b99bb5b2f800094778c74ea110d700e0d22da631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a7379d9cc9211a9e81c57b5e0122a4f2b18277711db3e9e0c59fa8afecffd81afc23d56b4719de86c77588b41226d5000000000000000000000000000000000e99c9c166a36a813fc488c00d57a3f576b39954d0074f240dc7a5cd1103ee6c6ec515e80a69d41b2c98f3f0e5276aa41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e44a2b8cfb96138345fc79ff62df105ad53e9d2ebe94dd091bfeb320902128d3453e80c8b26f48fea29c06630704967000000000000000000000000000000000ee4155f63cba0d57cbb9c64e2470ebcab1e38857490063c737c05ee30c5bbef299ffe120d3dbc9f9c95ce4d0d95e2851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e8ee6b6db540c3d7bd0a84f50b4588237e7fa27ec1989af674d6d7de150dbeb16d96a9ce2134d512bd47e0b8303c07000000000000000000000000000000000ae06b55cc2f14404c03cbbe344499ceb69d9e1bb7a9f0747c09223aeb2804a4ace3b3ecdfd48608aa90c11cdd31fb201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db546943c02edfbc05886f781a85220ea3faffe1f740892dab37ba51d711675a5b7d5a686c3b13decfc0f02898abdd1000000000000000000000000000000000b4823ff38f91a33a7f906ed6f433c1893544de606b95cf7b969c08ad7596fd9b8c4931ce1117258456a7eb715202a6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff950089c390ecaa4be7a475a1d8498bd52db0d9288025ced228be4a5c7d9b672c6200e24d7bc000061c1fca2fe8bf300000000000000000000000000000000039ec6c37294b5a6ef6e124adb86f9a1e44224b0a986ade2d6c66a1257d43a144cbf591fb9584b2e398cbaa5e485571a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001681c1a8efe90817e0352b115381258d5f860c7fe7cc2636b37c0254cbc18b1e06b3eebe0ec079aa1a9875a3a14fbb9f000000000000000000000000000000000744a25ee61d8917d232d0f5b680f94053ee94249e5aab6b895c7a63f14c0fe0bee7991832b790c42d4ca24ccb3063701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014673a362a7e58691db22038440b359c80e7a9c3089457f65e663a10ca248dda03df99a73da427f85c217f2b9e82b9d000000000000000000000000000000000090decce0b5d39cd91d6092f1d2684ed3a25d652898a58f462998dad13dc3509aeb4e6a93ad990d33a032e4a4b687e7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f37d09bdb7575434bb7d8b81d8f4c7224fc69d861000ad95b00c9c4d96a0c03d1622c958cadb6278acf7c62b1b578c000000000000000000000000000000000658ed63a89a80b4d12592de824b695cafe884ac81cb096d5651c770ff854be188e7c4b4b6279f132f67260765ab57c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003bd8020830748f5cbf7aa11d082f73b829e6a6a1e253d777957fcb7c69765581b5ee6feba52529c40a6d5fba578a5e8000000000000000000000000000000000d450a421b99895adb23e113b0dff1c79f4a9f477bb800d288a84f8a3d234e406f17669147aa83ddadfb80cff1be754b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001654baed6e488143ec4867960d4346d90c28062be20b4deab24abcad9d707819ded944921129e090604cb1b6a34a85870000000000000000000000000000000019a22e7273bf6b64f58678b429b8b1f104102e0e9ead9ce2660e6a7610626c6f16015242a2d29919d36f518a1b353adc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cdb2004cea1819d33d7c28c14a91e64cffc6a9c2836210483813c42b0621e3b7d56af8d72728e971153bfcdcfed2ff0000000000000000000000000000000001369d94d084f00b1d68a136428e11c659034e71216ad058ffb65759a9862ec21e0a763fedca6991c8d73e3266ca563931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6263bfc52a439bc68bdf6f38a105c455a0b5d0eb604b3116daf466a7bf9a61151f0499316dd792f56046629c5ae70900000000000000000000000000000000058406f8e3ddc48776e67a3666467a2b324c856d9b2ff04a3a179d07b0d2e935c5f4a4b976dc5559e7aa1450538f548f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007de81224cd5f7789f5622b06c9cce12e7c242443468168f11ce98632ecc68644be3654413c54a6b07b405f6dcfabbb400000000000000000000000000000000184438db25d7bd4ba14f7577837f532c70a50c5b45e60adf175b40df28bd77ddc06062e9469f84e092ba1c1e4b42bf9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f84ef89ce7c6edb4b44f78fced7e2aee2d1121305aac0a2df912686dd263c3d6a59eda567d304967cd9bff970a18f6a0000000000000000000000000000000018b44e5c2e7eca64d221d8b8853a20f60cb029203d547fa56541d9e212361f82a6dada13163155eb524670265ff6dcd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006998500ac726d1fc5c31832a10266e232873543a7cf23e9b6a85ee41ef436b3c25feeb93e2e57dccaffcbd2c52c98fa0000000000000000000000000000000014edc9e79d6e17f0a196feb215e6b317d9ff074fa1f8a3be2d33364f4a44a752e5e2c344e6d8d239581dad316474a9ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b19e7db6ec5c82ae285f779629fa71aeca960b9d77d3ddcc0a7253e3661b20827a778acb2c8d2807ef87a9106c145100000000000000000000000000000000137ea0da2e655a86ebb40f78ed84cb51436158fcfb901edea8d3b88226bda84aa3cd7510ebbcc7fb871e9422a66a912a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003421b8c520449e2375f8163e0abadad80a6f6824d9a343f47503379a79a907b1c0a0051deae0b6d7546beebf4e118b8000000000000000000000000000000001722743e81ff6fd370d3d16240bb3492b4f6d9bd05500be9c0111309e7cfcebf550953dd3e8b69f68f9b4ea007e810cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c01aed49707be07b752b7eecc651d765f6c3dde5bf7d2d15d038aa5c4c86fd0e576f603e13050170bcfc7e9f9cd0074000000000000000000000000000000000c7eba29b7f8b7a2275f6a753060e345f7dc2bd8ee808a6f949b36ea3af38018bc5ef5ec17082a4f905612d87a8fc7191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000eb5caf92ec1e8ce05eaa246eb1b19f2c2973e85a2b65a1d866d9afe2fd532bb6aaa5c7225e3307a6d199048fbfd346000000000000000000000000000000000c089b9d16b9e1fdcc8cb8be316a85c7f81bbb31db542532ef0a60c7de9338f5800463de665d643b4265ff9cf9c37d041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018550a0ac6c00bc0908de8b8b46cd090a3dd75634660dec25642f7fe87abdf726310ad892c54468ef68a214eb1ddcf30000000000000000000000000000000000e70c9fd778849a57b1d77406bb6c02a20991e6d497f64869ca8822ce16a6db992ead7a7dc6249020657a2fb7b54cf791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001323fcaefe5e291403cc07a0407cfcd9b59e2d62e321e7359c778257de88f895143212248418269eab5a45a4235f2029000000000000000000000000000000001880f0ef888bfed9f284aedecdde018fc64f0fdad9bd75c9780c0ce3475faddacb623827e7f3f0ad2903a4fdeec0f2d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d56a5807b826f8b5da96c78fe403ca1582988fba6b6d68643a77ff796d1771c2398a7ecdd38db8e77eae1730dfd248000000000000000000000000000000000111d78e1f8d2a2f2ba0f1a4272097d98f9a65be03b0f4c74f48d7fb581ab5bbc233db95ebd5475c11fb47094da3b811c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f845c4863bc39c257f89e133e200a5a6f9bec0f1277aafedd9da8e42749a922abe7ede0b95f6fea78e867e1c3d65a560000000000000000000000000000000004f9c3dd53b5cbd97a1fa5cf4e0fb39d815bde164530b7ad394fb7a474f11e57df7f598c4aa2a2ffcc2ba9f582a1832f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195bcfa7f6e92a6db605bc807c16d37e108fb53c93841f01d90ed188ec74babd08e511a277aac4a9e4ca5c9329d225380000000000000000000000000000000004dfed8033fc3968dc99e476232f3cf015052a87e7fbcda6f77c66e627543da9e7af7ab32d8f10a442442da09255ecfe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9aaa41dd733fb0d2947c084eb636a8b12cc072a7b962f1f013072f713b936bfd9356b1fb02bb4e94e2efcf44491c950000000000000000000000000000000003c8b2cf351047a4511c1defda2fe5c66b3252ac440a188d5ca99616e589d21de9c56ffb6e2e691e5f3fae026c3d15ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018196f98b6f873906713e25f936aed219a7b040fe2b5765652cd1453ea1444ee116e8114a17045bda94b82ae1d14e8c50000000000000000000000000000000014c11a6dd7d70a53b7b8ef57b68afaa06c821ec1abaada6f3a8d7b9348fb38c97fd23de77c725704901aebae124633891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a3be8b461344101cec2ad95490c85409af78a9d56cdc0a76560278973040a2954d90bf47ba69a8e38ba4fd0e6691e7f0000000000000000000000000000000012cf0251e68d3308c471ccd3d8b6fc919dcc70ff525729754c40cb73fb8d84693e9b6a1847a690853183ce42301a12081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a757b0063fdf78ec95ffbf93b97c28111053657b3276ec886fc75342ae5a54cc30e947aacc3206fcc06bf31e61f93a000000000000000000000000000000000950309f83b564d54ae193df4ffc000a74cda3189a8329663925bb73cd1757096ab5e2557795ccc6ede40995d8b4a20b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa73119e29e042a756c2eaef97c65b2087eaae3af35e6f21316056b7b896576f62a96cb42ce7de22daf863e6397e74f00000000000000000000000000000000100fcf4558f9f21f0e27dc7fa266e276db08864aee4556b9fd71938010cb5dde58e8e17e30a58dc5b177ff57236dd05d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058cda6a99fe3a61fb7b3966f93c246ddb214c662d092ad624c69838c7b1e8957c82c2a94bb1035109eaa8b77aabf8aa000000000000000000000000000000000b626cd6fe7bc670df7c9941217cfd54cde93549b765cef6887d36407d12c2e75d3a23778e98b89ab0cde710589368a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ffd0b660874facb3349894390d02931f06654ce0132d951e888a3ccfcf48d9b50e670e2bf8aaa55eb471e4ad1ce80a0000000000000000000000000000000006fb52bab4a8df567f865785aa76a40c95d7a3bbceeb733c994d2d5c906d15e6563bb6eef412d2434019dc77f10d0e881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090d37f7f7cb9454e6c6c4e5b32b04f5bb7abe2c548c954e0a5d3d2474ec900c0c6634568c981e102a3910b4bcd7ae09000000000000000000000000000000000f4c244fe24406770e84efa931f19020cf41cb2dea4e289e705c15096b1c150b76b3adc7c35d5fb6261c739f66c412bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001efe87332f2e970a2e7dc406096899daf01ffcdd8ba5b5876254bdea4dde852f42f24d315e27c1a1f02c13349cbfd17000000000000000000000000000000000b233923c24921a4e182ef9d9bccc4781d863c9dfa45dc6ca6eca4474cb467b67e5ae593ab93a2829c3116d202a81a2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008aa3f76745a5a17681fc69dfed95f87a47795a37ac68e89a380317a2157d66c07d98f48363a135f7f2343ca13a8a0190000000000000000000000000000000002f7d4bbb0b25762fa1e670f206ed6b2d2fd0971760ac4913ded8a6b2e744811f9ea986fa54706764103ae69e0df2d171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e287477f127a13031865cc2cb5810df6bcf48fd6cd2e3c9f51c9e274ade5be4fbd02290d2fd64d80d64d6508e920180000000000000000000000000000000002c030c1bb7600a63cb879a999c86ee793052cabf2c34d0305d006eed0d88b8e807c4665ccfd162c502871f2e285ff2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117a4b8f5f51199cecd6cb7f26bbd94da77344164676c7720e56b7e8487adeb93e96bba98d919e68ad959dfc77a00626000000000000000000000000000000000f0a5903482513d6c42b55b9c70d7faafcecc95217bc62b1cc0117fc42916bbf314eefe22b3e69e4e305988e7b55731c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ada78096c2c59bc8dc24bdb7fec70c87ed8c274139f5e6dd141ee7d293204de560546ce5a4d817d175cbbe559e964ac0000000000000000000000000000000019d588facaa929d0ebb94bc08440e25670ca985eb148eadd143151407cf0703cb1abda2aa4c832598b8383b28cde1d251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000106bb1c9a751fe58361a83bf04898505bafb486c6f601e57bd3ff91d49061f91c5c7d6e5cc0b1d2c7603b91bbba8b306000000000000000000000000000000000d62258885339094c6ba81cc823df6f14b94cdbfd5c5334c7b5a01944dfd19ba97ee13dc41be72dacd9a4c4507f52b441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfff4c4927eb8bc279b63b98e63aa4ea94d11cdd485078beaf75246a5eac706c7823a794b1bb1a125ac197b96a1bfd8000000000000000000000000000000000d11904384f429f44ac54c3cc980fd0ea1a5eaf94d41a32b0838b8e748a9eec524b9d498748d51f4dc7f4d5f1b088bd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e3d31e0090f4f375f6057ea9260ac04b2cf6b5da10e0327793b621baa16b67cd67f5afbf7b3f38ba202294cbe1854a00000000000000000000000000000000000630c5e90f69cbcfaf17c151b71d44f7a430cd22586f6b7f436e878c2b5010d4029ffe4acb6820b6cf0107eda5b4651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138a20d57200124b381a9b7ea17d8e4fd82cfa596e3efde313313d28d68d37cb0736f4e9f1fbe1ab977d6caa6de7394100000000000000000000000000000000027b8244d19dca38b351c6d796c8d6189439ec8aac3aac523865bfc1bc7c0c201ff5b0a05d53c63f144802995c7f74ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006694a0c70f6d3e245d157cdd52c7d0e7cb6274db04b7f8ade197f68a13387b8ccb8290cea14047f523722e28fdbb08000000000000000000000000000000001726d95af877344456b2f2c053fd92251a96356012bc51a365bcef878301f56810abe425c82feef61060ed0dbf1c35311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066f6abc564621898361c5df6a4d2ecec002544372896237e967671981747e23d6b84d7da24f1cd71434843af6f19d7d000000000000000000000000000000000bd41dc2850bc17dedb123c14d4a505565a5202af653b5b30d7a8c0bb20917ba799e387abe1cc8bf55b3872994b57fdc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000feb28be418692ed131339c3392e29c2d1e30eb34c11202b57f598abace6bfe22554548616c93f0e3a576125b9bc4e4d0000000000000000000000000000000013ea5f992dac7b82a9df4173203e2201f1b8a05f851462befe321eb83a3aea62d53ca8089c0c3588c484c519429e58e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093475f526633791d50a3ad6bb6dfb31864a924ed126830eb394963500494dd63eec3c73e99cc61b4a8fa44d261df2b70000000000000000000000000000000008a3098aad0646aba714b7fcb8fd862a115fdfa8935220c0944ed999774b2c0628ad4f9a10e4f8e54f0f6ad677c571b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147e63b348cffc21ff8ccf80fa91b680dbef325ecf0c37f68a7d0292305c8ca7beecf20244847f7ed0b31cd01ddd7e4c0000000000000000000000000000000016ca25d30933b25e3a1b5bae19b3c99423d9d39f7620456bdca480a2cc03638fe276d43efb36cd739b2ed4404d3b70c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019686d10d81dd91d945d77118a738c7026cff7f7ec8f183867acadd235bfa822c11df722a91f6982a663412fef2a1078000000000000000000000000000000000205386d7c022df1ef1a8ecbaf778382cf9b89e2472d4833f2a82b4bd330421a5f183aec4eddf3a6cac10f7046b097d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000822bd0d953f849069f198c6f2c57d81f657cf2070eee6b03625730587d2f790df245161ee35c91e75b6dff3fa8db488000000000000000000000000000000000e174c58799ee4d62e60e0f59bd199927942548f06f5ca3505165561194ac48752c43154e3778bce7f5df50858908a761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6fa0780933322fedd45076a6b8ac764ce833686162d473fcd210d21693a762c7e07ae0a59b2a26deb56e98f7b938d3000000000000000000000000000000001585ad7dc6293bacee6ab52b71a7bcd9d4879096c03c446f7090b24755e67befc571fa275bc86ca130030774fa8eec461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a69f8534ac2c82c184894f659d223bce01c813cd9c6446da92f6a1681add3ef2eb41964d8c72baa0c6e57aeca19184b0000000000000000000000000000000018be90b9fb67dd1f3ef8da67535c8bdc226e58d5a1234ec46d229c5e291d8b0481dd6f8281021f2a4cd525505fba98f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a38216151b9037db9ce417bfb110a501f96579e3cf65b3ee00ac8274e032efb3380aca284b51822f3d0ee5323665910000000000000000000000000000000002429a98a8c541c213f7a0b9bcfcc0ae76ec243fce7243a0e3ab5a319458865de187752f06e2b32577cc9992357dc2d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f50898587dc3f9f6b633b65511e20abdff5152995554f9557694a29fa637752b996c6bbffeed64b63d1919df00644be0000000000000000000000000000000005368cd744cf84e869347c2796c1d0a08314c0fc0955d7514448c2ff967ca24a104de7296b351ec90f90b62d7fe1b41e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109c2c15358574cf99cd2a0b6e3df786feae5d2bea15459060dc052653fdc0f7db1e7f644b17cfe2cdc88a5319dca2c300000000000000000000000000000000199b1fa4a1a6db6232f860bd32089c6608e114f89f8752bde137363dcc90072d6e844e1579de413238a621cf46dc8e2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126359d7ad7373b5a2099c0b11e027267578a8c54aee6831999a2404afdf46f6d327e1cd2470f53a0cd12249e22e31ff00000000000000000000000000000000091f71b271f3e7f4f2e5398064273bd28b4c8c36d8d19749ffb0afc9a4a35abc9466713d7b8e9fb7869661745668b2921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d6baf01617a330b5c0e723cfe7d355f259d3558028cdeeeadcc07beab4a8f4b9adfdd9c31015c2daccb177428d84900000000000000000000000000000000007fe48f8d3330f228b742e146cd5e94fb2a4bbd881e33438b15d79f2cdf15705e92d210ae8122b18115038290fe179901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001005c8fc3c58369968d65a12f90203f91e304e0f09c51db2c82a06acd3fcce96b9813ca4d55ea3d14464c7b1f03b0c550000000000000000000000000000000010a6359aa1c2202582afe05b52df0a78f98586d6c7f5ab1bfecd0a0705f6dfb8011399a568ee0ca123ce9ecd5c2c0c281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2dba33bc1c4ab9fb8300a9a66c308e4f4e939171f998f5bbc9958b1d3a892e608003aa26ac84270778fe9bd1998c65000000000000000000000000000000000da5cc256f2ebf9973e932db0fd6d72ab119232cc63a7e80d8f44e6d3212f0c955a01b4d89d23ef4fdcbce4e4bc323661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ad45352fdf06bd7dc1ce87309142200ae276a34ef084cbaec2bc8a168b4c3e3c01994b2d17c64e16834af2bce86dc40000000000000000000000000000000014fe3fdcf40ded42f2dbbac1172a4f2ef8db5338df69f4ae4fc9e3f6776c27d77264f275e97d46a89c6ec92b863504d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b238b26eca9b1b156356473581de6ccbe600f6ed9809669963efd9e5b683ed3669e6bcbceca3c74ba1c7f840d015e2d000000000000000000000000000000001128ae0585912592cf9b5144fdb08a0284274725e06ecb2c6d6db4919466715c823bc1fa1e77ac368d62d984ade366561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121e83dd10c9115eee656f89a7564f6d529eae87a64a898cf1e68e1e7e4629fa202bbe881b9493f1b306ae842b7c7eab0000000000000000000000000000000016a2feeb4276274f0f6f8d5352644004935c9030e6a0092483f28d23e9ca051290c5d11df3fcd25788b8cccd1905eb791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab46c7de183ee87d63d5de408e28dfa58466ffd9cdbef534db106b993224afaf7f27b4c948297ae65c6292ecd19c9cb000000000000000000000000000000000d5042690d0524de33d68d39c2602a0d35ec63fc4e4808708672111ce7035d8cec375b47c42bb477fd3dd52039248e411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d88024893aaa6bbcbd3cf1a4e0c55deeeeaeab60e31e151eb62eb8da022b96fac2a4bbfbcfd0b648b6067faa46b35a5000000000000000000000000000000000b427e8f7bc5dea9baa0a8f7b1cbb8fa9f642a2644b266a064c789b7acd486b3a0814294699c38644db097169819b74f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f42889caf073db3cf184c227ddae1cd0cace401edae3c1efb75b60ca8b3f1c46f0c235470b951bfebc18fd48b47c8ea00000000000000000000000000000000155e01e3e3258df3a20a431f36402731ad7291808a6507a6f37c1b7e0ec8095a5b5582911eea4ce270abd0aea5e3dad51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f07c07905a272fa66dc12497f3592bfc2fb7578cd27545ef2fcc73eb43807b8b019285f9be9b92cda37bb3805c37d07000000000000000000000000000000000407edfd4ae2bcc499bd43a04c4435222c9638979ac8eb9aefc87235a93219f753710011f95a01d4de0332042a5cc3b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb3795f68bc388665d4e9532e2e79860bbedabc7db77acf2dc8c73eed24fa630c0d21bd1a0a44bbd0146cfad6bf167e0000000000000000000000000000000010bdd266acf71c79f27320da220d5a97b238f0be7052afd32d9785785e8382bac411597732bb647658fcb344bf73c5a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086568078a77b456c68175fa5ce8e45d71af32f145696fcfaa48a48c64b46c667ec8080ab39cfa7a8c01de8ebf53210300000000000000000000000000000000122cda8d2dde160690622638b3d1b939cbec1e7dfe9fde774f8b3086e95e5444cf8e2356009363a3d20be756eccd6f791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f2e6fc0f5ea0f0a752e3791ad26dacecd293e6a2623402dd75b736e88dde4fb1b3d306e9224314750e8c402ddeccdb0000000000000000000000000000000007ffc8775122e562570d879a6f0184ec9b22e85a0eb7bd6ff17b853fdaf1d7d095e14aae86a1065ab3f228cf691b489a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007654aeb4e7ec52af3f171996a3d903857be38682e6a2284967ab0c4d4c4475392576f0be00bbf8fec1ad731f276fc71000000000000000000000000000000000ff8bbc7f8c348e3399dc83b8f721e78b2610798191ac602d83cb1bf67e3f251be9321941d8d03a9b99dc1197c81edac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003487d000616ee9475c8d368dcd1f39e449f87267772dc76dc1f2f2e966392ed0f663f9a6bbbf0763c6240fe9edc186a0000000000000000000000000000000006bad4fe4f85b85559d7e1906d081fca82f9e2aa1be0abdb9d926711f15c219d5f101e68d43a938d520f0ad9ff58f1101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e4075841bf11b459904b5c37b27e6f1d7b23931dad18a9c381c875a56ccc3422037ad44af8936fefaaf908771676c200000000000000000000000000000000031115fe1467eeb33a89d6b4db05f4893d98cc5fa72b48e0cfa0493b13fc0f3af393b5bf79adf88c827152c2257f0eaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d82a376057ce587a4bbee669589ad6b0bb685abbfc79c7f0bcd3abf64a9321b37db7aa4fac9c397008ccb20b934b3b400000000000000000000000000000000027a1d90ba72c6aa1f77bb666e73a953c6c461e0ce1777bbbff3463931404cf4f32cfe2344f17421213a66a4223870fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013237a815a5e3ec7f7bca6d4700a76b69b314356b6923dc4ef0c6046460239890bc87fe01509108c64ff52a17e67d52500000000000000000000000000000000081a70f4d256ac589d85a5884e346e45178e0782b0ccabba7626d775ea8e9def6b818502345f0453aa38f05173b1a7031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8d10eedf21dda2f003c9cf671b10c607e6c2ea4e5103d92ef0401d4a6783e89fb9b3e4f01c2f6cdb42dcf9140df6ac0000000000000000000000000000000003861554e6c33f66e7fe7cf5cf47a2da67b27f52ed3d9eed70c5c044022d1a826299eec62bc04a538ad10079de0c2ff41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000deb722b15709fc2b153b28f396bfbfb03fc64a6e0bd68472f6efaa27b0db7140b812085d385c0e5b60d64ed8143ac920000000000000000000000000000000019763e324e37dd02030460204157339b4c539e9884f23ec1a0d351d4a56b8cb85e05ba2dfe80caa7bc2cd075204bfffe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc233f2fd0bf4a89415dbf94f4c67b3e59997a4b59caa56ab6b769a6994eef21be40a54705a9c0c05ae4c805d2437b60000000000000000000000000000000001935ff5db947e299e140dc7be1ca334dbc69e2ad5f8387a5e151d6cda96d52b388c44a6e515d1b581ed5d2ee8d74cd91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e2f66835cabdb01ceee27528914d0f52820a1cd0a562d9fa953196cfb0c19f1864d7ab9b5cb128b6378caf6d0da5f9000000000000000000000000000000000597ed5c9ba5738781848b3ad3cd771a4c80a51f7f1ba9610f3c3814699f56db7e42b4c2c44181aed1af7db04f203d9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a15e6e1eda7dfe5b8cfe7409c5d5c1ec9d9d5af490ecc3fc5782ce61856a974c6b4771eb6a0af53a8cc3344050bd682000000000000000000000000000000000b7226444d71a04a35d3fa17db43207b8fe84230829802f45755f65a08a3f3102914c0bf92180b68c3835828f46cb4621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b22a41232cd2cc3ec669b39028c918aa6ae5c5eefa26db673f57b79dd1ad2ad49bc20f31c955f98e54b920bd00c9240000000000000000000000000000000001e700ff144fd4939b405fab8884ecdc70c936deeb112830af7f84ca02e1470d3608e1d173b1330b4360071a00107f5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a5bf3dd1ecdc1012f3c481dce96878c626c28df1fb55d400504e78d0c6e8b00281c9533527645d2cda17bdccc5ff7c0000000000000000000000000000000004c71650d0fcef16ae357880aaa4294ffb2cadba82e3ebf85d8805b78381e1c22e5721285c758e1af8073fe3fb6696691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7ce57889917275107b3280e368a4bffb3fbe0edf43896d4f06467668ee0bed164bf1c1ddb2460fe8c1856646a0444a00000000000000000000000000000000141ea944c806798ca3e0053f0dc803ae1f0be4b33de805df15f3f77701a427d6a0d6d715b883f4dd9058de46631844751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1189e9fc194b8706fa5fef300127173797c25e66adabc890c6a3b9cf69e17d116059fbd3651b65b42a781c60376dbe000000000000000000000000000000000b32e512e679859bdb77347e5c4cbac0a012b3588d1a5f23f3e93e382980fb0dcb3e87dcd8903dd4520c4248cde6deef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec2a6c8e7154d99083cd030d33ab62a49a2102728da81e9d3f7658580ca4a081f09e5458470a9b2e486baf3cbddc0670000000000000000000000000000000008ba2f0e681788a626582411810613007e5ffa8aabc59d2cf6490d5c0b20d83b30ef199b90413d7700aeb22506de30331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c34322f59e563a9930cf326432a05ec367e798b60ce0a2c30742c1ec7c6577ff34ef947be16cbce439dda9450bfb889000000000000000000000000000000000c24b3663dc3207de95a1eb68255db233ebae57fadd264f89849e402a7759091fcad7c412a8b7baae323ffa30a126ecf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe19ab1e5d4a56a50efd379e6584d0e8930cad4e3474e09c024a419f038eac2e7e0b5122c1fb656b2af4aa47506af890000000000000000000000000000000019de0fc118a1034c1594a93b4a94a16d83e85c5e86942acf5c510d691ba6f07943f8894caa5222c35a73d4fb2296049a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000256c2970f1d3281c924021e28c23b92d16c3edffb5e91c776ddbfbe2b70780ef599db181d779e16d449b536cf0ecacc0000000000000000000000000000000001277bf7af6c983d78f706f80df9d2bb3c98a669cdf4a98080bb82bf1557d636b7a8bf73d3770f9c77c656c75e4f4f241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001172da28a357d85aff8c4697a491a6ff89ad38ef354c8efedbcd540f2564422e63f552a4aeb9db7f181780912383851d000000000000000000000000000000000567fb0b6180b034f1a0e4f198f7d5b8bfdb97874fc1e2b90cf5af58fd8413ba629e0e0f18e5a4f1edce7dfa36bda4ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001099063041d603e5897c5f476e859ab16c2e6ffda6eeb94151b38a2318b3555bdf2e2a7394e7dccf9c4144bd07f3729e0000000000000000000000000000000010dfa4b89c516004d7d62790113ee600bfc928a35b01d8a1a574b4e9d6435ce4c9129dc8dc8cce90ad9715a0125ff23e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c1404fa874f10a413bca4ae3a7d733eaeeeb889269a288291b311477d340c6b4213acfaba5d564aed893f50d4f5553000000000000000000000000000000001182dc1752dd419cf886dafc064487827479c613f293e2d13b7713485a26040aacdbd4f6c10d52afb87c5b66fcb5603e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a78b7070d2d7fa909605acea77ef2b290333005affdc1e481c535f722fcfa46375184bf7666ae542829e2e8fcedeea0000000000000000000000000000000014e281ba8d5bc5c78a5b66beb6d434196e7d17a271725096634f509d9512ddc9d4cbf7f3fdc4036e22fe5cd252cd95d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001093e2461d8a5ad955114c2f697fadcdd8aff026992772fd3e99d58508ae8e47d19a634223119531f05649133953406d00000000000000000000000000000000053a42632c7cfb4c03fb8932e791ce20bccf1f7c3ced2315295df758c3cd2bc022a3ee747204aff9af4d8e4011aabfba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019974bf48595b51f32ffaf0dc2dd84787006dedbe1e2ad41d048fe2e8cb16a9d56236b330ecb9762f26d839e4a90d5ae000000000000000000000000000000000ce8570f60e75ca375ef870fe6f3578770b2d4e569370427ef92be0e91f0d0a5a392f1d3dc1d6ed6cffd72e82e7f90ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db0d517e5c950bedffe2d40a6308ebc100725cb42264831bef4b9dcd784bb5458a241efd19e7997bdaf4a0e414bad34000000000000000000000000000000000cc1b0f5a2985d3aae15715c4ccdc976f4616a75775b648ca66b736eb32c49b89c51510ec7e956223cb41ccf2c182da61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003cefd2fdd7c5e83eb0d88a306c99d25b158904af490f208fdcaffab3a791992c3d0b2351f138628b26ed8d7d56af3100000000000000000000000000000000003c132aa33a08bc45414439ada47c3583c15638f52dc7652fd9b8376556ddd24aebfe9135b84b6c14a63737d8f12b51a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff291d4949878be7f95de509546378dc070d30868e62a063aa949ceb075d662544c76c0feb895d6190e3c04f7a9ac7d0000000000000000000000000000000019e70d82ca0fc26a7e67371b04f00b9c2a86152a24b5ec2a7de2c20d08f264154ead7fd184fc3b9131a5412bb6f75ec91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019960bbb5468f21ac685f85b358a57bd2a69edbe3ca1737525e821f66ad199f202d4329d929c1e83fd0216d6c33f12b600000000000000000000000000000000098f5dca3489f126f3e0bcc2ddbdefa40217fb68672f35b1ebfe60687f43d1de5e23f61d31fa3fdeaa6384753111cc4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7766d0889887313d07230171e6e5022145f44f36fe33d0b8a3434846859ea7b20ebd97a5d6cd5b7238192bcc13c973000000000000000000000000000000001265c1dfd5579a1535418b54388a9069cd02dc17c76243a1feac210ea2088498e93d897472510120bdbcaace5cc1cc6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ed4a3b00f0a3c1dc4435ba743fb6a22f9feec147dab90132b007acc5eeadae614059e25815cdd3d85a79fbadfc136a00000000000000000000000000000000065a62f36f3c831c1eb7d49ccc73f75ebb07325f5429a1bc6e2d9f0cfa4c84b3c445d5a5beaa9e5cf99a0b47e7a4e9541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000634ead49eb6ebb2e8f5e7b0ec0e31b35636311008d7ef681e904e7254ae9bd77160e52f7403c51cf0d0dc3e6a05ddaf00000000000000000000000000000000164382c9ee86014182f05ecc51f8550ba9a54767449bd46e454d6fe958b30cd791d85033af3fc1bea8f679fcb268a9bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019e389bb7aaa7b247eab69d15c7fb45143680e7b8d50b99e653412e191c394ebe95e00ca44ba561e2b8fc8085fcf250000000000000000000000000000000000000c86704ed1787ecb09bde8fcf39bdf32b079159ad8d115b7bf2021bb221e9efef9ebd8e0f3e48343a1e483ca55d9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8efb5c4232c9cbf2e6097486af882265ec77f6ab99fdcc089eb47f1aae78df24194a134cb653a82f7cd539ea2c49f7000000000000000000000000000000000de73cf8fefa9693da1413bdcec80a67ab152a7d04551a874f7f09ab8fe811505a1d288d03383dc78830c6f8175e9b761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000997c6eacea3040961f397e9d7b926622ec6fd8aa2273a1b06601f200cfee161c67c8f1ec5548f5b6444abd92510a42d00000000000000000000000000000000184f187ed44ede857103850892a9fbfd159df4f244b028b8677d508c5b3a8715788d52e823b223b6e080f488dc2aa47d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f0e5ea83a26d3eca34593b23b98b7446ac3db8dbacf6f3105da5ead1346b77ae018337529f27bcee8bf1be0a39d4e20000000000000000000000000000000007adebf2875a9bb5e31c2ef7a5a5e8fd81537e9d973a3021e0c21a1222a21dee370f854e2b54178d63c5dd9af50185d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001518f5bed56ba6b4f14d82a03b862a96c2225f667c9bc6e1854fb641ba7b9d848254fede9550cca69c1a6ab248e5fcec000000000000000000000000000000000ba06f813d3351c927063b98be4880750363c0be3c6a0966992c92429754661a390f029681514f374f0ea92f63046ffc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ab613611e2aa6b0058d7defe6048c5b2256a1740375535a7f0c676fe22cbf423acfd41800761488c2ece257fe4b9ed000000000000000000000000000000000f13537e306672a1fc3bc747337dfd8f05c79fcdeae09055b01ffa24e01b41c5e5989f92eaf165ce6c23b44bf65cba541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041aba18b9097a7d418a7f94b395a9a639f4ac1520206acf40643be3c2ede5471080d7b0adbe66e72b76ab820e8133930000000000000000000000000000000015f88f9b0ffd52c5f16b73f41d2329197164188a953ce00325e9782ac61e6aaf3c518064cf72618fed264360a922c02c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015416730835d00f6a73c8b991837ffa64d7180ba9228761fc476792499815b02c314132e096425fb925557339187898000000000000000000000000000000000535a4b5ffbbf0ca186ebe63992a0b2133671b3da481d254c1ba7ad1652fb983fc9dec7a7d0089d224c10c765d58e3841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009634a8eb38c02db736aab937c76ee5c11121c62bf72b6c2866dfddeccdd4691e553602fb370e22d476434b52d0aa2b800000000000000000000000000000000136abc1167988604aafae182612eed96276b0a01fd89b193b39c1be4ba96db4dcec77be8cd08bd9247a4522ff025bf791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000066330f2a929479e8348bcf6d84ff66170a9d422d2fd383a19a5ed1dd68dc6666575692907e2f2f124453af168de60f0000000000000000000000000000000017c18768c5396de8d31d59fc110827f9da2b34218bf22e20274ebce2ab6e68226c860f05b70c57cbc32ecea1af4397fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa94e57139d0de69e4cf53abae4a95e063bf6b255fb5932a008b91fec9b22372b838ec19fd9001465e4af0943896dc300000000000000000000000000000000155f42b375b107b0fb63b4174a3c8793361c547728b8ffb72b6d5b88b0dee2598fbfcf4419b628dbfd620420794578cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008dabb8fd32b3883b92cdb90e9571b7884cbce9a58dcf5787908462f91a31fe3a6a15724312eda31aa681a7ee399e29a00000000000000000000000000000000151afd2fd79423db99c5593cc08848e6cb763bf242172d3db0efdb5166b0ffebfba675b54f9f68e8d22f27b9fadc79e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d63372e22a5cd64f4f062d06572ae39096a1a07174ac19f232bf697573cb584615e24dc1dc86218da2cbd8786de5f65000000000000000000000000000000000feee06c2a979dfb4ca65744d0560bbe44ebf8e3e69c2b4eafe6fc139d8e3bee0b8b2e63d07a8ac6386433fe84080ae61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030dff2f81392463171b028ca0d65be238270dc698f7506dfc03a5fb85083aa8ab4d36512c48a5206782bf61588958390000000000000000000000000000000014e9e8b11d2864d8cb52548664096f6c66860d703cce4fa33cd3dee9769438eafc076effd3dd4ebb15179dd15bc490b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012bb59ec2c9d94d4c4ecc13a0e696dcd3f3adf5f5532a9301845bd312d69f8f39d571e919b287ae2bc36dff77da7ff1000000000000000000000000000000000060440f8df400cf3167622473828693a195a738f1a44c7109b0452b4d9a67948e4ae20d29c5302b40fdebb36815810081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3fd2164530eab3e5f472b7735a2c7e01c0a420ff2840a8d804dacd72fdba1669032fe81f99c0332fbaf75bdf9c1ee7000000000000000000000000000000000c82eb91810bd698f12ac69967dd7b87b4d5ff608a31de60be216dfc6f1aacec953e31e181410328f8782b4999ac8d571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177379f0dc18965beda800ca6e301c63da209d916b1c889b883a1b29cef25fb4d6c6438b5ff4b4ced401736c273d2ce80000000000000000000000000000000000cec7a90c631febef2ce24e31230ce992a681eb23496fd93a50b8861064a4b24608e457096d6269cca80efc03c887f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed4aceea3b2ee55ff68e4fe9746f149ba2c5981326dad5c13185f957f06678c8a261df1f8c63fd6b20681df948d950c000000000000000000000000000000000fac99d827225790ff8e07663eda1338d7a803cd66b59fe277c7141bbb08c05260661d65a5264ae663292a8b099ae2db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a75a45c913711db9ba536c9cf8658fa595f1bda7f6a5554b7dcde3a0d4d25510c9e9de43ae7e8946cafcda848f06a5a000000000000000000000000000000000c8528f8521d85b5e436bd468737728ffb1e899bf6c23c55621c4e9dff3ee61d96647ea78037648e9a22acfcc1020c351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f318e7dbbb9cd760e5fc35b2478672b8d2fad15cc9adf693df34badb2946ffb6d3e86caf6417d3f7ba25fc42c5722d00000000000000000000000000000000100d3fa8bae4dfb2d034e2a3b0969341a1faf489242d6f2c76e8168e0b29a6947d54c380d6daa9977a9292f11ced44851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d08a3968fcbe9ead2525d33f241d3dc18b96938635c865a7eb131c7a02d8f1b91afc1bac4cd56fc7e684556863729100000000000000000000000000000000186f2b3ef13d6155604f0b3688d45433a015b74f2fb433b67890c3db18d4f0e45779a8c90eaa7a80a47e91e30b24d0f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0c3f818495ea31b0a3d1a96a40b719918135635af754a60bbed0b46c530daa3b93aaba4943c7819b8053068c35ba0a000000000000000000000000000000000106223b96c9dd22adca5e4afa82b7a6cb2ce9a6e330457d906ecd9bb0ee797bf7e48b08ad3e6e932a69b99b114499d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a561fe4d2dcfc355bfd5ad27139e0ce9dc674acd93d45f95b327fd6bb69ce6c639532be11f194937bbf7f7e6994e20000000000000000000000000000000001912584c9547827f30872cfed22f71fbad7cf7143f688760e5f1cd31d592911049c5e5837993eb8796519402f02b14631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049c1bf2f8e56b9183f6197192fe1eb7ef959d1c5e36b8fd15fe2781ffd55a2d349e61d4b88ffcdfd4798d3bf484b244000000000000000000000000000000000b541f34ad6903c3ca39841bbbc6c8281bc7ebb4fc9a8705e5611f99d9cd26aef92a5ce7c813fd808871ece11307dbe71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007027179eb19707db1c1aaf7e0c9133e001ca4e56fa99037f2921b8e9c693ce8c296d475ca72f41469e9eb19ad6ca8fd000000000000000000000000000000000556fe5659cb436b31d36f932561f1714e5adbf4bc024eda16797083b396060cd1f09019f2a7b7af275835d47f7706b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006efa9179042688509e9d23287860e72f30c1ce3ca48588704514dac04b10636c3134e94ee61f4beb743837bfd3a29bb0000000000000000000000000000000004f316185decfaf0b9124fc4c259f99da4db36ae4078b0ac9864c9a7dd35b5e89652cdc801337cf85eb469b6c12babc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e25b734ec2e99adde2d526f066f24fca155f8f7cdcd4a9a5db08ad829c88d80ab4e65419c0f293a7d58606798ff21700000000000000000000000000000000060f0173bff2ff4e6f2ccb5a310b6bbeb3f0c18c6b94c257c535ce630a8e710b701705f4164959c82c43adc4e1ecf09c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069a4117fc6b8168b2c12aca408e73d7fe0f7afcd14f7d523f22ef5856a32331231c149dd81ddd2ff3e1092c6da45e640000000000000000000000000000000017d6704a1b1fea5acc3737cbeeda45d90f4d6fb413b94c5377901ecaa357a56ce6bd97e1aed5afe26e48dca75fbded3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a940c99dc5e54ca122f58f34986625b9210f52979cab92bc82b635490353c0407a0ef5b7d7059859cf64ff8cfe55aaf000000000000000000000000000000001177c395dc36fd2560f9c436838df13e974fd4297abd5f9a4d5dd2af248a8a5ef25871e1025ee3b808c54e7e12e25fef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018149936252740d0d055405d64ca9bd4d9c870d9e3dfe685f9a130a6e146781771135b593c5f3464c115a108502e66620000000000000000000000000000000007218be7287e285039960f216befd156f97d3a1ec24641b3f34fc02cc95d79c9313ae518d40dcd6735a66d4c12ad79c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020ab889381564aa46716797f5969cdc1d30a26cb3d9eeb97b79f0e908ef993a239f64e24f46a1390286b598b4eb0b9b000000000000000000000000000000000b8d7e3b488fd9be95f29f6fb613c26f5ef03fd2d851c6cb5c6398f525bad462a965d6b1ba4802534b8f5eb8b449d85b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001525d3e059a650a0e9bc15ec3145812d7c016925d533a52dce34c002d22b7a0027e51087110f2070a9aab4798c5fc3650000000000000000000000000000000004e7d8dd2e2bd3bb69ba0143583a431cd735fdeb125cefa5920c596d9dcd4bf93945e3583b8cc7d6ab4f08518ea787cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000971952c8e833dc062bf77f984aacc2983bc4ebba185016bc1e3e8f3edfe513f697def1e4aefd9f222cb07a53a88a8d0000000000000000000000000000000016ee349783d8d2d7b54ba219e7ac022cad0bcdf6319e2f8350918a5737bb4e65f54e2bbc59925e744405d5dbcbc1f15f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e29a226240ab824efdb457530aa96ec26b695e039d1eafc1f095cac437037e6a4059312559fe7c92e73199fe37744c5000000000000000000000000000000000313b97bfdb19419cca53eda4cba2d69c584c26052964bce3c1dbe8147af2d85f291bb612c01bd53b782c2d2f962337c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189dc3add19429bc8ac496e689e3907b22e37eba37c269364c7b8108b5f808fad08c5342bf1e6f03fe9d5e56372303a00000000000000000000000000000000016842f33d676a90cd97158b164d20bff847bf30e32fc81173fbcfb26b2225bae27d4cdeada9cb6b4bd4226a151078b4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f5d4689535e796487eb644424174656e83447094596212c65e043885f04cf3922122b74abe191dfb1a4ce973250760000000000000000000000000000000000e88f8655a2e80b6edbc334de91a445295e86bcf54e0538969b63ec16b6a679b16b95b36618e7efc00bc96447801c17a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e8243821d60f65c9f2450cc6b2092f0b55b772feb6a8e2b85e91c831e5d0f86fd211276208cdd0da61709e3cf323ba0000000000000000000000000000000003b58b493a8a23a55057218d0f061a3a2315e4343dc2bb6d6e8c4ae524a2e98e5fdfcb7d073f9d3cbb6fc85a28a5c6801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc4c1bf00fc3a7cc9f4bb5b3666b83e52af8435898294b95e41d9a4ac2a1772dbe9e84fffc1b3d728366227aeb30a6400000000000000000000000000000000107c70581ba81fac1fedbb6cc9d5cea8589b0a0cfff3935a03a9b184cbe5710038f2a57b9f008ee2326613674b2730841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5af4f9275cf99153e66def661b20a6d672cc84b9d2a96b067dff0958d55c3aebd0f2644a60473bc546a0991bd06b080000000000000000000000000000000004c5cc7cacdc2ac28be8941adbf10cd3b74b56c6e888a662e71349560010568b867909742cfb85a3c13b1d9ce01fe0071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dc6925e522b2ef65c416e4b1d4449673c7993dc973bae4952741105f308633fa5b18debdb815bef33cfe1113e5c6ca00000000000000000000000000000000038fd4ab5281a35e3d79c3107818c49dea6fbef4dca22ae438766e1443bb203046cfbdeacdc3474fee6e7d03394a72ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c0c715f844ae036d4cfe846c34d73a4898f0b3d2fe69717b4b758a6dad9f79339ba81a75f4710357ff415577ff0d4e00000000000000000000000000000000116047d57b155338326509f9be0997ccc48c99d998d001a48e262da616555c4afa08cbeeb10f746526910ddb57d13b971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001429935c5293fa437649ebffd00887bab438fe3973c95be362bf8a1f0cda12b780f896363c9d4fbcbdf7d4eb312ca779000000000000000000000000000000000f612adb430c2ae67de06a0f4e821d5249e526ff41ce6f7c858f8dd27b13eeab906da8d98d0285dbf919882c905d258e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f191d3f9d0d62bf213aa857b0965f9967d88c4b2f48c29de55046fb9cbdceb61c6dd6a2d57bc864bb309587b9cfa4680000000000000000000000000000000010879d82acb829655193394521fc47c1137d7e70af414318f056593e820e009fcdcb9c38d75f3ddaa8cb8ada5108ebd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ecc78a4fc8b222edea873e10b13d7c26aff6d4d86b77f179b8b435db73e17c04afe0ab7dd74e11d77f02a8ffde0c49c000000000000000000000000000000000becab1ad811a19f8f88a1afb8a7ee7823b668d5ff7684d9a07208079b2adabaf29a229cbecbe9d0b2ffa3e34535fb811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003237663189a911367bcf8e4a362f06489a1f9ba513b27a88813263d07be4188bbe07bb12a04c6b6b86e5d8a80debf380000000000000000000000000000000017512fc5588b0b16703a13b5f238554245e08974ac65e0b46eae57c97b10a33b8bc01f104a35991ee46c5f3654efad361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3a8b25f4d88936f7acf6043abab1759e959f55311557c7a836c55720c98960389b61ba150d13cfdc30ba35a4f99c0f0000000000000000000000000000000017378fe4ba3bf430802dc9c2e623c959ffbfe172d72d16f27f68d35b7208862d1a3d8ba191c99e9a82bdb2f30535e64d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001570f57cc254e36e731bbc311b2cdef5e97da51de84b1c7ef4164ed3f17135150a1071913a76708c0a791436853fb12200000000000000000000000000000000170967ca2fd04661709942fc2c5da6bc45e15d2f989d45ed952b80c2a38e5cbf339f376c955f996ac77e9ae38150627a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d64140311922b1c7d05e3f9ac1a68370741ac824daab2aecac3114ba3d7768f6e904606575d6cb406895c5bf910675a0000000000000000000000000000000003d8231c081a57e41cc491db7eeafe9e11e7e1e2adb022f9d9b76de45cd8820e25c91c6d302144506c2c65632aae2f791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8145957c7bd5a110bf0667091e3d16895204dc123f70d801472a47c3d9ac2d9b11f93fd44a0a74555b3f5704be7b060000000000000000000000000000000016ae910428b0aabc6a499d945569c91e1029a4309a85635bf22144c415161d976706bd3e673f44e74a5fdb0ecc428d701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f103336b40a5e4bfe7a86a03832b414f8957935aa4316b0161572166fce5602ebe8a0d5284dc6c818fe3dc0f3833b310000000000000000000000000000000012f8f7920ea770844cb6cf798c6f9d1a3abb921b3478d4f1802df36a3c101df1e28d2af09a1091d9d49f6c6a0ba85da11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c8c8be082d2f02513e7c2fc6ac032d058ac42bb2b614daff4583a4a16b4fe7661bba02a8464dbb9d9191b42cd6ebf4000000000000000000000000000000000070dcd6d034d13cb546cbfeb6f323b60ed11dd115ad9d3061c47e33da9c9d4ddc042026175bdb34720a5a92f59554f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a6139d00a7990ca91d42d933e0d39312ad7fdeb0c0496e9ea3edeae7d4854e531b28e0c912003c1177d0792c5cd8de0000000000000000000000000000000006a6a795f27bd4a36e9aea91ce07a1173edcbce6dab347a574d4fc96661aedf57cbfcc161847be6b6d94074dd53fc5ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010180f42d688c0c489efda991939402af807458b88b354bd416dae7356ae3ad06cd537139ec423c6bcbadb475ddc69c1000000000000000000000000000000001519f82f9cf0d1e4ec8e94347b6e577007893a18603474a269cf1e84769fa624f1d989411d2c51849b0c27e583f967051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001780930da219a98e2ec2c5725d25d6fb7b48241cddd375f4edf99bc930fea4b31bee4f0c8902f7ee30c69238cca0eec30000000000000000000000000000000018ee1e93d7e926ce942a074958a2fbf037cfd77ace27c28bf32b7775854c99d6f4a8de698e9384653f2dede6b0ed1c9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4dce78121515816f56beee2fb3595f855335183641a1a83188360edb3cdd6cab6f70c2f7b4f2887d489e733c9afa1a0000000000000000000000000000000015bfe06b7874ac5ed0c1a624ed5b90fd1be6dbdc56f7ce09e6613cd8636e8e11449283831e1e76a40027baaba2c5a45b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005775ee6ffe0e01e022c29c495dd242c24f4f4913d0127515e00b867241e179be8f2d0819761a8400e511425c45aa6b0000000000000000000000000000000006473c74d045c7117f06561bd1140679b32d72fcdb1de45b89a4fb363e3d1c4e5e857572e45cc603b5a9576847896bd41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d830d7cae29ca19634ad3985bcf7db786056c5aa538faa430d7102fe02982833a72ca079c237f7884fffe99ff903e70000000000000000000000000000000014b93dca69343921b7d9029d728eaf61862f1e9920eb7e29c48a7344a10548ddb0f98e5bd70628e062e5d54045d647021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba27fc8c0187a6493ed63f3e8c2ede5162f081c3dc048b03f918f1649ac03c33c25c9df6fb2135bbd863bcf8747d698000000000000000000000000000000000aaa7017d58aa7195b882a55bfdc605acf9bda927c02274566e9ef13b462223f9aa3e9d46a8e3a431c96b9ee7546d78a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd824860d22e2b3b504a3fb82bbe47d8e097465c0c729b1334153f046cf2c6229656dbc18439e3112b34047343d9cc1000000000000000000000000000000000faa6e919fa2e1da3b07827ba50b0539f2033b3063446a45e6d9cdeaea79bb9e1b8fd76f8801ed2b7579822efca7f1151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ffb9a1e0d2a5498aef2e2a5e5fbdc96f9ae5fddad805cbefc680b9c54e716990d2e22ed279073ea8d4dcbc9d100e5a0000000000000000000000000000000000429a53efa704d50cef9369168119d5e45b5bfd332c695b1a6b266b3cbc8ef32b09201b5591349ab738a0a2fea0049c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001203c563003c6c2b9991a0151543af6a2959246d3b4e7f5a022893da096635c9dc5c06c42354941784b4756f511caa080000000000000000000000000000000002627a8a781c5b9b94805fe697583ac5e2c8144159636444fbab072e838092fca0fb629007a835abba5a9ac3fc69e7081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197c0077825f2f746fa96dcab0fc15edbc5cc54a9cc35c13d2c7537cf8ac036c8d271dbc02886e440fab5db2442d0b3300000000000000000000000000000000004bdfb575d8fa2df5732248968f6b931dec26d44a253bb49bbaa4dc597aefb4b80589c2f533ea7926d9d107ebf0d53d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000046f44a0d34b12b1d34bad1e529b353bfa77b2efbe07408676b478046f1ea5e17543dbd85aacf6ffba5b0086c3425afe000000000000000000000000000000000e69a770acef6f33f7eb8eecadf6dc36e138f9748f9e605e4114c7d38ff99c382bd88bb46daaceeb5783affa6d7b9d101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176279f374709d54c734e3f9a959c44f05d1e5f4edba9f71978f9c83e2f4e16df1f25f0e2e57479656dc680148e2edde000000000000000000000000000000000283c900f4e975952f17e991a1ca5c52808477e3d977a3bf13e36069f9aba8201f5162869089e4a2ce7c08c4f410d3491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e691d39f7243df71f8c1026c5ebdf10de560dc97cf6c18d98be14aacebde4b5300c0413d341a35c4b70f80f1b2a80a00000000000000000000000000000000013559ed6d49e132c6a187b2d1529ee933943150ca06e831986ef42ed9adc1a6dc2f144142ec2bc2808587198a0e31521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bce95aef2a54ecda3198ff02574087c9bf92c10c8906de477213f3a78540ccb71e1ab7b4bf1299f9da12228a635d5890000000000000000000000000000000014f204cb272acb217192f6ad6dda7c9a67298ce3bda3fb6b1ab6b67ce85409e8ce85fc16db4412640f5f04b8fbd304ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2c68cde8682dfb11edd9fdd808e0e0ec244a38d8405f321787a394183fdc8167a38b98efa09714ff4180d0d68322f60000000000000000000000000000000011611269d6415e6e6f12fc2836039270298a85dd71c8cfac124f5063afb6244e5f8a8c787de6e31b02a9aec12855e2b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001209d1c4ed9d48a3ba2802bac42385e0c2e0995a6e6b79e884a3dee5928e1bec92fe7609b85661935e90b6e040a6fdb900000000000000000000000000000000082d7e49eec113e8ee9ad0481124ed851f6716fc76a328772e1d574d1fd8259b4d55c7f16f117608507611b95310d0331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008bce6a14f3f9aa1617e070c59a2ea042566e7de7b7b54a6c7483760f2d1e65ed32185cb3a773731658a6ea213a8a2af000000000000000000000000000000000a9b55ec566f54c48bba45c542d26fe96a27cef40160e8ae30ed78e1b9ef981353b641a2236d90108b5f040fcf3c1dab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088271a97d9862bd8cefc2f46460db3eb9efe5390c85be6fa134a0b776186c314566118a50060cb0e97c5954c0ada84c000000000000000000000000000000000baa89a5b1adf8c9252c6402886475930cc512e90255484dbbc0b6b496b94ffa4d9a56e2410a52420a0fe5d4dbdeca171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fec849aa99f886b10160940bb32d9742ff883d779650eebed55eabc65502d2d131fa67924797a7a69eae77a0b70ffb000000000000000000000000000000001286bcb2a8d390d11b9adf4e0246312959ac0b2d4f6bcaea8813520d98520bf64754d9b951e396c396d26180b26eadf01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081d1e61f7b729454c857fab50c88e4c3138744122c7a1c859e4ba53e08c0e169727743774ee5c304de27bdda7298611000000000000000000000000000000000640e0953ff8f5b4d18e48378b38eb7676c1ef76e4e59368e3236786ce8b41412b012045de3d62e432164bf46430a5581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000328ded122b64e9e361013c0195371cc6828c02c0004a64ac59be363120d066d8043df7e01ba2cab2e5d39c48cd84194000000000000000000000000000000000bf7ac9d8653a29abc833925385799b2730a0d60ef3105e24362441eba84bb989e8c34c6ae07abca17707993faf235e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c72178cadea50c8187cfb2dfc5101b9de0681893e600894b2606f89df36b2f07058bebc3eae92720ea357d26fcc088800000000000000000000000000000000164392bfc933b930860b9387d30f9e0c7a766d5bc344f78022820d7fe787fee302ae86abad7788be77344d522b26afbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074e2b16dddcbb96405e2902948a9c1a43043f9691e85b9bed9aad21d34a4dba0cf9c55d39b7296e724f16cd2c5cb3c000000000000000000000000000000000142bf02e017597bd511e06b487d06cf0520bd876f4fbfb7039d7fb48158e207ded3c2165b6bed6e026ee391f65eb0ef81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000548de52ecca447c99f5141191b1b197be036ba301521b8b290a4f59b3b69a210bee8cbb507ef2a6f6870206f8f1c22900000000000000000000000000000000163dc7a8aa6da9f591e3dc6b948959465daf5bebdd43e5d4077941f4e6131dd99c6d42b8b3f87d09baf0d1cc9b1a4ec01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000291b8ca871827f12a5d72b48b1fd1b968bc47778a5fe6cb03b9a7b6815dd0dba61ac23818d5ae7a5d49af5f6d759b8f000000000000000000000000000000000d2480252da7ca4bc7c012de367191a98fb11e5cab773bcfa8557f4860bf9f1b64bb8c9e929d99662f6784873a48adce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fdb2a9ee343a9cb7a182d8d3b7052f8ef5e6de5ecc7466088acb414b9f802dfa3f05b81c2483ab05d67a1dfa8c0a990000000000000000000000000000000019e20d34df29e82a9d975b22261c760f4e0672c8743e87d28d5520690e157d3cf59fd0e8a240c57757f8e1c9566502ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005751cf80da8e8cca7df46a8428f9097bfab5e5f0e0f595639ed8bcbf30f2b4abfbb80c0176906de72d8951c4e5d9cd90000000000000000000000000000000008420eb88b545e81c6e5a185dcb85b31d2033e88448e43f73b3bc684cf5b6d6373d5b43d4c12aa6851a4ff2126c9fe851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad421edbe9880d5e68cec5149f6fb5003d7d8459977f5693e0c67c48e581a1adc132f51fb8a154120389e3a9f7fed4e000000000000000000000000000000000c1053d04108227803efcda6628f9e0caa12f5c47399f4e234694221d42194f7a2371167983bfedabd5291a915f53cb81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123d6d50ac169978b431a9340ef4f2ff444c523eeff810b591a112f00742caf342c4d0e768b9bee37bf4f478360699700000000000000000000000000000000003ac5c383a20d4230268dc6798377d650c1d104b0d2031807aac7b3796ceb188f824a2b09477b64f3df9d6ac2359711b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005599de85996a8a483097821ad74664104f9f7644b9e6a04a7ea38e2f77bb084d21ca42f5ac8a924e12490bdf5ac166a000000000000000000000000000000000982550b4beb9c7bd1eb29c5937164d48657f9aab8586d12fedeb93f8aaa3dbda3ebc5385059d945d7ad13653687c0c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009587eec77f1181f7254c285a1054173f96bf31fccda6b346c5b62d28b1cbf3dc94a2fb0b5744134902265765758ee9f000000000000000000000000000000000f4f0b05595948af5d149e626142b870f629acee64cccb49d48178b005dd0b34cf78a1ba17fbe8df7d90682cc9b141c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c4d598bd2adddbb39e56c67d3d2240ef186e85b1da7788da5108ccdbe88c986578be858f37a8c2673de3e07c6f555300000000000000000000000000000000131fa148a96d927f804cf17b1650d8903d86a2f7cb358932e4e6c54c495aea83af42326df88d9a9f12437708bc3faf7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa3ffceb84e17696533b4f840d391520e58437becbced77ed6b4e77c7d889853e002b1aa1990df303f99e19aa7c2f1a000000000000000000000000000000000499d6cd4d219d9bf3c4ea0221367a6e35461a98d1654c6fbcde89a87255b023aedc8d4c33b5c19628d10ed5e7e534801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018589ca729ab6e409a481ba2caeca0f03ad813c60d10f4c4c54b171878572d4ee27058e3573f1858c098e6dfe49a56680000000000000000000000000000000019a01342142c17bfd9e93c79aa2ed19ae2c93138aa7cf2dde2477a69b0414561787d6eab81af52dfa503a17a91b5e3c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000faf3972d161782b825240a4a3f3da53791cf6a91d271573898200440e3cb2afe17aa97f63dbb94d63501dd618638e8b0000000000000000000000000000000014f574f394d5a3796d7e8b5e9604d6ef7312570a4fd06f6a732509ab45f733f61b127a6a6388442a5f4971e7407325951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d939610a281fd0860ce69854ffd33ebb0996ce1965a17e092931afd10392ab29eebb8dba7a035542f8a8560b47186100000000000000000000000000000000005af71d93dfeafa875e8017983300aff491dcf0d6aaf5f73ea0ae32749661e0afa5aa2860daa1681d2beed8e8ecdec221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c2a8b293b6337edaefbc7be9cd4f259ff6cfe50fd5fda89d20a8c4557447b8d77a5fb21d2cd52d96b2ce3691d96a5f0000000000000000000000000000000013ade3fa55465eb5541e50b0bc4e1c892c3ac581e6ebe9ae56b021ced02b22183dc8716bb75a8d1855cc07bf2dff25bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001cba6107005b6099711bc9bed98497f5c182a91002a687df39717b3e3c23e69cc355d9e60f518970cde7b3a1a4e71ba0000000000000000000000000000000011cce2ef545f432e4f6f5d17140dfe06dce150bbe201d72a99057c9e40ee927005394060f2820229ce7b33462e7c10331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139205c3454955864c3a3a363ee0a9091eec9db14f0380da3ab1f25f3fb631a2c7ce870300a021ff2612730382fdcf800000000000000000000000000000000014933b7753b6164103f6b9569b48a5730c885ca1336683e26e891aa351fd4f970f874573fcfdf1bd4ff329dce58f25801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e2d3f93faf40b1358297b2122f8361e935b16184fd8e7aaa9bfb4e8a6818bc5ba4c849f95a43cf5665d6f850a19a1f000000000000000000000000000000000033407979c761acbf3a62288984a201d7d72d8c18509e5bc0d2881fcd49a9866ec473f48ff62e66fcff3df1376fb7711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af88d3a1d0eeec8ddd8c7462efbc3b5945c9d7c0b1123e93157075d08b3a4670893b0770fa3a2fcae6848dac75306dd0000000000000000000000000000000007948fa4475392917f5ea70e5452d04ac9893ede9e6b3001a6e05e0e621b674b4f7b146f10f6b63981f9549773bb45911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137e0efa3254eb3a3000199f398812303a06eea470a04e356801c5d65e32f5bbd377f1a21c63236b06bd12f4cce5a77f0000000000000000000000000000000013c9a58a37007499dee3cd29704ed70105be2485f7808163c24b2b0441da9057b70232275e239c4b93ccfc4b735673c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073afed6fba90e89b8fe7b76e88b7bf32aba394e8afc2ac2c26a60f8b6b3c983e139a09411db918c6dcc67ab41535aab00000000000000000000000000000000032ee4015c21aefdb4bd54bb9329d2b439d508b5ed81327ff50e078457d1b3acfd432c7afc1ac9bc1d06a803cae561c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109ca86402d3d96bf010b8c20702e0dbc2cea2e390ebab92e1577b8f9f2bcfc7dc488bdf949e9d19f18a6b9608a8fc27000000000000000000000000000000000a6e260aa93469aee078b525d7c2cd7675f1df85d73bd3237a3f8621618b0960ec67c48e4c6b747fa83bf820a4b066a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b9b59de96a11aa3aafdfb514afd1581f084deef380f583adca8d72147de1fbd528cd7b7d8a92a5ea3e84e4fc19a07d00000000000000000000000000000000083bda6ff113393623c7920459c44c3969c093bc95cfac9d0771ce20d24b7593549b8434bc7d52b554d60c2c1780d6f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004b99bfb772f179b630b7d58a7d41cbb50affe56c8d01006b69c9d9d82e44e9017185cc013244cb4c6f666d220e5b0a000000000000000000000000000000000eb0b3272f4d1ef13118c58ad148dd0db76d763bdb297654dc490fb19ed863db791511afa15222924a7b25845ba8b6f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df44f54f3a59a00498116f05b8213aa8b25bbb52104c8f2b47c9ae43a7f41e56207763356138f04683bd576db76805100000000000000000000000000000000079eecf398ba66a9f4dd742e143fd582c5b645c6e1e1234adb83fc7367dc60ca0b17451366dc23751d1ba1450f77d1ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bfc699574aedbd91f87e819962e1f7c0a7317989ad46d70fef8012ebe7ef9df464437eb36dc4e09d195f3487b5da08a000000000000000000000000000000000844961b01e1c64e2cf6485792444cc3b0308ab3fe474310f51de4f2272831203106fbcefd104bc19168e6b2f3bb55bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001815cf6212abe48ab721af502e10e717b7f83a616268d47e200f16ff61f8f67d4f781cdf4399c33be0081e7680b8f1f20000000000000000000000000000000005980ba4a63904adade55258cd974dc0748a3ab8462e1f847ef976be395a90c0368dccedd3bb8af84c6eb36b5e0eb19d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001656dccd663a762c675a68ff982f5b3668a9d92e550cd2c363b4283f2e6f73736fd183e3f0193d89feea581fa1b52eff0000000000000000000000000000000003f7706bf2ae3dc41fbba3bec3fe4e55591f95275b09b368529bf67e029aee6cbf9273870ea19f9e01ebd768fe3b6cc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000539851a23d0b050838f4de937debc50e6c4b0e6bd995e7c66fdc5991dd7751513b0e617400ddef77cde37f9779e35560000000000000000000000000000000002559c00ee457064fe79a3af80ef8ae4f9ecd367630b2ad20e0538641c2a4c2d8775105fa325f6d2f4df33944fe5d0551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168d60b7d339edab24f476abfe56d89798b4a676a6e213cbee6e184f35ae7cad9a38eacb9e2bf31b7e5d35a09e49a891000000000000000000000000000000000dfd17233d1825e25f915d2028501729f930f56d794dda6a625ded2b868db9fa28170329510b2f09cdd4d9546db3afdc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005fac4bbf7fab9c06ddd2e3a1db9557eb6fc57a7a4fceb3ecfd2c187567c3971e88e9f59b5db4271e30ea98c1a20003300000000000000000000000000000000019e602f1be4f6d2debc494738d7fa03d17397007b121a866329061e5b1a16a6bc92580a7cce31fa2234a16d6a25ae671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b78fcff232c30fe19bd991d7976df11693e636f7078402923ac0d2832a8901f5f167c49a6fb27e5712da659026ec17c00000000000000000000000000000000047e7a0b05e778d4dd3da7bc6b93ace745bad9cb8e7ad0c81c180a54458942ed8a15a85c4bd69a96ef55377300c391081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccc205ddb7d7bc7dc559e04badf1867b6318b59d2d5a658e00737117a68f5100e7053143083980d7a64be5437711c9a0000000000000000000000000000000015ce9e3e939adf5b21672647ab24bcf3a4fbbf0b891929fb2d69df95de858c97f0007c5c343d70ea4a44c8f45eef77fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf8a66f5a33843a2c3828b168c7bff11115c2f2bd9c4c99671f1d69f1b3de0d3f2e51342785235fd93d720c54867d38000000000000000000000000000000000f899f8fdd2012d3ac16ea2f88121f5413de84b9f3a6b6d01ce515745a8b6b9aaaddd3a7c43856c6ee7233786fd4cec31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001514f463f246a6e60e6c474bd81ecea4b0ff546376697b185ba344c0ee35e9d4c91281389783ddfd7ceaf5169adc31f70000000000000000000000000000000009e1da9e83daf8b6843c7f068207a3fb4d690c9d11a87640e76ae1e0a99f623da0ffc0c25a5e8561b253eb11babc86d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061289606cf4508cf60bf8a54b31a73b754a5dfb954c2cc784f8b21650b33b81dde4f7f0086e781e739cb40643743551000000000000000000000000000000000eb3b1be290b7cd5528ceab57b7e869ec5177236aa6ea7acf36bff08580126dd20c7b4a60aa658931c3c18c9c5e6e4d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000162f37ae71771963148d957b24dfdd48cec9c7b4c2a37ea6603d8abdc3024b4b2603ec88ab1ab00e254986a507bc0658000000000000000000000000000000000755e615de6bae0ed175302aeade00c188357c48541b34d924ffd4f91dcffc14173e9065b16d8668e1f473a09dfab9d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051826f8c438c628b5490049d2f6f89af48e612a6600e326d021ea0c3a6ae326d74fe7d58337f439f325f8971d20ee7800000000000000000000000000000000124583402dbd30381e3965f53eef4afa7b2c4331e0c4f63cec2d6fa0169121482c6d0596796b65befe506142ea797fd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eee34b82ddd8e94aefc50317cbb3a4e36c472f3912ccd0e3b36b407dce8dce7a0b859a11c64bc4c721529bb7aed2474000000000000000000000000000000000991497bd267f64eee46309f123e787c42bab9c9ad9f5a9caa870c038810f9f69fd385479a61ecabc8a6c1909c535b141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014da3405b1945c2241810e1ea8ab77f87bd0915e1658a7d9511a0433c4175c6599ab40d3bc378c4965965a95544c89b7000000000000000000000000000000001915b0babe5fbd3ca5b26aabb7f32fbd3ee907b33eb3ec9f2c8e1e69b481693f9bfc6c54a4fc097ffdcc58a55b8400b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017598c3be22425b1088094223a52aecb58dbf20f4efc308d136fea338d491be3403392dd23faba2fe18d677998f348e0000000000000000000000000000000000f74484ca3b6d26157d506c18eb5632869829dcce3deed4f7a56eb20b50ce045df1d62d98ddf49e27424860917d7b00e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008061f9895d7252366b94f471d609ddcf7be76cc738891415f637685495d8567d4cfebb64e83f0db9408833023ed0ff50000000000000000000000000000000004305111db5ec3aa8f3f93468c05a49105258d470d97a74175064503f45537156fc561049b19fb9bb04daf067843274c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000096811e723c0c8a84cbf55d6059b226acd6d72266101dab905bfce75ce8061d1abdb2e005a43ecf9132664de226ad80e00000000000000000000000000000000087f639c68ed49140c385d039df1030df31e88d764f60559cabbd79ce8f4b025f7dc48fa24b74720b01b09228ffd9a171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b891ee25885a493ac307b65048e56ca63d1b5598ed2b5939ae3cfc8c66cba3f817709ce25345e779f961cdf0a2ee5fd000000000000000000000000000000000b30c7106a9af3367b2d930fa591c530dcc55ae27972af7f3ad3ff8c6e4bc3fd97ad0b97374d74b14649eb39f6929ce81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000403066292d808988f3dcf9c9aa8f8ad1e44be7cbddd7035409a052798e81a14003da88d3a0e245b653163de98f5024000000000000000000000000000000000148fddb2dc717c114441b5d4c4d726a4c20516167ed358a477b52c859c9dbcd30a0e75aeb9f98023333041a919320d041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9b22a0e6da44e9cb98a7e5b130ad79aad8810c3da48cc5a847bbc433272ca4b2e144c222fbcee65c1d0a3866b169fc00000000000000000000000000000000122b7d314fa335cdc989efebe2cf053aa7433a038418dc2c19cd516f51b34535b86f1db4a4ad11c4d554702dfe550c031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0150998231a77baa936b34e49ff55f8029d730d5767edfcbd246fe21b69c42538bb4ba5d9561235ee9912aa418f8ca0000000000000000000000000000000003f46a3a9e26096496b777d182acd4c8d44acb377d5446f7d1ecfe9474bf7c39921bfdab64cf5c97abed9448a65645361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cf6bd0d88a1f258601b4fe8cdf52ea6036552e7ddc2e6fd77e9cea0911309c9e25fc008d06d64cbb5fac386ecfc1d90000000000000000000000000000000014880d3cb9a7411cfd2024957d25d3ac470e456f2e5d8d364bffcf6083d79d279ae1ee86ece82a1823d07e9595437f9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d9b7ba393fa8df0a2b411d579cf678898a94fde779979f04b3267996f44fca9d5ca38da51ef08c04a392714f486c0600000000000000000000000000000000113700383f13ceb2660ef8743eb7abbaad2716a1be071ec772f6ba487bed1456e75c471fb15c089cdd532d300ed18f5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d837df5d9f0e613d32306e28ce89115f759e7d240900aff4897279518e3c1e380c121b3befba68afa3f5ba2c010f2cd0000000000000000000000000000000019fb5931d75918b9cdb8d160062e6518ffa5a1ce7ea9d44236827a398461c3eecd24e8b5cf0af3203b4ff925e43767a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001754ea272b55f1f84bd26ed7c4c9f2d762b994702e2125c8922130436c32d487d49865ab1b3fd7f12b7183bba80443ee0000000000000000000000000000000004f5b02aef4f388ee06e2a75039702b8e27f3e4b553ee9a4352ea416c4542f9d514e15828a68f3196cde2aae58cf522c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152e866afc2bd4fa398dcacf70526fbad1688c13a2774e5f14878a9f017e90b3d3842f23f401f7311702f668354095350000000000000000000000000000000009b4b00708d45d23a302959e822e223c1265fd44116461dc5067c189f18e28255bc8116dac4fa1c05471b4e9a1f7ce4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000487ded1892222f3436118b1afac98396e9b10a7f155a0d7cc34ac10bd5767265415ba9a6b2fe7c696aec2fa6f7609c00000000000000000000000000000000010b6ddd853a62be08605673ddbba0d252b5a71f3f7bfe2080de1bab1a5dfe0546b1cfa1e25957868186038b255de02c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000496792b5bbd7bafcd4550275ba8a2264c1e72f7ed75f5fd575ba1e8553e7ee0ed81eab32ca109d345bf644689a9bd72000000000000000000000000000000001230e2fce42d1db5cab8ee196281ad2f27b9c7e0bb5f229289fb3a92dc97f62ea7dc5fd626c2dc3fc3fe51b12081c1231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd6c26b91b488ea47d5673cba4296e3440fce5ac4af4bd2e40714ca6963dd75f6eea2812a18e54640d86684450fd3da00000000000000000000000000000000125c3fd4e97ff08fc77f5cc97604658de8d65e6190de0f198fd9e77d0a30e47e94546ca1f7beefa175448eba56b1bfd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001650c506b76c6daad95237c6bc1bd2cb2885236b2adfa9893bdde46e2094e9e843c74effd553e1dac5570687a4f71cb00000000000000000000000000000000011b6df2fa0c78ab4c85581a1448b2fe6ac64b1e508440393de858332332e33658fd827fb49357c2909a3b7b89df5345b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008475e6b3318d6753898545ebb2c14984921bc2619e4da3893b5aa2756e8b5a2ace3c3741f6af7ab4fc88b59cb5955950000000000000000000000000000000015dca7693ec6237e668533f762241c5e5c7eb9f708fe5fbbd0975611d61317d943ad037bb204a344efd6b802b8e65b451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144535a8545179b4d4d5df14a5c2f0b76bea627a9769132fcbde55992c60db28920fd753a2c5314abab8d7312f8d71990000000000000000000000000000000019d62c386ff41b693682f33405116724673b0a54d46d3ee69a65d396cc78c7dd796d494c9d2e07095ddb15d1e3fd75581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000038d11c89f3cf902da1789b5c0e4af17be06ae4a92ab2ad4242cdf8646f40059335036cd341f6fc9a189dce4b220d11100000000000000000000000000000000029571a79b876e320c343eb1119d83e7be9338ae1892ebe20c73487ef108c102effca463e35898f0cb0ac52d121655e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001057fbfdd25c687fa77c73fbc1f008416f9a62731ace70f5729b5af47ce05b0c64747e449d01da358dab6c4f02a23f4b000000000000000000000000000000000f5cdab136e727256b5bd420ef3e7c30204a99c8c62845355addf490e9d9c2ea0fc7ca7b01d8458c0cc86bbb741a9a971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ed5869874efb400f03c498fef99116c3b28e12557b3bb51d29d551367713d5f325fda3ea89c1973e513b3f86223e99000000000000000000000000000000000d160cb2c59efe900fb63c7462950f7a327ee5ff240a5efc50f73107f1c67ac89d43770f5de1ce04bc5ad057de20a07a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001efce793a14da04cf1a3222909c3288e6f4ebd4ec9f0a2f7f3443b852c5aa07f5576112a5f9c25f6ba317eb0bd3ea6900000000000000000000000000000000176b2ad174ff7892581742cf796c215473a4fedcd158b0989f1a1f1c0c084f135dab34af261bd4f91af06aaa96f18b1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f81c1c170f51ee6faf51b42a1de67e70e0b94f4d7253849075fc00a73d379b9e6e8b1283d869819bb324d09894ff86a00000000000000000000000000000000197fdb4ed1bc23c2a88466851f1c6ac2ecdb73961301f5e9c12aab65e99e89f93b6e751f063896b713d38c763269c5e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e15ac0d229f2b72259eb0cfb8d69525145a2402efbc62db47f868693b1792e7b79be101dd1c1573fb9d8e1af02463c0000000000000000000000000000000018be7a48bc39215fba39f4663923b20bc356b81d0cf95575eb9c6b7ecd9c4d0c1f6c1cd2f2e59931a2fef1aeb12db1611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9ba03ec1d161db3a85c97e698ab778097416b8a07ca72cd3765d7b7a5640516f95652183e82601f5a754aa566e6ecf000000000000000000000000000000000b7ecf4a64f298427828662e74e72d12b8147a58ad58f8f451ca0b23f08a10a00a78d184525ea7bf1d7b24f111ad63561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a89ed91190a40514b6fab8c51fb6435639b3368b0ea1ba8456805b79cb3dc7b2cb92422d6b5028df66e3aa1cd5b5e400000000000000000000000000000000013213692bf65ba4d4300cf4b851e41ef0cda01c024f0cc7c427fa4d498fa7ac2b5721fcc1cb09e09799f5f42863fda091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000787797e2b4bd823198db3aaa4094980824745480cf994a0fd92e6d378cd17c430e7a112c8b98d58e718ce31b04ce755000000000000000000000000000000000e960940bdf423e33a0d938d0801b97c9944479ba95b1c0774a5ca3a961b69455595e3ac4e44a057babae6ab351669ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017db727b514457379b014e4b23f03f1abcd26b18e5f73111960ff006d2014a73d1c629d98e102abee5fa3ca3a2325b13000000000000000000000000000000000c3ddfd751eff5351a598e4079523f546f46a924fd8f460b861efd0f28ecdaf974562a22c7d7572f36377fde37dc323d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a08b93e6076ff874cc85bc44eafd9771c05daa4d2b09ec6403a87a8e0744fa6430f44de839906c2654b39ac6d9ee4e000000000000000000000000000000000d58ae6c088af5f55c6b1f42c0b1ff53f47f8742957802137ca8011bea7ef7c6fbf9cfd2f241eda72aa49c3f6756f70d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018cefa58ab523810741df2a4df5422dd408a358208ee707a1ab117e0cef38095398672a580cc37679ec5cb5faed8cea0000000000000000000000000000000007f83f91d0d2509f08867e6bd962312234ae85dc6e6d351b82ae6fb1c0e887b170c5841c4a22b8355b97c15292d6263f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139f241da3f51c87632a68ce74035b89676c1c40754ce75f8f529fc9911fc54415a66645a0667fcf482accd6808dd35c000000000000000000000000000000000041723167febd59f57498506d1dc8d4ffe4edc2acbf4bd494a736b3209d7922b7f950f95f7e0b7f35dd4f135ab2783f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001860f8165e50339f9172aa696876cf38e2acc8528e3941f881778622901449fef5d7ba73d475d87dad0c1a1f4ac912ae00000000000000000000000000000000129b43ba963a3c07533b9796b35a0209cda3b6ca7d27278225e8a89e430a5762e16c93093b91bc67eb3fa8cf7f1e6fae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d424f1c83119a794e7e67618afac4d63ed157349bbdbd09ef00192a5e08154bae6fcf3e47c4ee27049db48cf48a6c70000000000000000000000000000000013212caff92bd1dafab11780ff771cbdc2e69037c44406f9cfc4ee87f08b7facdff8c273d74c24b3dbae274362aea8151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ccaba1e8ef4a3b0abf960f54132f3e8c3a1fab95aa3030d89ff4601fe430dbad57d79e767cb1f51c8f979b49dab2320000000000000000000000000000000014cc0b2d1919fa5a2faaa42f8e1e9430421e589ec7f65a5400c1b4138b205d9cb330902b7f742d5f5f9cbfdfa528fe601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ffed6f20e3b7e2d6ba8d9e5043e505233567385a5d2dec90f84dfafd6014819c7b7ffdd7a649ce9a9c763577e4eee10000000000000000000000000000000004fd48f6e9797ca0411a1232a29c7fc4fa276caf6d24a4efc2959510f681817ec39d8950b856bc30ffa28d03b421f20d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c194a1c97da407a0e4ff5d07341ec988ee2fd5b4687b412fd1bd4b6836866a4b116729741094463dbea603b13efc770000000000000000000000000000000019ab98311307a8dafd88e74411f74b2536cf554c9a8944e0cdc83fa5e128e312431e46a961ca31ebf18bcdea26b4a84f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113770393d9d51790b613d5c67baf7864dc6892c05ca5cc15895f4c9124768bf0714163684bdf5f17bd1a53c42ad95d30000000000000000000000000000000001cf48a7f7d2cef5d3fad15101c3acb59a80fe07ccfab8dddb6ef51c3c68ec93c389b4ebd005fd329c1aaeaf0371a30a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136db71a46c7eee425d3f32947ec9847828d42a0d70b7628b8895b42f6bb7a74f3235eed4b857ad2f5990ab7d3ccce0c0000000000000000000000000000000008f0b00c9f15f50d774814ec0521014e978dadf0827cccf4a455976177432adbed2ade223fb766621164f6ea6f26c6361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008562699819e683da8b504311d2a0f50f8c98ec7edbf5cd94a651cb91583ee74c25a2b7618faccde5b03659b8c4e1b30000000000000000000000000000000016022250c18f9eed5585e05ef26fd6b27056f23047bad590c2170f0f324484bb2afc113021edcf1e99c3d45a92644bff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a52510c70eab373ac09c63c9a90936ea8a80906d37b19b0ed97f96e287db58a9dec8808af203814a1bece686f1d99500000000000000000000000000000000094452f6417ade2591770a9dfe1ff7cf0540aec514f24012d40b531950f394ed702c1da63299b1297fdd2614d5f1f33f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001135061c93bd08adefaad33aad54b02988dbaa688f00954b016f1d820a1c840ce78b39f9b2f517cbb0a4c45018d8982d000000000000000000000000000000000d91951db959af63ebcce05cc03999af80fded43335883b852dc142d15b12301b76b99884c5401accad73e67fbe0e9841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176e05a68981e91d4f4d38118c7edcb486d8dc84897071b8cbcf3c64467ede53591d36251c56e8ea471b39e91d0321160000000000000000000000000000000002aded3bcdb23a13020647fe841645766166e0153d5e957d592b04356bcc81b8e3a0d00ca6db4c5079a3f559037a9b341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154a8cbfb8374e095bc27a8aa76cd8586b64983ebebafc317cff1db29d52a43725d8997699ccc3ffc04771cbdf1f56f00000000000000000000000000000000011310b05d105d4107a1c4be3187aa29598d9fe004b6fe2ea0c0cf9390dae53325ce9b07e6e33f1d63f01c21d02a637f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e114703b23697a172c6d7d9c9da4b067f0417d35f1075b0b953590e7df333cdc64dc802a2bba5025df1a610e40812e000000000000000000000000000000000d9facdb1b23eda1e538c8211ee7fdd4498e95de2f0b0a339875c72717f5c303701fb88259fccd5642fab59433c6636a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cc8170f29e6b1adee45f1838930ce70760964ef7e891a9e638e2e23a1f97134d475b30ed5ea0a8cc1d5a9b96906c39000000000000000000000000000000001953828883297cc95372690a942e999c877aeaa658051a89890024e4b455617d3230c1beb16f015244480625f889f9501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006fa950d20442e100e7eab3b94a148cdeed7ab15b589a0dd3ad4be764ac6dbbbbdc4520dc3f80d1359526d16fabf885f0000000000000000000000000000000004971da5b246d65eee87e3b232cd50e14cdbd77d5538d470ab35e9f8b12026fc7ac994f29f126e1042253843b48e71d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec033f86bc013cbdf0971a9152712c2959fba12ddb51814b582db597a60eb025c4f7ce40a8bb0e4685d7c80a6790e2f0000000000000000000000000000000009247a927ec0af042420213300c1ce471e1005150306086cf7eeefcab14404a10c90fd1997da5149900bad7de4ad8ee11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b94f292345559998bd1c44787d75f34595fb75c829653a3a2fb03e4a4903c88cd66b3b20f9ad816f815d4f7294a5dc5000000000000000000000000000000000047e0ef23009f130f0403541547624f78a8adea913801f4ff083bda13577d7e2e273f8945c7bd8658e8f49103d3bc771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015bc4ec84146fe5042b3201d629fcd5295490b918fe02fa5f84ed7b809b48d11688ff30ea132e4ebfad0bc76ad1fb17f0000000000000000000000000000000013ae842a93d228eb585abf989c6004505b2cf19426ea27c13b07ad2f12f408982d6e7376c8401469f18a1866238f4dcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cac6a277d321f35378a9f046b308c98213209df49a426ca34fb1e43f50f7531a1a0a170029b4637b9be3437729549000000000000000000000000000000000169bb341cebc52396bd83c2ea7e6f4a8d72a84053167d5b2f229f77d7896190cb7d61ddea77ecfdaf9b7ed44a9e4d1d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004533816a243823e7b3475c2e63394ffea01089254b31e2f64661b10bc3717736bf099a0c0b1e6dbaddc0eafe325105000000000000000000000000000000000169eacc012f078c717f62a5bc67d6a014b7949439add5855459f4b66c5cb9a5b2e95812967f919d83dde78faa742b3671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000557dcb5ad08de34382d56e0b611751e53e766003637c4d4f9b0d5d5f5e13fd2e6516eafaa1c0790671e5df2763bd283000000000000000000000000000000001805077c7e39d88e127a732eb738738006e271f21cfa4091127ff46343cae30d7cc24e7d61efa93c19fa802b34a40d231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003565c99b76ffb7cedda2e9ed43ed2b37c7417a464d060574739da488bcf35aa39d4d13027fd17029de1945523473c480000000000000000000000000000000006b9866b561a78eedb647c53cfb06100bf5ad627453cd0531e2a46c2ffaa9e0c17f4d46264dd79090fa982ece43e14b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000582202db870de45ebade9d081be109bed7e4de081ab169d416db6bb0e10d15880bf2d98b4d16afef1ccd2a8de4e1bc40000000000000000000000000000000004c8bce91b3a1f7768a81c3da81ec586f785562a361a5d189a3ee27203effff99496b695911d740dae0e008ff02c27761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef8686bfb3b7b3a8cef9986d3a18f36cfa4e21f7e10c5b86206066a72f8ebbf4c5c26c3a9dc93d54e2827810ccd29a8000000000000000000000000000000000df2bb3c1fd2ab48009750e13e882563a35405a495dbf721e17d9effbfa3cfb44e034d3c2969fdf83f0d7451b8be93511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039d2f8cc0c810619e137fa6721e57f80b5e8ebd1ea8524b942bef4f76927dd702d5b6edbd4f766b6c3acb190fba21c1000000000000000000000000000000000896f4afa5e8d9cc9b8f83cbd0593c9f1f927d023885c14df171f9675803be5636e46f82b43c0ab6645dc0ee5fc1cc6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000085bc358cd6703ca2cd0a4ae1e29a763e49131aa7fc4c34528d3018f1a5a28407b82b81f355c560ccb0bbe651270b13000000000000000000000000000000000340fc1e89d4bfff8fc7ef363b4762fa710ca34e78212013ca2e18b910ed8959f8a7571db682f618e454910213a0586e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e85a3329ad8c8e8ea6b56f13b0ad1c1f807434178cc2e91195092cf3a0e41cbfad1d3dc9c5619df0c11b4928bd2b31000000000000000000000000000000001853fd0c2e3cb5c22f43b0a0ec8f427b11481ff306adabc8f1852e1e853aeb46cef65633e687ade694ccd19e1577ef371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016612bdc5823aa43f3a2231a6f9c091ced5ea2c00a6a9c532bee192e89a13ed0105cec809ccbbfb3c8c1604bbe0cd91c000000000000000000000000000000000756ffecefa1cda372a5297af63a448cb3303710b3c1545c52619f37f3822104eddac852bc1ab3310644b0dc5b8b498b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122f47200608d56ed78c98820b2100e67e490b1075c1e3eb0a2c6df40f4f0e33c3eaffc6750ccc82909f91ce43fb06940000000000000000000000000000000007031b4a578dc3f4a9b8c10d72d21830fad427e206fea4b99207720f78f045f8199667c7e14cb2c13e3beb079e821a7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152885db532cdb66d04941591f3d23ec04d902a73222e81d16c66083b0474037bd3ac68939ab91dbca03900ae637454300000000000000000000000000000000176007cd60937b1c554dc3777f9469103082bd22b0b86a77cb893f39e5a204a8707f05a92bbbcb905f14466a9e67bc971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2e87e587e2b33af1de6216eecbc6c96dad6b17fa38b7c58553d54790d09d95e1a3c8a39314c90a44a2ac48e2673dd300000000000000000000000000000000070164feff1a3112949129ecb1db8cb43d57f6c3f5680d04195442d35524c4ad17fd4c9a4a506f8d0f8eaf6a23e542551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001cc3fb8b4629547602119596ef9af770c7f445ff2bbc05582119773d295400bec6e1012be1b41c1410c127acde07f0b0000000000000000000000000000000019a9aa5f45a437865b5d0031dd9915f8bb4c0660e841c0803ec595c50498c855e3a1c70cbefdab9a2c859f0cf8618cda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000693644e99b13c150817d409b37e250e582651897ce03f284276d4cf287c38e09ee7788738887ae98ae260caaca899bd0000000000000000000000000000000002ed5d43c840b50a081c0105d8238a458a51ffefe2ab0b3ebbf595e13142d06b6e9e4b673507931f502ea7cccaf4cc861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ea1b1b72a50bed7cbab7fe55fc11ee5f80e82fd106350c52dbde9f3b49e68b381cd0abbf7d83de2e03c303ecf3a66d0000000000000000000000000000000002e92ab97b9316acc5a4cc46178467cbb154a35a99cb5a26568e8039261568f6f7a0b2291dc64cf440dbdbdd16f8d2351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f6d8bd01c8314989358d8df68097c15c16231d66745c2f6504f4714d84c4de68107dde79c8b2893ab2976f741ae365000000000000000000000000000000000b38f3a228a5baa59b850dfd24309b3a4207c7adeb29137b876b21975193a7cfc10036c504118451fb65cd004b398b8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aca3c9193b3138cd9085123e13e9b5c4a8cf675a4b82b5b451c91628a3310be4d25d44239c7aa926f6e951a132b9bdd000000000000000000000000000000001188604da73ce0a5a1436650e3832a3a9e9199ddd624eeb5df2ce55a85cb6efc835ef1d2de093bb5592da051d8fde07c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001971f1940887ee36e930f03d3b677f3939a04f752a86e5ecaf2c1a3583c972b3e685bbd6fb742fae1033f6bf9c3e6ab7000000000000000000000000000000000dd5ebe8b2afad2ccddfb036692cc3a2d72c9200b5d3330875619001279eb399259a68f6712f198db7af6249299a13f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000799b33022b3ee24eba812de4cf544cde7a6894c344b57ec009ee483de517b7fb2f75a2d064b884c94324895248e8fa50000000000000000000000000000000006d2f24a11717ac889a2bc5994044b4790b7283f4e3ade25f7b77fdf0348e0748a523e461aacbf425179bae7638cf42e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3e3a6eb82986691143dea394a278e6f8b2917dfbc627480f19de4b3670c96ac836b7c41fef928a7fd6f3fff4be6e010000000000000000000000000000000001bc33169713146d01730343d81ea32389ca34985329f6adc5a7028afedd3d910c2c15e62d94ea3a3c83ab9c40c1891b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002068c622d6cb619dd16b4b91be03e4f0aed364b4a1c59b72e200fecaa0021905c2ed79a5c3d5493d4d0bc7e529ee94600000000000000000000000000000000021bfe3633895b1ea954125429f21ac9e7ade2dd4ad9a9ae9f244b3b1c96da79122a27ef7b15d1e232bca3d25339b33e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133689379bd57980dcad88081295a0d12dc85ca7419d15d3e24bcfc8976ad35d2de3cbfddef279cfee23a8a727915a760000000000000000000000000000000001a4bff3854b5eb2656ebae8480d3a858e0e16716b26ced496579582c0faf99959b8a389192015f737cf04643d22b99d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9dda7c7b77b9fe1b474e47454cb4215d802e5ed72131e4411987c3e8f95be67dd3a89e040e83c99f01459e2c010cf60000000000000000000000000000000011e104658935c879b09ded57f73ee2761ebdfd5de0a1e4d0b927bd56b4d2841af62cf355bbee33910cadefe3dfeef4081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100f08a8d88078eefc8932a42edb66557690f5d2d54249f0776e487db611b02bd138cc927fb7e6cafc0081d603be20b2000000000000000000000000000000000d815119f67e920273c578fbc29318d4a9b93342096c14dc1de2256fe3efdc2525ec1f73f4c1addd8620040b14de13641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016870eb02ac057797f8a76b4780c48b886d22d49c0eb8f2ea605875e69a5d19e7ec8f7d91b3bfe404421750eb4baa38200000000000000000000000000000000172db71aa5c89e0f84889b51faf4814d54ea17216742e8f50916800e5cc2ffd78d060ee36d9cdc37c76feb6b6cf73b901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a03bca64ab3966a3468ed1bad6fb6517434e373cdd1f0d2551716ecc067445dd314ef638b24ebbae26609fcb3b4bb400000000000000000000000000000000189b8cb09089ec04a71f38c9e01beafb695b206aca85274aeeb598e92d61a91f23169e8284cd10902f6493ffcef890971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af35d80dbadfc569223208e2d5f515b6e7eab59843398245920a5af8c563cfc78e1d603c66fafe1535f0d480218e8bd00000000000000000000000000000000175e46f89b3d63452c879317893e7dd19d0a9ae426ce4e99d1a94cd6ee79a88b97d94d51aabba8738b62376acb037cc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061f932120eb74dd2f702b3559ee4b25f7094e617bfb9b60e40534ae2f8a0eb28664576ac7cab1d91b88490c50f1fbb60000000000000000000000000000000016f39113ff2decd67f9441000194e50074d9c32359a6381fd083c75787dd1efbfa645397bb9efb512d2428d09ca091fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000644fdbd9637e8075902460961a9e59a146e0fb44d2f13dd4745b5d02317ad448541f98bde13be1d0d668cc76cb6097c000000000000000000000000000000000e5cd58149b2697ff46f5f898f43ffe4b25e87c83c739474ff4f68adf2967613a187935aa6afee35345af04baccb98381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c2d1b55c83103240e3f9f59d1f659d17cec41fc96614c695394addbbc94bb9400755811a979516e1d5e7ad5bde8df90000000000000000000000000000000005f0ae66143f7ccd61f05e6326a49d4048e27b9200240c9ccc3208e50aacb39a011a38a7c7a9bebfb03aec64153f152c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de01b52d0476e8ce8c557f3f71b5ac1a4640b67b4ba8ea69071bed3c3efaa7bd34e381736d7cb0f83568dfa238746a9000000000000000000000000000000001219cf8a50765dafdf9332bc948fcba8c47c945035eda2e0a184b43638ab72a9253c8d4347fc1765b488d9675e5b8daf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9c438588eb7cc58a165fea2418e1f430ecaf9786db2cb2d4a5d853a91bec87e72f4b11d224c63e2422212c646d30f2000000000000000000000000000000000ee39bb67fbf9dc7af04a068d80837c8ec1355584d76c6351064b4c576e65a389b2e9b87f7d3679f396b7a7fffa607bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132fd1168cdfb8946f5019f599fbfd7452dd7c89dbd6b246ae0da8edd2b29f2a9fe9020947bd3e09c7878f9a607b31740000000000000000000000000000000012ecb87a8db9bd6dc1ac3422f1f812f370b45ddd4d28cd203fb6edaa112bdab900da25e2d59754bf2a4d2404f087eeea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026146ec5ef6929be1ec2df395a878c9e1ee0f6f27be202709e09cff3098ad15ca989e2f2edd673bc8214c02c0dfa9540000000000000000000000000000000013cb27be2cb14ea2349115a8c9f8c2d7f61a9fddf2ae5508581d0f8a42d05fa9fedd3ddef6b8f4badf138f2f6b209bbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e9f1bebba2668539e154e65177fa187812df6114170ae46461021a3e7b358b3b20acfa69f1698630a3330ecbb20edf000000000000000000000000000000000f971fd7b3e060494362d40a5d4d674d2d0e3f273e48fb85a25dc556cbc8785ab813681671eead8a419dd9de717b87131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185e18ebf0c82c8e309ccc1cbc9e1aec1373da8db6d965bedbaeed91ca7c4fe0553d90858c6dea054ceecc20227528fb0000000000000000000000000000000004681dd9f85c181e785f8c06e606820379e92bba0d4ff587520132a94e3d0c621af7a5841e3ba1c40a91c5e6b3c7048f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001270c243bcfbc387a538f53b74767b78b8381668468032b5818f47fe5cd9f8b8d838adec3419060c56f50919c281d3dd0000000000000000000000000000000017bf377d16e5294bfd43b61d024e577ca63c178cb8ff8b0760860105a0f5f0eb1c5e47cfbb56133b871dcb89a87331cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001246aa044f3a02b68cb16c405cba4460834fce0fc9fcd59fc198a8c7ebb4e0b42d581bd47f727fdca571f2f816da615f000000000000000000000000000000001992c56047d03bba546c4e1e1e2e39eea1709103ab7e63201497ea3f8fd05fd3088432e9777a8cc8ff628e1d05f8793f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131b375f421c6bdd6006f18aaaf715d865c3d3a95f715edd696b56b05ee2510faabe8a9c0b7a61390c4d0786a609aeba0000000000000000000000000000000008afafb325319986179a679e4639948cb48fb738a61f4b4363e067c1ece76e512aa7371766e0d935eb037d142217a2a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd7fbca565ab850631e645d0d6466010e2d55fc3a93cb414d1e5cb4c1e5f8060ecebaa74db64614f8c0ca9b3c7adf42000000000000000000000000000000000b78a1bf6bfc8f44aa3014b18324f37297ea7032f27c1b5e67a5073b73e8fbee9d373611c968f003b015ef19cc0851891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101f7c11b79187914d9c4c84fdf4472a9aca6178051b5c8a066d13a1f99c2592489c96852486e94caab0012847c31d460000000000000000000000000000000013e73ed84c657711df767b1ad96b281fdd63d90a01497d74567df47e96a9f14c983e8fd7c2cb6a80dadf3d4eaacdcb081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f7417b1fa997a9584eaa61f336bd750fd5347c0e7dfc496bd3cceffb6fd20d6e2844642f7f0b16a0aef17dddb2a20200000000000000000000000000000000134a6d1639ae80e37ad3f35da183d7a83b6a0afe9718f01cf7ea3fa208bf7f68a296cb22badc2443fbbab51d9e368af31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147822bd7a84ec594f661e7afde6a3fc5b8aa47248981f5c5601c2300e3d55f672e9ed91d994ebd54afb5f3269b71014000000000000000000000000000000000ec8ed4e5a5ef62da3647aafb16b0d42928c9e262c45aee1e372402a221822980eff1dafb10e5c97ed5e1e519575ad251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001099aaa95699b7c65a72f0b472b256a76ac0b302f798a29bd8b78a394e83ca9e43e3ad2a2c8836ecab261bbcbc19708c0000000000000000000000000000000006df75d8fb0bf897fce956d6acf8a54d0a6476ead2cf929bdf602227d799266ccc76b6acf935a23780c5bacf0039b88d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e18a05406ee1709d7d095f05efdfb4da54558f70448989d02cf4864f92b7e150108d61fcf30d976f68c1f11ee50cb400000000000000000000000000000000069550bf7c18ba02f97f755b9735ca6208cf92fd86208e20a94c6096a12ea5b6427df767436564c024575531bf60b7f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bcde442fa8a1d734b76bf959909d18278b34ee956832f5ac49f68981228484a66b59cc139333a39825c221a92530b800000000000000000000000000000000013e40d5978260b6871eefc9857cd2736f39b158fe849937152cf6f320b68408af6754de3d7d564f650766d20edd7d69a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e18ba7f45d20f1e5ec5c7dc4cdafb57530a88a0165571050146a735a3b8960c8d20ae3f3324126284fe2531545c285600000000000000000000000000000000073cb8f9b1a6bafd74b3d256358c914b42d1eea1a80269aed97d56ba7f0183b1db01a05a4ed13d14a0f7c861de648a971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130c6d6ac338b20ca3fd7bf0619b7fd562145f6c2a83981a3b23d07e77e20ee6fbea7e1b0f378dbdfbe6c206c350da49000000000000000000000000000000000cb2dc59d96e3ca227c06b0536a8913aa5561355921f18dbc397a62240d13879963c073c5b5248cd5bf939f36df7373b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fc533e5d6a74860d93c3b3b7737bfa6cdda0785854bb98f646f678eb654be70525ae1524e935aa616f51787ce9c06800000000000000000000000000000000187ef8a77effc734c97b59484b0cc6b660d74c611fd51939671ddee33fd17cb225145ebf8d3ed938249f772b85b96d911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa1dda26d80306692e16d48e98f32facce2414350c72ca81bd052a386172e8e0300363d5db8892f1b94e3d4d99343310000000000000000000000000000000013615214d4cde9f63e5803b9e321c403399a0a3edf235b4f793c6006b54cd17facd5369585564207d405799a1b55cb881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040fa595724e8beb7fee1edca40655065e9561df12888357b8d645863cc14b9155adc4ca7fc91e3025a062ef517c41e5000000000000000000000000000000001662aacd8ae85acf179be2c922835b0938a1193191fcba906162216423dbaee265a3370a6099a9293e7ddfed1aedf3521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aeb732bc03bf60940e25d7a6a7bb96c0d4e4d72282f13d48d10c2ecbe87e7338739a9b1b9e125f160f59bd22463d4540000000000000000000000000000000000198fd13e1fc580733623a24203c856348c965f1d1e0df6a68327d0b9c1bf4243cdeb6e32cfd00b539afb43d52126f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119eaea67c8aa9a319390119e73e36601106006afb8a9ef6098abab40309fdc2038a3317991d92fb18ce247ca7d1f5e10000000000000000000000000000000010d378e0568c0a2c0a3476cb34a86a7515e4ce6d123cd2057498f681d86d4cd7323ff923bbe72a82260d5470850154161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040bc777a01ec8700b90fdb72f435a03a1b8d0d5c3f478de38d6c9b8ea1a31a025f8bba396d3461be1db7423e9d5ef4f0000000000000000000000000000000003540ddd975bb819c91a5e1f68185ed186d5cace078d93b4d8421cb4a645744d71371c153f386f72c4d439c77a6ad4121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a0045c8c0c88094ff2b7cb0feaea36dec6a374f20916cf108f63c8a0c82ea59a32a95d32132a423db3f187516fd983300000000000000000000000000000000062fc6b5391334e7f2e66bb276e5c0a7c77f2222e1a5f09ef954d743f59e95fbf247fc0a995481ef673fa33f221161591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ab2f2387e58341e71c3de1ab9363de988f6fa23a638490784b72836ecdf6135ce185f6a0205fd2b466d5e01c11f64e000000000000000000000000000000001105363b6a7b8d996d55370409472f64be1fc8e91e3794d53af775b7639954d695c5ccdf2fa335967e1da1bedbecbe6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012169f892b89533e667f0284c59d8290b05ffc0786eaad2f91f80133b928352030c04a82227476eb5e2667c6963cca540000000000000000000000000000000008052c2a322e7cd404151a5f036497d5f6535e6c76d5b19bb517ae7609723ed3d0496fe5882a388c61276d07b25c27501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e475a6e31dd1908fa305a70802f3715f0c48f56812b1321c24ee29f9bff2e21baf3cdc9dcde0754b0259642aff80509000000000000000000000000000000001083306da90472ce0ee7d8acd29aca516c65d940b3a9dfc42a471b7abf816cc28a97283d348ff5575b0461174ede53061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111fa36dfc6fbc929fc2ac7665c8de726d656efb718b4d984a756681fed6158a8d372403e18d8e4b6a610224c6d7ad7f0000000000000000000000000000000018ef01065bf66bd295f0cdb13c6de452aab434fed68d4a7e8d8f46a9735c201b31a7cd547af2f439aeede3ea7e9c8b6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042b29dcfe6a621d023a464f1eb6b6cb2c1581ddae6af44c80f00c4eb16e1677358507b0cab6691692cd7a0f9274a2c20000000000000000000000000000000015083da0d6d89cdab1a1877c13e6561034448ea057b608181085335b96a178ae3c2b923ca16e49181538f28cf68fffc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e632929b71e05df1d4f497553efb842d3a286b0df663df9016182394b0ca1b7510c5ec7f9d19d243b178535a1bff82000000000000000000000000000000000bdedb1093a3240c5e2a4659f604e5147cf7b300497e0f1fdfed1653b6c4a24a8c9a51395fe97c27f71a5b4f6b52c9731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097cfd3608ae495961cbc69c39e4fdb2f9340593532859bfca4b0631b67d4bd237f9fe3610eac80f16cc376a9b7cd82f00000000000000000000000000000000000610a85b4010068bf5fbe661e0dcc391e8f10e641035cdf9f62e8b4e90aef3c02efad48060484bff237f9f5cf2de3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003400da5e5a306627532e78e5c31855b81a953e53ef482ea80267751b369824bf1ebce86c6f5e860f77f5df9122611fb000000000000000000000000000000000badfe57ea33b051d54b3265826c19745f7ea6da29b0717f83d2d8ac82f6073ae469fe6c6a08205f691d9713d5f285461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001687aeb40b60fd146ca41456fdb6fbe1d23be51c3d1f45a51fa9888db7aedc6cd043a8cdbd180b2301f7ab0e93740f940000000000000000000000000000000014562f0b9dfedc26dbcc60c101f5f85c1a728112417079c3a51ac909959a91bd6f3fef7569490ed01af2d91e94a6b5191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b57af56577385884e4a61f7356c27660959166550f5d2e8085bda29355a4ed806476a7bae78b30cc52d96b16570304c00000000000000000000000000000000155329db361682434ceda4cf6ce49ae296c167352bdae922304474d0e329f8c77dd433e7c1e1da9d916fb8e18e799f341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005450adaf5acc678ebb31224fef2a0d2e3444aec8e2dd843151832c5a94654c493b31f93734a3781de1a35fd5d6923fc00000000000000000000000000000000094a8d0906e575411537a36bf4448b6d3696312ee762ad9a517b4edd9fb05f82a82eb58908dcb8baca1831d009dbf64b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ee63c84b48e561471e1f4120905d6f8d91fa4a41e9edfc14cec0180a19849731d39d8aef273151e4b8b287210cda58000000000000000000000000000000000383839ede8849cacca9ce263cd58642bb4ca375090f5be0dbedd342718a85fdcf18c9013bcad6eb2f95563f9c9ff9b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000104cbb266f94eca53d30b20c239c2dac542b15790bb4af3684c598541b1ad1c095a1e2efee3f472508d0f9b0f0737bca0000000000000000000000000000000011e8acb1284ecc6c88ec36f37cb7b134e49b476857f6c13682a2c5eb97a19f158832e75a801d19b6a60267061af67d081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182a9e2deb868fa23f4448b8a991ddd6e2d58ff0a6c8b24b2bfe0ccf0715bc57e1c29c1395fc6394dca1ee6396c295cf000000000000000000000000000000000c5939d45a5db911c3b719bb80eb71e412325f7c3634ca6db36beffab0f8d508c9235013730a8f481cb87260c3c12cea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011217e7aed6bbd230a65182d6edec32535d83fbedf578b16eb9e1e2d6e9b08186dd617b816ac4ab865830ac2b265ef2d000000000000000000000000000000000694cca1bdc0ebb5c1d0d09192bcae63ac87e5b6855f7aeda1c0d97093f5efed1a72c73af2085bf082344275fc09feee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003783170c2c95dc5658274d61f8b54bb3413dead820f7b29384bcecb98bdf9d53ede8288c64a6aeccee69d294eefabe200000000000000000000000000000000130bf2c37eb720c4731a850f2a6b7d9a214e26efaecfe16469b0b39a9f54e705645e8754e7e2865f74d0a7a5edc5dbb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba5f0089cd9096fd34b809210bdeaa1099a1a9130627bc3eb017688927bfd630006b9dc792544ffdd9f137cd5f9ffcc000000000000000000000000000000000ffe66322db6aeea62ac317fe949703c6125da92af85cc3e0ac8d8a5af7ab14842f1eef72c25a95737c6153f3442041d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085c49c037280f0e9994895cad16e323f38e59e4578407882821e6324ed56587010e932e181635e1ffc18396a4238c4700000000000000000000000000000000089d213af54613a338f10ecdaa3cbe9eef4b2e917ff44bffad6fae46bacf6b9a6ea9e7fb83539877f285317616a33a381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005536359f00ba85e2ac9f0db860a0fff3ebb1dd3eb418697b719c6caa392409761db22e08281d0560fd2e7b8a7ac79470000000000000000000000000000000002c9d76314878bf50143b3b69d582ba90d796d5352ab55aa8e125e032ca74d078539644e8da0fb22f01a8f4c313d9f8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002fae677f9e71b5a07290e7b97cab17e2a4d83e2fe56b9b2f90a08d928eaaf7728ec9d48073e8cc928f4d886430d7f32000000000000000000000000000000000690ce4cf9f36580efd5e60418b114857eb3e8ebac4b9329fb12521e0d5cda899dbbf5e49c81d23eea456d8bc8708a161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166b1f8abdf620947b77b9e064ec983a64aa3683aa7480d14f0747ad614582d03fa6b358c0a022b033ce19c0c3474cef000000000000000000000000000000001016dc01b4b57d9db775c61e13fdf0e5c50fdbf0cf8d5d5a7a3ca0683e9f61de5d08be5ec77cbc80c7fb5f5dfd486e161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190d1adfcdd41681f541b0111c169f3e7a85e7a6383ef6260e4b884ad1b907b78f9fc2720ecc0839512ccc25182da36c00000000000000000000000000000000026319005685e1ebd1cf00da6be131c445f32d50e0c2b3fa7af319f9c339b9ed22438531d3fea33c98c9f5977982c2ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dbb471edd5f0189d82b0eb5590c84f8d9c7781edb179a5cdd29cdd11d7b4eb45f0c34f1c43c27d1ed75e538e0a3cf3b00000000000000000000000000000000055356a2f88ea8d08714a2b8b9a2de24f8b3b8613b483831a8812381c01d1dbabd81a74cc9ee55af7d39fd72e49cdd831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035a7a881349b6756c3e27f2732a18ecac97eb87fb94c284bfbe727f53b4f87dcd1cac7219c70c91a1bb6b3cd4adf646000000000000000000000000000000000055a1a44381acc2113d4e3b4d359598f1960425952d8dd4fe31dd8a593b09ee2cb73893fb45dc0500e08942a1dbdc7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7d3970eb82949eccc717fd15b43d70609153a170ddc3043181c65adcd10da983389554eb5fc52bc16486de3d4107f80000000000000000000000000000000006de65b692aaee5ba7e27ae71323f8521be08d3e51ceed86cfed685c34d525497b90e865a009fff295272ff8f643701f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000110b74ad6735e703fbcace6c89e0a5a874f25498da9a2a9422be4e7b6589c2f3aa61ef7ef96557f40504306269e56020000000000000000000000000000000018dc0678a0cce8b8008618ff78e2d52d37845cebb2963039f87a890229cc441d63dc48779c20f830b63de17cd82f25761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011821defea047f8ae7e410b0e40053c551ae78b550755e53b4135af3e3f65ae74a2c8d11f2c5e94bfb485c1d7bd943c20000000000000000000000000000000018ed5c4b2ad754040b54eb495787a4703b5955d28ff354b4ce53c5dc79f003463bd92200a1d746a6eda3dc6b1cf5fbab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012c35fe854d6c9d41b0e229cf0445d30993a3be03ca8784775ebbedadf47c15a519944a08ebb45d0fbd9eb067b363590000000000000000000000000000000010c0ee7793b27b4b84465e81bdf764b36a2e3ee3fc0a149c0805a5f7e08303cd38154feb9dbfc55001471c0c73fc02ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c71d678034680a2c22a8cfdcceaba1d284829515afc9a2d075c411a233f4d383c15efdf9b38c36fbcc522805ae1a79b00000000000000000000000000000000010d39f975e0558ba1a8775949a2924b9d53af6c8d14c2eceab247beb2c5fdcc4e146a0916629713440eacca4760e2561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015593cc0c0b4edf82c121aa62a65d59e77f509864ebf834d6c4c4bceb1475e7d6dac076ce02a6c9d048667e984087a2000000000000000000000000000000000926918fd5709660cbf1315f57b16b10269afc9b0f9ab771a3d263237831f04e91d63dee1276c0dc81e8f04293e9b23d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002067e1b319c4af12c01da2fdeeb5023a6cb6796ae13f7c10136f77e5f17d59772a6a3b0bedbd536f7385a599f9a2fe200000000000000000000000000000000117e47ead23ed2ea4f0bcc9d90762498f37694f12a5bb24ecc82ec77029a0e9e1b0c7123a9538246e970e700f6d1e2d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010587fb7dcad99516c9a68832ce579e8cd07c829dc997e5c24c318a5d16cf33af493da036bb227b941cc0905020b725c0000000000000000000000000000000009d91f1a3341b9295d85026260f8dbcf909832b504d514bae9dc15011b1cc0d64ea53a9e9f39460da0d0b1527faae40e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097fe4a745fe9803efc5c4f106c56434ec2642143eebdf729991fb21ec409db2ce080c2e40998923ba173d036cded8750000000000000000000000000000000001da0439e3d62895a3e270f7b5b73d0db152016457775b90a057132178e67fc385999d68558fd482dfb10f3012a7e5db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ef73a51d63c29e98a659da8aba2b496cde60c40eeaca0442e53daa6b56a9020268af3d69e7ac338875e444ad8f925a0000000000000000000000000000000011d8f414c8c9a7db0688c6da3e719fe55fd2564e2de03e954962ebf0a59dfb59516b24e58286ee26c2089910192bfaeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030812fba39af8d0ec3c275850f81479e9c9fbe7d3d72961e0c1acd2d126435cbbbe8f9fe17438bab9f262c8c571b1a70000000000000000000000000000000013950af9af843cf55ff3cb22aa67a39892b13d2ce9ec92cfe4e2bb062bd7463804e8f48ce8942b8b3c115949f502f6ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000087f5de365480c350c6c9eff3db5df2fff245a95c42ad70604d3215487cd389bfcb037ab2daab12c8ecf25c18296abb3000000000000000000000000000000000ea3448277abc3abbaf772050d964692b2f77adc028d3fab7cd9c41429f2a0ce145766b41c049bf1d11d3b82c820d7741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f0ef6647470f398f4c46d370a61c3693bb82c7ad1169b80cad8d6860105fd60723169259c2ec7c80cdecb32e30bfbc00000000000000000000000000000000107996dbf17ec32db185c7671fa4d909fe48fe901b7c9bb70ae0be66b32395df7fb6d3e8b9f46c970e0483c3cb68bd831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188dadc56fdeb7c12e3bc17598369df0b32d1472a9144b20d48226d950452686f99fc81916197d9b98b9c3277aa5aa3800000000000000000000000000000000039b400b3e1a5d1a2536f07a779599e63ca221f17c523019fc33355fdc0f7777ff5c826b8e0b247018191cda461048d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002830b178b6b44651007646505dd41a0c9edc713235163521f486cca96849618c3e96688320a65bd365192f4d9b3b5d20000000000000000000000000000000001657b61d393d2c354139f36269f238d836b1eef467fc56ea1b99db819074f9de76ced36952e4e28a84dd2b836455b091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a11953a4ed918347dda5ed4cb92fe0d696d0504611a1d8257dcc80ae2121084538816b8615dfc96ad293474fb7a4b50000000000000000000000000000000010747d6a69ad299d5e15b6876138e5d30b347e156417342d7ed5c193537e6e1c0c946f0ec7612d36a5aef907de7219591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e7c5a20598669f6f14e3332d70b896b4bec6e1c5412eeebcd7908f9418252648864ab7be647d28a10f6f769b1ba88800000000000000000000000000000000149065eff48c87736813e8fb6a7dccff196f96f8cf4e9ef00c8d3c5a7f0dbdeb01b143b88b83f30aac0423310f9a4fef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bde6cdf6ff6a795e333497ef003ef13bbf47b0830a3ecdfc3eea32e9b1b5b8489e47be4e64bdec5b3bd26a056277a24000000000000000000000000000000000ce5abad01f8b59d2ba06b637da67a981f88b584604be71711d91363ee23a21a733e9b2e252e915be13b352b16a7f8461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b49b39bace0974e8197c990b965acac828239231141107b2305400d9e352749baafd577262a3eeccfc283b48549ce620000000000000000000000000000000019b8ce1c1ec36df8324f227ee01a97494b8430d720c155d49f4121f46375085ced8295590c3c96efc812f1cb5756bc1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ee0c5b50d16ae6def56c2eb47dabc74c72f84b50d1001e38e1f66d1602bd48762c65cf7f18ed17dda7fcbd9631d3b200000000000000000000000000000000143e3dea2fe77a259f194eb318b252061365830a5424fbf60abc3a4ddee072c3016b7d0db76fcf24439f31c1359cd3691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157f226d40743bda60d90addcab85fe41be1879192fcda3cc28cf41c452026af8781ebc84d39866f96bffa4fabf238920000000000000000000000000000000018add4dc60856e3c65b6701f85e3de3f906e585151876d02fbe5edcb9e03ca5e5a9a8ec6570da68bceca21574ad1cc6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e37282fa13ff000c5db0eac966468988c823e82465cdefa700cccf3f6c058f5e8a4cb3f5a2a2bfc3ed0a480d562226e0000000000000000000000000000000001f71a4cae9a416c6dfa0eb43d42bf2017db82f94f0dcb7cf43f044a7815b66f5f21fa2eda37f7d0900b5155a1f25dfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a27ac4ed6b63cc4edec30f3df4874ac1eaa5fac2d28dcbd8dc8a85ef79d11101e369ac8b2d821fc14877cac1e50826c0000000000000000000000000000000001124b42b00ef786d5ed515165319f83644e7643cb0c4d765e82c216460f516da83bbfe4dce5ac047145fb931327f8011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bff757740446e9dd061cf31403623fcc0fc5d36233cae36f5f9fb237c6b33350bb32199b4240e4a5a7d2992774f3e7500000000000000000000000000000000056be9bdb9bb8ef5c12411a3ea930c693a691fc171d2f363f8ea38f645aff98a892575a28d8b820b20ff6148ae79a8431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000135ea73760db39bc0c28dec2c3ee42008b75617bf3517f48ecae338a2c28e666f7cb421d5b2b40c9933ba5998bf04ede000000000000000000000000000000001140bfb083fa54e9f8783b4f94afb95daa87b43d4e228d3d1dcc02af8e54bb89225c0cf779c6f2043e45cfe4746020c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001738c3d4a273523a0646b3017a030eb25e5d8ac5181fe006b67309981f2ad4c42c50b3a9a268fbdc99136d82f2827c5d0000000000000000000000000000000019c1ccfe1cacdba083eb2c6508a4323e461339e8e9c5ed69e7d419fe3aea6f5ef0615a9d579873b9b96653dc5a7ac79e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157fa6a78fe1d801418857cc0c4cac470b3d817ab09b57ee5e9b15cd80c31e672f697e9ff051984db2696a6bb38515cf00000000000000000000000000000000130b697a63ee88848063fd5f85eacba15726ac0e5bbe0585677390c39cefd05a1a3560b7e2939bd3c5d99b2e5bf1cbe91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfd68e1a744f568c5db97036b512cba89397e771124fdcb550ade4d88ff261e4ebafa62fb7bb93ffd29a5a78740ae8d0000000000000000000000000000000006674b7550ad80e3d208bc588457c152aa676181be8824e0f502788950d04dc6f97d4520f5f08329192259fa7acb7f9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001229f08d29ec0eff8364f06203bbdb1ace0518f67b548edfc9b9a6903aed94bd8e4e5ec29c9dbb2542250559ce35ebcf0000000000000000000000000000000008bbe8703842463d2ae5064e4747de36050273e63a750b8b3aa7ab3b205bebff541204747d1de0db4678e68d13a4f94c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016bd214cd9be24b856fc8d0abed768bdac48eb19bdc609ec5d8a00165f425878c937afaecc42daf387c52a5a1d04d5f7000000000000000000000000000000000cd6530f58a361c7114cd34f02b39fe0e9e1b19c6704fddc99d42bb64b48b5a6525e759035297021b3438d7628f84a7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a95a40195f2bde6cae58a570987c7f50f712f90498b503cb61c65b67d04ad2e75a0a7460107d032a47f1df302164ce40000000000000000000000000000000006fb856e55f6adfebf759d1f40fe92cb55ff9458057dcc05149aa36277c3477aa288a29d71dd33cce5b916c5d60433ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b6bbf521cda75970d8937f96803018971a62a63eff8e536958fd805d68148f284317ddba2747a6c741190e37cdb4610000000000000000000000000000000010807b802e69a45689960cefe34627ed89291a1822581dccafe90f14dad2697db3fe4d7361697ea8e76bace1e959af0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f3c7c796dc6156da8a582494d70bd6d1e7f8927fdb52fd4c64a2aa0d63e91bd48d25b8ddfc63f48c6ad84d43ea9fa60000000000000000000000000000000015d886c557b490a7d609b38f9306af6c3f63bf97e90f310db4f25b4d90ccb4cc75792884bd9e6ebcc59144c5ecf9a5661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153915b5af6df4fc70297f410829fb9de7fb44312313662d45df144e270282f1a3f04f44ab6989ed87233d14729478a100000000000000000000000000000000176a24a6ad50ada0db8c5e22678911ee304490e2c1ef49aae3246dd2f6798916d056d970dc57ed0af6ab74235002fccf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004234d99c52e030df56d1e0996b1b9609377b10b82e42de5f7e98b176384f5d2a6211688fdd0505b4fae0a9085a198a5000000000000000000000000000000000f1deb0d205f3c553de4cb19ad7385a8ec5666cb50d41b3ff5f35c4c4b682a0ec14913d34fbe7b31312f62cd3c8ee5351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042f960a0e70adc0edc14e5ff4acfe32d98465f8bf4c79a95dd3fcb3d83f758c69b50b4f6e8434bb2525740a4af6eaac0000000000000000000000000000000003a195f39529bf68ff1a84b81b89ac4c624ea4f8a84a001704419e4efd699ba0e8bcd4428bcae5770c13eb25fe74757d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000965927620ffeb7745396798aeb67c85fc5858c135f3bcac80b9c99b739564f0b823eaa1e680d32a63da702e26b2b1e90000000000000000000000000000000010a9086cf5666c8054774baba649981c4239eba8966fac97b13f870b486050145339c7f42830baabe3b9cdbf57bed9b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000839d6fa2c972575b980f10c14f6effc5370bb4e4b9f2ef01447530fc89684e4f81b83c33469a0451011cfb8eb9d9c360000000000000000000000000000000013e83db9237dac1110bb449217a3ac45998eda8742884ec4c3d40a1dee610c15ec2b492086cf04edf540e6ae1928476a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f40f2f0fe706b9cba8beff3fbfbbeb74057377f881df252000ffc017b5ed898a81874a41e68917c841add1421b42620000000000000000000000000000000007668b0ec8861c3785ba955dbe46bbeab9c4b276676dc22dd83a126c78b49cc37e4abe79ebd5bde88bf97aaac3c605531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097608d73c5553ec354fe559a1fc0a91c5eda7fbc2847f288604004de7c195a2d49e45196ca2d41459fc8c086aee3ab5000000000000000000000000000000001956454bec3ab6e32cb6735897118eae4f2805444bf4fc65421ef3239ae42211930a371d88e130fa4076e33bd13f29061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001792666461e081e0fd1e7d598aaf0eee51974ad3cf07298a4886f4338c72f799f3ffae497a4703e5de140c70a1b06db2000000000000000000000000000000000c61d67968f80c1c53d7c0ee639c8726b5a2b410a862892152c211350ea6c4655247ac97130f02dcdb2228bea2969eb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105f4538a759a7936de7d933d1454995ad27c195877cd66aae6517ae5890b05ac08401178183bf8a051b83975cd817a00000000000000000000000000000000008c84dec52ea2f91f132277f915405eb6273e7a81ef231c360ea50e261c20feae382d15b1e79db67a8118dfb00fbdbd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004870fd12576639ee504d6c4673ed85de343b868984b396e7dbba0d69df0367b009c369c61f538873dfec56c8303246d000000000000000000000000000000000b65148dfa906ce7647ab5192b2465ba65d74be067b3aac590eefa592e1d4048ddd4b1c7bb8f5331a66fb714d92237bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c566b92ef5d9ef0f33aa14caac5452ffe5abb6592694fee382cac4788eb1ba7acd8ef8ab8ea371aa404cdd8f6ab8a700000000000000000000000000000000095f8978de0ef3286744726e8df26c1dfdab944d49f0908e72d94ce1eff05e452517cf5bd8ca7258fa4782769ca12ee31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebc3f4b274b637c1e2474a02e8b195020f3e9a7677f90f97c3c0254df02852be5ed7c295073c714ec8d85fb11b6dbc700000000000000000000000000000000135fa897779c0a1e417f6d1af81128b61d13360de57cd91b3e69bd7f7ae34d7277bed74f48107fa30b5b01d86178df7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b3de655a2500695eaa7812050a62dd71ba205e5d08beff1c2288106952b4baa5dbae65dfd9bc6f645a23598fed7849000000000000000000000000000000000d125743535fe4e55f1893a2e689f9db0adde3b3d26c1554768e08ef204ad60712d0de731ca9d65e81ebc96ddd1dda7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000931c0d5e2dcb9c2508031e6b8a4d1dab91cddf52f31a0a019401b67e4076fa77d5c0e030d7bbf67ac4b1abd93c4fd8800000000000000000000000000000000023fbfbf22e7fe29fa87e616207ee147cd1247da42b7d749d9ba5f855065b2ca1a5c84c07a50ad4e962fd8ab2c7c1b001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001908d4ddef4b4dc7bc59dff3828fe404d3f568b7c90e4c88a90bcb0559084140a6b5f8b97a5fe9dfe5458f9e8aae489e000000000000000000000000000000000f14a1f8d6908686123fc359fe3a7c4a6a9eb15c9b3b720aaf88fb1156d4c6979c458dcbe60b398c85c18b9cded894601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e5531cfc3affa1543bb07b55d86bdaf3af5f9a23c3e535c108c049dc70469edb231685757fdd6209d66919bea0e30e00000000000000000000000000000000066167310bedfaaf277bf07b9602301af885c089ff5fcba210a7123cbaad0f13f73121f1b4b7f049b8fe1f57535609541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018336035871f1c8afb338ffe9efe254cf76e66fddea963aa6cfc248a3b81de6247f97aa21c67d541bf4d1c0ad5d4357900000000000000000000000000000000046720f87817331fe3472d94dd931aa6321876556f060feb8d1271448d851957b10d4d2f1167defbc943bdf2a75a24781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f6892eb08c8e1380b57c191dd02f363b7a967c82cc18de1130d95d727d0b7ab2c4cff0e87eecb7cee45481bb794c2e000000000000000000000000000000001100c1ea6f96b4399030d434201fd4d2d6ddb9bdb48072c3747ab12bbcd5db4c88c3b3b34a13d5124def604439a3a19b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf308fb63727f155b74353721915d8008db2e2173b06b849dc83d913565a4c70a166f04cb08e0d7537c164817654bf1000000000000000000000000000000001261acd51ba3bb478cf6fbb9cebb37c5c66b88b4b8f2f63fa84c19ab034d44e1620d7dfed65fc550f7cd5442ad5ab4ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199a087a02d6fbbac39c30857942b2f619e52a68a000902a0b98c7a63be05e250ca68b2f7832bab7ec473b3778d790b2000000000000000000000000000000000c58593b99a936f3380c7773147f1de50646e61ac1156e39a1a9119447dc1b07d9ad8c3f48502b5ecc36f3037f2bf1801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009db68fbdca3bf8ad2a98bf9b9e45cd91b7e33ca7026b92eec2afa3eaf796cae96e47b028867934ad6debbbdb6bfe43800000000000000000000000000000000078c204bec8e809e36bda95277f9c6ab9c88d85f2c7045a741f45e972daded1ace83597e83f180b3899157208ce532a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f6301286bc3e529f92db82914d20c5d23fe12c6d59bb430855c3f306e42c5c92b14e68c180970caed697facd639eeb00000000000000000000000000000000107414cdf846216fc126900da3425ef179439cfd27188533bc8b57eb12d05033e488b55a1acc684f689149f164ea07d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134b259fa35323ddb6c4d8bfee81a82862386951056db9da4f5d501235679615f3d696916c12999078195d3b3f7ce3eb0000000000000000000000000000000008b5583c138079ee82b1bad6336bd93be979bbb6f9f9d3fdf529ef3335eaadbbcbc95c6b4b43708d2890ea4841e453701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000846819214c21d4ec375035d91ac6312d11ca71a740d904505bbeb2c93e56085312a0e7c8c1873d86f54decede55b5f20000000000000000000000000000000000e7971c24d4ac0579c67178b117af8865eae68a9098e54dc2230ade0be16d95203a2b8a648213b6460063bbc3bae3e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002b62fb779ae877823caeb1cedd026aca46a202d00745d5b4466382c9aef9deace93a269c8b9eed2e33e253cd99f69c000000000000000000000000000000000baf8e93b562ea911db32eebc7881d8a38e92638d058135b0ae49cfa54115c1d141c9c61604e16e18bd88b18b2423cef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067619719b934e00fc5544d387412dce58c1d0fe8c17a8daf091db354e9982ea2c03c94b287abe3ffa80668ef38ed05f000000000000000000000000000000000aa033fe3a2096e3632102d98195821635caee580a0138d113db1cc2b50c64a35f3e9c57c851d51a1722184f41fb8d671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077fcd409736ab10abce17d3666fcef33902c5004cc0292fad126b338c35e3f57bdeb7f32ad3822bf2fd167fcd7aa5ea000000000000000000000000000000001561962667a7f38c322c5b409702e481e528351bfe4d4a2e10e9e1a693cd0855d5d305c4527fa067b4f010cb4a47f1081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d4e739c363ff1ca9d73ec8736fe24dbbd1462d8b41d632502b2704e6cfb28405d3f440a05abc9fee7245eb4a3b51a9000000000000000000000000000000000d77c01323193071bb8bb0d65f180978fe3bf475c0b938b97848d20dd42627cb653626568bd732c673e66be14d085c4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000096382f11181625eb1ae8bd79357fdef53290037824d86d288ebbc93f6a526291d72c8bb6104958d075992d7210d0cb4000000000000000000000000000000000f83530da3fa6554b00144012f6027b80adf20b15e48a8fe2805b82574b2c2194daec8c477c396f65f4300d2cb72b3311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7e1520804099b399bde36d9b79377059d3e7f02be46570d225d73ab69bd76ecaa7618fa6d72bf284fcbf924af4cf5f0000000000000000000000000000000018142fcc466d3bf2ee8a1efa16e7727b71f3336b1fe3b1a93d525fdf8a0a6ee34e18ac3dc0efb7af7ac88d4af4fc75da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b31ca726810fbf53187693003b3951bb9c448d06dcf8a7dbb120d8d436b44476a02c2ce887efa1f9065410c9eada0b30000000000000000000000000000000005e5ed64149e246646e38d83f2e2fa6b692971b19d806aeffae6168e12f900877be6784b31ac67434188c8d30967fcac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d7ee0d3e07177ff1a3f939b472df1a0aa253c1463207f52a29bef30435c7789f5fe22c68156e74b8883f4587dd30c500000000000000000000000000000000088512034da8012890760b2f677a60787859b4ac72682879886c8de0942edd5eb63f1a6e4718181fec1e8ea25533aec61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb2d4f38563d5fb23b5b33f95fcea1f11f9b353424f5893d078432057fdcb73b561f6752efe5e92699e529f3cbb3665000000000000000000000000000000000aee0ec4363d8143bce9a8537e82c123e61027510bca53169600ae56d678fd6e513394d5b34a77c8959f301b94885ca31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001388fd6fe3b7907b01e49635fce4dfe3bfb05df8debbc8c5af9df86bb5dc16cd9c8c35b3184f0d193595f68a9a11de8b000000000000000000000000000000000ac7f2620a45dc80aa5af926587b0655ec882966585aeae87889aedc98a1a33f9dbb483a6add415e0784f452edbcaccf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004da92224cfa217420deacf8d427aa1d3e6268348a6ac0d23d4534e4c7f4d490743a965a94d8c7cfc7ba205488a27fd600000000000000000000000000000000145904a450258729a7c419c0d2e01bebc4421d59ab0baa9f20d62bae0160c9c1afd11bdaad2f3af5b910335191a2ef591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000015f95203b0f1e4b071484d974611b0a03338801df32cf9ea00abe2500bd6dbd042fb03dda5ec5bfe3c92a0505f98eb0000000000000000000000000000000001830b29e99ec697cd279005e8646931223f0fc005d8d7e152d3281ac7f3327d3013f9b322208cedc2e0b93f404f27ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c24dcaa36d609607050f0709fa8fca40d5777cac1ee44718f485fa0c9fdc92c0a7ab163373c60c69df3712df421c680000000000000000000000000000000018be04d1326b970ab176a62d682e877aef7ac534f6d6118497989890b8ae6df80bb061e8c71ddc247d6f1f6495d8a2191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006354cd30b9bc2f762d7d2970f8bcb73b33a9731c55fae7fd115010dd69c0bed9701ab3e1430373006c0745536a898f40000000000000000000000000000000002f5b7672e352e2b519eeb81ed45a9f2fcfdeb79ade86bd3b12ef27de298c1d2b9678dd3d276f7042b7e506d4a0629211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4a0b803cfb5d042cd93f126caab2991ca65cf1743beef49f16337b951b6e7a41cd1bf72acd0578411c9327a42d698a00000000000000000000000000000000029b1a91015b17ec7fc460a55783a35a8d35af3290b71fcbf7ab753149ea68f00746bfc48791621a403aafe5756d743f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b5ef30aa8ab3caf3b1af8e01c650fa5a0e96c44924d5d06e03477aecdfd4bf343ee14687e46c9a8de744a802248b35000000000000000000000000000000000aa869d7f623a0b3e586dc3b2af48bf52bae06036d29371ff8dc6cefa610fd3df08003187840b927891b5540b8b518281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b4d1e69b69e67f09aa8b8b9b554f467ce7501527113cebc13b293dfeb9394eb198fdb9b75912421bc82bcd11a0a972000000000000000000000000000000000446d4746e255d8f81ac4df1d5a451287a791943e2187943525b2fcad4778bef92aff9e770897e9daa08be733d0b08211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001453ebcefb001ded4aee20224eeb7d84fc4a79a900faf19a0b904dce7d5de2f91d57a35265b7fa95f4c2ba7c34ba7f1300000000000000000000000000000000039f9c28346b182ba23579eab72c0150c14d61ecbc5ba5894dc2d72030175ad290268470eb235af033f1af2abb3619461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005cdd154d48fab1a248d4b46d6bb7c2263f868f5be6a0633ff7623a30757f84fe49db0b8b45a2d51cb275c229e43fe2200000000000000000000000000000000116657893a630d49fb4cfcac1fa16958ce7e12a5ddf95f3ea28b6d7a09821c3e162752924234a42587ddf7f9e85e3f0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab684885de7cd3029c7aa039fb0f27d6a4b719cc73fbb6b22c420b40c71bbc2b36b6c2456edd34a27d0e1e7934c3c7f0000000000000000000000000000000017329d5b941edd858127ff5c7349d9860087b64ed0b6f202eabacfaa0c7276aa7aeacf22df087c94cb6199a2b2e7e8351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ba130ce7ffb00c56dd5337bff14ac7433ca78d89a9dd5efda1d8e2462e8f69a0471aaf0acdb063d78b74ae4b35c634000000000000000000000000000000001190a2aba2064ac2350362ef83607db954f7d4ef3724965a5fb089eb0c6469b348bbb77ab2fb1abef660c2459abc0d611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab1ee4eec9c6e73b52dd0ce541f5b1a655ce522aa7f5ffa31a6ba65087f7975fc40769e2b3274cc1292b7a34014831e000000000000000000000000000000000a38e3a0d357d8771e0071ba95c53702bbb8a784c5bd570a30e4245977b79f1739304ae65d2938d65dcf323f15c068f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175bad86e0918127faca4391bc73077a1ab48aec2679cf3975e388e3066ee601190c9eed60868f8c419dc1256e8088a80000000000000000000000000000000000f312f01308352c5f6262dffc351ebc529bd9ef5a30d6bde7ebd58d988d4b4bcd4308a6760d3add2f93acd36be5101e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c201912ad9e4e86ccf98478cac2f211b9b9a71f27b6775e198982c8d7c4b176f284ce8d061b4799ebc6d5ec9d80ef4500000000000000000000000000000000057d3ce28b5f75bd164deb738ab3e0d5ba15b73b1fe5f3a1a33840f1bc7ecf33c0cf082f93409c9b61ee8a0f0eb757191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001673ac336c306ad0b2a705f07417fe5a3f92cd08419931b9d11595a2d173b72e823a986a85c7165415a881955e8ef76c00000000000000000000000000000000197845419c70a99d9e6859642d4cf93e15d87938cf63a56d508656bec0e6fe9b277cf1b2a9a91bed2f270aa7ade13fd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d384d645e982e4aaf5b2b9911f27c90a1782a7c1373d4869031ed39c61e0a73c4f872786cd1a60d7aedec1cb84829e000000000000000000000000000000000ab1c707a024247b54563f879b8eac6e021ebb67cf10fe451ac9343fbf61b3dfcbeb20fe7b3e2b45356efc3e601296b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008fdd1e7434bcc85444733590a911810f68b447985e29078196b0f285b32fc62cd0f3f8e0df33e367b06a8162a293dad0000000000000000000000000000000018738f903badcaaa65d4a384853e079f5fed839f7155dd81fb5d34fcd6139528f690bdafe2a3e632a7d829c08e95c8e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001004b7c2f038bf83b21ab430bb759c0a265f556214dd73895649321bb559fbb68e0a30bac78a04f16952269c23f940e700000000000000000000000000000000024d128d1047a69bf41c0ca3cf0c10cb095968c8d72a97fb3685e1f3bb848788b4f174dbe5fef7b26c48884fd40365f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001ee46624f93d2345a2181825e4e2c9f4f19439017e798b669e64fc50f71c5d7e48a1acae9b51e827638cacbc0795160000000000000000000000000000000009a4ebd9b5bb88aac9d1231eb36b0a32352482d560257f074af610c4d6de1368297cb38a0cb4ef8925d0dde389b6da3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9b4cb1eb011b931f125b3efb7602869f04e6c041a974a07411e6aca2b75ece4ad0669b500dd8e4650ddee0f104a0a50000000000000000000000000000000015ee6c929cacbd4e4f48f44fa2bbfeeae85a843cd1dd9d920a05d04e4c31f6dd4ada47523e03f8b18a5dec80872daee41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001520b1c1822fb566cbb68a1b1b42c409ff97b9237bd9383d96e9578002c72f47565396c7bd1786916d3936021137a54e0000000000000000000000000000000005f0270804748650ce51324ce0adb335a9527d7e6afb3022237656b41b83e3415c66ed128daeffa51cc9d5258825f1751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001790133643eb78f99b2325e69630a96b3b6e68bddde859e5357ef9cb7077b12139a2aab5b7805946ae08c15735456328000000000000000000000000000000000c506eba2934d1839a6d43a26bb49f3e423edc69fc1d53ff1c5169cbc2450acf96ae1a129dd434c791a61d4dbacaaacf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045715e6ebcd9a3ffcb26e702e310a9b86a38693b41f24086504a5e46ede2f06cecc53b62bb5fd637571e758bdc2b15f000000000000000000000000000000001517cbbb177218ddc22da290cda48a45e2fe9697b3cdcb7c99135bbcdee1c1df0908d02fa160a5d526af7299798c64411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000683df08172b009f344a0c09a6756b7050c8d769c663a205487396fbbe962cf97d0b2f85c117d13b3d5b8293b3d3ae8700000000000000000000000000000000093006628bd09b9a8cd681866ce7401628f1c103043958b9c4ceb4ad4f123fb4b59b60689a22720837a13ea1e49a2d6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000091f8f00c356201d81aec1d6a6c58c4033b5a7fd30e6fa5eb4d1a462eea7dc39bf679b4d80830efbb4a8a68e5f3c2260000000000000000000000000000000001bc02434a63730ef71dfc835815fca8355cbf400138a253260e72ba3c5b891b7a257070720e8137d73e6afea9a4c9501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000044358e5ce43b47a67c3e32c559bc5bc0159ea7eae087c0569f0f4eabbe21a1cf15086e9942063609ae581adf2bf5b6000000000000000000000000000000001774f16889492e6b33fa65e293ac654bf3c9d86ac6c380a7d339ed8561355cc84562f292d63ee72c292c2f45d6a6d34d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d5474c7f6fde44b420745f0db077d49d91fd8da065eab81d203073487dec28d508c3977d80f6452eb8829378d1c5f4000000000000000000000000000000000c97cb79ce73e7d784a14327f12e3078e1957d2013b3b9ece239769e5950e4cf1a7d25deb7d6dc77d2a40316fbda63221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000104d5c73a631bff7a935f75fab6a72cd57d2f924ce6f71e4511516683c026ad3ad89d6ac0ede9635820d59dfbfb291e40000000000000000000000000000000006fd052e0abd6384806f26909edd0b310f82cacf4d1e0b53ce2b45501f2f42d425f1c2282b1b658f0419399b9f6d1cca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000134d33c54d8590bba2e3981fb141c9ff6e52df9cecf52062ccd1e12d90c4f0f57ba62cf37e6a185af9c06aa60daf6310000000000000000000000000000000019c9a35b2d94a9a2243705a91526b05e68e3ed170c39261ac9619cae636621c0243497e41cc5bdc7ec4c3c4a136738b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015550b9dd6068a759434b6a097739048d33500f3a4857c537e86635dcb80819b640464f726b8b0dc2bcfcf8d7dbd6bc2000000000000000000000000000000000c2ee1ce1ded97c69da4840b52283e533aab896d86a62f8d12fe086c620fd76033cef213bbc681fa810e30c382d049f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c19bcecd287d6ceb9e74feba5cf9286f25d7920215ddf8e81d56abb35ac93a0d0f8a8cc40661bd92df2391d1749ea00000000000000000000000000000000012408ef5bcc98d3ad62132a7dfaf037f4456f0b37ad8b983ae9d390e1844fbfcef0611ecfe3c805b94e443b90e658d6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011553fe18ce7e629a30d5961763fb174ef5c86b00640ba0d586014b3cbe2fa70a4ac69483e9b7fd1da21920f1086424a0000000000000000000000000000000001d0c17b1900cf9f14051cff77d8e7a0b701eb2c27b92bef8a4358a1157de170e5ca581e0b601bbf9b4b2b9090b6a5091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174dbb27a1cc96819265c3d885f59bca5604ffb9071463c1ac1b3515b749860aac285b8eb9db11d6d06303b689506f3600000000000000000000000000000000175c6133ad5484dccde28512dfbbea740b7a19f5b95fb47f013869fcfe6e376cae83481f71db906d336dcdb6dff9caa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f319c933b1a32be988a9cb672a0d8fabb357f1ff6d24d23935e2e63785def45ac84b5d68e4da507938d0aa9c9b5d120000000000000000000000000000000018f64b379735cdfb045ae4111fdc9575c086c8dcb289d9481521b0f1a7264bc9aa0065c8087cdeb89924b6d0f9e8dfc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182e62382160884974e94dfb13bf34bf19cd7a4864166b8d8f90df41d8b94158397d47a776317436d3fcfbd47b24e8b1000000000000000000000000000000001652fa3db52102e772c590727a46fa7af51009d7640f3d512f84960ffa2d41ec2b3488947e35dbfe08c6291fd3e7ede41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066c1a2e39bf78c4428bd007aa37a37bb10431d32f5635e23646ce81a2b230030ea70db94e1ff7f43b0f11b3a0888523000000000000000000000000000000000a7a04b7d5944dde588bdc478cf6d22759bbb61ea56397e729b0c436a039054af9fbe99d2ab34843a6eb933527362edc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000011e06290461b06a4d1bde45c3f91f85460e2501ff7ec4222b4b0f328fd76e9e37285411ab2dcf32fd7532e5e9ef6602000000000000000000000000000000000f1ef0eab341cf4114c130242cf57e6ce95988eee3982a86f3c09c635ccd155bb6b94dd4b30df7e5ed7bf4c9fc1c062a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010350dd168fde3225cf7406d643d7a26bdfc3da68ac490e1932dfbfb8b2738e9f96712611f34319126512ebcbe5af8ce000000000000000000000000000000000d5c2df7cb88fccf3e60e9c87fe41582225e85704f817deca73088bc7d92c56c69d71d8e00619079579a585dd45d820e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016307cc7e923dd4401f42c99a8ebadedaa7b7a290566c677c3b5904f2896d2736fa65d5d1126fe9e7996fee91d7578a40000000000000000000000000000000002a57ede35b9d45974646a1f66683de1b471ef33d891422491877a0501fe14110ec187400626cccc062ba226d4e59c221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cbaecab51f99d705410f9f0594eb3707768ffa072a03c81d6c165243b0711f75f409e86370a00d6ca56b196c321a6a000000000000000000000000000000000b60154fa3aec3b0449b0574442f66684f49caec95b637313d0e9dd528f549f9f23abbaec4be0ffa3589844c4d05b7091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001030eecaf6615777c9aff309299dfaaea3b286a95cb10374c5ef234131bdc8bfa4d7d0378558e226c0f7df1b7530f0f0000000000000000000000000000000001202ea63e2db63031647c7b66aec33f40aef6603d01a85297ec9a3e0c0bb984b9d8903079afcace48642d6412c0a156b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a0ae8edc0ed8d5642267013d843aaf5789a279f462c69889af47cf0b20b31195e14d538ee3f831b2d4ebc24e0ac9c200000000000000000000000000000000072d019bc43c69c331b5d3c35e984309f9550f66032114211fb40e6bdf51a7e8ef0ecdb52c898dc8ed7842120cb5512b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000754061724865567b0654afcd38bb4c35e2c7e8868288ae794f3a0c2928c847df0451c18ceadedf1bd46cc31163df70e0000000000000000000000000000000005504f200d230e1140c53fc53b60d96302371eedbc07356d613fd9386cb3747873aec2725fdeb855b481f5c2d9fe3a031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f62f5c773b8261d192194efd3ed7d2731d629bf10986a4e57a842e0d0774e6236c0e238d6df9c02d7fe31f291d5d280000000000000000000000000000000007937a960e332e92ed5ca985f4de66d75bc32a7edbbc560c9a1efd60d5e3f52848aa938590d5a29dc3304da1066ed6ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000519a249d9ae62103ee47f3275d0ead14142c8be0578d013c04471d898d52ac84a18e43c955592c2e74820f8facf42d90000000000000000000000000000000019afc23d1174f4ede9d34cb987ce79ca0c91fecf3db835c5b2e43f90bc8b84406746293c352d8a728fc7e849d7e4069b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044bea11376ea3322d194133237bae05dcc3f2ec7cbbef78949f1c34bf99a7f85266114d873ca2b929ea765a99c3eabe000000000000000000000000000000000abb75c79f7271c368d8fdf2f295786c81fcaab5c112def778636a1bf58e1d36e27007522c86dce0b0608aade192a7361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001259eb1e3d111422891cad5b506f6bcbb580505694ab8b2cde79144eb72d51b2736381ca2dc4624b4f3a5d7ef641602a000000000000000000000000000000001536e2a0bfa5a5fdbbdd6f454cc4156aad62a948f5b7874ebab9aa19be41b7c5581921698e90978f8b04221b2bb786591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a2a344bb24d32b96ceae594d566a732b142db7c3b3e35013d94dc142e355cce06c6ce33cbf554928b885a1cb623dcd00000000000000000000000000000000031233c6ebc36668fadbf7ee71083bb25b3cdc8fa93259bf486885450e80a0008e84527a9f6c3d93eed16a64d1e495a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b5979a9181ab84a4ccfc97b4ba9b77a423588e489a5b547ebc6e82b5af63bf4fe8c25ff977027f68688ae3b27001350000000000000000000000000000000018ba91529c4e3c5e60433548b9463abd07ab47c99060d68ef42b6c0ed3f96cf508293f588f563fe194c9ee96426e68f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134e5cba303d3363dc1105a344b733955745c9ea2ecde95c2b769fd69ad6f03970df2ffb222bf6b130761330761464cf0000000000000000000000000000000008a408a8da834baa9d903a4c96430828f6cfd7700c26f7b65d22fdb17edfe6c132819abed47d75302f88bb871504f55e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ab7f137dbd16ac75f652136366d7706d4bb89bad22ab4b9d64b8a78fee4f308a3862e6e95ba386057ed359e07113a70000000000000000000000000000000016aace40c10a2e3c42a6ca49fc19c81b8a6a44c5e9a51ac1b5590581ea3fe86e8b5398cc1a8b2bb03f2d791eef8358d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2b3cf4ecd2868551755018a478976208f4984fca01bd18d2a4d4a6f9a7ecfbfb0b89ac777835eed768681b8457e06e0000000000000000000000000000000001c2c5cf4e13221b4f172113c6622ba06147d01b0dfe566268ba77951e0a781ab1cd2b34bd00dd89e0d9fa8d390559ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018feb4ba0b489565cf530a1812461c11dd6a619bc3b0b82da4c1d0424aef83ffc2a9ba059f19d5f7605f6a45d5c26c0d0000000000000000000000000000000009e541f7587347d6f617a7ce72f541402de1510b9cd5840c615db05ea100f4153de8d1f836076dd2829e439b65453ff01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba97c329643a9b1c6d38452439ca35f1cd73f268ab9b5a763d89ae3889090340a65e3d47a408092baed69232f188115000000000000000000000000000000000d5951abed7ce6bd57ca5548a8f293c459500cae7a69c7bdc141a244e5aa57dc35d4e36ee5087959bd9a8ea03eedee9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f720f052b0311e03dd5f3aaa8cf9400b16f73df081de05232053934dfb94de6562744f5b8ffc83891f0e74b5c4769b000000000000000000000000000000000494e8bf92f523dc1c1186c22a7d9efa85b808746fafd979814e0f050f014f29c323a0e1cb7781ead6fc23a780b14e701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009eab960c0257a3a9ebd97f692dcd2edb5a696604e2e409dde5678aca3432a273e25e790d69b5060e62c5c5a0c6d23c90000000000000000000000000000000016d2e8719b80d218d257e2dc50ba40a5e6a2bae3c864c88cc22ca731fe306a833c0941e8c515a9af9af8b60a96b5b0001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fff55cb452bf4b29a181e05fc4a549760bc6db7d1f95bbd92013ec506949f69a0512787ef535e0de4ea39af048011630000000000000000000000000000000015d87751a0f392f35f15d536ed960eafff49a5b377287d250e8dbfb54953f81ea80d3c4ef9dc18fece8070887ac93a521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013409257cb8c5706fd72c0a3f54f01f18f52d5d7ce32329c4ec69f91f77b266b9e991acfe6c09c1be13292c9c4619104000000000000000000000000000000001256fb5641dfa056c1543f4210ac1bc71045769e28139c8ea0c2e34b5c9af2f2ceb762b6d743b7ece9bae959796becb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d9cec304c65798b07a0565e37031985a20e35fdad3de06e63b8349f90e560aee6807c70626729a8ce07de14030141400000000000000000000000000000000086f816cffc993d27d99cb9e38049224acb3f3265454e3acd4a59cc1be08fc748654b109c74c26277a6d1adaa45d4dba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001949f8c3006a9fd1b38562af028b3988d9196fbf138a08761a5996c9f78cd04d98881fe04e31a1211e9af008d3d966f0000000000000000000000000000000009a9b17ff34f25b08fdd7649149101616d806be021a0ef2caaf0f444baba6ed1911d1f228092e44195a16330d7cb1a801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001862718460302f9bfb1f0ee4bfd7aed66d8b42dce4a1947328c9285987da79cb75a66a0fea0e52886fc3c2109fd8e3140000000000000000000000000000000018556cbe768fc7bef3764cdef9d1448b96d14c295b61fba924891792059a4bc2d2ebf9af5f16ce001344d788d2d1fa511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff9f8c53fa684ff07ed321549d7313c343da213ab816045432c34037b9a60c842d04e432675f40c06845b335b491e760000000000000000000000000000000008bc95295d3e64f4652652f6cdcdd2ed7fab894dc3ffc44bdda7239a42f0793f445bedef930b556db2fe4fde00f703611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f6909454c928812eeebe5d769ebe70e4cc34a3e9101476a8015ada1551467cc3ddb0dce463fd288546839cc136124b000000000000000000000000000000001431ea74c09a8e0b688766e1a4ab78ef88d34ac37187dc98bb5479761f0de4076d3872d29c3474b602791b5404ed95ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8bac8d09538b05b92c7ac2e72890884d57fa9bab00294eb06104b1abea03cf924c478b2ec62471c99a6059f29c6a4b0000000000000000000000000000000016c6ae2c8be6a2621365d08971076ef450ccc5cf2eb76c67fc951d8d885373ce27fb9a27d70b7d67899558866a99fcf11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc80f8038c6af3bb8d0f31e89c2efc2b7b15f5437cc72053418ac49ba0c2a73669d9f2e05e60ea5ed91e6cd0374e74b0000000000000000000000000000000000bc5e28a49af3fa995cf68bf0b557ef7a38274e4ae2ca52bd684950dd9b2a263502d2e3257f7a9a86e243e22914fac51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097b950382ebbaf99b261e0703a4406ad156db535b991b099f546aaadf8fc20161edb8ccffb3cb02574cd2343334625c00000000000000000000000000000000187b1a57453d8a977af44987b99dfbec678d72777219be86c9564ee3b53c8d54310bfd807aa10612d23417862128d8c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b2f5d961a328aae62cfc82b4003c5332d9ef0e3227c07b6f373ba066529785b3e2d4165f5cd97554ddef8294e873530000000000000000000000000000000014a1848d2a311ea29d462f55bbe85f1f56417164d9e05f01219a3df02fcbd654240a0f1b43e7053ea89c477c4128409b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199037c6899c293b728cdd6e9e10f4ccbc8bb17c1c1377ab0877bc85b6f8891b4e6a746a167c9831d46881ba786abdbd000000000000000000000000000000000f320f07e1854612de8a3ceac12529de519f49a05ddcecd8662b9e1686d52bdced8309ab2d78d47268c99df37a3cc4c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e130955d9360bf0aafceea50cf3b4528db8017641e66c312b588d4ac58043570c01b778bc5ad65f907bc8b642881630000000000000000000000000000000011a6c4edb3e9c53922d7ca35fd3a6ddd8c80effc7bd0ed3f6f0ede8c33b246fb771ec61e8cad29b52bd9ccaab892a30e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052d83bad3ccd6ca92ec559bb270ccc727333e9f3dffa0be2f9042ec8bd9045ff024b20f855e027c4be1e2cf71032a0b000000000000000000000000000000001074fde56849ce5fb412997d89d49776af8f489824107a616a796a124043e9b6794d268788dcc3af9bcb7ec5e54d138c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001cc9b6a53f2f28aff549e3b0b8c2ca7fa2ddc62c0c59c01ebced96c13363479c279eea9a0347c40271dc3ac50781985000000000000000000000000000000000b6dc2dbaec24ba15d0996b006d651fe0d92e57a23f6b14f74a4b57eff95f9c10e382a84f4c69ed8a9e6ff6fff85e6011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036c2673f85e74b094adb61bf4ddd2b930d9c4d85dfe4344329252e7d7524790a056f432349ec6e6c6ad05bde1f7ff980000000000000000000000000000000010cf06e825dec655a2ad4ca87dfc550ed9d046049e7e662287558cfd04ced49833cb95e9aa08b0842dfe79e97436c5511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000699b97289001080373f0d6386d7da6bfda67ac3c63ae2572d0747ca1db42e946ac4bace449570a1e15987d6c5759ac0000000000000000000000000000000000d02702a5f7d67391a35a690413a074e1da491ff09b831d170e4801e1d5ebda34b6997342f7f13814b53817254cbd4d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139d55fc7b72e4e916369a1a897916289c3d375b25f98029eca0d6423bcdbcae31d45dc0fe0de8ec3b1cb594430d720700000000000000000000000000000000115629efc9227ba89a95948c962392d7044ca8f04836c433cc1761bd0517afbddf3b1b4e79369ef66c3ff9ff358640651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017bbc4098ce17d750cc954bc3e388d91ba41dacf61908cfe851135c1758fec5552acef94cee7d046a4eb418d3c75c0cc000000000000000000000000000000001586056abaa810b260424df3f385386ab6f8672822bb4dfbd01a7999a231250767f8dfd8f4908aa1420565b196bee4c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000223fd420bf152788af499ca9163a2c10c0a88b2985c9604da0550438065d99a98a080b618d58e9759aabd9f75e5cd65000000000000000000000000000000000b3a9fc09ad2428ae0e6147921d508ba10c5573415c39b578b13de4d0535ddd4c06704f4a7c95342eebecc10739aa7701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e085d117460eecfaaafbe4ef27c29aefb8aff9840daa207379d7c7c3d4a2b9f4756153035ffc4555261f9cec56cfa60000000000000000000000000000000008dcead8bf5d8888ca814215ce50fcd81421ef661711fb318dcbd2252b009767079bdcb074a4684533d512886f5d94731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001424effafd8c24a9d2d3dd282457b6c79653dadd7285f3ef7952e7965020c68434f54deea81f7cb6eb69528a435128720000000000000000000000000000000013ea60f289f6c5a6e593d2634b8edb22a97193cddf026e459beb96a366df07f64594e0e3a2469c114635d34b9b920a461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033c05956d9d47f6773eeb4bd0d8401c11c6dc2d4ab0a257347f8f8f47313c8f498f1145c284ba785282987e12075e610000000000000000000000000000000007d77b93a2a018a9c1644fb60d9d56e6dfc73d9048b93afde7900773b0e7c490704079c493270c6306969b5a7cb0676f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c92df4fbc3dfddcd3fe91a5b964765fdbd57b5359de078e2901cf8203eb01cf68a25e18180ff17ceaf00de7587fcd8000000000000000000000000000000000204361a3f72101dd1a82a78d74fd8120b3c9c85e25676b1e0179cbeeffd3341bd9c23a7dffb95ab574bb1952c0f72981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b0a4c42bc8463e5c99d464900e05c1aba594152197b732e3669b2b98819b682ddbdc79d6bdee56e678e0c2ac1e658a000000000000000000000000000000001450e99c30418fdd3ab051d355f295ab55da37ac3b1e0b817608503a0aab370425806690d3bcb97db179c6fe89b17bc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6a3f4f871182dbbbc5e40f3619f4933d17e4178aa74b72c241a880958c886f830ef35799041424949e86aa5f3a805400000000000000000000000000000000139de4f3f5b4deb8653a476c5904587d0f9bd72139a50b7027ac0824e20ce001585ac799e1d126f62a150a00a2fa731a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136da9bad883290e409cd6ecafb62f7206f68fa3cfa8586824cbd9e4cd6706298ed126e5860b7eb36155474596c352f5000000000000000000000000000000000ecde7140870a35df40a936351d74bb9a7c17933fd842638d44c378cddf7cd0ba8e447048d8f533eea439fc27ec1b0e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a75742112f08be82286f14eb0ac44135e80e2ee2d343d7b2fdbd414eb265ee4732dd218ee0c5271c6443edb48a95d600000000000000000000000000000000018663bf79f5be19540ca3f6134392462973aa92483b10b78f5bcb1377180c768a4016a7ee6ca5081daeff402e2a19df11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4a3d5c23da8b18675326f625c8555b8a63216b7a58b015cf12f0f9520385b01ea7af90c360845491f0f31be33e96530000000000000000000000000000000004d13ba2fdddf20f2f457d917c0bf8b7f144e7c6e1234259757f175008bf7e2807c62bf8364127cb017524a038d9199d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bff3f429ab382c5f77a0f18b6540855e046d7ffe99ac42c5f777a1ad1748a9c0b92941ddae8b651e4f0bbb6df441496000000000000000000000000000000001922e039d95ac0175b2fe4aead5593a1adbc096ec37a9aa9de1468f9eed032d74a7908444731a0f68b84fa96d71e24d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000807fc6f852669f1e20c697c6ba7a6be972b2d2edaf37640b5f7e0eaaa15e5548cba6580f757155b43544370ed523cb400000000000000000000000000000000055a7201055761682f962eb49387346b60365381adbdcaabe0832af039d16120eec5f9691a795b5b80cbd99d0dff67fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103152a3774d38f9ff9c5ea039914df2ba77be06e01cc646a8c9e4859d240f70d70ed8bb0394df0deec45a665cd73eec0000000000000000000000000000000000e2a932c2974e9cc4db2183bdb2e9508866d749e3bd214583ca7873845399d6038b95bb39cdadf99d39d2cba76ca7d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000707143fa6336fc4f92f0b722319ca7c6292ed962391a9d79a6ccbacad3316df9d9677ab16a21cb7702701427a2899a40000000000000000000000000000000009be48caae2b58d288324b70c4c17da302f8e3b2896bfd864a97f83122f8863ac10252bdd81e8e5eba3ad831903e99c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e6ab2e31494d0804a7703d844de6ea4f83ca4d3c0f17804172bc79a226f1220ae118f0b6aaf2e2ceb985a39d210696000000000000000000000000000000001409897b3ae4f2dac17a321c45c7eee1e787348e01f5408c320ac674977107d04fd298d649c9c24b5909b94f3bc7ed211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e922ef3b61546587cf2b8d72d5ace79d09c39882e9fddfbb028fa2e50c746fc310be6c1fa709441c3267f7880e865aa0000000000000000000000000000000018f92b1cd76a5c146e651a60676b776a30b702f4fc0071d1f07d3be8ad07a3c9b44cf60aea5cbc1bf4d1660273ec3e251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c88cc0376be4de2d5813eec54bdaa3f4b674e29e76beee06c152cdde87b73f94d4f029654c80e6620f44665036bc8800000000000000000000000000000000189df77417243b30a8ee53fe6596840237ce7f1a452076ba30717af727a5efdc36fede12ee51482a484cc63d7688b4c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005738835c100d4bf2bd5dee5ef730d4c2539e041b696a9d612e54dafdba9d8b03e1ba22bc52879d15adc03fdd2a9a86000000000000000000000000000000000118879b5be0ef3d7c5783b22dc21f7ebea149bc46ee3401c1e030afa6565d1b15293ac420073796abc3921cc432a5d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014916e0b677b6dd38794d50c516b0eefd630759b6ba60ed52cd46d0f6f6a5040a4b012f53da723b83fd3f6f315bc46a4000000000000000000000000000000000bd104283d7df4227bd76901d02d7c24d8594ea40bdda0522a5a027ff1a97e6ee5e2cf4a1c2f7ba92740f29ce915aaf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017577ceec48b7c761e9bc2ef23475459086743e419c60dcd245f6f96e4210b3e419cd83525c283b0a4740464f4bec43000000000000000000000000000000000d128c33f50a4dc74e847b2e143a9a920e72eabc96d5124a6802585bd4f67f5cecdaea1a393c2eef2ad8bdb4a52bcb8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001254055caa9e7df6e74e370816e3d5f171410bee1b2e063281ccfd5cdea8594cf351d4533419cc86c814c4b22fdbc9b6000000000000000000000000000000000f98027c58d94c4e574dbbc66e1559f57537315318586ad330024c8926dcbb6854c87c473171ac2bdd574ac1d7111a811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af34145fef2554fb92ecb798a0eacd6c2cf4bb8ecc43802b55113a0782eab3365b4cd206e922f4dd4d1e2a712adc21d000000000000000000000000000000000b798df6bc751245299341f6d410c39bd59ff8bb6a8a6172295b1d31344cbdce45516094fe3299a58d0453968e746b8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148a3017dd1252b6072b5a705f2873ecfdb44527248c09c37db6e699cdb8b1bea38236c694f4e9768550dfd8a4ee438e00000000000000000000000000000000138ed9231d869236b6d9f5a4e20b6854301aed9ae1c33b4858b9ad9d6d9322da30914311c84addecc59ca838f1723b511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ec1a0298a1f2c4484cab04569a4a6528d6d5bb20cc6d3c6961589b9867bf09cdcd9d92e0f4a4130e4066e2fd9cd489000000000000000000000000000000000de6c4cc2890584cd615e3ea8c0847c0d6065e480d79b11517fb69447681425b959549dbc8796291f4b69d29e0eabb121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c132c07a3c24a51e743584c064e4da1b0333f557f467fe38a3794981e756337292455234725cdbb44e17ea5d1095af300000000000000000000000000000000067db5a0a68cce2156090669c49d125be123d6d02fe6df0d0ea979ed432e5f0612f33d4e2028b31b671d03e04ca92b131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160c624288787e6deaeccc96be907bcfd3b6c6447a68626e48489b245c1e5b7b02ac9e816368bd26014112723734735a00000000000000000000000000000000127697d5528dae7d3d25edf85cf053b40c8d9058b91e855ecd647ed29cd4b3b3534376d5058368cd7561ae0588611f781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c427fea83887658879196117f0ba3b1c80a8ef195d3c322628d51a488c8d9d8cc24a25362aa6c2ad3385e87fe96ae9000000000000000000000000000000000fda2ac5d2b030236025507b9062992f28e52cb9bf8682ef933c3fc8ddda069266d985adf3a841d7356b4f19f13ecf9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c2b0f1c6927e060fd2e1e3429e686fbffe312ed7aa93adc8f0aa039635756c3feebd794ce61672a7bbbcf2cb789db400000000000000000000000000000000145a0c709cb36cc9a3d9876ad14ae90473122a89395e2efb1880acacca2106a4c0de6521cddacc5f39a74f9956e6d4151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b17bbc8bcec71ff5630840f2f44ee8afa6fd1285c95de1ee1862684ae629ebf1aadb28dec7816235a506527b004754f000000000000000000000000000000001677ef99ed8d05d98bd36b30dfac9490489308c6b69aef8b45471d7278136874910179bc4250c287b3194a1884ea1c431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099b9e7162f8147ca64515763c0a1d3977b2108c5f92d2bff3efe51193a1bac2d5719c603a097fd0b33c198bfe911e3b000000000000000000000000000000001036a71dc229149ea90f2097091edf4e6e35997724c9b5309c1c98faebed852df4587dc279c27be7ef0f6d856b77c6501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088b1082c9d3e700a6eac260c8bfc1090bf8b313efb96af470953213fcbdee995fb14267b1008093cdc314d1a2f2a0c400000000000000000000000000000000136beccbb9c4bc8a9628b416bc455df705cee623e4cf785ec0780b2f25debaac9635702b6f90db6de820d62e05af118b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ab0c2573b4767e81fbd4679622385bed85e393626b163ee63194646202c3ff4e6f5394a38a2ffb46cbc8d6e546ef470000000000000000000000000000000001fb163006b922f0561a4594a9c8f53762cc5dcd10f6ce185760745faa516c9f87edfc3123b099bab6878a9f96972bcc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9cd0c9ea338b6e4fd92ecbd0092f6b9fcaf11c41f1a6db16098b4a9efb974946238c2a250d3c2bd48b43f48072ba500000000000000000000000000000000007a3fdd09ccfa06e5a2280d6f2c88c2e5f71cd43bbd57b6f07dfde72e8c3ae2aa89ba554dcdfc2f74ed66066af8fcfcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019aaf3d50538276347a5ca2aadb21f1270af44af2d0a343b97906570fa5ee820bb5686b1b5213183277b12f12c6cb7cb000000000000000000000000000000000f71def9c8a9b6bc555ae3250a7a3b256d15a10180058426fc385c7d1f2ec484f7968dbf0591394060218c0abbae88231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f57b512be82457b8f4575e596936844e9aa6a9fdeb16e204ec1928a1ad519fe71bed7234dffbaa566bebc401cbe369a00000000000000000000000000000000190c2ae4bee3ed2ed40ec75381eb1042034f2e14ad755b025783b65ce3f955a0311e110dc40ce3bb7ee762e41e9832df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014ddb4e74acb26fe4b3393dfe1f69ab6410660e764e546e78283e38e178ec521937f518f8b8517bfaab2b39040823dc00000000000000000000000000000000019c136f0785e341984193a5bbeb3bc6548fb31eeced9574070c26f0ffc91ee73b051916f64dde3b9f4896fd3129ba251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004561b232c35fb60bd0b816fe6f8d1bde2a33d13e810aa6e451b2f4a3f4101c7ee12a69491e06813ba321bc927e9ef8500000000000000000000000000000000098fa407e32ce4bde5caa4aa4b1f875e1ed4175b3458b69a406d738003fab915de94617486d30adb6562f3a5ad3b5e961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001eab1fcc9884490cd5acfec38da8c601c4dfca4c08a3ddf9fa492cd10d042b4825102c6d7aa3b8c517d931697fc59da000000000000000000000000000000000960e84db7cb48d66e796c0b79540026f504d47ca2b1798cfd83c35f025b92a1b2094882fb85a8ab81918dbf1b2a2d6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a81e649c7e25b6802185948df23c829612fc74803572620d7c6706e7ffd4077a1f39dd4ec91facc1ee24da76d37a1ed000000000000000000000000000000000c37bbf210f00ec014f01a144626a359617ee108db28c13f8e14a5a05c17be274a622905ec8df58a6c2071fd556f3a821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ed17ab284eb2b459d711a3fa4862e32c19f9e37d0d109d28dc04011b9e23df08c4872a6196175d05aa76ae6ae17ae30000000000000000000000000000000017dd9ccb7ff37c891e037a64a4ef6e164aff7a188b20113d3be84c88703b44ff7fa178879aac4a7f48af11716b1ca1df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017bbbd531022c696b0fc7ef477804567d1c7fc16c3a529a4b815ff68828ff02ddf0776ceecd6013470034468265c4c0d0000000000000000000000000000000003b36b2cb7a59852377acd258c78879684cf6970b870a8fb45f05efb85f06a14e55d1a604fd44a15a1c152a38ba22c6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001028a4dd5e0ed5cbf50feb81b975df8820ec9a605816f100ef69a0fef036e8736b535458a855a0f8f6f7e14c67d9a1ef000000000000000000000000000000000ae6f68d5c89250355c7f137634a53c286672f14e2bb30d1279f16490cc21cda283f5c4a29c86028da593637170e917b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110476c28c744fb76a33ddf92abaf7a147b0f1bc7ce46df5f76a2a41f84dccb6d75a7e6cadd5d4bd8945e71fb605fe9a000000000000000000000000000000001502dcd865a85daba8b4293578ee2c2b030ab38cd27aa041e7cb749e8495a8bad350914a15da9cb0b662602bc67688291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce47436ff67e35037126c1215450cf09b413223bb7da213c489039f437e2b2e6eec2437ca8eecded7075e138baf528400000000000000000000000000000000028db966959059d30027ba64e41dfed409a738e08e13bb5b35ff123cbcc4ab5ea6214e9985a685c90cef36f2285940391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044197fbb6caeef6702f2e49aa73b8c2ea198a331527ea66239d6c63c9560e827ee5bf10f6907d3bd8adf5c5bc800f530000000000000000000000000000000010d8a4ffbc646245af6209100cea902ab38c6ef8b82488390a13e60aadc3a01f205499cb86ddc2ebd8ca3cdb8af08d791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fadf219e7b52190f13840a590e438f0641baa274e66e144a9f9c37fa7c1a7bf6fa6be6a8bd678ea643be45e3356a1b0000000000000000000000000000000019d507a4596ba55b8ab49b624eddf1ef803e4346221b4eaa42a4e83e3f345003ca6596a2d50850cbb33433a48ae7d4ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001820af4318193cb4f303e645d8b3f05910f122ab9ddade14e18c535bd5c74b5e2ab1582a0a5265e4d44e40f0191a7cac0000000000000000000000000000000003fc00a27d948727575a2d7a5ba0c4c3ea596ff3b1eb2e57b9a51c628375138c22ca93ebeaab39e1a953890877cbb0631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8ab6cff137f979b38a05fc284f58c32478d05393e3f209315e087d5d89779f290b8e6bd405e779daba59392f381e400000000000000000000000000000000010460e84c8dc37032fc060494f0f2a8533b4f6276e27875abfc4a57f207e6c949c5361385254518ea03e2ae6e5df0a921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8bb7b7109c98e70cef8672ccd1ea68aafaa195146fd2071e7c3857e3d5da9d57432ba86c3cb600445f4396a4e19c400000000000000000000000000000000015560f9e322af3d3c8bec7a899368a0d45ffcb7c027ab2f26339d94e1516a35a6450664f8fcd0f5569b81cb07a3616cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fe5bc639557dee959ccf9172b72bb6284d8a25806d6bd98aabbced7c321f96f557960b3ce9c1a0074102d9fd1c5e4f0000000000000000000000000000000017ef6ed144cb840ec4cb664d069d246f2912e0e815ab9584f1885f38d17531572d9b537b51feec26f1078931532842d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101f2b7f4ae8d205e885d84a4b09e7de834caaecbb31e61994991ef0361017ad25bf8dec1009de3ef3087d357c4caa40000000000000000000000000000000000c102cf6af462ee1fb901a67efb90bcc45740b67f772f5e40657be8858164831f99d0b94e352b24edebe65c35675933e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006044ce11df891dca33e14e826c54df404ef4ebc1c58f31303effeaf4b41acd0b8ff842018f12f6539b1d2e2adeb89850000000000000000000000000000000005ea06237a571c9a561d54efdba1b03ad64a16a58d541cab3d15a9d4e0ef2da96a8bd0a1f5a0ee897c0e7edb0085bb181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f7730758a63c5c84ddacf0fcbece6f89879d42f1379584be332e6fa8d8422cc1eacb2174c2219fcd1e834618da00a600000000000000000000000000000000084b313b9e3f7f476eee9d84939dc270751281c5f2c8876a687e4fcddad501da2c3ca3e14297bda3551da4eeceb3a3461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049e147ad70e2fefe95f50b56aa0a896baa01c9e7d9eb2c92c64471e41cbd8e94ac867d3d6aaf71996471b7d9b9d33fa0000000000000000000000000000000011b0428bec8f4344ef72e2d3a3bfd6656792c26322aeccc126a016480744ff74ef234413c3ce5630d5bfaab2ca4c42811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cfe7c84f8259cdbb10df2e1041774e914175734f141cebf661c5f8954f76aaf73bea09297826c1c3b470d2b84a31f5000000000000000000000000000000000fd81b5652e55c74884a416f866ec1a011d361df10135e26d2bae9bb4ea21c5afb7f8d88eed18d68b0f76146b0ceeaca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110f424eadb52aa547c6aeb02cfd82b00937493c490ab10bea322146472deab2425a8201befacaaa66fe89986030ad2d0000000000000000000000000000000017188451976d4c3f15ceaa2b9ad9974510e7473d968172ff2496f71fd36f812adb05dbbdc401d0cfa0b4419d5284bd381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ee5f61d62ffdc777e60d3eda462fd982942d8d7d3a75fa328f1fecb2c31278d1bfba67d728986cc0a717d536b7e7aa000000000000000000000000000000000cfcbcc42fa7e744f40afd3b8565753e8f420b5d7f0749f4ea4a36db0f3013fdd18fc772bcf2bdb93635171f9fa1b0a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f03d1c004918427452443c351912fb464c6ba5c290986055154c88538f9334a33f896cd8d9e7e7a7dc844521742afb700000000000000000000000000000000178c2cdf8b9bca61517accf152b86b2cd9004eec49401e792f2bcdbc54a9390ef011d51816d292c83b19c832b64d4d6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0ef2124eab4941aa70b6b6614c3944813378136d49596a170fbfd1d523c49b25d1294835f95ba91e416e6693ebc28e000000000000000000000000000000000ed793e5e1b84a6f79898a551562ef7eab240962f1a21b54a46d92e2d5643144e9a206cf69123ebe17203c0433583fe91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db39aff46275b0f1ad346d89818b3c42501e985b134834e3a00ab2af0a93861105bf7f86c2616b81b57d61516f81623000000000000000000000000000000000c758624c0108bddc03c8415ab1191f3a47a417a8c3c4099952c4eae1f3c3b7b9fe78381d5c0337bca9e72665c5e10fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001118ecdc45d794a8e5da752f07c813ce5d2d5ec99a9d51d68512fe7d20074575b17fb781c925e04c6564a54c3a7a216200000000000000000000000000000000168a3d23bcd6e7c083ab2540b5a719a545a0f02409265a5cf34a232c268e3a635c975e288b8c023e1444fac068b6d3731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072bd0399cc64f8e8f80f109618ec63a63a441c0bce0641b20eeeeec04fbd31c3aedd8d8218179d7c9f323e7e317f88b000000000000000000000000000000000250566d87cf739953cb0bbe4e29022d4f9b1217b40432aac6e904dcd6177df6f120d19d13f59577a349c18db9e0c1e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ca1005596d46ba521a576a7876dea2d54822f606d11e9a865d1d2d2d40db2970d1f1eb91571ed7d7adb99c0946b4af000000000000000000000000000000000ff5c3ffe56b281045b302976fac3a586c7673918e89b40f148eb5de54cc7456e5aa354325146cbf33a6ad79ddfb02d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004eae449cb76344bb8d0d875ddcb722bc7b6406f7747bcc872b3ebc4732dc3c0ba5ae941a90d6244224c14d37ce318e9000000000000000000000000000000000c3d3b1c242aa396588857f2ca9bfe5a27e719fa4ae08b48b2d67d39ec1c10f56663577d984b9697c78edeb9e7ef20671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f6885956471becb7db511a0068da34f58a51c6dc34116b780d3eafe165f6b2adcbc8558f2d80a2cfc5179c0254dee4000000000000000000000000000000001622531e50446bcacd7c9ccbbf458e900f174e0ec914e9b0763d5ffc969876f0ee4708771fd13afe872b89abbe02f8331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001495f71d011d23767192a7c5e4b029cb0d09f5b52cbe3175d1873c5234994114fee61223e965bdc4054e3eba2e8163230000000000000000000000000000000018e018bfc4c6e63653c2719696b7d6889984b4adc044781e79549d58582cf096b3b02203381ca73db65ddb6bfa3efa7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a590b31a9849ddd77ec83c54ecaf37ce3f85b3bd0acbe38234d6adbf74671abb5598ce6bb34d65e1d399d3f38417aa30000000000000000000000000000000000352d0e73c6b5e4f321643e9311f8d220549429b90865370061a4b54112db26831a4243fb653143e009be13d11af0b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f75a7c76e7ae0172263b05a61a1205c0c0d1ae2df07c7c9873dd5eaf8b82aebcb3ce9fbe8afc50d31c5e4cb63f3026700000000000000000000000000000000081b594abd588ed7710e6dae6b3d84a3e690ea32d0242f2846b23db056b92d5784559fb390256ab110d9e835ffe8769f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000536ae82c661a58b4599f29c29e4ba5bc2c45b67511638057219bcafc10527bfe5d927ad0800ec01a170acf3cab4afd000000000000000000000000000000000c981e963ff54df01d85a172f375c855e4e0ac6a44d3580b2c008b8ce2379ddbb897587989f7fef5c39507314e6f1fc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060d70d7b323f7e4d1f1f7ba8a530998575746342eb840a3a308ab2b101b55ce870f07ceaa7087f57222a383c947f6fb0000000000000000000000000000000004a3a3b312896aa719aebffe9ae7cf536d5c1cdc1ec04caa77a5f555d152b8b3b6203bc1e6655a94cd0b970ec2c0c38b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048061e01e777e517794a89e8e08bbfa028dfc6d3dac3993f0af4608bb4273efb65bde5ef98a41a4e95a7e77a78356b70000000000000000000000000000000002ff48c3945c43751fdfb829ff4b775db5a2a425e73cc57a7d88509ca4e7081879695020f5b442ddd3c55a2cd647970c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bdb3cdc685d2e912e00518de50123d0563829638cd46518a6183b88e2b1b0fb37bf63957718d8df8f2d0688f29e624f0000000000000000000000000000000019cb7f2677aef17e0d414577887997845e1aec634eb7bdb327b8f0791f82fbb5eb55d78f852ce77cd66789f96e6e9d801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123a9fad69c28ee2f8710f271fb6827ebd4a393768dd3b47367f44ac29942d2e089c5509ab41e3b3bdd18d530c79f59e00000000000000000000000000000000026d84bcc60ef42dcea0bb3cbd3e8b695a65ae04fdcf2f7f40e459034af82821be7b034d7408eec9b813255a98ea28e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f2a97a5669d252dcab8ebbbbe10244f2e0e29bf49bb0fc6ad772965ef3f3ce352752afdc5bed1b9f851d62772514ad000000000000000000000000000000000cf4fe7217f8d84ababe2cef667af63c306c0a44c113aeddfb79dbc5114b315169852b9806d5933570be71114d259fed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076fe6e63676bdc71cf72f1f306d0496ede550cca31b72386b34099fb75c86a387717069a2d59d7a29357b4e814708d90000000000000000000000000000000017ebeeac5e824240d0dd60d11fe293c7092210fd633947889e574e24fd4f30f02b49b65b045999e545b497f9fc8a82081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088bde6f7caa65dcb745403c6645700280aa270190bf9bd265003a21407fff6e5541f051e64d6747fb9418d6813a037300000000000000000000000000000000063db74d5e321fb54bea443e997a865b3249639fefc2a23838ae4a5a9fb0e866d533b2b3c07ef22ea14d7a78737634561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000610752ec6075b6694afc2ddde05e2b65f8f28ffae628b11ec7faa2d423f172d5fb3062cbfd2ba7657a7d7b4f17052210000000000000000000000000000000014564a4848e2c442d6aac740f943ec9b11d6b076b7f7b711859144259e6ab2125b05834acecae57acf624784594209051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073a59d827f6052d7095cea51cc76d426247bd416b113398d738298cfc721e0050f3f9e4f4efd9067fdff2e19877b86a0000000000000000000000000000000016539295bd719ff861a4e38dd57bfdfdca65b8785daede242b4b4568a71563bbaa06b943b855b08239bd7bab5cce40641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd5a8d8cb68897ef727fc6265f1afc9df200e89fb01312654055567edd4c9d7d2f4053dd5ba7ef3169c2ae38295429100000000000000000000000000000000011ac51b2162fe981fb44d6b840f103264025ee1dc57759ea630395561ab841cec65f3dfc69e3cdda044166e9bbae8471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001616d71583724dd03aab3b4285fe4e2bfdfda2dd83a1270a9073616823f091b081f8f44bcc0a28ecb9605df012bdb87700000000000000000000000000000000146b7d6d87e40a6410aeab5790d966b45832aed85b2fc7885a7f3bc922096709dfc1fd028bf26934afef8456a0d58b461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6786b2140887425a8ae65ed3028125f4ed3e4053ccf5c487e47eca96511d0d97a30b1ac0096dd16357377c85d3c4dd00000000000000000000000000000000090bff2093048f94ce1545d7a737adb2cc76cf20ad3926c10717630b684a99017f22a6c39f3ed1b9a7e955140c4354cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c73616481fb2fc0b533ea07501e8ab2c8c797db0a3ca2517e339ec21d5ea32de4c28c80adfd1705bca87449b2cb5860000000000000000000000000000000013393b08d1b37c6140256337a3b03fafa5ee3fb6e50dc5e2a0d679ea08c73e868e76d4a1a49cffa553a37d2a9285318d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011db23779842201faff024b712ebaca45566181787cbee9418ca0fe2b966ffa24cbdf26549bf5705d552a92ce1f5935b0000000000000000000000000000000014f7c460337e3c4413a49acf676bde6e2b69a500e42e4bd5be590a4f9c9d37a0f46622c0fa7940f25a654bbe0dac07bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbd9e173d1d5317e1388f922a888087b12bf63797a87e1624d47c6ed89f2a46abe4438648471c7ee69c5f6b6ad2a86a000000000000000000000000000000000a498b77785e85a0ab8a3061557b562074e91112f186c2f1552de927f146749f3358710040df403d0cfe58096d5266361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001219e276dcb04064cc2736608bf4d9f45c2368f59ddcfc961e0776fddb5a61813aa91ad39236524b0ab7ebf66407edfe000000000000000000000000000000000198bdaa519f206b71b4b2ba3ca5d239c8de4f121b4058638d5060d2bec8fd706f27dea081c555c2dc18aa28c5ac53fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001733b475453d6987c9e417399c4241a978a59242036d088fdbe822d51a9a73a5fafc01c0c9fb2924894fb177b8b1136900000000000000000000000000000000126f8d591a97322b0948f3230d025a20a9e6f0bce400fb15dd7145aeda051979b97830da579a39e3ef7456bdfa3f4e3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c8c82c648f4f552c3aaaace443860008e91062c285ca527153251ce051050014365864f683b60bc4eaa6ea3f3c26ab000000000000000000000000000000000d6a6a8ef621dff9d259ceed3f7ed4a44400741bdadbfe257341de6ce7cd3ccd5c7c86b2c2245eaec65decd8d96802a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c95177d7a5c2203ad8678a19994f4396eed5ec8194c1958c91f66122cf1c31c1e09554b236da69c8536ff41963f82c0000000000000000000000000000000012b3fd4c9bfbac1f22006b2c1ebf06d3c652dfa0ea0ecc435c8873582556ded084df1c6f4808b9f9091adaab887343d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b7609b2c6a27d602806f24fc45357f98d62304e8b43a959c1f11f0cd892eb0e6f6f87bbdab1bd77ac2649db68381960000000000000000000000000000000006a70b015c4c343ccef09abc894daf520fc8d20b6e0d1461da450e935b5e94b2c07f9cbaaf948da639f69188858334e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109ad0c31cccf8979062916c64cfad9e1151ea6506b2d46efbc819a11d3549a9948b199895f9fe0c05dd445e1306699a0000000000000000000000000000000004a7be9220cb74c62e745207967ed0d5820c5ec6fe16f96f1a3f7112e7e76b9cefe8ac86fb25fa296552c86e0a544d8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000158b856f880a537997bc22f740ece5b67cc234bf8100177fd48ee3e95ff8280a9927a6e48957be19656d4506fc6652d5000000000000000000000000000000001480ae0d6b8111c8adefe373cfe6ecb2d9ea0ade44129dde2c0cd1b8ef6f79d32cc2933c775afc381d9d62fe600a60ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000032710ee67b2852909ae2537b6964a711cf929c7e5909e1cbd1ece2c0b302f4629dc0112b0ceaa1c45313c6b4e1fb56000000000000000000000000000000001805b1297892a09273cc97b6d8dd6258bb845f8f32ab087d840f08577949f7d1558a2da4d1e3d88a90c1f1b82a7035f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d007c829703c814de461253e18f12f9cc721acff8d82dc7dd4f580738180f3f11f6b01b6b04500e691abce0f2e84c10000000000000000000000000000000009a6e7e3998fbb0d803022ee8f8ffb6dcd7e227a730d49a9e11ed709b91f18c74269b05289cee0fca67894aab8aa19511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b841fbe72807a55f1cd6540d0ef63674f8a08ad30db6878c66d1147b47b67b3a69d19a3eb98890b92ba29ce93f29bf100000000000000000000000000000000095b85039fdcf946b23f52a71b6efc722d3bd1e601341031584d735737a70cd7588dfa62053e03baa7a55cccb61d83991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001999600ccd5fdb94a17f7626d147456b5ead657a588b87ddcbd1c5fd30f01815632f79ddf7e00e0d5b34bf779cddd2ad0000000000000000000000000000000009596fd894043e582baf04f6dab4aa24d8630ae8cf6440743a5d636b74aa18cfbd9ad84e0f778dc9b0e5eb0dd3e8168d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ce76f3232af4e26d44aecf0f34616572342f3fb64228e709ff279249193e537fc2413e584322761594c768ac83b5e500000000000000000000000000000000103b41786f5477b8189934b43d79cbc29fb7afbc6bf1c1cd88357a37b5f996885bd071286386e1cf5db6f46d16fe508a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000641839018bb72cdb6391f94e99c74e402843b60df3f03e3e362d8a534a81a115720453c9574df2b93dd27561eda74c40000000000000000000000000000000014c91b573c11d0b5a26beac01619cf51010a0909000a52094ae13bdffda2cb4d9cd7e48e1d1c171d291dfe9812fbe7f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dbae97970aab184aac94bbff425ad01bc641585d9985e6378b4841e74bf4f7cf82fb8559aa6c4724103276cb7aec4d30000000000000000000000000000000009beb522a5297e76969b799c572ce74d6ca92f19df848f027051372f9416cc882d11b0dfdc803c6ab871e26f2560f2e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097e293d62ba305e6f6656e510a0d6e082cf2f782a7b41d485171fad9e338f21bdd84248fe4652aa3e2bc95e53dcde6d00000000000000000000000000000000143e52c9396bea4c79a2e68886c762468c1328e75df73dc3460f95e82bb4ce85ece96f3aa074fde705cbb26734aea3a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ad1e9dda4a0c540a2b91b2fbcad6b4dc5122b0b63d5b2ba1fdaf025b4932686d06ab4835c68ddfb6dff69c4d0e170900000000000000000000000000000000140f193c508a348e877f31aa36cfe2385898ed32331247bf6a204cfeb7136652b5619724f234303bd828abb2c5b25eb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001792580d2d7bed5f4d7187590c4f4c8897929d30ad53ff5744af4fbc4b5d5c57b74a1c99e24860acef4dd87bc71be0670000000000000000000000000000000014356351f568196c162be30eaa96d209aae93533e449fbc66467e10ee97c599dc4d64284452f802f6a712ba580d3f03d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c275272dd72342fdb1f1f4db4d8ba82a751ee379a87f26d7778c929a56120a96f286b2bc8473edaf2d3d0653d777f90000000000000000000000000000000011c414d18595a1895c9af42365241095b6510b4fa5704256f714e8a81d3e4b1acecea7cf4d8f2bc01485d6903ab54c481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005cc84f2190fb3643989137f8884bb4eb77416ac395407af554e8501503ee2e145057d4f22bacb629be1b0dad7ca85d8000000000000000000000000000000000f5fb1d1b64022599bfbd214725302a894f032992475349f23c2868bb18fa1836da38981f333d3004b8921a50ce3e2ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001307776aa3c28f99f6be998d64906219ccd1b880ab54a588d8993ed97a1ecf14c12e7694981f8140faf359d21776f9280000000000000000000000000000000004859e8acac76f4b2af72c51dd3497c2dfe40adc65d4762d3596f2415844eaa4f709c4b81307aa49f272a074d30c20db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000095cedfcc32ea620bed3fad20f9d17057bc7b291a49f4324214b1772bcfcbf27dea516c8cfbbbe944339bd37a4289a230000000000000000000000000000000018d29e8cbd01d664678245aa8c07de3f2887b5dff09bd253a29d36b86699bca406d4eb473ab0678b52daf93f812b5cdc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001355bea25feb09895aae1ca997f4a88b31fbcdbcc20cda7ee8f19a01b897343104d6afad6c63b7de8b18c5227fe752bc000000000000000000000000000000001276aa69bdd1dd0dbe110ca622ecf1f9f86d2a7dfbc486302ea0f76c232f3ff60e69904aa998f33eb0c3dbf2236bc0871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019151c38d933bc2a74c581db3cae81bc655e0eeb3031112792b6631dded36cd8d69e5e846ca8beace0ff495b5f934ff100000000000000000000000000000000182e82a6008f4f93795bf540223eef3edab53596f223d42010a04dbd601373681bfc3c5454419995ed75d0ef203ce62c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a75d48ef374747f99ce2c6a4120c053d2a8cabb1cebe37e1f925e9fc34cb57a0679c18784721717456427b60269f2b00000000000000000000000000000000019c99b15a1c50b4c7d6754db62ccc0fe505d637e116c32a2136b80062d33fdd64980e5f88b277aa533cbc9b3324753221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000093c0f6cac8cad88679f212f3f69621d92560d51eb8a38f07fdb5b0e47f1ce890123050901fe5d5eed45bb769f9e3d6000000000000000000000000000000000942b35046b666ee55b79f151b21b5ab7364fab5a73160ae81ccbf61900a8b0234ba4d50613128796f0d1c1aed89ec761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000171054e20771fd095632ab51e13836c9d4c38799be1a75a74532b15c4eed6bce7f53305130fe9617e8eb447da911550000000000000000000000000000000019ecbde7d21f4aeefc6619d434fec381cd1e6ff5d755c69204e3ffac4954ec184c2907e8690b6ddc822376ca2c2dc10c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001112b63a03d018af74ca0f27bc645f6f17fa945be8b1aaed62a77f743e31368ebe61fc1d58f438fe84dd9ab78108fd2b0000000000000000000000000000000012d7625b134d15b5949247d55e95d146c6e30c3f0c8edb79ee1addc9f1130ce87d66c9bd071d89c493e76afef30f223a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007bd2bb6707220d1c16d12d89f95b6dacc209bc2bf9a27273c5037dffee7c157d4ce0ae7eca0ef5662021baf5e87ddc5000000000000000000000000000000000238257b34e5cc4b6d6f3812141f5149bc20f6a589594c0b9e905f6a11930c82cdb8199f9900fc6c7ecc1db602affbe61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bedce42ca45ab6dde10dd6dcb79cb9457a71ac0693a770510ab21ed4232fd23af6027b9e431df35c2034af3c12c932000000000000000000000000000000000df657ccc2c2b2c20c6c38ac442ecc82d399efd1397a4d31ec8c3c0d4404f967ff585cee82729f86f851c6356ca0bd251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000673b26b897752394d5ff4d55f2c2d2fbe3ec3d91c6fefe43088e1e4b1e539d0b0369479aea4af3fc23eaf35e02e0ee100000000000000000000000000000000079c3da3911f44fddf352c3ad99dff853753ae696ca3f169869ffc48a7bdccdd023d673c38850eb5593f4bb37a0d896b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006a51a66a0d9ad4cf6d6a571269cf61d1260d8c73200716b15257e824ce40f9b65423f66c5cf5ece60d9a4ef17e44c1000000000000000000000000000000001145016e95c35b61aea66b4f2f98261c2ecca66b236c8b94bc2ae6b1a53c31774b8b58404902f55619784d3d819cdf981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001166faf413bb0f32a625af9d223269e43ca5a71e0f92c79ae7981ba876321bf008bdb184dd961c2c3a347e5e080c2a50000000000000000000000000000000000c2703d0ba96eff7d258cb09ed4ada8803d373e2ea4a364925d14cfdbfaa77dfaea9eb3506b058e615c42bd7c200e5e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010acf0496dce4a3d9f0b72ca5cb1f59675a294ac8f92a7539dfa661b600161294b37a99301a1d27b13a0b12e3c89bf3400000000000000000000000000000000168af6cdba3b31b3f865740d59764102d350b714a601121bfa771fd207fdd6222c50c464467ca2194a8b6d3b5f09e1461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025db1a6c019d7873fee3e7f2f8d40866f808a8a75c437aa2046239580ccb1e3ecbc7f00149ba5b82567bc0108c0a0cf000000000000000000000000000000000de040edd5f73de4732c100134e9d35afcb217225bbf0212ab5d3bc88ff5ea7d855c86ac701e18b910232cf80956e5ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000011c8d1025df627a8f60eb96e6051aa37e1f6216df1010bc42b3d96eb5e2a8ed53d03eb50fc6d39772c5899c6012560b0000000000000000000000000000000003aec2de34b07290a3331270f01c3e317d8f3d6c0855007d70c7dd9e0852df2143d3c9de905b0a1dba1eebee88b3ec5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b71274f2877a8ed00d3bf172d23b9020142de223f2336b786fbc355705ec8c09353b5af777006de91f184b10215631000000000000000000000000000000000f6484f6a20fb20978e9eb71b94b14ecea6b2e0bd55f724a076b0bd5c51663b92695e8e3c700732da45eb3aeae0e00941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001606eb6a75e26b280f8058abe0c452fefb02a22571f561eb143315879750db12098b0b19099709388d2630c5a339ea8c000000000000000000000000000000000fb1235241722f2e09167482a1067cbe66583fa639081ad4c8e3b06116a53fcdac730bbd33ec899937cba5ba5a7ac3291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066fed1a40f5caa0cc57d78562b11630b3eb40b43ac28bceaf114f78304142d38526f872e6d5c3c83750d5530874b5ea0000000000000000000000000000000016535316347e4b7a7fab67be00de108a8f9b7359a0c49a2d58b1279c3e7e0aa8e63ca8c01a7cbcd08413019f74fa2d801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130b1af5b6dc6e504001471b953dedbfa505a15d46a78c9364557d5a9fc723d294111c51af73189e53aa2a0a031ce87c0000000000000000000000000000000017c7f152c5dfada406db46aac0b7d8f7c7b56d5e08af8914807ae6c9e9b11dee56c9545e722f2f8e64e2990b8cfc70511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001952fd20672ae2486b2a1bee1972088d7ba1e990231cbbb8bdd8de855fcb23f9dbadca3bca7105e6eff71fceca33ef0d000000000000000000000000000000000a4e31d994906894a157a5796692f1e6f5e033be2e3a01299194662d975983fc54854e839f879c3a3bebd17625e1913e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150681d80a8f923e2a2fe1f8f1a19ce7765c913c5ac1d71a03cb853bdb79b51316ab7f02a9e04b97392cd409cba1b8ff000000000000000000000000000000000a01a5cd056f484a3f97082b8fdf43c1ff00f5937dc89aac330295dacc1ad832f6a6e5a1e3a507e67a5419e9aca39a791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035558b530ecb98ff1ecc5c3386118cea40ea2d25d2e4e8e25bbeef7fa9cd69ae39a4de78d5665c0900a236f1760c8d4000000000000000000000000000000000a7dcd3fbc8bab4c853b9c298b1db401484825880f6f66652350af4b1ae2e74297cfedcc6412bc255a4b374f32c06ae81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd759a0c8524dbc755bada8d373b4719d0bcaf9a722e976a70f40b62d33fb1215a4a7cd1402fe0ba20a9f28d7ad57c900000000000000000000000000000000185f4cea3e456c25efcb4c2a5770aa5e0de4b2556e4c827ee234531c5785c29148b36808ead601c108e0220d554b70a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bac42521dcc70be69d6ea1e844b99e870cf29fed3e176ff889dac057201c3d7f8a7d9bc7b61d6792b273e97885a84d90000000000000000000000000000000005482985e06dbf2510b90b8be3213640b202c5ec6c572ffef1672abd02c55f15a97612902e270aee0e7f47f40026e11c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083e97e8fc6bd9d5fa57a30ae72d54283d6fd3b1ae19f76ebd64d5264467222214d840e48874ba51c76315317c5e752e00000000000000000000000000000000119e5ea8a334eb2f367fdb5c0c40c13809c8d8224e206c6a29f5c5bfa18c7533e2ed9971972d36a6d6ae483ec0e95fbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b2cfef0ace9daad7baa7629eec891e7ea578209ac9bc94a4917cb82359d99f11314a5f81f2cbc185ce25d90ce81a6a00000000000000000000000000000000174a6b9fb60fbd017f214d002ddba7596c02beeee3bf9e679007214fea6d60c645109c3616079c2a58e0784d04cca4781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a272689068abbc959afe2845ce16117545fc13ec1d8a6453a87763439f3970ae01eed6d20e02331f1485570a14d826a00000000000000000000000000000000005a1ba371762575fcdab489b072ac197e8dc65279b09ac3a94b19bce01fd80408c82f094fa8a7ce11aa2925d18cc0201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c534a60de438b1829ef559743dff610495a93d5d9949eb974f2c0c78cdc2a9b64414a0d1690ce7f005310496662d1c000000000000000000000000000000000345aaa1a7ba189eedb457fb99b9aa3b0f5379c224bbacffb3ea388fa133cc82f07b9b349d09846162777781da7f91261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017cb3041e6973b2440ffa499129350be0d607437acf5a92ab4cd317df6293300e2612d69e417bb58225ead19da68b1d3000000000000000000000000000000000a67372c5bcc8476ba59600fd347d7bd0bc971d86f52b6004bdd0bb8413b9aaba76dff76465b0198917e5f66b0881a3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185770d658f382bf37e5e28d502f1a8d1e1fb16b7846cdba8d0d061cbd4051d4e77225e4683432e41f3a923a51d9f99400000000000000000000000000000000073860d68f0edc329825632061b7ad2cc7c0de07367ff8165ccb3c3cddcdf4b4ff539bd2e2e58b81a617abb0f88773fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066c51bcd2c6a821a00a4c1c5d81e3c5fa817e7a5adb25f9e22e4563e81d75f31c7214bbcfa1c1dae6b0e662270c862b000000000000000000000000000000000ad0ba0f5515dd08422fb5303ff389f383ef399499c63e3873dc00ac744dd856c5e614510539dcb7df0ed2e7348691511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4251016c0372bde4a05be67765ff833d7116cb5718cc6147ae269d935eef194f7ece096a210aeb36ce3ad931d905e30000000000000000000000000000000009131dd3c9c908f02307c8a447003e18fe07d106239e5c45f129fb1af5ac1480aa74585b1e9d4c2a1c9289bf8bee6c401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bd49e84bad0e9b07ed81d57218384a0b13fc23ee981e95c634434ee2d2fc2bd50305ddad9dadc7a845da89b0e82c7c000000000000000000000000000000000b7d5806a901c14f7d149a1febd957589e095e7a0f751424f5464c9a11fe87d0ca6d7bbf2daad42006b32a02d46809b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3ff38766c7310003aa1e05d172b9bbe9ef867bf60b8f01647069dd7865d0ca1b4d085913790cf866f502760a4afb000000000000000000000000000000000017dbccae6e9ecfd5854a57f1fd1f27309e815f03fcd87236af60af1a0f910cb89c77043ca5508e38704ce6bc5b04e2341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011bd8417c3edf98676d31179914a5e9e248420d0c3e164c38a774b2a85187ecfd27fce8a7c8aafd8814f47150b1a8d540000000000000000000000000000000007afd52f80daa5f04729105a1602aa66fab9d6249dad4f4e1b55aee8c98bc9a2dcbaf36dd96647e67a90598fb1f90cb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f5dcf4cc9a605968c842771e80b430af1ac6c325e73917d6c9ca6065ee88975007074033b68f54dcc0f1659e7f95d500000000000000000000000000000000198bfcc0fafdeb4f45cdd4fb65b125803270c182d9bad293d6525bdad1ba6ba7e930dee9e65dc3b61574642e5e6706ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dda18ad34f43bc17e3f8708519dc0a31d1f1c300191a7a57d6d80dacecac18d53f89e39141a9909277c4f332284de500000000000000000000000000000000139c2f42c8d215fe43c8728d6f89683a32ec4402a288ac1a079bec56a17fba86d70eaa09027eace5e9341e158418f7221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008357084539860615f2a6491f0b8828993490397b766404d0a97d04a7016015830fe33c29b5f2159e874860919f0150b0000000000000000000000000000000002b69fda7aea712383132d2778dcf9113d49cf3731662df06832341dfa3851e921d2be47a493dd45a90c342ca8c39c7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f835bc3f8a6c845087f6460f42c58ac08a434f04e61d7bb167d64eabf8ae37bcdd9f4520984a4f15095b14e1c39a2c0000000000000000000000000000000003b00977e36b9aeac2fbe67d2d4361cb646ab7ba3cbc82495865ef5ff7045fccf74d0fcd1c1af845dc5b63afdba709991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0034c649a979f9a7fb38cdbd5139c1c9fcf7b5fed2e01a583f6d78e8a083f89e73dc0c360ede09826ca2761be4bdb2000000000000000000000000000000000b132f073f9fe0c70da323c711925d1cc1f7ef024e7c5729d9a5f31df6c4075399d890352dcf3370e58c3d6270c467c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000721ee2c1cfedf346f8a5b4b90ebd2f41ee47573ecc7793a1a63f4c6c91266299ea588633c54c919ff4aedf418b3381c000000000000000000000000000000000f3d58f573ffded7c03206719e71e3c776d689cb41d3e693b6ae5d06db71991aae1bb1cabe822c2c145e221181c869001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000580cbf7539329132027d92701d69aa550fc2445b24f704f550556b2018ce49a584eaf95b1dd55d39471f17f06bb4961000000000000000000000000000000000cd0d571c7b96a54d9d11abfd69051b8d5ed89018844515f5078bfb657ee09e51557ee79fc49de3166be2c4c8467517f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c22b26f017796f8276727446efb3053822ec24e4fe55ae629410b26a791d4a3bab71eb845131800cdbefc5d0b5949800000000000000000000000000000000118d1ce29682fde0346b5b42d86d11ee4a2fae6131f8c74a6491da1d4ac5898a2ff9208fc9a2ee331de0923df7c834631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c82e0ba1e9a49fbaea47c1e1e1b0c8771f1ba263601b4b37289178df68cf4dec35c04cdf55549ebda44bbd8fb1e8d50000000000000000000000000000000012f56e912490a2ffe77c3759f54f4909bad27b9e1fea231d510ae9a4879e5e78603764bab9bfc8f6f4d629e79ff8bfaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b003e57e1c74fedaab38e0e2629e6efa9afbd2de8239a979d420e8034d24d15b45d989a5843cdce523079965263ad700000000000000000000000000000000036f893125aad6575996da90dabfd73c93f793c296b6e08123b1c0d9fe7bb57a7c52ee9ba0f72dbe41a93b2dd428da921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f282ba2df9beea080a1463341323945ebfd30c5b68492febb868722ec3e32412d8f692299670816d3994d30cb8d4e5000000000000000000000000000000000e2e03c9519430e5c9dec3741cf0f3dad719fdd34b9857ef9a860cc0b786085629cc32a895ad9181a21d4d43356cfb491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab2bb6c1769ab85dcd0227b375dd6b14c4b58495d0054acbdd77569b4c59cb759fbe0e2a8db074b0cf43594ec161add0000000000000000000000000000000003a51d198e15a3f26abbc98f7791f5a94d4eaf3d455834567fd0967bbfcbacbbc81e835add3bb8c7cc16c6e0d58604071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b18eefe08f146eeb93ca3011510cf6bd45057f62a7b20158d6e6a1e40295a4988cc3cabdc6e0012ecd5d0c8df0083c0000000000000000000000000000000001fc37fe7d05cb55e9f019925194070c346cfaeeabc87fa3bfd133ddfd82340cdf33b0628d5eb4e6ab464a42f6966f201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001195e53fd2ff7175fcea36da131136eaef8669bbc20d2b31596119ad1ce1790a16442e1dbbfe237bb0820100a8f3b830000000000000000000000000000000003118c1236f48d28099d8bf5dbb16639b4913d231d1813e2b4687f9c53e889308988b1848793111bd9f73b1f410d27161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bdec6607776099cd4dd93007c5ddba4272119d37abb836a82dff7c734704f81a9e31da21b491bf00d56851d6f1d9ff50000000000000000000000000000000007734d972cc7a64d979b9cc66aabcfbb0b2ad77caaf0ff40cb9eb78183fb3178c2999cc3bcfcc6864c1f22803d80e33f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003bae441613a18af6e0049c78c23f0e784d0f0137dd93511a51b398738e5eccdbee89400f57f9be7f88714a7d33f0175000000000000000000000000000000000d363643697e6c58c00168dd0b3df281dffa2d27bb4b172a08068bb2b05cb9c1d2da26f8d512c329eb64191a84f5050f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001679eeb2722bbc5f31822673c07dcc7a263c1c8cae7bd058998659a954a55624455fc800731f06c29653133be8ec755d0000000000000000000000000000000004e62ca6e2fb6f576135c06aa5b53bf0bda70347d60f8f4926f2d7a515d91fd92ec67486eb9e4267a47a62afb84de05c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000199df9102d15e0319584ff77851c04952b5a68f477ae84d570ffada39a0cec817151905770ffa78381be32a397f3cd80000000000000000000000000000000015e4e114824b65c9923313ceb2a7d360f36d07bf5e2011d6beb00f97c92abdfa6724112c44e7957476312a3d17e659b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122b47e56e34daf7653d5bdcb3e75d887553ce99f21bef5974f9b2fec5184455a1fa0999af7f28b851a420470c6cd6b70000000000000000000000000000000001542687df8e6d52972bfda3e5dfa7dc6bc537ae13818f31fb319adf5b042c7d8d9094f428a3d766208c501c6d43a0f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de152a37cc3ab1e9553e0f54f800e52b155d629994a73eae549067fea6d14a0c2b156b1ee3f9b781cfc3b3b0b88bc3200000000000000000000000000000000083e2a21921a77bccd34e8e626c64cc445a0206a73636fc8ebc5a7c4b018c36029f4480e2636e4b10bafb6a651c1282d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a7ecc412be53d20cdfbef4ea0ae7007f25a8218c39be732c91b34e7ad9ad05a74cc69817203b8929bd9c16568573b0000000000000000000000000000000000fd10504cc3d8ae4ab0ab1ea7492d7b09362ed5ee2c5af9d3868a28e029d5860afda4097cabd18c57e53ffa6c47334661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001719bd521a9e71a9a0f7192b37aab412395fe04b55d000309ffd1e9458d239db9799b900715dfb4930b60af5d2c3763200000000000000000000000000000000191555e483ef578b9183d74ec432814e484be7da872c5861a8a9e070472115dec554bda7c83bbb7ca2f73f0ec67b05101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000c41e248635fa186c4497851c814e124988ba8f4db329c2ae72ce5665d511b0cf72b3ac3122d1b825f5d14ba6e3e67000000000000000000000000000000000242e51075aaf087155ad59f34daf37af824839a3126f2ffbc29c2ddf4c832f36000ce312a03da4568bb01773cdbb34a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189d003b0551a8cfab4ae83ac67e2d97fa7d3ecd470e841395da9969aa48b9300f8aa7ef4e5c00ce76b3974c7524f552000000000000000000000000000000000427211b247b475aee0274df2156121639e3dd759ac85a9a5f2fbc80251d656b9a8301b3da04cb1abaf94ce133b871db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000886617997d171e3ba6c99a27b2b79cd48d4ffccfae6cd213d716f766c75b77a4a8907a8d0bd1ad7daa650569555681a000000000000000000000000000000000c38d5187a918db63662bc5ee2ecacfdcb50934721019cc8e2d951bb150c910986b127da2b099a78af227f1a24e8bc2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039c3f38885a296dfc969dbe139fe0ba8850c9849344e43959da74ba3c88336b1f9b232923137e00f63bec94964e453a000000000000000000000000000000001001b0029ffad34d03f4b566317c6b9ce0ecfc9e94103bfa91e5a5224a41f11930846ced29939f2b33d29685890ba8ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f4f05ae2bc9b05ccfa85c0d751cb2c0522133d90cb1d422ad71c69b6e5deb9aaa729c4041ab1410043eeaabfb8d74c00000000000000000000000000000000188b44e4059c88e9e3a5c084ba310a1069924fb65d592ef4aa769709bd39e68103503ddb88a6164ddc8cf931a883583a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab7eef955b9ca1efee65980764104bf950223715f740584aa8d4e1178db867544cda3d97d43c835b3ba4ad9feb813af00000000000000000000000000000000182bdb028dd8e51364c986a788ba4058b470719d774c0e05975c564be87eda5d7532f926c3015e73a0dbedc9609d16ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f2894a4691c802c027d769cc090c3044060798c64aeb5a2dd310b30b998cfb67c47be9cd8f80c76443231e06699bb1000000000000000000000000000000001775b6cf3eb18fb3186a1cb7fe202a2de13940b523260f6d08f0f68ce368c9e24982027b973b201e8752ba3e9a7f77ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d7dd438519773b2494c3f48f94b6ff388c69d0d479cfdec6200f20f14fbc89c169b67abf25802cfe570d162e53ced20000000000000000000000000000000011a236c092df352578458db1765e09fa33349d18987db181696db16a7fdf65215ce31fa1e2b40afb5ed2382da101e4201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150bf08f70f4de3cc46a9b2b4a02eeb2e574e536476aeb2ffdffc842625d4ff6eacbce0b015a45450836e52cb775a8080000000000000000000000000000000017a6fe20fe5e4e34e810fc6208d5572f1b3bad1130ea35002aa3b8b8b1cdb9c255471051de989d73f7455575a77269001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034ca0147d6ffea3579c17b5a781ed74243b56692391b094ef1e3b7e795bd7fff4a6f4f00031d249bd42bf36d0b72ce80000000000000000000000000000000015a98ed5d981938cfe7f3ff90d838e0dca637557bc54e4c1487a59ab66d16343d42d316edf8d2cfbb324492e98865d6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab2166ebc6162beca7edd8f0770cb0af3dccb41e613940f841c7e601bc93db8afdb29960827c2245ae9bbad099458cf00000000000000000000000000000000117c22e8d504895ea1cbdce447698bca28affad52d01ec7817c2ef4d451dba46cff01364ca87cac4c0e3031ded1eefe01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ce43b125d8ac3323e9f08d13fd556207450e996433da1dc56fb634bac2422dd12d3e72ea8187a4fed7e6aece4ad25d0000000000000000000000000000000002893624b134e5e4ed4a6ea787b39b2140d7c6f0e7da65718a973874607dac91f3cc8299ff88ff656b5ce270889d38be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dbac43d51c70bfc0fa2265895ccd110a74e78e7900c1eb32e878a7a319a65de850e7111a1b4127720cc96ec53d7b75000000000000000000000000000000001219ecd60c5c62fde6f58d4174224e073e08c6b859032437f528867823cd73aef065938684cfc423d0a7c6c707b379d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016098b07be0a5e22e2d010f3b69745578f272ca4fc1a631843194f0a6d80228961f1197aff6eef549e430b77e36b93a100000000000000000000000000000000134bd264a3ea6c8a6f46771eca7d68a7cb8587dc988c0d9acfa15c766a1aad683fdcc07c32dd8160109eefc3dac1095c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad200a52be3dd4c621070312d35255b95ffa56153476998e0c603c12cbbb7df2fa2e3328dad1dfa8882b36f85bb9b0e000000000000000000000000000000001428eff2221b92061eb59bed1ddc8a3c292155ab515d0a12ff9e3095e009df65a9057cb2915f01bdb10c5fcbdbe3832a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a75476d362d3479410a431efc172aa09e6860fa1b7d74230aa8e104cd49de3ead3d4c6184619babe09cf5abf6d7d12f000000000000000000000000000000000bc07aa8979744705e2526b8962b0453d867dc03c9c0b788f1ee0643c0f12f551aad1ce3bcba1ecf8db7dac3df30d8a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001923f2229257a834002ce2f5cd1003be34c05775bc93be2fc953017fd361e1eb5534d4b373ddff2f105b3bef760856d900000000000000000000000000000000157c20830e7acc2484d2005fb9a055f603d6a2d930bfbf534094ecd336e39f7b763630a109f574d2dc13b338d4c0d62a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ad6f12838e1c8d9cfada32515c3d2b9a202988a2288385f9a218e64bb6bf53d7ac4ef5a0864dc54797aad0ad7272310000000000000000000000000000000016017f2cc8b4a4bb6b9fb24cf643e67411fa008cab0138681da6b89546492841e15724a761bf074fd99fa9cb725b5cb91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fcef5c0049a794b5a7918363636d393f87c3b34e225bb37aa1333348b4ddfe678254b1caaffbcdd25df1648363a261700000000000000000000000000000000175b56d2f43bda56dee6393ede61a075ec600c9d529f35dcbd228387bcc7cbd882c9012eccf2f6df46ee3cfc3eeeaf0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d49783696c7c6cd324a3f27ca5d38de3d014cf5e205ccd7a53a8257523f3a50dfdd973738b3a570a5adf6f5b3b41470000000000000000000000000000000000985eb4158fdcf22d7198d8016fd5d142f47a0681adc5e953df8478359a151328bb9618c12cec6f54696c1de892e7211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001050fb60a3c82453f68fc186ce3e1ed02f6ac8212861806b8fe29652c1875662d32e5fb073004c9f402154917552b6ef000000000000000000000000000000000e9dfc089d1505e13d0c41a915d720ac1b1175e78e0cfd3b420fe2bdae5aa580eeb164c7fe8837245433638c9c650c5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000706c3ce43fe463bf0250de2577108ecd8d068964e57dffa75714d54a6dd27b0f82ff46dd272d72f55207168972ff9010000000000000000000000000000000000fade45a4a41bcd1ca186017304e0db2e45c664b98175636e631167cd8632354ed715d07961d7c713ef80e50bd43d941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017bb6b3286c17986cc5c5f9efe88e58d3443d00c40a2b0ba9641ba54a6b0c7dcd64d955e494c5d92cb85976b896519830000000000000000000000000000000006afe9d4877065e46efe7b8c2780e0dd579eb59f51b330f8aa1fdc777660648f99d93c3eb500372c6267cace3ba3e5181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000057dcc480aaf282864be9274bf3ca7699d62995a592d8c644ff1f89b5a1b9097099e9de74c8f60d40753f7d41ce6a00000000000000000000000000000000002574a2583f1ee4049089f04986e9e1aad89a4f1e65db3dea058cf710bdf6d9c3abbb0bb40c85844b5faf4d865765ac21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df10fed4bb30c8f1612f7c9fdec4c93259d0fe2ac4a60a5eb839f1b8790238278840aac3cd2eb0673ec7590008ceb6200000000000000000000000000000000001cc197745bc860881dad6f36ef7c9f6328e942f3cc94efc323c9fc2bcee545b02b11092ff585345f0a8c966b57f7f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dff6ff2ffe2af6bd7a750d9b05cd79fe8c389f7e5e9fe9cf54f2ac374f40dc25011465e65081d27f577942d5e01275c000000000000000000000000000000000b5b417d7dfce5e19156b4b57f72fd95588e7a743850d92f0293de68a519af6adca00ee7b24192da81744f85b8eea83b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002107b07d573481e0e326ffa415a63b32ff50878775b83dc6263ef3830fe0f62e82f01965a5638c25b4dccb9b6c48cda000000000000000000000000000000001341554c70003b58a6cd0f8c1a5dd8ccd6c990487eccc7bb3bf5b4d4ee685e31ccb8d86010946f822c03ea1ecd2775f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a2d029f6427723df063531e523c0b3d53fcbb876962d4821a684c65b911905955fbc53ca193b829b785f689997c02a0000000000000000000000000000000011abcb59a45c6c79a53934adc0a1b2e2f03cbeb3952f24d3bd92f6b5abbe042964b17ddea720db3a610dad890f2d3c401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000070f17c0793c803b709111a90700bfaa3a2d618229ce8225be0c7a85808d92eed6f1ec1d9b44757c9cdd401cdf1c8ba50000000000000000000000000000000005a934358f8a7362c05a881a3bcc1da5fde19d6e43994f2e607b9308fa790153e41e454ecfda74caa8a689a2633c489b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013fcb0c935df793c1f25b489bebb38a1216c83a082cd234a8bc7ea728281230d886b770c8dc8cb6e66696675ea1548280000000000000000000000000000000007cea65bd10ac159d24bd2fd0532f7802bda997f4c31befdd2e799efc09cd23bd7cbd81359be49e4e2b29f269e53e7c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008251020287af5ebf948310b2d0c718f92a6bddaec3a456760a35bb8bf23651140a2bfb8960d10de187093588759011800000000000000000000000000000000166120e0a17c851841b6c6d7512c815f5e0b0f3e740c0c3c0f7cf0e7581bf02f28bf697c330ba0240d4e061ed7593ae41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c4d82516ff1762e0a44795b4687c8b8fbca63200b53340af38d0d41c0169e46925cb7c8a255255d175f82e42393b830000000000000000000000000000000019e7d8b7560c51d0311d795dca5b97471dec0b36f1efe52e90bb54f3dbd7b44b7edcb206596bd80ba68023fc94b5196c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014195c5169d2bc6d9d31a143317c55856535c1ccb4f3f401f656eee5e2e07224c04a82212b0b295f31960593950f967e000000000000000000000000000000000cc32f83d76d9faa17cc06550b7b2b5989d063b72c6d6a8658df7b03ff4177537a7412c82f8be81ed56a16d6529c48bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117dbe8d8513333f699863ebb7a604717eb4d3191fe34b3fb6bb42d3f5fdad6c0208df2014fa5237c6afe4b30ecc15710000000000000000000000000000000017bcdda756df685282981153f822e14472fa187bf105317c46f5c49c87cbfc94a2cbcd006b93e71c26d94d6368b8a3071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017138bffd5834ae1bc660c089dbcd8eeb913aa3aade8da8b7489b2eb87c5527ff392a4c429b6ffa0566bf825b2421e9a0000000000000000000000000000000016f7ddd23e3459eaee15b294f06ccbedb428c9c6934fd185b0d33325b91067c58eda147e3395ef3303898b9947c334f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ac27cc2d8552dc2a4cbc0cae91a3e5d178b6ac2ad498e74d1a284c9651130cf477fc58e000c6f88d5c191838d7b183000000000000000000000000000000000bb54d5035ecbb95a3ac7557c49c5f45bfb738ad39abb84f733fa9289efa9a7433d5e61a41a995a8ece7b3755ee179d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032f710645727bb1c49117baa7c7903962013737c40e3fea6300711ff3b77bff5af6810edd261547c44c12239e153a8c0000000000000000000000000000000008c8cdb9771e98e244cd75dfca38f23a0dfd504087f744137279ad252c1d52c34a0dcb7022c09d63711a05d00d4e41d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b7303e54b1ca9ec39fb3bbdf881c1427e66ebd6ed58bb6f591bbad6c0a0ae0a6d837c402e398273aa2d398a2329e3d00000000000000000000000000000000007dcaa47a5586a9b8fa0f373a96212c547b32b9ef376f36260fe8f85f6fd7a5ccc1b90a6fd5caada61f5bc361eb38dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016fdafb7768d900d2d900c4328a270dc2fcb6fcdf951aa1918e8e73f5c881673bce8e9691277bb35ddc72c04c9454a4c00000000000000000000000000000000089aae702b51201215ceac74a1ba557eb15c761ba5997d554539e98fd79d212a0231aa466f04b5595646ebe18d35acd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1ee6e4470ac294093804b610ff0c233b4587d80682ad00d041c2db61a76c3ca6563340121c1ddbb1f5f4d659045166000000000000000000000000000000000cb22831ab3a26a990991c18738b79e19acc423485fbf3caa0c0e08c2544c0da44afdb3ac4017252326cfcca725ce9c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d32a976a3308f49a0f8330be655033f3462ec55b7155c04085bfa77faa38fce70a76d557d892e5976123b8d4166d95000000000000000000000000000000000e32a70de4ca8e4ab9eae6b5e1daebbf8c5281ae16f732c34c1d8e4306fa790de9ed847165576c2d7e1771f417da33131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000251a8c1bdbfd43dbd739cc49df3d3f2dcd9eee2e481a6e4d9f988709ea1d507eaf0fd40c69b01c8d9fbb65f5789a5f4000000000000000000000000000000000dc0ca937eb55529ad999adf5c208590d1bd6551a3509f7faab2efe3be3feda9b2348044193bbc0a33e41eb14869dfd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013dec810a2ca7f2d46775d7c9dc7a9b9338619e6d1618bb6df5166f968770f2e4577b4632e01d9914e3470674367b70a00000000000000000000000000000000190cda6167278048b731b919d8973e12287fb104e8e1b7da26b83a9048bc7b78f0e26e5faf6e4d2ac97ba1f75ebe87161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c66a40ab2edccc6c79b358322a79792476409d798fefe32511a2265ace229c718afeb3fdc8a800995601a0a1499ba1d000000000000000000000000000000000577f65da4a815da54b5901c917485a7287a75e53e5d802f6addc4ef05643a979698bee00363f68265e03fe285f96d7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000172fec9f191804e66d23cbabf1363df207f1a2c83fb34486fa0cf4a7020b28c7fe3f14e272b02822a83647f6812681b600000000000000000000000000000000092bb316167a3dfab5ac6806a76a3493427a87909eb19ccc06d15ddc407a5bf1cefa13276b7a096cefc240ea23c43d671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ddfcf274889f9098cf717c130edd950d8be9f1a1658d1c69fa841dd7879a70cebeb4cfaea1c31bebd8fe250b1ba7e6e000000000000000000000000000000000f4e4ab4f559c5e142ad550a6d033b6a24cbe8c2f72aeab56b82f52531f1b8b901bd496f49c83f31eb44542ebfc8f2c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f284ef8c378290c7a07e4ba4c49079c5ec31096fcd8835aa8086d87bfc2bf460964b12cc87f9e1cf5a45a4ffda450c0000000000000000000000000000000011eeee3fa1edab6eed94181fce1473141a699c5c14800fe58713f44fcb42306ef94704df5c7ec1c42a294d7037a6f2161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018df084c8000add26252a8f2a5d128587888b50f31e01e017f748b420767e0121f6c1facdb03ebcf49e0631c85828da000000000000000000000000000000000fbee5702afd32030ddd485cca9918945bb9d7f6b8eddb8b49c87a698ad777a385b5a357e3d08fd9632f859167bae7cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ff3a9ddba8ea46bf9c4bf84b1a89f84bc892e4d327de415373862660052ac8961c37296a9e511e04e63d1522b51e7a000000000000000000000000000000000f706aa2e0c47d94c86985036c1e554f565b9052133c32734a154c29df6c675a1231aa1a129c6aff8b884e62b40118301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035578fcd95c71d64158abe7c208adbb5a1c3a9b5a76dab8113609fae680d2817cb60a547eab8647d163094efe4e3f63000000000000000000000000000000000d34d9fbb399e057d8f435068204b3058f1981121a5ecc63dfba9b969300496e45c19d167c2a480816f2ac59c79416211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c0811e41e5ce8cf7589f2abe9a65629a5935a9c778f5f3e8be6fa272a908f7324b1947a6e61d857e487d143be6fe8000000000000000000000000000000000074b16803126d7fd8bdc867c72d069a75139bd17be8a2e26292202220b1d3f2039e069cd4563656f35534648d6b1dff11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000abac46d9caf0e70f1c5ea33ba8acfe37a18a6df210219053a128f0a4ad89c246d4cabcc2ab452b3db97c0e24245f7bc0000000000000000000000000000000004da7a6230cbc0d75ad7d6d745846cedcaae5bbb7df5ef0138010e7890ac960876c5416c5dcc2d8b892a4d397ae3a4491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000106332e62070830a02876ef10d23016239edadc9dfe2ec041a7a85fe691c97991a8af8e3738b71c985a43ae40e51a4ae00000000000000000000000000000000116abb64db2f03b687249c66f444c4cc3b068bda06456a773a461a1131b3ec970e53d640f00953decad9500a2aaff21d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001cb777e1c9f77c6232f7a3ce1fa2f99cabb467241511f1ac40327ecf7bb8dfa0b201183f78932711dcf4a4f47a0968b0000000000000000000000000000000004199bb1b9681e4ca55746f9bec3dcd83cc07edb4736b025abd2d9aaf625a8e9f692768aa2f26e0b0c6dd5981b5816cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b00e370996680bc8f2113a09dcf94acd89dd74905dff81ccec15d3f8c68e0cd6489689fb070810fbe3e79da633721fe000000000000000000000000000000000d7381d520d5584f1d224497ae615484c2c887d1cb4d0554a02bdc72a0ef5c9a32ad0e27b25bb8c5f8f2afb6eb3a72b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107c1004ba60ca9603fc6a582f290247107c86812b9322247a055d4569a8648748e258e8d28cd41fd43c23e0024f2a90000000000000000000000000000000000b144d001a5da1bf1153513039a8cabe4697367edba05d74d17ddaeb29703b8e95f31352d711ed4bc2e75bb191211a811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f12da7234025c5fee95f6f6a50a63b2588993085f6ff097e59f8125afc2445335a04035b3a3a2b0f7233f3a2817e060000000000000000000000000000000002e19867c2bb015b56a86fd085729e55c69f2434684707073bb163f6c2f0675afb676653ca9a1a73ea2f79a645158f9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2cf49a05083c4d4ff93addf75f34ae7b09e98ad3d1624566fc40792ae6a75390eea45ca2061a2bfcc82b4dd9e93e9a000000000000000000000000000000000782cd194eb089160a6ec3819554efec099a6b47e3dd865d5dd3743f4bea19962f17aec1ef1a5e025abf770161ff8a751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b884ee2fa05a0625cbc2b241f9822977c0bac869a86e1c4ea553df124a755e920f633fc8bb9a14882cf81c16f9903c00000000000000000000000000000000033597121b1e5176dc3d91665fe2115385821575530852acf29b2f45e3a466fcd0cb28ab49863c8ffe8e4218d51c0d991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cbc36c1b71baeaebf662514ada557a7c07127e46a9b6bce2770c6b762c190248731902e65b7330dd04012b84375d440000000000000000000000000000000007d047eb9290ac0a2987287bdd3a5ebb180aff6e6da25f022dd94b8c9317c2bc081bb199f64123e8e698732819ce2ee71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001046a2b39c7341f9f36ca3b5da7186e184aba0936de635613e7eec9086806bb27cf8ea99e00f324dcecf03d1ceee7fef00000000000000000000000000000000131ac04f57d925a4d1174c166a387db81d1674862552f2783e6f0e38aab2a43b2d5ec158c6374a36195ab5abf3800b791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae01f62e61dbcd7e10c05327a54432be8aa14837608334f047516aedd8a3cf39c5a7ebab43e2f1354d09124558c55ba000000000000000000000000000000001059ceaa6ac2feaa425ba1df4c23845334419840cd31fd57d6e3fdac7a20390e9f575296ee1ddf563a647f685c75231b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a06a9f012e5be6900eaf1253eaf5331927dd4e032b563df7e135545768b422b1d16de295edf256b1e613b29389b4160000000000000000000000000000000017bc1cc1d2b2759e78b850e3dd83b257a98fb7c39e79c95b4fe5ffd496e80253c0a0f137be1fb71d33c7b73930e58b251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b102f8311187c0b84e622a0ed9c497fafdd6dfb39f8e40077cb68a268230c1b82be2c4b558ee04369d53ddcd9b5f0cd000000000000000000000000000000001725cc4af7985779bcd7af3936874530f4e2e99d753cd7c40dbc6df10f61c8b267b7d9161f235905e844e03cdbc5fb391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d27bad5d6734724bec530f5ebdb15c334599ebcfde49ca635bb373b991cdecb45fc2e3757162529b6266a77e906ee900000000000000000000000000000000003adde06f1f82a98f890b41f0bc9a3f56f45dc6a28ba67882021ef69f92a59968dc01e329df5bf3aa33fd4580afd7311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001480fe9796b03f65c2dfc8d7667c88f888d4559b84b9dea6f830af8715baf80951a1201bd9f6ccd3d8578344fd93c95c00000000000000000000000000000000004596ac83e4d53f8f9322afad8976d0378f41a54a9efd08ff81c10dceff0f0a8306d28692abce430d0783868dc4236c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000592a66e57b12f6dc54583d40654ed5e13610f729c4da9c9e56f81e76459fc83e6edfc97b6ed396d2b56973d1180283e000000000000000000000000000000000545eefd6097db75c33c16ca92df93f6701033f6a43f79970fceb1021c1b2c42d5b1ea4fbc1d21840b7112d0ddb6e9051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3d8b5783309e8bfa5e183128ef55906980e7797dac9f49772e3da92b7fdfdbbe377106adfff48bd8bf4f6c3ad39fa2000000000000000000000000000000000888bd6f1fb9cf82dd6b4c0b993aac19e3802b84f4990d3aab81d3adfb10327671ecd00aac394ea353c14a9c2685efbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f5d460d6e4cb387e2aef66046d0551e0d7b79e37fcfbc5847409e48aa49c578665e2f9951114a061f3f8043c9cd632000000000000000000000000000000000d7fe2a8d29c82d7c0eb5f2ec5f0cf22ed0a0e16b2e08b76d9635af481e3fe2eaf1196e64d577b981267ada0b2b78a9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122e53cb3b6f15b4609facd738166dfe707e925d1cc78a757da2ff1f7eb460646c109d9a6c19c07ecc76506ad8d5c0e3000000000000000000000000000000000f8822f15ea9890e0366e9497e5435a4b12d76db5bc1c2fbb057154d95ad238f2366ac179e7374730c6bee69e282b1091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199486c252e88ae64edd7996285ec0ae96b0f8c47adb17b911907dd47f889c54222b1e2cbc0bf813ad04e1cab2b72d71000000000000000000000000000000000c448c1102513d70f485011b83571bbdedf797cc8ddc7435f6078505851332761736dbf1aaeb85dd37cc1ac88375e5691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d099bbf190e608841e934025a6ad2813663029078d1a4cd55a138b4770d2eec66649bf1a8b2fc52de1d7e600b98fdaf00000000000000000000000000000000060d8359a72f8027c41fd95517f599e211718dd2b6cb7ee799c9d519b9af87aa39d0abdd7de87328870b633ac44075c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028de2d74c1e4115ca8e311ea8a3183da2b1da74e3d9d39024053d4747eece68a867b2fac606e6b9fb6a1a1b7bdfada80000000000000000000000000000000014a52d0a2bbc0da103bfbb41e33b42f2a2e25c3d2b6d8a461c879670d05328fc46bf76faea4d61fd2c39161675285a8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019feadb8aae9605128ef8a7e5e7464904692935b4aa0f071c83e5d764598bf22cab0d447bec2b75ebcd352f25dd29435000000000000000000000000000000000e29f99d5cd00b229437da308625e789ab51bbd7aa1ce07b3bf0fed81eadfc27644b4288cf3ecc4b7616706c9d19ce861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d47568f2e41d4f12e494ff1834b373d8e6e5751dea9a0f92326c90159a2a4a1a366bb7c246dc5e7c8268ff76f20f02a0000000000000000000000000000000002311c179d953bac57c7e78b1d47eb826bde900dba9e926a889111899a0a474db9e79b5308671ff55219249139a07c911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f558daa5331f7f71f8a5c202739d2667c94c7d4f8c4526cfabeca521ba817b59313b74252f025171e4215370571c9bc0000000000000000000000000000000005eb55a322d602619742e2c7a0789e59b932d2c06b463749bbd74b9585a2620fdf9dd9ab4a45fa13104531777fa07e6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c82b961e57d515ea0892781a80e90c379edf06a0e4c9f48caeffb1c27ed4da3f6a4aab4d606d4a4b030a2bd3b7ed60000000000000000000000000000000000d0d8d96ace834b3b78f655391cf0dc64b400da5a6dd3881f971dbf7839712d9cb2eea058ff7adb334adcdc7e370764f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000111da88adc2dc96023c63648302a2c6892cee147a19cda06f409fb59569e2df1b436b9c897eff4b97356035cba0ec0300000000000000000000000000000000015d4e9126a3b202fd1f6707ee5e106c08f595c1b80451d2707b9505ced85621fd0c714f08b2cc13747d913c3e668a2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129de780407a19165bf441c33ffb126eafe5cf19f374c0431bfecd5ce038220b24e396d86230a927e3dade4914e509fb00000000000000000000000000000000179545433a62b0a912d61595cfbd9f300e8eb51d01139afbd5b1c28bb01d326ab7dd21ea766628b606466a6550b235c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000664a3a100f40b55def8adc08dbb4e8a3531b6069b6d0713a6618e39b42ad66df85a343cfc5123474979e66158ef667e000000000000000000000000000000000db8e7e5a3d862009901b66445ee9ef8f6041a6767b313ca577eb5fab44612a2275eb0c3e7df29d58c28b051ff7ef2691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d49fd513593e6c0ee647d266b70b6f6b8948d3df30a4ead1682de173717e2bb66b0e6f1f3b04512ee3a312a94d9d801000000000000000000000000000000000dc35533dd3beba6af9c55b7bbdbf87f13fc848ae1db5f295c1fce35abbce45a0201c8f6b20f0b8f2372daf7e13985191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cae7d9c1dacd5873a94bd1a7ce4f7b317a4f0e4a00510e5b315a5284388df54ccaf66ab6343783c0537589388f12ef200000000000000000000000000000000129abad4ea7852061262bfaab3053fbb8eae6e2576cd0f20af335234acae3e3a2f6cfde127fd97286d338c88c0c48e531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000336adecfec05020cfef6717347a5f3877ddd4ded33549832a0ba2e561e155ee327c72919bbe42409cb4ce8df2860103000000000000000000000000000000000de555f8cd7244fc3276f91d9d8d093584c1f6ac75539f274666103311a6f244e51af045a85e708c12770a77946c31471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9807a293a298622afb0f97bccb054e6a14ca6e32153012a575edec52206f175ab35c3c267923b37a1ad286e947e85c0000000000000000000000000000000015a0284f984fddb790679a726fdfddcb703ae389b81956c2b7a9fd0bb8c4d1e7998aa80d23a616babe488616228c77bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082e8f8012e85a3f82afb9c796118fd554f818baf24426dd03d6f5169f068d8ad4a4e430401f333e7285e4ff29126e5e000000000000000000000000000000001927c2b87575c2896445c728e4c5201ec3e47fa8a5998d42b2676768407fa77dc101ba70e14633f9d819f670ae88370d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fed6c8682f5d8d469f2abb43fa89c061653921426777e0404a32f7730a14c6b1eb88d8edf45379fa90494405a1466ea00000000000000000000000000000000162642d55184cee24f6eee0bd25b0299e1c927bbabf5424d99194240ef7a626b28f4e54db88feef14a39821923fea7a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048fa1bc38671cc4b125c57d9db3d33c8c25925ffab2c5a9e9b86c526dcf4bf291554a0fe1996efd2ed087f8210747b10000000000000000000000000000000003847d6061e10036265421953407b10964213f5d5a641d43caf428a2958d29bdb3f338b4ea10a084dfbb4322a465305b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c16ff9d85b074ccc3b1a89fdd08cdf14871bcbb79e0fe2be07911e9d840798612a0e20553214a486b85ca4e5fd9b5c000000000000000000000000000000000ff6768f72be779f8efb59f0143377c370fe0aef64ecbc27b3349b653afa88766dd19371457a02d1157d5fdb2bd5abca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137b2dbb0d7692378d09d69a4c550c66b2469c6f0bd31d718392a5dbb3ea59b27329cbb10519d19e9446e233ea3e0e9a000000000000000000000000000000000d9f7c72854439fc4f6f7cad7792988200bd38cef7af378053b0da3404278223cb65c2524f4b607772dcc53775c0e06d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012dbb56d62c30dd9f922d7d187bdf37b5e1617caa4d57398248ebfca7bca05dd9535ec96ebbf85c270832d90a940143f0000000000000000000000000000000014360021fee7ca6deb29a469c740285323661a205df206a50adf93e7ae9e15eda6d0d009c3b304a10e5b18215e2b76371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008fdd1e5b1476661c2571e14b8a2e3554bdddc69a5658f288e10d06f7f03a4dfde60a81da963b3d0097993d519f21731000000000000000000000000000000001106b929bd96bae00eff5cfc8560010ad02abcb0132e1abadb46dbc4143a492ab73e387ba63dec5af50a0ed8dcb3c7011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132425bd7886d3e028ee3cf137c28416888cebd8f738a30cf665d3b2d2e0d41bd979017f061bb7fa74a0b6081267bb0e0000000000000000000000000000000000cbb80711a010c484c164e4ec7054c79cf968004012e4a02dc2b38edf66ff8fa94f73323f3e347508082018d00a6e9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b293d1abed211a04772d5264d2b1c0e66fdb45fa4de64245736714a3671fb25e5dfd6215127ba5b2b452bb4144d74f0000000000000000000000000000000013e33258dfb5493b3590da48471b38ff7bb5f9a5973def9d7a7584c7b9610c1c23df1591ab4fe94984f21ba9089c46ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043fcb2ed212142227e7c8a7758f52ec40dc9f81203b10e40e55498703725f88bd314d7ca005606fb9a9a32de43edbc50000000000000000000000000000000004514fd3473a382e9b17b7fbc42c5b16804303e73f82c65f89879ebd8852aab9f453e9816fc797309fca8fe05988f2401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f39f47e7c9c2daed27c9288be45ff7497dce932f0aae9dd1366078692a75d3ef375d7ec571ae0fe1d87d035723e7a70000000000000000000000000000000000256e69eab6fb139d1b11dd0b08c6d75030f79194ece0a4e29c2708dec3bb377a482633c264d91ab21b07141774b30e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a844b1a5edd3f0e29e6f65e247803075f114f0e119a5aab240b006aabb30f6c18f8bd1b5ea2b308e63d392f37912f200000000000000000000000000000000155c5f7d8339238bafbd02a37d718bb75af164701e2b480ed74aaf93157eae8e63aa58cd47d63bf3edf7c0823d9c6af11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f36636831274066ff32dc0e98ac9b4367351da7ae88fd7789212ea9cc675625f075f767cc5e70300bc757dde79d1581000000000000000000000000000000001915afa483bc0e7437305611efd47baa29f9ad6ce8a177af2c516044448ace10f5db1926f3f9272c32049a03acd5b3511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001262108681725ba3312474398ca7af16e9c381371755d5c64760d987ce7b844ef7c1a808074b9891dbd92ad5fe9234130000000000000000000000000000000012be468db76f5e3fb609a222a6298b8d825d8f2f642cfae4ffe20fc5be8d712a3735d5b9e0518a4964dae2c545d92f7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015e4619e5b94b3c0790784d502ac4e3d094ff44b260f66dc71d7a40e58f54fb08c2ad817a3a0c07a6391b18515f740b0000000000000000000000000000000014ebcc4a6daccf4b8303d8563bc5c4eab1812d3449a27d513d36804c24e6de02abe4d291391d84fca271980c506570571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a2a0248f14093763ced150093fa47f3fd8b30d72ef156a6253017c03a089e99282a5ee332d0a75ac5dd58838eab6ab000000000000000000000000000000000b7527990d34345433ec6742263a8a173ff12f453e010b7e8b18880c4c1a50074d9981ac3ae525d0e1d6f0a6993cd57c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021d79fe29b950a5ed3115cf1d0ac09bbd98ff54da53ad230d4d18bbeb6a3b1141cf8e809ae7758a14be791e93aaee530000000000000000000000000000000009720864c6c10aa1ff281f969c485168a32b34289787410e486c883fc1d9636a2cad087b30d8c06cb87af117d86a76a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006201b99a234aa8ae87cbeb24255996099a0f7130e8fb6821d6741a9eab1009f39e3c22f45cd4dee9f59f5e06b6afb230000000000000000000000000000000014be94cd8549172b1bafbed136569a9584d0783f0919f8b666dba37f5485999210a9879ea5aafb6e825d81616e2e005e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d8c346962286318d25f34136f8760db46c0cddb94b0b556a835ad5a847dff30692ba53cab49a9344959056cbbc89670000000000000000000000000000000012e656921d9a268b02b5a08ec1dc2b96a51ede435eebf63fd176f88339254512a06da55497448ceb321eb7565789f2961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a2e91a24275d7ad56c54b3a4570f1882c91431c374df88852581540a2f2de8d5d866935848e84b3b0fdc318228b40e000000000000000000000000000000000efda833e49d32c9568a4c07f69ac18e72070c82a2fd404f09f28427ebf9ce88ed0648f519e893a6760d7fb2d6fea46e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000096f6abc385b15828fdcfa2f914fba28845792d76027f1a857fff57ccf4f7f6f1344681731bcf89d44ed3d554b7bf86d0000000000000000000000000000000006ce6abaea1eb2322abf1151783726f2db845051455cee92222ce3c297f49e1611cc5b8b69b6702963f1364a0e0db2531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134d0455a5d0b830a4cd8c1f5cd6a4565fa975b68aa3e8586d4c13709af49b0702d24547d226e12e0a2164bb3ca23e920000000000000000000000000000000002eea83a11b629b04c2b859f14e8d64e90c81d1a65c10a632de2431a7ce4badc74756afb7feb28366cf34a0cebe9d1311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a3fdde0e2ec331e63c9de21b9daf29f6664c71197f3a19313ba0b24baaca69759bdaf41945986bc125b92f4b1de9f56000000000000000000000000000000000702926c2ad3cd2b5e6963d391b2ba7aaf73d8807d6acd5d13e7b699ad0b4d17e191ab2538dacd890247164d8551c2671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000784fc8227e05aa5af690a0907cbc61e821b973b5f38ec87722645a68c4a9bfee2a023231dbeb5ed654a6b9895a962a30000000000000000000000000000000012089505a283413757dc86d57aca300ae55404893c40e8dfd7650805c8d36000ea1d2aaa52ca3be104919a64667524c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc6d9dc8a9d12dfdeff75f84d6cdf46cc3eefbebe5693a343bf8f065dd7a1b0f07a055dd204ccbc50e7de57a255043e0000000000000000000000000000000002b30ee9154520136af5e00b41cea3d197fb16638c8b0e27db04ef26b2beb1f0524c030aa12207f04dade06140eb646a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071068aeb2da0abd740945ac95eb1315fc3ee36546daa98ff19df32cb2268de75811795c4c857b51d15b5af77fa21936000000000000000000000000000000001383def2963220133f9e53ffb011110b277d929991475447427811a96277bc7a0f8d73692d038de255c29ef0a26b54411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa8d41f8d2e406223512da2eb25a3a84ee60a5f6e7fa7c08db9825042c87e1660b7609acb2420ab2cf6b47400a6e97300000000000000000000000000000000084f590c23d03506246f586be8b92ef1a8e6bea8c5cdb68e6496cef9954c3aadb304629bd3c94842968e99ae62b029731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000140ab4595f7f621bb57375a14261836f1ae53026b5adc1229cbe2fd0f18707139867d38ea3510d895917e6e46b41ba9000000000000000000000000000000000b3ee0ef74b0b2058ac914be5747c57c56b576dae3f7a6ee375e2f9b637d282a258c43b6b2a808ae63b8ccbc2f0c0af11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003edd1471e326b302f326907410ed05d15eda89649a2cbed0c8a8e39dd43d310d6a6d942b7a2ee3a3cd785b52f7a911e00000000000000000000000000000000038797a0b7fee56c950d0068860c111e6a1e1986d78b4425948d94820765620d2a925f8d4af88f863ddc1886ff716c3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d11e26b94fd0226dc45bef20ca2b121b53f1e01373d3d11c330db54edbfcbc51131c86396c232f388a8fd16e7d175880000000000000000000000000000000007a4db4cee29cf75d92597592d2a02baf5328979a273545638b4d06f96c0d1705f61ea3bdb6c3a3ca547ec7db2ad86071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e2185ef1543229ef5ee3d21b204e716f6010370dcb0585e7b1a8dc4629bc06b145406d1513de19270659b373e6ab34000000000000000000000000000000000bca21e7992b37521e9123f2c52e8769b99a47111f72bec767e87f10661957f71ea30ebb985bccdb17d353889ec8c6891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010040a77f16295aa94e7b376dfee5f3a4d535b9c8672d145f884eb91a40240f23711f0f7cba72f71ee0f2770b9eeecdf00000000000000000000000000000000083bb9bb523c71c9f6721d4fe52fc4b6275934248ebfae16bf4b0c7be0de755d2bffd6a37598ca6ff6266f22f4774abf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea29ab29c9191c2c7ca467c955b4a115936d2da83c659e7e53f9fce891e7df1b9e61c75172809285c75d40e22f479010000000000000000000000000000000016afc4c395ec6b108837af8a532f39193030ce1e13dffa12f4cdf0fea039d1b659b75e929689bd65f9f7b5f7b5b4fc161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004aa6ece79e12ac8f3285112bf86ff83273294626b73f1613a8759a83cc72dda5d86384a363e6e2f93b7db6130cc8c450000000000000000000000000000000006640019ee46b667aeadd7983370bd3548363af90e2d147969e7cec178f591f7e3eb8a9f9c2acda150090368c26add711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1417080ba8a76d823e53e3f61e071fb674675bab023dfb671607a080a4f9aeb0304000bd40bca43548029dbfbb7128000000000000000000000000000000000ee7d58874226097c28f45a33f6404ebc4671ce782a10d833b8f94a352476677a998ac49d4d4d2a815a807848962f1b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128686dc4b42ea97f0d5302d6323002f7b7e0265610fb4a3a79864bf8ea8ef5c4aa357122fa1079043f8ad827b7a084f000000000000000000000000000000000f461b1ee6f52ebd5a451cf7b1595b79bddf592d25d34e46fd8f2ad7eca4bf30120c3692d325326cc3ad039af645f3961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f96d0eaf9e0317e14bb70e31c94f0d1f2d3bbfecfb30ea93f34a7e5071506848e07ec4c3af118f61267738acc6fce150000000000000000000000000000000019f5cca6d3b55e45e44d496cc403f771813658f368897588fda43f37a809b2aaf95c7d79f2e974586ff47ea7e2a9003d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a504b68bf21c0ac56bdce3783c79d1ea7dd2c6ce7164446dc1dd3564b2a1a9a99ad47bec04cc83f545564d2f0e3538d000000000000000000000000000000001437eacfb3ee21dc4514212d9b9b7fb6cf24b641718e9ebd58ffde0ca9e7fa7f899ac802f10ada25b6210a8452cb09691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050c3d3ac8b00656caae1bf4280b3bbfa252afca51131d646e4aba719201da4661bdf888b7697a020309b7840f88a31d00000000000000000000000000000000026e116bd461efe94dc5452f79c3f22e55cf70a1cf0be9cff72d07737fe3c4b3267394bca3b3cb70d978bec302bf39721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000807c713d4a50ee84cd091a02b84cd70b305e73184dc563f3db1d9b05de2f28b4ba0df1a97916dc986984fdceb173ba0000000000000000000000000000000000f65b71408435e838418f3af58b8d083d9992307ef94cbac612d16ee1d27796424c7f68e97ea7c98e3f93779ff4e87571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a9c5a37ecdf4846c449792ae970b62b7328096b4bbb960a16df355089c8b84cd16abd9d8acb3fe9d8c19ccf01a2253000000000000000000000000000000000ce16d316333193824dc70268e75db57adf9aec968f45397a51fcfae4cf6fd70c4cf785b78adaee730611718267b36361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e64bd95f001be6408638e93a21f4ad4dcb5d33a763c4bade8d56ac031de63fc373ad14ea3467c49889d285a40595900000000000000000000000000000000005f3aec71bc0cb4621c60ccae169431c7af732e8a5a59afe83d0f4cfd734da361ca2f66cb13ef1310f70c2b56221e9a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092a1b5d85957280d8fb1ab5a60aa3d84e73ba935d81451e979ebfef460d7c9f7f914abf05f3cfc500e21f3c270d9f9c000000000000000000000000000000000d60a01b7bb45463287e38b71840da4026fe211d86ebb4b8c46064e60bb2ea14559249b4ba32080dacb18c6316cfa22d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000947a1cb2a25f313d93f4e0d6ada5e74b5103b5e166bebc0ba01ef685889ff4d4f76801f1663f27acd18e64bac3d56950000000000000000000000000000000011dc2f55c63d7ed56344cfccc286c4ebbe19061307935b05dafc2ef147f268a184fcf4fbb4e9785a7e381fef42d0282b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005d33f385a650ec8ea8bbcb4a3825aeec9fea1f1fff223f3b6eaa9f14fb03d0ad071b42b148095d05c77fdcd8b451260000000000000000000000000000000018bb939b20c3530a46be3c8f44376a5ad6b95c1f8ac2ab132c8263dd3d404e31afd48a1d88b646e3229f6e1f397de15e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015726d0020f9e63c3b41474a4d6c6d63f5d029b06ea161c75ae07a9895c26fd384f4a532f8b4a4849425a207326c2eb2000000000000000000000000000000000fa11e3367947c4159fd5fc5a223ae5de5472404050232e9f536a64718a95d0ae028cb9731f81c9059c1873a130dd3791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a4f288141024e4007ceb89522a8cb9d4cba74f1b947fef8976d13a0ead1edb02c76a6e891293c5f05c0070f48c39f50000000000000000000000000000000014ae87e5597ca97cbc3a02e1e776ddd2c04263fd62ad374681687f2fb7f24f760eab408d56b990d2b7e45f7311a2602f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001828d39e38ca7da6fcd893eedc0806508083932c5f15eae3ba072b3aceb097dba204ce5b9d11c0b09bcaf497336885300000000000000000000000000000000003832d343959621e339959b164bdff6764f2c02875e9c716ede4c21a47623df6474ac951167fbdb6cf8687b8cc0026a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120c1f59ce78b7319833a3c1f12697682a81e76f112e2678823241c953978abbfb38241979c1cab0ce50841e2679d3e90000000000000000000000000000000015fdad8707d644fa921198d4ede58e1a845ba04142069fc7f9d824d801ac09887a43573a70fd92184c154786788a3d511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001510e382500eeba249fed5687c13a344f301fad613c715e2664bb9d8dda8f56dcc09b82502daed6c5b3efe6fbc0321ec0000000000000000000000000000000005c1774a417215d654ae9a73396b8a5f2eb0f85e317c0e08f63d9a1c584373b1cf7807f6a536c2c085277d0171bb52701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8a208f76058b3430d81ca13e742fe5714b46e10ee0672bc966f889e43dc199f4dcd958e9a46a7199cf1d7b423e60fa00000000000000000000000000000000071723a892470433832b0b41743a5df692e13b08de622db6564a690995a5618155db638fa079b7534f8cbd5032e61a071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b444a33a3e0b81682cf09f78eb502faf52cfe4704d73e03413667e8a2c4b0e859348f01e99b8aa6a519f62ccdc23c15000000000000000000000000000000001262cfbebc08972b003a3fa79a1db786a777adc309c1a7dcb12a497d11cea5241e8a9fdf66049333fa0b1cc0407148491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d91f825aca6aa44baed28a6f4a6c081f4859ef9a51f6d9bf21afc78d3958650923b9245f78cd7ca7cfa5f5c7b145a9000000000000000000000000000000000f0cef2229837da6e933672ba382660e28d8f199b235f9d880386b646258ac6864ea3bafd3d8eb36e1ba376246927a241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ae3005befd604b001cc0889364493a011afd35943bff70c6b239547dd142bee8971227eec32b2deb2e8230f3e52f02000000000000000000000000000000000169929da3186f1092f9b170fa734edfb6275f6c42ab9e9d7c083e219d6a3543522ec8ce16d333e4a33e6304bd3f1b931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ade6a3630e120927a568c3c5e7af3a7f2167ffe9ac47ea5541c2449615837e4012af1f8ab32455a0cc2f7578b405350000000000000000000000000000000009a0ce5c7cb8051b095b6e66d6ccee9234d5a6b175b43d2479d18ade111abf054398db47f7014d64997f6e43eee5d4d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006774f98386d0f7bf14df73f958e6eebf4338c19f82d2d31e7930c9841570e992620f764de7fc905385fd14b9149b2cc0000000000000000000000000000000019ee9c785c1e93aec20c6bde989f3f38e998aa044b034d81b0de2d6a7facbd3cdbd0781a2415e463e856c634c4661ac81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050991fdf32388a015b4599986def2d2481be8bf4331700c9bf201e34bb74f2f862ff6760d048f21635517957d27101700000000000000000000000000000000185e035b9f9b736b0fd2cf539144d36ee7e6d42a96990f4f1f2a4f9e3f2fc84d0dcce47e8154e2048523c40fbff28c071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001990ca1a9bb9d36539ebd8b63ce7151095c61b64a74e5c38cce158855907d1d15adc46bb478c6e169dc0ad595460b3ef000000000000000000000000000000001646ecf66583a86502c4905a5c2b57cf373272c26273d9d9118d469ea602b56a636ff96f7e3905a3918d5ec22ac9dbd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014789a9c564be2817dd5806b3fb47697d3936e773f2773b20cd4a65f096da1dc754c3242cad108d01f2ed4ae8df84afa0000000000000000000000000000000010f2ec772ca0ef7afffb31030d4529f711aa103576f369b129effe41f800f7148ae15d45783f9aa899db1e60285265751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111aec3f4f6bd8b8d28c9a331ef9d8f796f8a87d6603b333f8d6d7772a07513d5cd86dc3e2f9d5a48e9338068f5e5fbc0000000000000000000000000000000016f81f4c7ad03aa15e26ebeae68697ffacd5ddb967c48161f33381832128bbfb1151d9879d44cb37b63a5309bc93d8a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092120f271df91567f708efa79a955eab379adefa7ec29fb72e8f9fee34932bcb7fa3ffd9e0db0c733122f2f0c5c942a000000000000000000000000000000001619ed78f7fb4da227cf8d82d18d9a0726c350bd5d3d0fae6e74720e5c6764b51033bbc4c01049bdf4ee3fde659e37e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d29cb0f63cd86d5671fe582776db03b13ba37cfd659a36f320ee3f914ea592eaade5b939a77ef8e13fca309dd3b8ea0000000000000000000000000000000005f6df9875b49cae712a0e1b2b2f03fa5d4ec2d939cafe59110132fcb63ffb2cc784c5762e9f654b4172721a5a649ff51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d164b70bf9f7ef5dfcf18e7b072c7cd630472403c8a4226c884adecccdfc2e317c7273b95b763d09296374f9a1385a40000000000000000000000000000000009224caab937b4662b328469f75508e78801682964cbfd2e51f25ff457d5d34347106aba9cc9fde0ada323fb25a616a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d9912072511fa6f7822e81115daa21cf39ffac1caa5b4874171362a59d38df43453b758ab57a09e8878043315ebf36000000000000000000000000000000001487d30f8d55168b3eb47e245bf87b1f8bb3b9fac16a3717fa2932d6ca8f4f2d228ab76cfd36e8d39f659947b62f8d5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d985a9d46492436396cbbc9e5c7f14f99e4a95807b871c80e2585339abcb5103573e4876e6823854e125740583629400000000000000000000000000000000030c09af0a495f43c07f54a8dfe030232d872abae7166206c91fc807f3e5c0d2b3ea6159c75527040d0f5cf35838e2221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019070cb800c50384bc62ba5a4b170472c259f105cdecf95a295163cf8c0d62f9c052cd0f1969088d1c08f33413e82bf40000000000000000000000000000000005269a5f60561d08f018ac09afbb8cebd39a9b22bde4cf2135a10e774e95df33a1f4214cb54a067af8478917166171541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7a23044d93c7b03a7766069cac6653fab8d1a117606c5ebb77456a3d08e774d1f21800fd4f23cd064964dd219dc94b00000000000000000000000000000000055583fa48d767606efd6c82f1c0ae1e6d56dbcb26c8caeb551a2c5f40ab8dcba9007e3bb2357a4cb9a523518b9c0c051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017faa20074845a1bb02392b00034d2196303a5be345fcac09757d33ab6c66b352ea18067c793d616f0dbd0c82a9b58ae000000000000000000000000000000001153141d5ce7b746e047c3a84e1e9029176e94a0db2fabe1015dbacd4c1c8f2c97f57bf4d928000a6c7cf48b582c54f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d8a8624c32dfbb770292ccfe5b18a672cdee8cb606b6ddc3e7cc9620926d512ea316cc5b613a82b4c60eab93bcaadb0000000000000000000000000000000006bbaf464d8bf9bcdee81d1aab424b0b3c08daffb4ead83de5119b628a8ce358824b5c72bd4de0d2ac5a897e418805d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6b6d3151f71be86febeb269eaa1feba37c3258000a667106de4b1ac84d91355ef37229251654f8ad83ba0f10321e55000000000000000000000000000000000b480e1ddd10a0758767afda0ae6bb0767c1d1a4833a5f4af323354906c62e66bc2330598e07bbd0dbf90af320c77ce21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd420a8a44016b806fb0db97b87e92b793ab48df243469e187230c19b262febfd8ea4801b39f2f1f1796cc6de21389f0000000000000000000000000000000005708499c87788c2b49ae9c08b5a4bbd782fea43ea68a6aa0926f5fb4c8a6120a7d00a4e861e0a4a0108736d04c46b6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000397d9b1ea0c17ba8bfba39ba8b9a7c7d23518507a95d53ed70a1490164ca7e42378ca5e3bd2f846b164c06bfba8d51d00000000000000000000000000000000062651d43715ff392f89d65370585cb36d760ff35a17e07f637ee9a1ac654981a19b667bd3d8d7d8d504fdf00413f3271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c5b2100522c7500740520357ade93be758008696ab6bfc82120aa1e56e352891e1c2a944a9fb91f182a2eb391b03d2000000000000000000000000000000000f3e921ca36af5d2b5f984a0c8edd38f4decba458641f3a907c323cfe243e12f6f853cc62aded980d1cc84f6bc4ee50d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d192b60876957a35dae510fcbac59832e5476310195438f636aaee2d6314544fa99aa5a7e798d51d7f8764f915b4521000000000000000000000000000000000df53768b4aae77c7f23f74d595d10fa10be44939449cda1f1f74f4f0eb4371982d960207ed5aeceefe2f7e4dac4e5ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006db91cec22ebe5c50c7ee16a126c6897efb97ef04e3f45c0f1e13b69faa3245293baeb6b43ccfef5b52b45e8e8e40d1000000000000000000000000000000000fb6caaaeba72291edc9c89cc3e96a28cc24d78d4646d12d97afd7957c5775d13a846ed32a4f255e03fafc6846b024511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004eec3f5c26327b54b03e7990b8d0f7745806a08ffd1a3192d43b458d7f4b00fbb81546f44fcd5fa02922f5ee158aada0000000000000000000000000000000011a13917c75cac2515193aadc239ec2cb4da1e6e11baed1410ad62e02ac63784616d96f48f17b54651076755454e77a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000279b8d4fb13bfcba38a5b6c92eaee084fc851dae3b0623ea1df13e01c18a3051072e977b61239817a8bebc17afbe266000000000000000000000000000000000e93ca08e7f8c8306a9e39d4ae0793e85fce82c40ce51266e7565988ec68129f0dc6bccb15cbe1932e8c81269d4457481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd944d3b3e96eecc15362150ba661cbff971e6cf1f828c95e6fba00416807605f0f3a367d35e174c6dbc80b1b8e43ad000000000000000000000000000000001069a552e0a77834d73da735b008b789fea422f3b2b19cea5c73127c6d14d172b928d9324074d8458d3f4028a5c8757f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0a9c4fa316d0a65b6d8ae371d8809a5eff2f4c47a58bbb1732e4fad64bd5e077bbea2badd59f1729a0b702f2d7c2970000000000000000000000000000000017e55870c8642711b162a7583d18983bf6f83b2b4479902650257e16b1ce951980aadf1b0c16165c092943481298d1281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014323197fd8f200b247ee900bbb4328f728286a11b9dd5edd9f8d2a3cdeb4a0b955cbdd836287d2d68ab69a25a565250000000000000000000000000000000002f88372fcee5f480a6ad826b5af5dd4a68a7b5660561e239893a8a361bae2195957094139788e3edb5738b73028a8da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003854dd74698295891ee1b5acb5b8978c82a7142f911d5d8abad84410a7207daa1d2c41bcdbdc66c56e5be5c90ea4c2b000000000000000000000000000000001440e15cbf14d10122307f8e29a94336060b4a441ffbbfd6cd482f7ca1dd4ef5fe57eafd2b49df8ea1fc19e9e7899d211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154d23e35c67a231551231b43d695d66bc01a78a044de8762e215aa7871daee6e50033430ec610e021983dd540d3a9dd00000000000000000000000000000000104eb4dbd6402e898d25111bc30b773c4382133a3c2afe5e56e2e873f1adff57450fbd719adbe10f12ec8446300703471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3cbbcb0ddb83a08379eae978fe444cb913020fd841b2b3ba432850aa6d3e29e46de6d07436ba552e8c7ab42d03e06e000000000000000000000000000000001745929db2ecdae61686a28f8d6589570c29bda7b5775c0a31a12a0e55805586d3cf06e76931d5622b00a551c2b265401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016003bc892e78edff115d0d88da2349791d9d761dec16e22fecbde28067f1300b83e1e9787e7f5afb4ea05d08f8ca4e7000000000000000000000000000000000a6dbdb86b7ce1c6528144dd7db8ca744b8ed7227c5de419cad9c2bbfdbf54f38db655b667c1a2b46a17b1cac5069e551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035125ed32b045f767649f54be7f68006dd965a56fdea04f4a3a3e0f11cc11617e4f94a315ad6250c7839e74d91421b80000000000000000000000000000000012a61f52b5f69f426451d09353aa0674f09a99e8bbe9ded79fc96ae755ddef0e06c5d013d9cf7cc30e0458a04f1b6fe71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf91ff84184820e9dbe1363ada1d7974ce67196f6d0c4a652277422500a11e5b3c92f920ad68340abb297170a0b68d40000000000000000000000000000000005afc91a88a02e8024266cb70aa48a7b7a0e21fd9fa908c5220ec2f3a1dcda6b8c1316318b1370db1896e9f2e48bd76f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001348af7ae01f1680502f95d7766f58b58090cba891aa6bad7d3c8add8e1cd210a44017f4c4c50eb2a64e07875b08d803000000000000000000000000000000000877719ea4899f88e200cab5e3dd2f450f58a4926742ccbb21236ea25bd49b5afc18f6f1057e411c11638b0646fbcfff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053671bb429e57201fb396a8a9bbf88c3416703e46260a29dae767c652dbc3db6d9f4bd9b70ec9229802d1ef9e433156000000000000000000000000000000000c9da36de9f6d287bf762277bebd3804569526d9e993fe34677d5945baee89c5fe1e9439d9382736e7ee963862abdb3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176670ede37e89fb10ea865f02864484c88b8ef598a0ab0cf0c115b6548c796188cb64f2aebade923ab990c0164c1b810000000000000000000000000000000002c7d0f101ffead3baf97b392ee7e4275d60c7632a472e0ef07a4700de8c056d8f6db5b20f463c065bab21b907a074a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c20981c0facebdafe00119f2fab2114c6af3864f1a088e24e896d6f2f9b756e06f282f12db8d1d5f5b41e7ee23792c0000000000000000000000000000000006f504bf3b85c64d744f33d248ca3b7a31fd0b534b430b156c36f379880ba2538ee1a691c9671d550ffa9fb40cc8e28c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000038f7882b4bc43082913fda01e8e4a309dfe886185eff9fea61864276d25657ce5986b60dc1ade7a77cb5835ec07fd0400000000000000000000000000000000164eec14bdbf9a0cb9075cba4b97a0599c01a6ec2a8b9d3299c00c12f030a5e2fea2d3c44acd95740e4d2028a9d51fd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031f4ebb8c150a2bc7f6dab0dfe4b26af2d4777ee19ed2e580deba92acae59bb65cfb939992a607b61c4293ae3c319540000000000000000000000000000000009f6b9d81cc4231c9e33150b6fc5e924b11de4d04d4eaa81dbaf50193918dc681cb627ad2ca580eb87f9af1bfe9ecb541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa581fe30b5e16816b22b70e2c45ffd672b594ff2c6de7d1029c11775dd94a0469478e09669ecd78d8651627f332a3d000000000000000000000000000000000841ebe1612e4122f05d05999a42585191514583c3aa737c0e0bc7fc757b30973372cd5b8251efe77bfcb4fd8d8a04d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f1a51be048b40d4377ad41c2444646db8c351ac0e0a8599780b68b02a7528301a74431221f82f86f365a1dc984b25000000000000000000000000000000000042755042476f2aa1d3d85dc9b23f566b5dcf4d2101169f72bcca1114a5966b4b93bbb734042a8ef253b4ad0476c8bfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d9e10771dc796a70aa29e8c9effdb3ad12a394f4b84938d518e2ee7f21804ca50a725e900fa9f33894a94762614250000000000000000000000000000000000e12fc5826661c0147d1d09945d125dad846d055d2047a554f2f67201b4e9407f3ccf8597d7b531e02527d6b9aa37a4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b3246c84b29c836e681cf9b0844e536bcb536a034df74eadbe0d3a65342e52aa77bf1aba2cbfe031cba1cdc3ae8ac6000000000000000000000000000000000b0264f63019ea555736fccffb02c73a7e7c1d174a37f2b1e584a5eca336702a6ef912b8ee5a2334fa1fc67af9d082f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001911ea7d4c3b832311daf9ea2187a9c2dc2786bdadcbd095ca389951c6c00b83bdd2a766c6861ccbdb2b76d69d4b1754000000000000000000000000000000000f3f165c12df6a03cab03a058fbfdb2695fb48ed00b1a9afc58145c2dc226cff0da1e23622689505595401adb03e05fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ebe29ad202153071b8a0075c08e78a205fde58111347b38ad63227cb9c015b79858d01c0cf053160a93046e57caec60000000000000000000000000000000007ae8292a178e10192c871ab6f4345eed8b50ea01e717506943384b5ebdb4f66ea1f940d7b699b1e1470e25ee729c1871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000136516bc261991696ec38aa4e0b484edac0ff8dcb1f4954c2e13b977cfd7b5413f5c149ee45c14a3df6427e9c4d5b90000000000000000000000000000000011e07424e789a146d99810f5aae0ee9fcfb94ed499154dde6582024c56931d34fca37f502359e0e3db624109067d39f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001482a7cbb8a08ac6c58bdaca01ebdc96c3583c292b9a6b0e634bfc340564edfe5e1b1c382a4608a1a703aa65377852170000000000000000000000000000000000557b5b5d9325631b320d553c1445855ac1ff861bf743cc6792a879a5d89133eabe8b9058cc8726330693465eff19d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ca7649db2e9ff4a27694027c61a18136c0ce7253cb49a744bc9bfcb2eeb0f9508553fffded834ad0f9a4ef7b86be830000000000000000000000000000000013a34de5bfb7bdc6dff720204466200e4a13d884756990f9da79a1e4e5df5ed88de148c916dd7a510376a160b733ffcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c6ebf0b8c8ca12d17cf430780f22b5fce6a1abd593169cdae862bb500594d97e3ac432df1fdf389bb40665a69103230000000000000000000000000000000014ac7474ad52abd4b31fa37e222a390700dc01c94cb5b7465febd669dd7d759a3e867d2caef07d5db22cbe8ad42f5f561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccb8588eea17564ac421af3ec356d161b951644e718e4da16c80556e912dddcf5264a429ed705f7852ce98efdd1babb000000000000000000000000000000001353e0bde13391585bb156989fb531c3711adc5e86893545054075c792fddb4dc566374707d61b57dfd8b1f24d01fea21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006dd3a31a46223be524b6d00a855764673460829d6fcf8ac686f128fa7fdde71d487cacf493eeb2de3387f74e085c23d000000000000000000000000000000000d2b299805bb732a097f041be32094479c001fab61fb8c8f210e4f22e87fc2b3cbbb40b45051d8259088e8306b39f4e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017852a34cea9d72a0f06b44f78ce7f0a64622f91e00af204074b0469e5b14b4a98a71741f1ae4d21f6d273c8022296a7000000000000000000000000000000001800e70ec3327f20c9043513551d2d792960bc09eeff27fc6b821d324f66b3473e97a1f074c1ccfa3fff9379bb2263041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001023e0ca5a8b960aaae50e4525a56c03bbe1da7e90f4e83b6c36d1307635b5558ebd705c22504b73792bf28049d8ab560000000000000000000000000000000008cdfc8b95133d9567f970f56c7c6f0995d9b464e25ae9db5fbcfc09c3749f83f65823bde2c16a9dbdb2b2c574f09c771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011952e955fedbbed36cb4d2911a6e9e4cd167f456832a463b1f1988ae32f40751bd195d5b1e9686ab428ac637bcf7fcf00000000000000000000000000000000034decb4999ccd3b3b69a302fddb3bdf12b5939776d1e32334c4ccb4c95d2aba45673407de47347ce57fa8a92dcba8fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc12455dad0fd38c8dc3008d3ccab64e03366b6fbd07e199595e42d0d45c3581d92b8cc4cd828d60acc0d68e58d3e85000000000000000000000000000000000c626dd11e3c340dfdbe574d61ba307d84cb747755a503aa2874b57e033b87d065a31104a3f7b68de1db5bd92f90e1b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001764f49ee3571fcdaf72c30995a0bacdccf0a1152f4ba95116d244b5293932b5baddf9712aab7f662a7be28964c73bc900000000000000000000000000000000116e95aafc9a7d5c343ca5c8ed14cae22caa6f64f18f1c18283a8f20b37f45fec702e2482e1f45d31cb4e849d0d64f931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001569c0a587e297c652a14926d39b1281db6a60bbb5e01b2baeeaae31b6fedc863ae3dbdff782f5216a7ba800d259947d0000000000000000000000000000000001f8ee4b532ef576600d963905f8a642df01354777f762dc9d551a8863be870f6c2bb6e3363c22c0f496904f6f30e7d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083246bfcdeb3abd820d62268479a04f408c59f5adbaea40b261c00cdbddaa9a87c5794a46396a997cd64749425ad3d9000000000000000000000000000000001195ef3b2992cb323bb5289f9fe5e8fb0e66b29b78700a9553e82a02ea750d0f8ac7b1d31025553c6fb5adb42fbd00ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035d58cee313e58341655f05ff8534006c48733d17098989d9152a965adcd8fcfd1016c9024932606999c825756ff9c7000000000000000000000000000000000c7e7bc99d8450239f2428827052c2c5e3109481cac01c54c8cc5e93d1e74e3007908a44dee5e6bc5c1bde4e12486f711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191e596634a54c462636f5412f567d7e1a29970dc44679d1e234e8c6ecab1cfac16b10d236d62a4dd86cdbc61359108c0000000000000000000000000000000014483895bfd165c1b5f7cab805cfd009b86d37391aa5c9a470abf8f2916b179126a78cf0afb9b14869795f0bc20f34641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f9c1c806a3fe403a0924975c6ca8ed3d13ffca31d0e08170b917ddbd8a4265735bbc1b36d8eb39aa526b208e68014d000000000000000000000000000000001649314df69f016975fb2da668f8efc4197e4a5c6db8a32d907d25a44978edaee79f5a1cc6321bfe7750f9b4b0c3ea781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019165977c6a3e555b3d796fe558b135980321b2efddb5ba1c5db5d2fd4b28882586f0739809e325bec1b1943f2ffe69000000000000000000000000000000000164f123ec09afc326316e92e2338352f12e8d8097820427636c572555b54905b00cf227e8c068321b0f0460c4f7b42b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001107f39c0da286e7404e2f7841a54e4ef9eb55861c9c7f643abe8269a8b43e373df8b7a2a3dd1cb62897beff0b998a200000000000000000000000000000000159e0b10d6077fc77d03a98186b459e13cb275a2a095acc097e59e08dd65e8fbbff2dca9bd240e9a46ccd020bf911a361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000003a69414b1d3ecc4425f3ce88bf92cedec017a5a56f4737249a88850e271b2922081427185669cdf460086efdcb8ef7000000000000000000000000000000000a3977155b262ce8e8203c78e13f0ee11e2073a02d9ce4565ec4f71ff22a351b31cf018020f2de96330da7e289e9b6131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150c0566dca578e8047543b4d6248b41afe3d28de80435177a61dc4a7cb4d930ebb6c69f7a4169c7afc675915e9a7159000000000000000000000000000000000b043de6ed3553b055dafda0a1be645de10085595ba02a33120151b9ac76260e992615aa353c7a8525a31477dd39a7611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166b74f51667b43803059af1941b340050dfa14c915852e03aa4228047692d0b1ec8fa2d0e7a8c2de4394d8b82d47078000000000000000000000000000000001607ab94c338f691415a05eb0a1d14817887229ed5dba0ba007412f1840f8b6fd70999e7fb96ad1fee32ecdc196975b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012d8f23233d1d442ece97d5a90033b3d3d247dae694b2ea07d1d0c3e7fa259a7216f0d0c873c8531ac46254ebcaaade0000000000000000000000000000000006918f9f9e62e8e8f18dd7028bb5b02c9a0eb90044361ce7c18482af760a96f32a1b4aa1c696ed9af203d659a4f6c6431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026b3e043fe8c1732c86116c1881692d5d7ad2545102ed4d7ac48fb9875679c59733c9d47cadb970e28cc11e77c2019d000000000000000000000000000000000f4e97dfaa754e49ec2149e85143818e732a16cddea5a28ae8f11a11e1f78c3e71d73ceae977e1e37b0d40d82dc2b0f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000829cecc6c9eff30cf2171e0ae6821c9be72fcf325df65f59735ff3bf7a955c2902224d09bd901e05fd13b893cf460a00000000000000000000000000000000009441a86a80cdcd6d5c2bc7ae9a3a8385f29e2f3de060ca0c0b8c645afd8681dd01a80c6089195fd44765d01b74af3161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013399883cfa147566729742f9a8c56575d1ce6c7d1d2259de89e7f1b36a93f33d9cc843b4e4cabbd501d5598fc6f2a930000000000000000000000000000000015819d5ef8d05cc547677e01a461e3b30fbb51054c121f83711123216642a9df5ef18e6d07658824d8fe3c0aefbfee921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010054b20f655f30f8645cdcc2c13845f8024383a1e6d2a2c4a15bd08a1ad2ec3d415da676ec648cb4d64c9342c488ce10000000000000000000000000000000014c77475a095a7087f2b6dc7a27da27ee7d9ce7f9bee82a9560ec002aab370eddae5d256c368a705042f78a7632879351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189ffcaf645cecefa3a717f93dcf70c615f75824f815f47cf02628dbbff782495d594c988d2278b5be857d99db0fe70400000000000000000000000000000000045f7fdfbff9c8da2b23ac88212786079db7cfb5777d92ba59dd9c5e40addb60a354c90752d559ba8ac04985b5b3cbbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a3d42df44adc46cdf50e173acb4cff2d3197a03b585437bede5460391f4e12ee2458ce5576abd14c656d22c1588ce80000000000000000000000000000000011730a4083ba5d22ad161857496c991ad9c37abf30ab30207ee46b77b28b8c2e915e6b081e14e7217618bc40ef5488511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027abeb5f5ccf3f11d689dd746f8dadd9b3b9c6160d1975f8bb3e41e4ad6da6952235ae385b5b8a3a5899cc8f1b13fee0000000000000000000000000000000011a90363703958e362de002017e4e86ed2dbf5c04fde4e560aef013c9a49f49e51acc19f5f3e2e46c33c81cb90d98cf31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d3ea45cb0c04a16a6cce99ecbffc9774cd0cbd79eaa8955398d60b561c09f3fe4f83ccee537f8d5ab5f93461e85c2d000000000000000000000000000000001736ac366727445880a43c8dc1bb15878cf07c6f1eb9eae0d3a435595c791f68f5fa10ac4da0411640a5e9c4fa1724371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee7c3dbb6847432bae8cf6e6b7339777867c07d8745c335fc4061bb2b49da4af3be3a22877a9428f9bcc6957d0d64ce00000000000000000000000000000000100bc614d637275674bf1dd025127c5670831586d4aca79c9149f793c71b92b7f71b144d50b900f0140f7e42b1a8ab4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9a55089e6fcd424863c35d52c90d2a5fe7c45ca946e7f973812a6cec14262ebbaddd01c872ddab62213b56aa181da6000000000000000000000000000000001283e293ff5e04e379b00e7a8251e1b5e5dbd7038b99c3e0221e1f7c242458eb31f5e2a7722b638c4b08c3ef1131ae681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed7ad207ce19a772919a1db35bf0547f74dfcdbfb0be33bf388b147a17fea10617c8c07607245d8997f6775f47d8dd900000000000000000000000000000000142308f35bd128e384a630d1c7ae1547d833839822570deada353edcb09f5325f318fb1feb6000646fb5ff26a2b22b901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006524535389bde29cdb4021475adb9aac3b3a6039bf1366167c15ec72ca56d8d9cc66b8393e2fe7b1213de4859130d5f0000000000000000000000000000000007f12ea23c2643ca11d037806367948c7d0a032cfe61b281dcdb63b038c6977a3ee642e5c1844b2e97a8bb4a7827a0c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0f2288ad42102f284bf7695559b0d7ee44ff79419902b5b06a32a4d03fd7ea03c68273e959041d7ee25a8f113b5e390000000000000000000000000000000003823ddd6b94fcb20ea16e56239417b6039c5237577e34deeea479d60ae9ee020e701f3ef30b680e58facecb3bef953c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6ad5d3f33da0e48e182653421a497b83d2b6a16e64ae75f5309158722f72b2c35dedb6b3580e81a28391775f77fcf6000000000000000000000000000000000e7e6cf3ed216ad95e87c3e9d2f387436288448af3a8fcba9e64487da322540cd2698dcdfaf11352bc27fe4849e0a0a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffbb74b75dd5ad1613d7f51f7e03f9ea2c94235a4abb918c50b2146d5a17892f0a4c81a274f678fa6bb3184063fcb49000000000000000000000000000000000a371de0789ed85d8801a9c9fe8c5a4320a42130755b09fdddc9edf27d721beb90db93238c3bb1968561c190c95f23651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006546be4106512f52cdd1849aa84cd155be1f4ccd8f1ae8185b17d0bcfa2f0fc9e95a8a14e503f80562ac4fbd5a58ad50000000000000000000000000000000012d0d9e53f902120bdb4b74009425187844adfaa1a72bc453ba9b8bde708b7b6281d1ab12bd2c247a84c9f175996992e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd26a9c0ddf2fb1a04da0a1edce583cc1e7109abee3ba2ce57356dfa6d718083ecda9bdb4eb56c82930a302fd9fbc8b0000000000000000000000000000000017250a9d4acd12df90702265920d19dbff62820ac28a53886dbddd215c8569576fe57fb5d6773ead34e5c350b21edbad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001593c85979da0cbbba2be2f21c8634a704b5a2d9a9058e75318ce478cccd2fc682b1344e0669a3fe63a377ada1d19959000000000000000000000000000000001055b5a5b351a39284a5cae6f667db6859f2cd7afd3558a70c0cb8832d354a7130397104d65e4bdaf4c6fe5042cf7a651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003152e79c26bcd3d6be2d008da5aa3db178be19c745bbd5e180f91bb2555db75899c2b9c5aba40a5b7938cd1bd0e02ba00000000000000000000000000000000023434abbb1409fa6200c7aa1dfaa5aa138a8b5dcc34bb511b6d8944a05e2e856fc8e470cd59672367ba0ed3b9725bd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000064a421769e7a07be019579c2535f4833635c07646dc7ede80f5f7595024f8cf5c3d2012e28eb561616d4161adb73ab90000000000000000000000000000000008dea6f18bc1c91c0462bbea52cb4fad9fd2f3e08a658908079a783f7dd3d7a431ce365260ac88d7696e20b011cc59cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e8820a5df7ab0425997577a26f2e07cbbe0837aa4c02d100e30d44d8edf91ba54f4a026619b24e270142537ba33c8a00000000000000000000000000000000195e4e8a57e36baa77321b3c0a907a8ec2b091ab5a660e180c05ffeb16f509f6a67d08cc85d097a7fce9e80cd125a4981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002404b3866534ceef07b6f4b032427ad51f5490cdb923be78bc9132533357a173d38b9cb3b7694209377f1a90b460f3f000000000000000000000000000000001742e92898b4f3b31a7b7b7ab0cfbd95dc804d46db4a066ac7b9ee9c6cd12340cbe222eceb175df34855e85867fb6e4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f437c104ef22a3d140eda90f524089ed3d4ccbee836a052fccbf158ec2b39b9e6914cddccbba0aa8a90aa63a3266ed000000000000000000000000000000000c3ece774ba6fd2fadf621596d3eb9eeaabd79fd8185b74185a23218b7d04b985ad996952ad894fcf1cd30d84c1f626b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057c7ccf0cda632f6b28f7a45d13b4b1615cca160c54db6a8ecf24fb628dd0ca964d9dda3117b6f38fbc5d7f07e012f600000000000000000000000000000000072215ea146eebd043aba3ebccdf6e85e19d0ac7cf6470650e27734e20531b6891d5f597e5e75d5e7ca646ce6819e63e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c93354bcee400e5ade6bdedb95b9c9d616823268c51b4c579d87e56c576cec97de20085c309f5157123a890c6e6829f000000000000000000000000000000000b4b518be79eb3d762c68c94ffd981e47ea847fd625353bfddadc29a289c9d1f9d325e9cb97d3892480ecff66b3ae0211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018feafcfe6047e7be0294cf81c4487576479477106bb17bd9a037042d30a7058ad69ec575b9a79459a15a2311f25b8f100000000000000000000000000000000172ac9966625cb75758e70906846564cca8a6bc6842a0c05e8463085e9ce52e85fb0e30d735b509476d561a6e6289c5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac6f7ca16244ca9b03dcb770bab60f079810e7edbe0d9a3d12407a35d70a14eeb00e955f786cab3efafb64f146bbae700000000000000000000000000000000010ea5facf9b8ea088c92ff1580262b77791cb8328026588be483e3633fcff3bd597687628a0ce443c04cfe44db7d1ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122ced525a41d10bbff55052930676c45a2f52e1d5cf3abf12f8c775eec3b80507633460130b17b9c4c0c5869ae3336100000000000000000000000000000000028b92cdf071a327019dbd127db1c3c6c2683a43228486e751fbace9c5c95d1133b7bd03bd6381df4a1b99d2069effe81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198c8081949a7fc40c645c3e662f6eb765050b0aebfc710fd81a605f7ab33a983027d638b6d6ab27b34eee23af4a06930000000000000000000000000000000019b7eea2abb90eb8c2a453ea7b99f564e9de89398c6ee145dc8ea7050ed92eeced4e9d6bc0592285b7d81eb1e55ec8821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b7ec88ddf82828d69f0af9f0dd4e943e87d482d33137dd7ab55906253a5dea4a418865da2b357be66723367c26ccf7000000000000000000000000000000000ffdc792276fecfc17452ee4ca4616875b8a376cb27bbf40bfd4dabf891fd9b0af3f5c7578bf8112750f742980bf45271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008dc718d20cdeaf12355e9b4abeaba99bb491026833def62a56028239a5dbd2ad2405b1f47c026c5037bca74a257073300000000000000000000000000000000117e0700a7f257d5377916e679e147564812710d468ad88957df25092fe41574dfc6d4a5568d61f46fa9f8499aa715021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d083b057e01a19a519012e8443312659dc9488874c3132d2f0225d5287a500b05333b10ac97d6a35bc076b7b71541210000000000000000000000000000000018c7c9d21e9d464e85933beade2fac8c5c64510015474fd83008ecb165b9e6790c834d405406223c64a32251e4fbc0811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f906ecff9796c5b197b303375a18e4c6324c0f6329be23c367bab583fdb3999f63e07ad9302321fc17946a272f4708a000000000000000000000000000000000fc4f3a3fdff6f6ff67c64393c51c2f9104797b81910428d0d516e442ee9dd96ed92ed4a867a8e7ebeeb42a8816f85bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000561cade10c6fc55f3dbdc7f984e0847ad00eea34b544ad1f04b4cad8bc2c067f7a3945c7a1caac5c20a2f4d37fc39af00000000000000000000000000000000150e3dc81d27bd0778b46bd913c9230e9ec3f8b8c2beb0da37d5cea59343989c040e3d107657d372f39e9d38ce8d966d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bb8fe74aa0af494c6ad85ea2f53936c6297cc101a48e5c02810696dc24c932637436165e7bf85a7b7f3c99ec56b2a50000000000000000000000000000000018aba3b77bb2e1da2df67d27fb007e46980fbea37efc6c5ddbb90ba12599d0384ae37ab125bc24ecf5afe66ff3828d0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008cfc579e2d646103094129711d774073d7c0c2bab4d92fadb95fd8fcd87f5ed4a0945f79ccaecd316390493dd6ecc0f0000000000000000000000000000000002a8b2b6bd49fbfcd96cdf6089bd849da6e82620d38620d7b76077874e8d66ccd2807dfa438c7157386d3f694f1f68a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002febfc1e185028f383de39c285aca640989799f935460bc650e68d2077f0a77d0896ea21715264ed8f9c43194363ef3000000000000000000000000000000001376f2e6443461ea7224298d45707358a74d8e46998aa9e535e440f4d7209d906b5678baef796547d37102e1540646b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e97311f62da93aefbd6439fbafd57570712f5d4f714018fe68e715928a0e978ba062d1fd440ef85d82a3e07a24e95ed000000000000000000000000000000000a78b45a784470c78bcca7d9702630278604816e4c01c74f14859cee3bce05b77d255bbade2261e9334ff5a5913336091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d9bc0de62eee4097280555b81f5e1b3070c63897edada5894bf948fe3748c17003199b5747c8a9f5c032d05817775900000000000000000000000000000000036083796cff0d6c15233ef6ef00282d9967aef21d8e75851f7dd1921cd4fb49057a6f1824312276927e243b315f147a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc194c5be3bbaa06014872764bedb9cecb3b4080b009d3eb3cb73e3a1f408f6d40733cc215c35200d26ae4906b6840e000000000000000000000000000000000b79e3bb2e163fec63b588dc0f8d33e62c6b3ff44d3921df782e89229db71934c946975c7d18d03913dd7f4749c8b3211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018abd6087a069c941f1989121984cbaac8d7b08713bd71ee95df05350b0e47c45bc9a50a4f3a11ee28f23afa9cfaee2b0000000000000000000000000000000004eeb9984d209549b2acdbfb23b344189958953d3c78fdbeaac0c61fd5d837beb10a455caa2aa0944223299575be815f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6572d80a157f02e3d16c93e82bc11c5a5994794dd9ecf628d75c93d72baaaf65e97d271ec114e8a12a96729947824500000000000000000000000000000000061b8afaa66d4b861e2d442883bcb65809ec930e5f88916f9b410434c7a1e064f060f94f56bded021cd8b0051fd8f48c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a45c180d71585aa1066059aa92c0c87edc8b0af3c60a780f3a511dcc65099fe501040e149a4e3c7f9626fb93cc60e78000000000000000000000000000000000ba38feaa90cab68eb88970eacf57a6f73894532bb37ddacf8f6411c6ae2117538b50158e118bfe09c841253f7a139d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b37bc2ce2d4c989bdb41a98312b424824afb2e25cb4574963abbbe0d4af58eea1aa905ab882d4d73059ff95b529b2e000000000000000000000000000000000e9e9a611f32c6dbd627fcff3b80e6dafbc830d55a41ff5fc8e65b1260f4d6827c3de9cc88d9d0bb6856db493a53385d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005abcfca187c11e355ba262f3acc8073d4a6c92a22d888b85172684c14fa171dc5726a2c5fb6cb817a9f6116646b9ddc0000000000000000000000000000000007dd558165c7431466773828a44f3bf4722ff76e5b41d09d95726b4c8cf682287e1435c45f939f70b78fb1fab45ac6801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014400c30aa7e17a4cbc2e8e6154683ba827e0cf640f311c5a21b4ccd925d2f6e6243a7e9f04b12e396d9cad573e5004b000000000000000000000000000000000cb9006c4b45113e72119707c6e6c5409d4dfd324538f5cf32f31ea96be48d06400b610abc29e550ed5663a6f021826b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007505688416b67f45d30f93c620926538015bdbb9bde663c13e8c52962f5f99fe708b47977ba5c67a54355431a58c8670000000000000000000000000000000000bf7572b65536a4f064d4af46ffbe1f3f179adb81778799433424133feb54d2149d24890ab1d7101acc804b0c8ec2341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d36c7036fab7244f80f608ec310ed56e71f16c606a5e0c32fdb246589f6d1f9e86d82aeb92ef80fbca9deb45e45b3300000000000000000000000000000000157f947f6744567a8fbabfe35aecae22db2a90fcc9a7e0f59ae70d4861f8ab26d4c6803cfa84ad272628d7309db551241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ed9f10ec3dac0d655070c5adb506d34ae26003ccc0a3f0e3eb1d236068a149110199ce46b105b77d1c84be8f880a76000000000000000000000000000000000bec424cb16fa12d9383daeddf2f0e4497ffe101a6bb1dc1f25587d36ebc15079d80b9fed76f6413e0319ea2101da80c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000edeac545330a230358385cb0bd815961466b42c22a2f2c1abf09ad6bdb1ec4acc610515bf68caad34958d2678cc8b9e0000000000000000000000000000000018d53d4d1cbcb3f4a164eb7284fa4ead1a89bbcdfb5c5f6500fed44c48b62f63eceaec1777ca5cd8181c7c15c33af6db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001590e721877c4b430a79b2deba121777120d0ae3f4fd9dbb0d6374b458994cdbcfe91ffad5b461b4b289de35c75bae19000000000000000000000000000000000c5b0956bc43422f9cde4766f6a8008d8f05ec10d642dfa02c4e47a8327a8ec0965ad4649dd0542a8ce565e66bd001e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048c961d481923ddecc36a5d37a813be88d6d5ef1d3573831b0c494533b25cda4071cce1df8accc71f06f2f358c9667f00000000000000000000000000000000184e14c8bfe8a949854959c46f6b4423865312f497307e446c7d717cb2993b3731b6c7a94ee54a4af9ed7b9aaffce7d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccc7ed0782c09eb07ebd5221b9c0d29adeafdb67a8754b69a856b1ee81fab2371af62316213d72e14786fc904f204a00000000000000000000000000000000019d158fcbbe512bd76c53fae0afc90fcc0ea282ba666de8e5f06e70ee6111ec986d2b53e3e2d8b17e9f9acec0b724df41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e088b828c4e6ac589dcf893c71f056483ab903433a2c011efe671a8e94d73292b52e9e6dad150d204a20417ce7201ca000000000000000000000000000000000003d573fcbe59139e2dc8cb9f5b8a89d4a7126ea89957b35fdd1e0c3541199584fcd98ad3d0ac7d42f9ea159fdb8d1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197e16fd9f3fb148316291c906ed4832d173f6184e7bf1748123d9d3b222df929414f812915fdada1858ec43d1b18a3700000000000000000000000000000000173bc0ac999bcbd09e24a86f9e0d594665a15c338368e726bdea7ec25bdb411ce74c2c9798b5cea3fb583ab9e69795631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dfeac09aa5125ca8d626183657b855aec70448181ad8da21ca4c4949280340dad52e087134090cbe1d5712c3091df00000000000000000000000000000000008325043269f7f39d71afdaae493389bf88e5472b0a476350da2dcdf3cd9d848eacbfbbc27aad3f923a5f2bdc7e20aca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018803688ea03f8d633bdee4e4367ef6ca23dfc925016672a96bc4b252aa917f5fd160777d2b03bc071894004f99ef677000000000000000000000000000000001704af270b60b6d87f627628d49f2466f5fa30d4c150eb59328378d8ba1f124bd4c4ee0d2cb3cca726447df2ada19fa91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113f4eb256c0e03e41a8b902b946cdaff709c9db498290ddabad5e192366a17e89e53eec06b2b1d9134790d83111415f000000000000000000000000000000001260b5036664c0eef34432a9d8393fe0f3a090a03d9958a1e1542b9d2dbfd862f9450dff5e8e70628fe9845607c3b5b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e0511179ebf03b33fc3c33d058e9a6ace6be29688fed00f3807c3926d3efa3902510edb0d6539ab0516644a55ab05e000000000000000000000000000000000c792ad5d217c5e48fa684f86ab9d75e2eca5785a44192f883fe9819ba01f652fb32a29b28d49905216124ba9ce6815c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001604724fb8af98ca2d2183795e610e8c169e93906563755b3be0e465db9e622905630a7dd9f15d61aaf49ea724c7545e00000000000000000000000000000000080f37e6dc929accc6fcbc9a3c13f278fa4b3bff1ee1a7249c956ab7ecf885e5580c08ddad0efcf7a30e71f9d357b5011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000418dcf53d6635b4c0931f49a68a400422df08dcc88ac270fe7f934179103d7541af3cf4003f9e7e32ced1050d22c9b200000000000000000000000000000000075338a16894da3ea6f512c7035e22884e250ade8ac2bb9d6a238036cb47e02747de4a76145d38d690a508089c0d80801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9cf279309791c8cc577c664fd332c14cc5c821905f194ff711b08b3df6b3e9f82a72bc46af00a1368ff77d775933b10000000000000000000000000000000015bb2eb014c3fa9ca7dcac01670e688969e34decbad364036ba40a961c77aa4d7a962386b5578c3b4ac351676736787b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001674f239a7f3532cc4100ec4c2ee2b0ad56cf272fa68ce5eff993611fab4e9e59c680c392200fb8206de486322ad5413000000000000000000000000000000000c22ace6ad16e6abf06ca0588b19841ff7cef5c72ad80d9041715036a0a160f5354f83959a69a1b2b922214bad71a9e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009ca4d7f1e512eade03b67b4fef5959b018e6af3866a9a7bcd154effa0868f7bc49d5c1be6410615df3c5a6570e7aed0000000000000000000000000000000008c6dc890425d3007c12dd4ba407bd5f15a19ce26580f348f3d9a4ed4c5ec289f4f2429546938e09c8644c02ca00aba31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6d2d7bc3144a4f6f6445e2d12c1863d92aa9c1f1a79b8bdac144d74a2aca175d702555baee5ddf8253b320a08f85b5000000000000000000000000000000000eff16de03c352263c5b5286eb94beb11d9b5c936ace083a6bb93818e1ccf6aed8c51af70a749db79491df82aa801c561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030c09bf41bb34e61d1593622c6ea1073fed838ca6461e974bc4883993d2acb237c07cc8d6fa1fcd4a9c03f6808749350000000000000000000000000000000012d2c4403cd5fe15734f571ec59647cc4f4ab4ed5e0c2263800f9f1a1e3d20b8ae55072b441efb21f09c4e72c878894f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4e344b6ade10c56530bf2e39c3d38babfa35d328f824450054e253b3a8b7b30cf21a23881f8e5f0677d1572691e389000000000000000000000000000000000b8b3f651cec94f48104f4ddf84b639aa44e9c7ca7c33672e1dcc4cd08d0439be62096dff9673a3b1cb7f287f5a14ca51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051849958125f4f04e79fc18e4bc08ecb481cfaf19a3700e23a9ebf4b653142f78cdce7bec9dadea96d0a959acbc55f50000000000000000000000000000000015580cfb537c7f3a719990669277679037c5553b2ce03c89d09e0f6e8324212171daf449dc4d7d6df0cb838bd06d1e7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001601e06adf8969c35218acd2016c954c3847bfd9e0fd7d5a9c6fab5dbcf6f67de9e47c8a9e57c15eb849bf69c465b7610000000000000000000000000000000015757410919aa01ed5d43bfbf4cd4a8afdccbafaba3dc8b8fde5fad23c8091871b302e859e7d72e7202af8d39add35341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074e6d01228713483dbc05cea49f32a841658d269288eadff56f31da2c831de1e48f899499868b650974b32a0e09eb690000000000000000000000000000000001afbd6aeea7c2fef8319bfef02f191182a3ed74727d6c62ace61ec165dc4f938f214340cb48f05846fc58840628a8041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074debafceeffef489e664f3bd81f15d0ae49e2a510795233a39f55819c27ad366ae38dc32c36687a095f7a59832513900000000000000000000000000000000120a2384968008c5daec5ce5ab2ead37c3e8b34d381ed78c8549f01e8e134583b29bc71faa947fee6c3171bcdf9b02f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8fffe737c1a46bef9e76e5b60f69f844c6a40eb8d7165051db1569b6eae9485384b3444452d1fc6abf8a0ea392038300000000000000000000000000000000093600f3841af24defb2d774963297d1615c305968b33e9d109482b93ff063d1c9267f8b611eaeb96bd912c13cbecf261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190be8b35c8cd03a1b804ca9587c6b6a5c79ea78063330bf49637afb2234d59fd82d5304fdf4d4396b10d5da4bf9d29f00000000000000000000000000000000177d45f747b2373672efc9d49f75962f28c992776a6624ac78b305a35cf970dfa00c4d334d56316ef504e6e63762317a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082b050941f7ce4ac3d95405c79d9a394016870d9cf6cc33813a87fc59dcc556fd323346286ca052063fa7d571dfe97200000000000000000000000000000000148e0312f314cb689d3e4134b7df68b8ee351aa95b45dfd0fbb1e9bb852648f69b18b95e06a6c2883afaf99ede8c26311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a015feb9f7feeda1a5fc50aaf3ba9a04c8768b1ec0987b85e3e3e36e9eb73341950e19df00d046c6d0f2208163aee4000000000000000000000000000000000fe0d57519122a66c130cd8713cddb9e5bb795a49ade0131584801692c2e733255b3dab830a038b015bef78549ffe5961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008bc2fb01760bfcd7c72175ae4e0aac45632b0d2107de734a9456694f20e8f9cbd06351aa37b236086721f9d26b9a19100000000000000000000000000000000151fc93cc357e7601bdba142d11f8d1f7fd282e7ee64b41c80c8155008c3fa66a20c7fe044b792b7b85c6484a85375a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6e2eda451d727bda5caf50301f7a5dfda551604d2ca995953ff9160f24fcae8c50793567496733ebb4194bedb6cefd00000000000000000000000000000000003bf18007c6265fa3279c6bcfe6ea01e530ad9dc46b6208e892b8a1ff559e51fa29f48f56cf0894d0d83c3e820583881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e4c2b54347ffb088cfc48e83f364886732023ad9b15765f7b1f4bd2246f0ae5affc9e7b00e6dba257d153ed058d8e1000000000000000000000000000000000cfde79090aafed59f6650d30425baec943981c66b8cd84eb3e359517e039230abf5401af5c8fe7047f73eb79d63d3bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000306a31cf7f485731181513b94ba67315d9bdbedb9e1a76cf6589a5ae3e9729a82409ae54ea427e9109b0ed7b6d4fb8e000000000000000000000000000000000a3babac244b49a34d440b05b3bf523f2119e659781b1a787d8f792557ab53c9ba4762d5266656d5da7d3425b17f76871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000bd24f79d8b557b20c3e822936c34f57c066755ad884e6dce616171ea29529ec5d6cd450d0658f2f9d5eae83ec7903c00000000000000000000000000000000179fd25154f799ffdfe70ba531d916051f52390e23e5109db61d122aed9d45aa8ceb1774392e94a060264220f22d8d301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ecd24d7ddc3f81472772ea2afed3c79baffd0fdd287ba8c6c0bdeb36d2eeff5b92947afff2dbcf2eb2ed36c3bef927500000000000000000000000000000000105f7882a7d1236810366b7ef3cc6bdf8ef8a433a7c27b6792f9a19d783d9e253b2536517afe0bb86e65ead5632034491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049aaf34e09ae3693115d92583d1bb56aef51464f0895a2c6694795f5646b6c0547df5901cd880a312873b5f3d70f5930000000000000000000000000000000007e78bb83e04ccfa8f9d7e158c66fb8140c29282090b6c0f9fbdc834f5187af5cc48ccc327fb1dc1d896c34380e78d3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013379573068a85df62f71de3157b2a3d042e54e74f779ef6ce08e3f373a113618e205bf2cb64da98881b2522935a24ad000000000000000000000000000000000dc8a012201ddfbe8a0cf5218cdbebfef1b239ee892a9664f5290575756abcfb8bc223abc809b3098ae6d1593a6bdcdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000148e39adf09ecf10fb21bb2181648436b2cff699ed62ee1e9a50516b80eb576a9fb9c56a054313faac5dd34eb5703bd000000000000000000000000000000000a093ba1b1d5d8e797a54ebfcf320e5557a006f8b4eb01a0817e59f6f1fd5d9c993ff882d0996956eb65529f47c5eefc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0e464349247043207a5c7d780f5d635b09a5d6be27f360cbc9397418d0a69e1e09db9c1a3078a7170f344ce27578fc0000000000000000000000000000000017a7ec70006cb88edaf099727b469cb1832a3a5d245393a7abc66cb338d5b14f5d73f7899615ce2ce71afe86240668d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000617eca06880ca45377b280d7edfc23fdfbb9cf5a1d71ec3de5d452366f6f8c0cae846145ea00fa55e66e2828474b6b200000000000000000000000000000000035faa871dbae0b924d81764c2d3d08d4c8bc1d9709b13c69449ed614acc58c4453ada36479e6ca3fa93182506c9fd941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002009bca2c96684b1cb2e7fa39cc70b8d2ee5a332b453dee6724d3bb4843157f884d733a15d0c922cf7782f77adfc52b00000000000000000000000000000000059ecf5d0b25742f52deab98554b02dcfbe87fa55586ff47bd2b693d0ea26ae82da72636e68007c3905f172e0961ec781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170762624fcbd6e1313a7d3605df3917799f87e2a6c5e976b56e687b5d666183e4a1a7fbd6b7c08f54184f883a890162000000000000000000000000000000000c65cab64aa762a3fdcc182ca2f133201d44c6c28dcb881fcdb6242583f42abdae8d379927f92768704f9465c7b6bcae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000158135fea5ee211d9b330a4112e4ae736921d6974838a2ee1240e77f558dc470e41551ac323884b113459aa7a964a91800000000000000000000000000000000155ef1ec7a8fbca7bd70414a73566cff1548d2d03f89b4a336e50d1971fd502e829c7ab4c5c9bee3905d25adc32d42581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071ab4895200b6c8c224cdb0376c2e325d723dfaa361bab31045332feceb9af7f7308f05b049750953110c8defd61a9a00000000000000000000000000000000047f5f7c158f8102105331b8bf9041c30ace29787259403047bd0a09c034a57323b1810e9e163e93b12de9ee4ef7f9b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019027b33f3f61111d4fb412e4d120c895dc6cbd7eaa448dd9f28e1e754a4decdeacffc0de9803068b6970310a3954f0a00000000000000000000000000000000082f94c1f1777501e7a3559570ecb30eae51cec434d2b7e81bb4ed496b2de42837321516e368b6dd9d15241ccb9434161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d065290372931ee3bff8e59dbabfa4c0c7a4be2fc4bdb4c07911ba57d0d4c4162e72ff3f3cd884958255d61bf7ff90000000000000000000000000000000000645fe437bbaf312d73a39d6c02910b5a71104f8573d1bb62c817ba4714648786a47a39d56d22c5575afb9e3c9b4a6f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fcf2597e1d007c58388f696f32e87bf0c1c9dd0a8d82498e6b712817c65a27312a6ae4d66801e89f51d8ac2db87495c000000000000000000000000000000000a2d0bf956414b2f86f2f868385f2c62daa0b4d1b67960eae829059a8e91a9328fdbad019d651dcbe37a48182c8baf5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b161ef685574c54796339d79da83c0d7662b11836cbd80aec7667706b198a49ac22d35ca8ec589591120a41fd61114000000000000000000000000000000000d55b8f7dcca3bb5721548cabfd5635060b4405d7968cbc4a6f6c2b7618cf99e9533a45f42ab1ccf343da563f482a82f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000012d8b3d241d6ea891fab2dd53e79743b809c71ff769da64a5c65b0bd91dfd747f8b858fc7f7abdadf2f857e13ab0f0000000000000000000000000000000013b03fb02ea7acb79426b730cdaeb67fd851ed51fedf34b954b4ebe5c0a7427dcd26da4de5a61f206f523fc423bc48f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084444f0c9049e4c912921bca7bd350a130d3bb90c440b590699f973d9bf15aa678878b44d4c855f6031d96c3a542ad20000000000000000000000000000000008b3f6036c1bc72e74fca81e3b3737b23277d3f144d82869e1ff5b5ca0995929e3f6326c7a3edcda18baf4de725fa36f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e61bfa84a8c090a64da3e495580aec8762579e2eac4c62511cebe09e6956b9c35dac4a0e0f2f5d857bb4f3314ade9f7000000000000000000000000000000001959863c91ada69808f779ff8367b3cb4bdf35bda52f89bf2b29c3b1bc25c3fb75f9ef7283b00c670a817ec4ffe164341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043952b8cca166fa8093696c66c8b6ce39bb5fce907480c9b930956aff574e193c7cb3efc849b68c9f3fb67f244bdb9f0000000000000000000000000000000000eea7bfe0d6185d4aeef016e55cdb35717c1be8ef64a36452c070eb46204a4b482b04fc7e0d65f88963f1a814de54fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103cc9f493f26295d855fe8fe8529c80176cb8c0cb1993b84fb59b86e0c7168ce3a80d10bfad0e94fcc4d969a1c9bab400000000000000000000000000000000102c014a17855e58b87aeeb6971bc8045ad5e75f2e22b59489830ef635659354390046429bbaa35f80b6b076402a7c261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001189cfc25c6c51ea038fd83061b5d5e48ce15911336fc9e50b8a8e81a8b2c2e7de605eb81f70e6a511b1fea6bb1b5b280000000000000000000000000000000011ea9cc3d7db9fae5c30368f670b17dc1bab0375fd1f8a971fe5a1ad0cb9972e2b4e04db9605903c29afb59096df7c3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152a1d2eae01c41ccadb7c13e6405c0a93a44696f58ff16ff62e15fb78a6a7dc9fbbaabf5bfdb589ef54d970b3647ff3000000000000000000000000000000000d9a5c2cf5713c2e484ce4f759ab0e5fb3d22e8b0131ebc9eb76e2a557a5721577e1166c57c2514feeb0b69bbc9b8f591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039c7097e720b8acb7f2b620f18165dcffd6ff89c16463600d183fbd3ce8dfa24ecb863dc54c9ca8072353977f391b680000000000000000000000000000000016eba4e180292f73f58f1b44e6b0ee19eb3f3ed8f25806ac690255099e7f69d11ba7e5f4c156b28a5628ca34133054421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6d9d1a830bbee41fab3825d0728e77e8ad22f8df12c3d829292acb379869c9630b642423ec1350b8d5f3f7ee49751900000000000000000000000000000000192fe4ac65b78ec4fdd534f320efc16d1ddd1a03ae5974a0100bb15c038f7e27db085fb6ae29c6600bd9aba4b78419431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d5513029f1f2a07b1c1d1e35e520032c187898e9246e33beda61dfbd6d754a0b86e17b5589ec4a1239c0996bd4ee590000000000000000000000000000000018d5a84057078f951c95dc9497728f92d4cddd773733c9d2488f886a85993309cf0c39346ba91ed818e3627511ded73e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015fa53f6e339c97f07552796ce719080c187fede2ea0a9d7c6add01243c88f3a257ade9199a1826477d4871086966ede00000000000000000000000000000000196d32a3d320a0527d874d1552c5da42342b3a5b0e5fa48b2cb86a838523e4cc9d278291ae4d612c234ee79c6e9a96051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080631d6f440e0caaf4c0977109bc8e727cda14badffc50898cbe2a97bb4ef264aeba669653410ebf0f1900f07a2648600000000000000000000000000000000184f0397f7cd94e7ca2135037a50c802a85e3540f0a7ee3f42d7e6a0346bf1f7b3b0dce301469136b0ae21b1081d73661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000957c8c6231d6f21fb331878c20587b4be19601040b03d6ac3a9e7750bbbf76ea044492bdd1ec86d2a0bc39b6cf119cb00000000000000000000000000000000012bf274249fc4eee13ed718b260d95e37a495375b96d99c99e9789103a420ed911342387c14b70ac751c9c0240a8a021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006094a74ac191d887254e4d4799d937995498077d04f414fcaebafb7e67b4cee4e86e57c2eca8d1e43f05410c23180ad000000000000000000000000000000000f252c575a8b5f2c67cd69c05276f88550c04d343f957f3221c7785417100d190cb9a98c6a181a9da02bb9afa9e129381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d124b9038f96868c2e51b8925d622d9bc0b8138bfe741d618ebee3ea532e842dfbc7e1825f459a0c83caee274119230000000000000000000000000000000014fc28b5b15b884f78867ce588c1a5a6f08c735b87ec72373a3fe490c242956605d572e6ff58e0935b3a1ab1526025201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3d23a294f9c7221fd73d8d6f8e2b39bb1c67203a0a77a98810ae8751f00a4c74c8c296f8308143d572dafb3323d6330000000000000000000000000000000001d8a837266020600df18f16eef2b27fbe21de5a7227106cdb424ba2bcb02893190cffce652066bee6949b2a3fb2666b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017bb01af082a0418f7862b5003f9974b047ab88362bdefaa30ab9c938942b100aac1371dd6eefb680666a9518237ad7700000000000000000000000000000000157cc059bc3c120a336e260395ba274d647b12c0e3198160c87fe95aa37e308c3476dda3066acdf854fa889fd8b1aa931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000338d3b7fb5a42ab99fa3d0c7899dc0b7018db189b52fc3db6c9f8805c63c48888050ea3d707241f17deafe0ebadd4cc000000000000000000000000000000000d9dd4888cf763efecf5289db692ea1143adabfbec4948c6de76c435ffc5eed215e516a080676b942303404108c3bc6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3fddad4c0b3df0acb6571568637c7e2ae928eb350c139964b15fb8c97763f187146f84c3f7777bde0b10a131e109d7000000000000000000000000000000000f9a03e55aa4c13bfede92948234a3eca2c34afb324ae206e861a4ed9183eb4656d3bac0738fa88e92b38805b2db45971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048399171ead1ac19314d19c79b08163cfa6fd4d2646f1f6b6309c0a797eee978cfca684e4f03ade78adcc35caec275400000000000000000000000000000000153c43bfa36675811e3e79a7d2e2e50cf5374442fefcabe0d2a51143dfcf25e80f134feb2bf91f43f8efba3f7a27b2be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036c34aed6c66ff21a6f2b545c3de17cbfc70e735165a0d825f7b602a3211098cfea1506be60fbcb19f3a0dcaa4c9cc70000000000000000000000000000000016d0369c42524833adc06b70290ac29a7f56a286b31a4840e63fa5092c36986adfdce20e917196a335ddef03bb73e6551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d036afe4328082d9bec8fd8b054c0470ba3417c44fcec1feeb4801caaee02d81f046f7aeeed5d7be5585fe19eabcb340000000000000000000000000000000000d7dfaf9c0c6bc01d10e5f3e30e49b45e2b280114e3a9d39ce0d171ec3ce00adbe791612b7cf4d67986ad68f56512dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7cca7b0b6383ca093a5151c0e048571e0149a4008da9e6fa3b71ca749b5e44ebe97a69faf6bbb3a84a6cefa67f518c000000000000000000000000000000000a0c65e3a156733d3cc9a2586f54dce579a0ac73c5c16a67d4eea5445aa83834fae20b42fe5c891c6ecbe55f4ee873821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f1f8f5811d41b03f8a06cd5d6bce93242614d601f3c2ece3f22bb20cea0ee5a0898366397378f0d0b54b557591514f000000000000000000000000000000000d424094c655ea7970fab942016da2f9e047e2679cc6936e73c8a86b4ffc30230f3fb32aae79a1bc114ad42000c321d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001900a5f2de43b4cc8b8201b50d9fa206b783404d39a2f1c36d6af2fb7ae5414cd346670c19272a0224916694b4b888f00000000000000000000000000000000003ac2b79b2042e711fe81594337977fc6074cc6f5685a72c6ce496949ad0c082817e648612b6364c11fb303152ff58a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003651e0f56ea75e11994813b17a23048e773ade830712c88577ac74a121e5ec664e2f56ebeda1f755e5c5a71963983f90000000000000000000000000000000017d8e13e9142dd41152ffab4529da7b5dfed85f38986bf873c3e8179d502dfe2c9620f9e73cb431d55a765fdf8cb2b5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017bec94137f8719b3c416399afd0c9653deafe810320ab57028b10ed719da3d67c7df0328d74fb98aad7dbcd13f2ec570000000000000000000000000000000003dc3fca0ad4266d3822920ba8c346fe009bc4a70064915b262556522c87f26d6a37fc090199df998ffbe9e00567627e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056f399c990c96d08dd9d00e22d1ec868d16c936ebdadbb67b8e7ee358de148493907a94e1a5a31bcfc4103870482028000000000000000000000000000000000e63e9e609582da5ffd06d37586668968da7b0dd0bf7848caa0a67cdeccb691c3d65edc89afd0bf37e5c574d6836d4d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1807bf3b94da647fde9a0b4759fae6665bc1746884e9f68233c0e0f31d0c39ac076192331073f972aea72fdba901a400000000000000000000000000000000056d4bfde8146bdbde9279634ca8fa92482df66b3ea777c0808829630d7b1de60a6feea742a3089e56f396dcae15a4e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185c6dda9ed0a2e9f838e31b049780dd63df502fbdf41411dc3f951d4d15351b431e25ba7b0bcc76e8d02d0e8f69689e000000000000000000000000000000000e5518ede62b48726205060429240c0826eddd1bf315da5304c9dfcee40b8165defcee41ef9dd90b35249c6a5b0495b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001819f8595014ac2fa5f432cc7ee167277d986745102826013f313cb105645c865dfed3bdad3fe2785c7a00d0b03302df0000000000000000000000000000000019d710c67b5c34b304799378e580b298d8ae1f02a9fbd10e3b94515ae79c1db838cb62881ab16f461b0da39dd18e74de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cda12a68ed37aea861402c59fc90b7bbb8a964427c1dc2835c640242c063eca7cf635502e055ec54dec19ba9920abd80000000000000000000000000000000002f294b0667da603e0b3b736bae541132abfaf1b1705350afeb029dc51ede721b2f7823e8d3db36b0a56e404c63b2c011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063b7af2ebbb584d8b4b60ba6a8048249d9871ba408f72e8518498ef73edd55f969455b05f92fbfffd6577cf439ad3280000000000000000000000000000000002c966b853839979b88f15feb7cedaac2390c3bae0a39847787a0f42cbdce964d91c1557c2800baababaf954192aa07a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c561c2be003cbc11b8520a06666b92d1b0b6dfcf345e7b39b070f6cff9044228d26cad64208687598e12863ca2b643000000000000000000000000000000000b874dfd4ac8b4891937af08b40366294c7d355195b5691161f3c3d62fe566baca7cdcdd57968b16f431c8492467ff321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee05d96f62d2aee89334a1b34328137996dfa45de4e943f76e9171df1235df49762db30564d905769cd0e22b54a86600000000000000000000000000000000010e562be0c84e350d26e66f345dd966c8c2d6f6f7fd734db1300fe4ff6e667f4617791c02d1d1bb2daed35070d33be451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5a29f182fa2bd36611fb68bd0f2b70d7737ec2a9824d20d9b9490f014dc417a3395397bbfbb5bfb208bd12e958170e000000000000000000000000000000000cf54f216f008eadc244f014ef04d7746302b5fad839b86261d150bf5641ac14b199c74a6d24959d5f62abd1089abd5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b9cd0a0b151ea21dc9e1270ac0c681e56af2d30d15d90b972f9f6380639067a1ff2e1e4c5d0dc6a42f7eeb0b7e597e0000000000000000000000000000000008d342af211a3bef380c83331ea97ff5aa9ce1234b0be5b16aeacbd4aabcd10ce9fdd9f80a282fdb489c80da408c3bb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f190f2bda94a6b5c15c4a3ece93205344c3dbf33e92bfb4964f756eaa54d6ea1354621a316c7937784b163df0a7a6f00000000000000000000000000000000101df29c0233f7d9211dba6282f2eb254ac00dc1af0471a7687ac624d4adb7fbef86f11692ca0bf67cf59a1be4788c9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191db252588ead5df4cd5b2646e5daae4dcd9955de380cdedafd658b2fa260d7ec0c2cdd3c8d1f5ed33319a949f4d2a6000000000000000000000000000000001545e825b781dfbcafec2e606fca50bca1f65258fff0231957d3c1c70765897c52e43aa6df35da9027e1cb18c145e0ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b401659ae5fc4b8443333bd9bc6a15ca919719bfdf3ff772abaa1a75c88162ba36bc3a776fc20720b523e31dcd0fa2f00000000000000000000000000000000076b0c3d530b28840c031dd0f9b0c9d758e353d98fee65af13109dc8abd6b98c16748e27355414d8e2221b08c2cfc2c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000980e27cc723492a0cb9f871a6f16a00a8e93143eee8891a09c17b2b070d68e352ea4cf3716f8b4b72025df090ba2ed40000000000000000000000000000000019d11c5f76aba7fc44df427db11863175ae82527a5e3704de7c20d1d8b287b37153de26dedf1e5c3a8074f0adcdf5ea81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005918d0334bb27edb3cfafef03059447fc4fce694eddc5be492fd68c50a0c0766b4b1f51b2ba57980282017dcf70a0cb0000000000000000000000000000000000f158ad866fa02dbaa1bae3ec3b4cf857819782b872d946a4b682aba43571e5eeec92ce4dfc00e68bf14ef0bf8a35081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000363f25c0a2f7d5581e3524b0ec986356366edbe1707db75d7440d632f9d60fa729a403c8d5e37824089dd97a22b59670000000000000000000000000000000013545084d519c85660b424da44da32a93e9e53f510baaf8b4222be5fdd93f43945a8b0fc0e2b9d14420c4027a0c66a471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f8f2bf4fd29f67b9fdf848103370268df354a3d5f5291c203adb66a87ba8611dbf8dcc68a0ff4dc98f9f41e08e737f000000000000000000000000000000000a278629272492068abb084589298f2a8d2f48d71e524988e44c221990185c8e74e4ef01ee54237989e1add2f12fde5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6364a312abffef938b000a7bd403d74851d9c6b6646e69b3455e40e84d18b77d0fa14aa862b0977ffacf16d37c700100000000000000000000000000000000073d72568c833a1f8cfb0d5e22d98c3bc812b522761a055026148edffefe58558461e9b670f09f471d0d2846f496ba8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c69a457e975f75b1bd3b29d1b5fe9c21eda14940da5be5b144df7798ac94a8173d830e80cdc52b8c5e9712160c047950000000000000000000000000000000018d377cfaea2aa32faf6a19794727f27c735f0026797c9a53797c4d42d3990a21a2427d5593eeeb1cb1720f28ce5c4311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000171576d9f87925451d578861acb515ef68e6b278f736687de653eb40c8150046a3572284b36aee38aa7f4c6bc81c1da0000000000000000000000000000000003f410b94592c4bf3839b2cfa9b0cffe8b6a0b37e2828945035c9a1e7b32f86a41d1eaa209d88182823727e05e49d4a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014fd5c48b41ab311b841b99fa2e29fabb6332db5112cc68be6bfb12d642d54a96c97243d57b2487d2ff79263006d1bd000000000000000000000000000000000c81eac9d2026118f35178703bc8886511953f7b86a7cc20d80a101b7124a471a36afc758cc6a04b75396e6a8b77f14f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b8469ba59e96ad7271c7f818318cc19d29dd255c7d38e94600c12cde76f6042ee1c2840ac9e6f14a8c32ccabd6777900000000000000000000000000000000116b1dc6de4923901f39be37ef5e92ecd635f3dfc97dbecfd22d0cb163b38b10c958520c2348bbcab676cc702416cfca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179b8e4171ceb15c935af42a3d9ef902bc3fae9aa1bda29a06b078ec14ebd9d3c779038a364a55c408188c90d1dcd38e000000000000000000000000000000000857e2935fdba45e5a64f0a5a592a49d3d5ccdcfe2116d2d13da31ea575f1c5ad1fc5b8aead349c0f3f737ff3842511d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e7dd6b05eabd1163be3bc19aa7e67dcde09032140e0ed42cf02010593d1463b68f312e7b1c78dc056b2bbf3601495b00000000000000000000000000000000056c7c750e03c352db94704757f57d265cb40cd95309509f4219e47820d092683875ef06d8288bc2b7274b355ef3ab101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a79c8a1e3e0112d8997ac0b8960ba062e3e6a66be2803e61f2fc88ac5d047ab9d68047dd1f99e8602b016cdcacd417000000000000000000000000000000000630c33856c1decb5f6c889c6477b11cf1feb65658cd1eb5b27c5cd41ccb3d340f8669e1f9cd17bb199127656aa6c9031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019694326d17f2a6eb476f1b149e8538669e6637879279d8f7aca01b6779803aa352beae9840394bc67cfc88e3cbc89200000000000000000000000000000000000e93267e08e2e88c4ada1338abc3f842f9534cbb4a663ce1902d96efe29ab00d6898ce4d7f519dfff23a8c10e54de581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008657511487a4cf3041737cbca8a9a57b9edecc93507d46a22cfb331676f9ef251987127541e40a9cce74c64700b262a000000000000000000000000000000000ec6c0853700af75c3b7a0ae0a9ebc2ce9f5272bb7f5a3d1fb2041a3ceeca5bfe38c0ac7852b8ad69722c437e01ee7981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f3afd8fa9d42dbe9d558d4373c1e04c2967484284b6ef07687902a46dadd4198b2f717888ce99077b2fb2bcb4b783d0000000000000000000000000000000019f949613852652d818bdd3808a4a16d4e8822ab5c34e7283ada7bfac3fddbe999621300fd9b265d4c5e7ffccf6c55db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013bcac738fc5b334a4b1a02847cb62359e4b7bd5a59d937e7bd5994a6bababfcadb1d0ee1bcdd1275aa8d26ae2d52bad0000000000000000000000000000000004a842961be097c91a43449b5b231773b5d8b20a4a0512f1d7ec95136b5be65a6ae42e82cc20e8f13960d1cb6c260afa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8f3a17da3574b5e88d5a0e01297bd652ed5062651bf099e064ed85b0bfa57737bb07c849a28353352f7a94fba8ee9a0000000000000000000000000000000000ea014804648e24649be2469cfa23d67eb7df8c40893ed6d37d72ec55a6ca095fb50554f7c8fbc7b951fd9c968ff43b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a098c4b5ece79b419d731e75f1ff731d20e0a63fede245fadeca480fdba01835d274a2df2992377ea1d9494237855a0000000000000000000000000000000016b0bc022d582b54a7dfed8e48aa9c8aed703c923838225eabf369ea21103a2cb7497c1c8d149e04077955693347caf41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195b409e64a2d6d7685eb3c2b82a577b4d0276198ade23e0f9e605d332b5ddcaff7010648ce7b3b0595c1c717ebbb7f3000000000000000000000000000000000bc7bddd61540c1638b1cc2ed60a0f7b51f35223d7a43f63444a223ff46b1214d89dd05f6debab6ed163ee1a66a4d8561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131604e4c1045f77bf80efc9f3ef72c0577152d3e4f4662c35ad77e4e3fe5387a69ded7b91d6fe3390c6cf9a3e97a85b000000000000000000000000000000000543980a1d8f4149ae53e48f13cf045e066541cf5ff42b2fdcfab6177578601bd15c86a5ce16b094fcddbfb1037234bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010fb5d57256bf951f342f9b337f2952a296c8f4a83530b20ffb8cefece7f45363c1369dcf60f7e34be340423e3a61b5a00000000000000000000000000000000055ecd76563d776357459b8b7cc42c2983884167ab5a2a9281c6ea11461256b69e185769ebbdf1e2ad766e548573046c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f0329a4f25683820b186232205fdea4d9ac16d77ae368d072eeea82e4f6828439f8a92a370b09a4270510fccafd15e000000000000000000000000000000000202f99e5a16ae529ca5ff8fa65a1ddb0931821f1d50883d74310883b1b9a27af355d706224424572980e9f4883d789c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a4c65abf1b8ab82beb2a1b8a298343abec58b55235bfd4b39e11a0f728ccc30bf846abae02c6ccb95d6420a4015ace0000000000000000000000000000000019311125a2d8c93a227e1cf56ec5288b91415c29aa4efd12b7763a2e5e9ff8a2ca0c541571dc9daed160275abf2b8dc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000064463ef8ef4f64b92eb8ee5d7c9c560754ea4ef556c5b951e47536a584ec8ecd2cc46606d87074ea1f9e5afe061a78000000000000000000000000000000000194a0e950bf91cff8b41d852cf317d30a1ab70160f00344d7e700c0c6d6f2639f57a7572ef4e5b5ea7e65519eea3db4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017eda2e5b923c29289c29b2e681d05494a4ecfd2cb7093af1e2debb7cbe3aa861b4c436699d7b5fab37fc5c34280abdc0000000000000000000000000000000009587f4a79e11f884613aabb07268769c69bc4dd6dd18021ca8b5e25ca329a401de201ef9b78ff1ae7087b15a662b6801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178d9024675adb6cc1379ef82dd41e29df4367e736c33f1ce2cb7d3586d2a07908ac5737915b583366029e512dc4b58d0000000000000000000000000000000004fefa28e42827e878a6bf9d455c30f9d53f7dbdf817130dd0b979c01600750e9a9708b4791441ad7127c164a55d39d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e9836a751cb070efdd4a7bd2b79ef9b0b2d5ab0a5ce382e12ba9942d640d10453da32916e7458572cdbfb36931a3d700000000000000000000000000000000023a05f1827a52fb8e3c97dea77034d347a02a1aa6db8e5cdb155f7ba479c5844abd957084d804b50440883a7f395bbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004162dbb0cd49fe5019df6f10a8bfbcb322c8ee62a8eaddc88700f3aba103a1668438c50969dcd37fbeecc20033d48d6000000000000000000000000000000000b06ca15f0b1e829551bb2b9b652ce329a36943d5c5b1e0106b6eb3eac3878a53bc079bfab10ffecfa5a4df2b15096501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bdb7abe42ce13ab545549c2da5ef63db56b5cf549bf6064966c0db4d4e29519ede65c0b069c0f2549e73302e7cd4ff30000000000000000000000000000000011034e41720620f5161c3b97a3e274b0abf6bf7ca5885afa888ccf4627682274d701497b331f9464673cbde9fc0be50d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a330cea940e8ba220a3575594f30caf80fca7ad9131a1b3a26318303fcdfde8d1eff41f9d515855a2a7d1eae18dccd4000000000000000000000000000000000e460c3e6aec2e17d7c326bec9ab97b59268f026f661982383cea9264a379131ea2b7c2979c3672d4990a052b72922191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0f2b0634afa168b9c1987009b6259ca6db6d7b198d52642bb5719fe27607b9e8be25b9ec0669e408e974425c79548c000000000000000000000000000000000c7deba9620f7d7688d42e11a5baac5819ba6988b77b5aff8f1c205013361a6157205d31156ee7a3c888a04ddfbd32151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d80cbc692428005beb46c71f512f258eec2ef851d74949bac0c59085544e96c7f2237785b03555ed9711cad339b4590000000000000000000000000000000006f0aa0e4ab492d5adf5f7df57c33651411a9184d340c9f99f70238e86d2086f3cc64bb05e7f0bba5d17d0bed2feb5a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014bebb7142be81af4b3ab2147ddba342cffd8fd9d5ed3417fcebd635ec706f89bb2b720fd94e9cbdc57975f1325b2a4b00000000000000000000000000000000030bc47a8cba434fb7df01f928a89b1b6bc37f329f43134dcbcaecf2c801b0c4dcff997e2bb5091f8642036e67f9175b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052a0df3a550bc012152186454f7d2e1baece4d3e52518c3549987178658b391d2c849beba1b38c59f7a5a1ca2f8b2a200000000000000000000000000000000130bbd95c39843d155fc1b9b5b9550c9d4ad367294267ede51fd1e7392d55484fec319922247a7d0cd043908a3574dc61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b77256bab416dfe1ec204ad1aaf25740da6bf3a373c68216867d66b013aa25eb18dd5d6fca3304b1f66410b602ad2fe00000000000000000000000000000000021c5e26af09f33d971b0d6d845c348976b4bb47a1911ed8221e4a4fc1324d399222130a340fb79b472277159cf1ccab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014eabd4d76d709b44b76d62f627b895f5d68b2ad9d13dba3737f317005cf805714662bb25041a9cdea7e912fa647c925000000000000000000000000000000000862b0ad9a9625836199133846b76b397220fc938e17cbdf0fdd3bccdc7889efd402d8e75c0e093102c349d65804ebb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fec5e4b27246412b028b09f9644c6bdfafcdfad163465dd8e3dd9f7de1fc9b668583dd2e147ec61a1eeb707188ffbe20000000000000000000000000000000005f3b1e0ad454df724016f3c94c3cb360aebd774c203ca4720ea541e5383867e875a5810d9dba61650eb1ebe8659d9c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f061a77f054b019cd2acfc1e0bdc86fc8ae2717ba1d134cd241fcc5c338726435ec576265e6559887bf7c6d1eda248100000000000000000000000000000000165b133416309552da35464108119e75c005a9f1ccc23b03f5d42e5bf5c0fa98f98bfb9ff85101854f4d96dad7c9f5b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000145bbcc8efb04c44ac83a087353d1d231e831bbe22c097e0cf0b9dba35b374570825f6f21915a85b5428f19cd55ae1b000000000000000000000000000000001495df4ee901ce0fa2a23ea7bda5889cd069f88c1ac888beae4f502b664e95563d2cd4ff9682a25189ef60fe3ca626531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b7c2f786f69e62485a70dd9d2ecbcec0be6ec0cac5e6e8c50995c0995793077118aecdb547dce1c190dab0e9f8e63c0000000000000000000000000000000017fecf7e1b34a13c204e419de810acae98de49680f572645307790bfb7d63619ccf8ae2004d6fd517aa2dc17edf03ef61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042e6e6e05463dcbf912b50de03142d55a08194938995d372d201aa34aef1f62ce875f619bde166a60431e518a7a571d000000000000000000000000000000000cd0c8d95c9370dc2f96ed46d3c8ef6416765eff945011a1c41cc4fcdf7fd14282781cc6179ec53dac71be931002b7cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148d585a223eef942d3c04217c8d7c428a7f770140f6e07613a1f2037790d8214379529ecc66ac89174f6b0bc2603070000000000000000000000000000000000e4349031f08084877d0ffffcf899290a522d4f19cca8cd9268806a6bac02b22fdcdc1882757b7bde1cefb3272ef86fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131944931ce981493eb9182cedbcb6b236a48a4c5d57e43acf5ce23b2ec43efb6b2990a7f792c1a47fdf5361c0228e500000000000000000000000000000000018cdc34647824decdef26a24c5558e83e0690bb29cc30cb3a3fe055a2df57576700f1a8ffbb5048822067262a42e92841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173379f32053b6f82df42f14552c91ee2d07950d32771a493a39b1cb31fa613c6456fb3747f0cd3b883f5679faadd05e00000000000000000000000000000000012e04f47a65a2091623b88df8feeaf6f4e7331432f85e0dbb451a86cb4a9dcb2eec0891c96cd19bdd0216275f6226dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe3c14cfec078808200cb147daf49d2eb913bfc0f827c8532f48a61e80f78ec762a03ad951107e28cda132252c976e70000000000000000000000000000000018ac56a7af42554bf080dc608754cc3da106be3bf3e0468a01315892c5337a2103a0dac37d38ca71a4bdb50f6cd9f75f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bed8ca2baa5965cc05abd385a2ff2fa5760c327554c3f0826f8d3643427e74484f08dafe4b643d03f602a173e5f9bcb000000000000000000000000000000000ebb6e541bf97c37a5f7783731fd4fde514a501738aa5b5ae8829fbae5bf63f862558e541d0e64f2f8935512f056e67e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036872cd30e6bf3730b4122351c9afe60ab0938e0406a1c35a89d62c20df3496cea52908a5e2896f127ecc3ed9b4804000000000000000000000000000000000180bbc580508fd8e1b682d39194e9cca4d76988942691376963a8a207424b6e0efb585967192ef84f127fbeead7b32071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149b2dcd4d75b6b568462bc672269b4d5f7d2bdf61416fec260eeaa76ef318201c6a0e4d474926c7317261a8c92b30e4000000000000000000000000000000000b0cd3ac3704347979706d288db0de75a7b0ad4bbc7ff0314a2774094331b9bd92bb3ed8b1c27497d53e8741296676781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062a7722ef1d30507e1d80d6e84367ff79caccfe47267fcbabf5191ab94ddc49577fc3807c27057ab547b13a8c5b78480000000000000000000000000000000016236da7a03d3986a8fb9526e9c45b386413d58fc2f9392b1b318c87ad104b345cbfce84ee1e06b7498c747658cd78901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0e4833cd2e31ed370d4b3aa2e7f6e71bc5349be6eda14e979d24affa79d0ff62aa7c3ffa442cf3417a400b9c6ee3ff0000000000000000000000000000000017c438d862e1bc0f3d9f309eb975bb09620802b33584b1a45b23558d6e68d0a695d7ba7191acf8d20c3bdf05d905b57c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d12f5dedd3f67b887651ee178d59e4ab01b8f403d69ad25e6a5b581ab1f1b67212aa92aa143a10e5fce008d22a2c10a000000000000000000000000000000000e44700f0c164836e796fa4c15a5929ee4b2937a4583ecfa662bff008f446c473d45be3bd978e4b50f411e64786df6ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c9e7e3cf906cc0ff2c52d5bff4d7f7be1dccc0c6924db53fe9c2a8bdc46bfbdf11b8a440aefaa3bf095eb6303e313c000000000000000000000000000000000e8c7e38fafb79dfe6d8780294a59b71e77989fc899517ace11bd45b50b12dbe470328189efd2ef5a92eb2779b636b551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001bacca1d023bac30aaeda08c53f5379946ae67416838083cea9aa7e005ee4b4b829b86d9786aa392e6a32bbaef151a50000000000000000000000000000000011923f683222e4fddc50eb4219cfc7c25b93c8a23c4f480671b79f2f926c173909d7eaa579ce312d3fccdeb1008577851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1f4eef07aa208821b5e922cef7768d79d37c0e75250ac311b64b457b6c7ec03683b676f16af045fa35d45a31ce7c7f0000000000000000000000000000000006f7dad7515720433a7233e5499b2de028b1d84aacf5e9b026177a95e1c52658aae04a1957deca4eb1c9171d9ff7d0ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191d16fa600f91b3ca6317704e25d0d2cc1f2b207beb8e1e98ca281375fe2d23849e0c05a7a55ab1ce1461c74f1db08a0000000000000000000000000000000011bf998911c5c3f5ce74ca85fc7ff7d012961cef894b0fc24232994ef91decb4e0135707fd4c94aa39787f0d98e7f1851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124e15e1fbdd7ad699793f6b63d533d22599546348e34bf81149613479783206c9ff793a050042870e33233cc00b3bc5000000000000000000000000000000000b8e75ace9bfa5cc531e094fca551af997ae28446b3eaf7c84ac45010c85b79a2c3b887813c2eac646ad194932cf43201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001dc8449120f0230d9b2460834318ccc967d9707660df7931d69ac7c8251b12ac8bceba6a88fa5098032a2838f892e100000000000000000000000000000000014d803bfd175a0b64c7109d31c50eaa71e5463fbd5925c98b1b3ca45fba9bfac8760ffcf6f0620591c3293cd76a6e2c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ccd8c5f558cebb35cb12a8cf3149cd242a1202db8bfb0e3123545f1910ad9ad6ed1496c191a65cb14bc79fe49b7e8200000000000000000000000000000000005d355167c3e64ee161d95cb9c9f86c1b2d13c26576cb8592593ddd6b3d883d4b54affad00a8aa4502a5fbbdd9d44641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ca6ec18b536c1a0fa7bb2d6f7e13df668fb7b8ac3a7f44ec5895e2edc243f525faded7ce6eca8b24283617def845090000000000000000000000000000000006123df662a4abaa8d519b3b00dabdc0136ad6e096205f751fd5314e15e45f5221266070eb7e23a08d4f7416f20cce601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173e440d00f0db24e17de1ed832f99bef7f3e87dc4d62bf54bf2d7a6fb358a98d21ce9a6889caffd8c8c1efe6716bc8900000000000000000000000000000000030b0d475a7371bf619bf330d7ffc46fc8d81213ce04cea7b8110672bbd602baf641c570e52d85f35e1cb3ca68d487ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c36b6258f0b6044628aef4cbe97866c560218667a87f0278e02088b253b9174fa22ea325815bfe577b8a444f4ec9e3d0000000000000000000000000000000006409da464b9fa3a38827b3747f8d3d148c896a87b2ce397748a6096445633f09cacb978b86e074fc0eb016493d5834e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014125f783d1db6c640b0acb1144ffcde173ab1bdf3f23fe57967825487880c7dbfabdd7ef85541ec697dfaf20a91153000000000000000000000000000000000bada14d3640b8d3d16ab8d1a5ed6f52bd25d8a8ad243d962e4503b724ab192f0e0c8a7bce9b8b00d6f7d3c3167d65431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017149af6dca0caee7b1247bceddf5ba0de7f00995f91f89e95f7157b7eb6e9e7ff5e87922deb4693b4631dce6386da38000000000000000000000000000000000639c4cae1d1b7d539b662726ddbe68857349557a0b19aa63557ede2981f8bb0c69aeec7dd865b341cde2aff2bd212b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bc5a31331c53367cb4a8c0e993870987025866f5ccc59fe2bf8e90345c58d34e20b878530495029e9a0956bfcb007600000000000000000000000000000000043e5e7e46b11490ccc19a684a80b0b63841fe6b021beaff27c9a1cd21e3a3c0f7d16941e424e6c55f57ba258ed019fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077118b0b0a0e2c69af151c07e0f213da00a2d74fd8c5266eb2db0e8f959e04ca5f0998eaeff7b54f7cb467b462de91a00000000000000000000000000000000066ef94ec705e24c05f666d4aebc17200f78f835f4af1acfe3a5e91cfb03b921fa637def74b000878846798be51363271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101457ace090cdb1b31c9d496fc2abd726f46d1160673468e0b2abbbd6b8468c4eef46997b8453ad93ce4be61ecdcb320000000000000000000000000000000019456add3b9277da8250ccb29f48fe897c8f72df826fdb5568633b7ac0035a50c6e70e7e1b212cadbf39e156b57467611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054183fd4866f8958762e142f539f60f5706072d60574cf669542cbbb9455858b9d62e2d426ff5c8643f835dfd765fe50000000000000000000000000000000004898ca36cf395d9097a082722e81d09987abfe1af50042f516c7d32c7af849e984043d80e9b3ed0be15d91af242ec5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010e1e77284313aace464b4113a76ff4d831da44e921d07a13f8d721fd05cbf489e75e0fe7b0c8fbc41ce499559dc48c000000000000000000000000000000000870c5f40db041e511ba8dc46b8ade76950622fbf6399c254792bdf9edbc60db37cf10e7700ca0578d216a68b9f03e541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000801ba58a8b7a5962fbdb3d38f27aaacdd3f7896f34ff01a64a31c38c8a502f3a145457f3f631a0b7bc938c56f544e38000000000000000000000000000000000ce2c50bb97d64228298bec9d89bd5c82dc449f47e6523250ddb733cfcbe1c9c98e3e5fa359fd58ae030dfbd2262d9231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000155e278b2fd203fa2d4cb7a5e6670b2b8ea005b535d77f40c6385d2e191fc01bebb43ac440efb31e3d90422c5abf954a00000000000000000000000000000000124f53f7647e1332bf909467c9108aea7216cb16f41cbe15523450763c78c86d910ccbdd86bbf8d044c7625fa765a9d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e9dff6a35c2bc0ca687b1ffac9d5c93231ec206237217a5805acb9df09b1a6b8182f4ed9621df701af72792da6bae10000000000000000000000000000000001158134b150f0fba045e548c77ae725782ba763baa2001d98276d9ed1b68edb4361a743d549c7b35520bd7711c6952d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb1e3abb946d1e5ec9aa145361ac84fa9aa548f0740a5b812ce97d38f47e067e5dc8493bab6f37f6f562bb0ed01ac640000000000000000000000000000000001d93268d611f9658f101c1087b77bfc95b758632a6b01d9b8882e2d65c056ed5e53350f7afa3bdeab9a7eadf0ef22c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000068ac72074450e256d551fc7f224bc2f1a82f35ce9834f41f44b561dd187f7eeb63a4849c2096d9aa08d99190b3bb73600000000000000000000000000000000188f0a026c88c0a427737d452bee229b4f6d1fc83efe9dee0592504eb4fac80d325da097e4aedf60648c7e9e294b78761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001799070dcd77e2133bca4e3905d4a9eb5373d189447b5622bcd912324c084ae08994d87c5b88680a9c148edab6858a8e00000000000000000000000000000000177ad7211b87d01918c73cf3ce22e67b1452f2871bacbc9df8c91bcf6166fd6d4ef7bef6d4b414ab22524a325321a0951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009518bc29b9c1555dd6a453ee98fc077a433de1fb02cbaefe656d5217aba8bcf413078f9ceacd526bb2d6c22ce6ef906000000000000000000000000000000000aec729a9765cf09d5316676fa593c9ce6c636e64dd9bddceb22f1f30526804ab901808a936d904dce969eb490b0d16e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000724ab07102a6d42cc167f26e34044529b3bab769e175606f082d9320938dbfd4e7af54ffb43d99421bf8e829dce0b94000000000000000000000000000000000599b1179ed5b40a164e5253096781f93d3c001e42b2e2f24a59e543bb6030bbc1e4c0cdc8978b1ebcca119aab6f98ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013755fb6dfbf3d53eac9014904ad0a86114a1a6a52c565ad341f57fd9b697e5ee9f259b771cea32a0aecc915f102f98e0000000000000000000000000000000004a38a3070da57b8afe93397a2895a104cc0257141ff2253067f20e550a6cc150923e0b3565bd73c0927632b5a00804e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119074e161f944b8de7584fb5e94e4608ec2d5afb161f87bdd588667047333494d37996a0e039b4ad61c89495b253c2400000000000000000000000000000000036d7895561a20e465e3e3b818f486450478c219d8e6aeaa2541837dd95cd168aedbb12dbf39b964d29ec0ff456344891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003486e9abffafbf258154960a841329a943bb2e4f67b2e24a787eb837b051c18ac14da2b57f41a321d63904f69ac11fe0000000000000000000000000000000009c8d96ae369c24d8abc1e8e52659008165a106a0b1716a11ac60f2b232db48d79c4aeb9954bf93455e1cf6bb79181541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001772cc685312a4fb2b563e7d688d95398526a4ee0e6a226c3feedd9f511e5c0887efe1298c47d1cafc4f3733bffe79a2000000000000000000000000000000001948f103021964150c1efc1993482c7ee68bd5880997e0d1822e535dbe6efd9fb611e2fd7e85847bf2b6a61d8eb2fc131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000345c14c0f34092275cec8962bcfcfd54778ef6d982c6250f1bc29776cf25fcd4b7f34ee53567e597408a6ad06a08df90000000000000000000000000000000019302fd67d63b19f836e704feaf5582e7adcc2b07f87fd2b5e2f7fb26efec4023cf01e794b41302d98a7ae34157c38c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b75d93b7b637577c1d613e045ed26f923c552a1d63223009c6c11b2bd9aff6772d44c8eeb7acf52bdc0d6b9874b81e0000000000000000000000000000000019f32fc0a501038bc4a0a1aed222aec1e5d3dc965a50179495a6364c29637649c3f56148d65148928f1e0a44cc8ee54c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034cadf27e69da3988ffb8d18761f7de9bcd466334b92b1c2ce8e8331ac25d7ebc368795e9af09dd713c4e7167ab8c810000000000000000000000000000000004001ac4535c9a49c0c685d0206e80927c56aec9ac4d5e6a05188765b94c9b7410b0cba02cd78b56c102c4b4de7a965e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011cc99c8391deaf90fdd471bcb765a0a96c014902931f184a2a6e51f160f5ef7ca45215b50eedd9ccf141f9043cbe7b500000000000000000000000000000000103aa3681fe016866872bdbb6d68dafc88629aa57c7882809f34af0490accea82aff0e42e4d545bb908b72c19314ee751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019755fb221e74da759ea37d11bc18c620e84c00bc3640b735c82a936648484bb12f669c24fe97a057f6b65018d7934cd000000000000000000000000000000000ae45ebebfb387bf02a618581baf7167e93b20749c52956e02a01e2c985d1d633f79aa4fdd164cd4bf9ee0f75f3583371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2082ae75b670e20751b2ae3d8c07a5d5ec457fc66b382cae4f0a0872d28684dab8da7e9aa7460446f74de5df28618a0000000000000000000000000000000017c5e4f3dd572c6d29af9b903a2902af5d783512f18703b5489266a858e2f43d7b92251683029d2e08f99f2eed7d172f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a26baae206d7a96c508378792fce2b5092e93cf091d056cdff7615efa8dfe78479603460815173876166182beddc610000000000000000000000000000000018420f5c583ee7df775c33a5633c5ee166649dd0ea3a47bec20155df7526a1a8896d135c7f25c09350c25e0a8d3539b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b6864da0f142384f1dbc0fdec037258911bc60ef38e3236bc9ded27c26d81ac6cd6318d1740815262f9abd84ae13740000000000000000000000000000000013bb2161e04338d7f62ca1135a7a449152f595ac20eeb5eeb2ab5c8bfa1e978ea762272b10252db3b9b9537088ae9b041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000313d3e5752444afdc4f85d55b0045848d5e5dd06f20f2ed722b9f31b26a0b671e15c0954307c88a9150ff56839b5ae0000000000000000000000000000000006b9bf6d6c3b961ec2f089db75404272dc47f4d58aba2e3ea99a0500819a22fe062749ac8eacdd1f551cc27ea5c32df01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d63e7b99854c7518c607ca8979f7f3bdd65a2d29ba7559425a0e89b9541b5b120aac109314c4730fe2c4dd0a7cc76b0000000000000000000000000000000002d990913bea08b6c18a91aac227cdaf3b226eab83f32fcd344a7d78dc28618b02062c982a3f5cc9d91516465a4029541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001507f2acc08671cbf3ff04a73e5058b8fb4ac88115835adc57c2940a5d5f74e18c8081ca2973da6cbccd0fbaad0a39720000000000000000000000000000000013168837b1c77236150f8d210ab94ce331b199dd53de7e42cb55fb7615b4255dd626efb8b6b028dedbc987beda252c361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147067371c214b98b6c0baea2234205be8dc11d148689e7807a07def24e2ad0d81a761354834ae526f4ec3e354ff46040000000000000000000000000000000010628ef5d71baf6b7c220ac605a567cad025c0a5fe13d1fe25530ac1b1b0a65d2ad57b5746c8f799473183c2294e027f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed037e4cceb9efcea31537ddbd9d2be7ffb9059217d52a40a87b8eb26dac6f05e45fe9deccaf8d05b4b36a2a3874cd8000000000000000000000000000000000cc732bcdc9dc08fd6aeace39e623e0a9a503ad82d5b0d7ab5a78a34383f7edc5a585138bd278fe5465724b2445a87dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023d7c65c7cce5efc4453b6fefbe9d735782117b125f579a65b25dc429ebd9baed44be6d99cf8e2abe94557ac2e3993c00000000000000000000000000000000164354e3b077b0f9c14d6c7c7a84db94615e434b807011e2f215ad65aa85777b9b9892e7f2a3b8ce7e203ea665ce46251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1217e68baf9c77132fde06d3092fe9da378a40885deb0bafc5600cd11092f1978588119d668e14edbe8f0fbe83b599000000000000000000000000000000000948af0118880d8dae794692cb2b386dc3828564b31f1a2407af48fe4c197159dac5b7dea5568915599b716a06764d5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007772545d564c170890f853eb935f873b7de123edcbb07d2bb3b21dd2a59dc1e7a63574ad560ea5cf4bb529f939ba7fd00000000000000000000000000000000132ae7de1b7abfd605e9df2c8522e18ee342257c44a0f0437f8def12f41fab19eb45359f4deb669f2813a53c75997e071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b108b091329878fa269e112edb919ca0e49e35f2a4ccf17cfa3b236d44edb34f38d2fce1cf0d5b164c926de74d48930000000000000000000000000000000001350c7d259f785468b05fc689bd515f98cd7c4c80df214276fc01152a617ce0a5e5e1947ed2b9c6f7cc0fe4b70db7c0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067797f0faec22dda3ded692a3122008d83d806f3e62e181322f35694a70915d7b9974b836f4961b257300f862a804a800000000000000000000000000000000134aa4f2dd4c0ee1f20d4c51e4d8a95cd241e9214b55d3dd22db840b603c8e03ea92771f0a6dd31973386e781bf9bf111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047a579690bf2cff3a32cd5df28a1222fd38e32217f96b29ea2cdc172581b6ca613db553aa685c68d253fc3c987164630000000000000000000000000000000007c3e58e4de4d4786f29709fed5b33f03d9a92d067bd62ea56aa0a18f184665b7c22140c225200864bd105f82c5e23ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186e195da6d8da3b4ba93bb115de35f83c59078ce2e0121d0316052b923b16b41b3517ddd1a039b03a5db1ad5e1f590e00000000000000000000000000000000047eb890f2919ac0f894718a1f55e11fb8dc1ca0f6065e71574b00a1c5520e91143354820b393543f97d4d0524bbc1ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7d07d2db3374ab1203ad9565248f9cdac1552b86c8ea325dd1532c31b21d19dba4d2437847ebe020fd72125e89016f000000000000000000000000000000000ab09e925d1b1895fd10a14a9ef322deab88f4ce9029e129fc278ef77c87be6646bb02cbf8609be21ac96a4e07309ae71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000996850ef0c1843cf24dad6363856cb70b81b5e974d62c64ecd3c6f3b3bb16fc8fa93a9193243a99f1e99a3c66fc4397000000000000000000000000000000000c9938109950f4e4011bcd5d3a57da43ba5aa1ca967ac2b3bb97eaa71e611a7ebc22db32e5a51b3c5c89bd73f8b990f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ecdb77dce577ab9b2a7e609b7e5c1dafff253ade5721cee1c6bdb04abb2fc184c67dad90fa088c7c8989cd7780fced0000000000000000000000000000000019ad26889948220d2d8d34c852c81dfbd3c71c8b9b77e8103d048f8fb8a104b5659c77befc0ec07ac2a26c200b09244c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000869a8f614c3ade83b0af764d7d2430f5d9bd01a3b84d0050d9b4e7d458b4517c5cef7e96b339ee749375bafecdbdce7000000000000000000000000000000001940807fe28050ff5c7e8b4eb0fd1a87afc1d40b7f881700c0f0e7e79547939ff643ea5d0045a68d4bc0b53063f7e1f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7cf2bbfd6c2073089616a75c59df78d38fdab556e46f6f083e6422f783c5de02b4ec1f4edb8bd6b4621b37b61c46a3000000000000000000000000000000000eca616275b579b77074a4437758ac72e273026518a5ed8f40504bee9acab4913e4db7dccae17931851501d1cb4529001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001135d2888790fa5f65ee520a76c03f019a35044c4d11f25a1af647230f47d0591d3fe21875aa18d993ef271d59f58ea400000000000000000000000000000000024e534d655868c137a700ae673d4d5e70e4de6813ffebaaf071547aaa97e215ac6d91b252dfa30895af12159ae7cc541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000731e1d5e13101864ef558ce08197a2967f837da91e1dc92bb55b0ef3054f2ac8f618006350a58bcd6bcd53ed5effd09000000000000000000000000000000000133a95b9eb4429e3ccf7f46acdee581e170df6dbb9de9dc0c4eb2bfcd297a11bb06b2fa158332e9ac82bcdec75057941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a16dbb611322215c8eb08bbf7dec61b584209ddb1739050bd18dfc1df35592df956ca3badfe09fac6110f56dd9535ff00000000000000000000000000000000116ee78b4223868a8959fb711d543d4a3a4a71de196cd1ed276ee58ee86f9f0582178c51075b8f56e243c707aee84a001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c100ec958757aaa9441ea5a3f715e5249c93d63e2bebfa5f7dd2622a0884ee6fe6d164fca7a2b80e8627477432e2a10000000000000000000000000000000001f07661572e57d3e17b528ab7afdb0c8318010bcb6e1fd19848de362e71ca448beb6d32ac8a1bdd2870df6d4f3353491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018205e3bbe3e92caa3972de12e92b86f11f1ebd46f51e318fb63bccf25767288b074b3e4c3f71fdccec386b7f2da0436000000000000000000000000000000000f8ebf3f886b2eb11707bf154a787a7423c368f7d2aa62f5950a8f80dd83ca96c8be8db82de8fc3ed1a65ba1e939efb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000285137a9709f40bab114f5efd2af714d10c5f7d7299c9966f18e5dbcea65b696a7c2b43810a4a8aa5d70a4784aa81e8000000000000000000000000000000000ac3ed78ed88fe0c1cb6905957d1ac95434cea03adc2f532dac16574b7d070c58535362edd50a0092842c59576c169601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001970ad0086a67e4fa67800be0837f64e4c45a2e292ae02208886b5955a30ddeba56fb5d4bf0f21dad884749fe3269c58000000000000000000000000000000000bf4c81f8692c50308705cff255c889198798d504bf4b5889b5fd98f63fefb5233c604dc8d8960435810598f0da667351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc2811da1fe524a25a154005dfa97a47c299ce9e1e2da4c93d4291d98928446e0ce5996a8244048964ccdcd9bdddc5900000000000000000000000000000000128cc484de090f0f921bea4889ac6e02565088e6ed12f4c36eafc6c57d2ab1166290bb3dcce726d95175d7fc2e5df48d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0f2d123755bb73c00639c70385dbc989df17586c35eb2bde85341ea6afdcfa17727e16979e5478604e99bf7657a35400000000000000000000000000000000018fc90c0579347ef3238182c74dce4c4c87f370bf97df4a91085141e6b8b3d71965c1cca523dde99a282e7c5dbcf6271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000054397ed4ea06f7d9cf5581f9488d3f96a477465e65b726f712f024757c1a7d3d297da93e56d6d21c8b600a623cfcd70000000000000000000000000000000018577aa55c945548496558e25b988465d7d9c92e97541234eca8787da4ad4d061978c27e9938585f373ac6ca39eeb5d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000620f809bff2858a302347e93055e9d41b53547d82495de4b9206bc7acfaba1397104a8a44711c5adc548738fd6075d10000000000000000000000000000000012aa46732b82804d324ba18c37772cc40b60640e07ea063ee2679c2456836d344efbb57bab86f434bee0b7432d9fe2f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190beb7d10b1460237cf097c823e14c0af827c385847cdf52ba44951e03ef82125b6e0841c1b07e10a3191b0e3841fd700000000000000000000000000000000111c682286a2146ae42b4b12a9ec2a7cfda346fc76d873310bdbca70a9645157eabd8fee7860b773e888b8d991fb94f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001201c17d111f7970ca13117b84e1b8128271847db6b361fa8e1c686d0aa29383a58828fb96ba8a553027edcdca3a899300000000000000000000000000000000157243b0ae6561fd2ee45cb8075e92ddc83430e2d9d643965c8db52341e3c3e8bb9db4fbef599a4f694a1690a1b8a6761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001209e385b8a9c8c7472cb9ab0c65a8248bfa0b69d574a22dfb1debe6ed61d6ba911d4602e8a2d80b78860aca5214ec7a000000000000000000000000000000000fc610f79469f54517b5f03327ba6c04f6dc44fabc3b65f5459b62899474004547a2bf22856cb14b606187460cf542d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c0c5278b1f95283722bfa78b14d30b7b81b3e3c3b5ae6fb512fe5eb4072c0f28558b84e2dda700328a2630b23657460000000000000000000000000000000016c6cb3012ae7f8537d02690ccc92730854c5bce7c1e7189bb285430537908e1489473c1e6f5baa99bcdc8f9a16fe5c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017948edd4f8bf62cfd7a7d8d129a85f26d1dca54ff5780f6df9abf0968d82dedc23e570aeef749624a4fb28b2e5b8ffa0000000000000000000000000000000014117623e92c4a0311ef365a38f19896525a939fff48703a3baa13e241f3a595faa267dfaff29af0456f16540859bcd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000625a3ac1862a0196ab6fc140e1a61eebeaa073c8580e78ae14079924579171c711a5375d9f8f1765116d5c25807ef62000000000000000000000000000000000a86a33a35c81e2f799c1b47438a1e03a72d099c5dea53389c6c4f33eecf02bf5f6a944f0b1d6e28fd315dee9eca08f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185188627407c10e12ccbd1d6ae90e64260a424e26969c07dc22e6272d96a437cf27ec989909e69309eaf5d7649ef0f5000000000000000000000000000000000dfdc31a362aca57db0e07596b19a3745312a2bd1290af819500669658334b7dee36d0697ffd515add2d81b091e8b0401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001182cffc34b0605dc65f43966b0c0cdcd79e657b458c0efc4b1857b5e3699301e52241a43f53cf794d5a3b6d87b131ca0000000000000000000000000000000019088f3bbcfa5c28db3cec94b87b7c915339d8ef65517c5ce12e4e9a7950f60088b67705fe2e6911fc335bcc6c971bcc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000106d215df1c66952866154079ea0b71d4ed47b0598b3991c322933d146ec051ee75ac4546ad95f52ba28cd23bac32c5000000000000000000000000000000000da4c23d36f248b6f10a58d20ac790a5bf26de745e57bf8a23210ddc70dc6521a450a2926b7da43f2f52fdc8e96d89ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142fce7069d5ef6851f4d6ff5d9c1e010e40965b5ff8951610c128118787e475aad0337255da25649a028f36ccba1d5700000000000000000000000000000000035b1116c0b9f0b68a1374ddbafd2f883ea9a01ea54a8a71873bd638e4669994b0adb3f498e1832995124fb88e932de01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3443d78d116a75b83cd6340f143b31fa316da5b5269c679d2cd11f6333a87aa3023ccb38ae3270d2ff0052f5032de0000000000000000000000000000000001786786d48f514cd6a2f49342f4eb1360903c8a20792c19b2861a49c9704814900acb668842a4a4d087034a8e151c7c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050b55c82609c0f1a90847fe66b2896606956ae641a4ed85fd15489f25f7a3dab66de41b9f58b9612e7d43e09c045fbf00000000000000000000000000000000019c79fa38536fcef4784d83b06dd9cf42dbad0ae1988558b9038c8d522101a51bb1f8b0cec97b025a6cefc29f8b65371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001612cf45ce354e907c06282d34b5b24845f255ca139c0ae77eedc317552665a1136a265e4043249b59a940b5c008728b0000000000000000000000000000000001dfc7b5586c7aa4f96db1bb5dfedf2b6eeee61f108ecfc5f0d490b00ae9d630c9b25c6d90711b17e30799da560320381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a828434635295ac6175aa01b1fae2b240a395712dd13c53260e6654d789dc1afae4ffeaa3ad26fd6f5213eec087789000000000000000000000000000000000e9dac8081d53e08f31e313a88ad7e4865854ec31f18f5b7bddb6aa6a5418f37815c1c3afceb95fd008d0567eadfbc681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017da4b4b2a1e010ae158c8df7d5c18d210b1949aff15c562b88a0cc46190ebeaa6f85a5c58432c15fdb8da44d40f41520000000000000000000000000000000019c7ecbf1d4795a55455a11f733712136e919d43540d44a982f6138dbb0d70b0a0b3e995d9701a54999ffd83200833451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000326587976be62f9b310eecaacebadd37c14fef7f95b2377839c5afb9a8f021cc73cd5c37bd8f2d629533ec927627d20000000000000000000000000000000000fc5df4321e26b1be94383a3c54cf0a41869742f25f04944ee92b0748605340156eb762c8da40dcdbd4e55e09975cc0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012442cb20a69c228bdd002b9159abd341728f38fbb8261e9fd17c2b23a46a986fa223d868447d00a8cfb4deb51b2ff00000000000000000000000000000000019c62ee4dba3cfdbbfd73e85cdf9f2f024715f971a46944b38c94a489f4e373eaae86b9b0167d0d0dd9368dd7f4de7ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073421749ab16e2e8e6225bb1827d67e10ed3d075c36d0e017de6c557c1c6357f9981b17ea73d75284f32932536914c000000000000000000000000000000000177a176dde7e983381157d2a263f55334c483bd8c82be074094113bdfa693750e873b2abcf51d70ad4f33ef3ac10f7321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000afd15e3552ab70088110fa92904851d0c36db558a3d65d16512f7bbc9b8c3c9bf0e71e3ca4485d22a85d2c109b470370000000000000000000000000000000015d1c16181beabbdbeb0e472474a898e2933004a5dc40fdba76e663322806cd4a0f46d3a5abcd06c8b940b815d348c3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131e1b144ffe856ffa047c130128c91bf27a3c59c7061f52d2a08842ad017bde74d62671d65d8be7a3c8bf0a451c39a00000000000000000000000000000000002b7f14f2aa6e30b88bad39feae7154f9281cba2353aaf37e5e2c3de3d328aa45d2c232c5759a04224e1a07994553a151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ea693aebae4f5e02229a089f0957f1cc0bb9db7fb5e8487e38ea229e60cf55855d09cb979f91aebb0b813144f69a01000000000000000000000000000000001258a1de6cf07585dd6cfa88d87589a8fd0c055947d93d968af516107b724966fb3bc5c47675d41ddcffb300331be4f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010604d4fd199b8308a8c9e5b0a62c25bf6cd7275d9182fa6d781c7ba68bff1140d97ae4c61aa29c8556fcc739f7504f000000000000000000000000000000000682de3a5a795af0a130d106345ae8e9d8a5ba2523fff38ad5c941117429786ed1f0e562b1628c70036ed56b91a8c72a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bb368a1ef9eb8946f19372659a571250784879aee50de4efe2e43c148e8c4ac84b23d2cd5626b54acf1cb0b6deff1d000000000000000000000000000000000efb4f97ac9011faf83afda4be67bcfd926c7575ea43654645a90ceb79c6c8d21d189bd46fd979869512de7517ef60221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001310cb34fd5e8055aab5bde3aa5d8b69f71d52f31c1f8b66a167506a14eaa2faadb74604bada4e6724e7c197c27f45ff0000000000000000000000000000000002dd62a444bb0a0c76f80c735a4723317fcfe881a900ef74519f397d9d0789beb6fba90666bc5f3805edbcbb8af9cbaa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd526bbc54f5bd7e7fff15d902b69c10a8e046e111837d907369ad3e95e811a99552701d0731e2ebdc832ae810707c5000000000000000000000000000000000cb023201b78c82104bbcd0d498d2d297378c36779c8976263d3350f5a1c3250bf5adf8be2ea04ba3a5a6baa7efb67ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000515512de97ef30b9ab9621813ea3cb8ed3157731ef6d9929112bf46cedf8941a83235216e101e74ee227bbb0d90593000000000000000000000000000000000165bb45cce8bd2eae73e764c7b19f19de04ad9ce763a332db6be8a2b56194d673f9048602e6236795748666f46bbe3651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010dc069d80b23610db1615396c173d0750307d0288581d997f8ccb2cf63f235d638e564018a901179a301696d9b54e4b00000000000000000000000000000000098f8098dd74039cf3ecd35cb7744a88618b0a0aede9a5e4ab78e5ab14639562cd85dff4618b4337e2937c0a4680a6bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7ae9d8a83656c38bc0eb6541f19b00a9f29f9ce5302555cfacfe96dc3b3e402453e99f23148c0d98c95b54f070d074000000000000000000000000000000000dc7be7595475c0db9ae12970b3908159a8872ca5fe1cacee0383198b9f9d40f18223c60867bb15aed46dfb916669bcc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059520c4c23093bff92633d8fd3ac3835f3704b661d848a4978220ea3b3128598edccca35cd20f3da6a3522be82ab62b000000000000000000000000000000000904d8cc09be578feac5d9002ad0bd6612b1a83eb3cc71789b90cf42272bf9b1a6b4f365d7b06166affd0b101c5bb6571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000518b7882d2e8f9b3772abb215f2ff11f4beab7752e41a44d5e63b18acc77d095607d7f4607055c030935f2a862ac10000000000000000000000000000000019a1ab8ba196d1de6f7ffa5dad09d7a276b492694754e050337f5857618639a5463f810a74425473ae40bf6d3a97a4801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ec66bc157c486d766b44558ed391444a323e86ae996d7ef1c7f07582e30f2b0b14549b8f27e27ffb1e82b09b1308d1000000000000000000000000000000000c1d81179e0a15b19e03ea2d8756bd088b98846657b7cb6d6dc364bdcd28e0c79bf8368ade430ba5e83365b37b030c841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dd6a21feb39438a54b5f1ba21126a761da7756b061326201d92f9ec9673f2bd698ab9f51cafb3ff83293fe340ed57b0000000000000000000000000000000009b400345b879beb2bbc9ce5b78b92699d5f7fad9382988511aedab5343b2492ebf374025490d660be0f0055c57eab7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cc4bf9a40dc806a8a1f324a812432f555d255ded0055a2796e3963e3e8e6ddfaa6250e6a56e829a1dd0ed35dfa8c33000000000000000000000000000000000a5b60f1733ac2fb02ce534bac7234ffcf54849af139ee16f808b838470cbb966237a56ab6d1a3355903f65df3f1f9801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138e280d4e7eaa30dd2b366c3ac26839cb71bdc64374d3cc8bf1ca693e8ed0755762db881da4ca36a28cc21696190d3c000000000000000000000000000000000088658acc052224756de51f5d41e12b764d767797f3647f0f8b00e54ef9479c1fd898534fe933fe571d2427dbb1e85e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e28de35850759362fffe018625872ed58a1eaf4ae434926065344289c35509e3fbdab6830d9d545dcdd9682fa934a130000000000000000000000000000000005454144a0557445a8f924795abb123b765d6ee824c6a7e4f3922b385d02efbb3e8b524e86c8b7310772366bdbcb238b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6f6881e6e2533c4997702e5a73aa29bc12eaee130b53d90cb492e075baebd119861a794765e4f18ac68b670ccc37160000000000000000000000000000000005cea9b2d319b01ed4f73ab2da998447b46762a36d3d8c182695714ba5ae4d4136d259dc3c3e55217d3d5363421e189a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f432fae63fb74ca33b30ab4ff62184d586f931c8fa5a2aa223787af7cb2eb956fb305a947a18625c9056682fb1504600000000000000000000000000000000166038ce66fa6eb68296ec474055004fd8fb87023726095a0cbb20d38855f8bfc29f878526dcb3dc88e334f2eec85c5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048c0ddc42bfc8d17303254682b7465037c11f37e34ad5143a62598a8aa8008a2314f59ec7e30656db6d1e013069ca820000000000000000000000000000000012da64ab3bc4e3d7adf0e0b6000333259ec23c33416057695e3a82e34d5c4bee399f3101aad9034881b050258263d2781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026c02398513f62ad752163dbc34edfa64b3b5cb4bbf5961693c7b7d3fdb0bfe914030c0673397a52f5a1ecf6f9b3f4f00000000000000000000000000000000177ae0e79802ec895c52c408bae671e01c2570a968eaed26f625b75fa9c98c4aa16fb33922fa621a5ce1f89ea9a9d8ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018522ee067b8c624b5dab45b3e76f577dcbc8e3b58491c87aa267c957355747e10ec1240c1b1895d9129767ac7df73c90000000000000000000000000000000007e481f44a18a8aa0573aeb64ce06a5da8112059c4448e312c19bb9867da5e1b9d581f4dcb0272f0701b4b8274d1ed971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a3845b662736c0ebdd261900cab0446da8067fcbf7a3e126e074da03c07d6a277fb82b65c54844e4fecce98f448d03c0000000000000000000000000000000015c978d1d4e164073986716f98f2b363841ae6f02abb51221d6ac9d632bc1e6ada434ea272f66de1949485dabb8e9bab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001999a398ac3d05939b46130a21c4370905c357cac3720f9ca83177c45319a79dd7af17ecb45f2e0ec82ccb3c3c8efd8b00000000000000000000000000000000161696716453d7a6818bd38e1a2a56ceacdadd5004763423bb254067331acd2c84438091fa9d41213f3942f5499265181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101d2761b573dc0950dc9cdbefe88719c084614a98226660411ec9ff2dd9c2b812a829f7552f2f533e46ca0ae94e348300000000000000000000000000000000009bdb1bce7e09d70dc47ee43adebeb7bec97300355a012058377c2b96708a05b7f86f055919b45f2a7df6d29dd6a9c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000003d62cd2eaa9e2975a85489d9a89f61d35430290bd971b6e42f23ac590fa0a76e9704306191a8b3929dc05bd386c1380000000000000000000000000000000004bd4aff6e01df2a6f1cf6eeec2d5e64e7549816cd00715c19718109b2be5f0d313bd89916756c0ccf8b172c1110a18a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4901d2e46c6ac3c9e2f39464453a6c7daaba5360707a7b2e6179cb7d6d225fae18582fd37f2c47fd75fa6e14edaa7a000000000000000000000000000000000704fd1d8c0f2311f9c947497a217eb165956aa49ef8fa4d3073f1d29864723789c97baa5b7c3ac92a2c2771e0279ea41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e36258b9fffc7fa146f28fb68a01508da0ee1bbb378e5b9f41f0d7116fd7dcb5088f045eb7f47f74cec93b97e903be00000000000000000000000000000000174727af9d6ef2e5699c931652955dafee15e876948600178d63cdac64936161f525bb077e0be91d1f03e004a913467d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015779a8bb3d0fa11638c480a056e6981a001baa346be93e1d627fc083640e1a0d12c089a1d0107a1e412af20f3855b0f00000000000000000000000000000000155e67a7596b01dab2713c60f182387d407a50d03649165323b27a8b59b7301baf8323f9389fe0ae7a334dbda543a54e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017325ee580951c62a534b139f192f92e74f60d78f4789becc8875eb92de409a653fd0bb5d3ad5e2b9544e27f6e1eed6700000000000000000000000000000000069d03b4e569e6016f31c6a66597399760b48afcea915823769a6adceb83fc1b38b2b23fa63d5915d5930ec8c555398b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000badfce8bc55bc07f5179ffaf9a4d9a7d3665b894579cef8a00b6bc75c3afa7779c949f71f74dcff551f0d6b1932cbb3000000000000000000000000000000000b0975bd4e9da6a51c4a258a26102850ebb28cbee526583fdc31924da31effc7a882e39074acc612ba0e5ed16fa975df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018380995a9e08108fa4ccc420b5706d39fd482da48903006cf0ee45dc9cf281324631566c19c10d24ef65b07dff674a2000000000000000000000000000000000e3a4be63bc1e0576c8fc947370da4496e73ed39f87fd4b924e4746dc619d85753db0267a20497e6ee9cc08cc9cfa8c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008153b366c75e0e0ec84576263c008d034cd6e7ea70662fc5f5054a37761f65988953f8377acc5de8be88afdb18c237000000000000000000000000000000000adea330372e62f60541baf13cd66b3b1126774fc9788f9624e7b725839eaf0ebfcdc2923dd24a3d3b73a59e8123bf0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f054a6035cf267f8ab2394afebda11d1fa3c38a998306cbb6110466a77ec83a6df1690b93bad4e8f424a21404da5dc0000000000000000000000000000000009fc6eb95f5d23a2ffdd888357a46f3303f6b7b478ea56506dd4dbf08ffbdbcb87440420457ceadc79d6aba39cd6b2681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000345b2d8dd8f4e9a6675863a0091348a7e3d6ea4e741640b2f4fda41db1ce3b239257d5e0f3e7b20162269f10dd32ff2000000000000000000000000000000000e1bcc0ed478c19ffaec404ac08a5cc2ed281dbd3d786911a31b865d841bdfb2016e2a91c1f8ce12542ba0fdb2bbcfe31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c2d8d69638792165f10eb43b3bca6f4b5803938e145ad2c883d5841dfafb399cb5660b9fb3304cd0c7835f232414f00000000000000000000000000000000014b83f9b9e6084fe73f92a1fd244fbb3d8bf1a90ff4848bda85eb765a4c64a2e10772129847fb41dca548899ad991d221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f641652228c5eb7eb2356bfaf53dbaa107ef15c27fdb92ab86f200a752bbcb30ee81424398dc59c0a7a3d5ae9d52a9e0000000000000000000000000000000019d5c91329ad9abe5fd7bf87cdbdc06aced85c6907dba0303a41ac6df49539b7ef2f30803e8f81e4a981049f121887c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004021b8c38841f20d012ea29bd5944d8765b8e9c83e52f4d0b970972dfa66482e5ab7b06f70fc983ab214ffd8d50cb2400000000000000000000000000000000041a0885fa7e234060995d727806b274b0b8f88294693c2da78fe7176ec558fca7ff6c15e42ff05b145f57342602e1371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aaf70a2f34d052efe881db309f225d9965cbf8618a7b143ccd68546739c50aad4d122bc2e05033089a4ac511fb27f08000000000000000000000000000000001820337d5f774f4041cb59c00b97e3c2a615c1eaa3358089ec0bbc69162679cb15daeca255f1de2f01e9964fac0cbb731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000611797ad7ef7d620806c4a48fb14a12fd910cd804d9ed063954548e21648185eeac5b32efe6b80a36a2385f6b7c09800000000000000000000000000000000002e81822460be0a390aba478e34d66526a9737cc201e85ea90c3ae3186fcfb3e42fbdb1be323b5819d337a97ffd20b261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002efbac97066058dd071f356c60bd176c2366493c27a708d4ffa9d021be7da9fb4063cf05e98f11f3faf36f39387f4dd00000000000000000000000000000000190417959030a3137de4af1fa28d401191d4b26343acd45b5359d82aff8e95acfb46b1c57bf3573bf1c5b21e49e659d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4c8ead75087f1ec889d543323e499673280b27d16c4528c707ca471376fa314a8b61d4ba71b260e8c27f86a8b76fac0000000000000000000000000000000007be34f41f4e434792c7b49775f5e2fc1da83602d99786a537ec6d1ba8799aa10fddbf707a9ebb65f579d129c15478f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8e6d9a0d1060e3ebb477765ca2e700927ee2c0ee21bb8b610e8d19adb1238b148c40557b639f4da35e4f886e3b8abe00000000000000000000000000000000195cf51b62e6a68685aa6660a3724302ebab9ed71408581d2022257b96b988bcc6458a515839ad300d91e3939c81b4001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003180ed4414802774c2564e8521b0d4280ca86515859cd628ce9ace55bc94aab11ad46298ff58b28896f2099ab4a360f00000000000000000000000000000000139374a224c957ab072918ae587f8b0a0935ea829ef0ef75901bb939618849e70b562890427e9cbaec119d1cc952cd081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c2fa308485b8567c1c76d2bf4e0ce87d714c51438b089afb553316f11916c5d5802dce99e456c8e79aa70412b90faf0000000000000000000000000000000009bdce6d811bbe8cbc8d89ee2a3472988b727908f7a6651284f3cd805d0bdf2a959d40b86fe18c49120fefafeff22d6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f8e7942c65d59040f07f4073fdd5b4fc9c8e7340179ed19d2927696f01aafa4e45884ada8efeab6fa59889df87329a000000000000000000000000000000001951ddd6f7a1f6d950e956015a7619a2d7662964053a09f98d2ca3539583f9fb5b4f0578c03ebcfc136274a77a9deda71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ba963531914ffe8b5af97ec4b5656b99d6124ede4328462a2d809459f3f9d2da5ed874152685137917598082ddd0e3000000000000000000000000000000000e98ab1eeeb2a528b88ce39e6e4a425549e3e29cc080874c383e1f8778015c23084ab04777d165d213045d54a4b434561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001535f3ff1366bdbd59e237ddc37e23a0c92f2974306e57a83fe97e42c368ea7f6fcb62b221eee2f154ca33ceb301e630000000000000000000000000000000009a4af87d2a599d2316d0c15793c0b75c013a94bb761f5608337d422eb588102d54298730496dce7b9c3276360bfd42e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f10b7c6e19d3c39324d07acddfdec4eb18a38e13b16a8cd8e3bce4fc4b204261c7d470a9941cc50a11c99d9d00623a0000000000000000000000000000000018db27fa37cfc87e069c35a5bad3f7991f64fc6dde2f49acc75787c8d639745fe802db24cf5f2aa0b196ee09ac1c9e601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b04fcde9d433bbec0873c436c914b968bb8dbc8403bab6753e6aa907ae7049973d5b88fb0ed306611ad968e69d310580000000000000000000000000000000007736d7f597f41c02025f2adfde4991d1fa7b65aafb7c8fa4e3a626b18b3270daa603e9a5079433bbb921bae8b1f15441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f7ca8cacce156fc6651d5f60f01427683ffbba9ae23a20171cc0e8429db2416725557a70ed3f91879c70fc1d5d64ce000000000000000000000000000000000f0fda13ce09ddf6fa1f808234cb07b0b1abe22bad611d372004c116ae66a70f1c67fde718cb9ef8fd9d13e00b140be21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f1700a75e9f2e0bb760a1ea941afe719b973bee31d62e8d74e8ebc2cffce6eb6dc2944bb8147694cb90b65fc5b6caa0000000000000000000000000000000017cdf01e6d54647f1b996b85223e0fa40c2771820e8c672adb514e0c8ca8889eb2e1315c2df13b730b6e7ab1ee209a561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000087dd5d4c827323e1ca76fb04fbaed5e67dfa2d3e775cdc23c4092fc3f1f0bf6a4a25e419912cb1169445d723b4e15390000000000000000000000000000000013be5368018527fdc50236909eed1bf4de7ea4a73df85aed243bfe1e0964b2545e0d06c48e541c33bb882f7e06a016961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f281392806950bba3d5b03a94f0f0c4b575fd0cefebbd4618f69f8de5a972fae47cbf54cb6362f736bd28261dd4bc7000000000000000000000000000000000ea479191b4072b72a510f33a3bd6ceced2b834d74cf5513a9ddd90c6c28e0edb9c3e2aeb5a452743d562e9cb342e0ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010670940ad9e2571a6d0d3c9560b7bfef47da754a08038994126aa960daee03467596ed8950e25c2e67525be99d37840000000000000000000000000000000011ab6adbca985f0aa6cfcc6b5b248c1653d210bea583a53c125630c17c5692730810227c4a1746f43436da6dc9714b9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a3bd791a3b27bdac3d89c26ec02078650f6f2c1144d5ae03ef0a39071e4756ae9b4dfaa500bad7b659fa0f22e3382a000000000000000000000000000000001524fcab621e8e35c995bebac8b567b3d55a8d9fb766f8fb9ffe8de5b9a3082496748843d941435bbd97ff4e1b4fe4211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018fa132c5142dc3db0bfdbc39cd64c03199859332e7ac16a1614c528e38342e83a1c0ee043011340e369fb5ddfff2a6c000000000000000000000000000000000af1ba67396f7ebadf48f7e754fad1afdaf2168dfae475b44b81914857d227f09dc398a57bbaa89e44ffbc3ae43642b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad8c9182af98ed81465959623ab3d76958c019f5ed8edb1dabb340069e2b8e8cefad89bcebbbec41d898647a8a93b3e0000000000000000000000000000000011ebcce1e38cc7e38e6aa8d59813aeddf0bea4fdc462f83c36ccdbb4f298f1e5482ac7d2e5b8b01e6ab94d377f03b41b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a217579190c9171d32e31d1a47e3acd77199dcef8d0c8cbefe28931776f4b5274b1fa9fe14c55623f6ecf19049131ec00000000000000000000000000000000026bc9aae5e03f066cbee582eca8177ad5c1b5dc08ed586484ee95c779d422e76d36fff68840e771673f850b296ad0481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011fec057e7f9cf9ad7f00146eaf2004120b3b75c0e751174c583794281b9ac1fc72e80ac76d54a70eeb026ae878a19bd000000000000000000000000000000001137b13c750996aade79c835b706b9b8586203b9398bb87289d12c0356b0c4c2135b1ba78dfb615b105659f111529d411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c595a8e95355e5dfa3a466c2b80ab9190ab3528d6ba3df88b79a8d8b17cae134fcb91e206b3421d35947b9cb2077a90000000000000000000000000000000005fee1ed612d91c9c090c2fff6ed195fb7407e64261f88875744579f813b5a38b1a330cd13c6c8ba5528e88c2650ef541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139881e3a0d9ca040c723d14ea3f4d0fd70dd2a4b20f59f0e9f9bfce83c9698a07d2b39324b1a7863f8c83141f45e5590000000000000000000000000000000006783fa2a93cc1ab51aa4f04fcf6fe193056e38a79d6cce83f90438802d675e36ea5cc747a70d106f97238d9f16692c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9d380b62fca0260552e15424dbdf69fff7ecb5dd6b60d0c43b98ea259e139ae42616aa27b9ca646d86c3e743a494a7000000000000000000000000000000000b9310718c17c0988b30748db9282f5ffb5872ce6706aef0a04589a502708c265d273e8426681dd681eb2d56629cab441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144f23ff0705b93f52c464a3662dc523c424020f5111711f9ef967af0685d07dbb2dd1f73a0de9b0df8b97aa23424673000000000000000000000000000000000cedd13c97c1f09778ed37053958d1d3e74d658e2c457ffb8b29f35612a45de0adcf1d45f71a077da7b960e2826d3a411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d189242537ff37cc87821e25070c3f8e04a49919f87fedf0b07e7fab88ef25621648e7dc966b696e0d26e17f657efc00000000000000000000000000000000135ae27eb2df99af461f25814313871e771a5dc24206d291c2072553ef26a2f5c30ff24c2da915d6274d9de79d3f8c9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157c582e409c0aaecdd47dde6ce2ad3e5db199920ad5aa7ae7f39ee79fe100eb9e5a9f4d8db890ee4735fc53504d3de0000000000000000000000000000000000c2e26994bc2df5bf239fac763390aec6b25b6e578baba391f5eee8def1214b74e67829e6bf2e91ac41011af6ce85cb81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000624eb17e5931eebea9040d23cc6724ff937deae5a4338657e7dee254396fe97a87ce7868889fcd9608f74c5dc11592b0000000000000000000000000000000019cf4769239b97d9cf207dc04ec188ed8dc4646f07b951618b4923a3ccc5b5bc7144b5006521ad4f894aa91f26b2aef51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f8bf08733700be4fc9abc12f556a50c5a8d00ffe64c8a5c74e033d8d51a1950fbd3f0923b2220a18fc154d065641bf0000000000000000000000000000000010099a564a7d8c7a72cb795d3bc3f4f369712959837ba6bce07be4b628a2e7ffa18ed1f67ce0f8a77f8a1c65b6134dbc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a4330352eae8c7455dc20c027a93175e4c6dba136e8c5240d8aeab64c3c1cce1f1c6ed0a3ec693e7bf560140a4c0eb0000000000000000000000000000000016af7ff6613395ac5a731280c5b573eda997723dfd3896d81e8544db7d1c5612d9205e16873e41c0549a43180d33d5f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014f0eaa92c19d69d3c4a1fb0df8c2bf7c167c123cc6095d0cf1cffd5f320b6e50acabfadac734a3268ad2ea13c837c3000000000000000000000000000000001291d0750352c9cdbeb480cf2ddea723d3652521ed6cad5f7f07f200c2a2c07547aadceda6df57bfa295398c35f61dbc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001726cdbc932ad48907a734162655f65d4008ea188a1f4fa13425c4d0d4170c7f6a14eb58230785fae19dfe8b990cbd35000000000000000000000000000000000b830160c2f525f5b06d41cdb4eb35279c05eeecbcc32759ac81d7e99fed9a24779f4565ed9b74f2b1b654bab78003df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e39f6bd87a6d7e2153ed393c46fab9ee3edfb2ef2af9634486b997e2a889371e2c321efc2bccc140d5094f2098637400000000000000000000000000000000186cd2327501b9bdc2ad858d7fb704b9ff1d1669f36b4bb9ec15fe93f82e62e3ff16ef9ac9eb6d3b85dbecd0af3899ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a32a2a46cac4adc4428d687fb8f34393e6d60a2fb91546eaf8b94b385111e5cfdb41bc18b7a599ded969e5c89fdd23000000000000000000000000000000000d633a889d21809639e633012daccb52f21a9af9f2f03f714608c58178b8ae719d00ace589421b4ee3621ac8203dbe911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001433317800d20159d380680be435b3aa264ba36cb2fff6088a007d82aa1414f642de62cd8f3b3d46bd9f26c1010faecb0000000000000000000000000000000005645dc25930c5f374f6bdc006cbd659936b98a157cc9078d8722dfe0348124a1712ad6c4577d162b74a83601b00f70f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e9c4532401ae40a0db678eb9b77d75aa12c8f495d4aeaab9d83c14041a40782e9d5383cdb4018c78650f0b372f117b000000000000000000000000000000001577e38c54ff2a74e1098b90d67c01f350061e30667c9fde423bbf1829cbdad836f64d0fe52906f2c16b6fc3137eac091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000195109a2e44aec39b9ebb7ae4121616fe58615999891d1db96831c43a466a565ee661f6d23392bd863efefd3c17d1fa00000000000000000000000000000000022462a51620e7be6c7b98c8805e7b128dc04789798ca4db66ab46eb7f064d23e00c4708748356d1d961aa2e217025981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194050fbaed1c80ee8f0ebacea0c1e2a33a16d6e3dc749c3dcc2aa0e1d383378aaab61591955455947fa5ef0d860de470000000000000000000000000000000012a1fb715621ecc89cd7008055c38c0390f07ade578bac59e33c22972a989f2d6477008ab8d562bd00c142d654915fef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010564449dec5e396078dd15a04640789a243d7344a9e58b55f5039cfa4f61a5b82e95633cdd013797aa3ff61b61be4fb0000000000000000000000000000000001f6d8721e2eca71dfbf71f914d4f1a9ec288d18c346b0506edb13323dfadaecc2a233c994dd119509f1e9fc639d62451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017cb81c2109cc05bf804b2a179193a821d5a161a8a2833057f1bb9d00e4f214bf12c4bd1910130b0051ed2aa983e2aca000000000000000000000000000000000c83707449afd6f66ee78a0e78c563b28b43cb35f88f582a8a07d43b93d4b5ed9872f5ae8b652bf99db3c5dd2d8a414e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145cab6789abe9fc85535d395f45f753fa25cc5adca12e8e4b4414873c01ff2ad5f676e752a4d8acb9bcd50ade0443600000000000000000000000000000000010689cf7250f4d83b639a6109bde9a59337bf0b0b5e5aa9f7a35db4cf3ab5d2d9b60648055bb2c68d773df495d7504d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112b819d8b0be43fe0a25f88fdb60cae2d4cb93d8da34a5f4f1d3ecb26683cb20acbb7e59256e2e16682f9377bd2ed00000000000000000000000000000000000d728fd71d9c0ab5a09fe6e34c87df560bb14cd969cf2e444af7ac36b56701eee6b6c29967ab7ac4bc04c7fd8cb921691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000096f444dd3258960d127b8a02c7ac97609558b4ef890cdaf376a12a969dcdb47fb5d5bc6a620b4a90f496ccbc5e5b633000000000000000000000000000000001668c53a3937f6a7ef9ee15c3a7969370562f476a455213e98daedb1ade41f08f4a6a10a2877c3ca35d60023eddf19551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc586609f2739a211458021a98a9c24fc5cf8d61d07fa7b69a27a107c3f0fafecf2129ea3ed4f221c51c8be4812c221000000000000000000000000000000000b71c35db4b0ee1d3625e39d43e18fc89d2bab581b7cfdc858a213f82e5244cbe3d3a5cab8892a60cb5f9e512f0b95821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051eab14e80be0558677a908142170fd80f120e2deeaceba737211c93ce0a966a62b65a86286ccb95eecf52766d82b6b00000000000000000000000000000000024f41b32bc97700fddcbb8a84ea8b33e9940a47d3c92f663a346531081146decd893ae3adaabf2203aa914967cb02161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126c31b413f1f22d9d257eff96229180891ca895b6799c26bf5a2fac8e8f6273bafeebc6f5e2fc39ec65d3c19b94a2d7000000000000000000000000000000000df2ceff55acfb3a19cf74b7f054d86a12a66406db301aa5a01c2409a7ac5040f9b192ff4d123518f0d099bf10d123f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ebd4ae590a1909f648b5175cbde3cd630182aeb8d2115fa199e47ef73ef37f0d99f178c02d9af794456d2503b27cad00000000000000000000000000000000185fe66379021fbcdb6232893eb38193c60dc4973f3d2731074c560675ce296de56c982cc65f398c00303b2b61e344651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2135e833564c0db590061a5328ad1b8e8c249d59f7f43651ebda660e71215c7e62c045d4044abe373716e711256b900000000000000000000000000000000003065d86280800141ec7c314b331af8ed68d58dca2f3019900b8ee96ab95c1b0049946847d61c3c56ac2e3265cc945721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001827d2a3375cd7a6f2de543c74781ebb066f90c5c64ef46212fe73bf9cc00401905fd8562d01bf322508d4b2d168346d00000000000000000000000000000000147345bda34af73b6533cc30f09e81075ddd83a4835111e5e3335ead04f98ae646c8d55369e41d0951a9c535c9297e591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f0ca1b0437291776d3ceb19cc7c229565e1030a1d8d41a4dc8261fce6b335692196aead347de03a68c8cb092c4b2a3000000000000000000000000000000000d47180e173da6e6c7ad2c558db3fc098d8b4644a5152403e4a68bcbdb29f8cc7680459e072c7efa9677eda196bf9f971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175c3fae1cf782340c97e18d8c9762944d4d95a59ae06bdd17a3fae723e31c15ab448cec214776c27a935b5a905d821e0000000000000000000000000000000017455e4f4ca3ff1761b88b10810aae602ef9c2e6d570f31b200b1dfd870f18716a975c2691b05e6c54b075f5f03172491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018af2aa6cdacb5e80782aed917e6f81d8457f66ef1099ffa31792bdb2190a788fcc4163aaab16b42c9cddf9e2ee06aec0000000000000000000000000000000019c4f4d629336b75b333003fb2978f8dbb8c8c3acadaea80dc477908aad8b932d86ba2d3d8fdd52280da4856c5c480031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ec140b4300e5b181110e18a5824c653cfaa73755c45d92bad4b7efc9ca1361f8abd4cb3d980608043402887ab8868500000000000000000000000000000000009b99f980c4626c0d069a0b83901ef76f0015d3a3a1f530c94679b5a81b1f564d1fe19cf9375ea8962e2ab4c7e90f151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e6aa7df0b094cea000dcfd5e5ee264174732f091ac6513037d9a3778671cf90c12456b6596038b8954ab13724cb835000000000000000000000000000000000408a44b5660162806106e225b0cd8c48141f7e6aa3e266a2e2b9af554c510a94d15762faed6064b524d5c941a1ca5f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094cb5504889a15c0b5101c1377af4ee8d5e82da618d5b9bf39b8d1abe899d3bd7152e8aeaa6b615f0a0d846b6cd24e200000000000000000000000000000000002d714a7530e1634733945cc252a1fc56bcb6d7f06c713fbf75f0735e40e5ebb37d68b0453fa2495e273dbc095457141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009688819eb6525d20f23d2f839e2eb103f327dfcf9273e444a6ca90534cef1b7099f05c091bf7f4e32a846403bd645a0000000000000000000000000000000000462b0190238322bb647a2f88be7581ca008a4a699f1eccfb34c8cd0d160783a7ef133e09804fe52f1c6e93e9ee668141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137477a11e1bef1bb7890d5bb7507d697e751b13759ad5b957e4c57c72519f20c03cda148c35c4594e73bd8e7e64151300000000000000000000000000000000099ab0913531df0d5086c61c593e088c72c865c6e8fcb6af92aeec180f600f7036a56dcecfdd7a2f21f966684b5cfcad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090d1117476d93998f80a5c39690bb9c2fe9ad10f2853b842ce6f859c1b1927a002ec7fbeb229d0939457781331ac8890000000000000000000000000000000002edd39365a79b19f44f9310d857644a512508e63524b81f00c89dc64e212f818587c14cd05572271d6aff0fd7b0df141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c0f5356abc8aec544b220fb07a358da727d38ad3a641afde91f2e2d99b9ce67b3cd71c9542b597833033f3ab86224b0000000000000000000000000000000013be4bace02ddde85208f186d238eb2bc503988a95b572cc1e52c2f8b2910e7d53b25a2467c2c20d6f7ba926ef19d6c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032a291afda5c48bea9f0a2aa12be52ba21c05fd2e9560e4e0f8cf0e45bae7e50753a2418ebbedef094aaac19cf7bcdf0000000000000000000000000000000007cabef6ece211562b21b9f65460045e63d4bae5e6decfce9246cf5b87c3a6d41994539733892f900f6c9f743040e7181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c7569cc0b122409a0cec112e531e2f0ebb32f0ce625dd88919a22e97213a999325cfb24f0d65c9561267a5a8c36b3100000000000000000000000000000000040579873821d826ddbde8ee16111358ac8104c55eb9c15dce9a1505d72b64689a5864aab40d4d56deec3646130947161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109ae0514d4a9ffad25fd3d28c2121757befdf5b1b1529192b0efa496469f928747941a81a9f72adbb4573325c87d1cf000000000000000000000000000000000b663cca373e565dbb866fa6df50cf04f3b30070eff683fe9026c40d23b98ab1b50ce3766ff504c69db6d09e0902341a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003aaf42c999d4294ddb6c336121cefc16063dac4a20d8b054a7d0bd80e70a381b2dc3dfe4d7a51a99bcf0fdedc0a9a4d0000000000000000000000000000000017b2522acb1f3ddbfc2d4b843ee9840e4f0965c09e948c98d9e0f1e100703918a51b276392a6ac24bb3a1992337a48fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a5d563ec5d4bba5c4fe29cfa9543b63378b6d6f638ac78be92d48d3e9199c465c61ec971d9ccb25a36a90ebc90c4a70000000000000000000000000000000018595c3e1ac655a9898bdb08d70cff69b97474e87e8fd045117cc9534bbdc33b2e119e5f13078063b2a9f9b30589e76c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019cf60c466de47dcfd9d6c4ad1b9a6c9c213d870afde146ce543492dc8e908740bce11486ffee295c308f85229d99d650000000000000000000000000000000010016176bc3897490bd66ca73472f3c4b1e49dcad510a5955a3146ae83be6b0e3df7617ac2e12468dfe92f4be0dda1ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003059cb4966bafd78b8c5efd34df5b2a05da7cadcede24e4f3d80bec458e8947380c68ccc472079898ede894a8cd26650000000000000000000000000000000011f3d37aa82a4e6ec8e2b855a23ebb7e875d3aa1a71feb248406ee5bc149e23428096612a38783810e4c07512e3b64601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008400ca9f2e8d0d0138a830d95f5a0c62525ab4712fdeff210bed20385315997ea559801f36af6808c3ac20da2bbc2c700000000000000000000000000000000020858260c042ad5d4b23c7b6f85584bc2329247a24ab67dff8da3dc26acedbddcfd5576d4f72f4fbbb88ef391d979291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097d43409768185fa6267d5c65dcf3bc2a89282ef7de1f511029b5b974420afe3e5fd17333e186547074945f9e0ead6b00000000000000000000000000000000166162acf4a62cbf371628f50bdb5e185296899c6d16b3ec569c2850b9b9926e7a1a2a609ef7655baba24c313cadbc8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee749bf0eb482436b13e8a8bc539b30076bbf88019b2269035a1dcb87be0a6ded5c3017980ad14474886dbfa7d2172c000000000000000000000000000000000a7e4a0a6e8860c426b466667464444deb12e749b27383c3a411666b739dfb48fd357566a2276a19ba3a60c98e3ab62a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab78c6af656fccd07bb0d68d95401e54d074bac7840ff670e17164fac756e105ee23456f562ba12922b8cf8bf4b771d0000000000000000000000000000000015ab2cfe8d5466f9b940df38ed0b72b0c887bd8929877573e2454cbe49bd5c97b68f438e6cf5d73e742db7f96e8b66c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d34840c59c38479509369988029795bae5832eaedf74a857c7817412178e62d274fc771eef772660570c7dae1bb0225000000000000000000000000000000001185fabc0b10261b2a7c20f545de14b2a97d4f8cf5b9c6eaafb34aa90f581d15efe741a469c26db176de167db13da4b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000876e3830f5219519e12cb4013e8a0dfb3d7dfd1001669a1833f77d86f4bd56cf95eefbc7cc7a89d65a36632ecf93daf0000000000000000000000000000000006c7409a101650c11a462dc7218a6ef768608ce6ab880246ae7b713de4513df8b099d1160d137a3a629db8cf19c9d6f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152d01195c1e1f42b7befb1c5fcc101c79c663f93b37bce1d62158b556b9df82d921cb4f9f1255008b19ab9669584c1a0000000000000000000000000000000014bf4620ced3201483938401fe3ae8553cc0377aab7cf71a43ac67f7f33b2b710ab3ba406a69779a9f81c77ba21de7961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e802ea37750c6412977649624b674676b04f2cd726c1a4340623a233901b84d9d0f1a699baac456cfd833b33ad0b1c0000000000000000000000000000000010559de22895014a68bf59d71279463a0445b8bed92d48008ee344c7689dcdb16d40e7e792e1d49044a4b2ec8ab3b4141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ff348de534a39f46929814c0ab81f1095df34bf5a49b04e4556c78f6fbf77ec206059a9663307ea829fac845e187f30000000000000000000000000000000010a243a68614f5947425ce153bce76bfc5e0b2662519747e7df742777de47f32a3fbfc1eead222990653bdfd170bb37a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019317e522bb35bfcb293db19dc83855c206c6a63c95c5654c6a7e98c1dc121c5a9e3a6b78494ebe9625f659cff2fab420000000000000000000000000000000002363f50389e3936101f7851cb471816ccae29e8ab1e4e10ef57327b636da83157e6138615051484e07d20bb0a9fc1bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e1a2ae82ee08c0e3bc40276288840b6b9ef7a654c98631bfc8e34a7d182c1a847dfcf5de00ffb3a6892349d097bbd1000000000000000000000000000000000f15ee34f15660cb6b2cb651897e5fcdb7209d809b6e1a221458465c184494ea6d78c47810b64029c9499fc23f192a3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018240558dba4aa381444cc92bbf2d2c06c6a2d3082f25033e8c0a756a9aa66eb3cb499355869c9bd767c764d7df06c3c000000000000000000000000000000000275dec20dbb317964011d230a75e900a260a8644b800f6cb7e0066f9514abd2d706e1de56546691cf00294ade614e7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013dfcae20f28e376e1c4eaa71952fb94d2b0ecd6f567b526379aeadd5f163223070a9030980a295e51b1b865c6402c31000000000000000000000000000000000239592a1cd2a7378a7091b5bb63bae1625016ec0fa29e2caf53a1778fdc47928c270236e723b91480860d4eeb6fe3131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084838ec621dfe731a0f061b1d2bddfbe6f81ca3ae66fb70d22a1fb31d2f402be3bf62ff208dd089ad502ace1843e3eb000000000000000000000000000000000b88805c7b66eca1c078f34f72cf2d032e42294737754c13279145e41e99fdeafc57819fa07bd73dcadcc15cc93d68bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136511ebeee6b98fe1339db907cfd9662c33114d86915fdf94db4d960edf5cc18e1205ca794061042dfa053b343039820000000000000000000000000000000014c90b10ee3fca4fb6c07cf988012aa59ec98c4378b5fec1f5bb50343de8b273e386fbf078e4225a1d61e781ce4dd2381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173f426ed1c9385e13ba861b8b854a01a2dbe36c75c0d8253d2135a1b1125f589684e73dac9a02b9cf45ac9dd3738c08000000000000000000000000000000000ea6e876ea13c6ca1774a4053e6922b1c8548d424a5e18f2fc42c17fa86150aceeaa1f946a5f8179f060a69d397050991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001143e7823229436ddb657072cff30c71e6590dd1e3a8575bf904e97a7955eb88f875a51297ef5dec11357341284ee43900000000000000000000000000000000015ba2e543bb43dfe7ff84919f95b3ff6c3e611e290f656c6fb4c5ad365acd90f973db09228df8a814c946cd783a005e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e069c881af7adc50056fc8ad9ec7dba8e6a40fbda5d0cb14b81aee508214039e411ce001200980e6cbcc70618a6eac90000000000000000000000000000000011fcc15d75b22edd074e4601c1497561532454f2a277fac7eb032022466036e80d96529cf77bd0c93e589a78c5fa99611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f64652b93720016577981eeedcf7aa344c30f1c666829c78b88d520931947dae2528acc1146f27f8508df3b608437c90000000000000000000000000000000010361dc1ed38f01e57dd2bf481ff39013dcf5681971727e21901d9a9deb708d91380b7842bd397511ebfdc6f08450eda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f785649e9cba7d11a8797afcccb917dd9af73bbd4de14c1c56334d20ebb2484a8673a63fafaa8771bab95d3c733e020000000000000000000000000000000004b74a1fbfe0ac3000d89fe32ad795f7ddcb0f64bac77612e4890304a37b158df94289a9f2487a9eb6c432bc14debc471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078dc54a8c2bc5f43e7688299338306881460d87a74219d0d14c566f1fd4b0530c7538fcc71e6ed378f0a7dfa5701e940000000000000000000000000000000004b27133d71475045df3cb72c05dd0207ed18d556cebcdb76f0d6bc25caba399c6eaaec787db7f699387137a46949f921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d3a6c791339ae44a86583e7b1fe19522df8cbe3a5e1c8efa0487c800f98b234e21c35909ce3696a8003c9e1caa4b1a00000000000000000000000000000000153c3333e0c28efcbfe700bac5f0a61bfed4fc6da73861ab8d1d85b925b9a606f112642a34e8278b38926d370d6d69151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a947a93e12c6230122e4d0e29bfc6f95f734dc93cd29426b0a5ca816a06b939d24e0b2939c552234684d50e7ae9a63f00000000000000000000000000000000129c6b59c2c1f61604335bf624db2bff14ad47476a55b50fe0aab9b34608971a11659d15a0516b78472bdd6ce5933c0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001556c7064f4f1ef3929db9ed8de036592d8a0841a70e1d834addd47c8e738cad97e6f1c70084c59066c71baf07a4ce2b000000000000000000000000000000000d0dce7977dc5c70f28a1905a18c6b1449b3d469f0679086cfbd59af33f647f0913cdd6cc190920c2d4ba91b8e6d85a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001807dd844caceb14669b190d2b67f355f38b86b5732030f2073d474f5a31fdfcd01f2ee382bb57aa7368e2293fbaa8e1000000000000000000000000000000000cac5f4045cb9de4b16117fa7b58d289e7220188ccf7ff7c0e931a78a220beadc472d866a42bca69af7c19c9dc0c0f3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2fdc2026239517e34a9b5bbc5d22314ab0f8e27e9c4ca06d3d80ea502074d78e1250b2df1334761e7d73aa528710a9000000000000000000000000000000000e3981abddce0782884ce3198ce96401e40dc5866e105fc0bcf4cecd287a6a538af681690d2ffbb5da4564130e747c301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005fd67332f22eadd7f9a7fc4f0e208e744d7aa85947b79dda024a46e036d0ea28d91403218e3a433b80562362827d1d50000000000000000000000000000000003e30229abcdd4da055771f85263be533d679ace6fee311ebf566ecd8968643b6b89a5c0e1c9a809732e4480d63c0a931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014dc799eb53ab9553c20c0cd7d73a446e67a002ccfe2c2f50aaf6a67949843b1ad308fcb75fa16fb508d446994259a3f00000000000000000000000000000000118397891d6cc849654ed21e0c3650fc86551147e52430f2f2802f140caf5f48e8785811c9841bb82fbfb22513a8591b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cd1283696323b7e8e3b6fe2e4ae95cc342cbe929bee0076be88a09184520b85e7df42f74ae010ed3622920df0952200000000000000000000000000000000008c23cdb0edfe93c235edd2e0a6352d40069d39f4754057435a00d8cbe67d5708d290e61bbdc61562a353e43b37e72de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba9eca902ba0c9d3350a51af447f68d996d1b1024299494090744ad2f07d8e08a1ed53a56437d65991b90c27c194199000000000000000000000000000000001841622d67b5a0dc6e21533c9e6eb179e6ed385b767e1b15fd809bc21bd26642fbd9ce1c21a311e0dcd5eef9c3dd163a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003dd19d02752abfbfc2c46ce1d029f60d2d3d50360695ec82a82de64182331764eac178ae5ad443ae12a45d4b51dad8a00000000000000000000000000000000033a3c5a0aa7bd1326688236f42cc9a47355c133a204b2633d09ca2b8b48a8ae5cb4c6e71426bdc074218f0b7bd0d9d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001281b2d0bd52eb9b0aa9b425f1db10ff49496a0f3db23a34f8072370f9e82c21c4c6e51c1370a45f6c7aab38e509ff53000000000000000000000000000000000d0804e911b421a75dc1b9c768c8a0265580ee2990ac6648ea2e1f0cf49d7b2c304ba738920f9f71fd90463da3a019871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184978aa1ce37f0ee415fc763cd2c068bf7d20dc1e43f32556a929a231f93972bebae7ac58b8c91adbac0d6d7e0516690000000000000000000000000000000003c3309ccf812d2426eec92fadb52a7306d21a8eeed3034d9ab3e0342bc00e868621057dc954316ad13e2f9aa804eac91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d0772c1c9d18dfa53e5a5cbe84b4ba822a2110f6e827ea8ffbc1578fd200708a31cf515a9ddfbf4e9c4a361039430d000000000000000000000000000000000dcad6d3548e242e4cfbcd244dc888dacc6dc7b28ded4460c4a02838dfd75a7fe43606d700a2776b6671803f028738fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144c00bc8ecfa45eba043aee6059430269880c74709ee2f02cda5aaab8023d96d17394a9aeccdf58b036549418b76ba0000000000000000000000000000000000899ad82116a8a8ec8fd6b06eca4e9729a637e13daf94824857bc2207bf419e6f4d54b2836f2bad9e196127e2b01b7c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189e742127d6fafc8531a6dbd9d5dd052be4afd3cfe5517bd4b7abf13668e3ebea055f63afddbd0d512d3e7cf3b377020000000000000000000000000000000007c1c38fdd18bc6281aeed25a5b1fa5c37cc1abdbc1043d44bcfa5a01d1ce2abc3992b001ce547d4cbde74931b4574431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199bfd61ce873342bc5a692e0c5aa671f8277c8dea681dd26cfd52a614e91e31d1a3bcf407aff346323cf63fc739666f0000000000000000000000000000000014306818dada1206ff5b1ef24e3155c5ef386b2f8d3d2932947641b803b616d22b7a292955990716fc26813df188eea21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ae67150a359b7f1497360ba26902fa1cf68058dd891fb1d0ad875ca5e2231fad50bec298389e69b8e1098afdfb1cc200000000000000000000000000000000120c519c65e96a0e377229c54f0e0d0c86ce059692f19f55738b392bbba65f3cc843ec64ca493cfec990f4f59de52f501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c87f722fd4c2d0b54e30036ada7f4b8c67e7164899ffb83724c347a1faef10b3bb8fc32b7284983a3c36cf277eff48e000000000000000000000000000000001158e938c58c74cff146ae9fdf23c29a9a1fbbc07dfdf22d370a0cd77dc5cee586de90e386e5eb16badbe739286eb7b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186a2890d0a9201d91aac640f4f06d8f3eaa51852270f64f08c678bedf6f747243a6079de046361f4e7a4b3166866ea600000000000000000000000000000000041ba7533f67c3c58cbd1e5c59fb9d08a805985d8cd81fd6764dcfd3cb782570ab9133a6950d32e2b4c593304f04de811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e69bf2c806d40bfb07c4ed68a80adc844a1bdcb208150409537ce786109c89e16fd2cf4d06bc3a10960d050ffafdf6000000000000000000000000000000000e9722e0962ffe223ccca06764d0f40892e7de7079113f795039a2b6a0e12b873f08aca4aa43a8301b9189e10e2dd5f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004586444308c3271227817bd7e34188db5d5f42f13f87ad2c734aeb064f84f9be2edd32bd107b1692e33fb4c325a765b00000000000000000000000000000000151eba68cf5134bd9e745c44af0c03685cfb42825ef1ad7b2147613c9db391b06ccb3efbf314fb6a792d4f47c80f4c771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b6d0cd240d296f39729881320f940dc02d84bd002f934f903ef24f5250fe7994a489be6fc46a2c4204a39a0b91fcc50000000000000000000000000000000011aaa09b480f80fdc825dfdde935efac6ddabd85cff016ce61c23f2f9bb9e8b63ffcfd81a4fadcd68ce7e315af45d4681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002eea660e91dea9a7f659edbb409b63eae7f421ead0aa5375c91fdb83c0a0fb5f80bc35bde5b985bced69f8b9f76832400000000000000000000000000000000120cc31816b340702ca26371b54296cbad56587a767dc8be15496acc20872301c94dc808840fa3bf4295745d5a830fbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aea40b8da6b8a412ecbff0c9eac6cfed70da1f2f17dd3eef163f8c380aeb8519fe2f862e689ec3dbd42147fb61fd4ce00000000000000000000000000000000010cd22695c4d0f9ed49f35d80b875dac008b4c45bcd793f408e92106c060031328e9db25178a8d4dfb8adf7246380b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016694153e799c192cc8837430ce7292b85532264bcf66024d6d7532731de3e73d1fbce5277dd11095f64aa2b9d97791300000000000000000000000000000000050c8019c9ee4c8034457354d109626ed7f629bbbe6425d588b3916c8e851d03dc88040f05057e7c7512299e66c3fa9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194baf079adcd08d95456aa5a6585be7001cfe1fc9b1734568db9bbefd2a938883546f5f2e7920c93455755842f878bb000000000000000000000000000000000b2674771556984065cbbc238823a53a2768fe59dd733d5a82c32bf9303fdbc333f7624b425c12c36f3fc32ef2b8305d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af9d77b68e0c570a1fd928d79ec8f0cdb99d0fb34e4dacff1e26ebc59f9e701d189619c02984ffd8449c18facef4544000000000000000000000000000000000387f1c4431e6feb8ef397106b6ed189a141bd151b42e235de7a328c1a52713ece701ab3fc3ec85414241e09d61764081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6af89655756d3ecb46231f49e5f806f30ad97e96ede4c7dcb781c82a55f8978612d215d0afdd7ac50202e3f493b9f10000000000000000000000000000000007750d2d54f51f23c2c88b37c803dbea64a9185661e5eb7fd4e59a27eab92ea4fc1d29bb6728ca7ec5bad0a2d18c3ea91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b23c66227f52dd54adfecc39c56650ca08c55117a17e22dc9329287c28488f2a9b9331c5ccfa9e33cc63f8ec93a1fbb0000000000000000000000000000000007f58cd6d476e97d3cc012a814b34155bbe0f8989ce1329891b420865115614984178e11c5e767f6febaee0123fed1ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8db4f6ddf7cbbf4864eb42f849e4ccd3500c85bf5315387a140ba8739429d96d4a23fb87e22421d04766462efeba4a000000000000000000000000000000000dc66f926177fbbe81a0ca85239df9e760dd3d9cfc736c3af724bdae76e7f74f6f22e042bc275bcb5771e2702ce25baf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001765beefd04e0e855d9b91532d0d5fc439b90fdb8d1a5fd649297ce52352ae5c93941c669f14a29558e6559ceaef04c00000000000000000000000000000000110fbd6e021799309bed6fb47ebf0ae84a4a73c564dcfa5ffac03b69d4d3c17799f6784d8a9a0044b401f233f6546cd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041844a3cae4d12a8f5b7654f5b7f2a6e44c8f02ea150b864b2ca5deaf20f09e2745d2ae22a664b53b3234c3ed46753b0000000000000000000000000000000019d3b9ff4854b4b821ce97d32d0956ef4728394eff713248b3dc97189a8195357657eccea55b4b2d83365eadcdcf4b6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a256303b307e97bf2b38bfd80b9b8fd309b8e7079c416aa4c811b0923aea5a6a658768ed006e6a5c1f811da2c697eec000000000000000000000000000000000af45f33fbd3a4958773bec545ac3f1c9f2c4ad527c5e21850055a881493128b0598dc2eaf9be7e4984c1d946117fa031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000196cf8732372f1c02b351ea5b4bb7eb8f0e6409ec2b1847b2892d111da1d35cc8402831313ec4315f68c293b2c7e1280000000000000000000000000000000019bc46d5e30ba4151fa71a564f58aaaa23be46a334aaeb0340b8d11f3226d45ce133053377a64a3a71cd0d37ace67e4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001290f521b45a92a46171e917101f79cac23330a89fafcb04ea83a0382be810b01f28ddd578a901dc04e7ca009fade2bc0000000000000000000000000000000006303b87c41c771dba9620e0d535b05187d495018fbd84245bd199ee2cd990297d58339d94a01f0047a4a2db26f498151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000118030299eef298ea8a721a41dd0bb31be0f86742144c05d7fe632b6c35e9f0c2ccb7b7fd87cac1e5882d43d465c609000000000000000000000000000000000269052c4d2afb14bbbc3394d2f1b49e2a68ba0dd6dc08bc0328468ac77cb601af1719d412b706ee2c0c2aa425592ef71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e98a6d533a0472e5c15b3e00358ff53388dd1db0dda0b40b2fe210d88cebb2b620093b577f526f3da72314b695f267500000000000000000000000000000000074fedd522430e7db49d6645bba93e374fa45f2fdfea593263c30b009cbcafdff30e8f2c758f85c324f97c9ff0b198b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004eccce5aa7eb494ed80550a8c7f2adda1117a33e48d2df367e0190efc3c75372b15d035ad4e21803bfffaa8af22be1200000000000000000000000000000000177d153c6a1920ef73dd3ca6c9794a384e9e52b2c1591afb7d19cf08ede33f82cee31d94c51ff3390c3c0db36284b0261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001400dd903191c1508f2c4bef8243744b53ba9735ab327e585dff03f789faf15355a8b3f453ad65b78942755ca7a16b4c000000000000000000000000000000000b5995cf77455ffe5825290c0c26be1c7ffcdbfac32e528541323d3c7daaac8f0e40c6144e34d4bde7ff8fa22ee01ea31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da474302a6d882c818edd65816364e9f4e6cebbaf7b3d8ea287fa32e89ca363c0193260ace23f89f51cf8831365593f0000000000000000000000000000000014d2b16f2a16e6dc4f613b6bf68a0d1b1b4482157e80eb4b7b9bab7590374e8d392690cce70b582c4fdefe117dbc86361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b06a05803d4eef9d67215351a841a3f1bb0876f4e4e7aac23693cb77e01254e6b09e220cc955ef5824ac7a89165306400000000000000000000000000000000098cc84e0c4445d5f37ca5f6073fea188824e98e986c13cee6afb997536274e2dc392d1c00ef93705c4a6ba70df664471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d8af6334edf7d9de9e2a3990ad75a77b3bb84973188b26f39526e97e4b8073690a0f3ecb5dfeafcefcee1643b0e5a60000000000000000000000000000000007992793af8836a975ddbc7f548802aa312b64f458d65a2f7f52e8794e7023183a57164f17179afd7df20d8231e245c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000449443b8d5576abcae6c6fc5450622f4d6a29f573e887b220e6bf240afa56fcd0a52fdb6e9d4f908629f254b99cc7ab000000000000000000000000000000000cb871bd95a10a4e6ca1a7b1ce2c7e750fbb6329237013a17ed82e16212d5152ccbaf3ca3412de407422a96215387af21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a8775dacd21fe96cd3c93385d74b304851e30fe7fe96e1f323b223996985136c96430fa1d0abd10a3ccb60597cb4cc000000000000000000000000000000000dabc1460ce2b684808a27d468d9561f4f997ca6678b3083fbfda14fc83d2984a5d08764ccbe6732b9dbf6860c28b3a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ead00552017bc66e508e8fc3ed83ce277c18f1d3f2dc6e410f5b0473dd4ac4627b5a9ed5b5dc2586babc3aebd67137000000000000000000000000000000001681df95caf06090ef1d2a7ad0663176103a988cb7b42d35da7e7603dfcdb2ccba733063b8b88367c58b2e0fd1c569e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003dfcbde75729e236db9c1c86d583236606c6cd64019ba89bbb1e6f9ff464f5e861e23224a0da930cb15a28de0b5a61c0000000000000000000000000000000019207825799c31e93faa9e7d2a149ff933dac099a746e60b6b425949d97ffed36dd41387fb7d1d281fe00ccee0c14caf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039edacf9be55a33c96ad2646a8dc48c769fb536db44b25864a288f207ab0c6fa28125d3ff23ee8215949368dc57b12c0000000000000000000000000000000011041a5adbe46ff76381b9811c0e0721d2858ba916bd79a0498c2448dae440c6d0a4e0de7fc98d9601ea8d68fd4ddcd61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e42da0ec8cdc17b759b568508b7135e56b6b4c08c3ce7cbe6db721f6412445c62d0e6afc207fa67051c37e1d06e76140000000000000000000000000000000018cc22c0dd2767cd0ea2c4c7eff51745b0fb7d1de3a13e249190c8d88f85325bdd2a3a0f39af6a3ee354b150287ec6bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b842ba47c7f95cbab9308f121170bccedec09cb2432e2813b4c1ec2a74475e1b3563e60675f2e69088f9fd56855cd7900000000000000000000000000000000195b456ac66c17321eacd7effb38cfb2b3dc3bf02dc46fa0804e2c82e3a4c2d8c42ffe1fd7c929010947a12d0876deb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad61409fc3430c81164ffa466330a75448a3efe4dfeb1e0986a91e8e79333eeab43a14bbb04d8c0d198a55bb054cad40000000000000000000000000000000001cd36e9b60e078478a9fc424ba94c12bb18a611b34db2fffd66d0e670fca127e67939ea71f274aeb33bbcac8d44087e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef61b14a7ba4e88dad298de167a3677a0d971883c0c5f3b615e3de7b0c2be686907cffa25878915e08ce7bda7fb175f0000000000000000000000000000000004460e7809f5de78761dff0665c5b143ad4e45be66cd129ce61d95fcaae27b5517de75c3e54a5b9d5c2b0d11059ec9481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067fffbdd8fa56c4eea545811bc7ff61f443b384966abcaa955318f94b4290421e4f48b6309c6e36f7bc0ed2ece304b90000000000000000000000000000000002d67b8ae3bdf68412073c5e76020204600c346d658407b6ade017273cd0083e3b13a80bf1b0224a2fab2d52478a98521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bed948721c0ea417d32d7dd7948f4b551ba8b3274c0253d5b0f359155028caaa1aa4261c778519eb6c3e0976c0d7d2a0000000000000000000000000000000010996eac90fb2c6658bd7924b56dbb1894d09f287d9993294d2d93d60eae85f7bd3c7bb20adb87db0b0b6b280d10d0c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2ffaf84b09ca8659844f52ceb1f8dfe2fe45c002103c2b61716d0cb57adf2bca0c292602d5846f5ca2327e2444bbc20000000000000000000000000000000010c95596a9d89d84984a9d0a71bb0178bb5766d88430e85c8e963bdf455de4d518dec9101ccfa81d49f3fb55280db36e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000613b1afdc72547e9cc86292e211d30c3307be713a7f9ee701d99bbefc0a1afa55e1c2cf5929438727cbd7aada8dc1f800000000000000000000000000000000141e58e47d82c1950d2638c766c98fb0c982ff562cd15ee4e0ed8c409b7d985d86c984a3735d31a6af6e4f21b948919b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013677a29bf9941995454e887132d2df51b813dd22aa5f4913c3c900aa9ec62ae88c8aabf9313f6494361e9c412aa7cd9000000000000000000000000000000001995ff2214023d62f435ff5defb48a8fd2da6203429e311c688a5fe72d8ff71ad06fac85fca63c18d93ba717756cad3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e82175df164d9ce2ba4b0f8f52a290cbb9dd9620f263bd07f0dc4ce278e0d64c9bae04e27d000919864088ece92ec1200000000000000000000000000000000104ac870a1feade71e8fc2e4cae12a8b2b6abe635b7440f19a3038c25d9fac853cf20fe7a8e3436a58e913c1e16166a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192759b6787dccd74c3eb737076a6ef29b414bc546c0ab160300a4c9e9688d4ddfe78cad120eea9a38505f90c2765307000000000000000000000000000000000303a69e562faf5707da410ed1e788bf3e44ecd70d8754bf22e27187abe99acc600ce695910f7c7d4cb3385330b3fc2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001857175ecd64184455fef2dc8dcdc95f54db3c26b549b10126fecc32190c0f2b1c29683a05f40415b82608a4539a43ca00000000000000000000000000000000196f330f35fa7e5dc109b55b35104a13c35971433ce3b224b6129fd59918ff252563cec08d17784e2e6377ac08d125c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000754eeaaf1d98eb71d56bd2ce724bb4b24cca802c77d57da63e38c358fd4d9b63cde929db2007a77a0b1d6569d78a87f00000000000000000000000000000000006063ff64eb8fd24f46ee0e24892b8d369f6a5f42bb0dbe3387bba8fcf71cb1dfe36db56a4a33ad4ff38c92e6f2bd6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009df67b1eb91ddc9956aa76369086c34a7306da10d5446b793952fc2aa24569751f202e5dc9ad2575bdaeb0cb26cee0f000000000000000000000000000000000a8c8dfb0470d5584c1dbe564f27a71fa9faec1e8e26ad6261d2c10e06201e072aeb70772d414994e7b2802107e4753f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbe495d32115a3328de135ecd0566e29801e9ddb1faec6a2412b71aa24e531a2bc9cfe768d53b3c0f5f438e16bc5823000000000000000000000000000000000782382130bdd522933119e3f8537cb7b424c113f7b3035a3de0f33dbc91c900dd622739020cdc1005fe6cf93388bbf11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3672b72f0d9d3075d76eed164c1c021d34024229221c181a139d41f2ba778b4d516d0b7c15cf1c8d64cb85df703273000000000000000000000000000000000b833d35193a4739f7f181a50709e76e35b1f0edc71e01cef6252b095c6ec5772b573e222d446edbfd53a7b25e70cce41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004eed604970767b09484a1e0e0d80b6c8c8c5f6a1546e88fd4ab3741f12d33c307d65e5f7412b18473ef8a128cc035f50000000000000000000000000000000016983ef707f7bc2aab8719ffd283b37f619b57dc47be27acf81bf6301075c5dd935114130eed016baa6b82df5e08132d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8e1b5cac1e8cbd6b62d6336be394dfff8af8b1c087df956341b4289076a96e0c090dff1b7d91e743ce7056b3595a6e0000000000000000000000000000000013c804a038ada92c5abc0e4062d1ac57c8afa8995612c40a0adc37366f63e17b24772e615962be0f63076d4a304ccf4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014993c56c5507ec226d02faccdb700a6f601a833b2cf5e1b2fcfbecf1eae40703707d5d78db54e5d43a8d3a053559d0e000000000000000000000000000000001882521e14fc5043a7a4028e92b46e679af33e7ed95e02a68e2c78f6834b2f4ab8061d789a5f6fafc1ffd586df4fa5561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc1dcf2d2e73b92c25f7adb5709906f46edc7357720592b57e177e8cd0e3ac370314ad1b7124f92ed9d2f21e1a3bbdf0000000000000000000000000000000003c7596270e4f61aeafe91f7f7f51bf197a254cbc8e78fbcead8bf98f3108d3ecf2344a887563708960e9a3374e304c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193ace971ac3cbe335fe577d1c57b3f59d89a249d1b90a3e74737d993e11e5fe5fe1d9b3e1be397b9cb5530d1be6b38d0000000000000000000000000000000018feca1c1fa9924751f39b4f9ff840c056b4f7ae54b60badf8edf3017aa218d4c4bb6c8c3263da84739f498af538916b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000155878fee9a5fe514cc8704e0644452ab40b9df815e5294c729e44432dee42e1b8311629f7790b7909b26da4727fe4fe000000000000000000000000000000001637223f6c518518d9cdacd908896b4253b275b0813bf259240859a5e844a076a0fdb5f4c1aca107b4ca8b8819d5f3841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001722e1205a15c5961c642e1d0f33d32733140c8c72bb90f46a12fbf3c373d03cfa9b0cc4d97b37a105ee9ce374fddb100000000000000000000000000000000198869c0906c40cb9ed9f5ffd78f0ff8042142292fcb8da1477869a8e92ed72a89ae50dc7ca52ba33034d56bb4cf77031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057155f7027801412b5b72e64081acecb9e32e03c509854b83e73d2e6289ad570bf219c39b0ddb3250946975a677c1da0000000000000000000000000000000015ffe7341ada9fce0707dbfa39cf1f161985fec9c18cfdc980fb554893e004f8ba7449f9551e5f0e1e9a7822d0221b2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008faca2078b5b5ac7c9bb99fd94e093d02689c0e0dd5d30d2b2d62c4e163486c5f052975cda32117f81f9b0f2b0802a100000000000000000000000000000000110716730769de8446141ee082b886726ce60f5ab80fbbe2d7e4bfd3631008ca4232387f0c17acde2bd3af10468cc6fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d08f186d0a658731c6cbec73f5aa5143a7bd1a73cac5d96b9245132ceb27fadae2ec78e77895811da336a7d7eedd770000000000000000000000000000000008345b077b819b25e13fbb4100c1f361b223d876ec6b579c5f78b6de4218a0c889ce33e5c65e1d3cce7e81f98a7572ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c4e5a96fc060a88284313bdca833681a90580aa4587d1115acf37773746f179bfad612bef1d81f83ec767f2e96410c9000000000000000000000000000000000e735e9b9aaf3659dbae640adb20489a17dc9e618c5e0f086193cb0beaf636d10fbc2e30d7269562506540e61fe25cbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134e994b407a8fc5347b05b91e40c2887925b3429f41eb4964f518e046bff873d43707c212b9f1849d4a9568e46a1c000000000000000000000000000000000003f26a1ef1d35335bf077717d08e740f2e1fd1b6905c7524128e8e23f8b662508b6e0caa9948ece47acb56d19df63af11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022f58be560afb08baf071db85ad388dd95409520d164f5574092f45de76b7545aeb4dbc9e8587e143b3703de46f6437000000000000000000000000000000000a65915b318edc344338043225b9fdcd5f55ffacb7530aa1aefd8a27258e16db0df9fe6b90eab3d31c3ade9ce132a3241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001042273de380c70db6496029650584890d477991fd2e588cd931dddff10e78b243d753f55808ded6197cf651b1419854000000000000000000000000000000001557146e067b72cd33cc8b03b6d61bb371e332c70fe6d93b8edc0b56d8e09edfc3199f1346c80699e09fc810fdf2a3111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3b1f3ad0f9c488a57d3cafbf8bbef233257fda9b8c4c0fa29778e78251cbfae648e669425a76f58a82d2a5dbf0be560000000000000000000000000000000008a1395e4cbe4bf6b81cefd3fdfcf6542a00d9e28d8e1d3b73619d4dce1ea0967c92404abd5096d9c43a96ac29cb2acc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ddf48cb8c152608e333b89fe72f168825552d63dba4ccc4667e2e8bb32adce9dab27831560742bf3d90980e0d64366a0000000000000000000000000000000012fd2a170c8d0ee456a4c0aae6837539e79c799c676a3a19179becbe2d57f0eebe0e0c30e46cfa6bc5265f78c2c256441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000046491d85721cddd56bc9ba9a7d1c54296c9ae2f3e3dc811de0a26b50560c7a423192cf190198df873184840296806550000000000000000000000000000000011d7695520a8777e97731dadf79d4608520233a9c0bb519b20de0abb375c33f376b78da587a5259bff83da1b669088ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2dd654ea142ed86fbb4ca0913ca5367fa8f205b197ae3286b36c0b20f96252359e67baff8c524fc7d2712502f3f65d0000000000000000000000000000000009c67b7b25c5ad1935db10e39720fc06ad2313e6fdf14f34df0daf15b44666d8820fe90ed9198e36e0c19d7180bdd3161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da395c33b26e2002419a93a965881056b59cfacf390f95a100fe77fa1db3493b885da6b45e3ae35077a61d1b0c3ee4c0000000000000000000000000000000008016dc5022eacc7cc458d29bd687654435c7d170157bc30c6d5fab732811ca70c1ca8f45eae1d804033e6e70982a63f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b3b6876fd0a0f1e05eda1ab8060d7e4fa4e9854165d31e44edbbc4aac8020ca117436e099821bf9de3dd462d856ee30000000000000000000000000000000015a08df9e87137d030373100bc2c238a57a109faab569ec1170af939c6f68e9a94a5170ce14938b368758e61517463b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099fe5ae800fdbbe9090e11bb57242b4fe7f2f898e84f7a96c2cd30ea9fd57f49e3a099c916c2e20153501d44158832d0000000000000000000000000000000005af19271406f1450a81d42bc1138a07fa2a30d8295ca10896cdea942abe130624b107f433b1bccddf831c88dfa44f181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075a7f387f0eeaf13befaf8c37655d3127f7afa3512aaa1fb0554dde5a0ddfb62b1116dbb111f70e32247140b43c7ef10000000000000000000000000000000000c9d6f510f7b3e7efe9bf87b160d891bdaa359e77b6c9e4c129d946f03b37d4679d5793b97e28462976a44c754e5a0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2539db3c3644236744be7851161929b2c3590e392669379d272a889df6e0835fd42cd7a48608a1318dd51dc51d9a1c0000000000000000000000000000000018771d61f0ff4e7026abb8b12771d9778afa5937f20391cae167012dfba6a16b643e2c0757c8abeeac23c93223f135b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050ff8747848f47321a602d93884fc6171d96fe4665245590636adb55ba0b87562ecad1865b66753837ff02b3d2e3dd600000000000000000000000000000000042aaab1c8c24046d6ac0804d4bbdbc09a1193c59c71c79cd20703ff7b5b5c08e37f88f41fb94d72dcd55f19a4a24f1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a25b5bdd29a1856b06d16b45ee6ff8e0c89782c24d7bac83563c5d27a59a86abfcd6e45aefc8252e93bb0d85bafaa1e0000000000000000000000000000000006817dd5d13b8a87bccc5df1a4289ca2e3b06433990fea0b8f21881deb90594801e24b1fc6c6ef2a8a89a210d8905b4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036c7bc9688b8263173fe9b1805d942cc444c43e5bcb34a52a9964703b1f8b0e89282fe5451f1bf367e90634b047197b000000000000000000000000000000000518dd1424a9489b56e90cef7076086be6d9bbc1ac98e3cb0aabf984b8f99b6bc5ead1dbc581fba00bbdb6aff0454be41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c0e9dd1a3ee82b771a3dfca8192b15447677d5d772522d1ad2600c497b1df505cced652526b87667425d2f5c527e0a000000000000000000000000000000000f915a04fbe51552ee125fdf44b918130a510d34151f05c29fa4dbf9b3cb0b13f0bebff87bd3822431202ecddf59a84a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019dc6d3a3ef25835b6ca577a320faced7222ffb960d0015145f282305d59a722525c10f247a3b30a6289bc45265de70b00000000000000000000000000000000022e088110173dbe2f535ef887c540c5d94f6c8d342fbebb368281c5c9861fead1a1c2747999fb7edc4d495092fabba71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f05bbc6490d499655213e3b40fc3d2322c6b586da991164ca2800212d88345d9663f8a99e043c46b177655e9b1dba40000000000000000000000000000000002beef6b052579c4dbf0a69f55a5251cfced3a4a2259abcc256d09e8808bd7c404fc832558b017f82562f103eb3fbd511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118ef7a65b15a8a385801344d7c731c7bf33b8d94bf500291ba8708886cc1a0f5df827541328e52385c1fe0b75bda5c0000000000000000000000000000000000700de6e48b9b4ced185c0883d6fba32b4c5abed54df18732ccd5c27448ef0a52c6c202582c84cfcb6e1ce9c81fc8c711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a521958831cb4f4b829ec8d46a19147cd99a38bf2c3fa3c48d7f7c7d7aba877a6025086e522121eb2d6ed19fc74123000000000000000000000000000000000bc97e37f397f1b7356493a41aadf04bdb40fae1b3c257c0ae96f1be9da655ca8d0b8127b2da7f67796359c6d6f0425a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000633deca8911646ae188660c78d29bb133583179457e762d5634ec7d4d09c9b4c2124450436c93cb8c62c2da5d913b9b0000000000000000000000000000000002b237bc619da52c43b982e2c98faf898d14141532292b70f96375acf56fae4f09ea08a5ef96fd5c24e8e211abd9a6681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000381b8925bbe1b08a4e5b7b72525665c271a9dbc603dda82f0281f6fc703c97b730cbfcc4a884d7c291c41ecf46cd05b000000000000000000000000000000001954c80e47b2fb3c7c3293217ff22384f978f8bd2d29a2f680090fd3ef4737c5bb848bd5b244cd0bb7d4dc8804e1b8791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179b16b8e7f01f01b59957e6503de75594a3aa0a81526f3371b19f3fb1d1abea621499047e8a4c978961a22a9cc9c697000000000000000000000000000000000b4e1bb84a9919dcfa1b420e22a3de952f93bbd430501c8c7051cb49dc606e7758254b5232b154f389d13bb0584093841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019112066c6adeabb8f6d1ff46b58c46e7f869ce4d3ef1def9153329d6448f0d1e7154034a0deac6ce213fa54747a13060000000000000000000000000000000018e6f5e3a57859f9d670c5ebc7c69e0a41103b2d915979841ca5c172a69e3965f41dd2eaa36d6f3ea8ecca3d0e34354f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000afac7ac38da62b43ce70efb3e158afba0d6322e0e7fec41f4513ba95f049cc1ac8498207f118dcfa82718e0449aee690000000000000000000000000000000001f4aaa8dc3df31fe8887c43048997a10bbdddd76f112b6dd01ab14a287b3841a7f9c58367e0eb9748122a9a1f0ee9191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c5e74635eb8b85afde9a293033de072d6a507ee907c3063d9388387c2b6fee14dc91d0aec291f85864d0d89fc257760000000000000000000000000000000009126a7ba2614130d5b3696b09e36a68dbf71165ec60575545b3bf24f2c6f63a346cb0a77624ef142c44f96b525370431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164fe8232738a914f834626c0d33aaab43bbc174349733afa0bdb72eee7f8a661495ec613c4e92601f4a79af51c54ca400000000000000000000000000000000035474535602193b9b66722d6ab765cb02b67958518ffdc85b67421662989ca6f067b8db360aadb18305a273d203a4061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141c53423b58bb9ff7d27ae251be5f0afdc50801a7df402b88fb6f951b834000b55ede5e90b88b06675f3e6e8b0a2e6a00000000000000000000000000000000132cab43b5d96668129142bcab9911b089bc65bb6920de80ba6d69656f62a125882ac8eeb524dc0e75417f77602cc1731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013dfca23a6de3aa8473ddf75a31b5fd7cace7034b756f85ac86fafdb197b1c9193fd7b731f6c21a5b3e7957e6fc57cc000000000000000000000000000000000069cbfa0f07d34318580b2d26eec830a5ca9d91de32f115c2937c602f8646fabb1861f559c04f68517c944828af7fce41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012dd217a250398567c35150bb5f54b12329fb65f2148bf0fdabea5c6fa976ad94a48aea2034ffbd150a86d645cd22026000000000000000000000000000000000dd36f8fb3724b73cbe5390929bae16610987d9465ab444b0396aad86b0abe2635b8ca3c4f49dd47c6609caa9af53b6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001443851045e9ebcbf325686f279c61e47887fccf4cac42bf16a25be8f23858974eebd2b5b4c68473780fadb5328aaf70000000000000000000000000000000000c54f60391ce8e8bf5e82e2a07e001b6e1133b85d95b2dd46b3e4d865dd91e0a7d82ce8e176b585759ebe52de978b9131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a21ae14c0577411929b94baf44b011035f43681b0687dabe966fa4a0c536e38ba53d7184d4386a5f2d3546a0d2fb9a0000000000000000000000000000000000a1515070e8dee546d6642628d11d97965c008a8a77383897652e0530fe98cf072983c28509bc033d3a655fae26ccf291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011018373e0216d38775b9c01a58eb68356631a4643efb2bb5686c607105e32fa4ac30fcc9247f3f6d23be44fc35b70cc000000000000000000000000000000001730a408d06a4cca57f2d16321667da3af8f22c0773a00df27d9fbae3840936c4f9e874a757cac4d8a9396a24b9b19e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001937df44e0a722a2f0bedecfdb54e44951624118e6fbb59910c685606c044a6326ca1bcfbd4e8150eb5be3284d74624d0000000000000000000000000000000010e11b8811238a4378340f57c944bcb22cc5f90207ec8638c0f8d76eb9caa538c4affcf0c0cfe11fd2dde722ea3f85661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001569bf45aa71c78ca97b62dd1bbf0134341b9e68a7e7cc32bfdc4d6ab3bb673ba55573630562882bc178a72276acc8f40000000000000000000000000000000005c9785f234150e087d570fd46649afbc89fd4868e323d9eff3e076aebce2e9fb09c1a427a7ed188b820586f3a7201fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168bf81438dd0011239dcb839d897845400483951c4a7ad18d431c081be517877817ee779ecf137c094b3d5189f375b00000000000000000000000000000000014df014dbef9ba7efa763bc7811437de082e6a53f3a5cae8d5d2198d1b3ff503c34f646638f2858abfc7e00a223ebfdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c192e98669be2dbed41f8e61c45b13658ed0169c5e5f80e60a1c92be21dff495c8f63c6218f3953226b21108ad159f000000000000000000000000000000000d13ae4d1eb8f0aa2dc32946d4140225a214edfe841bfbf1fe8119c5e6062133e490aad97ab158557c93603d253c29231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015066911f305f3581e488d39acd4c21c8fb732a306133f8c26c8b3386a7aa5c1db92c6a5f90663ec1c2d10637988a6b300000000000000000000000000000000070b9e1983f2e5cfcd27f6baa424b19c5088d09e54a600752bf9dc149f38bbeb7c2f3ffd4cdb7f8ebadb66e97e6bac7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053b262b75ac965f67e3a4426d03f2d3401b6aac0c848564098c1b0780fc7d5ad60dd68a3f4600a16a94de7a00c60b6400000000000000000000000000000000170e8be9139f9e0cc9f08a49fadc38e04b76314dd66b8b7f87a855fbfc73ca305ff0650cf9631548d914465bae21c6131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ecac5f8a09bec5b728dabb6a42256b80e294552c9882b9fef9fa4bf0b2f1ecdc4b8ef5b7b5b58f93988c98d3286eea00000000000000000000000000000000128cd3180884d6c6669c807edf86da6249324e75207db8cfe3c0dae753a9ff91801e44680cb871f8f030babf675247b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a3c055d34e132d2437401572217144d5f802b4066ba98bcc6215d85b968a2bdd4eb2fe7a869a35289af0fecc44c52490000000000000000000000000000000017e2cf12c7917a33588262b988c39fa208abf79a19e6a3c8e72ad42f0aaaa3310d6a7340249eb75e181513fb069e0a961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123915e8ccdafa20d60e1462465d17c1fd127825704f8e73976a4e611a3d3b8a85fbea6a6cf839af569e0ebaaa07d82f0000000000000000000000000000000006e3ff74c0fe03504224bbb25137284c624a1efdfc4bf1c790716db26dbfc89df4488e1be7157c535a91aacdb886abfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010368947b850fe7f68d38577f798d9751e5ee3833cc1f01f7fadb7be6fe1ca4da2ef79f0e9e2c731b4dcff4c2db88f750000000000000000000000000000000016e387e9190f9ad95d0de690a177c008cfbd061da000d3e9047b21c669be3f140cc93aec8c03d88ecf4d84f7f8d821631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003af12a2ccdc7fd35105e639d1524042f2e41dbbea20c993222ed19fc50e083770751eb23d43acf8bc882dbd2edc5e260000000000000000000000000000000019727b23d3fe623433764e4e31650f300dfbdeb2c0ab8ea3faca9331a755ebc520171ab226d4e68badfe15dc7dc646861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097d0b066098541976d496948e619d2d915016af5e7da9e1d98ec860f6d1d6a011cd5754a2269fe9c5299a4f1cbc447e000000000000000000000000000000000b7708f4bc17411ff67c025f55e495cff8fc0a98ad0ab65f672f6c5eb24f649e5c05156498109303f370845cd3e269c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d8e8033b4baee25656ec226ff9e5a833f5d48ac075dd9089b8d0cd67242f39f095a1e7098418b0960f045f99e8535300000000000000000000000000000000128e656237d5d5489dba7acfcf261137666cf501be256fdc7add8fae50796b312eedf403e560aec343fe7b6958f40c2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116973b23fab78e6e2bb86c38abecfa20e1caf5df09f410329b7840fca245c444e5631420cce346b7b4f596bed17974c000000000000000000000000000000001412ec548a6c79a9615d6bc1dc7bcfcef0bc71ac811e6724fb88d8aa87cb187fa38c28f864b84d10ac21887bc4cd79521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004494662d055e684941c308795ff2116464e0cab72ee9fa20a3eae4ceb4178b17437f3216102a8fed95ee1e541862bf7000000000000000000000000000000001895a144b0621f1ae8a6d624fce43102ce5fbc3ab844d39cc0f822b0df2e5d58f2381659b9d8b5abcb6a4f5b0dfee66f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f959ab7ae43642b043cbc6877d24697a4fb324df8eefd065a0ac2da6ac53489f1ba5a056540f344879a63b2abf16ea000000000000000000000000000000000080c1956342b3777067b607dc5fbae53c96e697120ac7e158cdcf8266b4649215a095dc5c3c21144784f4b1024982a081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a09ad646c9f1ddab48c1e8ee2819e19cc9e89c2b22f85de88793c2c21e552fde407422227b5515021bddc0950f52920000000000000000000000000000000005eebb8bdea44fd2cd4f5095d5893330fa371b87ab269a19e4714ca0b25227da83ee5035a426e0fd07f8ecb050194ca61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001265251439d3b1989cc5c1d7b98276c4f75decec0c78daa260161c7deddd4df418c97c746b6ec9ff6188302dc5c84e00000000000000000000000000000000105fde2f4a81d245db44cdf900601b0780cfed92764194ad11505696978db156f0c239dcbb2ef23b961743270724ad641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092f2122130876b6e380765b50372c9f2cb18d8b4ea272e598ee8b55320c863372d418fb9b591dd2c57c71f1e80b030e000000000000000000000000000000000efacf890803ca2b1920b5261510d9583abb12aa0e1efc820c972988e2a8912bd321896fdb911937b5e1b9000e82a5571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a08b9cdec028d98bcfa263723ec32bb283b191f6b0ad5b8b6795ec7af4600209e7ca17007252ad79eeb92e70d699ef000000000000000000000000000000000cf8bd21dabb69046c657d6e66ee81597304316930306d8189c7ccd1ea2a2b9c0d1bfe8bd354df765c509bf41e4f34261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a19c784f15829810c700b41b38e06b441025802524593a186c1ecf58e761a99dfdf1a1aa4a4ca80d10a0ab17fc3e0ef0000000000000000000000000000000007b74102cff63c066485b68b6374418b0051b896756577cd415ced272858408550c1f4669d10282bef2a732ca58e8cf91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfa15cc7baeee6e4240d5197540483e79b4a2b7d100d1f1f3777643dfda5313c7495bf21ce8696dd78586fed65d6815000000000000000000000000000000000a656801969cf36a3243c74892a0bfc923cf813ad824f3d2513937f6ace4a83c8efae3af9175444dbcbc05348ed35e121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020b756331a997e91011bbfdbb490aa700bf26cbcfc70fbe029ba42bd97990017f24f2a12851539865ec312994a22e5a00000000000000000000000000000000100fe7803ca3d31bba156db9147c685d5858bbdf8b34accb3dae0402b139c29eb8068b51e5a36dd1177ab8321457027d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014bc4375e473a0cb6217bc4ebae061fbaacea053c57d25b3f5cc847d245abb35c3ac165e679e71a996b936a7db11c4260000000000000000000000000000000005f2a36f716b481d51deb094a3dbb81452918eb243da53dcb4ed200aa78ea03ca4559e0f1819e717cc66ca76b9a817f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d9a85a0461845785e39f8f56bd99b1c3dfa89fe6335530523b38649a62448961f340086aa5da123d86a11f098e7ca3000000000000000000000000000000000576b7bfb6a2e2b11fb515333b890cfe75e907ab4518d3d60bf36683eb2981d5eaabfddcb809888485b652aae7d4a7f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001229a3425c1cbbc4538212633fe88944df87e5c71b99bb2c8d55a88191861fd2acf21cb5b4cc058ae84c91b8cddc9d6b000000000000000000000000000000000fa86b9206edcaf427b9432ed8a62106f27cd466611dc2c149af246eda8f7252d1537074353cfedca6e29a426a7f546c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100cf68390412b3d6f7515d7d8f88b1f6a3eb6456ad911669e95ab01d304aa81aa89879ec15c5bc3f2cf24a5409caafc000000000000000000000000000000000497f45ae5a965cd8175959b2d73e647dcee55a104c5f89c4ecd81f9470e3bf003008fdff453c57a69bad46b5d6b0a2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006816948e64a32eed42b0056102c9f3f1a5bf8214f8718a19f8323fd59e67a1ccfe2127455b21cbf5bfd08124c6dbdb30000000000000000000000000000000009225e10b8a5974826fa720d578ecd6bf7193f8c91675a0043497e2bee9801c7698068faf316ddb6e5b77fa491b22d751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119854734ba80a316abd66ed2d220ce40abc655791c58f70a9c20a9195fc164f72e680e1c4da4155c00a4b078d2a0ce00000000000000000000000000000000002fefa172cd9d62512e1ddc9566b6f69855889281af11701d7d24564ba178e6bd5fd7863eab398c0c21ee4989ebb4e521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001172acd67a574da584c69629e3d0749dea49a4bb93b07d0b7eb24f0a85e16614fee96d2ddec8fa44ed767083c53035390000000000000000000000000000000008ee21576bdf5b2e1606962dd8fcae0957e7c722d31832091a69cbc2eacf1590f8ca5d3f46b4fcc321d5a25f066a17551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1c221a750819fa7d92b538f2cf863a43cad81c6621dddedf81f2fa748b2563b565fbe1cca539600ce0cd452250bfdb00000000000000000000000000000000191be772861050cd4b68504f7e839db4c830e89d141c8efe5b063c9bf0b1e2ca97b0c0dc77095841493c4b29463102141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004fab92dc56271f5431772d7f4872930cccdfb1ad94e13fa075840f6584203b9d3abe769fb028b5c8e05ad9ba8b9c73d000000000000000000000000000000000e91a61e13012b3f1f3ed18b7c91eb4deac1d659c7da3580469178d9c861104a44cd73a930cf9901e770b43a42c0d6fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc82e3d7b9a135c3eb80e84bcd655885ce42f92f50fd1c958c503fe9ceb7e7daebe947f915b45968d1d0a44931ef91000000000000000000000000000000000158a02157c32faf4048ed4ae5312d5a48466aeb435efa50b515ac32e88f4578a02788298215683a3dba8a2c30648c4321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001520d4658d717a8b9fd64bb5f23dc86d7d75600be05e8e6a2c31fce815f42db4e30aff05fe16e3f3a0b2772da8d99b7a0000000000000000000000000000000011048429fa0623f549828457db04684a413436c17c551c897cb9b325ee5000b05d67e25a163b54be7c7ec558a6a746f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b0b07ff4f07c8ac5b9c162a1bdcea4efcfba8e4f961adcb02a7fbdce2bed72f316be3b3ea4ff72c0b06261af247e5c0000000000000000000000000000000010468f3d1425b239418f7bd8e70ff5747d85069ca86d14d716d8f54905936203c4f11b26c51cc50d11062e8726f683db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019be99ac80ed551520a109e83d854d417d18298fa8ec7024a0b1eace829334d0992a36a069a424723cb2fe3d8512d6b000000000000000000000000000000000180d7ab893fb3f7b1f4cc7454a53e9ea1e67ccc0fe659c29b460882168b7aaa3069fad7f818ade4295a9260190db9efe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018287773c452dfe9d64abbe69dcd21027764248a684a40f630ad106c573de6037fc8896d2452bea8572199574a6029400000000000000000000000000000000139d571255edcf9a8c26054d6dd29da2e4753b8e2048fdf058290fb440c4978ab2dd19daff3303abd4e147933a99df7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000036c9798a049b34196b5eedd9df22399ff1f02b0cda65b58b87ddd9a8e36b1600f2242c6694030940737ba0eaaa7a630000000000000000000000000000000013aa2d506119b80d0f0637907173705e80d93c51a5e033044b322c87df88029df2246de09394a4fbccdfd02daec264da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000807eb8f582ab3f6f4af8d1119ca65f39ed44873bc8f05fb3e24071815a33efe6edae9bfd17baad7be38636e32752d7e0000000000000000000000000000000007d169b2363d7000d81aa036fc16557dd7559698c26958b2a30a4c312cab5253662dcf4a06e4dcf4996aa39e9fa470381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000795e084ac510f891bbba776dc9c89c3028bc5be7ea4e8d7f15c7b2b70f73a6d7ac6e78e33955310866edbff5a137df1000000000000000000000000000000000f0e02a792452ec96c0b869c92d095065fb218dcabcd2e8286948dc51e573235d4255305ce8587d0f5038f5c72aee4681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d49432dc402de6f21893d9283996a259d6df2a7da5d218a51a4c6f0cbae4938f9352429f7b5a8fd5052ec86c8eeedb00000000000000000000000000000000072c2502b05bf02e13cdb15fe9c457fe611f37dae396f333bc161939514934743affea10ffacb0673d0085a2f5f9496b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160c52e982cbba73b7f70aff84820e5d8d1fed4595141bcaf8f8ef0e5739bf73a0283bea40c9b8471768b08f043546e800000000000000000000000000000000056617d5dfa539f59ceb25f607dafcc9c586f67635e47f406b67c49024b56a105693d39b2609a497f7c46d75864a05471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014cb3c2dd83c9efd78945607c18f02c872ada20e592dea21315e8d99af3f9b88b68ab17d4fc25b8a43404eafefc979670000000000000000000000000000000011de8e838d8b5807a5a20edea048ad6a7082965e8d6732a902a2e97c40c80896d1f9dc8b15d8ea3712aa04e8020ec3891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000070bc90292f5ccbc7e68588089a117743a7dea99aaf4d249f8e0d93a00f7b59451966c00b31c9824dbea3e30f2e6596e0000000000000000000000000000000011e8d0194ff0404f9ccbca22456ede1e3e3b482ab9e4636c8af477cfd3102ff89c9af9f1ac25243575520d29c6ec00d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ebdd540355987212b2fb9cebd71a9eb72c57fd1eaf95ccb8e5b9beb65da2ead0fb6e808bbcc3ad59c2ead2f36353bf0000000000000000000000000000000000cab74266752d4f33f41abed43c67c2cad5a83a201c91acd282f1e2d837f72d52175b9c1df7a57567d01da4dda8024c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b073df5fe8949a394671de49c17c5277aa1304c9ddb673b6389d1e3c88741d7a118aec6f32c2238d27adb1bfd115650000000000000000000000000000000005dd4477f898237f76aa803efde2533088280d503ed7a02c69135a1f761c84520ce675c3d2cd973d12255793a58abed61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120d32237fa7d4023f039eaeea63175d43534145bcdbedf88832f37ddc8b0b48bfa4738cf54a6557149307722d1ac6c60000000000000000000000000000000004cd2b45abdb1d444205d2dd606ec840112b8d1c7bd1baecbba996071e9ebad4ebc9ab0d8fe11325c57859ee535efe751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109a6d6021ceca689b98a50e48502681da366be95d584565c911582d0ebec2ec842eec9a8c0ad4c9526deb19b1c8861a0000000000000000000000000000000014741c0fdebdb08b450183b36b1ab2f26e8749d5ed34c4cb1155a9f4405741059c249de17c7fc0867d6f42e145e056411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e6c05e9e850a5ac95723e46054b5b0658adcc1be8c0900f480946350b5369b15540378ab55f8f3e9c4390b953360da0000000000000000000000000000000012505dc029a53a509b845a6eebc12eefb09d729aafcc9797c27acdf29a6760c6547ee42c2fa8bfb4176b8fab2c88ddac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eee87a030ca52f7af02a50e97f0b0ace756a825cedb2a02ac06fbad9016ba46e7208577a023b648271260121f1147710000000000000000000000000000000002cfcd74931d0fa72ef3a39fe76d4e3f3b63b441a7783575069960ccf00c050fba55ea8c8e945a9b4437fdef0f6003721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c589a1fb3e786d9eaaa56cba34d51aacc43dfc9d92859654a90c7bd4f6eac4a2605f49ee25a889b1043c9dea45430790000000000000000000000000000000008b099b6dc9de481649e442eaa33b4a4d4d32223c38265c26cfc02c71f7c43e41e374c1a919d2c2909793e7239ed80ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045b341c66de142896199f574ed462d10f7225932d83b06376669eddb042a4f82e6edc86c7fc359096718af2bf37714f000000000000000000000000000000000a36da6a457278f263498459ebae99ce6257c920dc7eaabb20ecf36b24514e2003e6dd42a45c4cb685ac38b7548b3ab21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001950ed0e0acb4c3765f8128cf778ee58067f9d4cd9be955cbade4547104ccd19e16ec01b91f30575fa39e50c7b2bd9000000000000000000000000000000000000d663fee557efaa61296e20b547f0f82c7449ca19d4f1e02c9367352cd763e85479755b57231bf5355402af7daaa8e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b3efe0b861c14bf3a1b50c61ba56f29bfcc8a67c04c24228ad64f5964a383fc658c4f11be606aa22856c7cddd516ae000000000000000000000000000000000cb3531054645600fed1ca0a0c6b3779a51d292a6771cf16de5dbc698d448a844746e4622e6d472440c540d1bafd97c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce7a0bb51cb2eeefad7ab2f1f6f20b330c0f3d3a1a6b94244d9db4629a49e7a2d370d9204d349d4fb1729d371f1819a00000000000000000000000000000000018fa3727cb19113dcce338637c2b2290e9ff1137161d14dcdf1a1bed054f7a4711b50ac176352daa83add7cae2870fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a6d37dcfbee39ae8b0943980996993f47e9c4dc7db34db03b6d24e1d457fe6aef4517dfa32ff63528ba35dc6f9950a0000000000000000000000000000000015a229f9f528a3dee397a3bb776bc04fca4eee97505f9f9e7f218383575b22f5475d6cb4ad0376e035be4b324675afc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001323a85be79169297cea9daf0368cef178ce2b133e093c91e9c9802e5082dd76b804fc7be55548986761ad71fc058210000000000000000000000000000000000697222d456a45bf05eb61516a82737afc133634a069c5ce957b3371b3933cf75b83b29a6f31f60d67a170a7179662fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001690e91b9fb7ddfe0ecd191b6fec8047409a153f2e08ed3d309b0f6853dbe5cdf2579e69c27f354ba205bf875143916a00000000000000000000000000000000149050f172460ad12c7ba3aca01934acdcb8e51150d917b4b696494376d20bdf8f3b2a60261978585c45cbd47313efa31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195b76af3b69e7ebcc573228abc82c08f252274cf05ab89cc5a6d8c646dc22f340d1f3817f503e7381d8ea8d72b313550000000000000000000000000000000013314c65e92ea61dba1e415e5d0c46ba0695b0c03c4c9905ed3c629d71e2f16a479c85424d5940871d53ef17acc221331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b86eea0f6fa9681e264acf5c0290a950ad9287be412d4715d846b0bb1d1543605da633b7299ce52246c75499b75bc64000000000000000000000000000000000a81b45683a01431678baeb7070c0c903b92f1f96b0a2a5d896ab7ee6d6d6062fc07b387bf9f7dc4f093f49b0ac06e411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa61cb0c9d6494853bb501e1a7fb6689f970772b8038c0ab3ed17eecfa28955311e386ebbebf8d160feb572ab85410d00000000000000000000000000000000151b9ff63869c97a5c385790f39b440ee1c72de16a576f82f9c3fd80f9de39bf481456763729667cd34c08bcb0e024a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001586935a07b819a547018adbe63b0a3bad8c1636f7023ffd4b26d07fa540ed02ac821e5dbcf3e10e63f7d348471c5bbb000000000000000000000000000000000614232f3dc6820cdc96eb56843c0aca376586cb801d0325e5b05451359c85f810d8c63c9177f2d9ec744f1626386e5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000011de7d147588446d75904da811ef4e85ab0c8680f688bf04499ed7e517643e07d4fe7754dcec9124a2151d4f771464e00000000000000000000000000000000141b756e740d973304f890dbccf8e197b0a1bd254a9d0e1b49468b37326d169afeea2d86baf6cbc9ce0f09967b00d48c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c97054494d055e828247968f8902380a8687e0747f2c8be0ab56ddf58b75df16651f248a757925f9ec6dc218bc87d41000000000000000000000000000000001600e069faf4fe6ed355a948d7b9f90d223e93eb26e34c2248f17d25242b88cedf2beae3242053b381b0361752f20ce31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cadbe674fd18cc4d241c6643bfd5120200ac8e0a6173e59dc52add259b91ae3337f6db0662ebccc9fd107d7c749079200000000000000000000000000000000139079c7b506f61c943e5e9a861211a5cacfe42363d8cef75ab2ff05e6ef1b316b7fc89f1cf7d7aaeebaf600ff591f491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a909049ee11dbadd7bddef177800c5023ff19596988266d9a27bb740cdf9ea74d12a4909b147834a583b5db20dee6300000000000000000000000000000000150dfcefce15869fed2331a924c77c723fb464441e664ee25bb8ffdc0cbb505490b0105eaabff24cc3657845e8f632201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000091bb0a0f2e6ed30dc8bd6b185d4597151c5a0c0650170c0da53cd737bbc748f015c8ea2ada70e6006efe60643d3ac00000000000000000000000000000000005dbee65ea4f90fa60ab702d1f136d2ffe9e88cc46d06a1ae0f2a08b7423dbee61f4102346d4fdd29d732fe553d854151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff968b9460d9e9b0123bcaf5e7cfc57f4fed0eb5f50cedf4bdcbc6b58247eade79aba316e3809f1e2c9598876558c3400000000000000000000000000000000198f6d5fd4f12978c8ed50ed8273d67ea2c28a432f25a094f76e5fe9434c350beba3f1d93c5b1ed5ad88a5955410d0991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014048b78b7a1132cf3ccfa1269712bf5e9cd59488797c2ac6c4c26f3bae4e3b4f3050085e9bbe41954d10ae5a9a87075000000000000000000000000000000001357fea3d344292ae65d10d92a1123a3ef133d37374bf20f0f07e31964b559035ecf1f812aaf64309f43bb51f3a4e5801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001199e39255f6208f0bdd309af7ab559dec39e6836f608100c7c3477866bec058dd76546f79e0fb5e22fa598575e0d2f4000000000000000000000000000000000df872339c6cd3ca630ffb33834075a5367602962768ab890cdb2db6784f95e554d99c9adb713aa206c96180ce1512fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000195ab991a36c912514ca04444c0d44fc3cdfd0e40c0afb9dd310fd712ea133181cfac99cc49e898a07c18098f05721f0000000000000000000000000000000000f489b243e09e54a48a589c15ca823af4bbee5e8afef6a45b89fc0adaaa2a9a79bf422b2c610f77550071d3285078a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011391c9a359c9c1ba68687efa2bc381531cdeb571f586c8893e6449befa4de0886351dd6497fc9cf9a29c96be77594ab0000000000000000000000000000000012b76ecf7301cf85f8b6e4eed83ee03a37707dd8fafbd9c0f2e5bb01d49a5401abbd2ea6d4def405c04fdbf58dc71de31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000044e7ef1cc2092abeca7516ce3815c1697d4cbcd3f19d41c85902c88a4e686b77eca7fb5a46e03aea0e4ec6ffd70504000000000000000000000000000000000e54ee755b698f7c026d94d065ba1094e68992afbfbd89e2dd43e17784cb5a713e723a15bd96b7bcb017f459ade54b541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074e9718bea2e11fa01359c4a545382a931fc177084f756971e2641096d9254565ec4e02099c8b1be2c4516b5c9e789700000000000000000000000000000000127e6082d5f838ebd676e60fc6260e007d66fa3998b8c191ffbd2acdae0aae025fefe0692828cc869fbd308a23e5596a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000257559732d99da8f646a75460f143a91475d6e06d4a52b2840afd18325bce52727c5b3cd4c4faae5fb7c9e23daf6ce3000000000000000000000000000000000075909aa15aa574db3142605772c43621f75d72bea53edc701ed118a5f5a793d46c0cb07b4b7dbab5d8912c1863c5f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060dd4eefed2ef57a59992e5d130ad7dc379239fdac34513049fd25e21b778d66d4b7867cb5047bf76c4d766b0f97e6600000000000000000000000000000000056a52d55f4f5944cf2538986388a406a8d4d1037e701488129cd6cb88ae57521346c79c2d1bd70fca9a20093e7752e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000162105c0737d011caf032884a379dbff34dacfb40010a49d22c47b349fe45354cce0b32abf70a2fe9d0d39eb6ce8dca4000000000000000000000000000000000a77e56ec90af91ce92400fa544bb6ef83de8261cab0f263e26e87c9f9c866ba16b5c6870dac9f4f6bbdb74c42c870ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e99282b1da5c274df366840f317af96b438a488eaafb61c3c43cda62edc175b4a7daa034efdc94afe4b167e573802b1000000000000000000000000000000000ecf8da5c49aff47c28b4685a815806ccf0a9a194d5e7995aa52790a6b33c2ceb52b7b59c7b31b905fe5818fc51cd1941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016cc32910bba04d090fe0ca9912dbcf26f8b1f95d3ec65121a5429413984a82b54840d0f252e4b6a57bbf26a9e6476660000000000000000000000000000000013f1ead087dc89abd71cb221ccd6b33c3c02f044d5a542117cf354211d4996ec9350370f1158c1b5d0fc7763d007ba3c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110b4aa749e6d111899f08ed0c1993c77bfd9d638957bc0aad18926e457103001b5b819a1d62a6807ac78949b278f3260000000000000000000000000000000005c33a3ee78d2c0c3c447c2af5b35f8f44854549baeaef72a09dd16cd33fc7317fc32e3ae7a90d94afa202fdd53c16921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000885bf363dd2914730ee942da5da479a488259e72c75bf543a2b97a6975601d54a871cf1eddac034e13dda8001b258270000000000000000000000000000000006e0052b4bf4cef0689526b6332732a7f61d09871ff59185e0da997cfe5bff201fee5ceccb09f9d6eb1b343e152038651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b0b93c63e99f45e47ea1f34726950a059cf373cb109b8cdb279fb9db2af5a74f0702747cf92e6d910a85f7e8d223550000000000000000000000000000000006e95fd92e41e30a55f00db40e3b77cea6ad62277a63b5de995f63091d4092720084b8c91df3b7609ff27d6ffe1c02fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d624b2e9c019631f3fa0f5579f8cda39a840162ce6d64934f4df851e4cf844081d77924bb0312380f7469c4c21d1efc0000000000000000000000000000000000d978ac41f054eaae0ab1e2022e1e675d4e157b04b9caaf8148b0edfabe591a86cd6000d8ecf58b7719e3946c8d92d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058464c26f0bfe8982c02a954e3cf15d433489a29f73cd3d0a99ba7306ae467e2e31de7dafba19e2cfcd7cee1794aee00000000000000000000000000000000000a836ae57108ecd890ae8e53b98a13d03772ac8e7365c4ee3940f6bed7c57906f9a3096548b8a135d95edfaa7c945531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007fcc4c28705f30bcba3dc8f21f50f146c94dcc1ea06db07f1db4bf8e23a2201947dabf410523989dcb4953f0f3d84480000000000000000000000000000000013844a44c75ad1f3bef5826bd8cc6a155c9a1b1ad55c2806b355b235e79bf07ee9f89e517bb020f483b668c2536850771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026988b706ce9fcd1aad5fedbe116b133c751501136e3beccdaa6f348cfc7a3dbe1f5e6ceee4c367130ce863b5592617000000000000000000000000000000000823b0b866fb9b5d56a5659a92c649192184bc8abfabdbb65962dce24728ee6a88441ad9bf6ff290f3557f2d34f258c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7ca17dfe1e8e6c256eb985edb81d9a4c47b8370aa6a694200d969c54e82d10cde63b6f12f315119e2b3f7afe5b92190000000000000000000000000000000017e7c45696a9182677cbd4214250b08b8a0941215315038844aaed01f02f23676a4360db38ae88e7be684d505999ab1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000155ba51edfd06028e1e51c04724e23e9df577e748f264e8eef61ebe232104f5d9795aa56ab1d7e1dcaeaa1e5979e081e00000000000000000000000000000000126c5b6cf0e102c92bb298ee6ab18822870192e55f990f2cad7aca1e710f90b8e24f2d61dae6e91d5d360d8e28db724e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000121eec3ca445ba81559fe7877e5f205cfc2b5c257b01b3e0382d767cef4c52a2132741332f3c270eab22c7f3ebcd2bc00000000000000000000000000000000145aa5d02f86061238c465b3aa0ea7d96f55e821d1c0e88a8718884069cb16647cc6a68fbb0b8c79921ae6bf85352ec71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030a5de1f0efc90969309a4ab3b759e37bf3af9100693de0154969fd1a6f00b71cfa4f1a5939ce830a197816eaa63c54000000000000000000000000000000000a79d5911081e6de8f1e8a251e9809dfd5b474785e33efb536b8cc5d5c160f2262fffe6a5a0fd9db64d3044ec08a8fcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b653a35f69f0071a0c3c5e1d12429634278bf5e30079580c3e30dbbf207bcaa00946893c3ef0d9490c74791dbae222e000000000000000000000000000000000fdfcc4843ac83643bc9813ed57414804b33a431d7901e9eb8f8a11c74975277ea48923b69461a4408e0a01fedca21ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136875932d8b14d0525ab3a1b7e8fa61594804edd00ff2fe45b5fa706919ea9fef5eae900b429bf5674dc3e84b40d2c80000000000000000000000000000000010b99d5e7251b73910cb5dd443755e4853180cab2813f9bb4245538c193f8bad88ca2c3a34a4685af0bd704db4fca42f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c67931a983ce71e271a443a9514423f6aa578a2a9e9b0197219832e79e4ff6eab503d438492ef3b8983f4788d3c2a8c0000000000000000000000000000000014ee7fa2c9a626a7a5ab6221cca2a78a7a258668ad24003fbf262babc563f87ef8393569076cdd1d59ecb2c8f57e0deb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e568741db3e4d8361784d7aafbcfc9e6a99dd3c9ec5bf92fe4063f69f624f75c3f04407ff00201a54c8e45df346f900000000000000000000000000000000000b211ceda1aa72598cc3f9e1ae8ea3e5d77ccf82ddf8c86474bc0b58a1c7a3b89b05ba96f3bd2d66c48237be125a0f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cadc312c3f92ef48134d415c1a34e97de19abe06ed2b96ccc4b3d974ccd563e566bebe76e67877003bbdb8bd401c4c2000000000000000000000000000000000d7d610baf66d3a2e82774ddbaa00541d30862cbfc2f29b4a6dc24fca976d5dde8167f957d1ae7bc7e2c409859face3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154cf2dc88d1b9efeb401208434ba14163375f62aa02f0ac7de4828d0306c85554bc7146b17c68043b2c4b33067a26c600000000000000000000000000000000159030a1c6529acff9a9c496e662360b647cca03f3d00aa0eec639dd5572f0960ff2250a6eab18cfe9d16fdf377449011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000475cd1fbec7c172ac560cea6fd9448d745e61301014f9887569da845548c9b3ce8f01bc6db6fbd8ff6c84073c7f02a500000000000000000000000000000000131c69d5c3bc61d25c662133fffb9dbc98c01b706db4621e54437d3ed62902d56f6d5020aa2b48862e73ec7bc1a1778f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008fee063b6c6734d96de1509759de9ce6679cdd953155a6d9ff70e3259441b35c8ae391f2ee1714efc9255ebc93bc0d2000000000000000000000000000000001790ef7ae78dd3fa52c332ca783226a707bba58ea78806d752e64e41267dd6321c7d42634e151d1fa1c4fd902776408a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017cf4a64601b9bcc3a12cfceabf43d5d4ff93d03bab06cae3f2cc19d4a88affa9e46465c1dce988b66d423702bc4bdf000000000000000000000000000000000eeb54579e8f121183a9787b22bf3b42f317da44b77965a19f1699326b73602def0d935f60d4a262a85911df81f8ff5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac22c1558585a06a2fe3942a28d79983d3be184de3da4e49413fa3ff94f4a0f66445b9d1c5aff5b7f6e64db59e3422e000000000000000000000000000000000558fdf3d68d6bafb253c424372bc5cd6d1f0daecc97bfe163e65962ca2a8886b2077b078343e67aaa7953af6ea85f441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000daec869af0613fa94aeaf448a2695c56ce85affcec568592dfe513a81798e399cd00732bf90dd071585bb9bd1645de100000000000000000000000000000000023a92a28d32daccf0c35db4bb11236666723c3f75b1b6b043071833618d4308483357193eea8ac52c11c41a894f44a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007d88ef9aa5eb670d032324a7aa389b936eb7bf1fc80a82dc47f49293ca92de5a700a6d8d37f4e10092c4de9e98503500000000000000000000000000000000128aa5e7268422ea5842fdc8cf1b634f04c001f9825b841b70e79f14c3181556ccffa998de98ad318f91f90dda9f36731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014dae8702d9f1bc1c7c72b1fa61c7d26513904ce9ce0934385e9b3d613d517da539a1ba85bf7782b9ea7b170ccca2bee0000000000000000000000000000000011aeb40943f4fd1e37d64230bf258cc482b5222b0c16d33ff730e2dd5b68555a950d9b4516cc8ed8783319115b6285d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008904071d0b512f08371d522ce44409ecd053028bde4760422ffe63581a604ce53a303750fcb8c0fbc90b46dd982d7cd00000000000000000000000000000000179f1a5d2bf6a51e1b52daf88dcf17ebf0fe923d8d6ee356457b8c186bfc845e378dca77963ac31c9c1f844a5715d2a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149b71f3b1f2b0543aee0d862520cbd677f306cfeaccd1c7faa48481370c3ff0d39e3e170fd88eb25a72c86c366d24ae000000000000000000000000000000000c597594f26a0dba4f8d96336a43c7327874f9dfdca7468740e16ba77b935168b008a89f55049ccc54834cf9d2e6b9f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000fc8b28cef0fdd0b2bfdb48c022bed85689f6b6d76ddafc92ad800b1158c455abca778b9fd49e8c00977b5d2ca706f00000000000000000000000000000000048849fa78aacd30157693e47fd2157e9ea6c8de7b79eeebf8dc76be195a31dd5f3cbbc0aa3a85bf6bf0ecf586c348761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013dcb7ecfce41f680a1c4340c9501c111c146ac5a9457c68eb4b77c62a162ba8c8b6050309083f31e3f6d8f2495dc9ee0000000000000000000000000000000011ed7cde426a5822af4f1b9764c7892849b33d83fe10b24e64711b89e2a4702085fbb56dcce3cc946ae033dad76250841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001537a9e86f194adc744154e6b7639ac03f754a3e1f9a4bae9ae17bef5a6b3a7c59ae73d363679bb9ecc88ab86c24272400000000000000000000000000000000168e11aae3a8b4b1c5149cbc08a4436cffbcd093f476d44c7d49c5551ec3a20279dcff50dbab0245048c8c06e45a16551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018154344c90fd0e427d938c9b1452febe277928eaccc4507397a28501f6ba102195c0c20c95124dcadd9b032024040f7000000000000000000000000000000000d587f2e943d436f82779f74e1978855dcada6b84d79238d39f7e55ca3c00f3b856e921be2e82c7a35104000d3a205e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d192f001de6e72b4b85e4b276505177d8298efc0b56d20e3889f5188d781dd15c08e7a616049f86338c424cc48c0220000000000000000000000000000000000d63383b0e872d454abacabfae483f6499c890c2a5b30afd92e38e08e05eaa6054bcdfca9932bafffabd4fcb299957551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009da375a4351830986e6f7b93c8cf2c79372573c0d09cc313bd6ef0ab1820f27dec320089e8746fce4379f1895e9575a0000000000000000000000000000000012f934629242edaaf4d243234b487a6f74ad1f6569226b40e4517bd31767be1a3aa4155feb9a296ac79447cc2beccfdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001914fe4b019bb63d75d10ccd25b78c3c534017c0e1f72911b21acacf0860579806ccd70d95269bb6a3001ca949e2bc8000000000000000000000000000000000133388ecf830695dac82257e0c376b5e25be77b5f5088519962758cf14aa49a27adaee2e465b92aad592b4070868d3b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000256c0fef8ee7284fea5dd2185edd290655dc6b4d08085c853eafddd3c4d329b389e1d4b7be5a2db2b5ef82102f38071000000000000000000000000000000000d4ef464c0b650ea412deac762f5e59d3e6b6097e2ed72c4f961f44fbae29f300e95d24db49550d65b8dc3177eb0c3391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006fd185205b47a025fbb4a67f1c427e05dce5d163f6f00fdac0d4c2e47812fe0519b386bd2fafc46f68a445465069afa00000000000000000000000000000000105e05262097644a21def89751ce1957c8d1d150317a9b4bfb01fa2730bdf0e946e3115e316f07e233b1518f72e919d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143a176c2b333f6d2e19a43bf26ab8a9a3dc5a19bc2b71ddc2f08b8719fd32cba54d320e88f3b57548b7470b5446675500000000000000000000000000000000185498b3c2bb8f72766b46e1fedee2af3a91650e926947f65c61e40ba4a06d83f5f68016f21e1d40e1390f383c323c6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec1027cde8aac7bd034b60b6f17bdb1d0839ccb32262af595f15c0a3ced4c834063316fa0930f7f6c34fba15439ab18000000000000000000000000000000000d9b8cedb0243e8ce56f92be31a243a42bbb73a6fae3448c6b80417b18d0e8ee7048157d37f884fa66c0506ffd0083a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006daa65c099ac2362257b9bf1ea5a16f152df28e9526c31080f17ca785c1fc2c8543e42e8c5024fc9420e199f837c9490000000000000000000000000000000012589e7bff4cd73a9509e008413bec5f257626f2365075d11630cb8f167c3bde03f1d062ead08fa2eb36931f8e3902701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ed324872838934d5359344980d459e5edaff39eb89c33a3b911b1208f33763bebac31909e74d9b86f8fa276b4549d0000000000000000000000000000000000b387f9dc31902ccc58cbdd83c1d129e628c6fbdc8a180e58b14a2ecc3e35b63c6cfa85c08c4a56a0f65d6384d768fc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136b1e48073c265dd979482e55ae2de6114193e3b1fbe5cf3a1d5ed11d62d51f4bda13c32266703339f4cfbf357ce82f000000000000000000000000000000000b17e24e77240924321c2db1eb2941b570f31e3a31234d11c2caa86cd2436b67ee4c17dbdb0ce9cc99bf90470c5287d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009dfebd57d40a7e0aa93f975d485d054eac9f999ea1409d338eb53d5269c61a7592e5cd50dd3561ef0a176e784d428af00000000000000000000000000000000106d959ff80754040502035e32f8773b0c00045068142469fbed48851d289902d70c97042a592087aef75a75d010c9521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1e23ac180af7f325eeadc38f4c3b9d37fb7aa9148817ba508ab16629b9979cfae24c65d2a83b64a457131c920dc9530000000000000000000000000000000012bbfcac733666df96a5c3fb321411c6bd5504451037bd32d0b6aebe7164a81fd0d70dcb40adf6685d4c49eeb75bc5501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018563149cebd11e8459fe8db1d3cb1acc7037fe5d5c308ad0159be183144966c44e3e7a8c0bf375972065813ba7a366a000000000000000000000000000000000d33ae69ddb61995d10fd4ff1592c5ad11d30561db476364e8386806ba2f047dd07ed6746eac3a754aa0d295972f315c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007e400744dd3062c24f397ab8c678c400a0366b14b7e1bc89b0ceb7390cc6d31aea0d3afc9cb32ff471d241471a2e88000000000000000000000000000000000c39a4ba9cde4479ae5b5db32c13dbe4bead8669a35499c2f009bdfbb879604b4e2387363bac076392502a6e757c8d361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bcd332572d766e3a5eed58985c755b7c0986b5cae01c24282b20d1bda5dbe39f5cea1eb5a29212874a337d62a96fd510000000000000000000000000000000011849c12737b88236624c411e210f0a55b6459f1eeeea5ad68e287c8308a9e5e87e7b96dd5f97671fba3677f0c0b50aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000671300a283a9695b4aa3135d98edf4efa124f22503e646acecd877e6a207991813855032a8fca0b908ec7f05dde75a8000000000000000000000000000000001049a2e11fe6dfc9f194a76534fce4a1b99a4bc58b989a89506294cc64510f37a102c670ebf23e7c412c353c74bc088f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d1332404e5d497b78e44ab70eb8d5b981bb6230c3c1fc47f634fdf4d78fd0c0744709b92f9370c84551d0cc76bbcf7000000000000000000000000000000000fdf2902401ec6ad1bd16aa0df8f78c0b4042ed1112f69a1740da04e43315e6e14c06d0f73dd207b36f117bd3c6f871a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000294d018aa3e8129250af5b689737d108517e30da4f93f12487f7f57f3f5344222e004ac75f5a65c1a02e0d0137dea75000000000000000000000000000000001217ae634c6a04a46c17fb8666500175662c44fe7639f43a0a80965f00cdb844067c4797b4ef5fde14879ea270e3f6721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000519e13e91d8d2a0e6c657197fc96ffd26bd13d23c6e7a69ded5a95a07fe5c988879d84bbdb96ed3d4047cedadbec1d30000000000000000000000000000000019ba75602a0d92e30d450287930f5f1b25666ce235cf4bddd9e33ce439d8a1a2e1bbec54e20396231098e168b70b3d3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b9198d08399658b084bbdb04ba7e9118792f83a77bf443ed3d73ceaddf199568fa1407ba976970149fc9253804acea000000000000000000000000000000000617fe94151cbcd6f8e35420c9ef326dfedf10896059898a8c323591aaacc1696597d1b8d60275297de9e87ce74fd63a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009dd3b5fa4439ae2744a8fc770c4a4aff203c6a49c0de485a9228d38fccab96603271e7514fda27afd4626ca92790c4800000000000000000000000000000000163e5107efdd6c749e18ef16fd5adbb5cf080f28c390f872dd6d2a491b4f4ac01f350ac9470d65c7decd66e3f181e94c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000404538485a8a30bea899b4a23ecd8ba1c38e2dddeaecb99e7a05444c31b9fcfb40489dbc792875203c6941b14e244c5000000000000000000000000000000001761c409e265138b8f48e399f7500d031e372f0138f3c6f5aa1823f444378ffe958e0da4efa481e03614c77a240a10881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006444fa17c868d3a94517b0e6a73153210de21811a22c46b2d9037a9a6c359a9a18208fdfb133093a6bb5045212b38fb000000000000000000000000000000000b537e55415bd31135ac89ad4a0a8191384944aee56ae517d49a632e8930b2f9cba38ac1db423f279add2f153d48834a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010918060bf6bf3046632b8f48a25b044fb3e51d346dff24b6dabeb4177843f65059d28657e956fb5465e9b06adfddc4c0000000000000000000000000000000015eea01168f52269a09c90518277ee4a97b0029b0e224d9744ee4faa7b38431b821cc597997dfd0362d24fff1871c2321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194859f3ea3cdc0ac42e403ef25f298d1060478e8f998feed8c2cfa83e7a904f72a7611642192c4aa6e43afe067bd22800000000000000000000000000000000098d51524e941205d4995cdad84157a6dfdc687c4aba3461adb40287481fb27c92810ffb53c62f364707ccc313ecede11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9bb5dc30840774ac873dbbb617bf37508846f47f4a1afb1becf49115025dcd0e276bd59f1263f2303e0003b8d3a39d00000000000000000000000000000000062de355f55abb1f7f63e6eb007ca4bd8d98abe569d64f132816c75265b9a552398dd204c3b38a9882580ae677e7c57b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019cfb65adee3205e2592903cbe55c41a9ddcc51caef96a38b252d8dea589f12b6514bdbe8db75432967a0a3a046b5d240000000000000000000000000000000008b40b23f2f2ecaafb93db1fc378351544a74d08e335ab80f150b0ba7e7a382c91f87a6b05a2a6b3e15cd310204651631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009687be8156dfd68ef223302157083bdbb579cbfafc8a62dd4187f113db0a8fb0e8ca6c1edb2339aeacc6fb2f05446c500000000000000000000000000000000146edfdaae75cf331e0f21261c1bc1eacba1fefe4c95dd9f010d178a52a6ce7936b69e0cbe9dd749c12fb3b546a1c9bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d60fc6d90aa77e460d5ef1aba5c5f75319e8e88c8f3ede8411f9d15f7fa3ad59ef33c75df513f18b31e76fb1350336000000000000000000000000000000000f130392e2c9ed3e54df3d939884086359892f41d395b5ca0b6d4e639be0d00b3c329381f286313f7c9ce1775fb5ca661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001524120f1fb00d612dec222a775e85f9ba3a18055fd15258a41cdee77e1ba5d2ca56e7c8de5a367f62cc805a58d183fe0000000000000000000000000000000014c55722d24b4e3c99a21060c9261648095b591fce65f82059fd18e099663e86b951cfd3e229f44f4cc23615945ecbd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051f3aa5492708b02d5800dd5435dc920393ed23541886da0f22c8c235dbb4b3f263c2bd356e469fde68f306f26e61490000000000000000000000000000000017130e2c574d966452da9987c7832fa5f3b6da5d48ae4dfc34f05c084a23efb57c9c6a9bad3945331685fe12efe58a1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c1eac72476c0ab505873440822370908504f7f17cd3b88679eeed0b2599acf8f9ade3c1e509d95e8dbe80d758fe52900000000000000000000000000000000172af8a8f2e04c9c5864d7209d49f2b293d9166d57957823768d35c2114bf1f9ba057820fcb061862cafc2c26bfb1d581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d2a3957a29e0f726d603f944207f62d772a04cf897a41b795691c31c4667ab78ed733c22b7d918fc60b895572183d80000000000000000000000000000000002ae8c95b2e805137727b99418aba57335a3fce46e99079e7c1cd2f46c774e18dc18f7470aa30f8b2ed1b185c950fd901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a751f9a48c6c6c2fb4d6dc03c0d940f13d973a81460677b84b33439d3e484943e9eff6507a3fbc60a90648e7b84dadd00000000000000000000000000000000068dec6ed826fcede3907949346c1e864bab5211fae8349e0a083792036960b1963de89bca1dbf009400d59fce069a151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142d29d0b40d847e91262695dd8d532342e7721ff9c9913843c3e43e5cf7faa13d0f65421ceb327f0024f32aa04fe50f00000000000000000000000000000000180d1d8a3cabca93eda47ae7216984447e215f9106624b17f68e20fba48fe88f36dc5f4d5d8aec1408544fa89474e0211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca0dc24dcf78c0a9903cb58790d7650127f972df175a796ce47cf754517f0dd3e52c247510fdbbd31ca512b1cefa77d0000000000000000000000000000000018c01dabd9fbf047f53d226d97aa54f4878f60733ac5237904e6142243e5e9391385f5a622f06530f9086c15ec3b89d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059e0a3b295890087b19f094430ac4edc6710dc7ded1e4431cd27c77272b6f2678acb72e1f882d7b183b3646eac5181000000000000000000000000000000000173ea65807fc8e52db9293b7499c7edec86240ece1dd152fea87e21360a01f54fe2e2d610eeafaadd8091b9434fa5f3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018ab2ada92f243926c2beca33deca75f69b82fb7f71a34c0f3e3404ecdf3fb3eee7b5fead5985f2c7a56a5f250f88da0000000000000000000000000000000014a2eb6e97fe92433af845604e23b1eafa18ba317599bb0b280ad38aedb1ccb5e0cd5453b3edfbcf2b849ee4528eb3311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007aadebb34cc4d77cc49645107fe8517034fb62c5e1d0f6d34b6737f90e932f357986781b42d6a4563ac8b24dea7d11700000000000000000000000000000000099ad77cb36a7ef863dc64c987eeaf207aa07bf36f23a9ebefece128cf2de308c1e39d41784e170009722bb816b268c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019423a4fd03dcd91bd01bfab813ce8cc583347207d762600a3038b9d2e932e9c5ef0a08d9154be79f4cd93323b41d0fb0000000000000000000000000000000013ef87e3e3d3719ca7220df884828862f154eb20edb9a743306afb84ca2e84596c473e013f5d5a0cb6fd63a1bdba6da71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f26bc4e9a5af09fe36525cee913f2a0ebdaa48312d264800029e1d96649a7728e4e68d7ebf131b59af13f20cd0fbcb60000000000000000000000000000000002098e5f2c82c005b9594a76c239fead57b8300774dda04f972f076176c64535206a5c46a83dc47907e48647e91dd3fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb528dcb0fa0afe9ba57f744f1cf1c3355a581d7193cb9ab571c7a29287015c665ffbd0f644e5e00f063e7e424f6fb40000000000000000000000000000000010b795bbf8782860a6775d7f34ca2a59758e9d68e7127a8ee15dacbb4a701ef92c7096859151c0af8b5b5941fe15ba821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a09736baae46dd67e055cb1e59ed49f5a2d3eeaff0741f6b9572cda18c08af9e816cdc9d283985c0964c41b70ce8f400000000000000000000000000000000195434d7a60e52cef1c6d42f8cd47a49363e2432ef7581ee6e003794374644b0625dbf36814f910b4a2595251756681a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005798ac4278c47d9376480e8fe1f3d22300a1b12b8b8777ee434909dd9040f7a9b7fcd00cb171e441a52614e0c1a45d50000000000000000000000000000000000bcab365ae0c01a7393efb27d013c5d78fe3276be7ca34126a1d109f0e8b006a3e1dc859881aa909fbdac7a16262a181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073953dbe2ddc59c682fafea7bdcce0041051288eceb83f3ed6dde99f478dec897cda2a0dffa27341d11a54ccae6b83600000000000000000000000000000000122735fbd366bd91fec19d737ed25bb7f1c93b96fae37e371eada8c3474dfc05c0711f41054e9fe985788d392acaec421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f5b9c55f62e97ebb4c0a9a2c13db0ee839f3595e8c8a8404357ab2a3a9b4aeef2ae808ee43f1d28fbaf19b9921c6fb000000000000000000000000000000000da39753e36961b767ff7c13a73b5a07f1d8ffb178fb96a0be3f0a5a5b421a338152163c7f84b9cbc03fda9f05fdb3751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5947c9934c8c8a782a17a383eaf0fdcab5acee9669db2d24526701fb8bec0dd2d235d711e1a5cea0b420c4f702b12e000000000000000000000000000000000da6c6eb9f20b0d3bdb3934ed281cb1ec47de1a0852599297a97d25d69ef9fc1434f63cd10677b07aeeeecee08772f1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f570e4e568128ff643b05bffb1682bcffe80b97de3b695f25fb8ef80a0f571a8e642c745fcd9db02ca301b522c3f2f000000000000000000000000000000000092bdccf597e4203542a7c9f062ce9e06deaecfabd7fb8e185b0ed127e862124915d66a1202e638a6d8ae34c4ceca991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000837c07e39157fa53f0f72fa6c0a5a301970a0b68f8977ee6929d6fe2c60adfa4a4f9bd9ba7eb744de8f0c1e878658600000000000000000000000000000000013377b22e1affd67d3e31112eb27ff14b2cc8b30ac0af07633e216e5648dd6465196be99a754259820cbf41198b290461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ca8ffba09abcb7b98080208115aa77ebbf4718fa593efd04d1ad9d1b6fd2dd8183d5be01005eac0745e835fc3c3adb0000000000000000000000000000000019f3ac589b1b5b4464bf7a8db892c65d3aa8c2d9dd554cf6499b85be03890189da67612537c31f16c37b17708cb0b4311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c845eb37d9b6a6470e19c7c2c8c8a080b06d53d33640fe2dc6aa5ad5480f817e92d822f62783946ad1f3735cb73d2d400000000000000000000000000000000052ac51c7ec7d920d6e8654e69e353c28af835d5c0cd74d48847397b1a7c626e27b074a223451d9d5d646207ef9fbcb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c394248512a006df665827276682746c5de1d173af3e6350ccecee7518d8b306dbf86cfc5b6a241d465656d38320550000000000000000000000000000000009b58a441e0b8fa142ea1b350e0997f4307c05fa9b4aed1b2076a65059e1aea7dde4b80846329c6f62975354e74791f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130b18169f6e1b9b35a730e44a1336cdb753ce2bfbf268bbdb11786fc343696c09c60a9abb4b474790979c79267fa304000000000000000000000000000000000158c48234f32f31777de7977ea71e49b8a93c032091f1577d8dbc1167adb453835b664412d442174b1d9de4b9d9582f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001d9db814161221103a7daa7f1e7957e9234e78955adce0169cba91063fab855d0e2996873b3e7c533337aa370e5dd2000000000000000000000000000000000797a60157f43dc6d2e739b1b63c337bf019337e097a5a2cd496c4b38305fd0278fa639cbe40f1458f77770719597a921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100788abc3ac86f54e64a0b8c91a4c16cdbd029332456575cbb48ad07a94b6cccb7e8e97c95bccbe111aad8949b364a20000000000000000000000000000000011b8af6e976ec1a08dad7d44cc3cf62de4b85a1e9c7fdef6994f433b661f52ff8dc5425e0a1ba2706634343812a93e141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001535ca6f5ca62067f97bbd091f2f1b273072a53080bd4d34a0c57357d0e0ffbd31dbe178ea3527bbc60b1db28a43bc7f00000000000000000000000000000000045c44c06f49908a38087ada607194813eb1f6e914f5c0ed2f7f046fdf87794ed94e046a79baa99fb9e50ee645245f0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132601bc08081104d1e3ac1e18315494a37ca85fa671d6d5352389dbdee649ad4bea8e05ddb1ccc5ac9231282092635c0000000000000000000000000000000011022a0683449868c381aca7f5899b932b6ba01f6a45f65b53e04eeccf013142a86f120fd5adb25ee691843b2686a9011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c65042b5e92e816fdc8f50bfc2d33501c319f73e2b9183b796d5bdeb519080d3b103a320868678c0145018aaca8de6b00000000000000000000000000000000020e22abf8e3e18bee6fdfbdc130beedc5a45fe69bf1c70e2028df0580857fffeb0bbb3ea7328dcc7a428c08542f24041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b304d752ecb9a6a5b79eacb25cb684fc05192276e5f36900f0559475523f0eeda27a3251b498f0118a9842eb46b27d00000000000000000000000000000000114b65d422f2fd77ae9913f194dab90e024fbddcccf4f19c911c1d67135ac542710770d08ce2366f7983502940e071f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003fe122b11d0f5ac0b4c609998bafae12d701849eb7d8899cb9cd6059c0955e1c5eec12cff77889d88c2c219932275db00000000000000000000000000000000072480f02a37821b59abd3d07297dd98598593b9704a02f0d65db4404dcf45fc0716b323d454e1ccc0bcc97362f29d861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053a3a2e0467130acc0d78effd5ef299cac38d9263594cb539a9b567e4535a5e0bf54a9a3f67ed731b47d5eba3312d6a00000000000000000000000000000000142e232037d5f0c658a25627967f4d77c957b2388fe289e5324728657adcf267dd2b6c1b4c8dbba6815662cb17e4e9ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003987ae4c072ec0ccbd50884d7fefe0b0e67302c2bbabd0882deb5cc89a15d31be37d1428b2094d52121542cf21264cc0000000000000000000000000000000000e89a160a6ff6271eb530e4a408d3bd910f79d34c520546d43c20ca2a1761069d55ba876901becf355f42976c97658a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000169af034cf6f516f76380d296069d6b05a07175e86e9c91fa6a4a48925cc41f2d5983fb088ba7274431c06251babf31d0000000000000000000000000000000014a4ff21fba7d28d32b1c3ddc6859695e4d09e8402e8feb8245a1ea5a59cb837b93d550113f80543dec9d3c1e5831d101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050c44599bd0c9a0518fecc1ea22738fe2819f1303c483984ebe0a855936c1965ad64aeb5c687d91cd51b1fd4592ecc30000000000000000000000000000000000020d23d8742ba39c96eb91ac0b5043a19abbda297b9decd29881d12864554a2586419dd3935c4559de0ab7f73ecd441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014947b554cd6547338abf2207e63f763190606e07a14e6acc841ab7ca1cb2ed8a0533fcd20dd9961eec00daf1a54597700000000000000000000000000000000192df8e21513a584b5620e3192e27d798111a786c73e236582ab29cee644d033feffbcfce2b46687eb6bdee271e92bf01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171a8fbfc4fd210b912d0948fe93cc5fc2cfa46f5eb014c0363f797b510419c070427691d1e943e0e4fd90edae759dda000000000000000000000000000000001775c5cfbeb60d20dfa0f59ce29ee5b2c97e9804d27d2ec917cd7662f7d9c3df6235d80bf51915700e07b7a7d45982f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4859318283d6ba2763bd2cd168f4a0dac50c6efbf3c127a56dd82a49a54802382758cf1c30026ec1e54d4b520d84ab000000000000000000000000000000000cd253e743b1dcbbc9520da24d0cba2fed238b789984fab90a9712ed3233ddc5010417d4988c54ef2f2a02bfae9ac4021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000258f2d15a4dcb712639479ec6252a78966674dd21a0d08360e6fd1a3122d090b84f3622e8a50ea68da5aa39865c7aec0000000000000000000000000000000001c8bc79a630d2795fd02c145094540df1026e82a59388181026d890abb46e5a9469c5fc3c7a9f948078bca5f22c62711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017712b6b2ff52c1f37b2eac10a1f10c3eb1de522e172e909480b7502f0b57258d4600fe3d149a4a14243ba72f04a9a4d0000000000000000000000000000000007b9e60073c0cbf28c5bddc9d1baecfbb0074d88163cf09daba89f7960af91427e40d1b22de74c9934a7228bba9b38911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001545b79e420335c44d37852c6660208bda856c6060ae7f17057d16c7570057c73c3e74a433d8f6d73badb4e2519d9938000000000000000000000000000000000ce6dd53e06f253e36b962e0bae79960a0b8db05fca83a262d58eaa21306d5a373915bfa2f1c3b26185c1760020265a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123983e746e8f131c62416fe3baa75d811d84c42dae0c2fbb981112892620d88529c75cba693450e27f9fc1058bae5920000000000000000000000000000000019c02a83862ae62b790214c220b2f23114c44968c98296214a20241b89ba01acdb04f5627f51fe649727723a25ed9f351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000040a2bfb0f3bfd7e44a41d6c19c1063d47e3c0c088ddbbcb580ef75834d8e09f84082f8af25683d08ada377122ba3020000000000000000000000000000000015873b3e3090eb1f5ef68e25c53e20c09797963025fbecfc9058946b46ad9bf479b7a77e8d833022ccab797631726e2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a572608e685bc3baa0068273293a7402f215d6fb1c38d8ea81bc99ff3a2041e32f38ea997cf9c16033e035a96543978000000000000000000000000000000000104d12c941f26a175d4ac36fdc39ed058a89025294e98d86ebdc39564f9da0dea8735789e723d4878a813d2f2c686651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ce04f999be665bd91b5ca7615949f9c9541af8bfecd17f44dfe1d2341fde5574f23d0f391455ff2968a4d443ec995f0000000000000000000000000000000014ac55dc41d33d7d739ef78225f5b770ccd2a704771f22291942208dfa306ab6145b460021bfd50653c772601902a0561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a3d12ffaa5e0080c74d8832acee016d7fe1a3f36f9e6c5402d69cede785f795d5b9594f10630876bfc680086ba1bb6000000000000000000000000000000000544460af30e2d06b4ff3189c4f25f88fbda57e63f5101b5658726e592516ea22a7db66a42ec0aa734e1dedd8f3d2aef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5c8461d4aa30d897c2f916e5691c52a07f35d65f465d00361da72dbcabe9a17190a4b782c4529619193a272c434ef4000000000000000000000000000000000ee2a2315e4b1b110f6ed63f83bf9dc94052e3411db87231dafaf438d8ca66f391a783d79ec7307f249ea8c006dc0ee31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000169f41b3d39285beccbf89aa2fcaa7bd7644fb121396345622904d2202b68d9af6aa12a164d3abb40b77561a9d306b81000000000000000000000000000000001039b9ebc1099b923451a0a5602b0490121ddf9c9710fe40a526f65faf81badf306784fa8a9f8db4c47a6384e34cc5561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001309f591eb1ddda7779fcc9ed31bb27fa97bf606a51091b349586625bf18f4fb767b2cffb5177012110be6d38b3556c80000000000000000000000000000000015db62001cf4d8689d991d1b1e78bd4e4d948eb0b9f3b7d7b5b829467cb9faa9b3770180aaaf9183ea2365dbdcbf27471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5a4e188e69c9bceb3d4a9a4f4f83bf83ac7b9ec089ba53026db2e8ded246a006f10694a21e70c39f9aff1b4c08cb54000000000000000000000000000000000f1ef3ca42a2d0f1bca9abcc5366040650149745870e5e23b78c598c0d3e2ff3c69d808169e72bb3010bb41664702e891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099a5ec5b44b4a039b9749c6d2867c9d6a071a7f5e9267294d3bdc7a2992444a29312a54b8c1b2852057935b4707b78d000000000000000000000000000000001733cc053b1a977200bf8f8a122a814f62e7a737be5f90db07c7decaba7dc6ea4eeeaeafb682755a503a452285fbc1b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b65c7a7258d0a9d42f914e2354ef6d2118a697ddeb32a0abe88247850b55b71690e6f7df8081b1ccd464ce341d54c200000000000000000000000000000000181f47cd05617e40ed26995deb4ee4d7afb464b9e509a7e3e7969d17a4c4f0f1f2be81471b0067f764b63134019174321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005dedba233dd5314bb6a5842929c0fa0c50bcb2619ccdb24d81f943e9fee0a31f21fad3f143234dc075aaf9aa0c46490000000000000000000000000000000001186ced9649aedacb91dfc479a78ae37651117aee96acc7794395c285653b14b897584d41672ec494922b8f0272173031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012bd746de84a779815d28df3454a3f8ae86304b57f527c73709311edcae8a1bc49930953d1e33393b048b21f9c58d178000000000000000000000000000000000b3c42c7cce7d0f64bd6b1468548634ecbe30e108c810857143346cfd2c7f3087ac49a709468a600edf6f9fbdd600d4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001123c0a321ee41fb612d725243b62d9f895c5243b7b8f5af5fa9664d79a374f5018b1397507368a2e91f92fe1151c87d000000000000000000000000000000000644cef7939efcfa782abba8a6a7744e59095cbd657fea0b94a6a50b3f0b93d17a341b7609675e3e45e2affb08888ce31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016cbe501c93bc5b65adcf4f27d5d9bd4148c27666f17e785295eb8c346dd4e48a7c677659751c6fef04d76f6d24c89970000000000000000000000000000000001f274a8e6e95e52759fcb89376c2aa9c720984b2cf0c501b0636025f814cc52ae6ca0c1fb2faa2364cab732c49c3eb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000146f93701cc9419dcdacb86a5a66880f724e53af69c28e45218e0969d1add8faa46025e2009ceb6482c1dac37b249fe10000000000000000000000000000000006e39c2576aa013b7b108e086be1e860bc7675de6be454bc22c2106c439dd52992a7c06a041ccbcbe0abbcca35b8d0051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b44d67e52b901733866038e4a4df2e17d691f67bebaedca0259bdb2b3c44d5a5c75c5dd309b8af49b597b246c5cd62000000000000000000000000000000001117f136956f3aa97997c1f773d098af2234e838328db138d8150dbd3609294580cd9fd097913cd28dc3b3cee664f4691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019aff41cac3405d006e43cd0a0ab4cb861ebcc5836083bbe657e411add94824c726c9769307025676635fba220722a0a0000000000000000000000000000000012ed758472ea003c5e07e2c064b5a009215fb0280d2467db05e33d7bb28c98ab9e565191ab0ad3dceb54be08c7199fea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a3ba2ce76af954f2f9d5218f9ac2b9d4933bee3e303225b84e408e89c7c5920efa2a7fe2be82b6adc29b14f425ee4d000000000000000000000000000000000cce0c60fa0c57cc9c6b8586b018402ed7e0beae1654470092d7aa8c023c657298f68b784c1a294d0cf1e6d84351c1441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb0de7dd2cd1cf1f27351cc04f707b1fcaa5159b01f507e19ea425cb18c09dc343de44aa0fac400049d3077b1338a320000000000000000000000000000000002bd14688804912462655b2ba970f481d043cc357594eb44f05f0390306d4c9f0c82347383208a71a977e696cb2730201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0a07cc3229d2ba16a73bceab432fbfda17ce3c526782b2057ce650c82e71c15c5932ce87a7b92688f39daded4c77d700000000000000000000000000000000050a1756ce9478e7d80139a09ac041591a5663a3874a9ff8d992d6b49edbb0ce475df923eab24d19b56e4a75878dd92b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d74df3789c32f32decc8c68b94cc9c83346b31b951466c1b7d42ff4be45c7a76d5da33ccf157769406c4cc32dee6ab0000000000000000000000000000000009f25cf34570239097cfa720f8101168e58637ce0334b9a465bab906dffb96e7544a05ede469c4d3368d07d3e811ccdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002be1d513755de9e26f70e52f5f5dbb82261f6ad430307932b586f3951597427b8a2972ee28ed4d00216d95b1b59d2b000000000000000000000000000000000291deffc942625f839f2b4306f682aea47c997e491370a2406eb2f13cbebe65efec19af3ff606ebc6c3d7f465cec9511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030a38daddeff2e822a39d66be80063d86442be0360b203dc5dba189cdfe731b7476db335a1e2351932b2dda77256a08000000000000000000000000000000001380f6bc349145f90229aff6f5c7ca0afa72662d37058ddaf36ad5066b961fe43923ac6e8c8e29b0a0fede5a833a78fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186b7559098a8832f57d2471f64d07ea0fc5f43e5957809ab76dbacec9d81ba37ae59b54eaac9ddc7c20fa866dd4b0e6000000000000000000000000000000000caf4a4e9a77528af9781990efd1c554bb7587073f1446e09800bda26f49932d93b042200f93b5ed3c59dbe9153120f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001495f4ed84240f37f3c6924950846f40f8a94ab2858f27b7f14bb79b5b55d37f27e3db9069a5fd69d146086cd1738502000000000000000000000000000000000c2a450dae6acf62d965c2281adb7360787c12304c83df50079a449ec42d945ee37ded1d55e0c325c3059a8861ae6f8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058f004d93ecfa600e871b0e02e3b6b9f144fc955ab8b8f539d647817de3b8b1520effd22b734c8d05514578eebfdab800000000000000000000000000000000133678f22607bf79ef764e059fa4d22538ba0a9b2e17c40014102bb2c636645e2963164575fa928234cd2ef07c522c9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b317c96dcca84230d676b8608bbde7f9ebbfd505f82b150138278b9326bcc9566b17b89f2b8d95decb39c2c7c65dffa000000000000000000000000000000001124165dfc607df45515d41af9d80f28c081b1c5530b3806afa03f12d43ab1c4b958d9e76c2e31e4b074f82782add1fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014ba91cb74e862a75d94f1096ca68309f475189ab4eec941843e465a1e7c8afccfe91a4e710c7d0eac906ffd51cd13900000000000000000000000000000000090a6f22f56e1cb8d23f70506bb42538009a03e6c51cd087059524e440f480d6adc48200c95e1970a2ec6b28f434d82d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069dc7c55387c795a802da58174eca9212e28b9f635dbd9dd40e6872f4e14f009c8a3c6c8fa3095403f50f45eda33ef9000000000000000000000000000000001637470558b3f448d742363454e3ea9aa816ef9070e47ec34e29c065da87309db31e1ada1afd2826efcb72d241f99b111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000334640b27ceacb7f39ad6f2a9563b36578e428ec66722da9b68ede088259563c83209a979cd6ca27b6064368b4c3b7300000000000000000000000000000000160911767d155b4be6adcd4ccac95d179a11a57a5c502d15b0ce47db78b36ba2b2496e36a1f5b9090a1aab8803365e981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145dd43cb3fd86cc6a972c7622260db52fae18560090b19a4488de57e3e1e48516df4bf5b6d9ff2acafd21a7574869700000000000000000000000000000000011fa08dc6e569b4cff923996f9d5791535de7969a71c6e96c33c1d1cd16ee8d5a93e27be604fd05a903467f82cefe2241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f9ea2e119a7b76b0a0f7a5a12182118ced171213423fdec86c0481eeb96eab14a38170541804347b5e9d5c601e27b900000000000000000000000000000000038e2a21e5e969ee39eb604267c551208821e562861af45f518e38537ae36126d4ab1eebbbd9b8aebc7fdf3e13a5a3d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bc72f736b9fb8264505ba322b9580385955e2d3b29c7f4e1e66438ed4d78832dbdf6c08e9b99456ff6483f51fe349f0000000000000000000000000000000016be56b1b622d502c4601c70866ce96dbb011c56d59545270d31002950f296bc42e9657c2bdcca36d5e32f6606ac0c1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b430c3990f64fc049b99505f9711976af7665329e46a89a5db107b805e1f9156c2fefc471925fa1f8a2d4ef2d53994f0000000000000000000000000000000009c3c589fd456d56f55511f3fbec6af1b070afd7cafa7a27415a723607852954103c0c4b8f25f6dd5ec09ed1b580729a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bd706c6cec82fc45319f454f158fdc42d8df01ddc79d245daa7545a9c6aa687a6410ab53e26b69b0e9d98b23021ad60000000000000000000000000000000005bdb89cf1cc55f51088eb9a573863f6b6c0d8fbdeb4902e55fd001b157dc6dc793b95211912b04fe2dfda04a03699361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b766c298b5b1c1c31acff294e1b73240e101045f82da8a353a0d2d19aee9f2019ae2b3127177db9ceeab6dfb0235ab0000000000000000000000000000000013fe14aed2f43634ea56e47e6766e1f70176b7ef048463280b5d6472c1ea61ac24e12fd40edbc46d1baa0aa9e520d2431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004fdc3bacfe962f6abab42cfa5c5b46025b04ab144143788bb545ea6f41b0025bb7238d7ab1380cc73a42bf46979a816000000000000000000000000000000000d2f4c5593e4ffc6bf38942500ebf182a757b243fe8a68575ad4c83866cd0b27eaf5bf13c22299d2cc50005c0d3a41031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c09431e6bb6e3ff17ab8562bdc375f1fcad232006c4648dd2676183cffa5bad5eaa3bf44f0df036d8e1990f0610c6c0000000000000000000000000000000009e1ffc59b64de9f1313b842d9778fc89917c2cd2e03f8c3532a558f9f4ffad7de532ef91c9ffed39fb16a31238880a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009460bdce66b93c899f21cac851ae3ba055f4b5c2611a2c837df9da8b382adadfaca8e13982e4eccea663e74f7a7c5f6000000000000000000000000000000001117aa9a960b7a7ebe773f1d52b895c9428d23d55bef4afef53a9cae10c851999436ce812bbed28a94ebd0ef78672a561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012aadfb9875a81a8e98a3bb9fed98cf1d353c3a53f159bba8caf5bde402a4874f94bb9a3e53a4d39b83860e46a470dd30000000000000000000000000000000006d1d36ef517dc15596b5eeb39390a8389d931c35d0a611235897855a56e3c74d3afceac69f799bd702bdb85e62701c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001242686bbcd118b4a980faddd057d6310c341243bc050dd9d028d7b18607f74e0390e209c58e1f1d087011a4283fed97000000000000000000000000000000000e1a057f838aed63ca2d0f859c784ed93737d67224ee1dfac52bf6181f2d89f77e030773a62341620b192716b4d1a1591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bca58037997e802aaeac3c83ba8a45dfee792a4c13339bee768ef9625dfd8b90aaf3f76fa70637714d6ec253f53f6d0000000000000000000000000000000008a3b27c350e478eace79276604e38ffc2d2e39238870ef47e09375c4d8506c78017ccae65c63ee3005d3464e58a79091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000816d97f86ca02fdc08ca87f1627f2c552801cf9bd5d6284e5b0a5a4662d1992026fe430ee7173f4455f80705dec2e11000000000000000000000000000000000fba960e0fe33402697011d6c5db6ed7391db32e59a16eaa3d7a7bfc15f1c5a6eafa5808de10e845b93c2d83f117a5ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ac03a9555897361f01a2b1183d13ba62d01581c9d90dcd8f5d1144947c231ee270cc8c9ff05d049bc60f00a569da6100000000000000000000000000000000032a280182b7f678850f1f249198dd2bc52f9f4e708155d1024005ebe4d16f0f92017d24f44ef87d5cd6c8857cd52e441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6e1db8322876a1061f8b627975ccfc06b869772b01cae1ed152d9140946d9fb6b7dc9366daa054bfd621b0d792f6d200000000000000000000000000000000193dcd1f35df631e6d5328b4835747e4f10b26d8f95aa896fbb762980a40ccb3407be9be85e04976c50aab0eef8b8eaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015223b77f13593ed99a560a4ecf4ce2e96e451a379dee462211d982498fa22e2878fc6d624583a694ac00db4340c12ab0000000000000000000000000000000014c582e2158fe485a533bd3f95c3f060ad70b8dd956383c84971e7c0f4a5d5a57678bdc735d1ef8d8df8194a69533d191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dfe96b343e367a6bd0180f7459eaecc5402da1268f8ccdc7f89ac6d3c492f4e386068a73e4d67be06956e8a3a988ddb000000000000000000000000000000000f70f51cf54d25d792e200357ab8ca6b38493820252f540249afb4974c4d952aaffdd3e3d3cbcd0c44b82b1320078a0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cd91139278f06edb6a0ed8306fe77f5aad91af559491f585d9862588351120d75082e498a954b6343fb9bb857df3f70000000000000000000000000000000019f6d2ba3ba097c117698a349c33edcfb131ae7067aa1c0f299642e3f7eab42265f2e8a4f8dc09e4840c82834226cd731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006451bf0cbe68a40a02447d126d4bfcfd12121fad1f70da60c74b89f051268d40169697ef6244fb6d1e6c68bac7ce5cd00000000000000000000000000000000056d0be19c73b8d85c57120bb616f518abc2ff388fe748201146157bd420028ea6d83c2400ffffa7f3091e55dc577cfc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da1ee24cb3aee7977d34f5c9d7c8ff0cd9f6858ad6cbba73cef1da7bd6e44205e39811ac1869895f48b25e5fd691dc000000000000000000000000000000000193e25e186229fd82e1c9f90cd6e3fbf66b5ce365b9cc86e9b9a6df10c8365b0b80660b6c2dc285f2d9aeee86f4cde031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d9c6591a6b05cbe2cb01c4b137cc56017b7506c8449b909ba4a7d6a5da39502e059f36f48bfaf3882102078b72cabb000000000000000000000000000000000512be90a1ddfb6896ed02baea6a21b14c96b6bafd029d4d4b353548c4b62b16db9c4331bd4fd4b943b04a1457b63fbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000641ea2ac241b7c3899db22560c267a409f7ab591cc41f9aed910f9dc3118e90ddad82e6cec8970235227070e35f0afc0000000000000000000000000000000010e623b9d900e8f696f6d2a2f7883ab02ab227edeac7be8f741a8bfe07eb0b0d5731e974ed86fcea0c2bdbf82472415c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044eac7f50ab7c4124977d18ad487f1dee7779bc5c6858a66aa451bdd83dc1ee23758ade3eab2c236caffdc5e5cb8ea8000000000000000000000000000000000c2b4a4964cee0973deaaa9bd38c70096e3756b4afab5a64bb00109fd86f3d4382831456cf9c169b1a8c9da769dddf4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010dccd3bdfccd782f99df445c3395bd3f420249d6074c83a098c49e978bed4f05ae9758f9aacf966701d7b0fbc065939000000000000000000000000000000001759db1e40e54b654b270b6cd5ef2d92749e12fda43667d78db17b4b9bd8968bc78771656c9101cf7ea87f34bff73b621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001917c430a8d61fb3c0cc1a0915c9652d733171bddf4f13cd87a109b192d7b671a9d6562b4a9a779a2a36bb3b0a24e4bd0000000000000000000000000000000011ba74f7ab7861e2bb4a25c2c5b86c26670648dc9d665eb6c697c3f0f5acd13cb951aadb52bc37f49708a46407385c731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3fc9586354c14cb338465ea2334e7eddf404fbe810fe1a8ce10fc0b7ba0a746527b4d4f3d796af995e46d0236391330000000000000000000000000000000018d168a3b9ca279b9929a3e431776acb119144418319d7d2367f6b44e5b94cb7ff640a45da61d64e0c9eacf4f544e9401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001571cd3eb9563be1ed5f4da12d182a1ec284a1f5afc08c615c5716c939e831dfddcaa47dab7c43262b671a8cc7d7728e000000000000000000000000000000001381dd080f0f39e6ffa37ce5568aa269efbd2f8c9ac02c8c3e98f5df21e728a67521a3a4d730ae96c5ff9dca0f8dd3b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000761236f004ca82fc189ca57406894a83f663c4ee1172318e9716bf3897d5299e2678b39a62d5f8718c4d8d92bdaef0d000000000000000000000000000000000190f03b4a1210a7f3a4486138c85f8b04f7d7e394173acf4115d7859675505611b055de029c0462fb0faaa590ae33231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5cc0d3493bd4746057bbb071ffd65613865fa918271fb95e33792e2d107b45abaa455624c85bbe97d20f810f737d46000000000000000000000000000000000a8ff632fad7388e42eb77768ce1c3730182204121505eb55941ff9ef99abd6e5749412488c536ea5fa5beaf29c7bbeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047c31805bf51c1c1cedd32ed127e6d4db09d7e36ffe8275a16028e047e2a45583047d7c0bdd93f6db937d7b88ebd69f000000000000000000000000000000000a117b6a4d19103d761e3698589695cf4d887cc99df52f4a4e168c72483d1810642a4f7f97602c286c9e9b9ca5402d7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c1b84cd981f7fc4039d1f79a6de0bdb1a12b7ef4228adbecce80437d64a558e1d67328d5ee230bd15ec59b1fc8c71c000000000000000000000000000000000a27d65a50887a76c51459dc6b8505ebbf31b107dea0df9769eaa379ac6fa36a9f145bc53000c6ab93bf9367421e3aad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dcd6f86494811936f04672bc836665d647cf5c950aed50ffa7ac96fda78777954cbca957c5a0f5352355d4c234dc7f0000000000000000000000000000000007a128a0f8283d250d12031aa2bdfd9291bb6956bb86a96e2483f866e065446d3cf3aca59fe2f3baee3202f5c538ad721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013093dc6037e82f03f8b9e40f18005ca9351896c97bc536d1ef04c24fa80a5a826e3faa7298a5aaab5bf451f93522a510000000000000000000000000000000015f44e7b2a5e484a3328fb0efc9b1c884505e8dacd22e025be898041196bec28f8d06d727981ac9bcdb062f92063bbef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f595d13ae920b25e61cdbada5d59b70ec116616e9767e7d9f900b1bf0f9d770c68fb32e314ff40d4c200ec8b13e2cf000000000000000000000000000000000d0617ba8f02ba2d34b5bc7485a9722a241eb3ffb0d94be22609355c6f91d646952e8dc3b63fc44f87cdf3b40cf47fe71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001690c65ee4cc146eb25840ebb0f31aa074cf6deb582618d20f235de27d60cdbcf4ac1942e6c7ce6d69ad4ed28c8da63b00000000000000000000000000000000060109dfc9f340a3b8081e42b2acdaec27c981b4f3b555df9e12e9fa5de2aa9c53f5f72a64c9244de0c2958d99b4698f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f940d38f06d8019db6f403aa9b6305f262209e65de106e7ae15a9ba7256ec70593dd7746be248d3ad4bc4d77ab4df7b000000000000000000000000000000000b028f3807032dc37788a19e4bf6de8d90df899467af06a6bdc363a5918c78e3846422dafc4d56e692d4e3c1dbec8aa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4ec361ce4727321435db1db60b15f22815a867701d6ee270575ccb0c299abd5dae0dcb6cae3e18fccb1e0930acf417000000000000000000000000000000000d27b8174707ecc37f40b07eac828668878655971e20f1e4a3c427e1d379e22caab6449af4e26f01c6997e9f42f000c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014991150fb8306d94717102de8d30f76a1c074898a3d9da8df8ca8489902635b97ace62bacaf4bd1092be2d7781b1eac00000000000000000000000000000000070acd2dcec064f5b5c72dc1b0f6c1bf7a964106de0d292c2efd44a7d32152fb064e01e3c91f8d60920b9d9889a4800d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116a924dd6bbaee3b26f1c3b16335ff40f948fc9c1fad12a35ff437f2cf5e68ca7ccdc975c6f953cb4d0a9274410db58000000000000000000000000000000000fce9dc655e2463eb9b1868872e210d91b08bfdd5372cf5462a26f5a83e2677787ac9e2aef54885163c64407e3ea727e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000509c0b1ae7ba8f4cc336b40fb75bdbf6c4a454f3439f2d40e81589c614e7d3324314d25c1d7d1351eb2892c4a3d11a300000000000000000000000000000000149ec72c38900ce863e339a5ed71364b00c96217f4369e0de623f1f291e1d2b8144e160642dd37184daee8afeba58cd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5bceb1e90927091326dc60aa97f33b8abb59aebc0539a001ccd4d99b738bb483b7373514d07cba9cb05dcecdc04131000000000000000000000000000000000e47917b5ccfbcc31122c022b176d72e30793ad4b6da694b61f2d91339c76e37f0893e90a83b80afe6fcac61eebe11381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000789d54c3b41a7af487d63e53c69ecfde20243332af7af1cd87ad02c758c0848af8644dae5cea1cc269ef31ee576caec0000000000000000000000000000000016bae18a053de086f1ea73a5bbbb4e6e4a8e59d8aa7aba8f9f4fa1f5f5ab9c666387fd9ba61e6a25ead44d9d5b68ffbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190a8eedd9b92ff81438e2a72198944b98a167335044b84bd7dfd1fd38fb958fd7d045baba2d09daf9701ef11ae48a6c000000000000000000000000000000001954d59bb07d501850c59c0e0d946e72930958b13a4b7f7fb322e22bd53e0a3fb0644bf5bfcd66bb2d809db465c370c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001a008824091f1229c1ecc087e73f68e4c6576675e86e2afe283097b38d93b8521a06c5c829c63c358a2a0c1d769e98f200000000000000000000000000000000173c000524cde4e43734757d405e2f22c79e909e14fa4c719c6e859c0b40d463cf074e0da3e1880f023ac034713f0e9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fdf243d85a195df663e7322d9d135f37f59ae5f3f7af112a11d05629d8d65ed6b772d77d8ce546eade6c4bd125147600000000000000000000000000000000116a4162238cbabdd34690689ea9b399429e9aecc9dd59488e53f86b9c0fea97d397d6ad2e631e90644fba9fac4099531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f5a2aa5d92b42ded42023c47060279fdf8ef79df84c57699386bceb38af360ab34969efc7b9bc4af14ad22431a8be3000000000000000000000000000000000a0b05301a23621505acc5ef06bcb7203dab95d0e0d6c7cbc3e1d399f536971b446feb25505d3e75ab8737b7a8bf98541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011354cc92d4f7fd7de00a85d6eb4653f33c81e081a6ef54e01f34c3880c11c7c1985782ad0532479d98f8dcfb037e5c90000000000000000000000000000000019619487ac29c5920f83db694b171257f6cc41390c3459bc977efe5e3fe74fa08de74a524824dad334ad58f2fd7c18cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004daf2b6f83593a45fd4838d26017292e36023a1ac8c7036e8fdea3e99357a07aa2da19543acb0496ade188a25adec72000000000000000000000000000000000968158572c40e51d91094f14629b3a4e02431c85538a9fedd0e08d948dbaeeb1941bc68d97699b98eb6ea6635f581431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002dd4457b87612ecb6a205a49f0be84d4fbf75fdb4968816d8c1c92b19fd49ff7bbcbfe73ac499f7b602b0a8925a96a80000000000000000000000000000000007042123ae8708a8499fd18d6fa92ca672b41bd372e550b820428820db74b21985322ad8f1d3d36536cdb0975cc3447b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bb0289b35eddfe50a2678af93fb33a0248ac2ca00406e9f295310e5d036c582127e3549d504e1cf151853895a60e700000000000000000000000000000000002ffdb08dea599a112784e333799d618a514d18bfb95657f4d97c23f5d17b4d8a30a97a25a59c1a37f7f77d3995e99751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133e4a31151bee736fdb3d0172f34a3084b4cc055ae96aa25dd910bde976d8d53ee36e34fce2034faaa7659d974e80c1000000000000000000000000000000001794089cef87d43c56262f4f5b4929b1ecd5f3a6116f1a46d7630ec2146bf2721d9c39361418b7fbaf51321de53b241b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002143ac4d66382c831dd0bde5c8d620e728cbb92cc2b02611f69f0ea895f44fecea96c599da45d2a9a264d756719030c00000000000000000000000000000000089a7476bfa2dcd26e29d3ceebe3b7411ae8205e6df1171b8cae1553d83ff09f1fbf82db5b08ca64e9c0e2b5acca2cb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014dd8b8f3be4451b3d371d7d5d663e950741deaeb6488e0e1912b983dcf2938f61cafd05e0d135df0af23cd074264f5d0000000000000000000000000000000016d8f1df9cd54fc20486557a2bfc59b0eb0b89a4e24ff2aa4016dd1eb07e9430ce93b3b17cee24c4db3456c22875e0071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d81b20a63cc524bd3c93cb7dfa6d8f666871103f5999693c966da8f53784f2b05e51344dc2b5aec2f226660382e4376000000000000000000000000000000000267a7d07c557c24e218a006f271dace8259acf4adf7c965ba510fa2714c68206d0bb6d082525a32d8aa820dfabb8bc61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3d5d505b8ddb8f6b6e9ddb39c5e7feda63ce1691ad47c22b9acc4895272f0b5a46d39d18bd8020303eb1882e671a3f0000000000000000000000000000000001950e22788144247a8a2e2fdd2dc4d22e529f5dd165afdd9a80e84ffaf602a88489a9cf141227b91b7df5b92b59b9961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010055455028fd3b5674a784e874583198ae38cd1a75d93175644d429ef7b940f5e20e9b0acb36df8d2714bb9627b363300000000000000000000000000000000097b3c25bea41b9325c6b4b9bf5340c804571108da83bd1e0ad04621accd40b87d2ef2c5591dcd7daa3da6bcdf5c45701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af8758d4b9518c9a8e8a1746e0f2a7d2b21fd9e3fb4495b4d112c251e76e882d94761c7e6fb055bbf1ef957b68348c00000000000000000000000000000000002f4d5b89da6542acd368057e6e1c9885215a73604fe7245f02e62cc151976ccc35038ef08ef97ef9ea5647ee38f8f1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e15ec549b59ff5961fd1ee23b8ffe533e8f6e8382e2dd84b57228405e19ae3bc94db0abaaaef62aaa2475be46c06be0000000000000000000000000000000004b3a39397bc04bcd5f114fa17581fd714409118c5b74a1f5ea45b576afad2bd50a9524777945605a72ec41a549380341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a87b0cc4f9059a5b548457b216907982de8ea939d79a83b2445ea45f0c6a2853e1443b78d0e7a2ed8e111ec33e4db1900000000000000000000000000000000033d7c045a5332712dfb33cbaa1a57862521f94af5a84349ddf15f2cabb8eb040226df2ee86587a6b5a17fe4a204ddcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001213bc3358e2cadbeed872e1783c5786fe80ded92f12753e376131bd3961874f83c18aa8ebf1daf89dc6854ac09698ff000000000000000000000000000000000775ece57afd032b36cf5d3e9ebee0121b3a667927a8230cd109b4d8c83e84a67ae09de9d17467656220ecaa44c66b091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000394d17090718ba504f748071688ea9c99a4c6b4f37b79bcd7dc329592f1d8b492c0e35e3e660d5c30231d6f9c0f62b4000000000000000000000000000000000ca6b54ab44d758fc8a0bfdd57d13717788f9b0672b5e517fcfb2d220da572ff706524b7d247f15345936a223a5d61c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c75f767841c115f5f91f989afbf3851a7983c9228c0d0c22e3321825cb9ada3de1e3effcfb8f2479bf07530ab53b257000000000000000000000000000000000a96644036b2b81bdf8e8cf447df975440ee6421fd13da85e49546c08d9eeabad391621b9995d059f6ff0b7508b61e831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d500cbd528194af718a06c86281bc02ad8456182db78be7073153112df532ea64321a6182a907c6e0720ade5769dd900000000000000000000000000000000057b169b3bca558b891662aa7c28741eee4490447f38dc4c4577ed785a952410258b420e895d3ca116e4efa16b8d080e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065ace26804907d15d38a507b272f15fffe9fa8dc5d7cc1cf3142f93f2d0c8d1bc3a5bd144e0860ceefbc96a33c00f210000000000000000000000000000000011adb2e8c6a4ea8043bc1c4778a3572b63f77de43dc9218a4a9de370cc82af04086aeda0347685cbfa328f9d07d8806c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001507ace73342a2da65f092540bef86f5402633c874b35fc91dde21eb7338bc88aaad1ed82498e5ece65fe9f56323ed43000000000000000000000000000000000c6419b62dd59bdb5a2755704b22dff1249838c02cde5e546a14cfd3b7804efa9031d6c452e3d376032bcfb268c547861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000477b1e258c964d7b9994bfd3f220777641d54d18b1c0643f924aa895a7fa46ca54ff1f1b54d2d6f1ac85448a1f1e65b00000000000000000000000000000000125edbc8bffb1b884b0397138354bd87e621c4825caef64992c4637d8869156f71598ef4682b897d59445891663d2ba61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ca65c93e679d954e4ad8e71ae1963db5793dab99f4391a0c4c4f3e91f96a7ba7d258b682f38a322e1ec4eecbce5e8400000000000000000000000000000000161bb3e53d2f40ae1722446802c684b1d76de2823f146503633f99028b1cacb136ac08da25f5abaf02b65294db41a2061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c8cfb68f37f2130774e8eedfdfe0eab62915d37781ac69ad61af77130772df3337b0364081d8834285db6f7dffbef10000000000000000000000000000000013d53cb14cbd4f6961fe6e72889bd547dc004bcf8f35d7e0855daf58599ebee9c7f858045c83f705fc7d03a8494239f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001609400fbdff7e752e83b75e309f0d0a30c106d7ff4f39cdc88998be3b4c39687a05923d386927687b7ef7f3758a7b4e00000000000000000000000000000000054737b20d664a524f47917188427a53d53adc1a71d98baa71f2d94b735ebc0ad1d9a85f036a2c50c3c5b912cc253e4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4b8e8372cfddf6b0ea29befb93538da01430e3f0b669388b8c51e7298692b2b0823cdaae3568978d507290b0f5e5c8000000000000000000000000000000000c75f72e65cdf40d8aa1a9d3814a04fde3934e941d8e0ef21a055a5442f9954122dce00b0dc6c5848ecd3097b2ed6a6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055fbdd3050b150a8cb5960af091c4dd2be8ee913ad98592795ea9136f055a9fd5da7b2ad7cd46b85d20adb5dce4aca80000000000000000000000000000000011551e409b3eeb1de4e90f864e0a74679c8a6fa13b6525d55a290fc72673b013eed23867be9ba2a9b4b4020c8c3c68561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002690104eae5966a229f57acf3553763004a5091a7ac2d0bfc2be4de3651442a3a110a1372b5fbe036370d45bc2f6cdf000000000000000000000000000000001637a90adf9fe4f43397aab004ec584b2b9dedf41412e4a0b1970e4e1d125653384f1cc4a4c6681076b57acfa1d58d311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c545e621d2f23032a1b64dc393a59cbd05cb4ff1b67f47d6eec5f81e589baa4067042d7cdae9f7b905281a43ac9e580000000000000000000000000000000000dfe8e70066690d20381aa4530c5d6368d7eb23bfb2753514956537c2648a83eaa4894efe4abae2f858ddc0575a060f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a40440a688848705b3e3f9d3b88abe3da0b3250ae5316e32b809e81cf3b9c94a3a068a1da33d90be961bf612363e510000000000000000000000000000000016f953a1f8e1df494e30df6d20f57511289dcdddd2bb5495529ff574c37718853261dffa269e8f7bae5d3a06e736f2341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124be474d61ad446810a831fc1d3fd47b4821cc915c373eb4a5a401037a89898ded96061a46c801206658ab99b2a9c53000000000000000000000000000000000df266ebf2f428926255fb74535c60ac14afb2d2a952cac47ecd90f9339350bbce30e2e9e52ddb1910916395afde99571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019774d7ff59a2d275eef8ad3d311d723e314184d6151133753c812ab9ca7794d33e8c36c03da51f127deaf2f26dfb1180000000000000000000000000000000006215eebe30d4b30756f9100f5085b50a2952687c287d75fca6758f657ebbd047ecdee68e8f85ef35f588283ef62220d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6b91efe1a4ff904f5e62ed5d46b3d4b5061a9be68929504734a0ca2d0247ee515c80523e0c8e159f98c4b931071c780000000000000000000000000000000002a219b88865140e41242a2a5fcdd443b0d0a631f856f6bc6135f90fcc8de7d3532234df936be7b2bf3fce5c704c877e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d737c22e18090adba58845d573de5c19033384586e3c12f2e357d111007380a5f1b935dc3273fbb5afbd0dc8ea114570000000000000000000000000000000012977b4ff957defa0240f23e456c7cd03da86f3b2d764f92b3cb7a5bde126eca400258b4c77ae1277c861f6fa6b421831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ac96b5418e7d87c4368da9a25a7fddb71f4d7cef07b7c73fb98936fd32020c03b0f904bfc5cd84012a85ac9eb9d8f3000000000000000000000000000000001856c8c60b6346cc8b2ad1b5482a5a30b42c43e37a487f4ac2ffb92eef8dc05332efd2a816ac591d55ed7663ee66360c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f98b89ade1afb85828bfde0efccccc0d4208ee107f0d32987ff92fd2ee7526939b496b36be5561c9350e6c40d5398500000000000000000000000000000000046753a3c7190ef7b0dad0b73d4f953d64664427d8e232b0a87c77c69b775eb4a35f463287661667a5f0be9d122b4b231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d1dabdf454a196de199eb35ebedb3dc138a9ee2846e6fdf8ebc604d128f08b4a0d782c287c4d297ddf30ca340bfdbd000000000000000000000000000000000b6e627eaaf3d2be3ebe22d0a1d1d67c22c4f7584cec6c610133a2d3ac405f76e55b8025120196bf69f60bb89e0586201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c77ade0f0a5e25f927fa674c5d9a4e9e7823449c6b1cd7bd814a57babad2e7e927ac3e5de69c5aa1b21b0f554a64e00000000000000000000000000000000003333ee0e2ea188a9159a7452b1650ee42a08f381ffeb737525a73205627dd272fc16e8b8eda97bc63e87b70863bffed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6bcceb0edc5270e004287a996897616e59dded3334b4b7facf72729ae87e4d53b692aa87ff32c5165c5891b0ab6bf600000000000000000000000000000000089bb912b73b529aeda7aa80d6beb5fc9c7e9329de0ee9429aaca1d37a64002af5a64647fb413fd07dff1ca6eadb1d751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021dbb7fe1194241588dae053184c59957b7090c839e4537c32e6259d1d2025b3d5e12ec33accbf84b58dea35e567a52000000000000000000000000000000001341b6c4fc818fce20d21cfe58d3896b4b354980f392183120de37520c76dd564d452c1e375b03df397f1916a68cef261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026561e93e0e2e300996bd0b7d334d305df17a9440a70b0731475d4ce9fa3d87e99c23914a8bbd0bb1a23622b2dde5d7000000000000000000000000000000000388cb1632c98dc43c24b71f5f18ff4abec9f686c9dca7a4320fa4df2f16833a27a4ecf493d5bc15be4decdc1d45a79b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b24e8cfacab48b5cc1152bc431bbec7af6ba51d5b1ac4355d6bc11f2a9fc2b7bec82d0969a88cd69aee8d2d70429f0000000000000000000000000000000000cb54a0754fc36324922161a24697092251e2e80fa6bfc79f227ba695366add1dcd258fc249e8a6934c25dd7a34d2f481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6730888308282d820e5f49187f5f8619a2b1bb527753e12bd19b0696d6acc6e2eabcdc87a24e3160ab466dcd6763e2000000000000000000000000000000001272b03e3b0ad7ba0e6434c725c16d06950423f542dab0fc99da1c274a4b98b50557b56b4481890ad49de6bdba91da1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017cb4d5f490c6a43376140bc18a98fe3aa94095e7bb777468f84e0c01e3fc9dd2f2cddb2b1de7a40f1343076f5ad6ae5000000000000000000000000000000000474b848b0fe8c8549bed222ad805fb4b87969d8f524db2b4dcdffd1872239bfdd187f8b9e38cbc3dc132d216e630cdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191458e3a3982195230be8fc9da15b0f6a4f758403415b8d835a5bdc086b334f932651487dd95977a62fe93ea715ec6b000000000000000000000000000000000b4e5321f8d5225642d1a79442a0a0440dc399ffc129493ee38fd53efe0a0ef248f9a3154537d3e14c652bce9171abf81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000655a595cabafa34059bc9e73344c6dd1ae36a49863d452919b153deef8fbec015c9a65457b8a280b145c3a67148c88d000000000000000000000000000000000a4445a39a72822b785adcb17f0e3b2319f8e3d7c56193bc14465b6b66ba79e8f56e448a7aa02c06eb996d0d71c1e3ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019327497181b3da5192b74a9fad4e33343da179c119fee4585cadb78720b18862e8583521db6dc3bdbc1380b748a753e0000000000000000000000000000000018d4620274ae5152b23bf21726d545c60239b8dbc8bcd62d6c88a9c554fba6717e48eef99eb78f7778d36580f746801c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098f007b195180c989704ef5c99b67d9070c7e2ed1467b378ba259efd8e6abc8a3fc591f91096c8a3cb4cab2f18abe1b0000000000000000000000000000000001551bc55d0cc827492826df9c73624a56df9cc54088bd2b9307d0534a837f1fe2a171be154a99347c16e0f8305ce9681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010b7e0642220f559b82ba41d2be17d46418742ab1f91a8825cc2ba0b6a9ce6556398967720c0bd6607bd0695bae66b5000000000000000000000000000000000275b70d632a486dabef2d92c1b55b25d74d68aa2ef3133d30f704c44e3b60685dfa888c1e4a8b42650dced216c82e771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af520515fefc40926183fd2ae26c5c24f74e85a25765a74b6791f59a3c713e7fb57c6ce54aefc2c8154e710492f9450000000000000000000000000000000000b429e9153f77a3d08c5f0c47cdcf73513039dec6d7058137b3d23122b06289adf17b4dfe9aaac055a8079039a49471a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011447843b7cba13155c62b5cbb8a298eb7aa57db3ec78f7971fed1ff3f1722165638bbe9260c0c8b37edb55cbd9e8e35000000000000000000000000000000000caa709b541a29fd2c26d6f74b2c580bf898443377582d1d808aeb0f162d5baf55c2691be5d4804b1e402a2253847e611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136a9edc2c7456129c1b6abe908d7ce24985e0e9a6c8b2fbd060b29044f30907c1e94bdc92ce8150bb066e4bb48c24f90000000000000000000000000000000008eeaea50e040c3ace35269f330f40426553f1b92134f700341f5f211bfcc9a49273f9383bf01be4f7106fe99cd450aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195d4c8e78813c8a7a82449ec8e7207aa65008278d48eaaf87fbf342d2f058262c82e0f47f214ce343a7d8647db861790000000000000000000000000000000019b8af15fede12e1bd523e51af08069cfd0ae9219c95a7be41e3fdf60d5fcb18cee2bd9adadfc34372ebb7d5539986461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000402cb58b3447ecf2b0f70210c4349d5d096ad95990cf995dddab89569474c86286bc9ad47371b9e8f32048abbd02c8d000000000000000000000000000000000d9b22738c7c4bc949d329d80d898072a3537b3679bda26c42861b8cdf54887ff3fd39d5e374d8790c3f2a5530b0565f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cefe29d70e1f6f5545174744f891a8eae67901fe9cd9b5fed7193d722fd0bd09ba163f282da3b850d9b294e75d8d8000000000000000000000000000000000198d518d5545f3c9f9ae1165ef82dd26b50839910bd101589d1a554e9bc740495aa7babde13e376dc540b5050d4e1cf01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148e4aee273b1f356f3ef9b89a236d3b1d4db651e50c3d4a9a4d5ea5b6fc5f0eda52152f891d1442dce8f4197b1978b800000000000000000000000000000000125e60d0b514de28de6a921bedcc3893564442e1c39db568562608bc8c1f143c2701b5431070f65d577b799cb7ffc5771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ce47007e9085f2099163ea1ba293e61f097d1345784e06cf32ea0ebe14ba0510e3acaaa85d4d2ee103a6cc94606340000000000000000000000000000000000bfb05145276802bec90a48a0713585d38f455f37b0ef7a1b0e69eb5e9ce34a0c57d480312fcdf22d8f90becf44366931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103b362dbfeffe70db16e28037a7724dd6ddd5ce38250ed3bde22ff641627f21c1592c61c209b53e67307bdd2ebeebbd000000000000000000000000000000001392bbd8d4134a696acc372c29f36f37aa7dbbf8827945c9bdd1ed30e5fb1cf9f0bdb84012dd188aec90725572f64d0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037de20e90bc2003ccba1cee28ab1ac29c73ec4863340d37928dfa6dc5b13b72a366ba0f8d34fe8b6dc007dc855a852c00000000000000000000000000000000067f0946b593778041f6053985e8c6221513f804a7d3824c8003fbcbb6dbe5dedfe79ed7c3b68ad2bde5c68fcb4726031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018889018d102c17a1becace07ce19153808bed3379f7dd562937dbd2ddf24f268288e3952e53924bf321d87aaf10d2a3000000000000000000000000000000000fafe1fc9a9cc439d4e9531e1ffbea780c242ea4e52ee6ed4f92586372116e97ac828a49d177842e796a7c9ea243011f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7ca86f72fa0a34908346a0ca02b23abd8978cf1c37374d9f7277b1f3be7b8cccb62bca991e3240b81468918463f8c3000000000000000000000000000000000038ae872d7669a416dd85e522002f07d0769d90761a32444d888ef45dde6ee7350d26aa71b021a7d27420a658626e1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001654c192918a85053dde43f99c5b90836e880372d82d4532dbbb9ae9fd3701883ec35c63983bf90d5a76cda07dcf83aa000000000000000000000000000000000ea6f384bb572be445c7ee3c72bb92b59d1e262ebab4dc142ae075a04d7bbef2a34b81efb2c9bbd8399f8c5977047afb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf8f22116c9c7b992e6b6f0dcd9afd811be529c5abef4080f0143f46eab6141591744c7ee62e0b0c41053afaae9a70e0000000000000000000000000000000015e0e6747c9d87826a8523e32f125af9f3aba3d85af8a40fbd43990271e31f12e0a2c6c73289390e4eec183b889e79a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f02d48ea861b1f3f07b0ff80e3c09a2e446602c523fd16e080bc480c7b8676357d6a9a07537cca50309dd21c5ccb4e10000000000000000000000000000000005ad8706a3fa386ce8858904bc8b0ea99dc4b5a366e6002a7ac4786e22c9cc9fb23a5e2e923b140779f756afa0f0cac61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0f2e66c8821fd5a443fca9535b992b0bc70a7caf62e9ecb511394d55020d5e66582d2876b776d27129d0b4d13fffff0000000000000000000000000000000004d7cfd164898b3d68b0b20f65d2f649837626d9f32084311a79f17c761064e25933c025fd533e5ce44bc4cbb0759ab01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092dfd0b701731670e2cc923fdf8ed09bfc2caeff6296029870ee17f959fbb2154a5d59289104e28e56407c4900154f800000000000000000000000000000000159be25ae3fd44020d962d02d7a39a38736b88e2ce91261dc24224a0c6302b909932f60ed57f8f9d50bc77575fbcea901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f7b3bf08b78102637708ba44b959abb5092bb339de8a61fcaae4ef4e35970fac9259dcada9a896e3383cacefd3123500000000000000000000000000000000000f201fe244ace590e44de77e7de540d188c8e6e10377989a3e015f7069f13b819b1c6268ff6c32790904cd0b855c2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037ca9779363e4a448b0d360502660f71a63c3e43f7a3a2c3883e6b62f0c4ef401530db411a6a7846d7c2306541a0058000000000000000000000000000000000fac7156c23e112cea8eb3f064c16d3dd0502f127650927dd38170071c02a0f3a28d841b868ef5af250eeccf70a9799c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd04c1a11eea9377809a62d3847f5934e96ea7eb682ba7305f53a65bfa899b361278e0a5cd1fddc032fc84b79bf910c000000000000000000000000000000000b1259b32930e5a66a1cb2dffe3a2a8e8eb277d38f9d4ce73ab1ebc591bf7b016b1f4b9beea946a6c6bf43d9104b91f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000728dd39e3251d651edd206f0d2126caf71c353df36d1aa4a5bc601312773af245ff296125c8fd1e63662ff5e6dde6c5000000000000000000000000000000000632dd081603c7036a5f1f9dcf2cd028a8f38d83237335dbbb52741bb6ea87497918024b2808d9c0aa1e4609ed6c93d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ce56f5615ef97fdc3ee13e44d597da433f1d91d0f86e8375e58a1a0a3cd8603d587cb57b847a22f458ea36a09562170000000000000000000000000000000003ab8eee8fef0e230b286d2f240292441991d7221695474bd74657de3cbc7e06765de6fece7ea589f8c9c113e0c89ef21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018857d052a349f52000f0a355987bf6bf1fc29aa304117c382e4f337de9a65dd1ed7613c7955c1efb47931c42a001f7c0000000000000000000000000000000007325e50231dd46009a063279a2a63a84b997842077cf5272950e246bae0c1f36f9568fe9b0da7de13547ecff957c2e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030a632b7414d13c76d17c0f272ff0718ded2bf6ba2ec9e3452cc9ac6ccc1f54ef69362bab463d9daef5e63c9f5cc531000000000000000000000000000000000e55c09dd2050c956c6d3b3b17fca72d453c7fd8a34e27501af521e003b0c03847f35526b88b60fa97ce0906dd7d3d2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8f323eec5c18e2d062790de52d120c643d99b40a7fcc8a98ca17d3c27763e6bda0cd37f5f3e56c379329a58fc47dbc000000000000000000000000000000000b8780b2028b28e1caed89d085637dabb9cafc704372a0873827038d44cd78c5de6856a2376c4d38161305a837979f5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fa4b01881101f973b8bc201b23144b82b1ae85aad670f9ea28988d63770580e97704dc98f2e2f17c7e75735b5fa32400000000000000000000000000000000045b3e531d921c65d38570137b0441f1748bc12fddd2fc1d8458be051c0ea225d58fa25967fe2cc970927ce986f87b111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189f64ae24498f25d84ce0b198998e191d6a8a7d728a2008c6de0658d689309c958c0e25f0b47bb15043541fa25ee5f50000000000000000000000000000000012e94a844965a8a1aa38a6ee73ecf065efd4c6202c6179fe63f0c55981ccec905bd846c1586ebfd06367b37580f4716f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153954366e6b25ee954a0356cf74b9361803ecb087207e64e276b34e1fb21d61a458c3f8f2b6923f67361f9673ec7703000000000000000000000000000000001126eb26895317c081d22db5b26f50abdb6b91e22eed139562f9bb0fa81c7663f90868d33cbb5ed645232d45a03266fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017122498cdd636fb5e3cc453585551fc6e0be644793649f8b7893b464df938b8ed246fcfba7e9e2031c4d604fa0197e000000000000000000000000000000000972a58f61dd6f6369fafac0994a567fb64ef823d4ff5a4adce07d56ffaf94b57f1b6a5b289cabf1cb6236e9aef6dc721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000895b1b5e589b91d240f83f6d93c5dbf86349cd2127a16bfae054b2f6e59c19bea6e4f1bc7f4a0183e03f906fa7f98670000000000000000000000000000000016357ec0e8d217e7ecfd87c69638312e28ed98c1b25fb48141b6c3c79c4b1a47a014de7801c6d90475ab754e480bd0ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ec4c98ad649af7fa1eb1d6b09758df2f31e1869b5e2d8d94d02347f3a015d1dda6e0fd317877314e55bcb4bf41810800000000000000000000000000000000054b715c3e79f361813ebd633ee2d0a6f5118f54c2ad6fbb0bc9ac80a62a7242e23ed7a8039718f79dfff2aba3cc402b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8b7e910d01fca5ab5e53ebfbd77a199a0ca616523fcadb46ce2fe5d4d8279cd4ec9b52ece33eb26ee53507c8f09d73000000000000000000000000000000000e2616f17fca6fe5ac9463f86f60587e1bdd432e43ca209634a9ac13c3381927c4dbf9d9d32bb9f47de02c88c2e6deec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff1cace6e7c369d483ff9cdd7659b8e43bbc6bcc848ed824a9ddf70719e11143cd4572001101d84a6d2fa677dff5222000000000000000000000000000000000735cf4d2a1a6558a6d336ed5fb31fa19f03522ec6a053d2b4ab7481c78067bdea946b190b138c75adfa7a4da25077961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052d2270965ca2c49226db6c1b531f90ddaf40e1d80ff61286eafa2f372e700c2a0ab45235cb8d79eaad3e69f7f8bcad0000000000000000000000000000000013c7962b4b50b60d5916bdf15ba8bb1989604d599908b961dde8a548315e76eb70645ce4ea8db7c7137a06b5697c4cc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0c5db34a79b61b7ec44d8edc8745cb774b18172b83391b2a6650c6527eae588d3de23222e17188e83a2dc78800fd30000000000000000000000000000000000fc16dd28a0c0bab7d22275948c553189b835661e6534d2b90a4bf717875dc5904feb6541aa4e2da11a58a489ec755fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f1997537fb52f94d196026f56fb09d5e93e433939c64e3ec686554c0e05f4e821873ba0657eee4ce170925198bcf5d0000000000000000000000000000000005af4e5ffae463ec39d73cd350ae1e2d7f73cfe7f2f20e7f57c103046680d60065f3c1d0edf895d4eb1353c824adfb7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c2bccf4d3fc88cd10f863228d76c9d3199bf2f1b73016b6dc33611dfcaa2971364a1bffca0d363c9469e756afc447c0000000000000000000000000000000017c073af9ab80b163dd4d87bc7475cc6d2005c0166d96bba4efcbf218c755abc3b7021021255ea19feb0e9e1e5dd81d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c819673e6ae10757f839040118b8b609721881dfd29f06be749a91f58f7a308a3b4a9c3fc30632b2d19de23fade57b000000000000000000000000000000001265cf971440aae83691f337b08eefed434f6dde1369333e8e677863bf404a4f515b338b441d7782c86e146d666851e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a8b6beba9e8bd3f58f7949c9476b7d6fe7de81aa04b8d74c6dec02ecad333e5a37502bfe511b73fa54cc54ecfcd88d000000000000000000000000000000000fc1bf78b29a82ab4e6466b84e83aac98e75ec6402c0179b0e9f2b3d27c8a5d3deaa093f93cad5f97df5e082fae382fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ace0142f74d8ebda313896beb772d001f67a61963c0778788076e50753bd93e8f83e3529975c91699e4e904d9b41090000000000000000000000000000000003827f1cf87459b1dbb80b1c585f3d29dce2690ead97737f02e6d86af1f1d31c2fc537be8e7b50d8fa65f31b7b8b3ed81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f18a5513c8e08bb3e4e648e5cfc15ff9d0b5e4bb031b80b9d2b9f3717fe617d7fd6e911537fe15be8b130644e32325900000000000000000000000000000000185c9209ddf5da2ad0a1affc46eba28ad317b425034b933d17811a6ea5c1497e5ae6adb39dbe8627d9c2fb6f27a4985a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000394593f5ed51e8ca8b5c44b1be690c9b4fc908cec57e013a9dfcf81a540914a854879ae39aa318eb3341f2ee47417c000000000000000000000000000000000103376f1d7015e3bbaf4d5f107b377bab22a9f026fcf4ec3e90258b87f5ad117f6e63ac8e0c6165e2ce7824df4558ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163a022be3d2838cd964e0052a67aa9ca9710dfe9303588d60335624ed77cf97bf5960da8ef7e4f0cab8c15bd86a25170000000000000000000000000000000002a166469e59d361ea18f766de68ade1005ba61cf785bb670c3759b73d6d23f06dc0dc6c8fadf9a146070390a0ce0dd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056a3b1d7c471a37a93f9835d91c167bb73171daf4f548cfe7f3363c835426a4087dddcb1bd4d8424557ff56ae84a6020000000000000000000000000000000001a38757d9235479b0c78f207b25163e77fd919d8775de5d4d950182932e78da4f541502d5bd2f9090ffb899cafe9fc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b83a476b664c9d22236fb0b78dd9af817f99b043755e6ec4ce09c0de032d840d609b6e3aef61f04bbb58cf6bde077fd0000000000000000000000000000000000d67f089e57cb578d4ca1225ef76fea52280114b7c4bd2495e5f845b961992052b12f270ed57a01ae548b60c6a32cae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001624d4ac492511f52d5ddf70b03a6dd5e26a738cd6ff634e8dbfd19aee1b6fe62054277c5cb4730b6a372fef7f14cba3000000000000000000000000000000000c41e675736703e995e1e6d9659f3f473ef344f893d8218a8fa50828fdd55ab74a62c6e60141d72f3c278ca9c3c5b8e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001780b01679550e813260e6af24e5cecd00a74442284a4b1d01628b32de02122fd3f959d9046d1816729d7754bcf5bccd000000000000000000000000000000000cdc847b35e8c1db9d3304bf8ca0f9bb2b6fa335e4a233ef3039eb44b91cea40fdc24121ff99d595a0b867a43472fe681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fcb87b3d456df47fb80f2f6c55c45dbfdc7b00024f1b48947e4c92c5e85af28cc5962b4f9bdf9f042a8c48716da69b400000000000000000000000000000000043ce44fea4a0c9529546ecc17987f6395167be1856e9fd9da84781ce45e2363f9e6e55573298c7ace3b76398d701c8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001944f6184943889fa740e193e6b664cc83d7cb73b868b6a1b9680d86f9e534330bebcc2912e08a30d67e5d8840e5a762000000000000000000000000000000000cf87dd015b4ca5fac58feb35233ebc9920fb44da60a1bc045be81379ed83c5c83c0471cfaaf6f20a77afc35618c1d731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c9407b77e402877b2d1926d9242d228aa7813e4fd825a7997442f304a777e96072767f02cd9760c56be73a4342b6f9000000000000000000000000000000000dedd33dd3a61d9724670ffd95b3b2ec6e69235ed651dbd4c403a9500723a71d8284191b2d757506fcef2cf0c7d21b4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e45874dcdc3a10a3e6bd859c39d2a419ab2d0529d42583cbb777d253817afeeaf9c7faedbb06583be004d0b8c30267000000000000000000000000000000000c2c7ae0fcb6c775f55d6ffcfa63476e61697e6aa6182810c91e4c48d44b5491a4bc858070bddcc588b7b41e2ae6b54a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154e9075f6117a788418a690d9ab818a9f553e3f288b231293701f70b4fd675bfca730c39dd61a50f3e7856a651a6d9b000000000000000000000000000000000c5530571fd75630139352a15cfa9c14e5f7c0630c8ad93af3957a0912a572977320aa5622eee148f83dc7a89ee1b43e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001203354573ac13ea13d25bab55cbf7108cf457480fc8a2d6b89917b2bd83f71ef4378140a08e90771cde78b381107bb500000000000000000000000000000000182f3db4a1d75468c6296e57641e75cf3b4f538bfaf92c7c83eeaf07b40ffd4b1d0e0f687d1aeff65d47463033cfbb4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b25f93a4b0dd05dd9843adc1b4172c81839168566a2b927ab71241aae9192293fa8a3ab5812244c531e501cf8b395f000000000000000000000000000000000fe8d6a81b7799921c5a9a8512f05c58b1734ce9909ba0855629235b94492b70ab849681bdf05a1ebfab91346c2a978d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005aa1c6068eac3cb2d0748cfcbee9b164bff473896a3bf05c7a20661a41d43afe5a1f7c90bd667d51cee7019d19f39f80000000000000000000000000000000008c9d4256efef29255ef4433075264937a7864ce5f000006cbaf2269dd389c548d6f88dee0605831d88c6d9f988093331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185e4743ea94c3d6d73a2fc7d648995656f87134a19717c661041230b4986e6ea919856af73e5c55dda15a65508e0b5b0000000000000000000000000000000005909e1c21b8486d46acb4131419f209230c7d1b88ba86f8f4eaea14fa06e5f01a39072a3d331eb52af1ba9547f9e4681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000713b4e2ce31c8363175b3045505c8193ebd1dc68ec1d5d638b7c4eb81431f401d4eccc30fcf0ee9002ed566765cfe5900000000000000000000000000000000118018abb0ab2877211333427c40a7286662ca75e6254aee20ec3954a6e90311f8dcb989d86b67ea38ad0ae4fec855c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b33259c2bd24bbcb8c77b21e7e63e2495f3f1f4ec75a83d6c0e0bd46a878c84d9fe0df14537e2a2febbc52b744655f0000000000000000000000000000000016e000812f8ca8b989c583f03cf36dfeb21791fe579201c8d2e09cc7242d4039bb510a4c9cb583b64cce8b99e2267a051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112aa9a3eb360728780cc0fc7e82fdd600fe3bde53d06a1612ab7cec9582df90f35672183c5bbc7dc3f4532ff7dbf9a0000000000000000000000000000000001129438b56d8e3e30af00ed805b4a8c0df361d25c8cd302edbeaf3a488d85945f8e741addbe8782d3e84ecb3b01560161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094b34bcbbb8c9412c676ececb8ed1c41a4928d395f345e1868a4c7c0514109698e31cf535f393bdd2072a300746b3bb000000000000000000000000000000000caa9f93140afb6b1410fcb6a8fb622d87c5519174c19f3ed31d5818ef9d28f5b9e88fffa486546895dc4308d84b7e631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6b47b2e1298bf23f124252b9c0fa6c278fef6acc40571d22580f3e9b2e344f1316e4ef4dd4c4aac9b865f6511192e90000000000000000000000000000000013cfdca57f264c1c82e8072beb618a601988a6a6746a381b1f8d170b9359aa15cdb7658f2610b7eeb6dfbc1c4d4aa6031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ac696014595f119e4cfafb03c32842e69d3d3552d40b78456fa3859032cbfe0a18ccbabba3ce1b512aaae0da9f433900000000000000000000000000000000033564cacf212f71672cdab25a2cc7f7fe29ddbd473522c0fdcae704227cd906d4d239e228dda66db9a09d68b7faca041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cb4138910df1da9b724fc850834a29f9915aaed5ec0a1b4bd7839df1cda322875625823e6ff3e577bed88d7735f7a900000000000000000000000000000000029a1314acb5c437c72e580100afd831d6083bdec9b562b1dd749eb29a29d7dee8cefb0bea1b53bff248cb334a536eac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004cd78dba670e10dd682ad4b1ecaf563cc793160333854fec5773504523c09332ad437d5187c56b536cf116d53c4b02200000000000000000000000000000000112c4b7d926624d466adc512bbc810258aa098e6d4af5b73483947fe2fd427e599b3ae191454104536561fed5c16ef2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d2adc5496282548bd2d65002c343b0c9493ad16d3fddf324fde870214164a4d96d1c0bf34618473cf67cbc2e844e06000000000000000000000000000000000ea4f2d957b21eb87e286e75acc8e1d89f47d3ded2ad1bddedfb7f9d5b43d1260aeb4073d95c9514ee436a16c4ef2b7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad1e6934a1e3c3a731a80d149d53bedbde29a34077333c406adbd48c201c8007f74ed028b3af6c107526a8f51da3ec30000000000000000000000000000000014f1b95b6414120fedefacf2fd5c8180b418c69aba43dafdee311646b5c82eae024c336bb96d94b2044dcfc7a96202781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000adde0c3de13b5021490f37c9d917493495b94b47ad0c44fb56ab27a64788291daad3fb0896152e0c8b5e05931651ea10000000000000000000000000000000004634c6ca41775d92bcfd61e2665b3f5a58ea6cfba597e5d401cf92981f04c309f5549af37c1d3c3c3cab81aa4ce03a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ada46325e812135e304db19ad9b040503988336f4cb129da0dd55dff4071799fc86ace822ba1f1872a7a1d26da2aa3000000000000000000000000000000000d153d03b839c0eb9b9d1f2b486853e9d42bbb6487474e436190b893f364b20d0c5803770236b9e35310d819a1eb0d1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ef784f949da0bc0216c448f5b0821cedd3382f0fb7ea24a16bc425138ab4d792581b7c9a943e085702b59eb18eb102000000000000000000000000000000000620665e06ca2a9984a2017a33c089e3a8ca040aa3317e3432bbe0f00b7bb0f7571659f8f93356abcc0486f2b54157801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cccf3495d097d93244b950b75d5f2a71ca82b993384d07083f186b497ec9a8e0fb5006bea898142a189e085a85f4230000000000000000000000000000000013c57f27681a2f974f7409538f213753a09b8694c92f71dda53ab3ccc2ed4f235b49705f205c8da43ff74de8864f8a061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000deb3725b064be6a19c2e9d343aa8f39540e701d6843a3c6d8e0c0f6ea3924938d35b204810fbb3158636606bebc572c0000000000000000000000000000000011be3fd18165c7eb43ab98697f040942c0bcf1572f93522484216731aa434160362789e344e60ce10e796726219425801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067054b1aa99d31ce601a1725c614afa54610b74d97fe245a35ffcec99500fc7f095d4f8d37b1e483464eaad0193ade40000000000000000000000000000000003c26a178b334b605a24d93d1ecbd0058c7f8eaefd28fe992d75dacaad7877fb828dd20f3d8d8987122d9de820bd7a1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dfecfa9732c9a9cd3e237bd0b1d00751c4df0a091cb372b6dc51baaac96138d58e1546f7c38550e230081d56562ac110000000000000000000000000000000015f233887b2793b0214d814731b8f7cc2baeeccf340f9f9de6049e2146731e830e77a58722016e2f657c77ad670a0f351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020e6e173054e1e2b89543830f767837091e17e7ab78053e9f15598c931e8e2bccc61364d2134905199b3614efc2ac43000000000000000000000000000000001614c7e7c54f163d58c892a6fad75711d706c138da9e478abf61b05db0c7951d889a3edcbd802c1c25e9b19885097ee91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018438c03c9e56431cd731645ed45cc8af9687f10b2a04bd49dd1867a46c6497a6dab56467e178bf22ed2a874194e19c4000000000000000000000000000000000bd5bfe1a6141ec755e1525b8737b3a329ffdd949b7b33508e97d428eafd72dee74af212c81348a4622a635eec2d40661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197de8d809db7bc5b7dc4432932c1e19db2dc45bf94db6c5d50420da22f40d785926ca6c36a4fc55ed273570a0c1e0c70000000000000000000000000000000016d0222928044b65f29c861f16bbb974c4056291271e05a5ac2461ff8800c2f575568bcc94701086db657f7dac64cfb81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e1a6e0c394616445f594928751be00f7f565af53558cd4831bb9d312113642bfb2f4ffc45bbd87d2f5f4e12bfea150000000000000000000000000000000000cbf3311e1b3e2cf796ec707570b3f7265154cd0a001fdd3378fbc89083dbe5e47df6fd591ede10be2b341a3a41a6e681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c43c5d23d8af4bcdf323b5c3f7d8976fbdba38a7c96d1537a60e506064df7e3b17905bd23fc5545505e5b2a0aa5f7e0000000000000000000000000000000014f2c90c76e52e2f83724aaad91c9c0346f880cbf704e8fcd954c5ea7752a664874865ca01866d329e7473b639b24cf51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001548960781817c6aaaf833d79d42649e57f8d284297a37eaf2c20a275eaf1c8f7ea9b858a82049536baf04909687fd58000000000000000000000000000000000df030d318c1eb2720169d4f6a8592efed7083be119d6128e127c6d1f8327c942b63346ee32447fade5ae7a2c8d3efa81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c4af0fd3a0581158c3c6b323db4a36a44bd0bb9f021ede5ff8b99241d8cf7f20d19855283796773ac143d1b3e1721f0000000000000000000000000000000016a73b1d31d8d234af8a9e820b4d1ec0c584c9591f7421cd95623f450822a8bb2e9876938918d83c7f8da1814b361d2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d43ee4b9ae7d04ba723e360a3823036121630180bb967d730f99c7ea78e65e5af64ab40ad6ef596759d581ac1cfd3b00000000000000000000000000000000137868ea6b2182e10d669bd461a6b8ce6c2c3dad8f7e7ad5f657310573633031a09addd06eaad2fd92fc6e143505b31a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001387a927c70a0edef3f4325b808581a4fdb07f33be097e1a082cd9f40ddc46346ad79829e1d2c87d3b130590975075aa000000000000000000000000000000001534a5ab9370de057181378ec7e580bb67d6379775668ba0566bd8429d832ddb4821c59ffb807e64377d4e2cf3a575ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187a84ad4cd132bc8dac86a6baccb53cfbea8a1bc424e43f6eb3ca03d7a2858db8f143d76a5692d40551e8d4396efb00000000000000000000000000000000000fc0795744641d0c90418b764fa216ae28ce7edf8c5e77266e43ea8514d39f4481358f92f94af022ea8bdca728fdbbde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098f99707d90bda18e305a03b0fd02a7557fdc355d71e02be92b633442b0ba55c850b3c020d36b249c61eac9a9b68dbf000000000000000000000000000000000796872dc3cc45efdb52ebca0301025bbe06aafa0494054e1879fe7be86b76cb145a6eca8bddbfd55f45078d2d97099d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f66910191955f4025d7638c8b8c82755e7749618f679a0cc9fa478688e7cdc52757e219a95c6afc5541ca929aaaf360000000000000000000000000000000001979109aecb27702c0a9591f7c002a0bf480164f4c48c26867ca58f3c1fe12e627f731c93ef3c599de48661ad906af71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000064a50eab9206d132a9103d64eb5574005ba4fcdbe50e889f648129e3c5289fb318156d856c8d5e0c8e41dcb94fb53cd000000000000000000000000000000000f639d12fdf796294c1bc245f22b1fcd80bfd90e0847309c51706e7ae7a15e2b3c2941c94d74248a0ce723e00aa91c551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ccaf612116d89f15c3f3c827162b1c259dd275fb47900e3a82477482d62435bb4f6644bcdf81da5c79bdab812ab1e0000000000000000000000000000000000afeb0f167b40ba2e3f99634a33b4f988a826bd7251e523adaa0e7c0954ee0eafc808a7472f73ef02da707ec38a7cb361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000769e49b8a64a68ca5e895dc7695b4db31b3da69eef2a11a94f473b477e0584f768c96594e6e397b9311a271657e42010000000000000000000000000000000004caf21a77aa0ea516159202b022f64f4fc7aa9e7b01bfc711d719cd1a0dd7bced0c7342b2f0aba16fc411c4f6103e621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001709fe2bb3fde768ac4b01a857472a98e4141b23ffa830ad42ca23058492754a67a2e749eefc09f48d94b740fe306adc0000000000000000000000000000000002402f51bdb7242903cc54d7ebd3d744409fe8aac8eb4659f6ee5ab4429f7403a973f85d6e127d9acd51d1641f2fc0d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098b3aee0c4f14e96ed96c220bdb30836a9e8f91dc7411d2220a088090475aedbd3e0513c0bfdf07f93a66f012a872eb0000000000000000000000000000000017f73fb0213a6dc18f2055c480f724ba9cab19cfcd764d725bbb3c752cdd539e75caf952b498bcb1e3feb5574ce6e52c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020d0d4731d899c384adb60348fd22569251ec1d7d19ac224618cc9bd37d104abe19400485f9e22dac5b0f7c7a71eba2000000000000000000000000000000001057dbf8f57634e103b28babc342e30995b2a7d53123b5ebeff687776ed82a8e2d5dd81a53a2ea6f1de75ee8323dbe711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183c93ba9dfa0e1c6d9ba95536ded6e78d606d1e76f971ba568d6fefe0f8fde86bf6f04b1a66e6ecc1bc9ce71e2ba5cf00000000000000000000000000000000014b9732b90daa700ff9e284e58375463608dcd7ce8b1307ad986a39c806caaa0f57251956ad7ac21a8632945997cd391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b9317943d346b692d32f67a8275ffe1a692ab3cca0acd56fe99cb2ffdf674ae05d53db5b34445df3cb3e681b91ae0c00000000000000000000000000000000153ebfbce5176ef8efe90d88c2b6ce43b8188d380d7e639e9c06450eca86e17ae5ca50726976a5164e78eceff2af69191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190913f75326b19e0d55a776964ae813b02ff83977ae18e59510ceed8fd7f2ef4427ef8bd45c6ce6483f3cfd7afeff41000000000000000000000000000000000a9b9b73ba6f057199ec981c656fe6ed1fc65c89abb665a0eae3ec714f2e8b25452097ba0f54f7d88cddbb214bacb7691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008198af373a3fcbfdb9737486ad42a86c37c679742403e61c0a381630737f060f28c05cd9333b0d661321e9af404c205000000000000000000000000000000000c3a2ac921d3c0e7aeb5a43039eada3b633c4659fd059454cbac5b9264778ec5bb9557e4313f9893213cc3b56c70e0e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001717491308e7f441de17e64509d3e5391222246fb318e221bd6937da55c1c767026db8a4564ee51e6e301a4ca4425622000000000000000000000000000000000327cc54aa5fd382bc4df6eb4f0e0ed2e3718b588c62ba5a6da7f0a0308d6c1fd9eab0f065410847bf004e2c1e3c04b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072ff0c994d65e0364ada3c3ce4eaea9441528e0545f03894b8c46305aee4e952917e1744a6427a9956cf4a5367af2130000000000000000000000000000000015e143971b656526ea728dbfc7f2c018ee42987a5d1f0480696ce06168aa6d6db7e8170d36304c17aacdb53579ad29fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbe0bb48e574ca28860e29ca02400883004d003f521d07b2a737c8919859acd968616edc2f6a5ffd62ea5135bfe62ba0000000000000000000000000000000014025e83d1d873a2831c90671988f9fdfaa5cf91dc546b6ed9a0d6a78b56c85a30ac919dd165ceb0935f3bfeb04221721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000feafe20727ad9815b9d0e9e38ef750b8e5e58257c37a1aaf870c2b455df71529bf6d3ca11cdc081c0e08feafeffadff0000000000000000000000000000000002f4ccb52e0b77344077ad31c186deb5c4a21e4902a5005464a35d5cbf8bb2abcb0985fd260069ae5294ff018e6bed0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c47d12e834d2d4d46c915126e06d12b6878f58b44afb764e7d0261407966d81177ad0dcc4eb7619d9d3abd710f4b080000000000000000000000000000000017b616805b1625c60e0e09c1da70e7f83d1894c97ab44575297550847bf7fa08ea5d731527b662d480e7dc1e300226261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f0d4282a824f35a48d1efa413ea9b60ee826b849a91bdcd960e3f1137a17ebfa9008bb188b7908d5535fdb7be77abd000000000000000000000000000000000b65f410a042d519862b87c1d66a7bd72a8eeedbe1b5dfa397dff53d2c3b61f77821b5f1f8eaef9b2d18f6ec336da1821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001718cc7f8cc5371f44e7777f66f0218cf3d39abf93fd2261f3c3d7d160da8193e9d5b12008c5959a58eff8aa839245520000000000000000000000000000000003ff3c7366737775dd651571fc420d138883a2846428ec04104c6cf461f0da6500036c08f057d4aa9dc69c4bf21cc9dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d8e48a0f4b5482868b4fa9d12b1adba697b249c6a578237042bd731fb791830bb8c09d80e14cbb602bffee50fc9d270000000000000000000000000000000008010048241948772d30511b1fb7f77bfa97eca5e14efeb2502ca1d85879f9a27a1b663b452a657c451d006490b3940f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127df660352ad016e565ed7cdc0bf1f6c1e729e08108323b0e171d75f26ae8b0bff101bdb24365466317027cc8a2d98c00000000000000000000000000000000178f7f91b7b131f5b522be02188cace1d7e42d9a224eb4555a7ab8eb6a8fe3cd86f3be4e162a97364e24f40375177f4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035b7673b391fb367a47e88e5f8d243ba7e78f454d2e3a4cfe98abf33b1f81ad17134b9a850bd252ce5f788f742432d000000000000000000000000000000000156021692b862f3a3d10908e60cb016a5b64af86e41aaddb525c5037208da77839250c3c08175c3662bde33c310b6dbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001356ee463b4d39178ba441ec481ccd9a9e24699545311dcf9ce7504c6e71533350d917a66bb8e611c74c8f24760c6248000000000000000000000000000000000964558bfd791b501b102aeaad5c42e08b161648d5aef8af7f274631eec68ee5bb913c89b7f2b2545aeacdfac15ca25e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae096a580e752a44e80692c2a95a60634e5fa5b2843e8769ec13ef11b1038295719c4ee4e3ef7c6a67673792b83033a000000000000000000000000000000001225f8d417578719295cca6e0ca0f207486b11ba38ccc023c2aa28bb831926d2018962ad0d987ed8a4956dabad77c4fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000acd4517399389661eb415bec10e4e66291e792afbefcf335beb38d56e00a9a3b3ba8790a02ac530d550cce1bbd3124d00000000000000000000000000000000137a6f6f53905d1a540b84057ef56be664f67e6cc723362b2a15a151b57830f1e9b9fb5aeb127cf685ae2a7944bf04a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6fb2fe7593b3beb8767c2fa7e2db04ee7f76aebcde2dee14f86ffdb35b31469d2978d74efb870344dc17da7b1dc2ca00000000000000000000000000000000073e9ab353a058159f4135b8d5f01dd1cf7e2899b0c5c521804c49f7e85b5b2b75002c4f2307146ae7335a11beff413d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001529b7421e683b48ee713f4f92cb926a05b198d111a268b0e8b5c3825237f385172faf23fb6431ffcac050395bd8b1260000000000000000000000000000000017d19067e6e363c796cab866318531cb170082fb19b686e50360b65ec0f4f58ae08c72a050ab0991cd7b421abebca9a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072ea13933e3dcf0130eda9f1a4504e0e61c3eb5874bffa792579125c6a840695f5de4b31bd02834494856243c51be460000000000000000000000000000000004777c406bc24928b81e715bf581dec4332366ce8cc1034bf436393147a1e64bfb7ea72cac416b42f96c0708541598821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d07da4ca2bfe04458cedc26e2c5aaa65b93ecbbca814e7d7a42b9ea3e446c24dc565d0c7b5e9e52c5a1c379e3d169c10000000000000000000000000000000003a6fd82c68891d0b56071bcbc88f3d728477343dfb21173f210cb9ca1ca1a0164bb40685f67ae27ab6d0005ab3d6a131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ae6fc9d0dbf9addc45002fcd2c897b76cac062187b5f930c999b5a0f0da8152e896e3dc731684346b7b8cbf50dde6b0000000000000000000000000000000008d3b5f0f55cc1da7578f81c20530f1fa8717dfdc2aef1d348d90b160c02ba86f5caa4f6f9394031add5923ae6f742881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001068d91c7a20d92492ff4ff15eff47307759a400f4c72c3fe26c2e1bc0427bdeb44bdeadc5fb56197ae79e91895d328600000000000000000000000000000000157f4d4f972617bd6a70ee63058d8c1b03d8b9a3930d825daf53a6351036758012fd5b312600ca9841f41ae041e560081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d48dfb7214495d23a3f5d4a5c2eaef2e4af49a14fdf2143d4aaffa611a2f7ca7e081b07184cf0d7b326757a0a72e8f000000000000000000000000000000000e816bb0c865957a2dcd1da14bc8043edfcf06fe03a0bfa3587dde25011862e32881ac9894e99e3d0deb0b20bc5beab51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000981209c7a79193a170d1a6cad516fe828adad25ecb07703fd2b765c0ce81d2e5784ce027657741840d359b7c8409c4a0000000000000000000000000000000002a6ab9a5bf08c438d073792eb1680f46941c77c2de9393d6eea36214c7834d9f6627b8c1958ec58725316b5b2f89c5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010902a41f82d0ec79b619a27d59c1fb40502f04d05e7e5d296a0770b0b2c856107607696cc58d04377ace84c5ecb5fc10000000000000000000000000000000013ec7fce55163625f845d54c359b78bc6e070d22c7132841966ddfe4b3501dfedc11bc58a440c24e818ce8b95e3a55c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a80ef0b44c4bb40dd27b6dba81226f6ef4756a15519f7261b4109305666a39ddf7d2d39488db2146ff203d68589d480000000000000000000000000000000006e990462537f9937a29fb42534400c0ba20d1165576b1371409d654e15375c7f3602b8f3ac54d8e8ee43fb9034eaf001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a61f53a9b5ddab05f17b840da7bb915eafb4b45616ad82f4ac9c3a3da9444cd9c966c4afc1c98e12133fb9483904c1c000000000000000000000000000000000b8ed02ef606539f7af3c5a28c512f15399d7cc0208dd50ae217241ef0baeb248e93004ca1475297c750405bc0c607fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa71a6a7aa4a28aa547d9cdd439764f31c920b32e6055ddebeec07d7c3f1146a36a1e1d6f707411e2daea2060743363000000000000000000000000000000001468a10ec26fa61fb13aabe2dd749bc45117ee0b23c2abfe9593a40beb35d6d1faf87258eddc06b472b7bcc39d8f0d1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6d08308b02c9ed31c8276a8a9309a2641e613855164336f4411dd1cbf8ff072429aa3cdc8c047254fbe2f3cec68663000000000000000000000000000000000d30dbfe0afe28320ba5d90ae312dc38218cfba4f6e79675a79af03e3c2dd3ae6b2044471528a8e808b41ff6a987eb2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c64f85908ebcdba5b886c03d2cd6c05a9a2c62854e5eb40453888dd5e64a19b3453767cd1ddccbbe5a00f7f00df0b070000000000000000000000000000000012dbdc0b7d809bfc1b982ae863165ad39c420b0672e5ed83f9b291fbb6632d5dbc3663feba64a44c80702397adafe80f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a18d50808170ba5008f077d429d08422fe6ccb1e8cf540e9cae73f3ff1fb5ef8ab4d5613b96ec6e58a5587ad987f631000000000000000000000000000000000bbe6b9af1097fabdb10db28c66caa07a2ddf7820717a9260127e59d037cab4b1c81fb2139d6f9d82ab01aab225021881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019903debb88d1ae0c40f21b682c6fba8534341eb6b8114d156d78d9dc5fed28fbf9729fc58f4457eb8ceccba821bede600000000000000000000000000000000061931ee10d3b88d9b119559c077d0c0e79de81c03b5a2b245ad88a01ac646d501b52621029217dacc707797a0fce6271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c18937d2c42ed233e07e05ade84d018455a674487f1c23a3e07768c6212499644de3550e9f459d62218b63eb4f8d41000000000000000000000000000000000166075ad74f83cdd39bbd7a0d5107fc5461cb66d860ab508704f048afa5be811d4e7ca22db03ec9bb9ac5c55a3be5501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019fbceaf260ca9331e0b7412690ab6c1604f71079c961d7129f1e45e54a39bfe89823af0b895ddfb688e3d9da98abe6a0000000000000000000000000000000009cd218fd239e867da696dfda26e1533671c3ad50abcaf08f4c34ab46ca0294cad596be097feb3eb1c6702ca28fecc361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e665c06de12799f5fb97d1bc365538ccaae66ece63012b32a061e6ed95a17210206c6526b3e3f512b90e843e62bb7f000000000000000000000000000000000e884e144a10e6f268b7f3c9cd8ea4641ff131333450cbe46e49ced7dada19222d47ac0c2f7bcd80ae2edd6ce819a20e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e471aee58161dcb711d96f7fb5403829cf8be682fee40da45dd47ba19a8c74e619947ab54af06a09efd518066af671000000000000000000000000000000000b5be4a912f590b4374f863a7bd33e329b89b7d66e8c3ade79de518e4ef1e3be9117d0be2180bb7806c8b9447a451f571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001271cb48885c01b03ba5e85b68e29adaa593f74724a6a70321280f6e7f5623480772277013e0cf9ca444043e2ecf8557000000000000000000000000000000000e84a63e0587eb66cc75e7a77e46ac859c92f9be7c12e3091706939d794d44a067a509d15d0f79db02888b2f38f5cf6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086cf874901f34aaa28d28cbee9916fc0476705424653f6d9825b8d7a4bfa03918924a04575a49e1a46bb77166f22bc6000000000000000000000000000000001073b7bcfd40bca0deb526c0268907cad2ec1ebc016da7f2917e9075c884b69ef5992eb5b2c8ca2e4edb8fed10210dd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc27fb1d25cc01965454246f6f8d88a0be740af5afed68120f97b9e9a97fde1c14a7f0cea14ef051028997664ffaf2400000000000000000000000000000000102fa1cbb91e761d65ebe883bcf6d32ccbbc8b664bf4114e1854eb78d63ef8a37e6c701d706a103499f162fff536b6881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e8b5292559034b1994c913e5326d351d67b0e4432d79f27d9a0bf069a1fd9e0163d0521f213662086f9395a33bea9600000000000000000000000000000000010d9397ce0e3ab166ad9f653e60c664b748a6f52081cd3cc9194e68383d2523d835ce3f05d76f3096fc5366f73d5a7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1958ea2188985b2eb0903324eb47d6dac15a8040c50afa3a7b4bec40251ac24660dbbed2f977c22608ab8d904562ff000000000000000000000000000000001843ff23c0ae5b7c22574ceba00a591f68576320dc75623fa215ae556ecd12ffe3d534833d32e2bbc8c856bab169b9111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000115129df0ff8d1bf8c162f0fffb7288f2e02cdad80b4b0ad5ead44bda5e20d826976fe05646ac8c20caa39fcd042ff4000000000000000000000000000000000816eea927f38d8b4cc162d8773ff5f2a820ec8f18fdf19a2fecf3266943b7a3615010886f164e4cd540b042c8aded681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011782db8a64776ddda8b6e7416c33e1dded2e897dd6c1525ea9a1428b0c9389d94620bbd6ddc24c6c52276e7d36eaba00000000000000000000000000000000012bb2686279148d8f3790d120a28bfa40ae651a6ed5072d3b37fcbdd12c0a68f4a67a86ebaa9e5ffdd82f686e161b7201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001100b2b234d7acfcb1cd46ca6fce1e87aab6ff1762712f57ea7ef2eaf84a19c34271ddd8a8254992ad2f7e0b0ff378e0000000000000000000000000000000000eae719caa53bc8403b0bd11a84493c577cb568730092ffa26141a361b959bdf32ee4a883be76134c8991c0809f93dea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000506fb3f61d9bf27a676aece8786c860739ec5ab672a229b3c562956d7d9ada429c97b6de8a9a9973df0f54555b75a660000000000000000000000000000000004f4eb767fe5e862b6059674562fcc0b070fef344947326bb42c0869e9bc17578714b1ab3b1aa20475fe05a229fe4b861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016152be87ad121f372f5d555c3dd767eba4f654c2bab5af3d9340c1b91c84cf40fbf29a0187a1a59b2bab0f26ee814d000000000000000000000000000000000055d3b29e6dadca2c04464e7b588943d82de86a4c46fe00f6094bcb98ca915a6b1e79e43535acf8931caa1f143fa05621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7e9cd95ce4f2283f8f52b7d870aaf9339e1a492059cba08b5a5b1ac94c7574ecaacb66cf80eec75363d25ef97cc82d0000000000000000000000000000000003af4b2ae5c6e4c9f9396e5442145d1522b6b4630474846af0ef6f2e363c294f078e7047507945c846484b61a116dbda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de0e32aebd4d83afc1dc70ca4d829e5af78836f2bffb0bfda52339968c12ae013f0386bae83ec73510efb889be27f8a0000000000000000000000000000000000bcbdaa1d5f642290d1909eb931dba726ef948a5cb242b9f02c12a524ca0533736ec4c70a4c6c9b4f629fc9ce166b461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009686a75cb811dbc7eb083931bc537d2e33a80f3a36ea7285ce57440bd6f29c09d6056bfea03ff211eb3ebc435d70bcf000000000000000000000000000000000e3bec298626395c71d7a99188f322dfa97937f305d98130a0bd90ba11e4b2cef372b2ce2e1fa435b5ad0077143dbc641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142a6227eb30cb51b2c7af06aa1e86489ea34a90d4e2a0e80164ad43e0d6b5202f9cde5db145f6098a6f24efca5c95940000000000000000000000000000000004751a45e2944494178ab16aff057e21ec0d1f1b7a5b3371fb257a8286274815e20c799230f98d10363274ed121887d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001784fcaa44fa1b42b72a08a49a30cdf8d1a97b7c626d455533b8d36bc1fdad4b429f914950b670f5d14f6f88e3e930d10000000000000000000000000000000011a78bd8602daf61e98dae8c775cdf0f42ca163cd72c8e0735e2642319c9f675b1f52f021358cae7b67d55e259648ad21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017c0f232c8112e8994b7b6ae201125bdb09f5aecfd3ff6c907f44cfca671e668b5f4396300e40cd409019ba083330950000000000000000000000000000000011e8141a04a46fd8cb67f4bcb700d7fc10c8f3bae45310c9644cb7e2e26ef64f25cdcb7cd365e4a2b4ffb37754b0c7ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f629a2ec4713aa4bbe7e29df85bcb3a3dfb49f8de0de1cf90c1a5d32adc5f90ebc104aaa4498ebe20643a49e022765d000000000000000000000000000000001657edfdf0348982f2665d7066a2570341cd66712dc0fc3956b696494f83a02e36c0e3e927470978147897e586d829ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021248a820ef82a119012ba21884c70446e9d353310c7d66d884a31200cc7a0403487ce8f3af741adb29f3a76692b92700000000000000000000000000000000026d55b7c8cf35519b2663b83374318738bb0ed700619c54f2ebd99dfd24086f7e312fd14d572c6e43ceb83209052ed21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015275b54352ae1c0c3ca4fe7b97d083856b3afb389dd3a2e033f1745058689fa29ee7b8e319e00d0c4b185273efc64fb00000000000000000000000000000000030fcb60f49cf77f8d96d6338cf719b36f1a984167d220d19ff925356593fb49165800d5f828e94b7f6e2087610bfa2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165db6631845a685208571e4020758686c7fffcf9aa43999e057e6bbe3c8f05810abc51a4d6014de32b900a8f3a60903000000000000000000000000000000000f92243dda8d5d782da0687e096c2646e335dbfe51427b6ac21b82312741da6a306566dcc4232ab86985395769412a061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098cfd4f949f620b85353db03bce6b58237fdb5212015796f6bedcdf5a40afaeb7780dd5893c8734676f1c897be12282000000000000000000000000000000001864469fd7ce5b6ed60ec7dbb974d7eb015a685c46a6384b9281798ab64ee789555f45a7c47e3508f71b80748692c3f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006000e76cbcc19aff95ea3e600e762fc4ae066fef6b37975e3ceea7cc6e03f281477587fdbd391a2f637ce4cfcf26b87000000000000000000000000000000000e6840e69580e51f3818021a00f22babd53aab98354253a6d9bce3808a64bb6ae24a715629d3729d4df294ac932514831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a3a2453ce024159df7d66a181345a4fefaa8bdcd3e576fb413bb9b8c8632ef423db9d59debd23b79f42353f56ec9d200000000000000000000000000000000007ffe213072ddc642616ec85b9a0736bf019af82a6dd720406a617b67fa238db97e840f1685a5b6a36140fcd65c4c8f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b19d231f5bd56b8e5be9458b493d480e1334d2b9245f3c1116d574171df47cb65fa50d431cd71094fc9862f5213f8e10000000000000000000000000000000019432e129ba3e1b074b3714b2fc309b216b6a93ce4b2dfa778aeaf7950cead749ca88bb837b4821a85322877344be47b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142cb388857366c94d3d345f830347000f01ff2f8d74f43061fcc1c41e43955ba99649cb6cee875b817a07ffa228c04900000000000000000000000000000000161706cb9096f32fb33626ac4e96f7ab0694ee12455c357026cc7d0e9f046db2be0b09b0c6034ce0a4e52d84f50803881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ee6331da12a117303519723bc2c8ec1b4ac4e2772b6db88048261dc8cbd5ae5df00f37b22d6acfe5823ac97a1b9484000000000000000000000000000000000500059e96827a21fe537627a364ad71d1982544a177bd1147c7d330bdbcea4a3a9257e1213ada323682a947638395a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cb49963924fe2807269a883ac92ccb211ef44bce952e25bdb47db464d21f3f57180fa51d9f59a20313a0e79b880f76000000000000000000000000000000000062dd86c04a5db6549fae3358f0050dbbd190f5674f6c716b20aecc638cf9bee65a62a7326503ee9caf8687298f6d371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b43b5aaa9a24acfbb031a957ea5f87ca5ba2569b2ae7ce0fa61b65edbb76c73e54e83742bf49650e7bc82ccf1dc022000000000000000000000000000000000743ef4cfe4a1a55dd8e2a68d31ffacc947247668dfa8b81b159d2a10e46a5698fce7049e3e47c61040ac0acb3b3bb801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013391769860a1f9f861e0540ca8140858108d136ed0e62830cc45cd9b366b9835afdd3b819a85e14442f3064933ffa9d00000000000000000000000000000000097e14246a5e19bf0fe65f2983565d6d2b2fd920d8df49c54b8b5d9cd49b3b220b08e3707cbc16e6a4dae06f104b1bd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174830cde36fc59364fa578eb81f5f53dd86b0c7904f1caefeb35ec10ad0472737d4596e0e8df6b13d3259caa12c349800000000000000000000000000000000031012ac20f5523948ff3167c160da3d4419059b82526ed15a1a7422a83a9a1732e2543ba27291ef110b3409a9ed43dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013225b6520f2584af1fa996602cf6d836ed83bb62cbb24035e07135d9dcc7355b5373080bbe180d74204af4d9190aef20000000000000000000000000000000003ed7a0f97ce73f7889e91087028836e8858af974928f4e7fe769efb2753102f459235480ed7968711e2ea56faddfba41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b2f2fca1306fcbddf02000bca8d1071f3e6b8e2253579208193c4cf64f593754481519ef62b23aa931c853c8df83830000000000000000000000000000000013d202c8409b43b76920af871165908acdb072c0ca049d0e337318beb1fd44e893b99a2722d1a19f65c975e2b88354241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081f10b179f4bb062d9fed04219b89334a283b6e0af4f6266c3d562756e12638990b7069300dd84919df70fc082837ca0000000000000000000000000000000016e6c8e190e62a343e7988a0eeef2fa650f1ad5eb339cbbb5b0ed7e1737ec76a6eb6eea08d2638f0f594764aadd543b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a130655ae07d71841720206bb6cade8accf09a3f1814a5cc437fc863179573ceaea4c59bd2295eb824ac2a28cf178d0000000000000000000000000000000000965ae68d69b1df7862d74d435787e4db5be8e9df24ddef682ab39ba476e57f8650d7a4d0f6f64954ac6813a66e15671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014bd0de07a69a8bb7f91e18d060adfe96c9502cc346952371aaf17f2d6e827414eb5ce325847a5ac610f08c9dcc879640000000000000000000000000000000004f4d323a4036e52eb248b6c252f8e29d924cba934804682f32fd62b23ece955730c73c58b6cb1595cdb06edbdc8d7f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047f966f35ad7193a1543807336215a8af7bb86ca50ff2bc84ed48554e59e29d0fca76285b5dbbc0ce0d5fa91de03964000000000000000000000000000000000be02bb7cf8b45282803c36a3a2543e03948bdaf4bf571111ee914a4c9b50e95b5ab65e20c580747a56e626cb205ac5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098ff6150e8bef0fa9b86c3499f7b7a336a9f429fcd570f6482f74c5a696169a2d243c46d13a36cc544d0aba8687d91800000000000000000000000000000000114ca91b45c040b41a2eda56bdd39054fd8b134b377e0bf9ff069a5e690259110c25e990b24324c7ec65b74eb50337831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000490fde965a94bde43e44ac869e35cf6ec567eea401faa1148ee58c1b03124f1ff0ab3e00e2fe311cec9e9875d0e44f0000000000000000000000000000000000cab21121115383fe3311259f287908ddbe8500c6830d448a7fb1b67aea6472db9c0c72c1eba5e392e387636e066642e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007526063da1733294b4b5cc98db4390f1eaa1c2f20976ef88a68dc9359663b6242aac0ebf4e724c085c0e4e064675c7b000000000000000000000000000000000a92034f21cd22bf7f563fafb53075e8f31ef5f7f7901e258efab4ceec2a62b4c647a7574c916912503039f59914326e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119a6840a7a15b7165264554867b457baee77a1117ccbbf08fac034559ee9ef4b82945bbcfa9958e3c5e08548d6d27c900000000000000000000000000000000095a7fc4cf4ceda1d05719826d14f305fe987a41ebf0c2853488a356341246e5e90c8369c1fbb1deee8b9b10c16f394a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed2ae400a6f891e1de390200dc25f058268f1acef276b5ff78a2f728d97ae6d0e913c8afb6ac6d7b808dff9fab802440000000000000000000000000000000007b0f5cc391dc199c6a2b28deb28d9cc8e4f4642d32838d2721d31d78f98002251611a2b80b4dd695f73327b1f6910981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103d41b6ce4148e421dc67e0542853709a30f978f7ffa0002aaf53f8a6e629ffc2d617ffaa0b5faa84d5dc38d4c59a89000000000000000000000000000000000b325e470c0a7a4c05bd4a183123a982463c077b819694f1677f2f7383aea3e9a32650bd66031d95ff98d2b3baf4a89d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dee204f4115551ae044b63aaa363eb10069f9529ea64879dd81dfdedb035415d1259d5c3ff8faad04ec7145375fff90000000000000000000000000000000018b75efdc32e3fbf5b9148016dae52dc7a44172f7b4e4720760ab0899e063c2d7b03c47848174d00019f5eb105dbdd6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065033c17d112c44858b364f0afdec53d6382510a1ac1387f4b215f47a3cf0c6865eeadd6e582b28ba60ac774a06682e000000000000000000000000000000000732d855828c5a0f7bdea65449de163ab65dddefd750f426e9d5c38065257780d189cf538c04d84c54fd692f4b9bdf231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e1c9230088ddc65f76f039b92d90f68e347aac05546e076110698052dbc1296c457f70b1776a4b28e9e1a2d5d1e42500000000000000000000000000000000127e6f4ca08d3819bd21f9eeffe80399817fe063c3cc999aa02a23f7768faa4a21c6857bbd03062801a97c866d6ab65f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001440546b91e4af2395cd74bad04a3417e0037213a1e62c29a0834f791a424cad624775f3699dad3fe33c0b4ff09aa600000000000000000000000000000000001792c409a941e234cefefb1a702fdd93010c1276fd3a1f798bf09350a57c035ac2db822ef9e06f7e6fc2398761a6644a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173da028dbec940da1aa48dc1f29aede078c968462b596a4f291b53d7524c352886c029d731306fe9b3227d32a2e917d000000000000000000000000000000001113b9d754a449560dedd8666367757cb210a66bbfbb5c58838524166d4c38d2953bcb73b2926be8c3715dea2b3d6eaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185adfbfe50cb40278096c6aec43c99ceb0c1e9c620d5f6b0afc63b7ae898282361b206b4fa815415f402f2f75bb41d10000000000000000000000000000000005e342cda6f9d73f713458aedba664fb0ae2af31072198d7d741b8b2bc0635e503af64b029becb1416c7d65df3a02be01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3db41bfa0b6c681017ba834ec4b34bf22b66ea3aa44053f8f97f1badea1495d4bda737571eee45c9a413d426a2cfe80000000000000000000000000000000003258ff7a8a93b44c1e8d9af233378008e3cc4549a4d9ae38ac342dc23e5144b9afa534a5df4aaae332c02fd1e0b9dbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017185436e9d3ff9dcb88afa9d7a3ba2777e65ab86fd3a92cec4b14e2c332cd80ab579324e41581bd16bc5fc5eec53a4f000000000000000000000000000000000923d216a2049abcf0b07bf901128085cecce233b4b4e879c835a228bff9f3386b33d907b9721c8706562967526295ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143d6c8bf2f9848bff41cdea96dddc8bd005c3b04e814641db49d59c4ac7cece0a33ba5ba515aea2cac2cd8b4f2a08d30000000000000000000000000000000016b65a32810e6cf19061d81eb4a08dd2d10b6e894654379080d53fecaba630a44a4d358554c5db488aa4db9d8866cdd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114ae424bb03f923d4668a249c7246ef5c040330e1812b1507f432dd25fd5e222b8050f5ad24701cfeac17ec66ab85da0000000000000000000000000000000010b1e9887372d31a4e952ad82e97badf5d3010bac27ab9dbaa32fe7af18a4484c4df99831ac21e19e21a0d918a8904361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f096edf252a29855f8c22850558c443617c621f020842fb4597b6c54920ccf1f9072c7ed003680d53d81c28f98aa2bd0000000000000000000000000000000016b0ced51f0f2145722b79d9f41927acf85f02f42e2c7aa63afd0f9078fd017240f8651974b3b396db7651c8cc0f88a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000881386d58225df214e5a90be1ae02366d1eaf6c7d5fe0f1b71f0e58aafbbe03312d04d6e4131a439aa2a973cd9be18a000000000000000000000000000000000fbdd88a8fbe822af7f74ec122e3cfd2d77a041995471d5c5e26298c0b4d788d13306ec6708a0d57d4667bcdf7fe86f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a67b0d4a9ef1d940ea4ac8655167c8b8a6434115c08f23a9f88194439c041761fea39c1ce7150199a5e1ecfd3a40d21000000000000000000000000000000001278e1b63d3013d4c394c7298dd57be96e24f85f6adb22b608fe5fa96e4a1ca1edf5568faa68f41b9d5208cfbaafbb061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f83a23025027e8612fd22178e3a1b4838016b01bb572134fd95283242bc7eb80ce1407631470499ef96092887968e6c000000000000000000000000000000001542ab9ecd7693f86374777166612fead509f07dbed57f544552802bdb6970e823b3190d3332d0df274b172ac0e4b2101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016106e598a6a0b0d1a321dccc8470352067520e1cb1cbced536b1aa609b4e76485d3b70c718710d2d97ffff48be151ff000000000000000000000000000000001858edafdba6a57dc3fc7fe49f5ae600f072e397c03cda9816aed5402ced67232e3cd6a4e413947c0f500500cc02b20c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103a5677b93c2127f73cbeb5029af545437070ec1feba08617b96b669146431a2678c46f834b838658a09212b82c78270000000000000000000000000000000014e66e960ba77b61d693a814ef0d5c6a49125c0367b029fe8ef511f1ad180c876d0a6c2e3ad8e4b74f73cb61d4ea667b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006fbe1fc29df63db20c40459e3810bc4bcb8729e58b57fc508bda7ac9d42a6b37ab3df1a1af773bc7852692640f492c3000000000000000000000000000000000b436bb9103d770fc6b59898ded02e68df5bec60c38b5bd84f3f9ff17e48ecf4664194fa160086badb0694b565f4921f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c38ef67cffe9c4d7e8e00e70d4251f0b03310bef6c07a9d987c761aa5a21d667c339526513b098c0c9c8c37e123445c0000000000000000000000000000000006b9a6e3c5d7657cd8a2d8f8afbeef518e4cd2b5d7cfff23ae6d8800bde79eafe0565cf4f5d83b90d737b795044dc9721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b55fbb936cc1119404f2a85478dd14bc7c29dd42c888eb129e0b1b09163bb1e3b4008c88f672fb7fce7649fc8a90000000000000000000000000000000000004676c40fb8a58bcd17d14d8bdb456dd12f1b30d3684687880bc47e78895bd0588df26ffa09893d2ba7804886d8c12061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ade47485c8efd60d0c59aba153933c19eaf200837e5985df675018f36b07e6b7c5e30dd49ffee2e9dcd24e3583c0f90000000000000000000000000000000003a8a4ba04d86dccf4b2d5796b6715230c4583351f47ac9c3f786cf9c7d39cd64b2748a6eec0c5f61be325a4f88380971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012dfae2b3a536057c98397d9c3f4ce9cf4838038bffc2833db8411a3f27e4cc27254c0a495dc32767d46b73af11b2fbc000000000000000000000000000000000c11b660ba1e1299a93de9cee700ccfe99267ab4071d7a8f601d52d647aeac576460be489177ef6bd0d2ec326f4717881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d9ec1c3735f50a81826e31ab326cfb4d696040be2a38285cba5973961e3f2363b5d213f9aae510f26a13fe9276ae230000000000000000000000000000000006c7383e97027ccaa22b562466c6e2fedb73c41dcc37fc48c113875ae5f4c7042069e60deccae98df29eae60ba9a587f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c4defd5c4019b48a75037914b27c6423fa4f9c68e8b0238872fba21c416d990db50e65f9686c0e4006589a23a89f7f00000000000000000000000000000000042d7a48904098ee36d9f3d64f357e729ba0d2bd34a2e6398c439a1a3969ad8a7a145139e1561e300345bc697a1134811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175b115178d952b7511d70c6ea4ff5d73a9519755f6e705dc52f41dcf10936adfc6ec0aa73e0b2ed28e770608ba6afb80000000000000000000000000000000003666e5c1b7d5943714f3356d81dd18b8e957b8480a3187afceec9c86bac053e498f04878b7710f461d1379500e95d0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d90836b484048de60c572a0022868c8c0a8a4977bcd875e510acaf254814841295c7948dcc4119c628d33f96b10124f000000000000000000000000000000001305c1501c95fddc6f1266327f0969a30a93b650e1274fcbc93fbbfc3dd765914a44709f1e852f9f4fd46ac0da9fda611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000e7adc1971494937db5c7ed847f57a9a6467dcc42ce0cd305d9217bd65d10a97f5e487bca4354ec59785ab5663a1c500000000000000000000000000000000042d9cacaaceb5d12bb0bcc3df40ec26fd67f2b51145d3acb9222971e5523963d2bb3b82d0a4ba336da2e23531dee8e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b1b89a5c9d4f73e4774a46de42358aafa7e27d065cb87f2eda27be6faaf90ae83d62d253e07117231a81fe32d0756a000000000000000000000000000000001075bb70c748fd66fbbe992ad6e8e3a92978cde329b17b6023df610dcb55a605d47bd1421d382c2131550250d710cfbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000abe54cc98f4c0a2ea99844f9344bfe6df769d40c8e94f5b9c47ed193b9f21f49fce1f3c74aae3ef145fb42a825dff90000000000000000000000000000000014149254dceeda26c438805a60843962e6df1ade0260a2d6e7cec572c96675f4545eab4a765642bf8c899dadd472aaf11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003113607082a2b70cf4269fa32e53974c10a4551cb77e42e2e6db89d77c13786cc78394542f3e228b48d557c4dd9c866000000000000000000000000000000000da19cdeb13be6f28cf6b225f07deb091d9e4f3a9b2a804a97b67d82fd67f16bdbe08c3621fa7f2d7ece7b41b483ee621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019256b3ea2de00770225e96dc15d4467bc61517724ba8e5ec48192cd2980e60e0a825d33f4db271dde64dd19d8acd08800000000000000000000000000000000167416f3ef7ee2c5361ce321d97d16d5baeddd4050dea90af1407189c981822596632faa4761fe3690cfc6068f2598da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e360c7a3250430441c47059e538bab410d6a2ec04a54c8c66ef37489d5eb5d1109e994bc3d6577b91a5ec90061a09a50000000000000000000000000000000004102c4d61bdd023b9effedd6f5281522764d1f49ea65755d8f1ed07ab4e0d115b32d9e5e81c1fa2f78ddc7a5f23505a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017dc7ca2d57ddc9f8bb7cbe16e73ffd47dfae9a1bc949213c4bfdbb9474b8f22092d09241dbc91a5630e82a6754108b000000000000000000000000000000000ac7c8b045168d7cd0cd1eea9f8164287b45d2a4cb4ca458034b7595249d22ec83680aa3de53f0d1a466ead95b2da5a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100b46105eea02e91cb6bb5dccd39c05746365ddbfbb736c27987c74f8fd82a076d89ae36d68b7978ee8e8686357e7f80000000000000000000000000000000015017546ad389c8f070d5dde58868610459ee62de83157d7e5a190ddfe129e6cf306c399bbdbb4a6133920c5926773ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d5e9424d25ffe389196d946370c73f74c8d9fec218a33c93562f9d5aa77068056dcba4e0a39337576668c2cdd1ef99000000000000000000000000000000000e32964e0608c964b8a8df2b7ee33aadaccf5a48b37e06161ba69f819f9cb366f4eeb672c718206cdb02c2f547f47b8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3851ca8be318c8a6a865e3b8a28eae24e2d7e5e274de254db81475e63e24e5a759ebeaaa623737dc39766381abb092000000000000000000000000000000000a1bd236e16e9995fa4d599bd76ca9b9958755a5e8f80e20fd1c52053fc4396705d737be433e617c45a3286e8c49c8281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005eac64826c95be4002733e2c74d3d8626afbddc66e01849ffbe9db4a5e6afd167e2dc6c23af926d6845504677ea4aa70000000000000000000000000000000012ceff652cfd03616d29adf426ad190f85be220dac1c68833c522b6e9f9dc323c32ebb7e4616991a5a432d8490c6c51f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f8ef24b2f4064978b73f96e3d2ca09e94091452d832591e2cee38564a8015822047550202c4d09912999c1c2189b25000000000000000000000000000000000ce90f8fc100d6b73f76c1ffed24ecfdfb7a778599032d2ec50e46d8d942dcad8b64ebe3adea226e6ce663558fda53b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188a3aeb6ccee304bc729930f41340b3273faf1f1cee9d4038f2b7e9b9a8aaf06708ba1e7b50b2f87108568d38dcfcff00000000000000000000000000000000165c69d3cc946fbc5c75ed752eee1d19998d2bf37fdab76aa8466f64594622fe7e3175403378c7411eb2d82b2528dfd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173082e0049c271a71ed0be0aab6eb73f0beef04232b3bb4a1e3097ec33ef74f63df992cb63509253698c20b469ca7db0000000000000000000000000000000014953ae5dff61ded4edfff0281b7093b991c62c9601f0aa64e1c1831c9a798e772d8aadddd8652802406261bb5bfba3c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000299da1882f322cb02a59ba81abd852c3e6c1392355db52f9beee8d339a845cc82f1e5f2d48f7909412e523aa5bfc4520000000000000000000000000000000016b5c4377c83434a9c953cdd042404d0786a41bc582e7ecd88d8566e667f8afd6f03eeb437a65f1bd5bb550c230610721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f8b8d5f0e54a2d3b59307471bc79375a627aeb2a53233c1722c56dd32f08b73c50fcca05e2402a5a5ff11013f17168000000000000000000000000000000001194559288dbc2efa842599820b79ec60beb659d15f50d2f8f1958cf369d5c2627e47f631a7474564472e1becabc9d511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b1f86ba54a90315811ebca01995657e54fa5b9832e5a69555199f4ffa356150664b7fc6694d9abc783ac78878e90f0000000000000000000000000000000000ed415e154044f9f186b0c2890ade67e486c401992189dce22cc011defc26bb1274ee9d3e910d5805410e0a0b394b96d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e13daa56faa40714799bf601004972470218cf1f3e22b5700276523953eaf818f98c51ca132db0f6ba2939ffab801400000000000000000000000000000000008f9da63bfe4940890af99963478ad067d85d5846a56a5f731ebb478a069d11617238b6441b5d072fb46755ec66e660a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110aa6fac509f5c020a2cd8dff7afb0fc584f0fe4fb38b32f62c530094653eccaf69b1b66b8cf65e16d5814a745ec5cc000000000000000000000000000000000237a358074639d00681cf993fb1c4d5facb7244c8f2cc7dd4f9cf1bf23582f91a8cdddf893b824b9ab11e51b8fbe4371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a44202404120d12ad00dcb8e3978637b48439700598074446098ee8f5e316ba00fc1bb417b7f68a03e35205d1d34f3b000000000000000000000000000000000dd4abdd77ef7629ac18d4d7a9b7345c8047795228d307d0bc270158d5ff8edaf680fd1c515d24f7741bda33a7c82aa11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006941c95cec9cf89a83b4b6147536df52db8ca2e5510ec2ea369c35caf04a4b61c5eec0abeb13356744d43ad3f9fda330000000000000000000000000000000018955eccf195b1f64ea88de73e6130c495c36c0aea23b57f720936383c0b004337d01cb51f897977766f637be51d07691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000225de0cb0825f7f99b0224da95e7d04144c24c7011300ddbc9831280170dc54a7af1c3f9a0dc2236d3d5d7ff53718b000000000000000000000000000000000030f95ec4fb1ed2c22e75c079f518d005e187e4e056b2b8ad5ecbf4202a71d6ab0c74017323d7ddb3a17f0f6e940469f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3f63df120c777024085443aeaaa51c5f8a462fa987a333d37fcefbe28a891753c6d13417dda3d4578b669b923c4fac000000000000000000000000000000000f11faf44779259ed20eb0be99584a9dbd6233d05d783cd9af6b6af1ab7121b3b51baa3de38af5228ae7765dc3b112411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a74f8331190dc0b7cfeaf13973a69c5ca70a6f7aaf4632fdc4c5ff77705b52334918aede4eaf727cdd57f5081c50e5a0000000000000000000000000000000012082eaef78c5a5c8b8e56e02461898c0ec231b3bad5e34f8472a040ba8e4bfe7ee20aea16a274bfe66b0e7dcaadfbf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b79ada27bd10c66d5dfaf1827a4d87b3c054915be0252b452a03fcc4b9c9182f0e6e8f2cc2510033debde61d5eef47600000000000000000000000000000000073524e0f807bd65ba037268bf87e2e8df7efc1bd416bd62529d74e1cb997a03a03c30f6593c41a8452be8c716c4b9eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008361fa84654132f8ca7782c8d36ec8b42a578b7f23f6dba4d3732f0fa3ebcc062568ed2d23c07ee29d639106833e56f000000000000000000000000000000000dd7689109e813857e37d0759b164a81e78c181193954361f1b028dab011e3f13de92226ef520ba835eb38d7de36bdb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062e6d31218fe6c749ca47efb6688ecbcbe51bc54e49f88908cac1aaf95aac9dc3e917ecd560f6d283551cb4ec0adbea0000000000000000000000000000000005280bd041c289354d8b3751fbe7647bf63c35a2c4508aaed60cbfd5d6d5cd9b2b27bfb39f91d41f7efa539d1d1c56001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000163195c0d7aa2aec805ef88c7c0ed950c4ad12f68324dc4a75451454abed24887a5000f663ab1f06987ff267e0146ef000000000000000000000000000000001784335a91a1ca7f70d938d7c8c11f6221bcb7bb83f4545778ec9aaaf107653603bb842a079c81a953b562c67e203ad61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c84d7150b7966612aa7d21af6d8cacb4232cbcbc0cc12deb08ebff3f0a91627273e7c0f6b7eb3b24bb5156d5f2ff4d7000000000000000000000000000000001099ee918e94b1e965ef755b861e330a568015c96301c65ba4fe41d37c6f9a66a42cb47de4672bed3fa44a5d20a473cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080aff5d354abc56c3c8b3613293bd98a52fff3b326bdc3f1854f9a5270a9ae43be4478b99a965f640bb7af196d9f6ec0000000000000000000000000000000014cb47b9bc39de4a11e7be6c2200df708eccc55efc29e74bbe56f665caa5a562076c35714f55437526a702f0cfc62d741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097ace2dcd6ff27dfcbaff177965dc7d0dbfe354f20bab46096b03db1ade5a8ed1398005e6f8306292e6e649a24c5ec80000000000000000000000000000000010aff1d427d258e471ac08de64fc936805d147b5e2547b84187a6547f19cbc1f43a9ec4d3bb0e21e69597bd4081947181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f0999e7c5a9a1bafeeabf5f9e7de5e91f0f8e7e8b3619b2238c605528168ca452b9a7d231072833cc89e537ac865fc00000000000000000000000000000000046755f04f94f5b7461e588f9342b74be381ba50681c32a9deb36a286ba6ae107aa0db21326790697d9f3aad3fd75fcc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d2a05456a67a946b87027b0b4157fb1a779c6e680f8417f84cd7e4bcf724c55a995dfc10220a7efb230054c5b94057000000000000000000000000000000000c895bad9887d9d2a5722f94623936337610329143bd33232b6b44140df1a813a1a60c83ab0d9f71f8f1fa20a7f61dae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102bc7dba8f07471d065c19645db587225d25b0d5d0a1ec32a169379e60fc6485b0fe04f9b80ebd9b1184eea4812acef000000000000000000000000000000000874e146a80456fd85aa35c1dfef99100c5f74a42143df11b33a9dc3bd45b5ae49230de02b93a136cfb22b3fb557ebd41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058bb9a1600a071b03943f58986d04fefbf06d62c84e034293ce7f3d8e715c55fab5ba70fe9106f6b9bd17ae1f1dba4d0000000000000000000000000000000003e6cf22495e05480b58bb6fe3b656059b06485e944fcf6cc8a651e05484b5adbbc987981e5230b14998e728bf95db731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017354b6f0838e4d55b00ca2ad40ef5bf718cb0f8b3468e5999e1bfc995b9e4fa2dbb10f453921e8e71590e078fedcbd50000000000000000000000000000000012df80f6932ee3ecd9a76df6bf27ac0d7cd238e8b81928bbb2d7ce2147372ae5f5f802b6c58180de92f778056881e2d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9e43234724058802ea856a70766f643b903575511c8487423d92958ecce1da686b7024660411307f0fb90e0712716100000000000000000000000000000000145d45e6146d1600b0c0882feb4eba051fe3c01bf7e4f1963a38c30158b473335aa7059220bc7c7c577ab8d482ca57131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160f1625b8f4bd477f3460f2534cb7eb9028f178fbc95d403040ee5065e72a7c587f768db2119cec13a65335112ce438000000000000000000000000000000000a1bc0cb8681b18439bf90439fb85a9be9638827749bf1b508544fc645ecfd18e83e7e37f39c7df0dc8a4707d43739071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d24c035aac02ae370dbb54de50c65df8d7bb90e6061ee5c3ab83389d6f81e6b5955df6b4d93f4a09d77c936f6474130000000000000000000000000000000019dc107b0b9dca38e813b3a2712d7c0d85ba4d7c289ff25b3d58e0aaeb68c572679d9f41ccda70b503724f1d6e081c631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014322181b436142575babc3693014e785d1c319d058081acd161a1ef6161cc20a31848845518ac5c9160f22dd75ee581000000000000000000000000000000000510c626d87768ee402169783adea593d3711f5ce32e10b611344be273de691eeebfa49f29e0c98d4267ff4a77cc45ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b9e17182810d5c070b77c5a3526f15de26065d950cc4591e01959bb3ae5d363bb8e9c53d7f6a521d0f1c2f2d395d6a00000000000000000000000000000000094673fe6239478f93c35704ff2861a92f257442a9f083283e5e6490d8c4a9375a50b7a444d39e55bf088ae638917efe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019df6cb6d3116126e991aaae3179a83cf53ba338dde3574de97aea48bcc7318dab17987a2b1d7cf1f1dd3580c78765700000000000000000000000000000000156e0344d9fec0f8180a795511ec113ef7476e027270324a439b84371ecda744b9c9bfc51261a5f1ff7248fb81d1b26b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000386cbc75b64113c132fcd8d807c8a12487dd192a31a71f31b903580aeff41e58272904ab3b69ddfe8e86571fcd601070000000000000000000000000000000002d064d223d9fe62ee6d137386e93526051a794a3ff91a003659360a24442d79cb29c066ceb8f20b7b9f7e8a5f93f26f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008075793ecac6c17624cb68562c0679ded37a9a143ff6abb1855865ee6c8e95c31ba427e21457b072104075ae2e74fa000000000000000000000000000000000050a0254bf96db3dddee69d9654ac7819be2b7f650b0f31f9afebf39dacbc66ba619706fad5904aea6fc983d61103cb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018c8fd0b2793c7a79da208ef4b11504734a39f62d62261f2c43d13f5ceacfdfef26753602ec4436cc7e95989b7dbc1f0000000000000000000000000000000019f3ba5f4d2ac2afa2f2a0888e27e80fccaacb8200be4a3a8298f75fd0e9e21916a252467263b41339ec8277a50705e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117e0f07bba9c9e0b92a2e256e91ba3198671d540b45a730dbf9495a6ef0e0aeb320bb847f1de3e24b7750068225fbcb00000000000000000000000000000000111f0e63b21233cc205b47afc460cb38be78999da4c93ba25cada6e7ec6725ab0d0347b487d527f39c23accc9f3cdb921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111ef6da9fc5c9d2d64b8a79d6204a379628b08ae2508ff528a217e803a91b6a7e76a702d48a40f89b96ea4b99433a470000000000000000000000000000000008943286a27cd49b4423ddb4f33ac37573669a1f3019ac2786da0796c14b7f4fd3584c4a95bd0d34a4eb74369899836c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bc096c879840d4cd15d7e5802dba2be47ce9baeaaa8c0c62ee33f9128d906792c831ac2b5963a4cd4903ecedee897400000000000000000000000000000000010c52d58e74d117c0335275fcaefc52ab0b525315ef29d7d50847a0187b6b677b44689dcd486c7dcfbf32865e9179f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e6162dcfaf71b35d02c5c8aea44774c2751902deda9e90f4d9be83965d78a11a32979cd8fc27097b03ce21e3b49f7600000000000000000000000000000000154d9a3392aee248682bf1aa6bb7e3d5e0a4c9bbe59620dc7869dcfb13beba012f5b6ca886d6c02010e031f14b68c3901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019da6bb122e6606f6227f1f9413136aa80a4f5a2e79f2ae02d570b9671d2be92af74a4b4d89eefdced9ea9d6ab4b06bf0000000000000000000000000000000013b681b1692c1b6f5e5d45c0652bdf986240e66be08b249f713ce1f59a73ace4032cb5d0318daedc3f19ba7f5f93a6961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120386e7fdd15633c18a108238cec88b3dbe9d1fd949d749407f4a5a9409a6b7be46c27cd8a09087e6e1fb02f0e8570f000000000000000000000000000000000435920c79d737f800f53801a72e6b95f96d71d743b2b77a8e24ac4ff3d378b6390bf6754449ac160ba18a428e2bec1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f212d0fd42ee5fe684fd7bcbdfb1ac8cfe7b1495f957cfbb8b006b825621a151a082da17a348bb2c7e1a8075cc3bc7000000000000000000000000000000000e19856b79cbd783bb4cb99372466547ef56e7cf597a231d27390906ae935d3ca71a0483cd1916b8107dc4fff5ccce741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d253612091eb02f7d5bbc6292ada98de8ab89f77d3d10dec71ef5d8e5575a613a493dbca65df777b2f7dc142edb089000000000000000000000000000000000e77e496cd62f43b54fc0ec7116c9dc7a898a081f5f0ac7abd7bc220099150bf4fd84fc7af3589f24b256e0eda71df9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fdb14f6de4d16795aaf603d0c90f535644dc2c9391d48adc4d583005a03771e1bc9910f15047706b66cd52a0b9675a20000000000000000000000000000000004a54d32f92ace095430341bef42bdf4d870a784e72eb8093331c8c0653d11bc7fbf28369b5550e14d23acacc2d51ffa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000add75651af869dbad425521b6bd0ce921c2c67be58b75d075e507d46db810c0e8c870e6b15182495197c9c912e9dd280000000000000000000000000000000009da83bd5409c27c58b630a563af5a7babc3db0ecb3ceb6a697fb331d3a77b2bfedd275b7c34fbfd49974533ec6b7f3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000204307d5b8d62e593392795909de84139b0342af7bf62171e445820c4631e904a24a054d5144170b0d1f663efe14aa600000000000000000000000000000000048d5045d0962dd811a1f0c73a78f3b2b7f902c8fc6594b10d2bcb011a8cca0133dc25600f8b565cfb8f60f3849c239b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160b5534f3276c7d3f96e994166882162a79de9d59b11d3452e527b241638965172536432606628312921681f10af68400000000000000000000000000000000113733d67b4f4cb7e2e1e8f94a0eab139760606edca093fdd2c4d637e92bd927cf605b673d1e3130ccabec6f39bb1c4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002c1ade277d3187c4523a4da41fe7c63d7748f621baa8bcc80f7e08db39146c66f20e552d3f0998479bd244e470828b000000000000000000000000000000000c2d190380bd9592f6972e899040ad28b7dfb561a1503d4e0be04244906dbfeb2086831624d0bd073530b6eca5b60fae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003cbea001895711f57724c544e90ad87c1edc69832ed427e112cfa5b3ebe4bbd697b5f01ae12e7a95103c1c7097845a80000000000000000000000000000000011d18278cffd7bcf9e284313d5211d1690ae0441eff747b5cd635ad728078b46b85ede6850ff9965456e8be71c2853c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010dc20b32f6efffddce6de5c41e0cdcd133f72234a4d457ce7f1513df33354f6fc58f2f1911ee260495fa0b616b7e19300000000000000000000000000000000052ab431058cb7d63a07e73a4e9212b0d2b063a8b52eda6de956ec2c30996f37e7dd20723990c29ad3e0a42194f98bb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012999ec0db1401b70dbbdbdfad5d685639982b90e40f27486d52c706fc70847b34af58c1e3f150939c2ff8614c3441da000000000000000000000000000000000adb361227db201ddf96b44f804933772b94899efe07db774ec3312552d04824138a63a221e7a613756996a81c06158e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000269507552dac81ce5075863fe8d41c4b5df57b3f275ace4b42941eebeb713c56311ba35665b1e54202345ee4fb841f9000000000000000000000000000000001353a6f314ce8117841aa5951c38f2452e8548e5453a14d273526029ce9fe166a00ddd4cf72d5aea1e47b2dde52e0c171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf5ffe9e65ce545b1765ba7f35f4ea958ec5fd2e3adef61007055d8f1827a9d6624e9420334764e7414467e28a941f80000000000000000000000000000000002af69ee1f4b84b421331d6dc6020958131715ed9d1bca7a17ab78b050a48d7bc5e63f042557f0cf8da4e8ddcfafaa6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e36d883b6a378e1c61a6afed62702baaaaeacb0c4fe0fd66698f42ed1f3417f7dc047f8ae8258d41a7327eba08046c0000000000000000000000000000000018bfcd932606b55d48167be88f2d12ed86db995fabd30801adc68defb5a5d991afb574c0ad45e7792b68042d3318e3771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000939fc33a76be5a9d454cd698c16225981ee5190d8820430904a8c43654a9a2267464045ef738daca1c46f4d57386aa700000000000000000000000000000000050df6b421416380927eba5a7cb0bb753c43438d987219bd097c6e5ec9c48e76605d01fcf43e2f22c69fe5fca9f9e3f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dda9faa76f41069537f849f579de11c2b61908a97c556ee397b5c5395060a51dffe745ffebefce80bdd99ded62b6173000000000000000000000000000000000b9b5ee1ea775ed43f3cc31721273047f23cdf0a3ef71628b04468c61a8047498db0f49d29ee01f81141c0a731a0b5a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d1f23b937346916736bb4b2868bd2f4ec600d95488d296461d3c07c80c14c2c5a254e0832dc9cca63ccc43531659d700000000000000000000000000000000112956e0c677e02ed2b9ad1b8a4c28aadc5fdb898c2d76ca54f58c01b694dea4f2cc158097210dda2f85105af940b73e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6efd94aa1debc9afff662fe38ebff4a5cf0ed0aa4a225483381ff75304bddd39399eaafc0f21867ba3066f4e08ca57000000000000000000000000000000000d9e31904c9f4f65e8739583d1edafbece6fbdb7703d8cec9065934d2ef63949abf229df0ade203ac5f3b0e2d750dad51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a8c51e8438c89deb9492db14d7ddcf88a9d1f92928e5c5e3c7e2399eadac428e8d99f8dbdeb85681d4038e2d49d43c00000000000000000000000000000000160e5321e9c3016f3b1a8502f395c17b183a6903bc852d2de59e0bd1cc82a822062140b57d9156eb10fa831777877d631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000686968df25f3a1d6d13cb50559bff6dd42f6c78317a7d189a7e4283c4d48dd0efde47960133985dde75b32cbdab03f8000000000000000000000000000000001877ed3e0bc8f16d7dea421c1e7a9b484fe78c65d214b4d73a93f4e70344381c2689fc73fa465ae02f9636e11457e0211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019535efa06d28a93b7b59826d0f4a7fa9dc92bec5c364567075b00698baf8dd4e8881a23f67d3b05ea2482d071d28fb400000000000000000000000000000000031ef5304bdce0b5df3356d57cd3ae796a270b856fd93e7570709f2205b95854ceeeda10ec060fff9de1e44122edcbb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab7830a7f90ceda6f238f8cd7bf882a7cce91c3a0e9750199ef55c85b2484f29da37fd332ac39a0fa435de030bb8000000000000000000000000000000000000829ae2db131e5cecd01125ea7d6cb547ba9809c74fc68df8587921bc01f637abd7cf4d650395cea8a139576460cc66b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000744f517cb9596dc4d9573c3c61c10f7dc3e052d3be58833e9860fd291bd831ef50af29a2dff72d35d7adbfe029099dc000000000000000000000000000000000085670b8e81d6de6070cabfd9785a4e07accd5e171d49932d5a8c6fec59163e361d1801c5a4a27c77daa46801f666de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007f2751987193573936cc8eb78937d51ee031ed30098392d63e392af93f73895cc000bc883c9a57019a3555f8d81d03000000000000000000000000000000000636777afef84b2c03cd4130f70b7ccde36ee824a4a9aeb02787ed27f5ed657e9642a5959bffc418fb66448c44d298da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ea7312a8f2f5d8d652f861c25a4a31d396bf92e08d94ece7045a6598fda44667ce783f0531bd1f7147a290692cbb7c0000000000000000000000000000000017a6d8b4867a4d15ac437d775ab89cf768e921e50e703c9accea84c15aee8626eb051e8e0c41ee2d860639b5ae2f9fec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129d8dfbf6a338e80af2306de6625e062e0475afbbd9b4e4d74c583f0de1b375af92d6cb05da449749a60461c689f5ab000000000000000000000000000000001093e809e4dec4c0d63b18d5b8cecfe1d8bd1f5e5b35f8a3720e3fed97de44dcc8d71cd84440ca048c80c8baf8f1d61d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a28c31cdc6f18d24c5127f3496582c884d6c2765ecd82b1e9bce844bfb7780d89d9d87a92d2d33d8e94d952109f21100000000000000000000000000000000109eaaa89b2dea5af12155c44e0e25aa01cf2b0625f71a0851b57c98dd78214e3d60e452a750a6fdeb8458c899b4a0c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cbaa1aa05f6365e5bd07c7c94b641c9213ecb1d5e00ed2ff0f1a93950af31721402896f8f9f77609abdfe058df385b000000000000000000000000000000000aa6dddb7c46a83c0d4655977afc40cb0ac91feb926c762259016aaeea405628a5187ac6d9d84e1574a6e3f0c89cab3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014cc0d9e7faa9f2e362592b6790bd1194f29143cd62bc0d62ab316292b71a2774803a0b7ab0666923d862b7ff69d01f80000000000000000000000000000000012ba54036a1e35bcd32ddbaac27b3e5dee76293a1ce599c5e9e5bf87e4c0f802426ee2643745dbfeb6354d2affe429f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d0207509e7d0f2dd13213f731fc977be1340098413fbd2ab7c54f2ebb401185a07c4febbcb2ed5ccc4a480551aa0a300000000000000000000000000000000153eca6ae8f272c052a4612ae30d06d93d44ff2bc46d1d224574280b3237d2290816989cd4feef9e9b94f1a816fd13ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074e0f8197ae9b1b4a31e721fe6ad0c2895a41b11bb285e1cb0539a403026c2efe80e4143493db00afd4a72133a86c1f0000000000000000000000000000000003267eb1f9a472763ac1efeaee92b689e47e58e76894f2afdabc33953b2873958ce1a259bca68a0f1880007b11b185f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002259000f06b3fbf09097b088f53e18068e3037b028517c60c22306d95bece12bab7b664b7fb68e71b7b93b6df4c1e0c0000000000000000000000000000000008aa7d7c47d3da648caa39df70f5c41f36e18e8954e32e859b3f6be2c9b49f0d5353be476aa275bcb481aa40ef1c1a8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001525d9745ba4095f7cfe08fb815ac1e89bda89207cedf8ec5853b56d0c795088a56ae454ba0422451cb0725611e482d200000000000000000000000000000000012d4d9738806dd4d26b73cbb6c77832bdd3ce690e93d035d439b01eb7dc459dc18da7804d809af45d6bb69bd7d653b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023d58997b5c8d35ff94e40a26976ac4fdf4c4bcd6cc48dfe519fcd65b50564d41f9df4b5b1cc8cb4a07e163b097ae5e0000000000000000000000000000000004f59956e4999c865c580b01c379e4d3c68c13b85880b8b9baacbd21eb5d13fb3019dcb24dbd6549ff4e96166452d83f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff36f9be04d939cd7ac2dc0d538db15733886ed3b8c0f4776e95f46e155f390ce1699eb7e25afd371fc636029f25cf70000000000000000000000000000000019bd5c1b48002efaac48cf24f184e71390196a6858d59184359e85937eb944e15ca9768dbaa7f77479c593ebe8e3536e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b27d9b13cabc9f9b515cce517559da96042ca0d0d92406737f1d95e5da465bc0a3818a865e715d11dd9da0bbf0a4fb00000000000000000000000000000000120c1d610eea3049d67e43f133c265d92471609b780b890005246f90a6640fb3827a72f16a04b89d3e005d825974a1871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133d2915ebdfe7443d89c8ac69832742435299129a345075d2ebe77557f770bdd2cfe46f4cf83931225548c6bd60457e000000000000000000000000000000000bc53aa2883b13aa7eb9bd0cae4e3d70ccc7bdd221d069eeb1435cac2127278638a4a472627aed5ee48cc4ace75346fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000938665903d30fc0d93e270802b81423d39ab264610d3740c28f7c808ef138f26828f07fb48a502a9995598265ebb57900000000000000000000000000000000035744722a3deda8ec074a62801208e0ca265b8012cd231d8cf1b5710f7c5e481378ce5208b2519b91a091a08a8b5d041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d765593ff173c52b49db1fb3b1bebacaec51852f07d5af1b767d733a85b3a84fdc550df0b6a749da2e6e633b835ce900000000000000000000000000000000052ad9c73567fad6fe1f17041931bd0a0fa72c755b19cfc6b615df3f4ab7dfa2b6232b4c0840ed991a9c1dd76f4e6b161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008fd1155efaba339a4b153683fe1390528e93e144d4cc611aa4df473ff0100a5873eb76b1a99bd3e55d591573ae4176000000000000000000000000000000000e44de38a58170061ac988bf3b5d15d6db629c537e15a5cefcacf4d65f3ef3378a911f142b5f679e91edf7ba4177aed11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec37af4c86def87346fa8d0ac6741074c6c184a19142d72d5589d3eb1d3ec535af4014a3551402332957b1e065460720000000000000000000000000000000010684088134cb1eaecb6dcf154f1475cac9c2ca8394bd037341240eef263f58e64abcb6a17f303384480502bd788c2f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bcc013431c096dc6fec985bfdc51b5907512c07ef592fa97e4b55d1c0c34e3ff62f60517f209e760bf0f1654fac3dcc0000000000000000000000000000000007a6705dfb802b8bbb83d7e5aee2fe32fc8809e664b7a89d08db694fcc2eddf75f6a6f0fbfa5b77686b8e66351b7e2bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174e672d9cbf5135727e4a1c8115ef41c379ee8fa5d8815fb57110a6e946fa43878fa0dcf1846291b438db8019f2cd8500000000000000000000000000000000122908e42064d08853fcc60517880b889f7e7a791810d39c8e4179ed3605977304c5d2baed33b60f18cc432d61f0aa8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029312d08b91687ad0da9bffbfcbacafe745976b6cccdb9b2cfb251a873664dd6e83e3c2540f208e5b885ec66d0a764900000000000000000000000000000000189e547017655de27d90b722a1bc728ebcdc889f775b064c8ed9497c4b7ccd780e335f8d0e9e1d30cab4acfd666e0d1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb64a1d534d425c41b35975facc39a1d6a775bc566a9748cb5a77c94e14d36caad9ac029f0db9a89ab1caeb469207450000000000000000000000000000000012b362f1e7e6ad18dcca8c49681c26afa32216cc46a8192e80e17cdf27288d1642f4b28fc3a34e5d03c3475dc20cebae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047c5075bacfd47298b572ca3a9698d7e2b1948e2754adf83d4d28eb2a5f01435b3d851afe9f89b2aab4fa48b726cd2f000000000000000000000000000000001584a01c0bece725a66adec84bd563e57063881e7154ff82bae17e8ac0de7e471213ad938ddd87a63b2b44199e857a111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccdbb9c4177b9952e168ca548a7e535337075218e0ae5ef1374a9dfce640e84b16d0db7a6b8928ebf0f1fbbe3b521610000000000000000000000000000000001ac558a19dc64be05afde347ba96b710ce93d6a44b2ca6d3e121c5827f6228638fd812e0e4ec601e23549273f121d9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebea2ba8ee96161a7a47c21037c6168f70328e22a8a4a521693e70030469aab9505e1c5d2259805377ec7238285e8490000000000000000000000000000000003a2a91c89109cfe1312b79226c2aefb7b1b8663247b5817587ff22386981090f32c9389ebd160dab0e5e322c3bccd691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a22c4eb3a8fd6a78477f860906208ec9dd9d6ba9cc2b2a68a8245d61a52e81b41eecff0929731806724af16c807fb00000000000000000000000000000000010dc39274387d87221d3b36a1505147537ee4a4d6b0a37d8e725c26fa33549e2923d9825bb47c79d0aff631f6bdc0fd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f1613809eb2d678822986e9d9a47e6716c218c0efbcdcf6e3249440622f8bfb0234111d2ce3fddd41bec43199bd77b000000000000000000000000000000000d948380dbffadad9bd76d19a04f385051343be2365cce283411a97a90bc5c3eacc9a301a7698b93854b84ead7cadc5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171713cbd3ebe33a3ca2930cc7c88db56987c176b7d019c4df75d29e57d50d3e90562a5691e214d0a52928dca66edd4200000000000000000000000000000000028d093ac89bbcc49b212ce990a288d9502b3738ac46e7c1badb3f832783c91da63ee482db107dbb8ac4dff5bafefb9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000093b6e9ea3d375a43108254f6de3f8bdfbf379823bc48afa64f3c91efaaab317328561ecd5765555f41a2980c298ab3000000000000000000000000000000000c3b126edb0cd037c6776ed67a459a2f65cb10e8164ae2cb58a272e81449d05f64111e49f1e45631aa2d1f5f390c94631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ee2c356a74a56210590d5a5fdfb8ada392128a15837646e3c1b5c2f554d213babde53573632fb42e61fc2efcff10a20000000000000000000000000000000019fbe6f59dcf0ad6982c6ddb523d0e2979c68292a50d71025e60e92b32cff4bb9634a03cf69dafe9a355abba41dc3b811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156a978aaf4ad0b7212eb042557ee7e837add87ef683014a736d17cb7989ae1d468fab7e7603907e3c2e43b485745b8900000000000000000000000000000000144b33dd4f07533789c0aecf3b31fd7a13a623e593387973fc2d13a7bc4dfd16607926cecf1b7060283dc40932e92f961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044cd95f78646ece01df935114583df43ccad16ff65b23de01191f2e6d31562f429c1cf224a3b527152f46392649159c000000000000000000000000000000000b45325017cba543e05ce63d068a3ed9e3f14f1cbc69670526a5b3dbf5bdccd9f1b6a19dc76fbef46238fbf3ca8135d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ab7580df53c160768ae3e40444031939e165a63c3e8b4006333ff0754ec737b0774e567cd614513f6b3d56ae93de77000000000000000000000000000000000464f1ef3df22ab0e0598a4cf38fea26456bb36ac9fc97ba6afc7a078735f4028f6f048f0df9d93cc6739dead32abe621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a950a9ff0fb2a6ec2b5428bbe0a70da80b2fd30acc192439f66ca1562770dc5ead051ab9878fdee2d30c9322df7d320000000000000000000000000000000013c6d457a46cb3747c7cdd272a64d44e698458d6b01af33f1659840c22d9b9d805f728b53cfbf882ce338248406188db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e29f11ecb1717706da7f0f8ed924105d1dd943f24016edc5ce7e5867ec1ebb237e7294692bb6cb2709b88b9c60d863b0000000000000000000000000000000016fc034eb0252e263566ddc1a692bdd4d8a97bc5f7f9281681f675a068e0fb6d77e8a92f9199d85094885175a4275f9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000682f53b1e78a700d38917d27039a3969304f043b4e163dcc74d0298e5f8293d217ce863bb69e6c183d9a293a0f58ba7000000000000000000000000000000000a88060199b86d0c1d5a638ca971c188139e4920d21c33adece5825c4acb336466472308788545dec1c5201133c2be5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018da96d262e9ba7b447e03f5a68c54ed757e513d312e436ea33d01d58cff2f1e0ea2f2f9c59209ab330a00a41170a5ad0000000000000000000000000000000006cf4d75383dae7bb7b83d2dbc91fd7a72eec82eba95fa1b0e425c33f82711b4e51db44ba5bc734c4e01960cdc4653431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000119f8821e4fe51fb759ea968d35d214dd63b89a50866ee1cdf5330040b7963332e1085f82f4dfa18302bda702a746c000000000000000000000000000000000152003d4a9a32171df2fd57785058fcc5487ea9965d151c287908db4e8163a71fb333eef4d91a2dc99953b9b1914ac731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aab889c581c59a5185ea72659a4ed8f03a83e7be5595e0e894185e2dd19889cb09b5a0c48246078e2c9a8f8729d05e50000000000000000000000000000000015ea01e37ac7803a89a879166e97dca9c6b96fd0288c1663a6bade53459462ad89121217613d9c54bf16a821e5eb0db11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f29fb94134c120c4fb61d7a90aa43e5e5194d3a41a92ef28e88d17397ffc99302c4dafee3f47a0f81f758016c44dc9800000000000000000000000000000000120715465f8d0f1b55c5d73779396af0ac85cf5fc7a0157549278367209f67b99418ed98ac58b168ef2a6c9f84cac1e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000051192eba0e3ba46a89f434d5efc7b506d5d7b18fa74202c8ceb9a83166230477e8245db53d67bf861b69d7c099fbdd0000000000000000000000000000000018fa8bfd85f3878d0fd826194bc7b63bd8103641ff7fe2d7c2af158c69260367010fa651b364260c325c85085b12e1bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b327ee838cebc2607ed856e2762983b4503b1cc114dfd1840f85d8fc573596cd92b0f8031f33ba0f18bb4a6882afb40000000000000000000000000000000019975b3746b4970a4fe6ba2b65ffa7167ef8b462ef9e09276fcad52d6758296a2f2896f9d1bed1425416c79e7f27b2591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d040836b8f0fd1beef01dcb78c28f3679a6f1c7d49d20d939d78b5d2afc9f8810b22246d991dc7ab0fb5bb944e02f600000000000000000000000000000000004032024052aeca48fc75f68d4057dcab01868c2a9663a61e8c6863fef645bcca35530742b7c2b5e8c1d8b73801aa161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110f3036fd7f990044a5a994d7090d92b965bfded7c173aac71f1c6d9d784cb39b88d1cb7ac7757b9926d0e86cb58872000000000000000000000000000000000c2e10abc4e4e1a4cd78934c57c593830ae5accefc19bae86d380323a128ce3e0d8676831add497c5bb77bb26a57b80a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011cd4f33dd10fefc7cf8e9c97216d8a46fed0a851006dbb38f049be4ffb15e2096d271c5e33ee770ad8d6c9bbd720dd50000000000000000000000000000000015bbac0aa5aaa83e03ebb656f55acb75a941ada612d2c2bf1b1785026c50c09056ec58a84dabfd23196ae45461ad88581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001643d59d2878df98ac3257f3056508553b80699e248841458751048ed3b4f7b50d520108a501d09029988f89d652f25e0000000000000000000000000000000009de02104c72eeb1274c7b1d3024398ce1aaea629044ef4587b4b744f1d536ab2c5618b5a4a6737e6524b3dcc04a3d721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c3ebed669daca862c519ecd9d7d52a1ba0928bc221ea45dbf86ef4609963ca484aa3f41bb7d6bda0c90874349b30320000000000000000000000000000000010b2b46356386ef179939b74a59eddbde29f88f3feb4784f0be394f0d5ec2c197f28023e59e54730f7e4501ba1ef18391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f4fc540c9e9bb5bd2524a731ea8ee835653093724438ae30af940fee5d0fa4ae0ebd215e79a386c63d26924076ca8c00000000000000000000000000000000019df2c0842edc384f40561fc33fa85d413f0836030b7770ee4a4a84fb25c95ce15299767cf2f0b847229d316ce1c1c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a829cb37dd28c5e941171a6e43ed3919a3f7cefe2a1e31b9bf6a84ac2fc089f95c80854b3235b3ba0cbc28fa358a58a0000000000000000000000000000000015dfa67dd80760affe476bc0a2995e36ac29feb084ce6b3410185af654d289518ef6fc55cf6ef42691fa7d20f71d419d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef2bb65a36641ff3965194a8f578ca9ed3036009f89147d63db2c4234cbd41d5dff1fcd9e65055f71dac16be566e0f50000000000000000000000000000000004dd9ca19d72c8de4cb87121a37145e001fda355ff5bbf9dabaede4cbe9002a4ba50dcd0f65ac8e4a59d5e0e34a0c2601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1c16eb8af28434e6a1548e4d256075405a48c3b8448b80b562fe1bc1c8dad1056f6171768a98a72f4268f7e25e2fb100000000000000000000000000000000035154e2631a09cf0dedeebaca68f15f51ae998434ee73d30f16250988ead13dfd4a51fd126e0d4f8675a4015e4d76391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7bf09da9e26d4258bfcbeb38463b15341960451dfc923ff5fbccfdc90cdc76e6781832bc65ec4203d840ffe9f4f204000000000000000000000000000000000cb1c0fe98c51fe9db06c4d9020823008531c9e3b7d95aea44811f89f10045909b5789bd637b60d2e79e2de79e38fb051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008619f14453a135a44e372edb80cf7d9b8d3796f2e3661a3a8dc58bc8d6915c7099a36e6d52f25c215095fd2b8e90c8b00000000000000000000000000000000008c6c5e395249331a020fd14626b409b44005c6c9b6cde5543814444a58060b359decbd3365f7064a6da7dbb585fcdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad7801d28b48167a85d962cbc879781b51594e1cb2b741cc2bb188ec47ac876b692433e5c52d961b8b94026ec5deef5000000000000000000000000000000000dfbfdfaefef632841a8e679bcf1a6f98c6800a52a8406d73dd947be51cd8d100926bf1b49fd843c53699686939fa7ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dbee8a9ac6f7d80dd314618abddd5d6f3dcc6a6db7295d4cbd07c54320d9ce4fd71326049c14bde60cb4525fbf0e248000000000000000000000000000000000d72127908d2368563461595c87a3b65c71b9d078578b4f7ac3f6fe26146389c2a7d244e35e97cae339dc288cca556621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047be5633b0d5e3a7ae598997420a2d3df0c8a7b52f88563159f90edd044d99d587990e5238224ff0e3e0fa1d8e10d26000000000000000000000000000000000f0477e0c8ee6e0fd9f11952b495561ab6b6e2e4da357e2cad5b9bde7b1c01ecd18623fcebfcbd0b4f8ad910f2e2c2f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b8ef64c209d24595d98d3668ba6374a565bb367ba077ab77cae3462a02e0bdbe57d572fb796817a6bfed4397ec9d92000000000000000000000000000000000773d08245f1f970bc0157cecbeedda7bd01b35e2b4a7a7eecba84e81ca630793a7e2905e5c2385ac04408732ac24e831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aeef118721adf15dfc8b4aa3d7f24d25e8e93d09448650019804dd4b3cf542403498f14c0b6d26351d6923f25849b3000000000000000000000000000000000156b3bc736e37b9f403b6e58c5915fd7519a471c7b7b5aa5ce7892a5094aaa827b4822b7b7a282e7771094dda8c139691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000566f225acc9678de46c1bdaa2fe77a18b7eb27e5b4203af35564d1b7974f8112ebad23aca88463950294b6651a40eb30000000000000000000000000000000011cdd1f402bce43ce1cb158bc152a68aad4b5aa4b7c7d3c9f2d0ebde56ff3534d20c9e3244bedc10dd074b1efdd975b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005105380b26cb9bdd08ce17995308d16621c12376ded3569d67c01b48f794aeda3d7d0351407507c184c9a0a68f158b90000000000000000000000000000000012caf0e94634aae6ae9c03baea1ac46753987934a03a157d7ebc454b4b9fe40c134d79bf2b71c3b5c2e2c0446827b7531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d7ea85ef270140d5f9cf89927d756345d2149815e4811318b14b542ff5e0b568ab9f1276f4ab26b4ee1fc7f1a9ccb0000000000000000000000000000000000c84992d8ac6e583201739647b254cb839db3751e3d733abc709ec21ac05eabf15f0583bc81eb3ee7a5f9dd31f3bbaa61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016001a27e7dc197ee240a9093d541170e865f430e0b69b4284299d97ed9f178dc55761209a46b3c012c429b26e9de330000000000000000000000000000000000650c7d4afdd19a5d8a9272ce638c0f6141f3badad71dfd262d6e6f487f3ed5ffba6d083f63dc00fd13972467d85d8ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a103c5dc82a17cac194fce92956c9d005ccf87cbd7ede79d56b1113835ef755666ca0d6f5746ab4fe99b44251da0d900000000000000000000000000000000192604f95d96f38bd5d6827285bd0d164e71b72ed8333f7150b189779920048e04ac9cffe60908fe69de0b6fbb22529c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124dcf9df82674ea54ff745ba6e8024480c103beeaf2cc8f4c5e40bfc31e409d2d92794f3916381cd1e8706c985698a500000000000000000000000000000000052b9b88007f58ff9ae8a2618436c206a478616cf869386b72b0fcec7a09332ca84836907d3706c9740fb473455745151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117b2a3c22e9ec184e9c8998d0cceeb9174b0e2244711e64c794607843941d05068f0b2aad7f2e8d8c0d6e1447a193d50000000000000000000000000000000012554fcea4b00c2ac818a63303288c87e913bf6f8eec8797a1002a53be28838f999931a04bff641efc33426141b77b231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6e99c06a8562d0c80e9289dd12a1bde931c8d3ddb0e4635efa55a81b214d619504a79fac358fc18c8344ffbda16f36000000000000000000000000000000001255c33a9c33fbf95328ecf9193a33c5d4d63df4962288e939387bafbd51040cdf37b9881894a9523fe1112962955e3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa29063860e7d4943050773c233049f309d2ae30ba180e29d348ed6522e5db5b08d6abbfd119f961f837aca7121f3cb000000000000000000000000000000001897cecd6bd872cda410471eeee7365a384340e5aefef39fb581e2d45fb37b0b85b66d31e628b2627a4d7453083254241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000996184b3737624d216f3650b84aa482f943b932722cf719bc8aca5166bef6622926afdaf17119b430e309d5e8b0133000000000000000000000000000000000e638d624c7c0f61af5446c9c7343ce399535c1289ce2c4f91dc5551420997b2d2cf2715a61e2cbf8c2e83dc19f6c51a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a11a0faa8eed18b2146328df63c0ec633470130211218ca88983819c361eb70cb80fd4dbefe2c6c1c9d040fd595dc20000000000000000000000000000000018cdd5506ae40955b4b444303bfb09b68022c1a215b8e065fe808e576cbbf7b096f296d7d153d0a4d5cc4812cfe4f2f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e96ebd31885b466bdbb5d828a47a636578509fc52732d4475aa85d85f74cad516eb16f9d581ea8daa0b96ea5494af300000000000000000000000000000000173d251234dd9e55602a505eeb279359b8da8a78976feb8f6dd25130c149f9963535a14fd72f3bbf3d246aa702d9f04b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e5cd30072b0fbfa00d5598c7450491b030dbb2ff13eec22c13f97c8b9a53aa692918d3f29fb914b6b474bd0b4562520000000000000000000000000000000005858b922bcd4db8c2b4e68588226742cc1af43a7b4a0d428c8479091ba525eff740b8c62f5fa0981f974b834db7f2a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018fa247ddc79645de2835867cfc818809f6a84ddfe0630357371b42e32b9d6a192792b8eae9a580939099631ff09db530000000000000000000000000000000002cc765e0f1bee545c3c55476fd04b5683c81da9fee5d4a8d48bd124e2e67b8081437e22768fb785615521c984483bd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e0569715d5c9d07289d0bee3d0eeb463994d2cb3885ff2c810856f3d8910c88a7415b13ae59c52abf0cdf7f5614c01000000000000000000000000000000000e58335d30de74a1ec71138eeed8f2e65df3d8e2fd228562670e253e5db6297ce5143ff697702e3382551846654c88c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137db28c2d40d3ba5f4ccd8612509736b77b5f229612d3114b7917081d7ef5a0ca03ee160d25e4823ea87240ead566ad0000000000000000000000000000000006a42925bd25877e15fa7dd843ad4babb0705b0b5d37d19c481d87215ea8f866dd424d3a07b11f6d7b7831db4855174b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f8f1d8d64d431be80826670d4f87d04bcde52d9077e36284a2e56dacb2bedaeedd98d32ca26cb9c16e364dbe3b5dc2000000000000000000000000000000001953e86f5df185fd780f46488cc06611c2738c8785acb86c8b4a53efb8fb6f8717dee8dae5f00601b3379eea7e98ef061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001074d846a6806752fde4347ea400039f77b5a242bcc9276366d8628405204c70aeb59bd03c0721338e4b87ee9edff1590000000000000000000000000000000011570d4ff979cd5baf1a8b0becf89aeebc77d39a3026beed2f8b3ee07c94fd24d391d8dda9f65c006359ab67bc5d8c2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cc49cc2cb37d7188058b84a4135fefb3e09b2f461a661dc2cd9f7f1a30ab7eba3620f7b77fcb8380da9dcb9727050e0000000000000000000000000000000000b8f7ea7e2f8c6cff5fa9a4c912cd2a913fe474d9ce2125b6cdb05b00a8305b67fafab4cc4eb3f27574bb38e6032bb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2fa197e604ae7fd31fdd8069cd8369bd03b01e4114dd1bb8d491fd556d6a2f54559a495c54239b75f9f4403437ec9f0000000000000000000000000000000008dbb6f24ff848d19b857f0649357b9cd44986708de87a2a7eccc901a5a181ede8ed4de8e3c69ee876ebafe13bb2eb851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006944e73970d0f02a06d39beac6a14961ed5e0969f3c690b855fc98ff709c09def58675ed0f3ff5756477d7bb8e5123c000000000000000000000000000000000dd082e85a1962e7d5960d26199fac8abc74e85f0eb164f5054cd58cbabb35ccfb821b22cee21575614ca14523c6d77c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161ade03834ec2464e75137b0467385814f90cedd335e69e30b7cb39be84d3fa2663a323355bf7acd88646fbeb883c4c0000000000000000000000000000000011599339a8bf243d320a848ac00386f5d8d4bdb60cc3f7b6598116728e2f2d94ab73c15c45e9cd5f5d8a6b9e31fd3e421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a3b317ccac0354071a3974ce28feccea6f6f71feb14fa764ae80bde043c86bbafa5d4d47ad9f73ff13e93c5948ad0600000000000000000000000000000000173b0b63fee7eedfcf1193a3ec870bae1417239487a4fbc83c7ba36773ca61d6cb92aa86958d25fe1c34fb361c05056a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e362f0bde50f89e79c5d74641d3afd24ac658292280b97d3e50e2d35534364998fd9ce9185b8cf92edcd9c74aeba884000000000000000000000000000000000d27df92d858ad19b40e1785feeb5d1dca13248773c7bddf40360ec874977265236e594194bb480841e0fb2b9b440c371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014eac9b0f3d86a5f30ad7ff365e33f45313ebc1b5b5ff985e575dd6f3d0cf80924af5d1640d25469f8fb1d9ed7b10fc0000000000000000000000000000000000aa3385e750554244a10768a4bca814a93d51d62b2fc92ed0499da9ff864a7644d67987f73585e926da4083a6866b6dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d7e97aa9f5c08e6b3a0ec7c2aa4fca12edc36f192b6cb409bcefc2ef0577a1ba06f9723470015f70e49e922d02cf3700000000000000000000000000000000096563dbf1b11f34b69793a60b46cf20d256e9b0bd3d16160c983010f9eb8d6c8b600ecca4530bfbeabb0e4bf5666b661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000624ec7a4ce6d89e70d23557a1e91da51eaa465e11d872938013ae1f15284610a3c74b4d3ff2d4a258fd67b523070930000000000000000000000000000000006a1e8e1cd6fd18e6f580a56faac6115659e0d3385cd3343369a69b945bd76e7b438535c89ac4d6ffac14a1f9165e0901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000947085c97fc9ef9de91a970f88f0689fb251f205d258a8621b64b2b44baa5f53772b526aacea7a9a74b186cb0f6bbfd00000000000000000000000000000000029ce2f8622a935b9cfae1b19a54a998bf12128a0af2f0c2d304ad497a2d657fe8eac77815882cbc7f3e223895b6ba921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d3990cc9d0851ac93e3d8f9b51a2bb6efb84eb5f5a9800bb9a49cfb71b01d17683795d92b3abe2123473b89d44e5530000000000000000000000000000000013841db289accd77400a61a6d771b54be3ba5f7c23f8618c3bb6adfac4ee0b5d4af8a9b197b2a02abf5aed031c6e47a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011fa80e938f64a5bd0d559ebacf2c0ca1479da9cdd05d3de135471fc03928dfa6cb50cabf89b0699d654d6520af9f619000000000000000000000000000000000c7403b38a37c84682383d86a74477b9951998cfb33cd2e8a9cc69977402ddcda3dddc39742c121f4dc9b5d75a6f817f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2e89d7cb46f202091726904980bb8bf266e70b753b479df561edbea6d3f4ed4cb1477a660f029b6059f82b4a0bb96c00000000000000000000000000000000118772fe9b5ca7796e2855d07c2558eed456dfe1e63821d853d1d2bb830bd7aab7bdffe8b760d434c54b257e38946fcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058deee35fb35298aa2400bca59c257aa8d87ad30559608b5da87eb2ced83ab157849390198a67dc73d61ca072538c9c0000000000000000000000000000000000235a134bccae84fca2465645293c2d0beb755aae310dbe62d417f360ef3d343ef6cbfae588b24787b98f4a202610bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4c23578797773ba21ab789f5f297e08c8471577f61d5364569f04864d09ec73ab8d2221fdba3888e7295dc3a7548700000000000000000000000000000000007fc18d17fd41d04bbb76081c64047a47c52781eabe1775b6336e3916967d38db194bdb52e70378bb80cf4d4efe327391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c933acc1890b4b0097df4ad57bffe8cf753ab98ce76f4497975e56d27032b2cf692600da65f1d3d128cf689aa6ba85000000000000000000000000000000000244c3de4789cf0ea6996911e9e0db614258372fe5fa06b732542fad81182bd6a03dfb956c44ad68b0eb2ffaa1ee203a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001399489803750d0170611d6c26f8e27039b5ea9a982738f7c7830ec47bdb9ac33ea516cca37f1837c7c577acea055d6e0000000000000000000000000000000007a30645d8912d66825a7b7f20480fb9124e6c215bf486d43802757e7e317066e5a8eab7cd8f4f9184115b152274e21b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e85451fc6b30ecf1375ce4fc2a1eea6033327057ef2880e2d44465cc3e2942fb8888ee93cc244fe33bd9d2ce392c98000000000000000000000000000000001005c4059a2a81768622c90f8842ce77802f3d71519cb3c89090f26f8b4c57c3fb4a6f3c114b0fce587760e337bca16a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164042ef1d66f14484fd833d1e794a54eb119e3931d21a4299b707021dae0822787d4767c46824f12da2a210c170e1dd0000000000000000000000000000000012ac6a08f0e36ffe00cc3d5075bde17eca2438f152ee52259ef45ff867179e839a3f7d7d8aced02e71ad59661c29e56f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d4b8499102bb2eeebc1117ef48484a0a17737b0f2b87d171f1ee03b5e7b0c10b92c54f96d99e5e4eef07984c475fe20000000000000000000000000000000019dd0aceb42bf192bcc849cd65ebc13d61d2b4c2746925adf31ebc18f158657f42bc36ee847193b864fb3b4b035552881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112603f370343059004a926005c0cf8a6f641d06dcb0a6a7618b66bbe163cd51eec2e58ce3d878233cfd252d6e3434a100000000000000000000000000000000060b12dac962a0fee142f2117aa050048c676229d524903455b838359610e2870f337dd387a42621d47129528c95c9941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e182c7452b78085584c253265c65557dc2e10739322e1297a3166437d46532db03e6dca9394530a728ec9ec6a6ff6d00000000000000000000000000000000113dc255b64b1907b16f730f81f236f3534d0bf3b678555c94e445600347d13e2e47caaa5d67c854b554c0bca72441381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd34dfc885f5b23b9b28c7f23e6b47f541a2820e627ea86066042878a28623ad745efa76851bdea23b93b34fff075c100000000000000000000000000000000013bcdd250fe6360be808777991d0cc7fa146cec8ee9083d9e0484ffa77c9bf51a00503a5e3816b7d006d1d37bff99591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d2daf32581b961b1f0e4b9b688ecdc7c5a267cf368ca21f1ad1c09a09243da369b792d2baeea0b4f83a973b491cd30000000000000000000000000000000000555ad8682fd20545d74365968fee0f908aeefa614c94c7a5ab534d9ff155fb429dc01dba16b480e38922986f92a6c331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063a8479ef8e3784fa6944409a64cd944c795ef311fbded7a88e62e832ed9732a20cc2fb53d96d3c312ab4a19e99e964000000000000000000000000000000000089f2fdf008f122c5206773d45d1c8532cd73dff3683e639d2481a0702f8d182debd48002707c42496a7f8b370be71d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000053c5c5d2517736a4b1cb1e57ea1de8d5f7cefd900335e6d67b25688962eaf834dfc3f8704c861a851cfb7ccf06620f00000000000000000000000000000000090d69c777da22d03b6e37aae0e44a7c22343f14c30bfbe68af60ef4de1ea3fac8b364c22702eb374ca2d46cfe2931851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5fc05480708ffd20419ea85953e9e52c50450f93d35fd966fd3c04593dcf1ea87b0b3ad80cbc57104a3547c202077900000000000000000000000000000000168ae5840afbb7d2438186f6a8228a24893993d14fc5bf21aa0aad39861fe63341bcc130ff65b5c6ae6e4b5f3580da361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000172ae3ec48df7b20e1f4a17259a36cf81337934ff722f12ce97f08f342f8dea2606ecab6999a29e2514f8d71ac498fd70000000000000000000000000000000014a95019bab52c0c13f66037f12d1331d3bfc479e18b3a4a239a2c28ebfea145851609ad97d299ddf46f8b992e6f61131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce66b2a982b3d8a93df162e5ad29e40bc39cbe3743ce98ff1fd3603c2bcc732bbe7aae6f0a7e9e5c26fd7aac991e7c90000000000000000000000000000000010b1d69af3f7b892478f144ce62b3536d1994bcf0e09a0c9663bac6bfa0e8542f48c511c6828c12ba989ebb184f192d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f3db8918d212f4d3e5468aea53252b468684450a30766ab7ff735a770fb490c3f333273fb0f4e6c0aba8bcc131c8f10000000000000000000000000000000006977b3561c80fcd787f26a6ea575737bf9614ceda908d60092a1811b9803034c17235482330e1d5415c6550c851c8221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ae1f20b0656c0a18a7e6fb67a68e1cc44b8334c127194aa7f4092ceb846f7bc50141ea670673bf0a4a7ddbca8314640000000000000000000000000000000004a18676c13abea760d6830ece56102038927238604839831214c03ba222b59bf19cb9144cc97cf297a5b461208151331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000186c69b362aa531166d1101fb6a5fd36ecff0c3cd22559589ccd0e8bbb8800ef2f302c430e5a219a2c8ad10a7ed02e6000000000000000000000000000000000a29eab1ec0c7a5eba5166c4a7b5962e44d0fd5a284e5026db55ef01f79a60a01a047e87aebedc654299961580160e671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001430cb8efd9117b996ae87069563ccf9d61cc161ac3256b8b4701f8fa4628dc1b950cb69dd54ed10938aa652d4eefee0000000000000000000000000000000017ea67dfd12a132b44a7b18764e13e84682995ac1b4cf6f43e60d65082d54e5382de6fdf0dee69c25c0d099c649cbea01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075eaa8bb63037b20beafc56a5ed2081bc88e618ee72f5923783a8142c148d00427e4bc8dd3f7b747ddff95820404d7000000000000000000000000000000000180117deda01538e264729036514d667994625e3ef1802ca8da33f77b13065e8b97f3ed0b30c7e6a73007c034254ed8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008fdcbd8a2fa2ba32751b5c68b0724d800a6d24e8e3142633b8036ecb2eaffc24972553aa45c0d6ec1db00b9297bb033000000000000000000000000000000000751e83f17773bfd780c8021189731674507b6028b6624bb316a4eb792d833a72738aba1503aa9254fe11fb5efcaacba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010da5a4c6a3fd9b60597d7a657cc0413507f5a42ab0244863c34b2a7caeed0396953e260ec232b7d872988408a76331a0000000000000000000000000000000001de5dc51c1bafbfa59c689a41a1f0ce70cd163e7143a80e14819148934865b2f11ef31af6d02acf487564bad524e66f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000321642be8e91c22b0432488eec4a77a953ad0b41e05cfd465ac6fe4e0a0d8e0d64495a1a42a4aa2af66dffcef063e6f00000000000000000000000000000000112c7e7c8c0021f534ad0138157b61f3f8ac75bcfca4998df0d5b4f9bd0e2a2710c1116ee5dc97a31ab7b3818bdc5e261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136cc14793e42bd8987a9d667e8527c69c910101f70b6aacb0a22790ee5fcac29cb8e3029bdafaf5c5a40183f195d7320000000000000000000000000000000014ab149d778ad6cea6f0ade2f8c2ac85f676fc3b746cce6994b0eb08eada6221fefc558485b1df77a23b36f4abb63b141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a51db5eb3c7d3681413b98d4419b0c8862df5c0f253266d992b6f4050ca156b68456c4fe73b7045b7e810596ecc40bf0000000000000000000000000000000002702a490e5c3f6c6924cc12eaf87a24ba21c188cc5004131fea499ab97664b4c7bf8ac781627a400a0324394cd593841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072f907ae37553832c8aec680d7a00388f9b1941d62c6fa1ba15fd302a50a2d9ef2147fa8246c071567d815112a19e5d000000000000000000000000000000001520fa86c4fd80a11ac852ee67c328f3e0c48e2ce6de28dca4081df615ab24b04aba4d4fceb47d9b1f606d916bc311331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175e26562abf9e622eda51e7eb8e9e821a0af605c68a6c7b576430f5b46d501b37e3af9cd0f633b99b16b1137d6af1bf000000000000000000000000000000000316a049757a032932eb9b55b3a5a3290d30e648f20289c6946623b6ebdf91265e36009da78cb402d87d205fb228c11b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc68ff1e69cda887a9a2d90fdbfb015374b8929bbbc20cd05912b3c764e9084ad94134cce695c206c1181c4766cff3900000000000000000000000000000000022baf28fd8f791b162cf4ee60804d080e7d0ff2633075b29ecca2ecb099ae96e2fe92b667dcef841c747706d287b3f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bd8bdc2cb56b7ade7177a1d23cffceffcbca4c3618436c7c9122db3c3d94175ccbcb358fcac3c640b130a53d4301fa000000000000000000000000000000000e340b7fd3d8abb3e903323056c31e4528fcb82f8bd391ee36efeb09f200922cc95da28703da061b2c61ef3f224d6a5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000484cde22c7cb5c61ae2a4988028f8a941a5fbd98ddd40be8e6645857d04b8199b61ba5afd5e92331bfa43269ae9ee4400000000000000000000000000000000159d88a3abe08620da1565144c9fee9d9fe3683e84d52f3bbd7131139cfb23ed5f9d15a9be939c6992026a067da972d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000256fd2c238779203ec9245d5d5394399ac45e7ee66d24e28a883eaec80db22cb3d40e60c4acbb7d4d9c0723c820c7c90000000000000000000000000000000016219f918e5a8029bf3b324ce34147c9fbdcc999aa67c6425d8232361dae0551c4e52f121731f0c4ac9a3e5de379c3571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e175fb7ce1c45e861ffbb4d6d035ecaefacefd4d1738e4d3abebd22d0cefad4ef2a9d8d1f80e85795ef2b9e5e2bb1d00000000000000000000000000000000137fcd96dc0653c3e286456af1972ee3f59ad1d8455b292fafbe90876189a5020bdfdd1505c8b8a1cc5bd6af908498f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114797bfc48f63ca372403704915b1ab04a01525e39668ad7f96d156947b7c1ddf2e0f912e1086b3644638e5d404ad2800000000000000000000000000000000181fe2b2419d0a2ef70f4c5171b2264c511a708802853a8a8c8cb63e06974db14f195caed54abda2be8e7cc95ba554d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001173c6dff5658f8d2b75e7cc25968b02f8980831035565372cdd07aefe800263db99265b2fea0199a7e0ee86da20287f0000000000000000000000000000000000d9b8b52f1f0f3109045a44d9afaecd71ec0c07bce58bd19818aa85d237af2a25de57d20ee3da29372fac19823165f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a0f18b15a351dea4a7620730be50d37eaafeb0fc420b28b7254b743667af4240506298a5527946f7a167c7af309d5a00000000000000000000000000000000013c4e796f70fc5cd79cb05fad66e863a686d69d1374eff100751d5e0d990fa065ba4eb1598fc91f234a32133c7f0ae21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001752034cdb0feb96aa4a621bda691ddd5c0448140de3a47ec6c05fc4fa95c57dc4e7350b0dec5e708d378d9af8d0fb260000000000000000000000000000000002a5a433a9fc8f438d3dbea44ed81db8ad1602f93b7076b24f234905362f77d9966519188c64de8023ccdbb5ea4522661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d490275de3298c1129f604f8b53425fc15579ad16bb337058c9eddb70f39e68dd512a5cb694e3bb238ae52202c6bfc2000000000000000000000000000000000c96953e74362709ff4e5b7d60169e6132c93db83e1941c017570af346ad7515ec39d24c22ceb5d0e9b2e0e632d50d471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013153f8824353d0e0ac8c2af57b5baa95889ff4d6f4e2e259a350f5d1556017f7fcc853b4f5a756db47316b3067727e60000000000000000000000000000000007851490d90a003a0809bf11687ff1893ae9e7511e3963fb221f09a3cc52b0bb2a3d9dce627fac85aad7705e430f58e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001384bb7a767c1dadcc33c1b91aaa67b09e0febd992d44693abbd423552029814bef690adc6333f79533cd77a5ac688ca00000000000000000000000000000000175a59c13f91865db10bc6ee32dc74cd444e585b5bd0a85334cd4ba834eb0c26370874878bfc811a91df1d9972be43521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab1f8f5ecaecfb036bf799f9067c7723df8b0cc770fc742888efea1f757c337c00396325ab3c65ed53a7078f34fdacb0000000000000000000000000000000016d21d783afb44ea3d7ebf353e222f3def22964bc09b448305696aa635db1fa60c56861470849068ad3c0bef6fff2f3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b04e3d8bc44510a0bef3bfb00d7c9325e0993ec72655c79d29e5a999fc7551c20e61f5711889e92ab0901b552cad640000000000000000000000000000000007d68ccd732c848b9da8d9b5e19da6d017c1d377d1f857421497c897181a86fdef790e22f6c5ab97b9279b808c97a34c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cf67258dc24f1a11d246600138a39156f03d36d500d61d902d21435fc825ae7f20cacc9be4e61a41c8f057c74f313d000000000000000000000000000000000a419ef3bff762b45d3ffd9b785640a2587bd4e445c895464d1cff3f6d8a24c5d3fb638cffe050c5fb6dd0b900ab5eee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025c1a875b3d7ceecb2c858102cdb18f71ea8c84224097cdd701a734ee786bd97a29bcfcc33cda023a50bf9527afd7d10000000000000000000000000000000007c40823f9ab5f90bdae41f46d9aa3e302d12980d759ab0a5da78ef4db6b25a1ff7576d7feae512d2c5b7a00bed137c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071becda544a633a00255a219822ee6305ef4d8a5e425b723e36d5a1ecbb16f6429e72fb6b9f808d1903d9e17a0abddc0000000000000000000000000000000004f573fdd43903c47fdfac2c9f99f9ac01b78aaff42daa2eeebda863331c863e7db8e3ac3f72d0a785240da5bf86909f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f86306ab206922dee831b3aab5b7a66181d8d7165404b0ae204677a82216a64b0a203d9e136aebb1c76295662f207f4000000000000000000000000000000000c4dc92a6df8ec9a3ad498e36fe8ab87aa89a51cc06d2e69d27ffb6904ac95126e7b5fb0383bf3c2bd24d1b889e5158e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a700a22442fa2e5ae2c30bcf2bbaf06f4f83ee67c96272f795fff9a69ba9e8bf15b3d54152be2fa23432df7e4999d570000000000000000000000000000000009c953359926deb190c2a79ea64670f1cd4c2d17748158b5913640b6612dd626040d79f75500d6e461d50786ae9f46c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000003ce2e8b9d4d7f361394fb84ae495806bd33f44c83ccbf78e74db16d4c0121f29e9611e3660fea361cd1d319a2553b4000000000000000000000000000000000048a841444ab64f1cd7256485b0cb0ddd5017115b0e736d85cc1a275615e507c5ffae850f3bebc6de799e2a469cff991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5d6bc13bc9dec3a9661cd0b3e0ec62ec52908ce556186157c6aa05d3ee365bde4598d08828db6036dd48b6d12469c9000000000000000000000000000000000aa8a78f5ce806b1613f8cd0e75af1720ec82e2b9d2d4cb193bc5d11e6b77f0e50fc7e44c6dcf0549290fa799bf184131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167af28735c55e8d6a628534351aa8fa8d51a8d8121add5fc34e529179d2fda73fdda61e826861526aac15aabd59440900000000000000000000000000000000046928ce13d14514550997784e7711033071861c02ca72d0c8d3a3abe0e28d4ddf0f2e917946645bf41889c3a93712831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120b633b072523dc8d9f020ddb3960c576aa139590d88f9e987a80a9a93e6bc72e46cc0bc10283bae675eb8ee4e0355b000000000000000000000000000000000365a56b8df56503ff1a0561c10cf1c5fa10967f8eb9a955acade9b6a70b3e33cf1c09f013c026fee1f6a85ac40747b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd52c72980b228a167ccdac72ceb8921b863b3af6dc0f5897d6b4f63a5daa07f878af1c2af83a3f8ba0ce0db5ac43620000000000000000000000000000000013068e2d6bab3f2c695338737a6afb783a9efb267a8b06182d326204457048066345c15c516709e44b6674e33a0d95691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006fc881e72dde64ccf8825f13a90a45fb9152a5819f00a89ce9ee59aa1b3881ab7dda1060a0fdec719d3873ac269ad3f0000000000000000000000000000000003ae7f502eca903de83b40c44e2085ecd1acf1dbb04e4f26b02770c94042dc7e631afa27a7cdc5ab603162e3787ae36f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000408c7c011857ad5f456512720fe0e90a8c2e60767005bb24fcdaa5f1474dcfcb190cf2d093fccb69a380c8b9d9200020000000000000000000000000000000003c731f7444223abb6475e0b00326cce7ad0506cfaf82b6903c4bced86e634c038730c008b25b9e18f010a45a97626471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee5b47c04bc210c0b63ecac79156fff8a7aadebd9a16f5e19bf083015dad1ed250dbc234ab4e706729d8b6f3971323600000000000000000000000000000000094643015bb491f15b60785ae54f03cd72b176c7999909f921261077a62f2b287e1b2db5371e41631fae13d7689e2d9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e78765c3e5cc3ddfa8c1f1640f4eddec8c1f347ee77fc4a21ac7648bd9faab4e7e159ec7ef084e22aef4a7be7263cc000000000000000000000000000000001211dbbb597bffc5d943f900da60a3e1535792bce11d78aa72be854c1445eaf95aaef08c0a2bcb3f9d1f2358487d1f401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e88f5c73c86d21ebdcbb9ade26d8a4f5b76ffd69db8e24f9dffc66f0bb66fb41f45578e529d77df33d971b2d19c64020000000000000000000000000000000013e6410c5bd08bcc5cad62cceb66d7d078951a37df24b1ab85f3d06e71a3dc67a6989de0f9513f7efd19454f0cbfc7c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a74ceb48485e58fdfa9ef1645d5b565af136dfc646945f1dd1a8e2adc3a07cf5578c9de70e4cd0a40e444107c519d7300000000000000000000000000000000079fc31c9c22e5224e104eb4a9c57178207336b8381960546a2c3f2d3270438ce568c237ac9bddc00c345997182625251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000987949c3d813f0392a8531bb8a465ef3bcd57186fc29948de2eb87da2c197e3ebe540fe86ba9d8d08792a3e59720d0a0000000000000000000000000000000006d945fac065e7a53df12f24895cea038d4a5999fdf481c8c0260bd809a05c3212eac608135e574fec2794ad0c11d8631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d2422130a1d9eae7d048873ec62df88a998f0b858a3c183f074cb57e33a8492a589f0790b2864942a0462ad1ac22ea00000000000000000000000000000000093fd6bd4b78064c27562257529627d098e698afc74c0cc588df5aae0dd318ae6be3f5d1a137feb939e8724eeb12f31e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171b1cd2092d9f62c47ae87df2d2d4468a9505945723d86ad3858cd7fb5fa0799920e75db9acb32ee3de30798b04d5b70000000000000000000000000000000013ea45b878f2cc39e7624474a39e56381f153ed466fd22423378907f61f30f27c5afbbbb261ff05b7ab1735299cc82ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001930e0a06d75f80fdcb7711048460168530772c5ee6d68fa86884cb1fe0d3ff7a2f5fbed10949f5a609b4447da53787000000000000000000000000000000000074012521d510418cb641d6a5eb0fbaabd5a83d999d211d2074cc6129aa575a625c2cde7bc6222c645322f69ff01307e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001507874ba47bfea1818950c9560049255eebaafd30be02d93a49b051ddb952561cf14f6aab3955bbbb2eb74151b8a32b000000000000000000000000000000001814b0f26247042fae1e5c99fe18b6f7d76b12487a823c4559105f974abb5d19ed9749685a63193eb583ecb26761d7421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b971b0951f942037df962d45f0ef2a3f9cd822ac89f0f3bd76007cc2f75c8f024b57182c0042769a13d70b175df87f10000000000000000000000000000000015cddbaa23aaf0be5a9072cb5a963bbcdcf56fc63ec30050dce88ef4d3a58530a8cb30daa28cd6895cf15345529afc8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e6ea808f234c7bae093efade4b59f38c26c873efd3d13dc9a49abc5b55f71a9bc8588934324015651cb3a022a658660000000000000000000000000000000014d6301720d12f02accbd35cee42947e3226cb0b5ecf95654694b203bbe5689ddeb5070d520fbd1cf4e613b4e96d04361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000127e548e7fc50f351eac4c7285dd55e3c11c3054be027aa4e76fa219f732fd72b95aa82c63cb56da9df3f0dad5d076a00000000000000000000000000000000134148977fc3b07ced0a7b6ae69b3901e5db42f51f31ceeeb20ad82f5b7346c0e7190c9d751f356a413c3f4d41318a431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010de422cf373960b0e8caf46859678de69eba51d49b56ae7d7166481897d91a699872a7b68b71b5753ebbe4cade33133000000000000000000000000000000000318096e6af31351fcd11f7059fbb678f8e64e60eb1ee00930b6660774e6c3d5564e246197303b75a7f5ae1490266de41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167cd3f1efc2e212b8cab37728087228c5bdc007efd46a583e1c2bd390d745d7a70efe1d85c0c755946aeee739fa969d0000000000000000000000000000000009922ce7fb12c802e361785377461079a2f350e3691330e06e78f52dbc5423cdec7ce68cba38d472b55f93a67d655e4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010595bbce676a43adb31213ef82327a0e56a3bdc47eca85ce1ab4d0cc7ebb74dfdc8dd494d0000037d74a2445ab696ae00000000000000000000000000000000145747a9d2d4eb7af6bde1e84ced0f87e2758df399122842d65f3bd85098866d4c05f3507a4fede4fd784019c1e0f34d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005953e8f0e419bd853a20b57d3fe46859a6a118adb2afb8ef6a5c10fb1a54d828781eb7099cd8f5cd0aff1e8711e3c06000000000000000000000000000000000418abdbb08122ffb78f03c0b1be480a446df16200bd5aaf246d6517ad1629140547c4985ac70891ea2ffaf2f9b7e8d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001804347a14875450c9a7ba8df26eb6fd938922ebb3df8699f9cb412b696180ec2cc1f96809d57be97eb6e20cd5c1d1fa0000000000000000000000000000000016dab34a31c0c9e29fc4b9ea4584c2c9466f9c25b0b734547b219972dc9011f2bff5b3243f7aadf245420bccd28c2b581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d09b73f38a361d9bfb516837dcc769b0673909d57b5b15cc19c90cfac6d6b9d46c2d4fafbbf5261d00ec8a79632755700000000000000000000000000000000096100e7d0047ed4438937e5ff8b54001d106c53716560a957cf41e8fa8e8ae12babdbfc4922a2ae7be42897241835b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007830e85168902d28512bb54b40bc26317a10d4abfe39e66561f683aeb384b987f18f5c6efe68031e422b256a61788d3000000000000000000000000000000000a50bd090b7ed1fc86def17e97d9e85d109b3fc5791c1f7c24e06c3dab994d415ff5d079fcc5f0c357970e393d7fce421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010436385de1925f47d38d60b487766e48efb5320d07b16063a8240d7e923bb640011ed2c64478525ce9b4b470f4fce9700000000000000000000000000000000054d1dd08ba5b5e6e8c662ec491471bf08f44c16437545c715b7427926ec1d95d42c440f8114ca0f79ec8599b46f64711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b44f5b80c879fba56141768b1ee5ce132b50bc33f618d1063a43b7ca894106f1b81b64998fa1e6f79248aa687a34e170000000000000000000000000000000015b7e15f03aa7d0ab3ffafe56d5c05a0f118a3721c2f19f11494bd08a28f25d812c1e23f20f99f1e9c13df6b4c795e3c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017faf3f6c3a1176c0210ca5dbc1e49c0276bd8cd55289208e93765647c3423eefdaa6328cda5b76ff3feb1d047c1e696000000000000000000000000000000000abbdfb510c15eadc4711646f55f2218bfa5dd3ebd35cf661b065a92becb3957cfeb6788ce04a09a5972bcf709a150e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0a34d29425bce751a063b92a8b0bc912b7b49c914ea04191397fae33a862dac65edc9f39ceda32eb9ee9caee3e99550000000000000000000000000000000003b1705aae6fd19eac9b8d0b183ba872df13b8390d8cc12e58ee46f10f8b885e172d7a91978d30600fd14d94eb93b14d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d83a98d663dd95e6e525adde6b331834cb1d55525f6bbafc843d4e8405ebddb0fd6a55a5effaeea154b10c290b672c100000000000000000000000000000000198a42b2d04812b4c837330fc832d68095d8dfb78f59a57acbb8965c7f3ec0a30078cc27da9aab88d8c0026d815c40431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d8b2a0a952460679ea60f33dfc4d78f68efbb90ab1de69b0c46ef14891d5bc309a5c205fa90f2cf5cebfa91b1982610000000000000000000000000000000018c1afe5958ccf07fde47603850bc4b869bbf6a4aa47a12a9a3fbcf5494682dd8550076e0deea9aa8b1c4994830582831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cdd1a55a5027e2c44b597630b7da0fa2b99ceb3c395e670f9d93ee273d555ee0fb67f6785f2818f22849946b9509bd60000000000000000000000000000000013ed7dd0122cc6cdeedd432ec18ba792ab1927fc34e5218c0dc86c2d6748476f15734c5aba5bcb1735281d59ba7e4b781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013a12002fa37391813c71e1bdb509d72b4d0a8bcd75e43edaff5b556464a46ac299df07e980fba7e604218a6afac22d00000000000000000000000000000000043d86e55be2f4b928f4688a947e3ef3dcb3d29bf35c2492d910410dcd22488af9a3efd17250fc490df5bdca105534351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004cde6b0b705c370e2fe6a1939b1578dd70c43e162e440c2afdf980af34ff327906b0d0422381f1e5186140bf6c5a5a9000000000000000000000000000000000540d6c1c63f5fb9673a3441ccc6990aa05993afc9464dc12c427a8dc4dbf48a3d3e730c798badbb893bfbaed687d8241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffc355eb1b8ad6adc2a4341b186cf207fa027ada410956ddf4bdb7c623c3de2e054be306d5cfe1348a4d0b4fc3e86220000000000000000000000000000000016901665333329601179dad02ef67768a8a8f60a0e99781f61d62b7be4587442bc93a3beeb7e528c7687a00d9e27eeff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011adc291df6d973e58ff3f9b58c495101853a5d12df9e4b4f116155103ea4d87a5e6c0784c01715ee19f05232331e99a000000000000000000000000000000000156b590de71a001beb99d891932577f62947dfa7f20b4e652efc0b634765fa9370d06dcdbe96ad7c1b5340a8f436bd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c40d9a484619d2c689fca42c4ef4a12fd03bdf2f9682822929bfdaad7df70b921e4e651ab5432eafbd82794349872a0000000000000000000000000000000012611ce2124b8b3e231dcbb9b70d32d589fb8ddd4bd209361af18baa4a65b4f9229b7fac6de5da0ed4d1629f153330781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4e19a621f429cec578d3d804b5d19cf4dca940f2c207f0ce260b467405eb727b2941ebf7cf6593e1fd571ae8dd1ebd000000000000000000000000000000001855e5f2e6fe010275492f6ea2cefcf76a9a20952a1605ed32290159d31af43622e9521fe42a24045d1db1ab4e90f4471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a0642f13d7884a2e94b1d2b94f0a201fb6e65baa224fc1567ea43e9df9d0325a28f26ceaa3451054ea44b019f4eb530000000000000000000000000000000016bf52329dc0d73466a1a5eee91f7fb8f793012b4efc35d8a9dc5991268e1cac7df7be00ed19f643a1b9053be2522fcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d22426a53cdbc1a07213295f15fda4fb5bd23562e86aac96d8f88d34442deab8d4ed1daac65873a894a18a337eb04500000000000000000000000000000000139d13673bc021de2b05ca27e9952accd06ce7ae39f9eadc8da8bc2891b87ac65b41b2791cacdb3a1869538a76f1c2e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007494cf434a5cfc491460b7279994779c55d4d89645d7aa40547469984430262c960697c3e34fcd5195a4453c69fe46700000000000000000000000000000000031252a4fc43e92244eb9713690d81f0039862a8c05257fe342c385eac12c1b6a88c52c5a32c03abda2ce5657f4eb8861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f2d6906fb28d14f9382eedd06e70f5ac4147585ea5bc90d9716b4113c9c33a3453211b590eb433b73ac055774a80030000000000000000000000000000000008d99615498d1e43db5a674c7496f7797e42d0af9da79560b89651ef15d02c6c7c8412efca0843132595743683033aa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001be4e3d77a3064014b7c10c8c613b62f0a4dce0fdf0a568c761e87337efb0cb61a18b033eb402728631a4e7eab6a7f2000000000000000000000000000000000592ccbdad457fab8c9ce5962e0d1281c3f0b0c26683a5b7263047534e435ead5eac3d51d0525ad5cbd4997a1407c2e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebdf13af0959060822c881b2e75bc905b3f2824685d2bf1fe8653a945d06f820419c1ac6b1a462ae030c2413ed82c530000000000000000000000000000000015363a3167b6f1199620fd18226631c51ea1ce6b11d49c84b7f314a66d43cd800f8e77690ff79c54dee5e9860a13d24a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191764a011327a7d999cdd60920872e34e57e76696fc268ccdd9166f2256389f38c377c0e9e5102e8dc328b205ff78ac0000000000000000000000000000000008fada840d35d60c17e5b528293f98331eb99387aaf39b5779dbd7adb581cb4e85c4c7d2732d4560fc91997a506fb3d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117d6a0d1f17f56de0c8a64203aebe87bce6a1a3cbb40c47de113de66c131fd0f9fd47b602b87cfcb9da399fcf076a9a00000000000000000000000000000000047b77585f3d8d56088d785633bebed6dfc36eac9fd8f70a78ac126aea72fda946523b3f48f877acbde2f329d59ab9461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178205feabac517d9cc5e34408ab5191d3dcd1770006b25af69b3a852787c531bee914dc06bc5e6fa9c8933007aa766e0000000000000000000000000000000009072b58117c1918bc477ee11bb75dace84c8411e58d8ff930b3a1129c9a62f69ce140ac62e24c85ca6bb804b769c4771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011b18fb5088ffd426fcb3ef8971b1ebdefe485586b41b4f3118c41ef8299cec3aff41bb1235d88b2d23d4cb4547de542000000000000000000000000000000000c07676d12e59fa963fb7c151a999a0d0af29fa78272c83fcb2084134ab72fb1bd347c90c1c445d9141b18e3964a0c621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3ad168e4ee533289f583873ab1a6e06a72cedef1f17d5f410b383a721fc9e1c100cc0b4f4f7bdd31f522d0c4c79b2e000000000000000000000000000000000488eefe5c3cef1320748594cdb7285b7b45134fe3c3db1cc5df8fc0e2c2752168dfad9fa7fbada1a01711e0f18db0a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015864e1ce52c4cf1c413995d75f412b98a5f3f794edacd17b920e1cafb8507a6c29b779dc117d678cf244e8313945c8b00000000000000000000000000000000018bc76a08ab5202dd7b51051e775b14dd0958da880d37818e5c9957f5f73e582a5b8f2316958bbfa96405b31d4fbb971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9e4138a457b2848f666715abc1a7a4461ad1dc6cbb6d012921e397cd51410911377be48c72fe27f51528c4116e3b33000000000000000000000000000000000c8d57f124c6db68190cd119bb309e6bb3e1a4003b9aec7fecc1806c58240accdd242d3dad863d9633be334c08bf19e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c526dd7aecdaf43eb556d00bb1ff8ca15fcaa34f72c69ba86b705fcd57529651290ed3a9492dcc883df16153fcf0680000000000000000000000000000000010426e4e9a76bee4ad2fdb1c35bd58bb52ea361b4de0b5314d2f73af21b947d40f41d8dc65fc368c9a3af8f3d4ad1b571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157b5316ba8ad822a3b54d94c13327e96a3cb1b734546ae28b394de25d21e60a8ee9e9185c74e918860701a1ddda63e9000000000000000000000000000000000271d9e690dbc0f6848630241932e011e7421bb53a7787497cf13083b9495cb323d5c457349d2204de590ecbd982e3a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae31f8fb3c18983c4c77001a5417ebce02fb8e5dd5789f2bcdc5766f1f481081a0cae57da0e34e434a4403333612dbd0000000000000000000000000000000013dd0cab65315b101ef5f4c0fc9435bc6c6ea76ad83b5e639f2a96fc59d1e827205a531b24ed8011cf7d96e1816393f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000983c402cfeb97ce8b71a5cb3baf32a4c449eed362c635525d20b2458ae636b8b7a4ccec97cf6722f1e3b266ee2118810000000000000000000000000000000016c8cf76bed2c1d37ae293b24a97cc421620f2949f32eac66ba1b839d5e2318086f752514f0510fdd1d2ffdd6f8ad1381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001489790ed244c375b40bcac401ba32326621e90a8617862490d394d8943d41a0078aa58ca02218089aaf6edf4bcb610d0000000000000000000000000000000003962c3714b1023bf79fc891836a0c56499a5cff186461ce71d741c437efe59fb114cdea4fdc4fd0aeca19cb89f1f1831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001975862116b6f2dfde4308bb09bd640fb7bf44194431c7c6c1208c018743fb8df74057e426aa882ba561d525dcb2b31b00000000000000000000000000000000152568803be056cec78f90d806426d8f34fefa8dd1e0190035735abe74551f9f48fc7046902c01247e71f56c5fb362121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2f9e8223fc021daad5dd0acdd2b49c9b70a2a7adabfe40aa82e565c2e0d2d393fd847f8170b7da4cb0dcd1b9f81f4600000000000000000000000000000000178845a237f1e6e518f66f69a6b087a72f6f480df9f0be0f33fe1ca3febeae7afceb877fa285ff9b571b4f8f51ce123a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b7f9ff03d6b9bc68c495131707ea7bca29442a1eeb56436d15a3fff92036edb9cb3acc60af335817359890dbe8d1a5000000000000000000000000000000000c70edcb6583a8932705803453e56fb6c043d0889752986a4f538fa7d9dd20216ed7d77276a11d75ff499b41551dd7b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e177a6cd0fae4d0b877e30df63fbaf218a70cfb5f85acf1a5b593454d8c6c25d4984650ea24c43ceea1ca23cfd1f59000000000000000000000000000000001246bfb6d8fbbdd5207658ef05d755720c5df02ab7b886362597d3e000acfa76e1eea44f71b5da1d552676be288ca4411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007161a672c464889f0f1b144791eee1633eb462618e0e7fce25b5acba115e5b27598ab54f29e008d74652b943b6226d70000000000000000000000000000000015709a44de5676ab445f17f704051b5e06c171cb20eb4ba2dc3b15efd88aa757f372440e6278109e006a0b67e8eac6621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000286facc76e251ead7a9e988138d24e3b16296be9de3c93acf2fad5ed190a6d8d666d5523df5d3771bfc2d1fd12dc6af000000000000000000000000000000000f1e7504dc1da9b1e73483271f24dd7a6a8f0c0b16239e5b0db26f53caf6aacff55da0bfbcb557842f0082e6cb2d71f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1849ba4318617e825d9d7af25bdf0d309afa80c7e299a78dc216f622853af7b7e201082f23531116f8ffc7a7ff5c29000000000000000000000000000000000ad2811a9b9abd5a8b174a6e92c3a8aaef72a14c3e146a15e79e62a07309f396e6f4694e79f63a67f2c9fb0bee0a8c791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c547a057c14a7218cae0280fb42d39488c85e7ff55a021534798f59cb45aae870b25df493c513c92f20123256e918a000000000000000000000000000000000ce08eb92c35578b1b0c16e1046e17e93200873d94d3a8f1c19b7080a3b9b2d707ba10b5063ec527b3eb11a105c2754c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102dee27508e1188b018cc34bd3a8eba9d49644eae56d7f38f59dc4a87bbda847026815610782d6508e80e4676de3d40000000000000000000000000000000000f20782ec888317fe7660495663cc65abec658dc7561fb794de45cec69e2973a6459683d69053e30f7ee398e6735afb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001630513a5a4d2f90da3e2a728150e505a285847672d570a783ea98a8d36ea34aca83d7fa85fdcb7cf92415a4d9f64db50000000000000000000000000000000001db66fc8de7ea227119539b621be487814415d6437406a567ed95840d6fb7003fff0a9e820402de7a326e29a6c5516b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040f2f660f633b84c99486ff664da260da39a72c7e337980bb8e3a02ab1cc51ae27776449f9885927b1043e8b73e1cd500000000000000000000000000000000057273e4f164c6ce308bcc67e9721fc099782a5dedfcd7ae7e08719ad683da4a3319e15c83115b1fe4cc188f9b4056121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000095354cfb522435830cd9db532099ce333486d0fd585075fa210a2925745d38db13f8fbb2313f6b587bbcf5a6bad654c000000000000000000000000000000001580b4008e7cd4bfeb8f1990650d4e531c4517b4f55ae4831aae50fc58df62a6067e34407b9ad36b42ee0d86479f2b911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d54b8f0b00ff7369536b1079abeb09ed386412a009f0c93e94d301572ec636bd9c536a9aadc1c5414cb0f92ae269930000000000000000000000000000000008dde6a54941488a969fd9f453690daadbd97aab9fc69efb04b0099baca28195e4f775b524afbbd848a234e3c221ea7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d5f1ef5e7882ca99d5070c96fb12df242654e60f6ab0411192562712ddd67613406964745c3f49392cdaf26cc03938000000000000000000000000000000000c023f521482359a34c1c80ccbbeb2a531d37a7a48aad87be2057546f935cd87b17159a21b195f5659cad8333216770e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b214047316b2052c5492f7afd7f704951420072a7f2e3c5a8f609f4ff2574d859a1fa360923b6b07cbc62565f682227000000000000000000000000000000000b5dc45f2b280e7c8ca9e1cc402ef911181abab0c60b28179fc6996494e1b6f362da6121aa61cfb2467bdedfcc49a7591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d025dc7feda626e4a2879ed537465edc91bc40dff2d3e2e5c9c58e1576b35c162f9bc7bda127ea20b550259109964c000000000000000000000000000000001654a7647d36e4d149b5197756a266c8809c7e8f79c743ca812643c4188c2722d648abb96bbb5dec6fe9d738a14db5381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a14033fb955e0040795d9277e728f624ef10dcb9bd31641bae6b364c696a8f192be6bb2095cc47e02b9de420f807ae900000000000000000000000000000000111ea8ba7ed71b56afd6b20e9d6eb4ff7a5f28a6b6b61aedbd13afc9d94fcdfa99068347f9e529ab7a7c09093efbf91b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c1f364625f6105f62f14b4f69a7bee5ff68b59bd7d15db3b94b3bb889a972d9fd669162b3edd921ec1c63409db34040000000000000000000000000000000007f9373b37fd0e08cc06d7310f3c96e0f4ba3b28f938dfbfd8b1427939e46b37d15a0efc513e9caf3a11e40ac88e82de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000087cd62556a01e8f35df74d8169c4e14542fe1366fcee0935c42732d983fd91ca1a8001328d602a16477b02fa246d03f0000000000000000000000000000000002941b569ea52964993c6e2854a58a239ab776dd013980801e224af4ae0607d50169b048955336a1a9e451bf930e233e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e5d5a874ee067be22db4efcd602ed5e2b168342261ef7ad344cd348985e5c24a373993cb94f83f6c8128ab2d1c67a1000000000000000000000000000000000ebb4ba395f7ff170e7c39bedd5446cc055bd043bae165c4088e47d77ced60d73c1cdc18d2f63342fd6be3bdad0f0b021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2e479ce8bbbfb36ec15e5571fd8f69d7700e4ba1bf85d3cd4db2ace30125ac920736329dafa39aa60adec3318c91d6000000000000000000000000000000000db33edd9b30ad68884e490ac9cde61c8986adc40ef8a1ec9a5b2868feaf1a6d40a5c91466e0802a677097f205bb18531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007131adc37a75f6dab98389051ef15450428cac64df34157ab3ebe4090174c5fdec0abef241eb85c63540511b8e6be9a0000000000000000000000000000000007308d95d4af168c2b35574316f151c562a3eb946923a5e1c8a3bbd62d9051df4ed76b646da7092fbb48fe96cdab841a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc8731839d6e8e852beaba6a163afbff808ceee455474349d8aa0cfb2cee4e728d7825c611c6a1a19213cdb6e9fc6a200000000000000000000000000000000165788ed11583a7e6674c12e6882bda8a33e433ed6d35ffdde07a9a2887b8f9a47ffe6d0ba70407a1173457e4f17b79c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0dbdffc104cd4b37aaaedf99549357fd4d4f4a6d9b32cd0b736f508bcc32b1d9c2bc1ebc041a7a5431b9931c7bac270000000000000000000000000000000018942e7a1135067f754c7c8b39c247230a41dd7a0e83e96ba327b1a113730b1630a6877805c1669819804ed721a6e1391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015bfed9b5657fa59093111f086e6f6522018f1b952eb8995b121dc1e4dc771c864c69db254558d9f9f64d7031eb0fd93000000000000000000000000000000000394775e955df9ca593af08be59acf96d297926d583355cd38affadc6aa87fad24e9473ff4101818b365e17cf82aa94e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbf0cd7b9f83ecb5d55adaec0ef9e7c5ffe712ece8e592121a1b3ceb7ed0cdb6d9024a0199ab6bb9b02b40d0e5ce2440000000000000000000000000000000001f7b6cf489a1cabd71d3ed385b35a544949605c39b9afd22c51c6cc163482f2359fa105ba13233e9e6cf75d45476d501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186ff5bd55cb5a79f5ab753f9c6fee615b3b4a868082bbcce150fdb88828e6be0ffdffdc92b815841cb4ad60d800d335000000000000000000000000000000000ae583adf5f87b9fc446a8ec76be8a02d46f21d05eaf751cc10e4f9c02cef15cc2791ed5da1ad33e1b527979d65523391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bdb4a00c637eca527ce245af559aa43e66064da39fadb7b32f43490cc2bd73e57f92cd15e8a097d5d2cdfabc97de54b0000000000000000000000000000000003a9c9c6b7c1ffd72e20181727855b7c6a54454210e2b59a0c12df69518e36a029c3fe8381538365296b626ae6dd1f881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170588da73ae88b3679010a2ed3920eea030232a1f03672ebd78222763ba22844ab20fffdb461ddef34cbca31584f54700000000000000000000000000000000060340f06324fc2aa4cbf557234fd0b0f85f557a1c3ad8b49eef7726c6a3711135828803be975fd39811021a4f4636b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071a8792b03325090a75f23d4f16a025e16b396e0ddbda1d0e14c2090348635642f68f8837d44782d4c3dbd6376147a90000000000000000000000000000000008e72fddaa45b08b8b577c08fe9f9fd02bb92ae2dad3d4a38512429da1fed97303a849733ddc083bbcb79ccd5d680ebc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043c525002c5f4f5e8f49aa62e3fdabc277a4564a4f40153e139d232818ab2fb67186c916c6f97d34877c2df3be7d98500000000000000000000000000000000050892bf8b541407cc988ba58bdd2a07be559d7e28860de5baed0dd5da3b3c34d8f268febf351adf909fd2e7d809e8171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001389e2dba73f4101f38fedfb0c8844a11899aa1363cbc157abcff6c7a8d9722af103f2d14e1f79f5ec1496f86df37a280000000000000000000000000000000012ffd45436c9360893849c3abe3fc610356522832395f0dc87a3e426e82c680a07e71b7af703cfcfa49570d26fc764d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018a724c8d870450e88a559579860ee1bcae1420649af70163a85b8489b06affdbbf9db2e9d3e3fab63d998c6c2d4fec0000000000000000000000000000000009e6d967282b0b1c526f7857292b062039f1aac4d32524ff940ec9a74722d732c2bcf6a03228d035ee9c64462266c0af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a143cd8141850f8799780e23ca5e88034336b8dfae8b6703b67c3861a86b093838bdc579ec17dfc9c8d511802a8c8b000000000000000000000000000000000876eb539fc293679ff1377a27b4c89969c7ea2dff20a7ef09a4be5ffbe97be047a17eec9d6700f5fa5021dc186cc3011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156aafdd9f63ae738994bb08cf55736e69436e03ca0f0d8cb6b142ce8037dd2ffa595ff5b0a6067dc38ee414349fc4b7000000000000000000000000000000000e23c86d857a63b115755206d1dc40e7e8c8cfa821f04908a152f0c392a6507c2ef851fb3f1fae83e6231296b3c4c8361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036c8f74e376a5f2fa83449080e486a90064343fa81b09fb840084884e18c2e3d2dffcef2f7ff538501a925075a36d340000000000000000000000000000000004e3834c0959e746d540453c98d495c4ae6ed96caf0e43b52f70cd79a35486247f1643c46d901269d662640353e1e3e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017bdf8c57c76a6f4a15fd33720d56dd05c7a436dc22fd9081878f686b7d2d21acf2b1d05dfdbc497690b0e0499535204000000000000000000000000000000000f7818a2cad848cede65dcf06535f99a96cb22310fb26d4f4f49955fc82aff09d36e29ec45524eb0cd068025fd26d7021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c0411793247a2b9080047dc845974ed0684420ea0715e228a65d0ba2f3932b9907134771034cb763bf991fad60cd52000000000000000000000000000000000b2b328219f502b4bebe7073275d3ea6e1428ce9b2145b32c99acdc172d4308a326c4f2ff872509b0a0ec2ba2ac0490b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c52c04cf70056fc6a0d6b8a7c04d12daf5b6c6984940e457659c601bef41f5ea81b3bd373d1ee6d890b30a9a2db737000000000000000000000000000000001879a242b5e492ed5ab41da7a450dfd56442755e0171177e0ec540047033bcb970aa2bd9e515a44f1332d394cca0c78e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000409a783d47da735ab470cb7ba54fbdd4352ab0158c47303120a2f9e07d21c8230709730a9721d89127abcd5293cec4a0000000000000000000000000000000018f5c058d21b0b9f641b6b13f8323572cfc700340a289b13262ec524cb2ef3cd6db4a6b5bd302348148220595a20fb0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097c9a0ac4e005f0c98d906574131f33a92fc04c408e04f4cd5b919d27c7492fb2cc60113e3086dc9583935b82354f2d000000000000000000000000000000000c7f25c7e2e994117a435b2e9534025dfde72d06be9bb1e04d84e7d811166f5b7b7c156789b972a4ac308617ca1c318d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2e8d75cbb13fbcbe597e5a8ee6179dca478bfc70444c3a413c733b9cf41d4a82b1f5cd6e5d526427163bce2ba70ede00000000000000000000000000000000083cfd45903b882b49e1d5f80438f2b436d9ff0b93e666d39835490795b15eac41f938b0616f43fe27f77abe3fb07a631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016dc1c57a8e3d242678e670e902eaa3b6cec8788ce8fd6ebf8f9098966684f3dc0f3c7b7123f61aa81737aa7ccd8d23700000000000000000000000000000000100c4bba1e04d566a04d29aa4d449097b09bb8837f0357291f06511d09bca36b3e483ef5af7ff7fe2e15dba2cb2a453e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086bc22bcdece3b990f534597e5c4a7aa8d60c7d16fc05a4ca6f68c5ce86111b62078d09ac3ae18d898b6eef082562de0000000000000000000000000000000000706eec3b03f9dd3801101dc46995919c18b58bd13775bdea6cbd8b1099d8fe4b0fdffd365a3bfd0fd74a60313f2cba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014405eedf0ad786cb14d13287d027a70023bb0515f7555358942cdff99a3c927024044fd414adb6be6e995991c4c580e000000000000000000000000000000000e3a248ae88b95741090b3ca6757ab934d1ed0281283fa6fef861d3127019dedf14719557bb9850441cb767e4e8dea7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152799b33ae932b6069bd809974f1655f20e8f01bdef67290e53179ebfbe648efbdb9b721c93425e052d8bedaf2e0f8a000000000000000000000000000000000e6f8d037fc48cb48c0b9a6196491df7cbb34eead34765e8e2da361d430d1c47abb828c9880957a19cabbdecca0e68141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4e32f49d801fdb498c30e86d1da8eac849f945d5daf5942334b68afa9a137b56f338fc6f9d6f75d2b6576c0fc2c036000000000000000000000000000000000526b18267fa99042e1df66937d1f0803d344ac0456a0dbf85b529ec35b343ee90d62a2bf6a59aafabc2ce53a082b6561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c485eddbd020bc6810b3eed3681c0795fb6cf487fc7f07bfe8920c47952bf6593c67c30da9b51ea078b0f0ecac0d0d00000000000000000000000000000000167ed7930ea1fe98b81ab1d1e258051dc2aee31cc214a2bb850440ad151756fc2a056c9e202d2a6b9bf8d21518bbf68a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121b4283e782aea757d0f5d69da17d151c3e1880ee884660191f839bafc90daed40ff596e8bc10c144b6b2f4d524badc00000000000000000000000000000000101878adc98b627148cfae69034c17a6346367eea17b0fa6410f44081aed8d5ac63e180c6aa4bda98bfdacdfa8c006101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189086621808d82931e7a7bf38909159092cc4d727706a6e094007cb7211cdf80c079ed1ba07ed118340afcc1dbba65a0000000000000000000000000000000008bff218e8779dd6c3b810579fc1b04672ae0292dc9550b717f71a2328651907bf1dddaf9fe7ec9c8c143111070159171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001615939d43bd7cfd77fa80b1ace0755115ead20eaaaf694a208c219cc67dd26c139068114ab76df03eadac7c0eb9f99e000000000000000000000000000000000c7c50d57f8dd062fa0c109f941d79d9a92f35afc1ed6b9a6ddc23663ecb75e4592554d81fe2eb544e3abcd16b475ff81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000575ce7dbc05f1940f5046ca4ed1e0850e35090ae8cda85d5a2f8421048e8cf850a2deb4752d7e2435ac34d3e62c394d0000000000000000000000000000000004e9c70ba2dff23a31a1a0fc804a24d0c07f201bbd49c985687bbb998bc35c0a8794f4ad1c89105a5dba1fd6b400c8ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c0c8fd87a146b48c6e82066e7afe1e08f608e9d8cc73101e7dc3f64cb933ef849250e6bcf2034ed464d065f230f20d000000000000000000000000000000000e8208495b7c452f3d364e0a201b279796291bafe98b5eb13491a2d4fbd01cf2828f694cf3e3d50c1ec430f6a0c184321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4dcaaa994d8a1b9e0808684d53cb815965dd8b10f5ba6976885ef37979c81df093ef76f447f7326954189585db55ea0000000000000000000000000000000008ade5db3e12d311ea738ea5cd4076f298d41f43117af071b33ee46e18024720cf5ca5fb4e484e4d99931c41cc696a801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010daf97565856be5468aac670357c35ccc56888c82779c2cf0fa4f53ad0782da1b9f2fe004667f770adb6834c330187400000000000000000000000000000000167ceff3e014a8d5920222209600a54d9b10e7741b444a317a7752d8a7ac0e02e8548d4a3fc1babc4903e432a9109b9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f094dcb69ab3035622724606c08df428a55d474d4b437201d7b9c4ff656b1202c82cc0e08f9c88fcf126714cf555b240000000000000000000000000000000001aca84564fe471eddbf081fd7081b39abbf2b06e1e829e5704fce66e1baf51b2075d11fd203ab2a17907cd0ae63cb021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134e94132dc1713678c7554217b49f6977e49bdb1355cef8b266a00d2659870fadacddb11a1381b7744668c6fe6adc140000000000000000000000000000000003fccd8cf77af20396f6b9ce88dc508c147ce7fa280513505b49de549c7c44b7c497d461ef09adfef33087b08386ab0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001034d478d2b26698b0965b1374a95018a1e6218547d2b1a14b71dc9949b1b6d78c35fb8a0a74ad1d4474f09b91e40b8c00000000000000000000000000000000182e84f5c0758e882968b501f9ff75efd28bb8f365bf34bbef5b9a44fa4a6ae0b7bfeca1d2a639e5db21a8c052a033bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003127702001d1eec30574b0395006807eb71ecafbc0ab2ae185d19bbe081245eb8074b370774c471792e06732b5c54f100000000000000000000000000000000176b2ed94a5ce83b326906e68492095981b4b8396e63599305fc262b94560960087fafc99911ceb1beac7fd9277ed3e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dafa652d7aa77a93ed62621b6eab96b8f1f3c00e66dda7f89ae37cf2a076a7941560a850291119efe20e3e90ef45eb0000000000000000000000000000000011a32427b4292ca03a63877d0f6f5e57c71238ecdb1ce91b6bcea0c5603166bb7188f717cdcc37da30f958b348adb9eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001348b9d516f0c89e89db981624072d9589e21fd60ab54c85f6bd54103c37eda77930e4e56c04ded1d9c727b1baf55d4f0000000000000000000000000000000012b7a3fc319473633eceb0b97997c8cebd03dfa229ee9d3b01b3ab095d20b957cb723549c7788ac11441eabf41e9bb671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1042e03363101a5a3136ed423f3c11af2d3b8c7144d357c03e5177ab9c245cb1a995c96cf0822de10be7deb057942f0000000000000000000000000000000018165fdd3603a86796ff650a21c3a40c8646a5a7fd8ef8562d96da4f852f917c9d18dce15addd67268f1a94b58cbadca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d248eaf53fd97624691d1e21cc382de032b64e3936272d9a80bbc8ba322932575bb5f883d0eaac5dd55a64c65476e1000000000000000000000000000000000999a20d60c2e47d9ac518ceda5bd58cf6968c31e992ac36dba000c462657704b147c0d07834a5cf0971fe42a7bdab891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2943eb19aad35fe2cbe8e5d45a79daacf4d61ff07f1bda0fee4247c227d08403600f396227bab2d33ca210902eaf680000000000000000000000000000000000769acad29cb08e653009ada40797ad1202261d2c0a38804cde8887031cffa7e59033b3a30db21cab8148f24d5cbd101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a0c8b70cd672a7e94e9c62d642458bdc5e93503c46ca70017006406b06c8f223bc6b7da7d4b7e03272401612f804bf000000000000000000000000000000000ea392849993f0aedd837600d9aea2c76265090af0fbb3c1eb700ffed994bdcc846a0da2dd76f2c733db5b3f83f7381d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8240630ddabb0009159c2961abb79f493c7c459ab2674d435cdd7cc0c5f6340aba52e94bfc48d7048e6685b2d10c4d00000000000000000000000000000000050e4dbd58647e215a0c9fa22f73922625ddc599b8d08847d8ce790bd48262313b178deb1a4199d7ac61841fca2318de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f988d4d1f6b2c2315aade775d5aa5592f9137e7b9f8376aa1e47b6ad7522d4309bde9c57ae91bdc7f860d71fe92c8b00000000000000000000000000000000065094d38e8d695a28f8b9b7033c66d75c4c08e69f076af0288e98ef4576e032f34a751fdf18486a5703b4ac10127c121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cd4a5f1f33b4ffbf4227ed75e7629ee41395b4416be31351330690847e19a36e6a9bc790ff9f68728dd193cf507e1100000000000000000000000000000000195dea5c5cd2d28bf6fe03ae38b3e18c2d7d98cf49c54e9a556591bf7121d88d686d3f76ccbc5fb502e9ae5bb5001bc31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e15ca63fa6587120a086b42c18182c5a64679781f391f75b4621e4780010e2c47c2447f4e242ea3c569f23697e7f4af000000000000000000000000000000000d27a970d50be8f5d8bc228b50ac6e27013384feebc5d824af5fa2ab763545cb337b62e9e8936857ebd23a3ad0bf8b431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc0cf6cfbf1fc1eaa11556906086553cb4ca1ff89b876f84314664fbd2a5ecdeff6c9151ec55b61d6743f47f8cf4ab70000000000000000000000000000000002de62e7b12a811a814f025adf74916a84bf767a7811cee8658d389e78a4d2386a5ba2011e5f7ea3883d9b014a87bc7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a58dc82488a26b87691cbbd333b73d40efc76efdd3028a71a901f10e2d602693a111479fe9e3b27c268413791ae728e0000000000000000000000000000000011e77d2fd6e3b64d870ad354629d59318cd690b14ffda43fc0ede0b6b9f51ec19c8dbf65c3b1a5d40e571a02066629751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c7fcffa27e9b41d358d34cad14a55360928cf005fa839ef94b117d79d7cf18b16ee9dcb33e36e62b30140b203c5ea300000000000000000000000000000000028c764b32a0302820c5e95762469df9c628938f66bd3c11a788714f95e960a89e2c7b0ce0fff6a00581757c522ebd521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018fffa1ea474fe59598579e370a77679c250b8b874d324b3b8aa094106a9e386915e9aeec85ddf9ba41d94dbc52fffa0000000000000000000000000000000008df80ca9da2f7ee21e62eff3d30d64d680ddbbc3a6699d4b3ae676350bc3d3789b9cffe7f9982449af72122461d46cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f5d5296a1fae3dfc78bc9d823ed5f279da8bcfc311e64b0faf60b91fb93e2ab83bd51d1350d8e08e064dc88e0b3d2c00000000000000000000000000000000062fa1ddad0680c58ffd11ba086ded53d44df2ed4a96d836a87fa6bcca97f489867ab1ab9f43c3f27258aed9e42cb25d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd929fd5b55bec3ba8b775c6ad116089989c862adba26fb5506ab155a953889b28da6945ceb58dc6100e383535877ba00000000000000000000000000000000182ce29d6d39cdc444cb21aacfc97366d6ac43f64618ad2d5ad8575e4def2ff194ce2392779bf9bb235a844f71fd54871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088219b7234b2cfd4d540fa9429d275dd31827d7b297128be304b59be36e0f3352ed67f02276bd200072de97024ba54e00000000000000000000000000000000015cd0e9d3810cae32072af0ab51405f33597ab1a8641cdc83bf40605f61f4ce8042dc02eada07f65141bcc74335efd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a5db56c7bd430d40d937584fd72d1bbfa2bcb21ed86af134e759fc892d9cfa7027d13851a5386c6945081c138d7400000000000000000000000000000000000cede2329f788c7b5536e6ff9ddc4bd8084df25714048680d13221bf4d0a55bf1f6d14ed1e5bb8fceae9c59e501748cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c090a3d0eb2a153e46331b6469b1233be67887019484e32caa319d8d2ac24c88583e87d7e88e3e565eb4a1a8f9a36d0000000000000000000000000000000004da5dd28de98b1c38d3766aebfacb9185f81ca2c5c938a4062afe3c216b5e8ed782cf639de953bd3a31ee4ae6bbea4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f73b74db6e476a55d48f6e3deb0f9f8b3511610dfb5f40e37a98f8f7944a360833b9a05d61f38cf7dbd59d8d0135d12000000000000000000000000000000001765a0ef1041cd0724c751ab7ce7355b663b83b2074db4fbb2ee6388378240721e2c23d1c5f2493268b3d7ffa9f355fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a8e5230d5b4aff6b55bfde18591abaa35c697f96eb7e1aa40857062b050fe74a9edf077e6716808ee41682eac489bd000000000000000000000000000000000bf9e412c2fa57238c035c18ab6cf875634868adb7f6f82cc56fbc16a42ded00a719e3bb8793fdf6a80b0e6b7598c1171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b657f04ca044c1e17dc4cf1f148f8b9a64baf528140d5f3b20b5526cc95548daedeea4ed971fe256f966ae03d5632500000000000000000000000000000000152be8d503a74e84243df796098f22a299a3c0e70b179e259b33ae8a4ace67669f1d71c29d63d65c544f2f0b369e9e421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147cc67d792628ecd3f7a83097b001f52961b164980f41dc610d04c1fe54acffe1d633043a04464036d4c52e02bb73260000000000000000000000000000000017952a7d3fdcd476b0290d74fbbd67462075e0caf2f4c7174a226cf4666b858757a7796e46892fb3f0035ab68ab7c00b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ead79b3196fd00b6fc90770b5452a55e1b20822d0753e8391db1517a867110a7d965583aa623b1c04a722e13e295df0000000000000000000000000000000013248f74ccb81f45a9c4e0e6cfa11ac9e063a3092626261b3ed70a6d53ccd8b566eccc2c08c992aaf006e5c29f186ef91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f85ee6c0eb0eb8059c0a1fc4fcc2589dfb5400093f5edb110536dda4da7ccf01053c35867bd7cba722bef412422f82000000000000000000000000000000000d6a3435b96a1a29d4ec4bbc1a5d721a74e168aa0f8b415a9d9f86e8ba1307aa7a56c77a7e8c3a41d3ead7a528996d891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117d9368bce34659880559ef27824c39a18b1644dc75b88d7c49e59a837c888cf69d2a82536c5297141c8f711c303dbf000000000000000000000000000000000232fa91de22693eb521b73c510c9a2a4c0d3e461ecb04165920247e5e883c326f3fe9362a20b47844695b87b68ac7e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140dd2ee9a4f573da898e33a479d3c0d3c3f55bc8d047564ca527b57f0d31f75760e01ba70dafe75d03e21e960a10a430000000000000000000000000000000013219c141ad8582e61b5675485ee55f8996e9f57954d808def6284762c09214e9d5421495b957372a615e5d6146f89d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5d0afb17dd82e267770db5803481a4006774d596f2a46120f49e162f5855060765ea16be86a298299e8d5e673607080000000000000000000000000000000000a37c2e3886b29ef6eb1be6b258b4e1f7bc060026887f6beecfbf4b01273476010dfa4d367cff00d16c4bde2ae53c071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000abd57068b71935c7b8512e7fb4d6a726ef62ee21f9dde2d772e882a408be7d2fb5a63dea08df2c6b8ab54ac3b90e3600000000000000000000000000000000098097f683a9d83545c410633f6921885c701e94eefb3a7526eabd520e3c31c4744b706873b4a362116d6e56d3b9ed4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b54f67187d9d156b2c2cb19669c7945ea70c9daa365e25e54be7af1051fc84a2b1cab84705354cdbf23cf733a3575a50000000000000000000000000000000011169c31981fad975f4b9fe25e6b3cc47daa7e1edca88af9f3ab3b43f703c169e99b4cff2297d37b3472893c864006f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133afbabb0fad52a9d16bf742480a46b65b623ddc36f0836e3f4d8d7065a5b99a21ff977ab445d0ce93220b9cb07f3850000000000000000000000000000000010f9740e63ef557888f698395215768f2cfe2ee1af56d176c30f722fa50af58b454cee2da5dfbb64378637aa1fbbec181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5e22fc41d88c99119021cac1f29d58f08dd0c3fa2281e52850e1219bbe024c9cf01c5a9ed6075cc37b9cf289df84aa00000000000000000000000000000000042b92aa3d9d7daf59e1c1a454b567aafb836d3e0e9f2dd5e719dc2cfd6294e36e84010257002524d26cf5118bef4d5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c3fe4a1caf76049fa8f6788e89371e41e90fc555e82caba44417a315951f9647f324240745119cc1d0953b740f5ec900000000000000000000000000000000032dd389c5d66b46e25b3bf79621ef45bdde10a14536cff7770d9e5b599e9c5009215b38ca94758c525ca15f3457a2da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001227bcfb995cf1ce71b673bc38f8a4bfed67872617fda83a8b86e9070dad46309985ca5862a011e53f79020d6c3c95bd0000000000000000000000000000000012527f824e925150161ea2fce6100592c2f4a89edab115fb875d8ef6fdeaff37ea7537d52f7947177c676487d93fdffd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012dfcee5353fca783ac968c93482b28e4b2988b83d42beacfe6142d113de23bfbba6abb68540e430c5602987d910ba2b0000000000000000000000000000000002129907efe303fd81ff362a5d9c55acff5ee6bdc4166297dbfb445a393c4d6a7de06b154beeebb73c22b0d99076574d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177c64106aae0934bcbf314c83788cf9efcf3bd7d5a6f933e65c648dcc10cf2b0b1a1610640c480233ff1c34964688b60000000000000000000000000000000012a1a6176176e88228f604bbbd3f721c66f3edb5f659c7ec852d12a83281162ec3e09cb32dbbd28246f81c11174c5eae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119a39c6fd474a378fc499c70bf661f4da7f9c07648c729bfa6acff51c4e578a7a491c2456a3c70b348ecbb9fd066021000000000000000000000000000000000224d34e3affb9cf5b15c22b45aff639234c6073013690cdc3ea08ab64184b0a9546b61e92d47b9d252aca151c2883cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179226288c91209a37735b7d2271f780b52a77c07544f04dff6c17f8017ae7267c70c4be86004f2ba3a59eb8b147faa70000000000000000000000000000000012c36e46149764754f3f8da4f42a4c74f7e4373f2dec5f2f989a564d7356d35efdb25e212c67d21ab06dab8b3fe6e5db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121fcb535a7f9b6b88108351b69f38c708ab9ce7666491e4ef2ab4da348de53ee58e2f970c0e034d702799ee26a52aa4000000000000000000000000000000001986cb4858829a3705693641e2b37da3489a292159c264dcb2aae30e4c57e570aa8ef96005598d0f94fd4b7448ba0d9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e059a037c66b9cc2e7f5c466833ec22d6d645d504fa88ab3f57b9e5376d6d1f48541a9bfe3281f2d05c2991d2e0fc60000000000000000000000000000000018877846020e28b1318dbb7117195ac6ac7b910fd86b2ac5232cf1c6c52630270183c9c0748467ee77ab786d2f91041a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001134052f59346c7607cc01bb78c2a33ba4158337a208878f5fe5efb00700c68c81febf0409a76e269e726315496c74890000000000000000000000000000000001ca1e890af2c3a408cc3ffe639f565a554c1486c5b0124f0b5972d8dff0272a1a531442139c85dbbc16770d07aa7bfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008459c590a02378894555a9398da781d996c7d1f0a4e357b5fb9a01c89e4fb2b52b4b12a3975d73a5639f4ce546f92580000000000000000000000000000000019f1ac7286712bd1fb4b54a23503cd04c9a61819cf94e015cb0a0986bb50895789a4848c8e6a52bc0746f73d6455a6ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000864371bf822c344fcdfcc848b9caf91b9292fcf337826b735b4d251ec5a5bf5dbe915ca7322c90d33e3ebe7ab677ac9000000000000000000000000000000000d628d50ba4747e6f24f28630807f08b110640b7884b482a4537af61d1bdd965d0a8184b83e8590b68897ecaadf802361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9d10092d4b21afabb7eb9e711a69d196da505b196fbc34aedcbf3745b87d23b66c0149aa5464b214d26dcebffab3630000000000000000000000000000000010767acae44d8cdfedb01397597cad56b1a4b070e22a3a408bff88f256009a737f1bffb516e749d91e5bdbd8e59023ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d8ec05cf6e9ba46a64a8927e5055b92051749ed219a878f0da9781cd56cdaaeb88686a259275ee5ed5e58f666bf1c9000000000000000000000000000000000d33a56a2a32bc4d05fa7bf0a6978133efc0ca1c594ebc5af4e887ad82212c426504b203aae1c437b613a4d3067f586d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c917e2e15c0d57a0a6305ed029876cb471fafd0d31b6b116e0973eaa5db4a33e3c596d54023dce9f4f154649ce3ec820000000000000000000000000000000008bf7597f79dd7082eec1dfc0d1980529a59605003b3e33c4bb5f7e3d3050fd950a80f8f387f9b84e1000891d7e962621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cef1368c4cbd5d932749cc0b0e63f17fde656f11d7cee2bc1dadd4f4b5a6e100681651ab79253c0140f68980b9932a80000000000000000000000000000000001461511658a0df5b5da128fa8b90528d8de67ab3399bedd07befc127b79ac25996377153cd7c46557fe2ad53000b48d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc205c10948fbd4d8b38250bbc6f7a463c00b3599b151750aeb87e4dc9de780bba6fce4ac3179200b7dd18be9e040110000000000000000000000000000000012d1959a51498cafc05bc6af7c0b9416b1867d9bbee371a550196753892465647d56ebde36b31b08a51f9872ac989f1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122bc9318be6f05825a149ee22cd55e8b7f899250d76b702f0fdbb856b06bdd629beae4c2f5f4fa60188b6d0295d184c00000000000000000000000000000000070febf1db092f857c365af2cfe718279b6d20c6b01931666eeee3f6ff8709226609854435976fc84ac674d2cb0914e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af5b0209eb702902d9f0817235d718b083647ac608fc2f53238974ace7b183897a3f4d096e91e97f806f8a6f713d3580000000000000000000000000000000004b0c3f4d1f694e536d28bb42a8fbc371372699c6c31041f83ba4ad6f5d2c8a5c1345f8ae112d5168ab00a7dcc7c373f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000070f10d1773484f338125d6d285999e2f9c7ca92e76f1ec5a69d032ca0e97ecf33685ac1ccb31d914f60d2d87a5f1b26000000000000000000000000000000001253ad7e29286962512cea59c7ca879d2b0d1df01c78f7aabb35267a6f1942a9fc823e25421592d0822ea5a6d4e103471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134dee2ac93903288ff36ac75df4fd529e8dcc22dbd2f586db8a2483d0bdda1bc62b470c95bec5df8d08a8610aeaaa15000000000000000000000000000000000887d6d5998a05275c9a62b439654f632288ac527c4c17f091b2d10875955bd214945cf95b3b68538a607a197b292e851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f683010d03aa4fc27d23c4bc85cadc5bacb5abeae2346e4b1c2542b44d32f0ec0e89f428a4d0b8d23500d52b961e380000000000000000000000000000000002981d0be772bdcacf8cec6b3e90f12d4f30f7413e33f772330e8d140269854c177fdf9cfc61a4f41ff9d89dac06607d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e13abb36796776a5bf5d0035caf79ed8b6a4cf8140ebcc2c4b2a071aabe86ae991b0f7304e425f2ea441429b3e71ffd00000000000000000000000000000000122211660e4c0a2d3cdf3b544df85ffbe96fa247c45ac148741a48c43a39bdb184c9633a4670b275d2df745dd2d1a5271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6d694268504ef5e09be3aaa4d73d2523da9113cf20cec97656e45df880e0b3f47a17c7e07da9fdec1f0e7d57ff85f30000000000000000000000000000000002061541aa9e0d9ee7317085f60e06c9481f867c5bebbbce48f1b74e565e1286c9868076329efe69e754df6afc8da1141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011dbf879d2eda244b9c343eb5894abe8c42767a0c306b8edc8ab199bbad78c217233f60fa7ea59fdf47650763d69c3e000000000000000000000000000000000154caae078bfaf2a5a4bfc96e2acd4488a2cee0efb9e30cfe2fc3273035b7322aa6aceabd44fe717157d33efedbfb7811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107f24b70c1c4bb1b79483166ebf052f2f2ecce17a4f594d8a10c914830db9e6f7f855d59b05cd27c46bb8c333f5cbc00000000000000000000000000000000012644665c27c6a90db276572c3c28306315bcdb7c9afc8d3f879ae643b0719bc61d9fae1ce70a6d4775a883626fae11f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab1863d3539e56bd6fca1eeff2e717d2745f135cbcf28f213c9d247bf2f57fc8ad74500d44c20dd40ba700b93de63280000000000000000000000000000000000779fc271569b24427fb1d362ca90895a8fa02c1be293fecc46e9f8238db757b02eff349ca83cca20ebe617dc8d095c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137f00e0a1e7ea7ce47ef1932a2ba6299e34dbfc485439d43a26c769999aa1438bd6ad44deaf0b0d4545df47d89126b5000000000000000000000000000000000268c083eb6634b447699644b76f6f42c07291fe72db258a579294787654a5f3ecc394cc92cb28694642526c838345701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3fe80c3eb8c1a9bc8f32ea4db42ca5ec5c05304257bbc45d23035498a020aebd1077bbf304e63dbffef54765409b0c00000000000000000000000000000000199890fff7a495c52d1912b2d2f7608b60038d9ebe89c11c55b3bbfe1bf8b1bb640d8d502685be987d084439ec0b8f591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d01553abd2fa20c7705503bfeff8ea4adfd6808399adbeb31ecde55f9c0584ca0253db923222ef414b8bb23ba274386000000000000000000000000000000000fcb59c25a7a64b2f6da1f847717f6d94a89175300f03d76e181531a831382ca90b8987750d9405c8c51abc882c332ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125a12c59639d0ce40b883261c4bd5f0e232d7751fa754932ca5d9eb7063422ce562cee8246b602a1fca6e608653cf2d000000000000000000000000000000000249dd8d2326be060496f5f0d7fef68ec891b10fc29149d0b8d21ddb4f1d41b1e61877de162402c7711fc9db3320041c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f28bcf415784395119d3b5c5ca500a807bbb724f62e6146bb75bb07715e663f4a9bc546ff9d325ed2fea8c44f7b554000000000000000000000000000000000bded07bcdb0b70cbff8e069834bd282c0a2bb6562f7e1d261f477a276feb00438ab84d53f3f35e9675f44d3701650731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017782c22a0ec6901414a29aed07b8eea3a50ebd9fbfe0d8a0a2feadc927eade0d3f48e3b39a43a9f89a3fa10f960659000000000000000000000000000000001579254ced0ecd3cdce9478da86d636bde054a1ab6d2ab75c90a639762dcd80d0e09d7b2df0d28898798cacca17a7d5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163c69ad6c491a87555a060f9e1d666e024ccf114affd667c06e694120c6089e015337205e96b389890d3d16022b6f3a000000000000000000000000000000000bf19b8511a6920ab194db23c7fa67a70f40eb1eced346963c8f65789505593e0c3c4da4090fc63411d819c15a7741881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1eb111ada505608c6826a89f406125b1b12215cd037aca9873a827eebd2825acb2d2c1909d022b4b70404d66a0e4b8000000000000000000000000000000000284d829f58e3063d716ccb45794337aa0639c3a7d4e6b9b23d381e8dcacfca88597ab05055aabb32a633fff06ec0a681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c30154e8ead8a42f28c2cd880ded0de9d6a56bd16b14bf872b585e1aaac30dd23c14eaace8012cb1c777ce458dd6f070000000000000000000000000000000010070241584bc05c8842f678b0f1a290aec6a67212d131493a8bbf4cb3d6396ea0accd8bd83a3633407354ce742ce7831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127f465cd2138bffefebd96aad1a1890b773bc3e92ef9f3bfce9b87e039a9f6637f9a04c762030a3c95fb481d23931a50000000000000000000000000000000000d183a827c4f74266b993fbbff76e2582e8c24fc18ff31df7c99d09fa2dbd3f783f7d01ae8b63024a924026863945fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007583ba430066f307434868063bb6750b75ce5703df2d88ff356c678374b8b8a9506d2bca473aac6a9a2b58f9410d2c0000000000000000000000000000000017ec6605f7bbb29e3ea35dc3432a4f29276a8d9988477e849a14c5fa9412a9f32705d4ab9cf30709bf27865c5795384b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6d6cde89a1228d9b78b46871f1a0cdebc525fdad5019678b413b00b79763de15f1a6cb9b729d4426b5d19fb1e43752000000000000000000000000000000000b5a4f056ce2832cb21ad990d6406010a9c6af80a91d636da44a5a8ba197e3a4bf47e21689668499c4241422f0fe0df51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf9edde2c5e0ef173cca5e72237fa34009322216515f2c73523de2f4200ff7c55bd8bf1475ff49cac7a859bc7bf5fd7000000000000000000000000000000000ed48dcfd622af979974665276e9daef0299685d64da8b05339aa981757afbdc9ffe681acc74e44cc78049bd78cd10c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114c626d5a5f97d01d8972a466db9d015a1c75c684349765a25266f48c7460a0ffc3c8c0a1702224449508adda2ac6d00000000000000000000000000000000009d33646807728325dd7f424eb52800ac6f155f12c5fc6ed1189f5937d1fd40aa591a4d14f895f81a3e71c5acf9b83ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000716e761bd8756802ff9c2a6b8a25d195acf82ac99a18dd583c311fa408254423af6673fdd0af20bb54df65e2f8ca3ed000000000000000000000000000000000b6657fdfd9d3e58a83cb777871cb795d68d24fece0986d14c70369bfe804f12e44d1dbcb66a999f821c79f54e1da8021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c3093154401ae35866793516c006d7bb89b1b40d0b69dac5bb39503ef6c2eadf18b977e64f9051919435f4fa35ee5b000000000000000000000000000000000fe4843ccb9a13953775b689c4f24cc0c846c674d8c09d747847e1994f4247620d7d4e385f2eb690ecac8f8ce1f433111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b0f635346328719bb8e3368c606fec67423ab701b4c846df8587e0afac91a99e5a17655905e4639069b044b821ff22000000000000000000000000000000001018f5e0c0d11018a90a1106d31f9cf41c9f011ebfac0a9dd4f98698ac39276a0253a23ccf5131e0f28aa717d175daf71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000162a830f6bd3d39a1569c2dd63331d5deb433c896c0410e8601a3b26aef037de369e8583e8b2fcbb2a6ed8be94480074000000000000000000000000000000001054b7f65503aae3366f70be50e667c17934449eb48babf075034e4ee63f71a938019a3cbe29fa547462d7c367a679bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190bfb7a0b49c8f583e4dc8b38ffcabf4c4488ddac0c03ba579bde6113b650bb469c67b35b7b3330ea12a4d8d8a19494000000000000000000000000000000001881f114393550e3dafdee177de737a6f25deb10691f5415f80353c48d185681208710322852169b05944a5b10731efa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006524c6a811b6aa84405c40d2471d17d368857cb81d1823c36c75dff91d741cd4447b6216dd7d2c39d2b56635345f16f0000000000000000000000000000000014aabd4eed2c8eee836efa318a80fded1f94004fccdeb4e178eccf0278caa50615395719858db7fb2c7c7325ac514ed61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066112fe0537c20b69ac978d0657f4bd0bca4b1069a328c327bbda09a10fd1b1f20bffc26657817597b65bf17508b5cc0000000000000000000000000000000004415f38b13880a54d1db36cbf0f88153b58f5e25f93e5449db627e2b5db39bd885430119ea83a21e84deb559218bd321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153ee311d0c39399e915b035c81cc49ed9975249b3fa79f13500a653a107015e14e6b0eb1eea2e306cc0619a0d1b59fa00000000000000000000000000000000187ca82a83c941b370685a00c5d368307a270cfe3ebdbfdf05a9c77011f2862a2b00f36f3fee987acb44d358bb9de0aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7cb7d27a63cdf11ac421fb3baee8be45059292661978bf70607db3e00b38038e88a31fdcfac8a39169e96eb2a59077000000000000000000000000000000000110aba6454b1515c7a8e715a1d329148f03eae054f4bb0b4e689f2f844e30cb42454c3d650b1ccf2fd55b13de391c981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c32e9510be94fb44f2c8d228d3ceea26f3c19bd3a115d0a2dd4f269c7bb7fc85571a4877012e469b3c184142d62bca0000000000000000000000000000000019306027faabdf805408188f4051ec8ec17b48406ed454441207683e08eda6b7fcc305542528faf83d6db4d199aa48201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124d308aeea141c321320abd18750ccb0e027f60bf46f75804595c1689dd6676f2d2b4de52a60f23ce2b0a9785d845ce0000000000000000000000000000000016f72448e45f6e1479bfa3b0a58f04823ad10a8fbeb9315a678a96674a77ec1d7e80bcd7ed366c087bea6f8158518e0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad1828e277dbc837727490d2b3b23467356a6afb35a679e8c4ce8b02da0fda62c37f55513cd3eddd25349a9f625bcaa000000000000000000000000000000001600a39c4ae049c22c2487dbcaa9d7cd83bc3d36217079f57af182ecab86ce2e377d8d6cd8d03d7d0238c531c65f530b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d0c95928e7443382a6801b52a89d5d765adde938d93f3458667320430372725ad5641ba43bf736e26aeada5840466a000000000000000000000000000000000f38f2fac47b59b51a6eaa6f10edbf0c808ed5e1ec37dcf4929026d86677792249537ab4c4c31cacd4509508df362e991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000617b915c1a71472611c0aca5f332947f0e9314cbde5ac9fa197dbbd4e5210c99dd4857347c517077c780b183911f5100000000000000000000000000000000111e878f21046605ed1ec1acff14a65ab76fe8bfd9b5366c60c8f5ea3411ebd9dd40d5cc566301a226feb5706a10e93f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d4dc494bfca265673402aacd8e03d03060f58817f1cb8ec02c4061c5927971882350a8fde6e03884d58b0ae09c05830000000000000000000000000000000009eddd78d93e462baa241c54834b50eb13588231592efd371567b0b1f6c221e42bbeab506771faf7f0f72ba707b2a1c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057177817fec28e26be81c7157bcb808948381ca1d7f15f38547d31965d47e578a80c6cd0df56326a88b2936fefe4d01000000000000000000000000000000000a48c9dd6bfe505565f29ad3f37bbdc105869644886db17e858584620390fd7c96ab9c0b4a071acbceddf1837b4bb42a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce7289e56f28c33a618a3d74aedd6eb540a6ccb11d4d76637113fc491b40c58f2350b0bef99d1a1f1145468f003bd41000000000000000000000000000000000719d4033aff1d6c7abd3a0d052033b7f11250e327d042db555f02e0adf8a5364926d0fa9af936a5a9d9ff074b3aa0191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e50c05a0aba567aa9263da3742f18a9a46c461e4da36ee25489023e9c83f29b9031ef255be676e38fea1976185fad970000000000000000000000000000000012ea0296b98e2c853a8b61658d95f098c327649bf2f0bcfac9b6a58264f9708d419d2569125a846cc8cd6a2301dba4141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175bad04a658386447d7def44f640c929fe001da40fc296128773cd948c0c45c6b4c668f7810482421693f27dc7b320f0000000000000000000000000000000015c056b2acd16f6df67e566d122da81055cc570e5f4be1071b9b58c3960966b583524d28c07ea281401783d215510cd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016e0f682af163d945b26e20df5f51847e1bc72a51ef59591e512d912bc8afaf52505e8a74e48071408d909051984964000000000000000000000000000000000c9f8b5dfede897748ed1290df886c7cfcf34813709fe127518889c27e85a8eb8e40fafd307ecd4c2811ce0ab663d6e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ccf9d859968ecb3b3376208406bfad762a7727cf0594ea06f3547af48ee355c9d7c52ee7b2ac7a11cacab5b7b474ae000000000000000000000000000000001748e626aa18fb16b0e20e353ead9add544e3b0fe24e651c34f0543d38d86a70dd7d183cd256511fb4573a32dcbd0c751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000013aab2526c8db7e75642e3b56a00c2759206757954f4fe3a684d9e719a5df1d5036cad7d515ea4668ba6ea95d1e74d00000000000000000000000000000000136a4065add8d668a870fe794211edff0d0e476f84da03a3796a1b1ddc9b46145d17a9c9284d5e162e842ee8d33791ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb9c4effa3bcbbaaf4f8bd9300e20e64c501b44eb7a415d1e7a5673a9e0c8cbd10aab248778602081420a229633c3d200000000000000000000000000000000165025776b37dbc9efd3f7d258c6fce82ec3f7f3fcc29fca665c37d2fb9d94af3ed66baa3c150d8f02d2ab0ee6d196b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d5e4702503f19606fd86456f6451c18d61a51d9e176df6c80bb4ff2832c8f81895ee58b5055d28fa070db5b465bd44000000000000000000000000000000001851023a1777e751d955b7ed41ccb59c79642c3481d3b83b1d42d225590ac5168c8ea1c73300a470dfc6896f9596e0821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137b0d317a634bfe36fe4d6bba0db9cff017c79604c32cad52bf04198b904033160836a1684d7626c4d95dcc8b9c4238000000000000000000000000000000000acfe12b3bcacba11ab226546a3ecc841d126b78c669ac88c58a19f16ae53c5c04f1289924e52e3bf25028a6e72f1a151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1bba3cbde5d43f9c78e65adf6e97a13d8e665ddd29d0069bb8e85c7c5d9a6a6c401eebcbe43117d9d37e076dcad4250000000000000000000000000000000002cff6630dbade788754421d07d9b9a5cf30916dd19c8db8f1d1976fd62991f29f2790525f30cf8d9ff379e532a3088b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eda161fed19f5074fd407bad6adff4571ef70bd435d4c70e4479d395e81f0833831fbbfc13fccc894e9c2df6479772b000000000000000000000000000000000369260e8b965240604d7919eeffbc84111f369dbb30b7a31c1e6b8278ee0324d8fd75601eac68c47be503803ccdbf9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134c07ad7506821a767e40acc9a4a3b690414a48380f01ec074a5192a0aa9dc53e685b99f9b9db1da3fe17cd7266e045000000000000000000000000000000000a77531440c8ccfa968fe835d6aa8d085a86060ad83e96dfb8b996ceae80dc707387e4293feff8dca1da7fe975852ae21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7a6941070a08e4af416367002e201abb19ad89099af7d54cf391893b399a5e8c1d0adac977329d79d4fd2bbaaac3dc0000000000000000000000000000000002748750118f728605090a5ee87055576908822b6d8647306381c709efe321bbeb7d8baa84d448f32319f415bdfbf8841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6e9cd4b4755f6061ed11a1998e237d1526da1c68916f27c3097b5a1fa0a2f8fc4cf72364a7401b1d083cdc9723da050000000000000000000000000000000014e576aa7ab9443ce6165b206f98ad8b65c63b36da61236a2215a06398998ef0b846aebfe7d5219cd469186b6a38a3071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cc6dda41f877440b84b733956377b280ceaa51bd0878154ed5a7524e2069a4a83199e9ca8599fb963333c093ba63a00000000000000000000000000000000007558b84a223cfacc73a2765515c5a1536dac83d355e77f30ae40cd94a8d266cb3080c7c2305033439a9fdf32c0000101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114f035c7db1ebaacf5a19b1eafce096086e3d1c15bd6cd840837207ad91605c1f6b39c645f2c73f9e1ee86c3c38a3e600000000000000000000000000000000043e9bd0631bc9655ff3567b23aa28809cc6c2dca10c19dd5d61d2f8da75ca66b3d3fa636dcd5291f0197cbc7445e5dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114e7f4761603e6e5f1cbc3045f724ef2a109e0303dd2de9f0cabc7a740f8683476e478d6c6c2f06a0e2fc1d3528bf19000000000000000000000000000000000d9423807bd5fdcdf9a29bf0dbb18dfa24e9f6d251238c21f7178bbf72e0ad7ca8c88f26768e19ca1155d0a50493d9241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000710badc66e453d341bc8024715491d8087f24d49abf1b7ab3dfd5d6400d1319086d5b28dbea5dc0e6efb6c41a04d1740000000000000000000000000000000015ff3098afaa2f032a19322ce84ac8e96c4aa8be45dbf9fd38d7535b4d032e466ce9f2777ffe2a67ff98b8ec646993011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d186768a7f5a163c0e81289e9deaf23beae4cef029e5b2732f5f5f30cdb3376a6fb91bcdcc60be0fb704274c8a7446c0000000000000000000000000000000011d9a5234787e99e6ab91d688e1b8d558d1307d8314300b9c98ddc28414c34eb5422e6d5ee83674d55feb7550986ada11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c5523270e36aa4b8109b1de6f2aaa64cb82af4735bcba86cf5290e70516dc9f999799aa8d46f8272b5f1b37d8aefce000000000000000000000000000000000ff88d738e8bde309250b084061bd5b02965abc89f414c570bfb7af2e46442a6c3fb646dae95df9f9a9146cd5c0555951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035e7ba1d16be64e34a8ef1643817be28070938a1338f0677484dba34afcbbe7bfb70aba8af6dc6f58377c9c0284986c0000000000000000000000000000000005d162b6aefc068956b642af50d8d946d9c54ec87f6a357d0deab1fd7e63667da9ba3951a173c43bd31c7b48a4a169711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097a2176bce8bdca929db516336d07a0116e62336b0f20ceb211b45d96934a4179bef91e97599120afce741a0dd2809e00000000000000000000000000000000167a0d8b7fa26a863330d0d07741a0759cd48070f4ae20f31a26c78d909a6e7db5740c47d63c2e6387c56373074ba7a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001523c906d6871d1712021eb6d02cbe3de3022ae065757ecbc649e774cb023910cfe432030736a5ea071fdb1c1a06ba7d000000000000000000000000000000000275529a5c5ac15d80dc99570e776aa6282187592f7d486dfe1d5d525cc4a157367a8ca95288a73845f9d603980157781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec8afb041a771bc6cc59743659de9d7edd99b8a4467324a08db0f4b825ddb8f7bdc49ee6f1c2dfb27bf70250e5d0a66000000000000000000000000000000000c2e7e9a81c2331908d844e6f3c460a9bdcfef83cf0748bc934c329ba4b7c9ab82bbdcd19c270e393ba1146ef2be88911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f51c3d6d6304dc229073956289625f7138dfa366b313525bf99a42cc0774fa559973c6f5dd7acc8ba8301560471e2200000000000000000000000000000000013b95841b2fef0dc5af31e47e526e54598fc34750793e48f36f6e95280d4ca507af75a8907ec779c6fa96e76dd4581011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6b5b1ad9b72ab88e1b7b22d4436541a94f053208d3b43306af8837320023767e256073466cf7f77f101aada424d27c0000000000000000000000000000000012aabe4aefb6a294ee68b3e65377ef41798330b9682b0d87a225cf1c371c39269acb9295126f2f20910ccf848e080dee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066568bb72034a6e91b7fca1be8f21547d944a28c0313119bf7659679abadb40677b1637c54ef9b0dcd69e621b0175be000000000000000000000000000000000365372f94ed3d8cb57986b1e57b5b3ada3574ebe3e7a03afaa0b5e0aaf3ab7e812040411358728d2d1211d3b809d23a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014cf3ec9d3877bca04e9f96f1c8c4a9dcc82ecd353ef497d76fdbdb48f75c469adb3ae71d3c4ef2a701996a740d67868000000000000000000000000000000000980375d673e44b235fd68811b485388be6befc8701048e68f7d07f201bfdf95a22c9729eb714a47643b86851575872d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f36c310d3a40630ec183b4968c6527369755c3c715a986472ea3b1709f7f68c83d4c09f75bc811de1edba1ea29a97520000000000000000000000000000000001760ea38928f86424537d3ed2804d2329fc670157fc2891bbe4747a594bdd572e08ac4f220f14d09a6dcf03690632e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189f946984fdfa5973a0ded1d655b9918672b7091a6673a6144948c28ec7e2a5d8c847362a10fe2f0be73a541f98f166000000000000000000000000000000000faa511ffee7c79c477123db97ca38bb07bd726e168eaf7f8613e0d85e7ed803126d0b22be174983e9058358285e80991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182e13651ef67332c456646b6ee145c6a55f3187a51ffa65a043ba707ba3bdae81de346b5bed73367f2c9d61fb7a06ad000000000000000000000000000000000dc33d15486efdef313c95f9f70f8297e518053c02a2df8f40aac209dc98d93925146224028580556718d72b9153386b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021570546f896c62dd22f44cd5ad4978330df53cfd79cd1aa945f1b593c563ac1d27ab36c6a89f57e8f984ca81d500e10000000000000000000000000000000016c83533cc6ecce644ff64cb1a3a8c57e66c704d1c2e28e86d7092eb27dd7fab6cc2f506b55cb1b334382fe4ee7f25a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017814542ddf5c1e24505ebc0f8a2e8ff2f7356f23bdc1178e6b582e5799ea6beb1205e332934ab2f58d1e03ffc2c87de0000000000000000000000000000000002a84fce73de430ad6f3bfec7d6a052b70c2f6a7f7701a755a38e7fd1677acbf43c7619c8ede78d6aaa215b1213884511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181b11e9cddb6e76477755a60a116bfb26058fabbfd24227ef77c0b0144376f73b85f6dd33fac5295b34c85c91da394f000000000000000000000000000000000be9ac9baef26b8e604235a9fd93b709201ab7a71bb40f7e0dd0088392615c9a1e6c5e512e0a1ff0af0df4f40f58d3871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168a36e2d05306a26a1c5f1ad7f3cfbb4901599ed3059e991ba25721b159499a0898db606cb4516e42335b1c51c15c26000000000000000000000000000000000920a2bce1aadb4660f013c39b6f76f5e02f1f991b9b12e01bdbbdc25660835915bb2e6f688b76a066985d4c736979bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004649674b64c3f92b013b7a0ddb3790eae67eef0a5e509a344b98f0da147213c8a5f6675fc0d3402f67c88edd1168d23000000000000000000000000000000000dc534a517ed648ac4aed345afe478e1e30fa68dac284f314643f174d3022726a274b7182922af6120230135cb4c2fb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084c67e965c52302bdaef759bcfbf886879fbeb7dddaf0866727aa656018efb2b5038aa9ed8bb00a7dc35236c5a258310000000000000000000000000000000000a231f94cb81b70ab7cb3c592501832e306420b8b01f2df45cf1b374b04e8e55a666863bf2b2608a4ade5804b9ff6811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001203f446a7322b15f0b5e6c077e7c5ca1f3912480073d39ad00e62b932e6dd23521b79bab8b871958b9fc681fc8f62fb0000000000000000000000000000000013a416d6f7c218f8ca044a13ab7149be277e30dbf1361183ac4192ec2293d090a896024b785d9598c31dcea5d9065b681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b29cde24f39c8de5610538bdb9ab71492cf65140876cf5a0de24e6664cd07ef95dba1de70feea6d54126d84f02d1e000000000000000000000000000000000003528892a780e1b4e7ed44dcca1affe376c30cd43a6fdce1632299a30cac86fcd31014361dbd2d2b41e619063f2384c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3a547bd965507d04e58ec7567db6291709edd8eb05ce5110adb31e4fd45fbb2eb82cf0015e0a16ab6e3c62574edc650000000000000000000000000000000010cae65f07bf99b3b8a82f659afe2e778f751b52487d5eb37a089ae2f5f944f4d3d44de66e9e5d9b73d072ec6cccf50d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117be0f47a10746ecbdb5f9e27171a168db44a881a5e8ac5a5284e975b0b8b799407b3fd56ecfb4255c7abeda46d9362000000000000000000000000000000000a07e72de4c1ee1d9e3eca42747797930c4fd152ded2aed2e4877cdd0fae4cd3462d0b5c9f998c24a1e30068cf3640091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000443dc582a43dd855a899e50c71183aa287da2ff7535ee914b986854a9755220aa19493e1fbb8a76c94df329fb7cadea000000000000000000000000000000000b88014d62c2f7aa5b66b0a911b4e680d4b62988abb805232cc40f071454d02a2c904da19c53ae71b5edc20989cfc7401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182f46aa6f74fbe1d6b7fb4289b64396981c2732a107426ce7ad479806ae5f58a1ab8a7c8e7bd49af3497c6719ec5664000000000000000000000000000000000087af5ded95a3d7c085d64b658099ea085ad95ed1712f6cb83fbefadaae2cbe073eeafc2ed27fc5f8a3fdf74e0536931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010999ff27f530a977a4dae5036f71be0f19aa1f4cb62cb5bfdb3049cd184b0d1750a395e75c575d2f1ec64dc239aa3da00000000000000000000000000000000156844ea096dec9c62e5b7a829feddc0df74e6e2a06db905477802a0e2ab5de6a9b7cc7001c2e2611e2b661122ad24a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001835fa9fef758d13e0d6d7e372e6455b6d26b6a0a10a677175f28288bcccf9b2079b94adca0bd345a8152cd45bee318000000000000000000000000000000000ee991f6788c2894c808b28f1d2dbea0fa39a5b7f12d40ebe4699e35e6562b696869309f603f94d3eaaab3661e812da11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008134308eed1c5f36fe7ce6a09a0d5c1b3c7ae5a54406ac462c9eabb4e4de5e1b9955e5679f317c1b3887414beaa95fb000000000000000000000000000000000cdab023018e27f3af8a3946461cf4fa87038684ba684400e6967dafb6a0375e806c9e4828d4ef0c99c5a518f5e62c4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117c50eb91c53ba1049a6842c4778f68520a2c777396e66077ba21332e6e748a5bc2d0b2c782a288f315132c155c99830000000000000000000000000000000004d476e19b48938e72501199993b114aabb3c194084d4d8391c52f4d965f861d73f0c6b0cf717581d639a968ac00fd261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000261eb78c2d7761f9f0cbb6713db252643f556a39bedead9b29ed85fc1622937dbd886c42df17539becbbeee05bf018d00000000000000000000000000000000050d568d427fc8168c0955df7bd3d75d101c7d6c3b61a436a3e8d3f251c6111f66e1268bb2d7af3329be1b30f1922c211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011dd3b5b12c8ca944b3678159bac55f06a191ef0afc22f96ac9623fe8219bf333a2913b80b09f739bd20879e267c1a40000000000000000000000000000000000a6676a6b75ce49853405f105301cadaac5a153a6c68e50e2b987b1b69c54ecce9d6f302bb334539c47e46b632aaf6711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000474eef0c18ce6215c547ac32ff341f3013901df42865adfcaffa0cac9c85fef1b34596a0374646b97a50ef7c021b4cc000000000000000000000000000000001635adaf4d7c320f9e3a886790163df345f5baa543baa7ebca3a712d3f66c55b837430f3fab9d0bcc8b6d7df148f0dd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b702c4c81966935d31f21935757d1e464c0a487cb881843fe8050a30b2ce931a6c279f782e6d0814fc75ae754d091600000000000000000000000000000000012190154b7fb607d47059a5c75a228ada1f9f1c6cd9637edb7404a4ea71bd0d5eba8f4757bacecff94f2521238a7ca591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b950c2d748f0fb01a2ee6ee3ae0be0a6f30698707744b8b2eb5756552215ed189cd1c1bb2b8a76cb132b97ea294d4c0000000000000000000000000000000014f4b308232231424209ce8ad7e3f7b9b2c02ba99f7794e37ba45766d364555e1e305d0a3b731f94db50e137feccaa331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000431e977a01295e59c0cad353c13cad6113fa10c0f74cac235ae1aafc8a9a0de705c6adad0e04596cff4f5312328fd39000000000000000000000000000000001292ba6bcc6dd06d06bdd43ee0e714099b76fbd0585cf5c8fc800afdf172292af73458ff2034bf35f30c663dcf07a0201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d13c4aa6210723e7b40e4c6303a5ff9037854a2aff73249a7c817565d46c5b5bf0f27904f397b3425809b5ad940b927000000000000000000000000000000000b6516a23e4404babe42fd1c9a10a6c90f80a69cb90fa4e564258a6bfa780167b148c3c667957a897b3effb52cb7ff8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128fb9b94833499c653e5c9f7b03d28d7a6937458c25b1d09f7457fc9469ccc8ac0a2a7790fd530a453b17c58246869d000000000000000000000000000000000fb5c99cc1b64db7bdeebefc69a4e75c87ce5286c5e4021eb7ae1b8e67b98ebc09c7aebaf733e96428c1d2ffb277e21b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7fc580bc588c297383e577785f3b82354f66b7390124ad32d5270abe95fbc8e5408eb7a49da3ac77ebca6a57933173000000000000000000000000000000000a3c7ff9c277b51d876e72262093fcf87520c6ec9911aa8037a624ed9cf5bb3a99f8089bd0b774f314ddeb711a82301c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034cccb5ff10ccaae44482dd32a1b91010ffd2a9815a08d39d027fdeb63840b8c0c00f99e60ce1ed0576166086d52337000000000000000000000000000000000bd6f75b651d27857a52fd5605273d6bb13387634ce17b789ddb51d61052a79189074360f1b415d5388fba9156d2b8fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a7acdc1c14d7c47f11819f09a2b1d33adc58fabe69a21377a524e624f6184dea0026ecc824b70e59b956b3f17fe992000000000000000000000000000000000de3fce8efe567049e0f899fb36280dab792ab5efa389e1b7cc99635fbabe3e052c600f7125fb38e095dd7ea980d47a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182027d4dbaa9737f2389936474cf920d86d3b3cc9a2164e0bd6a1087f7547170d7efef3409baec3ce68fb90b1d439f1000000000000000000000000000000000d01014a7ed1e888e282ca2037f878d4d46cbf134078e89dace4a77a41b2943277737d02cb2af43b5f8569f670a8d9901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118f0992f31e4a0f67545167fcdbc1a93c2b3a46ac77508c485a14c6e044baa8b04422a6aaf91d74fa3c73f952b84c4400000000000000000000000000000000126b32b62ee47a3676702ab4eb6735bd97854ada8ebef04c74c715bba28958694820e14f5c1fe4bcc956d8684abcf8461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f02309e85c8d18d0f1f42b36e86d4d08b30e0c1e36537e39748f1c889134b4a4dc82d8f871bbc20acf4271677560dd70000000000000000000000000000000015bc83629c4064c294832aff45af17faa7f313e7d96250eff7478808dbaf0e4790cdcd232ced5fc88ac3fa47dffc39381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae18244c91d25427e1de84fa2a9218ae99d8792f01132c5b9b63c885e3500ef49bed29270b0f694faaef428ffd5c25c0000000000000000000000000000000016a0b3f00199a6038e22c8420702dd3d70727b8838026b18521adc95653b9265c5fbb99a6052812227a266d62e8a41711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081fcaebab68677ace7cf5c31828ec9bd45e5fcab70151809da87ff57772e19f9cdd2dc8da2e31ed61d8deb51113b3d0000000000000000000000000000000001562d8f4748969d8cc2d0a3cd1dac2065f9491b47607f6965187e01b134a5ecc4c5383dbaafca17aba71eda850dba4391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093cb53222f27a258e0ed9ffd464e2fdcb7ab36ffce91d646ec1d158eb758cff0c1675440e82acec1ba55549e63d91a20000000000000000000000000000000004b70d06cc09bee74554f8aba2521e1d096df0deabc44a83efb01a8c26c700c733c725579384dadad7ec76fd323663391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010047f05006b8ebe1a8b52acb18e74dfff4324114c6291a2ea35747327313c8ba60139ea3394c7811b6938af414cc94000000000000000000000000000000000019a024075758e9fee3eaba5ee5fb6dc53d0f7a9c00aa3c1fbdc769851ff78c379544dbfdc27c51661feacdf9c3db3121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d79527bdb23739f5df6e853632c9232b4bcbef6acdd04b4530bcacaa780ab5c9e7e1f9fc46af8703eecda6078cd6630000000000000000000000000000000016a15faf5144270c79501910693a69dae9a5dc141499e87686e833dd75deec3bf11e0d9975fd97bc2823e07c9eb50edd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d88f030d1a4955d2a50907b7b6230dd479e228089765d6916765c2a9b157cd6fa08313dd7cc0a0bee51381d8db94fa000000000000000000000000000000000080000e9a5cf21acb270f85ec4dbffd5f878755d45242f98f64ca49460a27cb3f040e50ee1b1b1d91d44220f1292b9121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097d6dfdbe7a6d8b1e93ee7555a5e257031c62f67ed42718458384978265dfa1e541f3424d354266e9efc40fd377082e0000000000000000000000000000000009be64f8e4fd2725dc3ca220eac4bbe54ae5fac5708f548352c9795d80f9fd044750e2de47f6447b394489bdc9ca485c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197893290290fde71a9118b654ea3d08e40e5d6567b0f06607325e35e2b2126feeeac5cbba311e6c06bade1d776c814f000000000000000000000000000000000efb96c5fd2b4492912e6bafa90500bce0baf44cde9f4a2188c2ce9087fb6b87ecaa91222c5c0f37f932ce888f27febd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3fec6bd9dfdf12be8316365f412902f10f2c2930ef8ede5c610d3a6bab8d3f31f4d04de5a4d9012174ab480ad23aa7000000000000000000000000000000000885071f2e531d875eada9cbb06e0b9ff1dfc3456479020ce576ff73aeb9de7b3affc6c79b14b419cb79c28574dd953b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e3ad5218ea3d425efe262120b2fb2a58913ea63240a654b54604fe4faa4549b3dbeba0728379fb4bd12b6d526b5ebe0000000000000000000000000000000006277f4fcc2ae2c7d173647c435aa18e2b93122cb77a47ae4237402052359b80353a1322d7dd16cda5ad6d2e9c0fa2281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5ee7e1b095afb224ac02974892f3fc9fd5b0d1c2773f125c7602b1d997d13d2bd28130c81fff7d9af335570041b75e000000000000000000000000000000001384ce3936604451ffc039f79a7b2a548f0d58bb21c655f7a020dd6314aab21b046350273423263b1e4154de6018b41d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000888d26042dca804d9bce363a69c9dccab5375f3ba53ca6c92752f0eb0d6a0e2e9c8fa8de324dc3b32f3765ce97540da0000000000000000000000000000000013e546b71db223830a04d1b6ae39cfa85814cfea9decd5c7641136ce4a1df020e553f02495cc6c9d8f20570c246905131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5370bb0d75669c4e9ee8070245ee3c372e3cf940d7210fdf4ab443b9226099df908599c85d123c3d58829d0cdd827c00000000000000000000000000000000023deaecd26b72d2e6e40b7b33783c66823beed7fb47b393a2073ca9890ef4911742d6c44c7e1b138685f4bedfdd64961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1222435f5056d78ac596335828a8ef84f23dfd22504fa4875b42c7ff7160e1294ede214f667f74a633469dcb2d028c000000000000000000000000000000000fbed157ed6a9807bb35ddd1fd2c433fdf115c9e1da7f3702a245bd50fce3575ab25cfb10c1fec44f357c3fa241302e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001198a4a93f81091ecaf3c3c84a10c370505a37eb06895eaf9b026ac6caca4900ef2128dab1a086dc5379ccc508ab6849000000000000000000000000000000000a5e57bf4559328468d79a47849d4320a9ac00aefd04241b2013a3a8ec2cc3a4f01a0d1c94d49bec54c827df2e0ca05d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e4f6b1465621806f64ca23db2254f568deb6d93b766cc6bc2fa746692fca64463c384622f93189a510a0aba6bf4dda000000000000000000000000000000001437e93338dff4e9ec9549e215cffc01f70a4095e03b294bbf7a002d79b95368c2d7e73812b56134dc7b5d31f9998b5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190ef1bfb7eb8e589a7a1e1065e463420d8365e6c454e96485a11cfb75a9884852ae271839cd43546b8e8cbfeff012830000000000000000000000000000000016343ff76b64f33b45c953f6107147559f77221877234cf7c5959dab061d73c3afcf9f58d7962fa3e50852aedb18c0831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000515ea034f48ddcae65d1090faafa598fa85ecb349eaaf04808964522a1ba88986722124b1e7844662987a7e7a85c46b0000000000000000000000000000000017a53c13dca393c5aa672b5cd0f0d6417a5d68a193eddfb6154dd93f49de4420211d4a4a0956f9528f6dc4d394e0c10c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d1a7f429a1608395ec8a385d068297126a4cb5664c67eac643b9aed9066104333c4ae9bde178b22adf95812a394de000000000000000000000000000000000041641ad0950398b419249023b291d2f095c3d9503530bb810bd57430e51bc12e2065a6ba00ac7f6ce1cdae8f8c4b7861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017b8420c725f2ed05ac1e6e56b97b649ffdc69886bf23e8ea61f08edc407960b034517bfef15c57234ff396cc2ce9b6000000000000000000000000000000001170f591f2b15181971d2a12c2e3264ff9654aa74d96e4068a6d20ab4d4f8cce7ab74a87b4691271204f9c7f26f9019b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca8df01e17fc25fce290dae5212176fc3177a3eda26a6484e25120d594fab4f7fb8ea8a261a312808ff5341682e8e9a0000000000000000000000000000000001ecf5cb47f717ba154f3f6347cb65689477e676cd5ced69d1f50d71b788bb4142f888e2802cded07e8df0752cfcd8fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003277fe7e8942fc540aeb128b0f87a6937db3c42cf1b10986978a59293ec5f586d12f8efc56b24989bc7532f7d330cd5000000000000000000000000000000000365e6a7109d1c459be428fa4d920c3d7591dc0360a062e9d4f62c66877b86174c3f9c818fc7f0b8b0c083db4ae84f661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d42a100025f5f8bd56979a0b15a9f4e3d1d7c41c8903ece56cede7137157dcffac8c2fa75fa7db8a648c38b616d4150000000000000000000000000000000005a41a34f189f261cb2169ca1a2552d448000ff334d380510e868fe3b13122ceb254097207a6a2325aed2fe7954bc08b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d77fda012cd3804877272cb85e4fea4decd4220bd961af177b13e05e4580af2bd24de83e392a49a1dbc781d6fe62afd000000000000000000000000000000001533905928350e78609eae1252877972fdd8190c24913fb8741a5da6d5ee171b0effb40c0062b003ed440fe0b12d4cb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fd7872721407893387e1af9a487834689b804a4948219c9296e17fb936c7ca9f39d15549fbe79cf9c117627db3622e00000000000000000000000000000000035bfb2670871a6814285155e618ee55f538db075d6f5b37289ff60337f14a01aa228721a99c836d74a34a6be3d2d8261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092a254a1a8b90ac06f41a925e8929e31196f1ed044e40025e3dd92e388da467d0afb93f9865a4f16ffd5aac0427557a000000000000000000000000000000000d5fc5732adb4525c812c005038a319cf8eaa83fc3b65c048735d8ae7e82b7c3951cfcd5eb36e87cd0a70a2e41ba79231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043b7f73c36b44fa867d5f63d45f7e3ae3b9ee433797c148345557928634cab556df1843206db6fb8582b5d937d24a040000000000000000000000000000000018b11f00679b3ff73dafbbf9bab7e909e11a3e257f14f367145d31208bbd5a301af2b1664920021b5168d27fa3ba5eae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137b25b442d2788e3e2158b6c4e1e7c654d19910d55201f4226127588b459a110326f7e3f8243f7735f01a44ef5d7350000000000000000000000000000000000a54bc5143469e523183749756a760e02ded2ad292dcf2cdc5d5584084fd9992a80f5eee34bf051832f90c511c5476681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012bf4fdaad2fdc2888a8ee7a6ef278887e98a2268e56141b7bea32523e5bf38cb73fedd52af2c1804683c51bc31fdb2c000000000000000000000000000000001508739aabf53d1625881fafca4487a50ae34b3d8f675a19508cd320303a059eb82ed89851cc3f4176102ac1743e70a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011299c97ee11978dd6e4f4e10997436c523230591f2230112d0705400443fc520d94eeaeb4db5fa9820f1b01e16ff6a7000000000000000000000000000000000b7ebde19fdb8e2f04f0f1da417a7bf327fb97a06ed1ceb66a1ef5ae8ed27e4ec5f350c0267f84009009a1c5a5808f861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003029f907b768f745b8399bbcb65703f1f55114a913450f0d2fc79ab51c4c606254712f1bd73ff40e3d5f4fcafbd647e000000000000000000000000000000001637977689677e9a3253283c6925df235cd676210379f284eb44bd54d007185afff3e4f17a1ff021e242675551d5acc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001028a4c6a19e8f4e2ea89119947d59379490aa0b99760eb1d0d72ea3d0e727c5113b18d0631464dd60ffd6dfcbc9b912000000000000000000000000000000000b386fe01c4666262fcda30a2f2008e602e509ba7b6c3ecaf55d5071f4cf2d6617fad5a469f4bf298fd018d9b56e9bd11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016995386a79aa391fa6042d1bcffe3ddb343bf5d0e0b8fa5f969b96c2c7713aa4a5c1a488dc7d58db8fae1893776c8af000000000000000000000000000000001848397e095f75b09a7a2a0ef33f46333d716a2044d61a0910ccf700c337b8c9a1591ea51f47dd383f2e27268fb3dd7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000581998237e4367ea45c66ae720701c9564202d9e167de582d71d2e65948f32d451456015e0b678484838526f3238d1e000000000000000000000000000000000817a81d1f7b80db93faad87a5de905468fa98b907ee4bd00a6cec7bff92bef9ec9f014e2e8d831032031660e40792df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4ad9fbb902f1b9f7f5906d89200ffaedf48786f03539b317d10d1a7317d0fc43bc8124288879b28d771ba12707e4b900000000000000000000000000000000032f484aa3a751b0b830001adfeb8366d982c763945b62d6fbbd1f3f95a1f41465084a2afcf19087f02f1bdfc9e359e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000943a9bacb0faf2c80edfdd0cbe16ad9efdfdfbbea95a6bece0a5ea39ef0b2306ed177c4bb6e6cbfc3f1aa4aca45970f0000000000000000000000000000000005835bd610465fef99c27477a029d7f182c3a16c134e718973495ef49819c6bf5daec6014b39865d1c66651631ad6f241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001538fb84582b2d6cff465c2afbd2194365ae25e5c1c129875db0e87b49d842d82ebade8cc00b8fe2859dc16e695a32220000000000000000000000000000000014b2dcb25c17e2b164214da4d5090ce49366476a56e7efaae8fad1ceafcd46e32bd2ed1cedeb584d9132af5a8df4d54f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015261072d9fa05b56626f0c9de76681947d46538449b2f49137a3499dc78c2d9f128c5cc76bb1de8f2d4c11891ca80e700000000000000000000000000000000198bf287cf695b39f8213d96063c469c08b3fb0ee62641fb1b4f05e445a2cb70e5195f1cd5ef455cd7bf47fade2b588b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000882c23698a842f71b00dbce067aeb68c0590051765ca3b7732bb87ed2a31e2e806d89b803fb4c662ca17367f00c183700000000000000000000000000000000059abbaac8f8b2f8dcf70ed664b96ce3736e9975a40a48a25ca94f03c8401733745153cddb25da31dcfa9c73681128ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005972cd71237c7fa8a15f35f9675318ff1ac33ff525c27cc185dd79802df3d37617340d2a46fd5aca5a8882483bfaee200000000000000000000000000000000052b06fbfe7bd8fe2a7bf76ec22b1ffb2d68252511187140134b200438dbdc422028ea171989d7e3a6607dece4033e281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001251474bfb312c307243705e3ce250ea93488cf923536e5697e3026d608aae3921ca9b62d587cc1405c053a96dd71d540000000000000000000000000000000008242bd30f5cc2d9794b2c258006abe73a3547a19704ed34e37a8f06a5753bfe969a38098e9bc6c329818f8929aea1091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190f338c4548bc0a791e61280b91ba0433e51fb0488110203af50f4f1fb55b369165fe953cf9c22a5ce84efecbdfdb6e000000000000000000000000000000000e3dc00b2540ef94618a5c8d9998054140d832b76de7f79e3cf25eb607d191dc2298dba7c2dc501e3d5ab1f4b9514a2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001eddf7ffef969cf5418e154518e929f4c8f063e1ac82f730bc1bf55064a42884bcf0583f3928f741905cefc77edcdb0000000000000000000000000000000000cd491d60f3389b5ffd5c39224fc883990e57b550d48e8dd70cbe263e99ebab28a4df65adeb1329d744720195736fc211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9415cc54bd5ecdc2bea7b32a2c1a22cca7f1c86f9a3cca56bd0e59ffa5df9096faedde3f10de9c0845979353747fe4000000000000000000000000000000000fc38fd750c57fbce6191eb2b6cadf2af99854bb047a65be3ac428730f9e364257c747f455bbcd957477ac5a9e3266421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016cbc6f58f419b033ef48e86e295a7667a90863336dbe4a57af1c24b259da0cff2302ce2aeb21dda327e6c9fb1902262000000000000000000000000000000000e86204b2b08ce40bd0aca4af5d2d64b41441fab22945bce18baef1767cc4246b9b8421ec20e4c9b68f8eefc234b7ae81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ce327e7d2cf21417023d00bf4adabc5bc930e4d62b015798ebd46811df9937f6c11586bba314e57167334d88aa535b0000000000000000000000000000000013db73eafffd788d8d5450a03df60d59a5fcdca899a356cce73f5e212c9f79a6e28fb6bf716862e9d4c4643b40b6fdb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006790346c9b7e1231169eef17b152d40d06ede85c54abb87f0e1c314abd97cdd5d80a8d165d7c424e84027ca345b1fcc00000000000000000000000000000000015bf6e108688ea8ea223b6cad7fa3bd49568553b8e791d726e208d3ae91e5a7fec41855897049709ade21e6922419541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f93098d767316846b46bcb0d8b7fe1b8acb2889588a4f4cc100f5dbd5c9c987d4a8c6478ab091d224ac7499033f013b00000000000000000000000000000000046768ea3c2d0ce3a57607f3068a819a451d828833111c90ec8a68ecbcb62e9348b33ff776cfcd10c8a8c1c0c1602f891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012c74a0fb7054e002b8fe4414cbf4d3090cdbc2c1b17bfa52017cac299e2c41749356d6253f1864f290de38427624d5000000000000000000000000000000001570f3184fd3a110385d2b48424626de6af78d9e16c1e471103f7a85bbf4afe7bb92ae51becea5361c75e48e2b687c231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004787f32b74828883fde4c4eb8deca38bb0a9a1dd265188c09fdf75497d992f12d307efaf4da3615c6bf4b06d159e6c20000000000000000000000000000000011611ea2680db7ac587076e3a3b1ce5801619d96d124880619a0b099c844558ead47ba8eeb88bd91bedb40bb98ad5ac91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d889ecbecf320c8ea7437b7d306b66153d764be87dc07fe63c3c201ce80bd8af339d502f38826ef7d181edabf811c150000000000000000000000000000000015f02a803fa9cbd37ef79faaa00de75f395f99ecf5afdaba8ebd6a6e847854ea41b8fb299cec7aebf107baf3ecf2bd341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4b72a9d0ea08048b03aad6bdaa0010e42c29113d64020f913fd46f1ff428ef2d77786a114ea9a6a79cb09ac73428f6000000000000000000000000000000000233609f107eb923e40ad6828324677cb636063c6a443b66c84f47a86515c2d08f1e8d368bb06283a30a6fa40956ae821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197ab30ca98868e39a813c3033050a8e1b9aa45bc3c9f3f404e9e8c53922e3077e4e277a51ef12a516185d6ff7350efe0000000000000000000000000000000006ab36def0305303afa4a21855d26d3e8198a2646efe78f565e4696d4c99ecaaffebe72d6386878f482d02d4c10bf6e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001452ce20b2c6d9a67c7e279edbdecdf84ea7b20f57530405e2407335a0f02cf35c1b53e08a94fbd476dc31323d385ec00000000000000000000000000000000007649c64872da423d5b5332df46974504cbf9564d0087142fc2dcb9ce906a049325c1de9d69dcb0089331b52185f7fe61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022fcb0e5e71d1ea500decc6d7b4612db4243b2c7efd15c71a32360245e5f4aca2c5171afd8dca508443f64cf5d9f833000000000000000000000000000000000a3e2331b29958570b9d10c5e2b2fe6405300a3a312502e0f48f59e37fd5ffda9f6571c7970159a6bdf180db38202b371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000755dfd6e4d959b09c7cdebb385d57512a8fca54e5389be5401454c6c07ba0cb56d4ca8291502382d782707b4720897f0000000000000000000000000000000000e46c51aff857a6ed25202d10f0ca55671b26fe77af792d98091e04b9ea5795927a4c5697876596a7f0388ebc67dba81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de3ae7e3f7829937ad027342500c22b67e56261d0408677ad0679c532cede9b2eec3230ab488a14e1ea50d8aa7bf5c3000000000000000000000000000000000e50ca090f7905f30b04bd234c66e4cbdbc97b117fdbb3c50ae017b3fbbbe03f1aedfa6f5595824cfa9cf657690b86f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039f5eb9da27d3dd2ab039703f5ac8c1e83239169c51e9b8d0902d2549c128a04dd0649c4ef5108fd01505e9667ac4cf000000000000000000000000000000001564609f19306ff8e54523d2a183626793d5bef4e163b62f0c099ad5b92b5a7fd73735035760680049172ffc8726345a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168d9b50e8dacf5ab8f28e181f1c52d5415db0ff312b9f849c749b0b5b9bcf47fde8b81fe55646efbe39f58a73657f9b0000000000000000000000000000000019657fe35c6730948a74e0eee2e820bd3db1d3045e0cebff257ca6f07609980624047c8822e74261df59bbf73ed13aab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b68c6408d5d683baefe2a59815b974fbd7665ab60d14ef051917bd886671ea4235c98837ca1513021913e17033bf14f0000000000000000000000000000000003dd76b2bc86ae90fc18907c16909add5ec0bebfc7399ce26311b4118629d6d76a762b9d8654dc7108238e0426bca7191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082a3aba3ee823ca0eee25cdf5e35ced63b366f298e40db132e8e222ef695d2d1e2c3bfb4e0a119be9533e79a4f4971000000000000000000000000000000000132f474047b8da402e73166fb3369d321c97c1541c276753b4ae0f02b9777d01f273d1b8a9aa3ed868be6d11880b955b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dbf62e0c2ece933803404b3aa5764c26a2114eca5922c6f401bec8d5d447da3a3837a1b866f6f27eb04f51f9b2129540000000000000000000000000000000007aa036bdfd298a2bc8881643c7ef1e9243841f5ed023f4e006bffefe0066995783b1a89c6a5a41c781069e94d672d7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ad7027d0714919108bf1de241b4fda12f1fd1108c10810cfd38a79fa8c45c83a5041078e9e20f9579848da66937b5c0000000000000000000000000000000010d261e69d30994b40b185338671b6ae1f797cc136d75ea807bbf82dffb7573726080cf6ad3248b5b5fe202c382ff2941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175411ea735bb9b1387c839793758e0b84ba2e3978616902cc54fcf1dda6b16e3477087f3995da2c8a0bf0a1f69fceb50000000000000000000000000000000003169bf48b6b3d89560cec091a928c3d1fda2281a6dbcd27cca5183939765c09065fca3465e318060b533f73ee844df01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001947bdd2a8446fa04f5971c6937be70a02a07bdbab4269afb44e153e79283359e23e96e18080bf433b220a66be65b858000000000000000000000000000000000a2a895cbd02ee0c4581b1886d8fea4279c9a366675d9210d1ef22b1e315cf88fb874a3b20a7dd0a1898e205bcbcda381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f832e090abc2bcd1f54b4130d334531c3e8300fd87db86c9088a61118a25416a4478ffda2a9871b9ac43093e8e6a52500000000000000000000000000000000155552cba13477324160ae1bba296858fd2b4e033b25231dca30961bcd3b2e1f8cf989b8bcda5cc72e4fecb952cfc1bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fc55b5365a3a34267628803bd7fa5287c22673fc1bc7cc50cd43dd9cab4a9d5457fa7e87c1d92c022548e863a50559000000000000000000000000000000000c98348baf672865d20aebb9ff61b5a40c6aa9969ba199206c4b065c71acf550539a8f4374474ad031d75f0d1910f0371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001476d100c2aadc55b6bfd73d7b6e52900d79649c56de2e5e7274d35e93fe44f669496cebf82cceb321e7496e07093cf6000000000000000000000000000000000f80c36442ab26bc3c67d4d8006fdb69b4188bf58ea6142a93de279b0012dd603f46858084af0db531741cacc492568a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b111e8c6426e83ebdc80ff8dfe0f06de5801ec49011af1b0114a8f78e86a5fa7373735a8e6abd46ac9af12b2115aaaa00000000000000000000000000000000045edcc73d85db585bf6522db1007823a63786a23f0365212dbeb81eac584ef770cb7b51582322c35dd2fc51af8e484b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f8c97a2d26f3d96460581147ed13051fbb6fec4f39b57f6a7ff0caa2d170ca125135f999e50ec4e0f79c7cf2e42249000000000000000000000000000000000bfd93b606842a2efbdc0c186726e0810f35889ea42392859e900d8f8e546c207af645249ba07467e0eb94e1067b0aa41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005268642e8bdddf219e404a46d9d332cadac1087fa6598cc8d2ef4ad0a519b758a700f66a8dba35554eeda77784237e7000000000000000000000000000000000a56ca04a67af4269c95c0070895e83a63d12c1ae29e116847cc782051c65e46082d7a0a46a8bca4119408bdbb9beba81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061ef51d859710a04194a2efad785d6516b58daeac566ca601b39265ea4d00fc91c502614c26a351eb9b9f2706e70bf70000000000000000000000000000000019551764736d594117593547221338bbc2482d5175fd9dba46e081933fcf83c4d3ffde6e9aec56b6841f95ef9f25d9091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166e4a94e593a5841c5b4ccdb38914e7ed7dfb43331d3b48e2517bf6d64d7197a3d88c9c03f8440c28b1618a795cbc3900000000000000000000000000000000195dd4b627a72ef6a7b7ba800020a4de7d6764885b3e8ea861bd439c2d5654fe1fe7392199d19f6787fe0563ec1b74401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001542c11cbe0088a8799f08e7a9e5ba73ff4cbcac171cc75d530512395f61740964de6a88ec0f822cf7bd3e69c33e7be6000000000000000000000000000000000c0fc1826e12bf454be6abe4d07f52fd8e60f0d09e82e00c3cdca8789ed1d4ba58a3f43844cb2a7a1e4a88f4074569f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015822c53d5345aaf69f8583c60b4a51f64f8f17fd44c23bcddeb64187164f026651ebcfc9200d5755289347c154199b40000000000000000000000000000000010368a2faa902d3b699e27c610dabe8990f1a56e50c42c5f3a2db7412b4ffd5bb06c41ff73aa6d48594294c7cc43d4131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cda3b971d37280c3c7f38b4693321cd1461ac6efff1980d3bbcc26e65c71602fb6c0037bfc06a3a73d68c66cd56d9dc0000000000000000000000000000000002cfd987f64c351689d17bafac4b6a9889a15a12f499cbb067bbc5872c92dcd67e9ad12fd80438dcb667158e0b3911bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000169912eeef3d2567812c53f599e08230052a351c926425e156e25a81539ae5f269be12d33a9f9bc02614b87743b877950000000000000000000000000000000011f74a70d2a333e04c4f085f8e452d146a0dfe9143a3fa292a9c9e94253bdedf982878d094c61a24d337980d22e970541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071ee200816a9ab88d57c072f5594c577d373834befde0e8fea72f90b5611cbc0c5e8e2aa6f95c21c0e5a15aa3ad03d5000000000000000000000000000000000e3d2fd9888c7715d5ff4d0c89a1c2aa47d3c7739da8a8d64046bf62653dcd0ee3f6ba3e0a69c15f3823ac061e7627a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a71c5cf839d96f3b4a0e17cd6c7ff95590422d35d14cd7c8df470a053017650e3aabdcafe078f75782873efa332267000000000000000000000000000000000b3d786b512e252ed2741b637539e1dcd9ecb64d94176377c6c8ebf03bb0d29e52b472924cc08898eadc90f3e32efd171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0e3388569c8f9fcb8bfe3b7211483813607a2000169dd22f66950ef3e7f75a22b305be401f8f2e006943e69ba350320000000000000000000000000000000007098d2e3521387e3f38c34f31eb5e05c251b117c0d2f77c9ca24fb47168b0ae108ebda1627d6e32fec484efa7acc1811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015fc3a5f5fb16ad292901ae02011fc59d380f5228492c0045098343b80463ed1e524b13d08e65358de9590bcbc150a1c00000000000000000000000000000000019a5a503e3ecdfd1e800d2799287b39001884424ce207bd9340a2beec8337669a55ad6e624a097a06b00c1d5af818601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001cde754d4a7c87c55168831a05e9203565a3143f0d4c3d64833bf3c2385be46c60bbd48cb87890f3082fec9d0ee456700000000000000000000000000000000038b5bbb589f96a6b776c3779d3f064ac7628883e5d16995f125e36d58981c2b092c86a7ba79b2af64098c011195a97b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b01416502f217c3c4d3644ef7acd861f5366947a4010aece6d546fe108343b215d1a1474ab1602caf735016b71a7fc000000000000000000000000000000000f8401cbdaf818b64ff9725e975aa47500141f838dc2e4cdb091f481d47570bb31fbdc8058d3ceb4a9b3b6a6d58879ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e5b9b6f2401e9b9b4802891f5fd43f6851e255648f3dbde87a301b30cb792786b0c2e20323455876b52132397f6c570000000000000000000000000000000002710a0180b632b5d69416c24f9bcf83384c260ac269d27cc56b2a7108f6c99dd9ee0c0483a912e128c6fe3526e2f2fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e254a635a5d1e3fa55b22c3e6558cf796d5b4f9e1f1dec966bfc66d6ef769585cef36d4c31c7342d4181c7a579f265000000000000000000000000000000000d3bbd974d2bcdd4f27780d9a54d5ed8850bb1f4d591e89194347b7cbae24a2d1334285371dba9a33d143f48262f29db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cb6ee768b184c3606d7d4abc1dbad76354704ca6e83f7789d8ea4821b64524e1826b12da5320d7274774e0701cfb4e00000000000000000000000000000000099eb18fd5143d4bbbc1d0e94d097e422f06baf2e1e73564eea0ccb94d398bebcda09747c96bd50a34c29e5be9c1f70c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052181c68099d94b0d33015a88961ef166d220b5ef7aacf0d98bcae271538d2de17c415e3dbbfc317ce139ab5aace6180000000000000000000000000000000012f6123a05dfc803c8f6cc982151031436542daeea7d3335f2e0cadc385ded52b056068f1fc98b88a01c2e4a2eb39fed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c4a5828212e6847bca4fd3881f7996515b94dcacb29eb847d6e6661a632a5bfe5090bf42b3671d3224c58669b5f33500000000000000000000000000000000058257c1f6bf61583fbc0fc01731727f7381dde691270048bc5de52fa1fb7f5080d9ab9e36999924ca2e5243478713521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001883f73e2e52cf7e431039f5f85291cd7b5e5e41615aa07b50cef561b4bc225ff266d5127a498d3c2347157d2294607d0000000000000000000000000000000012a2c543a715d02d092c9f7f17c2250b6d3fb486919b870f09e402de795936894f9feb8f5482519fb9e19b8b190036c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b291889174b416c3c36db917dd9bf9c4fc873da699dc0cef731f1b4867c078a462a80688af97e346cd4f0bcc4d704140000000000000000000000000000000019648448888003c975f68e071626c254619dbd469d9b9132223ad3ba9f554741473a6fb9b06fed2137c5d767eb73aaf81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011531fb5df9f99b8d2dee28f7943a50ea2b23a565e4b4de411f3c79fc3e39c7451d396e04b58ae817b0eceff31a624a000000000000000000000000000000000013cd3edfca5e8022f2bc356c1ecb96c7350399dcfa49773afb7902c80981591cd2dc34017335270b271dcb90382a7551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a907299a10ad69c95c882eaa4b5c358fdfc8d5b8b7f3f0b269fa45b5f844c18291e12c45591fd352a6ad99a0e44c30000000000000000000000000000000000c75e0e7600387c6d09e4c3e946f9464507ede225a62d2d574d870846ae322d91c3625460e5b598d0780977da5f7bcd61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b20aef047d33f49a4fff43a4e05e4769ebeac15d9bdeed6d8a72ff68e1ce46b700d4f40ec436c14bbbbe7c9a166c7d5000000000000000000000000000000000c8a9896731cacea41f503ff2df566ad46e5574c50a14d954b1395d410133d5b985e2e5d1b4c168e1227756bc56910ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9c74d03e48d907b9c2fd3ea1920b4fe8faf2ce8fceef0347353345de346afb54437b524e6857c58df9a41415c8180c0000000000000000000000000000000011c7829b4eea03d5987c109a64e98d96f9d484d774f9dd50329a8a78b5ca4e594aaa1a3b8e78fc830d26e77e1d20042f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ff7238fb961161b04f90a0c411826f7d1e3a1d97f6c1ba6695364a40acf6e38f8c00b7d693e460503bf2b757c3a7d6000000000000000000000000000000001847b1d3706a5f11443a266efc4072b4e96b6bfc337e4bc2b07b6d58d3a619783c8cdf209b39c2be7623f9cc63b5a52b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001272966710902cbbc9f3481a6f2e1cde1f367074dc0365b14c6effceb11c9787a97d08fe4f6626bbe1263b8bc8c70ab600000000000000000000000000000000054be28a84bdf36adbc290fff833794cd5f8d6d15f5de5d1b712e0e0284ad1a31852258bce38df0551493ba8532d08ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010405774a089dff82f88fdaea591782d8d4ee7b85ddedc3cabd5449453fd7ea06a6cb76d73504bf460faa5bb03f2fdd20000000000000000000000000000000011a70f84d3d31b80b4fc0598b38801dc55bdfab5ccbba708bbe35b88e38a23cca6889c283d7bb34ab98e3aade48566141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000060b3957bb1d5e9eda50329fc869452551dbc8cdd4469a78e807f71fb40653f757ce067f07baf88d6063f40573b469b000000000000000000000000000000001118db56f4d94b12e58beb2618c48511885ccf6ea13c0fbee0d9378fb67add5cf042e60cd1a9cc595576d6b48e9d53281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108e5dc80af46215b1471cc48f3b5807c1752217263fa3ce122508b7030824abe440cd3bd556c9d1af8bc996904cbae8000000000000000000000000000000000a16b9686b572c45976251ebcbab0d7683ba4844a36f4ac8636a968992dad7b95ba70c360b297c24701c33118317363c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013824b1127bde34c82c0b32f271e5a57ba7c7309fc04101ffd075e6b5dd6804af9d247277d9e8674872d8fa831b6a9eb0000000000000000000000000000000002dc54fcbeb08ee200236dc577d5b22fa9811f82aff26ee4b3cbc5e97942066a11d8f693f984881673527410828231ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186156bc81d57479ef6e84d23675af126938e935d32dc1b70a226c17030b883ae6d4303399548314424d3e8583c4ee2e0000000000000000000000000000000011361862f0b9c14121146a9e72a9a2db9bc5f01f42928cab6ac8a3940afcd182eda241437560b76ab881a92e1070bbe51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f03a9ca1fc13669063f758d3afa3648329d2d2921baaba447a6ec43ff2ba6708f9b2cc1ccdc2523bb5b328fe63397a00000000000000000000000000000000039689bf993aa66a58a4a58ba58e6be3ceff19e2d4028e0cc475c3f640f78684f3db278877f1023ea0a6ed1a5ae3904c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010bce6883364bc0b5ba7e03437bce3b5928e039a0a3b0831be3588b087b4b2b62be5713e940974ec499d165d6a56fdef000000000000000000000000000000000e1916501843a040a43676ec864f52f2a35837d8d6072f8c14460e84f51f36321ad9909d9ff561a9f849d551b094acf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013aa536d13324c4a610749fc9d02f97fe8d792fa29811eab8d8811645c50759664d00ba9cb7ad8c902a0b5a3ae4470e5000000000000000000000000000000000cd9976558d904f7057c3973dccf652a7668bfc12f40564028fedb424c16a02b07c77389bc09ca7c99b2699ef6c618781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009484742695e6bcb724be665f54057bf3949b1a08903f3a3c6360872710c27ff7d6ee2736f9c154e2087b5d5307dc81400000000000000000000000000000000097a41ce90c310ed70558d79e379a41e805db80e49e36b458073fd9ab9fabd620e7a80e08bac98f1cd48a3c8a9cb1eda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001493e9cd2d1937f0f724e1f0d4cd180d661d701df181d5252e35dd468d72a47c2808e045cca1d84e0f9b20d6d2a41385000000000000000000000000000000000ac4071f471f8142906a95a065fb908e0531b21d47bec4009e2f308b7e3638663b3decaec27f4d58dc17d5a5d13db1981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd99775bb18975346d696106d8ae2e6be2d3f664af885ba7675dd0cf62294787b98f58013584075f139ccd344d76d950000000000000000000000000000000017aa5bfe3053b23691929db4e3a0350609777da28759c72ea7d76a8d47d09bc7941b58227e4010781ff3e708bd2951df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086a76cb30502c0a86b47ca8f546cd4a9630800725aff1c63a58adeabf03830e98cb0854b939398c5977d734eed1235d0000000000000000000000000000000000102fbf5c964a54b56a05fa6177d8a701774b0eb0dbdef1cd1dd21e8232e862788a674b9fc3101a32cf4724e5c57fb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fb3c4383dd0b1a2c66102250ae38cd50921eb23c185b05fdef7dd8d70b03344bac1f2974c3e591dd30d8981c6478ea000000000000000000000000000000000d7012cd35633f815bf367422525dc8ff0ebec6d4d2d3daf53a5c7c4e3bc0c8bdd8157091a04454d978501c47330adad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000223d4e0c500c6087448e4124cd655f9ff8f216aee42f04de64a5f5f94acccc5998a1164b3e50940e8511d95917e958d000000000000000000000000000000000e01d2a2e271db6b445f2f2d3e7998da54fe873f8497fc5c6b42373482978975d133203362b36cb102c0c9cebe5baec91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a190ed9c3d8cd5df3a5cb38ccc33061d9ff5d6f711d8047346a3e15f9157d0be394dd01af4a927c7a63fd40430befe00000000000000000000000000000000162de5c3ec84c0b6b4ba15572926d1128f7c459951a84f6611fd27d60af4e5a6341173247e7a67452b67b3f2cbbcd2de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aeb43ca9202276f4cf9ddf9937c5c35912c74fcc80144d7331c0f329d857e6fbf7d8cee2ba39a0e43bb19f296eefa330000000000000000000000000000000016b8fbadd675d0484493e5ab3d56acd658bd46b2494a89818ec288368d09559e403aefb06e87877691ae864c556255b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011312304535eef7d614060b81f0d0db188b8036c01bac69d740f9bd50f4610f76b7854f18dddb520ba966fb9afcc94ff000000000000000000000000000000000bc00fa8fbb4b03457869b7b220924a6a1a796093925e11715b0475a5fc95f6cd8271ce92661ea96e0ba2a9ba3cc92611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a276f6f1c32675c8a22fdda5378f7ed99878f9e7a6e4a21a3b077922c5e7428a322535b3864a93c3512a7f958961ef0000000000000000000000000000000015970cdcede3da7d64d784f77195eec0ab25adae3afc6f44eddb21e781938e596a65081103e2ea27de747807b9392d3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c4e55f80b849143f11d10ea6a19182a1fbbd3f3dcef3f905c6b38897621729dc42ed9c43818c1499f4616f51490afa000000000000000000000000000000000766d3c11696678d21c48b4a136800e089e2b85339512c468f37288c2b992c3629a9236f032f745745a0354f117abdf01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000998d6584973cbf2b4028cb92616f6fb38cf8ef3996d6e43f95ef557958aa207d092c87f9b7d28db4143e0af72d6c6000000000000000000000000000000000077c6d80a5299969f6d523dbea1e98d38a47ae1a11896bae5f03d5257b0bba68b46dc36557f778495f5b3c3933f790de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc2867e5850aa55d572a33356944b998f0316610f3f04aa764dc716f412c533c849bad50576f723bff7b3f758581e31000000000000000000000000000000001600f0c50deaa317171fac835a1562d011f494caa0daa8a77fd222fd0665e0e4c70e6256ac663f2cdb0590de1547438a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c6e53a6dde124ac85fd512c4f116287e1ee3f4ff34ef5f7aa906b2b471a2ada490d32f6180ae0734465e854ff6c72f000000000000000000000000000000000888a64140f58a64d17c5456d3356a708507733d9029dec489cbf0ba4f9b3f5b1767cc177b4d8ffa327bd7f5f14f95191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb6e54e6ab6243e3f7dbaea2f498b25d8d244003d27967891ca276dca6e74459dc11d192db19059daa4259f1386eff900000000000000000000000000000000180274a77406918e1c5a45fa2ba911bdb54d7dc2ee1d7708618004a9f1160afe2e53c0317393d60bbe61fbe8ae0927f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000817ff207ee37999d86144551e6dd4f1fed5df35bf74d167ddc235c3b2b95564e9d7ecd28cf21efe03b34551d26602630000000000000000000000000000000005483c5ae723d85cad4ca753d7fe43e168f2eae4330feea04f63829dd94fd938bd04978757010114584d54c48c3d1d0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7591146cf8cf47f60d456665c39a05a6a3ec2f524711d5a13afcfdd42f5b2793404c3862af760bec0ebb3120d8d41b000000000000000000000000000000000aa5f0f4ed79d9f4334670e1ea471ed2f451791ace43ad2d7cd93e2481198c029b117df9a38dff43af78077da130e7ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000685de9120b79495547fb080d0be29ebdc22b17357162d3e0ca48efb0c6431710e3a2c38d828621b59afebae551e812d000000000000000000000000000000000a7f9cad5fbf615df06c521e0796f40dfbc3b44c1533e1d1120a0c5b15404ced4b9fbeea73085f47a1b8d6c7df760b791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bf02c93f402a62d9d0eabc6c6312a5d1fbe623cd9a1d4b46626d43038f60a35ca60189a5da783ba331bc0ff54ba7ff000000000000000000000000000000000f86cdbd10dc3e6df368cb356b12a359bd08107477cee517a853fd6048685f9afedded341e12fd5b6cce414763550d241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025a1f5418d61dee3762e5077ffdabfa9b7cbdd7c5827c919eb21f11168f4114ab53b1d4384940ab2eda9c1ab82b690700000000000000000000000000000000041d010b3e4d02ce759a010151be38ff3b859920ec44307acd3cf3009d21c216d4c37cca1c0646c99c25b8f394ed2f881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006edb9e75c581b1bc96d45dff4970a63c4c0bd41d1b4c64e3f6a4425eb07375b007fc9612720145b8897bc75e84809410000000000000000000000000000000001c4008e7bad938ae5f68d31d92e9e375ed57af6f1436500cd8ad5423bc92704962660e469d7a4f3982cc3703556c46f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca0dd2b5ea16f5f5a7866d9b401539bed950f94e7aa1174ef6cffa908aaab8759e911af03ba6204b5344352b0c193710000000000000000000000000000000012616f913948aa5ed02fcf8695f52d521960f1e0cb8591eb433d92107da694f0a04e0aae6e454c0d7020032b5ab2a5271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001174a60a3edfcb5e8b5e3186933bb6ddef4824867a04213852c5356218b4c1f7d726b3f3327cef1cba96d77e9f8476150000000000000000000000000000000012f67a54c1da7682d8d2c1f4d60d9ac2bc7a000410b7b690b037079acc6b4479b4fc8e2812f84b93242808d2bc08cea31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a927935f97915e29442593382e8dcf998edee6dc609919de5284490e3d7df162144029b8cfe047c72a87b221fdf050600000000000000000000000000000000124e08edfcbafbbc93d8971d2c472770a116b4ebacac4e945d86b71e16bbbdb0132f79fb7f6c382561931785390cfbb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c69e897a15d4f9a9784cb8499838196e288f778fdaa457b3579ba0e2d8baacbd2a0b2667aca7afa6d1ed682533ff040000000000000000000000000000000006822aac2411ec055ced53dd23cbe1378fc92667afd2807e0a082fb4aff985b669e554cf6b655b078c0825c894660e241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078a372be72701f54e582949ebe73afa1a82a04f6effc85a57778cfcc782d3ff18ddaef402bb80aadc1c0d99a721bcbf00000000000000000000000000000000049b1a25fa6e8e601afccd0b8c35f9d79db58c735a04159197cec6a8a02107a7e0229c0dafc492548a1fd75236eca75b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9be4a858ec5d7e9f4b92572462764c0f10b8397cabba130ae8e56561e43b02359dc3ea8edd3c6a3afbba76053c06d400000000000000000000000000000000134189ef2d71caaf586582578b4d8dae20cd6200da08f0f5b9481f7f0e791ee8425757c09eed2408d5d3c8105c8310451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae0e9620f54cf764b92b2cd22e8c5d10b81713c2725dfb894e5950557d20de601c4ff6756bb5cc3d699e3d9b85792bf000000000000000000000000000000000c1b6a7816620cedeb8139904edffeba7b64d095e070c3e7edf4d186fdc1cc76c47ba52fad82f1e71e9f12db26fe49fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ed9b17499b541e03ed812fb1e4b7a2fc15bc5b4039a0d63c7305b246ef5b6cf1b1e209bdc9224584b6eb744a83809f0000000000000000000000000000000012a0d5232352a17eb8ce8058d363248d31285c0509b517f62f3bc108467552a01b16bc9d5494c0c5377567f7a665b6cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176ac42ed79fcc6815cec1924432922c22fe9f139f03e1723cf7cca901bd8e969db53abc9eb8a8c1ab066e67793d19e10000000000000000000000000000000016deeaab18548d983eb86b8cf5cc505da6e10ff5df8b50a9e271d008ac501365c6b2d676884a80980c4166920adb08971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044631185d7e9f98365c23fd3d3f47d2451bac728d15d8b3682c2824aa2175ef2429050e9e28ebbd15f9765a3cb5f87c0000000000000000000000000000000019cb56e21071d2b790872427cadfddb4bb277c6101c8b078632fc287b942343ddf38d2b37517d8815d9e74464490485d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b63726c19bf7d491af70391e09d46332a4aae678705b2adfb59e385c5cb0da27c2ee72d9df2dc52fa2a99485f0e09c100000000000000000000000000000000030da4dd6963929f022345d4e71fe820d34c6c0afdfac4382d7d6f94439747371a6286dc444c048a09a847af91c1e7bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c3da40a3ea8aca870a0b23b1f36205b7b617e5deab0549b781ecaa1433bd9ffb9260a80f210d6274eed78fd68804e00000000000000000000000000000000012581febaabd7e366db2cf94384031bf9648de37dee83693f8e9af60cff77cfc47ab5afcac8b1841dbcf95d148b90e2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e629602f9593a5097e7a6e87bd8849d48d7535490749f83d2b31723174ac2d177c8b192942ac9981d4b1d4fcaa30840000000000000000000000000000000003a7cbd60929d98293bdb3f80e0dd1be44249bd96ace544c8657c7d19a006b63180aeb8eff392dfa3f1cc648edb0f4111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc1d7474720cd58e21bd298e22ca44b913738bf8466ef968f8d1bbf69a6b2075d40d880efc343d16fe1580b4a0185a80000000000000000000000000000000002f329395affc28a66be2f03a8e5bfb9ba7b1a3b6b2153eb91aeb09ad039b3a3805d0ec8b85d75a521da20007cdd5d311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c947a6c6efd37b7ad92bd27b2362cc78d9ed19308945e32670ed02282ee586af30d6219a73847911bc0c5535daf1db8000000000000000000000000000000000340e074b08e57bc8ce48ac1a55cf525c4f5bd47a0ab4f521751b6d0c1bab207df57e54d33a333b2b0ad2a736fa12a281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000c126926259c3e13d7d2d146daaa0bfce87b5100710a0d694411ce87a0690f1b2c1eee5ac92895f01198189e71bbd1000000000000000000000000000000000ce520d7deaf014dc9cec02499a872e6a1bfb02b342e0b50989d51d09715fbaeb5d805305c5732bd317104d81dfeb77d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093e1631ae401bb528f1985febb8dfd56360475aa6d842a6a8f8315b2da0f6b0446c9da7bcdf9f952a964e70f0d9c36e0000000000000000000000000000000014d4d5217bc3f841e1ef1fa36b64700bdf89b1ce011315e14ef70aa7cd5f9f72cd4b6e089bcbb1db5bfb99c3c54d90d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011b16129bcc4be85f9c15320c70dbadf395b98de5712b9215e7b16e9d78936c112a462384ef53030a4935249cd4d4d7d000000000000000000000000000000001427211eb2c65bef186f7fad027ff7bee0bfb47b06b54c1b8a6cb6e38d5d7068c60cffc7cc1f5465d80eabf0fc6a796b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017867abd83eddc1e282c55ed3f32b58d1f85eeba59d12acce51ad5d3a07794b129a0ed52038353fe8a22804997e682ed0000000000000000000000000000000007031030f83f95e52a64a364095a1bde19c0fe1a7a55912941413e0628748f3dad2889f6b518b91b85eb5df1797d6b891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012287fbeb7e65b170cc1eb62d7f0b617965623ac2e2e7a25e10609a6bec0ca6118679d451e6d42ad3078ac576e39674d0000000000000000000000000000000008a11d1ba3d3e030d529e7053ebfaba155a4723123697c1a6eede20264008d7f79892a147b69cef34847228d81c3bd1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c91c7c6a81650d1c3eaadf1034fdd3d364cbc5780a99194623d05903d906bacceec091bd142d0a986f2e4dd25710ddc0000000000000000000000000000000001a5e45ef9b2ab62e39035ae9c262d79edf840cbdb149616f15c2f57647eab6cebf6946ed4159f95b12e5dfa6b04312c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c71c4663fdc5c06dcf0938869f6e33bd489613ec89bf26e8280496b23a703890bcfb510ccd2ff3f7e9cd00d7ea8e41000000000000000000000000000000000dbba6ee6d63b1c2b8ef08499ef24424612a49a5ec72148c7bf8ef0bf020cec6650cc21420b9a0a8e88a52e57b0bc5a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dcef986e2fe959522337b62a90424b84fa806dda9253632bf87e20a03d507ec82e731ff36d3280ea3fd0fb258031b9000000000000000000000000000000000cc6b5d543f20d9f558006e97748b4bdea619263dba3e502ab17d71a836b42d6de24e3ac4d3e45c8a6977e5ed7d2ba501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff9b2046e275597cb45d9d780d77a1107bbe64995ebdb125ef6fbc05b2dfdf776f93ce2691cb41a35c943164b23b5690000000000000000000000000000000011d0f56496878b6280996e2436440782c71665d33bafb3d826040aefcca2c2d065b9fe46c44f93474275fac02071496d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018eabb273bf7f868bcc52623cfc480fe794a8a39fa8f3b4d86e8185ad0cf13af669d2a852686159beaa4c9a8fffb6ba000000000000000000000000000000000d3896701ce5354f859e07b5a8273b34bc5f3d8c17390ad2509db8241dd7898528ec5c2c915497daf046ae8644fa13471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000735fe9c2c56a75e904904763faf30def907228bfda9f68eca8084369e4e4151c3563085c52ad454921e8e686e91edf7000000000000000000000000000000000c595df91cae71b38345fd0e0554c0dbfc0470737edeeea613c11486155d7f422054d024f8d34adc33866666d9545ae21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ccb57a30b0463e0395c38c756d6790a00c9b02087a76c4a21c5f819262d2eef026cff7d6e7a43b2c8e0c7e73015ce800000000000000000000000000000000114602f60b9d0bff0134a9d5c6c8e18365364207f838e0caaf41b070f5a9c3f50bd2b930314cbe9dc75069986e6307f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea2e01cfe19b683728793d86113391ba236b3f5f8a26d1a87be7c262fcb4591d8fe0c79c0bd03c0f0c3f596c70880a80000000000000000000000000000000003992bd04e9b5967a289f6c7673ff209018aa1ed2188b5da54c5a1ff2ae5e856112dda2d456404cc866fdb92dd8c49c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9099f8ca2dabfcde480a87d922a9e5e374241177e90f82d55be0cfa1fa18b69050c9c38f8d8bed3e491946937c46f90000000000000000000000000000000018a2b379c6bdc34b8c9864e686a8e16a0222db7f8e1f68638a627dc00c09ce0d01ee8e4eda121b1a043d8f3a5372aeac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de89f14e969e81c34b349e82c25b34753438d3de9f49dc551fe542eb50dba907fcc9f8941be452206f23ebbbd640f08000000000000000000000000000000000af63a1ec01796ae3775dd6cd8937293bad0588faa690e707d26706bff4540867ad80fdf04a89f7dbb9c2184134e9e5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c64b803d391a4c6457b55894be653be668b4dd3094231d36c08d393c9e3b575e59000170f4b7147d6a337392606ac2000000000000000000000000000000000639fa72b9a1cff78fdd3145945e8a6eeeac9e369119d366d1014f8e5839536278f8521f82029136dc4dcefe827596c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3e303652331c8e196ca0ab7df3aef8637cb77209d145140b575d81f945cbedefabafe6e89c897caa5b4d5ea4b8256b0000000000000000000000000000000015c592e43e21f6866a3e1b1f76b9279dbf33b4bc48c1e38d051e18c15aedc4e892f926cc62f3d763567db9010ee6a2341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ffb1efb5f6283a1d0e1ec4c396076fe0f6e36706a2ebce5a14b2994c46bb5f398f15a793d11c4228b0f32fb1fbd021000000000000000000000000000000001733609f21f78debe7c3d26185fa6eb4db7424b6dc79b3805e3ae5f377c087a9420bf1f93382fc165d3cad7fe158c0961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069bdac1b77d25211546e9b2693c851d66ead7307cd12724a22721c9860d7005e42f4ee44cd52edb107836489a2965bc000000000000000000000000000000000ab790d61fd02299d0f06926b95a4a5c26326a28012fcb141d24a4c114e9276eab60084418e95184314d324d15b284401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000210b6dfccab23641922ac03f1cd1773391a9d12cddc8f14cd1f5a172b6206f7885784e2af99df9323714d6ff3f4483d0000000000000000000000000000000009b76b46a35ae4090e0ee2b5c631bbfd815efb5caf95707eabfaa35299819509c4803e371dbc1c3df633903efac630fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2cc0c0022c9f49ed62d6e20ea3f4f0d62b58cc089d08a7835d3fa3aa945860d6cbb1267558f8e43cc08caa5970f36300000000000000000000000000000000086ced2dc798345e61546d7af83d735d3f9b3475211e458acbdf673198c555967726e87ae425fabff13eef7bf3fc8fc81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173a6e14c6901cda808d0d439251518b7bbdae9d88e67d695d793e396574b76f48606a61b14930aa3ffe89a2d96bf6bf000000000000000000000000000000001253eedc01cacea5735ee0acf74039f72a3f7003e30fb1b57ee1374f22f4bacdc53f24668fe39c6fd3dd3b2094bf0df81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018eea4f3a33f6ddb1a3db17728d069af3c8b57fc8fe8f8a6af75a2d0492a4bdcd629a02a7341376c94a49549abed25bb000000000000000000000000000000000c8e685b16b55efc3a5d7612cb61600d660bf6c61922678621822642a6472797607289f0b49ba2362f34e31e298f71281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b73ad0d82fa06a1589ef7d1e2c8113a3c046acb403d34638ade0ed070d5a70488df9cc7cd3f01172a88b1975216d3430000000000000000000000000000000008a0a0743e7cb4a32897c9bab96f09b201d38cdfbdd2cb8ef738cbe34ba54dc1fe7be8b5d9a95187705780455bbaf1fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141a3b4a5fee89cbad259aab46a1c0569a1a0a553692e877e73418eed9294a968d15ffcdbee6bc54dcdbc71f9a9b794f00000000000000000000000000000000080f3e1db0af9ae7e7d426fc5dcdcfafa708cf83f454feed320c1f9ead4f2c380a98ef09198153d88397b6fb5e937d851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e321b654e27c5434e499573fa0b0319409b6d24b9273d0d01e82f946c7736bf4c919bfbcf84f4d74c8d3a04eb800ce7000000000000000000000000000000000d6ef2dfaeaa917770bdbbcfe57446bccb1023721797ecad6cb74a87f1c2697e3697510ddae7a8911bbccb33efbe65811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000766aa5fb6457a99413aee1d2ff3d3953d3cdfedbd6d567097e6dee2a53609c7a3d1e1f5f4cf4244e3e7fd9c906736bf0000000000000000000000000000000015a7ee941771fd3fe9d41bb1ebfa8a3fc0024e04260356f69da48859760c7a386624f43987727c14b58874a97e4737011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000574218c71dae1b8d06256eaf8179dc57aca34ba1a9d19bdcc6d3ed6eda6492908c68233b358cc821e46c8bae5e77d360000000000000000000000000000000019566eb176cbcc5182772f8af4e7ed060f4fe426f1708c8f1dd85fe220f29c853f99de0ce316ee0bceedf80d3a15d4ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d539129ae955a56f57335eeba423c810da23cef10e0a0529fcec04af7722085b83e3801b139e7222d593110c24daf36000000000000000000000000000000001051d25895a515621f047cd12d09f34fb4c617c01f169af27e90645ffd02a6f355964f02498ff336f0aadb3d7fc1b41c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008cddb68e6dc68216dd18a139b9784b9eee498aa1c7e346d6600a2f31267a498142268354c02e5b29eed8db583dc4154000000000000000000000000000000001239d4b2cefe83747c11a0e8cdaf091d0a09e0065b97decaba824fd77c6f84d4c24d0cb919d2343d3486929d6b4e5df61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d2b9d9eae13ff4c0f27ee18819e7537b59d6bd78aceae13729bcd9270f9204163a45f389210be3643ca8ff0fa7ebcb0000000000000000000000000000000010f0d79e1d49b9c7fed7f7ff5b2cbfaf9b4b7e98cea3571083f6afdcb23393212d0b195a7e9eaf2a873d33dbff3d1a201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ce6acdc8248bcb148039ca8cc08780795cc493b29ec43820b02cb73c6775ccda6b9ffd4c6cb90c962f33d9956a679300000000000000000000000000000000088f86cfaca7d37e36553bcb6cc7d9bf75867f24056c48cba84715f7134d3144c2bd6c5007a8d0e5399ebdf2d25399e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166ca0a341e5acb98b70a0e0663737cdf67621802cc8386d7d03164c60a7e4c984f84be1c0db4279dd80df84bd56f599000000000000000000000000000000000130927b883391f40d4f605ffad512d5a172b9ed7b638ccddaa73f33ee3a9e83780003336b88e3d43cd098acbb7cd3711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000800be9cb28730a625f8d1483603de5fa31cb3cc3a6bfc3a4a2f9b08bf204e2af8fb31218911b73584016844c2420d39000000000000000000000000000000000c41d1d3d8a814e0aec48684a5d8d51d394960992cdddf43971c4e1781ed690af8e40b253c6bd8f9d8dadbfb8dd38ee41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d3e726846a89d38d2a9d4fd934843da13075e70bb0e9d2c19a0574b224de3701abeba58fb6f28e95968c1f86d4e5c6000000000000000000000000000000000dd8adef15b50a576901f312179dfee26fbc2203b9f4f6f71996fddb13f9ef82c87775f16c41826b72dba701a84827b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000959ec02b5e5335a0d9d981aa87c9693cc0e545d3229cf43e070963a2744468eef7e28d34e732b8c7f5ad4af943e3206000000000000000000000000000000001772729f3ef9e07c4ddf99e17f122fd3f0aa398356cb3561ad962b2ab6d31bde2617a7b7e78ee11ad59f2c4388f23cdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072e87cc0deee35949607c0a9bd0ee755a201eac9875e78c13f34c6e5f0a2e33890743e8e1451a03bed440436ec573690000000000000000000000000000000013c8590094d369fc3512273dc36556998fba9b203d1d2110be7564589cc1bd19a5940c93aa187e980cb8050a9867736e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da0ff079992e8a32739a60928cbeab7afad84047b173cd5bedc9a0285f0d1d2b404b135f11d68de35ca80c57fb360460000000000000000000000000000000015e61e00421b13f4f91973c308d9158f3c0d2442f00d3576acf9e42b26568d47f5aab442ca94dffcd136778cf3af13061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059d8ff3785a22535e251269fa41602e6b8f6a4dec9187fe15743f841a60481b25ad448084ee4a15eca2dbdfdf6acce600000000000000000000000000000000157b7e92bafe3203a317ee63fa8cf3607414c797e63c41a155a8698399a5e4f1024af4f53f7a74286804f88d478961241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019736c39d7edcdab5df31725155aed52bf90f51e4d7ff5f931a68246a74f1fb24d287243fe3a9148a291e23a68bbc464000000000000000000000000000000000207f3ae9e20a5a9790443fcd503bff1ed947df4624bffebb4eaa1268e1565a96c7d29d1f22c2f654dffb68463a63e0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad47bab9eb5b8d9093c249ff7e825ca054778524c1356d9ed13f6fde88de012aa120719b14685dc870c6c3adbc2189f000000000000000000000000000000000f0116a3cd42c55a1c208dd5056e32b91183dc19cb09b6b91aff749604dcc5470ba741edbe677df8c39fc2cabc1cd5a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b25b85607df57827358670fa948ded04020d889ff094533a2e490098ecffd6a6aeda10145557c20e6950d338f7df2600000000000000000000000000000000049eee265b0c90a7db6688df2a1312c1fae3de19437d0314877d81693fb72c0394cc0e1419a77f3f9e5a96aeff1cd3421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b7daf6ddff1fcf4c8f81111a1ab5be32f7d5618e9c347b29794fb899b5fc2fa6e693fd545f08f4b04483598876a0d2000000000000000000000000000000000ba1cf2f8c76e90d5420d2bc5468a65a6f518b906208c54af9a2a27eba945f650368d1446befdbab2958ab918fb95a9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b78cc0560c92bd97cf8d8a40b84caa626864317b970118a13f5516c8ea5dd2b75b15104de6d93e693e8e2b889dfa4ae000000000000000000000000000000000d44c529592561cc6e3056d4fd2d8d0e678559c2eea1bb66caaeed70833dc59faa4fed40ccbbae40dc518e477168e0af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013496b9d2ed109e211c04a70d9f3b50d71767087bdc8362641b555685a5671db1427e31d5c7d68690fd89d9e07ac51a800000000000000000000000000000000166a9acd043cf2dc69d9d416994105d81d357ffe06059d514cbf25d30b2a0729e65ef0061846f131144f8ececae4e8d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181802859d2b59d94dd8b4b1005c474ad8ec25931fef394fcdf35c8355d5c619ef63ae77cbddb52188a0f8b7dda81a4d000000000000000000000000000000000c52da301d030c2ace3f9e6fbc4731992f6cd20a21f006f4e7795b5fb01e2041084d84a108606b4c202a06135ffeb22b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165efdeca3e7321bf5624f84096b952237594564ebc7d07b146cad0249a03563ac269854b584208806c16ab4e7a0d478000000000000000000000000000000000ad08578ee635820578fc23e628d9f556602410ac69f9f444e47ad8eab3c1930b25fbaefdae214ec1e73ccc15f467f511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea3f94377b7db8cdc9c07a6242e46d37df61b3f93a83c4d7153a214c1b1ccbd37e7b15676da27ab2821e45405ca37b8000000000000000000000000000000001639cfb8fd5a199bc39be5992890e249ff0efb686f91843690dd66c27ee3f9edcbee26957b1a69bcca501a91ff7706461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062960c583ead123b4923f780332deb7ba23754ed858fe67686ecba37dc4a449bc234ae37cf90790bc58af88893ef2780000000000000000000000000000000007ecf5d84483887d6389bbf1a326a9581721d8c77badd692055eb5e3840e331ddbcead90efdcee4991437e3ee541d8a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e12d3d046565f3b6d5036082ba586f6e1d648e0fff76e3c5e8b2e348234f9e3d60e15a86c27e04997812e6d50bfa040000000000000000000000000000000009c44527d13880c1f15f2c961c3508d0d5bd598f345c96a10de41e7c4f44dffcacb702750cdca15d5aeef2ae449611531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001606f0f3d050fa67a69812591c236cb6a3ee0fe0e5947e92176554b8b495921c638740fd397522a88a8a768e64a4af19000000000000000000000000000000001227c2abe891712f4a542638b9214e0b662c151c359e95fcec56e7d284adb7ef622bd33c4afaf74eaf575c2e90d139f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c4b9fabfb4fd9728d7030bad50b637fa0c1ba25592c3398bddbc28ab5c05c17cba0759c693ae3ea0ff35b5f1e9a217000000000000000000000000000000000bb1393d0bd54135053797faf8389dcfdd2a03002cb8e8db1fcaaf0eb58a831292cbf12cdcc53b903657cca771c67f291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b85adef5e911bd7e261ab581341c7f5c44aca9a9b13b7fe15530b5dbd068f2b23fe3f1c03deb7f0ecbee5c4908abb56000000000000000000000000000000000cb84c4ee07b745ca74bb4cef45517864074a8a0f674fa56b76b1f90d0b26a5ad2c966c55ad4df043b7d2094eb6e2aeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001694ca1c011322e914a531d250390cc6b7a64a54741503ff4dcd65ef2b35b13969836d48b489ec296c888e09c2d1c523000000000000000000000000000000001977c69eee7e6a8ac94166acc5e0a6cb3d09b8e83eea1c62fde07ca5eb21365f7a1386a2c4b2dde5144b4ca820b47f121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170c67bd68b52f63e92dca20cf11bd5c36efde65c73d1910526c686f620aa7f9803ae8aafcd0a2fcba8b1b843c461d6e000000000000000000000000000000000dc54dd4c1f667b2aa723f5cc89e2b2a4f3bbe20d1523784b2aa69307223974e267250d901a1a737795bcf01b49916761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3702f67163b324914a469ec5ae6ef073022613fd8e19618489df4f4c3b2c338a834950ea8054a2397448f62ec7c9f20000000000000000000000000000000012f2eff7425ab8baebe628b97e5391ae19bb163440886c0c192864218953e1ee22e586029cef53bfd44dd43b00a184791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000acec7e6492ef1d2dd309d011a8c011f0d4a137e9c859d066e490cd2d5d07e4d6074cb36187ecc7ba43b6c8e11a6d6ec000000000000000000000000000000000521d6c2a4c8ea71dda1e67d2bd73b82df04d3651bb790dd412db04b9c716044f7aa3fffc137bb36e489a201c285c22f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010421799b261063e1a1bd13a1ecc5d7f76b0b46a5a15d0a6a85cf89764434c5526f9d2e34921e68a5df9419fc3d00c6d00000000000000000000000000000000049bf5795bc0437c4bc44e9c20e95a4fc22877932a7753386703f5cf7df049eb6d2b75797914d75bcea598362251aecb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d232879afb5e6c03f64d055440447973d0e548ec4dcb0ed51121a45907e806607dd4c9ccfcf9f175cfea96dd149e91d0000000000000000000000000000000013db5533852c4656db4962319025fc4cefce662a34d0ccbfde635b3c53962a702c013e0d3bc3678eb6a261fefb5c81711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a0691a1dd40b83b171dadb6dc2246601bdac2a2d9e0ec40e14e47ae673c4bfe461acc3c19db079030906241a1066d600000000000000000000000000000000009d82218ba2e0fa8a79acf70ead7ef4583fcfb2e7313e2285180927fdf48510ed44787f9276fb490ca1c16b0ee15b0021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e98868651f4ac5e573241eab717fc7d2aa54d2dbe297a8a41d676453092851f9f4bfab1e60f0e119479f14cf226199000000000000000000000000000000000b8e13e01a24dc52f259fc14cc5ca20f9d74aa93630d7728a2f458dd401ab2f33b52a60e6efd131b0d749eb3076154211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000463f32d6aeb56a8f8fc301fe574330810d97986915f81fcb44d14c511a916c0a86faec3c310ce15cc2faa55447e344900000000000000000000000000000000135e7b493d90c12d0c5d17824457a2ef58eb4710f3e0f02b422344f6549514404a06795332335b681b5c56cca6ac42ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140ee924a8f6a385bb311f0ec93809fcb2b1aba509c6beabcb05d7c1053fca0da389dbce79d20d807f34292b147ea96400000000000000000000000000000000077034530ca75083c490cd22c86d35c562e19773dd2eb3107a4fe7cbdac83161eaabb46c222298800b3b6a3cb9e984c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c12b54bbef6b2f664891fc51d4aacb4247e286b42273dca5860d72216b5208942d80bf3b3b28afced371394a547965d0000000000000000000000000000000006abe2a5f3b47223c52be7b27137f3ad4cc9064c871571b604ceada0c1d436079980b1500c6e4720bd18a4ef225bfab31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000916f8939af1b71cdf7b8befebeebe6dcefad363608c2cabeab097c75d1b5e273fae89e8af02f93fd9444cae0ac050c4000000000000000000000000000000000eddf90a131665ddcb25191154672f6beb0f7e8c786d741a10193a2f145b9646d91ed6b0133b330242d99b62bd006feb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000671dbd9ca01b25370cf67f6d5a767fafe2cfd419338d3b8fdace000541cce4d33644f7bc48508855fff27955962cf7d0000000000000000000000000000000009f3586f44655fb07b47556a435ba9d60f610a11a0f8415a1d7cf55583189a967af4d9d0cc133cfd821a806ac5efd5e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a7aa75fdf91e406c329fe61452ea9b5e2cb0eb505348275bbee2c1cc5398da2c0f5fc7b59f810050d0dafce6c30c3400000000000000000000000000000000043837c433a512e09f2e7d46ee03118c9f843994862c9bc8b10cf9a9bb1da6de38f726316e4c586910d77376ec449e301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139b6b621f6b5a506ab1b8354dc2200308eeeb4f84f2d94ec18a2e6ea30a3b2dda92e82184f1965b553f21a960360be40000000000000000000000000000000017698a432577048872d902d33a4cec34804b78b24e5db4012a0240c3e1e21d5ecd2231c38674e8969a2e433bf07df9491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000225f58d444f2bfdf5a288a69733bd0ee96c554a70e337261a659b795794c545d67031ffaf5f506dbda9675781dbf6a4000000000000000000000000000000000a6a9582e3efca1974ecab412d4865566b1bdd24e191089fa45f40e21960074336bcd1d7225906a1cfc414ae4ab131fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010c8da7727a0f32584747a94475738cb0038fc102975b2b4aad40714f4024ed90c3b57557576ce0df744b15cf1ecf160000000000000000000000000000000004c41fc346d8454f0572105d6798882a84d5c8df45eda32e6d5a1373a2857e57afd5c80fcb16e07643f04940abe317c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014707fc1f89793524b30ce62c6709928ee2b60288fc6aad5ae37499a5b970deaf3bd00315991d15d6a7b8a0a0225e29c00000000000000000000000000000000186cb3282e7bd62f0a5807a4c4ffe407d287fa8b759f16bfca4451961fa2cb522f5f12e3bc531645ee681c2f57c5a9f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015906b92e0e2927273ab3eee783f6a4a924fedcfde0b16f7ec41faf0ecb13d06235ccea81ea8a6a5b6a5514e21093a670000000000000000000000000000000010be2dc06b55c1a1c7fca4e22cdd9729f59943c95dd2502886687986da40de3445c7f96d34ef6c9355e6ac456df1b1f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5a858bea3409c9bb0683ddfc0600d2db8b667f80a63e26d3730e12e677eeebe5f6b42fd3a3bcee45f8fd150ff646000000000000000000000000000000000014f73254badd7abae6784dce2ffe0462c8072605cd98e0c7a3f9aa78e5c99f846eede8e7dc4db8165463344e96537b1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000edc3ded52d30cd7d9519ba5f990efbfafdde06e51f552d6e0653b2a9c95845868cc5cb4eeb0356fdc74a9c4657656270000000000000000000000000000000018f0aef7f0e6c1083f58822fddea79fa72b7cdc9b736b948e97180d40f0aba7028801bb69003ec7b3e5b8547c3444e8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c36332c65b1508ab2580dd203e7cba30293d6faa722693447e40a312b2d59c6f94b15aa83ab59d929b45c3bb58e8d3000000000000000000000000000000001549cc875a163c1c03f5285b1383582958f937cbe1881615c5e501970c06092436794eaabd1e4352d77302c6fba5c8821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ea466365f39ad591abf5a151a43cf848173a6fa2a00ae7d6a537dd5b97c9fef62f1df820c897d9c77f3e7f9a727276000000000000000000000000000000000eacf3ad07d54eec65c300cfb66bf700c43d0cec11922fcad82e4f7e249de29e08d1dde9709269cc5e1301c188b291e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000247937f2c8bd3c1d6f7ba1b168d1e0a39ffec2ccffe400de3f113076116e885006af62aedad8747ddcb79e8d8a5cf1b000000000000000000000000000000001914103df2d6b2526d4bc604267281cb7a2260b447d51082431d880398c1bbcf2ed5c9463a5112064f63eef5df85d7311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005381796a10e86bc6cd20ad90de53be27dbe025262ec7b4531001aaab2c65f03368eb89e5012d8f1de063cc65f7990c100000000000000000000000000000000012a546e0e18af28229ffd401dcbd6aac4c59b6979acf270b498f1e5793bc23c1a6bc1e2d0ad40a3e78ef4f4abe1da2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ee39430e44d3a9b27d35a71ae4df9c3693d59e019a970517f7f29f1a7a2204ac485f859cf544b3371be80cd7fee4ce0000000000000000000000000000000015ccff4228a2c8039a6b0ad3f2e867140ea810695ae5569b39d35205b5cbe66afadb72eb3e955ca4123aeb778388a49d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082898bbcf99b9a7cb5e5c36c83c821140494ed81477ab0c841f0aca2462170f13f191eed866460b2e0b0d6d6f4190070000000000000000000000000000000000e9e9261220d3a750221dfb52f49a97ac10371847a6057edd4ceb35b395b7f4bd321ab3f4ba174f19ab9a6b6f404ae61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001533fb5370050c488e5fa37ee750d3d72f6bc25119f93111f23ba4237a0bbb470fdf6fad2cde62deaf3242f8a7eb559e00000000000000000000000000000000113d5d632beb247c117666027d7fc5383e7d6793848c6b7009d62051f140ed84f6ae8f8323edfb9f789ee61be3d1fea91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c65f8f669558acc176e1cda87ecc9e30c0ff4bdc0f974231ae9bf2942c8f1ec068db6d0656a2e071fd9e3df91f869f000000000000000000000000000000000c8b94cc801be6ddf9f984291c23e01152b8354133fb7b6a876c564b37f9dcc2c9964d09ff58a3966dec741dc6c4d1d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195521f1c8cc6489b1459bcb7bad5c5e7e63bc7085d7a9366def84dba07111a33b409c7ff29fe591c17b8b58d2f060cd000000000000000000000000000000000e7acffc461b874fae3cc5ec42545c18831be14229e7ba891b6457a484a8ea843fe4f66121c17d1cc2d8fca5af04c5491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081ece4bcab5ffb439d5441a91bda095a45c1fc7aea97b7a5ba41fe03481dea9c366f39ad9192967123e04a1dde6ee59000000000000000000000000000000000ede071bb318f4d36e562bd3c38b7849a3bb59e3e06af55f77257ebc34a14547efb8a4788971553b0d62cbd7953d2db61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006dbc1750daac84f5359d5aa452293902238da269cb207c353ba8eae7cfdadb1a73e127e3bc5c7e038e74d70a1027982000000000000000000000000000000000ff13ef919373a6ab51dee4d523e8ca2cebf62f55de7196540867390c796b92ac45cbda716d0e6e49f70403fbfc1671f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ded8ef5bfc2bf0e4877ea2f485e6451c22504f473a64c2c1ef223a91b4b64cd4d744856a3ec0dea209791a7f72e4a5000000000000000000000000000000000bd4aa9bd580d7b9243ac324f5ca1317e209512779c64b2357635a581e7aa7e46ac09452df4dfe50475ffdb5f8e185731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028349cc8226cfddc4c4893e1fd2e21e65e7fd90dafefd73de447c138c3f3047788aa7ce70a9d8c667134559e3454787000000000000000000000000000000000a1938a7e55e54d4e4d1569ee92482dfca18070116edcfb0cb1d347ff827d6316a50e2ce81ff6d078cdd282ba2d1221f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000005b8829e7072e0b9d7bc195f665bcdfa4e0206b21c8a6084ba98293398267a62829a7366c9fdffc96b4f647b36b40d00000000000000000000000000000000086229ce7ea618ab851aed9b39fc51bc286102255d32e9c1275ffba916945d2bf3b3dfccd7b08e180ca567e22143fb341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fdec5f605990fff4f24b9dc91920de637d2d1a6c1510923c1996dc6a07d255cb70e961c6c29453604aca7240f5b3230000000000000000000000000000000013757a0d6d54db50d7e525d3b9ad4efc09209c8ca3f7e713270ac05a6588d11a916638aab61fa89464c2097b800310bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061f2d89204e10b09c7de7bca0f1be0f0cc3036e9d719499e5936d1aca56b7282a0e7777139824b22c6305fa4bfde5e10000000000000000000000000000000018919fe861a16aa91eedfe659f89a6dbcdc18d72278906c357e2d2865c45ecd54fdd7978d6b5b65c901cc22e6aa286021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080b843e9b740e246f616d2022a6eaf615e1f2f728450a61f27e5977a5570e18f5bc1a758221356c681f352fc6105c61000000000000000000000000000000000493fb5fea3613d37dca1a060d4399f19be49807a32bc22843ac6ff3cd88db9c2e532ed51d2c98c4bd344248405c262e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8a0e714748df41fd3bfe287ba2151fe0054fee9a21adb9817b31c096b85132f5601c0d891dc46ea1037c65ac64dca90000000000000000000000000000000005045be4fb6798807d73bddc998e576ee364ac0a2ab5df7aea019fdf15d413fe7853ccbc576f875df66bd06fe1e7bb6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d3e4fb948a2cfd0c563ed78d1062688bb13f168b895f8b6e5c6aeeee7e0fb7dad0a5ddd36fb06614ac295fe0ae7fa2000000000000000000000000000000000617903758b9173c8072593a1606844d20af9791f8deb4233d16f8ae629f8d0662bd4ff416a89a4e284fcb265b855a7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000070f0ff6a9a64b2ae86e04945aca036d3b806752660e9eb15982902181231b6f9d224f405eb06a5720c195d361e88840000000000000000000000000000000001070edbe9fd7b565abf56c2907909391bcc462fcc37ff6ba6c77ec54c942564542d85fd636459a02806beed71675e491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007de78240d34f266caec2813479e960946c79a6110a4d12d2cac25f0ba2ca9184412b687b77e4f2dcd0a296223eac3dc000000000000000000000000000000000c33a72db7cd6dd2b7361164a2082d507ade7e902db73005bc7e2372a7b7449644703f55ea44ed25095ea81f3908fa4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebd0502f8e159c02ed8c58b1e7ed8d5665384ec530f5e1fd9c9771e2d1415294204b6c3c043e195040435692a7000210000000000000000000000000000000003a09086062eeb6f702b938f0b70c657fac579673544f9e63c3e04286dd7b71bac4ff5fd457e984c1617c5742d46a8871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006025ad59b7df3aa441710c18f93bbd772fd68597fb8682ccb5ca7dd04db58d0babe0960d61122da138ab3a2f579fd43000000000000000000000000000000000ca4a8e10c89fb58835c4338cf93730e0c430a3a2272113a5db93fe0c974bb752ddfc02ec73f70013999cceeda675e7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b6db9577aae205f97e25d829dd20a2cc39cb4d18156532b1f227c3d17e5b15a0eee570f558bc4a8ebfdec4ba6fbe890000000000000000000000000000000011fe3da32f887a845050e57cbdc05d23e4072173347fc5e9db6f2b937e7a96e525183afdde465df2d6d1e56f82bf2cd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062199ed495ffffb1c0f39a93c5ad6cbb1e8c6d49f168ff6b1e270d59db6dda48776214f36bc1b438e104caacc06cd70000000000000000000000000000000000a55e4e83234c75950015bc8dd867c79e0a12eabf4311cff26ced23ecf717ee3c1c3317c1f1004348c4fe19df0defc2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000227ffd06cbd6820614adcb7abfb9d553a4ebe02c5ba616878e36e478bd8e04e125604bc731e6154ce6be59efe31caac00000000000000000000000000000000071d7b9710bd55c0e615e4056f8478546e1f6a906c2a8fa20a8049e884bdcb31dee4369292815aa3f7b3339e39dbd53e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db5add9c50d3ca73627d8ee12f677c14c6cc610d612b2283edbf0bae8bd5513ce98da888831cdef2eac40b38cd54ff5000000000000000000000000000000000d7ee423fd35f9eaeb6f457759ffe4b59e54f76e8e0845df45d63ae607f7257cc6fb99117b3a752532bc04613e1e367f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f1253ec214376ae4904edcc365ad68143e3e0ccca4a03dfb34ea75f05763d8bd586539155e0fbeac9c41c0efc646b50000000000000000000000000000000002d27760d9a95155be78f890f2a6b4cd6b4273045cda3554a0927d01641fdf70962e0b54080a4989d8e6e5f28c58aaef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e57fe695c3cdefea4f98a16dda72691866839f4d9dc9fbb7d729eece71e6611edd23148d99092b2deba874224a362a00000000000000000000000000000000030f69f0f03dc7249d8e64206489756ff6c695fc21fe37b34590f3d9a9d2e85157d60c98bf2442ba22da7a6e075cdf911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f927f8e5e4cbc7a1081069fb3eb9b2841ba715b90218830a6a92c13085ed5977bf1b54fb0224ec94a62759dbfc694a0000000000000000000000000000000012677b732b3c95f68f1f29dd67c57e4f6f2d3a9a08f1c3d3194a4880d19d2863f7cc174301b298157581fc6ad9ae65c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145c026dc37abf582d157bcd145d13ab4b27250f51af8aff1bb9860501eee54115f398bc6c157473e700556c8148ac0e0000000000000000000000000000000012219bd48ff9bee87d83cef54feb8dc0bc0208035218b1241f8e807dfa7a0694557575ec62baa40d8e32eac004e360df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee2d4e702869a7339ecf264e3b4e0d6f8060d1a0370f2bce559fce684bf66b705b10d3ca0e650d52dcd0dad704aa93a000000000000000000000000000000000d6c07088b7e7f1a0b85706870c343f2c5607f6b4a68086fbf9fadf7c5d2c494a0a18b97affdd7a7308c32f506ed84161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad3ab2b4362dc45d557cd857acf4a9331afac38f70336328f745a4934c26b909b7d5c726354c6b8a65e7d8368ed9f7c00000000000000000000000000000000044c6b8d2b35c3ec853d1a9ae34430059bb82a950bf4c6661e8e86223f3375ab683efd2c49115a2dbc7d985847f021921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001140135b586bd76e16457083bdc076db558e9b8ef5062d4edddfc0f90de9628bad3738bbc513b2816eedbdd91ad5b42500000000000000000000000000000000054a4e9528e853cb38dd0a2a932b4a3e48ae4d05b5c7cd6a0467fc5f7fb57d1387f04ce2900fdeb62acc7703786edd6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d380ddced173c842d0e8a16464688d47ad39453ae463a38490186b2db09c1ca6242bc22f1bc1f8b11d4974bd07fb41000000000000000000000000000000000c7f9a83fbdc43f4d513ba8f033fbd836d7ac7d9ae22d91b293ca0fc5375398812b1fafc353c5ec98540b4b1c5ea89821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd113f951cc41637a8ae8fe9eb6b229aa65168d94e06883b08f8def4eae28c99323018f09fa28d3ed48300e8b793733000000000000000000000000000000000e432967713b25a6c3e8742c970d7cbc7407975860ad57b06e96453fe8e29d1ce93375a719792def537545f9542c7a741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019463df93f9766d245c154be2fca15afdd264e515f8bbaf6a9aaef68e7dc187022ec5da5bdefadbfad57e35ce6c08e24000000000000000000000000000000000a91d47326c6e9c353bdeb0b4acd7db3c9a6b26f125ef4355dfbbf5300bbde537323cba5734f8de5ece51d967fe28fd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5d8c0aa6f45eac59793a44b2ec74c39d854350117f64ada3670d1ec6250089450d09cf629e10c9865919b2dd3bde1a000000000000000000000000000000000c824993b76f7e964a8008a0f2996263a2aeeae7ff1cb6429f5ef082abfd3f19a450aa31af186d8f0a296a8719c8040c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001845c391fd08576749f9c8fc70542d5297fb0a514f51043311afc4ea016513e1a57b1ac4f297d7fa305b1768e9ee7fbc0000000000000000000000000000000014137b54d0893b47c1b5143f1da6771e3da0a09f1d1a8ab574fe48b4288885b454ebce4e5d7dfe6d1df0fe71e2b7d44e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f23089b8c117d1f7f135e4c5b6cfd77be1dbec0097f7ebb25bab498780eb70e2c7d5d5e5150cc948f0a19425368fab00000000000000000000000000000000114da06fd9ef52ee44cf3a4e5f5f63b72cdbd4fe9966fb978b231d681c1255c8a99df3b26fb273850c84c4e750ec7fd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a49dc3573bb9f327c243099fb2cdcbf42f850479d0e3f4ccb2c913ed9435088a639bf100ef3fc6bbe73092a782d035000000000000000000000000000000000490a254a354d2dc461172bcea93cb51bdcbf633eddc0afbacdabc72ae4f68246ca062a43418a6557f0689bc7b9186d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185cd5665aedca80432224a30bfcb78422b0a50c444ba039b762a5999b2a112112229fc8adaf91cb52ee0091930f455b00000000000000000000000000000000077d7bf47b53617292fd2c909a3d35643bfefffd6593e5fa9b76aee416c6ec12bc1642a2584dc58a363c6d9fc03731111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019193a7130e849b48eb0d72e4f901181d640d79fa2bc1fac75de6bf535a13e094258fc61be9440689266c383d1fbded8000000000000000000000000000000000e178f92c190e3bd1e0821e5f63ea0e9bbcbcfb9c387c2753d69fb4d9516d19036d9302e93d06364fb138da3024b2cb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5fd1e985dacbf4b0308b64abad7a4bad38677adbbb443ac32377665f47137f776b4982dbd183ad33fffdf7471b09a60000000000000000000000000000000012db89b6aea7069827799ed4de2021e23488bdc6d933c656eeaa9bd7b7514271303638ca6a0c5ee9ff549884fa51653f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b889e8d01993f0358c3e1a00af6228839b77d011400d36955b8756ea522324d03d4ebc881b95fa5b2f03b442bbfa8a000000000000000000000000000000001778990e3f7e6f36dc75ee88c1279d7cd281540bc4ba26f80de98ab0c1c8a2ec19b490b23d16a423e2d7edc2c58647b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a4ef6361f2fd6f42895c13bb4c2c90ab997952215c8b322ac485a4ae8ea9d899eb79b145efc6f63ca1a55e3d459d810000000000000000000000000000000016c6843d3465bf05e37046ae0eb4866438a03ef1477210f151cfb0cc575c386cdce75bcd8a17289bd367704f3c5673911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5e3b7e9941e731eeba60fe75665ae6a6df1b23bb22667568d3d420f55e51fe50535f15b8fa2b1d609fdcd9291a5f00000000000000000000000000000000000c75ee60ac0f75fbbc8e9b79ab9e65dc2703bfe83060264f1d63ff62b195de69e2726ffb23f0202f279c73f484aec0721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c004198acab8bab037aa60d43ea250218bef6215e88b42599ccd231914b2cc17a29808fc77d6b252bf5bc5d60471bb0000000000000000000000000000000011b96b416ba8c7d755cac3b86304e7c0561fa731caab700c0e343c173e6d0b2f6254c42a5d8a0e4792278112a8a87aa91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000083a1109468bd5e64a468f222bb4ead4601d0b945b78c1af687df288b86b210f200f686807a0e434737cdfe32f05b35000000000000000000000000000000001728d02edb94e55d591ae9f4164c9986743059874e551894ae2119b0e518ac8cecdc7cb9ca1a35e67eb1cab1f40f1a891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001149136a42a39611bbd9645df50de68daced9269dfc24ec8ce5ca3b5b7419ff8b8262cd4e3b0f92308585097c3aa7741000000000000000000000000000000000d45bcabec8890c376499ace9d55bceaf3fcbae6b65e87eaebe6cff106cfc803392b01069e5923e5e888e1d4e7bd1aa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a802e2e3bfeb79bfaa298d4197f78b02536c5d9cb9a6f3caee9ed1583368cef9c27238d11aa18f22b62d5860419f0070000000000000000000000000000000017ee28c37adb417311e4044d42ce6d02bfdc9d647141c1361c5a9726ebabee5bbf546f8db56d805b5239b4491750d1781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003dd4d586a3382571dc7cf473b7ea6eedee5a8eb1762ebd0cc606ccc123b17265689b679e9b4feafe69ad7af462fced4000000000000000000000000000000000aac13ab1c36e1b27c09e6e763510873707f17b244e8696c9781d9141bb75801a078e2c84e54f5aa93ba99437df660911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000600775281216279d33b07bed40344db56026041abb49f8e97899f33f02ff91c0645ff436adb6525a0a76b79eb1cfd0200000000000000000000000000000000141399b7250bb51fd54f6a1627f265f7dea3dd90d944722f86f51124fd9de019fe2ba770d2d64438986313bd17631b401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1d0088e2060d2bb36af9d528b8333d500b8d972e803f179551e9d80aa4ad34f964e7053c28df3031f9b07d56f7c8f60000000000000000000000000000000017213d0645431f4c3f5bb3a081541c5f5ac6a986aaa5df096b8c5911d541fe6994a617654536e5bbac7ea41f27bae8271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012cf24e7f89a9351000931121519767dd525f9c94ecaf11e35b626d858f5f9c16d6022b246a1363f94bc13fd6b45c5e60000000000000000000000000000000003e04214287bd4532668ff82e2cd2041d57f8d672d08f5aeaef447b50e2149722516c586dfaa6ff49488ae6b40b875051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9259aa5488052421e3d08f2c26ae1db4397459f30e769302c1f6c1699b7f20df53bd7e42563f02614db8b469cb28270000000000000000000000000000000015d7fee47feb93ca119e2131efceda451e3c1971b0c6bd62d7d6e2e25df39505ff746a7734f39c7a3f4fdee4e466b7481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018697783c243da0b0a1576a07bce66740371fccaf37027406e0d51fb7bff7156a0771fcfc267861ecd8b489dba8bdac2000000000000000000000000000000000ea43a8f73d65a30ba1d9591075ee86e2397d167a9b377d4c7d85cb1d7505913f1c5c92be53401c182d133252045a4f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000328fc303165f9ae76ca63fe8acf9f9d29d98853ae2f6611a82c83b0a8ffb8184f462cab1fcdcd2e4aace69a62a55fc00000000000000000000000000000000011b84fc9f5db0e4bd64ec4c50e54bde6377536ae497b294de044e06ca9f7e8c1b3c01a68d32fd38650a53cf6de9476481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000157f45f4acea6ddf56574e911b007b97a8764b9abac0e7f72c149b5522e162bfde1e2a51825cc70faf5fbc8fe18d2a3000000000000000000000000000000000ab77e7852136a9df30e59b0160f9ecca2b86e906f7717db2c772200a8cf4b31e7f4bc866a5db4455de961f289269bfe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011045b55a82fd56fdacb0e0e8311a8a7eb41cf6db5cafdc2f84ca2ee78fa23bbae5c3e83cd542aff17de1a7ccc929e47000000000000000000000000000000000b3f6dc2e047005d0248eabc12bb5d8f055346acec2186973370db58a4eeaaa6681bb34d881c02cd166a2ef422c45b371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017199fde141217bb533d621b397b3e9ef1cd0366af049b58f72dc7cfaf7d1edfbaa199ccb173d50e747b27a1c72d035b0000000000000000000000000000000009d0853a74814f3991961d59585e90f4ae4a1be143dd8b8e1ef4f972c606d25e8f8786a800a31f83ee97d21ac0c587791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039311487024a056937fe1516d2f9d4c10feb431085202f049d3b5108e59abf626caca43be32be1fcc83c0e7229604dd000000000000000000000000000000000681075d589c0ecab84bc0727b1d604ffd170e991ef39100c17c5276ff0fa082350f430b0362688d7b90e9a9171ee3e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000802f41832842ad75f0965d15bb0cfa08ceb6cabf0f2749c6166e294a8742da426250cf06a35e47b9f59447dc1537d1c00000000000000000000000000000000076a075da305c8f1acf0b9cb611d253928cb7da90d255146d8243a88fb0a072e901b312cd0ad886da7600c482dfb3e2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dfc28db3c4f92586d3738350c98948bea45d80f1d4f0e300f5ca7ee675dc534de1e06ef0fc1121ad3c20b3d5ccc36890000000000000000000000000000000001649bbff40f63e637d34956f68f61d9f38a427836d549efe0ea08657b1a417cb45e312fe844378abaa052ffd69a8d3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011b944d1c6f3504d8f4315274d450308c533a2bfd513a3a0ba617277c3498784386f703e84b264a41dc2e0af4211b9530000000000000000000000000000000015829372d1acb8ff8909b6f757ce61ab660dc0a16f63788a7486fa204cf19ee51e4fa95c72dc1cc2ddc867ee45a76bc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000273005b31ddbbeeb9d3d2adb2dcc56bf404b26d6509692351674370b664461be47ddd0c69886158e677b99f574b1600000000000000000000000000000000001816657c659db7fd665202b44d99d4797a6bd4f319f8a49f1d146ae2385b1742715711e89150b62803f3c0b2455e52e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148965001e27318d85d826c1598507b6aabfe7f2e805c71a9ae4ec90ff8e1f3265b9c4b2536c5e147d1ebf9d0706cb6100000000000000000000000000000000157d1cc99e8aba2d5573407654cc20df9864855b38e28d0294e07c4fe0cc310168dc7372200e02dc6982a70e174e599b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a66ac4e0e3fb93e28fe7444124b87f6c0b90eba4e3776c0c5b7930af603b387228d103197bc156880bbadbd2cf55570000000000000000000000000000000001e855e172a4cd25553d1cadc2f07fd77e5f2246a53fbe8ef0fb2d0da0ea0e3348c0669c2d3158d25d8185fa5cff20641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019703d6050df5137a8710133c5c71a53291b249f6a0451a192bcc754b95d381f99e5002dd01a6d4938d862f4fbef4925000000000000000000000000000000001507757065f4ea16eab1b523b4ccc16d3a153c9086124659ab4731df6d49bd31bbaa6acbbbd49e742038a35c070754231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107065e821f77b06d7c0c70f036daeb81be64f90e128ab4bffb1d49b21fb5bca523b12b2122a48bedd3844dfd41d31eb00000000000000000000000000000000191b6c33eedbd8bc950c5160fa4560a0b174926d486335caad5f89426c6a7278a94a30527191a5954ce7bc914df575331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019db69c003d015489baced0eefc0003d8e121cc9ba7f9476b6fd8e3e5acccf31569c4f396a41918b3d3236f2d08e8b86000000000000000000000000000000001499783826b5782e09def40554dbca40697c017931d1ecdd8bff5c842fb354c8a4740952a19fa6594b9c8cbe26ab75b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018fe7379f752ec5f32801d8efb06a2c83b9f37adeb1d9bb6584236c9c13eb52e820ace40ddf2fd908f0c7a9a778de26600000000000000000000000000000000105afa7ae1c9c215091615fdd2cc577875bb543bbccb24b28b056f2c58be381c608033013e39ebe0375d50505e947ebb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a61669016f3fa47fe1f8fe1cf01e76783401f2b53098fce585e303fe922360a3ada0c5e3631c08ba8b321ecda1f5440000000000000000000000000000000006b8d35e9355e4a9c9c204e317df1f4ea66672f13ecfeb7c98468a1a3508c60b71275631081be367ab590d4fa384b43e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001088ec4bb2c1d03d523fd95997b9ac0c89b2dc01db6fe89c27c055b01bc4c8c5dd1e217264bbc4f7cbd99e9dec700dcc0000000000000000000000000000000010b64e3d64d030cffbea26e2a90455635924066f83d0ad071019adabae7c7db1a34f9fda1a3960599af9adf20bbac16f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000def07cd0454a6fcfb4d6eb9b84925656ab0859ae1a18c7829c003feba025e29f36912835f73b1e7d448613c53f1936e000000000000000000000000000000000e08f24295c28c656beebc76320cc9e17329ec8e5ed7f1dea11ef52b0189e783fa028fc5350f8f8e98dd03080cdde2371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107f442f86a16eb837fd6ec54060e56b2bb8fc3bf0730c55d53cf3dd21a8a1a2c29150b9df2a7945014b7e9e9d5de6ef00000000000000000000000000000000008072523f6ac3fff24f7b3a26a1a1f9f56ed6b1d2227e36f8f0e47997cfd3b1f2264a7a34e6b1fd166984619f2c5b791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5b4bc4958f117f9a82efa6d0de128cf00b28bd01e18b539cc4ebd4ae846678207b716395eca5f7a1b5e6ce5bf00a9800000000000000000000000000000000092c009226b57054d07ac20611e0e795428deef6a9eb5cd190af1c5806bc0e5fb2e7c0b0910adf78a96bc495f995164f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f895bad8698089b7a6e732e745de1ec6cf6fd34b24b67febfeb1e156986ac6e76e20a06cb1bc57ff0aaa55643c80650000000000000000000000000000000005bb615d1f7af74f2e9ecefc9f3c3602376cc1a1c13f1d6525bba6caebd8fe205c229ea432da6aa41697c753a8ab1c0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac6a801dfe8e3f3f35d9e52f107a0ff07d1d06abef9ced1b5f8c2d3180430ea7e07c0e84ec203de75e7b6c8f1fb2d950000000000000000000000000000000001efa936a8166b3cdc82caccd2ad89aa6363be9c3937a06cdc4fcfef92db97ae63af365045f7af7c7fa28fadd924baa61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b2f952f3526839cc25c13a619b14e1dbfbb8bb56d31bfea291703998212dc233f61f52b2e77af723ecdb8cd922ad3100000000000000000000000000000000089cd07a5f8e28b4512f633beeff51cf3b900ffb5d66f57a65e674bb21c867202924d3e59687aa4498b2588fc0e7f3c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f8b04ee4b13b02859ed0111a9d28a6441a0d03a4b3367edf24ece5799e9496460313dae1057df3d2dc5860a0905ac00000000000000000000000000000000017ca4f4d3f59e2ed9c93ce5c970194c1d0168a5eb65a3ee95fd89ae098561ed33c3d2bc196c49d150490768f951f1a941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de3b06110793ddad32685ad95bda7c8dc380903b713e17e913c306bf9304714997e013a4282078798ee8e7a5184ea16000000000000000000000000000000000a8f0f8ece294b52270975068aabe8819a99fb2881660caa7c9bedf1871f381fab2721ed2192af1956739bd1340631e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd71c5c6177727c36eb1851f63a6b1a571484e7b34e1e94e1437754b1afee91c5cbfd0c9794d078191ab8ef7fa4685b000000000000000000000000000000001681b2b3602cdbe883cb09784a88a3c7b38301f5226e4132f537c800577712897745472d8d423675a478b56c7f2d361d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d78d5a5304918eb0a90fe0056b8a43be41f45d4241eec751824dc5f498e909524b3437c385eb6c05a8d03b49c664a400000000000000000000000000000000058b0484ea1556fd39d3f8af968b47d98962d889d88e975c590ebe4ceeff927ab2d538cbd24f53571980a5750cb698d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142b168baf55b1a98ed743f52c29d8ea9abd4c20474da3b8339c37acb7ff1fc3d747f9a236c55c3c2d603fc9a9194c8600000000000000000000000000000000181822c82bb0ba31b573ee2cdbea5824648da065c8500260844b914c7e5afed60496f87e30e08bc74195f4046172d08d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189061e7aa566adc7b9ce4c66ab3d038fc9036d7e0582dcc31b9e06f4d89c814bd3b98a854c4f2ac8a36b29c38ae658300000000000000000000000000000000143e826f208a9addd96ddcf81499b37a0c08bdf72859eb34271fdfab952b8ae6f1e1fd5185704b3c509d17347e6c56bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba10d850e242aea79c52e11aee963fac7df643148c90f831ba8183d96187188b40c8a0a337c8eb70c62e0428d42d42d000000000000000000000000000000000ca5687eeb89d15536c74f2252d7c6a33a1ce9f06b34dddf3907d8af242d39a380f8e2cbc075a1ee6da54039f39a4e801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001153a2f97e3a48eb55dfdefe4678f3a556965a01e8b504905a2734c2ec95ee577c3d663af4d0de31aec77f568ae371390000000000000000000000000000000005a745a13d4cca838abdc83e921b55ea436e9346215ddc66d5bd98f960de3013101f5b7813ad04890ae2d1935b1d009d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140622b70d63ca6567285b714635f1b7b315d658717fa23041033de5b7f497524b46a0c8a71efe3e01be7f5c5094b6f2000000000000000000000000000000000ad63cba7e1b7ba072b0fe39e461c13aa292018f0403a605ab55ed4475d89d8abacd9a311997d02de19fa8bc95404e5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f362c15722df42bc54558e61f1bad262c6340393af4d826ac675d67f153c9b0c7b034e74b4b3d35d91754d4d46641320000000000000000000000000000000013c997f30539b144b241ab9edf61bd652ff86c5143c3e8c23795e0bb8fce2e6eb7af1cf1f46aa1d1de02016e6206410b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a56e88b7eb5b1bab38f72365177c051370d5e4a79dfd10e3c81b4b2cca5c12b17825bd804a13beed086dd060add2e95000000000000000000000000000000000a9d344e63d91ef6f5abb87e195cf6a1c8b071365986b148b905d975f843cdd0ed0f181a4137f21da69d7fb8367c52681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c0e77243dd7fde8646c435f35d039faade5c922fc1f22e3c6d52abe2ef34e3201cbfa7268c0d5d1cb757272967f4550000000000000000000000000000000011aa246bd618465903f369c8083516b63f2cb91e6bd0628c287cf14c032d7721a518b1abae6cc8799841c4e6b680b48e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8c27d8cc181a6fa4227e3cfe913fa3390e90b385f145d72d7c0d8e5030fa4d3b2c32fb5bb079afbafac48ef0f51f9d0000000000000000000000000000000016abb9b7138a58f4ddcb25209c21aaa9c04aa5e4878d3df59173d9e5c4b06362e76278a1d474e64003d21d8c48e4b4991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a02d28f145755f9a964920221b80a1f93fca15111a5d15eeab939328b36be417fda08d0b31890000fb5e2ee4bbac5690000000000000000000000000000000019a9f697c7d9b9df50d456a165ffdb5c9fd5cb403f368e2178f85c0b7ad18474846885709c90065bce3e2a731cd4fe241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7c299a19eeeaaf9bdaeffebecd52fc715374e3e06fd76c6ba7a86c32834d6fb2a294b65757678809af371bebe2469c000000000000000000000000000000000945f1116e0d382514035fbded3aad76ebde6bfbd1c689ec16a908f9c7383e066c77b503f1df7f77ff57ec5291952ed21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000387cae57c2ff8970be249947f0f321ee9382b4c5421edcf0040d0b84122fbab90e4edb12131fa884781052e38a4bace0000000000000000000000000000000005cf5dfbec4fbf64ca7458203dfe3f7938620f52161bd333d3e371f767766891a784ee5a198b0f623bada0d6359e368a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a2896bbbcfe4a44eebb7d27e0444be2bc19d5d0deeb3f58bf93989672e30497792b4b2c734df7a642ab82b5020f2e30000000000000000000000000000000017e0013e66e14eec9beeb1ed1114d802ef352563d1aadb27aa5a4fda8cf57dedf0a896b91b6802d7df44931f80f334d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076a8c7e7042b56f1952637870f28d6cfe8ccae2a9a3fdc05d862b4015dd89ebf8e18e130abaf4c9d90b249c6fcba4d2000000000000000000000000000000000c3ee99cfc5df084c6c9c185709b35d282a016028a96d990ff9c6394045a9bb54cc5e8291977c0955fb839faa46ec2301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016825cae084a9708acf2ca8ba31fe7c81cca8ecffa5fd335d58d1ebb791ed08978cdac4b21f11fde05819f40da6538d40000000000000000000000000000000000acff77119356e1e31add7e742a9662b8fe864f77543e75eb389bee2a53cb22699b9ac8f1ebd0775a9585d161194d081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ff4b295d3b274bf0b43dcc4a1e1a6fb5e2a32638c5d8aeebf00a2d807c9fef92342b0060c6954d57c0cd0172ef89e500000000000000000000000000000000069c52e3fb24a0548755d09d7712cdd16569993d06f8c02bb6cc7a69606ce524c3845d8bf2c68d00afaeef0fe3b2ac131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbeeec6b11e1db3880f59b69af90796b96c803f9a3d339f859f7bfa389fad8d6774b818b6ad3dfdfb7d60cbb4d46ede0000000000000000000000000000000013badc3b037ada51c279ba6462aa14933ab865a975848acfbc664a491f55221d254aaf4115d18cb91649ee6789ba51b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fddecd797ecfd389742c3a70ab5b7b8c272a53d4fd076bfbbf4f01bcddcb7b7bae4524d47934695eca8bba7f611d6020000000000000000000000000000000007911ee36e8467090160c9289e293e137ac45b1fbcc7b13bec24aa266878d25d84bb9919293dfa33b737ec2ce2fd67811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4580008d4457a50dc2799794ed8d3f652a03babe1ee03cfc61651abb0abb2469dbe67204bfd62b4690033a22758f0a000000000000000000000000000000000d3ec120eb3e7ce30b9c3be9f2b7cd0408ca9c7f672896cc7767f16370614ac26d6127f397f700e0408e52d6447aac931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd2eae0ad1b14f9ee2451ecfa168f049297998db9cad05bd05f6279c06c48ee56b9107033e97e766467907194f6b6180000000000000000000000000000000014a7561c8c41e5fd934e9c051ec362573f1244b984a59577d5932db98b9f1b9d5f4a7531a5a281f53e48eb1dd8332f801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000135febf45e5b1f977f83383aabf0bad6b3243816e91b7785fe79ac43413c48d62aea4514c9b217a5bc52764097d8052200000000000000000000000000000000085a8f381efe12dc72ba08d6f298cbfc74766d09f377272ea6c0aa81fb54f4178faa5ef3aab4f73995053503b633f5001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ba3b23460658870f55e20df729abbfa7410e9a718df11a272ec77afdecb36449096fb301abf4b4c56239dd84c0b6030000000000000000000000000000000016f52d1482520146d408e231d7554db2703ef004125d051b7f9f8c335feeb17cb23a9d8c8276a696599419762b8714411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003414d561a2ade9c0e0eea9dc9dd7b584dec5a5f1c4ff956911343d1c47531dd392be7851aa9aa0dab3558fd47389dd0000000000000000000000000000000000c331f446002cd45a9a1bf96777bbce604b30addba2638f7a2d69e55f2095f2a8af8a8b3d543bf4cefded8b93027a9491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a46e3def610d6b372d7de510f2d1f6296ca365d68b1540debc2a7037e4f235b800fa1293c70207a52d4d23a0fd708d6000000000000000000000000000000000ac48c5f3b863337866027be775e5e00bcaddf9b5b9ef42e5c1a1a9dab896dddc162214924f183de3705767c1e34e06a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081b36aece4cd564342568ff31c468dbe9c48cb7714e643a74693b991c193544a5d8a4f05786cd7d5a585b5d5f24298300000000000000000000000000000000037f26dbfea1097b9b275c8516bed034cfb4c237aeeda641e53505bdd9b04656299e82979f0a77273e69b540b860eed71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000806059c68dcabc5797de1530f0d72c1ad18f7869f5cd8f47e38877db62efbe968a87e0a8d7de77221fc79adae44e828000000000000000000000000000000000dad2a7f9e010bb6c9aad197ac3b79a2202dc07958d98a7507eff6928abb0b5d98481ddd44d71c7272214d79243a50f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8af193b20f9252af2ae9e46431984c142f4d4b59334ff5375e12f051353c360f083b448aab74df008764b8a5f2ca990000000000000000000000000000000013f2f7d29e3e7e5fff6ddf87725428a52931f2d5b0f706ccc16e412f9dd1d18b08865d27c82b3fb77d59e66a5fff9b041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fbfc512811452bfa5134feb157e1daccdc856fbf7f6fc087a4439070a7ae2e461251892ac42e9be088e22024c0ce4d0000000000000000000000000000000010c3bc0deb8ef8b3772fe67ce99ac8f817acf9a7a5a8ceb8cf4d5ec0f897fdd314217151dcb5cba775637ea267d604441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ad443118ff0358ea2e888ea09591120e8092a636740dccf3298603435a01ae8f29f21a3a22bf37dac9be25e7cfeaea0000000000000000000000000000000013b128b4489c2f200a9b027ffb156624d58a8ce933de34452a3443a00e4c59e170f5a52f617c9f5aeb6b27ffaeac00d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016589a97d60871e3af0cc6b78e9af3b9e11fb7eb1304602e2abaaa21255dc46b3848ce5567a73d313442364b422c55d90000000000000000000000000000000008c9bbb1289d6a9f02f9565acf566a33ae8ad2f4f70294fc2bdda55271baf90c5f21044cf129e84c9ea7fbeb21f0977a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000502b99435a32aaede99ad07a686fe1ad87bb4612b19a12857e7fb39523b1311b40ca06b4e5a4fcf6b870dd594301ab500000000000000000000000000000000035ebd546a4b8af6c3f49f85324d1953423a5a5b1bad5ca7cecb20166e9e9914868c2f47dbc10a44f92478bcd02faca01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005318679728f55f687be5b014f7bc1d1ac5fc50cc32db48d2779fe399ffa567e7551b01a9ae04545b9e7f0a55badd3dd0000000000000000000000000000000016b1a2848218aff2365ac45860fb6f6254fcd0b614f716e0bb8b3a9346e295f7fbfcd9b8f714c60c95c75e65323c3f7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000700abfc713714dc05c5a5d8e637e0ce7f8fce3da4e82c0bce0b6f6da4c9fe0e5985121c97e9db882e1fe9b51029a1440000000000000000000000000000000011a62c7d8ae4022fe6470c5a9b6481bc0b11e982bb98ca94c8aed70865200e614a97eaba3fedc55def5ce606b5c556531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b8d2b8d6147cbf8065f5f03412ea35bb57f42da3a83d415799bc2202b2bfd1ba2651288a4179f767251f6ca870bb7c0000000000000000000000000000000008b430f8a0f68b44b8cc4f471cb810769ed8d5212771d21b1deda18b6d0dde2c53d1f6767fed2cd4f9830dd121514fc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043537de26759fe5db48e9409322dac5776a8c15d10c9e6c8a55ebcfd303f44e86c98169555529f41648ead20ce9ae8e0000000000000000000000000000000007907bc4ea9d494289343f874469534cbee027fd4160d04f4a6eae64d0a915a7cfc5135b925575a46b5d13f3e15b26f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3fe8ec6e7a8004624e13b04a8c16ca1e0916f9ac873e6e51850a70dbc5a023daeac1372acecaea83253580d68361a60000000000000000000000000000000010aaf3745e8911ea30b6882857c6c0b35c61b5bb038f672e1a87b3cbbcd855976b1ef6fd464955eb34346ddd1b2bba581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017600f733356bc9706efb991a25cb2bef20066b3788711ce4c6c24e73df777c570b04570afaf8e56d8ab7dc8ed8ff5fd000000000000000000000000000000001609168a8362e4cf811c359dee4516ca53d900c57859eb917f6ac6f649583c87dfaa73613417df47de08ab901ba29d471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e709c467ff813e4c0a9877f6fa3e316d03d802095fd101422bcbaa1d94fb3fead5aa94e41a2fb4ad45345d16e4126d00000000000000000000000000000000022815363aee1a1f7018332745c21f17217c3a0439089386b755d280361e940fb4d12c1707527316d966dd654ccfeec91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112d296b561ece75d4c573988ae2fc84ab93f9ef15a5c2509844d69800bfba5d4008627bc284477db0b498e565c62cf000000000000000000000000000000000129dc7e339599c8881d77e1e08e6f4e0e414568eb1884a0a96da5074d9bf3096035ca5317ba6d307680e7508136ae19c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001566799ca2f853e31b9e6a7cbab7ab588898ecdb8ed6ef1a783e34b3081b97df311c8e650e6f7fcc877890e7e3975b98000000000000000000000000000000000977a96e2f2813bf13e11e34013302211cd744a7fa95c902a444d50c6de222899121e923ac44d916b657fc33643f50551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ab76ce14aeacd3e3c8e4714931e7aa541b66459281224c7d1f0be3b5507e43195b67ca5efecf7999ae23ad57ee8c230000000000000000000000000000000017fb79964ed12152a7d5c19699c376667e326964faeccc9d0f9dfe5c7d2c93922cccf456c4dd9acd715cf78453563f8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c252ae4be7c12b96caee7846036ea5e553414c7dd40a8a15ffb7d891039cf311de0252589958e6817def64ca399d9600000000000000000000000000000000141a68089a4a0cfbaed1c0dc66b8f59eb60f8e9a28576b7974945fc2ceac175a6efc7227a5461094a65417e8aac08d8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eccd14464654c11199a1be24bcc5bf894f171d7ccfa6a9c4e07f0083d259ea6f3afe0809492e8a4487618ec2be516f60000000000000000000000000000000010a1e5fb02f2e59df4228bd6dd45f6f8e5435ec0363bcddae18147d09a62acc6fc93e84b7b004480ce929a8fbda1cd3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011bf53d730774f6655e4af4fc81ea8b4202ef83c2e96042bb4498c978aeba16d8571ebfe705aed4a05593fc38979958f0000000000000000000000000000000013d9148e85a836fa158292055322a131f9919fdd02820b2b3af5472bd8167425d8e2ca5f64fd3ea5eb6d635996a453e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e544c26fe452362a6b409e83255314487166caaf12ecbdeee12d3e711bf744df543e1280b1c80ef4952ee38a9b7f59b0000000000000000000000000000000011e71b3de8768a6dafe30b614f97246217ce612d8fffaa32048b92155b13cf03ac26ae264d241fa16692a7aeb6ac79061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069b6a386fb5d31fb654cc97895955212a470e7680124fa96a085fc69165c59bbf083f1020d339a353e573edbfbdcb1f0000000000000000000000000000000015e2932de1d0af3358001db59e4777a5913f4407b966030918e1d9f6ba5f38944ef90b3fc97d89af40afbaedb65155c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d9f530bba156f08b6885f8c96a3322b4b4e31e53711c17dbba29714e2401fcd2ff0ed994a0244f10ac1d75e704b08d00000000000000000000000000000000069ee19cd9d4825f7e441ceac3e791a8d3500c1678fa60fc025fd436adbbcd607ccb26b6e60c338d2ccb675da93a930d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c376c6d36629a22a4e022762da90499966aee49465d6fff77058af122b6602a362b2ee85827b05b5be00d7d03b75b980000000000000000000000000000000013d339bb2ea01c60e0a782050c7a4f998ef64fc452c1a45b1f1845b922b5e5380510b170af6907d47360d86ad469ab151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025e51c15ca087a6daeac26c08b4bbc4effb0813f8a23dce1959d783406642f176f2aa05b8774d401aff0d4cb87de1190000000000000000000000000000000017d07b1a006e3406d8c748c4f262a27ce440490525506caf8c1c9d09308057f0aecfcbc286ee60b725401b083cd0442b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8f51265fbf77902058d52898dd332800c64e3243bae8a51ef933ece0357a21b565bbd2534fdb497d854bfd4e492c42000000000000000000000000000000000dd4516540e4a95e5eb05a10faddc47884eb7cbb881862c19dcd9936a4936901df881ad6fa029ab31d547b6e9f3dba431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f613e07c299424a59c969ec6f0ac4a914376a82fcb0f8873509347d5267cd2200c68d4838aa7866fa9ce440a412bdc000000000000000000000000000000001045215c25fa66c1d7a7947d81dbb998debbc7a5f2463377ef11c0eadb0e0249c8d1f52ce627b9d1b16675d05f47bb611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012932f29c9a672a080941ae2eeccf8f50f3155f01cd7977ba786f7125840ab9605b771793590735ab41fc1dd10babc65000000000000000000000000000000000e4a67aceb6e0331e6381e2ce6f69a91326302eba69b92c7432e53ba9d6230f99794be8eaa1220b272a3dedbeac0c1911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000867f3f29eb9aa8c1480137b86d1670a112d5d0c6f0d7baa3674a5e93a6fa47ce5eb604ef1eca90aefaf884f52b4c768000000000000000000000000000000000b23b1d055214e42749a51c3a94a75f5689a285d2a9fe981de27c565d4dfd59d8abb7e6c5868dad15c3cce822e1d21591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a556e55102935f073d0a907dfaafe15b59e6137deb822efe0ea5f7456413cdb4237da60808797cbea35acb696bf0a900000000000000000000000000000000129a5a2f446a56a22e162dbfdfa6e4da706ffee8ea937e1f6c8860bc6321bc4058c17d242c6578dd86c99c1456fc08201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e010f12ed38258be199faa4fd4083e88692a4bc14fcdf8b5ca5d330d6d4dd9490835cf8f6345c985eb2fd66f90f6f6a000000000000000000000000000000000d1e63a8bab7fb5feeb7cdc196aacbedab5a860dba9512dea39fe4cb62fc7440bb4e72ea9c2899132be49504f15845421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001452fe7d1b1e70a8ceb89698a18b1546998a28c2790c93bc9aebbbfafa4891f7f4b04ea3eb17f336fe25461022d28b8500000000000000000000000000000000190e2e9d90461337db4729445eebfc4b7888089cc9c09aadee260ddc0003ef34bc43eb2a364c7b0db3a163c750eef0bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de991b461c0908cbebf767e2361ca517477dfb9b0b83d81ab8758b0fe0293d6bdd3fcb2036fab71f4eb17654690101b000000000000000000000000000000000dd5aed5f49abb2892412696cd554ecd022d88aeb2f9c5fd27d39a8da0bf0e92637e7311314b9ed71bb9e7ff4a43cf1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b613ee71629dc2be82d0dee6e732124511cbb47c82f6e9b35fdbc5a00eb7bc5f39cea21dc734b637f13a9d670ffe7720000000000000000000000000000000018fd299c4d7b6d2c836c2b63bf4056642366c5dc5a08f030b890be42e719dad78e335aa750c3f9d78ebe20b35683339b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044cce1474ef9b00c4f74da04023ce9cc40912ffbd045e82d5929fcff527649a59e575e5499f4ce25a0320d1d7d8df6300000000000000000000000000000000131a42eda492ada34f1ba06d23ccc10de7f1977da173390aed188e2bbaac27276ec4e9cffea9c0dcb4f21a0edeb9209a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011646ade271835ed5bd917996e8b6e1a7bec01366dbfd5806e85d143aa7e14cff10ccf6900a5c6ebdd95efc2f85f5d1b000000000000000000000000000000000274d989be7a88746970815e7258c971fe3d084833d85a0b79ea25b111fa595e2e90b87cedb3627576b4f3991bd0235e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112155b07a321d069c05c44e92f62418af8cda4bd2e2c52d8b5edca85119ec3b5e6f691c95a2ab004e9faab5c5f328fb0000000000000000000000000000000011dec9e358e92ab524b0ec19a973fc169390eb8a74e334b17d3e919131978fd3aab3dd32a9acb30b203c15c5684537f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001479513fc9af463b57cc1681f9a7e4f5dc8d6567dcb5d7f4de7d20ace90bba25c2fe3b1a9dff7c4fe0e5887b0f3ed74d00000000000000000000000000000000138c1da0d70dd97948667a555441ff769e3413c3065c9e1e9da64cfbd8b4ea64680554e8aa0523eb253549e1aee400061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001888584708b0090fe51bd6c8eac47c3d9fc348ddc83173d2e41daf1b7b638eb3d953855ea660ef9d73940348e83f98650000000000000000000000000000000006f20a4bebc30066e24a63bab73e3e6e2a2cdb0020e4ee2f0c25aa011c2758d192ee99f36bf4cb8feb3f861fd3c93d5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010fbf64763545eda91fc78330a727c4b9b04899b66361073f828dd246b7bc2bf8a5c91099c99909a0190c46f2a369a9500000000000000000000000000000000070c152ffdfe035a10cec9b5a06081120d3e221fad1755f9e53329480166a8f2a5715643bd234497b77db804a2206ff81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb49275096c8b5944621fb55a5d8acc8aebce7ebd900eb5a9a27b8ca377b3760173fee9bbeb5fa390a5a27edbe7c4970000000000000000000000000000000017b3a5dc4bf166c3a7697d8578a72ca8fbdea4ea1c0d45835232c034326e6ad8e2cb1259a178d3dc6707ecd125bc3c9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002fbc71d1f4c44289d1b9e5afa52f86e1433ca38dc131dfaab90e91681f94f17a4587d5e5d313d2a35a2163d2c7de5a9000000000000000000000000000000000662de989f6966a09c3d52e5af827aae4b15172e605f7047597ff2526f85adb7b45d5db1ab2b4c64d356ecfd33f470001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f52a9444b72217455c7040a3d4dd1e88309a5c29619d1d22b42d451bde46b9acc2223e686cd3a19771b659ca0779f63000000000000000000000000000000001242d773791293ad16261e5c7afd958310d7940cea97626e0c4c6a6ee1e6b7af59e8f6bfc22c19c872c62b7bf43cf7931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157867cc023c51f3e1b611f473d9508e46431d7e1550ad3cd4626ab236d4fd93e55662dd3362d5f308679aa9d532ed07000000000000000000000000000000000782ecce6533867ed47cd1e8575b0d119094bde65c6115e1c7adf152b2d0201675f7550e9fccdc2c42f8f3cbf91602151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015bb8cf0162d1fe46da74a615bfb2942e3b7d290dc0db9fe38e1d2c9ff7c6def3372b7ed0fe02a476d0e1c04634d4b7b00000000000000000000000000000000078b9383b227117c6989679cc481c2f48108bfce795015f3a7e850a062cbb129f709f9f6f5665775886d6963f3b0321f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000742b95f1b93fbc3459744c831574a36afda214360af3d568e177f464d1ea26e05237645c400170dcd3d75e04210bd360000000000000000000000000000000018760e1f758cb4f35d456c03dac0054674bafd3492383668141735b0af82ab0350640d2e1aa5c815fa6cc4b08fd73fb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7be586b2570c8a78be52c121900716ef0e894fbf05935881555b2719b8cbe73def5a0077ccc468f85c44dd6bb28ce4000000000000000000000000000000000851796cd697a3bc972bbe2b91cb0626ab3690783f56149779fb36c86771dded06eeee5740a85046e84e55be9b6fea0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c472b8dc6196676a1cf27f748b58fa4ddaa79bfc0cf5e2a06c28b568e8d2f78b37f41eed14f8a464a49424e1d3684cb00000000000000000000000000000000094a43da82268a2aa369308247535069a490b6dcb7a5245dacbe7bfb19bc186a4e83999f0cfa8047d7f70ddb7bd396dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013fc5c0719fcfd056b25517398cbfe53e0cf96d910e4f6d502c9da027a06463443760aa3e76d266c1cc5be5585a042c200000000000000000000000000000000026bd35f43d1748ad7ae43839b4add2f2c1807d76e17fceedbdda6977f27eb3503bc17f32f4a0a8481d53652ed120ec61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb3eec09543ef3291242c6f9ea672d2bd41073d2bd98904df573d5bdc7d5708c76ddfaaad80cda3fc05195cc84973a20000000000000000000000000000000011a50d7568b8d2286961d2a4646e69301d979dec65305e7a417b7e0af6bbb266fa8c17085adcb6133e0bbbb41e61fb9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a83671e08b524b58e9e17e7aa1d4832fccc174573c78c0bbb7560287ac3bfffb7d7e10c41a1da6445497255d1ab3df20000000000000000000000000000000007368d3db9b1f69ed42e1cb8523e901a9b00390d85de4c5c8a6a5e0d64bd20345a92438c3e682d0ddcd8efd2aaab208c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0c61f9366e067f48fcc0c37367d1f8feedaa9db0a4e1373b9685f9a670fed865e7b2e625361a4d3100abdc850ec28c00000000000000000000000000000000138d4e39cae97af144e36d191886858a8bf134d3bb2d10aca771007bd6c82794d0046cefe9c1b2cf8b31e8a59beabf501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cb9aec0f949359cfbdd93f1d4189ea2d75a953d428e9d0a673e240467c3027ae55e183680e82c01578c9a8f092bd5600000000000000000000000000000000168e0559c6678a2559011abb2dd5961c53d46e11082aee1f546488e3dfd1e6f2b0d799dbf15d2cbb3d8209cbd69325bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002fc1f231cb8aa687140a40f4e7fb4cdf329f871500820896fc7963710850e71c46fc1686c66f519f0d4ae25af128d7700000000000000000000000000000000175e6aae004b92d7053808527776dc39cfcf7e1364cc2e4fc044dd6b85caf20e152aad78bc3704e14c9dca66413683b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141aaa3ee60c14524da64446e3b0cd8e505b39ff7dae1cb5bbaa9a57a89cb05a5617d3a9f8662b71dd5fedd44eaa5b1200000000000000000000000000000000053e6f25f7b4dae561c83b8fa6725db8d9c0afdcc7a4479b538b7400745c1f3bf8e0491bc3d277c42a6d08634917fd491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ba162cec0d042c2db771c91b063e004c425dc5dfc8503edea20e4795d11ad77da1161fe47f5bf159871dfcf1924227000000000000000000000000000000000431b6617ed2961578fad9a957b2e26b95c1f360064bf528486fa56900382c1c50ab2a93f1c8dc1b69218bfc97450ce01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000245c73193acec3b204fedd32afbc3ca36711cc4dcd6647705ef0f57703d57a6d910c7463f96b9622916e8b14482e494000000000000000000000000000000000557826222f8f3a683e5a5961bd27453c25969a4e8a786b4b65eab227ef94978ae5ea049c89c6d7c4739cba2c76310511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083617ac293f5a590d097ae1ac0b0cd0355f0b4edef527a2fe9ec7a66d4901d7659bfa6d0eb5b0959945f12be732317200000000000000000000000000000000013a276555d3f8f69ac1364070c4f841e6a956acf9f7a2d4945ad66d5ee7f2b47d910d09814728b1b62f9a96bb01b3561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a69858f4f67a3b5e9c3d3d251f2085afc32864341a24d47e9febd9cc82915b557f200bfd455a7bf43a3061a1d7fd7b00000000000000000000000000000000062c33a018c4cc935b4b6e949e3a1a68c6f440d34d4935f3e87b6f12cc7c5dda80222ce9b797439e13ef622f380ca8b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbe7ce45555f5c5c739a940282d01e2353ed9d3d7d02af8781f3c35810969878f73c2c8aeecf9712738d3d16a4605330000000000000000000000000000000015e33242acb8458b785f8aa04966adae73d2a16ee1d53d0684c519b3deafdaebe22d8e0968f4b7785f73d6dbebf2f0401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001350e65f13cec9d32835d90eece9fd03719659dc389aa95db54cddea182ae8b00dc3479ec73a8531293e36abda9f98280000000000000000000000000000000019a1bafdab6291172ef4f4362f24ec4738c729ebcedd1230924328a4d2018d9d8f3c2dc097457e4f770ab01ebf4482a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008ae16bdd1a3104aa11e7aa52b439c5d6ed93c5713076aab60e0eec254ab29f45a2232e6b62a7b7babd5d78efda96390000000000000000000000000000000009b0b57ab0c22b1fcaf3c49c731d695d9c7527d05866008c4e882186bf2db26d6320b5ee4934807d55aa95b88eb62cca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1b2c58285f5e42d39c8dd9c23b71551cab9399b664db05c7aa0af350cf3163f4a4a316283b0bf2893f06292f5b6fc100000000000000000000000000000000038cabc5981db9af8051b77ab548dfe1bcf53a330dff9dc2cd4a013a93c40538bf2992ca345442b00e446edc8cf690861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb606a6d2b191ce027889322d8e1b45a20830d3de2b20cd5e87e0eb6724319fe73bc82dd7ee0f49b53d83becdde1e990000000000000000000000000000000014d8c79cb808be6f0f18e44eca9029a129a6428026a03f836f9ad1766ead2883169ab3e3f7df2c3a1752b6debb9d22571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085614354b0bbd692928c69cf061163f5719743b2b701111a430abad8cb1d0a863b02941587a1cc64cd91897809cb5330000000000000000000000000000000006acded6565bb939e9861672e0c6a301628ab6f923afd84453c0de644bb9881abfd0893207bbd605c46b22833d65d6c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a5890fda1bbec36a6b1764ec44edcdd1aaf30b6e01f4a3dd32a22f79e4897568eb3d2a268ebcd8eb64cb01bc4c8778000000000000000000000000000000000e51d93624fa174fa47da1ade3adabd421f575bab5e0a6bd4579636ef4cf13a94090ecba86936392a6ad363c3b3323241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab7f3185c26803b4546a07176ba6c21d10160b0f6272baf9f5582c0bc1f77cb7d9f087f8d740dc56e13002b61da208500000000000000000000000000000000156afc2f4c4b0393a65efd03f27d212b00e92727b7b26b2277285a5655996d2e6654a4dfe647425e33d36065521d674a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063c9e0fa195753f6e639010ca7427fce0012a44b0c45f9c4a10637060f1a7c325a9027648df41dc7684b9c42af6363b000000000000000000000000000000000eed05a90ac8c4bfbc84cb90b406d9e9d9fc7ed718eaef2461184e6eef8470742f2d4dc10ab62631c18486541669fd631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001083ddc482222879ad5389d0407b4306b22d6e09b82700c236d7192eb9fba99c949d1b35612f687ef66e45315579f6e8000000000000000000000000000000000785c3e19aa054895f46ae8c744c8e412d44654283e78103867542618b63844f619711233167fd8820511647be55f9651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008043db79ddf6de0fa4e191d107ac7582f9758d6338d60119e2e8dbb8adf660f8ab33977668b345823b32753707260d50000000000000000000000000000000018c21abfa629e48f968f59b88c7b13fc335211985c8c35b934d99d2f698c9f6970980afe3d459babc76dcce9bc3364c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011b1bcc317f716218b021b46aab74797edb5679b209674147344424a77c79dad95cee5e8764a797d1501c6b13b66269100000000000000000000000000000000028a227f7e264760590f46dd37d047b1bc12208d1460820ff7d7ce5431791b971594f7a24e4fff78cd8ae174c33e62c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2fb40ee2791ee92d899ceff8e709558e08136a4405977125500cd88c8b45c4b61dc7755deaf554e431bc20357b6857000000000000000000000000000000000d886bece81d486278d0002c26d02d15ae6f1a73ad0187d0e21f911b346847331efb93e191d7651584f04547ce1e88ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f210b30119c8066e9004167925f3a449c544f2e7d8aa450415dd305e48bf618c69f5b497193268ba380c314a5c53fa40000000000000000000000000000000002a48b3f05b359e9fd44ef5c684cf322b6b95a12ee4932b75d9c883e025b9abbd08a97ba4fd19ea303e6f7e02c7bdfcf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b568eedffd1659a0ac38733b9cf02a012456ffaf082a69bfa45fcdcffc0dcdcfbfacb402a7c6b03400f143697af088f00000000000000000000000000000000114deab441b58379ad7c1d79ff7c97d30aefd7dc42cf26fe570cfb3fb5418c16c548c3c16cb80cf5ff67addf3edaea7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009246fdc74f70f3c8a7c75b4b225e0f8da8354a7a47550ea00b4dce290cf42e6540149113c987257088e1978c572e3370000000000000000000000000000000016b1d0a7e73d6207cb9912df0644901cc5f0fe309055293ff4e1c70813809da43ec2fba1707e6da6962d54fd322b5f791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a8055dd60d1b5aafbf771fdbed3f900e712b100384c77ebef21ca958ab417d9be1b6234967165659f3ed94bc624b1a0000000000000000000000000000000004c27e403332871075387d6af3bbe05fe19ad8d5f8bf34228b81d1a63d462f999e62525b0ba0c85a668d74cfb90f68a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016059012a0ea85605e9737a5cdbc223ecb54c2a857310532af9dc816673794363a5fbf0abee91917ea82d88bd87156db0000000000000000000000000000000010c11c12793f29e7550cd99e1079ad9b5199c00954c6a68553574251a6b575bc6b00d60dc9db766cf75a195e23a341b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d48a3b67394571effa194788addff8143eeb16d6f1d4db941a4ce2c868761a900e2147d716bed04f93cb9504310f3700000000000000000000000000000000000c1f954c4c367615b6a360b0f512159609d757552ddeedf1b7126f8e519aa7c57ca5ef77997c8c94f05d9f7022709f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084f2111a7abe0ca239c3243614c3cceba66ea4c21125c682202c720359cd45c0528f1763ea7f26d6b0b86966b5baaac0000000000000000000000000000000015e4514112ee251303ce22ac128ed1841445611d23c16374e4045ed81fc697e116c1a01212f66122d82ddb93edadefe81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181011f7bd3f39968b0391c2ec9ea05040c9c0645761f5d6b36bc6a43ae28cc674e5f31fd07d78b2ded4e96dc9cd3084000000000000000000000000000000000bd32807e078c8ab3265a761b425c07bc1d80a52b53f5b1829d2106c047c98ddf08b4e0918cbef96451cf5748666060e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e31e54ec7da342987d51e7ba6ade67c1c6e48d61965d02484715eb8699b80beb4c962b4952dc76b2f48e71a71c8e45e00000000000000000000000000000000089963c41402cc60ac886b6310fd99e6f78b65cedeae54eedbb93ab0460880404d51a78accbb65aa19f5015af65e244f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016495aee4dcb189a41f7aba5a37b81ccbb5f4b639918caf8eebe5cb8c299ff18e0a75bf0d6085e077dfb99d27cc99bef00000000000000000000000000000000136af14e20e6962488603388ca797e4f0bc466bea3be06d852155bff85b7d6371214b54d75e9f5a0a8f915b107a04a361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005978209a9d5dc334830668f1347593c71aa7992148bfcfb83cd0fbfb7a6f5b0e95fe5dd3ed13f3b7e21e3a2dbce228e0000000000000000000000000000000012b5f08007623ff9373b73c0bd83be8eb430d040f7930ccad1519b4a533474b91474129af3961de5bfb6b671619786741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a0595e1d2b0b4acfeae86e6d1ce4bed2dffa93a926af60d13b79c73fe23d800c85d5ace834b7e7b536cd0437b300714000000000000000000000000000000001465b7a1886b584b59be303268bb5ce42c33243a70542ec2d5c4baf7e9b0301a90b4175ba639b3a3618e33c219ffeb191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112388c93106797cad200bd85848dca83930a06b34d3c8cbe14566aad8af176d47dd997b337bf1916bb2cce3eb712b870000000000000000000000000000000006d1cf43c1a256a9a4d84947d1d2e93c0006c30e914ee31095e6667f51cba80c1bb9fe8937b2b240c8c65e24e4f1d3f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012deda7cf221d0fdde2d12ed17e569f8d8d3d1655559edb955eab3f22da0dbe349b3e415fce5b168330cbd00515729bc000000000000000000000000000000000669a46b8e6911bf6173ff4591e64d03432a568760418dac6beea5acbfb9abe10f2fbf3bc2da1ba2bc7e9b700785d39b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dad86a923ef0ef41f177744f72af35a0bde7fa4611c959b18c14dfaad477d7f555a162fac21e011a9a00d43a6dd95af000000000000000000000000000000001086721859b47fc3831b525df6484677d28d9e7d4c59c402db1a48a2c95cba2f6b3b0ab695e354fc01409e64875c28591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000115b429fb38da1d3379c84e8589fbd8136a2d6811537b7911bb72443b803214d3d55dbc4c6af95c386e06a484d9eeb37000000000000000000000000000000000832e5aaa4fb58058ff6590ced9ae289be5a804ae6bf49611cc71a3c698d9a521d343e1d5e8965d8ec6203a0f12795d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb4d9b18925fb558b991e6115c995a6cfb0b948a658c910384344cfd566ba6fb82dcfb10e45ade8ec04211119cd9ecc000000000000000000000000000000000a7f84f1c839f46ca6b1cd9b70a2e9e91311f1e9f3a9587ef5e6c487c59b7777928dd8a6fcf4dc5a9a18adc653e61d541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000106668c6915e31c2eacfe0e558649567b3ba07eae84801ce56ce37d5c19478b372350836d4e402506c67eff7b0e69f3d00000000000000000000000000000000109ddbd91c434c9066f0fb7332f00d5f0a967eea73015913947d2046551cb53b1fa42bcb02e37aa643eaf93f72567a931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e6dc40e081fba05ba39eef81eeb1537ebb98ac5dd23373a81fd0723691bf0c9d9a6343d2899ffa8c1cbc92dae28f90000000000000000000000000000000001956d62844570b7368e2f07023d052728bf063bd9d0215e0f5e51cc927619822211b4c46fd6830dab5ec499c9614e0761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000425ec500c17703d5eeaa85c912a427565b434dc9e8b7252b3d8447ad23e17e8348089d5dfcd5b830e9bffde000c864a0000000000000000000000000000000012a383e361b178ed0cf9f81a26526869769f623728c72d882496f581a7ce61468d894565c3d095340ec88f527ddce7081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5c30a0bbf8bd711d026e4e961f0db2a9cc897d50757d569c2e612513c2ffbdba902f6dfcbb5e243b2aa7f70eb7576e00000000000000000000000000000000024b20d21cd49e76452bc5fcff7fcb987e1b6b9f37bcd11887b9c463888d0bfb3e0d3533165c255a2ef7cbf8ac96f6d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a0a64d1909ada32c43a0cad9387c2dd01ce2d0ce6db5f5588eef1e3443b92d1b0df356d7858ed3183791feb4290dca2000000000000000000000000000000000d63ecd254ef781d6dc59d2b368923b652eed204c50f3dae94cd3106ff4f2e1a21b379e83f16ab02409d89da56d9e4991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f2bce4d90f7ddf9b23e38121243af0cbdf18394453cb0ac472e61c9678a9cc6fa5fd19c37837b029468ab8438f41bd0000000000000000000000000000000007541f9a17b370f212d248dbe3a1fb83b356cad5bfdb890e94cc4c7ae74fdab732c1277e52c09249d29028cb55176b521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a50bd4b0f42352d62fd1014cb215d5a4d64558c883af6e040553ed5da1b5da9de7ec6544756f32733c6af9730ad488d000000000000000000000000000000000cbab31e29efa431ab797f8a85781a3c7672a0072adf499598fa0471a92956bd4f15d1b45f2ae243b11331a9943a2cf11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000174475e4f0b6e5070db8e6ed290f28ecfdcfc304e96e50f455979ad120867b6247244591f90ca6ee68fb22502a82d2b0000000000000000000000000000000008bdde38cdafeecf8020a7274acbff14c4a12ef1a57b7ef19d81dbe8329c4eb099d1b5b954188149498bb58672cfc5ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005a5920aa6776e5fc442c0a85b4ddff1fe449484f19dd6829784946c3838b83b2d6bb0e67e7c438d24d0ff8908f99e90000000000000000000000000000000018125722af1eb632a258b126e4d9b324217c5a05a75633fb9b1c3556c4e37bd5ef6475b24cd855d89fd0fbcfca3f9a7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119324a5384b102195523cd5c68cf07d9c4eddc96bd69d7c1b1e4e31ee8dd633a1a6aa484bc59022c04c381ba54121a000000000000000000000000000000000091a1158c1de661f8fc0b154274dc52b92694ec7abade552e15fe97fe9592c86e4df0f642ceeb6238669b71af91fef841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001592d2e3f6216054ef981df453c6cba26ec695e6246cb6b5d9389a12e4258942f4c0cda3a717d1cc716b1d6259178cee00000000000000000000000000000000009443e8d0b7c79f70f38f7cef14aec8faf512ad77d0cb38f32c9d57afb9732a4bba39b5b2d227291ebf4cde6c14f3301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049111a1d44b7939723e47335d854861ffbf06829763d9961a1811b403c68736463e825b27e0f4f7d65653fbfcddc47f00000000000000000000000000000000039080fa964bc3e7e0aa04b5545c17a1c632a77a5f2c4689eaa6bdb530648234c46dff95fd7cbe3001a066c10a2ae7b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021496f49c7199bc9efc61948701868328e171eaa86f6005f08bf9742b67ecc877cb0d11ee6fc9db1353bbe67cd9874b0000000000000000000000000000000009d68f389c2a8abb3562d0f650ea44953e5482c8b861bd88e88d4751594f4f3ab901008880b58ebbc4b378d26d59b49c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084691c9e595e7cabe1637a271eeadd29087276902cbfe8ac37c5cd4108b963cc21b3d77411869dd53fee7fc6d7d7b8000000000000000000000000000000000043712669686cf41b0fc8b236f0b244a715db835da6e6365893b88efd9318a14b592dae5a8c4af48431269a72b40f81b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183e0279f3cf502cb280a14368420ee1fc8cd975a33c75fb50192f9c2dc063810bb301afcb813acf9f01bd41af4a5e2900000000000000000000000000000000124deb6fd765f33646a0a25132be9ede1a7536f5ebe34f638bdaf9c91aba22889b84f536b0f15b0d2047e991a3d3b5411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069a758ec8e948da7d62ae6e923b3f6c9e3bd8888a0300940bc150ebc7052912e51cdc3ed5f654f2658f128a0d0b0fd000000000000000000000000000000000160851c1b4655b6cde9d75a199c093c092802e7bf9a23b229aa5427f3c9f5301d67913582c69e937902d1f5438c7c52e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034cc953e434ab38c32d23f0b620db17bd0f799cb9088f99e47136093e15275cab448d2763f4d2bccdee31b4a9f64df100000000000000000000000000000000041e855cd9f9ef39588ec4a5a445357a307eaf6aec689e0bead56fd1f931d70de3c10a2fc0daa883a73375185edf35851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011b66a076478283f61e0cdc69b289efc7b32e5e4aee431a66a47648fc67e2e00584dbd6cf244a8db065c0297cdfa4e62000000000000000000000000000000000667475e40667d5c72c2608732741dc0288d7dbd63a3239ccbc58ef863e8a98af450ed9dcd244962b3f5a76051fcfc131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b6e3302a1c2dd6a7290c1f77d1401f2538e58b40587a984ca82c889b2f7c3b8df6d07b00831f17458254728f97b3a80000000000000000000000000000000000bef5d8ba5a820e8ecd1be3329c92acd80384fc41e87c0586b71c9c56541528ccb6d5c123b07e1ff10eaf310c3ea7aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f21be1782978184848f41f0c9289684b3de983546fb84e73ed4cdc860c1c1c1319decdfba3b3da0bcc54474949b95c00000000000000000000000000000000162a2167262e080710ca0369040d1439285cc4cdf1f326f9c4f6193b532d25a110b0fe7a76b14f3f5a9bfc427829e0631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd1a7033b93e0ad07c0fabb079d387b6e85b6120e5b9e704918b6c34f449b53f9b1de9dab11b280e09f98e268bf14a00000000000000000000000000000000003c3b4791555665160e25319b22d4b5b05ba863b27c948b0a86a1eedd359c96263182cf3a50a2be3e7880779d7318a6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b79b794fb2155f6c6c2a9e33f11bcc40c7d6c6534a1bb9d4bd40e332f01a31409a3fa6736de981aa77f719751874bb0000000000000000000000000000000017036201e6ead8bd4529f586c274908b44e4bb78eaba10d9457fc3eec811514558ae39767f274383fb25d9e21e53379e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180554e41066acb4835ddfb8a45a98917b1b7a4e6e8bab41dde955d69cc777cb991cbb989a541b219fed2694702adec900000000000000000000000000000000001f9690d83e1c2ff099baecf55030308eb89f2f88dd9b8a5b4054564ffcf7342397ce7e1bfed983709470c703888daf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004325298ee0128815df082d268421ca419608e9d65a68a7f5d91ab9e5999e5dc78c88387da124612a9d462f7d75c48bb0000000000000000000000000000000002e205ea73fa7a04b845ffe49e0fe2a992b8b37271097e7093bde957df9ca628e8241790fc2f1803fd62a33c317255961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086ee42724934c38b69a8f476a489a6779b386144cd3fa854c088c0a216195029b7c8fd31a597e1fd7c7793ecf8b37ec000000000000000000000000000000001296fe6681158df4a334f84825c006ff5e9552a45630c1a3e9730da3b56d7e7161ea5e4b57283cde8167689f31b5666e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002528ee7945a07a0c149819edd5bc01efa131f8d7dc17859904d69974616ddf16ffed7104711482582861a9a87e42d8500000000000000000000000000000000031edb7c42d73d15e9184275b933f05e303781f0a15f0d0c9f95f56161fd87c638262c28ef692b759b7a45c77ad8fddc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fae5969ee0a1b28a68900ef8427b5de0feb306265812b6a1b9259cda7326b5e0cb2c25061ac7b8094c878fd435664a100000000000000000000000000000000075f63ff43c737f35ebd0c069334325941e97ac9cfe4aeaa58f5d2213dd7d9cc91b4b45da037040365065ba10d642a3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf5407251c0dc89134b48450ac51d0e63191b40191d0c6de6a1698ec0f830f002494b5728142d0f08aefd54c0a11b3f0000000000000000000000000000000019795abbe1a1c93cad03b058ae38bd5ecb62e893a3fca5f63da48d11e3b4bf0e6b39a58555a4fc247eb80cc077f19cd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049bdec2bb1d254dccc60abc5f2de6b2936de9569b45542736446d5021708bb1568166c2bbf08b1d1639d1d9cb2e51bc000000000000000000000000000000000ee5b5196c35e1ee01f81d8e0d4afc91c71527fb966e466a2c67356698671751941d0e8f1fcce4adcbd1c95e41ff6d551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010afc8d67b3a804ddf374f9f458fa14f114817a0ad8fe78ce2feedf7edd6a224b46cd59fbdcbe4e8c2a5309ca287b155000000000000000000000000000000000d535d1e367cb2aca480ea943b189e400d706055f898ff2f69450690ea26808a086b0f7c036f5835c7ac78538f5f80591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015391a8f5f46bad9d3ce0c19c44ea33076a3b3c96d9ec9dc6d4300e21b45cdbf6b81830b3983f31cf54af7b8923b0fba0000000000000000000000000000000002ddc02ff93e2c5a3d2b8db546746ebd9520d1d227878463e8fefe93432c7e90f187568035f0754e3332cbe2d1d324641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7635677ff39b74e3241528a5679d562b81f8a4e45dbabf5f9b5092c0c49e6065d0265a9ef8b112694d3643296cda57000000000000000000000000000000000186987ca787a8a3f71ecab13da2bf4c7159afdfbef16eb5608f55826cb21ad88b7f5b2f1a582322f1068c0cac99f4b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001217cf74aeac2c72189d2ee2173ee8529c0abb2e7c2449cf089fbfb02e39453b5e53f6be6a0bd63e330522e38a95c92700000000000000000000000000000000159296e25ca8690dc30a18c3e82be208d8e88e8c0bb8935d351e28aff92fcf6edbed9011330cf1a41bde71f6ad72ae2e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f78465c45eeb0e514c0389349dfd0f6111ae995deb3fb9984a4dae5898e6f3326cbf5716ce06b1b08072b07d8ea1210000000000000000000000000000000009b588de3c78cb46d9b1b0a2c97d5def861dbcfe9e709b136a54775c2764a6945dd90e5c96cf1547a7638415c0ecc7c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000359b265ada07ef3dad974168226b39e163c3482f69f9935276d17779b665a3ce7aafe7858f4731e2dd5a3369c5d20a5000000000000000000000000000000000cdf30ae1e86f4d5632ab1936ac45689d6bbf4515fa0737e76d265d6366ac14339e232486357254c2b015c46b5fb00001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f25fec0b0e8a6cb2d9d4747bdb2a58ace6645911644c3527d177a88c84ef973e8ee3803a528c264d13531fb7f97ebf1000000000000000000000000000000001095dedfe38bda187c2aada8dd68622e255dade82f6a21a671733df91167c7912512f71bf88037586192706b590ddbeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054044e06122f5febe575b9265e9c7b9ddbdede97e3a2d827365f9c27503bd55c23d4281ae86139ccb916d9f8a4e3bef00000000000000000000000000000000131aab04ef91d6899617bf1a6413f887900c3400b2c87611df691c89d4f664ef5ded56b7533924b0680f1ddc3a9308b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8c541453ab6b04a055874957a5882ef85a81251f9ecbc72a24e6e574f3ae6fd078e29a3b56f9486fba7d5de024159000000000000000000000000000000000004de411aeed7a9d2748d57b2f8b131a9a28341d4fbf425eecdecb60788ca81ab7ecbd4dfb033bee0c74fa0d8a6c31441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000135f8342f7e43505ab170a55e4acb6affd403071dbd495d6baff2c93af46f792cf03a03f7a78341bdb984581b340f8eb0000000000000000000000000000000005dccff2ebbe47c68cdd4012a54f57bb0387da4063f6391a9d51a4aeafca350174c0fe0b4b86d0298e4d174334fd7dc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e04541112e446801783efb6f16c7b72ce80a6a58a5df859236a49f8c76f8e8afa8ec1655d52ee7907380efe139917d000000000000000000000000000000000cbc1f3534a09ea42b2702b370cce29abbce7e0805f62408c33c32e5eb20dea2a81b43bef69d6f39b143fc7313cf9d281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049f846554ae4763cb83e63562f52a8ac5f19e596f09461948b9782f6aa823b07337615eaff0659e19119344476eb66b000000000000000000000000000000001734f653d089cb5f424ce0b2a66664badc32b902947f0c18732fc19ea9a8852d0cce4f5c8716159d8040580508cbbf111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c53ec787c86753590b422355652c94442ea9e6815d0b9fbc322b0a339f47af9420ce66555e7a580602a13783f0e229000000000000000000000000000000000729057b6581168afc5ef9d971e8cb80612de4aa54424c1f3c7a5234a688c836204a368c55fdb2502ca5fc5e43f097971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000070d9c928e437ffd40ba8d0f432d58e51ecb0f9ea52f2331aea8cf3fb9cf2275ffcf1dc3b1340f50bed9b5c200480a6a000000000000000000000000000000000165f3540a1e4f55ccbc0d334acd2560bdeecf645cf52dc4412a381aa67a7edadfea9ebcc534a43ccff98e992c64fd731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9da4712eefb1d86a62c9de1fe982b984bf8c0d72d4e4dac8e0e566fa1d62c44bcccdb6bd6c97948635ba0cb6aac92300000000000000000000000000000000158036151024aa3a11863e7f5b650e9854f7bd0fb05872380e13a7944451d842e10abbf8412b2caa4b20ed8bbebb4f931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006a6dc2f40bd7d050f0acf206620f9b935a82a2257b8586c226ebdef0a81196ef321413810da2d115a9bb5e032f214c0000000000000000000000000000000003e9a178816c3a6c5c4a45d3390e88a42bdc94f864b91648421cc8f5e6fc60748574bd87e35ed9bc517f2dbe3f438d9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002531e21e97ae19660aeae3c0d56cc11876d6d4fe58cacae886b749f6a02b401be21ff1070347cdde8ba76211a275021000000000000000000000000000000000d80af3103c4f3dda17126b2bd5559f0e9f92cfc9cb8264857d3015fbbb15bbc5ab161e8e7151ebd573f7b0013c360511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102e8651e2421735424b9ef320decd63f820f9efe0bb5a14493154da699d66cbee852d9d8a929045173651748d108fa70000000000000000000000000000000019b7d775027bca8fca55ec5b14197d24538f50c1d62117ab0f0ecb48fad5fbcd2cd3d98bb419d12be236fa9d2da6a88c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bdb04916f15c866b2073e028a3eebc223ae984948304635111ac89c4380fa31326c62746a399cacbb1bb39f1b4eb5b00000000000000000000000000000000006eaa328e1cb84bf62de0b6da78852eafe9f8e0fc5374e42d81743bf2a4016b492630d3971e1009e45f4bdcf475992f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf2be054b9170ee2395fee23fec11ec89648faebaabfb7613d33bc541b8de1c3e4c556ba0cf66716d8aeef54c6022c5000000000000000000000000000000000acbc109c68bba2bb82b5af1e7c2939152edc250b8345e74bdad28ebaff9528ddf1f2ad88c7e62cc46301c7ddf6c39261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084c02d81f351c41d595323d466047c1c9238e2ad8fb78f8e8b54bb18fb3413e7993baebaa5a3471837676eceb19b19d000000000000000000000000000000000245b93a58d1e270de67bf339a8cb715887743e5e06d27bd2d83e2944f8d04ad400705bdec0a22517005a77d90aea42f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ffe5fd75a4c015af73d5f649ddadb16c0ac903b4fcb2dcfc89868bad85fa7ed30760e4a693ef8f4c52baccef40946f000000000000000000000000000000000941270a752797ac9aa59d512d4e743283fc7edb46dc7d28a9f2af3e6dd40c048cadb40e0bbb2a912c807de6bd249d601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b946ab2b7b1b3c1f825a11fbda43abd3cb8b84defbbf7dd9d68b7d8524cb090840a8cee5ae60d034482710d7294498000000000000000000000000000000001287d71cf3b16977ebc42dda57fd79595101720ad3f7775c0025896c34c29a1dfe4d9544e632a1581deaa268523d0c811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a041cd121b31ae08d8d185612418b8a624e8cb0d0935bd02d8de025892200958b67f1725bac629729b0c796bc5914c1000000000000000000000000000000000a52e73ee5f3be4ca2f9db6529033960d2859976e829ea5dd1a8750486b4584aeec720b27af8d44f84e543ae6d1836ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032a460af0831927d192f8ff6933af6a8baecf566c0f322544a8643049163aabbd5e1e657902d0ccb4dadacfecce33d400000000000000000000000000000000140457699590387ef9b6af0813f78d7038a7b120f039b90ad99b2892a0a07268bf7ec174a2227aa55d556c9afe4ddf7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001058f88c192393978eae87a87aea76b9ea4a9a52288503ea58cc9e7badaccb83cf3a4cf3030eee78a520cc7317e6286400000000000000000000000000000000091c91ce18eb1dba13770555ab0f151cb2495873315e53d5839976ed3b654d555000a83d7ee21bf2d9186a73958c64cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d17c6c9f78911bc0ac04bab3de11998a55119b475ed721bfe0050c81725c1fab79c8243dd90ab3c0eb1c98d9613f8a00000000000000000000000000000000171992fbb3e78a22045911feb9f959c6efcf790e5d48318514bddf7625556137a9773d79202b4dfc55e705f93cdd5d241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016bddf0f9e4c28242328e58b60ec912501b63a6b66f2dc5e1e1faa199d74de0d8dafe8ebe3b9bfd977efa16eb1ff0156000000000000000000000000000000000567092e9fc807ea56395e0afc4b6b3431dc6471d4bcd00c459bca676425c82294f235cdacaeef74a8f4991bd60b4e8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ea0abfead866753b81a73844ab7529d979c81a4fbd5f76736096692d6a6443e6ee9f26235e9f905246964de9aeed9e0000000000000000000000000000000019cf6ecf027dd75dd4b2aaeb89dcbc39d7bfe40a0504eace832ece56d1f3e79ca8e94d3e5f525b1154940174f1ab85b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086ef725dc03280911dd63f30d8adb0dfa397bff6d679a9fc6f2c3c4e59cd4a3c48133e7fb135c30b9d1d7af4d9033e1000000000000000000000000000000000e732bad8dcfe1a219ce87e3fddccb59568aad421afd4f6904aca4ec3b62711995788955cf789a2278115e73b2f03e271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f49c016d706658e33b5282b4361a38be67c5e066760b50aa07e0bd537817571918a3532c26f1fad7937393199dc122000000000000000000000000000000000eb5afb13b5bf29eb03fc4f32d0004c75bb0c20cf5f545b740c5c99f76877203204fc2797457c84b3a804710f54af5571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071b2f270c3982a3b526d5f5091b84e92fd2858f4f8177b9cf1ef3ad58bab50e611033ef539a909e05bba45d66a8059c00000000000000000000000000000000074a7f983452f9910911265021a04a940dc26b1286e5317ed70065d5ebb5f2a0d0bd210253a0363644a07d6b67646b091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014995c353ce70ca641febf073d06e1f300a1a669effde727c7a1ef99f5e8bc798044b1bef51ee1e611f60de8415a2f4f000000000000000000000000000000000e2b9219382180c2901e0d7f2f61e91989b8a70946e76d4e78ee5d96a6e1f0245744621383f204523118b3f7c3635e2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001370eb00e5eaadc4e69e2ffbbd48616061069de2a3fa762fa306446cf7f3f929485111753740d9fc66025c368d74a5120000000000000000000000000000000007b9700b11979a536c283664599fbb89df9f8bdf73c456e8011b8d3a53a31bc418e4d6e9ce48f098e3266136eced02d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014eec48d4a4f33e04fc1c80c666bc3f9b4ea165ae961e8b284e9fdb512f50f906c51957112ba67bb4e7dd4f4a0c253b70000000000000000000000000000000002742bdaa8196ad6fba002eb0b1ba74e44a0be0fa2a90646c3fd7e3598bbed3282b15339d7577e4a64a374e43c91be451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e315481e74bd37b9c7782f72ec1151f631320c5d20f86648e8f172d4b03a5b230c92c85e00136520dd1f8d2ecf21d7000000000000000000000000000000000896430bf16dc35d94fc66ce99b2b43962d70571f5217834f135d9ed506579f2c4c716d74e9b1a797cde4190beb72a271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d143dafd5258cee86e483dbc6d6cacce2f54493798592c9db6f29aa6b23e631c64398b9800ad1028968fd21702a9ec000000000000000000000000000000001903841ee27fa9eecb3e4b87c27daecc51aa08a2ee8ac5c107324f02c5a7dff66dbc680cff544ee0d6014e80f82a5b1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003118c2e408e1a0a675a7d81a4083922269ea3a526f60719e05e941408e2a63f46798c12156fb44ce727028fad8838810000000000000000000000000000000006382dd4ffdf4fda1a71d7c5dd0825cd7c66fa59fb59044c55dd01714737b2d4eb06635d69d62419c645093386de0eaa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004685ba3662d6789a40fce48931c38b97316364ff0327ca2fd6e64d2a8e1b2d417f7885ddfc3af46f6b2710cb7258c3e000000000000000000000000000000000996942db2f57cdf8a1dad785215508c73691e2b244afdee3c15f4fa8c31aa5a588c131416cac4413ff2fa019d4040841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001177777679c9eeae64cfcff5abb9a4b01f6579e247a04a63ca7e42937cb8c8db102b410fc5cd90ca4467d563c14ae153000000000000000000000000000000000a01858f9d767c3274094131e14fe7c7fdb6a9017ba70087c5fb9ae3af9c4ca9333df617851ab1548076955ff88d34a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc0b03ad66e0c8335291d7fcded349404c6c3b02c986a0516634297847e0b16b9fecd16e640d4d36d6753d505fbc76e000000000000000000000000000000001799ebd179f06038bc8e0d0252180729eeaa3b45ecff68bcd6e4c69f270d23adcb00427d4fa1a8f117aa5d28a09b183b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001873e3c2ff5146704d0b76419f29e242309b0ce31cd4ce9d8182bf26f5ab12729a0678a291e5d6d89626733280f7b39e0000000000000000000000000000000009fec362982a9dcfe8221a71e8378b3d5d810002be7a66107ce0d92238897acfd576e0c1131be29003ef3db01ba326311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088cfa996572b286ddf4105d5aabb4cc0d4b93344efb5092d73a841d40f54f8bd973a1e7bfb9dd73c094942bfc8ef311000000000000000000000000000000000fb3b59d239a22aea27b483bbbf81f1a6cbbc6e5462d02ce8d3a76f7cb4ff94810a0327bcf5e74efa027dd28b12f09f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5bd22977c15f92d4f4ae9a295cd76d32ec379fa4279f409e0eb9c4ee81e7204beacf51493e226bd01831cf496944f500000000000000000000000000000000161357b9a8c8032342d068418a63526b7ee6e465780bf1a4408f21c606d84a0ebbe87e95207ec6c0ed2b3659e38eef3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000038c949cb93a367c7a61e24fc45a0dbf249bc05c210f9ef4a222e09c22d22fa6e305f536f80215556fd786e19642a11700000000000000000000000000000000170af6f62e8d037bed6dbf037cee71d2d3b3e7ba228eabd1910835ff4d391f414733b631dfac9a59dd0c01e6704f740f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bc41c1c663b4487aa4989e8f9eb8038bba4d113f8857e15829b075f7d8b4e63c51a332684ed709865e56329fd02042000000000000000000000000000000000de477cc7e66fd6a285e199c8f384a7c48af70c3c0c971c8585d3dcdea2ad0b91be2d3c824c52c3ea1ab1b9f31aec4851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017cc8891c58282e5c4ed86652910efe4dea4e66520cbc764ed0c861c54773219ab5bd449d00fb89445edd6ef3bb0667f000000000000000000000000000000000208a18c217938d0f23325f90f4526b7f722172608776c6fb48983925b24f46e9a42cc41b9f06d828cfd5b6e35fdcb711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a1e79a8d63ab9a6b5116dedeba893e38e0f39cf6b5757302e6cba49b28cd18ff4371f5245226bbc0dfdfa430a32d4400000000000000000000000000000000179ada57f867261b55ca30898f5a72f24673e0939f201a61063417fc7cfbc7cc22a968fc94f9d1c7c566194d156167251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015e5736b55b840eb92fc3a39ebf0b9918716559d530ade497dd41271b2af51ef5d35798cfdd75607e3375d4fcfd050f0000000000000000000000000000000002164a8f6108acdcc7eed4a7abb2edee188f07a84c24fcc4847e7c2c840c8a9e22476f3b5e5a0f6ab2c020d13637342b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000880a5e849097d7f158ba1efdce01b4593be8ce8d9e26987ae07cff455183e41782349364e56333f3bf863d79bafb133000000000000000000000000000000000581ff810ce40be640f78cdabdf7fd1c03705cac3ca9c67a308f8b8e14618e264b7264007d230b37e331d8717e88fb441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006723e727341a055328117635105d920bc562628254cf3cd15dbeb612af63d9436a1118b115baa75160a56eb97f9672d0000000000000000000000000000000006d063bab2c8a95f34fb715fba6dec4f474bed6d5627e99727bb75015fec671879c4ad71a33b85f7b3deab769b421b041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f87517701aaa211263c35fa0719d0442bb5d610ec0764e79f7070dec93eb8ef418f6ec0ec9001a20e121fa6ad0e6242000000000000000000000000000000001334270ccedfac10af4af0ea27c237575c65f6b6dd9be35e8534a719dc9d7b584164428fb72e98173558b89517727b161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120df0d7df5b62bdab0c60e598e1d440596b97691a7135699ce582209f7a75424d0cc190276b1b8ca224b0b45553bf1900000000000000000000000000000000120d2a4abe9965d7ed3e20dec60f66f951e3da8574ad3587a840c314532cc943f9f62824251022de29fdc334c80f99401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082aba2d7cfb40caeed35310aae8edad4d46493fc490de9f3c87e178c21adb8c714623e7146fc2e5ce6d47423f74f7e7000000000000000000000000000000000578a554e8d9d46e3a925e53a65d07927786aa294bb1b64b41bdd2920b4df7dd14f5b2f3f710f4784ed97deeb72943c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082d21ef9dd2a6e1fb81fd344fa462cb2981abf70c30b31e20eb696c8033dcfc71a555589bcc56c6981bb74735d125cd000000000000000000000000000000001718c95050b1d07063a02ba2cd5851f78c57129485b697b5fdb14e06a1bf640be7d211d98d3046b7754508572e5cd4f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d4564f74a6e48c117b198f1cf6a67265f31cc359b175f1d48a597f06f9ac159e7591e42fcfa0a266d6c0963f46aa80000000000000000000000000000000001728c0b2da069859705e604aa6bf6fe4a0f322c14a01f968a9f1e6d4672200dfa5b3b4024980e2fb0f6134e342e3cefc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000561122d0fc951ce6c6b7737cd6376270e81acdb6370f07fc24555ed4e874b25e00ca6069b591e258981fff31d44e0af0000000000000000000000000000000016ad27b20aa2bff204f5aacf0e990b2c2486c90ffc656cf5c1d2b1ce16c1c341f4eba2c60acdc13275dd90cb7fe41eb91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148b2d0d0384bcb9a26a373b35b0cc9882df1e6dff6256ce28a74c9a6069303d9badde5230ba77ba8aa3442f51c6acb300000000000000000000000000000000126c90c154470bbca9959fd52caf04d1834a172ed11843d60f624d9f36ae1bb1100b352ea314dc9a6d643b1a1924831f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000589b21b1d79a615a8ed74f2a8e27fa416b9eea6898476cfc08241adbaf2b1c92b9625d6762d6b1b752e09f1220ac9700000000000000000000000000000000090542d2a9feeb380153966f7e3ba0af9646b83317e6236b4e5cebd594b913b4ff957a31803714b948d75b49f977a4c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002882d437268b6eba31d1ed1d5763f608c9c4b5f1cbaab50efb2369a30e7457435d34e086d02f1f6d4cc2e6ce8aef9ba0000000000000000000000000000000002ad711d14d30e883805f2ccac970ea5438b2d44f3e66a041077a48b7c92d487fdd84a4c400938b19958983e9b8dabd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147e2d7594ec31dd4b1afb58bcd88412c4f9d88639b043eb4556a23ab0948f9536169aa0006dbe73c5dac859288ad70f00000000000000000000000000000000023f5a4d7deaeb143c3486b5053b2147395711e17b9f0da379d508c18cca854e7cea70cacc191c52e04b89c3dd19ea3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a49216c008d61f896bc647eaca4e497f2fbc6203510f427f2a5052fb9fc84c0241ccd70ab9cc744fe84c022d2729ff000000000000000000000000000000000a0732103c03bb4aac33e6a0cfc64a5d15f88d71ed241b309a31c3ea31f46c09ad32dd6f647ac2f3fcbab218ff505a1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d78b39479f0a484c46596d2389269dfe92fca945555b6325709b0c9fb84055b5a7ff20eb700a302db4bea383cbcfd510000000000000000000000000000000007f1cb60cccfd1d99717345b9f77df541a5cbebed2a8cb2f2ceb77c830f759a81440e442f15df32b0423a7cec0d10e071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac5dcfecf9fb8ebb2f7dc020dabebbff6a23a7169abeaa6c56b2d6864bee3c670e5969792dd9a21cc2ff0cfe25c5e76000000000000000000000000000000000e3fa81d3234eea9a4de9963347b914df9a92ed370e9324640c65f1a793fe2117160fd4c227feebf29bde9be8c6bb1ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001811cda8eba404c5e924002eaa5f2c00bbf209ea2dffc771ca27bb1b7e197b40886ca03b973494a04e544c7b93d81282000000000000000000000000000000000202f96e7c1ed89fe436f7e625701f36b4cabc3fa4f558294c6ef88388675609f15bf01af16477ea178840db8e0693c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004d5f91496afdae36cb2f871542cad498f2a3b77cf6e6e1e120477939c3b2d4e0297a57479560b540f1ca3ab665bb49000000000000000000000000000000000263913192be2d0f0e1e5b2390fddbe6847c450a532ddf422771c5a55823f05381d12faf0d33ad52805b78cd462ad65d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131876acd7243937be8a38b724b2c6687fd8c5ae13e1d11f61428e179fab211bc18332598499237ed72a0ad885e6791500000000000000000000000000000000128a011c0caa0673370303b4f7019454bdbaf54bbe3c97c00b32da15570dd32c71551c6e5c9ec6a503b5d652470c9bd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3789124cb7f90bb08edb2fd29ae626358030b8a9c85872bc7bde39166166208cec7ba6ce1f70c5273b13e25fc0896300000000000000000000000000000000159deabe97d1f101d9cf236b2d33b93e13862e11b0097004151be838bc160d08c42fbf71a0508567fcca96ce530d14a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002fd078c644724688ccfa8f2af24bf30d0c87faa0d80e2fba66a7024b2f3a2d958b526f850c31c1651f44dd4c6373a5000000000000000000000000000000001760b1b0c08eb4c9a04d3881dc1c2d3d3e1ca23018f093a6e64a686d6eee8174960ff71b9d60b8935e2956c4066610691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003cd7bbc9c22a7227a9df1e5fd5d8e61a6e90e73f122dd9d7f20628fc6cd675e901b5efaf0621f08096e6b607eca136000000000000000000000000000000000166a2b8fb79d78c5e60235595ebfbd0cebfa9d0438bd0afe81f768ffb0707981c75afed8665e53753daf20e5e6edab6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef4cee4f157c391e2dcf43462b474db45fc584160daa74d0bcf26676d6546e75eeff90583cc506bfe8c7aa4dc673b83000000000000000000000000000000000b00428dddebe423784f17c9d1d7d29ae5defa8bb122b72520826ab612002d30abb81d2b48e6278a64a26094f241b84c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009af6b78417a421f291db660dc53397aafa63f1cee05d4d4c5d29e1c5c534671a07c48f551667e3977ab8aceae57798b0000000000000000000000000000000011c7805c7d26c34339d95408eea866924f72bc8874a5fd7e3b63c235dc5bbbf16712b6c62551b3d682cad6b980f6c4941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca7d96635870b64315914df2caf5a6257bc120fb5aa662c9992e669ccd6b2ec1ec9532fe2b9286049b2c55dcb68369e000000000000000000000000000000000e7b6144bb6d8c2be680e7a055d13d2fed10488c79a970366079e233d4671606b5f3b7f913c4a7298816ad4e987df8441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112e0ffa0db03ab916b5fd93c2689b64adc611d8c271683646af54f21486d9ec0974f669660ba3cde94b297b534a006f000000000000000000000000000000000eea32952ec0d435e56320aa3f6e90ab19db7ecaf5f77c57a780ffcbdd4ed208b3ae1f948dcf3172dbc94f7781f1d4691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001800907f96f8171fe646661e77bee6673c002d06a67a0d3360266330e638c4b3a174b26427216bb420250505d2f9d645000000000000000000000000000000000f45d5cd984bd2c1eab642b148253978ccd99d7231717d98fd43171b31cf34af87cfdc1f2dbe7ce3395a460dcc376a121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003957c25906e16e27d8b76b009057987dacf368189ca07ccc81ab06fce6e0254ca5e2d022d50ee6a4a7595cb0fa925ef0000000000000000000000000000000006410a835cd298689924f4dbe73f1dab40b736cf5e6f9ceafd3a5c0b517ca9fe2f5cff603f87c41956708c2279ce8ea01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000033279a421998acc68ec591f0cf320bfffe62bf76b352c47d1c20b3e267ee515a5f59a379c816cf721c8dcd79933598000000000000000000000000000000000b01308d18ee0c2f1baac4e52b5863ad48cf9c6142767f320c3e9fac2fb15b57db701f37266ed75634cfba435f6f58051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001214e9e7d8fcf312660575e6aa43232cb24a6af853161faab29a3f5e72203b7f182799ea674bc5df7ae712ca5bdf8c2f00000000000000000000000000000000144e08551eb29c162405e4c07f86fad025ff813241d1422c73cdffae893e6099b63e178fc830b22a0c18b2f98e89daff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014cab54feb6fbc79d0c0ecd8225e25fe27f9c9dd6721b69b8d383593edef543d53a72e291e13f462886090028b424400000000000000000000000000000000018ed520e6091745758e9cc7045c3a1f991a9266880cdfb46ace386ed53762fc5a7f9797372f3aa89f09d56c9ceffc3b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bce6286ba886cdd66264ad4e0e327a2f4376f298147e0688744c0272054cd6b886285aa01c3224ad28120a7aa11d5630000000000000000000000000000000015a2e71bb67f4c40b5cc884f3fdeff809932ca5a4629b9f0e9edca5cd48d94e549de301787fbb0aafc6bc8bcd77503981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013dcc166d171ed0d63149979b9545ef116049a303ca58e3971a5f0e9e87faff7cf55577ed03d62c57463293c46e40e600000000000000000000000000000000003926bf56f61188c4c0f509208982c2aee21fd2d77d320588467c3e78cbcc4aaaf7447e81b9e082f00920d26ade8c5021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013382c7bb1da9826fc1736c94a0a1e9c83c72f44f52a19dbbf82afed5552790cc51da26852647220091e3e523bc23659000000000000000000000000000000001754ea271fe9575e10a6f8793bb9ed7bf1d07bda2212806027953f12521fa3efbcd4ebacd10883a4dd4f5857d0741ee21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004854461441ccf044849c5a44ac53e239a13b2f790c7fec01044389013d869caf3a07f82909acb820c537c17917e977000000000000000000000000000000000196dec16024c33263854d8d96f413eba9bf073e1fbb674c6a11fe606d3dc444d734c1b85f3f93822a56ef8f38e8912a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079efa6ed020a10040d30cc8117d2ad4337db64ab16c9a219c0a31d718d11f2fc2ab9c09ce4d06b86a6bf96b0672268c000000000000000000000000000000001723eb2309e3d0e2c3129e181823558052802c2a64744824a2d2bff8304a20d81768b4d4d1515ee9e96bdfa7a93fed7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d1a451ffd71d205158e95fa4b25ecd48bb4923407c2482263bc38c5416143dbe7907d3deb9f5754e328eda0f2094cd00000000000000000000000000000000131f194744b656be23e16a9062bec09f7fd29a3884b8218729f410e9dfc72c55f087c200a373da6506b94f6cc9b056291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d13b67f68b0c0d5fb58c3efa9a71aeb822d76572ef05d1c36bdb79ea75b72c9fa7f1200bde843e77289c73cca74a9a800000000000000000000000000000000146b553ffdabdbffea4030dd58f3183a513707dcfcc6e1e164f72b7b125bc0e7837634f17847a988c7a6a4da25f0e6951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113a7948a2614e31d28e67b24a501bf873920b1a1edf286abec72e46c10193063d38823518c9c7df596e52dddbd77a1b0000000000000000000000000000000013ea4a5e1dee5164d02ec7df351ce5eb7ca2746b930731046a2a564ac3e7aea6f99030913c57b98a5150c63950bef2a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f5732ffaed418965c0c0d0e9fac1151e2d02dd1d13c4d185d98f635fe015adb526c838dc64fa957b61a1ab79c690860000000000000000000000000000000018325a5f90eb15a41ba01ade4d0faa4c65051faff9981fdd33f34d86dca3b6b7572b0d73149a2324d4c9145ad99e36d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce8841319701f8d17e78e938b3f2d7f4278f0db83899e148c2ef8a6e3a24dc1eff506e01bf1c0d887f4d78d56b90dfd000000000000000000000000000000000ae2c6953e07fc2798fb87c95069475cb29c890d9c9165b1dab2ea33dbecfde998e102508fe0196c634ef6621a522e991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012370fc0e4d806565992fefaccd09a3768ddfb3582b5a80a2e7920ba454d5e12f2db370616dac1251ed9a32457db49c300000000000000000000000000000000156c43d5ffde382f4e393f454511b2ebd69bf52fa84330cbc1bd071896b70a176a2a5e2ccaeaea5dc923b19412bf5bf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018703189b335cf82068e80eaa87b5d4f8f85e41970c8bfa6507c37e76ee83d5b5cf83c4557c952db64d5d4de303dfc8b00000000000000000000000000000000144039970ca20ecd8a8c2c9dca526964298876aa7f8b8a5517a34676b1475219342845c0f37c8e46b71b0d473ea49b4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185e7b7d3141133dc54886f718bc1d43026ec173e097c604f533c4f3bacda82512e0b8063fd8541ddb47712686afe5e7000000000000000000000000000000000707c76673ae26ff815bb5ed134e3d54ec622c2e68927bb4e918bb7ed58f4d1160c056165e0405c127eb3b99cb12e90f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7fda0868af825a41ac3635adb3f214402facd152ed275eada88ff725675e8156bab0f04fedac2cfbabe3cb4e635c0e000000000000000000000000000000001574d99e64867be5491e8e2401129892f109a00538b4f3a1a4c2f2b3548650f2ed3c62ef3ebd668c4a7e246f1f32d5ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c090361f99c42e7897deff86e54e64f0b0a279921c85ffe1f981655bffdcaed02f85a9499233e7aaae9f1d73e577cf0000000000000000000000000000000011d27d728df62489cc7c777211464fa3e350fa53ebd210d207f960e8ec484e78176f1593121e9d916ca69fff1ac3de0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e9b6f58842b955e2fc19430d73c63bf6abd1064aec9f32ae3adc6965849ba978f1841b66d06dc510a67f2bab60979c00000000000000000000000000000000150f7b5bf27d5eee259bdcc6466527a17a6621aef0afd11641a603a5452832aff96df0a93178f63209e945f0da0bff5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbd1844f2c54d18f0c71e4fe778498bbbd3e3a2621725bba4f2b0573baa193ebae0e58220737800f75efb37fb9d5cb90000000000000000000000000000000005b749debea5ff14f25a7d0be3ceecbd396b5fda0daacb51ed76e608e3d84aa2318766d1d83333165ea07349674a4b761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001349f5583de75f293ca8d6d4e8406c385aed8e52422085e81c56fa6b8c896fd336054c3a45810de1eccf48042d5df38a00000000000000000000000000000000035707fb49278a7f11636b95ab94bc97d8c7819e3eef9f55c83a917e7919713d19ebaf627ea063f2177185e9eb3c29191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc8f1d61a7c9565ce72ab07d947c5744859497a7627adc67e85068c8e15068a47fa98f2a357e3f65ee48aab5cc751af0000000000000000000000000000000000b317ba185ec85f9c6388377b8ad5ab85fa73e66a6356347819986ce79e123f601950396ea955075a21a1c6dedcd2231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca8f4f9e9a8c4ae473fc1e521e39a189a77f416ecd445fcd78e5e5931e342d5e647a9af56e4ebb79585c9ebcfa88a9a00000000000000000000000000000000102b8256ffb7ed4a303692d718544ff6c1f528777d9e08f8039daccfe242fd89017ba15d39ecde64f08b7385eb1893a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f88f2f88501df778fc128d5ce8e11bb254ea472d8328425d4db7a316042d16bde7c393372bd3da0894558ad53a97e20000000000000000000000000000000017fa2f1508acf84cb1b6ed166be8c8dcd003d14a4f7dc65c788790d894f618221e1552a9f67652abf706d9619e75c8dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014150b65046182d52123fa00d2afc8cb303b687f90679287edc51b6dc3ec59aab8421c4784be781fcb19c0cd6a3cd06f00000000000000000000000000000000149a4f80e93042bac22db69da5cdc576dee22d4d21a32ffc1dddbbf2dfaa9548ee07e4776e8c12df01118ca0505e40dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f5020ef5b4e7bc1c21aae13537450ca867debaa04f6a3a66f2ce605ac00637d30a1c6ec8ca802a1c5f9e2f3bbeb9ec0000000000000000000000000000000013c02190d579a8f34f5489914ca2687a89a15f5bfb17dd231a836c4fee68fe0158e27c6af8c367a004d9d1de04eb64401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7384a45dd3a55e34e6c01ba4cb951b32bcd5684693fd4217760e56cc94806e7caad422e1f4e5928d2c2a7100557bd8000000000000000000000000000000000a57a6931c5e57ec60e3bb5272c00648cb893ef022f26e33f6a6c455cc6f0eff77d1adaea7e87625f89801b72e4f8e881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051f940a9939aa16aa9b3f24b25324c60fb70e19d5fd2932c1f93b435ebd5bd10ebdc6bd429deba38fae6de67def4cd60000000000000000000000000000000012420d8942509abe6b7447668611dbb6f743689d670af1e27b01b97084e5b58620815994a2c4febdc5fd285951f8876c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032d8e6e03ec9fa4faa7a9d39d6963f765043f48e19b0195271d68bc2ebde5011752819063e22fd81706213e0a40e79b000000000000000000000000000000000d782584a12f0e1e1a1e2f1e640c019534eb5bfda891e1a8405f560c09bc52fa694959ae835f5d22c2c74f82120c96a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a8741637546cd3617ec18dbb5b4ccf74ba2865c7c1003c0f937c733a328f1854240d104a8110de9dae6429b1334999000000000000000000000000000000000c32107eeaf9f01dde2e9a7203cfce709fb5b4847de0945a8b186cb1ac2df2560dc4ee2089235c42985238594cdce0f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108ff1cbf8d8a1ecf8250e424c4d916fe777cfd4b6f4458fe1b33cd43b4e5b8877d9e09f478fb3357583f41cf94ecc960000000000000000000000000000000016618239ccbcfaa25b5337264584988ed29694887924190f89f970d9c788486b80a1ea6fa2b51a47bcda04cb61bc307a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000162179f41e2e2f5d85b2adf4e90a3e989ac7b37f74d531425e9759d713c33d08d3d677bcec603ca2fd51eb4d6e13e983000000000000000000000000000000000610eef42bdb08bf3c7adb8948d95b79a233905a9b71b70ee1fb22f7bcd482a57ac7634c03019bb5ae91b7fc2fe478fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aaccf87def18741c63fe5fe3425bd82595a29250954250fd6f52f0d75fcdb71bdfccbb2c40f83565c3572797b34c94d0000000000000000000000000000000005c01cc46574ce46cf9185270c3075744e96dcb488e003c54d647a35892887290e0a49fd8edb22da1421292175d400911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c68210933af738d9df821d1389881fa98126dda29cc197dbdad01fa0e22082121c28be59af8b1bdf52bc19b9b0379a20000000000000000000000000000000001e8d6cad636caaa1785845fbc39308c694ab18734b10bcc6b32552295c22a19af9cf05d9839bedced3245ffbb5584cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001121677b3768176245c16043840848cf42214e108a96b205cffb8ed059268081fa404258be5377d24f629475957f444a0000000000000000000000000000000008f430d611e2dc59a6e78a3268d66aff3eb6ab9dc29dfdba504d054fa673766f13eef94ccf28ff9e0d0d78273d73725d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f0165c08a2545b846c1d05cdefab7080b2a59ac77af97cb304e9f08794642e3ab2a537c23232c9fb6f8c560e6d14010000000000000000000000000000000011f548377765cbe98cd988376d903abe3b8d3e9953166a300cb693347aeec58e7477e124ac5b91438d9fcafca782ec691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e3ec989da2f5f4b63c1113dab5c119b4fcc6c95e81d8ebe61be5b713c0ca462b8ff7abe337c8fb4efdfbbde5dea636000000000000000000000000000000000ec7cc566bd4f29eb81167017ea2d14ee4ede46e9c539dc2609da74af8bb09345ff08bf1a6211fab13da1d8f145db9911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032a5387530e2da598d720f1924d621aa0da94343e05ed346acbde08958cc48d49ad486aa958dd6a337c6678f74063ce000000000000000000000000000000001880aea194f91fe32320503b92761c60e26c0242d2e0521d4feb4b96d7804f0fcfc3be4afab9a47636f047eaf86bc99e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ffcacda9b183a5077263f3a2efe37e11d7df0ea33e21518a5c1ed2c7f5c4a92d534be4555ec754671370dbee6a49f90000000000000000000000000000000000f6ff3c60ff9072742a960a6adfe5b390e2030ec3af9826f08d30895ae1f4fcda1181dc8d5c5c153ce43d5c965049d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001214d9ce5f324800c46d9de61c772dc6e2fb189c7afa63d873ed5a2a1e44f608a755a8de016b79c247bcccb37eec159d0000000000000000000000000000000013dd1b0928817e86f30b70fe605f5aea470e56be803b9ebb04069ea33283d8c194931e0e2e8d47018c4331ea44a7daf01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001392e022dd8caa6eba04204615cad587275789062caed525bfe11abfb5e456d005dc57ff98591fb2589f4a525e8cdb7400000000000000000000000000000000004d2f40b1ac186e513bac855871e6102aa9564eb8fa575114965adeb25e8584186b7ea54ddb0e73469b0a25091a6f3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011530988dee38c46a3d2b388580199005311b9241927292ec7a3d9132b5acf3a9f6424cb4660376ef9dc19579050093800000000000000000000000000000000131a40c103e66eed902bb20ef82e51a1ca8c2c946e55d73db4f9f87724105215be5d4b00b12be5d3989f5a73614d91e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010fdbc914b5ebd7d11540f76e11855f009743c34c6725f33776070d26c6b7fd251dfc5f94cac3688afdae452958eeb2c000000000000000000000000000000000e6d8f32dd8d9bb6aa4165a76fc96ab598b2b65a6e12db9e435ce12427c03f030310d80f8f337199f679da1646d59cea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018018549f6fa8942e0a22db820fc4bd4b3822b8f1b4c5a039e7508392c9ef5c802fd70c31c91e95ea6b5fe4c7271fee7000000000000000000000000000000000c4c6d4b3fed72c5d54b511da7a15740647e28a6d0908b2e3c01d55fcbe65bfc8a67019ac2fcfd4a170cb78f173ef6e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001832d06481573ab4d103113d49789125fe70d0f14adef4ed9b006ccc86ae717926bb9beeb44652b3e271fd99a75ce0e0000000000000000000000000000000012c7ca9bac925f4cbe91552261862340c1cd659e83045d83ce9489389bc920c0e3b03636789d10504722f736121691ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073de5b9cd4d2358c418a103d4fd4653b4ac32a43d434f723483621a159cb49255d7a0883d379a8a08fc8c9b0cc59cc80000000000000000000000000000000006ffaf33a960c1a466f8917da82cbe8f310961dec008d0d7fbaf3d76dc740339ee91bfd2e41d4177328fb11c19875d101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d82a0e8dc2d82dc8856f18a79841394f70d8882c09bff7248a1696d8801056376c9a8c6980e26f644e539c24fcf5880000000000000000000000000000000012a69ef008501aa90075d3a1d3cbb0af712784653667361325aaaf32006231d8dfa5b6125d4c840dd21192ade0c23d1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ff3fd877c2f7f8a14d78e5af42e1754f16c3bd53ac0254523761f433eafba64d3f158d2b7ed136c7f87e921e3962f0000000000000000000000000000000000d08d67da1798dd43d151cef813edb655d93803f1d6f28c60c79cc44226e839cc58f602e744c8e5e8881a4d725486bb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027be6f56273c38351ef2a857b864469b2743b5069832ce84efbda7b913624c9bc6e0962095256d262adbc4987f78ea200000000000000000000000000000000137bb171f08ad3e82a524e51290c6b9d5c71905a0d3b485802b69cdafedb57c753cc6275500e910bfb41fb557f4ad7ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001989f098c2bb8c8208e01dce2b5f7c237b191d11bb620eed3e8bbc77bd104a3444193c4b84b65fa0fd78bba437fc0bc8000000000000000000000000000000000a8792f2ab78460772f49c62bb036f92734f9fd61567074c671a2133a63bb18486075d4b10b08c8eb0c11f6f286278621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cb972663f97cf6682e7f258d5e2d540e313cb21371e9e656b318c45bcbc09ae402c8307d919c84f2bb61701185b57f000000000000000000000000000000000a56c242e6da1df7bf518abc777ed36a409fda31228ab519e6c63a2cd3b5fb2c1211461c11d4c6c14bf6fd70f255b3e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a3c26d38180f3cf375d3ab62cb2c1f00a9b20708f1f689c91f577459242c1541e47f775654b5e6a69c75c256661c852000000000000000000000000000000000e4372d7d92c21fab13a91b05ffb0ec33033c27a4e8e0d64794894926580ea12b530a665e6b0a4b12fabfe4be621bbdd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053fc35a33fd7dcea7cb2f5aa94a7338bb69526c75a6712b8cd91ff1012bb67c76e37b7fc391407ef8ce4da0137e1a4200000000000000000000000000000000051c06f3e010f06a2a7768eac1513005e4267623a5a3bdc9a8b6f8e0b9f39f1704ccc0045c358d7fd34656528dacc3e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f6e1f16a704b6aed9fd586a1a8863944e2b0e62ab18fd7637fcc5912e8f900fe140ad93464581663c5fa1510279f1e000000000000000000000000000000001793cccd33cec78a53af5a13b1628653e7c20b4aff2e3cbcdbb365fdc1eadb8e9215bdce9df7d766932ad32063fef0ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014432fa74b331cce53a246f844e6b13d96b84c5672a4ba91b0b89ac111ee5102c0d01fc8ac9083d2403f0d5ea41c72b30000000000000000000000000000000014e884dfc2d84cb632025a207f81663c5421b44333a32b079dba2c8647866e0487d06c0322d36e8f5a45e3ebaca990b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061595fc1c47a286e16c344660a62cde66f1b9cab357f26b77de3496553f8eada7126f5d68884e8ae477375656a9b05100000000000000000000000000000000092a23335ffb2f1c5e8cb5eb7f6b63ea31a9505eaf63bfa58a4fc77e0bfdffc58788e851b619bc1c144673e898240da71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ddb7188b3328592794c83f07c959aeb01aa660070d5b9b8248a0ffbf0cf7ee807d8ff9d98572a907422e1bbae4ff2c000000000000000000000000000000000524685a67b7b7ea6f8893e22f16852992af1624bb72a67b040fc4f25feaed92e837810230dc9b82dec732859cebffaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c6904ed6cd3ee7c4a26fc34b6cc4ad787c7ab3663de2f47bd002eb856d9857e2e940d3e79245b00b1728e358679c1c000000000000000000000000000000000b38589479505256b3718f96093b17e2351ce50930636cfe072513bf8cc6ff7f59fac2468d8cedc5351b5fb38ea4d36c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a5baba050ef38a53246de5465b832e2eda40e94cb1165621b3abf6f7986e9582533c54032010494f7bcdef0ff526fa0000000000000000000000000000000005e9458bddda75bef48f92dc146b2b7fff98b8cf89de62720a88527d01fe0ae1e7ca946defe6fee234bbfab522a777c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000872b7d182070e115309e8935ffd8eca8f4307170515780089d1a0254ce905c3eb062f9c1e5d81ed7c10aa31b639aef5000000000000000000000000000000000baf042059879a2f17e6b976240b0fe342dbca69b5868c59fc89b902957a83b368373e2eb2be201ec281c8f2788cb9911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016e18e49e5fd482fcfb44b91bfe7a8244b51b99143f592980d56783d29a40eedceed2b459c2a741c6c68e227f11d6af0000000000000000000000000000000006c1741d152d500826b28b52e7007c091470f48ff626188af95968bbc32e8f28db6940612cad79cf7b8c5f625d3dd25d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c52198ff413685236699b3cbdcb2a844743ae0ec388d0f19784d75b76bd32ecf9d2072afd24eb85ab7373902f23994000000000000000000000000000000000b52487e28501f279667b7b8177b65a17760c421bdcdca499b9c637364dcb680bce1356501aaf602297abbe0eff6132f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c4e01b6264c5649a9f0c99fa52869354e43a4fa21179eaba87782e73304d6bf104bfe75459e15a6d510af2ac6a1197000000000000000000000000000000001972b5464de7f91e11cd3ed6a995a7a0372fc0ac2294131eb35e6443a619fd74c528c2348c347847908a0cac3943133d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d838ba9f20c8d4d0e962137f5de82584538b5fd73092bd3e02a31de6df79b41692128c5323b50644603685af4b5bc800000000000000000000000000000000146388be7e8ae6986b7d667f77b08cbfcc9f0f880a02008a30dfb48eaa46dc9d42efe3b738ea3d1799724a2952cec88d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016bcb08bfe1da7657c42f1dfaffedff442dee9f2502a960300dabaad5efcb19d2f26704a36ac79c5ae8ad2542bbf1893000000000000000000000000000000000142268eab968c83e69e9e434ae15c54bd8f2cb784c39b3c84450446c6377ec364fb9c3f647b13b626c0f3a4ffe89e8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035bb13d24ebc2b627bf8d3b96e80ae2303f96bfcf441d57e4ef3ebc3e461694331566c463680700cd4e47d55372babe000000000000000000000000000000000858eccfdd2b40998f4050a131d875f9ba851a801c6dcf5d85f31bb76f2d16160987076d42d8e72ae419baf35090c4cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0d640d467efbdb1865a54e3fd0ca9185e08b52419b3bd1815bf625831f86c90f9f394c6de225c0043c4ee60320a16c000000000000000000000000000000000c9662de7ec1ebe557d148973fa21ac795050d7c5d4d048356b4c9b0d51c85e0a632955575b0cfbafd8d72caa3cc41f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012514c99af2c22f95f4fb02e307c090fa3ace72e68de35f12e91069e2a77745d6ea84595db78318a929aedce62caa942000000000000000000000000000000000309db4e4692418fefd4880bc0082055f25475a173babe8f12aeafc13846a8b14bba8e63ad44846be62f9f4277ba5d141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b2d8a702d9ae43f6d508f92f37f5ba3bb86abecd5ed9fbe2c590adcd853b911b03d9a05448318151d94ac9bbc433b80000000000000000000000000000000015a142f9ff44bf5f1933878e2c009621543f00d45ea5da8d70fe8dfdb8354df537615f41d5c31a86e1fed5c9eaec37bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df888eb6b6f9ec62b7803a3f6d39a0230473df6d891726cfac7c10a380cab7e6da502f1edf0b600b374caffb194c78f000000000000000000000000000000000f926c3bf6870e12a76e35c3d661d81927c00afc5028617aca866f477bd870e97494b0b88829904552d5b01925d89d321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dd2cb07b568d314425122f23177a13e59194a0d2feb2f818c3abf0793a0a27daf841ab0081af245f75eb6c20d4066200000000000000000000000000000000008c16784ca8cee3c304ba16b09acdcf7341162043b78df9ce8f069daee52407b6aa7a4a44d5e31f18bd4f17412e19e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cf443db1fc5dd8698d250cc9fb95505918d0316eae884bc323e2b06737f68a38f8da26d43e40e1d2b2e7df1a56b237000000000000000000000000000000001069b8ee7475043ade78b80e0675a4b808b98b8d7b0c3c2b7a63eaa6d5b80111fdc5450180994d179246847bb081d44d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b5636f7866dded581fe4a460b887cd18e0e3c9ce716e92907f95c491098f651a928a1208ebd139632aebc13bd4a2e20000000000000000000000000000000019f55b97ff92d86e56094f2d90cb177263220d74bf7066fd686882c918814e4d053d6e74757f324b6bc241dc74f4c3121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190fb436954884ce2fba4a38e52039b0449a3a556535425a93e3664fee7c1b2a943d3619ce2dee750f2949526185ba82000000000000000000000000000000001883c6626df40914ce2c15a7d75608e2fb359362e560277acdd29033be4533c293d01122ec0255122a18e90df478bcde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebae319e5f0460cabab5618c858d030b4346a560f95f1190d1215caf2da1b096920461a858240d4d6697d81adf0cb040000000000000000000000000000000013f1f0d1603a3dd6d4def1349072ca924fd7e4e79c3c72f1fc229bd9aa267b41abd7b9cb4a991d5e79f63993a1f5a47e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082053003c6f76cd6f01c0d0d50ee5053a6ecc285510b504ebbbcc4da2c262e6ea0b91de2c26a38e4cff4f4b2452859600000000000000000000000000000000183466a12df33b9ed7cf94985c29cf2d9434510496d8e73935d3ccfa345fc4be4c19c17f32144343b3a0cc3f15b62cb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112e8f75f6505f03bbc71bfc6e2e15a1620a2344a604d49b7a8f4b83c7329b96c3961cab4a692844b29ad76590c2492700000000000000000000000000000000028323f8840f5da31af29705dedf59b7f3f0d2025fc62c7db6200de7c076264c2d9498f839836106c28e53ddcce220111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b71fada96f2275c12542bf9fc2b932cfc7878b98292c8f32fbafec75a985b703440b10e6e8ea7825f9d16b41ae2d8f00000000000000000000000000000000043f36d8b2a3b9f5bdae91f7de8da2fcc52c9bf237f1515148ba8e9b4d874fc3ce9b10cda44b32d30954952c6ef53aaa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0e3f7c7b2694359934544101be4e4bdd4fa2849104da41fd80ada55ab3571fe2014af6cf640287176c0baf9cf09ada00000000000000000000000000000000057ec4d92931945d9c5c061ac62c23499424bbc142956aaf9c1a395b1b0817fd7a7e763df7c990e958e145bb260f39fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000161512d1016710aa14768013f2445b6dd727502f5dc1ba0e6ba2beb371137e7a78ea3151737d63c500fd1b757ccfdfa000000000000000000000000000000000674f712faa60aac4d7d623b54b15a34e832601d20a1a7fdf81fd27fa58a280520a5e552e59b10163be3287a457ca8f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e076ca12c4165da77862f49e479e9a700fb03aac93149491733a29c1e8d88ff4348512091f1e0eaf076390a6a25ef700000000000000000000000000000000137a9b12e0dac1fac59654747ce6e2c0bf69a92fb7ab12e53b0f83e333b43a747df3b8a9228b470a0aa1c67c7585414a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ca1e24e55d8ab7f1905957c9a2b487115e97d6baebefc2ea9066249ad553dadf77c816a08daa6571893a4255c3b71000000000000000000000000000000000106b740e1bfcc0e62eec98307c4f54d991a4ec6a861d6d1f0e62eb38a1652617856e4f2eeb99a69903a2cb8ecf8ed77f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac43272ff019f1ac63a156e1672d3734b3a988164e6bcd92c636560718b0cad035e00acefb6e9a7d5a498b237ec02c40000000000000000000000000000000019a483093ecf6a2869f9bbd5fe7c5d32a1b02dd7c7b6d1474cff196f7fa87f40de3fcacb39d8f1ab6e20db974bebec631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c6e4cf7e2420fb383e664990b6fae6e6903771ad8b37ed5d14a3b831eaded8613e3c2a5ad50fc5a19ac61b4e3afad8000000000000000000000000000000000c6ac8968b39223b0171f2d2314df24067ce48f5f6a045a2a758ececaaf9f51d00a83df3d2f796204f0c4fe190d869c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c04802e611a8cb1e8e56f9186cb827d55142e133e7b4097e83f41e736458efd722f69d224f761dc843961cdb6f46950000000000000000000000000000000015d1551f2a274666dd9e45a0e56bf0d2a27cf5c6dc7597a45614078f851bba62e3ab23aefc7828e6dc9d96a770a9d4e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018aea943f15bb896e56c41eb9b21dbafb4dbf3d1f46ad62a5a0d9dd4b0bf5ca30e8cf51d74cd6b2193bfc0ddb3885c8d0000000000000000000000000000000016febac9461db6901a8a13374cac49f2885af1aa4c65aebbf80474f7ee30dcb91a34aac766ebedb23b879f57f34bb04d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002d463dc4da27ad2115f2a1d13ab9a8d36325a66909c1cf4e40a105e1c536be11d4a0a83508ac82efbbaaf3c780ecb90000000000000000000000000000000011ca8cad60e73e7922d46b6d1f4e0bd13c343f477516df12a29903c3c5ed0773c5b4d4892aca81550ec4b354786f0b8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013401c78570d6152026a581df202a27b13c8cd807e0da791565f4271a285cd61dedc3986af4f4b6db64a74b479efaff70000000000000000000000000000000013090059bd58303cdc68152a2e38823f3999da7b227e15a8832f2b28268149b5e9bbf002d0a9ee1fedcb4447a4c696081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a272bd9af5fb317c933c975f2f11a4c3c7bd783fbbcfbea122786f7d104b47773b754033e8056fe00a36b4100d81d9f000000000000000000000000000000000e5bdf44464edb775cb592cda24acf1988b15d0557a04b0a8b7ff93d2f83e1932a5bc9218f8fe94e4cccc5e896401e311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae2f845eddec32d172e7679edeab4d0fd815700c0dd617369ddf4c7c7267373b30ed1f2b6e9f5d43eca0a6cc991364800000000000000000000000000000000197aadca3fd15e77c436cddc99bd623d25c507618a850fc5b438d1525e8e8228934fd330d1dac7cb7dad97a4a11b4cef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c58e0fb254a63c750946f8bd3ffa8766514314c1f11ed73cd6136f1c9dcd085edb233fdee84d01742448675bd42cd1000000000000000000000000000000001240bd1a1b5f7183ccbe0c3dae9d02b1e2bf55230b4d2b625338c7ac3ad6f8d542eb2f20ba076228d97590d23278d9c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f06222fcd79fd5949837331b61eb386a9d98f4bd4107cbeb232484880c045d6b55091468e1ff5fd24a8ba020253a2c0000000000000000000000000000000004f82852ad8d78166d6865234d8c50550a20ea28c251cc2a4d40c0d7b659b84b9819724c5c5decda883443fcb27a88901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f7811e2add7cf8b4dab10577ac3c8ae7f0683a1063b20fc23e0191401a7cf07237c6a618c2d654199357456042c1260000000000000000000000000000000007751df6796aad740712982976951bf22365d8ae6c70b70485f2f3ac4fc01ec4e37cd1f5ceaa09541edcba95b1f54c211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001320574bcb16fec24c391932fb92aceea2e6b862772f1dab4063963b877cf9923433cefc18b4e4338c18866294e57d140000000000000000000000000000000011dbded803938f2d02b5832d2bc158ee4f350a6ef1c945d0b456326916fff11083a5d0f0814c1766af3bb99182267d9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a8300f44d5dffc241e7598fcbe767279228df42145535087947b2f7ead6d51c8d8c95f963acd8d773386637d959238000000000000000000000000000000000e878732e843de4d6d0e557f3416dd9eb1bf432af6c8ea2c3c439dcad4d35f864b3566491b4e50614e4ad4965531db841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d650a4d4ef2743778596a60526677cb7772ba1df41cb7c962a5e9ab28979ea08f7b51c5c8c8b75d737a169a8e53be5000000000000000000000000000000000e7a95dae68634ee6be82936564c3b90b55f59dc1cabc0e7c0e21a39b376f6b6a11874c5e739400a8e7b90fb1349090f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007771b7c0046f0031323970e5072558e981f844dd8e776f75107973f7f25fe2aca81409aae9244245b2195641eec737a0000000000000000000000000000000013035c533a96a82117bcf5f3df119508a714844bc93cd5ff40d151b4af58a60fbf20053cb4e719798f5c54d838bc8db71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016eb280d0657b1fc4305ef1f91fb1030c4a82a543c26dc0bbd076e0065efbe284a2fe74143ce5f8a786d92baa2b81fb000000000000000000000000000000000166e75c11705dd841b687d5ea99238b90bf193209e19315c7146d52e42d23953b20c1dfff65d0bb7f5e5744a5b3d3adf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003be0ee0cc0e3edcec734b0da1dd95cc897a1ed8e078b3cf260c67619f07a08db4837cd480c9fe6362e2ae98480d88de000000000000000000000000000000001352a88816cedf38a5d6a0fcdadbf5b9aa6a1fc83b6cc9744c3ffc6e07ca90d51df1d16623479eddff376f99273cb2311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b8bd67bb43fb8a2266b98293658f4c707353ad3df04043d3a754adc7628e9d06bbea0cdbb7b406301a486794588b3e0000000000000000000000000000000004feabc20b20fac6b7cb620caebf5ad4fbbfe4a265f81784711d7d342f400c2033213c8147b5f7c0701a7d5e32d5dfec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093b5074e96c01ed6e9fd21693b8016547b17baff6c0c4be1ec9115d7ca16c31604fc90417d0f8e23f9162ad94672312000000000000000000000000000000001476950369a927d9f97f17cc3ce745fad4a43512f7af2c70c7405a5b1fa072a9d6acffb5aa9a9511ce43a7534fdd6ae71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000159877955d3e49f6e5347447f17ba0cac543c24de82e1e971ddf9e745335ca5ca4e32f3ca59484bd6bb690c17058704000000000000000000000000000000000857fa57cf1ada4013efcab045f646dc39a7499904ac45ad93e3d11791f36c46107e4c9ca2d274d902982d8994a0d4401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1c6f3f629dd9322d2c71220fbe607ab5881ff589ce6861375efc81748955ed3def5da1e21c9020bc9ab534893973a3000000000000000000000000000000000da198a54e61e9d098edacfb3dee63b0f296d57069d6fcc2888149ec0fc1ffc93a507b69d53d9955d874ed5a14585ba91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d495cad1b3a883ce7ec2ccf3f31ff9eed422dcc11302cc938ccb8f5b72382b0d1c6876125eee4bf207b659495e5a4600000000000000000000000000000000097bbe69b5e468e70cd9e89b2d314af647672e89d95f4592cc77066589916902ab1b297289ac5087627a829aaa642b661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001279862eb539f6f00072fb14f4933431e6032fa4a9cdf24bc19e34a55a6f8e5ffaa3afd151dff9a9fd53a1737747f6de0000000000000000000000000000000012e1547b8cae6d23aa036eaccddac346b8069536eb7b3a027cbc7909881c60cf8a5b70fbc89902ccfd2d6e4a24edf02a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab68e7d11758bdcbb2e2f7345720a370ddf1b3f3839dd9433fd97c37408035b23325318a8ba25df89e03de3cbbd802e0000000000000000000000000000000003f119844d019f29e05fa02b7cf065fa6dce02830c315853e3ff3afee580779e158ea602a08de2efb1462f9440d239501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000706a2d733f2e7ea6a7cc09baa3b9f3f86e0b938bba3db6d619438b2d8bca1184190af9434e69860acf00495671d72f90000000000000000000000000000000018261daf159d2534414d0daa0f4ad3b737ee2cd04ff1bafce5aca8cdbb9fb4774b3803cbe85f838458753b9c1856800a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056b6658d7817400086214aac098438ce97a7230e3496e335b45c5078dee1a843ae3aaa3f7fbbe0b2b07d0a8ec323c1a0000000000000000000000000000000001cc3ed8d20be9fc2ca26aa27733bd3797e53e4595f427f95ec937656b0d9def113fef67d5fc67cd9fd5ce0ecc79e0771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b811af804f574836cf077c4142881e30824aba7e8ce0ad581591c8464365d6424262a0aa47aa90d92e6aed60ac4230000000000000000000000000000000000329a101b1a82b10bdaeaa2151901e0b3b92e514007b13404d38e7bbfae03cdcdb3f7cf0b94613a69bd46dd39e52ef431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001571b940025035b8eba3c82f51559159a375eff08cdd0d18be551c58b32b712de4612149f2ac0a6ba621f252c8b8825f000000000000000000000000000000001438be78e9880ac556278d01b657a218298953d15194561df261ef0bbfa99ae3af4f6803185bc157ac892597df55246c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f897489b5667466c894e05e2ab074abd073185a1380a365c0f3b981cedcf5a6dd13a9f1cab8687bf4a74c510a9d4e41000000000000000000000000000000000d85a13387711329ee7232480095f5acd82a92bb56171dceeb5c2c1e2162b36ea9995ba6b557c874e6bbccd9158fbbb91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127ae22c38e5b623cd71855feae611d34848461779ac058141a1ecd3f1a83e7f51352e864a3c565657bc4a99ba9f0a740000000000000000000000000000000000ac436b7038e529c7c15d6cee6e25b145ce19b178ad1d54af8e228a4a6299360d1d4e8c26f664c646e6110c33acaa9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107bbd7af85992763bf6e9a46b74cf467e47d0d73b87dff55b481d782c776b7d5a3ef57e027e2337fb517c3ae388f952000000000000000000000000000000001291ef001a59aa4dc01e142f4c8c339c750e5576703b9dcc3094d640dec2efbd7e2e7593b00426c801241e0318d1446e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c788a17792f6612a287ab7f2582d72c90d5bc84bc89c0a5dc9038d679a0cb91d613df56a702662f7220710827f0f6b10000000000000000000000000000000019f80c7b4e69e68ae3f5b420e65b64196336ba301ded3227abf1eee2d4a0448533cdbebcdff2da75a154262c8451c8e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026eafe18c1e5cdb0f659296b22557bd0eb222e89c4eb74c5b21da78682fadc1eaac8dbb54a0aa714e68b288c4cbc2400000000000000000000000000000000018fec8de5cc8107ff37ec319c6a8df977de8bf61e172b71f47262967ea056a3e9d6dc8eb01fab2f5cb85195147b6970a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e2bcc87b4c21b0fcc0fe251eee14e69a42cecee1f180bcbd29969b1ca6dff77d8a0d4601cc25e866c8ea9454a4fefa00000000000000000000000000000000144a59ae421862dcd786ad2d8056ad7ef623efda3aec47eebda9218203220a6a4a31387823e5b9638d3cc941e049584e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ded2e47765593d38861e725b172bbf9121aa8d661c4572989d2aed03e024ae9d3f5945faa347e43b7276330aecbde000000000000000000000000000000000042ed94eb448c2f6b5f2139393ca7dd240ddcd709ba3bbcbf713c216e4895cd29dc30441564e12fb8d0f6c1b50631a451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3042a230f2c44ba569eeacb2d1440712e3f9d326123aab7d8f69463e389f7251efc69680d5017c7e5779eb4e11dbd0000000000000000000000000000000000c6c4bdcd3c33647711448c75c12ea905ed0f52703c4709ff62eda29d554eac990a101cf05f647efe6f98296c2fc73dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186ff13d914286ebdd5ad2032fad3b8941c6543ac1a37e30eada26c41a69258aad12c02a79f5ae82ba0c1be93821f54d000000000000000000000000000000000736e2d1a7078d0ad0537493ae07f09faa1268b97832d802010404b01a7c005f259b14c7fc886323af0f220f884aebb81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001955870617b6b85ab13b3669874ddd91b75826c1a736ec2399505496ba5bb1fd9ce20c303c2da60937a8d4f20a4e6d81000000000000000000000000000000000be61d56e9ccc1011afcc0d75621f12b20ebfe68ed8065c244a78c33c4f7b2f4f40d6b172143ed0108ce9d51c874d4bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080f1b3d001c049ff81b253b635c6992eb2961a72d60cd65caf2e27e6bb48fa4bb50ed4d7f9852613afcdf03326852eb000000000000000000000000000000000552b84e59fc41ff4aaed1f3918bf69172e72daae50abfc9f9aec23894022ea3450d5d65dd017cc31e1645cc2d53054d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a6df535871d8034b0a0a036ec42a8113f80fe1b74e5a487c488db45114f5ac9524c3499acf15b49c14821bc2087cb0000000000000000000000000000000000457336046d1a1a2889d4a7940fe9cb4a693ed6c9fb83116461e03bd54f705af5433181f0d47ad196b174b7a094ce7fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017f510a6df7e25ef138c3fbcaa5049c8ac38c5edf3e3fcb0993c8743153255c485b3e37033e215aded48071fac73c410000000000000000000000000000000015994c0b76d039f6c5893131d9a9bcf827c1276ea58ed05417154d51d3a700b5815fe7ea466a992fc22561bbaf5cb0831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000089711d2ffe689db8a76b4caebd69458dddd94d6502ca8d3f502b43fbe97155bc755a6c38e3fef02ecf3cb3e49fceede00000000000000000000000000000000078fc19736caefe8fe2da2d3ae22f73371a55b3fa8baf4b5b06f91b8baef4e067e09bcc0edce4fed14a109a14be007ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b88373362c8ed4fe804a41ee808fe9023e5aaf0b5e341118126f0c0dd0d8c7e75fc831243c5bffe2ec17ff8305eb1d4000000000000000000000000000000000d5948e6c75c4c0c39ae852b412e1474943fb615f5960c3c353224abc94131ae9d5ab8fae576cab9bf2dba61f7d993dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7ae10b09464ea00f1f7b1dbc69486f346d4c72a10a6569add7352ec2a699fa6c45e1fc83fd5505296e2d1982cd9dc8000000000000000000000000000000000ac6402c5c9bbe08ed99e57b2eaff2d69d7ff30d777a6bbabd454a377b2b78b666222e5739c8cebf339f459f5b6f857b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000949d6b7cb74a4ebfd9eb444479902640c2f26a2e402ec0afcd3c47db22d302a55aa39b7ea9fc7e30247f1e7ca821ad6000000000000000000000000000000000890c822bc5db707e62d98eebb758f5b14ca11708a3d924ac7fb3370c3679d0e7374b1ac19715c0ce3638c27e2a877fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001957da8b8c62081952044465c4a7a5cc248b204a3232a3db2a6543b0a680e4abc0d19651a1785f053f5318c425dbf77d00000000000000000000000000000000131c0401b07c5995c3821e714b2bb9c57349d81c93afc1bf95095ea7c3d3959574995f4c0bae8e3ab767b81fc07aa6d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfac923a3f0ba2afa4fb0a7b40b9008c2e62596119ddc63561c83991520b5eb6dd01ea0a6d64eb3152b9f0d8d5d8251000000000000000000000000000000000f80ec93ee30961d2ddc7ce0ffa7f125e5caf70a93c0d1dea764844423100b1dce97b3e74f0217bcdb9a20b0e98a4f381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105c920a8c628c5ee6df811918655734414a11d9d3c8c2b267211382bcaeeb101cf54b1218ee3b2d70bd103d93ef2a620000000000000000000000000000000018183909b6f4ae01b8adf79e8f943d35f606a8652c1003dda0e865da28ac0e5cfee03aa7ab6d119c1fe64cf3ae82eb691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7b6a789949ab6a18528052849366c64be6957112138a4d3cb2e4d2e23e4d36c9c9c73cffd4db1c6e5e4c130a81effa000000000000000000000000000000000f5b34a2a448a3b4dc1bae9e317726363d744318cd95a75be2718b6f2f7ed698ea4584de11f6312b9f06cb97a6a855d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183f731229099e4499ce7612c7ccf8592986f27cb77a37daf0b26bff95f7f5d3be11e5869c609ef24e2353415c644aac000000000000000000000000000000000114ec4f9b935b8b22a9446fedc91a1a827b486aac30147fd6e1ed17ae3f014d40d7ac93beb63c6c9e191e5cf85f53bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001244f72c444130d42abce0086ec4ff444e674915723bc3a76c38f1a5433312211506ee4184b6a39627138960695783920000000000000000000000000000000019d8c7191637362462b84eff3a35404dfbfc773644162557fee58e4eb19740044e12b6c595850eb69649964cffe0e3ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb83b92216803f44abb850c622dfbeda0c595a35925131ecf3833e39f9cd726c91555367792b0563206a8274aa65d6900000000000000000000000000000000019f59973beaa77e793d2fbda4db276b792c859878d375a21778dae5db344cb836f84985c02e2bf942bf148e0cf8c8441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dc7b92216d265c7df538698d3e67f42346e0d7d48b0637574a2dc398865a56f790360d6d35b8996ffe51fcd34cfc6d0000000000000000000000000000000004169afb5d531b61b2029c951db600aaa3425ad4acc61d100168e54751bc2b3f808d5ddc2052c87bc7a165e6470816a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008aab59620251cded56b0a75f70599e7993aa1a2429bf7bbf1aa5ab072dc76ca038077a4f2ec35a733f20e14da803bea0000000000000000000000000000000001bfb1a02bc7971e9cd2a6132dd5c6eda6d35b1cd9441441258959f4709dec0253ba6c7944fbeafacdb53d1aec7194b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053f21eef97cacdc21a070c2d6f982a82c2c4f98241402dd430b660b52ebf4e566adbc07b36644a3f338216f0cbccce60000000000000000000000000000000008ecf818f2fa8706424797f829074ca8a8dcd77ec2dcf3104579332b765bb3290613957e7c143c5852da45cc021c4ce71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d209a728ed2ff7a6d4e59743fc1f5f4fe3a1f74dab37d5f96a7997e11059aa1b6de4520a35716b14fc10f3c1fb6a13200000000000000000000000000000000140ee309280024c3a58c411a0c49fc166460ffef8891cfc505bd2b4ab75fa4be812f859e9042d27ad47344394f421a881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e56ab8267ab56080109e7e062bec24698acc1b23e1cabc79387eafad2f4bf798fcca2bbde5a085b68d1f06bcca53a40000000000000000000000000000000002f63a8904fee05c1c3c772e4a06512ee169788779b6b2d1fab5e15c9fb15efadd9269d6e8c61087ab93c3bb863f3c981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ffa0015ee1a894f153fc76a42f582c3a6934b818c2f6cf97f348e3745c8787f815ae0e24b9fb2fed2fffdb4bce86b800000000000000000000000000000000075dc304ec95efb1d003d5e5a8f2112035066d085117e2817c944f8df23c53db5800daa1687b0187c69195114344607b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dca360ef287b9834d5f6f85daca79b765d626901e82aea8d0cb772632a6fc5d908972a9afb4a47c0f04704b747fa15f000000000000000000000000000000000709902505613d4da8441e63052bdb2b53fc518286ec92d4668ff2884752fa66d0ccb1dc234f105bd5056a11ebfc343a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148a9292a36ef70952c15224a0c04b605026e58c0c05adeadd3551957cae51f5c2be81d5ba165677efe890791f839b780000000000000000000000000000000014494bffc51402185c8509f29c74d5aec835d855159f8ff2cb6189d6ca9609be63065877804802ee9023557c22d384621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015cafb23f4f461ceca20b75aa8bbc86704b4524efe61ff1e2adc704e38ac3648b205857464f7c1c995d3eb38abdc70940000000000000000000000000000000015ae0b7263624365a7678fb13d7f520307522dced26b4eb37be39e849378258ba1e54653272b3beafbba397aa7527da61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f75fbe3b2715efe591b764e09b9b29d3edf8096c80208893eacbcb091edf1a24e51b6de5e7aaf225a308902e9a7683000000000000000000000000000000000eeb52fce388696cb0bad149dc6b41496053e53c7163e7dedaa47b9724fa6fc22477728f0c4022ebdd22e592e202108a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f9984d2aedab56a7843e4b801c3087732993d7c75cc6aeaf7801ef285aff5fc7430c5efe984fdc3e75d58497fb7bcb000000000000000000000000000000001014d5953e8af52868da2a967635ecfb946b3b3dfbdb629e3271b5beb9dbb78ec4d3ee4c27c2cd04abae42bd53859f961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012cd2e31ec4d48d76f42fbe42873979cfab23c779582c0aea33a1069339b92edbb577ea4bf5f217a7e4638d6d68fbff40000000000000000000000000000000017d409fbfae282ee8a4bd78e0e013bdc0b1c5cd41e2ba40637be8666bbf92a9423f16d0410ff5529a08e57832966479d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016f8df8dbf74581b41ebab248602420c2edce6a242abfbecfe7ac0f3193bd696b940d5c44875adf78ea855f26798768000000000000000000000000000000000c30e8c3786c9d43947337fbcf14eb3b40156d72a4f0cd455f213bb33b53157487deb8f3523edf86001c376c8a0c746a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000670a10cf742da54bd016333f57c98faef907093197f565ffeeb99befaeb855f8c14a0b97775c3d2661373aea8553610000000000000000000000000000000000d087c99d1304a797e89d59aba20fa4f9e14a9eab0f804b5ff58a1c799fcd931ef0aef3be12662a249780eca2a4e02031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090bac216e4b504ca392a25dab9508a1a21c7e10af9f896649550ae25a9684e165b3a8ecec46512b0127e23336ce71bc0000000000000000000000000000000011a92c450da8642367bcf7ff2fa050ae89307122ab84c54971e0fb560d96ea94e9bebf03661ab1dbf0ee5bd27104d0791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e923f26ae98ca4f622e18ca43fcfdb4c67969b3bd1b79dc43855722842fc4085d544c8aa004e95c25189dff5f626920000000000000000000000000000000007ea320d51f2386cdb518355c81a85c7a4a4a8bf4da22f845c232577fe1b20bbd21fc69aa2abf4a913c21fe061707ddf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186d37d78621017933650d22dca11e8cd6535c4e00ff8c3aca6e93582530519223e7fd06bac0677bf37354553d8b0cfe0000000000000000000000000000000014746572098d48ef00a1c323063fbdfc227cb948486e7f11ef670c38649e3f8e2bf8de5a5a408206697e78427fa92a811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f9070126160d86737dee5a76532288b4083e4190fe7346dc10bc00128895a78123f2174c4d48ff54be59c1a6948555000000000000000000000000000000000b0e56a982f2d1430ad5e6b7165ff32f865af82dfa2b7618bc8ec1b93ee925c8f7ae5e6298317b1e470dd06667101d921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ad7d590eb6aeeca06ec66543051aeb4aa8563309ede60d323eacfb2b0596f4fe3d194f521d05253a392f287f83d17a000000000000000000000000000000000acf7096efcbeb870f588d7935fb0c7ebe3349f0e30231adc90d5e54d0feb47f7940219954c4e10c69d078c5980f3a0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112208cfe134e79deba0ae766a41c560cbf5b0a2401e330e477a843d04bde3bf36b8d63b35b78a2673c4bac76d1c49be0000000000000000000000000000000005e852db35397784eb28295fc29aac1592b13c71f8b69e06f4da3f1bfb94c02f42e8b7e56cc65dcc76d7c8073dbdad851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001385efc42ac56a1cbe446dc4ba7cc679faeb0039bb1ac0c27c1b05f42687cd457779ebbafd03593c25db132e217851ed00000000000000000000000000000000058807816249bf04ac2a73f3fa5dc9572caa9d5262e917b26bdff1cbd24e92c4d291ce47b02513919cee64f1b13ffcb81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e78378c06aa2cd45a3a4f9130e37a57e38d47d076ab34f03dcd1549ff34ea32fb4082b49f3f322a662de186f98c9df0000000000000000000000000000000017fab497e041b494a846d2599c70414a571f563b1ca80cbddb020dee66ffdf89827340852e2ced4abd8979c6508c517a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002689f2da3b72de33c68154bfc506a834270858ac1f8ebecc712d2c547efc3efb832c4dfc19dc0f83082812e870402e4000000000000000000000000000000000b9b4d92d4a2257a6865b6ee4695b48472eae649e5d0203f935d921d89d88f927dc9ed1713b40596b7dff965db9b415d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d81ef768ed945f85b2028e5ead9ba29fc735b6285290933befa4a687d15aa454d9dc11fe45c6ca47163115f573306220000000000000000000000000000000010b4f9de18ff1be318e97dc7d165ca46d17f82e028da544fb7790e7770fcf06394bcbe95108120e2095a01e03dd465651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff0d24868a22904416aefd8a90b36395ecbc4cdda7aa2aa01224c57c0b67629c0ed20653b87aa145d859ac87681b473000000000000000000000000000000000dfa71092402ddec640c90394281bd19fcddf8a803f302b560b9f3782ac1f316a1336ba2bff3ccfb08aaed13a6238a191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a3f61a4c5490bcd060dff8b9c28a69e28a6e8a9a326fe3c66d299a90c5acad54ab41c5b7c05776f0fdb1c39da92ae6e00000000000000000000000000000000074e925cee5ba0ae23092abf9077c7a1927f506e8900d8509f1c5b323d74a38c00d2501ab7c4e9304efe60576cec795b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000838180d3608bf17d8d949de03d91b1871e4a58bcf818861c2eab572cf5625a30a076ed0560c7cb41505e3180cb656c400000000000000000000000000000000056775595c8618bcfb11cbe62b944e67f3397045c5f4b07b65d595bf64726fb87ae300b8b81997219dbc4de1989129671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010b5446c938a0fb70242c352eda8c92acb4863c8496f18515a5840dff3bf2b395bf6df05cc6aa7a76e21a69e8436541000000000000000000000000000000000f026a9d2746d99c85dbbf5ec9f7ac1347e218bc3d2cd5a4710bcbc49bba269594eae8ba9c12327aae788e8d654549981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066bc772b99db3993c1654ad0d65ea88bff1aad0c0a714e5e82490f38d2154e28775237767c63a01288ff5eb0ea96b1a000000000000000000000000000000000134429fd827d0ce3ac96cb657113f278c15f9b18e39de9eee11fae8830c74bf2bcf8b1b0417acb97abddb6f64d9d32f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd09fed3eeff11b1b322a47ce3299e225ba9105f39916ae3f93fdce19ed756ca95f7f2408c88d58b80d474ae586e300000000000000000000000000000000001521a6cd2d76e935dd07eb511e085a42e96ab17fdae1d1f24413a743e99b9d2c85098fb88b8b72b4f1be8099a5467ceb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004eb4dc68a9e222fa5e97041037a7a3312f62d68a56a9ab036cc2688e202e12b9b48bbb092eda4f4bd2888c0365e3200000000000000000000000000000000015b50a8accdb228740ac42ea6cbad9e9df9d9a69b78697e963efdf918c787a1c89860e3384c0d13fe1d319bd1edb6d681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe49e93887385140fed86f065af5f26ace2fcd0d2b70f77035814849f37c7a918d443d7f5fb5b4171f2bda29b88ae220000000000000000000000000000000003cda1c7b1435c91c389057aaaa30c003d79a5d5cf377729d9ffb0bc7d14857413818ee3b5246a966d44a4d26d1b597c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031c9faaadbc4c938a2b549415590f679d6af42bf09ab11f0af1574dd2f7eef0b48e9810c40e6d2341a07a1388d366770000000000000000000000000000000000251443a2fd5c59d8ddb5e41447f1f0946e69a9ab6be208687d792a120b30d43938a1f38b8d27ecd982cd73b5fe5bc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092e2bcab95827afe4fc5313ace4349fe3e09e36d031a2548d6a5185f84857e2da4bbc215f5086ea461632af3d2b5332000000000000000000000000000000000a532862b949400a91302a94add18af9dba62c24e7b497d6ad134196d4385a618a474fd0601639354ec25ad3dde7b4671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075c27f00071971bdc1adeb1048c1f98b1955d603c4e4d69f74f66d2544a9a7c40637259136ed758cf7eda2cbeb804b6000000000000000000000000000000001279311dfb07bdcab96ff341d28eb77746bd268f2fa3492caa0f02272b17043e09cfaef088030c3fa8324d756ced66571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a1189c4aeff2e004e7d1236888bf741e1439499fd268581bb1b39fd0ab553dd6bb6ade98363931fa6a7fd74f4d6fb5000000000000000000000000000000000cc6f85c19c8f1fb460e29ddf7c83824fcd545cf72b56dffeaf0f9a428ab2cd71b70172e60f65b52a92e8fa37d946cb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012146524ccb8cb2faa14a0a583268c21ea99d55fffbd3278c80a93ebea010494906dca2a3d5afdce13083667fff5a06200000000000000000000000000000000000fc213a3f4e5363af7a4d8d7f62a54d93264cf43b55680b6c706a1c4f7efb822b9a6c3c0efcf9d2d3c8b414846c9921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107dcd28e7747c54f35dd5db9e5263caee70e9e7dbc2b7346ef32c821c0120a2c880a8fa81b0b6509c66bb51626e595e0000000000000000000000000000000017e2012179252de5172a940771acf02de4d94f29eec013dda0090fa48eeb52e545141b3ebe55d65abb1f885ce0b393881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a94e7cd33f053c0cb724521006dde9a0de77af19b233028efe7b6a5682a22d46a02cda55526d81ffe4dd0ff53e9d6700000000000000000000000000000000163ee20bf0a99b09c776b4bde73de92e728e258a51d5b97f4ba85a73931278dcb87425c69d4105cd53b6b63de670a3cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033c33cc3fecb91a6ae3607211a1863e35c217d66c2acc619423131d3d99f1c9d84c16c3f3820f1bca68b31d5ccd424c00000000000000000000000000000000190a9bf5522fcbb1e47d2eaf36efa78029f303fc075cc1ae07c4e2ddc6c35154f672c774c4a44544b2b0c7322d42b3791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000289e570546f4808cbd4756f826eeb12f92c86a449e1f4506b033d8083ab6a5134774e05c67890cd4b4d16800d287af900000000000000000000000000000000137ca623b609fd1a1d77323fd4d7733ec91bedbdf2429834515432acc80e71c99772ace4d1c9db37e69732bd3f86448b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008eda3c665e9bcbb702c9ef2d75a64a52efbef49873d223635ba3935e02708c609a9f3e667d84216ea242ce2be5898ee000000000000000000000000000000000ad8b603b64146101f8c91d2d228068fd7ad13ef53b7f670a52e70357500ee06c5bb3efc2ebaf2da27ce104b384e187b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001620cd8c8df11fd329ea5883bbb7a650a7b28d617e8887513ef0f9b046d992444e679639d90e6bf9b487b098e7bbe30000000000000000000000000000000004d3fef213cf87d6c0565726c77692f8cfaf2732285b32900bb8f37161c03fbc1d45a03b2106b84f79fa31ce9a2b8ad31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e8468fcb361b3c778c8bab018dc4472e999fecd0ecd9e71f488eff133e34025bfdb61bfed654ec68f8a2eeb08b2479000000000000000000000000000000001475667d8951d22ba9ce0a6eb2bef69f6c48f4b835ae66475dea344b1fc6260673c67b134155cbb200c7906c63d421e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011308b4a03b10624febb2e22b3f6cb66aad832cf35c25684294f93cc43c667c4e91d1db273d504f75f0bb620444e686800000000000000000000000000000000000c3886ab30f6e662dd52ff2122234a833a2a3592f6955719f548b12d45effdb31980b94c25b158972cc16c108b79fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ee50ccd4e9226c1c850f945f6afcde9caa3101a368d0b9df4138c4e86e01edefc19d359d03df76b5229731c26103fb0000000000000000000000000000000008dd3f5b1096559938aebd26eecdcd158333bd1ebecf2d1776298383fb7c15c66bd8c645e87b46c1b7f74a1a50ae5fd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012eb73b7a0b284e20b2f0ad40cf151925a7e481fc7352f0f1de5662176afe777080c63502845ad031bd1fd99bb4ea0860000000000000000000000000000000002c004ee718a84bd638fecb7755a3267b0908f687b46fde7f8fd79ffa6ab5deca6eebfce3a8ef6ffe15dd293c54aeafa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9a3a94dfad2d1a4b04c593a6f38baa0f254bdaf1e915c16c81ea930cc84fa8ef2defa91e34541f7461ff17cf9b1baf000000000000000000000000000000000474806abdba6028f13ba826d1834ba3e5a7211ce582b99a1b1cd81a0f3522e21e28aabcef79094da3af67e30e5a19551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009b1d23d51829ec71a6b43ee084bb3d4fa23b1ff58e50eec959e6701ac25082438547522aaebf4c7fb40a81b916b71f0000000000000000000000000000000008fc4226073f7200c08865747c249e8707a24e86c34e9face84087781020484572e4391fbfb8b2ac8f8ed4251808358c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000158ead58549a811a68b149c23e2e9508ff9388a5143872772a91245a5a7e09540e41fd37e47c7b767982d2437938909a0000000000000000000000000000000019e35957349a5be78ea22f50ea6ad9f95becc0bd440394344126b718681da15c4840a3a4dbd84153f31bc271de41eeb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002803cc9b2390e25712dc32263c6274b6e9e5ed071cdceeb68e61236f686fb7a0dc9bd4f83dfad457f618a6fe019853d000000000000000000000000000000000bc276a62de0b0f3721570b5fac9bdbfaf7e755b75c54f48e58330b7866ff5360e1a7919509cbe9f152ecbbec12989e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017233f007e11b554d20b4c66d506c826b53e73c5aa312d3edff95906e50382be6c2c30012ad8baa2a61828404f2a726d000000000000000000000000000000000c0dad0a3d241480c9a357bb64dd0d7da96de47a660a6f15ab5caed1aa0c09de91ce3e5c4e43a0333585acb93b9f43701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012df7bd0c4a5d257048f3a260674ddb979dffc43be8c527f1788f56aec89a2b1c5e199d08c9e4fb93a3884db453f763d000000000000000000000000000000000ffe3e828d07ebd5bb9ab1225b9b04e82137498d5864c206489d160f65d7c26eb2dd53e315f2597190510aca4cb728171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ce8e21d56a0225f99060d2de3450dcc7f0ade73ac83a8f33da339810b6642a8e6e3be4e0ec45f176ed0ce0bc2af143000000000000000000000000000000000e7b0517db283a0b65772876f9dc78d7d37f2072faeddd0dcaeaeb7e010166642348ee9087eebc1d16a79e5a17b63fd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9f3bf0a55295c28b9b511b0611f6787dc8279327b0a0378e929e2d97601481b1b31ce175f1fdac7bb62ab10928c42f000000000000000000000000000000000164d709d890005f1c9b6292a5adad2dc5d740251a807c1195d12f9a18e0554f8af0cce4da0d5cd6d16a51134010b0e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019fa4fbcb74cf63357ec20cf5e389528b0857057f827b22d7c98e5bee335932b7864c13ede0ec3104d97762c964c9ba8000000000000000000000000000000000c76d4601cdc4562bfdce0934679a3cd93e99df558948d488a6c05d5de28ac9aa34232948d39a4c92f2d57c7f0d36cd61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100404a0c0e1af655a0c170af2a139486dd8a5a950535cec29980a34e282bfedc42016b260c002ccbe092e72145ee93c0000000000000000000000000000000013d48060d5b7e8247caf74a33f25c9243bf7e6c5ec56e1bdaddb11768f41043ab8e6aebd96885319676ff116feada7ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005fac7395754a061a40ada34bad9b0a1d514835b12e37a3561108c41e1386047cea53c0fa6e8796381b1ead5eb23d7d200000000000000000000000000000000190a1fb5403a9cb118ffb6acab4077db18f42209acaf8b00e8acd9dc6267c3e10e4ff10787ca5831031d2fb5b11bf7b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012c6e6c14cb1ff68552f7aeef04aa9a70236f0430cc6fb0920c3d4788330db7abfa86a032a6583db0757fbbdda6d2520000000000000000000000000000000011bd63ca71b181a7ab4abd755162932724a3efc37e74569d55d59b2be3f72c79a185c31117e50bb8d8748501691f91021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a0271199d1bcc10dc730c7ace19b9bb014b3c61b1c331a4ad79c22886349d59caae000cf4db5cb5e30242412523cee00000000000000000000000000000000089837f08733024f44cad0df5c41b4bf4e6a326322e23111d4c433fbb7ca3ec47b4789f8b267556d078e31aeb1ea13411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000381c75f43acd9a4677a7ca01a4cfad06f4b9fa6d8ce7b762d51deb0b2e8aa5ffadaaa3ad9aab3eaa327c03114a0859e000000000000000000000000000000000452658ad02a7a05125264b23c79c52f51162ee5bae7e0cb45f360759cb1ac4ff61c6350d734df51ad82a685f6b5dba61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174bfaaf7eeae079a4dbfb55cf5173b7aabc5dca2d92fedb865a808bc0e23f74b696495f6732e7da79439a81ac149ef100000000000000000000000000000000056f5f1b11e65312543193826c5fd20d82b968cb122e1c6d41e294cbd2be551be488395f556c1c506d39eb16b04659a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012bbfe66de85a349daa8d17c53199cfdc23795f6272ca82b744517da9d1faaa90ab776d7de5aa1b1a83f1ff8954cf9000000000000000000000000000000000144279a62fffef383e2da43956eb39e4f40b3c36f6fab6ea36bec7b84b1fb6b61cff770858a29cd21c27a36e15bb1ab01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000853295f0764067431b1316bf6805d0bb095fc2dbee3ab01e21660863bc7b23117d1f49864b5a73d4498c277db5dd0bf0000000000000000000000000000000006d9351c0406ad31ec8e6fbbc06b00d1e8fc46dac3f1a3fd13f8c1757605e36830da693ebc2cafefd808edea627940c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc2cdd95c24622fd4afcdac5d4142e07563cc03955dcaa8707361535203f491584be38e15cde14c503565228eaa827a000000000000000000000000000000000c4ea0c587827edec68c5929c01f9b5f1de331a678a8c8f397f5736b84ec9b5a66741f24ccd1ade344da2782bbd192891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001903fc58d305ce920c122bda8957722a44b079ff202166d0ad4a766cbee356071f7f8f1f40ce31039d13cbb50da29d290000000000000000000000000000000000412d1c9fac9d71856412642b1c6d04fdc219641e59f35ed9487c7c913c337d80cc14d4b0c1249cbf0be5e4165da1a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000541dc34735d759c76a37bb006f3764d89c8022922e4799d503675d852cec5347c390e820a77c5c018200190649e4b4a000000000000000000000000000000000f380d28edf3190fb5c5af561779f472c3f5643df5b712ca50a85b01c7d7c5894d608fc407a635a2354dbd3ef7ee8ff01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001dc81bab958902c0524ad80fec2a6217ced5b7d02448320dda3e2851b0a4395a1c87c797336f60dbb556d227b066e0b0000000000000000000000000000000002627a45cb80fdfd88879b68cbc0585f6707f80ff17f9ecf3857dc24a823f9e9bb9875d522f4046f48c060e2173f60101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012dea9e366eec167c68bb9efb2418056cb640a4dbccb3a2bd6cc04a09028c4480a7d67a13a4449a92da20157061f4481000000000000000000000000000000000974660be9f31d459b6da4d4c9513b182412a4667085759fa132e09bf1c5f6916f38a6e89ad88c811311082c36fed24f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ff52c533b191b21255c9fb6f827f84a5e608cf4688afca81a3b27884f89cbfde0d9d827bc6116aa4a67f7ba239a85200000000000000000000000000000000190b47bfadd25468bfc62e068487b0a84cb3ace1a5909712b91fb30f60b081b1e93cd7f5fd5afad611717cf1c23069a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003854049f08e771b79e54bee7c1f6b3dde47120611bc66f002d037e8823cd32a81a7ec836a72518b5379baee7e8ffb45000000000000000000000000000000000125414c959e3a1d0a78bfba9224b147fd13a04e248a59c3237b65c52df290d7b9a2afff736b05403b355fee95d5a9d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c47ec0db805e4e3774b5e9a402909bd36e724d0820bbbecd0ff07d6ea039cef6194177abebd2cac1c676683840f14430000000000000000000000000000000018662c6fa3992c1bbb8ed23f9ffc816675667d99ed173eb8dae02015ebec2691ed615d94a82f5358f63c06ec080792f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001273f785da39204f8596647aada492bdbb96d2b22fb032a344c4a2d114456f431f648463ba2daf931db481864e9cc47f000000000000000000000000000000000173104686e5ec28b7a69ce937d1b26092e964911d42f5b66449314b27e69c12cebff23c8f3405d190c1c234651f94161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000819cbafe4bfaca62e087d8aa2d4e338fba0c0b9f3aec65bc90a604f62c1d31334d101eef4669e71a6d8850e9043755a000000000000000000000000000000000d46ec0b7911c29e7a874fce5894a41c99fb2303174d58ac1f58b8978ed5844ebb1c38c01230021c0a3b81f3858c912e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001016c7ce2847822d00d697907dadc87d93ffaf78c1f3da31a33b8fa33b56436f1b2b15e1a4810a2da092961e8d977150000000000000000000000000000000000f52c763bf7d67a07e66685bfd6886af1bd344cbcada7ff7e0371a009368f023c567b1cf7e0c5b9d622c1ee8bcd487f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023cecb99effe9cd992f840d86d7226b304272e3204d9fd0cbbaf0ab3be07d50ece62c2bccb3d37065074692a7da706e000000000000000000000000000000000b8690d8ac8bcfdb5de09f2cae1d96b59246b0c7d437421af86b77ea3711bae6dfcbe4a44b1149cbffc732df7fc578bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e992a2a297eb7e63f18200affb11f5b8d941a3adfb9554f404f65c8f28dcd6f9bce66eabfddfdc6d202f6f1d33314d0000000000000000000000000000000004ebb686b17428342097be1748fcb770b75bfea70a79316f3840bde2ccb133c475d5d75aa0f36cbd80d38397f53376781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007875bc16666e6709dd75b187719ec3bf2dea732b3938c7adb37771d6ae836c7e4640389ea67219f971929710d1e7279000000000000000000000000000000000147476ba3301991e9f9a99cbc4345e70e92ded560418285b7a8a067d965964b9f7972c86f3e0cfe41d502d1526f34d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009da21077f1534b46eb5a09a3e3efbdbe951b9098d803ebccc8040ca6d6107b4de658c7fb121d31dcee1b7f5d3fc3258000000000000000000000000000000000b8a0e07c99803f312da487e062e79ba223cf14dd5fe9c86cb3102bb6a97445c57e21f7f34415b21ff4b891d396cff1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1afd16790c25ca44f7c9616b7c4d58d7d98b3cc90404290211ed3bdaa7570be4b48b4684601d0178e031ca6fcbee1000000000000000000000000000000000130f7575f2178db4e3939cbe9bb6321cc59a143ee65ca06241c19bd8181b3fa281a27334307ed319336ebebcd771ce3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008febb3ce1404a784213246520299c1956196c98aae7a2c64389ceef9d9e8e8d73cf23c44f9aa00e4eca62d619940052000000000000000000000000000000000b4ffe3d6ad8382c64d011440c48d3f3ee5c81f0e3ad363cad047919498199758dbe01bfdbb1380ef1ec104a02a2e9db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001392960b7e8732af5ac56923e9ab4d1e01cda0429eb84044226d359e2ed726079e854e91e5137b481accc8cfb3d2179100000000000000000000000000000000061dd271bdfef68c28c8c387c7e0ab17ac6f595f601b4ac416e3044c29486091dabb00b926268f222b763879dda604b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a87046f2d334c3bebb0e124721acae080cfbd94b49e5bcb5b348dfb3a2621f5a1942f879a2cfd0350fef700328ae08c000000000000000000000000000000000980b518b0e5d3299427d9ab709c3c6e86d7567c483b4ddbd2bdfc0f34990902a20128dcd4781d056a3b59ef993151251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178ec0d791b7a74d4ced12970c7a57a3b310557dd90a05e7d5044c4cbbae3461194738c990a10c2faf2d84e82ad939fe000000000000000000000000000000000dba49d8429a64cb503746f41c24bdde9776c930c1e52049e9c1179f23d2b3532c4b754d74f05619b94a642f007f84431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059dbd83f88c2321dad43bc3d58020965110cf77d62a3ad59da908cf4923717e0990b9975ed14fc08a954457208d6f26000000000000000000000000000000001512dae817be1fdee54ea080292d3db5088af28ca66fac122eb6ee858d20dc38685363a8d08a9a1161cc120d552199a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019df95d91d2c55546bfbb5706f0cfaeb25f39a50500fedf4cbf2f5635bc5055aef8120f05172af7a2065bbe978baf2400000000000000000000000000000000146917c9e5a47135b6c6ab1b764880fdf88fb64d5ea4021c9b692213668f902afc89932041a2c917f2829f10a5b690351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e8fdef9cacdbee0a23bc17c40943a68aba8f8d77a3a5f9f326b70c7efa93ee0c7b100d04529dafbd256e6922ac3f3d0000000000000000000000000000000016d765cc7fbec579bb89402e553ff961d4f19cab4fdb2a24d9c8862146658e65d5ca536457b0bda73ac8c3056fe7ece01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001684699568b7748c179602148c8ac337fc90124540c6732a58ae320813e4587b1926bc729ad0f4c1902a0824ea664a8700000000000000000000000000000000012db1c6ac720a531b674c190354f706057fc18b6de1e7c7b1439cfab52c696efe4194dc5980489b2ecd7a45ea0cce181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015df458d1cbaf2d9f9f2cc92e6f266243ffe71505c2d0267164a5da78cbf2c2d0d9e8b70d10e3a254f7103f75e4ec84a000000000000000000000000000000000cc409c21ac675b66a3a53e90b125a499dde3457d07d7514e5757e3c166d40a77a133597eb2cf9bd3e506e8ccac84c6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e399b33cca2a2ca53b01b51cd1a657c729c711e9654cde8997dea0408b1158e5a269b1ee419767176854c30bf2aafa000000000000000000000000000000000305efa1b778575da8c5d116844a290b288ab119635d6efb2badf848f17f218ab1490aead65940b648d42473c2e29f9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000146ad132049e31f5674161eb7583e753a0981c89939c7a2f2467558a326a816007bf17bdc14a3f6d2fd21f77cf4b8516000000000000000000000000000000000d70a9fc5663eb6210b2ef7e60d6ce450f9776cf4d5e845d46c99d158cf9474ef240fc7cd6d3450b9bd60fee6a6cb75a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148da33cb66c0bc4d40d8da6ea26282b54886d266a0a2ebe5b4a9d6d43bf050e5e6f4a6a786d2c025b46ecd67850a33a000000000000000000000000000000000ee3cda47faffdd87ca9f985947345cf858f4dc3ff75707ed18b80486ae0bdb12e4ebea73c36cdc98e40c1c1c697bbc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba0b7f8cc0333f39d2ad13b760b12b6842641bf744fcc581fdd8ecb0f7f4991b9f2d272a2c19b688bc22f0504898f190000000000000000000000000000000019e5e5728ab067ae4912e188eddd983faf652bf98d02436455fda76640ad94be32edf17aa7c65165d9aa07a0dde0ce511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5a5fbce11e265d90110cd27a8a5dd44e84afa9b47b202d59b2e2494cb3421acd8a5c9ae626f9aa99119a0a6c057c3a0000000000000000000000000000000009ac6c7cf39ad858e884c60a48909f8eb8c93772293b672536b12c911e63c5088a025c5d0b651558c2ac4fdc85040e7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b8a3230503bf9eac8fa142e8d9590237d13f27243dff1e55329268ca81b9c8c621acc1d749072f7476b9b6993e0e3e000000000000000000000000000000001803f22a509c5b6f1e42e9336a9699acfecd62e51047ff0fa34edb29628814733710fa1ceb6709eca69f796ef747fa8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001441897d50b210b3ba99ed0b52c1f2cfbb842682eac8deafe16e254a9fbc0863c4e734ae3915b64ad1a66ce0d9a693670000000000000000000000000000000016ed42a66f357aa42f872ee51ee6c252ebe6dc1cc0c4b1d46eeb63dd3121bfdf46beaad106cffe7764ef5749a8ddfccd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d2048229aa7ea8424b2cb14a8e5f06fe534c5a39e3f9c094876edf9cfb17c1dff605d34e6f4a6302a6913464a04a070000000000000000000000000000000012685db80e805efeb0daa21b847f1b9dd540596d9ef3f3f2c610c8f517384c96ad4fffc1e1c1b19a2dff755526f0db851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dc120f58317c5f1ac1d145a0f40d3523679d78e7d7779b5e5f7fac66394b4f5ceb61685b2556ac1c62630ad99f9371000000000000000000000000000000000078fdd01f457ba3d3bda62be7beb2b780fd4dbf2620128cb18d5e38fe20eb352d222e7c710e4c43fa8682e60a08a0901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001210389741e66f6eb55b79f8ad96cce4231b76ce7ccb0d06b5c05dc88c9c26b64250c11b50d1acf60fe4a4b2a35e2fea000000000000000000000000000000000da04e446d92f9478bbed220a2ffbe44fb2e74f5b04d0b21a52ddb5e6c3abd8a42947f39c0b0dc07c9a960c7634597e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a19ebe1ac3216d222c92e6d674d38301c2f36ba04ead61766b6ded9b399b9ea4d47c643ec1818286348f42ae46edf0000000000000000000000000000000000c42b3f4ba530cc92b4503112b35618ca22fdd60460620cfd45143b73409396cc5dfe58bda6c13b91e17b5acb76e21091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137b5696c27abc84458c8a2cd7362d348c4886e6246751c188b5a46a5873c79fb13c0cca07993317d40baf87c35f380c0000000000000000000000000000000019413c058f6dc565a414b4bc73bde15bc12fb43348533d889ef4fc276c62329462558a7cbfc55bff6555b82152343a951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006fa2dd6e3ab26bc7a44c634b052644baa4ef5cbaf452601e686a3d3e014a2c416e5997baa70e59c48367c68b293a2a30000000000000000000000000000000000e7a3ae7fb86566575087567ba2405cca2ce713057bea5d324e126a4331f3f1c10cf13075d13ae4571e372d708614ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000733592cf60a16fdf4d83a93297e9248c70dd3aba8c950cc7f6c70c782a6fedb8c1166542d2b1019bdc8c6c0ffe21624000000000000000000000000000000001593170c3280012f0170dc7d84be2676d0041eb8298269005c80c64982b16694f39dd3b9d07fb96f10ddde76e019354d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053e2edd4fb2b57802d3caac5137abc025a463479c2cae77a5358e6e010d5e26c991f0dce0cdc87b318a04b258cd1f87000000000000000000000000000000001645a1957f5b267ba8bc83843eea174463c0d703dd12ef6383cae06ec782bf60d3bc8fb110c50a52c25bf029bfb383fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170dce55d05fbd5a22c31f1e446d7658eddbddbdcbdfa8836e0e1d93ccaf380fdd0a043fd9ca9e6b814755d7f60d99f9000000000000000000000000000000001716ab66ee96de04f573410d130da8feab60ae683ad2429fcfb9792eeec1076734f4d66ce6db7d63cbeb96f3c7ce2e091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c99a2fd35fe5e0e860762d74098bd3608101639a881ac9d025f4e8b0b61352bc91ff03ab51e27293851832c1c66ab9000000000000000000000000000000000cd1088edc93c45ea7f80d4cf9693adf87871b39d5bcc514e475b5c78052821111c4260bf7fcc4cab35ceeac080cf4421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b78d29a1860396d08f7898de3b46eba45879d53a205498959441bf1072ec6e23b3cf6493469eadb9fe2cd421c76b4e400000000000000000000000000000000116b1621ca40c598fa1e9886af25e7a882a3341ff75f4146a3f79805435c6c9d516ddb681c9e044a7cce2f52eea9d7c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0186021eefa7c930d48fb2008b8c8f2458f91c08bc16216d677f77b7ec913441c057efc2490f2c83bb5ca28bcea4920000000000000000000000000000000009a6ec839758efce3ad8b29af52a450f3ef84ee37a1eec54ba52eda0e6acb2cb6e8884896b9eae94fc6cd3989f784b641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082b8f9133eccc3baee10198188d3a3ad67c311ec8419afd63e6f9767af82f24f032d840fdc14137f9ef9e0883a7b4c1000000000000000000000000000000000131a10cfec6efb1566a600c5177ae6b78ea1239d1f6e76d19b9f36aae7214242fa1796892750d92793f6b6e191d34441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159431b25e9d2fd86e441921de5baf52f79442ef0eae41b68c9d06793d38e334dc04ba674a2eacdc373c54063c4e465900000000000000000000000000000000075b2266665a3f6aa3586073a167a8403fe0266cdc6a54ec7f284a043ae62b61f402121a790cef51f5857065074c47a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007722394c50476ebc7dfce5c7937851a4a77cbe38732c9b6ef6cfa5b2314dd4c3eb7475ed1c6cb617455cee653bf38b3000000000000000000000000000000000e78a1caa5303db1f7277d50154af087989c3a4239f2c0293663692a497bd655ea2a1ef39aafc3fabc85c65870b46ad11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001901e5eccc5fbf7e48ba8666e2d18d101312ac0ff1aec2e8ddf80d6c7e679d6f95a5d4ea289b80036811d6f10acbf1e8000000000000000000000000000000000120a62ff4e9799b886dac92f119376b19be0918ad67c234eaa86b877958f1e77982054111ffb93064da85a7e5f5510c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e86e1342b517d7774620114d5b19bea3752d052494d84bc944dab2807c1999ddb023816a468e22b856478aafb496eb000000000000000000000000000000000ac9568feab0361cce9bf4278baade58b8192d4333e360735f24e14e9e0399f387b7d6aa8f3349774a23fc342e2dcecd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000689716a41dbf3b23612afdef840922b558edb4ea3d786b81f4fb5ab94ba3e01404aeb5170a5be30179977f0e019d514000000000000000000000000000000000b8bf283b054b3245bedd9f534834523af2b5e2cbea68d2de813c5bff81764492b47b955d41817d8af2f02c76868e7331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047770eb09b93054e1e5d59ea23c5f5026378f84f3a35be9f288e4d5796b1c115ace6c6c36ef74b84e3a97aeefdffa8a0000000000000000000000000000000002b52e1575c7d1a4d33cb720fc1429ddefd4b5428f96ea2237c1df3110a2a29ed1ce6cb0732f5f834164e6d97e9171521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014dc9c74edf387a46bccabc3172b46f46e9163c25bfe30ddc02c7a88874c333d5804f3e97cce2bde43627ddcc4cfd85c0000000000000000000000000000000012c7c98ae66f4d6977abfed3460a11853f631524481d9f57b75b7424061a76a0d4cb8e7a6c9bb03c17f104a6e7a271f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139a42b6e16eab536c4d27ef4f95abdee9414324f9dcc9690ba6fd53565d1b1da9f211cdc4a60bb96060c030243d93370000000000000000000000000000000019cc3a3e001fac565940b331430843203469c17af9d2c796f424d6c849dfe0bc03fc6b70cf67eea2aaea4626bd2bae4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011223fd60a880bb259554cd98c8e11e7310017c16d731bdd15b1cb7e1b1385f44fa5979a60b97ef1356613a81672a1290000000000000000000000000000000012976c0483c6839f92c5fb702c73181d415fd681a5f3a16814f45d080aa9e0b8a1031c92152a4f8a980e0317186cb0481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078753794fdb85cdbea4cbc74891a7895624885e51d09c24358f6171d5fdc8717ae5ce331ceab096b88dc7cd4732717b000000000000000000000000000000000fc328c7422f0542defa870dc968796d8d063f448bd11fe6019d891bdfc7f265923a0fb1fdf475165e9235365f72c1191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198ca1c512c1312c33ed3d95cc65bf9c3ba58bcad5d950bfd9fc4a24fc271a715d665813cd34b15abbe1d45add1b9986000000000000000000000000000000000a3acc0d8297f302a1a336fca51de16e8eae373499b7960c7f1e81ecaaa8b5ce9a9b540a61829c1d6840620660b5c00a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2169a37feba05c4f3cb6e8bce5e1fcd587bdbe87abd58f66d6455621cb1c8027bc3293fd93185483f8aa57758e2c39000000000000000000000000000000001540efd6ff350d53841516a5763ad2257ec1bb880cbed1c6235df6c9cce5d49a429b7a12c5735d279e27a0615caa2eb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091009c5a5d3940bc98a5fa1ddf195673c71fe86c5103870feb30618f4b29b83fd118104aa21ac7770b6dded4904a9c80000000000000000000000000000000017f8b697e9b057993be628040eb39df0d77aadbf4df36a6ada26e0dff9c716f00ec701caa37379a504102ac57000a3861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002b43018bcf395dbcfd6b465d0ccf78a691e389ad0f9082c00fbb5d7d2299af268f57074b5d7f72bd8edce35ebe592000000000000000000000000000000000093b938a6d95277d711055b5f2ac39db305afaaf39aab26cfb6d00f04ef33e4df62d555e47a0021a3ef80da778bf58cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9f958aba08e01dd28f62d54b8b1c37653befb36606bd8a18053d53b6da8d751ed984daf5a4b9d19a9de65f936fc54e0000000000000000000000000000000014258f6b0c40cbc332bd980b0e781a4ce62bdca790508a19620dc11c72dd0e81539e5a9a083b7e5e2398e735572269321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d734564462983eeca9a7ca5c3475e8746ba2d197bc06812f79259518b1ddf2feee452f80a5ec37f007e4ee03668cc36000000000000000000000000000000001970a2c52e7195d585d49ea982a7f22fb0a2214bcfcd6676452df9f4e0732ce4128ef19d2f1d9ead2adf913e8fdf36ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ff274406abc579fd61f80bcc9678c9175cf4721ffc42dfb049fa993496a36db96e6f311ef64244b717c6140ca1f45f0000000000000000000000000000000008fe505adbd27a4a1996a8d506d2eeb2dc1beb578d4d3dc881d1a7bf4233604919822602189cdae7888d4f139e47b60e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fab864f836bd63ca545d854e49d60d2fc46ef81b3ca7f48d3c9ece4ffc602d57aa91c9faae7bf51a494fff329d6eb6000000000000000000000000000000000e6b64d1930e4d26176951f49e847c16de5031ebff3c8a0e76c9b315d186004b9d6b67359d69e2e863a9b93da0ef8f2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da15eedc5a9f943d548f98506588fc4ad8ac7c4bf54f6c137ea29e9facfc35d3012322b086594412175a1edb0a2a3f0000000000000000000000000000000000d559c4dfab7acedd8dc97230129a688af4e874e43281b4ef7738f2075d7f2a64a10db1dcadb3f3e541a4c3355d198fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000508d39d74e7718e4ee50bc29a651c337f1e1ad838d68b5664c5da58e28a4754394b1b3dc6a298e7febb2e8bf4c82258000000000000000000000000000000000e605cba8745acd1629333d24d20e188f0edd646fcb525fdb74ea8d860fca66cba5f85d7d924a21993e8ef729b0a640a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a86eef6452a73f29089e5471fd1c70b9abef3968a6c52e747877b958dd33de9b4b51cd617204dcd4b4765ee35150c2f00000000000000000000000000000000092d7edf7866c59a58e9a46f8a644f2d6939ace882dbb6012f1ea6b7c45e2535b8f30bf2c92b3974c1c6f46e545ee7ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031220713282162fbc06d1f0c907fadb00f4d8e76cc1d535b7b6ddec53583e2fa5480db1c5dd3744cd10a2eaf7373029000000000000000000000000000000000328f9f0b607caf0cf344f010cc01a6619b53c6754b1d69a056dec33bbcb935b5fb30a9a607d5a77f32ea352cd7281dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000095f0c23c723c191343232fb94f78429c0b1a4358a2909ddbc0fa1c551d49fd9188d10d656a554a9502fac1c4ce3075700000000000000000000000000000000034fe6f5e96a53036bd08b703906dc036cacabf7b88e808fa20e4eb48b192d1a68b327e12a3fc01ed0ad228b3f6ade9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001530537e6219752ad593cdc36fdc341487980c2fa4b2a222f10d0881620238d06dbdd40c4d1455c20266f659b53db0670000000000000000000000000000000015a3ee553c5670805471330dac8606adf848a1aad3b3285b07bd701894520c33702da3f6bc245c60f1ada98d95eb03471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000944686623548e4027a3c6349e6491b1f367fd879bde5ced04877437cdb079a042ebba2624aa10f459b858e5b08230410000000000000000000000000000000011e5a2042e3a687393495f96800c5e2d611c31771bed906a1ea14e85f2572be15614c4bba3af34630b63bb901a75ebca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001290272147436fa476d6ea60c005a7d7dc33f1eb69163cc2a71602bd38d7f4ad38184f4e72bc23935ecb798d368c641100000000000000000000000000000000122583b8d15ed0ce8dde481b491ade54f75f37c987d0ac6afb2098e02c84e37429e36ff3172503c97bfb4b5cef710f461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fabe8fa751bffba9a1d2971ad62adadbaa6ad86d0f5a26a146dc2f5778aae36f3826048e4a195f1c8adc2b1734992a00000000000000000000000000000000149f38eccc7482a50a62348c1582b361fad08f3f51dff7e62c691a27c55980c07cbe7bfd7c0f9f4fb100d0bac78ca5171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001656ec662ae7a60c95f37892deb1fb7931c174a92cedba1d3704f0d8e43b96a485514e45fa396d91be8644b4c23f464300000000000000000000000000000000113b12e1dfa7b996851847c92d3274232ce74a4f800968cf5595ad10393a78b7a4d731318da5a3341ccd58259748fb1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000956cacb668658a74830284df5b29ac22496bd202cba4132f5da470cf970f1121f1cbb3e3140c51cfb92661f797170530000000000000000000000000000000017a5a7a5fa41d93956d4c6bb3531a56c1d86ace01b8a0c28f4b65c56b02729aa3cbf60478935042b56da80a1bf655a3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f30d40b6f20887eab9cd907cee1a1e68d493e9673e44cc978ed0ab164139590f6b322a65e3cf00ac454f3ad1b62d1790000000000000000000000000000000003e2e7c24804091d180653b4159a858be58efef7f60bbc7dc82ab1647c5e9878239abb29b0302f4c9adeaae8898908131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000632e38402dc913861dfe9884a7cc7f7d2fedc72f96ba01b2509c25ae19d59102997d5d0b72c37bad2a9b58b4b3b6fd800000000000000000000000000000000104714d6f472e37d079a4b150f072e9d41789bfd0b3756aabd5df7952310e5921eab1f68565fb19014ba3caf44ffcde41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccd99971d40b308d1d68c1adf95c49a47fee69d0df2da72922021e7956bd2b652192ee0fde520d3526accfb61c042c00000000000000000000000000000000000c284c2a540eed2424f9fbd87861db5663aeed81d37d5c3a1cb54136549f3cfdba482ac5ba02fcf3a3124cae112751c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007835b602011904ae2b68128a96f4b6f709c960c010ff38df305c1f2aacd7a06e6428fcb1a5e91b348c84be3ca06a01400000000000000000000000000000000073aa1945abd28e200c880d57bfb926259623bfd24f20477973bac419399f09086d9c991ced3b66ac46126276d68fa7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008c2d71063a235692dedf9de76c042cf205da9d677b70e0caaed6a1d940f4231a7cd0e1cdbc3850e02c15ff0842d80600000000000000000000000000000000164bcbeed2534344dcf4de0582656e9967ca74baceb2d4a48f3671a284d6c09a4ff9fb4f00dfb236423476d269e943f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006c178e3d7b6895258014039ba7334a88ce19281878f735280523a4c94e665af641a4f17f15783d1c04026f4df78d12000000000000000000000000000000000484daca265f39a00eee8cf1e343382a55d851e3126ae125f344f8205999bb67f0ad099282eb1dffa8a6763e38a832eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c6a6f0231378bc28813339ad49ce2908b2ddbf700407352ccaa8c7ff8028f81d73c783a96f64708fbf9c8f6560871a0000000000000000000000000000000003cbb53b2a9294edf930e644563d4f0e4138c8463a3e0743f44b3b29f290be253f7bc1fcd10563f1b93972ee85d902971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b04396d49b3659c549fc5eb29cb134483a2baa8ef2b9833e0c58daa172b45e2f25214294411fdc09204a10193e24b6d000000000000000000000000000000000723892b5111e4332a2d6421a7d37f019bb1ab9da612a78044eb391cae0a9eb1762db45874285965846173abdb4933c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016087fdc8f38d75ec25f419250be821a4dbf4e0abb393e0629f2062864e3aae3ffdc54caedbfb60062840170312af0780000000000000000000000000000000015d91ee08c56cb73b7f9e19aeaa890c886f7c851340f342ed3e7822bda49442e767ecebf341bf17bfeabda7966513f721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc2ace7304eca1ed0cc7b04fc2188641618413940fa42ab0c2b8b9d934fb1088a34461a8299c75da37aed000cafa2d500000000000000000000000000000000154dd78d7b4f72af194151d628399f9e68e8cbe8a5b184644f6cda2299a31c5d49128dda0463af8fc17ef6dd8e6ee5ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000068920a256141bdef5e1b2722c4a513572ee5b9dda923f568a2b6c079cca1345196b0e2d4777eebb415c3ec63a73f1740000000000000000000000000000000002e605cd7a7c939e330c0a6154017d445c699af448bc6132bdec999a01c7c64f383db6f47ac2e031495460d6a78f29f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d88e636ff291c890d471d7f4f0c05ae0b980240c330ed06488658b6de8004e4813e7edd5318d8c48d6ddf31c0ca2020000000000000000000000000000000010d6a7722680a3fda70db776c14623f86925ad25175bef333be2ae10ab2bb00a7d4dc571936ded57bd33d999a6fa36d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1d27377b3a4b06ecfc4fc01515ab813323709141bc9bc0e9ea62a5b722e0bf07b79ecf5f7e0a8da7e96e66c68f891b000000000000000000000000000000000666737d4356c66d7308b0dfa1fad87676da2e7ff51748092e46ce373cfd823500a44a9998bd295ae78b997ff8b69c9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015111657d70d3892ccc6c1d63f970c3c5d9b3c58c34b3f685c1d522c05c49ca2a2982efcd6936a031c327e891fee61420000000000000000000000000000000010a4b9a34b0c56715c4547285ebc9e0e7a3f1bc4cebbb91e21b63018fbf19e04df94086dfb4f3fe7dcc48253d4bb71161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058673d76fc9e53d646add5a3f870d8c6ff0f86b56bd44106a33cb8ae2e8e7d2acd367587a3f286fc88f250733adc227000000000000000000000000000000001160b9af3915e07d7ee7bde6e5dbe9fa4fec6f0a98a1a12a27b7c0169bee2cc768deabb37df5e94a087bc5ec09e6af371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c507b3b3911a1b8ae48d55e676bb202446171993ea93250b782c0384414c7f87d1fcc1fd8d9a075fe6e0ab5d19467b000000000000000000000000000000001388b0bbf1a4a7fd35b187851fdfaf3d4c24df87379da0fb846b59fc81259c4294f05756655c9378b758cb1d643d54341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b682c786552d55edffacd83fbeb3368ebda160cbd1db8d21c78dc55ff410ad24007a2c5183bf4eea8f4a5d2b4b98569000000000000000000000000000000001105f1de1b1a48956f54fdc89b952774e4decc9e79871bdac5acd4cb3c6e48d758c6ecfccadb66fa89ea796c475f96b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a31d1b778deffef6618aa9d215b7be6ffed3979dd1cd65ce89fdff3e35265a0eb491cdf6e19a9646c5251bad5d14c0700000000000000000000000000000000069fccfc584c8331aad1f327b5f292bd8a8c281828ca3fb8879bfd94a571cc587affd7f4678b82bcbcebcff01851ad021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f5dc0a3a3e5021968158c9b67f09ffbe2bcfd19baefdbe39910545c1d55fed5758af1dc1abf6a87a298a70ed1cab54000000000000000000000000000000001419cf68824b8a3a03e5316f55540d13186d00d817557edbdc5e2b1ef85033faa684ac5e31ae0e3f85f7f6b50d0a577e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012464d3ed71655e9e810e34f41e54c2e9409231237e320643f15aed9f33e837e67767b6bc7c733a34ddb311199cdc57c000000000000000000000000000000000590a5c6607aebc86ae875cbdac3f99bb452aab41f4d134e9ee1ff1f0d02abe194518d91d81de33a0bc9374a114f7f751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b6508dfa90f3459ac9a7f0700c34885c3baca593df3644b4f54198db204729bd6cec39a12684d2cc954d199fcec244000000000000000000000000000000001927d9092c5c8273ed994380e6bf08918af07acf1a14d3cdf8b7970e1103988e8aba0b99f72e14413071441f7f5d201f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1aedee3270b9c4c20f78fc957e4c487aa5bf6ba165780c96e895400c8ded33e7233b75a2ac16608ddb6a673ebd508f00000000000000000000000000000000116f6a6e5870cb17f44af54c1ca69dd97f0efbc513f521263f52e4ce4e3692d01ac6420a797c6296dcd9da33fcd793e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c87dd44b0549209b8dbb9242d5469c77dbdc8fbb0d3c6cc6dfa9d89018ddf459101e85fb9f568adbb4d863587aa0b6b00000000000000000000000000000000089e6b7ac9d6f696e129337762e068cc61e5481045b583149564de250576c025bedd01fc8a59ff3deb66a781c10dcba61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000717a213568431157521a420adf4e66ace80d9bb7ed7e87ff8c8412d7d7ce9c399aba9c86e784637683f40629603fc3000000000000000000000000000000000d9fe441873ed2e642b6fea7f025eb4f016b5d43a263d0fb5bf46325b27a01bc362297c217825ff462e86c888b4ae93f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fb84ee2857a6925857a195e4f7fbde27a94d8d58170b9fbd412e17080d04bf60cee58f27b283ff38cea8a87cb36045000000000000000000000000000000000264431ac58259a6637e31b60bfbb67deb8a704c0ecdafd9f669ca24ff246b67c8900e6e4155b40c200f5541ca28ea791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143c4bf59c0feb30af7351a5cd57035345dc95eb3480c28d84c1fdf3f6483b4ea59a8792d4b508fc0eadca32a575893d000000000000000000000000000000000924de51161a062c65d903bb38591e50a9e9009c56f3c01fa53052a249129aa37917c285c48f10a2985fc66a7ad7dd141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e35032d2b1478f7d3320aa332db52f51c6ba8a73022751c4810ed080e5557cf8f7f415ba76e197cd6eed53b8e2993340000000000000000000000000000000018108de6e1cb75a85f3c0722ebf2f069aca9018bb3a56d1581b93b3dbbca8f799f9adf2c81ec475e6f4c30653e0336af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001372cf1d2b6c5eff6664fccc9de01729ac77995b63bb24d1c07bba8e909f7eaed215e1bf75c8d2122ccc4f66a0372c380000000000000000000000000000000001c5b70b9025863b2b31f3e14c38dc5f4f1591b21853321106053fdf6b57008cea654ebe0265420cd8a646b4061317a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048c72b1342d98b243a074068f028eda2565c543cb76200ed141cdfe1c162e075b3f404c2efc35e8d9993989a29c9c090000000000000000000000000000000010668156632fb5e263a3032c917c1836c93137ea4adf11420295d09d39000e293205f3a4a766bf6f128410514b6a47e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040bf0af53dd37d037dbf6edd791f299c4cd5b7b6df4571b6e99cec7cff3e4a649738b3a81e1d82586cf9a7ded70f31c0000000000000000000000000000000015fe8ec6865e8bdd40a47c58fa54072272636e0978bcb8fad1a88b4a5a6c88329ecb29a74afd74f2e3c9b7ef89d2b4441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001271f98776dd76cd3955d37fadc193ac0627e9c899505fc9882272b19d1d47dadbc44f6e1cb31cef63beaeb7e5ff5ac7000000000000000000000000000000000600dfd03e8c1bfe3cfd6e28696b901b30d5d4e9f2633d3d11be0aa83e08c4887833e81827d73c5dfc59e516c0d85eec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160314479b4863406cc1617c4e4c733983fbf47f3920df21c226b18c24b242c3b4b5676d55e127cbd5a35ecacf4cee45000000000000000000000000000000000cafe30a3ba39e04f28692fb36714fec7e6ab53439d637a6baada2114c5e374c440ffcc5a1d9f5fc9f0d3ccff8f20d001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b831e5f0dc0fb74757f8253858358e2d23acbea566dfa384ceb03f35001d618a0c72c8502633185bfd0b4d7d1fc6d0000000000000000000000000000000000f18ed9f7b1379a9fe02ab3c87bd5ce2881a5ee891b7a7f0ed80ff6e8e5438ebae7ebd146af70d958cf4ed734d4aa1111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105b14455cfc7ed1b92cb689694bb734945a0236dcfd54011f1f7c5b79c7d8a169135ba20d866274ea54a254df39c03c000000000000000000000000000000000ef3659e9fc55d71dde6d369f1bcf5cfe0d180d0be6c51076362cdb762d8d0be4b4f3acf49893666b78f2d7b604bc3861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0388b169e5509e42219f1bcc4e0f429c7cfe0688d23eb74305004b51ec5fa32d4d933a29e14d9bda492ccbcce604180000000000000000000000000000000008b59a341aec9542a224772c491c666a723c80a55241c68cad31c8d535bfb002d5cf6d85fbb5cda55dad92d5926d28601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a6f654fa95133f5b71758244ac30e66352c6a73915651f95792a85ef8d343e45f5537c5fc2f697ade2584eb6ae5a700000000000000000000000000000000013aa828d78b8b15d283ad0db332e58967c24b5ded030dff7ba7cd24ed4deeab08a8747b2947652b855ca10724030b9841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000caa963604cc8938cfe63e69c4caafd2ba420b778232db1071e1c831812d57a8b239b00d09259c4e0cb14faacfad72fc0000000000000000000000000000000002d8bf1d415e7933c5c5f7dd46227f2c9a7c0d88f58aabde71e83052e7e09d47a74b4d53245a2756487549440bc859191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b712199f21c725364d82ecfca7a6d9ac8405681d904dda9eca93ec221a15f4e3bb471781e62c1cda29272f7e602af2f000000000000000000000000000000000f0a26cf0a94f2ce9bac54c521b6d8fb6cb620b3f3e177b8ce6eae08b85e07268295c1a4f810c6e18fc2b7b20c6712901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037ac050e2be964112dd0ba5fcfe7eabd7bdcbc2a8bb2dd84175b844b6a5578ee03ab41d8acb073d33dcd43189d4a5c20000000000000000000000000000000011e93dc6bd54b85e1c1e4a21edf71f3ea148ac31dae7f0252016e9d56451624d0fc5c8b5fc0060f43659c6c14bc0aafc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b4c481518b7d5891335cfe8d081f9faefc90c9be6619ba1dc3f8ff086c6bc76efdd5c9a950208ad3d7fa3bd3a6f6040000000000000000000000000000000017e10197671ec37b013c339e81b5569b64f24ee138b8084688ed25fdb7f92f50a5d39adde9aff81ac8ad2965657e8e7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008bd328fe8afee0c4c9a2348c39e09cb6ea2564da01ee5bd971f04a5ef615868ac6fd571d3610716dbfba2761993f1710000000000000000000000000000000008bec344e45d27151e904b65ddcce9e51acc3a215afe8ea191d9254eabf4254b38b7612c62f8c96b7f152d8b30e2ce8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125de9899d0a983d9797a44df5677d641f7d72cc7633f909188d46beaa8134460c5aca8fa7dd2c370dc50c06f161fe79000000000000000000000000000000000ce9f83fec4118b16766310a518af679d8e5b265918472a68f9aa9b24b3e8b2d279b68c7f0031205ebd840e0d1fb27041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152e94fb80bfa6bea5ca01d201bd02b9878a717f083ce75d908f3f10b255a07c3ab3d25b5d51ff342d7eda1760b56f4b00000000000000000000000000000000046b2ddb20d395e8babff7f6a69c18e7fbfa10cedad4688e9ef90b0da41674a348fe2f7e641bdc5e27b8b29dc84fd4251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ab6fc3793e1c72ef6846d828b13becb6cfabee2d6ee6bc0ad9e9c4daab2d419dfabdde65763623f540b75075c9d879000000000000000000000000000000000b90502647c4e9204ac24d207c68570050f9a4bc9253e4fcc840342c5372d138c5cc50d1895970aed9046097019c32ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153390aa01866b9354f24d25c1206cc36c25e1c04ca1c3bb0e57b7487adc700ea082a448232b8ac2612864eee6df4ca90000000000000000000000000000000000b695303838b83839019f4f2167293f22d202dcb6482e379c6cccc6fb073dbadc7cf7105050edd85cd8092613df7a7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b159373bc1a70a2e189a1347a352d5076e3f1c9ea89c52bec1cf9881e6c31e6d6f7fef2a3deccff421cd4645e4b7830000000000000000000000000000000000df52d38438182fa2e1fd4666bfebedda43566791701218ea17baa68415cb5608f602938e20984e897d207c73b92f5e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dc1d6fe9d847204202721c0eb12197d24fd0542923708304afb8163af9479c3972dd1b8dc5b35e3daff34c4405f7ab000000000000000000000000000000001739e6acd835faf97eb98a500ca07e2d0f0b5ab334e7db818025b30fa714398c9bbc2ffa2c74e0876171f3f4cd1fcd241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2aec119878a178821f768710f18d9494247567dc41fa1fb3e8694aeba8ea825da4f05ec7092fbcb2a55403ff48c7a30000000000000000000000000000000019b25b73eb310f57f8382e0fdbe1ba0c140e9c1f00da88be7f3316b08c2c0bb08b209e3b11228b88b8a82d77c864ef231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000604444ecf0e9ed667ef886235bf7c9962440168c34f6e0664cb2ad2a5995f252b39c4fce4c31af33e37eee212a93e26000000000000000000000000000000000c3b733c51c9fa047398c27441ea967f3e5930ff97055918b744d75e23565255d6aef73b2e1db6f1fb9fa6f21ab460391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be377d4e409363c98e5e36083baa1ab3bebc319eea62c64789f35cd775834a85dd11ce04d70b96e79f43dbb4a5d6bc60000000000000000000000000000000011e67d3f0a725cff5de9f5fdeae9ca53eb6f5c3277cc6d9e31fc11416c6154361549f6317ff2906f35ef045b785f13341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f826a48f4ada87b6ba8b6c524b7b4cf23edc925b89d75e6b6ab8c90ad21a78d08f93da8f2c20d66a37d5bb043cfcbd00000000000000000000000000000000040df76bf9104060824b034b908f3d5374fdb2adac578a4624cf568400e2f8418905b01092982489d5434e963adc9d461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a7a33f22df1736262f2ac2eef284c2d5825c3ffd51348b61fe6fb650e80dd3df835af1a27b11888313895f638599110000000000000000000000000000000007ddeb304e5a6a3f4c4c82901bf3a83542f05628a98856930b1be62bc37e6ceda67ed16e04ec954dfe4f578ef18fc8911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd2e2fe9ef5583ad56528382c038b49a3981541933df255fbd7a2861dc10b559e3b323f0f2cc4e38169fb20196ae1ae0000000000000000000000000000000003daec0bd12a57a806627f1cfe264def8e9a2c72366afe7420e97f634157234262061339bce8d2ab725209f17f4d03441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010660129ccea69597825197095855d741dbab60b1028727876c88a56ad2fd24bd0c33b0900ab83c2dba959fbbb6dac9d00000000000000000000000000000000063ab3783b881ce28db2ec9ab55a618955f1b3e26938df9b72550ec5265003592778a7e095e338bbb5678dad9a8594db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005aeddf16374baeabbc83ff05cc4a0c01923f25dea8d65424065952d66a32bc0c0e679f4d5c86238afdb320c1708c410000000000000000000000000000000001751433832021d52e14d64a9943bb8d3d40c24d147cbd38a660da267383677fbd3dbe96d80f6645b25b46e47c222fae01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001616336604c8c3960c6dac6be82ad787f1d33a5e40d07be8f1b1c19afd36395373e3db77317a2a39ce761951d1fe82d1000000000000000000000000000000000d1305a2e34448b39a2cee407070965aa39aafce53de8fa6ccc66c0821dc178bc6f00e094bbaa0d24172bf8cd847c0701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2b835fe80fb3dee161ddf7874c6e9691e5c13e4fa7a1e4fda44e20dcffa495b33bc6b615d6dd3715b345fc13d934f1000000000000000000000000000000000479971b28446d30e658660625a11d17095a35d685d4426877ec51eff33917359b2c7614597fd6ef2a9cda4caabccca61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001888b705b40e1a7cacd6ca8baf8977220f603ad64f2b57abbbb25c3bb79a87e9fbfec39c3dc0135f567549615e8c1340000000000000000000000000000000000800cce43b4675b891f6715b0f72299724e27e7f226f77a219fcc696f6aa62032ef1fc1049d832be5a3b3d7b45658b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e2703793622ae928e8494aa5d837ed5a5b4ea94ec01e427a4c6a2af1903a662577149bc777804a175c00dd6317741e000000000000000000000000000000000381bf9394f69d07c2decccae195155e15fc778852e542fab205d936d4cf5f6e1ffad428968794bdc8308613f99e37351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e4364677a6b6732d137bb1aea847694dafde8d67689618e414c6979be677aa349203df0f60d2e33de1ab6d875c173e0000000000000000000000000000000013a8dc23c5bbe53ef6903eab5bc0b3a8f782aefb57fa6b8b8b7d134e6e745103ed34419f18fe7b8825beefd13de955c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e4fd807292c55d3876a4db9bd74c03598e7db9729b1c4da18aef3d303ffa99e90d73182d7c748faa44d069c1f5f1c70000000000000000000000000000000017845e4844becaf392a40c41b48a3fa8faebe05e78175065b417c669444f4ceb8ee551c57cb1d258da83b573d4ae60261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d9a9a752abc370c63a2f04807521e0dfa7823e73702e953527e0032243d72de62108649d4b59ef02826afd732d8d5700000000000000000000000000000000039ef9915972d2186363530d92a9da77efcfb2c032f2e73390c3fcd0b7301fe84c1dc69b7cdb54a3ea62a5be5200479c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dcd3147ab013428a8887c86ec72ae5a57c2bfd6bd75f46a993a085833e7e3e7dd7c1a5334821fe1dcd40027dcedae2200000000000000000000000000000000009c04ddfd3330f93ef03151527349150a6a5238ace8cc7dd51aedbfb291d6ab63db384defc7622577900a745ab60fc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192cadeeeacd29e3d3a3fb9ac024d79e0db4895872f78ceb39711dbbec0d901cdf99ec3a507c98fe22694b0b11e0a58d000000000000000000000000000000000ca9d937a9067d2ecb61d7160286b39bb0d505e771e2a9c0914d93aaa59e2d9194060527af87faf9104d693a148e888c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5c9580f28dbc989e6a0deade168d480c2eaa7dbc6806e12895627c99539fe329669bb1e42049362b46a2b25246c9f30000000000000000000000000000000008c6abcd70c9c37aeb94ae7670ec954a0760d90209f717ab6f96a5dfe52b49f2eba1781488014ad1011ef9f565bf50261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000848636be6cfff0f5c651472528805610dcf70d8346d3e5c86c58abce7f416c1d4800991d2f7d49d182265360c78b81a000000000000000000000000000000001692d25da91432b309088b5e31d217cd51cd967783d682370a26fba2e3289b1a8873f64245e6cd898fecfd473c1e5eee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a41507d677567a73e263f468a26a26d23eb1b5c3f8686217e1e09ab34ed7a678e3de57c1ed1a03514af0a8024601fb3000000000000000000000000000000001616c8a4993216452e6f90939816374c0c0677b457e44e6601287ac261f4f14f0bb8a7b5c8ae46af1cfd6ffbd0a266d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dd00e1be7a8b1e22b4e330e1838d9605a27a539961556333b2524884903af8b00b08e6335f4a307f036dd1bdddc6400000000000000000000000000000000010cfc6926f60c4f55750f9923f9998059a9d03c4c7572ef2ce79853016ff9d2be705c9e0458ed8335fd4a456891e49a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2b2a15e532956dc9fe7d1ada229f87c87406ea672edb0ce8f728bcd1cf6c7eb6eab2706ecd6f2a1d64400b9aa58454000000000000000000000000000000000db5ed69ff7f34b7ba997d33cb943788dfb0e67a07bd97d16a1184eb07cb60063af5b95605e3d1e874b9bed0f69d2bee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0d38103bf5206ad11375bc7a6df76d910f2d4f77d1c14126cf86410007201543c01447cbc4d37975f6239b35b9a1a3000000000000000000000000000000000e4d7f5cd57cc47f24dfd6b4b723b5c50644368022775fe5fef05d4bf351b842ab079bb95875eee71caa61a2445a65aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b62253c55045ed15e4d7b2dfcc71157753a225844f63160c9807927f48b9f35cded2da826995a31c5667295715b3c090000000000000000000000000000000013a8d3e1fc09bfe2e810406de651a69de748957dcb1f4950e44a2e075d45688e2fdcee372a20c3bac14c639743cb80811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001934c3db03aa24253f461aa3cbd2e759c5f7fc945c312f4658e25aaabe9ba63a69e4d8a53108f858f164710ccb78021a00000000000000000000000000000000074da0a9837f8d5245123f5e1702e289b7adc02abeb63a86582c90b18538dc01eec55cbab5a48ae64eb04bf367e91ad41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009199b28d6dbd3bf7221893ca18250cda72873352d91791e9176d2cd758bb2cb1d595d7cdf8fc0e5b99715b997c088b0000000000000000000000000000000000f25b3aa2d8d119948da4048436bffc457f586f7b93b72c9451e4895683679ddbe4746b96277a4391257cd822db2496e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097c57849901a0c8ceb9b9ab077cef030f6573c76bf3716b8cb798b644a07a025abb52484f2a42fce34c21ab6aba59bf00000000000000000000000000000000107d831faa5763986bf01da1befdfeb4b5f666c097801a651034ed12826268c70bb7a8951d6d8878cc7af537e73940081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000068dc00d547466b69ee4f046471df4483fd845c22c717d88ce1595f5ff499b1d5dcc3e21e6a568dcdaa1a32500f7cd0100000000000000000000000000000000187f2ff0fd30748154bd2cc5bb1b16d7f12772db5a238f7c7cc98646e54b0fbf38b39ff408febe977cad6ccfa02e8d9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef8e1610333a9b729ffa3c1e269e0903fba19f327840f94c5752927f9f1347642ff69416caabf7171a204e42c429d90000000000000000000000000000000001068d553146250b78582596a8c99a355fc7f891646e5d95a195e034a2df9fb57ab612d5bbb6e8ae3b7f68b18f10e08581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000601c5f1d30347ca81553d1189938116b0157c73b0972e54c9a0d9fe5ab48f543295a0f900c3f34c514e786701c8c3990000000000000000000000000000000003ea8dc74450579adc957b24271959c737bbea600cc269540bdf4c9b79f8295aeb2f8f5db86e03ebb33f3399e6952ad71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d001d499b54e833cf670a4554a4a877b643b9fea5e0bd7c846c373e79b7bb0892c1ae75f129837733e647d933ebb0300000000000000000000000000000000141e9fd4b6868da372a66b71a75304ac3a10b87098fb8b2540980dace4b6f579da5eb44bec509facddea09a4086973c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013da1c68ea9ae18057a9e9340a6cf150071e976db263e884b2c55e5a09b61115007956ffa3827eb85562ad7e9a20ce9200000000000000000000000000000000181f7e8764f46a0ebdc991c2f90144c0e9fcda912bc94304e9a84051c67ed432aca9f348a8f26074b0661c73f60b64d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fb53ed6ff26b2a00493666633bc7a50efb6a8d25f53361ad31495b2a57cb353e9b39c4d471931553c306b8575c826a0000000000000000000000000000000009efeae0f89156f2c4f32a4753de34f2fe49544a5f4e3c1f609735d7e8434b5c75389c0c8cae12cf782d7c0a858463961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019dcbc65b55500c6de4c3100df56f6a75352c38a18c4a25961298adcb65ca7610c0b320029d9b8d61f6f590f942f953e0000000000000000000000000000000014aafbee5cf292a3421d3f26aea44967362ed455dddcf4ed55fdeac84a2d1d1fd179e1129f994927ead0c30f6a26d6101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058cfa739c2d537470b49076a830472ad807226b52a9bf07e84a0c39de38c01f073e2696290891470eb2005a8737268f00000000000000000000000000000000191ed3ce208b6bcaab738572987928f30e1f20372f0518f2c7d8c43766ad31393b876cee074dcb9a1a77610ebf40b0411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000169d563023e0a496ad95f818457baaf0316e825d12e69afb2b5c0a6d63e89f188aeee97f06159a479f14cc7406c3830400000000000000000000000000000000057522c0d59255b1367797021793a812d77ca53f137d46587528901a922505b3f59baf821f9a239c1fa51889c92f29971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010bea5fd2658aa42ce339c8753155af12ba8c56f10719d0d3024c425f17a262d2189a1d12ae0cd91b6a138609a0aa6220000000000000000000000000000000003b653851754e56e0fafab7ea79da8f0d32793597cf109d49d78172df33da44e8c7a7bdc2b7c4f87ba30a262c38783a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e1dd9b39c8dc38d1c42f8724239ef8a1e0a429a368d0dfd2a954e054c2520a2c47b816b82fa0113827bc1b010a608b000000000000000000000000000000000dec3ae706926a4b5412aa1b1792f39700e39731ab05d2f3769499a0e6b2b37b1ab441155d6402018cfa564fab6595831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175c22ae8c763ad3e98ac4e8b1b595b6bffdae6f030c8e4e9a1269289a129313991e842a8638ee56844633387b4016d600000000000000000000000000000000126512e580bb64c9d0e2b2f81140856767b30600f2ef4e9f08b1a88d2208857c6c140bd20d32f82715c2edffcc4bb4c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db15ad1a06f77c6072ad66153332aae1914cd72c1d0207f1c711582d339944ef2bcf18a4bc1e247aaacad2fd4cf2abc000000000000000000000000000000000f426f7e706b7c12a8d5251a1cf15aeaf439014046fb6cb3a93c557e2d9a17e1b7d77dea0c8806e69337d5c4c97e8cd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ef5a2e56769ef864db536b0a6b7845a14e9554b7bded3118e61fa8736bea63b5568bccc00c75b027baa415d93285db000000000000000000000000000000000936f60473f9e3d849dc50a5f8382f627358e51672ff91f23b36f94d53e809c847e235a6833b24911ac32fe573b22c9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067c8ef39353039c6e85717f5cea69038138d28e5f871a8d824880e5e94bcad1d702a4288ef3dd0fe683ab49ee27881e00000000000000000000000000000000088dfa28ff418b50e704f0a92919a9d725b4832cfb6f881fd0af34bacdd7073552562e21635eec76931cdcb7e3fcadd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005526c9e42e8bd124690281c424641989c840c6b203a6f4be24d1302c8f40123ea80b82542a9254473cf62487a089ac60000000000000000000000000000000003acaa670dff46c78711cad38dd98128f849caacd734a2a043238fb840f5f58e08ade6159a378c8a95d9033b2c52990c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149959ea68c732401811c9179d7b6e8cf59cf2d81cf963ed9258518c5ffa49f9353530614daa689bd88c0fe539d010db0000000000000000000000000000000008be0e966f60eb0d020e59396ad64e2624ef6fa55069a8f7d4b576944b4ff450b00d94913691d24a87625a770127a9e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187194e63ce4888f10f0b99684faf7a65133c1a164024eebcb06f54b9064c47a63d348fb27351c3820f3e76b591952e0000000000000000000000000000000000ec000c23cbf6b7c7e691d5792b26e28e26d021ed8d8ad31c81888c62fc53d4f92a5765fb816564e744bbcb7abfde9791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164b60d378cc45ac4e45a8dd0af9bbb6b4c0b67ef5a4075540eb5c19df12062a9f6f23b5386dc206420c75482f0a628d000000000000000000000000000000000cc92a3ea8aed8041e4b2fa4a488fa916e1b5736426839dc986980fd4ea0b88e5e23c0bd18d7c0ee7624985f87eae1291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002bf43320647692469f8e05eab4f6ac97f21ecf30eca350cf90c4381a13dac51d2a851c76138e41cf8ee2fc0b00067b800000000000000000000000000000000121a9536da0957d7283ff97c2bef442d140ad8d6f430820d446c07da41aa1ec854a16a6ef19b2e0f77bb51f5ba3b2e271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d722c721603cdcb90cf09e9078aa2599f8e2cb20c08c2780a365d154140cd8a3f7ff76108cf021dcb8bd6ebc1035ac000000000000000000000000000000000e92c1fa8f90fc999b49521bcf26206f008f46ea78135887f7b6478e59b5b6d4afb7d34a227538ccfa06d220b0e047f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1a6a01fb85271eb067cf250a0aba46a7ef86dc77a5e790a5aed1befd205df5aad68937c1f07d9eb29afbf1e689eac10000000000000000000000000000000002e774fb318d04a1c6dff00ea421d76d0e7381cc972a8bc5a9f7c2a8d5bce26c979fbdbf0ba31cd9f7f90951e541c0331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000356f039f3604203ded1ebde41beb87347982ba0941fed2515de1447a08ba0ab4123724137ba14124cb127cc92be34e7000000000000000000000000000000000bbae900394d878d51e24b1aaf2c739f1599ab1b19ae2bef75fecbebd7031360f96795fd5337206a5818cafaacc47ece1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009961d8b69341b2bdf19d4268e489b7e11a03b023e39c1ca707ca568b988e28e962a8674df617f65d5bd912d0d280c400000000000000000000000000000000013d0d03dc3f5b4b462b32d6b187adaf2becb55e43ccb0572b331f9dff9f90522627a02aeb12ae0c40da260d2a7edb4cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019363e4d10d205e014e8d4dbd60ed1785455223fb9751f2900a76c72523be19dca6779ce5a549b61dd128eca790b33c00000000000000000000000000000000000f55f0a4cdecfccadaa18512f0fbf520bee75f42fde6f7fca140e314fbdef6ed36c4e005fb1492cf3331cf510ab83c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059ad18958fe60fb5e1bed46389f54e9904022c56524208c06774660406b6fb6c56f7b46439f4d3268eaeac39042a73c0000000000000000000000000000000009b6e55486829e9d1e8e5539921b188d65feb184e5db48738b666ff2b8272971b9e4c1e65985353801dd1adefb9a4b481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099794b90dd85ee7a8490dd428e5641b49f0aec14b02e32e57c884860a8982355ed206e489e5af85aece7f0e55e2b5240000000000000000000000000000000011ee8915cd6e0246739abce8954126be56f1373f4a1ed7ce07784a38f013967125a94fee3f70b33cddd937cd36bab5fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001202c23cfc2151e27f1871d4f31a71c5844714a84a403a2939e84b878598d7ea7822bf0e7ec3d4505495c6ddbba13a5c00000000000000000000000000000000156c7d57d719d3a26fc5a5237492c0561a63cb8bc31e31bf2c127153b885108dadd6c5193d2088db6fd185e6dc8612231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bfd8240773277ff84214daf2b275886e87820009a5766feb68c4e3a8ddc743589efe5ffe03c6d996b6e3b96e775e840000000000000000000000000000000018a0bdf3803c29a4bbe1a51dec9448172772c3373c8e9ad328fcfd10980ea2e218cff4422bb7e9bc6ce2788a9b6f143d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019de7fadf2ffe652e9c2ad8d05c87643b81f1e1a9fa999f930645e926f8ae58ec8f88d06243db0758c805d43b4dfea81000000000000000000000000000000001486ed9861114ed2d53aa68865ed479e7c1a4f66c29bd98f5c83697a7fa84dba6837f3240bce8eb5b23ad8b67e357d3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139fdac7528942d2c2d8d0148b6395776d4589c9f6db05b7cafb13ed76997d82dce83e7e5beabb21f2219a8d36c99d4d000000000000000000000000000000000673331cf6bff67cc9838e0f2fee93c96ed152ac95397519e863320d0a3750f8cbc02392d90d7a24b3f9e40fea6ef1701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebb7830093eed2cf5e53617209c9358bc521084a5f34a521b82d4ccaa95ce4e602d1c7f182836dbd685bc4cda334d30000000000000000000000000000000000fad4c66b50ffcad01d448e79efdf6c9446427732e7d2593e77a06a4d804f666429db195b4db3b5f216bd4fbba16d4101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d3323d02486ed850b0e45c281354ac2e12ce533684e610c0258116b5fd00f47d02eac97bddd1f195ce88599e3ae3a80000000000000000000000000000000018e3869e7cfbac2a62b2b2feb7df2a72c9dae59239a8d1162020c7947ad9751efc47a237c5c7da70ee25a238132484351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ed3a533aedeca6381443c3582b69b54525aff8fcab94320daf35aaf29a945311e75e75c1ec8d18aaffb0280cc137b70000000000000000000000000000000010f9b9734e3316ef54b9adaaf649761c9621bedfd3f1f7f2c183906d576962c13f2b92cfd2d69cb3e4337022fc8a41ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d160d3a0232e4a81b1a1b39ff97c1ddd6a07831318ee1dc9d2e303f97cd94d1a745c970beaa01625356c46c1d94f91000000000000000000000000000000000f9b9086130fed82a16120620e0cfbee3553750907697af3ebf9d6c3131300ca9895d6f7a2f33f968a1c4f8c7d235e8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100800e484086215688bae53087c646929b12f25d189a9fb5006f7c1ed0b661107ee46395ad7842632423449f4ebe7420000000000000000000000000000000018ff21cbb1651f42a82a4a065d463489915e003b677b12bafad9a4f4f460034278f55d5b3a3516244d5f3e2507324beb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000736c2f0af8eaea0b8fd4fff820d3e6ce3b5ebd439c303d30f838a852bb0fddd9c43996fa6347cbf922af7c293406bb6000000000000000000000000000000000563551f216257c9e38dc07686b2afaffba8ac4f22f267b154c5331b5f199af8db0f12b6b4c449c77c49b474f943b79e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb72916ae3e2ca262b6d5cb0065d01dcf5194e9df04ec7f38e0a58d19d40e4ee00305715e53b7ae568311fa8818f88d0000000000000000000000000000000009634d8703e0fd3552f5487b328dd81e01fb7c9d64ebda64a2b2debd06e18d6bc92f851cd0699642dc00b3b1f184906e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a221cb22551460cd5484318235e750b8c414560025937ebf55fc1cd1af2e911841e9a1c4294af021c903002352f2250000000000000000000000000000000002c1b0d00297e1f705944e4c1b9083d886f5b0c6cb4aed65826fa6237b554b348b18eecb1e523d79066141c5e34ca83e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010addfe3611224ec5ba409711c7e376bd3a382ee1ded2d297b1571be0b3631ab34fe24aa9fba5c9ed25599fb55d582be00000000000000000000000000000000166605242e271225a535294af4a136ff8d2978afc5833c6225c334cf34adba7874a0531bbbb918ef47a09c954c43b69e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041b6b093cf1d772eb41e8b989ab3eba4a970c3577f6b654ead56061a22bd59b6e50be7fc8a76275697a30ed06a9e14a00000000000000000000000000000000032bee49c5493763bcacf244807b135e6ce7e7f5ad24e0aa84c15cf93ecde7580b68df83e572a889c9e29d8a375870331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007af41a5c79382a1a43696b55e24ece6209bb2f16983735d56071d58b06c15d53c2c412c637f32e9ca00469e090911fb000000000000000000000000000000001237384457b67fb3026a96714993cf0597ec7497462683888ae695b2a630b76a25637d6930b48f1c9bc583bf5a71af071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000058f64f55522e1356e27f7f5a7faeb319666041ac42e4ed12cb79c228ff1fa43eb3cb8f8a412861245ca4529ed0d9c4000000000000000000000000000000000dccd41d4f84b7a8683f7737731335566d0dc8f14326de8b38334fa9446257900ac6368019b962766991e3bcfb767e1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015e98fbb4756324e2985b56827bb48e4861298c4648a87b55b807183d678cddfcf0846fb974eb39bdb1a5b6795963f4000000000000000000000000000000000a72cbc795546698b0ec3a26c9d90dd0ba1be1348a1fbbdef2ad3ebeb3130201dd67bd812328a34648f3342dfb305b761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001185b5e0a8d8fe424dab278693c39830ab5d66b11693d282f8b57a05ba4c45af08930393585f8a406616baa73fe72a1f00000000000000000000000000000000083f45e55b7c7e79e4860d63a1bf865fc65954dd63fd82aaf9565d1e0fd727e8a8f261f5711b684427932cfe4c94058c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003fac2dce2c80d2cd9d9f08277fa5623d718c65362fa002e92b7f4bf66316cfe3403d4e039b758280cc49bac4886f4710000000000000000000000000000000000cc4a501e9b3f847d75114ebb50347d5e38b87312218a91925c1248a3c460f1a1323eed76a7495074b3c1cf597626691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030a0c75eb0c277286c5437ce1b69d0427b6fbde89b02773d17da484f3a3e1464eab185aa479f2d5e4f595d0048200ae000000000000000000000000000000000cb4ab4afc59bddc19738343dc98d23f38180fe1bff8e0ceaaadf653906136fc1430cf78897fbc2949faf2bb9cb3b6a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049941a8a94e90bcbfc20a4fc6d4c115a5c0be1bff80ae599bd27a049bc45175fbaa6259ed94cc42e874d98771dd7920000000000000000000000000000000000ad60a7f9eba3120f99c1723c023d1fe584ab1a6a68fa440fe813e8677d5ddb7ecfcf942ddaed96538b5e5180c4d2c2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e277619e7527b61e542caaef4556418ea7c72f96d3decebc6338c9c346f2a26c5ee6494fd3ca70939176b1b4d201fc1000000000000000000000000000000000245f8a32bbc5ce8f61d80c6ecfbc2814deb9079a5f9250ab873ab11ab3658c8632793676c6039fec41a8de8d1c3e4181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a405f46a9221470dd68d594bcbad7109661a07617a5e395bb47628d24854ba09d559d44a2cf703b6c4b80d5bca246be000000000000000000000000000000000336ed34acddf9329a9669a3571819cd83555485fb2e06f9b44b6b162171b6e1544ba502fb5dd5de1eae3d8b870f44921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dca74a1f94c017b371b6f4c3f651da30890d23ff2b8053a77fe23f690209f1a440346a0e35b98fbbeda50242fd7aa800000000000000000000000000000000141b8e7f0bb420afa2836b9874d7a582f6a801721a9ddfc35e79b1fdc80f37a609fb68f2ce9e73fea07da05d1312c8be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000202bfbf8f87625fcb0146f86e5a615a828453bc77e4dcf2a790a941fe5ec0acca7c14d0d9141833694b1bd146245578000000000000000000000000000000000b08496d894eb75c2d5a04c0ad985a6b51faf4da08d1828a1001a15c8259547fe925d7ec71132a35ada479a6871622e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ab53b52d31517c09d460c5dd2533f2b4a8f01b0888e56f7d10821aa5021332b4b46954d4e94d497ab391d1dcd4184d0000000000000000000000000000000019150bb1262c44819aec0c80ab2a0fdac8a3ed7d4b1dc939631925377b9d1d46a78b48a63d504b5fcb3420c2fac72f8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6d341b362132f641a88dc01f886b6647cd30fd654886c02d64f0931ad4c2deca306f9e45e8089cc73813be4bc5ef7400000000000000000000000000000000010cff3e94bca625a6bdd323f5b7d89692ad1fd06e8f5f82f22e5ff762cfaf8b5fdbea66be9aa09566d7c04071567c991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2bffaf3cf09fa31ae5819c922aae799d6e715a32985a851f211d7af26d2cbd544f8f17d475d8ef3f871c5cc4de750d0000000000000000000000000000000010b159f3157361830f9241264c998dee3e4541b3cd6f7b8f38e9661b35adfa5c4122bb355df60e6cfb3def84960b7f781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001916815f3b7933be9e9a17dfd67bfd68c1f96800788fc60178d58efc4c457e6cd4d48f66eaf2c519f144e5a93e75fa0c000000000000000000000000000000000657e9217664397a47d41b000ba9215dceceeacd10071cafb0c14c2b4aa1b0b3abb6261aa09004062ae845871cc6f5081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d718e1cd30a051852e280927fad885d540be748bbc42d628210574dcc45098c2154e5520ccf2d7bdaa7e7d04b47dc80000000000000000000000000000000010881fbf33a29767c6ce25fa23a5c7c2e475156ceefb819a9e0adb28db7f1d9be3fe3b3e3df101e16efa73bbdff8a2a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cb3b930ce7ea2076f32093451f2f8a2d77890302a378fc30c3eb9952daa11da0dee215911ece81d86f79070c8db3fc00000000000000000000000000000000081a1e01184c617e11ff2df6a193c4ba925c61d49dae0762ea036ccd8b2fd0366f340205f3844273395d8537eefa847b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001457ed635dbea77a65bbae67b470e74b8ce77a1852053b674527f8ec3988b83b9f1775ee57ed7e694270b8ce99cb4c7f00000000000000000000000000000000014dd3de136b8e7881771a41f67de9dbe8b70057f54265450d4f50a9fc2fe794b53e97f9737433f4b2a1c3ccf7b244c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d047bcb8f97d04720af4ef9d4e5a5b6d50c23f86fef56772d994f760c7f0af6d1619e6b7fd319f5533e6aadc3aaf6100000000000000000000000000000000028f199aa9cbb1276fb1b6af31f549e0338a5d2456f83bc51b192f1f73951f4c5ab5ad37d3a9545d05b85b5124771a0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ed0548b8cbe2332be21d46de3dc3d24d37e4f36930e874b4722dc61c4064b26f33cb969601f1eb8c59b5cab6ed78180000000000000000000000000000000006fc4909410368afdd726702f364399a6483785f759353660bdd77200dbf64d5649feb3b4a68faffc5dea1b6cacae12e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c73c09c8b836098e64bc65102a6373314969ea4f953a1a6138018bb960845a987d8b5e629c3359ae44e509a03aa1710000000000000000000000000000000008efa599936f1976964f040a948bd500525ec147f3672adb2d55bce12c9d16c79d522d94464796c212c056f1a87f872d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e122df226e3b16b790face1dc1b3ad60422d235b4c99103eb50bd76717c54ecfcd68f99bd71d94482929161deb39430000000000000000000000000000000012e57caecbc9b97c63b11fe3cb9379d4d1d04cf382419a982751ce0ab03885cf293850c1f0b5d3bfc35e70d71e6354601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000166b3e11c9a3085fa5b0fb18717cca2f4b288a62dd1d5af870ba12aa74e08444aab8164bb6ad9d8561262a1461806180000000000000000000000000000000009e3e78e42bcab0f63b8d28cbcb068cb743585a7beb55576d481a2b57789a995fde09c254a77f4628b9401e39d5df22d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003048dc0a721cb06625c360c22ff03f00cb1671ac6f16521c734d940d55a62573ce44b1fcf4449c779836823c81b42f00000000000000000000000000000000019890ef43f93ae538ef8eefea0a3ee9fb39bdc53733da3e8d263182cf188974c7f510efdea815f7e96dcdb4c2c9629a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000daa5a8a44117ea2801f9ba6bf260d1653d454780f14933ffeca34e6d7c4831de6f84bcc9592b3327dec3669e29ccbdb00000000000000000000000000000000156eaee970da17b742275cbfd277bd9231116504a69b12c0c324348681fbc6b19647860247de6fcb9114194b5bb704f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000752af6d89a9834b2a7af7e84520b934e64dcf7546a53b68ce680c513efffb7a7c1165d6e3f2a5aa51d43deeed2944770000000000000000000000000000000007efc9650ae553e3cc5fa62fc90a86675db6d3204971a2619ee77616ffffb1aa1e09dae4445350c287a0f72f6d19e5631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017cb2c078b3d13b942f6b95323bd6f72aa0516266b505022e8a039607fdaa24c789ef3a705d92743258f1c171594777500000000000000000000000000000000129010dbe4a2b6988b17fe8113c0d08215278e703ba7f64232a1a4c002ba7f92751281245be0c92017def294ab3afe481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ae47927ba222b1d69a344b25aa6b4bd28312b0715868405f6c2cb3b6dbede3cfe606f7e8fadcd50e7ffa59796262ad000000000000000000000000000000000ee2f6ac4560323a534095c6555b67b07dfb3ef3656bc3faf9e053491bc593cbdcbc5781f97622f2246c84fa42c963dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141f076835181c40b77c256cd8b146ffe51d6f13142bebc9207e367b4bb7bd613b30231b15a1c4238b8f226da3242184000000000000000000000000000000000b99f0c05732f9a52cc0a9a3e08d650a952852527bf9c6dec7f2a477f92075e788732aa4350ae62db02d76ca9f02b17a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016aca25e60b86ea6b8df91aef0e82c2268b65d8b1cdf4269a889babcf9571effaca00da7d358c4f6bf6ea9af85e843f5000000000000000000000000000000000c75bad6ddefba40721ad492cf52f176d633e87ad67d2a7debf96fc347140ad66ba084d2cba40b05937a100f249eda0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000104dda1c1b45701322a361cbcd6042b9813e861da179a4191c3fafce2c493ebfbb9df8dc5dede373350b5ac26490b5620000000000000000000000000000000009ab0116b2ded6d93c7c8458d19911bdcd111c4d956af4c4b920ce8f07c8dc9120baee6486b87a33721c11759925b0511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000913c86373d9b73eb9a6e100e30d08dd36ceaedf7bfbb8d6540a26ae97dc7ffaa7aeb097cd3104bfeb340f6854a0bfa80000000000000000000000000000000017cc22bdd0a97c6b9e13751051b19b0b71499c704e8f967f232a6e37c797b0db5c49fd9ae9f3e39bb173c0302777a6131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001419f1b27bbf6bdb17a319c52e3eeae653b07ed99f84a96455bce7a87b6a8d80ca501c86df95bc42078d7675e168969700000000000000000000000000000000058728a522f3dc4bd6f7a7e58c4bb47f6ee8d65a4df4ef190fdc169750e77f89e78427611294799c1bfa50d6bc9ea0751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006294bf970f3186ceb2a2aa60075ba258952787c4d8c5afabdacc6c9fba595ff35eeebb1b3d0f404f63f1c619e6687e4000000000000000000000000000000000bdebaf5b7e81afde94f2b6f503aa6124175620ed0cb749c799e33754fbb24d87da7d11565af8855025b315321a385d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009fd6fe84788c407f1a1f694326bca2c39b24c173863c55ec2a921d8940d1d294583e5866bddda594999b8e6801cae580000000000000000000000000000000009c819869247e3ccf09f4b1600ef7568d807fb73b300f8bc7f197ed870e94d752b426cda413145e7a60038890ac4c6301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001670c1a57c2eb3ed9fb62cb5d6874381fc8d523d046db238b62d6936eab2d7019523bcd177758756c319d69f71ec01460000000000000000000000000000000009cfb8fd75c76e73ed9edb66add7cb3ce068c7e38af65d705b70f433ac391677ba8693d2b7a9da66874744a97f4c5eb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130d865d0bcdd521661e509a76d436afd0567591eac143dcfd87c0edf90c723908b3dbce8f522f7bae53116de56c7f30000000000000000000000000000000000d4a3453cee6210f473c9dff1a6edb803daf26f5351c8840fec93f4287913ec4fcdc1181c950a15d4f32c6574020e2ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154451a717b375799e61e9819fc814e8b3d720ab0c725eca55e46214a1c1ab3ecbbabdc62aedd7278d41dd603587c18d00000000000000000000000000000000152e95fcc64cd3304baf3425315650307d16bb89a339d563b5901a99a37c772176f59cdbed30bf0d75472920001113791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086e5ab34fae4b6e3cca1327a3b4f0937a31d2889472dd2694bcee4874c24306b4928906214a670ed815ca5ba4dbf50100000000000000000000000000000000088ab0f2a378ac465d719a365603acc61fa4c000fddf21d6b680fb54591ad6eaf2de2618bfd9141ae5e49a238f80e0331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025faf310a8ea586ab0357a5df6e8690c1514ce3f8c5918a2e0f0c838deca41d269a78246d9f09f616579e18ec21758500000000000000000000000000000000176e297c595186fb78b253cd468766dec77d64d6c6c6b8200b92770f93076f34292e63681c5081b69b225b0f074b2ea71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004af00e20fea7e198f8ed998bbb0b85792f232d7ce047e03af4ac8dbc81011cf9e9819116256f48aef1d782fb08b6c7e00000000000000000000000000000000177b309ca7bf4d3657accc697d3e96b260fea7d1e5c60d1215e7f53e989ef9bb9761b424750fa30803c11dda9df1cc981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017561f21f593a3ada8dc1831596490e8ed6099991c5c5d00bdc4e6b651a564ef3c60c51954de4cae44b983336203cd36000000000000000000000000000000000d186ec44246cdb540e385a909cfddb3927aabc8bafa94aab1c3458be19fd3862c52c899ae100ddab01f0cb9ef5715551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ae579f18e3100bbc6b7617d943a770d8ea56f1c04ef36dafa288805e6f6a63077a4a3282799d68e870c16036d222260000000000000000000000000000000016b9ee73a3eaa003ae931d5945188bc718bcaf0c5492a5070d304ce9cfe9e6f6e5736397535b481d9f128cb03397ed851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000989c613c62038d452013200503672f82d7c55b3beb504db03f6767340ada2a3cbbde3a8a0728f92af4cfb68d1fec375000000000000000000000000000000000f7bd845488fba68975da61c91a8f64667f713c228d89de5edbe9526bc63195bc08b09df910f02e519043250a340ec921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e1362b2d78d142bab24f62c42a68ce20c5c2608c1536827346b7e86666b7ed07ea67488f6965e1278d6f23f26114ef00000000000000000000000000000000103662bbf4739d68bb1bca50b8418dd6defb6c697e2d70a1a3b42e795f0dfcb4742e8ab22877af5d7d007a2e3838f69d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056ddb1a25cacff56d94299dfe3046743fe3432bd50f237257cf3dc33122963264ce1f11011696c43549f94fc9dfc1d100000000000000000000000000000000059ca6e500db63a0ae8c0dae73b101ac01274d477d8e33b0d25b4adb8b2ac8c9abcf7c5f6081e6c4dfd74b657e42c5dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ca25ce8835d989625f25295be93fd5c9b87b8956f88257b05c0296adbe62117696a20d34c1db3d9a6b01ff5578c9260000000000000000000000000000000005f1d27eb0ed45207932c21db85711c5f4aec17da426969f62c80431d1472958cddc81f783b85f9ece06a36ea61c88301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076c7c4c2542fd10ac59b1d92357ff4c561eb159964a2bc4867d44c714db9aabd9331eccbc572b9041428ab3c4ab118c000000000000000000000000000000001910d94aa6527b7249ae61389b7cca586292f6c763e338c7a2daaedf2d78742d7f51a6f657d47ce116a4c09fb96836d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a3877c93f8c89d225b6f6fd5633ceac3b7e7495cefd0af8a25e9af7f3e804fc400807c260880e689cbdd927775c7940000000000000000000000000000000017c119ca025cfec4e98413434e58f27c70d079a0b1b5fc23f45dd850215b15c81ad4fda47a2152e3fe3121bc763c0b861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000671d6d815def0718ab866827af3ba0a59193f9a74b19218a024e0fc1cd8165ac8019c8d04a70dbe737507d56a373b1f000000000000000000000000000000001640f288c3c70e136e6af37f379f0735b25250929196ac881b9cc0d012920541a756cf390d014cad4a540568dce883691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dba5d538c9b449512b49e54bc2ce9cc4ef99a985f48897c7c9025bb749de25209f4f9ead694cdac886032af1613c6600000000000000000000000000000000000dd0a9b60bdced64a0dbf4a4da92b8574da7f7256edcff05ed612d123945885232ac9e789c65755cc3bbd1af369a6811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000197189db96fb4f76264521677f2ab038d3fb8ecd3d64b9ecb4103004e4208faabab36dcc4b96bfe4ab448c6787f2d1a0000000000000000000000000000000008c6ae95c556d58c4fa2b9f09f551f937df26750753fa3aea3c98012906b254def4dfa75bc280547629fcf5309cf50411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175f7acc8e916bc7d5c6377deb56bc74ad3dd3859f4a02976373107c6cdfa2fa75f7cad8f22964395f7d2d0e6a65a2590000000000000000000000000000000003bba58ec2c5423d8e83ee81b1117b35c57077692e37343c8d91b2666efca10f661cae1217186695109dcfa3c86295821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d766536b28b41eb3a4c5c8ee9e49a7a535aef63deb0c3a30666624649295565259ad5e56d90af4ffa71ba341bf42030000000000000000000000000000000001d217a7ed35576c4791877d3c1e20490f447b5c282b4dcdd9b20ceb5999a1160fb24636eaea831c8e2642afe38a7f7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2e8565b9d3ba81bcc551a5515e5d71435afe1d64537ce2039d72b3c43e627b7ecc1675711138bc87b2cd4f24834fa3000000000000000000000000000000001293ad0759fe43b146ce53b1627e55d69d15dfb8740db827819bbc6afa78bec7006a009f6469537afd9af1b4b6b970c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c68b4caca45b59541c1b3f3a0280d0ad2fae571d9925f952c6dd47479364cb5566abcec2c4c54347cea55ac37a2e3d60000000000000000000000000000000002230479e97a8b0e6695d2893701705075a0f23acc4966deaaf16aaedb6a27cba1580fdde880188fbf4fcdda6e69e3de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109ce3f251c9cf8d4a7d3bfc39b3f956e10f92fab73616b9d8c28e8781b487337b785bf9021ac7ba0f7cc96b05c3dfd300000000000000000000000000000000043a25257d2fc16a749551d0c6a9bfb3537a4a91ac24333201fcbff752d7fa42e11c568948eafb1da2ab16736a268ee21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005a08dd6f72fa8bd1297c694d0b3349b60da33964eea2752f788d1b9e6eeb16d93241a1784ba600d9e4f40fd36c668100000000000000000000000000000000075b1eae7208070d7cb6e864b6861ec91ce3bc330a515d04f52b9bef11a1368f6b16c0aacf72846e0bb09c5eaa623fb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a6a85d0710a2aab1a7afd060b669bc30e2e0f7036024778c7e59b7b870b6da129c77d10143e5627b89d99228d84eac0000000000000000000000000000000013b5b6ac8128c92dd980c984e298ab19190fe97462626660e4352c66bbb435fc5c6e3fe81424848c68670640d04d31d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5b49a35c7aa86bafd2673ea48a6bc7d94ec3041017fa4c358483533c4dc3f46a2162847f20c80bf2457bcbc01b6efb000000000000000000000000000000000e16c3ca5a3952a38d97b9b7f36dab8c5586f2e9d4c0928cb74c463bb2e26eee140451527fe5f9fb846c4b47b5600f521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032ba70a3ad35e8a86cd3872c142bd4c10ef6e817fe353a14de6da1baea7d7e6abc5edf8446fc887929d563eff19647b00000000000000000000000000000000185199f8fe88987dad9d5954258b3fa8432b9a9ac77a211cc79f583d407cfa9c7462c470d485227648e15247cd44e3641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136f97e62d82e3b12db1a7dcd671224cd6b0043df2efd260043b363d653e16b3c21b087f78531137ad149af8a3e212dd000000000000000000000000000000000a8b9bb2379b39966f32331141b68f059b436b718cc6906d3e366712e112a445e472ec3b5437eb91f28ed670270323f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000747ec9b5e0ea16d54112f042aca56a220af0818b3169ffa0f576c0f2ed026a2dac40f6b4e53eaaa7201312e0ff867b10000000000000000000000000000000018c2307cad5c686c9b0f510e2304d9af2fbedbd3a79f4d6fa2bb843143cde9b29cd4d6570e758b46a567f55908854f861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bfe1343fc3ef85f8cd8558bf0874b1f63ab666d0b93cf7980c01f389aa36093135909fd96d04d405f5239f2318fb3b0000000000000000000000000000000003915ca17408af1ff1d0d3bbd1cd808d2cf0651caae41dcb2cf807c33e1f38f53bf2bd32ac28cfc6888a40e68c40e62c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015291cf122c57e841f0dd8eadbbb011beba59b1d517433b4ecf30ee6bc71e3f91c1d3853b6ab4673ea0933f5df505d030000000000000000000000000000000005227fc5907754b1f4baed066679f52f50458b6669b09dcbb684d7533503385ba23d135b59cefe45100d88af1344bf641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c345c525fce9ed80720bc6957f5599dfa6d16478cb45906b0075e58ff68680d773be95846ee579947473441a4b269e0000000000000000000000000000000011be34369216e5b47a06ac9e4cbf6eaf7f3bd153bc160ba8601be175e3e50c9309d60b43b9a67543c7576a2740de799b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001633e75703e50f09beaaf93e668a9d8d99b53e75146eb8b38adfb9668068603b59afc83c8c3f7c491a8d9ab555a78ba2000000000000000000000000000000000510e399dec9bb96170b3c30bcc5c356bebef14434c7396825b445c98a8bfb92e512432bd8487e056d060c58153a1f391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062daf4ed95025a94afdcb7d3df41be235239f402478bb208c65ed6649f2dfbc7f90a9c8452e766a942b4268ce9afaae000000000000000000000000000000000338ccb2175da5919f1286ba923e94ad7b20b46e8262b039a3efdaed6b98f7581257b94c5a464570ea445d5bf6397ea71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7c32b27f4597466469e90648d7211c35c7c54365cedfdca3ff5bbc063cea7e1ee2293c312b5fdadce4884d33cb2008000000000000000000000000000000000e80b774031e97fa5b86a120dca795cc4ae1577401494d27ce601faef3756438aa024a9b9eba9fdaac68749228ef9d771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009198de864af6e2b9d509efc9e50d366dcf20b78b58a837552a8a5861e77fee88981bf17c9c382529bbdd1d7655d54db00000000000000000000000000000000087bf7d5fba2d944104b641c146f85666dd4d4d8e3c36d41a8a63687fe25a936ec77c2182a90a0c956527b9901198aa41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000daa49621dc933207babad854829477c85eba58f348d553edb2c557e128f8e3a7927c3994170b44f6ee803251b2184a80000000000000000000000000000000009d7a77efecbd0090993047825608cbd77cb9e1903aebc214f0d0cd1251e8c79b8f419d1df380f00c25cac447888fd721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001882144f00f49bcf882d2e83b3730a4f8085e4070e45317ad676eea90419f616f1253d5dde01bb52a5f6c71717f5393b000000000000000000000000000000001409ac44e73bc0a065428b5ae3099554d97f545b5da8595b36e874483f1f4c1e3a61f8a7db59fdb6ec93a0f8f10befcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178a786866c02cc8289ed1f9a4456debd85c4727ae773b95b604ae3c99f1618bdcbdcf740c5840b9aeca0e5462eb616a00000000000000000000000000000000062a98b2b811dc8f6bba38c7a5067313251d1769f0592ae2a56de5c2777cd309b195fc12ff38d9326b06eb64faa8edb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000850ff3c7750c2ec22b6ce17bedf4288bca498bcc42ae2ac3f4d4e4542cb71440eca8cbe033486556a4c900242e5612b00000000000000000000000000000000030f428694dc02423417374f514ad6462577de3b4a8452bff5c490a4a1a5910a7e490a86b1bceae660a076b8e401629f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121a34fc6a5115b57c0134811a10d2e8e74fb34dc6c23409d48460c57e20f6dfdcb2f31f8979973940de528dae17928a0000000000000000000000000000000005848464235e71376758db902185bc4da676b9c9bc9dd1d18d93c5430f454a8d2d75ad168a117b9023c56943192fae201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ad329e17c0e8041e1ccca72810ce9d615695c47d12ecd7c36450601b801c9bee2e309625dcc9b17447b3b423d72d910000000000000000000000000000000013c0ff5a0a98dd6cd68485f616a1f7d6b2967a0eee8356bc7c1a75fe4fb8762e38b459cdf58bb6ffcab1a6be8a148e7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a2510660d7b4572fd5d665f60967f488db049b99a5436a8f3dcc56db168656aa2e0d9f410fedbe722e7a7b2195e45e000000000000000000000000000000001086630e48bd583bca8b3316264337b6a9ed8b6a95be56954ac953449810d230be3b21fc4ad8f501e3a16638675182cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7cf44851078718c57eb94d83fa431159ea793524e15716e76b857ee1317c619f58a05df19f5ba9a5bcb7d187bca457000000000000000000000000000000000ca4abc82f13b02c64f84e92497eed8463df5bb33a024f6836c805be3a5cbc094ad3716cff1f594d766b018bc80d670b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc42a196e5de18e38e50d6e78c16e26e2eb357e07015c3d2a821bba5f49c075b48d1caa7cda88bebf88250398e08e880000000000000000000000000000000007950cf6e46c5c03a741f3aeb1913d63f0673666017c35614f8673197c9dbc3468635034bfdb81d6905b543b501a2b2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056a73740a8f8293952af8f56ab236f12e1f3a61e480915243956d1925662cefa2d069cf7c3ee95041bdbc9620a584e9000000000000000000000000000000000f2b4844d222eb5264d7a906c4f7138db93e1a428afb6ad71e86fb98bfecf9613e4ed4a3cda5cbdabe6d0d532385a1fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000672693bd02a6d28f509e0a681f8c90743921e2d53a23fb3a53a7414245f4063cfa90798e9eafbfbce478dd0b8168c7e0000000000000000000000000000000004c1c8e666446bc8ef7c61eb75199f6c44d65f6fb7b5bd50f56414fb1692072e59264ebade0189d003a4d49f124b002d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040cd3f491f52f0ba00187cf1d43599b6e145be971d98589df0a571c487527737dc455c6b4221dfc4123b446f0f0e6130000000000000000000000000000000015a477eeb4669b650162b5b1fb111c5c6069d849e0b22e1526f4efff3d979d26e9ea10f5cdc8c2d079114ce84ba331531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d66395114180964febbe8bd6d44290e5ce746a3089fc9cdabae8ae0dd12a90fbbf7c88066d32ed7f0be40633b0c9c2000000000000000000000000000000000d9729c88361edac95c009817a83f1323d6747cb9649a6504a7eb38f0577b802617c704aaef1cf39e580f9fa4530e4821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b04f72a50cbd2bb52a99251de9000835357aea307d48c9eb8cd45a16b8def4a1fd2617597a112f82ed0117e6347c1d0000000000000000000000000000000015513dcf565eebd724c6f68066fd36abd0536c445e399d3492d1ccefd1b2ff265617f18004ba758e87d2c571c47c6d271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001662c47a593426e52945c2dd1e718b1a529240c428c6b8bfb214f189715d908986dcbba1773ff1bb293fcbce70482bfc000000000000000000000000000000000708cb1fa59c9ab3e7d849acace0e1e7da0465f3cb285fc5001a55125df277083f7b8c15d830c65426dca12ac6d498dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e1169543aab09515b6b0a87d3a4de948c3d90de680248e4091ad84223bcfc09f81ecc7264344ca1daf0af688ed47ac000000000000000000000000000000000065cc54fefe9454be27c6f01aed65e2aee2c4c90a5a838dafc56855cf734f5f1aaa16fbbc03d8fd414b33f405b975201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f92de10d62a287a5d35544be6890eb6a6474452276190124ddcb5c3b3e757737ec9f627202a541bf86dac05e9190560000000000000000000000000000000008ba87543d6c71038cccf3414f7be41d693caaa3ea447d97d10814f8eabd4eccaddecf4e4ebcaeb1469c73e5aa45dabb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f6a1c4220bb82372fe30495661500a10a7b5a46dfaf4365282dd09b170ba5fb999ef50cc77b7e885cee3e9730fd9770000000000000000000000000000000016d8ec09644cc741a705550eafcbadfdee1a9bb8611f71299ec4eabba917127610c5e782a9e29214c01dca81dbbd21251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6919702f7ae6cab9a16c552b8b4224336100b00f1d3aa4410372e14bd24e8b3551b571430007ac30221605e00002b60000000000000000000000000000000002c2d57117259b6ca9f789d7faa1d9e2832eda5e47dfc1f84d8c86e1598f97c7e161d21b5717be307972f1d8103b16741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a824fc9c92a28b32d6b4f2e06a706c78998e3f21635b1ed651a055797638d8bc8d82ba552dac71220fc4f5afb24094900000000000000000000000000000000013ce26961e7ed33a58c83d0f1b665937f99af31f217ae99f1e12f66e109fe70e76a7b01740f2287b11fbe47b0fcb7dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b8d724e06257ee8313316ae9759ab8637b25f9dc94aed0986a695cee4545b47efe6b685e4b3a654af7754dc1a2567c000000000000000000000000000000001959405099786ef965d172493898368cbecbfbff2b1669854b14922dc9b8fb607109a95af8b7723fd70daade8675eff11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f33e622738d50d92da1ed0c149f048d5e43c07d468cbe7cbb05060f4a119702a6c6bc876b84e868f563d96660329db50000000000000000000000000000000004c54da801b474d6a2dc81b982ac350521742816f25e1d92a1d527171f0ae5fa9536255cac93eeac417956ae56a7ace41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000715923ce6e7ac79dff184b5a397945f3e334afaa4525c4e5dac3a74a111c4f2295343dcfcb55f6ab4cf8680cef3e9fc0000000000000000000000000000000010517da1f4e8e1b551fea509eb11bc28ef800a31bbc11e2911eb0f983b06c6d023c31d6845bed72e3b61ebddee7a9db71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050ed086a0a8908828c15df35654a18b9f36ba70fad534924426aaabc71ead4301d39dff0fc29e71f6af122fcf6c177b000000000000000000000000000000000d04bc14319c2f4f6d8da3c865da1d1c4024539de73c5d2e78989fe7e64ea92683316dd5fbf32b15c73b4e4a1ec315f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076307a676494c98bbe93dcb7bf21a7f3cb94047fd0a85bdba941a072411c0be58cb4154197db9507d4071c8e70931350000000000000000000000000000000002514400b08c3af8b30d40cae95ac4b8602192a0c067bff97107337435cd1d2c4a673b1000ef00a70f61875c17523eda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7931f68cdc71a7527b22053e16477d8787012efbfbddbccfe1a9e4acf98b365e10001b968f469ee7e4ca294617c09d00000000000000000000000000000000100dce988aae7974724c229217a4daadcc8ad01f123f7cc4c0610e205a88502fb7df464b6b0e035e856dd070f37484811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3d73fd450306a19340b9218d1817222043cc64909b4b4e5c14ba17f3d697a767fbe2468802d159355f0659377a1323000000000000000000000000000000000ca66e1855a634a470f2972e01eb4ab84db9402e936e5759adeac01c85fdb033f114502f7fab6d99edb5b6993edcc75e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193a8c7b4eb2cb61364a10ccf547ff2960102286a88eea28e3ab52cc7c24641e46682dc716da226d66bcb31f4440f910000000000000000000000000000000000a31ee48a283f35754f6cb1973dd407d2fb550cc7d0661e42fe01bf6681f1da8eb100263b12956072aa1ab08fce3f2491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129b98bb61b15c856b17d64605742e402fbbf6c1880c0fbc0d731aeaf7210c90cd8563438382f00134bb79fbb1575e2c0000000000000000000000000000000007a04bcd1da99dfb52830ac9b08c0da7036928bd3127ba4cccd004359c353d986bc08fb98a71ad32e1b9dae7d694a30f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd143085086af59b500f3d1bf1a4af7e4f067578c0d675fb6fab135217296313227596d69b405078dadf74a19d7c47400000000000000000000000000000000170e4f9ea367e31c8f0a4784dc2d18ffdc99bb76f64e0f86d5c7e445c3d2ac2a82c95f5c6eb337ce0f0baa7a5c39698c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002aad4df3cfdb6e2e8c3045f44c6fbc5c6ef6b0cfe3089c020007530869fa6123d74516ac00e358ca94d776fb9824d61000000000000000000000000000000001432bc44a959b4230ee3606cc5a4e5d4fcde3f135a668c8c3e147b18c80a3afad5868b47bee2e7c0944651c79a3448c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7c2f4087c429f13b3c69661cee99a4c7473ae5b809f9724028f46ec1ff05d69bf62825258948356c233ce7911476fb0000000000000000000000000000000000883c9959484f3e829963955a0ba07b38c32823f2bfa33fdc651cfeccf79f46428efd930761136d6686c422b60bdd6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b53c1b6105762f787332a44dce9d0aa6248110d701234f5f3e0568a3b123732e5e9abe8bb2fb72931e55ecbadf8fbdf0000000000000000000000000000000001c84d0fe0f165847f00d399bc293582a06096521144f4edcc5df8eee45449f138284a78b09b67ce8cd0e2d56d5993441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f53d0ec0ffccffd5993a1e8ddc99aa6ea16082a8b55aee86be02eb69ad8220b37fbac98ef8bdbe153aa9ae996b4a42000000000000000000000000000000000327a7f5b57018205ebf1b3d9f365e295281eb94863bef7bc1e142d0e39736858682e9282a0fc28177b8fccc8a8022461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001774fa60d000130201997d891105ab4853718ed65899c6956b277d93fe45fc5caa2d5eaed0dc87e74c453a991ce9add400000000000000000000000000000000062402079f62b7a7fa3d865db00a7879dab814a31d0d90ff89f8a552fb802eb2efd29ee151914c60b0acdb9abaee69621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083b0c4a1b70cf9e94d07618e340cc5d7c5337cb2ed576ba5b872017b29ea77639a7a8452173756c39b8e364b0368822000000000000000000000000000000000b15c5d33eb74e7d391f0399e9c7d3065882ae2d136f3710958478e2069e2c336a405c56ad83c21bce29700d6ddfe1621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c9bdc26cbe3fa65c5ba4433558d84fb9a3edc9f6e2d8aa0b581ba781d7a8838ce59153a42ab81954b92b81bfb7016b00000000000000000000000000000000156b9640cc41ff582f0d544e3aff9a6887330b00378e6044e3f93a5ada5e810c6b8daaf00a180ff57084bc6207595e361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b26f5fddda6aa833967a69e6918bf2271b874e31e94c0e5b4a8e2f0e46c423781f76d28f140f980b8879316c3f0da60000000000000000000000000000000018b10c8f47127c1bfee7239a1364e9b1dbbf14abc4bf18c743e69c36e7cb16822e0897e6dc82954e55de37a8db0f07b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086d5454a7a2bde65d6543285af367317ef0c8043bacacb82f1ba18400d39f7bc5af1bf9651e96003cd8e7041e1bb9350000000000000000000000000000000001e4e3b59f526463aa2cb31596dd84649397c82470f45f6271d50ed0b1ee9a451f95e3d958d1b19d6e36128b76e52dfe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f9c42650ca7287c7c28857f9ca4d1ad77b77a3da47179e9bd28269e146856bc935b349e2692784d3765353fdfad7f3000000000000000000000000000000000408ac5979e5e1c22ffc4e6ba03155d5b358dc959f23df79a2a1a8f49bb5c38de8e5983e7d4637172b78a663ba15630e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f562b2ea047c1ce4cb0378bb7526b38d89b361c4a92420cc17e89a9edf25c67ee5bb1a0eb801cef6e5e8c1d8eb317c0000000000000000000000000000000003708d2720bb00c2f56c2d0b9ca7da7f721b7b12e2de2bd5982e88936379e054dc595b714a56717b54014749870276e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014103917b6e8fed3744426ddedf51e984c11521854f224d5636764e4fa12861dc3063a0d75e69e2c891de3a4963b5cb8000000000000000000000000000000001527172ffe2a09ac050079a43efedab358356055ec83db5815f4d5f1094629fc246e0fe58aa1cb440fc3a75f59902ee31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001370922657c96c5044f083f6a5e3b4c8cdce02590f389311563a526f7d71929ed75dc684c1203b35b630cc601ec264990000000000000000000000000000000015969a1981d6236b38ff248e0a1a41a17ea6355937ccd017fef21c2642be3ae74fa623028251f800e90f779cc85d369a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a993e22f919c4bda34d75315aec03ca1e5da527d20b358a65ad29ab8a5bc9ad117bb81402cc44b79914574474fd8e340000000000000000000000000000000013dc77a72edd884e685f865f08cd96f72c184778caa38c6ae6491f625a3a517fe2aaf7fed0ee8fe23c5d39a60dd54a331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f6a7820ad1b602075ed673fa2e66f10956786cea667b7faec790c17df1e5a35a9c96f38a5de73d89f6948f8bbccc380000000000000000000000000000000013479772a2a2a58ec53700530f4658b151b66fc8065c32afca1d61b5c3add9ed0bf0873d4de78107c10c5406c7a67b901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072ae9d9ef901316e3ce208c37c1f5e9e237887ad61fd6d28ce0405efe50d8466219f7e57216ec8e1fe9a9cf477ffef2000000000000000000000000000000000d2a652b46f219faefe8f2e55f7c430de027f3226597602756c0307c1694009bb947cca616fc32c3d449c6750d5d2b891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026e1ada965a3607ac249608a1e0da90e4ae1cdc71157bbc7dc303b8a7405af8ae81a1ce87d3a9e2147382b6c497a9ea000000000000000000000000000000000d50601a103b5e89c869ad9f3a8456b5c57e1b5216177dd52c9a5b3aa2460af8d81e247e9b7160b11ee0fd103453247a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c221f4f8573b8afeaf8195295a7e9b00a451c9a03f5b6814b3a5419b844d1d13978155c3916e4b2fb89ea3977c3f7a00000000000000000000000000000000034352802bfcd66fa3675d880531d54aa74fa4f2e8dc31ddcedadff8bffecd8988e058a97f102c5d0408d7947aee8ef71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000690ff5934c5190c3fb58edba3097285de24f8022b35b7744b2c7d8d476282c486f116d5262644643f31d91041e49e1000000000000000000000000000000000185fa522c936371ef023aef0440b850a18ddc14baebfac726dd111cd62a8a6b9e7acc67a428f19742204be7d12dda2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d687c35fb1aa4494c9545adc75fd82b18b90c398b2a8d1b488c37c611f8ffa7b2493c2d657548959e9a7fb04654cbc0000000000000000000000000000000016d1fe97b32985940459e15fb8efab3196f9993ed85d9fe1970b81515f22305a9c9b66ba55a1f10fc4fd7927847ef52f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a78dc317c72c8fcc386aaa28bc6c6aba6678f804e3b1ed3c3f1f5ff56c20e89c32a5dd0139a9673cf7629dda37d7e230000000000000000000000000000000002d20661db754d9cb9c12bda65f89f9b863beefd82eb4f4214f2fe688a5e983a062fd9d896a89067625b5697451154211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b858a55751fe0546b2768605ee7be43d49acfe34b6ccbf9d2aa5dedba209885cd81cb0937ba72bc138f835cf76bb83000000000000000000000000000000000cf51732be8f584f527621d50537b0eecd8dc5ca2f3402d7808f8e379f1940c0c1c756771da393288f16e6c24242f1f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf30763d77fd474cf5eeb2f0578da92a08b26b072bb8758363e341001e52172ba0382ae9e3d3f351ed9912189a19fb700000000000000000000000000000000088df5a6249d00be6629772046a54ab790063dc97025af6e3b1a67e71cf76726f14403968547a2654c57ce819e3434cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019be6e3bd07f4c6fbde9e010e177c58d8e67b60f23ee9dba7933191be50936646c80381ae5d50e66714dc3ab58578cc1000000000000000000000000000000000f28bcd77cb730417c14ba9a4ff5dc9ffebf6617ac94f462e862035dda2b6130a6f235f923bf3e4f3b404b56854c4dae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090c713a9027b9e49aa3f468accc7552564899b00eaf8601d683ae79f3ed1d262583d67375acb949a63bc66642ad57750000000000000000000000000000000015fddd957ded860774396d9171280d066fb15e52ee03641590bcca1b95c07a24abb654b9ff83cbf050b263e8c3d86b711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ba11d10a62d1a736ba94e4431d62fcb96755ebaceaced3b8f3e3a8e7b61fd37c880fca7dc236a41ebfce3b2901c688000000000000000000000000000000000734f7e35380ff40b608eec521e81bd3a988ac1e4a8a71cce0722e6dd9e7002537cace78e23118d689c639f8689ff5841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016bf27e5ccb271f878ac2e434ff5e26f0a166fbe9f0716eae87583fda93a60a296eb831b6492c54a601089e45604554e0000000000000000000000000000000016479994cd51b03d2e92be2cfdf05553e366222d7c0bac75ac729845b53ba5466e203ba69fd49e69834d01317c92f52d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e8bec5b1dd098efc10929a76714f7279f3561946ddbc760220a038cd5f7f9a586a23c6f1cf9dc66f8e7bbc1545e384000000000000000000000000000000000ed599906fe5bf2467d866578746cb99b1258f816621868ebdd45b03dedafaa48e4fae78622ebce553e57350dfef7bb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010fc1c5cd3d562db1f343dac8e3aa3e5aed9ba692362e61c21517fc7a01a150dd28249fe405358159614a53b073da61900000000000000000000000000000000121f936933d1d1869dfba5df26ce06432acf2b3a882cdda152f0a6ae849a0c9372af34c6c48221943fd50118f0e5bcee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb4868ddbae078cc1cc7a606b0a420e01f3e806bd8e15ac0a86fa881d2be874aab44b57bd3eb52608c3d71052befdc80000000000000000000000000000000009d33184e19ae2d3db145747deeb5ede8d5e3e538c08d0f8d385405f5046e8809b19b788e58b5c48c3e395fd17a775cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aaf4705a623e2076c4e6b809ca1d9b5f2b2c2f25ccfcd4f0fea73fade7c5c416ed7d46ebac6ed9928ed1cff004b2d6b00000000000000000000000000000000125558adc8a55b0aeba9bd5ece3660f5119efe5fa0b73a236941c509dbe07609cb95e100ba08636cc0ef0f2318bc2fdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001726d524081c1c7d38d6cfa8327aabff05a424e6670a7eaeb90b2b2f4a78f6f6eec453bd2d0b5007cfa948c8fdc12764000000000000000000000000000000001081fd7ef04d86286a39f0da66b548ed09ea0616d87509964d8c7bbef1bcf8245807ccbc8c6ffafb21f077fac9a40ec61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061dc1cd7463467db9e032099a286eed9f2d78dcad3e00fb6614d53f780c7787b98544723995815ad9f939f68378ceac000000000000000000000000000000000ee73385aaebb305770b70a449ef612ee04563b3defbad5b88d73eeff6f5133c02324c2d9a24869b514b1490f258a4161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177ea8117f55e1f43805fdfe5fff4e76083bb0f9458b746d93616bb6c89c593f138bdffa1d11e83e0ff2cc518d5251730000000000000000000000000000000008b2ea2670245628d07c6f137e77e46c388c4cc21fc42d7aea10bba773cc945662f0fe674e05e04700601ad1914464f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189f8a6cc8b32143b6f80dc723cb27607b41afe68f1aedda205bc081d070533ea9a538b56e9220ce037306780527c2460000000000000000000000000000000008feb8e8ba467904c686df242263e896aebc54f62514fd7232aff61eb04f9f4fcbc7818674135c2517bcf834268b0daa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e512e45d5ed4b359ec0b42a31a5c5f15a3fbe8e984e71c68bc39169555892491485c0ab2c5fe6e6a00b436372f6aa00000000000000000000000000000000014dad4da37b721b9f987ba6c16492ec9a4883d062cf02aa45de70d3c72ddf7ed975abd15f3b2c4191314275a11f7ff261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fdc3ca079caff9b2d20319c102ca20f2a9933d1794f8ebcd805b5b8ef643d4b4a11071a5aae4c1887ed1443cf2db599000000000000000000000000000000000f65d02c51e897fd4c909d7b44ac173f29449eb3f1b37766acc92f1fa55f49c75ced4894e50f88dcb1a54a582f06eeaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000617398f5b306f1a5b4afcb8805d97da687a91fdfe4d14cbe00ac80b8d509f24e18c87dd47046cbc14693c77b74358de000000000000000000000000000000000dd19d684a5413f6f58d24f901e99c1350b122bd158d72ceab6cdcf959a6d692e5ac8711ecad4b8a753c6b7aac37a5c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021b99fda2ab5c242a761de7b9cbe92d9c1ac8e6faf7f956f39fcdd1644eeba4fd15a06d4c3029c0677bc63861a16e0d000000000000000000000000000000000fefc199aee7d56105c99c011af13952d0a9f98c9de3a15fd095a1909c5fc27d52a938550ff63370c26844bc1902c6931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080bbd7656576917c95efd49c38add44b842a3bb0780eaa1e29c4102ff12ce5a811bce28d3faa3cc7286a23d1db7d0a6000000000000000000000000000000000ff4a0a4b654305dca52c309a73401e62b6b8a0e2496fb06d81b29d6ff1dadf8e9f2a6fdb429e7a07e0104cd7d8401ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012df87e8f1321e3418c4d8d3d5a400d13de389965c816aa48716164360b7bbe23a16fa3b96527a68fe178f831739b2030000000000000000000000000000000012e7f07cd470f4106512a0237c8cffe2e790eab8873482782df1d848a8b7da01eaf49043636d9743002295d864979f631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e023fd775c5e221536ffe0caff52d0fc46da1b865289ebca1f2e7916d8dedbbfb13f0919c9630a85a2f4abf56e1d835000000000000000000000000000000000feaca1ebef354d3efee51cb092f22ef6d18d60c81eca69220e875623498b59adb678f4a51f6d73ad9f44a3f4703431a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004851c061cf5a76a27ec2a6916eb65d933397377b16abdd2ffc0684a6858f1198950781d62ace5e23310cd60c7e4ec3300000000000000000000000000000000069f45b557b350b06d7de7f3fa18b1f867adf765654ea2e3254bffc958bd907ad81dbe1c3dca58dc451c592685ec03341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d50b5a6070393f86310dbc27d80974038be82996467b09c5e541383d1f695c8dab1f2f6b2d60267459d3425672531600000000000000000000000000000000068e9c0c815e43791245b639e6c13f3e627865ca09b1aed65248c2803f0e340e1f962f57cf356879ece089d02f72033c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aed7ff562a87ee20e9a8fd5ded84eadb2e62e8622dc146077bc4c9e59b97e9dce45a04481d73c1e2279c949e7fc30d90000000000000000000000000000000001f53dedd0aa856bd0e6db24b0976c7e09a6b0d3031fc71d44ffc7f4e3041780f37adf0ea2c2df98f19dbbdd840c22df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199898b9589ce2d703826aeb491f5412f8f0a785c3cd5aaf89a546f2df680e7162f2cdd0704b2ebd94371511da5da6350000000000000000000000000000000008ff4ba7203e15210eba70141f5a8b814875ef0646a5135261058b6c1b4f741f48fbc1c71d3ec094f3fe90d651e18c7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000133c30b22d35853cfbc6541c02bfe65b9c598c9a570a2ac517ee3cd987b47c15c8d82b3ce6b4ddf53d540e45caf592a00000000000000000000000000000000139e43a8dfab8c200542bf131040122ab724d7a969ab4bd5c28881489fbf7b185494c0693e0db9d5e7d4bcd95cd63d331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000568f762dd79782e1dd13be346659ef2b64e1bf4b22734e38d21a5586a5ea983060858c96d56256af2ee246ef96a987c0000000000000000000000000000000006ae808d1c8fa32d423c9805067dd9e15826d8384e228c22e135588ef37b7b382bfb58a98565a4f5f4d902591b97e4791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000662e5c9303040678501acc58cb56c3a961538bab72897b79b7994f4f83c8b330e14e57303aed79523fb86590227f0780000000000000000000000000000000008e240f6cea5672a9dc234167b9713d51418333e9e06d4536b9321a87443a62130e0a8a8bb0a3d31dd0c78c23cdff1071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007568a18c2633b09c7472d7612418b6e08204c7613ec90e536fb74535199e5707d5f004144b0a4c9b910d66cb334a2a1000000000000000000000000000000000f017bef971a3cf3f58b2760125e26026458ea50dadf976c6b5384043e2d507101c0995c636afbf5989fc8ec0c83f0931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144e72a0f9d6a789a18f2b48974db6a4ec224f84d0e42e4f6d15c53d75ff2900fe0638a33834778453fc0a5cebae09250000000000000000000000000000000008f3f5732c8419318395692356e613ea5b7b7aa5c792714d06282020a87b75dfde2ea522165a73ee9781a763b86c700f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009daeefdfb67a9de5790ee06eafac7dd40d31cfece6ffcb8c49f8db9e28a0ca64431cbc2d967e731fdbdecfb07359c3b0000000000000000000000000000000002660b5b7d8571e5c02d72a63c275df4493b4111263f51e0d19e1467676b9beb76bd5261ee7b17a0bbd35ea0895e4fe51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d9baac61892e9e7b47740d421e50b11adc76a1f7e1a9fbc958a342d969322cd6558f292d803c37c6eecebd1f41e748000000000000000000000000000000000cb0d2ffb62e6633d5a526b5f2f2f7b787b311ef61041c5fb2ebc95d6a742ab89606d0e8d82694d70177d6a2305494711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147b2beba39c95bf817b94a5b80f056edf03ea90cf7739e2944c916b74700f9bb759dc71b2980c3a44ccb9d3c3bd34630000000000000000000000000000000008bb29dfa3a71ffad8669fb24a0c854f02f70dcbb372ca0bd90383cf1b6824b22a857ebccc5d70ac9d48be571952df9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d10a58b7d344f597b8d0a817e81bf45e936642d0ed280c2956351660d2359444a319dd1cc1dd0e99331919fc5283ce000000000000000000000000000000000291b350eb996e5aacaea1c7b85cafa5103cdf27e0900515f734c2257d12e2fb694f9b49d5938e0fc4f51c2e7b57cd4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b74049ebaa441f0b633adedf45369759917cfe2719aa106d7ce098679d3b2ebab2fd420586bdaf222749348ce51c4a00000000000000000000000000000000004c5b5ce63041398a9b9b3749694a05670788bbd112bba82167e3af9e60b9f00fd3a74c0e691d4c3b6a3812279f931fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3a473897a0c9627c3316d59ffcb865e967378ecae9655fb68ed600afaebbb7396ff6fa98dab3b90ebade9321c08da1000000000000000000000000000000001179a9c27728246d2b18270fbcc3a75d90e89a86c75a9e6d55afb4582e359ae67c58ff5e3a4256cb4b8022f199dc41ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176dc15e0315a9b8fba926acf022dc8a474e2c78047a5d8b262471cbd4b5cca31a7cb40d65658b0540d44aaad894ae710000000000000000000000000000000004e2535d6baf26c47aa7a9868715d7033e2b573a1f5577cab98e82cced81225ad7c704c48700ab85f12db8ffcecf47fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e928ed9031a7092eec1cd98f8952e4f1b5e9456b3a230df46bff11e21fc2017b9f6798a58fd4ef4d1c3b42a8e5101f90000000000000000000000000000000000ffecccf12d0ef136a8c4b287b5c7940f0495e71f06fc1d228eea137941b00e897ae08206514e30f5c1bf8646db69611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016d923698a0a84a87b2651d551070f452a77d23b37ebe811289283c10b0b3f2d1e6379ba9445cb3a371b0a09ccd8bae100000000000000000000000000000000094048f938184f5b4fe9397ce5833a30389753cb9f56f04df23b9fdea090525187928a96623dd613363c440a826ff7851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e55b85981e5c04c8f6e234779aa1fc3fe649b4aa37b5970663a1e77795b7c04b7fd2c55956787c4dcd07585a113768b0000000000000000000000000000000014649ac93c708f0c3e68374c996ee8282829b18872b3663583e156dc1fc8122b82567efb3143ca05ce134e8768a7d2841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001554ef148c60bc44c976226e21b7f90bc336e745aff96b46aa678763170ce768f7fea2145892a72071a9775119162f1d0000000000000000000000000000000007fee5ca613f94898766070ac7a356a96b135de2f11605ea91661a99c8657d44047d3b315808f46f85645e33c8975f671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016895340406b1a747cf5fcb2b12be622957cc42b4697d0169c075afc98768af700f42008f3d845a592022c1a552ffce60000000000000000000000000000000006a46d4d6720db4ff2022bda0a5a62ca61303fc5a7500fa278c863812e55c5ea332f8659c895dca8a1933c8323a0cac31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130bd0b475d201d4d5b39d707ae7b4462ec8cda721259334f9d6f32499b0fd5e54c89ed4317b211c839aac82872056f70000000000000000000000000000000006a8eee8ef30327ff03d1e8a2a02d53e7d13066bf74c4a6a464968abbdd9a6c5e31db7da4c66c5f701dbeeda50f427ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030effadee585e20d5386d03ef748f96c2236a932cf5369332b14c54a1f2c4714368a35b4039c52e8c73f77f0a9f869100000000000000000000000000000000014ac11944192e35cfcac103222c2ce7229cb5e0e4193db10b33bc0d60e65efe0072ff87c753f25b845713cd1a9b7c1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126db1e73c97dc152592d8d4d50da875b157fd0fa3c9c58e61ea82b5bca5dda39d4f836a5a5967922caec9bcf6a4c6db000000000000000000000000000000000107edf16eb63c43f29240f6ab53ef2cdbcbcdff59e248465f642d93f724fb7f0e3c2158f175ae49d892ae621b6c05fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001385e6ff86d5c54942c61f8f6f0c10089cdc376f47c0eeb9aac526824e2425887d2daf3782b8af6ba5f257c713733fad00000000000000000000000000000000109650f8f39a6ccb7e3055722322ba86f5fc4579a689c7f36beb2114256ad3e9feb94b72ef1116f40461f12cbe7725841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081f8634a94eef094070e6d3a1479df97bdf813b068928588560507ed2cb27241749d02df943d03d1dfc1b78534e7b970000000000000000000000000000000011b336e5a5da35ec1035b3d38ea8d8ae4fd9d32105f9587f582e56a8cf456638695c803d41a2abf466724de25ac9ba391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001102fbde1a3c5ca838afac5e87638183ba9adb82949d28f257937de9b34e93827235be696c38c32a3256002e51c0d2830000000000000000000000000000000015d5eb14a5a12c7fc388f49993f9a56494f625033a4626d1ff66addf6ba85bf91019ade3c9771398e16b412ebc5654941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd4564e079b268e02e8b974ba0616f5f9bd8262a5465532a60b115897e1830efde0536478d56ca37de5d54010d90645000000000000000000000000000000000f21442ccbd0f604b6cc9688c8c714ba38249b787e7cb94f1f80cd3a9d0c6350d001eb90db1c32e15e4991227dd0f2ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b83429b471f82ff9f62cb2e5402bcb39e8720ebad12b0c7988a81791011bb1c212e0c7a20b5ebf2dfb03937fd7effb000000000000000000000000000000000f8cb80d6b2af497863828dfd869157ca4b7476b5421ffbd4c56054c6de29133e1040cdcbd83bcd042c7d47dfd122fc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dcc03d5a782be1834611cc121c208cae4266ae284b79d86630a984899576b6cc61781c865783c528b45b0de7c63ff3e000000000000000000000000000000000137d5c4315f6ca01c1c88221814a6d5c4b5895ce34997f0a34bc6d3eec9347c7192b199d01ed440aec2369a7fceda7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001299694f05b673207c48ea5b66d245163e95f6f51c08c941f53bc217c6426aed372617b15dd499c68c1839facb16d0900000000000000000000000000000000018c298fda0e18eb2c5fab6ab2c33a9211e8ad6d41dbdc609002a4ad61cb3e6af7d4a61a1b2e65f7b782a798cc20384251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015da7ca038fde08c0d01ff030484fe24e446573aa5d30f21d0539256c1ac80ac2cad1e240728e779aa4bce204834a6d300000000000000000000000000000000143ab5e494603aa04f7186b87257394b1a02069f0ac487121524bb734538123e5e88fb18fe45861d18eda761086e9e981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141fea8e72117d32a28c67c8032905e2a9c0914007f466a444abfca079075fc1929f091feef72238023b1b1e561df2d100000000000000000000000000000000036279deb5601c9a975f8779747992493c583a55643d3d9ab45d6fa55c2b22890e2833d3121f0db8660760654f8296be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108e9a7821d4f61f9c6ce5241d294cd0596df6b435a1fd28b8905bad742da45ea2eb0e0a5483f5dfe4d8c891b5a311550000000000000000000000000000000003db81d0f056db8a975c26a96111e6ba918fb064fc95f5414a7f56f64e022e25defb19fd48e64461fae0d7e921c7534f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001056bf81c9a3d6c848973a0b4697a6a42ccebcee8a618bdbcde792b4c3f3f92b00e006b932017d4863c1df03b68893960000000000000000000000000000000005467d0594e44290b6273d8c9d3f47bad4c6bee27a45142b892a0d6f90a29c4db5ede4ce58bd59d7b7edeae932ccd4a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a5b1b28c3a1bce112b21afa50dbd46234b89ee1f91d735d59b72f183bcf107eadf169ee547ce1a0b9fce5e86e2872f00000000000000000000000000000000013eabfc8944b22af3e1098724aa788260c16aaea5c7b624a02d867e8201b3428105a0878da9b320118b0e019bbfe1341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bd87ff830638652e9c5b1fce066aca06ff92aa99fe46393674ba217051fa972a42a2ef59df948ffaf497117d3395d100000000000000000000000000000000009db3eef2ca39294c2f953b94bcf48cbfa7395509184f8bed4cf68bf913780bd7fbb35f332ba89c8cc8ce20ce2c915e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184dbea0759c96dec441ca01ba93959084e874583608e8c9d8a8fbeb19af674a5692d22af75bd46655d70182ab88808b000000000000000000000000000000000c1786f7a46e188452457b69f8b7df4a575062083def1602c6453bf7f3059ef7843a503626652da9fbcb66b806a649d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9a8b92e3672622b4c71e488db3459885e3e41b5c554b3725196a73bcb9937344374ea259eb5998d4ef2bff4afebf7b0000000000000000000000000000000014fd6ba80aee046456da2d1a442019be90bb927dba8f74c7963dffc29950f576dbfe7670d408a1bb4f765faaa70b3be31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aaeb58a508f7eb92a4ab83a7005f6951c31f9d56dffc5e8f2f857ce7f2343a30f999f3407e4fbb8e3fca8a6370ae3b60000000000000000000000000000000009e598a46a06a887f22a63d98ce2c768bce86fa57b5824a7c270f4a3bb345301efb51667ea3c2654930232ca591cf01e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e381b8141a779006ec965781bddc64ebdf8d1d9ec3658d7b65d48fdefbabe129f5bc42c5cfc77960ae01abf59536843000000000000000000000000000000000b6ad8b406ebca6eee7e5c572f2166a583033250c6aeb70cfeea934f6fea4af7f8594e0864aa17b542c1d80e54b54d981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001209a8a1c3bb1c85da1cac03629f3a1bffa28ec3b42f51430b46f7cb0de037a659588da61fd32f20ceec1827d45a4eef00000000000000000000000000000000116266a999af3afa74e14515e735d5abd3ec85a36992a9f82f01d0eae40a33e7c79712ab8e91f8248f7899861bd0fe451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039e2fd3bb734927b58a595cc0ed40ad477e1f480aa690f4f9af7f9248420a9bf65a63f25bcc9eb0ab4a2f51a2531afd0000000000000000000000000000000001e9db2f59eec371ed108a643c8bb0e25ed9969c7b94efe60dbac0f03164dbf25375f07307425ed7a2998b48b40326601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040212c16c66902ebf81bc44353d3ba391c5b6aefc05f5c637dfde12e55c5e63fa8f705283d21180a2ebb365708266f300000000000000000000000000000000029cb5fef429ac10ed8b12412f11c1315da8f381ec728523f157ff967f076aefd0001a0feb39429e63c0405e6ac943d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbabbacbf35839ccc00d22e3be550e15a621b98ac545b9e9cf8551c65a5cd3c0290331d49e29278c9e3ca716e5a7f86000000000000000000000000000000000957646f5f592fee4d1aba264e1f7ac633417984e45b18e624f37f8b42653133657502fb25608276bf722f83ab54c05d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a7bd4db58475053be8079df2969efdc5bb47ac9f1d424efe6fcee3c23fef5311ff1f989ed8721e585eb5f95dd3855d000000000000000000000000000000000b996c80b2e3492c3dd2b9e0244373b5ba1b9b2c36292b8115ce1c372b9f6cdbb1cb9f5219ff9d6f65a470a5af1f271e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c2f0b9bc7c6db5f567396f4a24cef58151038aa022e35afe65820168e3af7f13a30f2a4ce1347f42e5b981c76578af0000000000000000000000000000000014068f6e954e92493698076978a9db21c5eabb1f94c9344a895a4201ed90a3468c13a1aa47e2ed8c6f2297c1d6ff3b531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f3b8e3dd11255f8748d0e535dd95024ea75892d9dba82c662308fc63dbb179c009e03e7eab6ebe9b25dea14ad85a620000000000000000000000000000000013c975868cef4873f827ce6fe397e3f4f6ed4c5d8ed44d76dbe3e6402063179161e3ddd1ac29f90c3515e5ddadfad3c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f54f97965863c77a7d657feaf05bf666178331df0859eb4439520907e2a6b15bb4d8f5b3dd269c26fd59165fcfa1d50000000000000000000000000000000003d6a3df5d87af1d9366e88f868bf41a1367e39ffe744a0eef615c956bbbbd1f92c10b838151f4eed4765b8997a5970c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132372a6104f8f3555dfaafd263054af25ef0d8b005ebce11c9e181b00cc7f0876c62fb7cfeebd827c675af54fd0c64600000000000000000000000000000000123a7f5254772da34a2ca376e8141b35ae417c88788c3f72cd0f5d509ad3a7ad52cdcba2ff803acd3019635cabeeab481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178bf36636136b8b0fecc4b0d2da4e49b9309f1fce351d4adc4a4ef7546b384c17f3a820669227eac319f3e26b2803480000000000000000000000000000000010912e83d60b91e6f0645e1ba2578fdd03ac0a5540f9e5a54aa8754ae15f9d100f72ae18ea0ff20f4e7018bf218565ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0fb85c7fd63e97ad53eb91643f1d7a0b02c4b6b4635b55239c80cdf2e9a09481274442aa82c10c180fbe58d4a4cbc00000000000000000000000000000000013ef672c3d4d5a3f950c385980ad2152d39a695266a3ee93b3e98156b3bec003b29693c910cd96bf78179ade194d64c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001410659e4eb02effce055f8d9816e6b6cbfe69b005ba3570a741dca5b8931ed501a82a8f19d9abe27aecb9148136fd88000000000000000000000000000000000f34814334cb289a7be240d4d3293e19ed7e942d8fb88d0abb412e063e47de4e8ac6a93402ad97f93a4d2742363ac1b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000166f64a1c3e3428fb2a9935c9bcb1606f97fd53ec36f89f559616604742400f7ef88244f6f0133a8a34c92b97a843c70000000000000000000000000000000017ac94dab4a5293f8399186b9ce92d2e5341ce4fd95c86b3ccdfdc83659df2bde4945f369744aebc219c41da8aa8fc6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e64f64ce21e71baed7b1419fce470a86e952aa7d77ace9ef83f4c61b724737aca14b5f6a9b8afc96f56424aab175fb0000000000000000000000000000000015bb2898673cbd1efa61d66e4d8b6fd3913319e7eb3fd2b19f77828fb64725a4d403becebe0667a18c3a87468c3a46ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f75a579c35cc744cc9cd5d71a46f9363c91c35b3f24a2a8e62e242bbd0f17b5a5a74615a5e1cc691bc976466fa4ae0f00000000000000000000000000000000064e4d67bd5b83269836e4839c86c8c3c7438b9d29408019bc20e0ab577e857b28ce2f1157941a360a858cb6c30427361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016beff845aa068cdeb86cf8f38e5fced0d127a298bbe5f7e3f9b6d89763b8a3997e9658814be1f34268ec3df2079503e0000000000000000000000000000000017226e07ed8cf7c48de4a121d3026df80b2b19bc71c7685b6baff5e8c038b2c504217a82afdafd043e731793619d72721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108b7915e793c4cea377c215d8f306d8dfdc79689789b22438559b803b7b319cb5d35bc18de9a0be317699808935514a0000000000000000000000000000000004af0cc42a5d9c121597d1ff737571584e3259344cf1fc3826eedf931412e739ddad5f3865a2da102612b6ff2f885a8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099cf3f1cd3043c741ba54219a92deaf40cd262b36736d8919855c625db8d2cd6a8005b5de87d8c9fefbd42776bc26cb000000000000000000000000000000001788c7190b8799d6bcbb720f54228fe997c9454fb9ecad3ecfe05da44900fa03f2ced6cc95e12df575f6db8bdad58a6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063d2fb1497d9cf93a46d0eb9c27ba309acc904be26b48eac9a755a2b0ae278a474d6be3e15bf1e71cc1c383682d98b40000000000000000000000000000000014d924ff714d996690fd1ad0b34c893fe204cb4da5ee3d2199a0b9fcecc42c904e405f1f1a3dcf4328457896bae802fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f1dc7f1fae6f070eabe369e02d83b9e0ae934f3789146a587ea789882789b47fdc3121368bf88c0c35ee2d687e6e39000000000000000000000000000000000fba1d253793ec135716ec03288f6487248da2190c4eed2b1cadc2286bef2d695fee0126216e3d9de8195e97ac734d101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001977f2088b9f343a163c3ee2d99890dd843459d5977d4b30b3eed034c5565eaf74355eaee08e599bfdea15b22478c7090000000000000000000000000000000008ea11d18299366846a5ff17172336d6ec85a8e442dc932a79530f735bab1a0487c65d924d27b56cf2d92a44c847a9a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000873c5370e5e674b9a01c7987d45fdd4ff6ddb85d68c30c429ff56296acc04706971c23cd03f6b6d7eaf2c8a40f3b5f80000000000000000000000000000000019a307ba13046d385b2b0eb72cb7e7a40e3776a9ad9486e68478cf7747f0b05d92c96d5b8e81751f2a29e5f205565a0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b5dc1decf9c6cde8651d3e8768ee709326759000895328f16e2f5c4134529655f7feedb440ac7c3649bce5c3fd9c8700000000000000000000000000000000074bb82ec97c571ea7e35655825c2c0662eb4b3e0cfec3782759752d0eb1552c9c2419c8a9c7a603be31eee5b6e7adf91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c69e8c316370fd788a3178c38ef14539a7309fdf70861c257ab29918c24927efcb071d7b3f05a91631d2b78549a0cfe0000000000000000000000000000000016f752016e2c3c5d41e9b47f842a0db704837e0a70b39641b65656caea64871140c385a3034c021a1d31f329ee9910a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d08f56cf71e6f4f41926276ba1c5e9e88d3f956756e38abc09fcf3313d0737e8d76a2af836b0497dffe4d11b6f183f20000000000000000000000000000000013f6e19c1b00db73c7b4a509b720ebf1686f12b2e27781815af2a5db351a07cf15a310b40896bfb04150960dda46d4031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030eb6627e38171603b17f60fc2402d9a16a0aa9e42cfb642f54fba044f0a60a197ad872172b61bb7bfff11cdf76572a0000000000000000000000000000000011615c1f53b54665c6e45d56bf9440f5f7e57757a6b2bcc2f8d3e564fb6cbad9d04679e574a2f68fe71d94008b0bd83d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e9fb55eefdc4f89c44fb78db33a556d7fb07e378dedb26bce94ffc500de8165f6ff29893e26cebf31630accd6a0bcc0000000000000000000000000000000007a95f4806e9d715509730d2ea65f2bc5bde9bc8f6f43705d8b5a8fcdffdc3b3e5ea367a5c75ff2407561a49f43767581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027e0e801fe05151071075ee24ff3e789201aa357302e701290d0970e96fccaece2377846eae528771464e214e9d8ea60000000000000000000000000000000017e25c94d5129e018db375a018cc67dc774c0fa8b451cecf247d916ff6043609e24561b2b9c1d450b630a11f23f112cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfbbb937297757eae35024a93a0d55121a0dfbedb9658540f70e1a4414dabef4eb56f1c3e02a95d12be59dc65c1be8c0000000000000000000000000000000007a4f900a46ebfd3cd082cea61b605b4cb9f4f4b5a6772e7851c670f724fb2415de49170ad03c34a6a4f2408ef71160c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca7ccc599c082441dfd17c68ecd01813c23955d0f4d506fd1ec76cd490f25c001daba20f1a1cf981a7d28f8fa2728c30000000000000000000000000000000001e23a2a75fa119834f50b00575158c530b630ad94e24ab7626e1c25c9eea6811b72441fbd32cc6b2df5a6450f45768e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000be397b1f6efd8cb4fd72f5b7c6411c6f9c4fe5f0b7bc3e1956e86d2546c19752328300b6b611bad65bf08d498622590000000000000000000000000000000019bc19d9f338e2970fef712536ef52d9296acbe15c8508c8c4a99144ef6f76f5f18d98a22557b7009303daa8c5ffc43a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b7721a500f0a33da809571be189a00b7502d4d871bac803f5728105a3d58b44fbe186de087ee67ee4ff89afedb5dfd000000000000000000000000000000001790b57376e47a707823043a95aa0d3f46ece80490e1e83109cdc0f52357f100d5f5ad523f0d734780c4287133bd96dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c60eeb008e009666e344f8c0486d54c2d70a662e4a1b16c577fc961c9624079f2d06a4137b194eb80b81e5c2befaa5d00000000000000000000000000000000177af139e7e5e038e9ddf909bb6511624ca046e2ea39fe37456025b59f661cfe66d9d69eaf067f743088eb8df4833af81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053311a219ff26bafade5603edc0fb7de19ffc83f9abeaa542c587c375037e20ec6285d8b0cb55ad724847f02439d5bf00000000000000000000000000000000173afca71f6bab7a9c8fa771d4ecf4104d88fa94e7fc98c54da0ef047dd1d08ebfbbc6001da2c9390789d8fa993e1be11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d185a1e889f6474a15ac74a43a3f01df572ac34b509513d63c3320c4f5aa967e0b57b4a1c21a6e851758594d2844db200000000000000000000000000000000085a01a961a3c7b36ff8cf8d1e4f1d3e8a13b97dbecbe49d13eaea3f7814db6d5689274738920af4b5b53c3cb570122a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001689f4617db2629c52427859183264a05d085c60ce7653edf55228a260319a7730a959963780acf0fbffa2bc79aff7de000000000000000000000000000000000480760c6f41808477ffbbcf4088dacd3e4d1ea3433be7489150f51d6e132de6caa0ff9f40169410de1eb9572d8bf52d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000386626ea6f078e55f0d02126bdc9095254ead02254e36fda4dada928010af313d80309b4c7fa277d1fe720c9f29a22b000000000000000000000000000000000f5cc754ce54f0dce68676796236da2b4605014ba5b34589cf03090ccd423a2b5254d43bbea6efe95e427dbd5b2ec7271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0f53a8a3ac24fbe02b36e04da5403aab375ba337071bff97f6fe1b0f213025f5510ca39cea980fb764fcaf174f7d72000000000000000000000000000000001499c498d87de3058c9d469d51ab1454b69d738a6754f8613309b7941b6778829efde33fc1ff2e8dd10cb08248fb7fe81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147490164e580a71e22e5d7e4542c9c7e34884bce0d9516df9d4227ae76bbe544f510b2627226c30857b45f7894ec2af000000000000000000000000000000001162c3f1c0a243d46429edd9f8e3151eaa87c21dae7d7b82af24a8ef8ffd94f7f3ab43772efd0c556646a909c1d73ab81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128f1f181a2067577e6f5e3fe29970bb4c51e4c2a78988ab1d43451719359288e56538e198e70bcbd2357ee6938e1e560000000000000000000000000000000012f2cc03e70f101eac90f5b11503f75500242e6460b4821a3f5f2b375bb9d28176d096f378be46e7f45608d84d5d70281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e47074eb7d730850d9eba36f22a2b79019886ffb1af3dbc3766fd34156a248d0269a6e8e01bf3bae25cf7ee7769b780000000000000000000000000000000004506c23963e7a4f043f737a3d2f78bf88d29dff9bbf4663f2090127eacc32e2a849e5e1be2a07e943142660c6fedb801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001661bd1bd92afe12190c94b965476111e0db7b3c7f28d8fbbbbbdebf40b878fd3c7591b11cba9a9c5bc983d989712e7d0000000000000000000000000000000000ef7c43a43f6eac3f1facafb73f7abbd57260aa7793f168bb789e136e8e6bea273e238f9c142c08e2e3b377baaa2d8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b209646e4b69b1323f4599a1049194d5a607311e639d91c500686e7198e051e5806cbd3be6f9d62b2383682a021b885000000000000000000000000000000000895dfd92fa42deeb99eae815d61b0f9fcc7b97f16702494d0311e95afc58504d5f493b8c64143f2a35d044dd58b9c4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120906549bd4786bbd0f5f9d1c6d993051b7626b2a3d81be62158cc38b8309e3652e806cb12647733e030fadb37dccf300000000000000000000000000000000004a3e963182dc33dff5ca035b9f8fa38fb24b6fa5bbcdcf999189158e8d8ad987b20e0bb2c0cec380b1a2e6b68d21df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007802fbc22f43355d31ad504f1199b9b22f19cf0ab62917c39a8bfa574f497ee4eaf3d6d3e6513eb43b9981fe984512a00000000000000000000000000000000046c4aedeeed3319babd08e47d9b76f0d4d9ea07efccb2ee44cbc0ca037692cd6c87b50e426af123cd4b029a9f7d86911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab39c649a8b969cf8b1845d8c7131db5ddd320ffb20e01673765da7ed6e403bcc8ca92ac267fe41fee5aee33dc1a835000000000000000000000000000000000a942b4522e4f78692d040f945c4c8ee7f8e67cdc9b1f81fe9db3f5b55ae0bf20892b2dad8f74f4aca6b4c05e337f1471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af065e3d5dfb4a922a986bc18967cdbd339f1e58ec93b720d771d627adaa3e84e503be837b15af06e1bce2e1479d2a9000000000000000000000000000000000086d68058a20fe23ee7f67fa6aa5ca4af696ab727185d1f1cb4b4c7ff0bb1e61be65cc45ed58bdbf00f95fc96adc95f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142cd027b1c4e870ddac162b6b8170d6a067ba6cafff9fd6d78c5c7f6f576f6201e449d0d0975061afcb44f8580df0570000000000000000000000000000000006817f31a985e1b534d3664602239412d22146a0111467cc8b13fdd3ccfab56e67b01f86dcc1b9097e7d4decd7728e771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001621e788cb0cc44e1b8c2318580a40db301ca29a81705381a11d7f096202562efe26be5c3c71639c648c0c0f5eabdb9b000000000000000000000000000000000a19dac3d16b27ea40a9a397c7331228e9e857290da2359e4a4f2638a2a179c3c672c62b9d96c7f6225a27a7311791521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000699b655918a7d1b2b61775cb3714472b493e7b0cdccd8ad4120ff0a42b7d1253331d98f6ffab67294309675c3b4ada2000000000000000000000000000000001032d11150d629a84aa2877a65aa278066f3c55c7d17126b4c048d4c88a57ba8c00d0d114ce49fe4df64370786ff6d5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000944f87251dc8740d49b7ea92a6ea71c1360ce3782f8229130e6926b3a861ee800325d7c50add151947a510497419247000000000000000000000000000000000128e43bcc2327d9fda3eeea7b63e297fd9b35b7d731d66a2c8305a6835dd8f45f665c0ce667440ef1f5f0611989e8e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148fad9b69bb0bdddf0047c5877c5af687360b82abb70c7c84411372eb043c7adc2c124f442ad0f2c1d30c6c746b131b0000000000000000000000000000000010249e8401d308ea8bb05dfaf0a32c30a3e1c44285137da5b08c3eca12212bf31c1fac80037c6132584353b2342cafc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a56103d62e728cff75041977cf94712eea192cbb325551c22ef17008d15296a3535b9925c5fb56416176a5cedbd10b00000000000000000000000000000000012a3d765f5338c4b32188cbf24f39ef5e404420deebb5c078427771ea7b06db25e7463a84cd16f37ecd3cc0d975d18a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144ec3b136cd25c2199a7a98e78b5a29d2d4ef40893a5ca6c2ae99db7d50c62a98a2688bbd638cf9a1711f25afdb7370000000000000000000000000000000000cdeeeb2f61823a8848c542dae28f0000960ed4628ced4187fcd569795f972c10be1357aee8cdb8038bed8a8234d65781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001515362b4b885dcce8100b2fc5ab85348077db5b83dc181543213849af3609e6d68ec1751876e9f4c4a4939bfbd36100000000000000000000000000000000155a2e7049fbd76f416b03c70adda54e8465f8c49862c39c0c5622ffab8e9fb2fec0885811b8a8e52ec5fc08cec508431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011afc43b67340dd4d08bcd9a32594b380351fa6d2f17569d4552bdc0895b6bcb3bea1ff7be58a7e93ab14c247275315c000000000000000000000000000000000e4033fa2d04230d22c50a42a9aa52877286b553374319329ae30cc1958a51d870ab2613ff43b210bd945fd6a64406651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ff9b229f19f0d535e08316cb24059ab1a424ecb125ce444aba56e5b7fa0af424a07f23cdc1abd10dd0256305f17bab00000000000000000000000000000000034fd1f4f2ae0dc342608fed1a3850d937a37ba9e1cfd3ef5d3283dce933acf5a9413fd5e2522169761c6bdc60a44da31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c492a93a588333a6d1ab40c9a11440e2f97fd21b0e497d8cb8f64415f415c2aae4f5c32d766f586d08532ba6fafdbe0000000000000000000000000000000012beb1ef4c4fbea1c5b0410586ba71a3dd8d390693285d8948c9d13b28dfac10516d08844f976142a6046e1f8dfc5cc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125a63edc2b5c383c726849dc734cb0d7961da58377cde3f994727eff1cc506dff698253e6e6171c76d68726ec747cf50000000000000000000000000000000015c6fa071f405cfbc45a69505cd91cc07bfcb748b2874d9ac77dca6a8426dc131c3c09f8c8f86052ad33c6091fd629d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bb437bffc5342926ab62d68805e9dc5099201e874ccd5940cd44f792140c57e92989e660e72648e72c680c78fff83700000000000000000000000000000000176459071bcc5d386607c5187e69360ccf7ca72acfd1614348500172bb27fef781d3b2a1ac2c0974519d13c3ef79d3c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179fb9c2cd3e282bd6464abc39c23e31176952b4a5ae2670f659b1b4967a2aa0f7655cfbfd6391928fc464179725c706000000000000000000000000000000000b11da59cbbe12d61f7df13004cea870bd9a10beebbd40c56ea9f8f045dbfbbb5135d6df5059d96fe45bd5fef07584f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000070f3adb21331dba3c26865b57794bee01142255fd2427ebbeb3bfcb355d37cb262ce2eabc1ef14f97f25e11e34603360000000000000000000000000000000007c2c25e6630fa4db72b04848ce5df1da3d28148558f2ed62581a8b348c343c32bf9d429daaef37f34e4e28e7b579f971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008cfa6857713747c5673a74f5b414fd98f7091310e31cbb2d1530459ac658c0d673e27299f53debbf41e4dfcce936f26000000000000000000000000000000000394549714bc3d8dd61c1cd1c6b450ccbe10a31c69886c0a767095d92bd847de226b42cc2f40a494e5b26601485686101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131ddd112c353192b8ffbc1578218573316d5eefd0b997af2fefcd5403a6b3d95ac161d4b7ecad142b8ed2113d566f770000000000000000000000000000000013f1d8132fb3fadb5a42f06051f80fa692a3c7f148d88c3d02ed8a92496952df3816c98b96511cddaa890de3b5f0e52c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187e272ee6656dbbc960c9ee2ad15416c2c51ab4e17b600b33e36bb0d054e4f231f8068a9c2181a68475da170c1b6159000000000000000000000000000000001693f4ff3b4616277b6abef396c7ed3bc78aa85d4d11d3b3d13b659e36721609fb491a6182fb9dd386631d0900d045431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007df3c4a648f06f28655da0e0d71412ff1f786da4ba6415235f227ae1b5c8b329464a5ebebfe8660d11ab06511aad3a2000000000000000000000000000000000f034e2d5180b789cbababfb9d1db3775074b1b4041b714b2b4c7bc55bb34f860bac254b73584004430afd90f38b0f091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139ba10bb54c62ccd4d6c40ca83128d0e39f677e542f2fe73d536ac286fd102b5cd66743199ad458697bdea931b0c96e0000000000000000000000000000000014986ee0acc79959311a821c42ed49ba7e3f018688f0505317060deaf6eed68fe86c54fa24faeec2f06a161c740339051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006afa28c5d710eb3e4fd2bddb05ab6c27982898e46cecae0cd4a669aa27f05f0db6ada48b213cf68cda433be631b360000000000000000000000000000000000457a160abffe20be008081f3d71fa56b87caf765ff611f5fbbd83d8bbfce307eaefa29d43f94d557bf2195661bb82fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd31c70b600c66013616a937e2a031e9b99a6968b6ad56314ddc51772042ab978b596cf1a1f4f556124048ab098afcd0000000000000000000000000000000000561ac6a65bd9950c9f75faa6043e280ceff22916356da8d4416d8e5a87742dad1d141d82eb90f2fd8e58ee39d106921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2c02cceae1ed3df350b68e324143fbb9f8ce2fa018960439baf0f243eaa81e04a77655a95da16f880ca86d990f45e70000000000000000000000000000000006478667066a43afdb7fb88a9b64d4d4a389b0120312b9abe2c793a358950fe3dec23c6803d782b335f4a0d82b08cf021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d6d5caa0c8feded6333e4776e5237daa42c181a058d4b8cac1c30bb1284f61bb6e1d40b591ffdb18643b943e67166a000000000000000000000000000000001154b7d57db13d477edfaabcfa406b7fe009e146576561e50c59d1399465a95761eae4675e0f3f196a9da62f1e3769a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005be98e323b44f1553d3ed33b68958e1b51b1425a9f68af603093f705748b6a9d187f9e22837ff49dee37416ab07cf820000000000000000000000000000000009ca6ba84e1f86cf3d50ba3f7ab5abd4b6351ceee1c35847d65655b14fa7789ec7ffc4971bba4973543106ac2218adf51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d4ac90a81b45990d87ebb037961f5f2aa11a870b2278dd8debf2604ddd398561903aa38f1d7e959c501da11d9a69ca000000000000000000000000000000000972c143863e33c238f41665281474d92a035b4c5bb23eb74d6814f4bff764871f854b70c277d9246935863eeb8e5d891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a7b5b4a6e27560fda7b47b47d70cc7562534b9ad407495863c1b2e7b4d6bc0cc03e90480d31db74c8714ac3a2708a50000000000000000000000000000000008e3a1754d5cfeec4efc222af528a6947c630e540981566237a0622c8deb8b1ea0f663f5b06ae3e70c4fa002ec151bfe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167a4191218ab1d97262d1b9eae10c8a789f3a8bbb5058945206255901d31cf0adc8c7d3f62e81c486034533cb2c1822000000000000000000000000000000000567f306d9ab0ac90e2db473afc4471017e0735dcff7a416f10882946b2467810768886cfae2367c312d3dc3373809491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001fef9e59d5cdbf7c21e2eab254833433c0dd7bf6f310294be5054aa01b6f96e1c42a844894b484f21df7e682e180389000000000000000000000000000000000e1f5a78e32b3af1ee825c121e9637df84af5973b755ac1aef7c7901afb493154771f6a2fa1ff1fb2dced28752d7f72d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194ddb28b07efa7f5640f8cf62e9646f5acab9b92cb8c7e9f911d1ffc4f66263939d29e58fe0fd817b8a32657c45a41300000000000000000000000000000000197139af4bd080eae31f7f97872a447ae21bd1a5de18db7a4413e216979e67eb95277e1e5f3d2f5befe3bfb914e9231a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001242d476d43c34e0a5eafc1a864f8354c2d44293821bc38ca6801f5f89d5bb7f88c9ce0ac78015bef858600e7a164a71000000000000000000000000000000000537557d4b1287361f263fdb88600bcc223bf763afc56f24a7bd7ff47d25976a4178a5b1d648b41105b4e2653c2334401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed58dae7a96105a03f03acf408da0a43c37e7388d15614fe24e278558f2fa1232f656afd531c6d639dbf200218c7fa50000000000000000000000000000000003a4de29591a8a184e7e47ab6bb1be1c2436c9e1cd80e508066d828a09977fd62d9b173e2510dbd1464b1b056f0a80791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000398bae306aa14d3ada53f8e944ba25926a9b57fef711adf39221910326ddc64ed10dcbc0ca09bd2c63e8112494a4eb30000000000000000000000000000000004e2c0c99475b69de34ffd0cf157b2583bc8a41cfadc3c2f665b2590702eb225e2464a1e585331892d831e51a89aaa2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d1094d50494a2fc829b20aff39bf7a663d42d63c4d7f1ca6a9d6070ca401b05283c469f256db88b76e044ee6fa6c9d00000000000000000000000000000000100c547eebf2071ea67a14405e2101add7ac9eb4f8f923f21adc0c503e3b539c09ac60f6bcd2a6c577fd138c406d8e221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e05393130d6315ae832371622a68dc08ead0a8fd5e748b114f682bb860a9a9870c1c03f699b4123f0eba5cd978dc7df000000000000000000000000000000000ac00f4fd02d97d61d7b877c79d89a9f133fd6dcb98d735578b9f9f6585b263b34d3764eece1c22fc809e8187695aacc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000082a5f6192516331d9e8b1833ec327b144a5a020d1ed0b0bb4f79831cec38cc6d223def3a17eb455b14abe48c2c39c270000000000000000000000000000000014046e573933bd62848f1accbd30994e87fd8e489084a4e22d0feb4a3d58252315f44e51568a4302ff7d1af0efdd89ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000527e8bd1cae5835c17796536b5cbddc14cd11788895261dd3c46408ea35d4ea397fa962aaf570b865b088ae6a448b950000000000000000000000000000000019439716e490690a1015cadba1eae76f523bdcb01b1b18ee1f241d44818cb4fd0563920179b354ca0d34343ec8a4d6c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000038344bdb314e9de4800ee3b8a70a2474b531b89b80a5219902894fb74ad4936e00023792f11c43f8fb9a73fec881e000000000000000000000000000000000008b36196a86801d0aa423ddfaf0646c1e05615b5af44e70e89f1345e4f629a1b09cdf87a287437ad78ad10a17fc70a7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8f6deef7eaca9ded38de029b72ff2d5fcc65d3dda922a4d5235d77131b5b45a3affdffaf26fb7da772bf26bfd587870000000000000000000000000000000002411f238bcba73197c1282723463b2c50898eb546076011b24ff24b5b82b2ff74f097a8f617e7e44b666d67cec3f3b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008593b39dc5c4e81b9e1a376e39baf84992960db0d9c13a8db32da7ee31bebbe20b17403135ed6eb28420576d7467b78000000000000000000000000000000000b6bb04b5b53a0db1ddaf2911f6052ac7774e067d23388d1ffdaf69cde7ed5873cabcbb50ff4a91c16a39095c1a2f2021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005fbef8516765ce9c9347e0d0b28946582fb75bb574f227eb5fac99ab8f8c03b7352ceb55bfc1e30e53ef8de37b9e36b0000000000000000000000000000000000c4e127992f0c2bdddb9288d216ff3d448082e97b19f11fafd93657907073e81d5169ba880ce6abdbc0dcb885cc01581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000148d4df38533516e588f813df1ee0693669c3ba8fddf50002efbe82ecfb651e907e3e72aa737a3ecf4c9ed896d067cb00000000000000000000000000000000122b93d1f34a58aeb960b77bf49576cd2d5bf371500baebb35c64ee4465856d6ac5a764739409ae2b1610dc70b70506b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000802f3cc53b9e19b7c86b67a0f26bf2edf26c9ff3ef03d89f66beadc7ce75879b73613883cee675613e78adac552222500000000000000000000000000000000136de5ba963ead16fe78dc68b326f95496bdd5744086a972a0564cc33094f7976f548a2abb84a6ef24865036f6c26ab31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000882ac25a031e8a8ee41008737a52b7f7bb5084cbaa44c2e8897feef93459ada9ef475f62bbb850c45c00164d6c9b61b0000000000000000000000000000000008d41661a294b291300279a823dc0bda32b7f11beac75d623ccbfe822a071c85b6c7ebb4e6fd4e4884df609665fcc01c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f320d2220190dd2a58fd0a15f3e06c1bd97430c8f61cb5cd7cf5762d3aa8795631710bd73107fc7386474a70a659ef1000000000000000000000000000000000c199b95188d59e362658562d085bce0498557a1613fb554f75116d61f87a4d2079e58da150ea28b8fd4a6e72760f64a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138c60fc15d0b801e129ce0f54e8bab46ee82796872e4b01f145d1227e69ed5398801b0a88962cd00df88cddb1f9768b000000000000000000000000000000000e2b8d5609be81bb3d1c7f8daf702d76463a3e6599a0721a3a2cc5ff3b6d3387743ac9e611ab5a629d0b59f7fe1cf9e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069c23677d7aeeb0a8e548a00f3006a40b493f0aebf20099dad8db312564816544a8db8f5bb10e1f0c57dc8ac63a6df60000000000000000000000000000000017223bf5c9324b990188f8c28604cd6feaa8886b2c6058d594c21b87c95383e01b962d04a288ed50ea13a2cb2ca8f0dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185e3a3a52709fa0dbd9780ea13dbe8ff0dbd94e514bfd9bb8d0784be0444ba84a987063f959a8830787560d6d6a95da000000000000000000000000000000000a0776471c48ad7ea6ec8f26e51f04ecb09a993ecaceb517e9dae29dd36713f12b7a38a0535d7242f698fd9a93e285e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff39fa938872b525f07b0e56f820a2c4b2dbc98b75c4c2635c053c624352577e7c6ba4a66af0d5e94d1058f5e67209200000000000000000000000000000000036a99847003812d138cc7f568cc481731ffa4b07ca87b0a63c65d8a4620b6f4585f615f5079053346eb90047e53d9461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007cf827a9e1f834143d334add1be4d168cb42eb7b99b13cbdcaf6f461fefc54f110199e8f909da8d0df4f4674bf0bcd00000000000000000000000000000000011526caeea64195a89f36aa1500816a0d0037b233dbf6a836827c84234607ab83e356f3257703f2fba96d07ae815b091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000979e0dca31ac72cdac9f21ef1d7982592a7aad51b55c006451e6da545197ff937add4f1fc0eec8a5004b8d6751d3f490000000000000000000000000000000011c4056be6ef0fb8d538e0bb1c9b3eff46d3bd75914634e5b2735e564b091c81c434e05c340837194fa5fe9cbb83948b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125e963b23e57c013df669158a2a27e028e4f791d030bf3edbf7f8eb40c30162a076472a5dedf82286546d9b6303f28f00000000000000000000000000000000114ccd83c76bfec63a1117739a648af091ef65437b6a987c008d89459f05647640219172ea1c5c3a780ea380b54188e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f22d12eaa8d8d9f0f534faabead875d7e57ddbd8880310efd23fefd881d5000ae716f52b57603cd3ba9a0d97910c45800000000000000000000000000000000015c86c379239e916f726455d25ab619077326adf6a6a7d1bb2cc6df27ea48a12809c03ba188842a9f91bafd9accf0ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145e1fccab0effa89cd913499c1b4bf8492460452a9ab15688400228fc76e67a830e6a39e79656f4a1661a5721d61b7d000000000000000000000000000000000bceaf5a5fd9753b0aa412c2808300151309bafc5170a83a67ec91e65b50818e15736b3861fd78798adabb5665183a9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004330e60bfb618262a5d302556a584513f213f898050b5812f783828944fee41dc4b14d1f0428d3f7e67edcc995fd6fc00000000000000000000000000000000046519ca05da7bbb3777c216eb1038e87237aef7c3e3915c127b5797ef5110fd60f4761e70ccd276666d8d7cb52690e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010bfc88cc3e717aa3a4cd66977eb4aa8bb2a052eae85c46e9d975ac61ee2f587734ae7760b94caf3136910011d49b462000000000000000000000000000000000e076798011510e334449fe6a33f74ce500deb47815ee4617ea4f4a576a707b5b1d434c6b48955d36a7d7aba3a9cdecb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008aef76a49b0eadb4b598028fc69120f855613d65f814afb6ab7f3458417b3f11a34861599d93baeaec1454b5a9ea3ce00000000000000000000000000000000127c732ee9c36db7c719581fe4586117f65de00a373a6fdfcf510a81e60288bebbeb21e077c1901ef11b8a7c0b61310a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f748fda777487583cf1ceb2bf42324ca0b91e371fcf6d80638d764e41ffd5398c5c7bb76aa44d0c6c90bd13ab8b580000000000000000000000000000000000b1eae70910241324931926d8981afe6f9ddc92ddbba1d51f838f5f858322a5d93fa9092a098c9f0dd29ff45d95ebf041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f9f7492e85537876b735ac518a95a382b60ab7998a152fc1922723c4288b99c3b227101246a2341ee5160c879ad9b90000000000000000000000000000000000045a7be00785ce04a5cf56a7c6d0b835dc9a005b826df57ea2ec2f6be7b2834db5b35865612805ffa74108c4e567de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000601000b7f064daa2a1f3fca93843e55d4a5453322c0405e6e2cb9860ed659d706f3006e72ea6be8e389d8df8f1fb42b0000000000000000000000000000000003ddba5602f396f868bb1fa8092d79f7dc8e0a59e0505666c99de910cce43ef49a9e53fbedbf61958b41a858db248f7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047a63a750348eae4ba673e5ff353b20719cf6bdbc68c94fb5fe054fbe9b407d28f4a7c46bcb5ca616cf8c80825c49a90000000000000000000000000000000014763ed0e33d8979ae27a947b3eae170d583ecaa864f0ef44f13f4b28d1b7724917656a291e00b2b1fbd80e741e940131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001587125684dcdb7994ae52b7580e94ca9149de7e06dc5107fd179eac5cf85274adb116d06c3d1b1e75efeb4c5eb937300000000000000000000000000000000006c7bc6b09f86a31fd2b69e9551a0458565f4bff88c775d8397831cbeec7f1de91ae8508f4ea75501fe072560fa8f33b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d70ba3f25d50f06ed351c55e396458e337337bbf923df7d5337464b2bc4d3e18c1daa81ba5197233f677933842801b000000000000000000000000000000001141ba7adf3445b4de07a0df3b545589dde0e41a28c9c7a193334251ab717a502f714e2cd46c4ff1c32da4560207bfe31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027f2bf1e4789a88bad0558800caa3574cc84a49d86ed1b40afd724d3506fa6d3cad309cae5d2b08ec4b14accec3395900000000000000000000000000000000109299c3506e096a803c2699c00e8639c1fc1504f2cd70561cd518ec858359ccce2fd06559160956e39120561c74c2c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008fe6b3d259bf8d8c2b1ba7e2d74da566661cc7478c06513f7c64298293b23579553ee6a6c603840715f5baa40628c7d00000000000000000000000000000000153bf7c7fe9c9c902d2f7307609a7b5c78563040607cb3967aeb6af52eeede9cf4be28d809c10bc03479440e14153f621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001345a0bbce7902d149c9501063d524881722d0a760075c5912b5dbc6ea18f8fbfebdb9017e1002c3a7575330edaef66c000000000000000000000000000000000b6346691f4c480528f74c8a8eeb88cb578f47e122d1377b1c26e11210cda11765f3c2a018314aca9da2d39397b33f9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ffabc584cf5734d315e8439e0d8839df833a654a47853a3f9580c03974e3a70d38a7a1f743c5782eba5450f7fccb46000000000000000000000000000000000dce15bd969daf9cb9477635743d10491fd96b3c21856136c66c047aca99f4212c2ee32cebdae113595a77432eb63ed41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164087770883dda13545a308bf4b7b68c6caf81be4a2d030c249a5b837997bc0954475d73baf2ae603400f38c0e9ec51000000000000000000000000000000000ff741f945145f099d758a2997cad7a99db8774587b03856189188f9f96afc06e1a181ace17cf8f960b72d9853464de31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd135b1f2b49d8555ac9aa9aa493d6d8d60738484ba90613bb15b328b93b08614fd05d96fd732b27e29ed576f297d2d000000000000000000000000000000000e03b517539d29a3ae9b552c129f7c611ec708b0f232db3f774a6e853936dcc09ace5d6728e175b9d20d9ce606f9e99e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a4b4a5ac8650067642d162cb52e63faec401607225b5f05335670ab59bc8c815915dc79b8e066c48f38f0e81634a52000000000000000000000000000000001702e03ba3bdf9971a9105a9112d802b955390cf5f57bd69624874a37c27ca507aab8a9fd6727a7227b3f545e0b90d4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f0ffab560d11eeb7038ecef42c043c6cdae32941bb329a6fdb9217f6445e431e63794ed8d9aa50f0d4cc1df2ed6123000000000000000000000000000000000379d9041c41d7443b1360c3620457ebe3186f9a1eb5cc7d7f26f8ff41fbd6b79f43987912d33a5bbecfa1c80ed9bcb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000afbce8d724d371187fa42e392c1679b3848f85a24018435cf89e73b70ea4a281667ff843fff2979ffc2d0ef9aec97ee000000000000000000000000000000000c367f9c6a31e1bf90a31dcd95f9e22b995a664553a444787b0cda7c91b69110b0b2e1ae105ad13c7ace88f8ef8125eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd8d0b306121ec305085c003aaf44cf1e62a9b12f4c3e65975d689d925d9ca9bdca04e0a5fab9e2d6e3217387a3b1a7000000000000000000000000000000000f59deb0ee31e2ab1e7e5c6884a9038fc1e78b735d2e7f5c165845c4625b1926fd3550adc2e0363bbfd61084d6c937a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3c46ac25f4442812bc443b4a064130730d1fa5269d23546e6d5d520a8a61e0d90025f135553e493d9eba9a5fb03944000000000000000000000000000000000a5f49f58d74de2cdb85c481eb244945d60c3f4465017aec127a0db0b4d0b123a6110b900238f3767a4c1c8019e6c7371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ce8c0ace3044c129b869013dc777bb09072820bc3a1c8c3a99b0a555f111146d6c95b21d7753a7857189f0ba0f383e00000000000000000000000000000000059275493bdc96b52a4fb0c1629af169ff790ffe40bacbe7aa6955ea2ddcd5b2d6a044f284928b593b8aacdfe3f1b31a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b2467f3f48fc7134251cf907b5e7a57b609056cb19978c0604c8486d0438d8e168b9ff19362e38a3b68310f539ab500000000000000000000000000000000014416c058869f2d4a5442cd8685f19f13633c49aef172323298ad38d76cf09eededa763c36788080820f7442a15413f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e55bb920ca483fd5c5f711b474e556a775418bc831fdb3e943bcb4b76c8b3f42027694ce9b1c0ee238f916c9737e00000000000000000000000000000000001318ca785512c43d3784a022fca4b7099f7b8299bae58853614e33a12d999c05b33455236b43a6224005b3c1e5d348971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009790cb28041cabe0be0701727c26794e734278f55a1ed2ea3ba7c307fac67e8dbf3b8a2d809a779a4d46275cf8258650000000000000000000000000000000018056cbe6a8d9e3d9d04c9cf36d06a742c1e7d562562f4388bdf526f82728d18e7f660a3cd80589d456acc3e5cbca78d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001aea7b7b25605401b97be443fefd83b301a9e4be23619f6c605ef5732c203f5d148d15a6363592d867af51e80be179900000000000000000000000000000000030a1d6ca1591722ed1219c91a9aee13c65fd4560a309ed7402ea5bbed3608b34d6d09633b574c67aa7fee726cc2807e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c69e722338339dc3b0258a2cf2bce14157a797eb87b7a530db7b45b6a3685e7cc0248f5bc01831fb9b13d83253d2bbf0000000000000000000000000000000017433952a0f68767bc166232b2a87a17c36746f887c3b48f1b23309d74d9022329541fe95a3928df87786be45c29797f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014cb2542b6544b75382e3c90be2f2431b54bde8a0aa795a778676290d9da6fd7482be1653a6f950a757be495fe9293b20000000000000000000000000000000019e13d09cc61578590f69d8d07906433d8abe3ba2b7e2d8751c9e4772f07835909b37ec599062cedb2ce0e5a5d5b72ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004511d6d12957eeefb2b5fe5846942961d7594c9817eacd126cd38ea6f156139e89b776fbeeda43358b6208e868f2c54000000000000000000000000000000000897fac3f14e30056bdfd8c55bb33a828cca3a2829e1081d149aa070c5dc660242dcc8f6e2986040fff0a8cfb9d9af2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001820425766eb7299084718610003e004db530f0622ba87fa7c99134193f796d4908c47ee67802ee55f5d019f11f3d5b6000000000000000000000000000000000a5fb62dbb1e1a76ae29c52a31cecb238ce198da83c8a25baff5ed989fc015d7f60b4aafc46b417a08778a5e9626b06c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092e2aa894c251b01f271051976c9b1add7d0852c1932f3e1004563a5f93c731bf2af74639926d9fb58351e6ec4b4a15000000000000000000000000000000000077a5ba7f61e50aed4b2350e598fdbc3be601d783d70bc5473f6f22610c76d48039ba03a03d1815a5e2c590645198941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3c241df6f8f7e09352ae002a36abdb9e870fc5b9e267dbd153bee62cb14c68cc68d78c64fe4b50e501aa8a096471b80000000000000000000000000000000002f92e1cce872bccd2374c4aa65a2d89cd9d695ee23a67951d3267aacfaf7920ed6eae1a4b4a6bcd2f28993491cf9ab51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f71d6ce835ce03d37853b83b14f5281c9766e2ca3b5eac565280fbd7e70ed1b12e290111fcd1e022c42427b58c75af00000000000000000000000000000000158e6aae0d7c22d2e052645361f19a60dfccd1434b1c5b40d7e56f7b17af05bafcd7909e11800c0c52813933a837b3d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce5573df58e74e4a84389d51a4e237af66ac7881f552a1a8a2338e3655f3adcba0be5e62158d8d6bb94d60d3a28a0d3000000000000000000000000000000000d4f196ecf6de0943b19551ad6c6dd4c9f34708b32cc2a85fc976b92cbc77fb306d0326241b57993869cb3c1b0efc3641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c41fb0b59196ff64eb4ee8a0234c41b4ac5b8930a9bb3a592cdc90726ed53eca6323d1411489bf8a1cf4cfa4f5bdcc00000000000000000000000000000000074f90a824480e2eeaa12e5166f2b78e5d21af3582fa002735fcd2c8279902a2aa94f288c91e614ed48148d66eafdbfc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bf2d9fc2e1d3de9e445e15e1711f20f8b018b69aa2a403a6aacbc8c4a602d61630c7bbdb9eed38d01080282804d4d6000000000000000000000000000000000922730482a894099e6af64d6c80f0a2ca3de8737aa263a827339b1332ebacac919eeb532e774b41db20503a47cfaaf31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052bc9763bb2ea95aed30ed23a83f4720a0b63589221eada77ec42e12081506a545e6b79838320816a98a6cb08ffb6de0000000000000000000000000000000012d71b3409768e8e49ade25b3d1345404e856bce789c53e908bd2b7b55e5ce4983a3f5745ab4f3eef8072d4ad17565cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001732efc20f2b3db60f1a5253bfd181b1bc266e028fddf8665c1edad8282f16f9d7e0491e58c4e9cbb9e6c09c1b11246800000000000000000000000000000000005e4e5c614a7b042e023419646b42b6f04796e886b4f06750c968ab05304835c8fe6dcd1a0046acc80b1c7c645007b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ac487643a5da96b8607ff1575d92915b7e858a5b8fef6421c7bcbbc38515e22aa997524b9d2e180c61c2b4decf836700000000000000000000000000000000155149cc3e5446bc94be31b9c244f43eb21bb47d241f9c7985a2817c232577c89405f941ab48bea49d5538cde6c18a8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006744c53a65ed278e0d4ca62f51c669cfb4dfbdd8c9d3638c5117507e29c0b86e25c0fa34465dabf88fae9be8233f3d000000000000000000000000000000000889bfb4c1b7711169f48f13363b56c7c05d59833426c55a4b113eed935c24d09cf36c422aafc74aec0e42ce424f85551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3ad5ffe584e1b6c80c7b2831af2010632326c01c8a3fe557d811d62ec8e60e8bb3c0a3987318203fb04b875af191690000000000000000000000000000000007c597142950f74993a7d6c98cfca3eaebd114809e4147793a411512a2baad1467bc6a9cc243d14f0b24835f310e08f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dba08466e1fa7044051b39ab27fb8b539715e3b0f6b358ed56ecbbb37bb53868c5ece6955c54cb843919ec21ff85d79000000000000000000000000000000000c334083404bd54fc3f279f8459da64a0e48b9ff07f0e2d17500062be83e93bdba295994a14fd474808de382b7ed49081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190eb09f200ccd147325a99a21aa51f09c15009b77284e801a77cc9611b4cc5940ec02d4268a00335c83a42cea21bfab00000000000000000000000000000000095c541544bfe68220b7b90165e5aa37d4793d3f9f641294228e8d5f1538e00fa10b455d70dfc344178b2392fb29b6e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000039dcfdd7a79b079364d47f2e010619983a1ecb3e9d6a043639a9b6b4aebcd1a086fa1869cda235c1474b407664af1a000000000000000000000000000000001015ca6303a8c3d6b057a170c1b4705ad2847959d5e9116ac3f67869dbd3eb7218b8fa483d3ab8296cd3ac10377333701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000508e67598c62dc72a4b0d14c2535286921a68021612cef91479b5f75b83612703e48d7c6aeb02575c3a06f179d771930000000000000000000000000000000016b354b9b6fbb5ab0d7939656303d374723d38afd571e82515f9d90e56d98fa13bb1b43eab48b4b9cdb6423f6c2af7331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a9455de4c4992cdbd93a7f83c065780f74432f6895c115a56eb0fb7641e7030284b1272da5ceea76b1b431d735572d00000000000000000000000000000000167112f9989876e7e330d787567fc60166bcf07f7dc61b766faa77e482e30d77dfad55464471ed8066876ff6096196a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148d72c843c0020a3d133a2cabd72cb0c5cff034932771a1f6670ef899aee71082bf936d1a096b1aa6f2bae13fd8ddcd0000000000000000000000000000000014b6bad54788ac7266223c2b9ac937206893583773fef15ec577a7d7bafed2602517e28f022ab9f1c2db43a3f51d073a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a50fe66ecf34da20fe032554072aef37baa39fa2f520015d5fbe7143bd763b424fa3fe922e5550f089430f74037774d000000000000000000000000000000001555aac1245461e814141b40c557f534d2de501ee4f06d400963316b19861736ee13b5363ade5fdf27e6bafb579e370c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c7b095d3a1e6b3fea0d860562163a7ae6391d2cf521a63c348f8287867b199d4126ab6f4dbb91cc2764ee97faa8365000000000000000000000000000000001397ebf9215bbcfd0e9ca49524c2df3fa89c3e946d506466ab2f8431ec4811ca1b518b78ae863f4b8667e8497a6a78591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066724daf7ef48974888c75ac6019116d1b812e70e77d3417a51c3d9eb24ac7a49c91cfb965c4338acad5653854babc10000000000000000000000000000000009fbb2ed47f57764dff9ce82fa5293ee1801eb342989d90a9a83914ccbe93428935a99c8458f1ff11d04bfc46875e2271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084473855aefd9b7cb72da9f07c0f4bc3188fb5b40fa3abf9f634933671fed7177f534e695d2b401a3bcb7023cf99652000000000000000000000000000000001155dbcd3a00368094ad6b1bc5ea0647584de379696c951344b7bd217e526c650fc3be6e91a4056fb6cad0937d45ea9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009732c3cc883c6b3dfa8b1508ac4b84e9dc8c3c43bb553df50bbc41eee68a5ddc7139d67c732e5f15c860cf351965984000000000000000000000000000000001586488d5d64aa01c2ab118ff2c67879f0cec5375795bb4d2761f1985c041cf5b8a8563a6e84e80d2145feb26e91e26b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167d96e204acaaf22c3100d2f50fcbe513194494b05bf277e3664f27a21aa3e70b4bc0c33c84ae6b213feb9d16794128000000000000000000000000000000000dff734764ec3982682d93a30c85bcff701b11babb2c9d9c7b714a4fba143809afe9b8cd6f2df4931979c6cde932d7b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f14d43fc67e0dca75b6f006bbf771ad42cd2968f2954755cba4e5809e82c3a6d1ff4fc416275805e93ea279287a0b800000000000000000000000000000000183a66df5d298123037f364466f0bb7bdec5507a9156925fd5f0f9b0e2040963af6daab3099b8c424a9f3466e336f3de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001621fd0e3600b2ab7824f4654c61a520cbe6a434df8c83f7e9f6537e1d7933d4de3ca943135ef96186bf4e2e720291000000000000000000000000000000000004299081fb08e700c8c268b6f0ab53268672612607847cb63129331cd9b43034dfd7e2f61ca80a200688e222b1774c721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c3a902cee2d059f0bfbd7c7d02d1cc58b2f08abf7436b1e26f369b3961d1889abee6f7415b52c9f892a95a317003500000000000000000000000000000000000496d5de982c7e0bea906268cc06092f950581f279737e8525d9addde0dc4cbb877e84dd632309a79893b9038a28b571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000640aa86a5b5d9a7cf5ed4ff40b31e051166b6a90483aab0f70ef51ff0e4dfdf7263e2c504677fb267535b15d095061700000000000000000000000000000000151404159be04aca0dfc823c4d241bb3563f63c949f19f89a24ee0d2d7927006ea68a05faafb32fe575d6ed3790212501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bca8cce3d7a8d2c3f7083910f81573b9fbb3327d953da3acb22c5ae06064d1824d5b23086116ef2767d32e391802ad00000000000000000000000000000000090a9220cbcc223a009ffefdc0a98598ce8afc6767e2a9a676e5ade17fb80128999f027adadd4aa158cff0a4b7e6a23e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bec82d9e44d54e252466ea0d8c15b535d5585d9cf820dff34df8fc76d347d70c0b908abdc9b2a22ced8c27277b5285e000000000000000000000000000000001287cdb054ad242d37a6377563ca31adad01512cd6d77f3776a07f2461ad6592f65285642c631f2050d0ddf8205c7bd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012908d6b002971dfe3786868971471376dbdd906acd70f8f8c180da843db18af1f44aa29725c38b9e473f1f8e4efe5ef0000000000000000000000000000000003196c4d418bfe27b313899bdb2a2223f78b30d29b4eb280d64c8783cd7092ace845538e2431d0016805d04c0dcc77ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000155209159a323faa6a0069dd056dd592ee0f78db4cca0f4b8732808f783956ab58b6816c8b6a2132ff67263501cedc56000000000000000000000000000000000f730e8099ed98e33815ef71333eb19b0bc636e8c094c12e2cdc8371b9856658bee4e33b0994396ca620e86e725e190e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012883f777d8939f935950a3ae398776df7980738a2989ad5640b68ead4261b5897a4c8bafcc1433cac34852e1a2cad7700000000000000000000000000000000001602fdfceb8d8ed6ca0407cb0f3704a82fbf40be03cc94a7a1edc501beea9a55e4ac2559af7a8a53bfcdad27e308cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b1db50e936cb7c58958f0d03887498d7b22d8859b9c124af2099fdbe532a1bc9f2e0ae15b1c818245827db92b89b180000000000000000000000000000000002c4fe8f2e4b61982dcbf9947256b60cf70263b1dd9c938fa05d8b8c008514f1a9d25ec81cfb1e789abeb361e18aab7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029812bd255aa73c4bc0a42569fcc1ef020863c5fd759712b6b511b18af77a1654ea726892e8acfe31ac9ab1e3a29780000000000000000000000000000000000b9d893e3d0419df8de432f78ff85d312d5c57a0ac4202d21befc45e04697d5bd0e3fa392c20d0916625708f70e7971c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c1bc99d288a7e3412eb70044304281e4753bbd2027be6e7f940a18ef6d71498a4ab7e071ddbc29a7c970369ab27af3000000000000000000000000000000000e11eca8070accd00eb0b304feb0e468d9027da20309f816ead0aac8180f53cda69fa87d9d86f6196b00514e721d437d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074495b3df8ad3b9063264bdf7752ae685cec7ee44943a14bab214da89bb98d1ad436144a38fbfbbec43cfa51439299d000000000000000000000000000000000533228056ade0424e4c291515fedd17f209f15df17dc29e312a6cfcfdc16d0f53efc91c17c01b8d8acc0d87ad020a5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8fee45d7312a66824ac2c6e2861860edbe7bb6be46c4934274c2eb87ccf579badbd1adbf3f45832983f91618fadfb8000000000000000000000000000000000e12e5a68ff42f08b467aca7c46b09b5e851fc2a2f6550fcdf556e0d960624f3e6f47735d364462845fef0ffda620f061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000379647160c7c4216b165551212eb8485687617af4769bc45151e1debe1651c05919d3b187fc5bac6eafe31b94475bc400000000000000000000000000000000082f0bfa32423848436deff7aa74d8ff936d26519769292a952d5e174e0774f873db2bf14ebdf1669c2363ba2ae12b7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b33320ca860c9c944d41530063132500ffa31d7a034e51d492445293315516e3e1fdcfe85590c347c71a74d6d205e61000000000000000000000000000000000e623b19e08a1c1ec1307d6599c964dd38d844e89f0931e8600fcfc5a2d25ea2edf88b9699214f527d15ab39c5b0ecc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dde052dcb1a0b8f385964c0c0686a8dd0a449b2ebc8ccb838008bc6a3e900c21dcc8af7009ff75028e461c06be4e760000000000000000000000000000000004d5a2d7866d81faf9070ed1430fce11447aba3ad12a5c6ee55a7959a324e1a173dff25c6408c758b9e6f9cf3cd1c22e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001482eaebf0c2906ed95f3ebd738e3013b3db0e5dc886a86ee720f17fb134d436ffd9cd92e39704d8f5bfb71e5f658162000000000000000000000000000000000666ec20a6ea1039ced4d5cc226ccca0b60df10c4b1c01ca641fb3d88e4a23554e4fb4a5ee0b74e97fdacc812f1dd2f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f52bca441c27802ab3b32cf68be9aade0011ec89a60d486d90c8bfb73e59d632a83cd93fe20ebaa2ab6a42d4359c90400000000000000000000000000000000016f96f62ceac74b2e3c8f3e274cdd57a5ead5bdf3915dd4f9e09e3518d14e4c14f227c1d1fdccf43916e03d207930a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ee3e0b56bc6f872c624d01bc4ed0fc28a2be32bfe7b2c9ac604805371df72eab49601cd5c6475063e177e9a4a92f6a0000000000000000000000000000000005ffa850d0b6baa605ca6579f2f9acc6134fab0bfa34f0f89d8ebef5287b505e298f139f06789fde5ec6b0837fb138491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a7828faac68084ef41e989b968f235f2b5555ac2cf92758afecf2ae0c74fd546c5eddce5f0f4cd0c3daf700ac1b25f00000000000000000000000000000000056bf8aa92d99ec5bda529e018d860b64efef75516a48bd19e911934f2db96f4106b57e7296b37c05ab84ce418ef6af71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007784d7e0aff950dace1712233d6510b4dc434cc1ecda1084a2083048bc2b391fc13353ec4c7f0e8c4c286966704eb6b0000000000000000000000000000000007e1c59969cce5fd3bd8a63877c5b099b046a9e775171687d93947242c5850f4be964242f4f9ea5c155e7ddffcd134651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffec8532175ee307f53b12051ba4c2afb18a79b37237e64b46692a9fcf69565254389f3bff9cb278b51feaa7062a85400000000000000000000000000000000130b15555bbbe751af34c7d9e330c9fb226b6b8b68072e097cb973ed5c2b25b129eedcdb4950e8382dde4b54eb550e841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084ab9008e4824899281e6846c523853c023a5c9b51d68b6a0a55a63d368fcbbaea9a35068d3315670770135bf5a372f000000000000000000000000000000000d2881943108c81a20491164340b74c6ffd01e49451671d48d7b16f465af83658c203ed1f05d9d0271fc4a831b0ec2b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a808e62c6c7deb6442b8663e52019d468a7979458dc433b88e9d5d0c50668a9fc6c212c70606202a2e46d9ca763ff4000000000000000000000000000000000c711d9a3f57df0a7966153b5fbfa6b3c1d58cb6d7e21337af41c3ca8b6612fc312b632f5f46c1254dc450d524d0c1cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000138ad3ebe1812c46acf97e12977d95bea6e6cd44b0b839c3d2a194b0d2bc0270abc1155f34b3dd9567ea493c8205fe5000000000000000000000000000000000ecc2dea430e6cb904e65a96d0ad5630a6bbf95d017c7c8ae2ff16d23501a6e9a7aece5191f6b20cd33276b481cb542a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181c4dedbc3766b06f7a6d555d86eea8864c4ad3c69317f719796b7b82ed806824633d42a1685249b8ecbd200b3b75fb000000000000000000000000000000000eeb784a270e7e827bb482f71fc641c00ea14bf7c3e8605222dc76911ebf6d6f4bf123cf89e6bdea2b268b159843c6e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd2cfe21201c40463e9805a1dab64f052faddff1014b10ab63946474ab98441cbb9398e1937583247d3415582e8d97b000000000000000000000000000000001378d334d571ce0eec0174b44e919e3a996cb706933c7314099b37b4375f22e03816ed8ca113e443d1fd969ee113015e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d760e4686f4b190a56cac0458c8f91a7ec74645a3d39f241c830a7842cfa5a3709cec89720f4fb50ac11fb810d0776000000000000000000000000000000000f80a3645bd1fa58a2965e5eab2cebe441c4305fc9b220cc10015d10bf3373ffc880cfefa374847fce253ff85fecfd0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d27c90c6a2dd4314e7587bf2d5181a6aa3025899d2fb32b1d5a34ab9faf9cdd632801db12a3ef1c4beb685a2ac81ad00000000000000000000000000000000028efb802c771144dab499069d221183d2404406956192ef160fc910df531f48c12c55535110efa5c3790e9aa92a0b5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce248aa7c959bb492c36fd8c4cbfbdc8cdde00aa92d5f5db4e83a7436c9180940c5ed5ad52adb098976a8aaa667d2130000000000000000000000000000000010ca59e855f27bfbdd0fbb79deaa388fc8a9f01dd23908c6178b6144d3ea3903af220c2d84418f544964105ee29ca4d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a36758e69c8dedee5f2e79d42ba974c471421b7680d7595d9c8d13be9560a90075a40b766a76b745020bff8677b71cd00000000000000000000000000000000008193a2b48ad95b4b90943feb9f964a31a1273c5779d645d057376127c17d00bc446683e4f6ece9ea94ee6990d84a441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a772bcbf2b2177aa472b6ac24680c6dc02a91a19ece19d44c4786cc823977747714be750c813672cab3ecf9f2ab995a0000000000000000000000000000000016355213a3a0b2f42f423e2df016fdb8f7944f3ff86113388f304003cad28a5a4f3b5898f0d9c1786c09fbd0deeffd731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9b098a732f22c01f3ce078b5343e3768b99c82be3824c71d45ecaeac03ee01c0228312e34de13b81b942e60d78bdc9000000000000000000000000000000000867b037fabf1a97b7470781a56c6f4a9650bca3fb8588553f11ed5aeeed240bfcc5088588f5aa255389ff8fdacc83111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f3bc7614c67b2211b6b016156e9093d88c7141fd8837d42972d6db2fdd6257c8f9511e8b03960b514909607a3a40f10000000000000000000000000000000003e40d7311d9bfcef8fa02fd53758a25119d782ae4168603e852c8f65f12150269a54b925971dac84bb9ce626d090aa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000165b971dfc4053ae2a36920313ef41a96ddc16ff57882666b1e6d26962f100fb46e540ebc6b9bb62da981c790bd76c70000000000000000000000000000000003ee86e515a8d8369ab529c8fe48c4ae97132a7db12710fc0e64a10991eb9f25b82b51173784f74c0b4f4b3b9d0cbfa31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e8e3f7d640a83910617b77ac7ceff3c7e71aa23d4bc4e8c71a3a46a4be08011bf3aa60188de4fdea03e6166a3015e30000000000000000000000000000000005763820a6d80fca5a91f8d41a71d4ba9dc6d46320c81a30203a485f084f11387b7d0fc6d0614b5123f28188cff12b061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097529cca8428b4027146f8df3a24c6f34b35101df16de022a2b509280c6a98139fc064d55bf4fb0ff56aab58e1e73af0000000000000000000000000000000006c4d337cea53f3dfa8044afcde803bd7f31f8531144e6683d354002374f935c2a8dce5a62492d911287cc87b70c35501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ee9cca3597ccfa5708ef6f4fc19f1fe962e54dabb6a4920abd2da8715a9c3da1a4a90b43a76e05798c1a8f0443a28000000000000000000000000000000000072dc1f70a35151f25ca6ecee9a7389582d57d7848babe64a3f0a87e35c16731c44fe6825376cff3b05dbc9645c071cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b2582e245171a73f5d8fbfeb773b4657073d1ed0c71bfeb50596cbb7b8b8b4902ec05546a99a7ad79a9cc1d1d3d2b7000000000000000000000000000000001804f2ce3fc8d22fe7a9b312cde7b5241c8387dbdd55aa0d099afd4eab6d2e854690354bfc6715bf3167c816de48fa871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004395b8560c2e00ebbfc6b926212f0278627ededab6f01c76469396920493f09a2eab43daeebe3e16f44f4510274dcc40000000000000000000000000000000011ec96a5dbb04a016f4907b1ea61db8691266ef0ba236d550d439f3a4f86d4968a0e82f81bc626d59ecdb3ca343cf48f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001209b761662df407da587c4edd21cba2490d08302e6a5d3e479cbd0858c5e8e8d887313f72f888598ff6292da6bfe089000000000000000000000000000000001480e2ceab346280b34cd55fb47a88735ec04da209a467dc2f0dedae6fe51d5504081671db0f70941b8cbada39a245951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000986483635879c384c59451b376efeb3c83dbb6ebfeeb62466d428dd6bbd859ea6c92f07ab29a4a888428b5ad2d702370000000000000000000000000000000010c0902330a6f82c505e2c38965f1b5d63b0935cf024fd66d4e80761fbb48361dec6c9047f28ece9cd7c819817a8dad51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dfb976ad352224958f5f042c78d095ddf4d672023efbe37a6e716b1cefd2ab0c8f1ab01895ff446f5b44cb716615d2800000000000000000000000000000000153a5bfa1ee5d2ea594fe2544ba3de9256c54dddb2f370bf7eade51e3b32334be1bcd09017dbfe751c3fd5ab13c839f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161a74ec8f0ff654dda4a25e2027252bd1a24228d05a0293f47560d68144dbbbc28011f6d078e458dc9be23b04b07351000000000000000000000000000000000e792f731289b71bd0d6f2983864a0534e994d264d614b3a3c0ccefba8e6c44c46c8be2eb43f92442a4c2ea1c106717b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfe530b6c4ae5d3df6de260cddda9ffe26f0d5416c5baad987e80dbdb855de7abb1c42ae175f0a253ec99d5b6c311070000000000000000000000000000000016abc877a6e3d2baa98304ac7c3e7266dc2649ce1b7b406f79d482825da75a16df10f77cf3d3384b32573013d4a0a60e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fdfb6fd591b298cadc76b7bf4877c6770edb6e119054e215293612119684d7eadc0960c9d8691e915e20def924aecef000000000000000000000000000000000f3c4b1418c4c666ffd69c3e27ea472934f1e1bae19da058a42bfaf3a9d23eb683b698e49a61406014fbf368dd5284661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002bc8f2bbd4bf1035b5d17849b2a499ef993c89725480b29235ab9baec44db18f099d52c98f75b431ef4b8c6a24e1360000000000000000000000000000000005c974be50f8f7619a382c599742ccec24a7fd758ce0c9ea3893e0ad0e22e0170ce1ac953aafc182c9c6b7d223e39b651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065de5ddc6dc276cbfbda7b25c5f324fe0b517c3df9d98755dad204a30c237c81c39aa72ea6e0f97b62547feefda07b40000000000000000000000000000000004e25761c473435262717e08a8edd35cb8222371537300ccb67193f063ed2386772112bb9ae20ebcdc892dbac650de4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d480fd74b34d4716aae1cc1ae806672231e58ee0e826f3fbc32e347bc446feac7406b61e739f22aa64e1f996ebafa1000000000000000000000000000000001469e9b5e1e890f3d9c7675d1c6fd3139a28d128d600e083e1e64112b35fe28dbc5a088bfc218c322488fad9d5d2f5b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001e31efd85acc5e94dbc3afee2034d81c28ea900d683100fb0bbedcbd4443530c1d5f4a5f366db4cfdb4dd9487e220c0000000000000000000000000000000002cd4bd9f642ffeb43546fb021133bd3f28e1f05241b84e27afb188562a4e2fed7f8b1512f33ff7843880b0450895a221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001561b9db57311fe2dc1de21cca11bb2ebe093fbde1e3bcd73ee6477fe467ec15e3afa67bc9100576671eb2126c2b41a5000000000000000000000000000000000f77f858ca649fae56cae1eace26ddfea4cc8eedd488f5342b0fdf2ef2749a4e71b1c618fb8c45d6367c1e9f65fcd3561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000003d50e15fc0c401adc387297a9086557c347f1aee6a96d7585f59eb80c1ba9048e63c5a5f3dbe769ddcf751bbde7240000000000000000000000000000000000a5b9f0ef77c8b4c5f2a15fa0d1ac7217fc19330180fab5cb6aca99f09712133493611633de9b4c606bfe0a0ee843001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dab424af569549f6d528820c0e6352fd2e43cc9427ac7e4db443eecf6907ee7fefc90d1eff203915da95b9d2af05c1d000000000000000000000000000000001106138a9306b5726c15d4742c5db785c7356aeb066e7ac9ed1d541ce862a560deac14f678f68d63f97194b810180c351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e57bab83500bd04ab1af8aad47d15c10454388e6b986bd68f368ca297541b0928ada2b64b1aedeaa92e8a9d8af9ce40000000000000000000000000000000011552292080a882f6dfb2353c6f83e559eac74e63c0f6ee75c1d16305992d6cd4e3dc47b4a83a95ed45f0f386be69c361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067ca607547edd63c6e045feb31686bb8c411272675ad576ac27c75c689fbbaa9ae50d117e15f70b71cd3adb8418edd3000000000000000000000000000000000ba660b6cdf7f49490ae0631478d02e310a987021486f0a8fe47139de8eb0f332468bdb321d8f6495b703313dc4260111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171e918d61e3f339fbf71b17570e25dbb925e3be0810ec566c4f680d044bb142b5a111dacdf73ff7f9b561df80fdf0ce000000000000000000000000000000000f66960f7a6fbaedd2450653db1ba3a3a0cb8af09958a7d3da6a5b8cf5f57d086ae7bd2c539aaf107360610a5977f4271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010cb86079a6b4b1cdb118b5ba2e24e8a61efe1014899fe09285c63fa167d9f7d6647848d9cdaf6d4d93bbae4889877c5000000000000000000000000000000000744bca0f63f4fde72a732aae6845f874012ef9a5538792a00561897ba06520a9b5fedc111279e78d989f729b3cf29eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001767504df0275ccec33f188bfc5f0388091b10c599f07e847e41891af2f2c256becf1253ab9a82f3f32770eb20c82dc900000000000000000000000000000000167ef787378466d427036a3eff27068a83d59bcf0c89fd946266ceddc12c11ac02cdd8e1f36b04f2f65a238a9d5a91df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccc57ff7868adf545760571148e2054934cf1185426110d2ae9aa2cf1e6268156191ea9c3cf890bd71a47f109128e7100000000000000000000000000000000018663175deaea4280d108f37e8cdbccab129448e88fc839051dcabc42451c88d29afefb6065083661ba6103e5ba71591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160174e603c366a1594410bf0c74fd8db53bf6e56f3a83b4d97cf5f361223cc6dfeb8143492534ed7bb0eea34422693f0000000000000000000000000000000009b557b469eeeaa719260a561e6cf7d5f4284cc1ebe83e368248d35af6f3288ee61ef476aeab342ffacbd5f572bf254e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d63e719127804e893cca5b5994a73fada4fbf82499502964ef1f22dc3980531c763155642e4ba290a484e48190b007e000000000000000000000000000000000c9275ce5d8a3965afb2efff41ea0678966524a7d1a92dcdaf6f6b1f564f1f346b74b5bac5bc64b8dc8f679cc073789c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea7eba93cd7dbb7be019f5af45689d34bfa2033e784bd00e10a7d189f79feb68f3097dbdcdcfb7d6f5341b0e1b155ee00000000000000000000000000000000082480ef6e25e8dea79aa76c80b9cbc7f1f34cf386c8696c0c0977d0a03ae4c63ff50bbf6f93cfe2f439ac00a1fad73c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177fa7edf5c1c655217b63b50dedc5378d0596530f176432538023c3a0b3b1daa3127aee15b36bdc9288f26c45dcdc6600000000000000000000000000000000110332e5f99e3b23a4d7b2119dad3af369cc5c40268752539190fd6f8962072116e443d9d8bdd1b11e8ec24fb9d971ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5ac4358df16489ce839025e95d330a32afe30666f99394449205c71a9cd684928d3ba19856e39505847402047b86b5000000000000000000000000000000000b8b750c134b442eb82bd71846d65c34cfa765dfee1eecf8779d3f1fbbb93d676300dd0445b5ef0d708066fdcaa1bbae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107febb6ee7c01ca7b8b5ef771c7c1dab6fa5b32e9089d0ace6079434a3c7b3287bc86fba47223700cf4843646f75d01000000000000000000000000000000001192e23794dc2690d725ac29a5f80fcc528a5dd1502d9c5a9cfcee89d65a970c2b71651743f2b8bd2680598a1ddd6aaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e819477da151c76d988c4a75da912b33bfcb480ea191911d711fe4d71b165f113b55cbe3dfdbdc650b3239dae61ea50000000000000000000000000000000008d5f335edbe9ba3a6ff1b8a6b7cdfdfcd54d55e6744b0ff8fad564326b38021aa4e6d4d4db1c05d11fd76c51e5b90b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008295bb3ab4d47a93ac284f70ac8033975f47c354f206bcd171bd9cd3fea84e1714b73d59ad4a34fbc5224a38dc4822c0000000000000000000000000000000016755f7440bdaa84d68109fb55ebd9f6ebb71c81c8dad90f585d393e1f9c114163a4de3c198f5660d0d2d8e2c8f66e9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001270375d304a5caca51357a7f81912d907d3333724ed4c3ddd038d8dfca308a7e534858a603ed08fce84f43cddd64e27000000000000000000000000000000000590a639f93e377b1b8123ae68c6da7229f479e38451d34e25ebca127d6253600bc59e41555ebe08f997ee45f2b5c87c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019625b00530ad0a7bee5a2a0b546ff59100ea45e9c4ade5d657f455beb867396c71044c646b4ef3de197a578ad43e4c200000000000000000000000000000000127509ae3dcc6554b767f179a92fc71854e2f4611696eb62000798c8d8e9088fb5eb2fb81c96ef8b5e96e065e3d02e091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000afd7c2e944ea76134b6ccf20f1dee9b2964bfbe5fe3d9400b97c02aafc866d966586ec2f69a03afdddb37781b5e87ce00000000000000000000000000000000075514a486e8b6285a5956e5aab149596303b26058b4f1ff21516be5d01b648ad0b0d776977c5fa84e5fb16cae6526b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4979a0349d585fd87063f8ff7f5200e62e2e3f031cba9a11ebdf86520e10a51d17cfe9bfc7bc0e5bd0cccccb46a8ec000000000000000000000000000000000c47c030505dbe71d18052a43c900c7c80f427676f8a58ab7b080bca5b2ba9a4ec08c03488e057be49b03332bfae899d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a77b6fd25f61e605234b5acbb23706475a8818f6c3eabbd2e29250feaaf754b7a4f29fd1e9b1f371d7433d4a159fee400000000000000000000000000000000043d833c0426f052c5648eacf88116c20aaaa37a131cb2d282ee7eff437d4a14dc35c7c7623843e94e3daee27ea90aab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d1f77c8a597f9d3581e1ed06bfea5bc03de1de11dcf0eff928024e279d0212f810bf19acaf82791031119e33058193000000000000000000000000000000000bae6e9d1d2cf08f99d9b889e2d2dff9cca9218593d050b59b9797835bca446e57daeaeb79f02bb3b51f738ecefe87781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015de7fa8bceb9ae2b563b999b3cbbaacac43b4e77d8274fb7a46bcefce3c724573fc58dfe80b29a6d1659e4995bceb040000000000000000000000000000000002181736e09e18bbf383418e796613815ace04774d72f1c04d6761064bf1bd6c7cb41d90440e24e17a9a15b05fa7a32c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141498f37a372b19066352d4194844098660d0463b9e7cd673f6185b9329ad3356f0de916925db6b41087607484f5597000000000000000000000000000000000da1bd1932483eda4ce05a12f75d09266d5f9a1ec23d375d908f3531cf66839624f4bd6ff0cab075b47c3c09d586ba5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014941a2215eb0f711175eab098b6e7d419cbc7094cfcdbe22d65df3efc08a4125f00ea7da81727e7c3d19b7e6424fa660000000000000000000000000000000018b9898cf15de648b099eb29795e4a6b8fee7815823ffb2b02a5c3569e714ff933ce189d564f299b69bb526d6da8264f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001368f6530617e9fe7ab985a4bd6328b6d41b9c2f8dbd1cda3ac9116fcb6ae347082569b873c7733e8b4be5a4dbd484ee000000000000000000000000000000000d815277889bae7035ff6b94a619e3519ac63877e77af61b5bea747e553e63a75b362f13db077e9f8fcc5b0c7cecb10d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ee53df3e00e451f3e79ce22c12016e82c45bbca0571fd42cc91f42ea73e92e661d2b6c40f17ec587c5b25ccbd0b8f50000000000000000000000000000000001b12ba0c9b5147145d9108d00a3336a5e99535a97a0f33fb5ddbe20ea2e37180d83257b9aedf5ebcd69489c618d7c9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016483f851928becadd24df5e1c29cb7cb8f9b4608ee0106794466275f5a0c4250f949188543d22660343a44018c607ec00000000000000000000000000000000026028df9757edf3592272f31ee8ff496efbeedf5fe812df3d81b6b7a7cbfceb08ba2585a646d442c7bf47c4094abdd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004225bccd362b65cf423675ca72342e21f8fd0b39fd37009913cb31d650418e2dbf61c7c4d3634478813ef92382508a1000000000000000000000000000000000026fafc0cade13e6d0b974ce95f026d798b252af9b654acac2b186346907269e3e2b17d0a909a8d3ce7d93a8542b6111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014aa2fdb01e537178fffff81f9cb4d0b7fbff783c5300ef6c6cdc9229f800b214f75d85dca95f814822bbc60c8043caf0000000000000000000000000000000007862643d0f2b5a8c76118ddbd07c5f372f4e435be1953dcef7290959e4ffe8f9bdbf2b2c73e38269e6189877b86f2151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd24533521c65fd9472d5b761a1a8bb435d65976f19599d4b20352fb208a6aeed37e46333dda502a43b19d3796bd5e000000000000000000000000000000000157d2fe2c98a5a1abcffb55097dc7747f8b7c5c0c2396c426c99155fc48a5b95389a57dd6fe86138f6d47cda1fd07f4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa7762fc4910ce3865c79b9af7ec03a77fe0a37c63f8bc90f02cd8f7c57ceb6938c363c68c1628a3864861c6053e0fb000000000000000000000000000000000e11b34d529bac3a68f313f4e1ebe0ef3e4eba0832cd69caf398a1a821219266e81fe58b6fcba38ab11863c6c440d6f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b224603d40eb0dfaedcfecc6c27fa1e1111455276a1f2f8f9111aa5e5168474769e62219d7d99752fecb2f2268fa7060000000000000000000000000000000002c25b5facebecd99a9f6378352702ad959a033ba70727cf0ab7571eb2f1bd0bac186bd2db03b729d5c942a8e9f3f3d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005444c167598fc866718e4088671ed1b29a10c4172d4d7d2ec7e09ec896c0937dcc3fa0e2fa5413a813ab247572f9cb40000000000000000000000000000000007b4bfb0f3c3cb248709eb0d6da7a5856536920c22f294249399c1f551b84b8e2a323a9a16c08a79972e9444cf9d29411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7fe1b93783366021354f370dbcb20ca8287872989cc308c30023ff2088738d9cda2e9a9e368440d495d27ec7999860000000000000000000000000000000001606ac002dae9bbe6ac521d9ba07e6e54ff7441ddb5be6e71d8764f02f22f7b1e258758b0c44ba19c205add7b138a74c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154d45be3c664dadd1226ec88454fdaaa2ac10b9f9c046c9dbd5f6d77d2c684365a66f4602e3f7caf4ee6e536be8f5cf000000000000000000000000000000000f52d6324bd111063da6fdcfd4c9bde99a21fb0c1dbf50573416f625b1888d319eb9cf3671ef33b28d56523a67c0525c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109236a2f430dd436451539b9aabde6034f351c231ec06683dc280693e173729b74d8ea92d1a2ecd4c11fd8e68be94ab00000000000000000000000000000000119cf76a755d72a0773e87032414e8112de139df4612def0f55cc5d4d7439d76642b7907d4795e1b28b477f06df9378e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015044a4d4ab02f81022c9db3d0b1e1eddea7beee38e30b73ad802b42d191bde0ca656cee195c377ba07951b1b15de8bd00000000000000000000000000000000072fbc8fca0876ebc194c54243ec163757763fc66b1c70362b8b1c162dc9bda5894999373b65dc38989a425a0c284d1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c88cca6543024d61baf541dfbca6f48ef05b0bf8fbade4a81c6fc2969547a833bd05069228ee3cc1e6768319bff3580000000000000000000000000000000019d1cc3c83143b77ce1a20f48c5fe5bf687b104ec7b0b97f32acf83d46663903baf94e9b9124d09ca415148b76db43b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e0bf7f10be04b5dddf42f245d03144afe12e88948c3a974e3922016fee2657e8deaec7dde68c60cf8a5bb25df083450000000000000000000000000000000000edd46faf3945b0c1de820a8734da075b7d42e5aff88b568039001dd2009d6bb51400dbd90856bca8aaf16d0e8b0f4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a74ab8c578871bb746da95fce4383ddcbd959156127efc1bc4c68affd22641eb6ef769b940b5e75d7343ff8e59bb040000000000000000000000000000000014b7a57c54a64f8ec69f0d63f26216082448d94b6e7c818be7002250bf44f65e722039754f242dce1d4be908682369e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001538566e5b219404f1bc26b3861837b573c99398102d749aa88e1183b19463deb8070d433a12aeffd7e7bad0a25b75ca00000000000000000000000000000000118abc01e63983e0dccd5b7bd3574038ba300ce3be84bd1a9f62613eeb9f505d22b7f258798255c7db447ff21b54e5031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016280f6f4b4a457219687586b6add63aee7c7acb3857c563f37ee4070923ce6efdede605aa77e0b19e4178a0c55825640000000000000000000000000000000002e6bc54a025f75533e2106f95b549c5392d599385d0bea55b802b0af2ff2e80bcdfdb5921f289508debf770956ec7381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002529abd28cb1568fe810da3ff97eb78f2f7a62287daefa0b3ffe8a1bb8a7252d920ffdf9cb07022ff09fbcabfdee58200000000000000000000000000000000074002f6b87993cb8fe40289d125512a1ffd4ef5c7e20f9da64b0984fbb46e76210189ebc698e9dcaeefe0014b954e2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176682241877385411d0121d2a18cc4b6bbd306ee1f23250c1bf1449e88473e3d4316f16bf816bf66aa5f32e0267a950000000000000000000000000000000000bb13bfc13195be19fd77e5443db47a3005a823a866237a6bee9407330a0acc8962efcaeb9a6fb1073506b35043c51381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f614bfb0d77ffb2981a1de0f640e8b2f206b45c3bc2e28b4a0c85dc94f318d982d6c0f0eba6ac15f9bb7ae005ac9f00000000000000000000000000000000004b6804cac754790b0ba4d2ed4157d5e33f34115694362e7d8b8ab4f05bc032fd230f2a70247b623389b6c5fadad56b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b9cd682b8d91dd87ad0436244e65ed502533c941bc4b15c22e9fc8208d2b1680b2c1d565ab8ac691ef8cb655bea1ec0000000000000000000000000000000013ea73ade23cd244c46f696aac40cceca8bdeab597f1eefd2a245bcc6814fe4d3b53df11f3ac9a42b5b857b4cbde76ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ba355da5f29072f1ce6556eb28117c291a5d8359c5d660d6dac032795247e6ab28227f604fa695b9af360ee1686c24000000000000000000000000000000000514827b0c2684cc83dfe4bb118c039e37eb3afe3bcf925f68d64ec6c87416caa9e76dcefb8e7714ace1c77c5bd577261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001916e0188c580c6da82b576c247bf026d5e1392d387b8cb6df4cea23dbb0b239cf44ea79dc5b69f3589929d93b8205010000000000000000000000000000000017fa7a6980d7bf80c02469fef3fdf99fdf112980919b171066e3aaed1d9811b351998701a198212521961fec1e7774551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000557a024b0b23b267aab806af84a6b27c8ff6732aaf1238271d502dae04fef430316cddec2ce0300f579554cbf507c6a000000000000000000000000000000000dea331dc85f67e917dab59e56d019a788277eb35fb26a30240c8fab661db14c3eb60fe4a1484d6223df1aa1fc8f6e8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ae2edfdc30e040c860bd8bdcfcafe7df509cf2077bd05c9d4ede461d3c9e6cdf9feae6092db944d98c3c14d8d7d3c00000000000000000000000000000000018d932487fc8f30e5c61e9fed02468a78878f1c64f3d98893b0f8c52e71ed175aad2302a4e41b43718b9ccaff0b410b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003eab3a07f5cd5d920e849d09337b6bf207817e97b62d23b2cf29826a7648c6ebc21db032a4e036dfb515665f809089f0000000000000000000000000000000008d24682976cf230ea65e08d0f3914b37f0c4c4fcf0178eecc4ff7414a2dc0b4c2192f85e33cc08eae5a313d46e8a57b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ad461daf75d97fb4a8df3eee66ad4f4d52ce7db447831e627f4bcbbc1af816a4fec85c29b917a01878a821697c332700000000000000000000000000000000158024acdd1c792066f52f56b0568584cb14a0f90f34c2d45f2865a42649c30d83210651e0127b1df198175ce27047ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6cad41b0f57af2f22761f8e724a7254250d88fc8a7712780919b6f89145541c8baa2ab8248d509bd391acbd4f34b7d000000000000000000000000000000000cfdf55a4707bf285fb728fef03a93d5aa15ee98c7367518c8462593a8911896f4e0d507b39e5467163e8f9c24a479ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097b42c25098c874f981add61f7d5535ef4bff8fcd7d976029f168d25c64416d8b6a25412ffb87bf0b20e7d82b43c7fc0000000000000000000000000000000019a13745bb270a798aa678b0b74c4b298c0586368fabb350f8cc791dd850706a42f2b26f62006ff5f08a3e864e635aee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151bd296259eceb417c3fc4854639e42db5d2761fa2cb8e38bc5bff810ddf5cdc9b718525b643ea96cd53c75a0bf4bfe0000000000000000000000000000000016a156c0e5a87e06137724c3f8d42d07a69a667d29d3cb271aedca14527c28b8a92d3d057808ab4187fb8baff1608d461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003524700e29419913574479cc57b3b98f6ab23ad7763deddb53d8088c8c958011610debb575761a12d07ff0b6cc0fc3d0000000000000000000000000000000018d4f884b50e4118d718d6e90fd3e30150c89349fe78623f312a94b83560f6d5398bc17d898239bc3c1c3fd7d09becde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000caad01fbbf719a9bd921defd9e68f6d61e676006c8b255c8f8186c79d5bd31587a6c7c53e8318615f7818ef4e1e293100000000000000000000000000000000143af413792337ac93809609910e305352473d818e82ec35e58dea271d0aeac44b75cc40cf7274abf48b31aeac1765ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df6da3d6a58eba74e9bbda1424de97fdb3b712809d4c6c1ce7fbaf92b88a46031543efa7afd29e588c3f3e64dd19e650000000000000000000000000000000013829e5628dc2892a064cbee1fab272d6601679243d74a7882f49f7d99e2418b9330bd638da2f4d42c05af50adfa5df81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139ee51f224bdeb7925540f79ec64c18f7a0adc888a7a8ca3b52e9a2e753d8b20fdfede311ac490b995bc67549209dd9000000000000000000000000000000000dd50b1136453ea9390f988eb38004636189433d9f21bab248a8afa291bd40993cd2a347c10f6a36697f0f03bc791a461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c1aa318cb330e66ab65935c8dff53ee393c4b313a39ee498d8b31970656f6ff9a88327ef03f37586ba7437e2f86ce1000000000000000000000000000000000f8b56f81a587bf020d05368022a54459087b9ce2a9f08d6f33dec1ad5b6a83a0db87c4353e7d553609a4fbb14a626011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066e25d11bcb49ea88e24030e35ac832445922146bb4052a282f7b038ec0751c230a4c51f8a48ac7627f636d2ea79d6100000000000000000000000000000000161eabf9cb16be07fd6039357899d1a708f34ff2e67d00d5944d0805b14bc8b68c87ea1bba1485936e23457c960388c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dfcd2068333404ae886686ad38a0815bfbbc15a15b7d336d946f234e72080fb8439901561b2d483cbbaf07d6f2ca0600000000000000000000000000000000107908de7e77f92219c83255f36385f157fb633fc0d6a0e33d3fe05cd3f7ed9371f0beac7664075e25eabf3a0fab03de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0bbe3d79643b4f7362a33f603e124259c8242c36e46d605b5f9b9c6453a0a1340dfb6f594d975f8ac3245d4f75f8960000000000000000000000000000000010c1323859a92acdc936d0665074bbaff149b6fe597fc6e9bdfe546ab7f7a16abfc8216b7e4033c3b23dabab84574b2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002fe6bcf24d612628b7244f08731b4b111d21c2ed5a55e09fe226eb6ef17c32cca07d98173e6846b446cf652c6d5745100000000000000000000000000000000082468d3b741325ff23aca7e67f8635cfb305424b9707bf93e236a4e9f38f914e97e10263fe7885304bc52a2ea5748ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192b245ae5e8ca0a49b1671f6899122430aae5ea97781db40592874cb8f3cb9dae2f6de6644d4b9a3dd67faf6e80f9ad000000000000000000000000000000001291b8d2a0f27399dbd297593fb09c7510b2c86f2f130c565abefd1bda8c531edc7bbdfde907f1422a9ed71d05a8e2201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030ff7915fce335c6dce7a1addb67c3cef95205733d4dc00c449cbe674a339ab06ae017b3ee346428cd0d417dc4637cc000000000000000000000000000000000f818e978eaf89b99fa030f563fa82730d19815b1b229bd87739dc2a09f5bc975bbe2eac2a7be420485eafdb59740a5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ebfb93012319e55105060482abfbd936f72d7a21458cdf32da7422875a277e8372088cb2a0681c516dd1d182b6ef8c000000000000000000000000000000000794199bbd52aadffdfc593cf27462be8fdde9b36317f976a5a16b3b42129de7612b6e06df954945f2fc7a36e030bd431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7584da5ecb6e67240d5af65ebbbfb257c080b6bbda0e803a11d9d6ea7456611d6d19c9efc029d5faac9375e2c582b900000000000000000000000000000000118247e0f3d3b24a8b7e25a2cc35fbd76732a7ed63f85203083381dab82f8d2b08a80e576dfb89e0b0240131d5a3b5141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd15a4cc7cbf56844ee8dd963521eca7b30cb3a68b924bf7f9990c6336c8a81e30a4d799451fe180898a9a5a112561d0000000000000000000000000000000017c328b30266075142b7ecbcad3b9a1c57723e7b0d319e49d4679bbb0ad9ad408925ca5ba0ec3b6167a8c106b62cc5781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fed565b085aa69f74d53882868862c6c487b6f5d8b5aabc7758768b9e427d2630c9c943db28c9404227f9eda1e9698400000000000000000000000000000000152b36f7f0a26fff1b2536adef9271db799e9460f35d91cf6afb407d249a88092058bd791e85f4f4d92e95d8b53fdd091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d2da898b471acd292dc77fd2f986cefbde3879ccbba2907c25d87c4e30c80ad91878f7489f5bb95fb4d46e574a1b9600000000000000000000000000000000022c0ce5d5cdea7fcaaeda85382c695d57fb08953448118a6d0359d04af80fd85687f3e4fd928db0ce145e28923cb3ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dbe99647fd155fb471450021182cc0b2a43abb4b3665c316f2b9cd922c2f1434f74aa700533e0d7a213b6f38f505549000000000000000000000000000000000a5daf098da498e17dbab98945b574e9ff779151b42715c4abbe9e6dec12815d6ec593cf22be59cfa855d081a09d0aee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b312de236ac83b0cdbdf7b8629676348b5fcd56f9486c6a8529986fd3f490c87bf1bac96bf5cea4b144a62b20c411a00000000000000000000000000000000006c9a6bf77de583d8bfcba2c339e1f731a4f7b73efed715bd5a03ae20cf9221593e075fd4ea4af5346108250b7bcf531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141f281aa6fae698432632b2479bd54cc4b0ba599426775efaadaebdd56d906ad2463c6ea9bfa532a0b8cfc632c1f22a000000000000000000000000000000000e51d23d398e232c4bb9d10556df130e782cec4d1bbb0bd3296405117e9ab0bb8d4aafa9b7c1e706832ee1a922ab50a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df2ccc52c64e81bc27246d789747a6e208d07e879f93b4d93fb5c35f225fcac7ab80a725c2139d12ab799617350e793000000000000000000000000000000001114e4f01d74c81f08875015535e52493eefdfede8ed03392d06882ee73922bb930bda835bd40f7b1956328ea364405c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001095d433762c64e8eef7feca67c4f2fac4ff73d177123087bc1b695c9df9e4aba4697fade5785a9ba2c2459906a9d7870000000000000000000000000000000005225842d300934c97c5f82e5964b3cf1e1f05831e23bf96e0d4867843680c33915b41990ebc6d71fb976dd7b30b47c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f29b93d410dd7ba6c935e4686271c2abbdac185ecf7cc6c1826f9416d2cb77ea0497cdd1adf387eb72a7083304c69e000000000000000000000000000000000bc638439215f61ab6106b726125d22b6ba2d895af5879443bfe539aba0da005fa050df05985a042ce83f5a22d04a7241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4d662741daa14ff358c9eb48684e00d5160cb642fef1e5091a94e8553f504e56912cf86d483b6774461409713d69f8000000000000000000000000000000000b514d840864602efd0e0c7c17102e3dcc17c2f9c6939c187d5629a1796b00f1fd02622d58daffb493c94b5cf79068131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c68615cb39650f2ee35c9153c0a260a8f1daeb46cd102b5470a92b918ff4f484fd3f50ac4324588cee4975fe4c5686f0000000000000000000000000000000016a18030f49c2034a771d28ad4d525867cadf8a37662f4b28c1b3881556c342490d72e4d57f6d1271191c8e338bac9c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039d8366c94afcff0792e31b7786d08177899b177b2cf49bc77bb846fae62b11032fef60f058a10466d668abdf436c130000000000000000000000000000000001ba0b06c6d3812f0c40c3bc2c5532eb14a957739eb7ed05987dcdb22f7b52a03955c2356240c58bb04cdcc2e0e975b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152d0bb909c0f98721bbd0a9949d87e84e6cbebb93a832d320321fde1f1e2774e69a379c318d0f60547c357c228ddf8a00000000000000000000000000000000035131e801995f046cb90e9232c37de121541d2d3435a910e7937dd558326ec771bdbec2f65dea72ef6aa111eb2503231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000905c053e24816281a46d68e203d597a4fa3c234e0257ce069a16bdf6ef3078bbf2def1b47bf38e190860070b42f0745000000000000000000000000000000000d4a328fc86e1cecc72b3b773649eb5d08c03a27db631de89817ab4df8caa58b94cd6ec2a23d7c07a13a59783ca128331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085b4e19d8873ebabc7f89e4e8c3ac8e798cab339a1b7d9ab261e719713605d4ae3842e6d89e01e892ce82c44a3da69b0000000000000000000000000000000004a40dfb58ffa92d2639951c5d08bac4ff3f716e04f31acd29ba9af58daa60d2d0b8fe72c6361c7fc1d510aff39909021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a0c8710c77b22b733e3b29d08e41b14a16bd61bfd9b015d6552080b2dca8482908cdb40c509ff94a23e3acadbb15db200000000000000000000000000000000190c6bd189e34d78456afc8e88942f0e5025bf33ed7ac0b709c7a6e4bb0eac96e9aae5dae4abfd18e1178805771862061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090a5c0e3323e1c6052061b48b5c818b7e35e93aaa1cb636b111ea616b2478d87f2592dea70cc0e73ea023a9e7d30e7400000000000000000000000000000000184164ecb8b9cad2a96bfaf9491cecc7be26f8dd6d93edba11368a1225f8c918b0110ed47b5dde3000094b54c0eba9c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f5553db67bc8df3a16fff2e8ebf2799c182ff790b953cf2c564754720f2218d9bfc5f0c3824f90e53272d362359f30000000000000000000000000000000000ef7615fb1aa63dae3f7386a37b4959f0aeb94eb4352bb463e72bc593f0554abded1148b119b6789c683cca53e159f571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149eea5cd1f67ae195fff9beaaaab6b60dad42a50ee46195527e2979d6ef0072cb02c6fcbba112c87110204c19da85ad0000000000000000000000000000000006eb91e83057a0ddff5f23e9b1c05dff534d0903e2aaf63aabbd779559112cce9ca71515d2955aedf53e0f84ee8270f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3df0ebe61fd0f3ff1c82a5d1f46a600c3e22a5b3be0cfcf09dfc38a0b8e6f199efdf0eb200badb8e78c44aab3e348e0000000000000000000000000000000000cfc4e93284ffa90482a2267a5b80be5b6d96d8114378d8034593b5fa054f0b1fb8aa1a1e9a0c55ec2d7b390d7505a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a7e86f0f19a6792d4a3755550b15ccb179b8551bf654ccf0be13a5f2a581c9d6bcc90494224e00caf7531966ac63c7000000000000000000000000000000000b92ba8ed18e31a9dc0c193f1eb33a570e4c09f204e453dd806b385c197139c8ab237781b2cd2e340f30d12f946a5abc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012be2d05f7e439112b9caf67d305eaa9bf18c56442ec3e31d256d258f39ba10f7dfde4c1ef06daa2666dbc473d1c83b100000000000000000000000000000000180017de22f7bf27d25cd5048edc33de6a6112bca4557b43dac4a62f1347ce02285ca46158dc0ee2ca4e58e33968b17f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d01530e2b3758e5d7c1a7d6147c60f028cfc0e9769363fd41967ed47cfe58f45fd683b43f1342abf62ee4111d2a608a000000000000000000000000000000000072e55bdcda75f484352b0a5e6b6600b5e0db8d6c312e5d2cdca6aea10b36075b6362e65cddcee44fda5c9c3904e75f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5e0f7bc5aa1e4667b543b5aa5f67ad30fb4d312dbab4c47dab883c400717199a449a37f94e1aa84f548f165d7e017f000000000000000000000000000000000cc112b2ee9bd8adfa23db5e18c70b294fa48869f3524269c355894c3d4a5c6ae4ff38b6469194c9a2b34d224c5dc7a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000106de6cd3c22859015ea2ebb966a6522eb79ffacee4022dd6b5282477b7227135fdf23112175090d818fd230cfce6c15000000000000000000000000000000000d344b613b8c4e854d67992afc41d213afe3a19e55a64f2dfe2039f1e4a5c416d17dec1c56e89261bafbfdd130f6887f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009782df7ff3f34944414ee90615641a7821c97542094607abc7f3dfab22b64a6d516707b8492373c45dde3bf2f5db93800000000000000000000000000000000169406ec0c21294604d99c1725902a13c872d1c3044fc2cc6092deebd18e0bffac7699ad8e289f344207f5877b385c271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011198cbeab130c5bdf760f6f094151b24e9ec64145ac0357ee48c5ccef380cc6a0fb58e207949a6f9be49ea1986774cc000000000000000000000000000000000b9136a902506fa01d15a44e8d471c51b004da3011785e41cea0670385fc352390e8325ca9e72da537a7bbbbaad00ba61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae41dd6640679a332da47c1af423eabd0fe632b341d7bdecb755c82a4dd4b62b02a5df0224ed672c7c619bc626a6d3b000000000000000000000000000000000788240e7d611f7c485dc5b7d71b8a5f2c8917aee7c4a85bcb3e582a4c9a201f7bac99a9bbd2e34a7d5ef4a2b504879a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001696def9c320137916fd0b9b1b9d19ab244e58b605b031519c4310083d2552fb22a90ed6397f2d91324824aef2df04460000000000000000000000000000000003ec63070553e114ff2900c678aa29e0f9549f20e5da6455036771fcd74e66023d10a8d25373372733e603b54ede9fdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e640b74f26ddb8b588d13fb12183c5553327c75bfb782ce3f4a7dd3d742724d02131346f8492f19d2042ba39c958ede0000000000000000000000000000000003b4e0174717953dcc8442bca939c52a873431ea6b09fb65bf0d0a3b73913d0c390ae5aebff42067fd4ab31a7ba26ff41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001876fc58ba72b8e11095dabf9f4dbf968bdcd63716a07ec9b42fb229259e7126162ad0a3cdb7516ba5177411ac688f560000000000000000000000000000000017e9d8b35eb73a0a0a4156bbe417a71477fa63e69b51cebf2584b8faf94723ade364feab382c536ac1a0d24b3bbec3f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129ed9691b2e6ceec944878ae158920d1deb9136211546754dda802ce434c58174091eb91634588074db4ae991034860000000000000000000000000000000000ea71ba722ce7a2cdbac5df838065a2671ed0e2957c5bd26da8bd9480821508a4d40b307c3f6531ef815cfdd3277470e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfa4b48cbde7c8ec52282d70133d6ca0a91d2808d877e6aecff0cf5b9dde710ac066c08cd73d54b010b498147091565000000000000000000000000000000000eb67f4daaf92108d67461762da24f0d38f19cd30c4c00468d58c5cc258438b11d26044ebb17ea09d5548491239d02dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b728395ef8aa8e76d64ab8c3fe3c4c84c7453acf4fb6350ebd6dc261ecd4623d47e22e853d12ae0d763815639c61a5000000000000000000000000000000000d4d417bb7e668d9d365a86b85c0f0d4cc32e71f9821ab1beda614ac4e2f1c0ea03fb3ee93ab90a6347f03e540ea9b7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140466f0b33681a8b910a82b896d640583fed191678be5d732907199fb1c50225ad104d0a8a169bca7f2e0f4c2671ca5000000000000000000000000000000000e7d645aff38ca00f056ea179d7a429fc2725d8292b6d9c98dc9ae4bc45e01c8abbbe9c440901a8ee15cbd67542bd9361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f94eeafe1e3e73298943cfd105a2d63e05673b1ff3d7d26a01a4fcb42e878732ff04d70d3b02d04d44aaf1af4027b680000000000000000000000000000000014c52335866b9486b3fcf15f4058c4f52438593a0abf0cb8732343091e50c354076d813cccfd64c78eacf22cce358ec61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fcb6e6510efa55b0524bd8acfbc22bd0850e4c59e57ff7fc8c07765c107125ca7866887150648914d0babb2135d5b97000000000000000000000000000000000ae4b76e47b0c9860e4d0e38c2491e37b2a3dc15beac38564b18dd39475f278690d0e9d2ce5ebfb306e7c7d4c61567a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001967cee7daddd5fc4d6ab943371ffc6cd17810a86c4acba42df60b23009dd03a9a6e8c7fd228dfed75926149bf777ba900000000000000000000000000000000185104ebed6c3f7021769f346a1ed3a371f2dfe0cb5aa30462a64a098fc96cb621f9b1ae89756592b3a71381295cd62b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c73305a7ffe40d128443ce2bf2c09b50334f6c6c9c157e4ee0651906e39925f7a5002504d9bae4a1b9403de1a87ad00000000000000000000000000000000005bb37ceb07b3f9d9e934e054dd23f9800c6b32ebfe9d7d367dd3e2c0ebfbe04be4e52c6ee170543972ab89c1747725f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051d13d5852b41df0072b099dffe4387cf70675fadfbf4dd0ba2037d6c2103e6c1982bb6f7f92b834c15522bb23259f10000000000000000000000000000000016dc4dcc3a2a7c470be10ad62b1cc867623e9e6cf463b0fa42bafca48c6052106b9e8934abbf7c0c83a2e6181f5dad9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f21d51822cf876b8f22b239c7ed3e1bdd08e8048b028a100cecd98ec91eb3f157b63b4e7c2a0d5b27f3fdc6917a9f8000000000000000000000000000000001978d4697130aac5700a57ac009cf5a0f6597df9fab7786a9d07e5b2294d7bac364677ace265e859e509142789f17b031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004977b41b70966e89cdddd3bdfd94c1c553b0f3fd0b079be877cfc02dee3e4ebee7c64fc90b735928967d02cd513bbce0000000000000000000000000000000012cdd6bcb7b917f9d9ee7506a167f5e5bc79585c8296d374c084e5b8cba293845d66e2a4425c30e60dd23c137667d95e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ebffb5d89a8e8176449a52f79676b8295711823f3cee7c2cb89df889618a0ff66c9cecbe7c36929519cad8892ac2210000000000000000000000000000000019d425a2b105257ab263f17529b0fbb89da61e4a52a183a46b550172e1d83b473ca74c49d067092a8dc1ffb0e11b77ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5f7eab7f3f9177c697e2b4cae8825480d5e45e57969c68332d73b1bfa04048521d43325a2dfa94d4cd26a55f4f86f40000000000000000000000000000000002336c19d198f8a6f9332463543a9cdb15c0c77b5184c16a8d2d22491a51e996398990ceaefdc6471292153c6bdeda611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c551c5feebfaf414b4648304d99e1b8d37d48e9f145c3d3201f32c7e9d2d89b00e3fe957e90a51b83a5e8d4fc31ceeb0000000000000000000000000000000019898130e4f9c445db004fba23124a1ee6ef52d3e80cd0600871484019a9382d2fe5ba1c702d98fdf453fb82b5687af01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f7599c089bdb7839433967ad2beae71d79e620c82cdb3443089f4e95e25ca5b69a0b32e762709db2eaace4daa9645a000000000000000000000000000000000d9ba27c416f49f9180ecc07c19f398f76b63a9734e3edcddf6815dc0a1dc87e0c5e24606dff575e650e6b6749fb04e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b319d7e9c2c41151470dcdeb437a4c55d0ade6263534e0ee3c389b663e6d2a01b707f8fcae2f7ef4435141ba2021a300000000000000000000000000000000065df37dd0fa2ea3ac47eea6878ef015fbe4d607c46abc5b4f90ba355b5d159c2d116218b0867eef96436c89d9500c331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d7ea2b47c08bc6f0308a40b9b04c3f1ad01b72d43b9e42d8113b9645109565315d9cfd9819d9043e598400614952d00000000000000000000000000000000007314cf838a5841da4a14200bd458b895b4a33bb474f0c84abc10330e538e220e6896e0180bb042de95c370ef52f8ee81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005b3b06cc9d8e000397897ed3ea3e861cd1aed60a1df0da1c83cab35754f758022d25c7f33d036639a3b89c84109651a000000000000000000000000000000000d5cce8fd7835696e33376c3cf1d4aaa129fd5b352f90377a78748c0a917c6d05000253fa30a2f6ec95a109fe2d4bb291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c62345a6c810dd06ada4cdf46def7f872626ffe5bd9fc7f1975bc95b3ef6fce801374c4abe99ba63a1095be697a9c8000000000000000000000000000000000303e5d509395dbe0cbea3158cc291ae11ed24e4db81bd05c71d62f52857a80c10eb3d403b8a1bac175947b0010b3eac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e93b306f6915e80f8d44c4e72342aa97c1654a370e8f5f71b001257f69e5542030187e55bd3e72dfe344bd0d861b8b20000000000000000000000000000000012b8c04fcd4d759963aa80bda996a5addab2fc0c01c6da3619d00194854b46d6a5edbc4c6c3acfcf34f09721f769b3d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001087913294a69e7e8d383cae35f7dc81e15eab568c87fd5d0a0b645def5c7e9d936240a564966b2500f88fc1ddab3f25000000000000000000000000000000000258220e350aa832b764a28379b864763644c0d2baa5562cb1b22737f8df361c86c8d757fe9f298293de891edfe1aadb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001527cac4daf84915843f4aca14b8fe640fb4674b8efa7cd47b229347effdbfff4413fba4fb62837eb5e8e2ae9bef77d8000000000000000000000000000000000cbfd8ae00594dc9579a3415a3afa2c15adeb28fb9b76942875907843d32cf763908b1601070c3b053aeb2065ebc9ad71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c623c9aacbe26468e62c3e618dee67e276db94e0339e32faa1079d1adfaba6653897de0afec2b4758b63189b211fcf2000000000000000000000000000000000f85dca1ab2017ca545e4033d974e932a21b5f0152dc2154e1ce2365da4a33d2f8516a40499a52ee07e390336060cedf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000290d3c670a67da0fdb3af26f70a5c9119a330f715dca52557fe4dfc20c2a28a92e649bdf8850ee03dadae330296d4560000000000000000000000000000000019cc08c8ffc527b6cdff5f9f9722dab5061dc96d8ad2866ea72b315a4602c90da919339e1065f87e2649b5dc284984791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb95dba7488bf18858d1381676f9576c568eb715ab225ff8d25a84b20c6f1cd6dc8e2955b6a5e6aceb176293c53dbde000000000000000000000000000000001908f016526a78f89443bbf738e4fa1ffeee5f3c54985ff9f21023d4fea68db6ee8bbd1cb33871bb0b0033580b59a9371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bd2e7dd67bd0b72b2ce52ba841a45d7427f4dbdd3702fab3d67655f1fa0befe5385c7d93a67cff9eb6c6301a8ea766000000000000000000000000000000000273a0cd7c02e397eff19b1c49174e9de5e523f51ee2943d3ee745ad986f5aba92f13fe45469b20e7d805904c335251e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d14fffa74365ce47f872d8671399d4385e2d46344cc9a14affb3e6fcced423d731f854bdf3098c05cdd42487c750bd30000000000000000000000000000000014550a918c4716be361acf40f30e8c2a865ab1ee5f0cf863828f1c2da824379d248f2b12b578e60509e36029096a89bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fca0d6b4fbc64bf3c7b7ad70dd459bc9f7ff64716307da0185e3bdb59a13c9becf67e6265de23d6abd309c5dbaef40e000000000000000000000000000000001507022bd6b482e8a0fd144e3923246b901d38b151da1bea81937f721a2baed35d39493a10494415847aa0fdd793f61d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018523585204bc4c34767b0939b40e6f2f3f9f1e0e1996af69eee55ac3d7a162e395e70fd611beee50cd49e6a203860b500000000000000000000000000000000019f6b68f2e3c0bad33b7833994716170b576a9d2e6d4f83f9525b6d697b78da7b51ccd44540ff147aaa2fade0f2792d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005b286587c6293bac49570a3e812f2bd61d9798250e64cb03c7dbae219314a95091f80ae143381a8f14c689a2781f89a000000000000000000000000000000000cd122ee1c29d904e55b9a6722e606ab08eca8e4c1c897a71aed8c63821fac8307ffc716612024580c03be1f11a606d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001672e3fe888c0d7b3ded53a4e418075b089c350699db800a0e48aada4e7528323ce36827f4b651dd19bd95ea14bcf92c000000000000000000000000000000001567281433198b984f240f7d6f7f402e4dddd482d28e25ed52b499e20439fe8e231b9e090fc0514c4bc00878a26777121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020cb7e8427e70ab2e948cd8e6369bb14e8d7b6b162315a0bff2fdc5a556960020ad498f31a3955e5290c1dd229346290000000000000000000000000000000011de6d70f29b24abf4dd666a6238bcce1edb34e30db2db8b36c1ae283840dc863786c79a1b5a66e611d1cd711c1f6b6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a11b0c833936400d13a8ab4d80730dcefe479b61f4c97ac09a8ad58b4ba08261a93a1c0af925836bfe119fa07ff5b4000000000000000000000000000000000deed4977fd03f3469d3617fc6cdc198234e518ab156c5dec9fb105627567b205d1d0bc7a272a3453b29528a6acd08e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143aaaa8ab651bb89d17d18ea6ee102f583aa34ad7cd7a7878cd2df5e1e6d83c418da05c3b064d0e80a9f9f739b2b37d00000000000000000000000000000000147868f9fb6174b85e50aba1b4c6128cd07e189d57d56651609bebf451e24c0c4856158e3f1e51600559e32b3cbad95d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007842fee58cbc24ac42ff3746c8d43a5ecfd93dd72158c5942b4517c175925d28af09ee117108bb53c5636846a6adf850000000000000000000000000000000005d9bae9894ce88cc11aeb9deaf05a90837ab689615ec3675b2c764d09ae05fa5a88b30bc243b871585477d8b006cfe01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000224f1cc5e10b2d8c220f0668475fd291c41442f5ee3a49299a37a4e8d7d5ee4fe0b89082d16b09e0e7d8891a6235f860000000000000000000000000000000012b9f8a3a88b5c81e547211a2d80013ccc3825ef5958d7dfb28b930e9b944a4da8b21135ca6b170c98dad70297328eb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002062a534918e723df3a2a1301caaa1e1116786c297eeff9fb1a0aa7b99ef2c7b51c6d39e4aea555ca448783c95b7565000000000000000000000000000000000c85da99188215305c77bef56fce934a7d4af4f974c91f5e9a91e1ca256d367b228589dc7a950bddfdc2318800057f301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8d7321d6cf2b2c76dc6ff4b4a98acf2dee69476ed7b78283dc7cd1a0d0fcd04c2a3b90de5d1ef95185f544f32e8b3c000000000000000000000000000000000f1913951d4171392b87edef264734b9d153d9c48c5823835c741e0b1429a4c4422c4b47a69e063ff1d8ff6922ff70811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092df8ad1a607f1a04a89b881ebd706a459527e196835cbdbbf480600b9f9e49103ee959b8e4bcd6001c1faf17619858000000000000000000000000000000000880b331eb233ad98caf105c1cf0897b75e006aa78cfe5b5fbb1637594439ada00f8d1bf690b0844dd5de837548e24131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000531f33c95777ceb8cc9fd5e855a6315ea2858eb8bf670e65690bb42705e97d2a837749b1b140298400cfbf5a4384ebd0000000000000000000000000000000006fc6be9ef19afe0e92166c54d9b91f1f46fd44c25b7b03d91504b1d24b5d67f4fd13cdcf210f1001102db9b444585ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000425bc0928f9876f443319b37b10f6a57691ac8ed52d39b8507c3079f14617aa73c70b449aa5efe6ad5d770b3bd557a500000000000000000000000000000000125cdf5bbbf9dcaef25863e793460222b25429a7071925949133d7075bc04fe5116bf4a65c32b31ab0c4d3984a5d668e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005294afa3910cdc869cb86e52834f68f2aae860af51fba8a42bec7ef32769c779c22333f8e3d49df1fe9d5c355c5f821000000000000000000000000000000000f84a31b00b7d78ebc073397a11bbf1e36cb3dec9518c19a722f3ec8f9a157a572811576bbf8fa7fe68fabaa8cf309d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc03151ac5e58b24b4059aaa89e11829b0ff26b274d6449da57bfb39f77b4853953989c099e0b6bc122333af383d4260000000000000000000000000000000008672b42fc3ffdec9766100543abdc6b9506f31fce07df72428ee395593c23cafdb9ef56d868c6018ceb2c7467eac56d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144ee6b7e8f68fdf1a33ad95616b0290d04e0611ca6a833ab55f6efc173e0432e60f4fcc5b52b5d255273067c6d0384500000000000000000000000000000000009409e46420494fa3f32906e474e2b0f676ba42df9920084e7ad6b503d8e0e2f9f67a2b1cfecfc097225ff8639ecb1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003deeca036c9b337add88a5b9846c9bc6b91f587517d25d55bb08408375a76e97df82adb13aa6f6cf8218003828f1041000000000000000000000000000000000318958073d06b7a346987cb543a3bd536f5f386ab4b2d9812c8b62a71b658b55a13411d35a09176e529cefd668fbafd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187b259ed5d758e510b2969ac280b7d2747a3804ef461b6f07024f92c3322637dd5c81e0606af927c7eb453262dd9832000000000000000000000000000000000627401245469fbe10f4625a1393a92835d9e2060ba66e8e1e5dc544461110e5a1f769a2d1af7d1eeed61ed090e483781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001694b28c850869b1c7f2cb1b248504f689461d8a7921ffd62eb1f644962735e3fd4f24d423be1f1d7d8981703ca6bfff0000000000000000000000000000000013ef3c6c5083e76c1db4524dd46b7273161e0d2e24e8198e63b1a0b55900484abcef24baa25eea43ae3e80bf755f52601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc89770172cc9971cd1cbfcc0648d55aa9af0b7758180288c38f933a0d7a08855a952cf32e38c769b579195c311ae2f000000000000000000000000000000000ab30469d47c249a718e1b63beb375eaba0035c8cf2e5443156c702090ab5ec1acab7ede3565bcf5d1ba987241517da51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b33e042a76e20edf7957410ebee0524bc0cee1ef544e0a005510cfd8316e5fa8e5c2858f8bfb78d9d1f2a7ff83fc8c00000000000000000000000000000000118bcfc10fa5beee740783c68dc484a16233d9baded29538fc968672510560d10869cade0429896f10059ce6611826011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b845cf04ba465565c31d4ae828625790c4eae943c46cd950d88a34c05bcc38fcd5fbf4aab38ce439d1b2bae21ba0f6f00000000000000000000000000000000171090be1a8c2f4509fbe1d91a6fd52d5673ff809ba9cfc5d01c3b0a51804f631899ec48bad485ab4d5042be19994b251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189c4a7f1d492e39cfef93a099279619f02e356dcc8d23d3e407b278c0e476d02bdc5171eaf782f8f1d7dc4ab4b73c6a000000000000000000000000000000001930a1d01ec9c737b99910b6e1c025ee3a981990998661c31d064223620f6bf13a0400d5ee04b7bf900d1dca34775a6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010040d2aaf104b9d3505b564366d01bf94051627a842d506e691a893b79d26a1b9ba2d3c696484508530f062166574c9000000000000000000000000000000000441a52812993acf6b648912910d2392564f54a022f3c0aaf3bb1b9581712486b9a001672fb3ee93497b1db4b355e17f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9c1e5b9c7c619b1782bb7e75d6b8b1e431016a485b17553e06ca1058d659f39ead9e9b9d69fbd7aaa43a468f3e1ba200000000000000000000000000000000045674e0327f4227be907735af33084f84214b8ab8c18bb22bf0625aea3be731830a6ba4fa86cf619ac4c1f1bcbce4ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000197b52c35a26ab7ff14aef8473582d79b80d9abe0ddc4362928c6025c52c5ab8ac44553c832004105cdeb01a828df29f0000000000000000000000000000000014f7d1b955c56a834558ebf58604501f7a69a14005dc1271dd0dc80475d95e3225ec0ee8811035eaa0a71c2b9189b79d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8e59276c63fdb451c223905578f8bad8d424f8aa19f99597ea444d24a77fd37f092886f937b0e25dc22693b358fe850000000000000000000000000000000010556f4d80a8cd9fbd385a86e53c03e3a6cd76b8d12beff4e9f8c6f030efbc739f70460f252540a8427e8503acebf61a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001324e5dedace06232165b0176dc23a0194085c722b8dd8f5350033250aa0b266d418e45eaaf980f2e24fd58b2970741e0000000000000000000000000000000003ba47e83a0f1a2779a37939777949440c8e4a02dc31950326a1130226a32f195f612d2590d8553d79b623e94e41672b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090cddcc6bbcc16e29874cd209debef6b6ae105f0f0f1bab8613588e3ada67e686cfe77668d1ec593382506752077ef90000000000000000000000000000000010e5636ed7e901456fa81e4e21068e63407c7f07e510543a694d8a17d1945da3ba9a620f9bb98b0d35a8fbcc5f9ba9f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce0436edc3fd7295cdd7ce652039ed650a742003201bb26ab1c4c97aead5f02194e42251f42eff28962f53cd0956fea0000000000000000000000000000000018bea5b9ae44dfdb73e987bcddd6c40e8a7d24fb779c72eddb214bf9c86225af5681f4357c1a4fca89c5bd7aa0afd19e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001258b95df4e8f29c0c27b5194cf47fe5255259ec0e3a3b97b895e06c9ad4c8bd32b4543547ecee722d6f2c496e3ae206000000000000000000000000000000001897bee3143bfb78d5a7514b582c1ee923ca9ee534b408ea1076a7fafd957e3d3f1dda66406a7a3af484df707f4035351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aab742d2416c4b241c5337e20ed2f7d096c707059c41d183d249d52c40c69e1c42d08fe2022902cf8f96d02463bd86d00000000000000000000000000000000190137f2028bc83e97becdd7057ce2e05d7df460c5a7b4671db5e4f4914fcd9c25aaab50d891c88eb7e4ca72a582c45b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a228d19ef65011d60a01123de1d5f1d812a94ff5f555209b21998f2ff9f74ad9bc46ca2a238c4953304adb7e88bda20000000000000000000000000000000006697bd5eec42e31f621eda979a37524bb47c69dbd434ced3fb1924014523bc40f7423d193ae3436ea064ca28a6881931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017288d0d65190656e9bf3d1adb5092d0c41e217f480ca2cf22348a8d92a602daa2fea9e33bc62bb75e874e9ece0c42370000000000000000000000000000000019783e0291416c6dd719e7c5e2d76caf8a7db47412c99f007fa399f5aa50e6685979ea29617bbe400c7ece6ee362c1d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e393e0b715eca642fe6c191083c9d44ef567888b7b89d078638715a13e33e6c287c015904995b21884de4cc1250515000000000000000000000000000000000f667afcf51858ff0983d10d04521b3e3063916fed18169b5880087e21fb8bdffa627dd0277dad5afc86f8c8dd3149be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a164c4e56854b445c68c678444aac2f40d2ca1429b6434dafb9fcfda201debfa07edd0f98f31e0bfdf3ccc7b1b66aa00000000000000000000000000000000112f0756b1d3309209b35d419e95574ca27ba45c6627a335bb212d65a33513522ffea2ee1411ddb44a25318a4881446b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da9fc4e942b288d2f5210def20ff835382ad5ba401d976c95ef455944700ae4a292e97b69c93e91537638a16cdc5f1d000000000000000000000000000000000247a1d6d3fda87c736744292b9c3f7400aa54542ab24f067036fa64831464b79caa31f3c45e97dcb14b8fc90a63b4771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c5ebb0ffb77edd6f75b3930c2a191e5c55c9a5e2e64faf95b4d2341e38c37337e445a5deaf13b878b6b2748849159a00000000000000000000000000000000154fb71d97a4c029c47fe1050d5be513c306c017f15d2c7e401a3bcde7a6776a822f5b70a8752c344202c9f695df4c981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008698920049fe32475f0f1839abb13530be46fed39244d54f18669c30a9f7e1aeb2b48df2d5d12aaed16fee19e9f64720000000000000000000000000000000017754c1e7df72152d4950f1a413fae9f4a5263b5b57c61149ec1d2a8c2bd1987f4a3f9d9235cd3ae17a868bfd91266041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182a296984baa54be20ed116741945827dfca7885cc41c16cd386684b6a97508aaa1b7a482d943eb686653973beb2b7a0000000000000000000000000000000000e5b33a5c3d0333e7ace47642b71a4770697c3d5b7d7f395091b02470ee9265b16a6c10bf17a0fdad6ad0ae879ed4891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c20fea839e22e38339cb9bacc6fb4a458045fdd5da9aad6e3e888933d913c9ee548d9e3dbaa6488ec0cbd252288e856000000000000000000000000000000000f47bba6522eba23618212b2f943511a9aed565578dc216cca2bddc1a2f7372b1e4984a7122a40ed2bd19cdd7c6318081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a74acc772cf806a2716f5bf52207d8991979aa2c0cab037c190c6dc03e5bc70c9e6d6e91c33fbe7739bee721f2370d6000000000000000000000000000000000f10e3002c8dd14fbe1e87590b4d6cdcde05a76659405380998bc218137a97555c79ee446a04bd3d73110fb1253e63c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011446c5331b9f762e508f5c4cc13eabc6078b206543e9c0d74525fc042f8c52856c58ee3006b439a4947d4ad1e72b3790000000000000000000000000000000000700ae4004b9c7dae224e4278a22724c68c7b225f6e865334066dfbe5e80a38e8838ff83fe29d5b1d2db6acaf4010fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007abd52f51ce39885e25cf397d48fd79dad99d66fa40fe4ef3ace7261199b02a183af4dd5e10e17b955c2349c4d742b20000000000000000000000000000000015a412a47d4f0d5d0ca3085ab63785b135dd545e8f122beb6b0e823b6cf8f1b83b216cb8e8957379c755b1010af61c1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001041146b3d05982a533547ea7cf05f0bdb8f6f70e73820f65aa87bc2b3009a154a232b94a61f8fbd5ceba72a05f5a03b000000000000000000000000000000000c9d8346be09eab6cc8b58ed6788ad8f00307dec4a48cd59d512747714511385b930e4cdb3b8fb5040c1910c04ed11c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d2ac62debae4881207cf5c73a2582df4d7930eaa0f09e7cf295f4c7a0e2461f84eca06e9dc7eec2f70e5cbce959bf5000000000000000000000000000000001628ccde7e966d29380fda2f7d235af0e3dab97fc66eb3b50afc2fe15291608082b64700e523de33ad3dfd16f35321631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ad779e2c7ed28614dc3c4ac1574dbda71b936b6e5cc8efa5a1cc191400250c91b0d3d1248ac2ef5a24ad2afb83dfcb000000000000000000000000000000000f9dbeece954dde2dddd4cb9d0fdbf06b5e83e80d67f98a1fe00c24bb76f5138d734ef2382d44bea9155f1beb7229e7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c9c42f4f2869364fecbcf655f4042a93367058526bc9790a43f302c00f75b0a59d4a35f96706fa045e90d5b52fd2730000000000000000000000000000000015f8d2c8406a816040b7676cc7736fc7e72fe2677ee755aa0002c9dcccda0648082d6625b3e072d16f79188022b3118c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1abd8aee02fbb67b01263efbf8d5bf6069545bda04868698863e00f211368c17bb5668cf4fb61903eab0e8593a780a000000000000000000000000000000000e943966559d670ec4feafc6e069190864301643b8e1b6131ee1dbdd8745855e6a11470ef62b1ba7977a0a26e02c20931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ab552994f9141375b32b4df1a4f016558fd679c3adf7c7e22b38e0e099a197cf908a39f97f7fe470446286831b54c3000000000000000000000000000000000c8ab44a0f76f550a8e52cd9acca3adf5b1073c13a3a3edadb87f08f702d96f63254334e097c9ff6f7f8ec71760d57941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000406fd6ea8da815b0077d6900729694574f47118fb3a81193fdb37db5184c5aaf20a5d5cfa268d72846d8f003a99bd1000000000000000000000000000000000ec97b2a9d4cc02cc67242e36bc5b154d397749d093d4e0f22ba15a55207af63ca2a6d0cb6579dcbfb8a5f4ad10e6bc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f99298ecaabc6a46b64aa0388d94c3e243cbf575ec1ed9c13a7d99a6f7856d95233cfcb56fcb17546c3558b1934726c00000000000000000000000000000000036b9080651bead33696eb09448a619dac90acf479b0c21a5fce917b9c26552742aeef1ffd198c74dcc89a5a45ac7a811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113237968a4c576cecdf9d3c636b24b48db3215286774920330f223b20dbf0a873212419b749e387d0033f2ebd0030ff00000000000000000000000000000000193e4900863772841f9b5d3e6083a784edd2c1129de7bb4ece6598039d2ade494910a4b94804d7b5a1368bc5c86ee5aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001319888749b5c4109a4edd94223623da0093bef0ac47e3a96e2c2b14947388f115acec1860173792283cdfc3a3b65e4400000000000000000000000000000000073f218d630a3aa202c92768f8bd8afe89df47c15e71aaf87fbd223961301414e35beab334f5dc31cac6b76d7caaeabb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071e748a86bff323f864742355627e82adfef377d0b566437694659d2838629e5ebdf233fef455bcda8b4738e9229ebf0000000000000000000000000000000016c150499ad747441a60d85365dd95d1e942ef94479f183f798ff9beca4a396a21565b11f62bbc049d4880d435f4370a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e89b8c9e9f150d6aaf476d186ced069d28324321b86a183590182a0b8ce56a328d6a285a7223cf97a016b3fef229a1b000000000000000000000000000000000067036c193f249eadba4e9d92de2c5957ff5cf0b2e65d191cf826212fb0b81fe54bd66e552ad9c866d86fdf7e96c2ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010eb76e7052a6c926add14ba61459b51657660f6e1b7e4dc1ba27b82408238cd44eb4644f6ee949c41225f288a942ac100000000000000000000000000000000162172b68ef75a1a97ab47474a801b21d670e06648914f26a90f3a9ef863bd9d1270a3f7c7fa6ffd4a97558779becf951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182f4c58c2f332bb0a207d08c75f84ce79d76b8680ecb0f09f6f234da4a6d748520b4527ca92f7926d76b7f108a254c70000000000000000000000000000000001bf543714e255ec0f2eca033915ee1eda3890764b20c75533ceea91b46884c4a3b2aad7032845d6ce9c8f37c64ded9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160294731c3da52bc00a61084e568e488bcf1a9dbba39733679e7c1c51da560cf01e5c0311a68e47841a5cfece41a135000000000000000000000000000000001212277503175f22731860090c92f56251cd3bbe06ed8235b253459c77bdde9ed42570e01e41a065f59c6497170b8e1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019505ab021c5b3cd703f076d52aa2bac927118f9e3013ff74d2452cf003a10e963c850724ff8d1ad083bfb10d6504479000000000000000000000000000000000cf1a5fbd75abdba47feb39e7675b26541364d65f73609a5d3f36cf8fe6dfd2d8970fbea034ff5743dbf7a0bb8c4cb9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8b14f8391c7b89b425914f5c46c42b52bbde0a23f00e59ff4cdb434061d7d970e2f70692676beecd6bf96c7c4fe3140000000000000000000000000000000010bfd77b6e8e5de7fc7d6aadc8119490896c7534194c2034128073e2ce7605c4af16bc300391cd2c29b3866ec1c4f1ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c15e60a978840f07ccee65d82a0801e48f7163b48036d992ee412dffebec86f8bbf33f6fcba1f8b379cfb8120412d10000000000000000000000000000000002f821132d589f2303c90a39128608f01766e302125c5f813e8865fdb755cf572afacc3025bc691f465b34abba53993e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ad1e29b358c2a627db496d0b2acb0726ac1f31aac410517d23039c6ca73718615736a773bd6480df74293df1c962e40000000000000000000000000000000006eaf5248e177d0568b294b228112fe7ba706478dd726a43277ff7364b62247810bdbe325ae8c20b894fd59c55f74c961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000729b6c8cd2b0de947bbec4ab130ba99e39abb2b145f03a98f896d4d60628b54c5875be3c612000b3073e3205daac20000000000000000000000000000000000e1464a79febe8e2a43afb2be57efb52e75f4736035b85bf6548eb910e89ee605d830f73f46e27635df0d233e944feb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b383fc01e9376677a8caefd9bf2e5ea7defc37eb07ba49a71a524fe861030e7ef2948e72613fc63f95254dd537b0a1000000000000000000000000000000000e8ffeb60fdb72800c7ca1ec810c426f402211b4fb024cbae322dc97d4719fcced67f107d9ebc2344decefdfca7c20661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123ef984064c03b19cbb95d762af67c9d74c4c3d59f0677a5518ef864a98636ff5ca6ed02374624e11f692676829beba00000000000000000000000000000000179ac3a2e118304936748658c3a5159b6e77152da5882978ac157313592526de48057db17cb44b87c11713f6bc770f671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000006b48042717697178a568f1796de736ddab8414fe53335382fc6e6690ccf67bdd5b21d3ba6940c582f17582a29918b00000000000000000000000000000000048ce9f11816f7d857fd0f6ae2f53f5004627318c928a484756f64a2b474434feffa60e7bbf5e80bc264dfef98eccbe51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013bebe0fafef376ebbf5d9ad4bc776d80be98a6a699fe533f62f6d701dcc381fd6490068456c37c217dd087bd02e5615000000000000000000000000000000000093ef6f8126bb31d1a9383d1e41fb6696a339b6386bee423ad916e6f64f1c056ac4484e340f257479c1f2311edd324a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000070e4a3e060b9dce04b771a23ba32fc0a0ddd346b16d476a16a22e3ea9069c625fb95f7b18eaa6963778c0f86ef97dbb00000000000000000000000000000000064d794f438aa7fb55760c95d3080da44baf278f4fe84c649ba2910a9df1aa3c226316d895586f8008ec70e00795f73c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a72d7c154db16f02cb2c8fdd81b0263775a68f370faae2692e7fdb8f67d3e205f7b952591845a096bbf830761dfc3560000000000000000000000000000000011e7146dd8407bc3dfcfcc752bdee0d3e0f2a91911ba365ac258a4fa2b9c147142294d8fe4700c2ac7add3e0a98386991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019af09fb0d44ec9a4444b715ae09bafb07be6fd30c9296a40d88c5590c62ca0fc6181fcc4921f7998f30aeda9f79f06c000000000000000000000000000000000ce6d2a3c377a02f4d6c509267c851fd1ba8447e448f384acaafc5582d635809f9b69fdacf60a0ac7c10e67f5a6c52a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d95a599112eea3de63db72303c5eae91631c3b5adc43ee200eb92434f378a4faec684c19f1e50da34ba11df93e1c67200000000000000000000000000000000042caef535d0942b4e4a865a22ec037829dcb22c0ba4f6b1add51ad757015373f138fad20374cbdd4caa7e67390a8fef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef26e84550832884fa6a572c6b296df12f68bf491c51f6dc7bcc9e19f64ebd02bc300a5d51556d6276fdcb6e68f623400000000000000000000000000000000155722b4772ef115fa4797a43423db26fb4e481172e480a5c437efaf74fb1f8a21da3b171fefc0c8e12cb5e340d79d861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001258daeba2b2b1a55d60fa172b0178103bec58362825d7e0b86e8bf414a93bd922a28099aa8701e359b7e03e3ad1ed640000000000000000000000000000000006431bb35150ac8bb1865b07f5abb021cd5df0eb7bbbb8ee826b26c5f5bda1a90079d6d527a9b3fbfbc161520d4e93ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f225ea60fbd86040d99d2b97431c368f1a05ca81d86e9fd9b5022cfbddcc9cd1647e895ecf527dc7b5d910ea09e49a00000000000000000000000000000000015e25141219f28ddfd695773a6f8a16a0b8c3d1f33fc45aceddfb88a854d26fa68b92944e8c24ab7dec89d12240454a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca39ee0f5a37efe276e25f3c5406cc07685e9a050f83448ed0dc8288521970f723ad587cdbb4d516a16bcbccec7e3e40000000000000000000000000000000001ffc8d99ef8eae221ebe1b750886892c13e63f3eb01c4e8bc416d5e994867a6663be09b3bc91684ed6d312e18f129611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ea14cb26bd057de40513f19fc5c3f711940fa2198041e31a1607bf489981a9e23e5357b143d1855e9586f167e3262500000000000000000000000000000000191c8091add5b1fc56f8804afdfccbf9b00cff1106bc3d8efb3a9abc1137681f9d38558d9cba646ddb5f7cca72bc67d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058c19a357cd3c4abceb502099bb9b3949040ade89536a1cc6b2eacff66f32773f3da943ab2274e800a0da82cb63bcb000000000000000000000000000000000008ffa9f887459e0ca67141b6e693e9d0ec0865e8c7d0a1cc8c5c67eafe72c49438fed2727dca568a4e94a33ddd852571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d304e9c35ef0143a96a2a5baacae7779632a537187201aef6f8e3e16dcfbd99d6470022b14b6052de6f9de47a53309300000000000000000000000000000000076abe43b041633c97b34e9e0c464d876743572580cafc20599dfb20d69513ae568cf07fce25ad964c883826d27ce5db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006006cc74b97b2e34a7154e076f3ab914276f639daf5dbdf812379ff220cbec7a826011f4cf91e7b9159065ca6ea72b30000000000000000000000000000000008f58e2bab0d8762a6ba35c9db59252b8069c564d60efc7c7802253fae95a3ee45698df8669b3447d5090ed9762315031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141455a3fb08e272cca4d32a5fd86875b1a24efb0bfaddacb9e3dc4d25ddcdf99eec96da98eac10903c3867b2e5c15960000000000000000000000000000000005b987cf14e2a497ddf1cd8f8e85649e550bfd5b4f470ff3e4a345b55d06211a6b89d1f30d6fb63396a537dbe10258e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e1fa520aecd67d2e454b4d84e03095c27d7153e045a651b174a0477da0971acb62db5f22bb820d15ebc644120969840000000000000000000000000000000000ddacc8352f64f37a74edf1c7000d2c72bc98a03806ad92520b65e75553223c0d9b55103c96f5bde15d2d53ba348e201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152be34330705962bd191b148e0c80432f9405f3bd0f7d167a80b863bfdf6d6237d6529290ac8dc871169514053dff11000000000000000000000000000000001697c291b31fb317d31f903442cc0012b444df787f24604d53d1128706f1178a2d05fe727c0f03e533fe652062f40ce31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1e9efdf7feedd94b6a854bde985fc0d60396cd7c342addd40331d2d7a1da202cafae5d447a4cf0dac8c22dc84b8239000000000000000000000000000000000412619988b5cfec5df02e409146650de1ec4d88f74e8a7a4421dad1ab195ab6ed0c4979dd237a65081c1bc844d57f551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017aa7017f3a991678cc987549d75561c3499787d13243996332dcd9cb1a8c68f99d32b4911b5ab803b9f65f7a5cf9a360000000000000000000000000000000007ce2ab399faf1e44b538149ced698698a764ac29aea52ec480b48a8b00d382a911ffaa5b40d6ce7738fde526cc683a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183d7a6314271d2909629a8fbae11c8a9497332fd0f1c5e3520c249ab6907fe369ceeed22bfe9bf489e119af67733db30000000000000000000000000000000003b92151d6d9544e76c6f6a8886614cc9be9989b80b34de25f9e3bf4ba6a0cea8aaa9f90d108be50cc3d559a48c72eee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041ce57780da4d47881c7b5a8a0bfc1a2eadaf4fd25605d14a7da5dc95cc2763c2cec81b02ad2fb45fd72d4d14271b290000000000000000000000000000000015fef4a1a1862a7ce4373d64b424f876f800476ece6f95f94602364f7d555adec687f8fc73fbe5be856e4d882eae1aaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001931f8a633c979f1ee003bd6e08acd890842b8bf4151afcf5250453772ed3de9fab58c10249ed7f00c00dcb17f421d00000000000000000000000000000000006f443c7f712f99b934a00648cad0d736ba642cecc147b245df90bb2232b535da55dea0b9ef75b64fd35b267fac1324e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019773aa35bf37396435a4f4ce0d81184314bed7d262ff85255999199bb797a1e2475301aaec7dcd8569b7fe12ff109e80000000000000000000000000000000003b95396fcf4c374e2eb8e00c7ac5cb91dd20c0ad8627bd5414bc2021cea4d7d47ea592c7f0c54cef0cb5bc1584b25191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fe329c53d8ad8dd8afa8bccc63838b2c719909fa9926c3f57c4b5474b77e16b6b61cb4b30a39b875d76a6f2d00eabe0000000000000000000000000000000005a756cfec97615b844a491646c542d9bc9453de1290e8169865fd87dbba3e46e9ede7e56de643ec263c95cd2883b2941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ea7182034f6dd06a2d767efb0b978fcbe51117eda9eb0ea2576eaa3dd98b56161352b7984e3b4eec1d94dafc9ccd0b0000000000000000000000000000000012f3d4b1b196758bde5103cb54d084e2ef6e335f2104307aa4c523bf6f9244e9744245847ad5280e138fd44d36f24b801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170127a26e684d9c343110786c22f6de7477cd42a8851ad6dbc00be4fb9259ed97877ff5717e2f1605d8553cb1da2aa30000000000000000000000000000000003b1c7add0964bdaaad8981871ddf74682d32d77ee0e6512d99acb522e4e9dfbc0ddd3c8bc0dcc63ca5feafcf35cfb211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091f757178a65905c64f45ce6cdb8fac2fa4fce1af485d0b2982d6681d33bc9203149ea0e2138636af2e09da8aec69eb0000000000000000000000000000000016372c1964a4ae6e8e22800838c50328fe76c223d3a7013bf55b154a89c8565c0487670ad8d1cc6e06e0b20b0edb53901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161df9d10203f549071b175c0be1a98892478e48eba1c7d65cc471bb28d9ba08b1d93949cb66cb68000ffd16202e74a30000000000000000000000000000000016d58c2cd8544b773bc27e0aa96dd0ca06d2aca9e8f5518007df5cc6d8f91e6433253ab6a84e154d2ee333a6aabb931b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e8078d8b90bab73aca86ad76ad90a11a2707cce2a46148183db7042b8bc307848754acbbe9df379c63defa912b588f0000000000000000000000000000000009d693e5202e28c1e619d30078a7b9066450c88c207d34c2aaec282509a240a7a73b75165e5ee12b60cfb2a557def3621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae00881c2876950e34614a7e8bdd9bdfce88c16f877e98feadfe2929b49046d1bb9ed05a43a11906d749ee0cbf8a70a000000000000000000000000000000000d499b4dd5c0bf2f6718a7a1fca08958f25873c48b20238b2fee93f907d6e698cbfa24df0d59cb0a88435002f2bc30c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102a9cd6572d0740326b2fd0891a47e2bdfd095e7ea0f26f26d626e9574c6e8c67ca0b62414e440e12becd8f0cf924370000000000000000000000000000000010388d4dbacc00265b4821279d2fae1be530ff75e3614b7d42a46efe2264ab034c4ded09888d1b8c750820ac581392281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ee34f4a2cac2171bab347bc78e837f5852660ea30b372b0a670e85d815e30af7ccdd1ac6110443e84ca8fd82a3ee380000000000000000000000000000000013a61ccaa13a8cd1f1e43e570326656707f4ea854d68e9e77062d7fa2c24cb257f3173837f6260429dc1d8970307df161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011320e22478aa33daf67f60f7ee94a1b9fecb8fa6cef70c40828d140692a30b0d07a03ad9bbfc2ba1e5f6c33022fc8520000000000000000000000000000000010ba3c4bbafa276d1434f1ebfe0b2541a93cf533dc2400be649a63a844df637bb8f6a52185c6becb3dac2276d7d659801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009afcec9996b8df61f0a6bd28573f1ed2f1e7881214484ca80b91b43b2a369b6d6a397ee1904554c32cf918a458eee7b00000000000000000000000000000000016ad065224ef9585138917e75cd13e32c2ed74279285c6fe95dd49c02cc7b6cb8347a648907e01d429c1a5b31a45b091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000043b49d7424947ce54335f9b0dc78bc5e492dab7104057e7a9f80097bdf5234a6e6c0921d7a6c500e7b84872c2da7b5000000000000000000000000000000000b45c1395e0e62f88875fe6b63384778dccb0f978d81988da473f388d7db89d79622a70d07426c1ec523206ef1cec60d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a63333de9b4f3516a06b9808fd43ded774dd8d261bc0814ba4970cc994082b97602cc7e9eb1ee651a4f6d509b7e77d0000000000000000000000000000000000c86f7645b8905791505220dc1e4a3d6116c39c1a29bf2d9e41d7acde74c795caa5605a70abc28016c0c0d7bfffd91d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5df07978f05f73f53109aab6434e994acf680debe43d530aeda7e3648054e7556ff018075eea36a2e7ca33a586e21700000000000000000000000000000000049d70eac478f1a649a2b30cbfbf59ac685c6732c8ff694e97a451582186867e2062482a504c693b1044330bb0a12fde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7c523ae2e879032e992f47f7b955f3b0c5aa83458dc16967921d77cd6b1725e0f433cafdc10d8d84fdd2872e8d5e73000000000000000000000000000000000384746ca5b42157faa5aadf86c403b181720b6119b1abcec51ae58fb868b9c17e87cd9e6388980c030f0db9c49079451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136d56e5dc87be3f279521f248cc2bd04f2525b64ae4a1dfc77c49fec5260537d542bc821f70f636d05808bf5260651e000000000000000000000000000000000f1cfd5cb2f0e05559fa4c3ec2ae2bf55a36a88df5aa0ee5191ffe4c8deddcf6cf21f76183c64f474b1c7808460006731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000561b137ccd91fbbe137ec2d46798438b77bc8371833e4f4053812eca9bdd67dc0cd9c7bb8bf1f42a9325e83f24b233f000000000000000000000000000000000b70d988aaf182b51de00bd801e11c68f4713f48fa3002a94b5539b100b0777c2e8e2e354bab037b8577f308a7e02e7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df13768e7007ed48ee40ac965d6b223a0c15a148c2e881624b4b726cb9cb8e149ef50a2aa976d628f30121799be24cb0000000000000000000000000000000015148a4bb01170654003ceaa66cd02f8ad0350697950e3042b3ea972ab455d1491a11bc7779f703a7452f62d5bad5c0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033ad90e36da5b9f49e3d106ffd6c5a3e701a842dc418e84c907a42ba2343ec17998feacb2182efb9ed3c0e5dcbe98e9000000000000000000000000000000000163dd1c83f135500d39a65084c33de072302ed5ecc3f3b8bfe1b74176c420e12d65e13d1628fcadf5153c43348a3fc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001757b8dcfe3fe33fb5ad643a897fad178571261f59406aed1ebd20f8b0a45b7f2f3b7c8665b545b57baccc243b32897400000000000000000000000000000000105e9f23cb556d10a3ce13f1720b30c9dc33721e6d8f5e8839a766a9d6c8dedd45d56f46768135ef563d950efbcca2091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006c093d5b6872625e4fc22d9b4589953d4638c6b3870b837ee0c2ed4cad7be0045b2e18506cd30ae6b34fd584654429000000000000000000000000000000000f3497b9ba244a3fe372136ab6fad41d337e9dc4c0a4bf26c9f92d5142ef4e4ba3f824633cf1b16e50d38ce35fc606721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c919abca00a292a3c1746752b499ad5ebfb237f35b57a93f207bdaab67681adf2fd677b5207d726a010cd35e5900434000000000000000000000000000000000fc10e64eddb2e2337553e7f3d6775387d9ece87be5fabb9549e9a4e5a5020e4fa3403cb8796cd099164dbe3b09fdc8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7ca8e9547e391925640ba8a2578c3734d1c3765e5170e5cc88fd57f0f7807acfbb866d744de6dd2bce248f9efb9787000000000000000000000000000000001658ab1c819b8da1ce6fac6724048dcf95b39b75a8fe8a85fe9fe34d270b044a5d8f336faff4cc1df5511a837d654df11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026f29e0e9842bf7acc07cc9874d391f4066ec6e04ae9904b4afa988cdc22dc386b23b174e5bf34c6f7d11258bc36a020000000000000000000000000000000009c2ab1ccea3a4daaad1ea137cd0292e35ba01316cdfd5e5ae9629199583be468d541f159491baa927ba78eb2be8f2871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d2dc038fb9f583463721b774461de2c6a0cd05971830acc3e1da538d4919b5e7a09a526c21f7f0b37aad31ece17ee900000000000000000000000000000000132728b7fbdd7a712c3ecfade91f6df1cf75240a63fe230241a73ebde95d3e7d9b68be1d46f9f2d1e7c92c53fe28d71b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028f4454baa657c7eefa24ebb91e641ebd6864bd1508482508ef56b969af18db6e862a1bdb188afbb4234de723bbc79e00000000000000000000000000000000199adf6786f8a5c51bc76bfc07fc0ec3ce436204a8133e2be0e4fb12fe00a76c71f1549e07e52e5e945b3ecbff2e25a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed0491b310c5b167d6887df742c1e4b7287f7213a2ab334003d7613d2bed5bcacaee5d9bca9bb2db7bcd62caf016f390000000000000000000000000000000013ee7eae92a74231014facabef7969d13753daab7e489ef382a670c39525b57270b0eae1752fd9a5ecf17a2e8f1702b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044b3b5a2330bc5ce041d9bde4bc448bcec0fd107d91fe12ceba81b3e8ca5c6ebd0b9841e5c206c9739cf77d87827e1b000000000000000000000000000000000bf8eb8b6b41282ae73eb630c70026632e36da0aa2da359503ede5a8d3a39dbcb57f16ea33366bdb3b2b6713ddf126231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019714ff8ea48419e676ec5e37655298850723a9c42292ccd0c10092d49afe3754c0d5a631fbdc6b86385de7f8caa5c6f000000000000000000000000000000000b1ba5bda8116d21c650b85c0fe2fa8784bb9a95d39966635b5ba3f65027bd95b58f47498db8ecd7ed2728af54086b911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017198e31ba05ba0955179f0ed84e927dc1a0388678ed247d74477ed058e4dcb7afe5941b5e3714865d004a825026f79d0000000000000000000000000000000006f084446a3f465371490ebadc33354003072876eaa2976482690ecb368d93e2523e5bbc6caca9559188095e7c54f77d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000118216bfe9d69caa6bdb276e1cf8d13649477ab2877cea5f18dcb76a0a0e82376d790850cf2f02910d60758ee8b9eb0000000000000000000000000000000002e24c4173d94fbb041f56c58a28f049f7da9568bc41807ab9e7522e91765dd5d30162743d1cc53ebc6635f5511c8c631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000889bc3495d60010b9a8fc354fc0970f7adcf532bb0c7ad1e8cbbe95db11776527f71ce7b1ee3076afe230d8a5f1db7a000000000000000000000000000000000141a834b8d213f432b2d2e749a5230dff9f3945116773c6c4364230a33546490cf2ef003dbc0e3cef5b76957a99aeff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c44ed292267982a027ceb35343f56d171829cd6876d47c36292c3c21528cfdfe02b4d5502780a3aefa3b6c71656252200000000000000000000000000000000186e3190007a65acd2f60b500f0d68d039499648428cbab8cf68d65fa7dfd160917e45fe977e40acb38f0cccdda47a6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c46425e2dc1408339e8be6c5bb925582a1d8eae0e0b844e19ee726f34ff89babdc03f9caa03e53945c6cad5b7d8b5b70000000000000000000000000000000011fcbeaa262c97e42a02ae70f34192e7f53890cab4d859c02bda8e6b0fc85410e6b51e66c32564a453f409c3215ba1161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3f9cf96b897b69645a6ff34c42ec84e534143c43fce8aab5f2e74d70c611527d5fde7563306f8ec32d6c8ac789695a0000000000000000000000000000000004ac3f3a60547e3bcd505cb1856a8fc4c4725956f3bbd48d72e57df4b81fae61d7c11b7dd7f257adb2da8859b3e255611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f266a8391aa2f49a9680e3bb0224e769234d7a87d6d162004ceca7daf535d7e7393de2d86abbdd246846aca655c804000000000000000000000000000000000b99d33d33625dc13658aac232707ccd4d77c3fc2d142ad086c457eeafc61a75e28d24cac0ae702d4300e642dd5e3de71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bdabf76eb0304999f97d2f9743504805f52d85381671cff259d768541ab9fce4a7460edb676bdcee84a1e5211dc6b0600000000000000000000000000000000145e4e2ea28a96cae223e000689841c04ff61e2899be2a3083fd4f1a247518e339e2a29cde0c865230754685a89c99801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000335598e6de809239a3e3fbe246d85d43f0c77f4d096d3399ef357c6116267d4e288f6885198f99ade0fdc4d25b0123f00000000000000000000000000000000057ca0ffcd52fda082aede02eb349cbd29bcd3ca4bf64521ff304d2f8507eb9da2165837b3ecb1124a55c31bfbf1df8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000152fe92cde534180194e10625c50a6fd41818d552ea722482d8775d003ddadfc37a7d549ec13f27bd28e2c1c061e9e20000000000000000000000000000000011d8007a4596991f21da83360fe441c4ae0ba4a13be87ae3cce6a00f83ea5fc83d8b60a6da1c64368da152aa767a81b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a5ef269bae013d5eb2646331bbda3c7d64f87ca7a8e4a3c71c802b1205b4f90ae582a3190cd72ae2661b9b38b6dd36000000000000000000000000000000001357f64debc1db223c416d91244c6adc8a0d0a0417027e751766f49a5368a943442d175d166a49805f1532fa1bc706151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001410d1753c8b8663b5cd8b7d1f9026d7e295f4c4b84a217588020566fe3bebe6f131d59ce873c50636cec97aa08fb6f1000000000000000000000000000000000c916f1ce545240b29e7671d938afaa0623a5d391cc4cac1d3a6a9e89320fee2c06dca26722556de8245e371474a386a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017daab196928228e11be0e97a14ea16833b59577084e83083c67d35febbb991291dd2d79259765d5b3a333473fe46860000000000000000000000000000000000a212710c38488eb738c60dc348d91f0bd915fff12244d642623c8b82705559a0bfb4857cc531b4f0d34f4f7ffe2205c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152ebd9e53c4a33e227e24258f43c56012a4d417f8f38a94284eaa77111022d9166d5b3bab01e84764c7a5db4f06bc190000000000000000000000000000000011d1ffcb92b1113d0e2491c90bdf1d6aaff7d766e3715761cdf74e5473ee9a75c9cbc68eca9b4dd683a83e3b1905b0f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d9cb67f1cc7e715ea0b28d2265fac08bf11fc8392ee31e4da3c00345ad606e8a152449a7d78fd8de8ed3ce2b6d9501000000000000000000000000000000000e37a9964f12d39f97adef0aef96a29556c23b46677ec1f5e768d4295416f7d1c9aecc5960aa050aee43e222abb026d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7b1352ef2eb97d9603bd16a085729fd19a7342c166385f58f4cc8b45befa4dd6b346ca6f115176d5201b6ec67704cf0000000000000000000000000000000004e8457d96c8ada2ed170287cf0369ebb4e3b427bc8b4fb5d248c6b16590a62f421a1151c5c24e640acb02760995eaca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138c0d9b7acb2d2941b03fca37a6db8137779538de42da7ff1b0bb29ab373d799e8a4d0f6f85622c0835e07b44e648570000000000000000000000000000000018943169a3337eb3e17690fbb58f7f03031da7d437c629310798c38ef1ac09b2c7c86723fd6315641b52c56c2772611b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002185205b4e0a5d0ff016ac32f1aaa141c224efc5ccbda4544f876dffd681dcdf5026a98ec0acbfc539a5542f558693d000000000000000000000000000000000df52b572a572bdb7888f163482454bbca4c711b328b09672375c48d1cfd34475241413c7d2aa0bcef01a35f7024909e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014921516356f557de72927adb19e226268ddddd9a3b234e1953c3e971e75a90db1a4f8f494f225c6fca7265f9c39181200000000000000000000000000000000188fa4c53a8180236b03d0c766358c27105c3fe1c35024a148ee38707724525c14500ac3b9c3cec8afd3ef3225e693031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbe31f82cdc0eac6de1da92a701047b2dbca2961894ec2cb1c4fc8503f318503a522da774c0a759b8f351fdbba517f70000000000000000000000000000000004bc09c4722e27bafc4b6c52b1d69da15d743b18cb8b5f534e253d14972098cf2142608a72b24bb54abf1426888f326c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128d181753dc5fd329e134f92d73720cae1b77305e4f606a8745f9725f16419d9ecbbfb41c816dc54642ca22f524e0440000000000000000000000000000000005fd12cf2df76f5d642bfe072a6cc338d487f3cab7a71f48599101f07d88acf75bbd3c7f3b996cee0f846961093180171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001566b2ea74b915470db0838faf0b3a8bffa28f2516d879a9776409ecb08542886a730e0a0c1c5938a47ad801500a5a48000000000000000000000000000000000fc64c55040bd9ddcd29d667dee740ff37687fd19d094c6c3c161b5d09553196be860243252d0e3692ed15d49d7286701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110e8745b034480a52d7b8ee8fa9441a26db2c9e26c3c1484a0c93a210d0831013b17974675495f5f23479d67bfbe7fc0000000000000000000000000000000013ea82cd790ace5a9bed8db0a38a6293e135897af476dcb45c6a36e84b1c5ed798e19d5aa3a86f1b145c3dbc82c5b5a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009566f133cd348594c0a9abed3329aeb63b1f8fe7f3e345b560dda9ff87401b7db0e2c899b9cb6a261e353336deee38c00000000000000000000000000000000174445b067086b350606d09667eb3fc01a797c75b7af82ab1a1141f0109c787d617389b3beb0bb0cf942579c916eb9281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c8a975fb1fdeb2144954d0b711d9561e61de9777977289f34de9624da41ec7d49a69bcd1b5f24f0aec772a8dfc074e00000000000000000000000000000000075e868f8174da59d14b4e01b75428b341b1ad395ebd62f49b1c20fb4eb0ec4a126a21a11ca6a0c0f817b266cf039b291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000155583d24296ce8e16599cb6696cb8e8480e217fcdc750234a9e37ed54548c5bff99740a32c760c9887a5c0161ba0c66000000000000000000000000000000000a71c2219452948095b2edcf10308f3e4616b9eb89194af9424c88eb433944b18649d8310a7e365d7bacc2ed253534111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7a219a1f36ec671bf6d969550e1ebb7b5c32494cef503b4fb84e5fe117aea4b5819587b49cef9417e7a4ff55d5e06200000000000000000000000000000000155a169b7812b7d3ae26566ea73e7690d2530e7ad7b086c8d7573a6df73b7eb56457397d697062a44606ba3e0357f6c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012789cdeba88c60e81d3d448c3d86fb9a64508e3ea147dedc3df258af03e78cc9b22f57acb3d4bc4662a2cb8ede5792500000000000000000000000000000000041459e0c31b598c9206609437b0604461f48819a0b5219f28a634526c68f2c7f47494fe6a42fc12508ec4a12b83288c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b88b970a0be332acfd3413849b44682a72daa7a2d993b21b1c8f8dd5859373a9588eb3702a0e650d14f3628c9f96a92000000000000000000000000000000000716490c0b58297262c7240bf01f7dcd70d94d722a722cefcd0fcea35bd4e40f9779754d5e486360ccd2529dc62b321d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000056dd8a7d7433eb39c25bf04c068ff584b09435db11f13659015121df64e4e128f54a3c5f154c15e11bc35af63d7d99000000000000000000000000000000001608017375368b6a2804a04312193121cfc19475abbffd86d8b5de414990d75212432d87b4cd17114c5fb89db1c48a951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005cbbec2c7621e6a358db5098505779c151d38526fc1ea37bbbd5d69fd007c3e00b669c3b5e98b671964c2f7d090b50800000000000000000000000000000000102ac134e1d4b5ffae4b567faddc05b76f37f09540062c308dab9e800e866195da765939b692c7e1538a47eb6390bc531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8f059b1d13872af5e6776982303e9112f97d35504cd07fea30bd2f3a624edb141224bc30df4aeac1537e680b86a254000000000000000000000000000000000c86505accc2f238ab91e7feeee74ccfeb2fee97cbb72957435d3c144da91943e687ba43988def1d47aa8b7c295f184d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8d8d3ece2d81e11be7329e46ea435a3882013fb4fe3749f768ed1c07d7f221168ae1ed648c04fa7e26c324405f4a4000000000000000000000000000000000066daf851d334552367936ff9440d3032e8168b88dc7c115d6eab5640dea2ae8fb006369649b2ac644b18d9a338c8c971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ae9b5ba6a29b120ddf30d54cde457643d8784845d1100419508b148f293af5ad3f5ef1f8e55741db0fa02c5a7b6d1b00000000000000000000000000000000169768ea58e3a9707e4a1d3d4e0ded5d546fd8f2bde67f784989ad28544f43673ccbf6f525780c42f14c902a0c0840341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2de02758c77c2d166ae87fd16e63f236a962c44bdd3a7e22a21b0b04edd9be28425d9f6277db7c968e50a3472922de00000000000000000000000000000000052d053b346b9da3789fdfbf34399924efe51b56e38ef1ad586d95be2821f6e379e3cf7852a8ffff7cf3f8de58f481541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7ff71a8e3425109398a24da639a7dcbdc1e71577e70d365450b70de83dcf85c7e9a0d85709d162f0e128c645927992000000000000000000000000000000000614acc3718e72bc66a05d82ac95ea075ec41d221f96c048c14a9014bfe42a45a69c6700008642cb7483d4f244d509ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001078b6b35e49e611bf9d67b968e3a6c28cd3e7e1b59a8b0ec46ddbe5cfb9d5a8809a6dc01bc73650c4aca69f76b910790000000000000000000000000000000017664b3a857e7a29e33425ab6ec98a266afc55ab651a16b28dab1a06efae658324a3e5b102ce88d626a9852aa9885a811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014a2f92f7894885341325ac05e41077bdbf2e28630321a12114a51e0c14b60a0fcabd1c75b9e046371b3ef78063f4890000000000000000000000000000000011b6869aaac4888746fb0dacecab0a1aec4d8bfa27703eedb42eb0e84713dd1b45f12c7e7234ef0c2f6366ccc25ab4ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f97a6aa9011f26167b9c62a1e626c7b334b7ebb28d1269dc669aa7a01c5868dd0eef9ac7a3e3cd36f7cb1e68a11dc4000000000000000000000000000000000098163530c5a14a9bbb7e1b321b1a472a6952d460641b0e4e8eb3c0cb67ef11254cf1683f317fd96e6ffefd3d05a122b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062a8771b779aeb35057cfea02bb02078c24ecf57e095674264bc57ddf5c69c731a13bd42f9aab01b9a3f4444f42c15900000000000000000000000000000000003191d8978a08c7cc46d0bb30078aad0438c62f595b5fa7faa1616854043ad860bf60f3e936c2b33088242db480c7451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000080473c94c5f01c89e45e5f335dde2513667bdc475a96699e5e3800e4995260f19b0a6b6a2c8b704091245124c2c32a0000000000000000000000000000000016967f726ca770c1afd2f5fa142957ccef96e142684dfd661cb6be0b44db2a52ebdae7d56fb43f8a2c5d7d856a01af951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000082ff99ceff379ff8218af0c2a50175bf45f6dfff618c0de6d06ad81d3ddc0b87f0074592fc263e78ee570f5e76f66700000000000000000000000000000000040cc1ac3d5ee27983cc0ba8e6e7bc2a4af78bac4ec59e0103d677e2dc5a9d0ec35d996ee52f6cb7c8100fec1ea8aefd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000337b69c3ed88acffe0d4fc6287cdf25b31eee50a284c25801354556b1c478704faffe5301c86e3b59395036ca0365990000000000000000000000000000000004bad0dc614d3edf3b34f9fd5215ca88df311d4d5d2b76626f18c215700e93a3f8621ebda433388ec508199383f85a591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cee1a85aff0965a37452f3ed6cc3ee694206d90eb4ad4ca6f859e3a81a8d3eb90114945b18ebe953c25f775d399430c0000000000000000000000000000000008486a2d7cbb646191340bc1a0e470730c6b8368b189ae15e4488e0c7f5ac6bd647a3376c1084f577140f58e51d5d4291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171082ef74fa2a6effcb9bb5ebcaa443a67d669b54ac92490da7cf3b64b8ef97a11cfb3c4f3e0dc76674e2fb4d40f823000000000000000000000000000000000d80e304fc75a29dbb2e4034c77349a8bebefbc5e74b9f73e841ff0d295974c0b6b8648e25c92429f90813a8ab5c71971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005240b23a7da074d3b0f61267c765cfd30cbd8bf9cb8628236c01ddb3ca80032d9bee8a39ba8e960de46fd4202bb908d0000000000000000000000000000000007876ef35263fb808d6a5528ada90e67feb9ae28bc55a15f9bb3c705fa88b1bc5767a843f6edaf42d8ca790b12ae0cb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113e305afc8685dfd679162cfaa94dd49a5bc79dd366724557a49562d9dc02a0cdf838c9f9ccf86330ac014f006f2d7f0000000000000000000000000000000018cb65427d9da03fbf16b87a9585f1c24c83e267e9bb8baabeb092b227ad65b8dbdafd45ccda7751839cbc124980cb431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c2353b8f363e0778a24e4bc60f132b3dc29775ea22bd774e59bc53615413092294ed7e91fa96b92dafddf08cbdc109000000000000000000000000000000000a7a0594bdaf9bc585f61ebc0288f56e539aa5bb3c9f249cc92c2e887541de8f5b5f381c1ce0c7105fc000fb52ae058f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f69279de331740395617d79d9a783bc607f57eb001cb9b28c95d6272c125310c8b638e719f9ff1aa4a06966cf72d030000000000000000000000000000000005d01439809bd20fe32f4c9c643895ef0362371ddeb99bf9ddcffe1beccca3ced30cd56d41c455f88626048870a61bf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001560cf987021816fb2ec10176288624df8e7c3e8656ef06d7b839519029b56cbe0e79210b3491185fbf2e869730efbd10000000000000000000000000000000018631a919fb1254c57f34a74e7b5a8cb2288c7947e91b27c5c6536042048726c45f3a6679e4bfd4f412def2bddb5be341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000849db4da34e073c43cfaf978c5bf2a56199f0caebb2a304e0b6c7f0b5d3123db6f4685be03ffd0f8db6789a18239d3a00000000000000000000000000000000127458acddfb814c7fa57cbc0f7ada750e1093f25bca8b3d830cbb907a2cf00779b243b1d30570f963e8b24a46d7078b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009607dfd042c18ec26e5c6bf7c506997b1859165ebdeb8eba08538085741f036737ddbc2d50e1ff23fb15e3cf91934a60000000000000000000000000000000001ec90855f70d3a1d6a6f4e8a1028077b2994bb3ec2fefe3de2e3ca7e33f2a350a19938c7fdb530d5cda1095fd604fa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0c698ed33d7289338eafed25384cc9c768b4ef066b4fbe92b12bbad8f06a1a6606b8f1ae60f9462ecacac4c84f25480000000000000000000000000000000015fb02bc533b400ff46fea525dbfd3fd4e6d5ff608c72a7b4348b9f99f0cbce400915ff44c5d510837dc4a97a00e8b721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d69285b9e37ac5aa391d85c94d50e72abdc10b68844b9a4573454fdf40989b46d6383c50dea4a9a57984bed006b176000000000000000000000000000000000036470ca82ab901ca4f54c59ce302faadf6dcb49bff77a2ffc9ff9d7205834740572b4ab3672f48e5df5172603640b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067b7a1ef278c826a51a8824235a84078696b00f01273794c19615352302499aed92170d6a94c24dc6967bd9b707cffd0000000000000000000000000000000004e83ac897c5b86ea230614856289639deeebd7f010129d5e898c717a5321bd11d37c39131f43b3913a551453c50de971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf14f770a90fd8ed99556e70c75444b263855964634cd851366ef047596ed6af6765a4811914e6f69a04086384a6b86000000000000000000000000000000000444f3c9d3727c521925ecd94ba88c06371e19e59a868a9611581bc37be2c551cc11882d4737a6723951023aae4bf8c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2958ac971525e879ce4a2ebd5791cc58a0fef2335b70384623eb19554bc7ae4aee87e2e2d82b9dd073fb8a0f6de15e00000000000000000000000000000000174dfa1e2747e7834e394c40a664c9fd15e6f786e0b44374685130e0d26ddba584a798cccf9aac94689bae80ee85d71c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000942f157cf7a5f17eb6b47ea6e534aa4d9d67d546712175f041d2700374192c75136a8ffa43dcf92fd54949a43f30f91000000000000000000000000000000000e03f7a655a397d3958f6655b3b2583296c1ccde6985f609a2a39390a01a19361df6806dc62638ed8547b754c8f544b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a80aed87190677e0e254f43bb045a2dc0bd61fc2ae0bab297fe5022380b275bfcf4d184fda535b87c10d38d27919b3c0000000000000000000000000000000005ddc57a3f38272126b7352866205949c945d45a6d2bcbf1238a30adad685f4c237cc6a944a77a3aa7f1114dee7c96f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000061cc90208a4daa72b55b1c75b4c1dc8f5cf8405f2cb3c6806c96be4564c781fc14c7d848053349787aa2e359a088920000000000000000000000000000000011e89e8d6b4a71b1655bc19fb5f672f04d3a8404b832c2fb8eb33d6788131832bb5be36a968f40c876deb9250db4b1451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001343cdbf82fb20ebe1be27a2cad67d9afba969cd9d4b192c40317de31906bf88861e16465555ae3822b9efffb449a13a0000000000000000000000000000000013d3d4c6ed6eacd34359cfd5ba7528bed76c2e39908063d4e14019c480701e1e81fc3a16441a2376ab639dd65be968f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005281e7d161fe5aac808165d5babc54a1fab2fcde7155e55ec48f341e4cf540a8b3a4045e11ef7554b867725c738dcc8000000000000000000000000000000000b1007db13af00588f5425dc5f6e8ed28579fa0d7e34b9bd9f3cf1fcec5254d0441a48e0de963f79c14f03e6e1a9b3f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b38f227434fcfa66532c445c577f0ef1bd713e16850713b89dc5e884e2c3b22b45ec4d867420ca84539af7b0c66df5000000000000000000000000000000000abf2a4f10097f11573a665e6e9a6b8a4619abd489f887f857f57abd4dc0e9913b3c10694dd34994955e45984c60670c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfd85beb6c67837ef0dd6b9c1440b71b237574954323fc6a853d4332411f97abe6734276367f751a5afbbad694d7fe7000000000000000000000000000000000deaf17dff82f4b57331498a9fde46b8a5721ac130907aaf4ff5531576a559581c22e0b2317018972ab2422a7a4fb3b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001336226c03b6a8c33d245ef3396a9310ea244888ba9516f7780e29c44a4239cd592a49b9a9851441b11414692185932e000000000000000000000000000000000214093f5c3686d49510ede32f30c1b183ff9e8135fcf295ae1ab44d23fbbc941317db24231ed37965de57fcb72a19391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001177b6893af5e2f697ed6c970269bdd78d8670c76a16c32b25bbfbc56c8228c1ddac2b57fbbf59067703a09d20637077000000000000000000000000000000000e375268e3956dbb16960585ca737c586b8edaba3c194e05e876a7ac0e85250b03389bf7b9fa932e38dfa0d96d2044d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136983a79b451e57aba1533f95b5392e48942cc696b76a338444c0991944eb20b5e04d97e24babe6c714070612306fe90000000000000000000000000000000015f3fa8aedddd131109ca9cd75e82b85cae51d27ad1361921b31e306874cb42a82ca96081e6aa22c47c88667ec60f4f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008681967968f9ecb524eae7b08d0cbf0cbc8bb1b15a3b6603f19ffa6cc406ec0797965fc71d444861e5c5823971f6dc60000000000000000000000000000000013be555d447640982fe2ba6d70426ca6970f052f4ff7214b17f1cebb6233678c2cf0e1bd5f97aafa314006eb3d1869241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7eed07e01a1d8f694c4047e533fa416e6e1fd3595ef0d9d8a971a4d41feb0c0a5f4496906d0c9731f3fa6bf4e552f200000000000000000000000000000000099e0aec238a9eddd69171a1b900bbbefff18505b6c99cab64880a811ece9a2e40e218e73add7a896dfae42dda5c79271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157b503b62e94514e63a42e116d4d18c56641d5b4868950355e0ceb23986bc819d3cf8131a7e78b758b108044021ceea000000000000000000000000000000000d72bbdf710c951aa5ccb5964921402ea2af032785526d4d3811421569fd68bbd847b1e543eb46ef8079939373690eda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a194a6a568954535675831a5abb985b26d43a95d0b402e08d606da7c1839a10f7df47c17068091959a40472530661d00000000000000000000000000000000003aee80180f519878e5497ba710aae527c95f5cb5fcd397a0583945fe7003c32020386b8d375433951ef7e0f02d7a331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002faf84e2bf58f36955eb8021490b3afe993a1651f47b3865577030a6cfcfe77e6e22468747c0f9aa274a97bafe1026f00000000000000000000000000000000036c77fd13205abc7907de3c3bb096f19e4933edf2dfdf03c87e49b31aafe37f915becfbc53df5fd7ee43016a8e59f081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f973acd8925102d61d27aa26e2191ad34fa9365b36bc756a6cfab46accb37f8528263af2d235b2254a62c2c852024b90000000000000000000000000000000000fdef8b926f0b4376b305edfc3e1c6176b7b942b6f9b7859b4b8b071b8dc12a116504b5508c713041aaf95565fa9f011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1dd72e764616adbadd27a35331cb3d50ee56f09563eca95f7f1e5bfe571a2c27734382bf59eae798ce99cd20dda37500000000000000000000000000000000035c82ce3404e583e429e7d4cc67b60dcb2f5174874bb03de494c2d85034e31cef6ee7c4f4f93578ef26066d55b59d5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9a56b814a5134019ac170b1f663fa3b6cf873e6171a716812d8d4ac26394b3b7cf2044d3416fe26d90046641a7724b00000000000000000000000000000000015cadc0765eaae272a27ea04d87f50463f18028bda6d83ae771756629341e3e10777c2e94b7bd73bdf9a34d25be49741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae75cf8041401512a35b2e991a98eb47eed7ab28c134b9871b5615a0e70824f0bb2c67ab75a082daaea5e9d1467a8f50000000000000000000000000000000004ae012fea8d12a543d725ff6bafd691eda13e1bfd9427ce3378e0c8c788520ec3cc09bb09477042b588064421c1f3501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073a5793217ec05210192719727737b7d8bee515c7ae7c9756e7988621536edb842570e3eb50c1b80d29e34e0db185cc0000000000000000000000000000000015b36a284108630704823cb7454cde11b93fb15bd5783722b24a0849d8e9f29079cad878c9b8aacd1e0de58e4f8f1eae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b02da9402e60d499e9c9f99398513c9021bc8d57b218586712983a97f1552fce0087bca68a713d6e8f6caf2086793000000000000000000000000000000000164f63ce74c0873c30628a9199063e9b0013a934769d54e32c108db1a0211a29ab393df313fa276cafd6ae460e7da3321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140dfbe8dfd661a89cf924281ffd1933ebb0e91298a95237a2826351c64c5c4fd379333c1dac0ff505212d7cd7c0f5bf00000000000000000000000000000000057dc28ee5eb6e873f63d99379ea6f93453053006ba5b27cc8fab163fff0beea8f4df0b1a9507a277438842e2cf782f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b6768a88e06e9908ba018fb0a2c3969c4c0b3c6c4d8fa53f5bdc8a8d65fed81c085c70b7b224f742d29a61f023cdb2000000000000000000000000000000000652154adca56de5084d0214e30452a0b8b778cf9043ea3852fbf2f16c5c4f2e72fc80adb7fe4eb431771d6e4fbd67ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca861086ff289d51ece5acf15385ad86c97ad01c90a5c7b560c0b1bc462101bcaf2ce5f70b23528d2643c3d4e81262b0000000000000000000000000000000016df41edefc6aa54948c26bf6318e4cc724066a0ce97d749cacedc69916fd42e6bfa081bee18852d4f1d82cee91569781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000381988da7f81fcd5e1d892d89dca6486feb9ebd53ff94fbe964f480d1e89ad0dca1989b0dece9856aa4165e1647ea86000000000000000000000000000000001239b90bd383f4567aa95023475a6dd6f3e3e3835bfb2aa15ff527ac009808f66d6c9024d754401ef7d80d67005ca56b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f14cf5bc72767d734f46e6cceac005a738b33c392c30e1d4485ea2b59f00ae31453c0d79f6e1ed001c86f30e6de484000000000000000000000000000000000a8ee9a019b7c98e3ad496212432ce60b472a1317a33b3da820ed44be6f5e64b978d22e07ce2c044647e50fc547374651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d02db655eca226737c23662cc306a1080809e8e9aacc6f9ff9eb0dd3ef590e982c37cb7d2f297406e094974bb1a72a00000000000000000000000000000000143bb93bdc8c3a7f42cd7ad1786b584a2e767f4e9639d016a359dbe398115f10d890668f462d07d428759d7c314a59871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016ce91ea741313fcbb7fabae6341c6205aa06e4e2f082b5f999077d65a7880fbf082560627dd812ffbccc158afc506c0000000000000000000000000000000014c2e717e327d44b37d23c0742fcb5fa840089d27367672a14d56f91c81408a79d601e122f1cebc8d36224aa142e84f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015565b040c1990352735a43a66200f4eefeb75476cbcf5888237aaeabf09ae2a8029624b0a7757147922fea651132183000000000000000000000000000000000c4a6b3d0275f0df20c49c08e06ef53cc4ae0a4eeb972143d5d8dab7ad66672f2cb7aa87395faac77ec5d7fbf71adf421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b1ded8cef5bf44b7d68ff268b6a4db53d547558fa057c875db742db6b17f4b82c75062e3d832c8277bfa49e8cec97700000000000000000000000000000000163ae51410a68196f3a0de2cf8e18aa5de410f5585c48013aca541fcf1913ffadce664c189e26fd629bdc841ba8404ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111555402017e17769c1f23871d26608c5000d39d2c0bfb8600b996c152542a735076c9f0545ed2bb34023a66d62216e000000000000000000000000000000000e5a4d2e4c16b0fd22508e171e5ef80b5094580a6bd89567e1e1fbf462dc05f43bde98f09cb894734b9dd3da8656c1df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118eba29a94b70d98f7219f93207c4096fd00417fd6e51e3ddca230741e89418f50a6f40ef7e9f1afa80749bf588d197000000000000000000000000000000000259083427a4cfe4c862666f60b01982c463804124f2bd77edc90c6e7821cdfe7106a2db3fe3d633b15557199657fbfe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd09354fa5000af1172c7863e8f09524fecdccaf04bd8bb31844090a6fdf3e4ad822e394d8038b5c4dcce74e3f005b2000000000000000000000000000000000117ffd89bc99938120e5b4cd9d4e4a89c87682e6474ee92313f30e573ec4fa85341d4ae1841fa42b9f08d55930a168c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e2c35f5c4571df3df94b52fe383452a7dd5089a884f9b109ea571ac809c077fb30c72d2366c372664feba3fcacc4740000000000000000000000000000000002cc72bb35ad8150d64f6d8cc1bb767bfb2dc758f38ec9418b2369db958c3f26dc842d7b4dc34b159d01cb3498554edc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f268ef7311fb3bc5a5d384b555a07f46e149d56bcc98c2c10b258abab37b7226abc09f3cdfe93ead8443afaca6dcbf000000000000000000000000000000001535429b0269bf65ba4a71dea759ed10e4965c9852d78d361a93d8e35e10be37a4e6bda0ba0b9608f2f7c1da5c8fee1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134b8e8022e77206bf0c0ca2bc1b385e8983754e7c468a5ca82add347f3a3300de5fd5ced9bfa30c79ad636f5b4db216000000000000000000000000000000000a1a919e2c8636c7b7c22485c1d1f2ea513dad7a7ed6922d589687c2d2c2dc81c1c1bb6628aa419bffcd098ddcd27ebc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bce0322b8c3e8efd8eca5837462882a7338c1619d37f0b6fa8b8beec0a36c8375ca23c333af007611285336eda5982300000000000000000000000000000000111a3d0c5bfe00b00442ffa1534b76966045de0d81092516866754509b6a484c24bf9d08e56c7871cb4071e5b9fbbe7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ff7184c0614d51bea355447183e8af1f6635ad7ceb5fbf13fa85d0c536a66bc1df734024de57942baa6558e442810d000000000000000000000000000000001271eb8d01f2a76ed84c5d3dd8873924c45784ebee12be098576f119798a05b1d378659498e39e2d8208b6e64c90e17c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c4dd33351acfd22771ab8981518cb5c68e016fd02a065edffed90564f2eaf37a5f5f46fe53c4466791a4044d1725e10000000000000000000000000000000007a2b508dc433737d96e9a0b0b07208f967ba13ffcf73345ad7b29aa7fe802e3f5988f27d10c6f7d5968d4c076ae198d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b19032e48b8242946fc4dc0ec74ece961ae1dc1528b7bcd6266d9514f103d6f8dedd53618c944d09f6287cedba823200000000000000000000000000000000067fffb43e15d98665adbef2b7a2ed42da2aafddb7acd6e772bfb88a0d1854f5d9c250eb681b3884793533d276b4ce131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019de9475d338fbec3140e2b2772562d23ef1941d8512a64981804e5a975b27370ee1951448645c2ae38c0d43a2b80b4a000000000000000000000000000000000926a23f7a5a7569fe21f528a4c6ffd2d2337852157a07aaa15ff0a9cd74c30801dc424b3859a275db6d6d32fe9775341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198435da5a41a613c8703dc56768508bc0458e649c321774ac459a60943916c8ff8ccf3f50e35dc7d0af45b126a9aed3000000000000000000000000000000000d67d9c15118f6861a6c3863dcd5a9248b65750a8ca30b667f87b392b4c8afda5260f99425abaa997470c8c5cfecf6a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e7af19ffa6231aeedb2fcb9ea939ecce9f4f3b746a6eb455dacc5cf243ed8222e589461a57290d75e886f56c9321cc0000000000000000000000000000000017b96db0698e15efce619dddc805028397dc9f43e9ff9a586dc0cfbae68e53b1e1c8f0be91fb464a62a40a632aaad1371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163b358cfd8ef6dbd38e21f2d00d929ce39f0a4e4642b74b378401a4180a5ac4a8f459faa8061d81256f11aed4d44a9b0000000000000000000000000000000017e6e962ce679a44e31b01e208de3fb0bffbf1becacae265c9ba05d3a9f54700602c013b2280bd179508b84952e745621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003982778c5bd26e39a8c48d03ab310dec6e0f8ef7602c51367afb6cb2b4a452d8987f9541674fed8187f61c5c803818f0000000000000000000000000000000013c483f18985898dc4a691941c2b7d3269e201644e3e2d8eab46f0b5719b1c86b092a1aafe22a440b5ca897048b7314d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a672c8895fc97c85e108f89c458a5f348c0d043825be87e695de4c052b0cab198b28bb9268052814d27e70da297f800000000000000000000000000000000007fea31dbed2776b9a2fe6c95076cadd53d9d7b8cc0b965eb518699ecc4b6b9b6d0e5ba9699211346537e7e1f47af5fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004961904582a05e77fdc99308e72eeed2405751b91e5416691b223b8223d56d9d330e17479186964df3eabe02d5aa60500000000000000000000000000000000109396ac2d77c271179fd140a100826c954ede0a64fe8cdd181231de0fa4d61241fabdd5645b40851247a4d8726b8a241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004cfb7f00bdf223744ca3552e82c0090e99badd92cb80aa1729b9062644ae4f91dcadacbb069c0dee4649cc90db00ad8000000000000000000000000000000000f770471d8653a5519028a626c9950cdb7c1b44319db4a1b7960cdda097c7f1e4a0bdd17c848b0f37de4b1dfceb6bb231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001181f10f6ec9a923ce8b541b9c9995e44370ce08d9a306ae5a5610beb5479e0695451fbd32f62e68f5f1f12eb9cdfad3000000000000000000000000000000000ae57bf8835e96ed4694813308fd956b58466afbce9cbb5f74044a7e692efcab08d5532ad4a4ff9b80a8fdbfe609a06b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050ae43d3dff192732ba86a4bf81694ec7da667d28c7f77402aab3d5c1482184d9699b4bbfed8e9b25e7ad516a460c0300000000000000000000000000000000123e62c1f38d91323869f4d3fe34a04bb25877d99be4255b6ed30a403dd0041f80f081c17acb35461475059ac3ff27301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001eb93dbb12c3c980c815e04330822bb70c7a24b561796f23f78ddb46d2c7cb47bf5cf15364a5dc85453df65dae8b4af0000000000000000000000000000000014f84c88935234f762853bcd7ef9a0cfff48f53313c5a3f8589a7074a68e0f188a1e77665759041ef6aaeb0848be32911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061971f6838b1f34c16ea34ffabf8305f9f916504bbcdc805ccb6118f09f9d31b41fd95b808057eae33c5efd03aff6bd00000000000000000000000000000000140326175e450b5421e436c618954d500e381d9fb8203040cf4eb12d93f8d2ec611142ecd6d2d129dd9135f6d97966c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001288c6c7bf2d17e6895605bb024a1745f0da23f96cd58d387210f6dcdd55b5c3ea23c0256c2400644427f8b9ae2d0c610000000000000000000000000000000016489d0309343d1d51783ba5f081c5c8d1fd777c6d8ed94f8949c888885a67282e7be0c23c564b0da4a9c10d6939decf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067143e697dcf6f53a4625cc7ef96e9d2e28d4f96df8d0f05f610680e2f59d7bd84f860ba1d587d685703ddfd1cedbf6000000000000000000000000000000001634ee51d57d09fb0a7db507106ed32b33c4889bd5e2cb7bf957b59376f36257ae9aacbba285ef9b69d293790bf2420d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001173d8d477d8128577bc340d8dad93f39d1335689332ce74d422ddf3e389f441172b5aa7cb065f7fc2a136d4f10fe5dc000000000000000000000000000000000dac65b4635f8b9a23d8ee085c4249959caa5ef589d08af377fd52519c380187416f9817721a998d815bd56bd4ce8ac81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da5a804e186ab01afa2d1afafbf0545c0c099640a35184cc1b74ee5484b97f84f7f607a11d5d9ba5bf021434ca7f0c500000000000000000000000000000000021f7f2bc9f45b334d5dcc8017f69506cc0665a108d0678f6a6e4bb10527a7fcae84d69a790fc370654e8ff269ce255c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f3c07e0ddbb10ef130ca1c08adf08ac8f12157f6803720763b7d078e04d15294d81aeb5469c270dd365fdaf245be35000000000000000000000000000000000977154c1c613f042ecbaac9e468aa306c94401631916fc6f14c192cf485d5d747bf74f8863f6504b40c4ef32fa6fa841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034950a6299de7869518671a48f1aca471a132b3f6a1bf1ab5b6df7cb8c942c12ad78c06a9048db77084c5f89b17d842000000000000000000000000000000000c8d0f3daadb7e3b6976e959db8395df1f93b4378531c0b05a88b59abb0cf473c157ca67e92b09324497d176116ebc281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee9a9a44de05ec357ca6adaa942c34f56a90dc7c234d1fa9c34a9623293b8a477c8fb3bc05b35b2b5cebf3e7bcc91a9000000000000000000000000000000000c59071d9d32d6708fe16cc46ef1fecde8a30e62112e2d167e44caba5be0a39c3fa16407b3d9c48a9f7f22a7b1d8f8db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6d21ef7fb71068f8413031e2857705266a7ca10ef31000e6ceea839394daade5cd002f723d5217b29797c1112ce2810000000000000000000000000000000006a183b8b3edeac06626ad8e71b3dfd0c0661bac5c3b504b5a9d7c3e155705b4f81b63048332dd84ba1c48c61411b50d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9dd221ae813b377940501d2ce2f11c5ddf71291cb09db93649731a1546d4ccacbe4d37d2b42ff138591c93b2c0fac600000000000000000000000000000000146a68a64cb40561b009460c5e4718750ddc4c69894904c3727edb63304625ac5cd82b1fd17da9a615323b83754f11cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1c62538f152f1667a876febf1ada00c5637c42d8708d4392aeae1348aa0ab61cc7ece24d267eea11ec5031706dc08f000000000000000000000000000000000af84db236f098e86f48513c59402ba602a5793bdd72506e4eef7bfa4c728a77e2f4bf3ea54ace5665470eee42c3320a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134ba12e9d1c3de55cbfc5d796cf5221ef0247b381041340b119467903451da8c2d6e804dada0e4404c4b971f4abbf040000000000000000000000000000000006ff6f235cc3481d0d12c15a287f2f18823a118d0759255d31b8ca5bb63ffd639d4643ce4afa81d425c16f6031bca94f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002dd3c9bc3ffa9cf71747c3db458df73e2df00112e636f9d02cb52153b36d3a165a1ee365a46e097e75e37e5da16ffcc0000000000000000000000000000000014a44f2c101277228c82648172cb51dc312c0af0539ae10f1ab81205bb1802160baad27b019846b74a90342ff11b587e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011cef9305320a13c43e7c30c1ebd912f955fd910ac908cd1e12dcbe74c453317bf75c07dc96fbb1d575fb0a44ad8a24d0000000000000000000000000000000004199af2e5e4256d4564321a8485edd408cb9d815fb464e3c39cce49687c57db15fdb93efe65232c7b438b4eaf9a01a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e79c90ef374b5638415725d017038770d2e0fae40071d5e8c0e98722e978a91b7a93f0c034a6996b71cb008127e7d200000000000000000000000000000000037cef266b8bc111df1aebd1d10720964cf22d3195ed159d196011b31c1db45ca1af7c95dd7322a2682d6efb318c0d881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000348449cd3128ea7dd0d213f7ae440aa86527005bdec12c7e6812978b6f2f032960bcd8d2d5c4918adf96482b7393b4000000000000000000000000000000001682d3a0960e3576a797422ef9f0003c11e8431e091ef61d351940bb3c29eb3cb1dd1b8d13573f560d81db62d53d81d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076564c3a5b234db1fac5502684a243b92951f3ea7fe2a79469e42659f9deada85b0caf8a430d5549679f8063193ccb2000000000000000000000000000000000c075116f67bbfacc9fedc448846373e60aa845fcdedbabf4dd1e59ab21c7b1dfc2e3c79c2f83466ed173d90e987945e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aef5921dda01a4932549f1be9e672c7cf4fe12391f3d7d65588fc784239c04046ee45b5b487c2e7ebd925586212862700000000000000000000000000000000132a795da61bce017c6d42d1e7d0cff770533ea34bfddfa595d4815fff9fb24868b31bf7b285d3900ae431dc1ea66f9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000095def14fe363928f99143a3fce9b30a2d9ef918cfb6438d45d062f2a2208831f140d0a01a8df0eff16bdaebee2c381e000000000000000000000000000000000555753aade7c4d315b41698a332ebe5a2d641e137442e207662b040560c1690095507cdd06fb2d21a5f5167286249d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159baa6fbb096b00e37d96132e8f9d9bd13411064068f00dbe80f4013067aab9daf8e7c9679def5474a7a834edce945300000000000000000000000000000000164cd5aced892f0fb15107bba0ec74ec0e0ee5ce840d475f9b040954a8b251353b1ee65341ae7638d239fdde0e427fb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015122e427bf409464f8800c53e7e8c3364686fb16b74ae9fb9849b99e17e441e117542c8b6afede418b6e86d29b721bb000000000000000000000000000000000280fbc214383bdcc914e01e3b74f65f7bd727e9733fc9b93535a49bcd0e7c85211899410117a4295244a252d6ac9aa61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015bc7eb8494fcadad967ca6cc08c892010844f332d0cd5d94e1c524bf669d749945a4dd178b79da9232cefe11c4581fe000000000000000000000000000000000eb01e49dd39506fb76e161dbb7cdd06370251ea9440693b2b846eb14ea8257095ef1dc2622c83ceccbba6e70475b2cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000149139a4838fac0be1067caf86a25a6e81c3ed6da9f97088ea29d15c207f9a9ae1a15ec45c88777843f8f1eafc36ebe000000000000000000000000000000000fb6a2bb465976d195127144c65a8f2ce3ba97f1463279a462064b5bf4b15d1a4bbd0524a44e91a85b5d44b540abed1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186f73854b56376c2b04841ca7dfa3521b343e20431c062c59b86ca95ccee0408b738837657eff66edadf897e62767b9000000000000000000000000000000001102c16a2d173fd846aafd58061a0ecccc6623e7053668ddee19d16882a5447b2f8a4c1f1bb50f39eb32844e515ab6fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041710297f5852af042ceebc2ba20787e23ba01c9d3b2d68b39c8815b15546eb568c864f7915108af2fa8101ce23b07e000000000000000000000000000000000cd20c2799673d5ac0bf0dd65baa3a4d7e9b5602706c37c4d314a021a23063a23804c500b74a12ad78f24ab2608c266a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001872406aa1b865bc76f78ca5791f5d8d7a78ff7d70538bfcf2bb39287605eff6212e1c7f17dddb4a85b7cb9bd8822ebf00000000000000000000000000000000147adf16cddbe6ddd6209a346b7e49ab2556888afc33c9d91d6d3ca85d294eabec0c84c6941e6ac0c1f70c96068d11751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001909524e6f6b1f42dbeed9f59ae0e0864b406e8119ee44c090478804d71ec330cce73cda0b40c5146fd7322c3905f7f100000000000000000000000000000000059034314201a64ea473b09c6442457fee247d41c7754044e75a9194a4790e81db29d98fa6c82d16302b9ced99571c7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad15d0b44530feab60b71a19fe0bb727e659215c1ded76199cf9e5fb1d453ae601680a3bace44f6aacde4959e4da77e00000000000000000000000000000000111923c739a04757e764c76dca1ecb3dfae924970fe6319499a6d8c91ce3188fa13dfe678d9362135b173378f1df724f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b3f097a244186b753a9d34aaef666fa743e2041490646cdb29061a89d33f86495ca9b4d8f26338862336073946f5270000000000000000000000000000000001233915ee82e368a4cc8c4cf67934bbc395cee6f9a07a82a5c3aecddaa572718c9d0e8493633c16fa8f972145e7c6ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a31c45435ff67c4099fd83361a39b0305d0ca1ac7bd983d09771dccfb32b94663cbe3fc047ebb8a79e86134ffcb89620000000000000000000000000000000011c821696d0354b0baf60435b3ad4f6438ac190ae51b50f82690bcdc2b985b3474a714cb02cc74bf7718ed4980b722d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6d091faeda381da24c2def22facf97017584c7dfd81ef91480f5c91e8d0467680bcb8f023bb24d53ff5a2a68f394d00000000000000000000000000000000016792e0773a52b96040694f1d3a9f9011ba4c8b3d48721514fee4cf880c7d2a4352039419230946d1ebc60a9736603651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea850dd323aae6b4dd6d61941e794a6b34989a0919ad97cd8a6ab1a3a999e5b26286350e5a5e25fb0fd1a1fb8a527950000000000000000000000000000000018634e07ca25c44acecd037208f50739a44c80a76a414ff0d47e4a71c4538e8d43709355c06d12870fc4cef00077959c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006154e62de42b06c9afc6c46ac15a77561d993585a6dea18a14eb86225a16d7a1fbdfae1eb2306af002203e6a8a3432f000000000000000000000000000000000007bc550c4dda3945ae6fbf8b58c6b29d4ad5f70a9730fd32a01b69e1d39e79db4784160ed6092fa4ecf48979bd22d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000431fafb50b9523931e298cfd766b6de0e648bdb09f76d5dd44e98920209ee10ea1a3fc573a1c54c033c35e1c73c1f2800000000000000000000000000000000083761021f9ac8a0870f733fe5b4466a31fc585bb32f896f6b738760bfe8a0c697948b149ddf741a012a0fcf21823c3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b601a79cf2ae52e9e1424a4ee500d822272fbe8ae2c822f1229e3ecb80420a2b0176f38c40a671bb56583928e34dc70000000000000000000000000000000016fdbae8996fe9c304e818871f8936d71f899f95b2f7a062e4144f77493342a8345e302e0f9d44ed099294c3b68d78a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016269e9dd8b57d7a110929ac830f140b3ab2f30d2b346aec59cfa113f5465c1e03be7f247d67deeb391b41da27645af5000000000000000000000000000000000ec2b0d198d3b587ff08cdb1f8094728261c41bb9898445ad60274c1c470c1313322148699b2000941b77b915f27c7561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c30d2b3c76ec35bc2f6d3b2424973c8dd889c738aabb03e4e093cf3ba2644c2fc5e4b11c36c6465880d237eb43893e000000000000000000000000000000000b42a51fdcc4a21fb78aac34d4713ae019fe877a3a5b519b749d8d04c939e92993ba1e292b116afa7cfbcaa653c5a92e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017430b1e9f9b4c3b0ef8cdefb3c4e8ace13b1d67f34fd71fdf9c2a0b278746ae02c204bd44a1b0eb3d9442c0051dbf6a0000000000000000000000000000000002486b308042995c6e184a1b7109a2e5b3a5f92b0dea150851f3b356eaeb869304c3f2afa79db2af23d462c1e831f3b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5cb8f1716ab70ad41a1dcea28fa66550b85b1479cc9051c1382ea63fac7e60b442a03d852ed7e770c678e41247b33900000000000000000000000000000000045e9bec29fcba13ae3db440d1e78dc7a21185fa0cead088d178a1d7aaf4e2190bcc31c670168b2fc537c953a20e6f081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5ed9dd21461ba501c0d18b5d4d43aa96603879c0a79600e0fd198a6fabe8c999f5789ca4589a14370e541b6e8f51760000000000000000000000000000000010ba806a2fa9490137a2b55e841b8345332ac26a690586263b535fb6c7176ccfc942c723d4e436f23dd4ba50dec4d37f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039f1b01a5a22c1269df77611728ea829e6811ab50ecd3f6983a267d1262833d659d0226f8a806ae14c5a0bf093e1c7b0000000000000000000000000000000013363b08b1695a5275acda5d651beb16b32e4128728c4fbb58836b98fe4f324b5aecf6f6e7699131df3cb8fd400c1d331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130d4b1fadce27ab8f6f79034a0da0f1facbcc623e4fdfa6a321c664f07e2f7f8e5ea979a484a960f0f9e2db27c459f900000000000000000000000000000000024ce1ab7702c712d8056f6ef16dd90e798ffcaadf5c34f26a89e12a4a9e4675aedaa1968f64188ad89d814680b6dc321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138ebe60328cd8677717608548dc30b1454023ee3b11d3939f9d8b053d92dd1b0efc5967704fdcdc9ee7df8aa45b997a0000000000000000000000000000000014709e5abcd566343ace59443ab7bb17b87f5e2a8aa5c638869c51b26ada593b5fccaa62c63b9459783e2fde2f63182b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d0d928b383aa45cc4f3626789541a2bdea9f5ae0561e70bddd3f12fd32c1f2c1d364cb76158c0a725840dc91b884af00000000000000000000000000000000127c7434425891242e174239f35768a8ea53e2366670ffbd4b8cdaabbd506fa65e7cc8f0ef5eadceff9e4c4ff4f9bf791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3361bf07dcb795ebe86546a0721324c82c190530af4cc0c9fc97e604918a1bb41537c1deb1ef1ae6ef64ba22125ee9000000000000000000000000000000000b0da95098ce9501da6d36692cd7387c76089de03ee7daa191adb2f349cca3dcf2453d2d3a8bf42858c3f448f19ee8541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad29c630ad12fef0c344425295f5a16aabc9b498d14c3a1aaa5bfe243bccde6fe791fcec0989f64e457377e3544d72000000000000000000000000000000000127d93ded907dcd4e422146785bfc7dbc60c56353480e2e8be78d927f53514b8f1915481f86998a177ba94b6d96374911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c60bb2f7fb2a5baaec9f60e68088b46ba854d9f58fe3b413247f76d9ca49d4131a5912dae92428570ade4bf53dbf6f00000000000000000000000000000000003e21c9e5a9132f5b470838f60de7c9d08be400a2d8d3fa0956832f5f91c64aed040347826116547407e002773ca51231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e20f1527781f06bfa0556ed5b3351a569161bff52d5c53bed067ad8e92ed5e0b74ed673744403edb10151ce09aef8f000000000000000000000000000000000913061357c40e0d396e7bbaff74999e64ad7bf31087a1bd0227acd86dbf6a5f981635a16f447271d58762b039d689331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188e91ad481ef0781e04bd123ccd00232eb5e6ac9e58c760373409639bd436e7396470fe343d0208fc590091b5ce6d29000000000000000000000000000000000547f95193a5f2b8bf4585b983884a3bd7b04731461c69f18de8ada62457fe4f22b20c051d2edd8ebe7266e0fdff435d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f117aa0cf2966f0ee0b9f7d54ece6ed73929f5b169717f196189b464a57a89f1a120825f66978d972eb71c3622a14c00000000000000000000000000000000016fe75724404866207758d508e13d570e32b94761b04e31afcdfb6364345b7bf715db3c85e3b1ea0671e9e567e8b1fde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002922a91387620faee87bd78f1b07696833cc1ec8787f57bf0884f5303ec5450e8244c9b569e35849448518662ffc045000000000000000000000000000000000f729ae44b8d3e76e3dc1ec52d8535b207fd6985f744f838630bbf9ce981b8568e90320c2b62fb0fcd284c647a5f82b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065234b9b0ea88385aa4981614c43fc02474e366ea79b6d215a922fdacef636bcc0c6fad70290c13ea4d013b1d4bec84000000000000000000000000000000001690f45936ea704867c511a706beef775c0df83fb39d884270bd0a8cc3b42ee350c6f08a4cb686d2ad35fcab4363c2ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f51e3c9f6c5eed3649a163c4cf96cc90e3eecd3777009460dd45ab93eb01f07f622701cedf638372c60cd4c6a3a92e0000000000000000000000000000000006f00e044efd13dc533c8e89d21fe78b927fda4752afb2b6d992965934892431deae064e6f174f27b09b66c5f8a0870b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124797f909dfce31270ca24a725771d56eb1e0e728c5ae10043cbeb9990f0d8b3641629fdc6e660a96d15fb5e41425fa0000000000000000000000000000000016fc687d0d274e36cbf8fc4785a8b9733c9e478254b97ff569532ff68bf25eed08b12a88043447082254ea01ecf2a03b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001980d05e67034a5d7a79fcb8d5afdbcd1e4a4bf8d98020bf9fc36513a30ca76a3bbd702f51369887ccb255a395a5bfc3000000000000000000000000000000000bf80f58f5ba700f4e8589c98ac00259a2ce4dc205bb739ee5e338103970358b01ce10de4c0d0c940f131ad8b1e7bd0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000651d2421317cc74da93d1052c75eb3e2e458173c06bec03c37dbfb7d47a737f11a77ed240cda5ce3634e53f6cd5a6a0000000000000000000000000000000017a66eff7687bfe8d797054948e813f1c2a7a53fdeb2854e8aa994f825c0a603f973e7a6d1a890ef4e8605e4b4c501661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159781810a404c8d3b9dcb3509ae01159bf2f0c5ec61e7f0ffb76c970624d8ae678d157f4e2c37e2f256b4875f65c9f6000000000000000000000000000000000c00726ec52b5a20b5e02f3b8dda399e3bd0b391c45e84c0fb3c1cd2dcd6840317295746904d2dc3a90ebd469e2487901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004080df94e2a441b9efd78676cabdef959b0124654f1ee9fe82673bfecb7f80ac7e4f035f29483bf03adf3d3e024d02d00000000000000000000000000000000020dbc0d81ca0766fdd4f1d75664cae542f51d1b6ba9dc8677e6904f1bd8c299ce705b954243a3f65a29a7ee2d37cbd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001089230dba7c884854c8b34ea86cad56120943a6f8093c179b1c88dc4c8c08f11941c326850accc2cf7cea518e7f9dad000000000000000000000000000000000e1f8007880c2fa48cf3d41689038762ccafef3da51145e93996796ca03f834c6cf42828a86f0c10130af6dac681c74d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a81d326fcdbb4874c155a504cae5359252ea2258db77689e35077a107be2fbb5e60ad1df002bc4da1084b82b90562f000000000000000000000000000000000e071fda83ff48ec0c69d236e09805b7a3de4b070728a8d7afb2aca801a84fa1c302bfedebf6c495ccc19eefee80acd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bc01888dd74bf1d579943d73f76cf9168574d2ea781a56e8cbc08b65bb0f7e232c348514c7608180058c79f47ff10f00000000000000000000000000000000085482021f53a52c5d74eebc1ea9f6c2fe1bae4d53e50a28953606eb0ce938b5e1836322241eafdb359361dec6798fc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b01008d2e02a255ef7959b45a2579bbad67d35577602165a72299cd8485119bd82380ebba9b15b96d7ca4e3b7a592db00000000000000000000000000000000051fc56ad0fdee44e7547328f7bf8e0a287a4fe12e327435f8b9b0b3ae11e9de638fb1cb31b3f2b19816720100ba5e0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000961322e4b85d3b4fde11276fe55f2e01f9976d6a58c256381835c7c9fea455e0ee1ea92fe96a81c4da1da26d086396000000000000000000000000000000000023a842e8ee3faa1fca123e9b8876976c6b69e755937e9f48d7e80b1db75e49a059e0d501a96b1804f7ddf15d29ffd631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3aa4b508ba6f3b6a0845fb4b99bef35e4461f889196ce8801e20841c71e0809feeebb8cc8fd38a9cef8b6a02a3f64f0000000000000000000000000000000016b8c6b52fabe93f4ff7975f23cc7da6f636fe53bb8975ae8a5537be5d4942097fe736afddb95b277260f497d6974f371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001619a8b47a41a884ed2506b59a36fe159a8dc7eb7818552d66f1d1694bae768ab777f81a5f64707988327040c673613f00000000000000000000000000000000181f6bc2693b6685eb2464fc6922d08566807f6d4bc406499ddce894c69e50120b3c6b9d94c45aaed904965dbac5f5a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f6f479610757747c178a2172269f03950e2cbde1aa4d0af3828ca5e4ea3cecd7d0b528b9f94f8d9fe97cc47393b4fd000000000000000000000000000000000553a349e029b92f9c95f1653d340d70474fad4b5bb528a071c9d5bb1a1e95cf7cb41ab5098559d8076bba343971bc121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001167989ca880c6a3221193c533b8844cfae51f81c16c9cdcedab20f1ce0e0b11b2410818ac0e8be12e744ffc8e51525800000000000000000000000000000000091d88c66ad50b30236859b29a1c0ada236f78525513285b4f51b35cd3cff3230591a8b77315ae4553f704786c99f2ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c917aa064a321401bff66177439c346f8019b99865c29a0d1184aa5ed2de41af31b1d760c151b3af3dc1b6d35134e88000000000000000000000000000000000c3c4b5d56594870fd8628ee8e1dc6a591174c424583f724d2ceaabc41674d182fc5a0a9488b30a4d3ea024a76495f591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a536381edd5a87ab8d48d5b5e2d126a42de60d686eb956aef32d3b887e7806f8e9b6c632237255408f0e961db05c8c000000000000000000000000000000000582665bc7cca1e26fb5f6c1115600cf6c8312d53697a521bc4a63f51a8556abed1773c54ce4fe9342121245f3fca2311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005aa7ddd5c99986f09e515c5586de6a414135f25356f79d8f20b327e30de60e988cd68e4780bc35db73a2b22012da10800000000000000000000000000000000111ba3a532de06535a07f4419bf56cee505a7489cb86fc84f10e54b224f0874cb1e66eaebb0283823a2c5cfdadc5a4ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008dd714e2f323b8fd1029b365c00641c8b0beb60a2a669e75b3cb28e712d0c7131c2c21848261930adff3d02d6e7e70b0000000000000000000000000000000000cdd8b77a2a1b1c61690aa7cba2a578f839beaddf25e5ab3fa6298035c34abda3919a38e6740da471ec8ae6811222af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dbcc8e2289a220317e815b104172cb2e109a7d227cf6b03fa0eef838059c98d9c5c127c14a9af4c2c5cdd015a36dfe00000000000000000000000000000000194ec626ce2ba133e837d1786e2e619b5d1d68b0a5a3bf9faee959880cf60ea2cda3ebb00d30273f209b1f34a0a507d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e422d5adcff6af64faa995b59de2af18d10b4f795c93cafdfb2d9cc5d875f5d779362db9b178577e4669915864cf3e000000000000000000000000000000000b462b874cd4c1678ad4101608fe07fb0cddb73fb886fa1d3c7916c9eb7dfa72690eb6cc9c7b55b9ca8c111f6ce8f4041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6abe98caa71760196de9ad7d16bc5a7919f7e4e38f37743310f57cf5d8b6dad649dd1c04e21ac7278d31b839ab2b7f0000000000000000000000000000000002b8ebbe772212359a010a078666d2a9f5ec00dc9e6b479c4005b91c2efc54328075c5658011656ca7fc7398479656551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179c842b7a2557204d2943d14ee7aa0ccfae8ca3ca42f22eb8f07f78ecd462c94f9035879707a7b8d8f8c5c79aca8b970000000000000000000000000000000007dd30bd37d3e62bd741dec6f5ffd1f664ca5a3ee3b122f30dfec4bbc519883e201e301ba92aea0c3fbded7c7e8627121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059608d8dc34d6caa30d99c18a262263be3ea6caa99036e67b416bed3e48706d2468a437f74d8bcfde987838c41a1ff40000000000000000000000000000000015d119e2c6099694f7dde1372102cb52d4c04d715c0fddffb34d4432bb211843e8dd11a1ac15dedd03d15c6d5ce31e311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178048144ef4543fbc2dde1e76fa2c723237be6de82f0f4ae366e132e68428f2d4055bb83424594dc23a86292f79057f000000000000000000000000000000000991fa76a1fbb1bba55c66597ddda281d65846c4b8b861666b8e4c8a4b906e5f189a902e2cdf6a4449660e2866dbcd3c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014945b7b2a4ac17191517869b021be60d1c6b580aa47ae59b96560213b664aeb980ff40b0ec3f1c74900bdf97e48ac60000000000000000000000000000000000a314b237a586ee94cb23ff60f6f5cabb5051e2e74de45f4463353f085e9e1d99b666822574e1552914a88d95054de61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ab716f50f4163f425ced103caefc1a1d25f97f960246bf9b0e7cb975dea7b28be893ee1d672c2b8c95c1af74ca9cb100000000000000000000000000000000041b7f8284b4f666d3d74f3b00b5482cd5ca8382782f54379f50c8bfec00996d71ea85f77467c83d858e4030bb1e3b041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d27524822be59e0d9308d04ea18cc5dea7570ddd1c787c759230188462a38d2ed7131e7fa41957362e207669692707000000000000000000000000000000000b4e8be6323b8953938f4cf72ce8f90902b057d7e652919d84b1eab345a5a4cb00f3bb8de71c1ed42bd6d13b77b7a5cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007077aad17f5a5bf5147fa71bd7df259acf9a6d514b6b59075cff6db10677e65d166e6b55f0c51fc8bc323034bd718ce0000000000000000000000000000000007dbb66d3e8744468f08d11e719cb1007088a04ddd34197f5eebea5d8594a6c86c087acd6b8e89253838ce17a87fa33e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be958765cf288926a31f7ee36ebb8a0824c7698e1b3828ae0173a000e6deb3447f988aaf4d7b69a594bd26017e85a2d000000000000000000000000000000000f1b8a2559eee674dee0f6b27fd729104b30c9586270944bb71069da1198491f116e55eb76275e809484d65d921a73871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9c7139db94420da23c31a5c8e5ac5175ce9a39d3a60b10ed03e90bcfeb641e43345af01124723431746302085e0f610000000000000000000000000000000006bd43c3d259dfdaab8b111a6ae716e25e32b76d3a9b8f2cef5332d5b558f023ae0f10bc2b982ea509a5c8f989f930a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ce5e19dac7549d8c8be52032fef1e26e0c9898fb6f0fb67ad11577a350af609cad635a5d0c2c6498443221f79592620000000000000000000000000000000010e6a361c4c7c61e2911cf6babc634904dc180050c9416fc761332ef59a2a61b52cae921568840e6561a6e002d068f561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b66ca9887402d79dd08bff64f56d96cafd2ed598efe9324b3a05f0bd4d85d8504ce022a61c85773afca59aa474a4d2e0000000000000000000000000000000000fd33d7006a63b62c6a0c388d85c90562cb995f86e0211e9545bdbeb6e611d81ad6af34d388776757c20e02c3ea74941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7cb1b5896efcd4694c11551fba3f155d8adb936e1d76474f41497d3daa34a73f86d352a281ce8a2281fc7c8b37518200000000000000000000000000000000089c9503bf95ac414d26d55e8a1c5c23a95bcf655ee94ffd3dac058968ea07f30289766ed1ae02596dfd338460418d081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1f97b1fbe4aa7e4de7b859de8a34634e9c0154a6ed19149cecbd1f659791b928cc83a2ef029c2361e51d2e2460754f000000000000000000000000000000001658c1ef72f1f9301a3a2f0918c2eac6051603384f59173465a8819ad6232cfa2f15f52b4ad9d611b66169ce1072de091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da3cc02370edb8ff35edd976eb79148fc9f7a189635bc34af81dc81e1b8349a28c8900ef379ce2e604fb03a04577264000000000000000000000000000000001334b442395a15a5556396af1c5c8228206dcfa35014dc63c3e8e8c14a818f5159b494ce2cd9238bc855abcaf82401001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075052afc243482153bc1ce5a7e2873e785bf5200f5856ac7398e673a53770ccfb1b23f292c9babf3aebfc37a0684f6f000000000000000000000000000000000c92f8a9226c7605cf170b74d35533082780fccd5972cf09ee7a98cd88d621ba3c285c6342f66c44a39183f1e3cda35c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008556ff623981896d755b33fb8419ad80540f3bcca4389f82e9a175a4b5ce293ab5de5aa667140d97d0b6889480a16ae0000000000000000000000000000000015acaea8115744c245165458ba1e6dd9ca51eb47fe79b2320c64f45d31873d66ce5a0c6feb6e7ec67ae0dc5d926a6d841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000994488ce9d79f670a98d96f2a34d38f845b69a859e9c0e62564266fa6c6a98d39817a5fa51881b74faf7817968f89b70000000000000000000000000000000014037d46d79caa3de9236ecedcaf510241699597d0810d0a6453a8523c0adeafd4bdc3e8d196a7996feea92986686e0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010049b11484be92516ea8e296da69275d8374d293670a59a3c7569f9ddf376b60e43b31367439613d05abf025b1f295200000000000000000000000000000000097662cd496dc28fb41bbd79072df4539e8945769299a9103841292f35d83e5dc90129a61fd2305f0d294e77867244d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7c2beba5335b3bc4ac63357749e865490fa474fdb5061121f83684ca466f1a30287cc9ec3be53f387f0e618a48d954000000000000000000000000000000001258e3642cf85ec56795763a2eae6ecb8497eb5e381f718928cacab2039cdb2371870981a68461d969d03f3cbe0590981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001719044405e8a408ea41921c463b781303f6766b26c4078e092b7b6ae4281bdfd3323e1d1f27b43d8415f1d2bcb8317b0000000000000000000000000000000018b3b932b5e1b5fe1d4669536a069ca130623132e770feaf0670a4f31663ccc0fa1109e6adbf2ce911179a8518e366a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b0949391d2fb9fe822afb0f2802eb7438a1604b43f65e04144ff5d77270e43dc79b91d0c87e2450386510f5008d1d6000000000000000000000000000000000304700ef60f62ab6c64349c92b83102079f98ac56676e560b33bbc23c160f5e17b569be8962f68af873cd967a9a2abc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fa75dcc1bf8f93abbe21843891bb6feee051c0fa17d85a1cf26f3d8814b91474b4c561170c125998c00f836a712b2f0000000000000000000000000000000018f42e3dc7b5ca94962d4ee16a791b867ff98135ea2c3c026fdc657788740bfc173b18b08efebc9349243b932d7c34ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001394698e826d7bef8c2ec23e6a919277152020faa1726383dbd9340b7acb377a1b9956e74bda055b9f04f3933c8036010000000000000000000000000000000016bfed5a31e376d1e0b5120ed5f518bc32ffe19b209ada87531a2849eb0d43c01e23a0a3f030af5c462756120a417efc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6e86020cc26d0f917b7facba524a8721b944b00599b7b96262578fe5c50b1626b90188876b0030a7144dede2d4aba6000000000000000000000000000000000337cb713f5dca702bad8cd057539fd4bad36c54d856c6d880e0ef561548f54cb28536a285d7ae274b789e1e19d5df271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d91201ce0a03c3d98fbc6e967727176f416f78b314f2ad7d44c3a73d4a017ac05e20a0f694bb6b915b45016545857f0000000000000000000000000000000006ec3a170539000ac9a60c14f3e2c425200e58cce4a15a0a9e934e52a9143c9f68f582dbc493dd52b1647fa82f95f0af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000577a6a28c46ebc96f09ed8f92e0e5cf1aecd0dc1f8acfdab70adbcc9ddf97d1392d211cd46d337605fabe0d8bee1753000000000000000000000000000000000ef66e1dec70cb91fd1f2bdf6e7460c225005ab1d4ff605af8f6beace860d1acb2770eae3e3b74322e512d6416b21a731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047deb34e613e504d08da46bbe0d0863f18bd5787fac9c905bb80ea0aa4ae36341b34b01478688a5c666e907f92c01a50000000000000000000000000000000012fe222d07d73594c3dbd82ac4d5c9043d79772d67553120080e4d398e5de2c608059e089f3dfe2cf8a7e7a423df79cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019575ae5e86452a763ebf49b4241bcff0f0e76eb9cf4069e901f126504bab9cae3dd025310e62b33d70ea05eaa6c006e00000000000000000000000000000000156a6125ce8b1f681ac014f5c7a75e98e811fb25e35f44da553f13b7865d7f671d02e99f0e0c8eecdb811c4bf1c239ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000059353f4b3b39938979692f780bb2aa0bcc26d7ac68d609ef34f17d3dcd8efc84a6ad051aea502b42948ebc6daa3f680000000000000000000000000000000019c174736ee25c2c824ba4d81390650454ea6d1c87653a1478917eccda42bfd6229fc82a7cdf732dde7c1ec92f6206321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e82768dca49536986dffb242eb8dd1ab0475a2d75e7a795d3db8dfffb5aff2161e7c9164af56d277b142fe677379f100000000000000000000000000000000033863add33d93e95e21170348aca83195c37189ea3147e962d109ba7594e0a0696d1666916fb9d1623e843dc703e7801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f7d75f289b19e1969a69edaad7686c49635756f788b9231ebfe0440a1aa5ec0f8e4333d9e0e824702079df354b8c8e0000000000000000000000000000000011479b683723594d64fe0de95b436ae2d71d8e19e4a0680cfde1c034eab1aa007c177fcd0164fdf65e3efd01204f4f461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e721b73a0a7b9c1d2bcac1c155fc1c78fc5156a5251051b3ee7622c2832290a66c046af25cf47d5169081ffea9a5390000000000000000000000000000000005f7b83adfafc68ba7e29fdc673cc25015b57392a67d11eace617b0fe7229e4076064fac9a5012acdbc037b6e7bb2ba01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055291b0d854bd145cddc63048db23570ad19a74748d87165f662ec36620b2992b56df69f729129ded368d64ab3bb2df0000000000000000000000000000000019e2040220d9048e2eca70f44e17c9eeefa3a057ed28065b401e3f9278f10832358ad44b059ae1eb294256621efd60bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d87be06b756119bfe4b7fb882275922fbded986a8e1304d0510a10fee80edd2d6e02359db236e8b414a856992d09ad000000000000000000000000000000000fe56e8e7368291be2e60ff12a3c463485f97bfd39826b1d9876e0a984830089a32334ec5f32888c1af0b02c1362f8441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000371d3013f51412b35c361a80d96111d004706a63174ec6c254da3bc73c9bfa40bdf793ddd5658e469c3540e4f24b776000000000000000000000000000000000cc91c03b7246408f709e78aa1de8891b2292ae8c90384b2938135333f877adf0b7e9a712f1c081c556679c9958e2fb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002691ca178725444ae61bd733a806327e5deb021c088c7d7e3a32ffca00251e14354572a63287044f936f1a485cb91490000000000000000000000000000000019bc2760fdefb400842b65ca4f5be87e33d4b035b24eca51ea2ee43df6cd12e93cad90ca73c7b1747372cf02e54051fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd5b5722a43bf8097d7b4f39d81c84465032e5dbd16cbe58a0626b398d199eff5af56af77346b478ba3d2ce149178dd000000000000000000000000000000000e20932d9a58cb489eddad1f666e968970987824846d8a88874f54d35962dc5fb7fefd7c8be1c9ee3f88ea1609814ac41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f2fc7acbb085a7e3740f7a8418dcc7f41b72d79e7f82b84ac1c752afffd088ffb3cc18bab6db1e5a5402b81f4bde3a00000000000000000000000000000000000e3153cd124f94092e208edeb077d9f43a45e8d38cb6952bc5bd1a7636da46b60bef450690c850a0bd4137003c99dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e21f8f69d58edbdc36e496b85ce348613e59c4d2e3e1bfa85fe2210522c4a1013ad500b1f823cdceecbb51968f802540000000000000000000000000000000013b719ecf1e66aad74139e19b87a9401dec4eff7c699116a7fb52b61c0c49e2307b052e9d9e227a929c340dba4dec9911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a66b6e0633171f799c7d96a87c6337d9cbda4b585de118f3283f035f48d5769cf765030ed1ac7bd5feda2435da76f800000000000000000000000000000000025d5ed119cd948f1f07e4d8760e6e4835c4b034e3531a1276984b1741ce14f8c2ad590ebe70aa73dbb5e8084aa612fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100236883827016d7437babd245723a840b89522c9ca73076887571cb55d52ee7b6061fcfab68b2d3d34d70113026b9700000000000000000000000000000000139c3267dbe37bb7d3da9f2018cc99427e3d4d3acc4781b1a7e09a4b799b4044f947a9ae01481c54c57c686371ee878d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020a95883d7c8860415e4309613445372c3ad6386cc228ca5e54de213bfcb570ea0b63a806a444d7aa550824210811fd000000000000000000000000000000000fd9630c7094a8a2d430c45f3221ca9cff1a9bcf9d9725eff9f57cbf8040e9d3ef0b21f8f2454acfdfb09d8566417d251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbf96c729a7433bde8c2d3e048228c02ead5d85002c486f732175599b7c027378cd9276dca7f5c8c8bbfce18222c51a0000000000000000000000000000000003a822ac6cdf8363ee3211060fabe2fe7d45593c1c537a7c20ff675d6f3f9de4d411704d0ba1e208faeefdb3854cd5331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000089cd71f592c3580d9fc6ed21e5d5982e99b8729397a724a0b4efa89afe92455a963ac2642e5fcefaae52e0a1c28483f000000000000000000000000000000000f11dfb4943ea9c159d279b36e9f0c20b15802db40b6c7cb7ad537d59e468698d421dad9078b66240caf03d587a6a3a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b7afdacad4183d1d41a3c357f6e1b286d55e5ceec500b1d0a3fa261b8deb6390e861e5495f430d5c7f658e4aae9ae700000000000000000000000000000000123a9c7745cbcb2da8283f8230bd54f844a1e500c03566c5fdd77eda6322b7e96d18218063c4d644ba7994154cb6fd061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ad7ec6006f03def1015a390fb9cb6a41467dc7a1e53621d2b2bf57be21ab21c1b6a1c5aefa7c98d0e5ac813144877b000000000000000000000000000000000392a799c068e3a754b30d08f3fb74b521928ba9de0b1b1e11fdb535e8413b66225bcbb67e5cbfa19db122ea342153dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005446d3bfa284b2abf019cff0bea520134b305a58b6027bae727160fe6fc26493f3549c963ac1596e95cf28147c3d28f000000000000000000000000000000000ad0d46a03bced7335cd0b10e58f19326afc772ad516bbeff11b0014b6576fd938f86fdc9e8d6577500b2b04b13570601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e694e5da33617f95e1a3c5d30cdc212f908cd64e82563844b4648d3fb9bfb560bdeb372776fb4ad2b28dab4c0da8d0000000000000000000000000000000001641d9f620cc262f55dcb5b4f35ccefb98d21b906681fabfbf84aecb92b97091f8d3724086294137e87e5e4a98a22fb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001893e09510804b67b0c618f7aee666a93c2f7851ed26b7b8952286de4d0e011cded679cdb277c0e86a732ec68658ac7d000000000000000000000000000000000b8ee6a99893820a69ca99839ab437f5eec445ca73c69f1dc3bea3e5c9c2ef708a74fff925cc609b3d86a2017f35f72a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004232efc15a3a48bf5248570bdcfa33ab9aa37a1d5b1e011e2d8b3348305fd0fc63c0d9ade59a92714e66f7d75d08c63000000000000000000000000000000001473b1592d73f47ac8d0e4f9284f950b95b2329de61c59d992dc85402f17b7eda99a7b413a8072a55230f38947b340791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fda1c699f7853b1c2d183ab064581b6768b1d58a8dfb1d93d8503f812ebf27739c7eef8460d82c88763f9bf699c4cf000000000000000000000000000000000cd092694c5383d3a3a946c0fcfd9fdce84cd629645cb188c89cbd6dbe6a6d92b476d5b3aa1b7e39c8eff684811f2d111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013fc259bf4982df8e330d1a46b4c5e6dd7c8f6ec834015928174ef0ba76f8b9da74629425044293985dca6669b7195ca00000000000000000000000000000000000f24008c365c1e3427c7a32098a7409a75fbca89f13f14201744cfec3a8da8c163762bc20434fe0cc1cb4fb0d9100f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d95b930cf40061611e664ec0bb874a1b5db1e2021de48112f674dbbf7dbb7536d09fae9bf4d04c14a154c440093466d00000000000000000000000000000000054ea1649303ba5291762da24c6b24cba7bb76e219c62fd8556d7d982d88332c93b4078d664b6b2a42f471e877a248831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b9d5f3976b63af77479a42580f820d421266bf584b4b703f75fbb8f189c95749c978a3610ee2cf513c1808d326333e000000000000000000000000000000000805133385f2c55a1ee95d0092cb703956f6594eb3c11f46b401edf9cd5aa0c1b2857dc6fd3faa39185e054b28b675e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008415d387ada727b7d8bd78a24e599eefda04952ef9f122fcaf046e2c3a94b8c8d77f7fa126ac13f375061eacd29c45a0000000000000000000000000000000001cae1db9825f1e38132bdc40728c875d6ce8d7f2c70cf7dd9e17886c233333cb0f5bb319bd6b677044c3eaa10a8a8ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f8ec61364e420302c7b69658bfdbb183acb44ac9185324f715fc3b30908932a7825467b520525b205eedb55b7e481f00000000000000000000000000000000164eead0ebbd34c190e152013e52680b1d9597a01383613a7530600afad000898245421a4c0991f6829cf0a1404df8421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075d5fffa1511130cc467ca61423c22b64221c47c187e2de64d1939d4443e5c25175c862c65120e3e490fcf427c2040200000000000000000000000000000000184eaacf3ef66b2e57657da7a950daf33fd071217009e74c3544ce20dcc96c7b0ed155c34ab3d0d0b137092493fd44511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000763761cd2ebc040b662475714afe908ad9dd5ff8c3b6b5f9fb8e18daaeb157f03c448f1c3de705857c5df8081e07cc9000000000000000000000000000000001760103ebdef4575c582f7ee7650332c5954d099c0c3098322ae08554b8996a51e5124d8f7a0d66b821bd202480dc5101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4240f8dfdc9ecc192e58aea7bb3b5573a206fd26d52bf885d698b0507e7b1572b219d53e6128b6dc7e42b67d7009bb0000000000000000000000000000000016e633b88455b1f07c72f3a88330ba6e8d29906b88b79a94d13af2c347cc587c557ef61bc081c8be5961a7eec4f2d5cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191ab694a3c060a03c63d48bb16b50f7a913bded06f0a98c0a9decb62ae7ef78c8b5908da6691b8414a90a8b431f6e870000000000000000000000000000000011b83ea6dfafc7d0f3e5e3bf256b3be362904dff9ea1bdb84b5e867b7a365bc4ddc9066efe50b01e8d9bf030b38e8e801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171981e948dc5dba3fdf614a8799a19be786a4572cdd9af1e15ce642b3dcc9bd9cbe8657597ffa580bb987932c054c320000000000000000000000000000000014def38bfdffa433746034a44e5711d83329677c1b5ab9ea499fc3caa8fc7ffe1961efd038b4dbdd84071621bde772031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000269898b8cdf98033a58fb9d834f89fdcaee04a1b194c806310846ebf3858718a4647e26ded7826f167e99030239290b000000000000000000000000000000000fc3b57be5af8738ba84e91e06b5a19fc507829de39021a1d15a0d65801a3e222969b53dfa49d7bacd77ef4d8978bb771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e55aef891af94dcc17bc8bb0aecd5310ee5c4da39aa5a0ddb826215aacfecba2d297de893bb06a4877f3b678fc252d000000000000000000000000000000000135d1b35cae63f807483c1a0e20af28171869121fe9449b112128ba2d6080706e245be90d549e9af074289465c0cbb161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000733f487ea1c6525300ee545a04fcd4584c9a8036d4f879c68e980a2672740107e147bad96471c0edca4648ef08f200b000000000000000000000000000000000bc2fd976f9a0303ccca59bbf788bc6078fef17f232aab528d39942aa533ba7405f268d875147657ddec24603275981a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ee05afe992efe78a9a27d1b038ca23b91290b5d4a6eaa871edf410d7b8e929aafc71180e3de18a337c07d5d67b580e000000000000000000000000000000000493ac823d362e1947ece5ef0d9df9bc3a2e57df6654695b47848458e74714be7aa43220460165c406eea167ee6c35941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000146cae7828c871adbe7c9aa5072f70fcb89daac458d8a42bd8c6760153b106efa2e28acf477ff927f83b646afbae8ac3000000000000000000000000000000000ebe6851cd81741443640d24c1b3ec264092850c1ba5e5aa51bf53f338dc7b7e03c9053dc2fc2c48a391981bbcc4c08f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013eec155f3f320144984231a7f62b3d9bcd7449eb4e5aecf7834ff39849ebcc04f2e5c2728adaa636ae119c2d0c920650000000000000000000000000000000018c891edca4b070e6cfc9f738223450a8e2ad8d3e79d9fb0d55132da4065f18df688005d33562626b486fb96779d8b8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a87625563e21ff386b5abca07f3cd37da21e7894282bfdbe976cd368815ae75bb316798036e63a0f274ffe9a78f9f1c000000000000000000000000000000000ce9d1a6fde6c871fdd5853b0857775e9f3cc4b2da096ed3c30d03c06cf440d37ddb15277b9a8aad30b2e140d24c5e001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053f29777c0febd658180eeaa3479ef1c4bab87eee206697ffe5f4aa7df2634b659530bd2bc1040ec0531609a1ed7aea0000000000000000000000000000000002b5588b0b10bf9c5949ffccd537b802a850b5bfd01799479a74c553703e96f53296b12a3705419d8785a507e6077da41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff1481cbd1c4fb9352d735cd559f76e0065d7f35553bec072443b06ff322d05c1c22d8396764f63c5b22c87f69288570000000000000000000000000000000003c4bf0361df71bd80a3af7fa8d643003a11cd4548a52ab8556723da25178981f394d541f291a44ed2b1548d9fa229df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005e8c573f9243b489b8e8e6b6e3812c25583b649ee8b360a5f9e1255886af1d2e2d9f8a4fef6e3820cba98c067205ba000000000000000000000000000000000ddfb182115c90b1c42bf5dd55e0a967285393a78d5f536f1a8e8883130295d94036622d6a3fc3a207ae0288336529f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007258cf66474c365868e760e605fba0bb27602cba6714e5beb06ddaad753706762469f52d74b49f928842b61c1364a9e0000000000000000000000000000000009f6b234506e26b6a3b926236b1f19b1657d294d921a9060e4f9027c7110110d356b61fb7afc1564af64951307cdacb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af45c841e5e7b250a99f93c38a0040f504e4208828462b9e1fe2325ff4a92d7a1a029f0445f87bd5bf4553ee799063f000000000000000000000000000000000cca6c197f69648f137b812797dbe2347b27332f88957717cb1bf38a9038d24f6a1c20dbc6f52f8bf8fe46dec59005e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001385b6d645a8ab2e6cba02bb99304362afb60c34f4c8beb423a0720bac5df622776dcef9b9e6518db15d251575974487000000000000000000000000000000000ec28f0df5a3f0c79cf953226916fa2ab18a7f24619fb52a04cc012a3b9ef0849d6fa56c7c58d3b0bd13283b899bdaa81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ee7bf8363bfb242a3bf89ec3937e8d1e6467185bbe04b9b2dabab3c95d0434e03afb715d4174e4d40c7b12555459010000000000000000000000000000000009f0f0f086f6742f3ec7745cfc32842dd5e6a778242f2645c315cbafd7628405633acc6de095130370b604023484cad61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014eb022fe1f4235672e241737200bf507bf4ebcc842e2685121e4d34fd57a2b3a0c36dbbc1f0bf9c7fed0761a687241200000000000000000000000000000000035f0dac383b53c2d3c70238563a5b12d5b7d9d2588a660146f3ea2cccd330804913791a0a0b19f3844aba9bfe7b57e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000121e1d471691b4a738d8634a0bc890a6bc0d0e7fcf0d85d1ec0247b2975dc168bfdbeb67e20f7134966e749ed255c95000000000000000000000000000000000b04b88658407ba9d620a1212dd38259f927a2cc5925a5e7dd4abc4d3b1b1480d7ec897cb4108b58c12bb95218c16c6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c084b17e9d679d1465d77581f5ef539a896f0592fd3e78b35561d968f44f3929b59463ed40a0419da69e4cd68eee4f80000000000000000000000000000000015bf4506cb7c5a2a45077eeadef73c181e274c524ec2b83f58a54bb1d6e2e98c1c6f118ddd678b0768918fb4c87934201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001538f3284a8bd61b0a2e535f0de9d794654d474ca727377f4a9e7409a53ab2b260071d5e279e7bacbe1eec8525551e460000000000000000000000000000000018ce4751e42dd6b2f447827ed2222499d0e674debb5313006a7dffe52789030c711a56baed2f2e4a4d987cb8955fcf0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154347987d25ab3ac8dd7e681ad5a3a54ebbd4a32f7c8c3e7a8f8037a89ae5acf40def6318a8bffa7bd03d677dec82160000000000000000000000000000000019e06ffd432e00392437c06efed9a39722011984076f9f2b7329ec004e4510b89c4f1847dc39b4e2b61e8782852c0d111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9c045576392a4794b9cb8f3ede03e29b3bc9c6b90fb8abaeb4d7c3266997c880e099d3898adfab85ccce0bd6819e6e00000000000000000000000000000000007f04a9caff80c31d4f71a54755b47e762ba7e42a5cc31e928097f18ff36707df3b4e37e276efb6fbefb2732d5a41bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cb6cc6da249eece1cc3280a670f4b28324ff99312d9f97075e70e403f200e5b6c477f90c3bf9a1e5e3461bfeb7e1e40000000000000000000000000000000009c1246d50e097d93575a483fcb62fd93ec95c48e3590f64d9b710158092fc2783aeca954c740c50f2c4c2f2cb57b48c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c6cfbf3949f43b79c73ebbf5899322697fea7a9be00e7a7351f649fb8bf249769e3bceb37e96f7b7ccdf0725efcec90000000000000000000000000000000005dc908d0a24f37efe63928b60d3fd51eafe641f8baf3d106f94ca7efe0ecd2955b4c2f7d9019710368489cf16cc88711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f51d6c04dedb3ff49704c0edf7fc6f0e4b0f566289841e76f8e71732d8566e0e287d5cb50bfcd7a501b598a4bd852ad0000000000000000000000000000000010ea9f03f57ec7df6a7c8d7af2fe08e24a83f4190adc0831e104d78f664d630d7a30b848fb2b2d69138b46d749704a181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb81fef2df434848cb83ce22b0bac08ffbe8ae5fb21d08cd21c9287cc35efcc26cea01449f920548b14151a0fccefbd0000000000000000000000000000000007d5cf99762f131512eba447944d4d2d86ffbcd9a112367bdd223f277778c9766c891fa820f84dafc1e7c4af7d89fc921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006917b6c8cb8a9a0f47e43946ca91d6c01a321750c40f4d887fe25e5f507f341b9839fd1c80d505212756fd67f1eec3f0000000000000000000000000000000005ba65859db803b2a42f3c38e489c2d90aacca52d1acca6bcf679c87998b31ae09d52126f7207040ca5db9eb3093fe6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003301dcd4267b2defedff1a830eab983220cea001e39c994995d8a8567a4b1cab91b3bdf8987ab627da2ea1bff09246d0000000000000000000000000000000001630301d11df6c9aceae152b49ecabc2ef3d24e092e5ebdc3aeea336c4fe8afff884fb7a2a7882980ef6194e4f166af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f2aae64c08e705bfbf9ce6e909e26c62ae72ceee896605805ca9885332c84888e6f021e29ca3b10cd3206e30199e03000000000000000000000000000000001354494650b81915f2222195196562f6300edb365a98c11a4070536486ab7fd76e63fb0572ef06cd89cc92ea36e0ea071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7cef06da387d0bf821b0f7e423b31ff13532f43843589ac5158ab803984cdc0ada3c3d7c48e575891f458fb385e06800000000000000000000000000000000123cf581408868375c7baa85093d110cb74fcb5decf8a31a79a89112ed3f80288db25346b11f6a8f95eca2b12d0fa5841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b62444c72bb045e20a83ecd08cd1a613833b904561c190f94e36bcca1dcf61a7728418dec86aba6526fad0045f64a4000000000000000000000000000000000a74ce3a2a74c77a2a89b9fa93f462e9045a58643a8dcbc154c7b46a27ad2c0380782304b43e8256ea69b19b671f59db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bff7fb056f35cf0be36ae2c7942766d5d5216bc4aaf34be2e0909a491cc0ca5621a52bab2b30e9282ffc093a41dfbbe0000000000000000000000000000000004d3db82fc2ac58964e66798dfa35ec9c6e3da96555bc81fea825ba3f6ed79f227475e5ea126d34a6e93dfed8cecea591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e6f4e96ae1980526153e9bd611dbb808c8bb5a1181cc42d2c6e74d452b31853d00cb773f7815604d93327ac621086900000000000000000000000000000000096af5bafd872ae25b3bffa7317c2aba437caa9b740659a2c9948f77133f33dd2a999b3c7468e3f57d6d90ea968648621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193bc968b4e79f3c472c68a899301e91a6221f97f79c3ea3b40b7399983a9fd715c2c61ea3639d1f605370f4a1e51fbf00000000000000000000000000000000040419329d26a67f9e22301e81d411a3f848c628aa4c4becc2df3a17785060a8e987b1e799c48f6740bf10f6d195f9f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001689f3466d2fe5a0d10398ad7a824b990e595052ce03442e7961733dc596913e6dc84893b64f3eeee5e5bf2b4eaa75d3000000000000000000000000000000000f268947fff9888a352b2f6f3be56f189cd7376f06abab3c1f27d175c02f84c8177a7d246698fc7eae7f539e0a0b0f641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010db4db9c30521597303bd0d09461f8748e315aac2d557e5594cb9eef9f3cef978fcfbb2beb90cffffb8ac3b7182f54b00000000000000000000000000000000175f5aae55bf5b9002eaf184f2d284ca1264ecaec21ee15b8eeda322a362ce1ce1fd787bf1bcb2f952b4afc0ad3ad90f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d45945227b5794ce037ee632fbf3f6409702cc4287f03adbab87951d1e7531170fa60b3ecf55a0a5622b8b86e92d250000000000000000000000000000000005b357676a10815481b546fd62eb6fab5e04c262245d427bbc44763189366f6df0dfed8fbbf7f655319db2429330a8321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019d4c1ed40b88bddad28a5aea556685ab3e9edea9217d97896aa4a66f2e65301268944c574952fe1a13b557a7dca160000000000000000000000000000000001296404d30c977e3849aa239d63ccc2c076822cb9740e9ea56d271ed6ae9c750043950cadade9efa86da1a272c7880991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074c9176206f6dd1f06bc99c4467a381281a2f08d886f18dd43c0b1f0a2a16a3ea2d725b62a952e599f0a12f5eb14d5c000000000000000000000000000000000890188889990214284ffbdc80afaf2460745aaad98167bf95c0a7c446b57cfee596cdd1d921396a301550467788eeb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000bde1c5b939147169b4f66d13caa17703521b6a97593f1ea4016638c6a1f8be6fbb600404afb4040e6bda3b682047f8000000000000000000000000000000000442519dffed255edc41d3c3b98cd8e8f596b83fe2e351269a3e87b23098cd6d466df1d74d2a1258b6c9c1ff0d2d5b2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000641ae4bf58740b5f568303660d3a8e225797a0b907e1daa920c72325aa54c8942f4f4473d00caa3f4c060d0c96040930000000000000000000000000000000003d487164d426f3d174fbc7c52cb0cbd6f788fd09959f345af713bd9502b30a4e18392c27fb246120df81efbeba98a051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d19381a524d7cdfc05bf621952b5c0915b6d31780e8d534c46affe608e054fd7c8fca0c7952e9657c0131ffc1062b90000000000000000000000000000000015dc43c5015861ec08277c938bd70c48bbd774009b757bdd9759befff8b11fb0666beebd469cec1d61cdcce5cab699cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014edffa83ee0124e791f040b6293875d17db893d35a07a8dc947370dbe568e9ef694b79799e8cb267e7799042faa9faa00000000000000000000000000000000068f6b2d7fd9f128b974222ee2770c0ec8ac6c632d1b86f711cfd7a5c0a07f32a459a891bc537809902bfabd79f692271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013fa8717d35099e4f09f9c17684cb8de738638e85a27f00b71e5c78949dc388b5d393394b43bf2c5646be7a7f934d63d0000000000000000000000000000000003481c8de1b4eec441b3ec08434f69ebfb6cbb4e43bb8205fb9b06204909c484e9c3867e0481de0dd60252a90e432a8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5b2d6417bc6fcfdf57ec3902d3cbe3ac7bf1b5df1bdc4cd6131f4f357441c447801bdc8954cfbd5352e16975d0ea38000000000000000000000000000000000502484d6e79dbc9ed88e8fd02183d20e6986ba9d5f227a85c059f7f24281a9fca6c88b9ab2ecd88569473f5e19248551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a68ebd1e0661dd9d9b10aa87354092049e39f1c931f788bba59367242b34405d486fd399bd3b417375b6be3336fc1a00000000000000000000000000000000139a9d5d4139e6dc8e8dbb30169fbab33c7221467a7685177e06ef9e5aee027b4de97b536e893402395896966cc3f0c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1c05be27831199b63cb6826df96f8ef6a4531462a392b72d78f3b5bd9c4b728d5b7dda7c27b6e0e17e48e1199ac732000000000000000000000000000000000d1ceef58aa563f418b3dfc7cd136be359c241e682431734aae479663bdcf1a18850783e4efa6c29774d39eeba7c9e421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000104b8cfe6145341aec3bf9a3b45b6e10e96188a55e48003dd6bea09381a662b8ae3c447c4d598a6a9d919d182183a21e000000000000000000000000000000000636514129c6b1b57b39b3bcfebf1642bc813c3355eac48d4c8304a8e8f79434ae996a60f04484184b197b449ee44bc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aaa998496bf562a6d58129b9c542b68ab9bfe8c426d1d44ced520d8f31ac45d5b831a6bbd81fe4d6ab2e388bee7cc5f0000000000000000000000000000000007f4d95f1c05c1162b6b2abf7ac64de43c316e8ed60e97ef0bbfca9ca763ed98b5945753e120fab6c958c76d95d6f2411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152a3e0282d47c9ae9ac663d6c293b626a6fa535acd717ed43429c20891f32a1708b7199e3f53ef4b6d2f9ac19ae37730000000000000000000000000000000018d1379178a62cf7d8a145770ffc4a849e40164c3bc7891f6f070b3e706640a749415cec8e16b8427ef032087dcfa38d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001280dfcaa01e08c4d19d1ca5fa0411dbdee1aace0987a2d46d4aece5f326127e3d1f9ce1994832fa2d9f66b0775256d50000000000000000000000000000000005fc30bfa50609e5a7c9533fd782c896057ef387e451c02016e48639f854d4bc486e47653b125f7580b81c2095feed341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1eed0e550e052372d4789cb44aaa5019ab80061b6fe92dd1b31226df08e05c41eb47f087a9cea81d8e3b2abad01f5c000000000000000000000000000000000c7db890f28176e6b4fa3159f513c9cf80a7d29739b01ed05301dd41445b1d9fef270e7e486ecbd2cb499c13d63908e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055e01b48ac35cd63f36cff92ac9a0f9b5ca9116a7eb56e1c60b565f000fa923ec9dd340ed584f3a633515e7d49e05b80000000000000000000000000000000019c79922076b58807a26acf5a36b459fa381ce71a92cb74307cc7873159264c6f687378faf160ddf7db1aa92c3edab6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171022a2a19e1c9d1427fee6177b14fbb36d02749da0f4b889009c66995ac7304f1f68185368a312e3f7270bf7e89eee000000000000000000000000000000000a37bdb345e7d386f2f71331e78298061f82dd7a01257e294998efa12bff96e50fcfbf09fdce5bccb41a8d15de8219091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011bfee584bd06bd0745a76974b6fdc2d2fed39b45439390dbf15df98501230a6310863392c6818cfcab1ffd0bfa1cb850000000000000000000000000000000016ed25ece3ab54abae5c3213edc7965543eb47856e2432c2a1150da9bbaa907470a128170c758b7e3d75c0eeaba8edd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d947ab8e88df817e30e9d74559ea94ee0283cd0e818e97365d406f1b5348b83ab25cddc886800e098ab8536d3890740000000000000000000000000000000005a5002f7b4005ab1afbb178f879dceac3f5c32ff092ba8fbb732eaad0e4a60daae78b546a85e6e5dc20475330d0d3611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152e08fc98d15738b3c94fb8d6ee9a9d27ce4757cca0dad46b5af0ce6eea9bb72c8a5f087b5ea16a1fe91ac51b4efcf90000000000000000000000000000000008f67e30596530097a7bd32396468f01b13ca9d2e38379ff4002c03060e4c5e41687489e43cbbf31130d38a48a6496f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001685d4255b9263e56cefde5b9856a406409654425b29435f688564e8058218ab771bc2c3a8021fd5d8009b9d23128761000000000000000000000000000000000ada6ed76129810aa8b5782c8f2106df6dc378f702ea49b1e498c3e430f89defcaadd43093abc3afe4a6e2572e387be41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010bad2c7543e8ebc1b6c77c0dc32ad8158698c4ef2098446e8da819e4ce80249d2bfdb97f446039c26b81e763e01a8e400000000000000000000000000000000041ec882d3a7b99b7f183e67db1cebd25d5290548635e456ad08f2af64740cccfa75e562b7ea0279ca65e579bf8e4d441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122fc11abb12abb6198a28dc8302df1b66a4b3c35e8081dbf00ac1d0a53c5ff13bbad129392f8dac47e12378ee9557470000000000000000000000000000000019aa0606f91ee5d4cac1af57aec63de1c3b7f3537af791bc8779229552ddf9076fd83bea1833081f6d80eb07c5139b861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021b363d3731804651ed8267125763151d61ee080da5b824ee27a519511c7cd5ab4bbb19a5399b6d8b4b53f0c1e887f20000000000000000000000000000000004b4542c696d5f1a6fc4aaed3356cf06f9ddc94a5635dcbb6aa14bedea810ec1c3499a9283a25910dd1d190a722df8551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069b147d0515c46a81c98af0e612da19bccb6789df292e4ddffa64e58f21c78b7dc11b78043b052ef9a3986b9d50786d000000000000000000000000000000001248985ccb175c80d5327a80b2767f20859c79f269d9665cebb1971ec62dd3f264a3668a006b030c68b6b415df8201041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d294cf5233db65440689802646a485988568784a386acc8ad44678d4cf65f9c7fc924f0b49e71a531a8fe412aa829800000000000000000000000000000000115247320ce7db88ec141304daa513abf38ea07879f1956cd12fa2e061a02b6c23c3b205b920f7df57a21288c0ac8c4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002859426ae10f57f52cabfc45fa569a79a5c1d41db8be14f408f0b75fe20f79ec4ab9f7504b61cdaeebbbf24baf42bed0000000000000000000000000000000018a46ec9691bfa73c008e62043a33f5a20977c8c9981bf2c0c351979a53298b51e46346243227423865c2b2d5d76f88c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d0f4f4d415be96efe1a4d18ce23d9255c55eee28397db99b89cd6f54eaee0c0cd46f8e81605360347f6bd7bbf747970000000000000000000000000000000011bb8726fde9b35919b981cc97242ed83ddd1ec307d417408ab7aa8be47fee9ad44352d39bb5a48964e4edda8b187f181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005223cbd3622cf0cfe4bdcec522399ea39e1d39ff644ebb9bdee515522f612bee5d3206a12eb95bff1f1a370c50b7b2d00000000000000000000000000000000167e5624fc12abc28af6e4416c339a54b73339e96dbfd2ed1d8377cb273b5dc8c034f4801431759e485af4b1d9e1fcd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001511cf5cd570ed46a255269e8e8983142a0eb4cad944163135adc6c1a883c2f1092ee4fbb8f1213efcd0fc179abd6396000000000000000000000000000000001864300a37950e21686f7dcdc9b313a9dda5ae1886b800e2f9119b5a08616cbccca5c3e374ab08bf46161458b2ff765f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd30cd411122418dd8f058886e759dd595be44b0c6dec724b90fadd0940c47c81c7f11ddd97a4aa6f08a44f9b27bfb4000000000000000000000000000000000e0274d68b9e8f8aded68991271a6a2ca5ca725fbbe4ad42b79c08fd78cb518af381450be413064871354be3f3a29be01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021937d34975bb30958beb45eebd73a1c76a8c2bbc2f2277cd19505b6fe9b33056a815fec2216884aea29370b9b9952100000000000000000000000000000000071d697c09409344406c3f54ef5464e28a31ecde22f59b7a46e19e2599f0e57b04866bc7e482a681954799678955a1e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a202dcb1a878e73fce11557cae947ef4cabd761f0aae5c3a02939a2c64d2e2ccb1aa175c5cfae68ebdd27ce51236370000000000000000000000000000000009f7b6c9cc25f8382e6b6e2e7af60a67edc94169f5382a71eee63d47f8c215509bf9d6ccbd65aea71993a450f8598f271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d3e4c452f97fbb88456308255484d863c3a3dc73895201f2d045c9ce9ab45c28ca90ceff7426653d45cfd7187e3adc0000000000000000000000000000000009e55f85bac752899addb9614bc7264d1b86ae04b72ae2d29f4386849704e10dbad57505f04c9ab599713bf0aac83d901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001809d4703fae998db9f1f7d6c924d59f0220743c7cc7e9fb619641acbf7244391989332c930b2ec37da597c0f56dc2c0000000000000000000000000000000002b147c0afce911f6cdce7bfde143d2504542acfebd8171b6cfae5b7e2e03a8d0e5b954b7d51907d2127e0aa00f44d891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017208a5255be77869e6cabf4e3ba403dafa18ddd9674616158225d7b66600b29c3ffe62119998977532a3f20d2f269e90000000000000000000000000000000008757c8be33ccd5549ba3d173394772fb8922f5f9926613b00eee9e6f9479808a085e94817a3333e5004221dabf4934c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af011abffd18c87cb9812944675637d6e383938d8037c7cb74081c31f2b7f4483f26956ea499761765f38527b8aad880000000000000000000000000000000002cb3c8f78e993a7855d38955e227248c53b3505fd1c64e3dbfaa06900b0c6fa67e4e9d31ed929d457c4b1f5b3fe459e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005cbc5a7427f728466117b27932c675f2189f7707b9dce67c2211b3a01be0a732f08e72e3afe69337ce49e27cfa25fa70000000000000000000000000000000010459399f8a687bbe8eb0431e2b56cd7a8f09e514a74f83897d26724f39e653c510dd81fa68d63fed2d21dfa474dc1391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013529d7b13a056aafd0b87c9c0b6ce3060ab6282b63983dc60399ba1d1e1ab1021dcfb7e17f50e4fe69cc2634321de4e000000000000000000000000000000000f485dc475b6e3e308596ddf1b0020878adc2caa7f294fe07b39d4ec369817675f2cab8e2800b52264526e1f23ad70411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009107d0b03f7b51997a723e356ed424c97e32f00e3c06416df0b3051de3efc1e84f3e985063576bfa46265463c520d1a00000000000000000000000000000000017ebd4201600792a47dc8d998daef95e6ba1685214f2b4bf366f21c7022ee588385a41b774d842eb6e1176faf2222361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da2d6d1a7017f43215f310756978b9e7e28375ae0b2000775b1960fe9d6b5ab731dd8ce3fa43c776ccc1734014bdbca0000000000000000000000000000000002e5eb7ea8219fa78c522fd09035caac6b5a42325fd9e84d085068c5ba7ec7a29b2ef197ec428ea3c32fc052e4f3a1e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108370886fc81b9ddf2fe348d3bbc42181ec573a69ddbf93610d8ec20f9e82bd0f8b76e61421601e7db771e58a67a9f10000000000000000000000000000000007bdd99a952a7d93ee1aca9a22e77c0cb01bb70aa3dbae20b434fb3afa18f9560c40ce6a491725826bc4792f22a8b1711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076cb0ca763335e4c2dfb51bf837b96220d5f202138ff070ad6f9608a537c30466681645173596a480a131d4d130251e000000000000000000000000000000000ed26330292aa33499af23596f7a42ca50556f019e553d03439808fd62d4ca56c0cdde8db3cdbc2d56b27ab5b65986041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040eb317415d85aa30cb7b951e366e89e4d45fbf746aa85237f791269f88ea9487aa55da7c4296f15a74411bebd48cfa0000000000000000000000000000000011c15a139b03a8a0150f6233cc8eeaaba450d67b7d8ece71d7533278d8451ce4731405b48f43646b568c6a0448f17bb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8651cd97f69695eebea35f179da3bdf9a2424681f0170542280dee325511d7362be9f82e9dc1ecb4d41d7fe2a5e85f000000000000000000000000000000000ba5af9394a30fa61a9131a9e14bd717ef4e7e29d42b15bd198fe358a5bcf044dad874a14a3b9ef36c3e3a3023bebad91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd4a318b55f7eec8b0a92b9f0aacf078490b495aca0a20fb5269de26e0875473be1792288c205dda05b5423a2ce252100000000000000000000000000000000085b6e3136d2d67fadac25250c543d82c77c0e14411aa20623d979e3b01fe479fdb69aee82eb2f1e5eed06e051a202651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041afbdc3ed5e40a4cb5c680c90649eb0700aaf56dbe18182d135c8f6303b4b3268f0dd83b79cb49e4d2474d0c463980000000000000000000000000000000000c632f6e2020555f1ac1533348cdb5a2edaecdac7442184d77bdfe059fba174ab49f7d971859f228a95c7365fa60aa721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e0437bb084996a31c5c7ec5bf66f6e9e420e531c13541492f4782ee17c0e1d19955fafdaf6f048a78339211094fe07000000000000000000000000000000000fe96ec6e9b20766bc2b3ddc9cb4fc0e7ca0fc6a35aea941fd8dae6be696c6fd649d6c4d25bfb62defffda9c0bfdc8361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f9a9c8094da590d1afe9240f1e6c1d6db9db91da13b2cd2390a9ae85fb0a4b35a67dde3ef228e4fe832dea467132c700000000000000000000000000000000090b062266b500b995195b8595b0782ee2e495cc98b70ece63bd93e232e542e2c878db1b4503aa959605783385c5776d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003c00000cb342d7a2f8820d8eaae6679ce973fbd4335e5c84b6bcc1183781cc4cbd9b6915211e3d8f91f2d535c15d855000000000000000000000000000000000425d832f7745c71f63bafe808bc1eabf47d437f062e9c45d24f56c443d53da8f0aa5ebaf6cbf8cc3a30a2d5256926c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7c463a994e5e38684a0cd2e18804e1139389bb1c97f40ebca64921d5b4563f01607ff8b8db72fc0bea52da9d97037e000000000000000000000000000000000ebe549961d8a97189af51a2f35ddb524c9a796338b1815f1df847a71766ef61ad50090416ad6754f53e5f129c65ad991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f6ab3ec387545505b63cf259fdaa5d0349af9f71aafd28f8028c30e3f3cee48fae58a429e4b55e37cda1994235547e000000000000000000000000000000000b7147de1e1b369170739edae46db196d119d44b095b94ea6558b0928fd1e5cf7d002d95b8dafde4219916389c0e860c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001610bf411998c812dae4ce41755f6fa7ed56adba9a88705eda3b6160203e1c59a291cd94814b327018a3b15637f38a21000000000000000000000000000000000299da986caa5f40e8057602322c7fe18ecb9cf4cbf5fa647e9f71939998e7124e35b8474ca809ed5abf8d7bdbd03caf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017989533f0795c5feec7a4d83b335e9c9b83631c7f7945d9fb4f0e7236c6d1d2a369ef2d1bd07e28a69d7ed50dd98234000000000000000000000000000000000cbfab2fd6da7897eaf46653634ea240296832d58cf9a44cc57731aed90cea4837acac8c647dba55a22946ca290dd6c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc8260c9a345bca2b604aad43053f1056f2092a1f6a3e36b64df9a0b2b6ba955419368a8b17ce1ec4e97034b87ad99d0000000000000000000000000000000011c7a849757c6dea736d2274d217fafb010b81f06b424f0012dd788913a73abdc052a74069a7a42865f9db84913774501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1ccb3f1db307856dd21e25a040053187a503118be78530ac0e9fbc4eefda70fd34b824b40c50161f920246ddcd6c7c000000000000000000000000000000000ec433884857a788428b13d087fb41edb292135aee62b9b2d5cb37d15dc9b404aa0cedd4027ce11b7f1e395aa89c7b331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cec8c6587e0c711d3001e7addf6fe7bfe855d421971d3bb5b3896c625fc4ab605801338e0c18bf9a1d3fc7495bbad6000000000000000000000000000000000cbff0998681c7f56512c848065c308e578d33ee48484c8e4ff3eadd2a80847f22047162e243d63af9dd2068a699b2c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d42629c2050ef74bcdb8c02c750217e869a9187e9ad8d1936a3c3ceb6c6546694be13ec615fc38d275fc5ebf0ebbcd0000000000000000000000000000000007a96de8dc0d84835e49ff97288fcb43c312ade8bd068e3eeb9f400658cf683a3a08afe6bf50ad7aadb75da248b2e8e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ae72f133107f1c136eda2e15c99f25234b135a3e875c80d414afce2b184feb2a7d83d3cc612c87d174cb8c45e22831000000000000000000000000000000000b50c2131e1f1141bb2ee355ef49487e2d8343ea51df91b3a2efaf9f4449e7a8c4b420cc10330a14cadc570cffce1ae01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010bb5aa3a38b214b4e66a581c7dcd78f223f0a76c075c5bf143b01986e855a57d81e00cd3a7db7585c271f61bc6791b1000000000000000000000000000000000cc4b7f98ef84d87cf5af2272da65fd477dc90b65dcad365c7c159f2f03f345addaab6239e470f9b0c289929118643ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000680364936095da7ced38847860a06daf53d13e3e69bb4a3eda004a166db4d39a150fdeaf7aac055e0850ba20ece1ba30000000000000000000000000000000012cc988c3bdbb8795822268b5d08cef78917b98cbf268585c53f1d4521bced36c37457d7e6d7c848a226227104f269e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ff8a4f6b20d623fa9e2917ff681de301b2d37dd48e32702481b1a3ed0224040ddf72f62e8dd679fea045f480dc0ffd00000000000000000000000000000000196c78bdf3d77587a85ba4e749e3d7eb245abefe6fc099d328c67614da0ff53c1c29d60bd54294fbc803ebe1c25561d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016692b717e655b0f66e5558121c910fbcaa25b1a0199f98ce83bbb96da6ed5d3b94638714fba313130abdc8a4545f0820000000000000000000000000000000019a56dae4705a8da9b672bd35bc8beee1852529c373de4e550fb238ad1999b1dedb5f3932401e6b67d0a94d8a00653331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000192d1938da60d5046eab4a3b26ae1cb8ed807aaaf8bf43d6ac127e67aade117cb6fd0b5c82241581ad8cded5401363100000000000000000000000000000000040346a5b1f695f5b4de133882b9de892ff6a7da483267db7671402188dca3102eaeee7d828f5fb4289608b36d49b8df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c3e30718a3873afc4f058170d371b03b79d3a847159127f07a27a1fe09549404fcc8a8b2c60f7ebe7409e7f2a6d1830000000000000000000000000000000016c1bd7ebe4bc3545bcd6657a72d674a1c7ec041a2172011304ff7655e3545b5d031eac06254c5f8d952629302b690851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010da547a84940cdd7c85a4ce58ec0274831fcf4ec307e99759956949e8384538a83d393e552d989953f22dcc9adb27740000000000000000000000000000000001136d2dd68f13e28d586a3d47ad0446b1df3e9eb1bc962122f34f050da6a0918062e59e61d12e4008d0f0d63d1a5ab51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008dba2206f76a34ffa8e9e3a9de46a226e8c9eee935cac3d9fcf0f72c86dd7fe173049adc7d38724710e0a25907d23d8000000000000000000000000000000000d21be8851a843f54e1b2aa9f8387d191c29a54d6e86baf76c5703c61a2687e2f200e33c48d71a2912f3f4ca61fd08e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002589c8f3fc1ee8f7f63ecec8f46f43804a5f03d900e805040fccfd9f3807a616afa2da6912beb16d5c19f2a7c27cbb800000000000000000000000000000000039c283ba16a47bdff4fe47fcc97ee27f7d60a6e5bbdc9290a7a8c1f3a38c6639e93e9d1e24c038cd49022740a5d9a561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075cda913ae121a30fb8182f0864933663bc49c5ed960468437864b020ae0bec0a796f4361d94f24326191514e4150d2000000000000000000000000000000001339d7cb860aecb489030049e116bcfb2a0fe519e74259001010c4e6a87aa9468701d7f321295c024275766814bfe95f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001102dee9f6dadacfcfd95be363c31cbc15770d5231d6d56fa3fe44d7b66d2f55bdb0e76c3c391dff12559fc8c15d6be0000000000000000000000000000000010118f80ed1e826f81ea4f127777a330c37b3f3cf00895a3d1fddd93f6c384c5f94f7caea6f2dcf0c350b960c796060d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001874bcd13f3c4d0309579d65c63900df2a7b1670da2a994435c5ae533538350bcda11f120aad6a22c2dccca1b1061c8f000000000000000000000000000000000c1a893b0fdc4ace6215a252d099ba97a25b94a9bd3f55a0701bcd3d452b4902a0debca580d3b3035260b656c1536cc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc3b8e174ca1787380088ab061f4f31b78c135b402c2ee40a22a2eeb3b9259dc5df933db7fd810182e8c9ef564deecf0000000000000000000000000000000003e232c28195296c6e35d20671488a55a2f3d80da643e80dd9c6bc7581a8955b14752d2bfb14b1db2400f79c3980fe6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a65fa6490c6e06087581a1098d592e871aa199d0949cd6475ea47e22440de37edfaf0a8b3001aba4e40e1ec5e73ebb100000000000000000000000000000000176239dee037f5eb902c8ceb3e249d38baecbfcfa847a96135da14ed70dd57eafa813ae6d1e44db47e89456a2c9e366a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ccd35e9fae2c17ef5700a48a5f69a25e255604dce2f0a522b9b70592835fef4bb8eeb07b987bd5f5a757052a31eb5f0000000000000000000000000000000010f8f19613606ae513c2bfc94e8a4a995f5a5d68361d98a96283ca022a8ebde510948abb133a0645005cb188b41e657c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000776caebd22ae57add9970dc04488159ef860cb0d056ac2492b482ef49d6624c48b9addf90275815fc146f60e5e5e833000000000000000000000000000000000157cc6f6238d83bcb04b030ee0a6e47f64f8501cf84bd0f8b1d8550629c4e5fdfe32b6edc2f6ea4cd78117881ccb63a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a4d7d6283dd4d616d764c5c422830bf1ce59a6ddbb9830014fafe94c1243525623ffdac46cdd57377a5c38c586fabd0000000000000000000000000000000007da883c63d4edaab0e0678ff8d692978b41bfe0a1376a011135270d3e9a0778d88c4265a3c3b7a6a5da45b4527cc7871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eebd68534f5ae97d9361bc9a0b47f7a1cf586f838cd500e6cfffef2a6cd184188651054c0b95404f4161ef779150bdb0000000000000000000000000000000001e2b20e96d3c723e5e099b676081b0308d1f8291e7964fb453c4fe238b33bfcef01e07a1cf4868a37d67ab5b713f1b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001121891c2fd0eac95afd89a470e4a1f019d7ccd0f6908b41e024a9ac80d6c4a34a2d3fb4675399cf8f5a8cc6cae090c40000000000000000000000000000000011c956d02b47bbe2691506cdf82b3d1cf459d1111739ee37ee8aeb5e2bf8406ac0e8f231a518e33a414d4e65ed23130a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ec78804581697c8751930147f37ecec0b08551b956653e8858447c48e10da3eb4fd53615aa5e0bcff5d6073d46a0d500000000000000000000000000000000038b4a3ae508a3d5a076bde92899201b529acae5a3ca6ae275277b0141c3edb6a29f9858d9dc7f8375759ed0d2a2854f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001144b8cfc620339c8494d98448eb21e8bebe865ab935100c9f5d3ea5e90a196a8e877c9b63ed9bbe125f2d252e58fd5d0000000000000000000000000000000017b3f3e93615c26c3bc73db6d3af5b4ef5e3fc14dc833c47bebb82dc6afcae6fcdec1104fb02c320ae699afe8787339c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001872be798aa2001c23d23e8c7a64feb8107b2043573dae31e123d0a7f938a388c318ccdcc2af945a19f49499f1d59fcb0000000000000000000000000000000000d3d42d2d0bfffae378ce72e9f0082157510f9146c033213c30453f69f628ab05e558f5b38346bb82ad5aa52134f5ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb256230e85213592f666da9811e5fa8f4303aee5d2e6257eea078953b19afc857fed4f58296161bdb4321a8412a9460000000000000000000000000000000017d14f7a193f85c47dd9c54b8f8465580abca29e3d3194b6375cd20d065dad91a44617021896ed23d3f4e46658eade2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000068edf905ed7d56930bb7fec40f2a5a0c11b18aaf6f7a6b4c76afb76ab3ac0505ef2e54309e2d6ecb53af9917338b0d000000000000000000000000000000000093f6e1c94d305f2a6166722aa08161dc54ba9d08dad068287e679c67716466daf90160b287d6eb900d4e3a69b856cfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ae30f44c51c9f72d93eaa5cb57838e56d6140f39677aff2e42c3d1f7cd81de3f6f8f0633622d562937c0965b206ef3000000000000000000000000000000001772a3ea74093709de27c109469316fe722a93907f52982507c196c4abd62ac96eebcd9ae368aa6f4e27c82459e228a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a1167415372ae14ee91998fabe33cb0f5a45dcc50213b62efa471bb2c9f575fb44e452bcf2c7fe47f8c64955f5da1a000000000000000000000000000000000983537af461d56b68565dbb1aebb9aa4e8202f999f3c2759e806f3e8704756fcafe83626544bdd4ea0f8d87eadd4b211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029eb274de08f231ab4bcf19e35fda133d963dec581c2a35ae77645641b69a72ff79f5d9b5d731a91b6c67e091c0686a0000000000000000000000000000000015837b803439fe450929ed595c8ea0511f49910837da32f2a777fbde95c36c04a35a574faeace8ac44115c63c946de171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014aebc2b7cbb72f6bc5f1472206f635954547c2626c2e3d5eb9da78a281b4124a694b649607f6a1cf4f431c1f5d686a50000000000000000000000000000000009f2e99512d7f755fcfbdf46820fc99c036bd31022ae60766a96204dc98d21f09d81d27ad6ca37a436fca90d1f8ab2e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c93101d9b29e7baa6ea300a6c7985fc71544949374e48378ef2f2f62415e8661f914f953e44658cdde80c225349012e0000000000000000000000000000000009cdaa91587019d24b9353b9bbf5de859117f57ab2265b24d516597adbfd8c0ffcd8a4b4110fedbc602aa160a25f89fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e6d2531bc535d944cd1bd9bde036e75d668cdaa846ec2068ea532bf530a61fe76c97776b6e41d48e4afae7a73ccbaa0000000000000000000000000000000013396ab6e8dff1f84a0973e8ca73f9ebc98180377472fe374dfd1753d790431f4f441d777fb9a808dd9f897cbda4002a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000661bc08d0b55c05197d30d974a6127ac610675787cdd8f705e2bcd32a0515743f4b301a45bfaaaf2d6e0ab99bffa7fa000000000000000000000000000000000c3f6d5d368fea0d6e750d02babcee99a8f9073e42754498647fc57b863bd1391a58f19bea7994fd62201aa3f9e483501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fcfc928bb356780ead8118d9b19d1d1bc35e88efb267c58fbffac856c163d19a2dea66b9c9ca5c6fa2d65a590f83db4000000000000000000000000000000000bdf79d8c23c0a6618506345cdc1f6de3e442747552529aad8cab90b8f4859e15678456dc7a2dc4759819bf09c155e351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168249730a9f2bec5166f2ca4314b8395dedece77949c77e13d8bedf039a54fcd3ca37610aa1c01656b7799dd0077d26000000000000000000000000000000000a1c74dd643fdfff2116356875fe75fb115102cbc20453f6bbd0f3f65d6793fd1e0dcaa37d8985ff3dff12cc8d4b88f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193d905514b5f698feef6de53f66a7d67949cc9ab9451f0c5bf781fbcbbf426f520e50b550c5c01c8301a24b9780c8bb000000000000000000000000000000000e18de08e995622e9d12a5eed19436e761efbb53657ed960d345c391744d75d672e9bd014fab26f344c04cbbe021d83b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a063d2f15ed07d541208752fb7dfdf89c27fa34f54c61e3c6f7f0702885f7687c255125e30077920aab70ecb70c8f580000000000000000000000000000000012a464dbc759a696e966a658e841c98e29d8c5472d78d0ee174b29ae56459d16ffd4e797516550a3fe36c629b3c84d331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000718bba2dbf470d31098a060654c267614b2eab220d38290725208c3b9a348f083c20b4af4d8b5adab01a904a72e25e60000000000000000000000000000000002156cab69d4a180697c45d25434191f8c3146496c66333c4fc06296fe9da6a7cf91b2ee06e7253b9295b5de160fc4151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c73c3d1943f0331128afb239ee83e10ce1a5b4a57d1b0370447e309e5cd5f23d6f37a429890af13b030e654d59c8c3b0000000000000000000000000000000012402518f71a204c00697b1209a9dbf16510e71a3acf791f49c2062589ee382aeea0d57b9d03888dc9a23f3e923e36651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159d5e36003ad166546e8870425b163c007a2137d753819d14372557e1973a3aeff979d36028b978ec0ee6769f79997f00000000000000000000000000000000174b5a0a47ec139baf76b9c344f84d8fb14961fd6b966c1bc4d5874801b202792a1732b467e9e61e936a4965154484731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040c0f68d91e7209ff7759da3b126bc71a8186b471447df1bba36b4968fa11c7562a46d8ad8af69d22e7ea691161b7a5000000000000000000000000000000000518107ebe282e9103fb5c6efc6df800402d4fa23c5abd61343dfb8bbb108b5d670f735dfeb4a85c44db92f98a3e7fae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3b99bad71aba858228fc9b9882dd8ca3d6721b0c735e354eeb9f4ed7b4a67312bdbffb19bc502784d54275ffe027980000000000000000000000000000000014be2752a9b0c54d1d2a6eaa4f58af8e8c4efe09455b42ff8e3d289205574b3995f9b67def3b3edd95678c05f93238c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109839bd46879a76879206cd65c7c514efca31778546146a23e92e42d157d78e19a35f31a5dad15401fca5f7aacc3e5b0000000000000000000000000000000007ce572222899d6ff5fb6d69f96d7a403066df9de6117a990050f039a51ffea4bbd52685ee82a55eaf55ad27b6bc68781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001828cc3b4d9a14863e6d27504296d820fd7f87fd77080c642b48c0d31ac0619df9f906a3f3b4011aa8123e3c0bf236c900000000000000000000000000000000059a7c60b5ab2a99ccec81083d5ffaefd5ee39649e4397041310ce97e59349ed20a7269ffea752603cd5d406d9e166cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e8224012766bb1cc64340a0c06a4ddbf084a5b592344a5c4c24dea4733167f67774b750efba6349fa5926b488182870000000000000000000000000000000015efc8c22a7709203fa52b82271bb6f6724a80bc2c1d174fccd0051ff217e1931dda18e04b88345962b19310236366491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a909b9d9e94890a5d92b5a74ce184004b83ea744d10f7c1833b40868467b200adecfd61296fd0e6e5617cc242cd6eb30000000000000000000000000000000019049064f046fe6c11c60fdb006f68da2d0984488caddd6b8af985e8af603b238a64d4c32c90bf288854c5f4d74fc45d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000973215015991b49a56f980ea5f5ca7cf2eb9a3417b2a7dd86035677bcb75095bcd623209cd69e816b296cefb97adc5e0000000000000000000000000000000009f6d9263bbb4f3139a354d640518b7524db7dda17948460972d289e310639de4e3886cb678ee97744f603e38e6e13771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c97b6ca92fbd4b79f71e3c11754c5d4307e56f90ecb4a778827b3a25ecd781fd2b34b7308b42472fb7d171845cda19000000000000000000000000000000001662016571cbc04eef9cd2987e07fbada59a06e174620b725af4cfa81407bfde7903a020c9bdcff71aca530e68a665471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002fee51754395bfd525ca9d25a3ed54bca8c4000fc505d0663d4a25d3d15778f7fade55d6fd4394e03676016cda7aabd0000000000000000000000000000000010273cb0670ab6b91b7360c072d327d2b07810b779c4cb08fa92426d67770729f15cdf2f5ce138a0f48bfd05d92751c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114b260c1c3dad5541a69d3be25a253ebf6a5cb093fc9ba5f7d70960ac8b98a2f630394e9c6e00d6867fb0d76f357a2b000000000000000000000000000000000bab53779bd7cb6eee6b722db6455a551183ad607fdeadc500f50dbac2022eef90c3aff3719ab27086e16cba5a8eaef11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000def3f2b1e5a983c99aad7e94c1fb9616ce2ddb1f4e2d7353cbd29c44f1ca19f064f899c53e06e01bcf9031ddbe1d586000000000000000000000000000000000c50dfccd743154e4a3c572bad3d24bbf589c0c9afe03786d60cb025f3a55ace2963e239c4a486306f4306f86cc6c3a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f0eff1524799f10be7e6d0ed6c7e192221314dec37c032891c8b49b0138404ee0f61b90cf7e38bdf7e00997d6c660a000000000000000000000000000000000b215a899022b8485ccf4cd519c493ea2c4e97561dc05f4bb2a228f315cd195e5c2489f7c3e719106f034f290b036f1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001802305d8910d466ed46645a86dc214083b17965c802ec2e73db7ef6c970b97c56c244c6db5aa566761157ef97e0cfec0000000000000000000000000000000017c643a5086265e2ff13bb8ae22a5cb29427694e4a05cbccb51b3687c4a8a6943875aee3a952f94d3d8577590a8c4a971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074ca2bd7660bda1ae9cd02f872aedf0067b172ffcf16b951e92d3c3445b56f8e5c6dc8c671de2bc02bd5b57155d82c000000000000000000000000000000000066c67ab1b08b2093fc47eb05424b1c4abd5329d980f26dc58153abb42b535dcc8138b9c57640ec0b19716463c1c04d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf9974483740905d5ac46cfa7f86ea2871d0c2c4f2d6db4f7d52de8a595a8e8f2483294cdb2ed48fbbe2ee995434bd10000000000000000000000000000000015452c17a3df3952c3debd55b948561973a9cc40089c32a2a05bf279b69cc498fac7b9acce331367072b24fd3c9c2b941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011eb7d2290c1e206ce8892ec7a2bb4046c74cd1b43d6a819e35ddb1e071800e16f258a202159b6d6ae2ea979f970bfc100000000000000000000000000000000053a83b265f58432e949d8fba46b8925de46b8a4729383ab915dedde6a151bf93291075589c046984f25f757124947dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e7fe57dd13da716bf208b075a03e0d1bbb77208a603cb5c75755f7bfeb1ad2b1a27cd7ef633d5c98969bac9aae0dcf00000000000000000000000000000000132202229aea34974d59683c677bfacc883e4756ca95bdc948e8d89e3d4798af82d3e9b1cba4c70bad8942abe0fc92ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c60c17e9595293c9da4d3aab05d157067993211a767f404142497e8dc1fd650bb8fc91f9ea8025714549dee63e932bb0000000000000000000000000000000007a25ec2e5064ae7c7e6211a75ca70b2e65b91db502bdce81e97bf9deac2e851e2c8876055f10453e640c0367d9cc3aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023b74339080c7c0d9b06cd6a30da6695f93bcbbe4512c447a4ab0205a0ec2694b2018597422a38a0f0be907a451a1320000000000000000000000000000000001d88d42ce585009fba6f8682b8b9395c94240450e00965a6b8bb0566059330df8546c64d25f3f3ddd1e82c57331cece1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001808d6bf8917b4e8c03adccc5550c16adc99a5895ee1f63069b20365d2819a15d26a7b1acd173c432a18a09ccb924a2d000000000000000000000000000000000654897a2dbbf07db16089349490456cb4f7712e43cdf92db0881465754470f0ff3e41ebc263d285dc743d369ebecfc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168e8474b562b341280f09e4ef3f611f83b33d983d8d210a8bfe31b5194b3d80e3fd2ddc8f3643650b6c9b31d696fe0b000000000000000000000000000000000560ff4d614742f59cedb4c876a88a333b7c4cab8235cbdbdd2a55c2841405369da761b9306e1a09c4a13aa85aa8f5141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000369eec48927a691fa6cf8424cb1a2a553835b3bfe4b0af0635a1686c3b9bb0ef6697e423f3a4bfdfa5d998cf3b91a220000000000000000000000000000000001dfb0cde1496d34083cb91d49de1d26bb7c4531eb5d373e50761333b0c18bc2e654fa4af7132e707c4ff278b097efc81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005060931ad227800a54e2c64201b32790aa09c7257a9ec8a5fc356f5b3d0cc8dbe7bb6b9d37460c57dbe15e6c1ba4c7b00000000000000000000000000000000181fe5713589a7576f26c8c63a346c1d64ac37227151a52f056489574e45db04b1fc2bc208882892e7df83126a7ebb241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c84ca06546be459597444bc7d5fdf545738bff29d3d4da98412fb1c663526b341736e69d6a80b4f93930fededa446ad00000000000000000000000000000000187eb7106ece8375ffb080975e85088d00a23fd3a8e6c8003f240d6f63bd636af177b5a235a1ec7b7c57332d5bbcc86d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000255347c160ff93b2466fb5f8259e9b232f83f1761e16dcd2f9558587bf702e8f787a469e6c7b78c57e9b49abbb2ebd0000000000000000000000000000000010e29a4b5601ffc6eb3ea0599d8760a49d4b1bbd689f4971ad6b669126d6e36c836513808cb988669134ef041b5b89e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000317fb47b5fb06686e0b5537e5e2616c39fe1ca926f07bec3e9cc8ac8336bfd0a3b45cee20183e65f67c6f0cee5c69b600000000000000000000000000000000120f16e6f93bbf3e32901602f760ca86493758299adce458ad7969b9f8de63f512f16e7eb6b19e4ddbd140611978d87e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001be3e496dd1f3c33c3e3aa3a3696c57b8e4b3835510d8e5b25ad1cd7dc578d2f85c3d85a4cb002b23b97d9f3e491f80000000000000000000000000000000000c43fce05be4bc1e67a2bc71269272d714d51428b3c515eb592f51f53a05ed89842d2c605e8bfccbf7677d084a823bd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012363927bf7bae16993a67ff65ac896a5a9b40ff12913611dd6520eb95cf7aa97636c68ba913d47866a461464cf56fa300000000000000000000000000000000021cac39b2f94cfaa083fec833dd1a158bae451ff3d5195050c663c93f8275557c09890ebf937a616495903bf66979ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0f9ba1cb6002eb3c74b0c54674936463df314f7d14252b54d41331487b155947b6d1454d1fcaee28408af008d7d1cb00000000000000000000000000000000186dc743979b259ef13e906348c808b36d5c6f7ce5a59ba4358b0c2b55ef41e15a9bd61a0f60a410534ed0ed9cd839e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c4772355d938c6db5d5bdfa7da2ea77e3f7a2d16b00d443c6715914b55429ee93ccb0cfe348b1a828ac26fa16e491800000000000000000000000000000000130a3c7b7b9bbbbd7accf619b79d70a7527ea86384d722873960c09624a8a0a835976be87e5435316fac01a53d48726a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000164903d578c71b740294ac699e7fd532d3f68f394df7f3247f3efb0fbdb4730f768abfbe98f76b4e6cfd38c010cbb34000000000000000000000000000000000f39fb51098e879d5d80143743fddaf795f087c1e894f51a81eaac9485ce83776a64c8e006950ce1d1d6122efcac55191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a7510183a533ab5261f4315140b5ce33211d0767629e541f6c54235b308f841196dce0c3aa763ec800070e1d01240d000000000000000000000000000000001381e7d726e6a537509bf5d0bf42ea4a0b02214be7c601d35263df182a56354abea3fe2cf66537ee287cad276e6e2ccf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ae0089b787a89f5af279cd09226822ca647e8b2f3eaa5cae8afa661359f329b64803c80f085847513f4a2ee9d757500000000000000000000000000000000004bd062d20f3c8923386752e4eaf25e04cd663e159a936bd13f557348b7aec2bcfdea8e461228894f781760aa5b32eb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f60f4c9ec91bf8840504de305cfb50e51d8f04e08427e09ea20c90e76c44c72b7ad5fc493313fe5d0768ff8206f1c39000000000000000000000000000000000446375b29af37f6f85789e7aaddc65abfa20e6a3718344a1cc14bc3b403050b6615146ce404deecf1462b095f5e53661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d031768868ca6b46fc6e3ea13c8227e5ff8e8e17d5e75b2f1ea01733ba5c87a58f09f3f634041f03043b5ef9c9e849e000000000000000000000000000000001459dd257684155f65fc7eccb8494a4490dc4f2fcc6a9927a893601514762d41ef7e253045ce5644a849ed7671b588621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d231605846bc1d8905b2f6b9fcd4344de4d8f95f548d0bdc7b4e77e15470b0a39e5c54f58ef41b436c81e37046df9490000000000000000000000000000000015474dbdc6e3f625c0afef5809eeedcdcfd62eb526d323cc7e479667dfc24d96452734216cdc2e215bec614e3baba7511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f2bd452a132690991d6abe4b8f89e46929543e2f0a68916958a4a3203af8c4e4860052e657f7b81c10d19a94d00264000000000000000000000000000000001326d72dab35b604c513451cfe4087748e8861ef7c47aad96000657506a76f14fb5013b3aae1b713fbf4d92fe28b1d821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b17bedcfb1d6eb09f516245c42ae9b77d1b3ae8949f0f2a1195373dc719e1974bfc63b8592a8416e2ad5e6cfcbd9ae000000000000000000000000000000000d57b6cf2becd766075080e5b589f15110d1cd022748e0c20cb6cd9619dbc6d34d61bacaa3e2c52c1aab204673cfa0481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130908707aababa96f8a93dca6da8372e3609bd9ce960d66a40ae5ec76c7f32fd11d50638207ebaf7f135dfbc3e372dd0000000000000000000000000000000012719dd5a441bfb75f04c3f93fe8ffe60a5818304c15b714376386c9fe8a832fc939ef7f1abca620b0b0659f9acceeae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001651ecc0dbd2f856cb207d03c031c1ed99ba253346d66c9a39719443de409b1d4558ce945b79820b0e0e519603b6f3950000000000000000000000000000000003e930d3f2da36f3975da2a56a9ca9966a66a540a5cd80c4120d04abfd688c4bfe1b582f3530401fd22bda7a2c6fb55f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f14664519a91756a3ed32f14f434775ff5cceb59c622ab6173da3935a06965fef3e38671e6c67f2a7a520a8f2126ba000000000000000000000000000000000611e0970e39ca6464e5ab4cb25b2ec3839af444e5c8adc225bed2f81104455501588280e4ce92bfaa90930829e265db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022b0d04ab735baaa42e5671ef8722fe290669af6183621632a7fc17f7d94fac578352b6b6c4ba5d3567b53dfc1529f5000000000000000000000000000000001083a90c363cd99fc4821b34d97438cd90cd5b77241cbf86e2f32c6454597387b7d92b27fe8a6608e6d098cd458e145e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ec10bc5c67adf872973d5bb076a7ed574f7aa082a5699607f27021c892010c2bec0cb47955f03cfcc7d8b68657d2aa000000000000000000000000000000001113b04f45a12741088b500b59b25a0d302fadab1fd83f3b8bbf09f20099d2e8ce013c760c1427300a73def35fa5dd4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008fa23bea1e8b5bb918188e249fadc6c51ccd7a839b799a8d0dce769dc91b8261eef17a50dc28734d04acfe7e4fff201000000000000000000000000000000000297055b49e217f6dc28c16b7e399808c71fae0807f7ce8f33e2edd72745815b5905f14acdd80d341b8f880f1d27e0a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189164cfc926d9118dd8c887927ba751ad1a60a1d8369f9830a1c43bd0258976a7456f89e77f3b9994942077508f165e0000000000000000000000000000000015f1873213c86c2b93e75afed9816996a4120dde402df086c4beecf699692c3c3a65fb977b5762dac545a832237aabad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034da32e29a99479a085e0100d71b0a3f0bf6347d5cca232a467582fc3cccd3bee64be61f6a35aa9501c585ad2b5cbf6000000000000000000000000000000001701bca8988c1bb17fb44c67ae7064e16840add6e92d0ab6cf249b8b9f5d2d1adea5ab1dd83c0befb2974f39c0b42e911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8f9b587ed9f7d1eefe6ffef0b697aba2afac186e3541d76f0cfd0da7984c5babcfaf3a73c477de59fb2c1f5a76aae4000000000000000000000000000000000fc16b37a08684e103508912aafce2a4dd11ec575e032f97dd26c96813affa2966c788006e976458189fabce39816ca21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032f07f0696b3016995cafb0763b43754d51d647cd4bddf53d4becc54a90c29dcb0a9bc7124cc9b404b58f2e7501eccb0000000000000000000000000000000001f8c06e6bb72af57ae018ddd657e862865a6a0fc03082f969069a31f65f6bae406a503dd5164cd1e925a06a8e000cfa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b9acfa7b11ec10c5716889ebec08d10a7dceb10c857fdc13b37f4f8f78b407947438d09baba3e0939497186205910c0000000000000000000000000000000009ef4dc8c0fca6d06f3ac0f93d991708998ae653a85589b193d3e15c8b65a5e3f1f9576179f561445e4ba5e9fdac89ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000162e572c3e7be9c6bea636a2de29758545e2af06ffd99ad959537f2f32c7017c341b9c6aa70df6cff54acfd2f8d5dee30000000000000000000000000000000016650814e7aaff21659e1725546da208bfa14ee095de78e345cb25ed781000c5da1d4151d1091d4d00efa1e17d6b00f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dcdd7e0779d0f46f7e4da9a6cd0c409813884d5d7e36e4a1b3df69f3708b4e21310d3d4ca445df1ac9e5c58cac101f70000000000000000000000000000000011adf274598fb43c1b1c73e3e262707d5dffe30fe8495b82ee606f22945e809722ea158b1568e3ea3734ca0d8333a2471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000192f37e80b58cb2bb33f05f18754dd299c7db8ac5af87d471a0ef9f6d10221bf1d0bfd21ba60db8cc8072c4ae0f84c70000000000000000000000000000000001898fbc5940ec600184601d65d665655040093ce45b437166d2e49b96905885becc7b70d9ee237c5791c9d1f8d270ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005673cfbadd283f76ae73d4bc3b72b037b37023a9f257e33190844cea8b3082ffd9c1bb74d61aa9a7b36338158753c84000000000000000000000000000000001826845da04a262ae2d8f08bdb97b80d2d0f8c1cd1e791c20771324cb44cb587c304dc48a366c5fc24ef53cecf961c951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e846a549269ec3287daf7efb6ea3548463d91c28e7468998935f27787052d0ddb69359c1c52f685a1553befd0ec6f99000000000000000000000000000000001736877df21b01a9e8d32756f180520a8c4804eb608a5b0ac999d23526b5a9f89bb112fac090ff1b76137971ada21f0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052ab0bcd8cb9c3b83585c0b0c428ab2b6b5ae2e64fbfa120edeff4430fbee752225f44364ff5706505fc66f3514de1d000000000000000000000000000000000ff9d7205da09db792e794a8958f6ce7ca43bfae14fbce1141a0a2b38a0ee4616bcb89ce795c5afb4bef81f2b843f3071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000135c1455a407297e8d3600e1dd0021b64c3dcb6c1a3895aa88fc1bac47e5e6ca26bb023727dec710395e38f3b5f832a8000000000000000000000000000000000e1562e13d17eae9178cd3c4954df8dda5919b05d03d74cf9586391c6a8d553a21981ce69110d70aff695915d465832c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127d87ea0d6e4c8484ef810fec45c0179deab9d4793546b78ceeffca20ca533395978cc175a9c9a7c69804f8dec3a3c3000000000000000000000000000000000b01393df5aa07269af9a43029a672e2e6029efdda750112e93a832c6f31c7aa0aee3fc198d7af98887c2f80cd388afe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aede57e01caf31caaa407d7d0262abff236fe6f2d1731fc5db6fdab86c40561c2e77c225d79f98bb1acef7df8876f68000000000000000000000000000000000948ccb2ab131bfdc95eb1cc57bfe25929d48ab45a9bb8f895a83ea96078d0fbf7ec35b2a2909bb404bb2568eb3eac1a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000325a3bf42bee14a691a31dae0d5fa0f656e3175d255b4c1124e8e3d8e78eb0464e142337a8cf5134f2a45266b559a460000000000000000000000000000000016cbf32077d37cd39818ba035ed67f4957ab5205f892b1a5f8000fc38f25df6165254b9437f40a7e254b2debb50bd77d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123f7c98cf9bc8aa622c66a6f5b52c8a0d62b7d2618a6cc0b7b0560d7d18e2ae3b776b45389a12319561dc10952456df0000000000000000000000000000000019c318afd7dd391ef8e99ca2c27bffba6edb540ad636868f17ed6bedb90bcac71c717f86b79e3d2e4023dffc5f824f661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000878486a7e72aa69cc375a2f4dd7214472f95ba0b4492d22672fb98b87ceb532412acc51fd0ad78707a91f4669bad42400000000000000000000000000000000019fd50cb5efe933673f368bb6bdc57dee3162724cbb304fd75a6d93853fef0d19383def7ce2f3e24a1e2c33efd702d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000909e0bc2dd6236931960bc3701e82404c72d005b1ea0eb329e9a92006bf3c8ed60b750cea2cfb0a50d1d6dbc038fecc0000000000000000000000000000000014908067978b4b5122a021119d699f43ada6250ce270bc9ee4dec0ae900fc1a69de95205fb1792492d981dadd58b39b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4044d5f4f427abf0c3f08faa4d080151fefaaa3bda670dcca75683723f9e379a3937b92f465b986d50a2639da1e6ce00000000000000000000000000000000051a6001c813f658b1e39250c16e253e1824ece5b62830e0a3f19e17bf0d6558531e568e269e6927460435335e6c07db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001118428e0be902b21f4b5504a1e927a6aad58114d0f96e894ed1048c40e6558793cc2f7af0bc4ea59d75e54ca089490f000000000000000000000000000000000000d7439ba0a4676ab10fad19381ef132169d02c992d94101ef3d990c8a8bb5546ae3e992f86a1d9e301315a970462b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e32612d21102f90217e832fb7a00f1d9e1d4080192893a14414158c7ba00df047fc3c2df8c0b7bc4a5d757fa0c530200000000000000000000000000000000145fad1d7fc6f1b6088e534a61814c0b1d49bdd797cf2f7cfe62da954b91aff5ac2f645ac54e02705225ec398fc7faec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002710add587900ee7b1e7e12a1b83b6dd9638a57b5f9cd69938a74731a731ad9d8989fc10de16843c72a87af23e0057c000000000000000000000000000000000b0ac0405c468a0b1675e1f23f336b9725838f4d09099585d5457550a5e60fb64b1dfe5c2414c7ec527d098e26390bbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009872ed07f121a0d5f3d74f7bfcab9b8abbba113337d11e638386d2e8db61a21d12a7241d88c080209b00d0be7d06ae200000000000000000000000000000000103d2c2529febab2293309f86bd58a8fe8224c1fcb82cf1fc50bcfed5c6ccb32beeedebe6e4eec0df327f435f3ca36491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c567e5e8ed207f1ba1b86aee5e687665c6fd5742dfd970febfad73584e05f87922bf3e55e4cf0ef7a0abf874d163c6000000000000000000000000000000000fcd41a407159e9b84971ffa787a5199c286d6ba51072cad3509900be7348a8963941b4a34e4b0c60178a2c023b3f7ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dc4e6f93c80277619259f7b5afa46e693e4a00f260abc801c45ec1e389c527c0f3c0a3ee0bf74b072cd196a571d644000000000000000000000000000000000dd845e8c348bcc0da810f5fa5ec30b899b535beab3f0dff0949d226e199d28ad60bba81729c311c1b720f9701323a031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e10c3ea6609cd38a58d398995878aba9b07c63f785b8c33a988d834988c92cc80094bbbd9f888b239aabe508e965080000000000000000000000000000000012b58bbe3f0ec9707dacda9c8d2d5c304648c9fb39cca9ace411e7bd6a5f530478ddcb7da560a8f19cac4ce6e80833691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018240048a347c33100835d095e9d2d967afd41ede3bb0850adf7b23c17506ab0a0dc2999757665f6de1d99c2eb51bf79000000000000000000000000000000000e98841ba1853b61153edba568fc7ddbdca7bc0d836c3436aa9ca1a5de51622ecdfad0aa72265da0cae241fccd6c5a321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c7be458037b16073e6ebc7b4b93f94a587e1702d09f01d1d52f62cf8cebd6c4132c536a8c986800c7e2c1e7c6a31d60000000000000000000000000000000016a58204a6043c70bb9f5810052aadfbc5a558ec4ebbcfd232a065e201588bb0205dd4f437921097a48a1cc24449d9be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa7c4703fa768e8ee89efaeebaac6a9f448b20c8d3531eeae8a134433c8c5f74ed95f6e135e4ad829b127aae01b5748000000000000000000000000000000000e8e83a8599d11cd433fd3fd96223ae81bb456de03c4219c1a3c9c327afb6ca7967bcc7a7a3a22a86ca04d3948e064281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed9fddffeb795c498da8ca36504024b7c0c2dedf2afa76cb362f80dd169eee11917e5cff391af56f3f8c6bc96d1e46d00000000000000000000000000000000001628c8d0c49595e45b272604753d6fd4828a5e726aa621b72c49af132e5facb48e59d4f9ecd671a30b22ab37dbeac61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ce613ca7baafb7ab66c1b948096ef3d0ad730410cec7fbf4fff3b45fc012554c58c0cd3953144973b35a06a43b24d7000000000000000000000000000000000482642d858d23a72bc577fba84ecab1a3e5a5af894aca65864a363dbdaf2118a1093e74f4c69f06bf5cd6234f5bba661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000196753e93d84df44b86ebaf70bce6c999de08dddfbd1af42e63f763013509c30286046accf00e0181923cb866403c20400000000000000000000000000000000190bc1e4bedb42488981b47c79f1bccfe7de13c7a7ea02bc8e674a4cf0179a5bc78ee22a1cc9197b04f477c7b433e19c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000920d8a2bc9647800d415c9f813a7c6bfce10bb499acf61879c21c1ccb465e42eb3097063b81937a7ddc2b2f617707f800000000000000000000000000000000022230ed108867cd285ac8642dbcab6d7bf8225785f1a6d8da8c487da70ebc84aad9f3b53d27fbad44e8815e327004421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e35fad09353a91cb9fe89a6de29b85d727ac235ebe8b81242f762df7c2bc8d9a2b7a436297de06f978dccff857a6a300000000000000000000000000000000144371aa408110e49e8d254ca3982620a3f9849eecf3ec47ab455dc17c3053d668e2e6ddbe008f97519d3a8b3bf5db831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e883c3a400bca3cd7e685557088020716279fb6780a6c357efd86b22e02ab2b8dab4d884f4fe61a2526f020dc1233b0000000000000000000000000000000004d3c46e2baafa0b18a94a3f14cd298a7938bae7cfc8c349dbe9220992142d6eb2769da6a1ce110da76e8f0b5567f0601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ca49ba2ab6ba3e3252e531c3f26b49d6aa98062a876a3d413c511c56546fae8aace2d0ddd92031474f73844ca0fe0c000000000000000000000000000000000c78d0aa1c26e2928571994d63c6da4a0fbb80e48fb96a745f98fe0b885d11797fbe5e64dc2e75431dc437aca9ec85101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184d287f2f9c58be57bfb20ec1dd0993eb6179f2e53c62203534012aeeab5149f40bac87092626ee403a33cd01b2e344000000000000000000000000000000000c852d782c6dcc989108bb76694d24561ca4d02e8babad775c047cf2225fccccdddb9a61923cdcd959f7233badb76f9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b89776b96c69b669390e1bd33247385da080720435909170c4cae2fcbb7de6436f9677516050e5b2c13de9f5b2b49cc0000000000000000000000000000000013cc8c3c50ee26981cf618f89e1da2a6af493f5771ff15cf66abdb516b08604ec7519d239f6e7085b01d943b11e594021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e2c58d86b10c8eb2925fc2f07bbc9e4e3563d21486f2746f28b380068ec31d1d19f27c7122eda43a9dd7e6f085164400000000000000000000000000000000101101f420c1b41fcdea7bc76713f0e8bc52c9bf19bf73e343e4cced7deb13250bb1770ea8a6d26e78a6f09acae310c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075d1dbc4571d6ae605aa13e16d3f78da77fc464af28a032f3ea331bb8d2d82c3ce2a3104df384e7f888703f612e606a00000000000000000000000000000000099fc4f148250063f394acda8d43d13c700aed3b68a60461ac340f9395b1509db02f2029a532854adb1c7128fb7873981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a29fe8f833972b439e48ca0393e8816b2051d3a755b49db17bc887770ca4c3754051475c87194f4b339ce7c6d18c1c70000000000000000000000000000000008c8094216b05f7a56872b735ef825eab2bcf653501ac31f13470dce9726bda321bd82ec9a85a2f4a79ffc91762ef0061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000faa1fc4c89c5e5598a1c1ae08f310e17d9a2b8d075ab837109e7523eb7f8e5ed9f26d64736f74a4213573dadcb7de7000000000000000000000000000000000ef7895a0ca0bdb56194422e3c4c1599c75ad99cb0f2d24b624a8f90bb8a6f95b56c71dc1f974edffc2a7a4d22238a121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8bcc6296a3576179640b34cea2c1d214612f777bf7acbdbbcbddecfee47fdf1e552ba5a1c86a27caa33f8c9d101a71000000000000000000000000000000000821c33a9074a907ff54dc3268b0c701cb49e35fc4a8c7103e982fe3c3818b802d90c35597ea585d34a176ffff943fe21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b42042063eb2de768aa8276dd86418a5f1aa923bd45f7a4cdc3dd49aed83f9a992fa3c00520a45a77ed27aa6d1bb83b00000000000000000000000000000000035315441da71333a4f09baeb928563eccac7f3d7b4df9a9444014fd8ae1aa21ec02f7741a41d86d4e6dad4ae78d5d951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018834d84f75434b8de47ad7f331673f63e6084d33d263d7dfddfcb698543bb19eef11c4fc63d3c8d05648e8654663af000000000000000000000000000000000146d7e4bd2ae56657b159da390048b40c4e97236aeeecb6f3631f702f5e4df67c36605370ffe2a1367559eeb44e7e0b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a4ae40f57bbddcb9e8dbe48ea9c326432d2c3a1a0d2a056437321fb63ab30613862750ccc795057786ec2d813176070000000000000000000000000000000000ef36f20877ab932d26539a8d2adee6c565fcaabf9c5da5cfd29a5898a72e806639cdd73dfa8505710a4bff8af1d9321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060f32d307b47be543d862e955befbbeb4315c55779af943e8b5fc05276418153f7501f7a1864630634d6b3058b09770000000000000000000000000000000000bd339d2ada07b2273a020e7b8c36ce412d8ce147073f0048df04d244389d509b31438406b9f14232853003cdcf88eb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bf216cc4dd2c63ed802fc8b1c24683ae08ec3525bbbdf302d1a18be095c1d3fb5ec9d69cf2e1eb46a9d0faf419db74000000000000000000000000000000000129da7c6439ba75877704612f6fb7ebbf9d70216cdfab85af33e1a1917a859008062ec54b6d032e33332f8ef425ba0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b8ee9d3d16834bc45fb141afe54fc1903478cffd1310a90a928c81bfd9bd02be2279778605bb345e778f6d1af45a0a000000000000000000000000000000000875a6f0f79b4ed2b9ee85c4463c5def1ec9d68f6d4aad1d803ddc31b9d82485d459b952a2004759d858b80d8a5614011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000037ba25066090e0a63098955eadf82202a69465ffe414ffb855a7bba0c3bb19eb5e56c76e5c92eabce41a492a3def980000000000000000000000000000000017c20ad674ed9f81cf4f545095c1b5170bdccf3a50bdf5a1d334f5850e4bb52b65d49c7d0c2d27603d76364cda8746de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000011fbf855c7425a92e45aea14d693d01f618ed4f617b2ccef6fd6fb064891fccc4458c52dc434014cd4c58877581dd2600000000000000000000000000000000190a957edde27f9e29aabcf1a48378f46b9b7419bf42f65bc28e2d5712e7c6a718a58137513b3e8f978dc92bf19106ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157947113a993c8aadf0bf2f186630cb597360e7f2f757c440b7d70db1fddbe4b61727567bf4fd1ce6e472ef21e73e8c000000000000000000000000000000001848c97f79db84fbdc9f3bf7fdea9415192a4ae90f2b79a778cd34f0b9d80fbbb993f7d2285cf84e063b5cbb97a445a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f1b00c1f0ff8e4a0599328688444a792895fee19133cb01906299ee23e9cb893d4905ae7fa6e1caa8eba18529f196400000000000000000000000000000000117a2070e2550e7a0a13a38579b03087b78d90024c5641d8e8dd434058f2a40ddcf1e23d0af6a6c91ebce263b81f04241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac064716dd170a3bb92e9263d8ace63140b6b989f5d7416b46771d185ba292279fdf03e8e4a12a443487ef5e9335ba20000000000000000000000000000000006bec94d0e8c3c4c0cce39104c0ac7da8da822fda8eadbf95c87f209607239c5bcfede6612af5ab839301873cba1e7971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000600215a1cf4bb254b57e03595e53899109c76b96e56b5acaa0f2a5518ac19707a36767ce7165a9c92012fab1ba1ab6100000000000000000000000000000000054dfe661a29ea7889a15f7502ed952fe7bcc6adb9507cab19f1dee1a076fc95493de9f90250b4707bc7f09241d999e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094666e7366f39ae104e01286236f4e6a2f9597d4abd16e9cfdd8209302123230b51a5f783d8f38aacbd9b84cbda6a6000000000000000000000000000000000143a852f395fd3abfdadb87a8c5ef670733928758a1770f5baf096601ea12c7d6772ec46dc7965894681d82e21c14faf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186f577e517f4c44607d25beb80db4cf436e7198462903bde451d5e4319efa33c87b695be9f7e69edc108ebd6aaf2c0c000000000000000000000000000000001306ae1aaa9e9fd01e4d62ffedeffe7a85d004e2c955176662d4e9c30475932e55cecf3a5892025120df844225c06bf41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e35cb63c5068b6d76d5337a8ea384e6546305a08c7a435baa4680067786ead4eb4391f93614683b996b13f00868e5b9000000000000000000000000000000000caebc465d3ddf6bab660774c690fc1ef892fa3122aea14b212cb0dc8d77eb44368e2cc60737811e4e7eb331bb7c20f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011cf066da14fd6b291349360732018b14c8c7cc96d4a4e607f7bbba326e25ba3c10267a2fe7f85d6ec66650690bace0e000000000000000000000000000000000fb6b961d146856f1f0044ed7d69adcd945dd30db168670682ae4985bcafa79d91c7280dc321990b26fa97cb7fefc0991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd76672456dfc8dc12a770e089d9ddb818ef65f04e05b13f0cba5e11b07841e07cf2bbb7a7219288767aee95080bcc1000000000000000000000000000000000625b913a7e46d6720129a019f79c9a6d172000260bc36c59f24e6e4fb2f4acf42f13cdcb4cf8e1d3a91081e92a6bb331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b15afe48660dc7a990c1f4f988a5157d0d4d27491c289dfd9f4bccbd1da60fe9e14878ac06d21c3b390ca51723694e000000000000000000000000000000000020de3f7d26965a54065fdfc2d309aa37596ba6bc3c861aa7d61c3f48fae06b790c4dc83c65fad3937d502f217148e9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d260738d6763176eaaa62c6b6db979079aa1c2625b7c0e820c14a2dcd87f8a46e1f5c7e9b30b905d04cf1eb1bfb574700000000000000000000000000000000091f4f8f28068dd6034b261bf9bcfd6cd37ebdcecf4b20c6ca93c2c826638af6c1202200b4ff357ccdad89d70500ca861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc5b4825ab27319bf5ff104789d5d5600162412413c265c03e41a7d8e96fc5b5152ed698a9acb55d2bb22b969b9af9500000000000000000000000000000000013a1f428f0ea9a772a8be9acede71142266f0b8a7dd361c8ca7e1135ebcb557e1e176308bb9677f9a6de81cc45384911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ff9448d4fe9609393af7a9b7f0291766f96e66fcf21e22550fd6eea0e78bfc0acbbf5bb976863bbc8f23d2f58e74f900000000000000000000000000000000170c45b1da76dcd55f2a87e159424df1f9eb0be537c752b7e3cef58fdc77f5a73951a97687613eaf52c0af80d9cb64fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084cea7382e79d557637c6f0d7a7a2291bdf2bb2ccc78683cb98d6f5b276d80e95ab03db8ee16c4011dde023068f0192000000000000000000000000000000000ba624e521dd57413dda37a56661cb41ee4dc8e9c8a599bc8f5befcd52e3e856d9e05837165ed65e96c943e0825f32161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b83593d1a8b5757aeac5a8e2ec2000684357b472e89b23b117fd8574cbe7968449dc735ad0c9786bdf1276a1fe40640000000000000000000000000000000015c220f4da549206fde3b7d22827589610aed2f2b4e2330e174ecda888b8f34cc611fe712cbd589efbd167b412e48f2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177ba5b20569c67c71e34a0b497d7f359bc4f437d6a0926e07f6d6c668ede731a80c0f321edad47f9d44d10586c26dff000000000000000000000000000000000a6b8d28884cf3ddf7f7b14e178c7e47a6861db91f3cabf05743e0adbdbf964e0052c73d2e91594c7405a265158d07051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d51e6ca12fa2bc24f2686908201765168ba36df1f05b01b392e58205ed619c2bbc32c970f2701f56acd3fd6ec26cdc000000000000000000000000000000000a1280fad6a768d2c0688a466f291317ab4e9e40ba672da5792f0d70fa1ecf71460bae1fae6f2e3750db73f6d25b7f211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007be0f8845280d75d68f995e1276d0e8edc1f91155eca48ca8fd0f526001b73d58023610ec4ed71583db3a24e45a600b000000000000000000000000000000001434c2d86cc17165d762a256a4cb6f2d8a1069103ad34c519bead5375698fbe51c335a7bea327c99b3c84158b78651e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000786ac64f8e785401b884b5e10dd256c05385e76ed4f729b7f79c054ee071fc77a21548f50533a6b2e88be44637f0a00000000000000000000000000000000018c982d99d622daa5077dab56373796551e697f8b7d02c71d754c588a2a559280d2c8340437b30b542ffacf1662941291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ed324c0d4ba4347e6e08d11df682873696f01ce1615bca089a2763cace20a326aac0586600ae454139de7e549cc800000000000000000000000000000000000d9139c89f55b10f88cbe91d9e2022f70821f1a145c7d6817e5148587bc53c6cb4c62e33f3fcaa76b3a5424aa16944cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ff97b0c1dca3eef3f9416627117485d15926457aa9ef6411d520c1bec291bd92192d792361a40ec2f3c1328d2833a800000000000000000000000000000000055566657e00529e417bdcb08d8ad2595db8b30e4de1401004645fad41272fe99645b6606f557ad7e0b32db45f2f516b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015768e53a0cdb465806b4b30c72b42848a21fa6849660c948b5cc88ab24f01576365dbef519f9e0370b92a36a5c1c2610000000000000000000000000000000010e3c6e2b8bf2632494ea2426df204a5266df85f3b58ca88e68062d2e7d9f513bed1950ea6e78536e68c959bb433a4de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2bdb884a5ff87218f1d4f1daf98094410d94c0f036f4bffa127434dc4a58bdf12849b45fa1f94e9d637f24ebb6e5640000000000000000000000000000000004127ae1ddd782d81459c289dd3f77dcf3193c2f682b1e8e9078157aaf051f02326a218c31d59f1419306e714664ab841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f7e03b4bb1ae15aca4d2169b012ef5f3311baa8b270980232e9cbe62a99c577c3d2dd66d566b236f65c36294e37205000000000000000000000000000000000854f3d551b677a1f48b0791121612523d8ee8e801f5b5b0310d78693b5514f08bbe2fb24900beca249230aff064864d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001021fb68942a846028108cb6fd58a841f08973520e024135ffd6cbbae1890d9b0946f3dc590db5f9f801f05827ce7cea0000000000000000000000000000000010011246ed5b8b14c5877cb0f5288da70a28f9ac3e8695db798b6125f00d24b2c094452d8f38776bd20ca1840dba5ade1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073ed27525e5a6700502abafbe9cff73ba7b4b9023f3f151e981c45626526b578594fd11a26fdff77364a9717b40a3930000000000000000000000000000000017d5d660705d4a887cd611d42e79f3e69d38f94ee6752f39d7fed623fec1700fad8e969c2985f4c56c4f5e001a692f6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f153ba71c6d6440539afbd559f0ca9de6e106a5f75b2e8b7919bc85836a808a8f765c720fe9db4f694df94593dabd40000000000000000000000000000000001f41a2bc99a77a840291338fa9eb83d3007ce6e45410754ceaac469f4837cf957900db0a517b4e009b4657a950c9e071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014d58e09e57bd4b6f4e2f45e4af1895d2c42a296f73a731488ff67076269a2867c995fa3ca42103792254ee263df15d000000000000000000000000000000000bacad14f3727296bc95cab4e5982587ac9d1e0ff42ca164d8ede267a1567a82016d2e14c7b94a6371fe5ea100e14efd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024fbb9ddb471b24290d6a9cdc6ca0213b0efbadb621c27e1075cd832a290bff4c60d478f6d128ed202228826d05ca55000000000000000000000000000000000c64bc8a2effc3ece60a555ab093dacc790274ad287eb6bbaea983245ec86f155d42ce514d78245a14596b61d426d31f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142105d3e847cabc69ba5e7bc5d1196fa5034c017fd44a5865ec648bd9197364b34ce7f8fa32022f058834d556bc3f40000000000000000000000000000000001667955e6b6f57fcf2b7dbcbd11bddfb76afffb4a23457581ccc2b46bde4f51ec9ff010a712ed86134e465185ebcf9341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c0ccf98e22389072725385a69a3872c46cae8fd1851fcc1f5438c20210df7159c10afefc12b5e5edfb6abb3ae2bdc50000000000000000000000000000000014a5bafed2b86ff707e2569ff243d8a0cb5494b22515462196ae579167feed106636ee9820fe0e8331ba3f66f6c0f8221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000399aa610ebd2f18b8a15d22f5a17a2fd5554a5a0601c80dc7370ca2c5a342c311eea85be3640d3c2a9573b758c67d22000000000000000000000000000000001606a920ba1bfb72782e8f3e15c13d6dc942fe23f6c50e68a25c24614e106d5c94ae4100f2ec66612e1b8973ffb202791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aaf271b89b9756d25b71d33cf31c75320d54b36fd49a07db4d60e4876153fd96d5bae7291f8d8bfccadbbe51eda11a500000000000000000000000000000000190552f52a8619dec191a62fbb91b9f69676939ec8f3b2a4ab8d819b1bb1c5cc3570c4b368c27d5cdefd4b27570f0db21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004491739f5c52361ef76cb2bd90fb935dada845e2434315cc0845c4af3677baf606b8fbfaf0fba3b8626f9eb8629a61c000000000000000000000000000000000f662b72d3c69a0020105f5e184a0048518bc9ceaa4c03b266bf7f1b44c212c3b3534f7e3657c900974885d315da01f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8a95dcb1778e07b26860689c776e3efc4c4e06e3bfcd95ba1274001680105be10047e4d23625ed9fac4fa70bc716e200000000000000000000000000000000089ea06c81ac54a76b0ba392c9ab2df5fc87a81989a13f2bf3b04dcab20aca35850a6430cf88959b62198035fdff900d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0885a0ece785b995056e20c5bff678557681c33dd2152089e0ba03bf5178b7ca5d60d49203cc73a0b7064df02e334400000000000000000000000000000000160d9e1bcb4119067ac0b68b533cc7ea7b903a19138dfcdb1869750bc0b7ff9177e7d38da687a908e1daad56cc9829a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c78af0e1cef2856a17cd14c2ae9f248fe56e84ea201a4475783ef85e0228db9aaff7ed0ecc55b129e9ac00217f2c20100000000000000000000000000000000181b0e369748694d7a08b49bec3d93b515c14f2081f10fbb99d7917e7a19da12b358fa5f6e502dd1f67342a412b2c4721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf7a044ff63e2233377a716e1b64cbffa503a3fc6169069bc38174e19afcd1a0d592505742bf9d3c13eed592738b7360000000000000000000000000000000000ac02fd573f9ea988d30e56c24b6545515d6f3af03c982ff0a82cd4ac7ac205c72551e6151e7ef5eac53d1d0b9fa1e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c9baee6762956f7b39e817571386f751fdf1c6e4ac40b9eecbe6e54d2977fb44c87c00ec2e1c1537ab66aaae4dd0fc00000000000000000000000000000000094dbeff7f3297076968a93d7182a1deb76cb7a596008ba97a1845b4f14a052fba96401a9c44fcf25078df9d38492e2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000667243375d3b84df7d3dabe71aa104f23504fbc169e473e91c0ad6119a5d4ff2820cdd7346d9cc79f45d38a292431aa00000000000000000000000000000000078affac52470cc57d47ae2c44e6560f87580ed2ca5f7fdc72e40085d33b11f5ea20c55506220239fdc8e9b1cf712a301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094c0d05e26b5d8b693c12a9323db394cf8549da95b5aa67c34cf15057ed1ca0ac09309b7c99d5df94fca93c5e8d800c0000000000000000000000000000000005b7948118f6e21c9f94709f97d971a61e64a04c49bf719b9e3799a714e7935a4cf140534286a08e0e726bcf6116402f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160fd88d69100714bd613d80384f58e431430d9292a0a73db821696d609b06e9f309c85a60b6dc02eb638210b2a26d9500000000000000000000000000000000021f826ef63b9d848ca2c2edb73e48c476f437c0939f1d0d1a00e03cb03ef1b7975db11be620deabc97253452dae23c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001882c6537e4001a19fd85d582e89528120bb66446457dd1f2ad739376539c4ff49059311a6bed322a2a4404f880d15f5000000000000000000000000000000001137cf840c4147c0047d40d475c78ab65ae3711e2d7a6a853f461bf7070f4895fecd2f95118cba8816590ba3ad9a47e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad20d1555fad0dc02e4ab6a5a01bec6c98dc7659d6e6e0e8a63e65eb712bc388fe14d8bdfb2d5fb33de4ddc1de553a900000000000000000000000000000000039b8969c79d5449c4c0a05a678b5475702cfa990b9f8b9db82c96d08432704d205070ebc4ea7b95e850ffb98d1c233b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000774e5e221649e135f19bf0b2072eabf8714413138b8c3591a6e6d098eb57d5d9f63c830577a56bb8821c13047b1113f0000000000000000000000000000000012d5b8cac25be18efe9f07be7f185eae73b7996c589da67b4f14679970ba536dc66c81ac2f70500abc695875e7f35fbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164b7ce95be6910597daa839664cc62ee7d0135ec0d7554fe0a15a0f5ffcaccd1206d3668297b5f871125ae547fcb1e500000000000000000000000000000000078df16f5ef148456d0e44334eba0f3ec0e7973ef1e8bca8dc196ad1c5218624427b84ae53b905ebb30236972d8bec6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d3a919c9347825a43e96485d27d031058e1d6fd407d38604c318b53c87e1c744a11c7c7d8ba12e0b42a18472ea092a0000000000000000000000000000000006d2e0c973935f0b3c1d64dab6063417afd01ff40a44f89ae626388c13f6062b8703fe2e4169f4794832fb26ff5869561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d948ec19e6e1851c7d6428f73f663f5ce8f73af55655c4eb30dc994f0a344e520496da240d14164b2eecdcd4a88d9a0000000000000000000000000000000015c6c46e7ef42a17f51b53dff689fe3c57c325103db00c4366a3f83dd6865ab84f21e646c33fc271c299211c02350a911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019abe68c3d541bd0debc1b578ea8b4d3ea3355fef68ebb42e84c9ce395a09a06cf34051b5984a71351c030fb09d05156000000000000000000000000000000000b901f00977952479cafe39be57eea06ad1b51519f8d26351a9737415041ec9604faa815a45c2326f3c557d307c15c291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001803b18c8b7e48a9b7123adf02c340c7ea473d4f6528c1b3f73245b9716d40afddadf28c552a442a2a8808e5dc448c730000000000000000000000000000000010780066e036aa27e4132b5e7499155ba4dcacf999dcd9929cce020e29aa4b310d96b592b17221fafd7e742f92555c711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010df04597fcc7d5ab26f51c1e78ece212418dc156da586cb29e5f300c7da75ace644654a74829e697161ace9b4aa30cb0000000000000000000000000000000013a68b30668270a99b5257a41950c8ee7ea69292bf18a9108a2cab2fd5daf6bd174111a9d383229b8c59c840031e09041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee986c68f5ed22afbe5ddf8920c7e5cfb75d0859de625ca1f862c6d8295bfb289ee647a82d58e969431ac33bce4f4c3000000000000000000000000000000000523a4ccd14ae836b482002dbbee0d423dcf7ed96a83f2dc64d0284e692ac45dafd16efb76cf417bc4ae556b1977ab6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160bd45f38087d834f22f03e9376f522c2a13eb6602f49b021c9cf08f7d22163a0cd11b7fd2d887a5fededd2986165800000000000000000000000000000000016559cfe667006ce075cb64f5c1cab437992868a24fd6038ea4245f196dc1cc7a270631b4711f401e37447566308c6831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000046a5143688a53446c5945b17dc454e00705e3ed855547f889e09734db51030548405bba1ce1649f65a156b183db6cf00000000000000000000000000000000137ff006009f34c6259c4b3f11b4288c95e8ad10f36ef98d4b86d038bd4407b33d42ff96cbfa9b7c4f1d1b7897d38df01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000baa74ef2afbc4629885fed9bc9fa50175367ae998c40b7cb9e96b2776e13a562a3fea2ce3e6f05126d3858bfad633ba00000000000000000000000000000000087b64d2639e16f7670a86e0e925e7cb8695545f402edeb5961cfde6e754afe30aa30732178e0025fbc72520eacb96701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166af934d78f24c2fc831e160fe1c88931de166013ba68a0a9c3f04ed39b95931b7def3c991bfaedb7fd4629c2ac9c6a0000000000000000000000000000000004e819b46457d7c31dbc87fed71c8f21243373b755a5b6192bd1f8ebf9767ee959fbd8b18c85e4d01f2f0223ef66a6451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1d109f96afdbe33174afab73e36554dda70ae21b69d5934ee59f54d85a287ac82afb9d312fb3233485e1cbbf6e31a900000000000000000000000000000000010eaf1f255887b5fd97a48d9728325553a170821bb534c000c195021091e42b5b388a31a1bfe0dbe0f8498c6ec69ef91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e9a9056a210f34c75264c62778df217d4bc1f409f7f989dd7ae9d2b7a874775824f1fe5ac71ba862abf4ed9c2d7586000000000000000000000000000000000ed9b9f04daf140a012c307a5eebdc96cdd9f4bc353c830fc68391ce5d5ba68474f440a44427e5af12f127bc77b6b0471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195de1ed5057c6c01919cff1c2190c8882c0733c3cdbe43430b4d6eb5ca4a5bf5cfb7a48c569025cbab58d784bf9b532000000000000000000000000000000001983f9d2e3ff6d96951cdd215c95ddc090c8e109ab0405aac22953db8742e11f29e32523cc437f47e1abf2cdd8d31d461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013364f490ff9f457d8b97040312abd45985cb83c2b081b204afcb0138c2f4797c93c50a5b4d8961d2d2b3bc40ae72b550000000000000000000000000000000016a9da0c74b7a65c047069ce10a5d0f752a94d7aef09fc606114136e8f3a14e3c1c8dc38b6be321c059384bc9715b5441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177ef08e69ae13e28037d2eb600d34d2c264ba3a6da7d275b14d1a2a1ab4fce1c5110849777c3250faa2a5f0a342e97c00000000000000000000000000000000054551cfd637ea60ad1b5fc36afcec4edeb34101711cc49a034a48bae6847ac8e8150b4e13d324c269c6309e57a048571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b462261c1aa5f552cf9990e8c8e4141bf2dd818cb6aa8f641a09a9c41b398dc6503fc0b27891f4137bce25822d46270000000000000000000000000000000015ac04d212fb8b661fce091f4114a0a6e4a36364780f0d6bfad04d268c51a8fed74f4b274e5f1e10e47aef57e605a18a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091cf9e04feef995d6898274a2df5a7281e586b846efbec3ad9ac88cf712f10b4a6809b71707837145884ef2cb1afd2e0000000000000000000000000000000005e45bd05e7546d18b08d6f9a6dc5fa775f464aae3223fd4a63441410dda07f7fc5a1f2203411ba430f5104d2fe7e3ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173943fc596ebd53fa3222c3879ea88757d3da19e7856ae6f84ede4acb580ce75e73f5da011c0b928ab89416e96928e3000000000000000000000000000000000d8c10f28530285378a077729151c46de22578815a06dc63e152796eb1a9ff94a6f3134a131f4aa516312cd6b603d6a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000944dae479de4729414186d9d3cfe1b9e3338d2b7d695f651d3dc7d1e1a1a96568aac6c52636491ff180f746b61c11b30000000000000000000000000000000007188fb6f89814dd35e7da3f377f30164ec67b5922dff3b6c4c175491cdb78c7a0aec962769f6ac384b6101f1679b0e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e5ee07700540faf2ede8edd9aef167d8d6bd12b59a031b589b0a3298f0694276c918e7e729b583e04f02caf5c1bede0000000000000000000000000000000000adb6cec4497fcd610afa33294353c5b5ae3e56308a121620de6fb35eee75313ef6a8e66482af72e7dabbfa0fc7aa991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037fdaf03f6b01d61243ff2d23751e1336307fafeb73d4874d42cb28d3772d7e93c22e1226f33044a6bf6ceab2aa7c8e0000000000000000000000000000000006d993fb518dd43860e452386fdd80451f9fdf9e5b16c1502e86e2b8ebfc1fc87c781e1260055517a1b96beb74d1b3aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009106f7b56dcc27b52e46d421fc06228b3c9e29264ab39c80433880de0761352e003968073fff44c9b9017d7f1e20930000000000000000000000000000000000874400363d26639c1eaf4a875f81bba7a6cd00891e19a1e38de97b6600e50d5c8be4c002d0e0b274aa1753d9d12c6c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e709ff863e368314701a79313510676c29aae9cb9ef84729a10663263c89649d942c73a4f631608f0f9f5830049ca34000000000000000000000000000000000db3700adbc48307ce6fccbfac6b37ef4a62c1c77033b5869812d1dc11ab2ea2ad0392582332323e2659b6c2eed20e401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f2e6d62cac4b859e7819ed4b663e1436ad39d37e6fb935ea3ea8043c05b16923d2e62274aa41de14e470b123ba5a9f00000000000000000000000000000000151044c9ffd6be16be4867cf15d17914f128eeff29e0d4f5d09b6f1f02970bf009bf0dcda34d0c950de2368ffe3329fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b4494e8cbb1e0caff13c61bbef384884b34204b1bdbe7e8fcc5d43b0726cbe0d97f22a615dafccc988e55409530d00000000000000000000000000000000000d7d63665627d60e4e96c55541e644aabdd0726833a3566ce6ae14981d85bb4e9d89953a303f25f2bb0a9fedc8446ba71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db465766f316464c1a371b2983783a45ce901eacc33e81f79a4dad71f5649a4e8f82cf26c9c55ba8211662ef170ce700000000000000000000000000000000016222ee296112bdfc17b0121f9b4dcf8690afcfff744c28e3f1b7db44dc6a64b0a69a03d4f6612cc5ea07502abb628ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045c5542264a9ca22b71a03913f5a084551aecfb0e3422f8eee6f9e05916ba5edbd56df66901c271d3f448a892434d21000000000000000000000000000000000832ef8d8ac6db89d5da7d0941b6f2b59cab63ba4c889ae1cfcdae2323ce1e777c2f6ffc3b61eff909f63f3d57173f9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2d148ae5f752b11e1c6a42522b056cfbd8fcc60f1ce731b757972829e4d5e2586a28b66478fd69158c6c62afa1d2fc0000000000000000000000000000000006af04048a891bc2650adad04a4994e9f9bdb686806d769edd6cf70611d28ea4a488d927dd80228432a184223b7a46ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb59379c0a31703bcbefa3af8a8a71b66742e7a64e50ae08f95526943321b84e130c77d6ca78a5357847a0845462fc50000000000000000000000000000000017bbd3e2ac5de9a22c9ae1ae13b9f025be97af6db0367c55801a9ed66cbc622579eb51521e4ac9f1b3304ea6feb346b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001805698d12e161ec482fbdec7778926f36886146ed99cd8847c5daec6f6aebe42e67be09695b2befe2c39b22a4b897b3000000000000000000000000000000000547f1161f62e6cc352e7ffdef1e034af90441d9f47b576e99a6a189824fea9400f7ed451bbd8636f626c745619be9751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072b803f64170fcc4e204e96d7a8ed30a6bcbd810bbfae4830d828e42ae9e65cb238d2768ee96c9eed4068fe23739de1000000000000000000000000000000000f26269c72f5fd088b993cc6f1600a27e296cb47ebe4ae557ba305c1fe89c110c78c022432e9766aa452bc5725e98ab71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182c1d8959219c2c7c45c6c2cefdaed170c701cab78f432da61e71709de6b196e1d3b54ce2d57b366b3c738ce5dea908000000000000000000000000000000000e1ab01cce625b3984466675344676ef904ca6d8a10adc0fd1f50a7cc1c91703789ef5b435c3ce207e8daee3cc7684cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005eaa90dc20c9e41b93cc9ffb817499d51ea355f8c0bf8c690d2c295c038adf719ca3c1b0ed580817a4e7745a2bae7f20000000000000000000000000000000008e6189c3440a0028d87f74207e0edbfc358e80fc84308492e6dda8490d50ce8018f9a06e2ebea4577a62046a9de4fce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fd1b1256db96ff920ba5aa5d2053b6bb616f40ee92bb87a5db74781e11868c2933ef7c13bb89f22e4fab0e8e8e9e620000000000000000000000000000000011bf2ca58eb4b9b40b9157570b9907472776f0f46ff284f6d22aa8b1e3c4a9d89fa8c293f4c541565ec68172296239861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f183bc3c76145ed176659b4e591bbcad73fa7e509c82f3093dbe0a443ecc15d62817931bdcd4cf9ef15738dd30c77f000000000000000000000000000000000e5f1d3846b9a6015e41598a5e02522619d3ac33bad98727c723ace55f19fb652d90b1c506f0fa926018d63015da801f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092e5a45b738293f8553b2bfde0dd252b1ffe9969dbd15a33ecd399d2c8dea89954b985c387b3ee40ba95687c9ae2f3c00000000000000000000000000000000037bde013aa0ca45ae22fa89579b3e3ba97a037396fd1e9144ece55911d27d10679658c2dbd7629430a953fb789748ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000011fff4058f1e6c171a3654ea2058c2a880c236e01e083dce134ce8397dc640c4138eda38bf4e7e7ce9ca21f2fa3a50a0000000000000000000000000000000007a1ffaa9b7d18b1a3dc7e2a0915d43a4b86ee4a8f601afc9823a836b6f7cec48a05f012646fc8ea95fbb54e46b32d251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000066765e4233509fa2d587a906f7e1bb4e8568a4664461d19709a86569a8f75ee5a67a4f2b6b5306ce7e911a98cb5025000000000000000000000000000000000bb5037ffd90df5a0d2d92217becad4a8519aef07e889b22107c3bdfa0816343a8ddc7ecaeea5be39d1f25a24fe11f481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f0737564f1bd45e29c052423ab8df58a258610d7259682b74427bfffa4f7da3e62f20075678fe60e6ffb7e9d18c2eb00000000000000000000000000000000063f537db560c480f43f6d2be395ddd4b404e2521ca707411e2a1eab5096a3ebc907c6b5d1e6e029c4e5724c69a7a6921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c6aa3c3cfbc3ff26b853f4e72cd6a0532a34b655ab4f19765b35fd6cab099674ac0560ef2f6b64fefb2a2c3ece555e00000000000000000000000000000000191c47355f12082b7d8bd8058c89b9d123859943d76a07a9266ec21380bd123234593e6f5b78be8fc76b38d59e72736c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011eeaa371882013e715b38fcbc590a9d5f2e291b0955ed485147170eeb22f4bd6d6437b0262ae43c84593a30fcfa03810000000000000000000000000000000010c1cd372df982c089032b9d6bdb1058e914ed7bfb68f5c048f872ce0b18b547316f62444f598b1aedb6eda9d310e2681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c35312b114523f646124bdaeb9387226ea2bb8874284bcd148c5fe66780d50be9e60127b19799d4ca65ac0ce5507ca0000000000000000000000000000000003fba228b9c3acd082b29aa42c11399007ec004dd66cfc28ec51889c487f43df432ce628328ca6947555eca25683759d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2f8455d719d941fea3aa3c4cf2f76bd61442bc928c8da2c9966f4b9f9f31d778723a3f6c1a9da667076289027ab459000000000000000000000000000000000b8e5f572457f934133f898370b5448164f29756416918539c2a9d060fde1044865199c226388cc629921f9086c210aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005a96e24a4994cc7ecf5550ecc6ba410da6f800623d6ca348c2a32f04390219954dc5ce1bcc661633fb98e6194a971d0000000000000000000000000000000008de198cf36a506bdc74b59376dff4f3e993dd58bfc8bd39f8a187993d09e2f451b8217b734e818c3ccb8948a014053d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c274d00f95cea7dba561156338053acbdb4f31bfbaf47b1b00e35578849cff908e661dff2e23193e7313463f8375199000000000000000000000000000000000f0d840155cf1fc84a2b4481758d3597c29cf69ddeb1f779a3b15c1651e2f32b36720f4ddec93efb9bba1b47ce0309061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001943c7cbbfb919839e46c47e9f19df641447bcad347a7ce756af314048488378cb6528c3bf932ad0a55402ad01644c23000000000000000000000000000000000aaac972ce7195298ccc8bfc7a3d2c87d5a7ccbed52f441aad7c0e7a00b06559149a6a5318133cd4ab7c6f510b3a36e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000072b0c76dae39b84c6eca2b009511285022e93d659ce55f7ad57049fa2e53ded33b1fe50f8d497430394269ffa639520000000000000000000000000000000008697092a9b93f29bef74753515df6dd650b05d2fea98b64879d0af85a69939c4dff3d1f9f88caac2594a280d0d017c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6248145717f1924cad4f37389a3aedf55f5088661a8160e15dc134b993c96d0d24884a7e9bfbfa497c5e572819f9560000000000000000000000000000000001365b48bd92cbe282b728e23df4ea369a773d51add1d8c8d8c90036f65b51bbab874810cbca850e9580ec42ed8ddbdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148765f3480592083250f19c793dbfd573c0b1a8172303118964538cc4ff5ae7a4631fa67278c2f9c1a10e3bda3ec3a1000000000000000000000000000000000587307541f6a28fbe08bdc685a63c8a4e1e6fff9c4a0744acaed202cb6869d795c2f2d4a777a91eb375f601dc550d3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f53547075d2df69025c158b9a1449711cb1cb00b99fc054f5ab1c3770b02447a0bdada9d8f23fe63077126be568b1ec000000000000000000000000000000000064249595c981d2054cc8efb60506a99a9f97264492eb8fed7766b52e0cfda1454756b1d6f28c9c043a35b9a36bfe911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a9b92cd11777eff0e2007de5c644f2dfd1c928cc587254469e51126436d376e549c816f3a554e40b646f092e257e1a000000000000000000000000000000000a6573e739805764878319a042444d72295540c741414d7502e7bfff83aca2ec9252c56385cca5eec1f848df7ac069281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6e0bce29f4211fdd5576b0c68569a601fe642a6fde71c16ba72f10fb7e5bd7e9f608710e5a7da540e73bda8eddc74a0000000000000000000000000000000009086878e3f915c3bc4d702e12a64cb9b419e8dca084a47ec0be0d646b2285fcc85f48c2df26ccc21d477b1a4c1ca0eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001596b04c9c6471f945b91fe5435d3f3ae6d8153ca5d9b84a027a7c5a5aaa60fc7c4cc3237f0dc53cebefefcd8aed979f000000000000000000000000000000001521728e9b2b73f4bff6a77f05ae8e38e21d3c504a833d204f90d9c1b4bc69d272d16035718fdddf2526e47f0748996c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127ee2c384a03fb9531fe7daaf872ae8860328c4a7c7b2601000a7c57ec2b0879e387ef2653215e5d39cf6fbd032f1b7000000000000000000000000000000001206972f4d820f16c691b70cfacda0272bfac32374ddd273d6c925a3ff5f80f0f1e247845e895160e15e2124bb7ad00f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168508a77dbabeec5ad9a0055b512b31056bb0b502797cab99a4894a6c0c8209aa3e42bc54c1ff63f6e8c21fd41a3763000000000000000000000000000000001668fc859075792e6e0c8e5f6d96f55163fd758cd338d49d4446e8af3b08160911d91279f3a2f285813e3d5a58806b671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e61d7b1b208a3e6be5a6bd2a92113719e9706c825b7cde82280c7ef478be45783ea7adb1acfe42266d8bbde294713c000000000000000000000000000000000a5ddcd761be47920253be7ea95c214fcd1627ad76a08eb5c83e214fe6f5262e1becc3739674df2cf7eabdd4627e306a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010395d32e619a91d17aa692a01a28c5da55acaf2436415c51d899fc83d11039ef689be0cc266029edd73a01b9ed3e20e000000000000000000000000000000000fe6ed5d39ef9a6e876d9f3e268b07bd92481c6c0dc01c2e47ebd2b66995174dc9b05d80d99e29af289163a7baed69021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5d2a542d4c8c52c1769b1d8a3dcd6c8919b4bf0d3a80061fcdafaca2cd30ef9c07eb363fea2987e0a1bb24b4651372000000000000000000000000000000000bf382f5fa38e00bd53289e74318b93c1941c550ee992b61b6749205820a541857b3cdcda2f4f3c1b990735f1d7237311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e88d79be7f26f9a68fe451d1fc66cda047e865c8420e239bf6c5018ddfa0a8b535fb6bf266d2e4be586ee1b24069770000000000000000000000000000000006cdeebc76068b695853a4f9734cebff4ed8e30a1a8cf4f1e8276b1d145e193fcfd5cde94199dd17893840d48fbbbc661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061ce1aba822b75e408d960cebc757b1c132aebe888af361b9e73e1d0ed3036fa3f1f140e76115be4d911d2ca923c966000000000000000000000000000000000b93cd4382e26d0fa5e003ae5c356541db03c0786db9d6917b25a061a839f4a4a0e1a85a5c43f966ec87931f939fd1851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080191784fc117543f72245ca290f29c1d983ab82a53958295beaea402e348750f424e2c5a90ac231184b07ae29f3a0c000000000000000000000000000000000467f272253efa6ef414180e32806548671c5e0e6ccb0fc920a116ffe1614947eaff98e68db09d8b47384e7666e173231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000898377b0edace3feb8c091692ea0e8c31e32da56c825b3c458172c98a7667c3a28329771c6ccfd80ae6776fe5e380090000000000000000000000000000000006f2a3a801b95aac32ea50e2605192fd10737e79480401289f295ad41133e63880201513ef8ce7a9234eef2b005547ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e37ea14efef3e5d930626e250ad788c96c61d92f990b6c32cad10d390cd08b7abc14d61f9bed0564556b9369328cbb00000000000000000000000000000000179844bab168569b4bc94963a9198ca7cc4dc6ae730bb4fb19891be107bfa35ae6d57e755af041bf59a85d59ddf5f0ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c41ef4708363dcd85a2517ece918da8d7e29337754ef28a0b67210b2af3afc38498c157d5cf70280beb6905a56515a30000000000000000000000000000000012935d0217fe0057f77742acd0140926de195f70c285cd9e08539be872bf3cbe0aa1b702bff7eb105b5ef6a4349fc4d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e95ec3daf371e4e1582ec1d5e0eac2dee411da2152052f231b4a870548cd088d7ef095fc0ff0e4321b5cb4d468c35ef0000000000000000000000000000000012ac24014c6c7933d819b36acb4d22b27447e538faca06aa06e7303210281e45f57c37dccc4dd0cb5177ba48094ee6101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000095ecbdb6849dd1059e30bf0c72d03e273400c025a674ce0388269eb0798428565fc4249760f0c2f96e5dcd73229ac6c0000000000000000000000000000000003358950ebb8113746421e4f85f6a11b1b9949f635408791e6bdb834e864cf695968b1eb6ad6e4d0da67129ff81e52821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000526794fda8e74ac3e48fa942eb38cd943f5cb61184b127fba8202ee6e5ad51621a3a331fd39cf7ac4e49635f9518d0000000000000000000000000000000000075281aeb2da660ee1de8baaff2d9c8dc826379c777481658eab54f24244df5d2dcff68aeeae6f58b59015ea22029e2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190b5dc941762ce5e81f369c244f307fb22afb653e1ae62ae34a1bd07d17aa8fe2a1bad1ef595d06485683ebd355f4d700000000000000000000000000000000013c9192ed58f620f0b32c649054d1b9248252c2b30af6ea73a5563434b68d3cd57c7b16cfd9ff6b01cc6bbe08106b831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c4d3f60cd85a69d1493e89040a62565f8bece91a2cc17f749355aa082a69dd78e8577dfb00edbca6980198c7e94946c0000000000000000000000000000000005bf2bb9b2974612a52a064859a020af4257a00f88aac05ed1e46b59568260dc7006485aadc5c90f22d48365d76623461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000930f7dd39ddfb1a99d675f7dde6b3677bffc199690edfad5a74fa459be88468cd1bd92c1440c2fc6917fe8668f5202d000000000000000000000000000000000a9cd73e8c2bb60c4a1c31dcc327d634ca87c8ba54910f31e10994ef8b45cb23a66d504c424154b9738398ab3f149bc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009069ad4564d09f68a84cfc09924a02c07ae01c9dbafee7d26bf0964a03f7deb99b05e6eaaf86631765e603d66890a1c000000000000000000000000000000001075d3cc6597f0d2ae57309c865fff945a9fae217eee4c20c70454136df089b4642a1d24f2f5b6664db3f2d081818e5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001470c838cb5159717a5dd9c9aada90f58d4fc55e5d76f53780793f0be07d12cd5a12abed88831ed265849ebccc22ab17000000000000000000000000000000000df539f83ec246470169b2fe9353147084727d8c28f6c452901f8b6921447231ffd5c57095464bb84ad465a08ac170651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009fbc2d256aff20222fbe7f4a9a21e24677fada6d05c3652dc7f9d19d5a04e1fc450212fe041bf15af49123b168f59e700000000000000000000000000000000013ae042886cd885e9380702885e8e05f3fcdf6a5897f64e4bbdb109b1d8983e4be03e7096740f1a12a405ee29aa8cb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a89a783c39aefa705473437d40b7c0cd141edda269290220479bda76566aae579631bfd792e47dce00cec4c3c81078000000000000000000000000000000000192c0202316e179f13de30114a9dad0a0788e50f06aa7a673551b0366839fbe155962ac02e967488784f0664a7b37d4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bfd9ce7c4e842e7a506145c9feac1557062b238de6b76b3765e4e231a16ce1b72e78c05fff18c9f23f0c07aa0d0bbe0000000000000000000000000000000000b3c942b15fa9336de467c3f50c18c8a50b23720c4e72eb4b2ffde36f9b74284f9c9f10de4fd31222bd97615a73b41811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fdca902dad1b647de40f044a683d981a01092ab2a809b3cd138001ea05bd48cb570e9da8c06d163044abf37a0f87dd50000000000000000000000000000000009f816f5730d73ad167cf51816e4e3a5d81986c4a717eda101b3a2ed17b0beaa6047b9071caeecb5e41aa67cd733fdcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe8387d5e818c5fa1d853132050b6e97ba493a59828468dbb9c2f7d7e794d3c0d14b49d939a23cd448ec6d7c06abc5d00000000000000000000000000000000171552ec8b1c6ad50902d8537a41eb64d192c065383372209a45b99cb7b6be987b1e9643fd25eb38ed40b54f0e8390311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000661b5e254a083385955d4b1a8b1049c45ef7588d77f3811a2aa044890a3dd881385a40c6e4c5e12d7a5859f5fc4eae20000000000000000000000000000000004d15cb7273d118ddee9adf5d2d488f86dbfc2db40e7e63671f5d1fbd891561474e5de54ceb107904ac66f76168fffe91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000186243414adf27f27c1c61870f2d10a4087d4e8c836861252653f614d494875c89d4e65d91f9c06eebfc8730ea2a79f50000000000000000000000000000000019ad5ea68e90f7ebceeba1ecb1aab1d3b50ca16343885a863d174c05fe9408c75ecb0027176f2e6ee7a9cd3f7956dd151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003060ef4c1092f82f4627bd0256557b4aaee4f2ab3f6527500f5526d839fd07f4d00398248a4eaf1eeffabe16c4b77800000000000000000000000000000000007fe60dcfec1cfed48d952a37da1fb9911e75616dbb409c55d272fd5e4d6c5422ad7a9217347c1a206846a28941d21e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159324150f19f71a8eb856c4a47c02a6bb86f7f84ca73d8735220f83a87b3cbc4293884bc6e8c69c0445ca6d71ef62020000000000000000000000000000000002afcc01243813dade2c8428d411e9a1452f0f821f59d6b9c3c476f02bde37c98c5ef296ca8c477a1502e3a266555c911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d821497491361921dec83c0525f309ae4c9f0a8b3da4d1743d09824c1c05095e2bcb2a20f070020dee2d16468e9dfeb00000000000000000000000000000000075e785866729323f90f63f2965d25a73e66ed2484c089363e4a9a9904f8e6343829bf4462311be378a9426fd4598a5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b03bde49547b7208abf8bca3fa5ca0448c1b7cc50559c50f05e6eeabc9db567418571c42df0c488b9bd32fd1f2d84e00000000000000000000000000000000004ff2a46e8d7aff33d6111ce1e6fdba6f9c7ce1a29dc3d345251a56127f85c0aaaa53d7df039db3a1e6cf98b7becdb241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001858bbdfb037519e8310d95317133baa291d17e39883536db0fbd4053f586d6ff24e866e2261dba0fb222026a24f614c000000000000000000000000000000000e330f9e3fe74ef2f210277c5337c76fc2db293f85acaaf8759407436733aaf114e0f1c43ae45ce74be8c8a07462fb501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001138b90339b000f6fdb2a8507c3f76047b1bc4986d6b15fb542e053953cfae5ae4256d34250874868b6c5421711d3a5b0000000000000000000000000000000003d1eb30382166de541160dca09986cbf0351ca8497c43dbd11f523680ca8fad96e1b97964cea518f0329a440d1111101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018dae7ec19e7e13816d6ce18aad9c28b97cb452510117c11608fa60ca4ad30cdec4aaa39e9342d648e945ae6674da9080000000000000000000000000000000013e5c329012e31e5aabb4c5c9e6e8f6a173b59e0fab66616672caba5d75ff940241e2f2192e614d03db4b2285afd34181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001405bd97d0a326aec71bfb79cd8666e93fc2ae3c03de65e17da8118e6371ea8d99caa9ace4565f55e9d94902f069bb220000000000000000000000000000000003f405fa1903dea0ae421712b0302e689beb4468a6f880e9398515083babc76b0371f02a6f872f632c2db6a5b55f39961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193778d333502cb80b298659809854b2d5364628b0ee19e3ebecd015fc72050297dcb5caf8d73d28e88fe88357ebfd83000000000000000000000000000000000f010524dec19afdadad866d21fad76f5ee0b5106f4d3aa6abd114f329750bbe39393ab3c0df89b0304b9f2d7bf13eb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e249c15c5d45bf202828aa14ba91c9cba20596c3b6e3d32ecfdd042998e03cacecd8054902ca2ba5003ec7e0c7b0d790000000000000000000000000000000006e0d4a6fcc1911ab063dff8829037165b86b94be9e60b06793e2b7707d7ebd1df4949acdb7344a97e1c2b538944f8401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014df2092137b79d9d7bbcab97a8d0d1a85385645937f0aaa0dffb8deebdaac54151afa68847e9f50426a26481ae4e9910000000000000000000000000000000015506542c4d7be853ce94855c9b799ea9578f8d57098d326bbda687b21624f1087e5165aba36928fb83383adcbb66aeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001301d6655e460aac557fb7934154d1ede5f4471c093586d29953efd2b3d2c7f95f68d45e0adc23bed3eb9cf60d48b2700000000000000000000000000000000014d40a1c55263ba560fffaf03b2c959aaa2f40787a3720608c0cf065e4c5f5660cb20c0d5ccd913c0eaecb29521f41941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080dbb4d68500f00452a4368cb5f87e8116bc9a0162c77f9a3e8ed8c247ff5c0434bfcde5a5a664ece2677e1e31b0594000000000000000000000000000000001454bc807afb4b75e3505a0f888720402383c3cd65e06fa125cfc3e0d73bdb3437db84ffb94ad3686a59f1b7a07eacab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f66963f609dd25d96c8f0253cdb894c23476d117c84ca6a9d1a5e0b2b504644282b11f5563ccd00d15af1d659fbd8eb0000000000000000000000000000000018b75e0be485c28bf03f96e8c2a49dae9cf0981d3b7f74321ac8ea92686df164375205fb9c0106684ab8b74329d9d2841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7ac90ef43108c1bb73f20df68ba71b48fe03ef64cc64de58f9d859449807c3bae15fe42aa73e53b7c43ab484a3dc0f0000000000000000000000000000000016cc1bf2773b58c734fd2eca0c2f64c0ddee8a470bbfa72660d0b53ba6e8c19dfd358a551ab885348736a9df5315e7801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a81b6c01a43c8aa1e113796f7fb17a166177e78a3cb17e28550040988d15a3a7cb9c44ae683ad9fc16ecbb8b1494ac4000000000000000000000000000000000349662ccd1655875c2a856af77eba5514dabf982feb5e320c4d19f86600691116404529d03917d13f83e110b94949d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f6257ebc95205fc519dfb270d32728bcfbd9437fadf399980c65fed9515109f751714a2c59914bffd1b9c625cb5b4800000000000000000000000000000000101b77933d4a59b6a9f96f1925fe304b90598a36384ab3173497984f94a98246910a1a64e8b7f4defbb1be793d021fa11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c5c5120d7f88fe277a7ac52fd6b088009921d2fcb8de3c4b87c70ffef2d386833524502846adf992cc7bee5af858940000000000000000000000000000000018d99c6940332a3ff9a1cee7c7bbd661a21418e19aa76a26d253e81291dbf3f58b8ff90fdf5393b8b8ceb9ac29e137e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001374bd903a00cac9a983f21fb7d7af0fed9fb908155f8d11267ca12919a73a9f3a065a2914a3e9aa6da52b341910aaae000000000000000000000000000000001326bc136b3b99481747df7663ef9be2e5edad64062329379aa5a7de81d8bee3fdce4d5ea0f31bae6a9f6ef0a9cd054f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d5b3d1e854f14b7c09399d4103e756cd6b763b565338b844798491658009471580fbbfaa93234a62a67baf2829ec06000000000000000000000000000000000fa932e1dd1b9259c4963d2dbd1b8baad7ee1dca1974fc5d8b4195d6685fbce02e4dddc88a2efbfd4c37a964027fd9881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbe15975e117331bd3f67bef1c3984792d3ff9bd54cdd4d743e854e08f49a4b53d9995a737d2260e02a9f5c006ebb7200000000000000000000000000000000117b488f467ec590d2fdb428363b14d72af6eb2f4aa57d7082cb0cd0ae94230b55613628ecfcc3960818209a34b9c6bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011aa5cb7bd6c84703a0ac1b4888ca8980b825b6064810544b0a427da4e62a503e960d1cc05c6d7112c01b9f562ca86630000000000000000000000000000000015e6df709464517031c6ede36fd7a3c8e016df0adab2b965410d920c87d753cb78541debbe0109468fcc1868a09a129d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001981820ce5a9cd926cab53c5fe1fbc06a1bb6ec7988d63fc00fea4a19fd4d26bd7c2e79a5ea024d0538265169f7aa5b400000000000000000000000000000000153c675f6c2e8c90f18ab15802d9682947ccdcda7f8b585cbf01054e548982cd221d327955b099a39d320e5b221914581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037f5200639d1b9d206764a3f0e7992ec472c3925b85d842ca1568e57d1af2cc53858cb3f87b495332f9af764ca51ab1000000000000000000000000000000000c7042ddec8091e407c0184f0e886225ac468b1fd8676e578dbaab46837d9263ab5fff8df3438e07d245f8f41059392d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2d989f81b48de70e248066514b70f1802650707158115d7d80f2d9d83889cd9eafe7d1e3ecd8bc6735cc57cce9f563000000000000000000000000000000000e89a7ef8215bddc217d659a7865d2061b99a702a9359084a8e9691f9f3a236f53625eeddec98babdde1ef5ef7795dfc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a2cb5351f416e77d89a10880a81de7306b695c8aaac896feeb592c17c483074dc8cd67eafaf7ba28e40c924e34f0d400000000000000000000000000000000058342c8a066b34b0c8b84e3588b612b72164e4ea9fa8bbe12f222c9ac5aaa7ba747cb718517522680c1068daea10b061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a57154444792db7029a46898bf1998652642adaaa69704d5e7256624c2fabb5fb9d3730c817f9cbd4f0535835f447d0000000000000000000000000000000001c9797b58fdd44aad834869872bbc94acbb7d767873de0f6d0f57301d30f82f34d03dfbac6d55bb68167039d80557b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d6082d961f5e8c92e6d20ccd485251eefa1bb89a8131b73dc786786e76aa8cd785b85765cc0d20ee4673ce437f054900000000000000000000000000000000153029a976b9ac56105dcecdda398daaa2fdf59abe05419b8fae0c34fb19fbfebf8f093f250b587468080044cded618a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026736877a292b8d97308b02b1770bbf5bdd3c959635afb00ef54e72ff0095330da53747093821b76068040b3a2d9d030000000000000000000000000000000017e44e0d4bab9ea67f98cc482b6042e4738ca966c440927f7ac8044c6e4a7ffebbfbe41f098058f7b961836909fe88231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be1d23ab6d11f9ff43d92c274a584b5fb90a25ae5399f37c14a9d7b07c02d3facc194ecf7621a11ff0e602e1e84970d000000000000000000000000000000000cc9230abd2cfdda07ba5e1b2a9e7f108cb231d0ffbf06be4376a1cece9b7f989376482e5682d126e167cd26d71ad7a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175a629de9152fc2f77b341c062872f0db9cb8d9f86e03573c343c85fb44225422a8275c7f1311e10d4db216e16e46140000000000000000000000000000000004803ec7b5d515417bce02670d9a8a23f026b9a75845f3caaab6bdb00f7459223fb6f8ea76888667f0dc05a69e9475e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000511817419050d90bcd51fcd8913ea1066bc4319ee2e114ec87cd100eec2278d28db82767e5fdde3e3fa2f5beb4e7b830000000000000000000000000000000007bf3f989b5b1e8a537fe560a52dc025789fec731a498fa61b99894cb1d13338309f49a1b78947caaf5bb2a2aa2be1a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001079bed1a00eb25d893af30d4337581bac578a11c8ab81de4e3fcf446536925264be3103d0208edcd7ffcda41b8b2c10000000000000000000000000000000000647606a0a95bbba268f8b5b2c2208d25a3b0cd3075480455d8775c30311c8865694a50f00c915d667e7aceb9ad468c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a067ccbae5f18e71acfd43a7bd5797e8af6f87adf0adf6d1c5878998db8a9dfd10ecf06cfe36f1068b5e4a257f06e00000000000000000000000000000000001816bca0a2eeda3f7a8d2e458b5efd2199890751bdd7780a9c000b11ceb253ada24d266b0a58f1d195f5577f771747a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007be6d6a62dedf527ffb005ec4485092c683c0d2d23fcefe8bf802c7eea1bd976ca0094ae348fd96019b5f05e340ee41000000000000000000000000000000000c91e78075e8b55388caf2834dd67e627956e833f502c5df9faeb93d420d6049e53baf7de3232964ffe6156bea40a0681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015df5618e0709bb7e205426bcf2fdb2963dc58b23980b7b9090dfdc4a66c582be60eff275a4825b8138e61baeba317500000000000000000000000000000000010d3136d3a1b43042fc946cd97e5a46daf305a4e11e64ee8d384921472d10b9f783fba9e6972439b462a91043849ee8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ad0149c87537c68e6ad8ff78ba2a209691968a5ed6ea2def40fe7d2d69488ae19c24688840cf2d880c6b15ec9b404100000000000000000000000000000000160c3b7ed995b9d3b1d29edab8ea2660b1a5b59627a08f57c54cf328f6379d5ba5e1a9532a38b09a850f2abf117a38f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000277b290fcb8ef1381cd44297a1d3bd3a41e5fc0a6e2f69b33da7b924d487acc5c9048ee2157a61b36b25039d63487fc00000000000000000000000000000000035e64315e574cf16896373fc3f1667563735a8552574026bcca92390e74cbfbe5aa84f872fd8a2403731a0c6d831b591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019072d7addcaf9e8d1cf24fc1920bfab0a85ce1ad7157502b3c0a3c04f808a1f17f7d241469bfd2d5a13c2860ae025630000000000000000000000000000000001ff345f762be619f24a165db81d208a3bc005a01d96347d76c64551f830c4b03bf6726e80cec5999973dc2fe54bab561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000670f7b47e3be01c0d248f3981d4a87dfe845924f4d908c2519cd100c89db6dee93d229c42af80bf2a05cce8ffa6370f00000000000000000000000000000000187ed7213a20a4d720903b1944a2592e8ae25914b9d67f99762427c17cccbcd512641001b1750cd19c0404ee36e88f471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005e6d78d76356cf2190879248a6cf520204f147b429bff70141bcd8a5faaeec86993a7a9eeefebed30fd9744fba466b0000000000000000000000000000000004ea428181993b93b472062347b1c977e797cda1baababdaab39cb6c6eb2d1d3718a654f73e7d919ea505423727c03d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093ae2a1ec4618c4b39800e6abce822f8cdfb991d0eb6090dc0a6c6e96954d651cf974addb619ba56d3251de6e3e2a81000000000000000000000000000000000a70348af1dcf1c1db01721a0a90b26c3c63314a5e67e93bf7bc9872e8d5ca43300648346248d043030ac65abd404dd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187ef916d050e60674d8409d5d89c495d4db271725dd5740551a78ad975af049450df424f7737167f4d31bb75e4da5a500000000000000000000000000000000054fcbea4998f2df6c510b4c3e41a50d05d9bf8605b01ddce218f63d4c4854c6e81985b6b97dbe368b4a983d5f9f29b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ba3f2e8e51c2f618b5eb9f5aeb78f9ab3e2c546107feb8c09eff9efb56c8321f2bdd726a830cb90f3a2b0252beeded0000000000000000000000000000000010af855ddb859157b11279a6abb66abc6de67eea324de819bd7a6cc93484ce89a4de969c87dd1ebeef78bee0f24565d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018eb485365ff7f1fa6b842101eddd76670444e5b9908c3dc6b2968eaf60fac66759f05395d4090b99f9f69a2ec1bc0af0000000000000000000000000000000003abe1d5312f38a06745cdda9e193245681203fffc3f130bceddc9dc26743dce701936586fb755521c5519f8471433af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6c7b6ba73ff633caf970c83fe1e3aef50ffff5fccae40d52de02c317eef50a57bc4bc92fe7f4d6ff3b60686dab92a700000000000000000000000000000000193b6b799057ead3bf52841a55a94fccdce3e15ebab7f2b00550003d78df067987d9933d43d6543679408ba68ef66b321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000013a71634ed6320fa0cdd18a78d39d3c1b2230efb90ad4e6e6efa103995d691c7bbfc131caacd198a606564af6b8c43f0000000000000000000000000000000000bba692670a6a6d9aa297c305d7576a438667898a0c121884d652c7edf991d4e0e914d651fb0844fb5a2088fa00fb531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d54d53a051b0c590420887116085e1842fd9a48c6d77d546ad12c383e59bd05ee86b9bbad29565bd053f8e6e4b026bb00000000000000000000000000000000027a2264a9eef42e1534b8aa48d72b40c4ba5962472228e35efd52e3f2b8c22a04e3e425e24b7dfa4e02041780ecff5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000058ef6d2d2a3af97081d0163a1e0baba0d4280e42b0e7483a81342d72faf731be8c0c7f2bab0b418b87862a24a4e249000000000000000000000000000000000362a99fa453dc0c348233f0f04288a940fe4ea50b1503d46c2c80293e820f8e2d1a9067677708d5491b67c1fb6723bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc96dd8caea981227ddcb73f9c6a18e0394f5e9c42a89f25a993a84daaff24d1652e9dfbb6f27bdef3183bba8ddfa14000000000000000000000000000000001111376fe8f10a1e11310583bef0266667ff3a5dec59ac84d38f8c5f1a49621ef1b6c8267870b66acce1c32001407b2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa07f9cbe4aca3e884423f35ec8421bada2545c1b7651451e884c1d5da8bf6e93b70c0336d7b81c7ddbc182df224ad700000000000000000000000000000000050e0772cb72232d86921d21300c1a072dc00f570a6a2b4f734c3b8adaa1513d5becee1f3e4be4fed7b023e6e19286d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3ce410c7b4b37e1fd076937d3f72a895c14bc278e211a49be2a7751834db4041563830151065cd89336e75c987033b00000000000000000000000000000000159baa0142037e38e8517cde6e9b7f78f2edcb6b1fe0ee877ecd22f22cf0030fd2fa213c6213416751c606dd7bf9b9401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccbb81e72c037de8896da7f4f7de007825e2b6491edae347707bb0029b2431355f4be783d0e6dd096ee49fe44a797e500000000000000000000000000000000011d88fbf3d25d8938b4654d7c7227913d633bbee3cc6d1a5a199aa9e414c4abceea43aa4146574cc0e3cdbdabf2d34b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000513648c2d6e2204edf40dc93222f1f5fdd6cc2dfd10a0158a20ff7b30a1bcc47c851e427a19eb07d18c6e7b118e3bd0000000000000000000000000000000000a7665d23bac858e716dd4d562d4d4a42c77810214f1ace468d013249f547bf0b9cdb4950219f47d5795a6788035308e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000268df8f7fa56c6f519202169f5601cee1808169b7ab63f430928e2db4b5a3d886b32684858f3e3d50286bd731f51318000000000000000000000000000000000c5c9a7a75b5880ff423921675b48ac071158f5f60180cfc61fd965ef730c65fbe5a2f152c188498b0229d5798f96c7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000777c87060b349ad985c877989c718a4f37798a13c52c9fa8a3db7177211de5e6dcec72b977f9e25fe0e58ba11fc7abc0000000000000000000000000000000003fbac6fc80f34bc319a0ebd4bf999a4272970c980aa05d5c5c7006cc27d62b9accbd9df50adaeeead30aa978eddef0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3ad6fb16c0b31d4575289c7e883b9d724d1c76e73cd9705813b0518870735b959b5ea3959de57d69dcb1d9c0ac854d0000000000000000000000000000000018572f4bd4563ed92091fc11389ea676cc084c97786c2b765c0b7097f158e92112b533c056f8a394544b35301e458fdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171f6dc271611b27885a064d2f3227b6a5d2be3f03f879bb3ce51e76da6a86677aef505a154fe290f836f33bf15752800000000000000000000000000000000015ca133a1541846c899300ff3587d22bbd3c2a678b3edab62a1e6cb765a6167892f6c2b8929c1f5f9721fe0685a58d211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f59f626e49e5abd07cef524bedc3550090f1c166e0c1a8b9d81724896df1c7fbb074ec896d9079d153dc08f768773a1000000000000000000000000000000000f75a2429c6838a58f311fbb03502968c19eb092d770bb834f0c38ab652ba18fe0152d43b3ec70eea02c619c45b91f8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3cc95fea0a1be5a2773b01f7c35b04e24590d206bb23e0b8538de1827917531f2134a8c2ae9213306dae150b4fa62400000000000000000000000000000000035d9748285140898c34c99d4e5054268add04d1d02c6add3d1ad87eb0e70eb551fb6f682170639f77f8e384d751bed51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001875c68715f254eb73a0d8d9c4d174ec49ca34c3e539594b2e1b111cd967f908c1892ad5c9dd652f3081172ab94c00db00000000000000000000000000000000000bcd4d859f032503e117d37432906d385411ce82761f1a3e5e991912e43dc0fe3d3c37c39ed9d9a8b12b43beafbfe31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016fac656894ad9e245c135530694d0359ef129607d8c5b9c0b0b45a4f9370345f0d6574bf8a1e59d945f1672702a4b880000000000000000000000000000000019b6d4d205a6d4f16c1a5a4a92203713d4a9d3cf6620d1070bedc8c46c27d81ce45e1f9d0b815e3b74d7e0d2eb97677a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a9ddb4e0d3f819a2099abb38e74949027c96b878386076034a9e70b99694ebb9f49a09e6dfab1483328252b1c4f4bb000000000000000000000000000000000a97f3855553d628abe26b228152a96612bf243996b0f3138ddb81ebca8b784d6c9011d7490859f40880422f6c02f04c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040bb10d7ee88b70e5a5a6d0a3525b0b2792adf9525e78126f4c6e9d3c83be501cb99087180f08f7f3dc32a71ee00d38000000000000000000000000000000000f8d38e563f4ea7670073820170f621c60281b38368a44d13b8a21fdac7de1ce7e5fc6d410498a6ffedfb83ee82f850a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc92969ed4603cbbd19ea5a9826ae45edc05a56e8a8c1bcc306c4acc83e2595a74fa0ecf3384f9719038370b2fdb00500000000000000000000000000000000059b3ad11d19cd6c1e236f4c9d5c712715b4219d6ab6349b9d2490a82a23a1e1a16a6d94e457e12ffd40a55647413e991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108a2993a55c9bf059786adf8b23b0b59f0c2a9b6d2ff200359f9378dd2c381728d753f181f9649f93821a3b1b22b7b7000000000000000000000000000000000b0e2c40634756b24bc4a5419c6b78d640fc8752fa6279a2517813a0d9587bc50bb052538a640815349202d587069e3c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b69202a9513913e34759b04f9abc5ab86e325b9313898647cb722cb67907bea4490f94c8c0451de4079e524a955d9300000000000000000000000000000000142b36e6aafd2629f5f71d234d2549c46ca62582cd25232db4faab388dd68996740da5f7d4aee990187d17d9d2b86af11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e903cd3607beca550823cacf5bb25e6b3aeb098ab383e04f1d1e16e4f576ecee7daac869b659691a7ad2b06a32520dc0000000000000000000000000000000009ba5dc1e11a67c56df51a27cbded5c23c3af496447f20f4c493859f16cdf2c18042fd0a86ab94c614fc13e7b4b1117c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e12b9ad49403f8fd114f077208e1d966721ffa3bdfde0dce1362e3a47e6f268b55f369553f762f95fd749bb129b2e2000000000000000000000000000000000991e85882c1456b2882f8431df90c422a8a969005e6aec16d5c9f666aa35d2944327e8d01b7f14553ebf65a8ef619051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014933ac10182e37cf3041d7a14d2ce736167555540f86fa2c84162d75004b1342c42ac0398a6747b0e694b21a74371230000000000000000000000000000000009c09e44a0cf2ac232a7323fd68896176595c9ad0e2042e476c0f34451a52500ed41c564aec8548009daff29a73451511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119f64273c6e0ff11bf3c8e7e66fe1d48cb2fb2d3f55a6a0915e8e8159772bbb239a504771dc5555c3fc7a9cd341fd8e0000000000000000000000000000000019ded20f8dad5bac309c9608b601dfaf4a4512f07496fea84bbf5ce85b86d05e644999b4b5c18322b12cdc2305a6909d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073ed8b7e60ad6bd49a0397f3e45e645591955a1ebc239ffdcd8f51213855720ce4fd84c778edb6903297a118c6429ca000000000000000000000000000000000e6836dd05b8a52ee9f2929f7c406a1bc87f6606e72d2bd119c514f816cdc6e5976c38c2311eedd4967b97e8997bd1571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001845685f599467136dad67cf8c0d5d456f8eb46d208b8bb3694664583b3596c52166b370e12547f60728cf96cf404dcd000000000000000000000000000000000e6abbbb93626da88e5b73b71aa87a69d5d42d50086b03ea7b2ed2e1515814a7e2e14290687b5b90a83ebd72616c8bec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199d1d4fb3ac3d96f0a296a668ba00077f8c907d9e600b1e8207ac19493d0cab9153a6a906745cb067f60180ca6f977700000000000000000000000000000000034af3cd8be9d7208e09a5397397f866f2f7f1d3a359793eede42b0e1fd6f1290b4492f01bb245b30d2c0ca7c561d7ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d27bde0b186d027b1a38ac5cdb5f81595ad2aad5165afb4c1847eed5aa705285c3d07546225e021c67232fe37c986300000000000000000000000000000000011c89fbb17895c32e51aef8b9ee2562296bfa7ac6881a2ec880481a9169e257864660de2b7f23478fa76faae2086f281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040b102e069101962753068282b4124ba47e667f890623479904a54304d33db3c297a7fe075f7382ff71ea1f53a546ea000000000000000000000000000000000f6198c132e1a85ec743b23c8d0bebeacf5ccdb709b7f4f5587abea22a5de212f1cae7d52c243c48b14af821793b5e161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014ee325c09040132ed7404091a89beb19ad73781e401cfcaf88f3e6f52147e8c5eb9ae9df9b904aed1fa6576010bedb70000000000000000000000000000000018d4d09fa00ea0bbb33ea9d9498afb405426d5306f4edad5ded0d85230e47656611f4df3e3c7617fd5116e7b556219761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016837b7d12ebdcfbe52ae077d7d83cbb1d2e6d50979e60b4811b4ba3a48fb87614fe874367191872a76e8cafca334574000000000000000000000000000000000c7aa0b4e859b4a425fc50b0024f5127f357da51a163063e375b6145367d73a228a1cfcdcaf15078b97a5f52e58a67f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006788fbb0a4139dcaf5b36da3c982d06b86adeb0ffeea53d5ebdd059f9ed65e53be33aa61b90fb6f807bc350a5c8d21f00000000000000000000000000000000126b61daf11191f0d2dbaab4be602ccb4b3571fd8ac5c55d6a3e5dcc29b3077a5e1b5df393e101c921a4e3a32a5188ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002414a2cff9c306e0fb92319b60d01f70c46e7aa503e1b508f31ee249978c6d8864450e13ed18ea8b2f909d5b504ccdf0000000000000000000000000000000011bfec8cdb4e3389c87e1a6cb4b11d086241c2a9b8c812b43e4c42cd98b53a77115465dab3913b0841cc87d156aee5161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c2432ce6174853a469528591df16dcedf50f8128e8832535176f76f2ed1a4bc574ee87fb09ce3b13be24ec3b03d9dd000000000000000000000000000000000beae4aa819fdc59f631f486f8997dc881f54aa97426da0860069e624823c7c072074eb811a9c2ffb0b63cdd0132862e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b414cdbaa033c2ad06a5d56adff9c0579e537b7e14c3389895642b6b6bad9beb277e274b24716f66c780edaa504e6b00000000000000000000000000000000177776b3e2211fa1db885d8013b04859421687e2eb8ff171c4afb645580e40bf3b3082504d8c8c4601e23c58d6bb3a601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6aa32424487fe942b544a5f2d4800dd477452a26ca9f8f8971bb64b3188b7ab891afa3c5c62aee50ce561f2523e7b80000000000000000000000000000000003a8b9578524fb9f8ef4e2b19c43e8a46e1572e8689404f10daf74d7c69984d572c19c3c7c1bd34ee9c31f7cd694b2581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c803bb1d3332d208d9b03c558ee18ca1df6193653c5b4303819bb7d7e3b5a84d53936e07741145287f2d87206b60a300000000000000000000000000000000113cd724eb81d728b7898814737ffd5b45f9d657dd9520b78245bb29e8ef6bc7ba82ffab9ece6a6327e41fe2e75443c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000089911369b0ec86ba5cc45cd2e27ddcaffb0fac52d1eab834771b3d3a4785b37b68643c19781ed987d29a1f5ad453b880000000000000000000000000000000015e6e5e7702f1f80f6cbe838084fdd88769f715315be921edd2df6b81662434342c277fc8ef65c9764266c8a914e80c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069d852cd5d8ceb22cdeff2163a0f273e04f92db160a98e01c4325d5ea78dc8b7687cf02d112ff91efb3fdb56e775e9100000000000000000000000000000000024d03df6337e86715911f1a0c9217395c53c97b15f2e1ac3c12c553193eae8d7eae489d0a3c564a06d431c83f3da3de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8a35913a0e359378f371af5d0f3152cd5640cf50e0972d0c90aacf60341b04ddcf86548f3f63870f169a9e6c1b5b540000000000000000000000000000000011a61784f00d089918c68af8e2ec3893bebbea59db4a1173d54b16de7839f237aa33de69b454af927c1274d74af956231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117b9752405efaffef6c7088a2dfca8ed00f0875f47e9f4a0f9c67cf8bd348f75f302d9910b813857521814e97bf5eb5000000000000000000000000000000000292a121cfeec3f134fe9abcacae7feffdedbb67520d9bf3147d8d92e39903d1a63524f9cf2a1f461678bf1ba5903eb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003dabb132b3a316a5c4ea0febf7cc5105f668779cb0b9fbe0de85ea37902dcc9e5c56416d3519a7f5abdaa1eaa0aa1b50000000000000000000000000000000018636b2e95a5aa1c3b19757d034afa502110e93ac937a41cce00e61d7e6c75816697f983fd6810f9099bc904086228ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000011d641b383d7af018e07de39d1486e7ae5fb9e2f65017c8c17718d48985cb4133a66893a67ce6acb0fcdb7b226ecc030000000000000000000000000000000007f11c42ddcd5b7ce907fd8aa8d26e1fdee1ef752451c1616a4e2e3f0cf4ff080ef3a1cf7af65fa1b5379baf340908661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000096f5e5b379b313b7301ca5b478e98bc603a4d3a580ae5b7bd135923d2948ce212f03dc9832b12a9df7626b0a756ffbf000000000000000000000000000000000c2b32bea66c604a275fa115a9dfa5de9dc4c5620cb2fbf4321a3d9aae180e63e9ca7d9faf5e392fb9d408527dc3269f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff9cd3039fae087fb1bbb7d6d12e0cf73c2b5864ce9843f7df37665ed6299feded350da086abb468da154e70abf3830000000000000000000000000000000000b5c720ba293ecfcdb0e94470d8c3553bfe22271a194235eca8f1d60133bd3dd54f9ed0d754e032a7bdfaf7fe99800bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be8da433ffc037f97f94d6c6cb1cd696c49c37ee4698e29875417ac427b1ba75afc32dcaabef073d8ef94796c781e200000000000000000000000000000000001221d03a3a0bca806bea4ace393b824f8761fb5a669c7e919fe5856083d140a4c2202f18c3c0d38d25e1302838400d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009dd01dc0ecc42430c176d6634a4f4d68d99b5dba42810566e85c7e485286d7ee88ea012e40c47d039fab6103dc9effc0000000000000000000000000000000000270aa2a32f03ac705050396829e343acb4d1ab3fdeb867f62b9a309484174530b77c6e4dbeacd8aa27109ade266ba41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a4b27b9982397c7bcf7a665befe3b160e708b81fb24ed138eb21df321a424dcd2aa3ed6dbf7af369045b302712668c000000000000000000000000000000001349f5e4936d730960e6dfb10fa00e4c9c53052aad9b13e2def43a3ddc6b31aaf09b3ef56a08a74d9789cec0ec3c506c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052bc5d3c971e200e845e89de02af916e1a232ea30cd69ca1db22d2b958175d2db1b38f583ea77f85e5da8c4e2642e710000000000000000000000000000000012ba5e6560e7ddd8d5d78845f08e570ffbf22f68df79333a4f133939157e7962a49179fec9cd4e03748d5844ffa8a95f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a4e15ae507023d1cd89f11b4ae46fb6b9808ced455254c6a9cec276b0a6a248661a44b84ca8dc91292a35d9807439d00000000000000000000000000000000177a39b719fe15ed797baa1ce7e33c5a3bcd71b1d647d708f3e62e85e95acd142cf7ceeab22725801ae87e13189c823e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043643e84f5f29e50bac5866a487b513a0c4e75fa9356a287cc4766d12f04b13f794d3eaff2ed3d6df5ca12fe48fc4c4000000000000000000000000000000000e64e76ab8c59c7fdf9be4760a40187e0df2e5f1e369be791e182070f53faf5a144685e36d307346b3d7b6a04ae213ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001170abb6403d1e138d2ff7aab7d5decfb076b619da1660fb9e237ca96b2a850e8b8bcbd6a5cc931f568c57dfc401158f000000000000000000000000000000000acacc8b40e6bd476ad8dd6f4cc658f952e065d3921e335c7de80d66521a821590259ac196f42b6bf4dd15cc187a59161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000883ae630302997b8e92a47dcd37eae5f2870f76a85c34d034eb2bc3e32476f335871146a8a176969a051d2ad1ca9748000000000000000000000000000000000842c1161c8b3b0721c88105fb0d6cfd6aa83588ecf6913aab2ec14be69cebf44701bf603d8e141576a0fec48f6ec7ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033b220a6f2a407d8b3db401179d09f39fc8b19cb82078ccb2fd08fe0cfa19f0a7867b09b89668f7b2087a23496c2647000000000000000000000000000000000d9e383b599c1b9b135f7b860b157d0422a1b0ea9687557a49faf5d873f08d59d9fdc55461bedb1afdee2a33ef12af2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5dbfd1c7253bf2760fcac21df0cb92a8aa896a4102fa691ebf15656c836cc534c9493abad0e402aa0adef6adb61122000000000000000000000000000000000fac9a6a1906d0818eeba8876b2ec0a83f49a91f6233d0696fa66e72d292d5c21800260f3cae6fa279b36d062335ad1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138c31b66ac1da0e369a5335011246a217548126ce818d1dd0d8100bd5b4340a53138768dea6364797e3ac7da1aa0f35000000000000000000000000000000001846d92180a161af03df383985284b3fdd3ad35c0b577658e56bae74fab06be2603251fa7fbff5901168609797d783e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139c94c8d8098411347b27652f9d42f4e214235639a0676978aec6d098d4828240d74dd74655feb58ac65f69859a7bce00000000000000000000000000000000064bd993ffbf86d08049ea63376125dc5460f07a70ef2fb9c8551f12f8554c0cc232cd1401f144745612b01939f747dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011380a7cafe40ca8e1ed3a2839c5b217a3aca3ad7b33625594e985ca58182ce115da63c752e37f66c029d9b49faf2ea40000000000000000000000000000000010d03b5bfe5cddea5b1bffdbca496eaa20cb9c551cba27145be5e1eff5cc73af530c70c1fa4fabfc2d565119073095e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195edb05eee8943fa8a62c94e65aad4da45fc03a315747e012141022da5d2d333c1b87ef029ed8888011b47ae4cf53b40000000000000000000000000000000010593b5d166a017724a7e8ccddc3ca0b56cfd55b7ec143f091f6b214976c7914400224046d823e6da87a59dc9857c6771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b64ad58fd04d22278bf4d2bcab984f46668f066b131bd1bf0cb1fad285987eba64a7ced070060e6f7aedb70aaccd0d000000000000000000000000000000000e88777d4295cb4f9102af1442443023b2174a9318ebd1af0b18369d413e1a20e86de219f0efc00efafc5f15faddc1a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e9b4a7ad446e953f5d95790c1b9503caa240b94b59002a364f2936c09eec34af1ead5e99b5d9a9cb5ad704450ee9fe0000000000000000000000000000000012d8bb9173c977f2ab3e8eb25d159a95ebb5e6147af0008bf46392dc35d039af382429cedddba16ceb97cf98d08e39471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dc81b524a6aae4a757191664b3c0b0b8c70bef533dca813f862daad51bdf10987e79508e976967a7b8c2ddd8def6260000000000000000000000000000000012e5a2d1083b46d322c4ea18e878415731078663fc034baef37e917c828a32cbc88614906f3d59e9087bbecd51f5ce361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143ce154c47f7e88e11434e5cf0f8f0c35fbd891c5a6f53fd5d6918fe674a80f6d3ddedf4d20ad24d61d21a2c32d5124000000000000000000000000000000000679346665be5a70b32fe3d9013ce91b3498bdbe06ceaf753e47d2a000b28f305c353fffe0346d82e62941cc48356c0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000143e92530c85a6e8ab458774a61807ec666d68005f1bdf3647a6e1bbb864bbe937abb693a6cbb48022fe64a2ca1ac23d000000000000000000000000000000000de9ada2838d974a599a8285546f0b9ab9d8f18f30b7f13e9495461e31b9340df6786dfaad1a92b2f43d2801ef41b47f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd00035ab7c55665646c55292dcc66610cb469cbf8ac75dcad016da69246eac903af5a24fa2c83d4747bd2252b457f60000000000000000000000000000000016387ade29a0dd23f86221ea645e3d4b444ce786cd8b9b540200d6eabd6c59a488a62526405405c263e5f8e6383e0e6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bcaebd6cecc3472645ef0c54d3d80c63948c2093043c2062748b31e680f8ebb62047b34da9b435e627d030ff740750d0000000000000000000000000000000002a9d3a722e3aa534f544c2c1cffa5fda027dbe34344d2be432d8ecccd557fecd866c0adf747e2c20c42cbe49e1a7b991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008cb26b71da29b7422b9f5d6d7cc7771988ce7e01c04e0453104c177ee1f0ecfce5eec5415cb252f28636a70185657cf000000000000000000000000000000000a7bddc22a31487057f1b5f461f0a3b4003139ff51c05e386e36481d0527b5094c1a469a5b6021faff594dce88db285b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2f0dc367b5a4fa5ea6a00e0d5531936b6f2897b026ea418dc3c6cac4607f9b17576ea3f87a062c67d17e6574b51f060000000000000000000000000000000014add8a8d829dde6abdd0ed62eb2e815ccd6d7790df7399445fdcf2defd9665786119be0d110cbce16dc2c89236aa75e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006dc6c77dd06a117efbe0ec4d51ab491094adb420a2f3cfa6caead0b3d8b8ab9caaa25e782521abcd07725367098f8df0000000000000000000000000000000015bf93525e4be9fa4fbf55cff1edb1a53e018f90f6534735e6444321f6405af5fca1459bfaab9c751f9150cee56933021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008fa957b164db4c8f426fa42989a1deac8edcba231b49c736595d6b7242dd3638e1bfb7ab1b4a8681a6f8302307dc29500000000000000000000000000000000081187a22952ad0ab4d397ad4d809e536863f888e4e7d843d2fe67d4ce4b5d7f673851f1d8b70501f63226211ddb540e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a98638ddd8ad888a5d1d237eeafde2ec4313df5336d63ef033f57360d334c2984d1594afb190972ba883d2ae8838d5000000000000000000000000000000000e39195a92bdcc68cdd0d3fc8557adfb3e9ff200f26cea133099c84db24418f768966608ab0fcb07b3652937fda818a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cacabf315a40a6f03262725268d659feb28ac9cbe8f6e55429f8e36e6617e03156ff8305eb32cdbd2ba0d002d23bf0a000000000000000000000000000000000f81defe89ae810c223ae455bceed16853f5bea0a1ad30e12d357674bcfb54d11edfa0d2dd851e0f10f875ac6a9bdb6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d389ca5575e17047b573f98f12a742c13195f5fe7febd6109c9603a9951c8e8e46598615667ff2268dbda39744a2fc0000000000000000000000000000000007a2e538b44dc6b077b02224f90c82305660fdbc4cd725accf414ffa23903a4d04fd23a6c421455ccee419658875d0ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026c6de630499f97ae3c613078343e5fdd83d0f8f185f7d78e2a52698d317ed5b9a478b5c5661500513475f68544ce170000000000000000000000000000000003119b1f9dc9a6be7a1a0ddfeb2f323884c2a84c2636d6b584e01650ea08420cd47becb706286177878ebc9d291a2e951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a12489b1982d5f435607ce6348dbc7b53cdb3c287a579264cad11a9188cc04b7e15b1c3bd1a59fb350a5d5fb3fd3fc000000000000000000000000000000000671a0e265f44fbf8e1fafb4a7b190076d8ec6b541406fa96003f60bdb24630e7135032be49cdcf3babffde0fa6e63f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003b9c7f582d97226549831f4733ee8e00339797af74344c615ba5dcd1058ab32846105a75c13e2d799c63aee1ec46fbb0000000000000000000000000000000006860dc1d36bccbbebaa61971ac2bfe8c31656df5977c7b70454208264ca67e3bc95fa8cb9fd1fdd9fc2d0d4563a4b2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153050d1942c3f00784dba283aba7e8df4850266523d83a073f057e9115e2216822af1864473d564e3b447e258ef1e9b00000000000000000000000000000000004d46188c4a7176fe28ea1847e0234afddc06b70541a11c7a24b340e0697e0aa3149b6f128b166879042906c8daae9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a24d8ed7c9d1fe6312af518e116c314e9b9e47c4fc83ee014cd96f6349db28e261246ea9d1f449fd68c5973d7efec900000000000000000000000000000000153cf2081b083d132db97377da31d6f7f1c9037919b8a6fb081581ec8fe1c0ffbb1ff3c3742a9df481e8c03dbd1446201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123b5be8612689fd54b7a51f7e8a59112b80037eb21857bf36511a111dc84bffdfa44a24790713878ba695f61a33881c00000000000000000000000000000000150cde68f4574cd1fe59d4b564238726dc47b85a632d4255a2099fe9acac32ad79fc637657662a7781de5b386d5e8b511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000201963a2559040627e3319277afc837cdf41bb5afd0c5e7bf2ca54e2fd3ee8a3ed876273f73159940230f71b242939a0000000000000000000000000000000008269189cc7805901027cad209a389b2bc874c5f3c1e9dbc202ddeda38cfa3d5c4a6f0e76d64c9d197ee8733e5a2f8371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d401071d0b8a04e9c675a63eed61a6b3602663904819f1dc6a007fba82ff6114f462d670b749303f60c44d0b4521db2000000000000000000000000000000001024d6295d8ce1827340b93d6d14ac47cd9894a7e4ac1c98e1e27b2f337a52d4116fac1524ec8f53c78d649eeb2bc3d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190afc05e895036170b9870a9e1f05b179e9ffe02e3fa4b017c89614b06c261a4c07f97d5378bfa6402ff98c7a0adcc1000000000000000000000000000000001296b02a572f5da700f05496f6083c5374c936b2ddd2eb9602e08ac237312856d37652dd5680d5f77d865c7db31d2e5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013fbdec5990560e72eeddd9ab2d8938056fc1e2eb3ab0b6ba31031147a888425f504936daae6d7045e94060edd72c6c90000000000000000000000000000000008d19fab6ae96b8b2df46e3207721e06531b61b450ff8eb0f06de1e5df6473bcc10ec9a466915ebd390919ee09fdc4c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bfeadc59f2148df1fff4606ec606e5d8c9545faf20976f789c50214fed89dbe830c6a8d209e5ac1704304b0ed08666f0000000000000000000000000000000002de702dc49123c7742b65c981da898e94da26e4b4bf86a9111c64452f68a2daf45c82dd8b1e75ef4f67e4153a15bce41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017754bdce925f6e10f51673621ead49e83de7d4210137aa0c3b2acffdd108bf3115a6f45bb0872647986c2eb6d6a6f6f0000000000000000000000000000000004d817aeb2a67533533b6db4d3efaafb40375684cd92ba0c69f28ea045c5a8274da3447c514e30d32044c21a60b71a351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042543a9fe1871e9d78807dee72a0252a160e44495799b2e0fa92fefae95e663814c3d5020fa35093155291fa0c4942d00000000000000000000000000000000028bbdbd96316a5c3418e8c9beb229b557bc550409c1efa84e0f8d8dcbca790dbb8ae396ef3b217a59ed3a7467b614661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ff06fce6692c337abd42859b64920153887d1c73d4a0741f858d9a69f0d78fb44422288ec685899740c1ebb99d79f40000000000000000000000000000000006ebefc9df44d309f642eb4641525169492c72b6e47a922b11204057678be15e95e435c65ec065eca4502cee7cbb22781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006755936219d369b896474f39d14f2100b913275f24d28e4b6c815bbc9ee7d08f675f9bd6e23c3708b0ef47ef26f9eb70000000000000000000000000000000001f8b711e110fe63c3e843eb1ead42bac16fdd7651e2b12bf7b2172651835e941ce098576c19c1e4d5a2ad922e3e25fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000046e9af65139407e3ca011044c41e76fe4506c3d435eab9c808166d52db94695af0e9d52653e1f7cffe15c89449a674b0000000000000000000000000000000014f225c106d8231724ef4d84cf1696c81783921e6698d412f1d63a349639737c5feb050bb90053a33602d460f1261f051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f4eb1e6db912772fa878f42912998b9a4956bb1313b4755befac36334ec70b7de2f683ae8e03c122242a1b51ac3c8300000000000000000000000000000000094d115f355571334c0475ecfe2a1af05aa7f32f96a691bfcb6ee56022e081402e92a387767eae0307003f5b9a392e121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164fb59f18a5628acca55f27918b5361edf348a8b733656b4fcc81fa220e672adb9d01be1265cc6d4a8f1682182043d300000000000000000000000000000000179c954c9a3d9230e29e0ab589be535b65d837556aeca8896e777e7026d9c1a5c68eab50c7dd8676fb75387d2b64aa741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9b0df0201a0dd3007e8b8bd1c6dc0a1ae4d97a1db5f552d7e9ced5cc40028fc38e677a870f55714b81886b6bdaabe2000000000000000000000000000000000190bf5fea0cc427ba8202e69481e242d1e538efe117cac1a4df0737a829c098680f7bf087db3d1f17adbd5d5cb116201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000bc1ff16c8796c70e1c5246e135d854ff2156236d01a6579206fbea337c34869f1d067dc18588100a67570cc9e3a4d5000000000000000000000000000000000c9694089a63bee85a314c0514f8dee88dd570524d885790fe2e61b9ea0e864578431b18ebbe376e429087a267c8dd631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dfd2ce375e96b14036dc540ed9f7c18ea2c121b0b4124e904730e3caf3e2b37cb08d6fb6f32d9d24934c99ef22c6be40000000000000000000000000000000007f83abc46e29bf9c4cde4a014b9bc08e937d8a87359914c4e2ef230db6c8d167fa665d7daaf2357bc30a82072b1b18e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173df18946b98b73c8bf8a10964d8af3b029900f4c5d4b18defa5e94926006655aad2cb086f738752c9fc66870f7d86e0000000000000000000000000000000004bc48ed518656cd62ae5a7ff205347a45f349328c546e066353726a2eb33aedc6ae204f68f3b693593802f307a118bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118c567c53b202810e7496c2a9c9aeb94f41c76ca3e440784a5ba33ab54a0ae27966f8db16efd8e439872166e642afb1000000000000000000000000000000001816b32254567a4b74feb7b01e885994ad7b4d4b5b9af292ab14a478527ef8fb4dbf4b352df0f86765d778cf01cb06401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2512a7e313a9f225831445193d450986181bb182b4b3e8d02ca46c36d9fe9421b8d9ed74e6ee0dfd27d1ed54c2c36c000000000000000000000000000000000fcd56e3f88a91be248459eabbd6110935cf01a60eaa213c9b2aa89203059154b4cbfca4af201809649d13675edd3cf41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001787b7e2d9406442d8f8a407bc1e4f038808795a2855bf0933ba4ccca3df79f2f43c3c18ae79aac9d521e159d30ad06d0000000000000000000000000000000001211607289607bc3c405d73756896b47884dcdade02a348363ecafdca5f53f4768dbea3b429b59b8bcafee3c73fb2d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c424d4b0f011ec400149500dca7b5a942247f7e7e7ee566bcc52a40311e169cb85e804959be2d36cb05d9e0ac8b2557000000000000000000000000000000000d297a1b3fa0b811bcbbad49552f26d68016a4d3916488722d877968972e160906eb28e8d638e8132476425747359eeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b06972916fa0bff8f5473cb0102e729aac7914c8d74f8c94b538747c31f2383fd4d876932e74aee52f86ebee79d36800000000000000000000000000000000070af831d3b1e2f8e303b7b82631f56000814941ab6db36e82e291a1ad43710bc64e12ce3d402434bb9707eda73087291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cfa731c777e7d6530c836ed98582c23f8fcb931feb3f3c506b8a01a5e583e0e538e4385eaed7c11fbccd58a3f9c74a000000000000000000000000000000000733ece5d96e443141b792b8f3de66149ea84dfcddca412b6d1f0c205d969753024cb7b464d202f1140aed3eb2979e131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fb315504f879ebead938710b9a51626e7bcfdf9408f584bb6a1f85421bad0f227c4e0924d8f3ed771ecd1223da21130000000000000000000000000000000017f8e4eef94aade0e3cce2a07e22eb318663f4bc4e716ef8fd46f323cc6bd5297ea088f664431bcb129d8fe4b67cb5191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a217c3608cd3e40eafa9f7665cb910d4fb58f317cd6a64bd433652368279ebed63a092ec9002fc36a021f8315e0768a0000000000000000000000000000000004056d9e4adb46c9667b123e6a66e53be0dea549d543f97566def03357c24307578db03871e75329b44dec182f1129ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af4a323b0c7708ae28c1754fc925bbe8c10a14af5c9a1427db60ff55679023d264e9f9c2803f92572ced913be7f7d7200000000000000000000000000000000195211e7386cd27b0e57d7718392a09560c7a81f255729d97b156dbdc4061eb656d5b265b4c49916e2999a6cf7ff08351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140dab8016f211f47617a04e7a34eb7675ded713287725c2a1beeffc4cf66d2bab4a2ee9df67f1761f338ef7767f3df300000000000000000000000000000000183d1ba515211ede4c275b4fbcd1ba0c0664b5cbce2e516dc2480179af709d38f1178d0f867de2e690f2ba179c962bc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c73c71a629f193a31bb575fc7e091e61d34846b8d2277ebdd8c2607ad73d2e8a266c95061b9d95d4230ea6ec87bb9fc000000000000000000000000000000000a47bf60c1590c4fed2ebd20b6dd7ddddaf4c16144caf5d99db0eb8f6e819740d21e3937b97a521ed918e801c7aca7281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013726f60b21f838c40890d86d3939fa535b44036aa2c264c2011c00ac811977efd1edfd5e46f733d8c5b7b528874f03d00000000000000000000000000000000126ff6fb3ad7cbe0839b055009f77e4209e414545afd6856918c547cc38b760612c6699d62a363154e60eb9ce085f6271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000e90fa89c97f843dfea3edf7487e99ddb9e750c0bd37ce07ddab645276af09ca0a4049c42f83969966aee81a80b0ba00000000000000000000000000000000007d2f99dfccbfd8a7d744a30b3e4eb77ede9fdb8a0c9bc57ec84965be8a44fbaeef08b1989a863193d79b786f869a9d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163b4043793c01b95d9512e71b91c905d378fdaef9b5ea6d65600ac9a04be1a1c997b2595040bad16860e379d029b82000000000000000000000000000000000179491b4f75e733e5ed4072a936f1c00a1adb21506dcfaafc8a2d59a3d1ec3b76e77465c8fa7ae2b9694b10b90850f631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9923c972befaca40ad64f1c93a053fffe1e71b3b8d510cc63c6535ab409bd829aae7eb40fd06d63852960f42b5738e0000000000000000000000000000000002d181470ab2ef7ccc5ae808a812347b1f3bccfe91a612aa7eec5bd1f01057d579a18da7d8822488c66eec6e01b0cec31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b963a11b52f91ed718f745ce62477f764464ca726ae42e4cc3d135d7aa4dd5cf64eea034d12c4ed3b9569b10d7fb07f000000000000000000000000000000000c876bf0a44e29f825d0de9006f697b3b3a01ac1ccd489a815d165dc98b10da82c1cd71e4c5a83fcc0665874f062f9301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4422a0165f90343c339376696417f446cb1622680bf2868474ea83e8e9e51f6f7a7b68c090e0f75f6086c444a1f52e0000000000000000000000000000000007cee964bf34568daa423816ccc27dd061b3c9138ad746c43c4567289a6381aaef2926faecaa02eed5482b07be7483671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011090f01d67847d44d01ec69a68e7423e737951e2d4e6297729d5f9d1a10dad253db00a461382765c8953d1b9a8489b900000000000000000000000000000000155c84999fe4c8b93179713e704f3c7ee0bc3377a785477e70af474ecf6fc966f15f91970e00ad69c9152dd39fa97d001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004bc244fffa93300b5179e76649829556665a61975ad5b4dc74cd7a33dfd62b335cf1f16ab6710778b3be3561c26b94f0000000000000000000000000000000010c74b20f18dc98e32fc4bcae52d763e51f3bd0a44b5af0869101bf8a147480d52e70ee3c5f6c3ef5e0abf9c4b13041a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001915c7448d52e8cbf5bdf7e97662bd2fe5242de642b8ae14179de52641d877fad6bb300ce7bb423de6b8dd40157c48ce00000000000000000000000000000000102d4f82db9ebe90f903868ec6bd84f73aef12ef691afbec2dae3d7f442842ac2e1d8abb8f64b05a2b0c2abe31ced50c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036605d1822e9fb91e8c2f4e8238a3922164ddec8cb2a10da31e712c00402f622801d73763a2c9b4215991c8c433c4d600000000000000000000000000000000189bafe34a25d9d0e94b677f8c6d92e417a38baa2c92c3e5f5bd4efb166ea26dfc7a2af97ba2fa7190c23f83e7e34ab71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080ff80a65972897edd715b62f5250f855912ea7df90226a7b0f47a936a7b25c164bead1130b133f95aceb5cc0dc9285000000000000000000000000000000000883d8d025d52ce0e316c4840ebbcef1020b45906444491aa6156ca03143f0bf588ab5871c38824b15e6295cd3729b161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011005d4ba614033a414dab053fe3369a858a4df0847a3f161c19d4ae19e96f3470936ce9150ae68b701890b8b3f44170000000000000000000000000000000001619180bb363d4a772a08533892fe7f1b9b2df3a791e687669a186186fcd16c80c89e0f2aa138f6a4c00dc5e25acc98d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052b2c7f72827649881467aca8f83d27a31271872e268db8f5709fd70d5421ff43a31527facd3038c2abcb0202ce5d100000000000000000000000000000000007ed5e0ec694fb3570b4d220ebe13d10a2e41f052bf56f6ce6ec1b8325a854b99a2e5991a117987d82479572d2f7202b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011881698ffc63c3c93239d1d3e323a2d4d0df82a32879f25f2b1d84c4f9e13832acb61a2590b61b51cbb09b94f3a466d00000000000000000000000000000000084baf8b96d01ae4cd6b55bf8f7932cabc573c6e997852b86acb2701257d23a0aa69391bb83758bd701882d516b64cb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a943d030f67762680aaed35a758c6be0291fe4f35b00c8508feb255f54353fc42c5fe9c742c5ed3adcb4962fcdc38b0000000000000000000000000000000016a6dbdd2cfdf0b2ee7ff33c8930bb983d251584a4cef2d4d3e141c528019b3c9f4ca298288bd2b424d567527c1159341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9010e787e5fbabd62e3114c7315381d8a1a1d76c67d5eb74c859796c412ac81db64fa9b9139815b4113667f96d8e260000000000000000000000000000000013c794be94e9ccdb62601bc4d8f12afe5b0276abcaaea97cb89eb33c4e315b4658a40611b7553b43a0fe2669827e06c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5d448c62699967eb0012ca537351eb13622de1006e950720691f0714f44d52fc795740653ca194e84dd6acae41b312000000000000000000000000000000000f29652a15934cbd5e28953f328e2d82a74b9e87a5beaefd4ae34e9fe4665c54d0507d1d4b74d45859be85902238cf0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b63f37d17c68f0475e3db0214b10f3ff20e87a22a4223dcd3fccc18980be018012bc2e16531a0aaf26d847f164a6c100000000000000000000000000000000198493adfbd103cbc5b15c9805602ef963df07cf8be20a0923eb53b64ae462d4f58705dbc3da591b5d787056bee9c46b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054497aa82c55c71b141fb372176eabe47d131e75bf049e1d994b6e8717e124079627ac293ef56d20f0b21e9658222600000000000000000000000000000000014ac1def6bbd5bced059b2a950511322ac5632ed99b2ea286ede171692da44a1017a5809124837c77df571aaef274fa51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001475a99e3755f855a0ec149b1b35cc6e43f1c717e33f975497cc4192ad0e18a86642618018a867f8323e613fcc9bd98a0000000000000000000000000000000005b81b4a910d4134ffeaf601289c3a7dd73afaf57ae3303dc0842aaca710e620e995c86e67df3273a14c374b08c903a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1347c4e1c5fa59d4bb3b30eea00652d87009d37a1f35764129115f53c8da5c9fc47275323474204114caf67286a28b0000000000000000000000000000000019f1925397fb0919672a483b2bf46e5777d30701c5b99138e4eee953818bb1584657d0563e9a5331ab76e665b610a8a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005474596ec8b34cb06927a34cb4b520202e63264dfdebeb0a83e4047c3516d4cc2949ee8514d7a06882d9ab58a37db0b0000000000000000000000000000000001baf5db373571eca2799cfa07c525eebfe9e993bee30cdb04ecd78d18eedf53a1e84a188b159c51ccfd051e194956da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018717811b337b659036e0842689a02a1b71aadbe503a20304b2276bbeee5e537499f334741fd21bef4c2789be394cb0a000000000000000000000000000000000e9ddf17df99036bf57843567e3eef3a2ca4b2ea0f98cd1e7f91a1fb6ceb3062b4c6c7332d073ec426ff65f0d633a0ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5081286157d40e84761957662756abc63c296438c1f5029db6b69ae5697623f1001f3be92a85c46976359e2533dcba0000000000000000000000000000000011645fb51ac18b81fbdece6f246f73b6dc0e83cb286edbae05c9c9f24637996ba6178aa41fc99b93bea7c05ffca5ffda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c37ec44a4cf6d92f4d70794c120e985805f65e1dd88425db221c02475ce3628a89469ae2ada6cb5e1d0a12acd8663f500000000000000000000000000000000087b3247af0bb89b0ea60ed9e2052c1f65a4a4dbd3b32dd137702aab5767d336054d97eb04c168e705b9fc02c9cc2be41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001116f13891f7d68efa0779d65b32ca048fb4f24dcc665805d33a60fe43d9fe327cfd328ac7738d50a2d738141a1fc4a60000000000000000000000000000000006ffbbe26e6ef58b83edce0e944213fdbd7a924c4cf15c4329537386d253a7b7e3255d00132f93992e82fad7bd085a281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ae94afe20e80965f15bbf5775002ca4d49fbffe62915235e52ee77ade15662246b7785b27b8f1e2dceb0b11e0fe3bb000000000000000000000000000000000ee364d9a38643efcbdce3adc1ab1a99d9e8b1e32d57457ea7d5f4283e50826395569803734292efc0700c01bad6b5a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ae0e828a85730da0c3bc6faa80c7edcc0b8462a476ed0a98a16bfc46f0de14b439e15c2e635c8bcaba00372082c41e000000000000000000000000000000001958c3d7ba82c7a58f538c609f042ef0b9827381677aa1b793daa3135caf67663e4c00a2aeb6b057511986cf9d7e40251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bcbac2e60c2d2503047df3117d0000565bfb03a89df73902fc9de907b5ed011d3f111d10f3d7bd73282049c7ce83de00000000000000000000000000000000158442662776df1a98b36f3e24c46d8a2c3ddf64df0f108782c262ad69ea69c749c3dafdad9596636089ab54c247c0731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0c5108993f21d6f399714bba57b9bef8779c7d179db7a7335f28dd097efdaad4b1295cd6d7fca94fe0bc617ff15c630000000000000000000000000000000011b077f0d08361292b13af72fc5bd5c6fcecf903bf7027f5293eba4162db7b8677f07e1c7e6a1551d1c52e3e2d70cf681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127c59f3b02767161303481f4bbccf5e43c6879b895518a6efa114a17d54a839ad60d240f284095b2bb42bff5ef2d037000000000000000000000000000000001239061bf3c44f0246451ad3e70681b3e4c3de80da91501830cab7eb2499fc312e4f02698768d9417b6a9e6ca6ed085e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083ab987676d27a6201c76029f7e9f6a8ecdd459fb9cc8c2bbbc5ff3123e61811e59a2eb297e6600b276afef8ccbf1bd0000000000000000000000000000000007d6d1eedfdf6e6bbe79c59167615687a0cd0eb3ac7e90aca363bf4b3c0aa480dd83d6b7bd77be21dbbcfaf52128f3321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c7f7582e641496fff87d53b9fd259c68c2110b134f0eb4763a759c0e53a0efcb8c153e3eb8341f1d69234d4526a61f0000000000000000000000000000000018a7212d8fd573444a6d6d461ea3564afe24caa43257ef4f5c40608d58ee8f42cd9fcf5a38cc91ed3d53f102554b49471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001076c511602b96a7e70e612183b14d88bd40fbcb07b6e88b948b5d15064f2f542512c1622146cd96973aaa0068939bf4000000000000000000000000000000001018e0e742184bc795de9d346bf2eed0ccbc19219f70ba57a1f57e9437d78ea0ed2f5bdc5c43c1c3c263fa50d4c7c2eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001908d12f0ce564d4f6e032f46d561a183ab9bbff034ddc3454d22eb41b4ffb8f6d16b11744b27716e6006b146a53864400000000000000000000000000000000164332a0a8edcb843f7499464e2192ad764710cbb1af8c8dec1991b0b4e1a7279ae82a7fbf112d8019e618b2591f27621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000979327714672dae98c4267010617a9c98f3035c0dd4fe0b51c67bddd7a0a3f33c387dc138cc15ff979ad33834d45200000000000000000000000000000000001192dc158a369ba124c4b07f54645dcf7c825f3c6e515468982af652211fdb4a309563f870a69d2688d098e103f8fdf11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc78fd54480cd8dc0d3e9526ece7d5a0a010f1a5d76439f64b669ca86e96450f81390f638f01963828dc65fd24f59580000000000000000000000000000000017eb4483f12e68d6273bee33d27447b98f23cf012562cabdf3710d46fc31ec359a2f6b9ddde6a236143616f9da78c1a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001194ad3565fa16dde329ecf41793c0bde4f14d806d18e9b2fab16d79ba018c2b2d9c234b9b9a765a428ea7e188b5c6340000000000000000000000000000000005c77cc4ed73e6fd14eaa930d05a6bbde53cf5bbe2feeba055cc22e5114ed86fe2160865be91c8d7ce5f4685f1d82d841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a08aed2fa9b3e616cfe2be8eaea968ad42eeca456f394453481d0aabdcbb09eb25c82073f7b28da9ecb6ec148de5a3000000000000000000000000000000000d4243136bf464f4ff36a8705cb88eaf4da3d362a85b63d7da8d575630758ab147f817c7f55d14bf99c798f1059ee92e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e11c518fe9eef2c692734520a4fd39ab10258622cd5ae317f6669fb5db60518cbf42a05c3215c0345e10ab458e6eb2f00000000000000000000000000000000199b41f04b918e0393a5e7adc6412cef4875d5bc03dc808a3a02386bddf964c30b28d7839c45a0d92ae750f341e67ec51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007763ed5ceaf0334e494284142117834b2f670e9b09ebfc430bb5513274ba4c61e08545d6faa741a17f05e17123c42a60000000000000000000000000000000014c082b07bda10a27172210e5953e4313d18bee178893364f19ab3d93466fc60cd95ed4b0cc5d348dcce17b46869ece01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178f95e4b974c56812fa9bd57d03d5e6617051b62c28c971fa1f421d4412a5ef261adcfb234dedbc907903615a8c7372000000000000000000000000000000001945808b48dcf24abeb0237b0172f2d8d91db6535dd9acec72331bde2ce6eac34ef5dd4d46578bed3eb6e27bd5df492e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ae400178cfaec36cf6ecd126c77437d9493ab23f0e4054a1ab4618a6ac3574e2b992a1aa3adb085baa4ecad2f18a330000000000000000000000000000000006b15e8ef4ae4affa0472e07062f148a7d2f689bbddcf5a2521a7bbf24a7d56d2ab2a619b0418483ad2a5e139ed9d14b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4f7ee6d5211d7d315816bc5f4b0399a0feb57faa106b8754a70655235f75e241fb6099bf480ca959b41ade8975574100000000000000000000000000000000123fcea6b6493d6cd328aef22bbd435a2e181b3da20d506deb2f15ad923f89602f45e1402eaa344140bacd5840b1a26b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003713b43849400fb86bca5d7b3c5da7a2fc7695042666c19ace1c1375ffb41fdcc21a970f1277486c05f489d7e58a9c9000000000000000000000000000000001735ba468cf126e4b242530f0f6ad46a98d3a04cd5a6c19e4ab8fdbdfda0857f501274cc315e088467bde5765440c87c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001714ea52a3c84a6e67f262620da111b21e5b8e3e1b408f483ae63e4f2969be2698a98f181e2f7db311f3fb6a6bfe60d5000000000000000000000000000000000bc389c0f40bf0af0f81662e8fce476302c2e34d1dcf7c7354e95d69c0e6b80560058f5d56b982dc56b7d25d706017001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5b09130fcd7ebb14f1d4abebeb2cab306def81db20d18c9be01a3cb96e2cc1dfa52f6dd9d085497485aab356d0a4d80000000000000000000000000000000018d49f7eec034531130ab18d4b9886664cb0ae4d22614b386c19fe8c4a9ab57a9817d33563848379d7944fa4ee0006481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2c36ee8ebf65603074e29ce922b85f2d5f42108c203117f0d9b55d99fb9daa5a60571e12312426b58e3b992b9c12700000000000000000000000000000000019fa3c7f4a8fd30b5849fbc41c96b363c427d7c5ed74658a52c11b99ec4154400a9faf3a1fa19469766a003ebd4f488b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e05014b4c4349313b9e035b911b21456fb7326182893b016da710a06a77da823cc5860f8b5913d2cfe196a3f0b4b2df000000000000000000000000000000000327852d486f0bc820758d7220d6645a4786cbdca9e51c7b8f5f3552ad7feef7a7a3e67df7bcd0abef70c5fd677f27451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d38bccd0f60aa32e5be727a7a6dc5552eb9bacd5c4ed69d5e669e40e563169a50efbb76f731f0b9a99457d5fe25ec14000000000000000000000000000000001828e3dc5849fa5602cb7f91ac56b9f65b63142a85aa38aacfe520e606140b90f9d389fe5b908b3a81365f3bce87b3291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab69f688a10b84fca21f4fd684f35ddeec3c5c9c56a3769f43464551b00246493c67728e2ba5bf05a8f1976b4fa898c0000000000000000000000000000000006bb30e8ef6e7818b34df86834a65d1a1b853101ecf98f263009547c8172e7702f292b560a0c2b8a931c734eb829cdeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c4090e91a415cf6f4bd45a2019b409b1d2e6fe0c7c9805a3cc569678dc18a4f4c01009d8313b526c7d341f9aca33ec40000000000000000000000000000000010c7bf76566aefe4060b3b46715d90c8e0cae138f4ccf525ee291accc7f223efc9475873ad550ae3a5015017801059ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000611f2177daa3cbc71a63c48f26cc666fdd7c03033e6a00be0b6a3fc88e692f0482747e73918dc97e65dbd1351b0bce100000000000000000000000000000000104449505fee5f8b286000ab1bc0a3728bc95113c27bb5ef67503a6dfde1ecb0bc4da9d3ea763f09616c53cc7c4181f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000defb487412d2c74047e783689acecfb8574ddb902fafed26b72336fd33e55f37a275c3fbcd8b6f577a199c7d7d8cf9500000000000000000000000000000000070be97996e1358d2ec4160def5f2bf6637d9edad972b7c4ef6173d7639acaff511c252dc05d52dc61760ca2511a426f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c588c907f721a8370f1458aca82e4b75b3a2f0baa2c4ad579c84f7936937e81e36c4cbc9364513cc8328a97790a34300000000000000000000000000000000089a72f2da003b65272356d54b0c7db68f0f11f2a70a72a70fb7c56093a49cb4b1974c7174801f606137ab09fcbf87da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012280dbd1e2e391297643900ae37d96cabb7dbeeda97b4940d67916c6af0f3432f0ae9531344e26d8e995f38619c78d30000000000000000000000000000000007bb2584e9ccd1e9eb7ac5f72f1f3ee6d387ebf1ce5b70a3bbb3d47d722548f2ec7760622977b3c3df68ab298711cdec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001166f0b407c94a5a540159c67ffddeb376c281108acc0d8909b46f325bdc11d2244c05a12445e742a883a67111a23940000000000000000000000000000000010924a74f6835e83fdcf019173fad65b79dfacbeaa23b88758dc63250e3d3788ffa81130e3485cd85e9dc3e5dc9509f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bba0d33b345a9e058c533660d05a6175e05ab05fedfc004ee499fe85a73b19dea6104a3f360058e756ef79e44b4a89a0000000000000000000000000000000001e829ba021603f979715f07e2b1d5e8186c8198530b1d0440342346006effb93c008ed134ad4c7232c75d73d25855551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000170dcf2f2c3a32f3af069f594dcb1f7b4ecc37611f8f97c7de377aced2c99e03abca5bafa806db9b559e66481413a3c00000000000000000000000000000000000bbf781c376787d8972891957258cac4b90c633dd24c422720f366a2ab04f4d81355ee5c569692a08858415e896f2141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010dcbc6102675f8d7244eca1c777ca3857892852739a1bd01c75dee2f1028b01e58e98d380a11935058998535d2c9a3000000000000000000000000000000000a13880a5419dc6355846511c1512fa1c6b6935450fb90edfdf7208981442119011a068776d764bd1e7aa481f5864e521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d7fbff992dac19d9b7ef0a42cf607ce2c7546b4e54cfb061448a3b43ed93b35027e060202418403389eb9ccd917d780000000000000000000000000000000001ac0934fe886a1d3d0099fb22ed656b439a89ffd239cbe572b38bf5edbbd695bb8971aa2bdbdd432ac64002daa849c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067fd0384d3430ef534d37e55fe9f4e68a7457a53ce0a85124ed2ec259d1b4f4367ebcf0defaca5e4930a20a10b35537000000000000000000000000000000000d8c387d295b5255e8f73a522f76feeaba9a5464955978669ea30d3346c2ff448b2308e722957b5e2238d7b24a1acab91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a4db1cf20278acb2aa644c24fbe27cd50134139af6112c0729ad42c803cacbac4c6fe182e2476d4baf626ed8017f6300000000000000000000000000000000062d241391d72da8c4a9b3029708b321242583c3ba13aad2aa5e1f2241f85ac44375510df448207d02074a1691f11cbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001681a37159e2496d99e15a6d1ab89fa3d820425e5d7b7c68e107f1ff2963e638115aad27e74a7b81eb07bd5b41a2e8b3000000000000000000000000000000000e9ffd3cece19cb759e3d32b9e7ea9537c0002e99920da4f4c4e2c4c9dd9a90db4f6ffa816653801c8c5f558ebaccd081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c80ece557162009cc57b458ca49a0819c15bfee08adc9a567b34b3e6380f754dd25e1f0e2bb0b35310fd8b28728e393000000000000000000000000000000001221229a590c65ba74271382393d822b05ed1d249cb266df4135d1d29691f20d23bc73fd8bac06071d78ffafb71e0dd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118085bf96c359a52bcc33d8c97069881b41b6735a5bc8261f871708ed4a6382df8b509e097aaae73e4694ce309222c40000000000000000000000000000000010f22b11ebba9f0185b02378adf464516ead32a032e4d429c77bcda250140997e337fd07c584aa5570d55c683650a5151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ee8e85fe077efdc5ee35186264d7aa80d41a4e8753f466c5d60b69fe021a9353834ae6e7c4f9cdedf506e4084b36f800000000000000000000000000000000136d8f32c889c32b0b07379dbce0dd2d3aa3c2bbb542f15e383042fbd6df583c119fba7acaef8156d456f03492eca6fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c485629bcb36d8bd43c2a94fc6181ab904d866a9efbee406e5fba99deb6f1344b202a4d60eb31dd364478ea14db9d9000000000000000000000000000000000d7b3aa6e4227774e7a0aee80bd6fb425c307c33e8249855eac88f6befc67afd7f4c4081ea0f1ce1b97a7144230a1b1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2215f1de6e8013ced096362460538ab6d337ffe6a62ca157076639b9db7587402d45d199da52f2ec7dad8f570f9486000000000000000000000000000000001316b87f4cdef09b1c789a193958f25c9d22ddc4e960f32a8d928775d7c8e67e13194829714fba6427ebd573bbaca8fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005f88d52bd8c91f4e7fb1eb01929e7d1907d7a76750ffeb44affc4494294a483206a325a3b688480062dc600d97c97900000000000000000000000000000000066b54d2565b6ee4dc419417973a043e83958298f9cddb8b4dc4c3cdbe4f1e872e698d9bbbeb6c960e46dc576f758b561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156b3af859234f2c0972d940f918ac883502a936fca14603bfa262f2d1bbaf71f6faf1851c7eb5d572d7f6ce060cbea10000000000000000000000000000000010b4312c7b8554701c1b39e769f59c9afa29014d001f2ade36bde785e8950847fcbdc8c8f6308c29e8c355e79b4025d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102a2ecf98e918b13eed5e1a40e772d715dde0d13a4b4441e9f0d82ec65d30e11cf6ad73d1ecdff46dea90680950723100000000000000000000000000000000165ee9c3f6f62f7e780b3097c1bfb9a70019318967740d52fa7ac2cbae9754b19a016fdac534ac04c5408a47af500e5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ded56615e622332ccdb3753f2adc3275e8011d9c2f590ea4fe0857c5d10aa4068797ef3d76dcdbe6d9b611f2eb744800000000000000000000000000000000031332bdc675851ee2826c46caec91baa5ae21c285de9c0c64ee08293d5ac5a0cda7f7480466a001fd49e1ca5a64c0791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d0b68675fdf406beb82d7eb14c62dba14664d8972357f0032e585a877d07d7e62ccd46d8164b72375f54288988591a000000000000000000000000000000000707237c7a311eb8f608eccb34f4002bf604def08c1e05f38c9ace1c02ca7c1fbc0c74012c29b9fc110c13d6ac74f1a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000c720191407be03659e04269d248b965487dd80e0c3ac9eb562a14f80c2fd37ce72ef6fb2b7cc109e127126a9c306f000000000000000000000000000000000ffda2e4fa57e6d9dd3a32dcb61f61cc6e402817af7ac94c40906b63d856618657018849994b804aba99ac70fa48513a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129e3166cb6f3fc4d20976ca9733bbf70ec2fde5040d58e975388d6ab43883194dc46d740981ff723610726035a0e5f40000000000000000000000000000000011c1246816dd39f72ad79e9b9ebebecb64aedbe7c83055681d659b631e19eb77c7d78dada74d682d3150b6d1c5ba17fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003077e260dd21ce1648efcd9121088abe78151324374b311c99c6bbb0b2f9d94ca60c34fb56df62712c455dfee02ed1600000000000000000000000000000000054a206499ad991b143be06b21c22a5be618173dede5b554b4c4224e0e80e91f0ca7d3d1fbaea3ab62ff32b7250dd32b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f3145e932f0cd1dd5fe622e0ab8b926e39ec3b2fe670e99037a3799656a1bd979cb2b3be7a3039d26fee9744c935f60000000000000000000000000000000000b853f10cc0235737633d8ab022a4045cf64e1ef14dd231b341ef820d2082d66c3f1dcfa15b0d691f6d959a17a38a8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7b4ca42cb0d6d4c48d24c5966c745cf84db4702c583f8daf3997d29c9eddc6e075b067ce7de100c73f9a5d252c27ba0000000000000000000000000000000016e7ce4d5b37d9e9e2f7ae147a982e8d986966a0bbdb332315f72aa568466f56679ca18dadde86eaf7242a6e66c3ec6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf67beb5b99fb74071b3b98b241133cda05c4106e9cc2ae52b1396495db43a61c3a1df52e4c668c1f5a558f1b2cbd66000000000000000000000000000000000492722d3ead5b23cc2e48062d9adf5b0dffc17d3f411d8a69292da6b8bc5adc2245ff9a9d63b85c45357a69b34060881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005084f3d992f528367ee4ce3b1777470e2bd701e1bbc85968d409216059e35488f789d1b9250a4f99bea991dc2c98a78000000000000000000000000000000000b8e89980b1621b5ef11175405d6e929051cc70a59390a9dffdd0d03e1dedfc0f7593ba26bd61c06992767abab98fdac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189c2360775c7a9b1a145b50d06e5d7c29f5d7cafa569d5d2f0b8d1c1f039968d9b7d7f786718a45f7ec0f576fc7b6f000000000000000000000000000000000167199bb310e2e11d2406fe0add46d3407571c7bd0fc49c5666f2062f28a5b91fd2ac479f7c4733347ed463dce6331851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd205118297c7a56b9ba83e471f950b8e88b11e8aa3ed773d46ccb191d62db1ec3b66d57463c019d1640dca3b2f7aee000000000000000000000000000000000fe84dec9dc2899ae1cb762999a85d5a6a00893d5340cb6f4248f7228dbaa7fad15dec036c26a9f342aa91ba281331901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028c3275e9cdad9bb98e01fc1a888735146b3a91bef8002eb6eb4bd3e4940cfa6fb9eb35e4b6ba7a7502655386c9f0330000000000000000000000000000000003ea3fb82fe36d835f9f5ab5558859c0d81ceedc7050cc34e143063d1211455998af1026a32321023bde5671579c0a031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001563cfe5f00d2df0c36e7d210b5eff9c59bc4d1dc3ecfcb4f4e5c710106f21fb73eaaa65af5d06d7cb78bbed8b1e05100000000000000000000000000000000004e2a74d8599b5ece040b4f3b1feb767b70855f10336ab49d63a1b9c32f66baee1e606361aa53e83feb1c6dbe1bc1ef71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072bec02f4ee67a86513f8059b837591271faa901929b6f64808b9091f7a217e4f04448e58e55792f4090f961e6da4e30000000000000000000000000000000018e1e8e0920f3fab9df791a471a58bcfb27c54084e2b2bd3715f1d01b2b1698041b026969ca5a13d809d062edb9142d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c24c613cb51fcb4cc3134e061cfdebc8893610737c7c500768630b93358d6d3c19e81ee83ffb0b2a3504c9f231fb4cf0000000000000000000000000000000002825f5c0622bf9206d96b5d533faf252464f0cb974fcef0abb868b3c1d714d0e052461249cb74b9d0eb88c72fe525fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001551205296d06b5ba542ba25823bd87cc9c9898b48c39dd8fceb74709b888185c53449d92b0ecaae9c30377c14ef69860000000000000000000000000000000008f90647d74d7ed9705293442e54caf4f331c3c40f7e97fa07d36547747461d75afe87f071cc73d84bf0ad29ca86a1721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000115daa4e77e9fba59ad4de88b95ce0733e7da1ae82861759be353e70dece9a6178a693f5c59124a6f8fe338694011cf2000000000000000000000000000000000c3a6f9b531daa61de46a494cc3cfc1ea6abaa37ba043bcf8b74318614372732ea04ffcc37e5e3e245efdad8e0b02ed61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d15a6eb2d463bc7004717522102ddb7c048bb7ca7fe643374a9fafc550868dd0ecdf12cf58d88b3bc5299e2c9694f32000000000000000000000000000000000d4cb9a5ecd7f5f62f89acd54a8d39751e5077cfcfa21d5c5b73c9b489b24bc249c577399135e0d64549e83f1f69f0fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017c3bf474cb06825f9d31df9b0d983cf475897d308f809e8a0a056c10a302765e22313538ef6ba29fabec27452d4f0300000000000000000000000000000000025d79bbc1b0c098003245f763db91fd53516134a4b19b558f7ec9f1a40508995c8a459767a334ec0cebe503f805de751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000afe08e4357382a1a2085439e4ce652023248ab62c74febefa46dbae62a777ddc0776fef72f11b0c5f4c77086d72e72500000000000000000000000000000000153727e76d034693f2b92149dee03cfe7bd3022f080bca053b731c00bdac04c4cf75e627a0b1b7ea85ef7c682cc009231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014cadf42f3db8aed3371093348cdd1e4d4892f35356e79092efe3fa1c01348fa479982ba6eaec9d6b24675620486692c000000000000000000000000000000000a3066a049e570b735abbf419b56d6f22c99c8a6b82ab5615dd03dbe42d3d3b7e44fdc3e9b2d3f95b7c32a6235d90f781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f2fc624d7367199404a40d16e059db78a5d19be099e612903d51b48d097d1710114b0e68b338dfc10ea7e3da91db970000000000000000000000000000000011c426147296f53d1a3f92e4d2a245ad517da7e8f976f6c15e2cebff1b200d6c21a7742e48c00ed57ac3192711208f751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168897633c1bd91f9690275afdf6d8fc7a226d9bd675ada7c43f7e996d0ffcf73374a0ab574081a81f378013be38df3f00000000000000000000000000000000187390be1ae2b449c870526065bea90d41978c69e86d1da233094c8aaae1a3702eabd29f640659ba375accef55d7ec461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2998e8f427f82c6cc9cbbbe3a7d2818c86d4708ad13e70bfeb76603adf50e3d76df72450cd4b96da6cb58648d5da30000000000000000000000000000000000f649b7b514bdf7efece32ecf7398afb2c19d3aaf580063bda8c2790e5e67d09729098bcef652f0906849207833323421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000077b4f1cc1ec0c11cda1d5a814d33e3ed25cdebbcbfc56e06afdd5236b5a85ec005e8d7dcbc51fe39602649ce3dc1c000000000000000000000000000000000ed22ba17867716c891f7b4f2a727f9ae479966b69dba7936743a0b2fb229f95ef34964945e47d4d80f806ce593b55db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012dd3161a8dcfdc3717e59831831214cb742e3d89c95a501d9aca857f9d84ed00edcc401a2abab46c9051bc718d8de1f000000000000000000000000000000000e0b764ce409d038768749c8894f1bb26a6ca912df517f2f79117d9b9d2cbf78fbcb65ae148a7beabd549ba5616747871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005009b6c6c0123ff561076f28aafe371296e3721ef7f2a5313ef7b3a587c21716bdf04d4fb3fe704641d679ca8a8b6e7000000000000000000000000000000000108108ddc46a214b28ef445be46e8a887fa0469e3c25b132bdecd0bbc1822d5301425ac4d2a78d91e41416903c2fed21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128335f6275a132726f99af7ba3b65a1aa13ce9dcf8a12aac9df392ccf046fe5cad198b75edde85bdfd3ff07432e2e40000000000000000000000000000000001279b924fc5001d64713a433e4d8423748f746cc90e1651d0bee4b6f1e13a76277e126bef6bf90a6e464c3349809fef71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f8868a889101735c5afaf9145b73c0944e86c1fc87811d3b2b32e4f1f5e67e35c1cf6f4dc7e0dbe89e88be0bcacbb80000000000000000000000000000000002322dd1a43e96a876b39483c37084c3f51eb1d943253311d3949693f85bcd8f433ffd14680ce17158ae389c6f2855711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c1fff218d42355fa8c5cd1e479f36124abc8ac06f5b8a0c1db5fe59f341985679dd89c9a29d477251310c711546f6f000000000000000000000000000000000d313913d4248223afd7b4178eb2c4834fdf08876e73b8097dce6696dd3c62140af92892e695a43851e9e30b721b65641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013677a92dae64d04196ca440707b73fce0d260145718604130a60f7912b1fdedaa5ab5e624152c9d71b9a77ae040701a0000000000000000000000000000000008bb0489db64ed84fc6d41c62642f92f2ed969d8d7790ddcb618c2a51030543aefcef0ffac2e9ca42b51ef83a9bc5a741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1e2b150b1e5aa7bea43e6fce343aaf6ce512e303fd89c021d0af0c0b9f642293f0d7790826c7d5be31fd2721df522d0000000000000000000000000000000008e4d3375cd225f783db60c8209501b9a0ca1268f57844fe5ea3d794ddba8611ed58fbabf167df6c0d4e74c6077869661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a65464b112c306993c5e43762a2d47a3d937b3c27f826d900c0a30da504c98bd8469e5decb1fa5e5e9c88e2baec36b90000000000000000000000000000000008d53ec9f666b3efcfb8e8c3be5d1b92e747b00628391267553a5f117c0e568f43e510ebb69259f1af649b2c6ce9334e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b4e8fe2baaf37343d10db89743e014323fbf472b0ec6df08ef642715cdefbb005022bbcbcf67a9160a74222fce7d200000000000000000000000000000000011c5ddc40f1d2dd68f7d1ad8185ec622c2008baf72aac69b0dba7b56be57e3a8e7aaba380859dc65fdb5b47862abee921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c708779c8c1f7618b08b4ead0befd4475803f2b262d7f1c2d0b444e7a3cf9bae1322c6356f99e78442d291f986e7d8000000000000000000000000000000000dd914f4fa648701487ba9124821ded93ca3876fc941112a887f80854876ca9645786fa8104002c9c0483f8f5ae0b9a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001604a7a9810c01eedc950302b8d7c6c864ee44f4eb3f6576a893a57306472927927585fc6cf4687804bfeaa20ad91ec4000000000000000000000000000000000b623ab75c9caebdff3f5e2be45e5af8eac5fa59a97cff73e9b4a67244919ddb14655c04f575f71c6834e0982592498b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012943c55ff3e8b939bcd90dcba33abe9485ef534b26e0bd0ed519604e978b327a984b0e2bbde8312afed0695b1ce3c220000000000000000000000000000000002b63d5533af80c6a2eff83e8b81be2469cdfb83cc383a29d55b50896c025bc54c89fb52b1bf345028b62703292fe6851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc8f8c520acbcf06be5cd1304321e58e744287e9b90d6d60563cfa4a489bdd1aeff238d1110f1c1da7297964c2cee1e000000000000000000000000000000000c9ae8e0f16a8d1fc06efa2044bde2c835c29e641981630815c9b7aa0b8ec343df8d0289e14c95a30eb62065f07f17b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d996fceb20a0610a66c14e81f14ec288feb646b6e0ae3d5892ffbe68d424f742e69e5b2a79763e923c665afcf9c29f0000000000000000000000000000000016b41edc29f76296d5376c042a10a7984fab423f6f3b1dc587de2af63dcec122446fb67c6d43c8f3adcd1a5afadf1b0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b68faed173f8eb88bde53720e89a690c6b50fd144dd80d1fddbdc9cb5fe2fd1fdc95bb90bf0d67cfd85162646dd9631000000000000000000000000000000000e128a899211c216de1b9bf5c6dbb439cc8602eb9392d34f524948ed8813777e4ce61b4b2a2787768e5d4766144b12bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dd014e3470ab9bb912df2298ee6d0f817d0f0da5e766e51f0856b5c386d5464580328bcfbadc7069b6bfa4ecc32673000000000000000000000000000000000836b454b5fa1f6643b6ae2f6cfdc7f415067686163ba6f650db65cf403e4d153db6653e393e8fa83a794d74831e5ff51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f750d8d974e3cec5b956652a804fe7336d706a4cae007a71db27c984c2ed60b78219f1e7bad810f9199ab96381dc50000000000000000000000000000000000becb5f31f980facdf3ef266998a376aa52bccd8f045764751d7937317bb1a6524492fe96db9aff37b4920f01bdd58c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000367927d68afd21a1ade7cf74d51b1cc8dee02e16c7c3e23f593441f357f892def1ce21956dfe6444c9d0e8cce31fa0600000000000000000000000000000000009a901358f1416a15f1bab3b7790ad32903fcd672fa7c28306fedbef33e54321e9c06f86add57bdcda0ae23a4de554c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001678dd21cc1eb6550fe025700267c71f4a176ee8b2cb0a1bf1f7f79c684674e3630526268af164c7f4be48ee5162bff2000000000000000000000000000000001796f624ec02caa91d2c6a78a6dab9fdd47b0a46f759a8c573a365b3e728caa486cd4574bbd3b991e4ca402f86ec88961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c48fa017b29e7530faeb7d75e0c0bfbf8c308d0a04c40ad69232ec66eb0008807ad25f161a54868e6b116d3f5b7390f0000000000000000000000000000000009482d5f050426e4e8e2271895eec133e070b83f1056d84eedfec52e47022451ab65914b6e9b2bebc9139193e8ddf5d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e86ebe52d07719f30d4c420d1fae6fec1c62707bbc92b36972b8a4484e309098008f76ec41a3b41ec447da1699f0105000000000000000000000000000000000b720c75db0761011ad6524f7a7571cd0973a59f687b59d68fcd76ffe82f54f9a4c958eb47b8806eae5117f54a3346261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3c6f4a158c1437ba61b94a3ab68e272a1583371df4f47f9f829b06ef62d32e03ba901ab885aab0db2c91d410f07590000000000000000000000000000000000e81a0401949cdbbafef0fdcb1673d7c6577e2d995f7fdace5158bdb56250e1685e34ebcd9ffab7f732bd5fca96835091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000172b70db273adbd87b2a338ce4cc299a403a23d134dba5496a838b40836a7f880ce82249e662da7dc11abf6e707cb427000000000000000000000000000000000141bc872c9e033f12016e407bb06ea1d305a8047b84be886c8b3c73e8f87b512ef058bc89a1269e96f9658e1737977c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001501ac1bedcad52cbd1334903a39fd13e40b6e86589f15e5f74e015747c4ebb146975c658cc417e73075c3932a69e0860000000000000000000000000000000014e4e476a483306b71a88eec2b698ddda51985df05f5ec54d3b95799a9458ea0c8466d1bfbdaf7b1dabfdab3ca3ddd381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001103c34b7655affdcfb57b6fe661221b066fd1775e3988c0a838f3e325fe02518fed12cfe02daafecf0f1b0e646fb7b2000000000000000000000000000000000933eab5b19ac98145b41d92da1cbd19da751b15c6631bf312c83d918e6bf5cb39e1d37817e22f3a1fd922f7323b1a021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd813171eadb2c692532718c971839b1478975d63f651ab2ff84315040f691b44a636cd77d335b8943de180db03ba6b0000000000000000000000000000000004dcc3f6a1623d7760d42740114363914522424bb3a30bb380323dad3bca124bd25a47ee7f84d1047fc2f0e35b19156d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001957e261c08709e36f873472dc84050d0c5c4f2346da39d0615498b46a0b281ad74d8a889891eea44f9b2406ac15a1a2000000000000000000000000000000000c2b8f79491957e1ed63882fad1739502ca0eb4e031d763ec3869d9ea20d40a71aa141cacbc7ab4410fc8551b81a63001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dcd7a1dc8383014c2e53f77a09222ad05177c5f85048422ed33993939cc5fe46c8556999d8e0e4550bade927046a4200000000000000000000000000000000013f5aea8875a6efd8497313d43cf94df191752dc25ba2bbfba24afd8cee7bfef5e96844e3a4db2a7904395ec4b8ce5131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4279b503b0c0c301d76a592e6d2f9c3726465e590c37d3545ca6542e122f5e4328566ab32289900cd945c37f0552a200000000000000000000000000000000031bf47d718b90112ee9fd78226b20f0657c0ba6a37bc0bb4caf2829bc8872edc35a266cd353ddb62af716042d4f216c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f148360d0083c297d6921baafecd9d61ffcd62ec138911390d2b8101b4bbbe3b7008c9043ae0d1d2eba9e53ed006c7000000000000000000000000000000001309c867c4c69a4eca2f6afb41aabb94b024493acaaf959e2a2fa81e1b0ab806cc18c6918e390f48edcc66419915f9a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c245499662ab3e7b2ae00285d607b9647c6c7ae2e204b5a97c0b3996836daf31435117766e07bce4f3593c23321826000000000000000000000000000000000a0760a36ce06f953cbbf1b7f563123668c61d9be4e97cc48fbddcaae2552183f2254b96e2a41a4d8de42c0d193871c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005ea761fd5b0461d1ba9d4b48006df4fe9fb19ff29f146b434a02740c5e74bb53df3576990f18a05114f78bd5d7ed7a00000000000000000000000000000000103b5f50663e57b2722648328ac493a2fccab52b7514aadb5d5e7d7f55ab47a89c3590fa0ff965023b877b1b1742a9fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016d9d31925a54c5a157dbed363cfd942094030bb242129f033f1ad99c8f3334fee8c9e87ab462a60cfa3ecbe689d08a8000000000000000000000000000000000fcc340ca5b19ef6016c60ee40378e8eab062e6b1970c6cc1456a9c910e65b038b77e6ce985b41b4c718e8669c43634d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f53db4a679d9ccf8b27953ae848b62ed5ce9eb7fe3d7c3f43becd9b65575e950cc6cc2d50067ec93603478ac0276bf3000000000000000000000000000000000fc27dddb4015a59217352e79de5b64e75b6920860cd470e2a101ffdd25961d19874bbb2c7ba02e9d351720d8074d04b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b026009c5570c19a180b7aba4c7df787bce9317f2f0304f47e36598125fdb777af86d5183954e487f53fd05b63504500000000000000000000000000000000025b7e38fdf50edcd6319388272d90238b1ce36b9da1976c3dbb7decac346547f066d83521d3d0ad39ad288745c8add71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071cfbaaa4b0b8ee4aa60c7d4a78a72217f8753ee92111f909b8f879c9604c64119c04dc261554d4e4f697caa36253ec000000000000000000000000000000001993f1efdfe5a11792f01d16449252f84dbe49ba5fe2a0438fa6434068bd0a607ed8592c29faede46618f5d614d1adfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000206dcace6c98749bed6964144ce12cc48ad114a6d24b8b579a6f80c1b79ea349a95a28e240e7616438abaf2914bd365000000000000000000000000000000000d680937d5fdb62b9bdfb1119677a1ee76cfb88ae5bbf6b6978e3b6952f80990cb24ed1244649792f31b3b81e50c7bb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117355f94435e3f3f8d94b44e60a5f4193ad35a1f8133b08c7248fa3f90403852db5e0df43fe6d1b7763f47c97e29a2a00000000000000000000000000000000125b25b10946497fe0c955cdea32a400c6c92ef29feef6a437a62582a3c30a599ad8946256bc24fca27379ae8f1362841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000125f0b2a45e4268728692b9dd31dcb4cfdd4b47ae6af83ef4353e7ffccf49ef0955872ca6ba722b86521f6f3f01e4c000000000000000000000000000000000010b934c017a3ffecc0200a03708216a2264ead70b327366a3606799a32be2af7a9bc4db4e5124f536cf4e64c291efd921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091e899dc27cde1a46164ef8649bbb852c112ae8aa5f04d7ef1c7aa1d000e05db4219131ee3bd1dacbba371d0e03c96b0000000000000000000000000000000015e8a7bdd71c6728473524891d0f26977b9b97de8c81230204dcede5528255459a96af94f149d1b657c7412d14d2c5e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016cd4344819945b32731d44e1e539c004acd610b215021a1b7fc7ba9eafab1041fd4a81f9714379f6f8bda3651c022d000000000000000000000000000000000e4f4821bac25d98c1206c82d75637baeb3ecdefb305fb30f13246254ed71065b7901c97988c140cf485abe8e1b47ead1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8b9358fc990d651bf5317846a828ad350799ad5043299d0ac447a9f6f056f8e5e4aa28a19f0e4311e66d1d8c2f3ed70000000000000000000000000000000012c8ceee3228491769bcaa5d50cb679cbc93962d5e666cbaa0c9c75b9d87a6131d04ec15c75b6f8b0a3570120875c3b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbd830ce4b3eca944a6a0e92e72a29d81c8093b6e345b1328e4e6412ff9aa3cb634d2fe0532dfbfaaee2e59a5a88e47000000000000000000000000000000000f4b126ad4a48e747d3f1424c20fc96a24bae606f69e6d7f8c870feae982f1f6e22e341fcb4246403e2aff38eab83aa51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001510b6b360e4453743afe2dba6f842a5ecbac0d24d051d996a819866142c2e7ccaadc51ad2dc3f80d1aa9957e36508b50000000000000000000000000000000000d027199631371e637463feae6b23c79e8640a40d501853b0fe810faefdfb065cc91466d7d63e8af2a2d0f2f80c70db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000953fc9fa991a6d24f4b5817b2ce650f7d6625b811e564b1fb842b3211295ee65cc80fa4223f0cb148a1fb0a34047887000000000000000000000000000000000856fce2aeb9fdd825bb702878c7afc4717c074bd67f6282d873fa00c6b914cea334429c0fde48cf2aa9fe39c20c3d2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072f191646daf141bc7a1cc9143d7f9b045a7a4c7d80a7f6392ee1bb551bfabdac441d5f1c5aec18719802a759239cc1000000000000000000000000000000000c2bf7020c348dd55704a2ad8554666af88ef2566c41fc27132b33fdb9a46d8a16f3fe9093982cfa2d4ebe7ba40a0d631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000160929cc188795a485521a14c1f77ae9403af77cb128331e20c52a7ac03702e4a950d414afc376f64ba3b40008508e53000000000000000000000000000000000d412be7af9a8b07922d75259238e21b3e43b32231031bc40a721dbf0cc4665029f4edd48d97e9e3041e721c634d6ab51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ab68153c029f70d7651fc01dd733b05a3fb39089956d1e26d16792e6fc73b4829b8d124c6a2e2d11a921e9c46f48a9000000000000000000000000000000001395a5572fb70138eb7b2e249619da24c2d4ecb1b7bcf0df9df3c93fe2d19525f73b5bd003029cc33197bd4b789f606b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011bfa06f07d6fe983323088ef936c43f0eb6d3b97f10a4f47bd3bf59de7f28a29728dbd4c744b722985fd1914a00d05e000000000000000000000000000000001028d3e3b839d4fd34490a8762f252a37bacd64460cf37a201d841608d9a79b6ae1fc8fa570a6452ebb3bf7c07917fee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ed0876a13154fa0cacb313dc42c37eaa8d64bc99a1305cd3905c82a56e68f4b4d9077fb935d68e5feb0869cd2af46500000000000000000000000000000000001e9fb29a9868d992ec90e667f12e0590a7833c705af3512ca4995e13623e24fbf34369bbddbcefab6bf59c8b82edbc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048a0c8cc7393446efa0e4cb9fd17ead656be2207965d9f5f19e799d89666e19816df8b7a25eb6ab02c1118a1867589400000000000000000000000000000000008de71fcc238cc1e74dfec902e0f68224988a536687c9520bea55f39a2baaf219c3071aa167c68fa6ff16997c464e4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018d465e7ade20538a98bc8b3190574fcb5bfe4b9d724b6fe4c5a9f2bc12bd6bab9ebdec9f01ed0bf1f0aeffda075ece00000000000000000000000000000000153fd60245dacd425212c695d45f31dc052f92623f8dc9b42def6a20f82b7b1af282528bbbd9282266c0ba30f6e73a991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9ea6fe522a437648df336d3cd95ee9505e1bc6e504e3282bceffaffd020b51ef2fac17de6d96ca1a7978f4f7cad3ec00000000000000000000000000000000153e9331b2c64dac21677f6e1debd22803576b875e5c516b24badc8d7c8ee1d189abe7409c59616c0fab7644f04679d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004141911511b3b3d12ed4d1a68f4b8fa986f3d213a30ac3cd1a6f3bba7d058dc0b7efe2483658298c69bf9403ff5eda10000000000000000000000000000000011a6f6e45ab920e5c3759058edff6ac5c32622a34c3b931979a8330de1aa148b63eedb8d905218e6d9580d43df989e2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056ee21f9f1be6c5c718af606199d91a8029590bbd519b2ebd562f16e2dc7234c27b2f831eb8f698a3c553f1a4704ac60000000000000000000000000000000017842894a3615d2e0b95771ac9a87aa935c971b22ef0c106246642fd56008eb3d1886b08f2cf6cfbb641f54097ad55e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000202305552441f69c23913149be1b613fa08f62b356abc6c83e1d751be217fc4fffe843bf497b930974d93646fc2441d000000000000000000000000000000001951b70fd53be2f4d073c94344dde05231fcd62ce1ea0932e5d3d9ea6d752c16ceb4f3c4462061f3b317a6edb50a1ec21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c437dc972a5c3af341a51569a6dc4755891c35b2a99987cf241270c1a4c151458e5854cd3d1a9aaf8cfc1f99dea2c400000000000000000000000000000000102c34fc0819de288f35ae8a3b30621e621dda4551661d78dd607c4819963a344f1bd0f450dd3977db33dffcec4ff57c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7d7cf7d76d5d0070a4e8deaf82c9e824fdd0470a0a9fede3c7b1a2cd74b767b5bc7fd57de092728f0e669bd0f06336000000000000000000000000000000000e9807a3a67d1208f9dc69b0d72bfc6a54ceb92c6d29eeb4d77d6eb1db681307f94b5f0dd0156516b354e547e00352251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000523fa5edfd6696fccfcb38bc0f667fa854e2be8657adbd84b35e1293461c44d0e1414c6ff100c1d92763a17604a9bd70000000000000000000000000000000014c5d79520ed5b92d7aa273d1d58dc9d6dcc782fd1a7affd61610a3c8729e9de55282c782cd2b9320ab0ef989b5de7301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f1687b6b712512cc059cccfeda62610d896362d84bcece1174792471852c1b1532fdc44d13324257adc7ad803cb10f0000000000000000000000000000000017e1ea6dad6438ac814f67d4ac5d6d282acee53503b389e9c77723279f015bc02b0792987fd2819a5d85fb8608eae3791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa86fffff4db66dd31b506b7617f7ba8ccbb1cceafb49445daa4b571b44b41e711eb0c3d665ab20ff0c25a01d42b8010000000000000000000000000000000011a6d3137447dbf60cb47318a03aa57e6092cdd0e4ca9d1bcbb8cd2a49b4eaff2db61ffde9bbdd0f89b1e39f163e9cfa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c3b84b02b287a13d6be04188c32f276e0a697ce1ab71372b68ba58cc56592891cf772ec51c1f3f200a2b0339c845800000000000000000000000000000000006e8b5c01cce52fe6b04a6862a26ac06d320f4ac9953183952b5cbad330c62d6ef47e1b9719ef41e2c14363fb2d5d7ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ccb9d14c2c46a6f3b1169abd7ea38e402cdb5bd6742c2867ec042cfb14597db7d42f762c58b89307038c2195d96691000000000000000000000000000000000ec47860b929ae2b2a64cef53c562d61c8705ae0e7fbb3e164190e92bf561c1f61dce99d4e715aa913e72f8475e9a5261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000522aafefb62af315abb6641a795d08b92eb446ec7fe09ac1a690b1efda72664c30f8936df44a4aa7afdd6346d05d1b80000000000000000000000000000000008fead14260e9f07e697aa1ca4c2f9a5215571c6cb281f75c6fed8fa3b61f30bf2141b2429a8790b51ee7e25bc0ad75d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d4d81980e3cf50a9e9f770589ff9729e4b5ac62761797df747914026b9e0f9ef6db2d95f56d28ff98e3c38e28c2776000000000000000000000000000000000d3c0caa1c51a0a060939e1403aa9ef4426a2a10342c6a6f2255e0b20f65443e9e25b6403cacf3d1513651512500d2e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009242e8176792dfebeda21badc305e275046236ba9f885b58fa07223b71bd68292430a64135ba32de0729c6b8a8e395d00000000000000000000000000000000002850d8294f406e15883152840e50077e3830667faecdbc440f43aba0f6dae7fe867362a74719b605af37aadff57eab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193d4ab7a013767ac6d6742a0dfab3f5081726f8ef1580d9efda3b323bee44f63f2fe715de287ae096c60fced81cfdc80000000000000000000000000000000014c84d6b5dde20cd9e800e7df887151bbb66d029109fceb9b176d243db26e10d7465599c0e6944c9c7b18a61e331ecce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cba2968f739aded66dfc79162581be27f19b9b6f52971cd1645b897f21136cdc21a7c2b0c8f67e4a44675761fdf97d9000000000000000000000000000000000dfa7e5e8aaadef3533ac9197f36dd347eab1c1d0af5197eb5698c2586d02a332fe1c74c37353f8d523eec67fa7cb64a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073df1ca45a848054c36204805987dcaecfae5616bf7ed27d69c30beb3361ffb73f17dc03af49591475943edacb225f500000000000000000000000000000000093bf03e24e1ea69e2248c8d7926ba8d1f87fada0ba1203e691267b95b5b293995a6d4b94e3ece2458f4e686b597402d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003933bbd0f2fcebb39476c11d5dcee0affd61d63f4ae21432d5f3a1fb95f29ce95d46788569cc7762a43b4241103163e00000000000000000000000000000000009429e37e8de9b10af669c968232820f5fbaffa4396b6da91877c3387b718de42b26e454dc2bae4b591ce3fd1192e521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec72c5993613691e5862deb3befdbed1f284d5e0053711bbfbcc957cf8e5002a34dedf702b28d16ddd058240959048f00000000000000000000000000000000189335bda22740b5f719bd76e8d81fb47db76ccc79de1109cafbab78981d8766a93bc233f863c3b6699bd71b4b773fb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140525d69e3e5a331dee6760af02707e86d48f01616b75e806f3c4401dc320b16570448aa29e6926803caa5f681e738d000000000000000000000000000000000edbbb746d6ed51d0b483ae42cc27d07784bbddc544b9c80a6cf3ff5c3ccc0545a04c0b345ac5df2231fc6dff60553871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001be6365228494d7057fa7302a4132aed61e8839fd4eedc8a1c77a07fd2c4d9883541d03b793f2a7ef581851580a04c200000000000000000000000000000000032f2247390a70b4164fcfcbc680c292929ed618e3b3c48441a67207f866302763c5604f768260c8ad0cbb7ce2cb697d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cabcd365f53ed1c8b2daf55ef71ef684c4710aa3b783ee709b904b37b333c032524eae931b25ead6dce771f89a4fbd60000000000000000000000000000000010bb62798b89ece568ddb039c9378e9dac1a4bb7db1f264d07bc0c04788bbe8e6e7bd430ffc0980380225b12113883081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187e3d59b300c4843a83dfde7f895ce9891ac298a186cfa5df708b2a6172369ae466cc9f43b7a064339b06b0caf38057000000000000000000000000000000000f9ffed1785032752ca247f728a4b33c1be1c96f51229ec0c29fd6b37a479011d397f7bf4971e6e8c3da152254d6b9281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af96cd0defbc78806c9e763fe8efbf77686cd25d38af9005d4a63000b444da34731c77b86df5d365da1967ed0e549c3000000000000000000000000000000000fff26a098af9160e0f99c5f61348c6d45ee37d5c6025d03431f3c2b66619d7c088f37f61920d095cb96bde5b7bd63041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000663649bcd5437be1adcb8766b2b72db33cd1b0941154e638eec4338514c5be053180d43451ce28ba134f174ded72e1b0000000000000000000000000000000013ca2fbb46b5735a6394ef3c57312b01e6c317d9eae4be8bcf698a422bdc4dbdb0706bcb460332caa43ab73511775cbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017fb6baaf4448a7acbf9a36637917f8512b442280089a3b691513929e6efb8f87a64343c0eab60f9b117fecf6fbcca440000000000000000000000000000000015e8a65c9f8ae703cf42c980ef3b8092f781e37f241954fde2fb5015f4da739aeccb58a76e43ffb0ceef721302ed3b301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040757338a4a74a8ca239674bef884be2fcba5fc027b201e4f7c01f7eccc7b22a0dc5b04f591461c27157458fb293159000000000000000000000000000000000ef3422dee73629375db8f079c5b625deb88faac9c0933ad186272d1f3027845821e409a9e8c21f94ee256c3d9f361761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063173b639fdd9c088ca88fa763f994d64a2f3686f0ee1189b5ec4afad1d43ee657012bdc78e1059e5268bb1818d617000000000000000000000000000000000075d874b508e7e3636b2a431ad143303b25c1bc61844d35c48e9f92c12fae0b927ae996182a4cdf549966ab76fb5eb4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000909fdd9007a9801de1d95570c4447731dbf785fac6e062f4c256b1d99662a9fa14b1f1da6a24b9cff16bde7d06dcec4000000000000000000000000000000000da1a9dc6e21733f57a1a33a18d10b85f91102692d9929aa50f0e0c3520afd32daf6e37a9dfea5b6ade3cb2ef10aaa6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8c24b764e0d8b1f50d703abe6bf609f0062f536cca3f9077aca161fe7ce65dfcf49f971515f032eff3a7c0d0c7e1bd000000000000000000000000000000000e77e685370dd6b39c0eec6fcf8db4db494b3ef1c57a362cd24fd6657b103a03a2a6d45d9effffc09bfd21b22bd37e211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163bbb77e5cb8c8601b5fb1bb09ffc0011c86837f3756c9db4c392d886e34523e7823cdcbd4bcdb50e516108cf26c035000000000000000000000000000000000943a59903c980b237c3f8b52d736e041d2a0531d0241360c7877be68ab1a42f9f220f830293e557a14fc1a997a52b6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112001c3194be263338e746a29c4b405eecbca49539e3d8158ed871cce7b3f3efa6e85aba456cd5621171321487a3fe60000000000000000000000000000000009a8bd5cce84162f6cca7f1d9924e9a7f7d8b74bb728f1d499ba3b5efbd61c66ff278756cc3212488b5982ab2ba834a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b47e7931747139f10d4e72de1101209ec8d62d62c3da010d3ea2487ed04b0e4ab7c43a34104dec15746ffb6dfda3bc7000000000000000000000000000000000a03961ac974e169786c09b9cb07eec65ae100d3e378724b7206a1e532344be77ea3b9533f89c44e5647c7039ec7ca991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015be951aa77153fdd9635b7a3b15badacbe4348d5278ab172035a75c6e4d82899f18f61219b6e96a2e7889919dc2921f000000000000000000000000000000000ea70338b206b57eae14b042ceeff73bc2f84f1c199dec82cdc9a9edaebf8b38b1f76d3421acc384d1f0f16c627a52ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a02c674268a3a383b776ea2a0ce972223b41e74b40d24791f9f12dfeeae5310f716b8254d3cfd04ed1aef6a0103b06000000000000000000000000000000000ed602f1c6a6a47399cfae6d5df6c3609fdd7574c0424d074da5ea85827167ea3abf0c672d833983964d4333079febbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f32b9c4d6bbbd7f376d84f1beeb6717bff5fdb6c8b8d6bcb6ad18b977eaf52a22fb2881462dccc71fce685b743a9940000000000000000000000000000000007f610fe504df2c36204508669bbbe589990b54e117c94a7a7c17134aa12d08638d99441598ea82eace7b783a37f28421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010427924d67255ab762c989895699c348ddf8e8450a84299c82865c39b92dfde00606e6a5786bbb779eb9a5938f4e88c0000000000000000000000000000000017cc2620bc9909b4334fbeed4f3af7be5904e40f175035131a7c5b244871638809294d90dd7cd586c00afad77a67d2841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f2eeaa9577bc28533376fc3e1a17173a47e3d5cd2cdcaf76b881649cfbdefef3de08ca3db6cf84770f0f29b7fbf9fb00000000000000000000000000000000133a76b0ebf0f23ab8aec895a9c425de294a29807268fd005f5ae786efff0627f9f032b1246daedb5857f59331c8da8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000022ff106000ebf7a439cacb8a19f0a6713a7d8c48ff47b2841ffbcd89c7020b2dc12dd8ecb552be379427c914a837f46000000000000000000000000000000001633a8b62fb2af48f125471e97abcff7b408838e4f7bb14b09e94d09352631389afbfafda128a9adc21c4d7e597014af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5dec39917d12e465c6e5d6546f8ef132c71c0ac83db9481d0ae9df66fd5adf6b83b40bf4b554acd7df487a06b7c7420000000000000000000000000000000015e87fa1b5f355b9b9ae9ac8631eb1597c03ad8db3f37619c081a112cfa07e891869514d00aa26d6d1fa059a76799c531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001389b72d9df5b6a7c98045843f19d75e26317e8d6600b730cb2a284d99be2dee516a7b685e913b977687f3b6db370c57000000000000000000000000000000001749bbed9957467ba50eee0bdc19535856a075e59e32e17d0f7beb0ab6e0ce3cbffdde6cb7407e9f1fe5f013ab940f341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014898fb09090e31bf8f4f7116a5ee09997e148138c4ab82714664d52b0e99d081a0bddf020968cdecad37f5abed48557000000000000000000000000000000000798aa0d4c6cf9830d45b2f2936a6470c7bdf4dfcceb91a119f639cef4bb2bf3aa2668ed8c1dc0732785be2ca95b566d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b2522b5789998e286b10c27498cf1d4fdd7f9f7d3a1f94093956c8c20abbac24d889d711d949b546c96572717ec0a0000000000000000000000000000000001958878c3be8d14182b6a29b0ed0f6f342db8894031a89b1dbdbf727a4e53eff83134a24c5ca9d5db5b6877fe258fa141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006678a0a8dc1fb64baead7d09427d370970d44bf3a4e1311f0b9fa36c0e4aa6af1ad1108d8b15f484dd1732f01781bd3000000000000000000000000000000000ec4b2561edfc6bebcf515b7f0c00c9bbbb601b788dea10bbd3d6b5fd93b8b940dd43ad3422303e4da39ec2a892672da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000846cda4870c3074d8a784bd877582121c0fc3d9ab8af07064d2cd27ffd3ce3d2af205620c2fe989660137406139d03600000000000000000000000000000000083b4ab1690d9cda996996672f2245cd1137f97b15f05b0b978cfe8cb226ea30628523a8b3e8bca0d2869bec385b9ebb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e801a2c295ef5a08548c771689144b051f29202fbf6091596110e6b45186917ebea855915960317714e476232b89ea000000000000000000000000000000001003dbafd6b2b2e3c7de2e58129682db674e5721d1121eec3a037fdc629edd169562d75f1a46d294c340767c03fccfb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113f3c05533ff8107a1c8c7d5fcabeac5de0620d81a5279759ed9eee3c236e2bbe0e568b6b059e2370b8e63020cac910000000000000000000000000000000000d20cec953b963d16356b1eeb3cfbce72404fd96a03f90a294aa95b332d1afb0b545c860b9490f7d1f6694b509ebe1061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8fefe9d1a7db70a6c3ac6403954dd3c392622b890e11827fb86a64d18b52b9ed729f9273ae91dd953e4dc9cd55795e000000000000000000000000000000000da7e157466b0432d3f1e384cc11908ae5985d071e221966aacd0148af8e6363566a61436c8f7ee28fc3c2a5631830c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014cca1c0c766218ef42f8f7f1c918786d6be3a7ebf3e9df0f7bf8f810cc57852af6b8bf5f377d81eb8a174c06a3aa20000000000000000000000000000000000107b4bb4e33fbb20fc8c88f76544f78a6d4d5923bd8ec90f573e5730f83b4e6646c8bc1ff5f7470deef4acc5162ca6c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa70f8de2e6bb050f35a63e0e62e0c84c5120d1ad6160d42d25873ecb50180624938dd7f117df66df9b40e9a7142ac40000000000000000000000000000000005b114dac9b66fb65eb56818724740807855af818141bb2423c086a5fd7f9b2f4e28cbef891a74c6c3c35773184f4a931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3a213ede740aa9c3e6ed1e36c32d5168d8de00db430bdffbef15aebef56d7fc5420b52c5ab19126a9545aaf264acbb000000000000000000000000000000000c75b72a641f195b18f5524739ee5bcafc6e36fbcc134068b01638df28e86247359367d350b5f13ca957e3e461fd21441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d8e5f547ddf60a9cf321b5546703a396046718828e646c20a41f606f1a56dcd9a543777e781572e416dbf4a64b69a600000000000000000000000000000000097e7a888ad3b117f5d98e60f2c646fab19cde95ce926c0cfc9bba18a4b2fe755b09266ada7b3b2eddd9304dbc637e641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010260149cabedb03e1bbbdc88cb1f0941d53ef5582b4b821de7489ad686e539eb5523a90b689bec4ea3d36fb3cbf05c900000000000000000000000000000000047c48a67399319b93ac0b4863b5da9f4c18616b183e8ec068d9e410c840451e9896de3b7d64c6a23fc13fda470e62d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cbd7e94afae4f0c5987ccc728915a3c6cb68965975b2e573febf745daa2d988a8ac1d9b41c86a6f0720019f4c90bac00000000000000000000000000000000023938b0ab049aa6adcbc6046808b0b399b002dbae87b3e3c407cdf8d20c6cec77839c5a6f8e35fa9e533a2c2a3d15671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092f46beca3f0bc7e265f61104530f00c6db87dda039a8235907f060361378889fa2b42d7e8eb644751483b10330dc1d00000000000000000000000000000000012c196fadc1d6297d30b4548bf241288cc049e16f79f9ee2109deca82279a22b51b751c15d9082b18b4c5e541c4cf441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad2c50e2e39175760977aa6fdbe3aa99c205d43a402f98e0beb93398edfd143a3694325e81243c416457bedc89be6f80000000000000000000000000000000015b74241056527fc75863a2b59b2ddfb076ac460cb2c48dd7d5ba4d92f36dcfa7cdc4a7782b17513d6879085fc93a8e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf1804c22fa51c6bb601b756ccecd020a105d991cd58386c44bba991ba1a89a4aa900c36215255b4833de151c8a84760000000000000000000000000000000005eeb082c4e15a51dd7e047834e122ffb8c43d7824ef68844102f7484eae9b8142fe00b4c8555a6dc7bd283137bdd2491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000863eeae18fd883887e68fdc27466f991c98725233cc662655d31a721de43855dd188d2a5adc46af7f11bb9a1f0210200000000000000000000000000000000015229dba420427d8b92d0671a9608b36833830f217555016b5b64e674cac9e47c2e4902de959b76f1c8f6f95b940a4561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c25f998e4a620c4e0d7ada6a84fa692465b0840fd0b3291a0c97aadab3d685272a1195ee2d1f5df9bf7ff5ae33fae6c000000000000000000000000000000001815b5406771ddc761ae6faebd3b18d873c51186ace72e57115f7e0105c4cbd3dbd11745b978f034112644ff0109deba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b22c9cae4ae714cc1f543b35c95d4e225925953fdbcaddd4fa93f321d00e82bad9b92d6c0a88e21d77ea969c0023430000000000000000000000000000000016adf022f5bd3d34cbb70f824184392a7d3ec19a4e27132f894798b9f6eea933b19ae0b5925ad7f7c2174c92d5f30f221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128c5faff3e186878556ecb9a88b1a9a554504917c6e5cf5056fdfb9dacff65391908ba5c77fa727f04f2d68fa2b0acf000000000000000000000000000000000c23da7fc5eee2840cdc83fb05d54429cff83f16e7d86193932f1f6624be8f1fd3e4f83e558742bed041013718d509001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e9c1e7aaf8e9bc3cde21530ee67f9adbb83e59604aa1f92b454c05dcd44d6a88405c3faf25c424c5d215faea27c8d64000000000000000000000000000000000af9864b7f34e0334dcf718e449538170f28bc4cb4ba05169a64c0e48de7750328851e4829b7b2df27de46d9c82147d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a657439d4f39103f2805dd02150f960037a82d32bd69f275f782e98b406ba5443ac0aabd837ef8913683f05be92e0db000000000000000000000000000000000ba380b5ab7936611e81837265334057e5f7735180a17d25d804ea027bebf8ab2f0bebcb7ea048ace4da33d0c24360ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006eb88263278f07234ba16495f69a343c102db2592592156d6b0b2f52ef9c2dd80c7610d619fc77888a716c506071cd8000000000000000000000000000000001508778b26ccfdbc8dacea81be769a0c746f16a1903e9a01863987b0da4bb210aab273271693727ae633824a06c9f9c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006149743b95562dd828284c1b71a39e88fb3b671b11f26fdb4b9512a01447b02311b5954cf832f2b929b93f2630f3cdd0000000000000000000000000000000009cdcaa6c6fc46a93a785a373b33c802161bc6196e4dd530b6630ffa1439968cc9e5762955c39aac51a878ccd73c3cfe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e433e884137ceb3566c3f6fb021ced4a870e5e4791606ac3ace7c239ce1c71c777928afd40b063ca7185ee2290851d0000000000000000000000000000000006b16c5b9f0508c67a5e04ba9ec561e8143e0087dad3dedf530edba58f2ee55c88fb01a0558657b8cb740ed4c5fefe7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d78aa8080884f5011b5387225951e564e9acb244fd30375fb7ab7dca2d987997ae57460dc4d152dfe4d2569253a09fe0000000000000000000000000000000019293184e1ec51d9f647a49a83e7ebb0d44ce284b79ca80ee121b40c2cdaaad676ce246752a583ee3994cfad3228f7d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b94d1fa22dcbdf751559076bbe7b4984e54ea950448ea7f9b7171bc991e174bb6342e2da21fc4e25a2913f77a65b7dd00000000000000000000000000000000099ec2666f4d652d0ec87c169bf21713aef5ec89a4aba2b63ea55cb794273fc06d17b64d517c3793950e1f34bd341bc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a45c2df5d29c66ace36fe9f9c0c51a25db2ce3ccf85e7120f56b5bd70052627f42cbc7d759c8988388ccc624701642000000000000000000000000000000001750fc73f51c406f08a0462604f751abe449f4ffefbcd7cfecacdf6e86613a2594a17c9c004f9d185b1f23f2e8bc18181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000390eb16f841231aa50a666b4ba440648b037c8250b1ad96cfd349f00e7019f475134dd108cde5f915aa25c3ad62d2ce00000000000000000000000000000000096debb24dcbb6c5bdc9bef9709a88ddaca6ba359a15c6baa04b50710498bbc214b2a8ac0ae67354af48bf4c7c1f8cf71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012ca70a4768c019388804ed3f9798178790396ba3128fd5cb266fc8ff715d5bfbbb8452b983383e08b1de80f939f7500000000000000000000000000000000001b88bdd3e40c57bdbcfb573a622f0a02c7fe7d13e3b6e6aa60ac105c20f6fd9d6c084dfe9735f8f0744f3d5700ebbb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c4c1cb2c4a404b456a7dce47282a881fd5a971766af43b9eddbadda793cac9264a2a227ea6f0ccc71ce9f0b70100ca0000000000000000000000000000000004ae0ec49b5c718cb443cdf08c68e49371630371dd7057c7f535ce5207cdaba73cb2621deea8e6c83ad858e7a6a5cdb91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bcba72b846275c9a54f9556bd0da65c883a18cd257df6d4780c14aacb4f3e470138e0c7793ce8f8505c88bbe8045d0000000000000000000000000000000000e3174ee1f9608f33962a4db30ef247e7ee46a81061bd1bd71fc3fa543e51919df45b30e032375651b6cdec1de1a41861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092643dd854ab10911f3d4e2da4503caa4b13962e6a02f3a8b1aeb96f807383b44f3acc7519887c7676f94f15a6b0077000000000000000000000000000000000ef023afa1164e59bc4d52e1fe2f33622a44f300644eb06cc83ee0af18423356fada0d5107c2f964c68fcf8bf11c7cd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001099228e31111d2c10a4f8fd8104c1f67eceb5bec7ff3aea03b668ca0d5ae3d2c8dc8bd878b799d4e4b01d3512e8e70a00000000000000000000000000000000043c9965c26748001c2c6b7e3e7a2ffd6c43db54d0ac293867e9b5c3fd539c4f10eda61b82c5f01315d21dee4e7d1bd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c50e0b7fbafb1761729ee402f1a0f9b1bfe87e050d1f9b51542c61b2ce0f9ba9c11ffe2828643eec1ecf682f87d39d90000000000000000000000000000000004eb6361827929c9183158653ec363c398f9ec85c3d5001275198e9445b1829164ce8b3dc83e96a8136ffeef7c843c891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000900e4c9c6ef755aa4e83a6229f4d4f14adb016c2ae0e0a6a7950de16817d055f7e7a520da3e40c881aa06169ec4a78c00000000000000000000000000000000110cb34eb673df99c751ce4fc8a6c04a829b531fc116fe1148ce99a8dea916da2e027fbb6c37aea16a4cd054649496cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1b3f4ebc406c848e108614dbc73e3f179b30ffd8a112902386b7464ff5cbf0e1353310d7f219260dd133b93238c1d50000000000000000000000000000000002c93c51ace18c4d3356307ce30dabde82b606ba3495442f93b90511c7de83f391a14febd9fe0d6560ac023398f4f3d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007fd3ccbc38b3d4b37398c0de98cea545ce330bb8796f3ff34b0434a28ed0c2724c1b893d5d2a098fcb317b356faa62700000000000000000000000000000000043be6c305b8ad9231fa9796ff3d8980b0ab970fd1cabeeaea740fcc77fb25a46660223dcc4a6b82758a1b5949178a751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f336849e1462c091ae6b7f30cb73d9cf32bcd79a405a28414b12debbbeb8b6f4f6b13d3ebb4b6abd28e1776d3a86311000000000000000000000000000000000472836464480aa64952d8f4a3f5e47fb5e72d3735a98bf9d40bb65980bd68fe7cf39cd67ef52d995b972f0c6c2455f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000917749a077036c0fcf68ce4db9ff9fa9eed138bc29185d6489e7388eab0158ad5b5b89bf9c2644f886767ef4f7e4bce0000000000000000000000000000000005240bc863997f5d079f2faecc00aaee7bf67ce298b5a9edddfb856dee127e548b3bfc8148320641cf3fb5e8b3ac131a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad3a1e0b636f92f925c18f3346c955867b17dd27a9d1bd7a8a8dfeff7dcdbcaee8b0a7207adcd0c999840f7a542d229000000000000000000000000000000000cae099f13d160d85abbcbca16270ef6b14e8e1d56164b58bdb7f51e8d36f4c6d72116423cbc9d44a9d753b55ab890f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb5ac9e5504c6aa9925fa6c1034921eed0d5818b4d30c806450ab5101c962bb86413bee10f9d18976adbdf6125adf87000000000000000000000000000000000d26ebea7d5db77dc70f43849cf7ea4493af4e5297d32f2ad5a8ff5d2fa0939d5afcfd1eda12e0e7e0d9686e8bebae951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f73ba8fd68881d40d7c10e4cd954e0dd5628765539bfdc86b1373c8a4685305e3c0d01253f9c4d0175fc23b6206efb0000000000000000000000000000000016eb923af7a0f173b5b0b5688347a8017cc22627706eaabbd169676edf186b3fc68cf5a7a743726490d515a06364b4661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001046f157cd0d5e3312a76b413754631c3d373a8eb2a8984e064bef03032c4c1ea6dc7a64cbc47ca167a8db2daa731e9300000000000000000000000000000000046ac9f6e3cb96aa5db209fdf837663e39f5288646bfa894033cb7c93c06f7071114e72cdfa26fbbd329f3b0098dcf8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008497141370663ad0f2a0fda0709704d0043716cdf2064ef9e52bc6b8816dae276d5ab0934cfcc0d942e865b2edfd8c7000000000000000000000000000000000f40a40126fccd45652c5ab2b887bbdf617082948cf536cdd75819778514b77b64c9ae48777fdf1350ce541ba41937db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074de88b95c3eed5eaf8f820572aa6e38c35df4a1252ec5547357ce63bf8d5a35ea04f620997db0b58fcd83bc25767ac0000000000000000000000000000000012f16ebfb1e199b4c9fc9780a6cd5aa0df4e274fd00604301a07c98ccef6dcd5524499eabca73774196243170335b4701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124ed5f5c532cd74a1bec08e144c5facc450286d9e49a33182f4f87db23c1092779e7a9e45a501786ae34f1dd609ccbb0000000000000000000000000000000016f703a97727df8c50acc45e8394bf5857f49d7a3127a35382af2b74c834fd7231560c60ea1328e69a6a8a87ee0a8c8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001230242be51a3b27f23b6ec72610a64d4a25e51e422949e7fe14244500e328229891b77565d72c7fccc554be308bccc90000000000000000000000000000000014c59a7845d6d73a361d9e5a9b57baeb95d4a4bec542e942121df7aa6cfbe780c603212d31712e4e359fc8b4599190f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3a4c2959886b62b36343f1f777f5bc28a2770178265948233c76c51a826156c2c96b3fc16813606c45826ced6e500c000000000000000000000000000000000daa8981c470263e71a2a9ad4e502e21267517fc19270c1b920d61a0ea60e0a5f1f9ff1e6b20a5e29404e5e3d772bd501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000011f3b5b6cbc6d0f2020033e74a69a547b34601b9d24f3356316b1a1a2598300079b56338eea9392720dac6c16620cead000000000000000000000000000000000cbbd1bc95dbaae3982031caf8037aae5feae9a35bc97fd8bde331d5a7044e4bf56fdb13481f78eaaa7e60b878e76fca", + "Name": "g1msm-4877-jwasinger", + "Gas": 10183176, + "NoBenchmark": false } -] \ No newline at end of file +] diff --git a/core/vm/testdata/precompiles/blsG2MultiExp.json b/core/vm/testdata/precompiles/blsG2MultiExp.json index 2138db409256..24f1c3383d6e 100644 --- a/core/vm/testdata/precompiles/blsG2MultiExp.json +++ b/core/vm/testdata/precompiles/blsG2MultiExp.json @@ -789,5 +789,257 @@ "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "Gas": 79920, "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000158d86d94d3fc700f62c8cb601dcf7764e6101cbb8de01f1f7b55fefc5e24e94f70746a7e653f3cd36e70f6f9eeb19a00000000000000000000000000000000017ef47a5a61b00edf11c076760ae3295ea98f5ea8e883133166ffe1e9c0033a3fc3130568d60fbc4ca34dd28143340a90000000000000000000000000000000018a20502ff640f5ccd4ef40c5b2536862bb45dd6d399d32ff4690e2470249ec3f62e5adc675b88097960810714aac65b00000000000000000000000000000000077c18d5153f5fe43e1cad6627c4cc91b9b05cc1f1661770fe873c5bd414ca06f6a660c3b1242dbb7658fbac2a4ec2381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000003b9f634aa9bbe5f1f1868c851ccb6d73772466f13520fbe90ff62ac1a4e9dc259c34f52a8ff80ab0d6e9a5c34e4b6880000000000000000000000000000000000a4e221babe00556ded0646a5dc2413eb0b9f53901ffbcb9828af356d7edf19c92161a3a0f2928260dac7a3748051b2000000000000000000000000000000000b832d19041b8c20daab73c63d140b89cc85b0e93c3e94ddb47c50f4551bc27ea73a8efb29f49a1ffa728eb284d9884f000000000000000000000000000000000f9a7b4a2d3fdf73bf527e56f711d5a774e49c39872902f2504e75548378c77a60d563bc80462a50552ce665327c3aeb", + "Name": "g2msm-1-jwasinger", + "Gas": 54000, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000001f3f7d6493293d421c83eb753a4a2e951d9b64841bb6aad436e87817fece70b87afcdc7ec0689b330c71462137feda40000000000000000000000000000000001c672bc28d52311f5b2a5dfb484f2de97da7b791b7280cbdcab636337a8c3ff92ef032e972a9cbce94076ec7a501df1000000000000000000000000000000000cefdd12c2460bb7a6abf1c562acee8a37aac4e080a3a181c5b2a7e4389058b3706d96895e7fda4843de4fdb4e24a5ed000000000000000000000000000000000b28cbe334ba5304c21c79adb2df297fd160cbb44e0fecd63164e7b77b5d6f313ad145461f21ab40c978bce695e40f5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080b4f0f275a065d13ec0757df5f9f5ccb6853690902202f06120b3df7438e62ef8d16dace6e5f3b2fdc461b707fe7e7000000000000000000000000000000000c9b3aaf853954089743824fcb7541a17d25b3b4ad821880280103e62429efd1b450df5636b1886c90e6b9b44049c7770000000000000000000000000000000000efc2727c83b7c58685632373bd043b1cebeda8ca5dce4441092b02c4d9f115e026602f614b3610e9443121285057f3000000000000000000000000000000000f674d8244e3ad6e0f624b9fafbd04da8cca5c0fb72a1029769f702295de353a05bc722862871c883cb0d33b6e31ec131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000140cd965dd0f87812f9dae22df3c53d14f957a3c72092653e142a2776d7dce04e4a4a398155a72de4ebcaad84064733100000000000000000000000000000000152bd340c9a33466215173a7e46c9741f7bb938bfb7c4128eeaa47952ab5d1ed78c5799026d3f3eb3b94876a1f4bd175000000000000000000000000000000001896288360604d3a63f8fd2d9da480ac11c1231f3d6bb9644a34aadf028269fa2ce10e04ab6372f9eacf21af01fa05c9000000000000000000000000000000000fa85a31024cbe2e330f3bed313e028e80a37c45578c429f82c4d15b3b3aeaac8cde593b35700357ac0c6770148ce3be", + "Name": "g2msm-2-jwasinger", + "Gas": 79920, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000012955d833439825eb893a3d4ddfe5760dd48d620099a2b18d9cda6a9ad219025bd01db7672047710d92f09403c2b742f00000000000000000000000000000000192ba698fc0ec408187c156e4de78a475cba4f40fa1a707b4a845cb6160ee09e84a7ecc3569f9620895d2e50885dc35d0000000000000000000000000000000013a841e58ec34358fff2921460f9fbed16d68a838a64219392245642c33e61f9cc9b53bfe1489f868e8dc9073d8747bc0000000000000000000000000000000004434fe1406840cca10e0d3b172d8ffd3989485a774f87761df7a3e162d7ae1f7eba45a52f34b5f4b36fc1759fb728251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008dfc2680bab8d9093e90c5324e2762c988ffd2d687aaa4c12f1903b468503a70cfe034e3e1e09d4a99332a7f7d2fa0b0000000000000000000000000000000000fae3fb5ca951839ce3bfb0da111a528fb1f8f869fa3d855f4131849744ad12f6dba88b6b22a8b41936dfef7fdc4f6d0000000000000000000000000000000005f26c825332db72e845d750d67db486d5ad3ec46fd0c138e88a01d878bc3074e4394f206b1182b96996926bc3a602c70000000000000000000000000000000018527a6c30b6f68e9a288146aea2fa4ca6cdf7e3f0539b37918f6e70c7ded725f0e1b6991858fd14b6df169cd712fe6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec5b78fcba23383a949d51c7fa511663a72e5e9c3ba97259dd1cf5b69f5775bb071c9ebe4d3557f3ff9a799a90985da0000000000000000000000000000000010053b3de4e313e2a2f3cbf6e53b62e9aaf31761fdf9ca1ddf784a0a7932fe219309d2fbf184dec516d283e0be02f5b5000000000000000000000000000000000ee6c39b3cd62e89b9c1ac3303acaf53c5fb15ed565eb4c7a0471e546610e1dc1e431a26d9e5362535ccb6c91fb59202000000000000000000000000000000001374bf0d6b58211fd62b6a2e674166044b8dc4c237c2ac28fe953e7dadb5a8ec128d2ef25949da1ca5d9131edcb8ec1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000011196b5b47439a23c884c0a809b7dbaab0776672b5c7f0adb2ea5477a731cbe9b2e0bd4a61a77f3bfd8739d2cef8bc23000000000000000000000000000000001647a9e8adc1d49f81a8c3336002925d37855e78ed9641656a392613f25f09b63a03563f6f169c4f208129507566c28f0000000000000000000000000000000009e90cc8f0af86e710bc9ae232f17a821d09ea9fba7bcb1f1103419a3eda7a04f99d4ad4613c5bfe0d768d187595958b0000000000000000000000000000000012258ff09fdf9ccf5727768ddc007b425e5f4f4bd93452d9bf6e3302aa9ff83ee59955a9dd0c66eeb09c47f18178ceae", + "Name": "g2msm-3-jwasinger", + "Gas": 103140, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000034887c26f5c3fcf41e4b6c823ca04b7f6bb3daef74a2c144e0e7eb7c67805b9d22eed1b3cc85b1748a9aa55c700d5df0000000000000000000000000000000017ea215ca57751c8959c5b24e9357b3d4362b22c8f8221156c8bd878ef04c9f5ac933783f50edc2f6e00b1335932e5e70000000000000000000000000000000016c81317773b0089f98201dc34c15512859170ace3c5f2ef2fac285df27c24b261ef8a53615ff4c4f07668d4a1a3144e00000000000000000000000000000000151e1f3f6a122d1aa6f70bdce5b155a8a63727a95f4d47cd159529155623e184b3a31a1481600c67d579597577dbd9141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001829dc871ed0ccf6a3c64f91c32357ad63c81cdca6ca9f73bbfa203d3c2f1288ef8f2febe56f32dc4fbd465dc19e63de00000000000000000000000000000000021abe124ca0135fffc9a0ecb1d1cdf4166d8119bab824dca6b980587420faa0a9fcc96c4a8e4a7d803a60a6862c5a7f0000000000000000000000000000000005e4fe11fdf781275b73e60a19a92f986fb5a4946386d5addde47d4c126968c57aa89a52cfac949045ef4933ec8852de0000000000000000000000000000000000c38b94471eddcff4677f91ee3a91628f19bcd7a677f092ee8311b1418b7cb8fd12d2d24466ffb18bcf4a6d6e5a21231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001952d3a09b2645bd2a01e51b8827bdd5d95fa6731fdad1af01650375f750f1c0a2fd792d953e2fd891e687e279209f600000000000000000000000000000000138cc5807661294959849bed4ae41a1e8b3ca1b79e21292aca549cf53f164696a542eaa61e37045a0b9dd671ee2102bc000000000000000000000000000000001619f340ac11abf2531d44c3a5a6ba0ffbdeee769be768edb86bd4d0eb65293aa8166af3cd5e863f03e7cd4585d5f2d20000000000000000000000000000000012d57a6eb9d4e8eccf0a4827a1b4d88c482b0cd59340ecac9c4444275cf8e09168d4b399538978c4fb77dabaf6a3edbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008882034cecccdbd8c4f2f8287d3496c4d6b1e31042ac8cb0c0c0beda3107a933d8f630607970abebb6c32413bbae0cd0000000000000000000000000000000017f66da5b28f21c8d29d8cef1c84ec6b66c387c5bbe86201526f61e6f4cda43d949c0f291f2ef6e5ad407d92c2649dfb000000000000000000000000000000000d5e6c4bd580f345930e39da587fe206dac9d96c0708b7abcf80bbbe4ee999e139c5b25964946e65f4d20aee7381ee9f0000000000000000000000000000000014d246f0c7f806861f890f1466b4e733804f2d647a133cb1bca2a41fcb0fd56192f5cfdd19a62fe8a14ec05aa184a4111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000002e2f0a92817ef3c58396993b0e467c5dd2840182da56ae69dd7c435491b3e8a57b5b092ae2189281462baa6c02577440000000000000000000000000000000018788afacecd0e2f5907d81074a97bbc4f293776b5ffc54c89d4b3aac5e4b20e68b2d3ec220ef42ec406ae1c18090d6e0000000000000000000000000000000017638dc3893ba2a66fc9e0f3055a3a5d44d36678a4e1a6d3475b7e58eb8a911b28feb1ec42a669bbe3b2efc3b669205c0000000000000000000000000000000015709e5378f7029bae3df1be83e7df9d072ac90783fdca4cd655e21f8e1e027ef06e36a49f7045230906f0fdd0619679", + "Name": "g2msm-4-jwasinger", + "Gas": 115380, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000264b8e6903cde9b853b7f6d147c3a3cafc37dce033b2fabebf812aabb024b7ddb479b347cc703667abf147622cc717900000000000000000000000000000000007fc8ca5e0cbd126c27bcdb89f6017af6e527368b74562dd56fddc36efdb890a8b6ce76cadd2ef90170e4f56f3b1dea00000000000000000000000000000000148a5a728d7cc081384160f8dc35fc9cf9df8700759d619db548991924eb2f5e794e6ac1947fafc0f00a3126f62c882600000000000000000000000000000000015ee82faf674f3de7da345e57145ad8b1c0264ed15e7c47fe73719759127024bab8ed56dc63180ebfb325bc936c81f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c77818e372824dc38d94210d10f68b3a1c09c05e95a85f9e37e2d66acc7d20e79c786d51f586a20228dddf893ff1f0000000000000000000000000000000000334b81064fdf6aa89b1abfd0668639c59cd953d5d056c37d80eb997ae7477928d82164c084bc191af7f266b1b6a499a000000000000000000000000000000000fe8cb86e2cf5d5f61d2a4a928e3eea222d6d04eed35eccfaa86ea7ff7367766622bc95b2b38f82d6022fb1e8d51e0090000000000000000000000000000000011a3ef26f6c283c089b11c3f4603e465f122e7e46141e8370435431faaecfdded7c818d6da4055db864698b52044abe41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076a1bae6858691e77777cb47d827a392f013fc3d2e851a474a0cfbba57f722f8832f1346193a93555ea2d43e0620282000000000000000000000000000000001485e7ab4a1c4e92a31614ee3ecc32baeda2bc405bdacc916ed1476f1909642a0831f6e31ab6df57dc071dd1ac09bdbd0000000000000000000000000000000004551a37a27f0e8bf915f4d5e93f38a349b4b652f9a603fac21b62668f62d1c018b5f614c0f14ff3462f24e1d60a3a22000000000000000000000000000000001144381bf3e4e6a1e6774e7b8cc596a98f815a56eea4f4e264181d39edf75d903efa2dd7563fadd6ad8c3021b8c9e5f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011083556bd3f8638dad279a2cea30ee99e9cf7a5f0a074be6c475df455618ddaac84b928d1453edfef55917c505b31b700000000000000000000000000000000153239eca7f451fa384fb7becf009fd5b7bd2ca95fd23a1c42c9b0f3e55588f31cf2f7c20acda746243e61a6a68acc7600000000000000000000000000000000021c3ba5d1b1959f92d48acaa7bb40780dc73e5890bd292bfe052bdac67463f78a466940e9fc4445809aeadb138941be000000000000000000000000000000000e7b12ccd28eb4c20cde041035e6045ec6e0dfee905a90efa0a0e09eb7953552427e5601511b3adb19810bbdb96ebede1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c8676b23e1ec143a3f7e0e790cae44a35d43d271380c0a72f5366cb74945f4e15ae03bd70600e1573ad44ac0b677350000000000000000000000000000000000fbb98e64634c44fa8637a2b88196ae9e781e148ae763fb46a54acd104b81ebe600fa38471378cf8d8ee975ad41aa8f000000000000000000000000000000000184994efaca59e5fc9061029a072994e6a4cbdc5c060f890cf630c1212bc4b13e79b2f67ccc1a2f7a1ef1302689223500000000000000000000000000000000068bc7e51eed6639bcd29da806227dc36c635055806135516aa6e497d52263fc130ab70982268213a19515a0d378723c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000b9622dd89ed150d7644fb3d6388bcaac3c1b83f3f14f0f0b41fdd9b5cdf3cb88dafae1dc7f093ac40324001ad6b4feb000000000000000000000000000000000710b44eb17a94c7374e7d1ca6ebdccdd09ef9e2e6a04ad1ede1676961c3681cdf8926e6b1e9ff124abf1441b72822830000000000000000000000000000000001cd993e8997fe74746cbb2495236c2f1cb60654832505ccaf3dfd4eda333f86208cac0d47afd11e3684a15e45dee13c0000000000000000000000000000000000401204a6fad559d9f80bdb5e88255368f12d8155466aff06aff9ce61375d9138acc6fce5ba43ca18a8bc67dbd71f0a", + "Name": "g2msm-5-jwasinger", + "Gas": 133650, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000003c28b0e784c0bb244f4aeb7b7a50c5b19fdab2231e83303894c16f96d14a58e913ea14082a3e7090fa02ab805fc8201000000000000000000000000000000000a1b92586d69dce9343ef029dae1adf641321ca3a1735eea98c334830c5c97206572584c01756e3224a821ac0da31a59000000000000000000000000000000001179e11173afc532d2535ed888fe9574fec8cc0973ea480ee7198d90b62253861bedb42ab61df556f0a96f063cc3f672000000000000000000000000000000000014081b26b7059c71dab11feb84942dcaa645501bb45c54ec46bc9d0f0daeaff5718149c26eed1a2586b840de48cf4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e8e05fc7786caf9eb246b98ad0db1ad087c64295c644d8d7b3664b062df59196ee502573c897ddc9f5f802da810c610000000000000000000000000000000010f3716b42ace8817fa1598b006ee09ba2b722572778acd13f09aa338a046c90183f44cfda57f279815e2547b4105096000000000000000000000000000000000f7b22389505f89531fb39dcd5a19305907df6bd07f838d5e5df07deaae5f4690d5a80fd0e31d2b00da582c09b318d36000000000000000000000000000000000fda566ba950611732fa913093ed4de14d9ebe7d464c3ab9d3e454982dd73d061fc514d718db01e1f23a21e8820b5b991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb6f7e4922d351180e1837f120ae4e24ee16b25319c6392a1b0760b399cb9324ce32322797292e10e87cedea04230ee000000000000000000000000000000000c16431b689d0352afea68f471810267c7a150f37f023d1e5fa99a1ffeafd52b6349b110fd9034ee1757f6cb62653fda000000000000000000000000000000000cb68b09f6b8664c4c7ea111ba4ecf215ce0ba778fd21e26080b754ce3e7dacfaa1f404e270c66a6563423a731d21c560000000000000000000000000000000016c851bd4c7c31d026dcbffce810ef65f519e047496729d853f61f48800a0057cc7b19c62c7edda4da979334cfd94fd81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122d96db38649a223d3934173c89879709b9fedba7deda40755731b4e6439942dfcdb3b1ccad148bee73e333558e9a3f000000000000000000000000000000000602cfc2fa34b92bdb6ae12abfc12446a076924fa685a0b0a3425019c087c9bcdcaec7b7072348fb8714afeb9b9cf919000000000000000000000000000000000341350b4b583a014871ddd15cb1667724ada0515a4eaece6692290b780504cd92a3fee6c90d6170ecbf2d5858470eee00000000000000000000000000000000141a45f966ca47d33f352480b9e1cdf5aa3e64d8c64a287ad29dde9a00a2421e7d604034614b90089a4e7a98daf7c3871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010605c2ddad43cc6960723b6509bd8c69aa0b92e886640bdeb592d34eec39fed15595a518f08c0ab87670d7fd75cb15c0000000000000000000000000000000011163e5f6702fe70d4b40aa76dd37352a09d5a8771fbc891d469dc3a3c8be59824a853f226ba80d09861a757451af3e7000000000000000000000000000000001184335a7f4c179727827670e21279bb5ae3e95eca61bd73e4324dd29a2c5eee159341d2bcd8aecd2aa3595718bf51690000000000000000000000000000000000fc8b8c9304f1512a9c8106bf807f8f7503b4954e9e30ad6aa1623349e59bc5fede56d5f1b6136d212c6c8147ce9f6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000011ad0b137b369e1e03de266fe9a50fd643a5725ab49bd14c5a35ac918dd022354dc138538018f2096ec129104925273000000000000000000000000000000000152b72b88b7ef02ea5131b256a411cd1775ab63e1d1bdf6ba29ca03e532a964d407fb6149b11c12db0a6fdf371691120000000000000000000000000000000012f4cb12482d070c03451d5beb9f01dc3d9c4aebe5a6d33d730e1a3b1259e7fb038f6d34f8a377408eb76d4744a4489100000000000000000000000000000000182eaf77de135051f31fb43dfc13450173983628fc956ad82140b22ec8b8f15441a526c90d796a3b64fed0592f0276291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000012bdcc0b1abd50c9389903ded99facce7ba0675a2101428f8d2632cc67304c07cddab92beaf5ec72605718604ad1bc8e000000000000000000000000000000000d489d7255979de8ce345cb2187cd2ed0308bbc3ce3d567365829cd99394edc3c77db561b1daccb9744338496cb8ca6d000000000000000000000000000000000da9c3d2e7cc60a2b2e39dd3ccf2f9552dee00f9bb4b578fa99c0c4042b1bb1735f3dea8d421c7e1c05450050fcaa274000000000000000000000000000000000d7a574aa832a8e388180ce22d1de2e1e22e5dc475f7142a6ea91dbacdc88577e2d4e14fce96465c6a152a878ac6eaad", + "Name": "g2msm-6-jwasinger", + "Gas": 147690, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000001568b92db6295c37f458af466eae1c494332a6980a29076bbdd3307848ad30e4fdbb2d8af58c4748763c28f0729ce4e30000000000000000000000000000000012d5925beef25addd1cf1b698126ab62b315acd1f4deb017ee0d04d14d1f76c78838b3dde1a09e8b2acb22d8857d84810000000000000000000000000000000010f7748e4119b43556445137ce528ab783c2fc1c8760c0686a17965bab9662e9808704016e6924fe2c92cb6c3794274200000000000000000000000000000000151a2661adfeb23f6e9f00a0b6a0f74b79cda8eee6e7e146901934986613dc50127d6b59a161f3b0f522d65957a3494d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009712947b359bcd80ef6cbd93e00a64f77a00a85d8884c029ad492f04bfcc644f619e1e1b72aaed4843f3529ff36c699000000000000000000000000000000001945ced21239e584a0387da586bfee54b780691d2fcab64dccf34d71501e0d8d91e3581ff5194a99bdf58a149f31e84f000000000000000000000000000000000aa17236fc61c15b162505b8890e51a535cdd3d55421fa770eee997e0321fdbb0ddb7fa8a0b3854440fa3c42904f9a81000000000000000000000000000000000739c89fe7ac697a0f0204ca6ec6e809aa838524de3c1c3021c0d19e1f04e988d058941d43253b836de5e783aacd7e351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019fbbdc17a4f5cb310b2cd0687036a4f968e72cb1f017b055c89989eee9e9e2e91db5ff84186e217346855abce33d990000000000000000000000000000000000f6eb30723f5975f9a79541332ad9a5e153e27a5c677f32b67c19713b8c6e347875e1f5e5b9542cde5eee0f66002526a0000000000000000000000000000000008ddf6c1f70c8f94643f85dca5afb344862a93ee5add41625861734848f0e3495a9dc1cb2c8c2d28aef48f12f68eac4200000000000000000000000000000000120afe3fde19116c36085a2d772af34e5499ca3eafc2f6fd6e4d58f16c1bdc895cf4e203155bfcea1c8b35e7b64dcd251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193369de554724ccd465adbb18f150f21d6def7a3d29f0a14407d9f5a8bb43b680b76cbf2904beb9668b55006aca587c000000000000000000000000000000001920d5d4077a24827c328dd5e8f4c9b77d47d3f1e22b33025fd48062ceb2d2cba18dbfe284d3347c9f7410a13f2e0d670000000000000000000000000000000006d5f676a9122459516b3b0dd88c9ae1ce682e81989a8aafa5af304d65c84db0e529c13fc1a81c09d80685af94230f3b0000000000000000000000000000000012bffa58dca487a6d8db92417ce6a56abc5ef22679533f9cba295e782bb8fb6cf08b342dc69ff44d69544ae4583938401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021ef3b8290f8b747896421c775add14710260fadbbb7c9c9cef6fcf94b9284b37601adad248f3e9671e380b7176c7a9000000000000000000000000000000000b4de709f6b68efd9f9b2d4a0d4bebdb7d3949c2abcaab2c55b296ce9bc7794cafddee83d96fd18c577f92442bb31aed000000000000000000000000000000000827ef6bbcc4081fdf0f58ad097a0448749f2fa50c7194102dff18f1ad55306ba9ba7bebf20790e38e8353517d48a3b200000000000000000000000000000000094ea63e52ff40098c2fe212edc93a1f81bdf804da9ea0f930c79d733f3b100414523c8149faf3fd8b90b133010be1561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199c117f57283df4e23d9e75d150037f67e48add03fa07b474b2ee15f4d9061258118f135471652506c2a4a20ac3ae4b000000000000000000000000000000000777bd3743b8e43955ba3f62e1f27c2df72ff787fbd69a25841b413c2b33f213212284833be11af2e29c6cd7b5d4f6210000000000000000000000000000000009e129f8c61bf518bbdecb3c87d8f82b8fb51c5644e9bade9f83cfb09e74ee764000df01f8be72cdbf7875fd23db803000000000000000000000000000000000109900bf0b6b0a6187b3f57db279f34973d6d1c7bd8e0bb15c27154ee6262d0993f86a9e0738954a6bf6fbf4ac54b4fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084ac228ac522f5346dcf9c904724827874bd4fa988f9335bfd034c0b4266bd8e3f038ebde74bcae289e25a20f208cea00000000000000000000000000000000157daaab922bd0f73d1d939360c69f11f06b4d2e08d6268df2521c2a28cf27d9b2f361d5051c0f6c6d10796a9210396d0000000000000000000000000000000002c39192261482337d32fab6a97865eb32d10f04401c760f6ff8da444c25219793977a3f9bb7a64516b407b07c38259400000000000000000000000000000000079ab4c19fb32a14516e55048ae47e3b472925fba7e0e14da9288c618b5160cb58cf387c859169bed3b7adbc957d2bd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000012a89aaa5ca532374c26dd42588c6aba4b2257208fd39226001a462216f36ba62565ffa427706c194c1936895b79fbef0000000000000000000000000000000008b26eee687de31a2447034696aaba5246d903c5e91b6e41a685ea823cb47ea4435c2ea656613b60a0a9bbab3ed3900f000000000000000000000000000000000eb4e9259adee74de0f091d201e6ebc39ad57cbeb007920fd7b32d1e2191be06735845325ae194c2c74b9a20bf07427300000000000000000000000000000000044bb10e1908f5779587f03ed1475cb85667c472b147c216ef297f240ae8b3c0acc21e8ad6f556badc3a78377d5a6d4f", + "Name": "g2msm-7-jwasinger", + "Gas": 157500, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000575ea1f8933e5f55fc5ccad48f195a0da35ff7ca84b8b483fdfc5ab3e4acb73f1074444d43e8c49cb5c555924f2e93700000000000000000000000000000000004cad6b13c7f09505f16e16712180063285918b1219bb9573413ea1d145ff9ec99601d6e7fe95af6edae55b0fc66c4600000000000000000000000000000000093e948124e2f221072f3711a52acba600f1f91d45ae41df55779b8f1f800e83bfecae3208dbf820259dc1ee76f747a900000000000000000000000000000000139a5f3f8ff4441750f4cb325cf45c9fdeea444aea56ca5c9c7e18f249c91bd8a7d893e53df72237a10f3e0048855ad21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045595c3980dd7a591051aa17815635cd625aeaf13ad30bdb5b034d4068945f88645d58ad79aa9781c1b86dd8f022862000000000000000000000000000000000cdb542b7c6645599d126284ef1a2b2e58e1b2054bc676db8ae97f623e2ccf37bdb02d8b6e2fcf2d6ea04de12256469b00000000000000000000000000000000014e1ef7d3a85eec28a763ad5d5b70e4a391f24cca27cc704be084325f1e2f6703e6dc670e5d5a6ea1040fc77ae9324b000000000000000000000000000000001013fa3ffe53d4f310d14928e8c71f946f5b28f8c7b318808c7b352f0e95cd2818590bb8e9512afae75dbdb72dbbf96b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d8b19883c03b99c6362c6dcce333ee1d22255e0bcd0568c0755b60c63243062b9dc587e675b5f5527e05ba8c7a02890000000000000000000000000000000018ecd7994e99a01f1b6fea527c9d3e9ddb64872bc519343853bfbcc0de8ca36c64f8d7f797a04aefb614cf58ad1b812f000000000000000000000000000000000280de32de8d34b3e0a2e81383d0e4b8dfed65bd5c7d260112d6bcf3301dbf4ce8a86cc705c03df34b1e30d7ac8a7e540000000000000000000000000000000019cae4d6a686fb66981a69b4c10e3f991a74b2857b685d396075a97e639874998675c0ad274067c6851cba90653440541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009fd66351e373bdbb9436099988f4f27f65381089396ecc641c2daba14b0c058e10de17d7d5a9b73345dcfd47738c4400000000000000000000000000000000012079fbcab20c102f74f72bf8de614bc4f8f995fb70ac5184c3c3b465533708720917b6600d92728a77a6ade55f5ff3e000000000000000000000000000000000a45023e39efa97008fd99c0cd05e05022ad007fc166938f5a5214194603f7b4302d675402cc1c2f56532c1011d91c910000000000000000000000000000000019a01ad236949b0b09037538063d6915021131892125383ba16d2f27837df5de0ec68f413afa9cef1c5185525326a8761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152600e1bbdd1c1b39f31bccffffbeb8d555b4c36372f1fed0d76ed3fb0ee7ac3e1868acb15e235b56522b51f71511900000000000000000000000000000000003c7e41c5928906e5ad26bd4bcfb575321cc1461126faed835b1cb578cd1b52ea83eb1d9abdf7141cb0ebbf5031968970000000000000000000000000000000005ce5b2e43f16380a7cf3a5a61f128800118784f3d27f4d8b525c51704285c3c93ff05c1a39f9ab272649163f138abb00000000000000000000000000000000011ba10720e35c7d9c67c3b86e9fabf64ffd82939e27d5c747890691cc49547a5153e5c32b63f8515d47daf2f67888e501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e19a37aa40fa653a1dec08e719d27dc138732c5f6f7499b852ab3a1625e372d1249d5493f404eed1bf9945dd64113b3000000000000000000000000000000000269294c8fb03e274b3b14f9cda3ffab5051542d71021f21d1f37266ad528ebc720c27024c97d6bfb7662a2d4081ce1f000000000000000000000000000000000941fd8e25bdb097fa74d5a4b6b2b7d067d56d93ada09e1c8565961747b3cb1a89822381a6ce568627aad5826de57d3c0000000000000000000000000000000008327f9bf13158e2ea8b03eaa2ce779fd3b326873dd9e081751c0eb3e9391015685d363921018943918370552d4d4f991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001108d1465cbffaba39c656b0dcd6e6b57503de65de2b78e17928d85c491bc6e5e52a59b1c6c1a4ba7ba0f19d784403f30000000000000000000000000000000009f09f6929e664fb8478688c1a7521e775419385e4fc2b7f0753164bc5ca688a6b258fcc42adf450959748fe606784ed000000000000000000000000000000000e2e60f3bc28a0d2b2304f46bea5fed3c46c9b7c8feef3432e40fc3749159b076f25116ba508b0fbc3e522d2baf216ab0000000000000000000000000000000015306378e771b076dde6587595cc9034f424d63cb21805d45cb8953fe06141048f8f6d7a983e89d329ab9a6deffc51971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e8b7adbe0527ebe07a97e53603f72ded2f53b50e8ec63849c858119cea23be3517227579e73c68fcfbd631663115fd0000000000000000000000000000000003de60f3e9eaa460637b693daa0aba0b7a819d5084bd9bcd5714eeca0538ea5f737756581d9eb3787d1d54f8fad2655600000000000000000000000000000000128acb8acd9be6207516a91e0a33e8489ea5b23f8edde083313deda2efeab74d0b3e6a38cf0d9d3b770950fdb4465e270000000000000000000000000000000014ebc2a17b6aab8264e824e70fb8748ea812e7ea7ece5b14f4fcabf51ae492b3c0618d309ca5aeec168b84bcb6028d711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000a8bad24149f85c641f9ece6e047ef5814be0fb078e11df9608325f836737d58995b8b6e616dacd1b7c978532e0880d0000000000000000000000000000000001153ef4fe4278ad03c1a435b15aed7f3ff6c1df8c630e5670337dce06a6c55a1a53c52ac1257d96799449a04b4fcd9ed000000000000000000000000000000000b61e5f1e81c7a07b9657133c5aa033e812494ed2b9bc54ff6f5bd7c87955fdac77aebc6275764c974978b38bde1e21a0000000000000000000000000000000001e02d5a5ca3334a2015db20a933fda95e1fffc018193ed0b8c8548bcdf6b83b2055831f523e3826ac74d1a7317b14f9", + "Name": "g2msm-8-jwasinger", + "Gas": 163080, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000001621f0d35f31fcce74617ec24a1482ad75ba0789b0fdf77a88c22dd1cecb4de349af00f7aae786d58f961b148260ed580000000000000000000000000000000009b09b16a22c62519d577601b8bd1290da4203f07ccb2d7b8aaa3b871d089362cd6ce1e702b9337b7c9723c0526fee9f0000000000000000000000000000000009f39d9b34bb0146fa90d238efeb6c7f84b077fd84649169fcc279d1863e35a0b9b8f9e78d41180dbb017b718f10a73500000000000000000000000000000000190924985457ed18019749c2203c853d90ccafdafdc0daf60a0efbba8b8fa3483a3091da0d082075a579c6de85f55c0e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165a09a80c33f5330bc74850e219e0e596eb0775555c4e60a52ef6ed1685b4696af225f179317a0cb9b34e153f41878f000000000000000000000000000000000edb9f192d3a29fcbf0aa47dd7509da9e1cc8157f679e517a20b75d2201b4cd33c77c2143134558ecc4a18621e93a902000000000000000000000000000000000f0a96e6791eb2a3ff16e24841f281b9a97867ab50152d91cd231003ca27b4ae619ad50c6bc66ae27c87387355eed1910000000000000000000000000000000015110f325518a5209e6a1af8add3fa7d6f049c3fc39e5d1b2b0a875cbb3a9f5e28cc1c2f4dba0eb13a28f2e90d3443d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e4704c71440c2f02173335834d75420e81575e6d48ea22d1f98468e5a38ac437180a2637175040c5756c9aeb276c7f000000000000000000000000000000000f6567cae1dc0099851c488b5021c1ae1abb89c9a2f4e7cf43697f2028c70fdd03bd35ae85a318a4b54e881a22ef64dc000000000000000000000000000000000514714b7ca31130e691ec29c263e97ab07df083962929bcfa66b7f924360ad02700fa34f28774a452eac57b995fd82300000000000000000000000000000000025d5913fc4854ab584998dcc740c98ae35f96246f3b19970bc2e17dc417f57b969fa741cbe7e667556a3ee1d57261311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001a002aef2af04d7c6d7ac63fb6edb72bb234cbf632d74d43d9c5f231084a0908192f265001f22d0aa5f5129bfb4d69200000000000000000000000000000000002d285f983183ce7e6de746da4d1d2f1513afafba16b813078105d06db6a096dfc325d465998473e86b05ebc2c01262a0000000000000000000000000000000006ef7f5be82136df386e66920d7d9e8009a0b39092f03c6c43e2393f08f8bd95db151f45bb15cf62883e580993aea81e0000000000000000000000000000000016c73809dd371e997a90bd9cb75b439bd93ebb6865ee31b0864fe4f45b79a7a20102035bf5044bf67803b8e7684b16501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000059957fd17f908efb9dc4a69e50d35df422585e2d3fd3d47155b87cc5d8b083631fd735926cb74d5c610f20822619d7e000000000000000000000000000000000da4b42060d9a12441735659893d5c31d5b94b5e9afc85a7947a82fab47ce90f4c598b29a27c662e126331d7dd71577100000000000000000000000000000000003447ec2ab21ade701eddc7a8e9605334f45aac2c9f45d1bfc4608322fe175e1f4d70764cad5f339d91ff818c0667c300000000000000000000000000000000060993a10a1856cf73b64bbdc1ad2f0cd9ffbc6e97e515afb0c14fb8b6a44d7407137bdb17d877785e893f286a8f27dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3326aee61077d4a020721754ee581235c8fe821463b3127bace73e6e4270033badd7858fc7400fa8fec9275d5683420000000000000000000000000000000007499936b653675f6b60acdffe500856c645d1d2c57f71012c188e6fc67d045f12bcced5f8af389c00d6dadb59d019af0000000000000000000000000000000014521e78a2ed57d798a990da4a62c5ca0f375aea24d47001676e59c2e089cecc84aaaff6d6a4d8718c098382f678c0200000000000000000000000000000000016410b170eccc178224c4308cdbc26653c7e511a4e98ebc8ab15c34b9dbdf9fe81237614df77ba59ea3fe88dfb4971841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000104216a309450ed821c26fdbc0b3b3617dc865f20969ed176c2409a7ed4a3c3c7f45c28e740c3fe06d61ead435a750300000000000000000000000000000000080ace8581134aa7c459826ef51f6e75f3a9562609fdd525f0f2d7474d8c77c1ff5a8258aa4e1a5b3a26335caf3e1ba600000000000000000000000000000000084b19b0de645043b101f6bf675b89d3d015a45ebd50312a0b4c5b5ad7221b7c1d513cc809262e5aa7b2b3b6807668c3000000000000000000000000000000000edd873e1689a60b3d0723aa3250f438c8fb96d74358e692a2d394d5cd9f25c84a125faae13fa3636dc8fa1da197f4171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001947dadc31b975d3c5f91d8b95a43644da6420a3edc85abbc26ece40832d94ad67347a9af59e9a663c4cde3534552529000000000000000000000000000000000cf895c88df23ae1d14a37e00e4bfdb051ffee35083af4c7af2e3a7e796bc0077db6cba5a9ca07773db9ab4d3e1b5ffa00000000000000000000000000000000156ccb455eb3272ea3a1b1081b83055746703cff0eeb34805c5b3989a4acdbef2c4fa55d1721e14eb25e717e9c2c24ba00000000000000000000000000000000189d0ee948b73dba11d65b5a88389c97a9720ed47181f0d6d1e2aade537b4f75c779c7a7c33045d4770857998d77f7ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dfc85943c1e0e44fe73bbd1c3a196d8ebe52dec5f9b33e96f9bfac159533b6dec84ed5529064c72261f9511664f21400000000000000000000000000000000184dc627dd2bd64c20a3399cd92242d177d1b0603b61c85e312ebddd2d58c1360fb893ffbd60db3511345c2c9e59bc380000000000000000000000000000000018370f49f7759cb978ca6313dbc18e4fb9dfd2f1f7194fa07632300e7d6163429a1f69a69eceae4d80a2eece38c9dec90000000000000000000000000000000018fb7d2608372060e6bea3c84650c3242d7590fb26e3d919bbf1a79f5174ec143c879a6df46fabea0300f9cc9394a1601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000000f1ed819d666836c267529dc11afcc81e44e83a4a503879c81a835eeb43468d229d3d6ad210e8c1cc89edb6561bde400000000000000000000000000000000007bf57030ad51243c4da76e66bef2024c0200d2b8a735975946a2086074393748269b6359494a12a98993313ad1529dd000000000000000000000000000000000e8e004b23ed9319be41f44ec4d58b2dc17daa7bf50f51eded2b5603eaa5057ddcca559893e9936969970840b1c3de10000000000000000000000000000000000674ba86e7993e9c56d309de3a5df99f0fffde0e991acb8f1222858b2635d073da8799134498e765d9f8a5638dffc64b", + "Name": "g2msm-9-jwasinger", + "Gas": 177390, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000000be25c02ea5c498e387e747aa2e976363d1d0e846673f62e596b964bdaeb5f569276e4a45390ecf59acdeea7f409e3e000000000000000000000000000000001438169d876ee4d793c8e19aeeeab14ae06638be9cbcbe2ade830d8e42afe598c59e762eb8d2d68313ae5595f953002e000000000000000000000000000000000eb493df804325610ea6350d7ee9f46ba32c2d0e7e8bb7f7fd2c14f3e8b912588522fd98fd6f5f1de4ed4002632591300000000000000000000000000000000001a6e862b2f27f1914bba24e3cbb1312695207d1c9fc70d1b144903e371c7edb941881455730097e2253fd1d76122f8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000022fdb3e6638255f2d7289f6e3a0407fba28fcd8d4e8cbf04fff7a9bf4adf229c59bb59bec91c6c379ca348d107ac3b00000000000000000000000000000000084645b242d56929a911c9e3867248b1bf4f0c105f7053345e15b181fe72b7c819575caff968e3b53d9c2432fcc2c8bc000000000000000000000000000000000e4cd1027858b45d04b67ea133382331e6e328aabd2b0a68ccdbc6c9c6140ddefffc9a0e79b2b84c9d17ebc5521aeeaf0000000000000000000000000000000008756525a1e56e20eafa20d8beec1769cd84ca378ad81c24015565c8f9b7f371b48254ab9aa6d3ac02700b772cac49b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000096f7a561f19ae8c02c2a3caa1e1d2ecac7a4c8b7f6bc77cbbdd01bc7978ef5ddf1505228cacb5093cf1cd8b0a8ee7c2000000000000000000000000000000000f57b593530d2d8df3f492697f5d80174f170f286833e43bbbc5001356b4b24a5e61d9a43672b0ac8673f781e33b47d9000000000000000000000000000000000b8229376c3daef017c82e8dd090ca268c154b8e8a8a77ce490eb4607621c7fff3d6cc26eeaea2f52fb4e4417fa1c7f5000000000000000000000000000000000458fe40dbca2d845a428c785707a7a4ec05b8731cd064e01a4e138df58aa13ad7e16cc2a87f48412ee2a12b191ba7a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188abb04cd4e91731b30688f8f1a550bc35aa195859549cf505ac4d6fd44f3f38c62ac7adc2d2507fb91112134a98fc40000000000000000000000000000000007dcc5f1a5b6c8f1c27e36195a149755760860782d2da5a865ed51993e7ab601dbdbc1e7c5669cb28fb33a2b221be109000000000000000000000000000000000c6e5945dc170e0885cb29f8fbfc8f597e4a0a5e9bf556065286ae0fb950b9685755bfbffd8b4d0c63fe2d8ae885443d0000000000000000000000000000000017fc476b3af209c55d284dfce74979fdf09e6a07546c76a7ddd0c5c3eb01018a512dea01c1802e76925a882ec9cce1531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7a6f882f9025c37148cce592b2761724ddd51c2489749bf64613cf5723eea93ec37f3c594a814e894607fa509516000000000000000000000000000000000000f4a306f58d80368c6c0bf76a53ded3da11073233b1388b744d760fcf5bfba1e13e509a379fb029e76d794d462abd010000000000000000000000000000000009599f6e3aa840698aeffff5930b5c60a94e3073e9585bfbc8d981695ee9267509715cd1333b0c67ebe62d18c1740bf2000000000000000000000000000000000230ef7858576514567ce6256b9887d9f3d29d8b25db893321f1ecf140349078ee1b61b5efe7cdd751dd3c5e9b8dd7a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad1aa5f390dcaf34f7763fe580a04bb3469b2aed70b63daa31ab223239a44ad694889235d7b540b6b8abc7ac78fd62b0000000000000000000000000000000005694cc9a0079ea096c12a177727df08ad58b93173efb09a1eb4876638b43a55c946b71e490e6c80f836f37a0b04991b000000000000000000000000000000000ed0fe4777908b1362ade390d97e6871450ee7d9a972503a4b7dab054d5cf6a5d4b5ffcdef05fa5a42413adc4e523a5e000000000000000000000000000000000300ae41ebbdb6968ba574d7495d160d72c66e94d2ff8c2ceb756f6225e28184424a0d0dd1255ea0dea760a1630c76561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000811d99bae042fdf2be044e7b456ba056a8338accd05d32275c7c04d52400164e1851c7c202ffe6470adf88e7c86228c00000000000000000000000000000000010f98d0abe29f7a7299aea362f135dd1cb76a40efea8b4bcce060a11b52ad432c196c6279624ce6bf6927a0938f57e200000000000000000000000000000000001a87362c2adb0d7e90b9bfb08ebbc8518830020cca53c72035b82bfc08ccd618ffd00c368cc3bfab9b17667c6ccc4700000000000000000000000000000000116bc061d571eb4a105f29fcc990fae9c350cb46747cc261124271ea1f7eb2c80d8e0daf70eb1550563197f06239bbc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016faeaa0b84257f18bb5bc8be672bc6d48d863acd8de48131aec15f21be9941775b983e20ef06675ea48d434f6c7a3c7000000000000000000000000000000001704979d11998af752d1633420809ce7a5276dcc3b12f2d9b775f76852ae804c05f3a859f872a9c3e0ed40622fafe405000000000000000000000000000000000ba589bb52347b7ee22979cb1a66d0123f438fed02c91fb969c8857792dae814ba15f042e57761efdb9efe9e06b409dc000000000000000000000000000000001485529f22b2b852870bd7d7b949bce855cb39331f0e18838363cef8593c26108f3614e73be65ce7de4beb02d940c3431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009239584f9b79df4953f77774ad8045ed80cb9d3bf3c898c35cc8bce486749cad2f00859f16cd82d368d68b5242a217c00000000000000000000000000000000142af6949adde4ae7a4e64b69e616cfacb0689f19c7d61b89bd1a9ad9df9ece9c313432b526213b4d1628fd087f4685a0000000000000000000000000000000017b56b96cb323797ba88f725fed7ebb1fd6b77c51af559f9e549a10085c97f0945791699385e0b7231c889c9bb58e92a000000000000000000000000000000001327dc36c3fb1b15b04c379af912558d9362789e390cc7a95b9a6ac9e34740300d8c5f3c06c92ca0ea56cd00c23fc2ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004a27b190ee24457764c53a326aefe801941444b8ae154afe4e767fb02b8836c00080a3c55308bab4f999be28beaf310000000000000000000000000000000001c6c3af694bc0c4fac3c2f57b3b4c16dfce24a4617c231dfbcd5ad5b01c042de3938828b8db14039865f253b33a0ccc0000000000000000000000000000000015b7b2777d09bc0d839b18d0faf666806110d5680c0f5e15963616a0a5d44355844ca88ab40e9bdb3f413b6ae40cee6d0000000000000000000000000000000005417df517082cc414895ea608a120915a89617e5a27998bb0d84c3d2da6a3092635f7a02e83164c653a0071506afeb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000001774b6bf3891cbded4214b6bc9ee92a87909fd0a40dc3c30bac5f08ab53d186b3ed644ed825c1e7e881d25fdbab221d5000000000000000000000000000000001731dcf5e3abe3f72903661ed31dd8f8e66d9fa415bdf54afac1082ef4d21ea78bb7e05eac2736805a8afc73172bfc5c0000000000000000000000000000000006be2608759b08776e344d3fe093f0c04f963ec35f01cc9019aa5e9e4a7593a9f42ae8d768d60b1cdd1055ebc53d9284000000000000000000000000000000000a55f60914e2e99baa61758d43a6e7fbb499265d2603b5f2458952c596e7dd97588919aba8a7707e20d9e0228497be61", + "Name": "g2msm-10-jwasinger", + "Gas": 190350, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000170ba2b9c5b83714330cf91b901672c659c95ff93b21c7007aed1fbb93097d096c20a96187ab3e79295801a156632f77000000000000000000000000000000001910f1a4066a17511fba37247cee3eb00569302016e74ce655c52a4c6b5fd571d463907d901f6773e77c6534ee6234ae00000000000000000000000000000000152c08b790bbaf46067df8f5def65e2d045e3695845dd7729acec5ee3860bf609197885500861c95834ebc3e7d96184c000000000000000000000000000000000200b959936e0660fbe3453dce595f686fa297cf21d558efe485927ca636e93f9a0bea0afd730ce6d9820bca8d2cf4d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000030e531fa2d3ce4d87b1890c712d881e54e22779f1b7db00d806f623508d5a997a569a00c32c5af12cd32f6eef89b97000000000000000000000000000000000c281190700084d7a2c3678d9ae67bacefd2ae7e7e43f8bb3e15d684c2381f4f4e6e1df446566e00fd9c177df60582520000000000000000000000000000000013595138de00cb7cc7f1df4821921cb2078a902d293d625c3e156e7f0d3b3a3763ee2451a11944829cd18b7b791ce99e000000000000000000000000000000000faefd77293fa9fb19f6ce5b55fd7f1b7c2de2cff08a0176f4f44423a63b4454c39aca4dc7a10b7d558fd951211b6b6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfb5f495968ab1eab77e9a42dccfe5886e81e20aedb73ec3ca106fa75886675a5e918cd01b6b1f0ccbdfd7993cb61a40000000000000000000000000000000015f89521b26cba44dcc585f464728a0556b11fad52bddb563734fc1cb56514bf3279dcac05b87fd105d615be9ef0d0d40000000000000000000000000000000012cfd925e29d9a8163b2c1b609d1fcba42f1432bf4d222e570bfface3d746d1048ce64a4c07e4eee1280d6436bf37a70000000000000000000000000000000000f1a40935cc6777d51ec6c422a0cc431be6de885f594013d9c2a7ca52f8f0dfcdc85d48e354aa37c533df55abc6c8dab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a16837140505bc33f7a508f6bc2a60f434559bff7f8ddd073baf74352c95ad35c530b1239b46a6be5d8571023b4c85e00000000000000000000000000000000088a27dcf4cc2e462c42fb38cff1b9e57ddbaced3d20c687263bdd96931bc5906afea98bb04f5afc509dadb839fa3c1c000000000000000000000000000000000a54940cfd303d07d2c56a79e907eef6a78b7c0ec3ed2f69f461d5d5e04d72008ac484bbfb80300b54adb4ce6dc97d3a0000000000000000000000000000000001dcfbd3af189e55c284fc3ececcc4810983a9898a75fe03e2973a762180f9d4264a9bfcdb21c8f60cd915518a93efdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d4548b7c765dfc7c1472e4439a969350d06543cd6b2753b8428c4907b080773f0ed7b0626f176bfd95ff89d5bbfa260000000000000000000000000000000019b4c05fb99be599c74cf2fa333c47fe595b9b09efe59187502a71b961d39f34361e04973c07aad4befd081366c21471000000000000000000000000000000000c7c6e726567b74f1020f6d2c5c233cd69dd376a5b8663d881335453f711af80ca19021427c1bd023428be15b4da5214000000000000000000000000000000000836222ea956757331e86a9a0699b0ef008a5bec05e5195ef1464b5ff6995b87d463b1aef9c3b0d2c28f0649126df8141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac183d4075b2d856c2b26fed5632eb4eaffe1958964b06c3ab86f2da7be2700ad7c86bb4c0197e8a2a76e7f50f490f5000000000000000000000000000000001695c676b22f4d2d9afc01450b6adeda6acc29a78b076650d7effc02ccd1b1a91fae46ea443de6b9e86e57be6648a2b60000000000000000000000000000000016e30c84efbde796c3a87f66be1c0dc1b3cd7c70a65f040177da67af4a2dadf34c49577bb962ec665ffb6954845edf43000000000000000000000000000000000ceb83a44e92644d77e68237bf4764f9b85aa3308cc012ae54df2e3237d793d635de23bdf2d89b97c22a922d687e90f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004fa38d20e6b8795ca83d38e4670e915c0bd9d2267a15269068f633925398c42f3fe75fbb89ee6aa32c15a9e46ba27a000000000000000000000000000000001764cbebb4c2656c71832dc1be7b45bae8c1787af59f56f01f74ad39182a3a53de209f5620f5fd91126d013ee6267377000000000000000000000000000000000e7ebe80c143673b472f0bde0a6405084eed72b536c4991a20d1a0e9bce6e63f0dea19aa4b225f12cb1c93d5c4212fc50000000000000000000000000000000000b3848dc47d694547b8f954859950d7fa69a75dc777c1ea967623a910538d63f5d648499dbc100ecc84770c1be2ad161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001518e9502ce3b13b7390aa476823aa1cf04205c8bae47212b204f8f5d395d9875d9e918b92050faafa6b3fde5f720412000000000000000000000000000000000cd206e4fd5098630169bd2a4c16b50640ea23ad96faf204fb1d60933054eb2189d3be0d0d30b7863d0a294fd46f56c9000000000000000000000000000000000cbac5151187ee126209a12cf4989d73a49952bd5d24fd6e53b382569299f8c0b5dd4e99fc63baea1d9f76e7e2f70c71000000000000000000000000000000000f5a897b7fa734198caae2a709f0a0eda5fc66a4547b454d855788d131442ede46aa2711d2a59b55fdb5c1a286a4757c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b8ba4b924855323b1f1a83e7e9294ad0797dc9c60bc4c8976a200f61692f0d0fe38998cceeda4b92d88c4d7f8c3ad8000000000000000000000000000000000d9c636c1be4533531703081f055b24a826ce1ac3f25cf97d26ac191a09851544f57eef4a8ab9313e31c9c423b5c292e00000000000000000000000000000000038feed24f8fd1c8adfd6a25eb4c60744095c34f88ca71176c698132ccb14dc781033cc0b575c9cbd530462cf379ed61000000000000000000000000000000000f4ffe09e20c53261709bc3c6f67a784a8d7ca92bd954dff9792db5a83378e4fa72973b4bc5cfe86b1cf39ad73f781a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017374f1a5f4e3b6a4d9ffce7025c2d8237ae7031fcc821524fb7a3fee1cd061c47c3882c7b9fd98e4ce1d0c04e2e80cf000000000000000000000000000000000a5c9fe4ca4ec2e2c1560002beb08fdebdabcac2e577dd34df5cebe1832ae2ad0a66f15bbc602fb3133e30dc1a58cbe60000000000000000000000000000000007c83e2fdc817dbea9c27257d745366e818729b8b2748f995edb51edfc748beef40a7275aea546feb2a6a7a2637c7b55000000000000000000000000000000000bae4ae44ff84cce8501370210aba32eabf6065d403b844a4b0e00a5cde519f2e335922b1b31a7a8603e873733ccc0fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000743d56ccddddf1e567a29fb50ed926d21d06eb7c46c693d19a61d2448e6312f7093a75592288c9e0513f8ff29680d08000000000000000000000000000000000e7c082ec15767fc2f74d1fac953f4feeb1bfdc31f9d55ea3304445d1aa590d8f19f3f8e882c4848f098dd893e665c2b000000000000000000000000000000000ff5c4d10cc63062a5f9574e65b23a562b21ad4f1d4629ef5b2661f112d8489ee4646a78e5e9959177cd9a5d315cf62b00000000000000000000000000000000081c117e556c502332efc956a20ae2880edfba794618bcbf95cc9b1f437295aded5ab1d9ce69277b57fc115b43f3fb7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000168fd5aa9b8445b584d6c7e89c018f6c89ccd1f79b1b356d8ca678c564a0addb3b0d8c1848a7f8e977ad9367eca547540000000000000000000000000000000003c787d24b0c6a00c457de286e2d2e169355df03cb4e979db68ba20c9a43aae4cb5473b9f840cd08825d73a51b549b470000000000000000000000000000000001974f33d54fb3a497673dbad193f554a2c6072d64212118c546f56da8815346cfca88ea841ed9c93940c6473ee9736e0000000000000000000000000000000011d585d3e76a4de65a870d6fee3d3a8bb574901746378c41030fd1ae5f24af9b88b221a8f1dff355975da5a3678ac084", + "Name": "g2msm-11-jwasinger", + "Gas": 201960, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000008021059f40f3611cbb0b6fe88ab8598717fef4d12a6f97a8bcca2f1b8d8e26a89ef6f3a8f10d8abc4a68e18676a4cfd000000000000000000000000000000000258d198bcd3a192914cef9e8071938afc873107550a236620d6971d27537aa1630a396fb6aae498c5372cedd03473ac0000000000000000000000000000000018be441b4c96b43b05d940fb673ba3fcb2b60846acea3fbc2f9f1c71b8e742e8b22dff6ede7b2e510e83b2563aed1ca70000000000000000000000000000000005be810660776cf03efaadac7c7bf0b0680481a8e022586492da8a003e3d76f3f2383f58fcc72eea001df87a2e7d75bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000686e71b329505a4cbafddd5cb2ab81e139de8a91886d0c916b5c54d8b21fa3b592f5b53612b95c94a047c6c58f59f4f00000000000000000000000000000000153f839f5f5a2fd8ab02b6676b01434d724d4a39cb8e149c45007e7fbc87b73076f3007e4af7cb87dba60dbd0ef593b5000000000000000000000000000000000132e53ebddb09a8bc4b562ffac215c82e0a1b2980a4067fd314e642737f3f7b2dd6386344a751f30651e51758df23ed0000000000000000000000000000000005951a024c8d12d8a5cb9cfb73fac15bfdbfce7c2018c9c2201d42884a93d5bef42f7b29440b0887f6557636ba9b2e941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001596ad567e8e2f2e19c61c118b59c3f89016625775d5c0c39df741c7b9f7f18307f17e11c9073ea718fe35e8d5fb46e70000000000000000000000000000000000f471320998958ed942f6ab088718a277df4e69f9f19a6b0be30ff7742ab98ac4726a714484da9371638bd9b8a6b4aa00000000000000000000000000000000102cfa0b735abe2576d93e05cca22f0f387e885972f776db62fd66414e4d354e54702b0f4b79b4480f4c8790616e9700000000000000000000000000000000001419ef155c2b746153626f4012a64627342388398c1dad29b1736149cb6709825b26d7866e56d6bfab5044ee889751391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e4e0705b3cdf80277d4df7b6fe465c224ac77c2f69d8e105851e29afb580d5c34de95d6fd0a4becf286c4de20a9504000000000000000000000000000000000ad556eb3cefa77e243d7735f2ac86c25d052b9348d84431620e83ab137df38322d3fe8dd657074c3cb0e345c38a9079000000000000000000000000000000000fd08f7f0f236568e382ea7dd0de03122450cf85dfa64abaaa0cf04c9da1988f927c6caffe881c3f9537c43f69c133470000000000000000000000000000000007e530159b887ddf2f9912ff7bab6638d5871fcf0c3238fd0fbea7c0a6fe815036297950519f6b30ce02e4fc76177a1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f89dbf32b2ba6c568d2ce8a9d05c77970d7d3f83eb7243ffb91bd9806d52e952ffd1029e9d319f93852c250c459457d000000000000000000000000000000001665200a4f370b7398e448d58fa8b9d7aec4c66f4fde118349666ddddf5ea97eabdd658f0408f3b6cb73594374a5784600000000000000000000000000000000081c14e77b6f7c974e6e03dee7668aafae6a9196dde851829046a784498c6ab2dc258ea2e1355fe73699fbb9c56519710000000000000000000000000000000001fda7ef679cedbe3b920aea656826fa8faba78020fd43d4092ad662481cfc68cb3c39a7808a7a757aca4e5a6039539d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001548cdf40e4daff92ea0970c062b99203346339a8c49acd7e663714366ec2ac562297a3303f917c50ff5dce1473d94a20000000000000000000000000000000016c67ca3387951e121c711866c5b33182727792ddd8bc67a01c5004c7615d6f96bba71b7a24f1f858b01194ff321c9d500000000000000000000000000000000128b57874567d338e1649f8c8ee0b5f7812909310f2e3085d496d64a5b9177b610f0d69800d7342518dd3a94fb67bd620000000000000000000000000000000013eef06e342eec5793bd5d8554516f88431d5078b2130cf00011912bb1da0104f85308415e6b24fba8ae526a2c5323ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004140cf4fd41037fb79dabce0b9373cddd2d48440774f9ecc560b5fecdf0d20d93f6c460883a8be058da750e25fbf0500000000000000000000000000000000050ab0cbb593a2ab42baebb7805a3af12e76b7a5b66aeb8f9697836a296b04670955c0932447d3c9d019208d28d18fe700000000000000000000000000000000185218918dd8342f8939e47c28cb49d00306eaf05f155bcc12ecdf8e29f9723b1f401a176444c9bb56a5c6b357427a4000000000000000000000000000000000151e609cae21ee71c737d04fcfed42f1fabc2047ed308338791211b3b40f8641a17d70391256d8a54f77c2d07f2b2cd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4cea2b372eeb1a7ba9db02dfa31a3e5a44676c43159c1ab0f65c61ad29260503927240d1dacf809b82bdc077ca5bdf000000000000000000000000000000000e3c22343b86af2dcbfaa6f5542d6f8005eb929d4239e968e99ea2357c781a0f1dc5f2ad3bbed2d9a067070c5362120300000000000000000000000000000000052439e0377729712c4736d921ee1d6e68ddd7adf1d4098b5de65bfc6d70981b535049d83728e47b46d35a64df877d4a0000000000000000000000000000000014ee22f6ce93805f2ff60ae79179e9d7e9eda9ec0905f9ce02f262d45d3acea76d510caedac9273e3d0f4c3a7d6a15211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e741397829764310a8c9ab4d8a4d99fda011790d5ed1c11b5c7001e68135b6e8aee43666f73f71a02902af2988a679000000000000000000000000000000000402056d655fcac456eeec6ef33f10abd382228514f5fa0c1358d580bf2f71c35ae638ef97ae602e75ddd9b4191f56620000000000000000000000000000000010815680bb4944b6ff1a3423c9cee175d085684c21703155c466d9360e7b8c82662c759f89ff468b356f89b83c95ebe50000000000000000000000000000000000b03ac823455b72a4e57e1c390118b5b78404e7bb7e891587c03963e496e356a3a1486e27563ef9a52c618daf7b10251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3aeab4e1aab27465954da4964dce671cc10fbf41cbb4dcd33b8b9a968b350d57269e7870c57cb7843bf002dbf408900000000000000000000000000000000001a309e3bc566c782e0fcc425d2ff84f308eb6155bbf3d11ac1f54412107844b96c46a9e69152cf9116d49190c9b962d000000000000000000000000000000000999b2cfee89a0b5e04e5613efc3f2581971e17b9fa4d416ef5e44888d57219ef3e85daa5343329a85dd65c81ed839f100000000000000000000000000000000166c133e98496c1e34dd0cc4f70d320f3a8607c69561751900943eca1293cbe35df8401beb774c33d3579cbb43173df71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002f020bd18e83d6983a2d88684835d77fd138e6881677595795db09d9a1ed51961b39f80330ff133c4c4413f800d6050000000000000000000000000000000017c8d8ba455223931394fd8c85132e0299cee989ba1666a5eda573410348faf41c7aa8be60207da8f4c50edf5d2b74120000000000000000000000000000000014525a1c5fc79b05198350921e931b491a15a92c517f9439d6f2911d51974fb0924991f94ed02da3c7ad65ddf2b02d220000000000000000000000000000000013803248afd68ea1cefc20c1ed41ab14c78c7067ceeadb9425aa96d28049697a53d1db7668e7bbb906ba47522ff5b08a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021340102cd47b30fd393ead273f2e8fa6a8813a46ca502ee01cdaa77828f961388c3a0f38a24b595a5ede1a4e42549e00000000000000000000000000000000089f53b73dc8d0fe934a4b97b8e757b2c32f74597e986637915b389b890e5e5866671ca9ace164d26e615991c01582e50000000000000000000000000000000012ca1e5ec9dd9da00af5d5667c6b46aa5023b4ed7de24ca4639742f6fbe8edcf8285acc8384929f6ba9eef096d05bae10000000000000000000000000000000001647c594ee077c3d0a162f920760f124a5268a065f7229738293aa7114c5b7e37e1980aa80b1870aa7481dcc7b7bf701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000008c64be86e3d75be980ac5f5cc4acdbf7955c8beef520c9c6896386bbea4fb32e22a76aab04f7840b818967c5b9dbc7b000000000000000000000000000000000add9213a6d009e0d5c16adde0bcc1e6fae879ca75bc2363669459ba996ba73a2c7cd13afabef4440fd6b6ed048ac015000000000000000000000000000000000291033ee24f6fbe0d33cb26a7f67912575b4b2cc595fc697446a5cda40cbe41bd0b78fe45e7672b29135acf12dcb0a90000000000000000000000000000000001f32b2597ae1bba016f607a76e9468b89062c67b8eb3e4106a16ee6af9a2e02e15038757083dc257692535941533ced", + "Name": "g2msm-12-jwasinger", + "Gas": 212760, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000125e569dfc47e9dedacc395712b13b765659635af6600c5cf41375c02178508736b4dd941348e3ff812fa7561d07d9c5000000000000000000000000000000000da114714ea8f220b3bcc699f5b493e73f88282e2be12199e174c2fec0787b4e9f17c4bd87c4dddea090c9790b79efd40000000000000000000000000000000011dc057d55baa6a3bfab1c68946afe661493802a3d351517512edd516b8043a3450a8b8d0020a546139084b38622d8e70000000000000000000000000000000014138f5e86be6cdd3770fddce9fa72f622622d16493da222a09162d26330c75f1644289225a3b2150f067d7e3e10e6401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011cac7597bd1b94f2700b6aa8cce78c85331763da801f6f8369eb7df9c2b0db5a757a86ed7e7cb47c6a6156ccf1f022b00000000000000000000000000000000131302fcdd3337ead2c564956670ad4acd7167e13d68ca5c36d6133a2273c07ac3db3654d93716bf4c192ffb24fcb7f10000000000000000000000000000000013e44c6898472b9050205d16a44b777c7626cf43e6a419685f5dcc29b5ebc43ed4bf6ae42966b84784414b34a532444d0000000000000000000000000000000017eac13bc51ad518dcb1b5c1d19e375e5311ef394b852a13ccba1955d63682c05d83de6d05e82479c50114d4a2e43fa31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007df61b6fecd86c1ebd8eea740e0a0c5b9de167ea8aa03a2e29c1960289f1c1be10ea48c9482a0ce9bcc977232d10f3800000000000000000000000000000000049a3d0f286c117d095ccd6729581d2faafbfa84459a8045bb6ba705cdd0c09e22aa56f66ff748d82684a996051508300000000000000000000000000000000015db9c16a6629b6b2871438ba769ad4a3bcfc0b0f8639081b5bbd863c7adb74b89340d10e98f8c20e40f31c02dc27e880000000000000000000000000000000008b8ba2a3ae2a886965702dc67c7b822b44c9b909d2717f31dba040389ffd8eb6dd5574dc155733ce3d0cbc1ee82dc571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000421e49e2c24c266da1880c54a13bc9d8b4ea469289cf457189bac4db99f6cf83ed9acee2938a7afe452e9b8440ded4d0000000000000000000000000000000010c6b17919d2d2e1a80438f23f9c30166c388471410e498064e8169ebe0813d6ad5d9b2f058973d0f8f3574e22a219cc0000000000000000000000000000000001f1da97038674de5c66144c8a582a46aa7d1adc2d6227228c7524bb9254aef1f6468b7b2ca305edf5c38afeb843e4e90000000000000000000000000000000013e5290fd76ecc159cea7f0740b7848e5ff83722c879a90d2d20c77962e524b6661004379c7318fec1257ceeab1248841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b10c3053adabe7e8a94b78465a84de70451e13f91ba74951de1221547a9e81271039c4c6196b43d39a5767b09fb0ca2000000000000000000000000000000000bdc31f3ca6a8d486d4528c8a6ea8aafa85323b8497d615c5fc0e8ee9f93f8793a956c80339194dfee43ebf6460f4382000000000000000000000000000000000f74f8ffb11b40b8a9ae19578243c67bf66fd0fdf0d1222f66957144681bafe8bda3a5aad2227b0aa68db3675a964b04000000000000000000000000000000001155d62127f2b1979d7ca00c7bd65b5bed5801f9533d80c47e917513b5dca91c941a389cbe4261d84bdbe1dae52968af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000810cd62cb5db7725014fba3ed40992c573c6ad46253af574ce1d32a88be655708edc6e988e6702739e9035ad6252e520000000000000000000000000000000006b231076cfe15fb8ce6f5e54bcc75352294288de0cb6a01770cb6268204eee6a56004a832ea4348f64f2d7f0c168aba000000000000000000000000000000000b06cf163b8aa842ff3cd9a6107e50b5aaa8a869ead5562b14004ffce96be46f9661a902a13550bfc2ffdbda010f502f000000000000000000000000000000000d0a13579ce2b8a6b85b3cea96c05e64f9a3985ea29f3b7ba0a13c0ba56d4d9c3d829dff0009b620e91a944d9e5973be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177d8cfbfe0b13345e557dc914b917707576db4d3cb65f75ae0760b0fe748ac7e503d05252dbdaff302c4e201faa3faa00000000000000000000000000000000168e90e1cd4fb3c1582229e92b71edf59d43d9767c477005b81309b454bfc0b2f6ff6bf56847ff4c1bba3cae9e9a496a00000000000000000000000000000000013b89b6c0dd84befeabd600e81fb02e95bb943d67755e6838a670fa53448410836c1d779a78d370d0fc5d21c9075a84000000000000000000000000000000000d9b14965044f35000ffad89f1d9131a89f9ee6d1286b7236cc3629ebf2bdf49c19353e06a715720a47753c279549ef11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016bf043d64cc021a08de60a3c473ca3b55012eafe82ed839ead4e0e2e61d4e95fae1edb44a6ceb841e77adad7b140371000000000000000000000000000000000d664ed33f6832c2633d5db1c510fffb446e3cec65bd4821cee132efd188787100eac3af8b6e2a626e6e7d26cfe1d28800000000000000000000000000000000161f46cd08d9dcf23ca2bc51be9d2cfbc46a210c21783b266172c7681d61b02176822fcff928beb50e31f8ee11015499000000000000000000000000000000000fa301b13647501e6b70a6b670f23c3f72c1c8b9c210e16dfba2afd9a718158a508d9bbe7e6305979dcfc739bc1df6161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c5f17579be7d1088692df3f5301ba493d2c215bf37c57a82f059513e54fbd692ca5ffb9ddb7b045cbd600a1e06eafc00000000000000000000000000000000073e8ab2f834f18a39acacee258f70a69c81957aaee5f0ddb5c22fbb3c68be6a15d76e60d1332d8bf8fc6e3121f6413900000000000000000000000000000000123bc15f394cf989f0b949c7afee86e7e02c24982c1ae01797d08104daa1936c62a0e40ca247bda4c0f6165ebdb2a297000000000000000000000000000000000b6233a74db1f492e2d6f853e46de58f67c6e01f6b677740b29552f5d7f4127ae94ab4d5c052291f492ebc4e04caa4361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c582636d12298774561cf0f44c80660da80410c0bfd92c0a0e1fa309a1f4dd8a410137a28b5a805c7b02aa3ca44f3f0000000000000000000000000000000000d7d89e3189649323fd75e67a2e087ddc225a68dc8c55933c0675d237c8b0cd9b46a2e70512da9470adb44455a654a40000000000000000000000000000000003583ac11d5525b073f3bd4d51b0b640ce43b751d28d30e07da35238219eebe56800ab11c18918af833ab953ce72e1a300000000000000000000000000000000116b4ba6304cb6f3b79f80a61d9a8fc083801996b7097e8575960b7167bedb7e997ea183f0dd0078aca51587e45c6c081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000140629bda15c8496f6eb5e65e71b7416b54490a35433f005b8b922b583e619509cbf3b57a71d404a4c8c501437dd2ab500000000000000000000000000000000174419792016ad53e4451853ebf36564184f691159de8b8521c2333ce60b5ae71a63c14735754229261ee0bc67394e5300000000000000000000000000000000160292b0e2c93330dfce76b71c8783a3e29f3035986f9cf8bfba2b5515e92fb779ef5c9223797382d35f9c560d8dc4e40000000000000000000000000000000013dcbd7230e02adf6497817996a7d1177ac351e92b2e501849a7f97b608fe3b4936eb715c4eeef2c9d63440f943161db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a75a9895b070f695ef417c1ae7cb0f31846fba4a8393ca068f5bf8622c272a3590c60268f067bc90b47bd8cc8903ced000000000000000000000000000000001333bf2c3439a6b3c3a994495ce7cab11d878a1735d57dae8b7d5c71a59f592b1b3d98cad3fba4bef9e33d06cef1adad0000000000000000000000000000000015c6696789fa57c6ae894f11c27267be467b9d8effcd1ed26e5f9aa79ca136fa44fa07799c0b892325853aa613960bd7000000000000000000000000000000000961c6e90f910424abd066ac16c342f87afc52f0d7ac0a8070f7e0a5fa60a5bc8ff1075e93d54ec88fe11efeb548c6c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034cc93ea8fd68c3dcf53a433fcb6b9d785f7a340f6fd3be806e395ceb055be37fbc7d8eb670719d592d19feaae16b210000000000000000000000000000000008581cfd3298278aa6652880bdf1c0f036f4106b19f9aab539710096afba38ff7b8b8a0775e2393981306b0a035aa52d0000000000000000000000000000000004ad80923ffabad8bb20319955895b919ce2e35ff7a1bd16de3044fb9dee9e229b106ffae4a28a27aeada9663103cc3c0000000000000000000000000000000015998a21555b39b3f93d23e1b5e4fdb8413189392571493629c4d0fbcffd97d678b8a5987009d93a2aa90658fc3956431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000013baefee1d40aa57eb774ba8b5430ae2d35f152bf0f514f5bca34a3a45a50b07237880853cf7a291d628a4dda2d00725000000000000000000000000000000000c1aa48826c086f959a6c8af040e949178bc3d2920c18ce2674a2d300b3f9a244ecfa07a5e497a3140cc1b7d33a4e6d70000000000000000000000000000000019e80fab4bea14c6605d2fe5fa80950f4f78df3531e50278439b3da08fae1969aa60ea6e192a70a71fc386255f7b5ac300000000000000000000000000000000142a13d159dc5f323036d6fcb848d89d18761d57e0d1d5029b02b5a04a3ff898188c6e77ec1f4e050e88cd1238faa72d", + "Name": "g2msm-13-jwasinger", + "Gas": 221715, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000001675b0bf5351afea5a97334d5f60b0759707e92455057ac6d2ab6da4c0e962f9830fe34a573a4c15d5805d3fe9afa5df00000000000000000000000000000000053284f9e73d0ea661124f1570e565cf53fcbed871a257f0ae7ad2ad6eee3308ca74a9830f1c9f1d967cf41713537e4400000000000000000000000000000000058fa7935703a53f92c32ef09ce838682b3fb9a6dd62e399d8a12a3834a90a2ae4353d57102cca9bc2091c2fd1e3f197000000000000000000000000000000000e292c94c7fd4572f0ac922c3dddc9933e3e462b13f44f7678bd0fe111a6b098f77569455473e128ea23a92585e11a091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011df2d502b32752bd5356e0dfcbc170a006a644cfd576e15d2955c4b2c084187b016fb02748acded8282fe7f80af4f3b000000000000000000000000000000000c07470b495145abcec20866a4a039142b15645f2281ba1e6ccb831156e90684159fbc7f8251bab8c79bca56283cd5e900000000000000000000000000000000162acff68e87be85214f0471990a76885e9ee2a9146f8e98e59b62ce8d7613fad2b380bccc4bb73303ac22d2d6b8b434000000000000000000000000000000000c46fba20486fc832894e97c866c4a3ed48fde23b76b4c43d3f8c9668c907678d4548d713d18eaf069db534c543bdd8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1787d29ace74ed80fb185966b2cce3832af345c97ebb1332c9796caffcb3930f37b4bb4a81ebad486870f7dda6a56a00000000000000000000000000000000103a60103eabc9d01fe5e3502c0eda239b0bdf261fb0a380b2178ddf2f4fab23fd994c3142e0cdfc3791831f5ddeb77f000000000000000000000000000000000ff536a6eea1bdfd6a8b49b81d189eb75915a2de2ecc2f79d684a519f5e8692340394cbce21d12152757cf88b98bcb4c0000000000000000000000000000000003f3390f1cc81827c177ec45da229ac2a7b6dd9e130c30220e843799d561052942fabcdc73e154bbbf649dac8f23d3851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a017b226f990a17b3bda171913d0e450e37e5d1dad2af29e42678b7cc16f37bdd3589a5c6b498a17ca8a02f442a0e0c000000000000000000000000000000000e6587616992b13eda95eb6647c5860d07f64457fd3a94797be82cd4720603c9b8723900ff562d3624d5e6edbdf075240000000000000000000000000000000004621a0f720cb397c16cd430638f5930a8bd75b391ea7e3c8e135a9e1902aa87bd6f2b29eb69a958052ac8bb3b7c4cd5000000000000000000000000000000000ee486313ef3b270ac16f4742ddd872fe2416fcca96b14a504494fb8138d2e08545658beb27863ded434e7bbfe9575111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2a119b161a6b8665d3d384a3a5068c0b1e6e363a17bf8e6250e2f79c7830bd5d2bd4f07dee660b22f353f3421f980f000000000000000000000000000000000226514feed408e2c7700582c4bfbadb11dc57a20a60e590401733e957fcd9e0383f1c979c77dbcc2f5ffaa192a0157b0000000000000000000000000000000002891a416c475d3ead18fafb3e143e0aa1bf707345d853ce713b96844a5c434cde0446b818628a5c11ba6f46e94b064f000000000000000000000000000000000bce4a7b3043334fb08ba6a2aa6d31fe7a69a666049120b622477d4597f16b9dd181c3a6846cc562b34cd96a05fa64d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192e7b3717f40cadd221f33ec65d77f7ed9a1d9ee634c03788cf51c2bb7a41732940a0986f9713f9fb16eca1cf36c7a3000000000000000000000000000000000c6432bfe40fe766e74ea73777997f0b144d4b4753a70c38dcd0a3f66f8f4cd976be4f3e97e4571b0c4ee761301c7472000000000000000000000000000000000a91c1d5c93caab9622915463e8328a16ba8c353d7b22cba4a419aaf3c11866228520a15440eb7d7d86c900f32f45b6c000000000000000000000000000000000300cee80b0f9767b241f1ea2ce2c802fa183bced933f900bcecbf8bf1bf5de564c93d583ffd60f9f2c8a894ae8d131c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f3bd9225d1a0a745038cee676fed3403608b6c42d8a58b572c3ad9293e51316f6c8930c02e025bf2aa0186b3de970700000000000000000000000000000000010da64d9e61a2f5f12479bd1d3b60031e6bda00cff35b3aef820515c1fe9ad9f01b575ab5b8b22c3d6a044fb48538780000000000000000000000000000000019e94f3b31d77564a30db21e030c0a5cbbcf02df2fd723c8956a5086aec711096c44503ef8c3e66daaca3d9f446455be000000000000000000000000000000000758f246d5b42a281e7ba140bcb397f0d1054a1558765d4fd2be6b1290531786008e3740cfe4275198b63240db224add1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000625cf5efb135dee7b4b3a91dc942c25d8f4c4b518012a6f1d18179d9aa147addd8d75a6bebb5063a55750ad0a027bbc0000000000000000000000000000000014b1c5874d7d7e65779a0ffdf05239e4ca96252191048702e9eff22475d2464fcfdfd0aa9640978b1ec710cbfa80a675000000000000000000000000000000000ddb149f99ad4e32e44f2fa93cb6a55aef7909b38f7b9c3b4d048420924de70a37f626e3899047d93adbb645db37f6f800000000000000000000000000000000059c97b18d9965647832c12f2e90359c765bfe38102c4404282b5d8efbcbfcfde91b93b3784689c05bb6ea29d761928d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ed6e17c926002070f77c00d4e781952a2eedae5bc9a6bfb7bb708dcbea68f792251fb0fdd3657488de4c903b2d367a000000000000000000000000000000000e0fd4f768d2a1e554f6d96e40d181ff0213c0364def9b2963691e764eb871dcb6c763dd552d36bafe42344c07994c5e000000000000000000000000000000000c2ab5c169b8ec27e154e7534a996fcb5becc8f423625c71ac853cea8f8e5a3435bb655401e0e79c268224cf01fb17b000000000000000000000000000000000026266f1fb7944b47b9c46091c7879909a5c67e02990e077010a101ea68cd53a812f7a42ed9ab9de1c135315ca0ff0691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a865c262cbaee16a98b8410888a514587e0646d65de00f85e0665232f0f03a9883c6a50fde8f266cd048e3c573213bf0000000000000000000000000000000019102286fcd371b8fea51f06c98d10800ce161c40586ab07890e14d704224187c25e269a5ad892c0fd087ff8aebb1ff0000000000000000000000000000000000e58283086b6244ab41798aa73598e37df131c3ba16943798d6cfbf29db0ae6cc1a0778c4d48897c54bcfb88b46206d5000000000000000000000000000000000938973335eca0d7bc31da6d707514f62fa641905a3570fbb5531fabc1117fe9e1bf229aa13baf0ca541f2e972fcb0151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7c7237076158115e0527ce32b7e2f0e2bfb97b4dfb7cec6b7ffab93edef896e37495c4b8309fb2c43c2d7ca4d0ad11000000000000000000000000000000000b22212fb5acca5649b04d1e1766302ac0599b8d93a0f1206efed2a2db9eaed1e428624a9241575b350512baed0a7e8800000000000000000000000000000000090360d266e428b00594fafaed2d35545cf42b98be6c55ffd7d9316e5f0489f65d42d5a5c679ce253f7ac9f2bced7f430000000000000000000000000000000015639a3d2992df101b79444b1f60b0eec1c23bfc9107c097693d1f1e01000011c0469a684b1f6f32225088a6427c493b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ee6bfe90a62d612516a0b8aca1c4a263b151ed0cb49a086d75d8c08ea3e7361a979fac5c0a61eca2df384ee036afc800000000000000000000000000000000097de8660434a844bf7454a5461b5adf3aeff48e1bacb9a97e3985f085e17c9ca8c370b62b7d8318b11e89bd7d920ca5000000000000000000000000000000000898081fffea5ea32073311ce63e4a99d4c98021bdc653cf67069ed62353bdeb7517e22d68e5badd91e754d99d9a53160000000000000000000000000000000005bf8b59c0584d8d1cd29be3f30adf4cd3c667294c4431c35c502b3b33613ef8f9749b1d115f3ac4e8223fdb43e6f6951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126d53c89900329df7644466505fc0597a8b32aad1144c9b7c797fc253553e55bd82f6bfc32457a32ebff6c58f5f3782000000000000000000000000000000000c804bae4eec145e11e986dde8a4d4c1d8a2319716df5d415f58ea82d68d533a588a244671e9c4455607291fef73491e000000000000000000000000000000001320146088f9048353f1f42236354d9df724f3a4b3a267e735e3d3982fda8f1fe49ddbaca66950725da20f8c7722d8660000000000000000000000000000000000cc083c86c4b5b482d17caa3769164402c85facc64ca7bf93b81822741581dd9bc10ca3e0137cc2e357e0d7a41f76121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000effd30aba827113ad2511fc92e47ad92d3173ebd158dafcb6f1521a0ac1e0f93e95dded5ac38c9a281baf51a272c9350000000000000000000000000000000009a11677280ef6388dbf4578fff30cdd72ef5124113df311f19ce81de1275a3bf2d3564e065244a976b215fb1fd3bee80000000000000000000000000000000018f2f7019fdb19e3a4c817473ed00c45f4d9300438f18b69e52704bd2f526d1adc77c4080fcbd192d34160dbaee8d14b000000000000000000000000000000000e88533f0bd693e96b4820962109d47adb1959e765ba7fc7b9fd968f71806670422c0558c125ccc0db658d063c3dab691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000010fef9f726a0fc131e54a66fede4530131b39382d031a79f1dfa457bb44e931f18c8c43bdea07d5faa5c1c9263d304b30000000000000000000000000000000018923cc680bc64fabebf1d20b420f8720ea5180a568a8f1cff39cded6d8bc7232ede266d9a5dbd907a9ce4685a633084000000000000000000000000000000000fd2d1f1ce4d1e43303ef0dc602b5b8e9dd9524368358625185530542303eee46634c7bd5da93a58b9d899cb5fb6b8650000000000000000000000000000000009ab87a9750c466b7c1f7a9adbf6b9f9ae5ce722346ae99f5c9c1d537f5ee63b5f4bb423e29f0f5983a587fa644d1ec4", + "Name": "g2msm-14-jwasinger", + "Gas": 229320, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000009585f82d0de4b032fff9c7487bd774ba390b8e0c4160e892bb05f80e5826aaf772ee2ea082090e8bbb8d63ec2c46d360000000000000000000000000000000011f2b894f97d30ad271af2cd13d2524424d7ca4e40dbcef4a8a1f09bea98d304035394ad82c1ecfe4889cea7282fafc7000000000000000000000000000000000d7dd773738b88435307f1ab371f424c6afe68d056367e8d60e96e03be384f9bdb852db43e528e7611446852b19adbb8000000000000000000000000000000000d5523327af66e927af025f46dab15136ee9272c89926ea30df5101d86eca077ea38658dfd982efd8aec7b359bde452d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2c1a78e8801ffdce4c00ed6f6f5ee92cc0572e26347828ed548ccb57979885769f483c7ed43a2807b418cccc0dddaa000000000000000000000000000000000e40f7ec8fb2248a8468e3e9de9e18a6178d7d80e8690cde852c67aa91e69d494e3eef846ecf8fef485a4e9fc8fec15c000000000000000000000000000000001424283a510a72eee9c53632a57ea483e5b7167c2f02de256360277486bd60f74489ecb1f1841b61faedf4b625799e8b0000000000000000000000000000000010830aba1e3673d8cf5eb4bec1d70f9e933a13246f5f8dbabcd9f9de1a399e29a6d459a33f865a044703e3569b9483e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001363ca31097d9067054e4ec6db6f3eabce58265a7caa3cd3b0b85d3e472db354941ba6edcfb19b1c302180cec245b5530000000000000000000000000000000018c130e92263de9d8ce0edfb46d3a1c3cc3989b7bcd02d91b8135361503b2eda8e9b78e3f47887107cebeb0639ff538a0000000000000000000000000000000001b32ec18187b4580d01a714ad705d4fa21620f9377aedc5d493445a26d5a785c160892ffa81757f707497f94a58ef2d00000000000000000000000000000000003356c415e602b72b21c742b0ceaad89d77cfef996a14c8d947498a0f1b7f2cb64c153f07eb46647957efd4d9589b161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182d682205cf2bedf008ee4fcf6f6f88990f603865ebc076a16f4f88d24d257b934c4a8bd0d23a7674064d1a961b9e97000000000000000000000000000000001096756e101c086d8a028f13003ad511e56523848d1e01d014e336df1d9a6369d5b3f645a5ddeebd723e739f54eb2d560000000000000000000000000000000012ce1c90831c762613a0444810eabb2246e7c029d6c507d95b9ce7a126e54fb57108b6c1fd05944c9e923ce511200351000000000000000000000000000000000e67837eacd96dac48560a5bb176fcb640c04541f13ab4165b5719027daa3a5915413bf8d349a82a86e124df183b6ff21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123cac8ad5c2d6fe9f53756a6b5a0e4136fc7859c1058511d00622729046659b38cff450ec4652b66b7d79ea68b58b3000000000000000000000000000000000196e2aee93d2870444cc0efd7d4b0527e18d0671dbb4649233da2728502b75aca534564c3a927a2612d9514731f4079b000000000000000000000000000000001210ebe4b49081c7de032c96ce7aeddb38b0d4f18e0880bcfe6ac4075700a8a1a64157cb2424126134111d8f2638a0010000000000000000000000000000000003e1bf0a5423be6efe9ed51d9d6b6d89207f256b2c333c94a1770084ea880fe726a24a7e07e2c326609b30d7c64aa6821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120c8afdb5c3d6c962ef29f6d6203dd8378054ff1e80747e9f32d624bf1a6f9566cd55e470d0b897818ae20c8d4691c3000000000000000000000000000000001076dc9486c2fe188f96fc35a8bee4bb5c63b73c75ca8f52d1bc85c35bfae3552aa2701016131b4a1dbd9e4a97d0ac1d00000000000000000000000000000000084a2652be51d54d4abbae4fdfae4a25059a32816ac7b85db04e816df302497a4612e07afe55488aeb0f962be2b332da00000000000000000000000000000000031df8dd51547546488af6b6e457153fefe1f9e9d4f86b23df276dc90dd83d3426cb5e40d63e7586a434872c4f67389e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047659e6f8231dd8b3795cd677d6735c7e07654ca9dad457c10c312e834860a7e2a5b9abef8fbf808e60d625aeaa90980000000000000000000000000000000017bda32ae2829163047d52af952259cf1af64fc173fc914216f44ba4422ab82264b7858a7357337584504758a9b209be0000000000000000000000000000000014cd7c5a8b141a3411e33664761fb157b4b30f8e15debfe7b36b64e02828810a42ec64f453efa7ec60dac56af86ebe860000000000000000000000000000000016a89b8dadfca75f2a079a977a0006e68658c3cec2f7826e6263e4bc0a8abc7d290db071979340f0eab780d7085c5d921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192b75967186020c75d8c09e4dee36974308a1462edae90ae24133827f9c3e365f31353ebf16757d23d64ddb8be39f30000000000000000000000000000000001901b5f019822bb210ca9bcbda63d9732fcbe2efb726e54dc2b5dcaaa6d4dfa0e5a6df1a66f9403a244b4f2d35d9637d0000000000000000000000000000000002d175081b980e410615d6c701ba77e8c22f09c494c430f1b7ba733409fbfd023572281a4e1a2d295b9a321c01735b7d0000000000000000000000000000000014309db5c7b3ea2e71ddfdc55b7bedc80c70b9297020cac7c7b52b3d43f8de899f7a5bd98c5a86d428ffca44e8b0391a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017af2836c5b7807288b15832ae410fdf595907159be55f55bc6f13e60b99dcc7a5f6d8a3177ae9f2479170a49a1b32e00000000000000000000000000000000001e11b5c1c90be5bd374b5dfb18e5ce201866ed908dbe20b21b5d58afae00ce3292e13cbbeff687dff38a4dddbd78661000000000000000000000000000000000df3a20c1d6aabdd7c98b4ff45d891227ed7d8fbf07c9be75f5c3925de96417edc53f9521f90fb176f56db4e462c053800000000000000000000000000000000075bf5763f85ddbb8fffbf1cb3d1e616790171b31a3ed46cc651a39a6fb2d0a7d6f370591412cff181005228390bb0bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca9cd18967ac13f7d2a7643107984c03263fdfc1bd6e365f478ff5df9aa9aa2bbe85bb3c52584ca93a603c3c65e20d40000000000000000000000000000000018359c439c1c3df752f26d1eb6da9f54947c3be0551d18455e93b491187bd159458cbdb516ae71d0c73d3e52be02a84200000000000000000000000000000000060942e464929c390b65f0ae0cf461b1499feedb18645f186130129ce7f3c23f3e920288db737d978c677dbc798fa56a000000000000000000000000000000000d92732d969bf6863daab6c50941fa748bd1da03fe31914f3c4b56285279ed890df2b38e17d077001c675b737e9b50c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f39146314f46c600fe075bf609c5aa83212615f3277085c6253aa04812d0bda206eb17dece35908940b98b579f0d1400000000000000000000000000000000156e50026a5e2d186722d40537ec19f102a4c928f3ec1d9d53fb8aa605ee474a09d2423078afc40e69214d1907e0e330000000000000000000000000000000000ee619d0510cfe6dd9d1f0f562d4907fb1081c7dcd58d37bf46e0b1bbc2595780716a210629e1037036d1abf5737f85e0000000000000000000000000000000013ed553587700422ce410305b20ac8b8f50f683997441b9b11faf5e264e3b82f98eeab1c1581a4df17b4dfdb915552cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b785bcf40b4501fe8918afcdf707e5f5c0daacc18ed5371bff0667670d8ac50c7210c8013873508895cb2897fc29a5000000000000000000000000000000000fc7151dbf7263fb513ebfe8c2f3a24946b6ba1e2fa9dd29f099db8684f6c17e1e39b63db98cc4b123e6c416c3b5900b0000000000000000000000000000000003312557c45fef275086b9b824664630ad351e2f25533d19fdc51ea5939e8c3b7a97716717f036a7b8b3478ee00c71c000000000000000000000000000000000195cda923236334d66513744b18e02a0e165c53ee170339711b4df0b72faf44e5a7d46f2aba96058ea7f3c5be3ca8fdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101687419fd635615bb013542735699cf5e3f0e048505da3d0dc8d9ff3116b225c839e23e973427f4378271df1531e8c0000000000000000000000000000000017f8ac8887b5646eedcd9403eaba4937403ef137ee9825d6c5e1d8012099d03ef3a1e49142991b5230f263fcdc7c18ec0000000000000000000000000000000016c729f3e215c2306c7aa24ae4f72c56906c8f00cae210b83d3edaf554e1ca4a73b38b49bffc3bb2025ab50104c21563000000000000000000000000000000001184c64ffc045de677baf6073458307f979cc152e903c6c737af828b6c59e350fdb69e4c9b8fef4bb178b1ca9a4e56391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193019a29a6d230896a62b27548e61bb23739b9bfe57acfcbafd1759d7fbd34339e2269462a5e45b6c3d589a7c2348ec0000000000000000000000000000000013cc2181e6c14ae4770f4fc40702b9df4907f958b99a16ff4ee3f367ecb0f7eba587f0c009b7a28562af3a3064273d900000000000000000000000000000000012387afd79057813c08dc751a929c79c44dac1867a4214065dd16274ff213dc786f1f98d493ccec9fb350ba49b22e4eb0000000000000000000000000000000004b32ca64b1f63b214561253ea1a3ccd37aa1b7d5a5ddc7b913a77bdec4a59d269188a03da94d615ae956f93f6bf31a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008eb48d60f08ec50d74a6f9b4fb7fb162cac8831cfa684facb06cf4372179b55e99c0cbe7f075cdefd30425f9902ec460000000000000000000000000000000014dab58fdc97677ac99b80c22ee7b9d39beb10e3028588d2e54e24336e5a25ae60b90b1117c79c4acb62c9853fd9e2780000000000000000000000000000000019f44ef09d41fa011e1dbcae0dfc85af938dd5d5b9c054238fc8bb79f19fe37aaf31bbf440eef9319609881b0cedf0d0000000000000000000000000000000000eaa75e3c57fbb857eb78519de3d75b5fd9b89d2f21bf05644fd3d0cd1ffc29416231a763ef93a3638e3aa718b4eca3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000b2ff0eab9f556316e3cdc9f3ffcc3cca500f87e78b6f0ea0ae236dd3eccddbf83ee3d2006181bc4ffc7a0c557e5649900000000000000000000000000000000129b1ba7a744174176b6c3c3e618f6eba64a61a77edbacde99a16f0000f4f4ec2f7df293ecc40bfeb374e23eb04d38da00000000000000000000000000000000032dbc598fa6ad4e672103f29ff117693e4a9f38cbea4a02c6a33912cd40ce5a19a940c902bad20554985f8adbafb9f3000000000000000000000000000000000357321fcfa1732b1638522f15cc85e5c1bb7b26d3dfc1b1f5ae401e40bd030d55bdd8a92ff9cd3ffb58b20df8f6e58b", + "Name": "g2msm-15-jwasinger", + "Gas": 235575, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000001058d1c8408794e876eb0756c8e3912f4351845642c51cfe647f5929acbcbf5b1ac73ce1fdad37b47f9d7e398e55ac830000000000000000000000000000000016b559edbe17138dae65b7e113deaf062872da451d283b9883436a361f939ff2e4335c361ddff609112887f3df907bec000000000000000000000000000000000f2f3d3cdc02fa73ff20d86b8ffb0d87b44cde00a835b87c19305ee42cb7fe48fb6f6d7eae0cac84007c4c5461c0ce2a000000000000000000000000000000000af87ff37d502fc6b6799e086784e26bdb9bba9491a1e48f0d17ff3544efe150c1cfa6dd35fc8d068dc73af110c8d2241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001648f0cf7080e1bed087a10684b89e4e99205b76d4c557edd5b1211b1214fa052ed609a3cb7d681311aeaf46ef19ec70000000000000000000000000000000006fdefbacf75917ff0b17ba08cf4bd0350de01ced463daeb8a55f149da95abd4233dea334ac50799daf663adeb97e59d000000000000000000000000000000000f286dc4d59f9955f63bcac9a2de7259c939f25075fe5099a3a3cca5a061e9357b9e443430dbc88509aab699887f816d00000000000000000000000000000000052895c6162eee3f9db6561ed540b3b2d300e38ad497f86cfd779220df9741043426212ca5d1d7bb9d7b84251fd847ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f1171e3a146490f761f8396e1b25d5499ad0d9eeda355cb0d9d2c94e00e029567375de2c139afe5ca7d1c34bbfa79f000000000000000000000000000000000744e97177f935081e73159c0ff179fd1432170d8a1e4f49a04a3fdfac29c6e1f6d323a4279350643fd94d0b5e6a54fd0000000000000000000000000000000006fd7d988b54b60f695bef25547d9110b55046602c9e46453e3eff69fdbc65dd13c77687bc44526e73c5ee9bc4d6bdbe000000000000000000000000000000000cc27777d17b9cfc921afa67345a060b497446e85d1bfa4fc18302eeb6c88d5114813322d475d72e66b76caba7d418731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000928724f312b832cc0448dc6cbd9f23846b6369c758e62dc8c4b4038a0ce85b8c34fd872a2561ac0a1649879e16c9af00000000000000000000000000000000019403353bb0fdc9d31246428f8ca07f371a21de827bb6bb7b23f7437a2196a3bef2b6ba78c0aacace2f1d55bf2025da9000000000000000000000000000000000433241c6b5c3b7fc4dee4c795f1725ac92b969ae8cf7efed1385f6bedd9d44c1d2595b6922de323e3548ca46e2d19120000000000000000000000000000000019dc1613f73c4d972dc18ee6b4b249f61e018b8498fa10949d9a318406472e8f62a678f643096025a00c9283c10a376a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001615400eed4603bcf9c2d843f9d4e1399f475d1c7d90715e83e588696805690954ad81e3128f79945d14d1d8489701100000000000000000000000000000000009841383263d0e0028c8874f69b621a776bccbcd3a50705e1b9f3457f5283ed97812dc8051915d555ad94f8bd1e4bab600000000000000000000000000000000119b5b19896d206db2a688043730887d5f4a8443239449c180a33164b4ffdfdc62d4f84c474e4009186e234a45705aff0000000000000000000000000000000005a5288a7ad559e3c840a9b2f04b077112acbcbce27f75ba54e78a160b3de4709532162ad973a3daea30589d27c0e7e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2bcccf91f2f92d8742f43b3ecfd0e86c5c0b571592a4b0229e5d758e7547099622150be509a0eb73faf60b8e6f32c30000000000000000000000000000000012a8ba2e96931e64a4c8d922128b6bb9b33759b4a8b90298dd966e24bc8f2a62c93578a51f1c69d25a985998b0f701b2000000000000000000000000000000000f08d45809ff6353d79ed446a61beddf32b8c10e80320863c14dd6f3963712a82ec08078d870be39c894ae7a115761d10000000000000000000000000000000015b3aacd68e406cffdecfa1862a05d2e86c18f88953c9fcacf4f57ed148b75fe47ee7d520423e10b253812c069249ed71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d33f05473dcbd7a6f87aff2c4492c5ee075dbeb240ac3efbf7c10100349a21414d7477a2a9bf8b820fa22cafa8fd2f000000000000000000000000000000001909b11e06993d3b3f8dbcf53af1f84f8f77f2a3b2099e43ad2e388a9f50cd6dfa3016bb8331b9c88f72a5644cc4304d000000000000000000000000000000000c2d1377a29d0f1edb540183986f4be344bde6b0e828e660e237ade096cc93951df423cdb31402db6a58305cd8affc3c000000000000000000000000000000000e00541a59a064e75dca4a34a7dc2b53166aef07c5304d4ef2958eea89e0c03731da0b1d34365d21f6a96abc3f5f3ec61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199577c6aa52005ebc97fbb815f35f5536b32d01832fcd38a928c45bdc74979166b2642e1f5c8105a7c65e1e3e91be160000000000000000000000000000000003b869f8fe45a059b2a0a0e7f881109c82f3670bfde042c5308e47feaf845ce74e61e706a9041a35fe9b5ad1b4c25b64000000000000000000000000000000000402ed4ae3f01663f6379289751b684083d40c08fb001dc3338452587716b31462e1b9edd0f3c958119ad3a99cd6e09b000000000000000000000000000000000dd87de5373639b4e472dceb52c1526489cae7db9449a76c2b6918af7be3324d553057d15b51d62ce4bfdd3eea04142c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb336ef38c387b531ef1297a3653a8ecfde7e9568efbac252f51cc34d493b1d287fcd03ddddc773aa753b075aef804000000000000000000000000000000000002879eff0355790a7c1e598a848c2858ef74ca6026d2f3982e60c0f5d4ad248ce5855fcadb171e959e63e4c0ae2fb7d000000000000000000000000000000000971e792f0dc832dfd3d324afde0fbcd1169565c8ffd6cd90d5e34ee97a6ecd47506f016878dfdefa4efeee1e97689fe000000000000000000000000000000000f01e28c11307cb75040a8c4ee1efffbeb204d5bd9c9ea4646216715cd38ac2a8a78d6960b9f20091a13ca1824c1e7991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b028f2577947445327e7a59d284540e4a70d818d923ccb094a964f229da2e8bc4a8c384e28bc1498971819b752e7b40000000000000000000000000000000000486fb86ee6924a74a6da138e4a33aee6f571fbea13a091dc5d36aba1220046fb5475f1df45846fae5a3bed42b2f086200000000000000000000000000000000128878f7ef1ea3a7d68d82805231665d6ef319e0c6ccd33f8b69574a9e9d3e94dced576aee30f8cd731964da3209a7a4000000000000000000000000000000000efd61a5527cfb0bdea34f81e3c4a0faeb06ed5fbb1b49099219af9241fa1504a2923e1e5d4921819caf74c1da7d20581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ee99d683d95606465110a6c7d701e28b6005f55325ff4dc7eb0530ed76d72f29777001f867e881bf88939a9626743000000000000000000000000000000000005be8ecd6eaa8a09dbe42b5aea039633f1af6a23f6f74dde1af31786d3306c2a2b154763db48ebd83ce35050bf2bffa0000000000000000000000000000000012994045e0a6e31801f8d811cd8474563252114526a5bab5e7ac6aced43bce1a456c1e62222beb6f81d5ad59db330f550000000000000000000000000000000001110a22468be14ee606c79e1982612f270e800dd4d9e5843b576d68de839da7f4c371720b26fd334abd05ccfbfa52161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b63af19ef755651fea130b411999a332440484ef0e3c3a8adc57222cb9e73b8dd54a33ddd2840ef7654611cfec8bdc300000000000000000000000000000000190107a5b7a3daa41257ab3a21ac2eddfd20d256a180bdcebcda2dd36fa7c98f3e142930e7a94095e0f858be1ab0728400000000000000000000000000000000074bd4deb184b3146130e2661a5f1c4186ac692450d40a43613e7db4952ac1275d609a9dd28eec54116342552172d1d20000000000000000000000000000000018455386ef333c7558f7258760e17d5ef2a6fb7c94b740e2cd1948abbf06620e2314c4f75fa1706c90c740335b8db8941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f9728915e60dbd472b8f381d0b3b96c850cc63f8a3175c95f82bd14f6e3a91d1587da029725e17bf6f1c4722c7c1f100000000000000000000000000000000185d005d561aeaa3c552c2fb8c7631bc36194eb7597a0f9bbe26fa77b6dce66670dd61f1938acb960a045db1aef98c4e0000000000000000000000000000000016cd91a64a95be7ace42d45523013343a4914fce213f25d3ac3cfe474b8e651df277ad41fb153fb0e3f7007553c8aec20000000000000000000000000000000008e9338c058917689eb01bfaa478debe85ddd665f15b6ba01bd23a8b0f7dbe7ae24c62171dafae6e72114af83044a18e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cade5e723b7b7f9c642302470b99c10eb065bb11ccea7929f6646749af6a49e0397c17db55ba1a1f5d210569c4f1820000000000000000000000000000000000fd4579f392c16763016a702f5e1c02c5f9e7ac279fc38e3a43f124b925ddf09364c33aab23fd178244ff5b8e51f7916000000000000000000000000000000000d74330f40790da1cb2788bd12be55494010969e58a3a90d780d129132a0430ace5552065333d4df33a3845f82e1cd990000000000000000000000000000000014125a57f3b50a5042898fa63221a1b503b6c02df4b30022885f956e7948ba7c98a8abec53ea5179b3c6c36a0fd5847a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b81c9ec882ea6636b0ef5c85d1629bd5c6cc9dee96d8aa623f8fd84aa8edc0d18ea82ce9319d4f7d52408e903325dad0000000000000000000000000000000015c717d944bceb4d49742411ec8e8a73bcc11e208e023e68f7b01f98ac7be8e557babe64da5bf4fbb50c86158748aa1000000000000000000000000000000000109ed3178a5daff7b565664c000192c4ca0270706fc7a0183a071c8cc9222820ccbba90c2957bc8eafe46703f971b58c00000000000000000000000000000000083db7baf34e5d542bc2194cc6e392366dd5895fde33c7a4654f5be6910a37bd2440d32ed6341c4b64f73d1b5f3fad431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179d929ef49df8ae1ebda88a578d530b91eec073b9c31f3f8c81c4d5873a260c97e943714e5831ce5c593a6a60ad081300000000000000000000000000000000071b51a611f6aae8d08dc5a56ab3cedd5eecc1e699dbdafc9fb66094667f4fab3e5066a15c65d84425f72e4f4440ca79000000000000000000000000000000000a3f84ddd786f48da54558b275c8e27afaf4b9fe709a5aab1363011ccc85627e00e949ad78bd3f5e237513d683ac718e000000000000000000000000000000001517a3b22cd6ac2ef59ce2817776f3313b1ed96fe4db283baa431aca0740e2d2ef5e2fc12bd5b0b66c86e6093fd8fce81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000013b03cd0cd2b3da6bcf67f1b66191e2ede276a1c6949a552784d03b02b0377a64b5b9ba19837f751a64d9f15ca5bd2810000000000000000000000000000000013ad666d1a6f34c1f647da9179c367efa2a7c29660913e4c3ee46d47f0e125bc9e264aa48a3c23e4a2d9f5347bd5a4980000000000000000000000000000000002a6c9fb6ca45ed061bd17513ecf6508d8d9ee2d8f918426f65058cad0c5e3aab205874c4452a45ea65aa2bbfcb67ebf000000000000000000000000000000000c2dc22dd05c745c5f9012c6d47075cd385818da8c91d6a70ee9c1e0d7bf497b85d5739285278e51a9fe7f283296d546", + "Name": "g2msm-16-jwasinger", + "Gas": 240480, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000001104556aeb45e44cc8c466a67466a4bcc9ce6b62011bc292a2985fa6b43d87bdf8e6206fdf952703c7e441dd8bc753c9000000000000000000000000000000000198c04fb399606cd7cfd4a6aeaedd05cbe8daf953a63c69326c9b359f8048941c888c77602ed810aa83a218ef24eec0000000000000000000000000000000000f0f91aa814be133b06e6cb830cd4b97c8c548e6869005ca34c83dde8f03c9d9ccc879169b4d37e646a3e8df9b3153620000000000000000000000000000000014c6813606a7f77084c0f28b071905c9fb0189bc9abedbbbb30140b3894a13ca851717cd8c91d728fdb22c0bd4aeca801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000376af4856ecafe1e4482d3334dac0b730492eca9c77ccac5133570e2a3d3bd563b4a07e905353a1317d8ba83e2658a400000000000000000000000000000000124a5ef79681ea5b556562c237a35e25ccede8b9c871f70972b25d035dbd30f72ce04954189e2f9cc7add3a94f59bd5a000000000000000000000000000000000fa6de68187bdffe5275af1f590bea2a84ee8bbeb321f60c4c5f885c15d01cacb54de29326693bc239a14d04f012503100000000000000000000000000000000101269f6cf51841f76147147c90b881815476c62b42f7b71961a073a1f184cc4e01b6b3d656c791c1e56ba27965bc2e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ba1a5fe02833c8600e725e2ec1a2b7f54be4dbf5ca6345d502c1fc9ab10c00c99d9f6120ece763d5532e83e426a596000000000000000000000000000000000e63dcd5386a32c287783a51492797752924713f7fd1f4ca41064e73c001ea057e9f976e4412b8b68b521837e8eca07a000000000000000000000000000000000d6e3a776dd6e7dbcd71f4666aecb51d214adc4af861a71ff2fbd7063469cb7e0086dd3d6ecfea00e9661c34a0f1ad670000000000000000000000000000000008609cd85edb79f4af9b9b2d68c18bb780d63fe0b2e4b4cb4a6ae1d64b25d9b39ebe3cc0055bb9244538fc048e8518941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f077c324ea0932c6e714b608140ad8177f304e0b133e6d9f42e668dc9a592848099d14b7116e650bc3c2bfe8e8c0e3c00000000000000000000000000000000021e2a8fb0962bf01b8e0b06f6824ab03ca53fbf6a5329c1c7572e6318514a2f17a6bd04b58b5f78a95671b0aaba1d57000000000000000000000000000000000ef2f38be769797fb08c80a01a842e1aa0d31c97ccc668a40efba145e533e9e8ff27f0c16c7699d817474f3195e7fb0d000000000000000000000000000000000c6e68098be8a66438e9bc378426f8c240fb6cf7b85ca5af8802fe42705392becae2f14f6388e11c75840447d0f5d36e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2320c070506d317ef35cdfad07e47b664eead07644a8e6baedcb92f26a725baea5a7b433966f6e09cc4ef0a25438b100000000000000000000000000000000030509190d69a4193a2653b430af65a0e420ff2da2f7dfe7f09961a814f40921db2316035982c60bcc3a4b6d24bdbc77000000000000000000000000000000001616ea2634e28558e4a5c11064315629bb83aefedf8e96e4242dca7cef1873116f8e32fb6d7cf28b772ff2b664fab5e400000000000000000000000000000000187b1eeefddf013a2a643e33208488114b67515b025d33b62111bd31a2681046de8912cbe3f9347ff5de476e09d368431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d4068ee6abd320dcf4833f72fe17405e62ccdb38fb46cda3c328f1bb5769399a0f17daceff5ba72a5d0c0e25b89c47000000000000000000000000000000001581ae43f73c970ef95ec34bbd406fe6298a9ab90196a01d20bdbaa207fbdd7405b70de5b2c65f5d5795e2171cfecc0a000000000000000000000000000000000ccbe6c487d3363119acb7ab34e19f95159aad14e123a0a8ddaee7357f311be2583676f24ee0edc702290813af0039660000000000000000000000000000000008dcaa66df2b5976dd8f035f337fd5a8571c7ff68fb97d1194b247bb9d17325e7f9e47dc485986e320748f00edab1aa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2b306ea42fa2f504d4641755f00b8a26496b7c1491c9827e335720ede523e72cb1b458861fa0889696615615651b17000000000000000000000000000000001071834c5fbd5be9fb9d76b74597569d912033d3912e15b2f8425c7561cbf27ecd114e272b84b53f325aa03895ebaf17000000000000000000000000000000000aa85beb2d031320e646d2484f60baa7ba7f19d836b46cf7855403c02363accc5a585f6c586975ab090684e4600c6c9f0000000000000000000000000000000003a1524524d3337da6b2598dc50a4d8f87bc0cf5ac1728daed21b2ecb4760ad89725cb65a1cf25d1018602e2ece363011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007accd88917e5ea54211a1b729ab5e008f430233b7d57bb3274e22abc3d0b721dd6d75fc192f5bef97d6b532d4829f1f000000000000000000000000000000000756395995c8e82c4e132df5deb98471e4725b6c0fd65499d64e7f60feb421b831e2c7c664091d2d6ea19309e693281200000000000000000000000000000000078472f3bcf1a22b836a71d0fc26f1e7ef1d1d2449e53219800043a86c55b616b3decb36b6a0dc09d897de07a8a7885300000000000000000000000000000000159afe20a5b84c33f0fc97ffbed58a47b8818ee1a4f7a6a551ee1fdc9f0a4713a8fae4659d1ffc786d3a26a4073c03ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000731250638b25d7c233c1ccef3de8e5a21b73539d2a066e40a6361cf02976bb0f808ce5412ea59bf29d87011f39b17c20000000000000000000000000000000001b6a3ba61fad94594c410515f98678d6a57100e1e7782eaa86e556494995b9af16a03477dc224d2d81c67e29aad02c20000000000000000000000000000000016f8cecf491d78b7ef48dc84a00a509872048ed8b8e36aa8195bd743ac383e72c9a1d32e282cc2d6f35f28a05aaedb8200000000000000000000000000000000078531036e75d83a3acc1b35eb0250e340f2460570fa002f9407fe0a3c7da9591c710162c9b9ec07472f3e7706cc51e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9959c588edda60c184b9d22de33453d9c338c7892217b07e3c6c1d95b8d7a8b35e6a650bc14e419d0193123667a34300000000000000000000000000000000029a4f9a79e1505d72130cd287e67abe9567151a0535ad973525a4f13384371ad57c96acdadc2410a8d073638d29e380000000000000000000000000000000000b1d866eb5f67a442a8fd367bd579f96b3ee1f05bf066a1f293a451cf97b211d6a68f6eff542d6f46fb60ea9f06e27ee000000000000000000000000000000000146d6a623164f50a81ea9552be321c26d53e32138c3d23f1b2d1d2cf12e43e65b56ba4fbf5336d5b9e68e2ecd6413541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0ea54358992c5a4c4bbf8e93bb07b7df6ccea95768e4248741ed3bcaa8152dfd13406a6cbddc9a22e440e410a6fa73000000000000000000000000000000000d537c497f954afda663c54144f38e6cc24f662a03f762225617d0f5e4357c6a01eac7f3b927c1978d76d9e1eb0d9245000000000000000000000000000000000db9b4eaaedacdd13132cdbeb1c1bf593b9aac552645604cb00d4df65bbd1efc54417de5939ae478e1394330b0d79ad6000000000000000000000000000000000472a33ba55805c1a1646720f72fded955ad0adc74992400d9a98bf07087407a11d255a6b6f70fb50cf0b57f595a1c651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017983879118e9102e8b2ac54d71799e30bdf1188c638e54b7fbeb5f2bfe39eae62ad18560ed29a2fa2307a6a1d9db027000000000000000000000000000000000e19f4b8defb1b7798eb74a885461373c368ae17fd101cac4039f0de41eace7df689743fb8f9003e7acd04723303682a000000000000000000000000000000000a85f33e410287e5f25739e2a2afed580f12ddb4ffc0c8c4352375589b3b56d1d55cc3bd145aeab54ee3cf039edd3dfb0000000000000000000000000000000015da8e3e3ebea1c51c68c0f3af09dd442a56ba75ee925db8700bea0a5b75f7cddd5d9bb5477dfbcfab6eae9897172f4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf1278667922f7994945f1688c96d373b6a3bac2fd6b277290c9f7ab86e049c4c661de7681b616823a64a6204a4c794000000000000000000000000000000000892aecad822fd54ba816345d36ffd9cc3995f435f9cf5c1990922a8ec9342680cdcfb076f235527e2b504080b1679ca00000000000000000000000000000000106af093f2778f6bd217876fd6403f28413e885f465e1019b83472ce4db3908abe0155334cb497fd44197093f06b0eb80000000000000000000000000000000007011bb29fc0f42ba45b7807be97ab361af719914b501d5325db1110d943af902a8fe070401ff1d77b78a35a5313a9491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194149f41f5859428a7a0fd746e5af76a527e460679552cdbb9db8de0afe261d7bd53ab72859fdade8b891b6c2d7cc1000000000000000000000000000000000105ab549dba17a7235ad523d02709a222fccad103a1086f8bf658a2c08875122274021aa65017a6d12bb414e9e290e0f0000000000000000000000000000000010667b321329b2bf6219387b9b0940c15065eebc9dd12d397207c94a8b3a1bc4603dc23b799379152a46a7e666ff5a5a0000000000000000000000000000000016a57f08a8ff767661012fca04b227033b418f06f1ae48f11e2a510af89704909b6d830ebae761010ab27cfd333969db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce8f0ffbe14511437a93cf5d5a6f41c8b141d0e2203bc72a54123cfd5f4a0bcc2af21d74ab7cae02e64c89c77601bb90000000000000000000000000000000013af57bd94c81ea4a2322c649b7ca7a8046d6dd71f774022a2ecc8214a7f87495a7361d62077740fcfc8ad8162188c760000000000000000000000000000000007623f4ae90d7cf1e3b3b269849e4ab2c8ad42530de2ef36b4ef4177a4b42d52ce1d5db26487bfb66b3bdea1ca5ad9800000000000000000000000000000000015cc4825d19a5824a24e147532588686141a2220e76e4ee45f89e181566efafbbe2928face6c1ba5e7d76290c503e5421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188ef76f3f636614fbd3d9be8dc5ceb80cc3b8ece05fa1ad3bfc2361cd9942decf6b5c97ea3edf5420a8f5d530f4ce5100000000000000000000000000000000105ee34bf0f58fe297ea264ae6307f3f0a14adc34eec12512ecc85a9509176044cdccb1ed1e7234dd336f4759c7c41d500000000000000000000000000000000111cb92d59590dc3c5d97b2ee4ad42be6180e076c41e0360c71a031552fd54665a21b462fd9ad9af9ff0fbbd1e3c111a000000000000000000000000000000000e5fa87346d31866aa046c6597d6b7ade36e71453ba2106ed739b512fb6168c61e2f7d1458137237279354b526ae84a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000beee9a81cefbcfacd5eba208142a6ccdcd40556483345155e4eb64d98eb07dd21c05246b3f4ef786fa45d606e207a1c00000000000000000000000000000000189891e35736b0190e6fb5ee9959380e9a1e1815590e4ccaf0cfee72cdce0c9eb82f87c7ececd102812debc1a51f2f51000000000000000000000000000000000d43e75c52216919c08749cd87f812ef0a95039d22636c8ef7bf0796ce4d84a5d0d25b26194129d071325e64a44594b2000000000000000000000000000000001007fd530a197b73dfa671a8aacc929a94b201f86d56467a72199ebfa39709818e917cdd6663cdbcfbf6bf7a92fae9e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000ae34591f4972146fffd248b35f012ab37061bb015d87b8019964079e8288a814d997c2c62b6d460ee5cec0f445114770000000000000000000000000000000001fe760c518dded13a56b10b8e266ba621b65ad81ffe5d9b7f48bd1f836a50be51449d8bc2bb50668ef6665a7f500b9a0000000000000000000000000000000011e71eb57d8c3fdd4ff08bf07cb79b037d08dcf554688594ed8a1a982678ba9acbfadbf7344a4b3aeacc5b2e273c8fb800000000000000000000000000000000149e4e3cabf0cada1cee16360c62699e4560f950269310b79e5b50732515780e489b1cca49695e4e607ca0258b97456a", + "Name": "g2msm-17-jwasinger", + "Gas": 252450, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000035719ed98fb006b91929459ccdbd9ec3d8a4ee3722fc7a6dae78885a022265c1cc591517c2ee8100d41dbeb6d7cf18f000000000000000000000000000000001996319f8063de95135c754433001dcfe4e07519c069f38c81f29b5c21315f19e259282500996cd64ee7a4cd5cfc393d0000000000000000000000000000000001b88d958e0aca51e2d31040da8444a92ea3f34af2ea0307110baaf16ca11a2b91f27e44e52bea856f2a8000c334971600000000000000000000000000000000102eae8acf7ebc9150b37d09a0cf5b99a6d114fd9fc256e5fe0414ecd5a3a1a533f3db8cd8c4b1afd3bf48f349b404141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050cad5460e28bf5d32db9c3986733f148ae9f36dbbb76a5d8728d29802dfe53f467893372c01072d913c0b83e9b92fc000000000000000000000000000000000e71d19bca2853a29452ae941263071d7b6f6103e2b6f6641aa943a83ae987c2a252742ae35e1c738ec9139e21aed4df000000000000000000000000000000000b78e8d86de0a4927a7a8d25cf0a0029c25b8c6620a7ef33cf6747caa71e29a8f0182f4d00e81e8668c79f3cabd6ece400000000000000000000000000000000033733fa7e65bfa79119196911565917edd32652d0bf11cff8a27569bf22c00d5f3468aa66fdb7e433ed8e5fb4a07cc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b7b2dc69076571e574fd74bc86b1d47327107874e53ba07529ec3e3deeb1316a199a8499f15396f966a815f64bbaf30000000000000000000000000000000018bc97f141aa016ca6ca93aea5805a63c18873fc5f955c5289946d66d5eca77090a347f1f1d39dd8b153f1d855e00a910000000000000000000000000000000002aff2b3dc781bb0a57f04564e299aea6c2351f08a913a7a24ad97f97e1dee894ceac5e2aa2216941d0e689da5ff6773000000000000000000000000000000000d8e5168d7711280795053af55a7eb6822fbd5e0cc413f5779396b345d9b7497405b0c5084f7871f0fb834b2b563448c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012128c36a1d438083dd79a43aa0df1cf069a5f562252c1f274c4c08a0066e8a592dc0ff99e1192f744b9e4de83bfa7d000000000000000000000000000000000ad959e43c6e608ad264fcc133abb4917b54e3db6673ee277aff84774e02a6376ba9b3950cdc413b6fd4051674ab18db0000000000000000000000000000000000e423d1aeaef918ffae49d269c8c8a0ce9158701d60d572ce08af691987803e8c5561a16438914f3b5c8810ae0aa9f90000000000000000000000000000000011634f65fc32ae2271bb957e31314e4cc7adee902bd78e3513aafb77964957a09dd7afbd988fb3debf4eaf32a4ce7a2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016501daa96be2224c9c53e2d918aec64052467edd47d4a51860384a082d487b70ebd869b32e91fa7d4c14caea76fa14c0000000000000000000000000000000008b9f14ff60d996bfa5150bf5a3c2f2559e3f7a9ffec965afcc48be2d8498020b55eb2f64b347bbe8b8a17297edecf680000000000000000000000000000000006848030ecacb1b42fc4d2ca9ce9b67a3b719349f60bc01b663a876d96df736d33e58d534cd71b84b655f5f1356f7be600000000000000000000000000000000076f075f53dc9def4207a6c21a7d85991d4c6e1045a540cd61a8c11f87c91128276fba2e1cfe708627e9a1643bea37481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001489e34a5245bb4198096faba6093cd65f2941e5ef2e2bdafa9509db89e36b0b0d93c260e96cdca3b9b6ce00acfb69fb0000000000000000000000000000000014038bea6c0852ef99321b14c2781e46cb8cf6ecfea7e015a57d0e577be3c60ad4b72cfea35bfa7bddccf62b2ae74350000000000000000000000000000000000121a942d335349275887731fd8134623ff7cfa6468428810ed5bec46318bc0b416fa4daa2e75bf10797d2819cd346780000000000000000000000000000000019b621d92198088a212dbd1c865f5b43b70f96ea719ea675a46e0272b704d89b86cf6dc0eb0738c107409e3b060970501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c35d18f35a311138652d7bc36f0884a2dc0f8b91c3679dfb596f25b5ab4702d1c262b88d811acf363b199d1a6fc2e90000000000000000000000000000000011323676de68c724929dcfaa5f52e4f9aad2e43cfa30ef76afa726ad843f6841befd4dcece238f623e0b9331651cae62000000000000000000000000000000000d695ed55b40264d16c757379e2b38cd251ae2ff0be327b2572cc415554b6a3c4831a462b901b5037c9c55edac28273a00000000000000000000000000000000185e3e5a4c19da26cd7516cdb0176dda8ae913f29a92d69c609d1a6bad1f535eb270756addbb791bc3ce3f7f5cd1ef211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168c03cde2800253784925dce9f31ca98c20b01e2b22d174a10d769f97886ee04cfbb9ac2f9d3dbcebd2461ee4b7b9f90000000000000000000000000000000011074252ab583d934ecab393706005ea724d57f7d29b3b34912a1bad84e599e5ab13f140f80c183f08ff2096bfa8c019000000000000000000000000000000000b36ff32db6dfb354794066938a652d042ee9647bc1d1520a8f32a4f66d9344ab843eb3d347d010503bc6c19b2c9244300000000000000000000000000000000060afd6fa713ff18d4d884b223dd65c4ef16c8e209d32805e51efeb176f43ad7115d2050ac2f434f480ef96d64ccd7761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014dd20d5592e48445e11c35ca4eee5e97ddb657b71b64baeef20c158b105638adf9bb5540c3dcd2cf42000a785fe572e000000000000000000000000000000000a54693a993d3f6238ea8303ff857c56f2f3e9e75069c8ffb280ab6b3a12c943e3afa6fc06f299ed0550a5d87ae6aa28000000000000000000000000000000000e364b04ffeb4d738fac3ee31acdc51381606bf6e86b5c27db8fedbfbee6bf7b368160755950f1cfa23764802af4e3a50000000000000000000000000000000015c1c0756f614d002f1365925e73b4b00e618baf5c5e8894bf4ae72665f3e3b40783d309970b170c88e017866c402c221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ccf1ae26d6c43eedc0c2403b3367dd8bbe8750fc3ebcb5506b75c81678f94f88f6c916579701d77bd11fefdf18bdc6000000000000000000000000000000000eee7577ebaa852710e6854dda56b99f4b459816f81fea9b5084431580960b7349664340174a5469e77bd7c3ba13308100000000000000000000000000000000128be48b19560b21d6d40a73b8ebe5b63df73169930d3facc710e997e7ae195fd641a0cc70ca835e8840aba48a5162c0000000000000000000000000000000001338804d0ff749c8fe0136e01b1f7f0e73783e03d991bc5109842f18205735a160fec54636240baf43a014783382da1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007008bdcca55692956df3519a9c945a1e48d2ffa1c6393276a7f577056dad11972396c3f1298d6b3544c8c135627817900000000000000000000000000000000179e40e314439c7308e4f6dff7f9c7b7346fe7e3bd5d09848d0d8f6095fef44b9462909447c6f97899295ac682f29e1400000000000000000000000000000000136d33c2ca515c36c0d265e07b830064c6964e7946876154094b37ab7e8e20bfadf3f93a4fb9b7985cfa098811e4df850000000000000000000000000000000000c08cd7dc791227e25e3b6c14054472062e0fa489e56d0861c21be190b5e5097a6e909536d297059ac00b3ae7374c841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd4963bacac22f80ba7c11169b304eb5866c70a7186625f365d289eeeed97c43e061edcc9e4bcb67edbb4147d9f34e9000000000000000000000000000000000d084653c685b7e36f64e9641f6041c41b1ecf4c30066adc642852ad628081cdd714c48312ae62b7061ccd193f9297f90000000000000000000000000000000008b3597e599aa1477eedf0f20e5276f8ee4d15811b7b49f9fa40ac5fbcea5f53879f7beaf5e44dc2dc83bcec370dbe1c000000000000000000000000000000000b3dd0f5a7c7a0b0a2427e86e2003275ed2e2a8bf62a51d6f6abd18562fc113d999394d5175c419d2c22b2ad431cd3f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001581b30764a1d414ff4e72e5707619ada81b04748d6465d31c5f59ae5cad0aa4b7436442d3e75a1b653b63af791f5b120000000000000000000000000000000010891ac43c75dc38e151ceb409b5085d9cf78307bb27c0846d7e44618bdcc2312ad65374809ce8789416a618ff160bed00000000000000000000000000000000111009eec61f58302425a1d0019b05d5437c447df221ed8d80285c565d5f50fe03a8e4d28dd20683a2184abe648a69710000000000000000000000000000000003bb86312fa9b8155d49c2a975b05a32eb057431a570925af9132e64c29c73754fbabb2acd97d7c6d283e343293096251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d2ae44ed5121abeb05710f27dea8a01218037869a4e11cf15d00ecd8e2603906dd7af6c7c3fc1865adbe9060c2934c000000000000000000000000000000000922107b997a88cbb898dcae58f4651b7e4f4b5726e6da2f591e3619800138899f780d16fdb4e91c31fed5c46cb779b60000000000000000000000000000000015287940736acf6538148a79c00457e0df3bd9bf4328be2d340d269d00dc7ba5037557a352704bc9b0f3eb8f6b69748f000000000000000000000000000000000b15be9d58cc568ee15be155e70506cb59e768f7186d7b563b1d2d1271ff96e170e8a5d9e25fe62747a2d44f32cf4b851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ffea71fc64f8c12a57568133dc46d8b8af59dd042f9cb6e62e276ed98bb9308e7e7a9d86cb372809a114e71f2ed460000000000000000000000000000000000aae2c13efa33d014785648c98fddc09130de67d8255d6d79250d408e553627d0cbea4d677d426bf1f9a25cce21c4ec9000000000000000000000000000000001258dccc658812f666a18fd832db1732ff84d08cefaf4e3e9bfbb72357c404d5721ff41cb7753b88dfa3e2209d10795200000000000000000000000000000000122b23779304cb6b46bc3417bafd9f5725309cffe74fe4b0b1daaa866594b8cce40d761cccc32c2e8991955dbe046cb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca71ca2b92d46b65ef609d058c3c7f2ba1614753da04fc98b0e75ecd3b701f397326058804c3162a99def024d9b99880000000000000000000000000000000015137873e7a55712fbc20c7875f599b52bd20ff8140de5c152fcdf38aad4811517a2a0d1e4c4323b98c569b37eb6901400000000000000000000000000000000080caadcdcaa4f67763f120e2903071b7651eea27fbb4ebf693651fe986ae63a2e409975d65df7b26b302ad17628efc10000000000000000000000000000000002b082b2cef0a5e458b0a498f021055c1df325f829e7770938bb85ebe59c55011192e8b0d89d70d54760c3433cad19061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110ac8b1d632cbf5ff24b13be7be786641a93138dbf10da4d0d8d64dfb421848075923bf928176e7eae4515990bf0da9000000000000000000000000000000000c76aa56b592213e39e31c24c5183c7ce5c5b9f90f0f69637e1f23da8848e802efb0a579273f329e841b95036b4423bc0000000000000000000000000000000009c74f81ce87f33f41097fb21031e4e332c5eb0539b58e6dc5d8fc780f434949564ac4e5a4b362c565f893942ee0abc9000000000000000000000000000000000d8069dde5a23fa45228c3af354a55a9ebd1138363d1e08f00b4aec37b606218614bb62205b5d28416aa24e1f9b435fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168bad83d30e07baf51db477b513955fd5dcebd46233b36958baddabd191fb02556d280cc6f2bf53337838423508f438000000000000000000000000000000001208bb4851ce728bce46afc4889a9c90340bf5d9093d84c1cbc275114fd478455773619e2168913cfb77eadeecbf049400000000000000000000000000000000113cef76c69edecf152d69ed9c2e402174ab8100141ee041e90ca6b64af9e14c62da0b589a8c461ebbbee6ad276fe67b00000000000000000000000000000000109acf09c71e4c53b15957073f3148bc719d22252996bc350f8f195f7324913febdcefa9aa417ad8993faebb50054e511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000007690d3e54ece0c6dab5d93090807691c391a91f63b9f05721373d2eedf91cd0c6372209383785a25b8891e5cbb1a4cb000000000000000000000000000000000e01ea6d7db007525fa4563493ea8b1dd793ece30c82ad6672bff6ce95ed270f0ae74ce6d02860006c8f1ef7298899620000000000000000000000000000000006fe092c18f6fcd48d7028e1b3f73bf4500b22453ed16f346e1a9b806861f288298db51d8d9a7ebfc0969f6b33b4b2da0000000000000000000000000000000000715059a9f4f325f23fb59c655b0eca4dadbba891249c6f3d0258c14f33b2fd36b7e708b98ceccaf8967eae9c8c1af2", + "Name": "g2msm-18-jwasinger", + "Gas": 264060, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000c91bf16071c210bd2536006eda967351e05136448c5d117c5cbb1688a7706e4da9db374b1de6326dd1e51bf44521c1d00000000000000000000000000000000034d41776748962e7e90570ee764c555d2246c02a25c71056db7db526b07355fffc18c0fe6a63822a51397a19c4b5f6100000000000000000000000000000000026282a86efe2f67d7b705c31a432d9751af03c4dbdc0575c2052ccbcc24fe8fd08874d5b9db7b8432c8375902bbadb30000000000000000000000000000000003fe50bed667d6446f8201bdba34cc92faf2760dc71d0aa0d13992874d74745377488eed34874807d08864d14c0683d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b1fc64541cde28fa3ddd640a33d2d010a65af5d0877a759f7d96c07ddc34469c2ffb4d3b22127d9b88e33f6166c31f0000000000000000000000000000000008e61926c9beb2b61a33e2331ae017d2edd5666d977301a307ca2688066456f846461f60df878056f907850de48d96ce000000000000000000000000000000000b03938811b993f6c5e61f7436573a642539b001628463ca899585c76633bc312104ad276dd8ef38e0711f33e02f2e5f000000000000000000000000000000000511de2e37e24388e0c35cf0014aa305456c4ae7e832c8788cbfb361ea4bd2b7961c871081f822a488f3a7d80ae5f6041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003cb69ad4e9b3c07932626844faf207f70d6a4ad387e97d584c0120d2cf71811c505d051efe796ac6c2afe5c8b89258f0000000000000000000000000000000004524e95283bc2df58a3df1711286908b4e6715ae78294e2777960c314085bfa863bee6bb8100b58fa47ab9bb2d3d5e5000000000000000000000000000000000e3b36c1922c77dd0d6f1836d5167a776f29b06006126f86f4aebe0ebfd3239c685fff16fa517d58c2e3bb52bf8010970000000000000000000000000000000002235af179058e1dc3343cae012b9788baa21457a846e276baa10b8c21a598aff439d44bc5c0cc1c33b2f41935b5675e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fadc8f674a9e2c0fe747583f301c23ae9f9c7dc39ab78c80a54ce2bb38d29000dd085e77a7cb7d4dc3b48321d7d2ef3000000000000000000000000000000000439234058aa9b405cc364087ca30784521696700e88ba11924dd90c675b740641dd059fd0d780880d8e916efc2475f1000000000000000000000000000000000fe208f0274da997e803ad54051aef3995508b46439478c03a4626bcef7716ae8c5d8310cf2794f4267c823f6f4aced800000000000000000000000000000000009d280383446dcf7f5242332848cd2bf2926c11eb51dcf17a3be10810fba75b55e3ea9ce9bea09ba9258b3f3bc92e631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c2d912d5b704077d63f16b64aaa8488f9c287b545a5a28ee0794b093a84221c14bd2187c7292450fd18b5877bbb46d00000000000000000000000000000000093c34af567e20b280ca71023dfd63dcf0d6b13f86c1ed5635d4970aa51d15023e9a1499094a81497de6765b2b2c60cf00000000000000000000000000000000137ee6e7169a7acb41ada9caa07ab4c0e4a3cdb5da3a9e9187c990e315c772433609e84eca600e07303be15cd66ff3ff0000000000000000000000000000000000021461bc73aa216fd499b71581581bfc909638d358aeee8d0959aa9e522c90b08d0800d0babc2b62eedb09f5ef72961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e3d9ea82df847002f31ccd13eca5e3a048c74bc52a8a44113119a2c61da28c186e8175b6400ef8d6331d189ff93ae6000000000000000000000000000000000c42b746f98a83238fc5c1c46c53edfe7d78a71071f255d42c2080e6495fba8164ca7cad2cf609f3ca7d28296b7d0e47000000000000000000000000000000001240d63ba7b36bd6db5dc681ada6c70315223631c02f17f1459c90ba7ec1dabc9b67d2d23812c367d9b74814037604de0000000000000000000000000000000014ccd4da05c7118ebb426289e45d214bb940c43dc8e72af906aec699e96826545f214a87fa743475a7c4397d65a740f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014be2ac2cc81d88aafce14ab6e2d0b957edb01c6eaf88da76dd4fa08d7c4754d5cb290f26e96e2c3f3f159340f2dbe360000000000000000000000000000000000e692f453e2568b88f22ad857032fc8bc91a26ca19da612fe1050be7510366f1143d57d6011ac7f927cbf40986002c40000000000000000000000000000000007165af45a85c1cd182c7bf81bd88cc8d6e461eb471acfe357795b99e8fdaf5efdefcd2113684bcf27c2a0fb83fd3fa00000000000000000000000000000000010dc9748f27e02f4fa0ea743908b589a53a75e23a8de853898d883532d660e0c899591a0f7390e02c340b7d8d3dc98d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a1890b4d4dffa5a4447016ae85772c0bdbfec6c5d26be7677714af485ff59714d340a22052f2698c1837fed5515b1800000000000000000000000000000000072990f6c153e3a4a5749eb17739336d433f3668be36cd186d2229e0bcfa9a1ea70befa3cb5639d72f6f2e5f34f79626000000000000000000000000000000000bfb221684b2ce498b5199a161ac1ce04b8790c15ec5bd550bb42df81e64205bf5958887a4d89cb21ba9185ad75f5cb9000000000000000000000000000000000d5fa435a1739ddfcaac1d5b3c14bbbd78af3612903473e9834a52ac2ae5a42027182d52925efcf7e700817867b19be61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024026ada856aaa945fae34944e494022545bdf8bba383810c68d15824d0a80b274a0a46ae8c1241385f975af9c3e1a6000000000000000000000000000000000427e0dbe0878f7478f885c4cc5786d3e2ea5149cac6d19beaf903931affd277a033000fa95e11bda7ef3f5f3d729e1b0000000000000000000000000000000010683dc1fd8b4bb10a0f6eccd6a2795392b1787602f5593804ac0d30d821c6003aa9369eff358ec28f367a6d595ef419000000000000000000000000000000000fdbfdee49be804da8ddb8a5460dde677c99669bbd344606be6dba6a00001df826527d78608daa041fedb600d6d32fbb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016d0ee130af57a0ab9f28e370dff9aff4cd96c98ee81b11f6c0eef3bf04fb3795242720e6984c96ffba1aa2d46c55fe500000000000000000000000000000000154c7802c70aee1fa597c413cf598c7f590cff095cc54d635b36086cc81f56bfb3477b70139579298f45095077678e5f00000000000000000000000000000000108ad6d3ae1d2e0dcdbdf17397323fbc14f0b48c1dbeb78dcd91d03695aaed3d1df15025f0dc8e262931ebc8047e57ea000000000000000000000000000000000cd0950ea8964c285e0d59c954625246b2523efa09bed7be352625fe9669cfcb73ef34f40e2ffa72e7ec638a3aea30601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1a0f0f572d2157e275391323b94e2b2dd34dec5b8d55d046db9af267ded4954d69c2474ea41c7a9d184ea5666d2c2400000000000000000000000000000000096d572953a64e9d40b1c40d43b60a1e807b22d5562cb194374da03c2570a29448c7e8f06b73bd31098d794858c6bb8b000000000000000000000000000000000465a2a55f415daae86e6f6b9345a4a0fb8b9d2c5834b7d8b23a5c89001a549e5757a3bdf336aef693f30fbe8614162c0000000000000000000000000000000015fa5ebeb480bd25dd0b8c4ca0736b0027bf38c54c3191d591cfc03b1d7214fb976cc81669e049fd63938f07d7831cbd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121a45ffb7266cbefc77f70ccd2980e545ea958c8b1670c899aa5cd796f1c0e67756ff64f0c16ba29321b1d7739df4b0000000000000000000000000000000000951dc5539a1a3aefc8e5d19c12a0ef501b980f0cced470a5a7bae1705d451be6a37a0601132f470361c89d8fdb6acc5000000000000000000000000000000000552b54cd7c46ece6bb050b6bcbc648a72104bf9a6302c33e34b25de9edd9a6c1c6b16cfcc72d9634d1691fc0e7235470000000000000000000000000000000003ace193ca007420d21e327ee11e192b76f1f3279edc95abe8211577e0f00aa42c20b5c98763bd194c7f6d8ff84e8b6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000862deee31a4267b28f68c6b4d8072fb96649e813058835099e6f7e0089bfa2f65dde0ae39f26f08377d3462b62d4535000000000000000000000000000000000e67769410a7d83423cf56816b7b9c16b0bf7cf65774430a7e5b409971b1cf3eee0d7610e2a83a18d202c15142e0bf070000000000000000000000000000000016911816e58f03c5afd11b3f594aeff05cecb58adfabbce0ab3ef9518d8b57c56914c7da80f0c8dc694405e4bf0e72d70000000000000000000000000000000006021b3c75ab2e839e644f79ebd78dbeb6d981f7485a3c3a7785507f8706e31d268594c7ca3758171723b3f022eb68791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f60a8ac58cefaa986ada5161559f76f315d4a3941926f6039fd42ad046ea4b17f555d645e30b9086fe0ac79db72d73b00000000000000000000000000000000136d02c317e369484beb6f8ff5bbd248e91697c911ce7ec86138686d242b49c3612b26def46b689572a37ec8960053ee0000000000000000000000000000000009eafd39d08da0610701a51742c5bd7f445f2f3f0379ad227fcabdbadb5c96ac962486c32e12a98b68922a2c019a0311000000000000000000000000000000000a688325c3cb618324257308ef898b01e39b740efae721b748ec705fc0b2bd53e4cc4ac6c0307d0823c149203d08cace1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127ee5548f43212192f8e529605729571c2c331dac3a68cf86ec0ad79dd59edbad5e2d70c8d5152cd80af89bc63e73400000000000000000000000000000000018cfd9991304e47c4fe81d116e55ce9b1dba7367fefd654592e739d6269449a34cce78a29b26afedb86b2d09592867850000000000000000000000000000000007f0acac9e1a56123a261ce6b0199c07b6df27974b6212a4483185a4e9cc026dde4bf0ed2a6a34e46a31e62c663aca9000000000000000000000000000000000089e1f4fd8fc4f640729f44735991e5cacb3a1dcfc66799ae6d75e473a17ce738f1dccf55cd3f1ca103f825f277c7cc61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e2a0683a04828cf23330a34a0d83da288286cea881bae946d84538cf7fff827bc46b7e7efdbfd1b8e97d8fd0969f0d0000000000000000000000000000000013a5de76f1230656c9cfb6a67efa77148947f2c03b98b58cd9352265f182788aa0128bb8f022f0db290098e393231d050000000000000000000000000000000012921b5ebc6a93b6e408f4c1c39a949a1937f79376cb4b10264e1313c62662ee5a638be4bc063ef0255b66754dc974fd00000000000000000000000000000000123e91bc924a36ef4ced5f4bcca7e95ea3101689d211d67176e3f69ef17d59ae993ded716adf4a860dd26719d1c722bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005024a8dc8f20c6f9a9fc082d79ffa62f08f658687c65baa99d354cb70690b00e3fe94dc98de823441eaa17ca92ccf9700000000000000000000000000000000196fc80d0ea57973027f2e9b30de3ffced35108534b3cc93a9425f9093f94b47836b81c3e6740a2130b155bcf8f3c40c0000000000000000000000000000000014b67f4b6dafbb2f9965d9bc7c5055c05c9662ccf6e4384ca68e2915502594c31e75ff5e37bf2f2f739ca1d4f5189baf0000000000000000000000000000000008dbd838a78bb3a44d26670c295611de82531c23611377775411a7897aaa06454a63fd70eb4a8abd3e40273494e396911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001025f0936d17d59f6cc4e2acbe9ebe5219615d319ec8b275b4bb9f5797d995932905d9399d4f3217603d8eb10a6ef48b00000000000000000000000000000000037402cb72cf583e2240c1f72823b98b76c67aa670733836f4255a0b132012ff86d4e0fb11d675175a6ad893f638671c0000000000000000000000000000000010eccd435cb96983304b01fdbda592b621bb6987234ede0260a16a5fa0fcbbfe48bc9c252212087e09683eb2f7d6ac970000000000000000000000000000000012218dcee30d14117028de2334c5fee50ec2023fe1c7b92d20acb7b1e7524902eb6f6ea4a3ac933a7b693801225ad1f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a666e5a713bca8f6899b90888085ca1f8a1b15753f58cba354bd30dfbcc6a5ef8f4b1cf869892bca1128ce06ecba670000000000000000000000000000000017de6a3422dfff948b2cdf00266e7e084de96422aec023d50383b55dcee605e469d8179789c96db957b2e9081e2d45a60000000000000000000000000000000002d935542ffcba215be258b759cdf34d315022327cab48a669bba812f2a307a01194d88a37f4d911d5a911feb95195bd0000000000000000000000000000000010d3adcc9dc1072da84e2225b5eadbe64b3a7d3668786a1d9b8b0da378ab47f55f0ecc439ccfd80f323491d22c0aa9ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000ac45f63bc2426d934848e994fcd07ec5353eff9debacda0c9e73f94b90cae7e8ce658d8b6ac43e001f2381587f29728000000000000000000000000000000000726bc1ccc50a031774ab909dc13c8f90829bd187120319ea5f8691279632c55a3f3d0a9f85ef35206b8eb624537e06a00000000000000000000000000000000119a0e0c1d5ad07b72313753605dd1845dca571c4906e9eeeb172dfb7197b177989604c01ddc8575a254801503fa5edb00000000000000000000000000000000146a7ab3b15a558d91e5d8bfff3bd43837ba9db09f09c58c4007c0d42bdfee962ebe5d09423a67d49cc0509d3e2db6e3", + "Name": "g2msm-19-jwasinger", + "Gas": 275310, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000148b8cda14be26000e73fd38bf6f5f6363b6ec3bbe23e7d54688483f31d331cb8992e45b71220d78f45045c59546c0800000000000000000000000000000000013ad017bb43a34bc478917cddb29eb9de0a6c02ba18afd26168a4f627dc5e35784428aea23cd4050a57d8ddece5f52b10000000000000000000000000000000002d8f0459a0bfe3235bf985e028297017185c83384debe144a86051957701ed2078aa8021cf643063e38de97bd7d06900000000000000000000000000000000018a837d7ba86539449e8a0163cab22ea0beb3dd56a2c163c84aff64b1c7b2ea291d687c4b14f0f9b66bb760c23897f301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193e5f6939fe4e092a7f74072208c815a91743063c0e91158824f1761d250508095477813270a30b69936cd95857d9ea00000000000000000000000000000000055143a310fe4e1cb4902ec611790b859a63de47702e7edce614ee82b74a024c12ac7755a43c64555f545774d2fad240000000000000000000000000000000000bc6f4c38059a65130f4d104285dddc5d4ae2aac4515fb5199e3c679dcf2c20da5251c93ed240a897f37662225949c4a000000000000000000000000000000001018c9bd59938df5f95ab82df112362fcbe7c17534c74c9c3ccd9377ddb588e3ae5a5c0bca356a7a7e5a59fb6b627f391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9a3c19f426c642a26f3d793d609c2a86311e3702c2fd9542e648a64c6570b97a83b0582392b575c1ac0df1297709460000000000000000000000000000000001dc8e6013dfef3b23943e6cf756550e197a400dc0b7132db5f863a51e8f80b78ce25cb70c8c59ab143ca5266e388b5b0000000000000000000000000000000008a02c4f2817964a4d39fc78c102445d9a61bc5d6b5bb2bf883537f56414265d863df173bea34645f1e75c3932ca485e000000000000000000000000000000001256a12c75ce894d69e8454679d753b348c4fce2174848cea041b8d8c14ab169b999a00325bf48e5583ed3e628e9d2aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cd0ec3445f279cad52433bafea18679d0f337054d02b7dd14608ab1955320001a73f54e5a46f56ff3e9692e8cf9a0a0000000000000000000000000000000002af09a6d73fb9fedb74c75f3e164adcc565f0e46c0aa3010a2af82bb634c61051ed85b93f99269f4e8f8c8bbbc8333000000000000000000000000000000000115f7eb05b3872eaa27c5ac4f29f02cc9978169e69d94ac6c2543e7b363046ae38c080ac076d32b1ba48d168c3018b0a0000000000000000000000000000000017f6a0e9d3f1e9989543b1a0ad2852a9c140facca300feaa124eb73ec85b7da627fa3e51c5f8ba01e70a8abc36dd88201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ed7e1acac29789aa95c94a129d9f713ccfcf6f0556a6a78b170cc22a93ed9a6eab92c3a491b48f6942e21e2e318a0b00000000000000000000000000000000191050f1993a031ba286559964f9645efe8d050d6a4b7b5395645a508be3ee9a0080df7c6725d70758c2af623683b8410000000000000000000000000000000018302c4c6ba7874aa0ec9b4da43f35f55a4e0c48fc9b62c47b77da24966228499c99807965716efcc17ed0276ca56811000000000000000000000000000000000d33ba1b47da75fe1747fddb27d8f619e3601bc23eb9572cd0ee2593f59b968b4bdf976cc9dcda7b892e1e0b4d24df0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf42d6d9ea5c339b24e16e8d3b4f3f41c2ffa95bca3c607da2f5af709b2d720c3f9f2f4b0fd1a3c01b483d194f13b9b0000000000000000000000000000000019787ed52be8ba34299af93d361fdeb2dabc58468056fb42e34f5f6c846c8ce527556b3ba746805aa7edc57499a990e2000000000000000000000000000000001497374c96893f08da5b90dfaee78d4ce4082f2b18dc482feda4070de15e1e4ad791ac705fd579e2448daf2d1106f3aa0000000000000000000000000000000003f89d9b704acddd21bfb1e4c0338230ee18d8b9c423a732f6a58776d6a937ae1da0a1a0a7f9a7005e14e13ab0ca9e481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000159a5b54f953c591855ba624d478154575d59c8846e00372f2453fa2601b3433f751964e51cc1409c7e96f487b37a880000000000000000000000000000000000c100c5b8da9d9bce8f50e031dad674f1c92c822b09a76cd086b78394d9790b5b6a23afa1f61cee066b0041369f5b8600000000000000000000000000000000068baaf40e36e12e2932b799c4422060e71f9142903d7e8492505228bb412f9e31c1a62368206494846c274df4643d3d0000000000000000000000000000000014bae9f6afbf3e5c8463d07cabee017794799f2a9035918f1f50d9ecd1179179400db98c030e4ad491c67ad12324db541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031ce7aaa496cb2021a57fa45f965c7f03b9f262f69072ffda3d9468c5b93a104c9b70a55651b1ecbb2e450041bc7d8e000000000000000000000000000000001222937b7f479ea3ec1af8c3194aedf561ef8508ac32f8d83105719370fb329c736fd9031f630597d3ca34a8520de6f8000000000000000000000000000000000c72a1737932a5fa47f9dfcd147c390dadb90cdaa8ef638d49aed6403c7f317bbf1f8180c17f2446e2ba05a79624df91000000000000000000000000000000000f5c314bac423a7414f97ae24b2eb499eb1a6aed5eeda0b4e8a3e52c392feabccaa586b8c793ce0a8dd2ec57b12ea9d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189f35bde68355420dc313ede7bddde6da4134033d08dfeb20d2177732b8c935846d8863d8513e02f7f8276bbf9f9df0000000000000000000000000000000000f85b5be789da2e739d08e885b9cea05c43da75096742cd947a80ce34d7c92bd7192875959d632b95e628f4062f408ea000000000000000000000000000000000949a909353d639529a1036c3811b63aac0f1e3bc0f0dc7f757ea2e79c82ff83040163c1511f4d77c4043bd6b29752f40000000000000000000000000000000002087c2aa2ef4ec5703205acb991b8aae33f33a4818a481a56316317c63296e3a2acf0d3604d00f84e6d3ed0e4da089d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098c85d6098e2e3cfc54c17bb4b00698deea5bc7f04018e514fb162398148cb81af8e0768d528fe0853426cafc5d004800000000000000000000000000000000076ff0a79e54a5fd716861d60f463534d3f9d64115ec72bab2ed6472d0fbd52face7e79d0c63f581e3978b84518fbc44000000000000000000000000000000000c2fbf304a4afee5df499a9040ff36b2358f5281218b6c884021e481f1b0ad2c480b3bec36bcbafa92b235cbcd6de8120000000000000000000000000000000010e8ff204ab55889910d6cde29219ec178d64c78f321f4a4fd98633b661330a474f7de7e0c91222ca5af7636c53416d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fab00a8d97972d3719825ffbc3cad064bc6a88fb4a2df8956c780f07930b20214aa29b339254fdd533839113a90dc780000000000000000000000000000000002f60f27634587c7b567516be673cc5fde7e4e77b00d4da7db2be2ae193d356e101e278d35bd49e114a030f8affb6e3a0000000000000000000000000000000012314a8014346575107a0eb34f7eb359d40e3b7ed29baeb5529cc73f25a151beaf2e3bd0700451c56da61caea596c8bb0000000000000000000000000000000014f9ddb4a24d4729684893936a27123398b340fd96aa763819f4966569c4fa422727b6bf035ce7b399898b31a23c5f3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152d1239444f495c61e3d6b3fd727fe7cf588c6127a0bfd5b3fc7ab9bad9b101c4c21790c7ac05cbaa17afb997dff5310000000000000000000000000000000003514e67ffb9c0b317ec0da5ba6d8893edd3bc4e76e230cde3de7d9c05e97527accc90e1fbabcaccf6f0f9a5a96f56fd0000000000000000000000000000000000da40fd0bccbee905f7e0f1f1e3fac02403ba83a0a3c15be1d3f313aed30feca69907c4d41277f7ad619bb0b3e36f6c00000000000000000000000000000000063f9dd09573d73d89bb783d939fafd6d1b333797a64607985d8317a1091fa4ff0464b7e8c6fcea2c4ff1bc5456a78831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000655d886f504d57faf1515431240c93c4ba13a04754a846aea59b8a779886d1d9b21182c55891018a2c87da722d3a14f0000000000000000000000000000000019ec8f737643ec3cf9af44503cae1e8e5c8028057103a62a7c3311057d208c6e9a06e80b09c63a0c7d5329b7c79d15900000000000000000000000000000000010a504bbee291b5bf5745a345d6a145d6d0a1ee614635923f45f8907dcd5e5a5f0276ce50c27e474d91448a35205c5be000000000000000000000000000000000b345c67a5e86d0b76f9a4e8312180b9dc46ee82208b7973a8c4de268200910bbae6a166d1a032ff0476d4871c1c62801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d34cbfe16be9cb89e4ca692fc9513976e24d8f826112dd93c1864dddf5372b9fde11559e0f17aefbb1b7b84932d3689000000000000000000000000000000000d4b1a482a504e2f47381959c2e43756639a1cd9ae2db035ac12263f040f582488598c2de0affed7acc255f0b2218e9e00000000000000000000000000000000161a4fcd013259e6a65a9d3358d756be6eab673256a73c13df70d4b7f5820b5cf96c3fcd6f6a20d393a3b3f76fa6007d000000000000000000000000000000000603fdd5d73f3d57d5e84c1d7d70d50bdc006df5f30a9eb990b243567a2e05b0c92351ccc5bb6e4049b4732eb9574a461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f75f8bd3d5da8b57b30085bd5dabd39b44c871c7b11f2099df1a86a2af3d963896397c523b7ff540f6e090da10d7a2900000000000000000000000000000000190abe7d06aceb09c4d0436c27c7c5ec5fc7aadcc223412bb5f984a3341148829b0fa4c4bc4eef506c2a91e8ca3012690000000000000000000000000000000004cddbc5d197cb038a32f291b154e57292d471f906dc786d2a7d185ea1521ff6780b51142a4db4e91057fef1ce1285ad0000000000000000000000000000000000be8608d4344ebdbab466ee582ee14f873f1490b6763d1cf10a3d6138b2ef0e95d4f854048fed396a217bace73fe1291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d99275b0cb9e093d87b76f7c7a71e15ea9822c22e7cfc4f0864737143d92e5dd3101bda4074de326b844347761c06f0000000000000000000000000000000000f7c9b3030fe62c02ff067e23d9e8db36052b2746013051aa118acd3cc79a53a8af5fa016e72827a70e08c9c20c5773a000000000000000000000000000000000a915a8a18f1a2e43133b88515e645ddee5e99871ecc90f31c1697670765d892445e347f7d1765f48d6a27725048dad40000000000000000000000000000000003246e960dfd5644743e0654a65a755605f28f3c8bd679fcb9d11ffc67227ee4169d91b18f947c3507070eecd6bbfba71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000309ee42999c1333541620f60dfef1aa86e2dd0048173bf8739d116d3912cc38c852a56c15c2bd4a07edfd9d9673d998000000000000000000000000000000000b42acd7799718e6dea5bf2fb76bd9dec576e9ac4f61b92687175362aad0256c8ef845167b4216bfae86ab029390d7f10000000000000000000000000000000005008d39e608f4e4ede942db4654bd14b7ec8def70df20dda982fbc8f0e69a30d2f91adde2b99cd8c468d84620e2df7500000000000000000000000000000000013a39a75098ef70f1f89e24755a708b456997e5d44ce66173a1c1d43366992308f72c7c88e60da9f9ee1796773170071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dad73f84474b92f3a891918925528e7c81b7773cf88890ceddfab0b3c535a5f0637a71b27a6c02ac964998e56154ac5000000000000000000000000000000001196b0c9577a810e33295f5625faba44640486f4b46ee744665e66d271a04383979f69fb68044259bc327e077f99733b00000000000000000000000000000000181772b69f3c8bb7a4c4a8beaedf29297b17d7920020e57b04b58cf8e3e20b74e056f5cdd4de775963f6905ebc0528300000000000000000000000000000000009638b56b40e2dd2857c7a42a341f49d9b32f5fa861d0802fdef175e38194a776db7e9b58023b6cc1a11e283b59412311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e26d1c036e1b0437ea51f331a78863c57267e5de8f7f62d437ab3db8df80750ceacc64c27c75061cc6d3148e419c0de000000000000000000000000000000001413dc9007ffbb3a4ff36ecad179e00da24f49fee810f73b09ce7b219627a471a5bec302f71ba003e8c5b9a3c2789d360000000000000000000000000000000013fbfda0ba359d71604676c4809329de14509e7ff0a076b818f30985579d37b097608700f323ad1cfe1b1525d596df600000000000000000000000000000000001c25db3ee3021ad7a87e6225339f2ac5b8eaf1151a86cb9934e852866432bac0a047da92ac55d26053b03204a4d18e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d44f71bf6ff77fe7fd692213dd2d554b0da78f5eb38565b36ad75b341285a3e8fab5bb0efb5a65c7936c50345f98d70000000000000000000000000000000002b7b2c5916280b9882754f6dd9f9509a9551315eac9f44006115abd594920ece186d591304dfc23211fdaf2f306a7e00000000000000000000000000000000015bffe11fdce13627f1c40c04b102bd66777d8b2ddb430caefb6c787d9323b87d3504d7c7343f9a86598cc7e4a72102f000000000000000000000000000000000948c6669b9593b2a1083aaa6232dcdb25dd2e56b3312ab0aa0a6a226ce5f0dc1ff0fc5917605483bdf071ed2b376b6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000101fe94fa6ce1d05f7c86cab15308d6c6238627aa7666e82d65e8d47135eb27271ac4fbcfbd3c868977e0b3074c48399000000000000000000000000000000000c7a99db64113cf884eb7d6c5f74475867bba483ebcf7201c90e78d54cf652c1d0225c4c3330756f5a145dff43200665000000000000000000000000000000001439d8413d0ea71bb350df353fd3e11309533f7330018a460b5b2bcec56a5ee768aac159d44b480e02853c9fc74f951f0000000000000000000000000000000014f5eab5cb3d83daf0b7cb9b09a08f7d1c8a34c26fe60bdb656907a6a0d921ef70af098381b11e95b94685fb88dd9236", + "Name": "g2msm-20-jwasinger", + "Gas": 286200, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000d39a25a214788fdea5584867a70913b76172e4b2a1e189fa8b6bc2761a5c242efbef62af940e3e094fdebdfc41f167500000000000000000000000000000000115d4efa0fe0c68e0fd4d05a577639bdc8c228f2fc725a4339203236c49555929d1a5cf5c5c1629d998688e1775c5a620000000000000000000000000000000010376622c7b197ae58cdcb741b337ecc712c62f7fa84605cb2ac1a7e8a32467a83a5460a7e516e145f1ab1385a300be900000000000000000000000000000000064af86fb8f9d5939874a1afb6a642eb9f3a9e06574bb5cefc688bc30ce78b3a33f0d43c6f4f0d80416ae090cc03ebc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139d330667ae626b29eec92ae0b4cf8374a26e1058192c61437bdd88c85442942d7e2c37b3c09788bb1df54c7ca2fd75000000000000000000000000000000001871be9f24dd650763ddc222611b6404cc9bbea21ea340b7a6dd6b4fefc3342f34409193ef2f8bea4ba55f74ece8270a000000000000000000000000000000000f278f73c7268f3e6917ba348b7a64d0ee0a976474321e04674b765b5bbeec4e3c869e61a3f336c568fa772e7891dcb700000000000000000000000000000000133274790ff2cda11cd64a8b65a8a9ef4e0f5abeb9d5f49e9b9c01259f94b8d895d059011201203ab1320c710dd1de831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150a4ed57d2ae3bc2c1b03e5917665a9ebe58c900e81139f482892824fde86ccf91b5805182fe2f97828956c4e5dc8880000000000000000000000000000000012810a6931ef0e8e5ee3786b093575cdbce5edc12734b897a6b9548ad4bb18205158af64e800a43273a0e174f901a79000000000000000000000000000000000141586e1111fac7509c0a3a53a37fbaed126d7372097cd7b71ea30a5b5610d1e8ec954f868c8a98d2c37a304f0694aca00000000000000000000000000000000178133ae5e01f992ab21bd72d14df795ff3cc2b3d094149e2201be50f224afaa2b0f4b174cc4664b9768f383ff143e7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b73035aeda3d68f2cb94dc36ec52fc9116d601c133945e9049a5d5abc58520e319f2d8cf913fe3148592f3755ebbc5b000000000000000000000000000000001563a3151250d5f367c1fe2b805faa422d9d64e837be5dfcdd9282ff3c680b1d6c4661fe0babdfea456a7708b1e5790b000000000000000000000000000000000ea5f235859c59bdda2f2691783592b77a22be0ffa146848e7119dfff71a0c136c4af026562e8075e634df4d6bde28b2000000000000000000000000000000000238590423c229e5a438dcecbe1fbd5a11146ae3c1e5fe7def6e7207f6e0414e0c072a7b245604521ac35bc71c9951a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f6659018a7c8f40232bd15c83dcba2aa412477711315c903c78f86b96d6e32db0a458e44a049dc5cc69db8ace9c6d0f0000000000000000000000000000000011e3493dc45a82fadf2ba02ea9860e61b20d6d0ae4327bad0f8b19f4a8703363f7d327aeb8bf3b72635294dad62f131000000000000000000000000000000000002b997f9c44465a398942548e721218fef999f1ce33c35f28ebbe5979313a21c11a02d4132f873b859b095ac34c6247000000000000000000000000000000001597bb4d6db0485e8f69d7631acbe7ed5768b3c6b3e5ee62fc1340ca6552c8885063b3c0ab0b2da91c8337a7e4a826fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114742609b293f5d0a2802edbe72f4493d43bfcd9ec14291724f067671c88f1ed2fef6f557f575f45ea863d465f989db000000000000000000000000000000000477e9694604e26403e6aee5c1fc2a38122c169ee3d5fc00dfef401091cbef2ff13296d6c954fe3923438a6795586c430000000000000000000000000000000015dbabada04bfbdcd138bf7b568e3d51b980b727a4f4d7e12f36e209e2629c9a6687b1871cb7bac70d7557d0161fb4ec000000000000000000000000000000000a705d0f03a2f42a6a236e0c51ddf4c7307cf03750638c4a1f2526db4ac81abf34607be7b130afc8716cdb889d5366321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000089f530739a88ffe4399d2b0b802d67f63424ef8d86c3c7367d04d9c92bb364d1fc2f8119385c33d8ece83a7baa74c500000000000000000000000000000000114c85dfb2f0fabe56cdd50ff499048134bb3d6565988d2f5cbebf04c408cea7ec52051669e0e5ca943849c908c6d1a1000000000000000000000000000000001420aac64a5660c7feab07e9181dc35a13c7bfa05fd60b0fcaf22339884fa71a518a10518ff4284ce3efee9851122d34000000000000000000000000000000001434b08a2121e59e522801045a80f1aa3f92e40fd823f468282975d1880148e01dae50f0f95535b702ce8ecbcab817cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113b776460e5e8c89a088efc50fe10bfa1014a6d56232319532829f11bb1cd3a9a72ad67e680d89ec9c80c0d5317bc970000000000000000000000000000000017281edfc803809453a01d4ddf7a3e2d7c7f282775e6bf64c64e776f09916842b9bb1fb4e3f3882f4a81387c156a8d7b000000000000000000000000000000001568cc939b0dce41e38e59f381a3f06dc9cd1bc6cf96a277474cabe918b430f17d3618e0facdfb8d0cb3e4b60f7b72b8000000000000000000000000000000000e3f5db953a5a53f73befd628e89a96dad3cdb0a0db3068b8160ca2bbafcfb45f6294fbf07a603398b4e010b0d28e0d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001983452b7c305ca10487090f4cfbfe3c5d750663aa4c2de7a7e673d7909601117bbe20c85fb5a9ad374b078436876e3b00000000000000000000000000000000183df904a871ac75362334dbb8ef9d2e4ace53c6ff87f3595dcbd575b55e5288ede43a13ec48010de6a062f9815f7881000000000000000000000000000000000b5a16aa669873ee0bc44bc41d77bc16847c7d4cc8fae9cf2a89e652b77732efeac2ed8e92c2ea23c1dd9b0cb6d2a8a6000000000000000000000000000000000d208ea376c4c3a811b3f751b3c109eaed74349b0b3fbd35e78656cb6835badd6bde3169e8a3e4fce5a8cc59591803771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124646570cb501af343db7fa451aef55069ef1d400249c7b19dfac380ac6787e4a92b6008af86b6b4f663bf93f3bb0580000000000000000000000000000000016b0ba55c6791218d7643ae750b800003d27bc6677d548e7425c10cb9e56063cf0734704cf04723ff8932b8ffbe87bc70000000000000000000000000000000009f47a0596ef35e028550c0825919c8ccae551b1a2ef85ff8a0ed7a67fbc172feba2d1c9099da6f3662b89db1891cf36000000000000000000000000000000000cc38ef0fac3f0cf0f5b48aa71935aa83fc89430ddf6a7c85c95c3083fbf4d46181b1e2b65fec95f55ac8d04ba86dc9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124cf45b64fa4b4ba528daec19307d92b4feb2a3e6846e92439b22cd1db80acbc40bc43ace22f801dcc2bfeb0764d03c00000000000000000000000000000000100d8cf3bc6a20208b7cf6c359efab17fc2f339a7cbfe2cee62877369c3e4cb1e371e892288d54edafdd345df8f4800c0000000000000000000000000000000006476bbda0b56a134261154c1c06a50fb322b31b094921dc7ab0d9e8c02784a2998996b7160e0b88386cbce2e8d42f8f000000000000000000000000000000000f0c6c1bc8ac491099afa7db7c6f7ebbe97d4fbe63da41f97b3bf20b77dd898d376d6097dd8c52fc993deb5daa6606071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4830a361ca30a0d8e5d0d15e2077a455d9c5573a268930c6d737344d30085ec55632ac91fba45bfc8e125a400b2bbc0000000000000000000000000000000001007213896f16df9e2fd8e8d1d569b77581a0c30415ad926103b49cb79fdd57caf0cbd948040692909d95a05662187d0000000000000000000000000000000001227e60229a3cb8fbdd7cea3defa0bc5ef5557e9c8cd41b9503319092b7ab1572e36df10d278a104720def0900542dc0000000000000000000000000000000002af15554df9ff55d3992e7af78215ea0f7e1959d2338b2b0c021750e7473a243120025e0dbd8b0f11b03807efd900ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012c77b9b533616491f85d5225ab9817e165d6cc8c5ce03892c5bcbf7f7e7ca9e6b8a926c2fb90cea6a0994cf2dafee130000000000000000000000000000000018d1338f46a28083fb751312500a34fce24f423583a6880e8245b0fdf1cea4d68f239af7d781dc2b5db27b8a0ca53eaa00000000000000000000000000000000072cac4e346e8ddff9ce3fd6a15766e03288b7519085cfcae8d2fdf89308dec58663106660ffe5f923564c84c9b327210000000000000000000000000000000018f2dbfb9107af43d2618bbd33b4ce6ccd6045e3e2cc715253f404213308ddf05fb000d291061a82428e670e1ac99ea61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000268ed056ec6fa0c7630d129d74b4a8826d3e40d754a4d7e4b10e7929824e332c8fc26fc42d5da72299f7699cc8762a300000000000000000000000000000000165506025da6ac77470268784ce3d6abcb7b10c403d2de773d4a1adf96054034ff69baa6eb8af2e4662f4ea5a423467400000000000000000000000000000000156f4ffa2e5caca2523c59dc9f7f7c2489895b3979b2daa31f8b9008da33711d778721d9fcb6fb43efd27baa17e6be020000000000000000000000000000000013007c98d5f43ebc81e6328f40b8bdb53852b20237faed89c4cf11afb8d8a510e91addb16906e3198e4812aa0d575aa31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ae38e4448a06b3652c0b42073dfffc4b2713d322df0586080d43cc8e01ae16e81569999ef35d393a6c00aad8a2709e0000000000000000000000000000000004f35418dc78dfae10be7e95c23df39c1cf33fd2a6f7db340b3208d782443c4c02ff963e455aa64ce05b143e9083c1ac0000000000000000000000000000000012c7091126dd9119b0d8ed1fa0036c2edf864342a693d8d2f44ff6a121b6f9c4249e2a54718a7771851eac9fb53cb2bf0000000000000000000000000000000006227458b1b300f3b4f6c9e288b9300e9247bdbc33fe06de22eadd58e0c97f140eee9fdb23b112867061921666c810ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e58c3705ed5374d06aea1b14dbcb8a3418147cb6325f39e8b249949ce91990519fa9f8e45ccdd398b1c77ee56dfb656000000000000000000000000000000000839cd9d0b4a10b0b22504886dfd681fae8b66e5c7ede7ee589d236d26f25b146aefd9e73c0f3bbf0ab85e10a49beb3c000000000000000000000000000000000fadddcb58cb45ea6f26b114fa1260a5a9725dfaab21ab3e016868ef09a106a75cbfacc44081bc18f8177510caa5bbd80000000000000000000000000000000007ff48e3d179069032a5944c5d6debc6c138c881651c92be73d0679962cff46b7ec33b934f646633e45d18de01e2a1f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be26a3b063ad70680f41812d645b60317a493c3706ea342067972eea0ce73dc7c9b43223dd9c99c16d03a7906d2af1100000000000000000000000000000000012a58625afd46dcc84e7495f4b691721893b6bda15e3ab29ec26e9d58d5309de4af910f6955a6ff156339d7826195360000000000000000000000000000000008435e735cc279e17d8d788ea4405e31b610a30d0bfb2d95c7e1b7c68f77de83de77423a2b72da8f504bfbc453add3ad0000000000000000000000000000000008e5158acdefd9bad46d8db77a773524530c013d4276d5a1146c7ebc3668c4644f1c30caa4f56b6911ecb0e19244bab91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001752b8fc94768ff1b283e49c15b9a9c1c34a4a7b999269a3c998b7d1f0044f153594e7ab6a647c530d8d2ead8216684000000000000000000000000000000000197d128fee889d77d8ca5b7fd759f86d70fc3768ddda49e0646bb493f0a670f84e1585e0c761b47bebeb05bb1f2ae3420000000000000000000000000000000005b3a244b4f6de472c8b49fa6f1a4e76f95f3469d95d7ab85ecd3b8b4b0f1aaffc25a3a7f5813802e506aa52cc6bb937000000000000000000000000000000000ba9510e0e2b5f01e35f0675bfec7c755cf4e945001c3dd4d2cf54c0daaf9bbd7c952b4fa50f7d2a3cf97b85162e12961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036cc22ca8f20a09460ed5da72468bb69c07e734d8eca32e9c9831142de3b7fec683000077e6db4955e971f4674947cc0000000000000000000000000000000008f6461e3e7aec375db4afbd8931cee2ffbcbce5f75b55428c34f4d418ca2aecde09e694d6a613e5a52847d150d4190c000000000000000000000000000000000b7c120d22959585e2876ae06ed92f95091d28999be71e2b692c4e875191e677ca8424270e419b6a2e77008a184656fd0000000000000000000000000000000001135942126dcbf4f0f294f0ea18f287959dda46524a73c31ea18b7c155a64d9bf908a564c535522fb1797ef97cb63111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181a429b07c620cf367096b0ca536b7c97f86d52a87359ba0a847b68909c548b8c30327c9857e71293bce838da140a4c000000000000000000000000000000000135b6e86c3852a6d7961f2bd7f4c5853592bc64d3842ea2ee2b8e088ee84af1f73de34df9c84bd0a352ea788758c455000000000000000000000000000000000e09cb6ac5cdd6046fe06f17f4622c661ee17d1b7d3ac39bd8c59489a187b0c857d0f5aea06c297348f001af350b241b0000000000000000000000000000000010248d6829bdebd6efa3e136ce1f9346929427e19324a1626ee537c415e6e373b8126bfc18643aefc1ef80c0071d3b6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a3a209680af4f754fc1178bbe7f98353d05aae0edecaede00b0c3b6db2e97636325d146286906096e333174c6c0223000000000000000000000000000000000c542cdbc7235badf21918d050c5b6ef59383c476362302221a2a2ac3991b1f0c10d923cb8a40db5e73f4e69594bd89b000000000000000000000000000000000464a7fe7e6ad12deff11477030210cf9ca5cd59ff25607fe16b2fa66011ec29f864f556219a586a138ca5f7745d227c000000000000000000000000000000001201087aeb3b84a41c2168798df567b8c09e71fc4b7261fc74b5f109a08197e54bac4a62173fdcd38f002bd27ec140af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000dd225c85f603cb15f8b19f0c3680726d6d096bbcadadd92eb074341befaa1698cf47bf83cb9965589b53e10193fc76e00000000000000000000000000000000042fb747be70bdcdb93b1be8a8828cbddb19dedbcb383ce417c25c138abb2d086a2d84fa3fe3d6b22ec97efc1588414a000000000000000000000000000000000c810d6b798644d14741635055bc5e3b79735985eea7bc6dae764d5290ab0954b86c2edc32b4205cb3009a9ea446f8dd000000000000000000000000000000000c0024c00b21fbbc0cef50bf2572e3208387c496f74a437e1691c94ce3a47d6e61345a81283bcec4837f3c8f37b1f0f7", + "Name": "g2msm-21-jwasinger", + "Gas": 296730, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000b8781c78411e83b994dc6b0cabeefc6bce0496dd4b02d1bb048f6d1c124af3eb812243fe49e16e96001e2b1a854c36f000000000000000000000000000000000f2aba4600491cc17070c314d6606db197a165deba2e26e5817274961c8f51b2bdb5df3bfc6ebc57243e684f0488736300000000000000000000000000000000140e9c7412da3284c6927f9abd69cb854087f48a874db2516d5f6df187ab7cf8c94adf2ecd328f1654be5ef406b031b90000000000000000000000000000000001a11bb463b2d349d2865d1302469daeff2078e7a0e28f5f60208701f49cfcfc8788618fa68f6f8a1bff98047e2e488d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6db6feae76582eb0ae8aa799876c5fd985ad37b54cb3ab758673b508c75b3fe2ab6ea13c068b046976fead1f844f210000000000000000000000000000000019bbc682ae9570e586cd52e2cef307fcb2e107dcd19aff6a13b1648f6d3f594def99a0e7cdf928e2338ddc38ca7eadcd000000000000000000000000000000000a789526f4e2930d81a190df174134bdd1073921215706dc9bc21b61cede1417d3e11647909bd601d78cd0f50c719aa90000000000000000000000000000000003be552ce382a274dec5b8e3bc8fc4da584b77dbee4dc7afaee856b50c992303fd0bb74a75a9a1b7886ba42c90c5975a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024903c05932d6fcdeb0767306df033b35afaf1404a19918c309f221660d987536993427609702f7019948c6a6afbd62000000000000000000000000000000001034088126b90c116f58a7ac6db4e5f2499712e13dececdd535bcf7b911100f522801c0592d7ca34d41011f6d54d92bc000000000000000000000000000000000a808eca3f7c1d3775bc2991dd81344e54eb066cdb6351e5cad71845753dc5597f8507d87afb9ad5c7de6002eeb1660a0000000000000000000000000000000001487afb91406d1d284187b8209d5d5fb58f0b38d22324d66a36d2d562f68af38d36f1a6c1d35346c8672d03e18b4a251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001dcf3408622fe3e87910c4f1c22a7a827ffa2f948f3c0b6cb4d36678c4786acd733f1e12cdb6220bb61d65ad6121a7f000000000000000000000000000000000adb7fe6e7296f71c60cfde98a823c006b6320d9fb4eb9b1fa6d4856dcb8ac5b85c4fe40320e19df112bc4d2eb0e1a740000000000000000000000000000000013299080e68b93a62069c350751ab6a5dd5c8d8ebec1df4549a1f18b89b7395ed81295b022d554fb48810bd37a18b8430000000000000000000000000000000016acb9a1c265c10d8d6d2b1aee4f8bb67c52ea534ec80187d8acacae221fcc5586df92a026907c88600dee1b5bc9f1c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000815e455667ed67aff8ce2200f5ded020385e0746e1b68872314bc7ac9e1682fdb8cf69f48a1b65a2d6217a64833cecc00000000000000000000000000000000021c1482a976ecce6bde5a240849407c4e924bbcb2cf6a504c2ae952809115ab3fb34ae741ae2a92e32d0c3ce639911d0000000000000000000000000000000003d318dac2e4971427c12aebb894c138f7164492723ce4b319422b4e9adc7c8dcaf870e42adef866d7585b105d74e0d9000000000000000000000000000000000df017287bd512f80b4cb62633150e64bb41419ce001fbcdd1a273d04d7c64bc773bfa1de93550a896254dbcb8a777b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f4d8d97484d5ef0b41e33ad7368e1708801d418c43ede1932bfc660cf55f89f592a82e67b4332238d64786ede139b2000000000000000000000000000000000816a4a5ef1ab233dc6b8cd5d40066d27cd8953ab220a47745e27073c324af2b8a4a13e531d1ba79db42166f3bd938ab0000000000000000000000000000000001de3e52dae742e81b2881fb7da2d2eeed801df2d5d52f7679a8584e4be23ab4e7738812c8153c2128abf452693af2cb000000000000000000000000000000000d44da7bf57931175eeb3b0a0751f5e42a2f26aa9e1ec01d2521bc0b54c7d12bc6a783eb12c5bfad8c1956791a25780b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1c4ae2e37fe8f0dbeb08cea7ccaf428ba2738069494a8c6353beb14a1530272d17f8a20ce2a5aa7196a9bc20e7670f0000000000000000000000000000000002f0c69da7751d7917e3d8d1d0e4ecd37222f27d8929e3b885ad91d735b915271cc13ab2781d866f429b1802090c5a5e00000000000000000000000000000000193ce4b6ba605493d34a199e98e7e21262dc2989fe962d6009aa8b1f9e58e5043ce75fa616e165996f49496a3daeeb360000000000000000000000000000000014b32eeec7d833a6d437a2319f9efa5047103cc18d6ddaaaa17449395c25ecbff0a03020aaf0ba3a859d048e37467c111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1c90987486f88c8b2a91370e946f2a474985d312d783067c794ac2b92f394aa902058e85370c99324740f74a88ef0a0000000000000000000000000000000012b04200b415af8abf6abff7554f789da2533896f79d8248ec6ce07bc1dcbe66f8fbd154b0c85880d5ded1b0f946da70000000000000000000000000000000000274164ed8921d5623c92bd1e788ceb29cd282375fbbde988028a6def27dcb2fafaa4b1a1d21d20bb8b29b5d7772f97f000000000000000000000000000000000b57883385337edf5f0f96e1fa72a2b7157673b595d7e8525cc0402843a1ffe87668bdd2c2f8564ecc00150d0808dcc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000783188b04df2608dea14416ae634dceaf5c8d1496fe3e956a560cc4835d34ade4a7b28e7e00e43f7f74b240b26ee9eb000000000000000000000000000000001372ad6f9f9ba1328b01ea4bdc8ceef33d0e222049e16086254ad119827f4579233814ab4dddb8115fa041069a96f43e00000000000000000000000000000000054c387ea38fc362a4ed61f09210d00b699841ce86555a95ce278e61ac8f0a5e21d258a093d04b41f32751c29082779a0000000000000000000000000000000005c9afe9ee25fc0c237d0a6eac9fdbdac5248ddcff48432c2201fb114602c8bfece4b40093fe1d1c103ed36f81ae5e721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d83e3974a7cd31419e1421503e0a6b8f7f1fb00f39a25ecbd51bf2950f65d077d666e221c0b786e8e565b67651c178f000000000000000000000000000000001811efe5aa2e91ba296ef5eadf3ec41f80a698c6039bd13f1be6c54dd128f290b262374a4959423cf380f044fce59c1000000000000000000000000000000000195342d27afd5ef6dd1fa88841ea7305092ecee1d789fd7d148027fa60e0fa881a4c84dc2b94373716f55a1eaafaaa4e00000000000000000000000000000000033120cc5ca0252faee9505697932ed25da821790cddef920b5371fe102c92a407a91b356bd43c4c733cef59cdaf768c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000466179a79a138ee6ea87e83525bdbf65d3bd43b619c8e47c79e1baa930d2ceb4324d551b788e2a0d21e2dc0db33be3000000000000000000000000000000000120313a281a7305ecf80d91fe2fc609c9958e9adc4e8804ca686d5348e75bf7521e29c539153adb4d24c26c1745035f5000000000000000000000000000000000e6ca13544d7eb6bbbd8d7d0a1b852d6bfd3339e3ed28f3d0d412c048b05c6a4cd47779bb546c9330d618b953718a27f000000000000000000000000000000000a2671245938ea3bbf536bd720a667ec57bb02d7c60cce0cd9e1efc42b56185e99ce13cd95946889a54190a321522bc31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b82769f03958450f004bf7fd0173290b61ae2c0fa898b2d5ff7c0b67d37fd78e6b405f443d5cfac46c65d28c87bee6000000000000000000000000000000001500c48bcc0030640923b2b62c1a6aa1f53c0b187d7d80ad2d60c822c74ef25f3744e616277101cb5d449e714bb037c60000000000000000000000000000000013d41057ef9dd8bea802a7e9a9943016307545f15b7929da36dc9c7644eefbbeb5aa27ae53d39715db49ac9dcccb8b9a0000000000000000000000000000000014750a69aa6753516e69084a89e305a23b2a9ecfcfcebaf3529e1683dc3aa8be0905a6a4ab616c0b10bdfaa5113a47211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009395af45db78fb3d959c19b106e3a792bfbb1d52813d03f712d344ede0208b90137581e4355d568ceb5493fe85a3726000000000000000000000000000000000730f7dc2707a1d448d656f1e2aaa764bbdd2bd1bc73739ff236d433a3f1ed8ba211cb9a396df2fedad8039c19522f330000000000000000000000000000000006031dc4f93d51c1efa4aa895d902b1886453ceb4c5746e9df96fa15f8c741c607a1540897aed955ea439367d365f427000000000000000000000000000000000d804efe22e55bc2db9066c82c9b26abac303da499b155bc07c6121e369f5be11a6f34c35f604c120553fdd65c54b6be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015fc89e4ebe7b181578a07e3bcc40f6eb4c3d998abb13f12510f9ee4b37a63e265a155e2331bf78ef349d4a40222f8d900000000000000000000000000000000176d554a58c23a2b19b267b10577c78a44bc6000d638d9adcbc8cdead61521cd643810db4888a38f24ac02afc63c07a50000000000000000000000000000000008734821dd3bafe78ddf0cc20828dbf46b24cc3e8ef4d39cd4a45357525ed77bb2632b09f99cff6c7afc85950643e62d000000000000000000000000000000000f5e40bbb52c510e1ffbe42f35a8c845a50a2cf69238ab0f00ea6f964e4cffb0d23ba711d1b587d76bd81cc31afb81721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012cbe4974098167d71d8a7c1a16350c6f510028be265d3ff3b452112f379b779ba7209ba99e8487d581ec0e97ad0b307000000000000000000000000000000000be87a4237380213a6f11752ce78704a95b99282b696a502df73f354e33d83ea1423ce2fd273836ed7f67dc7dcc93f4c000000000000000000000000000000000becb32187a437fdeb82cd7c2a34a3462ebdbe599849dbd2c2ea4aadab9a4d998aa8e83acc7e4266622075781c7ba6d8000000000000000000000000000000000f2aec3af375042dcac3e812618cf1bf6fd5368cae27615ea7bf56479aa46056a0d3bdf5c98a499b3295d696a289cbb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011aa8bed00b25bf550853f2b075e289f529c0d658fe3933acbeb9bee99918de1a3e6d9f9222e9fe48c9d83add14c83f1000000000000000000000000000000001887a7094663697f14067d525c28fca573a6f111f1e27f4e4a0c4020d6a21d430367450df8ae6ffe1686c2d49a33977900000000000000000000000000000000120e067b592929533aee3158882404493fcc832e981ea2f21f752af7f4b46a7b6d2e7da7134b629f8781653dee9b8435000000000000000000000000000000000e8c216b7d50257c0daf1099d8820be90a85e3d689545b3112d826a927498d501b56c98c32ab1a4f71150411f06e68611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d6339f062886fec71687f9a5001a7850424d7a366f8588e94d9ad9807ae439869a4b6b6e7410f961689e20be7333590000000000000000000000000000000002b6c32061cf3cb70f1f21531ffacc2b4b9226d35a3791602a0095a50c44fac67dd8c7cd708e0adccf5b443c71ac4d010000000000000000000000000000000016e78e3c098056af180109bbfa7d247a1fdab81fd02c083dc267a79a9186df02be730304bf544a12727e72cf8271ad45000000000000000000000000000000000a8436b14fee40e5d1614f3ab43a2a125f97f1e0ce6b3fcdf44ca0d37f3471823dd372799bff7e96ba674d22a2e0456d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000721767593139cbc8cd3c3cbfc0b50697d3b37d9ff557787ad92c8a0d72dcea6768fb883914135ec3d8cb1408636005f000000000000000000000000000000000198c345bc278efe6e0c81d7dbd6e28fa34a5e8c3707ee0e25d7dcc62e864f74655181913b5e1966b5430f1c6c79023b0000000000000000000000000000000005587de601e4d93246e6c0b482d1d6dada7c6b5b27f6b4fc56b99150ffbe7c0f092069644c0948b5a5bb520e3ed2c133000000000000000000000000000000000a9e1e2308123411fba1d812c1ff457cf2d6d86710511845cb3893fdf9cb69393388210cec426334d21e627805ce76911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017faca5f251941d73582ae287db133e0a57fae8f064021bdc3dda70fbaaa155d058fea0d1abb6b16bc272ed4deaaac230000000000000000000000000000000005615e24c9a8db48083019cd55317738e800eb5f1ef2aad8ee166ccb6e197f492380798255fdc300765daf2b9cc02e9d0000000000000000000000000000000004448b229a54a1b0f5783c38b0b888b70bc6d540d6029854a58d8bc7a22be4f5dd484f1ac712f36eb03fb1d831c33c75000000000000000000000000000000000cf1117d62bdaa8ab5e3b738649c64c3ef57909c9020d20a41d7ffb82f9c46abb865f95027ac03912716de511d429ed41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009173d831df901b8c85e739f6129309c81f804b7613bddf09267a102a55a02057d0cf7ef1b3f6e07a13969fdf264f8f70000000000000000000000000000000000b413ed93186f076903eb41b9ac5638e288b317c70ec09c0e5abffa3b376092e6e08d17f9967cdd95f35daae27d38a10000000000000000000000000000000013f19b6f840efeab4d3002dcbce9bdb3cb2c7fd3a47a7bb57937d268146ade463b1c0b1c246edc084d31d84283f8d308000000000000000000000000000000000a73ea2852b9a49821bc19784e8d6beb4bbe6f7a4b820fb6511b3a494d3198e44e5a8ea4ef0b64ad6d5788be9f2a30771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005223315fef4e0b783bffbab63fab52c1f71d27dd8ac1a85acf430eb29b81a51c21764961d1019c2cc4f1c4b31b1b395000000000000000000000000000000000cf89bc10bf946e0a74c0e21f3b3e56701790c778b51bd99a35f9b1b9fe2dece1a15573d3c9776213315126190f462be000000000000000000000000000000000020e8bce554499dbe0f4094ae2680f1466043d2dd21b84a90f3100b5b4d855632ec6ddc11293dbdfeab56e4d6177b70000000000000000000000000000000001030db39218d9d54cfefc38f41b9d298d7e3ab2ffd15ef33074d4a88a74966ff44255ab509d41ea30a393926a88ed63c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013dec914f41fa13f1a61ffa7bd48efd3a121eed737000af4cb6eadf45501fd9322d00ad5f280e547d53f814f5ed867990000000000000000000000000000000019259c47668ac612ef14c2580a14918adb3268473940f0945c4e8a26ca3ca032afc8cb054324a021075807ad9b6ae74d000000000000000000000000000000000ae2b72a50c2aecab13cdb040041b727452da7d6a836059e49931471b29c3223f3867eb240437f3173cb023a5a3ee5470000000000000000000000000000000017248f40deaef2b0c64d40af50cb6f0223783880853a2e7ad39e20a60da7e18abc5efaf4add2d59a41ccf94f11f6aaf81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000170ec5c26a0557810786be0b2ceda3b427e6d79d8950fd695f2322090f476f6eb94aa75f88910b42ea179bc76d2bb60c00000000000000000000000000000000075341ead4a03c50340461e34893fe82f8bb0144a4cbceeb6fc49f1dc7460e5a7dce7e8f79a8aa9170f7208b7273f1220000000000000000000000000000000007bfadaf2f7444c8890e8390260dfc5089f4b9880dacde3c30f02a8ade793454c4685fc4e88ac484fb54faa18f8f03920000000000000000000000000000000003c821fa013622a2347a90e8f740222d10c694ceff3b8ec781b6262077964313eee3c6733a3109171fd0801fabda4843", + "Name": "g2msm-22-jwasinger", + "Gas": 306900, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000573dafe5336fee19fff6eb837c3c33f8a618365fc85e20737df081bdec328c796f4a038cd958eb93a6f27aede21658a0000000000000000000000000000000016240923f684ebf178fcfbb478e2b1a32e276a35a1e07b9d5ae167154d31aaadf59f10fd412654f68abae35f584e57e800000000000000000000000000000000058980853e950fe1b9fb7e6f4be5949fdd76bcea95a8a21cf42dab68f0986752fc37a11a186595c2395edc301ad469bf000000000000000000000000000000000ad882d1125d9e4d5eb533ed2da808321462f4948a46c945e65a3162a459e3d5c9d7569f4767cbf207a5f4e7b02aa2e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ea173e06b6a71341f802606f01c066cce64c10c787b08171eea333acdb343ee22982a8ae467e3142bbb048d5726e5f00000000000000000000000000000000061bd91dcd7920f741ae362372c2e8295e6b91d2b8ecdc58d1beee0e6338304c3573dad7336beabdada2b8b4f4f5b9760000000000000000000000000000000009794e4064487f8664138e4a238441f32e10644229806e779f8046316e0a9c5a7b2f5b46bd56ddbd70b2927e31cf60430000000000000000000000000000000000d123371104c4e592193cb56e2fd2e71990208911b7b26b5f901ce1d11e0253e3b7dc68650eff589a47d6196b5457171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113f9b34e20f2a1c3e8f541eaf1a610470a7b3feffe0fa293cccbdfe7a5c32410c6d9607b00bcdc37c7c99963fff68e70000000000000000000000000000000017c9e7ad85ac4cc2dd17dfcf8c2bf3310cbb16564f2930e619e31f870cce935e502092250213c58b8c07fa7c8f42fc6f00000000000000000000000000000000026a38cc01863f603184ea9253f24865cd1050caa6ac5a1bc415bda639f94334c83cfda5043533459883d77f61f9bccb0000000000000000000000000000000012f015d7d9b7052c9d6b61a4cc28866736ea93767713818e2315cd4dbaa9b0c6a0eb8fb26103c83041e59698c37fe89d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ebe96ea53e5765440d990112c783f40283df08450943f3ce441298fbd968bf4520d0baae2e19ead395498956c0f07700000000000000000000000000000000032a0df00ea111a501cd8afe935f8ec18eaf10e03c37a1f1a271ed6dcc6ba2645d1cfd199464892e3c95a44f847cd7110000000000000000000000000000000006665d4044afce84b0b19b2b3ebfd759ff10354c3a3a17cae4efb3f66aa00ff467a48d5c916c5603b8d505cab3304b360000000000000000000000000000000003a0a5b8ba0512359fa5582d8249479635a9b27ae7f5d36afdbcb1307c2c83bf82364be5d4162835d57b9a5e75ef339a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019480e0a025d0f11a1cea3632c2d02f581d593d1d46d91b9eabb5c7c1e38298f9ab668c091da6d4859a2519916709b4900000000000000000000000000000000185de88460a81409b1ff4fe3260caf19efc9ad9855eb08088c2152d8812cb7d2e97677d12acd7388dae3442c4c9e85a10000000000000000000000000000000002eb5e8459297296cbdf12c9c39ed1f29c2e4c127ac1bed778cb96364445ec264149237b282fd22c1b75f735c629343a000000000000000000000000000000000af81f64b37188155674193d226b8b8b0a238d47180191970df64b2b5faff2d1776c4e653db6fe55ec1677cd259d7cfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001699ee113f8973fa0caccbfd4c1788d97d0072972cf17876befceed63989f07d73ffa266239131c17926b22b0e05956800000000000000000000000000000000049596b37fb9789f016afa032e5df2ae5f745a9faa4f51398ecefa86b4a37f1eff390b5870fe1dd9004d0f9290ac2fa000000000000000000000000000000000176d2a0c9d4b28e4faaccc74c21a100b3f4da7aa53400ab46ab531a56500230f8091132e4d125bc6d087d24a1c297219000000000000000000000000000000000e24da23b7dfb427a0fe7652fc793495a2a4f4b4ddc1c6bcb2f32947775acbee98d0e14cd50083d5a43477008232b0c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006130f031080bc0d10c428e2eb39670eef0b99a587fdf69493fbb6919dc85ffad86790ea6050cc799cbf70d880f0ca9c000000000000000000000000000000000077043bc028ed97005d32b39f81ef0e16ac3534ad2ca3de8680b5dd1ee47adb7654730c1893442ae08c2703d660e70900000000000000000000000000000000130fbb574c5277cbd50ec6c601874e33b4318c66fa884d095aff8aeaa343ce6d3730328713de1b736b346e7411f9a9760000000000000000000000000000000018d4f73a8ec7a988b35238d2327d5a468fc32972a09297102290b3ab3ac21f4ca73667e71f40cfd22579bff0511c57dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001109704851a82d4bbc01db3067e7ffce0f43b62bc41e560eeb7eac2b63f07fa2334da0a54d6302d59f286b55987ca1f300000000000000000000000000000000048fbd6d4ed0d746e5018fd4447bea9ae356f16a0a04b5c0f498208b82b9609d154dbe1c914243309ee3886f759d11aa00000000000000000000000000000000057366a4c2a65d7bf45036159fbc7fefe02c5240d582fb4c35523edfc399edd808cdf1353a5117a66a42664b8388c0ec00000000000000000000000000000000193108eecac90c8c1d70028f4937187b4663d889d75197ed16921a2c3313265e4af4263dcd13eb6e6128f42b02c58ce61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8b0a9c1247a2afda11ceffa8aa82a3a2d189434eb86389d018c0beee9e5c94359a0c273704690d741630638bc3d80c000000000000000000000000000000001389bbf2f908fa04c139b88ae891ced443597634c2673d90a5679f5fa803331316ffff653e50a46b019ca76cfd732d7e0000000000000000000000000000000011c8729fc1eb877485875a85be4e10d57e1899a5227edbd716c54c037e2b912f11dc1852423e38414016d9c799faa789000000000000000000000000000000000c4f5d9b1b68e08ebec20c793cbc12bb34af6742cc43950fab789f07adfc377110f4f4fc1612d3ae13184e69ee9fb5a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d63887669096f0c94ce0fa7f2a78b90b83f688d94455cf87fc1cd480995d09c7978bd28c045f2bb84e508cf3f2734fe00000000000000000000000000000000197e3f8cd265ef69716196ce9f33b3367aa3ef19d52b8c878a4f04034e3b8fa6b7b4dc3d3cc21c2ef36d358be7c0715f0000000000000000000000000000000001cfd18eea100691c9d9ddec533402629c3b073a4799bb5e69704944223199fa58e8f513c5150f53a42a16ab87123f6e0000000000000000000000000000000012d86d93700ce189a0672a69c57b639b8ed964aa0131792ae99d5f8e2db87d9112b68283fa8cbfc475ab7ac89de388d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004279f12936723cab202e5ba813b1aef587837a86d58b77210d9c3f39df1fa92480cf4afbaca6f09ba5004b4df011a590000000000000000000000000000000018b75e3cebb5f082bf79a81d20f43d685930ed6eacd6097872a295235c0c219e54c4452378d256dbb90a39b1803f205a000000000000000000000000000000000d8ac4b96a331109c131e1e840f4f26ceab1f518db33af30f3516ee81dc17ba3f3d0b913b6abfd81c65a7ce3512880e90000000000000000000000000000000013db89f8fc14a8e7c0d2f1a87d32ade1355e866277d627e22db9396b32c266993e9410b346e375e5b84f145028c0574c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ce78132de75936116985afcf672ec342784bbf07d08e1c464f54d4cdd1bbb2394e9db13e9b6c55b50e99cd1c75846700000000000000000000000000000000164dca10d7f37bddb4933a13af0f4c43324959fc1b04393e5cb34d7faacef97db9943e2dc081d1b1aed83cdf7c58271200000000000000000000000000000000183339f492ffcb743bcb9b263958f9c301901352b0a3d282bb7ff77619d596ec9afdd579a40587fa6f82b876834c9b8c000000000000000000000000000000000c0216dba404b7877367ff064e45a1276c8dfbbbdb322c037fc6ddbab6ef5c56340aca6e74732688a0373711d2bb6bf71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1f7fd5c2dd07416e8edb2afa28115c4838e4fab00c3d316665fe87c19856b33753fd5ef80551ca1d09efef47230414000000000000000000000000000000000605df65deb0f98ea718af6f16808a845bfc3598b8188d3faf8d4dddd597862e21b3a5433bb0f5752b1de8aa5c1d30e80000000000000000000000000000000008fac76cae6ee474cf3c5c4619030b7cb0b6a4f86badf439f0aa9a235ebd7efb9d0c593e012de498043d118c4cda1edd000000000000000000000000000000000d5950d75a16f745dcae762feb6e63f5b39bd34de624f944b2f0528d9a73bd8f3b5d0dae6cffb4a5aab514b2c36e27f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c6cb30fc014742a6bc8b7a22a58e87cd10ab46a9fa03ada3878b26f4c6f5317743db80fe38f59e5612a5d8e4c70c3c000000000000000000000000000000000b4248c32d9a4366082f54e5018164294237f3aeda1ddd5140a6b3df7652d1087f5b6d5c42ffac9fdfec3d7ad2818d210000000000000000000000000000000012c92b23e5e574881569cef70fb29982c68eb7678daa7f704e645498deec1d61329be4b23c292435fd8f6312209554f300000000000000000000000000000000124528f12bc7bb332dff69be35f9525876533a6e382aa35f94c88d4a365f1a6c140d8169ac89eae2be4175a2087fde8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ce1046a283576be78d4f11a43d8bb85bf47dcf59357f62d474464108160b58d6b478a588d7a6342990b87696b4714d000000000000000000000000000000000b6e69287718b1b8e505e595bb16fca264c0cf8e6b36959c2a2bd3908bf27c271b4dd5a677e9576a32924efa2f03211d000000000000000000000000000000000a6ca15a4485ae81ecc20a775994a87196ef2c144c662335a1cf8cbd950f902398343132cfd94a699f7d5e260c7b7a4b00000000000000000000000000000000156183c19a7b7544a63a807b6cdfd10cdb6d4d7a453aa2ce73f8a6796f24e8d2d30d26ba8bde792bb75371b0c6f255ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000210da1f9f2fbcf2eb109f16c68fd5ff6b4a3877c20933b104aff05e0d5e67ab69431bbb2220fb9ef78cd546c1262ef60000000000000000000000000000000005c9b764256d66ae8e3ed136526ebe0f448c4ba27101b982284c9ecfd33aa80e4755751271922889e07ad32b888d05b400000000000000000000000000000000052ed5c5ca63156239917b2642aba73e37cf93b97364e1b0cc187679f87b030721947ef8da01ea6339eb566fc8f5c98d000000000000000000000000000000000bf4f1a50611bcc0636df65a09cfbd29dec18ddfcb193c4a8413cd73e5674257a9e10d53ef8cb68606aa5dbb94069bf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000179160dedcb63e2f35917a6cd8ab70ad59a1af65e51f7d6363460188f6fe596318aa79547722c382575835d5edaf876f00000000000000000000000000000000017de38ba68583930ac90dccf618cd6e1b4e7f3bfe6045dc6299c0e490c8275b426193322b1ab0596e2eed2d4e838943000000000000000000000000000000000ea93d7529e69d6eb18df69ce0530fd1484409ddae8e23bb484abb0c3a540b435e4915acfa0cfa273f7bc1e792031960000000000000000000000000000000000810b1a008474b4914a6231d0a69565120518674fd04ebca8c339a2173629845529e9ef6cd29c522e5753f15b3bf66c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e866151b715237be76f147aef584e63eec98916f28e720fdcfd0504fc3b13112a76f1b14728223dcf8cc4ba00f78d8e000000000000000000000000000000000c471ef3c43c2214bf15021c932e216ebf211691922d7c9b7a3df80468001cc569ea4bb4c83ecc3c30de97dfb9afbbf10000000000000000000000000000000019f1b445b70e55e70e7214e18889ab6aa500844fbe1ccfde75c5994c43f602221c3e697cd6a016696fa02e6205370ed1000000000000000000000000000000000ca7b3ecefcc3cbcd157b61f7d209a01602eadf6e911218eeb8d1e4c80f9222b57cf33bb40c3be4fb7c2494dc9d4e0b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009f8cdfdcf8bcb083d7da9e8e72d18e762486038be553f6677a28301727604fe8ac046b9cb7193c30417701d4e188f5000000000000000000000000000000000153aab72aeedb8a97a2c807822fe696bb4aa299471923c31d20de2280031769f0684ba4c24f98ca7cf70c592c261f8e0000000000000000000000000000000018cd85387a413c60a6ab464751c4dcc35fc0187613defd19b184c64e3afe6dac57f496932c2438b6964a4085efc871c90000000000000000000000000000000003a64fd6aea7fbfb9ce2cb4fff2a0306983b9d90c8e8903c8619f1ba0f760d2391ba6923494a528bbd632d8cf9aee8fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000381cf6a29715a70ce5286dc86e828173ae3fe06c90246079ba2e8694d90a83f6e90288155ae98fdc0d696d98c2fab93000000000000000000000000000000000a7b4da09d96a65a9a3d6573be454a992534fedd1d424855f83261c0fc21835737d4bebc6f99ab30412fb91ddcf42856000000000000000000000000000000000b4d407e0a054b173b8fb03c1d2777ebd98375925e182a71675639d91721295118a1cc95027d062972aed98fc4e82450000000000000000000000000000000000c57240f97ff949e569152100e495927e4e5b0373ca8ada334071947cbcb601026595efb96cf2616f89bdbba0fa7be171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0cef50eb7a5e3035849dfc6eb98979ad86a71d465a193324065a9fb62025cbcbc1af4e96d9f394c32cd027a540fe5800000000000000000000000000000000144297119710930d924376cc65fa3d03cd2e949102d6f1265aded48bf392a89ff7088b421d1752524f27249ee92444c8000000000000000000000000000000000b71324f41b0bb47c1b77376cdd489d84b10d7a44d78f965a266f4afdf73565d549da3efcc4bd01c80fb95d0040ab9c700000000000000000000000000000000090234962b70396d5768f2b38ef24b5768f19a2ce75e1b93566e4c04db71a8ca13c0f80d6769cb8d2555e47554f050151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f377850882e693df1d80382a8c73048463865b0eabedc70787fac38a8ec1bf7d84c9a723144bc29ab5480aa6754e5e000000000000000000000000000000000492d9a94390ea6f83b91eee5abf18b3fecb9d4e5a007b853f9673796776b9f846728812e05eb4d62b912b6b831a337b00000000000000000000000000000000072ba7af7471dd664346819f03068a14dd172dca6688a4553607de7fabdd9eabab0afdd4c16cf4d5f8c49544b5a3cdb6000000000000000000000000000000000e33913cfaa0ce59e7d228465ae74c9ba7cc10886f053aaa8edc9547126e1ffad4de46df8deff9fa32f2e9647e8ffbd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150d2fba6b32294ac134add1744fe56e672fefbe58c26ff6bd1594975520fd6fda6088b1023a98ded22059a3c1d06c7b0000000000000000000000000000000001a383888abd51a0abdb5e9e6eeae39a8347e4b504c92e74fd7e70699ff1165105f4d46c72b18fc993ef0bb66acf2b250000000000000000000000000000000011ea920a04b0a0f352e1377f6738e9444f8edd2618cef4a881920908d296cb2a4e7894637876cb64146072d851a5965c0000000000000000000000000000000006e4658afb854426c63edf7573b26cc0b7d9762bf096d206e5353fa5f24591b67279c433702a3f8bf4b9d1933e20aa121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000014163749a57478e3de4ec207f38805931b6615f9c416cdf03cb2efe3b3523d4adc35e7153730cab351ee5fb3941dab47000000000000000000000000000000000ea40c9c694647efb74698246754599948db5b62df56f60b4d1371ec9952aa0e56b518283a804f25009c5fa1c753f1fe00000000000000000000000000000000195036913cad2da67e2c48a80049daf94b3af739f45dc2ecf2a36c064477e5c5e7c6d93175e06075f6b1cac8aa642c9d0000000000000000000000000000000013f6c7710f3b4aacdf93d0dc262c57a31fed77acb718c6a23d2ea903e9b24a4fdcae4be85d85e8fef721b6e4ddcf71c6", + "Name": "g2msm-23-jwasinger", + "Gas": 316710, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000109865d1a2b55309aa396cced61be00ba4168f8eeef80e1be234bad67e7d031b3be285f3c686be19b4ff31e1a14c039b000000000000000000000000000000000678ce9721031074c11f59bda6943059a4fa1799ec7e2fecbdc633ac793250a427d78d69429c7eb5896ee03eb9490aec000000000000000000000000000000000416e926f86de98af6222db8f8b12b39e390254cff1b987c61893ef03faa00616bd941a7163af5d117d56f98f51615800000000000000000000000000000000005d480012bf94bf1159e5645171e7f3b93fbcc5bb1298807f7808f375dca8f5228dd31f3d4c21c24d77f86e025e351e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001132153104e9603afed940009bc5bdc487b94bef819bad3af410df82bc4487efd3e94fdb37fb359c79832f2747de487d00000000000000000000000000000000187f290cca42b2cc54eb5fb6ef0f28a27eb6832c12f7b69ef6ebc53d28086dd2aca836f8f70b318d24d18f22c3c786fb0000000000000000000000000000000015c3b039b5792ab9d020a024b9e1df28907bda64adafc3e09974a1b59a4771eb7967c3f894d93026f7404574c360c7de00000000000000000000000000000000152c1f9a5e74580a46aaea0245a3921d186f4a718fb82702f8eb0d47690bf6cb21ea292b1f11f48df604faa06f4301f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049616bd63733a3db1a6dc7d8e439641372325700126dc6cc542ba62d9edecc9e5130927a148b7234260cbfe6c08c27600000000000000000000000000000000198cc6e1dc43604503e15369162d91c8b225e142f7996cce939f6b90e691fe81de391e2fb3d0091a8ffcde2f6bdcce99000000000000000000000000000000000de50d0889e7ec35951847bbfc1a3eefbf4802ff1480377786963ed42c41993f669ca90a19e0342b9cc4fd1884d179f9000000000000000000000000000000000a9195097ad62e62fe1da1814d81974b6cdc1112129e22a3ac50fc618cab6ece88b7a286e9845b7020c19c9d5b9b582e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007e168213a4ebc47a3265f345f3550e0c55cbb0468f9958ae9abcaeb2e78f8f923d8b72399eb454a60866959efc0785d00000000000000000000000000000000128843c012e52f69c4f8aa3bbe56a746956346d21b8df78be58cf5f06c8856f7cbe168e5d07ebf8d2473cc7f042c1e8100000000000000000000000000000000001dc911f409f178934441c9cbc6d77a229589b1168c1ca410578e9f53a26ed8e7d9abbad5e8971363723558815c054a0000000000000000000000000000000018df143c7f1a1c34cea98df652e9f505aac522934bf46a2f6a57df15c003dae677a130cd9e4b5d4ca9eeeb38cc45f0e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0d7cde992b6d094a1708e7e0d20258503cf1021a16709634b91e419d680813776e7e6ee9bd1877741b15ee1044df53000000000000000000000000000000000ef1d11338728cebf8c63a9e24201dea161fec32c4345053c2019aef589cba80d7a23d2b30486917de7120739ef391a4000000000000000000000000000000000959e2bc5063d75675768853a1e42cb488c0f7b8ec9f72f9924ece5d759ee0de3a0e38fa9c0663ce196d46b3f15be1fd00000000000000000000000000000000142afc1e9e4fb841ef2237f8f6a79ff58edcb1ce7a6086d520b41acae8d5606beb3614027874492b4e8e38913509b9e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001684545c1218ba9fde0e8325bdd8667f9b561e5d55ab77d46f386876de4ae532164859fed671130bbb540445ab9691f6000000000000000000000000000000000c2b890e62130fc347ba8aef09cdb1fbafc35185c86163680024e5b63c16c7a5602f25c5d37def475bd694d8074b649a000000000000000000000000000000000f7297bee7b0846c636451ebb84c1c38ae8274bab0282a9f83af7e36a3d32a492ac1d970374ce17c9cef7fb810a83e2e000000000000000000000000000000000c63c1709faf67f8748ba31e308dca68569cc86d5274267853151aef56c15398fb62a5ae1a1f269d66ea94c674af08f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7e1a6a94e975806963602b9ba19d8ce66712c91a58da1d995d37d01fb58017de2c1b412ea5d9d5adb255c81e736aff000000000000000000000000000000000ae4084e66e05889699c1f568cddb577151fc0e6869d3436e17ff47519a98cb622dc3fdf8ad27d30360957a1c95f703500000000000000000000000000000000182a0d7d43a3955edb182051ee9f0aebfb63c7464704f01c1f9e2c640d2c0e3828c45fcb34a068714095c26bff73bf3c000000000000000000000000000000000f5f0c64a135764d7a9cd31ea971112359dd4eb88dae09aad5d4dc62edf2b10d25ab35815a836b973b8805e39f5778631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009471cc5a5cde491e67a5227bc94e301bb353c3359070f0a0f7177e7e5379ca1df5f0da6fd398150682b6ada6ac3b1630000000000000000000000000000000012c46fd7ec8568f48554fce62a4a44e0b0c22856c4ef526e7ff6741e9911ba4053fc130da9e6191551077a3094dd6c5c000000000000000000000000000000000343947892bb2623d67dd2f51d7b09a8e3af2e3fdfb2327068a9d7903545c621ada924df136e21490d244a427f114d950000000000000000000000000000000011e68e8bc35490b65b1bbde34f3582a10913f1147b8c3ee96804096a83375f36749a9878543d30d31f91033ea1df79d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009582d83d23e74c2ce61641406aed544d6f68155d6f172ed323f94781a0c9c1a64f7038cd4e49b643905b577b8cf02090000000000000000000000000000000010052709b2194ac65033acaa2863ed2c33db45527cf53b3a9038b2e07c6cca08ea497b718c149c96f2a07020ee6ceed60000000000000000000000000000000006ad74180907d6d9550979d68e9b029885d3304f583a5e8758d18dea17b7ce5efeb3b45ece098270e8f552d7c28f381d00000000000000000000000000000000194a7be0f75b3eac392bfd37ea515254a06b64f2880786ca36693c139cd54ec4cc7e0b809f0d07be98a70800b92406be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016be09ebc431180110219678bce1da6d680cd6ba44488a64d0115ef5cd954651116bdc205281771360bd63a8367c121d000000000000000000000000000000000c11280343ed187e208fa8e931a4623e0f7640310af5945f7a12cdf0e0f2083a5adda0fe5f27828a035cdca6ce9392d9000000000000000000000000000000000c4eea08962e98ec2c581a9b4990c89e63a167c157989ef6c806cccb24c51e6e10cb8261285d2d94f5c57b6b83e3df4f00000000000000000000000000000000043b3ff24ef58a0a1f156475311f27bf947ffd210aa391f954ea270f09819e83cf0247109af6ad8df78beae7faeedb481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f277f567130b1d7ec01364e23282ed6d1135fd1f32a2754d35d370c0c7127be2c098c271256208e0ed1e7acd45af72c0000000000000000000000000000000008d74f5ec8885cc079f6c05556f3845dc00c4e36d53ca17e167272c6ca3a28137ebcbe824438b85b290648f23601e34e000000000000000000000000000000000e665a7a21ed9389ccfc957f3d3f1cf57123f07e74d94c64e4d073cfa90971c44fd35aec59ae07bd7d53c36d95e2112f0000000000000000000000000000000003666c7119c745fc22355e9bf5300131b876b331b0c6f552ae9fa4ed1f374fda4a4077e9043e04809c1c0f93c65aff0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a49705939136bcfe4ce068fab6b2f180456acf483ce83b665167e6261fb4e28e2fde80bf1eaf4689900db6d4d4e4aa0000000000000000000000000000000000c3f57dc97bcc76ef1733f7907b4d07e63bcf815b55bdf19999137bba9485303ed6d767cf05c8af912da82359f31641000000000000000000000000000000000411a1136ca402475732f0ae051b9ccde80cbdaf4c6432bfd8923442c47c8b89669c00832fb625983fb9e391ea8a2dbf0000000000000000000000000000000018216a0ba8cbe92f0a09a4b7c5515f538b2236e40031c415538ab425b7d698ceac1941e5c9a5c3857ce3fe3688a388981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000da00c4674f9cc01e66d129ca5a47fa81581a6a5e8527b7638742e2d04a5be8219aaab38ee1df821e91dc2db2d0c9e70000000000000000000000000000000000b4f08ccd4951d4bcb472279a72f948bd104eda4670ca22e4aeeda4dd7f968d068d60a0a90678a65cb13153e88eb588d0000000000000000000000000000000008244cba7d088ee6f4b92d418958263cfbdb0f83ccbaf263f20d6d3eaeabb3a070550735421082f0fe251d159fa40333000000000000000000000000000000000607c9a9caf7d099076b179342779c2e8ef5d36d407b9076cfece2417bf8c37228f2f033b06d827553f4652e50bdb2821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c568736ab3dc7f5dac000bf84a737af6070b557902677cff54b68e524fc9cfe3b49620b95e8289b3796c05cc26ccbee000000000000000000000000000000000ee224acec26335478f915ed9cc0a52e5ed7fb820e89432a5e713bda42c2a981656c5d379276185f7cce6a4f9cbfb6f200000000000000000000000000000000095593da5879ddacb5420ec46cf7aa9af4e26e62f93eb8576544803474c3abcc5b35629d7c5186699d27aa1b7f84e12e0000000000000000000000000000000003f3b1c69ed04ecc14f68bac66d07cee5217ad71fd02d0b5f3d496df0930a467e2abc8ef09043da4eafbb8e02a3ea9de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a6f3b41625d46e012d4a40ff1db95aa22d211a576eb7025973da271fff61d4d95ae613f6e16e538e2f252bafaf1690000000000000000000000000000000000cd1f362402473fb90b84ccbd14ba9e72ecc792b2a935d2b8dd38f941b30a5a9ae96c0fe230410dcd728919d8b7ae3fc000000000000000000000000000000000684ca05384a96e4d802634b17d3c576931c3330f827e2e0f8f198e1158f622a1f8460ae77519283da1250c492ffcd430000000000000000000000000000000014e1d7a84085208e0411525ffc2832b7fe4137241409ea386460e2401c574ddb81c75806ace5e4cfec92ae128875e6731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015a9c663619826060576336ea35004faa2a2cf0b860e1915f7e1a5bb9f3ca8ef5dcb48d5bf05674e9667faf79cee1cb2000000000000000000000000000000000b5718430ee7dc2a56fdb1280c0ff90e0884885f07d2817c279fc720880dcd1333d951d56240ca6b271df3d717b06d89000000000000000000000000000000000d71e58b14bf0c658b59ec38e1c98f9f5c6108c2a1f4887f1e685c36d410b0e5865fdf0f7b2bd7c468d9601d55a18ef800000000000000000000000000000000157fa6c7e879115ef7789961438bc159ed50117bc4bfbea6c50a2978c31827e00aa63ab6aacebf7110dea6960bcbce9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040676a107ab7bcabb5d1bd41a37e0227d8b646347441dd0b8362d4798380aa98d23469b117b5d2692a5fa07a42db03c0000000000000000000000000000000000d5cbe62a304f16b33a210448259bc49c67a92aa3909d3b8796336de93eec26e254b2a078e3f03bd2cb3935d8df19f8000000000000000000000000000000000a3c38fe9efab7fbbc7899402d29e8dc99123db5be2737730a8b077b0dc63f162fe8c289f51cfe309abc33bee885f0b6000000000000000000000000000000000988f9016f721b0f418692c34a4b02232a697e08bed812bdf2bf13f5cadadd09a325c4b46f0015219a35fbc1766bcb5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ede42c330b01942e717e3098ee6692e6918eb1091fb896eacc4ca3b17703d17e6b9fc7ec3b193fcdef863a2b2f64a2000000000000000000000000000000000aad48577ec39dad0b112a2849de88a18c991c7f55168223ce384c8e2b9ff9fe0a243f66c50be099807bcd0bfa98093c0000000000000000000000000000000013f4a655e94a1a71926b92dd7c09b65fe121b93af61433bad33808d7d0bb17a276b71020bb541c67bdc8a8ebd737930b000000000000000000000000000000000cdee44aabb91797019f10280cb5b79917e306f574e21b2ccaf7b0a00ec9db3b36f3247b368b031bdfbbcbac827ee9571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a77802ad0e9f7c48cf6a3228d02989f9ecb00348cba3fc2ac5b4ef4ede200333579e43d4b1576044560fea52f75f57000000000000000000000000000000000be4a23b999a34c94887206f7c1afbfd13d8def10d46041c816cb5bc5391aab0d2d2a843687df527bcd5a635dcdaa2f20000000000000000000000000000000016407c14049f61c7f9b0f2e49d4cdeeb701ce4a4839422147fae1e773df88c6b36c2971768a9246c789ede4f798b57c70000000000000000000000000000000008a6577554240e7bbee830553ac0a38b732cf3ae4713e10f174d391cf6f1e58238b7365ab440c7e872a6dbfd08b2096e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2d366e236f71cfb17bc808ad7f3a9249379648934f9773538c201a5ef668390345e0f384ea2b82fb9941cfa9c126000000000000000000000000000000000013092623bd946511781c9e0c8810f4b0cf78cddb01c3b50ef59c6253ccda85ad91cdad81484a4ed9fedd51bf93bb82a50000000000000000000000000000000010c9e1c4109630faf19401c9cd51ff8b51e5434a79c4421efe87e02a571c14b333a07b6215d12d9a68dd6c42873209b300000000000000000000000000000000190c7d2704b9a55d1592d2f1124a20ff72f545c87ba705f714ebd87aee19ae3c74fb94409601e7d862990b9d1b8368801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018da80402f3c38b1a5d6fb69270c8e2cf98136f6ac7ba24eeb4849ac58f7a4462a3d572ffa5b47bb63615cd83dd8d0860000000000000000000000000000000011b8d8dce5a8c215dafebc1de7f0360c6fd9dfbb382b772b62c81c06d8f65e8293dcb2c8614663dc8f27d0a42b12306000000000000000000000000000000000146e85d62b7f22a341dfcd761d6ac6f1bbd6911847d7ea687f7b0fcd7a8053cb34857bcf444e58eab1fe1e56d4a138430000000000000000000000000000000017d5399f688c96bbf592a160497da7a43f226e1038f9b1b5bccf8ce5e8a8d7af50e4ec4220b74ac1bbfb0cc01c908da11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f81f4dea7cc81860c1a2e571e7d2bfae72353bd064e1fd86d8f625935aad1e6da4b271f4905a986d45c75257aac315000000000000000000000000000000000bd6e1e69d59b79a7ab2eefd803f6357127b920acaac711781cc0689ae04c971418157dfb277a9c0dce4e3deb441eb2600000000000000000000000000000000069c9d5bd9597914115b26ffc743504958d20b630f9124ffd41fca76789320a8dd50a14a37a5466dcb8894d7f671aa910000000000000000000000000000000004178ee76b930cdba15a9e4a5cfee483f25313e03b48cd996280c666bc647305037c8396e951f95696920abb28911b4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fb86a7adcdad34a6e76ba34627b5baeb0008198d484302ad5952940410991d6bd5c806b98a7272ed3f4242662f39d90000000000000000000000000000000002e917174ea7b23eaac04026abeb2d0493d8fbebfe44d17330f5fec06d08825161ce4a1ca94d0786c7a9e57486413d2e0000000000000000000000000000000010702803c47d175e5e1a7e84aebd2ec1864058edf5857fc5725ec7c5b2d2081655caf4dab4c66d0d7e54a8f3c7fb18d000000000000000000000000000000000021f48eaf074c2721217dc547d7238b8ab63fcae68d2515bb9f4b95ad3f4b3c6be4f637d7fc7ca108ba59fb3243f34a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a3efa39078b31c23c23a240e9bfb8d09663b81fd81df214cdce9d5aa242906db587e46c373724f2bce325caf16ea380000000000000000000000000000000010d037ab19e47513a728afbb2da278ee80108e39849bdf3395a84efed36e34d370dcefc550089fc7833d29c8cf7c1b0b00000000000000000000000000000000049f9a20d5193d133bec5d98096e17f9aeacae5f83563de13d7e79e4adcd5a841c9d937f0a824ae1b42bf1c21759156e000000000000000000000000000000001959339caae71eac4e92b41df82650e6bd00e413e2334e5efd14cf7ffafb6da4ce75abe59253238e4be0ac3244fe9db71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000137654cf93c749e5264895a0140fb7dfde588c9255d3c6c2f57bb7fb3e6ae91629e79064ad56be0cec161c2914c07984000000000000000000000000000000000dc0bb51207f05f0fbab1114abdabeca56c1284f64881a3afd7dc1b16f96c496e07f90942fb33080a76cbd0f25c105d0000000000000000000000000000000001440d633a7bb379dfe305a829f7ff91f5f282c2d05e127881495a8160e6ec0c735a24ac0c97e17f96c93174f988c61ab00000000000000000000000000000000026dbb34ecbfaf430a029c5cc94aaab214bdec44a542e83ed94d65675f2f66ab31e5fd7e1b7ec491b3daae043bd33459", + "Name": "g2msm-24-jwasinger", + "Gas": 326160, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000001e5b0e9b9f0999306f0d015bcfd39a6330ad4f498e329db3be3d777fc4a06055f8729297edcc8a233749e472dd14c72000000000000000000000000000000001141f5cce35116ab733d2f7e50edbc316fe97a82635438683f212c9edd0aaa82134a7ca98355df16e843074c01ec593a00000000000000000000000000000000021d98390d8c8310184fc0d6c385ea6fac59e09b80c1bd8a8a8843ca952945fb423f9fe9c3eaa7cd5b9d0855248feab400000000000000000000000000000000095fe0a3219857cc8e8eac816e827109a94420f8311ca015c101321afefc894d899c52995719f16b96a0fba4f104a8971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be65aa653fc0a4bc3f076806e486e35c1d1809789cad5399fb69f9d5e73924223e57349234c8e805dadabb79176d99f000000000000000000000000000000000e1312bc5792aad3ef860f87c794b90228b1d59ef6497e78fbc9d8e24aed1009c18744ea5b00398d2c33bf8cb2dd8ce80000000000000000000000000000000006b73f602327857007ff2c91da9726eb5ad84c20808f042906c4e02659fa179e9748d2b2d578ec4e2bccc57256a365340000000000000000000000000000000006455303efa265248a283b4f671966f305562d18f11305a538652ed6cf34f8af3ea5328f15304c6e82ef759b97fb15401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010f08757e8c93a21970f87cf55bcbd870eb5098159354ae37fd620d204b74e253bb5bfc2898656715483d5a7b51168f000000000000000000000000000000001236eaa4c0a1821c732d2bfe0b11478caf4be4c3c2fefa42ed8718b901a3bf45150145dbc71557a215ce2d26e8d586710000000000000000000000000000000017ef5bfea074047c5ebf6e91ac65094fe4c480ab9df4de55bb7323d2e6ba5e01cf07698ee2e24bbc1456ce9940d7fead00000000000000000000000000000000090d0b63f5f7463941b7e768eb6b69382ba4d532363df7ef413cfc9fa3aed5c6a18ab978be63f277028f29ccc54d21fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000158689aff14b4ae475a25339d63129c105d348d6be3f3abe81e66a87640157070598b726e911d7b1b144a389830f68bd0000000000000000000000000000000015e89d2fbc7602324de017b06da6e0069561d96d55ee40aeff172dd6935eccb0e333205ac0b51af925478e15e830fc76000000000000000000000000000000000d00904cf9f615c3e88073740d06b49f2fadbaeb079871b711dbb03df9e6a0281f3f886e3e6c6a0d15fcd8663430da7500000000000000000000000000000000082a873a3cf582b8d6e2da576ffbe07bc4a7f39059a683ece1de5e3cda20a86d99dde9ab9cc20893ec82a600a52750511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000096f18a7d453f59dfb7f0776c8f0a73823fbd4e18c6d1387f02096471fb98f732d44dee7f639cfbabfd2bfe8e984b2f00000000000000000000000000000000188259fcd755917e7b00cd50254fea2027bb9e094fdde8883df2275260e6a03b225492ec21da987e308c531399d8b0c9000000000000000000000000000000000abe68e995aaaaf1b11a1d50c971e789a1e21d3f27f15fe4eb4e6f04f6389507f1206d6f6d2a178fd37667ee4fff830b000000000000000000000000000000001813cb814229c0512ead9c0821aecb71654ce5c4b6050704c0f0d9f085432ff9a8572e3f77acd9a35d0b865bdc61c3c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122881fd1f5b60ae6f906d5e79cd6f2dad2a0823eecf0ee2547cff1b95388e0c788ac6ff7ed586baf4768dc2dc251a0c000000000000000000000000000000000116a1b8b19f1a1b0b8041fe5fbd86803230b78d641f64c3a263b2258721b1f30e98360c753a36e8911e45323bf381780000000000000000000000000000000013c7a6e5504372ccf7af11b62d4b5c03afb126e491a87d87103abff27af5fe31b94d39ab9fc24608cb47e5e4371f55c1000000000000000000000000000000000de4fca6d2c0a35398e7dbd0f2d1224edafe7aa4ee5eff131436394de5559630355120688e42740168c4eb856748cf5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000185b5813305b5e9ce03d77a3dc58171f6f51fe0f3ee92675abb245a6d367984e0ccab9d08e947b0d44683dfa2fbcce10000000000000000000000000000000002108d9d924de220e1073c91c456134a1244cd16ea8ceb7934c00b2a96b4eec650050aad11c28a42d738ebd5c86058b1000000000000000000000000000000000ec354d211e0030ff667abb1484612a4fb56c8eb69366cb72229e5c1290e6c5580577a6c0def70de131c490743bb90920000000000000000000000000000000001778c599860ab1d85b98ab1bedcb85eeb7823af2eba115c1963020aee5da5998d0942c87d5908f5a7e035e305d7a5171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166c237b65bdc5c0b9b3ea1d87a6a011c31eb734e25858578bc02f378d731d869baa4294e31af49ce371d2466a05c11d0000000000000000000000000000000018935715b8d63d4b1f4e6b1fbb4f450e5b3cd2dbf3a1ff5c0b03020146a506ff6c493d589b257f63baf9ccd273241d1e000000000000000000000000000000000b000a8c079bd2432b4fbc6fdc2a05db27d775f60a5a353c25a531f1a5c0cedcfa13dd08da2d9cd86206c54158993dd100000000000000000000000000000000104f7191090aaae74bea16f234ed3cf942c089cb3821f555f400755ef4e7026323d632618575f5c2ca11cd52500918871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114b648f0fe373644644f42e2a6475eadcd951e82dc8d1fd0d67c0679ff0f64e9698c9fd1173cefdabf6d2718c01ca0a000000000000000000000000000000000b064556de57d8f946087a403368e99b7c2f661b54b874fb7300dd71c011d7c5f13d970e35f1a9618b3213bf0f79c281000000000000000000000000000000000668d923a8e5104ea1ef7893ecb3195a2d29693da86cf4bdd357eb3870e643337fbe65d043fbecd1b9c1e6a44e3e5a5800000000000000000000000000000000000251ad44c3e4751a686098edc96a00469290e8323ed1abae958ff0a733c4fcd31ad59faba68a961cffad78716d40571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013caee76d15a9f200d0a33f2390d68837821c4a89133a09bcf4663bafa953765f10310648e3edee2555970f44410f8670000000000000000000000000000000016549d4c0bfb31e9c7f4cd050d32f8a8d50a6ab9ae380f8539f14a04ce171973193d116599011ba33f6512e9ff041fc6000000000000000000000000000000000f30b18ea024e3c5d773df3188ad08633fed7f02ad734a3af765e062f0195db5eaf7c9a2d096df4bc42d0a6f478f708a000000000000000000000000000000000eda93cde7dd23345b08c84e84ef379688f7ed8f9794628801c2ef1ef345bc3df80d2eebd9b6dc908911790fb87a75ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181414a164d518599eae38992f79c6d3b8e5d523f939baaf67d7aaad7044ce59bebd6168018d06d1de9ccbd1b6a5aa0d0000000000000000000000000000000017f426c40d9549db66b9fb56cff2b60f6e8a145bfc688b4c8a8e5b5784e6ef776efe474e24de5d1e4a4082deeba8bb4300000000000000000000000000000000071b3af6ae3bb0a65ceb2a40403fa97146e206069fef1f42147d485605cdfc5dc71be6a85a4f6879c0b7f51b3115387b0000000000000000000000000000000017cb7152a5494bdd8590441aef8298097cd4f0205cf6a74b466778a529746847a948c47b5acbc9a229d9b44e3a485a251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd9718e8c66c5133124643b5ea1ff00f02dfeee3bf8f578129e53bee10c82ee6c979e2bf8a4d6b958df4f28fac1ca560000000000000000000000000000000018be48d039c5963aa9d1cac1f9bc95286e08235cb083b45e5a30159e48b050be7c9f49174923d041e027608a12e4f46b000000000000000000000000000000001569409c6b6aad21c30fc7a8eb76e3339a444bebe3f184b976e43d011a527fa4fb0909ec08e1b366c010f9259d5d5f7900000000000000000000000000000000079338ab39171dfaad8320c8d1a5f7462aebf19c78f80c71be95c98b255798dd974971fd96953de700cc645a02b803101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ac1633d6a9ad527bb793767ae7c7697d58d6572c11b246be3b7607cc443ef655b7a130b07407b7389632a21dacc4da0000000000000000000000000000000018a9a4596efda2d945704a5766379f8a63843af8341aea8fd63a5abeb1d43735da19256212b72833253ce25d02d3b8e500000000000000000000000000000000000c6d48029bbde34cf9135689fac4b7bb7a75fe8813a479fc1fb6fba9660eb0e4b71ac3fd89521a07e84063f080be07000000000000000000000000000000001392848d2910b35352fbbd10dd899264501225e3347f47e6ac3d0ae6107eb8165438d01cdb9666dc2374b3ea93a7a0a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041ee1006c843e70b12b93e9ec967c4e29012a2814cb8f06f51351a5df2700489b38fac7d1266f7fd61be766a220eb0d00000000000000000000000000000000177dd92c5800d9e32b3f616948c61de96c5d76bfac2eba80b563beb6eae1dceb66711631c0216c636d629be49e7feb480000000000000000000000000000000001bf08730acc28ba0bb2fc4da448187e3b8801535c9a4ad3c070908b1cfeb902f885b19cb6347e8a15463c82b84ce75d000000000000000000000000000000001322149794ac64e852c27b4df3741edf3c1d68aa217b867d78bf6a6cfec09cfa02e3e6bd9424a1389ac024ecc5b5f2aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb5a9b38afe3636f2fc349d1f58f324fe14b9dd2393e393dee1c85a7a00994c6053cd570ac31796b7dbc9cd8d065aa000000000000000000000000000000000192889afe5265b6174d1dded78fd56bf9b8cb3d9b3bb119467522f895c5d0cbeec58bff48977e89013143eb5db5b31410000000000000000000000000000000017b78fb572364b3d4c741ebb05018dd58a701cdb5a69c193c03c742a45b99d1cb69f9ffc1840a2049535dc424b3a136900000000000000000000000000000000090dab3dc5e7c6b336ef7509058a24a0d4ba582c1c6e94cba9ca5df3d54fe040a56a619accf3218189f7de98a35bddd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c20d82dd42a30f2c0b6fcb126e68e8fd4d3f9ca0577c77183de57e0e874c76e2a0078dcbf309e5dc030e0339b56088000000000000000000000000000000000a494eaad0ec56347d8cef8e4f836c80c8a1e69f8338645a50541a5040da2f8e36dd5f7956ffbbe180c831011fc62e02000000000000000000000000000000001665c0ed27e3a8e39a36c407542e00a3bfc5b9f6b83456bab28b79132abca823c66f4d076df802260024e0b3bc3d8e0600000000000000000000000000000000155430ffe4bdfe8f784ef854bb6c813658cf0707830f682176af31b513e480b169e98039dc4baac67636db60428cc26b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181becc4c9890613a2ae6d96fdc758bd81d89b9363fddfe63820fd2ad5e8a997488a54370402272de2f2ccf9af2214fb0000000000000000000000000000000000ead30838406e3c82046b545e3fadeedfd843743796f41d71f3c8fbc07afb94460861f9b527309ac4ed091ab7b02aa7000000000000000000000000000000000a3f7d7fa655ffd5fb79ed55afe6802dc3eda60f9774258facabc2f3ee220f68f0bf85fd61350571e9bebf990715fd7e000000000000000000000000000000000b73ba70cedcf6c211c72444126533fa068509e5ab6a6bebe8270ad3239c588d7e51b80cbf6b5889fdb8e3a355fc9ea21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf7d8d3afc421722745e07f37d6bc6b1bae37d84ddb4a8ebd71b608af6ba690f0382779713a3958235347a512a41836000000000000000000000000000000000a0f1d38913d0a87293c9607498eb586225919d44cfec8119525db35aa2eaae63c62a9fe907f50e97ac3274047337b25000000000000000000000000000000000c9984174e19426c4f891621a12b93a867ae7f05071616d1dfd349a1089d47e5667eb0048c809add6e1c78f281ce2f520000000000000000000000000000000006c5b5b848cb195b0344a9d1c03825d1962a520b69d8c2fac21528ceef4a7bf222afe62604c0243601ab6a1862ef580a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004cde4d4e374afc2e31c201f7fd2ea48e59395e76a1814f025a706c865d8956b16a601a28666e180aa823bea72e28dec0000000000000000000000000000000015903dbdeaf68d21a53b7c1b4508df8b5f394015213dd9396db0b828993e2d6e6299efab44aaab10ce11529c54a4bb35000000000000000000000000000000000bc260249b64fce303eb35cc60408f701515156b336b0ee783fceacf3ba6f6a5c974e84d069e105714126accb2be99b200000000000000000000000000000000143aa8e878468eab92990f99f2558b09168e6c1ddcd198e92ce189463885592f416b92f5f8efe499e37956faed45a34a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011124c28a8d4ec4d3009264f1c88a959f0f099a81d0704d2f92ef44d34a85faa4f96db4d26bc983e075df108c8b1a6f0000000000000000000000000000000000a5ac8d1dd5dbb234907ace0a736fe80b171b14568599725685600d26e9dcc7b3ca8ad3a91c47b09c0a5d21dafc9c70e00000000000000000000000000000000016a0ba5e1a61e820dfa1a8bb70a149a5f2c0526c98adcc4f61e683bc6e8907ae04af04e65385a6208a9ff6c33c54dba00000000000000000000000000000000181a4f5a13e95c7928a2609cf45cdb8e8bd34f78f8d92457d877badd0ff993bea93b52e039cfd4969a56e3cc62f7792e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005dfa1b914057df5e8ec729ab3485d16cfb64d23acbb5268da8f2bd46c91b4aadfee745dc0b625356aa65394d96589c3000000000000000000000000000000000dfc2c9e99a6ef09aec9daa12c39580d42ef5cacdfd6fba66759320dc5c3dca73273faf2a35be290d40634ee57fd76350000000000000000000000000000000005a57b840b7fdb736700ea63bb7f9f166d284afeae2070dd1355fb0d4eaf78f5bad2783fbfce0b0b50bbc343c9b0084a0000000000000000000000000000000008848359f48c2cf54a9d11e9525b2b62f3ce5d831e5bd4bafb12694ca7d56f05cecff05e91f1fd4b3a138359b53f99a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e1645a4f01472d207fcc367ef179d101b1066eac6155e20e01fac7894551603bfcfe31dd1f4bb39631dbfcdc59ba48000000000000000000000000000000000ea97bd05666fcafa7234a745622de8819b4d0259c2d2838b6345c160e4d309c73a536e8b53cd3b5843e79ae555cff940000000000000000000000000000000017a6145a5ca8815b581ac7ce6cd2cae1710689e2c10f104574e3076a133be6753387f03050cbc41723c18e751a790ff70000000000000000000000000000000018d77dfc4b2e700314751f5b1ea97157214c59d308c200fa3c473f7a7741aea6d19186073cd312aa9e95058e98366e031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a2d6ca710cbcad434cea93d491ba77383230c90488a3ae274aec1670fe789b1724f8fbb542a2ed59215a4d866be15900000000000000000000000000000000114f44f0bf5787db5a42ffcddc4184edb2b982ef65aa45e69552ee73d60f14b6ed5fc310a82bcfd5f2ca35a5be77ef600000000000000000000000000000000011de3a286920be37bb3725d5f6f46a27dec0d58718d7a8aa8db024a499a2a03135f2de656db900efcd0624301bb672a60000000000000000000000000000000001dd2e17de5afac749761939c660f24aab48482b18ca2d433d4b3f1dc299daf29d84979c329f6457f4c456cd28e7b2911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001e501858e820f6fcfe4d68ac94672bbd55b78a3747497ccad933679973dbd3ee5fc00460866f4ce0c535935df1aba20000000000000000000000000000000018a2ca2c471567905c6347073dc366f099f71e4dbb22ea262827f43a3513bc13b274f2230f52dd867205d91fc662c3c300000000000000000000000000000000143bbeadb69f9f62398483eeba5f31b295966a2e13512ed55220e7aea80dab981266e6e218fcc15a997463098be88f84000000000000000000000000000000000a04948d7a40e6e822dde1842c8d7b233cbf2e0656afe9f1f8f4145252a76f501740d2183effc4b7032dcbc6341e5dd91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e54526b9ba6727fe4d0b78a5941f01a88bd46fcf3ed6177aa6f7fdf907028d3954ef66cb64fcd7a3ab4d09a3143272000000000000000000000000000000000652522b515d5eb665544948cf5ec2798c77b89b82b19819df0cea4da797b4925d02a8c52cc23a46abbac023a30a9c53000000000000000000000000000000000e253d61845e93a697ab2233ce346ceccc490f6d7fda2f2333dcf982e7329d6d1fa9b335e62a4fb66b43772529b1702d0000000000000000000000000000000019c605dbd244f09df01bd7ba506120a325ebc06389da8e220564ead1f191aaba38a3b8ef911b574d9b3f4e50ecf250fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000129206dc100439db26a0f5442328e35213167e677976f0d5a2a967f16c4f80812c20a088f7be4b09feac7776d61ee443000000000000000000000000000000000656eda529137539dda942ef083bd444552f576f770ee8009ad91ac8a40b3af38680cf632d629213b363135dcf8a478a0000000000000000000000000000000000e907a8f9dc2f2886460a374ec6df1111337c969f4e4c69e567cf7d31eadf9bbd2d8677eebbef2dbdd887255b0cb9610000000000000000000000000000000004c59906f69ed3161bf4769734a2c2a70f25a0873bcdf6b98abb446dbfb63268fc40e50f3b1872db89ddbff968f772d7", + "Name": "g2msm-25-jwasinger", + "Gas": 335250, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000013dd1a8152ebd368d8da76ce266836f7c379ffe033e27ed4976f12cff52af857a14284bb5017d4cb4545cc331402752f000000000000000000000000000000000d800a6eaab1b6d3ed548a6d5c6f8e7af4ca695b8af8e0bb94027481904ef0d7cb54350c93d64c5df969eed85f65a328000000000000000000000000000000000c0007f1f7531e77aa343bae0090a5a747d43287972ba52f6e825f318508be57978427adbb02f6d235033cc1e8c3eeb30000000000000000000000000000000011bdf642b99a1f9105c8f121c712625e02dc1cfdf150eaa01f8cfa8306c55f8d6e280e3f3f77d3ffb06f78d4dcba37c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060884cc5d27b3b53a08b09a35e50f61060d35260d07adab24d0f7157879f85399dc756a2be322b61520fa778205c659000000000000000000000000000000000e9929a6775cb6368baa8a470042d3a7b6c034de3fe5ac6845b5795fc6f7f5abf5dd48e65b3da824172f4abd8d9505580000000000000000000000000000000015ce595ae51fdcb3f3c0d908e69efdb31da0daf3f7cf4a878d96ed0f427fcdd3156906d326a517b287e0666fa33acac9000000000000000000000000000000000fe2bd42dceb8166a57fa05fbf571db860537de12bd55c03654d72f805fbb065dc33d20e017d6e2a6f89b2125c0c5d731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001492b2c433c2718112ae39127d5125f4d360609bc0087d8270fdb3c3c78f84fddc57ea9c5d27c1114075fddbdf54800b00000000000000000000000000000000134386f82ac76bfddd6959ab42cc45b7698a398f475b59b8a35c450601ad8d73abdefc2f73f6a77cab466a73c0259742000000000000000000000000000000000f6deb7eeb6abce474ad01528523ffa39e02a5460d087719b8d00919cabb1b1a1ca739976421ac64433c1f01c55c8db50000000000000000000000000000000009d0ce63a7d8558e4711447dc182cae1df9e3765bc4bb4f52603716f1a2fe093dc2e3b03532d340f4bf97e64eba4b9bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c6c71de74b5de2035f35f7bc79d487ce73e4d53c38f541bae929f17036ef9fea144c3017a10bd45766dafe1cce17da000000000000000000000000000000000ad440a37a68764365002e8373a3a6a690849fd5baacb2aeb1ecbcdc2a6ce121a405f5dc4c5f073b791ff29467566ff50000000000000000000000000000000005f88814ae4d13df1622efdc55cc164732fbb7d673fb661a2ebc77cf3af0862c14ab51f39bab40a57402d8ff55e8be3a000000000000000000000000000000000790087b07d0cc4446030d5af3e655e567ec5bf203475166cceb778cd281b93a11060617f44385fdefa8ee6533d30b5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161231eada139db25be678e11bfa18bb940da23262b444d005f33186a951b28df6f415a334abaf36706771e1f9ed13d100000000000000000000000000000000148b9d050ffba4de9d217f7fb35e181f8ba13a41588b0d280f911540569236157901b8cf54c5d8b121a6538759865477000000000000000000000000000000000c08c483cfdd8879e0bbce35a74dd4c338c434ef1a321e43584d02774d3df79c52891f07e442dbddc14f1a31d73f8075000000000000000000000000000000000e0170851505091e265d3e01f6b44b777ebd774a25de3b48a3049ca0943562a4c2a4fff893dfaa4e27dade075755179c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012709e704164e1eb73c2fb05b0c775244ea24aca73eec420435e02182ce093161e510478542b4f42fc9a1478085bd49b0000000000000000000000000000000010ee54b9660fbf5f28d3c8069225291c1148fa3eaba1ede6f64def59881081514de640bc8f2270099b6865904ca0649d00000000000000000000000000000000021f022db589032b3ed58f65fcf69f1cf94f8a99eca279a78520042dd3dc5a5b790a6c02de652e3fa3a790bc388a8da700000000000000000000000000000000111d8975b2911ef7d003fb8ff9fb3c75bdcdfe4d3f5773ad9c0b68abf478d8b0c0dbcc26ee02cc6b20fb5c6a73b4ad421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015179afbc87e9d9546d3d1cebeb7c9af8957f0874fe4ea50d5af9b0d14e0e67c0b11302c1ca3bbaa0cb371b62c9ea4e0000000000000000000000000000000013819bd48580f9cdb17e59ab8fd70781ac73e1e7e3ccc75d897eea5aa7e30b4d39d264d1d6800c9aaeabf74991232fa80000000000000000000000000000000004418df4824ebde248b877e71631a6aa23c17dd5a800d80422ce540fc95dad09bd42637b4092906b53e3d8d409dee4bb000000000000000000000000000000000f8666c460e334789d26a01116d74ad0c8686e86d28eac52fa52b24d6b46b4b1aa3678353116226c193e57b9c2e296021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011deaeaf2ce4f55ae4450c02000e60018162a1736d7cf87d642838d7dfaa753f43d44de1c3e3bc58ef1121c193db685400000000000000000000000000000000044f060243e928eacd93e1061a25475d43ffdc8e8b340981696129bb0af50e5bb075caa7a3c6bbc95cab39f7872db290000000000000000000000000000000000742d18768aff82dd6c9497cd19a5a0a69ada2f1f887de7b2936fb6e2a8ba1bfaf0a40751e0bb49c9c6842b29e14526e0000000000000000000000000000000013b6680c635371c13ba2bef217e733e8f60a568e68b31e2096883323d2f7bd9d34dfb24942a51a6a5d8a790e0ff0ff271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001803419526f3f72df28d9d087b06127c66520a2d5f75bf00420b24ddbdd58b913cb9ca092031129eef5ee0738cf499480000000000000000000000000000000014020aab6c106805ba033d124dea06cd0720dc3e61893f1d9ab6cb55eccec27a49459c085990c67acdd2b26e41dcbc150000000000000000000000000000000009a5b97ccd6b5d544996794d0289ba3d84cf0e1303431cb1a3f1f421413548264c7c7a14458f28c46cb3aca8742ba89200000000000000000000000000000000014e3b14a186f8008e5d25bf9fc39c604a82ea6cd6be546a44be6f2650ab1f9f365b4c3fc989a285c9fd0156b47391e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d20e3e12d9b8d9775b6edf748aa50b143d052b14e5c467ebc97baf6b165a8194d2a684d4f393075432ab0ee22048236000000000000000000000000000000000e0461832b1eb9f83f62c39abccf9dc590823c2ed8819a27b9e739719147c3cca93e3390ebfce521d51b23e27cfe8003000000000000000000000000000000000c2134c12e4ce7e80b2b8ca73353380edb76ab4524531c122b1bf0cd7dee4dab36755df3cb34a77db0187df8c83eee90000000000000000000000000000000000d0695e2124054082dfe79933f13a7a79bf39ad0fcb9b27c41d8df86f2e7c1124d071655a149701417e09504cdc36e561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a68897c046971329440530e969a852ef7c9da1a009772d2280033f8f29d94906dad61e5631fb66cb0b7ad2899d76a14000000000000000000000000000000000964c8c14e460f2ec388e58187b4ad3857f2e09ba7c2e598f952534a93e5a934f063b814b7f7244bc0b7ea98d3b210c50000000000000000000000000000000000a42167b27eb20a61c9a1520691808d6c1eb6f6088bfc35a3684ed8ca11c5e152423dd124c6a17137b9400173197ac900000000000000000000000000000000102a59307c0165316bf4504b0f47b1350e122e29ed9a4feb95a9e4848fd6ad8c41128e46e5e84e4f900ea1159501f6b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004697dc1fdc1949bc1629e5ebbc69ff84aab8cd4a5defbebff8e87611b1dbf2d77985cc931e40ba06e9d707be7f89922000000000000000000000000000000000c9cfa3c76637d5394fa9a1f5fdb712d3af88e29382432f352666903dca9942ac08f278d5c81f4fd163c3c3938638ab300000000000000000000000000000000140d1072216269370197dbf30f307692c6699c2ac994e9b6176c7247f8897fc204942ba22ca5e2031656c99f80b8a39f000000000000000000000000000000000f956e3e0547ec8232c36488a7e24a70a9c6d86dec59893477c90ef6904276471056f628250c614f81cb82d80868de991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0f2e13dee86f099cc1123ab9e006ee7d0ca1c14d80f5268c1f3c21cc74adb50c63c06b1e7f837687094fc7b3d9b87f000000000000000000000000000000000e42ea636f6c4fbc12d0cbfaaea58514c2f984013ab8d6065f565deb436a8578d432e2b282aade0f98f64708dc5306c9000000000000000000000000000000000616e759075d548e20cfc9559f21ccf5259871d3d27da8a77bb346046d95e34ee736cc2139cba2586dd74d8deb43503e0000000000000000000000000000000001bd1ae73d11d4c9a0028009fd38dc305b7cda654e92361028c27363fc09436adde8f4b6a08ef644bd62547f418392851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f50857448d96536d5ef5a3d4a33eb14d511b4f4d3b0ac99e9db29f520157e7b6d6c2d2627b65a3e5613c872fad8a9a0000000000000000000000000000000006854b2cc04bcb2465c58f121ecdef8a6b423cbaa9253bb3e0aa3e7d605d94acb93b0de015f2a4b85b15f3ea3033e88000000000000000000000000000000000187d884c47cad9a3c1c41ed1f1bec9e54c623328a8fde5008d705e5d53d60cfcaeb63e48ed9027add5f24dc85a6089ff0000000000000000000000000000000018161277b9968d0f34456be8dbb7d8994f7301011267cde3e50cae92e58fbb6643a2ae16fd769d6b97d250fdec3f025b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ccf14aa0285ac35afce53ccd0367cb845bbf2e8cd5bddc7e9128a78c5e96e013cd3f538e25526583f4e0910b147f1d5000000000000000000000000000000000dbc9db4dea63cc29caefe7ceab9a72868930efa5a5b4a12b16aaad5d6e826e3bb88b8d1cb82683fe2fd09645c293813000000000000000000000000000000000c09c8100a2d8b5719a0c0f54c6aa8d1e06021bde9e98661ad3818848da49008f21db3553749072656b525ad5e0e5a39000000000000000000000000000000000ba759a2d5faf75978dfd8f5a540a551b9dd2c67f60df87b8bfe991f1b21fbce7ebe5d4835d84108a85f3240fe1177101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166e832b265aecb3f5a6e2ebdd45ae7360ffea4f64bcf8e2fa0b57dcb5c65587ffa87909995d1d2f9fbb011ccadb652c000000000000000000000000000000001640bf86712e0c6f326929b546c40a623719c9fa2af4ff8d3630f5553956c27f7a7af27929a60c202bc911e34fcf27550000000000000000000000000000000019a7a55d357a58a9153d03dcb9cfa12ad277e14138dc25bafadd8304978403fe45f992f7bb92e544bd96fcb287954013000000000000000000000000000000000d8936b3048ef98e2876c7b1d50c4715fc04121337cb3457e707fb67969b7b464091f9d29431b5e6eaa22f8861c0e2e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f02688856c4fcc6f6c570e1c3ad32c96319a7fb5bb95991a3e62ccc1c1b09c6fa756613481be9fa164784b734ce874000000000000000000000000000000001093dcdb9c449293bd6494b022f54bc96cd8da05236d09ce7c2e9422f78673c21433fe1191f6b7a3ae6f4693d07d673e00000000000000000000000000000000016c2353d0bc006295d8fd13e2754683658eeb4e0e9584700e5f1aed9d5d90b380af59d3b10549fb84e34f8fd8ae870e00000000000000000000000000000000107ff5c291597e2e877928483302890c1129e5cf9124d91cf95ce53a58ff94c3cc5d41c4cb6a1e41f8503f17c60e1db21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001302655a302b412023452ec238ddc572fa3ddf3966757813d19d44b5eb3cf251f8758e63461ffcb9c8eefcd152aa83c5000000000000000000000000000000000247d5f87ce634fc0993ef00b1a1aa26b62573060e5682cd2e6d7f4409923c706816da4bf8cdeae32a3ebedff3291a46000000000000000000000000000000001145a7619ca369b7f721db0fc4b3bbc8e7070bb469f9e1587f665ecc2587ea9e738122930df2725cdf25377bb81bd42e000000000000000000000000000000000007b0e1c6c3f270345beef094a644c9c1ad0eb443efa124088f4d519da693d9de271cdf135ea00b9805cacc75adaede1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aff7bec9c59d4075164402350cbd7248a272c7ddf7608797ca4783391bf32db5e4e58d166a701057448ebfa818005f100000000000000000000000000000000142e0524abaeb71b84a8b95f1501e1f2ee87781434b509f9bc97c95716f15d28fa755ad905a99e3b09b5a88e44cad716000000000000000000000000000000000ac2a1de84957ace2622630ba3165c44b5969ec41a767a3bf1b541e3064ac633ee8188e2b884f8cbfb8259ed0d5bae6000000000000000000000000000000000187d392cf2d94198fe036404b56bc76bbe6ae9ad153353cd3f70b620da22e069babf34eee14939db2d602cabbcbaa8571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039e33edf77f5f20adc62ea7f2468f4074fc507d92b470a29541e76758873d3419644d3052608899afef4dd984d0b25d000000000000000000000000000000001372a6a3c0fdded5de8cfc0f6792246b4cfcebea5a53edee7e21d9a8fd727defc50fd9c367444b38cf78de35ba5aa0f3000000000000000000000000000000000071d7ee9db8811bd5b325f453f26fe83adffb6ac8ef7c7fb6390d86426c535d7577e499fc2aa5b133bbc694bccff2350000000000000000000000000000000005f5e5610d7905ac024fdf8d45efb7856902f0b608c4ec3aa6ac35d7281bf442a07890d87b04124a1c9fbe6129a689ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d5dce62126f2de014f073841b85b77d7319366b856dc30722cb417d94be30921074d0f7e79d13a1e0ebf0943c999ea0000000000000000000000000000000004444a5232e9d9b6aa04bd1e066152b79846f43d108cfd31a6542efa809758e6321924a5dbc119d831c4248326abaaa70000000000000000000000000000000008095fed5191b647fc6703ae68e3abf0a5a2baa482997ae69b477f5e9e06a6ff78c74c6158b6f02d6fc310e68970d74b000000000000000000000000000000000bce8fc6340a5b7ff722ed27d5ee321fd7ff776efbfa7265893ad39b1886bb10d693e3a2f43c01f8bc1c4de19622d1681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051b7a9c0fd37b4c35229c52e75820c84c207fe45abaa6ec40a277a1d27b601ba4a9ca7834fd4a6df7ceb26ddc7e8b940000000000000000000000000000000005773f74858625875b7bc7d0ee281f9fd75296cba4a8269ce3281f6abd5d2a3bc747dad608831ff405dd03afc5717b030000000000000000000000000000000011b7541f9044e38eb7a5e796a00de796b711d5ea7ec6e58877b6a700f808509f4db6e957b1fd23be66204d331e09798d000000000000000000000000000000000038be568c9556ccddfde756399d9ce9381d94f8f352e31811ccfcf2910753984430c8e792c3df57b49d1b4343fce3a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f7e006167a88c4378fcb43b96ca9d69a141d76d3a41457beda5c24d4ce391fc11afff933cfb9436307f87e521bf069000000000000000000000000000000000c069952ce03883d72dc68f51bf515e5d84ec36453ed17863277cd27a90a3705b9f020ae6e3da2f24baf07ab0229ea1b0000000000000000000000000000000019f2653de8f385f4db69f0ca05398025108f71250479a701abe8b7fbc0eb54a935e9546ef3bcb40882232a23724788e100000000000000000000000000000000022decb44afa4c15fcbc3691fa33a97c3f0176983ddac54165c095e118acfe334f11d0cfd22429982a963eccb6e6392e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f5ab67aa74823fbf4eea840040d959411bf1d7ea277cbd7ab906b4b277377fd2aa42d108354b256c5951a040b01f2c00000000000000000000000000000000184f7dc075fa7368b0af95ddb5b936aa21c6594fd9c50bc0879dbc9afa1b82e82415a72dcedf90c68f3eafb6246bbaaf00000000000000000000000000000000059235c4ab09f4a5fe5c2310f65d589a52276ad2c6443351ae18bff6fc165f057e3d82b393cafe3bebc419dea4d946e4000000000000000000000000000000000c7b1d062cb1aab23bd1e5ab7558137ab6d1d0f8189437c9029556feb9b0f7b2184063ec3ea2cc5f5b03176241c318bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ef32bb3e895e074d577ae2f77cd709d215f7eef38b29a721afb4955f34cbff48f6d9ec9122bcac8ab0f5bb4038aef7a000000000000000000000000000000000202d0a71cbdf77a1b4abbe226c04c9e18bb814623ba74c0d22791398e0a4374111f6bcd0d2540a5a965528bf5bf1a8e00000000000000000000000000000000182b9ed7e3d41c69a535669783b2249d8237735457edeedf1da7767489f04b7093a2d87ca03cef263bec2f9fc19684550000000000000000000000000000000009f0b7f16bce7f6d68b22cb75c59cc25c546383ce9f4df786bde94110671f0c9badb591ac26f21cbf6221e8c61daaf361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea27aac8cbbd3851ac4ede681d8b4af2db899cd0fd7e4a006c362991f820f5a96f9f158e8ccfa8baa16d6e8825cc78c0000000000000000000000000000000017ae661ab033e69e0e2a9a29900aea6a30f96609cd60bf7e3f000967e4c3b07be9f24e694956fe551347f44a532e268c000000000000000000000000000000000b99875080448c455aaab8565995c059eff1d0f1ab92d77a753e7a855a189086355e2479232fabe87a9b30aec020e96600000000000000000000000000000000059b301d1077a1a5f9f83b3a10723754aa6dce8995de68df75d8267ac578417bf47c391b0acb77e47f396ee519b74ee91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000010e177a9ed4aa48fa03898471df1568ce90b2e827533119e92362e967b5590293edcd9130bfc9c9dfef6300cde93b70200000000000000000000000000000000134a2c70f369fe2404d85a8826b268b3a9d1407d823a04bf60ad7a17229802c1c7426fde5d165ffd9561f42d8fa74057000000000000000000000000000000000588eb0c6c315f04a2f785367ace8a2e7fcce3393e743dfd7e12fdb360f4d64137b3058ad246d0986f8399c3f7772adf000000000000000000000000000000000d518bb657230d98e9293ef49938868d069965310d4082575c7c9721102cc230a4f8c05a104b41317a7d9f0b0eee156c", + "Name": "g2msm-26-jwasinger", + "Gas": 343980, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000017b466f5635726ab8cc4e790b3a2b25cd4c895d00057e8cc2ca81111b1857fd336f5b94ec18dc3069f5069cf6a2a1d0b000000000000000000000000000000001491140e66fc8f6b753d1c1ed7f4947d57b5c4e94aaf5883b2f8e2725d586f917bcc2806b74b057241e52ee93a59955100000000000000000000000000000000058a38d7c2a69ed5c8d42d377831fbabe2aa9cb6c9730eb7cbd740075b21fb905f012e182db2f0a7a33a3e579833c8950000000000000000000000000000000014a5dab2f2e5b477a776d2dce6cb194e22b7123a5894c493935ab0049dab148289989a790f44b2615a9d4ad17f4534e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151bbc615a89678c85f4afea0304dd1a061e62ddad74721a92c8f6d271d2589a41efb06594e2e311a5095b4ee49ba055000000000000000000000000000000000e32e24fa5e12393a0c2872556bfe3b15c9df4b297fef463fd36795754ed10b78df15b765a61b2851044c1d844a6db2a000000000000000000000000000000000cca7edd74278ce7547be9b6020bd09c92f77f316f94f2604e2b5872207eca2e703c0c77dd8cfedd82ce15c8943c0bae000000000000000000000000000000000cdabc0c0d08f2a46bd407d82235c1acb4e8175072b10cd719fde744534338729984487d5595cb28dea61ab50ad706a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000abc3c5c082c9575b6db14b67300638acd81ca8c633aafcd87747ebc53450e3caad1dbe57da0025cfb9ed48c366081c3000000000000000000000000000000000a8a9e81a2742f8ed63098fef9305532fe03697026434846c345ef34bcae6f03f68312bedc10d9619e678b7e069f0013000000000000000000000000000000000aa8a864a3b2b1be8967400f782575a2bc8f43d813340a16387f26f78f0006b80cf82bcd3621ab90eecd3a85e6d2e9170000000000000000000000000000000012bd87a203e4635ba35eb2f150ba4b33cd9246c83caf899e5ddfba4b0adf862c5d0921b49bb6d40fa9b2402bdb3ca63e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5400b15cc3638cb278188c6d608d0314a370dacbb47de8e41a0ff31dba6a56b0c65f7fb1ab1f4b9fbe4f3eb51d38e7000000000000000000000000000000000a7a2dbd18c4e3bfdc3aaead6addebd1c3a0d3c1b61d93d79d2bec6b021295e5601ad3bd03ee40124360a0f913c5cbe00000000000000000000000000000000003ab5030ca9b102ed5486e6ee7c4f10232a761a09cf552e90c0d039f56f4343ac4053daaf92361254559b2e759b19e150000000000000000000000000000000003af1027d3e0ed0cafec41242a1a63e2850ed3a7892bc519729fb86aa163e2297f1176e284548d3099cd14a2dec2c0b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d49e1ce5f171c5d42950a3f8f52cad144fc17ac907cd00077bf201385fa71b7342ac626f9b8fc00faa23f84dbbc80d6000000000000000000000000000000001233419883f2cd06173325b95b2d987f5e659f480a94d44a17f4186f9e7fc293f209de645a924202f8ca70c599e1b5820000000000000000000000000000000010eca16b9389b9a281aec6dd1267c302d2839a342f7dc7b65d24b9fefbc852eb445ebc3b0d9606f1679782119332519400000000000000000000000000000000162b7d1f9cc3aac5cd09d43c2a914272303749b747d48667a7c02bb923e297d1fb05cb56f92da9e650fb56154e3e97de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001757baa808967dd431d3c68f602ab5d6e662c5b028c654701915c8cbd744fad0d1613a4fd619984f7732b947d2334e33000000000000000000000000000000000baf539045f029959312ee90b4c222c2553ed343192f5d98acde57bf7d4b159c036e24b3607be3c8adc38f93ca157806000000000000000000000000000000001177841f00f3e1f6ac23563bf697972fb216c2329a66a3c3a2f91b48d1608842e537bb8003798d14590731a423bfca6f0000000000000000000000000000000004244e5cac4d05bf002941ac9e026cd2f26afd0fb7afabdccab4de13d263f86aef058673447a4182d3859441ac4ebebe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f835602b4d70043985f2056dd8553fc62dd28f894271e2f09c58e088237ce5d60048b1c36ed82900f407b8e57a53d400000000000000000000000000000000060fb494ce78f7333f21c9becea0f427e4e471396634093e121c4723c31e555e92fdb42d112d2148d4e7f959862064fc0000000000000000000000000000000019d6eebd41c715ce733c4a84ed434a5e5bc8d657f0fc0a5bdec47d1ef5f496ddcbbc4625524fb21e6dae2c765e5e63cc00000000000000000000000000000000084fe95871d8f1685935ef338e6dc5d698c8a22a7804b1e1a4d399be1ab5c55c855a97db5b3454d347e2bbd89efbc98e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019afa23b7d9bd52ea1cb6d70cf77b2b82395d3e586a4050e84cac1d3c3a834ca9c7ec1141c5f72bcd015d2b5b0de6d3e00000000000000000000000000000000009796f840d334711268390c02e5c8da4f513a7168e468aa6c9188bd47a4ce8c416e59952a5003abe83ab56f8f63a24e000000000000000000000000000000000cc0d94736382cdb24104ee6e698590c9cc6069cd2fbbaf5720c97ba981a187eaffe983427012f997fdfd0f13eb2581b00000000000000000000000000000000070fbff3c4545862f54c8313949fd9eeed684fc2550ebd750d34f6807249674b2539d2ef4b47b3a8962b473091076cb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d51e907cfddc7d34fb58668d264ffa7570afc9fc50b9bab8af566e0c135eeac33a39f7903df7a279f96074e75f240e0000000000000000000000000000000019513e63124c4dc1b4538440e07c119b631742cd53a02ed551293b6b858af0c9af8e55cd6ff5d827bf406f613628f80b0000000000000000000000000000000014ac194565733db257887988048e6f1c3394a8d3b8234b5f2c7c8d1e16c8e2ae8d47e5c49f23734838ff9a075918edc4000000000000000000000000000000000fa82dd5a9c3f4ac2009764b398c74a14c44d0baebdcbeddcd046216a5ec686a025762c447e6eb143978b9a428c621a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015bc878d170467864321de521599563a9fcd21679d30bf8e9a5db6ef8549d4c1daca297af108e04f75f1a445b9ccd4ee0000000000000000000000000000000006fd6ac6eeb972720cc434839b9bd16391c0c83792560beb4064b47257cd217f1180b83a38ab55bdf6519dc1ffa02c760000000000000000000000000000000018a517ff253ce3179f5ec9477e8c77c307efd8401244d3604d1e0c473dfc061b9d8fa6d924ad1ab4fb2662d5cb8945850000000000000000000000000000000014b3791060323ba216cd3e458f5184c05ae4603f80f1677c16146cb9c5fd9d5009a4b4118cfab9f07b67c20be2d898bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bebdf5100096ede591d6d13ca10c58275e9f8328b54b33ee8d2d852c7345cd29746d3ecfb64168359c2e3b8770a50a000000000000000000000000000000000141eebb2a0071453cc5ffb21ea9f345726fd06987be26e4bb34ecbe34a85a287bbdc906d9677611241829e029f6fc16000000000000000000000000000000001343c588ae6a0c06232647409611f5f45f3f0ca31e2a269df2122f13b01fde6d85eb3af1185a8b4ff45a9b4f9486d3d10000000000000000000000000000000006ee525a3b4564e57b24b9b1d1355897b912f778ac4cbb17f4bd8f25f96abbedb932fe35b6b11ddea29c33bb223d3e3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f69f755437bd334fc131c71105c24f0eacc161abe06ccd7bd102cf85aef33d01c24a15cd429b25b227be0962b99bbe000000000000000000000000000000000476d24733c3e642eae49ec8234e7874f4bd8aac0cc38f34b94c6d40fb1fb201ef1aceac301a158fdae38796de335fef00000000000000000000000000000000173848165e601dcbfc32d91f8e0182f6113608cb693dc6e27ae92353444763f4f52402d92ca9c5ae8026e3efda2e82f700000000000000000000000000000000005a7c5fd80b145d071461f7aa976186e101157e8129c4cb3c1c724fe09c96366031a46c8bb15fcaa210643ba2c21d921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001497ced1d027cf11ced861566b78301ec4d2f9ef815e80193cdb4da398822b66b66728596310c236b054c9c9ce85d6a40000000000000000000000000000000019400c20c4f93b92b21014e081ccf88f80d9df55caa43dcb6ad638d9ae59b6db0b7388fdefafa4a02c226bd6d94d01ee000000000000000000000000000000000ede5826c6c31c6a5103cdbe9d26c250dca6ed2143ba7bf9158891ef4cad5c30ab8f71dbeb481b23e0a532109fbbebe0000000000000000000000000000000000d1a9307e2b3ff45d45252fdb7bf85f052d6933706029b6db3d65f912fa7330aaf66a0ff65cb9c66b56a57fa3954b19d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f117f548c43bfe134a1a8a2e1861d3da3a1e3b93819e7902097fb426f35311c7d2b67ff09557f6873415137d8e926ce000000000000000000000000000000000a17c85d4a209c992bf910592ed3fb48de953404b1b0c6b31a18afd84b47d9201ec115fa829d68ba8f662d28ddd09f4c00000000000000000000000000000000006a22a4f5a69a39fa527ee223df809d86e60df03b084226ef55cced6e7dde476ff22f1f09c9960f91c42b651c74408f00000000000000000000000000000000123ad07333d2440587cec7c73cf058f02dfe6c992ff539b08391f54efd8ee7be10b40b5ac66aa6cf0b6a00f957b381361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077c9b6e94d1aca3994d5cd4dc1bd6c8901a7d34cfaf149d7d8c02f0232d71533c7b2b1579dc68eb87f000fa3dd1b24c000000000000000000000000000000000b6cf279da391cd5d062d10ae52a981acd28b1c7d3fa193015ce625776d7cc9e5736856cb7b3641f594960b98b577d5b00000000000000000000000000000000127e22eb1897edb2830385baf710090a88fee08c4bfa4a7b3370503c7b602c53ed466bd7ef2dfa88727dd676f57f781b000000000000000000000000000000001279071042c07e5ca928d5e7978d44b944011580dfecfe9474a7a64d4552b259de1fb594c57382b18931d1f10bde74021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b39deb6eca09dfeba991241178979e50f267b297a3cb94430b7366269ec87a69838cff538a4d01ab155c6cab830ee6800000000000000000000000000000000074de9246122562a40367621d2ddc9a6ea7412a54d5b3a74b591684bf5c00f7453ee1d4f48f8545f826620f38cb7fd900000000000000000000000000000000005cdd165ac48c4b0c003025fb1fc91b67da2118d0444c5f13611d392f5f3463064ff921d7befb1d90139c05b00b8b8ef000000000000000000000000000000000ecb107cc78107c8f1b743cfc4bd408f3f2a45632e664e3837729b35dd0cdab30e2a78391877d4b5c6211c3305587a2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a76848f53b0031b5512386e1c695b26e1de06a920bf532ab10cb7be4b22ab87df480970a8ff8ecb35476c6181cffdc000000000000000000000000000000000cd966ee4a5e586fc25e89003e5d14fde890bc0bd2af3c563cdde68fe028fbe9c4496c5b88e8e1c6136bc248f207a88000000000000000000000000000000000031199b879ee7dacd87ba21dbcaaa692a36f4cec0b55ab9fce0dfe7adae1dc1e5e582d0297c6a05325ae578e0c8d8a460000000000000000000000000000000005b7f517f3db32e15aaec1a08685432c200ff98588a6fdb7484d265b7915a758db9bd20360810ffadfb98bafb1b574281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac6d95f36e9d04bc6903ffab8714b4102e6b98f5960387bb7aab3b6c052a931a859baaf813d663a0c2e4594f02fee1c0000000000000000000000000000000015be3da50ff8bb3698421043ae5044abe20d64fe0b71b637140bf911b118eb835f2a5db65b850ec1d1f465f635815aee0000000000000000000000000000000014e0a2918eb0ef192ff517f4e808267f11085868c5528a68f1833a3919fa1f0913409e51703134d268eff3bc5d1aa86400000000000000000000000000000000063bb03518833e242962521dd732c20bdb4f672083a593141c9748515da0bbdb698c3c6f4572fbf4ad628c36a355d78c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae24172927010919010d0addb5f9e1e93a360e015db898f4e743bd02f94cefbeaebae1a42f29364f67a57ab01690885000000000000000000000000000000000d954d74338179804f9e4013c6bc89f1ac0bbcfcfea325e21975404e730af896de9a4c9748d665ed33708a754ed6a23a000000000000000000000000000000001402cbc269a4f1ce3a2194ed8c3d729fe76e7ee202d1ec418e83e1d1398ec3c0abf9f47687d7977c23b1890f1337a60400000000000000000000000000000000198321c68182fc313e1fe922ba70bf4676ef1fdcc011ba3805dd8248a1154580caf8944ba896ee4f00d2d9ada0d323fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001014a533e87e44a11c6155c150763c0efdba3f62a98de9c688a60b2e9a19823e4dff26db690f9b648b004bc6a609e8b50000000000000000000000000000000009b9467efbbb1fe42baa62735b4996e52ef5b29533c65529a4e730f91f12ae36dbdb7ddf582f9bfd2a69a223f81f1fa90000000000000000000000000000000012d94723501dc809147db9e6c45c9c1c7af62ac122132a59d71468088d2332f17a0f31bcd460033cdc10ffd26cd62ed00000000000000000000000000000000016c60366c8815048be831b797782150587d4036b6f65ba649d8a785d2b9b917115924b424366f3ed53c7d597826c54181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e25a976a8a12af765aba9215a395039f56236afc43c923a51bd3ce1c1dd016aa6cad6f74a0f5ea4d57474b9b76a7c2400000000000000000000000000000000007698cc2ba5cf928790a90a09aee40d950c1fc29520caaca0546d1cf8c8b024fedac2c6fddb3477314ee0052d57b0dd00000000000000000000000000000000079047c3cf347eb68ef30058578113f00937c07b7319cc0374b94a0fe1ff4c8542aa35bc18461b3f0f962625f1158b910000000000000000000000000000000019fbf94bfbca1bf093acf58a78f136fd9acca8dfc626676eb9570ec9a698f14bc2ef4042a8ebdb2a8e25378993fa819b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f1af6d0309bf888f652d043cbd16528ca3c86e2f05af1bb362d2a1067eeb49d966b401e13cf5665bced8fcc263abcb0000000000000000000000000000000008be680e4e2c6c4417e401d971fb7275df79ee2ff3200bb9aac0d6542f8257a6af3bf8ca7c95a838d86afcc15f157747000000000000000000000000000000000c28cdc2a7019c6565b9b92c47d2cf047534af6d799c0a58047df9a249fd9f36790e418c1a3518ed1b8e610824d2ada80000000000000000000000000000000004896da286ced4feecbf29deca38853e3d586626160024ae1f1da515f81abdea9fd5625f632651e57e6262cee9e876231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002cebf49b9900cda755bbe105d60ec4a47eb79f870921535a00be7c6e2b6689c0437e4478acffa8cdde448c4711e0aa30000000000000000000000000000000004da75fe951f17da29b34fca5c924ad4c6df5a5c6b2b612d25542bc6b779aaf533da07b2abdf646fc24925dcd29829160000000000000000000000000000000004e6f4bd82ac78bbe67bb3522b0f1ed7d632a39d5f31dc5eb2f876bf201f181f94c39e5ecdea60e718e565d5e5c65ba0000000000000000000000000000000000d61aebfd0e86f6e14ab12f38061b29c9025d88b983c0e843f7a438d41f956afb95e762861e732473330a7bd35b65b361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d27e2be7309e7775e3aa1dc94e63d6178cdf7721ec1f64bca85afb84bb20de98204c8f3ba40b36c5aa483980b066fe000000000000000000000000000000000a7a8913f2df351fcf75f4d7a5f1d0125117ee3db2f214d948e7941f9ea8bdcf07f6869ce3ee99d2fa321d5d15daafb000000000000000000000000000000000197fe14215448d7753bfa7d238df37dbc905fad4cf7eebd5103a9cdde6ba93c2d91f87019c387667724d2f61e8cf80680000000000000000000000000000000016e3048a474ee64393bb9913d980dc43a5659c8a37bfe2cd2539d6b8cf4eb75dff68548827662bf9963f00271cbb39e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d90f9f255c6551743de5e571fddccd5c98c844e70c78a90b524d87d894bb854385820a48cfe38bc5e6732ef2ba73ca0000000000000000000000000000000004f139f78b067f05e8bc1cf3ce63370b32b8a163d3926bc661bc5109a694df5c76984eb2bd30e3106ca48bec862d7731000000000000000000000000000000000fbdf8f4c88903aa0e9dea70dc0d21b32af3684499d0a8cfe7ffbfc729513d09f52e83f5670f952ad2789d9b05e3719600000000000000000000000000000000106a9b356cc42a5b1adff8e2e88ff6ba1e341a47211f98f4f1fc5dfcadd63925b64c4849badb2f889bb79da65984b77f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001232f968342d779eeb01286888ce643a1d388648b7868ac866db73584db52d735142b4cd47be856c5def43d251ef6bc60000000000000000000000000000000015b06e1192335b10c85fba76ba8ada9c23846d3e6ee42cc49b5827b57f5b225bb69a0a75ca0869df79e4514d2ec980ea0000000000000000000000000000000014227d905c9900053710d283d7917f5621ac787e22b861cbb5637a6b36df560c2c23b463dc2b1fc58566b36f05b6d2cf0000000000000000000000000000000010121926165535e2f34f413683dc960a3a4a700aa0d80d7e8ec207e7741e8d063b57d41d56118dcaf7b0972a40ec86a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b1411b6078aaa7aab7aa1ea0c9c70b13b28d53b0a04a1b4a877aca37e2c9f5cc48b91985b068ed44c38683826f5ce0a0000000000000000000000000000000003ca3eff9a5b1625f84b479afbbb314c6348ce313e691d8c54f21e72f24e205c8ddafa875f1f2edabb85350b144aaf56000000000000000000000000000000000f510fe91a927846b3667d6a6566cf86d17bf024a861b06095849eb3d2c650ba1df68788a9ee21db8e3cf001552b915600000000000000000000000000000000154cf8d5ffa97f8b855ebee6561540b92ef7b6882deb6f4cfe48adc12c0397292f053ffa84751b49aea9018c5bee62341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000daeffbeac73086ed686e84093a9ae24a9cfc12bd858863228fc9f6b27631b4a11ae912c79ce1b1f610980f5db4daf360000000000000000000000000000000017b27cefdfe6b389f1316f3dbcce81887439fe5709f6cefb8046eef4bb45d93a42a4ffc1790621ae35cc8ef2fb6829a3000000000000000000000000000000000390ea0bb7e10fb98aaedfb38762d0b5a559eb0ce5daf83d1029b9110d3f11c81c2f45ac815440f650299da806f027ac00000000000000000000000000000000062cd79334242309b75cbad6fba6494ca7f79110aab975094484d794c1798508b9eeef0b4374c5ac000ff9893465ce38", + "Name": "g2msm-27-jwasinger", + "Gas": 351135, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000c32c44fadd47baf1caf5f5b2697c249afa20c8e1c4f9c6e09ad5c6af80c9a8b114d264d75a5dbb3bdb5f3f445cdc50d0000000000000000000000000000000002385341a7ca7b442a4532a15311f0c7cfec23dfad40ef095b2a94ed105f386a254025601542be63a4ac001e47b3945200000000000000000000000000000000133f14dee2ee1c61595a337a61d929e47b335ec0b3100ca7024eb97978df4f7c86bfffc6d30d162bea11ea6738a617ff000000000000000000000000000000000ae7788967f9d0a394a2cd395a5877457b0ee584b0c6f008425cd935f8f793e3b918ca7d37d2eef0721f3ea234c7a8341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e467650fa56c6f0681b43454f8eee10569b8b47305ddee63213e0b730c9d1a1fd38a590f5978458721b48482f69cc600000000000000000000000000000000043148f352a9f33c0ac3ecac702f6c684b06cc7f30862d14ff4e9a86f99e55045162320270b7466353c1d157b096f1c900000000000000000000000000000000032479ecf2080199c137f3a0eb9506bebc1d107e83b2bb0e432e5cf6dfc3aabd15daa43fc32a8f0a755bd1b90c9baf080000000000000000000000000000000015d256b0bbdf546eb925584e7a352f151f0921ddeb471d66c8362e8d986f56b7c2a5c2b614976b5c2978dacf0c35e1861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079fa7060654532d8609dcae11401a192f2530314f77bfa5260d767a76742a4abdd6ccde632b3b4da22a8df194e89d990000000000000000000000000000000012fd50ec71c0b06e86b16772acda4b0d2786953df25a837da27534f696f0cc60d4890ebaccf1182b3b73ccc9b726187e000000000000000000000000000000001383fd9023e827f3c834c9bcddf22347f69e5aa2e5feeac824176c191b4fafd225850723f14051462fef7922489c4dfa00000000000000000000000000000000105eae88ce62a71f5ce436112f44f3aeca3a279a16176dd38ed657cdce280553402e2edac3457445177cc3c642f9738f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037c5c4d37eecbfdd4a7d0512186e8452d0eb050ead1fb8f471135dae07394d5b1ea1196e0038a3f1fd4b2c2f18ba726000000000000000000000000000000000974519652446db6592e810bbd5b0ad1691c248a6d09345a225aab4abfc6da327e5878c1c956bd69237f6dc5fc943154000000000000000000000000000000000ca49b517793586030e93bdc32d969ab1855d89735354168d22ffa0dbf240667c610758bd52432841a9cf6537c3ae1b6000000000000000000000000000000000704b031a6c530ec15f84fd61710d313abdf0244ed47bedc75a605eeab477c8b4c6aa1a3de8f83d5b2125e57a27731801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019aff348b47627efe9373501b6a643f5e0318d032af1c17b73211e8932dc50602c3866b2c0cb42e605ce0494044a9e3c000000000000000000000000000000000c19d8f3c8f375124eacf0e8effb27c04c54ba5ee44de223d5e336f4d0903197c13107372d00c92f8a795eaa7920f8620000000000000000000000000000000014b7c1f79389acca1370808ecdf9b30aed431f2d317faad299716a423731ab3fd6e1b50ed20a6dcb9cb2ea7cb21023d50000000000000000000000000000000014613edad5cf6baba2b25387c442199ae84883e9b961fb671f84bd2e55b44ad4b6bb0e7d6fdb8ad893354459686c05931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c8add0c4d1b0a0bb17f6fcb2d6d0c5f94202293c7232967bc59ed9cc8a1f59a643a8f8c3619c6584c1b7c1dc860cc13000000000000000000000000000000000e322b288427637d1b8a892c1440851d4b4a8ad53f7a449e396e80707b52101ebe89f7dad1b8a3df99b334b55cd5e03200000000000000000000000000000000029cb43a3f28d085b6179ae8d51fbe6ce1dccf627d3eddbd56cc0360ddb2c9a841e0737bc3a40bcb819d2ffc0dc09cd6000000000000000000000000000000001669ab77d48ff744eadf86f37d86e5bf5627f24ef117750bd48006e9e90121b63f28bedf81aae6fd5165dff675b6b33c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145a016c0e4433f3e01868b4bdfc3e3e05aa88146357548eb02061642b442067442b6e4a307de8a4103a22a59ca59c780000000000000000000000000000000000f2d793d9484a116cbba46ebc6fe2db533548046ed49a9e5e120056969ee6f8c0390aaaeb57f7a6ab3ce225dcb15bbf0000000000000000000000000000000006043991f7fdfdc31c20a0c5cd82f79f7536fcfa5dfd161cd866b8146feab8bafa4e722e8b8cdc7778136e74ff7f8ebd00000000000000000000000000000000038443ced42df60ad556f040ded32506f6e409a4481cde801ce3deab58c6b20e8718cd0ad058d55d5da89444de5428f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000afad495b8844a566606922baa029d7e5237f75368a6c13818c4f016164a5016934393c6a5aaeb67246599f4e6fc6c0b000000000000000000000000000000001357d99be4aca05dc46dc0069c5f13ebf6b6635aa0ce83cab4ae7117c15a89ecaa6b75d90b99f87d078967a5aa25e582000000000000000000000000000000000233364039cd0d66d175197f8a13a47fb91b9323ca74364713f9deca73ea1b1e97cce7a33d53b3a4688951dbe6ac9104000000000000000000000000000000001780027a0b443639533d9ed9e2182064a0a8335fb5c474b08f1ecac455ef4e8476c3720aa328e7c9d2c60c76b4fd87dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a092f5f4ae37900d9a46a8f6a0d92d4bc8703c73332814e321f1863a956c7ece319b6ea7c3a1258923cd898627100e0000000000000000000000000000000011e4e1a1f683959b5193999b41abd9ddd647f830b921d69dbd736677e9c865dba82403a0408df67d4d98aaf55099189f0000000000000000000000000000000012308c4376c8bd463f5ed0e861f1b33c30e9c493e6e544b271bd89026edf3d94bd8672a4a64dd9fb0f2c27e23120279c00000000000000000000000000000000003e52b87815031c54f782777a42b3e7f5ff2bf87847d4c3c7734dc6f962e00202f9fcaf7907470dc5e631e0c9b997a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000169802dc492100fefc1058a40c669208fa771fd608608bd8d3eebaf4c6311feffa46d510ec400ae13b08637056e8a0d000000000000000000000000000000000690cd65076937b1c38e887a4a9526a79b67942297f4a53146c834fbe94ec6e6a393361fe90264ea3ac857ad5f43921b000000000000000000000000000000000e96678f6376db41792c9d97ff37479f1dca2ba363561cdcce41cb36353a378d7429588e6588adfdf4d2f0dc74b2945b000000000000000000000000000000000f1e9042941d5a0498758d1cc55914c29bb140129e1a1f1641be5c5b027634f7dce7db76426fbea9890a6fd62085356b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ff4096a7853a31be23cb3808f5338fbbf18db4a719d977e618410888f0d54efe51acf5fe4ec30f128807ae9d7c7fbf0000000000000000000000000000000003efe21c56f305ff3479e06231c54ea577185204731009ac3fd7ada0d71c5283d9408d4238c412cb753bef6b30d05bc20000000000000000000000000000000017c741481aa830cf2d7ee0ad2a137f3767a055318977dfbe45acd66f977959def711cbdf5e325ce6a3b27b8c2cf38dad000000000000000000000000000000001621907bc9e869fe938a37fe050fd5defb558fe760edc8fb2f91069612c284946f8e878b5b7b58a9a7c79ea3457bdc2f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1beb674ff1f0b97386fea532b49ce0daeab0eefecec2af119e16df7ce3e3eea7eba74ae5681720c3f154653fc416010000000000000000000000000000000008a333a20485201dcf576e1577f61e0f0cd979470f94888033b41d51bba9acfa34eb134852d9c6d1de948b1cbccf3308000000000000000000000000000000000399cfdc19a26417ef48665c98a2a4cb2da888f5a604026f8f807d7d852ce774e8c09b8005fd066b1a098ae123828771000000000000000000000000000000000f16207f9b7d25871d2d737bd63557d199e7280393a129ef6d021d1c5bac51d6c14e8898b058b84d259e89f8078ce71b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000062b5555f2779d87d835b064616c117cdb46ddc254398ce913d0303a074d165738bc568f9c6522b8b92d7dac752d32a00000000000000000000000000000000132344bf1edd8092e41e9419ec846b9ba197a641068e4dd8f09c7ad9643c21312b6c4f5f95bb6fa002ae155ce76dfcf2000000000000000000000000000000001936e266066d85d12f7c7831c8f6401150ae2c6744a8d1883c374163af75abdc5bb666ac90945176558aee0586e7f9e9000000000000000000000000000000000ac8c26dd493caaa7b6f8777bf89306161a564d9f369a06aa808306ce49ae4ff2d571670c7dcfc1a17f8dad65d8aef651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174ed45b0721698524d545d3ffb91491dbc3a24011071142fadcf1fc0aebea354773ff6071b6e3432cdfe0d01626fffb0000000000000000000000000000000016a297df63a1f9af115382a9cdd33f52ae87b637ac23c13669ee583e42e3304ce26a517604d6eb5f3592bc1ee24103cf000000000000000000000000000000001558093984ba01c3c1d7eac62ef6de58e4c340f4268d388537e2de71ad6da16441618682fb114f7334937a79ecbde3bc00000000000000000000000000000000046adec995a961ba78d1355ac54942f48a2d040e86732b874e45cadd6dec8c97a72e180926c607d220d25f56f320b2551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a3992a2f7493af523a9b8b864333388d2b8990072b0cb927357d072609710d6c2c8ba8faa8d0144e44114a1ded2fa80000000000000000000000000000000007b27fcc27c82eba1e8898e176ce248771144f5b5f989b7cbf9a604e600bae6fde2df0b5bc580a2d8d0bed9a158426cf00000000000000000000000000000000004a58858b2bb28766b4d6c508b15a8294461f98f65b69f257caa6a2885ceaf6a8f69d59a194e8e375bfc2c280ee09cc000000000000000000000000000000000f891227e5d7d79913bdb80710c56ce1c96bff76a2caac15efaaded0386f828389a0d8102ad688e6150613ca35702d6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149853f23488e6b24c4890644d2563b758ca2fd7446069507f5aafc2552a73483b45867714c617ddeec85c085d5919f3000000000000000000000000000000000de47334e2540d9d0e37b9784a4f49cad9b0195c61648b9f6f7214ec3917388fb50cd5ab449ad999f2c92b6a10d559030000000000000000000000000000000015f00cda6697922aa399d0e1860df291a7cd7e417b7bd6a6e8a65ba585afae4f87bb7459de1cffa616be6f9779b9a66000000000000000000000000000000000083cc36154ec20b0b42a1731fafc41e6355a7ce70213914a0c355b064576fbdbe00fa2c626af089bdc9b9c3069f955801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009feec7f4021d9c295007f4dca44ca445c73700159b3f27a759edb0dd09d22856a43fe8a1c1d07629c901fcbe6ed7e010000000000000000000000000000000000f6880b5541c0443f8850b969c4bd280c450a1399b19e2c9c9fc30b13b9862806fdbf1c1bf81e172eb4ea443d5f9c9f0000000000000000000000000000000004f744cfe41d9c07c84da805be6fb0f40db2e26aba48e663db442f0083232b84984b26b27aa3dba491d30e6afc2ec298000000000000000000000000000000000732a3b254a5e2a9d660a196e1afd9e722675277bb4b79074745529410e0fc81581cda9bd0c839437a640a51b7dac4871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001848f8fb198eefa7378d3139ccce119ea9ba588d09c5bbe9782e4f88f996c20f325db0e1e02f24132be773ae7a963ef0000000000000000000000000000000000f8e7c9042b0ec43a0cdd9cc0d0e1a4f4ef9e8fdc891bb3b81d097e760d9e3048bcb342aabeffafeb00bf09207bae1b70000000000000000000000000000000005b323f1fa95529d82a4d458f60a534cac2eb934558a4011bd70a1844d9b82c21824d1e7718d7e93724c92b8b6190059000000000000000000000000000000000b36f327c85d4708708731906a2978ff213f724281a84f80310f113c2c06235a7ca22a185f0ff54de827ee3dbc6f04341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f9b83bf1a2b3f7715cbd6f9f89cef4da5c910e91d796515f92980133785726705175960ffcb84c88a3ccd6b48baeeb50000000000000000000000000000000006859ba4b78789a8cd11964b098dc8c60164977ba05fbd96994d7c3567acf1eb65157cb4c34ada4fc14ff865e5900bc00000000000000000000000000000000005190eeecaadaa56f976cfde4f7c686c1686f96026678554d653ce440f78384676a60413d1accc366281e68ce691fc3900000000000000000000000000000000124081bbade758746f7f76015f37d4eab59184d3c9f3171cc21686cdc2394471e820c2a763d6af6c52c46c0d9b4b6cc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f6ed89d26040c3bfcf2419ae9c9cd83149640ed66c18cac5fe774a15021df2c9257f7b9ca4a894755963e8c3296e67000000000000000000000000000000000d24f1e8d955eb6b4acf8f85a640779eab0e4449ef20a19f40cb20939f0e58821bac93a345be29ce35e8db31a500bcee000000000000000000000000000000001835835d74583072dc033dead2f95407e54d59164ea056ae8d97412db161ed221e2ae072cafb66a4d78f3f0f82eae0bd00000000000000000000000000000000010ec7d42aa2b58e37614308842682d3a069d772de4efa92a6b3858346193f9371e8c334be145c048f5e5330c55974b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003908992f3cb44bba40bef5f87edc157ed299aacef07be539fa78ebde15d1389ccdb32d377da24ff520984261ba5a13a00000000000000000000000000000000177ee731653245970aba6dc8d30dbda17f1a91466fab337a2472eb6303684c2a9df92e3d65fc73b51e2648368923f16c0000000000000000000000000000000008038c18d14f64c15e6f7f9fe259c549f44140b3a9ca19799b717e661975a31b9ce9471e28eb465ef20fb21c1be783a6000000000000000000000000000000000973e0946c2be86276e8df11f8bc0a42e61752f2ee408e2b0e8641a5b0827f360b0cc947db90beef51cf77619ed1e1d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001691677dae70cf2d936692499e9d4a71c4fbb18bf37cc257f76cb13f61e3917f5aac5650400e4a0fc69bc0c43c578eba00000000000000000000000000000000124c792d0920bf766a3291ff82424c2161e3a36285c0d7ad4673fe8b6757dfec41db4647bbe36b8c4b75878b0f6ac7f400000000000000000000000000000000086d048134090c7b521f713efc2c924153de75c6d5386f1a1e2f64018fb066207e9b6286713779c5867bd3773a31e22c000000000000000000000000000000000f566fd41c7d09b728f29a01730e06fce26039240c6cf6ed8e19af27a3add6aa934dc79bdb520bba6c3959c00e15ee571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bcad9a30a850e6127a0aff1742559d23dac3da340217d7e61abf76035fc8e4d42f3d4dd7501fbc511f3505f41052660000000000000000000000000000000010e1ef4952ec07f02fcf5cbcc0b61afc96da97b13b05ca378e486c7e43ac413c06153f8b528e0caa056f37c7d36c02b1000000000000000000000000000000000dcf74043cb3b1311c0f002e467e568d8e1eca2bd51680fc03e4c53ffc3c270fab376c9560582445ad708d1f33fdf7f10000000000000000000000000000000014453d3b080c057cd112b08f2b3caf148461c7ebb3674c14ba6b43e0a41ef04ed568be719175345bc884e867c411fb221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001769a225954c320889c1d762db2cdb782313e014539c69c220c756b1ec086f457807a2d88cbfc5fa8f69ae2c5579c668000000000000000000000000000000001290789de39019dba6084b3730da0ff035be2aa88aa9c314c87c963923fc90d9948991d7fa88fd02364685702f5fafe30000000000000000000000000000000004d3cd2d0f407d9659ad176606ee02064af373a9dbd46e9139d7dc1032dd1d8e408c4ad8a373d7680b87e6fdf944efdb000000000000000000000000000000000bcdc70c547abf66fa66276cac98b16bdf2c31627ca3cdf9e7631f5ac29b7de386aa5f3c94432cc99730f2effe581b851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060edef5431e31c1a3296a5b4a31435a10de20cc0d2ef1e041da56f92ea96180d72f72576213c63d6077432132ef1fff00000000000000000000000000000000145019348dff4d7cd9598e50e9771a4daf6831a6047ba406758be943d8a48e3c2301d7b0b4eb781f78b79ad7791205d50000000000000000000000000000000008a2d007c3e1637ef05893491fa77a3fec188fa73cb4b3090b8023ecbbd0956e0fb1b2e3a6f64e7ae4c2c16665f6d49d000000000000000000000000000000001262fbb56c9d23b2ff386d83ec24a702805d29a987c434e917d9840d0bb03f00464200c2bc291cafbc9e1f229aa348321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084fd881a84f4cfde6b04aea35235016bef0bb8ff307741a8cf5bda7727a3140cd54995efaaffce708a1f5900e74084600000000000000000000000000000000052b491d09383bc4a2dbda0d567086f78b64ac9c851a5845e474b884f54befa938e396d822fa23d2424c3340464471c000000000000000000000000000000000162370332c6f840baefcde9e4ae3dfbb19ca656d2e25c3b89b05ce2bb023f3daef25e99f62837157f6396709feb4b957000000000000000000000000000000000335a2a4e45bed5b0b14f3e02cdaf6990bedf08c8e50d3e7d0f77ab7cb400fe1641e27b4b805773a1298b005dae155601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000832626850b08f620edf4d26245246084b559da0a08594c2ba791fcd644ef74b984b8ae6c6774fde442ede4d7dc2ec61000000000000000000000000000000000dc369fa7327c040c5cd1df23cbcc608e3cec5714ceddf4fadd34424c0204a050de74e49ec0bb05a79946c19fbb63587000000000000000000000000000000000d3423b795953bbfa552165d1935173fddf8efe251c0f8df75da8f48242e5cd61d18a2f760500064a7418da6a2160ff3000000000000000000000000000000000ac01e53065c5e2e5ab865df80cb1a8af7db89241ecc8d235bb99eab0a085fdb3dad0d102ced54574df4be0a7abdbb2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c09cf2c96829b2b3970b3da4bf26de7201f264f7bf34d2c464b6f1fc7a43a4f9118672d87899160e34e8aec4d38f2c0000000000000000000000000000000019e32f7bb9eaea3f5ff3c0f3c05c862a4c0447765344b6583e6c1602615328754c373284e90658328e14df3b206fd0c00000000000000000000000000000000010296afde1bdb4547ab39b33a3d5bd13dd8669b35b5160c8d8a3b117987e02c1f8fe78927720eda1395ef2012bb107b3000000000000000000000000000000000ed73744daf4c697365ba066bdc52ea310e964f43a601687f93a83e03241bafd55b9c6bdddceb1c4eb92cf36eb7c5ffe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000da3b3e467719ac6846145579f4c1504267ff4f3c6d24f367e80ed4c6d30853c7829aadcbaedf94a5cfbf7ebecfdb755000000000000000000000000000000000a09cd8e7a9fa2b2eecf507f6555f01bc96c3d4855c82c0438da19437a52e2ecb6f8c8c212ba1de60b1de36642549f7e00000000000000000000000000000000140c29dce8df8b8f9ec681751aa9edda15020e64f80d6571f921ff82be8537b90f0aa3d26bfafeffe2c0e4968d0da9700000000000000000000000000000000003c7f14c2138ee4cab84bfdd13d7cb9da96ab0f64fc24f6bbbe1c89d0bde17f8eecd43dd3e1f32112741474a6b033aae", + "Name": "g2msm-28-jwasinger", + "Gas": 359100, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000aa48fafe78a2b4376a28048e4c4c1e12176f6c56103daa1606ab6202c8f4eb72ebf5fdf670585c9978e1e87edbac9ff0000000000000000000000000000000009d9deecd468891e55d5f1bfa6723336647cb41f625c3cb351043501b595db1ce4dc200c1db776b69aaad15477280b06000000000000000000000000000000000357229e56063b99ab7bfdac216c1fa7ee5e9f80818afd64ba4108f8ff2e372bddac1b2551ec05b7bd747d3e1364d1710000000000000000000000000000000007d4e5bda6d0f9164758e4fc3d3821fb3a8c0298aa99683cab239ff339b80013909819eeecbd5745c63741d06a7874871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001507090a640fa7d99fd8b208fa6d59aefd7de175d0673d419dc5ffacd857a74f55cb7376ddc6e811f45c8b5dffe7890600000000000000000000000000000000083f9e6c3f0f2430b597099e5267ed7ddea3c59cbeae2c4b4ee8cb2f80b1a82d29c0e2145c126c95998de937d3f1e9190000000000000000000000000000000007399f120fe005bd2b2c6abee1748e915d031311a4a52bbcfb59bac197fd7288c8d15c90167fcdce7b0da325f758ca480000000000000000000000000000000005b0ddd3ca56c70298b4f528d823325171057f4f3b4c9936d4f1a6553a6726a7f5690ac1b5abd07044bcf955b9c809501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016587812fb8963dff82325c7f05f5887ebfa57c57ed541f1c3975ebc6706b252b022e58c38fe1d129c710a627574a28a00000000000000000000000000000000171dccb6214661f66c8e36f1e54206a871fe316ec6fd3d495f2cbfe3404f46c9492edbaf0ded72cca404b82336e7c40600000000000000000000000000000000112f344b3ef0b3d5fcf1d5523bc8141965e0b38c59753d7be12c7d690b4fd7d36037fdd6ab4185c6b330a1d6b4a6516800000000000000000000000000000000083cb4eb6316f22ad5aabf052c5fc95ea61a51f68824f752c88629175cbb74be05db55600d16dc5fe314d1a8e0dfe91a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000abd7cd92ecc3411b185d21213b4b3166421771ebc297c2a64b72f1038fb8b1a09dfea6fd9a2a011c0fe74de560308d300000000000000000000000000000000140ca465273d0e99428b79bbee4c8b447130ae4e4ebfd8b21e6f5a103497f23c566f77c4362bb94d061be15797d4e2090000000000000000000000000000000003e458704d3b65a6b5818e45003866a244e3dd15ffdfc305f513ed3c188e363519b6bc354e5218cf2348997b436668f9000000000000000000000000000000000b75ebe347b33a775afc9fec184387d05461f34fcaf45571fd62d119e7d767c7a268e8b3c81d97bdbe09bd516489752f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000829524bbf33e3e8f436de9779c236c0ea4004f339b75706f7fcb188c6f5b0e870292a725191bfe8adcefc0398cfda51000000000000000000000000000000000c34e44c99a5b962b64bbb0e9f270ab7a524ff6cc8af4606fcc71a600ad2ebf8cdb4b60083f264eb4e96d6c4dde7dc4400000000000000000000000000000000113f2713e356f55b4e0f246f94a28ebf8dcc4e71d069e5a4ef76ca34842704a109b7394a67c98334eafc5191e9c40ded000000000000000000000000000000000f1f106b73bd14746bac12561a70326690608e88a37a8091f7c137127de179b2b7923f6b6a1425272433cc96ecbc6e881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001539b41e46f218081ec2a02e6f59aef7bdd3d050ddfd350a34561c1b5f00aac65c1386173f4702aa472e2293407650b500000000000000000000000000000000145e0084bb792c726fe629f488b5f7bc07e46f17234c42bdbbae979d333c916b46cec63f18c2e7a7bbb9d3ebc52c7f72000000000000000000000000000000000605c56237757b00f26ee97b2de1e2f5b55033a071ecda57abf247a57c5c2e8a57834331c450d2b7b89fc39716a47972000000000000000000000000000000000c8e2b97dab2733698b3720081bf4e772f0f9de54427ad6a871a37ea6c0d0ac404cdbd6480ffd483b3e1341510e9b4431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e2972abebdcff1cd356c5d60b0024c507a8693b8efd1949049e086d9a4230c418465546badd09992a690814f1ab9110000000000000000000000000000000003858d6c30c4a87b317b4bea982f4191a98850287745a0ab8e72c5e51570bd1cffb060f264baabeef454bc05075c2d550000000000000000000000000000000008fcd3871c10813e27b7c10b5aa7a2b5a829d0402536c4fe0b81c80f581b52cda68bf0f08dd79782d4e41268d6f840c8000000000000000000000000000000000bd97069ada3a0190cf7c9a55ec0e03ac9b3bbc9c71b349be528f8e87f638bdf8078fb373f4358acf136b642293c8dad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f87ab0a664060c237e8ab4dcf61d10ea8002331fde5edc04b72fda604fc4cf9befa9021ea7a1590d601e6ec27d9d990000000000000000000000000000000015b880f1312695ec797223d9aa08e63166b7d958f988ba70f8f39c003b5abcdf993aea7e580d70384434691a262959d00000000000000000000000000000000000da2f26350a8713b6361020a6ffbe60457c55b863179b4e8f38a66b935f45474de7365374360cd36d9a77349bccf91e000000000000000000000000000000000522c27225a640224b35c0ed856ef628ddd614d2085855d687058d132ec7c49a69d660e7899428344ab93318f54cd2331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011528cab84ba8758244c3e424cfc235fcbd04b22a59550e525281cce226572d6670a45d4181910a02c09092b3b4972a50000000000000000000000000000000006eb7deadf6e2c1e4c006f7d97cf17d818e7758ba5d40f840244cd1395aeb496fe78972035c366b2b2549e337b8b80af0000000000000000000000000000000012fb39dea4aab8dafee722c01aaac139e830c73c57dbbdf8ee17b151973cc88492ed9c39832e2be054c57d437ef55ecc00000000000000000000000000000000188c3dd0aaded2140f4d7d424479fb4e2eaa72499b10791b448cdc78c6309864102aed3239dd5d7cc80943cffc63bf841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175431f2468db8f49b52d5f691004084b75d7655f86785f0a829495f637d05377805394ba70653494c11b6c67a0601a20000000000000000000000000000000015a188d2333a58c2acdb9e30c437de9efe2b504b3dbff7a75d5d69b31ce22aa16f5be833bffec2734e29425a6650d64300000000000000000000000000000000121631e432a98f47b218643fa8f0231825df6de554c63711be0066d8359053dad766422471e8bfa2ba10e00b1c47a47e00000000000000000000000000000000001c5f2697a18d7d4b4d7c5a97c2108df05d1981ec9f5b4663f01d64bbac16aaac73d6740eaf7fc5cb0a8537b5d80e621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa6d2680a8ea7a149fc7895547aca4d27c83e032f4f4596c5723b1d731838c46c5d8be8f43dc2708da277b2563010510000000000000000000000000000000019bd4e3ba469faba7b4181b340457345eaf5926d79e5ccbd99b801897dadbfe881fde0de5335028828d920dbae86186900000000000000000000000000000000029d29427b363979a7f689f96e2cb698b031561520a18481ac3caf31eca411ccf853d44a3f04ac8a94072f84cec0a14500000000000000000000000000000000178198f30dc0c6b1f0e342b2730fe87198dc3c6d295edf3715ec690346a482ac7f60320a9271bac492b2a821b83ebea61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002793b4dd7f29fdb3476f0f13a4a92376f88b0080d0cce6bf8a65973747314b19570df538a5e58206073d852453fa27b0000000000000000000000000000000008571739c098e0fee34025e3ee3868101a66b07fe19f0401c3b66ee1ae2a96e749977d67cffa2dee723ba01db0400d6500000000000000000000000000000000154e5a901b96124aeb581e239b4deb88f8b542e63edf24eccb907bdb874701dfdf99375848cca31b032e2f96547d322e00000000000000000000000000000000173149e0d6f1105894e59780019612636fd7ef4b448a471766f3acfc6caec551e3f8760a3bb65b423d1c79589f3561dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185a19b65d380bf4e4956bd65a5839f71596ab2233adf1587eb4a60b2780fb28877843724845ac8065b1f74b616f678700000000000000000000000000000000063cefeb1291b32c8e45754c6aaa6c363bf06de7bc611f7a1b4927f4d17fbd8da2d939b17b2afaeed8c3d412129bb2b0000000000000000000000000000000001868356d5a51c3618b8280f01d5b7a36e74dc2cf4313a76c9579b90cae1b447d11f4a8bc3183e8938b95010141513118000000000000000000000000000000001299fdcc6953639c3bcb86fd256defbd9b278041f3f58671b02d561417fea98db8236022b1fc2bf5328d7f54699e489a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003dbff820a219d9e74dd850fdc91c5a6b6ac4f18e3d2da9cdc06c1098c2bd7e4d23d33da731630eca9dbacd37cebc022000000000000000000000000000000000612f23323f8b468b2a5f8b222af056a4a4cb619e2045ff9572e13221928be2e961ec6bf08870dee81271566ee94a0ac000000000000000000000000000000000617f7aece41db9c7961f063e73ee8b6851a2e0f6bd3bebcfdf03d67e5cc8704433454afd862b7d1a13e8e5bca1ab5030000000000000000000000000000000017fa0bc3d544c0f299fb6ff83273ed28e918bb278726ec2aff725fd5a9b9ba1a16958911ed30249606d35af6f5925c8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c5c7cdf872a072005c11085c7990b78062e97d203763939b5bbde1b43021cf68dcd64260ebd95207d0428ddcd226eb0000000000000000000000000000000008e2c5d6b5261cce780717cc04945c6e6b0f056fd343140baf30fdf8d8e4c7fd0ce274c7761f1aa786b9797f63af931200000000000000000000000000000000008729e66b5f0040044489addc00ce4ed524bdadf835ca54da76ce447e6564e06278e4acc7b27f2ff95e9b5b51a119a20000000000000000000000000000000006dd04ccbb74b57fe14fa4d564ae16f7da40aebd9da05037145f1917e475a51784b8d7ac4ff7c54424c89886d193e9bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d88f718ca5e4bb66cf7cad1587cbe473be2c18c706d7bd3b5032fe38135db7b08df605a401918696d51054dedf3cc40000000000000000000000000000000017b644ac7b6e6fb8468eaddb8bfe45d65511588bbea98e5381cfcf7fafa4a25d727fc7437a0af08e4d50663bb29060b30000000000000000000000000000000007edacbc4649823b8bb1ef798d4d3842fd5b451933a92b1184a5d78c8415714a36cd446bceefc23213481d2495690561000000000000000000000000000000000ff036a27d6c0ab6a2930dbfd99fa7349d45354823b95e097a97f78a82092afcfd61d6550a4dea0012b7a1316653c02a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001313459c3a16c613f2b60d84103b35b34bf1c16a03f5bc24bc2f26953884e2d40a47f10487dc45ac531eae33d35b4795000000000000000000000000000000000ce4f22668073da84dcfddfc892056ab6b20ec2c7dda4ac7b3c7cf5423e7ea59d07a6a7516bfb9c2f8dfae876f94e9e30000000000000000000000000000000007946a3dc57a0fc19ceafc7429e4460f04e98a935c373223cb1dfa6758cb336d2d17bb2484546783f082301a566725790000000000000000000000000000000012a548ad8c81060a43ab54e482b9f7c54cfb63d62e30b94bae95912231ad74f04a03d47d0f33d2ff5d21e41db537f4be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bd994e7e4cef99edb0d02fe1330faae8bae8d19bf6ede6c21c1908018b887eb654392e5e10231c297850cdedcbdb83000000000000000000000000000000000b27c5be6e5087fa9fa84600a13f676d185102b8138326fc7aadad39079f4cd276711c033bd90117e9ac81824a1b54df00000000000000000000000000000000002d22fa29a3b931bb38c61765b093f3c9692a9b3b1967dcee90f669142ff5410e8880c5a52a2e558de01281a8dcb24900000000000000000000000000000000137bf2290e637aed7d8934f97cf8eb4278c8697b7736fefcff8b738a54e8f340ddc426c113dca5812680cf901aa73f4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000887db81443eede54af3efdb3bca266929ddc9e9a43a120642033f929912d34ae60a9eb88e0ef03e338f49235403148d0000000000000000000000000000000002aa770576dc800b4c5316042c809f3b6f4d24a6c0f646a65b7ef163ba4930a590f361ab9ba5bd0c85625bf120e64f4f000000000000000000000000000000000144e9b78e3d876551d5733cd1df770f74eb23fab0c4505f7904129a39cf82e0323a2ea27174f1eb98f69a40dea6ade2000000000000000000000000000000000f2042a342232e512fb77ffe9c73751a789d79eefd89c2b4d20a2bffabc421a05d3e935c038fc99b20dc38654f4bba4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019fb52d54a514106d10da8b316729a1af301be2ac319dd66c5cb6c0749c624f5c91106e8d42b88f26320598db46edcac000000000000000000000000000000001373329f07b87be139bc5a2f245a522f66081e79d9df80659b582649976d1b036fbf078e9056ab416fae5acea3ffc3f000000000000000000000000000000000160770d40d555dc2ba7563a54be90552411400a0425f9876420665b38d269a202d6926bfb08e5a343a2d32611a9657790000000000000000000000000000000000a4fc529f6ce817d254934d9160be43c28090f01c21a46b9d8a343b945f13a6054b3251f20a8be03eed7952f085f9401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199a57a493b04e40814c9a844de681414df247f5ecb879c495e3f5d01a4fb97beff515ce3d717b6d5c560c190132026400000000000000000000000000000000083c6c6d678aca761f4389324e72cb884c695fba93a992c55e6282e7f57e36616dbe6f0922a1532277637dc76ada322d000000000000000000000000000000000e340e248005b2be75cd19ae8ba96aff10541e70b2d8597c3cec1d00a89f7242bd4cbac0888293f182cbcc00db65fb33000000000000000000000000000000001513bada8318b97a8be4a26394f3f11748ef75fbe438f76573a371260e5359c3f711c45392085777d29e94c9d7a923701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009217278e4ebef81fd3579d265c30d086b782240f14966589992fa8d64f5f2508504db8fb07ffa70f0c0adcd7a42e8360000000000000000000000000000000011f8d5fd83554d971f39fa2fb518733834be58812f3dad21eabca81de0110ca36f9c15eabf4d013a9c7724a552a0dd50000000000000000000000000000000000306260b94b2c4b5461c932ad85a7d7dae1fe6dad06460b71562a08004988fc9e529813aa09c15c6b6f77dfca7e8045100000000000000000000000000000000023145d719e21530f2ead68f799cf2b2970a6bfcbe23d3880e7f1ec8188736884c2e0f21ee1b4b374c3df11268cf2d921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001576a4966ac550a5d8bf6024dd2043a71485f9d43e000092a1a06efd63c6e8278ad29c38de54812497ee7fd1af8d83dd0000000000000000000000000000000004c1111a2b00edd4fb0f39be5b576942eee469d37f7b21a523567ac2450846d743291d3bc48e1660600c33c78e3564d9000000000000000000000000000000000e0e76855fe748d3b4f9f2ab7fc41bd52714c446b4a663e849def5e279c6cfcf8d29c0e18dfc4c45437ba94bfbb761c900000000000000000000000000000000102d7d4ec73b871ff72406acc945d6fb7dc2ab4316942b235b0be1a02f97d973e75d0a1e55478f21ccc52a568f3223f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193c1e99ed56aec7f1b168bd7aa359bbdcb2fcd92d918eea303451b639ceb00a32640b44e06d960c146bad59929c90da000000000000000000000000000000000b5d12e7c8db75ca0ac748d5662a4263cd420eb9a32beac5650249b357b9197ee3eed6254bd4a0820011a2af4730b7e20000000000000000000000000000000007a63603bd9f94ab8250c4582429a0cb63d4056f6c49aa018868c40b8595c1af28e66634970354a10f5bafec32552955000000000000000000000000000000001419ac2ffe8fa879eca99a745fe41f215fe61e8dcd5d882ba4a836ccb29c70ecd3489a25be6be7752f244a9f73197a4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e8065d43f90763d365a9ce2ee22a4788011b10cb824886d068dfc3a17177b79910464569bbf41cd66cfaca010c4af200000000000000000000000000000000002fdca6495ac5f397ac17143d39d3d1788471621b54b40441a3ba1cb28dff1b993021089bf71adb661b1521678c17d80000000000000000000000000000000018a62f766a85f8578cca1897ed333d3ece770d10c800c0a65d6412d6ba0febfa495435a270eef1d0f83e05329df1094c0000000000000000000000000000000011f3e53424a279d71674626e26f139367761ecadd085c4941ec45b8d90e25581617a00ca13896cf499dd99d7b223bac51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015564d15414b53e91b52f86bafe8028653125e789fdefe2f88ff0593bc9eea73cc6d76f258a1663ff8704aecd67f16b1000000000000000000000000000000000e3697eb5a8e6c8db1c0ad2caf34267a4fa4d04e919c7b833536a2bb62096edc9ad82d564badd5f52da138fa3db8d43a0000000000000000000000000000000010f6c326a779811325392eaf53be300ae140f35655d53a5f0b69f1492ee4d8dc2b6ce9296fc269b03e9eb555d69b8f420000000000000000000000000000000017d57fb2cc15b838e55318e7d46202ede40ef5cc05e4dc8469135b96479d201bcf72fc6ce37aea70286354f1ba08f5ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fbf328148f76bbae0b3ed2272cbb5233d58b09da8061b720de301a4f35b4a4ee8ae8e97d0126558861741a060bebdde00000000000000000000000000000000120ca59a1dfed010d8edd6d45a5e6aaabcb146c8a1d969f0c673984ba08657d49bde5f673a136b6f792894cf7c3440dc0000000000000000000000000000000006d2d5726ffb08fb2b7c28079f652c551bb298779165bf1762b674f737a27186860e8f411fd5d985f01377c3b2b6477a00000000000000000000000000000000127a99bafb47777b4fb7ecdded23b54eec37383d5943c06c74812c73458bf2ff6a7bb48142489fdfe21ddf35567d51a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6ab8b871dad2ea46d271be5290d1815a7c412c400abccd177db6b31c8f143c7e9c3c618682c6254184438f77d4e035000000000000000000000000000000000ecfee9da433ed8ea9dac251f73d92a19fe25faae8b3b328efea227de7ab405652f1f62f720916096dff6ff78edef9270000000000000000000000000000000016463b46d87866de38dda7008c70ae2cdb7bb9d30c08dabca4218633f396b81d70dab5a621a79f10640a4fcdcedf251e0000000000000000000000000000000001a323dca99ef212926bba5043689788a4b666acc6cfcc3610fba1ebd4d09d37b0692839dcc85d202236252ecde751e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000038efc596eebb9d84bd941e08c79868525d8d384075e7c9c7be206c191f397c6b64a305f89e4818e36f87dbe11b67ffe0000000000000000000000000000000008f928a5d9986521766b72f15fb235850f5213e2fa85a4eea57ea040c0669bd097e291ab87983049a3122756fcd1db5f000000000000000000000000000000000d7b0918dadcef8419d6baf0ad897c976e8355098ba679ec32405d153abdad29f4288e5d36da4d6c94ef1ec13b4fc1d2000000000000000000000000000000001251840c738bd99f1a52f65d9e7d60b3b303379227773e5c2bfd7ee720c62fe8756c58d6506af3ffcc0fce5102a3dcb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000148142228d70d5530cb6e4b5d9f1cf8b9e3a5f589c04eb17254d12477ccd77fa44a4bc38cbe28927303c50ca98cfe44f0000000000000000000000000000000016f448dfa986ce9f305223d47e5bace1e29e481299892c90c5ed8cbc1456179029b06c4124f1c5f42a5cbf426b632866000000000000000000000000000000000d8d49a7ea64ed2e965181cd52e1d73a0b118543db26363eb8c8e29e50f14fd69fb01ddee38ed91f28cfc3ba16656182000000000000000000000000000000000ce5f7aab86a9c402ead61a6d2bd0a578d80868bd643b002c6e7116662f9dd244f213753fb38a634a591aeee8cdc4384", + "Name": "g2msm-29-jwasinger", + "Gas": 366705, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000001843fba3fafb6163d2d6f44be87432830a0c3ffc97674301e63daa5bc30f624b619330016fd5d3b25ff1089180b0911d000000000000000000000000000000000523cea9d2c4a053a5711ad24bb4f93c25c5abc6c3b0fdadffb63029a67abce0406b3dd65bdd41d4e65a10d126d9d4ae000000000000000000000000000000000d5a3e2285919253a4771da89c36272483411f35d7d29722889cb5e59d2fb9dc1a9b0ba74ab100aafcef4519bbaa154a000000000000000000000000000000000c460f2632b593f9f46bbf6151d92b9d90c67b95ca011f33a845afa8d182be74cf5e7cd83c21ac1e95b0a65ab79d0e921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130e1c30240f14c9ad3101094c88d52b364dcd4e3562df00a0574564f6ac25bf7e26bdd182f9606ee1bd781425a1b7e60000000000000000000000000000000010ecf8ff470563d180622842b4cc4fa073c6e83aed8899ad2d78a542734a31002d9120808f219944b59a50306537ab32000000000000000000000000000000000ea41ded7e4077bb6339e54b5ee6cb498a8fa3fffd704e55d7fc74c9cd5785b53183ee9302c140866d12bd59283a38aa000000000000000000000000000000000ff41ad8bc71519dc5582c7d73912fa3c803727e229e9182e331ff0d4cbd492ff7c71b3b0a4c03f44563a7c53bc0c13f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cb7973898106279b32fa8794081bad3260eeb70461a316052c97676f85b11d1fd427b09b4f5d07921182a26745cd9a0000000000000000000000000000000007eb11ba3141550bd52f28f0f71d9a0eb4416dfdf007de21972ffed256de46def48221b8036449711ff531c8d4cd7aef00000000000000000000000000000000122e123e1bf9949f4ab82c9b6297f9ea510aa1179bc5c04d8026eb5f928a791d5900dfa296e45c21a3db278117ac0842000000000000000000000000000000000a195a6529a4baff5a4e300f31633a122cee97e5eec417cdeb5cd5cf2d5d38f2dade528304bf17e6c46da23fcf9c4f211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002663204ec5b181046b80ea44b88ca0576b090b99b44aab4e9142f51594e92b064ba4c4e1bbd2e624df87164d4132a7500000000000000000000000000000000158d39819e15d6caa9727efbcd86449a48f9e240b8eecc7da9ede44762ffa7366811d09edaf435589258a6031416afa900000000000000000000000000000000052a0c049a806fde78229535b730ee06ce511590c887c331c7e1f389dccb49890eb523bfa6be7670f4a4b9f91c3b0c1c0000000000000000000000000000000003a59518ee1fd48dd11a6b69fe3a791da090d51e68c56db675c0b305f5545801aa814f6029e7b15e51d6f38fe2cae24c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d6d0239cd85c5c7b666294fb673a1ab92dc54059dee72f58127324dd0084d9da277ab9c75ef2b3b1c18f564f20ae66000000000000000000000000000000000fa6b340557c8d513832a58ac7254b46ec6f13579f0f76a241ac767496812b8899b5fe68e969ec22d7edad56d07cdb07000000000000000000000000000000000e67e6469a5fc08eabefcf2b4dec7da375cfda17efd21253e5f09adb6258c1bbfae1f9160cfc70698b27aebd2d0012390000000000000000000000000000000008a907f0f5438cf58308780265f215f9661c6bc18f9d6891dfa27953f39cbdf9aa2dbac8efd1890ec0aae51739ddf9031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144a68ac59c084d38dab96b5f7faaadb642d53af5413f369b340c15e292448dbb6f504e95a26696d9ccd32f65437021800000000000000000000000000000000104824e1cf15d29c96954b6808816412898c88cb5d11bf08ffb718f9df7a2299d5f9dbe287007d51bb7d973995031ffb000000000000000000000000000000000826b9acc6109a8000ed2627f7b57512a2258c94fbce7cb7b3b4bcd0ad71fc48518494fac9c2c018d8767830c1e611e6000000000000000000000000000000000aabbe550a2147973080cfa0219a5926aad45e10b912b651ac03865f4db8a515f162cb5434b4c563441f741be786cadd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6b1f70807ca67555ce9ca2970b715690d87b23ef0b76f20fbfc3779fd1c30cb3d6b259790514ef67024832e7a746c00000000000000000000000000000000005fe5649ded30720a66faa746f44dad689ee39ec0a0ca45effa0c82bb18bef9601b36b352a40baab6ac774f0ec3ab3a500000000000000000000000000000000194859fec7c6fc72215e641b079e75671d2cd85647cf646ef53bf89d0702acdae542a94ea81e800540d3aded7527a7310000000000000000000000000000000007f85d918a78589754bc8eb9e2e7234e7fb7e2bd3d3addbe76e76884e926dc6f796743f8973a44539b7b999ab3fd85eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163873a4a926cdd600d72e98abd92c702fad8b8a09a88d8c967eebe2e38799de75d72d20ca3886bdb8b4cefe0d2af5e1000000000000000000000000000000001100cb70b45ec19cb3dceb7d0859a2aaf9ace57c7365f9a8d5076824b93925e999a465316e776be16c96857260d01bfb0000000000000000000000000000000016ad120eecbd21d1898e4906e421bc737f24c27bf86572796ed9bd87928ec9bf764a8fe739392f5ba3c9af285f07e60f00000000000000000000000000000000194dbe8faad718436fb8b711701c707c8df619b53a03e809f6f6e258f3e963e3a0dcca644dbf41ae1a9e0a435783757d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd7f3a59b80f50b8b00c5bde398ce1895a3a39a008bd637ad51ffdce62e40051f1dca8dce99a393528286ec78e3445f00000000000000000000000000000000108ff554e46fb6dfa1be318919f2c0e2fe7c89d9a64c46f356e50c021a0aafa1641038a4ae18de62533dc6eaf548689c00000000000000000000000000000000050f861a6a6ae79cfb2ee14a70cd20324d64051c2771197fcb0e0df0a4be9e8b075a58ed81d330b605bf29bb728aaede0000000000000000000000000000000003c1e1f3ee9d9b1ccdd1bc7d3f82e0e9054c84dd522958f9c8fa7ef480a42ced10022b1ec21328e83845439dd8577fde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b788b2134d0b2f7ac2bc676c2acaf9ef949913aef81770ae4c058eef26d7d1228164feb78ee8d1b56921d1dd80a77a000000000000000000000000000000000976417866e74d5058419e616560038229db329d12959d5d38843051e7f2924495bad8e9c5f03a7a94d16da290762dde00000000000000000000000000000000101cb024fbb74e39c4a608f593dd1e3c52d08be36a8795a34e52c7ac8569a2e8469fbd5b962518f3cd27e46b01664a1f000000000000000000000000000000001706d4f03160a84dd89be4db244646eae56373a614e92f7323ec55fb57d7bb4d34ddcf1de3afdbee1d4606ff5f88fad31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001533fc6f0d483320f6724b8a1710891ad1d7a49e740f32a53ac86996439b4ba306f0594850c82f9837da589c51bac1190000000000000000000000000000000013703a221a1328cab98f3080687dd0452531bb5202413b3763cda20b2e1e313b99cc616f9ce8092d62c8581017323ec2000000000000000000000000000000001583d535bf030af9545ae68d0607488bf68ccddd54692fd699aeb1194fdb0d59aad7c9273bf62a8a6625b87fa37ae0f300000000000000000000000000000000089f5b7c7d6fb9779f12dffa3c4ff7a565ba7a92b0b9f9944cfa29fb3b6f083f16fb6bf3ecd50a237f26b28221df3c6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001346f358d75792dff013837c8175f2396c77207b6065c7810a9d7e3688d7d6b00e0b0aaf9d2ee204302859f857e68a4f00000000000000000000000000000000102d012929c79dafc43d2755091a81742276156d354f28ae8d0cf110b0a6404093b6cb2fa78788435b27a9de0763da2600000000000000000000000000000000176c297a742c3fc9fa766445ff945480f580f2049795d5043075289e05a6e395a056ea7b1b54d68fec03edbd281fcee5000000000000000000000000000000000f946c72debaf9ea49e336a43ee0c71c52ab5e273000d786f8d1303e94f30fc3a949d03708257811e06778424bc667211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001787a88e5237c4b918bc1e2a9ddc0c2490d97d4099586c87d49d1a0943503d3ef00ecd068517510a8a5a29809ff630040000000000000000000000000000000007e47859b162e5b13c4d5be78cab0671e4be52446cb29831152b44d4bfff567be2c8bea91ee053d022461f1221c47f1400000000000000000000000000000000096299d93953280d1efd447427f758b5ff7d2fb8ca4f32dff24671633040be456984585d963dde42afb02c444610e73e0000000000000000000000000000000019d947ed09cdd3e5638653fba5c27bac4c7f65626ebb8f6930c0e6ad5d0fd9522ed6b3341593eeb1f5828cb9536a4af91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5a990f728f2f819e364116b77dc29a07a8f31850c1a4cf9a9e915f376828fb552e69e47582f1fce16d6aa55e489aca00000000000000000000000000000000192616c750b9aa9b3f59c17c061cd9823e15bc13958150fb4e738e118f31c1a85cfde10625628da689a0b8a186219273000000000000000000000000000000000cc9df7c72e928cef3fd126ab0689a215d5120624b1e7a872d75d6bfecc113f2ee46027f884d953e8b87bc3f6a747227000000000000000000000000000000000737e28f65ca6e0441a15397e426fbe1a74c459eec561a66049a73ade79eae91aaa6e58b3436285e9dd1f644d0066f061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005646eef0273cc59407ce4c434b4355bb20afecd151e62de8f0de271a8f26ddf0e35b1e23bf206bf815db4cf1aff3bd1000000000000000000000000000000000ab2861a429c5f7205931e3448d8f8aec01b85709f7ffe5ff64b00e2c0ead637df4edb1130f183aed1724f96eef5c6cf0000000000000000000000000000000004d29d7eae734c9de809a505c32444c1f61584a0dabb9ba85773b1a631f8b3e96270b9f7e07e1a1a6f84e6c8d23ca57a000000000000000000000000000000000f329426296056160ba748d6be674ddd1038836a5b581efdc3cf2bcaf558ddb7226b5f595ecff119c01515f68b68a3d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004201010a93c7e5b284db0fb34473f774c6b81c0b819f2c9383c4038f747ba48970520e327d351e2a0f89c0c20d0479e00000000000000000000000000000000101c8a81ff3f734924362ea64c95779d698eee63f1d7b954d570f7532bba45d759e0e0665e737f47b292d31ffd7ab65b000000000000000000000000000000001395e3a216e5e64fbb24e7396a36c14838b46ecb62caae32ef2b39126d3280aba54614dcc41ebe5b91de8dab918da085000000000000000000000000000000000469c734608c7066224816adde8b65b53647f36d5429b3bd23d2448a2cc6b04c93675e1a14a30b2c4a207a939ba73c061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ec79483d7421ad9806f7ec1bf1aa860c2aaac94c9eb0ae876f4c8296ddbe532b44b2a3af39eb976c160445ee6308cc0000000000000000000000000000000000ddb1749fe901d7a3b21248afd78c311f8ba04d1d7096efa85dd5e1d4d3e441d840bbc9a5deaf81d9035fd89f7b2cea000000000000000000000000000000000fc7be1a4872e0fdd4eeab5d1a42258a86e367c7fe146e07e0e740bf9f1ef741de892c21fcf4c018cf6876f5b775e272000000000000000000000000000000000b674bd417ba339d0dde56f3338674edc8aa212b405737c81109783455b1970c1fdb8b0db4609c5bfa8db9f8f4e3cbe91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001157fd9c45c95da07d1df13a04b604f026e77d68d3df4b5f5522d24a647a157e99a545f70eb890f158e43564b1a266c7000000000000000000000000000000000a31b41affc520d7ac293735bdf8ec7f8e68ef9619bde73fa49476e727e01a89d6e510e6f68e3e759044e0977c3f1a77000000000000000000000000000000001076fc06ecf326d07aaf682e1a295a6622b982f350ed995faf270e60a438b1b0cbdac1dcbdbe0ff90ba8ad77f1d7ffa10000000000000000000000000000000002927b28470b7f95582253706eeca812af425245eb6920f3da6bd73083c5f47a3ce8058e9e05863c2aa6593041b3861f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001470166a197924188838eea04ec227248cde42e72530ca83d77166c0ff91b41edb78dbdef084d7203e29d39f3aa97df7000000000000000000000000000000001227880b3903da9e50b6d3b6102e5602b520ae6ed27030140d159e30e6f9050ab3d93ac1d4d91f8f4ae7528ba1a7fe6c00000000000000000000000000000000018b1e4f7d81dd63718a302ea537a87ae033c792157d5bfc13cd25f605662982448c88ddef48a063d2d8bb72af3d15730000000000000000000000000000000007074d5efd2f6dd3262421185e24eb1d023410c4162c5c6696c4b8795d4663674f395d0e02aefc4597cd6a453ec86bc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f80ebca2d855537542705c2915662052719f898bbd507b590888026d79d3fd17bbd6589c288f3fe5be6d2cb971e6130000000000000000000000000000000019b9be8fad1557e6a590bab42fd41e1a5d633113f7241c34f90d36298f66ef2cd2169153605ebb7d8e32bd22da8cbe0e00000000000000000000000000000000142073e8509fc0c1dae760f9daa3d98396cd3a101c1bf9e88884ba9febdbf12ca23c13d238ee8fd116dcdcd2be0c826100000000000000000000000000000000095786cb4075df368d450d4f18756a8ad38e69ca43c81b7031c337ed5c0cdac9e5ea263a9c47b28232604a4e51ad4df41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012861d7a0b8f9488f514dab456d2c155666c3caa5a1d824403d4c26b2c9570713924fa714d46c83a1eee6dbb6995d69400000000000000000000000000000000037afe3789bef1c203d2fed1d093d2faa1efc15a5f8498610082392cebcc08550a3584406dfd5c7b28f39beaefc9d9830000000000000000000000000000000013c45a37b2675bb887bf246bc82f8e28c0e4e52cfc02d6933f80240f6bfc70977732781a7084e3c350a59f7d1c41ec16000000000000000000000000000000001622651600b43e59a811a132218d9a3e40b1027d597eaebf047b381ba666470c74de071615b75d15d55386598ecb7b4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018aa74edf17ec4dbd09b27b87b9b7208c7beaf78f5e7644b51b8db62cfb78eae71cf03ee1e1c48c89835ae269ef206d800000000000000000000000000000000136eef36ee12581357f142f5de9ba449b93ebc6b784200296bbee002cf6f890f7b1f24b79e96fc48b161360a08bc5d610000000000000000000000000000000002ffe16cb6282768d13fd7fca6ea1724f2bc79e5a06d87afa14ad2b16cabfbc67edceb7b801120fe5cc3da787b3125f70000000000000000000000000000000012ad65ae5abf06cee0d290e631cac315eabaa449a22cf439434993cf1e3d0c777b2ddebaafcb3f066948bde0cdbc663c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f43a66daccedc45649ccaf0a8c7541f2bc4b36fa0c2839497d1b5428a3aaafcc5f63aebe3ecbba79bf6c3e2919918de00000000000000000000000000000000115249380550352bcb74aec2598f89186eeace342f91e40a2ccac444f51dbf6f2e2873c847869b897628eb51f2d4b80200000000000000000000000000000000057524a376cd560ef8c4bfdc14f447caef9c3bca9604333aa91a83b4a82661ea177071a4eacb42bfcabd00378bc4d5c80000000000000000000000000000000012b1622aa90a0e2f8153707556a0d754c58b63747a9a3c9c6fd92353b4bbd3a7033177d261caba53f04b011f69b6f39d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b68a1d5ac080c24e1abd5795f2f95fb588f4195527d2527985ccb6b0a0e13c2e8248ffe217711fc441cc5cbac8eed20000000000000000000000000000000015474001a7826e8c308c8730d9e9c7d1e72f20a1f810788d7a6f4f5f26f09aec5d6fc5964c0ea721992bb0d7be559f7400000000000000000000000000000000129ff9f9709d7a4810a0f897164e7fb83d5ea5bf5cfea1e110563e74cbc6df57ba7bf9cba37d4b42105d53a4600bf6f40000000000000000000000000000000018331a163cae4ad3ee137db5ba17268ada85814e0c431f14678679e5e903a9507d9fb9d081f1cc740855ba04ee97a6d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012915ec653a9ce0e0ec7062b3dc72d685e9c89382735016f65ee43e2750835da61584cbf3e7c594c391f6f52195c6a25000000000000000000000000000000001222c5f0fc72e6ad7b725abdc45874524d2bdf3dc2dff2788e04a0c671b1673fe922c90b9c69bdb287eb23ea4d30510100000000000000000000000000000000043f665bd1371cb2cf63d4ec877d80c8bf9a8e5ba08d5e997369d16524a069fb6883b651f8b29f29d56e8683018c27a50000000000000000000000000000000018a654747706b458a8acb41a3a5c9317c4856f47f051e623df2ce9ddab2224f53ecd65583d5f712c8e4608a8cdc08e7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055460d8cf2dcbd9467091e632576c45d14225827e27f2693048885094876ac159b01c15fdfa09deec7a0bdeb974d8d40000000000000000000000000000000016b69aade8a21ca56679366b0375c659f38f51008705a4dd73cb85e44c60133c8a928e3e173aa479972f0c15668eb325000000000000000000000000000000000d8a7c3dd7c7ddd6a8f9750fce895bc6a691ce7648fe7aac5abb68969b693eb9b09dab946bd87f9c121171a6e940d542000000000000000000000000000000000b24b366729449d2784fed14b74646c53b909065b29407e3ecf04cbd442592ebd00bfff6acad8c0460befbc7e3dc93001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae220041fc997adffdbb1c1798faca8ef4a3fa72e45fb2bcad05af58bdba057460563aa39d98aa640a11c4aca4ad7930000000000000000000000000000000016a37a5d7f6c0adacba400db65fd4dc1d1e3c32c5a0b157663ea2d9366634e8249b9c0254904427aaef27ec6f58abc83000000000000000000000000000000001354ca37859865ab93fa9ca8ad87fb5b48bb258fe5d31475bc269ec7690fae75c0acf1b18d072e6762d11afa9c13805d0000000000000000000000000000000012f08b54b97e74929f00c0dab3bbfe8133b213edbe641531b01899602d05ff79b3f92f20dafccef0321d9b0fe66b39201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d982372cde62abdc22230a921b05da1e0ca46c057ccba726cd08f1a4ad5d0a45f96db343277b5b24f7a9b1b3f8960490000000000000000000000000000000014d64115525a788139d4cd205f925cbcf6b06781d07e388d91d4ed79a0c76c5c075fbc77bf67c9114263e259589bb0e500000000000000000000000000000000184a80d3ead2a24883117724db5d5cee06351ce180465f8234d85467808d7e0b167efcba5526f50c5577014109859ad4000000000000000000000000000000000b43df100affc20ee26bca4b9f7f28d9dd1ca1451d2847dcaefd131bfa8ee3eeb27d1e49acdf6793f8de21841c1368821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008edf51d1538088179b0da3a42a9fbadc107b7667cdcace78bbe4fb65d3f12e10b7d60fdfbe436bee13ed51489f253290000000000000000000000000000000013525950b14e9b0bc8a6e87889f917e011359b05107cbfc10c9b2b9e5b351e8a89fcb2457575d3f4041051eadfe70c3a00000000000000000000000000000000011947ee7298b45484eeb476389378240e6b717940005865c226cd2b8a354424ec4995e8e8b5e73134bf5890f62ab8330000000000000000000000000000000002d0b54ff8eca3a8664e233a9d2d345cf537b853fa7a59cb4790dec7ab5a802b7b47acc8d3ec503ebf690d247c73aa9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b32b8543154a1af01763f4a8315337670d6bfc96392231fbbc7785489432accc1e59d245538bb9d6636ad54962ee5a40000000000000000000000000000000002c2d62de6b255d663f148f8127425bb1be774cf6cac7d7031b10965085fbfb5a4df1ee9c16887ca174fddee005d8366000000000000000000000000000000000efe96a0b3791b046666b2ea5fd4dc8ca2b32bfdd53d022f6d20a6f5a8ee21d69b7b2ee30e1290ac6870dc686008f29a000000000000000000000000000000000572c70eb109894c77e56556be9cf7e4c3fadcdb08b37d68b2b8cfdf82df3dd4351fa056a258bb008b096ea4de99d8641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000013fe2dc53b7954a55cc04fa0956a88afee09015466cc7f06f0bc0d7311775fa9f664c41532a38c26c70e5ed1498dca1c0000000000000000000000000000000002d3746c037827c9026557a38f9bdc1ad421a52230582850429e9b019dd0f4c53a47a2dac14950e7e1a5a69a45ee1b8b00000000000000000000000000000000036223c9518efafaaf8cbfdd21d6b2e347e77ec9f6d4b123ba4928b335ada4298bf5c6f8bfb513ec5f98f4832d97f7d300000000000000000000000000000000148863742ca4fcab2b49929f9628a088c9c67343cc78558598c770eb3c8bb355c52e8f4e10899eee16c23a052a6b0f29", + "Name": "g2msm-30-jwasinger", + "Gas": 373950, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000011fe294de63c0370fc14599ad86839dab91487c8fb4ca8fa3d4e2c5ec7cb0581ed5a963aa4a5ccc1f4d73cc2e45763720000000000000000000000000000000011108c53295a1c34595fbfdd24437dfaa9595e77cc46b828c3a28e4f6974297f18c6381e35c092943839ba327d91b529000000000000000000000000000000000c0cf7592723172d94e9226659032fb0d603af2769fdd97f41094bb41e375975f564040d9be764ff15c2655a0b495735000000000000000000000000000000001342dffeb8ff7daed381e8f3096651fd2fe6faf43bba2eb83d776660fea50f13546576a1fe5cd40d444458979ef61db81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000169ab77f5f817e1b7af302d857f0399af06577e10ecdf005cd46b000acd15ff7682f5e1673b6e9fe0fb560ffe1a5af1800000000000000000000000000000000100d5f6162d969466851f26e2e0e362f8d7982863f4ddaa4542ac02e7574cc062b3cab0081c6debf6c0e3b0bb4432b04000000000000000000000000000000001774aaee8665b850b3e5cb57603bf36238b46268fdc00d92215e561c93027161c292d80906de78f473ab5205d7cd41470000000000000000000000000000000011d078f58850cedc57fae057f929e456fb7495a523802bc3a18c18cfe476b7061686231c26f7c0e3ec9f7bc2750d20fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071567180e848385f452f184c508777dc547d55069b3d1001b41c6ba5d2ee9340d8cba37fc8d09fe07098a52e32fec0700000000000000000000000000000000054cd3957217fbaf0e63e376b1c79a50538332bc65906319b2fb2e59f6eef9e772aaad85845661cb88b5de08f3d23ac9000000000000000000000000000000000495a7fcdc1f9abaa599f70d17c1c73386c89ad2de8bd84931b87e96f67e1696bb82ab522a6569e3174dbfb3867698f1000000000000000000000000000000000c27d5b85d3c14ab4f0520009af609b18b87bc6963a97a46428261346741b8bd750e573c80fe3838c420e8e234104c121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8de7ab91b842c2e247bcb5078004264877aeb04d726c536fed17956fb5ca4def676b7b6a20f105970dbdf518fd9f7800000000000000000000000000000000049d68f46e7bb4d23a5891af9812ff534da4f7a3fb7d7a703bba82ce7ba1bcdbdafca2cf3651e1273c10a7ce39eae49100000000000000000000000000000000145467ec4f02eaef135691c38eac8123a86f47dcbf5078346ab230511ddd94622263bf136db41144b663355cbdaaff4c00000000000000000000000000000000066158ac9a239bbd00e3041e8444ea5e5cc43c62d722ddb81a19b98937a060b6e94beb95ff7ea449bbb9f05986345d101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090195d26d117281a8598c374706b3f71747a22b7463b5b589576aedcd773f09420f0ca8a63c5cd39cdef2e83b8f8310000000000000000000000000000000000095b90af146fde11c8f400f1246b9c1eafae0788a0d5cd7052cc36b77117a4e4154a0a0006509a5e91d88a6ce40dca10000000000000000000000000000000017aff59b368f3903c9bea49034e3c67c7d120b0e12f8a7a067f92ce871674d3a58764cdf7cb528d3d243f8e8bdae9969000000000000000000000000000000000c219e407dbd8d4b2521cba1dfca35ff2e33bd204fa96d410784c55e776218d8f1cfc9dd9d2ece2845f6c5363d3280311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bcda99a0fe589566296b085c63231040a30356ee10cb693d084f4d7d3c5d61bdaf483739f5173f1f95f6ac1d61e2f000000000000000000000000000000000034026d7e3173caa159b4cf311efa8674dc8b51680c5c6aacd762092fda89e9a6948534fb231369a2c116180bd328b0d00000000000000000000000000000000022710c84ba4081720ca907dbf2860814ec1c1adf017b4b27917c174f604675961c70ad25fea3522b8da13384bd9f1e10000000000000000000000000000000007e2d29ef5eabc6e26637deb393d843d09d0a7c599621bec0b921ae6adaa6e334c1c4438499d3bf7fbb6deea34c0a6fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3577e9c77f0366baeef1729372b7fad18a00d140cae134f5d6eaf8b334349c29a5e949698f9792ea9ffd7e1e6ea8b1000000000000000000000000000000000262fc8bc37a12b14e3945d0f901f892302ac0ad4f6d572186e354f9eb0d510c6d5c9e9e99bfbaf8850ac6c5a3b58097000000000000000000000000000000000d383801798a9536c46a686ed00370c21ce165c0e830053c67417966a4e8e22359a85771cbbea789fea671e74cb6afc30000000000000000000000000000000004581f63e62464cbb3349e41eb2f3aa5a284b0cefd857e16a938b9357b99cdde6c6d1c949600f71795bb2815d1d5e8e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b9e86b13bbe4d72b2a74296bd40fcc7f9688880d4465c4aabbc43b7a9242246f14e218475366739af239f0ac05c46a000000000000000000000000000000000659d60ccfbbea3fae789fa1ef668bf4a0b648b879cd56d45af104bcda9485a2ce68d25e9a76edaad8b7c2891973b10a0000000000000000000000000000000010416c28e8cfd0d6d64eda4a764068242dcf4af0e634c90186393de5e4374dd57d88f6cfa21b4134a92019dfd3dde2600000000000000000000000000000000000a073658f93980c037e9f6dd21e0bacda8c4b5551104d460384be22217e19bf69ac8702888bd7bf888bbb183e3707e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e2c2d8cd631f08e251436e47d8e9e1cfbfdbf27e96f49ee02286d3cf8238f8aaf01dbaa2c134a72170195a5f17494a000000000000000000000000000000001458704068da33793dd44ddd3ca25deac8b82f593baf30f005a77ea1b03ad53ba86f6c6be28d789207d879c9d6ae529200000000000000000000000000000000068b9099a85a6b1de2cdc22ad7c88bbeba607983b168f87c0974d9889c8497bdb6bb0d8c733dfb0a42c124773176fba30000000000000000000000000000000007a02d1824be9c7c25278d2ce3aa9e18d4750e2e733d4145158f9dd61f149afa7d27bb4f9f1820a0dd6484777f3e78331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ed40e8fcdef5b8c17087674872ecb85e653af040eae611b3e487444d5a09cfd77d2e3ff57b616fc7dd02cb134169bb000000000000000000000000000000001509c9550c5c016915f24635c1df6800f610df803c7e693dfeba3223adba3350d4ee2ea23b43203170bf4e631aa9283f00000000000000000000000000000000037e346cd4f033f784c7394b4a13dd4d6eaff2ae28106938d2725f4f4ecc7e031b4d22fbe4321a9a97d0243508260863000000000000000000000000000000001994633aa59c4d85baeaa384f350633a117ba149740507e44d32b46fd7ab7b3e6e2e10bd3b95c6b6a5bd56cd6dc3e8be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117187e61a3ed432dd1d21f1e1581a320207b93d2187697deadc134a150be15ecc665c5f33405375a28a532df2fa016d0000000000000000000000000000000011433b8af3549304e4b2878f8e988a3967a2207e6e011603e15069f290128fd6c7b435bdff8660307979b28485d9ffa0000000000000000000000000000000000d7af0353a8e5d8d8b0b8d355ce2298f2c6d574ad88cfa8b0f2ca231261a5b8fca2b288ac8d259ef064e5ebaa5f05a4d000000000000000000000000000000000149aa6202bf4a90810644e46ce0f37af064739f0df82fb1b826a3f5b0daf0f8c8a1db0c14788a9a64eab5a236a7a5fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147533909f6b564ff7188ebc54684f9f1ae46f5d71412a95dac50f3fffeee02466b048c3a623f5b97ec9334fc0af3a6100000000000000000000000000000000104a30ef64a113c0623192f0ed5fe8ca6e4526afe5d8f6137925c3e0d0c6f714cde41e9862047e12ffcb435bdedeaf8c0000000000000000000000000000000017b34c485532d4ba630a865df6bc3cd32a2bdd31556286b685b1bf722077d62c7864027cfd628a2f92cbc357070d20460000000000000000000000000000000019f346e3494f71e87d7af358b7d5685d26f1604e5b87b88e93ee3cce63eaf0e2170c7eef55db14e964df998cec3b088f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016d492b8a337b28efe2fb8e76c96cbac2a5ef84a4d5e602676350539858d1d5c50ba34ab7c7de1bc7999fca1bc1dade60000000000000000000000000000000000c8bb2849d9184c6494531450fcbc8bd0988322b6053161e86d7cca130e993a80d229bef4b792f93d75e1890d520344000000000000000000000000000000000e9592f6d1d65d53115953a86aa131ab8ee5e4acd45ded9a888f39552e1423bf35326a66924f350decee64c4b1a479800000000000000000000000000000000016cf54d46f12fde30781fcae890dae9ae1dc5d79ad549e973b3fee0e01285f9c7e8b275fe58805e5b4093e1edf1a30d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8109c209180766d1e01fc7b3307752fbf717403a63774a180c60c07d171974a997da85a1ff5fdaa52a52899ca54b8800000000000000000000000000000000183c720461fe98527ae1cf29d11f6aff4ddc87cee9eb94cd2b7e344e76577bbe354233f2d9ea5b614ca4bb87b094b19c000000000000000000000000000000000a99c91bf62ca2beeb5908f57e73fc5e14d20462f2ddd20058619e86595a44226c7f13a87ed8a31e7ac58a77613e699300000000000000000000000000000000173486da0d9efdcb111ad75636ea21ca864f127d594ad4c78cfe7d6a60ee216254cc4e7ad9ec4c1c94a2c03619a2468a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c9a3c76ad02ad837fcd4f5d85a2d8baf84f0df4fa49ddee43d1421796425d0abcb45fad37bb0d95e77992ce6c4c114000000000000000000000000000000000e0046f3a53de94bb63f960224c7383e0534882aeb9109067c8bd6423186700e74314db3b41368d2a88a5af837fabd02000000000000000000000000000000000f05c7bae8cd2fbac933ef672a92b758ca90e94b5898ee9204258b593e2ae220a816b5021803a5411044429db180721d00000000000000000000000000000000137488ab6873a900bae8a4f42306565cb991b4f9ab0a68fd7321eac4e718b3969719c27cce7b3148f59e41e7e695d2d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000115079a34042a252da93323b47237847d29b1f85635874fdd7ca9ed1ed515399636fcd325c328fbf4ca4c337bf4a74260000000000000000000000000000000008eec5be190930f05af995d91858cd097168bc304bfc1de514b0eef4850c9b0e387d8ca2cdd7140b00086679eb8182d20000000000000000000000000000000017125e1ae68d18dab9c37fb8789bd67287ee10a5e1553d141f6d9a7d8339876b034eb01174f407ddad98854601b7c09b000000000000000000000000000000000837c59843eaa08bb887e20d6814fbd9435767d2e2be78753cec2e3e3fe6c2115ee6ef6d4d465a7fb6b55f50015ee6bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fcb8d4f0253a9281aa9ec35ff49df054a3bf255e9e69fdd6190a9bd0f50c0a53817ac490984ca0a627b861594f6930800000000000000000000000000000000152ce805c36990c295bf13ee179dbd2dfd05d322564e3d2b3f11492e92c1e2ca2fc5c7776714aa18c7d10e34f97bde290000000000000000000000000000000011bb8f4c926e04b290848d903981c66185a9163905fb2e41951e53ffd3602352148c5b88da2323782940ab6125a4aa23000000000000000000000000000000001545c8c909716babdae2dddfb2dd9dbb21aa687796ae01bdd8616f2b558d6e71938aee86fdd92556c8378b88a60090571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a159dcd8519222e375b4664c03fc50f55d4ce5031c48522c4899922f498671348fd56ad2943484a79e72011604f17a00000000000000000000000000000000000168726d77c4b4ae3cdc5fd66af544e7cde0efac521d6ecf27235486f4b9febbb532d7de2be62232605cb6f95ff137000000000000000000000000000000001220c8c1f4bfd40fd6ad5a0912188c0275e0acdbd5dd064673098211d514beeb43660c3b3a3ee15b7e7c4303407e90c80000000000000000000000000000000002aa452800fb4b967c34f3615d795a497be3bf0cd9fb2783a304d568d8eea3821a98fa4b1fe1de314898966df3f9526b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017008a6c1822705ffdbfa5d5246c3ebb4ee980ec1642c1c8c9ef3e77ab384278d0547204a5052057b39390cf18899bc700000000000000000000000000000000154a4ef11cdd579e48b58a2f7e0dfc8457b6572e67ae7a87dafc137cd3bb6d8ec46e115bfad7f2589a643c1381a1c0610000000000000000000000000000000018f5fa3201a574328b57a266c19df6a3a5f8d55338a51bb618febe69ac0dd9e3a62551bf3d44ffa8c4f283584b0e9723000000000000000000000000000000000b19c5e2bd7183a3afcc14d5ef3736037525b8b3ef404eaa9e0337530f99b3a009f7a5b6648c5cf4471e89bd175bd6a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e55ae39c17949200420cddc2bf962a4bf817b565b05e7aefdde76785bacc9b591af3813510e008dafc113e97c1bdf9700000000000000000000000000000000045c7b30658a547968a430ca68d161d47d3b4f93adef63846c5db5ae921e4eb03c9d9bbd24f537c885abd2ae39d8c3d7000000000000000000000000000000000afd20180357f3ad21307794c6882ea7a705952fa0ef101610ff695b60f1463e4b91aa90f44e07348a1db27cdc9b17430000000000000000000000000000000004ef734bbfa1899f219bff8612f5de6f98ca801daf055f70e8c46cb6eb564ffb0e4217145295ec0d6ef7b207bf78bbd41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011679f986f685fbb7d60df586022cdcbbdaf395a93b60fd2b4999fedeaa0ec00feddd7fb96fb2869a4070483345afc7c00000000000000000000000000000000199f6604aa198dc6a42d7b00ef9dd6fbe7f4d07dcf13d58817e8f39a91d59388fbe2f8b04e8fbba9d09c5bee680897a0000000000000000000000000000000000a401f85eafa0a7135efaacf971e11ff3b9612f2f40ea470213c3187efea095dc6c722535ea5bc0023a811771415d8780000000000000000000000000000000001d40a84c8f8d83f3a13412257c77195f057b33d0e7514599a0cc3e2d345974a25d92364c0ae54ade8e9cb589c0ec0221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4ecdd7c4d05eef4aa878283a85250db6cacf2f022bfb2564f325061f5dd72e01b39be9360fa407fdf9ac735779f63000000000000000000000000000000000044bce2fa18795bc62627b4de89d489f2505167c54780bf051881ebc332cb3df398dad4d05edd8702e5df4c0b27177f8000000000000000000000000000000000a1568b982e176e393eb1052a9d8a74a07a01ec7370c9c1fe881d71fd80563d91b0e11feae1c1871e2b92f0069fc315b0000000000000000000000000000000014ac398a9d7df2dc317ee143ed4e56f8ea2a4fba307694745f72695928468ae2f66282735663dd594acba9d83e2c4a4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f53d9423664106a55b92b7945b88f32041187eb44836a803b1a1e61f660c1854e30179e8349d116a91f20f91eaffcde000000000000000000000000000000001895f05e99783ee68b943698f2bf2f037851df090768db976070fd92842c17642de474a615362653fbc01c744b80270800000000000000000000000000000000158dc7ea08fe72554d58ae70cdf4c791b7c9dd422a822d820526c9a545f7cf580beb4d405db438ee7d76cf32154d06b10000000000000000000000000000000015e9c5a8c20097f0f5c9afcd1cf03c8984496dd616241ad0af7cb6942a5a9c9e10b6cfda24e6f918dfc038e0c2e2bb7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008d78b43d9f65e2a4a9c1053ce262b8598fc6fc179188f717af8ad7542f89a10d4a5ce2430f89e49b9da24f62eed1a200000000000000000000000000000000169697779acbf79518f014f42603a4e9a145272edb13d0654e9b6c9b99a32777b8a458acebf1ea513da4b7f5b8659c8f000000000000000000000000000000000a5c767eecb4a98b08e91af9f5799448655743710b4138f180d465fa2c370aeb933695cc7b9272ce9d1209c29a953d050000000000000000000000000000000012b25728b1dee57e12932bdb2696189fbd443b48f79f91bc50ac71d6492fd43dfcb13a177abecb3907cddf7cb05ca2d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001416abef055929ff36493939c670f43f50e16041e9af07e7f60a10b6f35f4b80a5c7b08f1a6f2c7925242a5558cea65500000000000000000000000000000000071d0473d203b27921d1d18903ae0fe2047dc488448fa651afae2cc1331fc266eabc544dbde502b5a52343fc4473b9870000000000000000000000000000000011a723724fb35636f2934b28720d7f2e68ebe2d61b585011e1d185170e1d3205a78c4078ecc58d4e6e339d8b44374f75000000000000000000000000000000000b89654356408ad5f552ef2edc48d19d6f8be692bf09752005bf4f4927a2697226c6f336b036c20cd54f77464fb083171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001255f8a9016725700a6f19af155fc606f62b658d6032d534506dd02682ac912aa326f81a3d50cff51825473ba46d2b6e000000000000000000000000000000000aa146e10e838e6b89a9b73d2d227a828c401f28a4bb1a21d1ceb9d6e33b824c6c07d745f0d2fb12018184a044b8a1b4000000000000000000000000000000000051ce51eda0c3b3d15a1ddb65e0b346c64af7862b855555aa51a6bc29174fb70c7acef46a0901d197fc75436b2098c50000000000000000000000000000000010bbde38f70dd74040338e52d1e1786525cba7cabfc18594d1aa3e5044b13ba4f972d92362bb40b7470a802cc8ec21261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015bce24cf790ddf610333375b28840a261e349fc2f7155636d420cb9ad9728ad4fb13b0a3e88f4e0e8a9beb6bce3dc9500000000000000000000000000000000159618ca7ffe96d11baa38ecd25816eec598df4822587e826716c9ea4a5c81a901457823ad18a1e659d2f414aa1d24b00000000000000000000000000000000007eb42b5851cdbaeaa1a24d202f82a851adfabb852f11f296964d2928d8a8f5f30dadd54255285870298a4cc1d8b5b400000000000000000000000000000000002432af2cbb14536c8c0cdc18f7f56414e432b4b9e07fa31ded9aca3ac7dddd16d7dd93aa274a011f72c6ce0a20c064f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045fa125a9857620a592c8bb6c8199a884880c02e19db7d1694cc28bf5a956279017fa69ad3980a2474d6ec43af8eddf000000000000000000000000000000001359ca4a3d7dc25be649e77561b672f1a9dfb378bbce1ef005ad0da02a73e2a684202a5d32fc930054c4b6fefa6200460000000000000000000000000000000001d57f00981b049cbad4e205e708885e37f67ef40c791b77d318cb0d2ce341be3d9ae58e858dc0eabca7dbe7bf886d220000000000000000000000000000000008c935df115ce7daa7bf178b06bbb40ea9d4d0a96676bc95da9cd0fa6b0b60a5596a050891f719b4d4b11e311ae5ce541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb6bd846ca774707d8c7b539201adee8fa4acbf340d15bcdf4e484ccc9e0b3757344d3585192856ae2c92e4f8dcb9070000000000000000000000000000000017b6b83131c964b15ae933db128b1019f24b85d2680ea7fe5634f23f7b2194c45d041d6ecc80769f168041adb5289dde000000000000000000000000000000000c9c8b38baf6072326c18ac99f08a1273eb9b1dbff9c10b5591f5550d707f2df7aed02e16107444c40dd0e2cd9701b7e000000000000000000000000000000000ed4f6b55469a2cb3ba732adb4f1c2136601f4cc4ccf20ef9d5d9343b952add1d7eccb7acb45b24e3d72ee83d697da1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7a0be376cf6438431c968822996514a62262a634b9b0db438e7485e2f991fd99d30f462f92d3df139f7ed61ab26feb000000000000000000000000000000001970198c9db46369613e7787e56d5b185c17150cbd0a0889f6f9ab8b02c4581d35efa33f26546dcd05fef1163d1f27e5000000000000000000000000000000000cce8d5a55b1aaeafdb50ea2c5470bbbb8dc506c8276cb4ed618212be6425172d8013eb9fc07f39bea77f299d442eee2000000000000000000000000000000000cca501ed9200a901f30f583799d6d5453e97d4d899c8b9772d57ad0bfe9da2d06bcb77d20ae0650b0d5a93b040262ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097980da09d6f498d76335a9eff9d93042c85aebe7b07d047641d0563e4f1fc4daacd4cecff48640bbb93e453021decc00000000000000000000000000000000009c834d0990ca1e4e06858ce7de6ae4fa76b8e9c4d46f88d1da3afca9707f340316b14618b7717f07c22c934cfb07c200000000000000000000000000000000029ac91f0b9df5a39b8a5e1f22e139ef6385ec9ea8fd547fa5eb3912bfa315b5f474a776730ae8c5dfb68871dd96340d0000000000000000000000000000000000d964c9d7373e6ecb40fb8b7dfeeaa63084cc51a0d2e359dc9a88aae2fdce01c7c401289a89ddb779d604d6e612dd5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000952b3501d0fa50d25ad5e135e75a0f50eaec617a147f7d2b893364aea650a2d47bd58bd6c52bae8d7dabf4c4915f4a7000000000000000000000000000000000a31e469510767cc3e0cbb378ee8e883f8e062c157833b4dfafc6bcd7100c4bcd992fe3463cc2d40e7eb0d88a3aaf20d00000000000000000000000000000000083c68123a5175e1bf4d10edef347e8e39cc2241e1d1341b284274b9c380128c963d22df99b8bf674ec4d9837b5932d80000000000000000000000000000000000b12a1ddf39fbe68e0eac6b77d9397d54992f7737958a2270391d9bb716afc477afe6f7879a8897509c720cc4942bf8", + "Name": "g2msm-31-jwasinger", + "Gas": 380835, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000096035d973ce54172e18d3efa7bcaaaac3113f1233af789b5cf0efbd009d63b6a996bf81d7ecf5effbc7ce926bd8d6d200000000000000000000000000000000042ac0a88b1f08c391c4a93f60c7b0bb145e25d2936ee5cc93c2a9a220cbeea14cdd4b597b257bb02478d2ac7c7537fc0000000000000000000000000000000002dbae06ce6bb0802cba7050c74e26f26d5d2be93786e5419865c815902e46678fa80d5acb7bdba0641f641286f71451000000000000000000000000000000000654470bdfe54c60c22433faff0bf66bfe5b80bd70b84befd75b0f302a77294e65344ab35a031fcf298bc16f4ef123ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca87265eac01eda9b2e4fcb35410d543f2abab6edbcae49f8abfc36cf19f4b9005b10b7cb41712d83f08602135200510000000000000000000000000000000018369ac76639691c32f2f45da66b4fb0610d9adadf5412ef8af250d86b8e21e80703f35bd825862dbebc527c4b424d0b0000000000000000000000000000000018c13080eb44986351f442d49e93f6186526159851f95f799aaaadf3e015ec38eea61695d25d3d932d70149c3c555e00000000000000000000000000000000000fcb54a6a326c991a1c6c50906394e0907816d36b4699af6fe09d523d5c173262228778e10ecd4ad3f8289740ee0e3611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b94ff282e5b6e6d9ab33348fb5faf40df38b4c380bfc0b1fb3fd820ab46416d43341da75b9e33cf6b56d65268a5c38000000000000000000000000000000000e5bd9624278f9cfe7693593eb05760c10f04e1178b75346fcd9f373055cb62797cd7c1f8c34823d4fa065cc33090fa80000000000000000000000000000000019ebc3c19dccc7fe2102200180331814f05c7973383bdd98c079c3752ec455851fa779421ee2a02e5c710a722e1e2d5b00000000000000000000000000000000170e11a3d287907204b7a0dbdaf98eafb96118746ca4899b3bc86b5aaad98f4e1b751f447cb485cc990f217b112480ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134428bb054ace91bdc1ebf6f03c0e95e42e333370b07f80510aed1e592cb44bd5e0e617e7f1808d30c5f1e0a7938db90000000000000000000000000000000014be34db195e2a84109e79f2c1fbec1330fd97f84b5e09e5c281d06db2280692a49de70b20fe76f1ed835ac38e12fd4700000000000000000000000000000000180e7c05bbfc07730276c245c58f4731e4ad49b2e06a45d17901b558a7a52f10118a10ce3c85d5cd237b5f86abfda2ba0000000000000000000000000000000000af23524683b3620396b512d7d3140aac7843289f35ae9a325d2a581db78af816a4c6636f5d61a622385e3533b4bef31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ef19e1a3450e813ccd3296d7fc0825014a9723bbdeb1dd64270a562b5656ac25d19f15fb2b759548adf8052f786e890000000000000000000000000000000019d54b2909ae0f3d7fc1b642732e99534463c81d77b0535ae52599b75bcd233d2f362a6cabfaaecfce5aab852479b27c0000000000000000000000000000000000a326473188960f55d5c92cd85d51e365803e55bebe3163d18bca388f8c570e8b972e46fa5a2bc99d7b0887636b4662000000000000000000000000000000000b6aa6729090f9c6a6d87dbd60246acf6bb464636e36c477de0d3394461d44cfb82e472f26407b45eaa8a85567f30b621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010aeec1339e6ef01af6db965058c1d697162cca3d1f88c1b31fc1f9c54110eca0da247460cd5db9eec9122a25813ddc30000000000000000000000000000000001429d6f4a5b69f171cbb8e9adc9c7b2e14fcb1cac6d1e440266c93dbffa69b5f5f734272721a96c9e0078d72c79ffea000000000000000000000000000000000825648a95dec95cc130c3c345cf05481d8a571a25d72799824d56f8b64f2bc2ec2190bf5b23a3325cfa16c27829bc23000000000000000000000000000000001779388b901d0f78b95f50a32e99f32cc5d8079dc5c38123712c1b14c3dda3468dd13dedcd8b53665f707293754cceae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034be8fea61ec3872dd0c9e42c043e6732941759188c5586ab73cd57f0c304e1a31bb7c9c40543777f7a6299e673e5ae000000000000000000000000000000000af8dbd6971aa125e51f72686b577155ec4bf2477bdba83bc65d61dc59f7ec05818e02d4af2b13d7a012a5521489978200000000000000000000000000000000054e23ce1d67723d8bb675cc2a2594f73bb2e33e44cc77403d1d6130045e98d7943afb054859143250ed488d30d1a070000000000000000000000000000000001605cd5008efaa93cf562a279679aab202356906f5f39f4a50c0acea0bfb03d919d3844c5031eec99e3b1d79efee750f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019360391645ae62ed727816e3a58f41cc6a3a0195e455956e1a00f1cddde7443e95f50e88a6ae5ebb803259412477e11000000000000000000000000000000000f5647c7ae5012df5198dd77191a758bc2c519f748b07cfc6807b23c0726ecd9023250f3106173c4a80a823e074b9bbe0000000000000000000000000000000015fec9a42ea91098a0d063e7a984f6dcb0d98ede56b9dcad263b010031a57f74afcbaa7c43edf5cc50db582be1f02485000000000000000000000000000000000090afd7343d13004826c6b62d668f4bc77ba770917910b204232492d724f6c50d360bc5d63cedd936c5d47b61bdb30c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6f6c6ff2613957d15325d2e4d77e2a7389d0f9aa70fbb48d966ed2960b15e6756843ddc61c2d155fc6eb7a5deec4b300000000000000000000000000000000053dd983719b29e402a9150f140bd08a3d737ef356b9decba631bd6af3068add920ffae6e53556e3bee9664bc8bdd9f60000000000000000000000000000000012c9383ff3a5677fc23d6720d4e88bf2ea16cdc0cdc4b4f6da570f71c7214b0e224786e2032921ec9e36c3bd5d325290000000000000000000000000000000000ef513c79456610a1b4176a501ae9544ec7106e06691adb5cfa39a2fdb8a45a18f67b653c203848ad2a743dae064cdd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000087e5ce2d5ce45772ed7325eb0816e528d6427c3465148312664e855371fb929147e7b0fb8633e5501ad606133ff72810000000000000000000000000000000001a7f24909ab8775290e5a071c635024586d818e80c6d609d1f16f72b536c91409ae3311c97a3a6f093f03872e9d4180000000000000000000000000000000000b9a4522e074034278659c7aafe736e35e4a8377ef6bf646591573d468373ceb306da971a2eb90a0920954e0a4a3645d00000000000000000000000000000000154674bb8cca85491f79badc76b0b84cf6d788ec3bd729d9c0a46cfc04d5fe7c5607189f07284e8b00c8eee51fdf9b9e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f17af3f1b0ae6d8e66b976b3ba82c45efc912e7fcffcba99bbbb516ecfd05439bad343260b50fd89e3d3ed31bf9c3100000000000000000000000000000000041d4356e23e1c13d459797ffc4166070e3357bacc9d62f78d38bf55b415d6f5921271b2b5d83c533272b5006ff898f10000000000000000000000000000000005842e6f29660e99e20779d258b6823d663f618deaeda49a2363f1afff0d9fb6f6044918dfa0df48f9646a01b4b688fe00000000000000000000000000000000147b042eee20371a3c1639bc4f9fcb499a5aae71a51c92fe9255cac836025e7f3c7b0f189009aa8e7f915864702df8881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d114d526f4ecd35fce12727a110b6ced8a25925f957cf493e7261ba14eb1943d80f2c65a0b23953bc5208075aaaff190000000000000000000000000000000011ebfe2fb900ab4e233a6cca08a7d6c9d29780a4c426c89ed94626d41a75a3c984abc49d466ae7600fe2e3df350233bf00000000000000000000000000000000138b7b1575abec5a43c95af492b111865f813991186d9f3eb0efb3dbd810bc7b9f91f60271578c045dd8dff93974ea83000000000000000000000000000000001177c81002b40d881d83e3b9dcfd3c19feba2c51e33769326f6445fb3fc003a70592443b6391149484d7729b294d85021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000adb22e2c987bb0bdd1bf86dcc9f514440826f8d5727e563003bed586d07a0cd95a2da8236959a2758eef7f066cc619a0000000000000000000000000000000003092510625794fcc3487218e5bbb261cecbcc6cc3e2c4b93056876e32eb461239f18071a0c08a276f0631e51a0ed56a0000000000000000000000000000000006098f0a3ef777cf5dbc284df2ad6f445e32f87d7bd8d596652d564112163112802f19ae1e32e26d6ce5431304f5bed40000000000000000000000000000000015a1e30e0a367a56c438c5a83142013627cef89ecfe8ca6b0e277743e64f4d0fc6a744d019fd81c3aa896346611369711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000145e51d24bf7f15d99565721d912879d39bd583bbac46f5f652164eeb94bf6dd68530b462123b2bce078ee32b0b4ef500000000000000000000000000000000067831f84432ae2057ed869bad04a5153b33be7a42777a293dad1db5f323c4efbc776a047f2d3c125c3e4b04621d4e25000000000000000000000000000000000114c7bfdc9546cf2f57451eca30885a4aa10dce4ead3b3b7b6c527f6f3844cdb066eb7e0ea5d76e2f0e50ed1e8e629e00000000000000000000000000000000087dca605d1dd4b52fd9aa12c57f61791b46e7ded5479a0be83e39bb8788ec852d6fca1cb1415a92b9c3d787c17aa0211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000500972dfeb78854173c0ae7ed51c8e25899dc3acacb3a8542d8e337403a983b85ef5e5a1e86b509c0364c3ebf5021820000000000000000000000000000000010636bd45a02115f460b927a734cb03f8900532cd8626d01de14bff9cc925beb166f4495fc06094e093bc31e7586bed9000000000000000000000000000000000bcc32fcd96859eedd8d32a12d3ba7feeb8903eb80a5aa118e6feea1095d2223dfad89ba57f7d0233016d971877663a70000000000000000000000000000000019bac8625796126be24f4a49abfebaadfc700f66abc0f327baa1d12b7d6035a03fd31a1b7e9ed9f08a5d25fe08b9f1751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c373216173e65bfa2c619c4432b1009bc10dfb3af495f00ef1220fe0be2d0a415150bdf0f39e590158bd2614e0a7fe000000000000000000000000000000000c5efb0f8f23047f4470aee07e63ddc65c7bad54c001163de4aae5f03e5584137f603ab84bac48397344285ac927d51a0000000000000000000000000000000017fe23e4cc46615e24bc2eb4dd243c3c7eac19fcbbd186dde2646641339800e5c5b0eec1d12192ac29a102c32cbf575c0000000000000000000000000000000007aa4e74a47b7d0dbe47d8d5685745f1acb8035bdab63888402a018e7a8c242441ce375c568bfd6eca8c93aeedbe625a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1444700c2c2e4d94c0d612f6900d82423c4725e665760809823b5165abdc5790be920c27fc3ec39b80d646fb74635c0000000000000000000000000000000006b1d5073762393a3033e4e6ed6030ee19497cf9db86f020502b993da18e3aed1888eb53ec2b43ac92a78f77b0cf10bf00000000000000000000000000000000126b371f95ed69ee2a36c9cda90c94f77ff8d4c9b3c8661a6b9112481bb0f347b930f7243fa1e79c36b720c06efdd28d00000000000000000000000000000000005e1eb4ac90a1197015c742c8bc80a54e1a5fbe6bcd34fda52b2083500f320e6073891dbda16110235d85a5a5ff204b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000056d0361ef2f713a171771475bc84d2476f837019530b0df4186629e7f60c30b9bad5f022d213de07ec4c52f6e1611cb0000000000000000000000000000000018d714bf6f8e4a7394ee1076d4d4b99ee665b3ac23dfe4d6be37cf72f15882e16a6c9b7ec382e9cfff7ff3ba89bb243500000000000000000000000000000000194ec0f45278cc26883adc98707ae9034e3f895286bddb8a33824d1b631da5fef15ba2ae309f0fed790b80e3735d64b00000000000000000000000000000000006f1882ed50baef99619ca6c53c04b73e877842de023d655fea59c80a061ea2d264872c5e1f78ad10f8582d92d8a15b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001455d5376f953757729851c2b54b0469181afc88cbc0b8599d432122da820ff7814d81e06bfa498f3ed2c1c5a52226fa0000000000000000000000000000000019ca2171153e3c7c279144092d4e9dc6f67a858f40f66ea26ee637ae4589aa312c1107ad2604a8c4acda291cf41fd8f2000000000000000000000000000000001418deaf6dc21c51c76fd71d7c0c1a21480f729476770472c8d7d62e93a072ed2e7f734596ed2489cfd25313cc668eeb00000000000000000000000000000000128b88c14927d35b378f5bed440d1e5b9fb83854960eaab1a0cfd4446d8080fe384dd9fb4a4996d0f808b02b7adae70a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ab43ac49111f81945767ed9e858dae6be3d065fc39f0648237f07832cbf1ce128478baa5a8f000513e36010b4e9f210000000000000000000000000000000007ad77e8e31aa341f39bdc587389bcd33c1130fe4ac309f93de220f4d13a4d7a2f17bad4f79f3b32828bc5b4cc2fa2d800000000000000000000000000000000178592962510883039b8e536dd32e530a90770032ce14f3ab73f6b804c8e52dc7e2e6e717afce6f7a4119f1eaba9a966000000000000000000000000000000000fa47605933552027b8bac7e44114cd6b00f90d510b2b2cc6bf6cdc522aa2d6435f231ded9759529de44889230aca5201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001888718e6e0bfcff9d95fcbbb291a5d270d430e66c6f1d30a3f3c0bcb1a85598520e04886b33e00211119ebfe035721b0000000000000000000000000000000008b4a088592638d2f36a7217351a6dd76c57b7d33b4bfde09fb2e0cdcbce7dd06ffbe5c5c76ba1d6844503ad3d29e542000000000000000000000000000000000ddecabfac329c34fdd110a30043b9f2f21f60307648453bb99e06d7e73097fb840edf4e9b04ff4f25e013b9ca2a83750000000000000000000000000000000011564d38f5deca9f9c34031cfbef0c479b7266b9761f047c05e6d50047d7575802e727ed2a7576cdee9d072cd872b7c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012148440ca0d912f0a6402b68fe3a31d2f541014b9f6d8465962d670edb9482a57896d18d428317bb8a2676dd579930000000000000000000000000000000000c983600421e36bea09022fcdf0117d08c9a7e6f57387bbf2dee790fd0336d5db2cb939b2c7eadf04e17702ddb390d4d0000000000000000000000000000000011fbc2c581174bc26347d71af22d72cf725a6b7024a995aaf4857d464db17f4544bf61394a4a2c76bbc36cc89239b6720000000000000000000000000000000019c5facecab3b4f71edf675e0e74e218bbd756fd9af55b0c7c4b845460821d3eff4cc2d28cd8f0d681fecc1051ad63291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001488f3ac7e7e6a3264f6bea8812b499f09b869326cb81ecd7703af1775fd068ec5e551cb67fa339e15c80d66a50a199e000000000000000000000000000000000bb992f0ff3c80f5c1e3d055693f4a86ecb41400438d310f63f3db8bd106a9d6e383fdf8bab37852b31c63f8735e8077000000000000000000000000000000000608fb9d1352c66d34c1ead27caefcf0cc29046440aca78e1c70bda76180bbf6392419ff1c82049cc6fc306ed90b8b8f00000000000000000000000000000000053f74c09dc3cc6a0067ca5fc5dfaa16b6822ae648d4e8516565ef30c89e5d3e618f3e838a8eae7d4a5373762c123fc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025c4334c1dc4a2e9bf3f34ab3352ed5ce2db0a62fda1eb0c35359ea6ba094cce088c71f35b5bebcf8639b9480553493000000000000000000000000000000000c2281a34c929848b68394352566cd14dd2019542dff89815637898bbed8155bc774ac21e9f06eaccfc9316f64c67a9d000000000000000000000000000000000183887dd5f90bad6f03e362b7ec131f23ea1510c44e14c2ef3abbcc7f9b34432fec157eb1e83ed5f2b2cb66fd372a90000000000000000000000000000000001428a3282554314a7c08d4034204758b84a9e859a74f68bb19fdbeefbdea268cc176eec04db2e3b2ba1d3d5c0e22f8a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000106f59a8907987152b24d2e06b6544fa476f3ef59aa1607a6f2c46f4663e4ee180c734cb99226986389db5f16e24a48f000000000000000000000000000000000bd56287c531cf005a478b2e902acdf00611d80a7dd2fe3a4d8811d83b803ccf64597b0b306dd7c8268769c4f8d60f00000000000000000000000000000000001154483752e73081a2e810b7547c1fc850788608e1d9e535f4858b14cf2a26f25cc1f925da040d6ba8c93e08a8f63af900000000000000000000000000000000077b1b222af0ffaaf18f3b757faaffb2909c861a794e89fe4d176240a9ad7bfb220adaca9f87c3178c986a83b5b3e75c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001590df6fa7fc8e4fc1294202f185bd14050a6653d2229fbf80fa5af4160889c021ba06abc023e4041146291dbb18257c0000000000000000000000000000000001a3e3b925f86b18aadd329b4ee5c7b6189038253cb35142429d83cfe8e27da6c08d3142aae2498c7788f6fb38571990000000000000000000000000000000000173a95e7b82b260b356451b949f6818c94a34f14bfd6abea0588faf5bbfb62954cd36efeeef1afea83009a4660f3c790000000000000000000000000000000018e5ad3fa9e7392f29fffd5d8a8b9201c77fe56414782f40cc3dba1fe45382ea334265f334e9c1362a388ebd3462c5bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005559d24b6d99b28e29892ec08132fb34a5b776d761026e9501f7f0aa70dea13d233ba78590133cc0e263276ab10dc6c000000000000000000000000000000000a3f9eb578d2a5e737e34a9f435f388bc830b4e408740b2b6776d7ba7518daad0e37cabd4266f2da1aea0a44ce4c90cd0000000000000000000000000000000009fc460c171f54a6064955a27b2b559e6c96e3e3bc586ce1adaacc6c3ac09c9ffd027cfdba522dadd2a92dee37dea54a0000000000000000000000000000000005b05fc30a6d14e36c9bdfd07fde0db8c002f24866ef0ffae195f6a56c8e61f026770bf08e119b9b2e7bb63dc16350851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010148761dba4ada506400d62f873df235cf3fcecc858149445c08a36f73c8a0b24c71a5f4339152efb64e765cb151b1d0000000000000000000000000000000004bb6836896e065afca43fd8fd8bb34f470a3dd63102eb01ef700bcbd084625967e03465895142b102ce22f7b763be5700000000000000000000000000000000107b5c3de487d6e22eae4141e4fa6806a6f34ff7895d47926a8023c078a03ce52d2a68faaf692a4b79a21446c2d85aea000000000000000000000000000000000cc0a79cdf9cd11421900358413d16b9b3cd269fd784d0a0835a7bdaa7cb1bd10c675352059af7bdbcc1bec42b21339c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118abf8d965275a6229d17e6b62a4e35b3d3ff078592cc1d76e9f24c9a2b2dc3aeaa75b8ffa406e20c899b0a6b3966f300000000000000000000000000000000192e9cfbd3e60ed2e4f962285c17678f855e16c5301771d2745eea8b069a31a9154860ee77968f5b355144c8fb25ed3c000000000000000000000000000000000020b223adc51f9a62d1f51b7723b837a8025076d6318a4221fbdecce8cb6abe297601d4b305cdfcebcf3f5a8d3a38300000000000000000000000000000000008f14be65eff387e98dca761f66e91f0219bd98e87d4dc42daa6f3fd42c0d7b73a7b358f5e2afb06d89af9290dd5bdce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145d007835d6d1b37e88e301e1567987312e3708f5fdfeede2b96030dc871e442fe45f188a027b214754aa7db707f1ff000000000000000000000000000000000e2c098e63fcf1de15be8b8c2c97819085cd4d949415cd470043374f71127b9a77f9ef8909c47ef0fa74a6c73b2e173300000000000000000000000000000000192bd4353222a6bd22f081a768e6bf23c4c8cddc85f1185dbf0100c9a08aaeb7b8aea464a37a722b5fd4e013ae88d28400000000000000000000000000000000184218c6ce4da2c8fadaf539aa776574affcbafc1b096fb83a20a57a928f584fdfff1834104f590f3c43482e52a748551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029c4a722d92fa5428bb0806321c9cea2043b55de07e47e692e476e4c7acec3786b83dfc61d812253399d3856fe796530000000000000000000000000000000000f7d8390cb1da7367d245a655b1fd2c46255bb7c2ee4ee81d1ef959163154b980001bc40f0f3a16a8a200ac423307070000000000000000000000000000000019cd2783201bc606f6d8f06ea8480d11ba0fb2373a511be2d8e15247c62df140d2a99fa0c285adfeacd8c11e382e22750000000000000000000000000000000000af5ca3391c1cf5781501237dbb0d111f84b6325e217c5bd255a701dedac5ba52c27fb14d34f9d7e9261f35839126e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000089503a2f6e76486d5a6feb2e46fd53d3eb97539327e03360c5401167e2de33ad7130cce65b25e3a898b00b12f0fecd7000000000000000000000000000000000328997dd3edae175c47d3b0a59046c97205d7565586c09431f7f2e8d48136c67db03498ef6276c578cdd970a63b873900000000000000000000000000000000042392927e1159f7fc371fd15cb47ce534253f4902b08221fee9e4c6a57e87d8ba71d3cb5fff99ae11cedd20328153690000000000000000000000000000000006eeab2bacb56ab57daf95d03a030f497af1a6f84a33ccee57d9aa1065d496d054519a730cb9a03c21aa22f089257db61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001219e12304b160f2d5d7ad794af0700a9b05aa2521bff9b7161d935576d2d94329af954d07df6e464cab0208e64e553a0000000000000000000000000000000013ec3e1fabe23e08c543871ce8ba7aa682f12a857b6984e56ac8898be44c213028e320eca9eaa1a04ac64a3841009d510000000000000000000000000000000010d632d747a3760b060050c0ce3cb816ada1fce8ba9a228b6b427846a8680d6a31c065b521c2bcbb1e85453fd5629ee500000000000000000000000000000000155a76cf41e808e36dc5946ba4016c14a0f1b55fa3e52ea69bee3af6547c39872628363c57b148fde707fc67bb4da54c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb805540a2b017b3ab7a7514626784628d6c8e2af0c2e881e6f48f12f69662a45fdbc7da18a2ffce52c9d8f702fbe7a0000000000000000000000000000000008b37676cc30d321bcd50525a86363a330e36b2e02a00a882d8ff7a9a8684fa9f47076336a00b3d4a217e7e42ff3c5bb0000000000000000000000000000000019275a296cff3b1595725b57be0a2192808576395c5e2b33981f3c2f0da24699ce8190e459e22b62ee5ad66ee3c81d3b0000000000000000000000000000000014934d0b9c2dd1141018c3ee89e5e183baafd0144f3ca5fccb79b932989cb2245414679ec57a88cb74b8224dbc3958fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d4f6f982f5a24f092c2c1bd613e7b1a8c22072611f5a2d9b89f54415edf81070a30333bcebf4d7d65284bfe716b6a0000000000000000000000000000000000af87dc1fe049fb1c739513b4a9214c0a9e62a811e2e0b58540faea2bd73cf174987e764aa3e83c1ce78e2cc8cfa4ddd00000000000000000000000000000000021b72d4c6b4d84193aa47e41899bd982ac8051e76e7203ca10bdee2b941a4b941c04b51dfff170691e62d99857a377d0000000000000000000000000000000003292ac965b2e6952c4442f7c8927bd042b9acac4f41befc047e572f39d85eeb3ac42ddc064734a139a317132763a0a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7cab94de09818e92d50a78da93b7659e46c855701daa95fb435dd73e289f388ba3bb91359a504a4eb577899b6604c5000000000000000000000000000000000e868c81096d55d09d5289def0b9b788994fb9bf4a47d3c15c5a1a4622b2dbe071fec69ecea1d0a8c82af19e05022989000000000000000000000000000000000267233c3050ecaee9a068c58a710927cc440525f4dbb8b3f8920e11cea0c6caea772817357ca9ae510cf74127112110000000000000000000000000000000000e37b9297f6bb78fd6f7ee47efb5d6a27107e73650d3aa96369a666b9a72c98f3c0a6515d280aafe04e2a95da7ddb62d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fea85a96b12b300808f25892c060a72b52dad197705930899221c6a321e0614cad478e09977598341751ad566ad10cf0000000000000000000000000000000017dd12c8e43454363eb1590739d36fe2d9fe223cee6547a152c19dab114092e83bdca6a8c912ba64a656027d97cb32550000000000000000000000000000000003fb1b0a6f08f2f03bebc687b77903234582c808179aa78c1ec160ba76d6a662be3feb5a07588b01c26a370ce8de2ef300000000000000000000000000000000190a14e84d1cfcc0fcc759fb58e700d46d6228970ac4035067554a4070dd9a62fbd52efe025dd8ecef50f0cc53dc37f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000445d7d657e12332b549826b0138f0c47aeb5f50e6f68b6ebc69999622f12bb98fe494aca91babf125562c694af271050000000000000000000000000000000016454090b9be3f3d4ca511bee73e6abebdf81ffc0cc6b1e19ac3e584273721ee006454e0e16ae951eb9d1196a0f69dca0000000000000000000000000000000001cc3df73d05ae25cfe5cd150c66d73de3e2cfae2d3e22c97534e7552220a85a8ef4e9a94e3c74987fb2cb0e3fbf767000000000000000000000000000000000070c5fee39070cff04484b42b11348f950888c492487d101bfb195863d5f3ec93fe5363ebafafed19ed790c8465bf3431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf5142432565c7bb2d23abcc79f1c99ed3ea6b03443a0617dfcae19247c30f9e00fa5ce599b26cd5650aacac8d89405000000000000000000000000000000000180a64ff5a58f505520f62bad618ad50cece1dc4f7ece679edbf688ea597bb31f7e363fecbfcc372ea500bf1c2dcc960000000000000000000000000000000006a9e0e71829899f7b4e93988b760174eb816bc0b8c4040e492658ffa4d331346871f2a0513a3fd10b40a6dc9b6c044a00000000000000000000000000000000099a2f0120cf4f9e503113f8070f0424cebc5f8146c8f44f4e21f09f578d311ef6215bb39ae90cecd17b4ffefe32a1521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000118b97ab86279e157377e79587d93b45d6abb96db28e90d78350ca5e0434bb2b40be33bf68f32d220bc25377a43907b000000000000000000000000000000000c3541d8ff3c798988deeabe76baa8a33ef8e42cdd3c67e24eab2fbfa3ada4bc6353d1ab6fba100cd3d66eedf5c8a88400000000000000000000000000000000156d586569063d4e2c15985f3c9f1b5686d71772e02587cde456bf8c08ab9556aad7d3ca30a155f171923c6f6ae14fc50000000000000000000000000000000004436bbd14611049c6bc011accb248b798f69aa3a130a799fd72dd510f7ab2e2db850b60510c68b828c011c9c229e2411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018ae33f2cab26332f89c8ffb983817a6954c88ed60582ab84936d476ce476b29e6da25e770450403b85f257d61d19fa000000000000000000000000000000000b07df4bf883a70a326095cc7e289bb71ee13936939b7245b2b10500d34e9e2cf07d334d149a4c503418629855eee08600000000000000000000000000000000084c8ec19b2c62155a3a3d595615735a4960c0d9a3b50c06d464de088efdc45f7bd359c5499cfd1046abf493a047f5f800000000000000000000000000000000040495e7d8e7e9726c880793452c80ab5583c539f9f2a05cbaf354b702e74d0f8a6aaf860597cb22aec455e38dad0cd01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098c1ac4462089e04f53c4c1b6b9b380aa92e0ae6d0bd189eabdb94db6c53ff0dc0485397e47ad1ed812aa20a7cfca84000000000000000000000000000000000f51b4b2cd49bf76618865531bdaf018fdd42d5a883d6aed4abb9866c8254c1e5aed9f6c9cc1c085e0fa5067c4cbda490000000000000000000000000000000009cc8c63a3891ccba0bfbdcb72409d933471f76518b30e709a87e9db47737acfb0a399f19a44c99e6a22b40cbde3958b000000000000000000000000000000000bc46fbd5022780a1862c9b3bd73330f1b496c33e8fe7fbdbb3349a1fa2617fec38b0720da4242c07835bf3f2cb739c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed1624555d62e854eaddd66c65bd0c5520a8f01efcc08e1ef76da1c0a42a68c6639e7249b7e0324e86e2a55407d61c3000000000000000000000000000000000fac774e6a9736aa09138b00b08966bf0c491bf0e00dcd45d750015dbcd93b1a1a9d95815fab6ef7b293138e15895d690000000000000000000000000000000016f127cd5bb2f055e738351d713379482b2758f21e6b38ffae59c74994ef327e51939f89a746f65debbdff5cedca23c3000000000000000000000000000000000b34027a1947e4aaafddbd47981cb504b85214c89384d8abb3fc7c17338c413c94aee995d76b87efdf1b486e6fe6f9a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c70ddec848fa4c3ebe8517f614c9ed8889d9c5d349295b81ae8d0bf5bba3f34e878c9ad1b2d23be5c73d03e17349a50000000000000000000000000000000011aa181f0714fad33823d3932d9b07cc1d86ae31959a332de520e685a7f05c317ce7ff0739af78c30b5bcecf03b82e60000000000000000000000000000000000f0158a3de674f7743d4bf831523a3053a851a3fcff21f5212ef43a2e2a32be0bf5c3200ba3ff623088a5b50c3b457ec0000000000000000000000000000000002b1019978178a49063222109b4ac92beabddf1768f2805e6c3d2f8e8a4051a468110d3782251331a5399e94f43d57a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad7012462ecc64ccfa21a7f38f6a4c2cb73f72b85a1f60e824702da284151a87d3c5d6176af15b3e231098887221377000000000000000000000000000000001458c575b6fb43514a697e59305752f005abd92a50088867f6ac3328d61cdb66729c8acba780b7f5e1dbbd6ceff72b4a00000000000000000000000000000000143837e6eec33b23b50294b25eb99f8ba70459f55cf9c4c29fb89c70d3f8f8c69bcf3022687f7fdc887145819e633c790000000000000000000000000000000000690676d5e3293abda1edb565641519c6e052a84446eb9cca60e0ca61214d01d9c91080dacc77e92eb9900a933b7dc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c103b1d585bbdb1374ac1915a2056769a82deb25eae6d0b3dedd7023d3f4ec638017902d822d7e11009eee3c361eb00000000000000000000000000000000003de5b171452c27c66a17b9b06cc6dcd90582f3acf005a487c8dde60a0da0c1a9eabae9b078e7bb6685326625c7983060000000000000000000000000000000014f3a8f6fb65893cedaecd91bf97c436e3c7f3d515c20d160ab8a407e14d4613a21b906cf74cc63f4af5fc0d34eab1620000000000000000000000000000000007fc0a2e72c524b0f17e48bb17de67288924bd1286e85cbc8b42f6fe73d3311b753a26076c3ad62968d2ce929c94f2421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d3ffd39a341fdab36e0c3435d3ed1051d5269a5f0b7b6fa430d72e7de0a79a454dc68d098fd648e684b69b8ad59b5a0000000000000000000000000000000017ff7c02f11292749f8299fba00c82c8720e200f3b119e04d5bed67877443d28d79bb23c417110f0496e1257f73c5b4e000000000000000000000000000000000e53c6688390c86b74dc2c29afd4d853a9265c58737135eeb10db034bb233a747dfab6a0a9569ae494657f260afea7360000000000000000000000000000000013d475b4349cf1635a8ee6c5f81fda22d183a1c87f9aaf1c155b598ea08f1c94c30b9fd01cf10d0af87b5882dcffc9951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007698fd918e02cbf27d0f67c587a2394268d29a71553a2b68d21b629cdeeb77bb83f5cc05e264387e57237f592f835a20000000000000000000000000000000017f60f5ad4b8504e33989a9b139ce8c8361eabd0ff10ec77c777831c38d12e7544fed6b392310dbc6f7b65aab5cfafa20000000000000000000000000000000015d402fb6640583d6091c374051037fed0aae24a8f105548779ae9cc9abe95dde78a44a14e54d83bafc4c0b2df7014fd00000000000000000000000000000000187eb5dead0367e3e5387ea795fcd4c82b4b349fb9c19537feb5c67b4979594220884964505ab9a34ad8bb659bf579331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a16994ec5ed74a8bc7d4df0fa6d745addf40deb79d886065556581908204f3d914c62371dd05c08a9f4730ac1181f4d00000000000000000000000000000000103f6a92ce2c3e1fb12b47d46f7f8a24e895c1ef48af26df066f71b94be8b81468a62912673d532fe1ae9cc9277dec5900000000000000000000000000000000028978b42ad0b929ae98890122581c20db193a28103b472b8a337c0ef0eccf4b03157314753bab22b6894e1eb7895216000000000000000000000000000000000e30470638e4f7c5f9acbffcff5d6a9ecad746c2160e1db09b349e4f8b52d6e93f2899a4f00bd595896fada60bbdce3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024b06ecf1a79a587780396122fa407f36483272e265abd577e38349dfd627c433cf55f14a5cf2f86122d394ccb330cb00000000000000000000000000000000108ba761933bf2abc8e0f8ba0a8b60079529fc590463d25b3f8b69f31f1deee0200dda237f05a9e44cd480ec3104034a0000000000000000000000000000000008b509a6a62266b0faca794348adc435977149bb1c8a676b3f5447f4f441363afafaa3354f589ba9e0f8ac3cc6bad6980000000000000000000000000000000016b1961ead0f7a684a41cb6423deec76240f6b8e25f86dbda3d9dc398cce0c4c734e5ebbe23b9390d9a67ea6eb0b0d511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d6f4be5e2e7bc87fe2635f58b64f40a5e3824421f3042441df374e4ad592122e765c1723c5df55af952ec43ccbc38920000000000000000000000000000000004354fb79eaf507ddd913f7d22c8c6f9788eb709497f392820d0bd2d29bf5902f62702d3db0461cd078489da4ed0a3f1000000000000000000000000000000000951e2dac11df138e1bdad50f95ebbf07fda31db0e5880b66dbd358c5ecba7781a3b5a75277a1dd8dd1bb89c12aa8d930000000000000000000000000000000015f1646b3093d159313f10cc5df1beb38b7336e772e1403a2b59b4b6ca2a1e7f4447bc9816638503578674b6027a33bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d71c933dc5dc3b49843e6cc0a8659cb621b1ceaefb46e54bd916decef3598f6c24cf53cd520afb8da964b39311406e0000000000000000000000000000000008051472975077a123c20de5fb1c6136919f34d09540715af9fe926b142e061b931d81bf07e59bcf0d96c0b6d9aa51b20000000000000000000000000000000013b0cee58129957ba87fd87263a538aab45e38118aba23fd936b450a1254bc2fada25f33725c4bae050ca2079b5de35200000000000000000000000000000000042a0a8e30f7554a5407bb0327d4f320e7f37cec75248d18c9fb6bd2681024a6f71655cb319ae2588ae9a38f65fa95171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001bffc66d5f8be4fbecfd8c2f681be9a8b0fec5fb8b6e29727cf35167489bbbf994f38b5db3b693f8902ad21a76c2cc20000000000000000000000000000000005a09c10dfbe15d15256dcf73c1c6913576861f1fbe9d23dfbcdc62971438345385103b1c621141c928f0588b497b5f900000000000000000000000000000000141c70437c4a1ddad21ac5d8ea3a4c44468a3da4c71bf250f759b094ab652fc5b4ef9dee94d6a215f9c1620d7231373b00000000000000000000000000000000127ce51b386a00d1db60fcfc087daa9447d0fbc0f2c894f8b3b0a853d492713c073da1422090d4a5a0c6a6d16a6485f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e33681fbfaca9dad75d95f02d0a2f2c0ae458675f1a5d8a242b657716538b327f464dd67d5c441e43336082264f4817000000000000000000000000000000000b30970e14724178d5c3db7521103eb7f63a28b5222d3e9dc54ad456f698c88d5106e017fcb87de1570c75d743bf7a30000000000000000000000000000000000bc4d1f80113580f4e7ae3addefdae0c8d9ca2fbb07a9b50f01e435cd0217026a148cfb0d6627d78b995781157f51d6700000000000000000000000000000000157fa23d6ca8db81f46fcff9ec6bd9a55ea8ef74b92b8bb825392e843231c439e6be414cd61ac7d942525daa82df4e781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebe1fe085560e6cec63df2e9be5e4b93fddc0d9f2c106cf2bb090a6140f30dbd750e573f828c3e9995c47aac23e494d0000000000000000000000000000000009918e777dd9d2a862e842b35d610ab5e18131bb9db600a352a8be1404db5e927f5489dbd52fbcada228b940b7d05d1f0000000000000000000000000000000013eb8fd8e3a7ee57e43393b3f04c00b94003aa0bd303f6f9cab56eb0a11aad4f3febb4b851b3a854668d6cd1ae28e95d00000000000000000000000000000000128e836ca52db8703e0ba1aa225be766c866858df0e3d6faf9385a6b2336f3a027b294ca67cb7c9c75989398d02a361f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130686df1ea7843cff4dc3df6beb1cf53b51cc60895a292f77076b006d5f4dc0a902216567332c7f0952571eab09f4be000000000000000000000000000000001508fc91d30635bac7a8d98dac54e8967226fbc34547c6e284221bc75880fa8ac2f2184005a4be2ca06b41cd587b508a000000000000000000000000000000000d4d81edb5697e2e55c89ba3edc8c5d0155de81f1aad06b8f3765a91f92b9f51a2bb51481b98b0e5f50f66ffef2b0d4600000000000000000000000000000000186f3017bc3057bca6e168309521f1f8a6e94005de3d84e1d63f329ec1809327eede1424784f00251bf7f5518595776b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd8a1f7a0d6a6cb86ab876a2140ace1604f81d7df839c50d70b86ce71ae695bc1b531559f1220c13bedc3628a411fc2000000000000000000000000000000001416f6e7cca8f3408831957a64b2351b0b43ba7542ea21d2495c5990c5641315197f14cff29daec0bb5db6c608a38e6f0000000000000000000000000000000005bd126859dd60b6fca78d383556003607e08abd0ca52f7149504ffe204e4101d49759fb0f32c982fcd3c205f32c0b7100000000000000000000000000000000046979f08654aa9411aecf99580c5b07f3192bf5ced8e55a8e225cb9ad021edb3af7744e939be339d7c39e4e8f36e8da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071159f89a8b3a02906941f0aaf002dcddd336b235b531a9cff21c1e072073cba10ae3077181efae0acf0ba2f2202cc300000000000000000000000000000000120e0f802a66aa5e9b582fb0ccb60878e1f0433ccbf2a2f88d2c7d9ea0fe61201d6213ed2f854b17216243255878259c00000000000000000000000000000000136148759086cb411bded88ef18e1ca0574a6b3bc766e3f4e826a21f39b6da4de56301192dad4e00c148b191454f0a860000000000000000000000000000000018bc6cf50034eee58baa3a8ad1a54dada9e7ff4164460435e6c4592db53d3c60d635f27c5bdf794f52138d10bf7a4a5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e70178995eea1097369b7868656d24ee7769648d874bcd37484aa03c67b4126277ad480d28a820c20cbf6fa73e5f04b000000000000000000000000000000000adaf569491dd6e7a7b44ee30f6e091dd5c27850811fd82d267dffae514d2c8ceb68990c38b797d66a1f99beea3a3be00000000000000000000000000000000015c4c648991d5049534eb1a008149b869deaae0bc877d7b09f27bb916ea7bd431170eef3d4d28d558e68fe57d9cd371e000000000000000000000000000000000e5667149b1e9420dcc273a0b9309ed888a41163baf627d55cda6a826fdf5538055aec3bf149c284fd64b60e231a6c9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002608976378ec8bd9cc7c0295d67c18a3b46c479f2268385e92efeb1645c5f586ee258d8b38d415bac5ccde0adc2a01d000000000000000000000000000000000c3d0ca717f1ec16c9bd1a8b61b99448941d75f38be423bc5a1a3f26f9a32612fba6ed942a00c676332ded0577bd2d300000000000000000000000000000000006eac2a41b22783bc665f4d05e68e386ada295c00e9eaeaa23167a8b5b4888b925c3f2a9ac3164467b499ef77eff5f430000000000000000000000000000000014d445a2fad739c2b5dc5dbebb5cebf02308fd87d8d5a5ed228c174d8dbcb41b8fe876cfd04cb1f4146be1420c2009e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018943335cca4825575ed886566cd3efaf6282a39295b7e376a58daaaa57571134bfb36ea0d19a3d0cb95437dc40b3a3a00000000000000000000000000000000176fb128d85a741e82b72e182732c8ee8064e4625ec743cf675c95f2c3dde2fc89b09e26d260bea408a6833f8d66f974000000000000000000000000000000001987925266de60ccc4a2ca212885a66e9e09987413c8c8b3e2d7af71394b0c40d059d38ff17e2bd8ce6decb2daaf0be30000000000000000000000000000000003fed60acf0fd62308eee4155ae4344926ff113742ff975e89925838c0f9b1bd075983a4724e60775264e55e1363667a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dd19ec56855801d0a0ba2d50eda2b17905ca6fa183be5c7ebd4b9ba2c5ae7a5445e378492176c92eae1e717aa88188100000000000000000000000000000000055cab4dbb6c8635b95e4794a1a6d7b7eead9beac6ea80a6fe885fc174744077dac552afcae981069afe94d87b2816bb000000000000000000000000000000000db9311384e6f983bb75da4d0cf191186f3dd22bce3968dc4d38de07f00ab8d08edc32b015fb1b724189242cbb10f18e00000000000000000000000000000000009be8c974b772e3593086fc429c40e0dc4c5fbfe0b1ae3b29d98edf975f825571f3fca8a3fa6a4e1c29c6fe35ee864b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188257dc1f3b93621ee506da5519790912d461bd624ec515e0f611df97431ff44cc5c0bcfb0379ba707b1d2f232270210000000000000000000000000000000001e8ccb33ce64442b166eb1ff4a710fd4f8604a4af9820590a274d5ebb204b9d2c4ef25ca1e776c79f8a06c3d74bc1ce000000000000000000000000000000000a7217e53c5e98ad07c30f15037beae626afa2b396cf679d0eed440afbea745d124cd352bc099f6b62bdf61a5bc15e010000000000000000000000000000000019769842bad8bb905bfbd787c5680359023949bc03d67135666e8b7c88eb2a44d486c5706dde88962dea791f5125fc1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7f6ee7b57e45163f18e5eb0de457a3df53a1e5e62b81e12b87fab099b022e0d44e08dea4153e7d9f02c2789b3df2fa0000000000000000000000000000000018e82f6683bbf6faf502e88e6c5fb49f1f04299761d9aeaf1f6cb6cc15ead042d7b65f261edf503122fb96f5d19fb13a0000000000000000000000000000000008e8898f68ada22262019ff926d6c5aa6c16ebcfcc0d326cf5ce8f2c211cb253b3faf7f2aa31d0e3a32ef76371c84f3500000000000000000000000000000000062620bad9b4f5421ce177b0fe758faf0c5d404cad3ba2387d711ed6bce9d91fbf062846a1dd63d548431e565fba6bc81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000968e7834b782aad8c38a570a98172e7234c0ea09946e5dbf81b78a1fc8e6b7e897762af504f774dd250c4d5bbebb9480000000000000000000000000000000014d4d7380be984e0269edc8be18f7a8028f234dafcd8c6690392a7e56d6797ae7dce4dae2848d2d7cb9a20b5bf46b90d0000000000000000000000000000000018b68cef920fd129748369cd6967d72d53b569ae272744db405e70baa3d9c942de536c9c28e640999bf0bb00e153ea130000000000000000000000000000000018466c3fd278b30ab4551c2d7346a87b6c3c8abb778e388b18684f9051aa9b797e1f87607388d35dd3b18c4076a7a6ce", + "Name": "g2msm-64-jwasinger", + "Gas": 639360, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000011bf95ad1772f69ad45ac319a445e66408f564ed3daa1c38b617ee03f649f85a099e7a0d73c7fa47baa85b6cb775b6e600000000000000000000000000000000021cd661e557d8f48a7bffd200b55f235a3f004e10230214bbe2be93da31a2f14edb183b68027df610d07105824ba5fe0000000000000000000000000000000017ea617f4622808f353828b1b80a1ea192a4c0e7fcadc9729e88516b4485878e9221353a0f4e83ea32dac98971762efa0000000000000000000000000000000019ca9fcdcad78d5582b52ce9d659de99b7745ed92ef709daca9c4cff3720ee67e84a2b8be13e3ff943944915e4bf70821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000183d05207ac96afd59de75aab7126369244bf25d579a1aa9118272e3412225537515d20caa24801a4465165d3206b66f000000000000000000000000000000000b237f18e6abb7eff816b95ab7b520c371bcae2fe0b3fb2b497ea93fc9821bc2d821d4334b1bd50daa0ff4ba83582443000000000000000000000000000000000b4d3411c277de9c6436dee21c1dec262ebac011861c57790f405671bb103f92bb544a70f68d696d053e22cbe22959b2000000000000000000000000000000000eb9950966acc0a75ff84646151c2bcf0ed130f5cb4735fcdd78e49567ee94ce5c5ee1c6fbc2cec5c5e25216d31ce8581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f818f9305781aa9ac1f2d5747473eb498c1ec52cf6a04ea6850b6d4932631a32fd0d81200ab72b42f72440eb5407f90000000000000000000000000000000001e16b86c72788788152815091e905de94cd7c4544634b5786be5c9c7d548f0b470e8b2704694ad10baefb825945fdcb0000000000000000000000000000000006d22fdc2e0195cf84cc7e1beb4124f197bf294bb870ffe59b155406c9d4061137152afb4cfb0ee95a328f485a04437b0000000000000000000000000000000004db1b1dc6e48b7dc1d4e6483db63fd83f064e53ed49e369f7a6f7d7d6f2482c12b8ce8bbbf7a7a1d50ec85a0e0e7e421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016181cba8431a6a6ba44f0ac2027aa758bc68cfc9c81de414b5382efa57dd2a222003c70825a97a2768ea167451fd0c5000000000000000000000000000000000e22561c73c06767102e03ade2083ee34441ff1f5222f5dc170b5cc665703af8926568e46e8672ec9a518cf87332b7400000000000000000000000000000000001d96bd978693dbcd0b3d193ee0930ef8772773f644e0e8002cb600d59d20a2f632d2b99bc22624ce794f92f9675b5c90000000000000000000000000000000011d53975075b9a9ea263da477138d597938d26eeab1e61591543957edb8407632900665b5e2da92192d8e0637d050fa51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000528b8b49b95cce73bc630270ce3878d80b17e14de2f6c15543caf4246600069925ddc3a88715336a70196f63a0260c70000000000000000000000000000000005b2fe13feea37070faaaf0ac37b9ea86f12925f43f0407f6d20ac324bd72dc0fb17a80e723a20e6d52134084ff4533d0000000000000000000000000000000006f7b18d990002898e98af11b7aa4281bfa76fbec6dd0412c58db4d1ab40ca763cf337c78bb39b228320d0ab58ed2de200000000000000000000000000000000163f2c6b661830c103c69a21750bbf4d0624d62edfa7b272f717de925dc88ce8735f9231b34e722008259ed01fd8e8491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d3f67b80a7ea1dab0e0738a35d3c93940520588871565867755ef1279b44d99d9f228caacae8d110e3d7e48f222d54000000000000000000000000000000000991a65a302543152d436e398863e5cf78390fa621fb1ecccf3e27cfeaeed08df571183f238a18243ea17c94ee16d8b100000000000000000000000000000000095c56f87d0ac73281f15793d98a388a6ae48aa3eb5a3d2e52f7a0fc2c6ac508a792526aeb54ef936a70110a3c031b38000000000000000000000000000000000a6e112510134ccc1e0eed83d958b2dce2fa8e3782077cbd418369095e37480e21bfbb5d42dc8e23d23702c5cf3b4e7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017df7be5dde1a88a02c2d41fc0ae70306fa4d43419223cf8bf688bc69f1410b986a7c595e9a7dc350e6abebac45d843d00000000000000000000000000000000036f844b7eb9375b73eda48a93a46ba6f6d1d9447681817c859454382262b323015aad044bfc43314462816e4f8408000000000000000000000000000000000018e2d590bb7f4f5afb796ec26175fcdc6b297811ca0c839ebcc6e7aa3fbe7e31a9cdddbe3014b14d17095b8b1be9c89800000000000000000000000000000000154c986ff4adf5da8c67a1d9d3cb7b72f33091f44ecd143cf08a03bfe2b7327e4d8e062076c9b837924f59a5120ccd421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005dba9d7bf522c7861e59770e85c754826b6c0a1405581f8c0b951e395f12e526189ee280bce7335d9fa600bb6e4c0a10000000000000000000000000000000001e3b35f5b9841c503be6b78531fe35dfcea0621200b98631df020877dd07c464988fa7394b006b72be373337a705cbf000000000000000000000000000000000ffb25f224b9398347fa2aa6c480b0f430ed181804a89ba557b52aba392a46d585d180c0ced63b63fed2aff1e974a20200000000000000000000000000000000165df20728116af2c43d4939c9bf9d574c206ac38a4e5bfc83f74e30a3f7334630171e21f7a435d0dd0f9ca4412f8ebf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a9caa935578255067a7174973e0554aa3a19b95929e60c4d9dc5c6f16ba9c1cc79dd7b708e1f3d2a876d3463a8e3c90000000000000000000000000000000009e7cf8411280bc0193b0a731be8102d0d859be09bc9f209ef1528d08dd72a1ef358a8c3ea5aa8c238951b9ff603e6f00000000000000000000000000000000016989f0d153be7bec06f267c0f05dcdd40d78fb4b166eba9e3a6ea713fdaed4b5fbbc6a22cd905b9c50f6ad9039cafc100000000000000000000000000000000115ac4aac8100852d3e5a0694210a47f13a0fc03d3247529eb7f9c631cb3de95aed6c7ec062d1609ae3e6ef6bd942f571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012f31134bc1912d49dc76c721e2ed2da1f8b4ae0869509d7dae4898a971cd2dfb9317f0bd8482b81053d2fac12bb55e0000000000000000000000000000000007cbb903eab440c287518e1af691220c6261879106b5a93a00521b62f0cb9de25ee537125a8bbf0c411c4b353ef129860000000000000000000000000000000007d005d2afb9df74302cc74383d0252304e3bc8c97dfd74b199a6ff66ebed449689aa9e043548ee3c9630975179bb71e00000000000000000000000000000000184efa9721d267c93dcb18e28d8c46efe05bc940fdf04dbc7de5ba6aa8a6365a0f9509dac55c4243123a01312b79c0261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3f526772ba81c522a45bd5e6177e30bf50d7e95abd1e8ab8ae867d7f3a0a454bec9304fbc7c0a91ee2bb5ace139847000000000000000000000000000000001134ee079e575481300539d0d9815e8b2c2e7e255a15bf7928c11139c1d34a1f4c977a9380532f8940d5c1dfa6d2b7a1000000000000000000000000000000000a83a4b6925852afe2158959a8022e40cb2d4cf980a2a96675f657eb263b42faaa18e2917c24d2ec3d382079de47993d00000000000000000000000000000000030c559fb1b608433bd824a26471711dd7cee802ddd5440f9aca4ad4bcb41097b47ede09f523e02c785a63a0102b9c941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001799796f61018d14d6d87764b0ead89baaf8d7baad27e8654b9ddad269e93928e62924c91f119f05e6420d9b1ad90b720000000000000000000000000000000004c99dc947e4e907a15758d68e48ddd4992a77d4e8288f0612f477323408340c2086e1beb3ea2ee139f2aa6472b3f08d00000000000000000000000000000000187445842a928286f67fdfd7983a775d88cf0c33e9dedc9b1f5de020415809123221e290ada1466e47489d17f9bb490d0000000000000000000000000000000010a169368c6222a06eb6c427e02be4d1a98bf3a4e68d59c3330336a0dcef460af33786de7beb9119cb202444fdecc36a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001032b846395fbd00575eef388436d9667153141559c11088ada3b632c2e821feb3d383501cdaa39f5b8bc1f7273fe62c000000000000000000000000000000000b77ba55af6021fb5482b3ceb55c6f0595b5ad7dc21c2eccace0abd6044f90988deb6e02f8c21cd1c60ec47f55eb0bf90000000000000000000000000000000007eb939057991684219eb08ced81f7fc07e1c2e5d77584be74dd6e7eacf7f37b4236f45c91e2a6cff5f8c37da002571c00000000000000000000000000000000131f788b2be988ffda7ed22cd52199b3c287ad44f9baa2fdf7f36a7bf875fdd2b9336d0083a864d8c93c8ad19d1052191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198f30186cef7b4412668e4873364e94bf126dd00ed3afbfd65c168d961cc40f46372d4c996a12d4b83c1a2c315e18ac000000000000000000000000000000000e8c5af02e9019849426957ba7d11272708879643644165b3eac74b99a70a071d5f287bebdb8f76693fff1017bfb5a1a000000000000000000000000000000000012e046aa90badc0cfb78adc0d06d6440860969fbd884395cc3887eb9d2829785a0184cc2bf812fa9cced0590a694b30000000000000000000000000000000002fd0481d55b95a352579b251a41d6efc5c5ca2888b221b9067c57ed7d64a241a4aba6a2fb72d86c56a6596107b9dbe81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ddd58d0a85d73b8a443b76aac1ae70efe56eae01e8f7431c18f28b95341f9f0e136171f65dfd5dd2185c88ced1505960000000000000000000000000000000017064f021904c483279aad0e44627ad492e52482a57b53f065802d4406d19e91bb488a6eca187f904fac67d5030902bf000000000000000000000000000000001370456afdb9dcf3bbef4a9e5747b3ccb93e342775116f54b4826bd8c90f6f63a52d4b0b5f1582d8e650a9782933c21c0000000000000000000000000000000013d318d0cf0955267170480a7b69b429c49e8ac7ee3b3389f360229cef394ff8d80460369a049351149371411acada8f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139f8702b8b767db78da045b4846e55dd13395cd49df355e53cdd4a0e39734422b9d9a7e778f71850f14de459a989beb0000000000000000000000000000000018c2eefa8c6d35ae23e12431fadb12d0a48a2b7cd5902ffb17cd84855dcce4779aad3c7a4260397177b23b3bfdbf49cd00000000000000000000000000000000158c0c849d10c5dd247fe1e8ddcf3b364ee8d27c7da5de8cd482641dd225264f8652815e28ff464da2fc3be2accbd427000000000000000000000000000000000438e0a810626d58cf92e85c365cfebacd6f9c503b540b3432d5278de8f8ffc22a5e6c822e3c49a1e8076ce3fbed5b511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e0f28dcd092149d1ee75ffb1d248162909de3d4ccb434d24a045667c7918b860ad57f29d26137739d9db7adcee000b00000000000000000000000000000000060a0281668b98e6eca3fb0c66f894cbc5af2788355236a8dce5cb4e7e7b202393de4787f871eece9b62a88417ada91e00000000000000000000000000000000197d56944796246c98088f574c984da3db7898c63527bd2a1625f96cf3fd1a16ee52f4dc93006d98e975e1d0f10af24a00000000000000000000000000000000055e939c9891a4d8c1850004b7f27b3d769cadc78dd533ca47409a18f39e1d4b97658cbf3a6829ec60efafa93b151a781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1d69acfe9fe709bdf8b522807659034c32933f6326600cc4fd10ace2d4c7ed5ac590a22ab54c82f27d44fce704be6a0000000000000000000000000000000009c86b430aff2a061ec052a4427654229bf654622cfced2f84961af8941f74fbe59df1802cbff705819b7c62b8d59ddc0000000000000000000000000000000007048feb29124210e4b66ee35a1de37eb993780db55e49ead4c96a5c0c124d9afb4a9116507164f42e742b5ce72667cb000000000000000000000000000000000c4b40e2cd6fbe96903a9268dedaf4f8e15579aa973314a0c3004332bcf42acedc7dd8716cbb17887d926947c52c9ab51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188b14f21ddd890a5bca4a2270513575d9e46c95f3cb68c6b98616e2b1a0eac508928296548589d99d0146aeef386a46000000000000000000000000000000000f383dd7a06bebc5b9656774d1a7b9274a91ee213e5492cd1bd3325100b58b1c050c873d5b5fcadf083083a1b9956efe00000000000000000000000000000000139fe25154f059b556489e7e78713ab9d989ff788b75e32f70742f0311d9277c339be25240508d65fa91da115c7c4da80000000000000000000000000000000004f1fe8e6254fdec1968f807c061448a28746096d64d0f1919f51eb3eb23f65b3db1972abe985c48ef47c11b0400ec091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c82b622c68df579283e79c8e5c797de5727fc47956b69d2236f01e3272bd5707911b3c015a05c50c0e55dc7bd81e145000000000000000000000000000000000c15b7437c02b11331a9ec54128f20a1795ec4caa4740552db1d7d6a4b2b4489bbef556b21ff6ed5313236779c5260df00000000000000000000000000000000187f4ecd88c9aaa12c66b318c1e46a5fcb33c96bdc535b2eee47fbd2e8590d9c3a236e59322a367aa74668f3ca55b765000000000000000000000000000000000091fa89d41faa7c66709260fc30efcf8efdbdb2154311e79c1e7ca85aa32f1c431363f4b8e5cddd807fa32591c2ff6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be9ac27751f096b806d84bbe2c6073a3bac48d6d9e0e3cb78d57d53c1d5266bc3457ee4b7f608011c4acbe573ba0a1e000000000000000000000000000000000e59da4d545c63b3a206b2e096421d89fafad3ea2e1132bd1ecdc6e3c891756cb5f931f87c69a4ae6456db78a98c52b30000000000000000000000000000000013fb1e7bd0e80b1bb1080b4c24eb692430a0c7c00385634b4d626a3c69301e0ebc5f1f3930ac0edbba786c9d9f87ba6b000000000000000000000000000000001202bdcc1a174f032176807693c63135edfe432f014d1054fe22abf7a9687e0833f920c114ad4b4c3870572a2c06f48e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4ea28d7db46ad11c95f8081b7ad6520f3906ad1adc747ae04958688ca3f52d08664e5f779353e889f8a52e78f4fb960000000000000000000000000000000015650b4211fbaa984b2fa2045feed77ff29e2f96128a5170d86f4859f881a4d2a212a5b32c0171ffb05edce458a23dd80000000000000000000000000000000014820e8d8989e298cd4bc9294ecb69533db5da7e18e072e0b4875e99c9c00a90c84cce168d8b618c26845b34e2e65e5000000000000000000000000000000000008010a75425d3921b5cbf37e33f342af25297c116e623a2c3da823265fe50a05e67508a04ef0c94142b7a95bc380ae21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001617b619ef259deca8bfc5d2f628e26436ef1037d50fe9750697937f16676b8e83d6acdb79befa04cc8a62a8f6f8336c000000000000000000000000000000000d538ce271dbb8e830cd260c038746170ab7485d2649c08feba271254de32c380e996ef068a7451bda5aa07bdf2e4b0d000000000000000000000000000000000f476f858e7fc0cfb1c63e738ccc17bebf58a23ca3ff3639a06ee8151a886c9c90603b7950b5fd2a3dc5313bd8da9eeb000000000000000000000000000000001891a03697e445ce23b08fe548e40dc7659cc3effc25cacb0e1df2382b0a920a45a49d01e40858a0eea191ec66b89cbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a38bd98b3ffcc24ffd5bcaeef7b3714dd67e8399e5fd5205f5fd666c0e41a03af70d696fd3242e14cc152460680042e0000000000000000000000000000000017309c2771f7c4ef4af81ffe7150794232af664574ec45502b677f90c94fcdbae7eb588b73e45c526f25a9683cac2cba0000000000000000000000000000000013da92d3139de87fe537a6da43748dea4306936cbc7366c7f0cb9fad1b27656e2b2537b3c2b940fcb0d5c4811ed0fe13000000000000000000000000000000000e48e63a9d2f5e830a52389f696d0eba03a91c5ed34ee4de8a98bc2172fbe52bbd2d51b371f009260b12e2d5cffbfdf41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085ed6826c51ec127d79932edad21c18f882d2b98f6f33a49add86d4e1c5860356a03f26ec8e9324c967e81e1fa91f6c000000000000000000000000000000000a276b914c7adb3945b88b95bc7a237869b6035cedc606c1f31ab23efd8d4a9a07996e74876acc218b8b42534340d45d0000000000000000000000000000000008ffc3e72045c442786b342ee1f081a9634f9398bc383d752336d0b4a6919012b307bdbd330e7eb3622774262934ed4c0000000000000000000000000000000010b15912daeecac9aa40ddbeaa033b874c04457ff17cce889fe4a5fe2bd0ca68975075396af74d9fb60bea04764e49c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee9e739407b62524d511edc5038651266bd31b635e65c7efd25fda8c1d9f6f135742681372eb318256014a9817a00f30000000000000000000000000000000005c866e07aaabbb4a332e2b3d46e193cfb42a325543663acf14badbc521dfdeed259562c2f4f72ee93f587a4a737984e000000000000000000000000000000000417a4dc3d10b3b04f817130b25697a191abb7b16deaf8dec16d5ff7ed6bc90418835f8a7c98e9bd8ba711d8be83a35f0000000000000000000000000000000019eab00927b6837d3456992f0ac5c57c9109c725ed3a750cf3ee39f3338ebf658da128dc799bb1846cba4e4ed6481ef11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080ac3e2223c56dd5023776f306015a4437569bc21e64f4d4660f244188ce7114bd93ad4c054ce8c508bd6e9bfe75154000000000000000000000000000000000753deb5fdb6ccef5d503fcfa0cd8970ffecb85178aa104581231c26e6b1231d21e4c405fbdff1ac71f75f382f0e3f910000000000000000000000000000000005b31ac04ef418659b5c731e19334cfe4a79357db0eac49de306964d855e1f01e3ed208830aa9c51fa2143922e70934d000000000000000000000000000000000f0e51a992c5a3b3e0d00885224b3c0db8ccb9dd1fff3ff96e4832b06576ddc3b183170ed618d29b428e0a41aef7b3021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000edc2968c5e465ad9dd1e6603ef89e0621acbe64a4d480780d6e8b6b4d4bd6df6eebce7a410fac1dc4bee492ed2afac3000000000000000000000000000000000011f438422c6982811b06e9194090470de878fe605eaa6e6a550c7d4dfd084f5b854fcd1886d589732cf0b9c94c29f1000000000000000000000000000000001834b6000e3b60782a1b9ac42f2c8e5434f3dabd17e47f7273d9ed59e97a980430a62bc686d4fda780bf620dbd8618aa000000000000000000000000000000000182ca9b3256b705d1f55e3c9d318bbdca10e6a220d858689d185ed499e40626ee2a1cc0c3683572fc8c614b01bc00331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf42df84fe1849fcbb748946839eeee5bc832a6fdb3226125321218aab7ac67b4a149aa826c7bc879390e6fd116df55000000000000000000000000000000001517f9434b1c8614c5bd1c19982a652eae0c97ed865b1bca6a66fb62da01fb34908f9f167533ea59fa51ed25a2ae12af000000000000000000000000000000000603640cde6791ed619f152a2e3152442132b6bfab93b08e7df79c8aefb2af9250cdbd5c27d54052b7296ed9b0db10ef0000000000000000000000000000000009f90ebc9e335e266ae53f7f857d228d07675ca1617ad96869b9ea1e5ce9d7e28d27c72c02cab868812be61d6c519ead1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4dbd1ca6a1b59bf797cc715bc9916bf234cf00255d2b7329cc9f69ee6f7fcdea0f00d02bc710cab9687b0b169fbe15000000000000000000000000000000000c6e677e94f191a9768f220e900cb01c5024330b62e2e483c30618513762462176012cb8fff1ac235ea520883735d9570000000000000000000000000000000001667eef259b8fa9367a8dff793a922378313c26912dcf4510f00bff8d551b0c4d83a29522ee86ca4f58040ce969d9eb0000000000000000000000000000000018839d4765e380e66d7e4419161434fd34dc3fb5286fb28451f234b70d7e75b32f2cb509865a9bd76c6667ab504646ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000673f4ff25fb2b482426469ca4b83bb5e6f3db3d116daedaedbfdf6eb1016d4e83eb46fc50cc815f5f1b39e188ee215a0000000000000000000000000000000017da33eb99da88916b42d20ec280ac482b24cbc81bb8ca9acdf1943d7ab7e3393cd396a0303e23aa37a3f42aa9de47ec00000000000000000000000000000000058b58103c7fb9beab8d6e1d87fc4afbc171d3f65fc41c0596c7399796115e3e17f795117bcee8fdd0d0db6c83d6ce590000000000000000000000000000000006d9311b2628195c4a032e976db91d3921e0171dde1fc455faac598e0d9396cc9f02d4cc6ca0a976b934b2c45190f4721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001626a6e4ef0b345fed8fd06564df66890990690964f3f64f2fb26c11d8aba05e3a81e6b3f5f331ed3269fd87ccb957df00000000000000000000000000000000192f4fb06bbc52675c2bebc3628c97cf4568a74d71a80eabccbacc138d0523f348d97e411dcc665edd2c0cd66fb7cd9a000000000000000000000000000000000648884fc143d1f9db240e51f1cd57d4949690fa939b335aa1b61fdd9c6d88f8c6f8a4ab2d821c91c974d0317c9ba9960000000000000000000000000000000000be2344a007a4bfe708d037757e791324fc7f6d6e08e7f8403203f6dc20ee271f7b2a14a80aa7a4a6033b98cf7837741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013eac23c29960784fe978aaa687772a21c01a91979b5790947b875d6801e07c54f54a49273a75cf807b4e717a7d9c2fb0000000000000000000000000000000007325e10d81093d530b6918eefa8cb455346d02cb104185e3b7d114b2ee1e25ce634653e3bc5c23f99d2f9b9d6a091dc000000000000000000000000000000000f63d667d5ce455c517535efcafab8c39aaa3c11c9b18aaa6d4265916ce805e5c1f6765a8b22093788a6a41edbdfb8680000000000000000000000000000000016508f06b512677cfce2e9372e1ecb04cd82a13f3b35e8a01c052ba1571e56688d7b9bc0d5717eddeb1c6cd680276bfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1c4bec52ac613f60844a9cb72880dc11144edf1c728679a4ad0e013dbe0c02e731fc7d64b4716716604983285b955a0000000000000000000000000000000011e88d8a77fdedd2400896c1a6c435748091cfbc51a7c0d69a2b81dd1ea41d5d7129147ea407e1394a1fc9fdac4edbfa0000000000000000000000000000000016ef1b1492f2396e0e5eedcadee07325ddf725c26b4acd46ae872f4e1a9f79f0762e587b5a64409bf29446b3ffaab01e0000000000000000000000000000000018a952ed206bdc5a50e5ebdac082d2599f6b1d3b9b92d5afa54ba6e16b51021eb254b98f1ae6a24db9d55cd89cccb65b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001596bdc0f74a54fe803b986b32d91adc15ba757f56a728e2307c1ccf6a1baa646cdf912a48ce16be39a3dcfcbbf9812300000000000000000000000000000000095a1957d04b344839fe3524ca5f66b3012d03623e9c2f625dc6a94be197fc262a627dc0b77f1525817f5cb7ee3257a8000000000000000000000000000000000b09ab600f78429dfd35753f37cec7cfc3d9bd266a01e71ce3f7ec4cf2b0ac7029f29a21a2b6c61ddd0fe62439cebd5a0000000000000000000000000000000015c70627b160251f895f192779cc8738c390d7fe9ee899716547cf0420a832e75715e6408977005510a26dbf394ab95e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff3b12035e7918ab07539a7095c8bc4dff7754c706201ceaee303d13c0563a15d0a0f2747355c86e3b506a8988a6cbd00000000000000000000000000000000107a0765bdba2ad4bc1de7ddbe8b463358bf9180d76dd46b4005ca22a5cd031bf0bd2e3d7ca843d1265b32e303835be6000000000000000000000000000000000663baf7649adc729dda22d3810596c97dd1c35a22cb1fc436da13e0d7f36d0dcf3737a5779d7fc8c5ce2fdebba8630000000000000000000000000000000000019450d43e61a2c9c6a37cd4866afb20cfdb0cc520f6f6b12d7fc207b1319d4e4b60e0861147bb8b7e88c637ffe705181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b36a968f5bc41ad634c637a79e59039391e9590f6c92b20d4d492e883b783650d362eb4fb525b3932d4af12f9faaf300000000000000000000000000000000186d970f4268f9cab04326b00ea495416645b4d2dcc7b81939f33eec046b64506032739e6d86cb9dd2c70b0b28d8cec60000000000000000000000000000000001af7ef21c0dd79420e1b0c100f09484eeefb99daa4d3d4fd7cb3eaf41f1b1913a43f9bed22a7bf7c67e446709ed914a0000000000000000000000000000000002aa0a78624084204ead60fe307775a57c99212adde1747732c89a1d1f8d950bf78a2ae5dfd9f2be9c8c498d22c727471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b40e159d00ef05e7a516d06dfa3e2548867cc5b33595a7b4d9d4faa0a0f1986b4f73bf1996fcc91eda2af1418ae1b700000000000000000000000000000000084ef0039a12dc2b25b119ec5a24de11bced99a407e418f05a762bd6eeb2a37bbe403a02e277719b92fae19e57932e2f000000000000000000000000000000001790009bbba5c2d81d84037341452ced7ee5656763d1bf677a9a89e80fe3ef641eaec4df62ac7fe6cfc7cfab8ef438690000000000000000000000000000000017897e305c70487ec991202f9d6927257292dca4a99ad9845fb5c30fe9c0c08ccffea99d9015ca86877f5ecd4c53e7381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6ad87103dd219cf3858d66f22ff36fe9b1527330de1a6f4e055ad141df4b8e91ac5e509f63a73b11c7141296dfb01400000000000000000000000000000000013e9e162c38eb166ad82ca7ce5669ebced416e9217b9fdb3b11420d8fc65ecf947750754ac89449ad042ef6f091d7a8000000000000000000000000000000001584660a054e014a22ed8ecf959a760e5c71884b903d40d105153f212d4d18248cbd27f2963e97152af3ec713669935d00000000000000000000000000000000158951e10fa0b55ac24df62261912b87d70568fdbf7af3f4ac35270aaa653c6117ad081dafe34838e99de1fcc3cd648e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae1cd835fb836b1d20fd6e191e0ca3e721bcfc76e783a125f9eb8e191854eab77a5df6bde3a8739778953d2c7ef79f6000000000000000000000000000000000de30670a1ef79737dd98631aec3c7bf10c93f1ec852d09b86504fe9849572ea0b7d36ce2eb998fc338bb819c5b5a946000000000000000000000000000000000a8185e739ddb9a6be17b69702ed7ec63fec7383ae609a8033ac935df77c570cf6e6bc270e740168ea011f41a4f618230000000000000000000000000000000000c0c6fee5bf17d748ba7c6100c55bcba2c0360dcae8618820bb21c60add795af981df3ddf31b4681f8033a87c3487531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c6b0d5645fe1637f9cb1c37eff25b2b58aa98a4c8eaffc679bffc7b47bdd4c9b7c42846de7e71f58b14dbfbb3d30ab0000000000000000000000000000000006d290c3b636159a3b2f0a603f5d516d4dacd6b2416b5b06537cd9dd82d95c9dc1cbd354b4a3bc98633db46766d5216d0000000000000000000000000000000014ea73e8d3071f7e6037f18e818891da140e0c812c5354af220653a5a5f7c86df5ed38b049bb65828d100a6ca2efb4520000000000000000000000000000000006cdbdfe780167f83335774e7aa4c07f8691d1b303ed32dcd6e7f2572eb7ad51b555cace7321b1344317921f9023e4a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024a8f3cc11120a71d8a1be7b81758a7ba3420bf93d05273e678c7601523574aaa2a019034cb128536d5b3fcfb99603e000000000000000000000000000000001020d360f80d5832cbebc88c5758ddb1abcbc3be8ab24af389a104a60d67fedfa658f7223528cf2a8c8a2995c11faa0c000000000000000000000000000000001229decc46e3e1d3752f13af576a7c864216fbdf5c330f603f78d8792a3c38bab42c7a1099a41e608ba54b17584ac2fb000000000000000000000000000000000b210ded3b6818b06d6ac8d2607d2d8abe2f8948d8b82f82648f8d9c5e097e06864825a6a368d9fe96b4fe2df03cc3351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171c7f718e6114701f2b7a11d4f3440c22799ed210cb725da864ad8d435584146a982f71ea5f2dd761d1c0e326f1cd5b00000000000000000000000000000000074c4eb5e88651c25eeb1e0a6959cb5773281cb43ce2012314315b754e359c96c454c28821d51f00eb8e0ec33e213c2d000000000000000000000000000000000b98d81e5b4ea53e613ae0c4a21f9d033caec152776c7f8c2a214b12588541122939b24b115422294541a9214d4619040000000000000000000000000000000019ac99459d70817febd9159a8734f58963473c4b12b132fb2e1c7a3b2e1ce6f13abbacee4ad513e6d1b0dee70da17a611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016674e3e544ce80f249fffa54f104487f01303683ad4c213db73e1dc4452499e338eabdf66eb72641ac8a24b96155d26000000000000000000000000000000001483bb945661c9d57f62915312650015607075075b3335a744e6ba005ac9fd0c5846a89bf375d657054bd25210e6e58700000000000000000000000000000000131843d43d526c1ffa234ba01e6f67902490a73578f69bec299c8252e1505f6efed28cb775488a48c38bf63e4161990a00000000000000000000000000000000141cfef8f8654c2dc7040676b24c8722f52f429bedaf5c945d71d661bad6671a35e61b2cfb43a8199d4071d25744f3cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000663983693bbddd104a0b5ce420c872f3669ac9924dc28b25e2ebd0b09b8d9abecb4ce3a7454a5a359ba9feb68c82c8400000000000000000000000000000000015df74dc571319baf292b5c5ce44ea7140c90a5349ef3a17f06aaa3e2eca84f68ffbb0966c795a1c3256b3f97b4f9d8000000000000000000000000000000000bff4764b1b12ea3b47c20cb12fa6dc84184f5601bf37ede172c901a278aab456440a42191d8887d63d46136216b88530000000000000000000000000000000016d9aadb0c95e8162b3edbd5033db4a8757d66210f5fe9bdcd332770047627200ae1c87f45e7fdda1bbf252c34c751851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002991d4ff88e5dcc8a3da5b612ff8e67677529e44af8d921399201f356ce305097d11f62c427e455124bf4b3fb406d57000000000000000000000000000000000547a3b000e0038c69902bcb4185331be5512f7c3dc1d1b03b2e7a967cd37b2b6253421a422a874b96f11561aa9e9d4b0000000000000000000000000000000009332033579e17c5af88af7ff4bbf14008a7845f0831a4e33e565b06ad0cd562866bc0c8e80b9578de45522fe67df4790000000000000000000000000000000009845f21657806f7b3fbbe058375d8ef9c41247e6ea1ee6c0dad2bf0281e77ea5aae7df9bf29d362a384d674ec8fdfeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee973406dc581b232e02ddb24ccc01a284ef1a2350d324f6262f695bd8a0f48b2a1a1622e1e1e72d71e2c2bf62e808e000000000000000000000000000000000fbd8963f89e9bff2f3c1e626b48713258cc855140c1beb5a444585fad5142b3415b803e1f82975a47a0ab15c3d0928200000000000000000000000000000000077204a3376a937906764d1ab8290ba929fb020591bad0c926d0d8c0aee556b4b57f8ae30202f778cafe100e0f658b6d00000000000000000000000000000000066d43af5cba695f03bcd6bbe8e6f903e7d59a5e71bd0b97737bb75629dee3a709fac383ae45fcbcfcc35ff0e31ca22b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007c0eac8579c428bcc340acc15a0c520bf246c1c3e9cef2b9d4ceaf013643646251815a1e8f1a13a7d1aaa455c039b50000000000000000000000000000000005810a33300c8b7ecb77e5c52e0c40966c5167aefe3edafaf27dcb4ca5e0a7574b1e5359a046eaeaf00d4431a014ea930000000000000000000000000000000003fd8d60a61347ab3a52170994689df4a74692760461dff954f004697e377503b05766d756f1a24d9774de6db2d2cdcf000000000000000000000000000000001551c5c08c2a047f835a6482950fb31b93db8e0d89373dd2d206cf42dd421b4f0593b9421bc0cc1375ee67d1a3d5c15b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017db90497a8fee22fb0118f674aeb19148981276e2ddaa0391d31f7c9100808c491ea1cae6cc3f7876c75de6f88d7d900000000000000000000000000000000052b1c086e15d5aeb19f4cb9d701686e81b3dd8878bc3e15612c9ef17da3a2d820ec08efc3a0793e320028f11785e1fe0000000000000000000000000000000016131ad203c90e6e92b4580598cd42e2a8aeb8a3a48e3c89f71b37fed674a6235feff9a6b30836f3030411a2579519ac0000000000000000000000000000000013c2377612c9ee77ae26fe113b7932b79d62eec82ffc19a14a06c3f4622ee1aa5c394b529fcfe99152d6dbf148f415de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea0581916c62da7b0efea831ca102098e92dbc02ddfe38cd4244a151c60160f7bf60771cba4bddd4f6f0a851c5ed5f8000000000000000000000000000000000f0fe9a7f3487e60c776ba375e074425968ae1503ea5fd926d0514432e3b0d04105de98c9181d7660df4d6001924f769000000000000000000000000000000000a518de68b5d47f69165b861d2901c44c0963deb85d0fe84dc582be77422cbd4884113cdb9eb4eea52ab95d8c28d38c40000000000000000000000000000000008f0a654c24ed18b75851895722bf6f127d61c232093ad49e16908c9e0487e8c0f3b4c74b9a85cac5ab2a69bdc8899251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000137319b086088dc00207556410c9870a3aa9c0990c25b473170c1ec46e9f19b718bde81adadddc44d7f13ac0488fec0000000000000000000000000000000000a5baeca2e97b95f561a89ca9313825542610726465565d039a7e004241607a638c47fea035aa39a92254a4b2a47f5130000000000000000000000000000000013bc66a11b569689345bd17316d8a0e4d01f6aa9ec28d73bbc4f51d2d05d771e3c722c0ca782f8b22d39cc06eb8b86c20000000000000000000000000000000009c10117bb32e7feb8d17ce58d33cb74c4c2ce2601caffe24d1d74969c2749c2ed95063e785962e331047ca1bb9bd6f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9dd59209c5f7cc27a789d47c7381354afcaa30ae6c066cbbf7538b9600a32c94d19f28d36bdc4abb6b54ba575605e0000000000000000000000000000000000e299453866df6adc6dacc2a334bc944fcee3d6b6f62c9d5a1138589bfd60529623f943f318148420b7788ec912c873a00000000000000000000000000000000189d491e56da3f799f409815988e282b342f42db6ec4d594b40bbaaa144ac008234d664d2c458be840393832fb1d785400000000000000000000000000000000105341369d7dca64970fe9801bca580041421521f38064d6ade2846e1569ec96c6f4e89db9b32cfae29b4834f9145efc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de0b6626a2d05ee2b9a7852f9dc6beb1cd7f13a024b542cd6fcd01cda938b0cd80dac458b2c7c4590e80592a02760fb000000000000000000000000000000001171ba982883c95c49bacb8517c1a74bc3b887454e3a07c981f94aabb040dbff89b108a8ce2b8f95327e655be3ce822c0000000000000000000000000000000019d0021d984f4d1089ac5f3e146d69c4122f1c721a15b705e434ebefce3637bf80599a8060a967b8d0a552f4f0cd7d6200000000000000000000000000000000090a63ccb5d8eaf564c66c60d89f4c4f04171a36d80c449e5c4b9352c56480d55caeb3e3e3d657c60332fc095af65a7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014026585d15143719a66cdac1abd41fed49bfa1f57af5213a863f05a38541c591a675a4c70fa9a734bedab87e61110580000000000000000000000000000000006e94359d2d9fe706639c87e7fe357c28b795566d5a6d34802b6d67b9c5425e3852587d79ff096a9cef6b220748ee6cc000000000000000000000000000000000e732efe55cd01508e48d62d1115cc4b08eba81da9b80a3e51950c62411330d5e209bbfdd3155593431a98b1550aec1300000000000000000000000000000000023c7a805c284b4da5ffc03a8e2548354b4410a95662056255874c34d43df3738277382782ccb18e3b758bf6805bad2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037864e3243d6339da3bcfc5727b2b62f6b058dd4a60ac852a3dc3e23b374f9be8e7d6d36335cb23eab4a734a90328cf0000000000000000000000000000000002f8dd46f8740f1ef2180a6008383e4375205f0bae3131f899e97db31b3a89fbae51a797a7dab4a86d0466ec0b1a89e70000000000000000000000000000000015ff95d0320c39ab2531ec0a3ad1b62037ad05957e1b2682eef2cf314ea11fca435c4db084f4066ad99eba719bce762d0000000000000000000000000000000003c8d4dd2360a3a994b8cb7910f47c7e6589bbb466b1762312cb59b1f2ce21c6ae15a09dcf79a8eb376c40cf669cf7bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ef8979cd77124c9d200dd32cea1a5135e5926e92c8ff90ca5a2a3450429ff761b6c5a53bdd5db8eb4cbe0953e7184b0000000000000000000000000000000010c52bcbbcfdc032fba992ce7774640efa94e0a54fee0b99cf9a58664092da94decdfe001d9af89bc18fbea0e1a9153a00000000000000000000000000000000022c240aa672cc3ec13d6d5602d98a36c1c20841a1eb927e2656429fa8dc8af7057e578708bf12ccac5e764b8f5f75e100000000000000000000000000000000044e8e9765e97d5c2e095c61257d8feb3d93553dd81a9e68a5d07949f5404c10c5a45c20338e1b78e64da0279a11bad71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f838227d011430e8910af9c92e59575581a1d34ec13c8af8471a8615f90b98f30520d630a3186da05a2c9df888b28bc0000000000000000000000000000000007bae9130dfb0d74e596e0f76074b114fb178e98e0ce5ba51ac4997684a068530e629a0665d291c92ea99fe29f60935d000000000000000000000000000000000b553caa1d3ef68096226385370ee4ad5c740086ffa3e14095d03785969fb54a4d34e217657d921e9b99985451b751450000000000000000000000000000000009ef0ae1a7a3ba35c27b0433057d39e91a37a86f8ac9a528c9692748b5bc9fd286b921829a224e50c070626006460d711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000034eb2384107b8bca53812d6a061667fecbd25a96ca7b579a71a33acea69e6abc4f0bdcaff5a7c8b028633ea0bf6fbe30000000000000000000000000000000014585b64a280c39fc81a1aab94bf2ab6d89c2e6c883b174ed948be878a442c5914e0ff771865a1fe78cc2253f2cfbe5600000000000000000000000000000000029341146a0849b22b8b88ac9e029a7163176d7d3ce90365281fdaa56cbf5ac1f2ea42c26c29633798f27faa8b0c5d78000000000000000000000000000000001211b75613bac800e4388be3029b520562786925e379a06fe76ec4c615d1dbf25a7e221ea717640d11ebe52d4c6fe8c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069352e6bed45c60c8e201af87d5715dec3ffea9989e291faa1cdb849a3f51dcaf58f872b60319c69db9a4f75a3194e3000000000000000000000000000000000d96171c074d1039795985de56223820ded34425ab4a0b3f622001aa5b8372aa97bade946e80a579c3afc66937f12a61000000000000000000000000000000000d57fa895acb5faa49144c3d5c9ec5193e6a243b905d9a97c65a42a4d01a2ccbccc87695346ae0e275460eb2a41df8e2000000000000000000000000000000001797725e7fdf649d587c72bf4a08f8c96b52b0f3d57dd27160ea120ede9252998735c92b9b6aec0757a19bd1aba961a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd9abd6818f63f9f9a4623261f8adf87e2110058b6934b62c1cab026fb2072edc748efc494036090aaac55c8ee93eeb0000000000000000000000000000000012e78acdcbeaa0d996aff35367f2a81f03398a09ab14b6250c7f0c119d566b3a05887ef1d709ac7a56a2a0486e38ee22000000000000000000000000000000000fe14ca2f5b594450129d97900a680dc021cfcea0ce22037c8446209e40994a05fbe4aa312c589a008ef27470c7e2453000000000000000000000000000000000b997224e72a651a8b8c4edadd8a6c2b8805087e0f30e1f170686ad5937129db47840232a4f4b7de92c0dd3b7c6937901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e37e8a1962fcf0d02112a21666bdf1fb5c047bf2571714159717d693cb5b6d9cbca40d91100410aca6bc20c4719cef0000000000000000000000000000000001ce0d6374d0d265edb6a731cb98e4e0729d21d6ac5d34404a9e1b761eaf8ed1f567fad3e67cdac197c9a2812296d6a90000000000000000000000000000000004432341d99d0b52d58643f547211a427788722497a8b78dfdf1cf54e42d17e26b39f33834fa9466ae1e9ee0a337f5010000000000000000000000000000000006388f558d15244f910ab1d23b1894eba3182fd2588a2c792d530431da4df31389c0e3b4080284f075ccbb34bd1c8a651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112250d2f8aef73c7f90f94404af5cd8b335f75caaa1ad7981d93cc065d4f7f3020986e8a59735a0a8773d255c93aa0f0000000000000000000000000000000002100ce50ad29ee217a9d9bafd5dc4bc5c8919b50dd1c01f005339fd1734a39a8ec77542deb5153120ee044cb7114874000000000000000000000000000000000e19f5ce9e9279d7ad05061cce03b47a502a036f81e2d228611a26ff25da7e9ea47203cce5a3c1f16a45d2a96c20add3000000000000000000000000000000000418fe7a1ce837291072f043d6fc63407c0ae0bef0ece6d100e5a90cb10d1a2be1dcfcd90f332c61a28a238907ed24741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e30fd14206f5b6771818deec255780c9b255d079f43d1adca5654019bf53b98f367d07bd9786580ab52c482cc60bd600000000000000000000000000000000098b450b9d1748fe62cea279fd36e830367ae22760f53b8a8a70a26ca6dc4d4c853bbce7997eb240a1c8b37c0bbcaf4f00000000000000000000000000000000152ca0c0f25a88750ad59b07a8af8f394293ff7bec218b784cf2082c3e507bfe65dfdea28ee6dcdd570138e6dd6d8a27000000000000000000000000000000000b044765d7339c0e7e915585e9a29d21ce4866267cbe81261786f8bd4bb0f92cf625dfe1522f849aae215ef3ea67fc221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000036a95be13aa6bf481f2b887440763237fa52026f9710b0847e0787db4e0e452d5f8edb0c1e891d1d3f22b09550863200000000000000000000000000000000165ad369a4b9d1884f1361a96832404021783e8cd01c629462c91b342721bdd5f78d9d8ab395a2d20e23d827fce5306b000000000000000000000000000000000fb0278d086895488935464da4958a87b1409d0adbf6b70440e2896e0d848f783d2760bad64e505196521063f25facdd000000000000000000000000000000000d700621ce274a301b022b0054a95e07f94c4624c2c6ab4fe787608bcc8d285bd102b42caeb26c5efb6e182d191cab3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060a719d92873d4559f91786d235a11c5c9555a10fca4dbcabc5390484c892e7a36307ac9dc4e5ac2c3832f028ba23a00000000000000000000000000000000013d318a9a73d487ab956436611b853c2d2a37a9b47265b8ffa5c0ff61c114919b405d7ee186a51e1cb72e90d59225bde00000000000000000000000000000000176b5f52b45c3790ba81a55641a585322f38a3b6b382bd2fff844079f16a8b85d0e55967916de253cf7124ae6813478a000000000000000000000000000000000ba59d5f9d5583bff1f545454fb3e8d8d7f51c409566cb34e03c8f9523ef5114a1c2470f93292f29a81f403e67435f531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e356ccba886651e0551493cfe83d83f9ced0c818c6bb36e5775aecbc7f4a6f774b3fbcf005e13d66798db3e1e47bc21000000000000000000000000000000000f3fa355acedbf4bc5eaa555f3550a8bc88f081e00bc868976b7f3245e3241621f5a80f6a673a00b552859c341f030490000000000000000000000000000000007c542aeaeffa48629ca01c2f804f3d5aab46498d2d9355dea04060a06ee2e3999fa26563b80cd158cacfd439e5afe2200000000000000000000000000000000112aacd15490a9aa6b223bd3ccf39ff1fbb95e3e2141aa3110c508766817616f15174d358e41177c1d2eeec2cccf2efc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014dde5936af03a239f90b09583b58126df16ddec8398a9f92a70dfc96930041e4c9932f636bda0c150000ce12eee6d340000000000000000000000000000000010c2e9ddf62fb4a6c5193b95bf83389d48801e838d017697566c74cc570b6f49e0088a7c07e8e9c8518137db572d814c000000000000000000000000000000001710029c0a63921bbd7e84854fc55919dadf4951dd83791fe9579672bf85c885a545f4a72646dcbb96f40216850c33ed0000000000000000000000000000000006ae2a0a0de586aa6b6d4792c29c2d5dfac28f532084105c497418dd684119a15c2e9d12b9e9d831f23ab7ea40aa94571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e153d7ac9d57a2054b9d68d824d54935c4bc8384a2ae8f2f44b71f2252608539097bfe7ffe0ed1c99f54809c73d0240000000000000000000000000000000017670f813b6589cfd24a1f3b5cac66c4065bd9e18e334cb4ba90216a31381a7c91133608a9e9a853190a5e1f267bdca0000000000000000000000000000000000cb3aedbf574b480d4c5c623c9c303076961c848c128a0d1260ab06a05c9fc84d968e94bf531b837dac766cff3ba6fcf0000000000000000000000000000000016f465087b927ab1fbc557154f5e785542f08f16ac614a47cfa9ce3a18de62358ad7b410590bef069e605cad87e490961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003699d395733bd61e2546f5314cdfe7fb8f2716c2a19c6333b875bca03c98324b4203655c1b6df3275d76beeef59035100000000000000000000000000000000068a43b91a3aa42af7980e51eccbd85bf1fd22b37ca9efcffd3acac62ace0854107567638e120213e89c99b5faca19fe0000000000000000000000000000000005bc9a4edfd56dac254cfd76bff4fa36a589aa3f1a879976999078175882f5781b4ec596c080dbcd79a4db507d01676a000000000000000000000000000000000543ef09229b5d7daa99c7a191e5847d530d6f9806570eb031a86c48fb37c360df2eea17b6f3b0faccf88228e90cd35b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fc451fc06132e6f2be9a4f6831b1a3ec17c39e5f9433cfe1b16f376d200c06b5c2c4d4eaa520ba892b28e8805dcd5200000000000000000000000000000000012af42e1fae6850c0b8a34542a914f151d59028de32fc8f593ab4399cdbbe70816969b78233861bcad080e33d56021b0000000000000000000000000000000014a64566665979313aba10cead1bd0f55a7c871a0c9a4184d56d28ecf05597e956f4a3da52ae36261151f33d3224da8f000000000000000000000000000000000bcbfaef9a59d14a67fc9aa7490a897acc087b8ef06f8f29ba8b74744ad7821d088b7ff135bcd6419fc685b5d19f43c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000999080b99dcf945fcd23bd1db3b4269800465b9bea3caca496ac7323304dd4f490b8d56847dfc24e9198a9863b479470000000000000000000000000000000018c39709cf0d94730f3bb0e391293b8031cefb7e1b7ef8d3bdca427210f480a9cb84db80fec0a1864d5ce3b76c19da520000000000000000000000000000000019175f2745d381c285e7bb7efe9c4a605a2e148c796660c9343da686d11bc5e2b62b50ae438d0dc8fbe34a29236adcc70000000000000000000000000000000004b449f730dcecb2c6fa2c964f6d8de70546506580e0916ca698fd8e19ec920e037ff4252fbac07f944fc6983038190c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001892c6be68fd605a592f219d3f80280917d4cedbccbd146c23efb3a8a71acbb78e5ae0aeb9054837249a3ba62a9e5b1e000000000000000000000000000000000d083f08561c3abad5f17bcd5307057b7f65b0ad248d9ffe6b2166a0cbda68cf0657811171d9e8e36ec7503aab0850a40000000000000000000000000000000002724edd9374e87bf13bee0afee2a79e9ce7e7146ce7d3a0cfcdd42a3446b62d44027bfc5ee7b532212af1782ead22c0000000000000000000000000000000000a74f0a0d679dc5b9164e41a1ce76b8b455cc96e0386efee40cc6375d2e8bae5afad2081fa52794ec3d2326472e8004e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e84e2004d4d0eec01dd71a137d210d0bafbec3850c458b98ad4fadabaf85652f80fd47835f8712212db05723c7d1b3000000000000000000000000000000000847ff35f58aa2d76c6185a8cf4ce21a35edf4e2a18fddec94043f0872f47fb661a305114ab9593980a9314afffc8aa30000000000000000000000000000000003610ce1dc87e416f665b629a3f4e979426645005a24acdf719fdc1e21fbb13c0117c1aa43d2782f613af0956cbcb5db0000000000000000000000000000000000075efaf745c0d382156a2f346119c40db8b16d89210e0552481902ab5ec3da708254a559387bfa262c467c0948c9041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055a55ef212af9b7a931cc9861c1a0a401fe34a3ac5b15c0ffdba249292d5047ac24c4d903eaad924054cc9916e240a900000000000000000000000000000000123c6f2bc2ae7a22a44826b16498333fa980d4644f5f5b6e1234aef2ba87886f70f1003dd19a5ab5289737430c9daa500000000000000000000000000000000015d755742c9dc5fbf03658f729e0c76ac4a2a7ebe715ad3de9216b99ffa7e0ab55f3bc70c14fff441f29439beba8c01f0000000000000000000000000000000010a0aab9ae64618f7715972dacae1fbef65afc26fa056264e0a77a6a070751d0e4285b5100641b2d5ba35341f9581c371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006aaf1eb1774dfe7fd6244c369b70be72772e83e861d3e7b3e486174a1976ac6d0cec7da0807c9d7c4e3e802775ffabc00000000000000000000000000000000117eb9c3494e23ecc147f22f91e88578cdde99b0255be8c490fe1c5b10813488fc88fa059f0957536817b8dc8a97462200000000000000000000000000000000004da6007f31527853841593d737b2a3135126ca70d229d53ba67bc0837c45aa07f787aa111d85aa90cf7338ca5e2ec00000000000000000000000000000000014a3fdd257a31cb26dfeab9e69b92ed7eeb45a3f88dcfe111b6607f3b8bc8a120998a2698467897bfd1aa1e14a59f5f21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db90e94a8ac25e5e5b7d46400c578c1b8157d615e8e5f7c1fbadaf834f3f5803405f39f0c55ceca8b40134eb3ec736d0000000000000000000000000000000002a48fb6311bc682ee78b9b79addddb6339563d086976489bd55cd92125819f67033a8e4d7c76bd31987a6b0d208416a00000000000000000000000000000000087700c640bc9db46906be04caeafdc663111fe7eea167a3a9d1dab59e1bb0e018150d1dd0a9ba77d14419f92e6122c000000000000000000000000000000000198e9f2d7cd6d84f73592464240389fdf0414a8e17bd0cbc522b6968bb8462ef1f5fd673aa1a939f0695839c6014093d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d49f6c2507386367ee39679c205842e6b3dd9844118038654b8d8d9939ac2e18893a3224de878fb048a7529001472c30000000000000000000000000000000004c572bcaacaca048d5512bd50f9cdda833e190db49909b595ece1ebac2c2ea74a385e8e0de575974c3586cd5d50faa2000000000000000000000000000000000c752eb08309a190000cff1e5cd6710cdd15025534ff8fafcea4a80476b904bbf4608a40d1ce0548a3151750f2b40bfa000000000000000000000000000000000b18d25ed1dcde57a7420692da140807079768c202af7aa185e91b597304aa1b60de620b382b7c02c74ccbe4bd41d3af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121bba2dce6e02380fbc6c77fa80203323289c719e30a11f913736d496e4dfddfb2e0f5ddc4d56a63fa8b8b46792e283000000000000000000000000000000000233223b9276480014498120031e9ebd475260cad0b2bfe86cdba9965bfe0267b870e8c9acfd7be572072e51d5cc2b23000000000000000000000000000000000bf57af59d2d0dfe08675b6d132f24b74f094024cc162c0c7a4bdbdcfa2a39f2415e39b4cc3de5803f3d8607858b535b0000000000000000000000000000000001004172ba68e2c986f2f988648515fdce0679cf2eac66962b31b1929d29e34954956a8dc385f2aed9245567ac52ed671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012474dd50283468810dbefb6ebfdbe34fa5a550a1c39b3990155b176d6e2ae99db78a149c13996d17d0e987cadb1534c00000000000000000000000000000000155e61116bcbbbbd02bb1c4b70abff06e76214be953db7e22a967ab573846ffd6090be688b28ad7fad4b193ee0149f630000000000000000000000000000000009265f830ce88016ff90e50021e4c3b68ff3a38ffcd566aaa8b515668f0c69b16cf6c2fc9ce00cdf3fe0ed15971112a300000000000000000000000000000000013a8be1851741ec6e3c11cadb2287d63e7fd5652e5d7e2d6510dcd1badf036462918cad4247b50c24c59a963222f8811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142be69d657cc54f8a08a0e6bf68030a8369cf84ba2e1127275d5df5f0a1520d532b5126e068ce5ffb4a025f7ce48dc6000000000000000000000000000000000b35abea80e1d5ea189bf2776cae54533d3e4cf521adad0342a3658b200b3033f8b02f4f4ef98a9435565c0f77f6befd0000000000000000000000000000000002ca8d5af9a5cd39fc83fb22def43a6acc7aaa6cb518bc94cbeb1f606d738859ecbc71eac72aa5e63c54eac5c2f5a6600000000000000000000000000000000003bdc3a4f0c7bf0a80008ccd90f183c27d24615e658ef9ccb58736e37bb8bc8011234200fb6dfbfcd78e283f95fa7b841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8567915c8615ce1ffe4e686063128b6df754165250b0ca0ab8f988afca5c4887edde4e8c3b76560149874f834f057c00000000000000000000000000000000185ecc17ff65406d306e845e634fbd47e9d14c819cf5e03d8f8d689e3b84423a36b620db73b4b86d44fe5a29b21af57800000000000000000000000000000000168d01cf433fa1b4a6b1aa9f5fc094257568ad8782b60e4cb7773a0a84420e08d73d9b7f1dde5a9ef1eee07be1d3a73400000000000000000000000000000000121ceb2b2a4e347296de32ab01cf56c6d6022696d7d896123574e99350849493fd9794532ad391ce4234cb7362ca7ee11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000664aca6737b5cbfcc7c417a9a72ee73624c0a1a9746dd4b610c2e2fd7454f45bf02187054b7655c2045f34395c881b7000000000000000000000000000000000c4287f903cd0d6da4b5405da626f9ea7b02cae24c4315478ef6bfeebb666829aea8416a721e013a46e97be6b73448fe000000000000000000000000000000000ebe121b457bae4f35690ab7948201787ed6640c1eb6b94f7832fdabed91fbba9d24429239528669f6fc4a98b27b2554000000000000000000000000000000001230618fe528e07b5159189cd14b3499f69abba5c5f2fb3e7984864284030f632bbabc6164e257f49c362278237f466c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cb1b7008f8ac267de74b57a3956b60f100fd23904288b908b8c7c402643271f46dd4b495f6a0d9b0153900f4e7636e000000000000000000000000000000000e1a3b1f5223a66de87c03b9db92f829a0130988e7da6fa6f16af0ec7d7e21fc521f1a5abefbc562a7233fd39ec015b30000000000000000000000000000000002c44b67fb1810182a3b7bb9ed724c81fe4d77364b93183e9a3eb1252fde901138d5c214fa779d7578b6381bb4fe0694000000000000000000000000000000001385220c4c642d2e9be54603f2172d51d3ba516db05d1e85a98b7382d1a9a8b512f140c1cbc777f0b0e7192e30bbc1ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a7146f5a2afcf4acd8b0a4b888452e920fb9d6fae64da31cbdcab803d2b3f86f53b9fa5a6f25d1de4848eee472de9d0000000000000000000000000000000015c7062ce2abc98384adc6d78eb5a31523352dc717fb933dafebdbd4b850a59fd008e1256fecf37044619185df9392d3000000000000000000000000000000001682065104919181ed8ffd2ab1b60be876760ffbb047fea1c34e0edabf035c47a4a15be0c5af4829d9502a346c4c96e20000000000000000000000000000000010d87c41226c61c47c0a09a67803d2bee457bf1e0c110a8f52b40430cd201d6281feefa07ca3cfff336363cf2cfdb9ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000939e145429ce755135aad7a3f7e5dfba0cfe204d87cd8aaefa295560e5529319fd033dd07db2a783d8e9047cfac55410000000000000000000000000000000012e743a38a939caeec7941acba1fd0d18982dd2217906b9029dee933f3b55d44c85b49ce8279c58742b0b3b3e631bf560000000000000000000000000000000013c3b3ebf45fc33ccf37dbc3e88f8bcda87c1eec33dcdb2115640a7398114993a3979d0ca883f96345fc844054bb34e50000000000000000000000000000000008c378d2a8566e416cfd98edda6f73ee8f847c647c8c459878411d564c825d330f725cf36a3de497b7e05249abc8e7291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc651734d4db0303a9e6878182c17da646ebceda8b43366a74113ba1aef62f38d0988739c7351624030e7e8c891ac3700000000000000000000000000000000115de0caea2b1d3a168d4b1e89343f5db4bc74da8d138400f3f4fc432c7f732ee089593a192b9f56d5fe2d15b89b727300000000000000000000000000000000016fae4f4134937e909747adcbcb9ff0dad282fa4fe32f87a019cd3bcb9c6b266277cb858aa5aeb9230cdcec4250bb45000000000000000000000000000000000dc45d58ce36d265f110d866af1f4e13cda3c9076c8cc8648cd40738385be64beb680feaf6e3158edae87e19a7e96f311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5d0c277b597f86c5a0e2fb0b3da8386f409d1935f3e2b5a2e4d030fa12247c7d33459e4f8641780aac84c75b96f58e00000000000000000000000000000000006b9e66cfc126e4da7f39093ecd1591af77cdae13131d044eaea775528ca2ca7e64065c375edbae365f5c6fdbdfc055000000000000000000000000000000000233cae1335c93c5727f63ebc33d488d39d5a172df4a7f565b72e71db5eeefd6468746b969fa3895daef15c04c9de4150000000000000000000000000000000009fd9c975726c3c99ec00adc91124a93bc886dda37140eca2b492ae640f80e9197548f748a3ceead795446ff21933dac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f7942ca574d94fb5be40ea228e52a4a01f657fc09e8b6a7d42ec700b0fee7844662f330fbfcc31e9f2ee7dd7aceef700000000000000000000000000000000090967de755f84727dac7b24e04095690dcf52783e5784ad1419e7c2041a20ef1d97cac3fbd39f87a588cd6da216f6ea0000000000000000000000000000000001b3c4ff74aa157004dd3dfe52a7828825579098b77e5bf57bab7df8158303ccc7d505773014e54e574d1ded3b038cf10000000000000000000000000000000015b567e838e4fb2140642f3d22df90b384364eeb7db835725c03bb1d8ab0cfb84bdc0de9e0598c8a91c40187aca5366b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001027d35a2a426ef27e5e755e8d3288cdc33a62e6e7e614cdd8cce0e4cb8995966a9bf06d649701e500d683fd25e19d0000000000000000000000000000000000ed67981993e50e897d5f8a6de7f9870ffe508958ec2e1b6606139d478253fe5a5013deaba8a11678fa91d03d29257cd0000000000000000000000000000000017648aea20f16940557f5420a688e547696e58a6c4cbd665c6666886eedaad7f9e6db67f16722d3bcf8d261a197295e700000000000000000000000000000000080cf4d4eeef4eb7f36d3cf312b4ae33c4182ae0314d4a4bf0c76e1a6db03faeb3c4682c8cf6758a2fe635b9aeda6cb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000736cad24713b435111346b91659de945ae352904cf3bc5e4e8cf2b58b0c33a447c48455df9a9b76d0de8926d693f1e7000000000000000000000000000000000bb1e1f0eeabe97ea3fb96c1719585dd63343ac84518823e14423717ac8ed123423e8655085704a02d08b885aaa2f6940000000000000000000000000000000012291e706597cf8c33f09830e757498363532bdc3a479f0788ff8a5626da24c195662f8162079520f22727386e3f71fa000000000000000000000000000000000bd16d235d99633dd4519e8797e9d26f3e8d3912123d2cfdec3527ea56b1675d7c5592191448a0f1ab2019776e370ef11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123bab130acec842184f52a8485f83edc8e89d6982df2eb4dc5fdf8239ad41d795946c5b10e431698ae2a9ac53153397000000000000000000000000000000000abc22fa93032d6a2feca0b84e2a875d6a88e695de41b8ff1c65c76d9eb78c2b5590bf891d0b45e5f887e72032add5b600000000000000000000000000000000164d4bed37ff4aac1540e7a11b3d7673567cfc8431c9123417c7f8fa276083136771eecde7f896c18bfdaebbc004238900000000000000000000000000000000168cf6222f7dcfadecfeab5ce2d4a6503fe77e65718b39ae8ab02e2f75138419be60775ed908c07772411c1dc818d8ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007bc952dcd24b9c4e1006e3a3e8ceddf5fd1ff7ffd9c6af89753866250c9882c5fc1c0b9ad69012b4ca6b5e7f593d9400000000000000000000000000000000019fcbb31695d18eb5a64dfe2c3ba575da2cf2393f3d6e66ec201bf5c7e904b9f70a25e470ba16f1439850bdd173a3aaf0000000000000000000000000000000015f534d3a7331e1ae6d34f13a87e0bba435d6a674c56221220de63b428fec59649d5c6247963b7bc3583efdd04a17b3000000000000000000000000000000000118f2c13700ea22ffc79fd7630c933496e02fc61dd4465b549bc7ba2a21d02b2c08bc37e12eacb6da94126beac48f0961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180ef9a99379b6263c44129c177f19260a976ac05ab80227b0bac04adbe82f968afe56e39366695cb457c687e122e62b00000000000000000000000000000000054d15fa41a774bf1c99e1acfbd9508bfb8f44b155b513b871b519a70e535977405717a894af1c365cf95bd14ef09bad000000000000000000000000000000000ba5b049fb05eee77bd071d6da31a87a3871ce21f4c2762896a2990384466fde12f820f464c5d009b4617ef4ea04ec3b00000000000000000000000000000000161bae716290446d85e89675d04c68555fecd0cfb977d6fda4a9d5d61e15a520fc333b52988e98893a8155a7780eda761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b8e934e84219047d9a620f5e9632d1193ebaa7d68194d80944ce9e100b9baadc8001572d8a28e1dcb0f450527a2e890000000000000000000000000000000003bc0baacc0e11cc545fe0bc5d7a6c8827f6d2f5594310132badf2aafd0d19d6bb6b9b24d52976c81ce182ee1e59a319000000000000000000000000000000000208bd3f0e94480070900df3951f8d95a759ae7b569c1aa9c1755abeda37ddc567ba94a9bf45c7e9822e3b8ff907843d00000000000000000000000000000000098aad8960ab71bfb8619a8c4474f1ae28a48c97e9c614e0888be6c84555cbe0c030f363b55144fa4c3bf6c16e16e7ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000510699e9cb214b57dd894d926506d76f760362df745356cde004a1241221c3c5f954306e18869cc020cc1078320ece2000000000000000000000000000000000fff4f28847d8aa4e965b6670645e5668360dc1dce32fd122712f308a70de0936fdbb7e455f3b24cd0213f9b47b01ada000000000000000000000000000000000b51490480457f89dadffe19b0c03e48ebcc20f84c027166ecaf2ce09de183efc0628479068e2f3fa929fe21fedccd6800000000000000000000000000000000067fe13f7da4d53bd158199af2981760771aa311eae69e8870030a7aba4a38517f1443d2780af9088bda0533ca74da161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012e45d4ebf9f9b7aac97334a4b8782f522909e05c9ee7588503c64ee3774c40f53a91f27a39a2fb7e28b58b9d133cc8b000000000000000000000000000000000083d2c1af7b5c4190ced6fb566e85e33b274cea7ab3c7fbf4331b46d09be788c696ae1af1aaf050d91044c47fcd177e0000000000000000000000000000000018d806607a6abe8b31bd96b0a34dfff83e66a9d73d788f0cebb16a6cea1f8a451b2bd30a88e648c7ea00ee5de1f2753b00000000000000000000000000000000102b23d5d708d17b4fe8e0868b09ad9b7b37295cc2e14b1c6ee4b5c4ab4af33b0f99ca4d87de38385f35f6630b7ee81b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ec23e9c4baf84b672be2ecd4db60572da83a3d4d452343e6043921a6ed6ec93fa2d6819945606c086ba9ee03998eff00000000000000000000000000000000079177a1fe610e33cf8e37512f71d8bd80ef53b1500889b50773334b3fc5a61417136c5a4fcaab405cbb1bd7c8fb30650000000000000000000000000000000012047c7219f9af5f30e68abddbbce22e6579f2074512d796231bd5dd9e058b0bc16ab7c4162b1f97300455bf6884d8d2000000000000000000000000000000000319ce6412427e20d85c6e36c365e1405ba8fdb689d550fddbe17d3e8dfd900e76182a6cd02617f7edcab84e4bcd67e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9a6a548753c33dcedf77875a0e8835a41c1162d1907d59ccc32b85975c6c1a817fd6315727f21f9175fddec0ee28b000000000000000000000000000000000062a50907dfd0b1d441d4fc73244605e2570483afb608d1632c80fc30144e4709c2d55f9f647e9b09f7b0a3e5f5bf23600000000000000000000000000000000168ffa81b1ab744e941f04f446e9a7b29e499c8dd0d587afcd2c1443a28fe2ee42eff13d00096f2febfb556fb758126f00000000000000000000000000000000189d3ebd84691e001d40fe2fdbf35f7906ff43d5038528eb907e2feb1720fe39a9e37b83a896e50d085e1a4bc4fb954c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008258d5ad6292657fb5f7c661bc61dab6b59abb466f85317fd1b765bfcb2f95c5edb728beabe8ceeb702a690765819100000000000000000000000000000000011c735ca7c5042ef18faee3d4b26886741f25d957e3426b29c706c64f285db9688a9c95c5f3e27cecc5416d45442b3f60000000000000000000000000000000007ffdef518946ed28c840c1f1e4af58c25f6c5351e119b46fcb90dfcdab41111ffd2d1f8df3144436455d4eea6da65960000000000000000000000000000000018deb3bf9983a1fd937a296325945aa34e06cd507288a9aafebd940f5ef6fc1caa2eea0d0d8d3e51bcf822b6be2fafb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005425eeb6220b311da9fbf054aa48924e72b58ea713ce540197bb909318b1cd259a051907deb6287e24f7ec180ce1661000000000000000000000000000000000913ad2ab88cce183a0281389e3c5b942bbb857ae2ddb18227335e3fdd8e7f6e6ebeac3bbc4bc6eac4c0b12ba31c2634000000000000000000000000000000001733be13a4a6aad302fe202b2b32f14185a5bc6d5bfac1005d09009b45bbbd1df6c6f0bbdee5cf9354f610857a312726000000000000000000000000000000000a446de1b1ec697d826b6819f3ccf8539f973410d0cdeb36bd139cf24571bc20529e023dce524fdc39518dba50b824a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c95827c95d52e65cd9d99a0b19fe20acc27dadb3f536efd4c6124adefd9d957246adda7b824fae8df633ab7aaced518000000000000000000000000000000000935c4e890dd6710dcc178701a3e8680a3f4379e362427f6ea4a4a08cfe05f5a2e85d099a0dba81351b37cba822e898a00000000000000000000000000000000183e8a2562d8356d312c36313e7a2e224f3b171f0ce6bc652843ed3d5abf5f4f87272da0008ac65cebfcc559567a62810000000000000000000000000000000007e5e6df50a1f7a395f77ad166d205ce6640f5a3c47afdde1b70ba07eeba34139607aa4763aba45d82d1ac7b95783e931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000301dd736cc81ac82a330792e849992d1b1914abcefef007da494b3ee3448bee05f103f3112bfb4e7c200d9d7c0e8e7c0000000000000000000000000000000006e0f298abafc46146e65bc7f733c4c161a0fc9f7374517438997a3f0a583da5282c43db2859639cff7ba9c6eb664e7f00000000000000000000000000000000097b16c06bb885675cecca2bc0413c9605911ad7a32036e9ed13e22d04a9f139029cdb5e1cc9c19c6ca408a7f981bafc000000000000000000000000000000001142cd3bd1b89020c0afa682ca407f71440cc77a6fdf9f88cc19b134bd904c008b3f13e7b7dcb0fb47fdc78ade63e04c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001553412a755ca7a354b4f14c670a0d4e41a2989780ecea16df3ec4a06071c5b7f5f4e2aa9e21a74a8f8e9fcff0d3df800000000000000000000000000000000006f91acab3f3e47120804f6fcb8c01411636b916f9811a4bb804ffbcd084713e6135a80a08b6c4ceeb5f1d7e9282412c0000000000000000000000000000000016a3f21943570dba5068fa50de758ac895fa9d5b1034a2b6e3c6b3c3ac8482f9d5e3e5801092f7e5d00858c3f209cf2e00000000000000000000000000000000079674dfd4eb1ef4caef2148e3a632482e8f9452d4c21deaf4a543fb23d667447e4dedd02838897b33914bec99554b9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000999e4e00bf45a7d30faff2fac3140d30ee40881c0fe49c765ea9f817f67f2a97d07f6a51a3f01444eb661c217925f61000000000000000000000000000000000f5a0b7c3ed1634d4aae86e6fa88e2ae8a908364a27fe6d1e974e33ed0c22b8b0bcc8aa1b215c909a3bacfeb43608cf9000000000000000000000000000000000df8c7c8a0d5b0cd283261e80deffd88324af393b3cd65ec7f0d746d6b80c7d6d0a9ffa5082de7d159f89a4ad5a25022000000000000000000000000000000000aeb8da0e7c5760193511a00dc7a24e3f403e5f9a158f2470553377a4f4824c1554d274ffb43c3c44ab72449f045a6c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e60b03df5cc29e90817908897d7fc4322e968d333906ae688beb15a71e5feede0301e0959ac98b9d86ffffccbfcb104000000000000000000000000000000001555da6c3c96117075531a1d3c8fc3fbe8d154ee035135ca3436fd3913aba3537531a1038901a4b31659c694923351e10000000000000000000000000000000010f1426df0ada5b3ec79137ba46446b90d0c1dfe1c3e4d87d2240088f698896a046abe0c2043787c7e36120c366f39630000000000000000000000000000000013954acc7a990a2e35a43eb1c508a98f7bbcd153a3c29c9b51fae3217a01fe9cdaad543e3c4a9dd849937336cd7edcdc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000676e2c73390a2602def22d9239af9df7029965346f5bf62e40c16f2303a3c1aa7ea8ea3003bf0e7557c72f77e2eacea000000000000000000000000000000000496c5fcabb30f850c7f31f4be0847d597aa74bb30c0c13f26426d829ce6df0658564a1d0f06e1bc81f74bb111939f1c000000000000000000000000000000000795f3de7328773c9560ff55a0b96cc08f3ec305735ec3d3c789447e1559eb4e74072b31ad071e3a7322c6e5e913fdc300000000000000000000000000000000174b75fc43cee85bd5b702775dcba2e7efb7e01dfdd1d1a980bd1ebf5067df28d25eeb84b3b58a62cea9946a48d827b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000491b8431a72e3e3623c94a52677980843e95223b965be0e62365201dc949f61ebd06c6d53a4c6e948a8c54df151fbc0000000000000000000000000000000000312afbcef9ab0f503fde2acd9404c3834e3488d1781b1cb9c02504ba5a140421b3588cce9e71749eef4fca337af9c190000000000000000000000000000000016e9311dcf5f5e4385e01bc1aeb15e80ff4cacf1f404fb98d184d65dc58cd2ac117627b7d2ca01b68666b62bdb401b8d00000000000000000000000000000000152b69b04bbfc6698123215e3580df72c60b243894786243e7ab161c3ec1dd66ee9adf02512a7b69808bf917437890be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000117e4631d82128c697f34ccc504fe19d1fecfdbb1c27932e798e881526699c89fd616695868cb5eb5aa812773bdc03a600000000000000000000000000000000118393f67df32c5f4e300573cbeda3d115056163b8037e49c6cb67d5b7e614f74840b10f11300045d5a2bdbb12bf5152000000000000000000000000000000000ae07a0ac493daae9abcbdc48b9b284d9955e7983a62180f7085d1c22c7aaa870490e647ad502000df64d4761aa6f7c40000000000000000000000000000000019fdda4afd7f3b6859d9629e4e7963c3b17b74b3bfc9e67c016c83fe5b30baf1dbd5b82aea23b095d95666cdd8f7269c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b936da14f827c19202eeb2478dc0cc3cfc7104993e946be07ac3009366eb63cb1b904a65214242fa6e6ef64dcd6f0d0000000000000000000000000000000018eca6b02fb5e5aa27d54725ab17d5c8198f4e21fd38fa50e3fa4b11c72fde69153ce25e2af4d9cf8e47308c9d0579770000000000000000000000000000000006d8f04020b86ff219097f7b221700342b6b8a03be1d2ac51cd8b995e44309e3daf8f03c384ac96bb82932334cc6318d00000000000000000000000000000000111b9676a416b368b133f7958bfb11b7db9bb537fb7b3a9b2c25d0608b577dfc9c53dea6a30b2fb87d2751b7751df3901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c68c9d41ee543fb3742b2aa639027e18412bb29498c15393b117c99998ad4d4a7bb4758b33c5180eab0402028529f10000000000000000000000000000000011cb0106d12e1b5501c68600fbc64ac2825b537f875cfee53802cc66d7373379d182fd75f02bf4cec3f81b1ac6b17e1c000000000000000000000000000000000812059f1d48f43ae146c9774ff63e6f6a8863be7a51e238bfafb53f5635a316e0e12219bebaf84947d230c42693c3f6000000000000000000000000000000000ee1a7869f5d2a4ec0c04666d554ddea0cd95b8ad32a94a3288eb39c72b55fa3c838a41c173369d64a6a0235d3d3e7d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019109c6756eb217fd6536c93493334c04a2889d42d569e4729a55139032684520c47fd059dc395cdaa0753264a7868fa000000000000000000000000000000000dd46066cbe698d67c58b43cee3b0d9396f76d0af8a2d37ee0a0fbd0d2eab23b52b07207447af104c75e61c1844ff2980000000000000000000000000000000012a3195ea56cc3b9839ca96fc6fe308219f747a40cc64d21037ff76c6ac1e328319248ed8fe220abc5b4fa7f5cfcefad000000000000000000000000000000001150ae374d46aacac3f5899ee44f65a558e4c7e9df35ffe952d188035d19d14e0827081758c7015a54c5cbab7d3f6d211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000efdb95daa1dc32f1faa7bf6a99a63930ac91bf7a2417c50e812f0f9817caaf5a8ebaf24ad9077804d37db150cd018cf000000000000000000000000000000001989b01c59456d45031dd73c837c46a18a1e5c0602f0f78e3685f16ff1b068a66601a8e6ce9dcbdf6542fbd7ffecbcac0000000000000000000000000000000008636fe67257406caa75cbd315deb871f0cb4b99cb953a6e47ee98da7960637b340dd17c05581463598605f9fe295e0600000000000000000000000000000000025ba2a380a1b31aea06d22b7f7098c14caa3088a8816bc45f57205d5b96a2d294c60bc6e0ef017efb368da7a3dc08951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007eeaa19b0a784e9c069d74525c9a6bcfebb4daab47da697f38e0e450ebe8bea5b9264e32c4792dd9923d1b821cc98a0000000000000000000000000000000009a9c7bf3461d9dd5221c2c250b53f911b732930508fc578e4e072c3b2668a03a3dd4ca489fd24370c1c72cb15ebf3510000000000000000000000000000000009b5c5935a8745695108602f2214b0c8c0b6400bcaab17bfae9565145445c0dcd0c212354f448fddc1530cc96ce84e480000000000000000000000000000000014b816dd956026b2e3191470c0917b2963b4fc17e6ed2f463bde0d1d549ed51478987c528ab3d9dd3ac31c484db6029e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014cf88b8a310a19cac10acadac6fbbc9657beb1a149ae2731ce034562efe8561652d02a478cf6359315c2be3e74fb1450000000000000000000000000000000001beb10d79840fc88c8c98610f788d82c880d5af50fc72db1774005670f28444a88d12063ba9c366dd46614f281150360000000000000000000000000000000010f1e8bda7fbaf356a3c20c2db310b0783eccc755fc531cc832b5d66f3f3866070b419591aa18247c37d5e2ce3642e94000000000000000000000000000000000abdcffe861dc7f244539548a79922910289312da5330e2b587822f1f668e8e61e7851d4f407b1038b4e8028a9ba9bf51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008dafe40b430f0ad083f6b153ea13fc3d06a1d60d3957b969dc2b1f66a5384e52fe4a91e1b3b350c27c5c59937ba14a000000000000000000000000000000000772234bdf8c375c41d7f8d603dd43e18e07bc67b9755d9c44a101100e6101f6ebe1e0d74bda04840f1c6579de5211b30000000000000000000000000000000018d57a51607f295a3867f58350123d1fa91d51c53e55582d927d30ddee96c9f1980fa12584c92f8a1babddb2397b9764000000000000000000000000000000000560ed1bb3e29b4c7a22c9e4b2667cae858a61f52f560ea453ec4021a47f10361fdbe32c9f757a80ea6a00fed1ffe46a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fdaec6bdfb15375d40c3f6f984b4a7b4c0ed9f14a352c2d88436f52a7324f2a1027dbdc459f2c836ea47b6732f1241f000000000000000000000000000000001442d0b17fcd1cd1b96b556e8dd3688f58ba5ef002bca9dbdafc3c63e3a813ab606a88c5a25480f25fdcbe5ba14dafd100000000000000000000000000000000108e00b5d01e6da992a41e18f4bcd250ed453f948e98e795a40d2749252a9b2aac81f0976c9c1359a63236feae4513c9000000000000000000000000000000000a96587606f9d878c4197b314f6bc5a630ff9a830e72ca00ba3085a16d2a8ec41bae19111c8fb4ba2aaad11c650b12941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001841584bfca3ff8712a517890fef4fef3d5d8c7fcc4e1b86aa8487948d2fcdf30a256531caff574566c97ca8b4edaeae000000000000000000000000000000000c80c68ca1ee72f797e142c948c56ec532e1898e992e8f12efce52a39821bc3207e4756dabf4f52bbeca1564a83216f1000000000000000000000000000000000dc844a4d7eaaa74bdb517f70b140e9262ed4a9dc8a2cbd5a6114b0fd100b00651cf0ca4db0620dd46ce914a336ccafd000000000000000000000000000000001132f03438b1daec8220e48d682e6281e75368fe7baab65a40204081c789bf4e42be42ff03e265e6e61ae6dbea8435901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078ee8a3d04e4903d0d7774be33f80ecb55491846f86ed243b63a2fffbfd71f214c4027a8455aaded7b54a3f9122b85f000000000000000000000000000000000298a3ad5d9e7b1c4ed117d00047ff84a486b9feabcfd58e51a653c1edcc532e7622b95294237d137b91c5fec0d11d300000000000000000000000000000000007bd73966a3425bc1ee9d6e7d5f995551df93e9f2b64eec8e7814561aa36b1c878c9ed9507662411001aaff62d0c0e6f0000000000000000000000000000000001d7db3ca29ee1d1ba9ac84cdfcafaed57ae9b78ff6ee8e06f3429cbb8c359a1c606fe9d15ae99ed04cb52006f54defe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109998905009cb999f6535674f36e3fdca7a03b8b02aa6e2b6a704c7a98b399d8336941aaa3c71ed9db866920075f3cf0000000000000000000000000000000013d976203309cdeaf18072b66eeff494619e1766a0411e5df028285e75d6160f1ddbb1dee762087fea9a20bb3ee69a2f0000000000000000000000000000000007bee56f057d8bdd35a0a251585f471dc77032a3d5b501f1995e52eb90f0e985f0543c8ecdebac223dfb53ea3fd71879000000000000000000000000000000001247c7a7d743fd64d798b0ae036fa114411adc76b3bd47164880e39d494b1bc69bb0f83f74330a1c456b5d1956ad64441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c11343853e9c4eb18513d75cf9f6b77fa22197b56e667e6a7fe4a3be1ee482834e4081c349040af3c95c0acdb3d24810000000000000000000000000000000001a811cb3a65837fcd8ba2597ec0ab27e1a27a8be92f928e193aaa7f6b2ce08bf849af9d88c24b72fcc99f6adcdf7f54000000000000000000000000000000000df55d7ba54e67fceb8959178cbce0405946980041a6e6557e58640347ad9509e8244d6d369cdd9a75fbf3b8912c2d3c00000000000000000000000000000000086d045d3ea24c7bfdc4330f2aad5131b1f8abba92acd6161b2d83114888e95b37fb0c80d4d53a0ea7ce28de7626c2d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b6e5a667142805e1f89b703d2808453e571e788bb731b06f4eba667ad390ea6d87c4cc9953aa8f6f22acf4d9992677000000000000000000000000000000001223ea8ee9697cdebff911df3cc9dbe019942c74afaba9597c1679533e5a8a4cfd5eb3572aa43a89b0ee7ca6b4cc58e70000000000000000000000000000000014bbcffc4779b8064cb13e4877c012a4bebf44ec7a86fabf2c94630c54815a613bda8356ba12bac86dd90815da6d2eee0000000000000000000000000000000005266b5f86afbb4aa17065d03255eaa02b5f4c2b85a6ec8e339cca7d3b8ae2fae09361a31bdc48e0a2787a038fa2e6281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a63325abc6d1cb5c4caddc18032255c18510f13e93e937d2cce58599e64a819a663370fa96c3d8b8b36ee20f15ea591000000000000000000000000000000000a6ccdedd5b691fdb969102807174937039692a6a4082b78df39edfb20895b9c2b7c478b6611e038aae5d195d75ca7d70000000000000000000000000000000012151c07bfd1af5c9ebb76e5b5fde6b3963c31975ba5be2acd53c6749897ce83f0ea3e03d2fa434bd5382a5dc58914630000000000000000000000000000000003cc1a08f580e8a8aaa6d87411dbaf901f4041a93f4203cb4687c0b18d62e00e9d872c3fe861f95039fd7367cc6d789e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167f0ff730889c06edde438a6d806586701babafd03ccc1deb366dcb7c97051b9c441eb48f8062ef568b965b442a2acc0000000000000000000000000000000007deb2cd4fdc3562df41f517e1e05e444b05c2f1063e7b4c1614e5336e8998a5f7423be09990430c07135797a77ed8c9000000000000000000000000000000000f06eb2c2e74aa089918e012607e6da6eea4f6c7f1de72fe3eb8c8c021db110c8f97a21ca74838ff888317394e6bcb95000000000000000000000000000000000a295dc5dccb8986f29a4aed5d2e704be649124d9df4d039dcca9987db7e87041c30f60f7f7b6fa5f028187163a21e571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010adabfadf7d1631b1237808c2103bbdb0e033b831e8fd23470b4241fe660203957f502207c66167ebf2ef1b5764cbc0000000000000000000000000000000003e5b25259122be028ee8178fad1bb8bc834b3cfa71d9d2530eee683a812a5bff24cfada3d973b164d1b8bcc1394bdfd0000000000000000000000000000000017e70f567389d72dc600bb4df7e4319eb44b367adc70a0b7fe2040733cfa4d156315101055fad15b6302dda8ea005853000000000000000000000000000000000f79679ec963e55be2066336623e3aee4675afc4cb5b1ea1715cfd6e2612bb14029d416a54375b4a8eee83e04b5aefdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000176f95697d95b3920a99aea6a68af38c03f1e20476830a4471938789ce8e111483cbd270fb41d4b3a009f678f723529c0000000000000000000000000000000009c42533681e7c2297bc57a35d01890c3a23d4becbb19e4ea5fc7a07e88679e1c328b97f3e151494b5f0d9938f85e2df0000000000000000000000000000000004968e842aea3fb40c11baf33b00816f8d8b26d84ccfadcca9c6b5b2e873a1858abead404e1a19aa59b4fb4f0c8342f1000000000000000000000000000000001247a08562ea50581b0545da7fdaf40b2ea4587d6838149d1f9eeb78345728027fd2658ad577806ea5bc79d1f04595c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b91f33d80d6569dd2b047ce31f5df752e6cbe326f58f07ad2655fc083ffa1fde9510d43c902e10d268506717b19731000000000000000000000000000000001338f4b650ef1ea266b712aeb1a8eb8e68a57f22fed737bfcdd80ce8bebd36f5d02744376b4d196a6cda89387499270600000000000000000000000000000000002ac28e9d6d48ca54957e8982e00494d96d95cfcda61e78aeffd9561082ba783bbb21f4bf4859ce06c1125bbc470694000000000000000000000000000000000cba2dc2b8c45a02c5d90431726d030c97a820f4c04d9704ec8d091abfcf43d4208eef3d4598b4b5eebdbc1fdbaa32b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d18a19f27cd59f3d0f8728e4563a296f3593bc473ec3ebd8eedb49d21ec42f8572df213d96acca23287f2973bdfaf900000000000000000000000000000000111b2928296d566450c4499e3bdf1a2eeafa84e78b671c176c8df54a7308b7167730cec98db889c79780c0ffebec636c0000000000000000000000000000000018bac4d1649c2bcc1e9c4d9eee2625b79da2cead2a9b23388b87f1cb4db42cf9dc4698ae4dce98ce9c11e8913e32c4690000000000000000000000000000000016b0604b37b08cc541812657f126c8eff042a909401e65d699f76b012408b402419707ad568e66d0f5a9db31aedebd491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157f59c2710056be69998ab705af9a19af01a3386de568442fe1302a6b3119c6f5db7c1f74432b74644b044074f9b1f1000000000000000000000000000000000cabbe45978fbcc9f4a898bc0143f336b972afc4e9ee8e75fe69e7ac303a36b57ae1b08c0ab15f6979bc831a54b6296a000000000000000000000000000000000d40a14f6cd2008413027908cd0f17c7ea5b3809f016754c1472b8a326d7abbeb12deb351c013e01223cc32c2c70e599000000000000000000000000000000001874910b6e36f1d067a6320acf59ad21edcaacee5e198a38551e26ca3ee0a33b26a5fe9c322873425b0c590cd8590b1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "000000000000000000000000000000000cb25f65b284efb8a6e02a5040105e87f339d261d9f81e3f152a65bfe9665ebf1b01aac96a527ee79a00b58fffea87ab0000000000000000000000000000000001a42a5963e65742812174174ec1a1d28dbf4b2e5c11b3e6d26779e91a81c8680484edf5f5288936b0365e184292030d00000000000000000000000000000000041ba796453f671c3f4d81e1ae94388c19cbc0233b15228b941628803ad9b6b94a2ed9e54c8af448428169b93e3d194a000000000000000000000000000000000c241833e69b0bd819f24c754e5726bd9afa80631f643550a21324ecbb362a086df145bc21470682d0363270b9384e50", + "Name": "g2msm-128-jwasinger", + "Gas": 1002240, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000ad11bcbbbf592db9e0bb0c97033f732437cfdbd76261dec844136838fdfe09657711a1db7652b0d13058989e876de6d000000000000000000000000000000000872027f5f6ce0e86b926d25ee4763771d276e9f09ec4bd334fdbe869284df3542a6d2fab481ce3d16d82f28c64030490000000000000000000000000000000017263ac18d83252ec4bc85b57047a9ff2902e408f2cbeaf1f88c2eaeffdfcbd51918eaad661ebb0d7634e9d6ff0a0e990000000000000000000000000000000001d368165be8de0cad05e3e98c6526df84a28fe9838386f8ac01d6043cb4d12cd6ddfee625e8e25b03540e9208f384b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000819d94543cc995710e749ca6e874f41adad6ef823ff96ae56af5e7fa510b36a1643d99f9d3d681e6b4197cfd7a858730000000000000000000000000000000002fc380d5d2f76352bf885c442a291bd3460304f9f770a17cbaeda77ceb9bd895eedca323dd2ec39042258045e408aa60000000000000000000000000000000016f8bf2c52d10e32059231b33cc9272d47ff0a77ebac97ad847c5d5a4e2843ae93d207b8330fa76486619ea31addef540000000000000000000000000000000009eb35e34d0311fe5803e2bc22eec8e45c5489f097440848394859858398f3dfc1b32a63031ed2f4d41339fe821c932e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000173252c8f9ef77a05b9510dde93c778434b30afbf534b3029c3e4cc9dc713628bae6ebc17a6b8f5f0d8b88751c3060300000000000000000000000000000000053b2f2c539bd4b4fd76717d2e8e3510910d3f0b5c41961edcc0033d62033c38f2cce5bfbe75b3cfeb1850b5e27b45d9000000000000000000000000000000000b6824b049a59757edc31438bc32b1bfde3056fb07cb3aa4f4b5cbdb2e06f93fe5f0c90bbe1c246c2bbdb42f926d8ef6000000000000000000000000000000001589c2238bec47aca604dff716f9ee389e0f554c5c1f20e0281a79eff41f2ecd1264acc12e5a627c875fb55c2182b6a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb31c82ace608d185f70b387ac5c679885a98cafad74eaafd4c9780da7b5c07c82710b063aca870f6b200cc666bc54b000000000000000000000000000000000aa43f5026eb7b56f1c8af016a2b86509ed822750862b8c264116af52b05c4d5f730a9f9fecef13784ff5705aa2bb3680000000000000000000000000000000019fe715a85302072c2a2d8ebccac7996d3371ded0ef8c3bd6848a06b778a6b11fdbcda1f9b5242dd1c9149703db87c250000000000000000000000000000000005b7bd38dda881c6d9f39d4073478bd9ee57b91291add017788f71ba0bb9deec24c955ecd1a1fa933fe00cf9a912c01e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009dcb334e962638f3b65daa96955cd28d709c367dd6b619fdad4b37e52f6322dcb739ece5d32488ffec729dfe1cd7bf4000000000000000000000000000000000692e863b1ac1828b2fa2ee7218395ac1a5971e9bbbe97d156f13eb6e45913a87123c3949b58f21b3fb5c3cf4e78765b00000000000000000000000000000000178df65da50877f327823b57f930a0b734bf81c707c61b3a83eb2b9b6686cde4fdeff5cf2fb25d76d916bc058c1eae8500000000000000000000000000000000123841e3a9ca0878538fb2ed4b6ecce2b450325862e6ffb442ecbe1c6c45e6f757d47ad20b3548228ae76f0b37c6e2531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d671028a0f71c3f436691fa3cb72d606ef0e5154b52f1cd699ab8f372f397c93dbaec751e495b68364c99c4961499e0000000000000000000000000000000016d183df74c8e6fbb9098ad395670e94c21fc859c6859dd0fbf9187c051fcc4ad3cfac16db6ba419594240df0849920b000000000000000000000000000000000f8ec6886555f4fce6421f9b6e5505e349597bec6038e104dddbb4f019317246abe7338192d5b226fab2479d495ccc4c000000000000000000000000000000000816900dff573ce3ba2fb3fe7d0ad7c082a8cebc2803d5e3a15bec2c69c4e3db330a29a4926fc710292708191ad38cad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfb0993d237bbb255c6efd7c24b2ebd0b0f49823c4ed4d44446c338183d17e13ed5488ee58a7b1f9084bc81fce4bbd40000000000000000000000000000000006b0310e7aa60323868df4a4228bd8b813fe8aeafe0cc1ae7a8d2efeedbfd30a6fa7167f9d9d54bca11e6690a2c7dc3f000000000000000000000000000000000d06cb585e868bb1e39d2f03176ce5527859ce3c1bb9a41f79c505e2d2890cd4323cfff606557690647e22e084a99c85000000000000000000000000000000000e883e559db42ee7e026e479a8306ca9e13cffb4f9c44b85beb7f19f08d928388aacd9e5706859dc95faece1011719ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d4f1bf2343000a14f450a96469dd310b78d975a32bc83e2a6ae0faf261ce7f9a4e2f75532a65b60708e4b499a9e01700000000000000000000000000000000118262d5ed72f0433eb8e6207c922a26b2ad218f9ed6a0aba77e1bbd5f1fd2cb8907eb7081b37f86e42a4f6aac7161be000000000000000000000000000000000796b9f919b97e67a7739cdaa35501a431d295d13940b95b30470269cb7326f4a90d49f65e2e0a21689590c61670cb0600000000000000000000000000000000168c9146e402259d426b2e2b1dee9b29eaa3cabaa6392f1a1912a1c11096b6c927ccf22ed8918c0876d0d8d126a0a4721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000074e3702dcbcc68b3ca7cadff7c04262e883d1a25cd92faa5a383f01265259e1ef023572b63f0405b3c4284c6bab31bb0000000000000000000000000000000012faab84e08ab0b2f01e41585f0324fd1036fbe1b85c01964be9af3c582d72c9f1397807470de55786fa68b30e182fcc0000000000000000000000000000000007adfbf062434f76bb12d90467795f648d9baa2c7747d19e669a28859c62e38f3a48102e5814910d344ca9c98dfcaaff000000000000000000000000000000000829258faea86aef33925448d44746d9a9b8266df6dddffb72130fc0011c7da262019ce35e1ade7cf348d31748612b921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001198c37ebdcebc10b1e639310dfe3919f59459d69bf6edb12d086b935ea2638dedf389ceea39ef9f6a8ff202230cd14900000000000000000000000000000000106cf9a8fa8ab304fd917aff5bda9de6fbb338d548dea56ff1253b2a2d30a0c781c4a5ad5f8e31f41fadec3d4576598500000000000000000000000000000000117c3d0336783faf61724007c78ff7f0f038a35736e65ecf483e81f6b9d5feb5c587fa6ccedc1c97296e4c233c096ede00000000000000000000000000000000004ed03edf1b036eb4f7fefa589fdedd2fe843a8909ab6cf1fbf47dd5d91bcb067c0b3281c8d772dbcc8cef1256d5bec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001d94f333d893e0aa4d429cfa4e6563d4d50ea44020195cb06e5fda3a0a10b0d9eaebd8c273e89ee2b78411d6d2440d0000000000000000000000000000000005a1ad530cb9b77c22d980fd6d2a577230484380cdef7258986a93015ddfdd706b85debd37c183285625ca8abebf8338000000000000000000000000000000000dd2c8de00df7395bf2404651229415d4267efbb859bb340b1e4a83bdab7a63c5828ed6d9dbf41d7cd0447e2e8c03dad000000000000000000000000000000000205de65e01062643aa52fa84289688ae63c2d7c0e1af7e1dd28793af8bd49354607c6fbb1d003bd371d67ecca245fd61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009a6f6881a56cbe02c718920b0adc7ede32098a9aa85b2f8f6feef11694bab41c0469b76299cad687310ce9da23180d0000000000000000000000000000000019a7cffa4b3105fa424bf069373fd5aac017bcba1b054daa8b16f0b757ee26decdd8670af8556a50398f56ccadd883ca0000000000000000000000000000000010494b89fc3f5daea232059aee0efc189344d36b946e1c83813f4734b4fcda3d361e1d1389e6d114903ff5297c8bff320000000000000000000000000000000008167abcbf9d09a96476742db3c84b372c73203257846ef2d2fd4f8802f03bca21650a5503e242582619455d8a10b81f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173ce95e28c993543e4d9ab1f3ede8b0c85226cdecd2f97022f411d45c8122969033d68b4445387b0e433d0a0af5c57d00000000000000000000000000000000199b1d4e20fffa301f4c0c00d61f215d057d15b268f6fa5f9685c8ad5aeb1e2bfd65faa2f04ec0efb8d857b71744063e0000000000000000000000000000000000d5ac3d2f4ec7d5eb12f0f7e2389cc5c0d531fb8f8f913f5fca996e05d761cff58989465395430268846c270db6ee050000000000000000000000000000000012d196a3af8466b4d9cf0b5306821fb79cdfafaf347b69b623438941c25e7bf5abe14aefd556cb60d1df48331d4a86541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe12c7a5ce8e9d69a14e2b31a4bd3ab0f5672186f0ac5107062bc5792f4e449c9db66f33b9de8a9c527819e7a0203c0000000000000000000000000000000000481511be3651ea9ba7afbaffa7b0d9c9df7f2826e259d0fa76e776d81a71055908478e93d67cfb91b342dfbd130b8240000000000000000000000000000000013b33e3efb1a90e005873e88767ccc2fcff2608513334c23de0ce92274354a8cb7c9bbc91a9186734990219313256db7000000000000000000000000000000000959f773ca3180495aef67ab2c7e3b60a6d2f3b2012ef67492a721658a65bc8e9640f4c446fbca486a572a3a450230e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001130c03fa63b0be2e6ca5d70b8b66190f6db697ffe4888660966cf7966218461559d8f8ecda4cf5571116fb6ab5a3476000000000000000000000000000000000f7c36acd03a15d0a8223439c400d99f96e659771a59f99731b4ab2215af2d100bebe079cd1f0be338712072aff189b900000000000000000000000000000000068ceb20758dc0d736dcd957db8d3ce1cdbdff1dfe3cccec3aede6c12afefffccec65585b75050051bfdc4033f262d120000000000000000000000000000000014a30d60a368c79c0a080b0ca879c752ddc016b5a2da551774a8c80254e548c24ebc25691c978cb0e631f242a7bc5ab71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001064014f60540f73b24bd2af7096ea0bc5a9644460406ee258bffc72b79a3e6c1b8569f70c09aa05dca03cbe8d5819b80000000000000000000000000000000008acfd7e36dbd4647a6a5e09c24a3d633162e8e774de3abfb2b4266c7a6da14437cc0065c2a3652ced9fa4f5414a4272000000000000000000000000000000000a1876e0faa2d6098743468e6a9863820b5ce85f7d16d9baff0f8fc125b0f1889e3e8531c1ce148ce48481d8168b62be000000000000000000000000000000000d2cd6f7079d58685ab8bf4e53e84490656043ddfa54ce6df7da75e96ea963cc9a4238edf8344531a84f2cdc198a420a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c477619f311a56a1f94a47f675c40b7bd3433c1d44170348d523ce393fc084994a95de74f5673cf8b2e57ba6036a020000000000000000000000000000000018004427f9a2f481ae6416268921f34343a7dcb4ce20a9f1eaa681964bedd75b05e075a1afe6ed1251b3b6763648521b000000000000000000000000000000001647f4ae2f905ee9576e83fe7891bb1a92509e3616bd44d154b0e6e425767827496a9983caf359a958fa0d511fd8f47e0000000000000000000000000000000016cfe6abd168a9ddd49a05bb8b5ea76edcf67fccb5035d8059852249fb47171ff4a44ee8ccfaf23972da4aa3862f81211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000902476e2fabfc8467068f438eed2f2b79c5d6d12f4551bb6253274491a7c41c82ac5f2d3999e07ad24eb19cc5a3eff90000000000000000000000000000000004ba2aec8fa838c20aacaf2bb87f552d9b312bb15132e2578052605818f4ee13b6b918b5fe0bfce6cb3a0d222530c2ae000000000000000000000000000000000a422974a2199fc5409251cd337208e4db9fe131fc82a2cab283c06ab8785b9d9dcd15449a03083f8f19fafb05884ec0000000000000000000000000000000000387ad9d31f6f292bf84096f7bf14eca71ea71a20a601992f3fcbe9e90a45cdb310e9d603a611a72b47ca2765410dedf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5bfab89ffa5ab018a248b6cd5689d2c035bc563b9c006b00ef73c19a29b8d2ca3b0433e9923797d7e6183b76f7229f00000000000000000000000000000000001722bcb0d655d5517cc3c73b11a2f91473885d9c7c7ab5c16d3461f9560a84e116eb8bf17feb68c100c34e7c4f6f6f0000000000000000000000000000000015833256f99cb127eee594b08841e4257740860e72641b35b60f280e2427fa2fa912807888c3b3e795f9b156f61021ba0000000000000000000000000000000017969067f014ccda9420ed03e09a4740674e37dd9766b9260736d471c4d99431cf93c4b23328e02d7137a78ca4ba4d8c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088c8fb1bed82a11c239bd902fbf56e49546e0672994a24d3ff29e12b61e25161d21e89b2a5d4423c26c25f64cf94bff0000000000000000000000000000000017b2b65cdaade32d044cb98d5f8267e4976d1aa5bb72bacb4d92ec5a1ae4643ad9470ea7e07ce298691c0260d192f47200000000000000000000000000000000064bb96fef71d3f5fbecb02424771044396bd3d95ac42de68611e85b34b05a3f39754d0a781d406596b89d92df6f590e0000000000000000000000000000000009019fbcbd5375ad5564fb9952e101b17568995fcb1125e2f74bdf849a0042641cd56fdc9ce3b944d021fb09587762791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d244238af7f67fcdcac60b1cb5910dc36c213b39df46401ba6b85add951f30c0bf552e62d8a5d1f4af92d7a35a1d2ce00000000000000000000000000000000149bf1b9434d0350b75c9035a2f7fc60e33f5457194d2e61b9a760ae3dcd610b9bc93c4063aa81444bc5ef7c960d85a4000000000000000000000000000000000aadee2641fe7106361a441c9da151a39bf483d4ff511c903de64121deeec8d30d0705c6c86df27ef340f439be0db7fd00000000000000000000000000000000139f6ba23b15359665294d0f8bb5db7f3e134b7898a83cf8439f39791fbb7747a9d971281ba0b598e26fc811fdb43f141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012155c8e851393402ae6098089fef68b544916c2af46a46ef0b9daf2ced8c86813c532dd0aef54fe57609d2974a2099e000000000000000000000000000000000a53b852938617201f6a0920854130712a3e93e187721373f66836e64525105a0ce8c046c2f36a8b5e9eecc161a91c7e0000000000000000000000000000000013ed6995a4b334a220163e0360a4fae4f2f89d83816c4fe9f91d7c97eacbee4adc5636befa99422443030a7d4f5a39220000000000000000000000000000000006846ab5b892b54e8598bf4e880dfd1c99d059c2762340e1be60c5b42181a9b05e0f816ab2056f86152056400deac5be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f296d3cade62b2af314a4df35fac58eabe8b4ff643c218bfcf5e040356a48af5530ed7a09db577e25cf7bf4e2489a9000000000000000000000000000000001209e11b1e1f50156927cb574824b1ef638e7e21de50a45988e4a633fa331e037d5bb415f6a686ebee273dc66419d3470000000000000000000000000000000007457bb3dbc9900b2fcd4884623ab8ba2f0a2c414811038f2fb547a15f005f6bdae4e6537b560b9b88f506c79034f8b50000000000000000000000000000000002e98498231943142cfdfa5e429030ad5f7171bd09bfd5a9e9a72ce80177f6e9bc45c97b062b375d528fb4c4453f0dc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d74b7429c50ce597610b579870590ee92893eda14d9bbb3c8e1b486758e5409682d20ba2256586e18040699eea98f5e0000000000000000000000000000000001af81a5e502d6acb2b09c4fb57a6e37ae31221b1ef182d5377b6a132e52cffc81dad800eaf31c1bae32b44065437eb70000000000000000000000000000000007a289472e7bcdd44f1dd89df7e0a4300e4ed1b3ebf8cb69501d96f4ccfc5cc3daebfb5a0f9ac9ab4f8ed696d58093320000000000000000000000000000000003b635213d689be8c890372fcc03e80038f9f22bad8ffb932e063831014b0a7aaa2c161f7dca216185933e89cbccaa091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015481d84f55a0aa9a7631ce320940e203a723e0b2b430ca12d6d6a7b1d17389305480c3c6e4aac5ef5f31141fb9742c400000000000000000000000000000000195abab435ea8666c8cd86b364d592a5a287a29b126d99acfb44a49b4cb34e0bf94ecc8f01d4147b23f53e73782ac96400000000000000000000000000000000158525f940600794b63f36284af5743c4871c9e397d4aa163bb63c5220ee0855c2703241998f7185aaa8f31faae01596000000000000000000000000000000000ffd1cb0e142d53be55a7c9d4db1893e317ee45df5b5ea2f55d6eda640bb566c81d38b58edd757bf7fb3c227a3fca31c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c85e5eec757fab12d7df2b1f6d18d8439749f4aa520ef7891c29245d0f54554b15b5aeae5cd3d52767d5648fdf85140000000000000000000000000000000016ff0ceb0af2f932925fbfe49686bf833a095a32f2a0e1c04330e4aee6e6fad6bf2b027c4e5f6ae6c0ab9c06ba4ebc4a00000000000000000000000000000000063920264ae74bea33d625175b032171d6412c58da3c17c98338365bfc14ae20040de40a78c681a632e843891f3355300000000000000000000000000000000007fdb9c61b9591f607bbd90225dc2c6b5b439344b163c038fd0fe7d26af5fdd7c7bdbeb99c709408712d78d4d73ccea31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e5e35214db0789c725de8dd3b88fd9a6947aee235b94cc9d5e7ef8be8067ae55e0ad4dd5320755af04b4fad06ab6470000000000000000000000000000000011d67d493677b4ed0df628e1fa2e6972651387ba2386026dea21a56e87629d71efe1c78185b6c59163a3a69e07f95d63000000000000000000000000000000000325f09ae03abf48592bc1be1e68b0f3324aa38e2b4a415d127fb0362ea152bc5178820fa184b4fe96f91c27321cf31400000000000000000000000000000000113ea4385695d17d8911df9196e89ab05143b51def50c04fa4edbce7b0e550a860637d0e5feee921ccf56bedd7dbbc551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191534c9997ebf1b209f0010e189dba5f875f6e8fe4fb84f8b067f68eac17177181cf2e18f97f712a4682db35a98af320000000000000000000000000000000001f7180a46254a353cbb66810ecae841a3b16bc5678196a32a8ceedb647f3d7779ce7d4674ed1686186fa98180f0ad3c000000000000000000000000000000000203cac9d66e2b6c8a79e6768aaa9e42c87f0ac07ca12f3add022f4e512921e80d750c26cc3df54619fc1555f0c8295a0000000000000000000000000000000008da29096db7aa601c67a591de8fd4fa8fcdbe1361e7a1b9251f7f66d6a338456e80196ec562176b8e73a100ef34ebb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e2a630936f77c19ae45d618f978edc523e22d494743694c43e69c24f00beed6693fa44f21fdb0e6054abab1325c2a6000000000000000000000000000000000365472a029c53ea32f08063329da918756cb226e5bb67a0db2aa82f668d6c32b4bd4e2331786c8fe82045d7937fd0330000000000000000000000000000000005ff0ac051d6e06b8e4a1dd0dfe0733dbbb3195091bc98708945387993d4b561b4a69fc9a46aa5486691e94398bd038f00000000000000000000000000000000177ab4c59ed4067f5847449334f84e2d675f4bbd11bf01fa461655dddf0699bc843cc18fd0f525626c8cb464238db1321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001200cea27118cd52902cf86aeb08c9dcc29459d342ae956e9040ad516c06a79c0c56608a4d47d995cea76203decbe77000000000000000000000000000000000bbf072782c907749bc49de96a1e077086728e108731f7d56ee98e95a381211844d8dbbed7d679233812810c69152d68000000000000000000000000000000000bca5ed1692470c5d981b0695bf0c0fa23c07c1a784253acec9b2bae16598f3609100442b8d4b96e64eb73e77d7f0d110000000000000000000000000000000019b5345dabeee84f7b7b558dd9142dfbbee73b6e63f27310e88a98d799a237f063b4a188bf4fa11e88a91326dfd0b82c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013456a04934143da14a97e8387b72b58c47f290162037bfebeb2c1a095d2ff728c4cd79b8521d1f7ada1aa593f2d5f8200000000000000000000000000000000124052c7f380a2857293976ade77772130afac6559d78af076bfead8ebca6aa6b3b54c61443dfa64b771eda374e02f7e000000000000000000000000000000001671bac1992d281b2b377c5c34af17d7984d270d1404abe09303a4a70b911ed77e31fd0dc2b7ae730976d26bae5c20760000000000000000000000000000000006bc80dad1f9ffd972de97e2f5a51367ebed67602494035ef681e53faa264e92c0bc12d1c606a75d23c66f17c677f90c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000636632531e70fd162fc7fad34938cfead9d471e7c33144665f122792918e95f243b6ddc650f8196dd2f48424459933e0000000000000000000000000000000016354159de5164284dba467e6ab828ba50e6cefa2bc9382832d6e043d41cedd5fad0810fb0463e92950db65b7a88b0a100000000000000000000000000000000004843a730a96566cf86f4d6625fe16c90524db96962e0042489bf874c7bf30127b9c6c73248f956f6722012cf2b10d800000000000000000000000000000000110b1847a4b65f4818b90e55a4245524ad3e674968a6f4602c044e45ea955c821fcfed89b34a01fc753d6e55069b68ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cac2326ae8989aeecc5518f47d934d952530f7c3b96aac25e30b7bdf7a1d96c2d4a020ae098e39c665ea81a3a8952130000000000000000000000000000000008f3a55c5db23d98f19dd3c2719a2b478be1ac8f509ee4ee2cc29e381a1c873d58f971077eb0ce74de9714545525d4bc00000000000000000000000000000000130e27f453dcd6d9f4dd4b4e8c067a97426217d06ea4efe78a661fde2affadaa3efb39ca7205457b613c1d82d24bee120000000000000000000000000000000009cb5634314aa5068cd48d02f3140814e1e30eadc7b63a78157aa5163539356591de629f0547aeb05d6494645ef543e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000548b4db02d8e4e99ff08ab722e6de7ba1b57ac1829b35615608a4f525d8a4eced9da7c127cb166e0de991ce0bff8130000000000000000000000000000000000af26433f64808886a9f13d4c32c27a48b837938ba8c0ee22ce9b0768b91076e1eb573702592e0dc8c6360b2212cab6000000000000000000000000000000000ab153a6df9bdfb7518a5ea9ef27ff62a935f3e13df467685e61bad6f1c9c2baa881eb0a29b29e746cf82a93f00298aa0000000000000000000000000000000003d00bd940a8348652ca0f5529b73e05484ffa66c4e9abaf9134f0948553da4aa03234737775798006757d4eb8e897c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184369264c8bfa6370cc19cc8648432fef2cce41e98cc06dbd02730a916c1329878efaf66797eeb214c7b71438361d62000000000000000000000000000000000ab9ca1e7cadde3d9beca985109775f43d31bd0a8c24f10368458c4b487879ea1f718e630c9d71242a60144a053f1dbb000000000000000000000000000000000d4fccfb5335abd3ec0849a02acca3dc50f084c95e70a6305a76612bcab9dccf2d2a17efb458959841a6e90993b0e18c0000000000000000000000000000000006d3e9f6592cebfa1447afa88077c82b001a2cff1561d2d3905e606c1789dc4170b55f860b8d16af2a26458d9984d1971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e17796e0e1e854fd252a61f6927e8a66aa3d66ad1180e947412f6d4254b53806ec590b2a5827e51724f432ffb336830000000000000000000000000000000013030795e5e3efb1d7781a3cc77269c84ae08232cc0f77923ad9938f254c724d748d807cda835b5f229cbba25bc2c086000000000000000000000000000000001486bd1cb89dd086dbc111433ee826539bef52a882b558e0d6361e4a27ca3e22cf16e5ccdd30920b435bcf1d7af3e1a30000000000000000000000000000000011d10c451eb7bece593d300cac947e6c243fd18567a141682df6e3da4817cc02fad43e1a437a45d201c26d09153887ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c95cab40f706213e0064985ea58a05331873795b0f79385b4b64dd901432f590ce29c67ad50dede53dd5c3f35a3cf650000000000000000000000000000000016db74f7436c2bd18dcb5fb9637bab86d3f2e3bf57ba78d580f0a4c0bd453031dd2376c5d5a3fd3e072d3c5801541c920000000000000000000000000000000009cc2f5651bf08437242a7595fc5db53d32986951ff20fb048f2990b019c4efdac9a86fbb0101d6e4320f23c73ada7cf00000000000000000000000000000000021df241a9d37d6afe3554b934968de3235bbd4dfa037fcc1c663c6a6113c3da0307ae8511335e5e8868b6356ddc8ec71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105ef8dad89d8807190c2b58f1c73f8e7551dc416dd6140c194eff5c33f827407db46ad33ca29d7094932056f1e0dc4f0000000000000000000000000000000007b0563877e625942b75f87b0def5f4c96f89372bcaf0cfe81a65a2c1c17f3621789cacd503438269cc8e5a3938d30e40000000000000000000000000000000013c6fc6651c52ab1e25a6c9ad56eb8891eaabaf47ecdeeedb3082a472f5b871e3407b096f473100a5a56933761bbf809000000000000000000000000000000000d79d884ed467701b586049610a94080190feb302bcb1e5b518b5fe5a43f3cec6d392f731cf7dee8caf5a0d587b60c701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173ae734505c698a7edb40cb9cc1b33d166bac2f51f81d8a6de93334a42543d09aed72952fc440860e6f371033ce3b7300000000000000000000000000000000195d9225602576cd4e99f62d1c0696b30ffc785a22269e28bad05b8953f13041df70dbd95209f3adc503e9f3cad72d8c000000000000000000000000000000000694db4e4b96b43cfdc7a5b8b643ca83e1ba3ef13941e1fea31b6f15153e8fc8adc9cf1ac225538f36f48f7bdda333bb0000000000000000000000000000000000e00aa1b504e532e077cb71e1a7cdd5141f52383d5a3c95bb90e79b599147425b89fc67f7ff430d9cff3323706c6ef81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c1afc4c5eb2b007f7ebf51f60bc5ca3d5d5cfe688ed8eca9368f0550cba1bb1f2b99fe3460193dda464ac1f2673927000000000000000000000000000000001771f88f65273d708ebae98ba96b1020010202a1e8f53f5aec05a1d56a24cc2cf83850054ae976cd1e58c31b83a09722000000000000000000000000000000001608000189fc17fffca28b0958adff32860c664d90b85726450167bdd9be48d255a19a3c44a0a8757293a22522c81507000000000000000000000000000000000cc34ae5594baedf21ed26904db71e610632b43fdc40a51395952189269976791ec67810a7bbc6c20cd57119514ec8b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000766bd2d757009047c8392f595fbd24e2a981d5863ba8750d2b633966d16a75c85840df2a2ef36985c8df7a51f94ea9c00000000000000000000000000000000052222303f3fb4f41af3130b400f96c7c53927a67866ccb1cfb1de86609d35c9140d1a2299a7a14b73d4d80aaf118daa0000000000000000000000000000000019739f7c04ce73c50cff6810c690394ec7d9f4cb5b50fde79d71f7222eca5d516d4d1c3730cbd90a7ad38dcdae798aad000000000000000000000000000000000c504de8cbb1d4761cf5008c28ef752d66f5e5de6d4c3b90f6a4aed0b49aa0d3aaa295347ff17f2a3be1f3821b6496a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000683229ad3190c5c937f9c3ac033dd16b2350d13b5399f63ca029577b9725eeb138485048b67c32593c00a037a7a502300000000000000000000000000000000081dd4f491685cd0cf2425880d5dc1a19c8edc839a502319d881217306ea8f3969bc448bda26f98303329c56323d0b0c0000000000000000000000000000000009913591d488445ac5a61ad6299f2632083cdb602f413822273bf07c5af933f534f74a8ca82ad3beea846d1d37d654190000000000000000000000000000000000966f288801378acf8932862b9bd680259fbcac3bcec8ab7bc7b4460af8e0b0ff83ea764e102288e6b3a84b73112c491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000168a9e5b507ce272e1654346f45981fd2bfe4c4d33d819999c4898ea64a505c9637a990a2834a7d136094194468394890000000000000000000000000000000012011e1aca1b25caf596751715dcd8846d4f91dab9db5b0856e3b0117e38b734de887092d209bb35065f05116a095a680000000000000000000000000000000006adf2834569c39ff4e6c92e6d3ff0b2568bc5b20d7d5864764e249c3e4ba41f84c39e57fb3c4c8daf856df96f9924470000000000000000000000000000000004066dcbfdb0a54537150f7fe994b1a2cbaf82c48eb64fd793e763fe8f5ee5f9a13658adcd582b927f8ee22e61d296021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd0e254a3e9ef6fe034f786d3fbc5a1e4adefaa03c668b9c007797fe8c04aae0610471cc8ca9df846af76ae9305032200000000000000000000000000000000016b40812a13b2c0c736585bbefa446e00b83b49fe3a5905fb1c526cce4760fceed35aec4c1972fad26cb4a6d2ce06f1000000000000000000000000000000000dcd97c5745adecfe0190d5d9717cb2ce2a55969b81d035bced4e527997331903cd26451bf96b448a33ad3870fb8596c0000000000000000000000000000000002e6c5da094d341902eab34443d829e9fbe106e09c97dc444fc738d3ab2be85d9d1eff82e02189a9458c4437a3d2b4751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018930335964a936ff68ecb8b8423f740ea7e16b358c9d5603c89d42ebfdf83e17a2e34b6893e1f699072d39d5720e0540000000000000000000000000000000012d4a4a451cff24de1e12fad8434cebdc5b4091aa3bfff60a4679a565a0b26da0392cf923475bbf4ac1620de76973649000000000000000000000000000000000608fde1cbc5346360413b14f42916b1a4e1445df29ffc1f9dabfaf4ca0d60272da82b84978a451273ba0eeb31ba22f60000000000000000000000000000000010629a8a5aee9452d7c96be5370c9614831a5977b7cce7326424d2720675c7f561d09c0cc62ec71aa666753d3039f2361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014312e8de997bcc7163c60f2c3ca93be147c3982e2eebe61f6e903f2b3fe36e4d3986d9a9da202f34362ab120b06a8a70000000000000000000000000000000008415d3357126ea3ab6f5ed47fd91ad116d0e36a9ffd6dd261265eba162ce9dd795275eefbdba5c49ec9d254f224668a00000000000000000000000000000000165fee9fab28be5dff85d977c8a7a1f53ca97388766856c3778177c4c6fbe6a64e8407bc50024c3ffaf0f9d18b5b9a6d000000000000000000000000000000001496a7eb0321eaf1cff120636340fe47212912076e9d7bc627689a18327f55ad5bd7f17d29e36951a2d3473e7a21c1241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8ca23ae28b0aac591b3ce787a9472afc1eda5a7598626601e9ef565ec6178495c7ca0a91e60de6ebc77285825178fc0000000000000000000000000000000011a2327eb645d6480ac33006a7c3da7b028f1d310550571715bbf48f230955ff3088114b736356e793cb28a70c7eeef90000000000000000000000000000000003970c4cc6102aea9cd770c66ae79d8270dcee00fc4a45523ed7745a4f85e85a7d51310b28c5ba52eed510c9c7146268000000000000000000000000000000001390f44955e77f2f54adeeb202e857d8313bc08c16fcd89523fafa53147b432059ca40373869fedda304ebb165905b7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f722fe9eb5a4448a0c54f6bf7be58037e2acdf99ec92a7b5bc0d2c180131269eadb88a8f726b14ff12b8ffe6f3c34b1000000000000000000000000000000001378a408f340d94a992c27c1f29d72469e24003e8d027d9334a8be547464f4901d8546c69abfd5b4afb18861aa890cc2000000000000000000000000000000000f9145d64a26c2c9c163372ef9ad9093b9a25ab181450022e68c18378bfa583c360c12e2c6fde9367f7814d72c76904a000000000000000000000000000000000518737c592ab80e6546f97225cb8a09d3e4e8d9c12af3a07fae5ac9c5d34aaec6a1843ea66ffb9b3aec8f477447419b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005e505cb6c28ba517bee7aa2928c10e9b683883290839d9ab6edfa7a4178d30383c35685e9734a355be332de20a062100000000000000000000000000000000096dd27df3963af8e771d7f593363b06a123c90651e42d2d319df36b63abd8b2a7fb432d26de9237ffeed6ac39e88a2400000000000000000000000000000000164f23157a58aaf53634cc0a79528415729f4cd3acd0c513ded44c762e6dd1df98bccdeaf18693b0f03ca2ff3671fa070000000000000000000000000000000011602f353fbd06e93c726f7060f344da137aaa69fd24ba098137b1773393ac430dde9a274f7d193e1725b3b76bce21b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004a546ea332ffbc8bf16413f4ef5f34ff8cd7a1497ac2b96696daad82f74d08f679b2e731f99759b732051d6e9360640000000000000000000000000000000019967c1c3cd1db9fc5638dbc4d5fb7ca65f3a9a396f786bfebaf1bcfdb16e5f171a3b5fddfdf8c4ddf84e60b8eb3cc4d0000000000000000000000000000000007d7b8174b61db9761fd152270e3f76d82a03297d256cb95f1ac7af46a08d00dfb9d10066f819dd10bf703447324488a0000000000000000000000000000000010b31d6bd727dc3d27821747e798badd57c2afab652428b13de8d3e1bfae4f4679994ecb929c1a603fe79a463d8b13f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c198e01125410f6320bf7a4acd7a640de530ca27689a44af984c9a15334c03afb96f63307caf879fe7294956eba04a8000000000000000000000000000000000654d9ea5ab3892b243a8e8bf63ffed15d98452d4ef13b60a5ef8d860569bc4b5ca5a170b18f03658322874eeadf7c010000000000000000000000000000000014c2ed0f1d27682596539894614f581f7578aec7a2bf3d8d922b66c0a436194f6ab675abb60129b9ea7aadb383857989000000000000000000000000000000001773a585761559aa03e9b37be81165e189a99f33bab22b55a0e81e78f518a0b6c099d1ecbd7a40013b02d68b96bb35771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000410d641e0787b095fac2022226bec6a5317dca35934873569c26d0aead6485175bdbba5f60c644c083e11dbcbfe2f100000000000000000000000000000000012a0eb417c707237f2f8070b675c645954fab113f650862f2c589b8964f7fa7a022a053ec073f75e720c8ec55f58c0e2000000000000000000000000000000000355b49c718f2e72ec64ca9941459452206706ac88f9b6152b5d2f6727efb136413befeae90215d60e1c5c2e04c6d20c0000000000000000000000000000000016d2e76de6883ec5727dc38b5c8b1421f2e559c3dd79fb985d9422bfdb7ec81084379b86b3f267e3d581611c2f649cc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f7e46b261296f33ab11298e40c87004373ac16a8b3626776ddd0eb4b9222be3611b2ce9530f63383a6f98b1d79c824000000000000000000000000000000000ddfd49dcf4476f13c90e92cdcbd932c41b0e262bcafe6a4fd68829d279c7cce5ff0ec8c3d419836d055dc81899a4ac100000000000000000000000000000000144ab9a165388c99ec8fb6ee42e166699ef4221d3921599ee08fa8513fa8877d427095d3dbc1cfe3ee087b9ee7e8fd4900000000000000000000000000000000062389ee0d36bccc1e18f5263091a2a2b1fbb15d2f395fc2926d5f01a5c59c6d8f50db7ad33bfc6e9a63cc1646eb08cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002029250649194e022128b53404b6b532fc06f69c2b5ee60ead3cc60d91c0627af7ddd615256d7974d0eb1fa33a8005400000000000000000000000000000000005816dd76bcdff34b0cd1a23987799844d64ad61cb3ed9efa8ebd3676a4a7f5c7647ca2a6dc4f6bb710e76b1765cd1d0000000000000000000000000000000013cae4b0ed5ed32061cdf024e10c170f383f0c7e9b21b2f2842d21c1d1e6e1f48685518d0c88fa4bfbf75aa513f3f0af0000000000000000000000000000000002446ceea2cd71fe39f09be26ca1cdd494780c586cb222572851f824105b7a0e820ff079dbda3eb180cffb68c32820411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003aed39a259e4c3568ad4ca6ca031d0bedde6ad5e7c72b7ce55aa508c09dcd3b80affd5186acfb981a1d0a84b01f770000000000000000000000000000000000043757f55b145bda8efc3208a450a3a76ead947ff1db47ae240515fb0b251769626b7763cba369ac70cfd6a3a07e669a0000000000000000000000000000000006e946a24b46d345d84aa08df517d05a0883a8411388561a6e7ee3089b2dda4af2d690c0e9cd9d13a9a7f77a3988352200000000000000000000000000000000156bdfeb2cb87308f73f3af162b7ecc54c822505d9a62ef2368c4c4daba4b5caa1c660b177f336aef6c2cd18142a382b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012eb74a548a1d3dae079e689ebcf3860bbd524500371f110af5becb7d4e35d963e41e6ba4f990f3b1afd9a77748837e20000000000000000000000000000000002f5e9645275eae3172f4d169d618adf94e29679d31925df042deee5a76df489bf7f1ce143d090f5b2fa55a9ef4ce8cf000000000000000000000000000000000ff2a2e428a9d4e78bffa713da5c3628292cdcfdbcd1b0f76e84fa6f888c178b02356f66ba66af7617e7ee1b1af62732000000000000000000000000000000000e3aa36b217c9984496d67aa442546ba3fa3c94904010f27d38b48faa6db6d9a356cec7b5e2c7a9972d4fd0e6576006d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dd3ff146ac7d19a5343b1988e2d61cde9d073a5bb69614e12f61fcb3edd07058d983d286c7750ee7d322a4b48c3a3a00000000000000000000000000000000038d8d0ee045c379b8f1e03a5266be5c56adf2f877a256b96e7d86dab3d044706d4563a0f89b397997098a4b870704980000000000000000000000000000000000ae3d39dd2f6e211a5a7607768cf412ada6183d114864d9867fe0b756bf778e5d64dbaa12d8e469232e184e82259b680000000000000000000000000000000008e98ec751f9630746ce0cf76eb60988dd598ecaeb4cceb1b104249d1e489dfbb5037709d7942adcdffe8332836dce181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079738ac68fb9accf8e9ca7ba392d765965b5b8e80db2135d2b61f99509a7d56e0e1743e7549ada55fc93d251790bb81000000000000000000000000000000000b80ba11e833ea904fdae34aa6c85cb445d34d56a9dc85395b144def496efb79fdb83c1daf2fba8f9f7bad2d75e85857000000000000000000000000000000000a8423ae8ca4ac2a5a96bd2eeace97669c5529a9496d601f7390e8d934053af12c9c345b00e9b58346e057da116d68ce000000000000000000000000000000000a5b6be744e34e62ba5d8901a58d8280da920f06ceff0a31e71df6ae6ef6e9df40c8fc6297d14593403eb279a62c6f371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c0941f5b6529a4cdcca75761e03c633564a46a727994b7fa98fc88c08b645f5b6bfa15eb6cbbd68c6d44cafd6616db000000000000000000000000000000000f6f45b3eba6e24d28ffe0fe0218f11e5da6537c1dc1d9abacc5c4477ec96cc3a06c035f9ca75fd742af1e550cc9341c000000000000000000000000000000000dd39c6e93e09e0c9cf445796387649f6042c0a25c0ec2b354f56c1045691b3a2e3b8d94619cea8c5a820be60e8a28170000000000000000000000000000000007d76a1cf79f0dd7380de524d909a24940daf36acce417e8c8c0c33eac57ca246283a359a4bf6533b963fb26d5a557121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119e06ae46adbdeef04d7c67cb860136a91c92c1bed8393d0a3a07159828cbfffbda22c3cfd68374196139ba21c85f4c0000000000000000000000000000000015cc4ce7b76c1605111526dbc37298691d8493391168739eb7a742c55b8c25013c6a0df9578949d61509f35ba463a3dc000000000000000000000000000000000a8b0a36df049be37b4f0866a1f41159d8dd9d507544c1267394932be02e11502cc1609f64338c8d8583a647351c11240000000000000000000000000000000003a80c653ca122873ea273b3a1e0764c944b542414baf07745747b7ce29953ab82e4815af7d9b556ace7a423c7f6c5ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7d0f058317c6356dd2c637b29f305b0c13d7cf173a3373602622f953955e4cefe661e709aa755da700765a74036f7e0000000000000000000000000000000013c09a06ba5793083eac5d26d3d6322301f4b5c1d28394bf3894b370c6b8971cee2d83e567b60fbca66b26c417d747a00000000000000000000000000000000003aee9c68ad01518fe494e9898fdee7d321aa7c5b19e56b47689f3b608e90dca019d552dac286f900dd86073d130403e000000000000000000000000000000000819815295994857911f23ef11aa4c3e87d47addd68632c8baed783632ecc5fc0334f83ed97b27c1e0e2b5ae7bc260f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000947a7d5745234134a6a92fa82bb473952993970676c57111f177a25f91f7e320debef01793b695f9d0ba9e4e58d9fed00000000000000000000000000000000017a716846e63bf0eb295a0d5130b76312698dc014d2fc81ad1547e04aaf7589d2f6086401d067c308ef5d4af0bd95ac0000000000000000000000000000000015d713e8b563ebfd793a9601d9249af5961a5e3d9847f66c092d131a96fd2b324849c0a7cb7d6614c6c4e579eb5b26f40000000000000000000000000000000007447d1ffafc8f2707ff4ae54b52e7698478c6ab603bee5980c8d752be14a50710aa5db0f85a6c5d5a00d8274b086bde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122d450b292b6490a838b29a66a884f284f41d7cd06d10c8449762a05de84ec60f632aef87a98341d4b620413b6321810000000000000000000000000000000018753afdb6d354cdf995e8ce5d6cf8c26925095138e9cdcc036d29baf371cc767c90073748944b99ca3e75e4262c6e86000000000000000000000000000000001616f322206a510bd6cb941dd5b356002d9553ee380bc696aba51dde1b4ebfddee526c4d053d4c332a4d3bf371206426000000000000000000000000000000000e37e8bb5392c95f842b4dc5ba20847b395dd655c52273c1545b88b73e776405712d9e2c5958b664eeeb37a0cf02e21e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ab751f154b374d605f7578c4f67373ec40d7cc92ec4da5147187467eea751d367c882175d745886471c0b1096b8461000000000000000000000000000000001067bb335c4932df6bb43cf8e7da53026bdf1d7075e7ae437fc71ff6e44dd2ce8ac44e2400bd096f3ba585de00982b7000000000000000000000000000000000039a4e4a9e5b004c783cb8d63ac99a7d2765eba6e0e23c165257375b6d178f02baa400af6927a6fa19d1324069e0b0de00000000000000000000000000000000142a9b02e7c0a200a1970d8c692eac5e9f3a0c01168fb77201c25b72d50713e838ec284b897a5c1a95a25aabb226d73a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a7b1453c14088090b02721ad06a420df029e422a93a1d6c810a4e8352d1bd724cdbbbaac5b13483e83b31e5e4cbd9e0000000000000000000000000000000000221853aaad3007b02e306348b3d94eddec8bc8efac253db3c30916cf57365daad5520df40f8cd707c5db75a7244b43000000000000000000000000000000000f08805bff583b845ee4975e882c3bffe7f8e3a85b68ca5edda6dafcb1bc512f4886ab82ebee7b3685a3ce024fea2a820000000000000000000000000000000005f1325a3287b7c1908d7c55d0f6b336570df5634602beaf60f6deff7f581ce3fcba2ea1d92fccf35b3dfef8e290fec81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f205bf971908ecb4a65c4e63fc306b9b461e8ede63a68c561dc1d551df3081bbee4cbe7172a77ea1ff915163b3cd79300000000000000000000000000000000073bae42f2a4660e23a2cfbeb736d8856846f5b52791246ee827a0a08264cbbccb5b4f71a386f839c495efbcb8f8d64e0000000000000000000000000000000019abd20b6310c806cec9bcdcfbda88de5b768ae0a7586a8fef782ec30a6aa46c39565016c46820fb3a022e7c9f4c54e3000000000000000000000000000000000e40edfd794d78a8a12e5554102cece5d913d9d73a631eb5bcbdb454e83f25f95186c0d473c1ab5285a69fae7e7f5e231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac3f140b916ac41f4951bbde752373ddfcd16bc8751513b2b4dedb0701a8d0506365729babd550eb5a0522fe33eb9450000000000000000000000000000000017bd5b18f07462c8125d319d6114581a5bc062e875cc4923332d764116b046ef3ce5291676e7320a637a51402519d0a700000000000000000000000000000000128fc30d5663160462ac5c37cc7d78b283f581e8314c95483e127cad332c9da6ef806d0fbaa9bc84c2e9300bce8a54f300000000000000000000000000000000108dc8e698873a0986dddac9fc7df093205a310814a3946333809f59530b4e693c1ea76823eacd23a88c1bfd0e9e2ffc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001677afe25bc2001bb94ad58564ea21d03ce47e8b9eadf1aac423ae503e530a5293620859826fb9892d286ca5a125dbd40000000000000000000000000000000016a9b7045ab93e06029d496f37c0734d281ee42bfccf51dc205baaae5955c714950eacf781d9d2b988fd0bf824e7497d000000000000000000000000000000000a10fef925eaee2a04071b5541202fcd6a682c595a92442c12d11ccdabc7b856d840e176d0f6e72471b916ffe7391b6a000000000000000000000000000000001199e205ede10a6c03a46948679516b0a7233a060f09772ffea5f9599aea2b7ecdf43114aa971f7f6f5a16a37f0d97ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000918ceec090ed53acb35e344936e5596cf2a49b3012ac8f3fd7d567352bd7732795ba09ececc03fb85855734012affd60000000000000000000000000000000007bd7b4bc967ee3cc426a2c88b38bb9f128e38eeb3385dad84294d07c9484d3b950d074dab4d050991428e21dd9e216e00000000000000000000000000000000045a843bf4dc5e48ae5dc86ae52d5cc12a90a7ae793088c3a8d116e282b3cfe5807b276e9e200ea56d6e0189b2cad68b0000000000000000000000000000000006c6a4fb70531e80e2a74a95ab73671ed1cda57c09a288cbbd5338a3aa5c5b9a981dd598da0150be5312fc375132b8541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001214730589398bcbcc6ed54a42bcdca922882b2de89cb2269b17d05373353a27c7912bed4e72c523a86987086d16601d0000000000000000000000000000000019837596c1decae44ccc730825f089dcabd4c76e75af7d60bc19361b48ddd8844a1b514cc9955970fae28c1d644a7e21000000000000000000000000000000000060fdb650d58ff7d51630882be2824f99edbe66b5033e5ec9d2f31fa553ebdb6fa449278325f142234e77a04a5189bb0000000000000000000000000000000011e98099d16163377acddc2815759e49ccb966a8f9c576e76f170052ec657ea430529e38ec45f8ca081428546b1eb5f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc737a7d8f52197ecbc2146e824af51195d274a54e9e5dbd69e19990e340220cba573f5207dea8b40721e0f56f01f380000000000000000000000000000000001542b62398ff36b3b8728aa7b3ed6804ef413f23bb7e12ea15878f02da86a04a6e9d8a13efc269d8c14581f745856ef0000000000000000000000000000000011810c75066175a635f0cf7754d2e33a1908dcc9bbd7cc3cdac75ac833e8181ab0101c6dec9f224c9aa5574897ff458300000000000000000000000000000000001e094ef463e9a97defd4d56ce3ca1bae2e0a60dc41f73ce40bc079d87e8af49efa159dd9e8342ac66a6bdd6130d97a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048a6225474b874eb2da78811c547fd1e3121c0b50bf6796cf8aed75843d213d697b7d191638013c76f84c471226e3cb0000000000000000000000000000000011162f656c6a7d23f088d9fcd49571916d22a7e6cd3ef2fe86ff726de1bb17c0e7b0b801177a281b859909c50ff0b25900000000000000000000000000000000170be00763f37c24ea9770e1b0d65f0da228fa3058182492d0d76a412716932da3aac7c1475ac7d24047c010c75da50100000000000000000000000000000000042d05e315baa0918953cbaaf5e0405938d530da7b2af79b45d08a7626a350a805548404c227734fac6ec3d9efd275a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c324e5464d181537d0927981369dee4c5096f954c3107c8f833e2b7dd074ee5975309632bae27cb9e9c4452839cf43000000000000000000000000000000000327d814b133e3acd46191a54b1f76c12774dc94b32abb981eafea3fc4973fd9f8b51e6d4b7b2223fdf5dac13993057f0000000000000000000000000000000003acd25c84a06a57d1ab647f4696bad89008700feb71ff5113d33d27de3e8c10cdb76163998bb524e264f58b8023f98300000000000000000000000000000000098f58a050b09257dffc6a0719df7c981d6db50c613c6e729c79e68bbf56cc906d57f13e4ad5c6185492ba4cdce80aae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eadd934078a269b9ec187565eda0995cc5f897d787c0a6d9920795e7e5fd78c1db4a539e8a5cdafae345c6dee076175000000000000000000000000000000000603e7eb63cd030b17165b5552d3cffba2c7e203c79d326a670bf2ca8fba23a61d4da57fca5dc50f0ce7c6979c572d8e000000000000000000000000000000000999ea045d4d06dbe91897679e0be156630a35ab621b608d42168e830ae98c24c24367b942a81f49c3380d93e059e1de00000000000000000000000000000000023104b2cdb9b9b5971c83cae56276f84fb6025d999d6ce6dee6565a0c7515e1623392af69440428f3bb2ffbc879a4371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026edc1261c971704203e2afb96040e4a70f6de7f36fbb12d7d4a81df000da1c5697c89d8a40fb4e5ce369776f72fef5000000000000000000000000000000001210276e48310085d930360a3fbf64af7d66852709484284ec21a63021551b7473c6cfcd0c616df74d983037e9feacca000000000000000000000000000000000a26d98b75d0c6a58f462ed42c3381b63047d2f0d84fda5c6b6130b3fa562f88170546162ca4da276e7c72e4c20756e30000000000000000000000000000000002823783ca66a90030f57c021008e57600a248ca2b6af1e4e0c57a60ca5d569584a64fe2b5d8bd2960500fe823ddcbbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191c3f2b41c25376558e2a3d49b793e24907867bd44a5d19f904d564225562a566d1f65a8ad27ef52873355b63f930400000000000000000000000000000000008c325b1a5a34ca08ae1e9adc5743a3dd773eb221f11ec139a7befa7e40f32743db72e6584fa7f29a8b101e6edbd8d650000000000000000000000000000000019b8ba112353022bf86105b0bc2ef57aa723242510d368f989adeeec423a8b5fb49f97f0866ec6234c45f744b31abfd9000000000000000000000000000000000915abfa431c9f0aead9448094aa436f93b6296dedc09f3bfef135771ffee99e7c15b998d79c408fcc944a370db8a2d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000014ec8956700983e52a2c542c1dca1e416f30dd70c9e2bf7fc06d2385f0688989a17939512a3f06ff4baf7c28167e0750000000000000000000000000000000009578a388e8ec2c6eac0b4b8041788033e92ede9949ba4b2c0877407fd1f08d46a408e2fe8052a6f22a677d8f120d1860000000000000000000000000000000009ba315c61fa5000d2810a2ce4807970dc369a7a555685345ea225e972e75463e6c4bfcd67880eadd92bd29b469b6c6d000000000000000000000000000000000590415b52aa566db9819046dfaab890988e7aa849cd6a2a984e0fe3f34aadb2d9f9990968cd5d231227c5da6e3236421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a12b6d55161025d7124d1010d94a78c2023489b306a114b9ce5b6d92c7b4910bc7081fd8f1efe365f5380b83c6bc9b2000000000000000000000000000000000150deabd12adc63180d68c2ca320bbd5e13b4e6f1f5c08dab6a01ea6976c25bdbb3c7f821534b1bcf67303a6117e3430000000000000000000000000000000001622f25dc9e1942f210ae3a2c8d211879534605733e1d6895d190befe51a94acfd7281da48b49305b37be002692d11f00000000000000000000000000000000043b2de44a3114a7d778227b87cad83539dc9c2ee591f5b12867bf0a7c767d3167eb3650d179db0ec94c51e39bd271d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a366673494482520c33b209f32c884eb16bb28f3b84b0c814515fdd81f5a24c75ec036e29388068ddbdbe3f22a892a000000000000000000000000000000000c2fbe0263cf4dd2b938552ef49ca435f96dabfa799b09f234dc3a77d6dc3b616e288d1712ee51e08f5e24ad3fa184b700000000000000000000000000000000041a6b57f98541ad3415eba58c7796a850132c4028788436172c3ad39e792079a3d1427c6ed968bda1b84b95b1f30e890000000000000000000000000000000006605f6d887052822c1c67e9d327482a3f1efc29ff812fe4d929bdd9b055c0587544a2a646c0d224503a6ceccecfb5461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af33b7db5b9f73006a38559b592e1a7020f4a7f4be7428e27000c3367566606ee7d38c32bcee41c098f58a1b1076e4a000000000000000000000000000000000351d962c78a15fe1daf5e2b865e928ef5aaa3cffdae9f97d3b21acb6177d39365b375fd04de7922bcba3e5da431a7f60000000000000000000000000000000008f4697a47749c2cb8aed7f0b71d56fdb4f2c956fa88e6b5fced446529513955873e3479706cab0815447ebb7fdacfa10000000000000000000000000000000011c17b8d4d15586bad4ca93ac2e744043c59899c8b83ec38e3f9aa989384ed9daddcfabd75842663968bf32f595103ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dbf698bfaabb9ca004e08a97413bbb0c1ba0e95d9f10b0776746f38ce9fa8cc0436cc8027c397af2a14236540544b2000000000000000000000000000000000f1e697c01493493fb566613392b2ecac783e1e9167fd3a58dc4bf059d58132684559cfacc6f814546630bf50eca75c70000000000000000000000000000000011d31cdcb0a0dce0c26d46966a85e2f9055df822cb552a9a7a507331b064861882ce3e011ebe2711d670ecdd0149ce460000000000000000000000000000000019847a13b4e9c1d4c2558dcc38aa99d82585d9fe275930ab9cba66f099dc5034eeafab71002509a86fdca96c166015a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174053c2a210af01ed770e465b91c9fe68cbb4ebc66d7fa78e59ff2020f4bec3bc9b9b334999061768abaf45d47f91c000000000000000000000000000000000186e0c335e42464c15be0906241ce4c825000752eca97e75e5f9aea54c08a17949a38e95bcd2ca22052fd72d834aa55b0000000000000000000000000000000002dd632e73f60bdcacbfb283c4b31e1b13d445b07d27fe8314a9fed1d92d31bdde67511507fedf32923d6701dc2a06b40000000000000000000000000000000001208baba47d33ae9a759a975713fde99ed83753e42d53e7d605d62ac559f41ec7c1e6744cecb4692b53e6abb504a68d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9d16daa2e85bf133889ad7f1d6f0c109785f9a452277df1b09001e42290305c93ba390b12c01859f53a65dc090f5fe0000000000000000000000000000000015683968b9536b8e9671e73270fcfc536800fe281a00d0ba9d94857f901c5f2597ed0ee83efc3b852f542d209c8c8b6e000000000000000000000000000000000ddc09a6a07e48f8397e420aab41ba83b252b87cc4f2c3ab9db72b723186cc58b8c406e98e8990f8aa7f34f4d97bfe7d000000000000000000000000000000001911af855f9286c3d267c3ef5f754dd478790ac984066e9da6fe94b9a4e0435f5324f2afb27a7334bcac4bc16915444b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ea86c0d9142263fe85386c4635dcc0370cde6bffddd6f318b3065a8f36de77d9350bef213ca8d35f2780f0108eab75a00000000000000000000000000000000179428fc33588671f16fc336153cee277c14d2832b985d4d2f7b241b60ba84934564ad8fa64a51b69a9dcb3889bf0329000000000000000000000000000000000830a1ed942f5798e4b2f9d4c52c499a7e38467eea256e4ecfafb086863330857cefe616a4f8295a7ffe284e6d6aa01a0000000000000000000000000000000012fc90b45a63fe384e2d4a28be0ba84c864c1e2f0017748b4ac583231bcc24d3f3f3789f0626af958aa9b853f81a2fad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128b32a0869dbb75a60e111f477f7be506e2c1dbaf60077aaa095708f50d46f1f798e906aebeb61b1de606dbfeb69e01000000000000000000000000000000000b58c2ccc697ad3faf62cffae10b19f397a9cf06e48c44a04fd88e892c94ddddf84d4ff5e704fc8dab885c7191d60fb000000000000000000000000000000000082ebfdee49151e504b0b655a331b3a6f7956f69c9743bac327ad3c409f074bc907fba028b666c7038cb201ff4d80a200000000000000000000000000000000004e7c3c30347b99099171235b9c1fa984f46a4ca28447d25c3e76607234b6c241c54295ed5d02a8f9cd1f461a08af1871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138590925d44de1094c7a96e4655f59952b029596eefc866fa7ad4d0e01d921d522e9c1208e63dee1bae32ec3326fe770000000000000000000000000000000008845e0b9815a4a52af52816d5c16321d6aaac1c626e0c6a56f87ac3eeb3258519d3dd2187ba7eb46b26498c938c1ed5000000000000000000000000000000001523105e3b6372f95b245151fa3f88d48c807f07d9923bf7c070b91dab92a60b632990ff7fa6c40c6ba7e563bf9136f1000000000000000000000000000000000b12962452ef2f26b4177aa5e5865a67dc7991566fedca688d328c81b6d371470df5c31e816d23e92e68be8efa4bcfb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000110b50fa5dd26e83c68db04901f9582d31bc2cfe9bf1aa0485e778a4d0d3a0c23d46c0618ab7cee7a99b045d81a50cda0000000000000000000000000000000000cee5925904ec52e2d1bc6d85c001cb6ad950872f5ad62fdc3f43d786672f6d49b09919d24955a3fe0a0c32d94c28690000000000000000000000000000000010881b06e37f254317399198d97aab0199063e32e0356085fd39bfafbf940a82884873c62fcc77358baee9b27b74be6d00000000000000000000000000000000008e345b7d8c70b4e5d73747d2eda4a728c25f7daf95908f5849f64cc55f16e833473e058f003d49b988bcb9618d56871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d26eb9b04cbf4ef20ac9971c07e097bf2aa2c7a5a7414b70436b2d224d7dc914230f6fa11ea0d09336d37811a593f800000000000000000000000000000000141962f5d7779326e22ad5f832e45cc722fc855bb9a2282e0e8cce5c127da56349023953b5c9101278708f72f6856e8c000000000000000000000000000000000349055eb7d7daf85d67ef573aa9065b54e27f2e604a3b231cc79604e2227674ff97adaa85dc8b93c1e413533564485400000000000000000000000000000000157d8a568192df21246abc0881b3ec5d923ec01cfbeb3043255361ab8d3e511f844d536f85c3e4fc8940c4d7f47a99451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c0990ecac73ec5e0f2a18235ad112cee766e077e6fec2734a7c8a26eff5df3cb086e31284a57e100c9289c977d990e50000000000000000000000000000000015d3e5aad870be61da6c2ef5bc7576a899d3dda98ffb44095ac6b0d5f3ef5700dda3cd6d337a313859b4c20f43b69809000000000000000000000000000000000b6cf8bf5b9a24094f2c5552e6bb7719c43642e6b49011639e627422025074069940a0f5c081d8b7a81b1323e46cf26600000000000000000000000000000000132111b9738632e6324dc37d28f26c4f6056b89cdf0c3fae88ce8f2ae4fe45cdb142c22d4e23a038ffab79b5e2ed52f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190343f783e1f07ae0f1912491fde13c97b9ce6e31f36b58e85ff72d77a76afdcf6055255e4649c26d4f551f8b50714500000000000000000000000000000000010d32ec06a2c8a0bba5aa78bc1aa4d6245e7d0926439a19e5a8dcaa0098a405c6f9de55d9962998aec93458e88930bf000000000000000000000000000000000f89b7c96a73e04d78d8b830b3a3a9053b7cb26435e600566328fc00f7aa7d360e03584d266a237ace3181d4670cb95d00000000000000000000000000000000011f15205cb90f8172f6a20a3e8b79f1cf24d5e501656753027a1a10a348e73dc0f367159f2d231d61fde963a0facf861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028d061359e877e5e0b47d483ba7c4300e165bd82643db3c4080c6687f0ed0036bb6824c5ae2ed2aad3ac23931041a97000000000000000000000000000000000ea1f117083d92e37dc5c4f18f382cb9c4653e3e310e4aebe8376cacada879bf78d02264d818b5d66a11751577443eec000000000000000000000000000000000446c345cc07b77c126cab545f81bbbb2bd032f5bab08f48fa20a89b2f74734589f5724af7ebb3d3ab8029f8ddbd61c7000000000000000000000000000000000158641fcaa72ba48f3b7679374bea18a982f3b7c99ef9a3905599cf265a22a098f574d51b0c76db5046375a198172ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ce5a15102f54033d4d466330e84c69888a3f85b565d2be3cd94c07f50e2ec49ebd8693a27fd6299efe11c9697ae980000000000000000000000000000000000ccf06b5f37a29fc123d4ab2e93ac9007bfc8090101ec836eea6b0dd134658927d4e564d20165583427b33fc831e57cc0000000000000000000000000000000011152f9a638bf19413201b6d23d0a48b62cea08483c07790748b00b94fc6da4c4dfb44d5b9e99f79cdafd49e8de9347b0000000000000000000000000000000005b86e7d7b9cef3577ab1334d3135dfec56608b74c379da56baaadec95a3a756a7218554242ec424f85ca1bdc6b482991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008995fb9d42e98ef10a903667b51264568ef3f94272d96525208bda18b53931feaff4637ae5159e069eb87d6281586cc000000000000000000000000000000000964831905f925e37f68931b28dffd4d3a90041ca45ea1f1ad4c3bfdc1119c5f3b0315d9f5e8fd10a1f67bde61bca38300000000000000000000000000000000051482c6c3ef5e5d61ba4a9887f9e7a1676ae7b75de2d7e67fddb3ee768e9e0aa2ef124ba09c9276c463b1f5dd6f5b9c0000000000000000000000000000000018977c22659c6b83ce7cb08de4a5823f5bce4d519b68c7f656773023df8baf75d4ed199fa9cbf1cb9ff656fd8eba96be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128c4e9b32d7bfe385b98110d836675017602a42e8df4f2b7e77e737ebfef996090c0ebfd1bda3db070c612befd51f4c000000000000000000000000000000000db615e4c3106bde31029be8d7f5b5c76ee5f5ba8b7d702cd64f0a047b0d1d80ba97d82db1304306fb73bc9a8140af4d0000000000000000000000000000000008cbf29a7a0ec4ae170640cea4801f7b3ab7c8ccde680838b06f81c655672e9aadfbb608098dae657df1f970a6107f41000000000000000000000000000000000f7c30bb58659b39dbf658d742e4a2205dc65132692fd7d72859ef97e465c958c7bdc651c63778106a3d9406764b53921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000259e94891c1fbec71412fcc61e37b29a42724cb7f90c7c875d96ec06d112cb98d24d771b7b9609175f3deaaa7965880000000000000000000000000000000001359ba3648beda0473c81d10adf3a85889a2a6fec9c10b5f220154fa9b8a624b576c9ff5d64a4cd8d17754d110c181680000000000000000000000000000000005b100daef0a9a86e81d7c39e9bc4c803246a0b8756471b4c7e0e1349074ec1103453dc6723d63d7b13c47daf1e2d21c0000000000000000000000000000000001ceae1ef3bf4500ece7ec465172c4f8aef90f376a0b5d9da5178025c601bafac663b28da2172366ebcf4be9104091711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050b595b77d2d9f109128c8c06d010ae9b8b25aaf8658aeadb51cd6f83346d7a021d93c74f764abda540e33eaf1f0f4a0000000000000000000000000000000010365c72ca04d22bbb30c79537b43bbef502fd75505b1d90b157a0481477ac7edc14181cb4a3f74d257ef0b2be6341ea0000000000000000000000000000000012da222e5586098fed478d3ff55f8c6a8ac89f24e6d92b5357da0eeda4cf0552e001e932054012515842e9548be31e7b000000000000000000000000000000000407c50f2da3f27a8794eac8457d1af8a2885fedf929a1822acfed6af9e0800712eb1d8d14b6e6e0a99cfce84d8f55a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff45aeeb951e36417ef7f1c2978c5430f50b5361e3371d20e2740e2784ac9453ede05704776b133cc649066217d403800000000000000000000000000000000150ed0351c03dd47035c19233281f6e09a1d175c90b54c95142f3e2ef6cf1c08501647e575ac7f6e531180ec26efc15a0000000000000000000000000000000013ed61f0563217180c85f57c62d822139e6a6bbb4684dfd98f0c9eeb053439c447eb0b6f4c1105fabfaf77b1cf5c5ce7000000000000000000000000000000000e1ec166540d0e5cdaada7d7f06f6531d67ae34f784ee56154c1fb4a403fa27476c4516df659a617d44f9f8c7373d2311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001306911074201c6fc5c7befd1f1322edc71eca8aace4cd00edddb86251a03f7d195496ab87efe206a09b18e78b511369000000000000000000000000000000000a34e81ab13d9388d0c22dfa481842adbc36643960e5313d1ec7ff2bb8f3fbd2231b1e4a4fc704cb26a7dccb4b46ed7b0000000000000000000000000000000004b5e015365361589e4d1023d5017362e2ec60132da4f995e533840d3037e155727343d94215897a8caabd3f3399334800000000000000000000000000000000152bb3a60f6df60b43bcf16b4ea92c9af7f2bb0af325632e9882b49df12d8ecaa540b7f1efcbd28ef6a98eb7e8e471111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017aa8657f202973be657d76c5f04a6b2003652a37ef1e2ba1e4b8ea28d9058bb56516d000b8c1fe5da602ebf11275df70000000000000000000000000000000006a61a1ade9dcaae52c7168eb4dc99eca1444a01d34aa00e9234ed4ca5578460200a43be568943817f94e3bdccd9c74200000000000000000000000000000000006d00305a5b5d58a9d7ecfed94a14b53f7ee40b3d1fd471f42edc3509f303116357f3e914dd0625dc8b16b6d37963f8000000000000000000000000000000000ee4531ad2131a6af47928b7565ddb06f3100e1b773286a558a0f8104afa928a65155a9ab7ca3c641fadc0ff2d5df16c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ece19b680195af6a04fed72fb4f4b053a78b229ec228dc721b96cf64138763374960b2abb176fd2f1a4cc17a9db130000000000000000000000000000000000efc31e647e5ab9d6d2c0f1e0b150744d0f646c0a8d07b13ca8698cd1fcfd03bfb495f171b2fbd05e7fefbb2a66a79a3000000000000000000000000000000001512d2d7b745536b2e11ad76096591d8188310c1a12d9a5502b7ab288806182dbaffae07c996a2cfd7417f68df13b0230000000000000000000000000000000002559ad9aa48cc71e979b24cee9b726d2be63c8eceeda88dc6fc38e5d8057f3ea07a7c3014da122ddb445fcd455faff21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018efb469a3016d798d2e06f2b5bd3bd9b950398abd6e99aeea62b81b7dd69f239bb8f840459ad1f133ff99bc07f10bfd000000000000000000000000000000001868069b022300888a4232789d8f4b6ef18b80a8bd169eb428cd7d901bd9e5298e5f175b7feec01417634c559065fb2d000000000000000000000000000000000c38e93398649ff7bbc106bc8879bc128740b0e99deaa19088b7fbf714ee0e5803a95503f64eb6fb9b5db1002d4446ae000000000000000000000000000000000476664b4f273f369556759d445c36818468d95b17d6cdb578b02e48014e4e50dba33e1d788b8477356964c0d3ac1d3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072d11e49ceff04761075b5bc7baff4f29358c8add84eb9345f549d20ae187d1364d0e90a69ff77ec6671ac5ceece5a7000000000000000000000000000000000cf0db9697145ed6675cf566ace767b3aa3bcf500bdb7b83a226c6564a77982a66f326e7bd96fd38c68caaf1def3f9880000000000000000000000000000000014f29501e1fba6d83667bf0f375e86616c9b8664b0cb3b063aedb182f00f681ad968c3743a226e5a553e6ea6e1a7513c0000000000000000000000000000000014162d123d9bfc2011e8cae0907d34fdd23f81fe523cd405bcbb6c3afa6870d6082463bdb1c6d6a03fc97009e54ccc951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f79a1d41d66a9c297cec3c6700118e1e6f8753b4bede4c4bf49c0967bea8b88f2dcbe3100127873ecaf818bdc828530000000000000000000000000000000009cfc26a7c40ca7af7ced150cc8252fc7255b514cbcbf337c2a71a718b893025bb97e8536d0443ba1be16a9970faa963000000000000000000000000000000001914cd6232cba23e7ed1e4d3033382ac5f294258a582727a6965b4b6a83df4532c75d815027bde64e6531e3e8bc1afea0000000000000000000000000000000003f8defa6d3005fcab86545b77dff0f07070df0f2f11121a33bbcece40a05be565f189b4251067c380ab3822be2237ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ebfdcfda8097e504d1af86f558ca2a05470feeaeb8324217490fceceda9a734583fa8def330c525522c78b31e29fa7a000000000000000000000000000000000310d9b59f6c2c4bfa8fc93d19bd25b1a52549825d693c11c24671bfd8254b8d0fbf56797d7cdabba838620a4f196a2300000000000000000000000000000000079092b483f43135f66d0c56c89e159b7cc9073c314e30ae4339f6cf5743970d0714e61ff9904ae4876dd050e0cae5f6000000000000000000000000000000000b6753396bdcc6e1ec4889d3e387db9cc531295af8d1b342854307316064a082c0b9ca4d17d28dd1bf859117ea3444271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e10f8260ffeea3a67d97b16d8fa7cdd998574d524d7353f7b4ac3f84144ea06d02e0c79819b2fa88490030611fb9df60000000000000000000000000000000003de4a6f22fcf08900b1c567275c297e18f68d8910f35ad796783982852beefdb026345f7c6e99446e318de733eb87580000000000000000000000000000000019634d1c6f0c8c13f3b9e8f886f4df9978c8fec85e0da460e3045f2e6e18313f688e1c49bea57d3b592c551b7f8b4e4e000000000000000000000000000000000b64bced117c9c9706f1176fa14d06e64b744d4fbab32724c18805a6eb328b99be8b8a291a89a0a17113f1c1343b19f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091f69b517fc60e9f42d6ba5eef840e0f70274807344b7d8f245f7eb9f7bb3c41117849923a0363fbb4a9539b2ec7692000000000000000000000000000000001347e16462a3c64ebdad419905daad06b660acb3d260cb366ccd2fa00facd142e90c7453714a5b409b8d0eaed54260630000000000000000000000000000000017c5063061285d7645e59c59ac251dd1e3431099ebacde7d115ac7e10dd1fc30d99793a2b9c163923172a816a26fed510000000000000000000000000000000013062499401e6da94bce3e5dccb1e7d9934d0f53c2d52d86c18ccce7495c2e5afa423bb77c20ad394612517dcbdd47b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ca8d5dee12cf738f2f9f9ecf53d6c2eacaf8d75a492b71500e1eda35da7184ac9ffab308b088f20dd58b551e1cf0d9000000000000000000000000000000000e1974b5a749145b5db2e4ea92a2069d883ff1395cbe86c1b1fd8ce805528f83be7f6e930df5650dc64bd07801e9fc11000000000000000000000000000000000609542cef4458e08646b3cf17810f78924fb8312e78c1e103c29f8bc1abdcc035c60e80ca7707b9edaeb99269708d2a0000000000000000000000000000000019bdd888ada82bc286625bf541bf77eb35c2da7a6f8976bce668de54abc487f1db5c430fd5ffa493468b5e297fa173401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000630ef92f342dc773dae4651b6fcbef4c845575807ba9cd5b8dd6f981cb7fd2fd4b163dddea3972b04d23887ad974680000000000000000000000000000000001fb32b9489d3fc282b2a70b2cec39d99315d186593c3d304ed26c0b14fc20fa54507041dbf43394f0da96a56a0a6cec00000000000000000000000000000000022c499172f999be2af9a93089c80ce7fe57c8ac6e8610978dec5e495b64bbd8ad517a1a61587dd72d043eaf914922610000000000000000000000000000000007939a48a63ffb43539eb30340928d6c58110f4f557f8e4daa197ebf4a0fcd61f822b3b6a52773dfb9bde2b8d39ebd211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137d5e6ea7c1dddaec5baab08057120b40f196859bf80b5918a2d6c8a3606ef997acfcc3fb66279c5547a55888da2d5c000000000000000000000000000000000b59f58af7ba84ecf55e34aa54466a00e3f998f6f3651d5dee1145324649b7d8d82735e903fa0725c39861419a9ff7b400000000000000000000000000000000051d0cef4f015624d6f77aa843e3b56ef52e5850708fdd77e0c7a0741147c9bc4b031d3397c93c246de9491e9fc6c021000000000000000000000000000000000254db2ea46942d91266c024da71c90893910483d9c9c99e3f8c31a815ce833f4c74744b2e88691bf188b172c6ab621e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f112b4970bc40e072508f6f933a201185ad921b2ec5a3439a0365c6556fd27bb2530b662f1284a561a5267ffd644fc0000000000000000000000000000000016d5ce6d71a3535dbf5be62f1010d5c47c54e9c8b357d829c140002839ac6ab2f3c6ee137811adf197047c1664f466810000000000000000000000000000000011d9be0a5c2a25fd33ff440ab2a0a8f5841c0907eb660d7d1504ae3e62e03994fd717762149124908d7def0db9174d0d00000000000000000000000000000000031206778b98195707c3718cff1cdf92b85d1aabd6757f8dd4dbab0d5120aecde9335b015f83560f334343a81ea9f6161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018cc580f11f3d2e20f97c1970ad668012c5bde978c440b48308fca0016a5474fba3cf47e77cccc9e2ccda2744f39fec00000000000000000000000000000000034d9b5945a68018c6a015180d78def431f65b07676e979e136b3e31e728045be774d97442c26f507a232bb10171286c00000000000000000000000000000000105dd3f37c20bcf2e4ae08cd3149f787e8922a772185e849da92ec0c16aa488adac2fb8109ca26fc4224668c708ab7390000000000000000000000000000000013997689e929c469d8a8f1341f1d8ef8724062c02204378c086758196caa180f632f36c2f2a1a3d1077d15ca355fcbfa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8cdbab20f0070a72dfa2db96b4fa7bf30e215d6672c646e5486421b35316a5b80066188e9f64c82aeb198dd800296400000000000000000000000000000000161b5c23b3aea5e0427ac36e9f633d5db4525c7d0ef403951c53c022e662e285ea98e3e928326b0c288a6fc8205de6fc000000000000000000000000000000000955ae20d3f9172cf2ed4d45030111952274d7ccc1eaecf8b520cf7e1f146fb14cfc33e9d3e0eafcce2bb1c3418570d500000000000000000000000000000000179e08d68e86a002f005f6f3b21d6d123c7d7911f5a5073cf14a9c61d9d19be26917c8ccfdf406c38a5861acf9cf3e5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000104fb6888842a21c3eefba8abbdf60bbc28d68aabaa6e90cc3265e3ceb2c3392b8205c42f1ac2ed96225901737100080000000000000000000000000000000010356d6bf42a6c0f58607b4af0159effc96146b244d64fa5402153fd589cdac98d0a35e330a33b24ed68647717766f410000000000000000000000000000000001fe1b4eb81a364e2f85fce8f81245baf3b6b2de5881589fac07e4cf3096190e70b7d5b21db9a4a35822344daa066183000000000000000000000000000000000713173f9e67e528a53f70472749965da803700d8c718f8179acd745839d9a431673a6baa3748d68d7b5e51e08a1c9ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069bf07f285e7fc1d292933e840253cf3861dfff44d1f4dc48bcadc731e326753d898a6105dc5e109a9382868bdb20fc0000000000000000000000000000000008e9faad86dd2f2f8aae2b155b1afd990d8f1d0529c18de847e14577f84cd2dc9e105d805c65cea8ad3053ff56b59fd900000000000000000000000000000000195caf3f8a4be451e7423b3a1a3566c4b55d925f85385182f775d08a93bc50d7fb78446e1842e90776aa8dce02d38e3d000000000000000000000000000000000eac817c9c66c36ad0efb1b1fc92da15a068960e615677dd704b6fb458ed88812854449c2690bf5c9fc31af179c109601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f4ae5f3df2d025f567b37d9e23dde8a8fb23994475c7b85a7ce8a8c56a4fe53ebcb77b911f61cf8818c9c3ec16e5a9700000000000000000000000000000000059f1b087f545bc61192eb91d099a1615216c20d4965ab3246f53205718737bb7199c5c9b09225511b688f982c2a7780000000000000000000000000000000000d09ac5c318c3015dcd1db6ebcc6eabeb1839361c8a8b1e439dfe0127d5eab4b049763fdbca2cd5d1f8e40e823377f8e0000000000000000000000000000000003aa110a7a13a3844433f30f43e4261979fdf7b5aae401cc6d4cec740abc0ec1b853efe4dab9e3835cfda96b59f278061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f56d4a6b60eaa5acbb8eb0d8d143bee088c82731738dd83b74e99ae612525705f62f3ed347d5514f63bbe2a10aa8ee000000000000000000000000000000000474a13ca39f5f3d450c7c6f09fc0ac6f66652999062d41322786273f26eb41fd79d6d10ef5990293adf14edf46b78930000000000000000000000000000000008dddbc39f46dc472b75ae1dd280e7e0b9629e21f1c75b8cd70d951b1bd508b61f814cf9cd2afa15419f1b696ea0f77900000000000000000000000000000000124318028a059cf4c6091b1875a7e8da8325680ab7e71723b3f5af3baa0d8bfbd318208f0a5a8e65e07c26a731f6ba811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f6e589fbefc3b685a86c0804d73157548e741b60c68915a23bd4fb2a5b13976dbd350bffec4d6b699387b4cfb6aef3000000000000000000000000000000000373badb1e0f6de06235a44540801f95d321b9664f0b26b6389e9b5eaa9a3a6f066547b8560bea929c3331b5b56e04760000000000000000000000000000000017b6172dc2bd00fb3e8bda3b141ccffa52acf302dacbbf66c074c8c94f912c6e75190815381dc247d11d3f1d5f8441bf000000000000000000000000000000000beea1124c9f899749d867fcbc1b1b218ea3071ecf972823a3241377436e9e28bc73dca360b5da9ebbacb9d1af3f07961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014851ea2114886c5cf1c7f622d9cb09c0b17d8cb5e3f5338e1e876dc6183e06b3abd0241ac95fbebb58a7993122210b70000000000000000000000000000000018f556b21f923e4af217c90f0a80cc16425b12febd074c9738cb2d72b3cb2f82dcc562b3c012246ac8cd7dbf72906c8b000000000000000000000000000000000a2c855fe630961b9263322ea653187040bb415d2795596e1b2506b0a064163252ad3b12afc20bc80668e02664e33a720000000000000000000000000000000013e847dd86acb7d4d5a95f185311546959c8fb072f08fcc4b87ec2f191db3d96b87239b2b793cc4573861d4f84a12f4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001666d9bd55595213d99f1911ff0b08c86e4ba8688fb1a1e0a4f50474d41f79583c0c60ec849513d1d23a0486a8bb6063000000000000000000000000000000001114c8b5b5196b8b1223bdcaec062f5f25975fda1b6ed1298d6479c0a1229b371959d74fa29ce3f990bb90ab6a374cd400000000000000000000000000000000032c5985b2473e08a258f9aa189dd811ca7f63c5c8f040b7d5c62365f3a0d0c522a2a93927c2a4fe61200e9851e14c17000000000000000000000000000000000be55a6db7193c9953ba680537e7b5868d6395ed6db1f2e34c7ead02cfe86406c32ca17abf59534b7b6525fe01a4e1631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ba83bdff23b63043c05966c7d2713627f0873e47de995d73e273bf8fe112a0fc71ba82081484cf66b037252be4f51e000000000000000000000000000000000e360198c75e4b15c2b930a05ce3c7a59151550d815ff0f3c76f557e3430922e44958639891bfa29b97f33a99a0948340000000000000000000000000000000012b3629de66cdf4a21244d1c1a48521f4498302e3282691c0c2e04b0e8b1ba8a71bcba330e0d7a3829f84e8a59c1ceff0000000000000000000000000000000002a8d8c8ba8f1c3afc2acfae25a898e70d26aa72ec6ebbd61aa878da0a20db105b1f6e6c3c0a07eb8ee07e03bf55d7e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c569a35fa824913d6b33b5af5b1e276e42b7fbc79a6934d55872e33b14249a87e360fe55fa9c2a5c20b8ab99821e71f0000000000000000000000000000000019794a5eea6cdb571fd35243d49f2353081ebaab54f03257141af243acb5d10fbe5dc234e3e3a2b7079a8e764873717b00000000000000000000000000000000157aacc621ad418dfd8918a318311bdba8863683059848fcb9a2de1e53040edf628366482003575b362b728cb55ed15b0000000000000000000000000000000019f1384b27b50225167f47e60adfcb300d0a8ef76a0e6c7d73899db94d7aaa88f7f2071fdac9eb5fff12d48fb08c87bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b23938eec7c38a0fd5e23cb057645f05fb1db34d99b7e9f31feb96b9b614e01b73a84e4679e3aa31da923fe0dab0970000000000000000000000000000000018b47de2d462472d81651156dbecd10a0224a6da783c16d105918d0e1bfe7da122f225f4a8a90395c6e388c909862d6c0000000000000000000000000000000011992a81ada40afec631857b796538a6c80509e3304d9a0ec5d3a4c0c57c0104f69eb5d8508c70df54209c89f908ce9c0000000000000000000000000000000013bf6c1571d5cc1e5bad3836f766949df746b8f4ca801e9cb4f3ef754559a015f66eaf39d39d37dc2d61265769f8925e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000484da6582c0b120909717ca7d6ace183d752661282186224cc87d212badf4414dcf16bea2c8545bc3ddb7d64042b71d0000000000000000000000000000000002a9a4bd97f25d78751f8e777ba2556cba3d2ebf80ae0c7114820e7775218f4c9cee6ef25c767ff49737f998876665910000000000000000000000000000000004a4ee59f280272ea71e3ed2a1f30b604ce3a35cc64bd03a62ec544003a1a73dde59e3492c6356da5d8d2b63661092ba0000000000000000000000000000000008eac18e96c1b4d4cde118d3a81b33687ae5cfd66a02a78afafa47872509d7fc09b44e59c658b46e1ae451ff6b86e6431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012bdb50d214f8401ca4d4cb9cc2d82b3149679cbe28ad88a156e29607f27c737d2e29296a9cd2085259df5730ee659ef000000000000000000000000000000000e9fa2cd963d1af04102e15e89652997a26e94dd61b6d0211f05d54b9a3530dbf9f7901c6b5402a31f608e7ea807639400000000000000000000000000000000194709c73d0eb70266dfb890f7bac77395f94cbbd82ee08fde88027065bbb3d9574d7320135755ac1b5e8229b486ff47000000000000000000000000000000000767058abbd3ac26cfdf0e0d134962810499d0da5dbd3f3878f05ae5ddb397bdd253c5b1042cd0c159e91066ac2d8e3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d93d44ed9338d5e3443901544dca6be218d1c2f7366fcde2d0500d90e2a08a962dfcdb5e5fcf690dab3eb702f03598200000000000000000000000000000000024369733b502268af50b48a142a0ca7b187696fce692a1ba735bdca6902ce28276b154885a4571f5a129f20529c40a40000000000000000000000000000000017993b6eaa970f3c3980caa3187c075e0a039d3b03f44d90c979e2e8727c76813a02b305b810f95ecb2011767fe96974000000000000000000000000000000001289023d71ca945b684c661db8f4cb67fe473ad241eaea27bc8508793934b69e647d794c9ff6e1678a564a927e14b7ad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107d582e8e252379d6536ea1c679fd877c4b081313cad7b5ee6992d10e3f0ba5acb82e1e00ff38e57d3f54a06ad4775100000000000000000000000000000000102c8e8ec91062e6a0cb23afb8ec1dfccdd006270133e1d8bdabfdb4968e83d078b0444e3bf812d1f6f7a4a0aa300b07000000000000000000000000000000000f583cab7dc9d7ee1497123782dd181fb1dcf213e1b4d3d54361d98bfc941cea0a7600d7acf2fd60fb60e88013bf40bd0000000000000000000000000000000008fd545c8c6a4a48bfee639ad9fbc5c7416bace5524117e3670a02aa7ba41146ce8c96961a81f7fac66deb6d891657771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f56c81e0b4a1c039f4a2a3582b1ff9cb15f244287a6f952721f05139ccb9453b85f37d811e28be09a67a49c5119830000000000000000000000000000000000441ed1314c4116b3b80abd10bf1c8a4f9f096ac224318541292110fd0fac4fe1689a63ee1c21ad14f69d123e0105116000000000000000000000000000000000f2874662e7cce59438e36fe378f7ab47f10845ae0053f07306363e42ddc803d1710141f6361c165444c0c48b91091d5000000000000000000000000000000000a74df92ca74c59c1050684511f90a94861569b8629827799de1f436fedc4339a7a7dc21c947fbdb72845684617a6ed61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001140b749d2a793b72eb1f3bc6b7bf399afd699396591879649d3666f04433de7a87d195859bd601bda7be3c0179580af00000000000000000000000000000000000387409869ba81ab3e39e021d50036d7dda56c68c1fef803ceebb6d96903686f52e45f888c7d24fcf2e57912d7c0b000000000000000000000000000000000166e863227ae03b8abd021ca3fbf62d2307a9d78bc0526da8bb483a905ab9a04e66cb828844444afc3926bf7f3f67c6c0000000000000000000000000000000011b4fd5a0246d81cff3acda857b6522ad35712274406de0f9791b4653c404fe1d132520d2f9d02776fde09d2f9cef3c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f05d4a128a71a58cc7b5a850ec072b4fed58ddb433b1f7676c5117745e88d91b19a5ebd3889b6fc4442eb8d4f98659000000000000000000000000000000000f8df5db366f3aad5935a29b94098cd492176be8a29622002ec84eda278b5b66082e7a49d8a224965649308599ab9f7500000000000000000000000000000000167e6977839b5c8ffd01649c661fc6469da1823c641dbd55964d657fcb493e958436e298757b24e8d351d30f5ab88ff10000000000000000000000000000000005b92d340cab98186c56556f50ece3f4e32a655557433a074e282df52e444ca79a4c92374d4047cdcb5de13d251f74411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000229d1f6c9973db384ac9e8e2cb0cbab109e34a9ff4313bae1b410ba4a24e7f6415f757419ccd999604bedda86e544ea000000000000000000000000000000001620c340ac98b2e2bbdce5157faf822fa8ff7a14e696ec2787427d17f8eabdd62c469e4bfc2bf3ffa5dcfa66595fc4ab00000000000000000000000000000000022830aec36bc081c707db713850aaac4452bc48a6e6605895cb3982b3fcdb2794e636ddd79b04b193ce28aa5371dba70000000000000000000000000000000009f026c6a4dd3bb0b534c21a6231d5d5cb870716cb986e7b643c4e43b856c98e8badac3ecfca2bee155ed81927f2ba8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092aa2d6d3b465ab5e509a3a69f91cd362ffecf726ffacbf948bbd1ea92b5ec77a5eb11d3092cab496fd5b791254eeb70000000000000000000000000000000015eef2ffd527782b718d83688175e9af1f7d2b2e432eceebfe07a165751de5ce5f66c241bcd0083eea5683302d874a06000000000000000000000000000000000524795efb4a67c0c9b4d056a0c4e94929388d44124ab664cee1877836a162d82608b4fd69b7f698cda03f59eddc6b740000000000000000000000000000000003c81503950319b3d00ede11ba9e6079076f977e3e882e635091c5ab13f8cd0e4f210d9dff7ae1a8f82a9c56fdcb54f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011430bf125f791ff10023d0ec99286222b96037d82980dff5776ec225c0b7a4d9406ab0631bc821f4118350dca8d10e9000000000000000000000000000000000cf8318aa3535caf14a4a9a1fc6ee354d7277c8297e67861e1057ee1a3e4d8dd14f9a924962cc68cd973fae63c1b844f000000000000000000000000000000000aff41c5b5537dc65f460ba9b9345b0c499a03cf40599250845569f79b5e5f7d4c29585e97ff0cb55973b9095afa4c8c0000000000000000000000000000000006b0c2f5d4f393eab7183d56f94ad7eddbad3a64678f68fdff8b5a567d63ce4dc79abea3f9d51e887e75718d4c281bb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167b9f8504fa52de2e41da1b8bec5138016d0c63b18528a4c92bc017560ba989e79bd2d6147050b6eb8f4785cff173fb0000000000000000000000000000000012f9e65102808da959f421c28d22dc6e7e4daa540e00d1c59ff0ce39d70a24bdc08ccc69c7d7784300a625282eab28c0000000000000000000000000000000000bb3e841c32d79115470b44c15f658a3a4025776c1e2f5f1c94b2f4d599a09992e9c0f598bfbf7f4627a2f9e39de9426000000000000000000000000000000000058012f4a8c3beed3054e32d1c2c1e216a0a41b7f1e64c3d604b3f8ae839f3b5e1891c6d3d1e50b47ac182511cd74c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194cec814380c21010c5831c74b3337d2569a3ccdd65c02e1910c7fa24929b66cc64095ca4d7d1abd585fb610d33720f00000000000000000000000000000000095cbe2e66e78a8be9778a983c806d3c434044df1c49d32e26dddfdc4c549014d368fbc4056110576548c8fe367ed7b500000000000000000000000000000000047fa8f3288b40cd26b03fb394aab6254ece93a0e11bacd90dd1a8900c00cf23470fa3438368c7758d16193ed8dc4ba9000000000000000000000000000000000ba4a684abb610db708470cddb163071a9fc01abf2132d839801d3a391559dfe65aee97c96487175e0e014d3d97fec9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161e988de7034af750af33f638c62fa0a8a51186a0f59f17c746a51f926203d6180987f8c6fe486adf68a45c3d4d5a0b00000000000000000000000000000000156a3f22f153f2aca6244e31185359aec663a6d3cd3a15965bc63772d82210cfbc31f5a97780b0a4a9acec0fbb7fd80d00000000000000000000000000000000167a9584b916b3e5edc750001a59b6e93243b72b229340375caac62d17483ae33142ff4ab6e4bf46b8349d64808637fe000000000000000000000000000000000a079db6f23e4945ad18c43a4adc5bca36386f02078435c493f55e0310185d4304572585b409b2e764a2affb950cb6071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c33234da7eea050e79c955469ce0ad23dc8b24f9fcd8d1a5cf88e0aae8288df8047b221f9e935a5de43eb2097546e62000000000000000000000000000000000ffca4840f9406f812f4c1d336d03fb6259f4cea3cda10bfaba7a8cce381fedf3cf140459769908150a3a82e89b283c8000000000000000000000000000000000cfd3df51daf18e7196a6e4995350cba540ae047954373e8117157f2f598dc1371cbdcc72bd41a38fc58e5b60afa012d00000000000000000000000000000000121c8146ecf87a6f6741c9155b50def6cb323fa7529ca64d9d8441585fe5cc2f489a026d5f73c09e030310ef8feba36e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090ed22858be244a4075953b0451357e973f78a5496497828fd389e75f93d1cf125af790edbc1af082fde1a8ee43425f00000000000000000000000000000000137a4207a05c4da33bcd73c327de3b3d9e489a23ac30ae8a3762ce285ce61b8348d0ac0700da5398f078bd916f6883d20000000000000000000000000000000005a8f6c8ea74004f67cf1356f3a142116208432cd060d64aee37720892ab903ad052b0ba60b329f2d2005b6fcf3d1f3f00000000000000000000000000000000052b2b29c3e458e5df5767e0336739756bef3c146f1caf914eb224e5462dedac9e595bd2b4addae60e6d14c6a2edb67d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000945edbfd6162454a85622f3dc7af74ef158da53e4391f63532af2cdfcc5aac34ec09fa674c68c6b09a7c66efda4877f000000000000000000000000000000000d395e75abfb1c613ad98c5a48bb38375bad804f409ac1c34373eeb29d3507296e71fe5e39858dc23976824f68319aa7000000000000000000000000000000000652f6197928167a06d890679ffbc9ff72bb323ef8c7a918daea286a3f9266a44ec615934fc17c27342460bb2dc425b0000000000000000000000000000000000c90ce4c02f58954aebf368124abc39049fb3d8825fee47150c0d0f85334cba2d76598a28fc19092723d8f8e554d27c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000158bd33903cb1dbc901c211e8c308ca3b502cda446f7434e7266ab254b51cd9edd96a598ba98762a29c31c5d6718a9550000000000000000000000000000000011e7594d2b0b31bcbb390caa42fa9e332554d13d86f3aee127c65768c119a302d9913cf201e5072aa60996b2039f45b00000000000000000000000000000000003bbdd1dd2c1875650c1881642afd3c0ffc996b1f211f9a48801579afda7677a67f5a0c49361307730fb62ec13efd99b0000000000000000000000000000000019a8bfc09f840a7d959e5675881cb1f0da62290fbe8b9412b2c00f7b0b9b5fe7cd889e615701affc2c890e16f1f3628b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af9bcd5c687f5d1904b45c1fad3f12fa92e41ab546d4badc4da210da832a5dc139c191910345161e5d632417cba45cc000000000000000000000000000000000ddd84fa783bf50e77276ab6cf815359e8550973fcec7a3aa00c43d156aa36df77cf9c34af2dee0ef6945a68528e041b000000000000000000000000000000000ac0fadb2ba465b6d9e1e27ffce8331c37ecaa6f994a29d84a3fcaf574aa8a1945a370f56d136aa006ee660493c620ea00000000000000000000000000000000072bfb0c3352cfce2e8173468a66ee23c81dd7b3d4322ee8805be1d8ad1224bcd81e02ef8e6af594c42d2bcf62f6bd3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148f8416c4f75c02dbb04fbd2840d214c3da50f7cb1ae3ea57cf51171f9fb754342ef4c2a7e98fa01ce010a5400c6a640000000000000000000000000000000003f30dd8f1784e9ab30f07233094b67c22437518f4a27210b5762765c3094b9509ed5250e0bf75805e2b3957d43a55b4000000000000000000000000000000000280830549a36746e1e9f2f221385f865f9dcb0f8a7250335a00b8064bf327d2a6859f9ac730347efb6652324fdac00000000000000000000000000000000000050dec11250eb3b516e6c292511e7fa99eefe5a2ec08e0ffa3ecd26ca6c9cc7f683184c2c5019d6d9e85c229dc80e5aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013be3534adce776187a79a1acb16656195dc4c286ced57d10917d768d1ae4dea1f248dc9f12e33f352a4ee95c0d0ed6d00000000000000000000000000000000068f39870a08da3d82f9ca5e82814ce41a301b5c47a326f3f3e66161e186d7fc6a5d8e408bd18f3ffa1c1c91e326419c0000000000000000000000000000000011bd58c82f5d6f2ecb12014ce577adfe9d5dd5a66ebc82d09ff5418ebb1f567e6df884de19988bedf34e386523b7e4fe00000000000000000000000000000000157dd6392b841201c5c95fd92379b1e0547ebfe704168bdf434a227704fbb7b1b6b39aadf95fec74a8fe0e2eb5d9a77e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1ed68d2f589049fc661fa95678cdfc3485b460fe496e63d193cb7f67879b377edb342f6b1e0b6d500b1396a0adf88400000000000000000000000000000000157633302c718c7f2f771b4e876f3d3ce1822ff0419f6cf151cfdd91e9174e37e9e57abbb3e9330f63a3c45a8a8cec100000000000000000000000000000000011e8a805da50e60360a8841c13dffda894957209aa7a802a847a111403e1b20a0ee6339c3c60927f36ead0a62f3c349a000000000000000000000000000000000d3479c79fdee6e7aec7640a0045de0b399c2c8df4bb785f639d81270febf55bc97af4cdbd1eba5c514ec5343e57e8211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000046c07a1455c91ae8d9828ed569805d7451f9e45c8a2d44eba26a3582e3304ecc9c6afd03b7de00298ef00420a3984ec00000000000000000000000000000000072a8a431e2fbbfddd7f6793c100117f8be2dc2316a603617ddd2c61ed3a56baeed1f55f1721dd78c90d3580d1c94c9b000000000000000000000000000000000033585efb4822784072950e92a259f621739a8ebf70bb39d30c97d3b61924dc1b0e5ac4011a441d564cd2ad58f471a20000000000000000000000000000000000bed9f30ff5c9ccc7c9fab8107294da619f10db4aad2985d5cf3e194d6f88f993f07443544434de0665a24987d668a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a41329637cab7a6a439527edb905c3ea775d86098e24a24c9e4ce94b13174db56a8f6921a6718a06e39e4c2cfd149e000000000000000000000000000000000130ea6b483974b61b14743ab9dd13a21ea2792ececef70604f6d3c5824e9c94f85dc7895ec5af0ba526aa22f00d362000000000000000000000000000000000114b153bdadf64d5af36e2bad386c1a12194ef3bad5b58d4a2e9d57e94364d92c7bb9de2b282545170057ddfaa70ec900000000000000000000000000000000014985bef69873db45683d7e7ad160786c9b97a302345bfc4ea6cfc4bb141ae009bcccf786658797b2f59645aaa6206061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148fa58969a7e14df9547858325b801fd732b66d33e81fa73b994b462be0b937b75a816c47ac9786c70489cb1ef3103c00000000000000000000000000000000029e14faf13de377569f2c92657a617d57de6a2fac40d771a7db8fc09dcf6450582bd272b8bd456aa4a70114202c810a0000000000000000000000000000000011d45c56fb6ed8f16ea72539ae9bda7feb51737444a58dff3a4b2931a5947438e11598be29474270a7fab273682046650000000000000000000000000000000007c099a6c3c5ff9658b21e6fdbd5bae7f72638c40af8bf756cbed4e38a73ce0ea6b46b18c8f5bf3b9d2ec86adcd7f27c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d6d31fdd93c3b2777b3ba6c000f6c03ed95d0eb1ea3fa749340a2ac64a4abe7f8bcbf7e97017ee187cd269e83c5e2e000000000000000000000000000000000a6f32032d64ac1942f2874137c17dc517f184f31568c7ba663d8b9e8f80eaba363f7427723a8d645a70fdabcb767d3f0000000000000000000000000000000010cc8847166d54c47476a41ecfb43bd13dcd2aa9713e52c7a12ecdac81f6934977809d05e86ef47ae9625a8a233380030000000000000000000000000000000002df6dc7abaec263001b00de0263255dfcfefd1d62dcdf6539fc54d9e5a1c1c6762e369807db5d25d59fec7c016afabb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e956695307f67e13142528c389ef03b1b30f6eba37fa39fece565ef9efb0d27bf52a1b8e63131561511faf269be0a1f000000000000000000000000000000000dbcfc00f7fef8b6cfad3a14af3e780b3aa6f24e05eccd1590f9e87b9ea902a17c94a357d14f7fcb4adf6bcce2b45755000000000000000000000000000000001323fa5ce5f7143096f8915696f386993945cccef09d34f178c5fd99a5463cdd3fe8b7e938800f990a89b0622e68478e0000000000000000000000000000000005705b775e8b955ed8e7f7e2dadff73f5471302ce81f5ff9e9a32a94f405f52fab2ae4e178f3478bbbdf2f18801c118b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118ed3b4f1abdc298bcc89f1fa21b3491e8a31d479748691b741c1638be6aa7bcfc3fca88f1e3a0e3b061a4375b2d85a000000000000000000000000000000000241996a5498ceac0e5745015e687e96390a0febe60f779925d9bc280c67e1d70c79b18aa80b0d45bd99e8d4584e78a90000000000000000000000000000000006716deb77634e0349612f6cee427631342f983c1d34397d5e48b2b33834ae2be01aa0d90cdcde637de3207d63df250b000000000000000000000000000000000b38dd48dea5e3ed33a78f484c64b4054b7baf2dbab5bcb6c904f2d3f68218f66ec2b06b2bf8f1e82d349d58103419351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6fbb53397b1d8fd41bd0f67328592efef653d1e1273e1f6d9e5fdc614517fb778062c79dd10aba8fb0c9b71530ad4600000000000000000000000000000000124a8b3c42bdf68bfd1481a7530eaed4f8b479b0519a66141c88b8ac22e01f438cc1050cdbc0b76e13c7da88ade43db000000000000000000000000000000000023543819ac26f3ff2718a2b17bcd2ebd9bcf7e646b86e80dc8208591a50c18e02535d33afc901b555cd0fdddb9cfa6700000000000000000000000000000000031adace62048946f92d23515d4414a1091c26b44250f0b3197ff6d6f9b6241874aa6d41559221904500ad05edc49bac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018b15011c164379dbbd6a62b9f6d7c169fed8a0535c1443b0d46cce088192a8ac239a23c6620a420c1d1430381f57c47000000000000000000000000000000000caf0edbe7865541405c620a4f8b4cf2383a9dda32e2cfbb78a21461630bdb998095a7ad020aa4d66319b10844621b14000000000000000000000000000000000b5e9a03f7ec113035ab45b42f31f9e8853a99606d9cf798378e70f38b52388990051d7508d34a69a298db36b87f52460000000000000000000000000000000010f4de7687f5b2084109412094194111dd4af2e0d8a8a11290face8217b9c5bb6e633a858276f3dbb58d3372e99e7a141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000106b4e04353f6a8a8d671c2ab617b6335e83abd0d361375cfe6061dcc22e2755121f1e1b432246c318b0b3ff20c2283c0000000000000000000000000000000010166f90b34b546f21a3c82a4181e20ecde8afbe594206da1dd66b9c609f77df06174419501e8cad06bbea96b35898da000000000000000000000000000000000f72e13fa6546ca33fa0349306bcd6646c6c84347bc288076ad7577d04c71145551a84959f44c8d5fdb3ced1dbe7fb7300000000000000000000000000000000191bcda76b18812a7214e0a4a0be055175e1c6b2a43aebd9a1a2413dc32ab8c358d3c1fa5900cf4e09837fa52a5a82bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107358017387b20c5db682e717595b0480661c1b921e80c8103d2fef217df55aa02e3f7d6941c0c6911d4406f5742b0c000000000000000000000000000000000d241cc4577e78cbd37400a5230bb519d647c51ddb062b892b6ec8badbf86f02e169b9284bef93ffbf857b743c28e1ab0000000000000000000000000000000011a7382f55fcf4539fbb6a9315f65c21a51cb4853a11de2e1faba01b4eb6d7a47a932ec5f5d2f4175d5a941e97dbde81000000000000000000000000000000000842041e7fa19304a79e8c61787cfb7ff2bd37967f685f0ff42cc784730a060b3392202698270584fb7682beb4ebd18f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000193a9dbf6afc1bb9f8852fc0a3e6467e5440816508596bdedb0308522df062ea6c72ada06b7a1023981a93de76f7a16d000000000000000000000000000000000c2cb6bcabf77177941428f632cde41ddbfe6653accfad9d2eb06dcdd587b62202d674db20431ba460a3d9e5eba75e2b0000000000000000000000000000000009dc67648b10fcdfef5113d992404eb93217e048b50c65270bd925bdf64c84dfd6799d58bdd3701f7a904b47091fea000000000000000000000000000000000019eeaf62c27199722fb89f5b119acc8dfd1c9163253df05caa138b091874e31adaa8e2951089ec76682e941cd0fc3c031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c26d32e863b5a0a93a502f124a44e7e48c41280c6254f9f4c648a5722a189ff59295308895c39d4f75fc3b1cd6d732a0000000000000000000000000000000007302e6c17e291b19fabcfc10a754a5a4ed9b7de77e1f4c6f87c1ce162f6680bf942eacaae689bb885ea44e6b7a40f3500000000000000000000000000000000195391871b83f086459a8c078d3b25a692fbab2cbe47a6287cb98b47176aecb6522123195bf829620c7163643ef6267f000000000000000000000000000000000683c641c9549b0ac23b42bffa198301b519840b6e92c3586837de2a5925e684b0661384e51a0b8e93761e9fd1e6b2781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126c41359a52c4b60c70086eae8bac5da31d56057c395ee4b17415fa88f5a0fd04d55c217f7f9bc3d442cdf7f4d418d10000000000000000000000000000000018169da30a973e7ef1f491906acba73404c52055fe272e969fd9a7c25d11ec0771d9ef571e6474f7ea479250193b2fcf000000000000000000000000000000000e8bc103708ed76163b5e355c84fd17865b7fa8a0950e39d2acf8c6f3abd9fd273d8060f585f2799cf98a3b0dc10d93a0000000000000000000000000000000016e37d22c7d3c66a114441c96b677d829b53073eb4329ae0f6965b525b6e32166a0eb0cd98e7d690517bb56bafc9f79e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb9fcf8d8760a1b8dfffc1bb281f1fc991b14f79577c2f8f95dab4940b6c13c1d88c37f3b7ec047939fa4120e5c3b72000000000000000000000000000000000ac99677d25a78583d559de1806514442353d8daffb44a4893ada78e1fd394e97b4290b81bf2c85af42ab919115f7b5b00000000000000000000000000000000016b5b61b3384749f935eb7e47072aaed4149b54e1ab5b4ad5608d3c7557363ee84fc0107fcf150fd80f8797248e2370000000000000000000000000000000001983ddb827ffa40ec0f97451108d6f2eb77ed41b379db4477a0562c3865e996b54579d70049febf82880e194fdd73fee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f64f53696bfc1742be9c9a36bfda36d7e830c822221521b0927145c0c5813727eac4c4697aadb732c7d89ed3e1f5c080000000000000000000000000000000013f56691eab06db2ac30a39050189592501c16a6b846943e5a9890dbd466cb03e7e7b3bac312da602bdccf1605f12101000000000000000000000000000000000b8917fb95077ca894642cf29ae1ba5cde58c05f10c7a67e472b03816828b2133b9553feda4d81766b8857e609ff36c7000000000000000000000000000000000b4dd66857eb4fc0aca1c6dbccafe8adeb7b1c9a701528e92acb5055b51166beed04ae9855f74ac5ab3e419344773ca61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012feba07773004ab5abd5863aba51c9eaa6239a1ce917f0fc115afc8c28a2f321ab0caf4a6afa243c4e578ba2c84bf7d000000000000000000000000000000000f6ddfd920427a4cfcbfd24cffd0253b3235c84f97dddaeeb79feaf71adeed50ddd4b35463bacbf31c70da0c7dc82e5400000000000000000000000000000000012499f1dd5c2da4632230d37b1a870b6b12f705d867d46d92e6ab3bf7caf4c2da9541b119566be689564390edfc57d60000000000000000000000000000000017e789b489cd4fcfce278d7223c193f96b5df27ce79b7a02ed73c79e8c09e862d8a88f23221fe6234f38474c979a2ba61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011334414efc070d879c30dcd8496d5cb75e09f088c8ff9b4c4b71b96f0952315d8c840d694ffa8be023c5727f0f2ff0c00000000000000000000000000000000051171cf84c64652b00a15342c9435c31f6335b8d43e48481cd214a794f97c9f1cc8c53e00d2c64e3596eb7a1c8db37b0000000000000000000000000000000012e19c2d63b1b17a54e9f7d5daedabcf283a45a7cba86f778f0c1c16d84d42e75cb1a50dd091d33f3d2d02df2c9fc40b0000000000000000000000000000000005d5cbf9554efa3e6214f6353be67f3ab014cf7ac979ff7020932a454dcf9746f114581d6b8ae4055281091bad42125a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001948194d15391fc54b26e989d233bf5080dd91f60021c19c50d81f9a6b465c6bf9d3ebbf6804df8d0e271e20d5739d2e00000000000000000000000000000000044b65f359abdf07142773bb7029f6a779032d7833650efd95f913943e638fdf538b43735c6fac617f5eac5ba88f94a00000000000000000000000000000000008e097ac73988395c07099681f44f9a151dfa75575b86a7c083ad8110ad8bd4d9c24bad6c606d1186ce73c10d76ab7dc000000000000000000000000000000000c5df1bc05244707d6d2a86c515e7c5ea25422679a244fee8056fa513b0ead278d0a3e1addf3bdcd716ae3faa1b0533c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000007c1506da644f85a3e1825dd9b42548b0cd414af498782030ca34a3af02731c4eb25650179ab0f2b18af27b55cb0b370000000000000000000000000000000003e7d6a1dda11cb7f1cd33a71e0238e5a0e11e029bb5f23e21507d3437bbd6dca4e57925eef6760976fa610a3ba574be0000000000000000000000000000000018d72461bdf1f2a43fc932cd6bf1fed07b8670615e356cb75f4470dc6d3b30c58c76a4381ddc275b363d490728315c1500000000000000000000000000000000068fad8cdcb135842dd574542269fc1230c2a07602f3f934d06f24f39188dce6ab32cb7c4e2cb930a118bd6c3ff4e03c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007caa0ef37a25592f5603f7859a9844e79a178bffd60d997013a28fb692547363b2a2281b969d1e1cc18bf0ddca3e4a900000000000000000000000000000000165571effccc21210797627760c7a4fa7fa2b9586740ecc7129c7c2b20b0e0356ce5c29bd59002fc9146c82789674d640000000000000000000000000000000009a2811b3ea7ee8b1d2f742a28ef7757c65d91902d6d4ecfdd908c998be2dfacf03f067e867c5f5cc91342917f528dd6000000000000000000000000000000000c4f3e2f27fce562a06f93d30714d13ddf734648c2f5212c9e79e1f37b5df00cc1e748493e3e47d7282427f4b96fcc661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000319a43d7814ba5af3b66a901d4e39fbf5513c377ecefb4cdae6661f0dd3ed37932d5732c7a308368c1dd162dc4af7b700000000000000000000000000000000064e7386d535e9431e56b743f04b9852f8350afe12a1c11393d03d3f842141c395bd47119f96247f977924089460fb63000000000000000000000000000000000e204c2ede2084e29fbe8057bcd9145dac9537545a631eb9643923dec0ef1f6d477feb0af3ed0946d012f88464dbdb620000000000000000000000000000000014c2750d4267971409bfa62c1692f745f3a59e78667f95b1cdcf056ee119afb8808c1f11dc041227878305a79bd8cff81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a33ea2e5e38d2dccdb7d2fd25ec72a9c8e28679f5af1d30b51bb78048216653f13f4daed2469ce70213947cc71e5d2000000000000000000000000000000000dfcc2f18eccd32258aed1e3d2f13240cbb653e5bb8479ae730e99a96dd7b8c36a7caa052910fba8633b353259a179d80000000000000000000000000000000010cf7bca96576960f916386f27dbfcfc2734f41e87503a16740fecfdb1eb9c0dd86b7490173743d6c2916a4ed022d49c000000000000000000000000000000000dff35cd4eca984221817444ef8a88e478885c0fa981a179f2b42a7ed0c93929a76f83cb3a4ea5ab6eed279da50952971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d13abe80c13d81ec602863e52ca9e599d1f7d4bc952c26b7b9b8715bf1f6bac74432979eebdbdd2393d96b3dc9864e0000000000000000000000000000000006adff586cff085e99925a25aea0c437a2a991beb14b235df6e978a1104330ee152dbdae977b0b72a4e85f710db684f00000000000000000000000000000000007ee67ba0d2a0240e1ce44b8108f7a3e837878ac8d43d916a0a7a8ae0216243707f3f16f7ac05d319bc218a12bce80830000000000000000000000000000000004b25723569ccb3b25911ca1a07f341237f2a053e1325052e6527d35792e4840f2e9d02622a1ef8ecb0dac21df9b08391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001484a040ea2bae04139a34da6f809d74f80aee94af1ece6d06b29b91b2b8f21bc6e15cb5a953320651df2fc5e75380b40000000000000000000000000000000005242c250821bf498ea7a5247d38827286ce758d73c742af398a7ddaf59664944f329268c895dd52224fb0ec500722110000000000000000000000000000000010f6d5b952764d4b6cda0c36fd7d26546fa8df045efcc49db1d766d7d7c0cd76abeae3a169e1aab47e1aec289e1a8cb6000000000000000000000000000000000fe94bc1bf5d8a00e0917ae3886945ccd1df42a1f3f72a3faf02f0aa74cbe7e4b88004052592fe1fee6616c3d61a9b141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039207eb0c0ab8d79fde1e0b0b551c4781abee336d01ad1cc6601362f298d070816ebc370f8fe93b3fd822d4a50428ed000000000000000000000000000000000626ebb9b76ec89ad3efeadb96ef186bfd10f80ed0293c865e440974f8508f5625f329455f42c9494d0c8bc1622f7129000000000000000000000000000000001451e402e8d5487d08e2d3b0c2cb7098e751a4464a24780d1514f1166c33cc376d722f6a10131f561aaf6e2a0b1c03af0000000000000000000000000000000005e5c8ddac9de05efe4bcac5caeef10b2011927b33eefa0626c178fc2d05392e38ebbc5f587ba9bc91ecd846687c63411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000162ec183605c2511dde4bea1a9fbd6743162d26ff0d0de184e0f80d6e3c924d239114e55b9013caaf42bc139a0d05a640000000000000000000000000000000006c39bdd03c1c548c2d2f56281e679e7bd9407367d1367929b8c138ffbc63c3ec27505d01d5991b4b009ebd14efc3b3700000000000000000000000000000000133bbb87d98dc5027357ea143cea22f6136f1c2513e7d843283555378d6460402227f59e2a298a96408393bef880c2d60000000000000000000000000000000008a76540091bc9d3b0f3e717faa9c120806ad922b50ec43f09974f63340c3de068b1708be15cf2eefe95f6a845f83eba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010634708ca838cef03b96ffbd149f32460e9cc83566ce2585c524ba35af17954f78d7e4c38f066886a63df282a4a4708000000000000000000000000000000000b5bd6d673588012be3f1ba0101022924eeea3f0390edcc4ee2fe31e2acce9bc50b6f597ae97cb3c8571c156602f650c000000000000000000000000000000000afb476b6caa7ed864720ddde1f44209a4cf2a0d919464011cf0412e6ab34fb313f7840740ba43cf0a7492997610e53c000000000000000000000000000000000b3a7a785641cfcd2f1b0bae1026ad90ff68b88cce7105856f672c630435b0d924cffdb6c4177023c7123bab00e2d49a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131e849c2526dbfb0c026e63bcd7a4564897d12cf9df178aaddfb1cf7124f3c7e3dc505324d9c733b0cbc568e52abc440000000000000000000000000000000009dfed16626c4577aa2bf8b1f18c7a0f99b0baa67c1f3b605bc7101751dbd958ce2e70091173a0cc2ecad77911368ecb000000000000000000000000000000000db74538bd15c5cf5260bd1513ba24e93177f1b8fb7cca5bb38407f60028b114e686bb8a42af786ab2d38971c26cd71c0000000000000000000000000000000008cb7da1a1cfcae739b2e70da75ebe5ce88003b0e64e76a2bf14f014dfe58668111bad41bce8b04c6f936580e866de5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001910f1b7653d0f6c9f3321091688e0a1af42083a6aa8d857121e0eb15ceb013d5af2596a6d38ae51b2c370a388511f900000000000000000000000000000000007612d86773d41236bdddcb64adc9603c3d3fd7260b02b2bc799ebfaae739be263047f538dd9290704a88ac9173de20000000000000000000000000000000000196cee11ff27df206575e7f1dfc1e66bd34d4e56e12efd4c3336d10a4e8b42fdc5f9e6922c1bd17ec51ef746b1dea399000000000000000000000000000000000434fe2aff07c2cd6814f1200c2b4e3ba8d6a490bed42364e60ca5f148df5662095a816346810dd752fbfdc4a1dbfc681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a834e016100229c31418cd1656c294aa45f9361678eb739771c11b03a96b0a0fda7dfba97e819d32eec5f26d17e71c20000000000000000000000000000000014f717546a63bb591db133ed2a18a9c0c6c17a368064465fc6c15e05e2fceedf301f90401d1793d86d14e97309aa6cf200000000000000000000000000000000129224d30fb0c002970e954bb667769c9419b4b3d9e6cfce7432ec9bce93801b5881803bc76f36d123a453527e014a76000000000000000000000000000000000d5e845e63026b88f86bc1549c7ff33d0bd384be28e21a1be02ffe97b67b31af942995f15fd27a1d98ccd47d8344f2c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001593c45bf67558f518c90dda2a98ceef55813cfc5984522064df540118003ce50e25ed26cbeb13e3de795830d67cdd4100000000000000000000000000000000064fe133f4dbc162e320d7097079ac13bc3b524ab34b354ddebfa2d866e17f9cd7565f3d37e4db1fccec47345f1fdf0c000000000000000000000000000000000b37f17a24d92c63591625e4d664a6e182c25f58915ed1acd53f0d510728289b6f520ff6a83ae5af1adcfc4d2438889f000000000000000000000000000000001951fcb26d7c36ab06b43f8e95a514c73f09a91e798d9c22c99b22b48d4adaac7e052ac8ff662038fab0474a32de36501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0be046229986630f7aa765ece759c26fcd20e027db3da9320877c45c8ba62c9ade50dcd371f0474ae2417091b439b000000000000000000000000000000000033a48e75b898762d71ef38fa87891420befaf2defc79e634db65b694f6e104d6594ffe7a445d41d5e8b846e47804f39000000000000000000000000000000000631aa4436c3791fc0e76387c714efdc12c84eb8516581450731cc3e256ed9c92a41733d497e8a37a00f6603a3a36c35000000000000000000000000000000000c6557a4c602c1a847decd784f3214021536272fcf4593c1e27fb421f3f66e6e4b553330a25723d15ab09dc4c088ce5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8bc0e99e3162d95cc2698c6ee5deca568d160c6f0c407d71c7bfba91e284994b2a724ee10b58c206df751be0d9b5b8000000000000000000000000000000000a554a9495d1e0d2bfc3c43196cdecf63d03dbdb4a647c8dd4bffceebaa5eec05af3a572ca98a0dde92eff2361ed0adb00000000000000000000000000000000046aabecd5644a4bb82ba4e839e7bf92d2bfae8d9c60f07420e0b255a92b6fa0e62a284cd9cce83f343d5994d1d95ae30000000000000000000000000000000013bf2e9ba6033c6cfa448a4e3e35ba2d03fce76ff9c23a780b5e8aab54606caef9b12f3c5593611c591be380d093f2031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c039bc5dd2a0d25ca847b615a069d462f9abd3a7049493c8adde7cc8aab803066dac3ce56cd087c75acf334625895f0000000000000000000000000000000000c1a747f18a01eca9723f9b5ddef72e08371bfbdda517ef1343bae1504aa590b236b5b96446222b0eb5666ba1045d460000000000000000000000000000000000a22a6d4dc38ebb3a132913d4b26f4a0bf6d0d057c5a6db71f0dd05778a50f9e2e9ff17dd9ecd4b1afc69f3cef186e290000000000000000000000000000000003b6fd55fed34f7a8391a289abb360b022c46e4d2bbf4e01dab31a94b871124212a46b3ec663629ba107440a434521801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001fa0ad44811ab60f326825657fb5505552af3975646bc2c6b582596a6a9e8a52b331cfc40d782da02ff80610b07631300000000000000000000000000000000106b7382007607f35444f46b3ce4cd66889257ae2c5abc72231380b6e53bb844ceb1756e71788b5b0712ed886c2e1c24000000000000000000000000000000001261c3effa1338ee06a44e6e1cbc3da526396a577196d101cd802443e7fdf11da6c9982e636ee6f44df6ba06f9602146000000000000000000000000000000000707788b1548bea0788a8f8ed7852902d49bdefca9d0402603221bd36827ed4713d99de87d8585574dbdc86f1e3398011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194f1163ad738aa88a47a87701fc3dc06aba35879139dcaf518230fe43524958ad1a0137e348b8b9c13d8ce11ee815bf000000000000000000000000000000000d4c6a6b092a4b6773c06ed0d78641b422750aea26912449f2e0383305d42115fed62b866b01ac35dc9859f201183cea00000000000000000000000000000000097604ba7a791f3e90b439f5d9990d853e4bce39fed54a3f18ebd0582b9fdfd3427bf3a9c8b6074622605f57c85b63160000000000000000000000000000000019171dd195539cbf7e56a577b27c38600a920dd7638479f485f9c2b437f386e6858222dc921490ba0645b5199222fc861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000142ed612879f07123c3affa95d39e9d18ab3dd77b837d70750b1f42c14842a157081179b3ac9daa91e045a9f6fd9f957000000000000000000000000000000000af6f8db1de051835ef33ceca7f978fea1470148ae46119c0b3d24e173b077d5498a5f6d4728651d4b760f73d7449c8a000000000000000000000000000000000eabf34306e207b1987472d9819ffeb38fd30e7a3cb5d99285eb8c8e98c4784806da6ba7456349c9190c7c4b652e6b44000000000000000000000000000000000a774137e2b7260175dca1db65edb85efb394d9df79f68ccc814c057d3a0011743d8f228b41d23cec4519f774f84a7a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011949582891f35b0f5c4c8ade127129470754461055d1d1004eebc535ae0ea779ca6121abf62da3c4328420db28cce9f00000000000000000000000000000000197749429a268b646c8b8799eefc77034edeeace7f9460fdc4ec9df3c2cbffdca8ba45950b8ee6fc6c7abe7bf941956f00000000000000000000000000000000167c2aa82ccb44057850f8b6bc7c9b87ef7683014cd775aec6d0a5b9a261085b1854b0d2809433a049b8eb87a6821ff40000000000000000000000000000000016f08b4c09b3cc4b2c2d7903e06adb29632119fb6e1308f6ddce145bffed791b3a1c888d0b4b95027281131f0060b0bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000771de8e8660d4f9e1c4600da0e3d0abc70ff3ab5da56fff062c05c4e745e54e678c3c855b3e907b9571fed7b1202e140000000000000000000000000000000002826fa00daa313a80a2682720260022bfef9e31f4550ef3344ebf4cc594a6baf2ee29e1eacbd52cdc3407e9e5f72fe20000000000000000000000000000000002eb50bf8ec8ad3439e7ca20445d7951651845760860c1f8d281708669c34d032eb088b434c37757e00f7a1e6ac4961f000000000000000000000000000000000b1811eed32675e657a850f1025370cb22b027f1caedb46ff5ab77cc8a5b62e2dd652b1a65d48691520ad32e8085cde01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191315f046c57742959f2282263f1564f1a0783913bd70f64d752662ea7a14206b13cc685b4d3cf0c6bad5c85674f2900000000000000000000000000000000004994d47674c6098709dc38f2c1a8eddeb5a9ff8f6db29854a0efcf2d26f36d7685b3fe031aba63353e640679e6be0d80000000000000000000000000000000006a1031a1bdab364ef70fbdfb51419d92916ee4ab0112e7c0990a940243ef7fa528494461d016f3f512a005bd33d4b8e000000000000000000000000000000000966b18f7ab411f9f2d4dad1fbf28f466c37f6ae2f3a47c7057b93faa5ecade56e9485f321405b52696f52faafaf66741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091c096c661c61b35216d02dbb1ccc4d639f7cef5f8f611f89ec85a82b4c5d053312b4c7049e3bab5d3a1f914410dfc30000000000000000000000000000000018483fdcc8bd85e12832dc4d1c39dfc5c404d5ff087cb55e89cace3986927c06d45f12376da0e5b2aa66a2b052e3fbac000000000000000000000000000000001597f7397f7fce61422c28a0874c77efaeadae214ab2c63894377de5f8ad56ec0fc22acfd1d8c356c4a614f189ce048200000000000000000000000000000000113921f6c2a0e55ee7bb6727e9d9c879295549b5d340fcf5b80ffaae04c9d9c4c15418cf9b78220906c023f1373d3af81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e550be0cff8389005ac05b1d618968aa3c1f0164141649d89c88cf329a4fa645c4d931474f4e43329cddbae25d8747000000000000000000000000000000000e2966975469fe5feea6bdeafc8a66cefead784a49f7c2a5a30da0542d5e9d482d161a7d2d6814c63bf53074d4bcc0460000000000000000000000000000000009c2ec3f0f37968a2d77b4e1610c5e4055bcc7d6891d82abf1e7d2e7a3412af8bd5e644a7dca6efeeff6707fd3f5d8060000000000000000000000000000000017e6f1048e2195fb1ada1532f41116757ddd5f362a1f586047cde15c646a0c045255cfdea17130924ad1223ce0e719931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ab6e2fe9c3d0712e019e992d88b61edf4b6672d4c2fc64e2bb8f686b8708605a139d6f501d9bb5a7dacd28e36aeac900000000000000000000000000000000165246c7d90359dc3f602d5472285ab448b57e9c7ec21bc573879ea4683eba828c5a3d1d42b51a0db562cb526a97169300000000000000000000000000000000131d7adaf84c2af6320904ee49ff7ea6a95c49a655702135b6f4366fbf40c572eaad85a0300c5d23b70f7dd3bd194edf000000000000000000000000000000000f62956db7f0dc593387b399d1a5df2ccbfe94e5faac5ffd2d675fd39f736b260e8807f62a3cf4c98bd03f04656281c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc9cdde86d1778a13d90e1f93bddfb2dfead644bc1960f165e4e8d183638b4f95fcd81bb1ef927961a4a73f0c5627fa00000000000000000000000000000000192829219b8649d8e3c4f8682130eb60b7600eca8ffb07534ef55ac99481eaeb94454d4cdf0eaacfe4e1cd5a7e41458c00000000000000000000000000000000192fcdb07a469717219f34eb84d04400b93c1480986dd89451ee2d40b2eb7eb8944c9dd1b75b2492b3af66f7fe6bef5100000000000000000000000000000000065eca88f2b62fbace2ad31e2fb6eff4900aa8abed8d52d8321eecaed1d03dde09d6c59a019d7ac5ee0e2fef4813c4021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000225162fa81cc1ac5374a949d80c8e647765912cff7cd540042c8cacac963ad3b4357014bf90c9b6575374fede6e267a000000000000000000000000000000000df20bfc6ea454e53ace1c34868e01c0032d4b8434e93aa485e73169dfcca9fcec793b80a1efcca41d71a9c86704fa960000000000000000000000000000000019fdceded049ca0c1062f44ed6dac70976de325046c5472aca8145f00dcf41bd9c574292ad492473cd65c252c58987f2000000000000000000000000000000001470e6df5643e4c30eeadf0bbf2e5013523edb083caf916ff04c5602e78a4cc8fc94f2e2ce478246b85d2347d1e7aa4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001292973848c3142cb601062860cb93df46bf2994901258cc5053616624efddf6d8b56add48d07a213f8e664d62b97f020000000000000000000000000000000011d7336404919b753f7172a0742d495123e03e26c7b561a3282937f63d48111ff59b085f60d0c70a014d91482bf546ee0000000000000000000000000000000017df9d3f3ed74139bc2635222d6fe82650e3dcbae9be1b77d0de8d750675c47566823233bf6051c05ef0359c47a13bf600000000000000000000000000000000092ee128f1843bb015296ae245e321d5a26105f20e1f915fc97ab92f65e440f086f2ccc134a6b523e1666790f6c724fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f98bf2a27ab6a1a8705b26767bd75792643fad01b2b4ba57c604d14f1dda13e8a8849360f3ce25c00f7e19b276f2f6d00000000000000000000000000000000042ddf099c17007004d8429164b7972e86c0034130d37b73d4a2930438a1a570c82817c9890f0f03b742c27abb009eea0000000000000000000000000000000001fb470cb125def3930438cf47465429fa81ee23919bd25dd0a815e9c03bc869d603de16b69a8f788e6fe9682a8f9f71000000000000000000000000000000000246b4d5404367ebda04a0538668937f59cfc33eaa40252d51d90de826b392591ef52773fb020cbf9d8d80d346a9e0a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ff5eeabcc968caba8758c5a16f7f99576d9b855eec26432a79b29fb9273842ee04890270c5d13632d9dfd0d01980b10000000000000000000000000000000008ff475df5cabdaf64e953da4ef5ee57f3d781ac235a8aa3f5635bb9538481cec6807b1def40f405400872f2d6bc2eca00000000000000000000000000000000043c5af3ea49a0346cccea47334a7f27db6a5452a21cca7f696bd19cf1458cf9bff0c6a28a21f9d202de761b715dce9d0000000000000000000000000000000001427e0fbc36df1b1e526c7e54d0453107640eb9b3ab95c05d007de80e245eff513b0f3fc65ebda885eb2e04f780f6551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073b3da9bfb751214df7b9c54479a027b62ad4c242ed74f46083a5afe748262a8584a8ecde7e754eee941bf4292181a300000000000000000000000000000000077dfbd5f9d053e578f21beee78927e35d23dbcd1ac61888c37d1a38b70b78055cdf5af382f031bb1f4ffedd43fc83aa000000000000000000000000000000000be94cb71d04b05436d9133883296c6b8786aee9aadc105704eeb39703e5b47eeb0f2310fd0a2fa951877178ae932408000000000000000000000000000000000b41486a755dd51239442ba8262317e26651577e227e12065943cc94a5abe9632dff58d9e35b5960cd24292a39bafe5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019752af76a6e4fed03c3a72d22237ffdf886637095366536436f679239f553703c7ee09ac4833560f931a0da512393be0000000000000000000000000000000016fd40c0ed3b939570ad108a1ea61410c515ebc640bbe2cf204a912210ee502ce933237c4d9ba200e8b10661f32c32f5000000000000000000000000000000000e8fc48dd82fc0b78285b18379d47f9d3a547be383da3eff27fe6ab5e00b843f00f72785836f90c7315d94cde90af6e9000000000000000000000000000000000dddcc29eb358a23540f57632cb784c846e84435f4afc8c300ce9f429d0fc6808fdcfb2c0ec8541692d737d1e9d4f0b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc5d1dfc3573bef2ca271287ee24a2914aa5e39d2f8d8d0f382803eca6092bf58cfe66ca5fb1489402b6efaae851bb20000000000000000000000000000000006e653307f7470467421b1299bcaa72f5c272cf599cae6f50ad4581bec5f78361f86617eec683c491585b83840011f8800000000000000000000000000000000186803c8071f6f80ff1dc07b7e5524678be2c82fb8eaef6139f23a67b323cdc309627099cfcc5a0b382121b02ce253e500000000000000000000000000000000012ab3d61bce2b2b6db63f9c50eb7b40b2a3418803e4018a6711fc8c7cd30f5c2c75fccc884267ea3a16a76b49c35b0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102a867e19c660666edfe20063f26a58fb2df919dedc80a2399333b52f3d6bbd88279917f851e5c119f9b25b6ba4497d0000000000000000000000000000000011caf4ced309a00ce8076a0220179a4babce3cebf396f8d7346271dd75eb7340ea0d9438463aec43a82c13279246afa700000000000000000000000000000000089dbb0e0787df6f2ea08d64cb5cdf9b83feecdc8704190a791eace58e65c0b4c736a6c7cdde5c2992b504a92d5e957400000000000000000000000000000000152c968c6dec3f13f22ffbd5145905a667bde90e6dcc07959bba3be9a1375faca94ca030c86af69767f3fce541b7d1e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010594f91e0c1640c3ebfa908b3296912f79da618504ff4a552ba377d7dc882d336906463b33442303d188f0ec3d09d3100000000000000000000000000000000147626ed992710b7471d03e9d73ffe17d7462b83d21058a88782fd13b1df83ba46534a047db6a5e161920c6168232bbd000000000000000000000000000000000ea2119c595b81c2cc2b1aaae0cf883b0ef7cd9452ed59369d8e61c20fd7d7c4faa6641bbad00d985cad2441976d7f66000000000000000000000000000000000c106eee2bb71a42b800d40eb28c9711aa227cdbbb7099869195320abafa564cd0d374aeb14f74c9926becd04073ab741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a042bc78a23407d5c42c84feb93663bd5ee833d61d9bf67602586c6e12abee2cc18202e7b13d11988d75bd09624c54600000000000000000000000000000000163e8a4eba3d3cdc2cb0a5575e21e7eeb4740219798d558c9965501e114828825850fb6cf4e8523f8dd90cd9a4266af20000000000000000000000000000000001a090a8383b76048a7f7cc4032d3ee5a13e2e06aeb51ebe96ec7148a0e6d362a64b22ef4935b76b4a72d14474b0a4340000000000000000000000000000000001a7d6a0f9245b39b8bc474cc6102b75f8e44e7870e8040e4cfcdb9244439f8ba478257d7b3cbb3dc47937168dce1d011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020558b0bde515d9f4688cd3d40f08e149866ef0d9ef72ab15c8be20f6e838135d510aeddf269a365a4c2cdd01b2f0110000000000000000000000000000000016901140ed918b7bb92934eec91233fded0053405849c7a752025d4324cda4c8380994bd96d0a71216a12f2b9cd91131000000000000000000000000000000000c4166f5636771c015bb5f960ae052f0bd30ed1947bd0883eaaf0601781041ce2623410f0e872564b486b38cc3189c3f0000000000000000000000000000000015aa95732fbab69a9a0a9eb70c68998aa3b582f0dc67664e25ada1d44c8eba3c073142c1121587407ecba648347eea151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015fd6defc299d868e4c5ecafd2e80564ee369602c47fdb5fc162fa11132dab3afcded49af1ffa4cef460535845c90fac0000000000000000000000000000000013af4acbc698129722f58de7e93c5428347fb3d96dad7b308b516ffa02507d6f8450bfec5dd9289ffd9ce891a1986f150000000000000000000000000000000003cc553bbe0184b73133187de0fda87ebfdd7c02ccef169d4fe1576d7bad8e0842ba3217f3b02f79c1c416e4c92154ee0000000000000000000000000000000011abf9ba02b519ab6997c8cb86fe4fdda0622300eb64e1e50171d072f6cee8b8cdeb7f8c0f0de500d1cb44f194d3de981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a212bf2fb60a6f59cd94d916bfb0f77156bad56d4801854e261bc4836317e2afde6ac44855ab1020807997aa18440c60000000000000000000000000000000005093f26bfbc1edda0f4ff1a4f3dc5a7aff530a2785a307addabfc665087a9c3fe2721bb25d97ec5f8aedfa9efb06a910000000000000000000000000000000006ee42ce79e6f194fb96b2c47af26be1bf41ff732b1dc2e743029431b0554c201b41c1246c2e6fbd893d8b375bbea05e000000000000000000000000000000000e7b08abf0706690c0cd56165edb7a17ead5afab9c3ce39e65a0f6042802e18cbeaa45ce3a1ac928f0a361f35d8476c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000431a27b284abfc6cacd5dc404563fc6d524adc5344128e4fb9410db17e8ec91c86e3b1f282f56ccce20decf86f1e06b0000000000000000000000000000000000193469a53aae61229d7c18bdf4b760ac307165d73c1d01ce845dda5e0a3f08b70acafae0798789ff46b535e3043dd60000000000000000000000000000000012b288599902a4744ffb6fe1c7a8b2d2bf445edd7f040becc2d66b9bdb4550d1ed31b18d1c2da0793c0602a82e454d2a000000000000000000000000000000000e731209a792276d07067d84168983502f28dd1fd1cd19d7c9d6069bee0c4331e082ce457b98303932e5ac66f3fe56691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035f24edcab3b860eba731dcaa5eb6d7a5b0ead22a9316d860e1ba7a71107da3e457c52d714bf62e167b2bfee67f542700000000000000000000000000000000121525f4c709fc48f0769324c281a37f03167fd8651cd720a6db56ff20f7daa39ac3aedec2566a69f74a3241ef7315f6000000000000000000000000000000000e1ec42dab5ef9e34118b7e7bd2a3e47b333c2b43208294b22c209636570a0f99df5b094df0b2e2fef3ae1af0de157d100000000000000000000000000000000076f51d368e155dcecf85015e7cbf61dce92a1f1eb384ae11bad76903964dca6dcf4eff24fbbc4e962cccfb0e711a2f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000807ef356d6e5c36fc52549cb70b6d87d3daf62904e07dddb8cd7d50e55f3e3584392cee98aa6f5f9cb466588dc0f86a00000000000000000000000000000000193453a9df6ce4173b68c8bf2751e3457bedbbd3e6938f3cdd8f2c9f9cc10ecde889f546c37f158cd039e9b66bf5963800000000000000000000000000000000026d4dfbf419de80a9fe1f366b1e590a037a4fa36d30e482547dcf10df2d394b03c6b469ac140c256834310253d062810000000000000000000000000000000008a19496fb44febb18f51254ea41af88640f34f06a26617d6cf9802299684690350a3a40af9adf25e3985eae95f364db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016d5e9786a845c8db93d1dca1af58e34d24e488068564ecf1dd8bea3dde857da7ec61d904ed4a24503d5c4e664d016d000000000000000000000000000000000827a9737aa644c9c1fb2b24dd4c9c1f350e022cf39c60501688f20c6503bb009bf46b153e1cb15025e3393aed1491f8000000000000000000000000000000000c7d723c336ecac4fe15f3307bf430a76ca5d4c389d9ea2009e895319bd3ee4f1c7d74b2fe9d977a3477a58e2c3b263f00000000000000000000000000000000158d4cc467d9a7de2f501c37ad6a99df0c7c7c66f9a08de30de5bdef78aa8b6a7b13ecb31def2d58ff1e59cd53229c551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf63588c89bf35346eaf8dc9cfdeb1a88e499ff22b53bb8717363fd4ef90bed17bb7bb45c300c4f52fcdaae4c11b361000000000000000000000000000000000f74d5de8335492237a2f666fc505e7998da9b9932a3145869f2770322a8c5402dd47b6b09e557fecefb69820b9b709000000000000000000000000000000000115eff20f7c87afafef41598bdc5b38f1585aef556eea7becb87f8fee0960f27c2f527d89722c011bd12f47762d0f52e00000000000000000000000000000000003e7e41acc2aec7f5911a57fe5ea80041587273d11d1540fc7f49aa777afbf4dc90d44971deddbb139ebb2862744cbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2be89d0029915ca37194ee8f6687d109e1b6ea43fff92ef09c4e0fed23d271fb20b0f211565b2896043f5d04ba1da100000000000000000000000000000000184442d2e9dfbff934937ded2bf5e31ca81d7dbe14eaaf77f808ab6288ecaa85baff333cb38accc1fd8cf3b780b7527b000000000000000000000000000000000fa6df31dc666228a444c54ab05a3a4aaea059dfb116ad16fe2ee36ee1676dc5a9a5c3f578337e4ae4405720737837540000000000000000000000000000000009bbc1da045a4f63bdcdb8884d260073de2fd461946d900419579c079887ecccfb394542b4a35684a66bed06144bbdaa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017360695c65cce74126ce0de693c99f96c5030889e737b36e5cbc83d25e23b861f7ba2d1804ffe8e3c46d7e4341d83e0000000000000000000000000000000002dbdc94348dba998b532f2e7f3c181ef59bd11c4d95212c81a2780f71db6f25d46c5ed5020e9f17bef240fb316d2f0e0000000000000000000000000000000008e97c3bccbfd87b2b6652d6c17c958de3343253eec415c83e11ae51b602d2480436ca5af4ea12ebf6c053cedc7ef53a000000000000000000000000000000000336934e0f4930b4e18cba0b381437e525da3cc86a83f85348126e4ea0398f00f523aff05e3b460206bb87a8936f06691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a51f80fca3d163b04444cc59789545bdd28ed3f940335ae35f72b697dce043f8cb3d321ca47ea89b0aa08f487efb260000000000000000000000000000000013125a60d6e35923df1dca921eae3e2bb7aaa507fbdc42fbb07956f77b262d921c27fc458a29ffb84cf97d344d0fc3fa00000000000000000000000000000000028c55767be963f97abdec60f903ba0d5cdbb61ce8d5a4fa888050aa37f6451cc548ce9f35acea443efb4eac919bf6c100000000000000000000000000000000006f949d5c3465ffd62181a3f824b230bc7b8e5a06aa70152b32031ae97ba211d007e16fe19953d0c3143fb16b9ac6321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f05e3b8bb4a91ab52d72e0aa085bb31723c1df4b61740d532e50e96e17a1a6fca49b47f290f9b44e693db998fcf66e40000000000000000000000000000000005c16c27754c4631e3ea8200f338df7fe8f53609b94bb1bea474df51b379ace9e37f558cafb4fbe09083744cb8dde10c000000000000000000000000000000001178e4d321ade6015f57daf59eef6608f89faba1ecbc1e1cdbfa2ca72df02ba3894d57243fc3b3f24d5b00e77adaaed20000000000000000000000000000000017e68bfc11b18df40ac2482387209545d4bb6d2dc75b12652516f01fc6e818c5c5fbdbf490172b9273c1fff7274fe43a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000cf7ea90f19b5c0688df62591816fbc43a9262e0eabae4c1bad98dca79772b65e967c594963267d2b3cddaea5578b6d00000000000000000000000000000000053142bac426b797be19429c9c1b75cfed8fdce3e6ffe0ef346fcd8b72bea5c7cc2cd7b0732d8263006a9b070b6141030000000000000000000000000000000017e51585634b3b8f4b9fca43ad903354eac44ec4c69fd7e38d583458f04fc50f66c36e39d6344a9190cfa860d74e8d1000000000000000000000000000000000180fa7820a301145f9c67b829b0312c9011e0df0eae7541f941159b50fd7745e2abcfa705e0de48132164c4d75f7ebaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018691d5f24ddc2c3e342992eb6f0cff29c42ab5985c7be372469995949dd010ab6c3819c77726189b4788bc9dd64f540000000000000000000000000000000002550a8e94233d6778f630962ff75aa68099b599e3a89dd620b3e572ec9fc334dc18235dec7ae67570de9167a814694500000000000000000000000000000000198fc1cb660126f81ac33a260c983b0cf6ca5c877b8c29d1ca1ef7d8c7eea976c21c6b06e0a2558ea12afa40ac1f787400000000000000000000000000000000067c38ca55a91c3d0c16f9ba792b9efa7d44553f79e35d9c0befab943b1c863e93ff3a7fe29c36a0b30c44c821f8a5da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c68af23703d87d31700cfc90f70df92100712167754288d0e047f7916ec12852b5e6b197000e96eb561d67844566490000000000000000000000000000000019fdbd3c18a77cb2521f9b958a39366a982c395c887e64957dd5a0964fc3b3c03f37ef724897fbb89a8a29b068dd485c00000000000000000000000000000000087291b9a2f977f53a3f7a9650a9cc97ead897acfc014056d36693999fa727880c10434b442a4aeddbf3497ad474a42b000000000000000000000000000000001785a50d655afb09982bb31e856f5940bbe1b817ce86dea441a0fecb4af9b8aadf27a999c23e34f296c063e2b82cbac11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d81cc6285e18d3600d87880b8b619bfd4bf80d794590b01137051264625cd6be49020bcfda2a39aacc55459de8eb63000000000000000000000000000000000fdfa381fe465d6a832d2a9fd94f4c1d6e4f335b52ef2ce12f242e43ff8eede7a3137899a8fe5ba332d06a668326db920000000000000000000000000000000000ed8429e0e1588d94cbb616c3831096d2da8837229b7c1cbd562e10aa2061ffdff6258a7109a8b3a35c4d5f434616af00000000000000000000000000000000135324129d218f8fa88502ffa3445212260e4766658abce6ef976a731a960d0d4f415735f18657e6152a16bf5531c1301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012502a89815395f8b23cd9d9a075cc59874ff6b884fbbbed3487fe2be27c0c103983e7b13f93698bf4282d94c00da22f000000000000000000000000000000001988e82d8e941de540c474e69dc014bd5bc1b609f3bd8c38dc77cab9f4f95c9486d3375a7fb0dff270403ae0f61c05080000000000000000000000000000000010934e07c97578ebae43c01fd7a30be4d2169e78003287dcb3947f83285d2825634d37faa98cf81841984cfa4f4becb8000000000000000000000000000000000306c0210de723014fa448151f2aa96a85433cb7ba3ced712356b13b3256b8037b58184d4b19c3f22b0226eafdd979031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159ef4308b9c089b96f202e27f078c8a10d54e5f025eb7b5e7db5e1b3fc9f05b7ea804a854e2e814b5a20ee15ff520e40000000000000000000000000000000012e9a4af4c4eefa94b3b9c7fbea5911c055c93468df46da67aff464fe8451cf171c50c096724f8ca4b26e2d0a72adfaf0000000000000000000000000000000015f39f05f518eeaa76d12ff47026106cb84247c21494bea3d4377f96d22599d0a2e36ef32fa7d46bec6226b75b1b24100000000000000000000000000000000013b5b9f7bd3a5e6dfaacbc76a9052a200af114369348f3b52e6baee6f9b57b89c7e97240b467aa71a33f43da6ee528ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016fb482a86b75849fd7c8e79546469748b42b667630fa40ca76f9768dcd72086c69f6130aeafd5aa7f474cd70e2f1dc600000000000000000000000000000000020641a3ae3355c13c35725f9084cd3e42a0c839fea4ade23760940f4223826f947da5f346f32178dc07425bb7e78748000000000000000000000000000000000c41edf2531e2ad31a76c74add2c9be2e8eb4beb12dd716a6377808d2ddedc193839a39152ae9202e737428b88db9069000000000000000000000000000000000b965e655a344a82b8cce3aa58c9de7a647ec3496231d217487cc91722fa7098cc3ef8b4b363b19487761f229f9041c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000107920ade33c19eb09a080300b189b6cafe69ca3ff83de9a954e7759898d76e221891e215b37d0c29b536a689b6a5afb0000000000000000000000000000000007a616a02a3a9688dfbbb0846b561a6997dcfddff303b3e1b8f0c2a2fc219ed8df4a390b8ccf42ad713ac056e0b45cab0000000000000000000000000000000009c37ba212c697085bc6190b8992a254d0258db7a2dfc762cd2fce1afa9bf272824272ecd0ff7f13e53beeffb95dc4d9000000000000000000000000000000001257c1434440891e6fccec82aa2f0e768205d5a09972391df032759b2fe1b55531b43497a0313b93c4a56ef5458cded71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e0410d8c0d8ed93d3c4dc7de5a145dd769688b1a7b46f16291d9cbda775129dda2fdcf24e55d06f71f3a6e63e5e6c9b0000000000000000000000000000000011cb62af720b1b01f400e8d58f6b9c5919f5e703dc8ac589be2bd07e2619b214a9be451d2af8a668dff0516b6915b3e0000000000000000000000000000000000218127e535f1cf99b651f24cc1e4f2676673872d6271f6cdbef9130243e89a6606cd1850b40e23cb5e85381d6e721410000000000000000000000000000000018323dc29b6a511c4f6314f40b8c1fa91e8ccc5d4f81fbcdb779b7e037dd720174494998936a5d78e8fbab73cc0feaea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ad82660767ec97aed57da0cc4f2b66c6d42bead4645ab36a29dc72c825aa9f2b3e234e4a2fd9d25a98cf1a1e63d6d4000000000000000000000000000000000e10bb82e15b3b3a6a1bfa521ca50af7c3f2ebbfd2068fed3764f3fde6f4bab50a87daaaf67426d5be4d2dc7cc7c5662000000000000000000000000000000000025c9bc9c10e9d39a328a7dd4cc6c3bcca2f6a850d7c6d51163041e95b6f2740cb9820267f27370b1f44dcbc6a1ee9a000000000000000000000000000000000ccdc248583c4bfea8d68aa455898b0727179fa389e14108df5bec476f287c355e2bd78e0d641c16578efbcdd2c29bff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c78c033b4bed84be35191bc56ac0b570e0339348625943b8867c0c2b45466eb315576119a58c6aac246e21d6f1974f0000000000000000000000000000000015329eb9703797782968359b382d490fe1278d4c2d28836a2e93c6aca67e770b095cfe61fa9f87c78e31862385f1f7ff0000000000000000000000000000000017c519d3aa05d7a59f3f36e2a096e4d5c175405a6e7db050d8cfb117e973b5e1f7a8b008a21f89decce295b30e5eba7f00000000000000000000000000000000015d2e44d46e0b3abb8636de0e57093f7fe238afd983f1c6587a16ad9a1686b71b1316c3a609d523a840db04d91301d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bdbd1cd3bc6cb80a20c7ccd2598d36568ba9ace898b03576f99f05f988f062ff2ae7c5a7824f415ab92a708679a126300000000000000000000000000000000027b72f8e9d039eb44c0d25828da054daa9acd9f6456e336c6e62afa035ce431bc5a6787934ce0ed0f04d7b06d811dfd00000000000000000000000000000000002f9d2573cfa2db40ca629863f744d112628f3618889eb9fa4f75399714d1b6221e6fddde39816cce997cbaf8155fb50000000000000000000000000000000008bb491bac92c0bedc61d62187df1c2f88cde3124c0e35b70c518c82d341931ebc8bd0f3069c6032b080f430aa546aca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187bf4089aea6fc1aeaa28980ec47bfe5d2fb277abc971585276d7df4ccd12a6b2bb713b48ce5c04a078a83ac915b605000000000000000000000000000000000c2f38943e918932faa0280f0c99f46377ce356c01199eef623f5acb4a3fb8daa7bb8f12db427294f85b2ba5c26893ab00000000000000000000000000000000118bd3bdd8cc20c2de66392872b11c82e26c42186ef3015c859f3a1525707d5498add4fb69c23056a55ac1575e3825330000000000000000000000000000000000ba480f726953f5d1e8dbd908c1eb9610d298a1406c88ac48e7c01575dde556919e8e7b158a7ec8c7ad8ce9fd7c10401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000135b88b5d588f46fcc6bf8418004496c9b9fadd30d4b31eddf6329977772004d617bdef80892213745da66492b4a77c2000000000000000000000000000000000ba32ec4f32b8a86cc8dd6f42bff7357d3201bdd26f42f45c8c2285c34b58e4cc2c094090966dd72ed4bda7f622a07fd000000000000000000000000000000000e19a55b28e1e4dc78977b88a8e42cb88f7a0b6b0527164961bb2b8c80be4b687df514336d5ea6bb63bb838ee4a83f3f000000000000000000000000000000000d46ac62cdec0c6831e784a2844d1933b98fbbb32dc026fdede8f934973cf573eff7e962611476b0dcbc3964e39befc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067d8678440842e1ed3d4a61805e65e2374d58064344ce1f15e57d1c9b582b81d4c4c1532bb0ca981c2615398ab80b6a0000000000000000000000000000000008b6152f76ed27ef27a6296d1247a0a14dc9303eb4d235e0391a03d98625e1972ccb4a41614308f73d82283c5fa5c7510000000000000000000000000000000018e6f93db5aa60b0bc4e3d1ba43314fc0f7480d888282656f0eea31cf53ee887e41e4d056b4b32e3cbe35aeadf5226350000000000000000000000000000000018c5dd8e6b76ef860f6b68e308f1dc898fb024d36ed795bfe66731758fad9aa36399a85709fc0ba8e3795a85681550a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c698dd3b64edf7de51d4deea49759f447a97eced9941482b5293d6d3e793cd6bb221bc598e31bc4933e7d1ca96904e900000000000000000000000000000000059da03769444de1f4e7a7fd1e622b2cd00b9ea06c70145a63fbe310c338b2fe060c228cb427a3e222faf57f8d4a36b8000000000000000000000000000000000061e9295cc3979d5b17a73102e3604665f151045fae25046ed408cfe30e7a05cde740adb5f66a329c4d7ac24e1d937d000000000000000000000000000000000b567647ee214863e5a0d9ca9ffec691fd9774b3f8cc0d683602a6e2f81f49c67d4b24b9c8cf00fea346900efd3c8dac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cf27ab35238ec70f40c9a57b13f64253a6fd2911394d77fee8084892a4bb9f68d3d05e219ef888faf56f2e8054ed500000000000000000000000000000000013da55c6d3e85bc4cfe183ce9ae6ef3938b25e699ce62fe464f49a770bc1b66c1d1508a150631ea09d0fe843f5aad7af000000000000000000000000000000000bb64d76dc1beacd3bacbbf915e51aad1be1119caa3ce79b86d47055f5148aaa3a2570ad1a34635107af1d5bb3c1e3b90000000000000000000000000000000010a27e79db2c8dbd48567b153a835fddcd441e61fec4e4969b3778251c93e1c700a2adb8d30ce05e22018ee4555acc5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f187fe6c1feb1cb91d55140d4f50c7ee9713180c3422c6cfa90c7a9943490998168dc1df5b43a10bc85c41481c3f99000000000000000000000000000000000c9c5e69db4011397da44b5533e6278322a3057a1f778c0cfc5b191ff854fb478df4982e3163e8b5c4cc905e1afdd647000000000000000000000000000000000337f13d6ab830850ca0d79b9bb93d3fb05d6a1ddd61f625d4510a8c44b60dba6139eb3c72404c58a5a8ab758f098a5500000000000000000000000000000000115e9c8f77e585d65a5aae1705df3d2c9a3bca1b719ee9bc7e7379e80d7a28a149a94ac4dd426e6b93d722ae6e74d5051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d33f79aa4dd9116aae5a1b2acef224e9a372893860f45d01fb23c3e81394e6c30bb254dd7cd6d5b682865a7fba92162000000000000000000000000000000001093f868172833ead9ef39c296b5a6049a3be93dad003201016e8fa750bb2c80f30bef185616c3f5f80dd78ec267adc4000000000000000000000000000000000be69e73f8b8af7c876d93488a4190bdf1901c02528ff289ee89967faa58cdedee464a22c905de6ef889a491a5680f0e0000000000000000000000000000000014ca3bf7884b857a43fde4825a2b0cbfc942b418a60edbac1d3a01bbb03e7b7b779252ddb408cb10b4a4fab9bec4278b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd5c024b48219670b9ed72759538924f701bc20099030690b74ad04ea020a41fb6c6f107c73987b5565ffaddd73bb7d0000000000000000000000000000000016551b21419dded301fb80819c85beaf463c9240ef9ebd08d10571cd5041c4393ac9c7894c3e4ae84d0bd7d7aacbf7e3000000000000000000000000000000000c5c703df9a581632e2b4addeb69f8103b1952ab741f5a9e4fb574c1d2a97606e453355e55420735663aac6fad22f3bf00000000000000000000000000000000066087eee4912553cd200d0f3f6f59cdbc658879ae794bb3c5d9a8ba74be1d216fe2ba6f75f6afa510977a608a04236a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077a72e5e85764ab92ce17db7f9ada64d95a4a4f6341fd6191b4f901dc489b4fe955de2fb2bb55da479ad9cb57cc48a400000000000000000000000000000000026505ec2b1ba0e2e497e9e6f1d8792d7cfca3948158b22e6e7664e8f9675851883490e166b5c22f7e132af5d311cb04000000000000000000000000000000001438bfb20e3489fe2e2dc40e5e24d846740bb7947349ae13c7b593875b8e8046cf9a6bcaa2e51941d6530eca211edce10000000000000000000000000000000000954a59b97486fae92211927183babefdea29542158b94ed5f44bea4b0a7fe221c627d1f8d1d3e8aa5623ebb39644761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a641d93e11ee8884de7cb432c61d1c810f7243f3854d36eab9368b579dc305d6360c1f16a71a79088e692f5d5993070000000000000000000000000000000000f54663ae6a97bfd2ea830ab6bbf2223fb11dc7baa55323aeecdec6e52ead211c9eca69d4d34687698556f0c7b7bcd70000000000000000000000000000000018312e5f79ce033f2b6219403ef4a01bf1287864df81cc575acba3571b1281dca7e2348917c5a9aa0be9cb2cc946c4e100000000000000000000000000000000143515bce7314ab8799e2f122ff6c2c495d9a5d570c7972da04b9d2ce19731836f8caead3a1981e4e6b2097d3e0678831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076d32e9cd6145afab1201cfc345eb6e4f55b52c5d8af871683821d0d2e87042117c28b0185059c5d1cf51fd39c43e8e000000000000000000000000000000000367cc21ae344c80f2b529ce27d18fc5c1797c2fc0d68b5c10ba90c6b6c435cb75e7007e33ce1cf416671f1b4126180c000000000000000000000000000000000871375e0cdb52f2eee0b8329f9ac0a44b85f9a8954e8e0420faad9c132a93f6c0801996a8c5ae24f4c3042e3adfeaba00000000000000000000000000000000016c60b2494afffcb1b423c9611230988aff7cca174f7de08d369a564e05ece4a508cf839408a4cbd580f7f20a1e8c5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000374e858c211b479b593dfc63f62adb33def8655f5e3c1b90cb41b62a4055dc9a20f1f534b295e7028273e2c5e9bdfe7000000000000000000000000000000000b371a79f241721c39031bd242ed3732ee07fb1d5ca2bbc754922c016fa63e6543ec0fa7474dfae1bba79fdf1bceea37000000000000000000000000000000000859f389be87eb0d345a5c1385840f9c09d073855fa1550d4fc1aefb6d0545c465ae19fbd8fa313ff0ea6ac30af903700000000000000000000000000000000018e90d560b734ad1e7c949bee7a3875be5cc108c23df9eff40b09259755174048b90209b05278ce17812548ce437c4721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1a42cd7dd56b30e6dcaeab4d521984833fab20059316391a3da58f2a95a71301bb171dda31b9914d36f4970fc90532000000000000000000000000000000000fa25bdf0705b3e3f7f52424f82c54938ebcfa6a6b20454c8ce6db013d05e586c07ff2effce4775553455f50c36437e30000000000000000000000000000000000384f4b5fe0f8dd1f73370298b4958ba0644dafd9694489782c37d3c98a660d03de1113143997b31e15a2667afb612500000000000000000000000000000000162bde8982b7e47561d2d3fd9fee1afef17bf4d46bc329f4346dcbb8dde1e8eec148381abfe39355a3753d6b8aa0c47c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee574dc3ea71cfe44572d913f5df8474bd45fad041da70d5fa8cad8467c6714567618c6f0c3984e081eb106586d2d31000000000000000000000000000000000a1942dea806be3f2d51c8243a8e5534d1358d42fee32cc463ddca9e93d718aa302e29c07d8bc0620ef0d73080cbb3a9000000000000000000000000000000000959b050e5f7215270e7aab888d79ecb704464bf04920234d09af579ba5d805b51ce344fe76c1772551cd116c6bd8b50000000000000000000000000000000000d074dcd6db84d9cb79de6303dd87c7c36cf5649ce7b7c4716f6558733f47be0d450fd8f18d76159c1a16d139abeeb281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000300df5b9d1540b5d3f814f58aa3965323916cab7529f011991b56a20bdec2275a6901112fdc81e39b33c61842448eec000000000000000000000000000000000fd9ecb90022390f196e3d93d3f032c1009c179a00c2a8fcc4e7687c3f975c6b122db61976330ed645e0bb8b276cee180000000000000000000000000000000015ff3f48ce1db7b0cf57a1a497b64104dd5f7bac4f0d48dc344799e6442715c11998d302eb10a89ce948de64956f19a0000000000000000000000000000000001244f202f01ee5f0655d538854e11ad78bbe6ad23cb2564cd87f210b40e1df8a00d69717fa522526236aecb4282fcc6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016bacfc3f203a97b0a19e2c2ec28c4785beb54ddd0b62b6b6cee09030caaf9422b29461b54d038d790a993ca1520819000000000000000000000000000000001888da8178569a652c12413060a9248ee34616e020dc99ff8e960939dcdedecad91643324cca50f10fa530cba697b16e000000000000000000000000000000000c2cf85bbdd6bc0d79502810860eb9b75ebefc81e9933190dce85cc30ddec103ab7da08d633f2a7dff259ce3085dd8bd0000000000000000000000000000000016165312885fd6e9e75abb567bbbfc51b3fdf03fcfbe56317f5a1b1bd27797ba165528cf4cbebee73ce42bb24971116d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000681c0ce8c01703b2615e003c08e3c3345ccd0cc540c79081d6190743fcfbc2a7ec57c996e7c8f3cc8b4ead0f52fcd1c0000000000000000000000000000000008bc643417bf77e835411bfd3491070994c1ecc818c4c91d375b2c3acf35c641cc35b98734f5f396ae842daf25730ef700000000000000000000000000000000184dc9bd6176f9f46f2f4e30963134672c68ef7bb9ab700fd3ca1e5e527eba87aa4cea14c5369478f87d631ba002923d000000000000000000000000000000000894c681c5f1cafc8747c50d0e7948299c9cdc86ae6a06dfa95485be11e8a88af9d17d11ced0faccd0f076a38895372d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f264fccf147b10cac6b2ed684b4f450a4e3434ff955952559f885c3ed936dc63e234f5a0466e5581a74042b520c8ec0000000000000000000000000000000003c7be8aa562a8444ed9111dfcb748088763b7c9b2beae9081a2a2de537123f2c54a4d78b762d35840d63583bc8e153a0000000000000000000000000000000010a6db4c53813ce311119760f35e4e99de88f03c49cea3ebe24c7ad82ac30cd9c31eacd7a89e600b8eb800ff4ec8ffe6000000000000000000000000000000001835815b866e55387b4ee11087fce9cb1818b8126d76b8ff4708d57deddfecd53745ea329c8022c04e698caf4a79ea421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004872105d33ef42dcda9c13373882d8cfbaeff7d152467d542c4289e4575dcde512d4fb4439f9308722bf9c9ef80ca0300000000000000000000000000000000035be1afbd8dab3ce5fbd5e193596990afdc9a2fcf229e3f5986b9e43934e7c7a189ed7745029463e11060561d0f554c0000000000000000000000000000000005bcb6629ff60cb2f2764a1246b7ac6678f66134170c681114d8977321c09a037452ce33c0a212d8bec73cb13aea272a0000000000000000000000000000000003a393349ae82b0c03b605cb7732d0c46122b6c91e84458a15faa17d988067e4618d4a27533cf23fbdd458a994d8710b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005af5ec6c2d823736e7be7d6826d67bdc603d13d2b03074d09760ddeae1a4c59e297aee84dbe2e1792665c193785c038000000000000000000000000000000001041a26288ddb6e13ac17cfc35fcb1bfeb934c48c802b5183b51b2604172bb5586a8cadbffd90f5704b2ba248a2dd0f000000000000000000000000000000000120bc86e2b282ac9f5d2b765ccdee0c7b732c7cac453785b7e2605682408c2fd3716f9a046e41de56bcb5ec9432e443d000000000000000000000000000000000b074d02f0e23793922f4e7af27c483311179484a6c4beb5ef3e359ad49708f60a3317a78ed00ceae623e91b0ee9b7a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cf2cd1795caca3f7aa0fca4b54ad4b0d323707b2aa768776baedd18abeee239888b04dbb46a17b9d71aa2ca938f4d80000000000000000000000000000000001b099610cd80b5b0b354b86c92fc57925a88a79475eda2c4becbcc4c871d6f4e50f4d251f54cbea357ed9abfaf0c6ee0000000000000000000000000000000016bdf9d0b7a3c1cf98a92e24e9b40f4fba2312460beb2bc2f70d6f078953194bacabc8c55f04eb8127c56fea3a08609f00000000000000000000000000000000055ae8bac25485be86bc891661fbf4393894465bc5d422dfdb46bc56ec51db2ed83d96a4c8d5a3c1cd003aa59db70cdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad7b0ccb4ce07100ff7371d7bd1ad42d22a8db5f085f335ee7f05a9e23625df0ff058b65af39f9defebee5b1d82abf500000000000000000000000000000000106a963a06874faca6a5ff379f0ef6fb51eb6240329dc5536ec6a9b5eafeb45dfe238c379b69c84d23c62ac43afbd9d800000000000000000000000000000000069c42d8a62662682ec991dc6cfdbc1e9fdee55a4a9bfb90788927758aee3e6693ec49ac7f5aed93162b1487a639725d000000000000000000000000000000001801f5cba7bb4b0aba9168b8526fed7a97bf1dd3ecbc51167dd894835226bbf35bf039da3ffe77cb68eccab4c70dd0f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f290e373105740129ceb0040e0385f74875d9f2d87257ffdd8ff3925ed8768fbf31d361a9dc7acc4b2eb937b30b6d0000000000000000000000000000000000fdbf6af8b698a71ba5c9f79cfa2bfd4eeb901f76c42c0ad6d4bd2624439fd83ba28fa2e463c5f681bc9ac76687894b3000000000000000000000000000000000571b85a217753b2e6b90587cb2ef1a33e3446ec14eae7195d892cc2113aa7f0aaacc80b5a35da87ea027fe35ace5a83000000000000000000000000000000000ca3d90b67300e8a1f661dbfd8fe77265655a9bd6484a08ca75e9bb95d577db3f0d5bcfb080729e8423c3e7fbc4f9bf71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d18ea6c7b11be8e0af5aea5e9485e830c6011b82da82db1baf5f245bfcda85236d7b415d23312117853c85b16ff046000000000000000000000000000000001450a498d2f9f040ae4117e82df848f745870d42e9e05cdf8b9ca679c892ca8e8f8bd2ffcac959b1a216602149f50677000000000000000000000000000000000197839384739d425e2ec61536e04c70141ef315d68f9fe621775e60014a6eebf0c16226b13996c62016d313e7ed7513000000000000000000000000000000001727eb823dfa81ae9ace88d8f5c6fc6dbb4b079d7a2dffb500e7549239ea13bfadac590646180897527d2d09459329ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006604f456d2950879f3c2d2c8e0e91617d6fdaf7048c2f86d66c2fdc86c6623387070c6270757f5ed6ae2cc14c15ac5b000000000000000000000000000000000b715b310f7e2553feea1125144778fcddbe86f471bf868aa93ce7b2eb7e1e3fcf2d0aa7569b66d95dcadf9c98977d00000000000000000000000000000000000cdc16b6fb1a4d5d3ef696356da958139d219fc561bc2e5bbafb799696a7da9f2da55bf6aab22b856599f64bd74368c2000000000000000000000000000000000402dd55e9764dae5eb3dbc1943abe11de7b49e949dc96ac1409575c75ac1c4f1ace45db823771644d020b8b57cbf7451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055a7c1e2d6e222d0eaddad2977e0db74424ebdd93e30bc737821c00e45deb32d87452618bfa3bf43195eeeb6237686a0000000000000000000000000000000017e71cd105bcce40d3e141ce768fd38dd57e8bab7b22d33f55716f9f33eb002ea659440f894682f6441eb62b41512e6e000000000000000000000000000000000ca1a9c2ec02ddb3c79d8f5813188dbb77d76e32eb40df0a1e25136719decf1c9c996c1515eb1826c8ce24a052cc50710000000000000000000000000000000018f60aec758f64ca2ed60ce09ce62a9e52f2364bf394787127e0771183f549eba5d3ce2f7d1bb4b3840f6730e6f397cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7dab1d47b57d2a32cc682adaec1f832733faaa8ba0af94ff5aec9b4c64e4fb34fbb8206a53b4eda0c31cee7a8d64220000000000000000000000000000000004cfdcef8c0432f68f747ae3182440eee5d9cc512bcc56a1598d0da66b4acb9bb07178521043c2591c9459cc146fb44f000000000000000000000000000000000756397ae20adf42ed477d8e7914c7285e7e7099b5d97b7499b3fa9eae20e73877ca25903b17d56cbc82ce6b323110680000000000000000000000000000000015c148594133d7cacc6512d325fd91a5d4b88a39f6224aa639f81b6586f164bee9883273bd07aa41bab4f7f2d739dfa51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8dabfd710d786f53e10aafcb67f03ef29b39f969dc8e6d8d7d48decc72d19f3222da6329124f8c6c40bb61637d01980000000000000000000000000000000004091fd0f1e7be058d0a41c7c6f67f5b7307715e6e8670961a2df9505426a34f47ee4e292154927ad11c9dc14e4cf7e20000000000000000000000000000000002f1f99a7c554fce8963573327e9124ee677a26c1a18dc68ac3e259edcc00db46ef1b8ba91aaa9c983036fa4500af3c0000000000000000000000000000000000e765368fefac0a6505f7d35c6fc71b06b39a8209b3b9e42bf929d6418cf576315cba3b3c42e26315928f39419609bf71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f69cf347464c649dcc1c20507884688b7074bfbb1bcd049cf6bf686bade6b08fd0f1fc68e3c1cf1276eff28c2e6049b0000000000000000000000000000000000bd637fa3ca62fe693130899d96b0d1301e1ed968670499921517830dce791f81e1254ff245ac154e5c9b5227172899000000000000000000000000000000000b4703d1e7d7c4a3d9b2eacd668b8cfb1211cb80caed764dc541767ead7c99cf86b2e335317fb450ed0399886098ae66000000000000000000000000000000000e7adbb14450d2ce1c871be9d275879270227e6991abb6861f10964a7cabab127d4194c9998779d5a39a7cdaf64e29881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000940c8336680f64976adda4a129e32edbe205bd2a5b22ce67cbb2e4a3957aac932baf58b7b154af0edd0dda6860dd3c5000000000000000000000000000000000870b5417683657707a81e28bdf3566ae425f96d040f59cc5ba7b329464ec799d0138048d7ea15ffeb6a38c2fffa83d6000000000000000000000000000000001282c29a647ff6c0da2b6cb4cadba81aadc519f2d40a2b284eb73a4d553ff85a0874f20e12a30988a574c3fadbc8c570000000000000000000000000000000000c1deab1774321229b54d236660d7acb156a1d6bdfa2eff01095db76e2203809244f11bda9a51e1c05b60bc8333bb9261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030e176ce74b18a030abd398c5c7f4afb23c70540e0c97fe37ecf425724cabaf51f4e933a9a0f9c71a755efa291ebce3000000000000000000000000000000000b1cd0dfea1ea74350e0bf37e4dd894361e60f7db9159abfcafa905908f0e194a9f3127141c20d7cd74b2b1e8f9c527c000000000000000000000000000000000a8918a45b1bd109ee715ad059a1700327100c622ade353ca093965d0f383a5c53c1ac52a1d9c2cf2fd3f8123ecd826a0000000000000000000000000000000012752ac0b3f9f08353356eaf524226b9595263789cac18d2c4abecf7004e6cdfbe0306e787cbdb7906df1b119eccb35b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116b81bef4211fbcf210eb74b9ad6a488a587565c80607989826ae30fc5900e9005534b650effdea7fb9e6ba287022f5000000000000000000000000000000000fba5f5c2a9460f5257389bc7e13d1c3aedb3bc060a0ab66f7771f40f5bd708c8c1d212ea7f641fb7edf6894ee5918a2000000000000000000000000000000000904cc70c98f52d08a4c5d375a83ce52a02e4d7f3e9bc17318a35fd80c73a6bba4939e1f88a1bc53a3057e6017d3d60e000000000000000000000000000000000bb534ccde98988422445227319124d8c879e3bfb69eba324ec465a6051a0c4e5d691ed16fbcb3e074936c6c9c5aa0b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001bb258439adb464a31a5699ece630f6e82bb0fc8e8428bb65411f0017fe2f42cc2a9ef2b69919d16bde00c661bf1fb70000000000000000000000000000000009bdf623b962fc724b0f25445114f2ba305ceca10755c2e47761d8a15b382aec53e217abf0188f4f6fa025f884d27cda00000000000000000000000000000000143613a42d42318104df1e89968fb55b13869ef40677390e615d1d46b469fc03ad48ce444bbe261bfdea3dbce2eb60b600000000000000000000000000000000127ff9ec0492e240b8ef58de89ae240f5ed77d99efb896b3b68e7d7a86caf70dcdd66a44ac6ce3baae6c63aef564c5071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e10455177e8a37a3cb0704fda8ca376d4f15e56aefcd596b9b06f4085ff2c13816aed1b23746422b07a76414643eab0000000000000000000000000000000015324494db23007989cee1357989c1b38241d126366090df57f1b4ed4be38d687b38a9c4b449d29d31b33cf403ba81090000000000000000000000000000000018b804c8362cd9cd92d64aa19f0532eed011c5ef19fcecd6d2c8eade77dd24ba87901a0a3afb79ec19b1a34b59000d1a0000000000000000000000000000000003df787365366eac38bdab6f64756166eb7d26e06087d3d9c94b084038385d39dda4edf67c9b28be029e4cd9869ab34d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083ed6f5fa455608e172661824e7ebeffaa2fb95e051139d6a0d81cabcb3f1224ff7937fd1ad936173604d7b375588c100000000000000000000000000000000186ec401a2543fa8c2cd754451d4fb7f0d10116929ead484f6033343f75de2756e89c6dcd0efcb41f3832b2bd4678b1d000000000000000000000000000000000a6f2a54455681646ebf030a368e8641bbf9b5ed21dfb741b0beb96b2035f039922d80b214655135c689081e2b5f7599000000000000000000000000000000001762007452670844790e28272ea610d943d13ea60a19f0aa0b472e4fa3f9e996bb1fa4cb874e3b42464b1ce9a3944b1c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "00000000000000000000000000000000014d638dc4afe028be7e3089b7e6c10a456b999d1969e042f065dd1b71658937f5f1a428362139e2fbc65b153897217a000000000000000000000000000000001593404f32e08c40ea6d6f9181742dfb8b0bbe9a6dfc884c955428ba0cc6c252b336a7ebc75857b0eeea96920be44089000000000000000000000000000000001618e6f1c93bbcd2d0c58e615251a7efcfc066c6ccaa881dc81cead71e00e3f3e8b42e65122f93b1ead9df6ae342f5f70000000000000000000000000000000002d1ad7b474fd4df5f41ee64a45813dd76ca997dda8fff0deae486eef6670446d1578cae07a8aa92ad9427af7c126efe", + "Name": "g2msm-256-jwasinger", + "Gas": 2004480, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000052871b5ba2c2f23baa335931812cc7c400a707d7674b38fb8b03f6ddbe2ebc165bfedb907180b27dfc924a1441a42c0000000000000000000000000000000000a6ee537b0790f94905537f08cee4fd9d4655ef8cad394d41ef72dbb3cc1b8f54b09fc2cfdb6cd45fdbb59c255ff387d000000000000000000000000000000000a20ea7b3622100144b35031cc9a209c0bb77f2f6963445dfb5b576498a7728c8abfeff156d74d501d2475f62aab806d000000000000000000000000000000000cab63e41999719df09e92290dbdf7e0528760d446a9e4a57512578d33738449343ba1e8559801a9ae914bdaa71119731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c479f4cab473402b2754300b1a4abccd5ee23a4cf93c6f477055332abd6b711d4cf574e68ce471ff64467d00d1b020000000000000000000000000000000000f38e7258c28d592fb77645e7a86ce4d1be3492bee45d150dde2fad3fb726c89662d5cf265512fa7c834fe057b33f2060000000000000000000000000000000000bec3fa8a2281238f2477710775e79c6e81ed44efe5c5c9464653c6e05cc9c553ea105aee04c70043fff8bc99388e5200000000000000000000000000000000083b2b8855bc25c16e2480ef4b6c2832beefe8aa7f967bc560d25042e3f5ca6ec1ba8ce64104a20a8e53ce51fa54ebe91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159bdd1f735123ee7bb77a99d185a3ea65c77a37902b0c893c0ae8d6f5a8d71661115951c2a86c65013c311db7813b0d000000000000000000000000000000000bcc7766060572c440b8c6954224d3053325e1b9b1bfa771116ad60781e900fd3d77492ac08de0641ce1c7648c341ca900000000000000000000000000000000125827384b72387f50ba2cfefbf7d2cbd0d569b98a9aa74deab5236a037c4ac1d64a22c9131bfa1cbec1e5910306d5a000000000000000000000000000000000134b17dae92e50bd24f1d035a071adab470232a5fed90a2bbc6b6b215589eac045716b1b4b353e4ecc9d843a7f37c9ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045504927bd2921120d367665d789d9ca3bda8055506898e85065c8a31c09a5915021991e1bc05a2074f5e058cf9374200000000000000000000000000000000182f5af7da6987529f3603d1236c39a474d7952ce373dc6eb7f169cfa2a3b27505312a72c9b67ec0aff603c258aad6ec0000000000000000000000000000000013c53650e142466ed115a4b09d58621a631f869de013da0dc46149fe917197faa6b715601df6684306e2354dcd4b4700000000000000000000000000000000000030eb07e18eebfe7573fe2ed5af27f30c26d745805a8b5a6c661d9b167c353f2724a8e927a1a62524f6a241c42f62941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000283385874d144e6b9cc94b6f68de7e7bf5726e6abd1eff86310f7603c2e8428553dd87d0e3547acb2808de059036ceb0000000000000000000000000000000019e81a5675d56ce2167cda8dc7b10770ad7c5320a0e0ede8bc686b6df971e628f3f24fb37b9b3219e1000e7a7af74a1e000000000000000000000000000000000153d7ea8b437a08b6d6f94e384dae16ef0658e34fd883fdb77cf095f8187551031648090e4ab81973a138be0ac393aa000000000000000000000000000000000ee3e64357327e32109804a5d9cd16b140d8edfbf08ec38a49ea4cecd1ab245904ea4ca79ee71be0d67183104d2389061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d48e73309c1bd5690f67b9450fb474d48d7fd564cae67d4f3aa865c8c43457a932963c6ed824a0983b7f5a94ea678280000000000000000000000000000000016b42b77ac21dae1c5a09e445243070fac959cc30d625cbf72fd1251b6da33d907e642a411f57fc8840a6bca0a9641490000000000000000000000000000000006eaea88444b7430a168951e5261df18bf7aee2729b54dd5b1580ce27a4690aa459ffa676512678198a38717ef64db1c0000000000000000000000000000000019bd1938539eaa4fd6f4914793cab607982a75a3edb672cba99e45515c0e629136f29a378d960130c483abb81ff3c76d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000261308d64484701aa59a28e286f26bbb62057e06cd5ad4090c7f7238e00b292f9cd52520c989b768ddc31d2a5fee63400000000000000000000000000000000160cdca8787289470723963383690b20aa2c9263bfdc474b809c008667fc32c9c9a7ba2fba30fc7fe3d0bb9400959f40000000000000000000000000000000000e52f34db06ee6a19351fe14ce1cd2e74d45ccbcbe82b3d19c60065c8f80ef20d9ff64c38e52c52bb4816136598103aa0000000000000000000000000000000018f07a5f44255955860991622112051b21c49ae38a679903e96207c681fc813d36e587adcc2fe9c6e3b1a10c190c9e521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017018b2f86ecff208be4b1ce895a379edb2904df68c92c5d66485728b4c81c5bf7c551c73a0cd38f708ce5638fe8d633000000000000000000000000000000000f7d7abc65d5b6293aad06ecf49e69dc5ae19726044cde1ce9a386e982aece1a0190a8a94b7b53203f92d94eb50cd142000000000000000000000000000000000c0a38ef3bbacdbdbd251ebe8c8aa24a3cdfe820dd9ba951895609e35becd703f96f2405a5f666f3007c50ba2a3390a10000000000000000000000000000000015086203a9d471344ce7393273a2dda2df786172b786f8b76b5e4cd77b0431cea5258e4c1da1fd5165372b2226b803f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003cf8c388634f5932e3fb3b83c4e2f211fa00108559fcdbeb847e04dff68993828cdabedd2e489c6139dd5f6e053474400000000000000000000000000000000056aa9ddcb13f9c58f448d11d0112b661ba189be679a10cf68554e263ccbf79dce4aca8ecf542a6636702326a1d3d3f50000000000000000000000000000000016a4f0dd3e42ced74aa6f26e57cf09ee8e8f948260d92a21f8d4112efac83acd9052f5ecb19fb1a8914d61dfacd917d7000000000000000000000000000000001682bd8df2af2f2a2cf570a91c57bd8200116404bfba98f43c8fd0dca19c238309e4380da49bf8649ff53a43f295f5471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a482318198aa984d6e89c5840c3ca0e5f7d35f7e53c0001e1edc8fe9482d73f170ba79dee147793e228ced0258efb30000000000000000000000000000000015a4ec001143961b29423af3ed71abe72249f3bb7f3950b21d61cb0594366c8deadc0f9ebc57f32a197fa85ecebbae9200000000000000000000000000000000133e9511866cc253be65603789882c4abff1bea8ac2ef9ea4000625dc40fe11fb0259abf2ad448f5bb6209a793ba7e89000000000000000000000000000000000c583b48aff376e01aba68e58baddbd834bdda13a68b29f55dfcc0e321fa4e136ce222869434dde95b6f8e890dfaa7711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a1a078166adec647e3ab6204b28008365e2bfb8d308921b22eab86810db0005169c1bc80674649b3c82c71371f262f0000000000000000000000000000000008a04282d81ef3b5e438a0d9d0965efa92dda03abe9e8e2cfd76e7f1e6ec598c26aff96c12e271feb61c41f1fbe832a30000000000000000000000000000000015232b871b58a6748a8980e3dd6a21b35ef9387157643415cd5870dd0509a9e5d56d83eb86174407269cd6da69e922e0000000000000000000000000000000000a1f8ae179b5073d4395fabc0e64f1e03735c24f0a8bffb37966c949982e6495bf4816e5ceaac89ff7b09494b51dd9c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a28efb0d782f6a55341be11f305633c4f7467859b7bdef48046cbddbe1b927dc96ba88b9fef900b1e4102efdd35c1e7000000000000000000000000000000000775d5e9a86c7f620555672318085d3af9c2d00449904a4bd45c56a3c831f6389f30e84b212ec56b4a191a6335949b3e000000000000000000000000000000000d949485f8be75e90d5e4ce4d1689f052d0b59f3acafb6dbaf6584a7fb65eb85cb37751dee0a2158991c78572b0ac285000000000000000000000000000000000d4558031672332824cd59bed291dab6411edf7d108e085b69ef93228012344513f968c9bf47dfb3de6fcb8aaf55aea41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ebc1d47370b8689c475b703bf10fd48035618dfeeb6e707af3b7e010a646bebf10fbd8d46e432ded47be7373aab14e000000000000000000000000000000000864c45727beb709e81786f848a80042434e90c3fa54f3e882df740e3d3bd21743c2d30e694765bacc283a7d372c3c4b0000000000000000000000000000000017c81df6f19e945a94e180f11308792d615c6a4931c23cbeea8b0079ae63e18c77219bc8fdcc7e0a14127b1bf9daa994000000000000000000000000000000000faed0ccee4cba59ff6180824c45c010c19e5e1239f48a69976c8e80dec91f3b17493561a5c89c8273164635a593ce321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000067b59c35dcd09d697b7b9d7427f6dc2a45ef79371e4ef8bd6bf1f660fe13e293e9349d14a3c6ce83d78011f0c3c7690000000000000000000000000000000005ce370ed332cb3aee56d32d7012fcf0f1f68c6f73447a55be9caeb26145b4712bcc1c1f8dda6692021018cbecebacc6000000000000000000000000000000000e5035fd1d8798553c5ab23b61e3c66bd4662f7d7b50aef44094994163d0a6696679b7c58fb14ec412697b9c29915c2c0000000000000000000000000000000007924dff85364965c207b191dab946951142fac7a9f7bdb4ac2958f7ff0956ab9f03f32d8f8fe0860aa29401156315bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012bf142c242098d99f6f04dc5701e1f61b005bff70d33d4e7a569f0e3ca86655f219a1e557022abf5782b54e552d1552000000000000000000000000000000000b97b596875e5166c9a5b53a990281095fbe95e130635330f2d7750feb01a0694b49b66ecfb798c3a4c87b976e5f3b85000000000000000000000000000000000bd0181ab31f8b707ac8bc9421a9db3e7b7897b5eb494e3974fd146d41fd552dc5ddf0ec9952653072fb778f4b853deb00000000000000000000000000000000152537502998b7ea9d7707fb9d96d5c41e5e801049fec075383b59945c032b52581b186f3bfd5cc869b06e9cf1ca062c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b71d2fcdbcb0614d34c009fd3f0b87fe92b2c30ad05bdd85ac322742cf9ec3ea61c7eb6eba6fdc97ac7a045e21b4ba60000000000000000000000000000000004de114840cbaab5bbc630a8666fcebb3fd751965348538eaea15db32095c4a96c04b7064d3747a60f41af5071db38ec00000000000000000000000000000000107baec1e9df7ed94d49fca487edb18148df356654c7ac5fbfb66fe6944792fb5c5a6b919c2471cf56bf4f97634980ca00000000000000000000000000000000052606d51306ef085659da365be47d9a1ba3e02fc26295a87fe5fdac15727d9d7cd924decd0bd1673d725acc0797ffb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5fc61472ea7cb8de64be1ff5b3e52d7c20a31705b1d2b56d8bdaaf2466da4f3cecb6f7b8686a14a5d516b93aa031960000000000000000000000000000000018aa652edce2f8fff59b5786cf209cf93b1d2fdda78c1a109e87b3797a3cc1ce393a637e90dc0217afef449381c6bf12000000000000000000000000000000000bb4a1d4a6452df0ee24f8f2dd017be15582b6f81882837d94925c5f6fbca4a73a97d3b02d329107139c78fe74909ec800000000000000000000000000000000154b3442cde404083d5cec21292006beb14905aa841f042e1bae2ab33be9c341c7b950632226ed5f2f86a932837ab85a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000194532d2b9054c0ff2968f75e7f8ce94fd368628f28f8ca8e0d80cc252030aebdf931e03a82f1871db50531adb32074d00000000000000000000000000000000096858709792a32e47fce14b1910548eca780a96cf92d36585cde7646a26a23ee898824c63b994a5e3586c3d727e7dac0000000000000000000000000000000015e1871332b60af53706058454ac4d2452c4e075d6759c15bd9584c7491ab06df2d45c2552f99173c35dfa173629e2a500000000000000000000000000000000086fc2e317b0c1441256bfdbdf633b08b05d95ad99dcd3a25a9eed51d4f251d5b6eeec0185238b8b872ad3c822ef68301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dce295e9fbb91b1f0888f9bf97028f7bb1a47a47803817be27635145ad6cf1df3b44c64db6661617fa1c91eaeb0549f000000000000000000000000000000000f42365014da8f144407e0e5cbb04703a88441d101fb0e32a23967ee95db5cdda0aa32f03247e44399b2828e874b574a0000000000000000000000000000000005e96546c1086cb355ed9af196ca7cd62b5dbade7039b39e6ceb5bc22522ecba9888707e4a63ff08a24aa13bc5c035eb000000000000000000000000000000000153316d66eab7a14b1d08379e3f614a3b4463b78b44cc20e217c90784b2e3ea2d2b0d4fd023ecce34e3a905d66349361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001271d33938dd1759c6452d947099ac1f91c9da921e48cd76bae17da25ef418899741ec47f6d19832d84c3a579fd2dd4a00000000000000000000000000000000188fd6819263b6f500ac8b92f1cdfe92c2c781290b8b22660010e5a7a3160bc1c69c8bf31884bbb413cb8afc44ec0e5f0000000000000000000000000000000007194effbc9a6c3eac8b7b91b88d3bf8bce25f005b927a6ed4b959c472ca57bf7d88f4a8374add5483ca62c7aba5ed720000000000000000000000000000000008dbbe0ed3b96f0ac9c6b5f376f28d514f8e9895740c28e2de00065a4bd147343faf8756fa00d05ffd9a5e50731833751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c9a1238c8909331dabb8a83aa122a818be5ad93461fb08715006002cd04a2499272bbedad21fd6e4cacfcbebca1886000000000000000000000000000000001080ad0e12616f197775f0e8fabd3828e130d283b77f4342b265c459ae35209d15dc09101ea18959624aafa0a6c3c862000000000000000000000000000000000d1ddeda081a119dcef81a4d8740c72ec7bfc9662e0bbf21d27ad68a0fb1eff768b97ad3b482f9115d565b5bb33476df0000000000000000000000000000000006c0ae82584e1f4e530bcc400444a73c3e2f4abad8f282614e769524698ca798d8b4fd104cdf23bc9a8c2b6f7847aa071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bd232992af9c9116d6f1c91f05e672366728f8876ef15948d0ee413a198ba0d9e993713298d025618b322f89873c370000000000000000000000000000000004d51f2d438fde7f261d2335bcab5d2d66eeb19e9c4e7ae3e296a59e656131ba71478e7907c9a641d6f05e653a4a8713000000000000000000000000000000000b16c3ac2b14b6915de4baa4665ad1969c025a788ec4914c15081e737276df1fe6079771075a627cbe18f6241cec87b400000000000000000000000000000000102048acff5366c3316ba0f7101f11e455756da3fa8e6d5294e542986fb67be759cd4c410b1d1bc9c9be778e4819c1c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e067fa40b492a2441284394453b01597714a2f8e269d73e75bf577061a7e383ec69f188e34913645cf791bed526005c00000000000000000000000000000000118b77ef250fbe1d54b2c0124cd5da0196f83322e8cc5eea37ee657aedb44f7055b49177c695dc24d956b99abce8e3d300000000000000000000000000000000194b536d940236b8d0b62fd501badacbcc6a030c0e69936d391ead9d42c7fc198453ea944213ed1493387e8f857e6c42000000000000000000000000000000001864c1133b4c09f719d608afdfd5ed5fa3fe9eba835395b41a1c76831db45c753877e3ed22062dda0c5951410459f1731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f8ddb1edca337f12d275a08f2f82328a3d0884c95222df797a74e3116ad2a58008bf0bcafb951345e91588a89e9f9c0000000000000000000000000000000011e320aed1fe1432aaa829bdf9e35fad456530793ab68502c5f7944a586a3b8deb3559e730f60165ae4ede62fb2f6e14000000000000000000000000000000000b47c612b1bee3152fcf5280b81ba34d570295ba67108b984fe50d54227f2cfdeba8ef9198e57b174121016c5b71d1f30000000000000000000000000000000019e49448544c55c99c736e60339715a6096e0283ecc5e300ca11e81a8f584067984c4f904de56e1f047c7c0fd90c36be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019f6185820fc36dd07c975cf05fb2352257f14723c7e74abd00d1396c56b3206bdde2efab326f06ea36d9c50496719f0000000000000000000000000000000003f25d42845cb51fa000facc1b8d41ac60bf2bec4ab963c0dddbcf3219bbca76a0ad3d3abd2d8686693b4251973a72b100000000000000000000000000000000110b34eedc5669f8d4c07a1c6cb61f5a91d25be39306cb99400156e936664a58fa40a22b1f30d702040c1acd14302358000000000000000000000000000000000bcc657119c54de95011e55d1a3de24605001c938be87af72faa65494f5e77afba27df183496c1c1b9bd8db58537705b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bc3e3c92528405273313f9789d652beb260126740d2c4641de89fa33cb0863927bc9ddae75d346c1397c7b1ef41904000000000000000000000000000000000c302090d420f500b66c4b5515bfbc90a11d2ad637b115e51fce2807b04869078aef954c520a109a395d6ec42504d66a0000000000000000000000000000000002d7158497762a5a0fc790d9c04acea583675ede5c7e532bcdabac6676c1439e5755b9c194a3a09924e81cfa04ccf3c1000000000000000000000000000000001491bc1c3732f503f2aa0931f91a61ef67d0e1e83d9451fb0f44e41535b8254ccdf7480e565c52cafdd5ba509966f2a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021ae11a089d19ffc0822ee89e0d4ee6ec4742a5bae62fae0b350ea698515e83f82f460d6f57e741d4e4091725b360250000000000000000000000000000000013c879ee5192084a89b7785e1f9c7f5fec30fcd850940a54202556f9c11cc7075e719e6a0abc22955af7a91de439087900000000000000000000000000000000098e4ba133e12906a347af023f60a1735cf0c3b696c9cf0fb587f1afe7d8ed3ec98a7d29511caa4bb988257e9c76b35b00000000000000000000000000000000135e7650ba3f08a32476a8554c9f9fef33928a54e25f765ad77bec1a3899114232cd796bfbb1b6c234e6ce78109d698c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116daf89b2b04f02f5a5d208ce339a2b9ba2f71c94b5c92a39a316821835bff50df867ae9cb274318b6f08185e81adf9000000000000000000000000000000001179182cc96a5a333f24480d6172d9940a2ea115420b12bdf71319f45a91e2caaecee5de7094f853810c46778ff88f7b000000000000000000000000000000000425136a2218ed28393b87847458037dd5df34b3be356ffb615b67a9293a17a0ee3cdd76682e833b4525432e0c995e32000000000000000000000000000000001101122b7fa5b38b1eba5f10660c4d24bb8d074cdd8351cbf2d1ecaae31464034c2802e3e35a47035a684d5fbc8bb29e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c46307b5dcb53fb17070bfb5e7a4098142d5e43927db5685e2a68d123e46491fd831d6187d1d0d5e762322ff0afe510000000000000000000000000000000019edc903165b7ef0683a2f1ec4354fc0a2e943bc99baa1b2e1e39f65dede5d22475cd109c04ca2bd278b19adf97c59ce000000000000000000000000000000000fd15280bc9d74e3fda0637f2e145982bbb12bbb8c9141f9cd1a878656dd02d93d467d7014a5c164e40e10bea721c9eb0000000000000000000000000000000012f174e7815db551a91c954879e9d03e0fe9bd818e3e29433968dd00eb498854b7c8dcf20fadfb920981f39d988b7d861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001513b9e950811ac4b3c9aff93fbc2e3435c22244057803f08f0084ea0231953c15ca504f8e359c9efaff8d7a2131eb170000000000000000000000000000000013541c11b878dbb6e45a43b4697032567e55434d7129b5e580b74751c26b4df6726d5a14526177fa0477ceb9e3122246000000000000000000000000000000001051fb83caa28fba8cc3ca1a68a04e03a9399793c59c04dc274057b56515eda2446005e6a70cf447b6b0b8b526dfdf0100000000000000000000000000000000182512afa385310852aadcc5d206ed53e721698b2016ee51edd664d7a64b3e4ff6264821f801183222a72770a095ea1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080016371bcc6718563fd706babd77d630733379f75d58c71ca416f095a16be1246856056a89a5437c841221d14b9dc10000000000000000000000000000000008ef7e000727c7fbbdd2500c76d8b7af5d55c01cdb6d374a632834638d84c47702350aab9190b72e6457db48770e100d0000000000000000000000000000000008d656e9214f56abb1f80ad880e4bef024c1e8623f10333d6bd4e401ade2e8f31aa1135f9431f0e11475d08a0f147af900000000000000000000000000000000004ff1c2c69b27174767ee98e5ae81933aad68c2ff13b0ab9030883243fbd313f9de69de67a89fe8f91a34ed30385f6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016806597ba79852c4eaced0e10463111aa3be5cddb413171688d023ad07b4c4e30708387e1af8a5409aae423a12087c000000000000000000000000000000000143ceee08cdad076340d2f9ab8a9a229dd2d8db2b6b4ac9663902c87f6b9ba3fc8e52bd4087b7df92ccf61d5d59da0c80000000000000000000000000000000002a8e9d5e20404bb416b9d3c3f37545f7374f7136114799e942767448ee3b4b2e35c8e18359a6c01d11ac382803894ca0000000000000000000000000000000003f4373155d2dc66faf10522d437e73fc3983ee916d9d06c5063846f8133ad5c04323f3fb2ab26ce88b1ae15e5c53ecb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019aabf1fa38ba197b0295f00472fb7bcf4247c800d37adab9c174e69b3c5fda5e37300a56a49ab9a8f84967c51530bb8000000000000000000000000000000001497693bd1c85926f6ac7c9d598cfa9b8c1612a6fbea72ee928722d7834c886e6c05fa14c2301e03d0614efbf0eccf380000000000000000000000000000000002aa49ea07cbc663c6910ddc49a5c15d7432194b67ce1958f91cf362146763b7eb00e2712fa91d4a42013136c004ad7f0000000000000000000000000000000006a971fd1e4ae54d487c52de6d2636c05d02c6591694eea7ecf569e3a37bed0c003f3d85cde5bdcc4451e14002d0bb521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d22cc2d0772fd39d9797680e2ab3de4e9b9ca25079d16480b03ed41cea666ba8c23ec701c9cd8abb297a1dfaddef1100000000000000000000000000000000157acb8b4c371f16835f6f61841087d2c9ba58993d2a8ee13ea84edbcea4c9f0d670e2502c4e08b54751ebd846a52d090000000000000000000000000000000008fe6680d7e2e7e211a0fea79ec62cc290ede1d8a7011e19339784db155cb0601e596b45e0050ad81a136713b4b84ee00000000000000000000000000000000017bc88a3dd41d13d6d92e05a6d0753bdde8c4421cc6d87a20a9a00fe8356d8b47be94d2df11330ff4231cf600234070c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f4f02d3243c54be9e02998a690521c4d6a8566e438755a38e0559ecaf988056a7ce6a9e52b029b2e1d81a122637cc00000000000000000000000000000000013c22a66db668e64626b8e864df8071ee5766692b390f533a6268a9ab8f4815488738919ae75d0b73e893460147374c300000000000000000000000000000000169e805461e065314a2d3fba31a305c8bc0291fea3ff05427faf05447af9d1c2725cadcd9f3fbbc9142561c62392ccfb000000000000000000000000000000000ebe3a54234cf4bca0384d73e9b30551ca0e1a35e41572ef7175bd765610573ac5745a2f01805f21473eeb665e143e181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f637826b6dd5383fd29cd95fb1eb54fd798a41c82e99ea41d87736d580fa00557184c1a8382259eecd4997ae62f8700000000000000000000000000000000016f9e2a84a0600e9b059762cecd4d2abd7e0c2b5cae782f6c7a194fab6ae8d4fa121ec2c84f7a66fc7fd0165cae1d841000000000000000000000000000000001412fa940b347f60aa7df350ea8a97c0c652ec2ebf6c459b8f370ca170aa0247a04b2e3b8ce2e9ee96c14ae6ce3ff605000000000000000000000000000000000e18fcf75dad2ddf3bd29db5b16f106a4f0ec46a478615acd6e26d8c5a62ad1700203a785f4a996a473575c5be88d8d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075aac8cda9ebcff86cc717da83e4e2a000680e9978188bd56b468b0a9048bc0787b42c457b2459d18828744f4bef4df0000000000000000000000000000000014dbfed78ee4b8c85ffc44e8096a130738cdcc241cce36a1c10b5942208a7a08fabe890201acc0610f1e267c4aaf4364000000000000000000000000000000000f704c3f081b8ac59df7b78e31350132dbbb2c3017234d489cdddcc370a463bba1533b799d4730cb2d7ebd06400e3e6f0000000000000000000000000000000005de7f7f83267349944f0e87da4c27cc0328484e24355a14f84b4e1de2a48fbbe7bf40d93084401a75d10b477bcb919f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011475989ea243e90d4b896d502862947aa04743f3f910eac8b8b0941951130c55325db8b9f443503f9209070c0bbfea0000000000000000000000000000000000f029768a2f1c1163c493fa77d8568e302e41954db9080b773133ce6b0e8ff0b8cd38a7f88a972656638f854e4012ce20000000000000000000000000000000001c1f0ca237e3103c16d7d0f893079f5c66ccad94484ed53233e7c892c3a0b1674e2e405b8dc5630206456e0ab8cf4bb00000000000000000000000000000000155f724688c35f61e598023efdc8f410ba223a2cbd3150c14fe1429a672df50ab66c54b4033063b3ab39721522d791b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003308b9fd5b8ed798470cb183ae6d40e10fb020b3381bf747d9ef62c2dad08aee9169f410faea7fd4018f3cc09164540000000000000000000000000000000000f7c4f05e489d249ac723eaec7e75ec85152f9df38e963de89b574a6cd49600a8362f4c100af745a4c4d884d9e64443300000000000000000000000000000000149604491248f289c581ecea262f000cb60d893474dbc9c778a77426797762786eccbbdede16474881924a2ccdfc132b0000000000000000000000000000000018ba607f1613fb968e38190808e5604cbfd4146dd208d5a6e15daaf15f37801e36f0a96e924787f0bea8ad6ef7269f701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004d74420a393cba3c540376d78849be97c3520b52f0971a42a571e8ba0872c04a66785ac1e353190265360a442e20920000000000000000000000000000000012add2c21a97d832ffff82fb252593ad6c850594a5c3baa2c4c195fb2421535afd278f69f3b78896babd254fe5656d400000000000000000000000000000000002679f842475c6465e9bc2bc527bded4019f8be092879bd3b6d52f25599b0a166972947f0e5cd5048371128c3d18f76400000000000000000000000000000000166b11888ca58880c7d9104ead2f0c87dfd6973226056d796f9229e6c0353064019aa0c7f1cb289aa12f942131c6d99d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b2f4a146da613da4a32b837db76ba1db12defb10b4fc9a55a3da3e758e2d0c2712f393ef8930bfdc723dff4a0d508c000000000000000000000000000000000ec3b21f1cc682926a2e7826168045f68a605fd7b88b572eb75f5a712dbb367829f2b0d6f294ea9d42c9f610f803966c000000000000000000000000000000000f81d1df9305c0dfd891dfd158f0b95f6e841aa54f4c20dee110214ce7f07918e540391d76633abb574e49aa573c99e60000000000000000000000000000000019101c3d01e7d498e407976ae80e04f87ed7679ee7142161c5f35bb18e0f670d4f40489f1b78a7f66d98afea0ebeaf971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a1215dcdc1e3e0410f6acca62f31e60c528bbf66e42c4e995886f8d49f174ec66c4e64ca0bf3e272524e43fe184999000000000000000000000000000000000b6b0b2d0ece956fc3ddf0db430e39b20b8b5c6dca60923f1cd816817ed3b360e74bcf1115372317763299ba1566988f000000000000000000000000000000000b8af9b73a44674153096210edaed8d4aef5f8b7d30d183b9a9fcef63b1c327936e63aa09b0e8820fc1ba7d262baa77e00000000000000000000000000000000154fc4cba0f1b53da2927cb01accb60f2b45d8981f293f21c3953b424db8e4c8f4017690e544421a151e1f17267e86491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e9c1cf901fae4ee0ad856cc340f74f420c92d71ad76c1fc52108a2611fb4ef223a5f7a9be2b61b22e3063845c7bb65000000000000000000000000000000001907c3b981cf8a782e2904e4ff1a8f9875ca37a1350769dbfe1a692a35d24b93b13c04d8a1ac272eacfe0d4e446e8cc700000000000000000000000000000000080cd85d1e5cdb02fdbb8cc099102779c37e93d8432ec0c2637cfd1e8135b074b01ff63dcecd694334d7d182c65fc777000000000000000000000000000000000787b19c39cb5ee1dcd8f9cbc4535a689377168f3604284c2854bdaeb3ea7ecb5c17a264d78655fc479bdc25beb62b2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bf9885d825e010509147e72af4c784398c43c8493667ce6811d68d284b6cc2052dd9435b0b7644d8b7505ccde4cde50000000000000000000000000000000017d708e3e1509ab7dc64d1aaf485b17f8b851764dab33098bf986eae3c4c352b72758e4c75fae75c04c794ca68124ab20000000000000000000000000000000003081d02c97fed3af86ae14ec2feef7729714dd29387cb783745d3df6b36d3b60580707c2216ab8b0f890ab0f70495a00000000000000000000000000000000007b2ba4a3dad0dc77e7a9f8b6da7fae907e677f40529828af0711cebcfaff075b9db7433badeed00c5eb6a4650a9c2721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc32fa0801df7f97aefc9a0d43979f5126825220e990c972c48744df7efa8125a4410c6cd6dc44dcace7dc1ad120d890000000000000000000000000000000013300235bbb90bf30531361080d54381e5e8ea68cd530333a487fc96d81764f944c6b3bb6f6e02cdfdaa746564a5b04b0000000000000000000000000000000006c8ed0dfe282ed175208edd2c45cf2118718dd8564b2dd8ca77aa47e225234d302656e2ba50e8594cc92075416545f50000000000000000000000000000000017f74fc1bccbbf3d813cd90f91d750c27027a3f6fe09459d4422cef0e8b25b3fd99a644786861448a25a987971afbdb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195e461e3c7a58204dee46add8a41aef184e4e117e927f115a89aa9223110648229406220bc98f6674b13d86431eb72c000000000000000000000000000000000631721e19fcc66f7fa82e73359ab9231550bcc20a6958b9567e6943de5d744387eafbc8d298c0bf6c1fa3a43b0b1dd60000000000000000000000000000000013004653d9e98ccdbb88b8f56c32575d4cf227707f8dd595d6636d5fb92069ead4f1350cf0f4d51564aa7cf4d4117d6500000000000000000000000000000000153f8e7d62c09fea778aa23ad3485ec99ee604fefc5980dab2e2cf18e42992c56642544cd75136e56b089ca3357e1afc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003423fc99785ad4f2eff7360f6b3229bfa9c6deb3581fcbeef82e6b8aa109986e1891b1078c574dfd9ccc9632fa3268b0000000000000000000000000000000012495f9411896638c70261604df91b5f6f3689b9877d809897f84a3c9f1cd60be2409e37645d529ceb4a041fd5a4dbde000000000000000000000000000000000856a4fb80601f8ce0abb3679104e16d19ee6eeb15003050ace496d54260f298698d402b1a513e687f15822ff929d62c000000000000000000000000000000000c03948fd94be7f0954c9e4fdd1e8e133fdd114b625e06f115b1d8b42f17452609899cae392ad5f8c868c12096cdcf7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001113b93ab9a7d6aa75e26cf836807dc4d761b8114f2d3dc0a4f3e343bc1d5e420a4dbecf8b7267da857b52985b4f7aac0000000000000000000000000000000011afe31c565162a0e89e3e13567953e6468c0d62d3a30c584899b81c883ad0a0a9897668292a005a7135a21628fa07b0000000000000000000000000000000000a996e1b5a5cb52c23f682a38855972d312499e65e35aa3efb7a62c8edbadd869572ed273247423f53dcbdcb3e20c5fa000000000000000000000000000000000d88b734e6816916e0a48ccff25cb31503c0af7e2a28c8935867fb53f4f6a3aa135552c22ad254be869a80c3ee6362eb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9fc3be3fba07f15295d5e48d4345d2e6000771f69aa082a231ec25ec602320a64f6491b19f973a8bdd030b4ab4c5040000000000000000000000000000000002fcf026bdafdae38274ec666889be0a0cb4c9fcc9acb477f3d7408e61a901145cfa1d27472fafb18bd78f9f2e20005c000000000000000000000000000000001570ca33d7e4118ab9b6481a8a9fd78bb567dbc1666ccb4afab5b4ddae50daa134b00cc71be7f6cf11bfcf3defcdf1ce0000000000000000000000000000000011fc0588bd80b7e54d18247c439be386f61ed6c9f5d63863e0f334c5fb97cd0e8f1f77dfe7bb3eafa36bb928ed1ae0ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033cdfb5d0d03470fb5844ad125de8ef4f0f626d9739078de01f74cb785c024a0a55fc54f70d362cf401616dfc7c23ad0000000000000000000000000000000004e66c04fe2e3357c222f0f8f09ea24e9957a29154bfb2fab2a5866d090f82a933ecf1538ab8b2f9b32d8bb191331c360000000000000000000000000000000005abefd27e32b06c2f502f29b9da74211589b58a3cb38cbd7781faeb22ef48ffab0307a54efae1335fda12509a50daac0000000000000000000000000000000010bbd7901850676d43d444bf19396e9dc015518ac71891382685be941a5c6008c39298f84c81d679fcac5eee75a712391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b1a08be282a7d227b9194b8ad60aac51aab78241033c5e70623690aecd71441a6d5e841dcf709b399aaddded0abae6000000000000000000000000000000000911196b60cb518f555fe60c80e8d21426f32b195cd0d5d933ee7a8be8f11460accb69a06f749fc56de495335bf6216200000000000000000000000000000000087eab91b23a6a3207db7e933856ce88842fe47fe63b52ef7cee10056d056b9a187af012cd0b5ffbd39002627d40203c000000000000000000000000000000000c1067c54e9004d7e9e82d3182813bf6a41e0417f584417530844ffdfa924f4a280d009b056d24879b8a0ca561c182701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085028cf5d9983702910f40ef0a354d5b984c82cfbe814e48e39e726dd18a6269ae4a6f2a96617d8340d094fabce85770000000000000000000000000000000005a5fc500e302151c35e0a000dcd5a402dfaa601d74bb37a095aea95d1e09596b317cd406a40364b7a2db95c2ad4554700000000000000000000000000000000017a12f89c6d86ee41352eb7bcaf82caac5d1051727dedd6fdc801d2f4c83ccbf2e9ce5a4f408c96690bcec496ea5ece00000000000000000000000000000000189c93c80612fdca38cf00174c3c322de96b53577b75461fa3882375f29bb1e7bac53747bd96b120e0ba167dc0b102691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191e972dd4db4b25ce7ea746e90258db2308f7bcb2b267beebf1115dd1ea284982f1ae95f6c17af2b4ac556260cde7ba00000000000000000000000000000000021468418a523c2109c93de442d99608206503267c2e9f3b36d1f1913c892af48db5048c764adb2a342398e1e1cce7ea000000000000000000000000000000000391fb11d58ca5c2a706364db484a462a5506277465117a33cae8cc76716cb4be9604fb2e61b9350fd4773145be9695200000000000000000000000000000000047061e9503407173569feb9486faf945e6fb1a9cfadc4b630d3c6629c89816e589c7655b589ae9cf4bd0c61a0ba92f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000158855085dda5a4d28fb6d2e94f3afc6b6383f85cc5c5aad70a70370a60a0b8eef477c77175947f3dfdcffab0373d8850000000000000000000000000000000016f62b6a1a67579bc67fa228f1af2a2b1fc7bb2be63a90967b3671f06ed7fe6eb53a41567d887c363e28c03b6aa52d390000000000000000000000000000000016387a95a3757beeea17f6ad94d23531a30d79dc0a30b945308b0740bfc09f238f8d19349143d18570bbdaac3fe691f50000000000000000000000000000000004fd9ce59f494631a1590758b4001de8259cbc123c6254be7e6feb9f199f86e33acb983472776e9691008f63f26bd1b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005b9a8019ab6159ec14003771cde97a15ea91b0c86ae7f42804ba920d657a8c2260c53b91c59534f55a9c07885cf9d2a000000000000000000000000000000000fe2dd75e32eb7a130c0cb484f2f158dbdffbbdad245af089a65971ada34fab0a9a8aa924d1622655e2e7747372e080d0000000000000000000000000000000018d6fbf330ecb5de268ed7e4775e7977f13f229eb21200370d08cd0678186716856c562d48ce6ed51f1661c93cbfab1a0000000000000000000000000000000006ced36d057992df92e3cd78876f2719eeee1bbd27bb7dfd8229556be82280ade8d1e0155cbfe8144638bb892ad608531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000032a50bcf20bd4220e02a110bf29e059cf35f22ad5583b3e80f92f58162c7fbcb5eac97e7411611b66d90a7766668b750000000000000000000000000000000013fd121e2a6206b3a533305643a9a3c204a2f51a4368cd226fc8cda760770723bf153436a9b261bb9cb908655d6cf4de0000000000000000000000000000000019afd0c671403eb0bba36a4b12099e981af5dd18df80e54f6294e5d052f4a838c94eb11eb80b4ba96897ce1845e90d070000000000000000000000000000000008ec5b712553a7a254c93ae869ea8897ec6aa6fdec32c5e119bc6a0dc8e273fb3a9b35cb8c45eeaf15eb14e00454e3be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbbc0639df7ae17b3684ef5e1799d28cec6398294cf2c99abd6d8e207d8f164c3b0e9639de51dc0e60b85efd824943400000000000000000000000000000000086f459ba06e2e90620e3950653dd448f270c3d499af4d9e0bea18512a0c8f7924de5f1adeb9199decdb5e050791933c0000000000000000000000000000000000a8321e522ae78fc865e12de855d43cfd1bd93e492d5ca4b3c7eb72efde855bdfee249ec8e9694b9124c05362f7aa1a00000000000000000000000000000000179ccc5e9a2dfe6598d6887054c8a08f5900a33804cee26468aafde44d8b5ee538bbd7cfb38aa019927950174036ca3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133ee532d074b053049ee14ba6ab530ed28ed4ffb540ece4f7d1fbebf7a447d986035e1beb7cbe00d8614ad1e0498ced000000000000000000000000000000000630ea8c472e38564eb180c82842ca1605b3129dd9a8cd4b67c1a438fd9aeb74e40bb03f083bdc8adeb84094a21108c5000000000000000000000000000000000c281f5a33236606cfa25f222fe9c37336bf9afd06dac8bc7095e66d15d9f5c9277876ecd0c22413442402fc23937186000000000000000000000000000000000e3cf86b0c56029987736111796ecb12f827c3617bfb505802d17dd9c333816c61362b1709817db4d4892702409272541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc34a62f7380ae1f6078c2be739059397107b0d8e7cf84a065bfa37af13acb5aef2ac854c55c5dd8735ec8617a829500000000000000000000000000000000006fc70e8649364dcb50d505417cbaa81f1e851a2fac8124edb9ba8583ae930bc89829c730cd70f6bb5e54ccb1a7ba9410000000000000000000000000000000009c38bd474646318944b3d6a67ab1b8f4ff28b69297f5bb29f0f366840eb2b39f907617ba43d32204b4a1e8c1d4327e800000000000000000000000000000000000761b0d7b3b6feda82f6391e26f311e85c0f889dd779b8ef39a6a81e24ce7168d3efb0abbd5cb0cf7dd695ea3312c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039e8f44793dd2d51def595508c06016e85602bf124a2c4840bda18c07c1100cb6a4d54532612c8ea28cce9b7e943dce00000000000000000000000000000000003e58d3c4cb61b94c2a4ef89267aa7d8d1b04b2c931f835b04af955229511f9ee18d489353ce25f8803f9ac2dca35fb0000000000000000000000000000000002a019517fb42629d881cc7da5da0795d184701ea2e7b1da1edaf381a3c09be10309824bc6639afbb55145fa3edd0a68000000000000000000000000000000000e5d715d19764daffaacfd70bb91846eda01eba04ca880ff11797a02922db9493ab3957421668599292ea1bf5a7042b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e71755cad448836c83ba58684c5f439d919ffb76b198ad7f998933983505ce3cdc89251bf1ddffa5f24416524d8a310000000000000000000000000000000012453c0e387f3bb0b6e8e5030d1cb2d57323cfb44ccf4158ae9ac03f30846fae20c656b42e6f7f1914dc5ff53a29c69d00000000000000000000000000000000132c2fc27d55025e748964c3e736effae151ac258d6d8b4b48ff149b5926793c9792a16412d3f01b75d297061bce3f530000000000000000000000000000000001db47f50d5a44e2c1c316936b1dee0beef75ced351a0514038b1dcc442cd72e381a40f4702dccccb89457a02dc675a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000055ed694419eb1602959de5215c3314c12b768b8335d4d28c657ce96a27df566653a8a86279f3f75c70969f831082361000000000000000000000000000000000e3cdb690db4bd2b726b80451fc1c6dda7be4b6d441652a46995b3c408123c047b9f69be72e17ecb54d31ab5676ec6030000000000000000000000000000000002c1e18947162d1dee8efea07464819bf22de853951c896bfedc0894bdfa7e5cf432bbe14b8f52c5fc60c15132c851140000000000000000000000000000000016e171cd3db118a187d554ae05d5a18c7c89ef22ed5406b7e6c4d943e2b3ce8998e378b22986b4246c5ec5dc9c3ff3d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e8aa91e2635f006bf780f41e25b6d63f8d142f9028abe0823c892d20816e2a2f1f6030404e7685058ba1e048b5f0d700000000000000000000000000000000085092039a355adaf8961a8c69cbc97d0ebabcc315c96a66106e7b1ee34a7635308e507206e1d1ab858838047082c1e100000000000000000000000000000000147a71ecb74be2f395d8892fd32391887cc003aac7c5b8c1c5d1b338beda8bb8c4e8d3e996597956804b1dfef173342c000000000000000000000000000000000623e15a03d69a04c425a559fa7ece093ecd63fdfc85eca5ca2bfef3cfba72965e7c9d51a8b9e062c0ecf74c613ae0551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b9138af4a2e03dcf085fd96df5188f57deccd8a3b3e460b12d88848ff1d6a25517ffcb3e3b1d02fb6b2d20face9eb2000000000000000000000000000000000a83a2a2ec639e847d64a9ee3544623d7ac4cc69bba6796fa78799f43a787d697bc97add5a4dbef03547d99734cc26440000000000000000000000000000000010db66edb6b34eb0b0420fa2e2f3091737dff9f05d8055a0e13d0fe521b59c424dc5c49298e6b7b4bc6b76bdfdf8d5a1000000000000000000000000000000000cb065b2143a358b98b015bea98fce319162869a30dc3b52ebc83707fae8bcbd8a7b50d29f755c8b4281637bee0268991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca8bd0008c098fab2824b81ff4c1453583f30f94b0aa7ae778079b05a686eee0b96dd9b29caec6a68efbf0d94bec9c50000000000000000000000000000000017115a31b406c8fbd918b50c41148303fa9698d164a81f4bdd5ee7be6ca0c795dfc81738da07a64a9b0c03a2d7b3056e0000000000000000000000000000000002f255bf76896b857941230ec3aa40b90cadb4f25f540e2a2bec5fb8113f4507c9adc5b7c334b3b69ace9421bff911c60000000000000000000000000000000003663d1df92e8d9ef07daaaf50bda0066780a606fdcf0dd347331904eb0161c9ef97e9a1cabf120a8ef4bf03de9659541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a89e28ff57cc16f5f94b5923120ee4f9c9ef20f92a3ba2e0aa2113b09e93d9d962a9b0b5ea95ef394babdc84a94fd000000000000000000000000000000000144feb467d549c3dcf5d5e3081725d005e00d7d53619353a3c12878d8ef34bc4b47b5e5b93b8151b7f8a0063a15fbdd60000000000000000000000000000000008478f5471e1e36f3743079c76fa50fa768e2b35c83a38e04ca3c9c932d86cb4411f75932dd670342b852f725a58ce0b000000000000000000000000000000000e1f390d4433ba006f487feba0fa4ddeade5496e9fe6c9c151948ff175e5a1f130baa7ecd8c9b47c50360aedb8dfdc8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0611f844e12e218ab92539401b39084e38ad3ca13ee410fc5bd6540059095c81163e5b3291c7816a725b34a86ec1cd00000000000000000000000000000000096ec435bee236c2480e2285d4a2cf8de15933acce4650203bc4bbe7c5c6e76e5463074ad6a1f4f9804d39b8910c31dd00000000000000000000000000000000066dd6f01444ec294f64267216a43d065cb6f3495b4a2b2b0e5472838052a0b37f5c5d25f48ca0f54b216e71e9920d640000000000000000000000000000000013a95a519f0663b81354760f9f5abe46c87372140b050e5778ad99509c578147ce0a585935639ba6d5626397c6b723f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036712f2039ce7561a5e8182a113ea9b8dfb43012dc3872055ab39be4a7e44c1b1c3d59e1b00a69eb74dda7ec27dffa8000000000000000000000000000000000152a753ddccd4111b38197b16772b681eb6fb76fc741ca6b126fb4d5c7b69d03c2bc66aa797dcfc75565d3a2cea6c50000000000000000000000000000000000b72b538c64701858f4c9f19f6b52597487bd8f482209ac39c06536b2e7c6f50b847090a87e6a6c6911df330f3b0a720000000000000000000000000000000000e2d4b97d4d16d74e69f018fe5bfc0a5a1e770a323d4f1b8f46b2f3315d1a8e24961613d260a41f4938e7b31682539251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085075f9c660a17c9d200416492dc33a11f1260b1856f65a4f8ab0595e94e0651b29f3b894b06f0b54378827537166f2000000000000000000000000000000000638fed6c1fd4c764ecf3faaf3d2f05d2c57bfc9264133c3cd857a1e769c362408c564b158bce946e8f3de793258599b000000000000000000000000000000001635375c2c79c55ae715893eb621b95fc2dab065e4d7df8a22fedcd686588093008dcd004206fee7281dcf903e1cf93e0000000000000000000000000000000015e70440bd6249933ed2842590db0149ba71ec1b9852361c931bca8c7d7304ad0ffc9afb557fbd254e26be16300abd7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175570400c76d9e368cc656f48223052bc4544383f0c523cd2f30a1f415250f5279813dabf0b77f060a217b17148283100000000000000000000000000000000170692f20c0ae0c3396dd21073f77aa504b0b493cd3027643640aef1244eca09b3a0fef2f8e36a50fca918b2620afd4d00000000000000000000000000000000000605e2106b7d8369e6cd4f5c8a476c62e7c85354924e5c692ad40ee5e3e40bfb0fc62fda94547d1f72de4d744c6b0e000000000000000000000000000000000f12a6a810cc4247a10975446d826d47e077af2e346dfddb59f3cab1e3326d58520c6a09e71cc5a0f2f529b4a785f8b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000008886ae0fd358d4dc149b0366c1db1d50cb26363598b728a82049696553e92c2dcdb2f810fe07b003e328bec08d09030000000000000000000000000000000009c814257e55c44f174bf51a922f9143a2aa2674b70de8953766323a07e25ede861c13321b8189d3d6e6955043c1b62c0000000000000000000000000000000003eb001098f5981e8b966a7ae01d21239330373d5371ec7a12bcccc1bbdeb07358ba3c12e72101451665608f65c15a30000000000000000000000000000000000ebfb130da225e9f8e5c755fe7b21c402285e1c1a5d5b61e1efd0f75caf0c93433937722da0b3d42652846b08e8ec2361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001709a81aeb16ed6b9c4549f906c1a9d404c8ff6e3122cc084814f2d01c9cf16f6055f85e3c63c8f6c7299c18d2f83398000000000000000000000000000000001032b231856afa4071f49c7d7f58b4afdeee61f3862c18c75ba9a46243db2edba3c68dc9c6414d1ec501ecf2c6fabd7400000000000000000000000000000000179bd02b7ce645e658b589743377b5cb49548ee95725b8bdb03edca25a0db46387fc257e533b4c9974f0da7ec212169600000000000000000000000000000000108c1de129985029b73be854f0c13b8d0e9803472839ea68dae7bdc28a04bfa5b640d277362577ebcd27de379102df461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e662365260344eb3f929a99e08786662ffa422e6a5a6bcae331db58a68c5906a193bdcfb5a7d733cbb3c6dbf76823b0000000000000000000000000000000011f73a0e4fbffd8be1047d69abd9e3bae8f2936faaf497045ca740008bcf943ce2d51724fe23ce992cb8e58c042d70ad000000000000000000000000000000001147840d29e5cb11fe6e62322b9b995e46fe5c2d6a879e10f631b607b280e5aac00769b04d9295e676f4cb6067a244c900000000000000000000000000000000180b0dabdc65d76aa6f3961754540bfaf96ca0af31c5092edc632c693e59625e7affe0874f40f53aaffe40636b00c85d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066688e510fcaf65ddb11420ab667c8736718abf790442298aa5c341dbe31382aea702b08702abb788c7be73dee782bc000000000000000000000000000000000da45b1775a48aa8f4fbd264e22b28e6f4682086ac41fd384431c7ff14aa2eb0fac3553e0692f58555e5cd53d897a2280000000000000000000000000000000015ec2c09df35fd9acdc6ed6f4251003a2e2a9882faa038c5ed4f76fad5c48bcdc0ad1bff4da148deea4a0e28123ffb34000000000000000000000000000000000fba2d0fff5a5af498726990dd2dcd0f42fd1efaecdaf111ed8cc6fe38367648a07573eb7941818ee94f2dd259e9cd4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112cee8d07c469f9d4d3efc7b8f2fe405b3ae09cdddae5515010d8eb381f2f1afa8885f4485f1e746ddba9d6b49e925700000000000000000000000000000000098c4e4ec37bfc1cb012d649c368c887864c973951412b470ad4d419005962a3d9eee80af3a7b8957759eff1792b941700000000000000000000000000000000199bd20a602cd70779a9f672639bcffb6562b0d865ee417584af691ddbed10480db780ac7ee946dd65c03d019c506fa100000000000000000000000000000000161962c0eb6a6ea8d94aec981dedbd65ee0d4ded2d7220bad3099daf6588cd7da8115e68d46288dd341306533376bea61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019159dfba1593ecf52fff3a1c7e3d23288bc3c8db33e5cc12874a6bb022e35792003a2944a9782a3db866cb67dcdba2300000000000000000000000000000000012212fb5d4152c4a8623e9f5aead224fb12f3cd5dbc3777f4c573b96033e2ea3e7683385e595afc9cc297802a9f2c29000000000000000000000000000000000632f49f610baf38f0b9718b8c1039528f4a1bbc242143d065b1b74bbb5797ec550106c74b5e49769ec4594e5ef783280000000000000000000000000000000002e72f5b22e1b7130055d1cd8797dfda31d39a4c65c4fcd0def65bb3094f9d412b0a675daea6ac3d1f6764085fd370aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bc8ee00fa425229b850af08845f26cf56d169b380d888460f5a2d91291fb775081d706cd2b0a713cd6f61f758427d500000000000000000000000000000000003b4b65e9eb74a94b07f9894b48eb7f4865c5549b8774e532fa54fd73bcfeabdd10591437bada72811d419f0572e00d90000000000000000000000000000000016e4b70e02df08d385829599cb1f8fa3e7cb3286039a15972a9ae7f94a8205bee7a4d82f7db926bf4e107fddefb65ca10000000000000000000000000000000004211b530e029367b40a8d775ac519cfca639c1a092e24380e05554917464437d50f8838936ab71515e5d0af0ffda55e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f70d567babe34fb659a7444e42ae43e4334fffa09f2b9bc32e0116750696f2cad5781bb1f053f249d11058d06c3a31000000000000000000000000000000000c29ed1eae99265188e487d056da3b3ff9314c41c27cea3985fc340cf6698447dcb49d97247f8050fd9025e5b997bdef000000000000000000000000000000001455f3e89ce1e845c11ecf3acdc8a87cc1bc212f2729463ac31fc41f9255ad5a60beb42656f3a9ccfd9f0b69ce83a5670000000000000000000000000000000017207c79fb1b4f03c17f8091dc9fda49e21f47b23028b629ce453a0bebdc77fbbb3d1f850da03afeadcd427d8fd4094e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000152f28834785a27e87012c0ed6d722b989d2056f49133aeded9c5b99bc2dfb0613357442ee0bee2b22a238f1d05982620000000000000000000000000000000005b6a87546d5308af3f0b460628997abac8d563fc14cc6d4dac998a712b57e1c1c018c2fb5b73dc138ed9b8d415debdf000000000000000000000000000000000de2183b1782e661b788300548923864cc203c2d5449052accaaf5f79e32752d48ec05e2b1e833c8e6fb9ddab954774300000000000000000000000000000000110d66c8f8ddcdf71be1833d2c000f4c2f85fdcd9cde4f65b765749f9a63a368eb3673679f6151dc79cf5dc33022b7bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a5e4a980ea5abea6412ea30825338849fcdc844099798a2b33eae3e0d5cb25e7281cef2f90efd65b868946486a5130000000000000000000000000000000000d8e60949c5b9abf56fa4f509ae6acdb90c753708cd4a9eee23285cb502bf2326677b4f3b855d9d3f95332498d02a1680000000000000000000000000000000007e1fcfeee96034571d72a1197ce05ce34e53697d7a6294580ce56aa3dd49d494babc6e4f9fcc22d26ea8efa2e6d4e4f0000000000000000000000000000000001ed8ac2dcd112cf7edd79d51b7aed1bd2c5988edb02a7eb8ca01c4e30794cc246819e24550538bc7e166dbb653875e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148b994874c5ec173c38d591369e80aaf7b23a2a052ca2d280b612e23a23c8d66f70ba15746fa72aa420316767e38da80000000000000000000000000000000008ec0ab60afa123b776e5ee1b0a22d775251a465045f0da9c8f90a28320e3a4b5c2f7f5c6215bbb765b68881290583c50000000000000000000000000000000010394a5855c452bf39bb2a423518444405dc893e767fa9fd42a302b2390a7cdd2ce2dd965c1d334e774391e1b5fb2ce60000000000000000000000000000000003b6ae31ea537db4e2000516316ff3c9f520244ad452705bb576a2a5bb74ea5f7028865587a7766c515c5b2912d5a0c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9acf78e678875babcd5fd3fd9e5f62f19a90929402fd2920016dd555f298a92ea34a049cf6a741a1a9f1543553d8540000000000000000000000000000000015615f7463d0add856a62838ad0d79edb99c7572fe1d6fbb13abb43ae8d3d85d8f708595331802a921f3a357b215a23c0000000000000000000000000000000007ef456a488a08f49636aebdb8690e70520ec29faa8ae60a7fc276b9aef80042f84aaf1d636de75f9473465b9a8a4b2c00000000000000000000000000000000068d732e649bf661d279bd27264b24901c577de167036b52e5b9a091d99e83575fe503f678ff8992a6e8ed7b2f7d5d051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092c48ffa55def1ce34d0dba7cb7b8030f2fee81c2faafe7e149e565f4f70b01332e4eb9fa7c839b6c7939b9089d7eb800000000000000000000000000000000140c67c448118587fb0a78859369d05ced4cd823348830181632291a610b20f26aaf6addb7badf7c8c15977f16e9c265000000000000000000000000000000000717d34024b983f39cf59d31d426f9ff6f76ee8b6089cebf5af5ef9e0e30824546e0e64397fe0f09e493d8f4c4b215c5000000000000000000000000000000000ef10f691ba6b1223a1cf9852f015dee0858bfbdb564b8ff6eab7cfbafc5bfc18881b0671b78c6a8051daae774f9889b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fcae3e13184daf32364bb7986d2d65b91037530127565d70b6140a71cdeaa19f08dd95344a9dc7abfed1d23ce7d3194000000000000000000000000000000000418cce0a2f81969a385a8b210298737133140e07544a2961d05cbb97840fc5074d27ff305838ad3629ed527f88d7d720000000000000000000000000000000006c81ba77a2f1a59e348b3dd0939ee8a0edb9436c1edbbadfa6d9b7538ff22215b8a4ec69b99f731bc6ff3943c44e0dd000000000000000000000000000000000b7b5305f8ed0bb2c848006a036117a7d89b4c216e813b223e1a860a7b26555a6bb0de228010a92551a060cdb9480ea01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018220097f007dcd0a8122cc44be0d23364c7b68f3ec0e6332902eb3ca46ba8f0434589de0d35eaac5baf3f08b5a5cff200000000000000000000000000000000170a44f73678b017b54c58422293acf6dcc8be832f55c0cdd5e124f3bfe1c3289287452825c642de85226977ce75475c000000000000000000000000000000001572796799892e96bc6ec55053c91598edbe707ccb0376ab8759b6b9486f15582ca87323f1308e69c9e690554e895502000000000000000000000000000000001383a327f76862ce0341278bcdb0bf4663edaf6d33e8925440fd2e9fb84e534f2bf340bf31dad16a975a2829367dac461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bace9b608c575d5456ef2418e19bf0e5b40b0aef913380190f54b049dc458852175326bb51072660189fb4489b1a4270000000000000000000000000000000017fba5033f5f5fa6ff7388759a432060de9121c58aae3300559f77e6ad214c04e06ade066c513776d2f2713f572cebf8000000000000000000000000000000000646954a2e21c5cdd51e3743f75e89f1bfbeb99e8cdcc2e1dfec4c14ced9d68d37912c9dba9ff5a1d5492ab2d04946420000000000000000000000000000000007bb38977b6584338b0d40a09b5578bfe1c4350f361413123e4cb96fa37d6ad9651fe8a376077a0a29c9c3d33d133c7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f0c79818f4db2049d8381bde101faa48326cce226c54ef10fc9fb0997176046ba0ad2b1ecfa7fff08d06cf9685614e40000000000000000000000000000000010b2b8277d11a3d204f99bb626ab43fe9f5750a72bcc872fda68c4cddd6a293c40cbe9b610595b1f2c2b6ca78292ad7c000000000000000000000000000000001137391b4883ddbcdb4b22caa8eba53ff82c87e3f7c62677ded8cf4ebfc326c4a0e00dd699fbdede47ba7185f96c14740000000000000000000000000000000018cc75b7d282d192d95277f8889a0190df91c4347adaa0198dd76d643b1852c098658885b5a21f7d4714c221307aab0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001587bb8badaad9d73f4bcac7ec27267748c0c62160fc4a6db8655140671d624b7e9631f9eb699f15958aff07867164020000000000000000000000000000000004ccd119d74c8fa36e0d3fdf8dca487b6b27da877ab548e86b804aee6c1462350818239e438c1fa8a147d6749df89226000000000000000000000000000000000772617477bd9897f27bb602fa3b8e6a447fc08ff9d9311bcf1d35f4675a61a7eeebbfd8d5e5b6dd61eaa28405b101c70000000000000000000000000000000006ccf30b015b1bf92cc2ab1e5390cdd012494d933e05aef7772cbeb2d400be49ca4e88794f8b00c69a51c3b3ee8d35421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037e653978a769203edfe1d17f39674442c748f728bfd6bd8897517a14ab4c045c5d590da5b6cdbd116a645d591d019600000000000000000000000000000000013fc5225de46f535a68a5a21a9ac505ab3c81059dee70295ea18d24b65cff44a081b3967eb071aa72c0474d229cd9300000000000000000000000000000000019e6315c31698af5364366b788f5311df6d03e034e1c5a99fbbbf7f4bf0a63d11cf39c196ed92654825325d3c1b5f1f4000000000000000000000000000000000f84d1bde84578b57da85dc401a8a93a228274d4ce1cb36a602d7b38f9dc2b2fcec870681a92344d39651e23400764671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d2c25f41e5dcc785e507952143db7659a4cab91833372e9ded28d8e1f90292a4a8305c93a9d476377247769ab232c70000000000000000000000000000000000f8fb27adfd8236b01b48cbd06e9d51fafc7c5365160e5bafa52606654c638c1051305d6a2f45d465d70fad27cd641f000000000000000000000000000000000b3005d5e5ac6ed721feca1c9b2a6693a89b5c9aba8e0e1e6cfaa673651fe07ddf05e49723b01556eed7ebac513315c4000000000000000000000000000000000545971faceb6aca0748df65d42ece7914e2e8b9e1a3a8f998dc99caee87453dccc689523777e80fbc65dea6f03a17841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030560e81126ce3a748c2a9003d2098c9cad1db18a90c7bb817251bf032180f46955165992fc7cb2d4dcb74f6969f9da00000000000000000000000000000000036122082a8a317bfddb2666c7abfe458004fc9a3bdc08aaa9ea6b7bac5e116c13e99dc7db41ea657dd07111bd7ae3c300000000000000000000000000000000029deac2cdf87e1f6e86897c9faebd91a519bac1e87b91754176acdd99c4e6adf256b4a90dcf4283ce79e3a425848a6a000000000000000000000000000000001627e51f4c11cb74e3127c4412701819b70477c4ab2d627fa674b1e091dfc4f59085889d76a052c92f60a01e4331f0401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016a6d3fa1641825a2c6cb57ebc290f63032889458dafea568c9231a109fc88c17518f2567823e10b2e997de46d2798c70000000000000000000000000000000016322f7ba19ac68a362f93e76610831223935c80481c6347909e830b18a3e9080a415ca03f12005ad0980b5d02652336000000000000000000000000000000001544753b9c8fe12d74edd9e26f912b0cb6f7045a9264c724241e9e21c42e053e5eac56d855736470c8563257177423740000000000000000000000000000000004f7a96969a19c3df7b596939c99e8325fe2db0e5195d8fe0975c4a2323e4493304a904a812f2428faa7616fb67ac9051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018412445aed14377f37cf0883540ecf97086c6761f3692e932c9c1db8ccf44e88b5c91883f90a5ad4f9c8f61a50eca7100000000000000000000000000000000140526c92d058e26d578fdf232a3d982695e0061201c83eca14639edfac4165fbff9b5ee8f231b4107e9d8ae3ef8805d000000000000000000000000000000000669562d2d796a830bba80bc1716af8cff97e03a4ab069b410f491c301c6cb732e571ea280ba1f8fe7121353e2b0827b000000000000000000000000000000000f4165223e932a354e966c8a1f22c6ef2c78a3d97ae65b3ce3484d062fc35d53c5f111d231a7310e083de349c56941691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ffa02cff33f07e0a5357a410527e99e1b13536f669d9f14bd57e0352cf4b8b7558e9477bc3e7b3387ae7f340221df10000000000000000000000000000000009075885df8a5703965e26f84cf78e1fcc5d89b1e5bdecb9ec6493277797a049197c606904fa3693361a96af99a442e7000000000000000000000000000000000852bfd13d7c103d9e5ec7264e6a1ba46a415368bc2ed35cc17132a23301153daec7818e4c0b368cff8fb094261de5a30000000000000000000000000000000008261a627bac489093caff59154ba5353ba7226061d471750d5b301121e082c1a919925e56812ad8020cd444dfe47f131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa54c8111405d0c03f35100b7c10f8989bd574398e818cbacdee17019e68b938418e5d6534d83536f94234c3ce0e796000000000000000000000000000000000908f4029605b99e06360f8913bfa9df9663e1f8581d66d4e477ef3d6cca3390d8b4f8c37cee26a4823cc2417faecf98000000000000000000000000000000000b7b9eb8d8f7e84f8ce76ac2a2d9ea6743974727f8e8024182f64390c942cd982b9ed8fb61cec2dda50438799f967bf3000000000000000000000000000000000fffbac2ddb46c588620d481ae491a2e59dc852cd4c1180fbcb5ab1af3e90626951e8e351edb4d62d0e3f76227f744e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019352a2d4bf1b414a33d6a7688e8fbe1dd15c21592ab325a5deb35549ce0fd30d3d48917cd95df9658762b8c27321585000000000000000000000000000000000c3890a1fc32cfea5ca8a2f35b14367dc04c734a1b69dfaf8d92a8a15dee11d283fbcfa58e93af067855f2c57be2d2c70000000000000000000000000000000014bb622ea21d1878bf27f3db4ac182231156c5f7073a7bce2e06b2341609ae71509af8b2891a3d603f44581c0dbc26770000000000000000000000000000000003b0151220d4858605fdb2d361763faee72a76de0907827994f3bdd4f8a296f44b04e538c91465be19c5d0bffd23e2be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a204612d53db78afca947e0bcfd1cccc2799b519513e0e36c19a9dfa3cc76a25ae86a810e61b034e7c1bb02c5c205140000000000000000000000000000000014fe93fb6683fcd34740a322a6cdb664d2228c083702f7ad1131912fc9e0c65ba67c7b11a864a093c7d3a05a25dbb3ec000000000000000000000000000000001476b6996a63c9bc64488d79f797d19c6b80e067be01bc77c2bc17cb5533f72b1dad5019d76aae722b730408848ca878000000000000000000000000000000000a2385a1f49b090f35d953313bbe66c24ffb1cb6e44aecae6259a66555074316f8f4dca99d67670101e1173e2df764b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d33d6fd3642682b2eb0fb6670b51cb364367eec72be0a53a3cbb18188c84339db3c7aae6e53d7dc93bfaced96f73fd8000000000000000000000000000000000de0f197cf67c821c8ed5deab6ee2a055525d64a29a46a452f1627c27254f0cb7945c911751ea5519eca2df4928a901800000000000000000000000000000000043d5f77b75dad9a05be2548f487cb52df4e5708974823c2e1d06d2dfe1af9f48827c57d064d5c45cc06b6e42829816e0000000000000000000000000000000007da8a0b553346e3970994a40fa5379c8e6c8316d512561e422c34058a01df801abce2bd719fa38ea119823188d2a8441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8f51a0986a0c35674d96ea24b8d2a0ada8a65e32682b3dacdf3008f0f5cb83b7749efee23f27444d731d3eb8fc1ab300000000000000000000000000000000182fc9e0c8d0bb9f79cc8a66c242ca457bf651eb8d1ae530ca11a7181c3ecfb0232ea038d2066083ee6b60d2d1ebc03000000000000000000000000000000000109b3ea91b1490a7372ff2e093fdac429d713e4e96c07619e9a42208a172abb0ede907907dd4dadf18463b7d7ea4fd5c000000000000000000000000000000000b4654e698720ddf4a036401e94b9c39c2bc8ae055a6a1b19b6faa2a0e7ba824ef2f3037af846a2a2f727b982fa77faf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181af21f18a7d595564aa96dc3f02f5a6233dd524a962b76966d594204dcd4b7bb1f480fa568b3c2dd2452026661e25b0000000000000000000000000000000015c1e972c3db61c53664585426a709f873bbfcc068a93c1e86fb7790c48da425b5eacf7599d7171ae93e1b3e8f43a4a80000000000000000000000000000000019b1fa411a8b5c7c457953337185cbfdbdef4cc866fa7899a68a6f3af3d630287a4537b5e8ae71f80d05521eefc9e7b200000000000000000000000000000000152ba8a41a83c201b6e7e33dda1090ab9261313d219fc5407845c65c4e58c2ec0c58153d2bf8df57cc1dafa3b7f8aafc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a7b2ba163195a1845b37661e537a13f3f3b0c1ff63b2d8cadeb327b8b78fa5014eff4c07e1902857d3541148dff221000000000000000000000000000000001115c7ce999d4a332bd74ec9b6ecd67ca6526de7b043bd6f9bf24d0664393d381250adbd326207f60f82dcea2300978b00000000000000000000000000000000114fe0966f42826b191b7e046156cb2a6ead458bb9d69f8682c7e8436157bf1e1f3ea3b143724dbc6f3d24b9652090c0000000000000000000000000000000000e2fd360249488aabea29ba6d2a778b272676125657487f13196bbfbff5d1fe0c8d6833c8c2505401c7aa3e8ea05bf491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007032fb6938856b7b6751c8e44293e15afa939c41cc2eb7947b25b4959521568bb8dd71b94c6fea9d31abdbf262311b30000000000000000000000000000000014cfc5e63024d9fb3972e15383cce25cfd6ebd107da68a8fe736dd2297a97e209a9ee21ecc1deba8b0ca119e2a3bdc6f0000000000000000000000000000000004b52860377fc13f562103935809800507ebe7e7c707eebf64a6cc18b2f73f0ae1e9d7b9961d8342343b8b92923a0390000000000000000000000000000000000f5e1cc23e9610221a474781c6f3cb44342ae3471d457f0411f369e472a7efda951f81d623ef70782982c3cfd4c65e431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b7d8b4037b6ec3bd7fd00e99e9f116f9a8b51eeff8551443f862ed6a6f4a05ad1c8f5a905bc95d57cd9ef1e541c24c00000000000000000000000000000000184a677ea38273f7af7f689f8aa2e1b230802b9bbef501f08779f42d6fdf82eca5949f70cae268a8f61a3ade8aa453bb00000000000000000000000000000000090edb16254336cf902f07a360730d22c6f6dea915bf55d4e5ff00799b4055f5a9f467d4a6a59e7d8d2e302a2a461e99000000000000000000000000000000000447f0d73530ec5b68e8f47e97a77aaa6a1abfdb4b046760f50478c33d8b4f22c963b19f146d1c600059ac311658ac6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001165da18a43adcc426c8d1422f8e43ad33f406112679cd702bbef5442617f5defdbc1f7a02e2c5f643b13bd2d4df72a6000000000000000000000000000000000ccf19a5f22b8e3bc419d6a870032431793b94790a60863527b58855bcdfac5ed0496a9c50097067c0c9a9b14ef0b29c000000000000000000000000000000001085f5afd2808c359d2a22cb6e50e195a0b1525f04d8f95b73312ab7c09a15e732c35fd5292868a806b8fed952e1fa6c0000000000000000000000000000000008fe2f68ff11afca8a236fab884ff4ad5a97ae6637fc1f2adb79be630b7587bbe0d7b659b8b8c83efc3de83c7cbbfb111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f33b5121373d8139214ab8359f28791692dc33de2673544458ab4058a02c983f0226b38e926eb6455f15414073c55600000000000000000000000000000000195ef0ab287f17cc11b667e627b69c4dd5fbc976e81a48451e28c6be371256ed682761fcfe9ee5302dbf7078768261c6000000000000000000000000000000000e939114c8cd332043f5e01b8b3e606e48dd4c259264dc02afbadeff9488279d2427734cd1abd890c00364076c1ca5a00000000000000000000000000000000006444f86ded8a99414ecf6ca864321ac29b075aa01337ee689666c949c9ed046b140f31f109733d9d949e9a5598c14821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000aeafd00ed00f02f1c9a2427675e6f2bae46842d02d9864eedc27082f64bb70b47f3a74e65e4565f1c1f14198a2b89900000000000000000000000000000000040318c66bdeae1fbf2195f7c456f1421baeda98240c7bcca59374ea315f04f233844b2f826b79a6d28148ce1044ee0b0000000000000000000000000000000002b727883399298c762502c10c920a5f0ecbfdff7d0f4819b0e72df3657353e42b9817c76ac817910e4b048574284b300000000000000000000000000000000017a22d333462b4d53313f556efb9e29400852051f46b07455f98959578b40705b6bfd01cf4ef4a9c7a0ad8a752287d7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147c2ce6395844cc949a4a963abfdc14f1090e149097b6a14198560114266bada4cdc8861a6070add3a30766afd1b36c0000000000000000000000000000000011570b6e940f932ad6d0295daba39f0fb8705c538e13f877e1ead99057712e34276422bb6216ea7b61340532948dcda30000000000000000000000000000000007f6bdc504a99ee9cd57fa5005fa0e0f26762b646363e61bc507d97f82bcd453dc681b807e31e7d497b19d278dd0ee14000000000000000000000000000000000805a1dd2afd8a1a47fc363a4dc4c6d19f68c078ec58982249576f10f1ba3452d53318087701f2d3ced777955a70d8161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e10319d1b233a6eab491b9604ac2086685d29c19a484155439c1bf8c5ae26dcbfad52adc283a3df59b048b19c95590f000000000000000000000000000000000b17d5d1d1c6a73214ef95323e66e40653ec7069f8b109466f2cefeb1a359948e477df27f55d6294d274f633cc38ded80000000000000000000000000000000002232d2020bf2677ceda4ccc52afedff832115a71d4e589a57f1466ec09e1968621f5c55e126d70cbc02ec2072c693040000000000000000000000000000000012bca67763792c838e436882b59e415b77808d37cb6ba90455a7ca74784a8dd9c63a035cccab545128985b59cfb7e5931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000244b7a88515ae470ab4c535452514bfb99a605eb74122e481247c0332d9ddcc098377ea9a35238ef8e0004a1d6551c1000000000000000000000000000000000038a4f4a41219c9cefed9764ed2698c5ee36a47123080c0fe29a81f4d04ab6079f7c57420b889ea704c8bd5d3cdc5fb00000000000000000000000000000000034381085e74f8717a84e6cd6969407fdf50aeaad39e42bb6d6ee46759ddb5cbdea9a163a5c7f928ce65f69301f4abf400000000000000000000000000000000070cc29ced091bbd0f8ac95ed675cc3d97df4fbe1e7f89872fa354d8a8105a9d15dbdba00b2935f6d18b84b824b3d02a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018606dca928287ab29aae1875021e2f988f9ea1ff28cb82ed1e9a00f983544be4b21d13e16be2abd8b36da001b81fc080000000000000000000000000000000004fd5f248e14dce79fd25766561e88d86a142d310de56e1b132d2d49406c2dc768ed06c0b299145b9576c886f6889bc70000000000000000000000000000000000333f28dc5371481e29c1808b455a5941d3e3a2004767887366b698c208bf51a586ac74075ff23794b62e46540280120000000000000000000000000000000015a6101d66a734130f8cb44b0ad89b0fc57abe45d6cd48f91d35dc57c2b374bedfc5ffaadcae9ef82e43ee0b36a094861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a734395608579021e9ca428ba5f47a0235ac89c7115c467c22ecfa654d6e26ba08243cc76b037bf8d38828896a7f1060000000000000000000000000000000018d19f3448d52b16eb2f09df1d92ef62846097d809a9e4f71b5201716f8b5b7153c6cc94d4c7d6dcccf62f1490c47be8000000000000000000000000000000000e5563686ed6668f70abb9f59f5206b8ba1fe9ceb0efb7ea9785dbdc228a0eca6fb0652ad8e61dcc785c5cc2cf0e06120000000000000000000000000000000017242d006e41ede3dcabd4806431a784328f50b840f05dd4cac3a0d09c8134d1f0e88d41bc07c05111c48d2871bf6c021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000960fc8ed6359bd4f52a4be2042326a2c4d4f6efa191a206504737d171a1aa56f4d07357f1834d645833d0a9f055b56000000000000000000000000000000001407670157b31d38812a82a8eb8b58d80331a367a87d5a6271b93074fdcab2635a3262c36b820e639938043b3bb93ba4000000000000000000000000000000001339ac3270951d45e020398233649e07d1e74b1fd88b6a9174449ae7b6b6bed15094f346aeb5632bcd254a8cb502e45f0000000000000000000000000000000011cf85e4c5fa591ab0c0473a09572c483cb6f4d5553ce4b99ff07899b6f66e5414133dde4ffcb026fd71eabfc55d7a6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118a3b5bd9a8367df6af54b09b83566b6769bd71c95453f8e39ef9c7d452f3b3b3f1acf1f8efdd69a434a7cf308c584d000000000000000000000000000000001499c3eed43d3e84064bf99f64a9846feb2d39855f36371d280dd64e1d066ebb6b530668910dd188f8150b45f9b7fee30000000000000000000000000000000006189be0d9b5d75b72de13b4632344701f7c4544e6a5c0661e9b7cfca7d9c8f2c921778f51c3538a2bfd374cafd88fd1000000000000000000000000000000001835ab6e36a6dbedd7bb79a48186cadc8aa8af6981024ac2057b412446ba01bb322c5d00d2e5b678615c8a296b080a071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e49f5e9c6650dde9bbc767b5fb8eb8ea43455653193fd0bb6aeecff8d592eb9646b8c11343dfddbd0a255f4ec4c22800000000000000000000000000000000114b6db8ba79805e930ace5577806707307cd5fb644d01c6b41af665bd90e8b39a7cbb8ba1adaaae2e4db077f980fc38000000000000000000000000000000001215ee646eefb826bc986c6adbc591843aa3e318a6bc6886725185edbac6b3f22bd39593c57c6a9c5249028696dc9a35000000000000000000000000000000000796bc5b4770dcd90556aa5aa9ce03bfde22db4af927970d682af1d1a5c383edcbc86abca431c341981debf16b527c451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000190fb3ff260b07bf49720d832ba515ce384d31a8bbc34bd51777873d98d7730830a4ae9242ac3cfbe6c80a56ed0eadac000000000000000000000000000000001882c15afe9b86b08f26dc6bac2eb69041e3ab058a7bd2fbc2a582c3647788276525f1e3ebdd8dc9c39534df33c14047000000000000000000000000000000000ebf9a3cc852c0e662b770a70b45b946c629d1010fde4248ebef31c50bc7500a809cc0e8cafb3465c2e06a245958859a000000000000000000000000000000000539d0956445a8b86685d67dc64bff935f546641a408c2a506f3a2dc1e57f41b4444841562063cd5ca7ce2eb8d58bfcc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111a80b8e17a45740fdbdf94f5fc15505f4ae2c979874cf897bad03c603eac375ffd33cf8a75d71b88f348016b47371c000000000000000000000000000000000890117269dfe3986f2ddcebbd203422d631e93a181681102a691c2553b8969e79a3f709010e4adb25013fe333dc5b9d00000000000000000000000000000000188af64b5818fee9be86e9c0bf11f4e5a51cd6fef97de84df00b6355564bd00f1748b43ec5849dc11282ec4954eeef60000000000000000000000000000000000ca6fb93ce8aaabe7505f059c71e264fcb810dfe2a49bf23a48418666786f29f2b5efff04f459b862ab21274653500591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e2c1b55579b95f8ed370d7118fc276057e73d4baff293da1db3945dd1279e23136c6378d8293668688e45943fb4d430000000000000000000000000000000000c410da02c7c32f2eba77b8e2a085faf20ff9fffe799ba81e8b60c29198fd2a22f12bcdc9553df432861d59a5e307120000000000000000000000000000000002492568d25b596057e1013fc77197df068918bf75bf2095f7f337be7c9aed7e368c7282b935d41ebe94c489cdd4efa4000000000000000000000000000000000a0cd8e4bbef4537fb0cfbe75d13c709c263dfa64ea1b04258559c512a1eabae2d1a36cb7156e509f76ffa8efac7acc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000129bfef481b0fac1c327a2e47af1f9ddd42f782cc0d32b16b91be618b78cb0d0b45415f6bdb82ff5575b7a05868390f800000000000000000000000000000000163a0b1bfd787c1270164997b7ba2e2f0592570972fc9bd6a11d92c00c995c6c4bbf4d7832b88e48029b0cce424d4a550000000000000000000000000000000013364d52522e84ff293d03b7ad2bef4d8fd56612c0a60b8c8208da701166c12415d1b226992580c4c2f1a110aa30486700000000000000000000000000000000142931ddb4d4ccff2b29ead016f55c4effd2ad855afca77b0a3d58e34d3a3c07030663478408eb8fde9b775b67d3a9491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f4eb6e030980cf76714a2e98377c4ed296a248eaa65b63825c71a9df5bd69195782aff300a318c5b0135bee6f180310000000000000000000000000000000008b33313b29587b3d8f892ca9db1d924eb14836cc8926154379fbfde09b11c72a1b2e732a5267862ed1f61257e74bd3900000000000000000000000000000000114e0a4e0f937fbb5d1ad42c8747009e09b6b6fbcccf392ddfc724c57c2dc23215c2a9b6d784dccf21bd099c93d9c3d2000000000000000000000000000000000ad5b8f329bd0ab0ec2e330f92cdd2d8d69ab01415b8fd3b4d743a23290f0c1581f3648989218cb3021e03be447e8e031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007712221ffbc33d76b18787503a3e1049a67af192e78bbeb7faa5d51eff21e1489cccc82d6dd7dddf53c3811c3f2c3480000000000000000000000000000000000b19fd27233e9ac26b011c09d0ca875855e18265133e1a8ec384bb6f4ba317263b8538a37764543ecd16d67594b8ab300000000000000000000000000000000053abcb1a7507e1d94f033666b62ad1970ea372597f13b572db8905f8c94c715888a9ad31e0dce1f56a42e3cdfe9b19000000000000000000000000000000000036bbad31764cee56070df32db5fa3d1886179b125e5bd342a3fa93295d0238731febd01c7d22560bb64b1adef0139271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000068f84c19570bc5eb5d6780f2ebc0419c78dafeacfc6ac486d093114dededa2d2cdcf462559137b79919ce79f5debbe6000000000000000000000000000000000407b5d8793da299da23e747342605823080ed74203a415a9653f2ddf8b399f785ab8aea87005f1a01f35aae247081dd0000000000000000000000000000000011aefa333920867e9bb933a0a72431c09adb236e16274e5e83648cb796fbecf3d1f0a4021aec6ffd0c75e42a154560dd000000000000000000000000000000000584ee068921e9b5f11ae53953ee4b0b49524784c86fc4fa09d0cfcde8fa87417c63a448c10840601293a1e2b46142c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001812281eae1212851ee34d25f27f24b0d931e24cdf04b7323f87a9401966c50d2d9ac4b389c7a9dce4edd4a9f6317662000000000000000000000000000000000a08abd9dc218d21ec91e4377d93bf1a5d673504ee9f60274be05df7dea164391a36c53739c4b174bcb680d5ec0d677b0000000000000000000000000000000009f8a4348bb2cd5f71136125f3049cd8cdc902ac3da99327228364d2397bbd1abda4ba66576bbd8bb0a7a002a90087c70000000000000000000000000000000016d670a483bd40b836b21f39c3b6641a19e7ce61072dd3b14ad371553a1fd9bf39f6d73a7490785d75619bd6569454d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019305f1f36507e0e8521113e3bbc2adec7ce1c049de5a674e0085a102bf6f1d42338522b4f09a3961353b057e6db97b80000000000000000000000000000000012d439f0b94eab2216747fbbe257b0fafaceb41d38e4326023e4af91c840232947bc1b4acc0a2c8c283001aa1f42f66a000000000000000000000000000000000e0d7ebb5b7ba07fd5449df40ffb5f5719079ee0971878f2ca9607139e68249da6bc15bf7519dbcae55e3b1bd1a61fac000000000000000000000000000000000512c644575503d35739f0d605b5eac698a3325960eaf107fef2c2d46ff5cc6cae446a42c2dd09bd2080d060f349124b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000147eecf5f54d9e36215cff57a3104e228dfd6065b1c26f900455e39c04392b3bb183d755349b879770bf3dcc1627e16a0000000000000000000000000000000010432b2166989b922a30f29d2f0beac393c404a4e07c60c45e68f162930d419e037938a499d235d9c800d8257af734080000000000000000000000000000000019e6982286bf1a6e395c043e8c3c96eced51045340fb00d3c1054f1c946bc99c860330ce75fbf901327ef7516b6a4ea10000000000000000000000000000000012d700492a7fb1991c82664a6138ac7d1c9a1cbe684a76847d7ee970b0eac2b7ba990a3ad44054267aac03c8701cd2651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024f7cff881f2c0cfdca829a0a2265c4b129e28c5d57fa3da878b3f2f7474bca258fdff29994333d8ffc11de9bd6a3b40000000000000000000000000000000007ebb0c5f4696859943e60ebb0bf0f945f01c92b17464263b9a0b50a03d54609273d45736c633f5b433729b788b935410000000000000000000000000000000005b614db814123d240cfad4fbe8786649d1e591067b8531c18bc07176e39744641be4d0ad0d5b09a8f734f69e016ccc20000000000000000000000000000000019f20d67b9b6e3c4d62ff1fb6392c8c9c647c014b2e8b32e6fdfd0c3625c0a35c6c93cacc4c4f4a8f712c331daf11eda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b57ade409f3c95cae3672e11894fe94abb3a619454e78bf56a585c511c1374778a809f38985a66f2600a7d3c3468906000000000000000000000000000000000397596b505cef9e1cebb8539635d421954b00c4ef709262f932a27e2c5cce29f005ee1703d725e6b38189c29553626e0000000000000000000000000000000013dc0221eeea9740f34762289859eafd1c4e14f76dc0e4a15557a652c0062e76da199bed52bbfdc1902318e710ff88db00000000000000000000000000000000071e13a72168087b6e1ccca65f7beda0d1ca96bd7dca5f917986868a17d643f20a6140a649bd7ac024cb9293e48d25631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011365b62b61c0f3f6e021cb815c7c8d1b5a005a2169eaaa27bf8a230af1f169aca2ac71a44c2e6139482f0908c95f25f0000000000000000000000000000000007ccd54a9f3a898585d68af29032babb808197c6e60b3f9e41bdb9fb518a3bf5c90620e4bd35e7c533005a1b92f3b4c50000000000000000000000000000000002ea122b9908389c346cd77b5fa725bd338becc89dfd423b4a688209adf9894f34672757c009f2db07d4208c743cf5eb0000000000000000000000000000000014e5b66d4026ebe0bf79008fe22ee9dc3783806f7c0b96a76bbadec13e7312c412e11d63011038b06d32a1a2e0da93c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4a459a3b459eac8ac5258a501a6ba25c8fca39ce1dd89bc921d4bb313db4a536204ce7a1078d27aaffebaa29bcdef700000000000000000000000000000000163ea3ba94263b16e5fe968221a5c454e97d1c15462a36d767478bceadc21f5973d9cc0b3edd89295220655ba13c16450000000000000000000000000000000015034b768dedfeee249b008ff78a64a8bc5582ce06761ea2684b249e4218406d42d56e600235d83463c4bffcec8a9e7900000000000000000000000000000000175100ef2d14210b320998f4e2c3106184065036352b4d7b77733d7b3ea5d91173b16b42ecf04345717644acfcb5c0851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000064ea2b66e11cf7da1438edb1f9e3f72b622217d5b4b2d353de461b0272fa549064eb948620c368bfbe0fb7a6ea80ecd000000000000000000000000000000000c591e5b7b0cfd05435b9a56d0928a2a14c276b6a3896b637564fdadc5153683d672493103122f136cca6143978e2e11000000000000000000000000000000001625529d10ce4564f8edb8d4157afa00719f451297b75e3d095df0a54e4302588caf229f21de0c0372a56f9ec2d7ede0000000000000000000000000000000000bce063fd03f31a20c277434295701e20ce668c4e97ae83edc39336a81d9bbf5725118b608cec15d4becfcb2596ac2601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001547818ac7f74d0820a9786e0ecc319696a2c40643a6276f6bd918e5752e49f148f93d1efdacf9fd4b685f1dee3d09a70000000000000000000000000000000014b92c43c212c16334f4d066e00ffe68fab8c9df45da27a72eba6be871c1edb5ca5ab0697d7a7ca1f1fc7007b357a8c40000000000000000000000000000000001ae36b106b160c1c4ba7df26cdf50dec457b3077e709f80877240be5c022d676b3614709679abf7e671835d5b28f713000000000000000000000000000000000e2e0b144cc06e0ec1d6031595786dcee7061264fae10897e2cbc65dfcbe0c1954f7111cfdd30f63dd5a0a33791b92fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000edf04176b736c041bd82b913b9b788ed2b5b9404589d044a672a6069806c01ed07b25b37a7c5310a127f35e6e23925000000000000000000000000000000000fbb3e0f75dbd302453e2b9893decd0dde996860b530027d3ab9261b0874a28da530a0dc5da6fd22c293c143110b2f010000000000000000000000000000000004ea48fc776b6f64c683c8aeab32b0e483040e7c6a569ba91ce2762ef6dcd5f031cb8eb252accff2c90af515755ad70b000000000000000000000000000000000d69b8b4be292e41edd5e02879062477b67f76c483901d3de33ce586df982431b857b32da783ea9deb057ed971f324e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001643b8063e6b0d19e4b6da312c7c50a5c8a9f87ae705be985be581ef99d0df7a85539d0ea9f4680a338fa59ec3e21389000000000000000000000000000000000e244ddcd204e701874401aeea4aee55d4b0d1dc30ea2e486cc7f842ed6be9f39be2f2a577c7088c863a43ac7d3f4d28000000000000000000000000000000000c20f27c6ae0aedf5f7fb0c134fc5a5bdbc68ee6e4109b867bd3751edc7b3f8aa02549d7dc944a24fa69d7f7ae30011a000000000000000000000000000000001129dc6deded0ab3f53c60933a96ff62693a4419d453d8d240ce6f7ebd0a3a776d6100f35428001eb755528f342321941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfb714de3f8c310b0b70525670b5950ddf94da002f74a9a3387a5709e440e805ee8b5f7b631858f51e665c253108c8d000000000000000000000000000000000a20ed389c6f0df832a5ec5bec9c02bf890499d864f9ae088ac755ab811060185bbf9a53516f4b444cddbb0cd30d5468000000000000000000000000000000000d534736b52a7707d863f01ed59f96dd9d3914c03e119a3dc201f302941a26987bb53c77a27a5f06f19413ab74a3d06700000000000000000000000000000000090c7391a190a472f5ca9868f506625b0955138764be339ccf351a0b8e2540d129378cb5528bf0059a040173c56853741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083bc547c87a7dde16ce9826c9795944885ece1d2ce1031298af010d6827dc82a8ce2cc90fe0052a814324dca9ecfdba000000000000000000000000000000001398fc827f4969ac1a80bd0dd1503a34ed0699779ab6c8d902d71a829d786a5f688c694f99a47052c629007e4ea463440000000000000000000000000000000007e1b442d323d82fff49c42a0a48d695c0b14d0332c1c0c00f35d604e12ab70b629adcdb8c94a72c20131573ce495419000000000000000000000000000000000f3fd71f10d3c653f0c89e58ce4676fc148b8ef937b5aacffe7a4208d79763fcf53f26b3280026871a12b68bc511206a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e9d4a5748f2f56c336d84ee51ad589d2c250566d61b26e06357d15b0992ed64afdc436c2b923c5e6e0e3de85bec2a500000000000000000000000000000000172dc799eb04591be7b8680b86653a1de219bd1b91bd8d4a5381ba2bc3c3d769f45aebf1947ee68381ea2040577d45830000000000000000000000000000000000f6d5bdfa4886b16d98f5897b7e412f97e70b39dfd321ed77d479b4cf25e0b5408849fc84235147045007fe8f2156280000000000000000000000000000000003ff23b6c8fc42e3468b257f47efda211668e1ed644c84fba15ce61865bec4011d31e265f94cd04874672428dd94ed551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009effd5f8f5fdda8ac58c42773dffb2255deb9419189648d53f0aa9319f4441c63f9d2649cd3749b82158ff82c48e38c000000000000000000000000000000001356a417895f0e899cf6d330cd0a01db2a8459875dd5073b543c6560dda3cb54b40a5c25f5c15625a4272372d5393023000000000000000000000000000000001405b823df7a69d75f6af34f2cd076eb31a1fbd1a4c4a10b39c5fba46c12b30192dba27c2de47d05344ad496943449c300000000000000000000000000000000078be554c6a065c3c59f9917fe385f5c39bcab66055e4135772b118ae2fba3d5f8b5fb666e35fddded938d9276df04f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019208e29540af53fd32c26fb49ca26b0155610640e03857d8c21e97dd4431cea4adecfa3f94c0ce553de59f1be6664b0000000000000000000000000000000000eea9748af1282cc6922a74cb2907d0f81c112fa61a72b26511cd6cf0f561cce86024cb01f19a1287db4487d392e521c0000000000000000000000000000000002644d56f62dfda92dad99b6557441ec0d4afe5017aabdaf2dc536da0543daacea116ca569ca9c2f37d1472d6c05356a0000000000000000000000000000000000fc515a41dcad4ec5449f73889b9f8d6e3e2dccf73d6af8185987ec0b90953b0c2462dfe64ace2c4e777b704ea321a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007729f8bad404e2e6a20a28dc74d3b6c5c858c287db8e02469e606727d217a260502227dc6b3f5285fdc309f567d2cde00000000000000000000000000000000094332e237f3ee7fbe59b0d7bb355027534b6e6c48fbda8ff4567d336e378866c90e63db33dc411b37c29c84d02abdf700000000000000000000000000000000163336bb5c54f1d4e1ef4f4c8362dacd23a11c3c17456b5b303f749706194ccf15f716a17aac2a42cd187a0dc034c689000000000000000000000000000000000880af8fcbf82fa6054a320b3254df62c3af5760eb5c3498c5a91a44fa323ef0edbb76a8f8bdb98291ba7e9336f0f7231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093182555767eb1933e7f13d4dcca5bead5439c9dd9cd37204ca5079b33bb495bc120552c70fb3202948b5a5a64bc503000000000000000000000000000000001964d32269e0cf5d2aa0e87dacaca0eaf6dcd599d77e39dbb2f0b4623cf95a65a1582e614e85ec5672223753fa345565000000000000000000000000000000000006bfcb0003556f8b521b8d68346cc3d38596da9bf65af64d9dc2dfb4c5c32eaf0d403ce5fae467cb6708cec2bf62e600000000000000000000000000000000053f15ba0aec62869086b6d059a00e1b9c667706c4e3ea50fa2504e5965b3d0629d3d2efeef952f65ed8fa0bb14e278e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012781c6d5af21010d9df03577568e44b3fc9522152d75207a10ba055d1867d1ad81892d4ad6029630b755aa8f32e98a700000000000000000000000000000000012b14e871ca77c2ca89f1a833d277ff4ac297391414b8515fd2f5a25b04f84f03fc32e6cf2c1a7d2b4fe278e1e4a992000000000000000000000000000000000eeca068888ec6c2708e8ea65adb016b48ab6f4a0803f75fc8fd8c6daeb2ba7e38d773d2de2834dcab7115d4ce6c875e0000000000000000000000000000000001271e62542135fb74cde88f9bd8cfb559af51ae1d1ba8e0aaaab010051a6d1964fc21e818a14d5c54a39290ef0c60c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000088d7158364a1e18738d292efba065a3ba87eae7ea9ad1f39516a848d8657dd2bbdd51d4e04561f3711c46d28788f77300000000000000000000000000000000188121891681db0bd2f50d940f649b88ca6ff65b245a0bf5813262db8cfc5776c48629adf71370d9209a87799ebbb90a0000000000000000000000000000000013fb1f9c9c9700617568eeac2f224313fb6c4f6b51aa2debc4a8633e7315386091cb1f23208629a1a71acc71f7bbb77d000000000000000000000000000000001215edb100384734710f8c4c1638ee02820075e93fe359c0acc8fc008822fee0cb83487b486c636d6e9251855b8d491e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d92394bd48d316c86b5e12acf36d408bc345433fe8e10f761ebe4482d1f2a6c9c4530ee51d24e2c6fab5b483b43522c0000000000000000000000000000000018ea43458a75a40c39e041bdeeff36a9871c79fe2f23fc9760c5c30724f6eabbf133d34f817f6305160af9175ba87e0000000000000000000000000000000000038766b05933250a640535b161e7a2331f02eb43eee1423fa8e0e6e0aed58075547e5c6b4168466c700be9c9df22d6d2000000000000000000000000000000001614624332ee3ef2568abcfa71169db6dad3b6d0d04e1dce911b1d6de41922ff688d41e8ac3f78c991483d2b527b43421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004101196603ebd4ccf814d17c48a7536067a5df6cd845289ed861a95732b3ea7cfc6c429dfe1e6ea60095bf61e8f699600000000000000000000000000000000045fddffefd82b8023c0166b571b39ea192dd2ce113685a744d22d61383565cf1117ab311a507889b79e8e8fd8e25e480000000000000000000000000000000001db1ba2a8c43da35268eb174d3d9ab3532f3a37594161fdf2e7daf42431d5aea1dbca463bcd35b82a13fdb4b06be7e30000000000000000000000000000000014c45103a5dcd1696a2df687d235bfc17e35a907c3a28c789da44c02453dd690879709c9b9e4b7046c446e9dc4560fc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eab0e4f82c02f0c8ed3dc09ff105cdf8995f512bd321619c6850e35af1b2f0d0d68765f69b1f797f371d051610a189700000000000000000000000000000000057ca23796e4821fe58a5422c546f16c7c6e30c638d0de046d90f2e36e3ca6fa3bf77d5e3b420b5b73b7e9feb0b30c5e000000000000000000000000000000001948178580392a71683b2853416e187c48603033cdd3c8f0f525d3583efca121616b018e1b582b87cb8490a36c9121d00000000000000000000000000000000018dd06b4ebebfb3e97b07ca4eebdad9864021748ce3eaf95222e379f52dd6ab747f398455e306dcd0bdd41f26dfd03031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de9acbfd8f3516f5ba689950f40c97da6797387e8bfa16a97f0d549980e8786d3543f42ce3ecc54aaa4ce63f2a0a7ca000000000000000000000000000000001788fa49c930163850f2350b64fd1a42c217bb27cdf3be7f8d524698c8c18e20c9488c218afa8cf01de88b908315c10200000000000000000000000000000000093b672f370f43a47054c01d361e894e609922d2b6651c57ba7058c85a98a3b420833c265224454e625ee78c33f6c413000000000000000000000000000000000f9cda8b9316cc24542aaa54d2d0419cbf1353e14d49515192ebd77c3d7c20828a3453cc94ddba792d4579450b0eebc61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c355bbdff9ed673c80e79d64502109c1512648d71df0f01295e0611d705e405333967ee20856bf982b9463e625b0f10000000000000000000000000000000001535314b0dd4c3b3a597e552907af0f3976fcd65ddcdff390f71f46a8b9dfdedae6c84d8bb12ee83e22d31423f46c960000000000000000000000000000000016f7a039ee125b9a817abe9ec3efbdf46eacd1d1ec08def6ac458fe75644cd24945e74f2d85d3ec6221b5137a36f84350000000000000000000000000000000017e4911a30c85b4f0e993d9f94592cb5c560b0b2ac07283ea98ee3dd6b0318f965ffb1ddfc63abbe0e20c742bc2373731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014367eb296182917dcb756c6b987828798b308cf337d62941ecc1723b85572590175561a7c8f9d8af94273ff99ddba060000000000000000000000000000000009dec83d228d922215a70c50863993a02e99477b1bb0ad898d234af5a9f6b01d888acddeeec2002942b9939122961d7d0000000000000000000000000000000002f633bc90b897c01dfb41bf97652bcff9ee0a1ac57cc5b2d0ca2cbb806dc7eccd29ffc65a675980aad07c8682b3b775000000000000000000000000000000001205cdd1e8f1e74196f0570b078d9c8acfe49f842e0ebc9f8e6e41fab68c26e12aa8ba216d53fee71fa5dc61fac857b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001623a0433b16555d5bc9a004f8c63d5a09d93a78b05ea0264163e8e71de36c66f5900e33506039d99c62ffd051f0dcc70000000000000000000000000000000017963710245fb9e5e8181c66669d4e3f014bb4a637059b26d9a75019f96153dac17b0c663b1d65a4fee6c30e1b80a909000000000000000000000000000000000e21598e5d0c708ec6ec9856fa9afdc6a1dd0133dc9ca1233f739cb1cdba82d5b592e066773c295028279cdfb4dd6d440000000000000000000000000000000004c418427684be1ddcc1ece492b7cf8819c0d3a3ce9d8af1598e0e4b90a24aea3a840b1e7d83de581d15af61a37937b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151637fc0e6878455bb3412da853ab64b0bdd5ce4d247a4b4832c4f4f6c9711ada3f768a27657acb2ec20bac48b278860000000000000000000000000000000015ec9843feb757e81394b8cfdfe6a75f7750fa20b2f307ecba703844ca942cfe789377dcf121e50165264c9e2c72504400000000000000000000000000000000022eccbb8538d28a2b8a624e4326dfc389584d8cd5c3045168b8e5b92fdd5f54a2aba937e25ad51efaeac582465e2c550000000000000000000000000000000010db36d0c7131e033e7583d5fd10b4a87f46385c6422f731303687581cba08accef0d8a5c5d8474f8bb32ea79ec45aee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001977a828aa8ae4737760e4b64e927e75742569825a08d78020eb2ffc85cd189411db95dd838c0cec4850d885b36f6b62000000000000000000000000000000000f7ae64558472c653e9ec0eae5a54078c9d2d3c6569f271cf85ffded2b3366abfcff5add8788948e53c2a4d6d2a2f45000000000000000000000000000000000000efb4fe6e3f12150c2f4478f58c572694f92d8c848c1f3d91b248422228bb9e2311fd1b2d3258c0105d5ba01fdf13c0000000000000000000000000000000019cee947468f86c679255f5f27b5dd69749f4b91b370cc15a159c85b8a469dbe52c8c6d13c0db317db617dc069f351cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198affafb3831c650fe14f2c87e375608e44452ad1117b766807c1de93421a969af08aadfd194c6c51534fa5b394ba6700000000000000000000000000000000125ac71b75ee42bd44a3d45d58c1c4a36fee4b98e5d2049ec6373b5a26a76b28c2dbe48626882493ce4c67ee39121fb1000000000000000000000000000000000cd0ee18860807d8e8e6584f64f53633f691343d9726b4b7f995c25c49d2caf276e2b999c2856d9370454f63cefa2d88000000000000000000000000000000000b0316d713a7f948687843a4a034f11dddea2dcfd5529eb88bf94c0c94608b444b126e25007835080c27ac9ec3c9abe91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ebc7e5f0f9074bb38f8588f189c5bf8485dcb8c8bc8857ed467c7c49e2b9e850b852dbe04ad0c5521c3a09dcb29113000000000000000000000000000000000943acb721210decd22eca5e020ab9300d503b5c36f50d689b9b73c8f31f88ed415bf4e4f1644a643aad52d8a930e0f30000000000000000000000000000000000f15253c7895b4c261987586c69ce860c11052acf3f63fc02d29eb9342ebd84e1508fbbdeb420a9d731a58488d0684b0000000000000000000000000000000013b7ca2d77a1c38d7108c179770298ec3fb978129b4aa9a93f4edd5c614f38dce233f72b20dec0ee3669cc36570dd4651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ecbc2314630e9bc001b99efa8b29eb494f2ad3072ef750b6b3a7db18705965ea40ecbcf4590830cfc522aee67fc4f60000000000000000000000000000000006cff352d6ee367eca73b0447e5a5a895dc9ede9ffc2afe6c109514bbcd90fd4ad767917a018e0682952cafbe72794840000000000000000000000000000000016752aaca020a534d2032065db44e6a2b01e13a53816fe332b7fdd2a85f77481fb052d29829519967d4c1d965480458e000000000000000000000000000000001884dd42206f54aabb2bf8f47d1f926b5ba2415434dec1799ae94c0d336c8be0055d83af25fda1dae00079826a39d9c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033cbe5e6f424886dd87787a5b7a7e02a57f2e05c38dccb1f688b44513882601610f43f457c680d646d0f7f95238bcc600000000000000000000000000000000033ba3f62d8108c6e8b7a8c7204b7801f703a8cadaef024b78ce3b4bcad766211d2508d8e4bdbbc7867bf48b533ca8c9000000000000000000000000000000000967b1c01b12d9674dede0ea2f0c046397d0df2e0d992c87a912e441ff165b516256854b059f464fc80bd9d26cee0cc900000000000000000000000000000000078157ac9967d21c88b0ee816f006b3ebb54e8c7e975fce8f1f09a5ffb5e65b78167f1c599479bf31793ddbff6a7b4341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017376f10006af96071a4b3f472a226edd81a2472deffb5cbd27862e726f3ef3b79387eb1615bcc647d7e6c35e60c39d50000000000000000000000000000000005c13ad000e2ca030dd0acd6edca973e6835f5882fb50ca4e117830005419ee42502dd83c8ea3a08779128442218665800000000000000000000000000000000078242c3b98ea9a6b4efad294381aaff208f7170419005fa6c90791cbc371801e993081b5273d5d7a5824e3a48fd0d4c0000000000000000000000000000000008165587b2f3d6c729a84d225f66fd5d19a751889d686509ac397afda27b8a1e97dfd89eac60d649f8724e17370fd89f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b93119ccd3d7ec4438405ee44c98a26e7dd98049cd42fdb0b3f33dd27002471f966e6c64f75d6c2472556692c9f2d9b000000000000000000000000000000001801a069866f02555d4a5cc624dc2ddb8a496a2c5cfcd97c1cdb6a3f412e39f81437855c1cdaba353ad71a0dc5b8529f000000000000000000000000000000000ea85af9d5e266be36cbb8536025ad2cb852d065e5009a02e15b59f24b8418654b47661c591548f16056801235f380050000000000000000000000000000000000aaca07b3991ee68c91354052523e8e005bbf97ab9a5a0d4962b7310590347a2aa2f8ae66b04f64fa637af2085009971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000851040dc774acc6429188ccf5ff419e737383ce231c8afd990a061a1f4f25052acb287f31fc204e11c8ecb43b197149000000000000000000000000000000000cd1d0a5198f5763f1f75aef19633f8cc145cad79dea6a738a517554fab881663c31b61673f7e0481c15a082fb534b13000000000000000000000000000000000cd876970e1bb865f9991bdfcbbba9429768ebbdd27a693fd8da8b04d17ceb822bbae9b6121a69f59ff0d0c262a659ea000000000000000000000000000000000d432cfbfd8a3f3879c6277b50079d137c9b1e93a2207a21d2d6cc682cba9e9477886e24dc23e666feb2523d0b4530161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018f46989c80f9e161fb24141626a204502036e8f30f5d0f72c0167da9e52d28cb1fe99fbce5a7c8cbcca2c17d53293d0000000000000000000000000000000019641ff726ca947e96e7c607d0bfa8698910542ff9bee8926ab7e2f1b9561dca31a081bb84b699738c905d13f31c53d7000000000000000000000000000000000955c3ec513110766d11c00f5de5bd597b7d8c4968fd30e46600e92fa8117581ebf36f1b8040a22450581239b6d3b22a0000000000000000000000000000000009073fabdf52938925adaed1ab13185126bdf44b2e37f1487a59071ecfc1a3a38e4f6fdc654ec91c46cee2682db373e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5dc7fe04a3da23c66e9d27e602159907dd0bb7b2c9aa9f0a4c3fda1dce9ac96403b40b5f316d70bb8e2a94f54ddc9b00000000000000000000000000000000124eb710ea6ec67fbb1014302c6f01a63dcf53e66d48cdc9be5367777ecdd53d0ffc661dca8f3b40200d9fd0a289f38700000000000000000000000000000000178a403e49fac1a8dbf292f32ad0d05fc3f1308842e9ab0a861605f13260ed805c160b7df91b4aa2623c80f4fc7a1a87000000000000000000000000000000000bc2ef3dcbac9ebca3281f134394646aec6179923bddcd1a6c59959ded0fd3b694176b81b9f8b87aadd2f2cfe6a8031b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fb6a868a0302748e50445e7f01c08e4c635032c10e5313478489b01e18dc88b76415a9ee0fa617d29b200e35e5759d3000000000000000000000000000000000b30fc82e01dfee16c891f96980bf74613d93f7c3271efd99e9c7f120c08d7042bdde202fa63cd8423dc2c83eced25190000000000000000000000000000000013bb082127cc5ed19d50a8daaf95ee590e6b797afe6bf5e5a783d3c98351618c40504466d8a8f7bf7684b92b7b42be200000000000000000000000000000000008f2b843fed1baf1f0bde17036e6a03929e4a6f3a200ecb7d8133e4f06216ead55a074d8c913a9cc8f5be08333bdf5b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dab7bef886bc431677c5e31a8cb79d6b975df74a27f62722ff2ac715492a01eceb7c5261169518e3b42c33a6639a94700000000000000000000000000000000144cb81fa9051d520aadc390b183ae653677033b536792be194a161b088e0edaa1025d79b6cc038c253e90c8940cff430000000000000000000000000000000002fb9d2762b88be54ff0f1b5745bd121f3d46f5dc4452263ae881475a93f12f3360f2348010c75ad0e0ffc360acedce7000000000000000000000000000000000452a8ec8f7f8a99324fa831cc7ddd62dbdd899a60ddc60d066020159186f9a16a293e670bfdf2e9699a3825c78dedf81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d430638323adb96658df5c8eef5144616723bcecd595d904af14d5393e0bfccddd7a64bc8112918f5698426e3cb8e9000000000000000000000000000000000e73bc0cc8033d4ab206ebcaa815f3e8742cddfde5606738cb0045174a684cef5a195e12a3053b35f6c560315a2748e10000000000000000000000000000000005ffe4f98a97b8a32e6b85ee45b9e94bb53c7b5785c42beb3a902a0b0bcacfb2327fe54e38419e83da616487928cd5aa0000000000000000000000000000000018ec1d773274d2ed0d3101e6e64df2bc373e9edcd02d5dd267bc39f7094e7ab5b7fcad85b5392cdc41616017eadd8e2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085a30f8bcff54fc6f022049e57453215719371d9d12116efcb3fbefbf3848d11ddd66c5855e77db578712d64994fb30000000000000000000000000000000000219a5512287c37ee7865e1f6a5ea2c6d9d24cae15f3f6bb4eb9e9d31bbc23f7a22f43738b686cc66f0762ce975461a60000000000000000000000000000000004602db3bf19b1c8c3491f3f13e171760dbaa2b27b2f999f8cb0d9da6dd3de4a61de6eaa02976dcdc7970498fcba56e0000000000000000000000000000000000de25216f1ec24a522d8581e76714459eb00f09167cdc9e29ae5391fae174ea7cdb4ef3d77ecaf253025d4dc3a02d4d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123009a43a0e3b3344604072fc6388b7cd9f551fb099042d5993fa18a479c7604653dcdd797b2a99b6c5b3fe833225a10000000000000000000000000000000013fffdcbe27be0fe1abed71f6c84695297b1e291cdb9ccecc7f366089bfb0d55c19c195eecb851ede8aaaf39b877f19800000000000000000000000000000000096d505aef28676375c5a5ad3293b6b97ce14dee8007013236dd46c9e0a06ce233936ca8039ab8eae72b749981c36ade00000000000000000000000000000000070e653ac0b803173cb7c853051edff065d8220623deb0adb1f5e06f0c5e17f80a3d45ac2967ef7cde0d9823c2cbd6b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e82dea70048e69cab078fc84834333d66734378650e8a1c90dc937b96f3ddcad0ac0a3eec46d5f52d39e31ddaf92ed00000000000000000000000000000000147c359e258a21832c6f448ec55181d1e5be3901dd3285ac509b2412089b1205295a37092755afe5ca1e9ed007cc064800000000000000000000000000000000155ca4c17a0bc1185492bd07749fccd379cccbefa83a1ab39aa688979dcf5546131d6e85444e0e016491b98eb9c26294000000000000000000000000000000000f92027a6c93ce54bfafe5c2e0312dec1adc14ca81415c6381457ec060efbddef5443c09af2a0f4e20a55b2747ceb4b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000add85a0ce098de0eb4ded550a51c56c2012a7a1998a61fb1c81d5f10182af726fdef1d4f5fd115441efb165e351fb8000000000000000000000000000000000db192936f4bab12411a2fecdaf1ae59917c7c89a3e86cae197d673137223e223869661055dbaec359939297a9cd300c0000000000000000000000000000000008642a35845ed8971b5de3fbab667c8f711c7619af107f0e3ef0a70c9d7e2cb802a4a2d5028bfb5d3b6eef5d6457506f00000000000000000000000000000000128003aeccfb8a57d70c8fe3c5a182dd8b6e6a14860073f75848a844c0c6dd3d8005f3a040c05b74b6be14c59d4775c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090c48f656bd1f6196a7d2d3e64efcfffbbe5b6b7c6ca3e696416284c1aa8fb0cc63be6f4b963008dba83fcc61bdeb42000000000000000000000000000000000c1946b6a22772a27175332c503aa0d9cab20a794962a5110c6b8428da6b1ab65688c49b34de1a5a38013dfd86cb447d000000000000000000000000000000000f77aef75261f71eb7ec6bf5a8180b1c877bcbc8b999fcb7c75327756a28c19079c652d09cf82c77340296c8dc03142d0000000000000000000000000000000011d14bf0de1bd33abdcffa34a2d3f0d3f0e4011d9e3a147b937b0f4ca4bc2acfe1c440933b5dfbed8dd08f4969bc34631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000029b8bedddfac00eedc59ece1be9fcb8909c69f3e9b41b75658c7aab829a80c42aa6a43e78d0e819bc2805b12c08b1d8000000000000000000000000000000000b61d7edc11a58bfdf0c270595979d8dd522412eccfc63c247a98bc8d9c7539ab45fd46e41d50cdd35ca6d835e4071db000000000000000000000000000000000d629048427119a0a320ebd42f0c7eab263b1e344b41ac8ce01c7417a6846019a23267b02d70720da0b07183597e0a690000000000000000000000000000000006eb8c206929fb08b0be2760974ac71e31f2493af0c05595e4ab6487650a0447bb00fb437af29beb9c0529a18c901e501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105584388cd1aae21d6e541527de075dd6fbedaddd63071c0c244b0bc26ec8e58f1f65041ffbceb0cd5f094ce409105b000000000000000000000000000000000bafefc99e5a7a61cd3921bae2a47af5abc231ddc65027451ad800e3a57a3a2cda972c2a93f517222fe8cca56036960f00000000000000000000000000000000174187d745e3714e1c65a666a39df1c783eee92dba03fb0c9abd0df2a19a6a246ecbfc3b3787775a32ef36fd3bf7d22f00000000000000000000000000000000168bafb285d57b82bda2883d2eb7f8af2941ca337ca05474226c2c33f451f00a2932abe2824747673ef6f90c8b3a1be91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145f65a72fe59d45099900953dc949731278a0a01189d29a44bbbd59a3c65fe16e7e430cd6663ea2a31a29001b04b6a6000000000000000000000000000000000409c5e09e71d5ab19776e27d7077c7a004df2ee215502907730ee93d812e5829a791e39bbfb4c7532c4e775552ea3a8000000000000000000000000000000000645040cbe1ab018ccd42becd0d6136a30b5bd06a1847e07484091d06d031e93d410fbd8ad3a09594a42908ce487bd720000000000000000000000000000000003589d8389f2e3b8487d38c77cb3ad89bf8183ae51ee612e64a1685c52fec1434166bc8054d2bc5d8b796cf8999f7aa61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105042e46e6d772f7bf84ccdac8e78a913af633e84d9a68a5ce17900c81cc15f29728acafe208cd9a5314f55ff9af315000000000000000000000000000000000230ff3ae2c883676821b6f2b495c9b510a0d33f4fd6e7144ecef2ba4567091c0de942554692e2898af380c21fa2740800000000000000000000000000000000163b964f735ff1a904613177e494e2c1455e2ba2fabeaf7ca8327ef26770a9855587cc08e2d883104babe65ae244584e0000000000000000000000000000000001f9790483298ad8208f86307ceba8edad75c002bedb5d17520993facdcace6ab8b628d48033782889cad91fccab2cda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000109169e02a4de15fde8ac561dac1c5b20270f7e5efbfe2ccd01cf89a12b466e6ed5a4c3e3dbdba3f8a239f844ae8b37100000000000000000000000000000000142bad8573fb25cd4546ee6491941f732f9173c5ab8cee1646a15eee54785629b9c77b14d77c511522f47820735b7340000000000000000000000000000000000f44cc1a8e05be65e79c326d57210f22093ad14f8cf8a829f41b18cc3429773db8dfdac8589b020e1dfec5a2044cffe60000000000000000000000000000000009c82a449a746fafbd3da8c11527c7de14a65d21179323aecbff344f343b106b69bb566bc38e9115244959d99464ea751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005c7e8ab8044d4d32f086b5a028afa5fff9f4e90a8d6cc5016a179f2a35229a6bbad2f3404092447d4c0779d2216fa700000000000000000000000000000000002b5f26901362b209ddfc3bfae8532ec0079f702e3ee6036d83659fbbd6b326bad7dfda1f4fd5efa38372dc3f7399710000000000000000000000000000000001dfd3ec528b8c1e6b875ee6498a1dc7cdbe81fc0acb739a7af033b992d8d1af5c3dfa4138953004dcc876c62e34cc320000000000000000000000000000000005243fc4f50f736dbfbb774c1d5017899d381a77db3708ec10bcd83c629bd447f7037dc2af119b4897db28d6523066111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa48986ccd24a3bb0f06890d2048c34e411cccbbc46368321e56ce2e5b5278cf1c40fc1d6fb6d7b1bbc03f0317faab100000000000000000000000000000000176889454bfe883b43f13bf76c297f45a28a480c84f2b1cf28b34136cf848dfce900800232907b7826583403e82162360000000000000000000000000000000010e2469f64c7d0e8cad10ffc275a0a34166f1a1c8cec08663fe8be79d134271ef9575dac4dc7173f4b7842d405206d910000000000000000000000000000000013e3d0599a97ee929f5eaaa32545517f243a0d68852d4c5cd971e51a7e3584af3c3f8b96178970318d9f1cb4e0acbd9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001a000c96bbf648b42dd699ad7d4d69aff4916dff43aca6b157475697e8998f30010c08dde8fa283756d111827ae4e9c10000000000000000000000000000000007cc985dd9746b0e7acbd0e154231a023e1d6c8be69d468f6775d98d39eb38d3a85ba688e464078002f4d416be47bc5c0000000000000000000000000000000001862e5eaaa9becd72101e827f69dfe3de747857f951d7e2cb2f2c36365bbe2fd16c7520732abe213bb4089b601643ed00000000000000000000000000000000172f379a49a6fc3a8fbb546c83a4ab5361b372b82239c47730c8b69199c5ecd78cc99d6a1190726882e8f130df6af1291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001081bdf9e4b488c9b8fd26aecdcd75693693291c9ee22e20ff2be9a590c4dd4594de5ab96afce3eacf425a3a65651a2700000000000000000000000000000000025a6dc3e32a537fb29f717f818a3abc48ea43f0213b81292cee0400020b494f4710a3ea1136769260e4e7f458ba8c53000000000000000000000000000000000b6d992714594214c4a787485432d95794937717fdc301b177b7b147b43fbf6683fe517859303c1400277d8739dcd38d0000000000000000000000000000000014e6e298319ba0c8baec5a1a822a5573fb8145766fbb4684ba28fdec64943c5a962249ea60b0f3d3dda74812511c39261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001430ad4101ca9ace7553a6ead4e79942fe6d845af8f9e754dbb061eb347d18699b78e54d9a12572d6887998ae17815af000000000000000000000000000000001658800d9decb68cebdc024162f5bb768913a359707852cc96d3d52fc51a232e69626b4f1ce59dde7e2223d6379797cf0000000000000000000000000000000004dc67c66e234fe6671962574f6abe3bfb882c43c539029dc7c1fcd030cf47488463ea8cb58a79954b610e796a596bba0000000000000000000000000000000008d07b04b5d0869f161d1c28a5821b18be7f6d466bfa5ad39d0f098bccd562ac1c258ea3f69ef669bae6a897d3ed98611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f45b8d66ebda8efc12977b7751b5148eeee6742e0570bd1bb4ca772dec9eb1e8a59d50a8c1d8f8b22d062251121cab00000000000000000000000000000000102310fd67a768276f77edfa1616b637a7d4ef4459432b5fdcb0e16a2c8cdf6d8a555f826e4b17769026d7697e73ed4c000000000000000000000000000000000596e7e092fb81548f327349e2a57f76e115ba228035d74cd5841b5ad416f70c3d15e13c6ebdb61a751cff0a9c8944a2000000000000000000000000000000000fb8d9e3c8983a79399db179b7026cd4ef57b7be17c206b841ba1fb2296c8ce59b10fc78e01075668142cc0cd5c13a1d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148c755c34f146bf8333b7dbcd39a315ae441a5f361149aad25d0a655efedfc3d493563a08f389999cde5f24ec30f401000000000000000000000000000000000ff0e24e95f26f28e27e2c01abbec9c5f0e76d327cc0afb3a818651e5664d51d69328c604397cf52547a7d6f101f0122000000000000000000000000000000000615bec32a13443f559ab2741b214c9110d45334178c5d05ddfbc769b81fdd259b56071e46940be99f0865533c153e9f0000000000000000000000000000000010c1fa0ff538b11ca3a4edc058dd0d792d875dc40286eab78118c6f038b6afefd69e0e2fa9eb2f7feb06bf379862f73d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000046bcdb532cc7b8cbab9f1dffb6a638b87605d4720f1077389fb5905dde94a29a180ab4435d80d044594c4290ffd4242000000000000000000000000000000000c5c7fcaa3956c2de88288bb7edbfd44a79bb275a449e2ca6c81f26b1482523bf4fc0209ab1969d4f602f2fe189d3fad00000000000000000000000000000000183596269a830feb8a7f7a7260a642fa2a85727b7d852f90cea8e00e42d386f316004fd7f66944336e7658c8cd7d98b500000000000000000000000000000000007c885a86c7134888a7fb4626dd541059e2260ac20d24088e48b1a1997ea5a126b18fc2834795a173df453c40c6c6fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a38aaad5302e51e3b27be1eaafb13784cf8845401defa2ed27ea258f736fc569cc73e883a221712eb6cd64bbce4da2f0000000000000000000000000000000014f30c9f023fbd7c3a03c3b181d5f735c1313f618064ff941cdedb8371eaa728da8629482c76bb0a8eb411a15393211f00000000000000000000000000000000197a1fe4138aa14b24e598d9c9a4803298ac8acc83612c49aae28ea4eacd980a9f296e34d688302b449d49d2068e42a2000000000000000000000000000000000f3c079216373162bffe8b6c0eff1c620522132f5ba5d474c6d8da65a80797a4322b0a1f4efd80f32300f958a9f2078c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000019e29eeea6c85f41d82170b5a75b1f29fd7fe644df25ea8059a59eeaef6c2a2b38acd6938bcda7971b9753a51a4ae5800000000000000000000000000000000141b54a97c05727802988800cab93e73a3c07acea689e59f1c78e9595373a18d0ec2ea25153bee79bfe4c85958251895000000000000000000000000000000000d800d19c38dbe4f331ef7943b364f6af74e8ee0fbe9096e6fdeafb1f44d869ea843d12c90513026d00d326d66c631130000000000000000000000000000000016db97696bbf0e7398ac0e5444b3d0b3560e417d98aee6247a7125f8d264c1221f1931c7cbaf203792059ffcbe20e5ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e3ce33f11b07dc24a81884fecfd81fc720fc64208a72c79789d8d8f7e85cf239c9d01ca0171bc86a5a6655352a84550000000000000000000000000000000010fa5752db91a6812c9d5e1516e96960eea13d87de2a2a2deb85406fa0c61674758e20d7f5e853fdc2f6042d6555db10000000000000000000000000000000001971834c587a1db1fdf56ee8a359936539393873b886b7d13e55f50211677662e10d073a085e3c92f7091c6d6a007ad6000000000000000000000000000000001848d32240b36992a04236fec35b28ce57d05da145bbc5286638e2c94c9b3ffa21b0fc2c4a1c7deccaf0e2356808746e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180e90e534c01cf113e326051fd249741419269676495603accc7d774745f76798ae8b038313013143d04bb91d93bc9c0000000000000000000000000000000016b7f4897c1c6a52d57927d6aef5ef20d71bf14ba05509ed91611fd47a945d688e7bc07e181562d6c771dcdf62f58a3e000000000000000000000000000000000b189795e59ffcbf38766b70fdbc008b66e4123367f671b2c281ab3b0daad4f3395f8fada834a4837fdfab87a3c84c030000000000000000000000000000000004b903721cce4e2608ad9b4c76104f78992be9b51814a45cc67ecf26182922f100f79366d1f138a990c36cb24c73736d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053b2b2fcbe1e1f21c8975a50490944a2ec002eae2a3787fe1a5f2407e748eeaccb71ec9253ae5baab99bba68244320c000000000000000000000000000000000324e2be2500d713e3d7024e17bf7264b32d4682b9a2260908e136524b21898d13bbbdebe9c0b114b60d3865dcd3e3b50000000000000000000000000000000011555094fe075c812a9bdb67cce6e5276bdd9aa2cd47e08eda8caf27c64fbac993e783a67d4215829361a3d9bc08aeed000000000000000000000000000000000da6bb32156d43fda1e03c4f570507d96a5cfcabd1d06f2ef3e044b338d9fc647b6940d714ec6b6f5bd53cb9813a358f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000152f5e3a4c553685322ca904c7240655c2478d16e1b6d6f0303f1afab9612bb120f52d4cb7730f9a213b6f8c9f70c7e0000000000000000000000000000000005acee9da915ef5d8281ef1713d841a89be846c6a607be3209b49200076f65620c7adc6aa87dba17893261984726bc330000000000000000000000000000000008c4dc3c0fa77bfe29c060d1daa759750de6cc9aff97ebe81c8ffd10be465e7e57b39f1a545ba2f896166d99d38978bc000000000000000000000000000000000a980e08cec0f3a8bef83b9d46095a4081004ace5b70d28cc9cd478c91c50c55cc0220387ec906d28cab94edc821363e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017aa0a980b24c369c3ed66332ee85ead185c25034bb37c58e922e88c64773a431aa3356e8ec7f13960a187c7fdaf4f5c0000000000000000000000000000000013b303817316f19776a4f65b2f6150c484ed5583e0903826fdcdb1ec9dce7da1152462571047eb72b47f483d0632bf6500000000000000000000000000000000174ff23320c45150a950deacf5594b71bfc471b1a9ab2d67763402981110150c2f493e9aea5be1df0f951bf31869f172000000000000000000000000000000000a888193e3158791133bfefe0cb68384a69d180335f9af7d0d7143b072c4bbcbe48e97e5d6658501528df20ff83cc57a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d000c0eb1c1c952486478e2b81126b7b26cfb363451577dbabd7e47f7f834f04c47f90c74dbca9981f97105344db3fb000000000000000000000000000000000357a4e86818a660887d1a8ccb026bd45af74e1261fa4f8666d3d7ce1bcac676b213809d8b1be7619fd5cc54167703750000000000000000000000000000000003e78b2f2495ee9ab2a58f7f699aa7dfa11625ea57e3b8b89bf6e8474fd1b148aeca27e2bdf3aa77eb1803ac8469f1a9000000000000000000000000000000000da0111d3255fcdc941c72d1f099a8412982436be5414301c421fad34cf9fd8d55c79753619e229af030471d912cd1391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ef489090ce97b1f2e868153ffdf92bf8bfc451b14162bdf902ee74afc7ab25764fbca0709aaae47d74cd67e1d1be4b0000000000000000000000000000000003f4c7c3215125bfd2e01f214c32f2cd64331d0f6c0b46910455085162f9e1e1bc66c1d6e3bcd76e549ffe011fc85450000000000000000000000000000000000669ee967d4003f1691044306501b978aca86121c68cea892a924bb97bfc47fdb009047d43863fdeec4ab658c8024bc10000000000000000000000000000000012c0a7cfa7b1ee48bcc268dc596cc4be3c2c71083b24ebd2c3f29a5cb107fd5032a30a56f245238b01953d7c6793b9921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f807cdb1c92baa906a37d23688c0ac08754ff42915eb1fb1454efcac3180e2d57f769fed53ecc31c4865f831428e55d0000000000000000000000000000000008857250dde17e3a4147401995094a9d2a24590f6933aad466415f99c8d61e96ba464e39a6125dd27e92c0d615c77c350000000000000000000000000000000015a47094a686dc357e11cae38b9faeb3d1fed87795202df0080637f965aa871f407192615d519ca464ce0b37267c25200000000000000000000000000000000003a29b4a8a846e17ff0cb1df24e74f7513ad04bc9c6f84c0edd0eddd55ef86649ca331367aade80f6276e3b9593c23651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001585c9a3e0c3a1b302a8e09748a920602163e80a26a57ff15c3460518a348d2f5094ce317904945bb24b875e63ae5b1d000000000000000000000000000000000647dbb0060242d09ecbae5e1b9107bf1884de18641e3c70a4dec87fba584655f282497f5084ac3205a6a236d626d85f000000000000000000000000000000000b7c15137c7e6e9e0a6141f184e8343a75d578cc6408d476d0f7697bd0b054d52344fc30c3592c74f02bb378dcdf58be000000000000000000000000000000000120056c5750ea8c09d04fd86ff12650c95a5f5e35fd76ad46e12d78cbb90c3a2fe65f771e6f4363139577b72401daa51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136fae3065a9a2b332b9ba939d3c861adb4ac28f2cfc9a6774805abaf0f70f2ba8bf74d9423762bea089c0b53f64fe87000000000000000000000000000000001331b5b2817da4c8d91ad601149be8a7a5dadbf91d3c364e71ccb6f33a0bd6206bb53f1ad8b7b8778612efacae6751d00000000000000000000000000000000016f9dbabb5810c09e6b66f4fcf40200c7c59919bb96ee4b5ef5de2e85c3314ce189c5ff67285ce4b2b9cd454abf05a8b000000000000000000000000000000000d029d622e6abff6e6b649da12699f3a66de04a3db4445bf83297fa98372c4dc6ed3854a4b80c3bf89e6edde8a024e3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001050a610075da9409c58677b537b3f7fe35937c567fc8ccfdec23097400e2524188dd29a04e651057de01a4f9805084a00000000000000000000000000000000071a18a44b5725b9a67b1fefa7f1a5bbb68efc4a140ad732ff22f2988b0bb5492328beed88a61b25d3a8659186fa1cee0000000000000000000000000000000001f1da005f03b5e93097fe264e84ee6f9e78626ff9e7e9fb87ef0929e92d866fa92ee41f32f87308abd1c289cf67a2170000000000000000000000000000000003ba117ac29758582a66279d8d36e7ed06c830220eeeff06a6353d7d863805e53562c9aa0ae78a16cb37c54ed92b00661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc7d4095871586f1232fc3a1ba9d17639d08a4e0994b748122c0789c6e8ce9750ac50a3573ade3fae607671bbab6fcf00000000000000000000000000000000167346d1b6bbb3c8f969f4e57f4414e4bf22b583b228290cb0e48cc29b1894f6f07081b1d33dbcf0c9583720a5137f7600000000000000000000000000000000104a7e4713995de51dd913cbf88afcb00b6c120fdd9bf76af55423b682e51239855b4b3094147ab925f716f52af26ef5000000000000000000000000000000000e8264d23311028798624c0ac5a4195cf16d220682fd07e603bfe40a22e7ba68b6e7e74fc73785fd78f57129917d6edd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184817d1ee6df137aa76d8283c613f7a0b520414bd04f696517dfb543e493abe60f57203072eef76f8e444a261449b4100000000000000000000000000000000151e7f51922d0c0089c2a0b86e1906773b63eb385b8930be938061716cca9eb011dbd78e333e0acc3ce96bf400b1a21e0000000000000000000000000000000001ba1f2610d99c896ef6888748ac80e6f154d50dd4d719a48b58403549eab6834d1c719fc79664d3afc490a585750d80000000000000000000000000000000000faf8a7543818cdaa68478b81be8dca24c92b60023c38638483dd2e3c8f5ed5de8f41503570ece693b2a39fd274ec5411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048995f6d9dd8a63c0e0c77509a56e0f1a8b4fc4544f82b59eecb4e682eb09866cae72c33b822c817e83253b1400e51e0000000000000000000000000000000010fb277cda05480c9f366a020c6a86691c0c2d4b25c4383a615a43dfc3c8029d3dcb34042732de5c359107d003c5173000000000000000000000000000000000104d8087aa849ce076ba721ce7b0dd74643311fff2dc9738da9788c8d5576a0a42796992555c4c219498dfb0085e09dd00000000000000000000000000000000187dc6e5b87bae5210ebbcd365fdc9a6dcd2e8cd0f8592f652cfeb88b037abf9359e231e4df32890c82d41babdfa84641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f103c0fce55208d3aa190db050a6bce9086245289306987304bc0cd8113b22788ba712de1ea9b07458eaec574bb67700000000000000000000000000000000092fc2bb031006cfcd801faea952757f7859fc111ca3e9da8be67f3c553836fe0955001b45d8b9478e8ca3d91b08119c000000000000000000000000000000000bb954c28fd36b42e85f951c9e0d1e1aacf96ac35e7e28c6f3c47bfdcb447d2df853955cc13761870a57bbddcf1924770000000000000000000000000000000001cb60101f1aa721e6252154448e541d5270c4758245eb8935bc45f3b5938a002a2e02c6732e0eefc6e7c96fa3579fc71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dab3920c3f53ddd302e395c2ee9dcffdccdb2d5281f85d8bdea2d0ba2cde652b37a2dafa180f329123b9fa6b8e83ec800000000000000000000000000000000056677bcf92d552494a17cb6fac3acf41cf6d90bf1c4a74f62d0f54a85a5845e4400e691193d2cd98012aa15bbece41a000000000000000000000000000000000c9e26ccf504ab0fa912b66625331ad5bc8b34bb322843eeb6a3047cf8e964801623b0f771a96b13dca419a003ca6de6000000000000000000000000000000000318c2279316ee0829ea06e96638da096f8056574a500920e39a8cc0194c48e38a51f1c15ff46709a385edec4b1c7da31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d34656742cf47c0a3b70cb106f8591852c6f607d8e2aa3a1ce8954e35d8eca7a98bef8ae9baeb5a19febcdfc66f9050000000000000000000000000000000003aff8954fde8205cd299108c76a9294ec6cdef3b6992ab3895e36ad7bf598c9f98d293918b281e5b864bae3f33849dd00000000000000000000000000000000148a55f0bea0e7757ce521bead33b750f1defc04a750ccc10a69897cd358838e981a11494ba7b6dfec8120f263bb106e0000000000000000000000000000000006d167670a7c8e34b040615a1081d6d80a857bdeddda6bbdc5e5a889937c8b370d1df5d7bcf902984ef858aa5be0ebdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040ebb87878fe33475aa8de8bae409a4722eb545185632ce865c0dc9c458152b73362e3e4fae7153cf6f56fad0a397dc000000000000000000000000000000000333d99289b953538306f12bf97e4c7ba4b235648246be74c14efd491d6947d9cac4983e92bf2c3c64ef1bd467b5e6eb000000000000000000000000000000000542ff7cce89b479b80019b9f2c6d8a872ea679965a2c4c6df6d31ba4948dd2ae2e3c00361d1412de7b829fc7fb0b95000000000000000000000000000000000030193b79c84062c2fb840ee25a95ad4cbe3d35fa47d7c42350205a3cb3a183e018702710ce096db8a7cdf1940f803221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001d30669dd9d0a13782caabf8be76b8309e0611a05be32d233fcabf541c9e01ba340e6f205866796446d643b78c2921800000000000000000000000000000000090fc764825b02e16b463d59558fc80f7cd1345b26e989ec16e0027c366117e6fdde1c39a882a5e969b4a603e91b7c8200000000000000000000000000000000047f4d4356626f56c41c023ebf7b752c94bf27a3db272e22ae14dacbd3df6de973e2254a7eb8b4844361f17edac7679d000000000000000000000000000000000270e63b6b9fa5fbbd8780c9bbe4f33072244b56b3dbdabc0513ee9b4a0672a47f92221c09f50a63198294a57a001ba91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016d4723da07481e5bd1976e5434f793331f0c11823f8c9c27f735c64916bbeca0773692b0f88a0dc656071f9dbbe97040000000000000000000000000000000011bcf27234e13a9391c94c8b76cbef295b59fbf6f2a5ea094935d91387e617c885dc2c85701372c9f61edce0b413f1de00000000000000000000000000000000160816cddc7636d146a7c697625ef3826f9625e826073ce2c618392acdbafea02a2f0a1bb303771692c89c610fca096d000000000000000000000000000000000661d8ed7c6243baf08248cdf291ef9d135b84d10df07777c16d7ad109cc90ce92966e2642d6e5f6d365bafefe6cc76f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001078d7221fd4c1f603f43623b93d60484a71b86f2f515b2f6a31aff4fe20b7165f247ac5ef05dd4310d0f4262afd283000000000000000000000000000000000060ed7b37deb1bd552eed11f8180fdd7386a64b95640115414f205c27a0551a6c3522abd96209198c4b9e50e86b794220000000000000000000000000000000009f0734857c490439ddaa82cae4900dce340e3ead4dd807b41bb28bf1ba477b8b565f16a4cfd73fbf11137eee6458d58000000000000000000000000000000000902a1639d0b1deb30068d01365ca1970ee0644c5e704dd06f7da0a1389c551a27d2795318c5c154a27832e6509199821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004449513367249d021033ca021b459199deaa36c4b1fb7aefb64d720fa66d63e541a5047dd5daa3076ab5fedc2a0cae00000000000000000000000000000000010fff398f66c7d4ae193db24e78fd94fe2bbad10fdc08b93ed024aacd5dab6e657cb3ba568a133e39339b4d765b6aab6000000000000000000000000000000000072ac009b4a4e82db458fe5e6906bb17e6607639f7bf42fd7c203fb03e420f2fd9ddf6d0439c07d5995540e655b8d5500000000000000000000000000000000103dcbaf1a19e5e2a775467c896a65ac61dd5d5183d293307f20a7ba520bc6ac3ace5f911b841fabccbd78d64c0a7e491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ae58b2720348bba4279c824294bb3ed99e54107e6a934198366b9fdd5107bf36f8f9fd396784bbd27238f03e3d04db000000000000000000000000000000000ad2b2a7d11d080fbb931713f1100431eb36172f69b1df4b94fadecb0fd596c40db03508b82a56a3a4932995b6ad5544000000000000000000000000000000000e7fc999e088e01bdbf02e18a38952118e6209145f9aa07a5f6dfb69642319caf721a090cbbf3e631d3befda49001955000000000000000000000000000000000737ec60913434b7f04d1c8570b08a6246dd0c9952dce266c9ab9e72031906a1d350255dfcf7d01aa844ddcfc9902b351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fe219574c6e54ee49d7ab1041bee1395f2738fa0e291ebc3d65f4fce01e84678df22ad370b312cc97095976c14f12c00000000000000000000000000000000025f86f9e7a43106518578d54889e1740f9b2e7bc2635b4ce31031111c9813b9f06f9667b741d03d71b7f935aa8155bc00000000000000000000000000000000152f5bef58a0b7412af239b3e071d1bf3ce0ec09a5cc6a5c3e1afc984c4a8745006002f6fe4d715ff9519b96d1fc32bc0000000000000000000000000000000012238463418c1546770df24a4177c1f3d65c022c6ed47d0592c6e52d089d538bb0aa271cc817f8a9914087cf4a6ce1831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015549c80dd9627118bf4126eb8c8aab23f955a5638461be030769fc05ee9ec33a400700aa6ad6f85fdd4d442423ee2a5000000000000000000000000000000000b1556d30944b820702de2932be12be563acfc162dcc571b355f21be351a0f0f86ca48bff36675fee1e76cb028b5d3fb000000000000000000000000000000000255c6ad5c87aaab7465d7540b5cd8e5d47799247d3bca7826736026edec1f4e88d8765098713dfb4567b1422c8c29d500000000000000000000000000000000194a8a6fbb2ed1a88771a134417d95429756f3c70070f5149acb6ef74bb347734d08de67536a1cda8203ada6622fcfc11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000902ab4576ed4288b7914b9df1aeb6d0ccc2f2cba035e036708d07966e30a782be1acf5d57174d3a418ffc4e40320a2b00000000000000000000000000000000055942db6a5bffea962e757eef91066c6722b53154d0ad6bf0b953e93800ba5a986868a0c5f43bc0ff18c25c37c74c9000000000000000000000000000000000038263fb5773d444b843c830da1c0f0fcdd7fb82208d3dc196fab5a2e4d91727da828317e2a386342a340195e20dff0700000000000000000000000000000000111224fe2410def534eeced92fd2fe1390e73134ad253d7c937cb3338bdbe633c5ff424eb2e82a1bfc85943d80fda0381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007fe3184b6487c9f2b6b5fbfbe50a41bf48a0e36de219f384b9742a9acf4b48879c633782af09c148eb00ba47fe50d75000000000000000000000000000000001935040092d83014a76c9568b829f043a9c7e6f43d9c70449852bf5b744266f2d91f36b3282f43653cee49264ccf01bc0000000000000000000000000000000014fd3040f59ab59bfe7f89defb8eb85e85ef7ef788e07b3adb088687a3c59c304e0cceb4934a684da74dad8d26ffb2c30000000000000000000000000000000018688fc83cc9c9aad55c3ae01bec4af3d90cde232dce82071ef67f84cd665588e4f7c55501b815a3079f068c2ef3d0181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018dce5e200f59a7d24ca96431785cc8bc073e46e27265690e897b04a776fbae6e216612f7d23064189ddc36b1246a599000000000000000000000000000000000a32fb098eab0cef5d03628b726a94e14098c051a174761a3a96a30e9e3ed6d611584a675656caf16d53c772e5448ac20000000000000000000000000000000013293bee73df1b802148b4de537e20591fa3c662089deb9954b09fe0a823489b026713b2d63c7bab65d30c68ba266a3e0000000000000000000000000000000015276d35edc7a82ba6b98144b3d988f67cc345d10730e663014367858ea8b593448c37f69289ba8616fd3dadf946644d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000371c497146bf8226251db21b92ad5a6df623f4aef37587801417bf887ac8e80c612958dba15e7115a4a784914932c87000000000000000000000000000000001986cb3949ad5041c2ec2cc3994a6a97a35f3661f68aa68b554605e07a8d98e91602b7ff8cb315e9f628b7aca7eab869000000000000000000000000000000000d94930e790eefb208a414d210f5bdb2bca0ba8e4f97ee0ce10a6841230a940d65416d16d8c5a1e304b79bfdbf0c40510000000000000000000000000000000016aee9dc6497bb8a7db71280b9b55314ad046a82462ff55863de4bf12f52d3926687f4c1a151531c6df95cecda6de1bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d54ed6c28b2e15bf939809d144535feddb97f2259a9c0ddd70c3de5410bce4370b341218cc98bc0dba1f68629394b940000000000000000000000000000000009638b9955486d9f6897b85e34b24a0c2b7a5f1f57f7e089256f89cfe4b546281b9361d53ef9cfa45315150a534c6b10000000000000000000000000000000000259807c0b89b846f08a8e62d4e26355aeaeb4f3bb1a97a216ed26e56d3eef6cccb642e7ce0e0879a07080b5eccb04ac000000000000000000000000000000000558c3aac0bdee118d50eb7ab69f67ba87598cdf14aa8ddbe29d04b14333d360ac630db5db4050aafa1f1d3f3a706a741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007aab1673b80eac52a903d3b080f4a2a92e88021f555ce5c1f463a0ae097df183174366bf961d6a61ef7dd67ae5aa5a10000000000000000000000000000000010d7d4af18b5a912891c66424f740995d041c1b7583bc77a8fe3443afc58bd5bf468b0a8e894f0a886c0f0a57d3f63cf000000000000000000000000000000000d0cae1a2d5e97f2f52fc46766c1615b41028efa15ffa4424abf5d8e7ac5121fa0d2a0c716a6c6ab6cd230e5c8f776e30000000000000000000000000000000006d943cf00dcf5808537fbaac9cac62a493f461cc78290a7d5a9d5666b7c13568efbee8d6567d9721db4d1d253f262f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009446f8d5e39970f6d22689492ca6a4be496260a993e8e5a5069edf6e761e6968901b72fd6e6634ef3282913d84856f30000000000000000000000000000000000a638d97f46497148987ff80bdc38767fc3bbf3511ee4652c4bca3aa2992f4677d9c4adee41e50f694602eb6ca5f9b10000000000000000000000000000000008119c87b12859a05cd6f72ed8b2d6f64bd9027b9cd33265b58b16ad21e2c3001a3d7cd063401925ed788ad816d4856e0000000000000000000000000000000013af16fe9e83c565ef2137b8b9ef50f3fc61c3ee17bf38bb980ef33019e08d09c04ebe26df56729925e16ebd9e43cbfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bcceeed550e115a4aa0a115cdc4d6ae3a1869c0e5fb2c049889fe0e578aac3356b1e13055e6e2de7355a2ca5748c6b0000000000000000000000000000000017053c8228bef410fc0fefc06587f008c00735c3fe1c9d3976fb23f953b7de481ee94a23590744fb3969ba267ccce02700000000000000000000000000000000050ef4ddba5b4f035fb6fac68b5a50d824f699047e57e03d4aa70d34209bd85e39d9153505d0ec0d1fe80a7b3f1d2a0d0000000000000000000000000000000003a7e3636d3318c39ae88192af7c2330b81b9c061f6072168d27ad3f430f4a62b76dd7580580fa1844454dce1ab89abe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c023a194965dbd6d501d0b14e5b82431f72ca8e89e2ff5af6012628809df362e1fc2c6b5a3ef53a8899844f5c6afae8000000000000000000000000000000001331fe16b8c6f12c3aab4f60b1b3cfe233380a91cb3644e02d10bff29aed55f2e9360e35d499dcda40daf3d6d1d1057e000000000000000000000000000000001394c8e26c4914f0508d383c91fca90b34a1743b641e4be784a8a8062b578b9757b5a126af0195a4fb95ceb65ae6a2160000000000000000000000000000000008e0eb45af2b1b6287e4af8d99f7d9c8a4804009bd0a9514a4eeac8e0f0f22523e5ca3df80340be8f2e172d4713bc6181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167ba605ab88724e15581b02c4716519d9b08fe668107627ebf08f89c37206ab2cb197250af8117bb16d7d37afba08d200000000000000000000000000000000176f4689a652748952e6f0afd847228d8777b0393b84d7b0b3b864739bd9a9b5bbbd16f04e7c44b5c3df24cc3b9165f0000000000000000000000000000000000f19e05fa2a6c1f5e7d76d60cced73397693b92b2c4fbe10043212ff3db0aef54c55de65f589e11f25e82d08f831241a0000000000000000000000000000000000bb2ff9c4428875df45bb1f94f891b90f9fb4368fa5aec469ea4677a1bbdd3e3dfcaad5647130b31e625a4a2563809d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a8281dd9312c99f2f2e657a20170c37e312263c761a63927ea50455bb822e408068df608c9a779f841884bc3fd27d3000000000000000000000000000000000f6e79c687ce34e8ce32b49953a6673a26ecaae69d51b05350b61e800bfae2ea608aba08a7b132d752e07506a656186700000000000000000000000000000000063b606195d719cf5521b21696d0903c4a320868fc4dbe0c9dad8c58dbd778484a9fe01073208e65926b79cfe240cbb00000000000000000000000000000000017b1fee862b90bafb504bcb1d4f9a70a9360704b581c720f49f433142b7bec48b96db31e3b0f5786be4b3b134d754cbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016828dfd30eafe0397ededb8af873ec96e22bc778cba39ab082c4d55bf09790a4e4a845a87a9d6af74b068fe6f86b008000000000000000000000000000000000cf63ba474dbe1525d538fe6a9ffe9af81b1eb9dec37271d51d510b6a8cc21dd4b8f3f02997ef5e7307920b3e3ec40f600000000000000000000000000000000002b53fbf4800506e6e69d45910de04ae542994f7f337ccf97189572d82801de2f283f0d612b739b23f886b69a312a280000000000000000000000000000000008a46670066e0f629705d7446a265e2699369720a491a1044893f0bcce12697b69f155a01b38c53f17dca6f2de87b7af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001330045e6b6db0cd8fb80e4b3b8b804b2830f1f3db171eb54aa3d6c9676ef03a2167df3ff83cdee6ac93098a44740e070000000000000000000000000000000002379177126ff4a8c99ed85f9a072df7e4a2810de0bf123b1a0424540d250c5abaeea65777163ef25c8013383b0f16fb0000000000000000000000000000000018bc9af6eb4a92c78791952b3b63d51258ace3b6d3b0b6f68476e8ce0f893e8f942ef48caf6132e216f24c3450fba72c000000000000000000000000000000000176b33942db6c5e30a46c5bc739d9317f97254c35db71b7d00c9bbea681923133644ad97661aeea7042c3b2798498581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012befc00b4b53c5d2e78be7470bd7a11dde00e8e959664432e295f0665285473512cc3abc24ebe1951baceab56d793aa0000000000000000000000000000000013831f84aba3c6b2d42f3a1bd6ef0ad2cf57af1ecba781f065c8bcf624920c5a1a9e4a352ae8b8e47a8febcb4e289bee000000000000000000000000000000000ab77f632575fccd5d597617a9e411270efaefc276cc42d832cc48100b6aadc95f87612f1b6e2f14d7820349b053d7f3000000000000000000000000000000000589fee99190ba1b47810c8f32513e4cdff95861a1127feabc2eba21a45b46297002e014ef1edf87c186a1de252d36281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b6d88f46d8618d0f64e036d58f39a37f4d33a265dba378a628602d94668bcffa49b37a171071a0da576b3689c40a8700000000000000000000000000000000015bd0c3a546247eb878c789d4beb1b721df31cd78e019834f55970edbc7ab95c057ef03cd6102195e01e222680bc9f3000000000000000000000000000000000ba1d6f73dd55f6010730b61a49c85034315720ab5eb1bc91d5f2d33bf2fc6545f6b1f65b8e907d9147a7e5e97f8cccf0000000000000000000000000000000003a235d5fe02c005de7acdea89bc95bcadc2317082ceb0276631eb4a0467595de0d42463dad70af3e373ed2f6e60c5b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076b85b71e867a23446ee38d46c28b64be9bca94019d50ec47dca07d89b1783056690813812c46b124cf762a7473b194000000000000000000000000000000000bee773592ad08822ded635afb6c4ed9396ee7a81d43463d86d8f67100f55b823880ee41c776fd4f79d273088a6d7d3d0000000000000000000000000000000000cc25edf9db70a73996217897df0d652f93edef2d23878c184d68e1aeb49b00b49a8ee41c71213776318dbc54f2fc4b00000000000000000000000000000000148bae47bd452e29fa49850b3905ecb9e8dcff38e2d30dc27b7fdd99480b3d2c8edc3d3cf8994de941d69a5ae28627e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003719ae6c20753f989aab56d1b204416ed5be8690f84ecf1c8ee085ac917a85aee9f7f7e1c509dafaa03aea620ca3ded000000000000000000000000000000001736e3c4b13dd3242d0645a89a3c8103761769eca64dfb6e9586fa70042b2326f78093de3ff044535fbd8c3cba1495ce0000000000000000000000000000000005ee15315d44b213fdefbee28bbd1ee0d437d42e03553695c26df2324c3952b42b05c5e133301514258aea6309867b6e0000000000000000000000000000000016c3b0cad107b7b2a080cd497b8438d8bd427b7a8c029f77f34ca59a285ee747ff371b21d525100adcf9360bb9d3110d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019910c103644718ea31e7c21f2534dfd3b3fc4b9cdcf72232dacdc7aea251ccc91565e2399a5c1b864826b8aea9ba942000000000000000000000000000000000c794e0d9125990926d797272c7e356242b863d7ce22bd9157419ad3ec1dca12f582232abfaccbed584eb7aaec272fcb000000000000000000000000000000000441ba689544dc52a39c4d0b9c5d2d00f09d28afc8355b95aa03fb57b86abfc3653dce49aa4c5e5dead21bceb683819000000000000000000000000000000000084b5c26084c81a2aa3749be06c2223cfaa534fa3080c29b53205ea90182433c0d2ed58db2e500ac4197770741e215e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148f9044d350b8fd93e2514447f78b71d7d60edfbd49cf806e6f5f210f19742880b7fc41fd2cc1222675943aa2cf1807000000000000000000000000000000000b69968f8df265356d6d6706c9997763e896533a9c96b47bc24a9d0548b060df77304787157507a8417fbb0ed59843b10000000000000000000000000000000005049744786e8e11c226fd8ea9f360381335d93b3935cab343b8f055eb4891760fbeb61265085fd7a77175641701eeb0000000000000000000000000000000000c5022b5aec608817ca9d0e2b9982e2a4013589287c50ca683a05d7136c4175dd1ff97ff6ededcda73e6e07d1b407b5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d087b4d2f7223516b2570db01dfd91dc711f9fc2b9feb53d639b378f9fa7e74b2402bf4f8874448c4eb05d12e6694e000000000000000000000000000000000748667df3b0794a5d327f584d47c31d41cf2ef76ce2bc417a426a83f783a5fde90210ad57c297a11bae77d0d90bd7cd000000000000000000000000000000000fa8a8942a7a1e9c5fc47e093c6de83eb09459725db1ba24ae7cd8a9846e67e877470826808767f981112375793798880000000000000000000000000000000012be61bb9b4bb6fec48b7ef143f8404b6adbd3fedf70ae0c92fb04d766aaa28e661d069fbe697100e964fbc662c480011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1ea3f4098d01b47f2a4dcdaa2cd5d71bcf2dc32645c6a3050a5da911248c45a12facef170a1158b129ec61074f60bd0000000000000000000000000000000011ac8a39d315d27f0862c0aa9f26bab07035924296195a8f4aa5299a7037a6648649d252c384762a3b6e9ed4ad2bccbe00000000000000000000000000000000003ebbf5543e0bb713c776aa84d5b9fbbc81e4c76fdf5f10dc327fe9c64106a66f316bc0adb7fd78b9f3db9e3086c5fe0000000000000000000000000000000003c65fc457d6d9fa8b1dce1a5709acf397cd6acc3a0fc7b72a4ae53c245e090cfa3c90a3d93d1f9fcc3f888ed221209d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001745d38eff77a29d163c85c17de38c93ddbb7fbe995c30fb2ef99a731f49327f86b83ed0773e68cb224a5e985dcae88a0000000000000000000000000000000001b2792b5f82d1cfd4e38305a2bb663dbbb968d92f70d278e5e3206a47c14cbe7b518e45b3877e4392ab6855926422300000000000000000000000000000000007c77d3af4c342721cee88816ff3115c0d6b4ef40f47f0c4a62eebfb9304cf52f446417b8670f23807b5b9411f7fcc31000000000000000000000000000000000fd28acae824f7ce4f8e466173e6e9e3640fdfd669de69405f4365e5323be37634675d3afefdbdb37be419b04d5784291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b7389237d19ff78f72d0a9f96236f90ad87541d50b8a52220e87c16048f776043574bfc91600f7a6a0d69300795b0f200000000000000000000000000000000093e0b1f0d69c759602b247dcf5b98f71d151ef99bc2f5fab37f9bf6275f7b56c43e6667a36e312e78e4fda34b297ea20000000000000000000000000000000000710bf0b2734786f3149bad14423f062854cfd5780b78474ec16ed675fefd2e42839817338b1d713aa9e5dd8c8f2c86000000000000000000000000000000000d46a029c4ef8ac1782dd99bd0932287bde183f18df85b284ae6bfecf96548ab203bdb684f87d1166ade85afb4c8c0d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c22ae873d52e326e25531da24ae6fbdf5e33871433635646f6a4cfd59d13c1edff1445cbe50d5fd1a1894e06679294b000000000000000000000000000000000f388ebafa4f4c36a654bc4c6ef7bada77f3958ac827a5351e087c03fc8389169e99024b67ff7a8f96d481b20f694dad000000000000000000000000000000000d73561f940076c52dc74564558a3f99261ac8658de94d429276bac7df7cab74e492683eb1eeacfd20a85720c7a93457000000000000000000000000000000000c624810c9d1cc475556d5123d6121686c4ed06ce71abf3cb724452b0a54b1bb4b1c64db2f2958fb69604620ce1ac1031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e4e9a57e009c2b6105868ce993e8396f210f8df81a1c024c07ff708b599fba6db1192d9b5bab96d5880d5fb4aae4720000000000000000000000000000000003c5c3795fe1d6bed101c2884b8f9720e4d2fdd25cc7ee2626882266476fe3db0f7d716f55ae84f21856237ea676f1c3000000000000000000000000000000000fef9fcd12ab36262109788279cd29ec85e9e4a3d8ca680f98514a75a3cd614b0c75f85a566337becdbbcc607530e72100000000000000000000000000000000050976ba4ed35914e5be75f5f9de3deaac5788fb0dcd113ecd14fa1e2ed5bbbc358a3bfbca32f72228b305700f929cb11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b2db543374d2f05239be800495b209f1381d47c822e629d0965cf7f77a18f347e23fd20ef473a5558107ff048eb640c000000000000000000000000000000000b55ef580c6f3a8e9c17c412a743b317ce684cfb2b12623de5d03c48f07b3b42be6a50920292413c20ee309d6df2f75e0000000000000000000000000000000002f4928f98d2ac2f1789fdd7341e9698a504b682e6d9e97a78b98550d2cf03e329b77139ff73c11fc0caa21434dfa44a0000000000000000000000000000000015dff7df97f4c9edec3c5b699aa2889b2349056248ad95a02b520125522081c0634e13890bda325bde935ce414fc382a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016eac19552236e6e800248ca6037394e45e94b3d628f6e466a8bac835ce08c5183b5680d9f6e12b7018eb7f12faad5a60000000000000000000000000000000015c4046a33cabfa3e938d364cc78c64fb37ab69dff7d462fe07102ff0591b2aff4973371e121ee372b1d3a32dd0f2795000000000000000000000000000000001914c3017968277e4a600fdcf912c7b0476fa6623a503c490e1ca24e764cad562ce2004218a9a5f44d8cdc34edd9dd14000000000000000000000000000000001833086786d28b2ec1841b9c9af80c8a5fdc90611f860b9b2f8ee69cd33b42c44eecd34ec51501b34a8288a1e0e46ea91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000127c476d2232710235e4582b06406cce2e262e6431a638608fb71c7505f27a0971e12fd188cddf3a160d7548d6949065000000000000000000000000000000000c0643520defb6fcf90157845e12e5a94a938f7fce958339768eb2ab54c73c7a27059b658a27fa7303643398d2fd46ca000000000000000000000000000000000aa655149b8a0e3a725123814a95189d18a61701665b6d077abdbd18f1c3bbe63e9804f443aa11433c0a89e1a6f0a8c500000000000000000000000000000000177dc3bbc9983fc35af72839dbff7d84fd3ca425d18341c4ad7c8fd981f2ac3ca6c6ef0b125299c386ef9a2bd56a2dee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb000468f2da1df0e4d3feadf8b9e3eccf0d9f74948b77e8e8551d1d34300260a14b55fe9303bc440cdec44982070a40000000000000000000000000000000011d2d4f0c7302343b731d5a6afd34b35834710496d1b5a2b524480e047b1e87e8f54525b2d93a831cf33923195ad7475000000000000000000000000000000001823dca2011a85949ce46bf5d6eae540f4f1c766f9091e9e8c8775feb64986262dbe28450628350229c0715626aeac1e00000000000000000000000000000000048327b645a1c739e3e02df83244c0cb22beac3ca2f23d02b61754dabb0d9e9b0ec52079a83daa6059ce80a0cb8c04c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5fd51383e04dd3f69b1d6e6701a88c2da9ae998d81aaaf0f5978b4a1020b94be62ca959d3cf377c4d350cc42959dbd00000000000000000000000000000000053b3f3353dc9d983a392c81e9d809d42cedf1c8583affabc7b6e1c8a8f8ec8db4b860283890ac8f8aa0a11a50a8509b0000000000000000000000000000000003b5f4fcc5555c9581e0b19de8d7d1275359efdffc08ff2facf95856ae4f78830e7e2d59d058d7bb2a5e9ebd735f309e0000000000000000000000000000000019a39d175ccab502b15e50ea65d3354ec6564502db5168c8f77aacddd8c2a241359a958089f9670ce9e5752850fb4c881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bcd58a2dd9b4973710b5962c4a655e8fea442f277ae329574740ea3d6a7d39a6697857442a392a2cd4ff070530fcc240000000000000000000000000000000014106676107ba48b462546ae6d0181ba4c18fffe5e27e26afbc942dd0377b0d3fe2c4ae05ebfc56307bb69f21cb3866d00000000000000000000000000000000187e1df43c0637fa537665bf29799de57f9534adc1c46fba91d29813f07bd4b9a20c0d0c802a3f009ab676ae8e1be67900000000000000000000000000000000069798f6e6ff969caf189a99ebc7a946f1cc3961cddbde818345f4f158298aad1cef4414e7232532e917c046262b7cfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001070d9232e7fe7e808f3029dea44fc24da8496b4ed0d457f782dae4c449e27de8fa8fb0ea3f02e05b164c7919b2c15e000000000000000000000000000000000037f4ea013024ff2d375fefd45a781a7c1e153b54f7d829b0c18d85c8d07d77187bba9f75a4831af67353b999de1185a00000000000000000000000000000000141fd5d38544443b981054022e6eb097508f9d8b1a29c9dfeced3c1753a7d1366ee9126b29c831e0c65232efd6ec3a970000000000000000000000000000000016ebcc73410981f7830b6c36d53dc3749e96925670b8a20ae45ebfbffdffe4616ebff0678b232551836b6206f13b78541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083fb8c8f435b1302a7a640d45fddc9b1e4f490ecbcd7eb23a701757be87325498ee3653654b950a99f0109b50fc476f0000000000000000000000000000000012c9b6cfcdbddeec0f0f2fe30b8cd55919a991b738bf5c6230da517933847896fc0673773d82eff70609c30ccc7f5ad40000000000000000000000000000000002fc4fe5a7e0a08369e0187d1aa291618106721bbff8be4bff451f8c1b004e8208ab49cb79cfb6f155a3078f17565d6900000000000000000000000000000000194b09181daa18cb26706a4ddd1fa1227815dd55d844b3ee1aeec37a08c619043ac06ce5dc68032b09ba49c530bd65ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153fd2a33a19bd3d52451c83d3d031460857345097b38321745f437d181a2ccbeba46808ae513707415be4755af4ad02000000000000000000000000000000000b3b0b3afe0b2c0c315b1576eb0b926ae240fac68e1216d24391c7c230fab211bcfd6b82d2ae215441c8bf78a9e4356000000000000000000000000000000000116a63cb7fc0edacc8a988fc65249e2ccadca18761cfe36ea5cdd621d81b03a8984260b576b2a0aa795e85429389a267000000000000000000000000000000000fa0c8239ed77a227e879196fe2af304e9a6a6d6e48a850802b4de8b7c75ae0ce98edbeb6b7c1af1fdc689c1f6e5a1851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6d61674dd08be7e14534820ee1a7efbc0fbb9fed751a73af7a832a237800941613faa069f2d029b20de61dc293d6f500000000000000000000000000000000023ffdc232d52e2e5b5a84c2645fb362ba036549cf1878620693bc8177dbefc66879ad2fcd4a225e460381ed04fc6734000000000000000000000000000000000eb782b9405415b138ef2a6922956adde509ce08a67ef8e31c3d39ec9d1f51e11747766b29954534977369ce52b6b0cd000000000000000000000000000000000d0ab9a78b95064056e13a8fa2f60cf66ca1dec33d939f147580d19ef117906b5116662bd15c928095a1e1cb6442e9fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b9c041f2f8441b944fcb591e6ff558eac982c81d325403839adf8065dfd9aaf9b30abe1533e825c5709fb48840dd7c000000000000000000000000000000000b63536c900bb1eaac7b95a01645fe22b7c5fd9230f757048f519113fe5d46c75f7302fda45c2994127b313bfeea6c4800000000000000000000000000000000035f5378da22d7c4d9fd51609b03c1127b4e254386e0bf959592889f2d1eedb30ac85532e6d78966f91f5193c567467200000000000000000000000000000000151a45c6d93d32dfb47e2d89843145c9f6e14d0996089895654b55194c57acf67d2688d2589cb00601f0a8331202d2fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000033c987e7134e090ec98ee57d04afe43b3a03b7f7d77fa4693a9ff48bfb3e04cd49707d27c096659223534848128c2c0000000000000000000000000000000014383c9014e65602495f6f447350474dc2f3aec7494400bc238dea1470db4e56b66cec3630d09cab8c6a572ee4f3ee510000000000000000000000000000000011876456bf1d967ed8a1642e7f9b70498149f1d51949173d9d24659f00bacf5df33e6f8e8d97fa709139606b1347121c0000000000000000000000000000000006f4b89a3aa5967917768caf9850b7adf3c276fd5ec312b6170e737d4943ff5f7f672c64578992df6a7b020cacc2da461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ddf3a89451e80848ce315884378b9162512de0d9ab41c749b40f946d026bcd9f70d71b0fb889b23c9fbc764e3a31ade000000000000000000000000000000000e79fc011d79a4a552dc2b9e6466de01d450b7f9a0c3b7704b7ca2a13b766c2d6b28c3a32f2cdc00dea7f7385eb7c799000000000000000000000000000000000881c6d457010180fdf9b120db3a713d905fbe23bfb3c6ed520eb32700ce2c0c9b1a8bc0fd7467a25b612236466580d30000000000000000000000000000000015a30b2c139fec2ef7e50a2bd2b639c6c7625b0de4a1227ae0ffdc20bf694c4c54eafcfc02bad7994215dcf157cf74341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010aa5edcb9c9db6e18ad3cc111fe3fecfa4d8881eaaff662aa9963458612f4d24ca50ea267bca0c2ecfbd36ec0f856640000000000000000000000000000000009b4f263411ba3d5f2a54c9c01afde206a9881f6e8bb669b5c9e37de7428562b72ea9b27c824b4cfa35558d16a20c1350000000000000000000000000000000014355d9f2147417862a4d1ce7121fbdee3ae2e1fe3a7ce410157fb723891fc1433fad4394fdbd9fa68ce42a86c072ac100000000000000000000000000000000087866cc102141fd9f375606b0b4e862cb57b4b56d3d0eee92d05e0467239a906352e42d4a01f36ea55b0d35360754141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5ed72801addeca79b072bf5cb40e3caa818ad5a13ae99e4fbe7147293ff1b86950939e510b9abae7e47d2c53f80ee10000000000000000000000000000000017337eb986aa94d13ec6cbf277c2de721953d91c82314612162f8045cecfb2fdc7aee12ba1bafd71708ffe742f98fa130000000000000000000000000000000019cce38baccfdda9d3365f8eec5df1b14066b8a1cf16a027f553d8070897d47e05b516b55724f99d329ddf33833c1dcc000000000000000000000000000000001918d311ef01fce4f84c47569dc0bf1ac4d908dcba56d420b59da072931755a0c164022c3b4800cb4349cceee050bd211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001147630c19ed87597e257b2c06ff754d4f9f3f2329f3f081c62b5c9b1e6306535cf306d617e4332316b6141a956277ef0000000000000000000000000000000018c55ef22d9195cd21be90d91c8dcd2d9b87505ddc0f37622c05ecc4c614e21af017dd400caaa805e30c3c23a4e0f9f00000000000000000000000000000000019fd38d372aced7ca491e273d823b21c64369d5bbc9529bc4c5a0f757ddf245b38ab79ce3f7a3eac61163c760450fe170000000000000000000000000000000016fe4dfc4a5fcdcb5f4c28e153797be37939d5b7085133146a3be0ab39dc83045ef2a3dc32a61c2b62a29b7f6c0256231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005188a5227d4422623fa652f099b801a9cd34b5690342d7106eb9a66d2621b956f5c943cea313074abcfedc105785fed0000000000000000000000000000000004d28154b5197f878835f0dc971086e3ae1cd6a99fe0649ee69e2170e1f33e5739cb19656ce832555d29781159f1e0b300000000000000000000000000000000077e59f7631d5def46c78a39fb28b6a47dd332b86ad2c53d5158f2adb28faaa63548ff6f76c2a63104c308a8b0d568190000000000000000000000000000000018b23c1adc5d2d5c939914eb5cfd5db13e3603349be404ca9c0cfedb9726af7fe708cce2510f5ce29235e5d876e5ee5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012714f767557c677daf293afa80538592e374b21648921d5e489b6b3d4b8bebc5eac36e33ec97e3689365f6da0ee3a07000000000000000000000000000000001419c0641f6427dd0ab08d42ad885fc6c4c82078065494d1dd735a4843ee9dacc913d5fabd59c439e1ec3bd6a46c47b50000000000000000000000000000000007e4af3e75a92a99432dafa5d3d0bd6b3e8298650e323887bfc3eb76c3f57e047574599d7f578078461c5fb6e6d5a7b000000000000000000000000000000000199459fda236248101c948f8c10131699bf7b1c7acffb186286d0258d2051fff764340eddd9ae21dfdb288c97056e9581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ee2adb697c9f957edfde9c9e1079fd67e86b942af0a632a8818448e398acf1195e399e8496a2739efaec4df0878fd6000000000000000000000000000000001449ea7f322d55954bf0bb9873550eb2de170da04a34131387ee0d0376a1f62b5239c360a4ed3b9257f86b6031e021c8000000000000000000000000000000000eb578417e2cc2ad2db14dc03666f6da952738ee308ae0b55a0e4307631a4bffc69082ecb08ba1c13d9ff5917909f936000000000000000000000000000000000501dd7777ce9fd8a4b05900aebddc83e9227b74972f27a305ea0510debc45633e584c7e50d272ed230cd19187202d881824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001415a0598ce2bf6f8d57693c04cabaa0c3e92cb277983450ed66294561caa1c6206eceb8a71c3397e3a2753563fdb9fa00000000000000000000000000000000096ff981cbda6dc16d80e473a3d8f8446310256a8d450d37448c8de89cc179ac9927eb357d07283afaa60ea11a1f024700000000000000000000000000000000042c914c75aaf1792f82d1d8d369cb7ea2b4dc70413d66a5545d408d2dc437fc24b7f0207a838e04a021245d2ddfa3ea0000000000000000000000000000000002797844f5a14c86f9e5e6649fb82751fd67afec1c349603301facb5b0b7ab9d4f97a466437fdbdb8dea2e34d97402cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003dd2d066b8b5ccc3f76605758ef5e23dcc633f86272156ee71b8ba8cf29a00f8a6e68720987f5aa354f7b265135147d0000000000000000000000000000000003a2b168a9da3a3c0f2e0cd23716e8fefa0128eb65922806fc9a1dc6d54a954f731fd4cca74d6cfa09658c7e9c1857f90000000000000000000000000000000008ab1ebfc50fdb4865dca2ebbacc0f4eb8cfeba3461fd04d94cda523b1e774e71a2678f833b06bc3c1f7890945f8a0d70000000000000000000000000000000012d7b0b95e0220792f45cce9d0e7119d88fbcfd7b8250f7d7cf234f2602090526aaf59bbc2422b15cdb9bad58b73f8cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071699a71df00c4356670c329afea6ac2d04a705b4124a1139597e3cc7bd42615234b726ac301558a129cdcbf430aadd000000000000000000000000000000001500b2f30811891f6bd2f26c410b4bf60ccd65f47786ea8e92582267e50e1710ca3ee692291377901e804a14e4b100280000000000000000000000000000000014daac9bd679388992bc2079b64ef035f69c83a42e0aca06c20ad4aa45c7b846e82de49388fb72ca94457f52bb692c53000000000000000000000000000000000de63e3221cc20ca09f1449a28c632df37bbbec582c7baa24bcc9e1e23b0bf46053e2899ac97df7ea847adb54e77d5801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198032c8e535e475616f4bf7991d77a0d4e79f4645e6a53c042ae255610d7338db7cce4cc8c044b070eea69a3b249edd00000000000000000000000000000000120b243262ef837e42acae5478bd0f4580361f1b1c6e87e915047ca21f8170366adad9b290ae11866780b63cdb068d2b0000000000000000000000000000000013723d94c7bd5a94db119ee890980f2966516819b36947c856aced0b44b375c2fdd29666434dccc3108e8c23855beac4000000000000000000000000000000000820815ae4502f962cebd25763aeaf60c2c93dff78fb938b38b6d24e3719569b8183abd12811c1b9c2b5e662be6246391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c486710ea3db8f58e98af9e52ed16831b1df5c8c97c76bc8f11d81808ff75ba5b6560ba491cedcdbadab3631fb8ba5000000000000000000000000000000000332cd53a6f7351f59e9a50c0fedc6758d854eef0461059ed93b83474f981f2aa52469c124da285ee6026c6255fdae23000000000000000000000000000000000c30bd95fd28232885f019565c22b281f5c3a397978503813cb7911c22ed3c2797fcf936e7d0f6807fb58a45614f916f000000000000000000000000000000000bd300799944e6462cec070c5c57d1179b05a5356cec3e4a1bb52dad4905b27b53a822c6997e2f8569df3c04d6dbdc461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010121ae2c121ba4e165f0eb40c9049ce5f55b027cfe9e27b6ab5e0124b8c2d11194915a6fdac9e271a27e6c9afd5dc24000000000000000000000000000000000d077b079d950147fbf08ebf5479d31e3b94ce46c512c7b9f1e5b4a818a2bfb0bcc71ebe4c39f41a15667404c9acebca0000000000000000000000000000000015a60fb4d100fb649fb7329d458f863a2492e3364d5274ce43ca2b0a0f749127a1fa3e707184186cc862ddf305f46337000000000000000000000000000000000ae9c89a034c0b47a232f23e168509de2ebf10b7f1c6b422ca3d50c2d42f3f3c3d027f523d8d83d8853b16aac5e071be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009883f4f5680cf2e1ed65c3b0ceb125a3062245a1729660816d8d6ae7712f45f41b8fcb069708c90ceea1299623c7d92000000000000000000000000000000000f627209e410dddc44a86d00ab677198dc8476d9acb9652dba2308bbe213b953eb3bacad470ba95bd232f8095128262d00000000000000000000000000000000024e5a84577cb04f2b6b3c92b0057354f6a19a9477acb8059a1fcfb81497e87ca472f7cd71f8af0a72fe1967b91d083200000000000000000000000000000000170d2081c697db5549d674ae72d89672cb8e765232e90bb5b7b58723d2a6a29d73148d4110a61b0093cee013d151570f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016fdcf8d8c4e3c01bed8081559ca5d460194b2c5b416cfe4c4f58ca49631c4c501dd6ac3066069a7635b42f429b3b8010000000000000000000000000000000003c9d620b256da3a216a625c0bdece610b91ee3e7915e177c756fb71bccb0d0114d9edd8a1038cb7da49c7d2c5b445900000000000000000000000000000000012e4e0cbfad1718eaf1afb77aa92f7842d60e333436e1a0756a838c814156a308e936d6e648fa427bcf7ee1dac5936c70000000000000000000000000000000012218ea520639fc3a9e0893567dbcb26df6ac18fffbf8fa969683cdfae6cf572328fd00d1f0256f4d6caad36a0b317271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011492a3635884b6a630d355a17491a2b5390f7183f1977f2610895e9be36725bcc09e65f9e386876e8da06145e15875700000000000000000000000000000000020ff996af2df9baebeed729824e5b12030a178d58ddd41ad36cd6304ce850dc26235b560aa820f891ac28dae010881b0000000000000000000000000000000005d3a5c95972f4ebe79f8770e23b7584002111d79fd960f6bdaed6aa5c87ea2e74f7e205cdfa265199a501b3f445aeb90000000000000000000000000000000001439eb89121b5d9d75af8f7546e2f70599097ec0b6a29f086d60e6ef91fdcfd837b0b3fffdc1d77773aa206ee351c471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e979c5e1f98a756cd280a61c8568b79ebcbdbd6123f4cf98eb8527646b565b1e0f0fdc274847bb6737bf3b18a654c90000000000000000000000000000000010571de2574ad8fe07ad642cc855b3d92da980fd67e7a16e5ed942f20a7540fe67d58c926c30dbec406732f1cd363db50000000000000000000000000000000019c75d79f07750194f661fa22b9f75936a5c30f2b2dcd422941100c80da6f9c79d87ca38ed2afa4192760ee2a092bb160000000000000000000000000000000007115882035f763bb070f5e76c9c3b6ea8dd002918ceec24e511dbcb8fe6da3e9c2b6dc40c0b49b9e3cd13213d64a37e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000185a3ca1c44d30d9bd3f473b1b6f69ff705a44f25fedf4b63e902100b2d794977e2f2b49d1f04eee3d5b1eded45a54040000000000000000000000000000000013b1d42f33ef2ca84c5ea45edac152647c342e76509f61691864c4d5caf64300eb40ac00d891ffd154d5d97ca3fe050100000000000000000000000000000000088c5d048db83c7ec3a0889c5a928eec23ea7f4c4af52a9dcc9d6e5ade5c24d979000c5ce2a6512c40122dcf0517b655000000000000000000000000000000000ca37b17c413ee21979406ab8465e655156cafb57da0b6ffc1e737effb0de4c80e75482d58f5f269cb81ee8f267daf691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e167a36f639a19aba1898d28c727a9d1699ff5c4abadd55ace4af81d677bb937ae8986dc80b41bbe0c3398d4e8b0d60000000000000000000000000000000009033ca53e311fcef91914345ae157cc6a408c14f8b004060005099886e85cf17d816e3519ebf7851a5ded77d61182e4000000000000000000000000000000000426fd54ca458905c613b2e5ac8ad87a5c3d834800b9e40c06c7a8820c3fd3e67ae7ad52dc2a9ca671ed73d1996963d6000000000000000000000000000000000c56ced3e3c519bf54faf1a00cc9f6881afa0f1f607b51ac156b42bd5dc48beff6a0144860a5ec9d5b83b2f3d4b2a0301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c65cf0ae1fa9da0f4dff226a2e34934c5dbfd711559709da9d324a9572a6fa88f63e5075cd8d4f77e218d9ef4b063ec0000000000000000000000000000000002160ce5add4f2d4f111449d353eb8491296148d6a1679dd85f535b444c703277ef496d00c0e5edb6ce0277c526df4eb00000000000000000000000000000000188c69a16df6cab28205c4875659e9638ef7c0d7192ea42604d99e66e9cc007e490c95f4018921d0cf1d2a09005ca5500000000000000000000000000000000005b7031d0da9dd7f91e6cf9355dfe10bf9a0d61f0bfa5379e5567c453ce146242e8892fcfe8579a5e2eef371c2b5781f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b6510c1d380531114c81c5023ecbce33f2a4e833fbf5b1ba3143779e3818d4437557c98e0c69fb0dd67fc36df0d401000000000000000000000000000000000d001286d4e64fd378a0798b5df0877f0c374bf627d06b7d408069c2ecd841f3d20594545f9aa60c030637155b014862000000000000000000000000000000000f377701d5b3f46a1594f46aabf6e082c8504b9d21e56145039077238bfdf38995bd69a4ed2774618e8586a27611a8860000000000000000000000000000000011ddce00250022a5f729f8272cd912c6ac72f7191935e359775c606bb0c6adc514d32289d3c200619c729adf082b8cb61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d43bd24041ae9cd23e5b56fd2d84b23e2a7d892921ca64af8236d2a53efdd40a241b272ef8a2100ba31620ee5b977c9000000000000000000000000000000000ce5480b091f1a30feed8c761603c2f6f73666a676ffb8f709273261863e77a144b09c6bf18795a9198d25689199a2b9000000000000000000000000000000000149ddaaa50629b55a390212adf85be26b016f7facd55110762b002608f2bcd8542e727ca7b4cc419d4ece06460597580000000000000000000000000000000015cc7e476873dd3e373c0848609d1d6e6ca8a2e46da28fbe504875d767c8039bb52b50d97d0703f1e111a3cba214c13b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5c4a901dba02cfe056e17314a9d8b289f518d485128bb206fb5be7baa8b3ffacd48def87b1aa28210fbd9d0d2978ff000000000000000000000000000000001049b47b3de96a8b2b8a9f49c4c59b5bec2c3faa8dd4ff3ddaa619a7998b80bee527b8d062e2614cae1e559017123462000000000000000000000000000000001839beadd746456c6ebaf62553389a62970063534bfa53d523638b4711ed1ef9df79c42bda4d48251efc554ed08d8c23000000000000000000000000000000001410e9aa38301705789b21a6f7971ec0ad10aeb8e1b7d3d6251c047468a2695ae0502221c1f817b9bdefb83f2b16bfb91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001504ced093430156036a3c14d619f91bd7b2ba41551a4b6ecddc267e06be4dc3f2c9660cd9c5fb29339c4b0b71df4f72000000000000000000000000000000000c84890b8499b8938c5cdf77824f84dcb5dd5a19821e6ffab80b8ae859e26b4d19b11d04adc5a06b1d05122c4ca51bb70000000000000000000000000000000014eaf94644211db5540eed75e9c562540de9420763425ca866b3919ec3c8d2088682102ee1f42c83c29584728a49007f0000000000000000000000000000000018ac41971257668fd19daa64b629fe7df98fa7c227612308eebd1125225a44162c6a4c4a5424ff04a2fb8dacdd7a7afd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f82fdd1ec962e0334b93e1dff0cf01c5d7f3eef0063914bae6b29ead04e3edbaf9492b20186f580b9e83eb824ebbfd9000000000000000000000000000000000e5c5d38e12208f8c7c4a2d1bca12a384c82bcd93fef7e9e0a5af71dcb0dadacb1606144add1b4e6ab11342f297c50e4000000000000000000000000000000001026dfeda22285f45a3025fbac2184b8482545ef76117f2dc6d5f27ba868ea7125f95587c36bba2a8343910c7e9091ae00000000000000000000000000000000031af3147ae2d4c85f64f16d546737dd8218325f51ca1498642cdbae69bb5193edec901c698ba1433c0c547e217901af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167be99385d7ce93a615efc1d22e11c44789ef828836da3e666a372f8c32cf6b5d602c4b82fdd6aeb53cc5beb850fc96000000000000000000000000000000000300ecf977e41cb01f4d9521ac0a3cde9af237c4bf955d651279d6208158abce0d47290952946a82e9cb8e8f04f76b68000000000000000000000000000000000d6395fdbd07667917b592f18aa48d21edf609b593b27f480fc5ef9a0533bc9bea6c6b0d9e7f4c3092a5ca75eb64ed94000000000000000000000000000000001247acbfd3dadfb9b42dce312a307d40e37ca8fffa1ebf483f5346f449d4609e31eea3571d7d68c6ada08c86f13856b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000627c03f89ad7f78d278bc55474f9e037383486e83d58ada072b2613feb6d9c4d531fcc9fbd0e34d20bf15764c7feb1d000000000000000000000000000000000e144f1bfb8cb28f49d8d7bdbd83c8beac281a97df4152bd17bfcb5c3e72c482c1b8a5047d5619fa3b4f9dee5f667be000000000000000000000000000000000150161d39f6fce15a73c20a4bbd21a875562d03339ab55509ab9714e4352b121fc7832096691f96622ea4f43339b16d80000000000000000000000000000000013652f1b11475fa345c51735914013fcd0df2ee71be5203fa69cc1071a2cf352bfde97b78c819fc6b516c0394b3420521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001607fbeb5ee534f226ed43d05db846992e5d8b0fc79f3ef0cbf2463373caf022f3ad3b8252e1b73ac49a6e94d5c651d10000000000000000000000000000000017b8cb020bfa3356fb8f7c7ec14f10de3fcc54eb7c958a017f02dc91436d7477e873bdc38f788cd5c0fe97dbf5400895000000000000000000000000000000000e51485a12fbea0ab00895c2a2d29d77afe502c54764bccbb02a0fc98d9639246755cede24ad293bcaf6f8821a44f1450000000000000000000000000000000018a30e69b692aece041ea30f5e7016647f7586e70712f1c58d6aa89d4d75d34776cf3b8c30738e9b41dc760414310cda1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d51f2ef6ab5468504dd55007cbd2e71f812ea7fdf10c8e00462cf413b3e8126f42c1b8fa26fa46db1865719e67ade5d00000000000000000000000000000000109a861362d8515c87cb5237f5bcf666e232c2a4540a6c2ff9db7e4a3c0a0d191641915bd1ecb8d1fac619bd991d1a060000000000000000000000000000000010bd509edb0c3327e4178816abf369ba51cac6feadd352f14bca366175b7d91612733bc0d0a43b2758a64aea18cb82bb0000000000000000000000000000000004dadf23688c4367f253d4977f0ef39a0d6da3da8b9d9cca9fbf29e1613a6c8f93ef996fe89d4596cac1e549788d453f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001002c22ac5f90bda3a214f37ebf9d783e6e7319ba617bf2665b872ad05d27c36376c87b80d3f841b8ff927cf2cf8158000000000000000000000000000000000d0ef9aad16171f3832b8dd42ca4ad8f70c240dcaa2ed840fe0fa7e018cffb4fc6c8917e740e3f868727275b8c2eb07900000000000000000000000000000000131de01d402e8f3856225105e3a57b1a6475783c88136b3051d0b56bd0c881b0718ccab8a8ba145a55ec75fc984fe37000000000000000000000000000000000163f65ec4cba28256af978c07dc258f4564255a6c028931e5b80879723be6a8a2cde1f040b940634827c41a24f8f67f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151c950ec89c6a17ac000dd8de3b7b71e9d6cca040df38a2c045c2cab7fedf772618725047a7c10e1916df2e16ecc2550000000000000000000000000000000016c2d6f218a5eaad677c58a6fcc6c4e9fab6adbf3556245f69cfded4ac96ae9b734bf084006208d9d1c3e189aaa757e000000000000000000000000000000000126ca5b3059c9e1b7d3affc4fbf979ec4f8166670da304a61d0eae5b993ebee226b97ce497383fd154bad94a7cf39f190000000000000000000000000000000003c1b024b3a9b6a396fe00ecbff2327a21f0d31318a64c9b620d3c932be1b7b3e895c6f6b1a4cb5caa1fd82085cb86181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ae685dfdee9af24ff299148a0cccbe4b4ec68179c048b7969c6c7ab6e39becaecf88cdf54c8069bf99f34a8c3fdde0000000000000000000000000000000000fced4567e6a328feae68b91f9db6dfd50b7c382e3c48002a5f9a692e99b28352a16fe7416f260b4dbb0dfd893999b0c000000000000000000000000000000000cb7f7daf2a17aba3496461a7fa9d643288f46e26c5a0dda60e53af7a4b79d95699bce96ab2d35255fbd7d392c0b7158000000000000000000000000000000000d6ddb11f6720fb63bf69f90a0131d0d2e2397b0b9c294f4f3bfe5fbdcaa4bcefd979ebc63ffdb1217e44bb5f549dc761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000de0a8981edff6100977073b8f9f66047195cf16820cc7687a34ce3ce75f0ce2efcf4d2f15e8ec02800c355d0119f39400000000000000000000000000000000107a34c8605f711bfcebf0d3376d65a9047edb8e00a80565342dcf58f1f96bb0aa046ec4778e29c6ffccee8d08884be40000000000000000000000000000000003ed2ba135df2e2ee1c93f735ec475adf299fdcc46170473113b4c0a6c43f587db1d1e8b8291343a43d3460bdfbb4749000000000000000000000000000000000cfd85e1f117cbef0089e240ecdc62cbb15747c7d0cfb05291f9cbfd0c1612dacdf3e55fcfdce3cf9ef4db92669158f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cdb53466b02008b2b0f84740f4c05d3762f273efe7ec8b2503fd364f319ad97a715ccd9e833dc29c71424b63bcba19c0000000000000000000000000000000019d167d29bde6e55c7e65ca47069514bf86ef3517a3180d033d64f37f7e9665f8a076d86248156a643f9ed1862775dd7000000000000000000000000000000000bc278eda03903d161032dcea257527869deba9e8add3978f9fe1461a17eee7474f58dab1cc13ef30cb2abaec1ac74020000000000000000000000000000000011a5f4af48bfef7e9132c98977f7754795ebd62a3e0433856d55881b9c6fe58f7cb84beaa1bdad79e54f9aae736e703e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc5eda907f8e7df718d783b80a80b626364d348abaa9fe827154eba6a4b854733d32204e051c9290ad6a83c6999d620000000000000000000000000000000000958c1040f210a636f72076dad2d10a305fc5fb908033e8fc7a958453ae0ba3c186d4a902bb91fd2592196ba6a8308150000000000000000000000000000000018e9a5b8687c334ab67d4c24b3b9e4e5fc3e3b65638e1c41f7888b582029ba4069864d1127c4008fd3f207e9f9a71da70000000000000000000000000000000013caaad600b4b9b65fc05d4ee4ff77158bbff844839a0979ef18f25e68356f9ceb68082f57fd5c7f0a2a5c70f5dc4e081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9e0e938b405ee2877255fc9eef70d264bd21d6ebbc7b4946260d7fbe81e67dd481eb0c16a2c439f07aa4ab6642be16000000000000000000000000000000000b62cfa4812df202efac51189f25ab9bc09c6d877b4a0774a94d830d44a5b133e66dd66c865eac32a444903c10c0a37500000000000000000000000000000000040ec42488043bba3c44c1f25bd002eeda76280b1c42027f0db57c23998634d3ae1963194a57afa3a3412bf6e99f9871000000000000000000000000000000001448596144db1930b323c1da7df385c14c8e24c46088dfa88450368a7bec9a1a9371dcb39e16f3c5b9c3c99ef72ff1a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bfdb7c92ec77dce4902831a9b19ea91df6610c97cab6a62c46a2ddd61a5ec95d766162778991ed2b5bbf074a0b0002c0000000000000000000000000000000019123ca1b5e08967b9315b33e9fb34645994c2c2213f89ae36b48a7ab8eac567784e0269793171f6a70cefa4c549002b000000000000000000000000000000000ca81300f7ce8dad4928dcc837b06b74b427bca5ebe52fc97eadcfc122328e6b0f09a7c0ec66ec9b71c1516683b22f12000000000000000000000000000000001627511de7e9f2d2af38e0b5ca15e25aea87f1299846b875300d77346afd1ed1e47685ec08e375b22d3506b053a595071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078c6ab24ff115480c0f0e607831f85895f8aeb2100a1602d716d11a309063b7eab8b2f6a34e384deab016eb365bd884000000000000000000000000000000001139c2fd9caedd11470cfb671adf4c5914fb4880fc698c32bcb50ba8aca0e117ebf3c436c687493e1a03e178a0f555b200000000000000000000000000000000147bb6d621ef12c03b4aca79f93523a488c1eef9e82fd65dba1f5070af7bbfce9b52e8979e9bd6705142273e0e0aa26e0000000000000000000000000000000009114eccef8cfea317dbf8cf6bf7b09cc0b074f458b9dee490ee991d00aa9f4a688eadf64370815cddef502e032cf8e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003754b8f215266866c673796a51492615545c1578b7388b4c61e19f18ec6b9c9d2b4a8cd8f01be05d3b10413a463474100000000000000000000000000000000130c091f20eb463803705f5527f64b67b1abbab358bb3228bacaaa743b8db16a604bdb0a12771b0f9e3cc21938b8c91400000000000000000000000000000000080cbb4f9e69b77bf0e5777ad0e6add6c162e18d0699b27379b29aa9bf33af8aa3100349268a645d1f188401860676fb00000000000000000000000000000000162145aba6c09203b6f155ff61d434294dd90a2a2a2b5c6c3f594fef670b7f3553c0e122c46e1d03b0e6da477b460c221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118bd1f30ca638448536b76fd5521e486ce185b233a95623cec1bb546f228a229e51709cae32a71e791d0241e508ef14000000000000000000000000000000000bedfbd2a373aac9443a761a6f30d43426c0963c624f918f95fedb45b814044606e43436d1912731c28175605d8954ba00000000000000000000000000000000165f1d110cb5cfc51390f470d835120575f8f98931f9cd5fd3ea68a4e57017faca7c248d776d62e0bdacfca6b142d0c5000000000000000000000000000000001311fa6c7c6faaccbdaba38278d587e2dcd4119ce2b73001630f6b2331fd42e3c2d4ba8de3a44ed16f3b634634f04fcd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004bf1127e6d95a13fa636f9d40c5411d426e6408cd3b3727130075483f77688074493ebd1206f5591f2e2f604ec5fb670000000000000000000000000000000007e65289d44ff2e83dc806783599b88a6f8bc97c64036a65376ebd2d12129ae9cbac72928a5d5e9f98afb32d7c83b99a0000000000000000000000000000000009dfd75b2d0833cc5b5f8abbe7f45ac5db11a18964fa7699418daf2c169be391da7a3ec0eed882664e6682ea0bd3f7ad0000000000000000000000000000000007b25a92b227cf1f715b00f4dd533afd2baaa06dae0176bc4c7b5cd25a79ec648e65553a812d80849827190ddc678ea61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001116cab8f8e33cbf79ae02ac214983a394355c9e7d9a0f296c5943f048667344449009804c7bfca870b9924eeffa5347000000000000000000000000000000000fdc3da06a6d3be5aed09e9463f4b56dd4401769b89e868f08b0d11a47bd9513fb7050c69660e6ff18723beb543f02e0000000000000000000000000000000001928afe0d892f8ec9e40172b56a4ce09aa49ef9b41c7f0ef4426ce9f8401d6d06e35664c926e873fc750bb69366e7e890000000000000000000000000000000014632d1304075974d90aca417ea48073898e607acf80a5b05c09767729f6601b81cdf2dc5c923d5790b58c181883f9c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f000f96e6752fb8e8865d621fabefbb8635099c4839d4af797db158b3a6a4ba0c8cc8edff5ec9fffc637a9180a522a0000000000000000000000000000000014a117e8595207889f4a7a786eddaad1a08420e8307434d4f4ee54294ce841bdb5d797479bfa981125274e999d75177b000000000000000000000000000000000f9c1af2906873337ecb6d0098498987eb6789c8962c141f8f7671cbfd56ba03a7de70d20d5fdd55cce4b8275e41a8a1000000000000000000000000000000000eafce8cc3fb77ef17fe45a5483fa76e141e9f8f56b8dc6b0656e4554562f4804790bef4ccf3a3e6be43dcd99816668a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6acd0b2bf66f847f37c1d8c7b83d7efcb7be52163650f6fe07e8f857344830786c6bb99b0115311e3a14171b085667000000000000000000000000000000000a65c3e4a1bade92daf9c8d3fac5c5fac6bfe3081454d16ec178c5d03480b54e29edd8412d4e066f58e09009823dab5a000000000000000000000000000000000d4ccbf3b6a1df77874153c0d6ac75b49ccc9f920297755089bdb6ef496e088409c4028db914b5ece11b4fb54667e489000000000000000000000000000000000626d116c34943527f77fefb43589d7fc2a0184b842eb768d923c811790058f1dc2044a8433f1462ad7c0e59ed6d228e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c425f567bab793982b10acb8289d49c5844db59ae63cd9931da260458c8d545d251b639d359177b2b393ea5839230b0000000000000000000000000000000019f2bdbaf499e5048d391b1a1e3a066d2967bb255cba8e7fe0ad51436ecc0e6b6b37541e6ea1f232574e9259d56e59c2000000000000000000000000000000000c93384e282737220f2cd98ae97ebe15b387e7b1ab9ef6cd1c2094bf0737f6680b84e3d45aed64caadb5b3b581e14295000000000000000000000000000000000eaf9ddb54105337f9a728e1d7fa210765fe2f2f1e0d5aa52ffa110137384a233ef859d1667b9a3aea4db87a97fd3e701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105b4374aa10db4d0c8b0157ac945fe219b98203025437ddca05d29060a351435c2f9ae5cf9e17071e7a43944b5e3526000000000000000000000000000000000ac410b47d70f567fd4fe1a65203e27fecbe49ba4357acbb9c4ecf50b80245b2e69cd0ed5906012d45c717c041f651f50000000000000000000000000000000003f3560b6e61b58d6f6109e6a152d248dba4e41b2477a794ba40d3ae1311e4f4662a2e3e6d7b9ac65e84921148e3e4520000000000000000000000000000000016b6dd9d69231df27217acf3eab8f2d3399e91a990be1561ab67187ccc2fc12107535e734d3050f6d9c2f22dad9b738d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b337f152f9c24eef68acccc9ae3c9caee085d5c5fe26723b0d9b8389ef71d6f75d391067a913212b30a83d8a484af100000000000000000000000000000000061d7ef5a0ee32c264a6cfb9239b6e1255c4d0afce6cc63f24ad9c2cdd800dba5f5b5aad602b7cafe4588504030341f60000000000000000000000000000000006062cc2b33a680bb1aac8f61d0ddc4639524733f42e50950fa04451afefe8c21c1aab2a2aa4b2244c4dd2968a9d349a0000000000000000000000000000000006da48fc92893d3f9a67cb132ace648027bb1e9e148b993a25347af62b4d1fb95eb233f7bd5c6f4131051b08df0efe361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3a9f342e6e9cc17498c680f5ee464eed2b63a922746fbf3dd8a5bebf049526706968acce68aa425aa763451ec3d5a60000000000000000000000000000000019d90a9f6f24ea34e5bc22e34aca3ea9c04ac66f004089cf48e36ace78309c60d8e60db9a9a2065508be992ae094e868000000000000000000000000000000000bd9ade5f9572c3c019b24439cbce753ad59731bb88ead40d85dd3e19c447e0cb9f1323037bbcea3c2b365cef48fbbfc000000000000000000000000000000000d1827e8c1da0f25ea8dd88d32e39e915309a090afae6e4008cade7b4d9e85fc11a78cc9326b45e17a4857158f1187e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3b8676004b4e51b8d5dae14a02842d7e03fb0f2afcad563299a67612b8d2c6a496b2b429db19d413df9cc0b5e750e40000000000000000000000000000000018d2e7213e234390a0dcb74bcc3d4bf39b05597cc3e2dc321dba601f989736a554999e288229e3128a4d304a32894d6b0000000000000000000000000000000019be5a5ac86a997888bb5f4624b6a9874d6296aca3101efea97193e472900119085069d293b5f92cb7b44c371dff850f0000000000000000000000000000000018fbfbad011fda2cb17615d99cd43143ba768f3388604df385b84ca2caaeac79a8d14c13326bf25af59a87799acc87ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000158335feba235ae619cc60ce3ee8d12b0d96cff3a7c1006d38ebf079983f7765f8ecea1244f59ae4e5bdac376c9937c700000000000000000000000000000000080ed9a85756152ad208c793bdc975ebae27106ff680c584a6f598962129b88b6f403582619c0568f20c347c8f4e06b3000000000000000000000000000000000673378e8c9888932919bd70e24e62835242fa0f210a32719f252485b86e938da53bf114189d66d1cf7e5a01d49c30ad000000000000000000000000000000000e718e1b8c171357c5a60cdbc534b5531e3664db2b7e1952cde878c791fb6b0967d21ab6b4902a4e12fb8a8a28548b9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bfba909ce9f84150415553b75c139a7fef75b160a0592f0afa720937c5f10285a8cf21a7eaed3783ffb3375b1fed6240000000000000000000000000000000010844b9e27d1bc8e107aa5fd12810b863aa9ee9bbd24d62bf73e2a231e3993c4ead08fe7724a58c89396b5dcf6da2d6e0000000000000000000000000000000008ed4c7ca4be96d8ccb392a4eb7ab61d1f0a717688b327513b34da93910d1630de5e7f2ec9b7301f9d87c4f4c9b4bad80000000000000000000000000000000001a3778ebeb6d8d896f8a72ac0f7d71fb60e442d3fa4e59339155c24ea81a06ab1c02ad348a05e5f0c6e950a6538110b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a1e4a2602b49e1bd8929699ae37f5d45bf1e9f5c154216161e53e253ae143c941eeaca47ec0eb56657c72d89fccea5000000000000000000000000000000000ee51efbb17ec2aca4b42042fdab789e595bb2c1fa3c39c67e1749c9c92e03c77e9266ad071891f2de1b69cabe2d28f00000000000000000000000000000000014324ee89d4c1cb1f128a4ded80a63ef271cde09bc1c1e9b1d4d4310efa599e7fe2d448e48533a245fdf04910e8bf1e3000000000000000000000000000000000e15739e76cc2567420de9739763f11efc2fa2cc1846718de7a8d89fc4c40af00999ebabdab65e66083642f1680c123a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002dd0cf97101c5bb63ccb8f340af277de5e0584f3c3b4475591085cac7db1123ab254c01bc2e082e89b067201d2075b7000000000000000000000000000000000dbc679954d0c48fda994fc25d6d0a044cd98b944be043bf1752838b8e892de075fcd76fbdc8b83722b6e82050d762370000000000000000000000000000000011048a921d07939b7efdb0c57d452e5b0a6b7f0c4fa6c91147442fa4c1556a1fe5cbd15f234ae64d40c6cae2fb75c6cd00000000000000000000000000000000181db8a577109077b6da18d5d01f919330ab5287694467168d99ede2185033460f86016d96989e6ae5f32c3ff05a26b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ff50cccbf8abdced8ee12565eacd721b5834f037e8ace716670707cb82b045a0ca2729adb99f6c3615c164d50c35b3000000000000000000000000000000000f13075033ef2fc4c74de4ccd865998f6b9826f9f4aca52b84b429e21acf2a5c0f7b2c921ad3c66b9ca51ae8c39a66e6000000000000000000000000000000000317bd3ce1e743a827c12c8a89c6f7e654f4f7d2a92d16c3403145c1c02c89a5f3c8c558a4ce9edaac615fed0f39ecc3000000000000000000000000000000001606a62751f73cb6fa4645094994215ee0a85797bb033b24d9f1c2ba6f851f9e52d2c9b9faf6fdb1cb8dde0aae373c121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001910db38a815e2fa228ef6a21ae58ed9be9c39e041e2d14a4d1d7c8548e874de47d124b8d80cb366be8255f27bbcd4a6000000000000000000000000000000001357497d0ce360df0a4277970ebb0bce99c688f7ed08cbd7072aedf76b13926eaeedbe6c6ed7c4007b47d9010ce63303000000000000000000000000000000001072297bd7bed45ea6a616351462fd25b5f7b4d05b04809d1c169dde548f84cb67f74a243a3eb579ad84f32b485aa8b50000000000000000000000000000000013ac185bc16c65075d680000706d760650139e59933b9f5b88cfb2e54cd686b8dc9b80cc2f73311e966d8aef1856158a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ea6ea89e1d2fb8622a973966e7dd61ae6f561f881fd73c96eb5b877084305ebb969c54aaebe8c270e397083b3188c70000000000000000000000000000000014817b91533af60c29764c4e8f9afb55d61990f28d02c0817016006a2e4da28065b4c3d93ad9f8664ee644422cf7ec7e000000000000000000000000000000001096f1f31f64dcb84671ce9484e80d6114841958b66a068e7b905a0578a9e3d261203dcf62e8b097fbd27ebcf8279547000000000000000000000000000000000ffba6fadaa13335ce0ec0219e1dfa78877823bb226819a4783aac88bd3911ce3f09adc8ffee17e0291b99bceaf312cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000075d33b8c71bcbfd368ad0b57e5d0deb7059ccd4ef60e82097dd6311e2d24dfd14f205a8867c77bf19df85d7e8534e6000000000000000000000000000000000041a3a6a3821996f58630fd442872e3aab26ee2525c4db82ed49894fe39bfdffddcbdd182836b027e0d7824c4df716940000000000000000000000000000000016d507a9b31ff41fbe3f77db15845b872de8fa205362f730ddbe07b1b7adbb2a30a2e3a26000f5895f0105718f5c941b0000000000000000000000000000000008434c0b05990d16e7fa6c90169c7aba6d668427d514b3b2846da2b17fd3df3b236754a78f52fc2aef041d7cb341bdf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001752888f3f4fc2091f260cf2b514e86e60a09b5e4b65d66dddc97b9ac6ae63306d5bdca12c6873be687203adf7afb8ad0000000000000000000000000000000013eaea9eba97b2f707622fae8cb46bb075420ec56152d2ad7b013d067d337ef8cbb65c5bc697a699228d204a1b4fee18000000000000000000000000000000001459d872af072da1b207bbd77a5499e661b68b8cac646aa8768e2b979d184e9e764eb05a0bfbee7866cb8fffb58bc9bb000000000000000000000000000000000708e3ad8f488e246876cc98449e1d8d71ee253777b52d700649866f1994c2fec1e022db240983688e273eb5d8ccb34a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014913800445be4b67dd7c4a5f01bd10b72b875429aa7b3b665dd4bfa7402336f0df6e81cfa555590677a4e6b7e3f12e30000000000000000000000000000000016e1b3ee069b5199b0acb75f3c41bbb4d3330f4d08c826c38a5f58966379a6cff0633ba6ad0cd63871fe1276c6298d0d0000000000000000000000000000000017540d56d9612b03aead601d4a7c6c0dec229ffb0145c1303c35798199ac61c05a84bcf8d52ccd364994def9c3b69db70000000000000000000000000000000006640ec7fd66f3059377b1e9f1b221256bf93bab6f2a32e6e3c8392b6aed4ea573de5260dcf10ff4ffdd968ae2a0cfe21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000099073083ed4ca646d5ddf9de0b74af4448bf7c7b1b50a185e630ce37a2725c599bb3cc2ba2bff3bfd86b950e5ff83d00000000000000000000000000000000168c9b647315cf0a4f037249d51d6db74eb89dedae9af2e092c4b3bef08b247e7175cf9b8be46ae69319d52a6608a396000000000000000000000000000000000ae5c29f68910065df260823ea082d6716f47d444a4833267628357320ee0dca4c074710deeebc2d14da127f4386f0c800000000000000000000000000000000189332205cf856c026294a63d0bffe8a033e4a342d165186c111da7b93f61495843863db43c561f04fa94404f12294d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015917c2199ee06fde98e0b2f752ad33824548956fa29d08c313f2ea76df5d7cd1ff87cadea3be11ba884c2b4532075a5000000000000000000000000000000001178446f24e704f70f7c0dc1906561f94eb3fe4d19300f8cba44085d90605d09c4f73363bc4f6b92e043b984641f965d00000000000000000000000000000000061a421fd2f833da0aacab23106fc4ef83f5a5cb69231ef4bcce0ac6ce6f0ee559630a0ac69602370aaf627bdd93a02c00000000000000000000000000000000150e2261b714a80df3a66c7c941b189cda47d1ab111248f0d9973ff09e6e7dfdfaa647cd9d2c46e3c712ebce1730775b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041fcb3ea259e62fd94740c2ecc7b89805345b9157be620a2b11b69a2dc9797a526ade8bf22b21ef483a36fc09e87a45000000000000000000000000000000000f79b2d6a07c8b481becfc673835cb0cab0561fc22efaa7d12f4f86f93628c2641af2ac83f77cb2575397a4ddbfc915c000000000000000000000000000000000fdb44a327084dbc0a0826533923e3b16b1e9c159059f011b3e453fe152fd4c6192b66dafe7e566c799fbe756325f993000000000000000000000000000000001218604085494539799f72acc0daa7fe29b565f80f4d589e17eb82fadb8d7ec2fbd32786aeefd44d066c2cd3b5cdf2f11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007cf0832fbc4c11dd9071a018eb79b17862abeadd210a45a4576518f8850af5307a6962b104d1d09a855c96d94fe0f5b00000000000000000000000000000000026b740f0f0f05e9b88e3a068c973b2df967da1a0a1adf44c434d4bc47ef30f560719b01317a589cd4ed56f04fda92d500000000000000000000000000000000037b0f64c4672215ee839188b3555884885d2bcc1d1a61032b17012ed8b5afd1cde33959f5c3e0fb21fad19fd76fb732000000000000000000000000000000000f43c031e67b97c09774799fc325735cc94cf2c45ed02185118c076a2f86a4b074ebab5563b02c130f9f757856774d921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c899cb48482b18e3b5b0992382a26ca06c53b5342ce5a02fccc51d90f53589867869c7b8c1bcc71426bcfba6ac3fdf00000000000000000000000000000000014435908d66fecf9baf3274960c6d40d66ce30eb03084c75e17695fa127f335aec2620679c3adfacc7c30b80d9e2f6b30000000000000000000000000000000007ced172911f9c97296af3e37315d63da0a1cce84944a33e4a7330a185fe816aed14617ed185591dda3c003840ebfaa6000000000000000000000000000000000b86862d92115712d3116e8c78f0a225257f11eb7f14ef752e93f456e0dc79d2fa56aa3583b5271db0adf2ac0240b8861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ba616e789b84f95a39a65ebb3200f6fcc893734f568a9816b127a7392e441e6fa11850012feee8aa247327faf63e590000000000000000000000000000000010c040d69f55e636f82b58d0db13bb34db192ceccb2d6d2067e7c392688492c49116041ee074f1149f7d009a09e36aaf0000000000000000000000000000000019114d9094c833771cccdac6693d51c2c7c1b4aa88ff47cde479fe57651200f301b1920de7615f7cbf877606329fad3100000000000000000000000000000000164347ac00c50c8deb8a3ae98d27ecc5df2b304c8ed287efab6177973d139ea2bdd5c3fb19a6c14fa5c7bbb24e24f7651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c98e8dad75ca42e980705f690014ea2c9e65846cc9c3ee48fb43a23442ac88611a2db11401e1aa4666e0a3d6eb3315e0000000000000000000000000000000009ccf597d764d0721fd5275902ac3084384334554ff6eefec90c791baddc1eac9aad7d7b4b790b9986b0bfe98289175a000000000000000000000000000000001905f28719f1954996dd4c25941164891614e477332dba865857edc85a3c243c7e07d4c343b9fc5c7f7aa024a61ff115000000000000000000000000000000000023a0e9905e03833e0ed31c99e2fedbde47516f4611bdb3a696ce4b2c1890645c020365279edf8560ad5da75345fa811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d82eedad1d74f255fb7c9742078d4dcb51aef276cc6a59040dd71fed8c3513f50c73afcee25cddfb85cec36b4301c80000000000000000000000000000000009f8bb5e9626a113181dd00f014b132ca3b1a76d83c40fe65b2525392c92ed1024fd3ba0e80a5da317d20935519c556a0000000000000000000000000000000010fdf591ea23576378363d88ee2c1b77715d6a59e00afa2762f11b83f6e3181a5de387e4cd1448d5cfaff578a48807b8000000000000000000000000000000000f0589292eec654117f961ee5fea9e04e3fec4d503c93fc1da94813642a035adaf4a69ff7d01a031e6c0e84280803eb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000837420bf7eeabe7f8c4a2a05c37555fac408cd8efde02d3315526c482c592934bc426458084578ffc4037f79af312ef000000000000000000000000000000000fbae4c6ed4ffcb5c3d09109a95ded66a1276a787f919561db0e211bebcf4d6a68fde3a50b4d69bc54ebfaa4e823a3fd0000000000000000000000000000000013fa947ea81006533fc77de51bf6ad0e4314c9e96be064af08e5c0722b187a8368bf5901f491247f815c17f20f57cce0000000000000000000000000000000000c8b818cbe42774efbab957f11ac38c452f6087d661794b8562ddaf6f48ac8b57fdb65887e911fe1a501099fb50a89981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c6db3b2bccecef2a5812941fd3e898c7b5cc09d7d8e091d399616425f8bf1cf5125b76e3afe0f6f35222e74d3ed0d0000000000000000000000000000000000f784fa3f16c45245b9fad88fc02d4b296f00f28a1f800d7cdb5bf70a6b7751fabebe40dbf2e7acb7c423f6c7883fa560000000000000000000000000000000012f78d4b0d4f92d4d506fe670ac221efb2e88f244fa0eac46a16510d6402b53844575b77229e0a9563b901726c4911670000000000000000000000000000000009f9a6148d9f40fd71f97528b87a81140fb3e53f375a9f2c070e338f604c97c90acae7d346e627894219a18b378b55901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000187aa84ddce0d93b6f60d64a4fb02badc2d470ff7d4ad87f30e3113e0967346eebf3791984c4c0e4267d96a17deccbed00000000000000000000000000000000001896b60aafcf0572d17d59d7fa0946ef6c9605b69c2c0df0718ad375327792b736c61b4fa62c4b7fb5e19182502b20000000000000000000000000000000001536a55c0834df904f2febdce0ad87701adf0ee6654087f43700ae3ce7c5753894c8c6bbe11221a4e7b2c6f9c8b121b5000000000000000000000000000000001961d1273aeec167d23e2308880a23fb32f1fea5eabc01d5a01ae6cadfb3191da1bfdd55c3fe9f442210454477209aef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024e40160806508f174c96aa1bd3b8f94c8c2a6d77e57543e9b9a921f76d273375a67a2d655d8f735ffbb7e46880096c000000000000000000000000000000000e7cee95448c9f02702310cb4a5f4ec39a8f9445b00709ce7538566e3da308c76ea601920d8d5bfaac9a4716794211c80000000000000000000000000000000005bdaf41c7ba736a454c8441c5fe08a73052f579c763d867a557e6f9dc07643bced8217c8aa9f14ea408c33135b2100c000000000000000000000000000000000ad7065571de6f6fc8d3bf4085954e5b9a7511f07df9ba6cf848921b0e785259fab379c92c2f88159d2ac29108605c3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001371695d1fa94486c347f8cdfef256e45a1ef0e02950cb0e3a0b6116d304774dfe81815134e6a47f448e93d77f872010000000000000000000000000000000017bb4224391e03813e2317bc794a0de456fde494f270d50df1bfd4779834417a50fcade50c40230f1c49f970b83cf2d00000000000000000000000000000000002b6a799280d902a3b0c388b6aee31dcd16ef9c1c8c5ca689a6e6b74e8567ebdfbb54f00ba69f624f5c80bd5336d1b8e0000000000000000000000000000000005030c6bd9e0d929e7e75624dde3079391bea3d6eafaf7dee07646332cd92d96a0ae6b2c2ab42b58a47e2579e66fc6271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097e13321d25d900703476cf779448540f1b13bbf4855cfb33fe273219b340d4593547f58bc80f764800a8cf053f7de2000000000000000000000000000000000cf9e9e527370480c464b96045e78c0426adce4b52a89ac9e455bad6f239b028fe0ae5aa8629c62b727874428013179e0000000000000000000000000000000014a313d0c6d8c7ee5e3b8ea2c3ce0c7ecba7dfb17a4900e268ee1d0629db4a6b36846217fd74fd6f5b77dcb198b54ae4000000000000000000000000000000000551edbcd2191b4dfb1847b0c47ef5455b60a367742c3681670317fcdca0228b30793cef3be39031865d011b25d929301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000164c6ed712557b843f5a034fda2dcb67dba167e3ae0b4e07c2b7dd5528f69475d751ad2a75657831932d11a9b440775600000000000000000000000000000000060b222455819523f4d013533bb6d30929edaa6b24f7cdf1cfc598118f431786b06438d1ab1ec7c3874e895d81ea71e80000000000000000000000000000000007e6e99c324773855810cc1b269687933bc9215a2cbae14f217a433c731a562092b132b3a5d1941763ca05d08d8e2a3600000000000000000000000000000000159b45de2af00d9c014da15a9edc535dbbbfd6f916037a369e2d8e8ef4573014cba399f2253b31a5b418af85ad02a1f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010757b5220c22f43332a305d424d22fc36d27e0d1d22fdb88f4b06e63f7b4000b1207e1944283ecd20461df068e730070000000000000000000000000000000009fb363e408456f4bf8c48919dec4c2cd5483b175439294a91877a14feee2e22a657f435150f0875fd794765ae5a3a10000000000000000000000000000000001859b0db7aa0692a052803f2a484b7b92026d19cdb69d42a325983d67edd6604134e0706335bfe54ac7f1473dd16260c0000000000000000000000000000000010977a6d115607af211503888d2c61fad3d9c5e477309e5c392e124665bfcb1c564dfbc49ce51259d62efb8b40f7ec6b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013f9aca2b5fc5dbfc35b31bff6bd2970945995075df2ef5dbdf4c248c62856994cb4958a3e7a4f13c014809a61b2071200000000000000000000000000000000181c436480255c1dc070e0822eb1d57e78090e63229dfe4c651a56f84c76a5747696fd19b81af76201bf05621bb711160000000000000000000000000000000000b38229b8aef7cf55c2838fcec8c938e79b5912fc79a6551a925cb404aeed00c491d935e1414019fece1d30bbf82ef200000000000000000000000000000000111edd5e76c6c1be6ec8d1a679e53b74a5c093b5361c8cd1ceb3893c81e5ea3b23657d6b84689cf973b8784ea53958511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6c904d0785fe05a57945b23a50757a05a1c06b6a9dd4c8160bbe17b0c43cbe150abe51ca99cb996bbd1e777f0f6b0e00000000000000000000000000000000034a0bb9f53b6c827edaae4dda09166a9c68e0dc27503bb64638049719de46e9fde92d4f6a582a80f43659ce9d4aa30d000000000000000000000000000000000c7d3d5f43bb643ce937be3028c744d380741903d0eb2926c1daed222edab22365c55970542ed1afc65304766a901bfe000000000000000000000000000000000d5caa56d76c314fac3c624f84f6863f81455c16c47a5a272af4ff09524ff8a077c7d2d5d4b2a8d8d2c88b83582e545b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7a0d86713f61d447f7392d2c440de5b4448cc20d18ff649dac7e3dfff1880b424b0920034eb67404c5c41936e84c190000000000000000000000000000000000ae83d0b1dc1ff9c180abf0fff030ae57605d0c1d786f02e7346b885cfc2952e6de3db17d34c6ffad0ab8109ef532b90000000000000000000000000000000010756234b4fe401763fe4e76bc75d8235fcb043cb77d854246f2408272b3df5728f874a7eb9d6f2f2ad777ddc37c7dd20000000000000000000000000000000006d91067f71dfb7ef83a34724cc10b0ee7a2ced2d3720382e46091edf645d1ad167406ff8929a349f6cd06d7ddbda3ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014073e86b2990b9d220da0fc00d2ae6630a52a8f535de8aab971d0e521537c538ea461769ebc6393cf5f51630a3918280000000000000000000000000000000002259e9ee4fff4e24764c3177d75206de5b7179b90c7c5bdee4464264adf393fc7211c619ea0834406926da9b708beca000000000000000000000000000000000b4fb0bba50ee27380e2d5aec6c1d603f2665f5394b6518d051277703ea1c75bb786551b065cc962e60120e277536fd10000000000000000000000000000000005f6043b4cf155e86137d25664826f50077028c91fe350c5b47edf295b368677256c9e399ad4099877091ac1573b741f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff564af0ee4b31fd5ee56e33e63f75df0aa64a3861287d1e849c9af73433d0539157a1af2787552c37251e7d345d9920000000000000000000000000000000014b6709020de73555841ff3b01a454b23075542218d172518aac55b6bddc01ab63e65422cbb4d42430ff12f7fad6e41a00000000000000000000000000000000026b5b8a9bc22540f02eba500132917ed104f828b38cdd46854be42018689b0d52445ace9dc67806ff7b7f84635969c200000000000000000000000000000000083d370a1b82bb3a4f2149f27c59bad2f0cddb90ca28ccaad867e202b91bbb80cfb93b67202fe79c6879dd3cf3c3600c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a5ee512c097d61df832be506a76b4bb7559a5cc580cd946abc03bd99e964bc675d938b03191c9f6254d013d8d2ac5f30000000000000000000000000000000009c0ff98ac1dbe590a8af1b5d094e86aa3a3a9f1e92988b93def87e9add14052c152e5057ee04f695191c4350076776200000000000000000000000000000000195b0b31a599638748725668fb3b6f117852482ad5462121a2c661cde5043db6979111b0ee46ae075d43acd2322d2d730000000000000000000000000000000019860f5df2d9fbb120150a85e0888c092b89269a00f992665c6809b7627b37d025c088c6be4febcfa1ec3baf4950b8ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108e144a5ee2554ee0a6e14f9be152914c17d063a0f1e1168796aa36ab0f64b43155314c2dea756a9e1899ea9a9bdc5b0000000000000000000000000000000007e75959cdfc19a6d23e6e4dda31f15375127cd5868b4a12a53bfb9f73f71ab9989fed6c80cb2efe9ea93fbe195845f400000000000000000000000000000000042df5c72b66683ccedbade75ea6548c12c51088cc804ea194096d7a4de4ceaa91c7a130976afab451b1a8d44962fb0800000000000000000000000000000000045c95178c37bb1b0ee9dab3522e67bcf5562ebfd115a82a9717ed1eacdef20da49ea87324fb75a2cb0c9493b11ea7f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7cd0d8de1c803d7332d0db23f03d950965483791b2386da9fa80637f4bd664ece71cceff95faabf5fc398c747921550000000000000000000000000000000012b6bf384758da9a1baf0ebbf43863d4d0fb3737ba5e2d27d73b41fcbd0d2ab9f655bae0df88d02574066c26ad9552860000000000000000000000000000000019435743f2abd08fde7e4497bbc1ad4c8aaf26f6978b0a60558bca2a48c279bee9d8ed00a8ebed4f61961beaa2c658ec0000000000000000000000000000000005b6e32abd2fb6d6ab084b750450e2c534e7d1def6a6ed36a3ec81d5f27e26c0e317d9514d368b1279438f102b8538fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ac65d65e59fed9da765ca3ed94e4d832757d961420ac80ebb969dc391da5b65a0e04f5aaf3611a439889599197f5ec000000000000000000000000000000001909ed1729926833cad2c38b42992c47e496761ed9e67cde8d328b3125a7bc7a2c6e046f63203e4354fd1c61e213f5cc000000000000000000000000000000000d0cf89e34ec73c96faf2f006923b963c1eeddaef92ac4e81b21b5bbab1ef77afecf93f423a5e350efeaebc2b0e059a400000000000000000000000000000000013abe7f3a20dbffe873260925c72a3b4745c2e673cf05f8ed59f06b560d0ad9d380e3950b880fa0de05f4a232f26a311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090769d359ac8ec162851f631651ade4bcccd8d116b1a49517511eb96571dbc50ef4034231aa49563bfc82d90a801017000000000000000000000000000000000c7093f63d9d73409c6332ea941cd8691436adbe222c62acb59402bc0ca6df0426205054cfe2c27a9e03e788e4231bda0000000000000000000000000000000019fe0998a0cf4deb1e1de4ed8806c9bfb9b746ec8ad365c2ee3511e72e4fd828d2ea431cd4d6dc1d5f89c655fe0ebd810000000000000000000000000000000019eb8bfeeddd31649711702f81b2a1384c3592baed2b404aa169ad594f96b69d80c83bc2b206684b359f36bae4e16bf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024122957e3dfec5ffb2637c1f8b6d912c983e3db7e3d7227bfeffcbcf0e013ae57e03a9293bc9fedb9b1ecd0b91975f0000000000000000000000000000000017a224ecfdc6f7e4e8e3bff0c81a2bfc15bd51181d875ba3c2f8cdce7fff2c1bdd388faa26c0a99b100804a8f705440d00000000000000000000000000000000036b03eb3d1c24a8c98c63abc081a3f948d95b6164d0625f7c7c0068b4c325c291cec9cb85ad30e3a2d1760e6c0897e20000000000000000000000000000000012602a21dec118b24acac7d9a3d4e1e7154712ca184c4b643b4c9cb3b04d9fd760ba0d3104d6467544f328c4c7b243a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a954856119589afe89aa3ff25a7529175fb112abea4d71d32da93dadf8b5a86e38c5816eabe729517bc37a07ade95a0000000000000000000000000000000003f7edc857c26edcb4ebf6f34feaa4013a67782f4edd76826cc0a91841403cac5772e7406a60033ac3ab66416906c14900000000000000000000000000000000063cf811071daa91ded9ee1dfe5bb2dbf94ea05f8ba819d44e3fb9fc7d56f413a9719bd075caebf12ed0df959809eca300000000000000000000000000000000070a3c9a9aa79edfbfc2e18e08b6f527c1fd23a4664ce8d976ab5787cb7a4b8e8fef6dd6b19ff7b175e069b23be940731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6f1d991ab6ba65d097d58cb736c592efe7d4f9365ebcd66a37c1c9ad1155eab03576e4da2e42ada5d7d7d8e9be29d70000000000000000000000000000000012d654dcaef0afca1fb609daf1f1bb165aae11f97e59c88765021eb2bfe885c9ee00a52ddde4e5073c5bfeb30d0d1aa00000000000000000000000000000000000ea7c891cd5e51618eb2ab7b773a4a787c2a1678f57c20de0517815d7fb70e974d6c9e6fcc05f3f575fdc3d46e3f47000000000000000000000000000000000048d02d1d0a405a947b14f6425cc781cdd6eafbc9a569ce15dcf9ccc42137834fd6bbb2ad65ecf8db1482a48c64dec591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000bab387e78f9394f4df650a9816731be88d7b1ed9f1d106055a0387966b99e58143d0f520c04e2721664030490661ed0000000000000000000000000000000010bb3075c1c08443008d3142587146566012550832aa6ed4e41dfcc75eb7f363719485c2d088483e5267873c25c5fe0e000000000000000000000000000000001669bc2ae7e7294195795f3e47a675c39778e6a61d839307d7290d976e171cbcbbb02f66e6d7ed3a94581197e9edb2530000000000000000000000000000000016c2d8416e21478335ef5e7230189d1f930077690585ccd642d6925c88fdcc839240ef7f7474625925be1bf2b17bae741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191f14203b564fd6c2c4cb768be0197c8a11bd21ecf7948458bcbe31e89ec153d0655778ced8ed6906a17c83b8c6ae920000000000000000000000000000000003023b0d5cd394bb62d9c4f343ed1a73924269f14c71b52b81b5d4e775cdeae618635ab47b4d548909c2623c427daac300000000000000000000000000000000146d979c06e1347280698d81bf0bbfdd821b2e617c61bfb8bff72ce8d45188ac3adbb9425a28f182721961dba5dcfa5e0000000000000000000000000000000013983340442ea5a707aca6139df906c316d230bcb0ecbe97f63e5e078c480f31e49a730ce12c734c353e1868037570b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040c0b02a46f3dfc6cb7e2db63c369ae521c90aedb00b2c0b1146bb9481e4fbb2f80f59b81e392e4d66f2ea6ef34cee10000000000000000000000000000000011eaa51d7e042300d9768c26b00ed8eef5222004cc05a2bf71ef1c510da00cfc9532947ca807d3c568c8dc4e1f2fdab8000000000000000000000000000000001559a0a4a4050f6d7123804ea775b0c5683e39da0823fe5ebbf771760ff5a8a08a01003ba72b91df44365483456b3b2e0000000000000000000000000000000009067766261610cbf5dfd5c8141d12c4597edacd797146120c2d605944c6a58757d19ce96881faf14211a6f9db1914f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161c1d18b8ba8fed10863e5f7489bbe5ba86d64e357427075d3336d7d26c604b60bd68cf38cb6fff8b5a85241fa35cab0000000000000000000000000000000019816e5c0b26df636cb97407ed8855e9ac04976dc4e6cd7b380dc2ee499c80183723bcb7144126e907f051750bc6ad610000000000000000000000000000000001cc0b57708112486a7438b0c2b0a2cdfe18a7a200b6967ca7b8d6766a8a7519e6f6a7dd26fb5ff8734caa0e52f0b562000000000000000000000000000000000c0bb26032c50e4582e7cb631b54afbadd4dbd288f144e29fd67706c60e55d0c8011cc43bf40e2c329eef7dda582e97c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df2353ad63b41264e649dfd712e45b2e9ed7890f28fd50b355159ce067bb34256312ad788a1c579caa5ee0c331e2fb6000000000000000000000000000000000d9bb27d5a8e79b60eefb8625c809e2bf767e68b18ddbc439d2ff0e9fd888ec55d055731b3c30dbb71af2e8188797ca0000000000000000000000000000000000fe65849378b854ff69abf4e1a217f3bf1ac4095ae7572fd773de822aef7ddcfd0b249ab5dc34c627489544863ff17bd00000000000000000000000000000000173274fec7bc9abc6adac1620d27600cd361d8bec1c50e0f81f5faab221c23c8e2047c88dc52dc845cbcf0e7557069e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c43e67f5134e9b73b8c2d2f44f0d8e66b561f5e49c670d3966dffbbcfd3471258bc931fc441bfbcf8743718a2d97a500000000000000000000000000000000013c83909e34a332d40b84310d664b7d1000f5b67c352bb552403ec7e6791ed20e3b2e627acd5d43462b2a5e8c4756cc9000000000000000000000000000000000b7e7b1b9bc484d5117b93a5b9a6c6a4a3714ea54a220e0e38f31f8aaf97ef6738118cf1f8de76f070db27d56c0be9910000000000000000000000000000000005f13ecdaeb40cd6b71a5e0f5605b5c10dacb000165c038fd48241b4d85fbe3b880960eb3c6d239f3f8712e26ef509ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000fbe237bf204bc7b36abb0243af064820bd9505d80e31a1f7beb74c82bd76295895e055d13676d6e432b18af81882f000000000000000000000000000000000136b3701676b909c50ed5f757a863806bda73e64aa78cc1c5b5cfd8a6f4897bf3228237e18d325039e5ae0d30fedc246000000000000000000000000000000000903aa04553b4c71208927331e98e6c42110da7c86f05bc85dda6f9a3e0f6f207f2ab94069f401d1e072fc05fe00c12f0000000000000000000000000000000005a0fefeb20466a76d325f04faa24f5734d8fa557cc9a74ddaca1f283ecdf88c6c018cbc01f9f2feef5da71db1bd9a7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffc6f3ad6373b90bf4aec29056caafc0486a3e87c1eede2552fc266c43b7b29412145644d1e87f3a202e9496db4837b0000000000000000000000000000000007a94ada61c0cbb8921ac9e38fd66d3200f798295432a39a9474b40f3cc2d0f24957aae89e5433d714614747f1f5b5e000000000000000000000000000000000020f55981f6d148029279d24577332849ee60e7e9457723bec470c6ba69cce4d2ddef9781063855160ce32e794ec14cc000000000000000000000000000000001831243f125e9270100483f8766727c34e01e52323026be9fba9d85799297eebebffe18c33b89547ec944260c99430851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a585dc65e48c8890c74f000f7990a5a5ab89d849296b679ce71898b1f1e6f97392d152d430cd4ae5fb7daee7d07d3400000000000000000000000000000000177d94b2d9266cfa324069cbb4c341f08cf027346c8b8249d207509e39071e04ce8d70aa7880a1ae0fed509f8c3feac200000000000000000000000000000000112e81570b8f39024fe459b67f847d7122b3ce28f22b2aab80b1fb4473bcbd074d8e12e287faefa4c8728430c6139ab40000000000000000000000000000000005e6b5dec7d1decdc42c14b91e6a4d468121b8f111a7b2072bcb34a8b13b4734593520831fafaf4ce6178d3d80ce3f9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006138f76ed8eed9de440fd118ede46edb66c6a616c0a1640f71119e2ec99be693b1a5cfd70ec07282f76df25b8af2560000000000000000000000000000000016735a7a58c2c38226a096b65fd6aa9a508c3d4add600de29666fd64c68009b46498058596568d326ab73b33507a5bec0000000000000000000000000000000014885fb4689476067b26e56f8cc60d4797648a675ed88b15ae50c366bc85fae9403b54ceaecea525d6e8bd249b1e1ecd0000000000000000000000000000000010c798c1624623c561c251dfadcba65f01d7f4ca9da34ff6ee057c0a59d5f12f2534f668a905af62fb6516cae46fb9b91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000306e2bdc27b78d82da73694d88126809a99ad3059aaca44d0e721bb9abf44f571adf67323209d10ba47c3e4c76568e200000000000000000000000000000000117ee1240b7720274811689acc4487d951b7ad69fffca8e0b6c026e0be18937b37773d9d6c0275353c73a0e3a28d1dd5000000000000000000000000000000000fa6c0eab5b15c5e3a8e1c3daee2a67005e4f22420a306ce458d5afceef5ab6825172a94e3988cacf3e18beea0a700ac00000000000000000000000000000000028373079f51e476c556e4a50be844d8e41db6fd059ac2614f339c239472bdb1aeafed47b931a4f672322893e2dd285a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c9170baf2c611d94ad265d0f9cb57af0bf2b72d0cecec91b43b229ad5c1c6b7aa6219e4abe44d89896225457a8e915000000000000000000000000000000001827a249ab25b2f317f6cfdfe90c8b8c444ac0b32b0c4dad70841d54ae8ad055f890b1e4716b089b0325617cb42ec9380000000000000000000000000000000013e96db93c926e93601656fc2d63ffa7bcfb697a0e83f12a60c7bff997ef7696bbdd1ce2de65c7966824163fed96a5950000000000000000000000000000000000c758dca53d785b8b3310816b1e252ee9ab334946197fa9544878c18372b257ee61eac1ae75836079c65cf33622d0a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffda2ff763dad43d0d7a56c612d810e50db6e8648a0672b1680bb396a0709d8bd1c980a999961eb9dfd0a0f814f231500000000000000000000000000000000157abae6416c66f3020959c42a71b4d5ad76fbc9999413aca517973db9ad7ab7ac6e954949610129653a8e74a6d348860000000000000000000000000000000014b11367f18e78867d1f3ae681dbed58e350c4ba6c9be075ab34a2b1749e4f650d84abcd99ad2f33c9b408c501d7637d000000000000000000000000000000001588eaf9445226a36459378d3423c3aac666d5a8c0a3ea732bfbc5d6661cd39cc486389fdef7a46745f0a8acbccd29771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004d1139d1df3c85e4da6c15b9464749c49c6d3baa2c8fa1b610353ad262880ef7221d703d11212575c61e6376593c4860000000000000000000000000000000010099ebe6d81554c4889028b01cf5b986be147d69ae94b2ce1fc12684b17b4a82e1adc696633b3f9b11d49e294032db700000000000000000000000000000000196ca0167a571cf4eb744dfc1a39ddb4194c074d669bc55f82b20f76dab6b21619ad7ad2612ed48420478561e62dd9cf0000000000000000000000000000000005ba778dd30fd54413d74efd987530536e126595494a2b377a3d3b1d47be7e967a7d7273602b3033e7b697d6cfca5ed11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017eca5aba857534fef740e91fe61adf26da89768eb974cb3ecdb66e21216b99a72c41c88477a9f00c4c9d19468b510c6000000000000000000000000000000000df5272ad64e8602f0b7d03e3dbe34fc16d3c078adaf2e089d6ae3d11ae02e9af2785a0bb11ddb2f40caf99119fde8460000000000000000000000000000000018d6a774d0955a764abfe80c5abcde4c12e72dd4046b01f475175092cabb791661956404d22cebc272e354bf5b3133f50000000000000000000000000000000009d0c610edf48d449e762bcff5b487b7cadf177bd7619ce96bdc92b4843531f141c864f8511a7510334aaa4975b3876a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091fcd8c9edefd53787331797963f9dbf39df879ac418c8825fcb3425c74009c3d6292d8e068688b3049cf05bbd0429f0000000000000000000000000000000012993a4aaccc2e1dcb7c33b94cb7b0d08fa333913004c6245497b763e4576042488bafad29d5911b2168d730a1fbf62200000000000000000000000000000000103dcea329675155e89d772c253cf04a660881e7fabecb4c226d4c8b912998712b43323b015846ef92f1c9b120915ec900000000000000000000000000000000038e53a9413150b7c8a1a118f2714ce045fac51945e9f216c9c3fb0cba914f67b3d3db9f2899277f8203874b6c7a83f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a1847c3ad9130d159e48a89c596eb4b39eb6e5bb64ab89970787793577d25002765210cf5db255a7e24853722529e200000000000000000000000000000000121473b53137efb57317e89ae08961c9752c5ea98d29b90aa1fb6dcbf8cf9f2a10510f049fb9318b0580432521c4db55000000000000000000000000000000001293e7ac15e5447bd1a15139bd43325cec7b1cb7d97dbbc1ad00f2c8a201222bbcbb097047183b8b83491ebfacad68be0000000000000000000000000000000004a6c289207b3ababcf55457da0cdb78a3bdf83aa194ac3c2b37ea924d3c5e9da9bd2bce096c066c8e5df253dbfa66aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000119e4eb01df72bd9ba964dac23b475c2fce5da9be34d50d69afaf835965c46584bde125a674c884db58e21ee724d5a61000000000000000000000000000000001081282f9d052e2459f6e63b85d8adb7cd78dd56971ce2140a6edf29e53a89d7f311fa0308ef3329ffba4f8d8d660465000000000000000000000000000000000e96c5011858843f1e0e16f43ba8df284145e7bc4cf287d87ce2a101288ce9aa0b24fa90836f78ba0b33ef0c3f81f3de00000000000000000000000000000000101df9af40b7db25ed888951fae3e75b967a29489b2071a3225da848d19751532f9d068e7c6034e19c2dbb43f305c01d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbb8519acb4a38bcdf5667b2a8545f10ff88c04b7843a54526d2c78e1a777720e2f1d24327ab44e9264e0a441c949810000000000000000000000000000000010615254777726ab4588cd91e44f746004a2f6b211a2d8e72fec677c9ff03de201f4dd5ba6402414e8ea13da35e3eb3700000000000000000000000000000000183ddd54c5bf1f9fbd06de49931072c37b8521083d92282cde36ac25d6cfb56061c1fd8b4dd05e97a6b35afada12d07200000000000000000000000000000000093e32f236faba44159b1c33d2437aa2d2da3c67a8126ba86a41c3f4a4a7bd2de24c0bc58fc19e93c1cd415a37b183971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073af6337d2247ba5bd0c6c033110528f083b9ab67665712e6cc7a0308d311a7d8435dace8f9f64557ad0f1a0601acc40000000000000000000000000000000018cf2e780cbf7eeb0ffd2f170b49c169aa6e3d784ece12f7e4ea731e60cabae068d6893f0c6391b8aef5493af10694ba0000000000000000000000000000000008d073cee74a9803ad78e5c1281d2961ea287bc0eb93656b381cbc2d317c57b066723163f583b462916bc3f49b5205c10000000000000000000000000000000012e721203cc6cee14bb4f677874ef7714e69368d7d273ab6e2bd77b62a805435cd869a50cbc864a0d7c6cd649b3f57e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000051d488c9770ad6b8dd0bb618b02526fc3c54c7950111582ec2a5fd45ff825a2e2bb2004917a9a98f0200d52c055c8e000000000000000000000000000000000031b4322972391645aa129057a49ae7dd4bbfcc8f6034585cad806f0c14e86f4e566bea1fe20400060d85e34b06e23ea000000000000000000000000000000000b2ff770ce1bf9f84301ad2b3b2487a75950dbec3116ac939baac7e83b7d257e6f99979f9395f9d06cc15c2660f7495700000000000000000000000000000000087cc81fb51c6bb7eacdc31d05cc19e451d6370c25476572976f4192f49df127988077beb820d0e536e5a4cb28e6b7fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d20b5d1510263aedc8d286950c1c5886ef59a9a233748e6e4359eae5f41ce28045e95ac882dee7148b9f6c54416a7500000000000000000000000000000000146b8954bbdad63bfab0d53c260bdacda1750e1165c10b957c01362888b7b3ddf490a7c086e0b0041fcc7c4271c34c04000000000000000000000000000000000f6d3981b0d25e8a106a29ddec0fec8af95fd20392646a6326717f2270cbafc6abea36650c00b505702ca0d4118ca9c200000000000000000000000000000000038ac3666a19d681b6cb298b778fdbd1f154a80cfc41c9dae6d050359f9840b6ae5f55eb3d3a0fa4b1df7777c681eeb21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000165bf6b5a388332f425d6e369f4467f22cdb8c5bd42cb9f91d8cd09993d52289d4e2c1530dfacf3a822a498075d6210000000000000000000000000000000010f6a9119279a8f52fca8e0ae1f609ffd558b70be135d6c3e27bfc9d9e3ecdaa288980f5a1bbf7a85127198d19e4fc290000000000000000000000000000000004fadff49f07d0d332570c52370aac3e9e64d8571ef08eb2e9df777f7093bc0379c704b104beb67e57771c8ead87366c0000000000000000000000000000000008de32229e26f148933b206ff617d7b6a2a89902a0c8b5e00a352b0e75900b5152857632c00fc88061e781c875fad3271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015e8adb0e995d561e3cb84c681ccec3448dbc81bb52baecbf2ec70d92fa2a5af733e4272bf566fb283046716343c9c60000000000000000000000000000000018ac8b7be2ff56ac34852a8dca5b7dd93c75ac710277b95b846f1e1be05ab2af44579d55acf56cf84196adc88cbe7ade0000000000000000000000000000000004102fb6d360f719293136e5a1ed7afcd2a95f5faf52a6b5ca74230f0127c7bd70b6694ee2c3de2d51b2ac89a3880a67000000000000000000000000000000001097a9a5ed0789a9eebae5f1e06a638cda6e5441bdfe31821f55b6d3279b618bef3beafe44d8f72f5e448a63000eff501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000171d8df72e533f4489229b78253278d10c3838ac864270613fe7c02d2b48414ac4563392f465b3e20538fbc720dab749000000000000000000000000000000000d814b590d96568cca4c86f251024207a07953a0bb00e63f2498db22223419c2e027bea597981b8630463d2883c662da00000000000000000000000000000000035a58e3b8a9ad602e9d3c20773a2465841580fb59c486cca7b8fa1385685ac240eab9334742d5ea018ad03feea49d13000000000000000000000000000000000108396dcb7acc3cb44cd090bae59ca9ab3577951fe6bb2cf5d24a4dd3520b956f237a95b8f1885240160c147d3f1da41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019115d734ca7c4dddd9341144098b1f3b76e2018e24e0fd29384b8a43ce973f8514b8eded63284d32d6575bf7778650900000000000000000000000000000000098f6ad035f4a15e4beedcf7531a44f789fb3141f32a2c610b352153132e5fced6e1661d02ccbe0e3748778f944097630000000000000000000000000000000001f691e8fc5c50217de6d5458a500ee5930bdc2c1430462cdfda3a63ef5f0a576c4c141f15dbaa475eebebc76f800ba9000000000000000000000000000000000eb1a3b3bb50b7f00fb7d272816f885e63952e6281556d19c18ae3dda12f894821e286da45a811a3714c90a94832d3831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076cd4e0524f1bae32c15f3f626787a0d1d17b844fde15667f9e9426364716ad52ce75d537f472f777bd6e4fb91473c1000000000000000000000000000000000f9f2036039135539feadf46dea0d4fdd9fe6b0a5405eb1123c10be2688fec9381380995f54521c2ab2a4357eda5bac9000000000000000000000000000000000ec011f3c1f012fc2598411a4dcfac4cb2c71722abba66dfa43686e3ec2bf31b2b64d66e909d4b0573d1122ed00a5d0e0000000000000000000000000000000016f863a9b2af372f6656735cf6c18215ce0fecbd6c6c044334eec5e9ac3c4b6c84c307aa7a8fcd25849bae01f6a312251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000093d6b0da998bd9abdddb6d835b3942f09015c7d97349ed7b8368b20d806480021d368d553102942504032cfeec1334600000000000000000000000000000000094353b724ac4a83c91c6842541443171654b4a00a89736ef292bf61aa9d23ae4a0753b7486dc2061fe8237509181a990000000000000000000000000000000017d247da746446a7a8f7ae41c73a48c8b7ca1b50549e1e0ab28cfc35e8926eef3b22e6b2d060fea3d62599dd5e8db936000000000000000000000000000000000e257160db309af9045ed985d182c04a6b0720d12c5b030e32fe35ad25be516b64f439739a076af13b6e9332af1945fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058a251a92d10727fe08d3f04f2a5b036d77211b4a1c5782e7079d2741906a1d571b8acf83bc050396cf624c46a3735b000000000000000000000000000000000ca7354527093bd3eadafefd6ca855a07f6570eea4f11042db844bb172dd396c9ae47872177ce43694dcbabfb68520cb0000000000000000000000000000000014d4de2b61099557e8897588bdf3dc34f4e7db6729011af9ef8e2d0ad946d6b66d4d080d9ebd10ba950ca00c26acadfd0000000000000000000000000000000015540eb28e1d79bb61f3e037ca3249fe2ecc45f246dbc8b1c2d38d45dc16e56484ba5d61433a4e70bf9f094ad831add21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001562744906fbfb51bbbb06446ea91a5702ceb42f67d6956d640495b9764b1d7f780767a31e2f8273f41b62e0c2eb246d00000000000000000000000000000000130e51539984f815e52b2b344d7e1b20fc86803937e0a6d564fcbce7f978bce04dbb6576036fa0c5096356957c1873b90000000000000000000000000000000016b67dc7c4cf8c2f63a087f17fb5dda391bc93847f9a4b4aa9adb39e094e4d7508fda96c4bf3ee91498beaab69ec2d39000000000000000000000000000000000aaef46d58e246c8c8d71fec279b73cfdeb5d6753b5cd1c05c04f2354e351d4571ff30f2ca4df80a8533c0b03594e4af1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178b8e030c7dcfaecd654cb0302e3d194ffcaa714d76751c508472e745486fb7566d36f076c46be306a2e77a1769eb92000000000000000000000000000000000d0714bac7744a570928a237282d00cc0c837eb4d0687c404ae594ec6be94ed3bf998411bc5580da703078959b021bf60000000000000000000000000000000011c1ae0fd2ab07edc84ef4c847cbcf3f3b22224d7c52db891aa3744838da1c71c89763eed650a1b665568d455378025b00000000000000000000000000000000140ec30b8b229ee2d91f8556c3072cc43b2c24af80e1876070d2de0c8b82b89981c272f3ef0032c7c094a2f2251e4c031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d6fd8bef026009a7ec04ab092cf47ede0d1d522ad3c33da521c99247cc8f4489400b456c13febe5ecad23ecbadd2560000000000000000000000000000000017eb8401e5c78543ddcfc1c5f96dd07ade0e24bedb1001c18064eda866cc7f4e157dc1e85050e83b31f08243d1a6793b00000000000000000000000000000000148317a22edb80770bde7f651af49c4700d2f907a1f49c884c2744e50da893b92c0bd76c101f93ed7d2adc5eb13cebf80000000000000000000000000000000006a7725c10c82b4acd6238e7c155a80daff66dfc60258b93cebbb9e2bf14362d324f5d08b4c822c483f3e91c9b9426931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7bf2f2a2436984b7bd2a85fe840bdfa6a3e48456e2dc1814ad13fdf77d487904ec9b666b16d945cfdb8bc54060a6a00000000000000000000000000000000010cf79538515f7392124e939ac9deda43c379cfb8e74f06723fafc8ad69ec97753a9a2453f0abef688a1cf5e507f504d000000000000000000000000000000000916fa40306bbce7e1cfcbd7ede9cd1ad5a7b158adb351424195e7757ae7d732d3f5a728eaf7b1991db45d88e07879f0000000000000000000000000000000000b4e6707e73e7ffdb2a2e61f7811b4bef34935705c872859c30d14f52f8cbc63e2e269283a8d1583c1db132a1d726d831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000663e52411ce13fb94dae915d8da80df35c247a9a444326a82c2d8632ef5e8fe926b2b900a8c7b897d597a6fedcb5a6e00000000000000000000000000000000122349aa9a90337b2eb05257840145e05f5e51f63bbdd77339df6363f214978f5d947a70756da7eecf96899a4cebaacb00000000000000000000000000000000186fd30e62f6e9f799a501c19123580fd447d8243553fe6228ab9b1571cf3b9f07268d1918f4f06524d33813f53db58c0000000000000000000000000000000017a6bbe105ad54882151e15659c0207f5b8442213bc36621ca05ee03e1ef422f133ce59c1221d6aabd01f25b1ec1adb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018f4b4baa96bbbe725c195b37da2c0e2ceeb1095c89068028b7b515db98c83b44e986132f4a0ab9735e28f008bf9ed84000000000000000000000000000000001161e9d28fff8f7263875cfce715c509b13d880963dc53bac2329510f54d99323f171f66e04b79b93504dd11df1c52d200000000000000000000000000000000136d09931b17a6f822eb4fe0b2b535c1718ef3011d58813f87e50725fea40825feab1f1597aed5a24f9de143271ee0040000000000000000000000000000000003027df0aa589a673dcc9343163c2110dce0e4a10ac81684bc0bc97fc6ef0256e3393de90ac05ddc3c8eeda5926a54d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012a01637bf194eda5074f195bd8122c80ff04748dd98f3da2b13f893b3c8678be1033e4b7a6d17de73087dc1a4a4209c000000000000000000000000000000000c64d41fd1f5259b2f4b33f6beedc942e2851dd2f6addd01fb7dede00bbb374e73d1beaad2ba7d60f888a4433b75b06d00000000000000000000000000000000110d9b36155548e41ca1a74d3b3688993550162a853f4ab9da5dacce3f221ee736ac7de41864d343990e89d2b0a665fc000000000000000000000000000000000ab4ff8d6e2ab2972349f5631a7a09b5516e766120203a5ff8329909a883c4e0a3561920a09250ac285b7b845e0392641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000afa549faa30429e622335ed6b494f29e97e7bed0ecc4f80a03ed29e93740bb26f0f8d00b0d3a93e3698edb40fa11f78000000000000000000000000000000001025fc76d9318b2c9eff1371576ed6d5775dd762b3371b333250357a1186765c487708745a34e60a5c50920fb7c2a29e0000000000000000000000000000000007a220e67a8a4de1f22ac98eb646e115479a1c700befa3d70c4c33f5e2f770e5b457f59b3ed3134c98feb657e2d5bc900000000000000000000000000000000008c9ec26cc10365f6c276f01565a9210c85ced2b96adb368d964b0ac93f248f097e550cb2d48bc4d04105a677ddee6c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028aa73b70cc17b918ec5ccd0f29e2b417a34ab0db8e04522dd39e35a8be0aea3096192f0b81b60bebfce1d22f61b07a00000000000000000000000000000000081ef1737585f73f925eb0d0eb9c3dc03ae3e8c52f0f4069c96298eb747bae9454730b09edfede801368e32a4b59797e000000000000000000000000000000000148cbe1799cac79fe94abfd10e7882109ad82e7dd69925d609fac5f0c5cf61f0cf5de9bc9197d6b0fab77806938f6e3000000000000000000000000000000000e51a233c6065c6af57f613f10428ab17403e6dca59d96299e1e42fcf3fe86af62892b0299fb5cce06de93e3edb71a3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a8ed4ca0e944857a56aaa3d839e8b5548d6e626e8ad05c5813667af05ed776b7cd23095cd9f9621b9eb6c6baa8baca00000000000000000000000000000000176f456b9b28315c3a1a26d1fcf6e863ac33fdf55ef63f38d47f330b5c5ddf879c487b07f603c98ae3bd4823eba6408e00000000000000000000000000000000161da34fd9d8f29c356c70572cb9f90ec9d6a236f18c0464bb8d20e996112dede08ebc1f76c006c5a194386d6ef4430d000000000000000000000000000000001279e0305e842f0b34bb882b7fdf41988852ffbace2d48619fe0173f8819cb6fd27d5c2327d23a14397123750818267a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e970df2b1a6c9e6baf82f1c99c09f2b09e452e08ce528a900354f4d0854777baec0dae344b5f6edcf41cf33e8d8a20000000000000000000000000000000000c36466964f5e4e4d2f307d0df33805067858eb4e6d4a28c12e48a225ed40271706a57168c00e25309b1699861f31eab000000000000000000000000000000001727d33b75915553668558c92fd9f52c40091c59a17276cfe8ef32fb9c93e261443eef70a7dcbed62813be55ac5df63d0000000000000000000000000000000012df9358dab9da9e847c89455b1042fa94c9a9010c178baeb4dd8cb790be25741e450a73ef40977bb1c0e6b0565be3db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e1a7dc8e09f30c7daf552b910b1e6d9dce8c3aab0afd7fc8391776a42923ac23653656e1e6d28c42e31fa6cf16adfd7000000000000000000000000000000000819c3d53327d5e970fc63101edc0045eaa61061e30405070d7f9b474e530236718c96d65b170409345571684891ede000000000000000000000000000000000038dbb62f57eac2de66bbfa072dbcc6f0e6be3beba8a3ac0dceb4c51df86241689baf2eb79621741a50905616c45fa410000000000000000000000000000000005fd424cb23c095c9a6cb35730a33887a8eba7f8b701e422e5c88b617a48338131eda7914cec891bee983db8afe6aa5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071e06ed9d7ad3de3feed90cdd56850c0d316d78e25676f7510444b562a38dd2bd3c87f2b44ed1678901bc5385547928000000000000000000000000000000001682a9a59ab618bec193babbb69434562aa1f2bef691bb69acc2231f2f6e001489504ae6af76872da7df4b47c53e0217000000000000000000000000000000000b46205181a4f65266298631f1bbb8a520c783cd3597c019fa44668fe51ac3fc06a16810e4899bdfe801fa91535378c2000000000000000000000000000000000cea5aaa93ee5feb0af9b29af0e8015b8fd5cd13f45f4f1e740a521c3d90f5aa8619b2ac517f8b3b2a8f16062c33b23c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f9515b3aaaec44d5798a40e1fd7faa87cf5bee610c77918a8bb224cd5a064452d486da6a9c3b4b1a0f18fd4786bb91000000000000000000000000000000001696098bd18e1ae35068af30b352d9e31f610b7136faf976044c8d576b5a4a348a173a484e0a28234fe8010a4cdc55a900000000000000000000000000000000053c8678348b795eb0e9635aaa3b9e0f5ec2801c3f9d749fc26f225a3e6fac8b9794bdb44a8de2904b78cb20ee26ab2f000000000000000000000000000000000f222aa7cd6e197af805153876666a9d959139b7f22537873bbeac9b012fa9a832f7e3e70a7b2834d3fd1643c4b2a52e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000140da99410845d47701dbe9ce0e2451afb065a7a37c3615e954e21fb920dd7475f5e492ff850b71d91cf95b78e33bb40000000000000000000000000000000017851b713293f5f5fa4b97bcce3a28eb362f72582392bd90b1dea69623154a2f9907f93e895c579f3fb0e9f680c923360000000000000000000000000000000006b2c5837ae2c4f257ace740d2bac569c9d269b0118fef54ff02d2137dc770770a8dbca479cb8dc484e6862e8914528e00000000000000000000000000000000171c41e295db325aea6a21089da400811efecc7f39c5a2b7dbd89a2307454f7b364d289bb0c329c82af80607df78dabb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000003d4919618b8c093c2e3f1bc8766aa309723873337f58392a3186b6cae103df78bfd30366e3e7787a6518348f23f1b40000000000000000000000000000000014b3461ba810acf08b43f30f0a823192f09e56f8090da155ae617e008759ee31e6779d09e65ee178e7a0f935035598b400000000000000000000000000000000193d468f4ba46f577d061d9e5d13c9c1f1596d9be63104bb395f4b9f6eb46001f5d580d0859d84612212cec289db0f3f0000000000000000000000000000000009e9bb67d436ce09d22f1065dfcd598768954a8366b0665a21e3631ed2dab00b83eb560c7a418df005f86d0e1accedf51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ecf18b15b1913a8d62999fbc9b63005760326c68d8c1ab99abfec38bc60c9b98a6b2e5b51564ef6e852033d1b4d5110000000000000000000000000000000002edee3aee20b89ea1b63a8971a31da3cd78e5fc449f71c5763a22f9d932ed34f8f02309f6f27ac7f47eb35fd4440b10000000000000000000000000000000000793b40f5cbf4283110f0ab18db42b1f8e7ce8759937c521788e101417194502f2b0e5790a6fe13a5cf0aa53521454a200000000000000000000000000000000101c9542049dc352f7d7aa0a2ebcd204c916abf087f64cfe6dffaca3665afa6a07cc8dbda9e0cd7d6e30b89f6db5c65c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009da981994226d2fd4ef921154367646552d830ab8a603b63aa5966aec7dda6afdc26fe241a01884da970ad0a2394ce8000000000000000000000000000000000d015b1b7b90d26d65bc5f3cadb093870e0da62eb8412b28787e57061490224ab71be8f778213ffd35585c290cdfc5b9000000000000000000000000000000000de5e758fc3a95382f141ec7102cbc8bff65bb68cfbb42bb3d497ebb3726e0de2cff1fb3e44cedeff33e3b99150155650000000000000000000000000000000005ea02ccd8d4ae83acc97a8d7970d81515f3fef5a9ec48f5a8b2dda1f112ffed53c4cd9bf467927bcad618d636acee821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002466c4ed7b01e9779358cd4cb2df8176be3693c934446adf31f430425e923e8aa6fc5801b1206c1fc180ab51e79998b0000000000000000000000000000000009262e2c61fe866ae5604cc774f0cbf995b97c67901a93fbcc2174b11a72994edcf0f653be07e5bec20378d9c1ea1695000000000000000000000000000000001592cd7d93cca45a3e8bef8086ad6bbd2373c0011d818bcc7fa922c45403d6928ac6834a7c4cef3715678826db387626000000000000000000000000000000000ea86e8e3bb90103a24e3f5d2d87f38956f1589ecf40cba32361f64e6ee0d73d9a733bdbac7777fc06e0a33ea4488f531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000192ce668a9f162b8f3bb078eb2d116c65ff8e3ddf8813568d98a0d304362ff1d75504de2689d4fc9a6eb24371d8c0fa00000000000000000000000000000000056fe3e69b69e2cde9bbf303af9a37532882c0f77e87d68ab435d4b60e33cc19249b69dbeb90d4c7bd1ff789f96d5c060000000000000000000000000000000002f90136f280ccb05fdebf8a4afd566c21a1136b98dc875aeb58761ce21d6d657304c6e42366154d25831727b8541e89000000000000000000000000000000000dccdf054c7fa1fef8d413ad389ccb9a74f3a1b69473e6fba4063b71bef190bb2e8da68325a2602a3c6919d454b8828a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000553a9d57ff225c1251744b7bbef77afa32fcab4bc04a03214dba09d29299ef9a7f6d64eb94475453ec1ee46d46a68c6000000000000000000000000000000000c29b723a9efeb891dfb4d2c6ac4da7292d283e96cc51509565dad2623001ecda282bab0a15c966a5adcdd21be0e752b000000000000000000000000000000000d54498733fa68d38d0cca8f0d8f12a76eed3ba7057b448e80445c20a3b54b4d53ac5545925c923a87c37820685c37350000000000000000000000000000000019d2c37968b5b7600f025898310596cd736ba739ea16fdc07d9602d81e49448d88da7c5ec07c79886d8ddf663cfaf38b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000749f9c8e8a202ac6568279abba7981c94c2d81ef64eecc6e3e5cc47cb5df5ce536a2341bd85e1c1e8c5168f5bf455ae000000000000000000000000000000000e4a9d5e3205361ef8490d14444b4bfc0d2883333072f03b7f2d3f50607b4925362ecec81e2d7f0d3f966203492db7040000000000000000000000000000000000f8f96e04493bf61580c4882e4e0b2dd0e0c41899b2c7c2dca8e2426556b047724b8042ac5da4ea167d6790f0901409000000000000000000000000000000001967aa86c51fc1c688a1efcaed6dec94e7fd0fa3059fec629fdb3d816b0d73674aff57bef487f7d70049d5823fcd5a921824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058aed5f1c4d9911dfc0e838b9f19ec117613316a5d956b1b752b9a692790fb80dfec4882acf7bd9719464e11fd95713000000000000000000000000000000000b8fad375b6650daf07ad8524a177da8c43aa002f06a8f7df561ed321e7bc64635b0a26e096342d631ee1c28eb2d1f2d0000000000000000000000000000000019173f1014c8ba22214fd9b43aa7563ac47e3454349fdad5b38f4ad3b987b0ff763b4b51781f093a0e379763d6575d750000000000000000000000000000000011f150858655f94c78bc521c66a65d66df43c515ae503e986e06dd5472c19eef7f1f66e01539749c4a3d38f10e16b94b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e040eef71cbbf816ff2a6e97dcd2202f186a3422bd125502e8f58b3c763416913f660e0c2fe085885ceade21d815a27000000000000000000000000000000000584f38d9e3b117fc078f396d43bf4632fdc2ca9c8760e04fea54183745a3af347c06d3f9fd6485d57fb5872811b0f2e000000000000000000000000000000000c007681cd4aad14ad171d56d9ade7a979c533c7eacd3c67112caced46d14f810ed66adf78552a7c1a753ac45eda2c3b000000000000000000000000000000000c2574a5a87178a1a7c50c7c52a49e25af4bb9e80bcf5017255709377171ff3af28622ab3b73d6732f5c8abae199a1991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d1fb347504f44f3075ba9fc8efee0ad7af187deec47b23a484e12535e5a1e057b513d164339481bdf1b621116661e60000000000000000000000000000000006d60b4cba1a5ec145df68c5991598578d2857c5112abf2459626818dae7824548f0be94d4c994eb1998c6f6ef775ff800000000000000000000000000000000126aa9d653ad940910d82d4399c79988ad7cc11e13c1d01cd266aaabdfafe6adbbecebc2f2e62e2b6c521f1cbc99f8a10000000000000000000000000000000002bab14af46ddbe3568fe83a98dbcf466650b1f358061d8457ed862ec21bae8905ac0516e5f8112b8282cd137f9c34321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007d0174fea59346531a6f9c9df63e0fcee2fe66d9d26d51849024595c20b0e37bf780bb5382b7a1fa09ed92850133b72000000000000000000000000000000001995e537a78f043281be3e56cc5244a46ac65e96bb104b3e7334660aaf010f910f1f49d6d6f685640ffadf511483043000000000000000000000000000000000112f6ad4238fd03aeba61b6ded9f8eb215940e61645eaa5485dc625ae114372c96a90bf750a914e78e35b69dd9c55f8e000000000000000000000000000000000d76230929f88ab08d848e02585d75902da73376197d0df16bc8e3ede33a66580b37b007f64fb1ee76302b98006ca52c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f42bf1faa226d1d2011d769cdc180e5e0afaeadac3c3fbfbd4c6d7d051f6195698c71a718c3ed830f668a8f9a43da04000000000000000000000000000000000c94a68ff2a3d815b65c73f8b79019c0c90bc55d358d337c42cef8296d7dfd17b70dadee89097815a202c35bf2521e2b00000000000000000000000000000000052b39ae3f7d5b22fbd800c8c77dfb73cb325011584085c4d4d8190affd9671d5431af3a19a905a9c7d511db79bd0427000000000000000000000000000000001382e81c34262f9dbb0e16833d7412574de6cbaeb702e203c2bf64d6090863898dda51feb144e5b95703692f5755a7081824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffab82f4eaa01fde821cbccf7ca413bba724fab563037ab147e5a533c4f99595f6a4eb513af5d261e02302fd5ff43a2000000000000000000000000000000000cd4de9fbad27e66cedcd4ef2418ec7901631c05cc4d72ba6d3fdf108b159fac209ef4337f98b47309f2dd5d867ffe0300000000000000000000000000000000196402bc33c82bb2eb4615f2139427858b15432484ee2adac67feb4eb560a321387936d0c0e1f64ee8f88111b4ab1aff00000000000000000000000000000000096e2f7de7fd3f3cf22ff5aca99efdcbb6b5355d24e74f96bf0f6400e57571536e0bb340c02777bd103e1332127b0bd31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001775889c8c3aff9369bbf1a92ceab1b1de0fd7a0720d5ce437300023f7a9642e605662919df661a953ec2524483bb32500000000000000000000000000000000174104a77d2df75a692b25361faca47b16e04dfdd49475b88505818bd1f01907f4f3e22cc988f12f57335ba557bcb1fc000000000000000000000000000000000a7e16d4e5bbc86ef3238b8538387f8d188a370ef4bdc30e44c2e759760df78eb05203fcafb95ad324f7e02b8d1bdb420000000000000000000000000000000011e27c3159ed5d2552f597f34e3cdaf2318174ed03892109344c81bccfbf01fd322324a00a51cd66f3ff4773693a862b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f5aa61b6d11da86879ac53893e0f74314b791a7c597ca7fa4c0e0f6232235220272b4e5c1a42266ac75508b88becd00000000000000000000000000000000013805ebff265bd9468f3ce46a52977af96491f40939c0f99b727057037fa46514504680a757057d6b8d9266cf8c35020000000000000000000000000000000000c68bbdd3dbb97ddd79a56ff0922099268083e131843fa68c51f05f16e4050374806d4eaeacc3c6a84252d6ea80da83500000000000000000000000000000000133c3d15973efccafb18ef4cc65a64f2ea5ea1753b18b82b50a9282d70e8e88d5bc548528ec299f069d6f33e58156e6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078285b536cd3ed8d6d56ea3ad2b73ca842f24e29cfd58b3b1e48a2cccb152d0212abc03040d76893bcd0b80f0d60be70000000000000000000000000000000015ee6c2a8101732709db0c6dcfa3d6f7d3cfc2a6421bdeb3efb83f75d0ccae1663ef7209037d9ced750ef08d02d4a94f000000000000000000000000000000000e2b9e3dbbee317ec7a7d6dce3e58914b6bce7bc5d88b2b809b88deb8dfdfed5f5db56590643c03ab1f7c25bdd7162b400000000000000000000000000000000072b0b3acd33161c0b5a64dfc344fca2d5493f8cc1fca89495705c99829db60b158b0168d7acfbdcfe5e6780966855b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018410837b67fdca6fe90ed41b2016c7e6c1e1e3a9654e7673a893310ea850eb22f7cef09795eb7ac19d242e073497a9c0000000000000000000000000000000011d2c84dd7a198f9a7feb7a845333eab50f130d649c3c41d711bdfe6905c2649075fb22f3578a59abc8d7519d03f28050000000000000000000000000000000008ca2f9f5d53befcb82f50f33e40c497abb84db4489db52cd90b30004892608aaf2168c1efdbf6136a7fb336ef5a862a00000000000000000000000000000000038914c94061e0553223424607c9a2fa6073648367a84177d3b225bb350156cdf613805908500941ed0af1b4b2d910001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001004335e05f22dcddc16b676547f05c3506e0ccc7779a2286f8392cd0f53486f1ce626fd2f83524fedef81022962b52400000000000000000000000000000000174b99eab6a1043dcb718613b7107ec174389ad65bcae5d7db347250f5bbb783a3a93f1537005f59fde688d9dd4b829900000000000000000000000000000000008d2ab5b814fe56a7ec5df725abd3f57474181d1565b37f126de53f9b576ff7aa790a4c006f58283958742a39c56bc4000000000000000000000000000000000db257a1640668e86c1346d87d50aaf631578bb222c1a8dd11564de41bb5e2caab9f794c4276c0afc59852d781326bdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000807d75e4bca80850848161605bb8d663a0ab86843c7f844e72e2591e50032dc255be5f2cc861a1034fb619cbee3f33b000000000000000000000000000000001855bab65fe3c6f743f8a8283dbe70e665fa7d6eca033965a8466dd603f75e609a4fb34efa4bce126b70ae035ef10045000000000000000000000000000000000d433582fa257e610c780834806aa84487d46a7fc3c270178db00f4b390c1d5fa7e37dd2c5a17646a2bdd42b0678ef6f000000000000000000000000000000000a1204356667744d1fc8feed47619037cd030aa826ca86c2e457fe7e4384d2baa310e85b62917e9a62646a7962698e001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cd601bcd60a127592d562d7ec90ec95ff727c3f712872b2232a40271f61c9b11622df969ed462767ffa4941831446400000000000000000000000000000000136375639818ca53fa66151b66a3cd5c8c2d7c02ff2d244b57f2500b143be9c78dc0de9bd9ac59179ee48d102b3a8b640000000000000000000000000000000011f0a41746f628211c2cc5b4dc69023a88ba5ff47fdccc37a63cb8fed7d71fca224e095b28e22549fa1061f071247d6d000000000000000000000000000000000721f6ac28d8dc81918d9acfd0dc1c270b2327226ef1f7a28570dd6c0b20cab880eeb4e04203da283b7381f514bc437e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016931e5efc15bcd3cb42c2a499b609297e87aa20380877c98195d11e877368b6fecc1b7cf34422d84a59b9e34ab0daa50000000000000000000000000000000009eab1f6698c48f514548dd6697da5bb7f70fb2cd4c642dc239e4477316760e85cfb91d62fddff43a60c5c432a3e7a17000000000000000000000000000000000d17751a1843b99634577d6ad06a6fc531e64be3d69b4a446f6f85773c1cdf4e0c001e75378f284d36ee8fb0eb7c6e4d0000000000000000000000000000000008002e976538f21fa9e6c08f9865ae976f818126d4218ac99a21b9e46e43a087b52d5c4adfac3912a2d748179adca9301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000188b3c7918cec9938c635c93ec9be68f1da22bd1148c9eec245aed9c8a45c5eddba6bd56f5846ecd66f11d5cf96dd3380000000000000000000000000000000008a622b09b9f6394e9792381e735367f0a816902a1e03f03201a37c5dec0836518ad7af15de701cda4d1f06f93e7f9ab000000000000000000000000000000000be9c62473c3203be33614525bc9bfe4291128b7dc340e566ba2c1fae3d62a07139298da3f199c9d23beb6dd9a097bfd0000000000000000000000000000000009f66c82895e7738b21171fa8064800fc0bf8f7c29a94304896e37ecfa715a794d67bc2fd92e441940a0c0da819786071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024e8ec5ae4e6a10671d78cd892ad1c959176ae3ae6e7dba532fd24d6c93e80665be61ccf9912421fa5c44600ceec12b000000000000000000000000000000000d6feec9e73e8e980de822d5c99282101a94737457aabf18cdfa1db6ee08c0e7e2662f499f51f7e32915d0a6d639aa8c000000000000000000000000000000000f65a619f1cc78bafda329dbd10fa87020b79e199e9001fcb71598d3749cfd98914dc532e5ac64b307f3ebf413cab2020000000000000000000000000000000003aa0593fd022d636048d2da4aac9572e1e7f00aed2e7f17561614f0288e106e9f39d7bd036f2d874067b7a2abd4f3d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f782e0f6a0c821cb4857a9b8ced530f84d72c47f748337e28f3336ac9c9cd7ab27e98189f6874f2ff1b53bedb38ba780000000000000000000000000000000008f7f862470ca9fde7026de47b63a19150bc9643a9c35bff58af26e3260cf111f1f1eb220ac667e09e623e22fc8bf5b0000000000000000000000000000000000eaee1381a7559c4871075f396d4c94a823779ecaa78721b9eb87b1fff40b09e7b90252167651f54018ac6f00e6c1111000000000000000000000000000000000998af1a34d57327491a763171d65fcfa16e9276e024a5db0dc15b5afd585d2be74f04ac76bdb1c48a166043576db9161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ba3d97b3014b1cc21993c52db64e142b999e6b4465a601c47fb024d8150fb088ee3c94a7eef795ae44984207521847000000000000000000000000000000000e1089c9a02f037e96707f7dd7a22aa87603e0c20c2978febda9c1004fdeaefa9d594eb665f085489128a0510c5a9207000000000000000000000000000000001213395ebeeb024cd3e48649c3f9cdfbee182c589753684d4cf32a804729c33b689dae2c506f28711de5142106375dd10000000000000000000000000000000003d790e95e5548a8e38200becd2c9c4e5e2b7e6323c9aadea209d0ba4257b7822edcbb9e436d024a0b4745fb8b3d6b551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018886c20058aba8e5f065d3ba8cf412610228f7ee6e7375d7cad8fa6333c453b076e1cd84bdf45d13e60d929710372f2000000000000000000000000000000000744f24ea2a234caa355f76074251f6b08c86250ef8065c6c7d22b2e0a493fb4e50075eef3b1e18dbe2d404ab5b807020000000000000000000000000000000006b94c804ead83f59511acfe276908b23ca670c71bb434b9e4924ee83af305aec25d35a6210909891d8a93591991f5e60000000000000000000000000000000006eb1e523d3670f219dd581701088ccf2ca773012a09e8f26b719e220f6ca961748eb488c59ccdbc593817116b3ac6431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018de2eb6dfedd4051304932995d53d921bb42ee9f23189044e46a64d5f0236ffbc7c4e6e976f69a8ac5fafae1fa755b5000000000000000000000000000000000222ad5c50d6a60675822794ba6c0ca1622bc79bf2d9c99bf31d90245a6d1c78ca69d94e170208d820688367e645cfd600000000000000000000000000000000051c980111309cdeef42f2c49bc237afe7fbd30dbe99caf47fe05a5d5d156c54226b8c6326c6f15c313a71ab1fcac1ca0000000000000000000000000000000017b004e656bca2effe85acf6c74bd54025a2f5101c7d3ba8555b303a1121c0bcc144a837a2c5037a342b5ee185f89f2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002dc2d7dee31ec70af7db920be7e7a0301860c1c0cf0cdfb2df51307a17722f02743102d59fbd93c35b698bdec9ffff800000000000000000000000000000000127267625917b97475d75842e7000a84eedf8c5f7dd1195bc081a91d76e1a4e183472c4f5112c33273bf27d0e6c3e9ab0000000000000000000000000000000015f24487c96c9d063f0d77fc9e45355074f0519bd41aef22d49fe54565f62d0a322dc11f11c12ea67321488b6aea9617000000000000000000000000000000001796b0be2e9cb82eab98838442b972c679eeccb1c6ebc3e09ec3b31790df36a55ee0a51299e82f9487a9a1dca581c9291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130dab481733f795f53615eb4d9275ba3886556b2ccb1592bcf7ad344e72d2e3df254df66df5f43480c13c3e940dd637000000000000000000000000000000000371096973c7f529481ca98db317ed065c3ed8db284e33b6f530fb3419e6ef880fb415d1d5b866664c22f3f1791b9e930000000000000000000000000000000007ee6d74c425ef8dc9498cc712128d1f4790c5a1a1929e26cfd6cf32321b795738f6f014570a125f52310aa8287dd7b80000000000000000000000000000000007d592ba9cbb8409c485f29b53f2cda358cb0e3cb01ad401520c61f7c0de8eb9b40ccd031ce2262d785838cc0f50fa471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fec88aeceec8d7a550ccdc99c9e1df73bb98d6208286edf6460021abe4dc0f92ecdd77f836d509f6fc529713980e1470000000000000000000000000000000015543244453a07058a9dc04d3d3d7916d632c426958b67f80d0529ce219a27925d200899c2dc44404c4f9d6bd8492fb00000000000000000000000000000000015d129ffa40b8229a084cedea2097a3333cc8110761fe0184f77e400d945399350f51a43a2045627120a1ec390dd7a2d00000000000000000000000000000000049aa89cffc789daa86503b6f81ad398b4abb3e406cce3aed3454e5afc70782f33c4de9bb469f93faa4c43d708dcdd1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111c3d745df57b5c1cb9f8fddbb4ac59b186b12a9585d867cacbe74b8b51c26ad8df2c3e6be641ec4d44168f4d39ba40000000000000000000000000000000000735bcece0fe809aab55e85f52a5a688af3f3e47ea989a53fc8c45de02cbccef23e2fd603aaeb0a9a6c96b1a90a01f8d00000000000000000000000000000000118e13a2b2301fdbbb346de018e41c5ac2d55f08064047e8cdf7270a97b9e04579c52f68597f16ada4dcf0b10a2c073f0000000000000000000000000000000012cdc61d5c0161e444db495e731f966b2385345ccc7faf62ce880d8fb861f4d0663734444e8855c84f62fd22fcfdc77e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000145c8f7f1f1e67165374172bdef4bbc13b35659c19e45c6f5a88ff0e469f2b3ac207e60f43ac89aa06caaa1d01eae82100000000000000000000000000000000128fdf4aec3b2c58f0461073ab1c1ae3062f415e6e3c507793f0060a1b831f6d0b54a39174329e8149072f3272d330fd0000000000000000000000000000000008f4720b4801dbb425d3501cb1c7cb8b9fb937a8771232497f0497bdbca6fa4bf8fa5ba5dd5080805af6babef72c4ad70000000000000000000000000000000013d01bf4d28eb5a0d47ba8664968ce1a47fedcfb400f632eb7e7c9441344c5c9f66cf7115a15618c5abe83455a1257f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a734999ebbf8fac1d7bad9c580f6288c88aeecb2dc56bbbb78a1bc9a1bada3e9285cbd9a746d5c38fa56e7ee6b1b4220000000000000000000000000000000013eb920c4d49e4ce2306391c6ae3155ca42ec66451482515698dcec23d14a3fa8f588a18366af430bd3588aae112b455000000000000000000000000000000001680973fd55f212304b4794fcd73657f72d9c3a2a26f711dc992d7848d6b191d7f1b291a5a05b44c8be74853c52a583600000000000000000000000000000000138e48167b972cb0a6ace87bd447df069b08f01051868853819bb8b1d4e89da3f5df8ceac1e891fc6dde7f0931f63d4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180898b912db5aab074ff174577b3c97f3834d2cbbcacfeb6cd71d8cf8ec85f49c29b27e9ad8d35bcb0478ab3a8d03c00000000000000000000000000000000004029b306cc7f7b96f28bdb6613dee65404351beb8a320b5f42f6f0e3c7740acb5763652bafabb60a75ad4d49e868cda0000000000000000000000000000000008234e079d4f066eb4741f90307f3e23d082ee81fe83a866d8baa8e0326199b450e4a44525ec3b57e32d155923357cac0000000000000000000000000000000006041fdda835f8541dbdbf5c3cbcc1747bdd6058680e6fd28f0b6a2267f59e8af70af94b012ea5ea3e8085f02b4311701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016f797576dc02d8479bb040a39d65ad8a26896c4f86eba7798d562b62a1bc209cd5c393377b237656df889d7b55f3b7d000000000000000000000000000000000d3dd73f97aab7ffef9e6166e234f1249a0ee227e68bab100a7e5bbd3aa9bfac4eb539f24750848671d803b3806985bd0000000000000000000000000000000001d0d4a2455395d6a757262652fc8247da224a1b9ea787c73cf60ed3615f58587b556a228769921823d448fd8aa6cb14000000000000000000000000000000000df6924fba8acfba46b353e2d0740a51816196d0e02fb5229d7381f0fa17f65b976abfb21eaa15a3ae9a440d1b93e71b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab2a294c4be1b37002ac0a799d5c7029f9314a841e2b909f699b1e1dbca7f03fd25f66637c06a4c7550ac6fedbb53ff00000000000000000000000000000000156f9944e24b8a584d886f9617c638e94d9204bcc5ce96194cc61d438b07bded0328634a21a06a71e6e8b9902c9a34ba00000000000000000000000000000000020a455603c3db1da1b5a1e6bda6820a13644ec47c85925361b04b77ba7814c14c782be41093114078918f098a13639f0000000000000000000000000000000004a2a3aa9fddf69b08716e035aca16c6078df90aace92eff273228dba332255e2b97f630b29aa4d794839bb4f3becb4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000048dcc0699771555fd796049b07a73da3c51b659270920ca66005f3fa6a4eaf5dac3f915b96352e427639f873f650ab5000000000000000000000000000000000bc65e331774e058f4625b61cf204aeacbdd7949310f3eb0e89b723b03b0a927eac1550dba7da6f826b38107fbeac4d5000000000000000000000000000000000e7db32142d378294a614993f18aa71c714f6030e6e9a23ca584ea07b8515abd268e5b24912ed7132a50af40feaaab0b0000000000000000000000000000000004c623688fcc110c33295fa1a67c5625033945991c1bb61020e4274ba15e13f1ce0c7f61cf3d99f1f117bad16be3bcfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002761816f76bacb5efa092a028aca0189c9d9c2d7285018668de48dfb8ed0f698417031c6161b4c8683c722b9b767c4c000000000000000000000000000000000766b5b75dbd4330964f0dd53802960ab42118fe0addb13b021b439e1cf0c8ed83ea54292c547ea9e57013f97bb1b55f000000000000000000000000000000000d4e44ae0c1f7500a503c095f29202e427209eec47d0fed6a8c3a7235175024c10bc91b58416e0f767fb2532898401ca00000000000000000000000000000000002fd7b9e3bea99a7cf8df4d190606c1ae21bbcfb929f077ed6190d694fb69babac8ee6232c6984ba6ece7f53dd148fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001547cc973208431fcc7c9ae7139b82cec1fc2e0f112a459935cc93f6203c7c7399b674361c22da069182409cc6423e500000000000000000000000000000000011a1edbce56eee33c1f8ca488a4f6186634835470fe4b32614d978bc05f17447404b95928ec3f8da28e06ba1e007d7d2000000000000000000000000000000000cec04d085f4bee0e0b5c1b9ddd908681c87d619b166c572208a8d5cab63cedfe748bd5af2104225cea873e75129118c000000000000000000000000000000001482fcb626579a9ce02a12fdf961316c942e9fb80a58a4115b0e9c7c151ec7f58af4ea174f648755944b2497557e82451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d972fc019823e4aae36eeaef4b85caa5c88385a2d41597e843275b84a9f3e4bb698c8d3b56b7b244502e1e44a92f7b30000000000000000000000000000000005de897555c15efd2510243b70e0ab00252feb1ec0136551ec12cca1fa6c527108fa1c8a2b30a33fe3f3c30d8c4b47120000000000000000000000000000000018935f3b9a5630e88d791c32b1a4a7ea727af82d7dad934678f801239870b95a66f5373e1a3be98ab8f7922f7e21ec1100000000000000000000000000000000171648a63c99c19e2cbbc2a62e4180825a40ebfe8a1c4007e02a4159ea02a4a06e8fe8c204e1d13100df299df2c2f9bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084d464cbe91ff06d34e8b5be2bbab31d8460e2838edaedfb485c95a8499b4127bce7bd9b009abb917e6a7da87bd73fc000000000000000000000000000000000aadfdf51805e6536dc5a8ec9605dca01975a5e74b1c1b730232b84cf3c1c8bb33dd520e68fce55513d545d404de9bb60000000000000000000000000000000016765cd7ec4f04dd855a57f2ed5139db164fed1e8cb91700b4b1fa7605c7c2f9138197691fd12014a4367d5f4f6516050000000000000000000000000000000012bde76dcf910eb1569434f83fc1662606178b7518416739647d3721d4963fd9e77ee14dfa866afb1384b80bed7f86781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e04ff9af791c7a5549a6f32fd7017bd9a777fd165153f3d6fdf9266f3417cbce52c557364f54f4a5517738a7f981920000000000000000000000000000000004f41415bb88dd908a061caa3216bc2ce297c985634df7805ca62f3ad2bea3e3021544720f5dea5b97df60be7d94bfcf000000000000000000000000000000001484523a9da1fe76be8fd04fd5fca187109661b6bbcee44b6c11984e79c48bac2d0fe8c1617d1189c7904961c3255af600000000000000000000000000000000002fa75a986e781bbd295a2eb613de0d515769a090c5e43957d6fda23e91a5d203c9c5296c849d76551643d96a8673391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e01cc12acb6c871808d7c64ae26aac9eff4b9a827520eca39be5a9c414fd351a11cc8a36a688c1dd9deeb60b14619e0000000000000000000000000000000007686101ab3993c9d383f06350e18771205134a8611439db97edb44f024f397bf69f662b4303a8b8653786a9d46a5535000000000000000000000000000000000116858a905b6f82f225e588b846c1c7a7edf9bac0241c2828b917d100d241cbcf5bc00d25848c2471c7244c9e6cbfa200000000000000000000000000000000045914d3c4e48c5f99bb9cbb0716e62501f64cb5ea8a7fe8ee18add2c732d9386d05d00e4862f3e865185a9f0cd6079c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000998e7995633119f1daadf2bc5b3fd55e4f12f024fa965b29075178d826dac0fd9304c8dc3969ce2e99e3a9d8b4054360000000000000000000000000000000013b198108ee1a629ad004f55f742fded40cce51e36a5d6366e53c946a062cb2b40ebc7cddcee80f5fa1866b81f7028ce0000000000000000000000000000000015cad80c664792f0279e70757cfa32fcd4a55e4879289bf3bcd02856bb00baa0ac43860b6da4f58c9f5f3677b41a9f67000000000000000000000000000000001895c504538b1dd783eaca741b2eb1cfdac62a9a8f39dc705fe167c354c4498d725cad60807afa97502ae52d6a75d70c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000036e54c23922b2729c6f5d2f4d193ac65d7f0e72b74e1fab8ef74580b8d6bb52a70e4881d6b3236a6d30fe0b585cdb69000000000000000000000000000000000089f6669bfe1fee2599a2a291947f099860c70e44ace42cbd60eb4a5a7156218778bc5a44ca480a4ec0363cbb1ec42b0000000000000000000000000000000016fba274570491f8577aa8acdea156f7cf362ef2f25d42cd2228d16f4c79fcd3dd5b19b1d2dd8c1224761b688a3419780000000000000000000000000000000011a7f75f88493c545155f3ed3a4c77ff9dd1a0d251ab1f1f51a89f72d81772fc7c5bad0042329584925fecebd4e5f25e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a81cbb5f0ed38c0d55b3526a5039a858b9c87001cf363e45d619684901de11a11192dfa1a616f9e836f7a3272538d800000000000000000000000000000000089a9cd7169cff75bfc41a71b4d6f2b76fe16b37ae60640f785c6856f57f938704eb580c14a92b6e71e3cd9f01828285000000000000000000000000000000000574c2842e397f8a633da2d2905739916e6c8889baa6a9ac8c4fad446ddff2542f0aab2af703743d13fd3adea11ff823000000000000000000000000000000000c4f1622b505f09796f765354db60f583e75835ca2137d1dbd115c187fe894ea2e46ce334a122582dbdbc96c9d88dae91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000483748eff10b3cf9debaeda46400d785a827c5545c04f711ccf54143d382177a4bf892f8b6349620820d1d3d0b6bcc30000000000000000000000000000000009cfc6a3677a6093025a829071c32e80d96b669f2fc56be9cabee0b85b160c80cdeded09d24147a81c8f9e8f43338af200000000000000000000000000000000068793a2cfd31752177336c187420486bd0d11be0923c3605affc4e29eb449c442871ffade9348132b6a5b42b134de720000000000000000000000000000000007a4e77309675098bee58b05e6c1e71ca028c1ee9a69d4e518f5010bb0140d340a3af60bcce28c6aff14904be09e27fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e87387196947f1d45157d02b6667ceecd4f8708ccac70a7738bc1878f008c62a7bdbdc0c5049a7643cd17d594df24700000000000000000000000000000000002843e0f085420f74e12ceb8bb4b683719b6f422e555fa2178186440e3740a8de42feaff88e35280ff1a5e9423e23dd50000000000000000000000000000000005267e1ee025371c3bd478d28f649f3a5b030ad58226bc7e6a4e75c2f57fac05e248394ecba6ff0fb9d494a50699acc50000000000000000000000000000000003d2dcc3fe5eb7c7d9b5cb6b7fd023907195e9feae2eef03cb9fe74158223d0d7dfc7881657416c1816564b9ac34b8fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a0b64dc2a5613cc839228d6baa418fbf1c138d929a494e9d56453e8238c9aca05855b2a3356fad9d09c1737dc9bd7b00000000000000000000000000000000079dd3e4fe7f1230159555102e029578a45e763709231bfc1a06a49a555ae99f2edeb2a012788c382c7f28a84a5057380000000000000000000000000000000002adf35810a203b574508e16e0b61bb35250b24e286fd02269aa7242096a40947b377a5d11c600b8509a304bb0a041520000000000000000000000000000000017653192168c165be38380fc102d8825f3b88273ae0f96d0cdd73c0961a35b8951a5f9f2b527a623017735a7abfdbb531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c2baa8da7ac3e766373bb71e220dadfc07dc6116b3c51c76cbcda1f0c4d2afd4ec938efbf72c3942f1d800e5735195400000000000000000000000000000000079bdad850399e251dae9411f43b4d5ac6d514aba9dddeb6d81f1de0b0a492ab81bb55b39512be473a6a4c8851608bca000000000000000000000000000000000d3c0eb82a2ab37b09fc2f8d5c39c5d406b903f0adf71e4bac445f4f46ad406ad66524657207f5757fd853f0d09e985f00000000000000000000000000000000081ef04b174d0e9caa781d081df596a0a7c5e264a46ba9698e5ca535c3dd9c26f9dc1ba9585829bcae0a7b70e00c28831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001650af0e9b1b286646dcdfb398badfc7b7a7e07f7d841d67377e589321f3ac11136975e70852e731c86c6f8674ae4e150000000000000000000000000000000007515b6d8b201314c3e026628f9bd8c58c23b00d89926b08fdccd3ceab478345f59fcfbcef7b5368251f327628b128cb000000000000000000000000000000000a779ac28fae4ca9b6c9ee085702c9c4468d8ddd91c6719c418ec1f61999e7ff6ceabeb9cacfcdc633f50abeddeed2840000000000000000000000000000000012eee851d91854d0ce299be5d84822e23a22c9aaee84f5a728fc48afe81b6d9dadf9ff9de5137ae65b5b5e6f9f6695571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9711071a703e43243c372559663c3aba6d54177c2331b4dc5956fc568f42abc96eeeb68aafaaf19a0d2780c47309da00000000000000000000000000000000061199fecfb76c34a1e1128e11eb339a335ea2f6826dca8ee079c07e01f06aeb44bcd05f05ad8c14b6d7441d962336fd00000000000000000000000000000000081d1a83d642787a68f4362bce9efe8ececccb93461a1b44a0965e887e84bb830062c8940e64f230d07148ce4460dc800000000000000000000000000000000009b0b09d5a07883f73e01039f19346e0eda758dd9ddc459ea0d58eeb07ef9944607a408a09f96b0d7f811ef4dce3be371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f627f9dc9d3b51460899183abd4c9121843a6342611b82bbf19ae9ca53c18959cfb7675d27d7609d664b9fc030f667c00000000000000000000000000000000037bce7919e8409205fbf65a6645982fefa6e49fe0e792116892d6c656f09511e7999e574b70ef713c14e53940f40dde0000000000000000000000000000000002ebbade93249f52d5981d2b4556cf6b2189e526989b14f6d35b8fd0a0b6ca4037e89580e20b03c7176e9739ccf0cb30000000000000000000000000000000000bc2745232b97aba942415df7710094c4c3e5cd5e82142a697ceda5d16daa87c354ad4c616ff62b49e1b50271975bf5c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006599155e7224075d1258ec5f63e9c881c862bdf1405aa3500eb8574f1c6693bb58d23302b71901fc82207a36e53a7d80000000000000000000000000000000006605230b82faa3d74c7ef52a6ff047949fc2780080ba2240c004a35730f5c9631845b3d705a36efeba584d92a1c40f60000000000000000000000000000000006244485c5d3e9a163f7209a8ecdceb79402be005047a0efe5bedf706639c3fa4e865df3d6479d3c3309566cd688b03100000000000000000000000000000000007a9e92a27b3a9b4db4ca1bcd4a9d904d7d12ecaa99adad4edc504cbe5067e698bf84189b09e0c5283cfdfe3a4d904a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee03886ea8a34406dd0d767e49e83cb7ea2dc625bad0f15aac376f466e9704daf048129bd0e491f8c2ad5cffb0f10c4000000000000000000000000000000000c4396c2a0bd1cbdd410f37e4c77c164fb689e6cc57ef076e3bbdde160d856a5caa0caa9f1cec81bf3ac91e545bcdf170000000000000000000000000000000009f34c33d7b517858190d36999df89efcfd6b3d067537f9118baf4da70b112722fdde799105911a8f7a604c2029bd0cb0000000000000000000000000000000018aa91fe89bb9581763259c4b9b2954df3acd31f68741441b68728e9102efe8ffe135151779d54fc8ce9cd549ef6e2cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180b20271e64ac7bd1b54213088283daf4d8c646415484104218b893e5133a2a9a910854e255a9e597af6b5b97a6ab260000000000000000000000000000000009f66ff5ae096bae9dc1a13208501a33ef43b19e3e5d2727dd76aac07803d5c1b89b4604927d10ae9f1112e99b6a1600000000000000000000000000000000000fb4abbc673972249fb451235faccba59eeb8c08535e1aa513464aad83af4fa9a3daee59d873f2eda5248912422b4022000000000000000000000000000000000a838e4905685d4d877dbe8a4b624a7ad7d06d76b14bbac5180f51811034425a46030475a5e6af3faa4c3803227a78551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000060a7741b78e3cde771ca4c2d15b84cf3f0b9dafed26052a66f86b03d6ab5a1725b081f9ae5569ddedd18febb81f7d9d0000000000000000000000000000000010fd5fe1fb483d619485bea22d90174303ea7270507eaa783fec24d2f0c1443510bf8f7d61d5266a04c330efd9c05fe70000000000000000000000000000000007d5ad82f9481c2ad0599e9443c5276c844f48dc265bf5d7495ebdcc1ada3553b97283b439f20b7debf6d5b8d73af112000000000000000000000000000000000d2b0eaf78ed718c12fb9898c8fc6de7cbd8ae0f6a7297cee756164a2a5c29404f4bca988ab7a0d10ee588aebadcb1df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b15b90d34310badee69370d86535c0e2e533576fa7300aa2db533f0347a796b340949ea4934116cdc514899ae5047000000000000000000000000000000000019181b2eb5b44b2667b4b4ca18383edb5a340326ab476c5e854c3c9bb8cec3781d2fe3031eb61f536c9aed2513009ed000000000000000000000000000000000f6c51e7444c88172c62d68f13883edb606216d86f1f0a5d88d644db06f0a9fb9fc3df0258785a222589046bc66dd4990000000000000000000000000000000012670fc922e0e517bfac5face797cac3dc9bc360ee9204209a3c21434eb220ceae4afa71228741999c5a811c7e541acb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085df781c636527f8ea89bce264d34ea7fd4b08af97bf09dd53af298bf43a978115f2102abd621885d11e4483230a7a6000000000000000000000000000000000d03014a968946e85ca58c353e2b287796ae26d8bd90b6c33e92b382434a7eccf94d64e561934ce3c803ef81d96c258a0000000000000000000000000000000000e819c2293926182e21ef5951af7f028caedd9f681e9a89bb99fff9521338136f26742aa01a3db1f9a648d1aef9370f0000000000000000000000000000000018601fc5d88915215378376689fe9ef7da2884587d21cae2f0be72317d5b1742d4d25909517ec6014411a08a64e42a9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003677129dc0a5ac34362c385929b47eb56fb1b1a96b70c0b9ddbac0eef34e653de287d5b40d166e1f0c1b590e436481500000000000000000000000000000000176056f60e1dba6fa443e230c2ba463bac40aa74749141138059322e7809ae7913cf8740077a4f163b7857ac08bfe057000000000000000000000000000000000e3923f40e6e07e116cc68b1d7552805ffd0ae826190677b71853b34e6cdbdb57d433da1f63560eb76fe2994adc2c2ec000000000000000000000000000000001206b8693c4758b90c365457e316b518907d40fdde8e200893b8aa1b0be86d3155ef03fc26eb53774a8f7db079dddbc61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013ccaead2fa5aab80cadb887885ee5fab421ba6064ecd094f6b1f16cf9e1295fded7cf072d7e6402ef9cec211b089e5700000000000000000000000000000000061c6e714c7e04e5ad7640edf94cf45b6b6598792e3d6925c7873aebb4e1816d93f703b1dfbc05e3ec30c9e2cccf01ae0000000000000000000000000000000008ba9d619dc8f2334c826ee0aa350c9e876d00c33cea8a61b89faae8aeeee0238e278237eccdff898482123e91a96aee00000000000000000000000000000000124d4f3b11f691fe7bf025d02ce8dbac0f996e0f1e1eca6d0b189414632c7dcde0b452b5db9d2d08ccce26c911d9e6001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014a1e40d9599fe0c919e0ce3819e67df6a818cf23077740d765041637888f7770cbae1275086d1ca43b7f613590551c600000000000000000000000000000000097ac62e470175fd7229984c9baa3377b1f792a16fea74775d18eb16ab9d387c8d5aecfdb1b83db620e7bb798c3c72c3000000000000000000000000000000000a91497cfc273e48857d3907a1a845f165abe5a58c6d63d5eb2a2c0c346de19881c79564725b0f3528960678a169289a000000000000000000000000000000000cfadf181cb5f16de2b7fbc6fb3967b1e01a5983135798f398ea9737edcc4da44d6d55faf27867cd89eae2da9c03ca7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d67734e50c6e91a003fa82ad7a69c4342ef7a3b2b5acad0a0f86a3155da3b4869032b5ed00a7035c4567961190333900000000000000000000000000000000039402ca2af5fb8f0872c6dd7f2f9110ab070f966296101bc4611d45171bcbd8c9686bcf68ca910c64c92142525b9ee50000000000000000000000000000000004a6ead1dd6897c61541222bece0f4eb175fcb60b5c41543858b7093f443d49150533b0a78027e3b7769a9cadc38fbf100000000000000000000000000000000105f2fe3c76a28ef1524d7340b414587f689d6d47ddf2fc68df2b9549bc3be37f339d19a50316c89d64387a4f3075e3e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bafc3536259579595fec9e0ff45176c3963fc5f84169c5dc8925718421b5532972aa4823f9894c46d2b8031e9f70fe800000000000000000000000000000000047c6e0620974480ca05708b800acaea025effb6f576ad634d69357049b986968c100c05e789097eb7308b3c9c8fa1e30000000000000000000000000000000000959f79e75b4d8128de58e9b8c1cf0d800b3651f78a5a67c6a0e0a34fc780a25ea40f94031d635005f39da5f072cbfe0000000000000000000000000000000004087cd376fffca5d3002428b560dbc056a113710dbdf966241dd6068888d590aa1186acdd4c98398d0bb5820f00aa871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009305f9f1c40ecb59155007bf63dcb9738e9773d140a6193b2c4ac23b68a56174901f9822e930ca1649b6c1475ce6c7a0000000000000000000000000000000015575a0be5c6a3bd9ff313be58e70fc32e7e0bc098146816a95b776cebdc5062004fb2208bea054a463dfab859c5603d000000000000000000000000000000001172a7f96705b9198e59690c4439b3e8b4d3041b9a58a482722fc8166afc27906965fae78bc73082d5a8988120d2076e00000000000000000000000000000000115fea96f22998a3e5f8d2db4bba658b2802f7b182744029a9133bd6a4ba1c6c1d4ca9ea188fbbb0af56da1d9fdbcbd61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098642c2a1ab05b1f23394151c1475362b50cf1954cb645e6c8f3019c96fd1bdac1ba74599c874f7dde168366a838d93000000000000000000000000000000000cee556e7445c10d0710b39ddcb3f81d43786d767ae248f390a2c9bdcf33b0a4db4670a6efeb60169244befbdaa157240000000000000000000000000000000013e2f4b1d2fbc4fe49d3dfa4e08e6e2497afaba8c91ca49d532d936e5d9386be83aee1b30d1731ce9cea4534770041aa00000000000000000000000000000000172ff02c00313cd3177393920aa3ca2b85e7648638d6924e7c4934bc5eb3b826e4c17ff1d29d067ef09644a05cbea53b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102fb317485392c4e425707abc781dca91c7f2be60b194971acc2c6a26461e8ea703f6a5a4fc15d2bc1c6e2a0134b8880000000000000000000000000000000008823e2ec6a98ee2273f5e558b9ef98c35801236c0da4387934383819d6736902ce305ceaf2cebb84e8df147eb5a63c90000000000000000000000000000000003eaf433cbc029c6e0878a2b1c4ef0da210f685e5053c62bfd4e4431615f69d405227748fcc056bed19d46aa279b687500000000000000000000000000000000174928f3976ad6bbc0f2c73c2b31abdaef6701d98a24502317c5043d999466698f65276039edb1c1f71b1acf639349841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121dc77c2eb128285f299e88e12a1ed37092bdae219198eb70d3a20619dcf0847ec92ddfe950aad1e8000c872db82f75000000000000000000000000000000000022a9c924cf5f9323222fabafbe6730426d57235c0049bbd7a2b1600e7f333f7ff0361ceee589495ff70ef2a12940f20000000000000000000000000000000015a9cfcc41ae2210a70572b23d8109e437f356a107651f8e3a32ca18c242f4a7c8dcf2e654a215979143f1e100e897ca0000000000000000000000000000000012df1cb21d1499ea3c1e25f32079af0b09a1bc312c08e5aade2e3eef9c796261821b7022c2da93928591645c44bcfd851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e6db84d49abe48bc8f8e8a25d453ed28a7b1fd919b6782f470c424479ba53b780a3b0937870e1ed68165d194da80a39000000000000000000000000000000000bc70a36eb091ffd44bf898cce1f46c54525ae65290080bb20ba016cb24763a68b81dee32efc778d0e831cc3956c7837000000000000000000000000000000001929e3845d5c5d79fe20a9d5311877080b1349ad0a545d87ca912ad54cf48b78289f6dc3712b04cbc0c1eb4dd9c66df5000000000000000000000000000000000f337010ed9875291bbf22d45c7b9d8cc2429a283a75c5a0f5f16cc34d2c303e3a06a4c569dee4cc6f528dda824d33db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008562868da4df666f6fadc303c73067f18c37596403c801825325106b343dacba5b772499215607a7941bf61061f41730000000000000000000000000000000000274a95afb403d76790a98bda6e49d45bd8ca75e759a425ef5d4a3ef344a1dc742092ce587d1bdd5234812db2bce9c700000000000000000000000000000000114d6b8a3bb801fb4bb0f5a0e211cf0e2335bcb64c51913dc09f8b77b93db54b472f8f94cd4846c9840f0b7ee903e7c80000000000000000000000000000000002b136a50f5561e1a65beb09c1cb57338f5af2818d1dcf5f9dff418ba3c1d0b06553d0e781e241a8cc9100ee7df62ff11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f99f79640ce10014516355b393f2a9cf83b10f5f833507ddce813ca951388368eb5378655bac58753aff67d5a1cce40000000000000000000000000000000006d1aa852572a756019df2a77ed4fccdfeb401409c08025930fefd0a0266531a94eddad1188d6dce6a9b26ca118cd3d200000000000000000000000000000000189d7e92a192b8872ba245d2d7fba9f70922345d05d395d6a20245b4c1015f6828050626457a65f2334d3a1ac8018992000000000000000000000000000000000363297d59fecbbacf7ec9cc9ba49d9565c5090188e9ab9ce422cbe97aa98bb035a28b2f5eeb6ccfe471d3d541572aea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001068bcf6ec709042fa31b6e478b30c81fdb5e33233c7d2adf85c7aadb8702556091098318379c2f58a3e88a425ccd05f0000000000000000000000000000000004ac71370378f28d54ca43fb2d03c9e7fbbef33a73e623fdab3a4212f0a6e000f92b72c294bc8e57428ef28c7465b35e00000000000000000000000000000000049d338042bc91f54422838b9cb86ee9d10f36955d88c0cfc1ee50b81a46feac0a5c997955ba33aaa8b7696c8c613478000000000000000000000000000000000dfad4992b9a6defadae6eab9e12ade725b4bcc9bb801a6fccf593862a5a723a8c672a42d8828e4da701de93ec4f03441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000100fc9e940fc569e9631bbe389ac999dfa7990481308f9b992e5bdff872c2ccf8af7b0235c7e33b6824c31f91aebe93100000000000000000000000000000000123e1e5e5c7483564bee4362659c66b9811f02f8907d877004a2c30f80279026b0f00f333f5948c8a4542014d452b41d00000000000000000000000000000000159d0f525998d58716efaabea9853629b471133b24a2829ba29fd31c75b981d73f15f58a5e44c37470db2e7ee26beb5800000000000000000000000000000000199304bc110ca16482e5833be1d8c3d7e55b12adf2b89cbf14b9c1c75d34fbeee1beda17b8cc5af49658efca25fc0ef21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000166f3360b936c172bf49d8b61beebd8b56a436c04c91d63d351a6d94be9a209aabf9b41a82d8e1bb942e8bf8d104c1930000000000000000000000000000000010c3dea2e35624b07df35f45f5dc199f8b4078e3a86dfdeba72e2b8be4246be4f8cefcde2ac1d0989e2eeef275c9e240000000000000000000000000000000000365696b2c3eb56f2388eadf9c473781b69c53f89b80e9bb4635ac209b3cae58fa090b7df45016aaca67a1052ff9da32000000000000000000000000000000000e869c2987fb7370767816bc4f7fd4ff559b1ee44ce1687f0048c31103c6adbc1c63d42d12b59fe844abc693ad49abfb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cb6e0dad157a5ac2718ef700131b8cc85509f7d2b899b7686779e8d4607026bbcc4e305ed46a827c331114a15d745900000000000000000000000000000000189e7c222456eccbe6497961098d58c42de91f2273643755c186830c987191b241d48fc20168a0594906f0eaee41f5a40000000000000000000000000000000008dba00bd1a0df7f979297d2807059d58326a95c5c4fd543a051d030a74e79b41ecf00717f5d73433942dc55a0bd5c62000000000000000000000000000000001065e83484accec90906e206f1bb88d70fcabda7c3779fedefa8d39135d650d3ffab980d883c6032102defc698b9f1bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000b41fef828be98119897f15c380decc81aa6ecda619c44e782289e86eb6ca396016dbe55c426ccd238c0bfb0cd9f67f0000000000000000000000000000000015ff69a1079e09bc20f85eb30961a85eca011475de021c806ac4b4a5a9c0a0feca5fec9e865f9d10656b7e7dd641da320000000000000000000000000000000015ff7a1c0e45bc1c60ceae370e74f217fe4c135906f278ec77620bab39b8d4a52bed8710d362b5e8c6683e50909364c0000000000000000000000000000000000c3f599b48fc3c39de3a9eeeb87e3013383354aa951ded0a6638bd1041c6bda1cc5cb26c6b6fcc8d285fdbead22535481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000045b61660d47d114f18f40ca88e045701c4db0aa6ea45e76e2b640015bd5849c82d92c78ebfe25d481ba3cfa388d0c74000000000000000000000000000000000f1f2dfbddc073d1c6df10c2eaf9b07487d70bcf83ee34aa91f49619ca0f4b3642ddb8a43146fd0145c9ca6c7c30281a0000000000000000000000000000000009a785d47073a0dd21ec43ccb873368ef5e0289c497f79203a6eba07eba478e6c1439f4381060f5b025aa136bbb2c9c3000000000000000000000000000000000298f7a3faa5a0be707257f0315a950401080b8299c3e2d8fe716c6ac9217d78473c8f357a5dddca492ef1c677d16ef91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018cb599845b6155dfdeca1e896931dcc9e48fdb467b098167fac418b5b1b2deff444cc62a339107ec7196b1b9f01fd06000000000000000000000000000000000fbbd0c1e32c0966c42a6adaffbba039db93e09a76470e964e180042bc615729ec1c22a4df40613eacc2f10bba69e1960000000000000000000000000000000001ee478625197a157e3672e05f2e374c81bcff8b1602a4393fca765d98f6e4d655bb2155a7ccf49e42a04260006c7f65000000000000000000000000000000001345f35ed240ed76b6fbc11d59579c35d72bd17f46f2345761b8c71e10c066fcc1f66ec4534e63b0e881b54343733aea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015fe304725c729db1c4c1a211658abc844de913b3d6c9298b67f52254d644a211b7468e30256658d8e8f38abbbeb7a3b000000000000000000000000000000000ac59f7fc9967d0baeefb368cf29c5315c2e54b416131e89fc7621065423e79a3932c7ff648fe94f578add1a5573cd6400000000000000000000000000000000199da56d17e8a859f4efb9e4a3b6056be11c2b14f3bafee828b99e11b05d3638eb706e6c00fdd3faaa13878afbca9c8e0000000000000000000000000000000005d3aaab68949d3cc3c14ea18496b6a6053b59f86f9dc50a7fd1daa5e5357669fab91c25a1cddd86cddd8c2a611834fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069d6b32fc6bcbc5ca5cdf4416eb76d8f4710389501900d2fcd2c35a9224d66e1917655e8a64372a40f33f857220e3c70000000000000000000000000000000002277c1091add44571d3b5f60041807b3621079464344b6733c91588f6f778cfc16d1716b94443b5dbf837d5e9b372c100000000000000000000000000000000040bfc7ceae02a883374d2736a94f5d2746b8f208615e8e7ce26d98d954ab5ede7f2dae2b4a209a6f26ce8623f56417a0000000000000000000000000000000015a3327bc495ffb0301ccbc51a16fed7da2bb7a53bc39031d693fdb457d134170cfcb2e08aee757e3f1d857bb4a98d7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ecef1018565e58c7a7537797e6d3e08b53868f10c082a593c8aa459683ec1c34accaf1a6641c74c68960d04efb028d000000000000000000000000000000000cceb7b2e914ce8b2a3243c0d7a2d2a03bf26f6530f44ae02c5984653d5ebd8c7db83c1df6bd250502f1a1144a2127d300000000000000000000000000000000079a6da4ab24946500335f7ba30e604dbac078c19a81f40ba2133d3182aad8ed242b61b62024e67c7eadec4527fc40d60000000000000000000000000000000018f8be9033e761ffe9101da1e5db330ec7aef9c4dec87d69b801d39e5d5aeeb1fdf593d749e74bcce799ca885108ac671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000182fce21d076888bd5926c9e60a45d2476b8e4675454545a0d7a39cccf85270530e158508e7add4433aa51862f1e3f800000000000000000000000000000000007eb465241c5ced98645bc7334941376a492f32d23d8f9111830c658bed22cb0ab03e0359947b13ca605594a0b2e02f000000000000000000000000000000000117127e51f4fc17b37aa9dd4c5af6c5424c436a0c7bacc70255c5908edb7ee3e09e3f5b337f55878debe52fb099b5a050000000000000000000000000000000006793a788a2697d792f8ad18430713bda8fed6450952b01091bd2119b28a7ba09f94457fbbbfc0daba4351176456de6a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039d91a947c9f80f8ddbebbe6e9a4b519090f8916667112a782814dbfc4ce233331c73fcf6b9c4c3d66025009362d2590000000000000000000000000000000005c2548ce07194ca016ffba12b58b4e1a93f9c073fb82eb8db441a7bb88a25ed624073cb54bea44a52032463cae18a5f0000000000000000000000000000000010bd2254d04f03c6913d92b9e0df8c581a9c2c6874909440d3591fb82ad95cdbddeb8cc8d43317b47109d3f62ddc0420000000000000000000000000000000000885f665b0105787b484829e469008ebd2afa4a414c0c130663f1bee92c24ad58d590f3bc2352a220a3c2d8f1c17144f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c5b483cb4b8489eac6cd02d242b017085e16653b6239d247eb27d5e8dfd8668ed22d7ba2d53aa5891c5090e081f0ef0000000000000000000000000000000013f732b8c13b77c42dd118bd051314e8e30147922fccc7be7c2b3f4af4d09b8fd74018f7ed0c4e114bce804fb5b7272b000000000000000000000000000000001697d7f748e3f4398e19cc7eed5ac2efd02019ffd363e07a7c099796535b220d6fe0f2bee53bf76759724b75824fec110000000000000000000000000000000016ff3be41145787d05b25ed74d951fbf48cc3787279e74a0627d4a7d67909d3657118bef4acd08dbabda5235a7d95c321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001ef6ed9c1ab4caea80f4da22f128f61a1d45ac07a4fd4617eb2a0c89f4f3baaa613a58e635fc214e38158a88221193e00000000000000000000000000000000136216269dfa5e67bd6e037dd199f286ca71cd1439aabdf765f534d31f6a1a6b033b47607e0c418d7ce3e6289832269100000000000000000000000000000000065eaf4d47df87c637b8b3e2b5c0099dcd91dcbe3b3ecab6ee798e270eab1d0dd1b31f0db989d4e6dd74c048c3d5aa8a000000000000000000000000000000000ee25067233cfb1f191f543ebb28bee671fe5e49f3c05e3ef37f2ee82d99f6fc5b55975f19f03aba359e670e32d8d0391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f125f528fe6f5be6550fc203ad7e72dd4db72b1ce8c92e8a358dcdf74135b7edb97a4e40938440aba4406b6d5be92720000000000000000000000000000000009d7856bad35f707bf021a795a338af413c2d63b558aececd15fc534b2ad9532329cee8f577c4e31eb96fe0746effebd0000000000000000000000000000000014753e6916318e366cf03e535341996657d8e0d35999dee3f5160dedf10cd96d60371a2bd31c6d88e67356f70151e91d0000000000000000000000000000000012ff8be90144c09c435cd5aedbc34f2b649855d3ad31e2c7e08cdc61a23ee0badbcdc0384bbf3820a64953f45a0efa031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a8ac1b08de2c765039043a9a2f0a0ae5093cc6a4cf42245a06da09c4081f29d0ef91db8f26688ae7e5466032963b990000000000000000000000000000000013bddbbb3384ecd7917cffc7615444c288650c7b78b00430d04434cfbf77a6dc7bb4973eb4a228a0e63b5b03b8aed428000000000000000000000000000000001631cc8c5ad7af65e58d9bbac4affce7769c7aecbf19002906b830ffd88cdf21204e357def9375eafe9634118e9283230000000000000000000000000000000008d07215ba7c04ec32622b15b665b93ad9243ee3f5cdfe9dfad648b3d134cd307f6469cd2b9b1aa1cd20c5884621f2ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e486c3fb3fb3d4fa6258d08c0b7caf52e2996a27a42aab81ab9c828160b3620de313e0599cd7a0c9139cc8ea4b6e77e000000000000000000000000000000000e637bc6c98dc20cd86f343fcee3a86c14fefab8e8b5a1dbbd256b4f7b2f11204a6ac879f066f8ed6cb060a265a33e470000000000000000000000000000000017de8da98536d6efb5022e6e6063077e03950767f95285bc8bc7b74de7149f4c5e94212879fe3603f5d1bd757f914e4d000000000000000000000000000000000ddfebe58bdef6be0f54e18adcdd79d09c63df4e7b5c7e7707f2511780473abd4103523be4452bf3701db4e788635aeb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011451868f0d217f629a090c4a8463998437677d904b869e5e5f1aa41187546f80e1cb2fb1659591bead773cfa0fbc6f300000000000000000000000000000000029dff210f37540248a22387ef3c43da6eb4583958a37fb23648cb642570901874c5fca27d9a8733a698ec9f19fde32b000000000000000000000000000000001130b8e8493166f5895a6f682f4b2137196d662b7146b046e06bbbddb12689fa652960f2ab7c772d34c18f151e37ff8700000000000000000000000000000000058847782f9c5fbb3abf93a5541866ec2eadc9e6e9f0421c294bc92127d8391a70fe4ebba64fbbaf4bbb7542176547cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011ed4618558db5815033acace98338a9ca114a0c4a58f0643de71bb412ef66aa10158ffd543469259cb1c6f7a861c5970000000000000000000000000000000004bd2b1ce3ec73218556c9a341e8a621e256f0a8551473d74f48bc41172377eccaba85ecf1d16663a902bd3471da091500000000000000000000000000000000180024250a23278190c87f4b7cd471c2d685c88d3d1996ea9c7f9476d6649cc91dacbe107d895a7eeea18dd64a1dff3d0000000000000000000000000000000006028894c51ee25f96adf7d1f3c828cf844196bee002b8ce05c33abda3ff977a424c74e36c18aafb3847671e8ceb102a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004e0e87fd33d616efc15934e87ab2a2971926e36fdd5a3c1285d13ea693a37272281628350d62ee3acde27c1443908ae000000000000000000000000000000000aa3570f35fd5f81e055b90a01f611fc42d4fe2f84cad37fd7b2b60229bc1e9739f3870f1b8d421aeee846b6722196510000000000000000000000000000000007fdba171b5305cc946d6097b32a397c028b964d20f34b668f8fe999fc1165e712546cb61ae324f0d9c6cdef97dfbcda0000000000000000000000000000000009b0e76be2e962545ada81089ca729c7537692d96c4a924ab1dbda71a5b06162862a81203dde1e5ef542f191ff487aa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a5564995ffc82c950b3bb4e4564a3f2ed08848865fcd45de2c6e2508e70eaea47fa933a383b1bf54f429eb31cc15dc0000000000000000000000000000000019681c3fa8e67edc98bae675e441decb3bc0497ebb487c7722ef3f447f22dfea59684fd01b65b8226eab3052601070b00000000000000000000000000000000012ca7b4534ddf8df0039097b98824c1433f47f2ade057c1717431f0484aeaf479bbddfe51ea0ce71ef6550186e66d55b000000000000000000000000000000000dca22f8d6feca38e0b7cc0a3357b305c98cc3769e28987bd910dd88e0e2a0c3e28df225e83554de8307b3a1361ce7421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014846b3cf2ea92ae0372b23f224304aa49af11883780a48fbc8414a8ea00620ef32c8fdc938c05cba51b4de629792b06000000000000000000000000000000000f23b95ccf2e44c71dbae29518cca6826e6128fa7979d95a753eb2d8bec165d489cf92448c8ad743620dd9116bf49659000000000000000000000000000000000019ff5ac47c9ed48033ad33aca786d7a52cd7d169c8623a260539608427b4bbebd61543c303df6a260cd884d5092b050000000000000000000000000000000003b1de62ac79445ba31203e219a0f60a238b21f9e498491919c075371228c616e32122bc912c8ffd0dc7f327119742dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151f65681e5bd0954a4b6afd23978983f0f15f6e728805ce3fd20c7b2a2842a9d636f22d807eaaa31b030bf1d8d67c850000000000000000000000000000000016b24f4fb6386dc6137ca2c019a9520dd40841ffb055c21033120f4279bad13a525ff1e8ce1bc6f1d258172488b49039000000000000000000000000000000000a485ecfde32027b1f02d2734d3d0dcf757224a08b184efcbaac1e016e599c49c494e3da5f8a02518859b5a0332fe9f4000000000000000000000000000000000b6752d929e91140706d7564b1a490aec47be82e7eeac93c9c91ca5e3ce472d4168421c3b0544e2da47133820fa01f281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077b55af1df16da0f7515d0590026879da498192e6a7071df3407e67010c0161f74e58eaa2162226282fb939fa8c309b0000000000000000000000000000000014e7e08d0a4f852ea8593f2330ca6d0876443777a0fb5412661d254825018f1ebbe922fdc608f8fcda72bfb461fcf0b70000000000000000000000000000000005eedc2f8e745a44214e36c6625fb5aaa83fd65241fb99120a43f5072fc4a3d838de4142af40c7b7edeac81435de740300000000000000000000000000000000187d0fa57ae0d0c5c300c58b818197a803aff8d37beee10d895970f7aaefd7e5fd343ede07e64f659ae76b1189631d361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000027ee2508cdcbc83477ce5f0c1c156a0fba981bf887553b4d938824c3d214cb24b4f058addbd1168c01e0da56d89673000000000000000000000000000000000718862216acdb39c9fbb046dc1919567818b45fd4bdb105a5269628085093b26a5daee54b8fb684a3f0efdc0a14b3d10000000000000000000000000000000005991444e1e2c3a8bbe251c043e5769f8b4bb5cb3a4a7635b4cfd981631a099f93f4e183d217ac791e09c38b0854024f0000000000000000000000000000000012a63930bdcd48751e52b97a4002a965472bca25af9d39c3e2e95b3751a383dcc836d026bda27092dd7b8e951dd7d9c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a4798d8553889b21e62c21ad2938193ed25cbfef1eb19b0658c84e80f37c8e8fd0d027949ec5afc670a4034edb1aba0000000000000000000000000000000007de1465cf4e827adfca882f38322885c64305909ff9bbf38249756af76de26cf5c0d31ef035db8783b9df4d3918aec70000000000000000000000000000000003b0a2a5c9458c8b22b5cd92623dfe2f34d3c9e33e03b3b0bbd3493621dd9f67a4baf61c3ff3d8914a00e7023a7c4815000000000000000000000000000000001726d680008a7c651f4d6f627639acfdb1c099bca6ce910cb55bfbaaa67214951acd245b0ecd3e9aec1e13aa358fa3f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000154b0fbcacff55a4afe553eb168735008e50794ab436afd0c66135e234ce418b7cf5b2f514069f90977edea17163b4d600000000000000000000000000000000086a8056793c8555c43b1d42442c10342c2b8cea661c83e5e7f52d0fa4bb85968ab4a6ad94d42ecc5237ab076e2fe00a000000000000000000000000000000000b8d579293b1054463c61b1b7779ccbc2c03b08c4ab06064c4dca6ba99d7351993899f609dfa08460f5993d75651a43400000000000000000000000000000000058f18fb003b5c7e64a8b10fb8d97c047d74ac862802ff610d94b646dbed6def98ef817430228d04730bf61fc53e1a691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005285a0027a75801a12acc133182476b1fe6a1ee65408499fe5b1dad6aad66848b1965ae45b9e66ba6a0b061723efa110000000000000000000000000000000003d4ccc5b38612615b30d4e16b7f96dc4f38706f17a56043516dac4edc2329f1accd574d4539a88176eeeaefe16dd5c00000000000000000000000000000000014ee5fd0856a7f4dc525fe29f2507b5228722c04c136224438add5cd5fa353ed07bc6fd510e2809b54539a112f41deb50000000000000000000000000000000008793474513f0c93cf3007eaf8c94f0fa18c070e24be56c295f5c80b59318a798fbf8fa15a27a4e0f2ecf7c3140bee361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e8a2b63899d53c70d2641b9bea7221ee078cc8f4f4fc675d25b181b4b596f6d4cca45a487dab0373a9e1c5f9c680be000000000000000000000000000000000e8be53c79b90d6a41c55da1594c188b5bf503560ed6bd2d4b4c8f3831cf4896319960003c7e8f78f7f91d471f3569380000000000000000000000000000000013da69ea41c38b5e14978f1bf42a99d57023ad95922b78fd6dd5ed52bc15b91aaa2766f4becedfe195240d8c2236efe6000000000000000000000000000000000c0818da2dc99ddde67d3b8c6e31f1396c533c7d1fd34693107a8a969c1ec97936e25064ffd5314d16678bb44fb19e831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150bb6f851ec10aff0aa158ec3683af344e27692fd9ce61ed0d23f0622a03b87c2497be8516b3772974ed39fd31009d7000000000000000000000000000000001501eda3bf9d458def5ba0d85fbf0e05b441ecc357fcebd0d14f07179a50d4073f547a1415016efd23fe7e20f0b7e79400000000000000000000000000000000002f0c1f2f5b93f4ab5226d9ae969944d66e8ce9f8679e60adee78b55de5e981f04310a4f24e6da9eebf86d6585596020000000000000000000000000000000004343d0f8397f63ef2f96c63d8128154ae1031b5c1cf0e7a8764a56a1ce7a3d4dc4d1b285b47e04e4fba1bc7183170fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e04d1812d8e6e8ad5446aaca4850947179fd81b3670565d2c798b1be39c542d1bdff65030658ec91ea1e8d987a6cd00000000000000000000000000000000018a93b641656ed2da5a9f6a5305c085a0b9c9a45c9869c98703746b738dc4203aa45db947a67323c6176ec27cdd74eea00000000000000000000000000000000005ea7fc32d63aa6d5d5b45d9deb7f1fa093e9c61e4474cd6904d358c8125481659ff33ff2acb83bf226d18f5f016bdd000000000000000000000000000000001185ee05f1e6f9e6de989eec90f6d0fd7758193bd3bfa40c1f00799eb599e0eecf91f6386feb2a19cbf6a4bea1aae4cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001911ea309315b34c220b753037f439936d02d89568e8d3c5890fd6c307675adcc98924c30e472c2f21af6ebc9a9bd1e4000000000000000000000000000000000a2570005ce6ac6bf7606e2642f4c6b7d756efb4bd453db709d47f3abfb87335452a1ac1247f13dc83bd8ce55f24ddf4000000000000000000000000000000000fe3ac2c4658095130414244a1b8ba88377493ecb92d33e2d96227d31420f8cd75cf553513b2b762c117ec9bf6c6519e0000000000000000000000000000000012b51455b8e2eee2c65f35865973b3a6422abb887efab4b44172c5f94963d79e0b3c36117c4bfbc01d2a38e907f2ea2a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001835b8a330f182200a1af6a14753b80755370cbf3e2ca169772543b10f2f99b67a69892ded8ce882b99cfe6cf98e913100000000000000000000000000000000174deeff4c838748f322fbeb8765ae3f461fe901824e3e71d4fab4c9f5ddd4e68b8d8c22fb56ad79735486e963f2405700000000000000000000000000000000101f11f303abfef0597dcf554ce4e9e597127eee719594ebd0d96139e54541bb86bebac47eed9086dd78c1a8c4f9d98800000000000000000000000000000000145f3973aec7c38b2815c75323f9efb33424d26215c174460bbf1c3784525852943e351d721d1091164f95708fdad01a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1093c67adf571f9329ce8e5aafd8cd8dd813dbbc58ddb426b1b5cee3cd49d911079a1a56d1b9086fea56fa104902ce000000000000000000000000000000000b1c4fdd7d121163b6f5c30c87c895decba76f7ba7b3c6628fdac7e51ae5154498deea8c20644a9f13aba4edcfd15105000000000000000000000000000000000485dd49f9f7129e6127b78029ffca4ef83380f102dbf649d0b341fd7a465e7797e1636252bba6dfbdc3ae87d49f079a00000000000000000000000000000000131cde4a18f8cd0b88857717a241490ce8826938ed96754ffeadd5704002c9008d3bf02868e51b830be00c239230c8651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ba2e26d146be538e176d581d4a2b852046f08aaab3856398cc9c16a5c5bc808436f1b9f03f73ef1bbf3ca5398d5f4d00000000000000000000000000000000153742eeac8254b9973a5c6498a2c2e10b41ab3df3f15cc161e6e138d7c0a60d1176b6d4716b5d79c081cf543f00625f0000000000000000000000000000000016dea8dd5fb50a0414a13e6d8d7e909d3b7e96f5e131f2e312983e8402e3bb788d698f1c1f7fa70b33406adecc16a0cf000000000000000000000000000000000ce0921987f510a8c37de17c5b5aa7a531e4ce7cda101ad9c73c274788329f3555581008820470ddeca406e8e28b05a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e336e800d0fd36235586093f9620219e8559722bcd1e763160f181029acb4857e782a54cdd1d193681a96bb00ad278a000000000000000000000000000000000ffdb8b65ad621e42aa9e4b4bd1894b5046a8150cb73e4b24514e832598156f463d8f5f77c5db5580fc65e014348a84b000000000000000000000000000000000df3e1603856984356edfa26d14dbe26f2cb82195c0414ede41cea9d34fdd2c818d001b61bae751f2198e6430f5d3ad300000000000000000000000000000000093f8b217df491b4692f057a5f44a8d042b4b9fe53db11f086d9c0b9dc39728d7912a32341abeabab5b7a1051ef879a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000624dbb6e7da4983c43c0744c996481cd1aebd92a886256da9378948a47860eacd6e31e0640a19c24072899aa2c611aa0000000000000000000000000000000009d3c6d149b672a970b62c44bddfcdbb1661ce134f1d6e87b604d55e8910e00791c2973f14fbbfcbb3cf936c4814a3ac000000000000000000000000000000000b6a44dcc907446a1b8ef21153dcd1df6543231dddad1163073c34442ce85edd4c370796961c5748b6fdf822a8301ced000000000000000000000000000000000538b099aa287a524b87efe2ec96841be18831f3121c39c75fca9f9993eb0d4c6605e64c798ef2e17a14e6642247bbad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c518a751fc60f8cb331eb286b87c314853b71ca61ec9edc72658f96cd7786acb8fffed438f2969f04eb250443524289000000000000000000000000000000001372c1107bde7297cebd8d60123b6646b9a7b1051bcb7beeb272b07b22f1f634b7e18d0ec106c287b2fa91b7460220d80000000000000000000000000000000007ed1f811048b4fa52fe1c04dbc62b9c1c550b32dba824a2b061cd5f6d3f8a3fcb1e68aad20ff33d6bda5b4d7df2e314000000000000000000000000000000000ffa259ad9d606f24509ec338b98a9873c312dad7e2f8c399684a12e203cd78f71296ee602bfd68c56373815b31ca5681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e5f605b936f4feeb1098b6b3dd0b259b6280f936820cb31219db085d01f6d4e774660f65f6707fb082ac56acbb0fb10000000000000000000000000000000001bbd14776c5d4436a90b32cfaa6c0295a267760ea755fa0d4bd129aadba09a45d9502534ec02f9d96b056535be0b9c3000000000000000000000000000000000714408aa3ac01c2c3474dd6ae0464d51e0e9e288f984044971ce01b5900d4fada740dcf75dfb04f8d4923d1033aa0ca00000000000000000000000000000000053377371e22b1ddb94652ec17e17e90fdbf22b4d3db00bab0140e723898e683a8e921b518fefed37e755b4a4e8870741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010000d04ae001faa0a3564b66c4d174cedff410814fc661e3d58c0de2ec7572d52b60b00654185a6f76ffeafc02ec0b8000000000000000000000000000000000535df025e88e673efd55e750bf9a38e95bc7a0cbd22fa7671e0e659b82ef85a0cdf119a9721edf8969600897aad16890000000000000000000000000000000011fbecc80c37f00be295dc338911bf3b1d28015e7e90bcd3b5017e926aec352d3fd82ed8e4719e38f33cf657cbf7104a0000000000000000000000000000000014a00653278b1bda62541c2c7657874cd776278d81278750177328596d5234342011056c800a30341ced0df4b97883981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001104ecd145ca25a781046a69690b30dac5a81a71c87515e74ba19614e14a68df2780803fb8b7147581371ad37f357be500000000000000000000000000000000059ca2bf9007b391e5a6e7878816730cd620e08afc6caf0edefe540a7bf38fe4becae1407ab73a6226e801b0e6d06a7000000000000000000000000000000000123cff1ce16805cd2e54e6dd09821d1cac5d72d4e418575feea8324bc63dd268a52453034f539515114a166b1f0baab40000000000000000000000000000000006be06853d2313deb3b601fa8afd660aa29c1a381ac88e6021c4ac528ef60a07b417afa7f896570ff3940ffbd8ec6bee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000798f7b0e947891a511b950b5a67c78814d62c2c5cf558fadcac0aa2466006c0ea6ca4a086acc0d9f2ff2062409adf510000000000000000000000000000000002d2315395e64ab3a3709dfb0368484e21adccb0e64a0863fae2085946472b7f92f9aea494f0f5e316350b0060892948000000000000000000000000000000000548c41965554c24f1dd5f8193adb4b08a2b6ac9534e02d35bdce7f446ffc4d01f63d3bac174b0873c878f1d23709b710000000000000000000000000000000011c07e776d2e3d8744117ad3926678f266e4caca400b0414c4ce8ab03fb996267f1d0424a065baf0ef638493d25e985b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba0719277e7aad4284414cf07c82cf1d61cfecd25cb6c9092fbfb61c0508b5b5140cb539bff6c253b910ff8e07e41bf0000000000000000000000000000000015681628562ea0d7e74702813e15e28fbb0434fa54c5ad6833c942823c887bf6df5aae96486cdbb43e0babd876c3a2e20000000000000000000000000000000005e44624541b6e2933e107366661276dcfd2c4b9e324ba61020c9761e41d8715781b187cbbe5a5149faa4f881ad85c880000000000000000000000000000000017483a028cd64e65dd4dc35eacaed9bbd774ecbe6a9c18e56977fcf57286f06ca661950ada7c5af6803d846056386f161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001200a62fffb752ced0a376ae8bc2094499f660c2094eec9ee992184cf83431d7895bdf5e3d9a4e161d15331fbfc3bf93000000000000000000000000000000000fb1421b05bf1b57135e4ad03d41523ba116aafbe68a882c11135f01daf6496d7e5f3b0c0604e7b2ca148dd1b67d37d00000000000000000000000000000000000b141a990a43130110c0dde64235ad5c28e0a6f449deab2853860cd6824f98eca6e494b338eb7b8004e67244df9d29d000000000000000000000000000000000201b36256a2341fa22b18244d92e50bb3000929919ecef6d0c7578d8c77640cbc8ae0487a53e4f8190c7eed49192bd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ec8afa397d83c38751b863761ffcd808d5fb12a8bf2a88e2e31dccd25f2fbb18254e40897bfdb2555ba6d19033888400000000000000000000000000000000062a18e095d22451a9bbcd9acdbc7279072df860acd5a268dfe6dffa86f4578038ca2faff70d16beae6ac92891cf331c000000000000000000000000000000000addad44968db4686208b9d7b931c28e46078983b55c8d50b1d006b387928e59a581d77d4d648c5f1318b741f32b6876000000000000000000000000000000000be82a49b884ef629e089fed23612985f5e684275f6cf0b04a8b3a050d0a5e0eab63a55099e48aba468d9712692a4e991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a3f0bbef7d6857d47df9b0c4417cccb79fa270f6156c2a6bde400a3f3354d5ef5d1427ba49f941c2eb74a505a70fa70000000000000000000000000000000019f32b9bff59047894e83ec1ca60a361c5b747de2b260533cca16a58a75207b79939e1fec4544404bde69f9941a2096d0000000000000000000000000000000004824c114a7a3b110b002703acef48f91692adab97384918e49417e44aab2aa782e4eb9886e66d3ed89896d0f4402634000000000000000000000000000000000886be99cc60559febdf89a2844f82f7b1877e0d52f0b729c7ce8643c775b845c261420bc2c5918568c9f91b729a2ad91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094dfeb30a080a8132da0211782408cde294dbd9310d4619a08b750718d9359ec46ea92f364611c13f26b06be6635aa1000000000000000000000000000000000ab92fec8913e8d505ea83c99e9e2005ed0f344c05516ad9ba6abd2ec776c21be534196bef8aab146893b487f2d896cb00000000000000000000000000000000166d82400c9cd8ae8aac933c3f635a82572e2cb46178640b50abd21d84db9aca29c4323c40a32178f978b1b0589143f9000000000000000000000000000000001754fc023d49780e4f48fd42e61b62c2d4826dad2be65c3ee69f21b83101c7ca384fbcbf155480a99d3015744cf577061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009b49ff9649278633b9386c342f55f3e08b9fb29972a4f3d274ee32c675cc18b7254a8f008ba94d47652b074e94d817600000000000000000000000000000000011e2682a363b1c3a8ae5832159967711a62c0ea16cbf2a3187117807a9c33c4c8d5a01a51652834805163c15246326c00000000000000000000000000000000063a34737682b06ef9324f8d0b67aac2d81cfee69a7317150854c8eba4850bdb7b592015a81d6e2ff1c2e954072d81740000000000000000000000000000000012440f5cb859efedced0b9022317f962983711ea5880424e2cd5b06484b1abc50608cdc5d202da14a9dd41027e7479621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016cfebfede1d1e9281e22a97c63d3211d391b5fbf3e983f086ff21f4290e48e4a885aacc45e23c2abef01e5cc2f70a5d000000000000000000000000000000001925b00addf78c4f4b1161be6dc8e38a723eaac696bcacf977b6994823a9af52c1eabfb7568db4ecaa6646565f46a8eb000000000000000000000000000000000a46159616d391617559fa98db65d4df06d0d27739c93ec33a56dd622a4744442ff832b97466c07946dc00133fe3f69d000000000000000000000000000000000f243b7cd982d0e22d449d4cc898c496fa5ff9a49f60161e27dd82bbc73a96c1a43b721561807293e155a2eb8effdb171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047db7e40bc65e70ea3967c55958f5e472e58cda57d53adedbf910fb45f55aad5a14c03c3be38289c435fc767169257600000000000000000000000000000000068ba3db9da6c3bef087e3f9e6ace7a83a67d94d43a93824b064a8b61a11b3f03e3358b2d8e3aeff88ac9e3d9ac19ad1000000000000000000000000000000000ed52a27cc0bf47914191330aaabd04985331604ec614cf090c54935946f78e3ca60bfd6923674ba2b8e7c6e5d06a4b300000000000000000000000000000000112e10010bf7f5b6361a358a78f20080f7aca4daa9d43133ebde22c0386ecbfc6e954a9526466765764bcabdfb57d28b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a16af8202db60f9edba04ab21cc07f50eb784d8379808a7d03757fac35a46cc8bd78744fee49d3aa4704a53173fb44000000000000000000000000000000000da9870021b8c70a25e58a8355b6e79bfed812088756efdccbd079b1cefa0887f2a18045440fdf4e056bed91090a8398000000000000000000000000000000000a607a1996b03c75711331a27a13e26ec5c6c297869f9d83132c7cb7690fb4364c51cd066ce50c0244a97c59282e5857000000000000000000000000000000000f6ec39c4db9f398f02a38fe8948a65e7e29b8ad5e19a293c278e3c4838e725dea179fa71dfa9362a8074a33fc1b2e741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000080ecadd67299ce3cbcea237b149db12f5ca6bcbc0e5ed3b47d758862df545cff830be94ce35e6ef02f78f65decd426a0000000000000000000000000000000000fecfa7681a39bf36b0f2f53789d8088bc5c2c28b263c9efb81c06d43d32b782170e61f4926df1857c1dbfca8f095a100000000000000000000000000000000198c9619c92e20a64faf201f3add85ec756c148a19f3cd6256fdec42bcfe43de8281675bff422993918a22dc75e1cded00000000000000000000000000000000101bd2fe482e6dd02a6a3c2a772b276b238e35fbde2fdc045bd14da171e770f72a25e36adb10ba499c39ca98c53ba0f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003fb10c44e28693dd029a001433d135fe9660639ef55ce219b22115c622fea17f435909a78f81fbac7892b6025e3f5f600000000000000000000000000000000080857c80813bb00f125d418334a53feafb7c91700912b9c6a68f74a14b6e3390bd2b7bc74915245e0e4eb229a57f9cc000000000000000000000000000000001405e2b2ee36a65fbbcc8554780c3478f19c5c4d483ada8b0b62820c77d5dbd5367fae79c6aa1c95302535d14d392fe70000000000000000000000000000000006000db7012a30a41528fde8af185e42c6564c3c0b4f6d13be6ff81bb321d58939ddab0d68a14a9e1c0c0399948882301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ec938b24003e961cb597daf4f2f79090402c5a37fcd5cbabf9c28a19a68f7f919f56588fb0f44582e55fdbe5332dc700000000000000000000000000000000076beb5b3a6c353512e49c365e8ee9b007847a951366e4eb08ede898d6c9b933447f851476a2125edc9e9093d08d6d80000000000000000000000000000000000c3855f8edfb32fe59c85bff768d6c93dade8b6aee1d835df81b9dc6f30173f7213cf1439965b06dd575a852b330bafd0000000000000000000000000000000013b46e91182c997a9b55b5e68185bcee920e83db225de15a274c22c618958b8a4f945e7873e69ab8798bf4647640a0421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f296d079aadd7af995512224e26a93bfa01c5d898a04192c600290a5ff203e2655be1a1acf366a5251f2adb0f66d95000000000000000000000000000000000d0be753f8cc7b3e8fd1346a2abe4eca72a9a13ffdf6d36fa0c8b85e0209a7eb7e819a1d14785dad6d906d86542bec1a00000000000000000000000000000000022c53565dac049d98bfa351f02d62bf3d6977ba0ccf0ec1c93a82b7578786a4be045d30b7d4ad9310c885a5f5cde0260000000000000000000000000000000016e833f68a3175fa43ba6dea78f39b0da6bb163652cd21551fdce566ec8b0c1b6900a6ece8347064060d07fda119a68b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001303037e5dc432e448f9ff7ab3ef59507238dd8fda8c61b206726090dc6562ca2f1ae78cccd252d2cbd162d565e91aad0000000000000000000000000000000015cfe2c3bf760ebc8e44329e70571f80d839bf012a73fce7d44cd154ba6ca84a7987ba2d1a2e13dbb9450105c1e1a74d000000000000000000000000000000000d41ff84fc4e101c7041893d9e166a22ebec64d2a287b29fd5c6c2b15c947452366a649afc7afaadc1477ba3c570def3000000000000000000000000000000000f3c143e7f382a67bbb673143f5fe9ef05bc93915c5e683ab5c674d834329d7a4bbc86f9f725f268f59fa6cd79c765501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000769c0ab8072f03fb7c64d7ec9db0ab20196fcd9a3e6ba82b69b49e21a68c320b24b8efe9e43dee7f375ce0daf242b470000000000000000000000000000000008a30a5da46a0e00c03f209b7bb75b32f405e00d592046af2d9ff6cd06ee8ebd79c0e4f7182f18f83679c6a54363d44c000000000000000000000000000000001435037f20451a9f59acc08b00ffd8116f3da7cfb0fe13d9491b4ec755382458660e5d9b997e6a664f0ac77fcacf8bba000000000000000000000000000000000f78970698fdf47c5aa4c36670b7a95a18ada4ef44bd5cf5a563e7f60f5833a36eea1ff1673d73f7e7b788abd3d332941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001428e9cc62915f85cbd82fbb4e84c8f224d9cebc4bcf2a400882444831b6a3d32d7511285933c436dc0a4f0e45213111000000000000000000000000000000000ebd385c73d152a6e24bb67139834e3f2950a8cc7ab4dfa2ca5d050faaf4065930b48b29e3fe69d58f0eaf5e9739ac120000000000000000000000000000000014fc3c0a541e6253981eed9705721aeb965b89040a16c93e94ff985da0e0210c06a41313a9761b1e0cfd904e33a75563000000000000000000000000000000000d97f8c89b991f0d157c42d82f3db9810cb40482fb2c83bcfd3012ff5d031a2338bf55bb05de7fbff4414dc4ebc7800b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111ae994375526327591ee21d6b070521704baceb7a23ef5fd42f8fd62182696ece2fb23d38e66dac53e776040e0d34d000000000000000000000000000000001293a72d784e26b49fa2c5bafacea2892bec04ee970bc2d8915813f10a197b8055fcf00d22a6265c0a284da3ee3ad461000000000000000000000000000000001999d54e9e475fd17313d58f8693e49856f1dc2bda6b2a7b35b1abc7c572911e2c635658f7c30a5be7660116037aeb2d000000000000000000000000000000000b0959db3feb0815a17cfa8baa889d8e8645c0431f189453df441bd83cde19978ab687652b80d32ec96207ebbe9e97261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028fab5fbfcc8b3e8c49b742d9d84d1ccfdaf543f0dfaba9303b086858e7f550e88148cd1342de76380fbac084f98b70000000000000000000000000000000000ac31a70f04565d57881cb9283ab48079b47dceda1a182d21b72b3a7ff48fb46a2a9878e367286376ba368ed686e00700000000000000000000000000000000000966b277a027346e818015080a8f3278afac6b501049e354fd31399ca17fa927bef5c919e759aafe31d9db633b9ca41000000000000000000000000000000000651c0ca6b07d5426413c5bd9be11d9cdd0a4fcc57d469681129a5c4d6cbcbd2d1489026bb85523217ac7a8cde86e37f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012d4156b4bf0b87b64d157a2a42daff0703b1b7f104ee679a8b16b17f4dbe24732f62e95373114735f729904318787c0000000000000000000000000000000006240ff98ffb41ef3984750591b67995208f5c6b96099a73370730dd310f79d382841c32ebe08ea7c0ca5a4e25b1854c0000000000000000000000000000000007904a97aa815fbc0b07c1b2c35b173313f87fcc24040b69f0f6ce8e0d9355b69c57ec25013ee591ed826c5e676f9b9f0000000000000000000000000000000015eafa3a9eb18375826a3cb86c4c8bdf201c12ba4bf08482dc78925ead18fd69ea7e53168696b1fb6b7d450c6857a2011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000120ee461f7f44cd60c9567b19e93c1571fce77ca9f2564ba79470b1bbf527085eb519073f93b03501f47ebf4fb9d0f1e00000000000000000000000000000000033f8c64e2878a91acb28f1ab595d74a802194603b3bee8ac89f2d49b6ec8823b28ff13665a01795d57b03246b6fa690000000000000000000000000000000000d0af92e18fdb3f38d86f860bbd6dee233d30a69ed238ad308e9803962c7c8fa03b24e204da902e7839b6d03bff71d1c0000000000000000000000000000000002cb4fcd4d1706731c5d3f873235d63a1b3f037401cc9fcfa7de5342dee5058bfb587c02648515f4c79c00568993f50d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000994dd5c22ef4a8a4818a219f959daaf4f010b9311dee31592b14a34498ea71af911abecc4f0169c99dc3f04d3d6333000000000000000000000000000000000bd79ea7b7a26c3ac6a565b1138e1089d27ea1f9f40c401e838d700d9c5282ef2d7dcc06df440844c867bb19118e53ff000000000000000000000000000000000d8cf04b9a4cf1e8fc07f434e759bc9d2240e53ef1a2d919d0b1c76ff105ed46be998d8398e9b41b0826a11c6031a1b800000000000000000000000000000000112053cd14453052e97c1197d3b9210a4f4788c47e0f13a26066ac2940295e3f73092d9d87003e463d810e0a11a638031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001598bf5da4c6299c2987f71b9c9410c0ce4debb3e6629f4ed5f1e7f81c52998eb874ced3bed3544986aaf277028f2c9b000000000000000000000000000000000050071b7400131a557086bd5cfbfa8f0a2297d59291a21172bce975f7f16e7adcd9412b19bfabab2233e41b02de56bc0000000000000000000000000000000008cca7310581ebfbbf9f5e8b80ba57283de8e5e5a55e3c1666052c0a5e9798faba884ce82d23d0416d36590508fddf5a000000000000000000000000000000000d38cc83d8c3deb05d467b8bcd22fc718ba215a05890f2a4d3db5fda1e3962068999c8c50d36ed8fce7cb24f4d0e1ec71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e015cc35f0b62efcecbf85d1f1cae8c9677ea0b9ff8b117dc4ef6784d9e9015f9b2c19fecfc1fde40322ed84860d990000000000000000000000000000000000cb2c5b4a6267c6ae9cc2b076604ef3a8cc83741e575ada79d49e191a1a83f23fef5276c3007cebf3afa9bedc13855900000000000000000000000000000000008343d7e1392bde7511d19c4cf43267a99e5148c74fe910cc9e477d5e8a49f70f2962a7ee544eca066736dace0f8258b0000000000000000000000000000000010e231d55ab70d9fa79098e3c572f79233301467c2f43cbb474edeefc70f8e19174573cf444d07b36512512f98488d8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000008629fd2f1aef6d9773be17fe9671d15c393701b4493ad8aad0c21a3ef3d4196c8df009d09250965f8562af6f2c448ab00000000000000000000000000000000190dcd8ae4a739c02c62f9100aae52735255bbb96b6557145cb306c40788307b2f831a23d3131e832179862500f106e900000000000000000000000000000000022e9591f2055cee7d31125d9043e6cb45b514efce76eebc58f11dc7055ce42022becfb86e2ecc092f886878696e6ed90000000000000000000000000000000006c5036f276b4b3a88e4144a848a57c931162aa20a684399387684e95ec0eb7c20c7ee1d6a96145bdc1a43d534b56554", + "Name": "g2msm-512-jwasinger", + "Gas": 4008960, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000011b0c313788c4e60520eadad1f3685a4581ea4a4594fabe5e9cd9a9eb19e6be56656421512c4d316b19d4086aba226500000000000000000000000000000000011b4b99dfac236e1212c87f4255da6104bb4ddb3ee1730f517eb6d53d9788b64d1318bad43effda15ae154c43771d03500000000000000000000000000000000029b0560d22293c6525d0e64077bb90f3755fa9d7c67d299224c39064f64c8caf1353ac7ed83b00cc63c982e248dda5c000000000000000000000000000000001081844e26fb8f937e56ecbbca277f8ad87f4ed24e3d57d2c4884ee10bf1dede7968bba2c73434cbb873ce1c2d2bb2a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054cb9a695a5c86c47b29473b23123a72206bb0d522d534beb06453d9cc6815f7a2c4bf63ac6090fa335aa6d391b8a43000000000000000000000000000000000f52a4cfdad49bf02c5ecf9664e33af45e717bb087d1707bdbff10be3f90f81768eeb7e45e426a2d5ad59eabc1c003af000000000000000000000000000000001652bb1e05bcdaac957b87166707bab0728e5c4d8fe288fdb86bcf2e3b89219b8ebe773990a1a0d8df6398b40b3cdf8b0000000000000000000000000000000017b8b43010f7ad716970939bd3a8e61bd73d93de4d8ce4ae3253091f2f1ea4c1ce7b5821e5e2982f90c5cf6b8dabaef61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3f52ccb76597b1909861f89518d59bf982951f7b21c52c7ff8bb78e49f1dd1390faa6a6c8f4615328e7585286ec4e7000000000000000000000000000000000e1933193f6ed7f6e243a84823efb3f4faa6be40ec95506950c5e479845d85e7f65f2469ca0d18d9f41d1d5fb228e4680000000000000000000000000000000006d9fe4034708a5d4ba1b74e1dff28a9a77971d8d1680dab413b7baca2a996a44d5d25d5504975ffd99d919ed420f06e00000000000000000000000000000000113715359f0c8d0175d1242007962d4bd4c1058d628226f69f52ce4ebfab8466afa45c53bc75a63a8b37fa2962b1f2f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b4c421c64e22fce3153793f03476b256fad36d42edd97638d8557b6258b0af40495136111a9b41bd558437d8222326000000000000000000000000000000000668c35d4f9ad37f6b3a3fb4c309c8de2b4f2c5cf3c48b4d490fd337d72df4059ef9b6a01847f6eedd5efbd79532644800000000000000000000000000000000063087722c41cc680f59541191c38fd9c716bb7b82cb2b654a32e4972241a4e35b503966e2ea75723a72e3ca6a260f1e0000000000000000000000000000000014e8c5334ed84d0ef98fc94be1efa631c64a5aa4ccb2950811ca0a108b77e3ca5122f2208943c6f07fafd8dd5fab06e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002ebcbdba6bf202df969c191a91fff9e84126588edfc0b14eddf044c013409f1deb95b36568f9def69cbf6d6e7dfb6f0000000000000000000000000000000015c33e391ff84248c925ec4810a59693bf1a62542ad4163a7b63c15440529713fbbb1de069ef869887d92917717efad7000000000000000000000000000000000a549924ec10abf35e1a854222aa8cfc903a8958917c8423ed777fc6f3e55403d6f165835806fd1f497fa2d6bc806485000000000000000000000000000000000d2a9293d373f242d0788a3a40b12cd17b4ada39589e92839c05154ef51c6c40dc94cfdaa21e7b5fa5a762e13228d9131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000054dfff327423b18b418a39c24dca35189daec8a2253c8a2a46614ea45d837578e747e6f925a416f6d6819572903477a000000000000000000000000000000000e8743fee8e5447d5f2ac5c7fbe464b68b851632645c0b3673269fe87ec1debc81854d847cc2c5e0225917ec3546d14800000000000000000000000000000000078a1146f485142222269bac6f021e5ac318f92536d6db2f0bd6590d76345e9688496a2c7ed9d45090e43b9d7857af540000000000000000000000000000000019bc4932a07c037c6716c6e7495616373d37426c95f0d96d3ffc8b7908700de1b5a36fa67277f87c5f8c091a9de322221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008599c2fcc99d7efd655f590ece5e1b3a58d571245f7b63d48bd8f766f30103873981afc482f88012e06d3899206b737000000000000000000000000000000001922a85965903dc172dfe553331755684df947974d3a8939d0d4a6263db3cb0b41bc4a3c61932476f88d787c1f2518f60000000000000000000000000000000005180e5e9ab82b50daac72f2c3aac3433acffaeb8db96bf3e9fcd5b0225a6f550f27bcbc4f3fe249a96cede5455d593e00000000000000000000000000000000035bd07269262193b408d8768e87f7211e25f801b708b1d268caa5dfff380a2afa76dacbdca04c270cd9a079482aaffc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004314aa683db34da4b6eec837870a015456c1e8db4e46ac0fa48adb3de4d13a6e9d24e301841ae6a3e81f74561dd665c0000000000000000000000000000000004f14d246a646b09ae80051d0dbc9cd2b5759d86d19cdf4e9cb4ae94b077bc7f81fa09fe3a0e003e3dfa9f528ccc815600000000000000000000000000000000190c55d788da26dda1a1a188bf4a1988951824e31cd9ec1d076bab1c05c4e134d541cd48cafa0b7a0100009315cf89660000000000000000000000000000000017a01aac43217c9db71d8dfaca68b6a6eae3789c04fde4a0824a0077b02966c8e4b4f42e9a62c2a7de6dbbc3f28755f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000257e3df13541d4ec4eb6c136264c77b20f85e21a20005ada610e3b4a854b19b6434eda2d576dcc3f27ebfb7afe6282c000000000000000000000000000000000741fe5c535492fb3f0b37539045a6410be83e9d2502ab29f4d0ae4aa7b3bff074357a289813510f4f794aad957dc19d0000000000000000000000000000000002146dc9e0d0bad909737d7d3e947061331267f7b62c3b56d9150ef404f6b70287577be05d59ca9ff6edf23ba9f8ae4e00000000000000000000000000000000094c1876f5423974b04fb77234fa040f54dc931996d3e9073a639b03df82ae1df4afd53fd35ce8d79b13df722eefe6e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008c05cf7db37aa0e7ec5a78a110e943b066817d226d63ed39b57cf182f2f02dd1737665ea05edbb000c7eabf7bcb67810000000000000000000000000000000018e9bf6260df1fefb5b3ed0110305ef1453115d602eda4dcce0c6c3fb8fa4e69d78a8f020bdf78fb7063ab89bc220aa600000000000000000000000000000000198c757619f789fd85753e78b4d83c12122adbe456010ab1a98ed3230d0cca77b31704b903816404c5d0278309576c690000000000000000000000000000000014a7bf8f118f46f0b354f90f999e23ea72cba1f1a3b217035beda12876b27613a81b7d279c6b563915c879dec32c4a071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047f301a329f20a66e9de0fac40d9ce43ce2c2e3dddecc21f4c0a14ff9d82b5a31146a26285922585b9f62a0df3e2a320000000000000000000000000000000016a58e3d8caa87160138964786dece59edfdaf204a7a023c2bff47cbd444b30ff8cfdcd194e4b23b5bf243250b99abb90000000000000000000000000000000002eb21d8c8ce36ca0d12fdfe8e591fadf399b61dd2bb2e79adba98824e385fe429458177102be237bae294d492e0579200000000000000000000000000000000077ac450ae8608d9c0550c6df0175a9a1becc8f785ba45a96471e901c4860dcd671270090452e0339d34e75091021e761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009befa3f21e4a42549daa43eebd6093ccc56bcc70f36ed840951e18dc41227cd5ddb94c301953f40905fa30ca6bc81ad0000000000000000000000000000000003547c1604a9e4e07cc27317be52d0a7a580fc9eb058c7d6b327357ff62adeb7bcf13299bbac73da41de0f3dea4763f500000000000000000000000000000000036904f0b220ba6168e1d9671470a53c958612e2949ba8e8cd23e8cf9276977c1bac8edeb600fa6dde4906205cc2afe9000000000000000000000000000000000792491c8866c279be0a740c3b1addbc979eefba1d7b95ce25768af822749d0d1251f38ed3c3846ae120d4b7c854b1ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002f5f1908b357005e4f757953082d598a24d5ed1ab4f0e087bcede2a09d764cd9aec500dd267cddb68368dd50616ec78000000000000000000000000000000000df42b815dba924ca86aed618a8639fa1340c1c166ff0038cefc431517f9191148bf1bf128cb5d2ef6ad3713cd40e2230000000000000000000000000000000017e7d1d0bf1e3e714f2d5133624602cc77d193b4a03ee99d9b4e3bad83f558c205849ea3b0e13e72a162f4c9a81f7caa00000000000000000000000000000000022392b0a5d83d3b69fa0ccdae7af9d490eb76d1a577b3d9625ee1c49ac5caefa9787e0f2ee355ff6c8e917511aa8bf31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2a40210729417a699e48eb963c957d238bdcb54ecd2d8f1ab3c04077774199306f6e0b43d50d8ac565f0f8577c8cda000000000000000000000000000000000b524857d616a4b3c1e2fa5a0b4eac457fc9d50ac474c2789c4d856a2e9939319ff3a87840a5c8ea6954e0076f54b2b60000000000000000000000000000000016b7d0da5c058fcd32b224b598b6775fa77e50d071116839704cbe10b30e6cfca945526f1188cc6a58f8d64e8c5470ba0000000000000000000000000000000003fad7e14729f77e09e6575095485f709bd553c6166c705b00a16e89f8436fffde277390cda206ba9ffd5608cae1bc5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c5616c2f24bd1de048b41a7b890688dcbd1dab85690c817af8f1765b9b043300a2f377dcb80e496c0d0ce6f42e8d51000000000000000000000000000000000211d408ce694cd3e5adad31201d0d370e6fe2aefc7820e4d54bd8467431ccd1b49010f653402f7a781a277b6dbff4b00000000000000000000000000000000019d5baa76bcc1642f7e6522d13bf17c6ee0081a7f401c0312982e604438f9db0bb182f9c23a9084d833836bd70c1ae2800000000000000000000000000000000057ccecf7b7c099e1acf7f6df123a0dea258102c32641ac116b5ec033effbe319178dae3b35037518f3a931242eb80cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001d78e1da3bd442710c622789d29e94833a7e5bff88bd9af492e2a282aeafbb7ab2776fa2674da8ddc199e2ae35a5cb0000000000000000000000000000000014355df1d7cd9ec9eb0c0ffb045bc0096b7e1a54e6284f9f857bece09d7549031ef92b27855c1d07d2ad5b435a124a02000000000000000000000000000000000a468268d5af8aa11e04bbc5f0202b458cc2cc2147cbd36451855cd792df492eb74178cea9ad13436c9851ad10c9eadc0000000000000000000000000000000017f452b4f8c13a7613a29a15efab119148c6adcda63212252bce2f615543f307ac6221027792f6da85472138297b948d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e776a5779f5223ea00ebe7298cf83f99ee55ac49c3595735512ca7e8f0c32fd6973842257693468c4364a7041b07f6000000000000000000000000000000000c536e780a97e3dc52ccf424ab983085c1873dde4fc18dbfd23134bbbddf5ad023a373fc8c9b0e3751aefd79053fab34000000000000000000000000000000000389016c857850f90e0fb2570fe9c5dfced8c0af1c60311d509dc9b59f07fbfaf7954acd2b17f140f80bcb4ced35f8b00000000000000000000000000000000013e6bcfe7cf2dc06a9f281848a1d1c19d276ca2bf4cf60b4fa3dfc097ba5ee5e99056ee802490fb4cd51c836ab65d8721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024a1dc0bc3f7547705f08eb6bea518393ccb907ed45232b90f01c4533ec3887b7b18e886373e58cb9232ebcebcfe1770000000000000000000000000000000000410b2d23721ac77bba94713c0a5cb069a48ee8cacd10b8272fd91c4a16d9571ff74b2da47b84ba3e98c3a281c3a8620000000000000000000000000000000010fe420883c99179c351172adba5dac4dd410df42c4ecd56c502eb857f4d51fc69205e9029de79226257ad4cc557d67c000000000000000000000000000000000c32ac932d1101fcb2ecc23ddf2e481ccedeb31a11de4197ec14baba29afd57545d6b3175f2a18df384ac9501196d7bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122afa709f5cc5dcd006cf9af2eb0fc9f9675e77516d0c3ce9488b497ef4bd47b41fd8ffb618a18ae7e640851cae264b0000000000000000000000000000000014805a2c043290a53ee6d3d84d20987efd9e7147194059b57c59171984039ce4a306c6436b42a2fa0d2f489c282d9ac4000000000000000000000000000000000c42cc7b5dae0b06817b7cd567331cdae7f8b996d7a6a055e8829b78f20dcb90aa469fb88c0549684738b37f24caed490000000000000000000000000000000010cde6152b1ca69fc4a71cb53c7d33fef87d164f52705353ef254f76df6f5c4750e5af1784d9197e9b95c8ace44ae93b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d1c292f508462c38d4ffc391976ad18b86e89e551d169995269252f780d178febb3b2e939ecf1f4f00c8c16446c7a03000000000000000000000000000000000d67539b74aac48ca78cf7cf0065de74a692d6e802ec3959ec227a2febabf5b51b6b052e2448c7302502ba20ed722dd40000000000000000000000000000000018ebe9d93206e330560c9ae29b3df79b64b1cd7cbb84bff5d0f243dcc557e263a24df1761d6c4a5ad7fb6cf72fa7c3f900000000000000000000000000000000013af94d1d9ba772ab2ff59899680b41165f9944a6adc85209bb1ac2f59ee5f22a2a498d0b98aaee00d3f39900729dbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d3f34dffb58ab18291103bbe0c44581d88d932ac9db046e42adc2b74f9adb3a801b56d7fbf59fc201bc39267094a3a0000000000000000000000000000000009909e92441307c62032c11846dd94ba3bdeb79d5cd3860b7eb719412a06616a11d8dcf39a3e02744a3161c5563fecc30000000000000000000000000000000015ca1104d0d0584a4f6db38c31cf2f79b28c5067c2134c2463e2231b70b0640fe9153f68e080ba7afb51fdc61e6ba05f000000000000000000000000000000000ea43795f3c2fe2d5bfc3bf9d172efea82ca0a3c42bd60a612457f46ab847e1b60033157f49fea7ab2f067195472bc971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001bd4394256b1a04ef0b69bce01f1736331ec4757ab9ce744f63610f5b1d8a754805483f9bc8470486b073465d004b440000000000000000000000000000000008b5652d8fe0ba4617aa000e29b199f2acb77bb2968a93c77797f3f27928f79b9e5e1db195185e66de6663173a6900a4000000000000000000000000000000000f8634fb757e5cfd173dc636f6929235bdf73ec8886881f14939aee72aa5b544b33427de72d1d741b5a46f861f4ae9eb0000000000000000000000000000000003bdadcbfea971a38e11ddb1df62ec1b761e3c86dbd1bb690f7e6ef3746c1bea47dc235d8a0ebea3063da2d27109d79c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001661b2af3297740cdad612d5ae8eaa640ad960db4fe74b7ee59c2100a7c4d2f3daec6eedfbcb581aa3871eba9af9a69b000000000000000000000000000000000f3054182e756f299e661f25a91e6dcc64e2d62de2321f2d056ee0f4c8b2a37e00a272ba000b4f65dbff34fc40c8cbf9000000000000000000000000000000001290de4784ebd023bdb2565b1bddf2203672d020cb6f8c808d4d8e117dffdcc7999b59a2ca3a744c9481ec5ab546ec79000000000000000000000000000000000407d338b8e1b27cf0d45293fba0d5d016304fcf69b6cef1bc26482eb84755114b67c7b6c3472b1bbaee38f4ae9afcef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005a10b2298a6cbf67cecf71df8760f49a11a5a6a55a6fb7340f4081fd51681941a0d5f79794aa718a72d3c8ad8d4e90e0000000000000000000000000000000007d0c1d57d5679869b0232ca104d14916231a0e07eb09d269870b0d4df664878f5387b4a25bcf72989de5022189cf3c5000000000000000000000000000000000eb379aac9460add24ef081539b46418c4c810e9c91083975590d6bb9d1d7c4bdef418e7a46e9d6a26771ab385ecbe6c0000000000000000000000000000000012b8cf7b0c4268ab5d5c7e08b10e25f1cccb91655c961f21f117084f3436dabae1324b75422a29a44bb5d641babd97b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001363dfcdb7f0dbec0c2a265aa6532e66c5e7f8316fe29658f2b5f47dfbc7fc829e5ac3679beea66ead02611e0c4463bc0000000000000000000000000000000012b580d164f1fe47fef6edf43a8cd5aa323b87a146d098fd7017251f7ccb3707f4440503be3140ed71f6550d2abeea160000000000000000000000000000000011781f417c94a6f599ed6690321bd960ff934204361f148cdf6743ef175369708a7bb0d2d9d69c79f72a3961234d05080000000000000000000000000000000014222c251d59183b4af49760bb58766c5c9d3cad52307964b940571bcf9b54b9e82c9b60c17a60440e80ac70a960840f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e1f2f9e9c45524e52a46d6258320d19419b25921a75cd6138e7f406827cbce9769ce67b450e3c7c2dbc7ae81b7e1400000000000000000000000000000000015f3bb29b69cb7d911349392b2b17e8134cd54432fb59ca1566a7f12c5903276286a1ef528e82735ccfe7cee9839432f000000000000000000000000000000000d58c81652d25ac74578aeb22258b6efd65be4f73df56989c1e63c12c772f2c1efb1c738b44310976caf10dfb1cb4dbe00000000000000000000000000000000155b78aca4b8b2e52773ef29412e2080fa3e29f597e8945c86a2f21d08c8cf814b80a4ef1ee436039f047b9878df1cca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090a260db5ed4dd9588b66909b974ed9010a5bf5e9fdf93aa06a805d402ce2aec0a47cb254275a598350c6e1ed0a62dd000000000000000000000000000000000514fd7abaa89c3999d01703a471f7285ae2b3868bd317c215176ff97f1dbc9c854304275153f363ea8440cf39dc3db400000000000000000000000000000000195546c56bae59fed1db1caa08912e0bca3ee3e5a7c152e2bbfa65b665a0cf99d494dc2bca026c44d44d11dcfc630b41000000000000000000000000000000000b4071b0109840fd1bfe6c15992965ea7cd590d59f2439cce10135069b4cce0bb48ce338f92857e4a12ba011273708641824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010869dafcb30aaf22bfd4c5abf4aa45f375ae0ee854fa02bf48fbdda7bd8664df67f2ba4bfb95d43444acb3fcd5ca85f0000000000000000000000000000000009e5af86df74f8fb4c22f4d3e30e403075777510ad72f1e8575dff5a39d7d4e6326829744444556a6055c1f775b6ed2900000000000000000000000000000000155fd97236d2afb90c9483f6f2834501256cbab5c3a023bc3c661fc03f9307705d22f239c3e188d59ded071660e074f5000000000000000000000000000000000381a81a97755ae597451ec91e506b944d86fc16983debfd14ee890a9750c23813bd6d1ffc8f89e771cf664d9194ee631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156be6088e70212d268d0bf75eb51134ff35b005cbdcf8d954d88ba2f86122f6105ce6dbc3d2d417a938bf76e4354a7d000000000000000000000000000000000be4cb81bf15920d9516c510733a0d8a70a8aeab1b745eba3df85f76a20e75fc3cefb6918827f34e1222a2900bc20850000000000000000000000000000000000bc71ee969c4f361646718e379a0ad81bdebcd02d8f63a00b2aad166bec55314280a6b075f42c855d6f9dabaf74cb300000000000000000000000000000000000464bbc60408a3bbed72ed4a283307dd948c42005f4c5abc84912646a6e08a1e75624b997f548a404ac2e0f2f59319491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001675abe44e4a833e6727afbbcbec4670ae170745e9c70788d66371928e14fd1475b4fa504317dbbdb166b98fd0ba84c30000000000000000000000000000000018ba996bf2febc7b561ca5d24e78d47e930eb5a4896becd283e72eec0b2f17cd2de265535a01d98f9346f08f2eed371000000000000000000000000000000000057fcbdabb899ad458e0aee47ab3d563aa9c761956f05b9fed93158890d1c89f6d44bb8d915cd23faa5c86b81a8d5b3600000000000000000000000000000000032d09ea67932a901d4317e47834c3b891ced75b04a820546431ce2cd1f779ff238cb9fb34e7a93e32d8bf395fe728621824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001229468a6bb1fcf705cb1c7745507f506af7da14fabc6720a7ae256589dc0e418b9904d32766451a1470b1b48d43730c0000000000000000000000000000000005dba5c5ed25666be7a90e2b5d8ff3ec0f7352f1495f2035a3208bd318586037ead089282f6918f60b8518cd8c99787b0000000000000000000000000000000002bb2345ac84e11231dcd43b7b2a974f71b3b35cb6672d30fdb787002d11c0fada61e869825bff24219eaed8fd1ab68b0000000000000000000000000000000006f9a4c1894b8eafb51d7c9b87c2ba832b9d3013457a5f0d69901f27a3adfb9c2d66fb5e8ae9fea730e075a5610134e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e8a192ceacc1a78e4a46967ce011498edfb9bd3e62e2348136ca030055ce89dcc6d9e6e1c2aefdb7482e735800173400000000000000000000000000000000105f6d597145e31a4bcf771ea2a8215c60608b8275d9efb3883c9f71b31ab4f047824a9d2e41ef31c2d7033ee58d511e00000000000000000000000000000000132b19a33e16ae59839c69ebc9edf9c7e583a5554c513bdbf177d0b905fd565ed1aa339464544d0a6993888f838c1eea000000000000000000000000000000000f0140c57a3415c4db34a264af2f7ca85f25d6307f22cf74c55c97c4d97c7defb25e6f7371e6c8fc73319fcb2a7976401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e366082f445c45b8e25ba492ad780f9aa4c9b26fc05bf5214766ac0c832e13527fdb7024a3fa6e144dee4a94285462a0000000000000000000000000000000010ba69a2a73c96ca62bdd1553414451cd1de7d48ddb4c137708dab3e7da22b6105cf30c52dc6ddf632d5c065ea041f64000000000000000000000000000000000764c54be883ae7026e362dcae6e05e3947b9d381de9c4715fbe5f0c71137d53bcef46f4b358e008ebb6400462d045a80000000000000000000000000000000019ecced2a915c6e3428fe5debb83582b37fa195cc5c6002b16fe035af14a3c61ffe6b3ab031c3062d21c9f086dc7e7721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d16e160b04fe6cd69f86c88ebe446f90403ede270f1eba60fc1121224ad7475c9550130dde9e8d96f5c492196e67be80000000000000000000000000000000012b97fb3bdf47c432f544e31aa73ec634a54e0fc345319f99037297c359dfe656e5028e8a13a65ee52fe33b8b1cb2d1f00000000000000000000000000000000068d4108621be8dd28b66995f9540252ab7dbb7d9d5594aea6e5ff7fe985da413da74c80aacb55c4fb8772e4d5cc1b9800000000000000000000000000000000079dbe7ec178962e85fbb98ccc9be5f41bea5f3599dc9c9cdc223662cca80074ef83cf8deda5c6bc96d5241a620d7c841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000156953a513cb621948cc4afd37fd317f0e054679cae810b47249fa6d40a64b92baf0e651cc85e10a56d6368a2890b07c000000000000000000000000000000000eebccad4f99b480e297cb308ddf265cc5b654fe269aa18cf058317af40f05b94c7786f070012dc82803bb2f184fa9b7000000000000000000000000000000001981a0003b69c0af8dffca9e312609f5dc75a8814bede4e9137d0ff54c60afcb596652f08dd3e4312d0a38a9ac78f2dd00000000000000000000000000000000037612d6913e17b3b3557c0f8e8c4ebbe919fde3f552b7312ab6e2f1ca483ffbf8eced4d04ae3e9299906ba4ab9da2741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000460c0d5d5f0b43e30ceadd462ea274e786e8422dfdbfa410e43ece8452e0ebd66aa04eb6f49200932e3aaa9c926782900000000000000000000000000000000084ba030ac4cae39935d16fab8cd8eea78768720f27e065ee79f0a16670d3ecb94fbdee21d8dfa6f7f392747d36f5a69000000000000000000000000000000001753417c4bc941d0a468d8273251927aaf430611f18b840dc72b8e4838fac52ccd4a4f901117a6395bd571881e27efd4000000000000000000000000000000000720d7955ef2975be8c206ab045040a03cba4963ac3bad65bcd3b0c1e35b146f59e6879e78b5bf9cef6f16828ad8d56c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c17a9c57ebed95ffef219fd166c4c8e61021f3ecc5a6f95bc67799c24af329c3c9608f747a7db8a5d9e32356504522200000000000000000000000000000000054ff100ee9e7cae3778003ca8047c78a9caea26a12f4f5aaf09568d03571a2df637ba693b5366b4e6608382b6b81969000000000000000000000000000000000d50b0caf2f16e76faca3536dd05371e1c05b7f1e3b8a1ca58d6f97365299822b075888364cf6163e11ecaba828b6d970000000000000000000000000000000012fab04d7f13e27fbb3bff43f41dae46fb602797348713521d4758924c6746f1af4ef8445c9f969deae5e9766fc79acd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000332ae5f9be519465d4a83ac584635dafb5132afb07b52a6a20e92a7c01ffbe6a0bf44cd14e9e09b2842c7e356a4ae850000000000000000000000000000000010fc0bf3ac2390e7be17f3f7296b91c0359927a4a85099e085290b52ba7103a0eec509ea456c07d6391b88c7e7af93cb0000000000000000000000000000000009162a59cf32f37ce7254eea89307436ca7e8cd576b28049c4ed14b790403bc0fb87235b61a5652f3b2cd3882ea6fe7f0000000000000000000000000000000005ef225db533d5ac0fa33f29a6b776f5993c63892df47dc68f00fa8cb3d17f4934f8513f4a344e4058828a1f6e4007561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a4006ee51138caeb6d4cfb7fbd828ab480cc50102cc331081959aec97a3d1ea6da11359e8279603dd57695b77c3e2220000000000000000000000000000000008f4bd4cc7c2161673f24b78d959d1aeb4ef38b504cce10c417ffa33b8ac207c89d634fcbd48907e4df4f434ed8c6f7e0000000000000000000000000000000017bdd87a4cd699817ab5005313e1d6a6ed22595834f26018b8b884d3e0836d1272d192c606c148d9214ebaeb56fd6e8e000000000000000000000000000000000ec7ca2feba55fd6ebcbd569dec9def55e95ab7fbd626db004f8e219a0940306a68b2536f32c58c1bc39248c2ceae1f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d05d89a2fb7af5c9e3248ca4ee3508cda574b862d2c77e2d1382f09e8b476dacc530030b80dd14b5a7e7de5cc43b7da000000000000000000000000000000000af62cf1a4313f9e1950a074725b52886107a2d83f6b8a5bf13d29537b0cceb44b855e643f7f1f22024e872cefd94fd00000000000000000000000000000000006771b6f9711c959ec639dc151e4549eb6c9e04b19cf6c3d7c3e931c41c9a38ccc63d8b7a78dfe60ddbf0727865a0ac50000000000000000000000000000000018241ab4442ad7dc01ad6872a1bd4a67352a1d4598d139e02bac607a239ef7bc220b8d279013dd866ffc0b7d599234fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000500edf138cee4937ec746f5d3b9c1035408b6490203fad14f74670ce1e2d86efc60ef879f4ad3675600af903560a88d000000000000000000000000000000000a2b476ce78fd98e05aa3044b5b0a28e1522065e49cd60df3091d2edafbd7c324a87e6e6ea57c6c6128118afec88d0b80000000000000000000000000000000005d1696646bc02832ece30eb72efc5cb81ade55ae3588c0eede1a47714fc093a9c1d6bc9176f228532f7c8ebb98f83800000000000000000000000000000000000d7b6c67782dcc2ec35490267e80864abbd4f89f0c6d1124c35327738617c434a7479e70125ed025677bcb6720e27d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8c8596336da232b706a17886c2b1169fd4e8edcdb1504bde8924617bdd2c306903effc0872b93f2702edcccabbd717000000000000000000000000000000000bce5e4b1ff568aa112b37275b96bf32854692af89fb28aaf4e72f541d9239ea910fdc429b5d40d3ad3086a284301770000000000000000000000000000000000d3cd438abcc1d2071408e4de1150ab63dd267ff5d9e14383df16f6f590c4187b2fa1547580ce2878f3af74ae1aae7130000000000000000000000000000000011fa1868cad43a3b20078c96090861f3fd6e964abdcb14c9895f1df9ff65f20be50e47d60a110d7f9ca9ff4c8db5fcc21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001906e31af33349ca63bd6a10d1f9744d5298eeddd999615c4d18a9dfe4dd142256e9da657e2c2ddf153a1c0eb4e9d7e700000000000000000000000000000000146a890ad84c66c6263e6cdae7966795a3d3fe6baaab6d9dcb4bcace75504686a45d2bfbfaa290dfdac5254a750223ee000000000000000000000000000000000f4358a9282bc67ea0bbdb45763d9553f2aecf46f830747a08e7841c84cc059e8a6e0d832711f3553fdaa2bc59fa5e89000000000000000000000000000000000fa1fb11a793de883a97c33e1852c7bc676b65452c0de6883fb8fddba8dbc607ec81a715e1ad5774524ec682022aa9371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008e03836c60a3cfead50ad0603865b6280b5409293b4a154d56e60308a30f8df3c90d5a92ce8a1a9cd10f3e9904c679100000000000000000000000000000000003a9a6706f02a677d45c87b6e0a81cce2cad32af32623e9b6f479d1094357a04231a20b08657ff07bb79d3f58853756000000000000000000000000000000000aa9d339a4d17f370c2f66bbb0e9a56d4395955c63d8ffa95bee8b890c7df037399f91308cb0af610c6ec46f22161d070000000000000000000000000000000009762ebf13bee4711b9bf94be2d62d53a5393ce033f6e70273177199a059e83a4d7621a1b05bc04ccbb8427f93a52e7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000073db19c240fada52a067d45d4108e07ee2c951a6272b529d2429f03b7cc33650e6d426a104e60510b5571d12a841510000000000000000000000000000000000b1143f24f3e6c757f5709590c2df88afe089735ef17962650c4244aaa9765c05bc77afd93dd8564215f80d99f5825550000000000000000000000000000000011b4360e64f0a6d45865f8dffa32d42b34168c5cc16bc4baa209e44b99ac0ece9856231c59e9aecf873cff4f547e2761000000000000000000000000000000000f8907d7c23ac7e80af23f661ec22eef8ed79c3e73ea762edae9eab0bcde5843da1fd17a239d23579332a84b53dd2a751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000017cbc6966fdc577914413cc3fc3498f402e58d93ec0693f831b557c62c2fa1ab3d0ef5f0f13466a270fa67768665b5a000000000000000000000000000000000f33e99fdca45494a658c5c60c917ffd61e523281cc2d4d3dbee78f8d38c7e4f481193c5427e702b7b96341e543e0be000000000000000000000000000000000032a22641b45ca6ecf99bd3edf7155bc56acd971fbcaa3a638dfca070687e3ce3c58e0a5be1eefa7cb2720abc9016ccd0000000000000000000000000000000004ad230c32102ad6457a63ef85ee624acb83d799435c80ad5d8f0be16474f42178ef4a104783d9a1be73e6596aeaf8d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e61ab298954f3b737ea23a9aef44661bf6f42d8e0b9906576ed786a30c9fe42fdd835af8b5fcf596fe5ca074fa76ca400000000000000000000000000000000015f79924291d107130d8da6e23104b17229fb8cb903f718c9331f4f044a07459159b3b13afddb9c212c97e7fdda63370000000000000000000000000000000005fe913d8e9546eecfafb015a288baf36bac413b640f96af607dbad70cfceeb6e4439203f5af2457b0aec1fd40b004b0000000000000000000000000000000001055b5d4162b18bd2bfa1decf2b1bc8145bf83c77938e130fa666b23408f3e7c46a172b30188cefe66d6e3b8e84ba3aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006c1c99dc30b914759d98613d78f857aaabcc233e8b5c2b2167e391fea479d34b059574b9ba68f565643fbd4b178818300000000000000000000000000000000084dd3cae520eda2cb8a398c3e34a5dd5d1f790c7f9728d13788b3caf776b8eadf06760f89a29151689c94dfe8fbd1a000000000000000000000000000000000153ea85bb9c51e6aeb49c6b2f2d95cb27f3d58769d98ecc71d4bd0793ab0da0c893090c53f8af714a7f0659834616175000000000000000000000000000000000014f2b3c1511ba8ba23acfe3926dab3198cbc2cb5cfc76742ffe1d34a936cfd886a8ab621cd68aa161f45584344b2bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c589772f4b5eb3acd2643ab1dee70641ce76385fa4cf9c6582b4acaf8ae9a041889fd6a3f26a8187950bcc8d21ff3c2000000000000000000000000000000000c9a5e3b5e77fe4cdbe7c03f09fca02f150b3d65f63ca6eaa43e58e85ab96d44c2fef4da93d667f6a32c354c803b6d1100000000000000000000000000000000185ad8d9e7a7f214f5ebad350a67effedfa89157d84621974c6e28d09a9bfa1d36a32b09a925383be6154275da6cfe7400000000000000000000000000000000128c410094b18ef99ca51c293b40b6162d339197113f1de3ef1ded94f83af65b8d10283f8c9bbbe2aba87e4f9de358b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d4497b438e636884ebe0b0d181bd93815db97f2978df424804bcbfcb07d5562dea51424407268ba4cb3ebfcdbd4fb5000000000000000000000000000000000d08d7baa6cc3dde8c4f4dc725e2e86716a1a1c9ba14d156151bde0c77e233adc88ec4412ad77bf092b07a0ca3ff626e00000000000000000000000000000000017404580bfe227f75aa08dfce5b85c46fedfb06e16d2449e16cf9bc81238e2734131b7004882d0981762b68bed574eb0000000000000000000000000000000007b2674c1865836ef7026a8579e9ecbb39a5d7806fd92be31ad5af45f4e4372943a8f67dbf6333d15507feac08d20e7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009e011f3eff4ad27b3e1cac496ec95c6985c3d260172347f38e39e77aafb78c7ebba09c073e6bd0e3c8324b2bd9ba3a900000000000000000000000000000000117eedc3d1c9d06663a175fc891a42cc316785b1ba2406d703fd4bbd396fb9990963f264d9785ceaf1c26af2f731a19d000000000000000000000000000000000e22a6017880f63b2134dab76f1b27be918e0693923000f14ea5e0e8195c8b643d3a4589adff0dcb0a881d468e8a7a1f000000000000000000000000000000000abbd069a9f2918fe37fedb343166250d3fd7562f5e70893ec98750655cf1acd4742fbba0de008c3378df8316da519161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007692a0b182fbe1784e60b3ef86c7ca06ace852f26c9f32f49622f9844660ebdc6e43ca6ffc75c3f9f0ba8eb30625b9c000000000000000000000000000000000aafeb601fdef1f076bd027ca4720844bd1db6de7a48d182280da2f81f8dc00cd405765341c7f16a8873d19cfe2e1b8a000000000000000000000000000000000b7cbee977b33dbc59cf5148a913918c3e46482c859fbcaa2bccbe2327da10d0614dfd229646717cffdb2c3a5a2b099300000000000000000000000000000000015f5fff1e874e25648f9d7502e2f7cbe3a3dfed251b26b530c36e277e92da477b1e83c3589c41b1dd6310a94aadbf7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7b9ae9122b92761a85741255fe7183c9b7b239d4b21bbd669de945d37295ecf862691d93a43a3d18e9854fbcd26bec0000000000000000000000000000000007bb1ad0ecc377426ec89a238d50b0f0ac28aa76e32fda1b5873984a1c1dcff80560b463f9889a6dda81ad70466c6d3e000000000000000000000000000000000da826d861474eb69903060a262f79eae4bbdd61adefa5cb53a5fc9735c7c66d726326fa07a5e2ea55e88d979e98a6ff00000000000000000000000000000000023b2d0cd06ba7f5ad356602a7177678d09b2e490aa5ed6ac57e08a1938578d0b7b5cbb87bdb875404169b630710f3221824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb3b100d5ec3422df637970c18c9d8ca3da5966e158b25af12ccaf3dfe1af666e2f2570b91a967ead19f87f7cb92620000000000000000000000000000000000c4811526deabd94a7e837736f3588f3786f9690b3edd64c91e6da2baaef454acb258ab06b85b7594e467191b30e7c580000000000000000000000000000000019d99db246ebeeabee8383ff13660dc49befb6cab8bf254032216d726fcfbd61e35019233519fac46ec45a17b2928103000000000000000000000000000000000b216b7fda65e88c2ac675777dea28a52f23d9acfd05a855ba0e471f5d1276be184279ea1175dab504180d963ec1ad101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001513b6468bbcdb0eabbe0f4a53a70e21f37273503d4d437683f666dc118397c6055e07acc07dcd55b50345ddd79ebf4700000000000000000000000000000000003ef0709f2b15369a1e772665733e1e827f57ddc0da706eeab748954f5a9802de2b6906035195bf37a1751e1e26793400000000000000000000000000000000017a7c7622403061d29f4ddff05541a6dae8ce9b7be3c50ce9620e51d081dd34ff6a2cd51e78f87181f71ecd2d15877c00000000000000000000000000000000146665a1034e2b0d09beb5886a72849f3c27e46010caac57dff6b58388486ed49829a3c39385450be371da07ebb5d6791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000050cb68ce51b25935935ae47c35d564a25e9a9a0a9fc391662ceea18724e663c2577c780f3bc44562bc5107f28330d82000000000000000000000000000000000ac4eaaf5cca3898fb11d70e591949522473b3b58a6ef89e377f7b391b960ef3a61244e97bd4cbd6826ef13257a4f01400000000000000000000000000000000079e3029622d7bf192a3b2453f642763ae28a9105ee56ece44950061745678846a9e9f89c379143ee69a0b53b457020000000000000000000000000000000000184775d86b8c5acf8f8fe4c9647d55aa33bbfa8b8ba61aa4c73a1c3523698160b2c5773d5bb03f135480c1fd25e2dd971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f22f2826da1fa1822d2cfda5e629d977357951dbe975432de71683c9142c43ca895279f187fb0fec08246cc0a71e970000000000000000000000000000000011bd86ea3a95c7436fb3b8d2e9b5912ea86ad236a17e49d86f3eba4b0768361edecdf9440f825e9faadbb6b97459e35e0000000000000000000000000000000018c672c269f91c84b5e0027d3dd974d6bc86b7c2dc0641e8001b8a3881b8eb092e767b63c234de0010933f2e08bc30bf00000000000000000000000000000000018cff72b5e5273f6577a3e3eb7d8fbfa642ff5f8101bbb35c594e69bc08e991bb8041d195f275c85056e57e33b1d0d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ffd7cd5ca0aa27e773a7191d6fc03586f14667f6c556c9d09013fb83f84cd97c7ef9013385c12bbcfd9051bb87f44200000000000000000000000000000000091c05ffb3b28cf8e1c163fbcd3139b0d5fc1d10293e4e2f25f994ea14bd08dc9ac21089d886b704b31f68dd7d3b5c7d0000000000000000000000000000000017c1595ee22590c96134a214a77472410ef609c1e1db9650ac4e1588042ae169128673a05bcf0c8ff2b12d06951d3466000000000000000000000000000000001833df4e5cc1048381445de8de3bfe1d4f241459288478456aaf34978f6a380399acaab868083ad8582185380436ab571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e47184b023d6d35c7ba9093dacb7571947828312ed459956ea2e415c29f5cfbe02b84f1ab648550b3eda24ba13b26c0000000000000000000000000000000013c73d6e310a56b196270406537d0159c86bfc5ff877c852711a7dcae18097278f68945055e0be6b778162e711ca1f43000000000000000000000000000000000acef48c90d7ee271a61d50b3d65aaa1b99ab2f65bf32fc7b7999a7953670507e1ccda97d8919f70148f511506345d660000000000000000000000000000000016acdb8da4193beaa227351df6a55b670210e2a7124e2366eb95214f3ec3e343b5f0205ff0f8c830bef4afc56e17c7311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001395439f868feb6745b64ab1ef355a41611aaacb2a213e6b897bfef3d3d8b8314b9bf12885d3925a4b1db1b5136cd1b9000000000000000000000000000000001400604da6f36e62e8beae30fe197604fb33ef0ba99735f9ddef4039bcb1828114b2953b565f3938aeab320620cef6de00000000000000000000000000000000026d84086887ebf4291ba87a11a30665a754765dbca74bb2f235e570595aa2d76e3d0bd61f0b095fe0f9808ef5b099fd00000000000000000000000000000000005a513a25e59fa12bb1c7ed8d89212485d5d01ea1625b4437745409360a3dc5b9e27a394e818c03117c361b67209b441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce8569f08169de51a3706d984b1f4f0c08c4c916138db1be6a57e4e627e0706c41768fe3f49846af82afb43438cf898000000000000000000000000000000001498ef13205ade219aec50d0069338c4fa45bfd6bd689cae24e2dcd9003717a98084a8641d4e9ef30540b29757d252830000000000000000000000000000000005558096f859e13db6fe84869cd99ac7e420294eaae9e428114d32e3391a54b41a5cb200ab4b379a5c0189405ff2968b0000000000000000000000000000000010219ef05b58f74890372c8d3be53836bac20b30c46ed1a4c22f11ed5f019ab81078a4ee7ab1ecfb21f4c351136ae6a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f759777e731df2034c60d29674755f58a2f6092be37e1b02db33c1729c949c3867379bb6279b88c426e0c7cad0265450000000000000000000000000000000015d507d804e6597320433ef73fb505a67738e7d333c989e5e1f8fd61324d29905e5af3696a0c19c3109099d2800106e6000000000000000000000000000000000990339a2af7715452586d9df922d2ebc833fdf2d89d1940a643b11a3d8ff92221452ee3a89fd69c6f5e2a210e61d03d0000000000000000000000000000000014ecc0e4b804708ac7caca8cccc886c910e077875198ae0c2fb247abdf4c599d07437517681469ff8718da2fc628a4d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006efa923c0509e127066c2104122d9c40b24a338e7a3ddf0b60f09721b9f16533c91556fe01ec8d72fbd79186e9d52cf000000000000000000000000000000000278daaf62d08182cf2a0dbf0954aeba29febd95fdef299f38dca7c336495b3c2256d0611aecd5230455f24467d3d9b70000000000000000000000000000000007f9aef123f0bfa3c315fe544c4766e88e011cd9059969b3967a187cecf1c1227c04fafb15508911b927be3186eb941000000000000000000000000000000000051a36e77081f72706e3560ea51400892088bdc7b22b3bd5256a2230ed5b9c4e097dcc093e4162310d520b199af319c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e3eb9ff83995b7f95408097ea4ef531fa92c9523b3286d1df6699646046b9eea67dfe13f9ef9a2df28c7dda2e31d090000000000000000000000000000000011718dd69b25f7abff3395e9564a0b9b5f4a0c00ab4aeacb800055b615e32adc5036690bb186243743660800bfc3b640000000000000000000000000000000000f50a1f5b4f06613074f70ea562eb8a5f844f66a74068e9a2a11a73688424211542a84811bfeb71c6eb27d0b0ea65e1b0000000000000000000000000000000004a005a4d7130848c68b94af93d5fbefc7f6f8cb657931058ceba27724466d2e04579c88be18b77099bd738da6683ab21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014d1dd1dd217a9cde2475e654be17f3a78d85890301c52982dd49706920b7b270cddb2c0bb3671c259a7f8c7ce85e64d0000000000000000000000000000000019c4e618261805f2b5d70a4ac68b00528ba923146b283bd2e17af9fc2b686afd41e658e67b5d704e8ab764c39efe70fb0000000000000000000000000000000018060aee01635d1b937d91ba72e51516353ec0025e3c57669643b00cc6b4b820bfb0b56938e039a53240c94266aa7b06000000000000000000000000000000000abc4cad0eb6f65d7fe0347e7985fc05d74fa937d874ff46794b826ff94445fa997f987ea52caa1e68a1858aa628b95f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030d154a0b134c03ebb9f336789c350903e6c12e775f825f47d24c919dda0e7dc9a722a41715458d87e12ea32de43c87000000000000000000000000000000000c518618c5fc3a8a2b8760d8220e04419d0ac338d6b6f9694bbed5343faa77f850e70475abacb2292ffccb3ffe224ce0000000000000000000000000000000000a0cfe9f3659319f97b3f3948e294b34b42d95dfb6e945dc7a7e03226b0a4146a231864c51c22d55ae811d123a64195300000000000000000000000000000000093a40b8b4643bdd94d7f1571c589d9f3935f09a458f9f16b272f40602e740f8152e45f553a65a7e6b7e3bb3f481dd091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001795f115c7945f0561c338361cee45305215f6c57381df27eb4116fefabdcad82768890122baf6ab393113c24ed7e0da0000000000000000000000000000000017f2cb441759b475eb760343aa2570470104d878240790beb992c747cef57b775c0990f205d5c3ff10c6e909ac25a0da0000000000000000000000000000000007ae540d092e8180a02ba99612ce7494532b7739ec1fd685206c2798d1e61fb04d659a5bcc3600901b559f453cd268c200000000000000000000000000000000125bc7b95f90f0820b39f9450f7e55a85eb743d14073fec50c8162efcbf957fcf664576a73f4f4b7d22ee69af7e209861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf0175f5e7c50e0773ee91508cc3253a95588c2f5a35627443ed50d9f784fa7d86e88ac909a7e2a741130c1aa5c8d95000000000000000000000000000000000179b4e50baa1fc88b34116367889b47c6060f53d62e5c5cbc14d191e2e6d856bf28fdf1a4775b5332950465112b08b3000000000000000000000000000000001449a97876659c4921b4c8d626e008ae6d03a6a015535a711182fefbe59794e1301226f471e10627fe1101e1099ec129000000000000000000000000000000000659493c9cbff875bd2bf2baf02a9496c9732037e6dc08f914b4af6d4485e4232fd9d0d6b560ae1b02546f0794880be01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000859262db2cdc304e4562cd623bbd46490ea59c3937638294f95ff13a2f9b273de03c5de72fd8e1e0fc4badeceff0bc000000000000000000000000000000000c8ed88f4fef993946d877c7507ed9ae1f918fc4cc9b850b8e0ed879e67ea62f46de6ac8a77df759fc89cf0c7ff3198900000000000000000000000000000000046fd12d8ab0927102ab263c49fb1274871e0195b3cfb2d634f11aa4baeb1965385a4ed64d77346505288a4f91a551b8000000000000000000000000000000000afa60724f687e94e1f248dd8bad2c038cafee52f5386d2b8ad8654d59e007127c8b6820ca2a04bbed69bb5434f3b5df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077418a3c46b379eaf47085e21007afffb658a4cf1dea497fdd27b19b69dccf7ab04ff11bfb9e48187a4b7adf056b7830000000000000000000000000000000003eb945cea67d1d5727c1aeb37433bbf15044806882de00b7fb9bb706f8ff9819345d61858e3b9aba336d5b26e630a6d000000000000000000000000000000000477570709fb0f57566649c3bcd126775b706d49dc4267738fc1afa92657dbbe3af9055e066be4ac01b98bb9404a11ea000000000000000000000000000000000d740cae77e960d513050112b469c84de9d0b108647fb8bf73c7e2bc85dc293b12ec1b95fd58594d0d45e52411ad144e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000131c1f2006e29dca0ae2623128d37597261ba5dc652fecb77559882c9c21ea3ad87d2c3d982aababfd83cadbe2d1e348000000000000000000000000000000000aeef643a99ffecca76fa57914ba6fc87b3fb7914adde621f3f16c370375b575178c2c04bec0955323f9ce2b9d9e5db2000000000000000000000000000000000eee97728c17fd8cc4a14b75308496861232e73aae58db3fd6ab96aa5505c64cdbe8e71ed274cdcaaa0d62f1ff47f74d0000000000000000000000000000000011209b5c07cb451382e767805150d26c9d63b1197ea73231f8a0d95c934dbad06bf1d1ec5156e96724137d2a2e4536291824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c7e83627dd9bcb4ca46b32cf79bdebd6d2ab4217f73fade21315a432fc516643239467a57aa035957cbf5eb89072ce00000000000000000000000000000000084c5e2fc847b36cfe3ce7b9fd0471be0c899a759ac435a5328fdf1c29350e293e17d2d9b8f293d435f65091480127310000000000000000000000000000000007d76123b68212141a30c75c013f8e410ea37bc879db5b8a75fffceac0c96bb56505191e2ca6e44c4f894d873847f38a00000000000000000000000000000000148d142cce37b830b7de5b38cd97326a5a90ec5391b0163daccfd7199a4127b31b1335492925b2b6fe576cc1712182511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003d3c1d2f0f11f02edaa76c3e790e99f01f5a27df3177dee4a6853c9ac85c5af8d2306390b153ad57596fd1ba71aecb5000000000000000000000000000000000a2189b3dac8bb078c41ae74c8fa65d51191c8a441f621d6d942c8fafe1a420b3cbd7f5f5e44c638755b006adc98e1500000000000000000000000000000000006b760d7f6e3becb686b27ec56987190d0c3db3777ef532a7ebb7ab43b990aa148d210eec51a10662ce8727878eda19f0000000000000000000000000000000007c343fc7c677e6d96064875ed91fc76805a7108fd487534ef7dd1a5d84ec492a1062ca481b2e629977ba6aa173a6b581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000058e7d62ce9ba970c64679541ae2be236feada2a97d87fe7744e632d7a16c52ffb75dda0af8f8bcdef489b6e8af154030000000000000000000000000000000015f2ba3723391e35b101653700f1e9ed07c4e7554ef2d4f3d2da90f655d3f2e9ab05b0d9eb7d3c37e45347d0a7ed0452000000000000000000000000000000001672f7465e171d0cae38da2ed21055cf9b546c492dac944740e2710d7e5bd2780937b969ac7b99871ddaa3beb99c9d98000000000000000000000000000000000c2d56b6ed9dcc38004c476cd8fe9ece8aaf09ebeb32ed5e41ceb05fb15fdaa92987cf2dd0bb7d1b688192f12d4beede1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f8034bb38d294c61c33559c4226c5d8cb1325b46260e5bf840d2d2f2685de93c6df86a75b26194ab54e5f0d68b95fc000000000000000000000000000000000ee978d7c0b2e3e236b4867229cd4c887b58b5f723752f91a77c6f29dd3bc595d03dbd505718194da745755d7f9fb84400000000000000000000000000000000010d329dd25a76c4b978982bd015a73c1e3c0586f3ccf3bfa2df81e4adcdc51e13d34489e17808d30c36a57af58c332800000000000000000000000000000000013e96497276fdc44a087e6e1d62c0c3c04fc78f5233c4492ea7b9429b68e254a892a0b34886bb3abb3bdc516004e6371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000121dd21b17baeac663e9792966d47a5d715e61041c6fe80c6ec186820413ada72ea12b955c053862d3f7773d83ec847e00000000000000000000000000000000010bf9f2343ab0e208a66824309ef6c51f512dcf8e1e22eecc9e7f56fcfca439d01894519630df9330f218bc87cdd5ad0000000000000000000000000000000013f86142e0281cd038aa57650fd59678de43e7f76ad5391bd0ed20848cda53c1cafc57f130cdaaab308257a4c19659ec0000000000000000000000000000000015da547eadc3d5a99eed8031f63d67c0809e02392a7ca2d28e1b3d94899065f7cfb8069960ac845262e12c83ae6156dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b0714339dad73a7de22f9fa0af58e1585d92abbcdf57d47b1f66c11f3ca3f6ffe903a7427f53be05260f61b819954c00000000000000000000000000000000141af443a4df61c5546c4949086e53596861c900637d3df286a8c68a7566973f073a482076478f18c3b612b2d88f9baa0000000000000000000000000000000009be71b461c07285c7103c92123f13889e6969b94875245bee78e9c98e1003173a698fa967f3a846a7f108a7eed739ac000000000000000000000000000000001562d1c1599a7a4310841e3f97c700643f4a111268cf1b9c989c1f7ca531cd650df67a5ae48dfd43bce0dd0d7f7adbb81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000031939d812542c9ef30bd4f1c21e2aa3e33d494ec10617d05cc36757451628be03baea5fc51713a965c844d0c5edab900000000000000000000000000000000122e35986741489a38d97e4248413e5fdb3d887eff462712a27a30b4dd1a3480052497d758206a9760ae4384eac87fe200000000000000000000000000000000095abc9ba44ff55f6b81645ddafbf9f599558f864aec27058363489e4c263256623bf3a127c058c7bb713472efd70fd40000000000000000000000000000000012d06e65f40c4216cb077d5de93a40851fbba01b74fe7d196f5e32b6bc1b332c221242b84f1e9b34042e06d2b6c9e3ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001638baea78946107ec22952918913f87d3018e31378a51b0430c2bd2b1071f63b99c06ac7f4f9fa42555748b7a23b522000000000000000000000000000000000a298e52754fa6cc576a3b578c07fd9718e1aaac6a38d70fc913724af2e7a9b5786d556672f72360b36be598727767fc00000000000000000000000000000000142fce650aeffadde07e3979f7f0d0d22a8e9bf9572bca66182dc412310d23385bad9e2641e462aed90b779be79820b2000000000000000000000000000000001551f9235db2f36d114c1faab8fa3384dbe7c99f78d562f4269296a254346c9990075891fda5697c2c8e05a7282766c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014740f1a7b5eb588b656c234f0ac9f019c482e382e16309bbf1a2f89c360c06ccb5ab60c042e1b628104a886905ec40100000000000000000000000000000000164c2e7f7eda9e0db0074199a2a57f2b406f07008205bcd54dbf0934cc39d5a930f5eadd89a3dd2fd257f0c87f489c1900000000000000000000000000000000055db08413b3ee16a71a93e68eccdc09fe29f60760e69340243fb16c215dd58153ee160890db7f983a2cb5d9e27b3e18000000000000000000000000000000000bdac21c9ab4620ad96b62b2245b1aba6ada4798192358cb6869d950c646dfabd2717a81882c0a5b0b3599f3334cbe401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003bc63b523e089395225098b4813c7c710895386428f7c50552036b01333da723c8a2bb4c79455804c3edf0fccea987f0000000000000000000000000000000007f85e66b03faaad161153a1eefbb515a926ba68416d523f8b54e3846a02f3f8d3ced29d5f2129e43f0a974abd362ff10000000000000000000000000000000016585a5da82e782612b97ef9d12dceb6556a437a26aa234889b68e06b950854666330210d751a59d281df4b4bc0a153400000000000000000000000000000000149a2887a0270c240075deb21c1703f2ab2a15496d172251c7daded0c0ccf55742d0d9171ae0f89afd0d168487eabf5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000852cf8a375f3d008cac0d19e9cb72bf5fc1c9aa5b0a3adb24c4f6628558928703860d381869acf14bc358b084e0310000000000000000000000000000000000d64b64983eb51e5a8c012ba571e5d832652fce1f99339a3143f4db0cb206186b5b7888b6914178fe4e5c8c3ddaf4d6700000000000000000000000000000000061019f3f06a4013f1e24356c19732937d4edd4e81beb934f74bbb0ad20c1e7bf85b106d13ca1f1fcb22a0e1889582260000000000000000000000000000000009b023fef413e9ac43f0f87de5a3abf1bfa246f8c415aa18e300e49831164db63c3fb957929e8548af07fcbf8ae698861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb5c7d4f467c24f80654f743a9f83225712ce63e00ba1a86114c86b04fff414ceaf24518c3e936ad444979e21ff381d00000000000000000000000000000000052b32da77e600b0f96b48db6679e6c8a8782cf16d7e86aeab87bbfcfd52f4beb18c2b71d904058063835ae00f2482c6000000000000000000000000000000001553f18e43b5ed0ef74f8f5ed87d30cbc95a0dd51138e9ce556d7bd6107c864d30d30a0701710b6c829236f1c0e003030000000000000000000000000000000014fcbb9cccacc2def9e49866a0f528bffb84cb58f88d852d2ae27c405c75aa28a0542cb7f24678072faff7b15869c04c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000098a581ccb98321b916c2e995f960196235a4b806de94212135a02ae2a537a8bf7a58e39be7ecc678ebe1e3ac73f39aa000000000000000000000000000000000e11165ce3d64b3ee070caf89b4f016f43a3f48dd2f5007ba6ac6ff0ff7108015b65236a535798153e88356d4b77d96f0000000000000000000000000000000002136934ad93e33c5e22395ead8a7132c58231c7ee4ea82da55d79795c9e23ed8521f6234997453529c5d4829df3c9f90000000000000000000000000000000005f78cb942f25ac11adac9d2200d308e14f0640810a35b4963e3e75858f6384cf2e9f1e4491a192197299eba9df5126a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f691ab4955e5cce03d8068967abc194d348753a73209f15ba4cc5cbf3f825289f9dcefa659a739674714b08ea712a10000000000000000000000000000000012b3e9c5f4deff1b919d496c6e420bb22e28dad4c15c0f9c5ab9f17d6eefece81094e5fc42fffe7d78994becf63e3221000000000000000000000000000000000748fee3417c6939978ca6cba04cccbdca48dd1f95bd75fd88ad14191d92d218851c2c68105605fffc16f91f7540cfb10000000000000000000000000000000008b9ad7d833160ef1f56935e6382c43d04c0eb9a7949b5cecb4abf2b9bdc3def921c50ca6f2320053a88cd13536d2dc01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016685084dace53c82ed44e49da76e0a13d87096422cdf4baf2d71d18c50de72b8af64f14f5cc6f1acc3fa5111408bb9a0000000000000000000000000000000017b59bf54a27e11a7add43a544d2d2355ae858212ba11ed9c77a0fde7522047cc4bcdbb40faabd80249e70de83169ac50000000000000000000000000000000003fabebbcaa3ce87dacf181b647663a66cb5d3958ac90d72daf10d3043fc249e773b5db09af4e771d4d1517c95d2945c00000000000000000000000000000000092625d8620a75cbd09b6e66bee32c597afafd8871734dd69874ffba53730208bbce11050bc204aef397b4e159ede8591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d708b455a03f86b396c70bf267a220168c7a6fcdb657517db9290d159b8bc33f496b2aa2f9cd0356822e00cbb65a840000000000000000000000000000000013196e82b77ba7386ac233535c3a953c25339131f22a6676b9678b3a9133690c765ad16b06f259b31bd6a86c84ce8a9b000000000000000000000000000000000e889e33c77bb11c674a2864fabcb9174901a333e58bd75b48648bdc870d12128ffedb7f222a9a3543cede121f48bc480000000000000000000000000000000006c84c529828fdce11084e75582aabe6b2bc173f4dab3d4410adbdedbdcd2b84835c32241ad344f1043fabbb9f94aed21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000137d1380c1f0ef858215734af63afefb588077a47543791a0133e90f33baa1cc71ab5f41cd477be04280068a63f0a63200000000000000000000000000000000187bf6045b561af33baa41772435a6e6323f95aeadd195659778841e2a7edff09fdc0158028eb9d62bb60e0f5d2907e90000000000000000000000000000000017b30e1355ad34111d5f7dba6c696ada76ac491f08040b405304b052766e38ecc9475a059357207e596756494f241597000000000000000000000000000000000cb2c01b4927a8726180c5986ea5561ba21d62f781f14f51f95f44479a669c5231c12e3acafcbdad38b2a0a55c9b47a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc703e60f9674a359346992e790078b49fb92bf32bc484f3295e6e73e1a417e2ed885e2fdc7f7286dc4d1839f0e59a50000000000000000000000000000000008d469bb9ddef72a7b90032b3ef2792cd367d2b3f43310270913b2a1c347f329cbcc8833cbcbee036e0ed58b394a64ab0000000000000000000000000000000009e5aa3df44e8817e5d62145aee1c5d769383698e4df692aad232b481de2e0409ac9ca3262c2dbbe7d89ea9c3e809b0400000000000000000000000000000000057f94ddf81a70d2569ff6dc8be4a4f82343a12c878c217fd3d21151645c73031af9458f4ec958a6faf82e4ef79f23ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006167413857edd62f44b21d23ec857228429cfba8a0e41115044080ea23c387b73cd15871a95f9a4c5f777623fd40c7300000000000000000000000000000000160fb4ee7d8fa231ca190ca3c0cfe685b65785282915cbb3afe2935cd2bee49da6150742945f2c37ab7bed4a15b42a240000000000000000000000000000000004468e5345e3b7e28c2ddff769cf421c7942fd1f5541b2cf47bf7a477159b1a080a2cd54da8815f91b3861522acd476700000000000000000000000000000000154a0846bef0146652b797d0b4e598ae1a8eff6e5b5034471eda1c650a56b6f0c2b97d38c5251f90ca93c090fa7e5b501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab3599f00b4a21f09628adaae8ac30108a6d062f709650c8322c77479c04ee589288f5fa3ae9a82ed02815ba2ba899a00000000000000000000000000000000176176cdd4845029f4cc6b5011bd490bbff7f6069a7a5d8fd8cb5069fb3a1b4cbc69c333c6d9e2aa89b139e1b65980190000000000000000000000000000000003b72a3133656b482dd7049bb544acd19924f1451dd86e32d3a7212249e67bc5177fcad037694ecd597ac86c66f274aa0000000000000000000000000000000002d655431dd3b29ddc096a4e664c23779aaad98e16dfa90df14f72903204c0c9f4f66e3992aeace3fa2338f74171263b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ede393b158fe5591f4da6a869143bbd2400365c04539cc12a559acf01e254c0d601a6a12544d636fcf7e3d3135c123c0000000000000000000000000000000011f97f10e4a8bc45322f426c97bd049ccb037a12f4c741ec33943404b300582af74f2e83d48bc9f10a313407b867721d000000000000000000000000000000001497ea1e46d7e4fe89a84763fe3e497a78b675630234a1f1ce3f60f958b42a6aaf0eb509aaa43b244d7ccb9a991c2e1f000000000000000000000000000000000a4198412821b04ba45de4d23c8a9a0c59e0920b7ec6549d75978f4e8f7739b98dbf5f33d7c4507bc47df61ff79a1d761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000053132dae59596dde08c45e7060d07e7f3797729c5b9cd0ecb8326fdc2d1c96d404caf10ee900d9d72c030c6fb648d0000000000000000000000000000000011c5e9d20b46e40418e06f3c3d4188699272c73464202f875951902cf32e9b9dc595d04a80946032352b66fe515fec30000000000000000000000000000000001751bafab5df35df8bd6c28191e88eb7249c42493d18afbe8d6ac7514b4084b7ad4dc49226dddee549622e3c685ae829000000000000000000000000000000000d0ef2be5955673aad69b717953297614ed9aa323541b459ee956b27cbe7728e10a894db3886eb94a75e76249f8429741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000aadac19becac10482a9038428ab74e0ad51016c6557230d51a9138085803970f36af3e2a36f811a3d11b363db5b99e0000000000000000000000000000000018025583b1fa53a790021759b82797c6fa54acd22f7c74f3ad1f5e41f4451e5ea3e20924be461b910bc9e5c28efb7eef000000000000000000000000000000000898956a4d39ad8896fc653525594f44c8d975e088d15f97139b9bfba87d8903b866dc64c45d682367cee414c459c49a0000000000000000000000000000000005d234661f2f86d33e33a48baadfc9656bd376cb825ad86531554858f1269030c93ccea336a019067867b4a33259ccbe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a7eac3bb63de6d876acfb6e3eb81c2a8dedfcef7d3abffd6346e408f795d6dd9c10f6d7f134afdcf75c16baee518190000000000000000000000000000000009747c6f8fb73013a5c3e1e2ea678043e2838ce8bf24bc4f1932d0de55b01877ff9940c3a42c33fef3d5e0bb24aae162000000000000000000000000000000000655e0f82d1044d4805e029cc408b4a57843f5b7e96ac10f488cf51eb41a5b0e09af8125c05685f6623b4b9b1947627800000000000000000000000000000000178d2285aef475e34042db7db1ceff79cd442b76ef98f3a97c33f3777d08983150d530d227a58d3bf14a92e0f57b73c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001218ecf0226f565edb56cc9c0ecfe200086dc34e55139c91e871a8b676c6739e8927e27cad23b894fcf3c06cdb24b1fe000000000000000000000000000000000be54935250e1d066a78c0f09d0f91b33c3a13e5fad51917d901bd99e277923afd80f1047deada6dd37169c845c65e450000000000000000000000000000000017a151f2372cc23d0a4a06e9ff3fd4b4bda0b79d73f43234eab224a90e17a8160671490bc658a0f8b931bbb9a0679f780000000000000000000000000000000011b11b501d68c4cafe67b8c180f014cc0bf3b8994e75dbbe6027fcf6de79ac2bd6234ee5877622a050c77fe6d3cc16f71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019fb50fc64280893acf058da72aebe217ae6b55dd5b6f7f37929e6f3c3181c9019a1ef3c0dfe528d2d559126476069c300000000000000000000000000000000075ee6faf0b30c785dcb45521ff2b9825991a2074436bb7883fd6477a2231d64df2cf31e7da31a05b0d0fa39388f26b900000000000000000000000000000000072dbf2b635f58a2f439d6ae796ce93ee56370f4e6ec80d384cf76d84d15bb1ae19d6548200621523d4d26318ba41b360000000000000000000000000000000002276231690e7de1f538b3392e81d370f937c4d6c2000667cf383c244bd52b16d29795ca7b81293cff969638f98af3e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7395fdc354e072439d74381fc7812f9df508adb03e3e8c32c553e32400cdb45f48f017df0d2cb044be043526268c580000000000000000000000000000000001fbe86b8f93d2aeeea09cd6bea21f601fba7984dc52242ee42c2ed3d6c4999efb56bb2c4a9aa052bbff848b5a43aa97000000000000000000000000000000000d2e568ba0c18a91ade9c289be0f1ac36aee4b08d49e5e771ee0dcbc0b217049b51fd4572e860f75054a7bcdcc933aec00000000000000000000000000000000088c8e3868d192f6a5dff3c9059dca389076ac83c9231d9d52b0e2b5a700c51f77d2d5174e857ea1ecfdcbfa6a0b51ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012597f5a75aa5be46fe55a09f9e209bb879bc4558597b95aba12009b460cb8c3461e9a22ce2ec7740943aa9cdd9946c6000000000000000000000000000000001510b29eeb4159cc4b4404cb06aa19c542fbf57bf955c349440269ec85371fe877204f57100ce537f33344ec8ce9b9f5000000000000000000000000000000000d101b8d0d5e8c7193f2e659749b2e0630300c985cf6e46240a48e234c32f766c8c52785982f1c92fba1f13682ef8cff0000000000000000000000000000000002d1b45f1dd4c736a4fde4331161b3f6190fc902c29497a0e85c1bbc16191ccc4d7c75190b05e80c7011cdad49de38651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee30107e65a436e10af083f982a791eb18cc4f2c667ed31569c4595a602a52130d97eda52ce2460b7acb4a14c95e05300000000000000000000000000000000147830064915009206f9a826b0629ad29f63c5ac9f8371d86f66fc2ce5c67ed6f933a727efd8d7bb358cf1ac60ba71de0000000000000000000000000000000019d437907a3a4b86fc1c51a248977e2d12baebca7ba00d21442e33474de71ef5906fbd4462194cad9870b1caf2e5011600000000000000000000000000000000132b1f2ff463dbaf42e4bc83241ec394062f0a7b3949b351b75d9f4f67de40cba69b0facb8d4e122957b9148c6fd49321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c0560ea5e6cac09e58892d9ffcb6c72356894a8c71734157f74338c09ca0b100f63fea224416d0761e17a6746941cf000000000000000000000000000000000efb9fdf0d97d737b13ff0dcc5101735bdb62408188a97ec5a607f2eb9b1ae4af3b1d83baad3b46354bb72d345b667ce0000000000000000000000000000000016dca7ece2f687a6975fe2a836db5d21a96f2549c69ba514a2f57eb29c59209cd2a00f8f46981ad3540a85aad2a1694200000000000000000000000000000000118d6129651bdc2a65413911685dc58d19efa153c0559f43ddecca82f96db70d0b335b4c12b8428d473c5dfa025f60ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a09a4a488c7f1c90e0684f716ca4c5c608d109e791be322c9c4b42fe4c65778846ff3309849c58b36b65a5837cf73ac000000000000000000000000000000000bb4b27a306ac659d903240605ee24ddd1bad4f3b5b5aaad299552fce13578154ff7cd5749a71f618e4c4b3e2d4a061300000000000000000000000000000000065043eea876ea9093372cc2ba7efaa9bdeafccfeafdcd173c19f02edcee289f89008f00ad6b115d3c39ee5a9fe2bab20000000000000000000000000000000014b4ae24a593533f7daeadb32aca1b81cd4e6bd17b1ad85affe03f83515a03fd48416e694777d5cedc77d23c4c756a3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e4fcab4ad53f82427b7e3fc5c6cbe388cb183379fa071319909f853743a0fb24d1ea34393cc45b1054c51b1615a9050000000000000000000000000000000005ad9dfe88a00645318ef8ddb689e470b43059b6d0a91c7036deaa4af9a4ba492ca6b540117c69d79eceb89750894ee800000000000000000000000000000000072a2d5f16e29aba211b2871e9083176881b9075d1e40b9c76902c44dbee784a9c98673f273c4183da0153e0ecf088c9000000000000000000000000000000001229d894c862ea3fadad286780f940123503d7c2c5afe325ec0474a850601bf245ed8a203f4a41597be25599a086aa3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ae8d656429c5f3735de690db51007771e3bdc36cfb9e908e5ed00404833ea9cdf17cc35761a18aa61910d4857b53dc000000000000000000000000000000000ec32b6a6509de2a04ac21fdaa3ed0fa8ab3fd8d6198fe3b3d5cf532d9d962f8c6bbafa991df50991cfce4ae8ceb50c300000000000000000000000000000000010f25ce41d4d831b3037ad030e0c18f5b14c7eadb8632437e75edfd1aeb3355b7c58d62913542373111fffb70853407000000000000000000000000000000000950761ba344414c8ca2738acdaf439442d7fcd7918608cefe231110d6cdb1f3d674e1a1affd0427e46fa87c83e347e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001061bdfe95ebb87209d74b96103dbdbd6ccf9dd7d614d7366ffea4919873a7317706a646c17b16d70e3b32fca3ef72e8000000000000000000000000000000001156d5a3f278c0c3fc7486dee78c52e26f30b9e25e613d147449c558d5392c1f77d94dbd4970133566f7898034e70e2b00000000000000000000000000000000123c1d5c89baaf830bce5f3c65bd5441befc270b5ce189a97ff4e1d2a3a8a9697a50fe66f523325f2d80e34fd620e8d6000000000000000000000000000000000df1065fc6cc99295908df3bb2a3b3fd75862a69dfceb05cabf6c712d97268476ac55635a51372a9161487f0f1bf2e1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000769f5c831832b201453c76bd672a423d2db4e05b93536a9e7ad1d5095e2910c168f51ec10886663b05ee087343e29c400000000000000000000000000000000193d74879104dde9b74379e7d7bcac1d65990520b93d00e8de1c0bc5dc80de91f4663154c5ec8794227aae8bce958730000000000000000000000000000000000d54f6fe9102a6ea945e23192a808416a5b5563c0b4e3f5c6862620003b6e77b416126a7469d5a74b1ed979ab1956ebc000000000000000000000000000000000239e1ab20fd7926b71e7c265e630dbd9cc4b8f208d93273abe9b4dfe19b5543bb478b43a84e85fc97ce4c50aef57a961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000138a62e89c56f22d01c7203cf9bc70112725d4d540ba4e928755bad7446a62e863d15e324a551a539e4d09c2443a78e10000000000000000000000000000000005d235de829d7a9968af5629c2aaf756d66535452ecb6e89121bad3c1641b5283f93c1901346e07c683da326d662b0510000000000000000000000000000000002e2af1bc34878948aaadcaf1d878fe76118276c0253bd034bfb1132c491447c8e127ee0af67595662c42566796923b60000000000000000000000000000000003e5a0aa48246add90dcd48225bf3e01e7e97fd09c1714722041a9ba6208f33c465aaa8cef7d0be1218f2ec0e4d889581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003942cf5bd72b278797346f28252ae4654716a4ec429add3f22975af5f96ba2eea976a37310876dceba9eca5197e163d00000000000000000000000000000000052c2cc3ac43194b1b933bf8a64bcfaad5d4f9a38e547f1ac95a1c72009e10e80cb479a9748869dfaafdc62e8a32aaf1000000000000000000000000000000000dbb927492f61a01c2f1aa23a6c27547793444667ea165bb3effaf4e2e618194c07a7b6e6092033b10f3afee7da875ec0000000000000000000000000000000001f3122dc1a0560e8573b0611c789e38080744f94cc774736be6dd1f54222cf2df53701ced4ea4c8900d400fffc39b611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec2caa8acdcd93315a8bea7f879d4d7dd23e20e2df2f8d325696b9f1ebda9a16d7007d40998742166199930d976fc4d0000000000000000000000000000000014eccc8599ed8a60ff883b78145d6ee2322789b5a187e5555e73e74fe6825df39b7a13a1b578b3210951c341d7446a0d00000000000000000000000000000000094062cda05cc366b6058ed2b92a86c5c5b9c295626c4bb52dd61fc1bdd49e9d53c64aa8f3ca6cb58bbc091015ef8ee9000000000000000000000000000000000d530662c8d163a3c5491203577619a323d42d293eb1d31fc2b5029a13c9b1998df11ddcb9a6dc7c35e473592b399f1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002582c6041056ff4fc1d2367dad1ed78f93eef3f4b5e0f78017a77a5498a0dacc454c74954aad456c4002cac6216260f000000000000000000000000000000000f61690e0c89ce638c43f10b6e57c0d784336dba9f715a86ae59433662ab267fb9914f54c0bfa734f0cf7e3fcf17fcfd0000000000000000000000000000000003734378e57b0ceded072693877931bb8b05fd0152782b888e0f7411c93fc2bacdbc62bcc6b059f6cb7cca5ac467476e000000000000000000000000000000001459d737ca0a3dcc867bd1df41a2872f05c9d2c5dee46bad004b5d04bebca3fdaf2a6bee1ef42bf0f603772ec82654121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4b2767605c0139fa3bc2a0be2d437c1538e5daf87faa9f2f8742e91845f5c61fd9daea20c3809bfb822062a12a0a150000000000000000000000000000000018a216adfea965b17378ab05f25184b3a0a31c263baa7b77990a1c5a481c4f29036e71c79e9cd81dcb81e68ff3b6cc73000000000000000000000000000000000158da59570f52f67677a544f0333dc63a2f6cf4087514ef3012ed967cbd6156455cbab587dd3f73120823081cf804220000000000000000000000000000000018d531488160cfe020bc1c45932f0e5fa303963f81b2294da7bdce32b5c17e101531b01c3821464efdf64676623201a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181d8f3e9a3ae4adfe1c591810c0b4afce2d00bfdfca492e16f21daff95db61b345ddade1d42dedef897646b10d040770000000000000000000000000000000016da12dec4bdf7101866b2de49e261f676d2c82b90038c18a82c82b2f70a4d9ce9b399c394177d93167de864632ec2ba0000000000000000000000000000000010d4fd88a97acd43233cab2844e7b1a6985bd2cc1a82e85185c8d7453b5ffd14e554e7641b543a978d4bde8357b65cc10000000000000000000000000000000012e3824fd448bc2f6a00db0007a2c02b6a06bbfdd9d51e08e709d9897070b59db6358d097ec89c886e6a803dd49af6e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150781b0769c415d377bdab84348ab4bf9ea0278a46781f761a5c7f7d5785e1df86b88a38cc1bb9b20020bfe608002900000000000000000000000000000000012b8748c5bd496e17a03b4004db93528e2541c9b5fcbff687a9c4cfe7bed997e13805180d4b6db9442de1877aff66d1b000000000000000000000000000000001836b670c9b94be7bd732e9dbbd0ff420b1d1d0edcc8ea08cb61f4c7cb8b125a2d9d15a443cc91ad43bf33bd1fcb10e50000000000000000000000000000000010dbb3fc1a2f74a303b1c9ec5fb4182d68c29c695db59d3947f8a13a3eb45e180306eace0b5e958bf87326bbb440cf9d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d53418baf851d031aafa773dcec128ff596a8af0106b94c7cbf1605542bcb01ec1bb6015e89c922a4d2d8ca4ad6b0090000000000000000000000000000000019475786c922f3663b5cdc04b1b61b1957e6a5185329c18c7478725307dd2ce013e247f6ac84f1bdbbc79fc87e388da2000000000000000000000000000000000370879af9df10de8f606dec85944d78bdf46e5bd6321d89513b3b4052e55386714e818c156caef121d5b55dabb95e61000000000000000000000000000000000b68d40a4ef98f44c07b979b897c0c6b5337071946e1fd1f02be3d31a2858d3757115710cde795f8f5180060e9733c191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000942586ce3233de1a402661a12cbc229edafeda4704163a98bc22e05589964b211e827724cd2cd1a346ea659bb5e10a10000000000000000000000000000000001ca2a3bb9a199aba3a8c02bdcea6d3716043a73de5562a911592e4a78fd29009898c7ffb1c4ab7189a620eb7cfcaa860000000000000000000000000000000005234d991cf7018a8ede89a30392e66da4149a34625e5030979d79c08e7b3880b1963ae1ea794f0961640ba896593a220000000000000000000000000000000007c38370bf85ee2217e71068bdfca769fd5c6a58adabf39425ca8aa6d8e9e6be18a52ad7d6a6154fb8ec711baaab919f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013c994d8cf8e4499251b7c70832fed4b86dfa255788f8d1c90199a17afeeb705dfdcd87448eb0f3e76e913441f5b732a0000000000000000000000000000000010f8f9bf97c3b41c33a5fecb1095018b7031099385e4382dab1a57d3831ba5af8a04fabde1953d657330ef9ae51bfe1e000000000000000000000000000000000753bff5bf384e0916bdcfa5a5acee046ad0276a94384359722d6fe5d7d42920660ee2e920c6eff2c111de895195f55300000000000000000000000000000000197cf040eb92ecc3d0182612a3f47540955130858d4eda38ab06e32d3eddc6b58152db3fc6efd3febf471f00ff178b0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014dac6e8a15015ff190a74f8e144e6439079f217988955c0c3415369d11397d855d47fdd35f9a381dc7c093180e39a260000000000000000000000000000000002b01762ef3f2f2082d22ff4d0703344ce25ea5767cd907e0b98effa50dffa9c610d2888c3b73e16d132f1b652f01742000000000000000000000000000000001890f862601f4d7948764f29ca6fac6b6d4a7e719d92474b7f03c26ceb7d225c91a20adf0aa8a362e580e95a24121bba00000000000000000000000000000000193bc5466d999634cd98bdf0e73c5f456f7f80663fcf3126e1dbab5ede721b7c7a4d906661967f68861beef99a2de4e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010df820a10ebacdfd0bac38fdaa746d422d991995ccc366b2681991186600fab3e9cfd9101bf4b5b0c786f77a049bd300000000000000000000000000000000099a2f4ff62aa4c792ff1dedb84119051e2c4986970c6210fa793bce2969eaf0ef61705a231edfdc69dd87f1e55d9bad0000000000000000000000000000000007ff8fbd0d1981e77c14a1d47a2aec3333dc696eacc01cfb23c68168c26da8853d31220f6beb7ddae19b3c9d85d29f39000000000000000000000000000000000d95d9c6fabf3136dc210dd43431b62ba27544d965e057ffe8a93fb6328a0bbda40b35d6d21d975a8a7e70cd0ac8feaa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071a984a893a7af2938fa210ef750c8bb4539213062ba53d4c43d9284774d4c2d6eb35b85a46100e16b393e0fd564f48000000000000000000000000000000000aabd48953be8e03867e84347523b40e44125d9899772261a253422033cfa0aaed0898ad4657c45ad31c3b9a216be18a00000000000000000000000000000000117fc1f279706494470571a77f2cba6553dd82a81e25d0c05a19f4a60419c7bf3c8321df5b2c597a2a76f8f424962c870000000000000000000000000000000015eaa9d89e3f651d0399855922bec54945c228e08dea0a2fd6f9b9de5e50db7ed56ee1226d2464712c1a7cb5748e46571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f2dca96e423f4aeba9263db88cb434eda320e17a442be55621c2ce775e2b143c82eb2e6ba15a8bb5938198fe355d8e0000000000000000000000000000000015e154683f585fdac2c9a2faccaf221b0c9d907f0d0bd7cc5ee41f88a9d8b08b8e5eb70c8225a476f972c585724ec82a00000000000000000000000000000000075e59a1710ff6a16d470186ad54872d8b26485518ffda1da4933d1bfc5be9d61fbb121d2d1c00c8787de073f6522513000000000000000000000000000000000fd9267402d667ff53c7cf7e3a7282f11d42fec1653f8d0a5294fb634207429ed63ccaa4ff053881718eff08d57282191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000430d54b947ff648f7399d86f345611e1367f6693dca5ea208fa450fcd0df9f8dd64580e99a0510b4dd79d0090106ffd000000000000000000000000000000000cdc0ff0619d94d8d8f467e7be9682b5945ec4d05b0735887fdd0fbdcb6c71ef4223ed2e29acba32bb1db599638c4fb10000000000000000000000000000000002de61321d844f72287f79372cbf3137a51fc5c277ab55b4c02d7a18fc6b7c2f5c59c187cea4a87dc8c9c744e4a5d7ee000000000000000000000000000000000e9953859401421c7e4f1eb31663cfbbe44766b6ef4929b9093765ffa61847d8fb6072bfc3bc0b0dbe4ba53392d15cfa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144197ef8de3e80faabbfdea2e5c174137236e5677e2e33e05661ed3521ef95fae1e8bf0039d8cee18020b089c0157d900000000000000000000000000000000191c3ec1af9cd31cc55ed72ba96eceab258547fbc0df9c45e89b2510a857a2c1541e9b4153ff1f0f43e5a9608e8950e600000000000000000000000000000000032418b0cd38f17f1927ba62769626095115677a0a4355563b0ae2684c6958cf44ea2f3af5157ff6ec3498c5080f15c8000000000000000000000000000000000580f646dcda9cd1b6c866b83e3eb7376f144d61918b21eec578ee1f3ed14e70549964cae768efbfc4f3029d6155a4c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dc7c4fc554363ee1c8971e1bb5ec2277027814cec4555b181d9c074ed6bcbd1c23aa18ca60952e719f4dece2e7234960000000000000000000000000000000009094da02420ffac37202103cefa6007d2db43217ad3fe8713654b26809958a48c63e45df3a418a0feb03938f22af1aa0000000000000000000000000000000001332bab83460db2dab8ba1dfedb2a0a8fd2dbe804b9df1b632ca7dfc243c276607de5bb7a57adcd2040ebb6c6e8a5f800000000000000000000000000000000131c61baa69159c6b842cdb0940e7db74bc2688fb028207d3c3c2dff3b04ee66d9eee902dec1852d3faaea85d3891c251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026c7f0d403a9f0ffadc72acfb6d5d6ffce010e287a103108ab388e15e710abd4b6763b2ba8dbdc7bd65251d7dbe18130000000000000000000000000000000011829e649bbe71605e9dcd7cffec2f693b5bb8376d94bef35780bddbb3127b61233cf657b4431ce2b53f7c3109af91ba00000000000000000000000000000000044e4cccd338f4ca989cfa137db4b62638462ffc5298c2a4319aaab008f9665416dc41032eeacad257a3525da7e180b90000000000000000000000000000000014a9741fe8e4b389d59b454950514b26c5e96888b2540f08dcb0f6940935dedcc4580cc216df578718eac8ef2d5232751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000869bd184e03442a72e020987e53e22b78a8e19ba85f4bca24feb9ba25d230e2e5f1389c3a72d80970e73d0b2b9d3ddc000000000000000000000000000000001392ca32d183c7be512340c3f281843a0078fe122ec772c3251aad67db97f7f29424ebc9dbba9c718e49b584eb97bc79000000000000000000000000000000000841a7fc314edec4fade78880d1f55a481d1c59436ea6d10ae8c873b777e1095f03b6ecd02da4aee6badfb06c3d515fd000000000000000000000000000000000cb4f57c6a4fb92993e08f90e7ac8691f5743df915db919414852317c5dc27de5f015ad35f0f74cb20dc253220229a761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000661b63be1a6e5c8d517f7bc1efba732d28aa6a79d29a0e46016115f3601aa4263b7690f64e3437fa0c7347f0a43134300000000000000000000000000000000054ba61abb44247da16f99ce39bd2a91d893f681d787206be6177ffa6286075dd44ba07ee0138d86cb169aa9094f992d00000000000000000000000000000000079c02e5961dd0bb9f0646f950f5c956e09b6dd495c6b8c2cc4f075fe5cc4a2b2681b9b739b1f38cfbbfb1a7fda814e6000000000000000000000000000000000fe5b0112e3ed319d81de39069e15b6d75b27d66f4683f77691755a60913a354e1e5c20f28ae19dc63ac8cfab27ad1341824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b449d7ef367658ab4431d14276b18fd6820df160f799ca86c7c4100ff2722f99012708ef9dd8dbc8e8df7938857a7d00000000000000000000000000000000071dca4416b8eca004e53f870201ece759737ba88e769ca86017a77aabdfe94bb3d721879491d9765a139182e462b7ea000000000000000000000000000000000d0d352661eff22003c809582cb02ea1bb8e56ea97ecd02cc2e0e86cdacf4950044d5f0532323ff22d0cf2d6eb044733000000000000000000000000000000000d7a0cb8a69e5566e52c8ab297b4778fa06852a1b6133bab46892a04677d266548caf9816cd59d83afb389cb287ce2ce1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041f5f361dd0d5bb7fa89d6a3b9e85af7dd738f3069612161d8163ee17cab59e9d3430415a97f375d25bc962c9863d150000000000000000000000000000000008240c6a28648d4dad94722d11183bc2fce44559f73f0b1cfb2a11b389a4a448a49e38f7368eaac139e56f0a565c14060000000000000000000000000000000016760f38df08899c79dffbec406ae694a18f595c962631cc1269e0d640b69a54dff5a093eda11b42bd21153713fd39860000000000000000000000000000000016f8de7a13d0e7ca228209e066dcc8be4bc3fe2a968c6daab94cbef53370a0c6bda63ae1a488ace02111296cd833710d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128c2f8ea70b34b66c90071c62002638e1ecf1594f1efa0b99324d05c805583b44e1a4d385896fbf33de6fe9de7402ab00000000000000000000000000000000169909590f3ac5a4251526376d95700c40709be28c69ebae8d88ebd98aeff63fe54cbfdf205210a694c7e8ce7c9a2aae000000000000000000000000000000001567a3311837f99f35ea37fb6526b3e80776e9ff3907aaeae91e43891d94f3a6337b5646568172763cf376cd4fe1ebad00000000000000000000000000000000110538bd9fce5f280c7e0d5ed7c6e90dd117221e7dec283c8d87315375b5041867c6def97449c370aa118393f38d59a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008501f00568391601db35a5a80a53bbe84f53d28a45b26e9694771e82d453d941dea772eba964f3af0f62eb9dc7ecbc1000000000000000000000000000000000049c816ececbdf6b0add77ab1ead027448f08e7433287eb8a67a44d5d873b36f4d6edc8c2558fa881f52a808c34b1fb00000000000000000000000000000000008fc72234996bcdc1714715d24a2c8bd7e61e4402e7ac691031c816cb74670a2554d21683e8b8090381cad0c52a9c8b00000000000000000000000000000000062dfe200a223cf3cbd8efbc70c20a61a42fe6b6b8ba90d3c717ee6cd224504fe726680f0ed89ef31abe3fd3221ad0191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001ea085a42dbf1b36b2fcaee991e460a83b049e3c19ba9cce27e47670810c5094172e1a6a3ce373ce3e28d7ef87f6f3000000000000000000000000000000001979c2c21a5b78f3f1238ff99df2982823ba683f047a98d1c7cc5a2bb1c2bd6846974cd5733cf503a2d6cff97ec2b50e000000000000000000000000000000000aee615d2d24f25e8c9897c936e99fbd183c8c789be2ab3785cdbbdb2e5fd85831bfdad3154777370194445058ac675300000000000000000000000000000000127fcb6860c393fa199bd6f644fdfd2e2465b7c1f68cf4dd62b5c2509ad76bab7f8d7b1f351de695f59bd401407aa5c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004b855000650d5fac7abd5cdaa58ccfcbf86919c8a7744ea69bf0e966eeb0f2011fff71d94bbe5d4f60ba678cbb9e3f0000000000000000000000000000000006b0970b71690ba25daacdc9a9c36d57d02aa123ea2ea76c58f5c8bf069a35f156e7b115e491f2cded49e5bf93e1f55b000000000000000000000000000000000775f4ff6c24aacd1e2a1dc738031ee8e32d6e47ae6bfdcf539822b7efaf2816b8dd58136bc6bf6a14e725ade134a0a500000000000000000000000000000000188285946e65235b22ff05a2d4aaa9dfd37238c872cd663385b42c54cdb813967fcfbf852e6db3f457adc2b2ad70cfa11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ecfd019ffb86b58e8a5773482b3ac8b58b705c1da2896b885c41b6053c06e25cb76d8dd222280bf5ed1e81d8c8478e0000000000000000000000000000000000c249ca53663917212d185d472419c8777276dcdac08ef9610c54f07e326ddd7ed60198fecc7b6b4fab3ae858fb3f8f0000000000000000000000000000000009922a9469e46e07be39cd9ecfdbfc1cbc030b8bb48f57bc5c8feaa447a3573f06d397134357c48854486d717058151000000000000000000000000000000000177c2d7fd5136df5bbdc2f220ba4b92c1ae97a1f43541afdbe67260f38bd2b0f556ce034212b85cc2a26acb210676bed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001565c7c15bb1763d3289a31155eb9d28243427f07b8db224384fea64d8141f2e5a3592c5ac39e3e373148bf71cbfdf6500000000000000000000000000000000123ba9c99652eb0cdd19fe95a641b1dbcffea425bb3c07f2f099ca226001e6df17f42271f246c595bf872b69e830eb2b000000000000000000000000000000000a25e0580ffde95097d303a9ce76948e40fe7e5b6bf172f7add2f66de0ea715268174fbbf20313ef7ae197b656d4571f0000000000000000000000000000000001eec81ab2eb68675f031af0b425767917a400cf5a0fd02a9178e4486ca9e7367271c644030244532c4d5449daa04f801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004a266245f683e5443d77d63d7995501a5bab7539e980887dc546595f873b88fbd6a84f4dcb5c6ee6d3d8a3869be6dc000000000000000000000000000000000e5e2af537ac763ac1ea6bbd1fbd0eef4217fc53194ebe8a71af44e20f78dee17178b2a82f0471f90ae80ea73521d9f90000000000000000000000000000000017f7ddba179d67e69eacb523cfc100a5b9aaef7c2d8f8a5e360c1f3d274a2816c391cca0e110ceddc7c9f5f62c7facd30000000000000000000000000000000004881af530e0ccb481e7b5b2c0efcb8cc2224cb13d9c4d15f96941982db3db3509641cd5d10aa9f409fa8fafdac896801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002014fee4aa06b8b54df685fa317e6ae66ffe03400bf00a3b4bb9d8582f3cafcf20eeddebf29b42cf38182eb2c9f5969000000000000000000000000000000000e7bc3acd7c665fcaff176bc371d6b1619e71f8ff0d98c934281fa980955a872eda935d312d2be51d1e18ccc794f505f000000000000000000000000000000000139f54c94fd27ed1158ac68a963a3be189e3c5321b5b339734d467a01183a7afc20af10e56a04d05a40c3ef66e5d5f500000000000000000000000000000000082ffaec3f71773b0a337001f7eb83b7127f4bac147506985c22671e5845f9ea43c2fd07ef75ccec9f0b3c4f999d8fa71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d3188ec56b89efdd4140eaf94729db68ad1db5d8409be8812ca2c55f6beb41e288b5f57b7e0e320ac9ba524d5ec775d000000000000000000000000000000000e5d2dfbe3623d9869b2370b44bde33263c983c2b127b2771e8998593dc74b7e95dd3e06331993e02d316f58209f9265000000000000000000000000000000001846dd1057c0c1611d130392b6a85e9c21dc97bb4b7e58a1f2b29feff4189a1d0ac08b848a0d8514c7acff4fee8c9af0000000000000000000000000000000000de97f51f406382a0afc5e8727f78d528e04b138d3e99e38c0e285c556af840759eae9d61a65c99ef08a22f3a97074301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159f056cb7492c136a22a9bed3213a3d719648bbc94c62a11368a59b2df53b2d064fee6b64453e75efe0449c891a2ecf0000000000000000000000000000000008917a967024410371060e279a065f42add5effbaaa3f0d5cc9d50a2d11a1bad2b277b8d20e9a8e0704895b383bc2bec0000000000000000000000000000000013ed48213dddf23ad4582a18d944d031995dc1fd8911aeee63379006adc8bca790791e45994c3950b336a8801badc037000000000000000000000000000000000edd30ec921b9e05f15e506814960d49b561bbec136e4717aa58d217cd1712e45c7a5fa81788d1aac8e1abf37eca463c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030cab3e0e518d8ae1b59222dc4efe3d0df221cf3062891f9df9bbdae0db7b3cc691c19316c563b76ba7d2eecea5768c000000000000000000000000000000001439f17a3c3c78166c8ad39474c3959f34fce0909b8073ea397d5574d61915efa153518005e03896f180adee8dbad2ae000000000000000000000000000000000428dcc93864d930d05371cb0e8cfbebe26e3df67611ed045c68f86462b43144fc47eb7a7a8cd2a60f1c83702112e99c00000000000000000000000000000000009536646d9c7120a3691a347e100da139cc05c2bf8ce351f0710aea25bca104e6aeeedd0463103f459ba920e42f5d401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020489f3c57221e2e98823e40267d8dc7fec5ecc16d6683e6abddfe664d1ec19ad95ac645caf184a6a5a9765cd88187800000000000000000000000000000000141c336c6cc6b48ebc614db0b4a3f06a471619386444b00a16720e924a8afbfd71a262e8639eedc2e58bd32c8a161a000000000000000000000000000000000004f43c1d4b9d18d1859a7b1a0f2694cd619f1d05662ace8095c19d59bf5baedeb8348a6584f2530e2c9fe34c31e505b6000000000000000000000000000000000d1dda7763109331eb3e777b94b9a9d2cd4b055689dd31f26baf3a17f866714a97729808abe2bc7f3f107e4f74fa65551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f64fa02c64668b8c31684dc7d028a674938ed86cb3654695ad4b37c093dd21fcff225927938917a14cb59340808b0ba00000000000000000000000000000000147f9a2ddb46311e9e25784ee360b367ba4566f06a59ff18d525120aee4903bda6de92b8f264d2cc9079594e9df590cc000000000000000000000000000000000dc9eec8d41d4461394585e662b9cf53e71ae86633e7602ade1ed48ca2a249194389a46bb301ebb9abf0aa946a724adb0000000000000000000000000000000015c4b0513f54009dd97fc0a1369f1c4f9f6a4420b88952baac38cb641d0f4bc75be8d64ff2219f0e1eb54c9b117711c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff9450a6384a743c172c50548c5771154fb701bf2676f565ce4ff1fd542c5ec67f5e6246029ff25aa3bc124b528ac83000000000000000000000000000000000df5a88f6679e81e5ce2b04b9f40ea04c0716fe3242a5ea38df33e4f704ae3ef9f0a8dd22d0ec80c739616bac84c6e70000000000000000000000000000000001198ebd3f95f5901c323f5363efdea94bd9504a91f69177348fb0e6499ee07a1c90c1d22c36a6bbfff111f538c36fc5100000000000000000000000000000000190c2e4d307a9f4cae822c5feb1612d89d5879d1e5ee7fdc65006b30f81eef7a9328fa030791a892b2a01790c2ef37551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057ab7a09100254232f3cecdc9f8029948ba29bbe4c02dcf7840c8c9ca799e96436c6de292dd74284f0a1a3b4a823386000000000000000000000000000000000f24cbb3c25de6a49054c22a7312037ca10d7cb29c4c56d8cfefbf14203740b5b44c57f1d94c677b58abe4a7cc862f49000000000000000000000000000000001763d329b41d215e5c83d305a5ada860123eaae55736f1aa9af00113a30911e7999e174c4bf77ca28b373c4ecf1f6da500000000000000000000000000000000180e78b606854b01397b6be1d2d399aa5786de6ceb9dd71b5f0620d6d9a14d5ba8a8d3725c6c4e04d9b627d5a032175f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b4a7ee6a5d8a800a5a6dc52244b4a16be005a5d0f56e26b5f484ae6741bddf0c687864ce91d7034983def161065562500000000000000000000000000000000199ae18d3d872a80c00a0032e086048ccd9f960a916179fad150428f86b4b4c34a4d68402b54e7930c2b8c5e18424c690000000000000000000000000000000015785624871df04325ac9a1adef70b61c5095fb7f04cb8af48e28b3a538893f1ce77f5ef7bc46c9360043e2200a236ef000000000000000000000000000000000be56d37fb902564b9d67b7041fb126afdc19b71695273ddc7db741ec33c5f7b9bee392e171e2f86b2a26d156055f10d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000237fd377466aa897cce1cecac822408d835bea16ca81e3f4d78de1ac9c88f99f7c3060400d576288270db785a11c7690000000000000000000000000000000017e97a5c1180bd4bd1cf6c22f5b2796783908d8920d580131cddcff5073a9c04aa4b6312a010367a72db94e3f71cfdd30000000000000000000000000000000012bbece809142ef3902867698aff9aabae77f30efc79b32f3ab75899b06fbb26618d03661010c92f2c87baa88dcafe19000000000000000000000000000000000ff2bdf42031e500c7dd4796a417ba6543e2dd98ee7612fa345d631bcaa518c7c6f7b66f9cbc54722e0f519752f67cdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa59c8bc43e312392ff3a9e6dea839475962229bc408bd6adc0da18cb60e2b0b534bbe1c008549d597454391c44e5430000000000000000000000000000000016f101a351d3e0b1c4fa4598f1e3177e017b73fe843e0bf980fb570423f91eb9c334827c77d845432dd093ed205c9fb1000000000000000000000000000000001196ebb311900d6868117113d90c552cab49803cb0a0b8cf391b2fd9cdf1990c7649d47dcc2410a0cec6a64a749343c7000000000000000000000000000000000132a5483eedf0731c8659faae2ca4f5a3fff34223ef351aa7f06e4c981ee82945f5beed4682f78d4886c7d5446f50f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010077db5bde3b49ba046709a79a880b655b0f11fa3e4b9912172da0f8058a9a418d609d9896e79418df1ff227737c9ce0000000000000000000000000000000018176b1ad8a805446038336a04c69f98e29980e60c4dbe42dc3a9a69f9081ddb9507a271869169ae302751994ac2169900000000000000000000000000000000050a78400702e9d63d7f9b1ed76d4c94b80b0bd57860b01bbebba1623a859697802de1078f42f699944edf021d75e53b0000000000000000000000000000000019763ddd75a07fabc1ec6ed793b7a844141d264bb439c4356e30497904ac9fb51879252e2f52668970b7cb9a0810fdb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3b26ed3bfa1080d26fb1095bb7aab4da72c0aa90ffe9a7571aec2e623f0951eed48e1b811e0b11deb4e337bd720c640000000000000000000000000000000011241b13882b91e400b9a262be668d516af35e6e5142c247121bccf2b66b0d3e8b597cedd0d845beba4062424286464e0000000000000000000000000000000018d65ca084d05f17eb56bf4701f73590dd942bb9a9835b5588d66eefbeae5469eeb65cc04db75a57155ac24ca253245f0000000000000000000000000000000011043d27631cfddeba611760746df2fee3ea3208ef1b603f741570a98d88c3389c46dbabe5701402758ac12776a198cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee07ba9c2316d44065fb3d9b8d739da7e6d8c4226b8184567e59d14e787123918269c153b3f5e0da0dc077461be3fd3000000000000000000000000000000000d01499b5c0a3ebdc213938656d3ffced0a54c236cdfff93e1a0490074eb428516464779612efd2f683e8693029bbe2f000000000000000000000000000000000aaa270b96987ad5935b4f8a987381791952d8028d2983e71ae71c201d6c583bc2aeff5ca827ee4a1b0bcd801646824b00000000000000000000000000000000064e8e652d228d78f49ad75a6b3b0a273cd4dac8b81e5de5de45040d822a09289460475e2f24260b48d0be2407526f051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001981ee496f2adb595f8d97a1720264670d87f1860486e16f00dea74a945663681b09fbc7fd793492406cd51f7722a7090000000000000000000000000000000000d578a8badf0380362f42eef18a115e482bb2b14f5f7c896ad1b248bce86fe4282804f44ee9ccae8a29ee860b4ee8650000000000000000000000000000000017ecfddad4e5a0f335900d19057274a928cec1a6818f5ce0d81c0bab5bcbddac68a94cc724ad67c0a600e45d879cd3d8000000000000000000000000000000000d81b219565f8554ad1f7bd139e77a96642b51d73f1b89f978db4dc1cf3e781f14a659226b7ff2c524970dcb02a462061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000907c0e117ca2628517b6807a0d023d17b2a5a7188ab50c3660f5a716d05fc78f51d98fa739adc7959d77b16c832f5000000000000000000000000000000000006ccc067a6886a88f7a0b1f370c0ffaa7bb18ab4f4923cbc39aa292257dc69f80ee2d78d6785aa5bfd321368c73e02870000000000000000000000000000000010c13078cbf02f1cbfde48e11f52c5e9b6d74845244316e6482a997bc0c35db14e8c7246627ee2e6844864a775fc168e00000000000000000000000000000000095aa56fdef1eb2b268a0b996c1aa5342303f3dd2b50923c99c4b72ee81f742f7273e78c27a7ab3984af493b574a566b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004349ae0f80d90d9b92e757d4ed27dfb7a003e22719cca7661649a55dcf3a79192bb19b92309cc32af8020b344fac02700000000000000000000000000000000085e2c5493255e911482144788920ebf311bd5e93fe85056ffd08ae76ce666474c11bdd9467515621dbf65f998138a72000000000000000000000000000000000e9767ff8d73500397a43d644fcb3d114d6ce336b75cdf0744978051603e891480613096c6959f279518a49efbd3cefb0000000000000000000000000000000015785fa9647aa5be46d82bc5b257ba4317a0c8bd75ba4f0735c718086abc35b59e9d8761023643fd98d0ee82e4988da51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b5c47ac28de1316725fc048d06d172bf9e5205222802f5293bd3b39869b9451d1c23b4514d7f0d7db1d750a641276a000000000000000000000000000000000ab2fea3c7659635e3d37440e49233335dd18cf3cb4d746738d326b89853ab04da01834a35b02f3eb9c555f4204abf5a000000000000000000000000000000001603ba50751ba1d3af8f8b9a56edeeec42eaeb37ef89e2bb445f058f9a0aa4e94e215f97e51ab747f3357193ff56815400000000000000000000000000000000047e7e88c5e6074ef0ce938ecde5f2d378d510640f049f738d5999c01762bc050ffee6eb9e05cf3452404fbd5c52ca581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065f0436ef74dcd0603b4b6921a150754232aa5a0b36631f9435fe95f189f6f9caa5d41ea0296a77556ec1e6be69ac0c0000000000000000000000000000000003d518363c68dde58f596c2c83424c04aab530359fbc288bce56bdbf0a4275cd9ab5147feb77983b148864528ebf9d56000000000000000000000000000000000d2fbb6f8220f4d7975df76ae86be37f448d13392623942a4dee4fbc16dabe86ca33984c429e1732bad7bf2bf7a63d93000000000000000000000000000000000c1f2e5c07196d59e61cfed0282dbf84aabbbfe0e5aa319dda47f15f663888533730dfc62a3b626f5d647a2174b555c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b63b0f91837899fc3a5c8cebf4fd03de4997a36d7fb2ebbc46e3a0ca62b8d4f5fe193a669ad6499b004580f9a6a67ea0000000000000000000000000000000003fc02cf7a48737eea8e699b090f8a24e597227fea2c4e7c78f03fde6601df9409ad84b3b71204266136f5ec11961224000000000000000000000000000000000e0bf0e94ec6ceb784a16369d446408292e8b3be7137ea066956c16e75bcd29ecba1e76e6f6010189a63d64424deb206000000000000000000000000000000000f4cb04088808b3486a5dab785fefa7eb8bb01d66a9e4b696a2fbab2add7b7b2ecac6905f28f4e53df460376ed77c5351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a001a571fd2a5427a678066c3283226c153f41b38260923a9235717a8f63438ba4630d968ba8b6d35ce6f10df559b300000000000000000000000000000000187fd7ddfc6edfe8c168d0c39f8ebec03bbcbcf5d660a0b7faa4c9c02ab6844505835c97337989be85da128ddbc2987800000000000000000000000000000000191696547c4f4aca3cefcb2e37da58960b2acac1cd7fc3c6ac2ab6575c777cb8c643d51d1aa4b7f1b894413cecd7c14d0000000000000000000000000000000004535f298eaabe35018ea1aa59309445b86c90a6098157ee3514b2ea5bfde659ebb197673d0e84853e006b4413115ef61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c37aa4b763862f685ba6ef89b4d3fcea7cfb1c40c26710a428d20209c2e006ac7eeb04bdb23addd60c6603673d1a12000000000000000000000000000000000af2d501c2cede3ca33e62e38fd9cadf61b1e42f39ca5d8cf96094702572b66fb0a73007bfd8f8bbe35e7f94a83f3507000000000000000000000000000000000fb8aa0bf0065003fe8e7b7d0438c00f3c1d4709c2982380e9c5919f1e1840efee59c01f72a619b092ddb4af50ddb6b3000000000000000000000000000000000030c347b5b289a2099f05d51f576d10518503e40932cbdfd8b2d8728d6ab67731ffd3553ee5a501fe4b256f6f0a8aba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000092003e51e8ba3c7184ce5fa1e841519902228487588950d551df9c73504d26360a226cb287acd00fadec5019af35cb0000000000000000000000000000000001623545a003b3a0dc0f832fccc1ba420b353c2c2a15d77d0d8bc7c52587b79c7c35765cd1cd1de008c7e6bd96d994ab000000000000000000000000000000001986e9f839530a8b6a7ef4bdc2b7126a72b3a73ed2f24d5c7558a34578305ab82bcfc4d6a449a0b844844ffd2386bdd60000000000000000000000000000000006992656873bbdfcab7f4adeb4fd4c8090c132df16325518e4e9ecc94e7e9150067026d554fe333248f5f357e6acb1541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c0644ad831033eb4e58db3f76c94a9bf31bd0be767ef15340d57e45844fc3f55fd29457f81c82bacc9bf6cb97b5b490000000000000000000000000000000015926badcb95f762d0b86c430b67fcc471b9a56a29740d2367a71af1c3c97c8d41b97395ef9c825769986216ef14e5c50000000000000000000000000000000007966fbb5222ee7c60eed0b50be7f52cd4529aa1dd0e8144c1885329e344cf8809728a026fffe8e0f22e5968368aaccd000000000000000000000000000000001900e496c37ed7e743a76bbf121b8998af95a72e624618a5bea3cddc410902242dea40db1a5059fd628bf790b58e17581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000106d9034694c29483e2cac1a3f55e88121f3dae32d08a15537b57058af93e0b125f87381bd5b0c3332e6240c8318a730000000000000000000000000000000003e925789cf8dcf78556647eda280c0f786a86b71d17bd04f8097ab478497f9f3388efda0f8cdbde83ddae70a61ea74c0000000000000000000000000000000018f2826daec8c239ca24395a2d4590b03544b1135558fd049e0eeb4e1e2e68924975527192bbc71e7a7984670af17342000000000000000000000000000000000ce9a748558afd245159bc17244e90df35c3ce08444d3313b8b090e5570bea1ace9c05adf80a381923d87da4cb36d6431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d3c247d59457ac3feec6efe5c1aa07d91058c2f127281f8fedbbc2a65ddf5fbda2b07f92232f5b3f6dae5b28a0186a00000000000000000000000000000000085e33841f02c3883ec3b0184e4502c1277d45734789bdb2ce86e5ea3c03f73d9dd295be09ad99f3709d6c2b657e496b0000000000000000000000000000000003026ed8e4cf8c1b665f396e5c2cadf02c35853a7557d47477022d89a0b1fe8649ab073923f773dd39160bb5c02d6c6800000000000000000000000000000000096775ee4d2b24f1bc76e6e67c52c679a7852e64051b8ac0e0f448f42c4a8739185d585ece6bd91084fe6db7490a0fac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001179123c4e26298dc7757431d6427163d1458d0f16a5333e8cd695f1e0480882fb94bdeb44182e0243726209fc9719d90000000000000000000000000000000010dc8414f9f66cfc9539ef33bf3282d41e4bab53e3b97b88ab19d9bdcfa821532044ac081b22c17a1c7d6101c3b33cc20000000000000000000000000000000009d4f24f3427dcd4e64af0788d9201a2f081657907fe82da6d5a2d0949813aaf7fb0a2a276f4a426eaf0e19baa6eb1c800000000000000000000000000000000163cc177fb48e108539568ce153fa04dc95ef8e394c4cb50e9f087d81c4cf57655b6409aa97ad47849445b2b1bfa24f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cccef0eb0cf89675827ab514e56f05c973a8aef9b9b13022894e9ac115a1f57fdc6e579262aa11a81c38676263620c300000000000000000000000000000000034653e7da449c2084168697fa1b29048e592b6ecd65c4c671c64612167be749effdb3829827c5e49b0e8a875c296add00000000000000000000000000000000192a4dac703e856a587623d0727d8fe1759bbb571757ad70b69757dceea9b3b1d243549ba6ecd88d4e7c505179c8a1b9000000000000000000000000000000000d17d3d6e5c6b07b7768988f7c9234006faa7637d914ed7c40b4be9eed65a9a0261b42c1803c02c3c7eea5f7fd1ee52a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e964e6f7e134ca54bbdab74a6ea0bc19f52d7ee610887afdf058a5e6a855bdf0e1ddd65c40abb714291808d41cce6b1000000000000000000000000000000001705bb063994356c83f2fcf95abb8701b763437a38d4f0736193b14148f6a77cc96de59116a1d64601aa0f5ee6b498890000000000000000000000000000000005182ddf5ce75e21cb8b43367185a90b8712c652cc9d5a8e4931cbc2a347a8426eeec5d034e667c798939095991f7361000000000000000000000000000000001734837acfece89bc74d6b591eabcb09497b6fd9b08c28cfd4168ae75a951cb4b7de8cf7298aabefd1c8a8c088b102e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008140cdb4cb8cfc8389e5cfe143bad14c5d52859418ce201b47e44b591d11847c17a9130de072e3b08b6d9b622628c600000000000000000000000000000000017f9e770eb975b1da79f5eeeeff3db2c256c4d9d0ef26ef6b9c7e84d89827d9e5857f80f3689c917e91fe35ce750316f000000000000000000000000000000001759f95704a6c088d7c32dc9457e6e79e64126f87bfe9e8ada8c3e6f6877c1498df2f4bbded33e8f2a591150f2aef0dd00000000000000000000000000000000042eb28f70e9cb5713ae0f99911b895af1fb136765cfddd49d126ac89c5205f1a9978222b06963823dc327e3555203d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df43fe1fdd5f1db37abe99fc5cc7a0d796c38257fe1cb483ca915acb35f9356051963ef03b3fc7f0896043acfe20007000000000000000000000000000000000de3030e07cfa332158e8c6739651067d015d3cbb7f13e2267d8eda3341b488c792a552a9c4cf37b9d85788858a3b741000000000000000000000000000000001815d4074d940078ebb29d01fd4440a7e903e2594400beeec5a49099158074d0892688d625d90fcdfdb344355865942a0000000000000000000000000000000011dfbf5993989b0918c3e1552c575b34c2ed33e27303480ad6911e9ae406d06f530fbfb75313cf9beda18b9aca8ce34c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015588b2ac123a52c7dba167e56a06abc3e1f54ebe28812a658f208d57ab423bbce08876624c10095132fed8261577f83000000000000000000000000000000000ac654818f3b71caf47cf0715208ebb5bf2afa87b95b85911b8b687f9d96be8cc6b8b94585e12b9611542990f1a1f137000000000000000000000000000000001759fa999db74bcd803aa956004422d9b389c51f5bdd399fbdfe3fa95e180bc0786358b6df2a90dd3bc42ef811213b140000000000000000000000000000000011910f7f1e572a2769b333d622ffc29505243f95d2c14d7cf477a521ae5ca562ab86a40747e3a99aa7b22b78d3c18fdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003110ffcbca535770efc3237fa1361647633fca5d26a0c1365742326e42ae71dce6236f1a394a4cf3457622e5ce2b2d40000000000000000000000000000000019a808f34f27f28d1539aa96ac98f709ad2548594dfae76db7221d70f0358b6cc01b160302017deea95ecd7826d4218c000000000000000000000000000000000456cad0d6d602e87bf9426cbfe9681720dd0840dbfa72a88e23f4dd5ec48f3f6ea6e68835985ddf5e2388d12c380ea00000000000000000000000000000000003fa2d484b9203b926f52db3ce3862ec438ea01cd2b94a98485ac074b92ef2eda7330a8a2968926e48f4bb17268808ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbf62ecf0e0f1f43d05ea4049114d316858feeb5b3f4c87755c8634831768a0ce6fe7956cbe9782d52f7c2c6daf743a00000000000000000000000000000000043fe2d93d8667b324daf6d0c78451469ec4addd89ffe26618cb3513c20b54d1667c4f0f798e0bb57dfff9544b0f41200000000000000000000000000000000001b7562ee8b7c0ca113c1c96354aeae4ae33cf1b7847f9763b8341f47c71f4614d7e6c35356f0b20cc9daeb3e2241910000000000000000000000000000000000da22f72f4c534b4f6a182f55778326f03966e1b6232526a9f61324fa21cf4e9829da54cf98f09f95d2d3d39ee6edc371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001614a7583c4a0e9e75c5c05297b634b23f52aae53fd14fa298e7b9e5e6f396a41b6d14a5172501b6271f38887cd149320000000000000000000000000000000007e13688c00c2d5458328df8a761eb2940beb1d47e5588f6101dcac85889c19100c28e480332e4dcebdaa8ea9b2aacf6000000000000000000000000000000001919ab7983805f8aa845de443968bf0623a81aefe20b92756078f4768682f4ed974b7315ad60a44fbad335957d7044c90000000000000000000000000000000012fb65a7549fa68cdd4c595cb07c0aa17310ba329c2dc81de4ee78e15f801e492be9ebf389ce9f746fd10a27c555fe3f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9dcb9d4e1731040b186c9749f12808d6f9befda70aeadd88ed342c0a655c783ad7c09136a3a8032afe3bb0acd88d900000000000000000000000000000000002fbfe6f827ccda267a37a178718568c327ba19b604d3838e4b27f0690e06d40147171bfbce6533c6fd68c06d9a205f30000000000000000000000000000000019b8bb27f0ddd3c8188dd442a5581ab45512ef49daf22b8eb3fc1c468a0b8835f70986fb036f9fbd571b2eef1d4734d1000000000000000000000000000000000bb135d756b526bb06d728bd1ad3078bf844a8abe2d3cc646aff5f8472f24aecc2683955d1e99775297072a51744918d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001997167a030a1e9b630aa66fc9ef1b5a756cfb164bc4adc1fae2e2fcbac0e79897074d6c21996d7257ca2a8ed3a800d8000000000000000000000000000000000cb934cebdccb1aa8d17d27cd69c11c6afc4f7a4371a159f7043ec12aba4ecccb489733fa0de3ea3dfe5ed2181c47adf0000000000000000000000000000000005f37a6783e54e8652cecf1ae73985a1a032346a2214208aa987b7aa20ed0f25b6661166ae7312fab7cfe4caa6713446000000000000000000000000000000000e43dd67e0e746274dfb00d8d447c8c476225905f82d881eb3d5443eb8ee2e186d0b8e2fade98da52d14c6135ee0ab7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017a3199176836da4cc11b9222b2577335a492710d9550065583e18376f184525748f42124b18f49c8ee15091e3042ce000000000000000000000000000000000104f3bfd72a17e08e27c1269d029b9ca5cb0cf10578d5188cc6959041097982d8ef4c69347571f947f488cd2aea949120000000000000000000000000000000015e173d9a9e9b97a37f307795f5fcbf913cf3af37d2fb6831d6b9e9df56ec0d5bf277d6cbad64edd584efb96472b3e6c000000000000000000000000000000000b33774433dc1b6392d908fe01e6b5e6971980ad9f4c5be1be9faf44e1565c7a595498e9f078bb7e4c94c3aac3090db11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000132e2a31b62ac16f46166a9d6a77e49d627c6d7215165e30acc96ced4ae57b8653a353d6916ead2fcc59886c65b22fcf000000000000000000000000000000000c655f8b367fb8019b19f7f1a72349aa3640f22dba3a1fcdc749c5bf9f5f9c86e0a07dc7ff5cd4316691d977eedd0f4200000000000000000000000000000000171752d3d4f9e701c3514df071f78f13271ed4886adeeb65b4425d349a1c4a2bacbe94497be48a420abc3bde4f7d15110000000000000000000000000000000000ba2bc6a9d908b8760208d91b744543e3e8acc44241f480883c96d3beb169e6ac7229d9c9b23206fa745e3f449fb43b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000065a69c9bb85cac923021f28072283c1a4b77a9a629047a9fba87654365e1fb55833725f699b82d2a99e06214875645000000000000000000000000000000000126ef73f13a52afb960c11628a568dd181e97f7af44abb29f007b3f3acf376d9a428a0eac6ff38bd824835547beac630000000000000000000000000000000000f2846efd22b202ef8cb7fe91e3164749e69f66f449b72dcf34a7503c60c46f4d79da2ebeaa35d4b8bc3a156a546c84b00000000000000000000000000000000088e1d55c8206b4a2034ca0edd4d397c5a10ed3a93d2832e846bc128cb19356d33cbf4b89458d5b5ebedfdc1c7dfde231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a14529c650ce5e1e570a1ae183727810e20f4eabcf9c2352dec714448997a10ce044fb08fbf153da399bc1b4e8f36a000000000000000000000000000000000b4a0f2f1ffc49deb3959984f522ea271d171fb0e69fef232b6e12c50cd4c5f98b8d615b1ad8f53749dc396d1a3556f0000000000000000000000000000000000f08a83857984fb0b25fd2fdf4067264ae0e8940ff73cdeca74530fa85b997264be8bccc439216bf5612a4730361a442000000000000000000000000000000000326b846cf8a34045287effb1fd9f456c4b04dad5e7bb78883d9b938b0ee76ec09f0ad22ab23aefd549613d49f9ae59a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d9b9c8d3b6c3eee769553717b2b8de4b51dcff950444b9644e18d87b676f3dde2732f57e41ea7ceaaeacd8b479736a0000000000000000000000000000000005ddf6a5fb4d7b28c5d4b045245d870415c255815802f9964321c13a38fccc29159e91d630b891111fb1047e1c45c9d80000000000000000000000000000000015e00957e6b97d936d60fdb331f0d78e992cc098d8a240f75caf80ee285cc414c7523a3a43ec90a72ce864151eb0c0770000000000000000000000000000000015de781c05cdaeb24fa6a8fe3497fcff4c4b102048c1a9e758412e69d15fa2112d52ac1f62ae155c967e52e2d7d4c1851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f34fc2e9e857f06ce231cfde4dffff2dc84dbe773dc4d7627bbdf126fd855efd60c644157fa84456be2160b08d397a300000000000000000000000000000000005aeedb4c7e91c93560dfc93aa484bc6180501c29f46a706400db27f3074d69ec239a9d0bab6da90e4233310cbe07c900000000000000000000000000000000170bc381622dbaeeef978b34f16f169575906b58827c0788d4ebf0c635db4e6c5236d3e2df9ed0870e7813863ae5cf3e000000000000000000000000000000001727237da4b3fddaebd04ba922f57675f52bc581edd75502ce970ce24449dcb38e53957094605dc62746e1ac5ae6b83c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f043a8713b5c0cf6b865feb19113927a089864d51918d10bae89f9971bf768f69185107be13e6ca25f60b7c782918c800000000000000000000000000000000187bd05d8348c82b4dce46dd4d325e8c8847d1ac954b888f5e8cda299e5c8d808f04e0dd0eb870ce1141823ea990246c000000000000000000000000000000001244ab6e621390501361028117d7144d0a2662fdcac9fb92c2189f2e1254c0acf4610810b0ab221332e5afcb750dca0f00000000000000000000000000000000105c16a2eabf83e2af2617eabe2ea68afedf9915bbd3d6694126d72df8fe07094014a1c833ee89ad01f3f77bdedf8d611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007b013c832f10d4b31b0162c607f68ec74ec96ebe7078117318438b30267ce2e592e1acb583a3be6f8a714ba0d3d747b0000000000000000000000000000000007766ed0b47b107587682572ffe3155b27681d8a273a51a6aa15dd599fba1109b3cccd8f9ef070263897be0c238f6d0a000000000000000000000000000000001243031f2537fb8ca314b1a5046cb61f2ef464d2a0aea659a1fa38f2ba2d7efbf3d9c6cec33210fd2b511d1d2625830500000000000000000000000000000000069a1819789546594db0bf1d626f8eb39da9256e648dbcd070014880bff3f8276ae15914bfee85c68761ac2ff7e0fe0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b84e51d82ec11f438f79c7df8b7661041c9209e249ad47277cd6e0aeced61026b9af179fcc9856812e1bde581a57da00000000000000000000000000000000033176e1f0a031a70ef1525e1bd05c60a3a771aa3d08cb30c44a637eec12ab429a6643fc77a5c3e67365e187a2de3dbf000000000000000000000000000000000eeb5a8714038d775912b3ac5a153c3008a86b1033bf4ef66bbdc5a2a2e408fca069fed9991d08aeadc1b18fab17fcbf0000000000000000000000000000000014421e823b5deab8fb5b3be584f8ed7f5dcd54016a1b4e321fad29e7c6c60dfcf706d3c648ca8a35dd293d1fbda17b6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000321e7a6a771006db61cf7bd270c2a7e3fe0e967fa54db316fb48290d69d1a1a6579fe257c86bfa27f99fbca3ad30ebd000000000000000000000000000000001373ba6b8d7dadf1f714a9c28f686ef2b8a6c14c03d776f10b2ede5f3b9b789f5e2fe89b660ff4d16a2a2c1e4fb55f100000000000000000000000000000000004949a7b91d9c068f874f2a447d8ae15f7460c5e10a30ea97d1f19301e6c199d83799c3cb96c574adfa3153aef92ce180000000000000000000000000000000004786d19e3602c7e0717bdd04d6a709291cad672df856c52b2602090ef47c7d02a2cb80095cbc2092e79c009d3ba81441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c86095c7a6d66ad54a240b99907aeb19946f899cf4dc3d60cd61ead53f765d728b4009545b36cc71b419762d66e49e00000000000000000000000000000000138c6b9df8753afd528af139fa1d3b419e2abd4d60e8a78695b537b0d7d9adc49d60a8774b69f98263c87422bdbfc9440000000000000000000000000000000008b499f71c538063606c0bf691615b29f9c05de70ad785db0e18e8fa955ee7d5553a3fc6f7492531bb6703f625ba7f4d00000000000000000000000000000000061c4a989bfecfdc2f83f448c2e15f69b87d9208d63c1a5948cde5bfb6e102dfaaa87f2b5448255df53c335b998de16f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017bb7cfd39e1869149d70091d4c103c7504090cbdede75e68464d065c9a535959d9f44ccc7b9185c637fe36526d911ec0000000000000000000000000000000008206f8096d24753e4ac3ddb360a4356dc0960940bd14c796804b4fea6be6c90cbdda053f2283f6de0259a4541f0972a000000000000000000000000000000000a5fa157207c1cfb658a430210d7cbe558962a6c3a9e05a60f3f20217f15a586122bc088a17246b999a3a5947dff5091000000000000000000000000000000000e87a8604f361e3bca64f51aa12636a908fa0792ab0448d6fdfe60e95f0b70bcad7522469f037cc3d53e02424f8e6b711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018aebb8de8351e521add2550f82b0c5fcf2ba3a04278af304b90d4e87627ef822e391b7d01a43be4c3fefff721e95839000000000000000000000000000000000ceca7d82f2880b9667ecb82b87cc0b0902dacc204572d43fdfe534f8fdd9c95e993fbc6f5089fcfc86721378e3934ab000000000000000000000000000000001945eb052b2b18f4b24ba8be1cb8699477a0fb954589c1d54807562ebbc406e0b69afed0da654a43996246aca5e2d03500000000000000000000000000000000068ef5a9de112f857e2405a17aa13d7410e53cc0626a0de84bc5e036b364183b7578948944fe49deb8f1a977e50e64c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016aabd078fa8b7540e63b11ae13cafdfe774e9bd0c10dcc0306af335cf5d6b66059602c0257c4a6dc2bbef489894b63000000000000000000000000000000000aeb8dee867f9ef8b90437f3674ab6d9b6342dafc6fab273567bd09d6a5193ddd7832701082b86a91e81cfc3cc7b66b00000000000000000000000000000000005ab7b43f34f42c768ec878e5ee673e91cc83fa4a475c80462aba328f108ea989e62abf879ff2141cc3b53854336d6cd00000000000000000000000000000000176a4b3ec9d206a83e7584e21224eb9aa150c1ce954e8c9e6f6b3f76b0cadc716022decfe7f3299ba073743d416783421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed417a3b8bb8fb8e45f60f4437544cbd79160ce4d347705a391c2d55bbde1d7b47e32ccf7704e6e7c1b8a10e915cd33000000000000000000000000000000000f96bb3fca666c578a2f7a5369aa18e47c75627c4ec4424449535405bf40ba7b2916ad79897b084b34dfa315c78dacf40000000000000000000000000000000002768383f66145c3ec1759a0980b6dd0ad3ff237b2f8cb4658fc864b9d35208f3a5ea5040c5e8fd40ed9809dcd9a960e00000000000000000000000000000000139e24f49dbc498318fd8a8f64f273958c2c79b8918e0206b6af76a666746e64eeb1c41a55cb8e906bcee31733225fc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018c26537ad03e1d638bd5dec664e1ebb28fd2bc88bca62b722da21e2f3faed434142ea0b01c949ae4b9b56666e015ba4000000000000000000000000000000001107723a19cb9b2e556e8c2ac1c51455c611066e50c3c42278b799e1d84f4b0623f07252ec9c46b330f92f15086c85eb00000000000000000000000000000000022183865069ff29b06be9d6ce9ee9bb73d4e7ea7a0c7192c6ab1d5d72635c84d3b9dca786e024aeadcf891d58a0365200000000000000000000000000000000138ace168e274d2c6951f818a6e56a52451186ca413def4f0961aad4630cd64a5039e410bb66207b6d20238739ae7b4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108dae8e88406a1fa26abf9cc78c8bb3e27645e4548ea7edf4e1b98aea1be4ac546c5c8e9003ebf76cc83723c3590c67000000000000000000000000000000001250067057913cf430a3318e62234b53bb02a33f1cbdee6ca35179eb564efd2d547dab883ba7e7211c2c8c5da17909c60000000000000000000000000000000018d94329a21cbbcefdf0d9665430ca682f1ffea43e5a5e96c7d80bd77218e6ffceb58d8ba6e1d151d46270c948f60e24000000000000000000000000000000000dcc981a3f77ade9711f5c0a248ef6373bd9039e26f0b1c06b1404228283c506b5ee64a4fac7b61d12b94265cb9b5ddb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002595099e4ca262d5e6fdb7becebe3170644f02a9a444e9e2c6420189f02e1e02529f6cb5792186eb8a124df5ba1775d0000000000000000000000000000000009c893800f2ecf608b0b9d993f47b2adebbe2450653964f20351b25c11a491d93c0bf6bd80f791bc65e469a8e10f3cb900000000000000000000000000000000098c347acc5fc1dacc8875a68da38f997cef2f95438c7243e53f8036153c541ad78fc24e82505038ec830a6213b50bff00000000000000000000000000000000179a8b6c115b77b6b77e7a9a140590bf8ea52d753d9f42f866d199faf11b495fef7bd384478d184fd197e7736231a2351824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001965dae74f5c6ee804d755988dc4a3b73e7c93bc552e88f6a6d5f467011583c3e7823d6a233d44a783d6622aa5a40b650000000000000000000000000000000005a7b26c59d24bb7bdc47e1d71c3cc4520af964a05dca4d4ada5b409c6e0a952fddccc8e7e386862da75824f4d4544e800000000000000000000000000000000112df4a999cbff49f50f150ad8f55357cf56cb0a51f3ecd31c4a9450a6848c5a199fb41432549a529b12a4d9984e175b0000000000000000000000000000000011ab6adaa8c4c8134f0c008f8644fc2c4b8b4fd11080166a8cb87ae259c8f20318083aef79de76e2c64b5f0493ab94391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004bb84d67d6735c35bbe5e3f2fae19cc354965b7394310a822e71012a246c2c240676e2f4278f464ca43dfeae072514e00000000000000000000000000000000048438d5f8f0caafa487a2e52a7ec4db2ba770920d9e3232e63b1d4d66e0ff938927d970e7658fdbb93eaf7dbe32935f00000000000000000000000000000000179f8b4d7bc4c19c4f278d21a3f211d07263ac924716cf4f851f2235d5a6f162594815f6d4753136343f8c6f5996c221000000000000000000000000000000000b3eca2bb18c517f168bcd9e9e577b2750a0d28a6ee7ef412bb8b1147639e4ea0bf89d9b020ba7b45c84535603b709521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e5591dd97664dc06500ad3137921e46f156ee4645caa7b8db0a8c80d7f733da5cc30570d5b3d0715410569b6feb98700000000000000000000000000000000041c61a9d5cf64c543c755c229a0e1a969ec48bb47fee8fbe605fab879866d3ea3c01302c4b0aad573c9fe3c440c52aa0000000000000000000000000000000016e8cb7b3fd46af1a2e9c2064f19d2d37d7fdc3e33ef1ea44c6cb014dafa525bad99407f35c214d61198a39f79c22a6a00000000000000000000000000000000185d87111e9d9baffd69cfacf1f63ecb775edce00c44c1664140b94fae1805f66104adfc77e1d8526cb474b6ba5b83661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084e8a74e7ff97735620353e3b4b45c6c2e80c30b94c04798ab84fc7a47dedd46d3400d53e9a3d47e0567ae840c63c800000000000000000000000000000000001da152972a8d0dde24c788bd13fae8f28f2b2d7eda7617b4512f353d5c17cad542c39b89bb8b1a4d3832f89677bc16b000000000000000000000000000000000d1892e9e5d80fea8ed48c2f4ac9d196a1f98f2d4c1ec02d05da820da917779dc8d7c8257cd326d762ee7a718d715bf30000000000000000000000000000000003dc59c0c5981788515343468a8017e01f1a742e7e83480053d8b970243858859cfd9250d9dbc1bad3ea5d56f893b6501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009982168571eaa4b2d303c69a34a7794fb757d77c5930c4ae2742cc6ff69d3820898306ab8748ee7a2fda37dad051f9700000000000000000000000000000000128ee1222077755c7e8fd2451f2cb15a6ae1c2c29cbca2784b442e00ecbdc218e106ab9f5edeafae693eb2063ad5eda3000000000000000000000000000000000b12e0d0f716c51e8ecf053a8106a1a84768c0dcec09af5eba1f95d3172826294b50f7982df46b22ce0171ebbd25b897000000000000000000000000000000000b540b1ecacd4ed1b433fea300b4b2e17a36e8c6ce0a3395dc8bf7912f56ce8faddcd27ba7d9e3c401ee441d8c6d62f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000077b8a3b43bbb3e79e621e533c93f5691371920cfc48d336fb23f18b1648a718069d61824b5df97e0cf08e14e7ea5af100000000000000000000000000000000189ee4087eb020ca6507bc39b2f41febed4696f3ede735f94256f5b78e3f1b6a0dc194bae5057ea375f3cca6fe9b103f0000000000000000000000000000000002dab31227e89c44c19acdb6d52db136e5e601a73143034b8d9250f06c087be74d4e47a6f3a83f78dc6ffb5aa2ecf1b40000000000000000000000000000000001aeecb95c081310c99a8ba044c06fe35ad7384d2dcce63ba66c2514937d3299f9ba629f723e12f5b13be292e205eb6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005323b2e94ab16fa4150925429c6798b81c0911967f77125ee7b0116eb94b21dd67cc9680a1b4f97cbc849a2d43233940000000000000000000000000000000012fdbe3244c9333142532fdc8c09011a83edd16f96913f087931e215867581c8abccced2f05d0e36d17fdb3878a4abcc0000000000000000000000000000000014daf0112a5156d1cf5a9697df709f18c48f43776263e888123b3deb218b80353d9310bb09eb843855dd2d77aad627e8000000000000000000000000000000000ed7f356223a8b7bce7f935d6a284e20a4457073d44e981492df185c3c159e2abbfe79dc2975b0f7c6a5878eaa5f72651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000985fac75ea1a20930bb698cd4ddae6c35ae385a6c8baf55ff3d5a3d16b9baa6c944bc98de5ba3d63de70c3849e13570000000000000000000000000000000008d7cfd17ace82ae9e8abfb9f7048c8e449775db821f84fc3306a96f35a4fdfd32961ab8b77c8ad371cf2552f4a3804a00000000000000000000000000000000038a81c8b851c445faf6a4af2a16cabc0a177f995d65a88fd97f4a7429266748274d430f57fa5be76162480caa40d76a000000000000000000000000000000000b61ade03e3870a0d6551def66c5d742a91cd75196f0dbca323903f15d47eccfc0135244d729b190d2e2ffb662c29ad91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a761939890ba36010fbb173ab01f4b7f3dc60c034630779061b294520517a4c3828841910fca97987b02a59a9797deb00000000000000000000000000000000194c81f568ba893882c81d5c84e15789b19291d850e684855f27a32f0c621b3a5d7bf9235e845a5164959b4fe06d0b3e000000000000000000000000000000000842987c242e4d98311f6fb0ae2ea80614013700c9d5cf0449bd5e07fc2d0b7306b516aba534883d718635267c09c2440000000000000000000000000000000012609a9ed87e6568a6ee5896dd3a01e58b173d3feef634051fd033b27aeb78949d162b10da14097ca327aee8b2d5c3a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000067fc0a69718226b192ec4c8bb4f254c579343e40e47269e6109776d0e127c3a90ec098ac9aaeb448b0174c51bb5ab96000000000000000000000000000000000fe0e2959b4d38a9e42d819b8386e77b7322b91b9e5a40310955b78385b8ba6f2a0341d84a1e5b26db60e126e4d502a400000000000000000000000000000000111507ab1b27ff88e79d0cbac5a8236a5914692165a104cdf32f93a0435559880b569761564567386fb3a4156569e2cc00000000000000000000000000000000015fef3c4e58d5d0dd073f9b2bac11de877b5cebe571874213664d85b880735e2e289915853ab4bc96516f8f0b5e68911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000041e1fcb9927b7fce1294d3071ac15abcc85e6ea26758a50610d0ffb3e114c92f31bae94c30c2b4aca787cef1221e87c000000000000000000000000000000001430c8371e5fba95ad5bb65e6d53405e5667e0e9034c0e27e34213c423eb4e87d8a97d6acf6210e3e61b8665e8fd1ba30000000000000000000000000000000003e9b1f155f9458dabae1891a9d69d0b8f342c7e3f86cbe1d43f56431b5ca210779eaef73291991fef1624f161c88b9a0000000000000000000000000000000014d2ca7bd0dd239a4930644bab12d1b350eb2bd33367d777ecb695a08ba3f6e3ddf1bd1495b5bb0a04973556c3f4dc511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017afa77238c5e0cb667e08b2a8c8a9508edfc2bacda648703fcc9efda7dad60f347f01ddbffcdd2a8c05c15b26352e74000000000000000000000000000000000dc197ccdf45b4f2503363983229918b8b69fa60778a2a7bd007a5751cb6a383d3ed36ff7b266cd66e68d248cd18263a000000000000000000000000000000000c5ae5ece084e9e7c9884fdd015047f6f7d152f687b887ee333f22a95cb9f3aa3dd23e4dc869ac8a23b5ce3851eda0af0000000000000000000000000000000007b9ed5fd063b75f9fc81d8e6b82d63fddf9c238600a95b3985c9dcd1e31d05f9b1e91f8150b14db48872571a4ef5cff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084c430f0ef1f01b7416715e51187340b4cefa4eb3adbb7a1f5e8459d2d910be20251bee0c8bfa012be3b90d7624d5b40000000000000000000000000000000016cfd5b2639f3298f40ae81f4faebd1e69c08462833e28125817b2732a871423bd4983efb71c12cfed60144311b798c40000000000000000000000000000000010746ba5447ea73a7daeaa61e60334a06e3a4a4506022a07c083fd86dc72ed15f9686a8d3369948704974598bcd89afa000000000000000000000000000000000b225fa5d85caa77fa823886fb2ffc5d7bc9600f0818666eaabec253211af94cdddde8ec8feb4e28972bfde8453f60c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000465439921f86e73931221d277f123cb43621670ded53d220776502df6cbef2002116dd46b8d7bd1cbfe76ef145e400000000000000000000000000000000004e1fc63250b42af245a6b32a21190a7fec583ac87c7375134aaf212d998c7bc4ad3cc00e2f2974a5820d2b6a3056b9700000000000000000000000000000000015466e026fec7d63696f332fc7d8a9a8b0b4919f81dc25e20c8d37cf2b9b6df7e3aeac625a3899dc1091d612e5cdef4000000000000000000000000000000000c33b599cfed8c337472164c9fbaba5c92081ce0d0662d0b4cda47880868c9f6ca610558147db95b653be75f6d8091811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f54ddac20f8ec287bcad0dd245ab866c68338a696aed87a21d7c122943c24d199fb0bc85a56e34a921f508ba847f11000000000000000000000000000000000023e090da52dabd4dd69b66e08f9ab5ea31e377e0a4ba89f36b9756548aa256cfacf52f8825c1596b31644c402cad4200000000000000000000000000000000058f91536572b5f68574b6a8ce16d177655cd92bb3ed56552f797fc4c03d45d16e25de704b7d33d3bb529dc4e8121c60000000000000000000000000000000000bc90836202a58a064e392c63de291ed768dd8ddf44867bea99f6fc00ab8d1a6fcb0cc5217aa4981ab8e0decac715ed81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f63d0a841fbf2d9121c16f09787156e1d22c77c6191ff0e60a96c81d97bb6ed84868a5854d4749053370bb0a5ba3260000000000000000000000000000000018e513210a37174836f0351243fbf23b200af071051822dbab4fd2820e14ab4c159d3526c61cbb396f302211ae5e2e7a000000000000000000000000000000000beafa2465df84f66b15f3e6102f4d0cfb88c208f1583e69e520e83efdfccb2291d62ae662fbfd495e3adca1d11f0965000000000000000000000000000000000cdae97ddad48eb80e89d801ef711514580cead72c91ff40834eea8321c76af62f88c3ac980958387b190f76a606b9801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035af7869f993e75ec07ab76da417b83938a3559a84ec5bc60413e343210b4f1e9eb6da7ae04fa787582378cdc8ae08c0000000000000000000000000000000012a313a5bdc30efa8c9d5a90cd4e91e43eb090aae4cdc594b484dfb4ddf6089dbfd708937940d2ebf583ef5265c6b5350000000000000000000000000000000014efc201d62ebd79da6d97208bf076c8380b8b849e526bfa1d8595c4330f162496124d63fe255f65b56fb285b77917bd0000000000000000000000000000000000d5760211807036dcb74aea4106581b126724692af0eb45da3d12d571a858dffbc564da62ec61dcb70e1a592e08a6f01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a1320c4336f9a93e02b73efe85477e66abec2f6151db7c0fecf734a27ce7ab0d5d12633e9ceae5d223fcddec16a4b80000000000000000000000000000000010b537e65eea8bdcf573c3cd3d89d11bab36af71f4d50b12050201b80ed55bee8ed2d9029f61b407755c20bed2f6d6c50000000000000000000000000000000017a0c6ec237814a3207e006779fcf80b0a07e7d7681b358cb9b07731b2ae4511b251585bca647b9b1896eac90e6c40440000000000000000000000000000000017f95ba366fe9282b139b30b8f1a9821cea66fc5b105c4a2e8754fbc8d42e24337e4f06c2b12d286ecd1ef2b4dfe88cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ee38452b1d060d0b5b594b5d9ddb3ab25804800c64c5ca4f6c95d7fa23b678c7443794c809196a80bbd82193e5f3d9000000000000000000000000000000000fc028a0939b82cd60f0293978bbf62baa5ce2c05ffa9e5121e44afcb5bcd380636e8a4022f29baadc6a89b6f413b508000000000000000000000000000000000f04ac782872244d617c637cf0670decb9661f5b4ef2d602cd6389b888627294118d9ecd50d54d46a804e3820ea91d500000000000000000000000000000000018c843142aebb5f3459dfe0745006edba7d8cb7a258518b1cbd25f5c33b274a94099fe4785ce43994569d230ffe8eaa41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161e2d36553b1c03dba20e683412d7d90f8964ebb1a3d4f9eb5b220c32f3e408d178dd8b4017bffdc64f0565402e7228000000000000000000000000000000000a0dcfd4482271b5c9db255f36d011e6534a571ac82ff0f01b85d1655c5851f07854fb748586f7b0bd861f9b0aad2aea000000000000000000000000000000000ebfd8cdf970e76860a2cf7432760cc8117850dc77383178993b62b48c7c04c36cb20ca97d27b1bf43aa05e574a81dc6000000000000000000000000000000000aae79cea783414facc2a4a973b429aaf4443bc5f6ac518b0591e24f939db49e210a836d057917b44bf36a67174a306b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b494ab31945a3a615315ed9e4b9b89e293a55920a66242ca71d857987a6bf85e3c968acd588977e56831f241da124a000000000000000000000000000000000913c4aaa8cf7d57c4de6a49fec1056d6127b332b8b135501899d28e289162d3cfb19eb6bfd5eb2f8c015230c75dd24a00000000000000000000000000000000022dfc79a46220fe1cd8a764d1a0334a90f1f001f408787969bb688e9518f3035db065d645017301af32536e7aa3461800000000000000000000000000000000134c184220d8e8b13400677ce0756f8ef3e00da7d3b4a72458859034b741e45884ce32f3d26288c188fcf1ed1ce01a6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2bb32c2267b9ae69df73799299683583d2d442bec64457824bd2f1efd0c15696af4f0e88e6080f0944648ba1630f410000000000000000000000000000000008aa84b6d962f58ac3312a36d79331e9eb065633a7781f339bb0f7d9fd9af83e0f4ea0a58c0a23bba5f36ce099de39d20000000000000000000000000000000011e6734b0b64a57593e345c93f1a6214d3365c420b28e91d719985b4c09b81a77fdbd7027ab03cf4a369209bebe1ce2d000000000000000000000000000000001753cc3b957c364899724d73eff403e3e4c932f39060260eea3217b8227809dd23391ac77431e35b81fe6b1c76e8d0bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130f6e728bfb833172a003389a6f4bff85f8515804c41d385b2da36979aa035364fcf3ae0ff8c8bcfe6c05592d554aea0000000000000000000000000000000001344e8c7291991a9d96759c0bfb793a1545492fe027ddb898552fc298a4d2054d2d4763192c9ed5559cd6dc20bc384d000000000000000000000000000000000b6616290db82e28c08bdb193d2d17e6dedafcd5bd5a8061fb1a7ca72f4431aae4947a5fedb1026acd350cd1a11072c70000000000000000000000000000000007515e7bd725eadc39eb08229ded6af8735e032ecd6bbe1ebe828cd7bfe242de80e9d62e3de02406bb05067e4d7ec7fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005cbda9dedc1b008da733210b9eaa0602b07f8cabf9e56943d64012ccf4bb2c93396d2d03383ee68b65bc102eaea2ebd0000000000000000000000000000000016d7ee91de2f5a3605194a1d3336b724035ab8dc91ea460dd5e560df7388a58e57e6a6a45c27665de88339a7dab6f19900000000000000000000000000000000064af55ede76999bafef4108ec96923ed74da10f3a9f50c993076ba9669756fb3aca5951641e9608f5cc42416f83efdc0000000000000000000000000000000017067ef5779adc304ff48c7365324a405bf1a48542d200b7e9b4dc4c9e9fc1a6dade7a1c4eea3c2cd0accaf24e7acd121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d446b46a1da8860e7b1b2e5a4c55e002568efe4ca3d89a6fb50611e02171bef6c73cd0ee2c0183a68bd4dcd27f62e0e00000000000000000000000000000000001ec1a911224d214e20b8887dd247c9884f5e935dfb10fce3a282f59beac5e1eed71340ea51ceedf70bedf2614e640c0000000000000000000000000000000013ab6e89eb8ed1d5ef71689d7f36a329a2330c2574142eebf1a06e3ae9fab96293901c64c6303d4ef65f01fc4da140d2000000000000000000000000000000001083204307cc9f15f6768b4b77df2f8a68995dc1ed35e5ed596aba4fc34bd5c1e1fc964987942394f64eac5c2abbeed71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004328e525ed1e89479ae6cc0364688a0e522cd017d13bfee686a3fb92d65055456cf04dd8caf56551e38f21960eb3ff0000000000000000000000000000000000db6c5fa6af10ffbf625d1f69536c7bbcfa4d1c0e8cb0feb7594560b17cb8e81f6de0e840b51f90695f3f411ed66a2f400000000000000000000000000000000124ec35c7026d428a5898aaf4944ea7c7085ac6ea4382486f1f297e20e49990e3961f1a734306f336e0598abb816d92100000000000000000000000000000000073d42fb3dd0e4997957f56f0c177f8b3ce6a7333acbc9fc4f4af76d4d99ed85f23df1bacbfe856e9d5c555d394e59891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000747dbc33ae074b9959935ac56203582fe20645b893084990efa71447e55c824bfd6beeb090066dd0df662543ab2838f000000000000000000000000000000001845fabec5e37b75d9ff1fef67f4132eb2ef8e32dd7b62c5862078ef6d6b3eb5db2f6fc1166f4a23ceba9587810738d2000000000000000000000000000000000c695dc7471908de469d84930d84443560d0defc656fd75f2a6b2c924c43714216100a965fd9edb7f03a812e97c9bdd30000000000000000000000000000000019553238f598b7189f576219db3958598ac7f793418b839d75525b4f2e46733f3710c32488f1dde45012ecb6b56cace51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e37445856444580b397fd12fb7f1651b0ebecff3ca9c46e781571e435bef3ec81cca9baac5c94ce9ac6b8b53d201d39000000000000000000000000000000000e33d411a9c7272e71ca372f6158d42d03cbea01621412c389558bfeefa3135cb9fb0afab676ff669061b7d56604863f00000000000000000000000000000000165a81c2aa2edc8b3a032fbecd022b989c45e67533be7938f65b0a09097f20dc80d8954bc97d2660c8d61c877a7d7ec5000000000000000000000000000000000527e608fbb76005616be5d3bc3f08e046f9bb7f994faebd2f9bafe9e947e0dd8aaa0bca0ca99e894f0aeb010326732c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001019c6036ee2a0fc7445f44eeffd2d5db0b005df7301518719d22ec06e35db46f329c1ee202f65daaef64d930a1c16f40000000000000000000000000000000014960d55e06f8163293b022caaca2a6e5a5b521fc65eecee47a512d8f0d5c242178f0639c2d8566e3541b887b090e0210000000000000000000000000000000009af79097fd2a17735778b799aa7c11b6a5fab703e9997e4b5fc9a1cad3c72f8ef05350ee6af74215e75324a5b7835850000000000000000000000000000000017dfd9e10c4a6e2080892140344dffb971fa0c3a2ef473343fedcf14be46bd6c203b6573b36d30906ed31eebe871ed101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000180f84dfcf52a4efeb2eb62c66bb1bfa37045db287b111c2c491d37e7fcaa4bcaab57c0f9348758d05b7b8d742a60e5e00000000000000000000000000000000105171627eb5209afc2f8548f7741c810aae06c8cc1fb9f10a7b0aa570d9f99b58dcb096b5e24a66851af74e83648cda0000000000000000000000000000000001eb49a075e95ada314d6520fc0ba7b69cf25219e4f45f9b61cc715af4b78884bac6ec0c186cc85091ff00b4d6d4844e00000000000000000000000000000000057d550fa32942ed34be3051a40bb62109c17e81728727e30589c089ba50fbaef14b303f45ae344020f7c24ffc356d441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f07436cfafc0387e4e91a9bf4ec6c2d647cc32cda50a087a147dfbcf56f9816969eb394d7fdb0651a7fab78ab9daffe00000000000000000000000000000000047281dc56046733642436fcc44a5a696f3621b00c6983da544decf80316c4334a4492381f51406c602f2adcb8932bf0000000000000000000000000000000000820f91844679e3a0610a62ede6d5575327250e2fe09cff50dcc3ec86b4db46f5d33dbfcc4af1cdb87803c236e5646590000000000000000000000000000000012b39125b4f0d7b5abd1571b1f70e2a51b9d1f26675b5e66fd5f1e815034cd46c5f07bfa131c77dce08b96868ade1e3a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018381b08dcf7497935420b01d123b56b3d6464332f5f3ae060ad469660b3bafc170e42986a5d08b20b917065baacbc7400000000000000000000000000000000198bf25afcb3cd6ec7a7c63d81ed6f659b3a31c31ea6ccc4f6abc62cd816b65a9d3804f259fefd97ffb7e57bbdd385d0000000000000000000000000000000000a09b90a42456589b0c2959267c3f0fcc27bb39ea331a0b21c33b4dc2139c89dc9bc5a67bb7be9a5f26497d7e941e1a400000000000000000000000000000000138ffd4533246fae7d5459022bddc29d445719a0a64629d6d31265889124accdd7a134b093c23cd4d1492a595c9407191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133305807ee9bf53cb90f0456fab5a6331ce50c5858b63e53e66abf70751939a2ce20dddd4eb1cd3c6521d09709af24500000000000000000000000000000000003e5abe0ce05207439166ba6cd4daae1a42b53a3ae69311e5b25e431361af3119d1a15850d41fb6244725e8f5672d7000000000000000000000000000000000147b1d6c406648bf43800f70e2625b50cda14ae55eb97c5eaabc4d8d408d7ffbbaa196e961d4a1fa3e7e0a3e402b671f000000000000000000000000000000000dff3e5a5c8a1eab0016a13f52b9914e9165a0de9252fb80eb776824e040e3a4d80b1213dc2c7a0f67baa463c52c182d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018fc66a36e3fffc39e0524c65e587510ed1142ead5658ca4d2d2fa41703d1aad0b2e088ce3ebb41873af5019d44e98760000000000000000000000000000000010ab928c40e69811f64dc00bcba54c0ecff044a39d5b8dcad8306438793edb56dbd8791942be3d35124d36022b169230000000000000000000000000000000000b1cad3934f954ba05cfda8d62e9dfd821a43c25ab2ff414b35e6a774865725f7ce62270fa80676fc1adf754ac6094d000000000000000000000000000000000195d27ee66a6f9dc11ed948f5b3460a76c2b9f6d83bbab696027f660a6846b79f3a11099704379f56a08e32f5b1c1abf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ab75b888f1ae21333fd83cfb93e171907d8b1b95d45483a551df1c92f213b1de30201e7b04ec8e35e337f35d4fd109000000000000000000000000000000001615776a85a520867052a8c1ea19d8d1536179b7849d4ecab9ec5612687425b46ae84342e0b8b07aaf85d3568b0483430000000000000000000000000000000012d06192ea2a19bb822a2565fbf9f3e76c09c3fa48022724cf44bcfd757775d6c14fd030298719aa3f51d44ac26f3ef0000000000000000000000000000000000047d169f7de3196f91182fb3c78bfb50ffb0c528e3d6b76c97d6429fdf6948f5cfdb3700e34e013745d722e4955c33b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149d4deecb9afdb80204e897446d7d060b7c2d32d1209974f1d0d9683d21bd3060d3bc596286fccd52bee350aea761a20000000000000000000000000000000014b4d08962d26b0ee461903793b60b780cfa7516a322b15ad6694f05f6b6ea4879ec0c406b2d72db315d041ac3131ce00000000000000000000000000000000019cbe0432490e9ebb9072fc995e5666935acaa49adb0bc9129a1fa1799c75dc3689be1bb8a432928383b644adace0bdd0000000000000000000000000000000014a80cd9727a3727e3816b77beeb0c2ffebf164cabf94518cd61a393dfe17df25a539ac59b328fba8b5e2a8c34fbb50e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000553a50fb49c1dd6471d61f6714f12304098a893f56bf84cb1c752470b64350d3250bb652190758255eb5124700c0e9e00000000000000000000000000000000012f049c16b72edc3f9280997e0c4701d877297443af2109931d4e699c3eeb0d842640a96b97de9dec9130f7d14e21fa0000000000000000000000000000000009f68ecf06f2d2921816375c5bd4a53d51e7ed05a1edb368bc26a528cb11c3d1cd57870b96fa6d898ce9cb0d07aec0a900000000000000000000000000000000181850492d5e6649331af0210c98b7f4b79871fd4fcd30a0575ab0214a265720f3fc745ef1826b8c0132124ff09fa5051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000011c4673f5daaf8d246a8536a11e2a0cdcb5164a1e159f5a84c66ac812af2ba01068f9aa0fc9dc25d717608db73728ad000000000000000000000000000000000a4e182f39301aac81b759d0a02cd916a1773f3a84e0e6cf334e5723305642510b9eadc550bc7bc18992d8974791e3570000000000000000000000000000000006831a8f215b2c672807a6e4e83df2dceff10ef7c9b9c588567d7084c9b59113dbaab212004f18978bf386a12757fbcc0000000000000000000000000000000005dd8291e9d7282f3ecaacd9d3496a42e0ed2c248cb737ca0d71738b5f6da02237472689e4c3e015e58c4e25559986571824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189cff90fe76fd51f189b00ba1ccc17246e46b2d8ea3a19a92512db3e9f1a99fe118526488a3de0be0fa6866558622590000000000000000000000000000000013d699c4590c6f3b3fcc78c3de7b194195251c0f556ac641f7f87c6cadd75fdc9a0ab340b340706d17d53253cef19ad000000000000000000000000000000000179ef69c8072cf5d91192c38fe5737d3b7435089447ffcca5d3fce53ff4b013d7876498f47a9f718bc9119b5feb2eb1c00000000000000000000000000000000020057b3ce97c01dd22fa9b9a41d40fb5341c25ad24b5511e6f1cb76f7439e485dc4957bc302f641191bacf81929f9731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df71bb08fb418533d6c515712ab5c2d287e4e3635f7ece08addc8d49a938f475b62ae0b5a598a1dd0fc24b1e52ceaf1000000000000000000000000000000000c075a8624972a038b9e2254cb687a463ea70b82a5982a951457fc1223b4c546999b2645530a7947b9fd79f9119d7c85000000000000000000000000000000001410084d1ac9f4c21013af8f58b21f12a8ec3736d8120771ec88a14e00a468f4ee3183039f99dad7bfbbea3302b4144e0000000000000000000000000000000006ad635e406c52381d509d01235b1fc3c766fee1468faeadb861b8e90185e64b3d1415f965bab67daf683442ee1e3c6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053654574e8f67559d97272a6a63e0e19bbd265500661c974f087e3c669be142fcbb0c7cbe8a1a3a40b6dcc291622cd6000000000000000000000000000000000cc07861c5d539bbf67373ff4a2c28d78ac69ef226789e34ae567d4e717bb6f6a3605fec897561a0680f421d516584da0000000000000000000000000000000014bd17548e310539800ec617a0cab956fc4697c1b667d596a386abc8d8cd89da79bcf563319634324574db6b2a138150000000000000000000000000000000001707b7d55315deed5050e166a9b236d12a9e8b70beea93eedacd6994646bc99cd787e99387848c2a68166bac34fc585e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000134212f232247bb0146903fa71298799206e1dadc81c8a5f310db5af337c705f9e9558c2f2e209a945ee1e1ecb6969dd0000000000000000000000000000000018ea6ac16702d131745da69b4d528c257a7ef0defae1940b224e22ac565a14bb539249192c8aefe1f763168d64125a610000000000000000000000000000000014dab5d9e7201254b90e20b27f224fa29e3593c3dbabc6fc77bc56a5b897359ed24dc887c574aa78a9d80be912f7afcb000000000000000000000000000000001508d2694d9dde8f8eba5913cce7971fd2ff9bc262be0b52916fd9863ef8ca2e92117edefd9e9638f6aeaeea8f1267ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000063ed171793bd5ea72f4bb54a7edbdee5fdf1994e55ed4fba62098d8145f95ac6aa14e2b10e7b2c9a6c716c4eb3171360000000000000000000000000000000002a301c64fff7deb7cec1ac0e62fd85f88836f6fc982f59d7fab10681592c6f083d32fcad434e7d8f55e7928c27c70b000000000000000000000000000000000028325b5057a14876f6a343076681dea465c5eeeabe48496462dd9366d5a3fce059ab8d1cb72389d1f8c2e61b426147a000000000000000000000000000000000c8294dcad1cd634bdd3a61999d0fe014ee2a3bd803c9c0fbbcb8e3c0f9a41446ab3ce51fa26bb243ece93e21441cf271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018073daaadccb7fdffcbd0b46d1e9ba0c9b6fe2ec2e2d5fc862fc3870b9f0e7d18b26943c526887ee01b6c25448c22e7000000000000000000000000000000000725c813a8a04e5f5e49cc773500370e994e0000ab38307e2de0e7c66dbc45154236bd100df2a589dbfab6bf7a970f4c0000000000000000000000000000000003b5a421fd3727ac7680427a3e95c1a2ef43d6383677e9c3df7c54dad239af2812d6873768bb4a0800ff01182d18472b0000000000000000000000000000000001d7474a2c9b17fc62fe996ca755fb34c91aa29ac56337d5cbebd2390246b6a6e400d5b6d2710ffd7012a2f86c6a403c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6c095c2d195ccf82c2b7eb53ba940b535289df2315f95074397cb758517c3fddfb3c1f03bf73ef02974ed0af5c49500000000000000000000000000000000006f1a22ee51f26a3c9351678c5818a7168bfa518858c7c7a54df8267fb99ce3216b9f502f88cde8d3dd51e5dc75ba4d400000000000000000000000000000000008dfbf3cfab95dc2b8cc9173758d48171b77226d2613f1aa880e92317d20b5a455e668f5e7fa362ebc90fe73a569c020000000000000000000000000000000009d7e5bbac22580de9b76c56128baa3ea7469b861dd441938df0e90ca7f9697a83a78d82b1bda523feecbccc82623b4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008dc883445fef661285378b6e053f72d1b35d6370a0b720c4a65c3d0a017cacfba8e43856b46ea4fb1a423fe1f8a855d00000000000000000000000000000000102e181f8ca99cd94ca424e8471b51a856f58e2b9b0efce070ab53e48836cba89cff48b174d4c53dafdc0a34226483bd0000000000000000000000000000000005f36f1884589f4943d653266157460ddb048ca3eca86f87a4504cb03494ec842d4a6c7af42512cdbd3cf8e680661da0000000000000000000000000000000000a30548236a367de4f5293ab75aeb15373fdea9013d151c253f4555f751e2ad157ea295024f73a77bb0dfaea3ed386a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f28a3d7bf39c023e9dc1525c40c638d78d67a6aebd12edff007f6b9b45218d9968d3a98990ad6b14b8664e6a23f8f2c0000000000000000000000000000000017b70c626bc47e587b92c66fea71159bbccf3d3c3ebeb34879984aa81dac1fe88ff0dffbe60201028fd8c08740e276840000000000000000000000000000000013640dbef1de512d49b7e7a9190babef1238cf7fe7d69ded9387bd618b4fead5441323454c5379d624a53d1f00c81c500000000000000000000000000000000015094ee89fcf148fd0066539de3b6570fd5b8e4d47da981b275781367a5bf47bc59bf0a24f47e8c40b4847ee28376f201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a1bd75c543ad7af0c979d3b9fabbf20c8362e7a3b7ac2e23cb27c73c5afdb8b67f0ecca73e2e9cf12670e9ae25013700000000000000000000000000000000081567a99428365cb7fed72e455aa79fbd789066ef7a8d501caf02e6978f5e3010dd904a3660ae5a195ebfa2d47444310000000000000000000000000000000005a51918389a1c09e14fe965fcf079825c5704060d100e1574c797d9af0e177c78ba4644aee8484dfdbe98b826e7177000000000000000000000000000000000143d0cb5e6a7527e62a612d35348333b4fcb8280272c1639fecec02a44ca4864e7b017e46438b0430fb3cff4598fecd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011fb3399d231aecfe1ca99625dfa94e4fab53de98304286abec4f14677351890978489e3093ccc48223b2bdb2156d08b0000000000000000000000000000000009ff9b663e90ab72f7a37c47d4d4397c5fcb610daa04bdeb2c8c9a6a66f08ebc13b76252d7db7663be78123e3d4c4ada0000000000000000000000000000000014fa39d8892b67375717446244c3e18877aa4bc6bec1d235959acde5ecab625db53085a75df043f7092d91f586f26666000000000000000000000000000000001468e90a48d3a9b78e8b35abb9096fd11ec88f8a7e3b3da091e122472739915c6aae0677ce185d466b27eaa5235c720d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d9f1aaecec18cbaef602501e20b313ad72679d940edb729b1095a6657d467c80a91eb85877cebc62c0b74322a2202a0000000000000000000000000000000009afcd48687ca83a80da905908744443cd05b3d9b12d7bb311780bd5c6292cdb55a9bf2e00bb8cdcfe861d8d841ed0f4000000000000000000000000000000000c9fa5da50ad903a7f66d9d8aeb332dd26e9e0090199252f53ab231327029e55754b446e93b8dc58d7509a5175a98aeb0000000000000000000000000000000013c30c1cd7d26d9240477f01ca7cfae0d06f1ad4a6c6151b75b4e96b3517fd5c6e4af8480c4e7164b70a2e8b7668e65a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167d0387d68c150151824974945fb46ff605ff5b66d690d519f3143af1116b5e71a6b173881a455357cb0859f14ef39f0000000000000000000000000000000000f193c9f3f1edcc2b9d7619f3eb72754d7458979d804e20574f7e0dffc34378e216bbafbc13e279c312b5be09e930390000000000000000000000000000000009805552fe2979b1ed49eebc77407114bc5aee0cb9091cb3fbebbf0ab909f79b68da3e12b4f5e486257ee7e261df00e30000000000000000000000000000000018aecc8e940beeec9a8955fbcd79fc7c333258f9b6bd70ab488d20411b296c61bdb3715f6f693bfdb058e33686ec25b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025c25b732b0bd6fc5d20fe3533b756e8a4302e05fe65470050559e741a942e32da8133af8e2d823044419e0b38779a10000000000000000000000000000000000d18c9704c8e26e6ee80cbe3f3aa2ebc282e21496f6d74f5b5a8de7bc53e08f1c9331f20cb3ed1b64fb55a6294fd8340000000000000000000000000000000002e3345d57d4335b81d44b88b437c350b12a20e3867e85a8547fca4d618b8cc35122d7e54b7e136503615cfb4d9ccec00000000000000000000000000000000001eb2b67575f30cdd60f052128e0fe44b17a9fa2579d9782bc541ccc552354ebc0f524db84276f59a109fb4b6335692d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d1eeac3986fddeaa9df8424bc7bd44c7c29acb3de60f467e6c812e9b7f14f99b707a4a198d3fc70ce3a39c5ef7509d000000000000000000000000000000000d428063f48d0e330c6477a5c327c1766a2d52ba4ba476f7b83443003495c3198e0487f335d6b79dc9636f576e89805d0000000000000000000000000000000001ff67e92da087fc1fbc722642227e2c1aed8aca10c9d8334971382aec431e85522cc76aace7989027041f38cd31e4ed000000000000000000000000000000000f3d1fdfe3a81da72b59924fd2c71d4007639cada1afd95fdd75e141e86e6bd1a334717538a57f237e744f853c175b281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa1513ef7c596d45ecead6af24b8fd3308ad308019de79aa5ae00e70bd0aabc4b8137110d31b8a6c18af843f7062ccf00000000000000000000000000000000168250e755b721750da8dc38e6b20e0f6092eee6d428e49052451973462057e1f31b6a5e4a7e0b3347132369a33f5d8900000000000000000000000000000000185701edcd71430466e0c4a7fd06dbd5abde9cc1678467bd8cf0f7ff5cb83f6afcbfbce74241db2c206222275534b1de000000000000000000000000000000000d5aeb387ac2f52a31f412b28d0e65994bfd71104a41e052061cf4073f890d2e81b11f20f9783d8c879ea0494ce9febc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042dd8764f7f1ddb50f7c8fedb839f416e91c1b4f59666bdeef2bd9cd0c9f6d602e98e368cb0e4d8a1217715eae946c30000000000000000000000000000000016e6ec2c26e447e8a5f9520daae8a74c10ca154902a7e3edcf01efc40927f897f84f28f37ec1ae646236f4ec60e377fa00000000000000000000000000000000027d8c0f382f8b4d99b659ab6aaae365f0a733a44a2f3676adf5bf28a546757b8b09e7724de5d7ec865307657101b1b100000000000000000000000000000000112dea8cf3872944a1fcb334bcc6f331b0c6de8db72e473ea9c9d914febbab6358fb3d7e3830827ef705a515c7f03be31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012ce5f7f54026ba1d41d155c9271a0953b25bbd3c6496ed744f6589bd120195c9e9de66973af3f92295c8d99b828072000000000000000000000000000000000d237e432fcf3fff29f6c52ee6096f57345934156013bae091b5674e99b79b5ea37bbcd6c1fa92830a99d39c2d3de188000000000000000000000000000000000099cddb0866b818a3a47391a97eed41e82f119778339e40a336acae9a96ee30cf4dd2848e61f2a72a3535b2118efe67000000000000000000000000000000000d6a97fd54a765f7d7ee5a0e5becf6dfd593ee1cfcb4dc35c6bd2d5a7567e738982fac529549659c820225623e7986241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018207ef47f49a884cd279b216dc439d39eefe4f0c202a25dc246e75ab46b8801eb1ef55d9de6b0dc956d2bf29ff8a89d0000000000000000000000000000000000682fb0db1af5cf1ae28f99e9f704916fa1a89eb9449c9e68b45c9319c55feb699baedb65d44aab493dae61323ace1e000000000000000000000000000000000ad490c4e21f552967797a79a77fec33772045c0bcc0dae7295d07bdd1a502ec7f1ec093f3b839ee083bce6d9be58abc0000000000000000000000000000000011fbf2bcdac191374cd2eb64866cb2864c36a48dd7d81dc30815e6d994f54237bcfe3d253d6badd73125352237089b2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a89b43d6be6666ee0eb1bcc876429946c7f7a37025286475b7ebca27babd263c5c804314b436da846d27a3fab08c99f000000000000000000000000000000001613920fe70fb0a606bdb6f09eb80dea27ea78787b330100ac29ab93e5f830ed35e8e8b49e8438690cf6f8771e62f9af0000000000000000000000000000000010ac3245ec3b9f7e8efa9931bd727829447a5c9d86fc24adc8d159accfcf8344a0f3f026ef35af0bc45637278f9578ce0000000000000000000000000000000003b2ac3248566508a643b0ec64fa5d886dcde11ecf1e1b0f3a55f05bb84e042137aedf168675fc25fa0143a9d4a92fb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e84ef00a1b34974ae511b95bcf17845361312b2cd7e9c02323038a6f347d644d3753075af11312e77e8816540281700000000000000000000000000000000008f9ad141fca814ec974d4abd09f01846f1f4c99196934857f8eb49b9a8e0fcd281a9ecc6846cb2dbfd34bfb28cfa08b000000000000000000000000000000000cbb0894ae780c336aa88f479d73764fdcc4b73625e862b610439d627eff601a4ed8b5a8b53f4e2d786a9ca3f74da03d000000000000000000000000000000000b2285fae63c4a7860bd021bc5d6b32336b3629b5f635307c203ccac1f954615e6252c8c5dfdbb5846f6a5fe55d615be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019291c6f7a563074d7bebd65fb39d264de46e5c10cbeacbf409acb534aa2160e1a77f36c3c934fcab6e3e4b179b2b8450000000000000000000000000000000014b374ca1c40554dc70f78f36f838db9c6edb403c2500d8eee09eeb8f685ab565654fd1edce2020d533fbe8062cecdec0000000000000000000000000000000006a6bd2f06d3c54a33e08c659ee028419897243d826a90be227c53c00173de0459aafabde8dced73864cf104d4f668fb00000000000000000000000000000000119bdee636612c560c20208f5023fb6fac042f927ec3bf170d60582f05b27439b222872de2281f9a26e00c37248c3dec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000059944bf832302da5759bd3fbf7190031352df44963275e5b749b8e2a19b1a9cf56ce676a7c8495b1e8fc10daf731e700000000000000000000000000000000145ab4babd61ecd83ad9dd035b3195371dd6a09f7988886a6988d39b93ac74690f8d293c58cadfdf2e52f1a89f1e13e80000000000000000000000000000000000e9d3b2aed2112f91db906d6c33de7df37f4fba17ff2ffd0b7cdf24ccacc3e1b631085e64b6792ea4caeae44aeb8a49000000000000000000000000000000000bd91ea606403ce81e177db5ab9eb3304bd248697f71f6c545a15fef90a9612e447104f4a2becb76213b3f9a3a1537391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000035200183eced81565c8223f52f7eb624ec3f9ec42fac8c084fa52082b439c32d725523f21095c85448fa4075e6264d1000000000000000000000000000000000f9f49db2cdddc9066d1efffb6c3b854668f73699846a99f200e8cb3d36424e706bf7da998d53b3ea25fd6bdb493ff280000000000000000000000000000000019303ea1c21a3d79a1c41d1bb192017d0d9186428095bd996e56bceff7385580095cf4d93be3fe11aa9d1695fe2d8e410000000000000000000000000000000011c972fd52755534001377c98055c13b59d7eca825cfe928829eb54cb27089ee5bc43d98e126e4dcd9901c9eb9a846811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cc09652fff38fe1b94ce9c22989e66aa990d58e54b74adb3b43258a3dd768eae9b0208967746e7b1fc81274d652ca700000000000000000000000000000000112d62b3918e000b487f1e419969dc8f6ff82c126a1e5fe85a9647c3ea2f7c7236ddfe084e4ed61ad417fb1931547b2c0000000000000000000000000000000014cb264217c66e9a53f4ff1d151956a4a98111bbb42bd1d07a528fc26bb8181ebfc51f67bc3a42739834a5319800873300000000000000000000000000000000157e69d3c1c7cd190354cd51ba11e4699f0db61185bc2aff603198c23ac82e6e9f5e5a9a337efa7d66d23df462c95d4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017259b78fa05fd691262b7eba64f90bc01d52189cf368948bdaed8419c679b31148ca3897ac92da3868bb46cbf364f33000000000000000000000000000000000c52df82928f0c1d1b6af11ced001758939b182e612a4efb8fd4748f4353ca2c8fdb818d4f6801f1e1b0372fd463efe00000000000000000000000000000000000acce64cd8bf0ce97d71a80c335cf6f1634d50c44a8489d282397021fe06a8ca8889fe775d909ee4d5062dd5f8e618b00000000000000000000000000000000059ae0973d9afbe900804dca9014c116e378be8d404bb956739af4fc542d55188e00abec42dedd8ca5fe0ad13bc71b461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c27e23a3745c3494256e04b1804fbc26ece509b8f615e8969d28d01225abcb480aea62bf24ffd2897562ffa158464b7000000000000000000000000000000001725c7e705b5fb1ef59a4236c6ce138914e1bd7e9db9448fc89f5a00dfd24c073922d3b1305da378b87213044f472f6b0000000000000000000000000000000007c7b4b5f5267ad22776151ad738d68707c79e43a8344d891599833d09a4f5b202910e49dbb4edca7cc3da966839ff46000000000000000000000000000000000977b438b93819b4390a8a3cc6c7ef0f4dfb2db1927c9045645683e3559241f3bb6ff4ff59f99652c07ed05318c4db1e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163372d3c45f9e2eac9b265bf182d25cca7c46c236e9d91a4cc2db4d735b6cea5840a5623411e6dd7f09f5970a1dd6a40000000000000000000000000000000018433796811c2b9fab0c50c14538560a1828427d60fe422c37f3870a132e5e6a219b91fc769235d3576d246e7eb3817900000000000000000000000000000000077251b75cc7aba05269ec992c40f40b5bccc3cf04670e31b0c11441c6fe5e9f4953f3918b81a2a0efb3611a6e179d5a0000000000000000000000000000000008716216346f3159e5c85cf8078d9f3d29ef8e0990ee3fbb99b17f12a8d76a3ba0526d6eb1f247ab3fc7297e174a53931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007609f1a9a21bb51db41e339de97520003bafa842ec8720daeca8e87fd13deb62cbfc342113a773f7d236c747de99e9d000000000000000000000000000000000a394999aa00a495123b848bc041f1d8141d104b10ff3ce17428c8527d9425fe7f6b956e322db703ab81fd644195fae100000000000000000000000000000000101e1d860ad8429fb74d2e6096359be629016f35b6cfb06b82863648c74ee3b2de1044a41429730c6b6b5607a065c67f000000000000000000000000000000001670e95e6eaddcee88aa9f7ba4135f82ed1712732b0fcb926b940f78998933549d1fad909847d46724eabb8b606e4e5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d51b4fe70fae821aa68dfe507e23afdb2f6c5dfec5bf9dc93f1837f8861fa6b680ddf3a60cade2bfafd6c0513be156f0000000000000000000000000000000001963af7a863bfd4bc34b7ae8e8a401c23f8626b4ef4e73f645b161b0683cd8f8474d718595b2d98da50554ab67fa7680000000000000000000000000000000000e20c4620ba58590dcc0578b6e2e02b5310ba488303ee3fcdcb9d840cd9a7a09c366494ae9e1cb7febffa56cf18e78c000000000000000000000000000000000462f86a7341e0621ed993e7b14badf8aefd132915dbe99890be7d6f3f204135ee16c6ca90e629156770434e77ad1c8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011cde12d75a6e6e62d8a08af6b2fccf448c19a525f5fc7848023affb0c9ed310303c24bf3cbe5c9de81a3134cd1ef031000000000000000000000000000000001386173a8e30a6e7b88474ae9064d9bdbb2c182940449d843858a80202ec9fd7fe558e463f789f226bb211490d181e030000000000000000000000000000000002fb942fcbac015449c0448ff02d562802bfcaf9681661caa78b662e34d44bcf5ab828a5c8b69f7c71ee4e3a073b58e700000000000000000000000000000000166935836a70d0397e751bec1190cfcdf2e80334f04a8db22879f4ac236ecdfcf26b5bd633905227be2f1da4a37b046a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005780ac6e2ce2fe88f13e9cd39e5a2206d450289f216460bf1e49c26ef55c5b85829924babc285e1ddca62935e569f340000000000000000000000000000000017d4335cdc8bf515147f9b856fa8e911c77807e1e94fbb41f7c8ad576eea5201a15e916d357535ce830b4e3b301bab0b000000000000000000000000000000000ec579b70f8c4309b65dedf0826deb04736e8195fa83a6a9623556881372815d0845cd0e6bc7b80915e6f7c76e790fee000000000000000000000000000000000e88e2887831e6cdd4181795a6259bcc91eb61a8cb81651c73c4c6a07eeb9233b960208cb482f9cd8e6803be6646f8a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009007c0b8c2429bb53212c6b84481831b2756ba4ffd6cde21aaf100bf0d682798671120d873d40407e8464d91aeafcb5000000000000000000000000000000000c8e1d8f27d15d989bb3bc8274bcf06747e17971ce8865af10bb5a0cfd2ecfc999133ef012469761369d9029dee795170000000000000000000000000000000002db7c39c99707064e2746248ba53ff6056a3372fe573e3da65298317297382af0bdf78e53f762082ade305e32846362000000000000000000000000000000000e0e7e19f352f348d83ac7cfa8e7ae514533f972850eeafe97ee7efa01f7d9d032289c4dc678ff1dcb9bab4e3ef775b51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013def788f3c083c0143204af94457ca879a68ec67203bbe5c5e0d170fb506d061f9a412895fe6e191aee3f59b768e540000000000000000000000000000000001565e3884f0a538de3eff89df68db64555ea011361689b1219723e79a236596051fd788fed752226ed9d4dcff801ef84000000000000000000000000000000001040c8e0c3fa7d654b947b0279a2cf3a4cbb7c2317889496133585c0b7d7f0f15a3da197409925044d38e05de98bc9310000000000000000000000000000000013300a437ebc507312c0378363e79e2cf7c9c2dfa7ff3e4d1806adf31fc19c8525e5714808b525e2dcaca717a2f177f51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000244c1febe43602487304751606d4e264e922e367d8387dbfb115304e067b1f5f66765c58eed6d9147e3169e6a647f2000000000000000000000000000000000074ea31af02a6aac1eb2b9d43fa35e92caac00d5ee2856ceabf24ecb69ba50bf8582b1b5e9a36a2ff0ad2e20010710c0000000000000000000000000000000003d12fc5cc498aece813ad8b7c9bdbac6683244f765186f39621bf96248d3e0ba8cb7c0164931653df1c101290a6652a000000000000000000000000000000000ebbe0b846c834608cf5c7b6b2da1616257d8cc551386766e43eaabf56b041419d595136e595e589d00ced3c073c2a5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027dfbbe2799b4d17a84b633df3056fbeee5d5254a1cf2740b6b246bbe3c7f7bd41b0ce7c5d4eead51b6f90a34ea628c000000000000000000000000000000000b8cfd51c527b7c68af7f8c2a013bf33ddf39eddd955c97c880539f16ea92e3194aee1fb2ea9da3522a257cb7aaa7a44000000000000000000000000000000000658bf2cd917aa308b881e39110a72a06eff60617eb91f7d864525762eeafde8653ad42ea2e6297820a3d974b20fd3a8000000000000000000000000000000000db6cfdc714a9d5f2d5fdc7715800273079dbe75715f939416472e1154e80c43d6e2bfbde2399453fbd682cd5f1a220a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ffd2ebf6aac8247c18f1a9d111ef187156138dcac9bf7fe01110c19885f0af511ecd5ea261bd4af36c3417b0e0c846b000000000000000000000000000000000ec0f821c0c1a297f5ac974fc0cfedcce1dc154fc0d93be10e6bb3e75a8e638545161fc94d5de27cf063c6bad92f3a30000000000000000000000000000000000dc0c8b13f55e2192fb537d5f6c5da80cc0b935c54c03b02cf2fc493695dd6d87363c07fbcad0cded3b9a4e6b4e296bb000000000000000000000000000000000816213c92aa0e50df698eb435b2ec9d4adad4a4234a5ceca8c2acde7f5513abeea1c4ba2d3acd52d81a5a71b00d8d631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001b156b96551f7c49c46f16eb065a1cc07ffdf82d41b0b0ab00b7fdf60748498c0bbf2e8d2558fe3e5414205f7929cd8000000000000000000000000000000000cede2a6e9e959fc87a98155c3065a3174a0f2af45f89f02c58eac5e5806e9a7c82586dae683a7bac52055b63c195bca00000000000000000000000000000000196ec658419b89a73d47eafc8efc018d91e8250b0b3b51eef9ddfe046fb244e6ed509af8afe7e4ec1f04ef0c30d6177d000000000000000000000000000000000126f9f054ab8f5728e4e055cb9bf5a1df678281e74ac9ebd83b9854f170759fb052c81b41f3cd1525b4a221661879b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001514cbe8e0c8959f8076f84aa05f49b80e1050583d946bbfb5c7cdb78c971fe1ef1ab1406ae8b7f8eb892d1e2df7f9f400000000000000000000000000000000098a22a53a99dc2d6c2582327f22cbed632cab7f6a8202d8f4fac48d6df66e70017cd0bb4aa83d817c05000dd6abdf5000000000000000000000000000000000180eedf78a27b9feb2c3aadec66b5287677829989d93af9e25f003b3c11d9002ad76bf8787d5bb37d629496f2040638b0000000000000000000000000000000010c8e1f57eb51ad18a42ca8f02e7ed1250e1515a122571caa5893dbc660bae2d2ce91f4c33e38061493aa6ef2eda94801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd89253b00beada2601f18e95dcf3554e9bd251fc2ff3effa4eb7e05ac50cb0c533f974c61cd4552d9213e6c04c5abb000000000000000000000000000000000a5094c7e506041a1980fdc800058fde643e07009e4a54f2040478158b0e18b3934d9b2c0dc38ca226395173df33f7b600000000000000000000000000000000179edd70799aa786533adf0d788181001f10f3ebbc08f72edb965b77b3adb1c6825cd8413d495efcc2beef03fbddd2c20000000000000000000000000000000011aee05037475887dfb29015355d3adb7487ea9244a920d8851a83654102c2df41264296dfc326ebe927a37ea2f4f44d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042bfbdbb5819cfeba687c3ecd5a729ca9eb471bf4f0ec949e1aa79d179056b53a3836d8245a2dc5455518fbe49b9301000000000000000000000000000000001131e13447835cd01c0f9fbe03653afe64d0177e3fe010dcb071f4c078e86e997fb761ac3c28fe9c0c51f90e62a1018700000000000000000000000000000000043625fadd868b79d5dbc93c29b66bed78d4fa2ee8590d3cab9c039935fcdaa6d1dc24bd5850bf3d0bf2b9d276ded3580000000000000000000000000000000007a0d010e5cb25e9baa577f2ce4cf588a7a5f794c490e389dc7691ad3ef9d36923a6a5e05faf9f8203d393d6f17570041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011313eb2c0368f64834c62ea4a21699025f0b75256a2197aab03846daaf627f0da0816bfe63e84233ffa0eb5717b2680000000000000000000000000000000001743845da7cf3043ef54d90f2f4e178eedac6c8f2ecaf717e6524cd93e29d0317252a2ff6c284afe0ac823fd96837b73000000000000000000000000000000000fb7ee15f22ee8de7fdc4359250c883bb9baec75f2b0ab56ea7ee67e46ab092cd285846c31be8171ee5f240abdf0fc0d0000000000000000000000000000000007ed200d16f2d0446e23bf4908c099c043e19e0a1a036608d0ec8bff652e33e7e15b208bcf7729a55360d324611a0bd21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001677bc58593f530326550b484ae187024e2a087fc3be7c13a99cf6780c227435f5341db8f001f6df9386ed5c37a9153c0000000000000000000000000000000010f9af2a65b0b34902f6eb5c020f4029d24cc46961935e4fc83efce8789b59e90025bfd612e5a8930793f5d28fbf257d000000000000000000000000000000000abebcd8b26f10915f074bd253e052bdc3fb0865ee88745d32328292bbac013602ecb388f059c880d5a4789abc573496000000000000000000000000000000001102d15cb931a34e8eb016db0e46450133429502e343ae10de97b8a407c99d4d7beff207be58e928e6e742ca911adbaf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ecf9a2d036c7f5c5f789bc99a13da40b6f2477afd666f2c9d1b27399f9983a4643f9330bb6e2e5b42813cfd82262a8b000000000000000000000000000000000e075550adb19de7f9edf0c80ce20598ec815b6f622516ab171aa69c697da5d8dea8137dd8d6af6e4f4448014f13ec5e000000000000000000000000000000001872ba58fe674545df41d435d3957b875e612b3b92410b3f30a3ad59de6b2d39ac1f99662c67c37484aa1bbf7e280984000000000000000000000000000000000172d9bd3c908d742d1afc5952fafcb020cdcbf41e2efd725a26a3eb1a40797a487a609a4cbaf6bb02939e4af2553e121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7e4ed9ce55921795e50504edf868c8afd9524cf13fa028e58f02565dd441b75c178321a7c1942fbe70ff3312d6543e000000000000000000000000000000000f1bba6ead692f7986db46196166ba9b9a616894be468cba3982b943ecfc72e4be3e53e3cefe40147c4276814e600ab80000000000000000000000000000000000398fdbe1b93cb02617029fd500c6ff3ba63b883dcdbaba4f0b143fb2cb035874dcd3a6f271b9e06df0d3c12e71123f00000000000000000000000000000000115d8367c5bc1a84af7f4a83d6241823b805d5d35740afab16d232130d7fe0a5dc49a92fe9fa360afca2f09d6eefbf381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006156bf218e8c2c50b927f9596dc17aa82bbf2b5ff85790a1e2fcbb422b61b08f3a976df160ff74623c30c6b88c65800000000000000000000000000000000001701fb001dd1f3335eba33ad5bb740b7ad917f0eabe8ce5d297491ed44391576dad6fac7bb18acd32692c8b92f8b99400000000000000000000000000000000116f035c44caca417117d00c77a558584a9464d1c426bf8d1118f8a3bb4c1b71db36547bfec7dfab188d479b8fc9f3e7000000000000000000000000000000000322591bb68f2409c483d34a1e55581c141f9d6c2032b2c1c72057a9d7ce36974141514029f99b245d32506653ed7e7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101b19b296daa4d12c0581ebeaa04b6dfe5fa3112e8709a7e2fe97242759efaf20e2e13556dc1af09c033f30b1c51253000000000000000000000000000000000794f9adb5ee6355123673c9226b12628517623db368773c1066e28876ffa1c15cdf643569e9e1d29c8c5aeb2f7e307200000000000000000000000000000000093a88cf490c92177c02478e05e340b888a1a257a76c95cb5b998e09c152f28af679405512887c0f7d1bf80297d0cd30000000000000000000000000000000000786a9148c62aaa8bccbb48f31332865dd03f2bb58ca61f116425f5ad935e45ed4074add241b62b659452838c231108b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee1b05dbeec7d3f5c8646f4fee56c58155a4faed7fa29bd0b36316912a1f70b4d6b15c3eeff607a8bdc9caffd800e9c00000000000000000000000000000000028a644639a1f95f696109bd9fd771b7a87b2057ddc5068150cb3048dd57b5ca4199924bbb779a5496a953b3617f5af1000000000000000000000000000000000b71ef7777733fc3f3dfedfee92eb1b883760a00cb22d47e2bcca623efbc229b5cbc443aed34684dc3530841548c3c05000000000000000000000000000000000d4d5f057680ff3c45ade2ac0729e85b433127899df7eebf4660e2864e30cb30ac6d0a9bf2eceec6f68a7a0128ac86d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000016f8ac5504f9b44ca40c1c6af1b4cf9beab80d4e356e20234740ced20614490834d50b264e56594ede33e3b652ef9e50000000000000000000000000000000016c4a07044a62d85c37000c9f696e5bd7fe4376ad22216005fe7d9a8d8c9acdb40d13e36959e03a810f5f9e9cc386e400000000000000000000000000000000009fd2f411d1de7aaf889f01f4ee7d96c2b85d312d025d4c11ccea64ad951adb3e74f235e5d28c5e0b22a4c82ace74a9c0000000000000000000000000000000013069b22e7304768c4040e1a07b79a7517138d97b23c472cf2b1355c940495b931dce2ba62cc6a5d6b9cad6e8e05388e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011bc23bd1bdf7d6cfcc5e2eedaae20a4e339cd05cdb131c736338b216765e405196ef09b349721609be9826131d44878000000000000000000000000000000000bf00cbba2e3b686ca4ea3a8fa417cee87fbc7d0de49486846987b6ed995ad49dc177776a95f1ff61340dd74630ed4400000000000000000000000000000000002f9d5215809f8bb74a21916c19aac86e653a7535c43800da58001a5f2a2f2b26e480e6b78ec647fbb51ab129832cd53000000000000000000000000000000000674999cf32314eddd2cf06cc4d646b30ec07cf062a417e4eb17a23fcaaf333e1cffc6a0126d452a854e28cf92b898051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017038fc18ba5ab6fe6e8d3e6d124c6ca9a1505203a9f5087491e8a25862db909f4658b0fdb2e786c7ef816b5bac45c7a00000000000000000000000000000000038e6ec25d840e7317a2883a30331cd1c3e0b2517eb0b26dcf2f001abb77c5a08f1205ed2277380868b22092e1de85fc0000000000000000000000000000000017ea8c69d4ce8e12a5ed137219c9d6e4c662a1d5747ca660414b34f8f810d84c68a08f8fb31e3a0e79a928f5320435cc0000000000000000000000000000000009768b057adf0efc9f74cc761e7d784d46eb0eb388e55e9825704c5e783c640c65f7599cb59febcabb278ba5a950fddb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009d8a5bf87c36be002f5e62faee9a5cf1ff7edabefbdbddda85c82f236cae9b625920194b1b0a27d40b197e16baf1e47000000000000000000000000000000000b370a463ad25fb5812ff7a0ba468d8ddae1c38881cc2f88314df3d5b52dbb61df5db466a31dd26b75a6ef4f3c8c37be0000000000000000000000000000000006094bbc34bbd8a802f775f67ea19feffb2ae007ea7b976876b19575a917eb968c53c8d3bebdf999575eb363c1f229520000000000000000000000000000000010cbaf057b6e32b7faf7ef99c3403e8bbb65040f20f85552d0f38f0e6468a4fa72c314924465632aaabf9b50d8253a381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001996a1974dece1248b83b80a4233fe3c0188c9f687424a4b19ee807be1a24ccc6cf6cb3ed4476e043e4cec57eca5fb66000000000000000000000000000000001997d422dcfc1c375f7755828d2c841826c7627b726d1595fed32a0780365691b5457357a2617c48385279376a0202f20000000000000000000000000000000009854ef3dd4eceef5bc2955316eea0684c6827ace07583b789265d788c44dc7b9ab8673002e98bf766b67f964aed8b700000000000000000000000000000000002e03dc04be97478afe07f0b6d160a4b1a1ab4f339613a6468d92f0a1bb08c6c3f0d6ae5cc6bc213b37c995122b0a6131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000123167916a2b5016bd9031b847d9393888f3be3a862c615f5144598e1be6051cec9c2061bbe590c0f0064704cc160665000000000000000000000000000000000bf74f7eb3decf172813caa3901bd5569159ad30e71085744cb29364098fa94ae3e1dab50bb86f741a62f9b006b9738b000000000000000000000000000000001317ede6ac4224a3fae94a13cfc4210d170a6653aa34459f63f1e4f4a61476d197e177403b604ac33b9cc2de93e63b5f0000000000000000000000000000000007d550e423ff88e849e8ccaee57441c25f481e00f124243f38f2d9fc675d1e8a18845c6319494d5aaa89b4110330736d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000078691635956ca100a47eeb0af5af3b1d0089b3922377eebde4a7d07401a326211505786d011b1f6ee308c286bb20ec000000000000000000000000000000000f7908d5db053e1b57242532c2af87db634beb9fba99631af7037844840fe2c39dd000e8fb18d0559700fddb395c2ae3000000000000000000000000000000000204a1e215e7c01c65ee576a08afe014b4e1204fd4d0e24cde2f561af0b542a788e483a8b2766bec5f6bb84158d9a5290000000000000000000000000000000001f67ed7aae81a9e7e948e4b65ad89e88f9a9a75d015d28cc516aafee6162b410f89d91276e6b58186828639fc2762c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7d078a6785dc1689ec0a5ae460508c87db47c11460b5a27677b598f87a35bf1253b37f53ab83cef0c13d6db4cdc9e000000000000000000000000000000000014cb275bc56ab6e2fe3b657998226e4e6e61351cd98978e5d1860be5d30174ed51b7cbfd849a4725fd0ee371f197fb10000000000000000000000000000000011844dcc9d66a0b018aa1bf0fc5ceacdc984d3c81c4127c29f84fe048b50b6e32d16c5c48892e6081952715f145e0a66000000000000000000000000000000000c590593ca7968d9420bc354e9833dbb856b9c4be2dd1eff8319b348dd716f92f02a00fdf0eda30d3e16548d8098bf7f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bbbea141557723d939844d8d389aaeea923f29572922ecab9df9a4d7aee8298f9052cc7aad8718d804add3674b0fbab00000000000000000000000000000000181323fa4a9cc093181cea0426599d10220f9fc8cf866d4afbfdb1102279ef3511e461890e88198169a7e80b8eef6e19000000000000000000000000000000001045f55e6cc206ff627aee735fcd30b7dcdcd6bca99033b4e5606c80e3cc21bd9cb59c7f3a5e6d6ffb72089f6cd10394000000000000000000000000000000000e657d8cd91f791a98e829024df07d0cec92cf2fa4ded59a77f7afded48d4fa18bc19e04388c7b8ac7c47bbefb1c24661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b66e8c0b0c1068e685663ac8a74fc48bfe98b53630e674516f368b4adcbd066e6b0a71fc67735f8f142a143b62b56e200000000000000000000000000000000127163e526f2c04a4eff66138512aaf06fd1c0d3b0ae6b2b5b0ee96375266257225eeeb4dd7cf13d8c55a49affd7d6510000000000000000000000000000000012c5ca350117c650073362abc9f574d53cb0b629d005d6473d1ce3e7dc2769906efb7c77f1269ffe640c714861fe7da800000000000000000000000000000000042bb4f741538d71567a2ed5658cbc575e24f4f2fae610631f76fbeaf4668583f8c757d474f69131357d9b44a9feb5201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000596f9a2717b501d0052ef7167cb14710a6ffc22ef66239d373a9f8655a42692866e7366c921a9164c876ab1cee68a4b000000000000000000000000000000000c29df6c0191a87fe13c50946dfee8cc5dd6c8168674acfebfdde4c5430fc6e17de9507bf8a878aab88f17f9bcd0c91c0000000000000000000000000000000008fdffb184d72438a4cd355fbb45d2a9d1f92c51ee18c8c4505d1503090382e0479eda005bd8709424ca0eb0afb6aada0000000000000000000000000000000018a4a6b4867bbbfed63544f4f2d7fe6e07dab1fdc8418dbd375b638d7e28f1b30882e57e97387aa6410f21d1083e89b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1d105c03ac0e964fe62a9af0d5e16767ce5bd2feebad246a4b0daa82895707e7795e961e4d7aa264854a263e24d0eb00000000000000000000000000000000154f26eff2b4a9de2308f1ae8fe28cd247e8137df08b5d2aefa2d9552d1c483fa7aae4b2db4950266ba2b3559f71125b0000000000000000000000000000000008f93ce2fbca8452abf1e97a4bc6b997bbf151ba831fe7385fcd7a1135737cf66fcc23688dbcfebcf69f0e02a8340ff80000000000000000000000000000000015eddb9e121ff3a4dd704f52a47957e1630026e832850e74a977bf53ead27affff9fbcfeaaa40fdbb469c0ce92cfc4cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161db7be7e529e00c94958acf7eeddcd5db94327114370302e630855182bc5f68c00a474423ed70ae8387a0870fdcfc40000000000000000000000000000000002122b6b8e70d47ef1b68e23194efc083f573064037069f9c4088accc24552146ee557536e362f52575e7b2193ce3a0a00000000000000000000000000000000064eb7251d50afdb5989e7aa76d35a84c2f9ad011cc44c9039fcd3bb3086943e847e1810a68f67400b664b7a00dbba9c0000000000000000000000000000000008e48c44a5c163547fa43bbc6a1761bfbdc6846ade7d8551228ff8725a56df2815f1222233939440d6f350ea7b866e071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a698abf6d5e08149190a95ac357b5e00b94372ba3e41edaac00532b554d360aecae081a9cf9076073241d86a59458500000000000000000000000000000000024bf59ff07ce6e319346a136df739c603411a0f2c5676d3b100f5ec86266015856782e1e01982dfe5bb3cc623ae4b4f000000000000000000000000000000000df2a5a9022accb780490ce7c73633812c3221c59ac11f82e3aa994f701f77b82ee5812f7a252dff014608ec1c6fd5ff0000000000000000000000000000000019062145773f57a55bd622c1e77541331b744a986523936c0959ba2f90d15842acf0978924d136b929c59e17ba2f1c7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007401ea828b5fc36e7f50609b11bae9861142ac18c4ca0f7f11915391ff84b758ba028fad5c774e9fda0b22ff05040c20000000000000000000000000000000019e6920616c11d2874e224d9d14a65e06121308b59399d48f487bc8d3f3aa505b0a8afb3d039990405961f4cd8cf99ca000000000000000000000000000000000e56226158b3b388de0acd29ae0cb9708425d9047b6d0f1c8cbfdc3b26bac3cf11d30b02d3daa071c2657afa03b2bd7d000000000000000000000000000000000340e4fb653fdd0100ab142032a600f8ce62db208c739b0c021932a9376b91b4f9a3b3c11497415b696b2f22b397d55a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f4422c9c408eea5d315ce6df29de6b7df007490125648b5c1089e1d8eeb82b3b9ac058d71d36a387e472739de8e9ac00000000000000000000000000000000015b0186d8f17e9f2467695379ff10bf85601f4cdefd8d5d248597b42117ad5466a945e033a0ee0ed476df608e2416660000000000000000000000000000000003ae0a4d4f4a6ed15d7cbb7f97e13b56e9819928c264a959fe01fd9d00750c769d9ef0c52c09ffadd7ab2eaf55d9e29c0000000000000000000000000000000000d1058a812761217aa3de189881ed8347942451473eba79d1aab4e2a9db55123f5e33eb47aac6b057337925872c5cae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001444f08505a72a4b256683c9c2ab7c3bcc589626c2222d1d782511888df4c77d72fbaf267e7796d87097ca38e539d33a000000000000000000000000000000000b8cd5bd4b704586914f40d423f4173c1117e7b297a7060e610d1ebe0c5e1e4fd6f385aa726c4868b3b992b3fc7cb77d0000000000000000000000000000000011a701f2014d4dad656cef3410e54d1fbaacdc310374c84e86727fed21bd94b988357b24194555624d3fced3daa719fd00000000000000000000000000000000069d333979d29ece520448c9ead568c5446d78cc84b6fd2910823c58f2bb11f796f42fb2189ceaa20f1a16ca6e83aa781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000169148efb919d35d84241377ccc023352a0b770697aa2b0f83a66ddb57c1729fea06aa72e16d372fc0d83ed75c9f1d37000000000000000000000000000000000334cdd605b44fa7367bfe5c93ac57ec5247841e7e696c96ac1377ed4b9683ff57360ea015014aea144d1514edb4f8200000000000000000000000000000000017f1363dbd8cecae0f690c1d9dda176307a1637b1f2df1521c0f0e3241b59ee1f55b99f9dabea17d29a845f0c2f1e6260000000000000000000000000000000019e4ea16ae986dc4d3a7fd2ac010e0c0918630b1351fe5e262d529382439be1a64e70241526ebaecdc87e796a9e062001824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7abf3fae65765df0e2eb1d40f69a7f8d121f0df539f73b06553d72f9a4fba3f309f2400fab2dd6b59f81caff97f16b0000000000000000000000000000000019b5b7acc105206dc3d524ef370a206e12b6c6078d665d67dea8469e320e25ef269e2247be30e3375e7684189f160d290000000000000000000000000000000011f9a4962ac09651757023cd02f14db921f7b543490fa6f14986a305cb49e9742fb248f6129c2a69fa6c5a090bed27dd0000000000000000000000000000000003108ae6fce2efec5eacab28685328dd10f604afb9a8c55405b0b96c8281554ef77c581d9fd3cd37f4b8426b9551d1441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e713ad7da3a1bf9333fd9724fcc25ac118d183141bf20b11178e489e333f2cd407a6ac599ad9b3e17c3d551c9a308f0000000000000000000000000000000015f5d9aad0ce7b93eabdd99ea74c0d39faa75c9a8b69079348a024f7ba29a4565d13e5731a1912192bfd911c4928d97c000000000000000000000000000000000d1f06be6e153794147a6fd240c2186dbf29de2bdc10e843c73ccdb631806fbbf996200aa4124e6bb00f01ee54c07fda000000000000000000000000000000000fe4e889ba64e5d0b28e20c0f835c88898c8018d590cd2c9083a6eef2c44c72bd06ec000d8e12dda461e6642d03244591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199d59439fbefed56182f7c72f08a67c510e5483faa9372a27b6b709a2a143deb0aeb2934527c39883302eee4506671600000000000000000000000000000000025c38fa6880e79249f278293fbbae06f811ccbdfcedf1f4c5ac33fdbd185b8f14e17f64279c47d9c17eb02372d49b9b0000000000000000000000000000000000877683406bd00449bea64f3d7b0fbe47863693bf0dcd58645357e5a493a775f90c1bd7121adb48992d8c0b8a54711500000000000000000000000000000000016641a2f58e1b60e7a5af9c33811e2c6d7bf77332c72cd587e2bb5c2ba8ae5c3a629da7c20d8a7efeb7da3580c51d4d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e4ee5a9b7785bf824f2a867e45270b1c92b7515d67ca870cb09f51f3f91130ea5c1740e7edae7751aba755e21fbe22f0000000000000000000000000000000001eb233f7e8af97a5d2d956c678a343c76799e7ea0b9d4546bba675f6a1cb1f854a148f92e7816c7081983c4b9187825000000000000000000000000000000000e4e0005dda86fd5057c1ca922e742b1212bc20e561ceb02e70cd52d6ca97ffa1022e7df5781f0da2ab06a2b54ddaa9b0000000000000000000000000000000011187d5204e2487e84b854e058d56b6b2864d7e0a78e0f78db0442b61aaa5f9c5087278103c1bace2255cda048f036a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000167dfdba499597d14d17d2bf0b1c463f53d1b9549183ebf353f144932847fc55b538fa155693e7ac2afe94c2c3c025a0000000000000000000000000000000008c9b3fd35e0f8e77d837eb18cfd4082c1b5657a3f97f007c15812d85fd7656499304709a4aa2e3183806b85f52a76300000000000000000000000000000000007d6f70e1ce9ab6cbe48da75b18c5f159d9753eecd7afd3f61f709e02dd0cde863b1b5802484d1d60e646fee4d8e8365000000000000000000000000000000000ddc3359e379a407a56b530fef478fecfa764c94e70989fe2562f76fa2caba008c0d06647d87f4e4a34eeb7c52b54cd91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb008d43d5df1834599820aecb3adbed20938be01b19d25f828055e231e322a3c8604f64a5ae6c3e93cfe26ad8f59cf0000000000000000000000000000000003bf33c4f3748a204d0b636a9452ef6d37448296b9b26713cd079a7b4fb88869334ad884a8f39b0668cf251ee3a2840e000000000000000000000000000000000a093cea2de68ab15b76c12e1ca701ae13db4c66b511ebd5a282c92f81e2f381f205a74af9b7b6ba0bcc009669b976dc0000000000000000000000000000000003c92b8037398c39fe9e8e6929a400b892bdf09a6616fba001105eb7ff7bfc382e6ef86413195647be774e66d1675ad31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e4b145840c0ffa6ce587adfd9642789f715c167c2c894a4ef390f714d3bacebbcc371524d03787f84be4cb3e8cd32f00000000000000000000000000000000108d71dc01bf5f0d7c8575d11c295fde11703953207610c5bdf4df065a0dfe79cce16f788d72782930167217cb9c3db2000000000000000000000000000000000c8661755b04169f1716fa4c410930e5cdfb8fe2bedaa1dd1268e8e51e747712f9d9db9d57a405c599f334358940a6e500000000000000000000000000000000022e695541f6e113c5e771708cf5f9051964729ead98e2f50486cd9122fc2b388da566c983e10879a8bca3bf766e1f701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000000ca7421aabdfbec158dbe9de40c0eee5c15eef0c0ba847e01c23d6b6816ac651284c3b2d1b573365dde217878f5c770000000000000000000000000000000007b8f0976bdf1663a08839e44ca947d04903c8dac7eb3e0fe223e7c310124831fa84bdb29521c057e3a909ca494c1d950000000000000000000000000000000001718cab76151071956512b1c85ed0d6babd3cc368e4c889d35b90e3f0d0d27bc90849b1ee56614dd0b0500b4b74e4c90000000000000000000000000000000002189f491c3ca8f9f167c8fed28d96acb331f8dd516686d69eb46b2f611bb2c36b6cdeabdd4ba0b743bd7a4968a95bd41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f691aed2190e5abfab56b10db02d1c7d39d19e529b927ff410556ddb20f3321e3e8cb09a4dcd0f8f1de67b0dbb1c580000000000000000000000000000000011a7c1b4ca1b2f9b8ce69e90d1ddcfa16f325bcd11f4310ded935d3989771bcd397a22d7e927e0a4ad028fb4e05264a5000000000000000000000000000000001835b6cf50add5f250c03e7cdd2e17a2989022a57a9589adcc8f1a502ec70cba5ce7aa16b0d1ca4c71c9a209ed8f5330000000000000000000000000000000000b7ed12db13b99378ad61732579a00d63ccc305c8caf3766fa8de7b0f1fd08b4437c65aadb6fd4710c4db5ddf4f879fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011bb8aa0b7f6e74b8b886e63574a1e8ad649e72bdd04685bbcf9ba5cd794f9cb27ffdc0e850996e4a56f03b0cb089d36000000000000000000000000000000000d791df192964ee957a0a2107f619bb350cb9187424068535b13053a8ecc6243a76dfcd89c9dffb64a8a1050670c5ff30000000000000000000000000000000004ddf84b683616043d4ed3cf45f2397c5d2716be4402fe47fae04418b0f7b6735fd3101cef4887e06c35884e1ad1e22e000000000000000000000000000000000ef37a06ea0e8059b4c87bb634e59aff4ae4c90f4f90ceb3956581519e8b339b01869763768655fddc66dec82b4dde281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091940c8fbaaab85ee618960bdf8cca22f9f0ebfdab2140c5246899271d794c01e830cf6e13b285767358bcdc54cad91000000000000000000000000000000000b070fc560a1b38d7b19c417d135635647c92593e14ff6bae7921c49e5bc6b58f158552722b55d79a2a37eb0e9cae703000000000000000000000000000000000842abc84325cd6a2e4a5cecacebf9afee586a0c5767d832f1608a70fd81a7bc875de0e3ba3652e883b64d417b1dce9c0000000000000000000000000000000016ee3c8e4f974c577e3498c916ed3fa67db4b38e4f4d7f085aa1d4b6f8ec28ea6f394e66b06206be546e90986199aa991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3744e80ca42a82a2f67f1e87a9e64dd7cb156abe1fdb8edbaa6ee352a9184677b3a432fe42eed9597200e800fb740b00000000000000000000000000000000141580dca3d93416e5d7a9c56a825c226a7d8b06149a0c9f2d7bb54c282acca9f216818b6876a8b6573c6e2fc42b238e0000000000000000000000000000000003b101cc769110e15c2e5462532437512d38cea9add3f02ae7865034f119d80a5b873d4954de57a6560dc477028e8b56000000000000000000000000000000000c50f90e4484559b89cd8d3f24458d6c4c28d26494a6b3e2a872f864719e255ae629f97a95ba39e0621f8d11820deeb51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011772ce4221bbfd558fe842057d26e84339b684670c6304c8a00e178d2ee971ac0db2d6d00ab0e57b03f5afd01fdfe4800000000000000000000000000000000052e3e9b96ec1dad52c8cdeb06cf676c8a386943397ecbb5b9bf0cbf14bddd6f6643e61badcb34fe2d9190526e7e63ba0000000000000000000000000000000017c1a98aa4fd85ab9f2880766d7967330378602af4e99bfe7f0a472c8e5b64f1d1e10324816a63c21f54c7547500aab7000000000000000000000000000000001411eb75df52a00d653dc3ba4cea6879aa468a52d3d84f30244db61f36c7b8f285fb4acdfa62e19db7fa80db4b74078d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f86d6a5df59f0b81e0c067f49e0c4b933aa3704e73ee6a047f53d71cabb5f8059a1d391c8af47cebca3e7a671943fa000000000000000000000000000000000f6144cd8b8a0f761528b1805486a3f8b1796dc44040933c71da3bea8e7c49c08d5f8380548a72ae39538b72ad5f409a0000000000000000000000000000000000a775637b985d7453093b89bcd9791745cd353c026d55d6be9d752e37fd4166224687049920b4e95040602f428cea23000000000000000000000000000000000b35cf8c4cbf2ace949b4f6b8273b3d8957c7381dd7cbe7505ef6e5d4e12646390cb4e628758bc0e137387d00c749d1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003aeb3ad5c88daed98557e6b827c2ead81cd643d51247b776b6e7bbfe2d745089f0d2d97134e04050b21cd205b2336b5000000000000000000000000000000000dc8f567c0a0a4ef1a7b66ad3cb18216499e24deabd420d96a1d445f79ffd37f0d412fa194743eaef4abee0c2705bd230000000000000000000000000000000011a84591a654739b6ac11e63c66bfe768feaa2a48d251ea11ce229d4d18b56d651483e5c6816de68ba08e08e8aa7a91c00000000000000000000000000000000038b16716e8e21ebb570fddf7b42c140d23c6e9f2f4028d414f72af0b49c64d8f913f05969d6f9a37abad2f3e4eee5b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084e88f229205eb8c9f3e2020aaa37d8eb19c9fca80867395d72a78b9b5695c0a8fa07d956e118df2662bd06d686acb300000000000000000000000000000000091481e29e3df01219e2cc9e145f59b42ed517b31586a98f52e3599d25d99e648d876bc12b9322d82f40be0f4817796f000000000000000000000000000000000a24efca5e420e68dcde12c1f99925cc3cae831da86ea6b9894921c02cd8c1bebf657b4953102d07ed15c1aecb823b600000000000000000000000000000000002772f947b555b98ac1313eca35f4104436504156a4165c7a651d67a9528752da72ab34fe0140109d4f3e2cf3e9344531824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000092156d28b4b7f9e76ea486f725ada3d7cd234a2b29e28900dcabe2540d4159215201b504b6e0c84658373b940a01752000000000000000000000000000000000953fc5f4344ea035a1de62de1aafda2971d35a173e857d2a879df5735a9380d184f381b2f4a7f4f1d0290829d0ded6c000000000000000000000000000000000cbad1e52595c079294b168ad5fb5843361f74803f45281eb269253cc1995a72c450c11616cfd7ae1f1f3eee8f2999dd00000000000000000000000000000000034ab533f905c25b9564b9f8518d28acc0f3dc6f4ae13710841fbaede1995703472becbf993203b190798b044b5a35d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bb2dd566af07f70409f5ed9342ab72699d80934324a202c8047ce2767ef9d73760322b503598aad157d2c749804576e0000000000000000000000000000000005e46bde0389840731f2dd19c56f5589a0e7bddade4316918ab9dbf47c9c7d56df36387194c65687a8c73bcfdaef740a0000000000000000000000000000000002e93b8e95cd264252407cc8d7a9f9a432b2850a6f5e261a86a3e6e1180d4147367a9b561d55b5bfdb6e3f2951f60b060000000000000000000000000000000012c0bed900b2160ce809e31bc4ad41f3c3c012adff07b6403d91237d3b3b4a126a2c21d56db02e44a3411409ccee4f321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000031fdf2d52db432b390f7001de96b5028767ce7098032fd4980ca480461168379cbcefbf482cde54ec7a134bdfe3669c0000000000000000000000000000000012184ea06b1911757ef4c6c8fe756374016db70f70da2a39cbc02edc4a6ada034f177611671f13085c15e716261ed87900000000000000000000000000000000049407d3f03a2fd531e4df27f628f7a75cbee7d731a72fc3fb2af1466ae070e0794eb15cba79c6d62ce82b5b3998449c000000000000000000000000000000000a534bd3d848d5675306b97016409872bd65729e4f2091c1ed5561183b7ced144f55e61e341d81d8fc9555f1dc784e9c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163c2bab8239f6ecad1e78801164c587a787fa2c9553d8572adadd9bceff86c5b2b5a52cc90c1c7a8a7aa99ad83a57110000000000000000000000000000000010fca397f41a8252de1c737358627c74a85c3a3090032fa7c7d4d3a045031bd1f4af58c8260bd9d64da9fcc86dfd5fff000000000000000000000000000000000a28170ee4277ae166ccb2fb0cd935b9b746025e19eb7ee640c454ae8694122bb22baf8645e302b8d6b20e5810f99fce0000000000000000000000000000000012e6891d623465229cdbe20bc680cd26193b020cde1e52b1f4467ce31e91ca9268906179290af97940106a78205f41b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5b9c2f304773af73719ed3f9605c7e2a0d4607985c090b4fed44147f22ea3d0e41b19bf42b50796f6b4c05512262d8000000000000000000000000000000000438b1726f06d701907646636cd311c9ed161270ac03be594c2165ccaccbde1cb2c586733e04fba7b27dfa45a7e06399000000000000000000000000000000000d3d74b40628fc547623a2eb4b9585eaaf3d4ab01dfaf5a894f06f9be9e6cda988fe9960a749d6d7446d2ea95a2602ef00000000000000000000000000000000171cab72de82faa190a8f3244549ac5a7540e3b510c8b3ef3b899b9e2191f01aa33b0d8af5e6b84b85f373c4d614e1e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dec8c78dbf2432224a94f7f75871da720084d90473baa95aac2f848bd67110103d21705400b685b551c60d58530a0b000000000000000000000000000000000e9761b36aac6781c3b903668c4cd13bded5af2cae8d951dbb4175b7de4b35409ee20e38bc136aff0feeeffd629873350000000000000000000000000000000011ee5ffc4cc7906fdef9efb2c8fb5695149c36dd0d8c2daa44c42fbade09db3044d4b1cfd62c4144c11a3e4a16072a95000000000000000000000000000000000c4eb5e6a09e4fb485ea04804fa1d62cf503aded33a0e54aab13f79b0a5b8151f25bd03bebf9046267fb3e809e2d9de71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f8b80688f04ac8b498a19a9ff1d3087887d7238b9f82edcf578f408888a7eb1f83c587048174f38069ed105e434d3d000000000000000000000000000000000f86c4654eb6c9e9156b9e573f6b4eeee5d2a24d929a439ad7aaadb72f6de7bdc6b339d03b5a5eb26e1384c318646d3a000000000000000000000000000000000fffb308caff3afb10d956ea31e4680a82ebc147e3ebbbdeb7ad4f6f502fa5ddf03fb47018b966b37bac6754892ea429000000000000000000000000000000000073b1f7330c6414059897e9a316afcb77d6bdff4e5c4c460e09f2a3d4bbea09c81ab4902429afc148c96996e13c51d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c9b65bdb6b282e84d040df38f0df859ea29963f0cafea770e96f48d57203a4f8f626d58e49fa8560a2cfaf0d139a850000000000000000000000000000000018177d3882f4dcb9364db6815a9029f22db7ae4494994ca047d4614c3c9bb217cae7942fae17478ab393b4a909ea4220000000000000000000000000000000000b5048748f40aa1c7b025b9315acba77d8177fe9a358db033d0d38ea27f3255f3a0f560262097246a361cab4626c00400000000000000000000000000000000002f0ca0b2536b02cf0aa1dc53285eb690fb5e1b29d166b7dfb6ff9dbdba460207a051d77a9df602c6afeb5389d436b441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000940ec5a6666dc5f885aa3bf8eb285e7c2c8695acfeaf52c5a163d84b665be9e4fdcd4200859c8830c5bbd750ba9ed20000000000000000000000000000000008feec47df6be1f826a2a498c08af3b6abe88dd5de90c9971d62b618cd6df3d0f3aed80ed70f097c697cb9981d70a1f0000000000000000000000000000000000b83bb05ce07dd177a2e8781b964d24d45321a42dce5e388806610a9c2742cc57f4656ae91871d32b56143dd224ec2b8000000000000000000000000000000000da578dd312e865aa4ec90912332246da48d0a3a9c01b07726cb10459af6c7519389ac317e33cd672e2e73866e0207ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010da73562a40b166d7bc485e50e9485c145298120f7156b77fe42d4d118081c86af972c732775148066c55b4167c4d9b000000000000000000000000000000001331cbe4556103f9ebbde20afd9ede0fb4bfd8a13198d7459b3671cd32b68a9e848f899e3f084358868e79ecb166d54e000000000000000000000000000000000eb100445185dbcc81e5a23836b3210c2fa94dd433d9e018c9540942c2a8662dffd75a10dc182fbce54e5410449c642e000000000000000000000000000000000ec9712a33ecb529b6a16d1507c960f808b3b0df141862282056315c2485ef659c4a97c5ed8af3469bb023e9ac6015841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000150de26ea0f5511e4715b0afee411061e64e547efe1aa9b4401db91d0869441cba1f8742878f8c3820574d2cfc22da51000000000000000000000000000000000971b6df1a2f025fd89343f3e678220ddfc8231884c7cc8b5df2a906c412a4a09fdbc97c66d2a1ef24ef0f1511067b5a0000000000000000000000000000000017ef55e0f0789f08f2eaaa2e71617e77df7754ae4a21a83d41ffb07109a4ab44d35d919a53038ee843b5813c91803976000000000000000000000000000000000ea85a8c74c55a5bfca9629752f1bf4772b48f3bff8e8efec5515b5d8e922e9b8639654a2af4352bac599c888a59b7b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b9f81fc55e94af896b5ab0ce8cca90a651fabd55a21721799513e2c34fc9ac491a5d847c1bf12a5f0a2930057ed1860000000000000000000000000000000013abefaf0c2929c6c27168231787035f9ce76bdddf80630926f4e755e80374043a7a7ad5ff44c38861996c026085392700000000000000000000000000000000000f72ef4938bd4701f8d387683eb0623e48b62879378fbfd6aad8e5746cdbb8a3338a5e1bca4f6e3727a9394062f25c000000000000000000000000000000001603d0e04770fa76924a3e7d160870fd541822d9f331697a25a27df4d5fb6220c6d2a459cc205de2d078c055628fdbe61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001bd8867348015794ea44cb8953ca0f03e6e1366be7658a045dd00726e77f66ecbe9be004cbc31553c456f07d9cd80010000000000000000000000000000000005cf9ac85c32d9c7de5c9608f00e37784c1de818958ea2cb490c9faff1773691b25558e6679a06db02b2b04cba0030fa0000000000000000000000000000000017e3debad1a3a0d3213e2cae83772311301930ff279d8f6273a6a2072a82acf2e8543e0c1978b9e9d4915ec0b1d81882000000000000000000000000000000000761937005c8dd98780f769fa5d07612db581d1db7b7257b1abfcadc72a1f7a1577cfa6527835a3f68c5205aebf7027c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015da361bb523ece518e0df4c3b81c6d250e1aad8fc5517cd044925a4a656068e55015fff6588595202833a9938a5f5b5000000000000000000000000000000000e7c0cc6e112dd78b5ab418471eb472185ad9df04222b04fde09454222a3ee909d32551c886630fee1b1c96a33c06e26000000000000000000000000000000000945bd09e309cb8f11de66cea612eea8e924388f06050153f9d57b1d4942780fb2e610e0b3729b1199d55a3f9cb5ebb00000000000000000000000000000000018ae9bf5c59dbf687b347765a94789a4764b75ba4c8837e553aa77f7ea943ffe2d46566b29024fd07015abcca4facad41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f7fa3c0cc4af753705d0ab71728e068370fe017449dbcf72bce54e00a2b8ed7fbb9876736a86f522a6dde40bbb626df00000000000000000000000000000000116a9fbdda1d9795e276f2b3fd7fdc302acdfaa1f25b6e53807bb8fb434469b140413f571b90b410102d09339fb6170000000000000000000000000000000000126de033c999e7da01310dc102af4ffa664b254be3038620b1dc6454527297a5d1067c97350b757d2651d48cd659aef100000000000000000000000000000000057460ec73aa03f4b3a7d23764510f8efbe156c88123166c2b2af08acc600343d344d3cdf692fa5c8f90dd380fad993c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014eca02bb0b4009ce30c523a2f929c9d13a8b6bf2b0dc38a75944af5a646b99d131230f4e9475282b0c5dc8485dfeed10000000000000000000000000000000008cc789fd7f28111623ef1350d0e3d7c578bd1fb226d163ad79a623baec0136e82969c8ac0c1cb9dd3436e85b65d650b0000000000000000000000000000000019306443ff9b484afc5f0eb02a848daccbbfac3564a27c1eeb226897d12d49a1ffbd1c275fb15e57658b2e2fa1f5eb50000000000000000000000000000000000e9052d5cc62bbe264fb7a628d5aa761530bfc69b02955840233bd0ffa1550ebd22e81e06ffd97c2043fca37c38800ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018697d54dd19ff8efc61052448373ad96e1c3016c8e69c516d8ea0340c963d39c16f3d1ebc9b9b7c308e3a2cd28797a90000000000000000000000000000000009e37a8aa4c69ca7d3de7137eb67878b8a6a0c82a61025b45ea2993ecd8bf5c37c8c700d353a91eac4116f3ce7560703000000000000000000000000000000000946c6c8e0b5cb80a65254f0e653dc711fd0baa18e1a1fe7682a43f97fb8b6d80a52fccbb5c15e52bd46b3cade5e2d74000000000000000000000000000000000d054b0ec40acf9e605c1822415e1e5f6c10c8428312d951c266ed2c2804e0e4da985c45dc36fd542b1c3a15a60d947f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c2a641fa9b78e5bc887705f2e2cb02f37245f4fe95846cecde02d8d6511a78213b7232bcebab1454d1dc8333076a99000000000000000000000000000000000e6c897ea2ca9047224c0951ae48aac6f30168358ead33ff7efdca9181b794d36e499ff039c553a8796aeea087213c240000000000000000000000000000000012fa557346caf660f97d9e7719a1daa5061e28b3b86ca0e35accd7dba7ca1f2b1746936fe4c51158deb1f1193b0d7d6a0000000000000000000000000000000017a5ec25b331b697d82b43ca750f363fa7d9c8149856a730f4d4055c96e880b65106bcbf9e2a0eea4ba291752f2b17e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000126d72e1958aa856cdb47f3264f8c252b212909b007199a1434dd4fc6614ac9ef676691e483e5500a97a315c5db754bc000000000000000000000000000000000f45331f74ce5a1f998dd825e7ec767d18deeb5ee0f0e5858625e1201252d6ba437989497ac832f8f91ec9f139bd3acb00000000000000000000000000000000051679243271e84152af1ef98952ab27763623c419eb66e39f7caf97042018b69b201954e81a5332a8b822fd39c11cdb00000000000000000000000000000000166bb7976f8305ac908b6ff37a1b6049de9657f573d12664f2fa3b50f2dc85f12b7e57c6f80cef1127ad59a155e1ba631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000196e0bda2ce1bb046a3affbc5e6ad8d40e42117e1e0bb75c2c386fc4b3413d69cee50e2804f1f225daa6e527f20eecea000000000000000000000000000000000beafcdb3c675e06b9df910791bced1a866a11fca019c8e9339e6380289c249449dbc3bbb1670e2c4e27aee1629050f2000000000000000000000000000000000bb412259ff260c7fe0e79eda3fc64d1ed8c5dc94f47b6cb391ec8e138d82bd0c4f3fef8e3134d3f417bbaa6173404420000000000000000000000000000000018c8f8b4e94c1bfa527f7b3155c518a5a8534706b485def7cda06ef930c359ca6074ddea0f60fd7c83903a187ff36cac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000010b3aa26397b4d778824f763d1e2894963e4d71190fee9a07054698d94d78450eed5a26d1719acad128fe4d72be3ba7000000000000000000000000000000000a50c2f13d358f620d31231cfe1cd685ee1d2f0876e85fc564eb8fd5543fbe79d883f169eb64303cd27cacff816d441c000000000000000000000000000000000ccd06265501e021a5a5633390ffa7b6c74e5483447effbe86f2bec06ecbcf3f01e8adf70328ff11e5e778551023e4b900000000000000000000000000000000176d55d2d3c689128c467e24a48828c1c457a482bbf1030d1f415f57088680a292a9509f008db74c333aa9d7fd811c7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5bf446fca039a6c06654ade4cd9a47540188626a8cb19995ace029fb5fed385d3a19eb58415dd5e6573008129c1e570000000000000000000000000000000004ad16ad06bf0b83ede4d6c6c93c406bc8f041aea31a931bec4c15524e9ef5b03216565090618f14f73fa63556582d62000000000000000000000000000000000d0e796ee8165ffee653a593d28303572f975f11ea96c314f7513b79c9f0d0dc2383f54ff92070b5642fcbe61c618c210000000000000000000000000000000003b627fe739426d01ee672d2af287f6e227c9bc312f166069d7097b3ea59c12be548c247c9c2a7141c681e7e4db254861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a97e79631fcd3a2eda627492c3629974979fa35c92108cd20d8ca194299e94d536621e05a4cafca52843e11fa7f7c55000000000000000000000000000000000b67e4a00422cd2f386372e1093eaf1e0c6ab61fcb866bc74e36ed47cd11135b7b0fda1669323948f010a4864e7a2804000000000000000000000000000000000cc8b392227f93591a7d5d4e20dc58b123986d235f25330f4c15ac72f38285c51cb3c05e8cbe18c000f5a30afd670a1400000000000000000000000000000000125e7b769bd524e06d8d4bc169d42ab5907acbc3964f82ad5fc46653d8843b3b9b6c78f98fc0ee2faf309f1db66a6a201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019d26ac13ced53564543bd779c12ed59fd67c4ff04680e8c33ca350b26c55110f7e892d3ba5ac3b94a2ac69aab1a22070000000000000000000000000000000003ce5391468d3cd15a0112f2a85e3e695259fd621adedabcb31e886b276a8c1ea270f694c7fb743c5b897c3e3935b2f30000000000000000000000000000000008e2e8e27088aba2d302adb40e1dbf743491892b2a7d35d3e3fcacffe0a28f53426a071c67d9dea14619e25be07c4397000000000000000000000000000000000dcdeedc0f2dd3e7c751685cb36cf8bb0180b3680ecac5574c01f7f391f29c65f92061a9156e2fd436d00df6be2c12171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000373a92f7c50d6a1759eb0ad307a659d7b63a6fd62a7565c438c298e7aac19939a84d500402a0116b184f52e28102ef00000000000000000000000000000000019b69882700f174ef06bef64ca3c9a350e453af1055fc75c97f4d65872c2d74966cacaefdb83093c204112a03f270cb800000000000000000000000000000000104069b74e662c9cbc4fd31dd730904db523826816d6a90c872e3f4e85284a0fa0fb217d9f9557d9ed032a32d94b262d000000000000000000000000000000000974a4dcf5bef80dec5bbac6ea326d7fe1611c83f07247935b98033d901dcb54359cc8a54ee4c2b75728234d1e285a651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001e9ec8cd073e00cb57852f86bec0fd237ce3800d1089677e7c222b15492e7657436157943b833ecaadfb4e2ac0b325c000000000000000000000000000000000ebe09b93ffa3883dd9b1dc1a2252d46bbfc760e2210dcc9305809ec4d3a631c4673fe73a0100b0df94c0153ed723d2d000000000000000000000000000000000cb36d51b2b3542d0e0abb586e3f648bff887bf3f167ae90663bc7b888c03739b87b12606cef5904b224f68dec6aedf300000000000000000000000000000000110514f7a63ec805e4b937683b367b5afc15581a221051892090eb0ecd33b58bd25540cf057fd5e54d939cdd9d51f53c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000113f5ce01b869b9a2d6c4116d7d9e6802ae56e4cabd7e0541f7d7cb02bbd23e138ede176dd23b7652cafb323321a3d46000000000000000000000000000000001711be3d5d9ee00eb15d8de547ae85984f99fe28db895808c7df12f162f6dd2d49ef4287d7a95e328ba1931aa899635d00000000000000000000000000000000116555db0c03b92375f109c8632f4f32de6d75c485e116bdb7a9c6cb88bd743aa44bc570f8cea8a33457d1d467f8c5900000000000000000000000000000000013e83e6af5363b65d1a9c82693dfe3f12b071add3effd51767313bac84dfeef005227291418912bdf543e605421feb631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c4ec1f9ff2d1e0e3b66f54e026c3ad9850d97bbe9493bdfc66df26433344ee13ab99a6895e584f0805097b085a440e0000000000000000000000000000000005183f6c272feaef68d07a40084da61bb030ccc4fd1561777072e6805f81e7b426845a45b2b0d2ffea223f692dde6db800000000000000000000000000000000006347cb4d58be7b18f6415acec86bd873125c00fb1f3c9ad721a957a949cac96648fad4e3cc2431f436688faf4445e700000000000000000000000000000000097f1ea1e3c1f353ef757681d37cb0582adb5510359424242a4378ded03c753932564f9b8b094af629bd723dccf5ac031824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c769bda6ab1dde0088ba6a98213caced1434fe403f0f15659f57badc90c22ee12924e0cbff3b81bc83d721bf258a84f000000000000000000000000000000000add028dfdb6748a61a9b210b257c8971c2426d894cfde0bdccf2493ae7109139ccbdb22f4490b710b4fa526b82d83e0000000000000000000000000000000000dd69b5cd7dceace2b44b18b1801f1af2f728ccd6a04c34863ac770496bd3c769b94d1a97ba31120c2704c2fb765917200000000000000000000000000000000070cd27fd2bab7357664fef90d8abc1834b373fdbac7ba88d2d23908cddfdc05fc971ffe81eb0de3c7931d2c1f0032f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bd4131619dcd8977b9b7119124bd98735f9ed0a10161ae8990e2ef910da3643408505fdab947d396e63c8ff4791a9380000000000000000000000000000000004441ffc91cab39cb77baedac7656d8954a0887c441280d519363fad626d5ac039218af83d9152ba0335192c3b3c402e0000000000000000000000000000000019cb61cdcb0d4721d2642c27790cb1bff61d606651bf03461578b6101ecf1ccf9f816fd08d22cb780333270397a82990000000000000000000000000000000000e3944c093ffe8b3a063e9625ae99aac83e1bcdd500188525496f2ce0d572bcf138d9d4e53fbffa17cc869580d446f0c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f184b25423d67d60240e51f36f30d44a6edafa6e2aadd0d64c7e408a69efdce29b438401c71a318d23b8f475e287d3b000000000000000000000000000000000c54588a5ac8156cf0a602afea61af59ff4d1129566626c30515e4aeb27ec62ec94c91b14df463d0fb2bd2c7974ab51500000000000000000000000000000000026b8192202435d1df1f7a08f21ee7da8c4364dbba08c6d2411960bc4c3d5c4d934f4f695ed49eaaed0de8bdd39c7df4000000000000000000000000000000001745af385c9faa4d56ed2eea7819b168a902e57079d3e75af09625f24deb03a6898e674b63dca1439c68a5bfa090278e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000327e054f3a9b7a34de5b79c3f4474a123888e963d5293be93acc433a915a45318cc7b0b06196feacffb7c329d0a6bfc000000000000000000000000000000000f425b2c22ed73646036b45b90fab7852e7dbed9b2934c0ee762f92b0fa26b24e2ee3cc78c10b472c71ca2ce45fb397e0000000000000000000000000000000006379217cd6376b7da437913bd788585c99e4d8e9b3e2de36647d46ce9a8e19291c8fe016bdb4a86fa53837a82de83f5000000000000000000000000000000000daefe609ca2f03290bf86471a120a952bb6a76e3a19c50a334fb754fa470c3f269179a66d8025f24ceabafe5b8205ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d54937a1465c1a1f6cdcc3c3424e074cb25b5b8d6ce979382cd5361cc5965c6c8375cb0f59ccccff7d4888d6a6a4f530000000000000000000000000000000017e6152e041d405eab7e7722cebdae7121f8ddb3f0336f67c8cbb37823d377d3d90a3c40615d4707afebbdff78f8f3a70000000000000000000000000000000008fea85099a644721792c55ac1ed6f91967e0b6b8e671930fe4e76fa4a99c5a935fba364650d805797892bd24ea50b6f000000000000000000000000000000000b67a95dd629b70a6b50c845fc72d1efc078fd973bcd0c9a90e1dc5fad6c1aed4c696c8c2dd900ee45377416aad7e15b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fa3c17e8f1bf28d173b0401415093b216e3c0f915f102e1f6459e93837d1beb9510003564b6d6e94e8f1dd9275b51ad000000000000000000000000000000001106ce5694629e4e5cadde964513b211b5545099adee788a6bec3c9f647e0c08daa3c403e4f2c75da49e224438c6017600000000000000000000000000000000021a705f75ee9a4e77205e58219459562c555d62ebb6a28a51cc4b1ea8dd933e551f514d4e477c89ab3a7b7e33622ee60000000000000000000000000000000005eeb353ba43b1dd2b7d088f29e50138591b86346c18939b721f171a7f9a41c4957750f352ac7e0bf3f35668bec6c6fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192929f7ed8a0e7845fdc1b8c4a3c6eb8d1cc70a3134ceba27966be7c25c03b9c413963cfdf356afbb0d0284555c700100000000000000000000000000000000076ca0b158f3ae3923bc3360b7707c5575dd3e9a280301545d3a03b2037812bf58d40a5004b4aeaf27d2c9359cf45e45000000000000000000000000000000000bc6a5881954ece3fb95987c6f7ff60fa3e8fad078c2b7a808ede61aa9844f7fdd161d974edcf7c38d0a6d704d88dc9b0000000000000000000000000000000006ab9f6b230097467edb714632a0e48d331c1e6afaa503e18cc1919683f5885436ef97fc7ee84ab71bd44d114311858e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000165d84fe712cb94c9ba14eb23f925e229fafd759d25e7aad2f52ed54d3077981d9144d9641aeaa9a44e1ea8db0ff9f4000000000000000000000000000000000255c9772ab035d5d3ee8942d9b67b0e5c0e5a910775904ca18802ec11e8b1e7042db099240de5432b98a3a1a65f6629000000000000000000000000000000000ea9fe87af77a793811332d2745a4cfc21a089e9175286336717b303330710c27c5296e707a3623572025650e26aabbe0000000000000000000000000000000005b5cf552b9305f669189e66857a62d110b948f82c12e671893ce52d465e21594720c85c5feb215d3d1730d6aa54db421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b9f0db7fd8fc530cd276b1e088e103661cd92590eb1941d1cc529af9ea092721ce3d77e9c23919d64df36c657e0cd9f000000000000000000000000000000000bd0fa7923ef37e2b8ab757f4fc02b0f03ad3bd911ebe2c783d26add27664d997b97526323bae10a509d2a0bc6535fa400000000000000000000000000000000198fb717c39b731638009a32fd38add77143805e837ffcf610b535b0583de03884e09e766c162faf2ddfc800b9c791b900000000000000000000000000000000114b4c2187370bd02168ad24b6af24c81254c7dbf27b177f9664f38cbf0c6cf40d675c186c2d34838e0410d47cc674d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021425276188fa1b56ee332b8653e29ae12ede33627fad4b11c0b7baec66c4ccc766b7d870adbe700b1b9d6ab06bfd130000000000000000000000000000000012c2d581b49c4eecee4e2bc3a89d89fc044c8270b4103e3da503721c971be4c63604fbcf2c4e4f67385b59d2a058c0cb000000000000000000000000000000000ee5044e6e406c64212d4c85aecd60db6dfaa5d9d87e6a4369441c08161cb9d130a56c1eb4fccb7b0165f2d6921613a60000000000000000000000000000000014d2aa6bc7ac017f5648a9c6d84ebbe60d4903ff78beb0d5cf38cfb86b8c7a20d39c56c3194e95e5f94b745cfed169cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000a3890c341086df2f87f53061c1a175f6f712ece1a1d4f3e9e768842309ea10a3c71e2b68ef6c27ee02cfda6f7f33340000000000000000000000000000000019743449fc44aaced93e1ba066f77af00a1f3f764e1f501826f6f8dc6917214b9ab8a68629adbef3ea5f4afd3ce1edfe00000000000000000000000000000000136269fb7c6cebf84dd01d4f6cb0cf56e005b8d8b900c63020d0a2f357968cfa32d9b823b5f5de6e59eeb2f486ea4c400000000000000000000000000000000016d53562e5f0a7dae599c41df3daab457bf3dbb67350022ead1be23daf09283a49472c950026809560c09686433c31541824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001976747f197c2e15b83adc7abade6d7187e911a8674a692bf3588e72e0a446c043f0050d57ca6e24a0f7a19e2c4b1d7f000000000000000000000000000000001919667dfb7babb095e40a42f09ce73d0c8d246eda076196aefcff76268f90bf3fd5b5e362c8375716acfdd1b82dab930000000000000000000000000000000001aff2e3f1acebca71afa78544ad0ec3a63aebe44672db04c857afa15f3e9a2c3b0742e2d406c3d34162d86eab0a7b86000000000000000000000000000000000c50d66141e319dbd611b1663a34f883f778b165f4da579ad9f9cf631cb370870fe8a9edc60a2d3af26eccaa7d10d77d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e15f6c0e14710eaa9d44a21350f25658f7e2f2e12264c6d7c4d079122884ea49eea89b9add556424638ddb2a1bdd0560000000000000000000000000000000010003ebe432571abdb309876926cf6146db05829387ec491149e25fda2c71a45e518477a5e448b4fc720789e0df64cce0000000000000000000000000000000007ce4015d8edfd07cd0b452d64d62a919f7ddac90fae662d64b0224e80bf4025c266a4223d4f98e547af19c36b458410000000000000000000000000000000000d03dbc43f133030a837f198e650f18eb8c20c356f8af680b38225c88bdf8f98a25da98d1ccac1f1d11ffaf131ce8dae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079d76a0933c00df908576f73c529e9061b4afb00ef6a60ebdf23c72824f610122240bbdc2d0de1bdcf38d6197d7ad7100000000000000000000000000000000000616c836b2a78f41c772c05499d29a549d395bd40e2d24f058c8bf9bce2f10e9643b1196f0735da1eb5989ff1884fb0000000000000000000000000000000009216db1fc57889c35bbd921d27ab606ac667d1e5d0cfdf625f5ec59fa0059111d294435f46694b7656c6b1f732de5e400000000000000000000000000000000184d5a9bffaec172d01e9b3dbbf1c8aa523193b2aa18994e35b54d59a3e9c9847d64d1c03a95d4437d6a21b980a4ba491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001a7f9828141de108ba3adb7150a8cf3245dd75e503faba4d09fa9cd4df374478061eee436a13e64a8e9977ada53e28d0000000000000000000000000000000004efbaa96b16996db9838ebeffe831a6797b81712824530df24f79ea25b505fbcabe45994c3395481f822ada6d71c0f600000000000000000000000000000000189e7687248a102d4b6d81856a27f0a3badfd2304bcacb38d8001a7fcbbe90b5d8b19250ab307c4880af87de9c49167d000000000000000000000000000000000b679d584021f7d4ed51837b2d5107fff02a7bd852bd3ea69325728804ca362c332016b6d641175bbedfbe345c138f111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001e1dca7a05a4a76ecce5d48c66eea15232be0bea17c111fee1972e5a466b7003f3930669898de107687a5da6637923000000000000000000000000000000000aeaa77666b0b07dacb2d020378406d42274e2b2679c5fb8277633165b001cecd79f16dbb642f322982dc0a82706ba870000000000000000000000000000000002d8ea6580e039e9299327ad3525847da3bc95571d0038fdc41cf39cd9b4834357704e51f66ade07527d0ed8d2406b70000000000000000000000000000000000745c6d9dcb5c6709f3c678956b1e837308973bf6ab658a9e22ef82e0191cfdab536542035a41e6ce027be69975322b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ae4575214289f7e25d872aa1bdc8ec68a2e3a891226eafefaaca65ff66823417cb9fb1d940b2683ac2ce1e92569528d000000000000000000000000000000001079f904cafdf79694880ff13eda57d6b1bc35a3b420a7f65fc377fc6adf6b61b44e919bd70cb7dd59cde9720779406b0000000000000000000000000000000012508f92554ad575f493728a6b71813a43ea2ae3ee0a1888afd9eeec7553d8cef7bebcd880a178724e2584aa0c9180c50000000000000000000000000000000018f4b6f2564aed7a9a8842a039fb3d3ea51c9a158be8bce308221e27841d8793a18e00d8dfe0630f4cfc9ff5cef763951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000011ad3252b8f513e1685847fbf70d6cd24812934c2bf36778676631735ad2663c0df2cae0a11716b4230846040add780000000000000000000000000000000018fa816185a8b2f46279805adaf67670ea286404b7eebcf1f67cc2f3dfb2a5f746ff4a24fe343d311d6c383e55b44630000000000000000000000000000000000d4acc195a7ec99b707300d7c1a2615692660e0ea2fc619544e4ee022d8fbffcfea13400fe79f91271121c50347de42a000000000000000000000000000000001115fc5429cb3cbf6adc2c0405a865a9d3ea43b9a2de331c22cabb90a68bd6a0d07026eff4b76f9165f945dcc31f894f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149d919957d288550f8485a7388bdda9fea3bf2d184babd40f37091f6a7c75e2fb8f976bc5c18c9b674aa8fbb035cddb00000000000000000000000000000000008c1a688011da56db1a1f4b88a70ec4a6f1f8e6926a4af7a83a8c0a852c89778bd8a2e6ee87d1f8187597a2e0b5811c000000000000000000000000000000000ffb978b9d2936b159688dfbcbb49f04033e0e4682646d3f4d9aee28b93fada76c7a9c5a68eed4d06c03fd4758e42c970000000000000000000000000000000006f409ba8ebe146ab8472157abfb8888dee0386922120ba93593fe316cc28fc4d88aea859baa20f39d499bdf44e676cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ff23917b604fc34c1c704d708c6e86a15f702e2e867cd6092e8ea5f55282664687ba844c1f626860da9294a2b9ec4e300000000000000000000000000000000021eaa431f7de8ffe98f2c844d96f9e32b56da4f7bcd49778a222517b42fc64cbf231b02db851e74cfefd48cf8e98cc900000000000000000000000000000000120d7bb19660e13b544e0306a3977bb97287803a10599ee735e186f1eba2ba234c51e47bce279b0be30b23fca14ea870000000000000000000000000000000001961cd1f54b036de3b1c82adc0191174e232914cbb9841a872bd28515a409783366c64876e5ebe3237d39eae049fdd7c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004172e98cd16572aa4f2456992a3673c6a9cc9205bee4b841f9db84f77eab11b6c4e0b0df92d95fc7e6fdaa88042d6e6000000000000000000000000000000001580fe0cb278d27f18c198d419ca66b3366e893e1ad3f473ee75be521c85bc6e657c2c3164c1cc79add257aa798b3911000000000000000000000000000000000e9c31620c99a6dfcf65f8cce427cb2aad8c500d7ebee93197bfed0b5b487b23d3af36766ddcfd010c49f80ce882fd480000000000000000000000000000000015428c05d02145a347a189ee7e0220b87ef2f00b93886745d41e58a1df055d927acd1d08f10b1985d1304135b862cbfd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012902581e021c0e7b0146a289b35a379594b5506e769c4285a1b1daabdbf52722c5c7532a28e37e2b1e290feb58a866d0000000000000000000000000000000014d281316e2f4cd09423cd54dd62394bce7c91e313f1f0d91c6414de1aad79547532e8ff34d3d964a47f5f1dbbaa573c0000000000000000000000000000000015865130170cc3528a349836f6a4160ee4f868c1253638d4cba61734338a5daab4cf7178531a61b890ff60344c592eb500000000000000000000000000000000128ec1401cac058f19dd22d0436db7fbaa6bbdfb4b986da671ae82aff51c65a5dc2ab9789bf6334838413df4414439e91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c4dda0cd3c81cb10f50fdbf35c84ad2bfb5be5d45e27204b4e2f9d727a1b14080d0958430aaeb69f6c0bf9088bc820c00000000000000000000000000000000111c35a76597ba93de6708c49e2cf0b98602d3ae13c81d1fac0c5a8b1f4e9350d710585f68ce1d30f15bdd2126b20b8f000000000000000000000000000000000b4f05eba6908ed036156f69fb0efb5556ba90a9944e52781a8a4a01911bed0ef641d2e41443f33223c066be00b168c100000000000000000000000000000000006c6c97c53f8613abeb4136c5f3f38580e4c45494ae311ff6f1279e3c8881ce4e4bd3a735533b596c56fb7ce1ad1b3b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cbf050bee1f9a6762990de0296f3e779e82092e2341f30886e316520facce215b8cab9f0ea1eb5bfb99ba9f37b16d2d000000000000000000000000000000001725ddd8f5076e99fa06001e3a84ebe4522ffc36aa925a1af31c3f6933161ddf2cd43f63b185b5eb30fa0000f914502100000000000000000000000000000000176b8c74d77b443af759ab5a1e949c01de483c564fc8bdc36184d6796900c2c5d039744f17de8569df941f065165f0e8000000000000000000000000000000000dd6d733dda7cab83e27611941a7234ff8b68bd97f61b9437eec8a63fcaa4e48f3b484f4f60bac232e794bc9c8a6742d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a123f96417b3678a8a8c84952f6e98faa6615b041a633e7e7ca995cc52e749267c038047762c0fa7f54419ab590e8e0000000000000000000000000000000000807b8d1633d8cd1619d6dee02c08fc8f23fa4893830cfda32ec6b2f9367c18006b7d3d797c0a7385e70a454b1027e5f000000000000000000000000000000000dfa56c5d81fdaf2abf8f82512679858dcd8dd0ca0f142e847746e45a63495b4d33431892bd0e638a5be701ed043190d0000000000000000000000000000000005b2ef1fbebfa15051bf048f65b851e88ac94a5450b7b9a600eb7422a71ba5bd2f67bd727982f4e214ed128f5c4179c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005103ed736439271cbb7cb0372b455998c99b48915616ddbc9fa396e05dbb0dacbe27a2ddd2eadba3ca352dc40a765d7000000000000000000000000000000000d1de628cb79193e939d9a18f0e947f31ea00b5b2ac50dc1827ea41f6f134a59590d72e7cc43c6c17eda264287871bd8000000000000000000000000000000000adfae49d9ae730976b107a54b6d79bf37bd6d418d774a3898b615dfe6f8154ba9e1544f7eebc9fa4094bcdd7677c90000000000000000000000000000000000048ddcc907311c3130ea2cac650e8eb956959d52177f58d3ac96b294c27ed112906fe927291222295ba676e578e380cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000214cfe61508ab939b4a1f34fb795ce58380e4bca74d77b485444ab5b741d4395a78ed9b6b4c00284d6a212664c14e7e0000000000000000000000000000000015b1817974f3da7d3280dd96da5a0fe9a924cce513ebe4c84f80880d23629f1d3720661d4d2178665521163938a55901000000000000000000000000000000001325e02e5e3e57ffd0dfce2f26b70aaaddacce46c91ce6be1bede883166b0441302201e71d1f5a3758dc8f72627dc1ee0000000000000000000000000000000007cd7cf1b798c28e3b09882bef631bae76ce2a3b25e3d7d9b13e5cdfa8c6de4c8832e5524f59549f980a70c2ebf507771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ab0f16219535e39fd396a73af90d105679a8c384ece811c0c8d79cdf4a13141a1517d2223ab64c61b154eb11ceade0f0000000000000000000000000000000018444410033fe9496a0d27c5d82d2769fad952166adcab12b2b026e9d2fa4b1fc363a2e745cc1826e3397822900507d5000000000000000000000000000000000bb0349a8c0b0f6169df3c7efa546bb71b494e95e184fe6855fa4fc2aab5db198cab92517df33e1ea0cc54936c35a11f0000000000000000000000000000000019cad998ee871e6db8995d9e4a848050efe3fe8193b616b4355d5f89f74529f0fe3d7bd8a894deef85252dc2390079861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000071ecdc0b72d9a59b7f5c60b8d331780ce2010295e0f3a8069b75291cd9acfb6729e59736c17628d1f61ee893d1a34fe000000000000000000000000000000000e736b51b42e547b44a0d907fec6b4ff7101d3233a4f4c2190ad4d3cef61309b060cd236b0aa6f81cad80c4e987632f10000000000000000000000000000000005fabbb294c92e9657c998b2c785ab29e2b34e928a5db2b5ac637980d36b173da36841fa4b479e230f6fb64b26589af90000000000000000000000000000000002cabdb05b1db54c3e95d3d6bd5bec6a217af9a7989acd96da302da0bf5b954de69ade2da9edb600af9671a152409e2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000184e9307c980ee860ce798c01babb58c49a0cd4e7ad89f5c88d565be1c7799c2f3b5b5681238b8b89c675491b0a8c9e90000000000000000000000000000000010ad7f1e13b39087cad3051957f4f6e2b059f4efdbd233c90d4ed2ed042d26fa8ca7281df84cd3442717f5b855f60050000000000000000000000000000000000242d502a4242a1ec6679b24716e678b294264f54219f46360dac8aef8340c50cf25fe194b25d78d5d96eb8b8448e29c00000000000000000000000000000000005f183ef23df76c8cb4e94b0faeb01fbe1080ed10ff2ff12a446cab5dcc1822198bc5a2bea9de66b47d86f21d173f5b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009edd9541676d4f8340ab0d57dfdb204b5c0f8c439576efeed3be8e546830ad92a450a97f86335a99b82c54265370260000000000000000000000000000000001762fa5eb1f01e2b72d0be14cfa8bf8faaffdd0fc8129c5e19c02efd8401fd24cf09c51bf0b6a186ad23d46874f0c4140000000000000000000000000000000016f68b1318fee9f749bc490ed7aa3f9910384cf9da77156b9130e41a6c2362e5be9fef7f9d46b2ea0a34a7383b075d6b000000000000000000000000000000000f4096aabd760dde416501117d62189a0936efb6701f47689d864a2e87b004fd24fa7e3eefc414dc06482108dcac9f171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cd03ba323011dc77b4d5ea0616a45e2b1271eadac932ba65bb40ec8caeb404d2e32cbf8ce0c9d6f6906d22e35c570900000000000000000000000000000000109e7ffaccc50db492d0308636f6530d2a8c67982fdde72cbc9a5beffa490a328b6da29ae41895a1f8c90d61c96d1b2d000000000000000000000000000000001102d27bf3ee092097087f1efb844f1c2c16578ac6745b8f80c2ef540df7956bc73857336fdd95fc40f9cd2d182064bb0000000000000000000000000000000017c3eff4919bf69811adfa2eb77d1902e860e0a50ab692f8cb59e13ec055732f3fdff100602135689c40f825cab748451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004fe793c1c314fa38d501d26b54a7f515f4d2f3cccd153c23dd64ecc823d780d5e45716df4230de90b94f38ec2b6b47a0000000000000000000000000000000000208ea4ae3926138a0d53418d63f683de6ce9163bbcc1b17a0c2d3a61f9f57dbc43461c343422955bf5e447bac295ee00000000000000000000000000000000004f8b1257410d221a30880052a8c37a63686bb65f503fff02ec629c709e1c5e4989322ef0342ebda1426903b39e765800000000000000000000000000000000178b567544465e7142266a0d7e0c2d2e2876fe6509dbf18b84416d15c0f8e6d2817efd3dc8f10a71632f7324c1f66ec11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f5fcb3c738f5b0191cf66200a7d4c29c54b3903165bfdeec78184cc3679dfe89e68c7ab0c50c0a53a94f88b4b68369800000000000000000000000000000000039ac1d419ccf9d3540a859e51c48decdd0ab7ea1a78f9a2c915ed019f15b4f6efba57da3dd4955b1cb61e2a5a6ee017000000000000000000000000000000000b94813c49d13e3cdd4f6f3d6ce58b8ca9f75746a8324f5e3a4e9161bc3482ad478a9f8cc33f1bc5c2ca51008500a536000000000000000000000000000000000f6079b9a35d6b9c4bd7061275bf97260eb4746c206fe8ae27632f54008aaa2d3b8957c646c2b95ddcd95684e04f58111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057c2a472a04e8d4bab0e8f610fbc3b55a918a7042c5cbecd6e137244a64da6a7cc88a3ea666e232dcff09be460b772c0000000000000000000000000000000007ca4091c90c729f5bee0b8aef643d2a0e96233f5c24a4ae9a46a40a7163a19a01f6dceda55ad2dc6be9603ca7d5e6cf000000000000000000000000000000000d0d6f5b7112d4ecfca98b5f248ae2e4241da7482d14f99d17cfbb0bb8e4091ced8aedb90db6321a6f073671ad5918d40000000000000000000000000000000011fbdd5bb2711ca0b0d7ce837edad45b03faa6a25b9d4bf4e2761279fff6f35e53a2df6ccca2dfa076f69b45fa36e47d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018278c188a10688cafe661fee5bf97d5446f7a4b90efd3ed1324f653f0b2c57b827b0a3ff9218b9e9e3dc3e1ebf95784000000000000000000000000000000001045e38ea40d3261e3a6dacd64810d140a0527b5804ac085e15352bbbddf4a763a2086d62c928c13168745bfb1ac4afb00000000000000000000000000000000193d1ba7fe4266179dfbcfd99e7f8fece3fee75ffa64e6c1bb5559dfeab16212167864ecb6e0ad8e33f815826400577300000000000000000000000000000000062bb1586b9b5fd4818d59778f87a57e6416ccf3744a9a2be59c6058642ddcb9179b5ffa1632b0c19e27d60da3c27ea51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116d1f9ff304f684167c011ba1fc0c68dad640e7d3fae81641403f572fe85274d71e9d77fe27c5e2c2dc92df9e180dc70000000000000000000000000000000012b61248cbfe9cf54d489a259e80c10d444ace10e0a3bae31ee67de990d41dde96c5f55187ce663f22ec1284a6510a300000000000000000000000000000000003293571e8aa2e05e18a4ed3de76a5f75c2a62f14918b18f2ae5c158cc1520756e080394c6c96a8b4ca5b75ac5173208000000000000000000000000000000000bee354716c71f4a9c2e4f0ed6ed56ed0553567ff2a92938d6f3f6e22ff1d2cd7097b6fe65911000859bc50d5e6593251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128c52265ffd0edd5253860d0691d71f95ba0101cc93ef8d86382e7461f3487242b139b31745f19270c6b2a1aa6d8a9d000000000000000000000000000000000f2eda86d5126e3914be6bcd8ca7b41311276e00f5a20740e3f0d11b82a331c841a79e3c60e2b42dbcd932778787556a00000000000000000000000000000000001d7d245194d622ec87a564095d7b9810981c6837e6cd1be1dfe4b01516bb400db3e7f59dfa001f1574750c80716bb300000000000000000000000000000000068809d96854ce40c835e58ad602b7f75be3299b5e064113e2098d292f6a79eb3d112c9d8ad6bff41b06b6d22bd230091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7dfb7a86ba605f5dd3819f0757ee9782fa04a9b5c82ee3dce99b89c5a522cca1486d8d5a49ae7940a622bc54388e00000000000000000000000000000000000fbeefa22d9ea62968cef3d4e8bfa5e81002bd509b209f4b4e10de82a75a995bb7a1cf4b152d3c235eebd323b9b13b22000000000000000000000000000000000ec1fb16b00e6cb3a6fcc1303769fa7f1d5c94b1e122b576daecdd5c484e6f880d18d074f77e7fd83f53d65e4f7abea00000000000000000000000000000000000bc7e58f9cf9ab293ba008c9eccff5ea2606c172bbcf40a058a1eadb012d69995ac23b9f7b0b2f4cb460b4c73ccf0b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005e1c686bc90357fbc853a00e3cd3b0b03df94bc341ef9142da91696f6d46bd8a60589eb361ea068a8623e3ce0f17e96000000000000000000000000000000000acf45ea5a9f7a1cc7c30c11f80fe39d3e2eaccc4f9a2884365d6bb7a94d79786eee3a923788ee5497bc6645a25c54330000000000000000000000000000000018479ab8ff9787272d8b7d8e81175bef7911105fdb6f7903f8e5ceb57c2a487ce125b930251bc44b9a92cfcb082ab594000000000000000000000000000000000d6437faed48743a53caa2983010d0b04024d9c336242a6d2b9b2bdab712fd1b7dbc5f9fccf93a8839a95b500c1538971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017dc679a3c1568af23c75e9d450b47e8e9527538c1539331435d85573181ce998b39e2cca7016c1106b6724e2d2a7b1e000000000000000000000000000000000a2d86622d54542689b9ee01fa4b5c6a8c75712e4f32cb56ba61774110b8ab0bf8b66568a51f945cf2d986e4f7f5e8ed0000000000000000000000000000000008e4211618e1b8acb0e9a48ee5723a745317a24a9ae966fc8a0d0899fd701d59843064c4d0fde980565150534e1fdc3d0000000000000000000000000000000015b1e209d57954ac5a2bf6bb256746bd9c3856378a8dcf2ada78c4b3c2ad21eca26ec1b55896f3b1e4f3385c2f3a9c111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a1cbaf9a335c5c4691117ace37384774d53788132b304eced94f31cc9e4a7a05c5e5fc716c7f065cd13f320b2f65c2000000000000000000000000000000001580904030bca5974f21c485d2418585162fe86b33e74206f95da76f1b3566ab5bbbf15710be0a39ad02f4ecf75766d700000000000000000000000000000000120d1b3931d547aebf3a709151a153f07528dd4f0f3a59719836b8de2322ec5fd8a12a0b38e39febecc06d60efb50948000000000000000000000000000000000401c148d0782abb859cb4c87533252b91d481f396d313bb7318c536052a2ecbba9e067473d85d7c29aca75e6e30a5dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001916d97a329bf5754a28c085af6a3a3b1bfcda48446a1654238a584311b726c097092b38f0c3bf97bc94ea278c5058fe000000000000000000000000000000000b9121ac96f6a4b0b2172b4c43a9aa5a69fd483e670a205c093f498447eb898266700952eaa7b6bd3f4ed7e295d078b000000000000000000000000000000000143de548429a6215331bf5345c460a6aac7cd9b0c05035dbc15453b13477509a03f6ce9883a6ccc72546a51435661eb3000000000000000000000000000000000dac265a7b14fd7114492c89fc525b66ff2bbdb232f1eb0608b6d1406f48db9738accb1dba02f5a7457e0a4e678e2b271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000299097df0f7f5394805b7962cf39bc30443fdd85b73d9b38048b6309c9d893cfa4edd94120b2b1b801fe538216dae2d00000000000000000000000000000000162bb0f2bcb5f2fa14f807e38f0d023ceb2e8dd6617d190a9e7fa9185d48b4beef29631d0a66860d7a68b7416be9129e00000000000000000000000000000000110edb24a268e01ddfc79abbbec24c646ee7b3d93383a75b837688fae579f91e0a7f3c5a0b7855716661347522e35b47000000000000000000000000000000000f5bd5692e6ceb572903fc47f8f4e01d43a2e6c72694fe7ced711900d4b00c6b603d4e49e3ae4e097f18b17d5f2c2ccf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006e0453cc3a3c2274346b95bec30934312281306b99c3c054c20513fe31145cb4a5fe04661f2f5063da3bbe53f20894a0000000000000000000000000000000011fa917fe95f6ed0f912cf7aa46e91d7e901b03eaae42657244884ee96b847a0ace2fca43e9c2a3eb418f3292263133600000000000000000000000000000000186430abd0f849cabd821ca1a83a04c88a46795083de8b0ab75919e3f1efce1cbfd118a94c6213f2edc8237c94873632000000000000000000000000000000001541519d0ad580e1fe6375329e9843cfe3fc817833703bcc6ba53061e74e82db9900fa804b1e15ce51f6feb8de08b6c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033be273332f11dc925e221f92168cc4b162d9bd747e3f095036c81700f351f2c6575dfa742ab377ce2759e5c03cb63900000000000000000000000000000000133d4e54c040e7d406b92faa417e71d5867c77d1b0cbb802db3347cde0fb3558c212a843d40165ecbcec55c6a7d1c921000000000000000000000000000000000a045587b79d2b10ff8a1575abf2b0ecba81c9cee72c1ab2025ceaceecb178f47fb9da1d0c432a1bbbdcab7fe46f1fb000000000000000000000000000000000103b644cb11bf19a27a63dda30ad7b069450cc4afbfd8f42df201ce8e729208e286ce6bdfb89bc554e88f0261a5429c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157c33f53db31a060394a04e78a9242531fcf91d3a1a4a24052e873852f717f5e7cb318bd7485601d9a7829eb286f53e000000000000000000000000000000000a9dfb8956e78bb62a88b875a0503371423357b6dbe0754dc7273f2cbcf1500d48d3a2bb907cee8fc9cb05fbb5a230380000000000000000000000000000000018540ab1d16898717b59da2ae57a9627de25fcf3f31ba83ff8a110b3730331381d6515fef1d65022426fd36c35f782e50000000000000000000000000000000006bd1a503c954d9077dc4ac06bb902c141ce8d0f22788abef3d3b57420ab7b42080f7b9509ea66f374040244ffd720e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca5fa07f71e73d0f095f1c540fe4eacf6e3ebc84d0db37499919116255ec32bf7a8e0a68cb238be5b1b216376f35f1c000000000000000000000000000000000612c43fa29e8fb2c0804ef51dfc1263ccc22eeb92dc5dc89a25a96e22cf53aa1cacc66f9900c262115b95473b25883100000000000000000000000000000000030393cf4eb09d96962967e9a79b7cbd2ed077c14001360660e15f9ce2cf8f154acbbed3407dd8fb3216c9b650d1a3df000000000000000000000000000000000ce692802c6894c9c60cdfa1dbe617feee9ecbf65113393295be0fbcfb3ed43e329ad9cff3a87a07621f6b332f02f1431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003491599c9ea078d9627a85da1834b998d10cd06cd57770f5f05aa94dd6c3acf83bfbb4c1d9836bfa87d52d6285fe82600000000000000000000000000000000069a131c4804188c4abd6490a9e8986c4e27c639503307c8e145c15735903990a5a91caa362c5b3d75302b056df633650000000000000000000000000000000006ecac0df7694c696a1550b32eedffca51a344fca10a1a44776f56f43c940199e1680ed3beca99a004e12ce3ad64faac000000000000000000000000000000000d54e73285c45809d11ba8fe29ba21130cd12fc953e22aa91e5b0737c935b784039e54117ae436b086d15f286b0efe661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b583b6ce4ad20c73fc91cf45f0f7cabfa8a06e432bb98d2f05ebf7a0304f61f700512194683a1e939ca13a34faea94a00000000000000000000000000000000181aee787d82adf8f06a2a42b64a8ab5a1782ebfa41ba3128f65ae1363511cca79885a79f3ac428cbf77c62f330543d30000000000000000000000000000000001f50d9987c373eb4399f2ed68fedab85d582076bd268747076abe57217ee5fd74f719e1bd7ee5bc3b1d76cffb3e709c0000000000000000000000000000000012a72bb9fe4f2bb9159180b17e59ab44f94b079a675c6c493acde3c2ed97bee2c5f6af312e9a84ce21b2ca67cbbe1ffb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006d920f35201837f2b70e8b26e5a86ffddeac1a386a118b71087f67f4a0a15c4f4c7d1fd5c136b91e572d318d734ef56000000000000000000000000000000000622ae91637a0316872f7b73b635c99fe87d43783aee14f617d96fa7e777fc4f4f1bbaeff9100779da2b2fbe2ec1118e00000000000000000000000000000000113c43164531b3dcd92365a7e4cd32eb8fc9809828a92f13214bf9532c8f01d57388d66abdd1d2291205026047a594ef000000000000000000000000000000000a2ddf1fe4557279c105aa397e126ff745dbe765b8607b8ed247d5a04d99cd714d345bcd54fdc025b34634a872eb76501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016453bc748429529d164dc126ff61ffa34665e8792d9abd3aa005eb505308bc10cecdd60253a289e88fc9dfa114af5f10000000000000000000000000000000012432249118862887de4b386d14e7ebf88e6dbb46c9cdf350ac8711bb3517a255b3c376e4c577b322519e24dc53541b700000000000000000000000000000000161ca3cc5946a54a08b3d2ffabd0d9d25e144fcfd043da5981aa105b993b254d52dcf646432d7fcb4da491f4a47f16be0000000000000000000000000000000006af4e6098ad590f4bf4e9cee74a0e24be6c8fdd60cf98fb7aad3fb244245062b40a67a63074c8780669badaf9b85c391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019cae2561e04ea32b7bd0bb6a74814b06a33ba057d0f4a5b35f235d6c882ee8f640cde2682212d9eedb920dea3c89e2500000000000000000000000000000000083c2ac5f1aa3a62c5a6b0e5fb93b8c16b9565bfd86bb4882f33af7a1e6cb13b0474869dade71c2ea709a4df945d79500000000000000000000000000000000014239e6f5c7521819b4769b9c81305ff22db4f8da8275ad48eb4ad15a07bd9e85457f869f3cdba7791bbfaf6c0e95c2c0000000000000000000000000000000007399ccd6ee2cc6a70a10ecb9b2cfeb089d169c54086fc233b812a8bea34ed2dfcfb59e58a9a132f396520305dd1e62a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008abf98161a1cd76726e248e77549386fdf2e314ee41299b8de9337e5f05c4590ce2420ba754b1aa16a06a17ed13749b00000000000000000000000000000000103ee9f075d71c115e05f7f6e5c5e06ea775534c6fa6a89a6c96c55aed1894921136ddb5f875d680c387e3453ebebc5100000000000000000000000000000000085aaeb0138668b1b965045a41d27319cd67830e47adc0038d7f6d82cfb0a2521c68fcbbbc14d4b2c5254e0a12c747010000000000000000000000000000000014526c7ec33f836a07a761a4da78d2ce89d9f54402be767ee34caf6a3e7be713e30e84931383032987dd91124a26b62a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df8bc66cecc433f08031449139eb77d5d6067ebc927f2cb58dc793fc41c42e4971a7c57789ea282a3369489ca27cf990000000000000000000000000000000010e469d4e2fd2e0dfe4760dafa4c6f2d9eb4db9932175e9e3fdc4707c7fc085b020b8ae115462390d42a94b2dea48c4100000000000000000000000000000000061cc5a890e12bfe57c500670f42740e21080145d81672c3f2f13a90f8e0e9abc4d585204df6919b25bff9a57624e4d50000000000000000000000000000000012e7db8f5f679fe08fdaad3124625896a592fabf2e7269584754e9e9e8494fc071eea025489ffa92efad38e4ad70ec601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000105545e59c4f35137d3b1b498a04b5ac54aec5a938527708a9925ab458ec1901636be021c29ca65daf3d703a84b2e00d0000000000000000000000000000000018a9280c169ea4483efafcb4052ec0c2f48ec2cbbeadd2714bba1e501033b77a579348a85be164d20538f1a478f32331000000000000000000000000000000000bbfeaceb179f3bd1c527549bd9f800c96c7938377ef7f95e5c3e02cc1a466a055c1d5debc75b4ff5060022f5ad4b5d100000000000000000000000000000000163f7822aff84027284112bc38a79f5e5f03f9944152255820165a8dd03575001a00471bf43710173460d3610fccfd361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5be8e013b443c2437af0dafa8f1e90d59ed8ada6f960acbf9077c549cbf4a01e2ccd500011c12c3116b91c8eb4420a00000000000000000000000000000000156a5199187951ae35717401b27daad21b0308f0c689e179fcdc933447d6810d4176774b2f4635c18608d1926521a28700000000000000000000000000000000165301703b4424392724e84579b74a97a7d0151c30bc0a03dd4542ce2e8761c74b329499bb80ad874fd9a2bfddd49a3700000000000000000000000000000000133d7108bf9023949952a328c17d70333ff10bb2fc3058ae1a2f8b53c28763a7973ca37b424081a81a4fd70ea5d604151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa91553438f837a96a1fce86fffad1741a68d65b74f98ef5e9a5ff50bfd1287955e52432c45d5a4d961dafecc9542430000000000000000000000000000000018abfbca49ddb0a759277951edf0ff40f9a7f4d92920afbd2f3aa091ed040bbe2bd875b125281c7f07b00a4593a949da0000000000000000000000000000000018400adf07e8464e6f82bdd636a911ced7598e4da6a5a6be191e980d85955c5b9313aefbe1e5819f562020b5ce32246c000000000000000000000000000000000933bee32d06a70ac1d22f217255d4f9170bd31e3f00112ff7a32a975c320eeb15f9a93584f2e2118fa17a4bd91c78831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000061ea682ffd6209a854551f6ff2efecfca4326fc3100f1b906b584b6981cc34e1058983977213bc9c0065b7ecd1dcfb800000000000000000000000000000000134c05bbbe8ab83ae6983a380a13797aeee052cd10e04f629e5a01f3a151d12fb2e1a389fa2d54c246826f0a1ee4f80500000000000000000000000000000000190aa651cb1ce8d82b1bf1ba00a205da45092b83af683bb35add75baafae08124bd1516d2724094c76036597a55fb7ae000000000000000000000000000000001090e6f35febf7a783b0e4b2e2d20c9816224c940face656bef7843bcf320645ce34feae80a304f59b24ff2da4c2328f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f27f9bb136520ac0fc5ed0e1bfc83f312aa104c522e37dcbcb6b81d04018ca2dc8eb14bd881efd364041c76371c89100000000000000000000000000000000073e18b49f09627f4554c34f898cdbdd1f81eb405caf976be272e40fa79d90a0a69aed387ec1839168083de1923aac4c00000000000000000000000000000000095e2b74256fb640dcc076f3a68cfaadea7b44c5b456c4d1ba8fc8fb755a7de91f9ca99de8736eb3866f3edf1bcf898200000000000000000000000000000000065ef29196b54b6f74a6545c3b047b91e22f64b209bf7c147dbd42f54c24a4cd8d20b8e4340a48d52f6201758380cab41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052225f888d217b3f68f22f1f414967fc8a7f2b2a064055f4be39fc8f0ae36700d12afaf603d7861574315ce9ff6c8fc00000000000000000000000000000000154e32034d449891209a6e07e00f283ff04754d529010586b4395cf0c7a05e62f2d61156b5ce2549ad5068f4cbbac283000000000000000000000000000000001517ba9fbd9d0e821265e881bd11313519f9613a92cd631c6ce501e2a369109b22b2e0fe263d918e3e244f6cefc552ac0000000000000000000000000000000016b7e2e729dbe5947b5ee9153e36a5aa1cba17fd98f4c396eb84af40d95a0076851b1e7484352f4eb9a50c5339393c6d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f5c93830b642d8701552dd48a1cd044d50ec327ba49ce86bd9a3a877051317727977bf713144b213097200cd2eb4310000000000000000000000000000000003c801800afb875de3c7c69a8a62f0da133bd80f7e77f68da71d4a0a5957604e8d9b56b8927d0450f6fb2c905f148d100000000000000000000000000000000002be299a0e4a96404b1d94a1ce7995fe70abfd9fb76f3d2e7e5291aacba20b3a158f6d6470ff34b530608fa019fbf0cc0000000000000000000000000000000009d6a0413987fd5653c47ea7d9a1b64057be59d53d3bb6f1ce9503f48a1fe3eefdce66827d48448ebac82be98b9977831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f89863343d5ab6e340b03300eb3d951d75e88b2f10ed0f5ad3f2ce7c428c8f241fe8dad65db1f8621d16148fcefdac00000000000000000000000000000000006efbd2522170d2da1b5f3ce1757cb0ca29f1d349360e62491f54230642247d9ed8b17f87574e36548d8dc7f8e90ed00000000000000000000000000000000007c163c12031f68ea603cac1c47248315a4bf888feee92ba6c69a09011789ec4985a62cf7cc0dabe582a1c4b1ae495830000000000000000000000000000000018b548add8363e0b6a99c6d40f08dacbc7d9e58b56699f0554faff1463669dc8660aa839fb5c2cb370f493bad6a31a791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003ea1a249d41c107e8fc99c89cf1143da37b5d10c1ecd141f229dd4d0a4ec5a729fa72238c62480d9181790a73a12f1d0000000000000000000000000000000007e07fb727b8fa251c89ef8745391edbb78e867e1b304604943d832935a0803bf4e8c5120d012c986896b9d988974339000000000000000000000000000000000bd5b78773fd33062680d742dd3c92b541c41825075d88801fe91c67d392940abb6638bc045e59fc2f8c221602abb77000000000000000000000000000000000019f99fab2fb70b9924706fe5a4e44417d2debaad7d41cf3954e8392f75ebf4193c8db18a5a6e0cd492ec2a6f68354a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018e8d229c6b22bbf787574ad39c87428ef40eea49fefda1eaa308140e03c310ce265ce7a138ac2f0343e9586ab88f5890000000000000000000000000000000003e8131900adefbbd7ac0b3749e1af4fa7654cbdb7caa737c402e99a74804bad0e1adc3ef8da76ee7a10e8045b8a51290000000000000000000000000000000015298dec35e7e652f808f7b5990f5fa3eb75a6a510109114403adcf698eabc590ae21dafad25fadb2617e03f513153240000000000000000000000000000000005d10ee7585acefde50d07662d79253e2179b9a1b1dadf41c1ca9b07415f0c08726c23762710d4af7e96d5afb34b48fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1e56f0f184a3436d5afd00aca3ab1df438843ac4f4be54489e629e3964a762466d0af711b0f7face917f90d5a93daf000000000000000000000000000000001144b021ab8e8048618bbb3eb17769de37203bc0e068e147319ab49e886d8f97e1bde16c62dedae35c1d46dd138e81b300000000000000000000000000000000191ee9b0e77313b177f5d00bbb9b265804f43441f0ab60f217c777771e3cafeac32abab451651bd68654d459e113712a0000000000000000000000000000000011996b92caf8eeca74ce7d347937f158748d7e556565fe8117c311d94b97c5b71cac6e20340cf10a2e19f9d26971774d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2fd4d20fa2bbe8a36f07b2e1896b783c071f0a16d52a6b6eb065b36ded6a7a7fef512d3a47d7bea4c092451b87ee98000000000000000000000000000000000a5e8d7bf84f4ba86b6fefd500f7587b7e500bfe693d600487755cbc0632d2d1b8ce418758433c53fbecd0167e5c62ed00000000000000000000000000000000017a5b73b813e94f5e6458b9d9bfcf758671d9af84a326951017c6c1f9a419c43fedeb79bd1e52ba01509a3ddb087c5a0000000000000000000000000000000011f5aa33bbbb2c2825fc78133fa5758e73e1f7dadcae362730f25d1c85b68908aeb715603638e8831c181ca0e96dd02f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000abaf7a405f23cef690f52229ec51bc8c3a0ffab97167fa969a4d909549818d402a8f53fb304547a051fc3c7961c4c9d0000000000000000000000000000000015f2af9ff22ad3f23372184f7aebf644a0f0e8fe85bf850536f070dae1bc1d0dc2219b1d1279bf83e15d7843d1947fde0000000000000000000000000000000004d1ec46c5defab4a25f3d27af2d004fe5a7c2ae693d8e0892251d456f49c395c58d0f94c489402e5d2b99f8c9993326000000000000000000000000000000000e20f5646fc059fef433364fb948d84ceab0cd36b07ce397aa35ba71184618435b955fe3697a5937db471a5e01729fcc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066ddbd4924b9304fc5e3649e5330220d824f9c9409d0f61190e47751616f4639d796cc1e51941e997ac8f0967cdd9060000000000000000000000000000000008f41bcee28dac19eb10feb91ee7a2b7c4f69e0e846c7fa0d74c8a193cd09e34fae0b21b7023a278cc2d13b06b16dc2c0000000000000000000000000000000013e966abe538a8f5fd03515608ff7a6fe78b0011090c8e68051aa6ed6bdf963a87aff3e6ca46a6d53eee6914b9a60a2e0000000000000000000000000000000013f92a8759497c5b6aac811bec7473fb5b884c14598d6a9e192db7843da569871aa7d299d749c58d2c983470870512761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000033ee9277c9ca0aa5167fd2e0c5c31e035d639d5fcfee18e5511b5db577afb779655e1d5f50d61be281c914346ace674000000000000000000000000000000000d870f7bdffbdeb9c2fc1a457b82fb7df5c8cb04f0a3b97bf90aa451fd36df72f562197dc70e2b89d1c69649cd448d7d0000000000000000000000000000000000735c5eeeafc240dc2cb0adcee2eea2788264459d04d26b850f3acf33ff917246a0d2457e331f4a21d34d97875346400000000000000000000000000000000009d54785de42f34da35f3dd35d9bf7edfb8311a97a190d86ddfca28fcd55b06dd4e93d11ea9496c09621d596dbeab6231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000817029a26cf1106a8f7634563183e1e9b76475dfad7732f8c213f151a1272c47643f3c90de4fc887b91274a3386e2f0000000000000000000000000000000000cc140b5daaf20f2ef7d7a1f978f6ce4b1bc044fda9305873663e3da26453d15332de153ddcd5fee3371a6ab01acd9e2000000000000000000000000000000000cba31d153a5cecebcebba7283a565fe17ee8c0e13d89894e53038e7274353cfde1175ef5fffd5d8d5724094fb7e9370000000000000000000000000000000000e069d4cb4914bc268f5146306d0cac6fec65e97f0c9eee89d41e3485512ca715b2bc6145a13ee40169afeba22cc0d601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c59b7969ef96dbd086d1bfeea835faea99e34a2c80027a3c9944cbbf224807f2a5c72556df07cbfed55442571da7670000000000000000000000000000000010060fc940296ce66c3f0d21f5ae9a91e63a04cb6f50a94a3138bd3a2b3043d33d25035be8946c749db6612938930b41000000000000000000000000000000000e53b5b7ef78be9d98af99b9640ffd6198add5c553d8e3e236246b7cd635146346a69330514292ea18ff63e9b011d3960000000000000000000000000000000015ab50891d6a829aee6b05ff8354eaa9bde44f2937b7ec7a12943b590dfa878c3b02b8a9d3ecba0f9368212af6e2702a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004cb61ef4aa507107bc52c10dcc2f7e2002ed9ffa343a5814fd650d1be3e99474240c67661a6b8b02ea5ac93bec43f30000000000000000000000000000000010f1c31fce5228aefa8280585a550f129ff6af0d58e16041df670129191ceecd45b6ce772488fde181b38444697616010000000000000000000000000000000013e1254096067c28818e382addcc5e33d640b5ff8403ed4692f0493e9977a99faa5e5306accac2ce5cbdbea6804591220000000000000000000000000000000008698cb3edb1b4642c27f90de94751e6c7d83056abdf9fa4d9b8b682b645e76681df65ca8e4d46b04d3bbbec3bccf56a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001030489d08394cb93ce847531d64ac4e3b2dfe328691b7c891afe03270e08efaebe2559b51a2e4e06dba305c1f0fc738000000000000000000000000000000001863b4f06b4657c127b5e3d40403805e4376a8faa4052bdf84aff60423e92e85aaf3e0fbecac3a92c1799e0b5575b6b200000000000000000000000000000000097d5c89dd182c35b5bfab1ab68e35dafd1bc5a24b0b030100af01025fbd5c23538cf5b26c79aed7dd525f9707bef5660000000000000000000000000000000009639ede2635a34430b3f246d8bc141b2addd287923a2181885eb5adcab878a79a42012adefb804346b523ca3b4af1b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009dc0050a638e4306c2995f69423e417b2e6302f26883ce16e7a1180b4acf8e137128a60210ea3d8e23e3e601bde930f0000000000000000000000000000000011d00f7521201a19be2d684bc83fe2fa713706c70efae0152bdcadad1863266e61f9281c2e85328b11617883dd8a8f8600000000000000000000000000000000006cc1c9c2b041ad84c03a3ff9c71b5e146104daf09f48cca5746a40f9700aa8d917cf5d93d528f8fc5e09b0f1be804e0000000000000000000000000000000003e33c96fd850cc43160693892bf1d9bd88b01556573830c995b793d197b0b15cfa2beb5b584f1e49d2c43219efb4b4e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000161e421667b2036f465fe7d95ee7eb34fd87be64e6401c6b3d55e79579a9194f9b73ddb11034efa4c3c32b343ce197d500000000000000000000000000000000040893621ac3b6c204eaa7f12242b331f5377400473bd7ca2abdda4a4b246f3123b9fd2daee859df036c6fea1bd1aa0b0000000000000000000000000000000012d6ed6f54597c5833cbb439f76c30f36debe8a96438ab4192d430728eb773819f70d33f92076d0d9582f95107f63bea0000000000000000000000000000000001572cc131514f004343235ea96f6fb889f91f1d1105cbdf9785e04d4306ba66f41464b6c2e68b422a8029a1a78f06071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000118aad854fb455f167b3743d3e05dccd2b888ac6506fe5d95e60d3c148d48a9d71c6c04bc9c421b0ce65602da60c1b04000000000000000000000000000000001888bc5efb9322bfe8460dbf0800e3e8bd17c464562dde8098d845ae846e6db540880b67f764a6e523cd27f1f9be711a0000000000000000000000000000000009fa95cb1afe5cda866cd26694758b14ff9f04c0e0544c5adbaeb3fb37e6b3847b09a9eccb9cd8c2e90541da2b5d9ba70000000000000000000000000000000018935953ee935a9740ad860c9a7790f8cdd7333646fa55375880363bf29a443750a8efe8a38b0eda0a8b01acb6810c2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006ff65e2e6b09e59c2369cd50ba857592f7bd6615618d4f1199917c95cc2149f30e6bc4e556f8c9ddaa04869b3c2d1a000000000000000000000000000000000182db4c6aff99dd216912d2a9a811ac6e62f0d3973c82647cc06fbf8518d608d49cce6a5c728ea76d17e70a2dd400e61000000000000000000000000000000000afe3cf47b02038bab6c396ab289d0593a2f810c2ee1ba1085abcf9852fbd165ed4c73dd1dec4ac0c44dc3d325b28b7a0000000000000000000000000000000006b296a5ddb1c0d7c4981fc5f44b413cb8308641d3eacdba441187ded4c615326c8ea9d857aea4198c1a84244b2bb5661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130600009fccf0d7904cff657e81c09edb95cd125689e212cee2b897c7b1e642f68384ef15a69fb555ed1d2f3c4341c300000000000000000000000000000000086f7b892266417012c34faec3d88c195fee19ad01824a5c679f5b718e530fe17710a7de7e76d7b2f5f0676f34b3081400000000000000000000000000000000116305d1ef69aa90c2213c7f2f948597ddabeeee23f4a9fa43adf64d93a57f722c969137419b02242824c52cc2b4ae07000000000000000000000000000000000c40d66794e4c4cbefcd74e80f84e42e8da48aca0237cbcca5f2d53791c0c6e72938443d3bd57d57472b9fa49d1383ef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000083c35754c26e767c81831bf730504e2a8e0a0a0b2c7ad50b225b3417b1036838d6fe00c7c23b55be8443fa25ff658d9000000000000000000000000000000000ca0a53c1e59d35853edc03a5833c334f7aba68927195a28c41f062a3e352090be4464b469bf9990f55e4e4ceeef65bb0000000000000000000000000000000005f90d7d3fd01fc46015f86b9ad8e4599e6480158290a1a97898b806e3aee8e2325b508d92678e5e17617befe25f40d8000000000000000000000000000000000c393f193867d66ce261fdf09b13899b819b75a730b76c37bf2b1f4bab189c90444ac1914ca87d1e88ec915ef2d7c1e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008428d3e2e74f0d2db252711c2db2690f52cb51b0ec8522930ae68897e51bfd98430de04b859d95f102b0d07cefb43e900000000000000000000000000000000034857c479858dfb85910aff173a1a5917d262e019115b584e7f8d6ae724ea312360a2eb92359576e5109ca4a40fffeb0000000000000000000000000000000003a1f726ca7ff13ea5eee04a6348a961f6989dacca1764b0b33d2ba21009053c254338b05a92dd6561fbe8e74b55c068000000000000000000000000000000000db0dfaa9140f86c4239ae9463ada5b2ed9dfd0ecfb50cf0a2db9ad1c182f1e2301f0147ca63ffce726625204c2d8d651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141705e857d13900b2b38964448761dd1b4655c9d965ae37115264d55cd407204dc04080bde5f615011608e42bc6a2b40000000000000000000000000000000011aec51c26f824f19f177b7b1b087493605c84741ae6dd95ad31af91de8779dd3df22c9b76616d02fd9a5c7402f987d60000000000000000000000000000000001381eedf77bb6318ec3c5c365cc9febb18ee0938c4b2d98d955b30b8da9d523a262cd4b48cccafb3618e21e44a08bab0000000000000000000000000000000004a9fd82a0d0f29a7fb50da605e662e78bac8e2602c280ca750d09d885bda853c9030ea24eb4012cfd75fade752b80321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000066121bf4edc50efdfb406a2d07b3c70d30de060bfe1a0b5f87328b9694cc2324cfc00fb9e315d7999b15c0aed5a0230000000000000000000000000000000000739a21b57db8c020909659edd56703e2d9b2362f001083dec6f3674816cecdb45d390506c1c7874c050df5c339489d00000000000000000000000000000000112e33366e41e331f01abd7c8c758f86185ceabb0fe73f44dd5ffaed298a774e43aad2ab3a37410e6afb33c55e3379e900000000000000000000000000000000186a697a23fe7cdb81c94d9b62849ba14a9c9651bbdb4f9cdc912700bc77def60072448a42411d593c24f37b73a4bdba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198ab71d32c3e803712f3b9dda32e3a40f5443248657862aa362c80b40b2e5b0b9777ef5dd2be7736249efa50f363c5c0000000000000000000000000000000012b81ac62b7688c68ed3049b75634c9188de0111ed36fde33966fcad5c64960113f39be75096b40b5abf994ff3965026000000000000000000000000000000000099b0ba997b5d85b14cb9a9e84d5f5d4875eaef80816130557f542756c47454d762bb2e127399d841e1e8dcd1dd0a7200000000000000000000000000000000058f24391bdeacfd762fcf69b87c757de18ee586fbee7be9c2c16f7e7d04555ae4a0305eb7542cf467d4e1d9348afa761824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018a8baa8f353630e7acbf6e6de8f7e4c84c00ee7b3ddd6400b3dcbd02125c9452177b5a135852ea98156b68a1d239e08000000000000000000000000000000000ffb411e97e94f621cb467cfda0de928fa29a28d481b14eaf5d37afb6505665299c935a4a2a057103f17caf627345974000000000000000000000000000000000619a7823378645f5be1064d99c44c9af2f0e1ec855ac20e7b40feaa77e3b507578a0b850fb41fd089e01aad172a9ab50000000000000000000000000000000013fbdeaf830296e45aaa64f31d1470c2cf8ba843cd33c32df6f17bcb38eb50995c1606d69fc0ebb59e25ebe8b298a0fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015e73af91d7f28c3301387a3d2f653fb36b9288166b3cf814dfcc96625653ded1233de27acd4f0d32e56fc6bb1995b820000000000000000000000000000000018aa42d9453d8c1b20affcb76ad532dad412ba47998a8ebd2da4240995fba369a3ba8939e647ee151917884917f8f242000000000000000000000000000000001468624419912d192d7eef6cfdab1126f391bee55ade7f759f0cf47e78653b0dd875891ce694397c4b785d80495bea530000000000000000000000000000000016c652f8388a3297cb34509a80f54b5f3517123436596e90657fb44ee142d6fa9d1103df14594cb1bd942ddb73d3d1ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f1beedbc1ce681ffc6b56dbf29cbb95a2cd6305da295d9ca80937a0e5c4892ddbcca561c86884a5db2c7f33b0d544e000000000000000000000000000000000be20ba040103bf078690a0543a554728e972b01c970baaa884c17df674a067bba3e0a13098bc22b32eccda37706dd690000000000000000000000000000000018fc0656520989cc352273d046d6230fe8b22534210a2ca63fc2fdeee72f2c0b2f5ccee39452b37813bdcf3b729f74b10000000000000000000000000000000001df2338ff82a70e24f567a931eba8d2a27050e000b409aefb2305c68656356eefdcb0aaa2e4cfcff7c441b9393dcbfa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000097bbfbff47d4592595a6879edaab1053ff761449814fece45262699a33316a156cf70323720703fed6af04dd9bf4e0e000000000000000000000000000000000e46f5c5d14e009cb89270004d416923e19903837f84b77125cfddc248e1380da69c83cbdde894cf981dc4278df426b9000000000000000000000000000000000dbf70b7352a38e06478ec297d20def1fa1d888e225b0f73cca46dfce6c67dd321dbab00aa3567a3af00f5f171be72750000000000000000000000000000000014761fd503806ee5e525085006f0c46f039cc21e672782b30a401997dab6f0d2964b29741b47613d728363d1c710db491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ad709fd435bc4bad62400505f9e01acfba7acead4fffe78f44b2aa998b6f0a706cc0015d02a11a186170361b3a41c60000000000000000000000000000000010c9eb9e49c8151f0e976d5567d21c1d714fc27e549df12fe447be2d7bbaf396f5b018718cc176ff1ffb381212f9f0010000000000000000000000000000000003236caf1c2985e206ccc20e0656547e95721e2eaa9ec644d4ddd356edbb254bd9437f068c04b066ae55eb852b620ec10000000000000000000000000000000000f5c131bcfda82fb9ce68a935c3d4b4df045137d0cbc004912007facf36c341c15c3ccf5daaa8a26bcc81467f109e801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d2c6f593db751b9cef38abdb85ba9d35cfc06d8d703c7a05ea48864aac90239928bfa050059ea48cf388463c13d73500000000000000000000000000000000101dd3fe101b69063a94e2d029da625c7e7d2b3ac457b640919b9ce22c6897d3292cf12fe4650bd1a6ee354ebb22cf7c00000000000000000000000000000000138543ee48e66e39e0de15e16d01f9a36e879e4bf1f18b14d3edacc23d29f7a846ea761cc5dce2eb95a7c66af533294b0000000000000000000000000000000011dfbed076abc6eba808aa35e6591e3ceec4cc502eb0ea9b764883761b6a71542a505233b7fec4c58a5788b1db7b16661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000136e675a00d7327abb7fdae7e4bea10d08d1189404959f870ccfd46c686e0517886bcf6050e915beda1f81687c4afefd000000000000000000000000000000000bf15c5cefbac681b0aabbd772f0f0d0a7c81315f2441e92c838efc14020b3b423da37d2a20b9f1d5ee379c695ffe11600000000000000000000000000000000161bbaea6288e916b2e08ec7d288571b02c3155d855a177f3642dbf691c3afc3798b2094bd6426d7a9e0582fd93ad000000000000000000000000000000000000eb95d8a0bdf8de65b47aedab665c7f52741d86857e419ba2d13e89456593b675a12927326556979d0b96f58394692e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003668aae4a4ebe846f30d254b9b31132607f87bc3cbf4c65764226cb040d356049a095c0dfd8a647b349f94ed855e2d300000000000000000000000000000000124c558b61ad61841b8bb90f2c52ab047e863c403fb573de0741c06bdcaa95faf42a95db3fd050868808445927fa712e000000000000000000000000000000000c58036b9f85fd8cf4f06f712a4fbfc223ca3bc9665095ecdeb4b15636038986bd66ad16556be3f61cc59ac5445f10dc00000000000000000000000000000000152116318c9a71fcd0d2cfd59954abe0f5287ab6e72c1d79024f7111667769c67956487c1c3175128cfc39c8b9aa138e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018fb747b1ebbb8887c9810a92c29d4bdee0fdd92987b3455248e0d880bf38a82b1b5b4a08d908c2bac22d2f42a8eabbc000000000000000000000000000000000b2c71b0a24a57aa2babb047d4023c4650c75d61370988497d6a339d168fa6972777f21e3c6333c27e2759e2156610b2000000000000000000000000000000000502bc3acb91187fe1dc5eb4099b197acad6fb8855748ecfe9037a06e7f5ea5ee0a11cb90e1848ae826618734b3c14100000000000000000000000000000000002006721c959431a9cc1f0531c59f8cc0f6f765bcc84256e8b63d28584e9bc962c8fabbf6783a5bc11693767aa5fa86c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001344009f4da545c50bbe5d7a3491a74615f6610f717225860e7916699d847a2a49b4d40c4e4a789fb50b9b237840e00700000000000000000000000000000000156f08cbf940b03a82a3c939d184657a6672fbf72075c90273c0f1388abe0ca6f57ae03764d2e56880811143d5ce89150000000000000000000000000000000009e0a74a0866af8e2a4546a5f63f09d9eea8c2868298dbebb681ff19c3a07593cb9be0f5ff778b285167e4855b90ee9000000000000000000000000000000000147767e8094a9baa0b803bd6c65cbaf80be7750af063b507a51ab4d07befb03b8614b4b66b450e41bc2f8447ce20196e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165a03f5079da935d9890bc9ce1cf816ef7856793d6c7005cecd00e5b8190e8e87f50efae92fb5ddc1df570c4888fa79000000000000000000000000000000000b0dc849744767da681793dea031e37436bfe8a6ffc5fed2041c01d60353b8fa92080f007dc527cee59a9cba38dfac400000000000000000000000000000000018218715143377b8ad8cb93644ea665214e183113e51b0365029815ed89a360ff629f47d36ac99a51b7a188800ffb8860000000000000000000000000000000007e9869b2cba574f0fc71ddfe6b571a087f225da7b0d6c9bd7eae45d982ceab242e04e8c29d4fd3ef7a408f64ede73b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004f1b094e46cce2b3d4e73782305e84366a58a96a0692b03cdccbc21f7ba2ea8f5aa3d0aa60a8b2fd304d4f78bb73f69000000000000000000000000000000000beab4bc37813cdd7ea18e2f13dbf43f44f39fb67f5323283f8add7e102c704cbc7bfb6da2f75b8fc0aa5dc5ebbd0cb8000000000000000000000000000000001795353decea43a6196c8edbe9b56e403a67ab926ef758dc696cd1d4804513e5018ef267d3667662c1e1b8dea3ba06cf000000000000000000000000000000000757a38fa8c04040cf35ed700b14db05fe39b7e4cbdda902cf96cabbbd28774a4b6c330c1f7f4caae77c2f32b3aaa7d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000192afb9b6c2b8664038bee39a02411ba628db0177aead44a391adff4c4094c347548c300a5007792898be3c4bcd71a66000000000000000000000000000000000ff6189b269cdf73695607bcdab9d803701061aaea09271aaa8a95935dec7260465af7d795428cbe0769d78677cee3340000000000000000000000000000000019941ba431158354eb60360ae3818fb0c20d31b28bc3c5453f70673c8eceac4334d6bd89338e5925fb4351cbb8dee4070000000000000000000000000000000001d674da7c56b02b9eeca85497d5f92f9c35d353e88892f495e7c63ae711eaf8ee356033179ed19c5899e7a705ce65591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000472bdab72d4b529e9339857437078b362eb85ff345101ab98a60bb1abab672b9ab5b6399f13531f24f0d54f6d498db90000000000000000000000000000000017b7d6a7ebbd712ce804ed176e1e9dfa54e1dae7721b55b6b940827bcbd9918ca50f75c3b51dda8f0bb5b31b2321fa0d000000000000000000000000000000000713554582bc9a2f241082343b3b5f26d95976dea80fca76161dabfbf6a9595cd30ed946db46ceb1857cc33505e719aa000000000000000000000000000000000df0897acc9cff0806e795cb72a6f1b46771a913f7d4fe5a036f2c1041efa1f9de38c0b73fab38714fafe8443e79339d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f135d1b78400549463382d47e1a417e53e29f9c3d898a945f75628fc38160278139164191301bdbe6843ffc591cf520000000000000000000000000000000000008304493477102e0de7610d01ab7a8f2ce3c3e22dd72dcce3843c324dd71ca106a95ace5162f98009574ef8c61490400000000000000000000000000000000167a8f51050d0cec79ad0d576e5a233f8547b85fa30e0fcd6a3bce4f5b7bfd6186491424a8e17f0925e20f589ac0ac1d0000000000000000000000000000000010af43b4e75be6d2fe80c9253a526ec90e47d9035022e084f9065668c2b0f2755808b6870fe40db63fcb1ed576b22ea31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000112ee57f536e59371031c9bdb6f704f058cbf9a776c2aa83bda842794f9f75057456e17b54652781407753b734cfc2eb000000000000000000000000000000000f83454f319542ed9e70a38eb39dd4fdf80409ab005386c20807a9dc0ae1d71afcaa9705fba631dfff22c90ae550d58a00000000000000000000000000000000184797bfa9adca051f09d233de5a642809b0d5ba61c43d679b99d4c791ebbfdd03d0b3836e4a070fc510229afcc8ea2c00000000000000000000000000000000014a7b8cf630f70ebd3c78507a5aedcba397cf6b25a43007cf6bffce4e2eef38cddf11f6f0e33e4831b406d21a3d05321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004b0b4409ffa83ba08277b02ee02e5495c16a5cd2baa4ec73392d3a3e79790b37d504f7aa2c27d409a2b32666a333706000000000000000000000000000000000a1c708f8968508e1eba0cb0b0cb8fbccb4fad0e3ef8bd25c5d2ba176ae455adedae06b0aeccd65bfcc50652446c2c460000000000000000000000000000000004ecb77bd0a209afd80d50b4404979a08266dd94d4562f1a7f91a09b8c25417b5b256f4048dc66d511316819e72db7e100000000000000000000000000000000142297ad4ccc7a1ed6b8d5baa3c565cb1b3e9c367181f6771d78156739f996bce6d5b1881569503dc60568c4f9ee06431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b3a24d6da9473513b83b64c967e9774b70c12d74497582e3f611be88e610e779feccbb69e2213dea2d08587da8a51100000000000000000000000000000000064401dad14899a0ae1410c728cf8631e18ddde99c18b3a0d93a556f679c48fe9f5c37ea70699d9cf8b6d5ea2f696cc800000000000000000000000000000000027b84f45827817ec903fc12e22d105a613e3b95f2221004a06d403ec4d0213951ccfa0859626965cd0b941101b7eeb8000000000000000000000000000000000d1934071870f6c33a6c1713bde7940f93d230fda6fe24af8b8ba080a49c4b2e3799caf8daf7416eb7469cb1454ff8111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b794e15ed55ab8bfde1d9f818cb23455ea22175fa1d91c90f30d57e2b2b72179d308cd37d04b4260038eee439579be500000000000000000000000000000000030218d9b27ff96eb37273775627ce5a267b2e691e978de829717ee7f7ad7ed1d39a24ab95277a7e1f767ebbc9643d13000000000000000000000000000000000d3dcbbb9afeca28465fc10b55bdd611ebb60dd6bdf98530268104e19468ad6f100f56e0473b4029c1b02a2bc6c8baec000000000000000000000000000000000addb637202cda397d7a1b8a989164a382134d4e11c6060881673a1658ad4c35a2f6e815fa361802a15d74fd65ebce061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122d13878822673f38b870c92b65f553a48b6a270be88280f391f44e117c1318f8c74fa6ada11a6b402fdd5d9aeb19e9000000000000000000000000000000000b9cc97ba5ef2d496a4a4a3251965aad39c15b98c8e44670163d40455c79df9e6fd6a2866424e720a3a76b0f005c78e00000000000000000000000000000000013a979abd9a12faed427d96004a4bb6b9f35c4413dd27d57a9434c99aab2f1ccd73579db31ccfb19ae93de7aa703f2ea0000000000000000000000000000000012b25025dc6597acb26b3c58f03a686bb46b8edf041cd6f5b3212cdc6c6f40363cf697af9f2183ccc6df1eac612e99fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001376e515e9c1ba13c091677194b5a24885061815fb10671cf5ad758c176586d16e707aa5107739312e54b69209dce36f00000000000000000000000000000000098fca25cbab13830f919053999e51e6dcd03231637f7ad2fa6352ab5672a7154983fce44f3c6550e62b41ce04ed223100000000000000000000000000000000074f435ef3bd15b9983860d94778028f1e8751e9905d63fe0710ef4fa54fe73274da25b3b5e6296b5742c877b4a5e5750000000000000000000000000000000005c3c1d908cc098b790a7c1d912bbea6869214ec64efbc5fc636de7d348717c2d9c63f04a5d45783b0e0d0b568ca848a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dec626101cb8d4c202e616c467a2909eda7b672c256fe7bd381b0d7ef3c6d9d618839d64ada04c11ed597c98c606b8f00000000000000000000000000000000030fe1fa71f97677e8929a1b6e5f171799100a8a6cdf1b08f4a9b9eb6ca47d46fd0a81db87deb74dda4ab97b6f305837000000000000000000000000000000000e2267760601c8b13846b61bb6264b43464460accc55485d748b4c0fe4c55ed8009197caf63397e4693d2c2b700b21b90000000000000000000000000000000007f46397aaa640f3b8a330c14547d9d0f0a6fb7403ac61fd0c746f2bc7fa2d023aad0dc03efac6d03716a384c7d0813d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012507f86b86cdab8bac48a872a201cd676c626da17e09fd6ef821609b7bad4877edb445a34e9f11161eb4e4f5771f72c000000000000000000000000000000000712cda4c7ea7f9a5c99d83671fee577c825c7d62e7672f4082842a8b0d04351aa3277fed610fd268cba12e4c06c1aef00000000000000000000000000000000103bc815706d9818daea0a01bb53829921efe16c0bed27a10ecb74bb40b4e01ddccea5b7c0419d6ab241c4de6aea09200000000000000000000000000000000008a1c10128ad7f895e1b0a7307bf3f0a491391be183c93be57011003746320ef547c3b5a4f44d0bfe320a37b60f026111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce4fe24aa2659152f311f4c1c877ba637a296da340a1e7a40a85cdffedfeb5ba3deb897a864dfca0a8d785650e3ae6e0000000000000000000000000000000012f3df9a2e9b7643a1d12ea2595efdb907b3b1308cac8aeee16c93e622512f37e58bfcb2fa03dafb73dce7137651895c0000000000000000000000000000000017f71159ad4785d2fafd9d17353a1e9ccf31c602c450dca8109d9d59e9ea8a6a754d6abe8f910b617a9ecc14e78bc1ce0000000000000000000000000000000006f20b68262a34735723b57e3df1755b85f39b186370151ade08b6e24ff43bb6e97d24eee2ddd957027f5b257a3b7f5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001549625a9dcd55b3189e6cb1e18031caba3a06382c10cef2ce9c21f6d1762933567477eb6c4eb2dabe0331916d0fe8c300000000000000000000000000000000112db81c221c95e6ab7ef9d6b125b253a8f17f6b5c7cc36df114e1dd0f1218d6c5d6bac9442d03a9c03535be0c2e3b44000000000000000000000000000000001314074c055f79ae0c5da8245aecd133bceb4e718dd25770f2aad68c55a48c5114469b290834890fd5813879d51f5fa500000000000000000000000000000000005f239211fc88218ecd7189df2af108288047edc6555d610b710ec809564de02eecc19cbc43302df3aa973ed01da5fc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000042d368752875de851ff461366661ebaa61b56f8a367cec34b3b4bf2c1c9b13445e2260ff1c1eea3c8b4b50fb971aa140000000000000000000000000000000019773c9aeb32fa93387e4eee945dafb76a0a4619a86ba9a3c6e918769a941b03b23ca58d3c675e95751d20a407d208230000000000000000000000000000000014b79e7818c49bdce31ec0204d82723196bbea81b7b3e2f4bb92fe6e6a79da6cae910e6d909fc0961a6928b9051eefbb000000000000000000000000000000000f870981d1cf2151fcc3b870f3df969a801bf641da0cdff58905e387ddeb3279b90834ca0a890268cdf9d575b98b1c4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011f8a8e6919574aac5b3d568abb72a2112b058193c10ffd19117323062213f167db231563001400e889896628e2d7b7e000000000000000000000000000000001169392e2f93d071c831b7cf78bbc82e4a05f7b6e733c22329d06c4aba0769201d2e5378e009e966daf19151a9c9742900000000000000000000000000000000140092b33b73472b7a7f8e9617ab1439351152f78604300dcb8ebdc189bca5dcd6d7b244ece13a2c2af24a1647102c9b0000000000000000000000000000000008676cfe15a0007e6fbcc1d7d900f845747bc93a431fc895bbe23abb5076587f369253938c8348111abf6583ed9113ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000198257ee0350232280aa5ff2c095a37faf2ce79bffdfa4cb505c6a522270c3b64d8d7970fe15137d0471f0e281a41de7000000000000000000000000000000000825553090d142c190260a92f972bfe37fe97738eb1bf49969fc947a47a15280d92e5d759fe96feca7990332155e31a80000000000000000000000000000000014470e046b7b29224379c653c0df643b947fffdb4079aefffcd88af2fda33679a9f82e28a897e19bf238cce98832d41900000000000000000000000000000000110073b9bb1050c745e42d92b10b861a9fcdbd2a9f171331f809b8c94163fce7626770245cbf859f038154d3f7b013b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000129a7c7dad0d394ade01926400c666e43f7c01df96c0ee01d1fc66877879565df4482c30f8495d58cf79c8f07ba7e5c000000000000000000000000000000000856c0804822d2336dfc3b8794f33ab11b2bcf45304be69f6abe7afa2e1184099bb27ca50e8ff5d2c6957881249c63640000000000000000000000000000000012783070ea327422376d199ddf5372a8e4ea40f8f1a2968e6ce738565fcdc258588ecbe8407ecea96c626fa5e2e070d500000000000000000000000000000000130e611e35810d447242b8da283e0e4de797d59d7dc6dfe9da6184ce0424c396a51717502b3cf05588ce1cc59e3d70a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ad9dea076235b8ac5be5612004fb2e549ca3003e95a8b5937d3a470c79c21d413568e1096769d445005fbe0d896399000000000000000000000000000000001033cf820bb8ef77630e4e300b563dd1a198b17ff974ce4758362d4911b6f9a5199bf50b3897dbd6b000501cc58909bd0000000000000000000000000000000003bbff8c98ed3f1e5a7f282f4b223cfca702fa9e263c9c88af307ced2877f27c420531858a9c92c96f17c65f27ea8f3d0000000000000000000000000000000007010ada05d1837b57869d68c83353bda1d4b32cf4bf75b18694d05a323ae9576ad93108bf6e37be89e2b247bdfd7a5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b544326c5d44231bdf5940063e34ab14116801ff92593fff409cd1bc3b8310a3ecf008c038f9b8e1e94e9df5dfb05a000000000000000000000000000000000ab8c06d72af5b4d5899837c888312427d92652c421b9e1683f891693b300d7c0fb25deb752d3aaf3d1b15ea142b0da20000000000000000000000000000000003c6c02b0bfe20c87ba1157047a163604049b6756501bcfcfc715f33c013adf014a6d8df1a0a52780031c74d0fe82e5f0000000000000000000000000000000014ae3219aa97e6ea1cb4cae2d43075bb181e365a031014e53c42264afa811b4a828850c12f3286918950c9a10d1b1dde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000354afeb8f021cebd47c2906875806f30e61f47ce3ed481002fbbf38caef7f39bd1d7a3e79aae3afd3cfb3ba9a240e64000000000000000000000000000000000b0a1026dfb482622427ebe2fa83b71f14bd720ddc876d7cc71dd512817450f2de03c284c217d277157e0bfc1094b1a40000000000000000000000000000000015e526359d156859e6eae2045cc039c00f2f2b1f14b979ffef55d7797d2c06dcf3c375990bd9dbea0dad7b85086bd4f300000000000000000000000000000000154d3f9415c234003384ecf180221ae56e93e9c690f1eebed7ee063d5de241adbfb50c25febdb59b2c01528797223b5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc80112ee014df71381465ff5f990dd7e03271657e3a1fbe22fea597e212159a74b950dc706af28068829c21a4de33f0000000000000000000000000000000016ffe6f2bf7c365e257d496b43248503a1dfd52c34d6f3c43c0a9d484aa51eda456937a40fcb5af0a3d22342432bfc8d000000000000000000000000000000000d355dfc048657dccf4b929d39073ee3f04a8e3837fd81a724794a15e036765723cbb640be7714a782b49782e2c5ee800000000000000000000000000000000007c4532d2d759792cd38ab9b15cac7af7b6417a0b0bc337e3606279883dafdc21e0446e0ceaf7e9ebc2c69e6eaaf38b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b63eed1b3bd84cd4336c7e1e8851566e4478728bb9614e07a350286e03290162b64626d4f8caa3ef879d10ef12198b000000000000000000000000000000001963fcab39e0d2355b372654a5dc94ed87ef709151eedfd1411fafc7efe956f7b86e61adb3792aa6d94542f67af7380200000000000000000000000000000000127661f03ba355e54ae1e47d98b006270b09a2d4b476d65a394cb2085df3f1c80a8d84a8d7a22234580a7b2d08c68f500000000000000000000000000000000002f4feb22a9ee2691e44cbe7993db835ad208ceb8529ae5dab9e2c4269b56fccf325fb3bf569e994c9692447743227d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081faee8ea8ba5e91f6cab8b1fc8ad30285881f1136e5d2fcf342f45cf8f3b88ed0ec7d17bbad67870e8a0ab0632dbdd0000000000000000000000000000000009cb1fe7ff226f260254c92c7445ac82864b1d8b3d68cbbe3f737ff3eb430f866ea477c86bac3cbcfdef376a5cb7a61b0000000000000000000000000000000001da64626e5f09f557d549c6fa18658c32e0ca5e3f9ba30c2a72d123dbd330c461e36b13d1981730555a4013e5ec9872000000000000000000000000000000001314255857ff6c86ca352ccbcfee3394948b5f7309490faa1fac5c2bf6fbb101b1aa52fb199c3624e011f51b1559fe5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000089c63742e437c35c1e488d348f97a20093f198b24dc63c60e8208f0ab73707c10a50b978625194cfd96154e4155450c000000000000000000000000000000001950a8334833ae9cb665f9d712211361cdcdf3d6d7d5d1bff40491054a9aec3decb74aa2b8a6bb11cc23a26c885fd5100000000000000000000000000000000011c971ae8838eae20977ba58cc71ce35fcdf1ad5249d59fcf4bb0b2ce9c050546f9940b3be3bbcb10b37282aee55cb1a00000000000000000000000000000000070739f8dd0c9293ee70511fafd06b0b1ab6b779e8a486ee28a2fa7bb104524b36009beb83bfbaa791bfd615d28f41441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116ab95547ba5acafc6ca254f60391ab04e07c2e125f19da6421051bbb856336c077012eaf8cc03e4bda9b1826c5a5a10000000000000000000000000000000006121937ed728a1f86892a1e66ab589b0d0dab4d0ee53cdd24ff7635af48fb3dd16ebda2efad7982d0bf24cfd9777c8e000000000000000000000000000000000f1a522dc55ebe5297d5d8ba7c4f331134a88347e88dc6eeb7e1abc483b8d638a06bb6550949f87a5c36cdba12f545e80000000000000000000000000000000008e1f0126ae8a2c81b5ff881af612b08e1289bbe1c505a32baf050654d819c951b31c5272c6aeaf7d6b59ff657d2400d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f2cea33c7258b6a6c2b92fe4fb9d49c361f57474528b544b0b3386d499f8f04a4b8b9302497a3899a8054b96ea30e800000000000000000000000000000000013c1e885e8f8caa56658eb118917e4503d30ff6929a2a90818a8006136b4eacd51c8c5d149826f7f2a59f18ec0638270000000000000000000000000000000009563a36d6f545068ebc9e774740773b41f5847858681542d85e036766593e6994f4d83d5574bf54d9a90a945d0117af000000000000000000000000000000000a127553c8b9cece8c5da1dc5731c929928a2f3865e9b8129a864b94972683e2ae3115c2556b011e6b14f76eeac059011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009ce4439a5a3e73b8062f1800f3bcaab8bc848a7f6c246a53c94cc3e8c858c2659aca97b27629c74d5ee021c703e0c04000000000000000000000000000000000798c9ce0c5fedc8e5d07bc57e2086dd7a676a6545d012d169c4adbe63ecf971ddec797433cb642651d1804bd3251a460000000000000000000000000000000012925519e680293ca5d1f71aacdfc17040b2fe3a0bc1915a0adfd08019d3d0da6282f3b00e5ccb06cf85170a2c16cb480000000000000000000000000000000007f7e7e47e383491531aaa75a53192aeb8af70eb66d350c192874e4f465fffd9cca75574565f229783252f906797c7bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012316d6d49caaea2882c24a8c78cf9a22d977ae12f6e0c4b2cf2a933c4a897c11db5efa96549a4acc72b3c5f063779d6000000000000000000000000000000000f414870002a26f28549e553a7add1ed4b79fa4c6663ad4c70e9de519428d4bf41fcca9ffa496eba537fe28fe15934850000000000000000000000000000000017c26fb4f0cb9a9d412c515138c4553987dae310868bcc7c25fbca30654f212bb3fd123a384555267295de5dd84d95b0000000000000000000000000000000000d3398a0fb0198ed55e03bd61b3f7301b1909cabb8fcaf7b404fa54774b381c23c5059b39af80752e8ddf7001f3496fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043ac5cb452da2695b6d08572e6738a8cfda5ddd184231d3286b4acc718de4ac2bb748c40d29becb036a623c93064d18000000000000000000000000000000000af3762625ad743c414178536423c15e996169f71122eaf690ce3990f73c42efcccbde7cc90a209dee9f8e99e338b21f0000000000000000000000000000000019742a8a34e1125671f22f1aebde90babe31bf26b1ea30e36b063d3e31fa6aa53e001c4b5dd0630d3461b273e0e592000000000000000000000000000000000016aa2313839ebe9f55dde430caa75faa2f6f51435fdefe0a531beee998cfd8198743b51da99a94de5213d3f0f7895bc41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e0abdbdd5e64a72fbf326bfe327e265aca2d364844e843dd287e33773619067b8fff7278ea245eb14d53627f4300440000000000000000000000000000000012d3296a683f5a1538f7a06e5873bcd36d5d08414aa6c89e6c564eb6e3db1030b96ad9bb3fcc3948cacca8e652a5f7d6000000000000000000000000000000000c228610f01444ef881ea0fbc6d0f1205739fcdfac84e482edc4a1697948b1d93244d3eba901ce0ee7216f11543296490000000000000000000000000000000006990578246c1f863cae375cdecc2c41dfa2313490fa067596ccc17c169c1a7ab73b2b83b0d9a5b2fc63bd1842adfc471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000267823cd27b618ec291a456c297f7b91d5eceaeb97022461d5044125e8b82040526bbb5566b5fcd3c9afd756743b9a3000000000000000000000000000000001612be2213706a572d3d764fa06d02097086b2ad9b97a3c351bf8f06bf58a9198109036a43776d4ae49b33c1ff2f04a80000000000000000000000000000000009f15ab9963ba0292338358bceb43d5e58f14482cec904d5afddda501e1d2a7097d05ba14e6e2525c674caa58d48e19a0000000000000000000000000000000008cde8d2d376109aecea0a54383a6e8cd2aac7e5f97a5e0c5d8bf3b5aef888368523fddef2ab8b683c28c473c1b141a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be2a8c20f7e6129f754d6ced6937a491ae518b66c5240a135bb0716e09885cec8acf75117773f8c4e9c125d442dde5c000000000000000000000000000000001990455c88707b2800bf0269c15e78e0e03eec5aa283c6fa1c33cbced3cd6fc0894c3df8b7b0d1bdbdee26286d7fd25a000000000000000000000000000000000811d13d4565cca06de405060d6ea376b92657e9fecc34d751d5453d43af8dfaabce7dffb6a1105c85a19e468d3baba900000000000000000000000000000000012866d7eb581dd6bbec503da9631cc806988c5390e6c5ede4df734c161522425ef8a27cf8324c66fd95f83c8a18605a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f34c85fef6703c6eed85b0022cd1c28b46cefdae09c6ae72a5e0ef8cf3a1a896c6647e325138ff28cc83df999a2641c00000000000000000000000000000000070def530da20bf86e3544ddcdc5920dc01a5ccfecc284b1c7615c978fbf205302d294b8a026f11e8f543cdbf34fd9510000000000000000000000000000000019c765bc6acf3aa2578bc2b3a4a4f5aad4d63175bae3e420a843aed5c6d5ee00856d0b445207ef72f6e94ea11aaebab9000000000000000000000000000000000ca589249a7199676d285573f76a11f1c40fdc0d7e6ca0e5f90826240c50aafce26420efc382d43b8e5d4da2398f739b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e3993148f2064c37248e728bda7f952ed43d7ebb92f0b29c8a298f5d6e6bae46b569ac5f56a716e231f337819cbdcb0000000000000000000000000000000007304e4df5f33f8b3bdf7d396b39535339a8e62cc0fe431492d8bfef549b6e7e18b3b73865eeec09eb774c05a9848d670000000000000000000000000000000004bdfc6b979a2ccb35752715d371b985a5db897aec87facdb28013d587116b91b0a3dc0e63af12a9102134bee588e38d0000000000000000000000000000000004d930e1d20bcd2012bf9d772424fd831b54a18a2e49c2db1ba5afa02cf69f68e3c6c42eac23383647b843830819412d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000242fc169e84cb04d36a7e7f0647cc3303ebc9b4a4848d046c5260a1fa4de8e92c00f43f9f60cb31468b6fa0c0701e7a000000000000000000000000000000001667a670ddc17b2b7ee9777840918ca30e420302b80455d583509fb8a32d80512bd24190eddef23e8d1f3cfbe04c881b00000000000000000000000000000000174ebaf4ea24dbd6ecd32e86d517d856b66b42f5847326003034f0cb7988cb3641a69344a0d3c8f9e0fdc72b4c9975b600000000000000000000000000000000052d2a9fb05a5a45e9870baa27e05fd7a31e6760b5464f4b64612ac784f8a603dc06278abd9ec9a7b2d9e859c3196af31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012ef5dddcdb430726be669f2e6a0badfa1ebc1145624b74ecc544f445774b7af0b2197578116c3cb7097aa0c3d8018a70000000000000000000000000000000005c8333caa2083ced238db58d344ce14046629ac2a683164cd7ec585a1f1d565541a0ff5a8975a85a23a4626fc6d4b9300000000000000000000000000000000067af59ddc23c700d05aee23f6f692af78f6c9d59a92bb58cc9cddb66411061a31f189000e6a66179149df44dd8e1fe200000000000000000000000000000000025b7ee79b9ad300a0944bbe0963460d43b95b8d7a300ba200154262a485839ec0f42a46d2d47210872846f812f5f8ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157e35ab210bd0eed8c13520e205de4673c1ccfdfa46388ce0e5aac2172d5adcf6f55f571ae78aa212ac278f10a5c2aa000000000000000000000000000000000f4e318a625c6ff74c0c95baef5e8f3214b87ac509558f89ed9d76364695e8bd7a1f6eea701af793e71038cc49042c780000000000000000000000000000000008b65e0b6fa3e54c6e204e5ef5696da3d7e62d98a108a6d92a39440329a6dc4f6fd0308cd08c1101ffe5e27526023ed6000000000000000000000000000000000f901478846e605a4cc3c34b83223a31f172b40e8d3dc6c33c5b114cdb75e19300c31ac8c0ae0fdd9f399375fa2996d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003fb0b48c001ae1a5054a8284cac0673989eb10146c463c9cda9a58e36c6c36670e7479d13bb20200ee68b52b3eca73a000000000000000000000000000000001417c52dbf9378c549bd127bc113e64aa725b062e065b4abbe7ee0dc2e0ba766cd49a8d3564f9f46fc65f473ab5e85390000000000000000000000000000000002d96ea029f8cc461bc16c940a704b18f61b6abb83738d340dfd1ce90dfbcf78dcd9af4c084acc060d7a4f54a964b9ae0000000000000000000000000000000000ffcf296dcbbbc8ab3a907c344941beca1bc9f12a14843aeb5dba12210fb1afc83a12cb20779ff9c2706147a239f29f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010968e0ee59c1b362a24b741fa24e94f526315dcdeb34a118ba06a4cd82711b52fe43c9572703d036e262b55629f8626000000000000000000000000000000000f68f4bef24c33a3cf8bf67deb956aff0dfc163f23ae1f77d73d7db92ab0bd5871afd82c2fc855286df81290d6f0f502000000000000000000000000000000000e84300e64a874ec275c51065ff443a1d0c571b8cde6ea6b64860ab838a050106782454d87aeb70b526bfb3b2ffab5f500000000000000000000000000000000031f2ba1b9d67f219f7b3ca567ffe170b720018b8dc84a76f74a5b7474239d7ae2ce7d45e2ceee09282c9ecfa1bd6b441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c24690ceafe25f82ffa628e29a050afa29656c128470a32cbde5f65211bbcfee20205b619a6eeeef4423d859d316008000000000000000000000000000000000f96c850ac8389f1a29ab55485294eea0276112760d4104bc88c7a11e3acca4a55366f55eb4f49585ba18fe9d8c8826c0000000000000000000000000000000017029ca22f428b264fa8c4465ffa11b7ace32019a530b993a964a6101c0fa19567b7efce1549cda5a865ad512c8b5221000000000000000000000000000000001421d2c88aa5cce47dc38ae8e38066a7c8d53f14fa635933059ca45cb7d898f620c69fe58ec2d35ca9736f3b363d1a041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010f53a77c7ec5336021349ac04e27db1c514655111f7673fdef9e7f7882e5bb4859a9bf127d600504e5d8beeabce70800000000000000000000000000000000006a4dcad66bb727229b7ba7a40de1794f161df8a6c7181f80cf06b207d4b54174ca4a99b3028b0fd13c9a05f8c6e7b1d00000000000000000000000000000000146586fcd94aab0e00f8ab00a3775b08944cf949e5b80aa711278aa75a039ac8273879578f5be5d6ab37902d2b648276000000000000000000000000000000000b67a5497ea182c4bdc9813be7da5691d1833e91b680ac8e2d99111ab9907e58718b6527ae9e15b7f2e05db22c90cca71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001153783fafd87fe55dbd9734ef2971c49d6a5bf199e68d0bbeb7c2a482bc1d69d638e7e53f8877de2a17fe16e8cc44a00000000000000000000000000000000196cf7ca552109f9b83febcefb2e5c16d6595714056c3fe96bdc9b987268228373c92f54607ec7b73f6978a9ce65c8e40000000000000000000000000000000010aee1938c5f8feb5e50059b9e0fbe32949ad5378054d9f4e4d6ff3223fffdab7f0c744eba63ca5ddcb2716bef1ac91300000000000000000000000000000000138612ec55272e09b7f56c5335684a37caaa5dbbd5b72d4b6bb2487a2621eb779b207bfb662b000c1e1a561d67532b691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000329c1947188b8489824ea0f5c1378c18d2f070206f49855bbcb45e29ff36e1663d9aeb9bddddb0630c9edd43cc41cce00000000000000000000000000000000108c0e7e2cb636ee2b740fe2fcc10f2849dafb872149de4bcf53e98ba7c87fe8391125604c65d9ef5ee33e1dc91cada900000000000000000000000000000000012124fe2eed509f4786a2ce495349f5f03f97bdb58afc112df7f0e2f6ccb46f0739890d4365ff03ec0160548f1ca244000000000000000000000000000000001442e3707d740b9d92b75e70c875f452ce23db0dce240dfaa1cb874ed1ecab568b58343132b52928ede6c1c79e17d4801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015948d862549badd0e40eeb5ca5f51146e0234c02173cda657787093c720a4593970db877f877ecd5c542ac339a76930000000000000000000000000000000000a1449583f2d6f22918f4675158c7913b8b1c37ac2eb0af071a6105c39e96a89cf2681927d306d33641795939f11b78300000000000000000000000000000000009668789e4d6fedb2118cb0954f25680bf50765b17885fd9ecbb475b1490014e65f780df5ff6edde95b4db0ac67dc770000000000000000000000000000000013309b383281f20a4a00c324e13fadcfd5b073ea21636db221b454e8e36e35476e9d47204cffd5bb210b46c8590837a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a2e72917e4d76b643814028db457a6bb26f6ba49e8bd5a92943e9a928d043b5e7ae83efe2ebcb214f57e3e2a45d558d000000000000000000000000000000000e15a41346a7e5ba538223d91ffe1930765e5779f14ffa74c545b755d827ecd47766664d968176a3fcc42cee399515a100000000000000000000000000000000131c324e7da3b1d1798a9948cdce2846100e093d23d24d4d430b268aa4dca4726194fccf5bd5ffcffb81b9b2ec19eb4f0000000000000000000000000000000010a30201e0cea6a71b17071081a92e51149841ab6b5410de881ac9d14082d6403e772acb91d9b780463556fbd4a0ef231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ca9901b40bbd52c153a20561e7a59e4f155fed3a8efb808299879c495201da88a1cd62eac95f28a174df0545f5b1d500000000000000000000000000000000019ff86e033b9ce9131630c788254c5b8aa19edd640781211b5353d513f269e79065a411efd01bf88b23644fb459db0320000000000000000000000000000000018fd8e920ebbc8ec615274aafc5c12424cc62ca4672ff6cebfdfdea3704f7247a82b9575a9461bc9373ac38bc2686bd900000000000000000000000000000000095763c5e23fe263deae9df9cd30926eb10bd6a644feb3a59ca4d636586ddecbfa5c7a6e50092ae270069469737f33731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000191f67fff1dffb867b63827ce6f06a51cba58e58a9645150dbe7000ed52b4dda922e6c5f25998e2b23e3d4ba2feb98ae000000000000000000000000000000000324e3d678b747ad15aed135d493662f774348caa40fb27222c758c99c1d088ae1a6b93a7229beccda308c1de4a9eb6c000000000000000000000000000000000e3cdd3505249f242b43649c77c27f8956846fccaedda21aa0f14bb335c21032563aa712d90ea2fd779e4c998b94b8a90000000000000000000000000000000009afcf38ed6916914ed4657d8f48f2d0aaceb1d0c697e6922865b7e6404c627af16175943139f2477cbdadc3276afc3d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f595dd9e316be096971a6001084c1dbde3cf588eae80ceb5701f03a1469f3b09525d1ed4d849a335c2684546773bc030000000000000000000000000000000007843f62484bbafbd91bd933bd786b40bbe12078c72c9d9092c6a251646e4bdafb907edef6fe5b973e2d4b6a2aca649f000000000000000000000000000000000059d484d5bbd85869d1287dfa5655f89adeaa0d5607c573a32b71ba04808ae09ad117aa79763ceeb3d53c084af7e18200000000000000000000000000000000031a379a5fa709d08f1242d0645b0f1031318d7841121b2da4fc508e29b94bed0bdb792488cd4786017f5295a5e07fd71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001442e00a28a72d473cbe2b96ae2163b402a914bb1a91faf0739ea81c9a4d23924f1172f3b4be6bca27149bbbed73dfe90000000000000000000000000000000008600e6c370e296254d8986903cccabc27fd2828546b00e465a76cc5e77f8703fabff82b5489e88c02e62cb4b39479a500000000000000000000000000000000194c681a57a7fb54c0e8582a077cddfdd02dae579f67df50a569e27e415075f634dfc20b303618ab57f1d11e20feb93a00000000000000000000000000000000194d3df350e3f9487c82006d817c3a16a4d115e688d74aebe388ab40161142eaa6b3ae0e6c07b94f8ce216cbbfde16de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002814f72e642d4685ff1c6dd64a0d70e151a9e05dbc95e12d811347ba502fc0d90ab9cc9f7f1efe9c577b7abe32455eb0000000000000000000000000000000019b5ec11adb99977a43cb05981160ea8d1041f58bee93053f71730149762f5ed8abb5b43074c088c0c642f8d8b7a0c8f00000000000000000000000000000000022e208c8eb857b6b1dac105dbba0350ad79f117d3d6e9ca75ac758e8cf76b475c28c556c1e4d582c8ab23f526a9f3950000000000000000000000000000000002d7750fab5a52ca3ba2c11d3452044971da4d6faa188cb4731e29f83d48b5e7ede94c745e3ab1fff9b54c726018bf051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020e0d4b96689f0158f821cb605befa719b61c775c9a661de6e12b69113a50d53705d1ca9ed1f22a8226714e353433ce0000000000000000000000000000000007c0df3ebfe031b3608d7789bc4b6975e01e33b9b11effcc705f644266ebaeec5c92bc58fd9c1d0a282de7232d364e6c000000000000000000000000000000000f8db63c165fa90453e715a9648750d3748175a6e1d4ff9d4c105811b365cf9886f1b029e9300bc98089fe402b78004c000000000000000000000000000000000d60892d63f1ca7e5da3c7bc160b02104bb5d5ec69623838a2023b72578a63aaf1bb957610b18e9938cf751067ff39791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ead9d57626068c975272098b448e7fa5745ee3a2faa8bc183216efd7f8fa66e8c740b467452752e0f1a79899f41112000000000000000000000000000000000385aedacd1f2f59381abf8c9ab16bcc75d7c79619c1eb42ac8d2eae440f68257cb00be2204a6ffce537255bb2a8f942000000000000000000000000000000000c82dece8246753103a61b5b0b121108dc6e769a2bc04116ac832a7c29d5588495c267e1d222ce74cd178a77eaeecd520000000000000000000000000000000003984b273d4e408aea4ba03beae21741d5c2ad58258b317e8b7478835c06c0778d1317b226e007a704724e55a8f91aae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003f7f16d32cfb19da9ebb5ae2b1f514127e9e9c654ff9d13874c21eaa905745d0bb5ade1818942aa5e04f5fb4a4f6c4d000000000000000000000000000000001788aa04aeea9c873a866844af2ed7f8120da6d4e1314aca6d0365bc277d6a077edbfe3665bd73f57402dd0ee88914cc000000000000000000000000000000000a2dab50f75ee3d5a966f34fe56c8b92678f82a3f511021d5e2dbe8a8acf2d00a8d0d6f7a2033d35ad2fd95412db91f5000000000000000000000000000000000e450139e665e2ce43c8c40a5177a01314a8a292348290712dbecd4024eae2c0c5c4456a90f1b375667b856da821938c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000887a101d3d660853ae6fa29cf457275c2abde75594011a4af48eece1b2ce4d5bdb514be848378f01a73529ca7bda26c0000000000000000000000000000000001a533d895a1a85b987617d82fbc7bf394db327010823ff0f46b0b29464f84e7075184a7602faa5fc67f08d199e3ba1700000000000000000000000000000000149bb4d5dc254c2e306668c1dbeed236453c639c6111b2fad74b091d71c4dd1540aca0ac627a9c36ffa2705cb680e1060000000000000000000000000000000001fe611266ce8487168d333f1b7a0a7f19a1f27b47223722b8fa82a5fb893570a064ba1f5f5cc3dbbdc1a3a3581add481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001144389b54016f1eec4bcf885419b761847e9fd0f7c9b2a51a9cdc9f5fb9a0f91deea363cc1f3e72a58030f13510a53100000000000000000000000000000000174626c2a9e57ff41d0d1f1c53318bc482ccbe5a20845a15e5d77fe297ba9dedad0e52fb8a8a18de1d2e266da8b6ca4e00000000000000000000000000000000127c41fbe226a80693089a7695a4ee15fd22137423942e8ac4493a7b9604c1e7b56e39c555703d79d71d7de65955e1c10000000000000000000000000000000019007acbcbf82ae868a40cb3f477679a72a29de03c7645b338114627d37d437b1bbff5edabb2a1a8278f5dbc4f78eb871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000085d31562b95d636ab26951234926587929c227b9c16d789d1cf939ad1fccfb67b67af86466c43d95518e1245c7bdc9000000000000000000000000000000000062c5860a7efb9434b157d43e692ccac31211e0e0f03df1939977b80566023ee683f275f41043016ae4e2eb0995fc0510000000000000000000000000000000002c81a07054bde110e3ddaf74aa84d807ba273857d3945e394a0a8524f6f3bdd2e3e51db026e08fc3c6b7d84b48fd615000000000000000000000000000000000661700c906eec4773c7cd6cef267658be7f57c68ea2f44b30474d9f2e893db62c4f7ef3214b64a54e852a86ab0e36841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000489b397c308ad508ea1dab14f19f5c11ed38f76617173a1250362c5f41f9abb3d61727c417dc82f22c6b678b5202ea1000000000000000000000000000000000705601673c330a65a4b516c74141d118c43e7f8374351e3f22a6174de161a259dce88c42803caffedf5665beb8239da000000000000000000000000000000000f5543d20e1d06e44d94451bf8e47a274d82a2fffb6c4ebdcd0cb552a588e795930ce3df97dcf3211c2cf79f1bcb64c80000000000000000000000000000000018d5322817b6a780d0fc37e0e2db3085f725b7aa4e64d20b4f1b40feb940bac7401caae0c80f6221df9ae845aca0493b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc07ed168751006e9671613bc92a9adefebbe67936c0bb5e863fd177f284783077234bd26784d938f95b9cf4b7846db0000000000000000000000000000000008e7b5c1d9e23e2938660066a0f6eed6464b63757425f5c75d123990914c3f909a7cc52f4ed2091480cfa307b0888e3000000000000000000000000000000000134fda55c47b0815597f7f6c101a739d14e299269972ca88f0a0cdfccdd9167b8368a967ef834dbbc5626c41eacdfbe30000000000000000000000000000000005055e22f95145e63aec9f495651f2e360e1ff4d4baa6c7ba4986f336bd02494e65b2f90dcdb616adcb9ab55f862910b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019c32b1f49f0573786182a7b3b581c05e55e25f635a216dea33e887158bedb1ee9c4a770aa46314e7ac7b16e6f075ab3000000000000000000000000000000000e5bbf443aac540ab66a86db25c1d05a6e5cb34fbf5cb347965f4d00b1282b87759dbd2955a937a9f67e92f252c35ca60000000000000000000000000000000012b0eb95ce6da766d99393d9f01e01c339022798ea994be45fcd32d8c96e59b14eea6a5a0d5fdf1c94175297fc050189000000000000000000000000000000000778c349d6b1e2ae0f9737821f3be215ba7168cfccc4a83511bccf5bc4f7ae1f2b95c3f9d382491b35a35113f0a8624b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016659d4a5b0d35cf40d35b1e1aaaf04dbf930408f3e054981beb976f0471d7a859e8ff3250877f1bee27e7e906aeb6ff00000000000000000000000000000000056593fcba8a5fdbcda31fa732b81930405b9e34bceee6f83162521761721922e5231724a687deaf2ab5e7ef6abb90c700000000000000000000000000000000189ec6018b5bfb2d5d09b7b307242fc029f34c60e30a4372ccc521524c4c18d5745edd4adc291c5f5ff8adf1d7c745ea0000000000000000000000000000000019228f66fa6bee5ebf1236462e141e4e1b08bbc07a188631c379a571cf5f3b086c7d7e174bcf93f3fc7eedd472c179e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c66addace5e99961bef8f026128719cbe2c58428cdd463898c82de33cf1cdd96fb83d790f2632d5f5e6e0f914debfca0000000000000000000000000000000013c348be0db111dd02dde7bca4e1702c52db76b376e466474b184cb68e91dae08e871c18dc09a793305e3538a30ca7190000000000000000000000000000000007cf33d4e36c92c130bb59fb5087afe5b83c404593dee3c2dd22df20524adaca37612c25eb2e256e2e2e1dcb118704e0000000000000000000000000000000000eb15a38483152dd3c3ec96d27ad8d07356a3f34fe128b34251aefaaf3e9523b14ebe0b6364800330b7a1996c02139dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e8946781d7f4d74b6ca034d57654b996b006660ceca6553313dc5d2b3eacafb9952415eb675089586d43b9adb752be00000000000000000000000000000000035893eca04bd3c5530f878df48482eab6191f67ff41062444379a32e7b68ea4cb60236a4e16ba4ac2b900e93f1591d70000000000000000000000000000000003987238cb5d2eca10dce7d2d70442199c4af82879b22742a4f70b68b47cc6317170804141efee75ca926d709061a794000000000000000000000000000000000fdf0d4de1417bae9e2cd2b14f90cf82d290cb9278e539273cd846698d8f2ef16efcaff9a0068d6fb4c707acbd19e7841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6b896705cd53a1bb031ca0ac7e3e82221460f33b1557f2449b77e60d28288aef47b81cb1be40dc2112d20651c9c83600000000000000000000000000000000018d336b112e486fc054aa67cd7bbd770d364d834ca1f1fab9ab63e3d2bfd964c53ecbbd2a8cda89779ec5dfe8d8cdae000000000000000000000000000000001104fd8a9a6878b2d0d22adfa6cf14c04bb784223b1aeeff2bc8eb280bce00bfd8c3658bd6305478c52c908b07a41d3b000000000000000000000000000000000b601b3d81a2661173202aad276e821adbba2f1746b465ad0531e017845745d2b3f1f972121b6a13dd607bcefdef44d21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cbbeefaea065c55cd84a66de3243b63bbb88b3bcc95194106f42de49cc5774f314d7450c124d654179e771d81724fb000000000000000000000000000000000b0d7d72ee4782ce83064a533ac365edbc9c1214b6ca56a63a484ee35ddeed07f23f0d86f9ba7b9527421ed96961517400000000000000000000000000000000103847d5071512e338773f733430e274881fd2cbc48de91ef4abc3f6549c506acd8f059bfacf602dbd1b316a9d4464bf0000000000000000000000000000000003cc61f71aabfe1e2c135d9508d1d2b557566334f425d139f7a6d5ef556d06f60c566b40a07bf50ae095d8333ab0d5c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001661f515380234c0a59442d7c010ae3d1a1b1035cdbf2b7234153820cf9a92e3311268e51d5db16369a24363927147490000000000000000000000000000000009e8e735f51dc89e2bb06b2c2468dd53ecd58e8c2d0a5d3859a5f289277fd71e72e7f150bb3ef7ea55a42b5838a5cc17000000000000000000000000000000001030aff60617eb181f372b69ad3d1ea53a55bf4de8a1ccf6871bbc940c0e5ff7981ae1637aeaebcea5071e17c287ee0d00000000000000000000000000000000007c2d148dcd7fa902bb932c40ce6f1c92f88fbcb5e224d99f583ededb1805364e410699993039d38624d7aa1cf9a6331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000db79512d8fd8fe4e7eff11b1ec883a40e740a4b08bf7ebebdc31c7cf21f62eea0b9ddb9320ee41b0c8a50a5d162d7750000000000000000000000000000000009962899d2cf55ff1072a150cd8065c1b5d37fe68e79ff4956a18ed1f55d48d48832c7c70cdd0ab481887a62c7a95e390000000000000000000000000000000003a7542b146cb58dd4eee5166f85c64fe0353fc3acfeab029cee0650a9ae292937220c083a3ce45564c8e5d5d4c730a20000000000000000000000000000000002251ce77b5c4b6e7c503fc0b1418be383bdb4002a68d1caff22ac1ff68c612ed722923c0c8f4ea6f8136fe2a64768ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000731ec3415f253a7bc0f86a9564f760eb7dbb11491b6e6690d230724cbb3046c75d29041c5e62f3942cb98d42750c90b0000000000000000000000000000000012ee823a7e4463f78e33599051cdfa85cff07e96009da46ef3989dbeca49ca125408ce8391245477b0cd5eb5d3c839d3000000000000000000000000000000000ab3c2c6f65656cedaa740eb99ee386cba7dc37f8ad63e4a9a9485591b6e49d8fbf3a5a3802a40408fd1c5ec41d3c98d000000000000000000000000000000000b2990209540ab2156920e52b6f93893377373c16acbe21677ddaca425334f6dcdfc614f533afec45d3767eaf0cd1f4f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049646b7eccff3349dc143aada88a2fffb1fd84f8c2e80b87aa882d30789fa145c2573d4acb1735f5e70bf05949b30110000000000000000000000000000000005aeaf963ab3e5623b7de4854559e9778edef9a6f53e3493910bcb5dfbedc8a982bdf55b2b0dbd5a7f2131c2b1ff8eec0000000000000000000000000000000009727bff147cae9bc010b70710f1cb7d31ce8e55410c7ff2e650919ca2435d54d1eec8deeca4eb9cee68f2e4f0fb962c0000000000000000000000000000000007700b87a79f84d77b79f1c297b0decd16d012e45d976d50bbe39728ffba94a687f86a61f5eb79e2ea66fee3e8304f431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7b7b6045249f57034eef7aa38ac269d8494373ce19e3790fdd0f780343707c472191ec0b9401ddf21af84ae42cae1a000000000000000000000000000000000d47983a09d102d71fdbf9e02eeaf515973422f4c7ce6dcacbc25250ab1cd8baa5b6acbe863db83ac090dc84d68763640000000000000000000000000000000011c0cd9c08ba860ee12e7a247d6feec77d13658a3cb43ed0ab2eafb713160962e1c2c9aa83a10b11620ca505c936e0e00000000000000000000000000000000015c802a6ee6c88bcdf486514b2762df039a9b6b3d7c30d1cd26a5f7ed794d2c6b4a2ee46045ca90b00d21992bafe8d981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000115ea66480d6a1baf6894dad0a7dcdea4a2e83232b2e14daadb6ad79bd8ccc4f9ff946a39f9c709f036349fb4036c5ea00000000000000000000000000000000017e21ff69229b1a0f0f91bbeaf72dfc81fd8577ce044072d355adda4bc041d76e4e140fd7dfeb9b97560b9859cfe65b000000000000000000000000000000001238a9360954c5fdaff8ab0041566be11edf76acc5226946024d41dedfefd0c524d51caeb53c296b3749fb0df7b64ffb00000000000000000000000000000000109b068db4330ef999bdfef98488f89e8ec038e5e6f536812b8f30a1896c292c6f18de97ab383ad7433b7dfac36404961824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010a639365357db31fdef35065c3b032e6417f15d7452e7514be10c39360d75344943e1440c2b54e8acf3c16ab11dadd50000000000000000000000000000000005041849f2d6ea6e3e440658bc07891045b5e9ef4987d44a375f955e30b3abfbac55eaa36ea81be8bfcb1cb98f3230d6000000000000000000000000000000000bc2624037db36737824be7805b7e8dc4cbbe495497a48645007afdf68192e8c617de259268d7babdba8ad5c25c8272400000000000000000000000000000000193db7076e86563fab664acfe31aa963dbdb30f07d252f22580c88a9261ba9ac2890d852949294e0cd6853b060685ee11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000396b5832a0978ea80d727857d243ae6424d61f0ae505bda880aadd22f0f1cdf6fbfaf19beeb16d3e1c62a35ff700b6c00000000000000000000000000000000056ce2ef08387c754c2dcd7919ec36e06cf2142392b2c8226af3a1f454a088e035fd4a37ad7b7b48a7372f85906416240000000000000000000000000000000016369dcca2839130df1551e596520e06a4bac33bd769509f45905c7f44ef76c9a3c0100110f5386017cfa2aec49deaa1000000000000000000000000000000000be654adc5e8ef82bb5ab25e8b1ff1fb2b564fd4b50c965fecc02c301e3e7aba58df1ef72c23d9e03dc639d973ef243a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000151acbfa2c8783979960cf61e509641c8fd1836900310a10f0d691cc09030f6baea22f6f153a69b3b5aba1d0f1a93c8a0000000000000000000000000000000000894e002072999e0ca7ede8c726f4c75cc6b82a31bca1740540fffc0e17327f2e642e2135c9f89da8ff740d803fb6470000000000000000000000000000000012be8168df1aa225e871256383297e9cdff6127bfbe92a042fab85c17c5599398b1f53a1108108caf2dc73e930d3a22b0000000000000000000000000000000002a565209a5908151c30af8dcda0b5934d2db6fb37e483c11dd787fbd224192d8cd10b571cc928ee6d616aee8f8782a01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000039d47d5c3369d1e62fcf47d71c811861a5b70345b2becc5787b3e3030abe72295626882e5c9754b95b76fbc213249810000000000000000000000000000000019763951a0f9ac885008cfab44f7825ced5847dd38ab656d6d89ff547b52a69698a577eda8cb610959be3b73775f0d5b00000000000000000000000000000000126d7bf11d1ad4c15f55fcdc340a5c0f2ff945aeb1bc783d6f4bbbf6603e5285630a7d0f34d990b4a6b07cf102b17b8500000000000000000000000000000000029b3e43c9054e0b1653e9fccd4d9a5d96b2e5a7b2504fad8ded8120ef5ba0569c4c79a1138a535f9a851aff6c2204d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157f47295f13df2d2627e6869b7cf056768b9426e8ccae7083bf2ca4a5a10b45b09f741637dab12a60c1de3a85ca0a2e0000000000000000000000000000000008782be2f156ebb382d305ab028ee9cc28976b8f9bb9e07ec91b975c7f0b39ce413b857a5741906892c26f8b4eb0423e0000000000000000000000000000000008c8d45ba88eee71a845c19dbcc97c9b261e9e13937579169fca22c1d9be48e413f7c9b4d38505316a868a027109958d000000000000000000000000000000000f24bcb062e33b2b898e9cfdbd20d7cb7177b868a69fa2ab829f310053bac913059171f56bbba2d4ad6216cc0cd81bef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084698bd604896a0cd2e0eebd4e382e167a6373de1253e546702bd000db04df8117f53abe1ae7344201eb3350bccfe570000000000000000000000000000000018bf63cb594d35e52efa26526fcd2ace057c8d3ff4b969678ebbad585d519532b0ea6b74e165aeb46a1b5867e39ca290000000000000000000000000000000000b2fa9c1340898f1c55c3b67328ee3b533e3f7a052f52a3bd4fc83bcaf12e15c7f216941daa312f653b0d35d86297ac1000000000000000000000000000000000dbc5748707d709d13c78a7b50d5ac5c842fdd8a63d07b9e3e86d0e2fe5ab4b643cabff581e0a54f6bc21eb3c5c98a041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102b7cc4aa54f08da7fdf99d027606114a1e6ca0776be7c3357de89c0c0aebfab12cf8767ed6e16760fc9d5dabb542230000000000000000000000000000000009ec268661082a56ce7149534dbf3027a0fe09e503183e96dc185acc93cfbdf407becf9e14e771d0bebe0dd5a42e733a000000000000000000000000000000000ad4e3af58aa2e2946ca41aedba984ba8d7f09cb667eba750e9052a3f57c62d93eb0392dffcb56f90b71e98d20163ee000000000000000000000000000000000038591cc8ae93647176a0ae5cc915ac98ebd1c9a442497168763217bff127bd12a55383a2458c1512599312187c0b5fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a6938f5c8440af210a5036b70aeb72b522a57fc800960ece6e501b84a6116239ba7bbf26c2eabbe447170f1e07127400000000000000000000000000000000149bee97d410f0c4b0d067fc66d83771758e31daacabb2d5ce812dcf2a9383a44693b86b1904cec13bd7b69b6fb1c90a00000000000000000000000000000000170b96e381c3c2f9c47ef9135541916795dc79d62b27489b0963f1da673a889e6d15ccfe8e04cf5bfb7ed10ac2b2fa8b0000000000000000000000000000000011fa0355ab6533c491c5fdb126ac9e0f8caaba2c0df9675b14e4d6f681894580dec59e00bca329df8db20f7efc7e19491824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001254893cfa1222e898107687c9ea1d456d871933a486e72587a57afe42d4c7d643934a58e15b8dde13b181b4002431ee000000000000000000000000000000000f93889fcad428b2d587855e449ae811b6ebf78fac045304507d26c876514a6d5aa716f568606c3b0352e5c9d556cda4000000000000000000000000000000000c862a99c63cc4f730e364806a6caa7462d63376e6de3c9162e5765fc40456b2889ca3e530f3387b3e4c575099ae2ff1000000000000000000000000000000000ece604cd8c1cf5332695f93c06f8a3c0b9734ab3caed1f1f904e670605064b6c18d6c4e82da5e1378cf45f46214d2151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c47502c58488e45bae96614058688f60f75c93a3aadc2f2164183f16fc92bce8422217e99bff12f137905187fb37e73000000000000000000000000000000000818f48f961c2237d0500d09bc4ddd12e8989b277efc86b23fc418ea2e45de860e20d3bfea4fa36542d5dcc2fe81a26b000000000000000000000000000000000b59c3b766096df4e9aeb1aea7b6306c593b33a8fa69dfe6631a77715fb268e2d48f909e3ab0efc22a40b0def89a16a9000000000000000000000000000000000e3ff59260ef6120087cd3e6cbaece3a40f498be54e77ae8f90643e831fd521c861332d017b7150e3ce9b61b877794e01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bcf01731aea813193f3f12e1fbaaccedb7c66ae7b589f168b7463e454e4af2c331bd4a3f4e429d0a2e5890190377730000000000000000000000000000000012f0d056d9879cefc792f0df1c1e28a6e41180eac7fc7d6406fd97149be577779bd37b6cacbc4721a37777b6e1187ee50000000000000000000000000000000004f34e4b494b21e9005d0911f85218b7fad7cf6cdb6809553e61bdaf920a54e68720534f9fc1196458f12d044fcdf6dc0000000000000000000000000000000002bc6ff2608d055860e191b3eb086692415d42a2aaac2c4fa6ddc20c9234eb81fcf2f96b22763de32641bce904eae8b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011120a58672595b8efe37faa92d7dd8c584ba7e35437e74d5a6055bf894978ee198345d7ab8aea8946d2c9a2f53a93a000000000000000000000000000000000175ddad501f60b4de06256295b581a94e3383df2a61994e5e95b87a38001efe0e20bdd74b5f206ef7e8686e4ecc98fbe0000000000000000000000000000000006e57d04f12204af70e29e72a78497c86242c852615656e090dbd11cf4f39aaa38d3b9fc022a7f74a64606700b9c585b0000000000000000000000000000000012a91cbce10734eda74784ab5eff42faa4a730a31e8710c8b0c0ba65856403a22ce556ee4d560c429e55ca2010b711da1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e38434db2ae79b97486a521f10d89ade3c1e4122e403b4fd4f2bd6a8fa84d8480362b7463b3373ac336831a022d0b0000000000000000000000000000000001186d9310ef488484748ea7faf460cb04c951b041a2c3c9ac8c6f3293cea1d58780f82f9d7e579096afe7ed3293494ce0000000000000000000000000000000013bcb4243a8260e570bbfced687a1ceb858e7fc21313f186cb5480f12566870562c138843080bc063aa54694006291ec0000000000000000000000000000000006de05e8988cc16b3d367a341fc33f9ba2b7d900d45f09d23be924c3b18c0caac93b4a08086bffb94797f9172bd06dec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000420663488b35a491c7f50446e22a4da1371269d2da92715d0d5c6d2b4d93ba5d1c87410760790f1e21af7329e9ef06900000000000000000000000000000000139e3307f1e501bc20a2651effb35d68a015ba6114992a34a78072df2a4c6a04ab2d0d99bc7d613421ed944aba6f0fb7000000000000000000000000000000000faabb750ec4c63567307eebb95c60c81dd996cff14ee1ce3361948bbd404bf07983b564e6b7a46c1f5e95f912f521cd000000000000000000000000000000001272a4dce01b01a353fdd3a7d50e1bf8461e21b8860c8a0fe0b732db60c8843722dc5a895daafbd641893e749d9171d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001c542021024ea92eb805168b2c4fa23c8d08eb5f7a498d4101766985f235d28231a35e753a9f173f0a200577338b935000000000000000000000000000000000caa5089b70dbe494ae28e68080f98c1deaa01a7167f72fa4adb4ddfc19396cca85a94a9c8fe46c85ede833b90657ed50000000000000000000000000000000014ae68c0f46636c233777459d18a686cf192722708e49077640ecfde8296ce5d816e599e272cebf3b0c71306f469e8380000000000000000000000000000000001054e3cb3910fa72eeca0c8bafcd72df30a0c70a2443bc90035d2e5ecd71ab1e04466b22b14b2518383373938136ca51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fd9ca2adb79bde0d55e765febd705872570f46e9e544badb26b57e7be63fb261f25b678346203ceb0628fdc646233970000000000000000000000000000000018e0bda32d5d736522feec43d6f63c2e69a55a19d01eb7d192fccf7a9f90492fc8f1b06667576042e523d866630bcbe2000000000000000000000000000000000ea94b95b21f7fa3035aca5e5d5599ae5ed4a95888f69b551a4626f4ae712a7e3f2a5739e0f0087aba716f43826e38b00000000000000000000000000000000008a3964da6261688cce2137861fb084d5bdcaf3be5e41dd4121eac3ec3db8cec534e2d447a6eaa91f3b4eef8f1f2df521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a217e5b5edfd02f6f99a5f525416932f97cc808e6988d897d7ff1bdacdb034a3f6020873549e28925108da3932d05e500000000000000000000000000000000195c2f24022b05aa87eb8ec34c664af9bb27f79931b51ca690b8799070ae8a179b7de65e42a3811706a5467ed6dc800b00000000000000000000000000000000054fb9f5b95c2e685540b840c6ce5b143f80b755384eead683a5b05602e2f893c39410138af86fdc42267255fb55b0870000000000000000000000000000000008d30063022f4ce11e7349871a1fc8a82dc310fc96dc63f68f51f50be171c37e8efcd09c4e207e648746624038fd2d631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001219e002cf573ce860c209d5239a119275adef27766f8a80f71a174a4e3b8bc78c10c9f50f18b7ec05d20642c93bdf84000000000000000000000000000000000a731847d4ead262109a4b2da537f507c47cf8bd0d223f7961196a3768f14e17347d73cef5b095ca0cb3c9a297eadfa3000000000000000000000000000000000d862192b4ccc5f928b6b462b06e277aeadb9331a7b583c5a82c8dc9c0d4824eda570447ec1433c3b7c086455c3ed1970000000000000000000000000000000014a95b3999bb3cea421dc78d6f8d52c0322670dfa0e3d9f1d2477ff3918b94d86f7f7c5a5562a7b27c938dbc3a93b9bb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004dc0cd7b46d37d091c30a0cbb48fd0e987560fa01bc0d8ffe33a425c5f0b4ce2e4be1ab954da8e005cbdf8735509560000000000000000000000000000000012aa8048d743daa19208a56224a8f833ba3bfe48d0ecbea51a7f8e577f13ca81e41fd8110108bf78b6e2f559721afe4f00000000000000000000000000000000041f51768940f4939808f6e3bdb703b9ef906dcfa6c3d8804ba315e1f979742f8876523fb34b4e39c3f43cc542b07b50000000000000000000000000000000001485722610e27dcd250d2888d86dbee47a3c19ffd00771899f497b85a75055d0f3e3fb55aba760874689d7f89dd24dd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001806068d9ce9371f8913b44cfa2eb0561c137d4e8fe75aa4f0724a82de02f6c4f3d4c56863f11d0ce9d897c6ec14c2150000000000000000000000000000000011891f4ceea81df9c4cd4c981bc8b9bede1308b814fdeb32a4cb46bb78c239999669cfc5277951ce8dc7b5e0e3015ba00000000000000000000000000000000014484c59785be3c0b3e2f39adb4bc58a3e050c88674c72ed8b70838c62e3f8fc069b71124cbd7325db5e2569d06aa163000000000000000000000000000000000b61153c4e58ea62a32ac0557c8aa3e1bc63acb30e62d48e1cfc2df2736fe65a3e9b77780a43081ebb987b35378073cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001596eb58fd2183ce3fbd12a453c2709e05ad578864bcf4319023a8d9130d1713f11d9d16d876cace8dcf85debd45b4c80000000000000000000000000000000019536767c164b10b490ded04d887e0f9abab3aa9e3ef41e943c6ae3c5cdcecc7c6f35a85bbc1c24c87bbce0917ecff9e0000000000000000000000000000000002d3561d12140f2a01ac12ed3266b4dfd91bdee8e4f2e5cf3244c46012ca778124ba966e0b5862309961396695f2ab8700000000000000000000000000000000049c4607dfe57d218c111c6a550ef05e6030dbc8f66a9bee77d2c2bacbe8795efdb8523f3d7efb277faac75086f329a41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000034bf7bc3f17a83272eb2b78dcba1a1561371c0067c0906769e499d3f7163561e5871560329581bc633721fc82fcb9800000000000000000000000000000000198abc566c2b50647994cad427d64a6bbb03ecd6cce2ef503ec88159bcaf161346333099b58e7a8b174afa4aa33d9b20000000000000000000000000000000001561a63042f604486e1a8588a2aa1a021c0e971ff1ee39856a94a6d18fa0d9d1d0da19085bc5e0b1c7274ed2974091320000000000000000000000000000000010703d5ead1b741421abce2e23c090e2621c7c0fb8ccc2b1e7a20ce23af9f0bd93f89d4c8d6ad47945e3655610bc01421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ec67a203a192d981b8759b259425aff045fad249a769c0bec107745a199d31e1b4ba40d19c1208b1b532ae6d3b0cd80000000000000000000000000000000008334ed637b214f5f33c0359d6540405df12db5d707160d5bbf642256d94fc2301b6257619b8f8aca167757cfa4f24a10000000000000000000000000000000001fe8523ad82924a4143e12c03757ba53cb479a51ae427e79f91f0de469cd0fa8ce793505729706c6b4de49f43b3ccb8000000000000000000000000000000000abf6764c325e63b010f83c8de59fd3f0bc811b01ce43739015e3d352dac535f929b7ff0e6e2791f4590eadd10bbe04b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019ed60136b65c5df608c4c5eb0e7f91ee80c0233642013e0e5302c4fe3298ecd821445cc60f9ba4e46701cea1b3981210000000000000000000000000000000011ea7eb246d65dcb87e53c9f42ef0b33a419a67a349b3c3fabc47bb4abb84ad9dc319ec262fff0dc8a724c028b7e3ca1000000000000000000000000000000000b909897a2e0f0099996b70854018deb89de6bd6f1df5dead6b678332735390ca6301cba1367e63f4d42cb3e6668945b000000000000000000000000000000000f5cfdc46bbfa817a776d799f22c8c4c9989b65b3b188d9040c765b31acabb988058f8285e667d3b6c8d69aff00a1e0b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ea8cf19f171bffcb398a648ee7882827870759fc3c1c14743b5f16ddb43a99c58394d52f792b2942c3488c55f86aa9000000000000000000000000000000000a2b8ca69571212fe07b89f7eb60c0e8b1f14b78601ce03107fa23dc9d04ec5c80b2cd7643fcaa42d4951f072131a41000000000000000000000000000000000124054e8d823ef41517902422d316969faabb314371f88e099ada9dbbe53a1bdadc0def8eee2399cbd7a1e51993824fd0000000000000000000000000000000017e2c1c1912cbfa38ec772ee45673e9ddb00416ba62432c756528c9bef3868fe14ea5953508846d623dbfd74715841871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ba63691d45869210e4d5c88c4118656ba39b990a3e84d2d4f307a4505c22e877ac9fec6e798eb77a101b8418b24dcc000000000000000000000000000000000497173e0f3babc0301e1380bfaa9725b5965ff0544f64bd9e53efb47fc7d91dc55383d03b0b262525c725032a2e847800000000000000000000000000000000071559248baa95962c3b6ab834b1f785fcfcae2fad1323b4845b589cde98baefe28b5ff71ed99391549835f08afb5806000000000000000000000000000000000554bd633ce9c440e266760dec954d14074c4fd57899bfcd9007959252ecdda9ae63996eed30ecf3b4c24e8bee6d5e361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004227229e86f6f395462f00d6c1a7d380684d6f6d08e2a873573cda75b2b856164d86e675489ab70727475180b83ea6e000000000000000000000000000000000429e75169e9848674ce1cf7149c6f22a539152283c2bba38d1d9546162a1e5f1f0010636755a0b1e7e4cd012e0abdb700000000000000000000000000000000150733f4cedbd2fbd9649cce0fab4337f7855a8a73ecd406094505adda8107f234e7d36e1018cc67c1b4bc839d056a7e0000000000000000000000000000000013a2a21696c04cfa8bf099db8fc352417f54b289688023ac7e911f0c6a9ba21bd15d0dd39740b8143e44f9abc88188d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016885004c57809e7b29fd06fc2c207a9280bc522747cdbcee3cb94362eef81eac9e864ac8013cb5d5953bd1be19dfcf6000000000000000000000000000000000c6add91546fe4fa27f7a164baa2f8f3b4d93dcee48177f131ad83062da1cfc62673050bf486c5b1a47f01bd288b6b3d000000000000000000000000000000001978f26a82445aa10891d0fee103ae94e60bf1a72cd8029656eee28431235ffdd2dcb467d5f936d4e5a6a258cfa4cc94000000000000000000000000000000001822a2574af71405218269e841ac6a3e849da45ad9ce95a27e7933cceb32846fd945b157ada4b670d9cecdacad5cc70c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017e0ab193a264c7199250d280aeb69f8d99b90538443a4174b0fab1359cd1353ab5060453345381344a3397a642b6cf5000000000000000000000000000000000e155af008ed3dafd0976f1f50d18aed8bfaa859a1f3b1804b07cb0986700f2b9e3703165b6482927d5b10803b32b5b700000000000000000000000000000000171af473540c901d42ce187611fc099c6296480807f9825335e0d243627161342ab96e02e670d4efe7cc9c476f0dd411000000000000000000000000000000000370e24d977a0d91a1a2395e504730a26d2fc69a37427e371df8a8e842f94ed355b1cb09bc5b1e7018fcbdf7113f70a61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e3cd5caf573b0b8435456b7db83968f1f86743cfdc2c20ce6c49862f87095c5c8e2a11608390cd6023c1f7171e2385e00000000000000000000000000000000126c0e6dde86e59546630c658859d64c39bea882dede4d2a24f12a0f227071e8457a16f901cbbbe57e01b33f0df7fc9f00000000000000000000000000000000164b399c2b8b049e694bc7077fae3d60449b59e917236430a4f26bbb5a409078f21f98c35de7c265b9cd18c608be760000000000000000000000000000000000184eff9698c49a589a1295e4e4d9b34ed4a8022cbe1e74c97c501519f906cda51b45ab5004091845399c3bb5788b420d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001282b4bade13ac9beb21c0ed9b0d3ea584902b3c21d4fa9dde516c805331971481bf981195983501a6ebd28fc042289b0000000000000000000000000000000001ebb2e77e0eb0143e6b8cf248f725c3bdba886241fd431dee11c038532291d8b1c4fd2e7afece625108d4f4fc5f3a840000000000000000000000000000000005715d058973e4ba63a5f6ce8fad6f9e5336dddcb585bf812f25e37328fc12523175ebaec670086a46ff43a34089d85600000000000000000000000000000000051193b285e46080024ba0299cfedb52708ef5a6034f063bb35d4a5d3049301e8ba47702b85fbfd60f7812e4fe1938651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cf040ded64a384db949a456fbc85798e54fd850b1270c645bbddb6d31747a4a95d2d140a282e1047cbbd5f7e7024ad4000000000000000000000000000000000fb86c3885369ba3b7b138b085dcfd6b3a8bfe9e515a24e51fd98623419a9cc317e94255b7edde66fb5ba862b07eeab900000000000000000000000000000000003fc6c6a35063a35deb6db39c32251310dd7f3b4113832ca1511624df08fce6a1a0baa3d2d3abc7b925d36626e9893200000000000000000000000000000000167b67eba366380138b2631513d2a8c8c5f81fd8bec80fb944f70a5fa1de8450d6d8c69c726156a30d2871c487a3c13d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013b43a4455af23d4190bc53d47f0639ad47162ab9f764632f9d665d173c304134c426fb1605b16ba1726e4bc937cab6e0000000000000000000000000000000004e74ae6145b4c3e04ad2616ee57fecb6edf31111d570ea8a0f006e041dbab4dbbad1d0bf5ad9f5325d5e7e8849276b6000000000000000000000000000000000992e978c1eef0d5e3b5ee5d183cd923a016098536d54b53dda5fa850a7aa8e8e1e0a60e64b4495486e4cae18c51bd1400000000000000000000000000000000169323a1ec687f6e734d77c5de493ee5b092ad5bb1c524610e48f9729ffc3fd35bec3944071c51828d8a4365108ac9b01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000047b15d5129aa3b51e8677e28d7f42a4c4d2a5d3d0921e174a6eb165a5d96765bc2f9f8e8c38bca79552848d2e9f738f000000000000000000000000000000000c340911aa5db25cc79b264caab3129697712f8136c2e723425223ee8456ffb08db08d694a36aa59fd223b5cc95cfee7000000000000000000000000000000000e82e27ab63d757a9b90347145e6bb7de950754bbbc915157f13156da4b9492fa860073ef15c1e28f6c7a0db4099038800000000000000000000000000000000151176932c72b7425a7c6e4d6f570a853bde1c8bdbbef40f18a743bb100b4a037439314b839be3b246f32fc8eba174f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009cb0ea143ed1edeef1a4e2b46a95b92e693eee9165dfe0447009823b134a68af564684a1384d7b0620573001f9ba1150000000000000000000000000000000003ae2466b28224a89eda1a6b3bdcc9e891a321bcff23c204d9519f29f2fe5b3f5ddda5ef80fff7f23de6ceed5298ffae0000000000000000000000000000000015deaf4751dba2071431fbbd70474848b18872cd6f6d7158af0f067b4c4dd5babdac7ac68360ec4bf7d8e61353693aa700000000000000000000000000000000083f6a38fa522a9fafa406d49a5f0fe498c8a6a52d32fc19590bd78f8ca043ef112b72a1de3d15cdbdbaf6d88841e6fb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009265979074f4f889c34e9c48010118004954a5a90d84064501ada8bde715bce4a625116b920d88a22df6b9ffd008a4d00000000000000000000000000000000045d98fb750ed9174977642f248c70aaac20da2d24bee02e4e90528fc5abe44689e26cee2343d90076dd4a8efd95f06f00000000000000000000000000000000070ed8a0064193d012d85ab3a63f32bb9953612ac1aff8b0ab533dd4fd12b93631359a28c50244bd31cd534364ba7ccd000000000000000000000000000000000b2d3c512f019ac2f14b3b656f739e1f5250a0f8149dd7ed58452477ea2c6e4c63918352b93c0d5bc998b782f132984c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000018826051ee4040d30cdab952b102a527dfe311d98863e5fe585bcdd6931e522633dc536015e77f07b29c89ec9ce31130000000000000000000000000000000012a57554408570c3025d8d02a22c1a73009e2f86351812529e12f7d54f6b32dc50deb47b599b7c5d9c6c71dfa1fdbcc9000000000000000000000000000000000e2e64e5d507ea00756a121f988b58045dfed499384cb0d7e19011c43a230d9cfc0d920e12d1ed6970579676ca4905300000000000000000000000000000000009184eeb95f3a7c0d0cf10555231cf3bc09d3cab40fc603152d4fa4f00d7b533f486486d671293d7d290fcd601893add1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cfd112957f6505f3108f08863888abf525f64118d7a421c98d8551a84f77f348e9171aa48dbc39b5b690fa5df9fb12d00000000000000000000000000000000093d89559bc88a157ce4667ef2da6784e6cd7bf19026914feb09c1bec2fc5d233187f07ec5fbda74f863c2feda8327840000000000000000000000000000000013b511ce2727c7bed5ede51ca520e389b3e23968f47b50264ab4fd9a9179c462c05a96fdfbb3532167e270020fae863e000000000000000000000000000000000d2e6506bfef756c04e9d3c4b9671103c76650bf011f3e9ad372c545dcf8736666763c93fa6e7e859ef116ecdee31fb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5e8897efb30169c85c346a8bf1c51be5ef283e353246744af4093847cf3cbc7433d91dc16c86c575129a0c928d3b170000000000000000000000000000000018cf36b7cb42ab433d55d788ffafdf038d19f318fb6df9c2f344e8c780256c6fe5f0ab07baca6b682be88d2f28af9abd000000000000000000000000000000000f3dc995c84dc8fb8cbe47d882d483c1f2fda52744b9714d0bdef3c861ac6d4067749150c1208dc3c9a3da6aec5c0f4b0000000000000000000000000000000004d735b846b627b9683f88f82d65a063ef7c7fea5a51942e47d6004d7b24c8f27715d6e1a66b62226f7c5b02c4449c451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e38664c56e20b34e08e5f8fc856282078cabbbe0a207193fa7eedbd5f37db403ce077767e45d85f9a1bbd6b14e4056400000000000000000000000000000000149d6686cdef272e5acd31c507ed46223977a41de9a9d4acd01dc4b68e2d743a9e5a8786eb920495974f9119ff7637b80000000000000000000000000000000003dab75dde3a9db93920d92ebbb7743e026887fe4807a42d4f55aabafc7ab7d2cba7d3e4c86405dcce8acf5e4280c1c5000000000000000000000000000000000b17b81ba6e9cc6684ea723790da5fe36786f2a541183b7aec2f1660f7f0475edf34425f0ae24d243a123aa87ddc0acc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010ce789b7254f9f44fce5de2c166bffecea342150f66ff47472a2428d767756dc098c53018970fd18718b39352c98d1300000000000000000000000000000000117a853bdbdaa0304132440c4dabfb48a04e6100239df9c3c30c6d408cedb60f1c3875da9da472de1f7abceff52d7f040000000000000000000000000000000009cbfe9a411c3bd5a4d6cf7f2b1e392d65896bf4a98e4e6bd2e16dea7d7365f2f777639cbcfe01a41858bdc01540941e000000000000000000000000000000000269f187fb68af2dd9d2c89ee6b42ed1e8e52c01493b4f949d9c3e2478092da425e0a7f7ef3d8ab87511cda32aacfb0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008b2a69e0f50382feb6a52bec5a619a52af2567a71dec7df9733dbc1563b9a752e7ea037f81da573e070e55a1b9f29c5000000000000000000000000000000000f2590761eb3bc0016d9706ca5951b70c5a0570494e7136e1b9d2ed5f4f852c1ee8c80263cedb8ee0c7d06e76479a2e600000000000000000000000000000000076281189c987570697535506aaa7f1637e5f4ce46ba9cc2ea5db0a902b508c7b13172bb5787d5476f11f8d7770f526800000000000000000000000000000000047ff3ec2b995c447ffc923087edb1591fa3c0ea93a632eadde47398fa0ea0a1d3774e99b5d159d8f82c0252f08093371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d79de5077cbb627c5a4bc6957ea5d00fb5a97ee91aef69d8d77e1b8ab105b099d98fc1024c1ad219de4316275c9e59700000000000000000000000000000000166f2820053055b369b667e5402b080e0cef6b5373302d03861ce02b9270530de1966c8ce87487027eb416fc82278bf0000000000000000000000000000000000aecabe7773b36a21d1de641d26e13788df5b395c61e94d6aa935ef3e10b70a75fbbacadca94c62f780c7ff62385c68a0000000000000000000000000000000003c01c8de89b70754cabfb6f00e29b62c4c5b1f7b9edd06f7990a7f9d032beca685a2b68844b3b399d74f483e9acb45b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fc29de8e6307b77c2c08484e26adb64266acbc071f2f3a43faf7f4ed41ba2f954389a357b5abb49c7a9bdfcc95cce020000000000000000000000000000000004fee77a61817636917db7d8f03babdcff8d3d1e139d8874a1ad6c3995fc3d58969ec5c219d76bc4d8efc2146aca513800000000000000000000000000000000197a1304de74431d6771f9e38fbedebdaca6d8830a165ac289b012fde61418a8889524f4319a3d9e5e4c0223ecd063470000000000000000000000000000000017e6011a6d3cbdb9891a56fa7ea32ea2d89b49b1ae5739dba51dabc0035ebc90b7ecdec4c609fc0034b26f408252c5751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001429a08cb8fff05e88014c2729808667fd9d38bcf1b6f405d20c4471d58fcc68b1cea316d8c15c7d0aabd03d7c5dc675000000000000000000000000000000000831a636f98491333e71b86d86c75d2bd959c04df0d74c3d96fcedbf9c0a5139e88a229b20a8fe52fa2910cfbe68354e000000000000000000000000000000000b3f5aacced744b4f9a85b9a60977606a8ea5b6f20af32a5c9411fad6c7bc62ac4fd79c5b25c90e74479f21191ba4a730000000000000000000000000000000001641a095d25640359111cd47b62acd27318a13f519a62cc652bdca8fa5d45c50dbfeaf4846a9e55428886998cc895a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044ad2ada71dde708fc35e2a75d4c92ae61b3da6187fec5a51777c1cfebf1a00ef24ef5fe71678bc8c756d9e6098871c00000000000000000000000000000000036daa00011b813f90faa3a28e5f7473fd0d0a025caa3cc2eae3b07be9920bbe256080a0c2745e72278381391af67983000000000000000000000000000000000e7f2ee200363c3fd0849b80984e5418535c0156988ad4be3f682f01c33ba05c537371345569c23325c5544f95dcdff9000000000000000000000000000000000d50102e87276992e31aabb20431273357c2dabff73de366a353a0e42c0147c0d49ae12d706157aa40b9636bc467b90c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000005ca3568c7e0d73e64ae72a9569236e9e9e7c7adc75e33ac56c1b11e3f8578c54ce180e4fa093b1f51576fafb309f7b000000000000000000000000000000000d5dc3d2b994e1da6541c68ece2d4711eaf94edeb19fb38b6a5cba383f58e9a064c482549fef4e373fd91ce778f38317000000000000000000000000000000000fc4d0c677cfee9213fb03d0fcc870412575cd73694b6d2b246b356692b55791e1381940a98ab6f8b160ec683334261c0000000000000000000000000000000002dfea3829e250bc04ec481859be8b5e608648488a2abad8545863b9e186afc852b6fa7a069cc4cb2c842c92ab4bcf4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001189ab183dc1e7652515190d1a536be552a50c41c468b1ef1a3bf03c2d1bb4b5604e44fc5c941d585437ee3b902405e3000000000000000000000000000000000f57fab0149dc21cca83403628f98967dd12b3ed6249c8571f92d61ff73fb613ec84f5264775155b0f2afe692fbf33650000000000000000000000000000000002bddf2be26219b8a80ec130ba3c54d9df1af8eea8f588746bcee0e0181a11dcacc27df2ff6c7832c8a2d2d0b1e398b2000000000000000000000000000000000d8b552a4c787605c0b3148c9f01458ca5e9f302ac33695ccfbc8282d81b4c733433c1d9f7a78fdd61b56707b7c26c0d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f4e120eb96e7e5677b3d884791b78d2deff8291162c85d3ee270dc2947cc7c405502bc615f0e157b33aeadfa08811700000000000000000000000000000000041e2cbc8f15c126dc192997e7efcc056d96456c5f828d274fc9e054bc27e3887e33a092d48af4292c90d7d4f04e6e650000000000000000000000000000000006fd2957b52b4568898a6d52194d63e4833f78a97cea4daf25157d13f924704c668505ec09212f57dc44acd698951ddf0000000000000000000000000000000011a40b1780f38293f1f6ea97e84145b579e65da1abb8dea94bf1138c6b263b7574a751cf88ea52efd3419b93b08d2f561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000102a40a6b52635eb364902e3493a6485ac2fd17688b0d3a62b101ce7b7e169c0018e41442f5d5fb6244a06dd052c5071000000000000000000000000000000000f21db1db74bd329ccead2e5d0a773ac478a4297af923e1b2567c4eb2c0ec9308717b711258dbe23b4505f834772cbd500000000000000000000000000000000106602979ffbfa5806033c3b15fe0fe49f81014f76fa5862b187bc3ac86a7e42b9163dec24a38d3002e9969d405f19af000000000000000000000000000000001656a6f5bd0801b25b06be7430a411749848de631e1896db3a9948ddd5e9474792516c9083e34e3a055af866564762131824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019e4477901b302d1e6ffd3279d1595c26ff5e6556c569323bffcc16d7e55b06377af946ed06ed40b783f828a02c60366000000000000000000000000000000000f173bfbcaae854e0f7cdca127cfee99cfc84b57b114006f7cc2a1604f8159586599a60ff807150bd9a9594e91a33c1d00000000000000000000000000000000107c48b722f39dc8431bab90442248ef84bacc0e67718f747adb083bfb8c40b9d4e38c13eaca7bca9846753193adf7ab000000000000000000000000000000000cd2418be5bbdaca2a1603a69e6350327f5292fa8a9e8302ee5660aae0aec1470b47f8af1ed5c7ee1706fc6067c882cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000168ffa983e03e3d4ddbc9fe80fb51be3f2db2d6819a1dfb2c96407c4be7df51f31a06c03be8af084c3264284b24829000000000000000000000000000000000170c5c3a90e560c3e5dbe3bd4e5eaca8c0cd46f0a19516b0cce13919ed1054467a697774a49ba359c47aa117b275635d000000000000000000000000000000001077a0e3866e662faef70dd1fa854ee5b12e92038e24dc55a24a2b3d893ec67a4f13b35a985408a881018477ef31c9930000000000000000000000000000000017d40135930c4782b10f269f5080b65fed4f12193010fce4a1c161c34bfce3142fbea24aa23fef48b2d908048ea3a76c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df8f3890285fee1d3121a786b933e0b35fce71756ba98d1594c1e5c9bbc51c72dc4c307eab7a84ee97acca1045cbdbf0000000000000000000000000000000004e98ea549df24b6a1adb6ad3a6f01af4236b0c271de9fe95e8b9e8ef21283b488f9754ac67a12fa975fd66d595721ec0000000000000000000000000000000019ffb12fa5d0852dcc474690e621c0822ebbe57f44cdd2c515c8e64c152a6240b24f7d698ae1ba59ae69b745ec0dde000000000000000000000000000000000019369898dc67801a5de8b70b190e5bb36625dc7dc480b2992264d361c1ca1ba5036f39df6e7d4a9a79272d14126308831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e096cff78a1ed89b7ce9a048affc5b9fe1cb26ff9c94798ec6436e4f1bcdefee7eec2d6ead17fe1e3e8bb5b4d7d900500000000000000000000000000000000194a60031bfa005e5e6e540163c27db047a01f3c84478ba220b7ddad67e51b50c45baa695c96bed44bd5da5787b199390000000000000000000000000000000001dcb09eb696098747e28a11739ebc77d2252aaa50ad1ad28eb96f6250f1d16f67b785949cfdc7a7cb22363126673abf0000000000000000000000000000000018a063c9107ea44628940784fda8f52d092b5711695a14b89e42ad090b9c751aaecba0868fe8332dfd77cf71625185061824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a670b82f948e1d447c46b2a59759232d2639c32933a01586af0f85b7043b2aebd5da0e08427d6d7d7e3c3b2e5a37a4000000000000000000000000000000001883625bdb964a19b3e3e3e86821ac3a0a17a04cb3609c8087caab44d9320b552e643e53b33485ad829de8114614b2a800000000000000000000000000000000049cdcdd6f4bb89e86803d643d31101aeac5d7f4405e655eb5eb63cc4a3548f2c2b92261bd7a2fb1edd15f310c08f19500000000000000000000000000000000113cd3aece00114467c3e86bf099e56edada7e14442d864a18884bfbf2e5241ccd4c0567b78758b2a26ffbd978e855141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013399d0573f415e333518f342b3f5218d27faa6091caceee8dc06e4b375182d43b4f5cb0cb1603626d8244166b33f4970000000000000000000000000000000017825ef803a0a43c4f720fc29ca1e22d7116977adfda34ec7f6de95708b3b39695881422318e1fac75db7f23c6e98ff90000000000000000000000000000000017cac54453562899bcb5faa0ea866c2365c1e0a9afea9c0527b8a17a2efa654b40a1ffbdef7358d386a1e8793fad51ea000000000000000000000000000000000d129223d0a3b612fdfbea48fc88e3b8fd9b1c383f534a06404ef23ee22dd3ba931b9c1c3ca3f7e978b0ac7c8c9137901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b5af8e8953836b3888803ca1819e4f949e74612f53f96ed0bc3763e77c6f192c67b383e4f0bd8f6867b40c15d1cd8d2000000000000000000000000000000000fbf6658c3bf26002730cdc0dc85371999bb3bb4e903de453f2f300d92b3003aaa0f843c5d39c7c4da28cd5b25bfbf98000000000000000000000000000000000dcf78ee8860f5dc01fe53ba4b60bada638902e67334dcc01088e8648e30355da5c8e1de2885831febfa48ffeca0893500000000000000000000000000000000049b7690ac7708e7f36f7ede214f53540e79dd586685eecee76e0150d45f9b103894d865dfdc9171e126e03208f983831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000057b61a050bed803835d2af0031547096661be9f3a29b6f71dd2d5db9484d6f7321ffd82405d156727b0dc7f2cadabd6000000000000000000000000000000000d25a03e12c5b5e4a69f8f7000881cd48259f4e9cd77a38bb05973c3ca74a6adf2431a4fa8385c5ab5769e0df9fc48360000000000000000000000000000000000411057626036cf7abec0573906e8aeedca814486ab45b48802dd5f406594df2e38ac7a706a5702fe995bbe45581d2600000000000000000000000000000000037d4ad9f294eb2d55b99540aa71141e0e47bb62d68502703a19fb1291cd702911be385e60ebfad1a4fcdc1809237eb71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076762c73c719700a43c451c0ea37a0d2e07859b7632d25ed9c219ac2f8cd573289ccab4362755d78557076978261c43000000000000000000000000000000000126f61c62029d40527ea8d06c29dce68e88531c888e626f863c5529aff5c4e95f011719581d7bf59554d6432bf67ff70000000000000000000000000000000019520e2daa94b8de7909686204d867fdd9b40d9b15d08cae1769489248d790ce6c986288ed2ef1a3469c8a570591842e00000000000000000000000000000000186b7cb63c012ad06cf575b810966f9cf8e88d0b9478315971d7e4700633977f9fa05a3bc926abc309ab8648d1aff8561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002e30edbd003a8b1f35e5b76562284d80b9274495e85f1b78ed8a591fc09bea8ecb015c0316f8821493fa6aaa5fece80000000000000000000000000000000018aa84b77df8c602f087afd32a6b1b4abbed927d57e5b69efb50dcb5229f5a91aeae8f0277f337e6ddfaca145ab9feeb0000000000000000000000000000000015ddaa1f86eb5c20a22a3390284a63f6e14584b22d202117d56155fc6bc1ac63dff60bf046c2af69dadab0df5d730db70000000000000000000000000000000004f2558c5bbb70263071cd5b998fe03c0b1c91d2dc74fa8c5211d2b7257578f99756fe1c425d49dfe0792adfe5280ec91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3ebac605ba794db968286e37279af75bc5b09af7a89463e9fe9382544e1002edcc3bd9b39f501a34fb7051e97fa3f50000000000000000000000000000000001dae26d6dc63e56aab94eeda509057fb70e74b1c541f17bf6958c2afbacf400c1b08408fa6d18f4a9f9d33046cd52ea000000000000000000000000000000001139178537e886e646778fd28b2857d2838e8dae68a0ab63686e34b358ebfaa880192cbd4a8e3a907bb928235e1b78d600000000000000000000000000000000058ec20699de411e7836dd8b285dc2194e643f9d5dac715c886c687c7e0629f849dd68d8176a2285f1a4e6afade67c931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e7f21a14a48ab0ba4aee91c0625885d6b01460fc98b266be345eecfc3cdf1c34769a39f63f4668b01ed27ae507dad6c000000000000000000000000000000000853707f89785a2fd0f91cdb91a3a26eb945dbc1004c5a96739712ce5ac5dd718fd63de4b2cd1c41575210ad5e557649000000000000000000000000000000000a6b1a644e87bdfeedd7d5f5526470df74392c3e23e20b4fe9f22f3772aafda3b8185c36e5284b7cc25f257587a91bd7000000000000000000000000000000000c89bd84eb387935d59cce4171f00a590ca7007ee760d2581edbfce8e6ef8b2cd2acc22351254b0739b240e6126dbfdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000069a0ec0378935cf3101ed6e52baec487477103a6fea80dcda112c3882b31feb45afe4c4d16f96b2e286b15493fa693d00000000000000000000000000000000171d6127a632cbdc8db25e389f60c50ced77989b8d6c116807bfaf7891d460cf287209f9f98ff6b28c118b053f88ea6700000000000000000000000000000000061a6eb11eb9c532b1b08933a61b9067957620b6a0d90e42c48d887509965dc0086b508f37b3bfe93993222cc2dad84600000000000000000000000000000000036638d40d00d948002019b937eb4936fee10601565d324b7b180b0e3ac404138f0d266eaef281be8335cb99ce201e581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001359248cd0bf470c91e2c6707801cb1c663c12204fb2539e04cb2cbc6ce5e119866827f9ec3d89cb7f42729a1bfa5aa40000000000000000000000000000000001e93b0c7438774fa8c7b5fb6ccd58d648247572a38a3b47e3e998efcb8ea1d5cf53bb8f15fc52822e7ebfd238d930a70000000000000000000000000000000011c18f3f677feb36217c1824d9e316c76ed1baf6c8ffd1f938f01b2127e08554851db4901563a5849bb3941b19c1c7d60000000000000000000000000000000008e470e844f51e60e6f744d4426755e4e97bb3639c79fcfd2fc3c60fc12f82e239e654287f6a0a7b7af4ea2b889be1211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aceff7d57bf85828f03febbfa81e512131b9d4ea6cd6a8b466826d3d143f0a8c0147d1c58a35290468cc7f31dc8d6b100000000000000000000000000000000151147df8066284c0165220ac8bbef374a91f36916aef8d2990c957fb34a65e685f4bff37be438d02349d5302c3c7f50000000000000000000000000000000000c5a9b5a3872ab252fdd2ed190f079741c2e3970c97661ff876eda3ad1fc6aafddf4502a7651e7618aa0121a957b49d10000000000000000000000000000000004433a3d4d5f2fc29c141858cedb63354fb863ed365b2c5a03dd96929d37c46f0959ff37463466067476e0f932c387cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb0c8ab6e2b98c5f9d34de3acd3c50c191e012f89796149d8a95d4ca7a9a118541995757e0e1a725d837a364233e09200000000000000000000000000000000181728354e822ac48c67b3e6db100645377ca7c92893e0b599dd350b81bc301aaddfac54e824089a4ed9792e6f0def3e000000000000000000000000000000000563af6098beb4815eeec530cf08f50342f066d08d268138d9cdf5307e284e5a6ddce6bcd0242e00570aca3f13e5a825000000000000000000000000000000000d263de0cab6f2865c75c6f00e878633d33baf30a0a8bd7b637ad786b6511a3bcaed6f86d1c4cc8c8bdf08d2ca9efe6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b098f261f7b36be73527f17037dfaca7d3d7d0654cd8eab5347e00b7a43732ce3063d3dd448d4909bc1c24f35293f240000000000000000000000000000000013ec0125601c2325c749281495841ac6ecc27f82f0bf84a907e3fe0559f425e1cf0b4e476723d6c12913706b0e10d40000000000000000000000000000000000115b837546fcf4eac8f35bb6c33ac3af2dacb6967b5f2b4062575646815d88df26a03b971f2ad20dfb10f18ddc0de36a000000000000000000000000000000000769941fa017e11bb61d304d445c4a6b5f9c012af2ebe84eaf5de7e7355f9c979ee945da67e56f4144cd80c2c5c4e2301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000267dba8e4e5d087d44270e623761c7d11c9d00488433a69233f171c9d8a95acd9d38b9a015b7d116ab76b2b7154d2b1000000000000000000000000000000000845f2b24916d1547ab0be03681307219f896cdb5b86fc1f0e53c5b99a8b92b3df5f7fff112fea21d1e8dd940a938899000000000000000000000000000000000bade5301578cf7c77a5c7e01dbf6a42c46b4f01c2d8f386d522b649c8fd03b046a15a19b1cc45df65313b91238a8f4f000000000000000000000000000000000686416d563d90b506192987a5108d094be3c9830172b4599368c4d15fb2f3302474c8db966bf39f43a0ae0a7afd9d311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ddb0d375b76ed7a209c4256be34324730de9b4fe138659a04b4072ec8a39c61bf49b310638f32cb6e4a9a00ee3081b6000000000000000000000000000000000c9a88aea70c3f1de752923eb586923d100e229b032d95b64c64b64e0bb8bb5d66a8de7bce337e94654c99c2fe08fc61000000000000000000000000000000000b00d25fe797e0f0853d05f3f680c8e71ab0003405e23d67e700b26321a49715010e09a4e9969b2315df28420337e2ba00000000000000000000000000000000181869b308b8208570c245d211f54c63c8982a5a49bfd738586903009513becd10ed89270c82c2e382c8d7798940d4471824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000081ec49df044de2aaa613504cf465f72d4ddae77ab22be1ba9ed6836d52babf265628d20bd6131d4be51aa8bd66d0ca0000000000000000000000000000000001575f94dce5530c8948831ce62e9bdf11b5fe74e6b714dcde95614d2087116f505126b68e929c6b6616e625cc07571bb0000000000000000000000000000000013617d667d380884ea04b6709f9046245e7781bbf171f32cc0c533f87f66aafc5d68a7ebb97a26ed948482f7c42e73ed0000000000000000000000000000000000029eaa93844a3da0c1ba0a52d4707ad29175a678439bf3081739117daea7f933b0a4c531d66036c481a56600e3092c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001689ec130c40431d438e491ae5a7bc87cee09becd88ef0e0648d8e8248cf4325c0dc982c6d0e20f7ce192a41762188bb000000000000000000000000000000000cc158f444af97625edf850a4c272d1c7b1d255030ba8b1239babe4e2c2671766ba6adbc8d062de205723ea7625c9ac900000000000000000000000000000000189ae15da3403ed35ce5d7ec407fd7e1247fb10155ec49ccb86c160e84212a6d47115e01c3ae10e72dba94d5f89f930b0000000000000000000000000000000000a3a7c128a2f520c53438ee70fe50783681072c95815027b919433c9a4b028e14236f6259bea12ece2b46e35fd002891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a4214f9de7c9843d047ff728093253cda06a23fda6720b690ab26845a8fe35c5d526be2670fdeb3e2e278fea80217a000000000000000000000000000000000e2ec56ef65c82af4b0eb1cc09248ac73538254b1a60035c7b7b2c845938e7edb4a5c71a44ce81c01d6f35d6dfd86af10000000000000000000000000000000014f0dfafaf14961eba9e3fe5e4d5783eaa364f11c0339a29f8fc7f94aac1ef219c61114390af6a58714deeb41d3b9b85000000000000000000000000000000000a6df933b1ddb9d120eb7df1a65f9b247e6f426f1f0a5f845b0c08ed437b2ee2c1a798997a9dc8da398fca488be78a241824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000709868729d44af981a8d77b241f931904be222bf61d69d75eaa2777c75c14fa24b70849fe30ac607c699c5d2313e6b100000000000000000000000000000000131cc6bf14bd32e234c534b015566815159596bc88f8d4b9a4805912fcf2387757cfaa011be1f5ceaa6de447771d95880000000000000000000000000000000004748caf0b67721fe17c42266be0a00ac8b7236177228bacc2a74d7009cf15b5a713f98155783bda0d0ea8bb21b47b3600000000000000000000000000000000020af8f341527d18b52d39dd221858bfeeec5e33322a08d5b330aa19781ab2901fc6ee9475c6cf4b6d84ce72d51512211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000144df9df4f9f3a274aa347e7a9162bdded981db496f48aaaad98ba54c3c793bb913ef27abf37a1846cb1dcfb2e276c1900000000000000000000000000000000140041f093bd58eba0438122b980da002d1e5e4d71450c00ba63228c14822daa702e4c3c412cb7b4bbd57c92ad3035000000000000000000000000000000000006324b67a55664f1c02361d0f01183397241c14b90c098c3d00bdf8c4b1ca2b26dd8257b565010cf72641628640d81e600000000000000000000000000000000183b82b62f50dee386bae75f5e24e13ed452347dc84240035b0b2221412db58e79ef2ba68ded05330993322bd57918071824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f719bb31f5e1f79a45c12230d3518463c398d97218baae01ab6c7d3f140ed3d04cb7dab2870d811202562bc5a7783d5000000000000000000000000000000000f2fc77e2a11ec4f0a9ed54939cc74f1f8fcbaa9b73c371f58ab979d933570fbbb09a6721661ff2550a526492536bd0800000000000000000000000000000000003b6a4c08f902b8353a0bc93d001d44e626bb0e7720ffe83680352e4ce238129de015f83441a467116337b9166f3739000000000000000000000000000000000fcf44fb32c7f37ff02fe20e4bc20874eaabe24b721ab44c879411bca895562a8b6cc60d191c7226ddd8606442b726aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002724a829e7dafe58fa3f3932387d7c8b136d141d3c6ab18b385248f8e2fbbb91b0b52440606d26cd1b6842840b39a75000000000000000000000000000000000502c0cf101ec4b56c0e212f7783545f68f72b94aa9699de29a0c36568d9124b1ab30e9e4ddc672145048f32cd396a2400000000000000000000000000000000110c6f627595207e936fbde1ccd0588fa2fa66d47178afefe644d44c3840b5d3e661a8a1cd6be88eb49f9456f58c8fa00000000000000000000000000000000003dfa7c1b3070cdb3e31d9cf7e844ccc00cfe46a58ffcc2220d6416f71294d34885414af429c58cac0de9b26944404fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000181afbce13ec8943c79ef2a915d4db5b5abc8be9daf6231f7c8a7f29a22f304c2148285292ca35fc2f2a85f52d542cfe000000000000000000000000000000001525bc110adf22f500d8ed319db2da50ba97e66238120b3a27516c384cd28725ca67586f0d6eda2e65509f6199b86daf0000000000000000000000000000000015d4652569125ab08bf224eaf841dbc3c6a41df4adf45c3c1419d7f6d030993dfaee344d2b5ff4c5ae597ea9e11306430000000000000000000000000000000003ee7c1e38456021733e8603befebd54b9fd7c7ed06a492c108fcefffd2da512da925ac6dbc59653e2b5a526ab47ad631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003e7d1bb17560f275108c2b0933b2fbd5819a8e188127d2171483a4b830d005a950512481369e12615a407aa069fb38200000000000000000000000000000000056013cef223a6f176a39d753b35029d84b9be3e4888afb075ee3004b53c9d50c1397464f19e9c71622500dfa2dfef030000000000000000000000000000000015ffc4d1b37c21b7e8ce5bc2d0985b68fac891101253783a1584a736e35334afc76ac1dfa1042b2af29f70e8cdb2cce4000000000000000000000000000000000c69a89d0ad5d1a10c423ec320ef61f27173a7b3862f6ec5140b42551617723b59f22a1358ef4becfab338b31547295c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000165494a48107c001dac8dac9a3dba18c1bb88cbe7c02da2ff26f190afb145af687c085899c8ce8255e147709c3e616f70000000000000000000000000000000016a7dd65362fb61f713d734b26afaab46fa9eb9641eacea27416c72f4fcf9cad7766a7ba7bab90f4b9c12c889f2347e00000000000000000000000000000000013344386e8265103057b30e0e033a9775c4d2199c7ca8def995f63e1bd5cb72fc6e7f4dad49b7e8989001ff2c94c9b64000000000000000000000000000000000e5939754646b3fa1756ed1fc052d2855752de4626c47343a15663f3c1ac984e34ff0859f71c3906874ea76770772a7b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a5e70e4faa0c58fb8cb8071682b83bf59b05e15beeb110c5f64e6fd92ae0a2396e951de4d7494ac9d22a9636c5c51000000000000000000000000000000000017b29cc701f229e76c2e950618486e43e7a49a1665069369f0bfd562b6bc84fd3eaa2fade85e8c7a49242ab0b8bf686000000000000000000000000000000000ff9d5b8e8e55abd68dc13864c4dadfac324bed8edb82a7f7044f4d002bcfc08818ca34f6fcb40d218119c8f3601bb6800000000000000000000000000000000192ddd284cd3cf707d54847d93ead2d95a64edb9903934a55a661b0496cb37a82ef3d745e23bb6800e847caab5a0c0111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001673100540b2263bb43cfeef25f79203ff9813b53ac74271e511a208c138bf333f0274ec22c2de9e1d0c5b61388d492a0000000000000000000000000000000004952f3c7cb942a5cd603e9ae97fd449a5c89dbb9e4f10067009b525eecef339875d8483e470a6f88573a9501658417d000000000000000000000000000000000710cf44181450c7d921b2f7fcef0482664af80f5b25e1d4ff054723995cd8a5ec4e83e5b40c183f7d33c80898de3987000000000000000000000000000000000aa0a4fee37a5e56187da1a321f63a59006a8e79e8c96c0c8ccaa29a755c0af7e130310ad8adfee2f3af5babd32255b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015dddbc1a2fe5116c220f22b1f66f4aaf84f914ed863b4f89e633fab3e40c307c031c30e4f12e7f103793c499c17808f0000000000000000000000000000000006f932bf8e5814a429be0e14d9b0ee1bdc86b76834f90023017ff05480356d7dd84c0ac8990cdb0af048318f3ef2e0af000000000000000000000000000000000285a67174a5e62716c9007d995d059bf3db978f30f682dc34fbaf35a948731cd88b1f04997e72910a2560df3e1d78a1000000000000000000000000000000000b57de678988fe43e30c1785c8795a2df8e6f49e7c2a3e934a914fc506f52d2992a33cc266647fd884d3a5c1a5fb025c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014338a8d8ff57255377f4b50fa8a268d53c48a134fc3d540b309c560a66652d321489fa97ad4c482b49471ceb7da60880000000000000000000000000000000003b04d2d1dd8b1f7fc216b81e2c20d1dd4f382357aed9b8a65335c39a404ff6a03748d8aab545ac8683debc705f951ad00000000000000000000000000000000128ab8aabe5a12de0ca9a725b8256703a3d5071a05a1ea235e1b51a5953deb6313bbb014521f3a0803c1d6956f23820d000000000000000000000000000000000eb24ccd6830c787321f6de698ab43a404f7a47c21cd502feecd80a1d711dad6336937d68baaec3aabe31cb69e1ae96a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000099ba6f8a88fc0d6384dcc5c79091e4871f0afd07ea655cc9034ba800b324ad05cf206f17b1b34944c6af0e5e166c2890000000000000000000000000000000005ab857ad9430e00a14abb44cb43ed5654ba957a475752677f92bfe1edf18acd31460f3b63ce9518fa667cfb27ea51e6000000000000000000000000000000001175f99fd078c1b24f7952367cd0ca868dded4f7c961d12d950bf70b73fcabd625839d263c2227db1cb7b18ea20d7d290000000000000000000000000000000014dff1f530df08f4af9df5a6530428cc80c430c1a3624ddb084b84c3ec41b81b2c3e1a892d54f851eb7866b9dcac533b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c04c1aa0b9ace3c3b6bcf84e2c466e8c1874fcf483324c6808d2f3f2408da43806fbb56f0e66fcaaa4e4dde8f75aad000000000000000000000000000000000fdbb8ca07dbc7d444e6d9c3f89f6f2e9cfe33cea0b77d43537a1258bc5d63d6ec288205bcece21423d753031094b458000000000000000000000000000000001932e8729fa5bffae3f9f6bee7aa1170d57bf63abad55ca4dd0c541b59668f5b2760034ee0f99e1584126c621180640f0000000000000000000000000000000012cd141f78973fbfd0f270e8efe5aec7e5a096f219859c6cf883916d713e35d5b3f40f5cb5126654c9a6a6fc89ae93721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005fa7e94a776ca6df651eaf65bff2a07580394e47c2ee2b3c6b2779efd4077be6132961647d2fa8ecba9e1d207dd29db000000000000000000000000000000000d61ff2a81a962213875bb45cf14260398c9a00c594745fe53943f7630bf1602a9ec03b11757f3042a37fcea8e9dbf8900000000000000000000000000000000126fb94bb500eb760f0ca93ecd665c63040d2b264d23573763f6c655db91736f15ebbaa63ecc0305471407fcf0115769000000000000000000000000000000001789e6c34798e7dc104a46c9ab162efce605d82549148d073cb510fcaec56fae4b8fde37329ea8f89d339151a80a34521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002b4c8c06678d02fadc3ace20e692170b3676faa3d3ca0907a8c015479443b42367d4cb564cd15258de87e29ba4ecbe600000000000000000000000000000000057951498d606a20e2177f4632cf819afc45d03a6bf2e781c125cfe5007debbfb3400f4a61cdd748aa2e267ced3b9dae000000000000000000000000000000000e074b729f8ec07b627737238cf8620eaa41b42182b93c966dd377eb1eba593ca67885926fca46f2fa29408fa9e80d6f000000000000000000000000000000000079eb0f264a3d4be99eb1b3355115d5bba6bbf83cf77ea8da18e33923f47b3b2fb0897cbd4c884bf4c4428d7590e9cc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001917bc809717f34992120edc423236e18bcc06b8d44aac3a0831d3222cc3d532301d8ecb5a4f40bbf485263383c64d300000000000000000000000000000000000eed9c45e8679807531dd7c3688a0d470b2c151e84ccddd40152805488b85aef14fac8adcea7a943cb1c415e87af160000000000000000000000000000000006c9efcff83966a07787c4cb80dadfdce96e2bf79cc4fedfe65e1c91122eda6d3c37e38047ab90d043538aaf8374e0c4000000000000000000000000000000000fc64012cf665e6c20f7a993831ec06ebf367b36b4a9c243f74366db52035bac90855e0600802a4b62e086bd74ec156f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116f5809bc9199b21990d092d1c5d195f58e7be168ad49c261ea38789038dc3123c4f93b055dcd74286c6011dc62a8c900000000000000000000000000000000053b4c190ab3c785a735259d04d23b33c321a5be985e29e90dedb01ac641c937db36f0a36d3ceb9e973a0902c8996b90000000000000000000000000000000000dfc0c99b1456bcbc63cfa571976e4181b99d13644a0a4ca01d75fb1e9b0476404c3bd5b3283d82d9d51fedfec35fd6800000000000000000000000000000000178bbac3bf05705d6265168c1fe8a0cd6dcbc93f126263f756f0e255aece8d474cb592a722697488cb894d124cfe84151824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aa2a2d4118f60b66d1726695735aaeae4ac5ae7366404a62f8ada825aa7b5e1db4cfd81669c92e2c0b284c3daa10b0f000000000000000000000000000000000f0a7181c463e30d1b35758f12dc71b99d8953e34eb934726381a72a98f8dcf3aa3adc57c4aba31f38b901911822c6190000000000000000000000000000000000a341e4af8f24ff69cb37f27a42222640a1a131b52fa83ed2863fcc2a99d02e678e60db0b63a90a750343431e0bdfae000000000000000000000000000000000f2a07b3ea760779691d43a58096458421dfd6f0eb7f150eb68953f7acf98177741c3f273fc3db86857e75f447c4cebb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d475c932cebb0b915bb9d7e0e8c13878186d832debcb7b7f28eb029060af2b5d5aa827bdb7f4d2750fd89d10fea258000000000000000000000000000000000520caf9f6a7cd2254645fdc9b6c7d4489f28078ab4bd40f36012366a079b68a3af995c66c7c6c05e9b4e0a08cc561f70000000000000000000000000000000019cca35e5c162005918693d02b3e45d6362ea66bb2b907a53e0a0d2979da7be7c8396015fdfc621966e3c9b8f37585910000000000000000000000000000000006025ca77a89f47b27c0af17120bcbbc53c1afff891949cf2485d1a897e4c8c8df49630bfa1bcac0fc77dc663d2c11911824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010445e2b83040a3b948df09e5cf39c4804cb3a8b024d9916dbe143fe3ea80dd678a165b3d7e1d707ef85ffc3a1d7b4850000000000000000000000000000000000758b0ea67585b17bf96b0bae92d4893e1abf536cf3449c2cb1318b14d10e30db1e7e203b11790743eef00904511abe000000000000000000000000000000000c62948913b675d591aeebc758a01b17285e36a4cff1c76cf28c8f41998f7bc23e444bf874fcd5af6af75909685c750a00000000000000000000000000000000192b566e3412b2b552a4537f010d2cf46a80334c56e73c58a96f39b2733ec328c0307a1805328298790820f44a75a8bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019689cfe16d252a9c25f07970c30db5c8baf59bd74c6fcb892a4836add6dd8cecde4e6ffb57d238214e66a34035e82d40000000000000000000000000000000009cb3a73b936ad8524e2e47590ed54ce72311835d4efb2211285c4a5b5be5daa5cfad58d71a6708ecc0efda47eab29e60000000000000000000000000000000017beb9d2af62503cdb05aa98624c212780889b9d13440e699b60707f4d3178c6d01305205d5a42d23f5301f6241fdb8a0000000000000000000000000000000008e7411727c49f488502e6674e36bbba6859080a4456893d4f513521f55473a9abf353134bc089b2b7eb28692c70d5de1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000004957b5f6ca75a70b9fe42bb88df63a8d6bf2f01abc52f644a886cf5a08eeac7097f49222c613710058d48aaba158410000000000000000000000000000000009790581d267738075d7a7107479f2cffe447bf319e00a6285fd311323b364d5a97ae8bece2078cf7d0ea380a7e555970000000000000000000000000000000017d0a2c1800089f20c079143a9e3091f48f6f6870f2a58aced227e60d802e8e85b3440aeb2d1b4fd3d36b9c3b53392b40000000000000000000000000000000014f9159460e560eaee29b1c78da7058efe5e1457f7f0c03aa23537c23f648b1ee592693d7c3c87b02224bed6735a457a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177ed297174517dd6ea283733d18bd6c204f5ef00601424a87dd1d2cc24a3a33e50c167624865b6e7b4c4619320d1490000000000000000000000000000000000d3fb5c56bb3f713d61e955f5e5336869649af82d6a73ea9d9dd2bca1dbc89dcc226ad52634e815486fc1f6740e471ef0000000000000000000000000000000005a44c6276945b86ddca5bfc78cfaeee16e30f793fa24b877dd99dddea6dc1dcc1626f99c47aeae79725d81332f1140000000000000000000000000000000000160c0d2b670e9caeb75e1f85bc1245119534cba3160e73db34d412057275c3d728c25206b64a33b3c624ed38ac5e997b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b0d4256916b7c7b5951c4cafb5e2511bb47e412bfe93ca3917ca6b2c6ff3118cef186d54c029b1215683a1a65b1ab4f0000000000000000000000000000000014c3b5b020b255883e9504ce92fe3194e90e4aaf3240226f2066f382096768b4121c73638baf143723e3221f26b2b861000000000000000000000000000000001792c5eefb76255cca680d20cf63983fc2449ebc0296241535ff5471cf095e6c29010e738a1102fd10c016aa0e188da40000000000000000000000000000000018786e5549b2aee0614bb9547b092d687b173aadd5d17231cb3d71aeca4f253bf8af1a00945604211e8a9e39250d53ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010e9eaad650b55002dfc25e4156cedf321dad4524fb4bede2ca949656cd1023a6c0bcbdea861fdd582b22f6d894032d70000000000000000000000000000000019a8710846ea7e0c69e25c1d7744499537bfedb3a86c911482b4b340278cfdf0c0a51e58280477c8e0e016de615983cf00000000000000000000000000000000186e518aed5ea61cde29fca3fec2155c0af008572053a19c7487617ff344b071a79f633f89881644683570256ab932b4000000000000000000000000000000001405795c44d5c04d076e0120b7b61d297d1392ee5d73c1ef300073c86146e99c726c2dee3abd8f1bf1bcb9d8377f51d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000abff40939849a038697f19932861d4a76cc10929bc661505f333e0190c2c20082a53c29494414c28b07762b2993593000000000000000000000000000000000060e7d4136ea2a93f5354e4332e338b94ea8afbeb713ad036f6907bd5a1c032ae8e6f7484dadc0cdc97a4d0f0bea539c000000000000000000000000000000000b9bcdeca3100689c0374e83bb95d7325eb55e61c755b5c2aa7540f1c63e9018d217234cc8437f30353b0d1b7fc44574000000000000000000000000000000000741b62a1cc4e2b4d8bcdd33df2b253845da922abad4b98f279553e60caa5dbee82b5129f10ffc7ff46c74a9759a13451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011c62f015bac76db98830b024c7204d1e328293106086fa76418a1f31e0d4e6d53d7a357179de03994fac98ca6f5ee7800000000000000000000000000000000104086c4d3b6449ef507d49d81b1f35e0cedf3aefd7d4543ebc237b4d681bf36ed3735af8cd5ea3d1c9ee26b8a3c382b0000000000000000000000000000000012439681e2f8c76d75b84738bdde804fc779b6ebe2fa64beb28f3ce334b411dff35358839a7ab02c35367a08dc29ee0b00000000000000000000000000000000063a68dd66f63df2067b81f51b2b1b95bc378125f730ebe02456808d2d88446a6be630cf2515f195dc70d7ae029d2d4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000abc17b721b7f2f6d3eb92c918904bc014e2de7ddaca1a7f97aae29d255f6e3f4fe48ca0f0ac040930f0e99cbd6e8e8c000000000000000000000000000000000e0054bd8defbadec7d7e0eb14710361322ee508dbcbd3b4d3c0819f14c80f4dbd61d47c41d0880ea0c8d87794169ce70000000000000000000000000000000015ce6029134cba549dcdd9f73d9de31ab8076e2335091e652519d01e3dd95ff498a784c925146a4393665cfbd18db63d00000000000000000000000000000000198e1e9e2f3c7d33890a6dd5b6db5b6c1ffe7b92dc471a537f26a08362f45efc487468d32e98339ae31f86e824f7b6ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007718137e88a2f8e000652482615281b996b77230148b54b4ed4c470053f995a24a1bc4b5faa3f06a3c153170c45d0a70000000000000000000000000000000005d92c689ffd08736f1f4d4f0d942d9e44fb2822270f80513c84640163aacf4fd3b1014faa135c0afd8d55b10dcebef30000000000000000000000000000000019bfead70a4e1d3cde4b64876da431680280d70c8451c4454b28260c2f3aca32ed533a060ddacb60284f34097022f46f000000000000000000000000000000000fa96e17d8be8a521b166f5fcac3289b2cbdd5498fb3add85103fceee1445d143d93c87f9ec9f5f6a390ce9a036cf5461824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018bf90a4bab9114ee3f2902c4cdea1f69d28e3ff32cc5bfc6e5418065293cbdedc0532c23a45ca27545e5a96ed7f0a6e000000000000000000000000000000000ce224ce4ccb2caecdc8fc9085b2717831d8252ebc045e50e3383645c5a114fa29c24bf01d5c3bc35f957f5b5ba82ea00000000000000000000000000000000016fe0c75a2a9209f603313b133aa355fb52f04ff8a01142d5a97109c9b1797d45769de74fe724897d8e05affc833d0ed0000000000000000000000000000000019d70711101fb25af1a54aad5ce24e386348d62ae0e61e11af69a7f36f815367c4f57e2335cf7b7166d4f3a8509517781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017d842fda881df718865f8b9944f0d485d158f1f013e50851e79a67269839897be046488c8704b0ffd8c92393f856907000000000000000000000000000000000ef30cbae5512176bde58cf6d12429435fd3d3b2f469f74f99f73fb1142801c4c3b895ee6b7955614ab01bf34f125e510000000000000000000000000000000001a5a0a4fcc432f8a523e1153619a5342ff344bb9084a79eef88fef94ad4d7c63d3d0871a698d7d634a462cc3b99a0b0000000000000000000000000000000000cbef2c1e2610479d01969f75b1737316afa401ddf2267808563d2214fadeeae987ef2a496c945cfd43272b50c66cade1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7ae002070dff96ae3645c91b1814d82d96aa7b84ba54d7104154e3f6c190cd3f508ee0a5d53192cc70a0c0c08ab82900000000000000000000000000000000113300e634be6ca3679abe1425737026ac0d330f69471dc409b4eb0d586eed89acdc210363ddb211382df2bd8b27150b000000000000000000000000000000001059d8e200b5ac2fa789f0ad451c3b3146a8aae5a6e9a811e05c2542f1a01ebfcf47d7bb985cc0a693e2a949f369e28c00000000000000000000000000000000092015f406ead8e680c79c1bde27efd43761aee2e68617b3308ec947c292023b732a0e4719f531ec61a0071bc7e739f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003865f377e22b6cd97042f7051c4e1d555e41b559b4d3fadc0243982c82ee6cb1987d56413b25ca35df81b80d8f5bff4000000000000000000000000000000000106d883f74bff33c0b9c2e0d2ae5c4d5849256052a39aab503e096a88e4e8bfdb805c635fa77114f56a7c21929f889f0000000000000000000000000000000001713712649164bd47203f77ea1ca8cac9eff03e579d7c2b16bc4bf49348a0ab37a03649337ed08a573176b1c33a3013000000000000000000000000000000000e5eaf92ecd6781249c4914f71887e6d12e28621eaaee4e63f285e93a22f41e288deda63ca7e40305c7a8b9772dbc4361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b28f5ec052e263b10e818435f3e75fb962da023e544dcc3014ca0d537a62ea1df5e69165bb215ebf27b26f4a05b0670000000000000000000000000000000006ff601642fbd93b29041111202ee8c2c902c783148464615d3e9d676c900530d4b17514abda99a872c4060f164241d600000000000000000000000000000000094338d84cb8f6065c1114149310b107885570cb4fb12f5ce43d3528c4e0628b2d388a37b2f76f1fa3144aa90cd94164000000000000000000000000000000000d1b8cc47a954805bef610dff73d66a49445dc7567443c297b4ff1219b3013c9346ed2fb4dbf91117d2b205e48d0a0971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e6b29457d0f0322111fceb1fbf214c8a8edbac56bcd773e4132c0284922fb5ab60c719c93effebc431f2601001603d000000000000000000000000000000000fb178cdabb181bfd15d805fce2ff5a07c277dd51b082dcadf13fa69b465f4e15091e399f459d0063d5cdc415dcd390c0000000000000000000000000000000005322c49cef01a7137ac0f712c393df7229ff74f1021ef67fea734ba7a0bcaf27901ed269836d5a48384e2799d93a72600000000000000000000000000000000022244755cce1a4b1654f56e8bb9f573bdbbd78512ead3960587a3b5a0c50a9039683294263c3bd87c3fd88dd07ee5a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012b0f165dcce1e88b9508bcd3a752fa8dc8a01e89f6cda2fd469df3454bb0b49105640303766232160c86e7a3124c2d600000000000000000000000000000000109e54d2e4c0144443b0ca391cca156f2df0f92051d85d6a62ddc611ee3ed7f1598d76e83e5dc322278ae78d9ae606da000000000000000000000000000000000c7cf2adf7873052faa09e2331fe7dc9af81c2062d7d35d9d9278496663bed239a84611cf7e28c6b7bb7958acc74098a000000000000000000000000000000000af03dfa488643cc3fce89bc9850cf96490535b7dc6aa64cb9698e311b7aaea295efd3093a7a6aad3807d0bcba3e4c011824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000def3196603d1e047795a08c04c2f645a2c6a56e3bf5fd4ab51ec9e77f6cd6208d194c83b744437e85af5d586b4fbe7600000000000000000000000000000000096d92d089d4c82923d984acb8436a1b3775610fe88db70556e75955a259927ac5051402226b4ca67a121a2176ad5d510000000000000000000000000000000006fca4841d16bf033de4b74f73ece7f9dbebfb9764139826391e9302f1499c7b1566ac1dcfadc14be6879412406ccffc000000000000000000000000000000001753abddf4b24178e91f3ebf00491664e80b8c97c70a26e90419f3880b2f1afdffdd7546c6bf68c04bf83a16b192157c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000777fae0b6cd6f260560c65724985a042da7df7a6f132d27c6fe111c9290f8cecaf06f3624f426250b49b7e7fa89508500000000000000000000000000000000069b4e74cedf01869e6d633aedd210347918fc53f663ea3ef0e53a39d5da9feb616f02aa96016a3ba66b10318e57f4f2000000000000000000000000000000000d0366d217481ad7137df055349a8e9f2292dde0e30610fc19a57f480e6eead369e3cd4ef3896a3a559dbabf1ab766f60000000000000000000000000000000016ed4ca3f38f1435dfdca3d4e63053711660bf1088b6f4f2c3e595ab4d6d83541f0098637a1613fddbff12784ca45e2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7d68f815d6e9e670dd2b3f9e254d5385f3d36db42e0d8c9dc148c41e7564393330d5dd7bcdd099a64676ef2b178304000000000000000000000000000000000765abcedc72d48c62070dd2c2b81ccf0211ca302996ee77b84294d7491f15f005dccb03b994f79060b8392649f48b9e000000000000000000000000000000001862ab3ffcf336cce1498d82f7d72ebfdc28c6fc6af7f8787f5a71ce36170a243a6b6fc72b03c925ab0669a96dccb3360000000000000000000000000000000001a273b2752edfd56381a1b106fe1ed691e173633c3d463c211d474537ece36ca0900b933570d64d6113f2170ac3da971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000189ddc1115f06063281e58e42713da114bcc7fef3ba4cc973881d0f350d3b4f95c3ea1492737b6fa0b47ed6a5dd79cc7000000000000000000000000000000000a5f0d7c0014c0a9adc1f9b2247260bc5813b64c0dd079e523034fe0bf137533757c3e8cd23243ca0c0df9e00cbff3e70000000000000000000000000000000017223b26c89a4d7bbfa44e197c2f54890cfc9bb9d1136a7690b8e9030df9432421dd9280e311d6a1470ec0c36f79ab060000000000000000000000000000000000484502cec0ad39ec237c83dfdb99651bc090b42b8a7edf1e15752a726901e3117d616456d313c3532dfd02bab2555e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008cb3ca43220f0e79eca8ba899a19dcdf2aafd3f7b8728506773ca9c458f8e2e3c44c72ad5f815365d0b98a12ad95244000000000000000000000000000000001683608ff07d3f38dfd3f11cbd368d207139eaba6c5120e18a48bfea68b6a1e3a2c51c49dc148d30b11f69099689ad9e000000000000000000000000000000000426ec6debb43f340c5110f830bc46e2fcaa723ad2bea1d0db3d98414d46172af100cbe27d71e208674dfdd95470f817000000000000000000000000000000000978bc27dabf88d58426510ef4e5e6dece2fb22151df5a8af1ddfcb05a9abae773e94e9d9184881ea9199b43bd2f30941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000066dcb061e83deb38b45233b2fc41417f44d3c7355ac318dcdb122b85df57e4e7d649115b62624b9da4b27c78b74c214000000000000000000000000000000001162d37e829ef40bba082dca59b0c3541a354a31de7f745a3b2e976ff5986ec26f4660f077ea9c7024c912e4616a1d0d0000000000000000000000000000000001ff168f874f3eb9350958a29dffe6a12cd5e262b79f742249ed5f514ceab20ebd1f3451270be153233d02926d93f3bf00000000000000000000000000000000056a0913ebb34ae39fc33691c98805dfe1931d9cad0ceb19dee33fe4a1e45e44863cdbac5d31eafbfe3363030c20f6bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078be24ae206e04e873c8957b9edc91a21b53429dd25e60af0f505c6b7ffb91db832dc283b5e256a080fe295fe41ab38000000000000000000000000000000000caf223a522a5b9b3bc19a4d714de1ab7abc1634db8894ec56654d98d1d5fb5c2c3cf90aa55e0ee550f47533b2aa3d5d0000000000000000000000000000000017151fc25c8f05d41eb4a5bac124ab137061ee13c29888ab2bf111ec468c7d4b02aa0c085d09cc6e45fcc786aec82d580000000000000000000000000000000014d8f39110411107f058cc31b6a3cac03a7d5bcce23e4264b0b6a1e5452ab5c3f5de123c5256b5757a0ec6d3a9bd1ca81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013e73ab575a40b395c247fbd68b4b0d23163c3c30dc093be7aed74ea588d89361a785652d320c5536077d5a89ae4c7a0000000000000000000000000000000000db8c81c0fbdbe4e45548296e36fce418fa559e4fa82272a9e578ba671faed797ea46cc08e572428c95c62ed64cda67e0000000000000000000000000000000009643e46ba839f2d3004405f334eaaef1d2ad888a2456d63e56b5b9957128498d9eed6111062dde4b9fa6344c1748093000000000000000000000000000000000d2f6f7d6c67391b9300bf69f5af2558434fd03cd370fd654699d23702fbb3f33e6b1608c12747000160253ca8ecf5c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014fd247e8e6ae9b4e782b5d84f191f8f5b3a59bde4a0b9aa5fdd22f6597db0dd14a58813dddc0bc5a38c85366ec7f7e200000000000000000000000000000000119c254b242ff185465fa6e081486478d7148789dd86b38e5f75721af9d6baaf6a2679214316b5ca410c60900e33599200000000000000000000000000000000049ac54643db917c4576f724392b86070230e3a081dd94ae70a71ff6ddffaab4b145941e3047e3b4214e92c3df6034020000000000000000000000000000000013498d131a1da8155aa7faed75b7d55b2b60d0b79b4c199de4da6b87b82b90844a5531758b047628c4cfae136bd1413b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005865fe0238422b1da4ff6ab487fe389a5eca786f44164c9ccbdd7bc04dc2d2f7b9ea65153218757091c6402508590570000000000000000000000000000000006ed2fb68e7348168004786796ad4989f6d1a3255fe2d25c4951909298d0fa27666fe21a9e34e23b0db09591dd63011c00000000000000000000000000000000107b541ae7945cc2658836755c7adb4259754cc3f6a0a067fa05d90805cd1be339e81ca122f645b5e87fc376c9a3a4950000000000000000000000000000000010d4b65e277ae18d05cb9c469b749748ec2bcbffd2d661cff9e2f571f43c13a9a342e896b78121206c74306a2b98f4d11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015fce34cc72d56590fa28777db8af7d3a627f5802825bfedbebf9a9d32bf6ae41551f9da2cb81d993cb4d49a79287d580000000000000000000000000000000019458052d819c1ff8d686d893681b7f8411093071c6b03e8619bab346519ae880ad8c8cf50ffd2061caec0598656c06b00000000000000000000000000000000119a1f8007847c0db8774b6d0f2aa5f4a9c12991858927641ec4e7386c387d302eaae74b99042212d2531b300aa78302000000000000000000000000000000000ffbcf865c52c616ebba4236221572d57de4c98add09eb069a41cd86bcffc3450563264927ea45b5aaac5e43765c91e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5bc66f4d00b0be456eca378b5d27b97ecd11ce0e54619e7401b041b22f31731491ef4f50073823f13476be03a1da1c00000000000000000000000000000000113d4d650dc4a031fdaf180f9b8740a99721190ebf417788cecf17872319f40d27ff04342b4992d7ac91c0275ed302dd0000000000000000000000000000000009b6dfb4f31e9f93d331bfee7cf56bdcdd3e6f36019bc5344b8089362edf3ea6dd124030d3cc378281a62cc7138ae51f0000000000000000000000000000000002845de987222a9bd6b69af5632a839e43c6da4ded2e11a4fa55a093bb87d698ad1c53ccd332ff6932aff2cbcde68efc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000573d3c745c6f0d7d155e49301f1db01eb4c31d3650ac1bc4c061afcda1d32b2fa4250ef3f206667c13f31a9edf1c90f000000000000000000000000000000000787a1aa0058b38e56106aadc185531d3ac75aa5073b46a1ccfa3a37c000778de7bb5116681a5e2cdae7e71cc17733a20000000000000000000000000000000008b4223ac3ce99b30baab19d00a0faaf46a2ee9257556b54b88e77c202fa77dae0465e5d6b59ca6ac43b0078959c1bad0000000000000000000000000000000000cfef6f7ade50d0bdf917bffc23f59c1256275620349a26b7c4814ad745cbdcfb49372fe2fe7a3c5f8baae14b1397401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016eca2ec40415418a0b00d7505d5d49ddfe6af6e1403eb8c8075f666f52479bb0991444f3c0a34daba899af7d599eff000000000000000000000000000000000029654062ddb405e9e0828282b5a939c5bd63358700dcd14d40d312fd0a24cb5addf656501dba301087846e462092bca000000000000000000000000000000001148dbc03051d355430ced38f855119d4781c219e011bf40b0e14eefe3e40d95bd3d3a4362171475a56bccd2822805210000000000000000000000000000000005fd9d7bba5b16749c324c33d846b1d923ada7902c5e66877f238e60fb18281e888b37218cd831ff288223ffa9eed4b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017c868961f18f02faead4479c0a95ca9bc2d7fa9f038eedd645d0a69e41169e40e47c036a53746a697bcccc9433b3cfc0000000000000000000000000000000017dfbaf1c07e26411736267f0cc8dd0b10742a2fb388223c295b6f9ba34c02f15a08cc8a945a668c8abf9925f6797ee90000000000000000000000000000000006504aa29ea99589a7f70bd37a46ff658688d3ae23731a7959461e0ab8d34eba49964acfa4904208deea19c48e498f100000000000000000000000000000000003c6e943be26c1dc313a2d544ef9c5f77593125f44a42d8d1e41c8e53810f88708fbef275490be616502c8468041d4dc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012f646083fff4e3d6ba5cd860682f93031d3332b09bf561d8df2cba9bc6f58f866bdc87405689bac228234528ba2acf50000000000000000000000000000000001e0e095611503a7e916bf04cc85ca4461016e419f04ad6f8389a5c72f9b924ac54079c9f335b288c34eefb8686795de00000000000000000000000000000000019cee62be31a84b05d242b21a6772760b1e9ef2ea9bd3225f60b613a49958b86ec368549be4acbd07832adb7bf3bcb8000000000000000000000000000000000976113df5c659871ef972a42cc7e6963e0f4217667cd0a5d7e923adf8d0cc2eb7e8fba8f916f64558a9518c23f7e9b81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000009b62014432021ea5e304db73fe988ab90a5ec32ae7f13f79ee732edaba2c9fb22f9085019b2a3278024cde677041e7000000000000000000000000000000000a31fca503715ad271cbe652de608c8e9d5825ee7b04a40a1c708a438c2ed96d98dbeba1d2b1cd27859caded1fac9d0e000000000000000000000000000000000d0047285f64738e752642ade541a8332a5ea6f7dcaf6a3f6e0d4bc3ba8c5f185ddad68072885b79cbd294efc3efaa4e0000000000000000000000000000000010c6f24ce85bc819a3519d5f4f31457a40f110a0987137c7b479dc21b25b57ebef55ada63daa4f5589390b8c50c9ced81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e2f35e28c64fb31502e504dd16867167e91bf796ed1fb7c219b26a380ea34daa08a2af7c1fd5f5240900b61e771b0dc0000000000000000000000000000000000b9ac468ba0421cd63f817e56bc75e5d939f3f0761e0eaa884041175a1400090a5fa6f60a9d091d35d8a9efda98232a000000000000000000000000000000000a834bf52722c059456a6a5e5c27617fd3f34e5549966224bfb1f0b103bdea0efd8db1657acc28ca79d3bf93b7017a6c0000000000000000000000000000000009864fa7f76f6ad5babf6b5c1e313e618a0c860efc2d880bcf63929308255e8e69da502e675b413a17109c1ce1a175bc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001057362300cbf5c5cc9755fb6a0c8f82932dd4da6efcbbea52ad30edfe0082d731195843c575fdaeae786ba15dce3b7c000000000000000000000000000000000d27048d7a9c36602bc97d42df08e34d45b7ab097f1201857d788146d0cf7a759ec9d9c151da2e83561cd2efdb92372000000000000000000000000000000000198e29d9115d2b6b7fb59c05216d1f35eb0c1ab9d123fbe1688d883a32c84989151dac23753ce0b3002b5c2f3cb1e2f3000000000000000000000000000000000311bfa53cb8233ddbba8cf52bf7aa4785d9db6a19a3dd84c41b196dee13a5948aa80f04f876cd25c9b7d97b1bb249781824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091fcfda6ee019a71cd4ee26b7552c0eab8a1f056702a80d23db19e9b10f5d8c68283c34732e5b356390387548dde44200000000000000000000000000000000020fbcd1c35b9cfe000f6ed8eef438f8d73d281bb4eae18e8c53bca70fed5782f588e0ce0815472168b613e83763ee8e000000000000000000000000000000000e57e3b4f558924ac1c93fe2c0eac2edbf53bbda1139ec2073af10337dbe5ca1c9aa6b3d0c6a276f1ee32d44dab890e50000000000000000000000000000000003005007d5837562b10432889327f8f5e1a69645b7f0ef737949fca0abf42a6f92ec463534a8f153f8a3f48d0e0542931824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d61cee7f0e3703ce621ab56fe946e4069409673ec30d221534239b16daa9026ffc924ad3e1a8d875be4398f1bc164800000000000000000000000000000000009c5414bbfbc11fae7b74061db6b039612c77314efc0515e6f2a470604cb6268e27b6f6efa3d3c851d89734d2f8ab468000000000000000000000000000000000d898cd8286930f55c07d3ab481bcec5afde71b40f30ec83861bcaa5f00a28ba3dfa86f8efc4cb9c9d35481ffd160cf900000000000000000000000000000000059830dc41bfe09476863c6bf42fca0145a194845d959c28ffcef27f40d79851d774c6d445d54635c4b52136530609991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000116bcc85f3de4a7bb502694425b0cc53702f0cc3f1ce8a89b3f21301c97e290bdd40f920c26f0f3d2b44c33f5b71067f00000000000000000000000000000000130ef144706bdd7de3f639621b4772d2748a5650ea95c9514a247e649a21978575b32d0c50ce1f997d16698bb500669f00000000000000000000000000000000127a6366cebff9a7b65cc902e3704d974d024c7b75d4954644d89981bd015c9ec749cb785c82d79f35ad8468cebf96a80000000000000000000000000000000019ae7097fc64cad02820dea663a58e6bff13ee4a4cb4389754f888614b7d2a5ff4b02a37eb428bf319d6873464d92a171824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049b52beff42d57446d9bcc967fea2052eb55721e8d89a93d67fadbd79270ce9c5702045d3dc00271a07318d6bab7ec80000000000000000000000000000000006c3f4e4a229416276a72b7d8035c3ba6a5202774e392525fcd630d3eeb35258e7aa854979464497c024f2006fe5df8b000000000000000000000000000000000aa14f5945a7976b6cb68c1b3c5e29b983945e868befd4b055db43c1ab68215e9b10e38d5203363d7eaa82f260cfe61b000000000000000000000000000000000bcf2914427f76a26068582e6bca484b78fa6ac134673862cc4a51db214a3f50280a815812888bab63b7c0eac55552ff1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000677555797c0627a120f7c8e1948e0cd56e9d1a404fb59bd4e9ab6820f87d0c3a66e38d4146a95de0dc8ad6fb2cc5fb40000000000000000000000000000000018bfeca1c774a454d6387bbecd9eda3d479f978d7d61dd9f1930dea4479f597a126a25e30f7dc89d0f8920fa2aaf82a10000000000000000000000000000000010eca98132284c3df31b3092d813463bbacb2e4e94ff0b551a251a2341dffd75bf970ba19777bf58d464530c2c8e75b3000000000000000000000000000000001113b849206ce29b7977b9d733b745a8a94bf587fc88a1934554b9ac5dae09ff733612ff69b70e10ec1249fc5a98acc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133c811f9ac0fc8c2120de60cde48c467ca5e668198aab0d507e321cc1299ad783b87af798de9526ff43f6427f9c9772000000000000000000000000000000000e57e5feb6eef8463f99ddc6f9fdd0c8c95eb10a5159059eba4835d522ed1055458176527fea044a14bbafe72788154000000000000000000000000000000000086381552e3e5f747b0de26aa3ff606fdf470c8f3fb5bd2fe32a2c4676ae9bfb899f1be405f79e3f32c54d940dc50db10000000000000000000000000000000016736c2e328873c987a9d1a777b6b9025ce7ddb0297346388ea6283afe68b6f7118998404b5b002a25e03d9fabfe667b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bbdd418783584b0f5c75e68015c63a28626b7a6021feefa6c5dcad0f1188ed559245fec5d678f00e41b8e45938d74f0000000000000000000000000000000015853bc65e68363e78c2b7e75e0b826c9a01721ebda605a6bf292dc4c48cd484aae92881bfa7639c995975a59c92b8060000000000000000000000000000000010f1ce4a87c6a3622844769e6104545c45068e91e22ef0bda4510be21fc61bcb66ccd19e94ca8f01ba20da89ad75de9f0000000000000000000000000000000010acd9cba7fdcbe38e8f9bb07b71ef1c79a082d4d7d21aa49166e3bde0c8e4ff35d7dfd4c5144b333a7c9cbd431391181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cc9bb5399e922540d7f00cb40df3e8f5194cff2c8ad86d6b6f5f356ee2b44bb213bb354ced372b4fefad42dbcc157e50000000000000000000000000000000005b86a1a5758146afbc52911c5cf7fffe3b0deadae6fbc830597be0431ffe190db7a6a7b13c17fae29ee01f1376c0353000000000000000000000000000000000df8d8af518013f1c39ec0c8dac2ca78334cc8b7d36ac57c892862a7d4cf41e232b7399ea275204f7575976ed5a236420000000000000000000000000000000003ecdb633151d2631e09e65c6e60531aa81b8217ac2eb9d4c9c02f3c1491623c840f9a9047695b55e0536167833c80861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000167b2acdc1658ac4888d01105cc027ead3be1219360ad2f3051d5bcda6b0d40689143782099e69d421139925c5b626e5000000000000000000000000000000001869ebbd1a45a542c69448c25d66c996ac93db6448d3e5371d23794597853a0da438b4bb445ab6e25c66a4b12169ac8b0000000000000000000000000000000002ed09ed34be4571563e430588e0a06fe8b986913ff6e350156a629bddfc156e58a4c254b3ffefa479328ee461e5907100000000000000000000000000000000150f09fb1ebb0c4583a9bf5b0b94649e78a668fa3a0b484aaabbc046d72c8a5a8bef2528acbb02d0c6657a8d88e9b9d31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000128fac6c562713b37b25d65b39733d48cf26f9db6e04f86ae5259a9c4a81bc022347cc72d686eb28c07d7c699056e925000000000000000000000000000000000a4708673fc3b587d9c786d26c74052510f214f75ad4eaddb820ffd623b25c7cc65b0020bb7e2a963dab6def12439ff9000000000000000000000000000000000855f569da42b2c6368383dd5cf89471ad73b7e06320c51b5c2b60f4ea73454f22c1383c730b791428ad745ca539668f000000000000000000000000000000000c79e2f552fc22bdc70d056713d060b5ddf808cd430e0f6811aa1f7594fc73244656e39c0e41704262a33d45c773c7bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f2c3b9e321c6792837de46f3cc80c2f0e40a6b53599954caa65aef3674406e47db224e56dbad8ed74c87965f2b179ed000000000000000000000000000000000940dc94e66fbaadd5cc173b41b267a540efdde17550798b5e00e3b1b5b1021f5d024aaf94b438a32fca94f62f64e5690000000000000000000000000000000011945c0cf903972bb1549e5cde5fca4b65433c6df78eed106e78ed13ff7bf7e91b2592bb132d6479b82a4a25dddac025000000000000000000000000000000000309bb2f3cf059ff552d26fe5b3d6af15ff9a6872440ffae64088e00cf8f6503a09c441ba626fb16c8ea0f8f27d03e2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000053c7c7cc29789b497886771b7956959437f8f30b3096977fa0afaecfa7b920ee0e4f10029f1b7044931be331d56e84b000000000000000000000000000000000a65599eacea617f1ddfac947b928b9e638838145cd91587ef1aaf40779591ce9328adf76fe9af573e839ae9a8b78e0d000000000000000000000000000000000bfc7aeb636b07206067e415aa7be74190ad13a7db71c869fa2abf756f8b0671bec8c5581f70de87f277f60de44590220000000000000000000000000000000003f437da111e8a98e22847a849b718e1481d95f33e9c0301f7e9af0fb389a823fb2f020fec7169d332e02aaad89f5c811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000276d9568e9a453e5e912a2ef3d0e0393f44354b876ba00cb4fa5a4f3c78ab8674d36bd08c358b7e29e6bf1d060d55be0000000000000000000000000000000002cc809deb00924be412d03d09e3dbc23aca77456cb6a92465615eee65e13826d5536c16845467867b37c21c52724c9e00000000000000000000000000000000102a3569bb92f49f760a2a2084081067c693dfbb9598b4450d272e130643e2ca442637aaa27e536297abde363b484fa1000000000000000000000000000000000b81ba1fd771dba95e76fbad68abfd3eac31f2a361d85ca9eece02d2763c24a60791466d77853b1ccf5f17cd49e377bd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ded75a6df70a72d41b99cda6fff97b7f40f2233700e7ad5fecf5460cfe6fd9447289848658345f029581b903fe91827000000000000000000000000000000000af19b9ce241193cdc1d229849ea8f52a98be4254e8aaf9cbb8e9233cced5f4bcb53c6d5e6867839e9fd630dbd85db4800000000000000000000000000000000032e13a3377f41c9544e99b68c31df0e4b3265c8e546040382f817584e97f0804a8f4819b2afa645907603d87d7426be0000000000000000000000000000000016a6b82210834d16ca9b75ffa17319f4b7abe9e27d670eb6b084de10184ad8f1cfb8247cda957e1cbd89927d2c6a11691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1f36063132cd14409372133296b82abb09c954e48c0436e65d3825fb1e97b21a447c416bd3ef5b30f1d5cd31ac271a00000000000000000000000000000000177953cbbbf705dbd469ba2fdb49d1116b12b9133ba8aacb58b6bf8c7a56f3fe552f7622a7b1337230d4740ffce0f82f000000000000000000000000000000001535da46034bc92cf6e8cff61e59014f531c1483e6fb2c5dd3c6b90898694ee005516fb05ecbf7eccac210a344c19259000000000000000000000000000000001761ac0ddb458dc3cac31b321c6746979ae08608f86e0e59b84c39c255635ae3ff4ff0a01e803702e954db2d85e8f51a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000026cebde043b9adfc001abd772a5847ce72a5671261ccb809d638f1f54e59860364b15c1a0b363bf927636ed8381bf69000000000000000000000000000000000563f92b65660a1d62702738a85fae4ddbf92aa3fe2e3754e595650653a297b15b07b642b023a1676834fc8b2bb50f5d00000000000000000000000000000000048405bf169c9a765f0ae653cd57c8f2a928088f2a2ffa516b52075dfa1e5f3fb6f5c15bab6c45d8663ab6f5f6b37977000000000000000000000000000000000656c03c520a01b0632aae184f04bad70be7e7e12c4364c411db7af5f2e50faa65d36d0d49d3e9ab6c92df52fd5fe7521824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f68b1c74be63488305cda0417131f23659927b276a3a8674ed03eafb2ad969e5e824f2bb8e50b5e2873075744d2be70000000000000000000000000000000011611f02d72abbb372660c79cbcd05c0271ad8a4eeb294d50946f08f1314266c772bf1a8fddf7547a01dd5eafc6ad76b000000000000000000000000000000000f5972127021fa24e5d7a819c6b457c171b3c538294b8f1c26cba6d75aa82c207a703ec097c9e9172a00c049feb0055d000000000000000000000000000000000eb3503f69471516387585a69fcc553ee4f367d67412da7f6ebd65e13f1de8cb782c540cd090b338e14a3b1ff1c2881d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011474a5ed1ccc1e1c554786bc61efbe7f24008d23a5b0bed5924a8df8e1f80b6202fa51e5fc08fe9bfb3e6d9d2db7e99000000000000000000000000000000000aaab2537c020f72e78ef34c253f7344a124998be9249121301bbb87dcee995659afd65b913749067fde70ed61266a690000000000000000000000000000000000c79f362a55ba6ae051eadcfbca2174e1d78f0c416ac1491542fddd3b32d20b5c6c28814c675b333fa0a3aa92268dfd0000000000000000000000000000000002cebce9fb34978cf0b5b69d0a41b3848bdb024eb0c263799894f31b2c84e7d3a75397172472ffddc0847d7af7f17feb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011e9c29ab7719f842bd439233a6edb540c5e3bca29e9813050f6b51cbf49ecd4d606eb82073c488198c04e67bf72c3b20000000000000000000000000000000007cc2ab4c03a762ba1dfd25df2476ca9fee77c0a9c3069d6e9a061f2913908831f19eaa5a9731661a54073f5e35e960d0000000000000000000000000000000017928018662eae1825abd3c460d02c9abd8c2580fc24ad2e1eaa1db3448ad9a913f162fdee3e705643c9cc1649aa245b000000000000000000000000000000000031c2baad28c6c7311b7d1cd22e5c7f5674a9e857210ae6d7e764b3ff802f1a271653ec15871797eef46cce1c74295d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b88e9241776f5f8ec1989ba1da8592bc3e42c4c67bc15bf28cd51903b2ec74ccaa470a1dacafa8f1da908d2e62dff4f000000000000000000000000000000000ce3fd106496c3d4b9ab0327e695b30f6827afb45c75379206fe8ed8b81664440accdd37a76e0a7eae6a414f612ac8130000000000000000000000000000000018e066eb37ea89ae8baed435e9b07e268c66ae227ce0bfb720935140f76baddf9e08ee390956cd112a6d34d991044ade0000000000000000000000000000000015d3bae286dd8a166527584cd15826540fda53b40af71e4d559708b711d589a356b4ec46c183a244dc15fe4b90610c421824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000103d64c1685555300fde5d9961201e76c53cad947036149c003dab16d09cc2d9bfdf1f83a20f822bb694d1573b5abca100000000000000000000000000000000152660692870127e72359f6ca1d375d580ac3983febc904ae0ad0350ad31a82ad78f8e7d4a097992884b990ecba556b60000000000000000000000000000000004939c5cfc08f76578983ca59d14786244fe8748a3b47f068187667cd37f1f0e72abdf6741def6e1384c308df10916e900000000000000000000000000000000054d5e9ccf0bc635e1fb4570c67fe00cf571c901d59090b5f44f8eeb42f05f62aadbef5d10f66152f05017159c38676b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000318cfd3bfab1360eba1f07b898108bdb5685212efd1a10bbb1e30aa80a28caa9b7c8799c60f9e606ae016acc55c22a10000000000000000000000000000000008d7620147280eb8562ec97c6802bec3a075510e85e5b6dd2c30485e0ddb8bbaf1a3b6d013900c40c0ab9c5954f53eaf000000000000000000000000000000001150c79e35bc45d2ce7ef94c048d6aeed09d55a45b7e22c053e82f7be06f41d314cc5b9f66bed7de7f260f4ceaccde0e0000000000000000000000000000000010f4792df33198a61964a81759260ba9c6b80288b8e1b4c133604c9b71de4ddbab315c78bc3c7ee10b5b75f44dcdbd2d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009fc853672e07ab70fcfc7c7e0c40b349be68bcebcb3a41632791c9f04f1d74c125c62bdb414d77d56aea5683ce636a000000000000000000000000000000000034826e0493904fe118f444555f85a0baa08bd88488d700ee1d0750f4749ee3fbede4a45adba1884db7388c2ec2654860000000000000000000000000000000011e5941880e4c8b8b99c8bdbadf695fe181be75f1f01249ce501186487960ac8e49d35df9796b4220394b8fa72c90013000000000000000000000000000000000b4dab793a4a667d7af2022bc5e18fc8d8a7879b6857cd0d427973f147dcded42bedab845a708002b6f28a8352fe9cb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015c9ab495e5fe7f2bd342fc2efd27490a455079801dcec626af30419975c37f1684f72b5acb41ef98aa56e6482fb270f00000000000000000000000000000000185b4b1668c0e0ed198d5d04b95a3d3a389c801e093e2c1b5727b0ef36f3b99a804926426d6ae1b791f9f06e88db58200000000000000000000000000000000002a399f8dedfb0851f1b6e2a4c23304b16cae8eac6b6b770c9f71a32a48300e209dd25011f2d94b748b95789dc91e3400000000000000000000000000000000000b78c49e9eaaae55372c80df92aca504b7391f10f9fec1dfb4ea63b35c15c09c4c1c4c0743173b55afd987e64413df61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c36d184d69756a2612eb7556537d558b332fe008c635299d2dd81618662803a3479d11eac43ac591c70bb5d4cb1137b0000000000000000000000000000000019243c0afb079774ea0248ffd86d43d68ab9e803358dd1fef446b0d7208e2cd2412289c546028ecdf7a5deaf56175d59000000000000000000000000000000000a500303a89da3795c41e7353b91f0f446ed0118cf96e0907c7022fb1af187e99d74fc83764bc8831f6a6a9281ce398f0000000000000000000000000000000014f08026c48f8485dea8ee48f78527a02a39aad64763e837b99832043941c8b3c0c962d12e5a545a0eb1316b938f16fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052c30760aca7fba6de13ee17ed14b41a2bb32423d4846e0bd19abf2d058589ba504d95ba96e0596a0be12414049e353000000000000000000000000000000000bd79ab008494216b3c71b1c614338f2dac580a4915d5afc2da53ea1d2dd2034e0791cf69a0c45aac015f62fadb4e7c000000000000000000000000000000000166f8a2add5a19b2b4024d9adc20043f259c92384324db829e09e7408a21f42ac9799a9c342629c6363f426902623974000000000000000000000000000000000c2746a502f50e7633dd983f4ff389b9ec25308b96561c97b480f95271974be5d27da266768fd771d2c784f93cb233591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a898e9bf6073147fb1e60102db677162003f1abd25edc5fa5dd6ab049254d4524f2d8b556d29fa3eca6435b05c979d80000000000000000000000000000000001f5ef70cf6a1d05e5aa5c8874def8738b0db2cb49db7c9af351ebfd204434331de56c6c6ef98de04d436fc5bf557fc200000000000000000000000000000000051dc3879cf41087d579bc0e8a7ea5e9064f5841ab44043afee45c0c4e3b32e11720f4aeca328ea39aecef743fe9b18d000000000000000000000000000000001383c1b6994087d9a0dcebfca28eba05350b71ba2425959bb064f868a782a36aa8a63e45a08503463553674b1c821cb91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009412cceab3a86856160fa4bdeb1d58ff1820523e691070850dfe1b103954bb9693f3b3041176689c57f9750bcfdb140000000000000000000000000000000000faca7a963fc6683388a896c30e02d7cf1f240e535eabbc3097ed183c8dbda4a4a3a12dd85e4c3022523e2a380ada35b0000000000000000000000000000000006c4746f6ead0992092871bbda492de9cb83385090bafbd6b0fcabd2ae1ffce99ec57535a4dad5c7f2db8486409899f7000000000000000000000000000000001129304e49fcfbcadf136841f097aa993179013aadc959a2c591bf8a1e641317488464ebad805ac2562994e2712f1c9b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017f5c2f7fa387f1eb2a22fc25e84dbc78ecb4ef72827e3163a3a5a693e336ee722efaa857e114064b4f8a170f628441d00000000000000000000000000000000186b1670491a0ff4a1d9da4d22d35fb3924e47b2839b3c531ab862456e80e2e6854bbb232222f42de1cd85706762656a000000000000000000000000000000000f0851a5c8dffc773be9a02500650b8a7c3af338bd334b4acbeefc5e076d60290137c9328e132ad61e04ed561071407a000000000000000000000000000000000e64ea24961341d10a35700dd2e771ea7f727bd18c2c0211aa8e64df540d4482a3e5a6dc95b24bfd136b3e082523d8db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002c72b172c14d6ce9a4acb132a1263a2fd4c331596657542335bbb149193a8d6f66ca6c2f0eae3e7ed77388b204c669000000000000000000000000000000000cb8ced85fd739869e64a13d15a331172589698d6019963e5863e9500098e1459fd1f960142f5320403f50a43f35cb4d000000000000000000000000000000000e4130995bed7d1a94aee38154766f36cfea3ec89488d2e7cab0b3205dc999ade95e37d1ddba81e496eb298b9a2a1b0c00000000000000000000000000000000103548e88f56e2d285fe630000fba9f9b0b8c0eae22c307d6e4cf9af75f282556e4ee02bb50486990b9b43a0624d1ec81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000273eb86e28dbdd6b2423884bcf55c83487cbbbb853418392cb6656f4f440056f8bd4c5f3d53cc8ca217647f437645cd0000000000000000000000000000000015d85bca79db13c5b3b7a889bf50ed9477def0e17c316ec2d5dafc039df11ddadc98f109a02d4f71680f402ee24d576d0000000000000000000000000000000013ac7ec160094d25148263a22483e84d88a36651facd83f03b1aeeece8d0fd93c0f084f921175c1cc0bc1df19e9c12ba0000000000000000000000000000000016b110d12d8d4563e972bc0886fec621c2ad3544c508d58ad424f9b80eea596799eeaf7cc9fce77ca6e35c43ebe171561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cd9fdb238ff03989b23a6783fc0b0de69de6b295141b98cebbf5f0fa2d316b3fb7698cdd1e6ad369dad4779ef1407c1000000000000000000000000000000000ff358ed45aaa6da0e2b43f850aacd4aa46a133c856289053d3c89134c6dab82f0398cac0df68bae717c4f4eed11751d0000000000000000000000000000000005509f7b37e168a8b03fc8830e9cde61e544b13e03b08d9fd0972ffd34cb07d98d53fee794382faec6ff58f3dfd86928000000000000000000000000000000000fcf3d4e7e1501387c4ad71e146c2cb03b30465fc3c5191ed4e829e37a948ff05dea484d969167a38fb63743ea7426d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019bce9cc56a47d29396f85fcc71486b1737441f95319cfacde19d7fbc53f7a053bce166ec2a38b84fb6221a151543ef3000000000000000000000000000000000ecfcbba6fc001bf16c004b45b869334fae017a57f5f038359633b9c3524f6449b7476c171ab23514e995dc88f77e1f80000000000000000000000000000000016ae2f78dfb78b606eea0ecffe24e4c4f085b49f3f38e41a8d6697e6b8dd32ddafdf1d7eb9ac1755d7942396d6f5e5a40000000000000000000000000000000011223f7d0410f677dadc11718667557ef3cbb8604b0519835f6853b06aefa80be64330ccc3457b7fc3b257cfa8584b0a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1a54fa926de77692d75a3cad9e71be514a3b2552c818ccf6c7fa2408afb6fb9014d2984beb460e9df5c7448d11f8d00000000000000000000000000000000014776766c096b363e1cd5e7128823a2ebe879dbd54face59eb5976ce84901fc5b9f2555a20944ae49c1240473717c17b0000000000000000000000000000000015a31c692b8f24d999ad4485fd1e6c49d1f4f3bb6dfc7f9eac3d20300bf697649a3eb5e3c8466f77096595b4d40b3e2d000000000000000000000000000000000c4a57c719b3262359bac95e3121ae0c651296c9bde0c91ccb6f734692cd0ffd46bbe64c37247a3b754a11f233af37451824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018dc66929e95cb6bb55df334357a7749e5860a0af7df982361c76cd6ee988c966b25a9fb1d8e2d3db9f3248a3496cdd90000000000000000000000000000000016337a847d4b22165257d5739c8d3737b846768f4b700bb9dea3a9921f824555f1133e1503c8f8ff361da013c011cb3c000000000000000000000000000000000701ca35573a82020128bda1f7f339c20a1d0f357dabec6c50394ef9e2ab05a1acf7a1e527cdae8ef7569ae389d7810e000000000000000000000000000000000bd4b9aaa17f6f93255cc93d118abd364a8dc9a1a9e94b794cd61d76dee9e977d622caa43442edfd2737e95a2c5f646d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001150376664173958be2ea5d309142561dedb2bddbd0aba954b6cbfd9db3759c0940bbc79352044706606d7c7a3d03ba3000000000000000000000000000000001636000a4b9423a751072c304051b1413434351556ad7e58b905f46fb0362861303abe34138370102497c16d186c5ccf00000000000000000000000000000000092752b76c60fb756feb4d98dcd5a776c68f8f8eff9962ad4d613007be0d4734fa5dff1154e25271287f7965435771fd0000000000000000000000000000000013637d02a5d90e2b160fef32b57d4aa271cfba5dd8ca373af7fcf3724fa49a7551790a5ee5bf54f5038ef5d75b01a24b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017051ed4d39e0abd5c3145554c90d0a4a478fbd9685572fde9d71be1a4f9815f4e62966f3f2358bba3d46d73d8ca54250000000000000000000000000000000010bcc4c0b57f90257fd3b62c0e79c93da0e5b17de9e4ad20a8c1661b182f7f838e460a34930115f264870e2e03322928000000000000000000000000000000001256736af16c9490b18c649ac67b5e1cce4d20fb5098aa9861d668cd502a69ac2424ded4146e2f08f048fdcf5da56a580000000000000000000000000000000004f81b24a6dd764ba19eca06df9b8fc8710a5821e31541d8c754acab7cc7ff01cdd66686b01ede62d2824d0c185623c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000195ddb1687debed13e531a304727c3f30240e17a1aaca98e517191428c38f5e25a735833f582b6bbc9486b28195a3d82000000000000000000000000000000001092620786f7846ac2dc228269a948a4de3da3bfcff07798a6fa9377c4fd879c46d4519eb0bea59bd49e5d4eaf86a1f4000000000000000000000000000000000ce50660ce6d3fd708fb3ba997b1185276ab8b05fc7ad763d7661bc64f31f0b33308e12c7e8ad2fcae7d9fe24347e40f000000000000000000000000000000000615c39aa9d1454e9ca870d896c4ea74357df18c1c21be9ba6c0477a3b8716e2c8a0e31f460236b23f6f27539d1503fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001955e0c0f1896185ef15437d7198abc66ba02647a4ef4af586c2b7750d71de0d2d39fda884791b0c66a0275f93c26bea00000000000000000000000000000000180176eed7d517031ed3a30a0c58a108c3616e00f6c70d8e020377500b2c44dfb40a0ce049021db1440dec84845bd59800000000000000000000000000000000135299be63c3e74f91978b9bcebad6c2f35378e37528ccdf06b1bd1fbf93e8aba219b40332969d1fb46a77b24f05370300000000000000000000000000000000080ea37e8a2a4f73242d764380a6c9b79b26d936e81977e6e2600af076f7c231d08b5477e7861482a54ac1e64aece7161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133a8dddab8df4f14c06f5b28f117053b02f61ef8c9da1356e3a81f81320804db033e49bac94a5f1e037b4104db396390000000000000000000000000000000008352f81c73310c31e31cd5f267303e49bb1490c13a8b28e09c5bf3d72deee1f7d15f33a1df987c9202ad89e18c36a7500000000000000000000000000000000041d43f619edac2ea8a3a15b9915ac47e31a65a0fb5e62833aa5ec93086d8371c0f9a56c0d8afdb3403141f7735b8a780000000000000000000000000000000000a31e2b5840129cf2f2b7389ef4ba5f5f4c255e81486398a2cf52408f14f5556790fe11aa57a08836c15921baa0e56c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002edf086f489795507935e3b941f89775548b6e897f3544de7bd7c5c759aaa30cd4bf60c0922ddf3c352f9ecf3981e0500000000000000000000000000000000162aeee3f31988622e2f3302774a01a6cc1e8993a2cd3bf8b0684953603994db7367a7d5e5e4a2d1dc8cc476c75d6140000000000000000000000000000000000a9f0a63bb4129716047ee984daf1834ed7d9277739059db13c735a87fee6f8092e218bdbbb7c1a5a6ae1cdb9f448905000000000000000000000000000000000b496b2a1f6e4f031b7764f56b20aa7eb70e5bcddea7bc36ce59f2a9139ad1945b55b907986ce95ea8c7c4a98e8613a11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009aaa77547265b05493ba1875a42cb8ca412fc010d9e706bc66343c15722e6e870ccf47f54d7d218fa4cdc06dcf2ce59000000000000000000000000000000000350878d2d873b3802f80594382e50f66eaba21f8559c61432acf6b24e3126c47a6d377fe39fc4cf89fca9aed09df7be0000000000000000000000000000000011292e077d168103f893090e53bd5abed36c8f81930f5580f8753f527d61a451b73fa142a57a1ea6da91693cdbb7ee4a000000000000000000000000000000000db0b51469338ce21f5a3dfa25e0761ca07f28236f9821dfb2283237c82a1c1bdd1be7ffa27124d00d31fb6812d78e6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000126403343c8dad4dd0d8e800aa59dc0aa60f4196a72f4aab76f07fa4c64ac48b448f12d01721a15ddbeb55257b2a74f0000000000000000000000000000000017d8b47e9033786fee0396e0a04bd3abbe4d014d8f9560502dd65c2c8420f1aacb821e011db7f20ef55f54f19aae6d6c000000000000000000000000000000001572acc3635d24bb78c24b436af8baf966eb167fff2a0be4b1d64b19a0fa881fe917b5caa6ec575db6a9f91281c7068400000000000000000000000000000000111f84b16cdf1c3781c26a3f8ef0b2e85963b1fb640862a7dcfc1aa46fe76560d5796533b60d6b9711bc240424b80e731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000079c8c39f0d403bbd3f44dc94ae92328b345058020b7f33422a7861891cdcf11e6cd4e0c4c77b501fb36ae2440f4ba8c000000000000000000000000000000000985b745a089245da76f6d87aa6d3c9b629ffb0b43905b719e2703bfb00a27aebae3eac37741aaa195fa30e8567b065f00000000000000000000000000000000131d3e353448c195068b752abbf0f4f394e4a8762ed13eebd3183d898f44edc5f6f1306fe82b6cf4935d18474109aaa7000000000000000000000000000000000f8041783b4030af0a3d88b724b4e0276b24238201cbe9753355b10f3a11d53580eea092c52f60882ebe00126128200e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001037cd0e7d7b00136f2702285fc6f73088826d0603ecca0f3f1498ea5d20e1d6a62360c0300047f8436c442f7efe13b0000000000000000000000000000000007906085170bf3493bf0ff17414c76ba19569a10b258e4c7abf23604f8638dbf414f7a20e6d9ed0019ed09b41e8216920000000000000000000000000000000005bf679a8f619e79c7f50f39bb44fd1c02ac18fe4e59f8c1c86cb56619dedbfa5f2137e42328b033f721bfc0a58ff48c00000000000000000000000000000000179ef36a294ff15c4b8efa726e0f500169854bc5cf5ee44def42f6c53e76112604e6899b661718a3f6c9a2db0ba1c3df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d8cbaf19363b801e11efcd5576a7972f0093835ca51077705545eca482bd70e3a666def2ad867416d8a08fd93c655200000000000000000000000000000000079b32498cffa784e0731e39c94229b2eba2bad5606f4aa4b89ad8f813e710d3f51de851cb1a38cdd5f52dd162f82a6c00000000000000000000000000000000034b14c6339705c8fb1c5546bf4c6a10bca33a92eb75dfa70431e65e0a3a1546d6e443082b258241465496231619a93e000000000000000000000000000000000b8e72dbb405bb9b98b62256e41e771c7f2e04ff106ae140f37953a2f84e4b00e97dca8088ae37bd96f50d0f993fd8271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b87d23c37e95b6dfd26eadf7f19cebe18229a04668f32384dcc73b5b17ad67f6375b09f5f11ccde6dcfa2256b4ed75000000000000000000000000000000000f62dbed8bc5090f1244fe1ac509954a97e771e650699541df4887009806392b7e647138a465868fd4d6d8a1a18628f400000000000000000000000000000000103dbfd9571687b5af84aa444cbe4abb314b042c7043101cc78185af539455104ec0edc16bbe6b53abc2e3568b7dca5100000000000000000000000000000000080bc7f1510037f91b1d769f0cbb49a373b06818c56fe8c924242e36bf4766acb3938c496e7621a5d2e9a3767c8a0b9a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f3f13801accf8766c1f3c9d561c3c160c1877474bd26f67479b3e7f82439d9695ce9b6086c18aaa3e34f6173f51feec000000000000000000000000000000000465674bf53e64e5dfe8706e0601ee0a176ac8cf3b34ac91f59180d85d05c22bfa2c3bb7e46779ec8c0503b19f88b7db0000000000000000000000000000000004bfb27e4312d7e090a4ffc5cdc14531cbfb72ec491df77e7de0d9b6938598b8e66e9db94ff38507539cd510c4dd59c4000000000000000000000000000000000154be220943b8ee38326e749a4994c6182ca4f791b314b4cb3d4f4aafa6b5182ab03ae3e3569cde04002d2fa1be55f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ea38a022397ba85a538fb2947e8055fc42002f121d6391f3a0ba92b8359c805d57764a8230b2bc15f708af83c339da000000000000000000000000000000000b39783edd1f7b77a8265198115573ee4088a909827b48b35a8ada6e6f424d334cadd805b19e887af7b18c9350b63ae000000000000000000000000000000000019f581ee78caff7ac187c1a89cb4049323b3ad1239c8a62bd7ed6b4896e386a3789dc4a47a9edc01f31f1e55da44567000000000000000000000000000000000929f30d804ee39c217b45f8cb18de3752a6935fc894a3acc0261baac783f0f30e86e58dcf4a5284eef8d7ce2426b9df1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007dbf0dcd22d0a03961397aa48c05c9b0e4d7ebf877d9fff28fbbd413439680a3c81802b987ae0509164f7777b66a5e20000000000000000000000000000000008349533421f0442a88daf60bab189c157aa17184cae1f1daae4d732efee8203c45f6bb27001e95ca8d583d74e5d65b70000000000000000000000000000000003025f5ce26d2d74c53a2ffc2b320041cbefc19d45349ff9878baa60d284e47bce97938172703fc8c644446a5ce004a2000000000000000000000000000000000ae27390faac2649aebe6a1818d7da58666db23398a044974c783cbc777abb8dbb06da01e735af6e12c70ea042d732991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017b9c67380c949a0a24a75113b4e2c86ab60170fc23659caac0d0f0f8e1b4abfd5b0ee58b9e8fa6c20dbc23703b1581a0000000000000000000000000000000014dc1d46a84e86e64db2274d073f193b43430dc167eba1a92604178bb25609e181765ef6585e778fd7db1229f649ae3a000000000000000000000000000000000f75446b93a2f3c5bc49e9b7a1424262a1ff7a3e742786424ea05334a0e09ba4badb4d9bb93362bb374985e74fc77b6e000000000000000000000000000000000ce56eccc0d98b184dbb892d517fa0acd694bb91dbcae1798f24b0c49d58e40596a092317584d02a63a2bf1cbf4740401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006bce5b221e27b2e3885c693a5b05cb508b317d704bd992e991e42001ac01ec94ae6b3322f77141013243b9f96d27e6300000000000000000000000000000000133520e5e823c6a61e7513b5df1338ead16bbf403a0b1b98754fcd1eb5b143b0b907be55f3bdc8e36ede2dd95c4fe12e0000000000000000000000000000000003fd7501e9b8fbd788a1ed9b786c1681b878917623ffc49c5f317b42947defa58e16ab6b95550c46b260fb46cd5621e00000000000000000000000000000000007f10ae4a3cd2fdc2b43c8e179301283329757971f2ec1fa2a54e1959175afde2aebd879cf182bb7060d379fb824af281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002e1f9f7d0048c82ab84c9b89326f4fa8a6b853df1be9b851705592bfeaa44a1ca6955fe41a8f634ee6097abad5b805c00000000000000000000000000000000159974f70f6e3d670feccae339352803dcc84efce07940d06ce066e34c269539e8e99a508bc5021340fc897bb57ddb5500000000000000000000000000000000077f9ea71f064e76151ff58e0ebfb2fe809f222309b8e86bc7e14fa0284cdfc52b07a38122caa12715d0f1caff1d8b770000000000000000000000000000000015a5241481d9759e8e57a68713e07f2d756129bcb651416aed40ddbd8b9bf8a03f61b272f9f721bf54639ddeb61211dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012b50a5944a9a4b3344c5d4c59db746a2e5731f6f61127b314c6967a8a5d7539431fa82d2ef095335ec590955f07b080000000000000000000000000000000011d8fdf2892ad7ba64f81432364ab96e61b5b27463f467134d885f1490d4219658a287700bff256be0ca9618429ab84400000000000000000000000000000000028f7a22571cc0d04b7e276aa42dda4f67ea8e3a576dce366bb795eff22b38d36b5039c7575ab496eecf6e3c78ac74bb0000000000000000000000000000000006f6d7dce287fa364d19cfae2406cca3fac9e068540d6d2bbd95ea74c62c70ffaa35abc3113a90e79a35c785e49f9b5d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ab06fbf3d816cf6549a7e687b1956ceb1862318b0930a813bd81051976f193926fc4e5d1a2d0f1812ff13819fcc3dd000000000000000000000000000000000df92ec37a7c37079c89c82f0f1e33184e9871d9c039f249dd78e319b1abb024b9315f77220fe94c43c66cafd884267e0000000000000000000000000000000011d8787ca7aa8369b2decb423eb0f8d94dabe02a2c8cdde843cce85738454cdf22c79917095d0ee9d1ee6780fcf571760000000000000000000000000000000008808e276bd25cef7ffd91119165f261656a882673e47ab00cc01573250b0fda3ff1a9750842ecd2b6e7688cf95001771824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019db9e29845dcd0ad33c9b1d0d3dc4abfc126873b637e1d8ab1d830cc9cb6978a303616107211272b996988329866d6100000000000000000000000000000000016e40e0d3c1e9ae56da9b877b03ea498864f2c7c8d5b9424bd29e09c4ad9530633774b83f7c6eb153b39101d4fa2eed000000000000000000000000000000000a54f39e77441ba4750a7f9a524a4368109f571b8535af89f6669531384d4e187d13f098641c1fc81d0db2c8d307303f0000000000000000000000000000000019cb93ee43cf626dc8d7d301e3ec84a41ad94f2c19906205b818ee7f2bf978428f62d23016403f33e0d6f88b979e39701824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019297a4adc7ecfaa534f652a409e598370c46147e7074d0ae847d3b0d20f0455a0f76acff49f7c09ee2fe9b9bdd4b26500000000000000000000000000000000183b0698cde4efc6b43ddf50de20afed7c3c6f385261248cdd22c348cbea3a74d93d202535717fa0c65995ae2e7406ed000000000000000000000000000000000ebe942f591fc05f70d0af5c899ff13e3a9f2c8ba904d972353d85e2584dcd5ff93e7274dab1e0306d9be507d6a9bf420000000000000000000000000000000002fd3ae56e19b0fada08380bc3ccee76ef9960abadbca1c603f9e6e304c01be96b763d9684a9c43dcdb1c8dc244267251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000175b1298f71958411a230be34e16fed58b5b17a0a6aac479d95e67cb3743b1b95b76f4676504702478e0f10ff3e5c0ff0000000000000000000000000000000018a55a478776c7b9fbd60bcfc88e45e8b7836d6458793f5bfcbcad2b8788ec8d3ac3a4542f573cb0449f49ddfc3cf83f00000000000000000000000000000000074b62425f79b4d8ac10bb9bad733ffeccf380f480f537fdf16dfabfa35cdeaec748e80f55a01ac4bab5aafaaaf713830000000000000000000000000000000004c0ef7dcdd20074d611ad06ff60061c1ad25287b4bd085642ea14bb3df8dab3fd2b6536c939b700e2af5057c75ee4c21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007f72e00cb4a5b217ce2b6294359fd979e0ef0918d36ea46471f193c7f4cc9fb86bd6ca1ced232f96d0940f6e00e32d200000000000000000000000000000000172506de01b301dc54980213329bb02ab14d4fb6c523130155b5ae5262767a919eee8165071a9795706a146556d74a3a00000000000000000000000000000000075878e455499f636715eb8543214f39c067873b3282e263c73877f11a4902c42357edf7563d8e9f69cc3336f697cc7c000000000000000000000000000000001821feef28dfb7507b23e29bffe9c53a1ea9abd99a63be06a7f41ef11ef8b848ad5bbf260bee74902b44d39cdc30a6d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049d5e2eec780221fb6a73e21195900ce1544782b7c7c2319ee479a70db21f71223e9556d79978b7a172f9a3b0fa18810000000000000000000000000000000008cc9886fafabf0f4b947fe416e0a4423a113a4f06cd6aa2931f4b51f92645c9710d7223e989a7311b3bfed917fea627000000000000000000000000000000000aa8d5cecbe99fda4813324c2e2803df05f00ce21183e10e46f4c5ac19e1e14f70a07bb9f2b55e37a9b9fd1b98fb5af700000000000000000000000000000000187dc3577bfbb50e1e6cf4e5410400469452230c41f17062c4d11421f885b8bc410954bee0e7aa1e39420799b89530841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000130d38daa9f3b5a0ac75b18c12c51f80f1e49de3a019c91cb82b67523817cd2434fcb557603e372c7cb496b95e935c1f00000000000000000000000000000000082371af4aa99251a204d91748ecda513156f43dee192cc71083cdf73d7d54fddedcdbfbefdb2d66faa91e90bfb0f4d1000000000000000000000000000000000c7f8474821020b02fb36b4b035c4014575aa0899a8a258558aa410ea0f13cb59d404fed21e95f7f97047aa5faf358d70000000000000000000000000000000010e6c26ac6b4fdfb5fa3b9b443d4c70f8edf8b63d4d170853780b3b55a707d0c3ef9986607c4fcda90d7b36c4908c8a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014c801768920ff74331d33930daa4aabb9040e99dccb5c22afd0b430a39942799f56c4205b07a1436f8575db5aa9a0160000000000000000000000000000000003efa318c88a612ef6919681d540a8139d1704f36218d256b01741cbe4a0aad5650f5bedb03baa2fb24f54455745da050000000000000000000000000000000007382864a35024f4b3ebf353b7d5903efade4be2da8f1f4a85b5899eca8007165c59e8d8847a1660e107503c9edd555c000000000000000000000000000000000eac240b773eea4ecc4ba7f4f8213216dd088f0766489d503e361b4d46cad3e1d52d1c28b4064c873d90dce1cecbab6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ee1d1862c3ac2cd03b2ee00c67a8cfec3d668c04d4c75963189a6b27ac32d0d9f606fc153ad3db968f339f7c55632960000000000000000000000000000000004b882ef9badbe9eccfc771b001dab81435a347712ce32cdda52a1d042c606d7423d939cf13c3ab91f5e8f1eb12b858b00000000000000000000000000000000179c72deb6740d42be45aab0d7f606c930558cd83e58fc447d282674178f61c1a94f8f1902d5d11dcfe51f5b504b805c000000000000000000000000000000000ff7bf505a5febe052206aa81022c9799a03d3124fa83db4d8f16f521b760521bfe928dc3d4b510ff93211f5ec5d25b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000679f44cd736a3a44574120a3abeb11516bcd4c6957b3ad0ca16253bfa964b9a151a517a76689a71ce959bee7d7f5ee500000000000000000000000000000000040bb186740a9a6ae78927c839b5121f22c5d16b6708fa3a573b572e9214572e273fe6791dd4f75b918a3415cfb8f35a0000000000000000000000000000000013064b61afc225b673274c2a4a1df3cf89becc2688ed92e42ef9e5bfd7cc2b9a0609e59755a16433ba0c7894d5b83a9900000000000000000000000000000000063f98c43791be32b4c7a07885a6622716e521754a982227258b1cebf4ad7134861d504cfcd4ee42d05716b1d2ec5c141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018d7524ee690a740a5f307238b2a720920bbed7929c2bd135aa25f38f4d73a161957e59fbd87da388bbcf5529ce960fe00000000000000000000000000000000060ec0e83dcb5c628ea715b6f549f37b58f1410897a466f650a9cd6295f3bc877db3a2f838311afc39cdc7582998ab040000000000000000000000000000000017b1128ef973b8bbf2b1b40d147cad2c433a6d180ed06d20df736fe5624d0d3db516b60537e31067860a187aaf7c2c3b00000000000000000000000000000000190988e4d55e5c407c394547cb3373609b3d959b8aad66e87a0d888dde1127c49db2784c5441a21116ce9207d396f6e41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000276312a5b15800f53987193dc84dfb1d2ce5672e5328ae3fc39e1f460eab23d42499f991dbbf0cf6a1e9e39b3ebde5f000000000000000000000000000000000550195b6b7bbd24a776bb0e0c405dd01734e66ddab73bda74f33e1781d9c3a81cf4c114a091b1192cb5e8949716ed6f0000000000000000000000000000000009cd1f1bfccdf21f61c17ae7d5af891631ffd77ee09dec82c8e5664dc3fc81eb3788fb525dfc4ef43323a328186bf93f00000000000000000000000000000000147287aa781dea3ce6ba5db8b25025940da8a8cf9a58ae5fc0cf592d5055e0a6fd848de5d47abf890d79ae715b59ae711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000101dd21251ce5222db7e686167b327a2f6ed2577d46304ccb975d36f547f30db8c0bb3e1905ac47c7c4855f6f77d35860000000000000000000000000000000016dfa1679a2678884f494c8c9deb60f8445a914c84c94a13ba4584ce590011014b9cd35a12c755175ea811fb9f21b50000000000000000000000000000000000192fe2061c167bef84d95c5fe254ea9e074071826eabee6542b3775ebe497fa7c01e0f2a2bc0042cca59533d213e19fa0000000000000000000000000000000018f929f25308da10b2d21ce7fbcabcff4610aef253fbb23c672daec107fa29a2ce82227ac130fad0be6fef8f58d0b8e31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e6b71faf8a7db82c34d89ba0f223c3b518ff14559440f306cc341048cd4155cba42f234c47d0197a59d5750df8fa7f0000000000000000000000000000000012ada1890a934f812332ab2787718dfe9ad95ff5d2d6a15160dcb98a42459d59a622057b46c90eac9883284fca2b73920000000000000000000000000000000012dce874a3e81bdce42560d8cf588f29f0b0e80cb00974f616f467e63f0c2ae924b76a50c4ed5c60c1eaea8561563bdf0000000000000000000000000000000016ca998a066416aca071ec812b5dfce0ce4d50e116c3ddeee5701e006d5d465c541b1cc2cd591329f47aae69498cc9381824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000062363a22ca6261947a218a24ccad5eb75c011fc52a9c001016209f837958ee13cf0b51c58fc41b534a750f5892438600000000000000000000000000000000008ac2ab97a2594a35f6c05dcbc19513378b91d973953f9f1dbc62ff2259e071ae900939409cffd0c10c8eacfcd7061ea00000000000000000000000000000000041e2eebeb6b79654fe232d4ebbf6805d8b963d4bc7bfdbaa3c4f407828c0aa7ca0050c99086498fa689804c18eb482d0000000000000000000000000000000018d10f2adb5978e3b17644cc48c38ef671e82b7fde2509452701abe02e2086f7b8050529e70766de391dd286540ed4391824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003bfc68dc03cb8b80b19a2596fb49d682f38a166b907e13240dd6ac8d57b89ae7a390608949c221e771ccb0947a3a8d900000000000000000000000000000000128718b83ca9b9b20d06dd811ecf2bd3e33d3fb49b15006c5cee67ef6abf20b50ec315c990a2b28ef8d4e71490fcd506000000000000000000000000000000001718253f5faea86eb809ea9780cd75dbf2ceac93538c19afff8bcf9cadb3636e2e9bbacd6fba7940dae601ac9d16d543000000000000000000000000000000001090e127447cf3d84d863178b6b39e580aea4e1c7f214d02d3cbecb863145b6916f41bee779a0e383069c9c8d60065fa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000549371d30d49bffc4021f3a926164aae90b87c58cd8579f6857fefef519c52736f7bd154475bdf6bc5378a33c1524b600000000000000000000000000000000017394a396578fcfd49fcbdfa362ff99705624ee067e25f551ad37e03605173556fba0fa0aa52d261df9fb483575f1e30000000000000000000000000000000012e2d0b76b73fe55810acc2b6f6128d672c8acd4fa3bd7377aa81e4f21d87d8103fcc6c965dc798e89291f42a643f837000000000000000000000000000000000599888c960b1c253910311fceb07c21e5cce03f68bccaab3cbeb043fff84d462e81de2f1f6bbc913d59f24f110b5df11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000177294a4e2144b42b011ec7f86ccee70684a5b41eccc86d640386d8bd09f55e27c349404395d6ad8331fc7ed1ee4e8b30000000000000000000000000000000016ca647a9a1ae4a29c0fc3bbc462c3c624915707f4b2b5149b52c96661dc34bea10e5040e25b176a22c677ad9940dfcc000000000000000000000000000000001249f0d55d94e8ed44baf565ba3c14209eaab9b4546b17c04f5b56643aca1ff6f5ea961619036047c08ac2e37a4f23f5000000000000000000000000000000000937c9fe540d74bdb5b0a73d984bf8863a122a22fd06d21534414330b673dd6a7e6ca02833f61e79161234c0032edd1b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009bab0da6a2235936692a0f62f4cfe20521fa94f5d11e52df052c4c8d869fb94d72a64fbb2b805f38af6e7d30236cf1d00000000000000000000000000000000153e914116d1b90a84831b1c53d7bca6b6029a1c58bb65275b552c3170de5f7a3b695e29be51b865e5b85ed8534ecaf8000000000000000000000000000000000eacbe9abce096c8f98a2df5098fc4ae3f9d885926077bc32b52c4b88e054d65306b7a8bacee545df0b6112b850b9fd4000000000000000000000000000000000a27949b36f57bcc14679b2a4dd52aec709c8431fec29de4435a9783976e8b22cc9a30863ac4fb6d0792c76c9dddea2c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010d2300c12bb6218dcba92f96402cda4bc3c039b8c63c546008632ca4106fcebfcf5d8824b745bda87b246d5f8ffeb1b0000000000000000000000000000000013780db322d7b6cce8f35fa17f16f59db5f44b91550d802cb36f7c0c88704f5810b948e3a7d529d4274b0e7f9e05b5280000000000000000000000000000000007034a0e82a33fc50439a6dd4fe5101869571bb6c9933f83d47573da714ee2a5887683bea688238ab1da9761c7a24a86000000000000000000000000000000000b60f798acb7595c3c6f66f254d198a2bbd0e2304e818718ac15cac0ae811c2c98189bb6c2d6f146347af83a34db76c31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ac34afdbe2547d23c6c16a36e877c74fd9fdbc3990b70379f0a9a2a83a770fb2d54bf1126b80df92bdcf264a3679e30000000000000000000000000000000000bfe81abd2cc11486fdc7d455ad814fade8a95e0d9ae4a38cf487d2927e14ca84f6557e1857bf58c573bc6d0285d92500000000000000000000000000000000042e91d8c0cb8dd9562385cf707864786d1dc1c7b5568d1aac58a8709cb4b0f12d27807feed96b12381f246061b9d8350000000000000000000000000000000016cc27312cf0b40ddf2a0e32801c64076b3b82f0e7b13b8e623aac5fba108ecc6e48bc6c2b1af2334ae1e110a01015501824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000135fdff40e206b4172414d72e5e8a2b14365fcd69bd1727aa01a5c183810be819b86c0d80906b27c168021900c0d031600000000000000000000000000000000081fb85f2010e892d50cf843e65bff69a063016b24c9432fddef000f0423a153a17e1d2693c68815fe509bb82727ad77000000000000000000000000000000000e22f5ba0deb00d09bb53f29cc2f74000f28cdcb3808f02b24f393b530066328619b2de26c583babfff0f61e24e3f25800000000000000000000000000000000065ad005050ee95c321d012275ed4a643acc7f4008c2aa92967aa8613cc10807b72159851648e4d9e5404716dad6f1361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004fe240eb31ae81e9cf1bd853d66932b2003ed93779286c7f2fad349b1cfd1209d902705fcc3653cec702603246f27ff000000000000000000000000000000000ab7809d6c1e5bc804d4f7c85f31a38de7824cc67ea24cfcfac032b38f724a03b626647b3d4862dcbf58d7de2891c29e00000000000000000000000000000000017727af51675aa339e73f44bfc470b547ddec2a093c41652ebe7afd3c3aaa679418056c44c2d25ed353774cff94569a0000000000000000000000000000000006dd33f65a2252293e3df728c405ed25b4d04e3cd3d699009f5fa81a73570811c82334a466ff1cb92cee8ae4ee9320e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010561cb107e8493fa542f341c9ca67f59f1e3d594cc21f95bb54c720159297e435b4e4b4976d706e28a2b6d1366a5c0c000000000000000000000000000000000a96209093914d1bede9cf3c71c948545f848acffe94c82885219dff5779307070ab5b99ecd899903546c3265f35a60b00000000000000000000000000000000001048989a0e6505ac0679f82f58fc56bd5c7c6ee24a6602093055abcf9deb45a49b0f607fd81506408152b4f2e691390000000000000000000000000000000018daff12269d6aa42ff9a273c61bc53dfc3b5e527e51f0d852e186e67f977d6a139d21b9604afe0545a2e29fcd6004711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006366a86469913eb09d73baf15c2a775be36773b9db2544f9e21fb92fbe11d93cedc4ea0bf480c3b1bd3335e193d974d00000000000000000000000000000000126126a48ad1aa83a743a2d87c1fdfbd62ba65d18b564fef9a58d2c1fa24e3de8e36f1fd06122e72ddc23d51f843704300000000000000000000000000000000011d326b1404e62207ea95efe2e99da412381499d26c4c878ecb278381d870ce87df614d21926988447f66ead84e959f000000000000000000000000000000001699bbfad9448ee94f7cda86d624a47db405efe28fab6bfd88c82a05d6b33941093af0b1f24b50fa33c355d9c294ac231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004c3424afe8eb2df5b554bd8760c6e1a5c7b52c9c4e18142c1107bda305eafa2c1a7266799b8d585f6356810ef4dfc730000000000000000000000000000000013854be6fe7bd5a4819bbd8085d89b868e98d847c572f4ebcb4364afd55765dcb9038eec1969c302b5720d5fd64f512800000000000000000000000000000000004451ca2a146ce88bd007a5352cfb886f2c0d3c85963f4b9bc2e00db68c145c6b341ce5fa2c4e86dc846ed359f3c1da0000000000000000000000000000000000fbf20093dfa5ca56bee01884d75be9814a9b80ed5c1db73a64d1a80dd7b15854936a7bd15dfa0b1f7154068e5f906f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006434964546d700f66e7764334a5d51aa3f2bf0eb9355d957466792aa7bd493a856b4b4b6c81237eeef02e1ebc289e3800000000000000000000000000000000126921ca5e56ee4262fc5d9812e88e4173f7ec393945c67f0df3aa0b84b9e595dfa46f1bc851b46952f184180487d547000000000000000000000000000000000745520de7871d4f3e2cc8443e24170a4ad3696640076562397b6e65eafd235abfd2fcd9c40f799d4a1d8ffc797bf5f00000000000000000000000000000000000f3bb7e229452c2e96df937217e484932488c6903b5f409d2934b71a2422be034934c36bcf892cb648c0d4538a559d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000108cff35edfc19996527bfe881fc7391f4d9dc10b2e5441eabbaa23cc48e9b4050217c74460c779ac7988e124a8c4622000000000000000000000000000000001813f0bd823de40e1a5a0d06b650c22055bf376c38014b85fdba4fdca5ca0578eed080f1d26599ad2abec32a5b176c1500000000000000000000000000000000004a732350bd6b265055bc1475c677f683fe388c972931daf046c43ac36b53b62842a4f685af7dcc2d0702b24db5dde7000000000000000000000000000000000c43328fa78310b94f125c6e1926be7387c181690d18d13d6dc93cf2bb995143cefef631e44bb50e5d6173f52483c7251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b36a7521c4e15d11c7c8bd3b10a74043e36aae4414b860588ff55da7de1df9b397ec40b8dbee7a10af57315b6b98a6600000000000000000000000000000000170e84e5f96eed4d8af494da7e2c8a4377454a6f79bb5df725a02b985aa8077fe34fa9007995f957d039a0d054be843000000000000000000000000000000000059c4c0992e519a159d00c4afbc20b9080bad7b770ad9cf8967b6e4e31d8d3d70615c9b073bd48d26991d4ca8c412e5f0000000000000000000000000000000012a1c6f0f93b3ccd56efaccc1047190c2161e86a9dc1f167c14c87562d8ca4340e4ffb2447724b33797b6233503801741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011313edcdd41e12877b8ae3be5d32bb251f16aeb545d24441e0310c9a9e82bc6fa29053c1f0a49e766301ffc511a6faa000000000000000000000000000000001024985dfde909917c1cbcd32c070b99e485a0695b9eaac558c5bb96a8b517cd3851a3458c8a7021a871132c33e26f3f00000000000000000000000000000000027bab13bfaf0076b436de3f071bbd27276a3cfba3b68d8d0f20eb34e6f16ce617cd09f06aa1cb4e8f3824b4c1adc1a500000000000000000000000000000000070901a56579cc144a2426ad7bda45055c9280cbf84b754262cd337f10a7d2abb635149b337e058b637928321ed32d8e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a9ea39cfcedb8bc4affb781c0789e0d323e61655e5be4d3fd1d5c3bfeafdd1075e400d9a476d5f7b01a8162f782e5e1000000000000000000000000000000000495ce7d909ed7a478eccaac7ff2bacc25c34b71921058920dd46caca34cff8d8e8caca979858d9db72953651975bc4a0000000000000000000000000000000017607b61852ba9d3ced5719df1a4324359cd251948d15091bb19ea443c9fb2fc3556bb3116fea1922d17c9f763c4c207000000000000000000000000000000000ec36466a3dbc41d20b06219aa2e13442e2249868337b707526c6d81e60c861e2c9a0f923c6793fec50ea24cff3479ec1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9b306ddf5e76b4af38833e1881aa1c1327be40b5df157e4c3d18334dedbb8a8a9c7840b3957a6fe0f4c85e7d5bb0da000000000000000000000000000000000accb5bb88a764d71c82baea2e08456959c8970bf60baebbc91162beb3ee876c58a68d6c0fbe2acb2c69eb55d1980cd000000000000000000000000000000000149f49e9c9b7d1d68e45a26cd7cf88bc93fcf90e156790630d1e3819a63f302073adf8531d1fc2a71710ed435205fe99000000000000000000000000000000000d38cc3e3853814d20b1ebb20d396b1b87992754e96af4a6cbbb0d7e9ddcb771b3a82a622a1f786c923c129e82d857861824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009c2996ae6122a98a9fc36425c0c22b6b00b82f9a8a6d86c28b000c4204c67c8e0c5e176193fba8e696e80efd993ddce000000000000000000000000000000000d3b18a731b8bb702ae279d5bc8ce5a20c4be033b502c115f683b2656c3de600ed94088cb77744850c4467aa98314f940000000000000000000000000000000011179b01fb1289efc28fdd7222a72966eb38c63bb4cb00c82a2fb523d341c3c7b0cd015d179a8c1dbf64163b34b7145c000000000000000000000000000000001034eab1f023c61c54b74a9ac7e7c50ecb4a6a889939da3eaf5cf5ad5f6ed33147918dd627caab152860436284f679301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b35738c36134d42a50c2de98cd85b8943987a5fe933de2c92f44805ca1a24ccffbc9e634ea6ad18ac676fbf938a2a7000000000000000000000000000000001538651d78ebc75bf6f48f5df8d7e44d91c4ca1e3b1babf29a7df3059df88188a5c555d963b03dd6bb3b4488cc488490000000000000000000000000000000000fda0a0ad3ed83d7886da108332c34c7099f59d06c9c63977aa41f092ac0a54c51d248bae2a8c7bdf72d683dd92687e4000000000000000000000000000000000a375ca1fb70fa49906cd14ee29a13881e3cd4edf070a1226dde07978d8f619bad96bb61c0fc9fc05c21af7884151f251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019da887951e85e073c7c46cbd86f9fbd821286d41cefdf8bfc376205d9c5fa5f9f936961fa6b7fbda51330408da5bc220000000000000000000000000000000001baf7646092529287a2ee35c5dd9112afccd5c35d4cd81ffd43542c6e828e48d56ad392551e8348fc53d39ffc51a5950000000000000000000000000000000012e987e09e6332e115b672f3b3c118f1f0148155e4ad9fe1aa31492c8a3ec5dfc0f55e448cd296e2486931730e8b0a3100000000000000000000000000000000029bb0c0bb59be221afc85c155cae3c97cefefb6f6d1a0d8c2b3e9b881672afb3618584c82d3c9d40e083739187e68ee1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006a061fd60d00ef87feacc12cdf48fac79cf32ca64fc1fda9bba9b13eb67bd54bf66c86e7cabf3ec1105ccb8b92caf6a0000000000000000000000000000000008249d8e4d8105d4b81940acda2b0c096d4706fa6b1ef604dfc66eaac6a8f104ae7445931db027e18df9d67d2460b4a9000000000000000000000000000000000e66773227bff5fde682a98755290699e743850ac4091f8a3d9904d094e4c6fb60c89e0484c9d6376c5648086790084e00000000000000000000000000000000190b273712deddf0d85454deb4bd92494264c765ae2f10e359819db4ac9bb0ffee8797d7b7adff7d863050bc0d179be81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e08dbadb6ab4b9784aa805a8f73d55655a293f91bd454248dad05cff6ecdd6cf4dcceb1765e52933012a12cbdb7c3eb000000000000000000000000000000000c71d60bf2bb9fb12e570cd4ee6d57e39e2170bc47aa49338bfdb943486ad5298e59d2ff37c0bbe6fabd1bfd403e6c680000000000000000000000000000000010e10fd7cd3284446e8506d577e31401bb730be96418b97160cf994077408fed9c7332d2262909fcffe05e8a2035ea7b000000000000000000000000000000000eb03c999434173772a14d3639f0a4a4dfdb800d34b38e56a993bbdce4b8edc37f6c454be8e3f4adc8541a5872e4e9d01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ce9d0227ba905b527b5901550ac3185ad80ea07847d357ef9b5261e52122f0b21ad41109054b8f530ee6508a366bb1000000000000000000000000000000000b983c40526952f3480da633d6a0a3228057a1804b14748066c8b2e1d848aabb62e44affcd35a7da0134a53722bb4cf90000000000000000000000000000000006eef96420d99b86b95e61e77334fd04a7bf5cd2d0712b0262cabd5d61e85552ccf3742d1af392ec0774cbd19705ef11000000000000000000000000000000000bb9f60235279c80e18976b40a10fa7cee7f40c4f26e88e6c518f23886a2a72f2ebfacd798b15e2794cfcfa2402f122b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002ed80dfd93492bb81c380f2983a48c61033cdcd0c8e65d960d91c88e256ce5dccbc1d867b113a3974507e5d6601247e000000000000000000000000000000000608f9f60a74814aeb7badffad1a3282e8f4468d3cd016a54734733d395f661dfabf9772491736a3df371b51f1519622000000000000000000000000000000001470b48e11901d3b36a8fcae4155090f3ed66665a74a686105c7c9720dc8f8078130beb5e29789c97ecda31620b099e4000000000000000000000000000000000d7bfc7fb471a3068871e08cf8279512f25ecc052c68cae84e3b5609d84ac64c6c39dbd6c3df98b767da729a367cb4101824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eec047b9d63a7b31a5bc7a16ef2ac626a7b1885fe1c6efd24eaa31beee23eb839296cc5ba74cdaa929ebf3d7cd81277000000000000000000000000000000001046a73424a7c9e533361ece7dc2fd0381eed96f6501dfb19025fd9f175f71a4d723d797f02a080c283bbbe1e3922f150000000000000000000000000000000014e451848cec6dd4b2ed6aa4a1976fefa34f382be497205347a521337fa813a6caea7519804bc24a0149c12f073babc60000000000000000000000000000000003e6ee5c2ba37f65de587e48f8b2a0e098ce36c87121896952c86d8db258330c97419c918e51815e60a90a8df3be781f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e17ad9aa80a485ab08b7e3a89bbd402a6b1c0c183759a6090b2c33ab52a79e0319d68f676cfbe9b5cd57c3c502fb8100000000000000000000000000000000092338ca37a12dcd7a2c7991c2e1ca7923508896a8205aa190e17dd1b08e9a87c2a14851ff0d13e47109aa2b5f009bc20000000000000000000000000000000007a463f9c09de4b3c91ddbffa4a337271b7a1bba6462544cf0b9e304570467b82eb5f086ddf24023c7bdb7dfe8c4fd0d0000000000000000000000000000000000732bf09cb2051b59f8cc9b3bb247543b95ba4b8d9ed7a4c6a4b89f03786387f4ab899b6f47eba340d13cf7d12f087d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000006225682eb4ed0e52bed3e85a7960f722346a1efdf53733f4ca4cad1bf92c9e4880b90c705e7306617ad750f2d94939000000000000000000000000000000000d564cb26c440ecf1c73092ad5993199cd74a04f3ca50e5e51819c5562d58d5717ecb3e2b393346a47f70e787ed79472000000000000000000000000000000000efaed6ca12b94442ced852dd6325916b1789b1639559b820c5aab9e854dd47aa49b26318187d5d32ed65f00d4697e1b0000000000000000000000000000000019b73586a45cb579e3c1d9935fb5b63d5e8620054f4f4bff089904bd3537dabcf2885a2fb11fd22bf4f00721876828e71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000178823ed42745258a61944f28c33d4e2e620755561bc44d72f072e3fb933c43737d03eeaa06d901a5182bdb423436a0100000000000000000000000000000000073b0e9307b2a457eca228510164728a261d2ab189754d785c59ed95393560bfbba0d2d0dc8fec7e8ff682d20fd8e71e000000000000000000000000000000000d300ac575472c99f1690af3e52c22931769feebf4b50d99710660431b2a619f4a95926bb7b8e965edc590a24bfd4b5900000000000000000000000000000000028cd64aa95676a2def419a8fa639eb9a4f6361261ae323367c2af982fdb10036b5768b5101f7c501ecf875281d51d741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000072f86f3c90234e4df352f3966e542e9e7577132cba049743f63ad4054b58e30a09e12489bef6cc485162ccd45e00aed0000000000000000000000000000000003edcf4a9db723a43a32b48c81f906cb3536370935e30a3ff46933310d80c8fdf3f1c5c175128f63bed5e3a8829c20ca0000000000000000000000000000000000e0cf2560e89853f0d2b0918c62c801d20845949058badb2d7e0028b19aa35dd020102d6b29f89a41989be41d6d890500000000000000000000000000000000022f3b233d23b1bbc21e703dcab3caeb18a19b009fe4a6989f3e13983ed8a454bbbc7f74d4145625a5b0e85cddedb1581824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000199ad3ea86dc2b02add5d20479049ea669c01ad172082e642014661e956916f08ff31670fe7464cb6a1f4e3ddb77ad94000000000000000000000000000000000ceeda74bf5d6aa1ea8f2e10d284120981cff618c632edd416cf60d2f67636ba93bc964958a12ee75ef24da9559fac350000000000000000000000000000000017b7060ebf3ded9cf1eb236ce0e2c880ba238aabc96e90e1dad35544272b699ff61856ad45860b8928d01a76ef21d55b0000000000000000000000000000000005b0315c2f3a18ac601accdd875d7e9c3ab759f86bfeedc7f184d0e9a38a21dd687049f98983590208c8527c8e4db8d71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ed593ae848e2bbd2542e72875c8f8a07aec2357b3123dfb71a70e2bc7bb42af8c54db20200a21cece183a02f2b834f40000000000000000000000000000000013e59423208b1454f01920da11eaf4c6a2a7431d7b15dffda0df76cbe868f43ef4b85b8ac6734e9b536c550a40bc886400000000000000000000000000000000179f713091a79a157231b9284c78070ededaa3ca1abb43f6e1d4182fce4e43a991404388f8b4d56bebe23164a164c4d600000000000000000000000000000000091e466f622aad04dd2261762588f67ee64a3d831a84983e810b58c97a049e0428ce062b812d0ae44bc9c88b989431a81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e97be158a87113c7f12d9d063cae42dfda54dfa7c6f1647a870e16f2d8bd0309a1f160fd0f790dc2aead4b5282cf831000000000000000000000000000000000665ef19666b2642bda49fc596625dabe772706950120eabe0d8ae7d7c9086de55987f43e2f73d68ce599d2319d85696000000000000000000000000000000000bac6b0bb94b4eab0878d929623b772e82ed8d475303917fd8e694de3cc2ef6bcc733a8c7ca8a1b48d56da6bb00a936600000000000000000000000000000000101c51ae4d592116e7362a630abfd85d78f4d9ca105e722050782d6810b360a954b232df6ef830a78d5fa9cbd2a953b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fea13830b82b15eea4e4d5a7626002f57f24a4be86f23a2bcdd97ad47b77feb6f4534dfc067dce4693052e5336cf47e000000000000000000000000000000000983408c20b090d49c8b10abc85d068a217bd979ecf73f487c3f687aefa13bdba714e0b6a681540a78b4221b9c7a0666000000000000000000000000000000001021c0ec79afc0edf0eee0fed313ba553899ac601faffac0f1dd1a58bac4dd52017d181b4809bfe19f1c52cdbbb11951000000000000000000000000000000000d712fe8c0723b94b9cf67863569a7eae660fed08127f66d183e3e6fb5524db4e6a523620ab05bf87462b0795ded75cd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018049f77560200cdafa9e36123d20bed8e1aca7157d97fd6c95a64cb02eb3f93e5bb41c1017534b7b1a78fc699758067000000000000000000000000000000001243c9c097da84b4bdd82daff0f63d480459f154199b900162d8fdddee11c8ea2ae31fa8a2dccbc0f7d1f6dd99a32d540000000000000000000000000000000010c9a183e439c55a30b2d830ee9f9b5af9b5b11703a3a43f630a195afab19d1ea3d81cdb99306f82a82bd7bcbf3cce5e000000000000000000000000000000001343e22d23306a18c266b9884458a260b6e9106c6ebadd39f2706d4aff343730fb375990ed78684722e7ea3bac069f671824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000163e24391ee67c2e668f18ca2c052d5ccb24ac3b427af592c12bed05d6ad929ae7767745dc99074eeeb8d63e020561e40000000000000000000000000000000010b5f5c330722ff6f4a3ba72fc7cb66c6d73f3da5f1ff144792555ec1dac509b1ce38c567cf8caea42de1e53b5b2168900000000000000000000000000000000160fe4c4dec8a24cf10c04572674132a929e95be253575440c38b107c7184199a1ddc835122a841635ffc2f2a20679d9000000000000000000000000000000000240cb3e0d8217788fef85e7e8a9319b7c70f5b164c580cb02a1a19a0f04ac02fb352d59c12ead81561c0380d34fd69a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006cc624101b30437fbad665a7862ce3a046fa6a1ae2391d54a9a203f20287f939fdb1beb9788cb1fe8d396ce07df0f6e0000000000000000000000000000000002c5cdb6ea3f8be5630799eadb307304a68d24b054643b96b7caf0f0b3e393d6552b38acd6ed8f2eaafe92694397b743000000000000000000000000000000000c0b70e788eac5ce02c2435441ad189a027c8f25190bfc48fd90ad9f2e528e426431422a7b19b484cdf11e5ab3c15f570000000000000000000000000000000015162730efd8432b687b5dff860552c0c899824b2d14adf50b8a2df4854bfa362d3957590b0c088b23ea1fd01354890a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e85d8f9b8f1c734df3f774fe00357f6b8f459a33a72a9d56bb6eab1eaba156bfd620466e7d8b516e824958b6143612a000000000000000000000000000000000ee3389a3e6cd163f0c489b63e0d863195e247042fcb719377ae13655a65a908031418a7ae4733c46b7997d707a848e20000000000000000000000000000000008cdb756ea5a4711b46c4956027a8aad41fce620173a48869cdac139f18fd39ab6c387ee4ae819a1b0474100487d07c7000000000000000000000000000000000d2248c2b03b7532cdb85a3158eeab966216feadb091eab3d5b8f877bf7b6eae9b35d00a0afdaf11698c86a9d9b3335a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011a725d9588491e79f44a2b34d1dca28d36987fe1b415a3d9f7be9d9a5fc2e1b21c096fb3444c0ff1e5421dd3be4c34a00000000000000000000000000000000084f69c3b49ded14de5e7143aaaff1fbe0e5b486b25d27cd19f3d70d87919daf0f426b0627efe414fc99492a6948b040000000000000000000000000000000001674cdde4b113fc1895f588a648545045ffdf123cf9130f462a18a1bdbc5ab8c5b1bca8c0ec642c398b2a4128439a6cc0000000000000000000000000000000012e73fe126a3d373b5536085c3714ca4f3761618b19df85d02b77ecb9acc8bc1110c321bf96e76025e689a0e300c90161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013dcd0eaf26ec02eb73468f8677f388b1ab4b8f7a02b3a7f22c4e87e598070693dbbc62e5e8bdd425db0d1d45d2854ea000000000000000000000000000000000cf94bd98c67887ea70f724f39a1a8afcbea090558611b3f4003facb46aff731bb2f105f7ebb3836d415661be902aff800000000000000000000000000000000086e8d170aa5abb237dabe0a9076b788cf6e549c2e48139fdb53a8b0d204051414bf596f8a4de4f02453692db20e65170000000000000000000000000000000018f200e0609e513136e615fead1f6a0577e6414378b7d35054e1efa713bf579ae103abf43dbe1042643a2ab33e8d779e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000091a48c15a56ca911fb46e7345d85ee4fad8905218904a9aa858d635dcc6044984e932f43779a32daac5937f3750285000000000000000000000000000000000c0476b0f7d091b458b9a455e79d9515d5a128123da8a071d32e5243d784300940fe8359997419d78f835dfcc8e2f7370000000000000000000000000000000009a90c08d8c7096f444a1c39ad2534b15b4da71a048e51845ccedc1f5e2db8faa534afa4eac4f98fd9f7d68cef918a4b0000000000000000000000000000000011301b5780b577be096fa6ddf2faa5b6bf7dd9ea4540c0aa90e5fbcd0793c893330ef2f5be2522575445d2c117de56971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084ce2cb8d38ea2bd4eb48c217472998c614c4c527dcfd8eb5ac56424e8259f5e996053448f0f60ac55cbd915309c16f000000000000000000000000000000001374404961742a306c45eea63ca8437efde40f7bccead29b3475dc0d7824b5a07f03baf913a0b66570a76e7ad99e77d900000000000000000000000000000000014b244d86ffda34171b4760a21d1d24520dccf606b74b96061f56af48d79b7f2af0791f0006ff72a525bf7364dccf840000000000000000000000000000000016a8c96aabb813750d940d7da5f5c43e214d971e615f6dd9c6aee0cda7925fd93003f323ba1c30b60f2c854016878bf51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003225c4f0f420334c2de4f782fdde19e3710151584d1d435f415559f5c3f320bff4fec8b600972ebba5084cb6bed09970000000000000000000000000000000010cadbeafae893a0f6bd09fe3fabea90c551977ee8494b21a4be3c945d7a84d4e438698b7d3f62afded7f4430e685eca000000000000000000000000000000001351aab4be82be8720b1ac0e6d87c88bd714732f5e98e999492f2bde419bc928a73ab4d8445d56d75f1c77f44cd0feac0000000000000000000000000000000000a0191315f15836aa46ee64f3c726ec953fa3604c2a2df121d5a1f6e56a03bd9ba0e9e4653c883b7ae3f0f91358a5261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000be692ae928e281521ab9465f096e533a6b35a9e1436c5cb122c0a71574a03c7980b211b8e4627e1c3ab7a0314024add00000000000000000000000000000000106f396f6b3ac247c6cdc28c14f147de2b007c14ff4028ec2ff36e57e8c03547ec874a33ca569d29088452a3a70f90280000000000000000000000000000000019c58669d1355fbe838019f124e87d8d2adb051cdfd763d70c43a1d958736af0002a0be49997d21fdec7a19fda75b2ed0000000000000000000000000000000016d94d5968c790dc23c5f83a995d7d3e98763a4a05a99b0ceed7c19392932b8ceb729099ea37b94c6d3e671be10881841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8abe44fad75df26c87fe24d81c37f3ad9ae2296d44ceccc55578f1c840d862dbdf05617e35b96976fa18ad4e947cb60000000000000000000000000000000014401d2bbeae4169398f55bc8a68d89c25a179b32d43e33d790a1f57a2905bf76c24993f5c1d0bb8bc5e0da167c8ece70000000000000000000000000000000013cd2e983d82375856105ceff18d4f3d7c1f37a15c985f26bc4dfbd68fa9c17ccd4012b0eb6dd46867c8c11114217bac000000000000000000000000000000000d6d99cb4b90d4085fe9cf943aa24c064049d196b98bb13f4f78e48ea3b8e454eb58b4bf9148e9d2d0d3ed146e544d431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d9351ac36ef705d824943a224e591665ad0c702a5a4f199e414b6e3b5c78e02afcaeb7e168a108e1e08a91e098bc0bf000000000000000000000000000000000ce8984f73998071f6e0e474c880ef422290a090d9718d1ea1ef26f199de2897d54eee65c68c1d07cf605f812b922f6f000000000000000000000000000000000ca78321f8d2e38a9699a653061f6e76a52b9f602780ece6ab9afc19f27cb24034c31fd4b9d4713a0bec252983d25a0200000000000000000000000000000000117c034af42983b7d24a4499e6b0d7b8ededdd1376a1abc951993bfa7f89d20a5157bb724f77489acbaadda17efcb5e51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c740a9380661edfd62409a5c036f734a878e5cc122dee24ed03f277de70d8821f480995003fb361b4ea12c3e2f0ba00000000000000000000000000000000000276cf71f3adef5fa430b8dd2852384036e0474090a586aae38a66d7bcff663dd58a8cf6d341d2d2879b3680c17029b000000000000000000000000000000000a01d0d8a25a66fc3dbe3c4a11aa4c6ccecf5d3b594382836a6c26006a67b3b7488597267a65e1836cf9a89284744d23000000000000000000000000000000000a5ac2b43f92b0640174de668a35dc2f86be6237f40677f47c82821cbf55bf2a9b50498d5c2e7b70d5f2a2db1f8fc6841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000aeeed166d7b11e0c8b1c65092b40d16f8790d7860a9eee4c89f5d0a35f3238b5ebe1d4842662e755b848df09f3bcf730000000000000000000000000000000018ceabbb63ada9a230659ee9728b5f14cf8e857e934181e67bf040c42daf7de4affe5e41743cad6b5d3046ea8f03d25200000000000000000000000000000000049c863eb295b87e6619475e5b4632fc08f275f8f32a31cd97125fb565b8755f316c20677e145e0eec38520e02bf4eb2000000000000000000000000000000001897ba567dfde72cdf30ec183e909e04d808c8c23ebed817dbb4807d589a5ecc4dfd5f2fab486fa1a7767fc62e1e790e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000076e4bd310f4dae8d66d4b53641269e5b379d34400ab954c0452fd194d4346005b1e0771c1c2471109f2eee6dc3c945000000000000000000000000000000000070cd80eb7d8c3ccec94c0f900a301dbf2d372dc8b602bdf3d4a0fa8618d701592852cd36a5dea20eeead5b4f712fee800000000000000000000000000000000156475dec4773a0418f669d40434b3f25eb9c2c96ffea2dd953bd8902a61f33d0d40a1a79b5de6c158b08e7461d027ea0000000000000000000000000000000007d998e9ffc4f02036d0ec51037063420fee16c579c30efd9161b38cac389148b50dca5d01d492b4dc4b9f6ae832d8ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c7a326c00f3dab7a7db7858fabfb10420d369a7d30dbd73e5d69547641c93eb7153cb223f0963c851c3fd55d3eaa45000000000000000000000000000000000054cf6b8cc80016886573e09fbfb3fee0354f2ccd38f1ccf0d212c5379cb04dc4b3878f883316dcbc6552c1fb63360260000000000000000000000000000000011e635736a42174dc7516e0d04027094ff9cc4b93f0d03f44cc00beaf1147056c79b5e543f7e657754a1d8e0ed15dce500000000000000000000000000000000005423a00b8d5be1ffbfbb43669be726c95963d7a8a08683dfca1ec163f99e19b4a38e688094b8855a93be22200c52181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003bd22069cd233033f8c1d3b2916470cc28bfb205373d8edbd708750f1757dd2788f54c86ba377ee48053977c71d99f20000000000000000000000000000000000d6a2074905e73acdee2a68962bcc4486a5582f3876698be10c2e5ec0a5f5fd098843481183343ef7475881ea51373b0000000000000000000000000000000008e86f0e94a8492e689adb757ed465d7682f57a8d72461a5109ef11a1d4936f294c5e9b4f5e56607b6345361a4c4c9770000000000000000000000000000000013581fde5f973292678d876c339dd5cbb6ce57521c2c4b2711f464354fe805c30a62568c7e3bacbcbef47cc67ef150791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000114a17e8ad25e7406ee68a36be5102af45f26da1c124f14e4b371f43ebad8a9ff9edc7c4641c4281908751ed217684a90000000000000000000000000000000016501395e9c3adcdb4177be93dde731e2282c7ee8a2447878e671be11c91064e90fa445d548533a3dacde70b1004ddd00000000000000000000000000000000017a998652efe309ac621784d4a165ba2d0bcb907bb5074624f23f469f157b4918f004f4a34d246bb85cbc93401f2270c000000000000000000000000000000000b2e891ee80afbb636ea80a44e5e7a61bb5c7a295bf429e82b8aa98f7b994f9165effd787183db75ba950b0aa95639981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a659d7ea97bbb4443f9b7aedf2ea90628c280773585d76e9ccb934146a01fdaa7030ebe1169e66067dc0a55068bc7850000000000000000000000000000000004ab533e7a52e4f339cb17e52bec0fb7f329392805440333ef27bcc25b040ea37203d35fa7a1b43b8c056d3e3e913d740000000000000000000000000000000013e9e9d260b02bda35b626a96420a956e0757429396301cc1a40e3c50599f18aecce2076d50e9a3c6b75666a53d305fa00000000000000000000000000000000149e04d07d4775efd7f19b8a973c1c1956dc742bd65bce47f3bdb06e0b23ae7bb44e995b64139b72eb55f6ad2c4ee63e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000fe359021b94fc37795bda8c9f934ed1b6979833e2fc31fc3af7d21793d38a292f1fd1f476834e8263c698dae2eb4d530000000000000000000000000000000005a9caa42b02282f87174547ee49ef7207aac3df969049bf38e3f2d3de4ffefdc580003fc6a834ef4ac853212cfa458d00000000000000000000000000000000127c38a8128dc05401e44b950d1073fdfbcfd62c309554b60781ada7faed08548859364e13ae2611a8890c3fa4e4ff92000000000000000000000000000000000fd8dcc05bd1f9a9e0e6d886d7b7ea53df47ea44c61fc8a3f3b35095fe8d8e577966c672089f1faa46e0cf10017cca321824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c90a6913b11501de10f3a49033c880e7c06230a0ee9fd7eb604c86464790228f4bfb5f7804377d25868f75b0a9d733f0000000000000000000000000000000003a4cc92f612b995cc7a0b414d6990e2f8147594c61b8bee7b2dcb20e50f0f98d60bd6b39aa4e7c47d7f59d18ba0d26d0000000000000000000000000000000013d269b30c504d8caa273b0d9877e4efaa87b95a72527ae960655c5833e6279bac03a3114c8f5b67cb7d7672b59a7a840000000000000000000000000000000009b3e68d04cdfd410eaaa29bdc4280292031431444da767ae9d4167c494fc464184d06330140b3a4a1579e16973a65ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c34dd384673fa91d37b444bec4c7d92379ac92bd98f64f9f7ad96f74c91ef190c5a9ec18802909a6fb77fdab582fde3000000000000000000000000000000000d42489679b07b93e23abb4dbe19c4a6b776d8d86c85a0d16ce039cf585c82d010081a4586884019b878ab9cb4b88f15000000000000000000000000000000001876216f281db581a351686d1b7c0c564b40811ee7f968e9bb0ea393d4cb610ec2fa24ef27db7425ca54f8614b55597000000000000000000000000000000000166292886c3728021695e28a18c48323e8afbd6c50f97ec22e89c2285adee2416d057394ee353ddb8de05f76d4678cb41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011076613bffb6cf2b0bc8b22f9b47d379f6cf794877db267b0c489041172ba892ed2887fa4a935633720d15759c20dbd000000000000000000000000000000000d6608ffbdc80952c59255ab400b8d70b5e6ae325cb8c8d3a3130f219f24315de23d951923594bc8aabba23e81037da90000000000000000000000000000000010c8899827fd80778adce74f463a2f859315717492ed9fe9c28b5efbbc450e795d0ce4ee4255464d0575f7dfa66b23d5000000000000000000000000000000000b1132e2c43d4d7121b53765a83b86450b5141e32b1e0de8de4cd99772855f219e80f1960951798a45ec8e0a704b0d4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004a8a6e776a2d079adea228435bed8883731046c1a503768a4e258ec554d960af0f3888f339d8ddd3d9c369e618488d80000000000000000000000000000000004119697ff4b5e5e80d0aeac8907147125fa58fa03da8bf9dfa15bde6a7f6dcd6d22bdab8fbd835704243938cece243500000000000000000000000000000000181d77bf29b0ca13bb0c63465c22e5767171fc1304c2e398e42ce08d736a770a562bf5bbc1b4c1d8bf38a16481ccdb5f0000000000000000000000000000000016522df4083d9fd61cb55268a193e298d6d4ff85e142408a2458f3ccfcaf6629f4f760a9dfa8614335e5f6a54d13e9a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e40b90704e1d011480ba4f23b55b10990806f3893f16f19b5af1b9ff912751fdb697a580ca3636556e5ff8b287ad2d700000000000000000000000000000000008e4cecf52f2173f13af160245d085069d176ccd0fde746536d22a3b6be4ce4600cb96abbe99f514720adf1b7f27c57000000000000000000000000000000000112096263a0f96e7cff6f4e591f81f83179bf31dd2530597d7e2a5672b743bc77a3073b5cb7e2ebbdf4a1d8c822306b0000000000000000000000000000000008564ec67c9e03dd82197dd53f97227a395e994adcbe78b8cc1ae60db7b516c1f655eb578a61af4be250ac80bc6cda991824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012932453f18a7b9636ae94c301ff770ab9d4933ae76f685b1ba974fff080d0353fc7ba6f90baba1974d13c48dc1274e7000000000000000000000000000000000f1400c9fb9b5dd663c2ea0ceb9aebcdf8d278f9a6bfb0ca1bddb34c17bd48dbd9485507ab7216f6a8414dce275cc464000000000000000000000000000000000d4a1ac04a5e2e72ff0c02c4ed6e4f66bc3ae6a5575c3d5dcddb0c7bad3d98a6b6cbe65143f959c4c091b6d04da9431a0000000000000000000000000000000006bd749afd600587773530d214b79ae5229196ce71d86e052534f670bbed9ae3cfb5b61d181d70ef504c935d42d5af361824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c1c65af8305054ef717f1d97871a9fd706e827fcfcb238ac08be2fbc9fe1128e7460dab92bfd3a33a3978d7ac304b470000000000000000000000000000000001aea908dd74c101022c7e21c04af814bbe6f2114b3f790f761e359f1399677eda7ff1393b14a490ce91a0e6f4e8f35300000000000000000000000000000000163f1ff0b9163412551bc66618de7f8b2cfbea9bd3302ddb680566f93582b9514f17f8c38b75d53c5955b9229d0592be00000000000000000000000000000000101518c20316176ad6fd6b939d9b316b15c8c56cb7fbf833c5c1c4c4ba15ce2e4329f64e6c15b05ce1ca29889b5432cb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001553d033b622a1f43074842b5a406beb7e19f4ed5ce7d8091b0e877ff89cf8cd8e021e82c197ede024f776c684dae62d0000000000000000000000000000000005f0ef9eebef4777792fc434b7376fdbfdce36db09093380b9f4c3ba674fcd85eb952ec7d5485178593a4104596594490000000000000000000000000000000013fb72b0e82b1e14ae41893b8c8394ddaf25e358943eaccb3ed912fd19e6f550abd6dce2541bb54b35b61c3a0efa4f9d0000000000000000000000000000000016035bc4c10f7212d1a4659d1d3f8e2696abf8f03def6c5207b8a0fb8dc82c9e543e65bd5692d66a4ff24d2544f32beb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e8db00c8e27f6c9538dca2fb1ed120aed85d6c70f1534992fd69b19ec27a7f5f6574fbec880aea2c6076e2bf01a8bbd0000000000000000000000000000000008f1d3c1d87ca51f68b1101a155c1613bd60ec1aa2325f3f48bb39dd841eaccebed3ba053b389c027d8582a5801bdfde00000000000000000000000000000000169eec186bd18e5019125e8934d2621349de731a8e80c9224e1404f37daa81dc4097e10de3318f13cd6f8fa32aa4d2f4000000000000000000000000000000000d180b02b0fa06eae14ae2e629d57983a6be10c2b648773a1caab83c927d5dab637a8d0f7cf1ffd2d5a6baba3a131abc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003bf543c98b68020e26c5e8d03e81f33a6bdc8fca5b312383f4b055dd198066ae3eb15168b52bf3e4add4e6b0148253200000000000000000000000000000000112a6629a7814c8de9a89685c083f75306ea52ee7f00102f1fcf01065b21ad7c81918ba037af05703cc1bf47ba9c44550000000000000000000000000000000005ed770e9bbfbb323aab5ed5ac9b8d6cc38acbd613f2f2a7f516fe06136fb8cc6a3300a4f7636316886478c457567b8600000000000000000000000000000000090fc0325e97bf20ab51b6e45e77a99de929b7404920c337d811d04db43f829c0eeda9bdc1950fb2f5f8948fbe18b9cf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003596c9296a8f7f6744836a05f7760a0ab6b4318874563e49e688d9c8219af0fb700657ad718123f697be3185ce2e6df0000000000000000000000000000000001031fbc80cea2eb8f5a1426f78851469f56630563c92c1386a198a4efae3f20fddf5724bf2ca43c505b885ff5ac4cf8000000000000000000000000000000000b2ecde10665dc9fa228acfb349c5844e937de601af24270ec9a03bba40fbb46d5369ee84d8b3d19471791f280fd614b00000000000000000000000000000000118c44871160322d1145312ca065430894a08da9ca527b2a874915fc7930f7be78060955cef47c1a56a21953d5526a331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019b3af8dde9b5473c2de6c7ff8630c3a8dc102dd87ad1bfd75181df4f7a8081ec0259dd89a1ba2a4a757a4fd47b243130000000000000000000000000000000015096b7569d790136f95a58d85cca1b1f7cbc65587d45561abe417b3494e4477b773c0d98b36a4274c36c0b750d0b3fd000000000000000000000000000000000b29f95b84a4d18b31973a3b69fd956c873ebff362c6e0253149f98c4f4fdee9b42837a30830ebbebfb189be9eff6492000000000000000000000000000000000aae3ad137e91fecd02105995c393f88c95efc71f860120839a8eff3f47bbe2ff6a4a9f79feba374462c015bcf77ab0f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004263c8d9ea0a330300cb4830ae76b8b7de2700bb5bde6b14491e9c47701960ff5d6c47064a09abc3309da278aa3183d000000000000000000000000000000000f1bf5c6bffe11a5fce0e59977edfa1c3dde1e0244a15e61b60b5afef379713cdc8dcd1118424703937f2dea490a65f2000000000000000000000000000000000cdd880536481144a2b32128659cedac2427cde5afea533a7f4307b1ce7ccb51831a8e8dbf24388de4896a9b0fad21ab0000000000000000000000000000000008c536eb64d2ab3a572c485e9592abcbea7e8d66f0da46cb216ed56f57711ab68c0cedbb24ff06315223ce95c88798b61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001761a37754e58701c38caee53752502dfd1d21ae9593ddb8055ff2232573c3a8cec59d17a9f45a9c28a2437d50cfebe3000000000000000000000000000000000c1a8552a1f059672a1cf33a91815a84725db6008950d60de9c8348b3c40b6fefdcdb96a8b05b0e51df20ec59d95a31f0000000000000000000000000000000014398955c9c4c227ac2914eb88810dffa591357fcced5416daa7ae698712bb6d1fda60f93127874dfe4fc3ffdd703bb70000000000000000000000000000000007ed13ec9d402bf10277f2157fd0322f8e74844b9542c251a81d2f5e2b29d4ea00960707d3334923cb2fc375c4813a8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fc934973a609315413fdd01e5ba712bb388ad1b90653a77eee5785a873805d6ac17e787ee5c3d518ca6546bd4c1bd50000000000000000000000000000000003de2cce604421255271c12173256278c4205902ebc54053f6126f5b7db74a0280a1b937dc345689c40cd3e489e417dc0000000000000000000000000000000013b00489a1be8473d9f5de62a9a04678f21a985f6eb38474997b4cdfe022aea226679457c2b20660f63a297a91d9eb4000000000000000000000000000000000113336de707f7cbfca8c1584eefd11f589b450cb9ffc6a6170952a8a7c83c660105c0b754f6812bd54b25728000093ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000043b6637277d95a91b09d7caaf198a1d12f174879eb949868a117650890be31976dabe4d94172a912df4e1f3bea5b2d0000000000000000000000000000000000b944ed882ded4afb80e38d4bc9198fd514db26a7a2961169b7345c355487ee6f43b834881fb76b1a15d5f110e45ff76000000000000000000000000000000001076a938b6e182483e262ea6460a6176580a7c85415e53eb9e94f8daef239728776dfbe4c9c8a95464c4eb08e0fa2013000000000000000000000000000000000471ed648662035cbcc685da843f14cbb5d4ec416265fbf289b694d11f8d265c49369e4179e4eaa85a235698ccccae2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094741febbf573f8c1abf410fa21015fb14ce5748c0cc9dee332b2cea95eb2c9dd815e24d7cacfa24bd1b81d72a9651e00000000000000000000000000000000066a66b8aa45a66aef71835aa6427ddf37b16eb65887a06864380d41e264df5c2518c11ae38c530b54184d223aa10e7a000000000000000000000000000000000a30edf74548a4a921e2e62c4bdde320f8cc795b4d749dccd832d2050deaeaf452a2b989a15faf212072b76a0bf786e1000000000000000000000000000000000c644125e1541c3eebc18df5b8d1139eb385d8945c6131329ed6167a200871f88c2dc15c7c5e21fba2f99f15d2e84e431824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a58b10792e64bb58871cc738d0adf631a95bb6f006c1eeeb4b7905ed41bbda196ab24662b227e092c9988c5666bb9c0000000000000000000000000000000011fb6a56ba06a9c239b47101e6fa2d85360a55ceb0f6878d24afc2d45e63b367c176075f8a360e87f2b8a19f9d314d0d00000000000000000000000000000000036fba5dc42e68d18e9da3bb57e32eea835608e01d6e2c10becb328cc8423ee4126a5ec7bd1922e3e7e3dd5b70cec6d40000000000000000000000000000000000750f36d2ed2bfad5a9c99479b8e7d8d3113beb70f43b4c00bfe3b545643467a9770e461ab0f370f67512b877b73ef11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000141fd961e4eaec72e6ffc8a6ec1c201533cbed22c71131e05a7af4eb862d749e33ee5b577f51e40ed066d8768b188fd9000000000000000000000000000000000ed253284e17c2860e309b17ac9297b33957d90b148aa181e9b56900ff5be90377f626cc94c85fb507b2ee30bd5210680000000000000000000000000000000008f09499000178f63a9897b78b50002d2977c1fec05aa63c8a38341bef8969eb01652f69f629c147d37a0c8984c69c17000000000000000000000000000000000527ff185fb07c3f50f8b56b5367e57300944830e4bde821e2a21acc81d44b39afd50d7dceab458e1b5a1930782c16841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015da155cd703fb6ba2237128e12445d218e3b8889a32ed0f806ea4dec2f9b5a91df6b87f6d798b6dad8ed1831e0436cf000000000000000000000000000000000e1cfbf18424dafcdddbd8d619fe04bf2a6970746413b443dbb7eae79275e06ae741fc8a5784931a63a15c2dcae43e9b0000000000000000000000000000000015f3beb0fd136cbb327d52efcd57aff1649a69655984b9228f46496dd72b0dc904a2d1622b67c8f646cf35f532e3c4700000000000000000000000000000000002831375e89e596f7fdf494b91af829bc2c5ff26a31685ca1c113886853aa4995d51da8899be70cd71ed5795c519c06e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000025698a7d7adb1b7e214c9021ba8f1c988aac626bd62c8fafc55a446fbe24f22b3c3a346324c153e0768aee21fbd80b20000000000000000000000000000000001591c862a715f208f8759ca439b6ee477457b8dd679b6fa4fa4388c7c83d1ad4329434616ca97d330cea79bd5392f05000000000000000000000000000000000d783ef2c0e9c8a6c0220d2897d207192c46fa13a4f0a965eb1c2e6492ac264e036d975e7993f7e5d24666418c7d8f780000000000000000000000000000000011114f88ea27f2235d6f7025608c0fd2cd6e06284a5c91be92ae123391de35e28d1778ae2cc6a5a399ce9c5d5e5752891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006556405ad63aa3edf0520995023df56aa4ca5f89cb9f88a80df053d9fdcee2a7007d908b0fa54a838f9c1d95419c65a00000000000000000000000000000000106b8ada7fe9f96729ec1b5e597c964d4e410861ae1decd34121b7258b4e4b6eecf7cd57ef3c4256f7c1e5630d73e4e20000000000000000000000000000000003c7e760026812060587bde37f0ee36b1f98cb0dc673931da468b3f5490f0678a8aa3fb2daeac581e6ea4d12a750606400000000000000000000000000000000171666266002f3677e7210996c363f0173d62b633784a8745276a25f239888c89793c0678276b4ce863a3d4d3b9411811824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000091d5864bd824bb9d2557b68f9de3f031f719313fd8b9e53961e410f79e37290eac707fd7a5ee28ccdc4b83359e65c56000000000000000000000000000000000db6f8ed9bfe832899f6bf14b2ac4bca5ebbdc80218403312e72a4bc27c219b0021d831ce57bd2af58915950358fe2c70000000000000000000000000000000010bd2eb5b65cdb72900edeb058e5da09d9071130b68e442d523acdac27220fd5da011b9b7a572516d74d3fd43fdfc733000000000000000000000000000000001624fe0155ec985ea2e3def4263b9b97928620b63793e22b7498bf83218ecc3c6cf9803c447ffb8723c2ca0fbe9f53631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c683dec0c017398b8a33f67077ed8ba39099874a75cfef7b35171c329e4bacb0ea931264ef04f1b1b77e3a93e295ccc0000000000000000000000000000000010ef88938593a56d846065eedbf72185e67a8cde91f78c49ca1cc0dc8b036967442b6b56a22449911c7c4eedf52bbac00000000000000000000000000000000003cf7d6d1515f83c35d9fe1c75340bd05b5284c3f5dcd08de4a0df6480734f6b91d8859ebf506f4b390d5bc937d0062a000000000000000000000000000000000c17332e7f0b062f1b859ebd46a99b7164a6ee9eb2a0ac4610cd79772a0b7f50f4607c267a028ffd642016eec0ede8c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d8cd5a74b0bf0ddeb256cf97f4505247e5b53199dc04be1f3020d0864beaf208c0a241388da9f15997a662dd4f60733000000000000000000000000000000001421d35626d2367b20a0c6553bb00aa59b8df8d6f41ef3c02d4310927fc9ebc37a32392cfd4b858f2d045fa5166915b70000000000000000000000000000000005fcf311b4aed4346027ecb663756651b322e2fbc08aacbedd19cd4d026cf0c1b9a186254df6d0474ec644ed524732ae000000000000000000000000000000000aa7377e3500a797bf5c58179e2cf31398a07dabea5ee995962fb7ee437e1d8c3240dca891446fe6e7ec36f1da957c821824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c466ee9ca224efbeb025f1d69e9b2ce25c2ba096801ef3f51da07d982ead125702f0e11474fdb23c3be32ffd165a6320000000000000000000000000000000019ca6989fca100a5ab0cbcdbec95724f2ac002811cd3993ddb9dfba3cc1cad206e71b612cb0ce3be4a85a42633321322000000000000000000000000000000000ed5fb711a2acd6456ec2da9a4dd2f1542a8c0796ac0fce2e24380cac6cd8573dd79586167a55fb5bc0a2585cc1ea0a800000000000000000000000000000000158c20e4dc1eab22bf97e75d9af4a00bf759739b84824282a2fc4f5ef723510e0ae305e4783c2c6b3f1a658824c19dbf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000015fac153f91d15a5c8158aada69d56fe4fcda32fed73da6141c6eb54feacc96f4ac79deb711f4bb711eaecee2f70b1b0000000000000000000000000000000015c7c796d34ccfda01c014742d0372ab5d172e345c64fc0b9c5eefd3092797cd71596a91a10269698ccc5617dd64a66d000000000000000000000000000000001482f722d2c1cae7d7bf30419b939190d198f6a74e5e29de8236c5f116eeafa013646e328e13a22f98425cb5346cefb10000000000000000000000000000000019747f33ed0ef91f0090353f5da1e607f462391f91f179b89f0e4072cc9151099a78654787b426d3573c99b18a6226be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004dc2cdcdee7ce704348b19f03d9719d25b01f7ae2ef06bdf5019f095022d724f6740d15863cc76f39fb3236005ec041000000000000000000000000000000000e5c695835e591cf4175252b87979ce87dbbdd71bf6f43104d40ce2eebae184e01d0f20011d674f9a1d5593007670f21000000000000000000000000000000000495db7a051e7a410f8f2422820caeb7ba0305321d1d3e4bcb0f28c9fade60c68e325d8ac8277f52d4eeba6f4bdbc459000000000000000000000000000000000135a21462d7a49a7c9cf7912b683b83ff99c9fb8204a88964deeb43174f7caccbd6adfe3986f0b1912ebfdf852d4e8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000bf1d665765d7b4a19ee70fffc5521554b428b1b3e76d3b64a4b8072d7800f7ce2f5ae589eb1fa77da63f3f8957c6092000000000000000000000000000000000cd4ae3ca4ecbb7451f942879504ce9b2197fe86c19d75e201f16080ae0e7fea09c3397eabb1256a095722ca94872b17000000000000000000000000000000001506138fb2e2c0c3b37eee21759c5e31f2a2ddcbf89a6389b09c14d0efbecf34b0ef1becbfcbb55ef5f987e8545f80e700000000000000000000000000000000087c6167568d2fd49b8901e0d8a487d776666199ce37a5a022076bf6c45f4ad7980d7144de3c6fdb8079b43d9d530e601824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000094a7138c5791a68a90c2d59366fa12794838eb83f82cf7acb0a7d2657cd55aa83e81b8342426d1e5f180b4176de79ce0000000000000000000000000000000003845ed19a6fe121f4b4c09d50232dad512a51dd0a496e7a2dd37d1c7a5b779c6539e5234fc6cc30bbe3a644127bdc4b00000000000000000000000000000000176b8926a5732adfa97cb3fdb7ab5d70264cbfefc79c1222752e847e5545d278ac466f1bfebf317abc6dce42bd616beb00000000000000000000000000000000048e64336bfbc1c0b004a7bb00f65180f7c7f213b565d1133b0b31e79262eef477cc97362a9b8046d05c7e81037a688c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010797e29a4900b5fe01f75ffe3f640e6484103c80e0b0f3aeaf1c4f79dbf86b154ca8f6d2331c13d8af2c13ca82d5792000000000000000000000000000000000699bee300f14f83c19ee47ea25b4c90cb1191a00120f476e582f3348dfbc78ed50625533117989f15b2f04d6ae9bcae0000000000000000000000000000000017291005915567d8c3d7389bf3986f0bb2428e3a03b6ad0c2b0a9335c3036a5023ad11fa1188078683f1c9ee93746020000000000000000000000000000000000663496a95a79c05fd18ac27a3138a3287f83213e1b76a26bfb194b491a172d7b87df955ccf14eb45a8e57221cf8ac4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003cfc9bfd507e5cc70ba4fa6c9f68eda8ee3f7c0815c8cfff63fb7809087f112293e9b31f8327eff59016f718f68c4e00000000000000000000000000000000002d039735aa9e34261ce3ab102bebca08d157e6ee56126bb8fd1f62eabba1b6364bed9b0515857f49c769715115561390000000000000000000000000000000004946c5d0508945d3a31c4c67d2e1f3b963a05b468dadca126c7ed38255e1d4c69a0da8aaa40c0368581df4ec91316430000000000000000000000000000000017fcd079e55e6f9dbe0890e81f111b11a9e86693b2864a549b884e8d8c10803888943ae1efeb01347dcb392b04767c091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000133f9519d4cfb9e6db6dd9b22a8dd8a566f49c1cc1d0278eec4abd178b44013145363dda08b71814520846feae4ee5b200000000000000000000000000000000014234e365fcfa6c4e8cabd3f4e54d8885b1558111cae3d360dda8f7c039a9300667b7c00443d7736b59c6b324c51c4c000000000000000000000000000000000250ae48806537ad044cbd829105d01bd0687c9991a4d585c2e25f1bda7e48eb05b6bb994f870905265634e2f798464e00000000000000000000000000000000070b9ec7eb94797cb4a02e9969d8c1ed222c0febb84ebfb8f164054b96483423fe828e21ebd59e2d4052f26c286bc0e61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a8167c191c06a896706beacfa8f71b971f1f9f64d8e8555c720f5e8ea1460715e3c441372e60b93253a015aa7e5cae00000000000000000000000000000000056563cdd51061f617754b658fe2bb36e99453ac79b6b5a3ba6638a7458d721fc146316e8112ab5bd3f54b8281bfb5d1000000000000000000000000000000000b36a794b72050b997d60205fa7e0b1fb5f86278e4217263a82b5ed774f88ae6994c9cd0673c2fc10d7ad0481a1e99a4000000000000000000000000000000000961ce2970a0efff0f0b8689d0db831192526ab7b43263966f17d9b9e20f8e24af56939db3f5081255923f73621353691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000122fad5a5f9b8e9e4121a83f5b5b6ab0ab1e7126a4e997be86e9214e786b22ba19a20bc3e54241df3f1a5a0cdc1af2f0000000000000000000000000000000000a6dea66e830b60826397a49b2a96b98adcaeffbf9285da9c813d46880cbd171d8a6799261b970d6a5480565b46f133d0000000000000000000000000000000012e15feb89478bd82e07911636e04a7cbc5b7cba58cfd55ab268274ddcd9d34151ae58962c30e93741d9a99d3bb28fb2000000000000000000000000000000000241e74ac6acbefbb94f23c2a488e59080b0003d9db02646199776a12d621b8678d725a094089134f20b0cca77818af81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014e6d74a7a1616c42c6124c86eb2989c0269f440da7bec470c35e6669d422ae4eb6a7d0b2f1d8cc1632f3eee32498bad000000000000000000000000000000000dfe924c6b386852a8f80ec12db58740389d3ce23b269909485d588324e7d47cbefe051fe4c0f8a225d11b59ff148efe0000000000000000000000000000000007ac6ee8a33a17339860d3f07a63c3cddb72a29d983367c8a77a2011f62379d1de0fa0ed8c5771eb0215f629e7cea952000000000000000000000000000000000dd18723b7069beff825684a49023174865c36082a1ca749c8ba39341d3cf312a28ee0ee48368f5e96516345ec6132e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000388eb87d87878e4b9635865d05492a10c9cf6a23abb605c0aec50e0aeac819272c21277525d8cb8a27f5ff378ad38f00000000000000000000000000000000016cd0031b0c47a0e73d43e0cdb8c25c9225e6c67cad318b55136527285c00884827eab6d7b6753adf6ba61e00effc894000000000000000000000000000000000d85f9850151d07ba16feceb7f7a64585cc22202ae58d5d6637017e61804bf820f9e928b25a0bc1a4b202ddd6545a9dc0000000000000000000000000000000014f7ab9bd0eb8e7da04a8da89c731be6ce0882adcb2588a5880827d6b616e736c798c988c0f084d3ec6e6ffa4cdd22731824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000011d33b656778ca2f10ab3770159671f297046dd1c75f75b3c456b464060d8dc61701a3e0198bd03d646654d5f11fcec10000000000000000000000000000000015eb4d601f16909ec3c3238a6ed4642f006fb61b84327bb16a51c2fbe10bd98ba5ed9e2b136c4d65b8909b10bd3404f0000000000000000000000000000000000d55bcfec98de5904faac277e189506e9dd4d569ee96df512d13f58cc2da9a08effe47be63507314b8d2e392cb7bf079000000000000000000000000000000001139582b42f59692e72dfac3c4fdfa34e95425f11d32609b6e3761922156b8bc493d00cd8c1078cbf127fc3d9463d4561824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001265fb7bc6ae46529c3fc46add2a7c68d997b1227fd4106281174ed8e65622bfdd1d81ffd48f9f7112452748eaca37df000000000000000000000000000000000d1671659a49c4f4de7f5453c07577411d307c88fa64c5c5d9c81cca4c7c9f9c39752f39fa472607ce507b2c05c66a470000000000000000000000000000000017b87dda4b117d3609088eafa8172a3ff91ba3445a6df6115c0756adc27965020e0a605e3acba2fa2ac9dcb922a01745000000000000000000000000000000001044d4ad9f0d70ad50511356a0a17429320b3ed07c963766db84374a50c21f0b4607bf4a4870a0ecb100343308c817ca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ba377a51a85e0e666bffa9a43aacabf498505a460b287523ee29444dbb8d88b4f580cb685e7b6aec86dad08963168f6000000000000000000000000000000000635f9c31e4bae6b2f5407fb5d8ff45d395a051770d47f66f7ffd345b6899f2141557731852e43d505d2c1ccd9b6b776000000000000000000000000000000000263646a22761d58ca1fe0a85a021dc29c648826894e924c312ba92da45ee288304c353a2760b779dacac49e1cfed4380000000000000000000000000000000000bd5d3705bd40e93431ad76e63e4a2215d91e0c456cb8bfec5deac70a8153c01ff7e4ec88e0ddd28df7dc2b4f7f37ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001558820efcd210c4b87210500dbf928bd247ce9f402f3ccde9cbb561e7c8850f279c4c05fef06cd24ccd6f658715798200000000000000000000000000000000189eb6e2ddc6d8bad1615038a32682c9d4f0e46c1fd7e736ce83da55f1d7057f637f2dc94a5091e4416a642b5831cc9800000000000000000000000000000000173fa28171ce4c4327be6d359a83ed75e6903f3af8e73c89845c5848af9c0b0df4e7b0ce5413112c26f10654bfaeb42f000000000000000000000000000000001722a3d3a3b6e639d70850e0e1df37e4984f6309bde6097e80f3de752e98139415c54b8682f03df56cf043f27d70fd311824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000835e86b09c7953c0631e6521d4eb3392f7044944534a7b2022ddb53ab9c7f5ed91ba311196348a3385b5cf503e44bfd00000000000000000000000000000000015c95f00c6908e2bba970b2e08f95b2a9bda9b738cc045f6cfa91c259ddc29d1dcfb4815080cb87595ff77cc27616a300000000000000000000000000000000130dcc0dfffca7fe40aa6a29dd73ac2a7762b5a351e52bcdf11bab5d84538b307bc7f2ddb6d09150d59ef88db8a06a8f0000000000000000000000000000000009d40bfde86b0f658e55ae724660b55076ffa73ce8c8ba19f41abb0c308cc07996552ed61318b737100bab5038fb5a711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c383ba6282e9cd17b676f2ed0e4cee0600b1ff848c156e12108d85de8187e749833bd52d79d247562b1d2647242ca9000000000000000000000000000000000d425a39acead53d8587eec2ffb1dc1e59e335a0449dde28f2a000e31a5ffe4b106512274bbc6a254813481e8b3199770000000000000000000000000000000008e9fcde4c67faa5d243f234f8bae794524fb03d5ccf660798ba764e9754d89f77698a51cc195c82725ac4b712f5a3940000000000000000000000000000000008938bb9d340ca0362f9659eb009286a82da813d5f303dfb3c98caaf6ecb56dd12da34a52b055ad0192d7411cfd0766a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e364372aaabcbbdd1db491bc5498563d2c618a6dd4b945e01269c0d5ac7d9f47cc9fab05dd89e964a32f313a959ab16000000000000000000000000000000000f53d623291a24a7b16b0fe662252823a3cd13f51d7e17737ff6051f126545fa8a9b15f259b171bc80a4c78d6d85f8a3000000000000000000000000000000000a835cd9b48c61a526b54e346a5ac9f18be8aa7b6102ec65b406802ff3e3aa311f18fab0eb94632e67e4d12baa58f29b00000000000000000000000000000000159c9ed69d46f49d0f6bd4af7e04c97fde0396b8bb01bcc2b675c646a7cde81bc5ba7c4e9f9b8aed2e2e03df1e32754a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000834bd07f5ca9adfb4e8a6940c655f53b1754c6c41cf33f13568d8df974a9ed496d2464819d073a5a8d1aea2034e46e000000000000000000000000000000001712e1c7fbcb92df74ffee1fc0e82ffed9d3a27f6c39d1f46415ae06af12e7e6dd1ead5f709615eb064d2ec4634ad922000000000000000000000000000000000f9d5ea43d714f231443a84e751dee453c0fe8b1def06b0657dd2b17acd8c6391a47437600557b790ab01dff96a839d7000000000000000000000000000000000353fa9e8c50f6277cb1b355db14bf424b0b88e90eb99edcde637228a6c98d6454b1efebddeb77b8647f87aebcb39a901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016151999451c18622a388a840ebc1b35e0c038f80d5119ecda1ce780983c999b14a115d101381bbc703171b3a473fb900000000000000000000000000000000014afde5a763a70668dfe631a68cb001369fdcfa1d484d2dab37404c9e587040da68b304e679fdbdb8a11f8be6215e5f80000000000000000000000000000000014acf3cf03328dcb4bc73bb40ca05f590bd1deab34d7173535bad07c501747d12a05f8063b1a38fa821d323011f3c78200000000000000000000000000000000087354b0e64839bf7602c2cc6505ef530b1acf7fca88b05e03486f9abc548f64dc79b21df28b3f6c6b308fc0c2adc8661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005d2b23b040e35db312cb41d76ef57838956d32f459ce074559df425b7ae462f6bcbeda0b715e6ba0bc69283560f6944000000000000000000000000000000000736eed339e66933e7e083cdd4e48b3b931ef4d8afab0d601605536871435442ead4e824ea37a0f2113e50f98c3052a000000000000000000000000000000000130b83a227feb9765ec77ea6ae34d787017eb4f60849f60a78801d3d80b5e3f363e194094f748644b18d2ba12b27c68b0000000000000000000000000000000009c33360e70b2fc08a8ee4d5c5d56ce1078cd5549e90d7246e9462934648bd8b062db2c0be8e8cdab4d6db776b47961a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000024b13eea5366357fa852bda231dd2d17c405fb405e903b3cd0d5538a6b829ac428f565193ebc77e1376f70ff03fc3df00000000000000000000000000000000147d549543c86fe83a7395b6fe5fb9b1c28561eb51f5b6212348183ea1743d6680d048cc881a0e76d605ba372a3e172e000000000000000000000000000000000434cf4cd629703fcd75c5269fd17d92d959acf10f20383849eef29da56947f2f2d6682d4283bcc8dd3412485ac60e320000000000000000000000000000000000683431fa5f360ae2a367cf8d9f39eb261a1e7c4617a4a43cae1cf4b3c1310d91450b26fdf4c5d6261cabdacbedcfef1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010eeb920fe41ce4952c50bc400db650fcca7dcb8bb29ea14f1607b2c1fc604f6fa4d3efeb8d6cbc79231e0216a9d89620000000000000000000000000000000019b7dd44978f46bbf2a2380596fe3551d39f426131421d5f470a5b8ddfacaacc90fd824cc8bc2f8759ef6b6d783dc22100000000000000000000000000000000088de28f137d782a6647bc917e7b1b3e4f17d4ad7098f4beda3373814b0c3bcde6f588fec3bfd5276ccf5ba18bf10e9b0000000000000000000000000000000009829f39d63616a3c3875385b12b9f029cc7de41ded5d26cf7d5432be6c08c9b09f9c4f8464d35c2e9c4252ec0809ce61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d2e1f4a6eecdec53b63317b171dc485192988107c7e2aa9d3ef84f5ca7c3a4006646e9fca3b8b9ad451779a61031cb00000000000000000000000000000000164d567c6d6b8e3f8df6c252c918c124bb0bf36dc9c98fc1298128a909cb5de1827e5cd3dd62ebc42a9968f87bc8c6bc000000000000000000000000000000000c0dc7f3d9b7ae6724cd374b6716da9dc041ddc0b78324076f40e0f9c86a9a02b001c825c09da258b0a8175313b3a5b40000000000000000000000000000000012bced71cb57dd2f70907925a3ad6835900e0acb8b370b7297121641d5abeef473d6e0805a024b99c4e15bb321c0e5d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001539a337111d7f25dc8460aa6f2cb3b1f0b80433cd437bad0addcfc6f376be4736642dfbb8dd4411ffb80e30c4dbd43b000000000000000000000000000000000eaeec4f453cc0e3e814385c9d84fc41e5ab7567b89e9162df0078804ac570432cd8d7e00dbcf45e3f6f40cf7c8e556500000000000000000000000000000000036c6a34c42943a156831c350a8e289f319ca60fdb4208a048197a16d6da6a875356c8b5ac079e49ed0eb44692c2c6b30000000000000000000000000000000006ad0289b4a108d41dd864ee375ac17e513660e55ba0f10c3ee42ca311a9c7dfbbf0b14fbd771d454c56b7baba1bef8d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000017ba8f35367eacdd681b5d24ba9cc39b8f2635975d87fb9899216c51c6445cd6f3d7e7109ea2fac0d0cd4c0767e2d30400000000000000000000000000000000084d88829dace9719d2667b84bd919ae2c5b14f845c38bed640e2fc91b114a568d67fee11e66649fd48760cd60dec3ea000000000000000000000000000000000c1ef628647e9c967eb409a965eed091f47dec4d6810d4fe4a15e3292e1098a8f621afa05e9d0e0a7b77e41944b8ab6b0000000000000000000000000000000006849a02accf1601750c21e11cbd6cfc7022134f19771efe49058000c6994406ac3325054b314b9d9897390c63fda2e11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f8ce4c439446732e3f13c81658f0dd0506ef6ab6232a5d539dacb75d6b01990efa681024af1bb50f91e2f2b57644488000000000000000000000000000000001401520246d9116f2c53f69258a3f6d3bb10b660e3325950cc451f6c125fc375378ff8a359ead4097829d4316f4b46d4000000000000000000000000000000000c4131f86ab7d4864d555b95af31163b5b5f48f03b4358b5ef37b24a957eec32d751a490e28d5679e62f6b4ffc9f52a1000000000000000000000000000000000abec50a41637d879f77091d8db1fa8e1f1ef03cd964c834277699b2c32041ddbd21343bf0c86b5720a2800ca6ee7d4a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016eadbb358edf3863827f7cdaa5c532819a8ad21066335a6f4fffb27588c483cf18ae754a72cb660b6189beffecacee30000000000000000000000000000000007348ac60a9b2d6b288f412134fab783aa15fefc0daa5702621852cfd15a70d9b2d3dec7c9d9598cf871dea1934750a200000000000000000000000000000000100483e1710958f1841f9f4b588850db0ed179fe442579bd20b36bd6de7e2a93818a77e0343f54da6159c55c3aee1ebd0000000000000000000000000000000016a4db9826d9acb35df1f9f59ae04434700acbc62f91a36486ece774d730b8ec0a8d8cc92cae2d050e8cdf68b576714b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000414ec2911d0f8af340d440f3084b90f03a7fa2ee8af36a3759bcdfe47dde74a6868c6141400200b4ca2d42e62588421000000000000000000000000000000000bd6d392c3871d0b23e69081cf347dba0ebe1403a95d221bfac57be00b0ea227b7c1e981d21b63cb67c756229f75d1190000000000000000000000000000000001a2cd89a5f3faee0b57464ef350d5de48e47a938c40ae0aa721dc503d064b4b7f7cd883457f7b86a34820137f1e4546000000000000000000000000000000000df9624b6676b1f5e869c38499816c92143f81dbb01194770e33b8a5ff027b20a33825df3465c575ed14108ca37a360c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001851a9ce9ccda98a388e8b0b057998be89a046b2f6d55a81fe0d47923eeffb249837f01d57679a70d55aa7a5920023b50000000000000000000000000000000014c6bae92d2d6866cd56c3402869acb0e15f888aa5fa76339c8587c136ee8ff7e0eeb5d02d8f97b7fee7fcce496e0fdd0000000000000000000000000000000000293a1d2dd11527df30161cbe1676bb714c31bef22c95282d0d3c29af4450fa581f6af53a2e2c586b964b103f344c9300000000000000000000000000000000179c341177a4fe720d610355c948b7989ef2f93d7214e25fecd270a79d46a352f783af34b20bf950ded31f06765d709a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8e5de0f35982c372c5656645f0def721b5e0ca79a66a6ed57624ecf42103184f6a746dd39c77d94b14abf6b3d8bf1200000000000000000000000000000000019cf04a281f19b9363d0120036f63957c4149595a21a16285dfc2e88938b41e945f2b565b0b249a250aef65cf28e99c00000000000000000000000000000000142bf0169d953d526735d32b4dcc1af7922b94bd388812a539a05c9621c80262e977a46b209110fc963d96d8be97a4460000000000000000000000000000000013b5624a26c5d7b67e79beaef451828c6dde67d11bec99dccbb04b2aee6db1a570a4b4495f344cb64f6bfe5394f5917a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001221dfd9cd5dc7d0b2e1fa532b77447cc405aef2d9a2332f2c515987247adf37f4d6b5db314114b65129c174231ca5e30000000000000000000000000000000011e7009f332391898993d631bbd5a0de29a4226a9555c80fd310c57a965e950578a3d5b7d79d78e40f7046aba94e310e0000000000000000000000000000000009411ab0fc172bc18bb0e6fc2328d351563934cf363878e3e67c9de7f580559109ed312bab68d7457ddb93957d9a10dc000000000000000000000000000000000009eed5fd804bef986f8c15589b0ac94634c7f5fb82641970a9582c7e30fc500726b0fc4a34bc46c2305660a8d5dd511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111ed230d374796c86a5ac71fdb6317de85e35da963d242562c5e812b1eed0abc0819049c296bc1b38317e486c8aa7390000000000000000000000000000000013e22f39a8c2bbcf398043d54b1ea8f1106d137d179db281548ad1e0975f87d9c1d4b5b7ce1bc015d1f3c9f93b8b8747000000000000000000000000000000001498cccf4c6d8fc2007c18a7f63798b981fd986452af21f96c67bc453c459d36b49d554666285d1c1aee4bc8f73dfc370000000000000000000000000000000017b6fb9e4bbcdeedf579fe687a40f60ddb4cfe881509684eabf28ae933478f82af6109f2a4714a947eaec73b368645fe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000096461ba3aa19e21b5d2f6d9ee6bd3b2fb5c46917f47e896c751d2bdca571aa16f1ff9f03256c7e268fd73c79d2dfde30000000000000000000000000000000017e79facfef179527ed19f8fd21927a5db2b10fc3c34ad847420d59df6e4999ab24a2ccfe776707ea8a6ba38c807a6da00000000000000000000000000000000159f535a1b2a97410d361c5c3935bd85884fd9bee4355833e1777d24005480eb6563b4479aeb20f42cc461dbbd32a9d0000000000000000000000000000000000202ad2bad33895f5a046b4c13231cdbf7d26fdcf3cd754a512e7a0cf8209852e07443f62f6d70a01815d0f5026221a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090ca17c3a27aea9dd866f3a3f1c49eb98073b42933e2292ce6b74e165d61f71ba2b16a31985987eabd473856b7c1e550000000000000000000000000000000003cc688b3750779e99d9a7acb2692c0b330e6d1d43081dee9060cc85e9c1b1a70fd940d2e236987866f728262b4436b20000000000000000000000000000000002e140e1972fec8b1c975b2ef7dbfc19774630fb64a6b0304f181ea4c5e20c22245ea4b354ea70fc86032d1192e09cd90000000000000000000000000000000009173d4d59ce7fc35d9bf15840f3f56a735c5e0a87108b2ebe5be19d3b4aa690465cd59ef2661d0a3d7e88009c346be61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016307218569b19c148703af5f321698122baf03b59251e0cd0469bcf7a8a20d8b9e54a16d2dc1f4a2e2c2c6fca95ea780000000000000000000000000000000010d8ec69d5ea3897197bffbd494e13679b82fc48f5468e4ed42b4bdcc8d9e0870e84c70c1ef0a997175ecac162f99a54000000000000000000000000000000000abd8f45025a5342284a746e2d6ffc476902279f81a7eff67c161c9212a42f7598b5a213b46711d014f0635ae41caddd0000000000000000000000000000000004747ae66bbc88b9838af8be374a84d914548670cf28885a49fc9a1c8dee736023f8819b1a72c1fcf7bb9e175667038c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d65c68026fec5ba5456025f4c08b63669b486ed1761ed1dfdc40acec99490833109dff7b401ac0ef66b7ff67cd3466b0000000000000000000000000000000014764b47407d0dcd32169e0a1b83fc76c0773c8e511141de9344f64e8ac63f5eb48cd8b5c6c54fba4326791b512525320000000000000000000000000000000000cfcb716c322857a46d7a9d2467d4ef1f520f752b7f264abd4b0ee4e9606d255cd5493849ed3c9ebd6f8681255ce53d00000000000000000000000000000000010ea7f244f9c31c3988c8e8859938881de9380c0d773ae353207a7207fe5e11cf52dadfe79c96e5630e916de41a9da71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000153d27abdf1dd3dee817d9262dd41e54134d8ec21c350fba833c3a9105b7695967e4d1bd5828a42a17a49baaaac7d947000000000000000000000000000000000b88ac63a84dfe3ec5d12bbdc2c91d6b095b2232fb071d81041462a08e6f82cc376fa10821e3df609bf5d26d708d78880000000000000000000000000000000018695c06ed0769453546cd1ab92af6e6cc500b0ad74b664bc378eae8f6ae533c4163316a14e98d084838274527a4e3a5000000000000000000000000000000000afa982eb924c3a70b47920210986d3ee3660e4c1765377055d7c9a087112e68023264f7b1bf2248a91a3c5b3468cdcb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001eca2992a6208112a2bd9af4f48b7b4b64f23a4745ccf6e22ab271b88e4d1a9f1dfae50703dc408f4a917a2685e53f70000000000000000000000000000000000c291bdba0e6aead00c842c522baf92fe3c53117618e8a7e3df9bf110619b5f01290d291cb309a651dcb49f65e470f000000000000000000000000000000000179b4eedccdbca1966b94bc7fb5da250656e92243f7c4d301be858733ea73f49516ae25d6f5257e60285865ff26c1ed4000000000000000000000000000000000f1e7a0cb3a9d8c5dfb5b96c6f01afbd2c7cc5542e88184d8e0f72a6c24916e91e4f8fe2690c9af8a9d82cf737f02c111824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002431782eda44ad08e1b0eb24da6effddbe2488ec70bbc81c0e47fc384fab905070bea968fbc1a9fef69ee0163ff0f60000000000000000000000000000000018434211578bbc2be210c29cd3820b1b8f99e4ef9c39e8db8982e6783f1be62ea5d84c8ff98ab420386590b7b0497f080000000000000000000000000000000016b1f18bfc818ac6f8b42b8d725b4e3d108609b55827361734a1b178d567e5a91375118089d59f0096415b02f80fe6ca0000000000000000000000000000000015311675dd364849c0b15b3e68fe3ad222c381185a95be25233e9f72b089b271ba4450db5b5298e9ea9dce5b4f62ee951824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001826b931f8f36dcd99855fdc37f2f76fdc3831484d9ff9d5a4dab19dd80a78f698ea26fb7816438757c7b43f85ac3df00000000000000000000000000000000001cec37a4c3a9cfd37d47199ffed888a4e08b8926cc81c521604a9102f45e5fb45fc696dd5d6c5ff8ed5feaaaaf25d610000000000000000000000000000000014b01fed71c43b1b2763ba6adfbfc77faa1d05d8f92f96b4d1d27513f106cd9308dc4a8d14ed63ca7f885a36c92aadb7000000000000000000000000000000000692cb1c34322d501e07cab7e9f65aa9b7ede69ab1cb51d3a46f3523ba11564b3d6510f42649903d98c6f4f640c1e87d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f63a21485c9b69c46dbe177e5d6aae9e0c0972450575f85cafa41d38b701308fcb4615231bf3670d2c65e5968931e7a000000000000000000000000000000000a2d2a9ecacbf2853dd9657417d1056c42b62904eebb1e2a91297fc73ffe22c09d5a6fe6951b7b3ac799fb779fb8c0d700000000000000000000000000000000170ef99f741779fab6443e58f54131631a337d1a51f50643f3bb67f79ed0c5d4f76ae52541f141e8eb7a12f1fc9a0e5300000000000000000000000000000000017ade664b2250785a250377d3a2d5867c32b8558d886a0391816f200bf90d3d43a69a02461af75f5bc823ebb63241411824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000976091509c439fa6d0a28ef740be1d2a4adbf7adceecc68193884d3c0991f995bc4cd157ff8ba01fefc7fff9fd605e600000000000000000000000000000000195e4b6d8742b8ad41b226ecba866ca0e2e19f132d2421110256e71c8efecd08499928796bf0dfedba7e5a7b5b4ff8e8000000000000000000000000000000000b238a6569412720060d1044e4d22d61279b8bbb5dc7036577a1c7991a2ff18ca04c5522399890b22555ffdd4e3e9e94000000000000000000000000000000000278aee8ef24f25801baafbcf353f1ef8d0b6d78e5dc248791a27b050d207688ef9180512098c45ffa0e342e6971e5871824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e2d0cd0111b5d5078c9194bdd84158c7022ebf87a3853b0ecdb9ad1d661a51d742b2371769f62f4ea8c0b622ec7f5f0000000000000000000000000000000004a4e735ce00444a58212ce7151bfb09af25a9d605f72e3945d7c1a39e06d7be45c65b4602e39708d1aee1c66280831000000000000000000000000000000000181ae1c4fc4bb2e998a3088f025c06d5f0bb1211d162d31bcd30018c3d12b05796458eaf46cea9c99014c40ba3dac6110000000000000000000000000000000019514645ef5c815bfd4900266363a04d76a8aa4846feff37c95425513bd07c413b290e45ef6768546c575ca58ee6a1c71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000159716deafd9486d82c1edd265e334d58daa3f715a89e0b138b2fb5be8273e0cd6af4573804267e3caf1730152b3f838000000000000000000000000000000000c5efd41e630583860e09e28a03aa294da83e21678fa1d66c126cc414d3e86126126c5814a1272152578e8227c66604c000000000000000000000000000000001003959fdc8b53df3e29f8c78e155aeb88fa1338e978fcdc11ed9c0a8c8058be73eb2de6091c8c2c071ea1583360c57400000000000000000000000000000000104ccb8e8cc1edd2aa4a7e856a3d655b3fe3a3cc29fe7ff6431f490dd783cb435bc04f2c0ccab28da7b6b0b9d988cbf61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001212a2c67dde7ea1e34f8847d6c1ede1dcbfb09c9e4fbd60004aca8ad0e116e5a6ef114682a2c3eed89a1155d786746b00000000000000000000000000000000016a6fd89dfb33da0c3ad21f49b24f43622932d5554a51696182137cd2b4e75a182e99f26ab350b724e9fd5a97a145f10000000000000000000000000000000018ca96cd152882ac920b7b3373cbd5d58f956022e3bfe2b5fb943f663a5026c194f32fa0ba66493e92246435ecb27d9d00000000000000000000000000000000135e65ddc9ebcd7587408d79a460eb3a056797199ae736ee24c96ed1fe7af3c0b06181aed64683b2ca54e3585e63ea6c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001146898701b384be18a69f8b8a5502872c07d2dbaf8b9875251ab4932ebeac48516896239dd26e697617628dc7f5ce9f0000000000000000000000000000000000c2e534f3ab1c183ce868f3a8f7f838ed8073873453334e81c66a3c88e25c9c152c1ccc557d7381c6d3ca227743217c0000000000000000000000000000000015c9bd39c476def60654722e7d66a1c67e5f709a79d4863a986932df324d3098baa81f7983a45ee3b9b243dbf5c7f012000000000000000000000000000000000391e16c496f3970d3e651bfba2de04c3ab8d2030832a96b4f9d3e6eb929f8391459ad0b731af382e92afc69c791dcd41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000149c62ca958b77caa3658cd486e350a153216c597a0e2df863f17207ef8023414e87ffedd9365813765f05fd88b0bad7000000000000000000000000000000000502514928161f0a28de23e929e8e5f2113fff4374ea6c6b48982e99a261f46da0d4619d8ed587b714ae84a06b2d4abc000000000000000000000000000000000978b5c010aee3ff492143936547fe42618ad525e95ae9ee8d045435db9b34f8e621cf78e0eb2b05c3ca7896ea8a3ae00000000000000000000000000000000016e2fc63f0066702f5b98441efe6d7177a3396222a35bea29d86296b7520f5fc20d221e2cbe5e4222bf564adaf3a22be1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007ccd685d94a5d4c35ffe3c9205651bed55c4257673bc4e34f1009bee5648cb2ec5fb468876eb4471c4b207adbb3b7de0000000000000000000000000000000009a47a6052acdbc4ae1ce4580bf65df6e62f3309ab7a5dbe3985c88798fa4cff026d698cda16f2b00a9b97e4d0be85d400000000000000000000000000000000016da47d5358e4faff56da4a4285ebb52c4645af82d90886312258eb5c5bbc65e59f8a4686affd0242688eade58324dc000000000000000000000000000000000a43a1e05a86d25657de4a5030a5dcd0093bcc0bc7f639790eca54583d0ae38508a37809a167e508f808d2eeb5c2cd8a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012cf3a001164694b023453a40db3985d13eff8efadd0dc1b6271c794361cb7835b481c9a65a01c1c400b43285d76644e00000000000000000000000000000000165f4933d313e30080651497bb851111f7f5026e19024988fd637ddab6b661820d65d94e8bc3e250ae517b3dc05b7251000000000000000000000000000000000c0dfdabee46f9b0e218ca45a1fec30b31f9eaff8ffc155fbb48fad1ce8aa5fe94628245117dcd8e4771a72c6c32e3120000000000000000000000000000000017bc7378f4fb0e5192da4d093d01dd520f2fbbdb8cd8e61ab153f1a69e57debd4b6503e136ea559d406b09069143c98b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014f2a0e834d4c1edfd89a97226758e4835c6e4d5e1526463e796ec984740d82e9324875fbec8d3f3d6a7e08cf7a878f20000000000000000000000000000000015ebefda39a7113abc5b53488f00cd6c57b1dd388f1025b4e5661dcd22b62aed4d1fb3780fa4e18aeae548a616f4394f0000000000000000000000000000000016cfaea18431f548304b5f2898de0def2bf63c98731e66901b4f41e32f70a5b6c768673dca87441208daea27d0c227a7000000000000000000000000000000000cee61b31e2c3d9a6a8e2bdd24f9c63ab1316a1da37066b50a6d73245e9087b2e4f65f0da1d17164ec561b67b1b63fd51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6c3b69da6de4452ca6d621dbbcf0f54c4684caeec15b382963a00e0a0ca1d34a17d23c02073a0dead7dc8bc0ea67b20000000000000000000000000000000003603466f5b593eb067330695b2bb6ee89ecf48a32e71f70f5e5b6ed9ef99a7af877f762f3171f7843d17ec3813368b700000000000000000000000000000000109d7a34b29f984d742bfeebce03f0b972270be7838ead74cc47e62c4c7ac28c4209c00b81c3a5eb2979f23041fb87d0000000000000000000000000000000000eb9b10f194316243529c3539ee89955635d7673db96c41b7972863c13798b27cff6d0774ec522a55f7e97f49d7eb0851824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012fe84a3486bf8e818643ff42802dfe934b4eb5930e3158dccd0bb46ae4ecdd31367fca882bfe7e63bcc0105c50e31230000000000000000000000000000000002a29dafe28c8b35ef7bd129195b9e9a1a5a7267729577c290e82f13949ad6a78cfc7065091c81025e3fc3c46c978d3a0000000000000000000000000000000001da15e767337f529479b0f29a4ea3bd8a28f1d0dda7ec2dcdac09bc3292c0e336e778226e2ccf0622f3fa60faa186c800000000000000000000000000000000168f2c2a00e33dc93dbbf746974df7d145ceb3928f58fb4b8f345401d972080e18dab0a8a0ed893910d37545c7761ac11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a7d918787cbd36c05ba95bb13b742f3d8694d3accc072a0e7492d8dd13d4375f78c2f1506e86be64bd4814ce041e2390000000000000000000000000000000018842ebba79eaca0b724d072467a4c50827e2e57da5c5b632b82432deb82129789f01f912a192383a7c2513e9df0d9610000000000000000000000000000000015fa7b6924ead3bfe46446bbd55d4e8b8c154ff49742ef3db6e075c813f5900032eae95bc440e3d06f66dbdb65ef61ea0000000000000000000000000000000009691570ec96b20adf3719d0dfa4dfda5b41dba1f94d512f842799a518f39db46b0218cb3bc0a6bc26af3cea83ffe5211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b32fa61a5bb9f7ed055b8e6aad30b278d5404ff56d1b81026c7767f974f9d83face382b7b4f0368b8286e8e1ead8cb700000000000000000000000000000000071a73dd8f89250437b57e28c3e5af365bb363406c4a70a277b57242bc931ce6d2750339d7517f2a7b9b0796976395ea000000000000000000000000000000000d2bfbe18363c73ab189ce5abc02567442ab24f5ac6f8b76a1b5d8242e5d7417679ba1c65a1b1972db6bf8635d49abb10000000000000000000000000000000000c47ff062ddcc7401da07612ccb76bee27b83701b220e7d295b252074e9ae0b340296e8155c585c6e347a0784d3c0831824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000237635eb8189d612dbefe663222be08e27d991a092a9e42db7c2dfbaa55370b4e68a7ec50cd7120f3980d991e485d4200000000000000000000000000000000109b548f41cb900f3660b63cede53454261e7b871c6724b23855fe475882991e7a52fea573cdb2859755d70eeb4b4fb800000000000000000000000000000000094ef53e1a5f745f5c3e23c7bf58600f52e0dbf41296874b43307b8244e3cf6fc4044d5659cfdff4f2fea888a65fa5c90000000000000000000000000000000015e3bc1422f4eec1fe741c6e9ba94f1f9d2d096bb27ef99910316d0c73f78441d473a32ff1d4920a58f6bc39c429d96a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005950540b7f5044c42c34690c88c99bd9705b58abd5dd5142e47ebabf28472452021cb7978a17409820843a2eddaeaec0000000000000000000000000000000008e8cf9c6fe1435a5fc320b3969edca84008aa45688a88c54a882e6ee2c63b6dbcb3af5bffd9bc451dfd6ab8e72106a70000000000000000000000000000000006770f7eeca9627507906a3bc548e21ff0858a4588b93cbfd40ea177fe55ae7354bab74c2a6671dd4de29e7fcb15cbbe00000000000000000000000000000000151cfa452a924f6e5d085bf573bd249ffb6de78844cc369ef6736d82017c455abb5237988b301d5d4b6c28ec6b97b44a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001555d33d3067d263ead52793e6b21662c9dbc0d57cfb4e7287a0715d010013bc14d9c66840774e100ffac3199e6492010000000000000000000000000000000009a80bab7066195381b196e6e84c722235e39c77ca3df5f758be7ca87259011f20ac2540c07dd587ee3d807bdd8d484c0000000000000000000000000000000000a64060b8c54824a49467473efddd469583ac5e31a8a0c95a4308fd9d1dbda21b6497b7d772a059cde2ceb5dc1573be0000000000000000000000000000000012fadce1e622e2a355451283cdd33d0774f17cc425cc1dfcd2e85fdfcabecf013c902597b9a387506dd52caf923c08e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005b77fbc64ef78568a3de70bc0f5b8282b7b3fe2e0d6d4f06dec00e90e78d757edcf3286a4d47d6613c2080c8eb57c3400000000000000000000000000000000083d9a9ac10b128580a3af7aa704ff2dd42c698d38b4635137c8a7491738539d96724fc8c8cbbbe9c7ed0369f8bfaae40000000000000000000000000000000003eb249017248e1791ad9f887f34b447c2c25886dd3e7c3f2a052404877dbf3eaa3764412f4e5000a2b3d53b6d55a337000000000000000000000000000000000939ffda58c435d64123759c0e512444d05908a2834f2547f5278502032eb84f1d6047d67096c706769edb40f67e0a6e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b630173e8d1a00499c6fb7740626e75bf5fdd1e91b875e21163cead3230e8ee9d53b13d53ea116d029767305807431c000000000000000000000000000000001320be7664b46285322d5f767e72a4a9da32463b58d9aca4118a5d738cc40dfd0feca21f6e9f308c8e0c8b61e8b482600000000000000000000000000000000011f5b5ae033d14a8ef8704d07fd409fcc89fd94fb46c50ff8c56d0ce6e35e3ccff78b447f9b7bba1cf075648631d197a000000000000000000000000000000000e2680c618adb8ffc751c5999f68b18eb78efec68573eb212557aca7edc891a2c47c0f96f8cf14149eb1f0c8c67061a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000af258f212fa69a9dec8910015fb968440bc3a3681ea593e8ba16be58526177549ea62493430b22f1cf2e87dbb45ebdb000000000000000000000000000000000510bea33d26c2de27ab23b36803bd4840bd7c399d0ee4329193e6b9c192c109ebd9b37539dd1279e7498084e734573b0000000000000000000000000000000010dcf586845d62a20bf0e63bc8fa02846cff6aa2f2bcaf009823b46e907a428f2eb724290a81587af781c60c55abbcb8000000000000000000000000000000000088ff84e0c3b7ef6825f2527985689fd2f2a54961befc05a76ddaf4c7b8c601a6d0b40200145de06b9b50a6004bb5211824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000441f28adce4619679e982d3f3e3041a2348131a5a54a93d9ac45d62802a862f5610ea21939a0d6df0d3e0253926436500000000000000000000000000000000160a14cf9f2e30d0655580c3d7e998adef7037d2ebbab02885f721637e797c74a53618c7d6d09233e3a80582e3e4572d000000000000000000000000000000001414b0fc8d37d5ca1a24b5e1e1fba58e154069d0ba8143b0b0e105dbf74a20b1bb9c6c95648646edf7cdd58ae507119b000000000000000000000000000000000f22084af73bbe1320971836eaf0e775467b70c55466a6f5cb2f20d9a35107036ba621d3ecae74fde937a2a810e600b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001466de960bf0b18f045bc56f8d6ee6f5e0e293a589dfd396329847a4ae09582b2597ad5bd514009883988766a97daee1000000000000000000000000000000000a31eab509a1fe1a624e6606e95fb54d3ccb8a317c321e616295ce910b854fb0aa4617dadd42c686efe0138848c91d4f00000000000000000000000000000000008a6eecc250f1d648b6d8f4aa9dc72d5ad0d08d69d85178a1b864d5d84b8e121a6bdec3567b9cfdca6bb93b5661bc440000000000000000000000000000000018bb1ec3de6f8f11bd897b9e015a7c3362c396af45fe52feb005f268acebc4019006250a469f01d62074dfe1457a6b281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001954ed78df89916120fc161ee805397543c67d31258ac58d666f56a6dce6e8b9a6ddcaf95121153cb5525901d85a8a23000000000000000000000000000000000baff6b95e1248e9e1aad9d9519683c1ae9a915dcbe270be5113599979539d5b36cad24782d9043ed605221a537ada18000000000000000000000000000000001642fb8c382e2b8bb8cb113b0fa3479b5ffb9806c0959865002501c39fb69e6574544a03f88b9754933cc97fc9307d280000000000000000000000000000000007e3a95e0f01d44cc452713c22d7e712afa190cc81eebe781944632a3e5eb2c2403c08b91dc2233ab96e2b6f02d30dad1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000746613818fb69a7e9b30f2751f8f5d412ffdd5e04dfe14b6fb9547dc40d8a2a5fd90ace85b2c5e5f342e27e6544eda2000000000000000000000000000000001463f79461ab147e2427f886fc360542ae37d53883dace17dbe2493cb57148b3a820d68a9d2d1208268796ce2cd7a3400000000000000000000000000000000014d087ef9d735a798cf78829e5a64b1e5a86dc2f62baf6c8a5e696c196db36a51c602eeabc6a1588ddf5ce1c814e2f7600000000000000000000000000000000149cd177b7b2ca0964653d49e96f6f175c750ca4df30d0560ac6678a5d650083ea14b04b69c2eb7aacc9407fcd2e1c611824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000dce477f427baf54a2620489cbc45289f1df1e9132767c218fd19661de2cf02af74a35a9e66193d44bd395fb96c5f035000000000000000000000000000000000116a85c3ee84147afb19fd112ebcdeca8a6a5f4dd48d33c7cb431264c2a61c96a36605ebfc284a7158840605051717e0000000000000000000000000000000000e752aa973c7f7c46b763f4ca1b8390ff12f241449cd09a95d81bdd532f3d0cc894d51ee2e41d6e41b161d139e39b6f000000000000000000000000000000000e8db82b8019c534a439dc2f09369e74915bcab3b6ae7e9d49427f59d52102cf2b1db043ed11e9da30aaea67b41d56a21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111830b6f009d5e92d2f19f9ee0b51b8d0c82e361046ef0a1ade136dd998ed6e5a0ab1794e22943fcc6a3af4b5074a730000000000000000000000000000000015a06d6ef2aa3780aed246e22365dc2903b4c30ab89c5610e408e64f0deffa66fc39242053c0492538ca023f1d006dbd0000000000000000000000000000000009729686416c78c85e492c922fd9c1b0a7e69009609119abb2dcfdb0877d5f750a84035ad5c04ffa918c6d6b6ff3b2720000000000000000000000000000000006f0502a80a83cc8d787cdc03b0b8891b7d24a693b9903cb08ce4007ce5b6ada13fde360a483da18fe9316d2d6e03faa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012da5a2f312c5c352f3ef7a9fb5015568cfaa56a2a3859d4067802839ec07201c24d9717550854bce3058537ce49742b0000000000000000000000000000000002f270471a3ae6f72647978c850d4f9c3cde09dee309fee2b653d18b5300243c620afe37325fad422ed2d3388294d8740000000000000000000000000000000019e2838c731b3a02bb0faa24dadb5d46ed5edc9a318c5aae8bbff763489db5a35ce78b9c0d6baa0ec8617be6e55bfb6b000000000000000000000000000000000fa8ce31762a18432e8d985e25737b124c8443209d8e0789f3f3238a9e825eda9d162457a017ac3037228a45279e84051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000139ae67f3c4cc1bddbd70e180242f25f4637c1b109b671a667ea72f3e647406f8452d653d04890202bf4acb01786f88900000000000000000000000000000000078513b9f725201cea64ae5e2c6473ed35c61ac335429b1715c75c9cfef7171d894771f402254cfe84fc50ca36c386a000000000000000000000000000000000121a8b1efccbeecaaae7a499479298289c17fbdf1e2d89c0cc4837ad39d3839c7c9736822aea5740f6eca15e001cf56c000000000000000000000000000000000076f73c42dfd90d49803cfe2fb2678df7cf609430b2db58af00135c90b1abdc6307ddf4efffe5f5f416c08c0a7464751824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000600a1682ecd3af6957c599969468bcc1a000f4cf98182645b6aecf256af4c5987375659a76db132607ffd77e4a5134e000000000000000000000000000000000aaab49b490286c29c818144ed6682fa4604fd952f09d134a4de74aeb126b76df32d02fe6a51b62b1acfa303ddf4f2e800000000000000000000000000000000101c4f705ef8014846fe56c3263882dc81d0fbcae85415c7b6ef0644ccfbed27b917030c75f8551f9a354a7299ec2f1f000000000000000000000000000000001241f7e85497fa33da4a6f0ea679551a03481bd31561cb243686c3c62bdc66c2d93b645a54d2d29244e306af1d6f007d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000226156e38cc42de1c0b9bafabd5896e6809c08724aec4d4bcf1db3d397ee539163096ce97286337c189c0a3d4d764320000000000000000000000000000000016c9fa7dda47cd916d8ee2ffff6414ac3b3820d36e7762e3eba836a1d1837c700d4cd4b18bdd56f237e6d5319c438c6b00000000000000000000000000000000107df5fc706e9cb9eab01616d30d001ab32112d1934afc255792f70bd1f341c2ed7fb1272ca62e9ed0efd54a5c6722b300000000000000000000000000000000190db68f1ea0a07e7d236969fb4405507b0dc53088736cde07b11452bddd26a6b3d4ed634632beac36fe5ca01e9bd16c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016aaf6c50b3a4807a9dd34b70c38283ec5021d8aa9420424a352d1578db742cc612b828e0a2a435ba6323c8dda0ee3260000000000000000000000000000000006df2db36b93c9d9c171388d1b09c41412c2099c259a857b93ce99b5350d51d82ba18c37d6064290c6e81beb7dbd82d200000000000000000000000000000000035f2182ff6edf2b95012f2ee57e1a28f167eaa4697a5d4928f1019fc6b4abc27fbc65515454f833beea1f07a8e3aca300000000000000000000000000000000062ac88083ed4ead633678f6dbea62bb89e386d4594a74586293d40d888f10335c306841e519c50032d4964f01fdf6f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000020d2bb77c3b1203e201ce0a2b9b978d3426a1a825a2af0b3e340891e67b3684c8af47b819cfacc90313c595d9d442fc00000000000000000000000000000000022b242ef209d023014e83165f26838bac71e3eaf395d53801de21b1982af93bf250b2d61d9fe570eb0ba328c612242d000000000000000000000000000000000fa61bf491064282b3ece7fc40c3736c0e3e25553aacb0b5cdf277358ea7d251ffc2dfd432ff2bee5cebbf2b6c3bbc530000000000000000000000000000000002d29b91c99b60f6013e00ba867d943d5375c118070e109461ee2d0dc9e0a5f6bab9b9c2fada534955eb1c63face10691824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010446443794bcff7795a3377b3af9b9411d6a7f3cb2568fd2db5a8a0ab931d6a1b217fc9838ace79d18e9c743bedef070000000000000000000000000000000004df7f86aaef2ade996ab857c8ff1b50e78b928451663d444fea75d41cce178dfa2067eed81450854215f2c004b2641100000000000000000000000000000000123e9ef5f5b3961e34d8a194da8f264b468ea89ea9beb305f33ac7f6ea0ceee1ca84656b315aabafaead635a8641ad43000000000000000000000000000000001753c10d98cfb625244e20866260080107fb6eb4e1a9d00ff5f610d5604723f5c69dbaf3057a99d72fa32b04232de89a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001292a864dfe5ad73fa4e057daceafa483dcee68289f1090ea86c4a64a242342067c71c9ff5816725bade360beb6d4273000000000000000000000000000000000a776b048b47e4277e12d896d580f04d964c2129d9fbcb17985eb1bb5cd097b3cbbaaeec0e5c835973a235bc507f282f0000000000000000000000000000000008b6367b731f2f4d8cb6a7c35562457f1ea9c9ed48aaaec963c39a4a0026eae1519beb4c83ffa7876577732f0418f264000000000000000000000000000000000e549976a666dd7c85e9503114de6e1a3c8329b8ad1d29e13249c813af438de2db006bef12cb34bc65e24a1e79bc82f41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f725f0e0b443774734dfa3e2a2e6070b08f88580c1c1c5faf3b65a2fd6dcf8000908939c060b00cd5b821567194ae800000000000000000000000000000000194a7445389d64aa9d29d9e6cda19b2360442a1ca70c883288ac75fe22f5848737eb15929581544b21ce26aa3d876088000000000000000000000000000000000b6de53d5dda1699fb305578c86612fc71652783deed78ebbfd59a2f419b48598d26a9400673c68cce2991d137ff590b0000000000000000000000000000000012d5abc09dceb589932f15f7f756763f1d5047ccb7d5f86ce41aa13ea2c4b7a9357e6c4244afc1495965fe6d92b4e9f61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002c871727a46b0b7aec724b0c5a88f84a45795bdb4f22f8f67bff65a44e6c818ecd577288a2bf913c3b61674abbfc33f0000000000000000000000000000000005d5bcad18543933bc4c120f2da68bba81015b2237975b69ef6896a618f745be72d1145ab62908ace3011ed00beedc5c000000000000000000000000000000000f061c113d4d9cba6c4b402710c7fbc23e81b37dc6fc666196919dfdbcda511ae312b3751faf560e60ba606b90470b750000000000000000000000000000000013e96a9d6f9201a20d25bd4fa96eb0f78d6705cbc44fd8ec4e760043e44fb36f36285ba67f94ac4ffa3012080cfa64db1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009f93cb9617c245969955e2785019c292227038d8f8ab4ce4bd057766420ed88b8c6e08526472275ebe1d4677a912d7d000000000000000000000000000000000e16ac32762f466ac7cc1b0388654610ba1907a1152437de4806c8ea56a827dfb60c9e99a3f5893514bcc1c7d32304ed0000000000000000000000000000000014cb917d35ec93eceef9c5253091c55cc0fb08ec6393a8fdac1bf13aa8f2121ada05871725cbaf9f5b2da3c77b8999b60000000000000000000000000000000009e44894cd7cc95d33d36dba905b780170cdcd416221aec8bc46dfb2e62587a238787b9768c492e8a9e4a6eb4c439fbc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007340a6fb5da118c1e7ca4a4ae1d03268acab0c703be69ecf6cedf37673f7726d7a1fc99ae11e9b2366bea7eca8f0f5e000000000000000000000000000000000ddb53eba1eac64a37b6902f67ecdb97020e3c2fae3ebad9c7c77248986a7b41581e9aeb18f7d9344f12d74662eda6e3000000000000000000000000000000000eb65453a34e6a1b29103e588243c89c424faf793764beef2f76adea8e9373d52734dc431bce6c46769a1258e697b7d10000000000000000000000000000000008f07de200c60859be4ab78263e72b6a326c3c92bf5d29660b050b3ab147ac64cfdc4e20559498b0487fb327c94f3ea41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005c87312005457656a177d97575b4a4e7f5b7c1ed372bd66820b57193493b880cbfbf580f0af64e68186d93238df195c0000000000000000000000000000000019689872835fd016146686e6f104bd9aa40cc1f8a4f58809ce5ba2e142211bda39e89b0cf6edb76cb4ec498c1ed31d820000000000000000000000000000000000720ca78cf5394e60c28f86c28cd73779e1acd9c91d33d75768cf8b2e4d81c20bf86df5b996fa837ecf222a576d42c8000000000000000000000000000000001818e35c64c9bd6885295cf37e96a73b88f67ad793703491f3dcf5cda8a65db0494bc5b47c491536cc3bbbd3ad30bb4b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001243248e664acf6d803966286cb3e13e5651315b509392b89cb511ab5702b8ee92696d9071b64221183804317456ae76000000000000000000000000000000000ea1031d4fdf7860ea01ed3dfff2a8d56c7a588862c22e9895d74ef770743ddd964f681c4a07d95f4a83ff06c4a148b700000000000000000000000000000000034049cf253306bd7d326d40db95adf5b97a5b45e25d27c7fc7478ce4e4d51a4e0080420f5c3b4540d774c259b837d5700000000000000000000000000000000178fa2d33ee61af3aaa5f79f29badabefecf07582dd61eb16e26d9e863e2d222cee9735f0e4cd70a017da649ad342e271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003420a3eaf6d6c088f3abaf983df3caa90bdc2a82170257341595af736dff55e5d071e7e4dd0251d7984ff7199d6dcbc000000000000000000000000000000000db7b8e9a17b49f8af699c1422344bf47d5855ea27e190384384b8e51d2b2151eb7f983bea785e529d1620d076af8c92000000000000000000000000000000000f3d784f5aae94783a5a47ba0ada086ebf722bf27b7eb3fccae56b2b0ce5136815d28463e42620383dad753e39b6b7db000000000000000000000000000000000e1b33e3d2a2720f114d3f3b2c6c73f4d4f222a58f2fdfcb000606d4e047ce636f1ad5f460a2283f6b674b7c2d5747c41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016b7668222e37387e21cdb6b3e0107846b7aa868f687227b7d9d6be27cb1efe57fdb0b719b5401e0d6d4e1a64442b354000000000000000000000000000000000ab894e8a47e8a15904e1760f59249329cdcb7f0f939720629f060b530e4998094a949a34c2316bf7758bc35622003270000000000000000000000000000000007046b0f7c092b0cda5891d405a64829152ef5ad41d4d5164a20bff5d176b1bcd9ac71b6b96ac7f3910dd4ccb134188e000000000000000000000000000000000698dcd91ee30501a9941993085f860e4e30f9cdfaf27ae42c904a923490ed5b845b14a342cf7fca58c841dd85ad92551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d5e0bb49c375ef74222a26899dfadd8e257c2d25d7301a761778e50c629d9cd733470e78178b73ed66e3ac140656b5900000000000000000000000000000000172e59fe16d189e285a09264c39fcbc7d010195019c7ca639ab83982114ac8c54c3c3db4aafe067a791d33a5b3abb849000000000000000000000000000000000cfe5c92cdd431894cd0b9f79fce485e45e377ee549a6bcf4a9b54e776485b52a1e27931a423d1f4e9791d12a21023790000000000000000000000000000000006b728d48057937aba2c06b4a1e11962df778e0189bc89937bc0221b9603c24b50a570a02617fd3c61650aa5ba8a20f31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001729ef90984984e54d57d18cdaf1bc20aa9a4649c25b171aa0b8ee6e82dacc4db41680ef522bfc6e1cb7cefaf4ea7e920000000000000000000000000000000015b89fa758178ba4f1bb19b00d25080055bd81e509260ec9abf09dba87537970d1fb96afcb4e8d98a0b3aa5d2b0d309500000000000000000000000000000000185fd81eca3bd34f4fe0f40ebbccef4b13926a5463976d09f219f44735cdccf3fdeafc220e2e6e89851dbec64137545b0000000000000000000000000000000009404a51e47648befc1f6eb8020ef5398b62da2686475082023af6b875622b54b1fc035855dd102e9d11e8b9333fb3891824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019f7695379d718fa1344007a23e4e2a7eeabb28bf7c968bfa47b3def88c8ba4b1b9c5af136adf18464f6f4ce93b1f51a000000000000000000000000000000000b3c7e3c69de69ca838c461efdf8e24624c8cf6df71ee4cebf7154d0bf91cc9226c0c91eac3ed7a8a55db0287176cbe0000000000000000000000000000000001116fecdb47df938bf45fd6dccf8c047257f2478865dcd484d74693f1f2afa11913b40c23708b77aad16377e00de3d1600000000000000000000000000000000013578c050db7ca7bfa84061f9621d885ec1f0b14af74892eda50523d9392eef2295b0b70df948b3d393310416713ea61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f790f46b0b15e30a76d3a47dbb411756712a0261807e425a4beec395bd48dd17111591bbf6adb86df128c6b68d9d81a00000000000000000000000000000000008ba25aab1b09db4e9d6edce642e9f16ee4a6d9d42af02410cbf728efcdcfca769879cb5201b0b4e40eec2a67c0497a000000000000000000000000000000000a0816ff7c73cd383f1c2ff1ba5702c65d057a1fe7a8a9d049b42057f725c1ecee1418d2fe782fe04b89b0d6ca6bd22500000000000000000000000000000000141fd5d1a31a1827b84397adc3265abd00aee9a2059c3af2bf266f04aa166d28b332a957f5714965bc9b9902eab7303a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019457eb033efa116078c797dd924c056471e6073105b9eff7c6777e3e89eeb5a74e56fa7045b7b772ff3f9139bd9b5c0000000000000000000000000000000001474869e10aa64e32f534fa418d0d006e8ec57fa2bc31c06b5164accbaf389e2d1cac6cbfd41f51080de1b68a38d78540000000000000000000000000000000009ec92685445b1039531f29947af1f4a7d1ab30c1ed25d896ecc7aa23d0caac0c9bbcb95a7536522fbc142dd28548e2a00000000000000000000000000000000104fd0947bf8e74de3d5d626c7fd743a4d0b1b3ac5abdc546072d88e7daf31b8eed60287de7b595ee9b4b7c75121eadc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d893d521ead5cfa993f3ecd441d060b674fe4759fb393dc342b1db428964f71b0864f3682ae75cc696a8401a545c2100000000000000000000000000000000020e5d15f393d571d92b204f6d0dcc66c60e870685b058432e2d18d0968ef9df1f60b7b91c428d2fb03915218d50e2540000000000000000000000000000000006946e5db6a06b0a74f8df5ae252c978e98e5aceac355e41031737b4181e4e30ef51b619fb3209ee91ad089965a15d3c00000000000000000000000000000000023ff23f09d104c9407b0df7fc543b469464e9c09daa7632a6bef2ea7371801b00ac90874d5d8534da964b7d700cee5e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001246150193c62c8d5bd2e35a0fc7c539b27fa1991f3f7309afff45548a2c862a51b8b917026f51e1ccec594e283cec1d00000000000000000000000000000000105bbcdaf24c0e3011428cfdf5511dc08edfda5e318e4148ed442ad069c68d195de02bce17bd1374d47c2bf89e39634a0000000000000000000000000000000015db5c23fb930f1adc6d76f14dfb54b0fa1e19ccb773aa0215251e4ca3f1b6a84c536ae6188924bda4b42531c4544d6b000000000000000000000000000000000c8d52c67dc1b86cdbaa3486385af0c43888c73a9a395a296ee95e2cc5ccb70cc73d5e9be07bd62fb0819025e173f4d61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015b9f0c580d7eb3cffed3afb22235c4c099504d272c5b9aca95d87c17121efcaae42333b0b0c107c17efe7ffee2a07500000000000000000000000000000000019286479995820bad141d275e2c73a14bacd4e5713d3c5e3146992a05636e5419c7c76c960428ae6cead53025a87e70f000000000000000000000000000000000d2faa2e1569f7e57eaa730b98af089f950acdeb36982b88d8f8a9b9ce10573457d4e2fe9ef5fef1db21927278bcf5230000000000000000000000000000000002b88eb2d55e8af15b7677e6fae3d16a20090a7f93b5998f8772cb351d7aa32966a11ed7929a872f8af7274603cdeb661824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001276ad4fcda2f33e43f83bd4498a1ebece3981e8e0876189a4d911320f9697987207b44ce33df7653ca7a9949f1490fe00000000000000000000000000000000002509ce5b2c21e6d6f7656c6e4ba97c5fc55245494d3db4c2ec1737713817d32996150fb8afa32b3d0860162a5cda800000000000000000000000000000000013aee10bcdb8e316173ccc47c6f43181671d9df84c24474166496a09f65d3f7f9acf5e8e05bf9e4e79b747f25586d9080000000000000000000000000000000012a34c91c708d994fb0c20659c5bed3ee1293c11a138d86b1180ff23fcc5808b5883d6b9023b1be67e8d9309a2481c901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018029631bdd03f299fb60ad1fcc7c8d5384b3191d148ceeb1257ab745ee072ee5feb1822a72881faa64e606ca4d38d0d00000000000000000000000000000000143284c6f978c33a329c5b87f8dee7b76ba0b6040e58903684e973eb0c9e3a5645404feaf6dd97d85e56bd57d02c8c240000000000000000000000000000000007bd1c6081c6c472aa18549ea922ff46dcc6429361fc2ed1f67908584021bb4bb634d771a5647f87ae438255d43e9dfd0000000000000000000000000000000005317959b00fe5fbad4f4fa7c10a565049022e8c1b5e168681536156f1b03b96fc8b44df3fd97d56fbccdcc413766f271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174b8624208828c62f08f23a7ad6a59501b3e98e80e150e5cc2ee8752318d43fb3faf0bad522bc8aba70a04651df1e130000000000000000000000000000000014776d28af31e64d4038ed0319e64180cbf9b5190a62e3a43fe0607b5cb0717f1fa8cee8b4824d8bbe9a531592084a2f0000000000000000000000000000000015e87692d47baed1bb4326be47df36915e69c24deb68ca0357118a25a4d272f0cf58fa8bc73ae35ef6ed48f38e5bb153000000000000000000000000000000001427e8ae9c2f0619e700310f1e72d8f291c8b8c53e8c751b8f0ea3424650216908bd56d4a76d35d94524e2df5000dbdc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f10bcc727a623b45d9c7f267d22a8ea999631339dfe53d9c3de32cda38d0d131579821fb08c742c2c0f80737aa6593000000000000000000000000000000000f7463f27129241ed2c32b55ef1c38d05e3f05a127a8ca6efed07cc4206393ad06f4bfcf173222ec66d944bd8f4b8f9b000000000000000000000000000000000f05be82493b1a2a0f1285e1b77850e839535533b88a8c6546c6233a0de2d4425876224fe7667562424129ceb393707400000000000000000000000000000000085a9c309021c17e08c15d9f2bb8098fbfdf5c4b3f3bf8a721adf9aba8eca00ca46950a287132bb4031d557effa4074e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005fbd873e62a1242f96e1f5a45cba9457a9cdf3efc80b09a66eb716b245130103ac0b2ddf9751fe501d26c4da179ffbb000000000000000000000000000000000deeb3ab3344392d21ef61529627d7afcd3285db92d09bd5e1df7a3b0667255cca86f6be91f31ff67012c2a6b8e90aeb00000000000000000000000000000000155c6467efb899da51284b1e12aaadc37c20ef270c43f83a3f9a09bfb14a39b62b3444417827cabd7745298ce8097be400000000000000000000000000000000093f491139497f0019e795da164f0102625f49cf7aba1c5903e691418d7e2ad3f353169cb530af25feba698608caa0681824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000064a572a868debd34835b63dab5826cb293d13a83e8f931c199a0764d14acb8b10e00be8a4a7869601467fc4d86c2480000000000000000000000000000000018337b37fcaa71d06b60c7dfdd4db785da6655190a97c4f09fadbcfbb45168f29efd6ca91a8d77776f57032ea7a97853000000000000000000000000000000000066edbd82d76c063b0a91f37fe737e9fdf4967d9db18f4abe707df654c9980f77eb090142693f604774b6e800dc1b6900000000000000000000000000000000181bd9170f327740e4da7189bda44da0fede263d9bf70264b95aca21c6c0dcdaf50cfd107a5555fee1a1ffd299fda25b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003a9e35e9310d75d81bd47d86ad79b532aeeeea8d26f4dd803e74d7e4ec11baea8c70136e0245f801695b1ceb0c71dd5000000000000000000000000000000000578bed25b80cf68dc823acd017a30fe09f20bb7ee4340d9aebf9980e041df3886ebf85b1138a3496c0b4a4d7e21ddf90000000000000000000000000000000008814a11e702fe9af00c3b46c44fb00dd43104832724ddfdd012e07375d7a3e71a33a17ed609fe2df77a58c60af293850000000000000000000000000000000014a20167981a60d9d037c0975ad63e8f9dfd004f9a9d501ee892a9ee3cb2c80ca9f65f3fa850d777908e53c01d9cd5401824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000c11920161a56053346e1156cd06ad339f0f54706ad87d4513e797149322f14bcf56b28589ba1e8bf8e0cf5896a769b0000000000000000000000000000000010eb2aee9bfd8c54d48f4f9406c91233f7e7c4c52a0c64c2f1f828955cda0ce22b370667a5b535d569a51e755f5b5e00000000000000000000000000000000000f55424cd3f70a8bcf02e076f7f05a667205a29f5a88be5ee8659a8ee9ce4f0fa68739379dfc34cb70e7e11d8033728d00000000000000000000000000000000071cd00e983952802087d2697ee63aa0ea29972cea5341cab20013586399e7323d110802a291828c90b4b83a338135021824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c3564953e25d303df3edb5d3b7de4a1f29439e6b72c7cc487edd630b3beef300bfb01b8a2a7c46b2d87e5afde080a14000000000000000000000000000000001545c38231e77bceae49274c7b0f8090cb6ed196d641f79df2f9305ca1588aa2a7de88959560957c3b83cb33db5ebd720000000000000000000000000000000007f569eeea5df71f20809ae8294fa9a4b28541d564027d7b87565871fd78b6cd1cf2bbc04b7109272a57795fbb859dde0000000000000000000000000000000015647a3e0a32dd49deb073963728586ec7b8dc0ad79ba3f732400e3c39b38445e0b5879a9899acccecda11f7afbae8a31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013fcb5a2589cfb11a0a1ebf034b016a2f673fc965d068e12a2af726bd97fb2086dc37a33fc82524f556c4ad43aa903cf0000000000000000000000000000000009fd7b3f337e0a5d8232211756d55c4e78d0f73db4570319ae4c978792d0cda5c212a7ff1a733d4ef3cbe35f77142984000000000000000000000000000000000b124553ef8d3c83c60065f9146c93accbe59aaf4dea092ba72095a4a5c94c1db01a6a64d13d7e433755e553ac5258580000000000000000000000000000000008b349e371a6ba1268e2cea53c0c83f8fa13cf442f1056687afdd9e09ba2757be841c00f1a3c0fd6ac6572d8599b2fb31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006dbfa8a278b219fac8e2a97d8be8508e4cd854d28e66a4383688abe8bc3727ea625af720ce454f31c70e159d301fe420000000000000000000000000000000002c36aed8126986c60b1401008ea598aaf9c5c8c92ef2b2b2cb516c059e91fbf66cb455251b0c09345f35eacf7c6add30000000000000000000000000000000018dc9bec0f78e2ed26960bdd3f0c7cbaa607254d8170312ef510701132e365ea0acbe9d3a922c269e5403e0dd10d06a900000000000000000000000000000000005340836d5d7061b4b4a1585e01884ffbede51118f9e9de9ec21983f870fa3c78c3bd861b8c433e876b1ac08cba94651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000157e82195994a1d886043de55f0fe38db6529fea161dc749157f623a21fd377efe72912e8576e7c2d57b994bd52e75830000000000000000000000000000000002c940880e0fa4dc84ce09b3c3bf05f6b3315cbd253f97d66e7c95359b82525e70dc05cd1b490dbcaff16a901d2f13ee000000000000000000000000000000000a6a4083a2b40f734f347920937f58ad0b4958aa2712ed367df1c44131137f17ca1bc264ccc746edcff33320ff32fad80000000000000000000000000000000015920088371d552eed0efc9c0ac20881f9a2d41d5c19b225a29678e3041ff03fa22875bf840d59431f4d005f3532c3d91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cb7f1ffbde73e1e58c2f0706e489072728302ba3ec71f337f6db0bc9644eafa92251763504f72622c21cf80f5b54ef7000000000000000000000000000000000102f6f9a587c3974942ef5eed138df216d9e6198c3bbc51f7208f9f1da98eaf3231d5433a5141fbb2e0120d285c8c690000000000000000000000000000000014ff98db3780c67df0fa65e4743222f76e53568e17d0e43d0801804d1464d1e1dac4968fc2348a8532e282dc3679534a000000000000000000000000000000000a95ff99bbe17d799b3cd8737b88cd211eafb9f9de15fb4b2436cdc33ce9cef17e679bfbe9c0e1897c36850d81ab96c81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000090e255d48b8bd61525d457015c4ad33290e44f423ff30a1354609f39bf2905031a65e7028103e877b8da8080bc9aae90000000000000000000000000000000016f7758c642d6d0ce541bff39f8ff0e0c7538f870fe63bb121d154c17c48acf6a307bc7287412f5ebd352faec70c449b000000000000000000000000000000000b2ed3b4721ae409d60f273268f0c356bc1393670b4116eb25d16f5cdda960348b73d232977f2384e16dbf072174319800000000000000000000000000000000085367b487d6972109041177bbe49f17a2e2186463a1edf8e9006c13ad93afda64b6aaa63c0a4c116ab08f1708652d7e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001456424c37c92b6777a1e00c487c808ad903f79513dae5cfbf1cdd824d1a2eea62ee8fc2da2c9fb18f7a022f45855e660000000000000000000000000000000000e4ce03ff33f8e05a9c01d472bfb7be6f6cb91fde45fc7fded22c53afd16bdaef7669425e74c1670d652f57ab4d1a0200000000000000000000000000000000059946d0b0e64448a93ebbf67298cc7340e85f95773ba4d425385eeb02834f9b456b648de22de9fb8da58d28ee73722a000000000000000000000000000000000ff09ac5240b3e99dbf8a39399a1868ccf7818af33f09c56a50387896ede2b7de959c63ab28e3a6f36da389938e585631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001275616a06d4315888a1bb987459c0f5419063d31ec1c45393fcd31380fc80d4b5932dc9f33b2b5ff3a04e78347fee0f0000000000000000000000000000000012fb1b304e77ba40d324935969bd8f8e294d8665e6cd73469a2d9cab7889cce98e812878baa1b4bead0e41c141e09ebf000000000000000000000000000000001838016e18d55180da13aef58e5e8b90a4f9a2e2ded1f78905b704a29fafb5c1ba236ee6e2d760bf936cf07448e3a2b8000000000000000000000000000000001542d204d553a6ca455f5e15484e58bafe5258710a7a005ff165b1b475d5a11c82bb9478a89466a65fbfe705c9e619b41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000021b2234c619bb27f62e480d4fced211584f115d6cc5dafaf6e8910c8e8a79035dba5fea01ce7a45413c99513c9682e60000000000000000000000000000000000d8989378e1657b66baca43d8cd93e54306d51cfde5a6de93ed506b6b9bb1258e8dd407f1ed9a9fe85d62da2b88533e00000000000000000000000000000000092b4133ccee71b20f7fe2b2de6c001ed2aad927298c0a4c6a1b4125a5db823eae137f8aa5cd854f222fdc8d5417f114000000000000000000000000000000000a82a008f166632a685443add00edb2a1f333c491764fab59cac13dda878c2d67f42fcb4c8a0c6b5040650159930a8b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016cc69cccd75e170a4976c7294c40f99ee26a5cd92e9d4556377d00c08dee587237daed3fbdf9ae4444a4e55f4f8707700000000000000000000000000000000120b40cc8d0d370ce1f894e8276e223e98be9e604d0d23496895a615bbe6da1c1eaea53e4725f8a241278e4126b9290e0000000000000000000000000000000010e0af8399079f7eb3e3cee68be2b33256329558e19bc2870ebe6454958fb72121e3824897d6ba806a6d47598038dd44000000000000000000000000000000000b4797b811ff46f91202ec949b86ff25fa88de3ceeb3fee8a1e1e6e141ed0f1d95b1d34474d902e9fc3579546a27f7e81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003beae7593bc02d5cb0557e56e2b5c973d5a2111b3447f8d03219d9730e8771c7bc4c981117287fea626f2762fece2f60000000000000000000000000000000002b835c09327bfcc970995392dc026f5b34cecaa02a5d9b352ab216c9576f623db15d6d231970da3cd9a1b9c79ccd08a000000000000000000000000000000000ffa66e9703bc4cd31b2255ab05d3f153193634602205d459c81683f4d28bc4594cc462a00379dd490f11c303b0e97a1000000000000000000000000000000000fe651094f4131410ccf9c4dea2c8da727ad9aa16fc1bff55547414a98ba99f532ff92571afd8e7cb4345ae031000bca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ac06a0bfc3c89a103d077e18298a15393a9ac7d06dbc054ece5c2582b9322d6048fd6a11cf8dee6b492bc6e7cac010c000000000000000000000000000000000bed51ad1f2a3efaf8f35f9b5445201987861e77d44513a4ba61c741d4f4f262ac308b5089097817c56c3b697496c52f0000000000000000000000000000000014a0d55188fea736487f7bf71dce35a7ec1dc0bf2363de6643775db68cf8401ae656823ee10a888c09233253fc4727d4000000000000000000000000000000000dd97cdbdf8906b2eb44f50ba0d8d684ab56754cf7d856dc23e4dd2f0e791b32e00268c3049f2a574558c452a01ed3c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000040eb1732f2f122f799a46188d72a8e7bb0a17c93cddf792c99f0db5ec707b46a5edafe54a9893d9f188350b7abc1d7b0000000000000000000000000000000002e86ea84379337869a671751a5c6a860a27f5a8418e5c401933acc151fb4a6208b8f7cf446ae7bd5d30c29c6868bdbd0000000000000000000000000000000005acde871aeaa00c7e7ca769b6ae095cb47177346e024fd2ac7e62ea0e44567242eb68e3bda423df33c3584fd59ae1f400000000000000000000000000000000137ae35eebeca7b534111feb1865343b468cc75c521b8bf12b841455bdb6711f9608112452623f5856d7ac1342724d201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000efa285efd6a028ea9859c7859e4d8d9b873f6d9638e226a4bbc7b77b5c282287182fb24228af36ea497436acdc71a68000000000000000000000000000000000f78674aafd1fbba816e496a3d2bf543069469fbd8f68e79d1aaad766ebe5150bcaef62a008e1dcdd02637c0905de30b0000000000000000000000000000000017c65210c093405cbfae8b839118c874d7a817fa029d3d7f7bed069db01511780224cfc5bc036a6c73794cb2d364d0fa00000000000000000000000000000000109ddd0f6f42d96abd9d21bccfdc3ae626c95d5dda347da3a0675f68b59cd0bdd7263a571a14ff8658eb60a07800ab721824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a468461b04dd30a46758b497b87b3783f0970f258983107bbf76df37e274320e3bbfdb057485d367f7c1085b77d0755000000000000000000000000000000000f0bb22983c5edb6340b34409eab0a119ab730ec3af217c7812fa42f2392228a53d43d266f308d52c1354a9671510c640000000000000000000000000000000014abd8da46e68284d66e65760b531f73266e3036081c456226a8142f0ccd8cf7f2e53924bb596e7e8f9813e0d79f4caa0000000000000000000000000000000010e6ed2a8c023d292998adc162edb02e763f101d4938303fe6460a8cf1e5f3d91288f1ee7745580668a023be8fb0c7841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001771f86eee35691905b3c77b6c49827e260cd5ab39ddb6b16e16cfede00f050a99895b50fbd47c3d5e5ea7408902a5760000000000000000000000000000000010941ab2cb78691c8bca685bf4618dc3b07c68e937f6fc51d693c5bf0c2c49d19d3800332679fe6db6383e75884ac5b8000000000000000000000000000000001216abd3ceb3debb91a4293e67d46a087520f2db4e74929e44b00d5e74dc946f1bc86b8eedafb9c57f8531a18231ab5c0000000000000000000000000000000006d30188b4fbfc168806aab5eaa348f3c6aca17f40932d05b517b26550f7cc53d09021df44ab7f7ed01c1c48ecd5c6e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000028ed057e2c1452a4e8d68bbbea39bee340ff617acb45d2a202a6bf49c55a455ee7932b63168512a0276587ce410a1120000000000000000000000000000000000e93f238e5375538208aafb42c7555f5d271d6ad62f0c4132dbad3531a33d40a9f663e5c365b687fef143c9aa2bf9e6000000000000000000000000000000000bae3df4a6652b898059fec2716f8b9a968c007baa9cd93a94573d7c8c38ea92059f489bab29cb694bf53be9bbc49b6600000000000000000000000000000000063bc330c9a01a770ded61be9cc38d5fd614e5f5075f2325cc6a7ea816e5fcb379fae2a7e5b6cb6b99277274730ae1d81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000f6d816e2086a9c04d415ff83fae52ee2693185596f11b9a625cac512a8cc6a262fe121e0300f707d7f7b2c4ce70258000000000000000000000000000000000559e7ad3de60b5c864f618d5a116a3cf179d4ccc5cce84abf41fc2c7f914b309a3f38cfe4567b99e0b3d766b9b3203f0000000000000000000000000000000000637feb00603156cef80402a44d127e10307ab8705ec283f942bd5525f6bcef890eabb376f644664f7512e0a10e2a9d000000000000000000000000000000000af575d2d87eeae3447630c6972e0a361f7d0584ce67deee0d86d52f1db2870b92bedb2389535bbe93019a21e4dbb82d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d7bbe51498b5d3cddd5d15e4b4743e2e87349f1f6d42e757a929fbae25c11fe027ea68756cb073130152edfbbc99c3a00000000000000000000000000000000071e26257841318822a1c5227e5427b780f6dea649cb4670d410403b1a923291094f3bc7cee658f8e467d9fc994e74790000000000000000000000000000000001f5f87abfb00f0d0114310f15359b99141cdcd3e42a69d0f0e59fe70ef191ab54667f1b7a8249e75dae47096f8b7781000000000000000000000000000000000085adb61c88ae489dda0b4936b29118bf9a8c7610d1ab239c75c4c98a69ead8fd0fca2fb51b0a779d4fc83e2a6dac191824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019122c98fd1b0004c280177eaa2c6a658ddf81bad31db4c1dc7b36eb62bb066009c4266b6a4365c76243a25623b3617300000000000000000000000000000000133cfe42bd773888dd4e6b7729266d7fc060acad5cda2abd65f31dbcfaeff72b3fcb2132174aad467c77b5377ca890740000000000000000000000000000000013e75ad2ac9d4107a8ceacddfaf6ec3275b1a6c39c3b8baad9f9c6f5d1aef2513dc2fe7e21df44c3d9ad5ed2b128891c0000000000000000000000000000000000adf6a14bd108bfd4908531e6ca0e738a3596c080041a7143d0746cd7fa018443f24c6f265ac7eeb3adbfd5d3ee0c981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013fb29e7e495cff757afe9f9cb6d13d3631140de6a75b4c9aba42b9cfba4b2b8a8ae85a19a3113cd6123f5fe855fce5e000000000000000000000000000000000188596b9988acaf27ab8e45a63d8211893e4d88a9c9caaaba6cb37d48778cae5b770c0cb8f574c1b4a9f4930ab467e70000000000000000000000000000000006bbb521062980c2fecda6211e1b40da39b4fd5d7bbdd4a7794e1c9e09bfe0339fca0adaf1113b0b5b06b46842283b800000000000000000000000000000000000273498da932faf53410dbd2bef983e69161d417fc02c527fa75c44e1abfe7ecedcbb6143e9213c4576d694c66e429d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013cf42fbe9ef85b47f0b7974945484e911e63596441731da09750a5f3483fbbdcb6e344f3e78615d7ed5484f3e33d5170000000000000000000000000000000004a4f03c4e9288530f148cfba12b8e646a45ac36e06beecfc27ce8b63674dacff9a9a1d4deb0c8624f440c5de28a71cb00000000000000000000000000000000071aa999afe3a0cfe48fde579e7ccb987f6a5577d0f4e63e91a2bd24b41d3831a5835ec0e2ec143da6502b98641b808d0000000000000000000000000000000007d7c553a045e42c6d8491fdaf838fc6ab4d0818faef3e5babe57b38503b9dfa67543e99d5a53c2800cc91e248a130c91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000d3182d845e0bba57863799f41861c92e11f0a6fe90fa57c210b35d5d520232a1ee098e4b68bcb5e3fb52872c261a78000000000000000000000000000000000a2db4d1ee3ccac7f3178f4a1cc4ce694a43449aa5f1d6a87e14ae3080301574407128ee385e3f8d4f9d922cf9a7a5db000000000000000000000000000000000fe4b2348cb7364c4565f5d7dc4d080aee93b5f9f2144d81aff6925ea5a2f5c66fe77202df692f32c0be9711951ffb0a0000000000000000000000000000000019db314b62e2b68b70b7563bf5ec4a329d352486c64d28218b5f9886963a9c523a0ce3b4baa2e88b8bfe29d9a656684c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b3f70ac266626f2af4fc93e3db2b657d5b627f5d344320dfbfbe3f28a05176c5feb937a7e64fc447f799941b43cf3da000000000000000000000000000000001537583addd88d1c876b00a4f5f707cc272fb3d2bde72b244b061c1a4d689351af7d078606fc752680ac667424412ac9000000000000000000000000000000000a95097e5ae9cecd211349e1b478450756524a1a5e9e02681fbed713c6a2505cb789dbeadda38d692468200dd4039d6a0000000000000000000000000000000014c63db461ed28f80794648f302138dd5ca3db7e6d24e83f0e14b27a077afe9e5ddc6effc694091605f7aa128db93a3c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007c2cab9fde3bdaf9948cd8c9b374cfb627dffefdcfd52fd1df219eada149e7dd9ae2a287a095a519aac1b88fe1ac02a000000000000000000000000000000000a875a456f6c5a2985fc904e56cfdec30f7819fc0a65c863c033d8985aa41b2b74ebac6db2b7c0a59bcbf6f6be1c63820000000000000000000000000000000002dbf1ab764de8aeaa66bdf87b14c1339139346912b735065c8feb810565a9e5894cc5b546aed233671bbe81023d087600000000000000000000000000000000039d228aae06367d612418e3c092d1fdc261956902b6045d3eda215b8acecc96bdb20a5982e672fdc56291fa892601041824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013d9df9a45916d0e7eb0ad9d05e70c794259a686b84d4a9c0707e63d84a2a0cc6b4a69dbe8c63db70a3f844d88fb77f70000000000000000000000000000000000f4bf88fbdb4273783dc53295dba5eac21546c4d582ea563d888fab98965d06ddefb3e1c0163ec33112c17d50a305890000000000000000000000000000000016b14a3cbb66c7ef1c9278972566e5325169bc0171ab4991de7bcdaca63a6416cb0bb7c8b19a764b7ba3f7859439a9c4000000000000000000000000000000000a7bf2c21afa974fd6ed1378a9e4e9a56f1d97f6f24c0550beececa432e7565641cc7af4286c5d3c118d2700e48ccc141824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002663656334d2e29608aa58aa80efce637af86551f55ce3408c6ca1477aa77f64bcfd1b6234916c2a0c2d38d95562fed0000000000000000000000000000000010598728d572aefe58558945aef6ff7948ed424ad2037cff6796bbfaa2d49078d61ed03dd4795b4b6a074fdd6ef7961d00000000000000000000000000000000060f14cc937b8a5acb514c181e64355aad6d70a314b4dfee6b10d327499e31bc331411fbb8a1e11d22ae5bc7b45c56db0000000000000000000000000000000014e148b8d179b63ec8dd1d382ffeb59a699211429f1735ecba9f1d18780f284e0e079e6afe0d1f449031ed3f3ca57f271824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005bcf6a46489f8b0287f31011ec48a12ed66bcdea7be8850f2138a8a4909fc3dcb2bf1598a7be40dc956ec1c6d30726a000000000000000000000000000000000af6f48196e6fb42209ee24bec47389c224c1dc1c87650549470397aa65a20224ebeabd1420171ab4008722b1dfe1c440000000000000000000000000000000016a95b38cec3244d6bf2d86a3fc2d19e5b6d26656625829d2407c6863a26d3a887f10d768384ee44356343cdd6433a2800000000000000000000000000000000038782043207ab8d39639aa267735da9400649acf4fc3cab4a507da1af5e1fe09b76f39a6b133139d6fae346551f61331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001927daac24920e2a9208b9fc7a87533e27681c12c1155d7ace0d78114d522cf8b3e59d991e1f721ad9eadfb13069a43e000000000000000000000000000000000a1965f8c800c6e32e4bedf295c0ac9f914f7e17eb30d3eb908bffdebade6975673617425104db8ae6037d39db54d9a90000000000000000000000000000000001353bb21e4e3518b08349ab35d1dd22c8695c19f442745be6cff44c04cd94059513954012caface5539cc20876d11120000000000000000000000000000000001537d259a51476dfbc80ac0bf0235b21f3fb3ea62a1b737f5ffe8b3c77c22ea06158213dfc309595da0627c6d5720aa1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001fa9bf9b7e624d6b2cfe450bc2a1253e549ce40ce3f8ac7aef6a1a3a3d840d7f0e4a2ed34eafbd25c96b4cafd4f5c040000000000000000000000000000000000a45b09f2be6df22f20a454035a0ddb6b2a9302897b9c7761d0549a0917fa57cd298b60af8f55c0c5cf7e20ff4451f5000000000000000000000000000000001929e10d060820af285d4b799f959617907a649f326cf9d37d3e78a3c3c29fa718912ca9704aba511eacd6f2bf3dc2690000000000000000000000000000000008e017cdb8f4a4ce90464999d9f7b965a1d81cfc6e99258392bf3c6ab351cd9c44ca5aed99b120ad4a12ca4f39e6ed7a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb53b30757e8c7eb901bd27444ef6231431c8d14087574b000cfaeaee9cf711454cda3964bd96b2e7daf04b4b151d800000000000000000000000000000000004f3fb8e3497361d5b4eaa113df7be3820bd75bcda08659612c9223998070d8ce740d040f0e955d172c88b64f424f9500000000000000000000000000000000018eddd36730558f29080e826f081770ac9673085e3458fe2be02d0c0276a9d930c9f005900f2e9c007e56d326fdcd68500000000000000000000000000000000145f47fca33f1e6accd255be7a2b7ecbaed811e6fe68870de808a37ac1f3723bf79387edac8f6cbdc1db29513e8b2bdf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018ea1e9af08df6b37bf2bb257652b7c5de1512d5cfeb8706776d4810e9267c22b8f30ea53bb8b6ffbbf1f57e1d74f45c000000000000000000000000000000001074b6a8f13c29c7d4db7e304756f1f028adbc7cac61d96de2fe24f14207ad581a8abbb3428dd2406b8f12c21f10022400000000000000000000000000000000012e0f514a3d56f07ec8bbbf9a97d1978020fbea1bc4585334460b38dd9f29ab995ee1c24e17721c3a483778eaf070c400000000000000000000000000000000183430201f6154bc626b5bc3153768d3505a76706059d530c0e6468d7d09ceead3a61b8e69f6a625f6f2c2ed2cb7592c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e208f7b22018fea3d6353653edd6e274e51e820419a9d504a98d0ba386140e9c597921725fb2ca52bdc5f18a63d74bc00000000000000000000000000000000043bf3bfba7b951932dea932d79776a8ca3df9a00d7456976c76fa6ce613e404e9df958d784a7e3472c1b59624744c8b0000000000000000000000000000000017b574cc6d5dc483528c7e5d5b60f47d3c7447f5ff1b79b98c9a53b02c60213d890f2ef109899a28a37ad8180dab1b5200000000000000000000000000000000091659c6bf098733e8b451ad25d80326db8bf7f25a0e3faeaa88b7c749ec89e3c700378abd761dcab9396f1e7e71cabe1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ec7c584293e71c57cb09f23190e05219d847bfd95867832d4c8ea616ccee129227fe1e1dddcf5fdc753dac736836bc50000000000000000000000000000000007d75110d8d6f1f8170cc4204191183a9760eb532c92b34cb17226632585ff8732d2be3302dff775edc5914fc9d8607100000000000000000000000000000000167ed8a5ba23e0cefa09830d2ee533923da9d773ff724e4c6cb22aaed6f76dddac3d1c5da8ac562e66363277665d9f2e00000000000000000000000000000000128933190d15c3d33e3069b790d3efb3bd53d0ace163b82cfb1d33789273af6eda14165d58d8b108240bfcb0449dc3fd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001213e44cef05953f75df29b8c9a02617d8a662f6f5153b0838506c295a2e234491997acfa7c7f9cc5ec5e5275a7988490000000000000000000000000000000001ceef3a5dae59f2c5c575417418e4c23e94fd830b3acdc7feeab64cf2514a3e4acd610630ec2c9cbb42b67103a8a2f40000000000000000000000000000000012ba442af36566ded0a4f8df5b9da71769c4aae408c064c427f956469813d1199182dea2b2d52c95373f706784d00749000000000000000000000000000000001991105e87558ec8de90e70451e9b11e675a29efb3ca9839df5ea7db9ffc5a648f3f2959003423bf4c5beb00a045c1ab1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010b3aab5ba6a9ebba028735229e95da5296605c9bddb262050edc50a9924d5d3f41778e50c4e2508c62e9ceba6664dc3000000000000000000000000000000000c5c6c298824358d46f27bab06e1743a5a2ad84e2cf7635f71987fce5c54e8e11d826dc5a04d8a429303d84c0974635a000000000000000000000000000000001603436735afc3bd443dce435c436f1c5e6af47ee49142b668f419552acad8ebf85ea07b32d4c9658e65aa4814b3d9b90000000000000000000000000000000014c5493d1b23df125028e41f6d3bd9fbf633ec81592d9d1d3c77f5dd798bf5f47d701953deaabb46beedb6e3dbdd645e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000207e7bb5ec1e7dadfd583fa6bd777dd7e640caea587572fae42c3ebe5dfa0e0b878d757e70d62c1ef3d41f202c3c2ee000000000000000000000000000000001344915329ac8134f3aed7804be9bf47d77626c6f3a046e92cc38f994b945d18cbbf41697dbeb5aceb7659ea3ed7ff5100000000000000000000000000000000185d4dd392e3a1b1b389683541c55843189832d2179279f4adc09a02575528491e485ce0c67d25db894f83af1b32da96000000000000000000000000000000001740929ad15676b7cd72a41ca786c65160bfd5d51aa9e41c08cd6a8fbce0babd6d7041923e5fba1aff1f421391cef04c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000146ca59a1b0df35244c8c2b89eaee64977895bc41cfc888f03a6bc350c902924ee5a2ebbe98af0d7244294b66394ee6b00000000000000000000000000000000104f9cea6279617e236f25c3cd024fd9cb772cfed74b6a6aa3fae0560955b1e786bcf82d028bf158899386e1561f57200000000000000000000000000000000016e342276a72fa4d2c92bbddfc5cd9157d173b85cd998b65921949a1cea224312a6eb797d266943fc53812fc1beeff9f0000000000000000000000000000000007ebb7ffc650291a0c5a5693dffdee5bc847e18d12d9979abbba0625739953520111923c711dd62cf5c011d2f43f84a51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018691be4655e3904a63d777dd7c77fd31af6f060ef68f72f3c7d151f5bf146ca08b8f0db6979808c0faaaade3bc4215f000000000000000000000000000000000ebdded275e66d5bd8c1dd81c228b1141ab26c2bf4d9a79ac3d952b98528c8a7332eb13f63f858b3a036e5f5439541a7000000000000000000000000000000000389ee6840d1e6d749ecf5d95bd3fde2ced323260d6a80577f53ade8231e2862a34c8010721f9f2c3d7d929c2ccf34670000000000000000000000000000000010173a5bd55bc401a0a1e3d3771c71cf0fc0ce2d0ccfcfd4a07e8ee28ea0672e0e215980e02525eb6cd19279ad5ea54c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014b85eca3b187274008a101ee3566f7ff2cb5d3d0d1570641556fa0b41975e98446ca3a8a7e645d6066340cf6ce4d046000000000000000000000000000000000994935e97b2fdec7cdb02c624da3b3967363e248cfb1bcce3c78d66be3a6a5500afcb6902d4ecb53985e736b62a2dab00000000000000000000000000000000007474204dca97c20b33217cdb8e722d8edcc141aeb4b51f483dd38e4a87b4fc18a5468b536f043476045f82c50e291a00000000000000000000000000000000165b02c0640369897acac7c01555c0b53231b12cb804201ab1ead31035514050b8e72f23a23db3b13c817451da08e6c61824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003836ca3dcdca55164df53c624232f85711579bc9191a6ccc9637ab8fbedc0fbf7e4efdf71a99ea6ba84a6f0d7e9e0290000000000000000000000000000000013d5c830e29de1bf70a78a115ced284ea30e63c4b45e8f7c2e22ae39b8530db5d9b79b6456cf5664b55449c05f82cb850000000000000000000000000000000009dde75b93f423c9e2dd9094194346cd5af81b69c94381ebdb53a69c92ea5cca9910e7d5216b27de6c33028e536412d80000000000000000000000000000000003600e9cddd22fbbf592f0f8af8345558871736c7eb55240e1a9e5c9946911ada4174746e9fe933d5084bfbe285eb5741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000003157427b57a3d8939225e4d9bde6f0b588fc5e617ce70cf44e70dabc8aa48572ceed5898dcf4b755ef5bc7ca1ac19eb0000000000000000000000000000000000f641ffe91f3b74fee1b3a6a78cc5dd513f9bf3418baebc2d22f6e50b8b9038eb320a167bb0c39de6e03433ab3338020000000000000000000000000000000010f3cf0b2b024a575e007f9386b3bac5b0cb67ecb7dcf46cd792b7651d62c989d6c8a8f337663874e1927948a09bf8f60000000000000000000000000000000014e07a0fcfb7ede380c31c662ac9c8b0b0cdc8327b974ba2fb82b09a38b553dc0128f042b41678b07b8ee1378c0e31161824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001169f293b66d53a751e5076e1db96d0787d04af6ca872ae7cea0ecc002a9890a85b01f06a609d46d474b3413a17e4099000000000000000000000000000000000962a5b0e45a93e6e97ec3258bff8724b6bcc024746bddc4eca6963602203f9e8fe5ecf577e292fe67910bc9b21519eb000000000000000000000000000000000ce1ea1a7d995302136a9a3f60f64342ea69c7976ddde65ae603b9bdcc69e4f1df317aa863d14f435824b2da239ec0dc000000000000000000000000000000000bff09658b8512bbcfc77047220a63d9035357f907f7d73e0d27bb70f6ee423e086bbf8d44f16a1e198284065b8353c01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000012ab9938aec52913a167ab4a6aa660178a73aebf72f526a948a31102b425f7bb41212e8d4a87763ac8454a30fbeaf9b00000000000000000000000000000000012407d23128590e274bb206c929dc457c5cf99d26aa8fb5424fe17b7fa23a199ad98346ce7de1148efb4506bb266f860000000000000000000000000000000003477491b9b4512dc642cbc1d1a6b1ad3bad3156e387fa844ba9df9766d3a062ac38100f8099094474c4cd3b2e31af3a0000000000000000000000000000000014c1f3966da30cb1597277af41653ffa0283e8c9709ee5319780ad5e98f4627fd01712945102fc460bcc3759f76ae2b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ce255d82ce850d116392702319478f701caff434ed6018504937815b0deb6884ca99a7845ef61ad9ec40f193f31fc72000000000000000000000000000000000c2f2bb0cbda8d1100f39e79f0f38fada2378bd5578285d5c35fe919f1c7cb114870d19d33695b25418bfae21a09e97100000000000000000000000000000000067e677ef5b8240074a5d356317afeb05ea0cf5d254264238455d9b98668fb7d5961e778df5e8be00b62ed352c6c9e7a000000000000000000000000000000000953f22e389c0a87d7d655508482d42a9c293bf3f3fe40bd0cdfbb21c0a34754e0f0c6bb66f9c5da6ed54483646adbb81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a1640339125bcb4eb91cde756347876cd74600d3ce825194f0b15b8d788e37304b0ab0c50efcea45f695225016f6237000000000000000000000000000000001642a08c000d113f45220777b5cb12501027e8a741d30725a7e61eaf1987d47c30c6bec3aecd094b1ca1e7841316e56f00000000000000000000000000000000102dbe78566e47b4c35f67d2ad04bcdf5622992f08092b27efe17ae5bd885503a205ad5ea3dadfd1cc3f1f2b4b17bf5a000000000000000000000000000000001533a6f9d99c4bec0fdc154dae9e3f5822421ca7dc3676995193ce5f9f89e72d1d27a86e3b9029b348a24d8f340ab9551824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008d7ee6960afcf9d04ff786e666cd869d766d609ed2ff1bd95281e9d731a00d535891cf69786e01e262382f929cd26de00000000000000000000000000000000164599e6263f8908b97becfe105f5864a51704feb01f36f51714c9a834f56042710ef62b0ac7660b3908af410e099f1a000000000000000000000000000000000ee2705c8c7515dc659bafaa07b54c022680769752c2108f4d8ff37888909abd77ecd86cf91329df0a6da4318ab191dd000000000000000000000000000000000e754081405b5e60111a14cb97a7f9831d48984f9740ee482c08d309ef4f00764e9a108d329e0f26f300c306e4514c181824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000eb897ccd128d4ce233afbdcbeda15762cf6fb69ffa509f023d7b8b31865eaef79c38a80a4241168041442a69f9b402000000000000000000000000000000000172694f4a075a69f96eed7c2ad8e7cc133932b725be829d13fef1806b4efaaf2cd34dd201b952d575deddc043d19f84a000000000000000000000000000000000c339d111818e87df3c3bd7dfe935b7d65a77cad6862dc8766437219e45fac306584f8b4a5feca46c54cce17aeff88ec0000000000000000000000000000000019d71963edb7aeff6e7f0b071763cd27ed31399997f865d6e0bfc40e8e7c22491c97cfb428673f0da241aef4f0393b6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000906c00418c225184ff9e2c19d49d74a2246bbba3699badb4c65f8d08bec65a27d4ba1d64240143a1a8fbf260f0fa05f0000000000000000000000000000000011d66f22ce3acd52e43293ae777b03fbd8d557cef0107ad7b3d571fd77f22d887b4d5c36ab09b0ba2e4c3931427fe5a10000000000000000000000000000000000e2df417a8fc4da840da572a314a46e5b45040d32df1542d466a362eb381ad8929d4eaab2fac95bd73b6c7dbe937a380000000000000000000000000000000003d0232a689dbbdfb3b244c886ffa25fac07e993dbe4058b90fbe5aab220b5c80f3d4e52beb1d28d93f8f06c1110a2301824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000365b01425aeda60b4862c75a7d75134543b4e05802c54dfe879381fc6d3363809ab1694e108f27cc658a14136880f570000000000000000000000000000000003c26a9350007404cde07a933176b6e2f6d8bbd81dcadbbe78fc3e1755b61c653258ca27e44fa5328d94893f0205ff670000000000000000000000000000000001b9d0629df9e893eafbc7dcd6626ecce949ba7a660bf2fda2b631f260ab983daa5efbdfd752e80b79578366f88a6a090000000000000000000000000000000012bf88495d371754d40f11e43d0911cfc5c09c6b7cd35b3a33b77777589b32873ad9aba3db8a65272cf753e87e40d72e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001044694288f61226320d910326427620d00c74bde63bfd48440099c5169667a139365b0d21f1944b9840f2b7379a4439000000000000000000000000000000000af35f28dd4db796209b67bbfb437ad0247703c1c16a4e0e61c14b167790137d4617ae0c0fda7593964acbf327305e790000000000000000000000000000000004a276b412f247821e6c78520edc15850aef049ff50cbfa47580c401b83130cea24f54e9d666aad3a3539e48aef7b3da000000000000000000000000000000000a5244c83e3dfb164fb5bf75009c4e024891944e2fb43110d7a4d1c00d808bfb9a751d1a4418b68456d02a43652cd4591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e5cb14edfb45378af4d377c102a75fb31b66f98663f16f0b5825660f4da60aad2559c4532d0914634183d8ea711913c00000000000000000000000000000000005655dc62c085ce8ef4f1a26cc6c2e675b0556d3e16c067de805c8166cc291c95773dfe2abba7864c9883b6ac36e2160000000000000000000000000000000005c64df7724557b6d4c78e6895944b55e769aec01c45611b1013f0653a739a72ebfc550a843cf388bcb388f09b4f77bc000000000000000000000000000000000bed9bda1aab999f3886fbc83184e0c7b4d393aad27e97a6b4f746871c21e4f18b5afe3aeb7a59e1d227744570091c2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000cde4067f09dd264460c862ca6951ccb6d6426471d4eaff297a4073c238a6faf02af758b8fd508d13cb96fd9709a937b0000000000000000000000000000000011f5e85a3d81fe7cf5780994bc5077d3359531a5d59390107bf02ec82ed5a599e200da6a28b0753f3dc47df3632185bb00000000000000000000000000000000009e5b8e5349754616b6cb34b31d3e1942f799beb137892c437b0c7f8be09daaa7448c26bb10ed432d3bce9c1878f90c00000000000000000000000000000000032c24fd4f6c4061335ecc468350f236f03dfa5cfffa3490065efdbca3669c98a3b92b938fa8749e474e01a8f030e4ae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b6b1d8a29050568fea5da7988174c2c62a055d99077fb3f891ae7a983241f7e9200d88672e329aca40782debd2f653a0000000000000000000000000000000005b565ca99fb98f322ff0e38dfc0854615b83065488ace0556059c02e278daf4d525ac16d5e03e6b9ebb6a46321099380000000000000000000000000000000019573fe4511d38edb85c53b0d13ba927ffb79f36239e1de9f6e2cfe162945c7802e800156b4538e353ff7d12256fe2fc000000000000000000000000000000001833895cdcbeece53b87813791c372aea281636f9513e95be98eadad003227e6ea28deb41dc7682ab751942cd961a9a71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002d226368c872b1efd2098b31b7a8b59ba0c7f28fa9759b0acc41fd1a5817714a240c444b2d28865dc98a93bc756ec07000000000000000000000000000000000e7c50673720b873d856e62e4bac71bfce8ca7da762e9698ebebc80f7d54d4f23d7eef148de34ceaecf61b187de7a26b0000000000000000000000000000000018da00c32b1549c028f308e48c26ab47f2cd4a83dac7cd0d2d929f97c721a9708af5bcc6051a357b484d881ecafccc130000000000000000000000000000000004cf897aaec32280235bfc64bca69f7d31849185227d28a2e3cd6e7672223489373edf082589ebdfd2bc2e5ee0c858ea1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000019a9e0696f9ded3be996d5d39add737fc4f07479dbf26444f5b0d74e1a1f1c0a3c249760c46de5a726b93e8a11181f7b0000000000000000000000000000000014df3a0ddf2486f36bb64ffc1db1565cf9d4fb91c74ff3b71be6b017e66620aa2a8a797225da1f8bb7e4c171bec6a69b000000000000000000000000000000001884f21c35e06834dc8607fda3ea84bc2862a22159e608b3e8510c8476efdfe9bde53f210a70327cb151abba9c3ee358000000000000000000000000000000000a3ba7235418478b2ef35b6360707538f1488d2baac6a66b53d52c70b46f1a8d071dd2c2718c520f9ddc73ce6ea3adca1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005f4b4e720a9b8afef57b1874a856b38505040c00de74effca5dce7684bf74a8f5ed32a6f20d7adb7f7dc7ea9ebf71cf000000000000000000000000000000001153633c94b822c13c2195d1c4378acaaf65dcbf0c92254b50ba59097ed05ec41ea3338f7d227c62ad9166e35e86302b000000000000000000000000000000000290837b545e5a05e9bcad16092c161c4b922936a2ddd4efda5b2120d8b382921f05ddc8034d997d4b1234f1da292ef600000000000000000000000000000000173d27b8a441272c97369713ef00e1e753584952c25be71e6cfda910b9377ac7cc647448e8291de2911b5f057d0f72d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008a5533408466ec1dee4d6531266b7012c54ff39cb9d8a35e3d3e8c7ece654c6b29d1074654a21169e5a67d6050fee1800000000000000000000000000000000064b8de7b7ea2e5615c2f8971669bd3fa0283734633c6630c4595f614276a9123b6f1b00f8bc45628b5b7a759f62d7f700000000000000000000000000000000090bb1a3782e13e472ab4ef61fc5ffdfe6a20f404fbc615338660e6fb8242281c6982cdb0852395528d32581eedcfb10000000000000000000000000000000000f12c50168db7ec8a822e5908af746798b99c4ff9a5cadb3b849d8a367ff3b2620fd0c681d0bcc907edd0a88f104b5ac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001f21e6476d659f438868194917daf491ef2b09cb619fb88db44f65bed390c83a9131583572106e90850ea020a447e1f000000000000000000000000000000000c7f0b60f4f0410a40e7daf8ac7f0073a7a7a7412fa1dba907d55aa4fc1f44ef771667fff572dd49532d0905df2105de00000000000000000000000000000000016e23357b61ea66fab4866036fbd3ae07f7a3fc943ca6d294f93e9bb81e4cfc004dae04ec6126984fad59d7529ebf49000000000000000000000000000000000e817957fb0fadfdd00add4117f7a1f2702c4419cc63d41072ffa8bf44663a766019f9e5bf5b5f12e09a5de8114867631824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000002816815337a850c6a70425d12ec3390fe91941d1adfe5f9542a521e7beff090ec7bad56fed028e7016021432ccd1c80000000000000000000000000000000012cf06186331264b8451bcb870714ecdc10bd339bc6c3f6e2f48e6a09c59f505bd2c1f6b8997043fb0bb3dd3a4902d49000000000000000000000000000000000c70e2a07de67066be51c29397a0f496ae20a583d9c09f0d7090572cf6dbc565efa9b9cc0eee942c54ba0b9e02d5811e0000000000000000000000000000000017ffc76c6b38bb859b7fa6f84128e5625b00b4e39a87452edfdac73d0364cfbe5d8e58665d0f05686ae5eeb72f07f7d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b97a5cfdd2774b97fa71e22844dbd689d5c5dcc15afd85723b8f79d8a7fb3ad67d3ef0900afdd6cc54b3874e179632c000000000000000000000000000000000019b76d73e3ed60c2f718fe083f9e0a06f5d7d2484bda1008e143d350f8a913efca3a49fd62fb1862c71fb8335cb3cf0000000000000000000000000000000015590957f25caf26147396846514fb3948a168a72868d7bb93541a0863eec33d18635dfc630a459cde30f2786aa446c40000000000000000000000000000000008a19ed73912b02649e42778622d00f95b422c83dbc94b047bc9a9ea6e9a06b892c69fcf0848b7c585ecdaa36bc923841824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000104d483b82b2211d2924d8e59e54f0f33050d1380a2094d6be75f1f0bff4aa30998c9344b55c573ee7fdaf2d56e7106b000000000000000000000000000000000c743bdf0a67d1414b976ed9109892cc29509e92e87f285b204291c28ce384dc739d773b00a8b61d31e33f31eeca5d4e0000000000000000000000000000000001e3cbb7251dcd9e9eb0fb812f628f03f4cc4626d1b5c1e078fd02677a6509e60226cdabfd57025467706db6d62467140000000000000000000000000000000002d271102c8d3a60d71e1464e5f1edf93fd08a103727c2a358447383cbdc8beaa38c85ef3d0f8474a6edc852d8b754261824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000007a56584f6bbcdbb4c0fd7d04f731d7198392273db59427e4f4002ef453205b56b909785a20407173910fa2a49fd7c0200000000000000000000000000000000173f5f4c45358f3fee629b9c0dc12418b2652603026f91030558fff1c1635ee8214c831032acd249d7b5b9f92d1f26a3000000000000000000000000000000000bffa7fb4ab1ebda1701e000c9507a3519000f432d2ce3a731f9acc3670f61af22e5bc1cce07be824564de6e5ffcda4b0000000000000000000000000000000012fc9a52b0fc78c505abb56db1a74ceda46bc8f4ac20a80ac90b93ea94a593233559d4489eb156360869258d1238224b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004fde13120f9c0a7bc3f5b1aa1b291036830d770685f9f7798ec8228fec661e96a6db77b5a2638255f8954c18bf0d9a8000000000000000000000000000000000aad0fb28039b54c5799ee3c49b8425e3531d2f27fafbc1a66b7b85452d93113f95f983e3ac124e45c2978b12eb7f63b0000000000000000000000000000000014c89c9ecc4b713c409028fbdbb0fd393bd4fd4363a1b43ec43f2c658fb732cbf673d0377a7adb85f47970640855b787000000000000000000000000000000000270f8452abdc0cb63e5140b0d8570454694ce3c14bff3a0594952ae812bc17e850edf53a714a0ca39351f80f2be8e8b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000204b73d4e7b585dcf5df25e8faf02d61f92c8547f9ed0fdd71785a4ceeac79c618e76298f0fe579daa7083f45041e4600000000000000000000000000000000195fdbcd815abca1171946fe4cae5feaf7aa205d129ad8c28f0c2c349b03e497397a726910e56f0f2540397bc4a345cd0000000000000000000000000000000015f95e50aeb525fb4926b81f391a3f05fd3e462a93da3eb8ae927c15466745e64c10d1fe5ac68064478697c026a6c4c6000000000000000000000000000000001032f80ff598999f7e2afb61d77d9fadbce053efbfc254e2ffc2ebbf8279aedb668a2007a8abc3a312872ef0f612392d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d609b1880e6c72c81921c49f7935b56640d8cf0701ff823ae996ddfcee0dfacc31edbf56175bd4e2081164bfe43662e000000000000000000000000000000000105553df601273442739d5f10800990c4ff2d7ad14417337a4ad3bc455a2b3fe3b6d3a6b95f0afa3044091dab88db8c00000000000000000000000000000000048cd7dbd9f125d6664ebbb1a0e0dbe141822a5af05187bb0245361606767206d514883084700554514c64eaa51d1e2000000000000000000000000000000000000e912efc427fe8fa469951ca4b5e4d5c9f9743ee28cae53454f0cfba5fcd3e922c748d5a0aa32eca8a96e6c50ae4b71824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ef1b20c17ea580119863acac8c8d639c5d60491a5bf7edee55676b64c172cd23ce3e4b0087d0c5d460ca13fc3ab200000000000000000000000000000000000958bf34c0106b9ca8b4f98a172515196a94deef9ab569923bef89de4abd35dba845bf7694c4bca6bc3a81248dc010d60000000000000000000000000000000001e0eabebfca330bb5c6a59304dd0d3b003dc7dab5b0104ee09c17a8d79f6f2a9836049fad26c0485d947177ef5eed44000000000000000000000000000000000d9e2193c921f83fc1931a33cabad22700bb716fad5021b0c902f0c71f84645fa0aa2d50cbd1919e765fe3d1bbaf532d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001387a26e4148f81484d3ca7a1be18d0bcf02a8f9d62e277d1f1b8a30b53bc17c10205bb05de743b5a67394ab4d47fa400000000000000000000000000000000008c388d3d3f7673d0356fd2cb043d1494f75959fc39aae1126c3a1c6472425298f3fce0da5d00c7974f6a9da4f94c025000000000000000000000000000000000ea3014f8811f30e51477d3f3c92e1b500657cb5a17a87b1dd103ebb9ccf8042d378e8f4e5acc53b9d9a3fe9c045d6ae0000000000000000000000000000000016e379123eeea3a088001a9e4d196104d2904a6c66939465ace7d815314ffdc35f18d57ebc32d008d6e15f41ab55b6791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000462219e466e1a11e80e9ed687cbd07aa1044eb6b821fb450860daa6ddc27c78254e1d58fa115fe0745157e07174521f00000000000000000000000000000000144e1e18501711daa4cf3abd6221822ff9c42028d2c4f2af34fbb78b99498aa487cb32e5786f0bc2f833203e5f9bbf36000000000000000000000000000000001759941ba0cc06439693e42c7c37d011529a05348580ba8dd58fbae1189ae742cc244242c3ff07a7786ab44a5f73f041000000000000000000000000000000000fc471997e7b0ffd50562f80a5027f397a3d2c62c03260f8691125b550c1b8b59d9b29efe79bca80a098fb8bf44590741824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000014773a4bea92eff773a345e1901454971477aa1c66652d98427c5c6799c1e57aca767f5808a5487db0b867fdedb74313000000000000000000000000000000001596c205b2f73ada312d62bfd465917c9f2dcc5dc8115368630539c250ff5a817ab960d9781479dae1bf4eced86383e20000000000000000000000000000000011b30afd0b167ad733e48eef7886a18b7352a54ddee7dac85f1782cea75f05a58869f9eecb8991ceb1412a3476afd15900000000000000000000000000000000104a3ee1afcd6989b8cc3371e7ee05fce19be23566eab83575b3be9d1bacdbbceeb659e324ae937bd9a5b60d99f907441824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016ea02e5933cbf95186a6ffff469432b17588510bbe6092ca4ac7aadf9493a46a7559f9bac9265c027cc65d9e5e834500000000000000000000000000000000004cb34cd2fdb5c37b68b5db8a346336932f3ab8d34399ec3078c76f21cf4970a380e55ae0afa9597f6ff6ed51078a3800000000000000000000000000000000004ff2fb6b7708cf225512e50a3ec283d0b9be811dba7662e4338f2569add56c1d3cf71e3b063e5fecbe0a78e93a6defc000000000000000000000000000000000b5286e9db99a258c49272676c80bedcd9bc119437d0049f9412a13a0cc3c300b8a9bacf82a7632f7948383a95f7137f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ef3ee375740801712747fa3a3c2428d0fd3220fe1dd5613a614145d45ee44244a9a33d6e50f65bd8da50fb4858ad75000000000000000000000000000000001611d8bc7f50ff2e43040569ad46d58655eab601c18c15bd47fcdc390b77c3252b43436d95d0c8dcf3b9188f5c74092b000000000000000000000000000000000b76d09f4852d8500b4bfcc735c0c3ed1a6b882bd70b1abdbfba870cfbbae87339091a6fc41e904f9a7c123eeea13fdf00000000000000000000000000000000140da05fc3b661b37ea4055586f26db16afe67dcf8c21d3cbc69deb290deae889ea9fc62dc7fe25ed4965e1cd32e16c51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a6609a5ad8e8198d14f3c4f4980206588f38ea32e0107c758d30cbd680eb0b035519ee386a00e9deb2783d221baef8b0000000000000000000000000000000014405950ec3539caa74e01ade48caea3c91aba07839fdfbb45fe7b04ed02274e51ae29f54a8b72bda66c9a6aa5101a84000000000000000000000000000000000f36661c3e23c1acb28f45098b3b2602b6e2ac0f5880bf5f3140e8ee2ea49a425a7039b65003593918b83d074a32ab7200000000000000000000000000000000064c3f493725dadef50f888578d2b021eddd5b2b5667d6967e568245988ff465399cb194c0a861519ada049863feda1f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008f77f9acae4420335aadd5f6881780de8f6a0c7a87f3c8476e49b519a6644636a37598502d6ebd5815eade8ad364968000000000000000000000000000000000ee29e559126c04b325549373926ffae1efbee969da8dcbb3d82bb90e6b01170f02f4d53558fd9035ca98cf4b3c0eb880000000000000000000000000000000002127f4fef39a86365b05c56c783e0597b0621f0ee979475e6156cd40ff44578c784059beaf5db74c6b9b9a2028252330000000000000000000000000000000003aa13aa6d02d04435f4ea1b759a8813a243f0325e1ba8b1895e603de553f9f43396c50bbc11f1c73dd8b8b8929c91801824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000044794895d7275725e59c5ae48db062931e8309dc069d5632adf6fdc8712d2f28d98ef93652ef0432dfba8f5781dfdd00000000000000000000000000000000006c650d984902c0efffd0cd45aa1d87d9c8b24eabe08f21ce4b2fc3cae714512bdd21098d5ec045c8deab145e89661f900000000000000000000000000000000144f9cfde1ac3cf15698eb8c5a4c334cb45d24d81ba7e3c8fc6ab4504f515f944a9ea9db0e0fcbc713324883558a9b34000000000000000000000000000000000486f15ab7f4969e5995b633a7554534a60ea246535b332945af452713f73f1b2dafdffc96910ac496215742fdcba2711824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a9e86df2e099d35fd21d605fd8adf15a97f510e481a8aa61a8b446d98953f1b0f94084dc509305243af3b2ebce21ec00000000000000000000000000000000131d09c3f133d342548bccf841df423b77b748f5bd765140efab6257394a4a119e60593b5030ff1f7db5a38e056bd8580000000000000000000000000000000015f3e6a0378183fca3a20f583f11018adea1656ef89a6ff1ab3739d271fa4c8afc53c7a2bdcc4284c5ebceb651ae74fe00000000000000000000000000000000029fdb63b9c1e448285fa0befe229841ebca3763dee49b3155cef336f085ec010d3583414c754ca959ecb680fea859bf1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c5df1f70ea2693c8e2867c8e55a4d0844956567cfecfa4b9067feca5dcca31ddad34b0020e58f5e8c93865b6b14d4d90000000000000000000000000000000017997fb7d9554c79f2a67ce2081224976e0f7e0dfd7597c8dd8384d7e8dbcadc28a27fcd8c311d22e4e05b7e4a0d9b68000000000000000000000000000000000b12ec93de3c107f858c4c32b090a34cc3161a70f6ae8f473544b9ec5be417d3e35e9d761427947a1df669959d74e55f0000000000000000000000000000000016fe78faef9fe5db3e14e564d6b56b09eabf55685e229af36854282bba6d157b4b928da2a5761a7f4a444038ebb8be5f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d4778ca7c44ad31ab4fb26153d31ad435c54368d96bba290a76265ab70786f125962f53b7bfd7d62d4aa7d7213c45320000000000000000000000000000000015a2f7c68e2431a64ed7c6bfe34d2299828dd7e96ffa635f236bd1e5a447b1d150864a2dc7208461b373d13628bc58cd0000000000000000000000000000000010e7ce0d5d700d83b5f9d6e7e233a5cbed5df706505cfe2256abb7023c0891476bc57976a6833e1a7ee8f086043008610000000000000000000000000000000004f79afccf204d148c09eeb30049cd45db70991689ac9932eb2c527fe45e6404b6787368a0a9eb39397cf6eb1b2e91371824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015d8c87278cab864d10abac16056e279c1d6fa44f115f47b2fcb9e82fca25611a1c6ded85fc2c021d7d960ea81b366e6000000000000000000000000000000000c3ea6748a194fa6cd6b7fb5c0ad8137293524c3214331ed51d1469dcabe0e4f8ee0049e7d1f7f7109647636ec221c0b0000000000000000000000000000000010f44de525b392becbd27c1e7993af943525b233268ab423752d480098c0daa8b3361a7d3878c36a5753c57d72c3c72800000000000000000000000000000000154a47409c7b4faa667e60c22f5b01524f335182f1b2a024537bba273a4322c7bc081da3e722f9a2f0c6b536f4ba2eac1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000078a98c9107c3e149e89e8046b2a37024edd9e29d46ee5fc06e174e20aaa4ee11ffaa5ba44b56a20cb33026a45bb62d30000000000000000000000000000000006c072be91c524f34bca7bb74a18c682f731e435a35916fbebdcfddfa080b4975026dbca44981fceeafb3439ce5d2559000000000000000000000000000000000ad09ee876ec33c20bb1e191cb14091dd09d6fac15a52b00f415737caecf8fcabdcd2e15337eee86e7321b5cd27c10290000000000000000000000000000000010adcd5b1cf5a794dc9fe4b8f3f14cef4230976247cff3f6f0eca97e0b375430ab5a6c07ceb84a9685563f300948f71f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c6cd6056ff955b971f59d05f00f70fbb821fde269bff25cc4f116f8c3a9d5a524be2f194c7e50c4e695aad462e71ce80000000000000000000000000000000002e29fb207bce65d6f54ffdce6a71d2605043e7a3e3e142a72d88370f997b286a3d5825cc54796bde75fb215bb817a000000000000000000000000000000000001b98a04a09ff22546fa1f2abcf48a3f779b2e1b9b46d06e7e72e24946350841e3a1c1bd566dc29cdfe3e3f4444ed64f0000000000000000000000000000000014270a6e91dc58e236745b11f3ddeb2febcd49c75ce1de74347c137432a970dc3ac5f77a19acfbbb50512e69a721604d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000037faf1f2070326c33f5640aac8bfcffaeca6bb8704e279f2f217e6974b5df2a30a35c4ee9582c0ef39fdb0ea8d791550000000000000000000000000000000012e46f36065d4079438b20521643d455fc4a9d151c3a95d273d5e5d46296c671a7d50d34c106d545c9809a26359d87d300000000000000000000000000000000133e4c45ebce459aa2784b1dc27c8a6b4861de225bc944cd93d98b63e7976a8ba89dfd9d2e38a253c2524f43d4c6f32d0000000000000000000000000000000013b9a83d3ca8b4a16a89f54aeb9f0beeff083d30cdd2947868077752ecb0a7cc38a74c0f8416a523febd3d03ad56381d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000f1ab6f87f7291af0ae9ca604ea4dc83a1b9e56d5c515ef5662d033cded5e89a4cf30edf2dced8db27d7266a9cd162ad000000000000000000000000000000000337616207d7383231e6bc0b5926bfe7cb3ead824106656db9ffe39795ae44cb53c0dc78f9ab9ec9706228dcc2b1147800000000000000000000000000000000122dbcc7299137220d9b6228383276b2279ab325690e33e041e415cfc18b6abca3515168df1a410a13fd3fd1897b947c000000000000000000000000000000000238f5634310defab25c59e05bb39d0e620d7c74c1a2b7e882717a1968a5c9aa87a5d9b8064bf1e8998a461bd248f4f81824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000008ea368e4b9e0a3a8c30a985ecf805fc3768e5733c1c388f39c81585326c7c81086286fa67540378c6d0756d2f4cfb330000000000000000000000000000000000f2f626f68b59eaabf9d05b31abf8c8674b980cc31f7f449cfd56f02d15c575fa75601c6e6df78d06010c20efa688fe000000000000000000000000000000000681985e33cf7017bcfba59ce57a3761cce04ee68d8ed853450c07daa20c303fbb9ed704384e2cdfd23e886a030f327300000000000000000000000000000000100a062480edb3bfe23433a8de8da3136a6d66b6fe2c746806708203b0ae552cbf5be8f4b042118a898afdf1211e32971824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015cc32ea1bdfe2741059330b4de20c4a6aeb375fd602c7614535fdecc57a6902ef26fbac4650525045e3e7e0d78cc4ed0000000000000000000000000000000018c97fce161f1fc250b487979509ccdc7e63ef903d7acd6d556767cc2f0d69298f54f8505ca8ca977663f1bc641e1d37000000000000000000000000000000001032f2415560d8b51d32aa0d0de834bbdebe95b829ecc2f0dcba1235637c0502c044e5cc9dddc09d7be5709bec8bd57c0000000000000000000000000000000004fb62efd3944dfd4f1df6c732a96b185047aaba8bda6f5767edc6cd09fe188bb3fb562f1a37fee39a4d12d9e550eb2b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000942365ce762f989fff5188bc91010f952dccf4307104db492a4100e46fd139c394b17d31e805a8374c5476a93e0adc7000000000000000000000000000000000fd364c7109f3576b654f4bddec8aaa9832438b139d58081817b77a925e173729012e3f1274977ac0b33d7bd04ff11f70000000000000000000000000000000006edcd909b473d99f49a50389e7549a2222b062905f5a435271d16e93cc0970167176ed7866f1d232441ce2ce40b1d75000000000000000000000000000000000ea589e1b3d06bdbbfd681799ca49680cdc6ae1169cb7f1370cf30f238c89be862e5cd1cd1ded1f2c9e759bc2e647d6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000145aff2d1569b04e42a7e44272bbb8e605f8cdcb155491b08f52a3cf22a4b7dba8dea9dbf3f88dbe88c3b3c17b8dac9000000000000000000000000000000000a08d25da1324ec8e8759595df36a7159ec2547ca18a5e430f6dc1104b44f351ab7f82e79d10e98e2a9ceccc007cd31e0000000000000000000000000000000019a6ee88832e0395c3c637512a00da0f0d4534fe60a1ea703dfd218fd9ba14e3d1bec2b04177df7afa62e2569f461c35000000000000000000000000000000000ac9773a528f704c156004ba3cb9770a1de86c44cd42e346bdd274a65a837de3a67c9450f01e28be1770b8a3b81530231824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016c5ad4977e509669a1baa2cfbdbdb0592edf7577f90bcf24e0f7011f424e9b2f219341f003082cbe1cab7c2e5c7fc5c00000000000000000000000000000000190c641daafb9c6e925341cbbe3e9e89576786e79960059d6ff2ce9d08e91737cdeb84874e83aa2fbf95eaeffc67337100000000000000000000000000000000159a56b80f0b584658076c1425febbfc03390bc8d97220425decc135a51f93f9c98e207d29d76bf120e7c871ac30f4dc0000000000000000000000000000000017a5a0b7a8b4e719a7cb0eaefe95ac9f7c72955f9ffe7e24131a6d633e087cf8c55c8b6a1fe2a6b23796d1e9361ee6591824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012bd89fd90118d60ea4bf4df35902ea8f930a39e787b01ba0a60b3f40591e52db36b4735cb5c694887e1f2020ade4dfb000000000000000000000000000000000d7580f67007b68109c8aca895045e58bb858055f5adb64e536bd0b975122e35cd62406be60adc3e619e7dc4632fa6d0000000000000000000000000000000000c9a637021f8508b02acc97733f2353528f8068927813eb2937aac6f39e56b38d7ffddec5147d18cbf4b52b20ed7ca8b0000000000000000000000000000000014a251a3aafe4a7fae33acebd223a24237d51f0d7e6c2e36b6993b91d4988a0ac6418a3b65b65cd2e5c356be21854a9f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015558a948d169718e3a33b17c9cb380318d9af9c575d001d44523d442d5ba66be7a85fe66a73615af23c1ba9569c3ed60000000000000000000000000000000010a135b145def15c7dd0247af52d5b893e4f47463f0e7819d415ef06521075a565dc64902b3d5ed61981399820845034000000000000000000000000000000001873a08e7d041279d03e88dec0c700ba91187143ec7687ea1b66ffc84d0e75e2be608eefffbb47f74eaad37c50686aa700000000000000000000000000000000091839cf5b284a11da9d12bff9acc6a082f0503b3e04eda3ecd68a32b5df89f91f7e5373b86df5125c4385ad51263bc91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000b8f4c64fb3f7f3c040cf1811a5cb01c4b04a33db798010f3e7dfa1a974e629308bf9fbb66f2bcfd4efbcfaae7568943000000000000000000000000000000000a82c3cdb469e66c44bfc6aa9efeb452082cb72c98430fb6d1bbefd3d9c64760aa2c38f453a75ce813228d760a345e0c00000000000000000000000000000000018efab4d919e1adeee5b5fcc8e89fd1b9ecbb49de50e80d60f70251d4a7da696c1c5e8c5de0d55b2887101bfcd88b240000000000000000000000000000000002d0ffa855389efdee28281a1e95fc805ef8dfe55dd54861e450a065885c49b7b6f69ebb7099bd9dabe96fd3f65493f91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d0e6156f0099845f81b3e16246bffa9514ac35edd802e9f39a6603f3cb1a2e6056d2a09ed2f2ebccb72371ae0726ae40000000000000000000000000000000008efde50a1e9c7bb4ea222aa69904e89c0995493ec17e4260f09b4663bf9dea0f5939a526bef1684506f836a115112a30000000000000000000000000000000001a24f67ae179255fcb9188fc5011f7cfa3e0010b5c483b524cac9cf5ced6e118ea4d91a9d2839f41099cb13358a118900000000000000000000000000000000090a800d9657928f63d9d1faecad7fb0e40377e56ae3f8c27c61a3d09fd1e9dc2c2b6cf423e0e0f88df6e992b3cbaedb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000702a2dda96def0e19b6c754e784c519b4f42972cb976bfcd973372f17e1fca6ecc0088fa5bd448bd55ba3ae530d2ff00000000000000000000000000000000004e08465aa570c5c4a6205021cb49f2ac325bef823eef8302be8ef884f62de7e68010416fb070bb3d4ed08132055b89c000000000000000000000000000000000f2ac59da7ad3336cbeda881d0e5f6b71db2ed0fda523d0d9eeffab8111e64eff04d21c66afe1fecc8adf6911aaeec1c0000000000000000000000000000000014252236ed41d358902a8e7ef2b3e2f15add33f59efd1b0c553c4b16c4dec0efc5aa34331009582c57fceaf4cd3b77901824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000ad103e1f49b1a099ebf286650b65cc368ec423df1497e624fe5108e6115e4f7e7eae8089108bf019fd5a808fba2133b00000000000000000000000000000000039cb70034dbea094eb5bfd0a854360b378a3d333c55e3b9ab93335f4533ba2cc6dcee25a2eb90e61b1d3c54fe1c9c370000000000000000000000000000000013002ecc2c47cbc64e963d8fde3effff07450cc75322f64ab483074fa93e85e5aa2a17f0a2e85bcad8da09142b0921fb00000000000000000000000000000000074aad861044292daa97ad3f3cc4319c3db7d1eca9b66fbf5cde7e21117e026cbcaa94fb4ecdba15c45b7442f15e85a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015ff622c75fda41e830d83e1f7c2c8d37967b8b2073341b856d17cdc25fed9aa4786f7295960212c5c2ca2945065ad72000000000000000000000000000000001580b7ed98c3b9e3dd0777caeaf42386f683efc9bb8088158c9c43fa4ccd178405307b67b9267c5f8305962a794816df0000000000000000000000000000000012f80580334017c86013329511527829b51311e5d52c46803ad126f62f8d548767b5dd29692b2593a0adac436becf4c60000000000000000000000000000000014144667f1a8c3e4eaae596afb725020992ef1eec41861699ec8d659d23701012610cd5591c98cad72927a3d96f429251824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000001328dcbc880a0f6fa5d244ef89ad81f3c3905a0af36794800089f922e21b72ffe6b72e31f7ea58d1730e840181fbe00000000000000000000000000000000032a3c9f849533af17db9a05b229c8d3b142db58a8ce8ced3921366d27627733608126ba716270e1993b58cb3a1e596400000000000000000000000000000000045331d73f8bff93bc50cfc75302799e4a8898821e165f3de0b7936654beb9320c7ca4d5036a941b5f27ac185a8a234e0000000000000000000000000000000009a1f7b893dde9f0653f64d6a3bfe4a0f505c82a01eea7485a6bb07e39b42511c479a31e8237eeac3d766a3666dcdee91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000df72c38326575a3dfd0c60abe795ff1f91f2d6e84440a16ef6c08eaea96fe445f68dde38fc9da4053e74f201f0063e2000000000000000000000000000000000dd12c1369cc16b00532cf89f17048ee560515a6fc29242e0f9ad16bf90e7ce799344f970f349d7b9c38d6153afcc9a60000000000000000000000000000000010d56040471c724e0111e1012f1c5e643d6829413e8937a7c8f77413df2511d2a4ca41bbd4e4beedda986c40b285e7e1000000000000000000000000000000000d724cf9958bb8036e3f91b09c660a2ac10b9c0a162c2989977d9ec7757d3bcc6b72691287c85b5b05a171e24bc8d61d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000168cf6afe08f62a48660c4bbda1b0e29a6b63c07d2cc86d66cd200dbcc0fdd3f69376296ed71338672a3f7a9262967800000000000000000000000000000000180c5db29ff0e366520db2a55a871e560981a850ce9effd61d544c7253c99a4b61b0cddd0faabc205ea6f205ad3bcd800000000000000000000000000000000018c2251a6903d33ceb0b12abecb7535515d5289b112443aea65f6bb96e303992f01b53a4db7961555163863cebd8c8bc00000000000000000000000000000000005fc705055c3bccf7056c9a64e6f3b9b656b7d58cac5c8a8bae389029ccae818de768c894da3ade62c83cee02ab771f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000765e1b6bea654dc67d999421710ac41965952f53ba835a589441841a6163e7d0ae41ac5406b591c6e5bac71b2f2423000000000000000000000000000000000146f33c010ada3ddeff9d87dbdaa0c4c3be52d0d7295a4da3205909168687d0948ccd1b5275b700f50753a2fd15241b00000000000000000000000000000000018ab48c636b46c8cd24191795679e83876d274fab1ddc3ceb6749fb4fd6c1b0b74998a98a34f03ad4eace16b4f2a231100000000000000000000000000000000193d73264418017fe9d23976533e9e4ec522ef71bf97f2659933f354b19bd08ff423e25a08c0af9a75af77f897a3edb01824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000173d99f70ef55128675174a6d51fe24ac8ad83dd6bae15a9f391da65a4e5c9fe7ca4bac373a478e532739f21027aab6c000000000000000000000000000000000769c12f882e6e02cab80df2733415fe15b389bc0cbc6145013836b51026b236df8296e6da211eca019096131c98704b0000000000000000000000000000000014e7153561ac62442875caec537c4b16f06df2faa89ddfeb3994e0498ed673c4da24b3ca5066292fca1b9c9e1b1610c60000000000000000000000000000000001cc840b59b13af870042bb0ba7231f85b29a7bdc8d9368d5aa379005a7b2aa79cf481e54768c3bd9ab59fb93d0dffdb1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000d2f80834b33e2cd3f3c230d5a9e65fd674f29edfd8c0de3eac11dea59e8a9700585ebfcaac07d1ad59c4afda0a379a2000000000000000000000000000000000d6c27b820729a16a5050b1bc8a1d415f6f61da5c49e8ec83399ededdff4fe236ffedbf58b5a6ee7cda3a2d3977b939e00000000000000000000000000000000190fb3f8c608eec93abcbf1fe57b335919857d26521f30c105289a7a222490214f4147a4417aea594d912564c8e0db790000000000000000000000000000000016b8338eccde031e62fd0127d15ff0ea5f76c33ef2a49d87771228739e06e7de386a7e294bd77bb3b4f8c8a80e85ef5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000052ddae4c6155a2cb711f864e53455aa551f92c76c25130658f6e6392fbb66dd548bedab448ea5bc197d7c781eb01ee90000000000000000000000000000000009237657cf177f84ba2fa09c2efc113d8146f2cee5890fb207daf667b640022decfb6fbfd98c0f6b2ae7248488004e5c00000000000000000000000000000000129704e8b35fc11aa753f3b2c2145fc1b150f87e16ad84fea400ede06149ee453e51c5394cadeda7beee63e04733fab700000000000000000000000000000000128d183c88817bd7297bcd58e33cf1da2e21dbcdbf3e0e7533334133431303ac6c4723e449ea889d1c043c8c99e56e091824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a8b24cfe2db01eb6a20327ac388d08e2d7bfd432097c9e3dcb697a3ff3a05d3ba1dc4e249391deb2eff3d0a08e1763600000000000000000000000000000000129b1c3b9ec9285f6916f279eb15513b87deb860b64ab138493453187d2f705559f840165e337f7e9b76d3361075246a0000000000000000000000000000000005763c17c5358c8fe56cf3a6350a6fe717545e3236f14ff2e2d9c202d8905317595b0e7e20b6ec17a7fcb1486f7f617300000000000000000000000000000000175a813782e259d77769d3f17cd9edafe10af907a8d940364a29e9d3b8b75ec3fe78fb07e9a2d77909326cd49e4ad1941824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000027f79d337b30bce1689db92d77b95fe68519c3299008faeb85235425c983b239789a690613b3a72bb74caaa5299ca1100000000000000000000000000000000173b4961226319cced64538536a0f0dec928b8a79b1f0e8a49f18d0cdcad68bdabfd452e30f96677fb5b2979b82dd8a500000000000000000000000000000000130833412eb66afaf6b445c8b367e6dad4ef1c2558c6c5f75f484371c464a260f860df4837b69d568d89068053d70f1500000000000000000000000000000000076fd9f1d0deeff4d3784c597d12668910dd7d94ea5156f3116390204a75a04f087f6ef5dd5a4ec0ba7270092527907e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000e762c624f0ea97818c0bb83117d5df0afca15407a2641ded8561f00c7ab2e4e24cfe82457876aad20db7d3375254269000000000000000000000000000000000339a65bee3e72fea81701c3d0edfc75c38750e006614c4fd83895b10ac055ba5733ad7be8bd8a0811725a66ca12411a0000000000000000000000000000000012f92ce4b8c842fe0a4b22a3d950b1a1fb190ee09e771ed297369cf8b144198ef352c1d0e3f7e2390705ae1bfe18b2a70000000000000000000000000000000016f5607cdc02f9170619c0fb4e7ea1e24dd226ba67c41ae6cf7105785d18571bcf8fd601512fa824b247e6766af6325b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000c9fb4d154f2dd4fc40bb8cf0a64a36e6027b4ceef0f79516ee6dd5cd8144303ada1ff15f5e9b1603e2ddd6f94fee75500000000000000000000000000000000114dac33b2a522c7f8ddc9fd92925fd325b91a08f67e9d639cf616f517c66c4d1faeaa79cdb784f511ffd550d9dc81c4000000000000000000000000000000000bea9b7c4323d0b54b7101caeae2437f57b44e039c6b205fba391c00ece275fc609e4ab0213e88ee8f998649c6dfd5740000000000000000000000000000000010893701c4e486ccf3e3095d2f3f02a439611d4608a681652f2f4d8207b67c773e20b7805bc84e39f4faa480d8bdc2dd1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004273c66a22783fe880619708d228caa29ed4f3198690ec8ed3be4dc6b675f9ff47468c36df6d290c1456242d15231ec000000000000000000000000000000000358ef987e8d618b057948d354be0d95c8f140adec04e11d98200d66c500e57bbb527044fd415d6b0e6aea1380c620360000000000000000000000000000000009a290f91b985126e3419fd222e53f1bd23aa69ab9b81b9d957ac568d55a5c428bc981e216b7ecec357b6154f79848b90000000000000000000000000000000011d8f3f6aa71e9456a44244def7f0af9bf00e48f076a7163a4b15fda145e310078192ba8e1bfaa499e92f5bcc7b70a051824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000004ba6ba86b644bd96892caacce01841eed057ddf9f460eaebdce8f26fd50d31d9bac315303dd2aef7e3c905386ed6a9000000000000000000000000000000000043d9e7e32e4ac93f0903f0e7bf2e1c94a1dee22812a9d1aff62cae5fb665362ed4f3a7a775fd9ee3e2af252c617b18f00000000000000000000000000000000163e9d42c96fae30f013353e9d97e0b5786a90c8110e712341176504994176be149ae3e238141f7ee5e58b8bd269154e0000000000000000000000000000000001fff186044751ff136e0add91eaa4da0b2ca21e868b73607fbe0acba408596614a86c65e2e1f88b81ca8d8f9fb2289c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006b966bc869f1e1c728cd89b7c99e79d19b7daa0856f4d9ae54fad6c7fcd0772b69a1d00d60c76303a21f46e900f5f770000000000000000000000000000000014cb15361ef896464d79f84b0b3520e94bbcc92927824b4d269c2bbd0af0ae1fa212cbce88ec54346393c4d423ba52b40000000000000000000000000000000007aa57716b7d95726c0b76e9b7bcf7e311da08fffbc81ee15b02f4bf08b3dd41d165115a259d34384d72fd75fe6524f800000000000000000000000000000000008ba06b5a787d2e8ad4c3f910a601a45f30b176e3618c0439c00a871b2bc14e1de0bcc2b72ed593dd69798bf0ab97d51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000111ff17f78120f59943cd9b5007a1c607d787fbc08a3bcce5eca9a6e7336291e6b696a1efb6ce5193b7b7fd3f68fc43f000000000000000000000000000000000b799c1169fb6262224d7e953c3d710db495d88918fa5ca3ea106bd7cefc198f038df0e13db4aeeef4c4a6c6e8b7691c0000000000000000000000000000000012d458b19c9cd7ff654afdc4ea4d3e275271e579e3f083ed6fec04b92192ea19c1b55b921b34e20e1de9cc53a47951a800000000000000000000000000000000097e35ba7cf8b39ac42aa4c3632a0a0d6e8a8f057bc0fd4b11f71aca126ef7686f8f8a2c0241f67eea242e1a2771b1511824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013eb7950960759e13626c7b5be87693bdb5eb05968bed9cdecfa1068cd7d3c97075ccf709ee8e9637c076d727747cd7a0000000000000000000000000000000012ad2c196a4f7fd2d4089484e785062e43839b0bc3e1d604d1630e4f95cfc9ac91bc750fea7f1735b4ff5d01fe6de12b00000000000000000000000000000000113e31c9d50cdc9f50b9b00e8793ac8a07d4b1a84dfd732c53933c43c0cf0b4506ba18037798aa47348d2f1ca24b08b7000000000000000000000000000000000cec9ee9492a05a533a2a35482454592436c4f7edc5695a88f0cda522e106f07f35e3bd72fe01647029b480b6d52ed4c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001439a9fa5602ebdce91b248d2e1bb6d3f937e2d2249f5fe817301553bf36e4ff002d6d066cb63e24ab57ab920e600c59000000000000000000000000000000000da6eec4829a4b940710643495c17232d33bb7bdd767e1eee4915077ed0b831df1a3080da98baea829a6e377e9e0d9eb000000000000000000000000000000000c2a4d773e64c10431842145644ae2f63730555f11da19e1458f9a9ab2adf1c3f1a045d5aa997f8a89ec924a8278c27f0000000000000000000000000000000011ded0635e59e428d88629755a8ea11b8bd23e0b0c60182c73a4e8de4b7e50664399d88e228ead5528189448781166331824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000012d620ec19ed67af168446e21d5dfcce68a5d1d0834a295357facce7e26f4455030993a700ef8cd5a91891b613a3bc38000000000000000000000000000000001630fa86ef31311af9802c43c0e0a873f75109d5b76dddfd2da074d5720b23094dbccbc470358eb192fb5d365bfa7a3c00000000000000000000000000000000032d6422d25d881dd94b629ce2fbb8b6c2ba6cd08d2f3da854f1955affde1eaa6e871a2ab489adb0b5ff978a7df6d3f500000000000000000000000000000000169b3e6864dea595ce86d97bfb9fcf26eb23093ba75aebda1930fc5e3e0cf2f641d27226eb5f994dbec8e47f8120e48a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000ac9f1ef69025b67da31eafb81eed658f6472c2fceacd7cb5ac84b62fca6b04346e8341a02ce589d21e302a390d976c00000000000000000000000000000000175c5f9083b2d98038cf64df48e34222172c42646a57b9b538f02528950fe7260eea0502f6b04699feafe41d59893d6a000000000000000000000000000000000bc921434624de5334fd7f509977d4e8b6b69ba433a61cb20ebdb789a959748b30afde60e6bc6e740c0a9bf2352bf02e00000000000000000000000000000000002b757118fda743829e1d8fc328aa246d28be1b95f95452ddc146bae88660929a96ac6659984ad8d715dbcd6d6bf3481824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000a3b2e15738504b69eff2a74eac44096ce50ca0998a550c3752db69289276feb136c27c7b1eb357f73ed6e4a14810361000000000000000000000000000000000629f1cc9c59201c332c38620a90236031fd803a1ad128d619e643e1d4d532a71eadf8ebaf5a4b45852876b561fef30c0000000000000000000000000000000017d094359487563883715eb07669854e4f025cbf47ec303f7303842c9f022b6ed7a037eb0d9bceac987621c08e8d4ce9000000000000000000000000000000000e1ace86b2e1063619d1282e00565e0d1412482070fd43f400e0a9fc042311b87b348a33ec925f878115b253e08bc4e21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000006f40d0ebdfce6baf1024a669937170ad9e666660813dcd37ff6531d84f4151b6305dd084ff869988d99228fa1b60b410000000000000000000000000000000010b3ae2e95fbd78dee8c29da880747249eadd3334aa9472f08b31fcda74f8ba0678e7d8f44b30f0eea2c00d1f267d2a00000000000000000000000000000000015cdf4a52f79f6ef8aa5d61c4488b7314a71d252face9c87c93627c49e8a981a4b553feedf2240942632000b52a5b56400000000000000000000000000000000072e87ebd1b0d459651b6a3a0421304e5decca06aa8b4fa8e13a5f3bdd75b788014387a43b68388c0d2c34ba3f96d81e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009a4b021f45c78564fa6303113aef811501c61c0624de6dacc963b42f8ffcbb53164ca4deb0e4063c9200e84736aa5c800000000000000000000000000000000173a9c582dda8f313e1f5c14f21a7f00320ec3c2b7558ed6d113ac89729071590b3ec982a79873e20caf3c6fcf565d700000000000000000000000000000000002047ea8f40ff057dfd05b17b67a350f325e78dcc4a0d19a405e64ce23c44a8e56841ca9f57e35b2f7e88771210b31440000000000000000000000000000000015b5688dffc2613c16bd1a11e3410f660d40272d682c2329a8d04956c01806d7eedb9138001a23edba6a738a21ad2fde1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000100e0e2b1b4fc00721c1155022da0e3b394b0d8dcf6d8d29df8847704ec4dd9f6305ad7d2e1ab284c1074ae0e99461e00000000000000000000000000000000139a1bd565aa1f7013a5c0f08fab90bf3c157bf2b4bfdff3ad0de942fc4da05974b522be22478d4bc1b269444303f74e000000000000000000000000000000000e82ede5724d6b42a0b30ef3832c8519df8eccde633f7e2a91c3d25aed3e423752391b8f378d26e329f28f22fc0afe830000000000000000000000000000000006cf72bf453c494798b05ad401d1be0f1987681549869387dc85afcaf7a8e3f7bd4c9c9564e6087c8db68bcbf234d8b31824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000acbbc26ff8082e6201281507ec817e1aa48fc3cd749245e4dbf9813ddde2082f2232fdaa4397ff995b5efd258361ebe0000000000000000000000000000000013c2592b2699e28b4a4a6a55c5077e4e927770937d0b585bf5bff3ff94fff892949a262fa60d19e7a08e11ee278ba49b000000000000000000000000000000000aefb08f71fcc8531b67b5623403305914f4a1242452543c05a67b4d805e04bc2b055ebad1006d2d84384794039d2c80000000000000000000000000000000000df5642c7ca23d3bf49d6978cf0689718bb73c020d503e7cb021db046d16ada87161feb46fd56542c8dde6b382baf3b11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000030aa5bfa6df9718620f17020a39f2f6ae0441b5682e11651070cfd91ca9426061b98daa3eff2dc8cdbb850829949fa800000000000000000000000000000000104d57eac1696ab955e852f2e092b3ed17471bb90bc093d2bfebb75c2704f6ea8c7979117568a18f25d5f88c3a7cebfd00000000000000000000000000000000099415ea067b342246afcfbc0555ca55b6c26e25af9ec43ec087e035fa8675b06eec4aba6161d6ddf145ab33f3089ebb000000000000000000000000000000001384ab642dc21526b26669b9c690741b98244d45e1ae5161255ff1ed444d50d5d4ea9b5fd9906c822cd646a05381b12e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000086963227ebd8ae42e99eb67d87de72e9b8c8c4669cd9526bdd68670a76b4244f2827afc2d41a607dcffe880b466efdf00000000000000000000000000000000095650612c2197d7999241ed00ddae080c1627238d1884c339364931ea26b414e31c78a91bdecb1c7f797f61082748e40000000000000000000000000000000004c8900e47a670376abb302004481cd2cebbf5057115a63d03285afe62942f3c6cb2d165068cbe257895604bd0c107e8000000000000000000000000000000000c216aa20807ed1fc40c1d9a1792943154f77e87610416a26528af6a0571b2f5b61496504140d100ccd673d31dfa47121824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000002a47f12407eb06e902e57c1b44b95f74e367e7f9332fe3f222350169d9874b422f97d51a01271b3b2e6ae250396b72b0000000000000000000000000000000006e429926d5253dbcb6dada8a418be7aa9c80c02b10b201e2d9fe9968c610cd833451f43029f62ca0b1885d7922871d90000000000000000000000000000000018f4170bdcdf38caf19e7d3c9cd2d78d1180ba945228672584eb75b7afdc5083c41aaf5861e876cba452c384bfbccd5d0000000000000000000000000000000002e58256b22339fafb9eee9050aacf7f3b34bd63dbff334844cdf48871f6b5d5650a0ab8d70c48640cf04b3b973e20d41824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000124b19da6d8fb220f7e566499c192778e9b28cb2da5fe31ec2e569a03fcd7a1ba39deddf36d489655f7c69e10675e7ef0000000000000000000000000000000013650d54147ac7d016b4ee94de62e90469534d8f6a2bad6ebfd6e5d50247a7f184ad6a1af804cd43520d47e8c9d6d1780000000000000000000000000000000010d0cd79350974897876b17bcd2d6674636cf970ec3344677e381c72419fee418c15588fc37cd1063c5047a5ffbb5faf000000000000000000000000000000000f5fd55bdd7ea1b1c57702ed40cd6c63912ec6c0d13f954f41b5d8347e2a0befe2af9b900d48428b34ae9f5a038551981824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001400738f1235b9302b86d2128aebfba46088b755cd7095f8e0feb6400a91360eaef54bf8e714be30d743d91803457e3f000000000000000000000000000000000644d3929cc9911c1e292336c0d43d771410d46c199e064bdee825381ea26219d2ee9696e50a291f94ff2752f5e6574d0000000000000000000000000000000004cfac7cba9dba084b0418b147cc7f0a6090ffb3619d6206121477dd8842f09dbfc48e14d5528d7f12bea9ebce41d9b4000000000000000000000000000000001025cd701a8a3dea5097c94c3924350b53c9c8af79b7ed9baaa928065a2833f860baa1a154b61b068e5d9e2840bda52f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084dfbe49f37db531979d235fcbce3b5ee534a654ae64b7c1616bf5ca282b59325bf7f69825a6831c3766b867757f12600000000000000000000000000000000174dc6e4fc2575701da91aaf5c3fff3ba476aa664d183cf57b2634000a82e05b075768a8a442a5cafdf95135c2cc936f0000000000000000000000000000000015574ae00f6dc32ae57f1db04e1ba50c82087cfb269349e98b0f8841f83a7bcacd3785954f8847bd88df0bab01de8444000000000000000000000000000000000cbf903479efb8ae9818a9b824daa117bf8c04c7922cbd7185b6f1456f425049a02f87abac7dddabcc0a183df781bdae1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001039f728d8d83c9e8700063c169395bed6c7490d54dfabea1fbdb714dfead0ef5c86c8d8dcf8b06564ff3bcea2b803b50000000000000000000000000000000014a40ad99055d4c16e76d9922446d27be5761ccb547d22137db5ce8909004c3a39f797b0873a1a5637834ea0da52aac7000000000000000000000000000000001089b3a198f4f532514a35d74d69ef387fd54d8e8805f479b3425c840b256d40016f4972ccb3e1b650f6cbe7e17df05f000000000000000000000000000000000ff6b147cbc7407e1361e9e9f71c62d6b0d81a81be5be90aa6ac2d565fe07661fa73c8f0b604212f3c3a268c1f56c1b21824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000015f3ae1582692e3e33f2442991530517219f9b3ebf88fff03f81237553cc1509a4732155423dca88a6e63e9f036318b400000000000000000000000000000000000f80475ada3353f9f4beea3181004bfbd77033276fc97c73cea875cec86ce00c1c2956c5d45d548436226c4d0a48930000000000000000000000000000000000ced6435f355fe76d88f54401e4fb8f3992567b969177975597bb8f4f085b43dac6c4bf7b79b63d8bc617b1068655340000000000000000000000000000000010599298d7f952758f22e9c64f54b0c637c203b3fcafd205d08a408c20a8869612c7484c88d2843de8ede4c63abff98a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000deed304633e52f8174b8ae6f730f6751676a6e3f8e26ac8c114615f463eb2da71a9bac650ff188f16c1e9b61a2e0c900000000000000000000000000000000166b2764aa0c60dfc3d8d28d4a4fd2710608721be0074505f7c2f6061a48160812488f5918649d973888bcce4263f79000000000000000000000000000000000025811567302686b3d8304c35dca281ccde474b65acc50ab4c57be143cd60e73edd776395aae8ad7fb50d8d8f596ef1b0000000000000000000000000000000019b23e64059448e92ae75cd1dabbd569eb727a74f108552c06c1d64533d6f79b066a60fbfb1070eac8d9d095512d60791824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000148aa82244ac489a6d29cf7a5ed0a2099763db2d5b4c7324073e240271e9f9bf215a234ab16ab5cabffefebb36d8b3d10000000000000000000000000000000002dbac638f7cfc530c9d2bd1cdd3faf64f2c4a6cfb636ef69ea759aed9fd804f890e1d94a6507c1f330a760aa5fc37370000000000000000000000000000000015edbb563b6fb737e9f7eb0ab733b675ee622ea0ad3b27ad2088012434d01e00965c9d08d7d5e29b3e2312ce29d61c48000000000000000000000000000000000586c5fb0a680dcab6c924a7f1b77a4c4c5eecd7906ccc5766f0a9f874d19718cc8c84ec4349f4b2adeab311b259cfc51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000018536c11854b53a080f259976c390546547ebd0216c60f4b992c396297720047a64912403d86d2e7f89958b6a7e196b900000000000000000000000000000000019667de47937d95031897a3fc1b977d5d7194327c62a61181f28d5480a0cc5080be670590f1a3735a5e17e5bd1d9a8000000000000000000000000000000000006a522bb9af0557b0140812716059d749d47e8258254ef496dfff3d33c53ab448ecebf303ade65fed0747539cac0ba30000000000000000000000000000000010fe64b2d4243d5609af091dfea721fa7ac4a7a20e1d6a658ac48cf74fe071136f9245c76839c8324e57da741c40749b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000023284f6bbb674448250470b05317d1d5464aa25d2618ebbfd2c94dfb4242bb24740dc09b088822d53e81fa0c3df684e0000000000000000000000000000000012d0f6105f450da62341fcdf77f85c8635ae876d892fb8b84107cb3e1345eb9e6d4443bb58936b40c3bdef769e6f8f74000000000000000000000000000000001469c571de6025bf61e8d26bf42f2381caf37213428671ca27b5c3418dcc4c07acecbb01ca2b62556c3e04d498d7c2d1000000000000000000000000000000000ffcdaf88a02d1c5e67418ceb2b6dc133d8c35aa080b84efa8ef68ffa330eb85f99f430cd5a06878ac7241c811a160c11824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000001eb0ab3b9f7c535d2cf14bbce867368b830f0832c62877c581ca80c46305e2f2a264279a33c6e0e311881a8d38300ab00000000000000000000000000000000069180f60e9c49d57f3ff7f25698c34842f8d1a08a3c1b3a9c44389091898983571c4100ce9fe30f69d616897ec280820000000000000000000000000000000018f9cfb80f0e064808bc7ab72b07ff4d4cfbac4c2a332a52dc0d8864b87b8b0b28d971b0b55c3e173ee2c34880eb6f620000000000000000000000000000000001d32e89bbb423b49835d05e1ef847e3f60ef7e9c102547ef0d5cf7e8ca3860d64f304a5e9a652e2b00a24cd3ffcf17a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000084fa87381de3b4029a65a89d30748c6b36fdb5dcad5bf9f16a288a50b8ae8390725db0cd7b78fbfc18127cbb50053940000000000000000000000000000000005f29523e7ce25322e5c01696ee6a7b1b8c870e53dfc83918df6dc52d1d0890157c927257b111ecf41bee03bc90f1e9b0000000000000000000000000000000009a428030f019ee2907d46706e120be71ac4cde2f6bbf534bf8ff67d5e025f74f49055034e5e621cbb6fbdcc1024607600000000000000000000000000000000136934b9a77919605cc5cdf267d7ad3e17d3b98c411b824ff02a07f26c565630fc628895560030e9c69f0b174385fd7d1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000016e05e43fea0f6c7b589be17d2fd51e5d2e9e2c8119c391e3a65573dc4a29fa6fc4f134e6988f64ef97fc2ce01c09b040000000000000000000000000000000006da32b477fe9f75ca6c6aefd26e4a6c2adb2f179bd37c9f156380167842e85c86044ca21358363ef2fa4579c432ac94000000000000000000000000000000000a006191d9277dd93264ca4d3d7855f3298905e5c27c46983e91e339b890204d4b3e4bc7924da350dab83516902551d10000000000000000000000000000000007b203cb2e15248c5fbe2ce269c2e3027a5c03b07fa2cec6d2619ad9d9eda38d2e7d96de0ac5c7b9d3976001c5df20651824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000174a53f2ef50d98eceef87abb8ed231ccfbb065fde000854ec8ec55ed1d480ff4022446c06634fc9a7cb71eff99c4a86000000000000000000000000000000000a758cee0ec88392aaba77d7dd3b9c18df2f1da31b2daed006c3d79a196b86d5443388ab9ff3369e87e3ea7a3539fb0c000000000000000000000000000000000902fabb7c99dba8759f77accb5261282efa36bc101908e0f7d9569c7363d880c3b4ebccb93fb04cd6b271010cb524d0000000000000000000000000000000000b217b772f517d90805cb4e6037f2e82839fa9549da1859e85cf76ec8952fe98fa8a9d40e3fecfc7bb1846f1f8fa62a91824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001050cb16ce5ecbdf55d83ec6804945b882602035c3a621376267dd5ece77f083250c3de885ff65adb310e01db32a64380000000000000000000000000000000019da83f5fa1fd94077015622535295a6d4763c4f464ae5cffb3796cf99c3e0c115ec65d28890a3b68d0d62f7bb86452800000000000000000000000000000000102c31f1bd3638a26b7046fcd64919389572a6d2b290d03b0c028a0ab48f2ca5f30dbcf925ea90f68cadef85a239c8c70000000000000000000000000000000019a33801bf1c2977e1586a9ee9cdc74777436aaa069d241f365b13db0946078f5a70c846946488485eb1c19b022991ba1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000049318e9ce756dfa02a47602fef0c5f69c3bad0c1825ecf52afa1c9001e2b60a4bb026fb465eec2b61c040d467890c6100000000000000000000000000000000147015d586e332fa678d2e6567e8814861eda9d25813108e54874c37441349413aee08839bf48dc8050b6ea7cc5b3464000000000000000000000000000000000c87b168ad95ec5981eead6a37d74e30ad575bb09aa3ac17b8bf0e5c6a11bea1b8d40f56f90d347046139c19110ec935000000000000000000000000000000000b8f20662e356ca8b3616dcf03a065a97a859b72936d472ed9f12431959b4fdd69d414b53879f86bcaac130eac8198ed1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001900021195089a4feee22cf8b539dcfba09ca48f828e77f5d905b3c2033404f2ed7b21509faee6ee6248683db7ac3c860000000000000000000000000000000010759a56269209a12894cad47c979c6b46282902cec89511f7adda7392c90bab9e191b5b6a8005f72854ae8e858f0ed400000000000000000000000000000000076bc78ec0a0c097ab589450c886f300a8edca200ffc84c03749b76b484131c620b5db35ec0195ac33edf304057b41bf000000000000000000000000000000000a92607c52d5c7d0ed24738f671d1c6b11e0590f64283df1e7db79ee40a9ea4ae2e38c3cf76225d0facbe93e5eaf8a5a1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd00000000000000000000000000000000001851f0f6db1eab1b69dd7ced468aeccf2df239b455fa38e9313330e5281f18a20a8aa20ca1c5e5bc2f9866aec92a12000000000000000000000000000000000c1c251901260bab20360db5b0b8e050ac8fe5abf074a67c757002403416826c502a8775dfe851d2ba8cce472054337b00000000000000000000000000000000139740ed23b4d29802be95d6f302f54a2be8ab0aa3f183afce973fa9149b89f877a85246cde29676a6ae5ac1e0965c3400000000000000000000000000000000091664122a88acce381e1c405cfc18cc11f8c630bd4f438aecd02e9ddbb0ed85d38da050fa98e6adddc29a7c8c17344b1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000010c65ccae34ff73b68373937aafa307355b32e3c3d0ad250fb062ae82f9cc13beaf298c6a71dd8d5599831fb38a8d315000000000000000000000000000000000aa6a6ed43fa75789d2fac1a0dcc92eac8b9ce5f49d4e2429038141a47144d37e0a8a20a232ab6ebb075e0bc17a26bec000000000000000000000000000000000bd00304bd516b3b64b3ca19235c55e1a4dc2f7d8ad2823992909271bc659fb276bb8c42ad2811a13dd3c37ceb37d88b0000000000000000000000000000000000642dc986bd879cc949e2229935f947a17ad848af0d52fb990504f745152e4e7bb11259ce4a8bdd419480db833424201824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000005ba6a5d12a35ff05fff302c4abfa325db749075b30acdba4897092e9838e24003afd118800182b3a82b24695dd32e150000000000000000000000000000000013ce6eeac487f264fba1f26b6924734b816b88e120aad4a650c6033568e1da2eada3b07f097f7eb5f1433185fc68cc7f00000000000000000000000000000000175f9a6a026830306e7c9ab80dbb19bb0d0dc936141070e1bc165f0cebaa8bb35ddadd090ab8c0d85724eb83751578d60000000000000000000000000000000004ab1eabbbc1b88785770be143c478e059ddbb4a0be5c301449f7abdd358e8db0f1570bde2c37d25c33053a5cca5c49e1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000001393118b0664124d991ac7a98eca8888ee52cc90065b468838bba3371495ba4d5bbcf481d3d642c444bcf17fc8a69cc3000000000000000000000000000000000d3b5e12652096f1d9c6abd0475f9edc3e43998d31488eeba4f53c0d8b7261ee2adb0392168ea23ad8ecc8b4b607fcd70000000000000000000000000000000013b5209b79a78df0465415dec28ddecdc254f8c843199c62c23731a2f7e3f6b4f2f03a5e80565f74173131ac3cfe19270000000000000000000000000000000012947041c7c6f0b5cd83dbf442bab64e0c10cc33e0b53e9fade4354eff20da0b1c7f080fd8d50c429cc036eba2eafa281824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000009213afdc588d27053de6b0ab5df9ed62b313e1d05d6e5b0965d78f7cd8f665c3615ccd7a7759895a4402cca974a32fc0000000000000000000000000000000015c4262ad1b113cc6a65d022d480aba4f3201b519c296ccd5873a72bff4a9c4aaa8b6b1122486e15b1d9063e1379600b000000000000000000000000000000001832b25262ee5b8f100049b7e527f7adf82841f81709593211c3c2b73c20ea2627dd94c4af553d35a48f30416e7fb74a000000000000000000000000000000001776386a29b3457b0852f03e0c5abdf08c98a06809c7f7711038b8fb920f059d0211dcb7203177e37ea88b043d70f42c1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000000749414cbd262bbc05c87e61cf091ec90dae3c703e87b4040503f15cb0a0a9b5d208869cdf4a54baa9f737414717c350000000000000000000000000000000005485e5fe4329edff91541526ad98544953d58bd405b0d03a76aba85174b12910a77c2149f6479752e858bf566032a260000000000000000000000000000000014578447e6068e02f5d13120e72148785efae64bc1d52efaa8594dc0491a3b280ec9be9b06400047710cd7b88927b267000000000000000000000000000000001615ab016fdc2acb99eaa9872b4a896bc11009a66bc2c9cbe5cec0b187b2cc8a213731fbd33c6261d3b636a237e79efc1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd000000000000000000000000000000000292589156be4715b87f0946d868034f2d33c22f3f615ed620faa031be47b86bcd1713c5c6330872390c1632b6c6317b000000000000000000000000000000000c35b7e6e42834831134e7cca1e9fff98c83f8dea9b21baea96d3aea623fe6b30c4edff140784fe9f1581aed28d7d2020000000000000000000000000000000017bbfa07a4746be906e692e09a3ab20629c1be8c07fd275ae37d717b4b4af1f25303cbfa3473588886a614aa04e3e6f600000000000000000000000000000000083f3b8815c245bfde07a139dfa4910743241741ea46876e0c8e0a7c55c394c112b76c71f401d0192afb63af49007f6f1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd0000000000000000000000000000000013a8312c30f3a7f508cbc1cf6f00a6973873309a9cc1ea8cf682f637a73855ba7dc5c10908f306a5282764f66ecd3175000000000000000000000000000000000564c133be0d3be8698ab98a2dafb2b82ca43636a9876eff19fbca8e113e1990ccefc4492b6a6034ea2e2d6ff411e574000000000000000000000000000000000ca0f865c096920be147dc662619a2763817a474ddcad928638de4dbf121ede32f8c5b5d39475b18e8f924054b86a7e300000000000000000000000000000000043f0230d9352dd19767bc715b8d471dff8e4c4b355019321585add13f15e73bd5f7419abb924a300bda1f3f77c01df51824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "Expected": "0000000000000000000000000000000007ac96192f4225233b4b88f7cf2650464e10f3b8275304e790b72f006637051fdd82b98d791928342b00a57282e81f5a0000000000000000000000000000000007a341a771e2ef772134661c486268c3d354e8332655792b88d6bf7ec3cb8148974141d09b21a76a9af869d30bdc1b750000000000000000000000000000000004e01c938b6e64e5786b7e49b19d1f437d14ea9042b5b25e611789d1eb6c94db812976e75b9cfe635a7e9c8dffe8bdfb0000000000000000000000000000000008da0941af163a46252e9c6057497cd04637924f158f0507ccbff466ae810e2178eac76cb3ff8835804b88951cd44c0e", + "Name": "g2msm-1024-jwasinger", + "Gas": 8017920, + "NoBenchmark": false } -] \ No newline at end of file +] From b5a88dafae52c7126b185aed841a418943fc5cb9 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 26 Sep 2024 08:12:12 +0200 Subject: [PATCH 556/571] p2p/discover: fix flaky tests writing to test.log after completion (#30506) This PR fixes two tests, which had a tendency to sometimes write to the `*testing.T` `log` facility after the test function had completed, which is not allowed. This PR fixes it by using waitgroups to ensure that the handler/logwriter terminates before the test exits. closes #30505 --- p2p/discover/v4_lookup_test.go | 26 ++++++++++++++++++++++---- p2p/enode/nodedb.go | 6 +++++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/p2p/discover/v4_lookup_test.go b/p2p/discover/v4_lookup_test.go index 70bd7056fba2..29a9dd6645e0 100644 --- a/p2p/discover/v4_lookup_test.go +++ b/p2p/discover/v4_lookup_test.go @@ -21,6 +21,7 @@ import ( "fmt" "net/netip" "slices" + "sync" "testing" "github.com/ethereum/go-ethereum/crypto" @@ -67,7 +68,11 @@ func TestUDPv4_Lookup(t *testing.T) { func TestUDPv4_LookupIterator(t *testing.T) { t.Parallel() test := newUDPTest(t) - defer test.close() + var wg sync.WaitGroup + defer func() { + test.close() + wg.Wait() + }() // Seed table with initial nodes. bootnodes := make([]*enode.Node, len(lookupTestnet.dists[256])) @@ -75,7 +80,11 @@ func TestUDPv4_LookupIterator(t *testing.T) { bootnodes[i] = lookupTestnet.node(256, i) } fillTable(test.table, bootnodes, true) - go serveTestnet(test, lookupTestnet) + wg.Add(1) + go func() { + serveTestnet(test, lookupTestnet) + wg.Done() + }() // Create the iterator and collect the nodes it yields. iter := test.udp.RandomNodes() @@ -102,7 +111,11 @@ func TestUDPv4_LookupIterator(t *testing.T) { func TestUDPv4_LookupIteratorClose(t *testing.T) { t.Parallel() test := newUDPTest(t) - defer test.close() + var wg sync.WaitGroup + defer func() { + test.close() + wg.Wait() + }() // Seed table with initial nodes. bootnodes := make([]*enode.Node, len(lookupTestnet.dists[256])) @@ -110,7 +123,12 @@ func TestUDPv4_LookupIteratorClose(t *testing.T) { bootnodes[i] = lookupTestnet.node(256, i) } fillTable(test.table, bootnodes, true) - go serveTestnet(test, lookupTestnet) + + wg.Add(1) + go func() { + serveTestnet(test, lookupTestnet) + wg.Done() + }() it := test.udp.RandomNodes() if ok := it.Next(); !ok || it.Node() == nil { diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go index 1f31c98d2256..51e554e68adc 100644 --- a/p2p/enode/nodedb.go +++ b/p2p/enode/nodedb.go @@ -496,6 +496,10 @@ func nextNode(it iterator.Iterator) *Node { // Close flushes and closes the database files. func (db *DB) Close() { - close(db.quit) + select { + case <-db.quit: // already closed + default: + close(db.quit) + } db.lvl.Close() } From 93675d1da702618310db3232da41b09b8a5853da Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 26 Sep 2024 09:28:40 +0200 Subject: [PATCH 557/571] deps: update supranational/blst (#30504) This update should only affect the fuzzers, as far as I know. But it seems like it might also fix some arm/macos compilation issue in https://github.com/ethereum/go-ethereum/issues/30494 Closes #30494 (I think) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a8f5d11a89eb..e9692cf8b3c1 100644 --- a/go.mod +++ b/go.mod @@ -61,7 +61,7 @@ require ( github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 github.com/stretchr/testify v1.9.0 - github.com/supranational/blst v0.3.11 + github.com/supranational/blst v0.3.13 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.25.7 diff --git a/go.sum b/go.sum index ab9bff9960be..21a5e5bcd81f 100644 --- a/go.sum +++ b/go.sum @@ -495,8 +495,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= -github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= +github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= From bb9897f11be1054bdbb8fc3b10fed38be8f33000 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Thu, 26 Sep 2024 16:08:36 +0700 Subject: [PATCH 558/571] core/txpool, eth/catalyst: ensure gas tip retains current value upon rollback (#30495) Here we move the method that drops all transactions by temporarily increasing the fee into the TxPool itself. It's better to have it there because we can set it back to the configured value afterwards. This resolves a TODO in the simulated backend. --- core/txpool/blobpool/blobpool.go | 105 +++++++++++++++------------ core/txpool/legacypool/legacypool.go | 23 ++++-- core/txpool/subpool.go | 3 + core/txpool/txpool.go | 7 ++ eth/catalyst/simulated_beacon.go | 9 +-- 5 files changed, 86 insertions(+), 61 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 685c017cbdb6..864b92257b7b 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1013,6 +1013,56 @@ func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) error { return nil } +func (p *BlobPool) flushTransactionsBelowTip(tip *uint256.Int) { + for addr, txs := range p.index { + for i, tx := range txs { + if tx.execTipCap.Cmp(tip) < 0 { + // Drop the offending transaction + var ( + ids = []uint64{tx.id} + nonces = []uint64{tx.nonce} + ) + p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[i].costCap) + p.stored -= uint64(tx.size) + delete(p.lookup, tx.hash) + txs[i] = nil + + // Drop everything afterwards, no gaps allowed + for j, tx := range txs[i+1:] { + ids = append(ids, tx.id) + nonces = append(nonces, tx.nonce) + + p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], tx.costCap) + p.stored -= uint64(tx.size) + delete(p.lookup, tx.hash) + txs[i+1+j] = nil + } + // Clear out the dropped transactions from the index + if i > 0 { + p.index[addr] = txs[:i] + heap.Fix(p.evict, p.evict.index[addr]) + } else { + delete(p.index, addr) + delete(p.spent, addr) + + heap.Remove(p.evict, p.evict.index[addr]) + p.reserve(addr, false) + } + // Clear out the transactions from the data store + log.Warn("Dropping underpriced blob transaction", "from", addr, "rejected", tx.nonce, "tip", tx.execTipCap, "want", tip, "drop", nonces, "ids", ids) + dropUnderpricedMeter.Mark(int64(len(ids))) + + for _, id := range ids { + if err := p.store.Delete(id); err != nil { + log.Error("Failed to delete dropped transaction", "id", id, "err", err) + } + } + break + } + } + } +} + // SetGasTip implements txpool.SubPool, allowing the blob pool's gas requirements // to be kept in sync with the main transaction pool's gas requirements. func (p *BlobPool) SetGasTip(tip *big.Int) { @@ -1025,59 +1075,20 @@ func (p *BlobPool) SetGasTip(tip *big.Int) { // If the min miner fee increased, remove transactions below the new threshold if old == nil || p.gasTip.Cmp(old) > 0 { - for addr, txs := range p.index { - for i, tx := range txs { - if tx.execTipCap.Cmp(p.gasTip) < 0 { - // Drop the offending transaction - var ( - ids = []uint64{tx.id} - nonces = []uint64{tx.nonce} - ) - p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[i].costCap) - p.stored -= uint64(tx.size) - delete(p.lookup, tx.hash) - txs[i] = nil - - // Drop everything afterwards, no gaps allowed - for j, tx := range txs[i+1:] { - ids = append(ids, tx.id) - nonces = append(nonces, tx.nonce) - - p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], tx.costCap) - p.stored -= uint64(tx.size) - delete(p.lookup, tx.hash) - txs[i+1+j] = nil - } - // Clear out the dropped transactions from the index - if i > 0 { - p.index[addr] = txs[:i] - heap.Fix(p.evict, p.evict.index[addr]) - } else { - delete(p.index, addr) - delete(p.spent, addr) - - heap.Remove(p.evict, p.evict.index[addr]) - p.reserve(addr, false) - } - // Clear out the transactions from the data store - log.Warn("Dropping underpriced blob transaction", "from", addr, "rejected", tx.nonce, "tip", tx.execTipCap, "want", tip, "drop", nonces, "ids", ids) - dropUnderpricedMeter.Mark(int64(len(ids))) - - for _, id := range ids { - if err := p.store.Delete(id); err != nil { - log.Error("Failed to delete dropped transaction", "id", id, "err", err) - } - } - break - } - } - } + p.flushTransactionsBelowTip(p.gasTip) } log.Debug("Blobpool tip threshold updated", "tip", tip) pooltipGauge.Update(tip.Int64()) p.updateStorageMetrics() } +func (p *BlobPool) FlushAllTransactions() { + maxUint256 := uint256.MustFromBig(new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1)) + p.lock.Lock() + defer p.lock.Unlock() + p.flushTransactionsBelowTip(maxUint256) +} + // validateTx checks whether a transaction is valid according to the consensus // rules and adheres to some heuristic limits of the local node (price and size). func (p *BlobPool) validateTx(tx *types.Transaction) error { diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 5506ecc31fc3..1ac8086522b0 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -429,6 +429,15 @@ func (pool *LegacyPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs return pool.txFeed.Subscribe(ch) } +func (pool *LegacyPool) flushTransactionsBelowTip(tip *big.Int) { + // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead + drop := pool.all.RemotesBelowTip(tip) + for _, tx := range drop { + pool.removeTx(tx.Hash(), false, true) + } + pool.priced.Removed(len(drop)) +} + // SetGasTip updates the minimum gas tip required by the transaction pool for a // new transaction, and drops all transactions below this threshold. func (pool *LegacyPool) SetGasTip(tip *big.Int) { @@ -442,16 +451,18 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) { pool.gasTip.Store(newTip) // If the min miner fee increased, remove transactions below the new threshold if newTip.Cmp(old) > 0 { - // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead - drop := pool.all.RemotesBelowTip(tip) - for _, tx := range drop { - pool.removeTx(tx.Hash(), false, true) - } - pool.priced.Removed(len(drop)) + pool.flushTransactionsBelowTip(tip) } log.Info("Legacy pool tip threshold updated", "tip", newTip) } +func (pool *LegacyPool) FlushAllTransactions() { + maxUint256 := new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1) + pool.mu.Lock() + defer pool.mu.Unlock() + pool.flushTransactionsBelowTip(maxUint256) +} + // Nonce returns the next nonce of an account, with all transactions executable // by the pool already applied on top. func (pool *LegacyPool) Nonce(addr common.Address) uint64 { diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 9881ed1b8f96..e361eabd4e84 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -116,6 +116,9 @@ type SubPool interface { // transaction, and drops all transactions below this threshold. SetGasTip(tip *big.Int) + // FlushAllTransactions drops all transactions in the pool. + FlushAllTransactions() + // Has returns an indicator whether subpool has a transaction cached with the // given hash. Has(hash common.Hash) bool diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index be7435247d92..f18eb4c6a0d5 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -104,6 +104,13 @@ func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) { return pool, nil } +// FlushAllTransactions removes all transactions from all subpools +func (p *TxPool) FlushAllTransactions() { + for _, subpool := range p.subpools { + subpool.FlushAllTransactions() + } +} + // reserver is a method to create an address reservation callback to exclusively // assign/deassign addresses to/from subpools. This can ensure that at any point // in time, only a single subpool is able to manage an account, avoiding cross diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index dbf561ca4176..247d906d0500 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -21,7 +21,6 @@ import ( "crypto/sha256" "errors" "fmt" - "math/big" "sync" "time" @@ -34,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -286,12 +284,7 @@ func (c *SimulatedBeacon) Commit() common.Hash { // Rollback un-sends previously added transactions. func (c *SimulatedBeacon) Rollback() { - // Flush all transactions from the transaction pools - maxUint256 := new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1) - c.eth.TxPool().SetGasTip(maxUint256) - // Set the gas tip back to accept new transactions - // TODO (Marius van der Wijden): set gas tip to parameter passed by config - c.eth.TxPool().SetGasTip(big.NewInt(params.GWei)) + c.eth.TxPool().FlushAllTransactions() } // Fork sets the head to the provided hash. From 9274f28210f6743e06fc0692748cd257125ff11e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 27 Sep 2024 08:24:23 +0200 Subject: [PATCH 559/571] core/txpool/blobpool: revert part of #30437, return all reinject-addresses --- core/txpool/blobpool/blobpool.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 864b92257b7b..1789367be10c 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -949,9 +949,7 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]* lost = append(lost, tx) } } - if len(lost) > 0 { - reinject[addr] = lost - } + reinject[addr] = lost // Update the set that was already reincluded to track the blocks in limbo for _, tx := range types.TxDifference(included[addr], discarded[addr]) { From abbd3d9d21aeac7229f72ffff600d40fa5519cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 27 Sep 2024 11:55:42 +0300 Subject: [PATCH 560/571] core/txpool/blobpool: add test to check internal shuffling --- core/txpool/blobpool/blobpool_test.go | 108 ++++++++++++++++++-------- 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index feccb1792211..9bbc763e777f 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -27,7 +27,6 @@ import ( "path/filepath" "sync" "testing" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" @@ -53,25 +52,14 @@ var ( emptyBlobVHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) ) -// Chain configuration with Cancun enabled. -// -// TODO(karalabe): replace with params.MainnetChainConfig after Cancun. -var testChainConfig *params.ChainConfig - -func init() { - testChainConfig = new(params.ChainConfig) - *testChainConfig = *params.MainnetChainConfig - - testChainConfig.CancunTime = new(uint64) - *testChainConfig.CancunTime = uint64(time.Now().Unix()) -} - // testBlockChain is a mock of the live chain for testing the pool. type testBlockChain struct { config *params.ChainConfig basefee *uint256.Int blobfee *uint256.Int statedb *state.StateDB + + blocks map[uint64]*types.Block } func (bc *testBlockChain) Config() *params.ChainConfig { @@ -79,7 +67,7 @@ func (bc *testBlockChain) Config() *params.ChainConfig { } func (bc *testBlockChain) CurrentBlock() *types.Header { - // Yolo, life is too short to invert mist.CalcBaseFee and misc.CalcBlobFee, + // Yolo, life is too short to invert misc.CalcBaseFee and misc.CalcBlobFee, // just binary search it them. // The base fee at 5714 ETH translates into the 21000 base gas higher than @@ -142,7 +130,14 @@ func (bc *testBlockChain) CurrentFinalBlock() *types.Header { } func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { - return nil + // This is very yolo for the tests. If the number is the origin block we use + // to init the pool, return an empty block with the correct starting header. + // + // If it is something else, return some baked in mock data. + if number == bc.config.LondonBlock.Uint64()+1 { + return types.NewBlockWithHeader(bc.CurrentBlock()) + } + return bc.blocks[number] } func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { @@ -181,14 +176,14 @@ func makeAddressReserver() txpool.AddressReserver { // the blob pool. func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, key *ecdsa.PrivateKey) *types.Transaction { blobtx := makeUnsignedTx(nonce, gasTipCap, gasFeeCap, blobFeeCap) - return types.MustSignNewTx(key, types.LatestSigner(testChainConfig), blobtx) + return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx) } // makeUnsignedTx is a utility method to construct a random blob transaction // without signing it. func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx { return &types.BlobTx{ - ChainID: uint256.MustFromBig(testChainConfig.ChainID), + ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID), Nonce: nonce, GasTipCap: uint256.NewInt(gasTipCap), GasFeeCap: uint256.NewInt(gasFeeCap), @@ -229,13 +224,17 @@ func verifyPoolInternals(t *testing.T, pool *BlobPool) { for hash := range seen { t.Errorf("indexed transaction hash #%x missing from lookup table", hash) } - // Verify that transactions are sorted per account and contain no nonce gaps + // Verify that transactions are sorted per account and contain no nonce gaps, + // and that the first nonce is the next expected one based on the state. for addr, txs := range pool.index { for i := 1; i < len(txs); i++ { if txs[i].nonce != txs[i-1].nonce+1 { t.Errorf("addr %v, tx %d nonce mismatch: have %d, want %d", addr, i, txs[i].nonce, txs[i-1].nonce+1) } } + if txs[0].nonce != pool.state.GetNonce(addr) { + t.Errorf("addr %v, first tx nonce mismatch: have %d, want %d", addr, txs[0].nonce, pool.state.GetNonce(addr)) + } } // Verify that calculated evacuation thresholds are correct for addr, txs := range pool.index { @@ -331,7 +330,7 @@ func TestOpenDrops(t *testing.T) { // Insert a transaction with a bad signature to verify that stale junk after // potential hard-forks can get evicted (case 2) tx := types.NewTx(&types.BlobTx{ - ChainID: uint256.MustFromBig(testChainConfig.ChainID), + ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID), GasTipCap: new(uint256.Int), GasFeeCap: new(uint256.Int), Gas: 0, @@ -560,7 +559,7 @@ func TestOpenDrops(t *testing.T) { statedb.Commit(0, true) chain := &testBlockChain{ - config: testChainConfig, + config: params.MainnetChainConfig, basefee: uint256.NewInt(params.InitialBaseFee), blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice), statedb: statedb, @@ -679,7 +678,7 @@ func TestOpenIndex(t *testing.T) { statedb.Commit(0, true) chain := &testBlockChain{ - config: testChainConfig, + config: params.MainnetChainConfig, basefee: uint256.NewInt(params.InitialBaseFee), blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice), statedb: statedb, @@ -781,7 +780,7 @@ func TestOpenHeap(t *testing.T) { statedb.Commit(0, true) chain := &testBlockChain{ - config: testChainConfig, + config: params.MainnetChainConfig, basefee: uint256.NewInt(1050), blobfee: uint256.NewInt(105), statedb: statedb, @@ -861,7 +860,7 @@ func TestOpenCap(t *testing.T) { statedb.Commit(0, true) chain := &testBlockChain{ - config: testChainConfig, + config: params.MainnetChainConfig, basefee: uint256.NewInt(1050), blobfee: uint256.NewInt(105), statedb: statedb, @@ -908,13 +907,12 @@ func TestOpenCap(t *testing.T) { func TestAdd(t *testing.T) { log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true))) - // seed is a helper tumpe to seed an initial state db and pool + // seed is a helper tuple to seed an initial state db and pool type seed struct { balance uint64 nonce uint64 txs []*types.BlobTx } - // addtx is a helper sender/tx tuple to represent a new tx addition type addtx struct { from string @@ -925,6 +923,7 @@ func TestAdd(t *testing.T) { tests := []struct { seeds map[string]seed adds []addtx + block []addtx }{ // Transactions from new accounts should be accepted if their initial // nonce matches the expected one from the statedb. Higher or lower must @@ -1250,6 +1249,25 @@ func TestAdd(t *testing.T) { }, }, }, + // Tests issue #30518 where a refactor broke internal state invariants, + // causing included transactions not to be properly accounted and thus + // account states going our of sync with the chain. + { + seeds: map[string]seed{ + "alice": { + balance: 1000000, + txs: []*types.BlobTx{ + makeUnsignedTx(0, 1, 1, 1), + }, + }, + }, + block: []addtx{ + { + from: "alice", + tx: makeUnsignedTx(0, 1, 1, 1), + }, + }, + }, } for i, tt := range tests { // Create a temporary folder for the persistent backend @@ -1276,7 +1294,7 @@ func TestAdd(t *testing.T) { // Sign the seed transactions and store them in the data store for _, tx := range seed.txs { - signed := types.MustSignNewTx(keys[acc], types.LatestSigner(testChainConfig), tx) + signed := types.MustSignNewTx(keys[acc], types.LatestSigner(params.MainnetChainConfig), tx) blob, _ := rlp.EncodeToBytes(signed) store.Put(blob) } @@ -1286,7 +1304,7 @@ func TestAdd(t *testing.T) { // Create a blob pool out of the pre-seeded dats chain := &testBlockChain{ - config: testChainConfig, + config: params.MainnetChainConfig, basefee: uint256.NewInt(1050), blobfee: uint256.NewInt(105), statedb: statedb, @@ -1299,14 +1317,40 @@ func TestAdd(t *testing.T) { // Add each transaction one by one, verifying the pool internals in between for j, add := range tt.adds { - signed, _ := types.SignNewTx(keys[add.from], types.LatestSigner(testChainConfig), add.tx) + signed, _ := types.SignNewTx(keys[add.from], types.LatestSigner(params.MainnetChainConfig), add.tx) if err := pool.add(signed); !errors.Is(err, add.err) { t.Errorf("test %d, tx %d: adding transaction error mismatch: have %v, want %v", i, j, err, add.err) } verifyPoolInternals(t, pool) } - // Verify the pool internals and close down the test verifyPoolInternals(t, pool) + + // If the test contains a chain head event, run that and gain verify the internals + if tt.block != nil { + // Fake a header for the new set of transactions + header := &types.Header{ + Number: big.NewInt(int64(chain.CurrentBlock().Number.Uint64() + 1)), + BaseFee: chain.CurrentBlock().BaseFee, // invalid, but nothing checks it, yolo + } + // Inject the fake block into the chain + txs := make([]*types.Transaction, len(tt.block)) + for j, inc := range tt.block { + txs[j] = types.MustSignNewTx(keys[inc.from], types.LatestSigner(params.MainnetChainConfig), inc.tx) + } + chain.blocks = map[uint64]*types.Block{ + header.Number.Uint64(): types.NewBlockWithHeader(header).WithBody(types.Body{ + Transactions: txs, + }), + } + // Apply the nonce updates to the state db + for _, tx := range txs { + sender, _ := types.Sender(types.LatestSigner(params.MainnetChainConfig), tx) + chain.statedb.SetNonce(sender, tx.Nonce()+1) + } + pool.Reset(chain.CurrentBlock(), header) + verifyPoolInternals(t, pool) + } + // Close down the test pool.Close() } } @@ -1325,10 +1369,10 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) { var ( basefee = uint64(1050) blobfee = uint64(105) - signer = types.LatestSigner(testChainConfig) + signer = types.LatestSigner(params.MainnetChainConfig) statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) chain = &testBlockChain{ - config: testChainConfig, + config: params.MainnetChainConfig, basefee: uint256.NewInt(basefee), blobfee: uint256.NewInt(blobfee), statedb: statedb, From 1df75dbe3611d92b585148b7abc1a33bfba17557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 27 Sep 2024 13:56:25 +0300 Subject: [PATCH 561/571] Revert "core/txpool, eth/catalyst: ensure gas tip retains current value upon rollback" (#30521) Reverts ethereum/go-ethereum#30495 You are free to create a proper Clear method if that's the best way. But one that does a proper cleanup, not some hacky call to set gas which screws up logs, metrics and everything along the way. Also doesn't work for legacy pool local transactions. The current code had a hack in the simulated code, now we have a hack in live txpooling code. No, that's not acceptable. I want the live code to be proper, meaningful API, meaningful comments, meaningful implementation. --- core/txpool/blobpool/blobpool.go | 105 ++++++++++++--------------- core/txpool/legacypool/legacypool.go | 23 ++---- core/txpool/subpool.go | 3 - core/txpool/txpool.go | 7 -- eth/catalyst/simulated_beacon.go | 9 ++- 5 files changed, 61 insertions(+), 86 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 1789367be10c..745fc08fec06 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1011,56 +1011,6 @@ func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) error { return nil } -func (p *BlobPool) flushTransactionsBelowTip(tip *uint256.Int) { - for addr, txs := range p.index { - for i, tx := range txs { - if tx.execTipCap.Cmp(tip) < 0 { - // Drop the offending transaction - var ( - ids = []uint64{tx.id} - nonces = []uint64{tx.nonce} - ) - p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[i].costCap) - p.stored -= uint64(tx.size) - delete(p.lookup, tx.hash) - txs[i] = nil - - // Drop everything afterwards, no gaps allowed - for j, tx := range txs[i+1:] { - ids = append(ids, tx.id) - nonces = append(nonces, tx.nonce) - - p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], tx.costCap) - p.stored -= uint64(tx.size) - delete(p.lookup, tx.hash) - txs[i+1+j] = nil - } - // Clear out the dropped transactions from the index - if i > 0 { - p.index[addr] = txs[:i] - heap.Fix(p.evict, p.evict.index[addr]) - } else { - delete(p.index, addr) - delete(p.spent, addr) - - heap.Remove(p.evict, p.evict.index[addr]) - p.reserve(addr, false) - } - // Clear out the transactions from the data store - log.Warn("Dropping underpriced blob transaction", "from", addr, "rejected", tx.nonce, "tip", tx.execTipCap, "want", tip, "drop", nonces, "ids", ids) - dropUnderpricedMeter.Mark(int64(len(ids))) - - for _, id := range ids { - if err := p.store.Delete(id); err != nil { - log.Error("Failed to delete dropped transaction", "id", id, "err", err) - } - } - break - } - } - } -} - // SetGasTip implements txpool.SubPool, allowing the blob pool's gas requirements // to be kept in sync with the main transaction pool's gas requirements. func (p *BlobPool) SetGasTip(tip *big.Int) { @@ -1073,20 +1023,59 @@ func (p *BlobPool) SetGasTip(tip *big.Int) { // If the min miner fee increased, remove transactions below the new threshold if old == nil || p.gasTip.Cmp(old) > 0 { - p.flushTransactionsBelowTip(p.gasTip) + for addr, txs := range p.index { + for i, tx := range txs { + if tx.execTipCap.Cmp(p.gasTip) < 0 { + // Drop the offending transaction + var ( + ids = []uint64{tx.id} + nonces = []uint64{tx.nonce} + ) + p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[i].costCap) + p.stored -= uint64(tx.size) + delete(p.lookup, tx.hash) + txs[i] = nil + + // Drop everything afterwards, no gaps allowed + for j, tx := range txs[i+1:] { + ids = append(ids, tx.id) + nonces = append(nonces, tx.nonce) + + p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], tx.costCap) + p.stored -= uint64(tx.size) + delete(p.lookup, tx.hash) + txs[i+1+j] = nil + } + // Clear out the dropped transactions from the index + if i > 0 { + p.index[addr] = txs[:i] + heap.Fix(p.evict, p.evict.index[addr]) + } else { + delete(p.index, addr) + delete(p.spent, addr) + + heap.Remove(p.evict, p.evict.index[addr]) + p.reserve(addr, false) + } + // Clear out the transactions from the data store + log.Warn("Dropping underpriced blob transaction", "from", addr, "rejected", tx.nonce, "tip", tx.execTipCap, "want", tip, "drop", nonces, "ids", ids) + dropUnderpricedMeter.Mark(int64(len(ids))) + + for _, id := range ids { + if err := p.store.Delete(id); err != nil { + log.Error("Failed to delete dropped transaction", "id", id, "err", err) + } + } + break + } + } + } } log.Debug("Blobpool tip threshold updated", "tip", tip) pooltipGauge.Update(tip.Int64()) p.updateStorageMetrics() } -func (p *BlobPool) FlushAllTransactions() { - maxUint256 := uint256.MustFromBig(new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1)) - p.lock.Lock() - defer p.lock.Unlock() - p.flushTransactionsBelowTip(maxUint256) -} - // validateTx checks whether a transaction is valid according to the consensus // rules and adheres to some heuristic limits of the local node (price and size). func (p *BlobPool) validateTx(tx *types.Transaction) error { diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 1ac8086522b0..5506ecc31fc3 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -429,15 +429,6 @@ func (pool *LegacyPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs return pool.txFeed.Subscribe(ch) } -func (pool *LegacyPool) flushTransactionsBelowTip(tip *big.Int) { - // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead - drop := pool.all.RemotesBelowTip(tip) - for _, tx := range drop { - pool.removeTx(tx.Hash(), false, true) - } - pool.priced.Removed(len(drop)) -} - // SetGasTip updates the minimum gas tip required by the transaction pool for a // new transaction, and drops all transactions below this threshold. func (pool *LegacyPool) SetGasTip(tip *big.Int) { @@ -451,18 +442,16 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) { pool.gasTip.Store(newTip) // If the min miner fee increased, remove transactions below the new threshold if newTip.Cmp(old) > 0 { - pool.flushTransactionsBelowTip(tip) + // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead + drop := pool.all.RemotesBelowTip(tip) + for _, tx := range drop { + pool.removeTx(tx.Hash(), false, true) + } + pool.priced.Removed(len(drop)) } log.Info("Legacy pool tip threshold updated", "tip", newTip) } -func (pool *LegacyPool) FlushAllTransactions() { - maxUint256 := new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1) - pool.mu.Lock() - defer pool.mu.Unlock() - pool.flushTransactionsBelowTip(maxUint256) -} - // Nonce returns the next nonce of an account, with all transactions executable // by the pool already applied on top. func (pool *LegacyPool) Nonce(addr common.Address) uint64 { diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index e361eabd4e84..9881ed1b8f96 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -116,9 +116,6 @@ type SubPool interface { // transaction, and drops all transactions below this threshold. SetGasTip(tip *big.Int) - // FlushAllTransactions drops all transactions in the pool. - FlushAllTransactions() - // Has returns an indicator whether subpool has a transaction cached with the // given hash. Has(hash common.Hash) bool diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index f18eb4c6a0d5..be7435247d92 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -104,13 +104,6 @@ func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) { return pool, nil } -// FlushAllTransactions removes all transactions from all subpools -func (p *TxPool) FlushAllTransactions() { - for _, subpool := range p.subpools { - subpool.FlushAllTransactions() - } -} - // reserver is a method to create an address reservation callback to exclusively // assign/deassign addresses to/from subpools. This can ensure that at any point // in time, only a single subpool is able to manage an account, avoiding cross diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index 247d906d0500..dbf561ca4176 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -21,6 +21,7 @@ import ( "crypto/sha256" "errors" "fmt" + "math/big" "sync" "time" @@ -33,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -284,7 +286,12 @@ func (c *SimulatedBeacon) Commit() common.Hash { // Rollback un-sends previously added transactions. func (c *SimulatedBeacon) Rollback() { - c.eth.TxPool().FlushAllTransactions() + // Flush all transactions from the transaction pools + maxUint256 := new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1) + c.eth.TxPool().SetGasTip(maxUint256) + // Set the gas tip back to accept new transactions + // TODO (Marius van der Wijden): set gas tip to parameter passed by config + c.eth.TxPool().SetGasTip(big.NewInt(params.GWei)) } // Fork sets the head to the provided hash. From 269551876e86fb9428501b68a4e79c72d73e1502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 27 Sep 2024 14:09:42 +0300 Subject: [PATCH 562/571] params: release Geth v1.14.10 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 22eabc08f9a1..f3414c218276 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 10 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 10 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 283be238172c8ae3a05f97e2f3c159f5c2319e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 27 Sep 2024 14:13:45 +0300 Subject: [PATCH 563/571] params: begin v1.14.11 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index f3414c218276..1fe2d3459df0 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 10 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 11 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 6b61b54dc7f69cd091dcf3094ce19f26477f55a2 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 30 Sep 2024 10:56:14 +0200 Subject: [PATCH 564/571] p2p/discover: add config option for disabling FINDNODE liveness check (#30512) This is for fixing Prysm integration tests. --- p2p/discover/common.go | 7 ++++--- p2p/discover/table.go | 6 +++--- p2p/discover/v4_udp.go | 3 ++- p2p/discover/v5_udp.go | 3 ++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/p2p/discover/common.go b/p2p/discover/common.go index 0716f7472fce..cabc5c796232 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -53,9 +53,10 @@ type Config struct { Unhandled chan<- ReadPacket // unhandled packets are sent on this channel // Node table configuration: - Bootnodes []*enode.Node // list of bootstrap nodes - PingInterval time.Duration // speed of node liveness check - RefreshInterval time.Duration // used in bucket refresh + Bootnodes []*enode.Node // list of bootstrap nodes + PingInterval time.Duration // speed of node liveness check + RefreshInterval time.Duration // used in bucket refresh + NoFindnodeLivenessCheck bool // turns off validation of table nodes in FINDNODE handler // The options below are useful in very specific cases, like in unit tests. V5ProtocolID *[6]byte diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 8045f1389e86..cbe297254137 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -268,9 +268,9 @@ func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) * return nodes } -// appendLiveNodes adds nodes at the given distance to the result slice. +// appendBucketNodes adds nodes at the given distance to the result slice. // This is used by the FINDNODE/v5 handler. -func (tab *Table) appendLiveNodes(dist uint, result []*enode.Node) []*enode.Node { +func (tab *Table) appendBucketNodes(dist uint, result []*enode.Node, checkLive bool) []*enode.Node { if dist > 256 { return result } @@ -280,7 +280,7 @@ func (tab *Table) appendLiveNodes(dist uint, result []*enode.Node) []*enode.Node tab.mutex.Lock() for _, n := range tab.bucketAtDistance(int(dist)).entries { - if n.isValidatedLive { + if !checkLive || n.isValidatedLive { result = append(result, n.Node) } } diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index cc2a3fb9247e..29ae5f2c084d 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -746,7 +746,8 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from netip.AddrPort, fromID e // Determine closest nodes. target := enode.ID(crypto.Keccak256Hash(req.Target[:])) - closest := t.tab.findnodeByID(target, bucketSize, true).entries + preferLive := !t.tab.cfg.NoFindnodeLivenessCheck + closest := t.tab.findnodeByID(target, bucketSize, preferLive).entries // Send neighbors in chunks with at most maxNeighbors per packet // to stay below the packet size limit. diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 81d94812aab4..4453d1069534 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -862,7 +862,8 @@ func (t *UDPv5) collectTableNodes(rip netip.Addr, distances []uint, limit int) [ } processed[dist] = struct{}{} - for _, n := range t.tab.appendLiveNodes(dist, bn[:0]) { + checkLive := !t.tab.cfg.NoFindnodeLivenessCheck + for _, n := range t.tab.appendBucketNodes(dist, bn[:0], checkLive) { // Apply some pre-checks to avoid sending invalid nodes. // Note liveness is checked by appendLiveNodes. if netutil.CheckRelayAddr(rip, n.IPAddr()) != nil { From 0a21cb4d21a254cc87c7ecc50462f8c2735a302f Mon Sep 17 00:00:00 2001 From: minh-bq <97180373+minh-bq@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:06:10 +0700 Subject: [PATCH 565/571] core/txpool/blobpool: use types.Sender instead of signer.Sender (#30473) Use types.Sender(signer, tx) to utilize the transaction's sender cache and avoid repeated address recover. --- core/txpool/blobpool/blobpool.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 745fc08fec06..82df09a4bfc1 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -478,7 +478,7 @@ func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) error { log.Error("Rejecting duplicate blob pool entry", "id", id, "hash", tx.Hash()) return errors.New("duplicate blob entry") } - sender, err := p.signer.Sender(tx) + sender, err := types.Sender(p.signer, tx) if err != nil { // This path is impossible unless the signature validity changes across // restarts. For that ever improbable case, recover gracefully by ignoring @@ -892,7 +892,7 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]* // and accumulate the transactors and transactions for rem.NumberU64() > add.NumberU64() { for _, tx := range rem.Transactions() { - from, _ := p.signer.Sender(tx) + from, _ := types.Sender(p.signer, tx) discarded[from] = append(discarded[from], tx) transactors[from] = struct{}{} @@ -904,7 +904,7 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]* } for add.NumberU64() > rem.NumberU64() { for _, tx := range add.Transactions() { - from, _ := p.signer.Sender(tx) + from, _ := types.Sender(p.signer, tx) included[from] = append(included[from], tx) inclusions[tx.Hash()] = add.NumberU64() @@ -917,7 +917,7 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]* } for rem.Hash() != add.Hash() { for _, tx := range rem.Transactions() { - from, _ := p.signer.Sender(tx) + from, _ := types.Sender(p.signer, tx) discarded[from] = append(discarded[from], tx) transactors[from] = struct{}{} @@ -927,7 +927,7 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]* return nil, nil } for _, tx := range add.Transactions() { - from, _ := p.signer.Sender(tx) + from, _ := types.Sender(p.signer, tx) included[from] = append(included[from], tx) inclusions[tx.Hash()] = add.NumberU64() @@ -1127,7 +1127,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error { // If the transaction replaces an existing one, ensure that price bumps are // adhered to. var ( - from, _ = p.signer.Sender(tx) // already validated above + from, _ = types.Sender(p.signer, tx) // already validated above next = p.state.GetNonce(from) ) if uint64(len(p.index[from])) > tx.Nonce()-next { From cfe25c7a3b634efba5a5bd69d697f88c3b1d5b2f Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 30 Sep 2024 14:39:53 +0200 Subject: [PATCH 566/571] build: use buildx to build multi-platform docker images (#30530) --- .travis.yml | 22 +------ Dockerfile | 2 +- Dockerfile.alltools | 9 ++- build/ci.go | 153 +++++++------------------------------------- 4 files changed, 35 insertions(+), 151 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3c639d40f971..31c944641f58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,7 @@ jobs: - azure-osx include: - # These builders create the Docker sub-images for multi-arch push and each - # will attempt to push the multi-arch image if they are the last builder + # This builder create and push the Docker images for all architectures - stage: build if: type = push os: linux @@ -26,24 +25,7 @@ jobs: before_install: - export DOCKER_CLI_EXPERIMENTAL=enabled script: - - go run build/ci.go docker -image -manifest amd64,arm64 -upload ethereum/client-go - - - stage: build - if: type = push - os: linux - arch: arm64 - dist: focal - go: 1.23.x - env: - - docker - services: - - docker - git: - submodules: false # avoid cloning ethereum/tests - before_install: - - export DOCKER_CLI_EXPERIMENTAL=enabled - script: - - go run build/ci.go docker -image -manifest amd64,arm64 -upload ethereum/client-go + - go run build/ci.go dockerx -platform "linux/amd64,linux/arm64" -upload ethereum/client-go # This builder does the Linux Azure uploads - stage: build diff --git a/Dockerfile b/Dockerfile index 56c31bad2665..ff89e92f2568 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.23-alpine as builder +FROM golang:1.23-alpine AS builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/Dockerfile.alltools b/Dockerfile.alltools index c7871364ad98..44d5065af011 100644 --- a/Dockerfile.alltools +++ b/Dockerfile.alltools @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.23-alpine as builder +FROM golang:1.23-alpine AS builder RUN apk add --no-cache gcc musl-dev linux-headers git @@ -14,6 +14,13 @@ COPY go.sum /go-ethereum/ RUN cd /go-ethereum && go mod download ADD . /go-ethereum + +# This is not strictly necessary, but it matches the "Dockerfile" steps, thus +# makes it so that under certain circumstances, the docker layer can be cached, +# and the builder can jump to the next (build all) command, with the go cache fully loaded. +# +RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth + RUN cd /go-ethereum && go run build/ci.go install -static # Pull all binaries into a second stage deploy alpine container diff --git a/build/ci.go b/build/ci.go index 2932d2c9ce57..0d3cdd019d84 100644 --- a/build/ci.go +++ b/build/ci.go @@ -50,7 +50,6 @@ import ( "path" "path/filepath" "runtime" - "strconv" "strings" "time" @@ -159,8 +158,8 @@ func main() { doLint(os.Args[2:]) case "archive": doArchive(os.Args[2:]) - case "docker": - doDocker(os.Args[2:]) + case "dockerx": + doDockerBuildx(os.Args[2:]) case "debsrc": doDebianSource(os.Args[2:]) case "nsis": @@ -723,10 +722,9 @@ func maybeSkipArchive(env build.Environment) { } // Builds the docker images and optionally uploads them to Docker Hub. -func doDocker(cmdline []string) { +func doDockerBuildx(cmdline []string) { var ( - image = flag.Bool("image", false, `Whether to build and push an arch specific docker image`) - manifest = flag.String("manifest", "", `Push a multi-arch docker image for the specified architectures (usually "amd64,arm64")`) + platform = flag.String("platform", "", `Push a multi-arch docker image for the specified architectures (usually "linux/amd64,linux/arm64")`) upload = flag.String("upload", "", `Where to upload the docker image (usually "ethereum/client-go")`) ) flag.CommandLine.Parse(cmdline) @@ -761,129 +759,26 @@ func doDocker(cmdline []string) { case strings.HasPrefix(env.Tag, "v1."): tags = []string{"stable", fmt.Sprintf("release-1.%d", params.VersionMinor), "v" + params.Version} } - // If architecture specific image builds are requested, build and push them - if *image { - build.MustRunCommand("docker", "build", "--build-arg", "COMMIT="+env.Commit, "--build-arg", "VERSION="+params.VersionWithMeta, "--build-arg", "BUILDNUM="+env.Buildnum, "--tag", fmt.Sprintf("%s:TAG", *upload), ".") - build.MustRunCommand("docker", "build", "--build-arg", "COMMIT="+env.Commit, "--build-arg", "VERSION="+params.VersionWithMeta, "--build-arg", "BUILDNUM="+env.Buildnum, "--tag", fmt.Sprintf("%s:alltools-TAG", *upload), "-f", "Dockerfile.alltools", ".") - - // Tag and upload the images to Docker Hub - for _, tag := range tags { - gethImage := fmt.Sprintf("%s:%s-%s", *upload, tag, runtime.GOARCH) - toolImage := fmt.Sprintf("%s:alltools-%s-%s", *upload, tag, runtime.GOARCH) - - // If the image already exists (non version tag), check the build - // number to prevent overwriting a newer commit if concurrent builds - // are running. This is still a tiny bit racey if two published are - // done at the same time, but that's extremely unlikely even on the - // master branch. - for _, img := range []string{gethImage, toolImage} { - if exec.Command("docker", "pull", img).Run() != nil { - continue // Generally the only failure is a missing image, which is good - } - buildnum, err := exec.Command("docker", "inspect", "--format", "{{index .Config.Labels \"buildnum\"}}", img).CombinedOutput() - if err != nil { - log.Fatalf("Failed to inspect container: %v\nOutput: %s", err, string(buildnum)) - } - buildnum = bytes.TrimSpace(buildnum) - - if len(buildnum) > 0 && len(env.Buildnum) > 0 { - oldnum, err := strconv.Atoi(string(buildnum)) - if err != nil { - log.Fatalf("Failed to parse old image build number: %v", err) - } - newnum, err := strconv.Atoi(env.Buildnum) - if err != nil { - log.Fatalf("Failed to parse current build number: %v", err) - } - if oldnum > newnum { - log.Fatalf("Current build number %d not newer than existing %d", newnum, oldnum) - } else { - log.Printf("Updating %s from build %d to %d", img, oldnum, newnum) - } - } - } - build.MustRunCommand("docker", "image", "tag", fmt.Sprintf("%s:TAG", *upload), gethImage) - build.MustRunCommand("docker", "image", "tag", fmt.Sprintf("%s:alltools-TAG", *upload), toolImage) - build.MustRunCommand("docker", "push", gethImage) - build.MustRunCommand("docker", "push", toolImage) - } - } - // If multi-arch image manifest push is requested, assemble it - if len(*manifest) != 0 { - // Since different architectures are pushed by different builders, wait - // until all required images are updated. - var mismatch bool - for i := 0; i < 2; i++ { // 2 attempts, second is race check - mismatch = false // hope there's no mismatch now - - for _, tag := range tags { - for _, arch := range strings.Split(*manifest, ",") { - gethImage := fmt.Sprintf("%s:%s-%s", *upload, tag, arch) - toolImage := fmt.Sprintf("%s:alltools-%s-%s", *upload, tag, arch) - - for _, img := range []string{gethImage, toolImage} { - if out, err := exec.Command("docker", "pull", img).CombinedOutput(); err != nil { - log.Printf("Required image %s unavailable: %v\nOutput: %s", img, err, out) - mismatch = true - break - } - buildnum, err := exec.Command("docker", "inspect", "--format", "{{index .Config.Labels \"buildnum\"}}", img).CombinedOutput() - if err != nil { - log.Fatalf("Failed to inspect container: %v\nOutput: %s", err, string(buildnum)) - } - buildnum = bytes.TrimSpace(buildnum) - - if string(buildnum) != env.Buildnum { - log.Printf("Build number mismatch on %s: want %s, have %s", img, env.Buildnum, buildnum) - mismatch = true - break - } - } - if mismatch { - break - } - } - if mismatch { - break - } - } - if mismatch { - // Build numbers mismatching, retry in a short time to - // avoid concurrent fails in both publisher images. If - // however the retry failed too, it means the concurrent - // builder is still crunching, let that do the publish. - if i == 0 { - time.Sleep(30 * time.Second) - } - continue - } - break - } - if mismatch { - log.Println("Relinquishing publish to other builder") - return - } - // Assemble and push the Geth manifest image - for _, tag := range tags { - gethImage := fmt.Sprintf("%s:%s", *upload, tag) - - var gethSubImages []string - for _, arch := range strings.Split(*manifest, ",") { - gethSubImages = append(gethSubImages, gethImage+"-"+arch) - } - build.MustRunCommand("docker", append([]string{"manifest", "create", gethImage}, gethSubImages...)...) - build.MustRunCommand("docker", "manifest", "push", gethImage) - } - // Assemble and push the alltools manifest image - for _, tag := range tags { - toolImage := fmt.Sprintf("%s:alltools-%s", *upload, tag) - - var toolSubImages []string - for _, arch := range strings.Split(*manifest, ",") { - toolSubImages = append(toolSubImages, toolImage+"-"+arch) - } - build.MustRunCommand("docker", append([]string{"manifest", "create", toolImage}, toolSubImages...)...) - build.MustRunCommand("docker", "manifest", "push", toolImage) + // Need to create a mult-arch builder + build.MustRunCommand("docker", "buildx", "create", "--use", "--name", "multi-arch-builder", "--platform", *platform) + + for _, spec := range []struct { + file string + base string + }{ + {file: "Dockerfile", base: fmt.Sprintf("%s:", *upload)}, + {file: "Dockerfile.alltools", base: fmt.Sprintf("%s:alltools-", *upload)}, + } { + for _, tag := range tags { // latest, stable etc + gethImage := fmt.Sprintf("%s%s", spec.base, tag) + build.MustRunCommand("docker", "buildx", "build", + "--build-arg", "COMMIT="+env.Commit, + "--build-arg", "VERSION="+params.VersionWithMeta, + "--build-arg", "BUILDNUM="+env.Buildnum, + "--tag", gethImage, + "--platform", *platform, + "--push", + "--file", spec.file, ".") } } } From e67d5f8c441d5c85cfa69317db8d85794645af14 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 30 Sep 2024 14:46:39 +0200 Subject: [PATCH 567/571] eth/catalyst: use setcanonical instead of sethead in simulated fork (#30465) Fixes https://github.com/ethereum/go-ethereum/issues/30448 --- eth/catalyst/simulated_beacon.go | 3 ++- ethclient/simulated/backend_test.go | 10 +++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index dbf561ca4176..1f3d4f635c0e 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -306,7 +306,8 @@ func (c *SimulatedBeacon) Fork(parentHash common.Hash) error { if parent == nil { return errors.New("parent not found") } - return c.eth.BlockChain().SetHead(parent.NumberU64()) + _, err := c.eth.BlockChain().SetCanonical(parent) + return err } // AdjustTime creates a new block with an adjusted timestamp. diff --git a/ethclient/simulated/backend_test.go b/ethclient/simulated/backend_test.go index 308f5c44c9c1..37f4dbbf7b34 100644 --- a/ethclient/simulated/backend_test.go +++ b/ethclient/simulated/backend_test.go @@ -194,8 +194,8 @@ func TestFork(t *testing.T) { // 2. Send a transaction. // 3. Check that the TX is included in block 1. // 4. Fork by using the parent block as ancestor. -// 5. Mine a block, Re-send the transaction and mine another one. -// 6. Check that the TX is now included in block 2. +// 5. Mine a block. We expect the out-forked tx to have trickled to the pool, and into the new block. +// 6. Check that the TX is now included in (the new) block 1. func TestForkResendTx(t *testing.T) { t.Parallel() testAddr := crypto.PubkeyToAddress(testKey.PublicKey) @@ -231,12 +231,8 @@ func TestForkResendTx(t *testing.T) { // 5. sim.Commit() - if err := client.SendTransaction(ctx, tx); err != nil { - t.Fatalf("sending transaction: %v", err) - } - sim.Commit() receipt, _ = client.TransactionReceipt(ctx, tx.Hash()) - if h := receipt.BlockNumber.Uint64(); h != 2 { + if h := receipt.BlockNumber.Uint64(); h != 1 { t.Errorf("TX included in wrong block: %d", h) } } From db6ae7fa1249b29ad44fd52db751fef572ae43ae Mon Sep 17 00:00:00 2001 From: Ng Wei Han <47109095+weiihann@users.noreply.github.com> Date: Tue, 1 Oct 2024 00:32:39 +0800 Subject: [PATCH 568/571] cmd/geth: remove deprecated lightchaindata db (#30527) This PR removes the dependencies on `lightchaindata` db as the light protocol has been deprecated and removed from the codebase. --- cmd/geth/chaincmd.go | 62 ++++++++++++++++++++------------------------ cmd/utils/flags.go | 2 -- 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 018bca4a0f6f..d85e4a83c8a0 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -221,22 +221,23 @@ func initGenesis(ctx *cli.Context) error { v := ctx.Uint64(utils.OverrideVerkle.Name) overrides.OverrideVerkle = &v } - for _, name := range []string{"chaindata", "lightchaindata"} { - chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.String(utils.AncientFlag.Name), "", false) - if err != nil { - utils.Fatalf("Failed to open database: %v", err) - } - defer chaindb.Close() - triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle()) - defer triedb.Close() + chaindb, err := stack.OpenDatabaseWithFreezer("chaindata", 0, 0, ctx.String(utils.AncientFlag.Name), "", false) + if err != nil { + utils.Fatalf("Failed to open database: %v", err) + } + defer chaindb.Close() + + triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle()) + defer triedb.Close() - _, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) - if err != nil { - utils.Fatalf("Failed to write genesis block: %v", err) - } - log.Info("Successfully wrote genesis state", "database", name, "hash", hash) + _, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) + if err != nil { + utils.Fatalf("Failed to write genesis block: %v", err) } + + log.Info("Successfully wrote genesis state", "database", "chaindata", "hash", hash) + return nil } @@ -258,29 +259,22 @@ func dumpGenesis(ctx *cli.Context) error { // dump whatever already exists in the datadir stack, _ := makeConfigNode(ctx) - for _, name := range []string{"chaindata", "lightchaindata"} { - db, err := stack.OpenDatabase(name, 0, 0, "", true) - if err != nil { - if !os.IsNotExist(err) { - return err - } - continue - } - genesis, err := core.ReadGenesis(db) - if err != nil { - utils.Fatalf("failed to read genesis: %s", err) - } - db.Close() - if err := json.NewEncoder(os.Stdout).Encode(*genesis); err != nil { - utils.Fatalf("could not encode stored genesis: %s", err) - } - return nil + db, err := stack.OpenDatabase("chaindata", 0, 0, "", true) + if err != nil { + return err } - if ctx.IsSet(utils.DataDirFlag.Name) { - utils.Fatalf("no existing datadir at %s", stack.Config().DataDir) + defer db.Close() + + genesis, err = core.ReadGenesis(db) + if err != nil { + utils.Fatalf("failed to read genesis: %s", err) } - utils.Fatalf("no network preset provided, and no genesis exists in the default datadir") + + if err := json.NewEncoder(os.Stdout).Encode(*genesis); err != nil { + utils.Fatalf("could not encode stored genesis: %s", err) + } + return nil } @@ -557,7 +551,7 @@ func parseDumpConfig(ctx *cli.Context, db ethdb.Database) (*state.DumpConfig, co default: return nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg) } - var conf = &state.DumpConfig{ + conf := &state.DumpConfig{ SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name), SkipStorage: ctx.Bool(utils.ExcludeStorageFlag.Name), OnlyWithAddresses: !ctx.Bool(utils.IncludeIncompletesFlag.Name), diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index da2814855a66..a8f7a812bb28 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2061,8 +2061,6 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. break } chainDb = remotedb.New(client) - case ctx.String(SyncModeFlag.Name) == "light": - chainDb, err = stack.OpenDatabase("lightchaindata", cache, handles, "", readonly) default: chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "", readonly) } From 40fd887df6812033f96941181549693d2cd5444d Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:36:56 +0200 Subject: [PATCH 569/571] internal/ethapi: remove td field from block (#30386) implement https://github.com/ethereum/execution-apis/pull/570 --- cmd/utils/flags.go | 4 +-- .../testdata/call_tracer/blob_tx.json | 1 - .../testdata/call_tracer/create.json | 3 +- .../testdata/call_tracer/deep_calls.json | 3 +- .../testdata/call_tracer/delegatecall.json | 3 +- .../inner_create_oog_outer_throw.json | 3 +- .../testdata/call_tracer/inner_instafail.json | 1 - .../call_tracer/inner_revert_reason.json | 1 - .../call_tracer/inner_throw_outer_revert.json | 3 +- .../tracetest/testdata/call_tracer/oog.json | 3 +- .../testdata/call_tracer/revert.json | 3 +- .../testdata/call_tracer/revert_reason.json | 3 +- .../testdata/call_tracer/selfdestruct.json | 3 +- .../testdata/call_tracer/simple.json | 3 +- .../testdata/call_tracer/simple_onlytop.json | 3 +- .../tracetest/testdata/call_tracer/throw.json | 3 +- .../testdata/call_tracer_flat/big_slow.json | 1 - .../callcode_precompiled_fail_hide.json | 1 - .../callcode_precompiled_oog.json | 1 - .../callcode_precompiled_throw.json | 1 - .../testdata/call_tracer_flat/create.json | 3 +- .../testdata/call_tracer_flat/deep_calls.json | 3 +- .../call_tracer_flat/delegatecall.json | 3 +- .../delegatecall_parent_value.json | 1 - .../testdata/call_tracer_flat/gas.json | 1 - .../call_tracer_flat/include_precompiled.json | 1 - .../inner_create_oog_outer_throw.json | 3 +- .../call_tracer_flat/inner_instafail.json | 1 - .../inner_precompiled_wrong_gas.json | 1 - .../inner_throw_outer_revert.json | 3 +- .../call_tracer_flat/nested_create.json | 1 - .../nested_create2_action_gas.json | 1 - .../nested_create_action_gas.json | 1 - .../nested_create_inerror.json | 1 - .../nested_pointer_issue.json | 1 - .../testdata/call_tracer_flat/oog.json | 3 +- .../option_convert_parity_errors.json | 3 +- .../call_tracer_flat/result_output.json | 1 - .../testdata/call_tracer_flat/revert.json | 3 +- .../call_tracer_flat/revert_reason.json | 3 +- .../call_tracer_flat/selfdestruct.json | 1 - .../testdata/call_tracer_flat/simple.json | 3 +- .../call_tracer_flat/simple_onlytop.json | 3 +- .../skip_no_balance_error.json | 1 - .../staticcall_precompiled.json | 1 - .../testdata/call_tracer_flat/suicide.json | 1 - .../testdata/call_tracer_flat/throw.json | 3 +- .../testdata/call_tracer_legacy/create.json | 3 +- .../call_tracer_legacy/deep_calls.json | 3 +- .../call_tracer_legacy/delegatecall.json | 3 +- .../inner_create_oog_outer_throw.json | 3 +- .../call_tracer_legacy/inner_instafail.json | 1 - .../inner_throw_outer_revert.json | 3 +- .../testdata/call_tracer_legacy/oog.json | 3 +- .../testdata/call_tracer_legacy/revert.json | 3 +- .../call_tracer_legacy/revert_reason.json | 3 +- .../call_tracer_legacy/selfdestruct.json | 3 +- .../testdata/call_tracer_legacy/simple.json | 3 +- .../testdata/call_tracer_legacy/throw.json | 3 +- .../call_tracer_withLog/calldata.json | 1 - .../call_tracer_withLog/delegatecall.json | 1 - .../frontier_create_outofstorage.json | 1 - .../call_tracer_withLog/multi_contracts.json | 1 - .../call_tracer_withLog/multilogs.json | 1 - .../testdata/call_tracer_withLog/notopic.json | 1 - .../testdata/call_tracer_withLog/simple.json | 1 - .../call_tracer_withLog/tx_failed.json | 1 - .../tx_partial_failed.json | 1 - .../call_tracer_withLog/with_onlyTopCall.json | 1 - .../testdata/prestate_tracer/blob_tx.json | 1 - .../prestate_tracer/create_create.json | 1 - .../create_existing_contract.json | 1 - .../prestate_tracer/create_post_eip158.json | 1 - .../testdata/prestate_tracer/simple.json | 3 +- .../prestate_tracer_legacy/simple.json | 3 +- .../create.json | 1 - .../create_post_eip158.json | 1 - .../create_suicide.json | 1 - .../inner_create.json | 1 - .../simple.json | 3 +- .../suicide.json | 1 - graphql/graphql.go | 12 ------- graphql/graphql_test.go | 4 +-- graphql/schema.go | 3 -- internal/ethapi/api.go | 34 +++++-------------- internal/ethapi/backend.go | 1 - internal/ethapi/simulate.go | 3 -- .../testdata/eth_getBlockByHash-hash-1.json | 1 - .../eth_getBlockByHash-hash-genesis.json | 1 - ...h_getBlockByHash-hash-latest-1-fullTx.json | 1 - .../eth_getBlockByHash-hash-latest.json | 1 - .../eth_getBlockByNumber-number-0.json | 1 - .../eth_getBlockByNumber-number-1.json | 1 - .../eth_getBlockByNumber-number-latest-1.json | 1 - .../eth_getBlockByNumber-tag-latest.json | 1 - ...h_getBlockByNumber-tag-pending-fullTx.json | 1 - .../eth_getBlockByNumber-tag-pending.json | 1 - .../testdata/eth_getHeaderByHash-hash-0.json | 1 - .../testdata/eth_getHeaderByHash-hash-1.json | 1 - .../eth_getHeaderByHash-hash-latest-1.json | 1 - .../eth_getHeaderByHash-hash-latest.json | 1 - .../eth_getHeaderByNumber-number-0.json | 1 - .../eth_getHeaderByNumber-number-1.json | 1 - ...eth_getHeaderByNumber-number-latest-1.json | 1 - .../eth_getHeaderByNumber-tag-latest.json | 1 - .../eth_getHeaderByNumber-tag-pending.json | 1 - internal/jsre/deps/web3.js | 1 - 107 files changed, 50 insertions(+), 187 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index a8f7a812bb28..6db88ff66183 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1925,7 +1925,7 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) { // RegisterEthService adds an Ethereum client to the stack. // The second return value is the full node instance. -func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend, *eth.Ethereum) { +func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (*eth.EthAPIBackend, *eth.Ethereum) { backend, err := eth.New(stack, cfg) if err != nil { Fatalf("Failed to register the Ethereum service: %v", err) @@ -1935,7 +1935,7 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend } // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to the node. -func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) { +func RegisterEthStatsService(stack *node.Node, backend *eth.EthAPIBackend, url string) { if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil { Fatalf("Failed to register the Ethereum Stats service: %v", err) } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json index 549acb1fe6a6..b974151c1b36 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json @@ -14,7 +14,6 @@ "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "stateRoot": "0x577f42ab21ccfd946511c57869ace0bdf7c217c36f02b7cd3459df0ed1cffc1a", "timestamp": "1709626771", - "totalDifficulty": "1", "withdrawals": [], "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "alloc": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer/create.json index df0b2872b48b..621a6a97a41e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/create.json @@ -41,8 +41,7 @@ "nonce": "0x93363bbd2c95f410", "number": "2294701", "stateRoot": "0x6b6737d5bde8058990483e915866bd1578014baeff57bd5e4ed228a2bfad635c", - "timestamp": "1513676127", - "totalDifficulty": "7160808139332585" + "timestamp": "1513676127" }, "input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json index 975616064af9..0b38caec2cee 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json @@ -104,8 +104,7 @@ "nonce": "0x38dee147326a8d40", "number": "25000", "stateRoot": "0xc5d6bbcd46236fcdcc80b332ffaaa5476b980b01608f9708408cfef01b58bd5b", - "timestamp": "1479891517", - "totalDifficulty": "1895410389427" + "timestamp": "1479891517" }, "input": "0xf88b8206628504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb80000000000000000000000000000000000000000000000280faf689c35ac00002aa0a7ee5b7877811bf671d121b40569462e722657044808dc1d6c4f1e4233ec145ba0417e7543d52b65738d9df419cbe40a708424f4d54b0fc145c0a64545a2bb1065", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json index 6a2cda7dc989..4dd96e2f790d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json @@ -57,8 +57,7 @@ "nonce": "0x684129f283aaef18", "number": "11494", "stateRoot": "0x7057f31fe3dab1d620771adad35224aae43eb70e94861208bc84c557ff5b9d10", - "timestamp": "1479735912", - "totalDifficulty": "90744064339" + "timestamp": "1479735912" }, "input": "0xf889448504a817c800832dc6c094269296dddce321a6bcbaa2f0181127593d732cba80a47065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e29a080ed81e4c5e9971a730efab4885566e2c868cd80bd4166d0ed8c287fdf181650a069d7c49215e3d4416ad239cd09dbb71b9f04c16b33b385d14f40b618a7a65115", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json index bb16a4a4303a..8b3b1e3d93c9 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json @@ -49,8 +49,7 @@ "nonce": "0x28c446f1cb9748c1", "number": "2290743", "stateRoot": "0x4898aceede76739daef76448a367d10015a2c022c9e7909b99a10fbf6fb16708", - "timestamp": "1513616414", - "totalDifficulty": "7146523769022564" + "timestamp": "1513616414" }, "input": "0xf8aa0e8509502f9000830493e0941d3ddf7caf024f253487e18bc4a15b1a360c170a80b8443b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e829a0524564944fa419f5c189b5074044f89210c6d6b2d77ee8f7f12a927d59b636dfa0015b28986807a424b18b186ee6642d76739df36cad802d20e8c00e79a61d7281", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json index ed3688a942e1..e69df9d1f9fa 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json @@ -10,7 +10,6 @@ "number": "24973", "stateRoot": "0x532a5c3f75453a696428db078e32ae283c85cb97e4d8560dbdf022adac6df369", "timestamp": "1479891145", - "totalDifficulty": "1892250259406", "alloc": { "0x6c06b16512b332e6cd8293a2974872674716ce18": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json index 0108c93ae020..09ff53d1043c 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json @@ -11,7 +11,6 @@ "number": "0", "stateRoot": "0xa775801d572e9b79585eb131d18d79f8a0f71895455ab9a5b656911428e11708", "timestamp": "0", - "totalDifficulty": "1", "alloc": { "0x3623191d4ccfbbdf09e8ebf6382a1f8257417bc1": { "balance": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json index a023ed6d9bd7..17442f15b91b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json @@ -52,8 +52,7 @@ "nonce": "0x810f923ff4b450a1", "number": "2295103", "stateRoot": "0xff403612573d76dfdaf4fea2429b77dbe9764021ae0e38dc8ac79a3cf551179e", - "timestamp": "1513681246", - "totalDifficulty": "7162347056825919" + "timestamp": "1513681246" }, "input": "0xf86d808504e3b292008307dfa69433056b5dcac09a9b4becad0e1dcf92c19bd0af76880e92596fd62900008029a0e5f27bb66431f7081bb7f1f242003056d7f3f35414c352cd3d1848b52716dac2a07d0be78980edb0bd2a0678fc53aa90ea9558ce346b0d947967216918ac74ccea", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json index 333bdd038cf5..e28958a69e92 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json @@ -43,8 +43,7 @@ "nonce": "0xd1bdb150f6fd170e", "number": "2294630", "stateRoot": "0x1ab1a534e84cc787cda1db21e0d5920ab06017948075b759166cfea7274657a1", - "timestamp": "1513675347", - "totalDifficulty": "7160543502214733" + "timestamp": "1513675347" }, "input": "0xf8ab820109855d21dba00082ca1d9443064693d3d38ad6a7cb579e0d6d9718c8aa6b6280b844a9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f90001ba0ce3ad83f5530136467b7c2bb225f406bd170f4ad59c254e5103c34eeabb5bd69a0455154527224a42ab405cacf0fe92918a75641ce4152f8db292019a5527aa956", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json index 3207a298a98b..f69bb72e0aa1 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json @@ -41,8 +41,7 @@ "nonce": "0xbc5d43adc2c30c7d", "number": "2294500", "stateRoot": "0xca645b335888352ef9d8b1ef083e9019648180b259026572e3139717270de97d", - "timestamp": "1513673552", - "totalDifficulty": "7160066586979149" + "timestamp": "1513673552" }, "input": "0xf9018b0a8505d21dba00832dc6c094abbcd5b340c80b5f1c0545c04c987b87310296ae80b9012473b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988000000000000000000000000000000000000000000000000000000000000000000000000000000001ba0fd659d76a4edbd2a823e324c93f78ad6803b30ff4a9c8bce71ba82798975c70ca06571eecc0b765688ec6c78942c5ee8b585e00988c0141b518287e9be919bc48a", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json index f02e5c686322..add992f5aa7b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json @@ -46,8 +46,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf888068449504f80832dc6c094f58833cf0c791881b494eb79d461e08a1f043f5280a45c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf12da0264664db3e71fae1dbdaf2f53954be149ad3b7ba8a5054b4d89c70febfacc8b1a0212e8398757963f419681839ae8c5a54b411e252473c82d93dda68405ca63294", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json index 620df1d6149d..73960ea60772 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json @@ -47,8 +47,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json index 6c7d01de1fc6..b923b903bfff 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json @@ -52,8 +52,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json index affb4ab033ab..d1aa2a58b49f 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json @@ -52,8 +52,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "tracerConfig": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json index 499b449a6ece..d439d2b284e6 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json @@ -45,8 +45,7 @@ "nonce": "0x70849d5838dee2e9", "number": "25008", "stateRoot": "0x1e01d2161794768c5b917069e73d86e8dca80cd7f3168c0597de420ab93a3b7b", - "timestamp": "1479891641", - "totalDifficulty": "1896347038589" + "timestamp": "1479891641" }, "input": "0xf88b8206668504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb8000000000000000000000000000000000000000000000027fad02094277c000029a0692a3b4e7b2842f8dd7832e712c21e09f451f416c8976d5b8d02e8c0c2b4bea9a07645e90fc421b63dd755767fd93d3c03b4ec0c4d8fafa059558d08cf11d59750", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json index 617f52a14e8a..26495dfbce42 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json @@ -10,7 +10,6 @@ "number": "1719576", "stateRoot": "0xab5eec2177a92d633e282936af66c46e24cfa8f2fdc2b8155f33885f483d06f3", "timestamp": "1466150166", - "totalDifficulty": "28295412423546970038", "alloc": { "0xf8bda96b67036ee48107f2a0695ea673479dda56": { "balance": "0x1529e844f9ecdeec", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json index a2386ea9c713..72a4db69012e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json @@ -10,7 +10,6 @@ "number": "1555278", "stateRoot": "0x5f56d8323ee384b0c8d1de49d63e150e17283eea813483698362bc0ec9e0242a", "timestamp": "1590795319", - "totalDifficulty": "2242614315030", "alloc": { "0x0000000000000000000000000000000000000004": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json index fb29e49660d5..0c4d29dd5b52 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json @@ -10,7 +10,6 @@ "number": "1555277", "stateRoot": "0x6290d79215a2eebc25d5e456b35876c6d78ffc1ea47bdd70e375ebb3cf325620", "timestamp": "1590795308", - "totalDifficulty": "2242609643446", "alloc": { "0x0000000000000000000000000000000000000001": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json index 5e2726155445..5538a708ea20 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json @@ -10,7 +10,6 @@ "number": "1555274", "stateRoot": "0x795751f3f96a5de1fd3944ddd78cbfe4ef10491e1086be47609869a30929d0e5", "timestamp": "1590795228", - "totalDifficulty": "2242595605834", "alloc": { "0x0000000000000000000000000000000000000009": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json index 11bc4eae022b..83d20fb07873 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json @@ -41,8 +41,7 @@ "nonce": "0x93363bbd2c95f410", "number": "2294701", "stateRoot": "0x6b6737d5bde8058990483e915866bd1578014baeff57bd5e4ed228a2bfad635c", - "timestamp": "1513676127", - "totalDifficulty": "7160808139332585" + "timestamp": "1513676127" }, "input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json index 375a16361413..12754e9da97d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json @@ -104,8 +104,7 @@ "nonce": "0x38dee147326a8d40", "number": "25000", "stateRoot": "0xc5d6bbcd46236fcdcc80b332ffaaa5476b980b01608f9708408cfef01b58bd5b", - "timestamp": "1479891517", - "totalDifficulty": "1895410389427" + "timestamp": "1479891517" }, "input": "0xf88b8206628504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb80000000000000000000000000000000000000000000000280faf689c35ac00002aa0a7ee5b7877811bf671d121b40569462e722657044808dc1d6c4f1e4233ec145ba0417e7543d52b65738d9df419cbe40a708424f4d54b0fc145c0a64545a2bb1065", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json index e5a37cbfdd27..08ba48f1235f 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json @@ -57,8 +57,7 @@ "nonce": "0x684129f283aaef18", "number": "11494", "stateRoot": "0x7057f31fe3dab1d620771adad35224aae43eb70e94861208bc84c557ff5b9d10", - "timestamp": "1479735912", - "totalDifficulty": "90744064339" + "timestamp": "1479735912" }, "input": "0xf889448504a817c800832dc6c094269296dddce321a6bcbaa2f0181127593d732cba80a47065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e29a080ed81e4c5e9971a730efab4885566e2c868cd80bd4166d0ed8c287fdf181650a069d7c49215e3d4416ad239cd09dbb71b9f04c16b33b385d14f40b618a7a65115", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json index 177912420aae..c8d66ef2d599 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json @@ -7,7 +7,6 @@ "stateRoot": "0xfc01993ad96a8fb8790a093cea4f505f8db1b0e1143c5f57bb1d173db0baa9e3", "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "difficulty": "1926740", - "totalDifficulty": "482216286599", "extraData": "0xd883010906846765746888676f312e31332e35856c696e7578", "gasLimit": "19388354", "timestamp": "1577558314", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json index d977dbe30d13..250c4028083e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json @@ -10,7 +10,6 @@ "number": "1555274", "stateRoot": "0x795751f3f96a5de1fd3944ddd78cbfe4ef10491e1086be47609869a30929d0e5", "timestamp": "1590795228", - "totalDifficulty": "2242595605834", "alloc": { "0x0000000000000000000000000000000000000001": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json index 0f28c07a9be2..8da637a9e0e6 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json @@ -7,7 +7,6 @@ "stateRoot": "0x68418fb5cf4afa9b807dc079e8cdde0e148ac2c8afb378e675465b5bed1fbd02", "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "difficulty": "1813945", - "totalDifficulty": "469107641961", "extraData": "0xd883010906846765746888676f312e31332e35856c696e7578", "gasLimit": "6321166", "timestamp": "1577471202", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json index 6c4ce18063ea..3747d7f0f8f5 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json @@ -49,8 +49,7 @@ "nonce": "0x28c446f1cb9748c1", "number": "2290743", "stateRoot": "0x4898aceede76739daef76448a367d10015a2c022c9e7909b99a10fbf6fb16708", - "timestamp": "1513616414", - "totalDifficulty": "7146523769022564" + "timestamp": "1513616414" }, "input": "0xf8aa0e8509502f9000830493e0941d3ddf7caf024f253487e18bc4a15b1a360c170a80b8443b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e829a0524564944fa419f5c189b5074044f89210c6d6b2d77ee8f7f12a927d59b636dfa0015b28986807a424b18b186ee6642d76739df36cad802d20e8c00e79a61d7281", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json index 611e50e2c046..1cea8175b3e6 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json @@ -10,7 +10,6 @@ "number": "24973", "stateRoot": "0x532a5c3f75453a696428db078e32ae283c85cb97e4d8560dbdf022adac6df369", "timestamp": "1479891145", - "totalDifficulty": "1892250259406", "alloc": { "0x6c06b16512b332e6cd8293a2974872674716ce18": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json index 70442fdb9ab7..a8c11e83512c 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json @@ -7,7 +7,6 @@ "stateRoot": "0x68418fb5cf4afa9b807dc079e8cdde0e148ac2c8afb378e675465b5bed1fbd02", "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "difficulty": "1813945", - "totalDifficulty": "469107641961", "extraData": "0xd883010906846765746888676f312e31332e35856c696e7578", "gasLimit": "6321166", "timestamp": "1577471202", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json index bc9470871801..5473ef6343c7 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json @@ -52,8 +52,7 @@ "nonce": "0x810f923ff4b450a1", "number": "2295103", "stateRoot": "0xff403612573d76dfdaf4fea2429b77dbe9764021ae0e38dc8ac79a3cf551179e", - "timestamp": "1513681246", - "totalDifficulty": "7162347056825919" + "timestamp": "1513681246" }, "input": "0xf86d808504e3b292008307dfa69433056b5dcac09a9b4becad0e1dcf92c19bd0af76880e92596fd62900008029a0e5f27bb66431f7081bb7f1f242003056d7f3f35414c352cd3d1848b52716dac2a07d0be78980edb0bd2a0678fc53aa90ea9558ce346b0d947967216918ac74ccea", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json index 3fcc61fc806f..7dc6cc80985d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json @@ -10,7 +10,6 @@ "number": "555461", "stateRoot": "0xba8272acd0dfeb5f04376328e8bfc5b276b177697000c204a060f6f7b629ae32", "timestamp": "1577423350", - "totalDifficulty": "462222992438", "alloc": { "0xcf5b3467dfa45cdc8e5358a7a1ba4deb02e5faed": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json index 0eaa3f867ab3..82692d181ad3 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json @@ -10,7 +10,6 @@ "number": "1555160", "stateRoot": "0x95067c12148e2362fcd4a89df286ff0b1739ef097a40ca42ae7f698af9a9d913", "timestamp": "1590793999", - "totalDifficulty": "2242063623471", "alloc": { "0x8785e369f0ef0a4e5c5a5f929680427dc75273a5": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json index a00ea7a93b89..d9595a721028 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json @@ -10,7 +10,6 @@ "number": "1555169", "stateRoot": "0xc4b9703de3e59ff795baae2c3afa010cf039c37244a7a6af7f3f491a10601348", "timestamp": "1590794111", - "totalDifficulty": "2242105342155", "alloc": { "0x5ac5599fc9df172c89ee7ec55ad9104ccbfed40d": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json index f3a7d9a94610..cb4954d9b7f7 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json @@ -10,7 +10,6 @@ "number": "839246", "stateRoot": "0x4bb3b02ec70b837651233957fb61a6ea3fc6a4244c1f55df7a713c154829ec0a", "timestamp": "1581179375", - "totalDifficulty": "1023985623933", "alloc": { "0x76554b33410b6d90b7dc889bfed0451ad195f27e": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json index c3191d61bc4e..89f642db20bf 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json @@ -7,7 +7,6 @@ "stateRoot": "0x7f54db248a004ca182fe87fdfa6efda97163908b4f0cc84b36a6d60699d5d1be", "miner": "0x0000000000000000000000000000000000000000", "difficulty": "1", - "totalDifficulty": "24766", "extraData": "0xf09f928e20407072796c616273206e6f64652d3020f09f928e000000000000001d32ac3baf238e163e18ed6d77b67b0b54b08ad9781dc4ffd93c5ede1ca12c5f21b36ac39c7ebb88dff65da91f5b9461f19873a02602230b931ba388a809119f00", "gasLimit": "8000000", "timestamp": "1549153003", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json index bd6059faefa1..ea02454d3bf8 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json @@ -43,8 +43,7 @@ "nonce": "0xd1bdb150f6fd170e", "number": "2294630", "stateRoot": "0x1ab1a534e84cc787cda1db21e0d5920ab06017948075b759166cfea7274657a1", - "timestamp": "1513675347", - "totalDifficulty": "7160543502214733" + "timestamp": "1513675347" }, "input": "0xf8ab820109855d21dba00082ca1d9443064693d3d38ad6a7cb579e0d6d9718c8aa6b6280b844a9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f90001ba0ce3ad83f5530136467b7c2bb225f406bd170f4ad59c254e5103c34eeabb5bd69a0455154527224a42ab405cacf0fe92918a75641ce4152f8db292019a5527aa956", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json index 8888d3e68a82..e914ca52b69d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json @@ -43,8 +43,7 @@ "nonce": "0xd1bdb150f6fd170e", "number": "2294630", "stateRoot": "0x1ab1a534e84cc787cda1db21e0d5920ab06017948075b759166cfea7274657a1", - "timestamp": "1513675347", - "totalDifficulty": "7160543502214733" + "timestamp": "1513675347" }, "tracerConfig": { "convertParityErrors": true diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json index 62baf333b6e3..f6215a2b3fcf 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json @@ -10,7 +10,6 @@ "number": "553415", "stateRoot": "0x8f89e79109c19fa00e72b400502448540dc4773ad92dddd341dbba20c710a3b5", "timestamp": "1577396195", - "totalDifficulty": "458361299240", "alloc": { "0x531f76bad925f6a925474996c7d738c1008045f6": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json index b0346d860399..75ca39feee07 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json @@ -41,8 +41,7 @@ "nonce": "0xbc5d43adc2c30c7d", "number": "2294500", "stateRoot": "0xca645b335888352ef9d8b1ef083e9019648180b259026572e3139717270de97d", - "timestamp": "1513673552", - "totalDifficulty": "7160066586979149" + "timestamp": "1513673552" }, "input": "0xf9018b0a8505d21dba00832dc6c094abbcd5b340c80b5f1c0545c04c987b87310296ae80b9012473b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988000000000000000000000000000000000000000000000000000000000000000000000000000000001ba0fd659d76a4edbd2a823e324c93f78ad6803b30ff4a9c8bce71ba82798975c70ca06571eecc0b765688ec6c78942c5ee8b585e00988c0141b518287e9be919bc48a", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json index 6759b05e5206..8e5c7cd28ee5 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json @@ -46,8 +46,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf888068449504f80832dc6c094f58833cf0c791881b494eb79d461e08a1f043f5280a45c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf12da0264664db3e71fae1dbdaf2f53954be149ad3b7ba8a5054b4d89c70febfacc8b1a0212e8398757963f419681839ae8c5a54b411e252473c82d93dda68405ca63294", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json index 3c5d6d9f2b07..c8c6dc65c149 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json @@ -10,7 +10,6 @@ "number": "1555145", "stateRoot": "0x565873b05f71b98595133e37a52d79c3476ce820c05ebedaddd35541b0e894a3", "timestamp": "1590793819", - "totalDifficulty": "2241994078605", "alloc": { "0x119f569a45e9d0089d51d7f9529f5ea9bf5785e2": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json index a7244e97470e..1a9ddb8c7afe 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json @@ -52,8 +52,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple_onlytop.json index 5fbdf55d2227..b2b462c34b23 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple_onlytop.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple_onlytop.json @@ -52,8 +52,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "tracerConfig": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json index 6911ed4b32af..a25f2383d65c 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json @@ -10,7 +10,6 @@ "number": "1555284", "stateRoot": "0x9fe125b361b72d5479b24ad9be9964b74228c73a2dfb0065060a79b4a6dfaa1e", "timestamp": "1590795374", - "totalDifficulty": "2242642335405", "alloc": { "0xe85df1413eebe1b191c26260e19783a274a6b041": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json index 45ffbe2db975..e3ac8b8300e5 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json @@ -10,7 +10,6 @@ "number": "567687", "stateRoot": "0x7b4b193fe73ef87101c7c325954681861cc240c299d03459784b2b11c9c522ae", "timestamp": "1577578008", - "totalDifficulty": "485254950048", "alloc": { "0x8521f13dd5e4bc3dab3cf0f01a195a5af899e851": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json index 16d43767d552..f75953693451 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json @@ -7,7 +7,6 @@ "stateRoot": "0x40b5f53d610108947688a04fb68838ff9c0aa0dd6e54156b682537192171ff5c", "miner": "0x774c398d763161f55b66a646f17edda4addad2ca", "difficulty": "1928226", - "totalDifficulty": "457857582215", "extraData": "0xd983010907846765746888676f312e31332e358664617277696e", "gasLimit": "7999473", "timestamp": "1577392669", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json index a001178a42c7..52e1299eb131 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json @@ -45,8 +45,7 @@ "nonce": "0x70849d5838dee2e9", "number": "25008", "stateRoot": "0x1e01d2161794768c5b917069e73d86e8dca80cd7f3168c0597de420ab93a3b7b", - "timestamp": "1479891641", - "totalDifficulty": "1896347038589" + "timestamp": "1479891641" }, "input": "0xf88b8206668504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb8000000000000000000000000000000000000000000000027fad02094277c000029a0692a3b4e7b2842f8dd7832e712c21e09f451f416c8976d5b8d02e8c0c2b4bea9a07645e90fc421b63dd755767fd93d3c03b4ec0c4d8fafa059558d08cf11d59750", "result": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json index df0b2872b48b..621a6a97a41e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json @@ -41,8 +41,7 @@ "nonce": "0x93363bbd2c95f410", "number": "2294701", "stateRoot": "0x6b6737d5bde8058990483e915866bd1578014baeff57bd5e4ed228a2bfad635c", - "timestamp": "1513676127", - "totalDifficulty": "7160808139332585" + "timestamp": "1513676127" }, "input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json index 80fc0b0ada68..82980679d4ae 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json @@ -104,8 +104,7 @@ "nonce": "0x38dee147326a8d40", "number": "25000", "stateRoot": "0xc5d6bbcd46236fcdcc80b332ffaaa5476b980b01608f9708408cfef01b58bd5b", - "timestamp": "1479891517", - "totalDifficulty": "1895410389427" + "timestamp": "1479891517" }, "input": "0xf88b8206628504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb80000000000000000000000000000000000000000000000280faf689c35ac00002aa0a7ee5b7877811bf671d121b40569462e722657044808dc1d6c4f1e4233ec145ba0417e7543d52b65738d9df419cbe40a708424f4d54b0fc145c0a64545a2bb1065", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json index 2cd28bacc4b0..4fa866df1849 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json @@ -57,8 +57,7 @@ "nonce": "0x684129f283aaef18", "number": "11494", "stateRoot": "0x7057f31fe3dab1d620771adad35224aae43eb70e94861208bc84c557ff5b9d10", - "timestamp": "1479735912", - "totalDifficulty": "90744064339" + "timestamp": "1479735912" }, "input": "0xf889448504a817c800832dc6c094269296dddce321a6bcbaa2f0181127593d732cba80a47065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e29a080ed81e4c5e9971a730efab4885566e2c868cd80bd4166d0ed8c287fdf181650a069d7c49215e3d4416ad239cd09dbb71b9f04c16b33b385d14f40b618a7a65115", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json index 07fda21d4b35..b83b7436326e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json @@ -49,8 +49,7 @@ "nonce": "0x28c446f1cb9748c1", "number": "2290743", "stateRoot": "0x4898aceede76739daef76448a367d10015a2c022c9e7909b99a10fbf6fb16708", - "timestamp": "1513616414", - "totalDifficulty": "7146523769022564" + "timestamp": "1513616414" }, "input": "0xf8aa0e8509502f9000830493e0941d3ddf7caf024f253487e18bc4a15b1a360c170a80b8443b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e829a0524564944fa419f5c189b5074044f89210c6d6b2d77ee8f7f12a927d59b636dfa0015b28986807a424b18b186ee6642d76739df36cad802d20e8c00e79a61d7281", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json index 16e413623048..ff305588740b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json @@ -10,7 +10,6 @@ "number": "24973", "stateRoot": "0x532a5c3f75453a696428db078e32ae283c85cb97e4d8560dbdf022adac6df369", "timestamp": "1479891145", - "totalDifficulty": "1892250259406", "alloc": { "0x6c06b16512b332e6cd8293a2974872674716ce18": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json index a023ed6d9bd7..17442f15b91b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json @@ -52,8 +52,7 @@ "nonce": "0x810f923ff4b450a1", "number": "2295103", "stateRoot": "0xff403612573d76dfdaf4fea2429b77dbe9764021ae0e38dc8ac79a3cf551179e", - "timestamp": "1513681246", - "totalDifficulty": "7162347056825919" + "timestamp": "1513681246" }, "input": "0xf86d808504e3b292008307dfa69433056b5dcac09a9b4becad0e1dcf92c19bd0af76880e92596fd62900008029a0e5f27bb66431f7081bb7f1f242003056d7f3f35414c352cd3d1848b52716dac2a07d0be78980edb0bd2a0678fc53aa90ea9558ce346b0d947967216918ac74ccea", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json index 333bdd038cf5..e28958a69e92 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json @@ -43,8 +43,7 @@ "nonce": "0xd1bdb150f6fd170e", "number": "2294630", "stateRoot": "0x1ab1a534e84cc787cda1db21e0d5920ab06017948075b759166cfea7274657a1", - "timestamp": "1513675347", - "totalDifficulty": "7160543502214733" + "timestamp": "1513675347" }, "input": "0xf8ab820109855d21dba00082ca1d9443064693d3d38ad6a7cb579e0d6d9718c8aa6b6280b844a9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f90001ba0ce3ad83f5530136467b7c2bb225f406bd170f4ad59c254e5103c34eeabb5bd69a0455154527224a42ab405cacf0fe92918a75641ce4152f8db292019a5527aa956", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json index 3207a298a98b..f69bb72e0aa1 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json @@ -41,8 +41,7 @@ "nonce": "0xbc5d43adc2c30c7d", "number": "2294500", "stateRoot": "0xca645b335888352ef9d8b1ef083e9019648180b259026572e3139717270de97d", - "timestamp": "1513673552", - "totalDifficulty": "7160066586979149" + "timestamp": "1513673552" }, "input": "0xf9018b0a8505d21dba00832dc6c094abbcd5b340c80b5f1c0545c04c987b87310296ae80b9012473b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988000000000000000000000000000000000000000000000000000000000000000000000000000000001ba0fd659d76a4edbd2a823e324c93f78ad6803b30ff4a9c8bce71ba82798975c70ca06571eecc0b765688ec6c78942c5ee8b585e00988c0141b518287e9be919bc48a", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json index 5c7e5629e9d6..563ae9126e79 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json @@ -46,8 +46,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf888068449504f80832dc6c094f58833cf0c791881b494eb79d461e08a1f043f5280a45c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf12da0264664db3e71fae1dbdaf2f53954be149ad3b7ba8a5054b4d89c70febfacc8b1a0212e8398757963f419681839ae8c5a54b411e252473c82d93dda68405ca63294", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json index 11b23a990e9e..be9acf1409e8 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json @@ -47,8 +47,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json index 37723f17dd6b..b152d43a3e44 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json @@ -52,8 +52,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json index 499b449a6ece..d439d2b284e6 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json @@ -45,8 +45,7 @@ "nonce": "0x70849d5838dee2e9", "number": "25008", "stateRoot": "0x1e01d2161794768c5b917069e73d86e8dca80cd7f3168c0597de420ab93a3b7b", - "timestamp": "1479891641", - "totalDifficulty": "1896347038589" + "timestamp": "1479891641" }, "input": "0xf88b8206668504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb8000000000000000000000000000000000000000000000027fad02094277c000029a0692a3b4e7b2842f8dd7832e712c21e09f451f416c8976d5b8d02e8c0c2b4bea9a07645e90fc421b63dd755767fd93d3c03b4ec0c4d8fafa059558d08cf11d59750", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json index dbece7229d3c..cef0c1c5a80a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json @@ -10,7 +10,6 @@ "number": "995200", "stateRoot": "0x3579328470dd2aef5b9da69f5480cbe0d375e653b530ab3c1aee0da5e1ff4c94", "timestamp": "1455322761", - "totalDifficulty": "7077231809278509672", "alloc": { "0x200edd17f30485a8735878661960cd7a9a95733f": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json index 2b03dbb8dd54..0ae76e92f9bb 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json @@ -10,7 +10,6 @@ "number": "2340152", "stateRoot": "0x38295a2634c9c62d48bcbf2ef2ae83768b9055c1f5e6469d17a5d1bcb052072e", "timestamp": "1475034708", - "totalDifficulty": "66488249547380413902", "alloc": { "0x01e60b511fced1eb2b5b40991eb1dfd171a6df42": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json index a9092bbcf02a..049f24d9328f 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json @@ -10,7 +10,6 @@ "number": "469666", "stateRoot": "0xf9c50965ffae3f99310483a7836c545a025cc680303adaf3671dbeef99edf03a", "timestamp": "1446318401", - "totalDifficulty": "2462705215747880313", "alloc": { "0x0000000000000000000000000000000000000004": { "balance": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json index 263e88d6e14d..5cc3013f8076 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json @@ -10,7 +10,6 @@ "number": "1881283", "stateRoot": "0x6e3832bc2e4e66170a1e716449083e08fbb70e7b2a9f1f34e0c57e66ce40c50f", "timestamp": "1468467284", - "totalDifficulty": "37186898441932102239", "alloc": { "0x0000000000000000000000000000000000000004": { "balance": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json index 66d458200812..c931ed63fc37 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json @@ -10,7 +10,6 @@ "number": "595531", "stateRoot": "0x79d00dd270bffc48d89fa55842f63f840981121378da8c6de4d479535f25ed6a", "timestamp": "1448471472", - "totalDifficulty": "3448100174991667199", "alloc": { "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { "balance": "0x44dc051cccdfd2e132", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json index 762ccbe58f75..42fc87255480 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json @@ -10,7 +10,6 @@ "number": "1725115", "stateRoot": "0xca08a341c1f95fcba0821c4a27662ef162d39e1f9f5722717531f510d54112b0", "timestamp": "1466232982", - "totalDifficulty": "28554024908214037524", "alloc": { "0x0000000000000000000000000000000000000004": { "balance": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json index 64941dd4dbc1..5300d341b824 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json @@ -10,7 +10,6 @@ "number": "765824", "stateRoot": "0x8d96cb027a29f8ca0ccd6d31f9ea0656136ec8030ecda70bb9231849ed6f41a2", "timestamp": "1451389443", - "totalDifficulty": "4838314986494741271", "alloc": { "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb": { "balance": "0x14203bee2ea6fbe8c", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json index 30346d07f1ff..d5c2f864c168 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json @@ -10,7 +10,6 @@ "number": "1968179", "stateRoot": "0x6420003b1779cca3bcdab698c239bbc63623c0a7e4deeedbdb8190b9e7fd7520", "timestamp": "1469713675", - "totalDifficulty": "42284028928878034360", "alloc": { "0x10abb5efecdc09581f8b7cb95791fe2936790b4e": { "balance": "0x81f158e2814b4ab624c", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json index 6faf898a0f6e..1267160d1338 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json @@ -10,7 +10,6 @@ "number": "1646451", "stateRoot": "0x2bd193b9911caf43204960cc7661ce864bf0bac7f9b60191aa02bbff24f061fb", "timestamp": "1465103859", - "totalDifficulty": "24813742796574158431", "alloc": { "0x01115b41bd2731353dd3e6abf44818fdc035aaf1": { "balance": "0x16d99e16e809000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json index e73081107f61..38d96a6bd08e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json @@ -10,7 +10,6 @@ "number": "995200", "stateRoot": "0x3579328470dd2aef5b9da69f5480cbe0d375e653b530ab3c1aee0da5e1ff4c94", "timestamp": "1455322761", - "totalDifficulty": "7077231809278509672", "alloc": { "0x200edd17f30485a8735878661960cd7a9a95733f": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json index c3e7387f02e2..444eba450bec 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json @@ -14,7 +14,6 @@ "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "stateRoot": "0x577f42ab21ccfd946511c57869ace0bdf7c217c36f02b7cd3459df0ed1cffc1a", "timestamp": "1709626771", - "totalDifficulty": "1", "withdrawals": [], "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "alloc": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json index 893c60444310..b013d520c1ad 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json @@ -11,7 +11,6 @@ "number": "1", "stateRoot": "0xd2ebe0a7f3572ffe3e5b4c78147376d3fca767f236e4dd23f9151acfec7cb0d1", "timestamp": "1699617692", - "totalDifficulty": "0", "withdrawals": [], "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "alloc": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_existing_contract.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_existing_contract.json index a34d3b759ee1..64a3b16cb1fe 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_existing_contract.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_existing_contract.json @@ -10,7 +10,6 @@ "number": "243825", "stateRoot": "0x47182fe2e6e740b8a76f82fe5c527d6ad548f805274f21792cf4047235b24fbf", "timestamp": "1442424328", - "totalDifficulty": "1035061827427752845", "alloc": { "0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": { "balance": "0xc820f93200f4000", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json index fb85b31a4897..78e4a887f11c 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json @@ -11,7 +11,6 @@ "number": "39137", "stateRoot": "0x715f00df764dbadd4863247a215ac44b5420beafde3ec458b15db7aafa89be0c", "timestamp": "1709022192", - "totalDifficulty": "78275", "alloc": { "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { "balance": "0x10f06447a8d44dba190", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json index 7204bfcbfeae..9811f87c4f9b 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json @@ -52,8 +52,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_legacy/simple.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_legacy/simple.json index 44b1f08dd337..a4cb3f60e470 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_legacy/simple.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_legacy/simple.json @@ -52,8 +52,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "result": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json index 1b09622474ef..6eea6085b82a 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json @@ -10,7 +10,6 @@ "number": "1061221", "stateRoot": "0x5402c04d481414248d824c3b61e924e0c9307adbc9fbaae774a74cce30a4163d", "timestamp": "1456458069", - "totalDifficulty": "7930751135586064334", "alloc": { "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { "balance": "0x9fb6b81e112638b886", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json index f5adb1af65d7..19e1f08bb7b5 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json @@ -11,7 +11,6 @@ "number": "39137", "stateRoot": "0x715f00df764dbadd4863247a215ac44b5420beafde3ec458b15db7aafa89be0c", "timestamp": "1709022192", - "totalDifficulty": "78275", "alloc": { "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { "balance": "0x10f06447a8d44dba190", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_suicide.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_suicide.json index fdeb0e50673c..cf8f03bd09a1 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_suicide.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_suicide.json @@ -10,7 +10,6 @@ "number": "243825", "stateRoot": "0x47182fe2e6e740b8a76f82fe5c527d6ad548f805274f21792cf4047235b24fbf", "timestamp": "1442424328", - "totalDifficulty": "1035061827427752845", "alloc": { "0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": { "balance": "0xc820f93200f4000", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json index 9c0030a0a8d1..e6d6f2435b43 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json @@ -10,7 +10,6 @@ "number": "1062502", "stateRoot": "0x1df615df5fdbc8d5397bf3574f462f6d9696428eb8796d8e9252bccc8e3a8996", "timestamp": "1456480432", - "totalDifficulty": "7948153536501153741", "alloc": { "0x0000000000000000000000000000000000000004": { "balance": "0x0", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json index 01cc3c50582f..22932ebc95af 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json @@ -52,8 +52,7 @@ "nonce": "0x4eb12e19c16d43da", "number": "2289805", "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", - "timestamp": "1513601261", - "totalDifficulty": "7143276353481064" + "timestamp": "1513601261" }, "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", "tracerConfig": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json index 5021bda192cb..3f071468711c 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json @@ -10,7 +10,6 @@ "number": "422908", "stateRoot": "0xd914c6440edf9f4a6f997a9b3ecb6e1a9ca2310f74b0b6890c0d0d4a3c28e4d3", "timestamp": "1445530335", - "totalDifficulty": "2148894717741690476", "alloc": { "0x2861bf89b6c640c79040d357c1e9513693ef5d3f": { "balance": "0x0", diff --git a/graphql/graphql.go b/graphql/graphql.go index f7cf164d3144..90d70bf14233 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -906,18 +906,6 @@ func (b *Block) LogsBloom(ctx context.Context) (hexutil.Bytes, error) { return header.Bloom.Bytes(), nil } -func (b *Block) TotalDifficulty(ctx context.Context) (hexutil.Big, error) { - hash, err := b.Hash(ctx) - if err != nil { - return hexutil.Big{}, err - } - td := b.r.backend.GetTd(ctx, hash) - if td == nil { - return hexutil.Big{}, fmt.Errorf("total difficulty not found %x", hash) - } - return hexutil.Big(*td), nil -} - func (b *Block) RawHeader(ctx context.Context) (hexutil.Bytes, error) { header, err := b.resolveHeader(ctx) if err != nil { diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index ae3a58a98301..a6be589a0f12 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -338,8 +338,8 @@ func TestGraphQLConcurrentResolvers(t *testing.T) { }, // Multiple fields of block race to resolve header and body. { - body: "{ block { number hash gasLimit ommerCount transactionCount totalDifficulty } }", - want: fmt.Sprintf(`{"block":{"number":"0x1","hash":"%s","gasLimit":"0xaf79e0","ommerCount":"0x0","transactionCount":"0x3","totalDifficulty":"0x200000"}}`, chain[len(chain)-1].Hash()), + body: "{ block { number hash gasLimit ommerCount transactionCount } }", + want: fmt.Sprintf(`{"block":{"number":"0x1","hash":"%s","gasLimit":"0xaf79e0","ommerCount":"0x0","transactionCount":"0x3"}}`, chain[len(chain)-1].Hash()), }, // Multiple fields of a block race to resolve the header and body. { diff --git a/graphql/schema.go b/graphql/schema.go index 8264f1c28638..15e4557915b4 100644 --- a/graphql/schema.go +++ b/graphql/schema.go @@ -232,9 +232,6 @@ const schema string = ` mixHash: Bytes32! # Difficulty is a measure of the difficulty of mining this block. difficulty: BigInt! - # TotalDifficulty is the sum of all difficulty values up to and including - # this block. - totalDifficulty: BigInt! # OmmerCount is the number of ommers (AKA uncles) associated with this # block. If ommers are unavailable, this field will be null. ommerCount: Long diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7981f35ae391..a50295289340 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -807,7 +807,7 @@ func decodeHash(s string) (h common.Hash, inputLength int, err error) { func (api *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) { header, err := api.b.HeaderByNumber(ctx, number) if header != nil && err == nil { - response := api.rpcMarshalHeader(ctx, header) + response := RPCMarshalHeader(header) if number == rpc.PendingBlockNumber { // Pending header need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -823,7 +823,7 @@ func (api *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.Bloc func (api *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} { header, _ := api.b.HeaderByHash(ctx, hash) if header != nil { - return api.rpcMarshalHeader(ctx, header) + return RPCMarshalHeader(header) } return nil } @@ -838,14 +838,14 @@ func (api *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) func (api *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { block, err := api.b.BlockByNumber(ctx, number) if block != nil && err == nil { - response, err := api.rpcMarshalBlock(ctx, block, true, fullTx) - if err == nil && number == rpc.PendingBlockNumber { + response := RPCMarshalBlock(block, true, fullTx, api.b.ChainConfig()) + if number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { response[field] = nil } } - return response, err + return response, nil } return nil, err } @@ -855,7 +855,7 @@ func (api *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.Block func (api *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { block, err := api.b.BlockByHash(ctx, hash) if block != nil { - return api.rpcMarshalBlock(ctx, block, true, fullTx) + return RPCMarshalBlock(block, true, fullTx, api.b.ChainConfig()), nil } return nil, err } @@ -870,7 +870,7 @@ func (api *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blo return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return api.rpcMarshalBlock(ctx, block, false, false) + return RPCMarshalBlock(block, false, false, api.b.ChainConfig()), nil } return nil, err } @@ -885,7 +885,7 @@ func (api *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, block return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return api.rpcMarshalBlock(ctx, block, false, false) + return RPCMarshalBlock(block, false, false, api.b.ChainConfig()), nil } return nil, err } @@ -1442,24 +1442,6 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param return fields } -// rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires -// a `BlockchainAPI`. -func (api *BlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { - fields := RPCMarshalHeader(header) - fields["totalDifficulty"] = (*hexutil.Big)(api.b.GetTd(ctx, header.Hash())) - return fields -} - -// rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires -// a `BlockchainAPI`. -func (api *BlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields := RPCMarshalBlock(b, inclTx, fullTx, api.b.ChainConfig()) - if inclTx { - fields["totalDifficulty"] = (*hexutil.Big)(api.b.GetTd(ctx, b.Hash())) - } - return fields, nil -} - // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction type RPCTransaction struct { BlockHash *common.Hash `json:"blockHash"` diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 2a45ba09210f..0e991592b4b3 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -68,7 +68,6 @@ type Backend interface { StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) Pending() (*types.Block, types.Receipts, *state.StateDB) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) - GetTd(ctx context.Context, hash common.Hash) *big.Int GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index bccf87f8efea..4371a4246480 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -125,8 +125,6 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[str var ( results = make([]map[string]interface{}, len(blocks)) parent = sim.base - // Assume same total difficulty for all simulated blocks. - td = sim.b.GetTd(ctx, sim.base.Hash()) ) for bi, block := range blocks { result, callResults, err := sim.processBlock(ctx, &block, headers[bi], parent, headers[:bi], timeout) @@ -134,7 +132,6 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[str return nil, err } enc := RPCMarshalBlock(result, true, sim.fullTx, sim.chainConfig) - enc["totalDifficulty"] = (*hexutil.Big)(td) enc["calls"] = callResults results[bi] = enc diff --git a/internal/ethapi/testdata/eth_getBlockByHash-hash-1.json b/internal/ethapi/testdata/eth_getBlockByHash-hash-1.json index 73da1b175258..11c0545ffacc 100644 --- a/internal/ethapi/testdata/eth_getBlockByHash-hash-1.json +++ b/internal/ethapi/testdata/eth_getBlockByHash-hash-1.json @@ -16,7 +16,6 @@ "size": "0x26a", "stateRoot": "0x4acfcd1a6ab9f5e62411021ecd8a749976ae50b0590e967471264b372d7ac55b", "timestamp": "0xa", - "totalDifficulty": "0x1", "transactions": [ "0x644a31c354391520d00e95b9affbbb010fc79ac268144ab8e28207f4cf51097e" ], diff --git a/internal/ethapi/testdata/eth_getBlockByHash-hash-genesis.json b/internal/ethapi/testdata/eth_getBlockByHash-hash-genesis.json index d2bdbacd7390..134d60c67a42 100644 --- a/internal/ethapi/testdata/eth_getBlockByHash-hash-genesis.json +++ b/internal/ethapi/testdata/eth_getBlockByHash-hash-genesis.json @@ -16,7 +16,6 @@ "size": "0x200", "stateRoot": "0xd883f48b83cc9c1e8389453beb4ad4e572462eec049ca4fffbe16ecefb3fe937", "timestamp": "0x0", - "totalDifficulty": "0x1", "transactions": [], "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncles": [] diff --git a/internal/ethapi/testdata/eth_getBlockByHash-hash-latest-1-fullTx.json b/internal/ethapi/testdata/eth_getBlockByHash-hash-latest-1-fullTx.json index 8e0748def940..3c8d42c9a946 100644 --- a/internal/ethapi/testdata/eth_getBlockByHash-hash-latest-1-fullTx.json +++ b/internal/ethapi/testdata/eth_getBlockByHash-hash-latest-1-fullTx.json @@ -16,7 +16,6 @@ "size": "0x26a", "stateRoot": "0x78b2b19ef1a0276dbbc23a875dbf60ae5d10dafa0017098473c4871abd3e7b5c", "timestamp": "0x5a", - "totalDifficulty": "0x1", "transactions": [ { "blockHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5", diff --git a/internal/ethapi/testdata/eth_getBlockByHash-hash-latest.json b/internal/ethapi/testdata/eth_getBlockByHash-hash-latest.json index 6e914e37d0d3..13876b5a523f 100644 --- a/internal/ethapi/testdata/eth_getBlockByHash-hash-latest.json +++ b/internal/ethapi/testdata/eth_getBlockByHash-hash-latest.json @@ -16,7 +16,6 @@ "size": "0x26a", "stateRoot": "0x118f1433ae23c4d1c12f5bd652baddb72611c55ac1cd6af6620d209db222f9e6", "timestamp": "0x64", - "totalDifficulty": "0x1", "transactions": [ "0x3ee4094ca1e0b07a66dd616a057e081e53144ca7e9685a126fd4dda9ca042644" ], diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-number-0.json b/internal/ethapi/testdata/eth_getBlockByNumber-number-0.json index d2bdbacd7390..134d60c67a42 100644 --- a/internal/ethapi/testdata/eth_getBlockByNumber-number-0.json +++ b/internal/ethapi/testdata/eth_getBlockByNumber-number-0.json @@ -16,7 +16,6 @@ "size": "0x200", "stateRoot": "0xd883f48b83cc9c1e8389453beb4ad4e572462eec049ca4fffbe16ecefb3fe937", "timestamp": "0x0", - "totalDifficulty": "0x1", "transactions": [], "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncles": [] diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-number-1.json b/internal/ethapi/testdata/eth_getBlockByNumber-number-1.json index 73da1b175258..11c0545ffacc 100644 --- a/internal/ethapi/testdata/eth_getBlockByNumber-number-1.json +++ b/internal/ethapi/testdata/eth_getBlockByNumber-number-1.json @@ -16,7 +16,6 @@ "size": "0x26a", "stateRoot": "0x4acfcd1a6ab9f5e62411021ecd8a749976ae50b0590e967471264b372d7ac55b", "timestamp": "0xa", - "totalDifficulty": "0x1", "transactions": [ "0x644a31c354391520d00e95b9affbbb010fc79ac268144ab8e28207f4cf51097e" ], diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-number-latest-1.json b/internal/ethapi/testdata/eth_getBlockByNumber-number-latest-1.json index 8e0748def940..3c8d42c9a946 100644 --- a/internal/ethapi/testdata/eth_getBlockByNumber-number-latest-1.json +++ b/internal/ethapi/testdata/eth_getBlockByNumber-number-latest-1.json @@ -16,7 +16,6 @@ "size": "0x26a", "stateRoot": "0x78b2b19ef1a0276dbbc23a875dbf60ae5d10dafa0017098473c4871abd3e7b5c", "timestamp": "0x5a", - "totalDifficulty": "0x1", "transactions": [ { "blockHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5", diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-tag-latest.json b/internal/ethapi/testdata/eth_getBlockByNumber-tag-latest.json index 6e914e37d0d3..13876b5a523f 100644 --- a/internal/ethapi/testdata/eth_getBlockByNumber-tag-latest.json +++ b/internal/ethapi/testdata/eth_getBlockByNumber-tag-latest.json @@ -16,7 +16,6 @@ "size": "0x26a", "stateRoot": "0x118f1433ae23c4d1c12f5bd652baddb72611c55ac1cd6af6620d209db222f9e6", "timestamp": "0x64", - "totalDifficulty": "0x1", "transactions": [ "0x3ee4094ca1e0b07a66dd616a057e081e53144ca7e9685a126fd4dda9ca042644" ], diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json index 1d524d6eced1..60f18bc1144e 100644 --- a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json +++ b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json @@ -15,7 +15,6 @@ "size": "0x256", "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp": "0x2a", - "totalDifficulty": null, "transactions": [ { "blockHash": "0x6cebd9f966ea686f44b981685e3f0eacea28591a7a86d7fbbe521a86e9f81165", diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending.json b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending.json index c0e2b07bb8aa..dda2d9321337 100644 --- a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending.json +++ b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending.json @@ -15,7 +15,6 @@ "size": "0x256", "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp": "0x2a", - "totalDifficulty": null, "transactions": [ "0x4afee081df5dff7a025964032871f7d4ba4d21baf5f6376a2f4a9f79fc506298" ], diff --git a/internal/ethapi/testdata/eth_getHeaderByHash-hash-0.json b/internal/ethapi/testdata/eth_getHeaderByHash-hash-0.json index 1bd68888b601..e1e64a3093e4 100644 --- a/internal/ethapi/testdata/eth_getHeaderByHash-hash-0.json +++ b/internal/ethapi/testdata/eth_getHeaderByHash-hash-0.json @@ -15,6 +15,5 @@ "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "stateRoot": "0xd883f48b83cc9c1e8389453beb4ad4e572462eec049ca4fffbe16ecefb3fe937", "timestamp": "0x0", - "totalDifficulty": "0x1", "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" } \ No newline at end of file diff --git a/internal/ethapi/testdata/eth_getHeaderByHash-hash-1.json b/internal/ethapi/testdata/eth_getHeaderByHash-hash-1.json index cf662cad751b..adfac5110cc2 100644 --- a/internal/ethapi/testdata/eth_getHeaderByHash-hash-1.json +++ b/internal/ethapi/testdata/eth_getHeaderByHash-hash-1.json @@ -15,6 +15,5 @@ "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "stateRoot": "0x4acfcd1a6ab9f5e62411021ecd8a749976ae50b0590e967471264b372d7ac55b", "timestamp": "0xa", - "totalDifficulty": "0x1", "transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7" } \ No newline at end of file diff --git a/internal/ethapi/testdata/eth_getHeaderByHash-hash-latest-1.json b/internal/ethapi/testdata/eth_getHeaderByHash-hash-latest-1.json index 4721dd1e7ac8..39209a86db92 100644 --- a/internal/ethapi/testdata/eth_getHeaderByHash-hash-latest-1.json +++ b/internal/ethapi/testdata/eth_getHeaderByHash-hash-latest-1.json @@ -15,6 +15,5 @@ "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "stateRoot": "0x78b2b19ef1a0276dbbc23a875dbf60ae5d10dafa0017098473c4871abd3e7b5c", "timestamp": "0x5a", - "totalDifficulty": "0x1", "transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5" } \ No newline at end of file diff --git a/internal/ethapi/testdata/eth_getHeaderByHash-hash-latest.json b/internal/ethapi/testdata/eth_getHeaderByHash-hash-latest.json index 4dd590915915..5313348a5097 100644 --- a/internal/ethapi/testdata/eth_getHeaderByHash-hash-latest.json +++ b/internal/ethapi/testdata/eth_getHeaderByHash-hash-latest.json @@ -15,6 +15,5 @@ "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "stateRoot": "0x118f1433ae23c4d1c12f5bd652baddb72611c55ac1cd6af6620d209db222f9e6", "timestamp": "0x64", - "totalDifficulty": "0x1", "transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445" } \ No newline at end of file diff --git a/internal/ethapi/testdata/eth_getHeaderByNumber-number-0.json b/internal/ethapi/testdata/eth_getHeaderByNumber-number-0.json index 1bd68888b601..e1e64a3093e4 100644 --- a/internal/ethapi/testdata/eth_getHeaderByNumber-number-0.json +++ b/internal/ethapi/testdata/eth_getHeaderByNumber-number-0.json @@ -15,6 +15,5 @@ "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "stateRoot": "0xd883f48b83cc9c1e8389453beb4ad4e572462eec049ca4fffbe16ecefb3fe937", "timestamp": "0x0", - "totalDifficulty": "0x1", "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" } \ No newline at end of file diff --git a/internal/ethapi/testdata/eth_getHeaderByNumber-number-1.json b/internal/ethapi/testdata/eth_getHeaderByNumber-number-1.json index cf662cad751b..adfac5110cc2 100644 --- a/internal/ethapi/testdata/eth_getHeaderByNumber-number-1.json +++ b/internal/ethapi/testdata/eth_getHeaderByNumber-number-1.json @@ -15,6 +15,5 @@ "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "stateRoot": "0x4acfcd1a6ab9f5e62411021ecd8a749976ae50b0590e967471264b372d7ac55b", "timestamp": "0xa", - "totalDifficulty": "0x1", "transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7" } \ No newline at end of file diff --git a/internal/ethapi/testdata/eth_getHeaderByNumber-number-latest-1.json b/internal/ethapi/testdata/eth_getHeaderByNumber-number-latest-1.json index 4721dd1e7ac8..39209a86db92 100644 --- a/internal/ethapi/testdata/eth_getHeaderByNumber-number-latest-1.json +++ b/internal/ethapi/testdata/eth_getHeaderByNumber-number-latest-1.json @@ -15,6 +15,5 @@ "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "stateRoot": "0x78b2b19ef1a0276dbbc23a875dbf60ae5d10dafa0017098473c4871abd3e7b5c", "timestamp": "0x5a", - "totalDifficulty": "0x1", "transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5" } \ No newline at end of file diff --git a/internal/ethapi/testdata/eth_getHeaderByNumber-tag-latest.json b/internal/ethapi/testdata/eth_getHeaderByNumber-tag-latest.json index 4dd590915915..5313348a5097 100644 --- a/internal/ethapi/testdata/eth_getHeaderByNumber-tag-latest.json +++ b/internal/ethapi/testdata/eth_getHeaderByNumber-tag-latest.json @@ -15,6 +15,5 @@ "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "stateRoot": "0x118f1433ae23c4d1c12f5bd652baddb72611c55ac1cd6af6620d209db222f9e6", "timestamp": "0x64", - "totalDifficulty": "0x1", "transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445" } \ No newline at end of file diff --git a/internal/ethapi/testdata/eth_getHeaderByNumber-tag-pending.json b/internal/ethapi/testdata/eth_getHeaderByNumber-tag-pending.json index da177f218928..289ff5fece80 100644 --- a/internal/ethapi/testdata/eth_getHeaderByNumber-tag-pending.json +++ b/internal/ethapi/testdata/eth_getHeaderByNumber-tag-pending.json @@ -14,7 +14,6 @@ "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp": "0x2a", - "totalDifficulty": null, "transactionsRoot": "0x98d9f6dd0aa479c0fb448f2627e9f1964aca699fccab8f6e95861547a4699e37", "withdrawalsRoot": "0x73d756269cdfc22e7e17a3548e36f42f750ca06d7e3cd98d1b6d0eb5add9dc84" } \ No newline at end of file diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index b0fd8fcafc3e..a4141bac43c4 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -3854,7 +3854,6 @@ var outputBlockFormatter = function(block) { block.number = utils.toDecimal(block.number); block.difficulty = utils.toBigNumber(block.difficulty); - block.totalDifficulty = utils.toBigNumber(block.totalDifficulty); if (utils.isArray(block.transactions)) { block.transactions.forEach(function(item){ From f14f13bac74a091a726157ab548fe205a7d53cac Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 1 Oct 2024 15:14:30 +0200 Subject: [PATCH 570/571] params: go-ethereum v1.14.11 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 1fe2d3459df0..b5c0dff7c0aa 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 11 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 11 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 154820ccd87922fd8ca422e549beb91bbb24716e Mon Sep 17 00:00:00 2001 From: Arran Schlosberg <519948+ARR4N@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:20:32 +0100 Subject: [PATCH 571/571] chore: squash `arr4n/libevm` into `libevm` (#7) * feat: pseudo-generic extra payloads in `params.ChainConfig` and `params.Rules` * feat: `params.ExtraPayloadGetter` for end-user type safety * refactor: payloads only available through `params.ExtraPayloadGetter` * chore: make `libevm/examples/extraparams` a `params` testable example * doc: `libevm/pseudo` package comments and improved readability * doc: `params.*Extra*` comments and improved readability * doc: `params.ExtraPayloadGetter` comments and improved readability * doc: `params/config.libevm_test.go` comments and improved readability * refactor: simplify `params.ChainConfig.UnmarshalJSON()` * refactor: abstract new/nil-pointer creation into `pseudo.Constructor`s * feat: precompile override via `params.Extras` hooks * doc: flesh out `PrecompileOverride()` in example * doc: complete commentary and improve readability * refactor: `ChainConfig.Hooks()` + `Rules` equivalent * chore: rename precompiles test file in keeping with geth equivalent * feat: stateful precompiles + allowlist hooks The allowlist hooks are included in this commit because they allow for the same functionality as stateful precompiles in `ava-labs/coreth` and `ava-labs/subnet-evm`. * fix: `StateTransition.canExecuteTransaction()` used `msg.From` instead of `To` * test: `params.RulesHooks.CanCreateContract` integration * test: `params.RulesHooks.CanExecuteTransaction` integration * test: `vm.NewStatefulPrecompile()` integration * refactor: simplify test of `CanCreateContract` * refactor: abstract generation of random `Address`/`Hash` values * doc: full documentation + readability refactoring/renaming * fix: remove circular dependency in tests --- core/state_transition.go | 3 + core/state_transition.libevm.go | 9 ++ core/state_transition.libevm_test.go | 40 +++++ core/vm/contracts.go | 4 +- core/vm/contracts.libevm.go | 83 ++++++++++ core/vm/contracts.libevm_test.go | 178 ++++++++++++++++++++ core/vm/evm.go | 20 ++- core/vm/libevm_test.go | 9 ++ libevm/ethtest/evm.go | 52 ++++++ libevm/ethtest/rand.go | 41 +++++ libevm/hookstest/stub.go | 60 +++++++ libevm/interfaces_test.go | 20 +++ libevm/libevm.go | 52 ++++++ libevm/pseudo/constructor.go | 24 +++ libevm/pseudo/constructor_test.go | 45 ++++++ libevm/pseudo/type.go | 175 ++++++++++++++++++++ libevm/pseudo/type_test.go | 79 +++++++++ params/config.go | 9 +- params/config.libevm.go | 232 +++++++++++++++++++++++++++ params/config.libevm_test.go | 164 +++++++++++++++++++ params/example.libevm_test.go | 158 ++++++++++++++++++ params/hooks.libevm.go | 83 ++++++++++ 22 files changed, 1533 insertions(+), 7 deletions(-) create mode 100644 core/state_transition.libevm.go create mode 100644 core/state_transition.libevm_test.go create mode 100644 core/vm/contracts.libevm.go create mode 100644 core/vm/contracts.libevm_test.go create mode 100644 core/vm/libevm_test.go create mode 100644 libevm/ethtest/evm.go create mode 100644 libevm/ethtest/rand.go create mode 100644 libevm/hookstest/stub.go create mode 100644 libevm/interfaces_test.go create mode 100644 libevm/libevm.go create mode 100644 libevm/pseudo/constructor.go create mode 100644 libevm/pseudo/constructor_test.go create mode 100644 libevm/pseudo/type.go create mode 100644 libevm/pseudo/type_test.go create mode 100644 params/config.libevm.go create mode 100644 params/config.libevm_test.go create mode 100644 params/example.libevm_test.go create mode 100644 params/hooks.libevm.go diff --git a/core/state_transition.go b/core/state_transition.go index d285d03fe245..d56114674063 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -377,6 +377,9 @@ func (st *StateTransition) preCheck() error { // However if any consensus issue encountered, return the error directly with // nil evm execution result. func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { + if err := st.canExecuteTransaction(); err != nil { + return nil, err + } // First check this message satisfies all consensus rules before // applying the message. The rules include these clauses // diff --git a/core/state_transition.libevm.go b/core/state_transition.libevm.go new file mode 100644 index 000000000000..4d2ee16f0207 --- /dev/null +++ b/core/state_transition.libevm.go @@ -0,0 +1,9 @@ +package core + +// canExecuteTransaction is a convenience wrapper for calling the +// [params.RulesHooks.CanExecuteTransaction] hook. +func (st *StateTransition) canExecuteTransaction() error { + bCtx := st.evm.Context + rules := st.evm.ChainConfig().Rules(bCtx.BlockNumber, bCtx.Random != nil, bCtx.Time) + return rules.Hooks().CanExecuteTransaction(st.msg.From, st.msg.To, st.state) +} diff --git a/core/state_transition.libevm_test.go b/core/state_transition.libevm_test.go new file mode 100644 index 000000000000..d81e9ce4f763 --- /dev/null +++ b/core/state_transition.libevm_test.go @@ -0,0 +1,40 @@ +package core_test + +import ( + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/libevm" + "github.com/ethereum/go-ethereum/libevm/ethtest" + "github.com/ethereum/go-ethereum/libevm/hookstest" + "github.com/stretchr/testify/require" +) + +func TestCanExecuteTransaction(t *testing.T) { + rng := ethtest.NewPseudoRand(42) + account := rng.Address() + slot := rng.Hash() + + makeErr := func(from common.Address, to *common.Address, val common.Hash) error { + return fmt.Errorf("From: %v To: %v State: %v", from, to, val) + } + hooks := &hookstest.Stub{ + CanExecuteTransactionFn: func(from common.Address, to *common.Address, s libevm.StateReader) error { + return makeErr(from, to, s.GetState(account, slot)) + }, + } + hooks.RegisterForRules(t) + + value := rng.Hash() + + state, evm := ethtest.NewZeroEVM(t) + state.SetState(account, slot, value) + msg := &core.Message{ + From: rng.Address(), + To: rng.AddressPtr(), + } + _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(30e6)) + require.EqualError(t, err, makeErr(msg.From, msg.To, value).Error()) +} diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 104d2ba814b2..c56c37274687 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -220,7 +220,7 @@ func ActivePrecompiles(rules params.Rules) []common.Address { // - the returned bytes, // - the _remaining_ gas, // - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { +func (args *evmCallArgs) RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas @@ -229,7 +229,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uin logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract) } suppliedGas -= gasCost - output, err := p.Run(input) + output, err := args.run(p, input) return output, suppliedGas, err } diff --git a/core/vm/contracts.libevm.go b/core/vm/contracts.libevm.go new file mode 100644 index 000000000000..23057d6f9c8c --- /dev/null +++ b/core/vm/contracts.libevm.go @@ -0,0 +1,83 @@ +package vm + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" +) + +// evmCallArgs mirrors the parameters of the [EVM] methods Call(), CallCode(), +// DelegateCall() and StaticCall(). Its fields are identical to those of the +// parameters, prepended with the receiver name. As {Delegate,Static}Call don't +// accept a value, they MUST set the respective field to nil. +// +// Instantiation can be achieved by merely copying the parameter names, in +// order, which is trivially achieved with AST manipulation: +// +// func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) ... { +// ... +// args := &evmCallArgs{evm, caller, addr, input, gas, value} +type evmCallArgs struct { + evm *EVM + caller ContractRef + addr common.Address + input []byte + gas uint64 + value *uint256.Int +} + +// run runs the [PrecompiledContract], differentiating between stateful and +// regular types. +func (args *evmCallArgs) run(p PrecompiledContract, input []byte) (ret []byte, err error) { + if p, ok := p.(statefulPrecompile); ok { + return p.run(args.evm.StateDB, &args.evm.chainRules, args.caller.Address(), args.addr, input) + } + return p.Run(input) +} + +// PrecompiledStatefulRun is the stateful equivalent of the Run() method of a +// [PrecompiledContract]. +type PrecompiledStatefulRun func(_ StateDB, _ *params.Rules, caller, self common.Address, input []byte) ([]byte, error) + +// NewStatefulPrecompile constructs a new PrecompiledContract that can be used +// via an [EVM] instance but MUST NOT be called directly; a direct call to Run() +// reserves the right to panic. See other requirements defined in the comments +// on [PrecompiledContract]. +func NewStatefulPrecompile(run PrecompiledStatefulRun, requiredGas func([]byte) uint64) PrecompiledContract { + return statefulPrecompile{ + gas: requiredGas, + run: run, + } +} + +type statefulPrecompile struct { + gas func([]byte) uint64 + run PrecompiledStatefulRun +} + +func (p statefulPrecompile) RequiredGas(input []byte) uint64 { + return p.gas(input) +} + +func (p statefulPrecompile) Run([]byte) ([]byte, error) { + // https://google.github.io/styleguide/go/best-practices.html#when-to-panic + // This would indicate an API misuse and would occur in tests, not in + // production. + panic(fmt.Sprintf("BUG: call to %T.Run(); MUST call %T", p, p.run)) +} + +var ( + // These lock in the assumptions made when implementing [evmCallArgs]. If + // these break then the struct fields SHOULD be changed to match these + // signatures. + _ = [](func(ContractRef, common.Address, []byte, uint64, *uint256.Int) ([]byte, uint64, error)){ + (*EVM)(nil).Call, + (*EVM)(nil).CallCode, + } + _ = [](func(ContractRef, common.Address, []byte, uint64) ([]byte, uint64, error)){ + (*EVM)(nil).DelegateCall, + (*EVM)(nil).StaticCall, + } +) diff --git a/core/vm/contracts.libevm_test.go b/core/vm/contracts.libevm_test.go new file mode 100644 index 000000000000..28bdcde09a52 --- /dev/null +++ b/core/vm/contracts.libevm_test.go @@ -0,0 +1,178 @@ +package vm_test + +import ( + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/libevm" + "github.com/ethereum/go-ethereum/libevm/ethtest" + "github.com/ethereum/go-ethereum/libevm/hookstest" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/exp/rand" +) + +type precompileStub struct { + requiredGas uint64 + returnData []byte +} + +func (s *precompileStub) RequiredGas([]byte) uint64 { return s.requiredGas } +func (s *precompileStub) Run([]byte) ([]byte, error) { return s.returnData, nil } + +func TestPrecompileOverride(t *testing.T) { + type test struct { + name string + addr common.Address + requiredGas uint64 + stubData []byte + } + + const gasLimit = uint64(1e7) + + tests := []test{ + { + name: "arbitrary values", + addr: common.Address{'p', 'r', 'e', 'c', 'o', 'm', 'p', 'i', 'l', 'e'}, + requiredGas: 314159, + stubData: []byte("the return data"), + }, + } + + rng := rand.New(rand.NewSource(42)) + for _, addr := range vm.PrecompiledAddressesCancun { + tests = append(tests, test{ + name: fmt.Sprintf("existing precompile %v", addr), + addr: addr, + requiredGas: rng.Uint64n(gasLimit), + stubData: addr[:], + }) + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + hooks := &hookstest.Stub{ + PrecompileOverrides: map[common.Address]libevm.PrecompiledContract{ + tt.addr: &precompileStub{ + requiredGas: tt.requiredGas, + returnData: tt.stubData, + }, + }, + } + hooks.RegisterForRules(t) + + t.Run(fmt.Sprintf("%T.Call([overridden precompile address = %v])", &vm.EVM{}, tt.addr), func(t *testing.T) { + _, evm := ethtest.NewZeroEVM(t) + gotData, gotGasLeft, err := evm.Call(vm.AccountRef{}, tt.addr, nil, gasLimit, uint256.NewInt(0)) + require.NoError(t, err) + assert.Equal(t, tt.stubData, gotData, "contract's return data") + assert.Equal(t, gasLimit-tt.requiredGas, gotGasLeft, "gas left") + }) + }) + } +} + +func TestNewStatefulPrecompile(t *testing.T) { + rng := ethtest.NewPseudoRand(314159) + precompile := rng.Address() + slot := rng.Hash() + + const gasLimit = 1e6 + gasCost := rng.Uint64n(gasLimit) + + makeOutput := func(caller, self common.Address, input []byte, stateVal common.Hash) []byte { + return []byte(fmt.Sprintf( + "Caller: %v Precompile: %v State: %v Input: %#x", + caller, self, stateVal, input, + )) + } + hooks := &hookstest.Stub{ + PrecompileOverrides: map[common.Address]libevm.PrecompiledContract{ + precompile: vm.NewStatefulPrecompile( + func(state vm.StateDB, _ *params.Rules, caller, self common.Address, input []byte) ([]byte, error) { + return makeOutput(caller, self, input, state.GetState(precompile, slot)), nil + }, + func(b []byte) uint64 { + return gasCost + }, + ), + }, + } + hooks.RegisterForRules(t) + + caller := rng.Address() + input := rng.Bytes(8) + value := rng.Hash() + + state, evm := ethtest.NewZeroEVM(t) + state.SetState(precompile, slot, value) + wantReturnData := makeOutput(caller, precompile, input, value) + wantGasLeft := gasLimit - gasCost + + gotReturnData, gotGasLeft, err := evm.Call(vm.AccountRef(caller), precompile, input, gasLimit, uint256.NewInt(0)) + require.NoError(t, err) + assert.Equal(t, wantReturnData, gotReturnData) + assert.Equal(t, wantGasLeft, gotGasLeft) +} + +func TestCanCreateContract(t *testing.T) { + rng := ethtest.NewPseudoRand(142857) + account := rng.Address() + slot := rng.Hash() + + makeErr := func(cc *libevm.AddressContext, stateVal common.Hash) error { + return fmt.Errorf("Origin: %v Caller: %v Contract: %v State: %v", cc.Origin, cc.Caller, cc.Self, stateVal) + } + hooks := &hookstest.Stub{ + CanCreateContractFn: func(cc *libevm.AddressContext, s libevm.StateReader) error { + return makeErr(cc, s.GetState(account, slot)) + }, + } + hooks.RegisterForRules(t) + + origin := rng.Address() + caller := rng.Address() + value := rng.Hash() + code := rng.Bytes(8) + salt := rng.Hash() + + create := crypto.CreateAddress(caller, 0) + create2 := crypto.CreateAddress2(caller, salt, crypto.Keccak256(code)) + + tests := []struct { + name string + create func(*vm.EVM) ([]byte, common.Address, uint64, error) + wantErr error + }{ + { + name: "Create", + create: func(evm *vm.EVM) ([]byte, common.Address, uint64, error) { + return evm.Create(vm.AccountRef(caller), code, 1e6, uint256.NewInt(0)) + }, + wantErr: makeErr(&libevm.AddressContext{Origin: origin, Caller: caller, Self: create}, value), + }, + { + name: "Create2", + create: func(evm *vm.EVM) ([]byte, common.Address, uint64, error) { + return evm.Create2(vm.AccountRef(caller), code, 1e6, uint256.NewInt(0), new(uint256.Int).SetBytes(salt[:])) + }, + wantErr: makeErr(&libevm.AddressContext{Origin: origin, Caller: caller, Self: create2}, value), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + state, evm := ethtest.NewZeroEVM(t) + state.SetState(account, slot, value) + evm.TxContext.Origin = origin + + _, _, _, err := tt.create(evm) + require.EqualError(t, err, tt.wantErr.Error()) + }) + } +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 616668d565cc..450a75246480 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/libevm" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -41,6 +42,9 @@ type ( ) func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { + if p, override := evm.chainRules.Hooks().PrecompileOverride(addr); override { + return p, p != nil + } p, ok := evm.precompiles[addr] return p, ok } @@ -208,7 +212,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) if isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + args := &evmCallArgs{evm, caller, addr, input, gas, value} + ret, gas, err = args.RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -277,7 +282,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + args := &evmCallArgs{evm, caller, addr, input, gas, value} + ret, gas, err = args.RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -328,7 +334,8 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + args := &evmCallArgs{evm, caller, addr, input, gas, nil} + ret, gas, err = args.RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -382,7 +389,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte evm.StateDB.AddBalance(addr, new(uint256.Int), tracing.BalanceChangeTouchAccount) if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + args := &evmCallArgs{evm, caller, addr, input, gas, nil} + ret, gas, err = args.RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' @@ -434,6 +442,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } + cc := &libevm.AddressContext{Origin: evm.Origin, Caller: caller.Address(), Self: address} + if err := evm.chainRules.Hooks().CanCreateContract(cc, evm.StateDB); err != nil { + return nil, common.Address{}, gas, err + } // Depth check execution. Fail if we're trying to execute above the // limit. if evm.depth > int(params.CallCreateDepth) { diff --git a/core/vm/libevm_test.go b/core/vm/libevm_test.go new file mode 100644 index 000000000000..ee9bfcd094b1 --- /dev/null +++ b/core/vm/libevm_test.go @@ -0,0 +1,9 @@ +package vm + +import "github.com/ethereum/go-ethereum/core/tracing" + +// The original RunPrecompiledContract was migrated to being a method on +// [evmCallArgs]. We need to replace it for use by regular geth tests. +func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { + return (*evmCallArgs)(nil).RunPrecompiledContract(p, input, suppliedGas, logger) +} diff --git a/libevm/ethtest/evm.go b/libevm/ethtest/evm.go new file mode 100644 index 000000000000..ca5c1feb8d8b --- /dev/null +++ b/libevm/ethtest/evm.go @@ -0,0 +1,52 @@ +// Package ethtest provides utility functions for use in testing +// Ethereum-related functionality. +package ethtest + +import ( + "testing" + + "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/state/snapshot" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/triedb" + "github.com/stretchr/testify/require" +) + +// NewZeroEVM returns a new EVM backed by a [rawdb.NewMemoryDatabase]; all other +// arguments to [vm.NewEVM] are the zero values of their respective types, +// except for the use of [core.CanTransfer] and [core.Transfer] instead of nil +// functions. +func NewZeroEVM(tb testing.TB) (*state.StateDB, *vm.EVM) { + tb.Helper() + + empty := types.EmptyRootHash + kvStore := memorydb.New() + ethDB := rawdb.NewDatabase(kvStore) + tdb := triedb.NewDatabase(ethDB, &triedb.Config{}) + snaps, err := snapshot.New( + snapshot.Config{ + CacheSize: 16, // Mb (arbitrary but non-zero) + }, + kvStore, tdb, empty, + ) + require.NoError(tb, err, "snapshot.New()") + + sdb, err := state.New(empty, state.NewDatabase(tdb, snaps)) + require.NoError(tb, err, "state.New()") + + return sdb, vm.NewEVM( + vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + }, + vm.TxContext{}, + sdb, + ¶ms.ChainConfig{}, + vm.Config{}, + ) +} diff --git a/libevm/ethtest/rand.go b/libevm/ethtest/rand.go new file mode 100644 index 000000000000..dfabcfedca14 --- /dev/null +++ b/libevm/ethtest/rand.go @@ -0,0 +1,41 @@ +package ethtest + +import ( + "github.com/ethereum/go-ethereum/common" + "golang.org/x/exp/rand" +) + +// PseudoRand extends [rand.Rand] (*not* crypto/rand). +type PseudoRand struct { + *rand.Rand +} + +// NewPseudoRand returns a new PseudoRand with the given seed. +func NewPseudoRand(seed uint64) *PseudoRand { + return &PseudoRand{rand.New(rand.NewSource(seed))} +} + +// Address returns a pseudorandom address. +func (r *PseudoRand) Address() (a common.Address) { + r.Read(a[:]) + return a +} + +// AddressPtr returns a pointer to a pseudorandom address. +func (r *PseudoRand) AddressPtr() *common.Address { + a := r.Address() + return &a +} + +// Hash returns a pseudorandom hash. +func (r *PseudoRand) Hash() (h common.Hash) { + r.Read(h[:]) + return h +} + +// Bytes returns `n` pseudorandom bytes. +func (r *PseudoRand) Bytes(n uint) []byte { + b := make([]byte, n) + r.Read(b) + return b +} diff --git a/libevm/hookstest/stub.go b/libevm/hookstest/stub.go new file mode 100644 index 000000000000..3dcb1619c3cd --- /dev/null +++ b/libevm/hookstest/stub.go @@ -0,0 +1,60 @@ +// Package hookstest provides test doubles for testing subsets of libevm hooks. +package hookstest + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/libevm" + "github.com/ethereum/go-ethereum/params" +) + +// A Stub is a test double for [params.ChainConfigHooks] and +// [params.RulesHooks]. Each of the fields, if non-nil, back their respective +// hook methods, which otherwise fall back to the default behaviour. +type Stub struct { + PrecompileOverrides map[common.Address]libevm.PrecompiledContract + CanExecuteTransactionFn func(common.Address, *common.Address, libevm.StateReader) error + CanCreateContractFn func(*libevm.AddressContext, libevm.StateReader) error +} + +// RegisterForRules clears any registered [params.Extras] and then registers s +// as [params.RulesHooks], which are themselves cleared by the +// [testing.TB.Cleanup] routine. +func (s *Stub) RegisterForRules(tb testing.TB) { + params.TestOnlyClearRegisteredExtras() + params.RegisterExtras(params.Extras[params.NOOPHooks, Stub]{ + NewRules: func(_ *params.ChainConfig, _ *params.Rules, _ *params.NOOPHooks, blockNum *big.Int, isMerge bool, timestamp uint64) *Stub { + return s + }, + }) + tb.Cleanup(params.TestOnlyClearRegisteredExtras) +} + +func (s Stub) PrecompileOverride(a common.Address) (libevm.PrecompiledContract, bool) { + if len(s.PrecompileOverrides) == 0 { + return nil, false + } + p, ok := s.PrecompileOverrides[a] + return p, ok +} + +func (s Stub) CanExecuteTransaction(from common.Address, to *common.Address, sr libevm.StateReader) error { + if f := s.CanExecuteTransactionFn; f != nil { + return f(from, to, sr) + } + return nil +} + +func (s Stub) CanCreateContract(cc *libevm.AddressContext, sr libevm.StateReader) error { + if f := s.CanCreateContractFn; f != nil { + return f(cc, sr) + } + return nil +} + +var _ interface { + params.ChainConfigHooks + params.RulesHooks +} = Stub{} diff --git a/libevm/interfaces_test.go b/libevm/interfaces_test.go new file mode 100644 index 000000000000..05497ed40ab5 --- /dev/null +++ b/libevm/interfaces_test.go @@ -0,0 +1,20 @@ +package libevm_test + +import ( + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/libevm" +) + +// IMPORTANT: if any of these break then the libevm copy MUST be updated. + +// These two interfaces MUST be identical. +var ( + // Each assignment demonstrates that the methods of the LHS interface are a + // (non-strict) subset of the RHS interface's; both being possible + // proves that they are identical. + _ vm.PrecompiledContract = (libevm.PrecompiledContract)(nil) + _ libevm.PrecompiledContract = (vm.PrecompiledContract)(nil) +) + +// StateReader MUST be a subset vm.StateDB. +var _ libevm.StateReader = (vm.StateDB)(nil) diff --git a/libevm/libevm.go b/libevm/libevm.go new file mode 100644 index 000000000000..8b7d85bd49e8 --- /dev/null +++ b/libevm/libevm.go @@ -0,0 +1,52 @@ +package libevm + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" +) + +// PrecompiledContract is an exact copy of vm.PrecompiledContract, mirrored here +// for instances where importing that package would result in a circular +// dependency. +type PrecompiledContract interface { + RequiredGas(input []byte) uint64 + Run(input []byte) ([]byte, error) +} + +// StateReader is a subset of vm.StateDB, exposing only methods that read from +// but do not modify state. See method comments in vm.StateDB, which aren't +// copied here as they risk becoming outdated. +type StateReader interface { + GetBalance(common.Address) *uint256.Int + GetNonce(common.Address) uint64 + + GetCodeHash(common.Address) common.Hash + GetCode(common.Address) []byte + GetCodeSize(common.Address) int + + GetRefund() uint64 + + GetCommittedState(common.Address, common.Hash) common.Hash + GetState(common.Address, common.Hash) common.Hash + + GetTransientState(addr common.Address, key common.Hash) common.Hash + + HasSelfDestructed(common.Address) bool + + Exist(common.Address) bool + Empty(common.Address) bool + + AddressInAccessList(addr common.Address) bool + SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) +} + +// AddressContext carries addresses available to contexts such as calls and +// contract creation. +// +// With respect to contract creation, the Self address MAY be the predicted +// address of the contract about to be deployed, which may not exist yet. +type AddressContext struct { + Origin common.Address // equivalent to vm.ORIGIN op code + Caller common.Address // equivalent to vm.CALLER op code + Self common.Address // equivalent to vm.ADDRESS op code +} diff --git a/libevm/pseudo/constructor.go b/libevm/pseudo/constructor.go new file mode 100644 index 000000000000..91429240340a --- /dev/null +++ b/libevm/pseudo/constructor.go @@ -0,0 +1,24 @@ +package pseudo + +// A Constructor returns newly constructed [Type] instances for a pre-registered +// concrete type. +type Constructor interface { + Zero() *Type + NewPointer() *Type + NilPointer() *Type +} + +// NewConstructor returns a [Constructor] that builds `T` [Type] instances. +func NewConstructor[T any]() Constructor { + return ctor[T]{} +} + +type ctor[T any] struct{} + +func (ctor[T]) Zero() *Type { return Zero[T]().Type } +func (ctor[T]) NilPointer() *Type { return Zero[*T]().Type } + +func (ctor[T]) NewPointer() *Type { + var x T + return From(&x).Type +} diff --git a/libevm/pseudo/constructor_test.go b/libevm/pseudo/constructor_test.go new file mode 100644 index 000000000000..a28f3dd42de6 --- /dev/null +++ b/libevm/pseudo/constructor_test.go @@ -0,0 +1,45 @@ +package pseudo + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestConstructor(t *testing.T) { + testConstructor[uint](t) + testConstructor[string](t) + testConstructor[struct{ x string }](t) +} + +func testConstructor[T any](t *testing.T) { + var zero T + t.Run(fmt.Sprintf("%T", zero), func(t *testing.T) { + ctor := NewConstructor[T]() + + t.Run("NilPointer()", func(t *testing.T) { + got := get[*T](t, ctor.NilPointer()) + assert.Nil(t, got) + }) + + t.Run("NewPointer()", func(t *testing.T) { + got := get[*T](t, ctor.NewPointer()) + require.NotNil(t, got) + assert.Equal(t, zero, *got) + }) + + t.Run("Zero()", func(t *testing.T) { + got := get[T](t, ctor.Zero()) + assert.Equal(t, zero, got) + }) + }) +} + +func get[T any](t *testing.T, typ *Type) (x T) { + t.Helper() + val, err := NewValue[T](typ) + require.NoError(t, err, "NewValue[%T]()", x) + return val.Get() +} diff --git a/libevm/pseudo/type.go b/libevm/pseudo/type.go new file mode 100644 index 000000000000..8c453f4cb0e7 --- /dev/null +++ b/libevm/pseudo/type.go @@ -0,0 +1,175 @@ +// Package pseudo provides a bridge between generic and non-generic code via +// pseudo-types and pseudo-values. With careful usage, there is minimal +// reduction in type safety. +// +// Adding generic type parameters to anything (e.g. struct, function, etc) +// "pollutes" all code that uses the generic type. Refactoring all uses isn't +// always feasible, and a [Type] acts as an intermediate fix. Although their +// constructors are generic, they are not, and they are instead coupled with a +// generic [Value] that SHOULD be used for access. +// +// Packages typically SHOULD NOT expose a [Type] and SHOULD instead provide +// users with a type-safe [Value]. +package pseudo + +import ( + "encoding/json" + "fmt" +) + +// A Type wraps a strongly-typed value without exposing information about its +// type. It can be used in lieu of a generic field / parameter. +type Type struct { + val value +} + +// A Value provides strongly-typed access to the payload carried by a [Type]. +type Value[T any] struct { + t *Type +} + +// A Pseudo type couples a [Type] and a [Value]. If returned by a constructor +// from this package, both wrap the same payload. +type Pseudo[T any] struct { + Type *Type + Value *Value[T] +} + +// TypeAndValue is a convenience function for splitting the contents of `p`, +// typically at construction. +func (p *Pseudo[T]) TypeAndValue() (*Type, *Value[T]) { + return p.Type, p.Value +} + +// From returns a Pseudo[T] constructed from `v`. +func From[T any](v T) *Pseudo[T] { + t := &Type{ + val: &concrete[T]{ + val: v, + }, + } + return &Pseudo[T]{t, MustNewValue[T](t)} +} + +// Zero is equivalent to [From] called with the [zero value] of type `T`. Note +// that pointers, slices, maps, etc. will therefore be nil. +// +// [zero value]: https://go.dev/tour/basics/12 +func Zero[T any]() *Pseudo[T] { + var x T + return From[T](x) +} + +// Interface returns the wrapped value as an `any`, equivalent to +// [reflect.Value.Interface]. Prefer [Value.Get]. +func (t *Type) Interface() any { return t.val.get() } + +// NewValue constructs a [Value] from a [Type], first confirming that `t` wraps +// a payload of type `T`. +func NewValue[T any](t *Type) (*Value[T], error) { + var x T + if !t.val.canSetTo(x) { + return nil, fmt.Errorf("cannot create *Value[%T] with *Type carrying %T", x, t.val.get()) + } + return &Value[T]{t}, nil +} + +// MustNewValue is equivalent to [NewValue] except that it panics instead of +// returning an error. +func MustNewValue[T any](t *Type) *Value[T] { + v, err := NewValue[T](t) + if err != nil { + panic(err) + } + return v +} + +// Get returns the value. +func (a *Value[T]) Get() T { return a.t.val.get().(T) } + +// Set sets the value. +func (a *Value[T]) Set(v T) { a.t.val.mustSet(v) } + +// MarshalJSON implements the [json.Marshaler] interface. +func (t *Type) MarshalJSON() ([]byte, error) { return t.val.MarshalJSON() } + +// UnmarshalJSON implements the [json.Unmarshaler] interface. +func (t *Type) UnmarshalJSON(b []byte) error { return t.val.UnmarshalJSON(b) } + +// MarshalJSON implements the [json.Marshaler] interface. +func (v *Value[T]) MarshalJSON() ([]byte, error) { return v.t.MarshalJSON() } + +// UnmarshalJSON implements the [json.Unmarshaler] interface. +func (v *Value[T]) UnmarshalJSON(b []byte) error { return v.t.UnmarshalJSON(b) } + +var _ = []interface { + json.Marshaler + json.Unmarshaler +}{ + (*Type)(nil), + (*Value[struct{}])(nil), + (*concrete[struct{}])(nil), +} + +// A value is a non-generic wrapper around a [concrete] struct. +type value interface { + get() any + canSetTo(any) bool + set(any) error + mustSet(any) + + json.Marshaler + json.Unmarshaler +} + +type concrete[T any] struct { + val T +} + +func (c *concrete[T]) get() any { return c.val } + +func (c *concrete[T]) canSetTo(v any) bool { + _, ok := v.(T) + return ok +} + +// An invalidTypeError is returned by [conrete.set] if the value is incompatible +// with its type. This should never leave this package and exists only to +// provide precise testing of unhappy paths. +type invalidTypeError[T any] struct { + SetTo any +} + +func (e *invalidTypeError[T]) Error() string { + var t T + return fmt.Sprintf("cannot set %T to %T", t, e.SetTo) +} + +func (c *concrete[T]) set(v any) error { + vv, ok := v.(T) + if !ok { + // Other invariants in this implementation (aim to) guarantee that this + // will never happen. + return &invalidTypeError[T]{SetTo: v} + } + c.val = vv + return nil +} + +func (c *concrete[T]) mustSet(v any) { + if err := c.set(v); err != nil { + panic(err) + } + _ = 0 // for happy-path coverage inspection +} + +func (c *concrete[T]) MarshalJSON() ([]byte, error) { return json.Marshal(c.val) } + +func (c *concrete[T]) UnmarshalJSON(b []byte) error { + var v T + if err := json.Unmarshal(b, &v); err != nil { + return err + } + c.val = v + return nil +} diff --git a/libevm/pseudo/type_test.go b/libevm/pseudo/type_test.go new file mode 100644 index 000000000000..27ecf7e497ea --- /dev/null +++ b/libevm/pseudo/type_test.go @@ -0,0 +1,79 @@ +package pseudo + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestType(t *testing.T) { + testType(t, "Zero[int]", Zero[int], 0, 42, "I'm not an int") + testType(t, "Zero[string]", Zero[string], "", "hello, world", 99) + + testType( + t, "From[uint](314159)", + func() *Pseudo[uint] { + return From[uint](314159) + }, + 314159, 0, struct{}{}, + ) + + testType(t, "nil pointer", Zero[*float64], (*float64)(nil), new(float64), 0) +} + +func testType[T any](t *testing.T, name string, ctor func() *Pseudo[T], init T, setTo T, invalid any) { + t.Run(name, func(t *testing.T) { + typ, val := ctor().TypeAndValue() + assert.Equal(t, init, val.Get()) + val.Set(setTo) + assert.Equal(t, setTo, val.Get()) + + t.Run("set to invalid type", func(t *testing.T) { + wantErr := &invalidTypeError[T]{SetTo: invalid} + + assertError := func(t *testing.T, err any) { + t.Helper() + switch err := err.(type) { + case *invalidTypeError[T]: + assert.Equal(t, wantErr, err) + default: + t.Errorf("got error %v; want %v", err, wantErr) + } + } + + t.Run(fmt.Sprintf("Set(%T{%v})", invalid, invalid), func(t *testing.T) { + assertError(t, typ.val.set(invalid)) + }) + + t.Run(fmt.Sprintf("MustSet(%T{%v})", invalid, invalid), func(t *testing.T) { + defer func() { + assertError(t, recover()) + }() + typ.val.mustSet(invalid) + }) + }) + + t.Run("JSON round trip", func(t *testing.T) { + buf, err := json.Marshal(typ) + require.NoError(t, err) + + got, gotVal := Zero[T]().TypeAndValue() + require.NoError(t, json.Unmarshal(buf, &got)) + assert.Equal(t, val.Get(), gotVal.Get()) + }) + }) +} + +func ExamplePseudo_TypeAndValue() { + typ, val := From("hello").TypeAndValue() + + // But, if only one is needed: + typ = From("world").Type + val = From("this isn't coupled to the Type").Value + + _ = typ + _ = val +} diff --git a/params/config.go b/params/config.go index 9ecf465bb67a..04f98f2d2a33 100644 --- a/params/config.go +++ b/params/config.go @@ -21,6 +21,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/libevm/pseudo" "github.com/ethereum/go-ethereum/params/forks" ) @@ -343,6 +344,8 @@ type ChainConfig struct { // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` + + extra *pseudo.Type // See RegisterExtras() } // EthashConfig is the consensus engine configs for proof-of-work based sealing. @@ -894,6 +897,8 @@ type Rules struct { IsBerlin, IsLondon bool IsMerge, IsShanghai, IsCancun, IsPrague bool IsVerkle bool + + extra *pseudo.Type // See RegisterExtras() } // Rules ensures c's ChainID is not nil. @@ -905,7 +910,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules // disallow setting Merge out of order isMerge = isMerge && c.IsLondon(num) isVerkle := isMerge && c.IsVerkle(num, timestamp) - return Rules{ + r := Rules{ ChainID: new(big.Int).Set(chainID), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), @@ -925,4 +930,6 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsVerkle: isVerkle, IsEIP4762: isVerkle, } + c.addRulesExtra(&r, num, isMerge, timestamp) + return r } diff --git a/params/config.libevm.go b/params/config.libevm.go new file mode 100644 index 000000000000..37665be21060 --- /dev/null +++ b/params/config.libevm.go @@ -0,0 +1,232 @@ +package params + +import ( + "encoding/json" + "fmt" + "math/big" + "reflect" + "runtime" + "strings" + + "github.com/ethereum/go-ethereum/libevm/pseudo" +) + +// Extras are arbitrary payloads to be added as extra fields in [ChainConfig] +// and [Rules] structs. See [RegisterExtras]. +type Extras[C ChainConfigHooks, R RulesHooks] struct { + // NewRules, if non-nil is called at the end of [ChainConfig.Rules] with the + // newly created [Rules] and other context from the method call. Its + // returned value will be the extra payload of the [Rules]. If NewRules is + // nil then so too will the [Rules] extra payload be a nil `*R`. + // + // NewRules MAY modify the [Rules] but MUST NOT modify the [ChainConfig]. + NewRules func(_ *ChainConfig, _ *Rules, _ *C, blockNum *big.Int, isMerge bool, timestamp uint64) *R +} + +// RegisterExtras registers the types `C` and `R` such that they are carried as +// extra payloads in [ChainConfig] and [Rules] structs, respectively. It is +// expected to be called in an `init()` function and MUST NOT be called more +// than once. Both `C` and `R` MUST be structs. +// +// After registration, JSON unmarshalling of a [ChainConfig] will create a new +// `*C` and unmarshal the JSON key "extra" into it. Conversely, JSON marshalling +// will populate the "extra" key with the contents of the `*C`. Both the +// [json.Marshaler] and [json.Unmarshaler] interfaces are honoured if +// implemented by `C` and/or `R.` +// +// Calls to [ChainConfig.Rules] will call the `NewRules` function of the +// registered [Extras] to create a new `*R`. +// +// The payloads can be accessed via the [ExtraPayloadGetter.FromChainConfig] and +// [ExtraPayloadGetter.FromRules] methods of the getter returned by +// RegisterExtras. Where stated in the interface definitions, they will also be +// used as hooks to alter Ethereum behaviour; if this isn't desired then they +// can embed [NOOPHooks] to satisfy either interface. +func RegisterExtras[C ChainConfigHooks, R RulesHooks](e Extras[C, R]) ExtraPayloadGetter[C, R] { + if registeredExtras != nil { + panic("re-registration of Extras") + } + mustBeStruct[C]() + mustBeStruct[R]() + + getter := e.getter() + registeredExtras = &extraConstructors{ + chainConfig: pseudo.NewConstructor[C](), + rules: pseudo.NewConstructor[R](), + newForRules: e.newForRules, + getter: getter, + } + return getter +} + +// TestOnlyClearRegisteredExtras clears the [Extras] previously passed to +// [RegisterExtras]. It panics if called from a non-testing call stack. +// +// In tests it SHOULD be called before every call to [RegisterExtras] and then +// defer-called afterwards, either directly or via testing.TB.Cleanup(). This is +// a workaround for the single-call limitation on [RegisterExtras]. +func TestOnlyClearRegisteredExtras() { + pc := make([]uintptr, 10) + runtime.Callers(0, pc) + frames := runtime.CallersFrames(pc) + for { + f, more := frames.Next() + if strings.Contains(f.File, "/testing/") || strings.HasSuffix(f.File, "_test.go") { + registeredExtras = nil + return + } + if !more { + panic("no _test.go file in call stack") + } + } +} + +// registeredExtras holds non-generic constructors for the [Extras] types +// registered via [RegisterExtras]. +var registeredExtras *extraConstructors + +type extraConstructors struct { + chainConfig, rules pseudo.Constructor + newForRules func(_ *ChainConfig, _ *Rules, blockNum *big.Int, isMerge bool, timestamp uint64) *pseudo.Type + // use top-level hooksFrom() functions instead of these as they handle + // instances where no [Extras] were registered. + getter interface { + hooksFromChainConfig(*ChainConfig) ChainConfigHooks + hooksFromRules(*Rules) RulesHooks + } +} + +func (e *Extras[C, R]) newForRules(c *ChainConfig, r *Rules, blockNum *big.Int, isMerge bool, timestamp uint64) *pseudo.Type { + if e.NewRules == nil { + return registeredExtras.rules.NilPointer() + } + rExtra := e.NewRules(c, r, e.getter().FromChainConfig(c), blockNum, isMerge, timestamp) + return pseudo.From(rExtra).Type +} + +func (*Extras[C, R]) getter() (g ExtraPayloadGetter[C, R]) { return } + +// mustBeStruct panics if `T` isn't a struct. +func mustBeStruct[T any]() { + if k := reflect.TypeFor[T]().Kind(); k != reflect.Struct { + panic(notStructMessage[T]()) + } +} + +// notStructMessage returns the message with which [mustBeStruct] might panic. +// It exists to avoid change-detector tests should the message contents change. +func notStructMessage[T any]() string { + var x T + return fmt.Sprintf("%T is not a struct", x) +} + +// An ExtraPayloadGettter provides strongly typed access to the extra payloads +// carried by [ChainConfig] and [Rules] structs. The only valid way to construct +// a getter is by a call to [RegisterExtras]. +type ExtraPayloadGetter[C ChainConfigHooks, R RulesHooks] struct { + _ struct{} // make godoc show unexported fields so nobody tries to make their own getter ;) +} + +// FromChainConfig returns the ChainConfig's extra payload. +func (ExtraPayloadGetter[C, R]) FromChainConfig(c *ChainConfig) *C { + return pseudo.MustNewValue[*C](c.extraPayload()).Get() +} + +// hooksFromChainConfig is equivalent to FromChainConfig(), but returns an +// interface instead of the concrete type implementing it; this allows it to be +// used in non-generic code. If the concrete-type value is nil (typically +// because no [Extras] were registered) a [noopHooks] is returned so it can be +// used without nil checks. +func (e ExtraPayloadGetter[C, R]) hooksFromChainConfig(c *ChainConfig) ChainConfigHooks { + if h := e.FromChainConfig(c); h != nil { + return *h + } + return NOOPHooks{} +} + +// FromRules returns the Rules' extra payload. +func (ExtraPayloadGetter[C, R]) FromRules(r *Rules) *R { + return pseudo.MustNewValue[*R](r.extraPayload()).Get() +} + +// hooksFromRules is the [RulesHooks] equivalent of hooksFromChainConfig(). +func (e ExtraPayloadGetter[C, R]) hooksFromRules(r *Rules) RulesHooks { + if h := e.FromRules(r); h != nil { + return *h + } + return NOOPHooks{} +} + +// UnmarshalJSON implements the [json.Unmarshaler] interface. +func (c *ChainConfig) UnmarshalJSON(data []byte) error { + type raw ChainConfig // doesn't inherit methods so avoids recursing back here (infinitely) + cc := &struct { + *raw + Extra *pseudo.Type `json:"extra"` + }{ + raw: (*raw)(c), // embedded to achieve regular JSON unmarshalling + } + if e := registeredExtras; e != nil { + cc.Extra = e.chainConfig.NilPointer() // `c.extra` is otherwise unexported + } + + if err := json.Unmarshal(data, cc); err != nil { + return err + } + c.extra = cc.Extra + return nil +} + +// MarshalJSON implements the [json.Marshaler] interface. +func (c *ChainConfig) MarshalJSON() ([]byte, error) { + // See UnmarshalJSON() for rationale. + type raw ChainConfig + cc := &struct { + *raw + Extra *pseudo.Type `json:"extra"` + }{raw: (*raw)(c), Extra: c.extra} + return json.Marshal(cc) +} + +var _ interface { + json.Marshaler + json.Unmarshaler +} = (*ChainConfig)(nil) + +// addRulesExtra is called at the end of [ChainConfig.Rules]; it exists to +// abstract the libevm-specific behaviour outside of original geth code. +func (c *ChainConfig) addRulesExtra(r *Rules, blockNum *big.Int, isMerge bool, timestamp uint64) { + r.extra = nil + if registeredExtras != nil { + r.extra = registeredExtras.newForRules(c, r, blockNum, isMerge, timestamp) + } +} + +// extraPayload returns the ChainConfig's extra payload iff [RegisterExtras] has +// already been called. If the payload hasn't been populated (typically via +// unmarshalling of JSON), a nil value is constructed and returned. +func (c *ChainConfig) extraPayload() *pseudo.Type { + if registeredExtras == nil { + // This will only happen if someone constructs an [ExtraPayloadGetter] + // directly, without a call to [RegisterExtras]. + // + // See https://google.github.io/styleguide/go/best-practices#when-to-panic + panic(fmt.Sprintf("%T.ExtraPayload() called before RegisterExtras()", c)) + } + if c.extra == nil { + c.extra = registeredExtras.chainConfig.NilPointer() + } + return c.extra +} + +// extraPayload is equivalent to [ChainConfig.extraPayload]. +func (r *Rules) extraPayload() *pseudo.Type { + if registeredExtras == nil { + // See ChainConfig.extraPayload() equivalent. + panic(fmt.Sprintf("%T.ExtraPayload() called before RegisterExtras()", r)) + } + if r.extra == nil { + r.extra = registeredExtras.rules.NilPointer() + } + return r.extra +} diff --git a/params/config.libevm_test.go b/params/config.libevm_test.go new file mode 100644 index 000000000000..9b17cb428795 --- /dev/null +++ b/params/config.libevm_test.go @@ -0,0 +1,164 @@ +package params + +import ( + "encoding/json" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/libevm/pseudo" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type rawJSON struct { + json.RawMessage + NOOPHooks +} + +var _ interface { + json.Marshaler + json.Unmarshaler +} = (*rawJSON)(nil) + +func TestRegisterExtras(t *testing.T) { + type ( + ccExtraA struct { + A string `json:"a"` + ChainConfigHooks + } + rulesExtraA struct { + A string + RulesHooks + } + ccExtraB struct { + B string `json:"b"` + ChainConfigHooks + } + rulesExtraB struct { + B string + RulesHooks + } + ) + + tests := []struct { + name string + register func() + ccExtra *pseudo.Type + wantRulesExtra any + }{ + { + name: "Rules payload copied from ChainConfig payload", + register: func() { + RegisterExtras(Extras[ccExtraA, rulesExtraA]{ + NewRules: func(cc *ChainConfig, r *Rules, ex *ccExtraA, _ *big.Int, _ bool, _ uint64) *rulesExtraA { + return &rulesExtraA{ + A: ex.A, + } + }, + }) + }, + ccExtra: pseudo.From(&ccExtraA{ + A: "hello", + }).Type, + wantRulesExtra: &rulesExtraA{ + A: "hello", + }, + }, + { + name: "no NewForRules() function results in typed but nil pointer", + register: func() { + RegisterExtras(Extras[ccExtraB, rulesExtraB]{}) + }, + ccExtra: pseudo.From(&ccExtraB{ + B: "world", + }).Type, + wantRulesExtra: (*rulesExtraB)(nil), + }, + { + name: "custom JSON handling honoured", + register: func() { + RegisterExtras(Extras[rawJSON, struct{ RulesHooks }]{}) + }, + ccExtra: pseudo.From(&rawJSON{ + RawMessage: []byte(`"hello, world"`), + }).Type, + wantRulesExtra: (*struct{ RulesHooks })(nil), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + TestOnlyClearRegisteredExtras() + tt.register() + defer TestOnlyClearRegisteredExtras() + + in := &ChainConfig{ + ChainID: big.NewInt(142857), + extra: tt.ccExtra, + } + + buf, err := json.Marshal(in) + require.NoError(t, err) + + got := new(ChainConfig) + require.NoError(t, json.Unmarshal(buf, got)) + assert.Equal(t, tt.ccExtra.Interface(), got.extraPayload().Interface()) + assert.Equal(t, in, got) + // TODO: do we need an explicit test of the JSON output, or is a + // Marshal-Unmarshal round trip sufficient? + + gotRules := got.Rules(nil, false, 0) + assert.Equal(t, tt.wantRulesExtra, gotRules.extraPayload().Interface()) + }) + } +} + +func TestExtrasPanic(t *testing.T) { + TestOnlyClearRegisteredExtras() + defer TestOnlyClearRegisteredExtras() + + assertPanics( + t, func() { + new(ChainConfig).extraPayload() + }, + "before RegisterExtras", + ) + + assertPanics( + t, func() { + new(Rules).extraPayload() + }, + "before RegisterExtras", + ) + + assertPanics( + t, func() { + mustBeStruct[int]() + }, + notStructMessage[int](), + ) + + RegisterExtras(Extras[struct{ ChainConfigHooks }, struct{ RulesHooks }]{}) + + assertPanics( + t, func() { + RegisterExtras(Extras[struct{ ChainConfigHooks }, struct{ RulesHooks }]{}) + }, + "re-registration", + ) +} + +func assertPanics(t *testing.T, fn func(), wantContains string) { + t.Helper() + defer func() { + switch r := recover().(type) { + case nil: + t.Error("function did not panic as expected") + case string: + assert.Contains(t, r, wantContains) + default: + t.Fatalf("BAD TEST SETUP: recover() got unsupported type %T", r) + } + }() + fn() +} diff --git a/params/example.libevm_test.go b/params/example.libevm_test.go new file mode 100644 index 000000000000..37e8b2e4b580 --- /dev/null +++ b/params/example.libevm_test.go @@ -0,0 +1,158 @@ +// In practice, everything in this file except for the Example() function SHOULD +// be a standalone package, typically called `extraparams`. As long as this new +// package is imported anywhere, its init() function will register the "extra" +// types, which can be accessed via [extraparams.FromChainConfig] and/or +// [extraparams.FromRules]. In all other respects, the [params.ChainConfig] and +// [params.Rules] types will act as expected. +// +// The Example() function demonstrates how the `extraparams` package might be +// used from elsewhere. +package params_test + +import ( + "encoding/json" + "errors" + "fmt" + "log" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/libevm" + "github.com/ethereum/go-ethereum/params" +) + +// In practice this would be a regular init() function but nuances around the +// testing of this package require it to be called in the Example(). +func initFn() { + params.TestOnlyClearRegisteredExtras() // not necessary outside of the example + // This registration makes *all* [params.ChainConfig] and [params.Rules] + // instances respect the payload types. They do not need to be modified to + // know about `extraparams`. + getter = params.RegisterExtras(params.Extras[ChainConfigExtra, RulesExtra]{ + NewRules: constructRulesExtra, + }) +} + +var getter params.ExtraPayloadGetter[ChainConfigExtra, RulesExtra] + +// constructRulesExtra acts as an adjunct to the [params.ChainConfig.Rules] +// method. Its primary purpose is to construct the extra payload for the +// [params.Rules] but it MAY also modify the [params.Rules]. +func constructRulesExtra(c *params.ChainConfig, r *params.Rules, cEx *ChainConfigExtra, blockNum *big.Int, isMerge bool, timestamp uint64) *RulesExtra { + return &RulesExtra{ + IsMyFork: cEx.MyForkTime != nil && *cEx.MyForkTime <= timestamp, + timestamp: timestamp, + } +} + +// ChainConfigExtra can be any struct. Here it just mirrors a common pattern in +// the standard [params.ChainConfig] struct. +type ChainConfigExtra struct { + MyForkTime *uint64 `json:"myForkTime"` +} + +// RulesExtra can be any struct. It too mirrors a common pattern in +// [params.Rules]. +type RulesExtra struct { + IsMyFork bool + timestamp uint64 + + // (Optional) If not all hooks are desirable then embedding a [NOOPHooks] + // allows the type to satisfy the [RulesHooks] interface, resulting in + // default Ethereum behaviour. + params.NOOPHooks +} + +// FromChainConfig returns the extra payload carried by the ChainConfig. +func FromChainConfig(c *params.ChainConfig) *ChainConfigExtra { + return getter.FromChainConfig(c) +} + +// FromRules returns the extra payload carried by the Rules. +func FromRules(r *params.Rules) *RulesExtra { + return getter.FromRules(r) +} + +// myForkPrecompiledContracts is analogous to the vm.PrecompiledContracts +// maps. Note [RulesExtra.PrecompileOverride] treatment of nil values here. +var myForkPrecompiledContracts = map[common.Address]vm.PrecompiledContract{ + //... + common.BytesToAddress([]byte{0x2}): nil, // i.e disabled + //... +} + +// PrecompileOverride implements the required [params.RuleHooks] method. +func (r RulesExtra) PrecompileOverride(addr common.Address) (_ libevm.PrecompiledContract, override bool) { + if !r.IsMyFork { + return nil, false + } + p, ok := myForkPrecompiledContracts[addr] + // The returned boolean indicates whether or not [vm.EVMInterpreter] MUST + // override the address, not what it returns as its own `isPrecompile` + // boolean. + // + // Therefore returning `nil, true` here indicates that the precompile will + // be disabled. Returning `false` here indicates that the default precompile + // behaviour will be exhibited. + // + // The same pattern can alternatively be implemented with an explicit + // `disabledPrecompiles` set to make the behaviour clearer. + return p, ok +} + +// CanCreateContract implements the required [params.RuleHooks] method. Access +// to state allows it to be configured on-chain however this is an optional +// implementation detail. +func (r RulesExtra) CanCreateContract(*libevm.AddressContext, libevm.StateReader) error { + if time.Unix(int64(r.timestamp), 0).UTC().Day() != int(time.Tuesday) { + return errors.New("uh oh!") + } + return nil +} + +// This example demonstrates how the rest of this file would be used from a +// *different* package. +func ExampleExtraPayloadGetter() { + initFn() // Outside of an example this is unnecessary as the function will be a regular init(). + + const forkTime = 530003640 + jsonData := fmt.Sprintf(`{ + "chainId": 1234, + "extra": { + "myForkTime": %d + } + }`, forkTime) + + // Because [params.RegisterExtras] has been called, unmarshalling a JSON + // field of "extra" into a [params.ChainConfig] will populate a new value of + // the registered type. This can be accessed with the [FromChainConfig] + // function. + config := new(params.ChainConfig) + if err := json.Unmarshal([]byte(jsonData), config); err != nil { + log.Fatal(err) + } + + fmt.Println("Chain ID", config.ChainID) // original geth fields work as expected + + ccExtra := FromChainConfig(config) // extraparams.FromChainConfig() in practice + if ccExtra != nil && ccExtra.MyForkTime != nil { + fmt.Println("Fork time", *ccExtra.MyForkTime) + } + + for _, time := range []uint64{forkTime - 1, forkTime, forkTime + 1} { + rules := config.Rules(nil, false, time) + rExtra := FromRules(&rules) // extraparams.FromRules() in practice + if rExtra != nil { + fmt.Printf("IsMyFork at %v: %t\n", rExtra.timestamp, rExtra.IsMyFork) + } + } + + // Output: + // Chain ID 1234 + // Fork time 530003640 + // IsMyFork at 530003639: false + // IsMyFork at 530003640: true + // IsMyFork at 530003641: true +} diff --git a/params/hooks.libevm.go b/params/hooks.libevm.go new file mode 100644 index 000000000000..c44cd3f1f055 --- /dev/null +++ b/params/hooks.libevm.go @@ -0,0 +1,83 @@ +package params + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/libevm" +) + +// ChainConfigHooks are required for all types registered as [Extras] for +// [ChainConfig] payloads. +type ChainConfigHooks interface{} + +// TODO(arr4n): given the choice of whether a hook should be defined on a +// ChainConfig or on the Rules, what are the guiding principles? A ChainConfig +// carries the most general information while Rules benefit from "knowing" the +// block number and timestamp. I am leaning towards the default choice being +// on Rules (as it's trivial to copy information from ChainConfig to Rules in +// [Extras.NewRules]) unless the call site only has access to a ChainConfig. + +// RulesHooks are required for all types registered as [Extras] for [Rules] +// payloads. +type RulesHooks interface { + RulesAllowlistHooks + // PrecompileOverride signals whether or not the EVM interpreter MUST + // override its treatment of the address when deciding if it is a + // precompiled contract. If PrecompileOverride returns `true` then the + // interpreter will treat the address as a precompile i.f.f the + // [PrecompiledContract] is non-nil. If it returns `false` then the default + // precompile behaviour is honoured. + PrecompileOverride(common.Address) (_ libevm.PrecompiledContract, override bool) +} + +// RulesAllowlistHooks are a subset of [RulesHooks] that gate actions, signalled +// by returning a nil (allowed) or non-nil (blocked) error. +type RulesAllowlistHooks interface { + CanCreateContract(*libevm.AddressContext, libevm.StateReader) error + CanExecuteTransaction(from common.Address, to *common.Address, _ libevm.StateReader) error +} + +// Hooks returns the hooks registered with [RegisterExtras], or [NOOPHooks] if +// none were registered. +func (c *ChainConfig) Hooks() ChainConfigHooks { + if e := registeredExtras; e != nil { + return e.getter.hooksFromChainConfig(c) + } + return NOOPHooks{} +} + +// Hooks returns the hooks registered with [RegisterExtras], or [NOOPHooks] if +// none were registered. +func (r *Rules) Hooks() RulesHooks { + if e := registeredExtras; e != nil { + return e.getter.hooksFromRules(r) + } + return NOOPHooks{} +} + +// NOOPHooks implements both [ChainConfigHooks] and [RulesHooks] such that every +// hook is a no-op. This allows it to be returned instead of a nil interface, +// which would otherwise require every usage site to perform a nil check. It can +// also be embedded in structs that only wish to implement a sub-set of hooks. +// Use of a NOOPHooks is equivalent to default Ethereum behaviour. +type NOOPHooks struct{} + +var _ interface { + ChainConfigHooks + RulesHooks +} = NOOPHooks{} + +// CanExecuteTransaction allows all (otherwise valid) transactions. +func (NOOPHooks) CanExecuteTransaction(_ common.Address, _ *common.Address, _ libevm.StateReader) error { + return nil +} + +// CanCreateContract allows all (otherwise valid) contract deployment. +func (NOOPHooks) CanCreateContract(*libevm.AddressContext, libevm.StateReader) error { + return nil +} + +// PrecompileOverride instructs the EVM interpreter to use the default +// precompile behaviour. +func (NOOPHooks) PrecompileOverride(common.Address) (libevm.PrecompiledContract, bool) { + return nil, false +}